summaryrefslogtreecommitdiff
path: root/spec/ruby/command_line/syntax_error_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/command_line/syntax_error_spec.rb')
-rw-r--r--spec/ruby/command_line/syntax_error_spec.rb13
1 files changed, 13 insertions, 0 deletions
diff --git a/spec/ruby/command_line/syntax_error_spec.rb b/spec/ruby/command_line/syntax_error_spec.rb
new file mode 100644
index 0000000000..88864c048e
--- /dev/null
+++ b/spec/ruby/command_line/syntax_error_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../spec_helper'
+
+describe "The interpreter" do
+ it "prints an error when given a file with invalid syntax" do
+ out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), args: "2>&1", exit_status: 1)
+ out.should.include?("SyntaxError")
+ end
+
+ it "prints an error when given code via -e with invalid syntax" do
+ out = ruby_exe(nil, args: "-e 'a{' 2>&1", exit_status: 1)
+ out.should.include?("SyntaxError")
+ end
+end
lass='right'>165
-rw-r--r--.github/actions/setup/directories/action.yml176
-rw-r--r--.github/actions/setup/macos/action.yml28
-rw-r--r--.github/actions/setup/ubuntu/action.yml53
-rw-r--r--.github/actions/slack/action.yml39
-rw-r--r--.github/auto_request_review.yml13
-rw-r--r--.github/codeql/codeql-config.yml3
-rw-r--r--.github/dependabot.yml14
-rw-r--r--.github/workflows/annocheck.yml112
-rw-r--r--.github/workflows/auto_request_review.yml19
-rw-r--r--.github/workflows/baseruby.yml73
-rw-r--r--.github/workflows/bundled_gems.yml147
-rw-r--r--.github/workflows/check_dependencies.yml76
-rw-r--r--.github/workflows/check_misc.yml117
-rw-r--r--.github/workflows/codeql-analysis.yml142
-rw-r--r--.github/workflows/compilers.yml580
-rw-r--r--.github/workflows/dependabot_automerge.yml30
-rw-r--r--.github/workflows/macos.yml207
-rw-r--r--.github/workflows/mingw.yml175
-rw-r--r--.github/workflows/mjit-bindgen.yml104
-rw-r--r--.github/workflows/mjit.yml113
-rw-r--r--.github/workflows/parsey.yml94
-rw-r--r--.github/workflows/pr-playground.yml127
-rw-r--r--.github/workflows/release.yml108
-rw-r--r--.github/workflows/rjit-bindgen.yml86
-rw-r--r--.github/workflows/rjit.yml130
-rw-r--r--.github/workflows/scorecards.yml28
-rw-r--r--.github/workflows/spec_guards.yml23
-rw-r--r--.github/workflows/ubuntu.yml211
-rw-r--r--.github/workflows/wasm.yml127
-rw-r--r--.github/workflows/windows.yml221
-rw-r--r--.github/workflows/yjit-macos.yml170
-rw-r--r--.github/workflows/yjit-ubuntu.yml227
-rw-r--r--.gitignore45
-rw-r--r--.mailmap431
-rw-r--r--.rdoc_options5
-rw-r--r--LEGAL76
-rw-r--r--NEWS.md909
-rw-r--r--README.ja.md27
-rw-r--r--README.md20
-rw-r--r--addr2line.c824
-rw-r--r--addr2line.h4
-rw-r--r--array.c2670
-rw-r--r--array.rb160
-rw-r--r--ast.c698
-rw-r--r--ast.rb82
-rwxr-xr-xbasictest/test.rb18
-rw-r--r--benchmark/app_aobench.rb4
-rw-r--r--benchmark/array_large_literal.yml19
-rw-r--r--benchmark/enum_sort_by.yml53
-rw-r--r--benchmark/hash_aref_str_lit.yml20
-rw-r--r--benchmark/hash_key.yml5
-rw-r--r--benchmark/hash_new.yml16
-rw-r--r--benchmark/lib/benchmark_driver/runner/mjit.rb34
-rw-r--r--benchmark/loop_each.yml4
-rw-r--r--benchmark/loop_generator.rb2
-rw-r--r--benchmark/loop_times_megamorphic.yml7
-rw-r--r--benchmark/mjit_exivar.yml18
-rw-r--r--benchmark/mjit_integer.yml32
-rw-r--r--benchmark/mjit_kernel.yml20
-rw-r--r--benchmark/mjit_leave.yml8
-rw-r--r--benchmark/mjit_opt_cc_insns.yml27
-rw-r--r--benchmark/mjit_struct_aref.yml10
-rw-r--r--benchmark/object_allocate.yml27
-rw-r--r--benchmark/range_bsearch_bignum.yml10
-rw-r--r--benchmark/range_bsearch_endpointless.yml21
-rw-r--r--benchmark/range_bsearch_fixnum.yml10
-rw-r--r--benchmark/range_count.yml11
-rw-r--r--benchmark/range_overlap.yml19
-rw-r--r--benchmark/range_reverse_each.yml16
-rw-r--r--benchmark/realpath.yml3
-rw-r--r--benchmark/regexp_dup.yml6
-rw-r--r--benchmark/regexp_new.yml7
-rw-r--r--benchmark/so_count_words.yml33
-rw-r--r--benchmark/so_meteor_contest.rb2
-rw-r--r--benchmark/string_concat.yml6
-rw-r--r--benchmark/string_dup.yml7
-rw-r--r--benchmark/string_rpartition.yml18
-rw-r--r--benchmark/struct_accessor.yml25
-rw-r--r--benchmark/time_strftime.yml7
-rw-r--r--benchmark/time_xmlschema.yml27
-rw-r--r--benchmark/vm_call_bmethod.yml37
-rw-r--r--benchmark/vm_call_kw_and_kw_splat.yml25
-rw-r--r--benchmark/vm_call_method_missing.yml62
-rw-r--r--benchmark/vm_call_send_iseq.yml77
-rw-r--r--benchmark/vm_call_symproc.yml83
-rw-r--r--benchmark/vm_ivar_ic_miss.yml20
-rw-r--r--benchmark/vm_ivar_memoize.yml85
-rw-r--r--benchmark/vm_method_splat_calls.yml13
-rw-r--r--benchmark/vm_method_splat_calls2.yml27
-rw-r--r--benchmark/vm_send_cfunc.yml15
-rw-r--r--benchmark/vm_super_splat_calls.yml25
-rw-r--r--benchmark/vm_zsuper_splat_calls.yml28
-rw-r--r--bignum.c269
-rwxr-xr-xbin/gem2
-rwxr-xr-xbootstraptest/runner.rb185
-rw-r--r--bootstraptest/test_autoload.rb12
-rw-r--r--bootstraptest/test_eval.rb43
-rw-r--r--bootstraptest/test_exception.rb2
-rw-r--r--bootstraptest/test_finalizer.rb8
-rw-r--r--bootstraptest/test_flow.rb2
-rw-r--r--bootstraptest/test_fork.rb22
-rw-r--r--bootstraptest/test_gc.rb2
-rw-r--r--bootstraptest/test_insns.rb62
-rw-r--r--bootstraptest/test_io.rb2
-rw-r--r--bootstraptest/test_jump.rb2
-rw-r--r--bootstraptest/test_literal.rb5
-rw-r--r--bootstraptest/test_literal_suffix.rb12
-rw-r--r--bootstraptest/test_load.rb14
-rw-r--r--bootstraptest/test_method.rb230
-rw-r--r--bootstraptest/test_ractor.rb308
-rw-r--r--bootstraptest/test_rjit.rb80
-rw-r--r--bootstraptest/test_syntax.rb54
-rw-r--r--bootstraptest/test_thread.rb26
-rw-r--r--bootstraptest/test_yjit.rb1739
-rw-r--r--builtin.c18
-rw-r--r--builtin.h8
-rw-r--r--ccan/list/list.h6
-rw-r--r--class.c286
-rw-r--r--common.mk4941
-rw-r--r--compar.c29
-rw-r--r--compile.c3805
-rw-r--r--complex.c953
-rw-r--r--configure.ac576
-rw-r--r--constant.h2
-rw-r--r--cont.c375
-rw-r--r--coroutine/amd64/Context.S77
-rw-r--r--coroutine/arm64/Context.S73
-rw-r--r--coroutine/arm64/Context.h21
-rw-r--r--coroutine/loongarch64/Context.S73
-rw-r--r--coroutine/loongarch64/Context.h46
-rw-r--r--coroutine/ppc/Context.S2
-rw-r--r--coroutine/ppc/Context.h2
-rw-r--r--coroutine/ppc64/Context.h2
-rw-r--r--coroutine/win64/Context.h2
-rw-r--r--cygwin/GNUmakefile.in17
-rw-r--r--darray.h140
-rw-r--r--debug.c184
-rw-r--r--debug_counter.c2
-rw-r--r--debug_counter.h61
-rw-r--r--defs/gmake.mk206
-rw-r--r--defs/id.def4
-rw-r--r--defs/known_errors.def314
-rw-r--r--defs/tags.mk18
-rw-r--r--defs/universal.mk5
-rw-r--r--dir.c1155
-rw-r--r--dir.rb378
-rw-r--r--dln.c129
-rw-r--r--dln.h1
-rw-r--r--dln_find.c13
-rw-r--r--dmydln.c12
-rw-r--r--dmyenc.c14
-rw-r--r--dmyext.c14
-rw-r--r--doc/.document5
-rw-r--r--doc/ChangeLog-0.06_to_0.52 (renamed from doc/ChangeLog/ChangeLog-0.06_to_0.52)0
-rw-r--r--doc/ChangeLog-0.50_to_0.60 (renamed from doc/ChangeLog/ChangeLog-0.50_to_0.60)0
-rw-r--r--doc/ChangeLog-0.60_to_1.1 (renamed from doc/ChangeLog/ChangeLog-0.60_to_1.1)0
-rw-r--r--doc/ChangeLog-1.8.0 (renamed from doc/ChangeLog/ChangeLog-1.8.0)0
-rw-r--r--doc/ChangeLog-1.9.3 (renamed from doc/ChangeLog/ChangeLog-1.9.3)0
-rw-r--r--doc/ChangeLog-2.0.0 (renamed from doc/ChangeLog/ChangeLog-2.0.0)0
-rw-r--r--doc/ChangeLog-2.1.018060
-rw-r--r--doc/ChangeLog-2.2.012157
-rw-r--r--doc/ChangeLog-2.3.0 (renamed from doc/ChangeLog/ChangeLog-2.3.0)0
-rw-r--r--doc/ChangeLog-2.4.09492
-rw-r--r--doc/ChangeLog-YARV (renamed from doc/ChangeLog/ChangeLog-YARV)0
-rw-r--r--doc/ChangeLog/ChangeLog-2.1.018060
-rw-r--r--doc/ChangeLog/ChangeLog-2.2.012157
-rw-r--r--doc/ChangeLog/ChangeLog-2.4.09492
-rw-r--r--doc/NEWS/NEWS-3.2.0.md820
-rw-r--r--doc/NEWS/NEWS-3.3.0.md529
-rw-r--r--doc/_regexp.rdoc1276
-rw-r--r--doc/_timezones.rdoc156
-rw-r--r--doc/bsearch.rdoc2
-rw-r--r--doc/case_mapping.rdoc6
-rw-r--r--doc/character_selectors.rdoc6
-rw-r--r--doc/command_injection.rdoc14
-rw-r--r--doc/command_line/environment.md173
-rw-r--r--doc/contributing/building_ruby.md238
-rw-r--r--doc/contributing/documentation_guide.md265
-rw-r--r--doc/contributing/glossary.md41
-rw-r--r--doc/contributing/making_changes_to_stdlibs.md2
-rw-r--r--doc/contributing/testing_ruby.md36
-rw-r--r--doc/csv/options/common/col_sep.rdoc6
-rw-r--r--doc/csv/options/common/row_sep.rdoc9
-rw-r--r--doc/csv/options/generating/write_converters.rdoc8
-rw-r--r--doc/csv/options/generating/write_headers.rdoc2
-rw-r--r--doc/csv/options/parsing/liberal_parsing.rdoc23
-rw-r--r--doc/csv/recipes/filtering.rdoc2
-rw-r--r--doc/csv/recipes/generating.rdoc6
-rw-r--r--doc/csv/recipes/parsing.rdoc6
-rw-r--r--doc/csv/recipes/recipes.rdoc2
-rw-r--r--doc/distribution.md47
-rw-r--r--doc/encodings.rdoc50
-rw-r--r--doc/exceptions.md528
-rw-r--r--doc/extension.ja.rdoc58
-rw-r--r--doc/extension.rdoc281
-rw-r--r--doc/format_specifications.rdoc60
-rw-r--r--doc/forwardable.rd.ja2
-rw-r--r--doc/globals.rdoc485
-rw-r--r--doc/implicit_conversion.rdoc10
-rw-r--r--doc/irb/indexes.md189
-rw-r--r--doc/irb/irb.rd.ja4
-rw-r--r--doc/keywords.rdoc162
-rw-r--r--doc/maintainers.md504
-rw-r--r--doc/maintainers.rdoc424
-rw-r--r--doc/matchdata/bytebegin.rdoc30
-rw-r--r--doc/matchdata/byteend.rdoc30
-rw-r--r--doc/mjit/mjit.md39
-rw-r--r--doc/optparse/argument_converters.rdoc70
-rw-r--r--doc/optparse/option_params.rdoc6
-rw-r--r--doc/optparse/ruby/argument_abbreviation.rb9
-rw-r--r--doc/optparse/tutorial.rdoc93
-rw-r--r--doc/packed_data.rdoc127
-rw-r--r--doc/pty/README.expect.ja32
-rw-r--r--doc/pty/README.ja50
-rw-r--r--doc/ractor.md12
-rw-r--r--doc/rdoc/markup_reference.rb147
-rw-r--r--doc/regexp.rdoc801
-rw-r--r--doc/regexp/methods.rdoc41
-rw-r--r--doc/regexp/unicode_properties.rdoc678
-rw-r--r--doc/reline/face.md111
-rw-r--r--doc/rjit/rjit.md45
-rw-r--r--doc/ruby/option_dump.md297
-rw-r--r--doc/ruby/options.md723
-rw-r--r--doc/security.rdoc2
-rw-r--r--doc/standard_library.rdoc42
-rw-r--r--doc/strftime_formatting.rdoc54
-rw-r--r--doc/string/encode.rdoc47
-rw-r--r--doc/string/length.rdoc1
-rw-r--r--doc/string/new.rdoc4
-rw-r--r--doc/string/split.rdoc2
-rw-r--r--doc/strscan/helper_methods.md128
-rw-r--r--doc/strscan/link_refs.txt17
-rw-r--r--doc/strscan/methods/get_byte.md30
-rw-r--r--doc/strscan/methods/get_charpos.md19
-rw-r--r--doc/strscan/methods/get_pos.md14
-rw-r--r--doc/strscan/methods/getch.md43
-rw-r--r--doc/strscan/methods/scan.md51
-rw-r--r--doc/strscan/methods/scan_until.md52
-rw-r--r--doc/strscan/methods/set_pos.md27
-rw-r--r--doc/strscan/methods/skip.md43
-rw-r--r--doc/strscan/methods/skip_until.md49
-rw-r--r--doc/strscan/methods/terminate.md30
-rw-r--r--doc/strscan/strscan.md543
-rw-r--r--doc/syntax.rdoc5
-rw-r--r--doc/syntax/assignment.rdoc10
-rw-r--r--doc/syntax/calling_methods.rdoc14
-rw-r--r--doc/syntax/comments.rdoc2
-rw-r--r--doc/syntax/control_expressions.rdoc72
-rw-r--r--doc/syntax/exceptions.rdoc10
-rw-r--r--doc/syntax/keywords.rdoc162
-rw-r--r--doc/syntax/literals.rdoc183
-rw-r--r--doc/syntax/modules_and_classes.rdoc28
-rw-r--r--doc/syntax/operators.rdoc75
-rw-r--r--doc/syntax/pattern_matching.rdoc32
-rw-r--r--doc/syntax/refinements.rdoc2
-rw-r--r--doc/timezones.rdoc108
-rw-r--r--doc/transcode.rdoc52
-rw-r--r--doc/windows.md250
-rw-r--r--doc/yjit/yjit.md258
-rw-r--r--doc/yjit/yjit_hacking.md75
-rw-r--r--enc/Makefile.in6
-rw-r--r--enc/depend277
-rw-r--r--enc/ebcdic.h2
-rw-r--r--enc/encinit.c.erb3
-rw-r--r--enc/jis/props.h.blt17
-rwxr-xr-xenc/make_encmake.rb29
-rw-r--r--enc/trans/big5-uao-tbl.rb2
-rw-r--r--enc/trans/cp850-tbl.rb2
-rw-r--r--enc/trans/cp852-tbl.rb2
-rw-r--r--enc/trans/cp855-tbl.rb2
-rw-r--r--enc/trans/gbk-tbl.rb2
-rw-r--r--enc/trans/ibm437-tbl.rb2
-rw-r--r--enc/trans/ibm775-tbl.rb2
-rw-r--r--enc/trans/ibm852-tbl.rb2
-rw-r--r--enc/trans/ibm855-tbl.rb2
-rw-r--r--enc/trans/ibm857-tbl.rb2
-rw-r--r--enc/trans/ibm860-tbl.rb2
-rw-r--r--enc/trans/ibm861-tbl.rb2
-rw-r--r--enc/trans/ibm862-tbl.rb2
-rw-r--r--enc/trans/ibm863-tbl.rb2
-rw-r--r--enc/trans/ibm864-tbl.rb126
-rw-r--r--enc/trans/ibm865-tbl.rb2
-rw-r--r--enc/trans/ibm866-tbl.rb2
-rw-r--r--enc/trans/ibm869-tbl.rb2
-rw-r--r--enc/trans/iso2022.trans147
-rw-r--r--enc/trans/koi8-r-tbl.rb2
-rw-r--r--enc/trans/koi8-u-tbl.rb2
-rw-r--r--enc/trans/maccroatian-tbl.rb2
-rw-r--r--enc/trans/maccyrillic-tbl.rb2
-rw-r--r--enc/trans/macgreek-tbl.rb2
-rw-r--r--enc/trans/maciceland-tbl.rb2
-rw-r--r--enc/trans/macroman-tbl.rb2
-rw-r--r--enc/trans/macromania-tbl.rb2
-rw-r--r--enc/trans/macturkish-tbl.rb2
-rw-r--r--enc/trans/macukraine-tbl.rb2
-rw-r--r--enc/trans/single_byte.trans1
-rw-r--r--enc/trans/windows-1250-tbl.rb2
-rw-r--r--enc/trans/windows-1251-tbl.rb2
-rw-r--r--enc/trans/windows-1252-tbl.rb2
-rw-r--r--enc/trans/windows-1253-tbl.rb2
-rw-r--r--enc/trans/windows-1254-tbl.rb2
-rw-r--r--enc/trans/windows-1256-tbl.rb2
-rw-r--r--enc/trans/windows-1257-tbl.rb2
-rw-r--r--enc/trans/windows-874-tbl.rb2
-rw-r--r--enc/unicode/15.0.0/name2ctype.h2
-rw-r--r--encoding.c100
-rw-r--r--enum.c614
-rw-r--r--enumerator.c234
-rw-r--r--error.c1139
-rw-r--r--eval.c254
-rw-r--r--eval_error.c36
-rw-r--r--eval_intern.h33
-rw-r--r--eval_jump.c28
-rw-r--r--ext/-test-/RUBY_ALIGNOF/depend4
-rw-r--r--ext/-test-/arith_seq/beg_len_step/depend4
-rw-r--r--ext/-test-/arith_seq/extract/depend4
-rw-r--r--ext/-test-/array/concat/depend4
-rw-r--r--ext/-test-/array/resize/depend4
-rw-r--r--ext/-test-/asan/asan.c24
-rw-r--r--ext/-test-/asan/extconf.rb2
-rw-r--r--ext/-test-/bignum/depend28
-rw-r--r--ext/-test-/bug-14834/bug-14384.c39
-rw-r--r--ext/-test-/bug-14834/bug-14834.c39
-rw-r--r--ext/-test-/bug-14834/depend320
-rw-r--r--ext/-test-/bug-3571/depend4
-rw-r--r--ext/-test-/bug-5832/depend4
-rw-r--r--ext/-test-/bug_reporter/depend4
-rw-r--r--ext/-test-/class/depend8
-rw-r--r--ext/-test-/class/init.c1
-rw-r--r--ext/-test-/debug/depend12
-rw-r--r--ext/-test-/debug/profile_frames.c21
-rw-r--r--ext/-test-/dln/empty/depend4
-rw-r--r--ext/-test-/ensure_and_callcc/ensure_and_callcc.c58
-rw-r--r--ext/-test-/ensure_and_callcc/extconf.rb5
-rw-r--r--ext/-test-/enumerator_kw/depend4
-rw-r--r--ext/-test-/exception/depend16
-rw-r--r--ext/-test-/fatal/depend325
-rw-r--r--ext/-test-/fatal/extconf.rb3
-rw-r--r--ext/-test-/fatal/init.c10
-rw-r--r--ext/-test-/fatal/invalid.c28
-rw-r--r--ext/-test-/fatal/rb_fatal.c3
-rw-r--r--ext/-test-/file/depend184
-rw-r--r--ext/-test-/file/newline_conv.c73
-rw-r--r--ext/-test-/float/depend8
-rw-r--r--ext/-test-/funcall/depend4
-rw-r--r--ext/-test-/gvl/call_without_gvl/depend4
-rw-r--r--ext/-test-/hash/depend8
-rw-r--r--ext/-test-/integer/depend12
-rw-r--r--ext/-test-/integer/my_integer.c6
-rw-r--r--ext/-test-/iseq_load/depend4
-rw-r--r--ext/-test-/iter/depend12
-rw-r--r--ext/-test-/load/dot.dot/depend4
-rw-r--r--ext/-test-/load/protect/depend4
-rw-r--r--ext/-test-/load/resolve_symbol_resolver/extconf.rb1
-rw-r--r--ext/-test-/load/resolve_symbol_resolver/resolve_symbol_resolver.c55
-rw-r--r--ext/-test-/load/resolve_symbol_target/extconf.rb1
-rw-r--r--ext/-test-/load/resolve_symbol_target/resolve_symbol_target.c15
-rw-r--r--ext/-test-/load/resolve_symbol_target/resolve_symbol_target.h4
-rw-r--r--ext/-test-/load/stringify_symbols/extconf.rb1
-rw-r--r--ext/-test-/load/stringify_symbols/stringify_symbols.c29
-rw-r--r--ext/-test-/load/stringify_target/extconf.rb1
-rw-r--r--ext/-test-/load/stringify_target/stringify_target.c15
-rw-r--r--ext/-test-/load/stringify_target/stringify_target.h4
-rw-r--r--ext/-test-/marshal/compat/depend4
-rw-r--r--ext/-test-/marshal/internal_ivar/depend4
-rw-r--r--ext/-test-/marshal/usr/depend4
-rw-r--r--ext/-test-/memory_status/depend3
-rw-r--r--ext/-test-/memory_view/depend4
-rw-r--r--ext/-test-/memory_view/memory_view.c4
-rw-r--r--ext/-test-/method/depend8
-rw-r--r--ext/-test-/notimplement/depend4
-rw-r--r--ext/-test-/num2int/depend4
-rw-r--r--ext/-test-/path_to_class/depend4
-rw-r--r--ext/-test-/popen_deadlock/depend4
-rw-r--r--ext/-test-/postponed_job/depend4
-rw-r--r--ext/-test-/postponed_job/postponed_job.c131
-rw-r--r--ext/-test-/printf/depend4
-rw-r--r--ext/-test-/proc/depend12
-rw-r--r--ext/-test-/public_header_warnings/extconf.rb28
-rw-r--r--ext/-test-/random/depend12
-rw-r--r--ext/-test-/random/loop.c11
-rw-r--r--ext/-test-/rational/depend4
-rw-r--r--ext/-test-/rb_call_super_kw/depend4
-rw-r--r--ext/-test-/recursion/depend4
-rw-r--r--ext/-test-/regexp/depend8
-rw-r--r--ext/-test-/scan_args/depend4
-rw-r--r--ext/-test-/st/foreach/depend4
-rw-r--r--ext/-test-/st/foreach/foreach.c30
-rw-r--r--ext/-test-/st/numhash/depend4
-rw-r--r--ext/-test-/st/update/depend4
-rw-r--r--ext/-test-/string/cstr.c14
-rw-r--r--ext/-test-/string/depend399
-rw-r--r--ext/-test-/string/enc_dummy.c15
-rw-r--r--ext/-test-/string/fstring.c14
-rw-r--r--ext/-test-/string/set_len.c8
-rw-r--r--ext/-test-/struct/data.c13
-rw-r--r--ext/-test-/struct/depend176
-rw-r--r--ext/-test-/struct/member.c2
-rw-r--r--ext/-test-/symbol/depend8
-rw-r--r--ext/-test-/thread/id/extconf.rb3
-rw-r--r--ext/-test-/thread/id/id.c15
-rw-r--r--ext/-test-/thread/instrumentation/depend4
-rw-r--r--ext/-test-/thread/instrumentation/instrumentation.c215
-rw-r--r--ext/-test-/thread/lock_native_thread/extconf.rb2
-rw-r--r--ext/-test-/thread/lock_native_thread/lock_native_thread.c50
-rw-r--r--ext/-test-/thread_fd/depend4
-rw-r--r--ext/-test-/time/depend12
-rw-r--r--ext/-test-/tracepoint/depend8
-rw-r--r--ext/-test-/tracepoint/gc_hook.c4
-rw-r--r--ext/-test-/typeddata/depend4
-rw-r--r--ext/-test-/vm/depend4
-rw-r--r--ext/-test-/wait/depend4
-rw-r--r--ext/.document6
-rw-r--r--ext/Setup3
-rw-r--r--ext/Setup.atheos6
-rw-r--r--ext/Setup.nt6
-rw-r--r--ext/bigdecimal/bigdecimal.c7724
-rw-r--r--ext/bigdecimal/bigdecimal.gemspec38
-rw-r--r--ext/bigdecimal/bigdecimal.h313
-rw-r--r--ext/bigdecimal/bits.h141
-rw-r--r--ext/bigdecimal/depend330
-rw-r--r--ext/bigdecimal/extconf.rb87
-rw-r--r--ext/bigdecimal/feature.h68
-rw-r--r--ext/bigdecimal/lib/bigdecimal.rb1
-rw-r--r--ext/bigdecimal/lib/bigdecimal/jacobian.rb90
-rw-r--r--ext/bigdecimal/lib/bigdecimal/ludcmp.rb89
-rw-r--r--ext/bigdecimal/lib/bigdecimal/math.rb232
-rw-r--r--ext/bigdecimal/lib/bigdecimal/newton.rb80
-rw-r--r--ext/bigdecimal/lib/bigdecimal/util.rb185
-rw-r--r--ext/bigdecimal/missing.c27
-rw-r--r--ext/bigdecimal/missing.h196
-rw-r--r--ext/bigdecimal/missing/dtoa.c3462
-rw-r--r--ext/bigdecimal/sample/linear.rb74
-rw-r--r--ext/bigdecimal/sample/nlsolve.rb40
-rw-r--r--ext/bigdecimal/sample/pi.rb21
-rw-r--r--ext/bigdecimal/static_assert.h54
-rw-r--r--ext/cgi/escape/depend4
-rw-r--r--ext/cgi/escape/escape.c35
-rw-r--r--ext/cgi/escape/extconf.rb6
-rw-r--r--ext/continuation/depend4
-rw-r--r--ext/coverage/coverage.c8
-rw-r--r--ext/coverage/depend18
-rw-r--r--ext/date/date.gemspec2
-rw-r--r--ext/date/date_core.c52
-rw-r--r--ext/date/date_parse.c3
-rw-r--r--ext/date/date_strptime.c3
-rw-r--r--ext/date/depend16
-rw-r--r--ext/date/lib/date.rb2
-rw-r--r--ext/date/prereq.mk2
-rw-r--r--ext/date/zonetab.h1250
-rw-r--r--ext/date/zonetab.list7
-rw-r--r--ext/digest/.document3
-rw-r--r--ext/digest/bubblebabble/bubblebabble.c7
-rw-r--r--ext/digest/bubblebabble/depend4
-rw-r--r--ext/digest/depend4
-rw-r--r--ext/digest/digest.c42
-rw-r--r--ext/digest/digest.h22
-rw-r--r--ext/digest/md5/depend8
-rw-r--r--ext/digest/md5/md5cc.h20
-rw-r--r--ext/digest/md5/md5init.c3
-rw-r--r--ext/digest/rmd160/depend8
-rw-r--r--ext/digest/rmd160/rmd160init.c3
-rw-r--r--ext/digest/sha1/depend8
-rw-r--r--ext/digest/sha1/sha1cc.h8
-rw-r--r--ext/digest/sha1/sha1init.c3
-rw-r--r--ext/digest/sha2/depend8
-rw-r--r--ext/digest/sha2/sha2cc.h39
-rw-r--r--ext/digest/sha2/sha2init.c47
-rw-r--r--ext/erb/escape/extconf.rb3
-rw-r--r--ext/etc/.document2
-rw-r--r--ext/etc/depend4
-rw-r--r--ext/etc/etc.c126
-rw-r--r--ext/etc/extconf.rb14
-rw-r--r--ext/etc/mkconstants.rb32
-rwxr-xr-xext/extmk.rb79
-rw-r--r--ext/fcntl/depend4
-rw-r--r--ext/fcntl/fcntl.c104
-rw-r--r--ext/fcntl/fcntl.gemspec15
-rw-r--r--ext/fiddle/closure.c34
-rw-r--r--ext/fiddle/conversions.c57
-rw-r--r--ext/fiddle/conversions.h2
-rw-r--r--ext/fiddle/depend32
-rw-r--r--ext/fiddle/extconf.rb5
-rw-r--r--ext/fiddle/fiddle.c54
-rw-r--r--ext/fiddle/fiddle.gemspec5
-rw-r--r--ext/fiddle/fiddle.h19
-rw-r--r--ext/fiddle/function.c10
-rw-r--r--ext/fiddle/handle.c11
-rw-r--r--ext/fiddle/lib/fiddle/cparser.rb28
-rw-r--r--ext/fiddle/lib/fiddle/import.rb2
-rw-r--r--ext/fiddle/lib/fiddle/pack.rb12
-rw-r--r--ext/fiddle/lib/fiddle/value.rb28
-rw-r--r--ext/fiddle/lib/fiddle/version.rb2
-rw-r--r--ext/fiddle/pointer.c50
-rw-r--r--ext/fiddle/win32/fficonfig.h29
-rw-r--r--ext/fiddle/win32/libffi-3.2.1-mswin.patch191
-rwxr-xr-xext/fiddle/win32/libffi-config.rb48
-rw-r--r--ext/fiddle/win32/libffi.mk.tmpl96
-rw-r--r--ext/io/console/.document2
-rw-r--r--ext/io/console/console.c878
-rw-r--r--ext/io/console/depend5
-rw-r--r--ext/io/console/extconf.rb21
-rw-r--r--ext/io/console/io-console.gemspec29
-rw-r--r--ext/io/console/win32_vk.inc2
-rw-r--r--ext/io/nonblock/depend4
-rw-r--r--ext/io/nonblock/extconf.rb7
-rw-r--r--ext/io/nonblock/io-nonblock.gemspec2
-rw-r--r--ext/io/nonblock/nonblock.c71
-rw-r--r--ext/io/wait/depend4
-rw-r--r--ext/io/wait/extconf.rb3
-rw-r--r--ext/io/wait/io-wait.gemspec2
-rw-r--r--ext/io/wait/wait.c11
-rw-r--r--ext/json/VERSION1
-rw-r--r--ext/json/fbuffer/fbuffer.h30
-rw-r--r--ext/json/generator/depend4
-rw-r--r--ext/json/generator/extconf.rb9
-rw-r--r--ext/json/generator/generator.c236
-rw-r--r--ext/json/generator/generator.h21
-rw-r--r--ext/json/json.gemspec13
-rw-r--r--ext/json/lib/json.rb9
-rw-r--r--ext/json/lib/json/add/bigdecimal.rb45
-rw-r--r--ext/json/lib/json/add/complex.rb33
-rw-r--r--ext/json/lib/json/add/date.rb32
-rw-r--r--ext/json/lib/json/add/date_time.rb33
-rw-r--r--ext/json/lib/json/add/exception.rb30
-rw-r--r--ext/json/lib/json/add/ostruct.rb39
-rw-r--r--ext/json/lib/json/add/range.rb39
-rw-r--r--ext/json/lib/json/add/rational.rb32
-rw-r--r--ext/json/lib/json/add/regexp.rb32
-rw-r--r--ext/json/lib/json/add/set.rb31
-rw-r--r--ext/json/lib/json/add/struct.rb34
-rw-r--r--ext/json/lib/json/add/symbol.rb31
-rw-r--r--ext/json/lib/json/add/time.rb31
-rw-r--r--ext/json/lib/json/common.rb63
-rw-r--r--ext/json/lib/json/ext.rb18
-rw-r--r--ext/json/lib/json/generic_object.rb8
-rw-r--r--ext/json/lib/json/version.rb2
-rw-r--r--ext/json/parser/depend4
-rw-r--r--ext/json/parser/extconf.rb4
-rw-r--r--ext/json/parser/parser.c4800
-rw-r--r--ext/json/parser/parser.h7
-rw-r--r--ext/json/parser/parser.rl223
-rw-r--r--ext/monitor/depend4
-rw-r--r--ext/monitor/lib/monitor.rb13
-rw-r--r--ext/monitor/monitor.c2
-rw-r--r--ext/nkf/depend182
-rw-r--r--ext/nkf/extconf.rb3
-rw-r--r--ext/nkf/lib/kconv.rb283
-rw-r--r--ext/nkf/nkf-utf8/config.h51
-rw-r--r--ext/nkf/nkf-utf8/nkf.c7205
-rw-r--r--ext/nkf/nkf-utf8/nkf.h189
-rw-r--r--ext/nkf/nkf-utf8/utf8tbl.c14638
-rw-r--r--ext/nkf/nkf-utf8/utf8tbl.h72
-rw-r--r--ext/nkf/nkf.c503
-rw-r--r--ext/nkf/nkf.gemspec24
-rw-r--r--ext/objspace/depend65
-rw-r--r--ext/objspace/lib/objspace.rb35
-rw-r--r--ext/objspace/object_tracing.c2
-rw-r--r--ext/objspace/objspace.c157
-rw-r--r--ext/objspace/objspace_dump.c67
-rw-r--r--ext/openssl/History.md42
-rw-r--r--ext/openssl/depend355
-rw-r--r--ext/openssl/extconf.rb43
-rw-r--r--ext/openssl/lib/openssl.rb3
-rw-r--r--ext/openssl/lib/openssl/asn1.rb188
-rw-r--r--ext/openssl/lib/openssl/bn.rb2
-rw-r--r--ext/openssl/lib/openssl/buffering.rb40
-rw-r--r--ext/openssl/lib/openssl/cipher.rb2
-rw-r--r--ext/openssl/lib/openssl/digest.rb8
-rw-r--r--ext/openssl/lib/openssl/marshal.rb2
-rw-r--r--ext/openssl/lib/openssl/ssl.rb88
-rw-r--r--ext/openssl/lib/openssl/version.rb2
-rw-r--r--ext/openssl/lib/openssl/x509.rb2
-rw-r--r--ext/openssl/openssl.gemspec22
-rw-r--r--ext/openssl/openssl_missing.c2
-rw-r--r--ext/openssl/openssl_missing.h2
-rw-r--r--ext/openssl/ossl.c270
-rw-r--r--ext/openssl/ossl.h13
-rw-r--r--ext/openssl/ossl_asn1.c249
-rw-r--r--ext/openssl/ossl_asn1.h4
-rw-r--r--ext/openssl/ossl_bio.c2
-rw-r--r--ext/openssl/ossl_bio.h2
-rw-r--r--ext/openssl/ossl_bn.c4
-rw-r--r--ext/openssl/ossl_bn.h2
-rw-r--r--ext/openssl/ossl_cipher.c26
-rw-r--r--ext/openssl/ossl_cipher.h2
-rw-r--r--ext/openssl/ossl_config.c4
-rw-r--r--ext/openssl/ossl_config.h2
-rw-r--r--ext/openssl/ossl_digest.c37
-rw-r--r--ext/openssl/ossl_digest.h2
-rw-r--r--ext/openssl/ossl_engine.c4
-rw-r--r--ext/openssl/ossl_engine.h2
-rw-r--r--ext/openssl/ossl_hmac.c4
-rw-r--r--ext/openssl/ossl_hmac.h2
-rw-r--r--ext/openssl/ossl_kdf.c12
-rw-r--r--ext/openssl/ossl_ns_spki.c8
-rw-r--r--ext/openssl/ossl_ns_spki.h2
-rw-r--r--ext/openssl/ossl_ocsp.c14
-rw-r--r--ext/openssl/ossl_ocsp.h2
-rw-r--r--ext/openssl/ossl_pkcs12.c12
-rw-r--r--ext/openssl/ossl_pkcs12.h2
-rw-r--r--ext/openssl/ossl_pkcs7.c36
-rw-r--r--ext/openssl/ossl_pkcs7.h2
-rw-r--r--ext/openssl/ossl_pkey.c263
-rw-r--r--ext/openssl/ossl_pkey.h2
-rw-r--r--ext/openssl/ossl_pkey_dh.c31
-rw-r--r--ext/openssl/ossl_pkey_dsa.c67
-rw-r--r--ext/openssl/ossl_pkey_ec.c74
-rw-r--r--ext/openssl/ossl_pkey_rsa.c83
-rw-r--r--ext/openssl/ossl_provider.c211
-rw-r--r--ext/openssl/ossl_provider.h5
-rw-r--r--ext/openssl/ossl_rand.c2
-rw-r--r--ext/openssl/ossl_rand.h2
-rw-r--r--ext/openssl/ossl_ssl.c169
-rw-r--r--ext/openssl/ossl_ssl.h2
-rw-r--r--ext/openssl/ossl_ssl_session.c2
-rw-r--r--ext/openssl/ossl_ts.c68
-rw-r--r--ext/openssl/ossl_ts.h2
-rw-r--r--ext/openssl/ossl_x509.c2
-rw-r--r--ext/openssl/ossl_x509.h2
-rw-r--r--ext/openssl/ossl_x509attr.c51
-rw-r--r--ext/openssl/ossl_x509cert.c45
-rw-r--r--ext/openssl/ossl_x509crl.c4
-rw-r--r--ext/openssl/ossl_x509ext.c22
-rw-r--r--ext/openssl/ossl_x509name.c4
-rw-r--r--ext/openssl/ossl_x509req.c4
-rw-r--r--ext/openssl/ossl_x509revoked.c4
-rw-r--r--ext/openssl/ossl_x509store.c36
-rw-r--r--ext/pathname/depend4
-rw-r--r--ext/pathname/extconf.rb1
-rw-r--r--ext/pathname/lib/pathname.rb27
-rw-r--r--ext/pathname/pathname.c33
-rw-r--r--ext/pathname/pathname.gemspec11
-rw-r--r--ext/psych/depend20
-rw-r--r--ext/psych/extconf.rb2
-rw-r--r--ext/psych/lib/psych.rb64
-rw-r--r--ext/psych/lib/psych/class_loader.rb2
-rw-r--r--ext/psych/lib/psych/nodes/node.rb2
-rw-r--r--ext/psych/lib/psych/scalar_scanner.rb19
-rw-r--r--ext/psych/lib/psych/tree_builder.rb4
-rw-r--r--ext/psych/lib/psych/versions.rb4
-rw-r--r--ext/psych/lib/psych/visitors/to_ruby.rb4
-rw-r--r--ext/psych/lib/psych/visitors/yaml_tree.rb34
-rw-r--r--ext/psych/psych.c2
-rw-r--r--ext/psych/psych.gemspec50
-rw-r--r--ext/psych/psych_emitter.c274
-rw-r--r--ext/psych/psych_parser.c524
-rw-r--r--ext/pty/depend4
-rw-r--r--ext/pty/extconf.rb7
-rw-r--r--ext/pty/pty.c200
-rw-r--r--ext/racc/cparse/README11
-rw-r--r--ext/racc/cparse/cparse.c861
-rw-r--r--ext/racc/cparse/depend162
-rw-r--r--ext/racc/cparse/extconf.rb9
-rw-r--r--ext/rbconfig/sizeof/depend8
-rw-r--r--ext/readline/.gitignore1
-rw-r--r--ext/readline/README10
-rw-r--r--ext/readline/README.ja386
-rw-r--r--ext/readline/depend175
-rw-r--r--ext/readline/depend-gem4
-rw-r--r--ext/readline/extconf.rb112
-rw-r--r--ext/readline/readline-ext.gemspec22
-rw-r--r--ext/readline/readline.c2144
-rw-r--r--ext/ripper/README1
-rw-r--r--ext/ripper/depend578
-rw-r--r--ext/ripper/eventids2.c14
-rw-r--r--ext/ripper/eventids2.h8
-rw-r--r--ext/ripper/extconf.rb15
-rw-r--r--ext/ripper/ripper_init.c.tmpl680
-rw-r--r--ext/ripper/ripper_init.h6
-rw-r--r--ext/ripper/tools/dsl.rb173
-rw-r--r--ext/ripper/tools/generate.rb51
-rw-r--r--ext/ripper/tools/preproc.rb115
-rw-r--r--ext/socket/ancdata.c4
-rw-r--r--ext/socket/basicsocket.c4
-rw-r--r--ext/socket/depend345
-rw-r--r--ext/socket/extconf.rb25
-rw-r--r--ext/socket/getaddrinfo.c3
-rw-r--r--ext/socket/init.c82
-rw-r--r--ext/socket/lib/socket.rb444
-rw-r--r--ext/socket/mkconstants.rb46
-rw-r--r--ext/socket/raddrinfo.c541
-rw-r--r--ext/socket/rubysocket.h6
-rw-r--r--ext/socket/socket.c5
-rw-r--r--ext/socket/sockssocket.c2
-rw-r--r--ext/socket/unixsocket.c2
-rw-r--r--ext/stringio/.document1
-rw-r--r--ext/stringio/depend4
-rw-r--r--ext/stringio/extconf.rb7
-rw-r--r--ext/stringio/stringio.c349
-rw-r--r--ext/stringio/stringio.gemspec14
-rw-r--r--ext/strscan/depend4
-rw-r--r--ext/strscan/extconf.rb4
-rw-r--r--ext/strscan/strscan.c1357
-rw-r--r--ext/strscan/strscan.gemspec5
-rw-r--r--ext/syslog/depend162
-rw-r--r--ext/syslog/extconf.rb13
-rw-r--r--ext/syslog/lib/syslog/logger.rb209
-rw-r--r--ext/syslog/syslog.c588
-rw-r--r--ext/syslog/syslog.gemspec23
-rw-r--r--ext/syslog/syslog.txt124
-rw-r--r--ext/win32/lib/win32/registry.rb30
-rw-r--r--ext/win32/lib/win32/sspi.rb39
-rw-r--r--ext/win32/resolv/extconf.rb3
-rw-r--r--ext/win32ole/.document1
-rw-r--r--ext/win32ole/lib/win32ole.rb3
-rw-r--r--ext/win32ole/lib/win32ole/property.rb18
-rw-r--r--ext/win32ole/sample/excel1.rb (renamed from sample/win32ole/excel1.rb)0
-rw-r--r--ext/win32ole/sample/excel2.rb (renamed from sample/win32ole/excel2.rb)0
-rw-r--r--ext/win32ole/sample/excel3.rb (renamed from sample/win32ole/excel3.rb)0
-rw-r--r--ext/win32ole/sample/ie.rb (renamed from sample/win32ole/ie.rb)0
-rw-r--r--ext/win32ole/sample/ieconst.rb (renamed from sample/win32ole/ieconst.rb)0
-rw-r--r--ext/win32ole/sample/ienavi.rb (renamed from sample/win32ole/ienavi.rb)0
-rw-r--r--ext/win32ole/sample/ienavi2.rb (renamed from sample/win32ole/ienavi2.rb)0
-rw-r--r--ext/win32ole/sample/oledirs.rb (renamed from sample/win32ole/oledirs.rb)0
-rw-r--r--ext/win32ole/sample/olegen.rb348
-rw-r--r--ext/win32ole/sample/xml.rb (renamed from sample/win32ole/xml.rb)0
-rw-r--r--ext/win32ole/win32ole.c204
-rw-r--r--ext/win32ole/win32ole.gemspec21
-rw-r--r--ext/win32ole/win32ole_error.c17
-rw-r--r--ext/win32ole/win32ole_event.c51
-rw-r--r--ext/win32ole/win32ole_method.c127
-rw-r--r--ext/win32ole/win32ole_param.c113
-rw-r--r--ext/win32ole/win32ole_record.c51
-rw-r--r--ext/win32ole/win32ole_type.c142
-rw-r--r--ext/win32ole/win32ole_typelib.c75
-rw-r--r--ext/win32ole/win32ole_variable.c37
-rw-r--r--ext/win32ole/win32ole_variant.c67
-rw-r--r--ext/win32ole/win32ole_variant_m.c12
-rw-r--r--ext/zlib/depend4
-rw-r--r--ext/zlib/extconf.rb17
-rw-r--r--ext/zlib/zlib.c121
-rw-r--r--ext/zlib/zlib.gemspec4
-rw-r--r--file.c1107
-rw-r--r--gc.c13974
-rw-r--r--gc.h147
-rw-r--r--gc.rb200
-rw-r--r--gc/default.c9424
-rw-r--r--gc/gc.h185
-rw-r--r--gc/gc_impl.h103
-rw-r--r--gem_prelude.rb2
-rw-r--r--gems/bundled_gems53
-rw-r--r--goruby.c10
-rw-r--r--hash.c1310
-rw-r--r--hash.rb40
-rw-r--r--hrtime.h14
-rw-r--r--id_table.c10
-rw-r--r--imemo.c597
-rw-r--r--include/ruby/assert.h112
-rw-r--r--include/ruby/atomic.h69
-rw-r--r--include/ruby/backward/2/attributes.h24
-rw-r--r--include/ruby/debug.h171
-rw-r--r--include/ruby/fiber/scheduler.h80
-rw-r--r--include/ruby/intern.h1
-rw-r--r--include/ruby/internal/abi.h4
-rw-r--r--include/ruby/internal/anyargs.h22
-rw-r--r--include/ruby/internal/arithmetic/long.h14
-rw-r--r--include/ruby/internal/arithmetic/long_long.h2
-rw-r--r--include/ruby/internal/arithmetic/st_data_t.h4
-rw-r--r--include/ruby/internal/attr/noexcept.h2
-rw-r--r--include/ruby/internal/attr/nonstring.h32
-rw-r--r--include/ruby/internal/attr/packed_struct.h43
-rw-r--r--include/ruby/internal/config.h4
-rw-r--r--include/ruby/internal/core/rarray.h198
-rw-r--r--include/ruby/internal/core/rbasic.h18
-rw-r--r--include/ruby/internal/core/rdata.h17
-rw-r--r--include/ruby/internal/core/rfile.h4
-rw-r--r--include/ruby/internal/core/rhash.h13
-rw-r--r--include/ruby/internal/core/rmatch.h14
-rw-r--r--include/ruby/internal/core/robject.h26
-rw-r--r--include/ruby/internal/core/rstring.h118
-rw-r--r--include/ruby/internal/core/rtypeddata.h57
-rw-r--r--include/ruby/internal/dllexport.h34
-rw-r--r--include/ruby/internal/encoding/encoding.h20
-rw-r--r--include/ruby/internal/encoding/string.h8
-rw-r--r--include/ruby/internal/error.h36
-rw-r--r--include/ruby/internal/event.h5
-rw-r--r--include/ruby/internal/fl_type.h113
-rw-r--r--include/ruby/internal/gc.h767
-rw-r--r--include/ruby/internal/globals.h2
-rw-r--r--include/ruby/internal/has/c_attribute.h12
-rw-r--r--include/ruby/internal/intern/array.h10
-rw-r--r--include/ruby/internal/intern/bignum.h4
-rw-r--r--include/ruby/internal/intern/class.h8
-rw-r--r--include/ruby/internal/intern/error.h20
-rw-r--r--include/ruby/internal/intern/gc.h392
-rw-r--r--include/ruby/internal/intern/io.h2
-rw-r--r--include/ruby/internal/intern/load.h37
-rw-r--r--include/ruby/internal/intern/object.h3
-rw-r--r--include/ruby/internal/intern/process.h11
-rw-r--r--include/ruby/internal/intern/re.h5
-rw-r--r--include/ruby/internal/intern/select.h2
-rw-r--r--include/ruby/internal/intern/signal.h8
-rw-r--r--include/ruby/internal/intern/string.h4
-rw-r--r--include/ruby/internal/intern/struct.h38
-rw-r--r--include/ruby/internal/intern/vm.h3
-rw-r--r--include/ruby/internal/interpreter.h2
-rw-r--r--include/ruby/internal/memory.h12
-rw-r--r--include/ruby/internal/module.h16
-rw-r--r--include/ruby/internal/newobj.h53
-rw-r--r--include/ruby/internal/rgengc.h443
-rw-r--r--include/ruby/internal/scan_args.h2
-rw-r--r--include/ruby/internal/special_consts.h6
-rw-r--r--include/ruby/internal/static_assert.h2
-rw-r--r--include/ruby/internal/stdckdint.h68
-rw-r--r--include/ruby/internal/value_type.h9
-rw-r--r--include/ruby/internal/xmalloc.h104
-rw-r--r--include/ruby/io.h128
-rw-r--r--include/ruby/io/buffer.h22
-rw-r--r--include/ruby/memory_view.h4
-rw-r--r--include/ruby/onigmo.h5
-rw-r--r--include/ruby/random.h2
-rw-r--r--include/ruby/re.h25
-rw-r--r--include/ruby/ruby.h125
-rw-r--r--include/ruby/thread.h100
-rw-r--r--include/ruby/thread_native.h5
-rw-r--r--include/ruby/util.h13
-rw-r--r--include/ruby/version.h2
-rw-r--r--include/ruby/vm.h7
-rw-r--r--include/ruby/win32.h16
-rw-r--r--inits.c17
-rw-r--r--insns.def324
-rw-r--r--internal.h5
-rw-r--r--internal/array.h33
-rw-r--r--internal/basic_operators.h4
-rw-r--r--internal/bignum.h2
-rw-r--r--internal/bits.h31
-rw-r--r--internal/class.h140
-rw-r--r--internal/cmdlineopt.h12
-rw-r--r--internal/compile.h3
-rw-r--r--internal/cont.h3
-rw-r--r--internal/encoding.h4
-rw-r--r--internal/error.h31
-rw-r--r--internal/gc.h244
-rw-r--r--internal/hash.h94
-rw-r--r--internal/imemo.h39
-rw-r--r--internal/inits.h3
-rw-r--r--internal/io.h105
-rw-r--r--internal/missing.h1
-rw-r--r--internal/numeric.h5
-rw-r--r--internal/object.h6
-rw-r--r--internal/parse.h118
-rw-r--r--internal/proc.h2
-rw-r--r--internal/process.h15
-rw-r--r--internal/random.h1
-rw-r--r--internal/range.h4
-rw-r--r--internal/rational.h1
-rw-r--r--internal/re.h4
-rw-r--r--internal/ruby_parser.h102
-rw-r--r--internal/sanitizers.h190
-rw-r--r--internal/signal.h5
-rw-r--r--internal/st.h11
-rw-r--r--internal/string.h57
-rw-r--r--internal/struct.h44
-rw-r--r--internal/symbol.h3
-rw-r--r--internal/thread.h33
-rw-r--r--internal/time.h5
-rw-r--r--internal/transcode.h3
-rw-r--r--internal/variable.h60
-rw-r--r--internal/vm.h35
-rw-r--r--io.c1448
-rw-r--r--io.rb13
-rw-r--r--io_buffer.c905
-rw-r--r--iseq.c957
-rw-r--r--iseq.h36
-rw-r--r--kernel.rb181
-rw-r--r--lex.c.blt85
-rw-r--r--lib/English.gemspec4
-rw-r--r--lib/English.rb60
-rw-r--r--lib/abbrev.gemspec22
-rw-r--r--lib/abbrev.rb132
-rw-r--r--lib/base64.gemspec20
-rw-r--r--lib/base64.rb110
-rw-r--r--lib/benchmark.gemspec32
-rw-r--r--lib/benchmark.rb6
-rw-r--r--lib/benchmark/benchmark.gemspec29
-rw-r--r--lib/benchmark/version.rb4
-rw-r--r--lib/bundled_gems.rb273
-rw-r--r--lib/bundler.rb183
-rw-r--r--lib/bundler/build_metadata.rb2
-rw-r--r--lib/bundler/bundler.gemspec8
-rw-r--r--lib/bundler/capistrano.rb2
-rw-r--r--lib/bundler/checksum.rb254
-rw-r--r--lib/bundler/ci_detector.rb75
-rw-r--r--lib/bundler/cli.rb519
-rw-r--r--lib/bundler/cli/add.rb8
-rw-r--r--lib/bundler/cli/binstubs.rb8
-rw-r--r--lib/bundler/cli/cache.rb2
-rw-r--r--lib/bundler/cli/check.rb6
-rw-r--r--lib/bundler/cli/common.rb10
-rw-r--r--lib/bundler/cli/config.rb15
-rw-r--r--lib/bundler/cli/console.rb5
-rw-r--r--lib/bundler/cli/doctor.rb4
-rw-r--r--lib/bundler/cli/exec.rb2
-rw-r--r--lib/bundler/cli/fund.rb2
-rw-r--r--lib/bundler/cli/gem.rb86
-rw-r--r--lib/bundler/cli/info.rb15
-rw-r--r--lib/bundler/cli/install.rb32
-rw-r--r--lib/bundler/cli/issue.rb2
-rw-r--r--lib/bundler/cli/lock.rb62
-rw-r--r--lib/bundler/cli/open.rb12
-rw-r--r--lib/bundler/cli/outdated.rb46
-rw-r--r--lib/bundler/cli/plugin.rb24
-rw-r--r--lib/bundler/cli/pristine.rb68
-rw-r--r--lib/bundler/cli/show.rb4
-rw-r--r--lib/bundler/cli/update.rb11
-rw-r--r--lib/bundler/compact_index_client.rb138
-rw-r--r--lib/bundler/compact_index_client/cache.rb115
-rw-r--r--lib/bundler/compact_index_client/cache_file.rb148
-rw-r--r--lib/bundler/compact_index_client/gem_parser.rb10
-rw-r--r--lib/bundler/compact_index_client/parser.rb84
-rw-r--r--lib/bundler/compact_index_client/updater.rb151
-rw-r--r--lib/bundler/constants.rb9
-rw-r--r--lib/bundler/current_ruby.rb26
-rw-r--r--lib/bundler/definition.rb395
-rw-r--r--lib/bundler/dependency.rb35
-rw-r--r--lib/bundler/digest.rb4
-rw-r--r--lib/bundler/dsl.rb140
-rw-r--r--lib/bundler/endpoint_specification.rb19
-rw-r--r--lib/bundler/env.rb10
-rw-r--r--lib/bundler/environment_preserver.rb28
-rw-r--r--lib/bundler/errors.rb74
-rw-r--r--lib/bundler/fetcher.rb120
-rw-r--r--lib/bundler/fetcher/base.rb8
-rw-r--r--lib/bundler/fetcher/compact_index.rb53
-rw-r--r--lib/bundler/fetcher/dependency.rb2
-rw-r--r--lib/bundler/fetcher/downloader.rb26
-rw-r--r--lib/bundler/fetcher/gem_remote_fetcher.rb16
-rw-r--r--lib/bundler/fetcher/index.rb2
-rw-r--r--lib/bundler/force_platform.rb2
-rw-r--r--lib/bundler/friendly_errors.rb10
-rw-r--r--lib/bundler/gem_helper.rb4
-rw-r--r--lib/bundler/gem_helpers.rb25
-rw-r--r--lib/bundler/gem_version_promoter.rb82
-rw-r--r--lib/bundler/graph.rb18
-rw-r--r--lib/bundler/index.rb96
-rw-r--r--lib/bundler/injector.rb14
-rw-r--r--lib/bundler/inline.rb45
-rw-r--r--lib/bundler/installer.rb68
-rw-r--r--lib/bundler/installer/gem_installer.rb25
-rw-r--r--lib/bundler/installer/parallel_installer.rb53
-rw-r--r--lib/bundler/installer/standalone.rb22
-rw-r--r--lib/bundler/lazy_specification.rb48
-rw-r--r--lib/bundler/lockfile_generator.rb9
-rw-r--r--lib/bundler/lockfile_parser.rb154
-rw-r--r--lib/bundler/man/bundle-add.170
-rw-r--r--lib/bundler/man/bundle-add.1.ronn51
-rw-r--r--lib/bundler/man/bundle-binstubs.120
-rw-r--r--lib/bundler/man/bundle-cache.127
-rw-r--r--lib/bundler/man/bundle-check.117
-rw-r--r--lib/bundler/man/bundle-check.1.ronn3
-rw-r--r--lib/bundler/man/bundle-clean.113
-rw-r--r--lib/bundler/man/bundle-config.1235
-rw-r--r--lib/bundler/man/bundle-config.1.ronn15
-rw-r--r--lib/bundler/man/bundle-console.126
-rw-r--r--lib/bundler/man/bundle-doctor.122
-rw-r--r--lib/bundler/man/bundle-exec.187
-rw-r--r--lib/bundler/man/bundle-exec.1.ronn5
-rw-r--r--lib/bundler/man/bundle-gem.168
-rw-r--r--lib/bundler/man/bundle-gem.1.ronn11
-rw-r--r--lib/bundler/man/bundle-help.110
-rw-r--r--lib/bundler/man/bundle-info.112
-rw-r--r--lib/bundler/man/bundle-init.115
-rw-r--r--lib/bundler/man/bundle-inject.125
-rw-r--r--lib/bundler/man/bundle-install.1156
-rw-r--r--lib/bundler/man/bundle-install.1.ronn5
-rw-r--r--lib/bundler/man/bundle-list.123
-rw-r--r--lib/bundler/man/bundle-lock.134
-rw-r--r--lib/bundler/man/bundle-open.134
-rw-r--r--lib/bundler/man/bundle-outdated.158
-rw-r--r--lib/bundler/man/bundle-outdated.1.ronn1
-rw-r--r--lib/bundler/man/bundle-platform.132
-rw-r--r--lib/bundler/man/bundle-plugin.171
-rw-r--r--lib/bundler/man/bundle-plugin.1.ronn20
-rw-r--r--lib/bundler/man/bundle-pristine.121
-rw-r--r--lib/bundler/man/bundle-remove.118
-rw-r--r--lib/bundler/man/bundle-show.113
-rw-r--r--lib/bundler/man/bundle-update.1155
-rw-r--r--lib/bundler/man/bundle-version.119
-rw-r--r--lib/bundler/man/bundle-viz.120
-rw-r--r--lib/bundler/man/bundle.149
-rw-r--r--lib/bundler/man/gemfile.5334
-rw-r--r--lib/bundler/man/gemfile.5.ronn19
-rw-r--r--lib/bundler/match_metadata.rb4
-rw-r--r--lib/bundler/match_platform.rb2
-rw-r--r--lib/bundler/mirror.rb6
-rw-r--r--lib/bundler/plugin.rb19
-rw-r--r--lib/bundler/plugin/api/source.rb12
-rw-r--r--lib/bundler/plugin/events.rb24
-rw-r--r--lib/bundler/plugin/index.rb8
-rw-r--r--lib/bundler/plugin/installer.rb54
-rw-r--r--lib/bundler/plugin/installer/path.rb18
-rw-r--r--lib/bundler/plugin/source_list.rb8
-rw-r--r--lib/bundler/remote_specification.rb4
-rw-r--r--lib/bundler/resolver.rb220
-rw-r--r--lib/bundler/resolver/base.rb12
-rw-r--r--lib/bundler/resolver/candidate.rb22
-rw-r--r--lib/bundler/resolver/incompatibility.rb2
-rw-r--r--lib/bundler/resolver/package.rb20
-rw-r--r--lib/bundler/resolver/spec_group.rb27
-rw-r--r--lib/bundler/retry.rb4
-rw-r--r--lib/bundler/ruby_dsl.rb49
-rw-r--r--lib/bundler/ruby_version.rb17
-rw-r--r--lib/bundler/rubygems_ext.rb250
-rw-r--r--lib/bundler/rubygems_gem_installer.rb114
-rw-r--r--lib/bundler/rubygems_integration.rb148
-rw-r--r--lib/bundler/runtime.rb32
-rw-r--r--lib/bundler/self_manager.rb61
-rw-r--r--lib/bundler/settings.rb179
-rw-r--r--lib/bundler/setup.rb11
-rw-r--r--lib/bundler/shared_helpers.rb73
-rw-r--r--lib/bundler/source.rb2
-rw-r--r--lib/bundler/source/git.rb93
-rw-r--r--lib/bundler/source/git/git_proxy.rb96
-rw-r--r--lib/bundler/source/metadata.rb32
-rw-r--r--lib/bundler/source/path.rb30
-rw-r--r--lib/bundler/source/rubygems.rb160
-rw-r--r--lib/bundler/source/rubygems/remote.rb2
-rw-r--r--lib/bundler/source_list.rb28
-rw-r--r--lib/bundler/spec_set.rb140
-rw-r--r--lib/bundler/stub_specification.rb19
-rw-r--r--lib/bundler/templates/Executable.bundler2
-rw-r--r--lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt106
-rw-r--r--lib/bundler/templates/newgem/README.md.tt10
-rw-r--r--lib/bundler/templates/newgem/Rakefile.tt16
-rw-r--r--lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt2
-rw-r--r--lib/bundler/templates/newgem/github/workflows/main.yml.tt2
-rw-r--r--lib/bundler/templates/newgem/newgem.gemspec.tt9
-rw-r--r--lib/bundler/templates/newgem/rubocop.yml.tt5
-rw-r--r--lib/bundler/templates/newgem/standard.yml.tt2
-rw-r--r--lib/bundler/ui/shell.rb28
-rw-r--r--lib/bundler/ui/silent.rb13
-rw-r--r--lib/bundler/uri_credentials_filter.rb4
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool.rb59
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb2
-rw-r--r--lib/bundler/vendor/fileutils/lib/fileutils.rb28
-rw-r--r--lib/bundler/vendor/net-http-persistent/.document1
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb114
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb7
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb34
-rw-r--r--lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb2
-rw-r--r--lib/bundler/vendor/pub_grub/.document1
-rw-r--r--lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb1
-rw-r--r--lib/bundler/vendor/securerandom/.document1
-rw-r--r--lib/bundler/vendor/securerandom/lib/random/formatter.rb373
-rw-r--r--lib/bundler/vendor/securerandom/lib/securerandom.rb96
-rw-r--r--lib/bundler/vendor/thor/.document1
-rw-r--r--lib/bundler/vendor/thor/lib/thor.rb163
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions.rb30
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/create_file.rb5
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/directory.rb2
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb2
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb18
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb19
-rw-r--r--lib/bundler/vendor/thor/lib/thor/base.rb154
-rw-r--r--lib/bundler/vendor/thor/lib/thor/command.rb17
-rw-r--r--lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb4
-rw-r--r--lib/bundler/vendor/thor/lib/thor/error.rb41
-rw-r--r--lib/bundler/vendor/thor/lib/thor/group.rb2
-rw-r--r--lib/bundler/vendor/thor/lib/thor/invocation.rb2
-rw-r--r--lib/bundler/vendor/thor/lib/thor/nested_context.rb4
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser/argument.rb21
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser/arguments.rb50
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser/option.rb35
-rw-r--r--lib/bundler/vendor/thor/lib/thor/parser/options.rb50
-rw-r--r--lib/bundler/vendor/thor/lib/thor/rake_compat.rb4
-rw-r--r--lib/bundler/vendor/thor/lib/thor/runner.rb70
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell.rb2
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/basic.rb176
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/color.rb47
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb29
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/html.rb45
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb134
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/terminal.rb42
-rw-r--r--lib/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb38
-rw-r--r--lib/bundler/vendor/thor/lib/thor/util.rb15
-rw-r--r--lib/bundler/vendor/thor/lib/thor/version.rb2
-rw-r--r--lib/bundler/vendor/tsort/.document1
-rw-r--r--lib/bundler/vendor/tsort/lib/tsort.rb3
-rw-r--r--lib/bundler/vendor/uri/.document1
-rw-r--r--lib/bundler/vendor/uri/lib/uri/common.rb388
-rw-r--r--lib/bundler/vendor/uri/lib/uri/generic.rb1
-rw-r--r--lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb126
-rw-r--r--lib/bundler/vendor/uri/lib/uri/version.rb2
-rw-r--r--lib/bundler/vendored_net_http.rb23
-rw-r--r--lib/bundler/vendored_persistent.rb4
-rw-r--r--lib/bundler/vendored_securerandom.rb14
-rw-r--r--lib/bundler/vendored_timeout.rb12
-rw-r--r--lib/bundler/vendored_uri.rb19
-rw-r--r--lib/bundler/version.rb2
-rw-r--r--lib/bundler/vlad.rb2
-rw-r--r--lib/bundler/yaml_serializer.rb35
-rw-r--r--lib/cgi.rb2
-rw-r--r--lib/cgi/cookie.rb5
-rw-r--r--lib/cgi/session.rb2
-rw-r--r--lib/cgi/util.rb20
-rw-r--r--lib/csv.rb2881
-rw-r--r--lib/csv/core_ext/array.rb9
-rw-r--r--lib/csv/core_ext/string.rb9
-rw-r--r--lib/csv/csv.gemspec64
-rw-r--r--lib/csv/delete_suffix.rb18
-rw-r--r--lib/csv/fields_converter.rb89
-rw-r--r--lib/csv/input_record_separator.rb18
-rw-r--r--lib/csv/match_p.rb20
-rw-r--r--lib/csv/parser.rb1289
-rw-r--r--lib/csv/row.rb757
-rw-r--r--lib/csv/table.rb1055
-rw-r--r--lib/csv/version.rb6
-rw-r--r--lib/csv/writer.rb210
-rw-r--r--lib/delegate.gemspec29
-rw-r--r--lib/delegate.rb6
-rw-r--r--lib/delegate/delegate.gemspec29
-rw-r--r--lib/did_you_mean.rb4
-rw-r--r--lib/did_you_mean/did_you_mean.gemspec2
-rw-r--r--lib/did_you_mean/jaro_winkler.rb7
-rw-r--r--lib/did_you_mean/spell_checkers/key_error_checker.rb10
-rw-r--r--lib/did_you_mean/spell_checkers/pattern_key_name_checker.rb10
-rw-r--r--lib/drb.rb3
-rw-r--r--lib/drb/acl.rb239
-rw-r--r--lib/drb/drb.gemspec43
-rw-r--r--lib/drb/drb.rb1942
-rw-r--r--lib/drb/eq.rb15
-rw-r--r--lib/drb/extserv.rb44
-rw-r--r--lib/drb/extservm.rb94
-rw-r--r--lib/drb/gw.rb161
-rw-r--r--lib/drb/invokemethod.rb35
-rw-r--r--lib/drb/observer.rb26
-rw-r--r--lib/drb/ssl.rb344
-rw-r--r--lib/drb/timeridconv.rb97
-rw-r--r--lib/drb/unix.rb118
-rw-r--r--lib/drb/version.rb3
-rw-r--r--lib/drb/weakidconv.rb59
-rw-r--r--lib/erb.gemspec2
-rw-r--r--lib/erb.rb4
-rw-r--r--lib/erb/compiler.rb1
-rw-r--r--lib/erb/def_method.rb1
-rw-r--r--lib/erb/util.rb1
-rw-r--r--lib/erb/version.rb2
-rw-r--r--lib/error_highlight/base.rb320
-rw-r--r--lib/error_highlight/version.rb2
-rw-r--r--lib/fileutils.gemspec2
-rw-r--r--lib/fileutils.rb56
-rw-r--r--lib/find.gemspec13
-rw-r--r--lib/find.rb2
-rw-r--r--lib/getoptlong.rb867
-rw-r--r--lib/getoptlong/getoptlong.gemspec30
-rw-r--r--lib/ipaddr.rb110
-rw-r--r--lib/irb.rb1882
-rw-r--r--lib/irb/cmd/backtrace.rb21
-rw-r--r--lib/irb/cmd/break.rb21
-rw-r--r--lib/irb/cmd/catch.rb21
-rw-r--r--lib/irb/cmd/chws.rb42
-rw-r--r--lib/irb/cmd/continue.rb17
-rw-r--r--lib/irb/cmd/debug.rb136
-rw-r--r--lib/irb/cmd/delete.rb17
-rw-r--r--lib/irb/cmd/edit.rb61
-rw-r--r--lib/irb/cmd/finish.rb17
-rw-r--r--lib/irb/cmd/fork.rb40
-rw-r--r--lib/irb/cmd/help.rb63
-rw-r--r--lib/irb/cmd/info.rb21
-rw-r--r--lib/irb/cmd/irb_info.rb37
-rw-r--r--lib/irb/cmd/load.rb82
-rw-r--r--lib/irb/cmd/ls.rb116
-rw-r--r--lib/irb/cmd/measure.rb48
-rw-r--r--lib/irb/cmd/next.rb17
-rw-r--r--lib/irb/cmd/nop.rb73
-rw-r--r--lib/irb/cmd/pushws.rb51
-rw-r--r--lib/irb/cmd/show_cmds.rb39
-rw-r--r--lib/irb/cmd/show_source.rb112
-rw-r--r--lib/irb/cmd/step.rb17
-rw-r--r--lib/irb/cmd/subirb.rb71
-rw-r--r--lib/irb/cmd/whereami.rb25
-rw-r--r--lib/irb/color.rb20
-rw-r--r--lib/irb/color_printer.rb7
-rw-r--r--lib/irb/command.rb23
-rw-r--r--lib/irb/command/backtrace.rb17
-rw-r--r--lib/irb/command/base.rb64
-rw-r--r--lib/irb/command/break.rb17
-rw-r--r--lib/irb/command/catch.rb17
-rw-r--r--lib/irb/command/cd.rb51
-rw-r--r--lib/irb/command/chws.rb40
-rw-r--r--lib/irb/command/context.rb16
-rw-r--r--lib/irb/command/continue.rb17
-rw-r--r--lib/irb/command/debug.rb73
-rw-r--r--lib/irb/command/delete.rb17
-rw-r--r--lib/irb/command/disable_irb.rb19
-rw-r--r--lib/irb/command/edit.rb63
-rw-r--r--lib/irb/command/exit.rb18
-rw-r--r--lib/irb/command/finish.rb17
-rw-r--r--lib/irb/command/force_exit.rb18
-rw-r--r--lib/irb/command/help.rb83
-rw-r--r--lib/irb/command/history.rb45
-rw-r--r--lib/irb/command/info.rb17
-rw-r--r--lib/irb/command/internal_helpers.rb27
-rw-r--r--lib/irb/command/irb_info.rb33
-rw-r--r--lib/irb/command/load.rb91
-rw-r--r--lib/irb/command/ls.rb155
-rw-r--r--lib/irb/command/measure.rb49
-rw-r--r--lib/irb/command/next.rb17
-rw-r--r--lib/irb/command/pushws.rb65
-rw-r--r--lib/irb/command/show_doc.rb51
-rw-r--r--lib/irb/command/show_source.rb74
-rw-r--r--lib/irb/command/step.rb17
-rw-r--r--lib/irb/command/subirb.rb123
-rw-r--r--lib/irb/command/whereami.rb23
-rw-r--r--lib/irb/completion.rb304
-rw-r--r--lib/irb/context.rb308
-rw-r--r--lib/irb/debug.rb126
-rw-r--r--lib/irb/debug/ui.rb103
-rw-r--r--lib/irb/default_commands.rb276
-rw-r--r--lib/irb/easter-egg.rb27
-rw-r--r--lib/irb/ext/change-ws.rb20
-rw-r--r--lib/irb/ext/eval_history.rb149
-rw-r--r--lib/irb/ext/history.rb155
-rw-r--r--lib/irb/ext/loader.rb42
-rw-r--r--lib/irb/ext/multi-irb.rb16
-rw-r--r--lib/irb/ext/save-history.rb130
-rw-r--r--lib/irb/ext/tracer.rb73
-rw-r--r--lib/irb/ext/use-loader.rb20
-rw-r--r--lib/irb/ext/workspaces.rb50
-rw-r--r--lib/irb/extend-command.rb433
-rw-r--r--lib/irb/frame.rb8
-rw-r--r--lib/irb/help.rb16
-rw-r--r--lib/irb/helper_method.rb29
-rw-r--r--lib/irb/helper_method/base.rb16
-rw-r--r--lib/irb/helper_method/conf.rb11
-rw-r--r--lib/irb/history.rb87
-rw-r--r--lib/irb/init.rb220
-rw-r--r--lib/irb/input-method.rb456
-rw-r--r--lib/irb/inspector.rb87
-rw-r--r--lib/irb/irb.gemspec10
-rw-r--r--lib/irb/lc/error.rb18
-rw-r--r--lib/irb/lc/help-message8
-rw-r--r--lib/irb/lc/ja/encoding_aliases.rb13
-rw-r--r--lib/irb/lc/ja/error.rb20
-rw-r--r--lib/irb/lc/ja/help-message13
-rw-r--r--lib/irb/locale.rb64
-rw-r--r--lib/irb/magic-file.rb38
-rw-r--r--lib/irb/nesting_parser.rb239
-rw-r--r--lib/irb/notifier.rb8
-rw-r--r--lib/irb/output-method.rb16
-rw-r--r--lib/irb/pager.rb95
-rw-r--r--lib/irb/ruby-lex.rb1158
-rw-r--r--lib/irb/ruby_logo.aa153
-rw-r--r--lib/irb/source_finder.rb139
-rw-r--r--lib/irb/src_encoding.rb7
-rw-r--r--lib/irb/statement.rb80
-rw-r--r--lib/irb/version.rb12
-rw-r--r--lib/irb/workspace.rb45
-rw-r--r--lib/irb/ws-for-case-2.rb8
-rw-r--r--lib/irb/xmp.rb12
-rw-r--r--lib/logger.rb56
-rw-r--r--lib/logger/log_device.rb9
-rw-r--r--lib/logger/logger.gemspec6
-rw-r--r--lib/logger/period.rb16
-rw-r--r--lib/logger/severity.rb19
-rw-r--r--lib/logger/version.rb2
-rw-r--r--lib/mkmf.rb398
-rw-r--r--lib/mutex_m.gemspec27
-rw-r--r--lib/mutex_m.rb118
-rw-r--r--lib/net/http.rb147
-rw-r--r--lib/net/http/header.rb2
-rw-r--r--lib/net/http/requests.rb5
-rw-r--r--lib/net/net-protocol.gemspec3
-rw-r--r--lib/net/protocol.rb2
-rw-r--r--lib/observer.rb229
-rw-r--r--lib/observer/observer.gemspec32
-rw-r--r--lib/open-uri.gemspec11
-rw-r--r--lib/open-uri.rb69
-rw-r--r--lib/open3.rb1268
-rw-r--r--lib/open3/open3.gemspec2
-rw-r--r--lib/open3/version.rb2
-rw-r--r--lib/optparse.rb229
-rw-r--r--lib/optparse/ac.rb16
-rw-r--r--lib/optparse/kwargs.rb11
-rw-r--r--lib/optparse/optparse.gemspec3
-rw-r--r--lib/optparse/version.rb9
-rw-r--r--lib/ostruct.gemspec24
-rw-r--r--lib/ostruct.rb16
-rw-r--r--lib/ostruct/ostruct.gemspec27
-rw-r--r--lib/pp.gemspec11
-rw-r--r--lib/pp.rb58
-rw-r--r--lib/prettyprint.gemspec11
-rw-r--r--lib/prettyprint.rb6
-rw-r--r--lib/prism.rb87
-rw-r--r--lib/prism/desugar_compiler.rb391
-rw-r--r--lib/prism/ffi.rb495
-rw-r--r--lib/prism/lex_compat.rb927
-rw-r--r--lib/prism/node_ext.rb508
-rw-r--r--lib/prism/pack.rb228
-rw-r--r--lib/prism/parse_result.rb721
-rw-r--r--lib/prism/parse_result/comments.rb187
-rw-r--r--lib/prism/parse_result/errors.rb65
-rw-r--r--lib/prism/parse_result/newlines.rb154
-rw-r--r--lib/prism/pattern.rb268
-rw-r--r--lib/prism/polyfill/byteindex.rb13
-rw-r--r--lib/prism/polyfill/unpack1.rb14
-rw-r--r--lib/prism/prism.gemspec160
-rw-r--r--lib/prism/translation.rb13
-rw-r--r--lib/prism/translation/parser.rb307
-rw-r--r--lib/prism/translation/parser/compiler.rb2146
-rw-r--r--lib/prism/translation/parser/lexer.rb438
-rw-r--r--lib/prism/translation/parser33.rb12
-rw-r--r--lib/prism/translation/parser34.rb12
-rw-r--r--lib/prism/translation/ripper.rb3448
-rw-r--r--lib/prism/translation/ripper/sexp.rb125
-rw-r--r--lib/prism/translation/ripper/shim.rb5
-rw-r--r--lib/prism/translation/ruby_parser.rb1636
-rw-r--r--lib/pstore.gemspec32
-rw-r--r--lib/pstore.rb16
-rw-r--r--lib/pstore/pstore.gemspec32
-rw-r--r--lib/racc.rb6
-rw-r--r--lib/racc/compat.rb33
-rw-r--r--lib/racc/debugflags.rb60
-rw-r--r--lib/racc/exception.rb16
-rw-r--r--lib/racc/grammar.rb1118
-rw-r--r--lib/racc/grammarfileparser.rb561
-rw-r--r--lib/racc/info.rb17
-rw-r--r--lib/racc/iset.rb92
-rw-r--r--lib/racc/logfilegenerator.rb212
-rw-r--r--lib/racc/parser-text.rb637
-rw-r--r--lib/racc/parser.rb632
-rw-r--r--lib/racc/parserfilegenerator.rb468
-rw-r--r--lib/racc/racc.gemspec58
-rw-r--r--lib/racc/sourcetext.rb35
-rw-r--r--lib/racc/state.rb972
-rw-r--r--lib/racc/statetransitiontable.rb311
-rw-r--r--lib/racc/static.rb5
-rw-r--r--lib/random/formatter.rb143
-rw-r--r--lib/rdoc.rb56
-rw-r--r--lib/rdoc/alias.rb112
-rw-r--r--lib/rdoc/anon_class.rb11
-rw-r--r--lib/rdoc/any_method.rb364
-rw-r--r--lib/rdoc/attr.rb176
-rw-r--r--lib/rdoc/class_module.rb802
-rw-r--r--lib/rdoc/code_object/alias.rb111
-rw-r--r--lib/rdoc/code_object/anon_class.rb10
-rw-r--r--lib/rdoc/code_object/any_method.rb379
-rw-r--r--lib/rdoc/code_object/attr.rb175
-rw-r--r--lib/rdoc/code_object/class_module.rb801
-rw-r--r--lib/rdoc/code_object/constant.rb186
-rw-r--r--lib/rdoc/code_object/context.rb1264
-rw-r--r--lib/rdoc/code_object/context/section.rb233
-rw-r--r--lib/rdoc/code_object/extend.rb9
-rw-r--r--lib/rdoc/code_object/ghost_method.rb6
-rw-r--r--lib/rdoc/code_object/include.rb9
-rw-r--r--lib/rdoc/code_object/meta_method.rb6
-rw-r--r--lib/rdoc/code_object/method_attr.rb418
-rw-r--r--lib/rdoc/code_object/mixin.rb120
-rw-r--r--lib/rdoc/code_object/normal_class.rb92
-rw-r--r--lib/rdoc/code_object/normal_module.rb73
-rw-r--r--lib/rdoc/code_object/require.rb51
-rw-r--r--lib/rdoc/code_object/single_class.rb30
-rw-r--r--lib/rdoc/code_object/top_level.rb291
-rw-r--r--lib/rdoc/comment.rb61
-rw-r--r--lib/rdoc/constant.rb187
-rw-r--r--lib/rdoc/context.rb1264
-rw-r--r--lib/rdoc/context/section.rb234
-rw-r--r--lib/rdoc/cross_reference.rb4
-rw-r--r--lib/rdoc/encoding.rb18
-rw-r--r--lib/rdoc/erb_partial.rb1
-rw-r--r--lib/rdoc/erbio.rb9
-rw-r--r--lib/rdoc/extend.rb10
-rw-r--r--lib/rdoc/generator/darkfish.rb11
-rw-r--r--lib/rdoc/generator/json_index.rb4
-rw-r--r--lib/rdoc/generator/markup.rb1
-rw-r--r--lib/rdoc/generator/pot.rb1
-rw-r--r--lib/rdoc/generator/pot/message_extractor.rb2
-rw-r--r--lib/rdoc/generator/pot/po_entry.rb2
-rw-r--r--lib/rdoc/generator/ri.rb1
-rw-r--r--lib/rdoc/generator/template/darkfish/_head.rhtml1
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml2
-rw-r--r--lib/rdoc/generator/template/darkfish/_sidebar_toggle.rhtml3
-rw-r--r--lib/rdoc/generator/template/darkfish/class.rhtml23
-rw-r--r--lib/rdoc/generator/template/darkfish/css/rdoc.css523
-rw-r--r--lib/rdoc/generator/template/darkfish/index.rhtml13
-rw-r--r--lib/rdoc/generator/template/darkfish/js/darkfish.js30
-rw-r--r--lib/rdoc/generator/template/darkfish/js/search.js6
-rw-r--r--lib/rdoc/generator/template/darkfish/page.rhtml10
-rw-r--r--lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml18
-rw-r--r--lib/rdoc/generator/template/darkfish/servlet_root.rhtml7
-rw-r--r--lib/rdoc/generator/template/darkfish/table_of_contents.rhtml20
-rw-r--r--lib/rdoc/generator/template/json_index/js/navigation.js16
-rw-r--r--lib/rdoc/ghost_method.rb7
-rw-r--r--lib/rdoc/include.rb10
-rw-r--r--lib/rdoc/markdown.rb42
-rw-r--r--lib/rdoc/markdown/entities.rb1
-rw-r--r--lib/rdoc/markdown/literals.rb1
-rw-r--r--lib/rdoc/markup.rb31
-rw-r--r--lib/rdoc/markup/attr_changer.rb1
-rw-r--r--lib/rdoc/markup/attr_span.rb1
-rw-r--r--lib/rdoc/markup/attribute_manager.rb30
-rw-r--r--lib/rdoc/markup/attributes.rb1
-rw-r--r--lib/rdoc/markup/blank_line.rb1
-rw-r--r--lib/rdoc/markup/block_quote.rb1
-rw-r--r--lib/rdoc/markup/document.rb1
-rw-r--r--lib/rdoc/markup/formatter.rb3
-rw-r--r--lib/rdoc/markup/hard_break.rb1
-rw-r--r--lib/rdoc/markup/heading.rb1
-rw-r--r--lib/rdoc/markup/include.rb1
-rw-r--r--lib/rdoc/markup/indented_paragraph.rb1
-rw-r--r--lib/rdoc/markup/list.rb1
-rw-r--r--lib/rdoc/markup/list_item.rb1
-rw-r--r--lib/rdoc/markup/paragraph.rb1
-rw-r--r--lib/rdoc/markup/parser.rb6
-rw-r--r--lib/rdoc/markup/pre_process.rb15
-rw-r--r--lib/rdoc/markup/raw.rb1
-rw-r--r--lib/rdoc/markup/regexp_handling.rb1
-rw-r--r--lib/rdoc/markup/rule.rb1
-rw-r--r--lib/rdoc/markup/table.rb13
-rw-r--r--lib/rdoc/markup/to_ansi.rb1
-rw-r--r--lib/rdoc/markup/to_bs.rb27
-rw-r--r--lib/rdoc/markup/to_html.rb10
-rw-r--r--lib/rdoc/markup/to_html_crossref.rb27
-rw-r--r--lib/rdoc/markup/to_html_snippet.rb4
-rw-r--r--lib/rdoc/markup/to_joined_paragraph.rb5
-rw-r--r--lib/rdoc/markup/to_label.rb1
-rw-r--r--lib/rdoc/markup/to_markdown.rb9
-rw-r--r--lib/rdoc/markup/to_rdoc.rb23
-rw-r--r--lib/rdoc/markup/to_table_of_contents.rb1
-rw-r--r--lib/rdoc/markup/to_test.rb1
-rw-r--r--lib/rdoc/markup/to_tt_only.rb1
-rw-r--r--lib/rdoc/markup/verbatim.rb1
-rw-r--r--lib/rdoc/meta_method.rb7
-rw-r--r--lib/rdoc/method_attr.rb419
-rw-r--r--lib/rdoc/mixin.rb121
-rw-r--r--lib/rdoc/normal_class.rb93
-rw-r--r--lib/rdoc/normal_module.rb74
-rw-r--r--lib/rdoc/options.rb14
-rw-r--r--lib/rdoc/parser.rb9
-rw-r--r--lib/rdoc/parser/c.rb57
-rw-r--r--lib/rdoc/parser/changelog.rb18
-rw-r--r--lib/rdoc/parser/markdown.rb2
-rw-r--r--lib/rdoc/parser/prism_ruby.rb1026
-rw-r--r--lib/rdoc/parser/rd.rb1
-rw-r--r--lib/rdoc/parser/ripper_state_lex.rb322
-rw-r--r--lib/rdoc/parser/ruby.rb45
-rw-r--r--lib/rdoc/parser/ruby_tools.rb2
-rw-r--r--lib/rdoc/parser/text.rb1
-rw-r--r--lib/rdoc/rd/block_parser.rb654
-rw-r--r--lib/rdoc/rd/inline.rb1
-rw-r--r--lib/rdoc/rd/inline_parser.rb652
-rw-r--r--lib/rdoc/rdoc.gemspec46
-rw-r--r--lib/rdoc/rdoc.rb11
-rw-r--r--lib/rdoc/require.rb52
-rw-r--r--lib/rdoc/ri/driver.rb35
-rw-r--r--lib/rdoc/ri/store.rb1
-rw-r--r--lib/rdoc/single_class.rb31
-rw-r--r--lib/rdoc/stats/quiet.rb1
-rw-r--r--lib/rdoc/stats/verbose.rb2
-rw-r--r--lib/rdoc/store.rb3
-rw-r--r--lib/rdoc/task.rb35
-rw-r--r--lib/rdoc/text.rb10
-rw-r--r--lib/rdoc/token_stream.rb3
-rw-r--r--lib/rdoc/tom_doc.rb8
-rw-r--r--lib/rdoc/top_level.rb289
-rw-r--r--lib/rdoc/version.rb2
-rw-r--r--lib/readline.gemspec2
-rw-r--r--lib/readline.rb2
-rw-r--r--lib/reline.rb401
-rw-r--r--lib/reline/ansi.rb350
-rw-r--r--lib/reline/config.rb222
-rw-r--r--lib/reline/face.rb199
-rw-r--r--lib/reline/general_io.rb109
-rw-r--r--lib/reline/history.rb8
-rw-r--r--lib/reline/io.rb41
-rw-r--r--lib/reline/io/ansi.rb363
-rw-r--r--lib/reline/io/dumb.rb106
-rw-r--r--lib/reline/io/windows.rb513
-rw-r--r--lib/reline/key_actor.rb1
-rw-r--r--lib/reline/key_actor/base.rb28
-rw-r--r--lib/reline/key_actor/composite.rb17
-rw-r--r--lib/reline/key_actor/emacs.rb30
-rw-r--r--lib/reline/key_actor/vi_command.rb50
-rw-r--r--lib/reline/key_actor/vi_insert.rb14
-rw-r--r--lib/reline/key_stroke.rb172
-rw-r--r--lib/reline/kill_ring.rb4
-rw-r--r--lib/reline/line_editor.rb2999
-rw-r--r--lib/reline/reline.gemspec5
-rw-r--r--lib/reline/terminfo.rb44
-rw-r--r--lib/reline/unicode.rb226
-rw-r--r--lib/reline/unicode/east_asian_width.rb2423
-rw-r--r--lib/reline/version.rb2
-rw-r--r--lib/reline/windows.rb497
-rw-r--r--lib/resolv-replace.gemspec22
-rw-r--r--lib/resolv-replace.rb76
-rw-r--r--lib/resolv.gemspec12
-rw-r--r--lib/resolv.rb636
-rw-r--r--lib/rinda/rinda.gemspec28
-rw-r--r--lib/rinda/rinda.rb327
-rw-r--r--lib/rinda/ring.rb484
-rw-r--r--lib/rinda/tuplespace.rb641
-rw-r--r--lib/ruby_vm/mjit/c_pointer.rb329
-rw-r--r--lib/ruby_vm/mjit/c_type.rb91
-rw-r--r--lib/ruby_vm/mjit/compiler.rb952
-rw-r--r--lib/ruby_vm/mjit/hooks.rb32
-rw-r--r--lib/ruby_vm/rjit/.document1
-rw-r--r--lib/ruby_vm/rjit/assembler.rb1160
-rw-r--r--lib/ruby_vm/rjit/block.rb11
-rw-r--r--lib/ruby_vm/rjit/branch_stub.rb24
-rw-r--r--lib/ruby_vm/rjit/c_pointer.rb394
-rw-r--r--lib/ruby_vm/rjit/c_type.rb99
-rw-r--r--lib/ruby_vm/rjit/code_block.rb91
-rw-r--r--lib/ruby_vm/rjit/compiler.rb518
-rw-r--r--lib/ruby_vm/rjit/context.rb377
-rw-r--r--lib/ruby_vm/rjit/entry_stub.rb7
-rw-r--r--lib/ruby_vm/rjit/exit_compiler.rb164
-rw-r--r--lib/ruby_vm/rjit/hooks.rb36
-rw-r--r--lib/ruby_vm/rjit/insn_compiler.rb6046
-rw-r--r--lib/ruby_vm/rjit/invariants.rb155
-rw-r--r--lib/ruby_vm/rjit/jit_state.rb65
-rw-r--r--lib/ruby_vm/rjit/stats.rb191
-rw-r--r--lib/ruby_vm/rjit/type.rb221
-rw-r--r--lib/rubygems.rb190
-rw-r--r--lib/rubygems/available_set.rb10
-rw-r--r--lib/rubygems/basic_specification.rb116
-rw-r--r--lib/rubygems/bundler_version_finder.rb10
-rw-r--r--lib/rubygems/ci_detector.rb75
-rw-r--r--lib/rubygems/command.rb67
-rw-r--r--lib/rubygems/command_manager.rb21
-rw-r--r--lib/rubygems/commands/build_command.rb17
-rw-r--r--lib/rubygems/commands/cert_command.rb11
-rw-r--r--lib/rubygems/commands/check_command.rb14
-rw-r--r--lib/rubygems/commands/cleanup_command.rb40
-rw-r--r--lib/rubygems/commands/contents_command.rb12
-rw-r--r--lib/rubygems/commands/dependency_command.rb14
-rw-r--r--lib/rubygems/commands/environment_command.rb8
-rw-r--r--lib/rubygems/commands/exec_command.rb9
-rw-r--r--lib/rubygems/commands/fetch_command.rb18
-rw-r--r--lib/rubygems/commands/generate_index_command.rb113
-rw-r--r--lib/rubygems/commands/help_command.rb16
-rw-r--r--lib/rubygems/commands/info_command.rb4
-rw-r--r--lib/rubygems/commands/install_command.rb28
-rw-r--r--lib/rubygems/commands/list_command.rb4
-rw-r--r--lib/rubygems/commands/lock_command.rb2
-rw-r--r--lib/rubygems/commands/open_command.rb4
-rw-r--r--lib/rubygems/commands/owner_command.rb22
-rw-r--r--lib/rubygems/commands/pristine_command.rb47
-rw-r--r--lib/rubygems/commands/push_command.rb4
-rw-r--r--lib/rubygems/commands/query_command.rb9
-rw-r--r--lib/rubygems/commands/rdoc_command.rb13
-rw-r--r--lib/rubygems/commands/rebuild_command.rb262
-rw-r--r--lib/rubygems/commands/search_command.rb4
-rw-r--r--lib/rubygems/commands/setup_command.rb83
-rw-r--r--lib/rubygems/commands/sources_command.rb28
-rw-r--r--lib/rubygems/commands/specification_command.rb26
-rw-r--r--lib/rubygems/commands/stale_command.rb4
-rw-r--r--lib/rubygems/commands/uninstall_command.rb45
-rw-r--r--lib/rubygems/commands/unpack_command.rb30
-rw-r--r--lib/rubygems/commands/update_command.rb55
-rw-r--r--lib/rubygems/commands/which_command.rb2
-rw-r--r--lib/rubygems/commands/yank_command.rb4
-rw-r--r--lib/rubygems/compatibility.rb11
-rw-r--r--lib/rubygems/config_file.rb136
-rw-r--r--lib/rubygems/core_ext/kernel_gem.rb6
-rw-r--r--lib/rubygems/core_ext/kernel_require.rb80
-rw-r--r--lib/rubygems/core_ext/kernel_warn.rb17
-rw-r--r--lib/rubygems/core_ext/tcpsocket_init.rb2
-rw-r--r--lib/rubygems/defaults.rb38
-rw-r--r--lib/rubygems/dependency.rb52
-rw-r--r--lib/rubygems/dependency_installer.rb81
-rw-r--r--lib/rubygems/dependency_list.rb4
-rw-r--r--lib/rubygems/deprecate.rb162
-rw-r--r--lib/rubygems/doctor.rb14
-rw-r--r--lib/rubygems/errors.rb13
-rw-r--r--lib/rubygems/exceptions.rb16
-rw-r--r--lib/rubygems/ext/builder.rb44
-rw-r--r--lib/rubygems/ext/cargo_builder.rb39
-rw-r--r--lib/rubygems/ext/cmake_builder.rb9
-rw-r--r--lib/rubygems/ext/configure_builder.rb9
-rw-r--r--lib/rubygems/ext/ext_conf_builder.rb18
-rw-r--r--lib/rubygems/ext/rake_builder.rb9
-rw-r--r--lib/rubygems/gem_runner.rb14
-rw-r--r--lib/rubygems/gemcutter_utilities.rb92
-rw-r--r--lib/rubygems/gemcutter_utilities/webauthn_listener.rb2
-rw-r--r--lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb6
-rw-r--r--lib/rubygems/gemcutter_utilities/webauthn_poller.rb10
-rw-r--r--lib/rubygems/gemspec_helpers.rb19
-rw-r--r--lib/rubygems/indexer.rb428
-rw-r--r--lib/rubygems/install_update_options.rb44
-rw-r--r--lib/rubygems/installer.rb183
-rw-r--r--lib/rubygems/installer_uninstaller_utils.rb2
-rw-r--r--lib/rubygems/local_remote_options.rb31
-rw-r--r--lib/rubygems/mock_gem_ui.rb86
-rw-r--r--lib/rubygems/name_tuple.rb16
-rw-r--r--lib/rubygems/optparse.rb3
-rw-r--r--lib/rubygems/optparse/.document (renamed from lib/bundler/vendor/connection_pool/.document)0
-rw-r--r--lib/rubygems/optparse/lib/optionparser.rb (renamed from lib/rubygems/vendor/optparse/lib/optionparser.rb)0
-rw-r--r--lib/rubygems/optparse/lib/optparse.rb2308
-rw-r--r--lib/rubygems/optparse/lib/optparse/ac.rb (renamed from lib/rubygems/vendor/optparse/lib/optparse/ac.rb)0
-rw-r--r--lib/rubygems/optparse/lib/optparse/date.rb (renamed from lib/rubygems/vendor/optparse/lib/optparse/date.rb)0
-rw-r--r--lib/rubygems/optparse/lib/optparse/kwargs.rb (renamed from lib/rubygems/vendor/optparse/lib/optparse/kwargs.rb)0
-rw-r--r--lib/rubygems/optparse/lib/optparse/shellwords.rb (renamed from lib/rubygems/vendor/optparse/lib/optparse/shellwords.rb)0
-rw-r--r--lib/rubygems/optparse/lib/optparse/time.rb (renamed from lib/rubygems/vendor/optparse/lib/optparse/time.rb)0
-rw-r--r--lib/rubygems/optparse/lib/optparse/uri.rb7
-rw-r--r--lib/rubygems/optparse/lib/optparse/version.rb (renamed from lib/rubygems/vendor/optparse/lib/optparse/version.rb)0
-rw-r--r--lib/rubygems/package.rb112
-rw-r--r--lib/rubygems/package/digest_io.rb2
-rw-r--r--lib/rubygems/package/old.rb4
-rw-r--r--lib/rubygems/package/tar_header.rb104
-rw-r--r--lib/rubygems/package/tar_reader.rb24
-rw-r--r--lib/rubygems/package/tar_reader/entry.rb47
-rw-r--r--lib/rubygems/package/tar_writer.rb40
-rw-r--r--lib/rubygems/package_task.rb4
-rw-r--r--lib/rubygems/path_support.rb21
-rw-r--r--lib/rubygems/platform.rb125
-rw-r--r--lib/rubygems/psych_tree.rb4
-rw-r--r--lib/rubygems/query_utils.rb28
-rw-r--r--lib/rubygems/remote_fetcher.rb51
-rw-r--r--lib/rubygems/request.rb53
-rw-r--r--lib/rubygems/request/connection_pools.rb6
-rw-r--r--lib/rubygems/request_set.rb15
-rw-r--r--lib/rubygems/request_set/gem_dependency_api.rb245
-rw-r--r--lib/rubygems/request_set/lockfile.rb17
-rw-r--r--lib/rubygems/request_set/lockfile/parser.rb18
-rw-r--r--lib/rubygems/request_set/lockfile/tokenizer.rb32
-rw-r--r--lib/rubygems/requirement.rb29
-rw-r--r--lib/rubygems/resolver.rb27
-rw-r--r--lib/rubygems/resolver/activation_request.rb12
-rw-r--r--lib/rubygems/resolver/api_set.rb24
-rw-r--r--lib/rubygems/resolver/api_set/gem_parser.rb10
-rw-r--r--lib/rubygems/resolver/api_specification.rb2
-rw-r--r--lib/rubygems/resolver/best_set.rb28
-rw-r--r--lib/rubygems/resolver/composed_set.rb2
-rw-r--r--lib/rubygems/resolver/conflict.rb16
-rw-r--r--lib/rubygems/resolver/index_set.rb8
-rw-r--r--lib/rubygems/resolver/index_specification.rb4
-rw-r--r--lib/rubygems/resolver/installed_specification.rb2
-rw-r--r--lib/rubygems/resolver/installer_set.rb11
-rw-r--r--lib/rubygems/resolver/local_specification.rb2
-rw-r--r--lib/rubygems/resolver/lock_set.rb2
-rw-r--r--lib/rubygems/resolver/molinillo.rb3
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo.rb11
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb57
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb88
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb255
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb36
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb66
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb62
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/delete_edge.rb63
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb61
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb126
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb46
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb36
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb164
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb149
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb6
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb112
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb67
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb839
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb46
-rw-r--r--lib/rubygems/resolver/molinillo/lib/molinillo/state.rb58
-rw-r--r--lib/rubygems/resolver/spec_specification.rb7
-rw-r--r--lib/rubygems/s3_uri_signer.rb18
-rw-r--r--lib/rubygems/safe_marshal.rb74
-rw-r--r--lib/rubygems/safe_marshal/elements.rb146
-rw-r--r--lib/rubygems/safe_marshal/reader.rb308
-rw-r--r--lib/rubygems/safe_marshal/visitors/stream_printer.rb31
-rw-r--r--lib/rubygems/safe_marshal/visitors/to_ruby.rb415
-rw-r--r--lib/rubygems/safe_marshal/visitors/visitor.rb74
-rw-r--r--lib/rubygems/safe_yaml.rb38
-rw-r--r--lib/rubygems/security.rb36
-rw-r--r--lib/rubygems/security/policies.rb74
-rw-r--r--lib/rubygems/security/policy.rb18
-rw-r--r--lib/rubygems/security/signer.rb14
-rw-r--r--lib/rubygems/security/trust_dir.rb20
-rw-r--r--lib/rubygems/security_option.rb2
-rw-r--r--lib/rubygems/source.rb50
-rw-r--r--lib/rubygems/source/git.rb20
-rw-r--r--lib/rubygems/source/installed.rb6
-rw-r--r--lib/rubygems/source/local.rb95
-rw-r--r--lib/rubygems/source/lock.rb4
-rw-r--r--lib/rubygems/source/specific_file.rb9
-rw-r--r--lib/rubygems/source/vendor.rb2
-rw-r--r--lib/rubygems/source_list.rb16
-rw-r--r--lib/rubygems/spec_fetcher.rb101
-rw-r--r--lib/rubygems/specification.rb551
-rw-r--r--lib/rubygems/specification_policy.rb185
-rw-r--r--lib/rubygems/specification_record.rb212
-rw-r--r--lib/rubygems/stub_specification.rb53
-rw-r--r--lib/rubygems/target_rbconfig.rb50
-rw-r--r--lib/rubygems/text.rb3
-rw-r--r--lib/rubygems/tsort.rb3
-rw-r--r--lib/rubygems/tsort/.document (renamed from lib/bundler/vendor/fileutils/.document)0
-rw-r--r--lib/rubygems/tsort/lib/tsort.rb452
-rw-r--r--lib/rubygems/uninstaller.rb83
-rw-r--r--lib/rubygems/update_suggestion.rb25
-rw-r--r--lib/rubygems/uri.rb12
-rw-r--r--lib/rubygems/uri_formatter.rb2
-rw-r--r--lib/rubygems/user_interaction.rb44
-rw-r--r--lib/rubygems/util.rb14
-rw-r--r--lib/rubygems/util/licenses.rb331
-rw-r--r--lib/rubygems/util/list.rb4
-rw-r--r--lib/rubygems/validator.rb20
-rw-r--r--lib/rubygems/vendor/molinillo/.document1
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo.rb11
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb57
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb88
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph.rb255
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/action.rb36
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb66
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb62
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb63
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb61
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/log.rb126
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb46
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb36
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb164
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/errors.rb149
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/gem_metadata.rb6
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/modules/specification_provider.rb112
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/modules/ui.rb67
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/resolution.rb839
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/resolver.rb46
-rw-r--r--lib/rubygems/vendor/molinillo/lib/molinillo/state.rb58
-rw-r--r--lib/rubygems/vendor/net-http/.document1
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http.rb2496
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/backward.rb40
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb34
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb414
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/header.rb981
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/proxy_delta.rb17
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/request.rb88
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/requests.rb425
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/response.rb738
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/responses.rb1174
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/http/status.rb84
-rw-r--r--lib/rubygems/vendor/net-http/lib/net/https.rb23
-rw-r--r--lib/rubygems/vendor/net-protocol/.document1
-rw-r--r--lib/rubygems/vendor/net-protocol/lib/net/protocol.rb544
-rw-r--r--lib/rubygems/vendor/optparse/.document1
-rw-r--r--lib/rubygems/vendor/optparse/lib/optparse.rb2330
-rw-r--r--lib/rubygems/vendor/optparse/lib/optparse/uri.rb7
-rw-r--r--lib/rubygems/vendor/resolv/.document1
-rw-r--r--lib/rubygems/vendor/resolv/lib/resolv.rb3442
-rw-r--r--lib/rubygems/vendor/securerandom/.document1
-rw-r--r--lib/rubygems/vendor/securerandom/lib/random/formatter.rb373
-rw-r--r--lib/rubygems/vendor/securerandom/lib/securerandom.rb96
-rw-r--r--lib/rubygems/vendor/timeout/.document1
-rw-r--r--lib/rubygems/vendor/timeout/lib/timeout.rb199
-rw-r--r--lib/rubygems/vendor/tsort/.document1
-rw-r--r--lib/rubygems/vendor/tsort/lib/tsort.rb455
-rw-r--r--lib/rubygems/vendor/uri/.document1
-rw-r--r--lib/rubygems/vendor/uri/lib/uri.rb104
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/common.rb853
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/file.rb100
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/ftp.rb267
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/generic.rb1588
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/http.rb125
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/https.rb23
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/ldap.rb261
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/ldaps.rb22
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/mailto.rb293
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb539
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/rfc3986_parser.rb183
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/version.rb6
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/ws.rb83
-rw-r--r--lib/rubygems/vendor/uri/lib/uri/wss.rb23
-rw-r--r--lib/rubygems/vendored_molinillo.rb3
-rw-r--r--lib/rubygems/vendored_net_http.rb5
-rw-r--r--lib/rubygems/vendored_optparse.rb3
-rw-r--r--lib/rubygems/vendored_securerandom.rb4
-rw-r--r--lib/rubygems/vendored_timeout.rb5
-rw-r--r--lib/rubygems/vendored_tsort.rb3
-rw-r--r--lib/rubygems/version.rb73
-rw-r--r--lib/rubygems/version_option.rb7
-rw-r--r--lib/rubygems/yaml_serializer.rb98
-rw-r--r--lib/securerandom.gemspec20
-rw-r--r--lib/securerandom.rb25
-rw-r--r--lib/set.rb84
-rw-r--r--lib/set/set.gemspec13
-rw-r--r--lib/shellwords.gemspec17
-rw-r--r--lib/shellwords.rb13
-rw-r--r--lib/singleton.gemspec30
-rw-r--r--lib/singleton.rb114
-rw-r--r--lib/singleton/singleton.gemspec30
-rw-r--r--lib/syntax_suggest/api.rb47
-rw-r--r--lib/syntax_suggest/around_block_scan.rb4
-rw-r--r--lib/syntax_suggest/block_expand.rb2
-rw-r--r--lib/syntax_suggest/capture_code_context.rb2
-rw-r--r--lib/syntax_suggest/clean_document.rb14
-rw-r--r--lib/syntax_suggest/code_block.rb2
-rw-r--r--lib/syntax_suggest/code_frontier.rb2
-rw-r--r--lib/syntax_suggest/code_line.rb17
-rw-r--r--lib/syntax_suggest/code_search.rb4
-rw-r--r--lib/syntax_suggest/core_ext.rb2
-rw-r--r--lib/syntax_suggest/display_invalid_blocks.rb2
-rw-r--r--lib/syntax_suggest/explain_syntax.rb22
-rw-r--r--lib/syntax_suggest/lex_all.rb39
-rw-r--r--lib/syntax_suggest/parse_blocks_from_indent_line.rb2
-rw-r--r--lib/syntax_suggest/pathname_from_message.rb2
-rw-r--r--lib/syntax_suggest/ripper_errors.rb5
-rw-r--r--lib/syntax_suggest/scan_history.rb2
-rw-r--r--lib/syntax_suggest/syntax_suggest.gemspec2
-rw-r--r--lib/syntax_suggest/version.rb2
-rw-r--r--lib/tempfile.gemspec19
-rw-r--r--lib/tempfile.rb307
-rw-r--r--lib/time.gemspec21
-rw-r--r--lib/time.rb66
-rw-r--r--lib/timeout.gemspec33
-rw-r--r--lib/timeout.rb45
-rw-r--r--lib/timeout/timeout.gemspec30
-rw-r--r--lib/tmpdir.gemspec10
-rw-r--r--lib/tmpdir.rb37
-rw-r--r--lib/tsort.gemspec11
-rw-r--r--lib/tsort.rb3
-rw-r--r--lib/un.gemspec11
-rw-r--r--lib/un.rb4
-rw-r--r--lib/uri.rb18
-rw-r--r--lib/uri/common.rb440
-rw-r--r--lib/uri/file.rb6
-rw-r--r--lib/uri/ftp.rb2
-rw-r--r--lib/uri/generic.rb58
-rw-r--r--lib/uri/http.rb4
-rw-r--r--lib/uri/rfc2396_parser.rb6
-rw-r--r--lib/uri/rfc3986_parser.rb155
-rw-r--r--lib/uri/uri.gemspec18
-rw-r--r--lib/uri/version.rb2
-rw-r--r--lib/weakref.gemspec34
-rw-r--r--lib/weakref.rb2
-rw-r--r--lib/weakref/weakref.gemspec34
-rw-r--r--lib/yaml.rb1
-rw-r--r--lib/yaml/store.rb10
-rw-r--r--lib/yaml/yaml.gemspec13
-rwxr-xr-xlibexec/bundle11
-rwxr-xr-xlibexec/irb2
-rwxr-xr-xlibexec/racc320
-rw-r--r--load.c222
-rw-r--r--main.c24
-rw-r--r--man/irb.17
-rw-r--r--man/ruby.1167
-rw-r--r--marshal.c197
-rw-r--r--math.c82
-rw-r--r--memory_view.c6
-rw-r--r--method.h8
-rw-r--r--mini_builtin.c124
-rw-r--r--miniinit.c58
-rw-r--r--misc/.vscode/launch.json13
-rw-r--r--misc/.vscode/settings.json8
-rw-r--r--misc/.vscode/tasks.json14
-rw-r--r--misc/README1
-rw-r--r--misc/call_fuzzer.rb372
-rwxr-xr-xmisc/call_fuzzer.sh13
-rw-r--r--misc/gdb.py181
-rwxr-xr-xmisc/lldb_cruby.py65
-rw-r--r--misc/lldb_rb/commands/heap_page_command.py4
-rw-r--r--misc/lldb_rb/commands/print_flags_command.py31
-rw-r--r--misc/lldb_rb/commands/rb_id2str_command.py49
-rw-r--r--misc/lldb_rb/commands/rp_command.py15
-rw-r--r--misc/lldb_rb/constants.py2
-rw-r--r--misc/lldb_rb/lldb_interface.py7
-rw-r--r--misc/lldb_rb/rb_base_command.py24
-rw-r--r--misc/lldb_rb/rb_heap_structs.py143
-rw-r--r--misc/lldb_rb/utils.py513
-rw-r--r--misc/lldb_yjit.py47
-rw-r--r--misc/ruby-style.el11
-rwxr-xr-xmisc/yjit_perf.py116
-rw-r--r--missing/dtoa.c27
-rw-r--r--missing/explicit_bzero.c5
-rw-r--r--missing/procstat_vm.c34
-rw-r--r--missing/setproctitle.c68
-rw-r--r--mjit.c1999
-rw-r--r--mjit.h145
-rw-r--r--mjit.rb37
-rw-r--r--mjit_c.c43
-rw-r--r--mjit_c.h97
-rw-r--r--mjit_c.rb807
-rw-r--r--node.c1587
-rw-r--r--node.h537
-rw-r--r--node_dump.c1281
-rw-r--r--numeric.c769
-rw-r--r--numeric.rb363
-rw-r--r--object.c703
-rw-r--r--pack.c186
-rw-r--r--pack.rb11
-rw-r--r--parse.y20849
-rw-r--r--parser_bits.h564
-rw-r--r--parser_node.h32
-rw-r--r--parser_st.c164
-rw-r--r--parser_st.h162
-rw-r--r--parser_value.h106
-rw-r--r--prelude.rb41
-rw-r--r--prism/api_pack.c276
-rw-r--r--prism/config.yml4058
-rw-r--r--prism/defines.h242
-rw-r--r--prism/encoding.c5235
-rw-r--r--prism/encoding.h283
-rw-r--r--prism/extension.c1217
-rw-r--r--prism/extension.h19
-rw-r--r--prism/node.h129
-rw-r--r--prism/options.c297
-rw-r--r--prism/options.h396
-rw-r--r--prism/pack.c509
-rw-r--r--prism/pack.h163
-rw-r--r--prism/parser.h933
-rw-r--r--prism/prettyprint.h34
-rw-r--r--prism/prism.c22584
-rw-r--r--prism/prism.h336
-rw-r--r--prism/regexp.c786
-rw-r--r--prism/regexp.h43
-rw-r--r--prism/static_literals.c617
-rw-r--r--prism/static_literals.h121
-rw-r--r--prism/templates/ext/prism/api_node.c.erb259
-rw-r--r--prism/templates/include/prism/ast.h.erb224
-rw-r--r--prism/templates/include/prism/diagnostic.h.erb130
-rw-r--r--prism/templates/lib/prism/compiler.rb.erb41
-rw-r--r--prism/templates/lib/prism/dispatcher.rb.erb90
-rw-r--r--prism/templates/lib/prism/dot_visitor.rb.erb188
-rw-r--r--prism/templates/lib/prism/dsl.rb.erb133
-rw-r--r--prism/templates/lib/prism/inspect_visitor.rb.erb131
-rw-r--r--prism/templates/lib/prism/mutation_compiler.rb.erb19
-rw-r--r--prism/templates/lib/prism/node.rb.erb414
-rw-r--r--prism/templates/lib/prism/reflection.rb.erb136
-rw-r--r--prism/templates/lib/prism/serialize.rb.erb404
-rw-r--r--prism/templates/lib/prism/visitor.rb.erb53
-rw-r--r--prism/templates/src/diagnostic.c.erb520
-rw-r--r--prism/templates/src/node.c.erb333
-rw-r--r--prism/templates/src/prettyprint.c.erb166
-rw-r--r--prism/templates/src/serialize.c.erb406
-rw-r--r--prism/templates/src/token_type.c.erb369
-rwxr-xr-xprism/templates/template.rb683
-rw-r--r--prism/util/pm_buffer.c317
-rw-r--r--prism/util/pm_buffer.h218
-rw-r--r--prism/util/pm_char.c318
-rw-r--r--prism/util/pm_char.h204
-rw-r--r--prism/util/pm_constant_pool.c338
-rw-r--r--prism/util/pm_constant_pool.h218
-rw-r--r--prism/util/pm_integer.c670
-rw-r--r--prism/util/pm_integer.h126
-rw-r--r--prism/util/pm_list.c49
-rw-r--r--prism/util/pm_list.h97
-rw-r--r--prism/util/pm_memchr.c35
-rw-r--r--prism/util/pm_memchr.h29
-rw-r--r--prism/util/pm_newline_list.c125
-rw-r--r--prism/util/pm_newline_list.h113
-rw-r--r--prism/util/pm_string.c382
-rw-r--r--prism/util/pm_string.h190
-rw-r--r--prism/util/pm_strncasecmp.c24
-rw-r--r--prism/util/pm_strncasecmp.h32
-rw-r--r--prism/util/pm_strpbrk.c206
-rw-r--r--prism/util/pm_strpbrk.h46
-rw-r--r--prism/version.h29
-rw-r--r--prism_compile.c11072
-rw-r--r--prism_compile.h99
-rw-r--r--prism_init.c9
-rw-r--r--probes_helper.h2
-rw-r--r--proc.c427
-rw-r--r--process.c3433
-rw-r--r--ractor.c2056
-rw-r--r--ractor.rb255
-rw-r--r--ractor_core.h112
-rw-r--r--random.c51
-rw-r--r--range.c792
-rw-r--r--rational.c69
-rw-r--r--re.c717
-rw-r--r--regcomp.c124
-rw-r--r--regenc.h5
-rw-r--r--regexec.c1112
-rw-r--r--regint.h65
-rw-r--r--regparse.c189
-rw-r--r--regparse.h3
-rw-r--r--rjit.c501
-rw-r--r--rjit.h101
-rw-r--r--rjit.rb41
-rw-r--r--rjit_c.c543
-rw-r--r--rjit_c.h165
-rw-r--r--rjit_c.rb1667
-rw-r--r--ruby-runner.c35
-rw-r--r--ruby.c1652
-rw-r--r--ruby_parser.c1135
-rw-r--r--rubyparser.h1350
-rw-r--r--sample/all-ruby-quine.rb24
-rw-r--r--sample/dir.rb11
-rw-r--r--sample/getoptlong/abbrev.rb9
-rw-r--r--sample/getoptlong/aliases.rb8
-rw-r--r--sample/getoptlong/argv.rb12
-rw-r--r--sample/getoptlong/each.rb12
-rw-r--r--sample/getoptlong/fibonacci.rb62
-rw-r--r--sample/getoptlong/permute.rb12
-rw-r--r--sample/getoptlong/require_order.rb13
-rw-r--r--sample/getoptlong/return_in_order.rb13
-rw-r--r--sample/getoptlong/simple.rb7
-rw-r--r--sample/getoptlong/types.rb10
-rw-r--r--sample/net-imap.rb167
-rw-r--r--sample/prism/find_calls.rb105
-rw-r--r--sample/prism/find_comments.rb100
-rw-r--r--sample/prism/locate_nodes.rb84
-rw-r--r--sample/prism/make_tags.rb302
-rw-r--r--sample/prism/visit_nodes.rb63
-rw-r--r--sample/win32ole/olegen.rb348
-rw-r--r--scheduler.c86
-rw-r--r--shape.c997
-rw-r--r--shape.h152
-rw-r--r--signal.c211
-rw-r--r--siphash.c3
-rw-r--r--spec/README.md8
-rw-r--r--spec/bundled_gems.mspec6
-rw-r--r--spec/bundler/bundler/bundler_spec.rb41
-rw-r--r--spec/bundler/bundler/ci_detector_spec.rb21
-rw-r--r--spec/bundler/bundler/cli_spec.rb52
-rw-r--r--spec/bundler/bundler/compact_index_client/parser_spec.rb237
-rw-r--r--spec/bundler/bundler/compact_index_client/updater_spec.rb189
-rw-r--r--spec/bundler/bundler/definition_spec.rb115
-rw-r--r--spec/bundler/bundler/dependency_spec.rb226
-rw-r--r--spec/bundler/bundler/digest_spec.rb6
-rw-r--r--spec/bundler/bundler/dsl_spec.rb112
-rw-r--r--spec/bundler/bundler/endpoint_specification_spec.rb8
-rw-r--r--spec/bundler/bundler/env_spec.rb44
-rw-r--r--spec/bundler/bundler/environment_preserver_spec.rb16
-rw-r--r--spec/bundler/bundler/fetcher/base_spec.rb11
-rw-r--r--spec/bundler/bundler/fetcher/compact_index_spec.rb18
-rw-r--r--spec/bundler/bundler/fetcher/dependency_spec.rb25
-rw-r--r--spec/bundler/bundler/fetcher/downloader_spec.rb66
-rw-r--r--spec/bundler/bundler/fetcher/index_spec.rb7
-rw-r--r--spec/bundler/bundler/fetcher_spec.rb98
-rw-r--r--spec/bundler/bundler/friendly_errors_spec.rb10
-rw-r--r--spec/bundler/bundler/gem_helper_spec.rb42
-rw-r--r--spec/bundler/bundler/gem_version_promoter_spec.rb56
-rw-r--r--spec/bundler/bundler/installer/gem_installer_spec.rb13
-rw-r--r--spec/bundler/bundler/installer/parallel_installer_spec.rb46
-rw-r--r--spec/bundler/bundler/installer/spec_installation_spec.rb18
-rw-r--r--spec/bundler/bundler/lockfile_parser_spec.rb78
-rw-r--r--spec/bundler/bundler/mirror_spec.rb16
-rw-r--r--spec/bundler/bundler/plugin/api/source_spec.rb4
-rw-r--r--spec/bundler/bundler/plugin/dsl_spec.rb6
-rw-r--r--spec/bundler/bundler/plugin/index_spec.rb2
-rw-r--r--spec/bundler/bundler/plugin/installer_spec.rb21
-rw-r--r--spec/bundler/bundler/plugin_spec.rb14
-rw-r--r--spec/bundler/bundler/remote_specification_spec.rb12
-rw-r--r--spec/bundler/bundler/resolver/candidate_spec.rb19
-rw-r--r--spec/bundler/bundler/retry_spec.rb2
-rw-r--r--spec/bundler/bundler/ruby_dsl_spec.rb110
-rw-r--r--spec/bundler/bundler/rubygems_integration_spec.rb35
-rw-r--r--spec/bundler/bundler/settings/validator_spec.rb6
-rw-r--r--spec/bundler/bundler/settings_spec.rb43
-rw-r--r--spec/bundler/bundler/shared_helpers_spec.rb77
-rw-r--r--spec/bundler/bundler/source/git/git_proxy_spec.rb122
-rw-r--r--spec/bundler/bundler/source/git_spec.rb4
-rw-r--r--spec/bundler/bundler/source/rubygems/remote_spec.rb20
-rw-r--r--spec/bundler/bundler/source_list_spec.rb6
-rw-r--r--spec/bundler/bundler/source_spec.rb20
-rw-r--r--spec/bundler/bundler/spec_set_spec.rb18
-rw-r--r--spec/bundler/bundler/specifications/foo.gemspec13
-rw-r--r--spec/bundler/bundler/stub_specification_spec.rb31
-rw-r--r--spec/bundler/bundler/ui/shell_spec.rb26
-rw-r--r--spec/bundler/bundler/uri_credentials_filter_spec.rb10
-rw-r--r--spec/bundler/bundler/yaml_serializer_spec.rb57
-rw-r--r--spec/bundler/cache/cache_path_spec.rb12
-rw-r--r--spec/bundler/cache/gems_spec.rb317
-rw-r--r--spec/bundler/cache/git_spec.rb209
-rw-r--r--spec/bundler/cache/path_spec.rb34
-rw-r--r--spec/bundler/cache/platform_spec.rb18
-rw-r--r--spec/bundler/commands/add_spec.rb144
-rw-r--r--spec/bundler/commands/binstubs_spec.rb255
-rw-r--r--spec/bundler/commands/cache_spec.rb223
-rw-r--r--spec/bundler/commands/check_spec.rb225
-rw-r--r--spec/bundler/commands/clean_spec.rb266
-rw-r--r--spec/bundler/commands/config_spec.rb82
-rw-r--r--spec/bundler/commands/console_spec.rb22
-rw-r--r--spec/bundler/commands/doctor_spec.rb17
-rw-r--r--spec/bundler/commands/exec_spec.rb359
-rw-r--r--spec/bundler/commands/fund_spec.rb50
-rw-r--r--spec/bundler/commands/help_spec.rb9
-rw-r--r--spec/bundler/commands/info_spec.rb48
-rw-r--r--spec/bundler/commands/init_spec.rb42
-rw-r--r--spec/bundler/commands/inject_spec.rb58
-rw-r--r--spec/bundler/commands/install_spec.rb941
-rw-r--r--spec/bundler/commands/issue_spec.rb2
-rw-r--r--spec/bundler/commands/licenses_spec.rb4
-rw-r--r--spec/bundler/commands/list_spec.rb58
-rw-r--r--spec/bundler/commands/lock_spec.rb1134
-rw-r--r--spec/bundler/commands/newgem_spec.rb383
-rw-r--r--spec/bundler/commands/open_spec.rb63
-rw-r--r--spec/bundler/commands/outdated_spec.rb309
-rw-r--r--spec/bundler/commands/platform_spec.rb500
-rw-r--r--spec/bundler/commands/post_bundle_message_spec.rb36
-rw-r--r--spec/bundler/commands/pristine_spec.rb22
-rw-r--r--spec/bundler/commands/remove_spec.rb342
-rw-r--r--spec/bundler/commands/show_spec.rb36
-rw-r--r--spec/bundler/commands/update_spec.rb830
-rw-r--r--spec/bundler/commands/version_spec.rb16
-rw-r--r--spec/bundler/commands/viz_spec.rb76
-rw-r--r--spec/bundler/install/allow_offline_install_spec.rb42
-rw-r--r--spec/bundler/install/binstubs_spec.rb20
-rw-r--r--spec/bundler/install/bundler_spec.rb68
-rw-r--r--spec/bundler/install/deploy_spec.rb308
-rw-r--r--spec/bundler/install/failure_spec.rb8
-rw-r--r--spec/bundler/install/gemfile/eval_gemfile_spec.rb40
-rw-r--r--spec/bundler/install/gemfile/force_ruby_platform_spec.rb86
-rw-r--r--spec/bundler/install/gemfile/gemspec_spec.rb327
-rw-r--r--spec/bundler/install/gemfile/git_spec.rb570
-rw-r--r--spec/bundler/install/gemfile/groups_spec.rb106
-rw-r--r--spec/bundler/install/gemfile/install_if_spec.rb23
-rw-r--r--spec/bundler/install/gemfile/lockfile_spec.rb13
-rw-r--r--spec/bundler/install/gemfile/path_spec.rb374
-rw-r--r--spec/bundler/install/gemfile/platform_spec.rb469
-rw-r--r--spec/bundler/install/gemfile/ruby_spec.rb94
-rw-r--r--spec/bundler/install/gemfile/sources_spec.rb942
-rw-r--r--spec/bundler/install/gemfile/specific_platform_spec.rb951
-rw-r--r--spec/bundler/install/gemfile_spec.rb69
-rw-r--r--spec/bundler/install/gems/compact_index_spec.rb567
-rw-r--r--spec/bundler/install/gems/dependency_api_fallback_spec.rb53
-rw-r--r--spec/bundler/install/gems/dependency_api_spec.rb290
-rw-r--r--spec/bundler/install/gems/env_spec.rb36
-rw-r--r--spec/bundler/install/gems/flex_spec.rb207
-rw-r--r--spec/bundler/install/gems/fund_spec.rb28
-rw-r--r--spec/bundler/install/gems/mirror_spec.rb22
-rw-r--r--spec/bundler/install/gems/native_extensions_spec.rb18
-rw-r--r--spec/bundler/install/gems/post_install_spec.rb44
-rw-r--r--spec/bundler/install/gems/resolving_spec.rb287
-rw-r--r--spec/bundler/install/gems/standalone_spec.rb158
-rw-r--r--spec/bundler/install/gems/win32_spec.rb10
-rw-r--r--spec/bundler/install/gemspecs_spec.rb76
-rw-r--r--spec/bundler/install/git_spec.rb122
-rw-r--r--spec/bundler/install/global_cache_spec.rb154
-rw-r--r--spec/bundler/install/path_spec.rb90
-rw-r--r--spec/bundler/install/prereleases_spec.rb16
-rw-r--r--spec/bundler/install/process_lock_spec.rb8
-rw-r--r--spec/bundler/install/redownload_spec.rb22
-rw-r--r--spec/bundler/install/security_policy_spec.rb20
-rw-r--r--spec/bundler/install/yanked_spec.rb75
-rw-r--r--spec/bundler/lock/git_spec.rb20
-rw-r--r--spec/bundler/lock/lockfile_spec.rb927
-rw-r--r--spec/bundler/other/cli_dispatch_spec.rb6
-rw-r--r--spec/bundler/other/ext_spec.rb28
-rw-r--r--spec/bundler/other/major_deprecation_spec.rb286
-rw-r--r--spec/bundler/plugins/command_spec.rb10
-rw-r--r--spec/bundler/plugins/hook_spec.rb133
-rw-r--r--spec/bundler/plugins/install_spec.rb143
-rw-r--r--spec/bundler/plugins/list_spec.rb4
-rw-r--r--spec/bundler/plugins/source/example_spec.rb40
-rw-r--r--spec/bundler/plugins/source_spec.rb16
-rw-r--r--spec/bundler/plugins/uninstall_spec.rb29
-rw-r--r--spec/bundler/quality_spec.rb32
-rw-r--r--spec/bundler/realworld/dependency_api_spec.rb46
-rw-r--r--spec/bundler/realworld/double_check_spec.rb6
-rw-r--r--spec/bundler/realworld/edgecases_spec.rb322
-rw-r--r--spec/bundler/realworld/ffi_spec.rb2
-rw-r--r--spec/bundler/realworld/fixtures/warbler/Gemfile4
-rw-r--r--spec/bundler/realworld/fixtures/warbler/Gemfile.lock6
-rw-r--r--spec/bundler/realworld/gemfile_source_header_spec.rb20
-rw-r--r--spec/bundler/realworld/git_spec.rb2
-rw-r--r--spec/bundler/realworld/mirror_probe_spec.rb24
-rw-r--r--spec/bundler/realworld/parallel_spec.rb8
-rw-r--r--spec/bundler/realworld/slow_perf_spec.rb117
-rw-r--r--spec/bundler/resolver/basic_spec.rb62
-rw-r--r--spec/bundler/resolver/platform_spec.rb22
-rw-r--r--spec/bundler/runtime/env_helpers_spec.rb307
-rw-r--r--spec/bundler/runtime/executable_spec.rb90
-rw-r--r--spec/bundler/runtime/gem_tasks_spec.rb77
-rw-r--r--spec/bundler/runtime/inline_spec.rb334
-rw-r--r--spec/bundler/runtime/load_spec.rb28
-rw-r--r--spec/bundler/runtime/platform_spec.rb144
-rw-r--r--spec/bundler/runtime/require_spec.rb80
-rw-r--r--spec/bundler/runtime/requiring_spec.rb15
-rw-r--r--spec/bundler/runtime/self_management_spec.rb121
-rw-r--r--spec/bundler/runtime/setup_spec.rb551
-rw-r--r--spec/bundler/runtime/with_unbundled_env_spec.rb302
-rw-r--r--spec/bundler/spec_helper.rb15
-rw-r--r--spec/bundler/support/activate.rb9
-rw-r--r--spec/bundler/support/artifice/compact_index_checksum_mismatch.rb4
-rw-r--r--spec/bundler/support/artifice/compact_index_concurrent_download.rb7
-rw-r--r--spec/bundler/support/artifice/compact_index_etag_match.rb16
-rw-r--r--spec/bundler/support/artifice/compact_index_host_redirect.rb2
-rw-r--r--spec/bundler/support/artifice/compact_index_partial_update.rb2
-rw-r--r--spec/bundler/support/artifice/compact_index_partial_update_bad_digest.rb40
-rw-r--r--spec/bundler/support/artifice/compact_index_partial_update_no_digest_not_incremental.rb42
-rw-r--r--spec/bundler/support/artifice/compact_index_partial_update_no_etag_not_incremental.rb40
-rw-r--r--spec/bundler/support/artifice/compact_index_range_ignored.rb40
-rw-r--r--spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb3
-rw-r--r--spec/bundler/support/artifice/endpoint_500.rb2
-rw-r--r--spec/bundler/support/artifice/endpoint_host_redirect.rb2
-rw-r--r--spec/bundler/support/artifice/endpoint_mirror_source.rb2
-rw-r--r--spec/bundler/support/artifice/fail.rb14
-rw-r--r--spec/bundler/support/artifice/helpers/artifice.rb6
-rw-r--r--spec/bundler/support/artifice/helpers/compact_index.rb34
-rw-r--r--spec/bundler/support/artifice/helpers/endpoint.rb12
-rw-r--r--spec/bundler/support/artifice/helpers/rack_request.rb24
-rw-r--r--spec/bundler/support/artifice/used_cassettes.txt20908
-rw-r--r--spec/bundler/support/artifice/vcr.rb14
-rw-r--r--spec/bundler/support/artifice/windows.rb2
-rw-r--r--spec/bundler/support/build_metadata.rb14
-rw-r--r--spec/bundler/support/builders.rb193
-rw-r--r--spec/bundler/support/bundle.rb7
-rw-r--r--spec/bundler/support/checksums.rb126
-rw-r--r--spec/bundler/support/command_execution.rb48
-rw-r--r--spec/bundler/support/env.rb9
-rw-r--r--spec/bundler/support/filters.rb24
-rw-r--r--spec/bundler/support/hax.rb14
-rw-r--r--spec/bundler/support/helpers.rb296
-rw-r--r--spec/bundler/support/indexes.rb30
-rw-r--r--spec/bundler/support/matchers.rb16
-rw-r--r--spec/bundler/support/options.rb15
-rw-r--r--spec/bundler/support/path.rb68
-rw-r--r--spec/bundler/support/platforms.rb11
-rw-r--r--spec/bundler/support/rubygems_ext.rb25
-rw-r--r--spec/bundler/support/rubygems_version_manager.rb38
-rw-r--r--spec/bundler/support/subprocess.rb108
-rw-r--r--spec/bundler/support/vendored_net_http.rb23
-rw-r--r--spec/bundler/update/gemfile_spec.rb24
-rw-r--r--spec/bundler/update/gems/fund_spec.rb6
-rw-r--r--spec/bundler/update/gems/post_install_spec.rb24
-rw-r--r--spec/bundler/update/git_spec.rb143
-rw-r--r--spec/bundler/update/path_spec.rb6
-rw-r--r--spec/bundler/update/redownload_spec.rb26
-rw-r--r--spec/default.mspec94
-rw-r--r--spec/lib/formatter_overrides.rb6
-rw-r--r--spec/lib/spec_coverage.rb1
-rwxr-xr-xspec/mspec/lib/mspec/commands/mspec.rb5
-rw-r--r--spec/mspec/lib/mspec/guards/platform.rb18
-rw-r--r--spec/mspec/lib/mspec/helpers/io.rb4
-rw-r--r--spec/mspec/lib/mspec/helpers/numeric.rb28
-rw-r--r--spec/mspec/lib/mspec/helpers/ruby_exe.rb54
-rw-r--r--spec/mspec/lib/mspec/helpers/tmp.rb18
-rw-r--r--spec/mspec/lib/mspec/matchers/complain.rb2
-rw-r--r--spec/mspec/lib/mspec/mocks/mock.rb25
-rw-r--r--spec/mspec/lib/mspec/runner/actions/leakchecker.rb64
-rw-r--r--spec/mspec/lib/mspec/runner/actions/timeout.rb78
-rw-r--r--spec/mspec/lib/mspec/runner/formatters/base.rb8
-rw-r--r--spec/mspec/lib/mspec/runner/formatters/multi.rb2
-rw-r--r--spec/mspec/lib/mspec/runner/mspec.rb5
-rw-r--r--spec/mspec/lib/mspec/utils/options.rb2
-rw-r--r--spec/mspec/lib/mspec/utils/warnings.rb43
-rw-r--r--spec/mspec/spec/commands/mspec_spec.rb27
-rw-r--r--spec/mspec/spec/guards/platform_spec.rb38
-rw-r--r--spec/mspec/spec/helpers/ruby_exe_spec.rb10
-rw-r--r--spec/mspec/spec/integration/run_spec.rb9
-rw-r--r--spec/mspec/spec/integration/tag_spec.rb9
-rw-r--r--spec/mspec/spec/mocks/mock_spec.rb21
-rw-r--r--spec/mspec/spec/runner/context_spec.rb2
-rw-r--r--spec/mspec/spec/spec_helper.rb2
-rwxr-xr-xspec/mspec/tool/check_require_spec_helper.rb34
-rw-r--r--spec/mspec/tool/remove_old_guards.rb51
-rwxr-xr-xspec/mspec/tool/tag_from_output.rb10
-rw-r--r--spec/ruby/.mspec.constants2
-rw-r--r--spec/ruby/.rubocop.yml12
-rw-r--r--spec/ruby/.rubocop_todo.yml2
-rw-r--r--spec/ruby/CONTRIBUTING.md21
-rw-r--r--spec/ruby/README.md13
-rw-r--r--spec/ruby/command_line/backtrace_limit_spec.rb49
-rw-r--r--spec/ruby/command_line/dash_a_spec.rb4
-rw-r--r--spec/ruby/command_line/dash_l_spec.rb8
-rw-r--r--spec/ruby/command_line/dash_n_spec.rb8
-rw-r--r--spec/ruby/command_line/dash_p_spec.rb4
-rw-r--r--spec/ruby/command_line/dash_r_spec.rb5
-rw-r--r--spec/ruby/command_line/dash_upper_f_spec.rb2
-rw-r--r--spec/ruby/command_line/dash_upper_u_spec.rb7
-rw-r--r--spec/ruby/command_line/dash_v_spec.rb5
-rw-r--r--spec/ruby/command_line/fixtures/bin/embedded_ruby.txt2
-rw-r--r--spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rbbin90 -> 121 bytes-rw-r--r--spec/ruby/command_line/fixtures/string_literal_frozen_comment.rb4
-rw-r--r--spec/ruby/command_line/fixtures/string_literal_mutable_comment.rb4
-rw-r--r--spec/ruby/command_line/fixtures/string_literal_raw.rb3
-rw-r--r--spec/ruby/command_line/frozen_strings_spec.rb36
-rw-r--r--spec/ruby/command_line/rubyopt_spec.rb18
-rw-r--r--spec/ruby/command_line/syntax_error_spec.rb10
-rw-r--r--spec/ruby/core/argf/bytes_spec.rb16
-rw-r--r--spec/ruby/core/argf/chars_spec.rb16
-rw-r--r--spec/ruby/core/argf/codepoints_spec.rb16
-rw-r--r--spec/ruby/core/argf/lines_spec.rb16
-rw-r--r--spec/ruby/core/argf/readpartial_spec.rb4
-rw-r--r--spec/ruby/core/argf/shared/getc.rb2
-rw-r--r--spec/ruby/core/argf/shared/read.rb4
-rw-r--r--spec/ruby/core/array/all_spec.rb13
-rw-r--r--spec/ruby/core/array/any_spec.rb12
-rw-r--r--spec/ruby/core/array/assoc_spec.rb14
-rw-r--r--spec/ruby/core/array/bsearch_index_spec.rb4
-rw-r--r--spec/ruby/core/array/count_spec.rb11
-rw-r--r--spec/ruby/core/array/delete_if_spec.rb30
-rw-r--r--spec/ruby/core/array/drop_spec.rb12
-rw-r--r--spec/ruby/core/array/drop_while_spec.rb16
-rw-r--r--spec/ruby/core/array/each_index_spec.rb18
-rw-r--r--spec/ruby/core/array/each_spec.rb7
-rw-r--r--spec/ruby/core/array/fetch_values_spec.rb48
-rw-r--r--spec/ruby/core/array/fill_spec.rb84
-rw-r--r--spec/ruby/core/array/fixtures/classes.rb754
-rw-r--r--spec/ruby/core/array/fixtures/encoded_strings.rb18
-rw-r--r--spec/ruby/core/array/flatten_spec.rb24
-rw-r--r--spec/ruby/core/array/initialize_spec.rb4
-rw-r--r--spec/ruby/core/array/intersect_spec.rb53
-rw-r--r--spec/ruby/core/array/multiply_spec.rb18
-rw-r--r--spec/ruby/core/array/new_spec.rb4
-rw-r--r--spec/ruby/core/array/none_spec.rb13
-rw-r--r--spec/ruby/core/array/one_spec.rb13
-rw-r--r--spec/ruby/core/array/pack/buffer_spec.rb22
-rw-r--r--spec/ruby/core/array/pack/c_spec.rb4
-rw-r--r--spec/ruby/core/array/pack/l_spec.rb16
-rw-r--r--spec/ruby/core/array/pack/shared/basic.rb2
-rw-r--r--spec/ruby/core/array/pack/shared/float.rb16
-rw-r--r--spec/ruby/core/array/pack/shared/integer.rb40
-rw-r--r--spec/ruby/core/array/pack/shared/string.rb2
-rw-r--r--spec/ruby/core/array/pack/shared/unicode.rb4
-rw-r--r--spec/ruby/core/array/pack/w_spec.rb4
-rw-r--r--spec/ruby/core/array/plus_spec.rb21
-rw-r--r--spec/ruby/core/array/product_spec.rb5
-rw-r--r--spec/ruby/core/array/rassoc_spec.rb14
-rw-r--r--spec/ruby/core/array/reject_spec.rb15
-rw-r--r--spec/ruby/core/array/reverse_each_spec.rb16
-rw-r--r--spec/ruby/core/array/rindex_spec.rb17
-rw-r--r--spec/ruby/core/array/sample_spec.rb4
-rw-r--r--spec/ruby/core/array/shared/collect.rb32
-rw-r--r--spec/ruby/core/array/shared/index.rb4
-rw-r--r--spec/ruby/core/array/shared/inspect.rb6
-rw-r--r--spec/ruby/core/array/shared/intersection.rb3
-rw-r--r--spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb25
-rw-r--r--spec/ruby/core/array/shared/keep_if.rb35
-rw-r--r--spec/ruby/core/array/shared/select.rb3
-rw-r--r--spec/ruby/core/array/shared/slice.rb400
-rw-r--r--spec/ruby/core/array/shuffle_spec.rb14
-rw-r--r--spec/ruby/core/array/slice_spec.rb60
-rw-r--r--spec/ruby/core/array/sort_by_spec.rb33
-rw-r--r--spec/ruby/core/array/sum_spec.rb21
-rw-r--r--spec/ruby/core/array/take_spec.rb12
-rw-r--r--spec/ruby/core/array/take_while_spec.rb16
-rw-r--r--spec/ruby/core/array/to_h_spec.rb12
-rw-r--r--spec/ruby/core/array/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/array/uniq_spec.rb46
-rw-r--r--spec/ruby/core/basicobject/fixtures/classes.rb228
-rw-r--r--spec/ruby/core/basicobject/instance_eval_spec.rb124
-rw-r--r--spec/ruby/core/basicobject/method_missing_spec.rb1
-rw-r--r--spec/ruby/core/basicobject/singleton_method_added_spec.rb8
-rw-r--r--spec/ruby/core/binding/clone_spec.rb6
-rw-r--r--spec/ruby/core/binding/dup_spec.rb23
-rw-r--r--spec/ruby/core/binding/eval_spec.rb99
-rw-r--r--spec/ruby/core/binding/fixtures/irbrc1
-rw-r--r--spec/ruby/core/binding/irb_spec.rb15
-rw-r--r--spec/ruby/core/binding/shared/clone.rb22
-rw-r--r--spec/ruby/core/binding/source_location_spec.rb5
-rw-r--r--spec/ruby/core/class/attached_object_spec.rb8
-rw-r--r--spec/ruby/core/class/dup_spec.rb3
-rw-r--r--spec/ruby/core/class/subclasses_spec.rb29
-rw-r--r--spec/ruby/core/complex/inspect_spec.rb21
-rw-r--r--spec/ruby/core/complex/to_r_spec.rb12
-rw-r--r--spec/ruby/core/complex/to_s_spec.rb11
-rw-r--r--spec/ruby/core/conditionvariable/broadcast_spec.rb1
-rw-r--r--spec/ruby/core/conditionvariable/marshal_dump_spec.rb1
-rw-r--r--spec/ruby/core/conditionvariable/signal_spec.rb1
-rw-r--r--spec/ruby/core/conditionvariable/wait_spec.rb1
-rw-r--r--spec/ruby/core/data/constants_spec.rb16
-rw-r--r--spec/ruby/core/data/define_spec.rb36
-rw-r--r--spec/ruby/core/data/fixtures/classes.rb5
-rw-r--r--spec/ruby/core/data/initialize_spec.rb65
-rw-r--r--spec/ruby/core/data/with_spec.rb35
-rw-r--r--spec/ruby/core/dir/chdir_spec.rb16
-rw-r--r--spec/ruby/core/dir/children_spec.rb17
-rw-r--r--spec/ruby/core/dir/each_child_spec.rb13
-rw-r--r--spec/ruby/core/dir/each_spec.rb11
-rw-r--r--spec/ruby/core/dir/entries_spec.rb2
-rw-r--r--spec/ruby/core/dir/exist_spec.rb8
-rw-r--r--spec/ruby/core/dir/fchdir_spec.rb68
-rw-r--r--spec/ruby/core/dir/glob_spec.rb138
-rw-r--r--spec/ruby/core/dir/home_spec.rb33
-rw-r--r--spec/ruby/core/dir/shared/chroot.rb4
-rw-r--r--spec/ruby/core/dir/shared/exist.rb9
-rw-r--r--spec/ruby/core/dir/shared/glob.rb28
-rw-r--r--spec/ruby/core/encoding/compatible_spec.rb74
-rw-r--r--spec/ruby/core/encoding/converter/convert_spec.rb15
-rw-r--r--spec/ruby/core/encoding/converter/finish_spec.rb4
-rw-r--r--spec/ruby/core/encoding/converter/last_error_spec.rb16
-rw-r--r--spec/ruby/core/encoding/converter/new_spec.rb2
-rw-r--r--spec/ruby/core/encoding/converter/primitive_convert_spec.rb5
-rw-r--r--spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb1
-rw-r--r--spec/ruby/core/encoding/converter/putback_spec.rb14
-rw-r--r--spec/ruby/core/encoding/converter/replacement_spec.rb20
-rw-r--r--spec/ruby/core/encoding/default_external_spec.rb8
-rw-r--r--spec/ruby/core/encoding/inspect_spec.rb20
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb1
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb1
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb4
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb5
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb1
-rw-r--r--spec/ruby/core/encoding/name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/replicate_spec.rb31
-rw-r--r--spec/ruby/core/encoding/to_s_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb1
-rw-r--r--spec/ruby/core/enumerable/all_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/any_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/chunk_spec.rb5
-rw-r--r--spec/ruby/core/enumerable/fixtures/classes.rb6
-rw-r--r--spec/ruby/core/enumerable/grep_spec.rb49
-rw-r--r--spec/ruby/core/enumerable/grep_v_spec.rb49
-rw-r--r--spec/ruby/core/enumerable/none_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/one_spec.rb7
-rw-r--r--spec/ruby/core/enumerable/shared/inject.rb81
-rw-r--r--spec/ruby/core/enumerable/sum_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/tally_spec.rb13
-rw-r--r--spec/ruby/core/enumerable/to_h_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/to_set_spec.rb29
-rw-r--r--spec/ruby/core/enumerator/chain/initialize_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/chain/inspect_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/each_spec.rb18
-rw-r--r--spec/ruby/core/enumerator/generator/initialize_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/initialize_spec.rb12
-rw-r--r--spec/ruby/core/enumerator/inspect_spec.rb5
-rw-r--r--spec/ruby/core/enumerator/lazy/compact_spec.rb5
-rw-r--r--spec/ruby/core/enumerator/lazy/initialize_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/new_spec.rb47
-rw-r--r--spec/ruby/core/enumerator/next_values_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/peek_values_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/product/each_spec.rb73
-rw-r--r--spec/ruby/core/enumerator/product/initialize_copy_spec.rb54
-rw-r--r--spec/ruby/core/enumerator/product/initialize_spec.rb33
-rw-r--r--spec/ruby/core/enumerator/product/inspect_spec.rb22
-rw-r--r--spec/ruby/core/enumerator/product/rewind_spec.rb64
-rw-r--r--spec/ruby/core/enumerator/product/size_spec.rb56
-rw-r--r--spec/ruby/core/enumerator/product_spec.rb93
-rw-r--r--spec/ruby/core/enumerator/rewind_spec.rb4
-rw-r--r--spec/ruby/core/env/clone_spec.rb23
-rw-r--r--spec/ruby/core/env/delete_spec.rb16
-rw-r--r--spec/ruby/core/env/dup_spec.rb11
-rw-r--r--spec/ruby/core/env/except_spec.rb44
-rw-r--r--spec/ruby/core/env/index_spec.rb14
-rw-r--r--spec/ruby/core/env/indexes_spec.rb1
-rw-r--r--spec/ruby/core/env/indices_spec.rb1
-rw-r--r--spec/ruby/core/env/key_spec.rb32
-rw-r--r--spec/ruby/core/env/shared/include.rb7
-rw-r--r--spec/ruby/core/env/shared/key.rb31
-rw-r--r--spec/ruby/core/env/shared/value.rb7
-rw-r--r--spec/ruby/core/env/slice_spec.rb10
-rw-r--r--spec/ruby/core/env/to_a_spec.rb5
-rw-r--r--spec/ruby/core/env/to_h_spec.rb12
-rw-r--r--spec/ruby/core/exception/backtrace_spec.rb27
-rw-r--r--spec/ruby/core/exception/case_compare_spec.rb2
-rw-r--r--spec/ruby/core/exception/detailed_message_spec.rb52
-rw-r--r--spec/ruby/core/exception/equal_value_spec.rb14
-rw-r--r--spec/ruby/core/exception/fixtures/common.rb4
-rw-r--r--spec/ruby/core/exception/fixtures/syntax_error.rb3
-rw-r--r--spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb22
-rw-r--r--spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb25
-rw-r--r--spec/ruby/core/exception/frozen_error_spec.rb16
-rw-r--r--spec/ruby/core/exception/full_message_spec.rb98
-rw-r--r--spec/ruby/core/exception/interrupt_spec.rb2
-rw-r--r--spec/ruby/core/exception/no_method_error_spec.rb79
-rw-r--r--spec/ruby/core/exception/set_backtrace_spec.rb28
-rw-r--r--spec/ruby/core/exception/syntax_error_spec.rb27
-rw-r--r--spec/ruby/core/exception/to_s_spec.rb2
-rw-r--r--spec/ruby/core/exception/top_level_spec.rb42
-rw-r--r--spec/ruby/core/false/singleton_method_spec.rb15
-rw-r--r--spec/ruby/core/fiber/blocking_spec.rb68
-rw-r--r--spec/ruby/core/fiber/inspect_spec.rb36
-rw-r--r--spec/ruby/core/fiber/kill_spec.rb90
-rw-r--r--spec/ruby/core/fiber/raise_spec.rb56
-rw-r--r--spec/ruby/core/fiber/resume_spec.rb15
-rw-r--r--spec/ruby/core/fiber/storage_spec.rb103
-rw-r--r--spec/ruby/core/file/absolute_path_spec.rb2
-rw-r--r--spec/ruby/core/file/atime_spec.rb5
-rw-r--r--spec/ruby/core/file/ctime_spec.rb5
-rw-r--r--spec/ruby/core/file/dirname_spec.rb39
-rw-r--r--spec/ruby/core/file/exist_spec.rb8
-rw-r--r--spec/ruby/core/file/expand_path_spec.rb2
-rw-r--r--spec/ruby/core/file/flock_spec.rb4
-rw-r--r--spec/ruby/core/file/lutime_spec.rb9
-rw-r--r--spec/ruby/core/file/mtime_spec.rb5
-rw-r--r--spec/ruby/core/file/new_spec.rb65
-rw-r--r--spec/ruby/core/file/open_spec.rb17
-rw-r--r--spec/ruby/core/file/realpath_spec.rb4
-rw-r--r--spec/ruby/core/file/shared/fnmatch.rb47
-rw-r--r--spec/ruby/core/file/shared/path.rb4
-rw-r--r--spec/ruby/core/file/shared/update_time.rb105
-rw-r--r--spec/ruby/core/file/utime_spec.rb102
-rw-r--r--spec/ruby/core/filetest/exist_spec.rb8
-rw-r--r--spec/ruby/core/float/magnitude_spec.rb1
-rw-r--r--spec/ruby/core/float/round_spec.rb2
-rw-r--r--spec/ruby/core/gc/auto_compact_spec.rb36
-rw-r--r--spec/ruby/core/hash/assoc_spec.rb6
-rw-r--r--spec/ruby/core/hash/compact_spec.rb24
-rw-r--r--spec/ruby/core/hash/compare_by_identity_spec.rb19
-rw-r--r--spec/ruby/core/hash/constructor_spec.rb18
-rw-r--r--spec/ruby/core/hash/delete_spec.rb18
-rw-r--r--spec/ruby/core/hash/element_reference_spec.rb2
-rw-r--r--spec/ruby/core/hash/except_spec.rb50
-rw-r--r--spec/ruby/core/hash/fetch_spec.rb2
-rw-r--r--spec/ruby/core/hash/fetch_values_spec.rb2
-rw-r--r--spec/ruby/core/hash/hash_spec.rb2
-rw-r--r--spec/ruby/core/hash/index_spec.rb9
-rw-r--r--spec/ruby/core/hash/new_spec.rb31
-rw-r--r--spec/ruby/core/hash/rehash_spec.rb30
-rw-r--r--spec/ruby/core/hash/replace_spec.rb67
-rw-r--r--spec/ruby/core/hash/ruby2_keywords_hash_spec.rb24
-rw-r--r--spec/ruby/core/hash/shared/each.rb37
-rw-r--r--spec/ruby/core/hash/shared/equal.rb90
-rw-r--r--spec/ruby/core/hash/shared/replace.rb51
-rw-r--r--spec/ruby/core/hash/shared/store.rb8
-rw-r--r--spec/ruby/core/hash/shared/to_s.rb50
-rw-r--r--spec/ruby/core/hash/to_a_spec.rb10
-rw-r--r--spec/ruby/core/hash/to_h_spec.rb10
-rw-r--r--spec/ruby/core/hash/to_proc_spec.rb16
-rw-r--r--spec/ruby/core/hash/transform_keys_spec.rb32
-rw-r--r--spec/ruby/core/hash/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/integer/bit_and_spec.rb2
-rw-r--r--spec/ruby/core/integer/bit_or_spec.rb6
-rw-r--r--spec/ruby/core/integer/bit_xor_spec.rb4
-rw-r--r--spec/ruby/core/integer/ceildiv_spec.rb22
-rw-r--r--spec/ruby/core/integer/chr_spec.rb18
-rw-r--r--spec/ruby/core/integer/coerce_spec.rb13
-rw-r--r--spec/ruby/core/integer/div_spec.rb8
-rw-r--r--spec/ruby/core/integer/left_shift_spec.rb32
-rw-r--r--spec/ruby/core/integer/right_shift_spec.rb32
-rw-r--r--spec/ruby/core/integer/round_spec.rb6
-rw-r--r--spec/ruby/core/integer/shared/arithmetic_coerce.rb20
-rw-r--r--spec/ruby/core/integer/size_spec.rb4
-rw-r--r--spec/ruby/core/integer/try_convert_spec.rb12
-rw-r--r--spec/ruby/core/integer/zero_spec.rb12
-rw-r--r--spec/ruby/core/io/autoclose_spec.rb77
-rw-r--r--spec/ruby/core/io/binread_spec.rb10
-rw-r--r--spec/ruby/core/io/bytes_spec.rb47
-rw-r--r--spec/ruby/core/io/chars_spec.rb30
-rw-r--r--spec/ruby/core/io/close_read_spec.rb3
-rw-r--r--spec/ruby/core/io/close_write_spec.rb14
-rw-r--r--spec/ruby/core/io/codepoints_spec.rb38
-rw-r--r--spec/ruby/core/io/copy_stream_spec.rb33
-rw-r--r--spec/ruby/core/io/eof_spec.rb2
-rw-r--r--spec/ruby/core/io/flush_spec.rb10
-rw-r--r--spec/ruby/core/io/foreach_spec.rb19
-rw-r--r--spec/ruby/core/io/getbyte_spec.rb16
-rw-r--r--spec/ruby/core/io/gets_spec.rb71
-rw-r--r--spec/ruby/core/io/initialize_spec.rb11
-rw-r--r--spec/ruby/core/io/ioctl_spec.rb2
-rw-r--r--spec/ruby/core/io/lineno_spec.rb6
-rw-r--r--spec/ruby/core/io/lines_spec.rb46
-rw-r--r--spec/ruby/core/io/new_spec.rb8
-rw-r--r--spec/ruby/core/io/nonblock_spec.rb46
-rw-r--r--spec/ruby/core/io/open_spec.rb13
-rw-r--r--spec/ruby/core/io/pread_spec.rb90
-rw-r--r--spec/ruby/core/io/puts_spec.rb2
-rw-r--r--spec/ruby/core/io/pwrite_spec.rb32
-rw-r--r--spec/ruby/core/io/read_nonblock_spec.rb8
-rw-r--r--spec/ruby/core/io/read_spec.rb172
-rw-r--r--spec/ruby/core/io/readline_spec.rb12
-rw-r--r--spec/ruby/core/io/readlines_spec.rb39
-rw-r--r--spec/ruby/core/io/readpartial_spec.rb9
-rw-r--r--spec/ruby/core/io/select_spec.rb48
-rw-r--r--spec/ruby/core/io/shared/binwrite.rb13
-rw-r--r--spec/ruby/core/io/shared/each.rb20
-rw-r--r--spec/ruby/core/io/shared/new.rb50
-rw-r--r--spec/ruby/core/io/shared/readlines.rb22
-rw-r--r--spec/ruby/core/io/shared/write.rb65
-rw-r--r--spec/ruby/core/io/stat_spec.rb3
-rw-r--r--spec/ruby/core/io/sysread_spec.rb23
-rw-r--r--spec/ruby/core/io/syswrite_spec.rb1
-rw-r--r--spec/ruby/core/io/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/io/ungetc_spec.rb16
-rw-r--r--spec/ruby/core/io/write_nonblock_spec.rb1
-rw-r--r--spec/ruby/core/io/write_spec.rb159
-rw-r--r--spec/ruby/core/kernel/Complex_spec.rb4
-rw-r--r--spec/ruby/core/kernel/Float_spec.rb2
-rw-r--r--spec/ruby/core/kernel/Integer_spec.rb38
-rw-r--r--spec/ruby/core/kernel/String_spec.rb2
-rw-r--r--spec/ruby/core/kernel/__dir___spec.rb16
-rw-r--r--spec/ruby/core/kernel/at_exit_spec.rb61
-rw-r--r--spec/ruby/core/kernel/caller_locations_spec.rb30
-rw-r--r--spec/ruby/core/kernel/caller_spec.rb42
-rw-r--r--spec/ruby/core/kernel/catch_spec.rb2
-rw-r--r--spec/ruby/core/kernel/class_spec.rb2
-rw-r--r--spec/ruby/core/kernel/clone_spec.rb86
-rw-r--r--spec/ruby/core/kernel/define_singleton_method_spec.rb6
-rw-r--r--spec/ruby/core/kernel/eval_spec.rb86
-rw-r--r--spec/ruby/core/kernel/exec_spec.rb4
-rw-r--r--spec/ruby/core/kernel/exit_spec.rb10
-rw-r--r--spec/ruby/core/kernel/fixtures/at_exit.rb3
-rw-r--r--spec/ruby/core/kernel/format_spec.rb32
-rw-r--r--spec/ruby/core/kernel/initialize_clone_spec.rb10
-rw-r--r--spec/ruby/core/kernel/initialize_copy_spec.rb9
-rw-r--r--spec/ruby/core/kernel/iterator_spec.rb14
-rw-r--r--spec/ruby/core/kernel/lambda_spec.rb74
-rw-r--r--spec/ruby/core/kernel/method_spec.rb21
-rw-r--r--spec/ruby/core/kernel/not_match_spec.rb14
-rw-r--r--spec/ruby/core/kernel/open_spec.rb87
-rw-r--r--spec/ruby/core/kernel/printf_spec.rb7
-rw-r--r--spec/ruby/core/kernel/proc_spec.rb18
-rw-r--r--spec/ruby/core/kernel/public_send_spec.rb4
-rw-r--r--spec/ruby/core/kernel/require_relative_spec.rb8
-rw-r--r--spec/ruby/core/kernel/require_spec.rb20
-rw-r--r--spec/ruby/core/kernel/shared/load.rb38
-rw-r--r--spec/ruby/core/kernel/shared/require.rb82
-rw-r--r--spec/ruby/core/kernel/shared/sprintf.rb4
-rw-r--r--spec/ruby/core/kernel/shared/sprintf_encoding.rb8
-rw-r--r--spec/ruby/core/kernel/singleton_class_spec.rb49
-rw-r--r--spec/ruby/core/kernel/sleep_spec.rb30
-rw-r--r--spec/ruby/core/kernel/sprintf_spec.rb16
-rw-r--r--spec/ruby/core/kernel/system_spec.rb17
-rw-r--r--spec/ruby/core/kernel/taint_spec.rb16
-rw-r--r--spec/ruby/core/kernel/tainted_spec.rb20
-rw-r--r--spec/ruby/core/kernel/test_spec.rb4
-rw-r--r--spec/ruby/core/kernel/trust_spec.rb18
-rw-r--r--spec/ruby/core/kernel/untaint_spec.rb18
-rw-r--r--spec/ruby/core/kernel/untrust_spec.rb16
-rw-r--r--spec/ruby/core/kernel/untrusted_spec.rb18
-rw-r--r--spec/ruby/core/kernel/warn_spec.rb141
-rw-r--r--spec/ruby/core/main/private_spec.rb12
-rw-r--r--spec/ruby/core/main/public_spec.rb12
-rw-r--r--spec/ruby/core/marshal/dump_spec.rb254
-rw-r--r--spec/ruby/core/marshal/fixtures/marshal_data.rb102
-rw-r--r--spec/ruby/core/marshal/shared/load.rb323
-rw-r--r--spec/ruby/core/matchdata/begin_spec.rb28
-rw-r--r--spec/ruby/core/matchdata/byteoffset_spec.rb95
-rw-r--r--spec/ruby/core/matchdata/captures_spec.rb13
-rw-r--r--spec/ruby/core/matchdata/deconstruct_keys_spec.rb65
-rw-r--r--spec/ruby/core/matchdata/deconstruct_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/element_reference_spec.rb20
-rw-r--r--spec/ruby/core/matchdata/named_captures_spec.rb12
-rw-r--r--spec/ruby/core/matchdata/post_match_spec.rb12
-rw-r--r--spec/ruby/core/matchdata/pre_match_spec.rb12
-rw-r--r--spec/ruby/core/matchdata/shared/captures.rb13
-rw-r--r--spec/ruby/core/matchdata/string_spec.rb5
-rw-r--r--spec/ruby/core/matchdata/to_a_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/to_s_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/values_at_spec.rb4
-rw-r--r--spec/ruby/core/math/cos_spec.rb26
-rw-r--r--spec/ruby/core/method/clone_spec.rb15
-rw-r--r--spec/ruby/core/method/compose_spec.rb3
-rw-r--r--spec/ruby/core/method/dup_spec.rb15
-rw-r--r--spec/ruby/core/method/parameters_spec.rb63
-rw-r--r--spec/ruby/core/method/private_spec.rb11
-rw-r--r--spec/ruby/core/method/protected_spec.rb11
-rw-r--r--spec/ruby/core/method/public_spec.rb11
-rw-r--r--spec/ruby/core/method/shared/dup.rb32
-rw-r--r--spec/ruby/core/method/shared/to_s.rb30
-rw-r--r--spec/ruby/core/method/source_location_spec.rb9
-rw-r--r--spec/ruby/core/method/super_method_spec.rb10
-rw-r--r--spec/ruby/core/method/to_proc_spec.rb2
-rw-r--r--spec/ruby/core/module/alias_method_spec.rb20
-rw-r--r--spec/ruby/core/module/attr_accessor_spec.rb19
-rw-r--r--spec/ruby/core/module/attr_reader_spec.rb17
-rw-r--r--spec/ruby/core/module/attr_spec.rb23
-rw-r--r--spec/ruby/core/module/attr_writer_spec.rb17
-rw-r--r--spec/ruby/core/module/autoload_spec.rb103
-rw-r--r--spec/ruby/core/module/const_added_spec.rb35
-rw-r--r--spec/ruby/core/module/const_defined_spec.rb21
-rw-r--r--spec/ruby/core/module/const_get_spec.rb2
-rw-r--r--spec/ruby/core/module/const_set_spec.rb18
-rw-r--r--spec/ruby/core/module/const_source_location_spec.rb26
-rw-r--r--spec/ruby/core/module/define_method_spec.rb46
-rw-r--r--spec/ruby/core/module/fixtures/autoload_const_source_location.rb6
-rw-r--r--spec/ruby/core/module/fixtures/autoload_during_autoload_after_define.rb6
-rw-r--r--spec/ruby/core/module/fixtures/classes.rb26
-rw-r--r--spec/ruby/core/module/fixtures/module.rb4
-rw-r--r--spec/ruby/core/module/include_spec.rb28
-rw-r--r--spec/ruby/core/module/method_added_spec.rb73
-rw-r--r--spec/ruby/core/module/module_function_spec.rb136
-rw-r--r--spec/ruby/core/module/name_spec.rb54
-rw-r--r--spec/ruby/core/module/new_spec.rb4
-rw-r--r--spec/ruby/core/module/prepend_spec.rb131
-rw-r--r--spec/ruby/core/module/private_class_method_spec.rb14
-rw-r--r--spec/ruby/core/module/public_class_method_spec.rb20
-rw-r--r--spec/ruby/core/module/refine_spec.rb2
-rw-r--r--spec/ruby/core/module/refinements_spec.rb45
-rw-r--r--spec/ruby/core/module/ruby2_keywords_spec.rb24
-rw-r--r--spec/ruby/core/module/set_temporary_name_spec.rb68
-rw-r--r--spec/ruby/core/module/shared/attr_added.rb34
-rw-r--r--spec/ruby/core/module/shared/class_eval.rb6
-rw-r--r--spec/ruby/core/module/shared/set_visibility.rb28
-rw-r--r--spec/ruby/core/module/undef_method_spec.rb10
-rw-r--r--spec/ruby/core/module/undefined_instance_methods_spec.rb26
-rw-r--r--spec/ruby/core/module/used_refinements_spec.rb87
-rw-r--r--spec/ruby/core/module/using_spec.rb2
-rw-r--r--spec/ruby/core/mutex/lock_spec.rb4
-rw-r--r--spec/ruby/core/mutex/owned_spec.rb18
-rw-r--r--spec/ruby/core/nil/singleton_method_spec.rb15
-rw-r--r--spec/ruby/core/numeric/clone_spec.rb10
-rw-r--r--spec/ruby/core/numeric/fdiv_spec.rb1
-rw-r--r--spec/ruby/core/numeric/magnitude_spec.rb1
-rw-r--r--spec/ruby/core/numeric/quo_spec.rb1
-rw-r--r--spec/ruby/core/numeric/remainder_spec.rb3
-rw-r--r--spec/ruby/core/numeric/shared/quo.rb7
-rw-r--r--spec/ruby/core/numeric/shared/step.rb8
-rw-r--r--spec/ruby/core/numeric/step_spec.rb85
-rw-r--r--spec/ruby/core/objectspace/define_finalizer_spec.rb86
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/delete_spec.rb40
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb26
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb71
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb14
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb17
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/key_spec.rb33
-rw-r--r--spec/ruby/core/objectspace/weakmap/delete_spec.rb30
-rw-r--r--spec/ruby/core/proc/arity_spec.rb16
-rw-r--r--spec/ruby/core/proc/clone_spec.rb9
-rw-r--r--spec/ruby/core/proc/compose_spec.rb46
-rw-r--r--spec/ruby/core/proc/dup_spec.rb7
-rw-r--r--spec/ruby/core/proc/eql_spec.rb8
-rw-r--r--spec/ruby/core/proc/equal_value_spec.rb8
-rw-r--r--spec/ruby/core/proc/fixtures/proc_aref.rb1
-rw-r--r--spec/ruby/core/proc/lambda_spec.rb8
-rw-r--r--spec/ruby/core/proc/new_spec.rb35
-rw-r--r--spec/ruby/core/proc/parameters_spec.rb69
-rw-r--r--spec/ruby/core/proc/ruby2_keywords_spec.rb22
-rw-r--r--spec/ruby/core/proc/shared/dup.rb31
-rw-r--r--spec/ruby/core/proc/shared/equal.rb17
-rw-r--r--spec/ruby/core/proc/shared/to_s.rb14
-rw-r--r--spec/ruby/core/proc/source_location_spec.rb13
-rw-r--r--spec/ruby/core/process/argv0_spec.rb25
-rw-r--r--spec/ruby/core/process/constants_spec.rb8
-rw-r--r--spec/ruby/core/process/daemon_spec.rb2
-rw-r--r--spec/ruby/core/process/detach_spec.rb14
-rw-r--r--spec/ruby/core/process/exec_spec.rb44
-rw-r--r--spec/ruby/core/process/exit_spec.rb2
-rw-r--r--spec/ruby/core/process/fixtures/argv0.rb6
-rw-r--r--spec/ruby/core/process/fixtures/kill.rb2
-rw-r--r--spec/ruby/core/process/spawn_spec.rb2
-rw-r--r--spec/ruby/core/process/status/termsig_spec.rb2
-rw-r--r--spec/ruby/core/process/status/wait_spec.rb158
-rw-r--r--spec/ruby/core/process/times_spec.rb20
-rw-r--r--spec/ruby/core/process/wait2_spec.rb4
-rw-r--r--spec/ruby/core/process/wait_spec.rb2
-rw-r--r--spec/ruby/core/process/waitpid_spec.rb3
-rw-r--r--spec/ruby/core/process/warmup_spec.rb11
-rw-r--r--spec/ruby/core/queue/deq_spec.rb7
-rw-r--r--spec/ruby/core/queue/initialize_spec.rb33
-rw-r--r--spec/ruby/core/queue/pop_spec.rb7
-rw-r--r--spec/ruby/core/queue/shift_spec.rb7
-rw-r--r--spec/ruby/core/random/bytes_spec.rb1
-rw-r--r--spec/ruby/core/random/default_spec.rb24
-rw-r--r--spec/ruby/core/random/new_spec.rb1
-rw-r--r--spec/ruby/core/range/bsearch_spec.rb44
-rw-r--r--spec/ruby/core/range/cover_spec.rb4
-rw-r--r--spec/ruby/core/range/frozen_spec.rb34
-rw-r--r--spec/ruby/core/range/include_spec.rb4
-rw-r--r--spec/ruby/core/range/initialize_spec.rb15
-rw-r--r--spec/ruby/core/range/max_spec.rb18
-rw-r--r--spec/ruby/core/range/minmax_spec.rb24
-rw-r--r--spec/ruby/core/range/new_spec.rb14
-rw-r--r--spec/ruby/core/range/shared/cover_and_include.rb1
-rw-r--r--spec/ruby/core/range/size_spec.rb66
-rw-r--r--spec/ruby/core/range/step_spec.rb345
-rw-r--r--spec/ruby/core/rational/abs_spec.rb1
-rw-r--r--spec/ruby/core/rational/ceil_spec.rb1
-rw-r--r--spec/ruby/core/rational/coerce_spec.rb5
-rw-r--r--spec/ruby/core/rational/comparison_spec.rb1
-rw-r--r--spec/ruby/core/rational/denominator_spec.rb1
-rw-r--r--spec/ruby/core/rational/div_spec.rb1
-rw-r--r--spec/ruby/core/rational/divide_spec.rb1
-rw-r--r--spec/ruby/core/rational/divmod_spec.rb1
-rw-r--r--spec/ruby/core/rational/equal_value_spec.rb1
-rw-r--r--spec/ruby/core/rational/exponent_spec.rb1
-rw-r--r--spec/ruby/core/rational/fdiv_spec.rb1
-rw-r--r--spec/ruby/core/rational/floor_spec.rb1
-rw-r--r--spec/ruby/core/rational/hash_spec.rb1
-rw-r--r--spec/ruby/core/rational/inspect_spec.rb1
-rw-r--r--spec/ruby/core/rational/integer_spec.rb1
-rw-r--r--spec/ruby/core/rational/magnitude_spec.rb1
-rw-r--r--spec/ruby/core/rational/modulo_spec.rb1
-rw-r--r--spec/ruby/core/rational/multiply_spec.rb1
-rw-r--r--spec/ruby/core/rational/numerator_spec.rb1
-rw-r--r--spec/ruby/core/rational/plus_spec.rb1
-rw-r--r--spec/ruby/core/rational/quo_spec.rb1
-rw-r--r--spec/ruby/core/rational/remainder_spec.rb1
-rw-r--r--spec/ruby/core/rational/to_f_spec.rb1
-rw-r--r--spec/ruby/core/rational/to_i_spec.rb1
-rw-r--r--spec/ruby/core/rational/to_r_spec.rb1
-rw-r--r--spec/ruby/core/rational/to_s_spec.rb1
-rw-r--r--spec/ruby/core/rational/truncate_spec.rb1
-rw-r--r--spec/ruby/core/rational/zero_spec.rb1
-rw-r--r--spec/ruby/core/refinement/extend_object_spec.rb6
-rw-r--r--spec/ruby/core/refinement/fixtures/classes.rb10
-rw-r--r--spec/ruby/core/refinement/import_methods_spec.rb235
-rw-r--r--spec/ruby/core/refinement/refined_class_spec.rb17
-rw-r--r--spec/ruby/core/regexp/initialize_spec.rb12
-rw-r--r--spec/ruby/core/regexp/linear_time_spec.rb25
-rw-r--r--spec/ruby/core/regexp/shared/new.rb60
-rw-r--r--spec/ruby/core/regexp/shared/quote.rb10
-rw-r--r--spec/ruby/core/regexp/try_convert_spec.rb6
-rw-r--r--spec/ruby/core/regexp/union_spec.rb51
-rw-r--r--spec/ruby/core/signal/signame_spec.rb12
-rw-r--r--spec/ruby/core/signal/trap_spec.rb31
-rw-r--r--spec/ruby/core/sizedqueue/append_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/deq_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/enq_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/pop_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/push_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/shift_spec.rb7
-rw-r--r--spec/ruby/core/string/append_as_bytes_spec.rb46
-rw-r--r--spec/ruby/core/string/append_spec.rb1
-rw-r--r--spec/ruby/core/string/ascii_only_spec.rb23
-rw-r--r--spec/ruby/core/string/b_spec.rb1
-rw-r--r--spec/ruby/core/string/byteindex_spec.rb300
-rw-r--r--spec/ruby/core/string/byterindex_spec.rb359
-rw-r--r--spec/ruby/core/string/bytes_spec.rb2
-rw-r--r--spec/ruby/core/string/bytesize_spec.rb10
-rw-r--r--spec/ruby/core/string/byteslice_spec.rb8
-rw-r--r--spec/ruby/core/string/bytesplice_spec.rb134
-rw-r--r--spec/ruby/core/string/capitalize_spec.rb39
-rw-r--r--spec/ruby/core/string/casecmp_spec.rb10
-rw-r--r--spec/ruby/core/string/center_spec.rb29
-rw-r--r--spec/ruby/core/string/chars_spec.rb1
-rw-r--r--spec/ruby/core/string/chilled_string_spec.rb71
-rw-r--r--spec/ruby/core/string/chomp_spec.rb16
-rw-r--r--spec/ruby/core/string/chop_spec.rb13
-rw-r--r--spec/ruby/core/string/clear_spec.rb1
-rw-r--r--spec/ruby/core/string/codepoints_spec.rb2
-rw-r--r--spec/ruby/core/string/comparison_spec.rb8
-rw-r--r--spec/ruby/core/string/concat_spec.rb7
-rw-r--r--spec/ruby/core/string/dedup_spec.rb2
-rw-r--r--spec/ruby/core/string/delete_prefix_spec.rb16
-rw-r--r--spec/ruby/core/string/delete_spec.rb13
-rw-r--r--spec/ruby/core/string/delete_suffix_spec.rb16
-rw-r--r--spec/ruby/core/string/downcase_spec.rb13
-rw-r--r--spec/ruby/core/string/dump_spec.rb12
-rw-r--r--spec/ruby/core/string/dup_spec.rb2
-rw-r--r--spec/ruby/core/string/each_byte_spec.rb16
-rw-r--r--spec/ruby/core/string/each_char_spec.rb1
-rw-r--r--spec/ruby/core/string/each_grapheme_cluster_spec.rb11
-rw-r--r--spec/ruby/core/string/element_set_spec.rb1
-rw-r--r--spec/ruby/core/string/encode_spec.rb42
-rw-r--r--spec/ruby/core/string/encoding_spec.rb24
-rw-r--r--spec/ruby/core/string/fixtures/utf-8-encoding.rb7
-rw-r--r--spec/ruby/core/string/force_encoding_spec.rb1
-rw-r--r--spec/ruby/core/string/freeze_spec.rb1
-rw-r--r--spec/ruby/core/string/grapheme_clusters_spec.rb1
-rw-r--r--spec/ruby/core/string/gsub_spec.rb22
-rw-r--r--spec/ruby/core/string/include_spec.rb12
-rw-r--r--spec/ruby/core/string/index_spec.rb33
-rw-r--r--spec/ruby/core/string/insert_spec.rb2
-rw-r--r--spec/ruby/core/string/inspect_spec.rb2
-rw-r--r--spec/ruby/core/string/ljust_spec.rb29
-rw-r--r--spec/ruby/core/string/lstrip_spec.rb19
-rw-r--r--spec/ruby/core/string/modulo_spec.rb71
-rw-r--r--spec/ruby/core/string/ord_spec.rb2
-rw-r--r--spec/ruby/core/string/partition_spec.rb4
-rw-r--r--spec/ruby/core/string/plus_spec.rb5
-rw-r--r--spec/ruby/core/string/prepend_spec.rb1
-rw-r--r--spec/ruby/core/string/reverse_spec.rb19
-rw-r--r--spec/ruby/core/string/rindex_spec.rb23
-rw-r--r--spec/ruby/core/string/rjust_spec.rb29
-rw-r--r--spec/ruby/core/string/rpartition_spec.rb4
-rw-r--r--spec/ruby/core/string/rstrip_spec.rb11
-rw-r--r--spec/ruby/core/string/scan_spec.rb10
-rw-r--r--spec/ruby/core/string/scrub_spec.rb37
-rw-r--r--spec/ruby/core/string/setbyte_spec.rb1
-rw-r--r--spec/ruby/core/string/shared/byte_index_common.rb63
-rw-r--r--spec/ruby/core/string/shared/chars.rb12
-rw-r--r--spec/ruby/core/string/shared/codepoints.rb6
-rw-r--r--spec/ruby/core/string/shared/concat.rb33
-rw-r--r--spec/ruby/core/string/shared/dedup.rb9
-rw-r--r--spec/ruby/core/string/shared/each_codepoint_without_block.rb4
-rw-r--r--spec/ruby/core/string/shared/each_line.rb20
-rw-r--r--spec/ruby/core/string/shared/encode.rb185
-rw-r--r--spec/ruby/core/string/shared/eql.rb8
-rw-r--r--spec/ruby/core/string/shared/length.rb10
-rw-r--r--spec/ruby/core/string/shared/partition.rb34
-rw-r--r--spec/ruby/core/string/shared/replace.rb1
-rw-r--r--spec/ruby/core/string/shared/slice.rb118
-rw-r--r--spec/ruby/core/string/shared/strip.rb18
-rw-r--r--spec/ruby/core/string/shared/succ.rb19
-rw-r--r--spec/ruby/core/string/shared/to_a.rb9
-rw-r--r--spec/ruby/core/string/shared/to_sym.rb6
-rw-r--r--spec/ruby/core/string/slice_spec.rb95
-rw-r--r--spec/ruby/core/string/split_spec.rb120
-rw-r--r--spec/ruby/core/string/squeeze_spec.rb13
-rw-r--r--spec/ruby/core/string/start_with_spec.rb17
-rw-r--r--spec/ruby/core/string/strip_spec.rb17
-rw-r--r--spec/ruby/core/string/sub_spec.rb22
-rw-r--r--spec/ruby/core/string/swapcase_spec.rb16
-rw-r--r--spec/ruby/core/string/to_c_spec.rb12
-rw-r--r--spec/ruby/core/string/to_i_spec.rb12
-rw-r--r--spec/ruby/core/string/tr_s_spec.rb22
-rw-r--r--spec/ruby/core/string/tr_spec.rb22
-rw-r--r--spec/ruby/core/string/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/string/unicode_normalize_spec.rb1
-rw-r--r--spec/ruby/core/string/unicode_normalized_spec.rb1
-rw-r--r--spec/ruby/core/string/unpack/a_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/b_spec.rb12
-rw-r--r--spec/ruby/core/string/unpack/c_spec.rb4
-rw-r--r--spec/ruby/core/string/unpack/h_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/l_spec.rb16
-rw-r--r--spec/ruby/core/string/unpack/shared/float.rb20
-rw-r--r--spec/ruby/core/string/unpack/shared/integer.rb28
-rw-r--r--spec/ruby/core/string/unpack/shared/unicode.rb4
-rw-r--r--spec/ruby/core/string/unpack/u_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/w_spec.rb4
-rw-r--r--spec/ruby/core/string/unpack_spec.rb2
-rw-r--r--spec/ruby/core/string/upcase_spec.rb13
-rw-r--r--spec/ruby/core/string/uplus_spec.rb4
-rw-r--r--spec/ruby/core/string/upto_spec.rb6
-rw-r--r--spec/ruby/core/string/valid_encoding_spec.rb30
-rw-r--r--spec/ruby/core/struct/constants_spec.rb15
-rw-r--r--spec/ruby/core/struct/deconstruct_keys_spec.rb2
-rw-r--r--spec/ruby/core/struct/fixtures/classes.rb6
-rw-r--r--spec/ruby/core/struct/initialize_spec.rb10
-rw-r--r--spec/ruby/core/struct/inspect_spec.rb5
-rw-r--r--spec/ruby/core/struct/keyword_init_spec.rb19
-rw-r--r--spec/ruby/core/struct/new_spec.rb19
-rw-r--r--spec/ruby/core/struct/shared/inspect.rb35
-rw-r--r--spec/ruby/core/struct/to_h_spec.rb12
-rw-r--r--spec/ruby/core/symbol/casecmp_spec.rb8
-rw-r--r--spec/ruby/core/symbol/inspect_spec.rb2
-rw-r--r--spec/ruby/core/symbol/name_spec.rb24
-rw-r--r--spec/ruby/core/symbol/to_proc_spec.rb47
-rw-r--r--spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace/location/label_spec.rb10
-rw-r--r--spec/ruby/core/thread/backtrace/location/lineno_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace/location/path_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace_locations_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace_spec.rb2
-rw-r--r--spec/ruby/core/thread/each_caller_location_spec.rb49
-rw-r--r--spec/ruby/core/thread/exclusive_spec.rb49
-rw-r--r--spec/ruby/core/thread/fetch_spec.rb30
-rw-r--r--spec/ruby/core/thread/ignore_deadlock_spec.rb26
-rw-r--r--spec/ruby/core/thread/kill_spec.rb4
-rw-r--r--spec/ruby/core/thread/native_thread_id_spec.rb40
-rw-r--r--spec/ruby/core/thread/report_on_exception_spec.rb50
-rw-r--r--spec/ruby/core/thread/shared/exit.rb19
-rw-r--r--spec/ruby/core/thread/thread_variable_get_spec.rb41
-rw-r--r--spec/ruby/core/thread/thread_variable_set_spec.rb42
-rw-r--r--spec/ruby/core/thread/thread_variable_spec.rb43
-rw-r--r--spec/ruby/core/thread/thread_variables_spec.rb22
-rw-r--r--spec/ruby/core/time/_load_spec.rb3
-rw-r--r--spec/ruby/core/time/at_spec.rb9
-rw-r--r--spec/ruby/core/time/deconstruct_keys_spec.rb45
-rw-r--r--spec/ruby/core/time/fixtures/classes.rb1
-rw-r--r--spec/ruby/core/time/iso8601_spec.rb6
-rw-r--r--spec/ruby/core/time/new_spec.rb202
-rw-r--r--spec/ruby/core/time/now_spec.rb66
-rw-r--r--spec/ruby/core/time/shared/xmlschema.rb31
-rw-r--r--spec/ruby/core/time/succ_spec.rb39
-rw-r--r--spec/ruby/core/time/utc_spec.rb10
-rw-r--r--spec/ruby/core/time/xmlschema_spec.rb6
-rw-r--r--spec/ruby/core/time/yday_spec.rb13
-rw-r--r--spec/ruby/core/time/zone_spec.rb11
-rw-r--r--spec/ruby/core/tracepoint/enable_spec.rb8
-rw-r--r--spec/ruby/core/tracepoint/inspect_spec.rb27
-rw-r--r--spec/ruby/core/tracepoint/path_spec.rb31
-rw-r--r--spec/ruby/core/true/singleton_method_spec.rb15
-rw-r--r--spec/ruby/core/unboundmethod/bind_call_spec.rb8
-rw-r--r--spec/ruby/core/unboundmethod/bind_spec.rb8
-rw-r--r--spec/ruby/core/unboundmethod/clone_spec.rb13
-rw-r--r--spec/ruby/core/unboundmethod/dup_spec.rb15
-rw-r--r--spec/ruby/core/unboundmethod/fixtures/classes.rb4
-rw-r--r--spec/ruby/core/unboundmethod/private_spec.rb11
-rw-r--r--spec/ruby/core/unboundmethod/protected_spec.rb11
-rw-r--r--spec/ruby/core/unboundmethod/public_spec.rb11
-rw-r--r--spec/ruby/core/unboundmethod/shared/dup.rb32
-rw-r--r--spec/ruby/core/unboundmethod/source_location_spec.rb9
-rw-r--r--spec/ruby/core/unboundmethod/super_method_spec.rb10
-rw-r--r--spec/ruby/core/warning/element_reference_spec.rb17
-rw-r--r--spec/ruby/core/warning/element_set_spec.rb20
-rw-r--r--spec/ruby/core/warning/performance_warning_spec.rb28
-rw-r--r--spec/ruby/core/warning/warn_spec.rb117
-rw-r--r--spec/ruby/default.mspec1
-rw-r--r--spec/ruby/fixtures/code/d/load_fixture.rb.rb1
-rw-r--r--spec/ruby/fixtures/constants.rb3
-rw-r--r--spec/ruby/fixtures/io.rb12
-rw-r--r--spec/ruby/language/END_spec.rb26
-rw-r--r--spec/ruby/language/alias_spec.rb20
-rw-r--r--spec/ruby/language/assignments_spec.rb529
-rw-r--r--spec/ruby/language/block_spec.rb276
-rw-r--r--spec/ruby/language/break_spec.rb21
-rw-r--r--spec/ruby/language/case_spec.rb150
-rw-r--r--spec/ruby/language/class_spec.rb18
-rw-r--r--spec/ruby/language/class_variable_spec.rb56
-rw-r--r--spec/ruby/language/constants_spec.rb38
-rw-r--r--spec/ruby/language/def_spec.rb28
-rw-r--r--spec/ruby/language/defined_spec.rb147
-rw-r--r--spec/ruby/language/delegation_spec.rb62
-rw-r--r--spec/ruby/language/encoding_spec.rb8
-rw-r--r--spec/ruby/language/ensure_spec.rb17
-rw-r--r--spec/ruby/language/execution_spec.rb78
-rw-r--r--spec/ruby/language/file_spec.rb12
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rbbin120 -> 181 bytes-rw-r--r--spec/ruby/language/fixtures/rescue/top_level.rb7
-rw-r--r--spec/ruby/language/fixtures/super.rb62
-rw-r--r--spec/ruby/language/fixtures/variables.rb72
-rw-r--r--spec/ruby/language/for_spec.rb103
-rw-r--r--spec/ruby/language/hash_spec.rb84
-rw-r--r--spec/ruby/language/heredoc_spec.rb10
-rw-r--r--spec/ruby/language/if_spec.rb53
-rw-r--r--spec/ruby/language/keyword_arguments_spec.rb567
-rw-r--r--spec/ruby/language/lambda_spec.rb91
-rw-r--r--spec/ruby/language/method_spec.rb734
-rw-r--r--spec/ruby/language/module_spec.rb18
-rw-r--r--spec/ruby/language/numbered_parameters_spec.rb68
-rw-r--r--spec/ruby/language/optional_assignments_spec.rb294
-rw-r--r--spec/ruby/language/pattern_matching/3.1.rb75
-rw-r--r--spec/ruby/language/pattern_matching_spec.rb1526
-rw-r--r--spec/ruby/language/predefined_spec.rb63
-rw-r--r--spec/ruby/language/proc_spec.rb26
-rw-r--r--spec/ruby/language/regexp/back-references_spec.rb9
-rw-r--r--spec/ruby/language/regexp/character_classes_spec.rb10
-rw-r--r--spec/ruby/language/regexp/encoding_spec.rb42
-rw-r--r--spec/ruby/language/regexp/repetition_spec.rb8
-rw-r--r--spec/ruby/language/regexp_spec.rb8
-rw-r--r--spec/ruby/language/rescue_spec.rb101
-rw-r--r--spec/ruby/language/retry_spec.rb5
-rw-r--r--spec/ruby/language/safe_navigator_spec.rb80
-rw-r--r--spec/ruby/language/safe_spec.rb28
-rw-r--r--spec/ruby/language/send_spec.rb38
-rw-r--r--spec/ruby/language/singleton_class_spec.rb26
-rw-r--r--spec/ruby/language/source_encoding_spec.rb2
-rw-r--r--spec/ruby/language/string_spec.rb42
-rw-r--r--spec/ruby/language/super_spec.rb30
-rw-r--r--spec/ruby/language/symbol_spec.rb14
-rw-r--r--spec/ruby/language/undef_spec.rb9
-rw-r--r--spec/ruby/language/variables_spec.rb110
-rw-r--r--spec/ruby/language/yield_spec.rb41
-rw-r--r--spec/ruby/library/English/English_spec.rb16
-rw-r--r--spec/ruby/library/bigdecimal/add_spec.rb4
-rw-r--r--spec/ruby/library/bigdecimal/core_spec.rb59
-rw-r--r--spec/ruby/library/bigdecimal/remainder_spec.rb28
-rw-r--r--spec/ruby/library/bigdecimal/round_spec.rb4
-rw-r--r--spec/ruby/library/bigdecimal/shared/to_int.rb2
-rw-r--r--spec/ruby/library/bigdecimal/sqrt_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/to_s_spec.rb27
-rw-r--r--spec/ruby/library/bigmath/log_spec.rb10
-rw-r--r--spec/ruby/library/cgi/escapeURIComponent_spec.rb57
-rw-r--r--spec/ruby/library/cgi/initialize_spec.rb2
-rw-r--r--spec/ruby/library/coverage/fixtures/code_with_begin.rb3
-rw-r--r--spec/ruby/library/coverage/result_spec.rb280
-rw-r--r--spec/ruby/library/coverage/running_spec.rb2
-rw-r--r--spec/ruby/library/coverage/start_spec.rb81
-rw-r--r--spec/ruby/library/coverage/supported_spec.rb32
-rw-r--r--spec/ruby/library/csv/generate_spec.rb2
-rw-r--r--spec/ruby/library/date/accessor_spec.rb2
-rw-r--r--spec/ruby/library/date/deconstruct_keys_spec.rb44
-rw-r--r--spec/ruby/library/date/iso8601_spec.rb21
-rw-r--r--spec/ruby/library/date/new_spec.rb1
-rw-r--r--spec/ruby/library/date/parse_spec.rb10
-rw-r--r--spec/ruby/library/date/shared/new_bang.rb14
-rw-r--r--spec/ruby/library/date/shared/parse.rb4
-rw-r--r--spec/ruby/library/date/shared/parse_eu.rb8
-rw-r--r--spec/ruby/library/date/shared/parse_us.rb8
-rw-r--r--spec/ruby/library/date/strftime_spec.rb6
-rw-r--r--spec/ruby/library/date/time/to_date_spec.rb42
-rw-r--r--spec/ruby/library/date/yday_spec.rb3
-rw-r--r--spec/ruby/library/datetime/deconstruct_keys_spec.rb46
-rw-r--r--spec/ruby/library/datetime/rfc2822_spec.rb4
-rw-r--r--spec/ruby/library/datetime/strftime_spec.rb5
-rw-r--r--spec/ruby/library/datetime/time/to_datetime_spec.rb42
-rw-r--r--spec/ruby/library/datetime/to_time_spec.rb4
-rw-r--r--spec/ruby/library/datetime/yday_spec.rb7
-rw-r--r--spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb1
-rw-r--r--spec/ruby/library/digest/instance/shared/update.rb2
-rw-r--r--spec/ruby/library/digest/md5/shared/sample.rb17
-rw-r--r--spec/ruby/library/drb/start_service_spec.rb47
-rw-r--r--spec/ruby/library/erb/new_spec.rb2
-rw-r--r--spec/ruby/library/erb/run_spec.rb2
-rw-r--r--spec/ruby/library/etc/confstr_spec.rb2
-rw-r--r--spec/ruby/library/etc/passwd_spec.rb2
-rw-r--r--spec/ruby/library/etc/sysconf_spec.rb2
-rw-r--r--spec/ruby/library/etc/sysconfdir_spec.rb2
-rw-r--r--spec/ruby/library/etc/systmpdir_spec.rb2
-rw-r--r--spec/ruby/library/etc/uname_spec.rb14
-rw-r--r--spec/ruby/library/expect/expect_spec.rb3
-rw-r--r--spec/ruby/library/fiber/current_spec.rb21
-rw-r--r--spec/ruby/library/fiber/resume_spec.rb35
-rw-r--r--spec/ruby/library/fiber/transfer_spec.rb56
-rw-r--r--spec/ruby/library/find/fixtures/common.rb14
-rw-r--r--spec/ruby/library/io-wait/wait_readable_spec.rb19
-rw-r--r--spec/ruby/library/io-wait/wait_spec.rb186
-rw-r--r--spec/ruby/library/io-wait/wait_writable_spec.rb21
-rw-r--r--spec/ruby/library/ipaddr/new_spec.rb10
-rw-r--r--spec/ruby/library/logger/device/close_spec.rb15
-rw-r--r--spec/ruby/library/logger/device/write_spec.rb15
-rw-r--r--spec/ruby/library/matrix/I_spec.rb9
-rw-r--r--spec/ruby/library/matrix/antisymmetric_spec.rb54
-rw-r--r--spec/ruby/library/matrix/build_spec.rb117
-rw-r--r--spec/ruby/library/matrix/clone_spec.rb37
-rw-r--r--spec/ruby/library/matrix/coerce_spec.rb11
-rw-r--r--spec/ruby/library/matrix/collect_spec.rb9
-rw-r--r--spec/ruby/library/matrix/column_size_spec.rb19
-rw-r--r--spec/ruby/library/matrix/column_spec.rb53
-rw-r--r--spec/ruby/library/matrix/column_vector_spec.rb37
-rw-r--r--spec/ruby/library/matrix/column_vectors_spec.rb37
-rw-r--r--spec/ruby/library/matrix/columns_spec.rb67
-rw-r--r--spec/ruby/library/matrix/conj_spec.rb9
-rw-r--r--spec/ruby/library/matrix/conjugate_spec.rb9
-rw-r--r--spec/ruby/library/matrix/constructor_spec.rb103
-rw-r--r--spec/ruby/library/matrix/det_spec.rb11
-rw-r--r--spec/ruby/library/matrix/determinant_spec.rb11
-rw-r--r--spec/ruby/library/matrix/diagonal_spec.rb105
-rw-r--r--spec/ruby/library/matrix/divide_spec.rb83
-rw-r--r--spec/ruby/library/matrix/each_spec.rb119
-rw-r--r--spec/ruby/library/matrix/each_with_index_spec.rb133
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalue_matrix_spec.rb13
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalues_spec.rb35
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/eigenvector_matrix_spec.rb33
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/eigenvectors_spec.rb37
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb39
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/to_a_spec.rb27
-rw-r--r--spec/ruby/library/matrix/element_reference_spec.rb31
-rw-r--r--spec/ruby/library/matrix/empty_spec.rb107
-rw-r--r--spec/ruby/library/matrix/eql_spec.rb15
-rw-r--r--spec/ruby/library/matrix/equal_value_spec.rb15
-rw-r--r--spec/ruby/library/matrix/exponent_spec.rb93
-rw-r--r--spec/ruby/library/matrix/find_index_spec.rb221
-rw-r--r--spec/ruby/library/matrix/hash_spec.rb21
-rw-r--r--spec/ruby/library/matrix/hermitian_spec.rb53
-rw-r--r--spec/ruby/library/matrix/identity_spec.rb9
-rw-r--r--spec/ruby/library/matrix/imag_spec.rb9
-rw-r--r--spec/ruby/library/matrix/imaginary_spec.rb9
-rw-r--r--spec/ruby/library/matrix/inspect_spec.rb39
-rw-r--r--spec/ruby/library/matrix/inv_spec.rb11
-rw-r--r--spec/ruby/library/matrix/inverse_from_spec.rb9
-rw-r--r--spec/ruby/library/matrix/inverse_spec.rb11
-rw-r--r--spec/ruby/library/matrix/lower_triangular_spec.rb39
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb33
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb21
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/l_spec.rb27
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/p_spec.rb27
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/solve_spec.rb85
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb53
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/u_spec.rb27
-rw-r--r--spec/ruby/library/matrix/map_spec.rb9
-rw-r--r--spec/ruby/library/matrix/minor_spec.rb135
-rw-r--r--spec/ruby/library/matrix/minus_spec.rb65
-rw-r--r--spec/ruby/library/matrix/multiply_spec.rb104
-rw-r--r--spec/ruby/library/matrix/new_spec.rb11
-rw-r--r--spec/ruby/library/matrix/normal_spec.rb41
-rw-r--r--spec/ruby/library/matrix/orthogonal_spec.rb41
-rw-r--r--spec/ruby/library/matrix/permutation_spec.rb51
-rw-r--r--spec/ruby/library/matrix/plus_spec.rb65
-rw-r--r--spec/ruby/library/matrix/rank_spec.rb29
-rw-r--r--spec/ruby/library/matrix/real_spec.rb63
-rw-r--r--spec/ruby/library/matrix/rect_spec.rb9
-rw-r--r--spec/ruby/library/matrix/rectangular_spec.rb9
-rw-r--r--spec/ruby/library/matrix/regular_spec.rb45
-rw-r--r--spec/ruby/library/matrix/round_spec.rb31
-rw-r--r--spec/ruby/library/matrix/row_size_spec.rb19
-rw-r--r--spec/ruby/library/matrix/row_spec.rb55
-rw-r--r--spec/ruby/library/matrix/row_vector_spec.rb33
-rw-r--r--spec/ruby/library/matrix/row_vectors_spec.rb37
-rw-r--r--spec/ruby/library/matrix/rows_spec.rb65
-rw-r--r--spec/ruby/library/matrix/scalar/Fail_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/Raise_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/divide_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/exponent_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/included_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/initialize_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/minus_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/multiply_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/plus_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar_spec.rb93
-rw-r--r--spec/ruby/library/matrix/singular_spec.rb47
-rw-r--r--spec/ruby/library/matrix/square_spec.rb41
-rw-r--r--spec/ruby/library/matrix/symmetric_spec.rb45
-rw-r--r--spec/ruby/library/matrix/t_spec.rb9
-rw-r--r--spec/ruby/library/matrix/to_a_spec.rb17
-rw-r--r--spec/ruby/library/matrix/to_s_spec.rb9
-rw-r--r--spec/ruby/library/matrix/tr_spec.rb11
-rw-r--r--spec/ruby/library/matrix/trace_spec.rb11
-rw-r--r--spec/ruby/library/matrix/transpose_spec.rb9
-rw-r--r--spec/ruby/library/matrix/unit_spec.rb9
-rw-r--r--spec/ruby/library/matrix/unitary_spec.rb50
-rw-r--r--spec/ruby/library/matrix/upper_triangular_spec.rb39
-rw-r--r--spec/ruby/library/matrix/vector/cross_product_spec.rb21
-rw-r--r--spec/ruby/library/matrix/vector/each2_spec.rb81
-rw-r--r--spec/ruby/library/matrix/vector/eql_spec.rb23
-rw-r--r--spec/ruby/library/matrix/vector/inner_product_spec.rb33
-rw-r--r--spec/ruby/library/matrix/vector/normalize_spec.rb29
-rw-r--r--spec/ruby/library/matrix/zero_spec.rb75
-rw-r--r--spec/ruby/library/monitor/exit_spec.rb10
-rw-r--r--spec/ruby/library/net-ftp/FTPError_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/FTPPermError_spec.rb12
-rw-r--r--spec/ruby/library/net-ftp/FTPProtoError_spec.rb12
-rw-r--r--spec/ruby/library/net-ftp/FTPReplyError_spec.rb12
-rw-r--r--spec/ruby/library/net-ftp/FTPTempError_spec.rb12
-rw-r--r--spec/ruby/library/net-ftp/abort_spec.rb62
-rw-r--r--spec/ruby/library/net-ftp/acct_spec.rb58
-rw-r--r--spec/ruby/library/net-ftp/binary_spec.rb24
-rw-r--r--spec/ruby/library/net-ftp/chdir_spec.rb99
-rw-r--r--spec/ruby/library/net-ftp/close_spec.rb30
-rw-r--r--spec/ruby/library/net-ftp/closed_spec.rb21
-rw-r--r--spec/ruby/library/net-ftp/connect_spec.rb51
-rw-r--r--spec/ruby/library/net-ftp/debug_mode_spec.rb23
-rw-r--r--spec/ruby/library/net-ftp/default_passive_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/delete_spec.rb59
-rw-r--r--spec/ruby/library/net-ftp/dir_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/get_spec.rb21
-rw-r--r--spec/ruby/library/net-ftp/getbinaryfile_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/getdir_spec.rb7
-rw-r--r--spec/ruby/library/net-ftp/gettextfile_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/help_spec.rb66
-rw-r--r--spec/ruby/library/net-ftp/initialize_spec.rb405
-rw-r--r--spec/ruby/library/net-ftp/last_response_code_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/last_response_spec.rb25
-rw-r--r--spec/ruby/library/net-ftp/lastresp_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/list_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/login_spec.rb195
-rw-r--r--spec/ruby/library/net-ftp/ls_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/mdtm_spec.rb38
-rw-r--r--spec/ruby/library/net-ftp/mkdir_spec.rb61
-rw-r--r--spec/ruby/library/net-ftp/mtime_spec.rb50
-rw-r--r--spec/ruby/library/net-ftp/nlst_spec.rb92
-rw-r--r--spec/ruby/library/net-ftp/noop_spec.rb38
-rw-r--r--spec/ruby/library/net-ftp/open_spec.rb55
-rw-r--r--spec/ruby/library/net-ftp/passive_spec.rb28
-rw-r--r--spec/ruby/library/net-ftp/put_spec.rb21
-rw-r--r--spec/ruby/library/net-ftp/putbinaryfile_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/puttextfile_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/pwd_spec.rb53
-rw-r--r--spec/ruby/library/net-ftp/quit_spec.rb33
-rw-r--r--spec/ruby/library/net-ftp/rename_spec.rb94
-rw-r--r--spec/ruby/library/net-ftp/resume_spec.rb23
-rw-r--r--spec/ruby/library/net-ftp/retrbinary_spec.rb30
-rw-r--r--spec/ruby/library/net-ftp/retrlines_spec.rb34
-rw-r--r--spec/ruby/library/net-ftp/return_code_spec.rb24
-rw-r--r--spec/ruby/library/net-ftp/rmdir_spec.rb58
-rw-r--r--spec/ruby/library/net-ftp/sendcmd_spec.rb54
-rw-r--r--spec/ruby/library/net-ftp/set_socket_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/shared/getbinaryfile.rb150
-rw-r--r--spec/ruby/library/net-ftp/shared/gettextfile.rb100
-rw-r--r--spec/ruby/library/net-ftp/shared/putbinaryfile.rb167
-rw-r--r--spec/ruby/library/net-ftp/shared/puttextfile.rb128
-rw-r--r--spec/ruby/library/net-ftp/site_spec.rb53
-rw-r--r--spec/ruby/library/net-ftp/size_spec.rb48
-rw-r--r--spec/ruby/library/net-ftp/status_spec.rb67
-rw-r--r--spec/ruby/library/net-ftp/storbinary_spec.rb49
-rw-r--r--spec/ruby/library/net-ftp/storlines_spec.rb44
-rw-r--r--spec/ruby/library/net-ftp/system_spec.rb48
-rw-r--r--spec/ruby/library/net-ftp/voidcmd_spec.rb54
-rw-r--r--spec/ruby/library/net-ftp/welcome_spec.rb25
-rw-r--r--spec/ruby/library/net-http/HTTPBadResponse_spec.rb8
-rw-r--r--spec/ruby/library/net-http/HTTPClientExcepton_spec.rb12
-rw-r--r--spec/ruby/library/net-http/HTTPError_spec.rb12
-rw-r--r--spec/ruby/library/net-http/HTTPFatalError_spec.rb12
-rw-r--r--spec/ruby/library/net-http/HTTPHeaderSyntaxError_spec.rb8
-rw-r--r--spec/ruby/library/net-http/HTTPRetriableError_spec.rb12
-rw-r--r--spec/ruby/library/net-http/HTTPServerException_spec.rb12
-rw-r--r--spec/ruby/library/net-http/http/Proxy_spec.rb35
-rw-r--r--spec/ruby/library/net-http/http/active_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/address_spec.rb9
-rw-r--r--spec/ruby/library/net-http/http/close_on_empty_response_spec.rb10
-rw-r--r--spec/ruby/library/net-http/http/copy_spec.rb21
-rw-r--r--spec/ruby/library/net-http/http/default_port_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/delete_spec.rb21
-rw-r--r--spec/ruby/library/net-http/http/finish_spec.rb29
-rw-r--r--spec/ruby/library/net-http/http/get2_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/get_print_spec.rb30
-rw-r--r--spec/ruby/library/net-http/http/get_response_spec.rb30
-rw-r--r--spec/ruby/library/net-http/http/get_spec.rb94
-rw-r--r--spec/ruby/library/net-http/http/head2_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/head_spec.rb25
-rw-r--r--spec/ruby/library/net-http/http/http_default_port_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/https_default_port_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/initialize_spec.rb46
-rw-r--r--spec/ruby/library/net-http/http/inspect_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/is_version_1_1_spec.rb7
-rw-r--r--spec/ruby/library/net-http/http/is_version_1_2_spec.rb7
-rw-r--r--spec/ruby/library/net-http/http/lock_spec.rb21
-rw-r--r--spec/ruby/library/net-http/http/mkcol_spec.rb21
-rw-r--r--spec/ruby/library/net-http/http/move_spec.rb25
-rw-r--r--spec/ruby/library/net-http/http/new_spec.rb86
-rw-r--r--spec/ruby/library/net-http/http/newobj_spec.rb48
-rw-r--r--spec/ruby/library/net-http/http/open_timeout_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/options_spec.rb25
-rw-r--r--spec/ruby/library/net-http/http/port_spec.rb9
-rw-r--r--spec/ruby/library/net-http/http/post2_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/post_form_spec.rb22
-rw-r--r--spec/ruby/library/net-http/http/post_spec.rb74
-rw-r--r--spec/ruby/library/net-http/http/propfind_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/proppatch_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/proxy_address_spec.rb31
-rw-r--r--spec/ruby/library/net-http/http/proxy_class_spec.rb9
-rw-r--r--spec/ruby/library/net-http/http/proxy_pass_spec.rb39
-rw-r--r--spec/ruby/library/net-http/http/proxy_port_spec.rb39
-rw-r--r--spec/ruby/library/net-http/http/proxy_user_spec.rb39
-rw-r--r--spec/ruby/library/net-http/http/put2_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/put_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/read_timeout_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/request_get_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/request_head_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/request_post_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/request_put_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/request_spec.rb109
-rw-r--r--spec/ruby/library/net-http/http/request_types_spec.rb254
-rw-r--r--spec/ruby/library/net-http/http/send_request_spec.rb61
-rw-r--r--spec/ruby/library/net-http/http/set_debug_output_spec.rb33
-rw-r--r--spec/ruby/library/net-http/http/socket_type_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/start_spec.rb111
-rw-r--r--spec/ruby/library/net-http/http/started_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/trace_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/unlock_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/use_ssl_spec.rb9
-rw-r--r--spec/ruby/library/net-http/http/version_1_1_spec.rb7
-rw-r--r--spec/ruby/library/net-http/http/version_1_2_spec.rb20
-rw-r--r--spec/ruby/library/net-http/httpexceptions/initialize_spec.rb17
-rw-r--r--spec/ruby/library/net-http/httpexceptions/response_spec.rb10
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb21
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/body_spec.rb30
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb32
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb131
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/inspect_spec.rb25
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/method_spec.rb15
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/path_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb21
-rw-r--r--spec/ruby/library/net-http/httpheader/add_field_spec.rb31
-rw-r--r--spec/ruby/library/net-http/httpheader/basic_auth_spec.rb14
-rw-r--r--spec/ruby/library/net-http/httpheader/canonical_each_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/chunked_spec.rb22
-rw-r--r--spec/ruby/library/net-http/httpheader/content_length_spec.rb54
-rw-r--r--spec/ruby/library/net-http/httpheader/content_range_spec.rb32
-rw-r--r--spec/ruby/library/net-http/httpheader/content_type_spec.rb26
-rw-r--r--spec/ruby/library/net-http/httpheader/delete_spec.rb30
-rw-r--r--spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb35
-rw-r--r--spec/ruby/library/net-http/httpheader/each_capitalized_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/each_header_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/each_key_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/each_name_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/each_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/each_value_spec.rb35
-rw-r--r--spec/ruby/library/net-http/httpheader/element_reference_spec.rb39
-rw-r--r--spec/ruby/library/net-http/httpheader/element_set_spec.rb41
-rw-r--r--spec/ruby/library/net-http/httpheader/fetch_spec.rb68
-rw-r--r--spec/ruby/library/net-http/httpheader/form_data_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/get_fields_spec.rb39
-rw-r--r--spec/ruby/library/net-http/httpheader/initialize_http_header_spec.rb21
-rw-r--r--spec/ruby/library/net-http/httpheader/key_spec.rb21
-rw-r--r--spec/ruby/library/net-http/httpheader/length_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/main_type_spec.rb24
-rw-r--r--spec/ruby/library/net-http/httpheader/proxy_basic_auth_spec.rb14
-rw-r--r--spec/ruby/library/net-http/httpheader/range_length_spec.rb32
-rw-r--r--spec/ruby/library/net-http/httpheader/range_spec.rb48
-rw-r--r--spec/ruby/library/net-http/httpheader/set_content_type_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/set_form_data_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/set_range_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/size_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/sub_type_spec.rb32
-rw-r--r--spec/ruby/library/net-http/httpheader/to_hash_spec.rb25
-rw-r--r--spec/ruby/library/net-http/httpheader/type_params_spec.rb24
-rw-r--r--spec/ruby/library/net-http/httprequest/initialize_spec.rb45
-rw-r--r--spec/ruby/library/net-http/httpresponse/body_permitted_spec.rb13
-rw-r--r--spec/ruby/library/net-http/httpresponse/body_spec.rb7
-rw-r--r--spec/ruby/library/net-http/httpresponse/code_spec.rb24
-rw-r--r--spec/ruby/library/net-http/httpresponse/code_type_spec.rb24
-rw-r--r--spec/ruby/library/net-http/httpresponse/entity_spec.rb7
-rw-r--r--spec/ruby/library/net-http/httpresponse/error_spec.rb24
-rw-r--r--spec/ruby/library/net-http/httpresponse/error_type_spec.rb24
-rw-r--r--spec/ruby/library/net-http/httpresponse/exception_type_spec.rb13
-rw-r--r--spec/ruby/library/net-http/httpresponse/header_spec.rb9
-rw-r--r--spec/ruby/library/net-http/httpresponse/http_version_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpresponse/initialize_spec.rb11
-rw-r--r--spec/ruby/library/net-http/httpresponse/inspect_spec.rb15
-rw-r--r--spec/ruby/library/net-http/httpresponse/message_spec.rb9
-rw-r--r--spec/ruby/library/net-http/httpresponse/msg_spec.rb9
-rw-r--r--spec/ruby/library/net-http/httpresponse/read_body_spec.rb86
-rw-r--r--spec/ruby/library/net-http/httpresponse/read_header_spec.rb9
-rw-r--r--spec/ruby/library/net-http/httpresponse/read_new_spec.rb23
-rw-r--r--spec/ruby/library/net-http/httpresponse/reading_body_spec.rb58
-rw-r--r--spec/ruby/library/net-http/httpresponse/response_spec.rb9
-rw-r--r--spec/ruby/library/net-http/httpresponse/value_spec.rb24
-rw-r--r--spec/ruby/library/net/FTPError_spec.rb11
-rw-r--r--spec/ruby/library/net/FTPPermError_spec.rb15
-rw-r--r--spec/ruby/library/net/FTPProtoError_spec.rb15
-rw-r--r--spec/ruby/library/net/FTPReplyError_spec.rb15
-rw-r--r--spec/ruby/library/net/FTPTempError_spec.rb15
-rw-r--r--spec/ruby/library/net/ftp/abort_spec.rb65
-rw-r--r--spec/ruby/library/net/ftp/acct_spec.rb61
-rw-r--r--spec/ruby/library/net/ftp/binary_spec.rb27
-rw-r--r--spec/ruby/library/net/ftp/chdir_spec.rb102
-rw-r--r--spec/ruby/library/net/ftp/close_spec.rb33
-rw-r--r--spec/ruby/library/net/ftp/closed_spec.rb24
-rw-r--r--spec/ruby/library/net/ftp/connect_spec.rb52
-rw-r--r--spec/ruby/library/net/ftp/debug_mode_spec.rb26
-rw-r--r--spec/ruby/library/net/ftp/default_passive_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/delete_spec.rb62
-rw-r--r--spec/ruby/library/net/ftp/dir_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/fixtures/default_passive.rb (renamed from spec/ruby/library/net-ftp/fixtures/default_passive.rb)0
-rw-r--r--spec/ruby/library/net/ftp/fixtures/passive.rb (renamed from spec/ruby/library/net-ftp/fixtures/passive.rb)0
-rw-r--r--spec/ruby/library/net/ftp/fixtures/putbinaryfile (renamed from spec/ruby/library/net-ftp/fixtures/putbinaryfile)0
-rw-r--r--spec/ruby/library/net/ftp/fixtures/puttextfile (renamed from spec/ruby/library/net-ftp/fixtures/puttextfile)0
-rw-r--r--spec/ruby/library/net/ftp/fixtures/server.rb (renamed from spec/ruby/library/net-ftp/fixtures/server.rb)0
-rw-r--r--spec/ruby/library/net/ftp/get_spec.rb24
-rw-r--r--spec/ruby/library/net/ftp/getbinaryfile_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/getdir_spec.rb10
-rw-r--r--spec/ruby/library/net/ftp/gettextfile_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/help_spec.rb69
-rw-r--r--spec/ruby/library/net/ftp/initialize_spec.rb408
-rw-r--r--spec/ruby/library/net/ftp/last_response_code_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/last_response_spec.rb28
-rw-r--r--spec/ruby/library/net/ftp/lastresp_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/list_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/login_spec.rb198
-rw-r--r--spec/ruby/library/net/ftp/ls_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/mdtm_spec.rb41
-rw-r--r--spec/ruby/library/net/ftp/mkdir_spec.rb64
-rw-r--r--spec/ruby/library/net/ftp/mtime_spec.rb53
-rw-r--r--spec/ruby/library/net/ftp/nlst_spec.rb95
-rw-r--r--spec/ruby/library/net/ftp/noop_spec.rb41
-rw-r--r--spec/ruby/library/net/ftp/open_spec.rb58
-rw-r--r--spec/ruby/library/net/ftp/passive_spec.rb31
-rw-r--r--spec/ruby/library/net/ftp/put_spec.rb24
-rw-r--r--spec/ruby/library/net/ftp/putbinaryfile_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/puttextfile_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/pwd_spec.rb56
-rw-r--r--spec/ruby/library/net/ftp/quit_spec.rb36
-rw-r--r--spec/ruby/library/net/ftp/rename_spec.rb97
-rw-r--r--spec/ruby/library/net/ftp/resume_spec.rb26
-rw-r--r--spec/ruby/library/net/ftp/retrbinary_spec.rb33
-rw-r--r--spec/ruby/library/net/ftp/retrlines_spec.rb37
-rw-r--r--spec/ruby/library/net/ftp/return_code_spec.rb27
-rw-r--r--spec/ruby/library/net/ftp/rmdir_spec.rb61
-rw-r--r--spec/ruby/library/net/ftp/sendcmd_spec.rb57
-rw-r--r--spec/ruby/library/net/ftp/set_socket_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/shared/getbinaryfile.rb150
-rw-r--r--spec/ruby/library/net/ftp/shared/gettextfile.rb100
-rw-r--r--spec/ruby/library/net/ftp/shared/last_response_code.rb (renamed from spec/ruby/library/net-ftp/shared/last_response_code.rb)0
-rw-r--r--spec/ruby/library/net/ftp/shared/list.rb (renamed from spec/ruby/library/net-ftp/shared/list.rb)0
-rw-r--r--spec/ruby/library/net/ftp/shared/putbinaryfile.rb167
-rw-r--r--spec/ruby/library/net/ftp/shared/puttextfile.rb120
-rw-r--r--spec/ruby/library/net/ftp/shared/pwd.rb (renamed from spec/ruby/library/net-ftp/shared/pwd.rb)0
-rw-r--r--spec/ruby/library/net/ftp/site_spec.rb56
-rw-r--r--spec/ruby/library/net/ftp/size_spec.rb51
-rw-r--r--spec/ruby/library/net/ftp/spec_helper.rb (renamed from spec/ruby/library/net-ftp/spec_helper.rb)0
-rw-r--r--spec/ruby/library/net/ftp/status_spec.rb70
-rw-r--r--spec/ruby/library/net/ftp/storbinary_spec.rb51
-rw-r--r--spec/ruby/library/net/ftp/storlines_spec.rb46
-rw-r--r--spec/ruby/library/net/ftp/system_spec.rb51
-rw-r--r--spec/ruby/library/net/ftp/voidcmd_spec.rb57
-rw-r--r--spec/ruby/library/net/ftp/welcome_spec.rb28
-rw-r--r--spec/ruby/library/net/http/HTTPBadResponse_spec.rb8
-rw-r--r--spec/ruby/library/net/http/HTTPClientExcepton_spec.rb12
-rw-r--r--spec/ruby/library/net/http/HTTPError_spec.rb12
-rw-r--r--spec/ruby/library/net/http/HTTPFatalError_spec.rb12
-rw-r--r--spec/ruby/library/net/http/HTTPHeaderSyntaxError_spec.rb8
-rw-r--r--spec/ruby/library/net/http/HTTPRetriableError_spec.rb12
-rw-r--r--spec/ruby/library/net/http/HTTPServerException_spec.rb12
-rw-r--r--spec/ruby/library/net/http/http/Proxy_spec.rb35
-rw-r--r--spec/ruby/library/net/http/http/active_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/address_spec.rb9
-rw-r--r--spec/ruby/library/net/http/http/close_on_empty_response_spec.rb10
-rw-r--r--spec/ruby/library/net/http/http/copy_spec.rb21
-rw-r--r--spec/ruby/library/net/http/http/default_port_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/delete_spec.rb21
-rw-r--r--spec/ruby/library/net/http/http/finish_spec.rb29
-rw-r--r--spec/ruby/library/net/http/http/fixtures/http_server.rb (renamed from spec/ruby/library/net-http/http/fixtures/http_server.rb)0
-rw-r--r--spec/ruby/library/net/http/http/get2_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/get_print_spec.rb30
-rw-r--r--spec/ruby/library/net/http/http/get_response_spec.rb30
-rw-r--r--spec/ruby/library/net/http/http/get_spec.rb96
-rw-r--r--spec/ruby/library/net/http/http/head2_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/head_spec.rb25
-rw-r--r--spec/ruby/library/net/http/http/http_default_port_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/https_default_port_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/initialize_spec.rb46
-rw-r--r--spec/ruby/library/net/http/http/inspect_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/is_version_1_1_spec.rb7
-rw-r--r--spec/ruby/library/net/http/http/is_version_1_2_spec.rb7
-rw-r--r--spec/ruby/library/net/http/http/lock_spec.rb21
-rw-r--r--spec/ruby/library/net/http/http/mkcol_spec.rb21
-rw-r--r--spec/ruby/library/net/http/http/move_spec.rb25
-rw-r--r--spec/ruby/library/net/http/http/new_spec.rb86
-rw-r--r--spec/ruby/library/net/http/http/newobj_spec.rb48
-rw-r--r--spec/ruby/library/net/http/http/open_timeout_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/options_spec.rb25
-rw-r--r--spec/ruby/library/net/http/http/port_spec.rb9
-rw-r--r--spec/ruby/library/net/http/http/post2_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/post_form_spec.rb22
-rw-r--r--spec/ruby/library/net/http/http/post_spec.rb74
-rw-r--r--spec/ruby/library/net/http/http/propfind_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/proppatch_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/proxy_address_spec.rb31
-rw-r--r--spec/ruby/library/net/http/http/proxy_class_spec.rb9
-rw-r--r--spec/ruby/library/net/http/http/proxy_pass_spec.rb39
-rw-r--r--spec/ruby/library/net/http/http/proxy_port_spec.rb39
-rw-r--r--spec/ruby/library/net/http/http/proxy_user_spec.rb39
-rw-r--r--spec/ruby/library/net/http/http/put2_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/put_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/read_timeout_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/request_get_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/request_head_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/request_post_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/request_put_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/request_spec.rb109
-rw-r--r--spec/ruby/library/net/http/http/request_types_spec.rb254
-rw-r--r--spec/ruby/library/net/http/http/send_request_spec.rb61
-rw-r--r--spec/ruby/library/net/http/http/set_debug_output_spec.rb33
-rw-r--r--spec/ruby/library/net/http/http/shared/request_get.rb (renamed from spec/ruby/library/net-http/http/shared/request_get.rb)0
-rw-r--r--spec/ruby/library/net/http/http/shared/request_head.rb (renamed from spec/ruby/library/net-http/http/shared/request_head.rb)0
-rw-r--r--spec/ruby/library/net/http/http/shared/request_post.rb (renamed from spec/ruby/library/net-http/http/shared/request_post.rb)0
-rw-r--r--spec/ruby/library/net/http/http/shared/request_put.rb (renamed from spec/ruby/library/net-http/http/shared/request_put.rb)0
-rw-r--r--spec/ruby/library/net/http/http/shared/started.rb (renamed from spec/ruby/library/net-http/http/shared/started.rb)0
-rw-r--r--spec/ruby/library/net/http/http/shared/version_1_1.rb (renamed from spec/ruby/library/net-http/http/shared/version_1_1.rb)0
-rw-r--r--spec/ruby/library/net/http/http/shared/version_1_2.rb (renamed from spec/ruby/library/net-http/http/shared/version_1_2.rb)0
-rw-r--r--spec/ruby/library/net/http/http/socket_type_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/start_spec.rb111
-rw-r--r--spec/ruby/library/net/http/http/started_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/trace_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/unlock_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/use_ssl_spec.rb9
-rw-r--r--spec/ruby/library/net/http/http/version_1_1_spec.rb7
-rw-r--r--spec/ruby/library/net/http/http/version_1_2_spec.rb20
-rw-r--r--spec/ruby/library/net/http/httpexceptions/fixtures/classes.rb (renamed from spec/ruby/library/net-http/httpexceptions/fixtures/classes.rb)0
-rw-r--r--spec/ruby/library/net/http/httpexceptions/initialize_spec.rb17
-rw-r--r--spec/ruby/library/net/http/httpexceptions/response_spec.rb10
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/body_exist_spec.rb21
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/body_spec.rb30
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/body_stream_spec.rb32
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/exec_spec.rb131
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/inspect_spec.rb25
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/method_spec.rb15
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/path_spec.rb12
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/request_body_permitted_spec.rb12
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/response_body_permitted_spec.rb12
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/set_body_internal_spec.rb21
-rw-r--r--spec/ruby/library/net/http/httpheader/add_field_spec.rb31
-rw-r--r--spec/ruby/library/net/http/httpheader/basic_auth_spec.rb14
-rw-r--r--spec/ruby/library/net/http/httpheader/canonical_each_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/chunked_spec.rb22
-rw-r--r--spec/ruby/library/net/http/httpheader/content_length_spec.rb54
-rw-r--r--spec/ruby/library/net/http/httpheader/content_range_spec.rb32
-rw-r--r--spec/ruby/library/net/http/httpheader/content_type_spec.rb26
-rw-r--r--spec/ruby/library/net/http/httpheader/delete_spec.rb30
-rw-r--r--spec/ruby/library/net/http/httpheader/each_capitalized_name_spec.rb35
-rw-r--r--spec/ruby/library/net/http/httpheader/each_capitalized_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/each_header_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/each_key_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/each_name_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/each_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/each_value_spec.rb35
-rw-r--r--spec/ruby/library/net/http/httpheader/element_reference_spec.rb39
-rw-r--r--spec/ruby/library/net/http/httpheader/element_set_spec.rb41
-rw-r--r--spec/ruby/library/net/http/httpheader/fetch_spec.rb68
-rw-r--r--spec/ruby/library/net/http/httpheader/fixtures/classes.rb (renamed from spec/ruby/library/net-http/httpheader/fixtures/classes.rb)0
-rw-r--r--spec/ruby/library/net/http/httpheader/form_data_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/get_fields_spec.rb39
-rw-r--r--spec/ruby/library/net/http/httpheader/initialize_http_header_spec.rb21
-rw-r--r--spec/ruby/library/net/http/httpheader/key_spec.rb21
-rw-r--r--spec/ruby/library/net/http/httpheader/length_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/main_type_spec.rb24
-rw-r--r--spec/ruby/library/net/http/httpheader/proxy_basic_auth_spec.rb14
-rw-r--r--spec/ruby/library/net/http/httpheader/range_length_spec.rb32
-rw-r--r--spec/ruby/library/net/http/httpheader/range_spec.rb48
-rw-r--r--spec/ruby/library/net/http/httpheader/set_content_type_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/set_form_data_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/set_range_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/shared/each_capitalized.rb (renamed from spec/ruby/library/net-http/httpheader/shared/each_capitalized.rb)0
-rw-r--r--spec/ruby/library/net/http/httpheader/shared/each_header.rb (renamed from spec/ruby/library/net-http/httpheader/shared/each_header.rb)0
-rw-r--r--spec/ruby/library/net/http/httpheader/shared/each_name.rb (renamed from spec/ruby/library/net-http/httpheader/shared/each_name.rb)0
-rw-r--r--spec/ruby/library/net/http/httpheader/shared/set_content_type.rb (renamed from spec/ruby/library/net-http/httpheader/shared/set_content_type.rb)0
-rw-r--r--spec/ruby/library/net/http/httpheader/shared/set_form_data.rb (renamed from spec/ruby/library/net-http/httpheader/shared/set_form_data.rb)0
-rw-r--r--spec/ruby/library/net/http/httpheader/shared/set_range.rb (renamed from spec/ruby/library/net-http/httpheader/shared/set_range.rb)0
-rw-r--r--spec/ruby/library/net/http/httpheader/shared/size.rb (renamed from spec/ruby/library/net-http/httpheader/shared/size.rb)0
-rw-r--r--spec/ruby/library/net/http/httpheader/size_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/sub_type_spec.rb32
-rw-r--r--spec/ruby/library/net/http/httpheader/to_hash_spec.rb25
-rw-r--r--spec/ruby/library/net/http/httpheader/type_params_spec.rb24
-rw-r--r--spec/ruby/library/net/http/httprequest/initialize_spec.rb45
-rw-r--r--spec/ruby/library/net/http/httpresponse/body_permitted_spec.rb13
-rw-r--r--spec/ruby/library/net/http/httpresponse/body_spec.rb7
-rw-r--r--spec/ruby/library/net/http/httpresponse/code_spec.rb24
-rw-r--r--spec/ruby/library/net/http/httpresponse/code_type_spec.rb24
-rw-r--r--spec/ruby/library/net/http/httpresponse/entity_spec.rb7
-rw-r--r--spec/ruby/library/net/http/httpresponse/error_spec.rb24
-rw-r--r--spec/ruby/library/net/http/httpresponse/error_type_spec.rb24
-rw-r--r--spec/ruby/library/net/http/httpresponse/exception_type_spec.rb13
-rw-r--r--spec/ruby/library/net/http/httpresponse/header_spec.rb9
-rw-r--r--spec/ruby/library/net/http/httpresponse/http_version_spec.rb12
-rw-r--r--spec/ruby/library/net/http/httpresponse/initialize_spec.rb11
-rw-r--r--spec/ruby/library/net/http/httpresponse/inspect_spec.rb15
-rw-r--r--spec/ruby/library/net/http/httpresponse/message_spec.rb9
-rw-r--r--spec/ruby/library/net/http/httpresponse/msg_spec.rb9
-rw-r--r--spec/ruby/library/net/http/httpresponse/read_body_spec.rb86
-rw-r--r--spec/ruby/library/net/http/httpresponse/read_header_spec.rb9
-rw-r--r--spec/ruby/library/net/http/httpresponse/read_new_spec.rb23
-rw-r--r--spec/ruby/library/net/http/httpresponse/reading_body_spec.rb58
-rw-r--r--spec/ruby/library/net/http/httpresponse/response_spec.rb9
-rw-r--r--spec/ruby/library/net/http/httpresponse/shared/body.rb (renamed from spec/ruby/library/net-http/httpresponse/shared/body.rb)0
-rw-r--r--spec/ruby/library/net/http/httpresponse/value_spec.rb24
-rw-r--r--spec/ruby/library/objectspace/dump_all_spec.rb112
-rw-r--r--spec/ruby/library/objectspace/dump_spec.rb70
-rw-r--r--spec/ruby/library/objectspace/fixtures/trace.rb1
-rw-r--r--spec/ruby/library/objectspace/reachable_objects_from_spec.rb2
-rw-r--r--spec/ruby/library/objectspace/trace_spec.rb4
-rw-r--r--spec/ruby/library/openssl/config/freeze_spec.rb22
-rw-r--r--spec/ruby/library/openssl/digest/append_spec.rb6
-rw-r--r--spec/ruby/library/openssl/digest/block_length_spec.rb44
-rw-r--r--spec/ruby/library/openssl/digest/digest_length_spec.rb44
-rw-r--r--spec/ruby/library/openssl/digest/digest_spec.rb62
-rw-r--r--spec/ruby/library/openssl/digest/initialize_spec.rb141
-rw-r--r--spec/ruby/library/openssl/digest/name_spec.rb16
-rw-r--r--spec/ruby/library/openssl/digest/reset_spec.rb36
-rw-r--r--spec/ruby/library/openssl/digest/shared/update.rb123
-rw-r--r--spec/ruby/library/openssl/digest/update_spec.rb6
-rw-r--r--spec/ruby/library/openssl/digest_spec.rb63
-rw-r--r--spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb42
-rw-r--r--spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb168
-rw-r--r--spec/ruby/library/openssl/kdf/scrypt_spec.rb209
-rw-r--r--spec/ruby/library/openssl/random/shared/random_bytes.rb2
-rw-r--r--spec/ruby/library/openssl/secure_compare_spec.rb38
-rw-r--r--spec/ruby/library/openssl/x509/name/verify_spec.rb78
-rw-r--r--spec/ruby/library/openssl/x509/store/verify_spec.rb78
-rw-r--r--spec/ruby/library/pathname/relative_path_from_spec.rb4
-rw-r--r--spec/ruby/library/pp/pp_spec.rb2
-rw-r--r--spec/ruby/library/prime/each_spec.rb247
-rw-r--r--spec/ruby/library/prime/instance_spec.rb31
-rw-r--r--spec/ruby/library/prime/int_from_prime_division_spec.rb19
-rw-r--r--spec/ruby/library/prime/integer/each_prime_spec.rb19
-rw-r--r--spec/ruby/library/prime/integer/from_prime_division_spec.rb19
-rw-r--r--spec/ruby/library/prime/integer/prime_division_spec.rb31
-rw-r--r--spec/ruby/library/prime/integer/prime_spec.rb27
-rw-r--r--spec/ruby/library/prime/next_spec.rb11
-rw-r--r--spec/ruby/library/prime/prime_division_spec.rb37
-rw-r--r--spec/ruby/library/prime/prime_spec.rb27
-rw-r--r--spec/ruby/library/prime/succ_spec.rb11
-rw-r--r--spec/ruby/library/rbconfig/rbconfig_spec.rb55
-rw-r--r--spec/ruby/library/rexml/attribute/clone_spec.rb14
-rw-r--r--spec/ruby/library/rexml/attribute/element_spec.rb26
-rw-r--r--spec/ruby/library/rexml/attribute/equal_value_spec.rb21
-rw-r--r--spec/ruby/library/rexml/attribute/hash_spec.rb16
-rw-r--r--spec/ruby/library/rexml/attribute/initialize_spec.rb32
-rw-r--r--spec/ruby/library/rexml/attribute/inspect_spec.rb22
-rw-r--r--spec/ruby/library/rexml/attribute/namespace_spec.rb27
-rw-r--r--spec/ruby/library/rexml/attribute/node_type_spec.rb13
-rw-r--r--spec/ruby/library/rexml/attribute/prefix_spec.rb21
-rw-r--r--spec/ruby/library/rexml/attribute/remove_spec.rb23
-rw-r--r--spec/ruby/library/rexml/attribute/to_s_spec.rb17
-rw-r--r--spec/ruby/library/rexml/attribute/to_string_spec.rb17
-rw-r--r--spec/ruby/library/rexml/attribute/value_spec.rb17
-rw-r--r--spec/ruby/library/rexml/attribute/write_spec.rb26
-rw-r--r--spec/ruby/library/rexml/attribute/xpath_spec.rb22
-rw-r--r--spec/ruby/library/rexml/attributes/add_spec.rb10
-rw-r--r--spec/ruby/library/rexml/attributes/append_spec.rb10
-rw-r--r--spec/ruby/library/rexml/attributes/delete_all_spec.rb34
-rw-r--r--spec/ruby/library/rexml/attributes/delete_spec.rb30
-rw-r--r--spec/ruby/library/rexml/attributes/each_attribute_spec.rb25
-rw-r--r--spec/ruby/library/rexml/attributes/each_spec.rb26
-rw-r--r--spec/ruby/library/rexml/attributes/element_reference_spec.rb21
-rw-r--r--spec/ruby/library/rexml/attributes/element_set_spec.rb28
-rw-r--r--spec/ruby/library/rexml/attributes/get_attribute_ns_spec.rb17
-rw-r--r--spec/ruby/library/rexml/attributes/get_attribute_spec.rb32
-rw-r--r--spec/ruby/library/rexml/attributes/initialize_spec.rb21
-rw-r--r--spec/ruby/library/rexml/attributes/length_spec.rb10
-rw-r--r--spec/ruby/library/rexml/attributes/namespaces_spec.rb9
-rw-r--r--spec/ruby/library/rexml/attributes/prefixes_spec.rb27
-rw-r--r--spec/ruby/library/rexml/attributes/shared/add.rb17
-rw-r--r--spec/ruby/library/rexml/attributes/shared/length.rb13
-rw-r--r--spec/ruby/library/rexml/attributes/size_spec.rb10
-rw-r--r--spec/ruby/library/rexml/attributes/to_a_spec.rb22
-rw-r--r--spec/ruby/library/rexml/cdata/clone_spec.rb13
-rw-r--r--spec/ruby/library/rexml/cdata/initialize_spec.rb27
-rw-r--r--spec/ruby/library/rexml/cdata/shared/to_s.rb11
-rw-r--r--spec/ruby/library/rexml/cdata/to_s_spec.rb10
-rw-r--r--spec/ruby/library/rexml/cdata/value_spec.rb10
-rw-r--r--spec/ruby/library/rexml/document/add_element_spec.rb34
-rw-r--r--spec/ruby/library/rexml/document/add_spec.rb60
-rw-r--r--spec/ruby/library/rexml/document/clone_spec.rb23
-rw-r--r--spec/ruby/library/rexml/document/doctype_spec.rb18
-rw-r--r--spec/ruby/library/rexml/document/encoding_spec.rb25
-rw-r--r--spec/ruby/library/rexml/document/expanded_name_spec.rb19
-rw-r--r--spec/ruby/library/rexml/document/new_spec.rb39
-rw-r--r--spec/ruby/library/rexml/document/node_type_spec.rb11
-rw-r--r--spec/ruby/library/rexml/document/root_spec.rb15
-rw-r--r--spec/ruby/library/rexml/document/stand_alone_spec.rb22
-rw-r--r--spec/ruby/library/rexml/document/version_spec.rb17
-rw-r--r--spec/ruby/library/rexml/document/write_spec.rb38
-rw-r--r--spec/ruby/library/rexml/document/xml_decl_spec.rb18
-rw-r--r--spec/ruby/library/rexml/element/add_attribute_spec.rb44
-rw-r--r--spec/ruby/library/rexml/element/add_attributes_spec.rb25
-rw-r--r--spec/ruby/library/rexml/element/add_element_spec.rb41
-rw-r--r--spec/ruby/library/rexml/element/add_namespace_spec.rb26
-rw-r--r--spec/ruby/library/rexml/element/add_text_spec.rb27
-rw-r--r--spec/ruby/library/rexml/element/attribute_spec.rb20
-rw-r--r--spec/ruby/library/rexml/element/attributes_spec.rb22
-rw-r--r--spec/ruby/library/rexml/element/cdatas_spec.rb27
-rw-r--r--spec/ruby/library/rexml/element/clone_spec.rb32
-rw-r--r--spec/ruby/library/rexml/element/comments_spec.rb23
-rw-r--r--spec/ruby/library/rexml/element/delete_attribute_spec.rb42
-rw-r--r--spec/ruby/library/rexml/element/delete_element_spec.rb52
-rw-r--r--spec/ruby/library/rexml/element/delete_namespace_spec.rb28
-rw-r--r--spec/ruby/library/rexml/element/document_spec.rb19
-rw-r--r--spec/ruby/library/rexml/element/each_element_with_attribute_spec.rb38
-rw-r--r--spec/ruby/library/rexml/element/each_element_with_text_spec.rb34
-rw-r--r--spec/ruby/library/rexml/element/element_reference_spec.rb23
-rw-r--r--spec/ruby/library/rexml/element/get_text_spec.rb21
-rw-r--r--spec/ruby/library/rexml/element/has_attributes_spec.rb20
-rw-r--r--spec/ruby/library/rexml/element/has_elements_spec.rb21
-rw-r--r--spec/ruby/library/rexml/element/has_text_spec.rb19
-rw-r--r--spec/ruby/library/rexml/element/inspect_spec.rb30
-rw-r--r--spec/ruby/library/rexml/element/instructions_spec.rb24
-rw-r--r--spec/ruby/library/rexml/element/namespace_spec.rb30
-rw-r--r--spec/ruby/library/rexml/element/namespaces_spec.rb35
-rw-r--r--spec/ruby/library/rexml/element/new_spec.rb38
-rw-r--r--spec/ruby/library/rexml/element/next_element_spec.rb22
-rw-r--r--spec/ruby/library/rexml/element/node_type_spec.rb11
-rw-r--r--spec/ruby/library/rexml/element/prefixes_spec.rb26
-rw-r--r--spec/ruby/library/rexml/element/previous_element_spec.rb23
-rw-r--r--spec/ruby/library/rexml/element/raw_spec.rb27
-rw-r--r--spec/ruby/library/rexml/element/root_spec.rb31
-rw-r--r--spec/ruby/library/rexml/element/text_spec.rb49
-rw-r--r--spec/ruby/library/rexml/element/texts_spec.rb19
-rw-r--r--spec/ruby/library/rexml/element/whitespace_spec.rb26
-rw-r--r--spec/ruby/library/rexml/node/each_recursive_spec.rb24
-rw-r--r--spec/ruby/library/rexml/node/find_first_recursive_spec.rb28
-rw-r--r--spec/ruby/library/rexml/node/index_in_parent_spec.rb18
-rw-r--r--spec/ruby/library/rexml/node/next_sibling_node_spec.rb24
-rw-r--r--spec/ruby/library/rexml/node/parent_spec.rb23
-rw-r--r--spec/ruby/library/rexml/node/previous_sibling_node_spec.rb24
-rw-r--r--spec/ruby/library/rexml/shared/each_element.rb36
-rw-r--r--spec/ruby/library/rexml/shared/elements_to_a.rb34
-rw-r--r--spec/ruby/library/rexml/text/append_spec.rb13
-rw-r--r--spec/ruby/library/rexml/text/clone_spec.rb13
-rw-r--r--spec/ruby/library/rexml/text/comparison_spec.rb28
-rw-r--r--spec/ruby/library/rexml/text/empty_spec.rb15
-rw-r--r--spec/ruby/library/rexml/text/indent_text_spec.rb26
-rw-r--r--spec/ruby/library/rexml/text/inspect_spec.rb11
-rw-r--r--spec/ruby/library/rexml/text/new_spec.rb51
-rw-r--r--spec/ruby/library/rexml/text/node_type_spec.rb11
-rw-r--r--spec/ruby/library/rexml/text/normalize_spec.rb11
-rw-r--r--spec/ruby/library/rexml/text/read_with_substitution_spec.rb15
-rw-r--r--spec/ruby/library/rexml/text/to_s_spec.rb20
-rw-r--r--spec/ruby/library/rexml/text/unnormalize_spec.rb11
-rw-r--r--spec/ruby/library/rexml/text/value_spec.rb40
-rw-r--r--spec/ruby/library/rexml/text/wrap_spec.rb23
-rw-r--r--spec/ruby/library/rexml/text/write_with_substitution_spec.rb36
-rw-r--r--spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb2
-rw-r--r--spec/ruby/library/set/compare_by_identity_spec.rb2
-rw-r--r--spec/ruby/library/set/comparison_spec.rb56
-rw-r--r--spec/ruby/library/set/divide_spec.rb35
-rw-r--r--spec/ruby/library/set/each_spec.rb1
-rw-r--r--spec/ruby/library/set/enumerable/to_set_spec.rb8
-rw-r--r--spec/ruby/library/set/flatten_spec.rb9
-rw-r--r--spec/ruby/library/set/initialize_clone_spec.rb22
-rw-r--r--spec/ruby/library/set/join_spec.rb42
-rw-r--r--spec/ruby/library/set/proper_subset_spec.rb9
-rw-r--r--spec/ruby/library/set/set_spec.rb12
-rw-r--r--spec/ruby/library/set/shared/inspect.rb20
-rw-r--r--spec/ruby/library/set/sortedset/add_spec.rb42
-rw-r--r--spec/ruby/library/set/sortedset/append_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/case_equality_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/classify_spec.rb30
-rw-r--r--spec/ruby/library/set/sortedset/clear_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/collect_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/constructor_spec.rb18
-rw-r--r--spec/ruby/library/set/sortedset/delete_if_spec.rb41
-rw-r--r--spec/ruby/library/set/sortedset/delete_spec.rb40
-rw-r--r--spec/ruby/library/set/sortedset/difference_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/divide_spec.rb37
-rw-r--r--spec/ruby/library/set/sortedset/each_spec.rb29
-rw-r--r--spec/ruby/library/set/sortedset/empty_spec.rb13
-rw-r--r--spec/ruby/library/set/sortedset/eql_spec.rb19
-rw-r--r--spec/ruby/library/set/sortedset/equal_value_spec.rb16
-rw-r--r--spec/ruby/library/set/sortedset/exclusion_spec.rb21
-rw-r--r--spec/ruby/library/set/sortedset/filter_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/flatten_merge_spec.rb11
-rw-r--r--spec/ruby/library/set/sortedset/flatten_spec.rb47
-rw-r--r--spec/ruby/library/set/sortedset/hash_spec.rb16
-rw-r--r--spec/ruby/library/set/sortedset/include_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/initialize_spec.rb33
-rw-r--r--spec/ruby/library/set/sortedset/inspect_spec.rb13
-rw-r--r--spec/ruby/library/set/sortedset/intersection_spec.rb14
-rw-r--r--spec/ruby/library/set/sortedset/keep_if_spec.rb34
-rw-r--r--spec/ruby/library/set/sortedset/length_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/map_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/member_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/merge_spec.rb22
-rw-r--r--spec/ruby/library/set/sortedset/minus_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/plus_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/pretty_print_cycle_spec.rb13
-rw-r--r--spec/ruby/library/set/sortedset/pretty_print_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/proper_subset_spec.rb36
-rw-r--r--spec/ruby/library/set/sortedset/proper_superset_spec.rb36
-rw-r--r--spec/ruby/library/set/sortedset/reject_spec.rb45
-rw-r--r--spec/ruby/library/set/sortedset/replace_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/select_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/shared/add.rb14
-rw-r--r--spec/ruby/library/set/sortedset/shared/collect.rb20
-rw-r--r--spec/ruby/library/set/sortedset/shared/difference.rb15
-rw-r--r--spec/ruby/library/set/sortedset/shared/include.rb7
-rw-r--r--spec/ruby/library/set/sortedset/shared/intersection.rb15
-rw-r--r--spec/ruby/library/set/sortedset/shared/length.rb6
-rw-r--r--spec/ruby/library/set/sortedset/shared/select.rb35
-rw-r--r--spec/ruby/library/set/sortedset/shared/union.rb15
-rw-r--r--spec/ruby/library/set/sortedset/size_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/sortedset_spec.rb24
-rw-r--r--spec/ruby/library/set/sortedset/subset_spec.rb36
-rw-r--r--spec/ruby/library/set/sortedset/subtract_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/superset_spec.rb36
-rw-r--r--spec/ruby/library/set/sortedset/to_a_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/union_spec.rb14
-rw-r--r--spec/ruby/library/set/subset_spec.rb9
-rw-r--r--spec/ruby/library/set/to_s_spec.rb1
-rw-r--r--spec/ruby/library/shellwords/shellwords_spec.rb15
-rw-r--r--spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb4
-rw-r--r--spec/ruby/library/socket/basicsocket/read_nonblock_spec.rb32
-rw-r--r--spec/ruby/library/socket/basicsocket/read_spec.rb47
-rw-r--r--spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb16
-rw-r--r--spec/ruby/library/socket/basicsocket/recv_spec.rb41
-rw-r--r--spec/ruby/library/socket/basicsocket/send_spec.rb8
-rw-r--r--spec/ruby/library/socket/basicsocket/shutdown_spec.rb20
-rw-r--r--spec/ruby/library/socket/fixtures/classes.rb6
-rw-r--r--spec/ruby/library/socket/ipsocket/getaddress_spec.rb7
-rw-r--r--spec/ruby/library/socket/shared/pack_sockaddr.rb3
-rw-r--r--spec/ruby/library/socket/shared/partially_closable_sockets.rb2
-rw-r--r--spec/ruby/library/socket/socket/getnameinfo_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/new_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/pair_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb21
-rw-r--r--spec/ruby/library/socket/socket/socketpair_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpserver/accept_spec.rb15
-rw-r--r--spec/ruby/library/socket/tcpserver/new_spec.rb6
-rw-r--r--spec/ruby/library/socket/tcpsocket/initialize_spec.rb34
-rw-r--r--spec/ruby/library/socket/tcpsocket/open_spec.rb1
-rw-r--r--spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpsocket/shared/new.rb16
-rw-r--r--spec/ruby/library/socket/udpsocket/initialize_spec.rb13
-rw-r--r--spec/ruby/library/socket/udpsocket/new_spec.rb6
-rw-r--r--spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb9
-rw-r--r--spec/ruby/library/socket/udpsocket/send_spec.rb2
-rw-r--r--spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb7
-rw-r--r--spec/ruby/library/socket/unixserver/accept_spec.rb13
-rw-r--r--spec/ruby/library/socket/unixserver/for_fd_spec.rb4
-rw-r--r--spec/ruby/library/socket/unixserver/new_spec.rb12
-rw-r--r--spec/ruby/library/socket/unixserver/open_spec.rb6
-rw-r--r--spec/ruby/library/socket/unixserver/shared/new.rb26
-rw-r--r--spec/ruby/library/socket/unixsocket/addr_spec.rb5
-rw-r--r--spec/ruby/library/socket/unixsocket/initialize_spec.rb10
-rw-r--r--spec/ruby/library/socket/unixsocket/inspect_spec.rb4
-rw-r--r--spec/ruby/library/socket/unixsocket/local_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/unixsocket/new_spec.rb12
-rw-r--r--spec/ruby/library/socket/unixsocket/open_spec.rb10
-rw-r--r--spec/ruby/library/socket/unixsocket/pair_spec.rb29
-rw-r--r--spec/ruby/library/socket/unixsocket/partially_closable_spec.rb6
-rw-r--r--spec/ruby/library/socket/unixsocket/path_spec.rb6
-rw-r--r--spec/ruby/library/socket/unixsocket/peeraddr_spec.rb6
-rw-r--r--spec/ruby/library/socket/unixsocket/recv_io_spec.rb7
-rw-r--r--spec/ruby/library/socket/unixsocket/recvfrom_spec.rb30
-rw-r--r--spec/ruby/library/socket/unixsocket/send_io_spec.rb7
-rw-r--r--spec/ruby/library/socket/unixsocket/shared/new.rb28
-rw-r--r--spec/ruby/library/socket/unixsocket/shared/pair.rb29
-rw-r--r--spec/ruby/library/socket/unixsocket/socketpair_spec.rb38
-rw-r--r--spec/ruby/library/stringio/append_spec.rb15
-rw-r--r--spec/ruby/library/stringio/binmode_spec.rb2
-rw-r--r--spec/ruby/library/stringio/bytes_spec.rb29
-rw-r--r--spec/ruby/library/stringio/chars_spec.rb29
-rw-r--r--spec/ruby/library/stringio/close_read_spec.rb4
-rw-r--r--spec/ruby/library/stringio/close_write_spec.rb6
-rw-r--r--spec/ruby/library/stringio/closed_read_spec.rb2
-rw-r--r--spec/ruby/library/stringio/closed_spec.rb4
-rw-r--r--spec/ruby/library/stringio/closed_write_spec.rb2
-rw-r--r--spec/ruby/library/stringio/codepoints_spec.rb19
-rw-r--r--spec/ruby/library/stringio/flush_spec.rb2
-rw-r--r--spec/ruby/library/stringio/fsync_spec.rb2
-rw-r--r--spec/ruby/library/stringio/gets_spec.rb2
-rw-r--r--spec/ruby/library/stringio/initialize_spec.rb123
-rw-r--r--spec/ruby/library/stringio/lines_spec.rb53
-rw-r--r--spec/ruby/library/stringio/new_spec.rb8
-rw-r--r--spec/ruby/library/stringio/open_spec.rb60
-rw-r--r--spec/ruby/library/stringio/print_spec.rb8
-rw-r--r--spec/ruby/library/stringio/printf_spec.rb8
-rw-r--r--spec/ruby/library/stringio/putc_spec.rb10
-rw-r--r--spec/ruby/library/stringio/puts_spec.rb8
-rw-r--r--spec/ruby/library/stringio/read_nonblock_spec.rb4
-rw-r--r--spec/ruby/library/stringio/read_spec.rb2
-rw-r--r--spec/ruby/library/stringio/readline_spec.rb2
-rw-r--r--spec/ruby/library/stringio/readlines_spec.rb2
-rw-r--r--spec/ruby/library/stringio/readpartial_spec.rb6
-rw-r--r--spec/ruby/library/stringio/reopen_spec.rb68
-rw-r--r--spec/ruby/library/stringio/set_encoding_spec.rb8
-rw-r--r--spec/ruby/library/stringio/shared/codepoints.rb2
-rw-r--r--spec/ruby/library/stringio/shared/each.rb6
-rw-r--r--spec/ruby/library/stringio/shared/each_byte.rb2
-rw-r--r--spec/ruby/library/stringio/shared/each_char.rb2
-rw-r--r--spec/ruby/library/stringio/shared/getc.rb2
-rw-r--r--spec/ruby/library/stringio/shared/isatty.rb2
-rw-r--r--spec/ruby/library/stringio/shared/read.rb30
-rw-r--r--spec/ruby/library/stringio/shared/readchar.rb2
-rw-r--r--spec/ruby/library/stringio/shared/sysread.rb2
-rw-r--r--spec/ruby/library/stringio/shared/write.rb38
-rw-r--r--spec/ruby/library/stringio/truncate_spec.rb8
-rw-r--r--spec/ruby/library/stringio/ungetc_spec.rb10
-rw-r--r--spec/ruby/library/stringio/write_nonblock_spec.rb2
-rw-r--r--spec/ruby/library/stringscanner/check_until_spec.rb10
-rw-r--r--spec/ruby/library/stringscanner/exist_spec.rb10
-rw-r--r--spec/ruby/library/stringscanner/getch_spec.rb2
-rw-r--r--spec/ruby/library/stringscanner/scan_until_spec.rb16
-rw-r--r--spec/ruby/library/stringscanner/search_full_spec.rb10
-rw-r--r--spec/ruby/library/stringscanner/shared/concat.rb2
-rw-r--r--spec/ruby/library/stringscanner/skip_until_spec.rb10
-rw-r--r--spec/ruby/library/stringscanner/string_spec.rb2
-rw-r--r--spec/ruby/library/time/iso8601_spec.rb2
-rw-r--r--spec/ruby/library/time/shared/xmlschema.rb2
-rw-r--r--spec/ruby/library/time/to_date_spec.rb42
-rw-r--r--spec/ruby/library/time/to_datetime_spec.rb41
-rw-r--r--spec/ruby/library/time/xmlschema_spec.rb2
-rw-r--r--spec/ruby/library/uri/generic/host_spec.rb7
-rw-r--r--spec/ruby/library/uri/generic/to_s_spec.rb7
-rw-r--r--spec/ruby/library/uri/shared/parse.rb13
-rw-r--r--spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/_invoke_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/codepage_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/connect_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/const_load_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/constants_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/create_guid_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/invoke_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/locale_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/new_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_method_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/setproperty_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_event/new_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/event_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/name_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/new_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/params_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/visible_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/default_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/input_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/name_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/optional_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/retval_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/guid_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/name_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/new_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/progid_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/progids_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/variables_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/visible_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/name_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/value_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb1
-rw-r--r--spec/ruby/library/yaml/dump_spec.rb14
-rw-r--r--spec/ruby/library/yaml/dump_stream_spec.rb3
-rw-r--r--spec/ruby/library/yaml/fixtures/common.rb4
-rw-r--r--spec/ruby/library/yaml/fixtures/strings.rb56
-rw-r--r--spec/ruby/library/yaml/load_file_spec.rb13
-rw-r--r--spec/ruby/library/yaml/load_stream_spec.rb3
-rw-r--r--spec/ruby/library/yaml/parse_file_spec.rb8
-rw-r--r--spec/ruby/library/yaml/parse_spec.rb7
-rw-r--r--spec/ruby/library/yaml/shared/each_document.rb5
-rw-r--r--spec/ruby/library/yaml/shared/load.rb12
-rw-r--r--spec/ruby/library/yaml/to_yaml_spec.rb20
-rw-r--r--spec/ruby/library/zlib/deflate/deflate_spec.rb4
-rw-r--r--spec/ruby/library/zlib/deflate/new_spec.rb1
-rw-r--r--spec/ruby/library/zlib/deflate/params_spec.rb2
-rw-r--r--spec/ruby/library/zlib/gzipreader/each_line_spec.rb1
-rw-r--r--spec/ruby/library/zlib/gzipreader/each_spec.rb1
-rw-r--r--spec/ruby/library/zlib/gzipreader/mtime_spec.rb11
-rw-r--r--spec/ruby/library/zlib/gzipreader/new_spec.rb1
-rw-r--r--spec/ruby/library/zlib/inflate/finish_spec.rb1
-rw-r--r--spec/ruby/library/zlib/inflate/inflate_spec.rb8
-rw-r--r--spec/ruby/library/zlib/inflate/new_spec.rb1
-rw-r--r--spec/ruby/optional/capi/array_spec.rb34
-rw-r--r--spec/ruby/optional/capi/bignum_spec.rb26
-rw-r--r--spec/ruby/optional/capi/class_spec.rb40
-rw-r--r--spec/ruby/optional/capi/data_spec.rb73
-rw-r--r--spec/ruby/optional/capi/debug_spec.rb9
-rw-r--r--spec/ruby/optional/capi/encoding_spec.rb62
-rw-r--r--spec/ruby/optional/capi/exception_spec.rb34
-rw-r--r--spec/ruby/optional/capi/ext/array_spec.c28
-rw-r--r--spec/ruby/optional/capi/ext/class_spec.c13
-rw-r--r--spec/ruby/optional/capi/ext/data_spec.c4
-rw-r--r--spec/ruby/optional/capi/ext/debug_spec.c2
-rw-r--r--spec/ruby/optional/capi/ext/encoding_spec.c28
-rw-r--r--spec/ruby/optional/capi/ext/exception_spec.c19
-rw-r--r--spec/ruby/optional/capi/ext/gc_spec.c66
-rw-r--r--spec/ruby/optional/capi/ext/hash_spec.c9
-rw-r--r--spec/ruby/optional/capi/ext/integer_spec.c5
-rw-r--r--spec/ruby/optional/capi/ext/io_spec.c117
-rw-r--r--spec/ruby/optional/capi/ext/kernel_spec.c31
-rw-r--r--spec/ruby/optional/capi/ext/object_spec.c88
-rw-r--r--spec/ruby/optional/capi/ext/proc_spec.c15
-rw-r--r--spec/ruby/optional/capi/ext/range_spec.c2
-rw-r--r--spec/ruby/optional/capi/ext/rbasic_spec.c54
-rw-r--r--spec/ruby/optional/capi/ext/rubyspec.h38
-rw-r--r--spec/ruby/optional/capi/ext/string_spec.c45
-rw-r--r--spec/ruby/optional/capi/ext/struct_spec.c13
-rw-r--r--spec/ruby/optional/capi/ext/thread_spec.c13
-rw-r--r--spec/ruby/optional/capi/ext/tracepoint_spec.c2
-rw-r--r--spec/ruby/optional/capi/ext/typed_data_spec.c14
-rw-r--r--spec/ruby/optional/capi/ext/util_spec.c17
-rw-r--r--spec/ruby/optional/capi/file_spec.rb2
-rw-r--r--spec/ruby/optional/capi/fixnum_spec.rb4
-rw-r--r--spec/ruby/optional/capi/fixtures/kernel.rb19
-rw-r--r--spec/ruby/optional/capi/gc_spec.rb35
-rw-r--r--spec/ruby/optional/capi/hash_spec.rb16
-rw-r--r--spec/ruby/optional/capi/integer_spec.rb17
-rw-r--r--spec/ruby/optional/capi/io_spec.rb184
-rw-r--r--spec/ruby/optional/capi/kernel_spec.rb170
-rw-r--r--spec/ruby/optional/capi/numeric_spec.rb8
-rw-r--r--spec/ruby/optional/capi/object_spec.rb22
-rw-r--r--spec/ruby/optional/capi/proc_spec.rb53
-rw-r--r--spec/ruby/optional/capi/rbasic_spec.rb56
-rw-r--r--spec/ruby/optional/capi/shared/rbasic.rb1
-rw-r--r--spec/ruby/optional/capi/string_spec.rb72
-rw-r--r--spec/ruby/optional/capi/thread_spec.rb28
-rw-r--r--spec/ruby/optional/capi/time_spec.rb5
-rw-r--r--spec/ruby/optional/capi/typed_data_spec.rb12
-rw-r--r--spec/ruby/optional/capi/util_spec.rb97
-rw-r--r--spec/ruby/security/cve_2010_1330_spec.rb2
-rw-r--r--spec/ruby/security/cve_2014_8080_spec.rb34
-rw-r--r--spec/ruby/security/cve_2017_17742_spec.rb37
-rw-r--r--spec/ruby/security/cve_2019_8323_spec.rb14
-rw-r--r--spec/ruby/shared/file/exist.rb5
-rw-r--r--spec/ruby/shared/kernel/at_exit.rb76
-rw-r--r--spec/ruby/shared/kernel/fixtures/END.rb3
-rw-r--r--spec/ruby/shared/kernel/fixtures/at_exit.rb3
-rw-r--r--spec/ruby/shared/kernel/object_id.rb28
-rw-r--r--spec/ruby/shared/kernel/raise.rb11
-rw-r--r--spec/ruby/shared/process/exit.rb6
-rw-r--r--spec/ruby/shared/queue/deque.rb57
-rw-r--r--spec/ruby/shared/rational/Rational.rb9
-rw-r--r--spec/ruby/shared/rational/coerce.rb34
-rw-r--r--spec/ruby/shared/rational/marshal_dump.rb5
-rw-r--r--spec/ruby/shared/rational/marshal_load.rb5
-rw-r--r--spec/ruby/shared/rational/quo.rb5
-rw-r--r--spec/ruby/shared/rational/truncate.rb26
-rw-r--r--spec/ruby/shared/sizedqueue/enque.rb58
-rw-r--r--spec/ruby/shared/string/end_with.rb4
-rw-r--r--spec/ruby/shared/string/start_with.rb12
-rw-r--r--spec/ruby/shared/string/times.rb24
-rw-r--r--spec/ruby/shared/time/yday.rb18
-rw-r--r--spec/ruby/shared/types/rb_num2dbl_fails.rb17
-rw-r--r--spec/ruby/spec_helper.rb2
-rw-r--r--spec/syntax_suggest/integration/ruby_command_line_spec.rb8
-rw-r--r--spec/syntax_suggest/integration/syntax_suggest_spec.rb16
-rw-r--r--spec/syntax_suggest/unit/api_spec.rb6
-rw-r--r--spec/syntax_suggest/unit/around_block_scan_spec.rb2
-rw-r--r--spec/syntax_suggest/unit/block_expand_spec.rb4
-rw-r--r--spec/syntax_suggest/unit/capture/before_after_keyword_ends_spec.rb4
-rw-r--r--spec/syntax_suggest/unit/capture/falling_indent_lines_spec.rb4
-rw-r--r--spec/syntax_suggest/unit/capture_code_context_spec.rb32
-rw-r--r--spec/syntax_suggest/unit/clean_document_spec.rb14
-rw-r--r--spec/syntax_suggest/unit/code_line_spec.rb12
-rw-r--r--spec/syntax_suggest/unit/code_search_spec.rb82
-rw-r--r--spec/syntax_suggest/unit/core_ext_spec.rb2
-rw-r--r--spec/syntax_suggest/unit/explain_syntax_spec.rb4
-rw-r--r--spec/syntax_suggest/unit/lex_all_spec.rb3
-rw-r--r--spec/syntax_suggest/unit/pathname_from_message_spec.rb9
-rw-r--r--spec/syntax_suggest/unit/scan_history_spec.rb6
-rw-r--r--sprintf.c15
-rw-r--r--st.c188
-rw-r--r--strftime.c6
-rw-r--r--string.c1761
-rw-r--r--string.rb72
-rw-r--r--struct.c167
-rw-r--r--symbol.c95
-rw-r--r--symbol.h10
-rw-r--r--symbol.rb17
-rw-r--r--template/Doxyfile.tmpl361
-rw-r--r--template/GNUmakefile.in13
-rw-r--r--template/Makefile.in214
-rw-r--r--template/builtin_binary.inc.tmpl10
-rw-r--r--template/configure-ext.mk.tmpl2
-rw-r--r--template/encdb.h.tmpl36
-rw-r--r--template/exts.mk.tmpl52
-rw-r--r--template/fake.rb.in19
-rw-r--r--template/id.c.tmpl3
-rw-r--r--template/id.h.tmpl9
-rw-r--r--template/known_errors.inc.tmpl8
-rw-r--r--template/limits.c.tmpl17
-rw-r--r--template/prelude.c.tmpl95
-rw-r--r--template/ruby.pc.in2
-rw-r--r--template/sizes.c.tmpl17
-rw-r--r--template/transdb.h.tmpl39
-rwxr-xr-xtemplate/unicode_properties.rdoc.tmpl59
-rw-r--r--test/-ext-/bug_reporter/test_bug_reporter.rb19
-rw-r--r--test/-ext-/debug/test_debug.rb2
-rw-r--r--test/-ext-/debug/test_profile_frames.rb67
-rw-r--r--test/-ext-/integer/test_my_integer.rb34
-rw-r--r--test/-ext-/iseq_load/test_iseq_load.rb2
-rw-r--r--test/-ext-/load/test_resolve_symbol.rb27
-rw-r--r--test/-ext-/load/test_stringify_symbols.rb35
-rw-r--r--test/-ext-/marshal/test_internal_ivar.rb2
-rw-r--r--test/-ext-/postponed_job/test_postponed_job.rb72
-rw-r--r--test/-ext-/required.rb10
-rw-r--r--test/-ext-/string/test_capacity.rb8
-rw-r--r--test/-ext-/string/test_fstring.rb12
-rw-r--r--test/-ext-/string/test_set_len.rb18
-rw-r--r--test/-ext-/string/test_too_many_dummy_encodings.rb15
-rw-r--r--test/-ext-/struct/test_data.rb18
-rw-r--r--test/-ext-/test_bug-3571.rb4
-rw-r--r--test/-ext-/test_ensure_and_callcc.rb40
-rw-r--r--test/-ext-/thread/helper.rb51
-rw-r--r--test/-ext-/thread/test_instrumentation_api.rb274
-rw-r--r--test/-ext-/thread/test_lock_native_thread.rb50
-rw-r--r--test/-ext-/tracepoint/test_tracepoint.rb19
-rw-r--r--test/.excludes-parsey/TestM17N.rb1
-rw-r--r--test/.excludes-parsey/TestMixedUnicodeEscape.rb1
-rw-r--r--test/.excludes-parsey/TestRubyLiteral.rb1
-rw-r--r--test/.excludes/TestArraySubclass.rb1
-rw-r--r--test/.excludes/TestThread.rb18
-rw-r--r--test/base64/test_base64.rb115
-rw-r--r--test/bigdecimal/helper.rb39
-rw-r--r--test/bigdecimal/test_bigdecimal.rb2285
-rw-r--r--test/bigdecimal/test_bigdecimal_util.rb141
-rw-r--r--test/bigdecimal/test_bigmath.rb81
-rw-r--r--test/bigdecimal/test_ractor.rb23
-rw-r--r--test/cgi/test_cgi_util.rb49
-rw-r--r--test/coverage/test_coverage.rb147
-rw-r--r--test/csv/helper.rb42
-rw-r--r--test/csv/interface/test_delegation.rb47
-rw-r--r--test/csv/interface/test_read.rb381
-rw-r--r--test/csv/interface/test_read_write.rb124
-rw-r--r--test/csv/interface/test_write.rb217
-rw-r--r--test/csv/line_endings.gzbin0 -> 59 bytes-rw-r--r--test/csv/parse/test_column_separator.rb40
-rw-r--r--test/csv/parse/test_convert.rb165
-rw-r--r--test/csv/parse/test_each.rb23
-rw-r--r--test/csv/parse/test_general.rb341
-rw-r--r--test/csv/parse/test_header.rb342
-rw-r--r--test/csv/parse/test_inputs_scanner.rb63
-rw-r--r--test/csv/parse/test_invalid.rb52
-rw-r--r--test/csv/parse/test_liberal_parsing.rb171
-rw-r--r--test/csv/parse/test_quote_char_nil.rb93
-rw-r--r--test/csv/parse/test_read.rb27
-rw-r--r--test/csv/parse/test_rewind.rb40
-rw-r--r--test/csv/parse/test_row_separator.rb16
-rw-r--r--test/csv/parse/test_skip_lines.rb118
-rw-r--r--test/csv/parse/test_strip.rb112
-rw-r--r--test/csv/parse/test_unconverted_fields.rb117
-rw-r--r--test/csv/test_data_converters.rb190
-rw-r--r--test/csv/test_encodings.rb403
-rw-r--r--test/csv/test_features.rb359
-rw-r--r--test/csv/test_patterns.rb27
-rw-r--r--test/csv/test_row.rb435
-rw-r--r--test/csv/test_table.rb691
-rw-r--r--test/csv/write/test_converters.rb53
-rw-r--r--test/csv/write/test_force_quotes.rb78
-rw-r--r--test/csv/write/test_general.rb246
-rw-r--r--test/csv/write/test_quote_empty.rb70
-rw-r--r--test/date/test_date_parse.rb24
-rw-r--r--test/did_you_mean/core_ext/test_name_error_extension.rb4
-rw-r--r--test/drb/drbtest.rb396
-rw-r--r--test/drb/ignore_test_drb.rb14
-rw-r--r--test/drb/test_acl.rb207
-rw-r--r--test/drb/test_drb.rb371
-rw-r--r--test/drb/test_drbobject.rb69
-rw-r--r--test/drb/test_drbssl.rb80
-rw-r--r--test/drb/test_drbunix.rb60
-rw-r--r--test/drb/ut_array.rb17
-rw-r--r--test/drb/ut_array_drbssl.rb39
-rw-r--r--test/drb/ut_array_drbunix.rb17
-rw-r--r--test/drb/ut_drb.rb189
-rw-r--r--test/drb/ut_drb_drbssl.rb40
-rw-r--r--test/drb/ut_drb_drbunix.rb18
-rw-r--r--test/drb/ut_eq.rb37
-rw-r--r--test/drb/ut_large.rb62
-rw-r--r--test/drb/ut_port.rb16
-rw-r--r--test/drb/ut_safe1.rb17
-rw-r--r--test/drb/ut_timerholder.rb74
-rw-r--r--test/error_highlight/test_error_highlight.rb215
-rw-r--r--test/excludes/TestArray.rb (renamed from test/.excludes/TestArray.rb)0
-rw-r--r--test/excludes/TestException.rb (renamed from test/.excludes/TestException.rb)0
-rw-r--r--test/excludes/TestGem.rb (renamed from test/.excludes/TestGem.rb)0
-rw-r--r--test/excludes/TestIO_Console.rb (renamed from test/.excludes/TestIO_Console.rb)0
-rw-r--r--test/excludes/TestISeq.rb (renamed from test/.excludes/TestISeq.rb)0
-rw-r--r--test/excludes/TestThread.rb14
-rw-r--r--test/excludes/TestThreadQueue.rb (renamed from test/.excludes/TestThreadQueue.rb)0
-rw-r--r--test/excludes/_appveyor/TestArray.rb (renamed from test/.excludes/_appveyor/TestArray.rb)0
-rw-r--r--test/fiber/scheduler.rb152
-rw-r--r--test/fiber/test_address_resolve.rb2
-rw-r--r--test/fiber/test_io.rb56
-rw-r--r--test/fiber/test_io_buffer.rb41
-rw-r--r--test/fiber/test_mutex.rb2
-rw-r--r--test/fiber/test_process.rb8
-rw-r--r--test/fiber/test_scheduler.rb43
-rw-r--r--test/fiber/test_thread.rb2
-rw-r--r--test/fiddle/test_c_struct_entry.rb8
-rw-r--r--test/fiddle/test_closure.rb12
-rw-r--r--test/fiddle/test_cparser.rb40
-rw-r--r--test/fiddle/test_func.rb17
-rw-r--r--test/fiddle/test_function.rb6
-rw-r--r--test/fiddle/test_handle.rb19
-rw-r--r--test/fiddle/test_memory_view.rb114
-rw-r--r--test/fiddle/test_pointer.rb32
-rw-r--r--test/fileutils/test_fileutils.rb24
-rw-r--r--test/fixtures/fake_sorted_set_gem/sorted_set.rb (renamed from test/set/fixtures/fake_sorted_set_gem/sorted_set.rb)0
-rw-r--r--test/io/console/test_io_console.rb30
-rw-r--r--test/io/console/test_ractor.rb34
-rw-r--r--test/io/wait/test_io_wait.rb1
-rw-r--r--test/irb/command/test_cd.rb65
-rw-r--r--test/irb/command/test_custom_command.rb194
-rw-r--r--test/irb/command/test_disable_irb.rb28
-rw-r--r--test/irb/command/test_force_exit.rb51
-rw-r--r--test/irb/command/test_help.rb75
-rw-r--r--test/irb/command/test_multi_irb_commands.rb50
-rw-r--r--test/irb/command/test_show_source.rb397
-rw-r--r--test/irb/helper.rb172
-rw-r--r--test/irb/test_cmd.rb692
-rw-r--r--test/irb/test_color.rb65
-rw-r--r--test/irb/test_color_printer.rb20
-rw-r--r--test/irb/test_command.rb958
-rw-r--r--test/irb/test_completion.rb296
-rw-r--r--test/irb/test_context.rb447
-rw-r--r--test/irb/test_debug_cmd.rb303
-rw-r--r--test/irb/test_debugger_integration.rb513
-rw-r--r--test/irb/test_eval_history.rb69
-rw-r--r--test/irb/test_evaluation.rb44
-rw-r--r--test/irb/test_helper_method.rb135
-rw-r--r--test/irb/test_history.rb405
-rw-r--r--test/irb/test_init.rb261
-rw-r--r--test/irb/test_input_method.rb138
-rw-r--r--test/irb/test_irb.rb936
-rw-r--r--test/irb/test_locale.rb118
-rw-r--r--test/irb/test_nesting_parser.rb338
-rw-r--r--test/irb/test_option.rb2
-rw-r--r--test/irb/test_raise_exception.rb74
-rw-r--r--test/irb/test_raise_no_backtrace_exception.rb56
-rw-r--r--test/irb/test_ruby_lex.rb817
-rw-r--r--test/irb/test_tracer.rb90
-rw-r--r--test/irb/test_type_completor.rb109
-rw-r--r--test/irb/test_workspace.rb7
-rw-r--r--test/irb/yamatanooroti/test_rendering.rb738
-rw-r--r--test/json/json_addition_test.rb6
-rw-r--r--test/json/json_common_interface_test.rb34
-rw-r--r--test/json/json_encoding_test.rb9
-rw-r--r--test/json/json_ext_parser_test.rb21
-rw-r--r--test/json/json_fixtures_test.rb2
-rw-r--r--[-rwxr-xr-x]test/json/json_generator_test.rb67
-rw-r--r--test/json/json_generic_object_test.rb4
-rw-r--r--test/json/json_parser_test.rb83
-rw-r--r--test/json/json_string_matching_test.rb2
-rw-r--r--test/json/ractor_test.rb8
-rw-r--r--test/lib/!Nothing_to_test.rb5
-rw-r--r--test/lib/jit_support.rb93
-rw-r--r--test/lib/parser_support.rb20
-rw-r--r--test/logger/test_logger.rb9
-rw-r--r--test/logger/test_logperiod.rb83
-rw-r--r--test/logger/test_severity.rb32
-rw-r--r--test/mkmf/base.rb7
-rw-r--r--test/mkmf/test_config.rb56
-rw-r--r--test/mkmf/test_configuration.rb39
-rw-r--r--test/mkmf/test_flags.rb6
-rw-r--r--test/monitor/test_monitor.rb2
-rw-r--r--test/net/http/test_http.rb68
-rw-r--r--test/net/http/test_https.rb67
-rw-r--r--test/net/http/test_https_proxy.rb49
-rw-r--r--test/net/http/utils.rb357
-rw-r--r--test/nkf/test_kconv.rb82
-rw-r--r--test/nkf/test_nkf.rb23
-rw-r--r--test/objspace/test_objspace.rb146
-rw-r--r--test/objspace/test_ractor.rb24
-rw-r--r--test/open-uri/test_ftp.rb216
-rw-r--r--test/open-uri/test_open-uri.rb616
-rw-r--r--test/open-uri/test_proxy.rb174
-rw-r--r--test/open-uri/test_ssl.rb435
-rw-r--r--test/open-uri/utils.rb738
-rw-r--r--test/openssl/fixtures/pkey/dh1024.pem5
-rw-r--r--test/openssl/fixtures/pkey/dh2048_ffdhe2048.pem8
-rw-r--r--test/openssl/fixtures/pkey/dsa2048.pem15
-rw-r--r--test/openssl/test_bn.rb4
-rw-r--r--test/openssl/test_cipher.rb18
-rw-r--r--test/openssl/test_config.rb12
-rw-r--r--test/openssl/test_digest.rb22
-rw-r--r--test/openssl/test_engine.rb38
-rw-r--r--test/openssl/test_fips.rb40
-rw-r--r--test/openssl/test_ns_spki.rb6
-rw-r--r--test/openssl/test_ocsp.rb2
-rw-r--r--test/openssl/test_ossl.rb21
-rw-r--r--test/openssl/test_pair.rb41
-rw-r--r--test/openssl/test_pkcs12.rb35
-rw-r--r--test/openssl/test_pkcs7.rb21
-rw-r--r--test/openssl/test_pkey.rb64
-rw-r--r--test/openssl/test_pkey_dh.rb64
-rw-r--r--test/openssl/test_pkey_dsa.rb29
-rw-r--r--test/openssl/test_pkey_ec.rb29
-rw-r--r--test/openssl/test_pkey_rsa.rb251
-rw-r--r--test/openssl/test_provider.rb83
-rw-r--r--test/openssl/test_ssl.rb95
-rw-r--r--test/openssl/test_ssl_session.rb2
-rw-r--r--test/openssl/test_ts.rb2
-rw-r--r--test/openssl/test_x509attr.rb4
-rw-r--r--test/openssl/test_x509cert.rb32
-rw-r--r--test/openssl/test_x509ext.rb37
-rw-r--r--test/openssl/ut_eof.rb4
-rw-r--r--test/openssl/utils.rb57
-rw-r--r--test/optparse/test_acceptable.rb7
-rw-r--r--test/optparse/test_getopts.rb16
-rw-r--r--test/optparse/test_optarg.rb16
-rw-r--r--test/optparse/test_optparse.rb101
-rw-r--r--test/optparse/test_placearg.rb20
-rw-r--r--test/optparse/test_reqarg.rb6
-rw-r--r--test/ostruct/test_ostruct.rb19
-rw-r--r--test/pathname/test_pathname.rb14
-rw-r--r--test/prism/api/command_line_test.rb111
-rw-r--r--test/prism/api/dump_test.rb56
-rw-r--r--test/prism/api/lex_test.rb23
-rw-r--r--test/prism/api/parse_comments_test.rb33
-rw-r--r--test/prism/api/parse_stream_test.rb81
-rw-r--r--test/prism/api/parse_success_test.rb16
-rw-r--r--test/prism/api/parse_test.rb150
-rw-r--r--test/prism/bom_test.rb59
-rw-r--r--test/prism/encoding/encodings_test.rb101
-rw-r--r--test/prism/encoding/regular_expression_encoding_test.rb131
-rw-r--r--test/prism/encoding/string_encoding_test.rb136
-rw-r--r--test/prism/encoding/symbol_encoding_test.rb108
-rw-r--r--test/prism/errors/1_2_3.txt11
-rw-r--r--test/prism/errors/aliasing_global_variable_with_global_number_variable.txt3
-rw-r--r--test/prism/errors/aliasing_global_variable_with_non_global_variable.txt3
-rw-r--r--test/prism/errors/aliasing_non_global_variable_with_global_variable.txt3
-rw-r--r--test/prism/errors/alnum_delimiters.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_2.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_3.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_4.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_5.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_6.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_7.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_8.txt3
-rw-r--r--test/prism/errors/alnum_delimiters_9.txt3
-rw-r--r--test/prism/errors/amperand_dot_after_endless_range.txt3
-rw-r--r--test/prism/errors/argument_after_ellipsis.txt3
-rw-r--r--test/prism/errors/argument_forwarding_only_effects_its_own_internals.txt3
-rw-r--r--test/prism/errors/argument_forwarding_when_parent_is_not_forwarding.txt3
-rw-r--r--test/prism/errors/arguments_after_block.txt3
-rw-r--r--test/prism/errors/arguments_binding_power_for_and.txt5
-rw-r--r--test/prism/errors/assign_to_numbered_parameter.txt11
-rw-r--r--test/prism/errors/bad_arguments.txt6
-rw-r--r--test/prism/errors/begin_at_toplevel.txt3
-rw-r--r--test/prism/errors/binary_range_with_left_unary_range.txt7
-rw-r--r--test/prism/errors/block_arg_and_block.txt3
-rw-r--r--test/prism/errors/block_beginning_with_brace_and_ending_with_end.txt6
-rw-r--r--test/prism/errors/break_1.txt4
-rw-r--r--test/prism/errors/break_1_2_3.txt8
-rw-r--r--test/prism/errors/call_with_block_and_write.txt4
-rw-r--r--test/prism/errors/call_with_block_operator_write.txt4
-rw-r--r--test/prism/errors/call_with_block_or_write.txt4
-rw-r--r--test/prism/errors/cannot_assign_to_a_reserved_numbered_parameter.txt14
-rw-r--r--test/prism/errors/case_without_clauses.txt4
-rw-r--r--test/prism/errors/case_without_when_clauses_errors_on_else_clause.txt5
-rw-r--r--test/prism/errors/check_value_expression.txt20
-rw-r--r--test/prism/errors/class_definition_in_method_body.txt3
-rw-r--r--test/prism/errors/class_definition_in_method_defs.txt7
-rw-r--r--test/prism/errors/class_name.txt3
-rw-r--r--test/prism/errors/command_call_in.txt5
-rw-r--r--test/prism/errors/command_calls.txt3
-rw-r--r--test/prism/errors/command_calls_10.txt3
-rw-r--r--test/prism/errors/command_calls_11.txt3
-rw-r--r--test/prism/errors/command_calls_12.txt3
-rw-r--r--test/prism/errors/command_calls_13.txt3
-rw-r--r--test/prism/errors/command_calls_14.txt3
-rw-r--r--test/prism/errors/command_calls_15.txt3
-rw-r--r--test/prism/errors/command_calls_16.txt3
-rw-r--r--test/prism/errors/command_calls_17.txt5
-rw-r--r--test/prism/errors/command_calls_18.txt3
-rw-r--r--test/prism/errors/command_calls_19.txt3
-rw-r--r--test/prism/errors/command_calls_2.txt6
-rw-r--r--test/prism/errors/command_calls_20.txt3
-rw-r--r--test/prism/errors/command_calls_21.txt5
-rw-r--r--test/prism/errors/command_calls_22.txt3
-rw-r--r--test/prism/errors/command_calls_23.txt3
-rw-r--r--test/prism/errors/command_calls_24.txt5
-rw-r--r--test/prism/errors/command_calls_25.txt8
-rw-r--r--test/prism/errors/command_calls_26.txt3
-rw-r--r--test/prism/errors/command_calls_27.txt3
-rw-r--r--test/prism/errors/command_calls_28.txt3
-rw-r--r--test/prism/errors/command_calls_29.txt3
-rw-r--r--test/prism/errors/command_calls_3.txt3
-rw-r--r--test/prism/errors/command_calls_30.txt3
-rw-r--r--test/prism/errors/command_calls_4.txt3
-rw-r--r--test/prism/errors/command_calls_5.txt3
-rw-r--r--test/prism/errors/command_calls_6.txt6
-rw-r--r--test/prism/errors/command_calls_7.txt6
-rw-r--r--test/prism/errors/command_calls_8.txt6
-rw-r--r--test/prism/errors/command_calls_9.txt6
-rw-r--r--test/prism/errors/conditional_predicate_closed.txt6
-rw-r--r--test/prism/errors/constant_assignment_in_method.txt3
-rw-r--r--test/prism/errors/constant_path_with_invalid_token_after.txt4
-rw-r--r--test/prism/errors/content_after_unterminated_heredoc.txt4
-rw-r--r--test/prism/errors/cr_without_lf_in_percent_expression.txt3
-rw-r--r--test/prism/errors/def_with_empty_expression_receiver.txt3
-rw-r--r--test/prism/errors/def_with_expression_receiver_and_no_identifier.txt4
-rw-r--r--test/prism/errors/def_with_multiple_statements_receiver.txt10
-rw-r--r--test/prism/errors/defining_numbered_parameter.txt3
-rw-r--r--test/prism/errors/defining_numbered_parameter_2.txt3
-rw-r--r--test/prism/errors/do_not_allow_characters_other_than_0_9_a_f_and_A_F_in_u_Unicode_character_notation.txt4
-rw-r--r--test/prism/errors/do_not_allow_forward_arguments_in_blocks.txt3
-rw-r--r--test/prism/errors/do_not_allow_forward_arguments_in_lambda_literals.txt3
-rw-r--r--test/prism/errors/do_not_allow_more_than_6_hexadecimal_digits_in_u_Unicode_character_notation.txt3
-rw-r--r--test/prism/errors/do_not_allow_multiple_codepoints_in_a_single_character_literal.txt3
-rw-r--r--test/prism/errors/do_not_allow_trailing_commas_in_lambda_parameters.txt3
-rw-r--r--test/prism/errors/do_not_allow_trailing_commas_in_method_parameters.txt3
-rw-r--r--test/prism/errors/dont_allow_return_inside_class_body.txt3
-rw-r--r--test/prism/errors/dont_allow_return_inside_module_body.txt3
-rw-r--r--test/prism/errors/dont_allow_return_inside_sclass_body.txt3
-rw-r--r--test/prism/errors/dont_allow_setting_to_back_and_nth_reference.txt7
-rw-r--r--test/prism/errors/double_arguments_forwarding.txt4
-rw-r--r--test/prism/errors/double_scope_numbered_parameters.txt3
-rw-r--r--test/prism/errors/double_splat_followed_by_splat_argument.txt3
-rw-r--r--test/prism/errors/duplicate_pattern_capture.txt17
-rw-r--r--test/prism/errors/duplicate_pattern_hash_key.txt4
-rw-r--r--test/prism/errors/duplicate_pattern_hash_key_2.txt3
-rw-r--r--test/prism/errors/duplicated_parameter_names.txt3
-rw-r--r--test/prism/errors/duplicated_parameter_names_2.txt3
-rw-r--r--test/prism/errors/duplicated_parameter_names_3.txt3
-rw-r--r--test/prism/errors/duplicated_parameter_names_4.txt3
-rw-r--r--test/prism/errors/duplicated_parameter_names_5.txt3
-rw-r--r--test/prism/errors/dynamic_label_pattern.txt3
-rw-r--r--test/prism/errors/ellipsis_in_no_paren_call.txt3
-rw-r--r--test/prism/errors/for_loop_delimiter.txt3
-rw-r--r--test/prism/errors/for_loops_index_missing.txt5
-rw-r--r--test/prism/errors/for_loops_only_end.txt6
-rw-r--r--test/prism/errors/forwarding_arg_after_keyword_rest.txt3
-rw-r--r--test/prism/errors/forwarding_arg_and_block.txt3
-rw-r--r--test/prism/errors/heredoc_unterminated.txt9
-rw-r--r--test/prism/errors/incomplete_instance_var_string.txt4
-rw-r--r--test/prism/errors/index_call_with_block_and_write.txt5
-rw-r--r--test/prism/errors/index_call_with_block_operator_write.txt5
-rw-r--r--test/prism/errors/index_call_with_block_or_write.txt5
-rw-r--r--test/prism/errors/infix_after_label.txt6
-rw-r--r--test/prism/errors/interpolated_regular_expression_with_unknown_regexp_options.txt3
-rw-r--r--test/prism/errors/invalid_global_variable_write.txt4
-rw-r--r--test/prism/errors/invalid_hex_escape.txt3
-rw-r--r--test/prism/errors/invalid_multi_target.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_10.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_11.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_12.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_13.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_14.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_15.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_16.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_17.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_18.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_19.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_2.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_20.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_3.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_4.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_5.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_6.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_7.txt3
-rw-r--r--test/prism/errors/invalid_multi_target_8.txt4
-rw-r--r--test/prism/errors/invalid_multi_target_9.txt4
-rw-r--r--test/prism/errors/invalid_number_underscores.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_10.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_11.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_12.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_2.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_3.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_4.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_5.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_6.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_7.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_8.txt3
-rw-r--r--test/prism/errors/invalid_number_underscores_9.txt3
-rw-r--r--test/prism/errors/invalid_operator_write_dot.txt3
-rw-r--r--test/prism/errors/invalid_operator_write_fcall.txt3
-rw-r--r--test/prism/errors/it_with_ordinary_parameter.txt3
-rw-r--r--test/prism/errors/keywords_parameters_before_required_parameters.txt4
-rw-r--r--test/prism/errors/label_in_parentheses.txt3
-rw-r--r--test/prism/errors/loop_conditional_is_closed.txt4
-rw-r--r--test/prism/errors/match_plus.txt7
-rw-r--r--test/prism/errors/method_parameters_after_arguments_forwarding.txt4
-rw-r--r--test/prism/errors/method_parameters_after_block.txt4
-rw-r--r--test/prism/errors/method_with_arguments_after_anonymous_block.txt4
-rw-r--r--test/prism/errors/missing_terminator_in_parentheses.txt3
-rw-r--r--test/prism/errors/module_definition_in_method_body.txt3
-rw-r--r--test/prism/errors/module_definition_in_method_body_within_block.txt7
-rw-r--r--test/prism/errors/module_definition_in_method_defs.txt7
-rw-r--r--test/prism/errors/module_name_recoverable.txt4
-rw-r--r--test/prism/errors/multi_target_parens.txt19
-rw-r--r--test/prism/errors/multi_target_star.txt17
-rw-r--r--test/prism/errors/multiple_error_in_parameters_order.txt5
-rw-r--r--test/prism/errors/next_1.txt4
-rw-r--r--test/prism/errors/next_1_2_3.txt8
-rw-r--r--test/prism/errors/non_assoc_equality.txt19
-rw-r--r--test/prism/errors/non_assoc_range.txt5
-rw-r--r--test/prism/errors/numbered_parameters_in_block_arguments.txt3
-rw-r--r--test/prism/errors/optional_block_parameters_with_unary_operator.txt3
-rw-r--r--test/prism/errors/optional_block_parameters_with_unary_operator_2.txt3
-rw-r--r--test/prism/errors/optional_block_parameters_with_unary_operator_3.txt3
-rw-r--r--test/prism/errors/optional_block_parameters_with_unary_operator_4.txt3
-rw-r--r--test/prism/errors/parameter_name_ending_with_bang_or_question_mark.txt4
-rw-r--r--test/prism/errors/pre_execution_context.txt4
-rw-r--r--test/prism/errors/pre_execution_missing_brace.txt3
-rw-r--r--test/prism/errors/range_and_bin_op.txt4
-rw-r--r--test/prism/errors/range_and_bin_op_2.txt4
-rw-r--r--test/prism/errors/range_and_bin_op_3.txt3
-rw-r--r--test/prism/errors/range_and_bin_op_4.txt5
-rw-r--r--test/prism/errors/range_and_bin_op_5.txt6
-rw-r--r--test/prism/errors/range_and_bin_op_6.txt3
-rw-r--r--test/prism/errors/range_and_bin_op_7.txt3
-rw-r--r--test/prism/errors/range_and_bin_op_8.txt4
-rw-r--r--test/prism/errors/range_doubled.txt3
-rw-r--r--test/prism/errors/rational_number_with_exponential_portion.txt4
-rw-r--r--test/prism/errors/regexp_unicode_too_short.txt4
-rw-r--r--test/prism/errors/regular_expression_with_unknown_regexp_options.txt3
-rw-r--r--test/prism/errors/repeated_parameter_name_in_destructured_params.txt3
-rw-r--r--test/prism/errors/rest_keywords_parameters_before_required_parameters.txt4
-rw-r--r--test/prism/errors/return_1.txt3
-rw-r--r--test/prism/errors/return_1_2_3.txt7
-rw-r--r--test/prism/errors/returning_to_optional_parameters_multiple_times.txt4
-rw-r--r--test/prism/errors/semicolon_after_inheritance_operator.txt3
-rw-r--r--test/prism/errors/setter_method_cannot_be_defined_in_an_endless_method_definition.txt3
-rw-r--r--test/prism/errors/shadow_args_in_block.txt3
-rw-r--r--test/prism/errors/shadow_args_in_lambda.txt5
-rw-r--r--test/prism/errors/singleton_class_delimiter.txt3
-rw-r--r--test/prism/errors/singleton_method_for_literals.txt39
-rw-r--r--test/prism/errors/splat_argument_after_keyword_argument.txt3
-rw-r--r--test/prism/errors/statement_at_non_statement.txt9
-rw-r--r--test/prism/errors/statement_operators.txt25
-rw-r--r--test/prism/errors/switching_to_named_arguments_twice.txt5
-rw-r--r--test/prism/errors/switching_to_optional_arguments_twice.txt5
-rw-r--r--test/prism/errors/symbol_in_hash.txt3
-rw-r--r--test/prism/errors/symbol_in_keyword_parameter.txt3
-rw-r--r--test/prism/errors/targeting_numbered_parameter.txt3
-rw-r--r--test/prism/errors/top_level_constant_starting_with_downcased_identifier.txt4
-rw-r--r--test/prism/errors/top_level_constant_with_downcased_identifier.txt4
-rw-r--r--test/prism/errors/trailing_comma_after_block.txt3
-rw-r--r--test/prism/errors/trailing_comma_in_calls.txt3
-rw-r--r--test/prism/errors/unexpected_block.txt3
-rw-r--r--test/prism/errors/unterminated_W_list.txt3
-rw-r--r--test/prism/errors/unterminated_argument_expression.txt5
-rw-r--r--test/prism/errors/unterminated_embdoc.txt3
-rw-r--r--test/prism/errors/unterminated_embdoc_2.txt3
-rw-r--r--test/prism/errors/unterminated_empty_string.txt3
-rw-r--r--test/prism/errors/unterminated_global_variable.txt3
-rw-r--r--test/prism/errors/unterminated_global_variable_2.txt3
-rw-r--r--test/prism/errors/unterminated_i_list.txt3
-rw-r--r--test/prism/errors/unterminated_interpolated_string.txt3
-rw-r--r--test/prism/errors/unterminated_interpolated_symbol.txt3
-rw-r--r--test/prism/errors/unterminated_parenthesized_expression.txt4
-rw-r--r--test/prism/errors/unterminated_regular_expression.txt3
-rw-r--r--test/prism/errors/unterminated_regular_expression_with_heredoc.txt4
-rw-r--r--test/prism/errors/unterminated_s_symbol.txt3
-rw-r--r--test/prism/errors/unterminated_string.txt3
-rw-r--r--test/prism/errors/unterminated_unicode_brackets_should_be_a_syntax_error.txt3
-rw-r--r--test/prism/errors/unterminated_xstring.txt3
-rw-r--r--test/prism/errors/void_value_expression_in_arguments.txt17
-rw-r--r--test/prism/errors/void_value_expression_in_array.txt15
-rw-r--r--test/prism/errors/void_value_expression_in_assignment.txt9
-rw-r--r--test/prism/errors/void_value_expression_in_begin_statement.txt21
-rw-r--r--test/prism/errors/void_value_expression_in_binary_call.txt11
-rw-r--r--test/prism/errors/void_value_expression_in_call.txt11
-rw-r--r--test/prism/errors/void_value_expression_in_constant_path.txt5
-rw-r--r--test/prism/errors/void_value_expression_in_def.txt10
-rw-r--r--test/prism/errors/void_value_expression_in_expression.txt19
-rw-r--r--test/prism/errors/void_value_expression_in_hash.txt9
-rw-r--r--test/prism/errors/void_value_expression_in_modifier.txt13
-rw-r--r--test/prism/errors/void_value_expression_in_statement.txt26
-rw-r--r--test/prism/errors/void_value_expression_in_unary_call.txt5
-rw-r--r--test/prism/errors/while_endless_method.txt5
-rw-r--r--test/prism/errors/writing_numbered_parameter.txt3
-rw-r--r--test/prism/errors_test.rb101
-rw-r--r--test/prism/fixtures/alias.txt23
-rw-r--r--test/prism/fixtures/arithmetic.txt13
-rw-r--r--test/prism/fixtures/arrays.txt122
-rw-r--r--test/prism/fixtures/begin_ensure.txt21
-rw-r--r--test/prism/fixtures/begin_rescue.txt79
-rw-r--r--test/prism/fixtures/blocks.txt54
-rw-r--r--test/prism/fixtures/boolean_operators.txt5
-rw-r--r--test/prism/fixtures/booleans.txt3
-rw-r--r--test/prism/fixtures/break.txt29
-rw-r--r--test/prism/fixtures/case.txt55
-rw-r--r--test/prism/fixtures/classes.txt35
-rw-r--r--test/prism/fixtures/command_method_call.txt41
-rw-r--r--test/prism/fixtures/comments.txt24
-rw-r--r--test/prism/fixtures/constants.txt184
-rw-r--r--test/prism/fixtures/dash_heredocs.txt63
-rw-r--r--test/prism/fixtures/defined.txt10
-rw-r--r--test/prism/fixtures/dos_endings.txt20
-rw-r--r--test/prism/fixtures/dstring.txt29
-rw-r--r--test/prism/fixtures/dsym_str.txt2
-rw-r--r--test/prism/fixtures/embdoc_no_newline_at_end.txt2
-rw-r--r--test/prism/fixtures/emoji_method_calls.txt1
-rw-r--r--test/prism/fixtures/endless_methods.txt5
-rw-r--r--test/prism/fixtures/endless_range_in_conditional.txt3
-rw-r--r--test/prism/fixtures/for.txt19
-rw-r--r--test/prism/fixtures/global_variables.txt93
-rw-r--r--test/prism/fixtures/hashes.txt28
-rw-r--r--test/prism/fixtures/heredoc.txt2
-rw-r--r--test/prism/fixtures/heredoc_with_carriage_returns.txt2
-rw-r--r--test/prism/fixtures/heredoc_with_comment.txt3
-rw-r--r--test/prism/fixtures/heredoc_with_escaped_newline_at_start.txt7
-rw-r--r--test/prism/fixtures/heredoc_with_trailing_newline.txt2
-rw-r--r--test/prism/fixtures/heredocs_leading_whitespace.txt29
-rw-r--r--test/prism/fixtures/heredocs_nested.txt22
-rw-r--r--test/prism/fixtures/heredocs_with_ignored_newlines.txt14
-rw-r--r--test/prism/fixtures/heredocs_with_ignored_newlines_and_non_empty.txt4
-rw-r--r--test/prism/fixtures/if.txt42
-rw-r--r--test/prism/fixtures/indented_file_end.txt4
-rw-r--r--test/prism/fixtures/integer_operations.txt63
-rw-r--r--test/prism/fixtures/keyword_method_names.txt29
-rw-r--r--test/prism/fixtures/keywords.txt11
-rw-r--r--test/prism/fixtures/lambda.txt11
-rw-r--r--test/prism/fixtures/method_calls.txt156
-rw-r--r--test/prism/fixtures/methods.txt188
-rw-r--r--test/prism/fixtures/modules.txt18
-rw-r--r--test/prism/fixtures/multi_write.txt4
-rw-r--r--test/prism/fixtures/newline_terminated.txtbin212 -> 0 bytes-rw-r--r--test/prism/fixtures/next.txt24
-rw-r--r--test/prism/fixtures/nils.txt13
-rw-r--r--test/prism/fixtures/non_alphanumeric_methods.txt105
-rw-r--r--test/prism/fixtures/not.txt37
-rw-r--r--test/prism/fixtures/numbers.txt67
-rw-r--r--test/prism/fixtures/patterns.txt214
-rw-r--r--test/prism/fixtures/procs.txt27
-rw-r--r--test/prism/fixtures/range_begin_open_exclusive.txt1
-rw-r--r--test/prism/fixtures/range_begin_open_inclusive.txt1
-rw-r--r--test/prism/fixtures/range_beginless.txt5
-rw-r--r--test/prism/fixtures/range_end_open_exclusive.txt1
-rw-r--r--test/prism/fixtures/range_end_open_inclusive.txt1
-rw-r--r--test/prism/fixtures/ranges.txt49
-rw-r--r--test/prism/fixtures/regex.txt48
-rw-r--r--test/prism/fixtures/regex_char_width.txt3
-rw-r--r--test/prism/fixtures/regex_escape_encoding.txt3
-rw-r--r--test/prism/fixtures/repeat_parameters.txt38
-rw-r--r--test/prism/fixtures/rescue.txt35
-rw-r--r--test/prism/fixtures/return.txt24
-rw-r--r--test/prism/fixtures/seattlerb/BEGIN.txt1
-rw-r--r--test/prism/fixtures/seattlerb/README.rdoc113
-rw-r--r--test/prism/fixtures/seattlerb/TestRubyParserShared.txt92
-rw-r--r--test/prism/fixtures/seattlerb/__ENCODING__.txt1
-rw-r--r--test/prism/fixtures/seattlerb/alias_gvar_backref.txt1
-rw-r--r--test/prism/fixtures/seattlerb/alias_resword.txt1
-rw-r--r--test/prism/fixtures/seattlerb/and_multi.txt3
-rw-r--r--test/prism/fixtures/seattlerb/aref_args_assocs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/aref_args_lit_assocs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/args_kw_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/array_line_breaks.txt4
-rw-r--r--test/prism/fixtures/seattlerb/array_lits_trailing_calls.txt3
-rw-r--r--test/prism/fixtures/seattlerb/assoc__bare.txt1
-rw-r--r--test/prism/fixtures/seattlerb/assoc_label.txt1
-rw-r--r--test/prism/fixtures/seattlerb/attr_asgn_colon_id.txt1
-rw-r--r--test/prism/fixtures/seattlerb/attrasgn_array_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/attrasgn_array_lhs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/attrasgn_primary_dot_constant.txt1
-rw-r--r--test/prism/fixtures/seattlerb/backticks_interpolation_line.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bang_eq.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bdot2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bdot3.txt3
-rw-r--r--test/prism/fixtures/seattlerb/begin_ensure_no_bodies.txt3
-rw-r--r--test/prism/fixtures/seattlerb/begin_rescue_else_ensure_bodies.txt9
-rw-r--r--test/prism/fixtures/seattlerb/begin_rescue_else_ensure_no_bodies.txt9
-rw-r--r--test/prism/fixtures/seattlerb/begin_rescue_ensure_no_bodies.txt4
-rw-r--r--test/prism/fixtures/seattlerb/block_arg__bare.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_opt_arg_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_opt_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_opt_splat_arg_block_omfg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_optional.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_scope.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_scope2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_arg_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_kwargs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_no_kwargs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_opt1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_opt2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_opt2_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_args_opt3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_defn_call_block_call.txt4
-rw-r--r--test/prism/fixtures/seattlerb/block_call_dot_op2_brace_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_dot_op2_cmd_args_do_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_operation_colon.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_operation_dot.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_call_paren_call_block_call.txt2
-rw-r--r--test/prism/fixtures/seattlerb/block_command_operation_colon.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_command_operation_dot.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_decomp_anon_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_decomp_arg_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_decomp_arg_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_decomp_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_kw.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_kw__required.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_kwarg_lvar.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_kwarg_lvar_multiple.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_opt_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_opt_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_opt_splat_arg_block_omfg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_optarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_paren_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_reg_optarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_return.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_scope.txt1
-rw-r--r--test/prism/fixtures/seattlerb/block_splat_reg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug169.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug179.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug190.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug191.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bug202.txt2
-rw-r--r--test/prism/fixtures/seattlerb/bug236.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bug290.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bug_187.txt3
-rw-r--r--test/prism/fixtures/seattlerb/bug_215.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_249.txt4
-rw-r--r--test/prism/fixtures/seattlerb/bug_and.txt4
-rw-r--r--test/prism/fixtures/seattlerb/bug_args__19.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_args_masgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_args_masgn2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_args_masgn_outer_parens__19.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_call_arglist_parens.txt11
-rw-r--r--test/prism/fixtures/seattlerb/bug_case_when_regexp.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_cond_pct.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_hash_args.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_hash_args_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_hash_interp_array.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_masgn_right.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_not_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/bug_op_asgn_rescue.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_and.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_arg_assoc.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_arg_assoc_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_arg_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_args_assoc_quoted.txt5
-rw-r--r--test/prism/fixtures/seattlerb/call_args_assoc_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_args_command.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_array_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_array_block_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_array_lambda_block_call.txt2
-rw-r--r--test/prism/fixtures/seattlerb/call_array_lit_inline_hash.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_assoc.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_assoc_new.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_assoc_new_if_multiline.txt5
-rw-r--r--test/prism/fixtures/seattlerb/call_assoc_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_bang_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_bang_squiggle.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_begin_call_block_call.txt3
-rw-r--r--test/prism/fixtures/seattlerb/call_block_arg_named.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_carat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_colon2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_colon_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_div.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_dot_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_env.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_eq3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_gt.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_leading_dots.txt3
-rw-r--r--test/prism/fixtures/seattlerb/call_leading_dots_comment.txt4
-rw-r--r--test/prism/fixtures/seattlerb/call_lt.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_lte.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_not.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_pipe.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_rshift.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_self_brackets.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_spaceship.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_stabby_do_end_with_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_stabby_with_braces_block.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_star.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_star2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/call_trailing_dots.txt3
-rw-r--r--test/prism/fixtures/seattlerb/call_unary_bang.txt1
-rw-r--r--test/prism/fixtures/seattlerb/case_in.txt111
-rw-r--r--test/prism/fixtures/seattlerb/case_in_31.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_37.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_42.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_42_2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_47.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_67.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_86.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_86_2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_array_pat_const.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_array_pat_const2.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_array_pat_paren_assign.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_const.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_else.txt7
-rw-r--r--test/prism/fixtures/seattlerb/case_in_find.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_find_array.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat.txt5
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_assign.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_paren_assign.txt4
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_paren_true.txt5
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_rest.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_hash_pat_rest_solo.txt3
-rw-r--r--test/prism/fixtures/seattlerb/case_in_if_unless_post_mod.txt6
-rw-r--r--test/prism/fixtures/seattlerb/case_in_multiple.txt6
-rw-r--r--test/prism/fixtures/seattlerb/case_in_or.txt5
-rw-r--r--test/prism/fixtures/seattlerb/class_comments.txt9
-rw-r--r--test/prism/fixtures/seattlerb/cond_unary_minus.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_2_op_asgn_or2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_3_op_asgn_or.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_op_asgn_and1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_op_asgn_and2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/const_op_asgn_or.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defined_eh_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_arg_asplat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_arg_forward_args.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_args_forward_args.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_comments.txt5
-rw-r--r--test/prism/fixtures/seattlerb/defn_endless_command.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_endless_command_rescue.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_forward_args.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_forward_args__no_parens.txt3
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_env.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_kwarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_kwsplat_anon.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_lvar.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_no_parens.txt2
-rw-r--r--test/prism/fixtures/seattlerb/defn_kwarg_val.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_no_kwargs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner_eq2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner_noargs.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner_noargs_parentheses.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_oneliner_rescue.txt13
-rw-r--r--test/prism/fixtures/seattlerb/defn_opt_last_arg.txt2
-rw-r--r--test/prism/fixtures/seattlerb/defn_opt_reg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_opt_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_powarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_reg_opt_reg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defn_unary_not.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defns_reserved.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_as_arg_with_do_block_inside.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_comments.txt5
-rw-r--r--test/prism/fixtures/seattlerb/defs_endless_command.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_endless_command_rescue.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_kwarg.txt2
-rw-r--r--test/prism/fixtures/seattlerb/defs_oneliner.txt1
-rw-r--r--test/prism/fixtures/seattlerb/defs_oneliner_eq2.txt3
-rw-r--r--test/prism/fixtures/seattlerb/defs_oneliner_rescue.txt13
-rw-r--r--test/prism/fixtures/seattlerb/difficult0_.txt4
-rw-r--r--test/prism/fixtures/seattlerb/difficult1_line_numbers.txt13
-rw-r--r--test/prism/fixtures/seattlerb/difficult1_line_numbers2.txt8
-rw-r--r--test/prism/fixtures/seattlerb/difficult2_.txt2
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_4.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3_5.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__10.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__11.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__12.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__6.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__7.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__8.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult3__9.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult4__leading_dots.txt2
-rw-r--r--test/prism/fixtures/seattlerb/difficult4__leading_dots2.txt2
-rw-r--r--test/prism/fixtures/seattlerb/difficult6_.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult6__7.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult6__8.txt1
-rw-r--r--test/prism/fixtures/seattlerb/difficult7_.txt5
-rw-r--r--test/prism/fixtures/seattlerb/do_bug.txt4
-rw-r--r--test/prism/fixtures/seattlerb/do_lambda.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dot2_nil__26.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dot3_nil__26.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dstr_evstr.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dstr_evstr_empty_end.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dstr_lex_state.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dstr_str.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dsym_esc_to_sym.txt1
-rw-r--r--test/prism/fixtures/seattlerb/dsym_to_sym.txt3
-rw-r--r--test/prism/fixtures/seattlerb/eq_begin_line_numbers.txt6
-rw-r--r--test/prism/fixtures/seattlerb/eq_begin_why_wont_people_use_their_spacebar.txt3
-rw-r--r--test/prism/fixtures/seattlerb/evstr_evstr.txt1
-rw-r--r--test/prism/fixtures/seattlerb/evstr_str.txt1
-rw-r--r--test/prism/fixtures/seattlerb/expr_not_bang.txt1
-rw-r--r--test/prism/fixtures/seattlerb/f_kw.txt1
-rw-r--r--test/prism/fixtures/seattlerb/f_kw__required.txt1
-rw-r--r--test/prism/fixtures/seattlerb/flip2_env_lvar.txt1
-rw-r--r--test/prism/fixtures/seattlerb/float_with_if_modifier.txt1
-rw-r--r--test/prism/fixtures/seattlerb/heredoc__backslash_dos_format.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_backslash_nl.txt8
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_bad_hex_escape.txt3
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_bad_oct_escape.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_comma_arg.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_lineno.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_nested.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_blank_line_plus_interpolation.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_blank_lines.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_empty.txt2
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_interp.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_no_indent.txt3
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_tabs.txt6
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_tabs_extra.txt6
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_squiggly_visually_blank_lines.txt7
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_trailing_slash_continued_call.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_unicode.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_carriage_return_escapes.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_carriage_return_escapes_windows.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_horrible_mix.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_returns.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_extra_carriage_returns_windows.txt5
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_interpolation_and_carriage_return_escapes_windows.txt4
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_not_global_interpolation.txt3
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_only_carriage_returns.txt6
-rw-r--r--test/prism/fixtures/seattlerb/heredoc_with_only_carriage_returns_windows.txt6
-rw-r--r--test/prism/fixtures/seattlerb/if_elsif.txt1
-rw-r--r--test/prism/fixtures/seattlerb/if_symbol.txt1
-rw-r--r--test/prism/fixtures/seattlerb/in_expr_no_case.txt1
-rw-r--r--test/prism/fixtures/seattlerb/index_0.txt1
-rw-r--r--test/prism/fixtures/seattlerb/index_0_opasgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/integer_with_if_modifier.txt1
-rw-r--r--test/prism/fixtures/seattlerb/interpolated_symbol_array_line_breaks.txt5
-rw-r--r--test/prism/fixtures/seattlerb/interpolated_word_array_line_breaks.txt5
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_10_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_10_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_11_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_11_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_2__19.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_4.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_5.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_6.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_7_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_7_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_8_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_8_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_9_1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_args_9_2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_kwarg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/iter_kwarg_kwsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/label_vs_string.txt2
-rw-r--r--test/prism/fixtures/seattlerb/lambda_do_vs_brace.txt7
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_arg_rescue_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_call_bracket_rescue_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_call_nobracket_rescue_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_command.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_env.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_ivar_env.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_lasgn_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/lasgn_middle_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/magic_encoding_comment.txt4
-rw-r--r--test/prism/fixtures/seattlerb/masgn_anon_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_arg_colon_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_arg_ident.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_arg_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_colon2.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_colon3.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_double_paren.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_lhs_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_paren.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_splat_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_splat_arg_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_star.txt1
-rw-r--r--test/prism/fixtures/seattlerb/masgn_var_star_var.txt1
-rw-r--r--test/prism/fixtures/seattlerb/messy_op_asgn_lineno.txt1
-rw-r--r--test/prism/fixtures/seattlerb/method_call_assoc_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/method_call_trailing_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_back_anonsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_back_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_front_anonsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_front_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_keyword.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_mid_anonsplat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_mid_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/mlhs_rescue.txt1
-rw-r--r--test/prism/fixtures/seattlerb/module_comments.txt10
-rw-r--r--test/prism/fixtures/seattlerb/multiline_hash_declaration.txt8
-rw-r--r--test/prism/fixtures/seattlerb/non_interpolated_symbol_array_line_breaks.txt5
-rw-r--r--test/prism/fixtures/seattlerb/non_interpolated_word_array_line_breaks.txt5
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_dot_ident_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_index_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_primary_colon_const_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_primary_colon_identifier1.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_primary_colon_identifier_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/op_asgn_val_dot_ident_command_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_def_special_name.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_if_not_canonical.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_if_not_noncanonical.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_block.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_block_inline_comment.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_block_inline_comment_leading_newlines.txt7
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_block_inline_multiline_comment.txt4
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_call_ivar_arg_no_parens_line_break.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_call_ivar_line_break_paren.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_call_no_args.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_defn_complex.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_defn_no_parens.txt6
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_defn_no_parens_args.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dot2.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dot2_open.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dot3.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dot3_open.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dstr_escaped_newline.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_dstr_soft_newline.txt4
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_evstr_after_break.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_hash_lit.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_heredoc.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_heredoc_evstr.txt4
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_heredoc_hardnewline.txt7
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_heredoc_regexp_chars.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_iter_call_no_parens.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_iter_call_parens.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_multiline_str.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_multiline_str_literal_n.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_newlines.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_op_asgn.txt4
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_postexe.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_preexe.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_rescue.txt8
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_return.txt6
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_str_with_newline_escape.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_to_ary.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_line_trailing_newlines.txt2
-rw-r--r--test/prism/fixtures/seattlerb/parse_opt_call_args_assocs_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_opt_call_args_lit_comma.txt1
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_019.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_044.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_051.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_058.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_058_2.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_069.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_pattern_076.txt5
-rw-r--r--test/prism/fixtures/seattlerb/parse_until_not_canonical.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_until_not_noncanonical.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_while_not_canonical.txt3
-rw-r--r--test/prism/fixtures/seattlerb/parse_while_not_noncanonical.txt3
-rw-r--r--test/prism/fixtures/seattlerb/pctW_lineno.txt5
-rw-r--r--test/prism/fixtures/seattlerb/pct_Q_backslash_nl.txt2
-rw-r--r--test/prism/fixtures/seattlerb/pct_nl.txt3
-rw-r--r--test/prism/fixtures/seattlerb/pct_w_heredoc_interp_nested.txt4
-rw-r--r--test/prism/fixtures/seattlerb/pipe_semicolon.txt1
-rw-r--r--test/prism/fixtures/seattlerb/pipe_space.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qWords_space.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qsymbols.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qsymbols_empty.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qsymbols_empty_space.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qsymbols_interp.txt1
-rw-r--r--test/prism/fixtures/seattlerb/quoted_symbol_hash_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/quoted_symbol_keys.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qw_escape.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qw_escape_term.txt1
-rw-r--r--test/prism/fixtures/seattlerb/qwords_empty.txt1
-rw-r--r--test/prism/fixtures/seattlerb/read_escape_unicode_curlies.txt1
-rw-r--r--test/prism/fixtures/seattlerb/read_escape_unicode_h4.txt1
-rw-r--r--test/prism/fixtures/seattlerb/regexp.txt9
-rw-r--r--test/prism/fixtures/seattlerb/regexp_esc_C_slash.txt1
-rw-r--r--test/prism/fixtures/seattlerb/regexp_esc_u.txt1
-rw-r--r--test/prism/fixtures/seattlerb/regexp_escape_extended.txt1
-rw-r--r--test/prism/fixtures/seattlerb/regexp_unicode_curlies.txt3
-rw-r--r--test/prism/fixtures/seattlerb/required_kwarg_no_value.txt2
-rw-r--r--test/prism/fixtures/seattlerb/rescue_do_end_ensure_result.txt5
-rw-r--r--test/prism/fixtures/seattlerb/rescue_do_end_no_raise.txt9
-rw-r--r--test/prism/fixtures/seattlerb/rescue_do_end_raised.txt5
-rw-r--r--test/prism/fixtures/seattlerb/rescue_do_end_rescued.txt9
-rw-r--r--test/prism/fixtures/seattlerb/rescue_in_block.txt4
-rw-r--r--test/prism/fixtures/seattlerb/rescue_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/return_call_assocs.txt11
-rw-r--r--test/prism/fixtures/seattlerb/rhs_asgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/ruby21_numbers.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_attrasgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_attrasgn_constant.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_call.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_after_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_dot_parens.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_operator.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_call_rhs_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/safe_calls.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_op_asgn.txt1
-rw-r--r--test/prism/fixtures/seattlerb/safe_op_asgn2.txt2
-rw-r--r--test/prism/fixtures/seattlerb/slashy_newlines_within_string.txt7
-rw-r--r--test/prism/fixtures/seattlerb/stabby_arg_no_paren.txt1
-rw-r--r--test/prism/fixtures/seattlerb/stabby_arg_opt_splat_arg_block_omfg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/stabby_block_iter_call.txt4
-rw-r--r--test/prism/fixtures/seattlerb/stabby_block_iter_call_no_target_with_arg.txt4
-rw-r--r--test/prism/fixtures/seattlerb/stabby_block_kw.txt1
-rw-r--r--test/prism/fixtures/seattlerb/stabby_block_kw__required.txt1
-rw-r--r--test/prism/fixtures/seattlerb/stabby_proc_scope.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_backslashes.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_double_double_escaped_newline.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_double_escaped_newline.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_double_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/str_evstr.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_evstr_escape.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_heredoc_interp.txt5
-rw-r--r--test/prism/fixtures/seattlerb/str_interp_ternary_or_label.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_lit_concat_bad_encodings.txt2
-rw-r--r--test/prism/fixtures/seattlerb/str_newline_hash_line_number.txt2
-rw-r--r--test/prism/fixtures/seattlerb/str_pct_Q_nested.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_pct_nested_nested.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_pct_q.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_single_double_escaped_newline.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_single_escaped_newline.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_single_newline.txt2
-rw-r--r--test/prism/fixtures/seattlerb/str_str.txt1
-rw-r--r--test/prism/fixtures/seattlerb/str_str_str.txt1
-rw-r--r--test/prism/fixtures/seattlerb/super_arg.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbol_empty.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbol_list.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbols.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbols_empty.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbols_empty_space.txt1
-rw-r--r--test/prism/fixtures/seattlerb/symbols_interp.txt1
-rw-r--r--test/prism/fixtures/seattlerb/thingy.txt3
-rw-r--r--test/prism/fixtures/seattlerb/uminus_float.txt1
-rw-r--r--test/prism/fixtures/seattlerb/unary_minus.txt1
-rw-r--r--test/prism/fixtures/seattlerb/unary_plus.txt1
-rw-r--r--test/prism/fixtures/seattlerb/unary_plus_on_literal.txt1
-rw-r--r--test/prism/fixtures/seattlerb/unary_tilde.txt1
-rw-r--r--test/prism/fixtures/seattlerb/utf8_bom.txt3
-rw-r--r--test/prism/fixtures/seattlerb/when_splat.txt1
-rw-r--r--test/prism/fixtures/seattlerb/words_interp.txt1
-rw-r--r--test/prism/fixtures/single_method_call_with_bang.txt1
-rw-r--r--test/prism/fixtures/single_quote_heredocs.txt3
-rw-r--r--test/prism/fixtures/spanning_heredoc.txt63
-rw-r--r--test/prism/fixtures/spanning_heredoc_newlines.txt23
-rw-r--r--test/prism/fixtures/strings.txt105
-rw-r--r--test/prism/fixtures/super.txt17
-rw-r--r--test/prism/fixtures/symbols.txt93
-rw-r--r--test/prism/fixtures/ternary_operator.txt15
-rw-r--r--test/prism/fixtures/tilde_heredocs.txt97
-rw-r--r--test/prism/fixtures/undef.txt17
-rw-r--r--test/prism/fixtures/unescaping.txt9
-rw-r--r--test/prism/fixtures/unless.txt14
-rw-r--r--test/prism/fixtures/unparser/LICENSE20
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/alias.txt2
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/assignment.txt53
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/block.txt96
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/case.txt37
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/class.txt35
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/def.txt134
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/defined.txt3
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/defs.txt40
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/dstr.txt37
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/empty.txt0
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/empty_begin.txt1
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/flipflop.txt10
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/for.txt12
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/hookexe.txt7
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/if.txt36
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/kwbegin.txt80
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/lambda.txt13
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/literal.txt91
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/module.txt16
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/opasgn.txt24
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/pattern.txt41
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/pragma.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/range.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/rescue.txt3
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/send.txt84
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/since/27.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/since/30.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/since/31.txt7
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/since/32.txt11
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/singletons.txt4
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/super.txt21
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/unary.txt9
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/undef.txt2
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/variables.txt10
-rw-r--r--test/prism/fixtures/unparser/corpus/literal/while.txt73
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/and.txt8
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/block.txt26
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/def.txt7
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/dstr.txt127
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/kwbegin.txt42
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/literal.txt14
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/opasgn.txt1
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/send.txt6
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/undef.txt2
-rw-r--r--test/prism/fixtures/unparser/corpus/semantic/while.txt25
-rw-r--r--test/prism/fixtures/until.txt13
-rw-r--r--test/prism/fixtures/variables.txt47
-rw-r--r--test/prism/fixtures/while.txt23
-rw-r--r--test/prism/fixtures/whitequark/LICENSE25
-rw-r--r--test/prism/fixtures/whitequark/__ENCODING__.txt1
-rw-r--r--test/prism/fixtures/whitequark/__ENCODING___legacy_.txt1
-rw-r--r--test/prism/fixtures/whitequark/alias.txt1
-rw-r--r--test/prism/fixtures/whitequark/alias_gvar.txt3
-rw-r--r--test/prism/fixtures/whitequark/ambiuous_quoted_label_in_ternary_operator.txt1
-rw-r--r--test/prism/fixtures/whitequark/and.txt3
-rw-r--r--test/prism/fixtures/whitequark/and_asgn.txt3
-rw-r--r--test/prism/fixtures/whitequark/and_or_masgn.txt3
-rw-r--r--test/prism/fixtures/whitequark/anonymous_blockarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/arg.txt3
-rw-r--r--test/prism/fixtures/whitequark/arg_duplicate_ignored.txt3
-rw-r--r--test/prism/fixtures/whitequark/arg_label.txt6
-rw-r--r--test/prism/fixtures/whitequark/arg_scope.txt1
-rw-r--r--test/prism/fixtures/whitequark/args.txt63
-rw-r--r--test/prism/fixtures/whitequark/args_args_assocs.txt3
-rw-r--r--test/prism/fixtures/whitequark/args_args_assocs_comma.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_args_comma.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_args_star.txt3
-rw-r--r--test/prism/fixtures/whitequark/args_assocs_comma.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_block_pass.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/args_star.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_assocs.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_plain.txt1
-rw-r--r--test/prism/fixtures/whitequark/array_splat.txt5
-rw-r--r--test/prism/fixtures/whitequark/array_symbols.txt1
-rw-r--r--test/prism/fixtures/whitequark/array_symbols_empty.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_symbols_interp.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_words.txt1
-rw-r--r--test/prism/fixtures/whitequark/array_words_empty.txt3
-rw-r--r--test/prism/fixtures/whitequark/array_words_interp.txt3
-rw-r--r--test/prism/fixtures/whitequark/asgn_cmd.txt3
-rw-r--r--test/prism/fixtures/whitequark/asgn_mrhs.txt5
-rw-r--r--test/prism/fixtures/whitequark/back_ref.txt1
-rw-r--r--test/prism/fixtures/whitequark/bang.txt1
-rw-r--r--test/prism/fixtures/whitequark/bang_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/begin_cmdarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/beginless_erange_after_newline.txt2
-rw-r--r--test/prism/fixtures/whitequark/beginless_irange_after_newline.txt2
-rw-r--r--test/prism/fixtures/whitequark/beginless_range.txt3
-rw-r--r--test/prism/fixtures/whitequark/blockarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/blockargs.txt71
-rw-r--r--test/prism/fixtures/whitequark/bug_435.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_447.txt3
-rw-r--r--test/prism/fixtures/whitequark/bug_452.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_466.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_473.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_480.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_481.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_ascii_8bit_in_literal.txt2
-rw-r--r--test/prism/fixtures/whitequark/bug_cmd_string_lookahead.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_cmdarg.txt5
-rw-r--r--test/prism/fixtures/whitequark/bug_def_no_paren_eql_begin.txt4
-rw-r--r--test/prism/fixtures/whitequark/bug_do_block_in_call_args.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_do_block_in_cmdarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_do_block_in_hash_brace.txt9
-rw-r--r--test/prism/fixtures/whitequark/bug_heredoc_do.txt3
-rw-r--r--test/prism/fixtures/whitequark/bug_interp_single.txt3
-rw-r--r--test/prism/fixtures/whitequark/bug_lambda_leakage.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_regex_verification.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_rescue_empty_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/bug_while_not_parens_do.txt1
-rw-r--r--test/prism/fixtures/whitequark/case_cond.txt1
-rw-r--r--test/prism/fixtures/whitequark/case_cond_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/case_expr.txt1
-rw-r--r--test/prism/fixtures/whitequark/case_expr_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/casgn_scoped.txt1
-rw-r--r--test/prism/fixtures/whitequark/casgn_toplevel.txt1
-rw-r--r--test/prism/fixtures/whitequark/casgn_unscoped.txt1
-rw-r--r--test/prism/fixtures/whitequark/character.txt1
-rw-r--r--test/prism/fixtures/whitequark/class.txt3
-rw-r--r--test/prism/fixtures/whitequark/class_super.txt1
-rw-r--r--test/prism/fixtures/whitequark/class_super_label.txt1
-rw-r--r--test/prism/fixtures/whitequark/comments_before_leading_dot__27.txt19
-rw-r--r--test/prism/fixtures/whitequark/complex.txt7
-rw-r--r--test/prism/fixtures/whitequark/cond_begin.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_begin_masgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_eflipflop.txt3
-rw-r--r--test/prism/fixtures/whitequark/cond_eflipflop_with_beginless_range.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_eflipflop_with_endless_range.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_iflipflop.txt3
-rw-r--r--test/prism/fixtures/whitequark/cond_iflipflop_with_beginless_range.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_iflipflop_with_endless_range.txt1
-rw-r--r--test/prism/fixtures/whitequark/cond_match_current_line.txt3
-rw-r--r--test/prism/fixtures/whitequark/const_op_asgn.txt9
-rw-r--r--test/prism/fixtures/whitequark/const_scoped.txt1
-rw-r--r--test/prism/fixtures/whitequark/const_toplevel.txt1
-rw-r--r--test/prism/fixtures/whitequark/const_unscoped.txt1
-rw-r--r--test/prism/fixtures/whitequark/cpath.txt3
-rw-r--r--test/prism/fixtures/whitequark/cvar.txt1
-rw-r--r--test/prism/fixtures/whitequark/cvasgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/dedenting_heredoc.txt75
-rw-r--r--test/prism/fixtures/whitequark/dedenting_interpolating_heredoc_fake_line_continuation.txt4
-rw-r--r--test/prism/fixtures/whitequark/dedenting_non_interpolating_heredoc_line_continuation.txt4
-rw-r--r--test/prism/fixtures/whitequark/def.txt11
-rw-r--r--test/prism/fixtures/whitequark/defined.txt5
-rw-r--r--test/prism/fixtures/whitequark/defs.txt9
-rw-r--r--test/prism/fixtures/whitequark/empty_stmt.txt1
-rw-r--r--test/prism/fixtures/whitequark/endless_comparison_method.txt11
-rw-r--r--test/prism/fixtures/whitequark/endless_method.txt7
-rw-r--r--test/prism/fixtures/whitequark/endless_method_command_syntax.txt15
-rw-r--r--test/prism/fixtures/whitequark/endless_method_forwarded_args_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/endless_method_with_rescue_mod.txt3
-rw-r--r--test/prism/fixtures/whitequark/endless_method_without_args.txt7
-rw-r--r--test/prism/fixtures/whitequark/ensure.txt1
-rw-r--r--test/prism/fixtures/whitequark/ensure_empty.txt1
-rw-r--r--test/prism/fixtures/whitequark/false.txt1
-rw-r--r--test/prism/fixtures/whitequark/float.txt3
-rw-r--r--test/prism/fixtures/whitequark/for.txt3
-rw-r--r--test/prism/fixtures/whitequark/for_mlhs.txt1
-rw-r--r--test/prism/fixtures/whitequark/forward_arg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forward_arg_with_open_args.txt27
-rw-r--r--test/prism/fixtures/whitequark/forward_args_legacy.txt5
-rw-r--r--test/prism/fixtures/whitequark/forwarded_argument_with_kwrestarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forwarded_argument_with_restarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forwarded_kwrestarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forwarded_kwrestarg_with_additional_kwarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/forwarded_restarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/gvar.txt1
-rw-r--r--test/prism/fixtures/whitequark/gvasgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/hash_empty.txt1
-rw-r--r--test/prism/fixtures/whitequark/hash_hashrocket.txt3
-rw-r--r--test/prism/fixtures/whitequark/hash_kwsplat.txt1
-rw-r--r--test/prism/fixtures/whitequark/hash_label.txt1
-rw-r--r--test/prism/fixtures/whitequark/hash_label_end.txt5
-rw-r--r--test/prism/fixtures/whitequark/hash_pair_value_omission.txt5
-rw-r--r--test/prism/fixtures/whitequark/heredoc.txt14
-rw-r--r--test/prism/fixtures/whitequark/if.txt3
-rw-r--r--test/prism/fixtures/whitequark/if_else.txt3
-rw-r--r--test/prism/fixtures/whitequark/if_elsif.txt1
-rw-r--r--test/prism/fixtures/whitequark/if_masgn__24.txt1
-rw-r--r--test/prism/fixtures/whitequark/if_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/if_nl_then.txt2
-rw-r--r--test/prism/fixtures/whitequark/int.txt5
-rw-r--r--test/prism/fixtures/whitequark/int___LINE__.txt1
-rw-r--r--test/prism/fixtures/whitequark/interp_digit_var.txt87
-rw-r--r--test/prism/fixtures/whitequark/ivar.txt1
-rw-r--r--test/prism/fixtures/whitequark/ivasgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/keyword_argument_omission.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwbegin_compstmt.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwnilarg.txt5
-rw-r--r--test/prism/fixtures/whitequark/kwoptarg.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwoptarg_with_kwrestarg_and_forwarded_args.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwrestarg_named.txt1
-rw-r--r--test/prism/fixtures/whitequark/kwrestarg_unnamed.txt1
-rw-r--r--test/prism/fixtures/whitequark/lbrace_arg_after_command_args.txt1
-rw-r--r--test/prism/fixtures/whitequark/lparenarg_after_lvar__since_25.txt3
-rw-r--r--test/prism/fixtures/whitequark/lvar.txt1
-rw-r--r--test/prism/fixtures/whitequark/lvar_injecting_match.txt1
-rw-r--r--test/prism/fixtures/whitequark/lvasgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/masgn.txt5
-rw-r--r--test/prism/fixtures/whitequark/masgn_attr.txt5
-rw-r--r--test/prism/fixtures/whitequark/masgn_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/masgn_const.txt3
-rw-r--r--test/prism/fixtures/whitequark/masgn_nested.txt3
-rw-r--r--test/prism/fixtures/whitequark/masgn_splat.txt19
-rw-r--r--test/prism/fixtures/whitequark/method_definition_in_while_cond.txt7
-rw-r--r--test/prism/fixtures/whitequark/module.txt1
-rw-r--r--test/prism/fixtures/whitequark/multiple_pattern_matches.txt5
-rw-r--r--test/prism/fixtures/whitequark/newline_in_hash_argument.txt14
-rw-r--r--test/prism/fixtures/whitequark/nil.txt1
-rw-r--r--test/prism/fixtures/whitequark/nil_expression.txt3
-rw-r--r--test/prism/fixtures/whitequark/non_lvar_injecting_match.txt1
-rw-r--r--test/prism/fixtures/whitequark/not.txt5
-rw-r--r--test/prism/fixtures/whitequark/not_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/not_masgn__24.txt1
-rw-r--r--test/prism/fixtures/whitequark/nth_ref.txt1
-rw-r--r--test/prism/fixtures/whitequark/numbered_args_after_27.txt7
-rw-r--r--test/prism/fixtures/whitequark/numparam_outside_block.txt9
-rw-r--r--test/prism/fixtures/whitequark/numparam_ruby_bug_19025.txt1
-rw-r--r--test/prism/fixtures/whitequark/op_asgn.txt5
-rw-r--r--test/prism/fixtures/whitequark/op_asgn_cmd.txt7
-rw-r--r--test/prism/fixtures/whitequark/op_asgn_index.txt1
-rw-r--r--test/prism/fixtures/whitequark/op_asgn_index_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/optarg.txt3
-rw-r--r--test/prism/fixtures/whitequark/or.txt3
-rw-r--r--test/prism/fixtures/whitequark/or_asgn.txt3
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_272.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_490.txt5
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_507.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_518.txt2
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_525.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_604.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_640.txt4
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_645.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_830.txt1
-rw-r--r--test/prism/fixtures/whitequark/parser_bug_989.txt3
-rw-r--r--test/prism/fixtures/whitequark/parser_drops_truncated_parts_of_squiggly_heredoc.txt3
-rw-r--r--test/prism/fixtures/whitequark/parser_slash_slash_n_escaping_in_literals.txt62
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching__FILE__LINE_literals.txt4
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_blank_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_single_line.txt3
-rw-r--r--test/prism/fixtures/whitequark/pattern_matching_single_line_allowed_omission_of_parentheses.txt11
-rw-r--r--test/prism/fixtures/whitequark/postexe.txt1
-rw-r--r--test/prism/fixtures/whitequark/preexe.txt1
-rw-r--r--test/prism/fixtures/whitequark/procarg0.txt3
-rw-r--r--test/prism/fixtures/whitequark/range_exclusive.txt1
-rw-r--r--test/prism/fixtures/whitequark/range_inclusive.txt1
-rw-r--r--test/prism/fixtures/whitequark/rational.txt3
-rw-r--r--test/prism/fixtures/whitequark/regex_interp.txt1
-rw-r--r--test/prism/fixtures/whitequark/regex_plain.txt1
-rw-r--r--test/prism/fixtures/whitequark/resbody_list.txt1
-rw-r--r--test/prism/fixtures/whitequark/resbody_list_mrhs.txt1
-rw-r--r--test/prism/fixtures/whitequark/resbody_list_var.txt1
-rw-r--r--test/prism/fixtures/whitequark/resbody_var.txt3
-rw-r--r--test/prism/fixtures/whitequark/rescue.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_else.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_else_ensure.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_ensure.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_in_lambda_block.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_mod_asgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_mod_masgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_mod_op_assign.txt1
-rw-r--r--test/prism/fixtures/whitequark/rescue_without_begin_end.txt1
-rw-r--r--test/prism/fixtures/whitequark/restarg_named.txt1
-rw-r--r--test/prism/fixtures/whitequark/restarg_unnamed.txt1
-rw-r--r--test/prism/fixtures/whitequark/return.txt7
-rw-r--r--test/prism/fixtures/whitequark/return_block.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_10279.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_10653.txt5
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11107.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11380.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11873.txt23
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11873_a.txt39
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11873_b.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11989.txt3
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_11990.txt3
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_12073.txt3
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_12402.txt27
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_12669.txt7
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_12686.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_13547.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_14690.txt1
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_15789.txt3
-rw-r--r--test/prism/fixtures/whitequark/ruby_bug_9669.txt8
-rw-r--r--test/prism/fixtures/whitequark/sclass.txt1
-rw-r--r--test/prism/fixtures/whitequark/self.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_attr_asgn.txt7
-rw-r--r--test/prism/fixtures/whitequark/send_attr_asgn_conditional.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_binary_op.txt41
-rw-r--r--test/prism/fixtures/whitequark/send_block_chain_cmd.txt13
-rw-r--r--test/prism/fixtures/whitequark/send_block_conditional.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_call.txt3
-rw-r--r--test/prism/fixtures/whitequark/send_conditional.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index_asgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index_asgn_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_index_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_lambda.txt5
-rw-r--r--test/prism/fixtures/whitequark/send_lambda_args.txt3
-rw-r--r--test/prism/fixtures/whitequark/send_lambda_args_noparen.txt3
-rw-r--r--test/prism/fixtures/whitequark/send_lambda_args_shadow.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_lambda_legacy.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_op_asgn_conditional.txt1
-rw-r--r--test/prism/fixtures/whitequark/send_plain.txt5
-rw-r--r--test/prism/fixtures/whitequark/send_plain_cmd.txt5
-rw-r--r--test/prism/fixtures/whitequark/send_self.txt5
-rw-r--r--test/prism/fixtures/whitequark/send_self_block.txt7
-rw-r--r--test/prism/fixtures/whitequark/send_unary_op.txt5
-rw-r--r--test/prism/fixtures/whitequark/slash_newline_in_heredocs.txt13
-rw-r--r--test/prism/fixtures/whitequark/space_args_arg.txt1
-rw-r--r--test/prism/fixtures/whitequark/space_args_arg_block.txt5
-rw-r--r--test/prism/fixtures/whitequark/space_args_arg_call.txt1
-rw-r--r--test/prism/fixtures/whitequark/space_args_arg_newline.txt2
-rw-r--r--test/prism/fixtures/whitequark/space_args_block.txt1
-rw-r--r--test/prism/fixtures/whitequark/space_args_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/string___FILE__.txt1
-rw-r--r--test/prism/fixtures/whitequark/string_concat.txt1
-rw-r--r--test/prism/fixtures/whitequark/string_dvar.txt1
-rw-r--r--test/prism/fixtures/whitequark/string_interp.txt1
-rw-r--r--test/prism/fixtures/whitequark/string_plain.txt3
-rw-r--r--test/prism/fixtures/whitequark/super.txt5
-rw-r--r--test/prism/fixtures/whitequark/super_block.txt3
-rw-r--r--test/prism/fixtures/whitequark/symbol_interp.txt1
-rw-r--r--test/prism/fixtures/whitequark/symbol_plain.txt3
-rw-r--r--test/prism/fixtures/whitequark/ternary.txt1
-rw-r--r--test/prism/fixtures/whitequark/ternary_ambiguous_symbol.txt1
-rw-r--r--test/prism/fixtures/whitequark/trailing_forward_arg.txt1
-rw-r--r--test/prism/fixtures/whitequark/true.txt1
-rw-r--r--test/prism/fixtures/whitequark/unary_num_pow_precedence.txt5
-rw-r--r--test/prism/fixtures/whitequark/undef.txt1
-rw-r--r--test/prism/fixtures/whitequark/unless.txt3
-rw-r--r--test/prism/fixtures/whitequark/unless_else.txt3
-rw-r--r--test/prism/fixtures/whitequark/unless_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/until.txt3
-rw-r--r--test/prism/fixtures/whitequark/until_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/until_post.txt1
-rw-r--r--test/prism/fixtures/whitequark/var_and_asgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/var_op_asgn.txt7
-rw-r--r--test/prism/fixtures/whitequark/var_op_asgn_cmd.txt1
-rw-r--r--test/prism/fixtures/whitequark/var_or_asgn.txt1
-rw-r--r--test/prism/fixtures/whitequark/when_multi.txt1
-rw-r--r--test/prism/fixtures/whitequark/when_splat.txt1
-rw-r--r--test/prism/fixtures/whitequark/when_then.txt1
-rw-r--r--test/prism/fixtures/whitequark/while.txt3
-rw-r--r--test/prism/fixtures/whitequark/while_mod.txt1
-rw-r--r--test/prism/fixtures/whitequark/while_post.txt1
-rw-r--r--test/prism/fixtures/whitequark/xstring_interp.txt1
-rw-r--r--test/prism/fixtures/whitequark/xstring_plain.txt1
-rw-r--r--test/prism/fixtures/whitequark/zsuper.txt1
-rw-r--r--test/prism/fixtures/xstring.txt13
-rw-r--r--test/prism/fixtures/xstring_with_backslash.txt1
-rw-r--r--test/prism/fixtures/yield.txt7
-rw-r--r--test/prism/fixtures_test.rb21
-rw-r--r--test/prism/fuzzer_test.rb67
-rw-r--r--test/prism/heredoc_dedent_test.rb134
-rw-r--r--test/prism/lex_test.rb90
-rw-r--r--test/prism/library_symbols_test.rb104
-rw-r--r--test/prism/locals_test.rb238
-rw-r--r--test/prism/magic_comment_test.rb117
-rw-r--r--test/prism/newline_offsets_test.rb22
-rw-r--r--test/prism/newline_test.rb98
-rw-r--r--test/prism/onigmo_test.rb66
-rw-r--r--test/prism/regexp_test.rb261
-rw-r--r--test/prism/result/attribute_write_test.rb56
-rw-r--r--test/prism/result/breadth_first_search_test.rb18
-rw-r--r--test/prism/result/comments_test.rb138
-rw-r--r--test/prism/result/constant_path_node_test.rb91
-rw-r--r--test/prism/result/equality_test.rb22
-rw-r--r--test/prism/result/heredoc_test.rb19
-rw-r--r--test/prism/result/implicit_array_test.rb59
-rw-r--r--test/prism/result/index_write_test.rb89
-rw-r--r--test/prism/result/integer_base_flags_test.rb33
-rw-r--r--test/prism/result/integer_parse_test.rb41
-rw-r--r--test/prism/result/node_id_test.rb27
-rw-r--r--test/prism/result/numeric_value_test.rb21
-rw-r--r--test/prism/result/overlap_test.rb43
-rw-r--r--test/prism/result/regular_expression_options_test.rb25
-rw-r--r--test/prism/result/source_location_test.rb950
-rw-r--r--test/prism/result/static_inspect_test.rb89
-rw-r--r--test/prism/result/static_literals_test.rb92
-rw-r--r--test/prism/result/warnings_test.rb430
-rw-r--r--test/prism/ruby/compiler_test.rb31
-rw-r--r--test/prism/ruby/desugar_compiler_test.rb80
-rw-r--r--test/prism/ruby/dispatcher_test.rb46
-rw-r--r--test/prism/ruby/location_test.rb173
-rw-r--r--test/prism/ruby/parameters_signature_test.rb91
-rw-r--r--test/prism/ruby/parser_test.rb291
-rw-r--r--test/prism/ruby/pattern_test.rb132
-rw-r--r--test/prism/ruby/reflection_test.rb22
-rw-r--r--test/prism/ruby/ripper_test.rb62
-rw-r--r--test/prism/ruby/ruby_parser_test.rb127
-rw-r--r--test/prism/ruby/tunnel_test.rb26
-rw-r--r--test/prism/snapshots/range_beginless.txt114
-rw-r--r--test/prism/snippets_test.rb42
-rw-r--r--test/prism/test_helper.rb323
-rw-r--r--test/prism/unescape_test.rb240
-rw-r--r--test/prism/version_test.rb11
-rw-r--r--test/psych/test_encoding.rb4
-rw-r--r--test/psych/test_numeric.rb9
-rw-r--r--test/psych/test_object_references.rb8
-rw-r--r--test/psych/test_parser.rb23
-rw-r--r--test/psych/test_psych.rb33
-rw-r--r--test/psych/test_scalar_scanner.rb15
-rw-r--r--test/psych/test_set.rb7
-rw-r--r--test/psych/test_string.rb12
-rw-r--r--test/psych/test_yaml.rb900
-rw-r--r--test/psych/visitors/test_emitter.rb16
-rw-r--r--test/psych/visitors/test_to_ruby.rb2
-rw-r--r--test/psych/visitors/test_yaml_tree.rb8
-rw-r--r--test/racc/assets/cadenza.y170
-rw-r--r--test/racc/assets/cast.y926
-rw-r--r--test/racc/assets/chk.y126
-rw-r--r--test/racc/assets/conf.y16
-rw-r--r--test/racc/assets/csspool.y729
-rw-r--r--test/racc/assets/digraph.y29
-rw-r--r--test/racc/assets/echk.y118
-rw-r--r--test/racc/assets/edtf.y583
-rw-r--r--test/racc/assets/err.y60
-rw-r--r--test/racc/assets/error_recovery.y35
-rw-r--r--test/racc/assets/expect.y7
-rw-r--r--test/racc/assets/firstline.y4
-rw-r--r--test/racc/assets/huia.y318
-rw-r--r--test/racc/assets/ichk.y102
-rw-r--r--test/racc/assets/ifelse.y14
-rw-r--r--test/racc/assets/intp.y546
-rw-r--r--test/racc/assets/journey.y47
-rw-r--r--test/racc/assets/liquor.y313
-rw-r--r--test/racc/assets/machete.y423
-rw-r--r--test/racc/assets/macruby.y2197
-rw-r--r--test/racc/assets/mailp.y437
-rw-r--r--test/racc/assets/mediacloth.y599
-rw-r--r--test/racc/assets/mof.y649
-rw-r--r--test/racc/assets/namae.y302
-rw-r--r--test/racc/assets/nasl.y626
-rw-r--r--test/racc/assets/newsyn.y25
-rw-r--r--test/racc/assets/noend.y4
-rw-r--r--test/racc/assets/nokogiri-css.y255
-rw-r--r--test/racc/assets/nonass.y41
-rw-r--r--test/racc/assets/normal.y27
-rw-r--r--test/racc/assets/norule.y4
-rw-r--r--test/racc/assets/nullbug1.y25
-rw-r--r--test/racc/assets/nullbug2.y15
-rw-r--r--test/racc/assets/opal.y1807
-rw-r--r--test/racc/assets/opt.y123
-rw-r--r--test/racc/assets/percent.y35
-rw-r--r--test/racc/assets/php_serialization.y98
-rw-r--r--test/racc/assets/recv.y97
-rw-r--r--test/racc/assets/riml.y665
-rw-r--r--test/racc/assets/rrconf.y14
-rw-r--r--test/racc/assets/ruby18.y1943
-rw-r--r--test/racc/assets/ruby19.y2174
-rw-r--r--test/racc/assets/ruby20.y2350
-rw-r--r--test/racc/assets/ruby21.y2359
-rw-r--r--test/racc/assets/ruby22.y2381
-rw-r--r--test/racc/assets/scan.y72
-rw-r--r--test/racc/assets/syntax.y50
-rw-r--r--test/racc/assets/tp_plus.y622
-rw-r--r--test/racc/assets/twowaysql.y278
-rw-r--r--test/racc/assets/unterm.y5
-rw-r--r--test/racc/assets/useless.y12
-rw-r--r--test/racc/assets/yyerr.y46
-rw-r--r--test/racc/bench.y36
-rw-r--r--test/racc/case.rb111
-rw-r--r--test/racc/infini.y8
-rw-r--r--test/racc/regress/README.txt7
-rw-r--r--test/racc/regress/cadenza796
-rw-r--r--test/racc/regress/cast3945
-rw-r--r--test/racc/regress/csspool2314
-rw-r--r--test/racc/regress/edtf1794
-rw-r--r--test/racc/regress/huia1681
-rw-r--r--test/racc/regress/journey222
-rw-r--r--test/racc/regress/liquor885
-rw-r--r--test/racc/regress/machete833
-rw-r--r--test/racc/regress/mediacloth1463
-rw-r--r--test/racc/regress/mof1368
-rw-r--r--test/racc/regress/namae634
-rw-r--r--test/racc/regress/nasl2548
-rw-r--r--test/racc/regress/nokogiri-css836
-rw-r--r--test/racc/regress/opal10107
-rw-r--r--test/racc/regress/php_serialization336
-rw-r--r--test/racc/regress/riml4037
-rw-r--r--test/racc/regress/ruby189945
-rw-r--r--test/racc/regress/ruby2211180
-rw-r--r--test/racc/regress/tp_plus1933
-rw-r--r--test/racc/regress/twowaysql556
-rw-r--r--test/racc/scandata/brace7
-rw-r--r--test/racc/scandata/gvar1
-rw-r--r--test/racc/scandata/normal4
-rw-r--r--test/racc/scandata/percent18
-rw-r--r--test/racc/scandata/slash10
-rw-r--r--test/racc/src.intp34
-rw-r--r--test/racc/start.y20
-rw-r--r--test/racc/test_chk_y.rb52
-rw-r--r--test/racc/test_grammar_file_parser.rb15
-rw-r--r--test/racc/test_racc_command.rb339
-rw-r--r--test/racc/test_scan_y.rb52
-rw-r--r--test/racc/testscanner.rb51
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Markdown Documentation - Syntax.text2
-rw-r--r--test/rdoc/MarkdownTest_1.0.3/Tidyness.text (renamed from test/rdoc/MarkdownTest_1.0.3/Tidiness.text)0
-rw-r--r--test/rdoc/support/text_formatter_test_case.rb18
-rw-r--r--test/rdoc/test_rdoc_any_method.rb38
-rw-r--r--test/rdoc/test_rdoc_comment.rb9
-rw-r--r--test/rdoc/test_rdoc_context.rb6
-rw-r--r--test/rdoc/test_rdoc_context_section.rb1
-rw-r--r--test/rdoc/test_rdoc_generator_darkfish.rb35
-rw-r--r--test/rdoc/test_rdoc_generator_markup.rb1
-rw-r--r--test/rdoc/test_rdoc_markdown.rb36
-rw-r--r--test/rdoc/test_rdoc_markdown_test.rb6
-rw-r--r--test/rdoc/test_rdoc_markup.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_attribute_manager.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_attributes.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_document.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_formatter.rb6
-rw-r--r--test/rdoc/test_rdoc_markup_hard_break.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_heading.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_include.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_indented_paragraph.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_paragraph.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_raw.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_to_ansi.rb12
-rw-r--r--test/rdoc/test_rdoc_markup_to_bs.rb11
-rw-r--r--test/rdoc/test_rdoc_markup_to_html.rb41
-rw-r--r--test/rdoc/test_rdoc_markup_to_html_crossref.rb12
-rw-r--r--test/rdoc/test_rdoc_markup_to_joined_paragraph.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_to_label.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_to_markdown.rb19
-rw-r--r--test/rdoc/test_rdoc_markup_to_rdoc.rb30
-rw-r--r--test/rdoc/test_rdoc_markup_to_table_of_contents.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_to_tt_only.rb1
-rw-r--r--test/rdoc/test_rdoc_markup_verbatim.rb1
-rw-r--r--test/rdoc/test_rdoc_options.rb43
-rw-r--r--test/rdoc/test_rdoc_parser.rb87
-rw-r--r--test/rdoc/test_rdoc_parser_c.rb44
-rw-r--r--test/rdoc/test_rdoc_parser_changelog.rb1
-rw-r--r--test/rdoc/test_rdoc_parser_markdown.rb1
-rw-r--r--test/rdoc/test_rdoc_parser_prism_ruby.rb1997
-rw-r--r--test/rdoc/test_rdoc_parser_rd.rb1
-rw-r--r--test/rdoc/test_rdoc_parser_ruby.rb39
-rw-r--r--test/rdoc/test_rdoc_parser_simple.rb1
-rw-r--r--test/rdoc/test_rdoc_rd.rb1
-rw-r--r--test/rdoc/test_rdoc_rd_inline.rb1
-rw-r--r--test/rdoc/test_rdoc_rdoc.rb16
-rw-r--r--test/rdoc/test_rdoc_ri_driver.rb8
-rw-r--r--test/rdoc/test_rdoc_ri_paths.rb1
-rw-r--r--test/rdoc/test_rdoc_single_class.rb1
-rw-r--r--test/rdoc/test_rdoc_stats.rb1
-rw-r--r--test/rdoc/test_rdoc_store.rb8
-rw-r--r--test/rdoc/test_rdoc_task.rb9
-rw-r--r--test/rdoc/test_rdoc_token_stream.rb53
-rw-r--r--test/rdoc/xref_data.rb13
-rw-r--r--test/rdoc/xref_test_case.rb1
-rw-r--r--test/readline/helper.rb29
-rw-r--r--test/readline/test_readline.rb955
-rw-r--r--test/readline/test_readline_history.rb292
-rw-r--r--test/reline/helper.rb121
-rw-r--r--test/reline/test_ansi_with_terminfo.rb112
-rw-r--r--test/reline/test_ansi_without_terminfo.rb77
-rw-r--r--test/reline/test_config.rb299
-rw-r--r--test/reline/test_face.rb257
-rw-r--r--test/reline/test_history.rb11
-rw-r--r--test/reline/test_key_actor_emacs.rb2082
-rw-r--r--test/reline/test_key_actor_vi.rb1348
-rw-r--r--test/reline/test_key_stroke.rb68
-rw-r--r--test/reline/test_line_editor.rb183
-rw-r--r--test/reline/test_macro.rb3
-rw-r--r--test/reline/test_reline.rb115
-rw-r--r--test/reline/test_reline_key.rb50
-rw-r--r--test/reline/test_string_processing.rb14
-rw-r--r--test/reline/test_terminfo.rb2
-rw-r--r--test/reline/test_unicode.rb97
-rw-r--r--test/reline/test_within_pipe.rb9
-rw-r--r--test/reline/windows/test_key_event_record.rb14
-rwxr-xr-xtest/reline/yamatanooroti/multiline_repl64
-rw-r--r--test/reline/yamatanooroti/termination_checker.rb38
-rw-r--r--test/reline/yamatanooroti/test_rendering.rb980
-rw-r--r--test/resolv/test_dns.rb369
-rw-r--r--test/resolv/test_resource.rb76
-rw-r--r--test/resolv/test_svcb_https.rb231
-rw-r--r--test/rinda/test_rinda.rb912
-rw-r--r--test/rinda/test_tuplebag.rb173
-rw-r--r--test/ripper/assert_parse_files.rb25
-rw-r--r--test/ripper/dummyparser.rb53
-rw-r--r--test/ripper/test_lexer.rb216
-rw-r--r--test/ripper/test_parser_events.rb134
-rw-r--r--test/ripper/test_ripper.rb17
-rw-r--r--test/ripper/test_scanner_events.rb30
-rw-r--r--test/ripper/test_sexp.rb54
-rw-r--r--test/ruby/enc/test_case_comprehensive.rb2
-rw-r--r--test/ruby/enc/test_case_mapping.rb10
-rw-r--r--test/ruby/enc/test_case_options.rb12
-rw-r--r--test/ruby/enc/test_emoji_breaks.rb2
-rw-r--r--test/ruby/enc/test_grapheme_breaks.rb2
-rw-r--r--test/ruby/enc/test_regex_casefold.rb2
-rw-r--r--test/ruby/rjit/test_assembler.rb368
-rw-r--r--test/ruby/test_allocation.rb842
-rw-r--r--test/ruby/test_argf.rb111
-rw-r--r--test/ruby/test_arity.rb1
-rw-r--r--test/ruby/test_array.rb54
-rw-r--r--test/ruby/test_assignment.rb10
-rw-r--r--test/ruby/test_ast.rb465
-rw-r--r--test/ruby/test_autoload.rb4
-rw-r--r--test/ruby/test_backtrace.rb60
-rw-r--r--test/ruby/test_beginendblock.rb14
-rw-r--r--test/ruby/test_bignum.rb8
-rw-r--r--test/ruby/test_call.rb1280
-rw-r--r--test/ruby/test_case.rb9
-rw-r--r--test/ruby/test_class.rb26
-rw-r--r--test/ruby/test_comparable.rb10
-rw-r--r--test/ruby/test_compile_prism.rb2658
-rw-r--r--test/ruby/test_complex.rb99
-rw-r--r--test/ruby/test_continuation.rb4
-rw-r--r--test/ruby/test_data.rb34
-rw-r--r--test/ruby/test_default_gems.rb21
-rw-r--r--test/ruby/test_defined.rb61
-rw-r--r--test/ruby/test_dir.rb135
-rw-r--r--test/ruby/test_dir_m17n.rb46
-rw-r--r--test/ruby/test_econv.rb2
-rw-r--r--test/ruby/test_encoding.rb50
-rw-r--r--test/ruby/test_enum.rb22
-rw-r--r--test/ruby/test_enumerator.rb64
-rw-r--r--test/ruby/test_env.rb30
-rw-r--r--test/ruby/test_eval.rb13
-rw-r--r--test/ruby/test_exception.rb151
-rw-r--r--test/ruby/test_fiber.rb18
-rw-r--r--test/ruby/test_file.rb325
-rw-r--r--test/ruby/test_file_exhaustive.rb32
-rw-r--r--test/ruby/test_float.rb45
-rw-r--r--test/ruby/test_gc.rb447
-rw-r--r--test/ruby/test_gc_compact.rb107
-rw-r--r--test/ruby/test_hash.rb820
-rw-r--r--test/ruby/test_integer.rb87
-rw-r--r--test/ruby/test_integer_comb.rb23
-rw-r--r--test/ruby/test_io.rb229
-rw-r--r--test/ruby/test_io_buffer.rb86
-rw-r--r--test/ruby/test_io_m17n.rb104
-rw-r--r--test/ruby/test_iseq.rb135
-rw-r--r--test/ruby/test_iterator.rb16
-rw-r--r--test/ruby/test_keyword.rb161
-rw-r--r--test/ruby/test_lambda.rb26
-rw-r--r--test/ruby/test_lazy_enumerator.rb9
-rw-r--r--test/ruby/test_literal.rb55
-rw-r--r--test/ruby/test_m17n.rb43
-rw-r--r--test/ruby/test_marshal.rb22
-rw-r--r--test/ruby/test_math.rb10
-rw-r--r--test/ruby/test_method.rb224
-rw-r--r--test/ruby/test_mixed_unicode_escapes.rb2
-rw-r--r--test/ruby/test_mjit.rb1327
-rw-r--r--test/ruby/test_mjit_debug.rb17
-rw-r--r--test/ruby/test_module.rb34
-rw-r--r--test/ruby/test_nomethod_error.rb2
-rw-r--r--test/ruby/test_object.rb53
-rw-r--r--test/ruby/test_objectspace.rb60
-rw-r--r--test/ruby/test_optimization.rb166
-rw-r--r--test/ruby/test_pack.rb95
-rw-r--r--test/ruby/test_parse.rb532
-rw-r--r--test/ruby/test_pattern_matching.rb38
-rw-r--r--test/ruby/test_proc.rb81
-rw-r--r--test/ruby/test_process.rb346
-rw-r--r--test/ruby/test_random_formatter.rb55
-rw-r--r--test/ruby/test_range.rb651
-rw-r--r--test/ruby/test_refinement.rb102
-rw-r--r--test/ruby/test_regexp.rb407
-rw-r--r--test/ruby/test_require.rb15
-rw-r--r--test/ruby/test_require_lib.rb31
-rw-r--r--test/ruby/test_rubyoptions.rb396
-rw-r--r--test/ruby/test_rubyvm.rb2
-rw-r--r--test/ruby/test_rubyvm_mjit.rb105
-rw-r--r--test/ruby/test_settracefunc.rb251
-rw-r--r--test/ruby/test_shapes.rb617
-rw-r--r--test/ruby/test_signal.rb43
-rw-r--r--test/ruby/test_sleep.rb17
-rw-r--r--test/ruby/test_sprintf.rb25
-rw-r--r--test/ruby/test_stack.rb1
-rw-r--r--test/ruby/test_string.rb791
-rw-r--r--test/ruby/test_string_memory.rb65
-rw-r--r--test/ruby/test_struct.rb8
-rw-r--r--test/ruby/test_super.rb28
-rw-r--r--test/ruby/test_symbol.rb11
-rw-r--r--test/ruby/test_syntax.rb483
-rw-r--r--test/ruby/test_system.rb13
-rw-r--r--test/ruby/test_thread.rb43
-rw-r--r--test/ruby/test_thread_cv.rb6
-rw-r--r--test/ruby/test_thread_queue.rb34
-rw-r--r--test/ruby/test_time.rb69
-rw-r--r--test/ruby/test_transcode.rb521
-rw-r--r--test/ruby/test_variable.rb105
-rw-r--r--test/ruby/test_vm_dump.rb13
-rw-r--r--test/ruby/test_warning.rb32
-rw-r--r--test/ruby/test_weakkeymap.rb159
-rw-r--r--test/ruby/test_weakmap.rb58
-rw-r--r--test/ruby/test_whileuntil.rb18
-rw-r--r--test/ruby/test_yjit.rb615
-rw-r--r--test/ruby/test_yjit_exit_locations.rb20
-rw-r--r--test/rubygems/bundler_test_gem.rb51
-rw-r--r--test/rubygems/helper.rb378
-rw-r--r--test/rubygems/installer_test_case.rb22
-rw-r--r--test/rubygems/mock_gem_ui.rb86
-rw-r--r--test/rubygems/package/tar_test_case.rb6
-rw-r--r--test/rubygems/plugin/exception/rubygems_plugin.rb4
-rw-r--r--test/rubygems/plugin/scripterror/rubygems_plugin.rb4
-rw-r--r--test/rubygems/rubygems/commands/ins_command.rb7
-rw-r--r--test/rubygems/rubygems/commands/interrupt_command.rb11
-rw-r--r--test/rubygems/rubygems_plugin.rb19
-rw-r--r--test/rubygems/specifications/rubyforge-0.0.1.gemspec21
-rw-r--r--test/rubygems/test_bundled_ca.rb6
-rw-r--r--test/rubygems/test_config.rb4
-rw-r--r--test/rubygems/test_deprecate.rb8
-rw-r--r--test/rubygems/test_gem.rb211
-rw-r--r--test/rubygems/test_gem_available_set.rb6
-rw-r--r--test/rubygems/test_gem_bundler_version_finder.rb4
-rw-r--r--test/rubygems/test_gem_ci_detector.rb32
-rw-r--r--test/rubygems/test_gem_command.rb47
-rw-r--r--test/rubygems/test_gem_command_manager.rb79
-rw-r--r--test/rubygems/test_gem_commands_build_command.rb17
-rw-r--r--test/rubygems/test_gem_commands_cert_command.rb67
-rw-r--r--test/rubygems/test_gem_commands_cleanup_command.rb18
-rw-r--r--test/rubygems/test_gem_commands_contents_command.rb14
-rw-r--r--test/rubygems/test_gem_commands_environment_command.rb49
-rw-r--r--test/rubygems/test_gem_commands_exec_command.rb105
-rw-r--r--test/rubygems/test_gem_commands_fetch_command.rb82
-rw-r--r--test/rubygems/test_gem_commands_generate_index_command.rb81
-rw-r--r--test/rubygems/test_gem_commands_help_command.rb6
-rw-r--r--test/rubygems/test_gem_commands_info_command.rb12
-rw-r--r--test/rubygems/test_gem_commands_install_command.rb122
-rw-r--r--test/rubygems/test_gem_commands_list_command.rb29
-rw-r--r--test/rubygems/test_gem_commands_lock_command.rb4
-rw-r--r--test/rubygems/test_gem_commands_mirror.rb2
-rw-r--r--test/rubygems/test_gem_commands_open_command.rb13
-rw-r--r--test/rubygems/test_gem_commands_owner_command.rb32
-rw-r--r--test/rubygems/test_gem_commands_pristine_command.rb30
-rw-r--r--test/rubygems/test_gem_commands_push_command.rb33
-rw-r--r--test/rubygems/test_gem_commands_query_command.rb64
-rw-r--r--test/rubygems/test_gem_commands_rebuild_command.rb154
-rw-r--r--test/rubygems/test_gem_commands_server_command.rb2
-rw-r--r--test/rubygems/test_gem_commands_setup_command.rb53
-rw-r--r--test/rubygems/test_gem_commands_signin_command.rb99
-rw-r--r--test/rubygems/test_gem_commands_signout_command.rb6
-rw-r--r--test/rubygems/test_gem_commands_specification_command.rb30
-rw-r--r--test/rubygems/test_gem_commands_stale_command.rb4
-rw-r--r--test/rubygems/test_gem_commands_uninstall_command.rb89
-rw-r--r--test/rubygems/test_gem_commands_unpack_command.rb8
-rw-r--r--test/rubygems/test_gem_commands_update_command.rb64
-rw-r--r--test/rubygems/test_gem_commands_which_command.rb12
-rw-r--r--test/rubygems/test_gem_commands_yank_command.rb8
-rw-r--r--test/rubygems/test_gem_config_file.rb177
-rw-r--r--test/rubygems/test_gem_console_ui.rb19
-rw-r--r--test/rubygems/test_gem_dependency.rb21
-rw-r--r--test/rubygems/test_gem_dependency_installer.rb183
-rw-r--r--test/rubygems/test_gem_dependency_list.rb12
-rw-r--r--test/rubygems/test_gem_dependency_resolution_error.rb14
-rw-r--r--test/rubygems/test_gem_ext_builder.rb221
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder.rb14
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.lock44
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/custom_name/ext/custom_name_lib/Cargo.toml2
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock34
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml2
-rw-r--r--test/rubygems/test_gem_ext_cargo_builder_unit.rb2
-rw-r--r--test/rubygems/test_gem_ext_cmake_builder.rb14
-rw-r--r--test/rubygems/test_gem_ext_configure_builder.rb2
-rw-r--r--test/rubygems/test_gem_ext_ext_conf_builder.rb17
-rw-r--r--test/rubygems/test_gem_ext_rake_builder.rb22
-rw-r--r--test/rubygems/test_gem_gemcutter_utilities.rb39
-rw-r--r--test/rubygems/test_gem_indexer.rb381
-rw-r--r--test/rubygems/test_gem_install_update_options.rb25
-rw-r--r--test/rubygems/test_gem_installer.rb324
-rw-r--r--test/rubygems/test_gem_local_remote_options.rb12
-rw-r--r--test/rubygems/test_gem_name_tuple.rb33
-rw-r--r--test/rubygems/test_gem_package.rb279
-rw-r--r--test/rubygems/test_gem_package_old.rb6
-rw-r--r--test/rubygems/test_gem_package_tar_header.rb90
-rw-r--r--test/rubygems/test_gem_package_tar_reader.rb25
-rw-r--r--test/rubygems/test_gem_package_tar_reader_entry.rb72
-rw-r--r--test/rubygems/test_gem_package_tar_writer.rb88
-rw-r--r--test/rubygems/test_gem_package_task.rb4
-rw-r--r--test/rubygems/test_gem_platform.rb92
-rw-r--r--test/rubygems/test_gem_rdoc.rb6
-rw-r--r--test/rubygems/test_gem_remote_fetcher.rb733
-rw-r--r--test/rubygems/test_gem_remote_fetcher_local_server.rb220
-rw-r--r--test/rubygems/test_gem_remote_fetcher_local_ssl_server.rb195
-rw-r--r--test/rubygems/test_gem_remote_fetcher_s3.rb233
-rw-r--r--test/rubygems/test_gem_request.rb113
-rw-r--r--test/rubygems/test_gem_request_connection_pools.rb24
-rw-r--r--test/rubygems/test_gem_request_set.rb58
-rw-r--r--test/rubygems/test_gem_request_set_gem_dependency_api.rb162
-rw-r--r--test/rubygems/test_gem_request_set_lockfile_parser.rb16
-rw-r--r--test/rubygems/test_gem_requirement.rb18
-rw-r--r--test/rubygems/test_gem_resolver.rb82
-rw-r--r--test/rubygems/test_gem_resolver_activation_request.rb14
-rw-r--r--test/rubygems/test_gem_resolver_api_set.rb130
-rw-r--r--test/rubygems/test_gem_resolver_api_specification.rb68
-rw-r--r--test/rubygems/test_gem_resolver_best_set.rb104
-rw-r--r--test/rubygems/test_gem_resolver_conflict.rb10
-rw-r--r--test/rubygems/test_gem_resolver_dependency_request.rb24
-rw-r--r--test/rubygems/test_gem_resolver_git_specification.rb3
-rw-r--r--test/rubygems/test_gem_resolver_index_set.rb28
-rw-r--r--test/rubygems/test_gem_resolver_index_specification.rb9
-rw-r--r--test/rubygems/test_gem_resolver_installer_set.rb22
-rw-r--r--test/rubygems/test_gem_resolver_lock_set.rb6
-rw-r--r--test/rubygems/test_gem_resolver_lock_specification.rb14
-rw-r--r--test/rubygems/test_gem_resolver_specification.rb2
-rw-r--r--test/rubygems/test_gem_resolver_vendor_specification.rb3
-rw-r--r--test/rubygems/test_gem_safe_marshal.rb416
-rw-r--r--test/rubygems/test_gem_safe_yaml.rb24
-rw-r--r--test/rubygems/test_gem_security.rb60
-rw-r--r--test/rubygems/test_gem_security_policy.rb60
-rw-r--r--test/rubygems/test_gem_security_signer.rb18
-rw-r--r--test/rubygems/test_gem_security_trust_dir.rb18
-rw-r--r--test/rubygems/test_gem_silent_ui.rb3
-rw-r--r--test/rubygems/test_gem_source.rb41
-rw-r--r--test/rubygems/test_gem_source_git.rb14
-rw-r--r--test/rubygems/test_gem_source_installed.rb7
-rw-r--r--test/rubygems/test_gem_source_list.rb4
-rw-r--r--test/rubygems/test_gem_source_local.rb9
-rw-r--r--test/rubygems/test_gem_source_lock.rb4
-rw-r--r--test/rubygems/test_gem_source_specific_file.rb8
-rw-r--r--test/rubygems/test_gem_source_subpath_problem.rb8
-rw-r--r--test/rubygems/test_gem_source_vendor.rb2
-rw-r--r--test/rubygems/test_gem_spec_fetcher.rb30
-rw-r--r--test/rubygems/test_gem_specification.rb552
-rw-r--r--test/rubygems/test_gem_stream_ui.rb18
-rw-r--r--test/rubygems/test_gem_stub_specification.rb2
-rw-r--r--test/rubygems/test_gem_uninstaller.rb191
-rw-r--r--test/rubygems/test_gem_update_suggestion.rb152
-rw-r--r--test/rubygems/test_gem_util.rb14
-rw-r--r--test/rubygems/test_gem_version.rb6
-rw-r--r--test/rubygems/test_gem_version_option.rb48
-rw-r--r--test/rubygems/test_kernel.rb20
-rw-r--r--test/rubygems/test_remote_fetch_error.rb2
-rw-r--r--test/rubygems/test_require.rb152
-rw-r--r--test/rubygems/test_rubygems.rb10
-rw-r--r--test/rubygems/test_webauthn_listener.rb32
-rw-r--r--test/rubygems/test_webauthn_poller.rb20
-rw-r--r--test/rubygems/utilities.rb39
-rw-r--r--test/runner.rb13
-rw-r--r--test/set/test_set.rb892
-rw-r--r--test/socket/test_addrinfo.rb4
-rw-r--r--test/socket/test_socket.rb275
-rw-r--r--test/socket/test_tcp.rb2
-rw-r--r--test/socket/test_unix.rb68
-rw-r--r--test/stringio/test_ractor.rb2
-rw-r--r--test/stringio/test_stringio.rb113
-rw-r--r--test/strscan/test_stringscanner.rb127
-rw-r--r--test/syslog/test_syslog_logger.rb588
-rw-r--r--test/test_abbrev.rb55
-rw-r--r--test/test_bundled_gems.rb35
-rw-r--r--test/test_delegate.rb9
-rw-r--r--test/test_extlibs.rb7
-rw-r--r--test/test_forwardable.rb2
-rw-r--r--test/test_getoptlong.rb163
-rw-r--r--test/test_ipaddr.rb95
-rw-r--r--test/test_mutex_m.rb58
-rw-r--r--test/test_observer.rb66
-rw-r--r--test/test_open3.rb10
-rw-r--r--test/test_pp.rb73
-rw-r--r--test/test_set.rb879
-rw-r--r--test/test_singleton.rb21
-rw-r--r--test/test_sorted_set.rb (renamed from test/set/test_sorted_set.rb)0
-rw-r--r--test/test_syslog.rb193
-rw-r--r--test/test_tempfile.rb118
-rw-r--r--test/test_timeout.rb110
-rw-r--r--test/test_tmpdir.rb22
-rw-r--r--test/test_trick.rb97
-rw-r--r--test/test_unicode_normalize.rb2
-rw-r--r--test/uri/test_common.rb40
-rw-r--r--test/uri/test_ftp.rb10
-rw-r--r--test/uri/test_generic.rb33
-rw-r--r--test/uri/test_http.rb8
-rw-r--r--test/uri/test_ldap.rb8
-rw-r--r--test/uri/test_parser.rb22
-rw-r--r--test/uri/test_ws.rb8
-rw-r--r--test/uri/test_wss.rb8
-rw-r--r--test/win32/test_registry.rb97
-rw-r--r--test/win32ole/available_ole.rb14
-rw-r--r--test/win32ole/err_in_callback.rb4
-rw-r--r--test/win32ole/test_err_in_callback.rb4
-rw-r--r--test/win32ole/test_folderitem2_invokeverb.rb2
-rw-r--r--test/win32ole/test_nil2vtempty.rb2
-rw-r--r--test/win32ole/test_propertyputref.rb2
-rw-r--r--test/win32ole/test_thread.rb2
-rw-r--r--test/win32ole/test_win32ole.rb43
-rw-r--r--test/win32ole/test_win32ole_event.rb70
-rw-r--r--test/win32ole/test_win32ole_method.rb48
-rw-r--r--test/win32ole/test_win32ole_method_event.rb10
-rw-r--r--test/win32ole/test_win32ole_param.rb42
-rw-r--r--test/win32ole/test_win32ole_param_event.rb2
-rw-r--r--test/win32ole/test_win32ole_record.rb60
-rw-r--r--test/win32ole/test_win32ole_type.rb67
-rw-r--r--test/win32ole/test_win32ole_type_event.rb4
-rw-r--r--test/win32ole/test_win32ole_typelib.rb66
-rw-r--r--test/win32ole/test_win32ole_variable.rb16
-rw-r--r--test/win32ole/test_win32ole_variant.rb308
-rw-r--r--test/win32ole/test_win32ole_variant_m.rb5
-rw-r--r--test/win32ole/test_win32ole_variant_outarg.rb6
-rw-r--r--test/win32ole/test_word.rb2
-rw-r--r--test/yaml/test_store.rb2
-rw-r--r--test/zlib/test_zlib.rb85
-rw-r--r--thread.c1016
-rw-r--r--thread_none.c75
-rw-r--r--thread_none.h1
-rw-r--r--thread_pthread.c3394
-rw-r--r--thread_pthread.h123
-rw-r--r--thread_pthread_mn.c1082
-rw-r--r--thread_sync.c270
-rw-r--r--thread_win32.c225
-rw-r--r--thread_win32.h7
-rw-r--r--time.c527
-rw-r--r--timev.rb105
-rw-r--r--tool/annocheck/Dockerfile-copy5
-rw-r--r--tool/bundler/dev_gems.rb9
-rw-r--r--tool/bundler/dev_gems.rb.lock57
-rw-r--r--tool/bundler/rubocop_gems.rb2
-rw-r--r--tool/bundler/rubocop_gems.rb.lock73
-rw-r--r--tool/bundler/standard_gems.rb.lock81
-rw-r--r--tool/bundler/test_gems.rb15
-rw-r--r--tool/bundler/test_gems.rb.lock45
-rw-r--r--tool/bundler/vendor_gems.rb16
-rw-r--r--tool/ci_functions.sh29
-rwxr-xr-xtool/darwin-ar6
-rwxr-xr-xtool/darwin-cc3
-rw-r--r--tool/downloader.rb35
-rwxr-xr-xtool/enc-case-folding.rb6
-rwxr-xr-xtool/enc-unicode.rb101
-rwxr-xr-xtool/extlibs.rb2
-rwxr-xr-xtool/fetch-bundled_gems.rb25
-rwxr-xr-xtool/format-release14
-rwxr-xr-xtool/gen-github-release.rb66
-rw-r--r--tool/generic_erb.rb6
-rw-r--r--tool/gperf.sed19
-rwxr-xr-xtool/leaked-globals68
-rw-r--r--tool/lib/_tmpdir.rb100
-rw-r--r--tool/lib/bundled_gem.rb56
-rw-r--r--tool/lib/colorize.rb33
-rw-r--r--tool/lib/core_assertions.rb121
-rw-r--r--tool/lib/envutil.rb63
-rw-r--r--tool/lib/iseq_loader_checker.rb9
-rw-r--r--tool/lib/launchable.rb91
-rw-r--r--tool/lib/leakchecker.rb10
-rw-r--r--tool/lib/memory_status.rb2
-rw-r--r--tool/lib/output.rb23
-rw-r--r--tool/lib/path.rb101
-rw-r--r--tool/lib/test/unit.rb267
-rw-r--r--tool/lib/test/unit/assertions.rb11
-rw-r--r--tool/lib/test/unit/parallel.rb27
-rw-r--r--tool/lib/test/unit/testcase.rb22
-rw-r--r--tool/lib/vcs.rb68
-rw-r--r--tool/lib/webrick.rb232
-rw-r--r--tool/lib/webrick/.document6
-rw-r--r--tool/lib/webrick/accesslog.rb157
-rw-r--r--tool/lib/webrick/cgi.rb313
-rw-r--r--tool/lib/webrick/compat.rb36
-rw-r--r--tool/lib/webrick/config.rb158
-rw-r--r--tool/lib/webrick/cookie.rb172
-rw-r--r--tool/lib/webrick/htmlutils.rb30
-rw-r--r--tool/lib/webrick/httpauth.rb96
-rw-r--r--tool/lib/webrick/httpauth/authenticator.rb117
-rw-r--r--tool/lib/webrick/httpauth/basicauth.rb116
-rw-r--r--tool/lib/webrick/httpauth/digestauth.rb395
-rw-r--r--tool/lib/webrick/httpauth/htdigest.rb132
-rw-r--r--tool/lib/webrick/httpauth/htgroup.rb97
-rw-r--r--tool/lib/webrick/httpauth/htpasswd.rb158
-rw-r--r--tool/lib/webrick/httpauth/userdb.rb53
-rw-r--r--tool/lib/webrick/httpproxy.rb354
-rw-r--r--tool/lib/webrick/httprequest.rb636
-rw-r--r--tool/lib/webrick/httpresponse.rb564
-rw-r--r--tool/lib/webrick/https.rb152
-rw-r--r--tool/lib/webrick/httpserver.rb293
-rw-r--r--tool/lib/webrick/httpservlet.rb23
-rw-r--r--tool/lib/webrick/httpservlet/abstract.rb152
-rw-r--r--tool/lib/webrick/httpservlet/cgi_runner.rb47
-rw-r--r--tool/lib/webrick/httpservlet/cgihandler.rb126
-rw-r--r--tool/lib/webrick/httpservlet/erbhandler.rb88
-rw-r--r--tool/lib/webrick/httpservlet/filehandler.rb552
-rw-r--r--tool/lib/webrick/httpservlet/prochandler.rb47
-rw-r--r--tool/lib/webrick/httpstatus.rb194
-rw-r--r--tool/lib/webrick/httputils.rb512
-rw-r--r--tool/lib/webrick/httpversion.rb76
-rw-r--r--tool/lib/webrick/log.rb156
-rw-r--r--tool/lib/webrick/server.rb381
-rw-r--r--tool/lib/webrick/ssl.rb215
-rw-r--r--tool/lib/webrick/utils.rb265
-rw-r--r--tool/lib/webrick/version.rb18
-rwxr-xr-xtool/ln_sr.rb2
-rw-r--r--tool/lrama/LEGAL.md12
-rw-r--r--tool/lrama/MIT21
-rw-r--r--tool/lrama/NEWS.md602
-rwxr-xr-xtool/lrama/exe/lrama7
-rw-r--r--tool/lrama/lib/lrama.rb22
-rw-r--r--tool/lrama/lib/lrama/bitmap.rb31
-rw-r--r--tool/lrama/lib/lrama/command.rb67
-rw-r--r--tool/lrama/lib/lrama/context.rb499
-rw-r--r--tool/lrama/lib/lrama/counterexamples.rb288
-rw-r--r--tool/lrama/lib/lrama/counterexamples/derivation.rb65
-rw-r--r--tool/lrama/lib/lrama/counterexamples/example.rb126
-rw-r--r--tool/lrama/lib/lrama/counterexamples/path.rb25
-rw-r--r--tool/lrama/lib/lrama/counterexamples/production_path.rb19
-rw-r--r--tool/lrama/lib/lrama/counterexamples/start_path.rb23
-rw-r--r--tool/lrama/lib/lrama/counterexamples/state_item.rb8
-rw-r--r--tool/lrama/lib/lrama/counterexamples/transition_path.rb19
-rw-r--r--tool/lrama/lib/lrama/counterexamples/triple.rb23
-rw-r--r--tool/lrama/lib/lrama/diagnostics.rb36
-rw-r--r--tool/lrama/lib/lrama/digraph.rb53
-rw-r--r--tool/lrama/lib/lrama/grammar.rb402
-rw-r--r--tool/lrama/lib/lrama/grammar/auxiliary.rb9
-rw-r--r--tool/lrama/lib/lrama/grammar/binding.rb35
-rw-r--r--tool/lrama/lib/lrama/grammar/code.rb53
-rw-r--r--tool/lrama/lib/lrama/grammar/code/destructor_code.rb42
-rw-r--r--tool/lrama/lib/lrama/grammar/code/initial_action_code.rb36
-rw-r--r--tool/lrama/lib/lrama/grammar/code/no_reference_code.rb30
-rw-r--r--tool/lrama/lib/lrama/grammar/code/printer_code.rb42
-rw-r--r--tool/lrama/lib/lrama/grammar/code/rule_action.rb92
-rw-r--r--tool/lrama/lib/lrama/grammar/counter.rb17
-rw-r--r--tool/lrama/lib/lrama/grammar/destructor.rb11
-rw-r--r--tool/lrama/lib/lrama/grammar/error_token.rb11
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rule.rb5
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rule/resolver.rb62
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rule/rhs.rb40
-rw-r--r--tool/lrama/lib/lrama/grammar/parameterizing_rule/rule.rb24
-rw-r--r--tool/lrama/lib/lrama/grammar/percent_code.rb14
-rw-r--r--tool/lrama/lib/lrama/grammar/precedence.rb13
-rw-r--r--tool/lrama/lib/lrama/grammar/printer.rb11
-rw-r--r--tool/lrama/lib/lrama/grammar/reference.rb16
-rw-r--r--tool/lrama/lib/lrama/grammar/rule.rb67
-rw-r--r--tool/lrama/lib/lrama/grammar/rule_builder.rb267
-rw-r--r--tool/lrama/lib/lrama/grammar/stdlib.y122
-rw-r--r--tool/lrama/lib/lrama/grammar/symbol.rb105
-rw-r--r--tool/lrama/lib/lrama/grammar/symbols.rb3
-rw-r--r--tool/lrama/lib/lrama/grammar/symbols/resolver.rb297
-rw-r--r--tool/lrama/lib/lrama/grammar/type.rb20
-rw-r--r--tool/lrama/lib/lrama/grammar/union.rb12
-rw-r--r--tool/lrama/lib/lrama/grammar_validator.rb37
-rw-r--r--tool/lrama/lib/lrama/lexer.rb191
-rw-r--r--tool/lrama/lib/lrama/lexer/grammar_file.rb33
-rw-r--r--tool/lrama/lib/lrama/lexer/location.rb99
-rw-r--r--tool/lrama/lib/lrama/lexer/token.rb58
-rw-r--r--tool/lrama/lib/lrama/lexer/token/char.rb10
-rw-r--r--tool/lrama/lib/lrama/lexer/token/ident.rb10
-rw-r--r--tool/lrama/lib/lrama/lexer/token/instantiate_rule.rb25
-rw-r--r--tool/lrama/lib/lrama/lexer/token/tag.rb14
-rw-r--r--tool/lrama/lib/lrama/lexer/token/user_code.rb79
-rw-r--r--tool/lrama/lib/lrama/logger.rb17
-rw-r--r--tool/lrama/lib/lrama/option_parser.rb167
-rw-r--r--tool/lrama/lib/lrama/options.rb27
-rw-r--r--tool/lrama/lib/lrama/output.rb459
-rw-r--r--tool/lrama/lib/lrama/parser.rb2105
-rw-r--r--tool/lrama/lib/lrama/report.rb4
-rw-r--r--tool/lrama/lib/lrama/report/duration.rb27
-rw-r--r--tool/lrama/lib/lrama/report/profile.rb16
-rw-r--r--tool/lrama/lib/lrama/state.rb146
-rw-r--r--tool/lrama/lib/lrama/state/reduce.rb38
-rw-r--r--tool/lrama/lib/lrama/state/reduce_reduce_conflict.rb11
-rw-r--r--tool/lrama/lib/lrama/state/resolved_conflict.rb31
-rw-r--r--tool/lrama/lib/lrama/state/shift.rb15
-rw-r--r--tool/lrama/lib/lrama/state/shift_reduce_conflict.rb11
-rw-r--r--tool/lrama/lib/lrama/states.rb528
-rw-r--r--tool/lrama/lib/lrama/states/item.rb83
-rw-r--r--tool/lrama/lib/lrama/states_reporter.rb362
-rw-r--r--tool/lrama/lib/lrama/trace_reporter.rb30
-rw-r--r--tool/lrama/lib/lrama/version.rb5
-rw-r--r--tool/lrama/template/bison/_yacc.h71
-rw-r--r--tool/lrama/template/bison/yacc.c2068
-rw-r--r--tool/lrama/template/bison/yacc.h40
-rw-r--r--tool/m4/ruby_append_option.m44
-rw-r--r--tool/m4/ruby_check_builtin_setjmp.m42
-rw-r--r--tool/m4/ruby_check_header.m48
-rw-r--r--tool/m4/ruby_default_arch.m425
-rw-r--r--tool/m4/ruby_setjmp_type.m419
-rw-r--r--tool/m4/ruby_shared_gc.m442
-rw-r--r--tool/m4/ruby_stack_grow_direction.m42
-rw-r--r--tool/m4/ruby_try_cflags.m430
-rw-r--r--tool/m4/ruby_universal_arch.m46
-rw-r--r--tool/m4/ruby_wasm_tools.m43
-rwxr-xr-xtool/make-snapshot42
-rwxr-xr-xtool/merger.rb3
-rwxr-xr-xtool/missing-baseruby.bat23
-rwxr-xr-xtool/mjit/bindgen.rb435
-rw-r--r--tool/mjit_archflag.sh40
-rw-r--r--tool/mjit_tabs.rb67
-rw-r--r--tool/mk_builtin_loader.rb129
-rwxr-xr-xtool/mk_rbbin.rb48
-rwxr-xr-xtool/mkconfig.rb18
-rwxr-xr-xtool/mkrunnable.rb99
-rwxr-xr-xtool/outdate-bundled-gems.rb101
-rwxr-xr-xtool/rbinstall.rb662
-rw-r--r--tool/rbs_skip_tests72
-rwxr-xr-xtool/rbuninstall.rb36
-rwxr-xr-xtool/rdoc-srcdir20
-rwxr-xr-xtool/release.sh12
-rwxr-xr-xtool/rjit/bindgen.rb666
-rw-r--r--tool/ruby_vm/helpers/c_escape.rb5
-rw-r--r--tool/ruby_vm/helpers/dumper.rb6
-rw-r--r--tool/ruby_vm/models/attribute.rb2
-rwxr-xr-xtool/ruby_vm/models/bare_instructions.rb16
-rw-r--r--tool/ruby_vm/models/c_expr.rb6
-rw-r--r--tool/ruby_vm/models/operands_unifications.rb8
-rw-r--r--tool/ruby_vm/views/_comptime_insn_stack_increase.erb2
-rw-r--r--tool/ruby_vm/views/_insn_entry.erb9
-rw-r--r--tool/ruby_vm/views/_leaf_helpers.erb2
-rw-r--r--tool/ruby_vm/views/_sp_inc_helpers.erb2
-rw-r--r--tool/ruby_vm/views/lib/ruby_vm/mjit/instruction.rb.erb40
-rw-r--r--tool/ruby_vm/views/lib/ruby_vm/rjit/instruction.rb.erb14
-rw-r--r--tool/ruby_vm/views/mjit_sp_inc.inc.erb17
-rw-r--r--tool/ruby_vm/views/opt_sc.inc.erb40
-rw-r--r--tool/ruby_vm/views/optinsn.inc.erb4
-rw-r--r--tool/run-gcov.rb3
-rw-r--r--tool/run-lcov.rb14
-rwxr-xr-xtool/runruby.rb9
-rwxr-xr-xtool/sync_default_gems.rb567
-rwxr-xr-xtool/test-annocheck.sh11
-rw-r--r--tool/test-bundled-gems.rb13
-rw-r--r--tool/test-coverage.rb21
-rw-r--r--tool/test/init.rb18
-rw-r--r--tool/test/runner.rb13
-rwxr-xr-xtool/test/test_sync_default_gems.rb221
-rw-r--r--tool/test/testunit/test4test_load_failure.rb1
-rw-r--r--tool/test/testunit/test4test_timeout.rb15
-rw-r--r--tool/test/testunit/test_assertion.rb118
-rw-r--r--tool/test/testunit/test_hideskip.rb4
-rw-r--r--tool/test/testunit/test_launchable.rb70
-rw-r--r--tool/test/testunit/test_load_failure.rb23
-rw-r--r--tool/test/testunit/test_parallel.rb33
-rw-r--r--tool/test/testunit/test_sorting.rb2
-rw-r--r--tool/test/testunit/test_timeout.rb10
-rw-r--r--tool/test/testunit/tests_for_parallel/slow_helper.rb8
-rw-r--r--tool/test/testunit/tests_for_parallel/test4test_slow_0.rb5
-rw-r--r--tool/test/testunit/tests_for_parallel/test4test_slow_1.rb5
-rw-r--r--tool/test/webrick/.htaccess1
-rw-r--r--tool/test/webrick/test_cgi.rb170
-rw-r--r--tool/test/webrick/test_config.rb17
-rw-r--r--tool/test/webrick/test_cookie.rb141
-rw-r--r--tool/test/webrick/test_do_not_reverse_lookup.rb71
-rw-r--r--tool/test/webrick/test_filehandler.rb403
-rw-r--r--tool/test/webrick/test_htgroup.rb19
-rw-r--r--tool/test/webrick/test_htmlutils.rb21
-rw-r--r--tool/test/webrick/test_httpauth.rb366
-rw-r--r--tool/test/webrick/test_httpproxy.rb467
-rw-r--r--tool/test/webrick/test_httprequest.rb488
-rw-r--r--tool/test/webrick/test_httpresponse.rb282
-rw-r--r--tool/test/webrick/test_https.rb112
-rw-r--r--tool/test/webrick/test_httpserver.rb543
-rw-r--r--tool/test/webrick/test_httpstatus.rb35
-rw-r--r--tool/test/webrick/test_httputils.rb101
-rw-r--r--tool/test/webrick/test_httpversion.rb41
-rw-r--r--tool/test/webrick/test_server.rb191
-rw-r--r--tool/test/webrick/test_ssl_server.rb67
-rw-r--r--tool/test/webrick/test_utils.rb110
-rw-r--r--tool/test/webrick/utils.rb84
-rw-r--r--tool/test/webrick/webrick.cgi38
-rw-r--r--tool/test/webrick/webrick.rhtml4
-rw-r--r--tool/test/webrick/webrick_long_filename.cgi36
-rw-r--r--tool/test_for_warn_bundled_gems/.gitignore1
-rw-r--r--tool/test_for_warn_bundled_gems/Gemfile0
-rw-r--r--tool/test_for_warn_bundled_gems/Gemfile.lock11
-rw-r--r--tool/test_for_warn_bundled_gems/README.md3
-rwxr-xr-xtool/test_for_warn_bundled_gems/test.sh65
-rw-r--r--tool/test_for_warn_bundled_gems/test_no_warn_dash_gem.rb11
-rw-r--r--tool/test_for_warn_bundled_gems/test_no_warn_dependency.rb13
-rw-r--r--tool/test_for_warn_bundled_gems/test_no_warn_sub_feature.rb11
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_bootsnap.rb14
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_bootsnap_and_gem.rb14
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_bootsnap_rubyarchdir_gem.rb14
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_bundle_exec.rb1
-rwxr-xr-xtool/test_for_warn_bundled_gems/test_warn_bundle_exec_shebang.rb3
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_bundled_gems.rb13
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_dash_gem.rb10
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_dependency.rb11
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_redefined.rb21
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_sub_feature.rb10
-rw-r--r--tool/test_for_warn_bundled_gems/test_warn_zeitwerk.rb15
-rw-r--r--tool/transcode-tblgen.rb6
-rw-r--r--tool/transform_mjit_header.rb319
-rwxr-xr-xtool/update-NEWS-gemlist.rb41
-rw-r--r--tool/update-NEWS-refs.rb7
-rwxr-xr-xtool/update-bundled_gems.rb39
-rwxr-xr-xtool/update-deps53
-rwxr-xr-xtool/ytab.sed80
-rw-r--r--trace_point.rb19
-rw-r--r--transcode.c41
-rw-r--r--transient_heap.c991
-rw-r--r--transient_heap.h65
-rw-r--r--universal_parser.c220
-rw-r--r--util.c63
-rw-r--r--variable.c1385
-rw-r--r--variable.h16
-rw-r--r--vcpkg.json11
-rw-r--r--version.c106
-rw-r--r--version.h14
-rw-r--r--vm.c1193
-rw-r--r--vm_args.c505
-rw-r--r--vm_backtrace.c539
-rw-r--r--vm_callinfo.h147
-rw-r--r--vm_core.h401
-rw-r--r--vm_debug.h2
-rw-r--r--vm_dump.c432
-rw-r--r--vm_eval.c590
-rw-r--r--vm_exec.c59
-rw-r--r--vm_exec.h36
-rw-r--r--vm_insnhelper.c2039
-rw-r--r--vm_insnhelper.h53
-rw-r--r--vm_method.c310
-rw-r--r--vm_opts.h8
-rw-r--r--vm_sync.c143
-rw-r--r--vm_trace.c463
-rw-r--r--vsnprintf.c4
-rw-r--r--warning.rb14
-rw-r--r--wasm/runtime.c7
-rw-r--r--wasm/setjmp.c69
-rw-r--r--wasm/setjmp.h2
-rw-r--r--weakmap.c1152
-rw-r--r--win32/.document1
-rw-r--r--win32/Makefile.sub166
-rw-r--r--win32/README.win32149
-rwxr-xr-xwin32/configure.bat20
-rw-r--r--win32/dir.h2
-rw-r--r--win32/file.c37
-rw-r--r--win32/file.h3
-rwxr-xr-xwin32/mkexports.rb5
-rw-r--r--win32/setup.mak46
-rw-r--r--win32/win32.c515
-rw-r--r--win32/winmain.c4
-rw-r--r--yjit.c353
-rw-r--r--yjit.h39
-rw-r--r--yjit.rb443
-rw-r--r--yjit/Cargo.lock15
-rw-r--r--yjit/Cargo.toml20
-rw-r--r--yjit/bindgen/Cargo.lock163
-rw-r--r--yjit/bindgen/Cargo.toml2
-rw-r--r--yjit/bindgen/src/main.rs98
-rw-r--r--yjit/not_gmake.mk6
-rw-r--r--yjit/src/asm/arm64/arg/bitmask_imm.rs6
-rw-r--r--yjit/src/asm/arm64/arg/condition.rs2
-rw-r--r--yjit/src/asm/arm64/arg/sys_reg.rs4
-rw-r--r--yjit/src/asm/arm64/arg/truncate.rs4
-rw-r--r--yjit/src/asm/arm64/inst/atomic.rs4
-rw-r--r--yjit/src/asm/arm64/inst/branch.rs8
-rw-r--r--yjit/src/asm/arm64/inst/branch_cond.rs4
-rw-r--r--yjit/src/asm/arm64/inst/breakpoint.rs4
-rw-r--r--yjit/src/asm/arm64/inst/call.rs6
-rw-r--r--yjit/src/asm/arm64/inst/conditional.rs4
-rw-r--r--yjit/src/asm/arm64/inst/data_imm.rs12
-rw-r--r--yjit/src/asm/arm64/inst/data_reg.rs12
-rw-r--r--yjit/src/asm/arm64/inst/halfword_imm.rs14
-rw-r--r--yjit/src/asm/arm64/inst/load_literal.rs4
-rw-r--r--yjit/src/asm/arm64/inst/load_register.rs4
-rw-r--r--yjit/src/asm/arm64/inst/load_store.rs22
-rw-r--r--yjit/src/asm/arm64/inst/load_store_exclusive.rs6
-rw-r--r--yjit/src/asm/arm64/inst/logical_imm.rs14
-rw-r--r--yjit/src/asm/arm64/inst/logical_reg.rs18
-rw-r--r--yjit/src/asm/arm64/inst/madd.rs73
-rw-r--r--yjit/src/asm/arm64/inst/mod.rs4
-rw-r--r--yjit/src/asm/arm64/inst/mov.rs6
-rw-r--r--yjit/src/asm/arm64/inst/nop.rs2
-rw-r--r--yjit/src/asm/arm64/inst/pc_rel.rs6
-rw-r--r--yjit/src/asm/arm64/inst/reg_pair.rs26
-rw-r--r--yjit/src/asm/arm64/inst/sbfm.rs6
-rw-r--r--yjit/src/asm/arm64/inst/shift_imm.rs6
-rw-r--r--yjit/src/asm/arm64/inst/smulh.rs60
-rw-r--r--yjit/src/asm/arm64/inst/sys_reg.rs6
-rw-r--r--yjit/src/asm/arm64/inst/test_bit.rs6
-rw-r--r--yjit/src/asm/arm64/mod.rs110
-rw-r--r--yjit/src/asm/mod.rs217
-rw-r--r--yjit/src/asm/x86_64/mod.rs81
-rw-r--r--yjit/src/asm/x86_64/tests.rs20
-rw-r--r--yjit/src/backend/arm64/mod.rs718
-rw-r--r--yjit/src/backend/ir.rs840
-rw-r--r--yjit/src/backend/mod.rs6
-rw-r--r--yjit/src/backend/tests.rs60
-rw-r--r--yjit/src/backend/x86_64/mod.rs653
-rw-r--r--yjit/src/codegen.rs9693
-rw-r--r--yjit/src/core.rs3918
-rw-r--r--yjit/src/cruby.rs175
-rw-r--r--yjit/src/cruby_bindings.inc.rs922
-rw-r--r--yjit/src/disasm.rs255
-rw-r--r--yjit/src/invariants.rs382
-rw-r--r--yjit/src/lib.rs3
-rw-r--r--yjit/src/options.rs247
-rw-r--r--yjit/src/stats.rs724
-rw-r--r--yjit/src/utils.rs45
-rw-r--r--yjit/src/virtualmem.rs90
-rw-r--r--yjit/src/yjit.rs144
-rw-r--r--yjit/yjit.mk50
6424 files changed, 381323 insertions, 411363 deletions
diff --git a/.appveyor.yml b/.appveyor.yml
new file mode 100644
index 0000000000..05ff204541
--- /dev/null
+++ b/.appveyor.yml
@@ -0,0 +1,134 @@
+---
+version: '{build}'
+init:
+ - git config --global user.name git
+ - git config --global user.email svn-admin@ruby-lang.org
+ - git config --global core.autocrlf false
+ - git config --global core.eol lf
+ - git config --global advice.detachedHead 0
+shallow_clone: true
+clone_depth: 10
+platform:
+ - x64
+skip_commits:
+ message: /\[DOC\]/
+ files:
+ - doc/*
+ - '**/*.md'
+ - '**/*.rdoc'
+ - '**/.document'
+ - '**/*.[1-8]'
+ - '**/*.ronn'
+environment:
+ ruby_version: "24-%Platform%"
+ matrix:
+ # Test only the oldest supported version because AppVeyor is unstable, its concurrency
+ # is limited, and compatibility issues that happen only in newer versions are rare.
+ # You may test some other stuff on GitHub Actions instead.
+ - build: vs
+ vs: 120 # Visual Studio 2013
+ ssl: OpenSSL-v111
+ # The worker image name. This is NOT the Visual Studio version we're using here.
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+ GEMS_FOR_TEST: ""
+ RELINE_TEST_ENCODING: "UTF-8"
+cache:
+ - c:\Tools\vcpkg\installed\
+for:
+-
+ matrix:
+ only:
+ - build: vs
+ install:
+ - ver
+ - chcp
+ - SET BITS=%Platform:x86=32%
+ - SET BITS=%BITS:x=%
+ - SET OPENSSL_DIR=C:\%ssl%-Win%BITS%
+ - cd C:\Tools\vcpkg
+ - git pull -q
+ - .\bootstrap-vcpkg.bat
+ - ps: Start-FileDownload 'https://github.com/microsoft/vcpkg-tool/releases/download/2023-08-09/vcpkg.exe' -FileName 'C:\Tools\vcpkg\vcpkg.exe'
+ - cd %APPVEYOR_BUILD_FOLDER%
+ - vcpkg --triplet %Platform%-windows install --x-use-aria2 libffi libyaml readline zlib
+ - CALL SET vcvars=%%^VS%VS%COMNTOOLS^%%..\..\VC\vcvarsall.bat
+ - SET vcvars
+ - '"%vcvars%" %Platform:x64=amd64%'
+ - SET ruby_path=C:\Ruby%ruby_version:-x86=%
+ - SET PATH=\usr\local\bin;%ruby_path%\bin;%PATH%;C:\msys64\mingw64\bin;C:\msys64\usr\bin
+ - ruby --version
+ - 'cl'
+ - echo> Makefile srcdir=.
+ - echo>> Makefile MSC_VER=0
+ - echo>> Makefile RT=none
+ - echo>> Makefile RT_VER=0
+ - echo>> Makefile BUILTIN_ENCOBJS=nul
+ - type win32\Makefile.sub >> Makefile
+ - nmake %mflags% up VCSUP="echo Update OK"
+ - nmake %mflags% extract-extlibs
+ - del Makefile
+ - mkdir \usr\local\bin
+ - mkdir \usr\local\include
+ - mkdir \usr\local\lib
+ - for %%I in (%OPENSSL_DIR%\*.dll) do mklink /h \usr\local\bin\%%~nxI %%I
+ - for %%I in (c:\Tools\vcpkg\installed\%Platform%-windows\bin\*.dll) do (
+ if not %%~nI == readline mklink \usr\local\bin\%%~nxI %%I
+ )
+ - attrib +r /s /d
+ - mkdir %Platform%-mswin_%vs%
+ build_script:
+ - set HAVE_GIT=no
+ - cd %APPVEYOR_BUILD_FOLDER%
+ - cd %Platform%-mswin_%vs%
+ - >-
+ ..\win32\configure.bat
+ --with-opt-dir="/usr/local;c:/Tools/vcpkg/installed/%Platform%-windows"
+ --with-openssl-dir=%OPENSSL_DIR:\=/%
+ - nmake -l
+ - nmake install-nodoc
+ - \usr\bin\ruby -v -e "p :locale => Encoding.find('locale'), :filesystem => Encoding.find('filesystem')"
+ - if not "%GEMS_FOR_TEST%" == "" \usr\bin\gem install --no-document %GEMS_FOR_TEST%
+ - \usr\bin\ruby -ropenssl -e "puts 'Build ' + OpenSSL::OPENSSL_VERSION, 'Runtime ' + OpenSSL::OPENSSL_LIBRARY_VERSION"
+ test_script:
+ - set /a JOBS=%NUMBER_OF_PROCESSORS%
+ - nmake -l "TESTOPTS=-v -q" btest
+ - nmake -l "TESTOPTS=-v -q" test-basic
+ - >-
+ nmake -l "TESTOPTS=--timeout-scale=3.0
+ --excludes=../test/excludes/_appveyor -j%JOBS%
+ --exclude win32ole
+ --exclude test_bignum
+ --exclude test_syntax
+ --exclude test_open-uri
+ --exclude test_bundled_ca
+ " test-all
+ # separately execute tests without -j which may crash worker with -j.
+ - >-
+ nmake -l
+ "TESTOPTS=--timeout-scale=3.0 --excludes=../test/excludes/_appveyor"
+ TESTS="
+ ../test/win32ole
+ ../test/ruby/test_bignum.rb
+ ../test/ruby/test_syntax.rb
+ ../test/open-uri/test_open-uri.rb
+ ../test/rubygems/test_bundled_ca.rb
+ " test-all
+ - nmake -l test-spec MSPECOPT=-fs # not using `-j` because sometimes `mspec -j` silently dies on Windows
+notifications:
+ - provider: Webhook
+ method: POST
+ url:
+ secure: CcFlJNDJ/a6to7u3Z4Fnz6dScEPNx7hTha2GkSRlV+1U6dqmxY/7uBcLXYb9gR3jfQk6w+2o/HrjNAyXMNGU/JOka3s2WRI4VKitzM+lQ08owvJIh0R7LxrGH0J2e81U # ruby-lang slack: ruby/simpler-alerts-bot
+ body: >-
+ {{^isPullRequest}}
+ {
+ "ci": "AppVeyor CI",
+ "env": "Visual Studio 2013",
+ "url": "{{buildUrl}}",
+ "commit": "{{commitId}}",
+ "branch": "{{branch}}"
+ }
+ {{/isPullRequest}}
+ on_build_success: false
+ on_build_failure: true
+ on_build_status_changed: false
diff --git a/.document b/.document
index b6dfcdeee0..3a6b0c238c 100644
--- a/.document
+++ b/.document
@@ -15,11 +15,10 @@ array.rb
ast.rb
dir.rb
gc.rb
-hash.rb
io.rb
kernel.rb
marshal.rb
-rjit.rb
+mjit.rb
numeric.rb
nilclass.rb
pack.rb
@@ -32,9 +31,6 @@ trace_point.rb
warning.rb
yjit.rb
-# Errno::*
-known_errors.inc
-
# the lib/ directory (which has its own .document file)
lib
@@ -52,4 +48,7 @@ COPYING.ja
LEGAL
+# win32/README.win32 linked from README.md
+win32
+
doc
diff --git a/.gdbinit b/.gdbinit
index 911624d8c9..34d044caf6 100644
--- a/.gdbinit
+++ b/.gdbinit
@@ -1,3 +1,5 @@
+set startup-with-shell off
+
define hook-run
set $color_type = 0
set $color_highlite = 0
@@ -65,7 +67,7 @@ define rp
printf "%sT_OBJECT%s: ", $color_type, $color_end
print ((struct RObject *)($arg0))->basic
if ($flags & ROBJECT_EMBED)
- print/x *((VALUE*)((struct RObject*)($arg0))->as.ary) @ (rb_shape_get_shape($arg0)->capacity)
+ print/x *((VALUE*)((struct RObject*)($arg0))->as.ary) @ (ROBJECT_EMBED_LEN_MAX+0)
else
print (((struct RObject *)($arg0))->as.heap)
if (((struct RObject*)($arg0))->as.heap.numiv) > 0
@@ -102,8 +104,8 @@ define rp
(($rsflags & (RUBY_FL_USER2|RUBY_FL_USER3|RUBY_FL_USER4|RUBY_FL_USER5|RUBY_FL_USER6)) >> RUBY_FL_USHIFT+2)
set print address off
output *(char *)(($rsflags & RUBY_FL_USER1) ? \
- ((struct RString*)$regsrc)->as.heap.ptr : \
- ((struct RString*)$regsrc)->as.ary) @ $len
+ ((struct RString*)$regsrc)->as.heap.ptr : \
+ ((struct RString*)$regsrc)->as.ary) @ $len
set print address on
printf " len:%ld ", $len
if $flags & RUBY_FL_USER6
@@ -124,26 +126,26 @@ define rp
printf "%sT_ARRAY%s: len=%ld ", $color_type, $color_end, $len
printf "(embed) "
if ($len == 0)
- printf "{(empty)} "
+ printf "{(empty)} "
else
- print/x *((VALUE*)((struct RArray*)($arg0))->as.ary) @ $len
- printf " "
+ print/x *((VALUE*)((struct RArray*)($arg0))->as.ary) @ $len
+ printf " "
end
else
set $len = ((struct RArray*)($arg0))->as.heap.len
printf "%sT_ARRAY%s: len=%ld ", $color_type, $color_end, $len
if ($flags & RUBY_FL_USER2)
- printf "(shared) shared="
- output/x ((struct RArray*)($arg0))->as.heap.aux.shared_root
- printf " "
+ printf "(shared) shared="
+ output/x ((struct RArray*)($arg0))->as.heap.aux.shared_root
+ printf " "
else
- printf "(ownership) capa=%ld ", ((struct RArray*)($arg0))->as.heap.aux.capa
+ printf "(ownership) capa=%ld ", ((struct RArray*)($arg0))->as.heap.aux.capa
end
if ($len == 0)
- printf "{(empty)} "
+ printf "{(empty)} "
else
- print/x *((VALUE*)((struct RArray*)($arg0))->as.heap.ptr) @ $len
- printf " "
+ print/x *((VALUE*)((struct RArray*)($arg0))->as.heap.ptr) @ $len
+ printf " "
end
end
print (struct RArray *)($arg0)
@@ -443,8 +445,8 @@ define output_string
(($flags & (RUBY_FL_USER2|RUBY_FL_USER3|RUBY_FL_USER4|RUBY_FL_USER5|RUBY_FL_USER6)) >> RUBY_FL_USHIFT+2)
if $len > 0
output *(char *)(($flags & RUBY_FL_USER1) ? \
- ((struct RString*)($arg0))->as.heap.ptr : \
- ((struct RString*)($arg0))->as.ary) @ $len
+ ((struct RString*)($arg0))->as.heap.ptr : \
+ ((struct RString*)($arg0))->as.ary) @ $len
else
output ""
end
@@ -457,8 +459,8 @@ define print_string
(($flags & (RUBY_FL_USER2|RUBY_FL_USER3|RUBY_FL_USER4|RUBY_FL_USER5|RUBY_FL_USER6)) >> RUBY_FL_USHIFT+2)
if $len > 0
printf "%s", *(char *)(($flags & RUBY_FL_USER1) ? \
- ((struct RString*)($arg0))->as.heap.ptr : \
- ((struct RString*)($arg0))->as.ary) @ $len
+ ((struct RString*)($arg0))->as.heap.ptr : \
+ ((struct RString*)($arg0))->as.ary) @ $len
end
end
@@ -687,6 +689,11 @@ define nd_stts
end
+define nd_entry
+ printf "%su3.entry%s: ", $color_highlite, $color_end
+ p ($arg0).u3.entry
+end
+
define nd_vid
printf "%su1.id%s: ", $color_highlite, $color_end
p ($arg0).u1.id
@@ -861,22 +868,22 @@ define rb_numtable_entry
set $rb_numtable_p = $rb_numtable_tbl->as.packed.bins
while $rb_numtable_p && $rb_numtable_p < $rb_numtable_tbl->as.packed.bins+$rb_numtable_tbl->num_entries
if $rb_numtable_p.k == $rb_numtable_id
- set $rb_numtable_key = $rb_numtable_p.k
- set $rb_numtable_rec = $rb_numtable_p.v
- set $rb_numtable_p = 0
+ set $rb_numtable_key = $rb_numtable_p.k
+ set $rb_numtable_rec = $rb_numtable_p.v
+ set $rb_numtable_p = 0
else
- set $rb_numtable_p = $rb_numtable_p + 1
+ set $rb_numtable_p = $rb_numtable_p + 1
end
end
else
set $rb_numtable_p = $rb_numtable_tbl->as.big.bins[st_numhash($rb_numtable_id) % $rb_numtable_tbl->num_bins]
while $rb_numtable_p
if $rb_numtable_p->key == $rb_numtable_id
- set $rb_numtable_key = $rb_numtable_p->key
- set $rb_numtable_rec = $rb_numtable_p->record
- set $rb_numtable_p = 0
+ set $rb_numtable_key = $rb_numtable_p->key
+ set $rb_numtable_rec = $rb_numtable_p->record
+ set $rb_numtable_p = 0
else
- set $rb_numtable_p = $rb_numtable_p->next
+ set $rb_numtable_p = $rb_numtable_p->next
end
end
end
@@ -954,7 +961,7 @@ define iseq
set $operand_size = ((INSN*)($arg0))->operand_size
set $operands = ((INSN*)($arg0))->operands
while $i < $operand_size
- rp $operands[$i++]
+ rp $operands[$i++]
end
end
end
@@ -1272,9 +1279,9 @@ document rb_count_objects
Counts all objects grouped by type.
end
-# Details: https://github.com/ruby/ruby/wiki/Machine-Instructions-Trace-with-GDB
+# Details: https://bugs.ruby-lang.org/projects/ruby-master/wiki/MachineInstructionsTraceWithGDB
define trace_machine_instructions
- set logging enabled
+ set logging on
set height 0
set width 0
display/i $pc
@@ -1341,8 +1348,3 @@ define print_flags
printf "RUBY_FL_USER17 : %s\n", ((struct RBasic*)($arg0))->flags & RUBY_FL_USER17 ? "1" : "0"
printf "RUBY_FL_USER18 : %s\n", ((struct RBasic*)($arg0))->flags & RUBY_FL_USER18 ? "1" : "0"
end
-
-source -s misc/gdb.py
-
-# Moved from beginning, since it fails on older gdbs
-set startup-with-shell off
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 60721014f7..6c5eac5a0f 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -5,10 +5,6 @@
# Expand tabs
5b21e94bebed90180d8ff63dad03b8b948361089
-c5e9af9c9d890578182a21e7b71b50334cd5579e
-e63a2115f64433b21cb5dd67c5bf8b30f87ef293
-712ac99e4d0384a941c80a9f48f62943ba7d97c0
-d1474affa8e105bece209cc9d594bb0a989859e1
# Enable Style/StringLiterals cop for RubyGems/Bundler
d7ffd3fea402239b16833cc434404a7af82d44f3
@@ -25,11 +21,3 @@ f28287d34c03f472ffe90ea262bdde9affd4b965
# Make benchmark indentation consistent
fc4acf8cae82e5196186d3278d831f2438479d91
-
-# Make prism_compile.c indentation consistent
-40b2c8e5e7e6e5f83cee9276dc9c1922a69292d6
-d2c5867357ed88eccc28c2b3bd4a46e206e7ff85
-
-# Miss-and-revived commits
-a0f7de814ae5c299d6ce99bed5fb308a05d50ba0
-d4e24021d39e1f80f0055b55d91f8d5f22e15084
diff --git a/.github/actions/compilers/action.yml b/.github/actions/compilers/action.yml
deleted file mode 100644
index aa23365e49..0000000000
--- a/.github/actions/compilers/action.yml
+++ /dev/null
@@ -1,101 +0,0 @@
-name: Compiles ruby in a container
-description: >-
- Makes ruby using a dedicated container
-
-inputs:
- tag:
- required: false
- default: clang-18
- description: >-
- container image tag to use in this run.
-
- with_gcc:
- required: false
- description: >-
- override compiler path & flags.
-
- CFLAGS:
- required: false
- description: >-
- C compiler flags to override.
-
- CXXFLAGS:
- required: false
- description: >-
- C++ compiler flags to override.
-
- optflags:
- required: false
- # -O1 is faster than -O3 in our tests... Majority of time are consumed trying
- # to optimize binaries. Also GitHub Actions run on relatively modern CPUs
- # compared to, say, GCC 4 or Clang 3. We don't specify `-march=native`
- # because compilers tend not understand what the CPU is.
- default: '-O1'
- description: >-
- Compiler flags for optimisations.
-
- cppflags:
- required: false
- description: >-
- Additional preprocessor flags.
-
- append_configure:
- required: false
- default: >-
- --without-valgrind
- --without-jemalloc
- --without-gmp
- description: >-
- flags to append to configure.
-
- enable_shared:
- required: false
- default: true
- description: >-
- Whether to build libruby.so.
-
- check:
- required: false
- default: ''
- description: >-
- Whether to run `make check`
-
- mspecopt:
- required: false
- default: ''
- description: >-
- Additional options for mspec.
-
- static_exts:
- required: false
- description: >-
- whitespace separated list of extensions that need be linked statically.
-
-runs:
- using: composite
- steps:
- - shell: bash
- run: docker pull --quiet 'ghcr.io/ruby/ruby-ci-image:${{ inputs.tag }}'
-
- - name: compile
- shell: bash
- run: >-
- docker run
- --rm
- --user=root
- --volume '${{ github.workspace }}:/github/workspace:ro'
- --workdir=/github/workspace
- --entrypoint=/github/workspace/.github/actions/compilers/entrypoint.sh
- --env CI
- --env GITHUB_ACTION
- --env INPUT_WITH_GCC='${{ inputs.with_gcc || inputs.tag }}'
- --env INPUT_CFLAGS='${{ inputs.CFLAGS }}'
- --env INPUT_CXXFLAGS='${{ inputs.CXXFLAGS }}'
- --env INPUT_OPTFLAGS='${{ inputs.OPTFLAGS }}'
- --env INPUT_CPPFLAGS='${{ inputs.cppflags }}'
- --env INPUT_APPEND_CONFIGURE='${{ inputs.append_configure }}'
- --env INPUT_CHECK='${{ inputs.check }}'
- --env INPUT_MSPECOPT='${{ inputs.mspecopt }}'
- --env INPUT_ENABLE_SHARED='${{ inputs.enable_shared }}'
- --env INPUT_STATIC_EXTS='${{ inputs.static_exts }}'
- 'ghcr.io/ruby/ruby-ci-image:${{ inputs.tag }}'
diff --git a/.github/actions/compilers/entrypoint.sh b/.github/actions/compilers/entrypoint.sh
deleted file mode 100755
index 198ac0e174..0000000000
--- a/.github/actions/compilers/entrypoint.sh
+++ /dev/null
@@ -1,96 +0,0 @@
-#! /bin/bash
-
-# Copyright (c) 2024 Ruby developers. All rights reserved.
-#
-# This file is a part of the programming language Ruby. Permission is hereby
-# granted, to either redistribute and/or modify this file, provided that the
-# conditions mentioned in the file COPYING are met. Consult the file for
-# details.
-
-grouped()
-{
- echo "::group::${@}"
- "${@}"
- echo "::endgroup::"
-}
-
-set -e
-set -u
-set -o pipefail
-
-srcdir="/github/workspace/src"
-builddir="$(mktemp -dt)"
-
-export GITHUB_WORKFLOW='Compilations'
-export CONFIGURE_TTY='never'
-export RUBY_DEBUG='ci rgengc'
-export RUBY_TESTOPTS='-q --color=always --tty=no'
-export RUBY_DEBUG_COUNTER_DISABLE='1'
-export GNUMAKEFLAGS="-j$((1 + $(nproc --all)))"
-
-case "x${INPUT_ENABLE_SHARED}" in
-x | xno | xfalse )
- enable_shared='--disable-shared'
- ;;
-*)
- enable_shared='--enable-shared'
- ;;
-esac
-
-pushd ${builddir}
-
-grouped ${srcdir}/configure \
- -C \
- --with-gcc="${INPUT_WITH_GCC}" \
- --enable-debug-env \
- --disable-install-doc \
- --with-ext=-test-/cxxanyargs,+ \
- ${enable_shared} \
- ${INPUT_APPEND_CONFIGURE} \
- CFLAGS="${INPUT_CFLAGS}" \
- CXXFLAGS="${INPUT_CXXFLAGS}" \
- optflags="${INPUT_OPTFLAGS}" \
- cppflags="${INPUT_CPPFLAGS}" \
- debugflags='-ggdb3' # -g0 disables backtraces when SEGV. Do not set that.
-
-popd
-
-if [[ -n "${INPUT_STATIC_EXTS}" ]]; then
- echo "::group::ext/Setup"
- set -x
- mkdir ${builddir}/ext
- (
- for ext in ${INPUT_STATIC_EXTS}; do
- echo "${ext}"
- done
- ) >> ${builddir}/ext/Setup
- set +x
- echo "::endgroup::"
-fi
-
-pushd ${builddir}
-
-case "${INPUT_APPEND_CONFIGURE}" in
-*--with-shared-gc*)
- export RUBY_GC_LIBRARY='librubygc.default.so'
- mkdir -p /home/runner/shared-gc
- grouped make shared-gc SHARED_GC=default
- ;;
-esac
-
-grouped make showflags
-grouped make all
-grouped make test
-
-[[ -z "${INPUT_CHECK}" ]] && exit 0
-
-if [ "$INPUT_CHECK" = "true" ]; then
- tests="ruby -ext-"
-else
- tests="$INPUT_CHECK"
-fi
-
-grouped make install
-grouped make test-tool
-grouped make test-all TESTS="-- $tests"
-grouped env CHECK_LEAKS=true make test-spec MSPECOPT="$INPUT_MSPECOPT"
diff --git a/.github/actions/launchable/setup/action.yml b/.github/actions/launchable/setup/action.yml
deleted file mode 100644
index 4b469ccd64..0000000000
--- a/.github/actions/launchable/setup/action.yml
+++ /dev/null
@@ -1,165 +0,0 @@
-name: Set up Launchable
-description: >-
- Install the required dependencies and execute the necessary Launchable commands for test recording
-
-inputs:
- report-path:
- default: launchable_reports.json
- required: true
- description: The file path of the test report for uploading to Launchable
-
- os:
- required: true
- description: The operating system that CI runs on. This value is used in Launchable flavor.
-
- test-opts:
- default: none
- required: false
- description: >-
- Test options that determine how tests are run.
- This value is used in the Launchable flavor.
-
- launchable-token:
- required: false
- description: >-
- Launchable token is needed if you want to run Launchable on your forked repository.
- See https://github.com/ruby/ruby/wiki/CI-Servers#launchable-ci for details.
-
- builddir:
- required: false
- default: ${{ github.workspace }}
- description: >-
- Directory to create Launchable report file.
-
- srcdir:
- required: false
- default: ${{ github.workspace }}
- description: >-
- Directory to (re-)checkout source codes. Launchable retrives the commit information
- from the directory.
-
- launchable-workspace:
- required: true
- default: ${{ github.event.repository.name }}
- description: >-
- A workspace name in Launchable
-
- test-task:
- required: true
- default: ${{ matrix.test_task }}
- description: >-
- A test task that determine which tests are executed.
- This value is used in the Launchable flavor.
-
-runs:
- using: composite
-
- steps:
- - name: Enable Launchable conditionally
- id: enable-launchable
- run: echo "enable-launchable=true" >> $GITHUB_OUTPUT
- shell: bash
- if: >-
- ${{
- (github.repository == 'ruby/ruby' ||
- (github.repository != 'ruby/ruby' && env.LAUNCHABLE_TOKEN)) &&
- (inputs.test-task == 'check' ||
- inputs.test-task == 'test-all' ||
- inputs.test-task == 'test')
- }}
-
- # Launchable CLI requires Python and Java.
- # https://www.launchableinc.com/docs/resources/cli-reference/
- - name: Set up Python
- uses: actions/setup-python@871daa956ca9ea99f3c3e30acb424b7960676734 # v5.0.0
- with:
- python-version: "3.x"
- if: steps.enable-launchable.outputs.enable-launchable
-
- - name: Set up Java
- uses: actions/setup-java@7a445ee88d4e23b52c33fdc7601e40278616c7f8 # v4.0.0
- with:
- distribution: 'temurin'
- java-version: '17'
- if: steps.enable-launchable.outputs.enable-launchable
-
- - name: Set environment variables for Launchable
- shell: bash
- run: |
- : # GITHUB_PULL_REQUEST_URL are used for commenting test reports in Launchable Github App.
- : # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/link.py#L42
- echo "GITHUB_PULL_REQUEST_URL=${{ github.event.pull_request.html_url }}" >> $GITHUB_ENV
- : # The following envs are necessary in Launchable tokenless authentication.
- : # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L20
- echo "LAUNCHABLE_ORGANIZATION=${{ github.repository_owner }}" >> $GITHUB_ENV
- echo "LAUNCHABLE_WORKSPACE=${{ inputs.launchable-workspace }}" >> $GITHUB_ENV
- : # https://github.com/launchableinc/cli/blob/v1.80.1/launchable/utils/authentication.py#L71
- echo "GITHUB_PR_HEAD_SHA=${{ github.event.pull_request.head.sha || github.sha }}" >> $GITHUB_ENV
- echo "LAUNCHABLE_TOKEN=${{ inputs.launchable-token }}" >> $GITHUB_ENV
- if: steps.enable-launchable.outputs.enable-launchable
-
- - name: Set up path
- shell: bash
- working-directory: ${{ inputs.srcdir }}
- # Since updated PATH variable will be available in only subsequent actions, we need to add the path beforehand.
- # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#adding-a-system-path
- run: echo "$(python -msite --user-base)/bin" >> $GITHUB_PATH
- if: steps.enable-launchable.outputs.enable-launchable && startsWith(inputs.os, 'macos')
-
- - name: Set up Launchable
- shell: bash
- working-directory: ${{ inputs.srcdir }}
- run: |
- set -x
- pip install --user launchable
- launchable verify || true
- : # The build name cannot include a slash, so we replace the string here.
- github_ref="${{ github.ref }}"
- github_ref="${github_ref//\//_}"
- : # With the --name option, we need to configure a unique identifier for this build.
- : # To avoid setting the same build name as the CI which runs on other branches, we use the branch name here.
- : #
- : # FIXME: Need to fix `WARNING: Failed to process a change to a file`.
- : # https://github.com/launchableinc/cli/issues/786
- launchable record build --name ${github_ref}_${GITHUB_PR_HEAD_SHA}
- echo "TESTS=${TESTS} --launchable-test-reports=${{ inputs.report-path }}" >> $GITHUB_ENV
- if: steps.enable-launchable.outputs.enable-launchable
-
- - name: Variables to report Launchable
- id: variables
- shell: bash
- run: |
- set -x
- : # flavor
- test_opts="${{ inputs.test-opts }}"
- test_opts="${test_opts// /}"
- test_opts="${test_opts//=/:}"
- echo test-opts="$test_opts" >> $GITHUB_OUTPUT
- : # report-path from srcdir
- if [ "${srcdir}" = "${{ github.workspace }}" ]; then
- dir=
- else
- # srcdir must be equal to or under workspace
- dir=$(echo ${srcdir:+${srcdir}/} | sed 's:[^/][^/]*/:../:g')
- fi
- report_path="${dir}${builddir:+${builddir}/}${report_path}"
- echo report-path="${report_path}" >> $GITHUB_OUTPUT
- if: steps.enable-launchable.outputs.enable-launchable
- env:
- srcdir: ${{ inputs.srcdir }}
- builddir: ${{ inputs.builddir }}
- report_path: ${{ inputs.report-path }}
-
- - name: Record test results in Launchable
- uses: gacts/run-and-post-run@674528335da98a7afc80915ff2b4b860a0b3553a # v1.4.0
- with:
- shell: bash
- working-directory: ${{ inputs.srcdir }}
- post: |
- : # record
- launchable record tests --flavor os=${{ inputs.os }} --flavor test_task=${{ inputs.test-task }} --flavor test_opts=${test_opts} raw ${report_path}
- rm -f ${report_path}
- if: ${{ always() && steps.enable-launchable.outputs.enable-launchable }}
- env:
- test_opts: ${{ steps.variables.outputs.test-opts }}
- report_path: ${{ steps.variables.outputs.report-path }}
diff --git a/.github/actions/setup/directories/action.yml b/.github/actions/setup/directories/action.yml
deleted file mode 100644
index d54c0f93f8..0000000000
--- a/.github/actions/setup/directories/action.yml
+++ /dev/null
@@ -1,176 +0,0 @@
-name: Setup directories etc.
-description: >-
- Set up the source code and build directories (plus some
- environmental tweaks)
-
-inputs:
- srcdir:
- required: false
- default: ${{ github.workspace }}
- description: >-
- Directory to (re-)checkout source codes. This will be created
- if absent. If there is no `configure` file that is also
- generated inside.
-
- builddir:
- required: false
- default: ${{ github.workspace }}
- description: >-
- Where binaries and other generated contents go. This will be
- created if absent.
-
- makeup:
- required: false
- type: boolean
- # Note that `default: false` evaluates to a string constant
- # `'false'`, which is a truthy value :sigh:
- # https://github.com/actions/runner/issues/2238
- default: ''
- description: >-
- If set to true, additionally runs `make up`.
-
- checkout:
- required: false
- type: boolean
- default: true
- description: >-
- If set to '' (false), skip running actions/checkout. This is useful when
- you don't want to overwrite a GitHub token that is already set up.
-
- dummy-files:
- required: false
- type: boolean
- default: ''
- description: >-
- If set to true, creates dummy files in build dir.
-
- fetch-depth:
- required: false
- default: '1'
- description: The depth of commit history fetched from the remote repository
-
- clean:
- required: false
- type: boolean
- default: ''
- description: >-
- If set to true, clean build directory.
-
-outputs: {} # nothing?
-
-runs:
- using: composite
-
- steps:
- # Note that `shell: bash` works on both Windows and Linux, but not
- # `shell: sh`. This is because GitHub hosted Windows runners have
- # their bash manually installed.
- - shell: bash
- run: |
- mkdir -p ${{ inputs.srcdir }}
- mkdir -p ${{ inputs.builddir }}
-
- # Did you know that actions/checkout works without git(1)? We are
- # checking that here.
- - id: which
- shell: bash
- run: |
- echo "git=`command -v git`" >> "$GITHUB_OUTPUT"
- echo "sudo=`command -v sudo`" >> "$GITHUB_OUTPUT"
- echo "autoreconf=`command -v autoreconf`" >> "$GITHUB_OUTPUT"
-
- - if: steps.which.outputs.git
- shell: bash
- run: |
- git config --global core.autocrlf false
- git config --global core.eol lf
- git config --global advice.detachedHead 0
- git config --global init.defaultBranch garbage
-
- - if: inputs.checkout
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with:
- path: ${{ inputs.srcdir }}
- fetch-depth: ${{ inputs.fetch-depth }}
-
- - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
- with:
- path: ${{ inputs.srcdir }}/.downloaded-cache
- key: downloaded-cache
-
- - if: steps.which.outputs.autoreconf
- shell: bash
- working-directory: ${{ inputs.srcdir }}
- run: ./autogen.sh --install
-
- # This is for MinGW.
- - if: runner.os == 'Windows'
- shell: bash
- run: echo "GNUMAKEFLAGS=-j$((2 * NUMBER_OF_PROCESSORS))" >> $GITHUB_ENV
-
- - if: runner.os == 'Linux'
- shell: bash
- run: echo "GNUMAKEFLAGS=-sj$((1 + $(nproc --all)))" >> "$GITHUB_ENV"
-
- # macOS' GNU make is so old that they doesn't understand `GNUMAKEFLAGS`.
- - if: runner.os == 'macOS'
- shell: bash
- run: echo "MAKEFLAGS=-j$((1 + $(sysctl -n hw.activecpu)))" >> "$GITHUB_ENV"
-
- - if: inputs.makeup
- shell: bash
- working-directory: ${{ inputs.srcdir }}
- run: |
- touch config.status
- touch .rbconfig.time
- sed -f tool/prereq.status template/Makefile.in > Makefile
- sed -f tool/prereq.status template/GNUmakefile.in > GNUmakefile
- make up
-
- # Cleanup, runs even on failure
- - if: always() && inputs.makeup
- shell: bash
- working-directory: ${{ inputs.srcdir }}
- run: rm -f config.status Makefile rbconfig.rb .rbconfig.time
-
- - if: steps.which.outputs.sudo
- shell: bash
- run: |
- sudo chmod -R go-w /usr/share
- chmod -v go-w $HOME $HOME/.config || :
- SAVE_IFS="$IFS" IFS=:; set $PATH; dirs=() IFS="$SAVE_IFS"
- for d do [ ! -d "$d" ] || dirs+=("$d"); done
- sudo chmod -v go-w "${dirs[@]}" || :
-
- - if: inputs.dummy-files == 'true'
- shell: bash
- id: dummy-files
- working-directory: ${{ inputs.builddir }}
- run: |
- : Create dummy files in build dir
- set {{a..z},{A..Z},{0..9},foo,bar,test,zzz}.rb
- for file; do \
- echo > $file "raise 'do not load $file'"; \
- done
- # drop {a..z}.rb if case-insensitive filesystem
- grep -F A.rb a.rb > /dev/null && set "${@:27}"
- echo clean="cd ${{ inputs.builddir }} && rm $*" >> $GITHUB_OUTPUT
-
- - if: inputs.clean == 'true'
- shell: bash
- id: clean
- run: |
- echo distclean='make -C ${{ inputs.builddir }} distclean' >> $GITHUB_OUTPUT
- echo remained-files='find ${{ inputs.builddir }} -ls' >> $GITHUB_OUTPUT
- [ "${{ inputs.builddir }}" = "${{ inputs.srcdir }}" ] ||
- echo final='rmdir ${{ inputs.builddir }}' >> $GITHUB_OUTPUT
-
- - name: clean
- uses: gacts/run-and-post-run@4683764dd706df847f57b9bed39d08164bcd2690 # v1.4.1
- with:
- working-directory:
- post: |
- ${{ steps.dummy-files.outputs.clean }}
- ${{ steps.clean.outputs.distclean }}
- ${{ steps.clean.outputs.remained-files }}
- ${{ steps.clean.outputs.final }}
diff --git a/.github/actions/setup/macos/action.yml b/.github/actions/setup/macos/action.yml
deleted file mode 100644
index 24ba48139a..0000000000
--- a/.github/actions/setup/macos/action.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-name: Setup macOS environment
-description: >-
- Installs necessary packages via Homebrew.
-
-inputs: {} # nothing?
-
-outputs: {} # nothing?
-
-runs:
- using: composite
-
- steps:
- - name: brew
- shell: bash
- run: |
- brew install --quiet gmp libffi openssl@3 zlib autoconf automake libtool
-
- - name: Set ENV
- shell: bash
- run: |
- for lib in gmp; do
- ruby_configure_args="${ruby_configure_args:+$ruby_configure_args }--with-${lib%@*}-dir=$(brew --prefix $lib)"
- done
- for lib in openssl@3; do
- CONFIGURE_ARGS="${CONFIGURE_ARGS:+$CONFIGURE_ARGS }--with-${lib%@*}-dir=$(brew --prefix $lib)"
- done
- echo ruby_configure_args="${ruby_configure_args}" >> $GITHUB_ENV
- echo CONFIGURE_ARGS="${CONFIGURE_ARGS}" >> $GITHUB_ENV
diff --git a/.github/actions/setup/ubuntu/action.yml b/.github/actions/setup/ubuntu/action.yml
deleted file mode 100644
index a9e5b41951..0000000000
--- a/.github/actions/setup/ubuntu/action.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-name: Setup ubuntu environment
-description: >-
- At the beginning there was no way but to copy & paste `apt-get`
- everywhere. But now that we have composite actions, it seems better
- merge them into one.
-
-inputs:
- arch:
- required: false
- default: ''
- description: >-
- Architecture. Because we run this on a GitHub-hosted runner
- acceptable value for this input is very limited.
-
-outputs:
- arch:
- value: ${{ steps.uname.outputs.uname }}
- description: >-
- Actual architecture. This could be different from the one
- passed to the `inputs.arch`. For instance giving `i386` to this
- action yields `i686`.
-
-runs:
- using: composite
-
- steps:
- - name: set SETARCH
- shell: bash
- run: echo "SETARCH=${setarch}" >> "$GITHUB_ENV"
- env:
- setarch: ${{ inputs.arch && format('setarch {0} --', inputs.arch) }}
-
- - id: uname
- name: uname
- shell: bash
- run: |
- echo uname=`${SETARCH} uname -m` >> "$GITHUB_OUTPUT"
- echo dpkg=`${SETARCH} uname -m | sed s/686/386/` >> "$GITHUB_OUTPUT"
-
- - name: apt-get
- shell: bash
- env:
- arch: ${{ inputs.arch && format(':{0}', steps.uname.outputs.dpkg) || '' }}
- run: |
- set -x
- ${arch:+sudo dpkg --add-architecture ${arch#:}}
- sudo apt-get update -qq || :
- sudo apt-get install --no-install-recommends -qq -y -o=Dpkg::Use-Pty=0 \
- ${arch:+cross}build-essential${arch/:/-} \
- libssl-dev${arch} libyaml-dev${arch} libreadline6-dev${arch} \
- zlib1g-dev${arch} libncurses5-dev${arch} libffi-dev${arch} \
- autoconf ruby
- sudo apt-get install -qq -y pkg-config${arch} || :
diff --git a/.github/actions/slack/action.yml b/.github/actions/slack/action.yml
deleted file mode 100644
index f0481f5bc2..0000000000
--- a/.github/actions/slack/action.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-name: Post a message to slack
-description: >-
- We have our ruby/action-slack webhook. However its arguments are
- bit verbose to be listed in every workflow files. Better merge them
- into one.
-
-inputs:
- SLACK_WEBHOOK_URL:
- required: true
- description: >-
- The URL to post the payload. This is an input because it tends
- to be stored in a secrets valut and a composite action cannot
- look into one.
-
- label:
- required: false
- description: >-
- Human-readable description of the run, something like "DEBUG=1".
- This need not be unique among runs.
-
-outputs: {} # Nothing?
-
-runs:
- using: composite
-
- steps:
- - uses: ruby/action-slack@54175162371f1f7c8eb94d7c8644ee2479fcd375 # v3.2.2
- with:
- payload: |
- {
- "ci": "GitHub Actions",
- "env": "${{ github.workflow }}${{ inputs.label && format(' / {0}', inputs.label) }}",
- "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
- "commit": "${{ github.sha }}",
- "branch": "${{ github.ref_name }}"
- }
- env:
- SLACK_WEBHOOK_URL: ${{ inputs.SLACK_WEBHOOK_URL }}
- if: ${{github.event_name == 'push' && startsWith(github.repository, 'ruby/')}}
diff --git a/.github/auto_request_review.yml b/.github/auto_request_review.yml
deleted file mode 100644
index 8726df577d..0000000000
--- a/.github/auto_request_review.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-files:
- 'yjit*': [team:yjit]
- 'yjit/**/*': [team:yjit]
- 'yjit/src/cruby_bindings.inc.rs': []
- 'doc/yjit/*': [team:yjit]
- 'bootstraptest/test_yjit*': [team:yjit]
- 'test/ruby/test_yjit*': [team:yjit]
-options:
- ignore_draft: true
- # This currently doesn't work as intended. We want to skip reviews when only
- # cruby_bingings.inc.rs is modified, but this skips reviews even when other
- # yjit files are modified as well. To be enabled after fixing the behavior.
- #last_files_match_only: true
diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml
new file mode 100644
index 0000000000..91f82b842b
--- /dev/null
+++ b/.github/codeql/codeql-config.yml
@@ -0,0 +1,3 @@
+name: "CodeQL config for the Ruby language"
+
+languages: cpp
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 426893be2a..bc63aca35b 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -3,16 +3,4 @@ updates:
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
- interval: 'daily'
- - package-ecosystem: 'github-actions'
- directory: '/.github/actions/slack'
- schedule:
- interval: 'daily'
- - package-ecosystem: 'github-actions'
- directory: '/.github/actions/setup/directories'
- schedule:
- interval: 'daily'
- - package-ecosystem: 'cargo'
- directory: '/yjit'
- schedule:
- interval: 'daily'
+ interval: 'monthly'
diff --git a/.github/workflows/annocheck.yml b/.github/workflows/annocheck.yml
deleted file mode 100644
index c9fefbb022..0000000000
--- a/.github/workflows/annocheck.yml
+++ /dev/null
@@ -1,112 +0,0 @@
-name: Annocheck
-
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- merge_group:
-
-concurrency:
- group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
- cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-
-permissions:
- contents: read
-
-jobs:
- compile:
- name: test-annocheck
-
- runs-on: ubuntu-latest
-
- container:
- image: ghcr.io/ruby/ruby-ci-image:gcc-11
- options: --user root
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
- env:
- CONFIGURE_TTY: never
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
- RUBY_DEBUG: ci rgengc
- RUBY_TESTOPTS: >-
- -q
- --color=always
- --tty=no
- # FIXME: Drop skipping options
- # https://bugs.ruby-lang.org/issues/18061
- # https://sourceware.org/annobin/annobin.html/Test-pie.html
- TEST_ANNOCHECK_OPTS: '--skip-pie --skip-gaps'
-
- steps:
- - run: id
- working-directory:
-
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/directories
- with:
- srcdir: src
- builddir: build
- makeup: true
-
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
- with:
- ruby-version: '3.0'
- bundler: none
-
- # Minimal flags to pass the check.
- # -g0 disables backtraces when SEGV. Do not set that.
- - name: Run configure
- run: >
- ../src/configure -C
- --enable-debug-env
- --disable-install-doc
- --with-ext=-test-/cxxanyargs,+
- --without-valgrind
- --without-jemalloc
- --without-gmp
- --with-gcc="gcc-11 -fcf-protection -Wa,--generate-missing-build-notes=yes"
- --enable-shared
- debugflags=-ggdb3
- optflags=-O2
- LDFLAGS=-Wl,-z,now
-
- - run: make showflags
-
- - run: make
-
- - run: make test-annocheck
-
- - uses: ./.github/actions/slack
- with:
- SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
-defaults:
- run:
- working-directory: build
diff --git a/.github/workflows/auto_request_review.yml b/.github/workflows/auto_request_review.yml
deleted file mode 100644
index ca27244b46..0000000000
--- a/.github/workflows/auto_request_review.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-name: Auto Request Review
-on:
- pull_request_target:
- types: [opened, ready_for_review, reopened]
-
-permissions:
- contents: read
-
-jobs:
- auto-request-review:
- name: Auto Request Review
- runs-on: ubuntu-latest
- if: ${{ github.repository == 'ruby/ruby' && github.base_ref == 'master' }}
- steps:
- - name: Request review based on files changes and/or groups the author belongs to
- uses: necojackarc/auto-request-review@e89da1a8cd7c8c16d9de9c6e763290b6b0e3d424 # v0.13.0
- with:
- # scope: public_repo
- token: ${{ secrets.MATZBOT_GITHUB_TOKEN }}
diff --git a/.github/workflows/baseruby.yml b/.github/workflows/baseruby.yml
index 3894c85d97..ebaafe3bf0 100644
--- a/.github/workflows/baseruby.yml
+++ b/.github/workflows/baseruby.yml
@@ -4,20 +4,24 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man/*'
+ - '**/man'
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man/*'
+ - '**/man'
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
merge_group:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -29,49 +33,48 @@ permissions:
jobs:
baseruby:
name: BASERUBY
-
- runs-on: ubuntu-20.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
+ runs-on: ubuntu-22.04
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
strategy:
matrix:
ruby:
+ - ruby-2.2
+# - ruby-2.3
+# - ruby-2.4
+# - ruby-2.5
+# - ruby-2.6
+# - ruby-2.7
- ruby-3.0
- ruby-3.1
- - ruby-3.2
- - ruby-3.3
steps:
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: .downloaded-cache
+ key: downloaded-cache
+ - uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
with:
ruby-version: ${{ matrix.ruby }}
bundler: none
-
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
-
- - uses: ./.github/actions/setup/ubuntu
-
- - uses: ./.github/actions/setup/directories
- with:
- makeup: true
-
+ - run: echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - run: sudo apt-get install build-essential autoconf bison libyaml-dev
+ - run: ./autogen.sh
- run: ./configure --disable-install-doc
-
+ - run: make common-srcs
+ - run: make incs
- run: make all
-
- run: make test
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.ruby }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / BASERUBY @ ${{ matrix.ruby }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
+ if: ${{ failure() && github.event_name == 'push' }}
diff --git a/.github/workflows/bundled_gems.yml b/.github/workflows/bundled_gems.yml
index 7d452ea876..070c0fa1dd 100644
--- a/.github/workflows/bundled_gems.yml
+++ b/.github/workflows/bundled_gems.yml
@@ -2,48 +2,54 @@ name: bundled_gems
on:
push:
- branches: ['master']
+ branches: [ "master" ]
paths:
- '.github/workflows/bundled_gems.yml'
- 'gems/bundled_gems'
pull_request:
- branches: ['master']
+ branches: [ "master" ]
paths:
- '.github/workflows/bundled_gems.yml'
- 'gems/bundled_gems'
merge_group:
+ branches: [ "master" ]
+ paths:
+ - '.github/workflows/bundled_gems.yml'
+ - 'gems/bundled_gems'
schedule:
- cron: '45 6 * * *'
workflow_dispatch:
-permissions: # added using https://github.com/step-security/secure-workflows
+permissions: # added using https://github.com/step-security/secure-workflows
contents: read
jobs:
update:
permissions:
- contents: write # for Git to git push
-
+ contents: write # for Git to git push
if: ${{ github.event_name != 'schedule' || github.repository == 'ruby/ruby' }}
-
name: update ${{ github.workflow }}
-
runs-on: ubuntu-latest
-
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with:
- token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
-
- - uses: ./.github/actions/setup/directories
- with:
- # Skip overwriting MATZBOT_GITHUB_TOKEN
- checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
- name: Set ENV
run: |
+ echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
echo "TODAY=$(date +%F)" >> $GITHUB_ENV
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: .downloaded-cache
+ key: downloaded-cache-${{ github.sha }}
+ restore-keys: |
+ downloaded-cache
+
- name: Download previous gems list
run: |
data=bundled_gems.json
@@ -52,84 +58,109 @@ jobs:
curl -O -R -z ./$data https://stdgems.org/$data
- name: Update bundled gems list
- id: bundled_gems
- run: |
- ruby -i~ tool/update-bundled_gems.rb gems/bundled_gems >> $GITHUB_OUTPUT
-
- - name: Update spec/bundler/support/builders.rb
run: |
- #!ruby
- rake_version = File.read("gems/bundled_gems")[/^rake\s+(\S+)/, 1]
- print ARGF.read.sub(/^ *def rake_version\s*\K".*?"/) {rake_version.dump}
- shell: ruby -i~ {0} spec/bundler/support/builders.rb
+ ruby -i~ tool/update-bundled_gems.rb gems/bundled_gems
- name: Maintain updated gems list in NEWS
run: |
- ruby tool/update-NEWS-gemlist.rb bundled
+ #!ruby
+ require 'json'
+ news = File.read("NEWS.md")
+ prev = news[/since the \*+(\d+\.\d+\.\d+)\*+/, 1]
+ prevs = [prev, prev.sub(/\.\d+\z/, '')]
+ %W[bundled].each do |type|
+ last = JSON.parse(File.read("#{type}_gems.json"))['gems'].filter_map do |g|
+ v = g['versions'].values_at(*prevs).compact.first
+ g = g['gem']
+ g = 'RubyGems' if g == 'rubygems'
+ [g, v] if v
+ end.to_h
+ changed = File.foreach("gems/#{type}_gems").filter_map do |l|
+ next if l.start_with?("#")
+ g, v = l.split(" ", 3)
+ [g, v] unless last[g] == v
+ end
+ changed, added = changed.partition {|g, _| last[g]}
+ news.sub!(/^\*( +)The following #{type} gems? are updated\.\n+\K(?: \1\*( +).*\n)*/) do
+ mark = "#{$1} *#{$2}"
+ changed.map {|g, v|"#{mark}#{g} #{v}\n"}.join("")
+ end or next
+ news.sub!(/^\*( +)The following default gems are now bundled gems\.\n+\K(?: \1\*( +).*\n)*/) do
+ mark = "#{$1} *#{$2}"
+ added.map {|g, v|"#{mark}#{g} #{v}\n"}.join("")
+ end or next unless added.empty?
+ File.write("NEWS.md", news)
+ end
+ shell: ruby {0}
- name: Check diffs
id: diff
run: |
- news= gems=
- git diff --color --no-ext-diff --ignore-submodules --exit-code -- NEWS.md ||
- news=true
- git diff --color --no-ext-diff --ignore-submodules --exit-code -- gems/bundled_gems ||
- gems=true
- git add -- NEWS.md gems/bundled_gems
- git add -- spec/bundler/support/builders.rb
- echo news=$news >> $GITHUB_OUTPUT
- echo gems=$gems >> $GITHUB_OUTPUT
- echo update=${news:-$gems} >> $GITHUB_OUTPUT
+ git add -- NEWS.md
+ git diff --no-ext-diff --ignore-submodules --quiet -- gems/bundled_gems
+ continue-on-error: true
- name: Install libraries
- uses: ./.github/actions/setup/ubuntu
- if: ${{ steps.diff.outputs.gems }}
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
+ if: ${{ steps.diff.outcome == 'failure' }}
- name: Build
run: |
./autogen.sh
./configure -C --disable-install-doc
make
- if: ${{ steps.diff.outputs.gems }}
+ if: ${{ steps.diff.outcome == 'failure' }}
- name: Prepare bundled gems
run: |
make -s prepare-gems
- if: ${{ steps.diff.outputs.gems }}
+ if: ${{ steps.diff.outcome == 'failure' }}
- name: Test bundled gems
run: |
make -s test-bundled-gems
+ git add -- gems/bundled_gems
timeout-minutes: 30
env:
- RUBY_TESTOPTS: '-q --tty=no'
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
- if: ${{ steps.diff.outputs.gems }}
+ RUBY_TESTOPTS: "-q --tty=no"
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ""
+ if: ${{ steps.diff.outcome == 'failure' }}
+
+ - name: Show diffs
+ id: show
+ run: |
+ git diff --cached --color --no-ext-diff --ignore-submodules --exit-code --
+ continue-on-error: true
- name: Commit
run: |
git pull --ff-only origin ${GITHUB_REF#refs/heads/}
- message="Update bundled gems list"
- if [ -z "${gems}" ]; then
- git commit --message="${message} at ${GITHUB_SHA:0:30} [ci skip]"
+ message="Update bundled gems list at "
+ if [ ${{ steps.diff.outcome }} = success ]; then
+ git commit --message="${message}${GITHUB_SHA:0:30} [ci skip]"
else
- git commit --message="${message} as of ${TODAY}"
+ git commit --message="${message}${TODAY}"
fi
git push origin ${GITHUB_REF#refs/heads/}
env:
- TODAY: ${{ steps.bundled_gems.outputs.latest_date || env.TODAY }}
EMAIL: svn-admin@ruby-lang.org
GIT_AUTHOR_NAME: git
GIT_COMMITTER_NAME: git
- gems: ${{ steps.diff.outputs.gems }}
- if: >-
- ${{
- github.repository == 'ruby/ruby' &&
- !startsWith(github.event_name, 'pull') &&
- steps.diff.outputs.update
- }}
-
- - uses: ./.github/actions/slack
+ if: ${{ github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull') && steps.show.outcome == 'failure' }}
+
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / update",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
+ if: ${{ failure() && github.event_name == 'push' }}
diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml
index b416b36597..79b2916feb 100644
--- a/.github/workflows/check_dependencies.yml
+++ b/.github/workflows/check_dependencies.yml
@@ -3,20 +3,24 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man/*'
+ - '**/man'
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man/*'
+ - '**/man'
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
merge_group:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -29,50 +33,46 @@ jobs:
update-deps:
strategy:
matrix:
- os: [ubuntu-20.04]
+ os: [ubuntu-22.04]
fail-fast: true
-
runs-on: ${{ matrix.os }}
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
-
- - uses: ./.github/actions/setup/ubuntu
+ - name: Install libraries
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
if: ${{ contains(matrix.os, 'ubuntu') }}
-
- - uses: ./.github/actions/setup/macos
+ - name: Install libraries
+ run: |
+ brew install gmp libffi openssl@1.1 zlib autoconf automake libtool readline
if: ${{ contains(matrix.os, 'macos') }}
-
- - uses: ./.github/actions/setup/directories
-
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
- ruby-version: '3.0'
- bundler: none
-
+ path: .downloaded-cache
+ key: downloaded-cache
+ - run: ./autogen.sh
- name: Run configure
run: ./configure -C --disable-install-doc --disable-rubygems --with-gcc 'optflags=-O0' 'debugflags=-save-temps=obj -g'
-
- run: make all golf
-
- - run: ./goruby -veh
-
- run: ruby tool/update-deps --fix
-
- run: git diff --no-ext-diff --ignore-submodules --exit-code
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.os }} / Dependencies need to update
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ matrix.os }} / Dependencies need to update",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
+ if: ${{ failure() && github.event_name == 'push' }}
diff --git a/.github/workflows/check_misc.yml b/.github/workflows/check_misc.yml
deleted file mode 100644
index 7da7dd0af7..0000000000
--- a/.github/workflows/check_misc.yml
+++ /dev/null
@@ -1,117 +0,0 @@
-name: Misc
-on: [push, pull_request, merge_group]
-
-concurrency:
- group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
- cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-
-permissions:
- contents: read
-
-jobs:
- checks:
- name: Miscellaneous checks
-
- permissions:
- contents: write # for Git to git push
-
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with:
- token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
-
- - uses: ./.github/actions/setup/directories
- with:
- makeup: true
- # Skip overwriting MATZBOT_GITHUB_TOKEN
- checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
-
- - name: Check if C-sources are US-ASCII
- run: |
- grep -r -n --include='*.[chyS]' --include='*.asm' $'[^\t-~]' -- . && exit 1 || :
-
- - name: Check for trailing spaces
- run: |
- git grep -I -n $'[\t ]$' -- '*.rb' '*.[chy]' '*.rs' '*.yml' && exit 1 || :
- git grep -n $'^[\t ][\t ]*$' -- '*.md' && exit 1 || :
-
- - name: Check for bash specific substitution in configure.ac
- run: |
- git grep -n '\${[A-Za-z_0-9]*/' -- configure.ac && exit 1 || :
-
- - name: Check for header macros
- run: |
- fail=
- for header in ruby/*.h; do
- git grep -l -F -e $header -e HAVE_`echo $header | tr a-z./ A-Z__` -- . > /dev/null && continue
- fail=1
- echo $header
- done
- exit $fail
- working-directory: include
-
- - id: gems
- run: true
- if: ${{ github.ref == 'refs/heads/master' }}
-
- - name: Download previous gems list
- run: |
- data=default_gems.json
- mkdir -p .downloaded-cache
- ln -s .downloaded-cache/$data .
- curl -O -R -z ./$data https://stdgems.org/$data
- if: ${{ steps.gems.outcome == 'success' }}
-
- - name: Make default gems list
- run: |
- #!ruby
- require 'rubygems'
- $:.unshift "lib"
- rgver = File.foreach("lib/rubygems.rb") do |line|
- break $1 if /^\s*VERSION\s*=\s*"([^"]+)"/ =~ line
- end
- gems = Dir.glob("{ext,lib}/**/*.gemspec").map do |f|
- spec = Gem::Specification.load(f)
- "#{spec.name} #{spec.version}"
- end.sort
- File.open("gems/default_gems", "w") do |f|
- f.puts "RubyGems #{rgver}"
- f.puts gems
- end
- shell: ruby --disable=gems {0}
- if: ${{ steps.gems.outcome == 'success' }}
-
- - name: Maintain updated gems list in NEWS
- run: |
- ruby tool/update-NEWS-gemlist.rb default
- if: ${{ steps.gems.outcome == 'success' }}
-
- - name: Check diffs
- id: diff
- run: |
- git diff --color --no-ext-diff --ignore-submodules --exit-code NEWS.md ||
- echo update=true >> $GITHUB_OUTPUT
- if: ${{ steps.gems.outcome == 'success' }}
-
- - name: Commit
- run: |
- git pull --ff-only origin ${GITHUB_REF#refs/heads/}
- git commit --message="Update default gems list at ${GITHUB_SHA:0:30} [ci skip]" NEWS.md
- git push origin ${GITHUB_REF#refs/heads/}
- env:
- EMAIL: svn-admin@ruby-lang.org
- GIT_AUTHOR_NAME: git
- GIT_COMMITTER_NAME: git
- if: >-
- ${{
- github.repository == 'ruby/ruby' &&
- !startsWith(github.event_name, 'pull') &&
- steps.diff.outputs.update
- }}
-
- - uses: ./.github/actions/slack
- with:
- SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 676047cc9c..8dba76fbe2 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -1,23 +1,20 @@
-name: 'CodeQL'
+name: "Code scanning - action"
on:
- push:
- branches: ['master']
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
+ # push:
+ # paths-ignore:
+ # - 'doc/**'
+ # - '**/man'
+ # - '**.md'
+ # - '**.rdoc'
+ # - '**/.document'
+ # pull_request:
+ # paths-ignore:
+ # - 'doc/**'
+ # - '**/man'
+ # - '**.md'
+ # - '**.rdoc'
+ # - '**/.document'
schedule:
- cron: '0 12 * * *'
workflow_dispatch:
@@ -26,96 +23,53 @@ concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-permissions: # added using https://github.com/step-security/secure-workflows
+permissions: # added using https://github.com/step-security/secure-workflows
contents: read
jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-latest
+ CodeQL-Build:
+
+ # CodeQL runs on ubuntu-latest and windows-latest
permissions:
- actions: read # for github/codeql-action/init to get workflow details
- contents: read # for actions/checkout to fetch code
- security-events: write # for github/codeql-action/autobuild to send a status report
+ actions: read # for github/codeql-action/init to get workflow details
+ contents: read # for actions/checkout to fetch code
+ security-events: write # for github/codeql-action/autobuild to send a status report
+ runs-on: ubuntu-latest
# CodeQL fails to run pull requests from dependabot due to missing write access to upload results.
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') && github.event.head_commit.pusher.name != 'dependabot[bot]' }}
env:
enable_install_doc: no
- strategy:
- fail-fast: false
- matrix:
- include:
- - language: cpp
- - language: ruby
-
steps:
- - name: Checkout repository
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
-
- - name: Install libraries
- if: ${{ contains(matrix.os, 'macos') }}
- uses: ./.github/actions/setup/macos
-
- - name: Install libraries
- if : ${{ matrix.os == 'ubuntu-latest' }}
- uses: ./.github/actions/setup/ubuntu
+ - name: Install libraries
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
- - uses: ./.github/actions/setup/directories
+ - name: Checkout repository
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- - name: Remove an obsolete rubygems vendored file
- if: ${{ matrix.os == 'ubuntu-latest' }}
- run: sudo rm /usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: .downloaded-cache
+ key: downloaded-cache
- - name: Initialize CodeQL
- uses: github/codeql-action/init@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11
- with:
- languages: ${{ matrix.language }}
+ - name: Remove an obsolete rubygems vendored file
+ run: sudo rm /usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb
- - name: Autobuild
- uses: github/codeql-action/autobuild@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37
+ with:
+ config-file: ./.github/codeql/codeql-config.yml
+ trap-caching: false
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11
- with:
- category: '/language:${{ matrix.language }}'
- upload: False
- output: sarif-results
+ - name: Set ENV
+ run: echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
- - name: filter-sarif
- uses: advanced-security/filter-sarif@f3b8118a9349d88f7b1c0c488476411145b6270d # v1.0.1
- with:
- patterns: |
- +**/*.rb
- -lib/uri/mailto.rb:rb/overly-large-range
- -lib/uri/rfc3986_parser.rb:rb/overly-large-range
- -lib/bundler/vendor/uri/lib/uri/mailto.rb:rb/overly-large-range
- -lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb:rb/overly-large-range
- -test/ruby/test_io.rb:rb/non-constant-kernel-open
- -test/open-uri/test_open-uri.rb:rb/non-constant-kernel-open
- -test/open-uri/test_ssl.rb:rb/non-constant-kernel-open
- -spec/ruby/core/io/binread_spec.rb:rb/non-constant-kernel-open
- -spec/ruby/core/io/readlines_spec.rb:rb/non-constant-kernel-open
- -spec/ruby/core/io/foreach_spec.rb:rb/non-constant-kernel-open
- -spec/ruby/core/io/write_spec.rb:rb/non-constant-kernel-open
- -spec/ruby/core/io/read_spec.rb:rb/non-constant-kernel-open
- -spec/ruby/core/kernel/open_spec.rb:rb/non-constant-kernel-open
- input: sarif-results/${{ matrix.language }}.sarif
- output: sarif-results/${{ matrix.language }}.sarif
- if: ${{ matrix.language == 'ruby' }}
- continue-on-error: true
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37
- - name: Upload SARIF
- uses: github/codeql-action/upload-sarif@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11
- with:
- sarif_file: sarif-results/${{ matrix.language }}.sarif
- continue-on-error: true
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37
diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml
index 3fb3813d0c..caf12cc0f4 100644
--- a/.github/workflows/compilers.yml
+++ b/.github/workflows/compilers.yml
@@ -1,386 +1,280 @@
-# Some tests depending on this name 'Compilations' via $GITHUB_WORKFLOW. Make sure to update such tests when renaming this workflow.
name: Compilations
on:
push:
paths-ignore:
- 'doc/**'
- - '**/man/*'
+ - '**/man'
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man/*'
- - '**.md'
+ - '**/man'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
merge_group:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.rdoc'
+ - '**/.document'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
+# GitHub actions does not support YAML anchors. This creative use of
+# environment variables (plus the "echo $GITHUB_ENV" hack) is to reroute that
+# restriction.
+env:
+ default_cc: clang-15
+ append_cc: ''
+
+ # -O1 is faster than -O3 in our tests... Majority of time are consumed trying
+ # to optimize binaries. Also GitHub Actions run on relatively modern CPUs
+ # compared to, say, GCC 4 or Clang 3. We don't specify `-march=native`
+ # because compilers tend not understand what the CPU is.
+ optflags: '-O1'
+
+ # -g0 disables backtraces when SEGV. Do not set that.
+ debugflags: '-ggdb3'
+
+ default_configure: >-
+ --enable-debug-env
+ --disable-install-doc
+ --with-ext=-test-/cxxanyargs,+
+ append_configure: >-
+ --without-valgrind
+ --without-jemalloc
+ --without-gmp
+
+ UPDATE_UNICODE: >-
+ UNICODE_FILES=.
+ UNICODE_PROPERTY_FILES=.
+ UNICODE_AUXILIARY_FILES=.
+ UNICODE_EMOJI_FILES=.
+ CONFIGURE_TTY: never
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
+ RUBY_DEBUG: ci rgengc
+ RUBY_TESTOPTS: >-
+ -q
+ --color=always
+ --tty=no
+
permissions:
contents: read
-# Each job is split so that they roughly take 30min to run through.
jobs:
- compile1:
- name: 'omnibus compilations, #1'
- runs-on: ubuntu-latest
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
- - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true } }
- - name: 'clang 18 LTO'
- uses: './.github/actions/compilers'
- with:
- tag: clang-18
- with_gcc: 'clang-18 -flto=auto'
- optflags: '-O2'
- enable_shared: false
- - name: 'GCC 13 LTO'
- uses: './.github/actions/compilers'
- with:
- tag: gcc-13
- with_gcc: 'gcc-13 -flto=auto -ffat-lto-objects -Werror=lto-type-mismatch'
- optflags: '-O2'
- enable_shared: false
+ compile:
+ strategy:
+ fail-fast: false
+ matrix:
+ env:
+ - {}
+ entry:
+ - { name: gcc-12, env: { default_cc: gcc-12 } }
+ - { name: gcc-11, env: { default_cc: gcc-11 } }
+ - { name: gcc-10, env: { default_cc: gcc-10 } }
+ - { name: gcc-9, env: { default_cc: gcc-9 } }
+ - { name: gcc-8, env: { default_cc: gcc-8 } }
+ - { name: gcc-7, env: { default_cc: gcc-7 } }
+ - name: 'gcc-13 LTO'
+ container: gcc-13
+ env:
+ default_cc: 'gcc-13 -flto=auto -ffat-lto-objects -Werror=lto-type-mismatch'
+ optflags: '-O2'
+ shared: disable
+ # check: true
+ - { name: clang-16, env: { default_cc: clang-16 } }
+ - { name: clang-15, env: { default_cc: clang-15 } }
+ - { name: clang-14, env: { default_cc: clang-14 } }
+ - { name: clang-13, env: { default_cc: clang-13 } }
+ - { name: clang-12, env: { default_cc: clang-12 } }
+ - { name: clang-11, env: { default_cc: clang-11 } }
+ - { name: clang-10, env: { default_cc: clang-10 } }
+ # llvm-objcopy<=9 doesn't have --wildcard. It compiles, but leaves Rust symbols in libyjit.o.
+ - { name: clang-9, env: { default_cc: clang-9, append_configure: '--disable-yjit' } }
+ - { name: clang-8, env: { default_cc: clang-8, append_configure: '--disable-yjit' } }
+ - { name: clang-7, env: { default_cc: clang-7, append_configure: '--disable-yjit' } }
+ - { name: clang-6.0, env: { default_cc: clang-6.0, append_configure: '--disable-yjit' } }
+ - name: 'clang-16 LTO'
+ container: clang-16
+ env:
+ default_cc: 'clang-16 -flto=auto'
+ optflags: '-O2'
+ shared: disable
+ # check: true
- compile2:
- name: 'omnibus compilations, #2'
- runs-on: ubuntu-latest
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
- - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true } }
- - { uses: './.github/actions/compilers', name: 'GCC 13', with: { tag: 'gcc-13' } }
- - { uses: './.github/actions/compilers', name: 'GCC 12', with: { tag: 'gcc-12' } }
- - { uses: './.github/actions/compilers', name: 'GCC 11', with: { tag: 'gcc-11' } }
- - { uses: './.github/actions/compilers', name: 'GCC 10', with: { tag: 'gcc-10' } }
- - { uses: './.github/actions/compilers', name: 'GCC 9', with: { tag: 'gcc-9' } }
- - { uses: './.github/actions/compilers', name: 'GCC 8', with: { tag: 'gcc-8' } }
- - { uses: './.github/actions/compilers', name: 'GCC 7', with: { tag: 'gcc-7' } }
+# - { name: aarch64-linux-gnu, crosshost: aarch64-linux-gnu, container: crossbuild-essential-arm64 }
+# - { name: arm-linux-gnueabi, crosshost: arm-linux-gnueabi }
+# - { name: arm-linux-gnueabihf, crosshost: arm-linux-gnueabihf }
+# - { name: i686-w64-mingw32, crosshost: i686-w64-mingw32 }
+# - { name: powerpc-linux-gnu, crosshost: powerpc-linux-gnu }
+# - { name: powerpc64le-linux-gnu, crosshost: powerpc64le-linux-gnu, container: crossbuild-essential-ppc64el }
+# - { name: s390x-linux-gnu, crosshost: s390x-linux-gnu, container: crossbuild-essential-s390x }
+# - { name: x86_64-w64-mingw32, crosshost: x86_64-w64-mingw32, container: mingw-w64 }
- compile3:
- name: 'omnibus compilations, #3'
- runs-on: ubuntu-latest
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
- - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true } }
- - { uses: './.github/actions/compilers', name: 'clang 20', with: { tag: 'clang-20' } }
- - { uses: './.github/actions/compilers', name: 'clang 19', with: { tag: 'clang-19' } }
- - { uses: './.github/actions/compilers', name: 'clang 18', with: { tag: 'clang-18' } }
- - { uses: './.github/actions/compilers', name: 'clang 17', with: { tag: 'clang-17' } }
- - { uses: './.github/actions/compilers', name: 'clang 16', with: { tag: 'clang-16' } }
- - { uses: './.github/actions/compilers', name: 'clang 15', with: { tag: 'clang-15' } }
- - { uses: './.github/actions/compilers', name: 'clang 14', with: { tag: 'clang-14' } }
- - { uses: './.github/actions/compilers', name: 'clang 13', with: { tag: 'clang-13' } }
- - { uses: './.github/actions/compilers', name: 'clang 12', with: { tag: 'clang-12' } }
+ # -Wno-strict-prototypes is necessary with current clang-15 since
+ # older autoconf generate functions without prototype and -pedantic
+ # now implies strict-prototypes. Disabling the error but leaving the
+ # warning generates a lot of noise from use of ANYARGS in
+ # rb_define_method() and friends.
+ # See: https://github.com/llvm/llvm-project/commit/11da1b53d8cd3507959022cd790d5a7ad4573d94
+ - { name: c99, env: { append_cc: '-std=c99 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
+# - { name: c11, env: { append_cc: '-std=c11 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
+# - { name: c17, env: { append_cc: '-std=c17 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
+ - { name: c2x, env: { append_cc: '-std=c2x -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
+ - { name: c++98, env: { CXXFLAGS: '-std=c++98 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
+# - { name: c++11, env: { CXXFLAGS: '-std=c++11 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
+# - { name: c++14, env: { CXXFLAGS: '-std=c++14 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
+# - { name: c++17, env: { CXXFLAGS: '-std=c++17 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
+ - { name: c++2a, env: { CXXFLAGS: '-std=c++2a -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- compile4:
- name: 'omnibus compilations, #4'
- runs-on: ubuntu-latest
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
- - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true } }
- - { uses: './.github/actions/compilers', name: 'clang 11', with: { tag: 'clang-11' } }
- - { uses: './.github/actions/compilers', name: 'clang 10', with: { tag: 'clang-10' } }
- # llvm-objcopy<=9 doesn't have --wildcard. It compiles, but leaves Rust symbols in libyjit.o.
- - { uses: './.github/actions/compilers', name: 'clang 9', with: { tag: 'clang-9', append_configure: '--disable-yjit' } }
- - { uses: './.github/actions/compilers', name: 'clang 8', with: { tag: 'clang-8', append_configure: '--disable-yjit' } }
- - { uses: './.github/actions/compilers', name: 'clang 7', with: { tag: 'clang-7', append_configure: '--disable-yjit' } }
- - { uses: './.github/actions/compilers', name: 'clang 6', with: { tag: 'clang-6.0', append_configure: '--disable-yjit' } }
- - { uses: './.github/actions/compilers', name: 'ext/Setup', with: { static_exts: 'etc json/* */escape' } }
+ - { name: '-O0', env: { optflags: '-O0 -march=x86-64 -mtune=generic' } }
+# - { name: '-O3', env: { optflags: '-O3 -march=x86-64 -mtune=generic' }, check: true }
- compile5:
- name: 'omnibus compilations, #5'
- runs-on: ubuntu-latest
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
- - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true } }
- # -Wno-strict-prototypes is necessary with current clang-15 since
- # older autoconf generate functions without prototype and -pedantic
- # now implies strict-prototypes. Disabling the error but leaving the
- # warning generates a lot of noise from use of ANYARGS in
- # rb_define_method() and friends.
- # See: https://github.com/llvm/llvm-project/commit/11da1b53d8cd3507959022cd790d5a7ad4573d94
- - { uses: './.github/actions/compilers', name: 'C99', with: { CFLAGS: '-std=c99 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
- - { uses: './.github/actions/compilers', name: 'C11', with: { CFLAGS: '-std=c11 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
- - { uses: './.github/actions/compilers', name: 'C17', with: { CFLAGS: '-std=c17 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
- - { uses: './.github/actions/compilers', name: 'C23', with: { CFLAGS: '-std=c2x -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' } }
- - { uses: './.github/actions/compilers', name: 'C++98', with: { CXXFLAGS: '-std=c++98 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- - { uses: './.github/actions/compilers', name: 'C++11', with: { CXXFLAGS: '-std=c++11 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- - { uses: './.github/actions/compilers', name: 'C++14', with: { CXXFLAGS: '-std=c++14 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- - { uses: './.github/actions/compilers', name: 'C++17', with: { CXXFLAGS: '-std=c++17 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- - { uses: './.github/actions/compilers', name: 'C++20', with: { CXXFLAGS: '-std=c++20 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- - { uses: './.github/actions/compilers', name: 'C++23', with: { CXXFLAGS: '-std=c++23 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
- - { uses: './.github/actions/compilers', name: 'C++26', with: { CXXFLAGS: '-std=c++26 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' } }
+ - { name: gmp, env: { append_configure: '--with-gmp' } }
+ - { name: jemalloc, env: { append_configure: '--with-jemalloc' } }
+ - { name: valgrind, env: { append_configure: '--with-valgrind' } }
+ - { name: 'coroutine=ucontext', env: { append_configure: '--with-coroutine=ucontext' } }
+ - { name: 'coroutine=pthread', env: { append_configure: '--with-coroutine=pthread' } }
+ - { name: disable-jit-support, env: { append_configure: '--disable-jit-support' } }
+ - { name: disable-dln, env: { append_configure: '--disable-dln' } }
+ - { name: enable-mkmf-verbose, env: { append_configure: '--enable-mkmf-verbose' } }
+ - { name: disable-rubygems, env: { append_configure: '--disable-rubygems' } }
+ - { name: RUBY_DEVEL, env: { append_configure: '--enable-devel' } }
- compile6:
- name: 'omnibus compilations, #6'
- runs-on: ubuntu-latest
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
- - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true } }
- - { uses: './.github/actions/compilers', name: '-O0', with: { optflags: '-O0 -march=x86-64 -mtune=generic' } }
- # - { uses: './.github/actions/compilers', name: '-O3', with: { optflags: '-O3 -march=x86-64 -mtune=generic', check: true } }
- - { uses: './.github/actions/compilers', name: 'gmp', with: { append_configure: '--with-gmp', check: 'ruby/test_bignum.rb', mspecopt: "/github/workspace/src/spec/ruby/core/integer" } }
- - { uses: './.github/actions/compilers', name: 'jemalloc', with: { append_configure: '--with-jemalloc' } }
- - { uses: './.github/actions/compilers', name: 'valgrind', with: { append_configure: '--with-valgrind' } }
- - { uses: './.github/actions/compilers', name: 'coroutine=ucontext', with: { append_configure: '--with-coroutine=ucontext' } }
- - { uses: './.github/actions/compilers', name: 'coroutine=pthread', with: { append_configure: '--with-coroutine=pthread' } }
+ - { name: OPT_THREADED_CODE=1, env: { cppflags: '-DOPT_THREADED_CODE=1' } }
+ - { name: OPT_THREADED_CODE=2, env: { cppflags: '-DOPT_THREADED_CODE=2' } }
+ - { name: OPT_THREADED_CODE=3, env: { cppflags: '-DOPT_THREADED_CODE=3' } }
- compile7:
- name: 'omnibus compilations, #7'
- runs-on: ubuntu-latest
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
- - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true } }
- - { uses: './.github/actions/compilers', name: 'disable-jit', with: { append_configure: '--disable-yjit --disable-rjit' } }
- - { uses: './.github/actions/compilers', name: 'disable-dln', with: { append_configure: '--disable-dln' } }
- - { uses: './.github/actions/compilers', name: 'enable-mkmf-verbose', with: { append_configure: '--enable-mkmf-verbose' } }
- - { uses: './.github/actions/compilers', name: 'disable-rubygems', with: { append_configure: '--disable-rubygems' } }
- - { uses: './.github/actions/compilers', name: 'RUBY_DEVEL', with: { append_configure: '--enable-devel' } }
- - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=0', with: { cppflags: '-DOPT_THREADED_CODE=0' } }
- - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=1', with: { cppflags: '-DOPT_THREADED_CODE=1' } }
- - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=2', with: { cppflags: '-DOPT_THREADED_CODE=2' } }
+ - { name: NDEBUG, env: { cppflags: '-DNDEBUG' } }
+ - { name: RUBY_DEBUG, env: { cppflags: '-DRUBY_DEBUG' } }
+# - { name: ARRAY_DEBUG, env: { cppflags: '-DARRAY_DEBUG' } }
+# - { name: BIGNUM_DEBUG, env: { cppflags: '-DBIGNUM_DEBUG' } }
+# - { name: CCAN_LIST_DEBUG, env: { cppflags: '-DCCAN_LIST_DEBUG' } }
+# - { name: CPDEBUG=-1, env: { cppflags: '-DCPDEBUG=-1' } }
+# - { name: ENC_DEBUG, env: { cppflags: '-DENC_DEBUG' } }
+# - { name: GC_DEBUG, env: { cppflags: '-DGC_DEBUG' } }
+# - { name: HASH_DEBUG, env: { cppflags: '-DHASH_DEBUG' } }
+# - { name: ID_TABLE_DEBUG, env: { cppflags: '-DID_TABLE_DEBUG' } }
+# - { name: RGENGC_DEBUG=-1, env: { cppflags: '-DRGENGC_DEBUG=-1' } }
+# - { name: SYMBOL_DEBUG, env: { cppflags: '-DSYMBOL_DEBUG' } }
- compile8:
- name: 'omnibus compilations, #8'
- runs-on: ubuntu-latest
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
- - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true } }
- - { uses: './.github/actions/compilers', name: 'NDEBUG', with: { cppflags: '-DNDEBUG' } }
- - { uses: './.github/actions/compilers', name: 'RUBY_DEBUG', with: { cppflags: '-DRUBY_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'ARRAY_DEBUG', with: { cppflags: '-DARRAY_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'BIGNUM_DEBUG', with: { cppflags: '-DBIGNUM_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'CCAN_LIST_DEBUG', with: { cppflags: '-DCCAN_LIST_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'CPDEBUG=-1', with: { cppflags: '-DCPDEBUG=-1' } }
- - { uses: './.github/actions/compilers', name: 'ENC_DEBUG', with: { cppflags: '-DENC_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'GC_DEBUG', with: { cppflags: '-DGC_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'HASH_DEBUG', with: { cppflags: '-DHASH_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'ID_TABLE_DEBUG', with: { cppflags: '-DID_TABLE_DEBUG' } }
+# - { name: RGENGC_CHECK_MODE, env: { cppflags: '-DRGENGC_CHECK_MODE' } }
+# - { name: TRANSIENT_HEAP_CHECK_MODE, env: { cppflags: '-DTRANSIENT_HEAP_CHECK_MODE' } }
+# - { name: VM_CHECK_MODE, env: { cppflags: '-DVM_CHECK_MODE' } }
- compile9:
- name: 'omnibus compilations, #9'
- runs-on: ubuntu-latest
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
- - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true } }
- - { uses: './.github/actions/compilers', name: 'RGENGC_DEBUG=-1', with: { cppflags: '-DRGENGC_DEBUG=-1' } }
- - { uses: './.github/actions/compilers', name: 'SYMBOL_DEBUG', with: { cppflags: '-DSYMBOL_DEBUG' } }
- - { uses: './.github/actions/compilers', name: 'RGENGC_CHECK_MODE', with: { cppflags: '-DRGENGC_CHECK_MODE' } }
- - { uses: './.github/actions/compilers', name: 'VM_CHECK_MODE', with: { cppflags: '-DVM_CHECK_MODE' } }
- - { uses: './.github/actions/compilers', name: 'USE_EMBED_CI=0', with: { cppflags: '-DUSE_EMBED_CI=0' } }
- - { uses: './.github/actions/compilers', name: 'USE_FLONUM=0', with: { cppflags: '-DUSE_FLONUM=0', append_configure: '--disable-yjit' } }
- - { uses: './.github/actions/compilers', name: 'USE_LAZY_LOAD', with: { cppflags: '-DUSE_LAZY_LOAD' } }
- - { uses: './.github/actions/compilers', name: 'USE_SYMBOL_GC=0', with: { cppflags: '-DUSE_SYMBOL_GC=0' } }
- - { uses: './.github/actions/compilers', name: 'USE_THREAD_CACHE=0', with: { cppflags: '-DUSE_THREAD_CACHE=0' } }
+ - { name: USE_EMBED_CI=0, env: { cppflags: '-DUSE_EMBED_CI=0' } }
+ - name: USE_FLONUM=0,
+ env:
+ cppflags: '-DUSE_FLONUM=0'
+ # yjit requires FLONUM for the pointer tagging scheme
+ append_configure: '--disable-yjit'
+# - { name: USE_GC_MALLOC_OBJ_INFO_DETAILS, env: { cppflags: '-DUSE_GC_MALLOC_OBJ_INFO_DETAILS' } }
+ - { name: USE_LAZY_LOAD, env: { cppflags: '-DUSE_LAZY_LOAD' } }
+# - { name: USE_RINCGC=0, env: { cppflags: '-DUSE_RINCGC=0' } }
+# - { name: USE_SYMBOL_GC=0, env: { cppflags: '-DUSE_SYMBOL_GC=0' } }
+# - { name: USE_THREAD_CACHE=0, env: { cppflags: '-DUSE_THREAD_CACHE=0' } }
+# - { name: USE_TRANSIENT_HEAP=0, env: { cppflags: '-DUSE_TRANSIENT_HEAP=0' } }
+# - { name: USE_RUBY_DEBUG_LOG=1, env: { cppflags: '-DUSE_RUBY_DEBUG_LOG=1' } }
+ - { name: USE_RVARGC=0, env: { cppflags: '-DUSE_RVARGC=0' } }
+# - { name: USE_RVARGC=1, env: { cppflags: '-DUSE_RVARGC=1' } }
+# - { name: USE_DEBUG_COUNTER, env: { cppflags: '-DUSE_DEBUG_COUNTER=1', RUBY_DEBUG_COUNTER_DISABLE: '1' } }
- compileX:
- name: 'omnibus compilations, #10'
- runs-on: ubuntu-latest
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
- - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true } }
- - { uses: './.github/actions/compilers', name: 'USE_RUBY_DEBUG_LOG=1', with: { cppflags: '-DUSE_RUBY_DEBUG_LOG=1' } }
- - { uses: './.github/actions/compilers', name: 'USE_DEBUG_COUNTER', with: { cppflags: '-DUSE_DEBUG_COUNTER=1' } }
- - { uses: './.github/actions/compilers', name: 'SHARABLE_MIDDLE_SUBSTRING', with: { cppflags: '-DSHARABLE_MIDDLE_SUBSTRING=1' } }
- - { uses: './.github/actions/compilers', name: 'DEBUG_FIND_TIME_NUMGUESS', with: { cppflags: '-DDEBUG_FIND_TIME_NUMGUESS' } }
- - { uses: './.github/actions/compilers', name: 'DEBUG_INTEGER_PACK', with: { cppflags: '-DDEBUG_INTEGER_PACK' } }
- - { uses: './.github/actions/compilers', name: 'GC_DEBUG_STRESS_TO_CLASS', with: { cppflags: '-DGC_DEBUG_STRESS_TO_CLASS' } }
- - { uses: './.github/actions/compilers', name: 'GC_ENABLE_LAZY_SWEEP=0', with: { cppflags: '-DGC_ENABLE_LAZY_SWEEP=0' } }
- - { uses: './.github/actions/compilers', name: 'GC_PROFILE_DETAIL_MEMORY', with: { cppflags: '-DGC_PROFILE_DETAIL_MEMORY' } }
+ - { name: DEBUG_FIND_TIME_NUMGUESS, env: { cppflags: '-DDEBUG_FIND_TIME_NUMGUESS' } }
+ - { name: DEBUG_INTEGER_PACK, env: { cppflags: '-DDEBUG_INTEGER_PACK' } }
+# - { name: ENABLE_PATH_CHECK, env: { cppflags: '-DENABLE_PATH_CHECK' } }
- compileB:
- name: 'omnibus compilations, #11'
- runs-on: ubuntu-latest
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
- - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true } }
- - { uses: './.github/actions/compilers', name: 'GC_PROFILE_MORE_DETAIL', with: { cppflags: '-DGC_PROFILE_MORE_DETAIL' } }
- - { uses: './.github/actions/compilers', name: 'MALLOC_ALLOCATED_SIZE_CHECK', with: { cppflags: '-DMALLOC_ALLOCATED_SIZE_CHECK' } }
- - { uses: './.github/actions/compilers', name: 'RGENGC_ESTIMATE_OLDMALLOC', with: { cppflags: '-DRGENGC_ESTIMATE_OLDMALLOC' } }
- # - { uses: './.github/actions/compilers', name: 'RGENGC_FORCE_MAJOR_GC', with: { cppflags: '-DRGENGC_FORCE_MAJOR_GC' } }
- - { uses: './.github/actions/compilers', name: 'RGENGC_OBJ_INFO', with: { cppflags: '-DRGENGC_OBJ_INFO' } }
- - { uses: './.github/actions/compilers', name: 'RGENGC_PROFILE', with: { cppflags: '-DRGENGC_PROFILE' } }
- - { uses: './.github/actions/compilers', name: 'VM_DEBUG_BP_CHECK', with: { cppflags: '-DVM_DEBUG_BP_CHECK' } }
- - { uses: './.github/actions/compilers', name: 'VM_DEBUG_VERIFY_METHOD_CACHE', with: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' } }
+ - { name: GC_DEBUG_STRESS_TO_CLASS, env: { cppflags: '-DGC_DEBUG_STRESS_TO_CLASS' } }
+# - { name: GC_ENABLE_LAZY_SWEEP=0, env: { cppflags: '-DGC_ENABLE_LAZY_SWEEP=0' } }
+# - { name: GC_PROFILE_DETAIL_MEMOTY, env: { cppflags: '-DGC_PROFILE_DETAIL_MEMOTY' } }
+# - { name: GC_PROFILE_MORE_DETAIL, env: { cppflags: '-DGC_PROFILE_MORE_DETAIL' } }
- compileC:
- name: 'omnibus compilations, #12'
- runs-on: ubuntu-latest
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
- services: { docuum: { image: 'stephanmisc/docuum', options: '--init', volumes: [ '/root', '/var/run/docker.sock:/var/run/docker.sock' ] } }
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
- - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true } }
- - { uses: './.github/actions/compilers', name: 'enable-yjit', with: { append_configure: '--enable-yjit --disable-rjit' } }
- - { uses: './.github/actions/compilers', name: 'enable-rjit', with: { append_configure: '--enable-rjit --disable-yjit' } }
- - { uses: './.github/actions/compilers', name: 'YJIT_FORCE_ENABLE', with: { cppflags: '-DYJIT_FORCE_ENABLE' } }
- - { uses: './.github/actions/compilers', name: 'RJIT_FORCE_ENABLE', with: { cppflags: '-DRJIT_FORCE_ENABLE' } }
- - { uses: './.github/actions/compilers', name: 'UNIVERSAL_PARSER', with: { cppflags: '-DUNIVERSAL_PARSER' } }
+# - { name: CALC_EXACT_MALLOC_SIZE, env: { cppflags: '-DCALC_EXACT_MALLOC_SIZE' } }
+# - { name: MALLOC_ALLOCATED_SIZE_CHECK, env: { cppflags: '-DMALLOC_ALLOCATED_SIZE_CHECK' } }
+
+# - { name: IBF_ISEQ_ENABLE_LOCAL_BUFFER, env: { cppflags: '-DIBF_ISEQ_ENABLE_LOCAL_BUFFER' } }
+
+# - { name: RGENGC_ESTIMATE_OLDMALLOC, env: { cppflags: '-DRGENGC_ESTIMATE_OLDMALLOC' } }
+# - { name: RGENGC_FORCE_MAJOR_GC, env: { cppflags: '-DRGENGC_FORCE_MAJOR_GC' } }
+# - { name: RGENGC_OBJ_INFO, env: { cppflags: '-DRGENGC_OBJ_INFO' } }
+# - { name: RGENGC_OLD_NEWOBJ_CHECK, env: { cppflags: '-DRGENGC_OLD_NEWOBJ_CHECK' } }
+# - { name: RGENGC_PROFILE, env: { cppflags: '-DRGENGC_PROFILE' } }
- compilemax:
- name: 'omnibus compilations, result'
+# - { name: VM_DEBUG_BP_CHECK, env: { cppflags: '-DVM_DEBUG_BP_CHECK' } }
+# - { name: VM_DEBUG_VERIFY_METHOD_CACHE, env: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' } }
+
+ - { name: MJIT_FORCE_ENABLE, env: { cppflags: '-DMJIT_FORCE_ENABLE' } }
+ - { name: YJIT_FORCE_ENABLE, env: { cppflags: '-DYJIT_FORCE_ENABLE' } }
+
+ name: ${{ matrix.entry.name }}
runs-on: ubuntu-latest
- if: ${{ always() }}
- needs:
- - 'compile1'
- - 'compile2'
- - 'compile3'
- - 'compile4'
- - 'compile5'
- - 'compile6'
- - 'compile7'
- - 'compile8'
- - 'compile9'
- - 'compileX'
- - 'compileB'
- - 'compileC'
+ container:
+ image: ghcr.io/ruby/ruby-ci-image:${{ matrix.entry.container || matrix.entry.env.default_cc || 'clang-15' }}
+ options: --user root
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
+ env: ${{ matrix.entry.env || matrix.env }}
steps:
- - uses: ./.github/actions/slack
+ - run: id
+ working-directory:
+ - run: mkdir build
+ working-directory:
+ - name: setenv
+ run: |
+ echo "GNUMAKEFLAGS=-sj$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
- label: 'omnibus'
+ path: src/.downloaded-cache
+ key: downloaded-cache
+ - run: ./autogen.sh
+ working-directory: src
+ - name: Run configure
+ run: >
+ ../src/configure -C ${default_configure} ${append_configure}
+ --${{
+ matrix.entry.crosshost && 'host' || 'with-gcc'
+ }}=${{
+ matrix.entry.crosshost || '"${default_cc}${append_cc:+ $append_cc}"'
+ }}
+ --${{ matrix.entry.shared || 'enable' }}-shared
+ - run: make extract-extlibs
+ - run: make incs
+ - run: make showflags
+ - run: make
+ - run: make leaked-globals
+ - run: make test
+ - run: make install
+ if: ${{ matrix.entry.check }}
+ - run: make test-tool
+ if: ${{ matrix.entry.check }}
+ - run: make test-all TESTS='-- ruby -ext-'
+ if: ${{ matrix.entry.check }}
+ - run: make test-spec
+ env:
+ CHECK_LEAKS: true
+ if: ${{ matrix.entry.check }}
+ - run: make test-annocheck
+ if: ${{ matrix.entry.check && endsWith(matrix.entry.name, 'annocheck') }}
+
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
+ with:
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / ${{ matrix.entry.name }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
- - run: false
- working-directory:
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml
deleted file mode 100644
index 69ab5d9131..0000000000
--- a/.github/workflows/dependabot_automerge.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-# from https://github.com/gofiber/swagger/blob/main/.github/workflows/dependabot_automerge.yml
-name: Dependabot auto-merge
-on:
- pull_request_target:
-
-jobs:
- automerge:
- runs-on: ubuntu-latest
-
- if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}
-
- steps:
- - name: Dependabot metadata
- uses: dependabot/fetch-metadata@dbb049abf0d677abbd7f7eee0375145b417fdd34 # v2.2.0
- id: metadata
-
- - name: Wait for status checks
- uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc # v1.3.4
- with:
- repo-token: ${{ secrets.MATZBOT_GITHUB_TOKEN }}
- ref: ${{ github.event.pull_request.head.sha || github.sha }}
- check-regexp: 'make \(check, .*\)'
- wait-interval: 30
-
- - name: Auto-merge for Dependabot PRs
- if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-minor' || steps.metadata.outputs.update-type == 'version-update:semver-patch' }}
- run: gh pr merge --auto --rebase "$PR_URL"
- env:
- PR_URL: ${{ github.event.pull_request.html_url }}
- GITHUB_TOKEN: ${{ secrets.MATZBOT_GITHUB_TOKEN }}
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index dfdfa3c011..d8dc58b119 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -3,15 +3,24 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man/*'
+ - '**/man'
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
- # Do not use paths-ignore for required status checks
- # https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
merge_group:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -24,164 +33,80 @@ jobs:
make:
strategy:
matrix:
- include:
- - test_task: check
- os: macos-14
- - test_task: test-all
- test_opts: --repeat-count=2
- os: macos-14
- - test_task: test-bundler-parallel
- os: macos-14
- - test_task: test-bundled-gems
- os: macos-14
- - test_task: check
- os: macos-12
- - test_task: check
- os: macos-13
+ test_task: ["check"] # "test-bundler-parallel", "test-bundled-gems"
+ os:
+ - macos-13
+ - macos-14
+ - macos-15
fail-fast: false
-
env:
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
-
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
runs-on: ${{ matrix.os }}
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - run: mkdir build
+ working-directory:
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - name: Install libraries
- uses: ./.github/actions/setup/macos
-
- - uses: ./.github/actions/setup/directories
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
- srcdir: src
- builddir: build
- makeup: true
- clean: true
- dummy-files: ${{ matrix.test_task == 'check' }}
- # Set fetch-depth: 0 so that Launchable can receive commits information.
- fetch-depth: 10
-
- - name: make sure that kern.coredump=1
+ path: src/.downloaded-cache
+ key: downloaded-cache
+ - name: Install libraries
run: |
- sysctl -n kern.coredump
- sudo sysctl -w kern.coredump=1
- sudo chmod -R +rwx /cores/
-
- - name: Delete unused SDKs
- # To free up disk space to not run out during the run
+ brew install gmp libffi openssl@1.1 zlib autoconf automake libtool readline bison
+ working-directory: src
+ - name: Set ENV
run: |
- sudo rm -rf ~/.dotnet
- sudo rm -rf /Library/Android
- sudo rm -rf /Library/Developer/CoreSimulator
- continue-on-error: true
-
+ echo "MAKEFLAGS=-j$((1 + $(sysctl -n hw.activecpu)))" >> $GITHUB_ENV
+ echo "PATH="/usr/local/opt/bison/bin:/opt/homebrew/opt/bison/bin:$PATH"" >> $GITHUB_ENV
+ - run: ./autogen.sh
+ working-directory: src
- name: Run configure
- run: ../src/configure -C --disable-install-doc ${ruby_configure_args}
-
+ run: ../src/configure -C --disable-install-doc --with-openssl-dir=$(brew --prefix openssl@1.1) --with-readline-dir=$(brew --prefix readline)
+ - run: make incs
- run: make prepare-gems
if: ${{ matrix.test_task == 'test-bundled-gems' }}
-
- run: make
-
- - run: |
- make golf
- case "${{ matrix.configure }}" in
- *'--enable-shared'*)
- make runnable
- ./bin/goruby -veh
- ;;
- *)
- ./goruby -veh
- ;;
- esac
-
- - name: Set test options for skipped tests
- run: |
- set -x
- TESTS="$(echo "${{ matrix.skipped_tests }}" | sed 's| |$$/ -n!/|g;s|^|-n!/|;s|$|$$/|')"
- echo "TESTS=${TESTS}" >> $GITHUB_ENV
- if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
-
- - name: Set up Launchable
- uses: ./.github/actions/launchable/setup
- with:
- os: ${{ matrix.os }}
- test-opts: ${{ matrix.test_opts }}
- launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
- builddir: build
- srcdir: src
- continue-on-error: true
-
- - name: Set extra test options
- run: |
- echo "TESTS=$TESTS ${{ matrix.test_opts }}" >> $GITHUB_ENV
- echo "RUBY_TEST_TIMEOUT_SCALE=10" >> $GITHUB_ENV # With --repeat-count=2, flaky test by timeout occurs frequently for some reason
- if: matrix.test_opts
-
+ - run: make leaked-globals
+ if: ${{ matrix.test_task == 'check' }}
- name: make ${{ matrix.test_task }}
run: |
- ulimit -c unlimited
- make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
- timeout-minutes: 60
+ make -s ${{ matrix.test_task }} ${TESTS:+TESTS=`echo "$TESTS" | sed 's| |$$/ -n!/|g;s|^|-n!/|;s|$|$$/|'`}
+ timeout-minutes: 40
env:
- RUBY_TESTOPTS: '-q --tty=no'
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
- PRECHECK_BUNDLED_GEMS: 'no'
-
+ RUBY_TESTOPTS: "-q --tty=no"
+ TESTS: ${{ matrix.test_task == 'check' && matrix.skipped_tests || '' }}
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ""
+ PRECHECK_BUNDLED_GEMS: "no"
- name: make skipped tests
run: |
- make -s test-all TESTS="${TESTS//-n!\//-n/}"
+ make -s test-all TESTS=`echo "$TESTS" | sed 's| |$$/ -n/|g;s|^|-n/|;s|$|$$/|'`
env:
- GNUMAKEFLAGS: ''
- RUBY_TESTOPTS: '-v --tty=no'
- PRECHECK_BUNDLED_GEMS: 'no'
- if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
+ GNUMAKEFLAGS: ""
+ RUBY_TESTOPTS: "-v --tty=no"
+ TESTS: ${{ matrix.skipped_tests }}
+ PRECHECK_BUNDLED_GEMS: "no"
+ if: ${{ matrix.test_task == 'check' && matrix.skipped_tests != '' }}
continue-on-error: ${{ matrix.continue-on-skipped_tests || false }}
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.os }} / ${{ matrix.test_task }}
- SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
- - name: Resolve job ID
- id: job_id
- uses: actions/github-script@main
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ matrix.os }} / ${{ matrix.test_task }}${{ matrix.configure }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
env:
- matrix: ${{ toJson(matrix) }}
- with:
- script: |
- const { data: workflow_run } = await github.rest.actions.listJobsForWorkflowRun({
- owner: context.repo.owner,
- repo: context.repo.repo,
- run_id: context.runId
- });
- const matrix = JSON.parse(process.env.matrix);
- const job_name = `${context.job}${matrix ? ` (${Object.values(matrix).join(", ")})` : ""}`;
- return workflow_run.jobs.find((job) => job.name === job_name).id;
-
- result:
- if: ${{ always() }}
- name: ${{ github.workflow }} result
- runs-on: macos-latest
- needs: [make]
- steps:
- - run: exit 1
- working-directory:
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml
index 149f9fbe83..0df917d3d8 100644
--- a/.github/workflows/mingw.yml
+++ b/.github/workflows/mingw.yml
@@ -3,20 +3,24 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man/*'
+ - '**/man'
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man/*'
+ - '**/man'
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
merge_group:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -31,140 +35,143 @@ permissions:
jobs:
make:
runs-on: windows-2022
-
name: ${{ github.workflow }} (${{ matrix.msystem }})
-
env:
MSYSTEM: ${{ matrix.msystem }}
MSYS2_ARCH: x86_64
- CHOST: 'x86_64-w64-mingw32'
- CFLAGS: '-march=x86-64 -mtune=generic -O3 -pipe'
- CXXFLAGS: '-march=x86-64 -mtune=generic -O3 -pipe'
- CPPFLAGS: '-D_FORTIFY_SOURCE=2 -D__USE_MINGW_ANSI_STDIO=1 -DFD_SETSIZE=2048'
- LDFLAGS: '-pipe'
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
-
+ CHOST: "x86_64-w64-mingw32"
+ CFLAGS: "-march=x86-64 -mtune=generic -O3 -pipe"
+ CXXFLAGS: "-march=x86-64 -mtune=generic -O3 -pipe"
+ CPPFLAGS: "-D_FORTIFY_SOURCE=2 -D__USE_MINGW_ANSI_STDIO=1 -DFD_SETSIZE=2048"
+ LDFLAGS: "-pipe"
+ UPDATE_UNICODE: "UNICODE_FILES=. UNICODE_PROPERTY_FILES=. UNICODE_AUXILIARY_FILES=. UNICODE_EMOJI_FILES=."
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
strategy:
matrix:
include:
# To mitigate flakiness of MinGW CI, we test only one runtime that newer MSYS2 uses.
- # Ruby 3.2 is the first Windows Ruby to use OpenSSL 3.x
- - msystem: 'UCRT64'
- baseruby: '3.2'
- test_task: 'check'
- test-all-opts: '--name=!/TestObjSpace#test_reachable_objects_during_iteration/'
+ - msystem: "UCRT64"
+ base_ruby: head
+ test_task: "check"
+ test-all-opts: "--name=!/TestObjSpace#test_reachable_objects_during_iteration/"
fail-fast: false
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
steps:
+ - run: mkdir build
+ working-directory:
+ - name: git config
+ run: |
+ git config --global core.autocrlf false
+ git config --global core.eol lf
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: src/.downloaded-cache
+ key: downloaded-cache
- name: Set up Ruby & MSYS2
- uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
with:
- ruby-version: ${{ matrix.baseruby }}
+ ruby-version: ${{ matrix.base_ruby }}
+ - name: set env
+ run: |
+ echo "GNUMAKEFLAGS=-j$((2 * NUMBER_OF_PROCESSORS))" >> $GITHUB_ENV
- - name: Misc system & package info
- working-directory:
+ - name: where check
run: |
# show where
+ mv /c/Windows/System32/libcrypto-1_1-x64.dll /c/Windows/System32/libcrypto-1_1-x64.dll_
+ mv /c/Windows/System32/libssl-1_1-x64.dll /c/Windows/System32/libssl-1_1-x64.dll_
result=true
- for e in gcc.exe ragel.exe make.exe libcrypto-3-x64.dll libssl-3-x64.dll; do
- echo ::group::$'\033[93m'$e$'\033[m'
+ for e in gcc.exe ragel.exe make.exe bison.exe libcrypto-1_1-x64.dll libssl-1_1-x64.dll; do
+ echo '##['group']'$'\033[93m'$e$'\033[m'
where $e || result=false
- echo ::endgroup::
+ echo '##['endgroup']'
done
+ $result
+
+ - name: version check
+ run: |
# show version
- for e in gcc ragel make "openssl version"; do
+ result=true
+ for e in gcc ragel make bison "openssl version"; do
case "$e" in *" "*) ;; *) e="$e --version";; esac
- echo ::group::$'\033[93m'$e$'\033[m'
+ echo '##['group']'$'\033[93m'$e$'\033[m'
$e || result=false
- echo ::endgroup::
+ echo '##['endgroup']'
done
- # show packages
- echo ::group::$'\033[93m'Packages$'\033[m'
- pacman -Qs mingw-w64-ucrt-x86_64-* | sed -n "s,local/mingw-w64-ucrt-x86_64-,,p"
- echo ::endgroup::
$result
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/directories
- with:
- srcdir: src
- builddir: build
- makeup: true
- # Set fetch-depth: 10 so that Launchable can receive commits information.
- fetch-depth: 10
+ - name: autogen
+ run: |
+ ./autogen.sh
+ working-directory: src
- name: configure
run: >
../src/configure --disable-install-doc --prefix=/.
--build=$CHOST --host=$CHOST --target=$CHOST
+ - name: update
+ run: |
+ make incs
+
+ - name: download gems
+ run: |
+ make update-gems
+
- name: make all
timeout-minutes: 30
- run: make
+ run: |
+ make
- - name: make install
- run: make DESTDIR=../install install-nodoc
+ - run: make leaked-globals
- - name: Set up Launchable
- uses: ./.github/actions/launchable/setup
- with:
- os: windows-2022
- # If we support new test task, we need to change this test-opts.
- test-opts: --retry --job-status=normal --show-skip --timeout-scale=1.5
- ${{ matrix.test-all-opts }}
- launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
- builddir: build
- srcdir: src
- continue-on-error: true
+ - name: make install
+ run: |
+ make DESTDIR=../install install-nodoc
- name: test
- timeout-minutes: 30
- run: make test
- shell: cmd
- env:
- GNUMAKEFLAGS: ''
- RUBY_TESTOPTS: '-v --tty=no'
- if: ${{ matrix.test_task == 'check' || matrix.test_task == 'test' }}
+ timeout-minutes: 5
+ run: |
+ make test
+ if: ${{matrix.test_task == 'check' || matrix.test_task == 'test'}}
- name: test-all
timeout-minutes: 45
- shell: cmd
run: |
+ # Actions uses UTF8, causes test failures, similar to normal OS setup
+ chcp.com 437
make ${{ StartsWith(matrix.test_task, 'test/') && matrix.test_task || 'test-all' }}
env:
RUBY_TESTOPTS: >-
--retry --job-status=normal --show-skip --timeout-scale=1.5
${{ matrix.test-all-opts }}
- ${{ env.TESTS }}
BUNDLER_VERSION:
- if: ${{ matrix.test_task == 'check' || matrix.test_task == 'test-all' || StartsWith(matrix.test_task, 'test/') }}
+ if: ${{matrix.test_task == 'check' || matrix.test_task == 'test-all' || StartsWith(matrix.test_task, 'test/')}}
- name: test-spec
timeout-minutes: 10
run: |
make ${{ StartsWith(matrix.test_task, 'spec/') && matrix.test_task || 'test-spec' }}
- shell: cmd
- if: ${{ matrix.test_task == 'check' || matrix.test_task == 'test-spec' || StartsWith(matrix.test_task, 'spec/') }}
+ if: ${{matrix.test_task == 'check' || matrix.test_task == 'test-spec' || StartsWith(matrix.test_task, 'spec/')}}
- - uses: ./src/.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.msystem }} / ${{ matrix.test_task }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} ${{ matrix.msystem }} / ${{ matrix.test_task }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/mjit-bindgen.yml b/.github/workflows/mjit-bindgen.yml
new file mode 100644
index 0000000000..26f8a1b2aa
--- /dev/null
+++ b/.github/workflows/mjit-bindgen.yml
@@ -0,0 +1,104 @@
+name: MJIT bindgen
+on:
+ push:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ merge_group:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+
+concurrency:
+ group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
+ cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
+
+permissions:
+ contents: read
+
+jobs:
+ make:
+ strategy:
+ matrix:
+ include:
+ - task: mjit-bindgen
+ fail-fast: false
+ runs-on: ubuntu-22.04
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
+ steps:
+ - run: mkdir build
+ working-directory:
+ - name: Set ENV
+ run: |
+ echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - name: Install libraries
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y \
+ build-essential \
+ libssl-dev libyaml-dev libreadline6-dev \
+ zlib1g-dev libncurses5-dev libffi-dev \
+ libclang1-14 \
+ bison autoconf
+ sudo apt-get install -q -y pkg-config || :
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
+ with:
+ ruby-version: '3.1'
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: src/.downloaded-cache
+ key: downloaded-cache
+ - name: Fixed world writable dirs
+ run: |
+ chmod -v go-w $HOME $HOME/.config
+ sudo chmod -R go-w /usr/share
+ sudo bash -c 'IFS=:; for d in '"$PATH"'; do chmod -v go-w $d; done' || :
+ - run: ./autogen.sh
+ working-directory: src
+ - name: Run configure
+ run: ../src/configure -C --disable-install-doc --prefix=$(pwd)/install --enable-yjit=dev_nodebug
+ - run: make incs
+ - run: make
+ - run: make install
+ - run: make ${{ matrix.task }}
+ - run: git diff --exit-code
+ working-directory: src
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
+ with:
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ matrix.os }} / ${{ matrix.test_task }}${{ matrix.configure }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() && github.event_name == 'push' }}
+
+defaults:
+ run:
+ working-directory: build
diff --git a/.github/workflows/mjit.yml b/.github/workflows/mjit.yml
new file mode 100644
index 0000000000..6f7181489a
--- /dev/null
+++ b/.github/workflows/mjit.yml
@@ -0,0 +1,113 @@
+name: MJIT
+on:
+ push:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ pull_request:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ - '**.[1-8]'
+ - '**.ronn'
+ merge_group:
+ paths-ignore:
+ - 'doc/**'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
+ - '**.[1-8]'
+ - '**.ronn'
+
+concurrency:
+ group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
+ cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
+
+permissions:
+ contents: read
+
+jobs:
+ make:
+ strategy:
+ matrix:
+ test_task: [check] # to make job names consistent
+ mjit_opts: [--mjit-wait]
+ fail-fast: false
+ runs-on: ubuntu-latest
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
+ env:
+ TESTOPTS: '-q --tty=no'
+ RUN_OPTS: '--disable-gems ${{ matrix.mjit_opts }} --mjit-debug=-ggdb3'
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
+ steps:
+ - run: mkdir build
+ working-directory:
+ - name: Install libraries
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: src/.downloaded-cache
+ key: downloaded-cache
+ - name: Fixed world writable dirs
+ run: |
+ chmod -v go-w $HOME $HOME/.config
+ sudo chmod -R go-w /usr/share
+ sudo bash -c 'IFS=:; for d in '"$PATH"'; do chmod -v go-w $d; done' || :
+ - name: Set ENV
+ run: |
+ echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - run: ./autogen.sh
+ working-directory: src
+ - name: Run configure
+ run: ../src/configure -C --disable-install-doc cppflags=-DVM_CHECK_MODE
+ - run: make incs
+ - run: make
+ - run: sudo make -s install
+ - name: Run test
+ run: |
+ unset GNUMAKEFLAGS
+ make -s test RUN_OPTS="$RUN_OPTS"
+ timeout-minutes: 60
+ # - name: Run test-all
+ # run: |
+ # ulimit -c unlimited
+ # make -s test-all RUN_OPTS="$RUN_OPTS"
+ # timeout-minutes: 60
+ - name: Run test-spec
+ run: |
+ unset GNUMAKEFLAGS
+ make -s test-spec RUN_OPTS="$RUN_OPTS"
+ timeout-minutes: 60
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
+ with:
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / ${{ matrix.test_task }} ${{ matrix.mjit_opts }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
+ SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
+ if: ${{ failure() && github.event_name == 'push' }}
+
+defaults:
+ run:
+ working-directory: build
diff --git a/.github/workflows/parsey.yml b/.github/workflows/parsey.yml
deleted file mode 100644
index 7bfcf27166..0000000000
--- a/.github/workflows/parsey.yml
+++ /dev/null
@@ -1,94 +0,0 @@
-name: parse.y
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- merge_group:
-
-concurrency:
- group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
- cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-
-permissions:
- contents: read
-
-jobs:
- make:
- strategy:
- matrix:
- include:
- - test_task: check
- - test_task: test-bundler-parallel
- - test_task: test-bundled-gems
- fail-fast: false
-
- env:
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
- RUBY_DEBUG: ci
- SETARCH: ${{ matrix.arch && format('setarch {0}', matrix.arch) }}
-
- runs-on: ubuntu-22.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/ubuntu
-
- - uses: ./.github/actions/setup/directories
- with:
- srcdir: src
- builddir: build
- makeup: true
- clean: true
- dummy-files: ${{ matrix.test_task == 'check' }}
-
- - name: Run configure
- run: ../src/configure -C --disable-install-doc cppflags=-DRUBY_DEBUG
-
- - run: make
-
- - name: make ${{ matrix.test_task }}
- run: make -s ${{ matrix.test_task }} RUN_OPTS="$RUN_OPTS" SPECOPTS="$SPECOPTS"
- timeout-minutes: ${{ matrix.timeout }}
- env:
- RUBY_TESTOPTS: ${{ matrix.testopts }}
- EXCLUDES: '../src/test/.excludes-parsey'
- RUN_OPTS: ${{ matrix.run_opts || '--parser=parse.y' }}
- SPECOPTS: ${{ matrix.specopts || '-T --parser=parse.y' }}
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
-
- - uses: ./.github/actions/slack
- with:
- label: ${{ matrix.run_opts }}
- SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
-defaults:
- run:
- working-directory: build
diff --git a/.github/workflows/pr-playground.yml b/.github/workflows/pr-playground.yml
deleted file mode 100644
index cc06006142..0000000000
--- a/.github/workflows/pr-playground.yml
+++ /dev/null
@@ -1,127 +0,0 @@
-name: Post Playground link to PR
-on:
- pull_request_target:
- types: [labeled]
- workflow_run:
- workflows: ["WebAssembly"]
- types: [completed]
-
-jobs:
- post-summary:
- name: Post Playground link
- runs-on: ubuntu-latest
- permissions:
- pull-requests: write
- # Post a comment only if the PR status check is passed and the PR is labeled with `Playground`.
- # Triggered twice: when the PR is labeled and when PR build is passed.
- if: >-
- ${{ false
- || (true
- && github.event_name == 'pull_request_target'
- && contains(github.event.pull_request.labels.*.name, 'Playground'))
- || (true
- && github.event_name == 'workflow_run'
- && github.event.workflow_run.conclusion == 'success'
- && github.event.workflow_run.event == 'pull_request')
- }}
- steps:
- - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
- with:
- github-token: ${{ secrets.GITHUB_TOKEN }}
- script: |
- const fs = require('fs/promises');
-
- const buildWorkflowPath = '.github/workflows/wasm.yml';
- const findSuccessfuBuildRun = async (pr) => {
- const opts = github.rest.actions.listWorkflowRunsForRepo.endpoint.merge({
- owner: context.repo.owner,
- repo: context.repo.repo,
- status: 'success',
- branch: pr.head.ref,
- });
- const runs = await github.paginate(opts);
- const buildRun = runs.find(run => run.path == buildWorkflowPath);
- return buildRun;
- }
-
- const postComment = async (body, pr) => {
- const { data: comments } = await github.rest.issues.listComments({
- owner: context.repo.owner,
- repo: context.repo.repo,
- issue_number: pr.number,
- });
-
- const commentOpts = { owner: context.repo.owner, repo: context.repo.repo, body: comment };
-
- const existingComment = comments.find(comment => comment.body.startsWith(magicComment));
- if (existingComment) {
- core.info(`Updating existing comment: ${existingComment.html_url}`);
- await github.rest.issues.updateComment({
- ...commentOpts, comment_id: existingComment.id
- });
- } else {
- await github.rest.issues.createComment({
- ...commentOpts, issue_number: pr.number
- });
- }
- }
-
- const derivePRNumber = async () => {
- if (context.payload.pull_request) {
- return context.payload.pull_request.number;
- }
- // Workaround for https://github.com/orgs/community/discussions/25220
-
- const { data: { artifacts } } = await github.rest.actions.listWorkflowRunArtifacts({
- owner: context.repo.owner,
- repo: context.repo.repo,
- run_id: context.payload.workflow_run.id,
- });
- const artifact = artifacts.find(artifact => artifact.name == 'github-pr-info');
- if (!artifact) {
- throw new Error('Cannot find github-pr-info.txt artifact');
- }
-
- const { data } = await github.rest.actions.downloadArtifact({
- owner: context.repo.owner,
- repo: context.repo.repo,
- artifact_id: artifact.id,
- archive_format: 'zip',
- });
-
- await fs.writeFile('pr-info.zip', Buffer.from(data));
- await exec.exec('unzip', ['pr-info.zip']);
- return await fs.readFile('github-pr-info.txt', 'utf8');
- }
-
- const prNumber = await derivePRNumber();
-
- const { data: pr } = await github.rest.pulls.get({
- owner: context.repo.owner,
- repo: context.repo.repo,
- pull_number: prNumber,
- });
-
- core.info(`Checking if the PR ${prNumber} is labeled with Playground...`);
- if (!pr.labels.some(label => label.name == 'Playground')) {
- core.info(`The PR is not labeled with Playground.`);
- return;
- }
-
- core.info(`Checking if the build is successful for ${pr.head.ref} in ${pr.head.repo.owner.login}/${pr.head.repo.name}...`);
- const buildRun = await findSuccessfuBuildRun(pr);
- if (!buildRun) {
- core.info(`No successful build run found for ${buildWorkflowPath} on ${pr.head.ref} yet.`);
- return;
- }
- core.info(`Found a successful build run: ${buildRun.html_url}`);
-
- const runLink = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`;
- const magicComment = `<!-- AUTO-GENERATED-COMMENT-PR-PLAYGROUND -->`;
- const comment = `${magicComment}
- **Try on Playground**: https://ruby.github.io/play-ruby?run=${buildRun.id}
- This is an automated comment by [\`pr-playground.yml\`](${runLink}) workflow.
- `;
- core.info(`Comment: ${comment}`);
- await postComment(comment, pr);
-
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
deleted file mode 100644
index 5534e3defe..0000000000
--- a/.github/workflows/release.yml
+++ /dev/null
@@ -1,108 +0,0 @@
-name: Publish Ruby packages
-
-on:
- repository_dispatch:
- types:
- - release
- workflow_dispatch:
- inputs:
- version:
- description: 'Version of the Ruby package to release'
- required: true
- default: '3.3.4'
-
-jobs:
- release:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
-
- - uses: ruby/setup-ruby@v1
- with:
- ruby-version: 3.3.4
-
- - name: Store Ruby version
- run: |
- echo "RUBY_VERSION=${{ github.event.client_payload.version || github.event.inputs.version }}" >> $GITHUB_ENV
-
- - name: Store ABI version
- run: echo "ABI_VERSION=$(echo ${{ env.RUBY_VERSION }} | cut -d '.' -f 1-2)" >> $GITHUB_ENV
-
- - name: Copy draft package `/tmp` to `/pub` directory
- run: tool/release.sh ${{ env.RUBY_VERSION }}
- env:
- AWS_ACCESS_KEY_ID: ${{ secrets.FTP_R_L_O_AWS_ACCESS_KEY_ID }}
- AWS_SECRET_ACCESS_KEY: ${{ secrets.FTP_R_L_O_AWS_SECRET_ACCESS_KEY }}
- AWS_DEFAULT_REGION: us-west-2
-
- - name: Purge URLs of release package
- run: |
- curl -X POST \
- -H "Fastly-Key: ${{ secrets.FASTLY_PURGE_TOKEN }}" \
- https://api.fastly.com/purge/cache.ruby-lang.org/pub/ruby/${{ env.ABI_VERSION }}/ruby-${{ env.RUBY_VERSION }}.tar.gz
- curl -X POST \
- -H "Fastly-Key: ${{ secrets.FASTLY_PURGE_TOKEN }}" \
- https://api.fastly.com/purge/cache.ruby-lang.org/pub/ruby/${{ env.ABI_VERSION }}/ruby-${{ env.RUBY_VERSION }}.tar.xz
- curl -X POST \
- -H "Fastly-Key: ${{ secrets.FASTLY_PURGE_TOKEN }}" \
- https://api.fastly.com/purge/cache.ruby-lang.org/pub/ruby/${{ env.ABI_VERSION }}/ruby-${{ env.RUBY_VERSION }}.zip
-
- - name: Create a release on GitHub
- run: |
- RELEASE_TAG=$(echo v${{ env.RUBY_VERSION }} | sed 's/\./_/g')
- echo $RELEASE_TAG
- PREVIOUS_RELEASE_TAG=$(echo $RELEASE_TAG | awk 'BEGIN {FS="_"; OFS="_"}{ $NF=$NF-1; print }')
- echo $PREVIOUS_RELEASE_TAG
- tool/gen-github-release.rb $PREVIOUS_RELEASE_TAG $RELEASE_TAG --no-dry-run
- env:
- GITHUB_TOKEN: ${{ secrets.MATZBOT_GITHUB_WORKFLOW_TOKEN }}
-
- - name: Update versions index
- run: |
- curl -L -X POST \
- -H "Authorization: Bearer ${{ secrets.MATZBOT_GITHUB_WORKFLOW_TOKEN }}" \
- -H "Accept: application/vnd.github+json" \
- -H "X-GitHub-Api-Version: 2022-11-28" \
- https://api.github.com/repos/ruby/actions/dispatches \
- -d '{"event_type": "update_index"}'
-
- - name: Set latest flag for Ruby 3.3
- if: contains(${{ env.RUBY_VERSION }}, '3.3.')
- run: |
- echo "LATEST=true" >> $GITHUB_ENV
-
- - name: Build and push Docker images
- run: |
- curl -L -X POST \
- -H "Authorization: Bearer ${{ secrets.MATZBOT_GITHUB_WORKFLOW_TOKEN }}" \
- -H "Accept: application/vnd.github+json" \
- -H "X-GitHub-Api-Version: 2022-11-28" \
- https://api.github.com/repos/ruby/docker-images/dispatches \
- -d '{"event_type": "build", "client_payload": {"ruby_version": "${{ env.RUBY_VERSION }}", "arch": "amd64", "latest": "${{ env.LATEST }}"}}'
-
- - name: Build snapcraft packages
- run: |
- curl -L -X POST \
- -H "Authorization: Bearer ${{ secrets.MATZBOT_GITHUB_WORKFLOW_TOKEN }}" \
- -H "Accept: application/vnd.github+json" \
- -H "X-GitHub-Api-Version: 2022-11-28" \
- https://api.github.com/repos/ruby/snap.ruby/dispatches \
- -d '{"event_type": "build", "client_payload": {"ruby_version": "${{ env.RUBY_VERSION }}"}}'
-
- - name: Update ruby-build definition
- run: |
- curl -L -X POST \
- -H "Authorization: Bearer ${{ secrets.RUBY_BUILD_WORKFLOW_TOKEN }}" \
- -H "Accept: application/vnd.github+json" \
- -H "X-GitHub-Api-Version: 2022-11-28" \
- https://api.github.com/repos/rbenv/ruby-build/dispatches \
- -d '{"event_type": "update-ruby", "client_payload": {"ruby_version": "${{ env.RUBY_VERSION }}", "openssl_version": "3.0.15"}}'
-
- - name: Update all-ruby definition
- run: |
- curl -L -X POST \
- -H "Authorization: Bearer ${{ secrets.MATZBOT_GITHUB_WORKFLOW_TOKEN }}" \
- -H "Accept: application/vnd.github+json" \
- -H "X-GitHub-Api-Version: 2022-11-28" \
- https://api.github.com/repos/ruby/all-ruby/dispatches \
- -d '{"event_type": "update"}'
diff --git a/.github/workflows/rjit-bindgen.yml b/.github/workflows/rjit-bindgen.yml
deleted file mode 100644
index 65ef44ee8d..0000000000
--- a/.github/workflows/rjit-bindgen.yml
+++ /dev/null
@@ -1,86 +0,0 @@
-name: RJIT bindgen
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- merge_group:
-
-concurrency:
- group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
- cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-
-permissions:
- contents: read
-
-jobs:
- make:
- strategy:
- matrix:
- include:
- - task: rjit-bindgen
- fail-fast: false
-
- runs-on: ubuntu-20.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
- steps:
- - name: Set up Ruby
- uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
- with:
- ruby-version: '3.1'
-
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/ubuntu
-
- - uses: ./.github/actions/setup/directories
- with:
- srcdir: src
- builddir: build
- makeup: true
-
- - name: Run configure
- run: ../src/configure -C --disable-install-doc --prefix=$(pwd)/install --enable-yjit=dev_nodebug
-
- - run: make
-
- - run: make install
-
- - run: make ${{ matrix.task }}
-
- - run: git diff --exit-code
- working-directory: src
-
- - uses: ./.github/actions/slack
- with:
- SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
-defaults:
- run:
- working-directory: build
diff --git a/.github/workflows/rjit.yml b/.github/workflows/rjit.yml
deleted file mode 100644
index 9cec3bcd86..0000000000
--- a/.github/workflows/rjit.yml
+++ /dev/null
@@ -1,130 +0,0 @@
-name: RJIT
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '**.[1-8]'
- - '**.ronn'
- - '.*.yml'
- pull_request:
- paths-ignore:
- - 'doc/**'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '**.[1-8]'
- - '**.ronn'
- - '.*.yml'
- merge_group:
-
-concurrency:
- group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
- cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-
-permissions:
- contents: read
-
-jobs:
- make:
- strategy:
- matrix:
- # main variables included in the job name
- test_task: [check]
- run_opts: ['--rjit-call-threshold=1']
- arch: ['']
- fail-fast: false
-
- env:
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
- RUBY_DEBUG: ci
- SETARCH: ${{ matrix.arch && format('setarch {0}', matrix.arch) }}
-
- runs-on: ubuntu-22.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/ubuntu
-
- - uses: ./.github/actions/setup/directories
- with:
- srcdir: src
- builddir: build
- makeup: true
- # Set fetch-depth: 10 so that Launchable can receive commits information.
- fetch-depth: 10
-
- - name: Run configure
- env:
- arch: ${{ matrix.arch }}
- run: >-
- $SETARCH ../src/configure -C --disable-install-doc cppflags=-DRUBY_DEBUG
- ${arch:+--target=$arch-$OSTYPE --host=$arch-$OSTYPE}
-
- - run: $SETARCH make
-
- - name: Set up Launchable
- uses: ./.github/actions/launchable/setup
- with:
- os: ubuntu-22.04
- test-task: test
- launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
- builddir: build
- srcdir: src
- launchable-workspace: ruby-make-btest
- test-opts: ${{ matrix.run_opts }}
- continue-on-error: true
-
- - name: make test
- run: |
- $SETARCH make -s test RUN_OPTS="$RUN_OPTS"
- timeout-minutes: 30
- env:
- GNUMAKEFLAGS: ''
- RUBY_TESTOPTS: >-
- ${{ env.TESTS }}
- --tty=no
- RUN_OPTS: ${{ matrix.run_opts }}
-
- - name: make test-all
- run: |
- $SETARCH make -s test-all RUN_OPTS="$RUN_OPTS"
- timeout-minutes: 60
- env:
- GNUMAKEFLAGS: ''
- RUBY_TESTOPTS: '-q --tty=no'
- RUN_OPTS: ${{ matrix.run_opts }}
-
- - name: make test-spec
- run: |
- $SETARCH make -s test-spec RUN_OPTS="$RUN_OPTS"
- timeout-minutes: 10
- env:
- GNUMAKEFLAGS: ''
- RUN_OPTS: ${{ matrix.run_opts }}
-
- - uses: ./.github/actions/slack
- with:
- label: ${{ matrix.run_opts }}
- SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
-defaults:
- run:
- working-directory: build
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index 40f86480c2..c12a95362d 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -11,8 +11,8 @@ on:
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '22 4 * * 2'
- # push:
- # branches: [ "master" ]
+ push:
+ branches: [ "master" ]
# Declare default permissions as read only.
permissions: read-all
@@ -31,13 +31,13 @@ jobs:
# actions: read
steps:
- - name: 'Checkout code'
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - name: "Checkout code"
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- - name: 'Run analysis'
- uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
+ - name: "Run analysis"
+ uses: ossf/scorecard-action@ea651e62978af7915d09fe2e282747c798bf2dab # v2.4.1
with:
results_file: results.sarif
results_format: sarif
@@ -58,15 +58,15 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- # - name: "Upload artifact"
- # uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
- # with:
- # name: SARIF file
- # path: results.sarif
- # retention-days: 5
+ - name: "Upload artifact"
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
+ with:
+ name: SARIF file
+ path: results.sarif
+ retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- - name: 'Upload to code-scanning'
- uses: github/codeql-action/upload-sarif@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11
+ - name: "Upload to code-scanning"
+ uses: github/codeql-action/upload-sarif@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.27
with:
sarif_file: results.sarif
diff --git a/.github/workflows/spec_guards.yml b/.github/workflows/spec_guards.yml
index 86abe44034..4521195a2b 100644
--- a/.github/workflows/spec_guards.yml
+++ b/.github/workflows/spec_guards.yml
@@ -22,7 +22,7 @@ jobs:
rubyspec:
name: Rubyspec
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-22.04
if: >-
${{!(false
@@ -31,7 +31,7 @@ jobs:
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
+ || (github.event_name == 'push' && github.actor == 'dependabot[bot]')
)}}
strategy:
@@ -39,15 +39,13 @@ jobs:
# Specs from ruby/spec should still run on all supported Ruby versions.
# This also ensures the needed ruby_version_is guards are there, see spec/README.md.
ruby:
- - ruby-3.0
- ruby-3.1
- ruby-3.2
- - ruby-3.3
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ - uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
with:
ruby-version: ${{ matrix.ruby }}
bundler: none
@@ -58,9 +56,16 @@ jobs:
working-directory: spec/ruby
env:
CHECK_LEAKS: true
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.ruby }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / rubyspec @ ${{ matrix.ruby }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
if: ${{ failure() }}
diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
index e829596165..4fbca1170e 100644
--- a/.github/workflows/ubuntu.yml
+++ b/.github/workflows/ubuntu.yml
@@ -3,15 +3,24 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man/*'
+ - '**/man'
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
- # Do not use paths-ignore for required status checks
- # https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
merge_group:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -24,151 +33,113 @@ jobs:
make:
strategy:
matrix:
+ # main variables included in the job name
+ test_task: [check]
+ configure: [cppflags=-DRUBY_DEBUG] # default to use more assertions
+ arch: ['']
+ # specify all jobs with `include` to avoid testing duplicated things
include:
- test_task: check
- configure: 'cppflags=-DVM_CHECK_MODE'
- test_task: check
arch: i686
+ configure: '' # test without -DRUBY_DEBUG as well
- test_task: check
- configure: '--disable-yjit'
- - test_task: check
- configure: '--enable-shared --enable-load-relative'
- - test_task: check
- shared_gc: true
- configure: '--with-shared-gc=/home/runner/ruby_gc'
+ configure: "--enable-shared --enable-load-relative"
+ - test_task: test-all TESTS=--repeat-count=2
- test_task: test-bundler-parallel
- timeout: 50
- test_task: test-bundled-gems
- - test_task: check
- os: ubuntu-20.04
- - test_task: check
- os: ubuntu-24.04
fail-fast: false
-
env:
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
RUBY_DEBUG: ci
-
- runs-on: ${{ matrix.os || 'ubuntu-22.04' }}
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
+ SETARCH: ${{ matrix.arch && format('setarch {0}', matrix.arch) }}
+ runs-on: ubuntu-22.04
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/ubuntu
- with:
- arch: ${{ matrix.arch }}
-
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ - run: mkdir build
+ working-directory:
+ - name: Set ENV
+ run: |
+ echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - name: Install libraries
+ env:
+ arch: ${{matrix.arch}}
+ run: |
+ set -x
+ arch=${arch:+:${arch/i[3-6]86/i386}}
+ ${arch:+sudo dpkg --add-architecture ${arch#:}}
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y \
+ ${arch:+cross}build-essential${arch/:/-} \
+ libssl-dev${arch} libyaml-dev${arch} libreadline6-dev${arch} \
+ zlib1g-dev${arch} libncurses5-dev${arch} libffi-dev${arch} \
+ bison autoconf ruby
+ sudo apt-get install -q -y pkg-config${arch} || :
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
- ruby-version: '3.0'
- bundler: none
-
- - uses: ./.github/actions/setup/directories
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
- srcdir: src
- builddir: build
- makeup: true
- clean: true
- dummy-files: ${{ matrix.test_task == 'check' }}
- # Set fetch-depth: 10 so that Launchable can receive commits information.
- fetch-depth: 10
-
+ path: src/.downloaded-cache
+ key: downloaded-cache
+ - name: Fixed world writable dirs
+ run: |
+ chmod -v go-w $HOME $HOME/.config
+ sudo chmod -R go-w /usr/share
+ sudo bash -c 'IFS=:; for d in '"$PATH"'; do chmod -v go-w $d; done' || :
+ - run: ./autogen.sh
+ working-directory: src
- name: Run configure
env:
- arch: ${{ matrix.arch }}
- configure: ${{ matrix.configure }}
+ arch: ${{matrix.arch}}
run: >-
- $SETARCH ../src/configure -C --disable-install-doc ${configure:-cppflags=-DRUBY_DEBUG}
+ $SETARCH ../src/configure -C --disable-install-doc ${{ matrix.configure }}
${arch:+--target=$arch-$OSTYPE --host=$arch-$OSTYPE}
-
+ - run: $SETARCH make incs
- run: $SETARCH make prepare-gems
if: ${{ matrix.test_task == 'test-bundled-gems' }}
-
- - name: Build shared GC
- run: |
- echo "RUBY_GC_LIBRARY=librubygc.default.so" >> $GITHUB_ENV
- make shared-gc SHARED_GC=default
- if: ${{ matrix.shared_gc }}
-
- run: $SETARCH make
-
- - run: |
- $SETARCH make golf
- case "${{ matrix.configure }}" in
- *'--enable-shared'*)
- $SETARCH make runnable
- ./bin/goruby -veh
- ;;
- *)
- ./goruby -veh
- ;;
- esac
-
- - name: Set test options for skipped tests
+ - run: $SETARCH make leaked-globals
+ if: ${{ matrix.test_task == 'check' }}
+ - name: Create dummy files in build dir
run: |
- set -x
- TESTS="$(echo "${{ matrix.skipped_tests }}" | sed 's| |$$/ -n!/|g;s|^|-n!/|;s|$|$$/|')"
- echo "TESTS=${TESTS}" >> $GITHUB_ENV
- if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
-
- - name: Set up Launchable
- uses: ./.github/actions/launchable/setup
- with:
- os: ${{ matrix.os || 'ubuntu-22.04' }}
- test-opts: ${{ matrix.configure }}
- launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
- builddir: build
- srcdir: src
- continue-on-error: true
-
+ $SETARCH ./miniruby -e '(("a".."z").to_a+("A".."Z").to_a+("0".."9").to_a+%w[foo bar test zzz]).each{|basename|File.write("#{basename}.rb", "raise %(do not load #{basename}.rb)")}'
+ if: ${{ matrix.test_task == 'check' }}
- name: make ${{ matrix.test_task }}
- run: >-
- $SETARCH make -s ${{ matrix.test_task }}
- ${TESTS:+TESTS="$TESTS"}
- ${{ !contains(matrix.test_task, 'bundle') && 'RUBYOPT=-w' || '' }}
- timeout-minutes: ${{ matrix.timeout || 40 }}
+ run: |
+ $SETARCH make -s ${{ matrix.test_task }} ${TESTS:+TESTS=`echo "$TESTS" | sed 's| |$$/ -n!/|g;s|^|-n!/|;s|$|$$/|'`}
+ timeout-minutes: 40
env:
- RUBY_TESTOPTS: '-q --tty=no'
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
- PRECHECK_BUNDLED_GEMS: 'no'
-
+ RUBY_TESTOPTS: "-q --tty=no"
+ TESTS: ${{ matrix.test_task == 'check' && matrix.skipped_tests || '' }}
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ""
+ PRECHECK_BUNDLED_GEMS: "no"
- name: make skipped tests
run: |
- $SETARCH make -s test-all TESTS="${TESTS//-n!\//-n/}"
+ $SETARCH make -s test-all TESTS=`echo "$TESTS" | sed 's| |$$/ -n/|g;s|^|-n/|;s|$|$$/|'`
env:
- GNUMAKEFLAGS: ''
- RUBY_TESTOPTS: '-v --tty=no'
- if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
+ GNUMAKEFLAGS: ""
+ RUBY_TESTOPTS: "-v --tty=no"
+ TESTS: ${{ matrix.skipped_tests }}
+ if: ${{ matrix.test_task == 'check' && matrix.skipped_tests != '' }}
continue-on-error: ${{ matrix.continue-on-skipped_tests || false }}
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.test_task }} ${{ matrix.configure }}${{ matrix.arch }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / ${{ matrix.test_task }} ${{ matrix.configure }}${{ matrix.arch }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
- result:
- if: ${{ always() }}
- name: ${{ github.workflow }} result
- runs-on: ubuntu-latest
- needs: [make]
- steps:
- - run: exit 1
- working-directory:
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml
index dac107c57b..27920b5821 100644
--- a/.github/workflows/wasm.yml
+++ b/.github/workflows/wasm.yml
@@ -3,26 +3,30 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man/*'
+ - '**/man'
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
paths-ignore:
- 'doc/**'
- - '**/man/*'
+ - '**/man'
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
merge_group:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-permissions: # added using https://github.com/step-security/secure-workflows
+permissions: # added using https://github.com/step-security/secure-workflows
contents: read
jobs:
@@ -31,52 +35,38 @@ jobs:
matrix:
entry:
# # wasmtime can't compile non-optimized Asyncified binary due to locals explosion
-# - { name: O0-debuginfo, optflags: '-O0', debugflags: '-g', wasmoptflags: '-O1' }
-# - { name: O1, optflags: '-O1', debugflags: '' , wasmoptflags: '-O1' }
- - { name: O2, optflags: '-O2', debugflags: '', wasmoptflags: '-O2' }
-# - { name: O3, optflags: '-O3', debugflags: '' , wasmoptflags: '-O3' }
+# - { name: O0-debuginfo, optflags: "-O0", debugflags: "-g", wasmoptflags: "-O1" }
+# - { name: O1, optflags: "-O1", debugflags: "" , wasmoptflags: "-O1" }
+ - { name: O2, optflags: "-O2", debugflags: "" , wasmoptflags: "-O2" }
+# - { name: O3, optflags: "-O3", debugflags: "" , wasmoptflags: "-O3" }
# # -O4 is equivalent to -O3 in clang, but it's different in wasm-opt
-# - { name: O4, optflags: '-O3', debugflags: '' , wasmoptflags: '-O4' }
-# - { name: Oz, optflags: '-Oz', debugflags: '' , wasmoptflags: '-Oz' }
+# - { name: O4, optflags: "-O3", debugflags: "" , wasmoptflags: "-O4" }
+# - { name: Oz, optflags: "-Oz", debugflags: "" , wasmoptflags: "-Oz" }
fail-fast: false
-
env:
RUBY_TESTOPTS: '-q --tty=no'
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
- WASI_SDK_VERSION_MAJOR: 20
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
+ WASI_SDK_VERSION_MAJOR: 14
WASI_SDK_VERSION_MINOR: 0
- BINARYEN_VERSION: 113
- WASMTIME_VERSION: v15.0.0
-
- runs-on: ubuntu-20.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
+ BINARYEN_VERSION: 109
+ WASMTIME_VERSION: v0.33.0
+ runs-on: ubuntu-22.04
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/directories
+ - run: mkdir build
+ working-directory:
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
- srcdir: src
- builddir: build
- makeup: true
-
+ path: src
- name: Install libraries
run: |
set -ex
sudo apt-get update -q || :
- sudo apt-get install --no-install-recommends -q -y ruby make autoconf git wget
+ sudo apt-get install --no-install-recommends -q -y ruby bison make autoconf git wget
wasi_sdk_deb="wasi-sdk_${WASI_SDK_VERSION_MAJOR}.${WASI_SDK_VERSION_MINOR}_amd64.deb"
wget "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_SDK_VERSION_MAJOR}/${wasi_sdk_deb}"
@@ -95,32 +85,29 @@ jobs:
wget -O - "$binaryen_url" | tar xfz -
sudo ln -fs "$PWD/binaryen-version_${BINARYEN_VERSION}/bin/wasm-opt" /usr/local/bin/wasm-opt
working-directory: src
-
- name: Set ENV
run: |
+ echo "MAKEFLAGS=-j$((1 + $(sysctl -n hw.activecpu)))" >> $GITHUB_ENV
echo "WASI_SDK_PATH=/opt/wasi-sdk" >> $GITHUB_ENV
+ - run: ./autogen.sh
+ working-directory: src
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
+ - uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
with:
ruby-version: '3.0'
bundler: none
- - name: Build baseruby
+ - name: Download config.guess with wasi version
run: |
- set -ex
- mkdir ../baseruby
- pushd ../baseruby
- ../src/configure --prefix=$PWD/install
- make
- make install
+ rm tool/config.guess tool/config.sub
+ ruby tool/downloader.rb -d tool -e gnu config.guess config.sub
+ working-directory: src
- name: Run configure
run: |
../src/configure \
--host wasm32-unknown-wasi \
- --with-baseruby=$PWD/../baseruby/install/bin/ruby \
--with-static-linked-ext \
- --with-ext=cgi/escape,continuation,coverage,date,digest/bubblebabble,digest,digest/md5,digest/rmd160,digest/sha1,digest/sha2,etc,fcntl,json,json/generator,json/parser,objspace,pathname,rbconfig/sizeof,ripper,stringio,strscan,monitor \
LDFLAGS=" \
-Xlinker --stack-first \
-Xlinker -z -Xlinker stack-size=16777216 \
@@ -131,44 +118,28 @@ jobs:
# miniruby may not be built when cross-compling
- run: make mini ruby
-
- - run: make install DESTDIR=$PWD/../install
- - run: tar cfz ../install.tar.gz -C ../install .
-
- - name: Upload artifacts
- uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
- with:
- name: ruby-wasm-install
- path: ${{ github.workspace }}/install.tar.gz
- - name: Show Playground URL to try the build
- run: |
- echo "Try on Playground: https://ruby.github.io/play-ruby?run=$GITHUB_RUN_ID" >> $GITHUB_STEP_SUMMARY
-
- name: Run basictest
run: wasmtime run ./../build/miniruby --mapdir /::./ -- basictest/test.rb
working-directory: src
-
- name: Run bootstraptest (no thread)
run: |
NO_THREAD_TESTS="$(grep -L Thread -R ./bootstraptest | awk -F/ '{ print $NF }' | uniq | sed -n 's/test_\(.*\).rb/\1/p' | paste -s -d, -)"
ruby ./bootstraptest/runner.rb --ruby="$(which wasmtime) run $PWD/../build/ruby --mapdir /::./ -- " --verbose "--sets=$NO_THREAD_TESTS"
working-directory: src
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.entry.name }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / ${{ matrix.name }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
- # Workaround for https://github.com/orgs/community/discussions/25220
- - name: Save Pull Request number
- if: ${{ github.event_name == 'pull_request' }}
- run: echo "${{ github.event.pull_request.number }}" >> ${{ github.workspace }}/github-pr-info.txt
- - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
- if: ${{ github.event_name == 'pull_request' }}
- with:
- name: github-pr-info
- path: ${{ github.workspace }}/github-pr-info.txt
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index e821883157..c2bd4881c2 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -3,15 +3,24 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man/*'
+ - '**/man'
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
- # Do not use paths-ignore for required status checks
- # https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
merge_group:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -25,190 +34,114 @@ jobs:
strategy:
matrix:
include:
- - vc: 2015
- vs: 2019
- vcvars: '10.0.14393.0 -vcvars_ver=14.0' # The oldest Windows 10 SDK w/ VC++ 2015 toolset (v140)
- - vs: 2019
- vs: 2022
+ vcvers: -vcvars_ver=14.2
fail-fast: false
-
- runs-on: windows-${{ matrix.vs < 2022 && '2019' || matrix.vs }}
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
- name: VisualStudio ${{ matrix.vc || matrix.vs }}
-
+ runs-on: windows-${{ matrix.vs }}
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
+ name: VisualStudio ${{ matrix.vs }}
env:
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
- OS_VER: windows-${{ matrix.vs < 2022 && '2019' || matrix.vs }}
- VCPKG_DEFAULT_TRIPLET: ${{ matrix.target || 'x64' }}-windows
-
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
+ PATCH: C:\msys64\usr\bin\patch.exe
+ OS_VER: windows-${{ matrix.vs }}
steps:
- run: md build
working-directory:
-
- - name: find tools
- id: find-tools
- run: |
- ::- find needed tools
- set NEEDS=
- for %%I in (%NEEDED_TOOLS%) do if "%%~$PATH:I" == "" (
- call set NEEDS=%%NEEDS%% %%~nI
- ) else (
- echo %%I: %%~$PATH:I
- )
- echo.needs=%NEEDS%>>%GITHUB_OUTPUT%
- if "%NEEDS%" == "" (
- echo [debug] All needed tools found
- ) else (
- echo [warning^]Needs%NEEDS%
- )
- env:
- NEEDED_TOOLS: >-
- patch.exe
-
- - uses: msys2/setup-msys2@d40200dc2db4c351366b048a9565ad82919e1c24 # v2
+ - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # v2.27.0
id: setup-msys2
with:
update: true
- install: >-
- ${{ steps.find-tools.outputs.needs }}
- if: ${{ steps.find-tools.outputs.needs != '' }}
-
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
- with:
- ruby-version: '3.0'
- bundler: none
- windows-toolchain: none
-
- - name: Export GitHub Actions cache environment variables
- uses: actions/github-script@v7
+ install: bison patch
+ - name: patch path
+ shell: msys2 {0}
+ run: echo PATCH=$(cygpath -wa $(command -v patch)) >> $GITHUB_ENV
+ if: ${{ steps.setup-msys2.outcome == 'success' }}
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
- script: |
- core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
- core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
-
- - name: Install libraries with scoop
+ path: C:\vcpkg\installed
+ key: ${{ runner.os }}-vcpkg-installed-windows-${{ matrix.vs }}-${{ github.sha }}
+ restore-keys: |
+ ${{ runner.os }}-vcpkg-installed-windows-${{ matrix.vs }}-
+ ${{ runner.os }}-vcpkg-installed-windows-
+ - name: Install libraries with vcpkg
run: |
iex "& {$(irm get.scoop.sh)} -RunAsAdmin"
Join-Path (Resolve-Path ~).Path "scoop\shims" >> $Env:GITHUB_PATH
- shell: pwsh
-
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+ scoop install cmake@3.31.6
+ vcpkg --triplet x64-windows install libffi libyaml openssl readline zlib
+ shell:
+ pwsh
+ - name: git config
+ run: |
+ git config --global core.autocrlf false
+ git config --global core.eol lf
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/directories
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
- srcdir: src
- builddir: build
-
+ path: src/.downloaded-cache
+ key: downloaded-cache
- name: setup env
- # Available Ruby versions: https://github.com/actions/runner-images/blob/main/images/windows/Windows2019-Readme.md#ruby
# %TEMP% is inconsistent with %TMP% and test-all expects they are consistent.
# https://github.com/actions/virtual-environments/issues/712#issuecomment-613004302
+ # msys2/setup-msys2 installs MSYS2 to D:/a/_temp/msys64/usr/bin
run: |
- ::- Set up VC ${{ matrix.vc || matrix.vs }}
- set vswhere="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
- for /f "delims=;" %%I in ('%vswhere% -latest -property installationPath') do (
- set VCVARS="%%I\VC\Auxiliary\Build\vcvars64.bat"
- )
- set VCVARS
+ set Path=D:/a/_temp/msys64/usr/bin;%Path%
+ if not "%VCVARS%" == "" goto :vcset
+ set VCVARS="C:\Program Files (x86)\Microsoft Visual Studio\${{ matrix.vs }}\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
+ if not exist %VCVARS% set VCVARS="C:\Program Files\Microsoft Visual Studio\${{ matrix.vs }}\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
+ :vcset
set | C:\msys64\usr\bin\sort > old.env
- call %VCVARS% ${{ matrix.vcvars || '' }}
- nmake -f nul
+ call %VCVARS% ${{ matrix.vcvers || ''}}
set TMP=%USERPROFILE%\AppData\Local\Temp
set TEMP=%USERPROFILE%\AppData\Local\Temp
- set MAKEFLAGS=l
set /a TEST_JOBS=(15 * %NUMBER_OF_PROCESSORS% / 10) > nul
set | C:\msys64\usr\bin\sort > new.env
C:\msys64\usr\bin\comm -13 old.env new.env >> %GITHUB_ENV%
del *.env
-
- - name: baseruby version
- run: ruby -v
-
- name: compiler version
run: cl
-
- - name: volume info
- run: Get-Volume
- shell: pwsh
-
- - name: Install libraries with vcpkg
+ - name: link libraries
run: |
- vcpkg install
- working-directory: src
- env:
- VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
-
- # TODO: We should use `../src` instead of `D:/a/ruby/ruby/src`
+ for %%I in (C:\vcpkg\installed\x64-windows\bin\*.dll) do (
+ if not %%~nI == readline mklink %%~nxI %%I
+ )
+ for %%I in (libcrypto-1_1-x64 libssl-1_1-x64) do (
+ ren c:\Windows\System32\%%I.dll %%I.dll_
+ )
- name: Configure
run: >-
../src/win32/configure.bat --disable-install-doc
- --with-opt-dir=D:/a/ruby/ruby/src/vcpkg_installed/%VCPKG_DEFAULT_TRIPLET%
-
- - run: nmake prepare-vcpkg
-
+ --with-opt-dir=C:/vcpkg/installed/x64-windows
- run: nmake incs
-
- run: nmake extract-extlibs
-
- # On all other platforms, test-spec depending on extract-gems (in common.mk) is enough.
- # But not for this Visual Studio workflow. So here we extract gems before building.
- - run: nmake extract-gems
-
- run: nmake
-
+ env:
+ YACC: bison.exe
- run: nmake test
timeout-minutes: 5
-
- run: nmake test-spec
timeout-minutes: 10
-
- - name: Set up Launchable
- uses: ./.github/actions/launchable/setup
- with:
- os: windows-${{ matrix.vs < 2022 && '2019' || matrix.vs }}
- test-task: test-all
- # If we support a new test task, we need to change this test-opts.
- test-opts: -j${{ env.TEST_JOBS || 4 }} --job-status=normal
- launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
- builddir: build
- srcdir: src
- continue-on-error: true
-
- run: nmake test-all
env:
- RUBY_TESTOPTS: >-
- -j${{ env.TEST_JOBS || 4 }}
- --job-status=normal
+ RUBY_TESTOPTS: -j${{env.TEST_JOBS}} --job-status=normal
timeout-minutes: 60
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: VS${{ matrix.vc || matrix.vs }} / ${{ matrix.test_task || 'check' }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "VS${{ matrix.vs }} / ${{ matrix.test_task || 'check' }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
- result:
- if: ${{ always() }}
- name: ${{ github.workflow }} result
- runs-on: windows-latest
- needs: [make]
- steps:
- - run: exit 1
- working-directory:
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/yjit-macos.yml b/.github/workflows/yjit-macos.yml
deleted file mode 100644
index 9c1e75a95d..0000000000
--- a/.github/workflows/yjit-macos.yml
+++ /dev/null
@@ -1,170 +0,0 @@
-name: YJIT macOS Arm64
-on:
- push:
- paths-ignore:
- - 'doc/**'
- - '**/man/*'
- - '**.md'
- - '**.rdoc'
- - '**/.document'
- - '.*.yml'
- pull_request:
- # Do not use paths-ignore for required status checks
- # https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks
- merge_group:
-
-concurrency:
- group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
- cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
-
-permissions:
- contents: read
-
-jobs:
- cargo:
- name: cargo test
-
- runs-on: macos-14
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
-
- - run: RUST_BACKTRACE=1 cargo test
- working-directory: yjit
-
- # Also compile and test with all features enabled
- - run: RUST_BACKTRACE=1 cargo test --all-features
- working-directory: yjit
-
- # Check that we can build in release mode too
- - run: cargo build --release
- working-directory: yjit
-
- make:
- strategy:
- matrix:
- include:
- - test_task: 'check'
- configure: '--enable-yjit'
- yjit_opts: '--yjit'
- - test_task: 'check'
- configure: '--enable-yjit=dev'
- yjit_opts: '--yjit-call-threshold=1 --yjit-verify-ctx --yjit-code-gc'
- specopts: '-T --yjit-call-threshold=1 -T --yjit-verify-ctx -T --yjit-code-gc'
- fail-fast: false
-
- env:
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
- RUN_OPTS: ${{ matrix.yjit_opts }}
- SPECOPTS: ${{ matrix.specopts }}
-
- runs-on: macos-14
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - name: Install libraries
- uses: ./.github/actions/setup/macos
-
- - uses: ./.github/actions/setup/directories
- with:
- srcdir: src
- builddir: build
- makeup: true
- dummy-files: ${{ matrix.test_task == 'check' }}
- # Set fetch-depth: 10 so that Launchable can receive commits information.
- fetch-depth: 10
-
- - name: Run configure
- run: ../src/configure -C --disable-install-doc ${{ matrix.configure }}
-
- - run: make prepare-gems
- if: ${{ matrix.test_task == 'test-bundled-gems' }}
-
- - run: make
-
- - name: Enable YJIT through ENV
- run: echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
-
- - name: Set test options for skipped tests
- run: |
- set -x
- TESTS="$(echo "${{ matrix.skipped_tests }}" | sed 's| |$$/ -n!/|g;s|^|-n!/|;s|$|$$/|')"
- echo "TESTS=${TESTS}" >> $GITHUB_ENV
- if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
-
- - name: Set up Launchable
- uses: ./.github/actions/launchable/setup
- with:
- os: macos-14
- test-opts: ${{ matrix.configure }}
- launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
- builddir: build
- srcdir: src
- continue-on-error: true
-
- - name: make ${{ matrix.test_task }}
- run: >-
- make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
- RUN_OPTS="$RUN_OPTS"
- SPECOPTS="$SPECOPTS"
- timeout-minutes: 60
- env:
- RUBY_TESTOPTS: '-q --tty=no'
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
- SYNTAX_SUGGEST_TIMEOUT: '5'
- PRECHECK_BUNDLED_GEMS: 'no'
- continue-on-error: ${{ matrix.continue-on-test_task || false }}
-
- - name: make skipped tests
- run: |
- make -s test-all TESTS="${TESTS//-n!\//-n/}"
- env:
- GNUMAKEFLAGS: ''
- RUBY_TESTOPTS: '-v --tty=no'
- PRECHECK_BUNDLED_GEMS: 'no'
- if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
- continue-on-error: ${{ matrix.continue-on-skipped_tests || false }}
-
- - uses: ./.github/actions/slack
- with:
- label: ${{ matrix.test_task }} ${{ matrix.configure }} ${{ matrix.yjit_opts }}
- SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
- result:
- if: ${{ always() }}
- name: ${{ github.workflow }} result
- runs-on: macos-14
- needs: [make]
- steps:
- - run: exit 1
- working-directory:
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
-
-defaults:
- run:
- working-directory: build
diff --git a/.github/workflows/yjit-ubuntu.yml b/.github/workflows/yjit-ubuntu.yml
index d67ea8d49e..0b7b9046e9 100644
--- a/.github/workflows/yjit-ubuntu.yml
+++ b/.github/workflows/yjit-ubuntu.yml
@@ -3,15 +3,24 @@ on:
push:
paths-ignore:
- 'doc/**'
- - '**/man/*'
+ - '**/man'
- '**.md'
- '**.rdoc'
- '**/.document'
- - '.*.yml'
pull_request:
- # Do not use paths-ignore for required status checks
- # https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
merge_group:
+ paths-ignore:
+ - 'doc/**'
+ - '**/man'
+ - '**.md'
+ - '**.rdoc'
+ - '**/.document'
concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
@@ -22,58 +31,22 @@ permissions:
jobs:
cargo:
- name: cargo test
-
+ name: Rust cargo test
# GitHub Action's image seems to already contain a Rust 1.58.0.
- runs-on: ubuntu-20.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
+ runs-on: ubuntu-22.04
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
-
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# For now we can't run cargo test --offline because it complains about the
# capstone dependency, even though the dependency is optional
#- run: cargo test --offline
-
- run: RUST_BACKTRACE=1 cargo test
working-directory: yjit
-
# Also compile and test with all features enabled
- run: RUST_BACKTRACE=1 cargo test --all-features
working-directory: yjit
-
# Check that we can build in release mode too
- run: cargo build --release
working-directory: yjit
-
- lint:
- name: cargo clippy
-
- # GitHub Action's image seems to already contain a Rust 1.58.0.
- runs-on: ubuntu-20.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
- steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
-
- # Check that we don't have linting errors in release mode, too
- - run: cargo clippy --all-targets --all-features
- working-directory: yjit
-
make:
strategy:
fail-fast: false
@@ -81,140 +54,116 @@ jobs:
include:
- test_task: 'yjit-bindgen'
hint: 'To fix: use patch in logs'
- configure: '--with-gcc=clang-12 --enable-yjit=dev'
+ configure: '--with-gcc=clang-14 --enable-yjit=dev'
+ libclang_path: '/usr/lib/llvm-14/lib/libclang.so.1'
- - test_task: 'check'
+ - test_task: "check"
# YJIT should be automatically built in release mode on x86-64 Linux with rustc present
#configure: "--enable-yjit RUSTC='rustc +1.58.0'"
configure: "RUSTC='rustc +1.58.0'"
- rust_version: '1.58.0'
+ rust_version: "1.58.0"
- - test_task: 'check'
- configure: '--enable-yjit=dev'
+ - test_task: "check"
+ configure: "--enable-yjit=dev"
- - test_task: 'check'
- configure: '--enable-yjit=dev'
- yjit_opts: '--yjit-call-threshold=1 --yjit-verify-ctx --yjit-code-gc'
- specopts: '-T --yjit-call-threshold=1 -T --yjit-verify-ctx -T --yjit-code-gc'
+ - test_task: "check"
+ configure: "--enable-yjit=dev"
+ yjit_opts: "--yjit-call-threshold=1 --yjit-verify-ctx"
- - test_task: 'test-bundled-gems'
- configure: '--enable-yjit=dev'
+ - test_task: "test-all TESTS=--repeat-count=2"
+ configure: "--enable-yjit=dev"
- - test_task: 'yjit-bench'
- configure: '--enable-yjit=dev'
- yjit_bench_opts: '--yjit-stats'
- continue-on-test_task: true
+ - test_task: "test-bundled-gems"
+ configure: "--enable-yjit=dev"
+ - test_task: "yjit-bench"
+ configure: "--enable-yjit=dev"
+ yjit_bench_opts: "--yjit-stats"
env:
- GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
+ GITPULLOPTIONS: --no-tags origin ${{github.ref}}
RUN_OPTS: ${{ matrix.yjit_opts }}
YJIT_BENCH_OPTS: ${{ matrix.yjit_bench_opts }}
- SPECOPTS: ${{ matrix.specopts }}
RUBY_DEBUG: ci
BUNDLE_JOBS: 8 # for yjit-bench
- RUST_BACKTRACE: 1
-
- runs-on: ubuntu-20.04
-
- if: >-
- ${{!(false
- || contains(github.event.head_commit.message, '[DOC]')
- || contains(github.event.head_commit.message, 'Document')
- || contains(github.event.pull_request.title, '[DOC]')
- || contains(github.event.pull_request.title, 'Document')
- || contains(github.event.pull_request.labels.*.name, 'Document')
- || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
- )}}
-
+ runs-on: ubuntu-22.04
+ if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }}
steps:
- - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
- with:
- sparse-checkout-cone-mode: false
- sparse-checkout: /.github
-
- - uses: ./.github/actions/setup/ubuntu
-
- - uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
- with:
- ruby-version: '3.0'
- bundler: none
-
- - uses: ./.github/actions/setup/directories
- with:
- srcdir: src
- builddir: build
- makeup: true
- dummy-files: ${{ matrix.test_task == 'check' }}
- # Set fetch-depth: 10 so that Launchable can receive commits information.
- fetch-depth: 10
-
+ - run: mkdir build
+ working-directory:
+ - name: Install libraries
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
- name: Install Rust
if: ${{ matrix.rust_version }}
run: rustup install ${{ matrix.rust_version }} --profile minimal
-
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ with:
+ path: src
+ - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: src/.downloaded-cache
+ key: downloaded-cache
+ - name: Fixed world writable dirs
+ run: |
+ chmod -v go-w $HOME $HOME/.config
+ sudo chmod -R go-w /usr/share
+ sudo bash -c 'IFS=:; for d in '"$PATH"'; do chmod -v go-w $d; done' || :
+ - name: Set ENV
+ run: |
+ echo "GNUMAKEFLAGS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+ - run: ./autogen.sh
+ working-directory: src
- name: Run configure
run: ../src/configure -C --disable-install-doc --prefix=$(pwd)/install ${{ matrix.configure }}
-
- run: make incs
-
- run: make prepare-gems
if: ${{ matrix.test_task == 'test-bundled-gems' }}
-
- - run: make
-
+ - run: make -j
+ - run: make leaked-globals
+ if: ${{ matrix.test_task == 'check' }}
+ - name: Create dummy files in build dir
+ run: |
+ ./miniruby -e '(("a".."z").to_a+("A".."Z").to_a+("0".."9").to_a+%w[foo bar test zzz]).each{|basename|File.write("#{basename}.rb", "raise %(do not load #{basename}.rb)")}'
+ if: ${{ matrix.test_task == 'check' }}
- name: Enable YJIT through ENV
run: echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
-
# Check that the binary was built with YJIT
- name: Check YJIT enabled
run: ./miniruby --yjit -v | grep "+YJIT"
-
- - name: Set up Launchable
- uses: ./.github/actions/launchable/setup
- with:
- os: ubuntu-20.04
- test-opts: ${{ matrix.configure }}
- launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
- builddir: build
- srcdir: src
- continue-on-error: true
-
- name: make ${{ matrix.test_task }}
- run: >-
- make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
- RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug SPECOPTS="$SPECOPTS"
- YJIT_BENCH_OPTS="$YJIT_BENCH_OPTS" YJIT_BINDGEN_DIFF_OPTS="$YJIT_BINDGEN_DIFF_OPTS"
- timeout-minutes: 90
+ run: make -s -j ${{ matrix.test_task }} RUN_OPTS="$RUN_OPTS" YJIT_BENCH_OPTS="$YJIT_BENCH_OPTS"
+ timeout-minutes: 60
env:
- RUBY_TESTOPTS: '-q --tty=no'
- TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
- PRECHECK_BUNDLED_GEMS: 'no'
- SYNTAX_SUGGEST_TIMEOUT: '5'
- YJIT_BINDGEN_DIFF_OPTS: '--exit-code'
- continue-on-error: ${{ matrix.continue-on-test_task || false }}
-
+ RUBY_TESTOPTS: "-q --tty=no"
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ""
+ PRECHECK_BUNDLED_GEMS: "no"
+ LIBCLANG_PATH: ${{ matrix.libclang_path }}
+ continue-on-error: ${{ matrix.test_task == 'yjit-bench' }}
- name: Show ${{ github.event.pull_request.base.ref }} GitHub URL for yjit-bench comparison
run: echo "https://github.com/${BASE_REPO}/commit/${BASE_SHA}"
env:
BASE_REPO: ${{ github.event.pull_request.base.repo.full_name }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
if: ${{ matrix.test_task == 'yjit-bench' && startsWith(github.event_name, 'pull') }}
-
- - uses: ./.github/actions/slack
+ - uses: ruby/action-slack@0bd85c72233cdbb6a0fe01d37aaeff1d21b5fce1 # v3.2.1
with:
- label: ${{ matrix.test_task }} ${{ matrix.configure }}
+ payload: |
+ {
+ "ci": "GitHub Actions",
+ "env": "${{ github.workflow }} / ${{ matrix.test_task }} ${{ matrix.configure }}",
+ "url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
+ "commit": "${{ github.sha }}",
+ "branch": "${{ github.ref_name }}"
+ }
+ env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: ${{ failure() }}
-
- result:
- if: ${{ always() }}
- name: ${{ github.workflow }} result
- runs-on: ubuntu-latest
- needs: [make]
- steps:
- - run: exit 1
- working-directory:
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.gitignore b/.gitignore
index b6beba3b3e..99d32a1825 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,7 +50,6 @@ y.tab.c
*.gcno
*.gcov
*.vscode
-!misc/.vscode
lcov*.info
# /
@@ -124,7 +123,6 @@ lcov*.info
/repack
/revision.h
/revision.tmp
-/ripper.tmp.y
/riscos
/rubicon
/ruby
@@ -138,7 +136,6 @@ lcov*.info
/test.rb
/test-coverage.dat
/tmp
-/vcpkg_installed
/transdb.h
/uncommon.mk
/verconf.h
@@ -167,7 +164,6 @@ lcov*.info
# /coroutine/
!/coroutine/**/*.s
-!/coroutine/**/*.S
# /enc/trans/
/enc/trans/*.c
@@ -207,10 +203,8 @@ lcov*.info
# /ext/ripper/
/ext/ripper/eventids1.c
-/ext/ripper/eventids1.h
/ext/ripper/.eventids2-check
/ext/ripper/eventids2table.c
-/ext/ripper/ripper_init.c
/ext/ripper/ripper.*
/ext/ripper/ids1
/ext/ripper/ids2
@@ -232,9 +226,8 @@ lcov*.info
# /misc/
/misc/**/__pycache__
-# for `make test-bundler`
+# /spec/bundler
/.rspec_status
-/tool/bundler/*.lock
# /tool/
/tool/config.guess
@@ -243,12 +236,11 @@ lcov*.info
# /win32/
/win32/*.ico
-# RJIT
-/include/ruby-*/*/rb_rjit_min_header-*.h
-/lib/ruby_vm/rjit/instruction.rb
-/lib/ruby_vm/rjit/instruction.rb
-/rjit_config.h
-/rb_rjit_header.h*
+# MJIT
+/include/ruby-*/*/rb_mjit_min_header-*.h
+/lib/ruby_vm/mjit/instruction.rb
+/mjit_config.h
+/rb_mjit_header.h
# YJIT
/yjit-bench
@@ -256,28 +248,3 @@ lcov*.info
# /wasm/
/wasm/tests/*.wasm
-
-# prism
-/lib/prism/compiler.rb
-/lib/prism/dispatcher.rb
-/lib/prism/dot_visitor.rb
-/lib/prism/dsl.rb
-/lib/prism/inspect_visitor.rb
-/lib/prism/mutation_compiler.rb
-/lib/prism/node.rb
-/lib/prism/reflection.rb
-/lib/prism/serialize.rb
-/lib/prism/visitor.rb
-/prism/api_node.c
-/prism/ast.h
-/prism/diagnostic.c
-/prism/diagnostic.h
-/prism/node.c
-/prism/prettyprint.c
-/prism/serialize.c
-/prism/token_type.c
-
-# tool/update-NEWS-gemlist.rb
-/bundled_gems.json
-/default_gems.json
-/gems/default_gems
diff --git a/.mailmap b/.mailmap
deleted file mode 100644
index 213a0f4916..0000000000
--- a/.mailmap
+++ /dev/null
@@ -1,431 +0,0 @@
-git[bot] <svn-admin@ruby-lang.org>
-git[bot] <svn-admin@ruby-lang.org> git <svn@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-svn[bot] <svn-admin@ruby-lang.org> svn <svn@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# a_matsuda
-Akira Matsuda <ronnie@dio.jp>
-Akira Matsuda <ronnie@dio.jp> <a_matsuda@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# aamine
-Minero Aoki <aamine@loveruby.net>
-Minero Aoki <aamine@loveruby.net> <aamine@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# akira
-akira yamada <akira@ruby-lang.org>
-## akira yamada <akira@ruby-lang.org> <akira@rice.p.arika.org>
-akira yamada <akira@ruby-lang.org> <akira@arika.org>
-akira yamada <akira@ruby-lang.org> <akira@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# akiyoshi
-AKIYOSHI, Masamichi <masamichi.akiyoshi@hp.com>
-AKIYOSHI, Masamichi <masamichi.akiyoshi@hp.com> <akiyoshi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# akr
-Tanaka Akira <akr@fsij.org>
-Tanaka Akira <akr@fsij.org> <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# arai
-Koji Arai <jca02266@nifty.ne.jp>
-Koji Arai <jca02266@nifty.ne.jp> <arai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# arton
-Akio Tajima <artonx@yahoo.co.jp>
-Akio Tajima <artonx@yahoo.co.jp> <arton@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# aycabta
-aycabta <aycabta@gmail.com>
-aycabta <aycabta@gmail.com> <aycabta@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# ayumin
-Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-Ayumu AIZAWA <ayumu.aizawa@gmail.com> <ayumin@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# azav
-Alexander Zavorine <alexandre.zavorine@nokia.com>
-Alexander Zavorine <alexandre.zavorine@nokia.com> <azav@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# charliesome
-Charlie Somerville <charliesome@ruby-lang.org>
-Charlie Somerville <charliesome@ruby-lang.org> <charliesome@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# dave
-Dave Thomas <dave@pragprog.com>
-Dave Thomas <dave@pragprog.com> <dave@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# davidflanagan
-David Flanagan <davidflanagan@ruby-lang.org>
-David Flanagan <davidflanagan@ruby-lang.org> <david@think32>
-David Flanagan <davidflanagan@ruby-lang.org> <david@davidflanagan.com>
-David Flanagan <davidflanagan@ruby-lang.org> <davidflanagan@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# dblack
-David A. Black <dblack@rubypal.com>
-David A. Black <dblack@rubypal.com> <dblack@wobblini.net>
-David A. Black <dblack@rubypal.com> <dblack@superlink.net>
-David A. Black <dblack@rubypal.com> <dblack@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# drbrain
-Eric Hodel <drbrain@segment7.net>
-Eric Hodel <drbrain@segment7.net> <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# duerst
-Martin Dürst <duerst@it.aoyama.ac.jp>
-Martin Dürst <duerst@it.aoyama.ac.jp> <duerst@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# eban
-WATANABE Hirofumi <eban@ruby-lang.org>
-WATANABE Hirofumi <eban@ruby-lang.org> <eban@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# emboss
-Martin Bosslet <Martin.Bosslet@gmail.com>
-Martin Bosslet <Martin.Bosslet@gmail.com> <Martin.Bosslet@googlemail.com>
-Martin Bosslet <Martin.Bosslet@gmail.com> <emboss@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# eregon
-Benoit Daloze <eregontp@gmail.com>
-Benoit Daloze <eregontp@gmail.com> <eregon@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# evan
-Evan Phoenix <evan@ruby-lang.org>
-Evan Phoenix <evan@ruby-lang.org> <evan@fallingsnow.net>
-Evan Phoenix <evan@ruby-lang.org> <evan@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# glass
-Masaki Matsushita <glass.saga@gmail.com>
-Masaki Matsushita <glass.saga@gmail.com> <glass@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# gogotanaka
-Kazuki Tanaka <gogotanaka@ruby-lang.org>
-Kazuki Tanaka <gogotanaka@ruby-lang.org> <gogotanaka@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# gotoken
-Kentaro Goto <gotoken@gmail.com>
-Kentaro Goto <gotoken@gmail.com> <gotoken@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# gotoyuzo
-GOTOU Yuuzou <gotoyuzo@notwork.org>
-GOTOU Yuuzou <gotoyuzo@notwork.org> <gotoyuzo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# gsinclair
-Gavin Sinclair <gsinclair@soyabean.com.au>
-Gavin Sinclair <gsinclair@soyabean.com.au> <gsinclair@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# H_Konishi
-KONISHI Hiromasa <konishih@fd6.so-net.ne.jp>
-KONISHI Hiromasa <konishih@fd6.so-net.ne.jp> <H_Konishi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# headius
-Charles Oliver Nutter <headius@headius.com>
-Charles Oliver Nutter <headius@headius.com> <headius@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# hone
-Terence Lee <hone@heroku.com>
-Terence Lee <hone@heroku.com> <hone@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# hsbt
-Hiroshi SHIBATA <hsbt@ruby-lang.org>
-Hiroshi SHIBATA <hsbt@ruby-lang.org> <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# iwamatsu
-Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
-Nobuhiro Iwamatsu <iwamatsu@nigauri.org> <iwamatsu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# jeg2
-James Edward Gray II <james@graysoftinc.com>
-James Edward Gray II <james@graysoftinc.com> <jeg2@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# jim
-Jim Weirich <jim@tardis.local>
-Jim Weirich <jim@tardis.local> <jim@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# k0kubun
-Takashi Kokubun <takashikkbn@gmail.com>
-Takashi Kokubun <takashikkbn@gmail.com> <k0kubun@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# kanemoto
-Yutaka Kanemoto <kanemoto@ruby-lang.org>
-Yutaka Kanemoto <kanemoto@ruby-lang.org> <kanemoto@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# katsu
-UENO Katsuhiro <katsu@blue.sky.or.jp>
-UENO Katsuhiro <katsu@blue.sky.or.jp> <katsu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# kazu
-Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-Kazuhiro NISHIYAMA <zn@mbf.nifty.com> <kazu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# keiju
-Keiju Ishitsuka <keiju@ishitsuka.com>
-Keiju Ishitsuka <keiju@ishitsuka.com> <keiju@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# knu
-Akinori MUSHA <knu@iDaemons.org>
-Akinori MUSHA <knu@iDaemons.org> <knu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# ko1
-Koichi Sasada <ko1@atdot.net>
-Koichi Sasada <ko1@atdot.net> <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# kosaki
-KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-KOSAKI Motohiro <kosaki.motohiro@gmail.com> <kosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# kosako
-K.Kosako <sndgk393@ybb.ne.jp>
-K.Kosako <sndgk393@ybb.ne.jp> <kosako@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# kou
-Sutou Kouhei <kou@clear-code.com>
-Sutou Kouhei <kou@clear-code.com> <kou@cozmixng.org>
-Sutou Kouhei <kou@clear-code.com> <kou@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# kouji
-Kouji Takao <kouji.takao@gmail.com>
-Kouji Takao <kouji.takao@gmail.com> <kouji@takao7.net>
-Kouji Takao <kouji.takao@gmail.com> <kouji@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# ksaito
-Kazuo Saito <ksaito@uranus.dti.ne.jp>
-Kazuo Saito <ksaito@uranus.dti.ne.jp> <ksaito@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# ktsj
-Kazuki Tsujimoto <kazuki@callcc.net>
-Kazuki Tsujimoto <kazuki@callcc.net> <ktsj@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# luislavena
-Luis Lavena <luislavena@gmail.com>
-Luis Lavena <luislavena@gmail.com> <luislavena@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# mame
-Yusuke Endoh <mame@ruby-lang.org>
-## Yusuke Endoh <mame@ruby-lang.org> <mame@tsg.ne.jp>
-Yusuke Endoh <mame@ruby-lang.org> <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# marcandre
-Marc-Andre Lafortune <github@marc-andre.ca>
-Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-Marc-Andre Lafortune <ruby-core@marc-andre.ca> <marcandre@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# matz
-Yukihiro "Matz" Matsumoto <matz@ruby.or.jp>
-Yukihiro "Matz" Matsumoto <matz@ruby.or.jp> <matz@ruby-lang.org>
-Yukihiro "Matz" Matsumoto <matz@ruby.or.jp> <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# michal
-Michal Rokos <michal@ruby-lang.org>
-Michal Rokos <michal@ruby-lang.org> <michal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# mneumann
-Michael Neumann <mneumann@ruby-lang.org>
-Michael Neumann <mneumann@ruby-lang.org> <mneumann@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# mrkn
-Kenta Murata <mrkn@mrkn.jp>
-Kenta Murata <mrkn@mrkn.jp> <muraken@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-Kenta Murata <mrkn@mrkn.jp> <3959+mrkn@users.noreply.github.com>
-Kenta Murata <mrkn@mrkn.jp> <mrkn@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# nagachika
-nagachika <nagachika@ruby-lang.org>
-nagachika <nagachika@ruby-lang.org> <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# nagai
-Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
-Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp> <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# nahi
-Hiroshi Nakamura <nahi@ruby-lang.org>
-Hiroshi Nakamura <nahi@ruby-lang.org> <nahi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# nari
-Narihiro Nakamura <authornari@gmail.com>
-Narihiro Nakamura <authornari@gmail.com> <nari@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# naruse
-NARUSE, Yui <naruse@airemix.jp>
-NARUSE, Yui <naruse@airemix.jp> <naruse@ruby-lang.org>
-NARUSE, Yui <naruse@airemix.jp> <naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# ngoto
-Naohisa Goto <ngotogenome@gmail.com>
-Naohisa Goto <ngotogenome@gmail.com> <ngoto@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# nobu
-Nobuyoshi Nakada <nobu@ruby-lang.org>
-Nobuyoshi Nakada <nobu@ruby-lang.org> <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# normal
-Eric Wong <normal@ruby-lang.org>
-Eric Wong <normal@ruby-lang.org> <e@80x24.org>
-Eric Wong <normal@ruby-lang.org> <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# ntalbott
-Nathaniel Talbott <ntalbott@ruby-lang.org>
-Nathaniel Talbott <ntalbott@ruby-lang.org> <ntalbott@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# ocean
-Hirokazu Yamamoto <ocean@m2.ccsnet.ne.jp>
-Hirokazu Yamamoto <ocean@m2.ccsnet.ne.jp> <ocean@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# odaira
-Rei Odaira <rodaira@us.ibm.com>
-Rei Odaira <rodaira@us.ibm.com> <Rei.Odaira@gmail.com>
-Rei Odaira <rodaira@us.ibm.com> <odaira@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# okkez
-okkez <okkez000@gmail.com>
-okkez <okkez000@gmail.com> <okkez@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# rhe
-Kazuki Yamaguchi <k@rhe.jp>
-Kazuki Yamaguchi <k@rhe.jp> <rhe@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# ryan
-Ryan Davis <ryand-github@zenspider.com>
-Ryan Davis <ryand-github@zenspider.com> <ryand-ruby@zenspider.com>
-Ryan Davis <ryand-github@zenspider.com> <ryan@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# samuel
-Samuel Williams <samuel.williams@oriontransfer.co.nz>
-Samuel Williams <samuel.williams@oriontransfer.co.nz> <samuel@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# seki
-Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
-Masatoshi SEKI <m_seki@mva.biglobe.ne.jp> <seki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# ser
-Sean Russell <ser@germane-software.com>
-Sean Russell <ser@germane-software.com> <ser@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# shigek
-Shigeo Kobayashi <shigek@ruby-lang.org>
-Shigeo Kobayashi <shigek@ruby-lang.org> <shigek@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# shirosaki
-Hiroshi Shirosaki <h.shirosaki@gmail.com>
-Hiroshi Shirosaki <h.shirosaki@gmail.com> <shirosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# sho-h
-Sho Hashimoto <sho-h@ruby-lang.org>
-Sho Hashimoto <sho-h@ruby-lang.org> <sho-h@netlab.jp>
-Sho Hashimoto <sho-h@ruby-lang.org> <sho.hsmt@gmail.com>
-Sho Hashimoto <sho-h@ruby-lang.org> <sho-h@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# shugo
-Shugo Maeda <shugo@ruby-lang.org>
-Shugo Maeda <shugo@ruby-lang.org> <shugo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# shyouhei
-åœéƒ¨æ˜Œå¹³ <shyouhei@ruby-lang.org>
-åœéƒ¨æ˜Œå¹³ <shyouhei@ruby-lang.org> <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# siena
-Siena. <siena@faculty.chiba-u.jp>
-Siena. <siena@faculty.chiba-u.jp> <siena@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# sonots
-sonots <sonots@gmail.com>
-sonots <sonots@gmail.com> <sonots@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# sorah
-Sorah Fukumori <her@sorah.jp>
-Sorah Fukumori <her@sorah.jp> <sorah@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# stomar
-Marcus Stollsteimer <sto.mar@web.de>
-Marcus Stollsteimer <sto.mar@web.de> <stomar@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# suke
-Masaki Suketa <masaki.suketa@nifty.ne.jp>
-Masaki Suketa <masaki.suketa@nifty.ne.jp> <suke@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# tadd
-Tadashi Saito <tad.a.digger@gmail.com>
-Tadashi Saito <tad.a.digger@gmail.com> <tadd@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# tadf
-Tadayoshi Funaba <tadf@dotrb.org>
-Tadayoshi Funaba <tadf@dotrb.org> <tadf@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# takano32
-TAKANO Mitsuhiro <takano32@gmail.com>
-TAKANO Mitsuhiro <takano32@gmail.com> <takano32@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# tarui
-Masaya Tarui <tarui@ruby-lang.org>
-Masaya Tarui <tarui@ruby-lang.org> <tarui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# technorama
-Technorama Ltd. <oss-ruby@technorama.net>
-Technorama Ltd. <oss-ruby@technorama.net> <technorama@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# tenderlove
-Aaron Patterson <tenderlove@ruby-lang.org>
-Aaron Patterson <tenderlove@ruby-lang.org> <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# tmm1
-Aman Gupta <ruby@tmm1.net>
-Aman Gupta <ruby@tmm1.net> <tmm1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# ts
-Guy Decoux <ts@moulon.inra.fr>
-Guy Decoux <ts@moulon.inra.fr> <ts@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# ttate
-Takaaki Tateishi <ttate@ttsky.net>
-## Takaaki Tateishi <ttate@ttsky.net> <ttate@kt.jaist.ac.jp>
-Takaaki Tateishi <ttate@ttsky.net> <ttate@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# uema2
-Takaaki Uematsu <uema2x@jcom.home.ne.jp>
-Takaaki Uematsu <uema2x@jcom.home.ne.jp> <uema2@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# usa
-U.Nakamura <usa@ruby-lang.org>
-U.Nakamura <usa@ruby-lang.org> <usa@garbagecollect.jp>
-U.Nakamura <usa@ruby-lang.org> <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# wakou
-Wakou Aoyama <wakou@ruby-lang.org>
-Wakou Aoyama <wakou@ruby-lang.org> <wakou@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# wanabe
-wanabe <s.wanabe@gmail.com>
-wanabe <s.wanabe@gmail.com> <wanabe@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# watson1978
-Watson <watson1978@gmail.com>
-Watson <watson1978@gmail.com> <watson1978@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# wew
-William Webber <william@williamwebber.com>
-William Webber <william@williamwebber.com> <wew@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# why
-why the lucky stiff <why@ruby-lang.org>
-why the lucky stiff <why@ruby-lang.org> <why@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# xibbar
-Takeyuki FUJIOKA <xibbar@ruby-lang.org>
-Takeyuki FUJIOKA <xibbar@ruby-lang.org> <xibbar@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# yugui
-Yuki Yugui Sonoda <yugui@yugui.jp>
-Yuki Yugui Sonoda <yugui@yugui.jp> <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# yui-knk
-yui-knk <spiketeika@gmail.com>
-yui-knk <spiketeika@gmail.com> <yui-knk@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# yuki
-Yuki Nishijima <yuki24@hey.com>
-Yuki Nishijima <yuki24@hey.com> <mail@yukinishijima.net>
-Yuki Nishijima <yuki24@hey.com> <yuki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# zsombor
-Dee Zsombor <zsombor@ruby-lang.org>
-Dee Zsombor <zsombor@ruby-lang.org> <zsombor@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
-
-# zzak
-zzak <zzakscott@gmail.com>
-zzak <zzakscott@gmail.com> <zzak@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
diff --git a/.rdoc_options b/.rdoc_options
index 4dfbfa140c..760507c7a2 100644
--- a/.rdoc_options
+++ b/.rdoc_options
@@ -1,9 +1,4 @@
---
page_dir: doc
-charset: UTF-8
-encoding: UTF-8
main_page: README.md
title: Documentation for Ruby development version
-visibility: :private
-rdoc_include:
-- doc
diff --git a/LEGAL b/LEGAL
index 162ba78483..0423d57ac9 100644
--- a/LEGAL
+++ b/LEGAL
@@ -58,12 +58,12 @@ mentioned below.
[ccan/list/list.h]
- This file is licensed under the {MIT License}[rdoc-ref:@MIT+License].
+ This file is licensed under the {MIT License}[rdoc-label:label-MIT+License].
[coroutine]
Unless otherwise specified, these files are licensed under the
- {MIT License}[rdoc-ref:@MIT+License].
+ {MIT License}[rdoc-label:label-MIT+License].
[include/ruby/onigmo.h]
[include/ruby/oniguruma.h]
@@ -546,7 +546,7 @@ mentioned below.
[vsnprintf.c]
- This file is under the {old-style BSD license}[rdoc-ref:@Old-style+BSD+license].
+ This file is under the {old-style BSD license}[rdoc-label:label-Old-style+BSD+license].
>>>
Copyright (c) 1990, 1993::
@@ -577,7 +577,7 @@ mentioned below.
[missing/crypt.c]
- This file is under the {old-style BSD license}[rdoc-ref:@Old-style+BSD+license].
+ This file is under the {old-style BSD license}[rdoc-label:label-Old-style+BSD+license].
>>>
Copyright (c) 1989, 1993::
@@ -588,7 +588,7 @@ mentioned below.
[missing/setproctitle.c]
- This file is under the {old-style BSD license}[rdoc-ref:@Old-style+BSD+license].
+ This file is under the {old-style BSD license}[rdoc-label:label-Old-style+BSD+license].
>>>
Copyright 2003:: Damien Miller
@@ -727,10 +727,29 @@ mentioned below.
for internal or external distribution as long as this notice
remains attached.
+[ext/nkf/nkf-utf8/config.h]
+[ext/nkf/nkf-utf8/nkf.c]
+[ext/nkf/nkf-utf8/utf8tbl.c]
+
+ These files are under the following license. So to speak, it is
+ copyrighted semi-public-domain software.
+
+ >>>
+ Copyright (C) 1987:: Fujitsu LTD. (Itaru ICHIKAWA)
+
+ Everyone is permitted to do anything on this program
+ including copying, modifying, improving,
+ as long as you don't try to pretend that you wrote it.
+ i.e., the above copyright notice has to appear in all copies.
+ Binary distribution requires original version messages.
+ You don't have to ask before copying, redistribution or publishing.
+ THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE.
+
[ext/psych]
[test/psych]
- The files under these directories are under the following license.
+ The files under these directories are under the following license, except for
+ ext/psych/yaml.
>>>
Copyright 2009:: Aaron Patterson, et al.
@@ -753,6 +772,31 @@ mentioned below.
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+[ext/psych/yaml]
+
+ The files under this directory are under the following license.
+
+ >>>
+ Copyright (c) 2006:: Kirill Simonov
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
+ this software and associated documentation files (the "Software"), to deal in
+ the Software without restriction, including without limitation the rights to
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is furnished to do
+ so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
[ext/pty/pty.c]
>>>
@@ -861,7 +905,7 @@ mentioned below.
>>>
RubyGems is copyrighted free software by Chad Fowler, Rich Kilmer, Jim
Weirich and others. You can redistribute it and/or modify it under
- either the terms of the {MIT license}[rdoc-ref:@MIT+License], or the conditions
+ either the terms of the {MIT license}[rdoc-label:label-MIT+License], or the conditions
below:
1. You may make and give away verbatim copies of the source form of the
@@ -923,7 +967,7 @@ mentioned below.
Portions copyright (c) 2010:: Andre Arko
Portions copyright (c) 2009:: Engine Yard
- {MIT License}[rdoc-ref:@MIT+License]
+ {MIT License}[rdoc-label:label-MIT+License]
[lib/bundler/vendor/thor]
@@ -932,16 +976,16 @@ mentioned below.
>>>
Copyright (c) 2008 Yehuda Katz, Eric Hodel, et al.
- {MIT License}[rdoc-ref:@MIT+License]
+ {MIT License}[rdoc-label:label-MIT+License]
-[lib/rubygems/vendor/molinillo]
+[lib/rubygems/resolver/molinillo]
molinillo is under the following license.
>>>
Copyright (c) 2014 Samuel E. Giddins segiddins@segiddins.me
- {MIT License}[rdoc-ref:@MIT+License]
+ {MIT License}[rdoc-label:label-MIT+License]
[lib/bundler/vendor/pub_grub]
@@ -950,7 +994,7 @@ mentioned below.
>>>
Copyright (c) 2018 John Hawthorn
- {MIT License}[rdoc-ref:@MIT+License]
+ {MIT License}[rdoc-label:label-MIT+License]
[lib/bundler/vendor/connection_pool]
@@ -959,7 +1003,7 @@ mentioned below.
>>>
Copyright (c) 2011 Mike Perham
- {MIT License}[rdoc-ref:@MIT+License]
+ {MIT License}[rdoc-label:label-MIT+License]
[lib/bundler/vendor/net-http-persistent]
@@ -968,7 +1012,7 @@ mentioned below.
>>>
Copyright (c) Eric Hodel, Aaron Patterson
- {MIT License}[rdoc-ref:@MIT+License]
+ {MIT License}[rdoc-label:label-MIT+License]
[lib/did_you_mean]
[lib/did_you_mean.rb]
@@ -979,7 +1023,7 @@ mentioned below.
>>>
Copyright (c) 2014-2016 Yuki Nishijima
- {MIT License}[rdoc-ref:@MIT+License]
+ {MIT License}[rdoc-label:label-MIT+License]
[lib/error_highlight]
[lib/error_highlight.rb]
@@ -990,7 +1034,7 @@ mentioned below.
>>>
Copyright (c) 2021 Yusuke Endoh
- {MIT License}[rdoc-ref:@MIT+License]
+ {MIT License}[rdoc-label:label-MIT+License]
[benchmark/so_ackermann.rb]
[benchmark/so_array.rb]
diff --git a/NEWS.md b/NEWS.md
index a09437fda2..f6c3c6fc97 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,185 +1,820 @@
-# NEWS for Ruby 3.4.0
+# NEWS for Ruby 3.2.0
This document is a list of user-visible feature changes
-since the **3.3.0** release, except for bug fixes.
+since the **3.1.0** release, except for bug fixes.
Note that each entry is kept to a minimum, see links for details.
## Language changes
-* String literals in files without a `frozen_string_literal` comment now emit a deprecation warning
- when they are mutated.
- These warnings can be enabled with `-W:deprecated` or by setting `Warning[:deprecated] = true`.
- To disable this change, you can run Ruby with the `--disable-frozen-string-literal`
- command line argument. [[Feature #20205]]
+* Anonymous rest and keyword rest arguments can now be passed as
+ arguments, instead of just used in method parameters.
+ [[Feature #18351]]
-* `it` is added to reference a block parameter. [[Feature #18980]]
+ ```ruby
+ def foo(*)
+ bar(*)
+ end
+ def baz(**)
+ quux(**)
+ end
+ ```
+
+* A proc that accepts a single positional argument and keywords will
+ no longer autosplat. [[Bug #18633]]
+
+ ```ruby
+ proc{|a, **k| a}.call([1, 2])
+ # Ruby 3.1 and before
+ # => 1
+ # Ruby 3.2 and after
+ # => [1, 2]
+ ```
+
+* Constant assignment evaluation order for constants set on explicit
+ objects has been made consistent with single attribute assignment
+ evaluation order. With this code:
+
+ ```ruby
+ foo::BAR = baz
+ ```
+
+ `foo` is now called before `baz`. Similarly, for multiple assignments
+ to constants, left-to-right evaluation order is used. With this
+ code:
+
+ ```ruby
+ foo1::BAR1, foo2::BAR2 = baz1, baz2
+ ```
-* Keyword splatting `nil` when calling methods is now supported.
- `**nil` is treated similarly to `**{}`, passing no keywords,
- and not calling any conversion methods. [[Bug #20064]]
+ The following evaluation order is now used:
-* Block passing is no longer allowed in index assignment
- (e.g. `a[0, &b] = 1`). [[Bug #19918]]
+ 1. `foo1`
+ 2. `foo2`
+ 3. `baz1`
+ 4. `baz2`
-* Keyword arguments are no longer allowed in index assignment
- (e.g. `a[0, kw: 1] = 2`). [[Bug #20218]]
+ [[Bug #15928]]
-* `GC.config` added to allow setting configuration variables on the Garbage
- Collector. [[Feature #20443]]
+* "Find pattern" is no longer experimental.
+ [[Feature #18585]]
-* GC configuration parameter `rgengc_allow_full_mark` introduced. When `false`
- GC will only mark young objects. Default is `true`. [[Feature #20443]]
+* Methods taking a rest parameter (like `*args`) and wishing to delegate keyword
+ arguments through `foo(*args)` must now be marked with `ruby2_keywords`
+ (if not already the case). In other words, all methods wishing to delegate
+ keyword arguments through `*args` must now be marked with `ruby2_keywords`,
+ with no exception. This will make it easier to transition to other ways of
+ delegation once a library can require Ruby 3+. Previously, the `ruby2_keywords`
+ flag was kept if the receiving method took `*args`, but this was a bug and an
+ inconsistency. A good technique to find the potentially-missing `ruby2_keywords`
+ is to run the test suite, for where it fails find the last method which must
+ receive keyword arguments, use `puts nil, caller, nil` there, and check each
+ method/block on the call chain which must delegate keywords is correctly marked
+ as `ruby2_keywords`. [[Bug #18625]] [[Bug #16466]]
+
+ ```ruby
+ def target(**kw)
+ end
+
+ # Accidentally worked without ruby2_keywords in Ruby 2.7-3.1, ruby2_keywords
+ # needed in 3.2+. Just like (*args, **kwargs) or (...) would be needed on
+ # both #foo and #bar when migrating away from ruby2_keywords.
+ ruby2_keywords def bar(*args)
+ target(*args)
+ end
+
+ ruby2_keywords def foo(*args)
+ bar(*args)
+ end
+
+ foo(k: 1)
+ ```
## Core classes updates
Note: We're only listing outstanding class updates.
+* Fiber
+
+ * Introduce Fiber.[] and Fiber.[]= for inheritable fiber storage.
+ Introduce Fiber#storage and Fiber#storage= (experimental) for
+ getting and resetting the current storage. Introduce
+ `Fiber.new(storage:)` for setting the storage when creating a
+ fiber. [[Feature #19078]]
+
+ Existing Thread and Fiber local variables can be tricky to use.
+ Thread-local variables are shared between all fibers, making it
+ hard to isolate, while Fiber-local variables can be hard to
+ share. It is often desirable to define unit of execution
+ ("execution context") such that some state is shared between all
+ fibers and threads created in that context. This is what Fiber
+ storage provides.
+
+ ```ruby
+ def log(message)
+ puts "#{Fiber[:request_id]}: #{message}"
+ end
+
+ def handle_requests
+ while request = read_request
+ Fiber.schedule do
+ Fiber[:request_id] = SecureRandom.uuid
+
+ request.messages.each do |message|
+ Fiber.schedule do
+ log("Handling #{message}") # Log includes inherited request_id.
+ end
+ end
+ end
+ end
+ end
+ ```
+
+ You should generally consider Fiber storage for any state which
+ you want to be shared implicitly between all fibers and threads
+ created in a given context, e.g. a connection pool, a request
+ id, a logger level, environment variables, configuration, etc.
+
+* Fiber::Scheduler
+
+ * Introduce `Fiber::Scheduler#io_select` for non-blocking IO.select.
+ [[Feature #19060]]
+
+* IO
+
+ * Introduce IO#timeout= and IO#timeout which can cause
+ IO::TimeoutError to be raised if a blocking operation exceeds the
+ specified timeout. [[Feature #18630]]
+
+ ```ruby
+ STDIN.timeout = 1
+ STDIN.read # => Blocking operation timed out! (IO::TimeoutError)
+ ```
+
+ * Introduce `IO.new(..., path:)` and promote `File#path` to `IO#path`.
+ [[Feature #19036]]
+
+* Class
+
+ * Class#attached_object, which returns the object for which
+ the receiver is the singleton class. Raises TypeError if the
+ receiver is not a singleton class.
+ [[Feature #12084]]
+
+ ```ruby
+ class Foo; end
+
+ Foo.singleton_class.attached_object #=> Foo
+ Foo.new.singleton_class.attached_object #=> #<Foo:0x000000010491a370>
+ Foo.attached_object #=> TypeError: `Foo' is not a singleton class
+ nil.singleton_class.attached_object #=> TypeError: `NilClass' is not a singleton class
+ ```
+
+* Data
+
+ * New core class to represent simple immutable value object. The class is
+ similar to Struct and partially shares an implementation, but has more
+ lean and strict API. [[Feature #16122]]
+
+ ```ruby
+ Measure = Data.define(:amount, :unit)
+ distance = Measure.new(100, 'km') #=> #<data Measure amount=100, unit="km">
+ weight = Measure.new(amount: 50, unit: 'kg') #=> #<data Measure amount=50, unit="kg">
+ weight.with(amount: 40) #=> #<data Measure amount=40, unit="kg">
+ weight.amount #=> 50
+ weight.amount = 40 #=> NoMethodError: undefined method `amount='
+ ```
+
+* Encoding
+
+ * Encoding#replicate has been deprecated and will be removed in 3.3. [[Feature #18949]]
+ * The dummy `Encoding::UTF_16` and `Encoding::UTF_32` encodings no longer
+ try to dynamically guess the endian based on a byte order mark.
+ Use `Encoding::UTF_16BE`/`UTF_16LE` and `Encoding::UTF_32BE`/`UTF_32LE` instead.
+ This change speeds up getting the encoding of a String. [[Feature #18949]]
+ * Limit maximum encoding set size by 256.
+ If exceeding maximum size, `EncodingError` will be raised. [[Feature #18949]]
+
+* Enumerator
+
+ * Enumerator.product has been added. Enumerator::Product is the implementation. [[Feature #18685]]
+
* Exception
- * Exception#set_backtrace now accepts arrays of `Thread::Backtrace::Location`.
- `Kernel#raise`, `Thread#raise` and `Fiber#raise` also accept this new format. [[Feature #13557]]
+ * Exception#detailed_message has been added.
+ The default error printer calls this method on the Exception object
+ instead of #message. [[Feature #18564]]
-* Range
+* Hash
- * Range#size now raises TypeError if the range is not iterable. [[Misc #18984]]
- * Range#step now consistently has a semantics of iterating by using `+` operator
- for all types, not only numerics. [[Feature #18368]]
+ * Hash#shift now always returns nil if the hash is
+ empty, instead of returning the default value or
+ calling the default proc. [[Bug #16908]]
- ```ruby
- (Time.utc(2022, 2, 24)..).step(24*60*60).take(3)
- #=> [2022-02-24 00:00:00 UTC, 2022-02-25 00:00:00 UTC, 2022-02-26 00:00:00 UTC]
- ```
+* Integer
+
+ * Integer#ceildiv has been added. [[Feature #18809]]
+
+* Kernel
+
+ * Kernel#binding raises RuntimeError if called from a non-Ruby frame
+ (such as a method defined in C). [[Bug #18487]]
+
+* MatchData
+
+ * MatchData#byteoffset has been added. [[Feature #13110]]
+ * MatchData#deconstruct has been added. [[Feature #18821]]
+ * MatchData#deconstruct_keys has been added. [[Feature #18821]]
+
+* Module
+
+ * Module.used_refinements has been added. [[Feature #14332]]
+ * Module#refinements has been added. [[Feature #12737]]
+ * Module#const_added has been added. [[Feature #17881]]
+ * Module#undefined_instance_methods has been added. [[Feature #12655]]
+
+* Proc
+
+ * Proc#dup returns an instance of subclass. [[Bug #17545]]
+ * Proc#parameters now accepts lambda keyword. [[Feature #15357]]
+
+* Process
+ * Added `RLIMIT_NPTS` constant to FreeBSD platform
+
+* Regexp
+
+ * The cache-based optimization is introduced.
+ Many (but not all) Regexp matching is now in linear time, which
+ will prevent regular expression denial of service (ReDoS)
+ vulnerability. [[Feature #19104]]
+
+ * Regexp.linear_time? is introduced. [[Feature #19194]]
+
+ * Regexp.new now supports passing the regexp flags not only as an Integer,
+ but also as a String. Unknown flags raise ArgumentError.
+ Otherwise, anything other than `true`, `false`, `nil` or Integer will be warned.
+ [[Feature #18788]]
+
+ * Regexp.timeout= has been added. Also, Regexp.new new supports timeout keyword.
+ See [[Feature #17837]]
+
+* Refinement
+
+ * Refinement#refined_class has been added. [[Feature #12737]]
* RubyVM::AbstractSyntaxTree
- * Add `RubyVM::AbstractSyntaxTree::Node#locations` method which returns location objects
- associated with the AST node. [[Feature #20624]]
- * Add `RubyVM::AbstractSyntaxTree::Location` class which holds location information. [[Feature #20624]]
+ * Add `error_tolerant` option for `parse`, `parse_file` and `of`. [[Feature #19013]]
+ With this option
+
+ 1. SyntaxError is suppressed
+ 2. AST is returned for invalid input
+ 3. `end` is complemented when a parser reaches to the end of input but `end` is insufficient
+ 4. `end` is treated as keyword based on indent
+
+ ```ruby
+ # Without error_tolerant option
+ root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY)
+ def m
+ a = 10
+ if
+ end
+ RUBY
+ # => <internal:ast>:33:in `parse': syntax error, unexpected `end' (SyntaxError)
+
+ # With error_tolerant option
+ root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY, error_tolerant: true)
+ def m
+ a = 10
+ if
+ end
+ RUBY
+ p root # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-4:3>
+
+ # `end` is treated as keyword based on indent
+ root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY, error_tolerant: true)
+ module Z
+ class Foo
+ foo.
+ end
+
+ def bar
+ end
+ end
+ RUBY
+ p root.children[-1].children[-1].children[-1].children[-2..-1]
+ # => [#<RubyVM::AbstractSyntaxTree::Node:CLASS@2:2-4:5>, #<RubyVM::AbstractSyntaxTree::Node:DEFN@6:2-7:5>]
+ ```
+
+ * Add `keep_tokens` option for `parse`, `parse_file` and `of`. Add `#tokens` and `#all_tokens`
+ for RubyVM::AbstractSyntaxTree::Node [[Feature #19070]]
+
+ ```ruby
+ root = RubyVM::AbstractSyntaxTree.parse("x = 1 + 2", keep_tokens: true)
+ root.tokens # => [[0, :tIDENTIFIER, "x", [1, 0, 1, 1]], [1, :tSP, " ", [1, 1, 1, 2]], ...]
+ root.tokens.map{_1[2]}.join # => "x = 1 + 2"
+ ```
+
+* Set
+
+ * Set is now available as a built-in class without the need for `require "set"`. [[Feature #16989]]
+ It is currently autoloaded via the Set constant or a call to Enumerable#to_set.
+
+* String
+
+ * String#byteindex and String#byterindex have been added. [[Feature #13110]]
+ * Update Unicode to Version 15.0.0 and Emoji Version 15.0. [[Feature #18639]]
+ (also applies to Regexp)
+ * String#bytesplice has been added. [[Feature #18598]]
+ * String#dedup has been added as an alias to String#-@. [[Feature #18595]]
+
+* Struct
+
+ * A Struct class can also be initialized with keyword arguments
+ without `keyword_init: true` on Struct.new [[Feature #16806]]
+
+ ```ruby
+ Post = Struct.new(:id, :name)
+ Post.new(1, "hello") #=> #<struct Post id=1, name="hello">
+ # From Ruby 3.2, the following code also works without keyword_init: true.
+ Post.new(id: 1, name: "hello") #=> #<struct Post id=1, name="hello">
+ ```
+
+* Thread
+
+ * Thread.each_caller_location is added. [[Feature #16663]]
+
+* Thread::Queue
+
+ * Thread::Queue#pop(timeout: sec) is added. [[Feature #18774]]
+
+* Thread::SizedQueue
+
+ * Thread::SizedQueue#pop(timeout: sec) is added. [[Feature #18774]]
+ * Thread::SizedQueue#push(timeout: sec) is added. [[Feature #18944]]
+
+* Time
+
+ * Time#deconstruct_keys is added, allowing to use Time instances
+ in pattern-matching expressions [[Feature #19071]]
+
+ * Time.new now can parse a string like generated by Time#inspect
+ and return a Time instance based on the given argument.
+ [[Feature #18033]]
+
+* SyntaxError
+ * SyntaxError#path has been added. [[Feature #19138]]
+
+* TracePoint
+
+ * TracePoint#binding now returns `nil` for `c_call`/`c_return` TracePoints.
+ [[Bug #18487]]
+ * TracePoint#enable `target_thread` keyword argument now defaults to the
+ current thread if a block is given and `target` and `target_line` keyword
+ arguments are not passed. [[Bug #16889]]
+
+* UnboundMethod
+
+ * `UnboundMethod#==` returns `true` if the actual method is same. For example,
+ `String.instance_method(:object_id) == Array.instance_method(:object_id)`
+ returns `true`. [[Feature #18798]]
+
+ * `UnboundMethod#inspect` does not show the receiver of `instance_method`.
+ For example `String.instance_method(:object_id).inspect` returns
+ `"#<UnboundMethod: Kernel#object_id()>"`
+ (was `"#<UnboundMethod: String(Kernel)#object_id()>"`).
+
+* GC
+
+ * Expose `need_major_gc` via `GC.latest_gc_info`. [GH-6791]
+
+* ObjectSpace
+
+ * `ObjectSpace.dump_all` dump shapes as well. [GH-6868]
## Stdlib updates
-* Tempfile
-
- * The keyword argument `anonymous: true` is implemented for `Tempfile.create`.
- `Tempfile.create(anonymous: true)` removes the created temporary file immediately.
- So applications don't need to remove the file.
- [[Feature #20497]]
-
-The following default gems are updated.
-
-* RubyGems 3.6.0.dev
-* bundler 2.6.0.dev
-* erb 4.0.4
-* fiddle 1.1.3.dev
-* io-console 0.7.2
-* irb 1.14.1
-* json 2.7.2
-* logger 1.6.1
-* net-http 0.4.1
-* optparse 0.5.0
-* prism 1.0.0
-* psych 5.2.0.beta1
-* rdoc 6.7.0
-* reline 0.5.10
-* resolv 0.4.0
-* stringio 3.1.2.dev
-* strscan 3.1.1.dev
-* time 0.4.0
-* uri 0.13.1
-* zlib 3.1.1
-
-The following bundled gems are updated.
-
-* minitest 5.25.1
-* power_assert 2.0.4
-* rake 13.2.1
-* test-unit 3.6.2
-* rexml 3.3.8
-* rss 0.3.1
-* net-ftp 0.3.8
-* net-imap 0.4.16
-* net-smtp 0.5.0
-* rbs 3.6.1
-* typeprof 0.21.11
-* debug 1.9.2
-* racc 1.8.1
-
-The following bundled gems are promoted from default gems.
-
-* mutex_m 0.2.0
-* getoptlong 0.2.1
-* base64 0.2.0
-* bigdecimal 3.1.8
-* observer 0.1.2
-* abbrev 0.1.2
-* resolv-replace 0.1.1
-* rinda 0.2.0
-* drb 2.2.1
-* nkf 0.2.0
-* syslog 0.1.2
-* csv 3.3.0
-* repl_type_completor 0.1.7
+* Bundler
+
+ * Bundler now uses [PubGrub] resolver instead of [Molinillo] for performance improvement.
+ * Add --ext=rust support to bundle gem for creating simple gems with Rust extensions.
+ [[GH-rubygems-6149]]
+ * Make cloning git repos faster [[GH-rubygems-4475]]
+
+* RubyGems
+
+ * Add mswin support for cargo builder. [[GH-rubygems-6167]]
+
+* CGI
+
+ * `CGI.escapeURIComponent` and `CGI.unescapeURIComponent` are added.
+ [[Feature #18822]]
+
+* Coverage
+
+ * `Coverage.setup` now accepts `eval: true`. By this, `eval` and related methods are
+ able to generate code coverage. [[Feature #19008]]
+
+ * `Coverage.supported?(mode)` enables detection of what coverage modes are
+ supported. [[Feature #19026]]
+
+* Date
+
+ * Added `Date#deconstruct_keys` and `DateTime#deconstruct_keys` same as [[Feature #19071]]
+
+* ERB
+
+ * `ERB::Util.html_escape` is made faster than `CGI.escapeHTML`.
+ * It no longer allocates a String object when no character needs to be escaped.
+ * It skips calling `#to_s` method when an argument is already a String.
+ * `ERB::Escape.html_escape` is added as an alias to `ERB::Util.html_escape`,
+ which has not been monkey-patched by Rails.
+ * `ERB::Util.url_encode` is made faster using `CGI.escapeURIComponent`.
+ * `-S` option is removed from `erb` command.
+
+* FileUtils
+
+ * Add FileUtils.ln_sr method and `relative:` option to FileUtils.ln_s.
+ [[Feature #18925]]
+
+* IRB
+
+ * debug.gem integration commands have been added: `debug`, `break`, `catch`,
+ `next`, `delete`, `step`, `continue`, `finish`, `backtrace`, `info`
+ * They work even if you don't have `gem "debug"` in your Gemfile.
+ * See also: [What's new in Ruby 3.2's IRB?](https://st0012.dev/whats-new-in-ruby-3-2-irb)
+ * More Pry-like commands and features have been added.
+ * `edit` and `show_cmds` (like Pry's `help`) are added.
+ * `ls` takes `-g` or `-G` option to filter out outputs.
+ * `show_source` is aliased from `$` and accepts unquoted inputs.
+ * `whereami` is aliased from `@`.
+
+* Net::Protocol
+
+ * Improve `Net::BufferedIO` performance. [[GH-net-protocol-14]]
+
+* Pathname
+
+ * Added `Pathname#lutime`. [[GH-pathname-20]]
+
+* Socket
+
+ * Added the following constants for supported platforms.
+ * `SO_INCOMING_CPU`
+ * `SO_INCOMING_NAPI_ID`
+ * `SO_RTABLE`
+ * `SO_SETFIB`
+ * `SO_USER_COOKIE`
+ * `TCP_KEEPALIVE`
+ * `TCP_CONNECTION_INFO`
+
+* SyntaxSuggest
+
+ * The feature of `syntax_suggest` formerly `dead_end` is integrated in Ruby.
+ [[Feature #18159]]
+
+* UNIXSocket
+
+ * Add support for UNIXSocket on Windows. Emulate anonymous sockets. Add
+ support for File.socket? and File::Stat#socket? where possible.
+ [[Feature #19135]]
+
+* The following default gems are updated.
+
+ * RubyGems 3.4.1
+ * abbrev 0.1.1
+ * benchmark 0.2.1
+ * bigdecimal 3.1.3
+ * bundler 2.4.1
+ * cgi 0.3.6
+ * csv 3.2.6
+ * date 3.3.3
+ * delegate 0.3.0
+ * did_you_mean 1.6.3
+ * digest 3.1.1
+ * drb 2.1.1
+ * english 0.7.2
+ * erb 4.0.2
+ * error_highlight 0.5.1
+ * etc 1.4.2
+ * fcntl 1.0.2
+ * fiddle 1.1.1
+ * fileutils 1.7.0
+ * forwardable 1.3.3
+ * getoptlong 0.2.0
+ * io-console 0.6.0
+ * io-nonblock 0.2.0
+ * io-wait 0.3.0
+ * ipaddr 1.2.5
+ * irb 1.6.2
+ * json 2.6.3
+ * logger 1.5.3
+ * mutex_m 0.1.2
+ * net-http 0.4.0
+ * net-protocol 0.2.1
+ * nkf 0.1.2
+ * open-uri 0.3.0
+ * open3 0.1.2
+ * openssl 3.1.0
+ * optparse 0.3.1
+ * ostruct 0.5.5
+ * pathname 0.2.1
+ * pp 0.4.0
+ * pstore 0.1.2
+ * psych 5.0.1
+ * racc 1.6.2
+ * rdoc 6.5.0
+ * readline-ext 0.1.5
+ * reline 0.3.2
+ * resolv 0.2.2
+ * resolv-replace 0.1.1
+ * securerandom 0.2.2
+ * set 1.0.3
+ * stringio 3.0.4
+ * strscan 3.0.5
+ * syntax_suggest 1.0.2
+ * syslog 0.1.1
+ * tempfile 0.1.3
+ * time 0.2.1
+ * timeout 0.3.1
+ * tmpdir 0.1.3
+ * tsort 0.1.1
+ * un 0.2.1
+ * uri 0.12.0
+ * weakref 0.1.2
+ * win32ole 1.8.9
+ * yaml 0.2.1
+ * zlib 3.0.0
+
+* The following bundled gems are updated.
+
+ * minitest 5.16.3
+ * power_assert 2.0.3
+ * test-unit 3.5.7
+ * net-ftp 0.2.0
+ * net-imap 0.3.4
+ * net-pop 0.1.2
+ * net-smtp 0.3.3
+ * rbs 2.8.2
+ * typeprof 0.21.3
+ * debug 1.7.1
See GitHub releases like [GitHub Releases of Logger](https://github.com/ruby/logger/releases) or changelog for details of the default gems or bundled gems.
## Supported platforms
+* WebAssembly/WASI is added. See [wasm/README.md] and [ruby.wasm] for more details. [[Feature #18462]]
+
## Compatibility issues
-* Error messages and backtrace displays have been changed.
- * Use a single quote instead of a backtick as a opening quote. [[Feature #16495]]
- * Display a class name before a method name (only when the class has a permanent name). [[Feature #19117]]
- * `Kernel#caller`, `Thread::Backtrace::Location`'s methods, etc. are also changed accordingly.
- ```
- Old:
- test.rb:1:in `foo': undefined method `time' for an instance of Integer
- from test.rb:2:in `<main>'
+* `String#to_c` currently treat a sequence of underscores as an end of Complex
+ string. [[Bug #19087]]
+
+* Now `ENV.clone` raises `TypeError` as well as `ENV.dup` [[Bug #17767]]
+
+### Removed constants
+
+The following deprecated constants are removed.
- New:
- test.rb:1:in 'Object#foo': undefined method 'time' for an instance of Integer
- from test.rb:2:in `<main>'
- ```
+* `Fixnum` and `Bignum` [[Feature #12005]]
+* `Random::DEFAULT` [[Feature #17351]]
+* `Struct::Group`
+* `Struct::Passwd`
+
+### Removed methods
+
+The following deprecated methods are removed.
+
+* `Dir.exists?` [[Feature #17391]]
+* `File.exists?` [[Feature #17391]]
+* `Kernel#=~` [[Feature #15231]]
+* `Kernel#taint`, `Kernel#untaint`, `Kernel#tainted?`
+ [[Feature #16131]]
+* `Kernel#trust`, `Kernel#untrust`, `Kernel#untrusted?`
+ [[Feature #16131]]
+* `Method#public?`, `Method#private?`, `Method#protected?`,
+ `UnboundMethod#public?`, `UnboundMethod#private?`, `UnboundMethod#protected?`
+ [[Bug #18729]] [[Bug #18751]] [[Bug #18435]]
+
+### Source code incompatibility of extension libraries
+
+* Extension libraries provide PRNG, subclasses of Random, need updates.
+ See [PRNG update] below for more information. [[Bug #19100]]
+
+### Error printer
+
+* Ruby no longer escapes control characters and backslashes in an
+ error message. [[Feature #18367]]
+
+### Constant lookup when defining a class/module
+
+* When defining a class/module directly under the Object class by class/module
+ statement, if there is already a class/module defined by `Module#include`
+ with the same name, the statement was handled as "open class" in Ruby 3.1 or before.
+ Since Ruby 3.2, a new class is defined instead. [[Feature #18832]]
## Stdlib compatibility issues
+* Psych no longer bundles libyaml sources.
+ And also Fiddle no longer bundles libffi sources.
+ Users need to install the libyaml/libffi library themselves via the package
+ manager like apt, yum, brew, etc.
+
+ Psych and fiddle supported the static build with specific version of libyaml
+ and libffi sources. You can build psych with libyaml-0.2.5 like this.
+
+ ```bash
+ $ ./configure --with-libyaml-source-dir=/path/to/libyaml-0.2.5
+ ```
+
+ And you can build fiddle with libffi-3.4.4 like this.
+
+ ```bash
+ $ ./configure --with-libffi-source-dir=/path/to/libffi-3.4.4
+ ```
+
+ [[Feature #18571]]
+
+* Check cookie name/path/domain characters in `CGI::Cookie`. [[CVE-2021-33621]]
+
+* `URI.parse` return empty string in host instead of nil. [[sec-156615]]
+
## C API updates
-* `rb_newobj` and `rb_newobj_of` (and corresponding macros `RB_NEWOBJ`, `RB_NEWOBJ_OF`, `NEWOBJ`, `NEWOBJ_OF`) have been removed. [[Feature #20265]]
-* Removed deprecated function `rb_gc_force_recycle`. [[Feature #18290]]
+### Updated C APIs
+
+The following APIs are updated.
+
+* PRNG update
+
+ `rb_random_interface_t` in ruby/random.h updated and versioned.
+ Extension libraries which use this interface and built for older
+ versions need to rebuild with adding `init_int32` function.
+
+### Added C APIs
+
+* `VALUE rb_hash_new_capa(long capa)` was added to created hashes with the desired capacity.
+* `rb_internal_thread_add_event_hook` and `rb_internal_thread_add_event_hook` were added to instrument threads scheduling.
+ The following events are available:
+ * `RUBY_INTERNAL_THREAD_EVENT_STARTED`
+ * `RUBY_INTERNAL_THREAD_EVENT_READY`
+ * `RUBY_INTERNAL_THREAD_EVENT_RESUMED`
+ * `RUBY_INTERNAL_THREAD_EVENT_SUSPENDED`
+ * `RUBY_INTERNAL_THREAD_EVENT_EXITED`
+* `rb_debug_inspector_current_depth` and `rb_debug_inspector_frame_depth` are added for debuggers.
+
+### Removed C APIs
+
+The following deprecated APIs are removed.
+
+* `rb_cData` variable.
+* "taintedness" and "trustedness" functions. [[Feature #16131]]
## Implementation improvements
-* `Array#each` is rewritten in Ruby for better performance [[Feature #20182]].
+* Fixed several race conditions in Kernel#autoload. [[Bug #18782]]
+* Cache invalidation for expressions referencing constants is now
+ more fine-grained. `RubyVM.stat(:global_constant_state)` was
+ removed because it was closely tied to the previous caching scheme
+ where setting any constant invalidates all caches in the system.
+ New keys, `:constant_cache_invalidations` and `:constant_cache_misses`,
+ were introduced to help with use cases for `:global_constant_state`.
+ [[Feature #18589]]
+* The cache-based optimization for Regexp matching is introduced.
+ [[Feature #19104]]
+* [Variable Width Allocation](https://shopify.engineering/ruby-variable-width-allocation)
+ is now enabled by default. [[Feature #18239]]
+* Added a new instance variable caching mechanism, called object shapes, which
+ improves inline cache hits for most objects and allows us to generate very
+ efficient JIT code. Objects whose instance variables are defined in a
+ consistent order will see the most performance benefits.
+ [[Feature #18776]]
+* Speed up marking instruction sequences by using a bitmap to find "markable"
+ objects. This change results in faster major collections.
+ [[Feature #18875]]
## JIT
-## Miscellaneous changes
-
-* Passing a block to a method which doesn't use the passed block will show
- a warning on verbose mode (`-w`).
- [[Feature #15554]]
-
-* Redefining some core methods that are specially optimized by the interpreter
- and JIT like `String.freeze` or `Integer#+` now emits a performance class
- warning (`-W:performance` or `Warning[:performance] = true`).
- [[Feature #20429]]
-
-[Feature #13557]: https://bugs.ruby-lang.org/issues/13557
-[Feature #15554]: https://bugs.ruby-lang.org/issues/15554
-[Feature #16495]: https://bugs.ruby-lang.org/issues/16495
-[Feature #18290]: https://bugs.ruby-lang.org/issues/18290
-[Feature #18368]: https://bugs.ruby-lang.org/issues/18368
-[Feature #18980]: https://bugs.ruby-lang.org/issues/18980
-[Misc #18984]: https://bugs.ruby-lang.org/issues/18984
-[Feature #19117]: https://bugs.ruby-lang.org/issues/19117
-[Bug #19918]: https://bugs.ruby-lang.org/issues/19918
-[Bug #20064]: https://bugs.ruby-lang.org/issues/20064
-[Feature #20182]: https://bugs.ruby-lang.org/issues/20182
-[Feature #20205]: https://bugs.ruby-lang.org/issues/20205
-[Bug #20218]: https://bugs.ruby-lang.org/issues/20218
-[Feature #20265]: https://bugs.ruby-lang.org/issues/20265
-[Feature #20429]: https://bugs.ruby-lang.org/issues/20429
-[Feature #20443]: https://bugs.ruby-lang.org/issues/20443
-[Feature #20497]: https://bugs.ruby-lang.org/issues/20497
-[Feature #20624]: https://bugs.ruby-lang.org/issues/20624
+### YJIT
+
+* YJIT is no longer experimental
+ * Has been tested on production workloads for over a year and proven to be quite stable.
+* YJIT now supports both x86-64 and arm64/aarch64 CPUs on Linux, MacOS, BSD and other UNIX platforms.
+ * This release brings support for Mac M1/M2, AWS Graviton and Raspberry Pi 4.
+* Building YJIT now requires Rust 1.58.0+. [[Feature #18481]]
+ * In order to ensure that CRuby is built with YJIT, please install `rustc` >= 1.58.0
+ before running `./configure`
+ * Please reach out to the YJIT team should you run into any issues.
+* Physical memory for JIT code is lazily allocated. Unlike Ruby 3.1,
+ the RSS of a Ruby process is minimized because virtual memory pages
+ allocated by `--yjit-exec-mem-size` will not be mapped to physical
+ memory pages until actually utilized by JIT code.
+* Introduce Code GC that frees all code pages when the memory consumption
+ by JIT code reaches `--yjit-exec-mem-size`.
+ * `RubyVM::YJIT.runtime_stats` returns Code GC metrics in addition to
+ existing `inline_code_size` and `outlined_code_size` keys:
+ `code_gc_count`, `live_page_count`, `freed_page_count`, and `freed_code_size`.
+* Most of the statistics produced by `RubyVM::YJIT.runtime_stats` are now available in release builds.
+ * Simply run ruby with `--yjit-stats` to compute and dump stats (incurs some run-time overhead).
+* YJIT is now optimized to take advantage of object shapes. [[Feature #18776]]
+* Take advantage of finer-grained constant invalidation to invalidate less code when defining new constants. [[Feature #18589]]
+* The default `--yjit-exec-mem-size` is changed to 64 (MiB).
+* The default `--yjit-call-threshold` is changed to 30.
+
+### MJIT
+
+* The MJIT compiler is re-implemented in Ruby as `ruby_vm/mjit/compiler`.
+* MJIT compiler is executed under a forked Ruby process instead of
+ doing it in a native thread called MJIT worker. [[Feature #18968]]
+ * As a result, Microsoft Visual Studio (MSWIN) is no longer supported.
+* MinGW is no longer supported. [[Feature #18824]]
+* Rename `--mjit-min-calls` to `--mjit-call-threshold`.
+* Change default `--mjit-max-cache` back from 10000 to 100.
+
+[Feature #12005]: https://bugs.ruby-lang.org/issues/12005
+[Feature #12084]: https://bugs.ruby-lang.org/issues/12084
+[Feature #12655]: https://bugs.ruby-lang.org/issues/12655
+[Feature #12737]: https://bugs.ruby-lang.org/issues/12737
+[Feature #13110]: https://bugs.ruby-lang.org/issues/13110
+[Feature #14332]: https://bugs.ruby-lang.org/issues/14332
+[Feature #15231]: https://bugs.ruby-lang.org/issues/15231
+[Feature #15357]: https://bugs.ruby-lang.org/issues/15357
+[Bug #15928]: https://bugs.ruby-lang.org/issues/15928
+[Feature #16122]: https://bugs.ruby-lang.org/issues/16122
+[Feature #16131]: https://bugs.ruby-lang.org/issues/16131
+[Bug #16466]: https://bugs.ruby-lang.org/issues/16466
+[Feature #16663]: https://bugs.ruby-lang.org/issues/16663
+[Feature #16806]: https://bugs.ruby-lang.org/issues/16806
+[Bug #16889]: https://bugs.ruby-lang.org/issues/16889
+[Bug #16908]: https://bugs.ruby-lang.org/issues/16908
+[Feature #16989]: https://bugs.ruby-lang.org/issues/16989
+[Feature #17351]: https://bugs.ruby-lang.org/issues/17351
+[Feature #17391]: https://bugs.ruby-lang.org/issues/17391
+[Bug #17545]: https://bugs.ruby-lang.org/issues/17545
+[Bug #17767]: https://bugs.ruby-lang.org/issues/17767
+[Feature #17837]: https://bugs.ruby-lang.org/issues/17837
+[Feature #17881]: https://bugs.ruby-lang.org/issues/17881
+[Feature #18033]: https://bugs.ruby-lang.org/issues/18033
+[Feature #18159]: https://bugs.ruby-lang.org/issues/18159
+[Feature #18239]: https://bugs.ruby-lang.org/issues/18239#note-17
+[Feature #18351]: https://bugs.ruby-lang.org/issues/18351
+[Feature #18367]: https://bugs.ruby-lang.org/issues/18367
+[Bug #18435]: https://bugs.ruby-lang.org/issues/18435
+[Feature #18462]: https://bugs.ruby-lang.org/issues/18462
+[Feature #18481]: https://bugs.ruby-lang.org/issues/18481
+[Bug #18487]: https://bugs.ruby-lang.org/issues/18487
+[Feature #18564]: https://bugs.ruby-lang.org/issues/18564
+[Feature #18571]: https://bugs.ruby-lang.org/issues/18571
+[Feature #18585]: https://bugs.ruby-lang.org/issues/18585
+[Feature #18589]: https://bugs.ruby-lang.org/issues/18589
+[Feature #18595]: https://bugs.ruby-lang.org/issues/18595
+[Feature #18598]: https://bugs.ruby-lang.org/issues/18598
+[Bug #18625]: https://bugs.ruby-lang.org/issues/18625
+[Feature #18630]: https://bugs.ruby-lang.org/issues/18630
+[Bug #18633]: https://bugs.ruby-lang.org/issues/18633
+[Feature #18639]: https://bugs.ruby-lang.org/issues/18639
+[Feature #18685]: https://bugs.ruby-lang.org/issues/18685
+[Bug #18729]: https://bugs.ruby-lang.org/issues/18729
+[Bug #18751]: https://bugs.ruby-lang.org/issues/18751
+[Feature #18774]: https://bugs.ruby-lang.org/issues/18774
+[Feature #18776]: https://bugs.ruby-lang.org/issues/18776
+[Bug #18782]: https://bugs.ruby-lang.org/issues/18782
+[Feature #18788]: https://bugs.ruby-lang.org/issues/18788
+[Feature #18798]: https://bugs.ruby-lang.org/issues/18798
+[Feature #18809]: https://bugs.ruby-lang.org/issues/18809
+[Feature #18821]: https://bugs.ruby-lang.org/issues/18821
+[Feature #18822]: https://bugs.ruby-lang.org/issues/18822
+[Feature #18824]: https://bugs.ruby-lang.org/issues/18824
+[Feature #18832]: https://bugs.ruby-lang.org/issues/18832
+[Feature #18875]: https://bugs.ruby-lang.org/issues/18875
+[Feature #18925]: https://bugs.ruby-lang.org/issues/18925
+[Feature #18944]: https://bugs.ruby-lang.org/issues/18944
+[Feature #18949]: https://bugs.ruby-lang.org/issues/18949
+[Feature #18968]: https://bugs.ruby-lang.org/issues/18968
+[Feature #19008]: https://bugs.ruby-lang.org/issues/19008
+[Feature #19013]: https://bugs.ruby-lang.org/issues/19013
+[Feature #19026]: https://bugs.ruby-lang.org/issues/19026
+[Feature #19036]: https://bugs.ruby-lang.org/issues/19036
+[Feature #19060]: https://bugs.ruby-lang.org/issues/19060
+[Feature #19070]: https://bugs.ruby-lang.org/issues/19070
+[Feature #19071]: https://bugs.ruby-lang.org/issues/19071
+[Feature #19078]: https://bugs.ruby-lang.org/issues/19078
+[Bug #19087]: https://bugs.ruby-lang.org/issues/19087
+[Bug #19100]: https://bugs.ruby-lang.org/issues/19100
+[Feature #19104]: https://bugs.ruby-lang.org/issues/19104
+[Feature #19135]: https://bugs.ruby-lang.org/issues/19135
+[Feature #19138]: https://bugs.ruby-lang.org/issues/19138
+[Feature #19194]: https://bugs.ruby-lang.org/issues/19194
+[Molinillo]: https://github.com/CocoaPods/Molinillo
+[PubGrub]: https://github.com/jhawthorn/pub_grub
+[GH-net-protocol-14]: https://github.com/ruby/net-protocol/pull/14
+[GH-pathname-20]: https://github.com/ruby/pathname/pull/20
+[GH-6791]: https://github.com/ruby/ruby/pull/6791
+[GH-6868]: https://github.com/ruby/ruby/pull/6868
+[GH-rubygems-4475]: https://github.com/rubygems/rubygems/pull/4475
+[GH-rubygems-6149]: https://github.com/rubygems/rubygems/pull/6149
+[GH-rubygems-6167]: https://github.com/rubygems/rubygems/pull/6167
+[sec-156615]: https://hackerone.com/reports/156615
+[CVE-2021-33621]: https://www.ruby-lang.org/en/news/2022/11/22/http-response-splitting-in-cgi-cve-2021-33621/
+[wasm/README.md]: https://github.com/ruby/ruby/blob/master/wasm/README.md
+[ruby.wasm]: https://github.com/ruby/ruby.wasm
diff --git a/README.ja.md b/README.ja.md
index 49cf72b5fd..93c0131690 100644
--- a/README.ja.md
+++ b/README.ja.md
@@ -1,5 +1,5 @@
[![Actions Status: MinGW](https://github.com/ruby/ruby/workflows/MinGW/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"MinGW")
-[![Actions Status: RJIT](https://github.com/ruby/ruby/workflows/RJIT/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"RJIT")
+[![Actions Status: MJIT](https://github.com/ruby/ruby/workflows/MJIT/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"MJIT")
[![Actions Status: Ubuntu](https://github.com/ruby/ruby/workflows/Ubuntu/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Ubuntu")
[![Actions Status: Windows](https://github.com/ruby/ruby/workflows/Windows/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Windows")
[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0sy8rrxut4o0k960/branch/master?svg=true)](https://ci.appveyor.com/project/ruby/ruby/branch/master)
@@ -25,7 +25,7 @@ Rubyã¯ãƒ†ã‚­ã‚¹ãƒˆå‡¦ç†é–¢ä¿‚ã®èƒ½åŠ›ãªã©ã«å„ªã‚Œï¼ŒPerlã¨åŒã˜ãらã„
* ダイナミックローディング (アーキテクãƒãƒ£ã«ã‚ˆã‚‹)
* ç§»æ¤æ€§ãŒé«˜ã„.多ãã®Unix-like/POSIX互æ›ãƒ—ラットフォーム上ã§å‹•ãã ã‘ã§ãªã,Windows, macOS,
Haikuãªã©ã®ä¸Šã§ã‚‚å‹•ã cf.
- https://docs.ruby-lang.org/en/master/maintainers_md.html#label-Platform+Maintainers
+ https://github.com/ruby/ruby/blob/master/doc/contributing.rdoc#platform-maintainers
## 入手法
@@ -49,6 +49,17 @@ https://www.ruby-lang.org/ja/downloads/
Rubyリãƒã‚¸ãƒˆãƒªã®æœ¬æ¥ã®master㯠https://git.ruby-lang.org/ruby.git ã«ã‚りã¾ã™ï¼Ž
コミッタã¯ã“ã¡ã‚‰ã‚’使ã„ã¾ã™ï¼Ž
+### Subversion
+
+å¤ã„Rubyã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã¯æ¬¡ã®ã‚³ãƒžãƒ³ãƒ‰ã§ã‚‚å–å¾—ã§ãã¾ã™ï¼Ž
+
+ $ svn co https://svn.ruby-lang.org/repos/ruby/branches/ruby_2_6/ ruby
+
+ä»–ã®ãƒ–ランãƒã®ä¸€è¦§ã¯æ¬¡ã®ã‚³ãƒžãƒ³ãƒ‰ã§è¦‹ã‚‰ã‚Œã¾ã™ï¼Ž
+
+ $ svn ls https://svn.ruby-lang.org/repos/ruby/branches/
+
+
## ホームページ
Rubyã®ãƒ›ãƒ¼ãƒ ãƒšãƒ¼ã‚¸ã®URLã¯
@@ -59,20 +70,20 @@ https://www.ruby-lang.org/
## メーリングリスト
-Rubyã®ãƒ¡ãƒ¼ãƒªãƒ³ã‚°ãƒªã‚¹ãƒˆãŒã‚りã¾ã™ï¼Žå‚åŠ å¸Œæœ›ã®æ–¹ã¯ [ruby-list-request@ml.ruby-lang.org] ã¾ã§ä»¶åã«
+Rubyã®ãƒ¡ãƒ¼ãƒªãƒ³ã‚°ãƒªã‚¹ãƒˆãŒã‚りã¾ã™ï¼Žå‚åŠ å¸Œæœ›ã®æ–¹ã¯ [ruby-list-request@ruby-lang.org] ã¾ã§æœ¬æ–‡ã«
- join
+ subscribe
ã¨æ›¸ã„ã¦é€ã£ã¦ä¸‹ã•ã„.
Ruby開発者å‘ã‘メーリングリストもã‚りã¾ã™ï¼Žã“ã¡ã‚‰ã§ã¯rubyã®ãƒã‚°ï¼Œå°†æ¥ã®ä»•様拡張ãªã©å®Ÿè£…上ã®å•題ã«ã¤ã„ã¦è­°è«–ã•れã¦ã„ã¾ã™ï¼Ž
-å‚åŠ å¸Œæœ›ã®æ–¹ã¯ [ruby-dev-request@ml.ruby-lang.org] ã¾ã§ruby-listã¨åŒæ§˜ã®æ–¹æ³•ã§ãƒ¡ãƒ¼ãƒ«ã—ã¦ãã ã•ã„.
+å‚åŠ å¸Œæœ›ã®æ–¹ã¯ [ruby-dev-request@ruby-lang.org] ã¾ã§ruby-listã¨åŒæ§˜ã®æ–¹æ³•ã§ãƒ¡ãƒ¼ãƒ«ã—ã¦ãã ã•ã„.
Ruby拡張モジュールã«ã¤ã„ã¦è©±ã—åˆã†ruby-extãƒ¡ãƒ¼ãƒªãƒ³ã‚°ãƒªã‚¹ãƒˆã¨æ•°å­¦é–¢ä¿‚ã®è©±é¡Œã«ã¤ã„ã¦è©±ã—åˆã†ruby-mathメーリングリストã¨
英語ã§rubyã«ã¤ã„ã¦è©±ã—åˆã†ruby-talkメーリングリストもã‚りã¾ã™ï¼Žå‚加方法ã¯ã©ã‚Œã‚‚åŒã˜ã§ã™ï¼Ž
-[ruby-list-request@ml.ruby-lang.org]: mailto:ruby-list-request@ml.ruby-lang.org?subject=join
-[ruby-dev-request@ml.ruby-lang.org]: mailto:ruby-dev-request@ml.ruby-lang.org?subject=join
+[ruby-list-request@ruby-lang.org]: mailto:ruby-list-request@ruby-lang.org?subject=Join%20Ruby%20Mailing%20List&body=subscribe
+[ruby-dev-request@ruby-lang.org]: mailto:ruby-dev-request@ruby-lang.org?subject=Join%20Ruby%20Mailing%20List&body=subscribe
## コンパイル・インストール
@@ -151,7 +162,7 @@ UNIXã§ã‚れ㰠`configure` ãŒã»ã¨ã‚“ã©ã®å·®ç•°ã‚’å¸åŽã—ã¦ãれるã¯
## é…布æ¡ä»¶
-[COPYING.ja](https://docs.ruby-lang.org/en/master/COPYING_ja.html) ファイルをå‚ç…§ã—ã¦ãã ã•ã„.
+[COPYING.ja](COPYING.ja) ファイルをå‚ç…§ã—ã¦ãã ã•ã„.
## フィードãƒãƒƒã‚¯
diff --git a/README.md b/README.md
index eb24a73ee3..c445448c71 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,8 @@
[![Actions Status: MinGW](https://github.com/ruby/ruby/workflows/MinGW/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"MinGW")
-[![Actions Status: RJIT](https://github.com/ruby/ruby/workflows/RJIT/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"RJIT")
+[![Actions Status: MJIT](https://github.com/ruby/ruby/workflows/MJIT/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"MJIT")
[![Actions Status: Ubuntu](https://github.com/ruby/ruby/workflows/Ubuntu/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Ubuntu")
[![Actions Status: Windows](https://github.com/ruby/ruby/workflows/Windows/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Windows")
+[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0sy8rrxut4o0k960/branch/master?svg=true)](https://ci.appveyor.com/project/ruby/ruby/branch/master)
[![Travis Status](https://app.travis-ci.com/ruby/ruby.svg?branch=master)](https://app.travis-ci.com/ruby/ruby)
# What is Ruby?
@@ -23,20 +24,15 @@ It is simple, straightforward, and extensible.
* Dynamic Loading of Object Files (on some architectures)
* Highly Portable (works on many Unix-like/POSIX compatible platforms as
well as Windows, macOS, etc.) cf.
- https://docs.ruby-lang.org/en/master/maintainers_md.html#label-Platform+Maintainers
+ https://github.com/ruby/ruby/blob/master/doc/maintainers.rdoc#label-Platform+Maintainers
-## How to get Ruby
+## How to get Ruby with Git
For a complete list of ways to install Ruby, including using third-party tools
like rvm, see:
https://www.ruby-lang.org/en/downloads/
-You can download release packages and the snapshot of the repository. If you want to
-download whole versions of Ruby, please visit https://www.ruby-lang.org/en/downloads/releases/.
-
-### Download with Git
-
The mirror of the Ruby source tree can be checked out with the following command:
$ git clone https://github.com/ruby/ruby.git
@@ -51,7 +47,7 @@ if you are a committer.
## How to build
-See [Building Ruby](https://docs.ruby-lang.org/en/master/contributing/building_ruby_md.html)
+see [Building Ruby](doc/contributing/building_ruby.md)
## Ruby home page
@@ -67,11 +63,11 @@ https://www.ruby-lang.org/
There is a mailing list to discuss Ruby. To subscribe to this list, please
send the following phrase:
- join
+ subscribe
-in the mail subject (not body) to the address [ruby-talk-request@ml.ruby-lang.org].
+in the mail body (not subject) to the address [ruby-talk-request@ruby-lang.org].
-[ruby-talk-request@ml.ruby-lang.org]: mailto:ruby-talk-request@ml.ruby-lang.org?subject=join
+[ruby-talk-request@ruby-lang.org]: mailto:ruby-talk-request@ruby-lang.org?subject=Join%20Ruby%20Mailing%20List&body=subscribe
## Copying
diff --git a/addr2line.c b/addr2line.c
index 02a3e617a6..e5f25293e2 100644
--- a/addr2line.c
+++ b/addr2line.c
@@ -8,14 +8,10 @@
**********************************************************************/
-#if defined(__clang__) && defined(__has_warning)
-#if __has_warning("-Wgnu-empty-initializer")
+#if defined(__clang__)
#pragma clang diagnostic ignored "-Wgnu-empty-initializer"
-#endif
-#if __has_warning("-Wgcc-compat")
#pragma clang diagnostic ignored "-Wgcc-compat"
#endif
-#endif
#include "ruby/internal/config.h"
#include "ruby/defines.h"
@@ -61,21 +57,8 @@ void *alloca();
# endif
# endif /* AIX */
# endif /* HAVE_ALLOCA_H */
-# ifndef UNREACHABLE
-# define UNREACHABLE __builtin_unreachable()
-# endif
-# ifndef UNREACHABLE_RETURN
-# define UNREACHABLE_RETURN(_) __builtin_unreachable()
-# endif
#endif /* __GNUC__ */
-#ifndef UNREACHABLE
-# define UNREACHABLE abort()
-#endif
-#ifndef UNREACHABLE_RETURN
-# define UNREACHABLE_RETURN(_) return (abort(), (_))
-#endif
-
#ifdef HAVE_DLADDR
# include <dlfcn.h>
#endif
@@ -144,7 +127,7 @@ void *alloca();
#define DW_LNE_define_file 0x03
#define DW_LNE_set_discriminator 0x04 /* DWARF4 */
-#define kprintf(...) fprintf(errout, "" __VA_ARGS__)
+PRINTF_ARGS(static int kprintf(const char *fmt, ...), 1, 2);
typedef struct line_info {
const char *dirname;
@@ -201,7 +184,7 @@ obj_dwarf_section_at(obj_info_t *obj, int n)
&obj->debug_line_str
};
if (n < 0 || DWARF_SECTION_COUNT <= n) {
- UNREACHABLE_RETURN(0);
+ abort();
}
return ary[n];
}
@@ -254,7 +237,7 @@ sleb128(const char **p)
}
static const char *
-get_nth_dirname(unsigned long dir, const char *p, FILE *errout)
+get_nth_dirname(unsigned long dir, const char *p)
{
if (!dir--) {
return "";
@@ -271,14 +254,10 @@ get_nth_dirname(unsigned long dir, const char *p, FILE *errout)
return p;
}
-static const char *parse_ver5_debug_line_header(
- const char *p, int idx, uint8_t format,
- obj_info_t *obj, const char **out_path,
- uint64_t *out_directory_index, FILE *errout);
+static const char *parse_ver5_debug_line_header(const char *p, int idx, uint8_t format, obj_info_t *obj, const char **out_path, uint64_t *out_directory_index);
static void
-fill_filename(int file, uint8_t format, uint16_t version, const char *include_directories,
- const char *filenames, line_info_t *line, obj_info_t *obj, FILE *errout)
+fill_filename(int file, uint8_t format, uint16_t version, const char *include_directories, const char *filenames, line_info_t *line, obj_info_t *obj)
{
int i;
const char *p = filenames;
@@ -287,9 +266,9 @@ fill_filename(int file, uint8_t format, uint16_t version, const char *include_di
if (version >= 5) {
const char *path;
uint64_t directory_index = -1;
- parse_ver5_debug_line_header(filenames, file, format, obj, &path, &directory_index, errout);
+ parse_ver5_debug_line_header(filenames, file, format, obj, &path, &directory_index);
line->filename = path;
- parse_ver5_debug_line_header(include_directories, (int)directory_index, format, obj, &path, NULL, errout);
+ parse_ver5_debug_line_header(include_directories, (int)directory_index, format, obj, &path, NULL);
line->dirname = path;
}
else {
@@ -311,7 +290,7 @@ fill_filename(int file, uint8_t format, uint16_t version, const char *include_di
if (i == file) {
line->filename = filename;
- line->dirname = get_nth_dirname(dir, include_directories, errout);
+ line->dirname = get_nth_dirname(dir, include_directories);
}
}
}
@@ -320,7 +299,7 @@ fill_filename(int file, uint8_t format, uint16_t version, const char *include_di
static void
fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line,
uint8_t format, uint16_t version, const char *include_directories, const char *filenames,
- obj_info_t *obj, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t *obj, line_info_t *lines, int offset)
{
int i;
addr += obj->base_addr - obj->vmaddr;
@@ -329,7 +308,7 @@ fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line,
/* We assume one line code doesn't result >100 bytes of native code.
We may want more reliable way eventually... */
if (addr < a && a < addr + 100) {
- fill_filename(file, format, version, include_directories, filenames, &lines[i], obj, errout);
+ fill_filename(file, format, version, include_directories, filenames, &lines[i], obj);
lines[i].line = line;
}
}
@@ -354,7 +333,7 @@ struct LineNumberProgramHeader {
};
static int
-parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgramHeader *header, FILE *errout)
+parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgramHeader *header)
{
const char *p = *pp;
header->unit_length = *(uint32_t *)p;
@@ -400,7 +379,7 @@ parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgr
if (header->version >= 5) {
header->include_directories = p;
- p = parse_ver5_debug_line_header(p, -1, header->format, obj, NULL, NULL, errout);
+ p = parse_ver5_debug_line_header(p, -1, header->format, obj, NULL, NULL);
header->filenames = p;
}
else {
@@ -427,7 +406,7 @@ parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgr
static int
parse_debug_line_cu(int num_traces, void **traces, const char **debug_line,
- obj_info_t *obj, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t *obj, line_info_t *lines, int offset)
{
const char *p = (const char *)*debug_line;
struct LineNumberProgramHeader header;
@@ -444,7 +423,7 @@ parse_debug_line_cu(int num_traces, void **traces, const char **debug_line,
/* int epilogue_begin = 0; */
/* unsigned int isa = 0; */
- if (parse_debug_line_header(obj, &p, &header, errout))
+ if (parse_debug_line_header(obj, &p, &header))
return -1;
is_stmt = header.default_is_stmt;
@@ -455,7 +434,7 @@ parse_debug_line_cu(int num_traces, void **traces, const char **debug_line,
header.version, \
header.include_directories, \
header.filenames, \
- obj, lines, offset, errout); \
+ obj, lines, offset); \
/*basic_block = prologue_end = epilogue_begin = 0;*/ \
} while (0)
@@ -555,11 +534,11 @@ parse_debug_line_cu(int num_traces, void **traces, const char **debug_line,
static int
parse_debug_line(int num_traces, void **traces,
const char *debug_line, unsigned long size,
- obj_info_t *obj, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t *obj, line_info_t *lines, int offset)
{
const char *debug_line_end = debug_line + size;
while (debug_line < debug_line_end) {
- if (parse_debug_line_cu(num_traces, traces, &debug_line, obj, lines, offset, errout))
+ if (parse_debug_line_cu(num_traces, traces, &debug_line, obj, lines, offset))
return -1;
}
if (debug_line != debug_line_end) {
@@ -572,7 +551,7 @@ parse_debug_line(int num_traces, void **traces,
/* read file and fill lines */
static uintptr_t
fill_lines(int num_traces, void **traces, int check_debuglink,
- obj_info_t **objp, line_info_t *lines, int offset, FILE *errout);
+ obj_info_t **objp, line_info_t *lines, int offset);
static void
append_obj(obj_info_t **objp)
@@ -600,7 +579,7 @@ append_obj(obj_info_t **objp)
// check the path pattern of "/usr/lib/debug/usr/bin/ruby.debug"
static void
follow_debuglink(const char *debuglink, int num_traces, void **traces,
- obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t **objp, line_info_t *lines, int offset)
{
static const char global_debug_dir[] = "/usr/lib/debug";
const size_t global_debug_dir_len = sizeof(global_debug_dir) - 1;
@@ -626,13 +605,13 @@ follow_debuglink(const char *debuglink, int num_traces, void **traces,
o2 = *objp;
o2->base_addr = o1->base_addr;
o2->path = o1->path;
- fill_lines(num_traces, traces, 0, objp, lines, offset, errout);
+ fill_lines(num_traces, traces, 0, objp, lines, offset);
}
// check the path pattern of "/usr/lib/debug/.build-id/ab/cdef1234.debug"
static void
follow_debuglink_build_id(const char *build_id, size_t build_id_size, int num_traces, void **traces,
- obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t **objp, line_info_t *lines, int offset)
{
static const char global_debug_dir[] = "/usr/lib/debug/.build-id/";
const size_t global_debug_dir_len = sizeof(global_debug_dir) - 1;
@@ -657,7 +636,7 @@ follow_debuglink_build_id(const char *build_id, size_t build_id_size, int num_tr
o2 = *objp;
o2->base_addr = o1->base_addr;
o2->path = o1->path;
- fill_lines(num_traces, traces, 0, objp, lines, offset, errout);
+ fill_lines(num_traces, traces, 0, objp, lines, offset);
}
#endif
@@ -861,11 +840,7 @@ enum
DW_FORM_addrx1 = 0x29,
DW_FORM_addrx2 = 0x2a,
DW_FORM_addrx3 = 0x2b,
- DW_FORM_addrx4 = 0x2c,
-
- /* GNU extensions for referring to .gnu_debugaltlink dwz-compressed info */
- DW_FORM_GNU_ref_alt = 0x1f20,
- DW_FORM_GNU_strp_alt = 0x1f21
+ DW_FORM_addrx4 = 0x2c
};
/* Range list entry encodings */
@@ -1083,13 +1058,13 @@ di_read_debug_abbrev_cu(DebugInfoReader *reader)
}
static int
-di_read_debug_line_cu(DebugInfoReader *reader, FILE *errout)
+di_read_debug_line_cu(DebugInfoReader *reader)
{
const char *p;
struct LineNumberProgramHeader header;
p = (const char *)reader->debug_line_cu_end;
- if (parse_debug_line_header(reader->obj, &p, &header, errout))
+ if (parse_debug_line_header(reader->obj, &p, &header))
return -1;
reader->debug_line_cu_end = (char *)header.cu_end;
@@ -1169,32 +1144,25 @@ resolve_strx(DebugInfoReader *reader, uint64_t idx)
return reader->obj->debug_str.ptr + off;
}
-static bool
-debug_info_reader_read_addr_value_member(DebugInfoReader *reader, DebugInfoValue *v, int size)
+static void
+debug_info_reader_read_addr_value(DebugInfoReader *reader, DebugInfoValue *v)
{
- if (size == 4) {
+ if (reader->address_size == 4) {
set_uint_value(v, read_uint32(&reader->p));
- } else if (size == 8) {
+ } else if (reader->address_size == 8) {
set_uint_value(v, read_uint64(&reader->p));
} else {
- return false;
+ fprintf(stderr,"unknown address_size:%d", reader->address_size);
+ abort();
}
- return true;
}
-#define debug_info_reader_read_addr_value(reader, v, mem) \
- if (!debug_info_reader_read_addr_value_member((reader), (v), (reader)->mem)) { \
- kprintf("unknown " #mem ":%d", (reader)->mem); \
- return false; \
- }
-
-
-static bool
-debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoValue *v, FILE *errout)
+static void
+debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoValue *v)
{
switch (form) {
case DW_FORM_addr:
- debug_info_reader_read_addr_value(reader, v, address_size);
+ debug_info_reader_read_addr_value(reader, v);
break;
case DW_FORM_block2:
v->size = read_uint16(&reader->p);
@@ -1249,9 +1217,16 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
if (reader->current_version <= 2) {
// DWARF Version 2 specifies that references have
// the same size as an address on the target system
- debug_info_reader_read_addr_value(reader, v, address_size);
+ debug_info_reader_read_addr_value(reader, v);
} else {
- debug_info_reader_read_addr_value(reader, v, format);
+ if (reader->format == 4) {
+ set_uint_value(v, read_uint32(&reader->p));
+ } else if (reader->format == 8) {
+ set_uint_value(v, read_uint64(&reader->p));
+ } else {
+ fprintf(stderr,"unknown format:%d", reader->format);
+ abort();
+ }
}
break;
case DW_FORM_ref1:
@@ -1352,28 +1327,20 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
case DW_FORM_addrx4:
set_addr_idx_value(v, read_uint32(&reader->p));
break;
- /* we have no support for actually reading the real values of these refs out
- * of the .gnu_debugaltlink dwz-compressed debuginfo at the moment, but "read"
- * them anyway so that we advance the reader by the right amount. */
- case DW_FORM_GNU_ref_alt:
- case DW_FORM_GNU_strp_alt:
- read_uint(reader);
- set_uint_value(v, 0);
- break;
case 0:
goto fail;
break;
}
- return true;
+ return;
fail:
- kprintf("%d: unsupported form: %#"PRIx64"\n", __LINE__, form);
- return false;
+ fprintf(stderr, "%d: unsupported form: %#"PRIx64"\n", __LINE__, form);
+ exit(1);
}
/* find abbrev in current compilation unit */
static const char *
-di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number, FILE *errout)
+di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number)
{
const char *p;
if (abbrev_number < ABBREV_TABLE_SIZE) {
@@ -1386,8 +1353,8 @@ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number, FILE *errout)
di_skip_die_attributes(&p);
for (uint64_t n = uleb128(&p); abbrev_number != n; n = uleb128(&p)) {
if (n == 0) {
- kprintf("%d: Abbrev Number %"PRId64" not found\n",__LINE__, abbrev_number);
- return NULL;
+ fprintf(stderr,"%d: Abbrev Number %"PRId64" not found\n",__LINE__, abbrev_number);
+ exit(1);
}
uleb128(&p); /* tag */
p++; /* has_children */
@@ -1398,52 +1365,52 @@ di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number, FILE *errout)
#if 0
static void
-hexdump0(const unsigned char *p, size_t n, FILE *errout)
+hexdump0(const unsigned char *p, size_t n)
{
size_t i;
- kprintf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
+ fprintf(stderr, " 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
for (i=0; i < n; i++){
switch (i & 15) {
case 0:
- kprintf("%02" PRIdSIZE ": %02X ", i/16, p[i]);
+ fprintf(stderr, "%02" PRIdSIZE ": %02X ", i/16, p[i]);
break;
case 15:
- kprintf("%02X\n", p[i]);
+ fprintf(stderr, "%02X\n", p[i]);
break;
default:
- kprintf("%02X ", p[i]);
+ fprintf(stderr, "%02X ", p[i]);
break;
}
}
if ((i & 15) != 15) {
- kprintf("\n");
+ fprintf(stderr, "\n");
}
}
-#define hexdump(p,n,e) hexdump0((const unsigned char *)p, n, e)
+#define hexdump(p,n) hexdump0((const unsigned char *)p, n)
static void
-div_inspect(DebugInfoValue *v, FILE *errout)
+div_inspect(DebugInfoValue *v)
{
switch (v->type) {
case VAL_uint:
- kprintf("%d: type:%d size:%" PRIxSIZE " v:%"PRIx64"\n",__LINE__,v->type,v->size,v->as.uint64);
+ fprintf(stderr,"%d: type:%d size:%" PRIxSIZE " v:%"PRIx64"\n",__LINE__,v->type,v->size,v->as.uint64);
break;
case VAL_int:
- kprintf("%d: type:%d size:%" PRIxSIZE " v:%"PRId64"\n",__LINE__,v->type,v->size,(int64_t)v->as.uint64);
+ fprintf(stderr,"%d: type:%d size:%" PRIxSIZE " v:%"PRId64"\n",__LINE__,v->type,v->size,(int64_t)v->as.uint64);
break;
case VAL_cstr:
- kprintf("%d: type:%d size:%" PRIxSIZE " v:'%s'\n",__LINE__,v->type,v->size,v->as.ptr);
+ fprintf(stderr,"%d: type:%d size:%" PRIxSIZE " v:'%s'\n",__LINE__,v->type,v->size,v->as.ptr);
break;
case VAL_data:
- kprintf("%d: type:%d size:%" PRIxSIZE " v:\n",__LINE__,v->type,v->size);
- hexdump(v->as.ptr, 16, errout);
+ fprintf(stderr,"%d: type:%d size:%" PRIxSIZE " v:\n",__LINE__,v->type,v->size);
+ hexdump(v->as.ptr, 16);
break;
}
}
#endif
static DIE *
-di_read_die(DebugInfoReader *reader, DIE *die, FILE *errout)
+di_read_die(DebugInfoReader *reader, DIE *die)
{
uint64_t abbrev_number = uleb128(&reader->p);
if (abbrev_number == 0) {
@@ -1451,7 +1418,7 @@ di_read_die(DebugInfoReader *reader, DIE *die, FILE *errout)
return NULL;
}
- if (!(reader->q = di_find_abbrev(reader, abbrev_number, errout))) return NULL;
+ reader->q = di_find_abbrev(reader, abbrev_number);
die->pos = reader->p - reader->obj->debug_info.ptr - 1;
die->tag = (int)uleb128(&reader->q); /* tag */
@@ -1463,26 +1430,26 @@ di_read_die(DebugInfoReader *reader, DIE *die, FILE *errout)
}
static DebugInfoValue *
-di_read_record(DebugInfoReader *reader, DebugInfoValue *vp, FILE *errout)
+di_read_record(DebugInfoReader *reader, DebugInfoValue *vp)
{
uint64_t at = uleb128(&reader->q);
uint64_t form = uleb128(&reader->q);
if (!at || !form) return NULL;
vp->at = at;
vp->form = form;
- if (!debug_info_reader_read_value(reader, form, vp, errout)) return NULL;
+ debug_info_reader_read_value(reader, form, vp);
return vp;
}
-static bool
-di_skip_records(DebugInfoReader *reader, FILE *errout)
+static void
+di_skip_records(DebugInfoReader *reader)
{
for (;;) {
- DebugInfoValue v = {{0}};
+ DebugInfoValue v = {{}};
uint64_t at = uleb128(&reader->q);
uint64_t form = uleb128(&reader->q);
- if (!at || !form) return true;
- if (!debug_info_reader_read_value(reader, form, &v, errout)) return false;
+ if (!at || !form) return;
+ debug_info_reader_read_value(reader, form, &v);
}
}
@@ -1494,14 +1461,13 @@ typedef struct addr_header {
/* uint8_t segment_selector_size; */
} addr_header_t;
-static bool
-addr_header_init(obj_info_t *obj, addr_header_t *header, FILE *errout)
-{
+static void
+addr_header_init(obj_info_t *obj, addr_header_t *header) {
const char *p = obj->debug_addr.ptr;
header->ptr = p;
- if (!p) return true;
+ if (!p) return;
header->unit_length = *(uint32_t *)p;
p += sizeof(uint32_t);
@@ -1515,12 +1481,7 @@ addr_header_init(obj_info_t *obj, addr_header_t *header, FILE *errout)
p += 2; /* version */
header->address_size = *p++;
- if (header->address_size != 4 && header->address_size != 8) {
- kprintf("unknown address_size:%d", header->address_size);
- return false;
- }
p++; /* segment_selector_size */
- return true;
}
static uint64_t
@@ -1540,12 +1501,11 @@ typedef struct rnglists_header {
uint32_t offset_entry_count;
} rnglists_header_t;
-static bool
-rnglists_header_init(obj_info_t *obj, rnglists_header_t *header, FILE *errout)
-{
+static void
+rnglists_header_init(obj_info_t *obj, rnglists_header_t *header) {
const char *p = obj->debug_rnglists.ptr;
- if (!p) return true;
+ if (!p) return;
header->unit_length = *(uint32_t *)p;
p += sizeof(uint32_t);
@@ -1559,13 +1519,8 @@ rnglists_header_init(obj_info_t *obj, rnglists_header_t *header, FILE *errout)
p += 2; /* version */
header->address_size = *p++;
- if (header->address_size != 4 && header->address_size != 8) {
- kprintf("unknown address_size:%d", header->address_size);
- return false;
- }
p++; /* segment_selector_size */
header->offset_entry_count = *(uint32_t *)p;
- return true;
}
typedef struct {
@@ -1609,23 +1564,26 @@ ranges_set(ranges_t *ptr, DebugInfoValue *v, addr_header_t *addr_header, uint64_
}
static uint64_t
-read_dw_form_addr(DebugInfoReader *reader, const char **ptr, FILE *errout)
+read_dw_form_addr(DebugInfoReader *reader, const char **ptr)
{
const char *p = *ptr;
*ptr = p + reader->address_size;
if (reader->address_size == 4) {
return read_uint32(&p);
- } else {
+ } else if (reader->address_size == 8) {
return read_uint64(&p);
+ } else {
+ fprintf(stderr,"unknown address_size:%d", reader->address_size);
+ abort();
}
}
static uintptr_t
-ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_header_t *rnglists_header, FILE *errout)
+ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_header_t *rnglists_header)
{
if (ptr->high_pc_set) {
if (ptr->ranges_set || !ptr->low_pc_set) {
- return UINTPTR_MAX;
+ exit(1);
}
if (ptr->low_pc <= addr && addr <= ptr->high_pc) {
return (uintptr_t)ptr->low_pc;
@@ -1674,15 +1632,15 @@ ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_h
to = (uintptr_t)base + uleb128(&p);
break;
case DW_RLE_base_address:
- base = read_dw_form_addr(reader, &p, errout);
+ base = read_dw_form_addr(reader, &p);
base_valid = true;
break;
case DW_RLE_start_end:
- from = (uintptr_t)read_dw_form_addr(reader, &p, errout);
- to = (uintptr_t)read_dw_form_addr(reader, &p, errout);
+ from = (uintptr_t)read_dw_form_addr(reader, &p);
+ to = (uintptr_t)read_dw_form_addr(reader, &p);
break;
case DW_RLE_start_length:
- from = (uintptr_t)read_dw_form_addr(reader, &p, errout);
+ from = (uintptr_t)read_dw_form_addr(reader, &p);
to = from + uleb128(&p);
break;
}
@@ -1690,7 +1648,7 @@ ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_h
return from;
}
}
- return 0;
+ return false;
}
p = reader->obj->debug_ranges.ptr + ptr->ranges;
for (;;) {
@@ -1711,42 +1669,42 @@ ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_h
return (uintptr_t)ptr->low_pc;
}
}
- return 0;
+ return false;
}
#if 0
static void
-ranges_inspect(DebugInfoReader *reader, ranges_t *ptr, FILE *errout)
+ranges_inspect(DebugInfoReader *reader, ranges_t *ptr)
{
if (ptr->high_pc_set) {
if (ptr->ranges_set || !ptr->low_pc_set) {
- kprintf("low_pc_set:%d high_pc_set:%d ranges_set:%d\n",ptr->low_pc_set,ptr->high_pc_set,ptr->ranges_set);
- return;
+ fprintf(stderr,"low_pc_set:%d high_pc_set:%d ranges_set:%d\n",ptr->low_pc_set,ptr->high_pc_set,ptr->ranges_set);
+ exit(1);
}
- kprintf("low_pc:%"PRIx64" high_pc:%"PRIx64"\n",ptr->low_pc,ptr->high_pc);
+ fprintf(stderr,"low_pc:%"PRIx64" high_pc:%"PRIx64"\n",ptr->low_pc,ptr->high_pc);
}
else if (ptr->ranges_set) {
char *p = reader->obj->debug_ranges.ptr + ptr->ranges;
- kprintf("low_pc:%"PRIx64" ranges:%"PRIx64" %lx ",ptr->low_pc,ptr->ranges, p-reader->obj->mapped);
+ fprintf(stderr,"low_pc:%"PRIx64" ranges:%"PRIx64" %lx ",ptr->low_pc,ptr->ranges, p-reader->obj->mapped);
for (;;) {
uintptr_t from = read_uintptr(&p);
uintptr_t to = read_uintptr(&p);
if (!from && !to) break;
- kprintf("%"PRIx64"-%"PRIx64" ",ptr->low_pc+from,ptr->low_pc+to);
+ fprintf(stderr,"%"PRIx64"-%"PRIx64" ",ptr->low_pc+from,ptr->low_pc+to);
}
- kprintf("\n");
+ fprintf(stderr,"\n");
}
else if (ptr->low_pc_set) {
- kprintf("low_pc:%"PRIx64"\n",ptr->low_pc);
+ fprintf(stderr,"low_pc:%"PRIx64"\n",ptr->low_pc);
}
else {
- kprintf("empty\n");
+ fprintf(stderr,"empty\n");
}
}
#endif
static int
-di_read_cu(DebugInfoReader *reader, FILE *errout)
+di_read_cu(DebugInfoReader *reader)
{
uint64_t unit_length;
uint16_t version;
@@ -1773,23 +1731,23 @@ di_read_cu(DebugInfoReader *reader, FILE *errout)
debug_abbrev_offset = read_uint(reader);
reader->address_size = read_uint8(&reader->p);
}
- if (reader->address_size != 4 && reader->address_size != 8) {
- kprintf("unknown address_size:%d", reader->address_size);
- return -1;
- }
reader->q0 = reader->obj->debug_abbrev.ptr + debug_abbrev_offset;
reader->level = 0;
di_read_debug_abbrev_cu(reader);
- if (di_read_debug_line_cu(reader, errout)) return -1;
+ if (di_read_debug_line_cu(reader)) return -1;
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER_BUILD_DATE)
+ /* Though DWARF specifies "the applicable base address defaults to the base
+ address of the compilation unit", but GCC seems to use zero as default */
+#else
do {
DIE die;
- if (!di_read_die(reader, &die, errout)) continue;
+ if (!di_read_die(reader, &die)) continue;
if (die.tag != DW_TAG_compile_unit) {
- if (!di_skip_records(reader, errout)) return -1;
+ di_skip_records(reader);
break;
}
@@ -1797,11 +1755,11 @@ di_read_cu(DebugInfoReader *reader, FILE *errout)
reader->current_addr_base = 0;
reader->current_rnglists_base = 0;
- DebugInfoValue low_pc = {{0}};
+ DebugInfoValue low_pc = {{}};
/* enumerate abbrev */
for (;;) {
- DebugInfoValue v = {{0}};
- if (!di_read_record(reader, &v, errout)) break;
+ DebugInfoValue v = {{}};
+ if (!di_read_record(reader, &v)) break;
switch (v.at) {
case DW_AT_low_pc:
// clang may output DW_AT_addr_base after DW_AT_low_pc.
@@ -1826,19 +1784,19 @@ di_read_cu(DebugInfoReader *reader, FILE *errout)
break;
case VAL_addr:
{
- addr_header_t header = {0};
- if (!addr_header_init(reader->obj, &header, errout)) return -1;
+ addr_header_t header;
+ addr_header_init(reader->obj, &header);
reader->current_low_pc = read_addr(&header, reader->current_addr_base, low_pc.as.addr_idx);
}
break;
}
} while (0);
-
+#endif
return 0;
}
static void
-read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_origin, line_info_t *line, FILE *errout)
+read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_origin, line_info_t *line)
{
const char *p = reader->p;
const char *q = reader->q;
@@ -1863,12 +1821,12 @@ read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_o
default:
goto finish;
}
- if (!di_read_die(reader, &die, errout)) goto finish;
+ if (!di_read_die(reader, &die)) goto finish;
/* enumerate abbrev */
for (;;) {
- DebugInfoValue v = {{0}};
- if (!di_read_record(reader, &v, errout)) break;
+ DebugInfoValue v = {{}};
+ if (!di_read_record(reader, &v)) break;
switch (v.at) {
case DW_AT_name:
line->sname = get_cstr_value(&v);
@@ -1882,44 +1840,43 @@ read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_o
reader->level = level;
}
-static bool
+static void
debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
- line_info_t *lines, int offset, FILE *errout)
-{
+ line_info_t *lines, int offset) {
- addr_header_t addr_header = {0};
- if (!addr_header_init(reader->obj, &addr_header, errout)) return false;
+ addr_header_t addr_header = {};
+ addr_header_init(reader->obj, &addr_header);
- rnglists_header_t rnglists_header = {0};
- if (!rnglists_header_init(reader->obj, &rnglists_header, errout)) return false;
+ rnglists_header_t rnglists_header = {};
+ rnglists_header_init(reader->obj, &rnglists_header);
while (reader->p < reader->cu_end) {
DIE die;
- ranges_t ranges = {0};
- line_info_t line = {0};
+ ranges_t ranges = {};
+ line_info_t line = {};
- if (!di_read_die(reader, &die, errout)) continue;
- /* kprintf("%d:%tx: <%d>\n",__LINE__,die.pos,reader->level,die.tag); */
+ if (!di_read_die(reader, &die)) continue;
+ /* fprintf(stderr,"%d:%tx: <%d>\n",__LINE__,die.pos,reader->level,die.tag); */
if (die.tag != DW_TAG_subprogram && die.tag != DW_TAG_inlined_subroutine) {
skip_die:
- if (!di_skip_records(reader, errout)) return false;
+ di_skip_records(reader);
continue;
}
/* enumerate abbrev */
for (;;) {
- DebugInfoValue v = {{0}};
+ DebugInfoValue v = {{}};
/* ptrdiff_t pos = reader->p - reader->p0; */
- if (!di_read_record(reader, &v, errout)) break;
- /* kprintf("\n%d:%tx: AT:%lx FORM:%lx\n",__LINE__,pos,v.at,v.form); */
- /* div_inspect(&v, errout); */
+ if (!di_read_record(reader, &v)) break;
+ /* fprintf(stderr,"\n%d:%tx: AT:%lx FORM:%lx\n",__LINE__,pos,v.at,v.form); */
+ /* div_inspect(&v); */
switch (v.at) {
case DW_AT_name:
line.sname = get_cstr_value(&v);
break;
case DW_AT_call_file:
- fill_filename((int)v.as.uint64, reader->debug_line_format, reader->debug_line_version, reader->debug_line_directories, reader->debug_line_files, &line, reader->obj, errout);
+ fill_filename((int)v.as.uint64, reader->debug_line_format, reader->debug_line_version, reader->debug_line_directories, reader->debug_line_files, &line, reader->obj);
break;
case DW_AT_call_line:
line.line = (int)v.as.uint64;
@@ -1935,19 +1892,18 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
/* 1 or 3 */
break; /* goto skip_die; */
case DW_AT_abstract_origin:
- read_abstract_origin(reader, v.form, v.as.uint64, &line, errout);
+ read_abstract_origin(reader, v.form, v.as.uint64, &line);
break; /* goto skip_die; */
}
}
- /* ranges_inspect(reader, &ranges, errout); */
- /* kprintf("%d:%tx: %x ",__LINE__,diepos,die.tag); */
+ /* ranges_inspect(reader, &ranges); */
+ /* fprintf(stderr,"%d:%tx: %x ",__LINE__,diepos,die.tag); */
for (int i=offset; i < num_traces; i++) {
uintptr_t addr = (uintptr_t)traces[i];
uintptr_t offset = addr - reader->obj->base_addr + reader->obj->vmaddr;
- uintptr_t saddr = ranges_include(reader, &ranges, offset, &rnglists_header, errout);
- if (saddr == UINTPTR_MAX) return false;
+ uintptr_t saddr = ranges_include(reader, &ranges, offset, &rnglists_header);
if (saddr) {
- /* kprintf("%d:%tx: %d %lx->%lx %x %s: %s/%s %d %s %s %s\n",__LINE__,die.pos, i,addr,offset, die.tag,line.sname,line.dirname,line.filename,line.line,reader->obj->path,line.sname,lines[i].sname); */
+ /* fprintf(stdout, "%d:%tx: %d %lx->%lx %x %s: %s/%s %d %s %s %s\n",__LINE__,die.pos, i,addr,offset, die.tag,line.sname,line.dirname,line.filename,line.line,reader->obj->path,line.sname,lines[i].sname); */
if (lines[i].sname) {
line_info_t *lp = malloc(sizeof(line_info_t));
memcpy(lp, &lines[i], sizeof(line_info_t));
@@ -1964,7 +1920,6 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
}
}
}
- return true;
}
// This function parses the following attributes of Line Number Program Header in DWARF 5:
@@ -1983,10 +1938,7 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
//
// It records DW_LNCT_path and DW_LNCT_directory_index at the index "idx".
static const char *
-parse_ver5_debug_line_header(const char *p, int idx, uint8_t format,
- obj_info_t *obj, const char **out_path,
- uint64_t *out_directory_index, FILE *errout)
-{
+parse_ver5_debug_line_header(const char *p, int idx, uint8_t format, obj_info_t *obj, const char **out_path, uint64_t *out_directory_index) {
int i, j;
int entry_format_count = *(uint8_t *)p++;
const char *entry_format = p;
@@ -1996,17 +1948,17 @@ parse_ver5_debug_line_header(const char *p, int idx, uint8_t format,
int entry_count = (int)uleb128(&p);
- DebugInfoReader reader = {0};
+ DebugInfoReader reader;
debug_info_reader_init(&reader, obj);
reader.format = format;
reader.p = p;
for (j = 0; j < entry_count; j++) {
const char *format = entry_format;
for (i = 0; i < entry_format_count; i++) {
- DebugInfoValue v = {{0}};
+ DebugInfoValue v = {{}};
unsigned long dw_lnct = uleb128(&format);
unsigned long dw_form = uleb128(&format);
- if (!debug_info_reader_read_value(&reader, dw_form, &v, errout)) return 0;
+ debug_info_reader_read_value(&reader, dw_form, &v);
if (dw_lnct == 1 /* DW_LNCT_path */ && v.type == VAL_cstr && out_path)
*out_path = v.as.ptr + v.off;
if (dw_lnct == 2 /* DW_LNCT_directory_index */ && v.type == VAL_uint && out_directory_index)
@@ -2051,7 +2003,7 @@ fail:
/* read file and fill lines */
static uintptr_t
fill_lines(int num_traces, void **traces, int check_debuglink,
- obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t **objp, line_info_t *lines, int offset)
{
int i, j;
char *shstr;
@@ -2211,10 +2163,9 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
debug_info_reader_init(&reader, obj);
i = 0;
while (reader.p < reader.pend) {
- /* kprintf("%d:%tx: CU[%d]\n", __LINE__, reader.p - reader.obj->debug_info.ptr, i++); */
- if (di_read_cu(&reader, errout)) goto use_symtab;
- if (!debug_info_read(&reader, num_traces, traces, lines, offset, errout))
- goto use_symtab;
+ /* fprintf(stderr, "%d:%tx: CU[%d]\n", __LINE__, reader.p - reader.obj->debug_info.ptr, i++); */
+ if (di_read_cu(&reader)) goto use_symtab;
+ debug_info_read(&reader, num_traces, traces, lines, offset);
}
}
else {
@@ -2254,14 +2205,14 @@ use_symtab:
if (gnu_debuglink_shdr && check_debuglink) {
follow_debuglink(file + gnu_debuglink_shdr->sh_offset,
num_traces, traces,
- objp, lines, offset, errout);
+ objp, lines, offset);
}
if (note_gnu_build_id && check_debuglink) {
ElfW(Nhdr) *nhdr = (ElfW(Nhdr)*) (file + note_gnu_build_id->sh_offset);
const char *build_id = (char *)(nhdr + 1) + nhdr->n_namesz;
follow_debuglink_build_id(build_id, nhdr->n_descsz,
num_traces, traces,
- objp, lines, offset, errout);
+ objp, lines, offset);
}
goto finish;
}
@@ -2269,7 +2220,7 @@ use_symtab:
if (parse_debug_line(num_traces, traces,
obj->debug_line.ptr,
obj->debug_line.size,
- obj, lines, offset, errout) == -1)
+ obj, lines, offset) == -1)
goto fail;
finish:
@@ -2281,7 +2232,7 @@ fail:
/* read file and fill lines */
static uintptr_t
fill_lines(int num_traces, void **traces, int check_debuglink,
- obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
+ obj_info_t **objp, line_info_t *lines, int offset)
{
# ifdef __LP64__
# define LP(x) x##_64
@@ -2360,13 +2311,13 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
struct fat_header *fat = (struct fat_header *)file;
char *q = file + sizeof(*fat);
uint32_t nfat_arch = __builtin_bswap32(fat->nfat_arch);
- /* kprintf("%d: fat:%s %d\n",__LINE__, binary_filename,nfat_arch); */
+ /* fprintf(stderr,"%d: fat:%s %d\n",__LINE__, binary_filename,nfat_arch); */
for (uint32_t i = 0; i < nfat_arch; i++) {
struct fat_arch *arch = (struct fat_arch *)q;
cpu_type_t cputype = __builtin_bswap32(arch->cputype);
cpu_subtype_t cpusubtype = __builtin_bswap32(arch->cpusubtype);
uint32_t offset = __builtin_bswap32(arch->offset);
- /* kprintf("%d: fat %d %x/%x %x/%x\n",__LINE__, i, mhp->cputype,mhp->cpusubtype, cputype,cpusubtype); */
+ /* fprintf(stderr,"%d: fat %d %x/%x %x/%x\n",__LINE__, i, mhp->cputype,mhp->cpusubtype, cputype,cpusubtype); */
if (mhp->cputype == cputype &&
(cpu_subtype_t)(mhp->cpusubtype & ~CPU_SUBTYPE_MASK) == cpusubtype) {
p = file + offset;
@@ -2384,14 +2335,13 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
goto fail;
}
else {
+ kprintf("'%s' is not a "
# ifdef __LP64__
-# define bitsize "64"
+ "64"
# else
-# define bitsize "32"
+ "32"
# endif
- kprintf("'%s' is not a " bitsize
"-bit Mach-O file!\n",binary_filename);
-# undef bitsize
close(fd);
goto fail;
}
@@ -2483,16 +2433,15 @@ found_mach_header:
DebugInfoReader reader;
debug_info_reader_init(&reader, obj);
while (reader.p < reader.pend) {
- if (di_read_cu(&reader, errout)) goto fail;
- if (!debug_info_read(&reader, num_traces, traces, lines, offset, errout))
- goto fail;
+ if (di_read_cu(&reader)) goto fail;
+ debug_info_read(&reader, num_traces, traces, lines, offset);
}
}
if (parse_debug_line(num_traces, traces,
obj->debug_line.ptr,
obj->debug_line.size,
- obj, lines, offset, errout) == -1)
+ obj, lines, offset) == -1)
goto fail;
return dladdr_fbase;
@@ -2505,7 +2454,7 @@ fail:
#if defined(__FreeBSD__) || defined(__DragonFly__)
# include <sys/sysctl.h>
#endif
-/* ssize_t main_exe_path(FILE *errout)
+/* ssize_t main_exe_path(void)
*
* store the path of the main executable to `binary_filename`,
* and returns strlen(binary_filename).
@@ -2513,7 +2462,7 @@ fail:
*/
#if defined(__linux__) || defined(__NetBSD__)
static ssize_t
-main_exe_path(FILE *errout)
+main_exe_path(void)
{
# if defined(__linux__)
# define PROC_SELF_EXE "/proc/self/exe"
@@ -2527,7 +2476,7 @@ main_exe_path(FILE *errout)
}
#elif defined(__FreeBSD__) || defined(__DragonFly__)
static ssize_t
-main_exe_path(FILE *errout)
+main_exe_path(void)
{
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
size_t len = PATH_MAX;
@@ -2541,7 +2490,7 @@ main_exe_path(FILE *errout)
}
#elif defined(HAVE_LIBPROC_H)
static ssize_t
-main_exe_path(FILE *errout)
+main_exe_path(void)
{
int len = proc_pidpath(getpid(), binary_filename, PATH_MAX);
if (len == 0) return 0;
@@ -2553,7 +2502,7 @@ main_exe_path(FILE *errout)
#endif
static void
-print_line0(line_info_t *line, void *address, FILE *errout)
+print_line0(line_info_t *line, void *address)
{
uintptr_t addr = (uintptr_t)address;
uintptr_t d = addr - line->saddr;
@@ -2594,16 +2543,16 @@ print_line0(line_info_t *line, void *address, FILE *errout)
}
static void
-print_line(line_info_t *line, void *address, FILE *errout)
+print_line(line_info_t *line, void *address)
{
- print_line0(line, address, errout);
+ print_line0(line, address);
if (line->next) {
- print_line(line->next, NULL, errout);
+ print_line(line->next, NULL);
}
}
void
-rb_dump_backtrace_with_lines(int num_traces, void **traces, FILE *errout)
+rb_dump_backtrace_with_lines(int num_traces, void **traces)
{
int i;
/* async-signal unsafe */
@@ -2615,14 +2564,14 @@ rb_dump_backtrace_with_lines(int num_traces, void **traces, FILE *errout)
#ifdef HAVE_MAIN_EXE_PATH
char *main_path = NULL; /* used on printing backtrace */
ssize_t len;
- if ((len = main_exe_path(errout)) > 0) {
+ if ((len = main_exe_path()) > 0) {
main_path = (char *)alloca(len + 1);
if (main_path) {
uintptr_t addr;
memcpy(main_path, binary_filename, len+1);
append_obj(&obj);
obj->path = main_path;
- addr = fill_lines(num_traces, traces, 1, &obj, lines, -1, errout);
+ addr = fill_lines(num_traces, traces, 1, &obj, lines, -1);
if (addr != (uintptr_t)-1) {
dladdr_fbases[0] = (void *)addr;
}
@@ -2659,7 +2608,7 @@ rb_dump_backtrace_with_lines(int num_traces, void **traces, FILE *errout)
lines[i].saddr = (uintptr_t)info.dli_saddr;
}
strlcpy(binary_filename, path, PATH_MAX);
- if (fill_lines(num_traces, traces, 1, &obj, lines, i, errout) == (uintptr_t)-1)
+ if (fill_lines(num_traces, traces, 1, &obj, lines, i) == (uintptr_t)-1)
break;
}
next_line:
@@ -2668,7 +2617,7 @@ next_line:
/* output */
for (i = 0; i < num_traces; i++) {
- print_line(&lines[i], traces[i], errout);
+ print_line(&lines[i], traces[i]);
/* FreeBSD's backtrace may show _start and so on */
if (lines[i].sname && strcmp("main", lines[i].sname) == 0)
@@ -2702,8 +2651,435 @@ next_line:
free(dladdr_fbases);
}
-#undef kprintf
+/* From FreeBSD's lib/libstand/printf.c */
+/*-
+ * Copyright (c) 1986, 1988, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
+ */
+
+#include <stdarg.h>
+#define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1)
+static inline int toupper(int c) { return ('A' <= c && c <= 'Z') ? (c&0x5f) : c; }
+#define hex2ascii(hex) (hex2ascii_data[hex])
+static const char hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+static inline int imax(int a, int b) { return (a > b ? a : b); }
+static int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap);
+
+static void putce(int c)
+{
+ char s[1];
+ ssize_t ret;
+
+ s[0] = (char)c;
+ ret = write(2, s, 1);
+ (void)ret;
+}
+
+static int
+kprintf(const char *fmt, ...)
+{
+ va_list ap;
+ int retval;
+ va_start(ap, fmt);
+ retval = kvprintf(fmt, putce, NULL, 10, ap);
+ va_end(ap);
+ return retval;
+}
+
+/*
+ * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
+ * order; return an optional length and a pointer to the last character
+ * written in the buffer (i.e., the first character of the string).
+ * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
+ */
+static char *
+ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
+{
+ char *p, c;
+
+ p = nbuf;
+ *p = '\0';
+ do {
+ c = hex2ascii(num % base);
+ *++p = upper ? toupper(c) : c;
+ } while (num /= base);
+ if (lenp)
+ *lenp = (int)(p - nbuf);
+ return (p);
+}
+
+/*
+ * Scaled down version of printf(3).
+ *
+ * Two additional formats:
+ *
+ * The format %b is supported to decode error registers.
+ * Its usage is:
+ *
+ * printf("reg=%b\n", regval, "<base><arg>*");
+ *
+ * where <base> is the output base expressed as a control character, e.g.
+ * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
+ * the first of which gives the bit number to be inspected (origin 1), and
+ * the next characters (up to a control character, i.e. a character <= 32),
+ * give the name of the register. Thus:
+ *
+ * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
+ *
+ * would produce output:
+ *
+ * reg=3<BITTWO,BITONE>
+ *
+ * XXX: %D -- Hexdump, takes pointer and separator string:
+ * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
+ * ("%*D", len, ptr, " " -> XX XX XX XX ...
+ */
+static int
+kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap)
+{
+#define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; }
+ char nbuf[MAXNBUF];
+ char *d;
+ const char *p, *percent, *q;
+ unsigned char *up;
+ int ch, n;
+ uintmax_t num;
+ int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
+ int cflag, hflag, jflag, tflag, zflag;
+ int dwidth, upper;
+ char padc;
+ int stop = 0, retval = 0;
+
+ num = 0;
+ if (!func)
+ d = (char *) arg;
+ else
+ d = NULL;
+
+ if (fmt == NULL)
+ fmt = "(fmt null)\n";
+
+ if (radix < 2 || radix > 36)
+ radix = 10;
+
+ for (;;) {
+ padc = ' ';
+ width = 0;
+ while ((ch = (unsigned char)*fmt++) != '%' || stop) {
+ if (ch == '\0')
+ return (retval);
+ PCHAR(ch);
+ }
+ percent = fmt - 1;
+ qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
+ sign = 0; dot = 0; dwidth = 0; upper = 0;
+ cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
+reswitch: switch (ch = (unsigned char)*fmt++) {
+ case '.':
+ dot = 1;
+ goto reswitch;
+ case '#':
+ sharpflag = 1;
+ goto reswitch;
+ case '+':
+ sign = 1;
+ goto reswitch;
+ case '-':
+ ladjust = 1;
+ goto reswitch;
+ case '%':
+ PCHAR(ch);
+ break;
+ case '*':
+ if (!dot) {
+ width = va_arg(ap, int);
+ if (width < 0) {
+ ladjust = !ladjust;
+ width = -width;
+ }
+ } else {
+ dwidth = va_arg(ap, int);
+ }
+ goto reswitch;
+ case '0':
+ if (!dot) {
+ padc = '0';
+ goto reswitch;
+ }
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ for (n = 0;; ++fmt) {
+ n = n * 10 + ch - '0';
+ ch = *fmt;
+ if (ch < '0' || ch > '9')
+ break;
+ }
+ if (dot)
+ dwidth = n;
+ else
+ width = n;
+ goto reswitch;
+ case 'b':
+ num = (unsigned int)va_arg(ap, int);
+ p = va_arg(ap, char *);
+ for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
+ PCHAR(*q--);
+
+ if (num == 0)
+ break;
+
+ for (tmp = 0; *p;) {
+ n = *p++;
+ if (num & (1 << (n - 1))) {
+ PCHAR(tmp ? ',' : '<');
+ for (; (n = *p) > ' '; ++p)
+ PCHAR(n);
+ tmp = 1;
+ } else
+ for (; *p > ' '; ++p)
+ continue;
+ }
+ if (tmp)
+ PCHAR('>');
+ break;
+ case 'c':
+ PCHAR(va_arg(ap, int));
+ break;
+ case 'D':
+ up = va_arg(ap, unsigned char *);
+ p = va_arg(ap, char *);
+ if (!width)
+ width = 16;
+ while(width--) {
+ PCHAR(hex2ascii(*up >> 4));
+ PCHAR(hex2ascii(*up & 0x0f));
+ up++;
+ if (width)
+ for (q=p;*q;q++)
+ PCHAR(*q);
+ }
+ break;
+ case 'd':
+ case 'i':
+ base = 10;
+ sign = 1;
+ goto handle_sign;
+ case 'h':
+ if (hflag) {
+ hflag = 0;
+ cflag = 1;
+ } else
+ hflag = 1;
+ goto reswitch;
+ case 'j':
+ jflag = 1;
+ goto reswitch;
+ case 'l':
+ if (lflag) {
+ lflag = 0;
+ qflag = 1;
+ } else
+ lflag = 1;
+ goto reswitch;
+ case 'n':
+ if (jflag)
+ *(va_arg(ap, intmax_t *)) = retval;
+ else if (qflag)
+ *(va_arg(ap, int64_t *)) = retval;
+ else if (lflag)
+ *(va_arg(ap, long *)) = retval;
+ else if (zflag)
+ *(va_arg(ap, size_t *)) = retval;
+ else if (hflag)
+ *(va_arg(ap, short *)) = retval;
+ else if (cflag)
+ *(va_arg(ap, char *)) = retval;
+ else
+ *(va_arg(ap, int *)) = retval;
+ break;
+ case 'o':
+ base = 8;
+ goto handle_nosign;
+ case 'p':
+ base = 16;
+ sharpflag = (width == 0);
+ sign = 0;
+ num = (uintptr_t)va_arg(ap, void *);
+ goto number;
+ case 'q':
+ qflag = 1;
+ goto reswitch;
+ case 'r':
+ base = radix;
+ if (sign)
+ goto handle_sign;
+ goto handle_nosign;
+ case 's':
+ p = va_arg(ap, char *);
+ if (p == NULL)
+ p = "(null)";
+ if (!dot)
+ n = (int)strlen (p);
+ else
+ for (n = 0; n < dwidth && p[n]; n++)
+ continue;
+
+ width -= n;
+
+ if (!ladjust && width > 0)
+ while (width--)
+ PCHAR(padc);
+ while (n--)
+ PCHAR(*p++);
+ if (ladjust && width > 0)
+ while (width--)
+ PCHAR(padc);
+ break;
+ case 't':
+ tflag = 1;
+ goto reswitch;
+ case 'u':
+ base = 10;
+ goto handle_nosign;
+ case 'X':
+ upper = 1;
+ case 'x':
+ base = 16;
+ goto handle_nosign;
+ case 'y':
+ base = 16;
+ sign = 1;
+ goto handle_sign;
+ case 'z':
+ zflag = 1;
+ goto reswitch;
+handle_nosign:
+ sign = 0;
+ if (jflag)
+ num = va_arg(ap, uintmax_t);
+ else if (qflag)
+ num = va_arg(ap, uint64_t);
+ else if (tflag)
+ num = va_arg(ap, ptrdiff_t);
+ else if (lflag)
+ num = va_arg(ap, unsigned long);
+ else if (zflag)
+ num = va_arg(ap, size_t);
+ else if (hflag)
+ num = (unsigned short)va_arg(ap, int);
+ else if (cflag)
+ num = (unsigned char)va_arg(ap, int);
+ else
+ num = va_arg(ap, unsigned int);
+ goto number;
+handle_sign:
+ if (jflag)
+ num = va_arg(ap, intmax_t);
+ else if (qflag)
+ num = va_arg(ap, int64_t);
+ else if (tflag)
+ num = va_arg(ap, ptrdiff_t);
+ else if (lflag)
+ num = va_arg(ap, long);
+ else if (zflag)
+ num = va_arg(ap, ssize_t);
+ else if (hflag)
+ num = (short)va_arg(ap, int);
+ else if (cflag)
+ num = (char)va_arg(ap, int);
+ else
+ num = va_arg(ap, int);
+number:
+ if (sign && (intmax_t)num < 0) {
+ neg = 1;
+ num = -(intmax_t)num;
+ }
+ p = ksprintn(nbuf, num, base, &n, upper);
+ tmp = 0;
+ if (sharpflag && num != 0) {
+ if (base == 8)
+ tmp++;
+ else if (base == 16)
+ tmp += 2;
+ }
+ if (neg)
+ tmp++;
+
+ if (!ladjust && padc == '0')
+ dwidth = width - tmp;
+ width -= tmp + imax(dwidth, n);
+ dwidth -= n;
+ if (!ladjust)
+ while (width-- > 0)
+ PCHAR(' ');
+ if (neg)
+ PCHAR('-');
+ if (sharpflag && num != 0) {
+ if (base == 8) {
+ PCHAR('0');
+ } else if (base == 16) {
+ PCHAR('0');
+ PCHAR('x');
+ }
+ }
+ while (dwidth-- > 0)
+ PCHAR('0');
+
+ while (*p)
+ PCHAR(*p--);
+
+ if (ladjust)
+ while (width-- > 0)
+ PCHAR(' ');
+
+ break;
+ default:
+ while (percent < fmt)
+ PCHAR(*percent++);
+ /*
+ * Since we ignore an formatting argument it is no
+ * longer safe to obey the remaining formatting
+ * arguments as the arguments will no longer match
+ * the format specs.
+ */
+ stop = 1;
+ break;
+ }
+ }
+#undef PCHAR
+}
#else /* defined(USE_ELF) */
#error not supported
#endif
diff --git a/addr2line.h b/addr2line.h
index ff8e476b92..f09b665800 100644
--- a/addr2line.h
+++ b/addr2line.h
@@ -12,10 +12,8 @@
#if (defined(USE_ELF) || defined(HAVE_MACH_O_LOADER_H))
-#include <stdio.h>
-
void
-rb_dump_backtrace_with_lines(int num_traces, void **traces, FILE *errout);
+rb_dump_backtrace_with_lines(int num_traces, void **traces);
#endif /* USE_ELF */
diff --git a/array.c b/array.c
index 8cfdbeb9c1..b76e9a64a3 100644
--- a/array.c
+++ b/array.c
@@ -28,7 +28,7 @@
#include "ruby/encoding.h"
#include "ruby/st.h"
#include "ruby/util.h"
-#include "vm_core.h"
+#include "transient_heap.h"
#include "builtin.h"
#if !ARRAY_DEBUG
@@ -38,7 +38,6 @@
#include "ruby_assert.h"
VALUE rb_cArray;
-VALUE rb_cArray_empty_frozen;
/* Flags of RArray
*
@@ -48,8 +47,13 @@ VALUE rb_cArray_empty_frozen;
* 2: RARRAY_SHARED_FLAG (equal to ELTS_SHARED)
* The array is shared. The buffer this array points to is owned by
* another array (the shared root).
+ * if USE_RVARGC
* 3-9: RARRAY_EMBED_LEN
* The length of the array when RARRAY_EMBED_FLAG is set.
+ * else
+ * 3-4: RARRAY_EMBED_LEN
+ * The length of the array when RARRAY_EMBED_FLAG is set.
+ * endif
* 12: RARRAY_SHARED_ROOT_FLAG
* The array is a shared root that does reference counting. The buffer
* this array points to is owned by this array but may be pointed to
@@ -59,6 +63,8 @@ VALUE rb_cArray_empty_frozen;
* they cannot be modified. Not updating the reference count
* improves copy-on-write performance. Their reference count is
* assumed to be infinity.
+ * 13: RARRAY_TRANSIENT_FLAG
+ * The buffer of the array is allocated on the transient heap.
* 14: RARRAY_PTR_IN_USE_FLAG
* The buffer of the array is in use. This is only used during
* debugging.
@@ -78,47 +84,48 @@ should_be_T_ARRAY(VALUE ary)
return RB_TYPE_P(ary, T_ARRAY);
}
-#define ARY_HEAP_PTR(a) (RUBY_ASSERT(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.ptr)
-#define ARY_HEAP_LEN(a) (RUBY_ASSERT(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.len)
-#define ARY_HEAP_CAPA(a) (RUBY_ASSERT(!ARY_EMBED_P(a)), RUBY_ASSERT(!ARY_SHARED_ROOT_P(a)), \
+#define ARY_HEAP_PTR(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.ptr)
+#define ARY_HEAP_LEN(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.len)
+#define ARY_HEAP_CAPA(a) (assert(!ARY_EMBED_P(a)), assert(!ARY_SHARED_ROOT_P(a)), \
RARRAY(a)->as.heap.aux.capa)
-#define ARY_EMBED_PTR(a) (RUBY_ASSERT(ARY_EMBED_P(a)), RARRAY(a)->as.ary)
+#define ARY_EMBED_PTR(a) (assert(ARY_EMBED_P(a)), RARRAY(a)->as.ary)
#define ARY_EMBED_LEN(a) \
- (RUBY_ASSERT(ARY_EMBED_P(a)), \
+ (assert(ARY_EMBED_P(a)), \
(long)((RBASIC(a)->flags >> RARRAY_EMBED_LEN_SHIFT) & \
(RARRAY_EMBED_LEN_MASK >> RARRAY_EMBED_LEN_SHIFT)))
-#define ARY_HEAP_SIZE(a) (RUBY_ASSERT(!ARY_EMBED_P(a)), RUBY_ASSERT(ARY_OWNS_HEAP_P(a)), ARY_CAPA(a) * sizeof(VALUE))
+#define ARY_HEAP_SIZE(a) (assert(!ARY_EMBED_P(a)), assert(ARY_OWNS_HEAP_P(a)), ARY_CAPA(a) * sizeof(VALUE))
-#define ARY_OWNS_HEAP_P(a) (RUBY_ASSERT(should_be_T_ARRAY((VALUE)(a))), \
+#define ARY_OWNS_HEAP_P(a) (assert(should_be_T_ARRAY((VALUE)(a))), \
!FL_TEST_RAW((a), RARRAY_SHARED_FLAG|RARRAY_EMBED_FLAG))
#define FL_SET_EMBED(a) do { \
- RUBY_ASSERT(!ARY_SHARED_P(a)); \
+ assert(!ARY_SHARED_P(a)); \
FL_SET((a), RARRAY_EMBED_FLAG); \
+ RARY_TRANSIENT_UNSET(a); \
ary_verify(a); \
} while (0)
#define FL_UNSET_EMBED(ary) FL_UNSET((ary), RARRAY_EMBED_FLAG|RARRAY_EMBED_LEN_MASK)
#define FL_SET_SHARED(ary) do { \
- RUBY_ASSERT(!ARY_EMBED_P(ary)); \
+ assert(!ARY_EMBED_P(ary)); \
FL_SET((ary), RARRAY_SHARED_FLAG); \
} while (0)
#define FL_UNSET_SHARED(ary) FL_UNSET((ary), RARRAY_SHARED_FLAG)
#define ARY_SET_PTR(ary, p) do { \
- RUBY_ASSERT(!ARY_EMBED_P(ary)); \
- RUBY_ASSERT(!OBJ_FROZEN(ary)); \
+ assert(!ARY_EMBED_P(ary)); \
+ assert(!OBJ_FROZEN(ary)); \
RARRAY(ary)->as.heap.ptr = (p); \
} while (0)
#define ARY_SET_EMBED_LEN(ary, n) do { \
long tmp_n = (n); \
- RUBY_ASSERT(ARY_EMBED_P(ary)); \
+ assert(ARY_EMBED_P(ary)); \
RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK; \
RBASIC(ary)->flags |= (tmp_n) << RARRAY_EMBED_LEN_SHIFT; \
} while (0)
#define ARY_SET_HEAP_LEN(ary, n) do { \
- RUBY_ASSERT(!ARY_EMBED_P(ary)); \
+ assert(!ARY_EMBED_P(ary)); \
RARRAY(ary)->as.heap.len = (n); \
} while (0)
#define ARY_SET_LEN(ary, n) do { \
@@ -128,15 +135,15 @@ should_be_T_ARRAY(VALUE ary)
else { \
ARY_SET_HEAP_LEN((ary), (n)); \
} \
- RUBY_ASSERT(RARRAY_LEN(ary) == (n)); \
+ assert(RARRAY_LEN(ary) == (n)); \
} while (0)
#define ARY_INCREASE_PTR(ary, n) do { \
- RUBY_ASSERT(!ARY_EMBED_P(ary)); \
- RUBY_ASSERT(!OBJ_FROZEN(ary)); \
+ assert(!ARY_EMBED_P(ary)); \
+ assert(!OBJ_FROZEN(ary)); \
RARRAY(ary)->as.heap.ptr += (n); \
} while (0)
#define ARY_INCREASE_LEN(ary, n) do { \
- RUBY_ASSERT(!OBJ_FROZEN(ary)); \
+ assert(!OBJ_FROZEN(ary)); \
if (ARY_EMBED_P(ary)) { \
ARY_SET_EMBED_LEN((ary), RARRAY_LEN(ary)+(n)); \
} \
@@ -148,30 +155,41 @@ should_be_T_ARRAY(VALUE ary)
#define ARY_CAPA(ary) (ARY_EMBED_P(ary) ? ary_embed_capa(ary) : \
ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : ARY_HEAP_CAPA(ary))
#define ARY_SET_CAPA(ary, n) do { \
- RUBY_ASSERT(!ARY_EMBED_P(ary)); \
- RUBY_ASSERT(!ARY_SHARED_P(ary)); \
- RUBY_ASSERT(!OBJ_FROZEN(ary)); \
+ assert(!ARY_EMBED_P(ary)); \
+ assert(!ARY_SHARED_P(ary)); \
+ assert(!OBJ_FROZEN(ary)); \
RARRAY(ary)->as.heap.aux.capa = (n); \
} while (0)
+#define ARY_SET_SHARED(ary, value) do { \
+ const VALUE _ary_ = (ary); \
+ const VALUE _value_ = (value); \
+ assert(!ARY_EMBED_P(_ary_)); \
+ assert(ARY_SHARED_P(_ary_)); \
+ assert(!OBJ_FROZEN(_ary_)); \
+ assert(ARY_SHARED_ROOT_P(_value_) || OBJ_FROZEN(_value_)); \
+ RB_OBJ_WRITE(_ary_, &RARRAY(_ary_)->as.heap.aux.shared_root, _value_); \
+} while (0)
+
#define ARY_SHARED_ROOT_OCCUPIED(ary) (!OBJ_FROZEN(ary) && ARY_SHARED_ROOT_REFCNT(ary) == 1)
#define ARY_SET_SHARED_ROOT_REFCNT(ary, value) do { \
- RUBY_ASSERT(ARY_SHARED_ROOT_P(ary)); \
- RUBY_ASSERT(!OBJ_FROZEN(ary)); \
- RUBY_ASSERT((value) >= 0); \
+ assert(ARY_SHARED_ROOT_P(ary)); \
+ assert(!OBJ_FROZEN(ary)); \
+ assert((value) >= 0); \
RARRAY(ary)->as.heap.aux.capa = (value); \
} while (0)
#define FL_SET_SHARED_ROOT(ary) do { \
- RUBY_ASSERT(!OBJ_FROZEN(ary)); \
- RUBY_ASSERT(!ARY_EMBED_P(ary)); \
+ assert(!OBJ_FROZEN(ary)); \
+ assert(!ARY_EMBED_P(ary)); \
+ assert(!RARRAY_TRANSIENT_P(ary)); \
FL_SET((ary), RARRAY_SHARED_ROOT_FLAG); \
} while (0)
static inline void
ARY_SET(VALUE a, long i, VALUE v)
{
- RUBY_ASSERT(!ARY_SHARED_P(a));
- RUBY_ASSERT(!OBJ_FROZEN(a));
+ assert(!ARY_SHARED_P(a));
+ assert(!OBJ_FROZEN(a));
RARRAY_ASET(a, i, v);
}
@@ -180,9 +198,13 @@ ARY_SET(VALUE a, long i, VALUE v)
static long
ary_embed_capa(VALUE ary)
{
+#if USE_RVARGC
size_t size = rb_gc_obj_slot_size(ary) - offsetof(struct RArray, as.ary);
- RUBY_ASSERT(size % sizeof(VALUE) == 0);
+ assert(size % sizeof(VALUE) == 0);
return size / sizeof(VALUE);
+#else
+ return RARRAY_EMBED_LEN_MAX;
+#endif
}
static size_t
@@ -194,7 +216,11 @@ ary_embed_size(long capa)
static bool
ary_embeddable_p(long capa)
{
+#if USE_RVARGC
return rb_gc_size_allocatable_p(ary_embed_size(capa));
+#else
+ return capa <= RARRAY_EMBED_LEN_MAX;
+#endif
}
bool
@@ -235,23 +261,25 @@ rb_ary_size_as_embedded(VALUE ary)
static VALUE
ary_verify_(VALUE ary, const char *file, int line)
{
- RUBY_ASSERT(RB_TYPE_P(ary, T_ARRAY));
+ assert(RB_TYPE_P(ary, T_ARRAY));
if (ARY_SHARED_P(ary)) {
VALUE root = ARY_SHARED_ROOT(ary);
const VALUE *ptr = ARY_HEAP_PTR(ary);
- const VALUE *root_ptr = RARRAY_CONST_PTR(root);
+ const VALUE *root_ptr = RARRAY_CONST_PTR_TRANSIENT(root);
long len = ARY_HEAP_LEN(ary), root_len = RARRAY_LEN(root);
- RUBY_ASSERT(ARY_SHARED_ROOT_P(root) || OBJ_FROZEN(root));
- RUBY_ASSERT(root_ptr <= ptr && ptr + len <= root_ptr + root_len);
+ assert(ARY_SHARED_ROOT_P(root) || OBJ_FROZEN(root));
+ assert(root_ptr <= ptr && ptr + len <= root_ptr + root_len);
ary_verify(root);
}
else if (ARY_EMBED_P(ary)) {
- RUBY_ASSERT(!ARY_SHARED_P(ary));
- RUBY_ASSERT(RARRAY_LEN(ary) <= ary_embed_capa(ary));
+ assert(!RARRAY_TRANSIENT_P(ary));
+ assert(!ARY_SHARED_P(ary));
+ assert(RARRAY_LEN(ary) <= ary_embed_capa(ary));
}
else {
- const VALUE *ptr = RARRAY_CONST_PTR(ary);
+#if 1
+ const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
long i, len = RARRAY_LEN(ary);
volatile VALUE v;
if (len > 1) len = 1; /* check only HEAD */
@@ -259,7 +287,16 @@ ary_verify_(VALUE ary, const char *file, int line)
v = ptr[i]; /* access check */
}
v = v;
+#endif
+ }
+
+#if USE_TRANSIENT_HEAP
+ if (RARRAY_TRANSIENT_P(ary)) {
+ assert(rb_transient_heap_managed_ptr_p(RARRAY_CONST_PTR_TRANSIENT(ary)));
}
+#endif
+
+ rb_transient_heap_verify();
return ary;
}
@@ -279,7 +316,7 @@ rb_ary_ptr_use_start(VALUE ary)
#if ARRAY_DEBUG
FL_SET_RAW(ary, RARRAY_PTR_IN_USE_FLAG);
#endif
- return (VALUE *)RARRAY_CONST_PTR(ary);
+ return (VALUE *)RARRAY_CONST_PTR_TRANSIENT(ary);
}
void
@@ -301,7 +338,7 @@ rb_mem_clear(VALUE *mem, long size)
static void
ary_mem_clear(VALUE ary, long beg, long size)
{
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
rb_mem_clear(ptr + beg, size);
});
}
@@ -317,7 +354,7 @@ memfill(register VALUE *mem, register long size, register VALUE val)
static void
ary_memfill(VALUE ary, long beg, long size, VALUE val)
{
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
memfill(ptr + beg, size, val);
RB_OBJ_WRITTEN(ary, Qundef, val);
});
@@ -326,17 +363,17 @@ ary_memfill(VALUE ary, long beg, long size, VALUE val)
static void
ary_memcpy0(VALUE ary, long beg, long argc, const VALUE *argv, VALUE buff_owner_ary)
{
- RUBY_ASSERT(!ARY_SHARED_P(buff_owner_ary));
+ assert(!ARY_SHARED_P(buff_owner_ary));
if (argc > (int)(128/sizeof(VALUE)) /* is magic number (cache line size) */) {
rb_gc_writebarrier_remember(buff_owner_ary);
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
MEMCPY(ptr+beg, argv, VALUE, argc);
});
}
else {
int i;
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
for (i=0; i<argc; i++) {
RB_OBJ_WRITE(buff_owner_ary, &ptr[i+beg], argv[i]);
}
@@ -351,62 +388,158 @@ ary_memcpy(VALUE ary, long beg, long argc, const VALUE *argv)
}
static VALUE *
-ary_heap_alloc_buffer(size_t capa)
+ary_heap_alloc(VALUE ary, size_t capa)
{
- return ALLOC_N(VALUE, capa);
+ VALUE *ptr = rb_transient_heap_alloc(ary, sizeof(VALUE) * capa);
+
+ if (ptr != NULL) {
+ RARY_TRANSIENT_SET(ary);
+ }
+ else {
+ RARY_TRANSIENT_UNSET(ary);
+ ptr = ALLOC_N(VALUE, capa);
+ }
+
+ return ptr;
}
static void
ary_heap_free_ptr(VALUE ary, const VALUE *ptr, long size)
{
- ruby_sized_xfree((void *)ptr, size);
+ if (RARRAY_TRANSIENT_P(ary)) {
+ /* ignore it */
+ }
+ else {
+ ruby_sized_xfree((void *)ptr, size);
+ }
}
static void
ary_heap_free(VALUE ary)
{
- ary_heap_free_ptr(ary, ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary));
+ if (RARRAY_TRANSIENT_P(ary)) {
+ RARY_TRANSIENT_UNSET(ary);
+ }
+ else {
+ ary_heap_free_ptr(ary, ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary));
+ }
}
static size_t
ary_heap_realloc(VALUE ary, size_t new_capa)
{
- RUBY_ASSERT(!OBJ_FROZEN(ary));
- SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, new_capa, ARY_HEAP_CAPA(ary));
+ size_t alloc_capa = new_capa;
+ size_t old_capa = ARY_HEAP_CAPA(ary);
+
+ if (RARRAY_TRANSIENT_P(ary)) {
+ if (new_capa <= old_capa) {
+ /* do nothing */
+ alloc_capa = old_capa;
+ }
+ else {
+ VALUE *new_ptr = rb_transient_heap_alloc(ary, sizeof(VALUE) * new_capa);
+
+ if (new_ptr == NULL) {
+ new_ptr = ALLOC_N(VALUE, new_capa);
+ RARY_TRANSIENT_UNSET(ary);
+ }
+
+ MEMCPY(new_ptr, ARY_HEAP_PTR(ary), VALUE, old_capa);
+ ARY_SET_PTR(ary, new_ptr);
+ }
+ }
+ else {
+ SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, new_capa, old_capa);
+ }
ary_verify(ary);
- return new_capa;
+ return alloc_capa;
+}
+
+#if USE_TRANSIENT_HEAP
+static inline void
+rb_ary_transient_heap_evacuate_(VALUE ary, int transient, int promote)
+{
+ if (transient) {
+ assert(!ARY_SHARED_ROOT_P(ary));
+
+ VALUE *new_ptr;
+ const VALUE *old_ptr = ARY_HEAP_PTR(ary);
+ long capa = ARY_HEAP_CAPA(ary);
+
+ assert(ARY_OWNS_HEAP_P(ary));
+ assert(RARRAY_TRANSIENT_P(ary));
+ assert(!ARY_PTR_USING_P(ary));
+
+ if (promote) {
+ new_ptr = ALLOC_N(VALUE, capa);
+ RARY_TRANSIENT_UNSET(ary);
+ }
+ else {
+ new_ptr = ary_heap_alloc(ary, capa);
+ }
+
+ MEMCPY(new_ptr, old_ptr, VALUE, capa);
+ /* do not use ARY_SET_PTR() because they assert !frozen */
+ RARRAY(ary)->as.heap.ptr = new_ptr;
+ }
+
+ ary_verify(ary);
+}
+
+void
+rb_ary_transient_heap_evacuate(VALUE ary, int promote)
+{
+ rb_ary_transient_heap_evacuate_(ary, RARRAY_TRANSIENT_P(ary), promote);
+}
+
+void
+rb_ary_detransient(VALUE ary)
+{
+ assert(RARRAY_TRANSIENT_P(ary));
+ rb_ary_transient_heap_evacuate_(ary, TRUE, TRUE);
}
+#else
+void
+rb_ary_detransient(VALUE ary)
+{
+ /* do nothing */
+}
+#endif
void
rb_ary_make_embedded(VALUE ary)
{
- RUBY_ASSERT(rb_ary_embeddable_p(ary));
+ assert(rb_ary_embeddable_p(ary));
if (!ARY_EMBED_P(ary)) {
const VALUE *buf = ARY_HEAP_PTR(ary);
long len = ARY_HEAP_LEN(ary);
+ bool was_transient = RARRAY_TRANSIENT_P(ary);
+ // FL_SET_EMBED also unsets the transient flag
FL_SET_EMBED(ary);
ARY_SET_EMBED_LEN(ary, len);
MEMCPY((void *)ARY_EMBED_PTR(ary), (void *)buf, VALUE, len);
- ary_heap_free_ptr(ary, buf, len * sizeof(VALUE));
+ if (!was_transient) {
+ ary_heap_free_ptr(ary, buf, len * sizeof(VALUE));
+ }
}
}
static void
ary_resize_capa(VALUE ary, long capacity)
{
- RUBY_ASSERT(RARRAY_LEN(ary) <= capacity);
- RUBY_ASSERT(!OBJ_FROZEN(ary));
- RUBY_ASSERT(!ARY_SHARED_P(ary));
+ assert(RARRAY_LEN(ary) <= capacity);
+ assert(!OBJ_FROZEN(ary));
+ assert(!ARY_SHARED_P(ary));
if (capacity > ary_embed_capa(ary)) {
size_t new_capa = capacity;
if (ARY_EMBED_P(ary)) {
long len = ARY_EMBED_LEN(ary);
- VALUE *ptr = ary_heap_alloc_buffer(capacity);
+ VALUE *ptr = ary_heap_alloc(ary, capacity);
MEMCPY(ptr, ARY_EMBED_PTR(ary), VALUE, len);
FL_UNSET_EMBED(ary);
@@ -441,12 +574,9 @@ ary_shrink_capa(VALUE ary)
{
long capacity = ARY_HEAP_LEN(ary);
long old_capa = ARY_HEAP_CAPA(ary);
- RUBY_ASSERT(!ARY_SHARED_P(ary));
- RUBY_ASSERT(old_capa >= capacity);
- if (old_capa > capacity) {
- size_t new_capa = ary_heap_realloc(ary, capacity);
- ARY_SET_CAPA(ary, new_capa);
- }
+ assert(!ARY_SHARED_P(ary));
+ assert(old_capa >= capacity);
+ if (old_capa > capacity) ary_heap_realloc(ary, capacity);
ary_verify(ary);
}
@@ -504,7 +634,7 @@ rb_ary_increment_share(VALUE shared_root)
{
if (!OBJ_FROZEN(shared_root)) {
long num = ARY_SHARED_ROOT_REFCNT(shared_root);
- RUBY_ASSERT(num >= 0);
+ assert(num >= 0);
ARY_SET_SHARED_ROOT_REFCNT(shared_root, num + 1);
}
return shared_root;
@@ -513,15 +643,10 @@ rb_ary_increment_share(VALUE shared_root)
static void
rb_ary_set_shared(VALUE ary, VALUE shared_root)
{
- RUBY_ASSERT(!ARY_EMBED_P(ary));
- RUBY_ASSERT(!OBJ_FROZEN(ary));
- RUBY_ASSERT(ARY_SHARED_ROOT_P(shared_root) || OBJ_FROZEN(shared_root));
-
rb_ary_increment_share(shared_root);
FL_SET_SHARED(ary);
- RB_OBJ_WRITE(ary, &RARRAY(ary)->as.heap.aux.shared_root, shared_root);
-
RB_DEBUG_COUNTER_INC(obj_ary_shared_create);
+ ARY_SET_SHARED(ary, shared_root);
}
static inline void
@@ -549,18 +674,18 @@ rb_ary_cancel_sharing(VALUE ary)
ARY_SET_EMBED_LEN(ary, len);
}
else if (ARY_SHARED_ROOT_OCCUPIED(shared_root) && len > ((shared_len = RARRAY_LEN(shared_root))>>1)) {
- long shift = RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared_root);
+ long shift = RARRAY_CONST_PTR_TRANSIENT(ary) - RARRAY_CONST_PTR_TRANSIENT(shared_root);
FL_UNSET_SHARED(ary);
- ARY_SET_PTR(ary, RARRAY_CONST_PTR(shared_root));
+ ARY_SET_PTR(ary, RARRAY_CONST_PTR_TRANSIENT(shared_root));
ARY_SET_CAPA(ary, shared_len);
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
MEMMOVE(ptr, ptr+shift, VALUE, len);
});
FL_SET_EMBED(shared_root);
rb_ary_decrement_share(shared_root);
}
else {
- VALUE *ptr = ary_heap_alloc_buffer(len);
+ VALUE *ptr = ary_heap_alloc(ary, len);
MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len);
rb_ary_unshare(ary);
ARY_SET_CAPA(ary, len);
@@ -593,7 +718,7 @@ ary_ensure_room_for_push(VALUE ary, long add_len)
if (new_len > ary_embed_capa(ary)) {
VALUE shared_root = ARY_SHARED_ROOT(ary);
if (ARY_SHARED_ROOT_OCCUPIED(shared_root)) {
- if (ARY_HEAP_PTR(ary) - RARRAY_CONST_PTR(shared_root) + new_len <= RARRAY_LEN(shared_root)) {
+ if (ARY_HEAP_PTR(ary) - RARRAY_CONST_PTR_TRANSIENT(shared_root) + new_len <= RARRAY_LEN(shared_root)) {
rb_ary_modify_check(ary);
ary_verify(ary);
@@ -629,32 +754,21 @@ ary_ensure_room_for_push(VALUE ary, long add_len)
/*
* call-seq:
- * freeze -> self
+ * array.freeze -> self
*
- * Freezes +self+ (if not already frozen); returns +self+:
+ * Freezes +self+; returns +self+:
*
* a = []
* a.frozen? # => false
* a.freeze
* a.frozen? # => true
*
- * No further changes may be made to +self+;
- * raises FrozenError if a change is attempted.
- *
- * Related: Kernel#frozen?.
+ * An attempt to modify a frozen \Array raises FrozenError.
*/
VALUE
rb_ary_freeze(VALUE ary)
{
- RUBY_ASSERT(RB_TYPE_P(ary, T_ARRAY));
-
- if (OBJ_FROZEN(ary)) return ary;
-
- if (!ARY_EMBED_P(ary) && !ARY_SHARED_P(ary) && !ARY_SHARED_ROOT_P(ary)) {
- ary_shrink_capa(ary);
- }
-
return rb_obj_freeze(ary);
}
@@ -681,10 +795,13 @@ static VALUE
ary_alloc_embed(VALUE klass, long capa)
{
size_t size = ary_embed_size(capa);
- RUBY_ASSERT(rb_gc_size_allocatable_p(size));
- NEWOBJ_OF(ary, struct RArray, klass,
+ assert(rb_gc_size_allocatable_p(size));
+#if !USE_RVARGC
+ assert(size <= sizeof(struct RArray));
+#endif
+ RVARGC_NEWOBJ_OF(ary, struct RArray, klass,
T_ARRAY | RARRAY_EMBED_FLAG | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
- size, 0);
+ size);
/* Created array is:
* FL_SET_EMBED((VALUE)ary);
* ARY_SET_EMBED_LEN((VALUE)ary, 0);
@@ -695,9 +812,9 @@ ary_alloc_embed(VALUE klass, long capa)
static VALUE
ary_alloc_heap(VALUE klass)
{
- NEWOBJ_OF(ary, struct RArray, klass,
+ RVARGC_NEWOBJ_OF(ary, struct RArray, klass,
T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
- sizeof(struct RArray), 0);
+ sizeof(struct RArray));
return (VALUE)ary;
}
@@ -711,7 +828,7 @@ empty_ary_alloc(VALUE klass)
static VALUE
ary_new(VALUE klass, long capa)
{
- VALUE ary;
+ VALUE ary,*ptr;
if (capa < 0) {
rb_raise(rb_eArgError, "negative array size (or size too big)");
@@ -728,9 +845,10 @@ ary_new(VALUE klass, long capa)
else {
ary = ary_alloc_heap(klass);
ARY_SET_CAPA(ary, capa);
- RUBY_ASSERT(!ARY_EMBED_P(ary));
+ assert(!ARY_EMBED_P(ary));
- ARY_SET_PTR(ary, ary_heap_alloc_buffer(capa));
+ ptr = ary_heap_alloc(ary, capa);
+ ARY_SET_PTR(ary, ptr);
ARY_SET_HEAP_LEN(ary, 0);
}
@@ -768,7 +886,7 @@ VALUE
return ary;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_ary_tmp_new_from_values(VALUE klass, long n, const VALUE *elts)
{
VALUE ary;
@@ -792,10 +910,13 @@ static VALUE
ec_ary_alloc_embed(rb_execution_context_t *ec, VALUE klass, long capa)
{
size_t size = ary_embed_size(capa);
- RUBY_ASSERT(rb_gc_size_allocatable_p(size));
- NEWOBJ_OF(ary, struct RArray, klass,
- T_ARRAY | RARRAY_EMBED_FLAG | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
- size, ec);
+ assert(rb_gc_size_allocatable_p(size));
+#if !USE_RVARGC
+ assert(size <= sizeof(struct RArray));
+#endif
+ RB_RVARGC_EC_NEWOBJ_OF(ec, ary, struct RArray, klass,
+ T_ARRAY | RARRAY_EMBED_FLAG | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
+ size);
/* Created array is:
* FL_SET_EMBED((VALUE)ary);
* ARY_SET_EMBED_LEN((VALUE)ary, 0);
@@ -806,16 +927,16 @@ ec_ary_alloc_embed(rb_execution_context_t *ec, VALUE klass, long capa)
static VALUE
ec_ary_alloc_heap(rb_execution_context_t *ec, VALUE klass)
{
- NEWOBJ_OF(ary, struct RArray, klass,
- T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
- sizeof(struct RArray), ec);
+ RB_RVARGC_EC_NEWOBJ_OF(ec, ary, struct RArray, klass,
+ T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0),
+ sizeof(struct RArray));
return (VALUE)ary;
}
static VALUE
ec_ary_new(rb_execution_context_t *ec, VALUE klass, long capa)
{
- VALUE ary;
+ VALUE ary,*ptr;
if (capa < 0) {
rb_raise(rb_eArgError, "negative array size (or size too big)");
@@ -832,9 +953,10 @@ ec_ary_new(rb_execution_context_t *ec, VALUE klass, long capa)
else {
ary = ec_ary_alloc_heap(ec, klass);
ARY_SET_CAPA(ary, capa);
- RUBY_ASSERT(!ARY_EMBED_P(ary));
+ assert(!ARY_EMBED_P(ary));
- ARY_SET_PTR(ary, ary_heap_alloc_buffer(capa));
+ ptr = ary_heap_alloc(ary, capa);
+ ARY_SET_PTR(ary, ptr);
ARY_SET_HEAP_LEN(ary, 0);
}
@@ -859,6 +981,7 @@ VALUE
rb_ary_hidden_new(long capa)
{
VALUE ary = ary_new(0, capa);
+ rb_ary_transient_heap_evacuate(ary, TRUE);
return ary;
}
@@ -881,8 +1004,13 @@ rb_ary_free(VALUE ary)
RB_DEBUG_COUNTER_INC(obj_ary_extracapa);
}
- RB_DEBUG_COUNTER_INC(obj_ary_ptr);
- ary_heap_free(ary);
+ if (RARRAY_TRANSIENT_P(ary)) {
+ RB_DEBUG_COUNTER_INC(obj_ary_transient);
+ }
+ else {
+ RB_DEBUG_COUNTER_INC(obj_ary_ptr);
+ ary_heap_free(ary);
+ }
}
else {
RB_DEBUG_COUNTER_INC(obj_ary_embed);
@@ -896,32 +1024,7 @@ rb_ary_free(VALUE ary)
}
}
-static VALUE fake_ary_flags;
-
-static VALUE
-init_fake_ary_flags(void)
-{
- struct RArray fake_ary = {0};
- fake_ary.basic.flags = T_ARRAY;
- VALUE ary = (VALUE)&fake_ary;
- rb_ary_freeze(ary);
- return fake_ary.basic.flags;
-}
-
-VALUE
-rb_setup_fake_ary(struct RArray *fake_ary, const VALUE *list, long len)
-{
- fake_ary->basic.flags = fake_ary_flags;
- RBASIC_CLEAR_CLASS((VALUE)fake_ary);
-
- // bypass frozen checks
- fake_ary->as.heap.ptr = list;
- fake_ary->as.heap.len = len;
- fake_ary->as.heap.aux.capa = len;
- return (VALUE)fake_ary;
-}
-
-size_t
+RUBY_FUNC_EXPORTED size_t
rb_ary_memsize(VALUE ary)
{
if (ARY_OWNS_HEAP_P(ary)) {
@@ -935,6 +1038,7 @@ rb_ary_memsize(VALUE ary)
static VALUE
ary_make_shared(VALUE ary)
{
+ assert(USE_RVARGC || !ARY_EMBED_P(ary));
ary_verify(ary);
if (ARY_SHARED_P(ary)) {
@@ -944,9 +1048,15 @@ ary_make_shared(VALUE ary)
return ary;
}
else if (OBJ_FROZEN(ary)) {
+ if (!ARY_EMBED_P(ary)) {
+ rb_ary_transient_heap_evacuate(ary, TRUE);
+ ary_shrink_capa(ary);
+ }
return ary;
}
else {
+ rb_ary_transient_heap_evacuate(ary, TRUE);
+
long capa = ARY_CAPA(ary);
long len = RARRAY_LEN(ary);
@@ -956,21 +1066,26 @@ ary_make_shared(VALUE ary)
FL_SET_SHARED_ROOT(shared);
if (ARY_EMBED_P(ary)) {
- VALUE *ptr = ary_heap_alloc_buffer(capa);
+ /* Cannot use ary_heap_alloc because we don't want to allocate
+ * on the transient heap. */
+ VALUE *ptr = ALLOC_N(VALUE, capa);
ARY_SET_PTR(shared, ptr);
- ary_memcpy(shared, 0, len, RARRAY_CONST_PTR(ary));
+ ary_memcpy(shared, 0, len, RARRAY_PTR(ary));
FL_UNSET_EMBED(ary);
ARY_SET_HEAP_LEN(ary, len);
ARY_SET_PTR(ary, ptr);
}
else {
- ARY_SET_PTR(shared, RARRAY_CONST_PTR(ary));
+ ARY_SET_PTR(shared, RARRAY_PTR(ary));
}
ARY_SET_LEN(shared, capa);
ary_mem_clear(shared, len, capa - len);
- rb_ary_set_shared(ary, shared);
+ ARY_SET_SHARED_ROOT_REFCNT(shared, 1);
+ FL_SET_SHARED(ary);
+ RB_DEBUG_COUNTER_INC(obj_ary_shared_create);
+ ARY_SET_SHARED(ary, shared);
ary_verify(shared);
ary_verify(ary);
@@ -986,9 +1101,9 @@ ary_make_substitution(VALUE ary)
if (ary_embeddable_p(len)) {
VALUE subst = rb_ary_new_capa(len);
- RUBY_ASSERT(ARY_EMBED_P(subst));
+ assert(ARY_EMBED_P(subst));
- ary_memcpy(subst, 0, len, RARRAY_CONST_PTR(ary));
+ ary_memcpy(subst, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary));
ARY_SET_EMBED_LEN(subst, len);
return subst;
}
@@ -1016,7 +1131,7 @@ rb_check_array_type(VALUE ary)
return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_ary);
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_check_to_array(VALUE ary)
{
return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_a);
@@ -1032,18 +1147,14 @@ rb_to_array(VALUE ary)
* call-seq:
* Array.try_convert(object) -> object, new_array, or nil
*
- * Attempts to return an array, based on the given +object+.
- *
- * If +object+ is an array, returns +object+.
+ * If +object+ is an \Array object, returns +object+.
*
- * Otherwise if +object+ responds to <tt>:to_ary</tt>.
- * calls <tt>object.to_ary</tt>:
- * if the return value is an array or +nil+, returns that value;
- * if not, raises TypeError.
+ * Otherwise if +object+ responds to <tt>:to_ary</tt>,
+ * calls <tt>object.to_ary</tt> and returns the result.
*
- * Otherwise returns +nil+.
+ * Returns +nil+ if +object+ does not respond to <tt>:to_ary</tt>
*
- * Related: see {Methods for Creating an Array}[rdoc-ref:Array@Methods+for+Creating+an+Array].
+ * Raises an exception unless <tt>object.to_ary</tt> returns an \Array object.
*/
static VALUE
@@ -1080,51 +1191,48 @@ rb_ary_s_new(int argc, VALUE *argv, VALUE klass)
* call-seq:
* Array.new -> new_empty_array
* Array.new(array) -> new_array
- * Array.new(size, default_value = nil) -> new_array
- * Array.new(size = 0) {|index| ... } -> new_array
+ * Array.new(size) -> new_array
+ * Array.new(size, default_value) -> new_array
+ * Array.new(size) {|index| ... } -> new_array
*
- * Returns a new array.
+ * Returns a new \Array.
*
- * With no block and no argument given, returns a new empty array:
+ * With no block and no arguments, returns a new empty \Array object.
*
- * Array.new # => []
+ * With no block and a single \Array argument +array+,
+ * returns a new \Array formed from +array+:
*
- * With no block and array argument given, returns a new array with the same elements:
- *
- * Array.new([:foo, 'bar', 2]) # => [:foo, "bar", 2]
- *
- * With no block and integer argument given, returns a new array containing
- * that many instances of the given +default_value+:
- *
- * Array.new(0) # => []
- * Array.new(3) # => [nil, nil, nil]
- * Array.new(2, 3) # => [3, 3]
+ * a = Array.new([:foo, 'bar', 2])
+ * a.class # => Array
+ * a # => [:foo, "bar", 2]
*
- * With a block given, returns an array of the given +size+;
- * calls the block with each +index+ in the range <tt>(0...size)</tt>;
- * the element at that +index+ in the returned array is the blocks return value:
+ * With no block and a single \Integer argument +size+,
+ * returns a new \Array of the given size
+ * whose elements are all +nil+:
*
- * Array.new(3) {|index| "Element #{index}" } # => ["Element 0", "Element 1", "Element 2"]
+ * a = Array.new(3)
+ * a # => [nil, nil, nil]
*
- * A common pitfall for new Rubyists is providing an expression as +default_value+:
+ * With no block and arguments +size+ and +default_value+,
+ * returns an \Array of the given size;
+ * each element is that same +default_value+:
*
- * array = Array.new(2, {})
- * array # => [{}, {}]
- * array[0][:a] = 1
- * array # => [{a: 1}, {a: 1}], as array[0] and array[1] are same object
+ * a = Array.new(3, 'x')
+ * a # => ['x', 'x', 'x']
*
- * If you want the elements of the array to be distinct, you should pass a block:
+ * With a block and argument +size+,
+ * returns an \Array of the given size;
+ * the block is called with each successive integer +index+;
+ * the element for that +index+ is the return value from the block:
*
- * array = Array.new(2) { {} }
- * array # => [{}, {}]
- * array[0][:a] = 1
- * array # => [{a: 1}, {}], as array[0] and array[1] are different objects
+ * a = Array.new(3) {|index| "Element #{index}" }
+ * a # => ["Element 0", "Element 1", "Element 2"]
*
- * Raises TypeError if the first argument is not either an array
- * or an {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects]).
- * Raises ArgumentError if the first argument is a negative integer.
+ * Raises ArgumentError if +size+ is negative.
*
- * Related: see {Methods for Creating an Array}[rdoc-ref:Array@Methods+for+Creating+an+Array].
+ * With a block and no argument,
+ * or a single argument +0+,
+ * ignores the block and returns a new empty \Array.
*/
static VALUE
@@ -1136,8 +1244,8 @@ rb_ary_initialize(int argc, VALUE *argv, VALUE ary)
rb_ary_modify(ary);
if (argc == 0) {
rb_ary_reset(ary);
- RUBY_ASSERT(ARY_EMBED_P(ary));
- RUBY_ASSERT(ARY_EMBED_LEN(ary) == 0);
+ assert(ARY_EMBED_P(ary));
+ assert(ARY_EMBED_LEN(ary) == 0);
if (rb_block_given_p()) {
rb_warning("given block not used");
}
@@ -1182,13 +1290,11 @@ rb_ary_initialize(int argc, VALUE *argv, VALUE ary)
}
/*
- * Returns a new array, populated with the given objects:
+ * Returns a new array populated with the given objects.
*
- * Array[1, 'a', /^A/] # => [1, "a", /^A/]
- * Array[] # => []
- * Array.[](1, 'a', /^A/) # => [1, "a", /^A/]
- *
- * Related: see {Methods for Creating an Array}[rdoc-ref:Array@Methods+for+Creating+an+Array].
+ * Array.[]( 1, 'a', /^A/) # => [1, "a", /^A/]
+ * Array[ 1, 'a', /^A/ ] # => [1, "a", /^A/]
+ * [ 1, 'a', /^A/ ] # => [1, "a", /^A/]
*/
static VALUE
@@ -1236,26 +1342,25 @@ rb_ary_store(VALUE ary, long idx, VALUE val)
static VALUE
ary_make_partial(VALUE ary, VALUE klass, long offset, long len)
{
- RUBY_ASSERT(offset >= 0);
- RUBY_ASSERT(len >= 0);
- RUBY_ASSERT(offset+len <= RARRAY_LEN(ary));
+ assert(offset >= 0);
+ assert(len >= 0);
+ assert(offset+len <= RARRAY_LEN(ary));
+
+ const size_t rarray_embed_capa_max = (sizeof(struct RArray) - offsetof(struct RArray, as.ary)) / sizeof(VALUE);
- VALUE result = ary_alloc_heap(klass);
- size_t embed_capa = ary_embed_capa(result);
- if ((size_t)len <= embed_capa) {
- FL_SET_EMBED(result);
- ary_memcpy(result, 0, len, RARRAY_CONST_PTR(ary) + offset);
+ if ((size_t)len <= rarray_embed_capa_max && ary_embeddable_p(len)) {
+ VALUE result = ary_alloc_embed(klass, len);
+ ary_memcpy(result, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary) + offset);
ARY_SET_EMBED_LEN(result, len);
+ return result;
}
else {
VALUE shared = ary_make_shared(ary);
- /* The ary_make_shared call may allocate, which can trigger a GC
- * compaction. This can cause the array to be embedded because it has
- * a length of 0. */
- FL_UNSET_EMBED(result);
+ VALUE result = ary_alloc_heap(klass);
+ assert(!ARY_EMBED_P(result));
- ARY_SET_PTR(result, RARRAY_CONST_PTR(ary));
+ ARY_SET_PTR(result, RARRAY_CONST_PTR_TRANSIENT(ary));
ARY_SET_LEN(result, RARRAY_LEN(ary));
rb_ary_set_shared(result, shared);
@@ -1263,27 +1368,25 @@ ary_make_partial(VALUE ary, VALUE klass, long offset, long len)
ARY_SET_LEN(result, len);
ary_verify(shared);
+ ary_verify(result);
+ return result;
}
-
- ary_verify(result);
- return result;
}
static VALUE
ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step)
{
- RUBY_ASSERT(offset >= 0);
- RUBY_ASSERT(len >= 0);
- RUBY_ASSERT(offset+len <= RARRAY_LEN(ary));
- RUBY_ASSERT(step != 0);
+ assert(offset >= 0);
+ assert(len >= 0);
+ assert(offset+len <= RARRAY_LEN(ary));
+ assert(step != 0);
+ const VALUE *values = RARRAY_CONST_PTR_TRANSIENT(ary);
const long orig_len = len;
if (step > 0 && step >= len) {
VALUE result = ary_new(klass, 1);
VALUE *ptr = (VALUE *)ARY_EMBED_PTR(result);
- const VALUE *values = RARRAY_CONST_PTR(ary);
-
RB_OBJ_WRITE(result, ptr, values[offset]);
ARY_SET_EMBED_LEN(result, 1);
return result;
@@ -1301,8 +1404,6 @@ ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step)
VALUE result = ary_new(klass, len);
if (ARY_EMBED_P(result)) {
VALUE *ptr = (VALUE *)ARY_EMBED_PTR(result);
- const VALUE *values = RARRAY_CONST_PTR(ary);
-
for (i = 0; i < len; ++i) {
RB_OBJ_WRITE(result, ptr+i, values[j]);
j += step;
@@ -1310,9 +1411,7 @@ ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step)
ARY_SET_EMBED_LEN(result, len);
}
else {
- const VALUE *values = RARRAY_CONST_PTR(ary);
-
- RARRAY_PTR_USE(result, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(result, ptr, {
for (i = 0; i < len; ++i) {
RB_OBJ_WRITE(result, ptr+i, values[j]);
j += step;
@@ -1337,11 +1436,20 @@ enum ary_take_pos_flags
};
static VALUE
-ary_take_first_or_last_n(VALUE ary, long n, enum ary_take_pos_flags last)
+ary_take_first_or_last(int argc, const VALUE *argv, VALUE ary, enum ary_take_pos_flags last)
{
- long len = RARRAY_LEN(ary);
+ long n;
+ long len;
long offset = 0;
+ argc = rb_check_arity(argc, 0, 1);
+ /* the case optional argument is omitted should be handled in
+ * callers of this function. if another arity case is added,
+ * this arity check needs to rewrite. */
+ RUBY_ASSERT_ALWAYS(argc == 1);
+
+ n = NUM2LONG(argv[0]);
+ len = RARRAY_LEN(ary);
if (n > len) {
n = len;
}
@@ -1354,30 +1462,21 @@ ary_take_first_or_last_n(VALUE ary, long n, enum ary_take_pos_flags last)
return ary_make_partial(ary, rb_cArray, offset, n);
}
-static VALUE
-ary_take_first_or_last(int argc, const VALUE *argv, VALUE ary, enum ary_take_pos_flags last)
-{
- argc = rb_check_arity(argc, 0, 1);
- /* the case optional argument is omitted should be handled in
- * callers of this function. if another arity case is added,
- * this arity check needs to rewrite. */
- RUBY_ASSERT_ALWAYS(argc == 1);
- return ary_take_first_or_last_n(ary, NUM2LONG(argv[0]), last);
-}
-
/*
* call-seq:
- * self << object -> self
+ * array << object -> self
*
- * Appends +object+ as the last element in +self+; returns +self+:
+ * Appends +object+ to +self+; returns +self+:
*
- * [:foo, 'bar', 2] << :baz # => [:foo, "bar", 2, :baz]
+ * a = [:foo, 'bar', 2]
+ * a << :baz # => [:foo, "bar", 2, :baz]
*
- * Appends +object+ as a single element, even if it is another array:
+ * Appends +object+ as one element, even if it is another \Array:
*
- * [:foo, 'bar', 2] << [3, 4] # => [:foo, "bar", 2, [3, 4]]
+ * a = [:foo, 'bar', 2]
+ * a1 = a << [3, 4]
+ * a1 # => [:foo, "bar", 2, [3, 4]]
*
- * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning].
*/
VALUE
@@ -1385,7 +1484,7 @@ rb_ary_push(VALUE ary, VALUE item)
{
long idx = RARRAY_LEN((ary_verify(ary), ary));
VALUE target_ary = ary_ensure_room_for_push(ary, 1);
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
RB_OBJ_WRITE(target_ary, &ptr[idx], item);
});
ARY_SET_LEN(ary, idx + 1);
@@ -1405,20 +1504,24 @@ rb_ary_cat(VALUE ary, const VALUE *argv, long len)
/*
* call-seq:
- * push(*objects) -> self
- * append(*objects) -> self
+ * array.push(*objects) -> self
*
- * Appends each argument in +objects+ to +self+; returns +self+:
+ * Appends trailing elements.
*
- * a = [:foo, 'bar', 2] # => [:foo, "bar", 2]
- * a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
+ * Appends each argument in +objects+ to +self+; returns +self+:
*
- * Appends each argument as a single element, even if it is another array:
+ * a = [:foo, 'bar', 2]
+ * a.push(:baz, :bat) # => [:foo, "bar", 2, :baz, :bat]
+ *
+ * Appends each argument as one element, even if it is another \Array:
+ *
+ * a = [:foo, 'bar', 2]
+ * a1 = a.push([:baz, :bat], [:bam, :bad])
+ * a1 # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
*
- * a = [:foo, 'bar', 2] # => [:foo, "bar", 2]
- a.push([:baz, :bat], [:bam, :bad]) # => [:foo, "bar", 2, [:baz, :bat], [:bam, :bad]]
+ * Array#append is an alias for Array#push.
*
- * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning].
+ * Related: #pop, #shift, #unshift.
*/
static VALUE
@@ -1462,9 +1565,9 @@ rb_ary_pop(VALUE ary)
*
* Returns +nil+ if the array is empty.
*
- * When a non-negative Integer argument +n+ is given and is in range,
+ * When a non-negative \Integer argument +n+ is given and is in range,
*
- * removes and returns the last +n+ elements in a new +Array+:
+ * removes and returns the last +n+ elements in a new \Array:
* a = [:foo, 'bar', 2]
* a.pop(2) # => ["bar", 2]
*
@@ -1526,20 +1629,20 @@ rb_ary_shift(VALUE ary)
*
* Returns +nil+ if +self+ is empty.
*
- * When positive Integer argument +n+ is given, removes the first +n+ elements;
- * returns those elements in a new +Array+:
+ * When positive \Integer argument +n+ is given, removes the first +n+ elements;
+ * returns those elements in a new \Array:
*
* a = [:foo, 'bar', 2]
* a.shift(2) # => [:foo, 'bar']
* a # => [2]
*
* If +n+ is as large as or larger than <tt>self.length</tt>,
- * removes all elements; returns those elements in a new +Array+:
+ * removes all elements; returns those elements in a new \Array:
*
* a = [:foo, 'bar', 2]
* a.shift(3) # => [:foo, 'bar', 2]
*
- * If +n+ is zero, returns a new empty +Array+; +self+ is unmodified.
+ * If +n+ is zero, returns a new empty \Array; +self+ is unmodified.
*
* Related: #push, #pop, #unshift.
*/
@@ -1562,7 +1665,7 @@ rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
return result;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_ary_behead(VALUE ary, long n)
{
if (n <= 0) {
@@ -1573,7 +1676,7 @@ rb_ary_behead(VALUE ary, long n)
if (!ARY_SHARED_P(ary)) {
if (ARY_EMBED_P(ary) || RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) {
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
MEMMOVE(ptr, ptr + n, VALUE, RARRAY_LEN(ary) - n);
}); /* WB: no new reference */
ARY_INCREASE_LEN(ary, -n);
@@ -1606,7 +1709,7 @@ make_room_for_unshift(VALUE ary, const VALUE *head, VALUE *sharedp, int argc, lo
head = sharedp + argc + room;
}
ARY_SET_PTR(ary, head - argc);
- RUBY_ASSERT(ARY_SHARED_ROOT_OCCUPIED(ARY_SHARED_ROOT(ary)));
+ assert(ARY_SHARED_ROOT_OCCUPIED(ARY_SHARED_ROOT(ary)));
ary_verify(ary);
return ARY_SHARED_ROOT(ary);
@@ -1634,12 +1737,12 @@ ary_modify_for_unshift(VALUE ary, int argc)
capa = ARY_CAPA(ary);
ary_make_shared(ary);
- head = sharedp = RARRAY_CONST_PTR(ary);
+ head = sharedp = RARRAY_CONST_PTR_TRANSIENT(ary);
return make_room_for_unshift(ary, head, (void *)sharedp, argc, capa, len);
}
else {
/* sliding items */
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
MEMMOVE(ptr + argc, ptr, VALUE, len);
});
@@ -1671,8 +1774,8 @@ ary_ensure_room_for_unshift(VALUE ary, int argc)
return ary_modify_for_unshift(ary, argc);
}
else {
- const VALUE * head = RARRAY_CONST_PTR(ary);
- void *sharedp = (void *)RARRAY_CONST_PTR(shared_root);
+ const VALUE * head = RARRAY_CONST_PTR_TRANSIENT(ary);
+ void *sharedp = (void *)RARRAY_CONST_PTR_TRANSIENT(shared_root);
rb_ary_modify_check(ary);
return make_room_for_unshift(ary, head, sharedp, argc, capa, len);
@@ -1689,10 +1792,12 @@ ary_ensure_room_for_unshift(VALUE ary, int argc)
* a = [:foo, 'bar', 2]
* a.unshift(:bam, :bat) # => [:bam, :bat, :foo, "bar", 2]
*
+ * Array#prepend is an alias for Array#unshift.
+ *
* Related: #push, #pop, #shift.
*/
-VALUE
+static VALUE
rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
{
long len = RARRAY_LEN(ary);
@@ -1712,7 +1817,7 @@ rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
VALUE
rb_ary_unshift(VALUE ary, VALUE item)
{
- return rb_ary_unshift_m(1, &item, ary);
+ return rb_ary_unshift_m(1,&item,ary);
}
/* faster version - use this if you don't need to treat negative offset */
@@ -1765,42 +1870,25 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
/*
* call-seq:
- * self[index] -> object or nil
- * self[start, length] -> object or nil
- * self[range] -> object or nil
- * self[aseq] -> object or nil
- * slice(index) -> object or nil
- * slice(start, length) -> object or nil
- * slice(range) -> object or nil
- * slice(aseq) -> object or nil
+ * array[index] -> object or nil
+ * array[start, length] -> object or nil
+ * array[range] -> object or nil
+ * array[aseq] -> object or nil
+ * array.slice(index) -> object or nil
+ * array.slice(start, length) -> object or nil
+ * array.slice(range) -> object or nil
+ * array.slice(aseq) -> object or nil
*
* Returns elements from +self+; does not modify +self+.
*
- * In brief:
- *
- * a = [:foo, 'bar', 2]
- *
- * # Single argument index: returns one element.
- * a[0] # => :foo # Zero-based index.
- * a[-1] # => 2 # Negative index counts backwards from end.
- *
- * # Arguments start and length: returns an array.
- * a[1, 2] # => ["bar", 2]
- * a[-2, 2] # => ["bar", 2] # Negative start counts backwards from end.
- *
- * # Single argument range: returns an array.
- * a[0..1] # => [:foo, "bar"]
- * a[0..-2] # => [:foo, "bar"] # Negative range-begin counts backwards from end.
- * a[-2..2] # => ["bar", 2] # Negative range-end counts backwards from end.
- *
- * When a single integer argument +index+ is given, returns the element at offset +index+:
+ * When a single \Integer argument +index+ is given, returns the element at offset +index+:
*
* a = [:foo, 'bar', 2]
* a[0] # => :foo
* a[2] # => 2
* a # => [:foo, "bar", 2]
*
- * If +index+ is negative, counts backwards from the end of +self+:
+ * If +index+ is negative, counts relative to the end of +self+:
*
* a = [:foo, 'bar', 2]
* a[-1] # => 2
@@ -1808,8 +1896,8 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
*
* If +index+ is out of range, returns +nil+.
*
- * When two Integer arguments +start+ and +length+ are given,
- * returns a new +Array+ of size +length+ containing successive elements beginning at offset +start+:
+ * When two \Integer arguments +start+ and +length+ are given,
+ * returns a new \Array of size +length+ containing successive elements beginning at offset +start+:
*
* a = [:foo, 'bar', 2]
* a[0, 2] # => [:foo, "bar"]
@@ -1824,11 +1912,11 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
* a[2, 2] # => [2]
*
* If <tt>start == self.size</tt> and <tt>length >= 0</tt>,
- * returns a new empty +Array+.
+ * returns a new empty \Array.
*
* If +length+ is negative, returns +nil+.
*
- * When a single Range argument +range+ is given,
+ * When a single \Range argument +range+ is given,
* treats <tt>range.min</tt> as +start+ above
* and <tt>range.size</tt> as +length+ above:
*
@@ -1836,7 +1924,7 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
* a[0..1] # => [:foo, "bar"]
* a[1..2] # => ["bar", 2]
*
- * Special case: If <tt>range.start == a.size</tt>, returns a new empty +Array+.
+ * Special case: If <tt>range.start == a.size</tt>, returns a new empty \Array.
*
* If <tt>range.end</tt> is negative, calculates the end index from the end:
*
@@ -1860,7 +1948,7 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
* a[4..-1] # => nil
*
* When a single Enumerator::ArithmeticSequence argument +aseq+ is given,
- * returns an +Array+ of elements corresponding to the indexes produced by
+ * returns an \Array of elements corresponding to the indexes produced by
* the sequence.
*
* a = ['--', 'data1', '--', 'data2', '--', 'data3']
@@ -1882,7 +1970,7 @@ static VALUE rb_ary_aref2(VALUE ary, VALUE b, VALUE e);
* # Raises TypeError (no implicit conversion of Symbol into Integer):
* a[:foo]
*
- * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
+ * Array#slice is an alias for Array#[].
*/
VALUE
@@ -1906,7 +1994,7 @@ rb_ary_aref2(VALUE ary, VALUE b, VALUE e)
return rb_ary_subseq(ary, beg, len);
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_ary_aref1(VALUE ary, VALUE arg)
{
long beg, len, step;
@@ -1930,26 +2018,13 @@ rb_ary_aref1(VALUE ary, VALUE arg)
/*
* call-seq:
- * at(index) -> object or nil
- *
- * Returns the element of +self+ specified by the given +index+
- * or +nil+ if there is no such element;
- * +index+ must be an
- * {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects].
- *
- * For non-negative +index+, returns the element of +self+ at offset +index+:
+ * array.at(index) -> object
*
+ * Returns the element at \Integer offset +index+; does not modify +self+.
* a = [:foo, 'bar', 2]
- * a.at(0) # => :foo
- * a.at(2) # => 2
- * a.at(2.0) # => 2
- *
- * For negative +index+, counts backwards from the end of +self+:
+ * a.at(0) # => :foo
+ * a.at(2) # => 2
*
- * a.at(-2) # => "bar"
- *
- * Related: Array#[];
- * see also {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
*/
VALUE
@@ -1958,7 +2033,39 @@ rb_ary_at(VALUE ary, VALUE pos)
return rb_ary_entry(ary, NUM2LONG(pos));
}
-#if 0
+/*
+ * call-seq:
+ * array.first -> object or nil
+ * array.first(n) -> new_array
+ *
+ * Returns elements from +self+; does not modify +self+.
+ *
+ * When no argument is given, returns the first element:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.first # => :foo
+ * a # => [:foo, "bar", 2]
+ *
+ * If +self+ is empty, returns +nil+.
+ *
+ * When non-negative \Integer argument +n+ is given,
+ * returns the first +n+ elements in a new \Array:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.first(2) # => [:foo, "bar"]
+ *
+ * If <tt>n >= array.size</tt>, returns all elements:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.first(50) # => [:foo, "bar", 2]
+ *
+ * If <tt>n == 0</tt> returns an new empty \Array:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.first(0) # []
+ *
+ * Related: #last.
+ */
static VALUE
rb_ary_first(int argc, VALUE *argv, VALUE ary)
{
@@ -1970,26 +2077,48 @@ rb_ary_first(int argc, VALUE *argv, VALUE ary)
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST);
}
}
-#endif
-static VALUE
-ary_first(VALUE self)
-{
- return (RARRAY_LEN(self) == 0) ? Qnil : RARRAY_AREF(self, 0);
-}
-
-static VALUE
-ary_last(VALUE self)
-{
- long len = RARRAY_LEN(self);
- return (len == 0) ? Qnil : RARRAY_AREF(self, len-1);
-}
+/*
+ * call-seq:
+ * array.last -> object or nil
+ * array.last(n) -> new_array
+ *
+ * Returns elements from +self+; +self+ is not modified.
+ *
+ * When no argument is given, returns the last element:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.last # => 2
+ * a # => [:foo, "bar", 2]
+ *
+ * If +self+ is empty, returns +nil+.
+ *
+ * When non-negative \Integer argument +n+ is given,
+ * returns the last +n+ elements in a new \Array:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.last(2) # => ["bar", 2]
+ *
+ * If <tt>n >= array.size</tt>, returns all elements:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.last(50) # => [:foo, "bar", 2]
+ *
+ * If <tt>n == 0</tt>, returns an new empty \Array:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.last(0) # []
+ *
+ * Related: #first.
+ */
VALUE
-rb_ary_last(int argc, const VALUE *argv, VALUE ary) // used by parse.y
+rb_ary_last(int argc, const VALUE *argv, VALUE ary)
{
if (argc == 0) {
- return ary_last(ary);
+ long len = RARRAY_LEN(ary);
+ if (len == 0) return Qnil;
+ return RARRAY_AREF(ary, len-1);
}
else {
return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST);
@@ -1998,19 +2127,17 @@ rb_ary_last(int argc, const VALUE *argv, VALUE ary) // used by parse.y
/*
* call-seq:
- * fetch(index) -> element
- * fetch(index, default_value) -> element or default_value
- * fetch(index) {|index| ... } -> element or block_return_value
+ * array.fetch(index) -> element
+ * array.fetch(index, default_value) -> element
+ * array.fetch(index) {|index| ... } -> element
*
- * Returns the element of +self+ at offset +index+ if +index+ is in range; +index+ must be an
- * {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects].
+ * Returns the element at offset +index+.
*
- * With the single argument +index+ and no block,
+ * With the single \Integer argument +index+,
* returns the element at offset +index+:
*
* a = [:foo, 'bar', 2]
- * a.fetch(1) # => "bar"
- * a.fetch(1.1) # => "bar"
+ * a.fetch(1) # => "bar"
*
* If +index+ is negative, counts from the end of the array:
*
@@ -2018,12 +2145,12 @@ rb_ary_last(int argc, const VALUE *argv, VALUE ary) // used by parse.y
* a.fetch(-1) # => 2
* a.fetch(-2) # => "bar"
*
- * With arguments +index+ and +default_value+ (which may be any object) and no block,
- * returns +default_value+ if +index+ is out-of-range:
+ * With arguments +index+ and +default_value+,
+ * returns the element at offset +index+ if index is in range,
+ * otherwise returns +default_value+:
*
* a = [:foo, 'bar', 2]
- * a.fetch(1, nil) # => "bar"
- * a.fetch(3, :foo) # => :foo
+ * a.fetch(1, nil) # => "bar"
*
* With argument +index+ and a block,
* returns the element at offset +index+ if index is in range
@@ -2033,7 +2160,6 @@ rb_ary_last(int argc, const VALUE *argv, VALUE ary) // used by parse.y
* a.fetch(1) {|index| raise 'Cannot happen' } # => "bar"
* a.fetch(50) {|index| "Value for #{index}" } # => "Value for 50"
*
- * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
*/
static VALUE
@@ -2066,16 +2192,13 @@ rb_ary_fetch(int argc, VALUE *argv, VALUE ary)
/*
* call-seq:
- * find_index(object) -> integer or nil
- * find_index {|element| ... } -> integer or nil
- * find_index -> new_enumerator
- * index(object) -> integer or nil
- * index {|element| ... } -> integer or nil
- * index -> new_enumerator
+ * array.index(object) -> integer or nil
+ * array.index {|element| ... } -> integer or nil
+ * array.index -> new_enumerator
*
- * Returns the zero-based integer index of a specified element, or +nil+.
+ * Returns the index of a specified element.
*
- * With only argument +object+ given,
+ * When argument +object+ is given but no block,
* returns the index of the first element +element+
* for which <tt>object == element</tt>:
*
@@ -2084,7 +2207,7 @@ rb_ary_fetch(int argc, VALUE *argv, VALUE ary)
*
* Returns +nil+ if no such element found.
*
- * With only a block given,
+ * When both argument +object+ and a block are given,
* calls the block with each successive element;
* returns the index of the first element for which the block returns a truthy value:
*
@@ -2093,9 +2216,16 @@ rb_ary_fetch(int argc, VALUE *argv, VALUE ary)
*
* Returns +nil+ if the block never returns a truthy value.
*
- * With neither an argument nor a block given, returns a new Enumerator.
+ * When neither an argument nor a block is given, returns a new Enumerator:
+ *
+ * a = [:foo, 'bar', 2]
+ * e = a.index
+ * e # => #<Enumerator: [:foo, "bar", 2]:index>
+ * e.each {|element| element == 'bar' } # => 1
*
- * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
+ * Array#find_index is an alias for Array#index.
+ *
+ * Related: #rindex.
*/
static VALUE
@@ -2149,7 +2279,7 @@ rb_ary_index(int argc, VALUE *argv, VALUE ary)
*
* Returns +nil+ if the block never returns a truthy value.
*
- * When neither an argument nor a block is given, returns a new Enumerator:
+ * When neither an argument nor a block is given, returns a new \Enumerator:
*
* a = [:foo, 'bar', 2, 'bar']
* e = a.rindex
@@ -2221,7 +2351,7 @@ rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen)
}
{
- const VALUE *optr = RARRAY_CONST_PTR(ary);
+ const VALUE *optr = RARRAY_CONST_PTR_TRANSIENT(ary);
rofs = (rptr >= optr && rptr < optr + olen) ? rptr - optr : -1;
}
@@ -2234,7 +2364,7 @@ rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen)
len = beg + rlen;
ary_mem_clear(ary, olen, beg - olen);
if (rlen > 0) {
- if (rofs != -1) rptr = RARRAY_CONST_PTR(ary) + rofs;
+ if (rofs != -1) rptr = RARRAY_CONST_PTR_TRANSIENT(ary) + rofs;
ary_memcpy0(ary, beg, rlen, rptr, target_ary);
}
ARY_SET_LEN(ary, len);
@@ -2252,25 +2382,20 @@ rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen)
}
if (len != rlen) {
- RARRAY_PTR_USE(ary, ptr,
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr,
MEMMOVE(ptr + beg + rlen, ptr + beg + len,
VALUE, olen - (beg + len)));
ARY_SET_LEN(ary, alen);
}
if (rlen > 0) {
- if (rofs == -1) {
- rb_gc_writebarrier_remember(ary);
- }
- else {
- /* In this case, we're copying from a region in this array, so
- * we don't need to fire the write barrier. */
- rptr = RARRAY_CONST_PTR(ary) + rofs;
- }
+ if (rofs != -1) rptr = RARRAY_CONST_PTR_TRANSIENT(ary) + rofs;
+ /* give up wb-protected ary */
+ RB_OBJ_WB_UNPROTECT_FOR(ARRAY, ary);
/* do not use RARRAY_PTR() because it can causes GC.
* ary can contain T_NONE object because it is not cleared.
*/
- RARRAY_PTR_USE(ary, ptr,
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr,
MEMMOVE(ptr + beg, rptr, VALUE, rlen));
}
}
@@ -2315,8 +2440,9 @@ rb_ary_resize(VALUE ary, long len)
else if (len <= ary_embed_capa(ary)) {
const VALUE *ptr = ARY_HEAP_PTR(ary);
long ptr_capa = ARY_HEAP_SIZE(ary);
- bool is_malloc_ptr = !ARY_SHARED_P(ary);
+ bool is_malloc_ptr = !ARY_SHARED_P(ary) && !RARRAY_TRANSIENT_P(ary);
+ FL_UNSET(ary, RARRAY_TRANSIENT_FLAG);
FL_SET_EMBED(ary);
MEMCPY((VALUE *)ARY_EMBED_PTR(ary), ptr, VALUE, len); /* WB: no new reference */
@@ -2346,48 +2472,20 @@ static VALUE
ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val)
{
VALUE rpl = rb_ary_to_ary(val);
- rb_ary_splice(ary, beg, len, RARRAY_CONST_PTR(rpl), RARRAY_LEN(rpl));
+ rb_ary_splice(ary, beg, len, RARRAY_CONST_PTR_TRANSIENT(rpl), RARRAY_LEN(rpl));
RB_GC_GUARD(rpl);
return val;
}
/*
* call-seq:
- * self[index] = object -> object
- * self[start, length] = object -> object
- * self[range] = object -> object
- *
- * Assigns elements in +self+, based on the given +object+; returns +object+.
- *
- * In brief:
- *
- * a_orig = [:foo, 'bar', 2]
- *
- * # With argument index.
- * a = a_orig.dup
- * a[0] = 'foo' # => "foo"
- * a # => ["foo", "bar", 2]
- * a = a_orig.dup
- * a[7] = 'foo' # => "foo"
- * a # => [:foo, "bar", 2, nil, nil, nil, nil, "foo"]
- *
- * # With arguments start and length.
- * a = a_orig.dup
- * a[0, 2] = 'foo' # => "foo"
- * a # => ["foo", 2]
- * a = a_orig.dup
- * a[6, 50] = 'foo' # => "foo"
- * a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
- *
- * # With argument range.
- * a = a_orig.dup
- * a[0..1] = 'foo' # => "foo"
- * a # => ["foo", 2]
- * a = a_orig.dup
- * a[6..50] = 'foo' # => "foo"
- * a # => [:foo, "bar", 2, nil, nil, nil, "foo"]
- *
- * When Integer argument +index+ is given, assigns +object+ to an element in +self+.
+ * array[index] = object -> object
+ * array[start, length] = object -> object
+ * array[range] = object -> object
+ *
+ * Assigns elements in +self+; returns the given +object+.
+ *
+ * When \Integer argument +index+ is given, assigns +object+ to an element in +self+.
*
* If +index+ is non-negative, assigns +object+ the element at offset +index+:
*
@@ -2407,7 +2505,7 @@ ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val)
* a[-1] = 'two' # => "two"
* a # => [:foo, "bar", "two"]
*
- * When Integer arguments +start+ and +length+ are given and +object+ is not an +Array+,
+ * When \Integer arguments +start+ and +length+ are given and +object+ is not an \Array,
* removes <tt>length - 1</tt> elements beginning at offset +start+,
* and assigns +object+ at offset +start+:
*
@@ -2442,7 +2540,7 @@ ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val)
* a[1, 5] = 'foo' # => "foo"
* a # => [:foo, "foo"]
*
- * When Range argument +range+ is given and +object+ is not an +Array+,
+ * When \Range argument +range+ is given and +object+ is an \Array,
* removes <tt>length - 1</tt> elements beginning at offset +start+,
* and assigns +object+ at offset +start+:
*
@@ -2457,8 +2555,7 @@ ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val)
* a # => [:foo, "foo"]
*
* If the array length is less than <tt>range.begin</tt>,
- * extends the array with +nil+, assigns +object+ at offset <tt>range.begin</tt>,
- * and ignores +length+:
+ * assigns +object+ at offset <tt>range.begin</tt>, and ignores +length+:
*
* a = [:foo, 'bar', 2]
* a[6..50] = 'foo' # => "foo"
@@ -2492,7 +2589,6 @@ ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val)
* a[1..5] = 'foo' # => "foo"
* a # => [:foo, "foo"]
*
- * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning].
*/
static VALUE
@@ -2522,38 +2618,38 @@ rb_ary_aset(int argc, VALUE *argv, VALUE ary)
/*
* call-seq:
- * insert(index, *objects) -> self
+ * array.insert(index, *objects) -> self
*
- * Inserts the given +objects+ as elements of +self+;
+ * Inserts given +objects+ before or after the element at \Integer index +offset+;
* returns +self+.
*
- * When +index+ is non-negative, inserts +objects+
- * _before_ the element at offset +index+:
+ * When +index+ is non-negative, inserts all given +objects+
+ * before the element at offset +index+:
*
- * a = ['a', 'b', 'c'] # => ["a", "b", "c"]
- * a.insert(1, :x, :y, :z) # => ["a", :x, :y, :z, "b", "c"]
+ * a = [:foo, 'bar', 2]
+ * a.insert(1, :bat, :bam) # => [:foo, :bat, :bam, "bar", 2]
*
* Extends the array if +index+ is beyond the array (<tt>index >= self.size</tt>):
*
- * a = ['a', 'b', 'c'] # => ["a", "b", "c"]
- * a.insert(5, :x, :y, :z) # => ["a", "b", "c", nil, nil, :x, :y, :z]
- *
- * When +index+ is negative, inserts +objects+
- * _after_ the element at offset <tt>index + self.size</tt>:
+ * a = [:foo, 'bar', 2]
+ * a.insert(5, :bat, :bam)
+ * a # => [:foo, "bar", 2, nil, nil, :bat, :bam]
*
- * a = ['a', 'b', 'c'] # => ["a", "b", "c"]
- * a.insert(-2, :x, :y, :z) # => ["a", "b", :x, :y, :z, "c"]
+ * Does nothing if no objects given:
*
- * With no +objects+ given, does nothing:
+ * a = [:foo, 'bar', 2]
+ * a.insert(1)
+ * a.insert(50)
+ * a.insert(-50)
+ * a # => [:foo, "bar", 2]
*
- * a = ['a', 'b', 'c'] # => ["a", "b", "c"]
- * a.insert(1) # => ["a", "b", "c"]
- * a.insert(50) # => ["a", "b", "c"]
- * a.insert(-50) # => ["a", "b", "c"]
+ * When +index+ is negative, inserts all given +objects+
+ * _after_ the element at offset <tt>index+self.size</tt>:
*
- * Raises IndexError if +objects+ are given and +index+ is negative and out of range.
+ * a = [:foo, 'bar', 2]
+ * a.insert(-2, :bat, :bam)
+ * a # => [:foo, "bar", :bat, :bam, 2]
*
- * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning].
*/
static VALUE
@@ -2589,19 +2685,50 @@ ary_enum_length(VALUE ary, VALUE args, VALUE eobj)
return rb_ary_length(ary);
}
-// Primitive to avoid a race condition in Array#each.
-// Return `true` and write `value` and `index` if the element exists.
-static VALUE
-ary_fetch_next(VALUE self, VALUE *index, VALUE *value)
-{
- long i = NUM2LONG(*index);
- if (i >= RARRAY_LEN(self)) {
- return Qfalse;
- }
- *value = RARRAY_AREF(self, i);
- *index = LONG2NUM(i + 1);
- return Qtrue;
-}
+/*
+ * call-seq:
+ * array.each {|element| ... } -> self
+ * array.each -> Enumerator
+ *
+ * Iterates over array elements.
+ *
+ * When a block given, passes each successive array element to the block;
+ * returns +self+:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.each {|element| puts "#{element.class} #{element}" }
+ *
+ * Output:
+ *
+ * Symbol foo
+ * String bar
+ * Integer 2
+ *
+ * Allows the array to be modified during iteration:
+ *
+ * a = [:foo, 'bar', 2]
+ * a.each {|element| puts element; a.clear if element.to_s.start_with?('b') }
+ *
+ * Output:
+ *
+ * foo
+ * bar
+ *
+ * When no block given, returns a new \Enumerator:
+ * a = [:foo, 'bar', 2]
+ *
+ * e = a.each
+ * e # => #<Enumerator: [:foo, "bar", 2]:each>
+ * a1 = e.each {|element| puts "#{element.class} #{element}" }
+ *
+ * Output:
+ *
+ * Symbol foo
+ * String bar
+ * Integer 2
+ *
+ * Related: #each_index, #reverse_each.
+ */
VALUE
rb_ary_each(VALUE ary)
@@ -2617,11 +2744,12 @@ rb_ary_each(VALUE ary)
/*
* call-seq:
- * each_index {|index| ... } -> self
- * each_index -> new_enumerator
+ * array.each_index {|index| ... } -> self
+ * array.each_index -> Enumerator
*
- * With a block given, iterates over the elements of +self+,
- * passing each <i>array index</i> to the block;
+ * Iterates over array indexes.
+ *
+ * When a block given, passes each successive array index to the block;
* returns +self+:
*
* a = [:foo, 'bar', 2]
@@ -2643,9 +2771,20 @@ rb_ary_each(VALUE ary)
* 0
* 1
*
- * With no block given, returns a new Enumerator.
+ * When no block given, returns a new \Enumerator:
+ *
+ * a = [:foo, 'bar', 2]
+ * e = a.each_index
+ * e # => #<Enumerator: [:foo, "bar", 2]:each_index>
+ * a1 = e.each {|index| puts "#{index} #{a[index]}"}
+ *
+ * Output:
*
- * Related: see {Methods for Iterating}[rdoc-ref:Array@Methods+for+Iterating].
+ * 0 foo
+ * 1 bar
+ * 2 2
+ *
+ * Related: #each, #reverse_each.
*/
static VALUE
@@ -2689,7 +2828,7 @@ rb_ary_each_index(VALUE ary)
* 2
* bar
*
- * When no block given, returns a new Enumerator:
+ * When no block given, returns a new \Enumerator:
*
* a = [:foo, 'bar', 2]
* e = a.reverse_each
@@ -2725,15 +2864,9 @@ rb_ary_reverse_each(VALUE ary)
/*
* call-seq:
- * length -> integer
- * size -> integer
+ * array.length -> an_integer
*
- * Returns the count of elements in +self+:
- *
- * [0, 1, 2].length # => 3
- * [].length # => 0
- *
- * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
+ * Returns the count of elements in +self+.
*/
static VALUE
@@ -2749,8 +2882,6 @@ rb_ary_length(VALUE ary)
*
* Returns +true+ if the count of elements in +self+ is zero,
* +false+ otherwise.
- *
- * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
*/
static VALUE
@@ -2764,7 +2895,7 @@ rb_ary_dup(VALUE ary)
{
long len = RARRAY_LEN(ary);
VALUE dup = rb_ary_new2(len);
- ary_memcpy(dup, 0, len, RARRAY_CONST_PTR(ary));
+ ary_memcpy(dup, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary));
ARY_SET_LEN(dup, len);
ary_verify(ary);
@@ -2914,32 +3045,31 @@ rb_ary_join(VALUE ary, VALUE sep)
/*
* call-seq:
+ * array.join ->new_string
* array.join(separator = $,) -> new_string
*
- * Returns the new string formed by joining the converted elements of +self+;
- * for each element +element+:
+ * Returns the new \String formed by joining the array elements after conversion.
+ * For each element +element+:
*
- * - Converts recursively using <tt>element.join(separator)</tt>
- * if +element+ is a <tt>kind_of?(Array)</tt>.
- * - Otherwise, converts using <tt>element.to_s</tt>.
+ * - Uses <tt>element.to_s</tt> if +element+ is not a <tt>kind_of?(Array)</tt>.
+ * - Uses recursive <tt>element.join(separator)</tt> if +element+ is a <tt>kind_of?(Array)</tt>.
*
- * With no argument given, joins using the output field separator, <tt>$,</tt>:
+ * With no argument, joins using the output field separator, <tt>$,</tt>:
*
* a = [:foo, 'bar', 2]
* $, # => nil
* a.join # => "foobar2"
*
- * With string argument +separator+ given, joins using that separator:
+ * With \string argument +separator+, joins using that separator:
*
* a = [:foo, 'bar', 2]
* a.join("\n") # => "foo\nbar\n2"
*
- * Joins recursively for nested arrays:
+ * Joins recursively for nested Arrays:
*
* a = [:foo, [:bar, [:baz, :bat]]]
* a.join # => "foobarbazbat"
*
- * Related: see {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting].
*/
static VALUE
rb_ary_join_m(int argc, VALUE *argv, VALUE ary)
@@ -2976,15 +3106,15 @@ inspect_ary(VALUE ary, VALUE dummy, int recur)
/*
* call-seq:
- * inspect -> new_string
+ * array.inspect -> new_string
*
- * Returns the new string formed by calling method <tt>#inspect</tt>
+ * Returns the new \String formed by calling method <tt>#inspect</tt>
* on each array element:
*
* a = [:foo, 'bar', 2]
* a.inspect # => "[:foo, \"bar\", 2]"
*
- * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
+ * Array#to_s is an alias for Array#inspect.
*/
static VALUE
@@ -3004,12 +3134,12 @@ rb_ary_to_s(VALUE ary)
* call-seq:
* to_a -> self or new_array
*
- * When +self+ is an instance of +Array+, returns +self+:
+ * When +self+ is an instance of \Array, returns +self+:
*
* a = [:foo, 'bar', 2]
* a.to_a # => [:foo, "bar", 2]
*
- * Otherwise, returns a new +Array+ containing the elements of +self+:
+ * Otherwise, returns a new \Array containing the elements of +self+:
*
* class MyArray < Array; end
* a = MyArray.new(['foo', 'bar', 'two'])
@@ -3037,18 +3167,18 @@ rb_ary_to_a(VALUE ary)
* array.to_h -> new_hash
* array.to_h {|item| ... } -> new_hash
*
- * Returns a new Hash formed from +self+.
+ * Returns a new \Hash formed from +self+.
*
* When a block is given, calls the block with each array element;
- * the block must return a 2-element +Array+ whose two elements
- * form a key-value pair in the returned Hash:
+ * the block must return a 2-element \Array whose two elements
+ * form a key-value pair in the returned \Hash:
*
* a = ['foo', :bar, 1, [2, 3], {baz: 4}]
* h = a.to_h {|item| [item, item] }
* h # => {"foo"=>"foo", :bar=>:bar, 1=>1, [2, 3]=>[2, 3], {:baz=>4}=>{:baz=>4}}
*
- * When no block is given, +self+ must be an +Array+ of 2-element sub-arrays,
- * each sub-array is formed into a key-value pair in the new Hash:
+ * When no block is given, +self+ must be an \Array of 2-element sub-arrays,
+ * each sub-array is formed into a key-value pair in the new \Hash:
*
* [].to_h # => {}
* a = [['foo', 'zero'], ['bar', 'one'], ['baz', 'two']]
@@ -3112,7 +3242,7 @@ rb_ary_reverse(VALUE ary)
rb_ary_modify(ary);
if (len > 1) {
- RARRAY_PTR_USE(ary, p1, {
+ RARRAY_PTR_USE_TRANSIENT(ary, p1, {
p2 = p1 + len - 1; /* points last item */
ary_reverse(p1, p2);
}); /* WB: no new reference */
@@ -3141,7 +3271,7 @@ rb_ary_reverse_bang(VALUE ary)
* call-seq:
* array.reverse -> new_array
*
- * Returns a new +Array+ with the elements of +self+ in reverse order:
+ * Returns a new \Array with the elements of +self+ in reverse order:
*
* a = ['foo', 'bar', 'two']
* a1 = a.reverse
@@ -3156,8 +3286,8 @@ rb_ary_reverse_m(VALUE ary)
VALUE dup = rb_ary_new2(len);
if (len > 0) {
- const VALUE *p1 = RARRAY_CONST_PTR(ary);
- VALUE *p2 = (VALUE *)RARRAY_CONST_PTR(dup) + len - 1;
+ const VALUE *p1 = RARRAY_CONST_PTR_TRANSIENT(ary);
+ VALUE *p2 = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(dup) + len - 1;
do *p2-- = *p1++; while (--len > 0);
}
ARY_SET_LEN(dup, RARRAY_LEN(ary));
@@ -3199,7 +3329,7 @@ rb_ary_rotate(VALUE ary, long cnt)
if (cnt != 0) {
long len = RARRAY_LEN(ary);
if (len > 1 && (cnt = rotate_count(cnt, len)) > 0) {
- RARRAY_PTR_USE(ary, ptr, ary_rotate_ptr(ptr, len, cnt));
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, ary_rotate_ptr(ptr, len, cnt));
return ary;
}
}
@@ -3218,7 +3348,7 @@ rb_ary_rotate(VALUE ary, long cnt)
* a = [:foo, 'bar', 2, 'bar']
* a.rotate! # => ["bar", 2, "bar", :foo]
*
- * When given a non-negative Integer +count+,
+ * When given a non-negative \Integer +count+,
* rotates +count+ elements from the beginning to the end:
*
* a = [:foo, 'bar', 2]
@@ -3265,18 +3395,18 @@ rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary)
* array.rotate -> new_array
* array.rotate(count) -> new_array
*
- * Returns a new +Array+ formed from +self+ with elements
+ * Returns a new \Array formed from +self+ with elements
* rotated from one end to the other.
*
- * When no argument given, returns a new +Array+ that is like +self+,
+ * When no argument given, returns a new \Array that is like +self+,
* except that the first element has been rotated to the last position:
*
* a = [:foo, 'bar', 2, 'bar']
* a1 = a.rotate
* a1 # => ["bar", 2, "bar", :foo]
*
- * When given a non-negative Integer +count+,
- * returns a new +Array+ with +count+ elements rotated from the beginning to the end:
+ * When given a non-negative \Integer +count+,
+ * returns a new \Array with +count+ elements rotated from the beginning to the end:
*
* a = [:foo, 'bar', 2]
* a1 = a.rotate(2)
@@ -3294,7 +3424,7 @@ rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary)
* a1 = a.rotate(0)
* a1 # => [:foo, "bar", 2]
*
- * When given a negative Integer +count+, rotates in the opposite direction,
+ * When given a negative \Integer +count+, rotates in the opposite direction,
* from end to beginning:
*
* a = [:foo, 'bar', 2]
@@ -3321,7 +3451,7 @@ rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary)
rotated = rb_ary_new2(len);
if (len > 0) {
cnt = rotate_count(cnt, len);
- ptr = RARRAY_CONST_PTR(ary);
+ ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
len -= cnt;
ary_memcpy(rotated, 0, len, ptr + cnt);
ary_memcpy(rotated, len, cnt, ptr);
@@ -3404,7 +3534,7 @@ sort_2(const void *ap, const void *bp, void *dummy)
*
* Returns +self+ with its elements sorted in place.
*
- * With no block, compares elements using operator <tt>#<=></tt>
+ * With no block, compares elements using operator <tt><=></tt>
* (see Comparable):
*
* a = 'abcde'.split('').shuffle
@@ -3442,7 +3572,7 @@ VALUE
rb_ary_sort_bang(VALUE ary)
{
rb_ary_modify(ary);
- RUBY_ASSERT(!ARY_SHARED_P(ary));
+ assert(!ARY_SHARED_P(ary));
if (RARRAY_LEN(ary) > 1) {
VALUE tmp = ary_make_substitution(ary); /* only ary refers tmp */
struct ary_sort_data data;
@@ -3460,9 +3590,6 @@ rb_ary_sort_bang(VALUE ary)
rb_ary_unshare(ary);
FL_SET_EMBED(ary);
}
- if (ARY_EMBED_LEN(tmp) > ARY_CAPA(ary)) {
- ary_resize_capa(ary, ARY_EMBED_LEN(tmp));
- }
ary_memcpy(ary, 0, ARY_EMBED_LEN(tmp), ARY_EMBED_PTR(tmp));
ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp));
}
@@ -3472,7 +3599,7 @@ rb_ary_sort_bang(VALUE ary)
ARY_SET_CAPA(ary, RARRAY_LEN(tmp));
}
else {
- RUBY_ASSERT(!ARY_SHARED_P(tmp));
+ assert(!ARY_SHARED_P(tmp));
if (ARY_EMBED_P(ary)) {
FL_UNSET_EMBED(ary);
}
@@ -3505,9 +3632,9 @@ rb_ary_sort_bang(VALUE ary)
* array.sort -> new_array
* array.sort {|a, b| ... } -> new_array
*
- * Returns a new +Array+ whose elements are those from +self+, sorted.
+ * Returns a new \Array whose elements are those from +self+, sorted.
*
- * With no block, compares elements using operator <tt>#<=></tt>
+ * With no block, compares elements using operator <tt><=></tt>
* (see Comparable):
*
* a = 'abcde'.split('').shuffle
@@ -3554,15 +3681,12 @@ static VALUE rb_ary_bsearch_index(VALUE ary);
/*
* call-seq:
- * bsearch {|element| ... } -> found_element or nil
- * bsearch -> new_enumerator
+ * array.bsearch {|element| ... } -> object
+ * array.bsearch -> new_enumerator
*
- * Returns the element from +self+ found by a binary search,
- * or +nil+ if the search found no suitable element.
+ * Returns an element from +self+ selected by a binary search.
*
* See {Binary Searching}[rdoc-ref:bsearch.rdoc].
- *
- * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
*/
static VALUE
@@ -3578,15 +3702,11 @@ rb_ary_bsearch(VALUE ary)
/*
* call-seq:
- * bsearch_index {|element| ... } -> integer or nil
- * bsearch_index -> new_enumerator
- *
- * Returns the integer index of the element from +self+ found by a binary search,
- * or +nil+ if the search found no suitable element.
- *
- * See {Binary Searching}[rdoc-ref:bsearch.rdoc].
+ * array.bsearch_index {|element| ... } -> integer or nil
+ * array.bsearch_index -> new_enumerator
*
- * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
+ * Searches +self+ as described at method #bsearch,
+ * but returns the _index_ of the found element instead of the element itself.
*/
static VALUE
@@ -3662,7 +3782,7 @@ sort_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, dummy))
* a.sort_by! {|element| element.size }
* a # => ["d", "cc", "bbb", "aaaa"]
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = ['aaaa', 'bbb', 'cc', 'd']
* a.sort_by! # => #<Enumerator: ["aaaa", "bbb", "cc", "d"]:sort_by!>
@@ -3684,22 +3804,22 @@ rb_ary_sort_by_bang(VALUE ary)
/*
* call-seq:
- * collect {|element| ... } -> new_array
- * collect -> new_enumerator
- * map {|element| ... } -> new_array
- * map -> new_enumerator
+ * array.map {|element| ... } -> new_array
+ * array.map -> new_enumerator
*
- * With a block given, calls the block with each element of +self+;
- * returns a new array whose elements are the return values from the block:
+ * Calls the block, if given, with each element of +self+;
+ * returns a new \Array whose elements are the return values from the block:
*
* a = [:foo, 'bar', 2]
* a1 = a.map {|element| element.class }
* a1 # => [Symbol, String, Integer]
*
- * With no block given, returns a new Enumerator.
+ * Returns a new \Enumerator if no block given:
+ * a = [:foo, 'bar', 2]
+ * a1 = a.map
+ * a1 # => #<Enumerator: [:foo, "bar", 2]:map>
*
- * Related: #collect!;
- * see also {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting].
+ * Array#collect is an alias for Array#map.
*/
static VALUE
@@ -3719,22 +3839,22 @@ rb_ary_collect(VALUE ary)
/*
* call-seq:
- * collect! {|element| ... } -> new_array
- * collect! -> new_enumerator
- * map! {|element| ... } -> new_array
- * map! -> new_enumerator
+ * array.map! {|element| ... } -> self
+ * array.map! -> new_enumerator
*
- * With a block given, calls the block with each element of +self+
- * and replaces the element with the block's return value;
- * returns +self+:
+ * Calls the block, if given, with each element;
+ * replaces the element with the block's return value:
*
* a = [:foo, 'bar', 2]
* a.map! { |element| element.class } # => [Symbol, String, Integer]
*
- * With no block given, returns a new Enumerator.
+ * Returns a new \Enumerator if no block given:
+ *
+ * a = [:foo, 'bar', 2]
+ * a1 = a.map!
+ * a1 # => #<Enumerator: [:foo, "bar", 2]:map!>
*
- * Related: #collect;
- * see also {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting].
+ * Array#collect! is an alias for Array#map!.
*/
static VALUE
@@ -3786,7 +3906,7 @@ append_values_at_single(VALUE result, VALUE ary, long olen, VALUE idx)
/* check if idx is Range */
else if (rb_range_beg_len(idx, &beg, &len, olen, 1)) {
if (len > 0) {
- const VALUE *const src = RARRAY_CONST_PTR(ary);
+ const VALUE *const src = RARRAY_CONST_PTR_TRANSIENT(ary);
const long end = beg + len;
const long prevlen = RARRAY_LEN(result);
if (beg < olen) {
@@ -3808,8 +3928,8 @@ append_values_at_single(VALUE result, VALUE ary, long olen, VALUE idx)
* call-seq:
* array.values_at(*indexes) -> new_array
*
- * Returns a new +Array+ whose elements are the elements
- * of +self+ at the given Integer or Range +indexes+.
+ * Returns a new \Array whose elements are the elements
+ * of +self+ at the given \Integer or \Range +indexes+.
*
* For each positive +index+, returns the element at offset +index+:
*
@@ -3828,7 +3948,7 @@ append_values_at_single(VALUE result, VALUE ary, long olen, VALUE idx)
* a = [:foo, 'bar', 2]
* a.values_at(0, 3, 1, 3) # => [:foo, nil, "bar", nil]
*
- * Returns a new empty +Array+ if no arguments given.
+ * Returns a new empty \Array if no arguments given.
*
* For each negative +index+, counts backward from the end of the array:
*
@@ -3862,22 +3982,23 @@ rb_ary_values_at(int argc, VALUE *argv, VALUE ary)
/*
* call-seq:
- * select {|element| ... } -> new_array
- * select -> new_enumerator
- * filter {|element| ... } -> new_array
- * filter -> new_enumerator
+ * array.select {|element| ... } -> new_array
+ * array.select -> new_enumerator
*
- * With a block given, calls the block with each element of +self+;
- * returns a new array containing those elements of +self+
+ * Calls the block, if given, with each element of +self+;
+ * returns a new \Array containing those elements of +self+
* for which the block returns a truthy value:
*
* a = [:foo, 'bar', 2, :bam]
- * a.select {|element| element.to_s.start_with?('b') }
- * # => ["bar", :bam]
+ * a1 = a.select {|element| element.to_s.start_with?('b') }
+ * a1 # => ["bar", :bam]
*
- * With no block given, returns a new Enumerator.
+ * Returns a new \Enumerator if no block given:
*
- * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
+ * a = [:foo, 'bar', 2, :bam]
+ * a.select # => #<Enumerator: [:foo, "bar", 2, :bam]:select>
+ *
+ * Array#filter is an alias for Array#select.
*/
static VALUE
@@ -3932,7 +4053,7 @@ select_bang_ensure(VALUE a)
rb_ary_modify(ary);
if (i1 < len) {
tail = len - i1;
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
MEMMOVE(ptr + i2, ptr + i1, VALUE, tail);
});
}
@@ -3943,12 +4064,10 @@ select_bang_ensure(VALUE a)
/*
* call-seq:
- * select! {|element| ... } -> self or nil
- * select! -> new_enumerator
- * filter! {|element| ... } -> self or nil
- * filter! -> new_enumerator
+ * array.select! {|element| ... } -> self or nil
+ * array.select! -> new_enumerator
*
- * With a block given, calls the block with each element of +self+;
+ * Calls the block, if given with each element of +self+;
* removes from +self+ those elements for which the block returns +false+ or +nil+.
*
* Returns +self+ if any elements were removed:
@@ -3958,9 +4077,12 @@ select_bang_ensure(VALUE a)
*
* Returns +nil+ if no elements were removed.
*
- * With no block given, returns a new Enumerator.
+ * Returns a new \Enumerator if no block given:
+ *
+ * a = [:foo, 'bar', 2, :bam]
+ * a.select! # => #<Enumerator: [:foo, "bar", 2, :bam]:select!>
*
- * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
+ * Array#filter! is an alias for Array#select!.
*/
static VALUE
@@ -3978,18 +4100,20 @@ rb_ary_select_bang(VALUE ary)
/*
* call-seq:
- * keep_if {|element| ... } -> self
- * keep_if -> new_enumerator
+ * array.keep_if {|element| ... } -> self
+ * array.keep_if -> new_enumeration
*
- * With a block given, calls the block with each element of +self+;
- * removes the element from +self+ if the block does not return a truthy value:
+ * Retains those elements for which the block returns a truthy value;
+ * deletes all other elements; returns +self+:
*
* a = [:foo, 'bar', 2, :bam]
* a.keep_if {|element| element.to_s.start_with?('b') } # => ["bar", :bam]
*
- * With no block given, returns a new Enumerator.
+ * Returns a new \Enumerator if no block given:
+ *
+ * a = [:foo, 'bar', 2, :bam]
+ * a.keep_if # => #<Enumerator: [:foo, "bar", 2, :bam]:keep_if>
*
- * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
*/
static VALUE
@@ -4015,39 +4139,38 @@ ary_resize_smaller(VALUE ary, long len)
/*
* call-seq:
- * delete(object) -> last_removed_object
- * delete(object) {|element| ... } -> last_removed_object or block_return
+ * array.delete(obj) -> deleted_object
+ * array.delete(obj) {|nosuch| ... } -> deleted_object or block_return
*
* Removes zero or more elements from +self+.
*
- * With no block given,
- * removes from +self+ each element +ele+ such that <tt>ele == object</tt>;
- * returns the last removed element:
- *
- * a = [0, 1, 2, 2.0]
- * a.delete(2) # => 2.0
- * a # => [0, 1]
+ * When no block is given,
+ * removes from +self+ each element +ele+ such that <tt>ele == obj</tt>;
+ * returns the last deleted element:
*
- * Returns +nil+ if no elements removed:
+ * s1 = 'bar'; s2 = 'bar'
+ * a = [:foo, s1, 2, s2]
+ * a.delete('bar') # => "bar"
+ * a # => [:foo, 2]
*
- * a.delete(2) # => nil
+ * Returns +nil+ if no elements removed.
*
- * With a block given,
- * removes from +self+ each element +ele+ such that <tt>ele == object</tt>.
+ * When a block is given,
+ * removes from +self+ each element +ele+ such that <tt>ele == obj</tt>.
*
* If any such elements are found, ignores the block
- * and returns the last removed element:
+ * and returns the last deleted element:
*
- * a = [0, 1, 2, 2.0]
- * a.delete(2) {|element| fail 'Cannot happen' } # => 2.0
- * a # => [0, 1]
+ * s1 = 'bar'; s2 = 'bar'
+ * a = [:foo, s1, 2, s2]
+ * deleted_obj = a.delete('bar') {|obj| fail 'Cannot happen' }
+ * a # => [:foo, 2]
*
- * If no such element is found, returns the block's return value:
+ * If no such elements are found, returns the block's return value:
*
- * a.delete(2) {|element| "Element #{element} not found." }
- * # => "Element 2 not found."
+ * a = [:foo, 'bar', 2]
+ * a.delete(:nosuch) {|obj| "#{obj} not found" } # => "nosuch not found"
*
- * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
*/
VALUE
@@ -4118,7 +4241,7 @@ rb_ary_delete_at(VALUE ary, long pos)
rb_ary_modify(ary);
del = RARRAY_AREF(ary, pos);
- RARRAY_PTR_USE(ary, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr, {
MEMMOVE(ptr+pos, ptr+pos+1, VALUE, len-pos-1);
});
ARY_INCREASE_LEN(ary, -1);
@@ -4128,10 +4251,9 @@ rb_ary_delete_at(VALUE ary, long pos)
/*
* call-seq:
- * delete_at(index) -> removed_object or nil
+ * array.delete_at(index) -> deleted_object or nil
*
- * Removes the element of +self+ at the given +index+, which must be an
- * {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects].
+ * Deletes an element from +self+, per the given \Integer +index+.
*
* When +index+ is non-negative, deletes the element at offset +index+:
*
@@ -4139,19 +4261,15 @@ rb_ary_delete_at(VALUE ary, long pos)
* a.delete_at(1) # => "bar"
* a # => [:foo, 2]
*
+ * If index is too large, returns +nil+.
+ *
* When +index+ is negative, counts backward from the end of the array:
*
* a = [:foo, 'bar', 2]
* a.delete_at(-2) # => "bar"
* a # => [:foo, 2]
*
- * When +index+ is out of range, returns +nil+.
- *
- * a = [:foo, 'bar', 2]
- * a.delete_at(3) # => nil
- * a.delete_at(-4) # => nil
- *
- * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
+ * If +index+ is too small (far from zero), returns nil.
*/
static VALUE
@@ -4184,7 +4302,7 @@ ary_slice_bang_by_rb_ary_splice(VALUE ary, long pos, long len)
return rb_ary_new2(0);
}
else {
- VALUE arg2 = rb_ary_new4(len, RARRAY_CONST_PTR(ary)+pos);
+ VALUE arg2 = rb_ary_new4(len, RARRAY_CONST_PTR_TRANSIENT(ary)+pos);
rb_ary_splice(ary, pos, len, 0, 0);
return arg2;
}
@@ -4198,7 +4316,7 @@ ary_slice_bang_by_rb_ary_splice(VALUE ary, long pos, long len)
*
* Removes and returns elements from +self+.
*
- * When the only argument is an Integer +n+,
+ * When the only argument is an \Integer +n+,
* removes and returns the _nth_ element in +self+:
*
* a = [:foo, 'bar', 2]
@@ -4215,7 +4333,7 @@ ary_slice_bang_by_rb_ary_splice(VALUE ary, long pos, long len)
*
* When the only arguments are Integers +start+ and +length+,
* removes +length+ elements from +self+ beginning at offset +start+;
- * returns the deleted objects in a new +Array+:
+ * returns the deleted objects in a new \Array:
*
* a = [:foo, 'bar', 2]
* a.slice!(0, 2) # => [:foo, "bar"]
@@ -4229,18 +4347,18 @@ ary_slice_bang_by_rb_ary_splice(VALUE ary, long pos, long len)
* a # => [:foo]
*
* If <tt>start == a.size</tt> and +length+ is non-negative,
- * returns a new empty +Array+.
+ * returns a new empty \Array.
*
* If +length+ is negative, returns +nil+.
*
- * When the only argument is a Range object +range+,
+ * When the only argument is a \Range object +range+,
* treats <tt>range.min</tt> as +start+ above and <tt>range.size</tt> as +length+ above:
*
* a = [:foo, 'bar', 2]
* a.slice!(1..2) # => ["bar", 2]
* a # => [:foo]
*
- * If <tt>range.start == a.size</tt>, returns a new empty +Array+.
+ * If <tt>range.start == a.size</tt>, returns a new empty \Array.
*
* If <tt>range.start</tt> is larger than the array size, returns +nil+.
*
@@ -4349,7 +4467,7 @@ ary_reject_bang(VALUE ary)
*
* Returns +nil+ if no elements removed.
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [:foo, 'bar', 2]
* a.reject! # => #<Enumerator: [:foo, "bar", 2]:reject!>
@@ -4369,14 +4487,14 @@ rb_ary_reject_bang(VALUE ary)
* array.reject {|element| ... } -> new_array
* array.reject -> new_enumerator
*
- * Returns a new +Array+ whose elements are all those from +self+
+ * Returns a new \Array whose elements are all those from +self+
* for which the block returns +false+ or +nil+:
*
* a = [:foo, 'bar', 2, 'bat']
* a1 = a.reject {|element| element.to_s.start_with?('b') }
* a1 # => [:foo, 2]
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [:foo, 'bar', 2]
* a.reject # => #<Enumerator: [:foo, "bar", 2]:reject>
@@ -4396,20 +4514,21 @@ rb_ary_reject(VALUE ary)
/*
* call-seq:
- * delete_if {|element| ... } -> self
- * delete_if -> new_numerator
+ * array.delete_if {|element| ... } -> self
+ * array.delete_if -> Enumerator
*
- * With a block given, calls the block with each element of +self+;
- * removes the element if the block returns a truthy value;
+ * Removes each element in +self+ for which the block returns a truthy value;
* returns +self+:
*
* a = [:foo, 'bar', 2, 'bat']
* a.delete_if {|element| element.to_s.start_with?('b') } # => [:foo, 2]
*
- * With no block given, returns a new Enumerator.
+ * Returns a new \Enumerator if no block given:
*
- * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
- */
+ * a = [:foo, 'bar', 2]
+ * a.delete_if # => #<Enumerator: [:foo, "bar", 2]:delete_if>
+ *
+3 */
static VALUE
rb_ary_delete_if(VALUE ary)
@@ -4452,7 +4571,7 @@ take_items(VALUE obj, long n)
* array.zip(*other_arrays) -> new_array
* array.zip(*other_arrays) {|other_array| ... } -> nil
*
- * When no block given, returns a new +Array+ +new_array+ of size <tt>self.size</tt>
+ * When no block given, returns a new \Array +new_array+ of size <tt>self.size</tt>
* whose elements are Arrays.
*
* Each nested array <tt>new_array[n]</tt> is of size <tt>other_arrays.size+1</tt>,
@@ -4487,13 +4606,6 @@ take_items(VALUE obj, long n)
* d = a.zip(b, c)
* d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
*
- * If an argument is not an array, it extracts the values by calling #each:
- *
- * a = [:a0, :a1, :a2, :a2]
- * b = 1..4
- * c = a.zip(b)
- * c # => [[:a0, 1], [:a1, 2], [:a2, 3], [:a2, 4]]
- *
* When a block is given, calls the block with each of the sub-arrays (formed as above); returns +nil+:
*
* a = [:a0, :a1, :a2, :a3]
@@ -4572,7 +4684,7 @@ rb_ary_zip(int argc, VALUE *argv, VALUE ary)
* call-seq:
* array.transpose -> new_array
*
- * Transposes the rows and columns in an +Array+ of Arrays;
+ * Transposes the rows and columns in an \Array of Arrays;
* the nested Arrays must all be the same size:
*
* a = [[:a0, :a1], [:b0, :b1], [:c0, :c1]]
@@ -4610,17 +4722,13 @@ rb_ary_transpose(VALUE ary)
/*
* call-seq:
- * initialize_copy(other_array) -> self
- * replace(other_array) -> self
+ * array.replace(other_array) -> self
*
- * Replaces the elements of +self+ with the elements of +other_array+, which must be an
- * {array-convertible object}[rdoc-ref:implicit_conversion.rdoc@Array-Convertible+Objects];
- * returns +self+:
+ * Replaces the content of +self+ with the content of +other_array+; returns +self+:
*
- * a = ['a', 'b', 'c'] # => ["a", "b", "c"]
- * a.replace(['d', 'e']) # => ["d", "e"]
+ * a = [:foo, 'bar', 2]
+ * a.replace(['foo', :bar, 3]) # => ["foo", :bar, 3]
*
- * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning].
*/
VALUE
@@ -4634,15 +4742,16 @@ rb_ary_replace(VALUE copy, VALUE orig)
/* orig has enough space to embed the contents of orig. */
if (RARRAY_LEN(orig) <= ary_embed_capa(copy)) {
- RUBY_ASSERT(ARY_EMBED_P(copy));
- ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR(orig));
+ assert(ARY_EMBED_P(copy));
+ ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR_TRANSIENT(orig));
ARY_SET_EMBED_LEN(copy, RARRAY_LEN(orig));
}
+#if USE_RVARGC
/* orig is embedded but copy does not have enough space to embed the
* contents of orig. */
else if (ARY_EMBED_P(orig)) {
long len = ARY_EMBED_LEN(orig);
- VALUE *ptr = ary_heap_alloc_buffer(len);
+ VALUE *ptr = ary_heap_alloc(copy, len);
FL_UNSET_EMBED(copy);
ARY_SET_PTR(copy, ptr);
@@ -4651,8 +4760,9 @@ rb_ary_replace(VALUE copy, VALUE orig)
// No allocation and exception expected that could leave `copy` in a
// bad state from the edits above.
- ary_memcpy(copy, 0, len, RARRAY_CONST_PTR(orig));
+ ary_memcpy(copy, 0, len, RARRAY_CONST_PTR_TRANSIENT(orig));
}
+#endif
/* Otherwise, orig is on heap and copy does not have enough space to embed
* the contents of orig. */
else {
@@ -4668,14 +4778,13 @@ rb_ary_replace(VALUE copy, VALUE orig)
/*
* call-seq:
- * clear -> self
+ * array.clear -> self
*
- * Removes all elements from +self+; returns +self+:
+ * Removes all elements from +self+:
*
* a = [:foo, 'bar', 2]
* a.clear # => []
*
- * Related: see {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
*/
VALUE
@@ -4683,9 +4792,11 @@ rb_ary_clear(VALUE ary)
{
rb_ary_modify_check(ary);
if (ARY_SHARED_P(ary)) {
- rb_ary_unshare(ary);
- FL_SET_EMBED(ary);
- ARY_SET_EMBED_LEN(ary, 0);
+ if (!ARY_EMBED_P(ary)) {
+ rb_ary_unshare(ary);
+ FL_SET_EMBED(ary);
+ ARY_SET_EMBED_LEN(ary, 0);
+ }
}
else {
ARY_SET_LEN(ary, 0);
@@ -4699,182 +4810,198 @@ rb_ary_clear(VALUE ary)
/*
* call-seq:
- * fill(object, start = nil, count = nil) -> new_array
- * fill(object, range) -> new_array
- * fill(start = nil, count = nil) {|element| ... } -> new_array
- * fill(range) {|element| ... } -> new_array
+ * array.fill(obj) -> self
+ * array.fill(obj, start) -> self
+ * array.fill(obj, start, length) -> self
+ * array.fill(obj, range) -> self
+ * array.fill {|index| ... } -> self
+ * array.fill(start) {|index| ... } -> self
+ * array.fill(start, length) {|index| ... } -> self
+ * array.fill(range) {|index| ... } -> self
+ *
+ * Replaces specified elements in +self+ with specified objects; returns +self+.
*
- * Replaces selected elements in +self+;
- * may add elements to +self+;
- * always returns +self+ (never a new array).
+ * With argument +obj+ and no block given, replaces all elements with that one object:
*
- * In brief:
+ * a = ['a', 'b', 'c', 'd']
+ * a # => ["a", "b", "c", "d"]
+ * a.fill(:X) # => [:X, :X, :X, :X]
*
- * # Non-negative start.
- * ['a', 'b', 'c', 'd'].fill('-', 1, 2) # => ["a", "-", "-", "d"]
- * ['a', 'b', 'c', 'd'].fill(1, 2) {|e| e.to_s } # => ["a", "1", "2", "d"]
+ * With arguments +obj+ and \Integer +start+, and no block given,
+ * replaces elements based on the given start.
*
- * # Extends with specified values if necessary.
- * ['a', 'b', 'c', 'd'].fill('-', 3, 2) # => ["a", "b", "c", "-", "-"]
- * ['a', 'b', 'c', 'd'].fill(3, 2) {|e| e.to_s } # => ["a", "b", "c", "3", "4"]
+ * If +start+ is in range (<tt>0 <= start < array.size</tt>),
+ * replaces all elements from offset +start+ through the end:
*
- * # Fills with nils if necessary.
- * ['a', 'b', 'c', 'd'].fill('-', 6, 2) # => ["a", "b", "c", "d", nil, nil, "-", "-"]
- * ['a', 'b', 'c', 'd'].fill(6, 2) {|e| e.to_s } # => ["a", "b", "c", "d", nil, nil, "6", "7"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, 2) # => ["a", "b", :X, :X]
*
- * # For negative start, counts backwards from the end.
- * ['a', 'b', 'c', 'd'].fill('-', -3, 3) # => ["a", "-", "-", "-"]
- * ['a', 'b', 'c', 'd'].fill(-3, 3) {|e| e.to_s } # => ["a", "1", "2", "3"]
+ * If +start+ is too large (<tt>start >= array.size</tt>), does nothing:
*
- * # Range.
- * ['a', 'b', 'c', 'd'].fill('-', 1..2) # => ["a", "-", "-", "d"]
- * ['a', 'b', 'c', 'd'].fill(1..2) {|e| e.to_s } # => ["a", "1", "2", "d"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, 4) # => ["a", "b", "c", "d"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, 5) # => ["a", "b", "c", "d"]
*
- * When arguments +start+ and +count+ are given,
- * they select the elements of +self+ to be replaced;
- * each must be an
- * {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects]
- * (or +nil+):
+ * If +start+ is negative, counts from the end (starting index is <tt>start + array.size</tt>):
*
- * - +start+ specifies the zero-based offset of the first element to be replaced;
- * +nil+ means zero.
- * - +count+ is the number of consecutive elements to be replaced;
- * +nil+ means "all the rest."
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, -2) # => ["a", "b", :X, :X]
*
- * With argument +object+ given,
- * that one object is used for all replacements:
+ * If +start+ is too small (less than and far from zero), replaces all elements:
*
- * o = Object.new # => #<Object:0x0000014e7bff7600>
- * a = ['a', 'b', 'c', 'd'] # => ["a", "b", "c", "d"]
- * a.fill(o, 1, 2)
- * # => ["a", #<Object:0x0000014e7bff7600>, #<Object:0x0000014e7bff7600>, "d"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, -6) # => [:X, :X, :X, :X]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, -50) # => [:X, :X, :X, :X]
*
- * With a block given, the block is called once for each element to be replaced;
- * the value passed to the block is the _index_ of the element to be replaced
- * (not the element itself);
- * the block's return value replaces the element:
+ * With arguments +obj+, \Integer +start+, and \Integer +length+, and no block given,
+ * replaces elements based on the given +start+ and +length+.
*
- * a = ['a', 'b', 'c', 'd'] # => ["a", "b", "c", "d"]
- * a.fill(1, 2) {|element| element.to_s } # => ["a", "1", "2", "d"]
+ * If +start+ is in range, replaces +length+ elements beginning at offset +start+:
*
- * For arguments +start+ and +count+:
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, 1, 1) # => ["a", :X, "c", "d"]
*
- * - If +start+ is non-negative,
- * replaces +count+ elements beginning at offset +start+:
+ * If +start+ is negative, counts from the end:
*
- * ['a', 'b', 'c', 'd'].fill('-', 0, 2) # => ["-", "-", "c", "d"]
- * ['a', 'b', 'c', 'd'].fill('-', 1, 2) # => ["a", "-", "-", "d"]
- * ['a', 'b', 'c', 'd'].fill('-', 2, 2) # => ["a", "b", "-", "-"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, -2, 1) # => ["a", "b", :X, "d"]
*
- * ['a', 'b', 'c', 'd'].fill(0, 2) {|e| e.to_s } # => ["0", "1", "c", "d"]
- * ['a', 'b', 'c', 'd'].fill(1, 2) {|e| e.to_s } # => ["a", "1", "2", "d"]
- * ['a', 'b', 'c', 'd'].fill(2, 2) {|e| e.to_s } # => ["a", "b", "2", "3"]
+ * If +start+ is large (<tt>start >= array.size</tt>), extends +self+ with +nil+:
*
- * Extends +self+ if necessary:
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, 5, 0) # => ["a", "b", "c", "d", nil]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, 5, 2) # => ["a", "b", "c", "d", nil, :X, :X]
*
- * ['a', 'b', 'c', 'd'].fill('-', 3, 2) # => ["a", "b", "c", "-", "-"]
- * ['a', 'b', 'c', 'd'].fill('-', 4, 2) # => ["a", "b", "c", "d", "-", "-"]
+ * If +length+ is zero or negative, replaces no elements:
*
- * ['a', 'b', 'c', 'd'].fill(3, 2) {|e| e.to_s } # => ["a", "b", "c", "3", "4"]
- * ['a', 'b', 'c', 'd'].fill(4, 2) {|e| e.to_s } # => ["a", "b", "c", "d", "4", "5"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, 1, 0) # => ["a", "b", "c", "d"]
+ * a.fill(:X, 1, -1) # => ["a", "b", "c", "d"]
*
- * Fills with +nil+ if necessary:
+ * With arguments +obj+ and \Range +range+, and no block given,
+ * replaces elements based on the given range.
*
- * ['a', 'b', 'c', 'd'].fill('-', 5, 2) # => ["a", "b", "c", "d", nil, "-", "-"]
- * ['a', 'b', 'c', 'd'].fill('-', 6, 2) # => ["a", "b", "c", "d", nil, nil, "-", "-"]
+ * If the range is positive and ascending (<tt>0 < range.begin <= range.end</tt>),
+ * replaces elements from <tt>range.begin</tt> to <tt>range.end</tt>:
*
- * ['a', 'b', 'c', 'd'].fill(5, 2) {|e| e.to_s } # => ["a", "b", "c", "d", nil, "5", "6"]
- * ['a', 'b', 'c', 'd'].fill(6, 2) {|e| e.to_s } # => ["a", "b", "c", "d", nil, nil, "6", "7"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, (1..1)) # => ["a", :X, "c", "d"]
*
- * Does nothing if +count+ is non-positive:
+ * If <tt>range.first</tt> is negative, replaces no elements:
*
- * ['a', 'b', 'c', 'd'].fill('-', 2, 0) # => ["a", "b", "c", "d"]
- * ['a', 'b', 'c', 'd'].fill('-', 2, -100) # => ["a", "b", "c", "d"]
- * ['a', 'b', 'c', 'd'].fill('-', 6, -100) # => ["a", "b", "c", "d"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, (-1..1)) # => ["a", "b", "c", "d"]
*
- * ['a', 'b', 'c', 'd'].fill(2, 0) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
- * ['a', 'b', 'c', 'd'].fill(2, -100) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
- * ['a', 'b', 'c', 'd'].fill(6, -100) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
+ * If <tt>range.last</tt> is negative, counts from the end:
*
- * - If +start+ is negative, counts backwards from the end of +self+:
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, (0..-2)) # => [:X, :X, :X, "d"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, (1..-2)) # => ["a", :X, :X, "d"]
*
- * ['a', 'b', 'c', 'd'].fill('-', -4, 3) # => ["-", "-", "-", "d"]
- * ['a', 'b', 'c', 'd'].fill('-', -3, 3) # => ["a", "-", "-", "-"]
+ * If <tt>range.last</tt> and <tt>range.last</tt> are both negative,
+ * both count from the end of the array:
*
- * ['a', 'b', 'c', 'd'].fill(-4, 3) {|e| e.to_s } # => ["0", "1", "2", "d"]
- * ['a', 'b', 'c', 'd'].fill(-3, 3) {|e| e.to_s } # => ["a", "1", "2", "3"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, (-1..-1)) # => ["a", "b", "c", :X]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(:X, (-2..-2)) # => ["a", "b", :X, "d"]
*
- * Extends +self+ if necessary:
+ * With no arguments and a block given, calls the block with each index;
+ * replaces the corresponding element with the block's return value:
*
- * ['a', 'b', 'c', 'd'].fill('-', -2, 3) # => ["a", "b", "-", "-", "-"]
- * ['a', 'b', 'c', 'd'].fill('-', -1, 3) # => ["a", "b", "c", "-", "-", "-"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "new_3"]
*
- * ['a', 'b', 'c', 'd'].fill(-2, 3) {|e| e.to_s } # => ["a", "b", "2", "3", "4"]
- * ['a', 'b', 'c', 'd'].fill(-1, 3) {|e| e.to_s } # => ["a", "b", "c", "3", "4", "5"]
+ * With argument +start+ and a block given, calls the block with each index
+ * from offset +start+ to the end; replaces the corresponding element
+ * with the block's return value.
*
- * Starts at the beginning of +self+ if +start+ is negative and out-of-range:
+ * If start is in range (<tt>0 <= start < array.size</tt>),
+ * replaces from offset +start+ to the end:
*
- * ['a', 'b', 'c', 'd'].fill('-', -5, 2) # => ["-", "-", "c", "d"]
- * ['a', 'b', 'c', 'd'].fill('-', -6, 2) # => ["-", "-", "c", "d"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(1) { |index| "new_#{index}" } # => ["a", "new_1", "new_2", "new_3"]
*
- * ['a', 'b', 'c', 'd'].fill(-5, 2) {|e| e.to_s } # => ["0", "1", "c", "d"]
- * ['a', 'b', 'c', 'd'].fill(-6, 2) {|e| e.to_s } # => ["0", "1", "c", "d"]
+ * If +start+ is too large(<tt>start >= array.size</tt>), does nothing:
*
- * Does nothing if +count+ is non-positive:
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(4) { |index| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(4) { |index| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
*
- * ['a', 'b', 'c', 'd'].fill('-', -2, 0) # => ["a", "b", "c", "d"]
- * ['a', 'b', 'c', 'd'].fill('-', -2, -1) # => ["a", "b", "c", "d"]
+ * If +start+ is negative, counts from the end:
*
- * ['a', 'b', 'c', 'd'].fill(-2, 0) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
- * ['a', 'b', 'c', 'd'].fill(-2, -1) {|e| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(-2) { |index| "new_#{index}" } # => ["a", "b", "new_2", "new_3"]
*
- * When argument +range+ is given,
- * it must be a Range object whose members are numeric;
- * its +begin+ and +end+ values determine the elements of +self+
- * to be replaced:
+ * If start is too small (<tt>start <= -array.size</tt>, replaces all elements:
*
- * - If both +begin+ and +end+ are positive, they specify the first and last elements
- * to be replaced:
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(-6) { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "new_3"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(-50) { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "new_3"]
*
- * ['a', 'b', 'c', 'd'].fill('-', 1..2) # => ["a", "-", "-", "d"]
- * ['a', 'b', 'c', 'd'].fill(1..2) {|e| e.to_s } # => ["a", "1", "2", "d"]
+ * With arguments +start+ and +length+, and a block given,
+ * calls the block for each index specified by start length;
+ * replaces the corresponding element with the block's return value.
*
- * If +end+ is smaller than +begin+, replaces no elements:
+ * If +start+ is in range, replaces +length+ elements beginning at offset +start+:
*
- * ['a', 'b', 'c', 'd'].fill('-', 2..1) # => ["a", "b", "c", "d"]
- * ['a', 'b', 'c', 'd'].fill(2..1) {|e| e.to_s } # => ["a", "b", "c", "d"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(1, 1) { |index| "new_#{index}" } # => ["a", "new_1", "c", "d"]
*
- * - If either is negative (or both are negative), counts backwards from the end of +self+:
+ * If start is negative, counts from the end:
*
- * ['a', 'b', 'c', 'd'].fill('-', -3..2) # => ["a", "-", "-", "d"]
- * ['a', 'b', 'c', 'd'].fill('-', 1..-2) # => ["a", "-", "-", "d"]
- * ['a', 'b', 'c', 'd'].fill('-', -3..-2) # => ["a", "-", "-", "d"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(-2, 1) { |index| "new_#{index}" } # => ["a", "b", "new_2", "d"]
*
- * ['a', 'b', 'c', 'd'].fill(-3..2) {|e| e.to_s } # => ["a", "1", "2", "d"]
- * ['a', 'b', 'c', 'd'].fill(1..-2) {|e| e.to_s } # => ["a", "1", "2", "d"]
- * ['a', 'b', 'c', 'd'].fill(-3..-2) {|e| e.to_s } # => ["a", "1", "2", "d"]
+ * If +start+ is large (<tt>start >= array.size</tt>), extends +self+ with +nil+:
*
- * - If the +end+ value is excluded (see Range#exclude_end?), omits the last replacement:
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(5, 0) { |index| "new_#{index}" } # => ["a", "b", "c", "d", nil]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(5, 2) { |index| "new_#{index}" } # => ["a", "b", "c", "d", nil, "new_5", "new_6"]
*
- * ['a', 'b', 'c', 'd'].fill('-', 1...2) # => ["a", "-", "c", "d"]
- * ['a', 'b', 'c', 'd'].fill('-', 1...-2) # => ["a", "-", "c", "d"]
+ * If +length+ is zero or less, replaces no elements:
*
- * ['a', 'b', 'c', 'd'].fill(1...2) {|e| e.to_s } # => ["a", "1", "c", "d"]
- * ['a', 'b', 'c', 'd'].fill(1...-2) {|e| e.to_s } # => ["a", "1", "c", "d"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(1, 0) { |index| "new_#{index}" } # => ["a", "b", "c", "d"]
+ * a.fill(1, -1) { |index| "new_#{index}" } # => ["a", "b", "c", "d"]
*
- * - If the range is endless (see {Endless Ranges}[rdoc-ref:Range@Endless+Ranges]),
- * replaces elements to the end of +self+:
+ * With arguments +obj+ and +range+, and a block given,
+ * calls the block with each index in the given range;
+ * replaces the corresponding element with the block's return value.
*
- * ['a', 'b', 'c', 'd'].fill('-', 1..) # => ["a", "-", "-", "-"]
- * ['a', 'b', 'c', 'd'].fill(1..) {|e| e.to_s } # => ["a", "1", "2", "3"]
+ * If the range is positive and ascending (<tt>range 0 < range.begin <= range.end</tt>,
+ * replaces elements from <tt>range.begin</tt> to <tt>range.end</tt>:
*
- * - If the range is beginless (see {Beginless Ranges}[rdoc-ref:Range@Beginless+Ranges]),
- * replaces elements from the beginning of +self+:
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(1..1) { |index| "new_#{index}" } # => ["a", "new_1", "c", "d"]
*
- * ['a', 'b', 'c', 'd'].fill('-', ..2) # => ["-", "-", "-", "d"]
- * ['a', 'b', 'c', 'd'].fill(..2) {|e| e.to_s } # => ["0", "1", "2", "d"]
+ * If +range.first+ is negative, does nothing:
+ *
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(-1..1) { |index| fail 'Cannot happen' } # => ["a", "b", "c", "d"]
+ *
+ * If <tt>range.last</tt> is negative, counts from the end:
+ *
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(0..-2) { |index| "new_#{index}" } # => ["new_0", "new_1", "new_2", "d"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(1..-2) { |index| "new_#{index}" } # => ["a", "new_1", "new_2", "d"]
+ *
+ * If <tt>range.first</tt> and <tt>range.last</tt> are both negative,
+ * both count from the end:
+ *
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(-1..-1) { |index| "new_#{index}" } # => ["a", "b", "c", "new_3"]
+ * a = ['a', 'b', 'c', 'd']
+ * a.fill(-2..-2) { |index| "new_#{index}" } # => ["a", "b", "new_2", "d"]
*
- * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning].
*/
static VALUE
@@ -4943,15 +5070,15 @@ rb_ary_fill(int argc, VALUE *argv, VALUE ary)
/*
* call-seq:
- * self + other_array -> new_array
+ * array + other_array -> new_array
*
- * Returns a new array containing all elements of +self+
+ * Returns a new \Array containing all elements of +array+
* followed by all elements of +other_array+:
*
* a = [0, 1] + [2, 3]
* a # => [0, 1, 2, 3]
*
- * Related: see {Methods for Combining}[rdoc-ref:Array@Methods+for+Combining].
+ * Related: #concat.
*/
VALUE
@@ -4966,8 +5093,8 @@ rb_ary_plus(VALUE x, VALUE y)
len = xlen + ylen;
z = rb_ary_new2(len);
- ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR(x));
- ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR(y));
+ ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR_TRANSIENT(x));
+ ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR_TRANSIENT(y));
ARY_SET_LEN(z, len);
return z;
}
@@ -4977,7 +5104,7 @@ ary_append(VALUE x, VALUE y)
{
long n = RARRAY_LEN(y);
if (n > 0) {
- rb_ary_splice(x, RARRAY_LEN(x), 0, RARRAY_CONST_PTR(y), n);
+ rb_ary_splice(x, RARRAY_LEN(x), 0, RARRAY_CONST_PTR_TRANSIENT(y), n);
}
RB_GC_GUARD(y);
return x;
@@ -4985,15 +5112,12 @@ ary_append(VALUE x, VALUE y)
/*
* call-seq:
- * concat(*other_arrays) -> self
+ * array.concat(*other_arrays) -> self
*
- * Adds to +self+ all elements from each array in +other_arrays+; returns +self+:
+ * Adds to +array+ all elements from each \Array in +other_arrays+; returns +self+:
*
* a = [0, 1]
- * a.concat(['two', 'three'], [:four, :five], a)
- * # => [0, 1, "two", "three", :four, :five, 0, 1]
- *
- * Related: see {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning].
+ * a.concat([2, 3], [4, 5]) # => [0, 1, 2, 3, 4, 5]
*/
static VALUE
@@ -5025,17 +5149,17 @@ rb_ary_concat(VALUE x, VALUE y)
/*
* call-seq:
- * self * n -> new_array
- * self * string_separator -> new_string
+ * array * n -> new_array
+ * array * string_separator -> new_string
*
- * When non-negative integer argument +n+ is given,
- * returns a new array built by concatenating +n+ copies of +self+:
+ * When non-negative argument \Integer +n+ is given,
+ * returns a new \Array built by concatenating the +n+ copies of +self+:
*
* a = ['x', 'y']
* a * 3 # => ["x", "y", "x", "y", "x", "y"]
*
- * When string argument +string_separator+ is given,
- * equivalent to <tt>self.join(string_separator)</tt>:
+ * When \String argument +string_separator+ is given,
+ * equivalent to <tt>array.join(string_separator)</tt>:
*
* [0, [0, 1], {foo: 0}] * ', ' # => "0, 0, 1, {:foo=>0}"
*
@@ -5069,16 +5193,16 @@ rb_ary_times(VALUE ary, VALUE times)
ary2 = ary_new(rb_cArray, len);
ARY_SET_LEN(ary2, len);
- ptr = RARRAY_CONST_PTR(ary);
+ ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
t = RARRAY_LEN(ary);
if (0 < t) {
ary_memcpy(ary2, 0, t, ptr);
while (t <= len/2) {
- ary_memcpy(ary2, t, t, RARRAY_CONST_PTR(ary2));
+ ary_memcpy(ary2, t, t, RARRAY_CONST_PTR_TRANSIENT(ary2));
t *= 2;
}
if (t < len) {
- ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR(ary2));
+ ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR_TRANSIENT(ary2));
}
}
out:
@@ -5087,18 +5211,17 @@ rb_ary_times(VALUE ary, VALUE times)
/*
* call-seq:
- * assoc(object) -> found_array or nil
+ * array.assoc(obj) -> found_array or nil
*
- * Returns the first element +ele+ in +self+ such that +ele+ is an array
- * and <tt>ele[0] == object</tt>:
+ * Returns the first element in +self+ that is an \Array
+ * whose first element <tt>==</tt> +obj+:
*
* a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]]
* a.assoc(4) # => [4, 5, 6]
*
* Returns +nil+ if no such element is found.
*
- * Related: Array#rassoc;
- * see also {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
+ * Related: #rassoc.
*/
VALUE
@@ -5120,7 +5243,7 @@ rb_ary_assoc(VALUE ary, VALUE key)
* call-seq:
* array.rassoc(obj) -> found_array or nil
*
- * Returns the first element in +self+ that is an +Array+
+ * Returns the first element in +self+ that is an \Array
* whose second element <tt>==</tt> +obj+:
*
* a = [{foo: 0}, [2, 4], [4, 5, 6], [4, 5]]
@@ -5138,7 +5261,7 @@ rb_ary_rassoc(VALUE ary, VALUE value)
VALUE v;
for (i = 0; i < RARRAY_LEN(ary); ++i) {
- v = rb_check_array_type(RARRAY_AREF(ary, i));
+ v = RARRAY_AREF(ary, i);
if (RB_TYPE_P(v, T_ARRAY) &&
RARRAY_LEN(v) > 1 &&
rb_equal(RARRAY_AREF(v, 1), value))
@@ -5183,26 +5306,20 @@ recursive_equal(VALUE ary1, VALUE ary2, int recur)
/*
* call-seq:
- * self == other_array -> true or false
- *
- * Returns whether both:
+ * array == other_array -> true or false
*
- * - +self+ and +other_array+ are the same size.
- * - Their corresponding elements are the same;
- * that is, for each index +i+ in <tt>(0...self.size)</tt>,
- * <tt>self[i] == other_array[i]</tt>.
+ * Returns +true+ if both <tt>array.size == other_array.size</tt>
+ * and for each index +i+ in +array+, <tt>array[i] == other_array[i]</tt>:
*
- * Examples:
+ * a0 = [:foo, 'bar', 2]
+ * a1 = [:foo, 'bar', 2.0]
+ * a1 == a0 # => true
+ * [] == [] # => true
*
- * [:foo, 'bar', 2] == [:foo, 'bar', 2] # => true
- * [:foo, 'bar', 2] == [:foo, 'bar', 2.0] # => true
- * [:foo, 'bar', 2] == [:foo, 'bar'] # => false # Different sizes.
- * [:foo, 'bar', 2] == [:foo, 'bar', 3] # => false # Different elements.
+ * Otherwise, returns +false+.
*
* This method is different from method Array#eql?,
* which compares elements using <tt>Object#eql?</tt>.
- *
- * Related: see {Methods for Comparing}[rdoc-ref:Array@Methods+for+Comparing].
*/
static VALUE
@@ -5216,7 +5333,7 @@ rb_ary_equal(VALUE ary1, VALUE ary2)
return rb_equal(ary2, ary1);
}
if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
- if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue;
+ if (RARRAY_CONST_PTR_TRANSIENT(ary1) == RARRAY_CONST_PTR_TRANSIENT(ary2)) return Qtrue;
return rb_exec_recursive_paired(recursive_equal, ary1, ary2, ary2);
}
@@ -5235,10 +5352,10 @@ recursive_eql(VALUE ary1, VALUE ary2, int recur)
/*
* call-seq:
- * eql?(other_array) -> true or false
+ * array.eql? other_array -> true or false
*
* Returns +true+ if +self+ and +other_array+ are the same size,
- * and if, for each index +i+ in +self+, <tt>self[i].eql?(other_array[i])</tt>:
+ * and if, for each index +i+ in +self+, <tt>self[i].eql? other_array[i]</tt>:
*
* a0 = [:foo, 'bar', 2]
* a1 = [:foo, 'bar', 2]
@@ -5248,8 +5365,6 @@ recursive_eql(VALUE ary1, VALUE ary2, int recur)
*
* This method is different from method Array#==,
* which compares using method <tt>Object#==</tt>.
- *
- * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
*/
static VALUE
@@ -5258,60 +5373,49 @@ rb_ary_eql(VALUE ary1, VALUE ary2)
if (ary1 == ary2) return Qtrue;
if (!RB_TYPE_P(ary2, T_ARRAY)) return Qfalse;
if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
- if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue;
+ if (RARRAY_CONST_PTR_TRANSIENT(ary1) == RARRAY_CONST_PTR_TRANSIENT(ary2)) return Qtrue;
return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2);
}
-VALUE
-rb_ary_hash_values(long len, const VALUE *elements)
-{
- long i;
- st_index_t h;
- VALUE n;
-
- h = rb_hash_start(len);
- h = rb_hash_uint(h, (st_index_t)rb_ary_hash_values);
- for (i=0; i<len; i++) {
- n = rb_hash(elements[i]);
- h = rb_hash_uint(h, NUM2LONG(n));
- }
- h = rb_hash_end(h);
- return ST2FIX(h);
-}
-
/*
* call-seq:
- * hash -> integer
+ * array.hash -> integer
*
* Returns the integer hash value for +self+.
*
- * Two arrays with the same content will have the same hash value
- * (and will compare using eql?):
+ * Two arrays with the same content will have the same hash code (and will compare using eql?):
*
- * ['a', 'b'].hash == ['a', 'b'].hash # => true
- * ['a', 'b'].hash == ['a', 'c'].hash # => false
- * ['a', 'b'].hash == ['a'].hash # => false
+ * [0, 1, 2].hash == [0, 1, 2].hash # => true
+ * [0, 1, 2].hash == [0, 1, 3].hash # => false
*
*/
static VALUE
rb_ary_hash(VALUE ary)
{
- return rb_ary_hash_values(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary));
+ long i;
+ st_index_t h;
+ VALUE n;
+
+ h = rb_hash_start(RARRAY_LEN(ary));
+ h = rb_hash_uint(h, (st_index_t)rb_ary_hash);
+ for (i=0; i<RARRAY_LEN(ary); i++) {
+ n = rb_hash(RARRAY_AREF(ary, i));
+ h = rb_hash_uint(h, NUM2LONG(n));
+ }
+ h = rb_hash_end(h);
+ return ST2FIX(h);
}
/*
* call-seq:
- * include?(object) -> true or false
+ * array.include?(obj) -> true or false
*
- * Returns whether for some element +element+ in +self+,
- * <tt>object == element</tt>:
+ * Returns +true+ if for some index +i+ in +self+, <tt>obj == self[i]</tt>;
+ * otherwise +false+:
*
- * [0, 1, 2].include?(2) # => true
- * [0, 1, 2].include?(2.0) # => true
- * [0, 1, 2].include?(2.1) # => false
- *
- * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
+ * [0, 1, 2].include?(2) # => true
+ * [0, 1, 2].include?(3) # => false
*/
VALUE
@@ -5366,40 +5470,33 @@ recursive_cmp(VALUE ary1, VALUE ary2, int recur)
/*
* call-seq:
- * self <=> other_array -> -1, 0, or 1
+ * array <=> other_array -> -1, 0, or 1
+ *
+ * Returns -1, 0, or 1 as +self+ is less than, equal to, or greater than +other_array+.
+ * For each index +i+ in +self+, evaluates <tt>result = self[i] <=> other_array[i]</tt>.
*
- * Returns -1, 0, or 1 as +self+ is determined
- * to be less than, equal to, or greater than +other_array+.
+ * Returns -1 if any result is -1:
*
- * Iterates over each index +i+ in <tt>(0...self.size)</tt>:
+ * [0, 1, 2] <=> [0, 1, 3] # => -1
*
- * - Computes <tt>result[i]</tt> as <tt>self[i] <=> other_array[i]</tt>.
- * - Immediately returns 1 if <tt>result[i]</tt> is 1:
+ * Returns 1 if any result is 1:
*
- * [0, 1, 2] <=> [0, 0, 2] # => 1
+ * [0, 1, 2] <=> [0, 1, 1] # => 1
*
- * - Immediately returns -1 if <tt>result[i]</tt> is -1:
+ * When all results are zero:
*
- * [0, 1, 2] <=> [0, 2, 2] # => -1
+ * - Returns -1 if +array+ is smaller than +other_array+:
*
- * - Continues if <tt>result[i]</tt> is 0.
+ * [0, 1, 2] <=> [0, 1, 2, 3] # => -1
*
- * When every +result+ is 0,
- * returns <tt>self.size <=> other_array.size</tt>
- * (see Integer#<=>):
+ * - Returns 1 if +array+ is larger than +other_array+:
*
- * [0, 1, 2] <=> [0, 1] # => 1
- * [0, 1, 2] <=> [0, 1, 2] # => 0
- * [0, 1, 2] <=> [0, 1, 2, 3] # => -1
+ * [0, 1, 2] <=> [0, 1] # => 1
*
- * Note that when +other_array+ is larger than +self+,
- * its trailing elements do not affect the result:
+ * - Returns 0 if +array+ and +other_array+ are the same size:
*
- * [0, 1, 2] <=> [0, 1, 2, -3] # => -1
- * [0, 1, 2] <=> [0, 1, 2, 0] # => -1
- * [0, 1, 2] <=> [0, 1, 2, 3] # => -1
+ * [0, 1, 2] <=> [0, 1, 2] # => 0
*
- * Related: see {Methods for Comparing}[rdoc-ref:Array@Methods+for+Comparing].
*/
VALUE
@@ -5467,22 +5564,31 @@ ary_make_hash_by(VALUE ary)
return ary_add_hash_by(hash, ary);
}
+static inline void
+ary_recycle_hash(VALUE hash)
+{
+ assert(RBASIC_CLASS(hash) == 0);
+ if (RHASH_ST_TABLE_P(hash)) {
+ st_table *tbl = RHASH_ST_TABLE(hash);
+ st_free_table(tbl);
+ RHASH_ST_CLEAR(hash);
+ }
+}
+
/*
* call-seq:
- * self - other_array -> new_array
+ * array - other_array -> new_array
*
- * Returns a new array containing only those elements of +self+
- * that are not found in +other_array+;
- * the order from +self+ is preserved:
+ * Returns a new \Array containing only those elements from +array+
+ * that are not found in \Array +other_array+;
+ * items are compared using <tt>eql?</tt>;
+ * the order from +array+ is preserved:
*
- * [0, 1, 1, 2, 1, 1, 3, 1, 1] - [1] # => [0, 2, 3]
- * [0, 1, 1, 2, 1, 1, 3, 1, 1] - [3, 2, 0, :foo] # => [1, 1, 1, 1, 1, 1]
- * [0, 1, 2] - [:foo] # => [0, 1, 2]
+ * [0, 1, 1, 2, 1, 1, 3, 1, 1] - [1] # => [0, 2, 3]
+ * [0, 1, 2, 3] - [3, 0] # => [1, 2]
+ * [0, 1, 2] - [4] # => [0, 1, 2]
*
- * Element are compared using method <tt>#eql?</tt>
- * (as defined in each element of +self+).
- *
- * Related: see {Methods for Combining}[rdoc-ref:Array@Methods+for+Combining].
+ * Related: Array#difference.
*/
VALUE
@@ -5510,27 +5616,25 @@ rb_ary_diff(VALUE ary1, VALUE ary2)
if (rb_hash_stlike_lookup(hash, RARRAY_AREF(ary1, i), NULL)) continue;
rb_ary_push(ary3, rb_ary_elt(ary1, i));
}
-
+ ary_recycle_hash(hash);
return ary3;
}
/*
* call-seq:
- * difference(*other_arrays = []) -> new_array
+ * array.difference(*other_arrays) -> new_array
*
- * Returns a new array containing only those elements from +self+
- * that are not found in any of the given +other_arrays+;
+ * Returns a new \Array containing only those elements from +self+
+ * that are not found in any of the Arrays +other_arrays+;
* items are compared using <tt>eql?</tt>; order from +self+ is preserved:
*
* [0, 1, 1, 2, 1, 1, 3, 1, 1].difference([1]) # => [0, 2, 3]
- * [0, 1, 2, 3].difference([3, 0], [1, 3]) # => [2]
- * [0, 1, 2].difference([4]) # => [0, 1, 2]
- * [0, 1, 2].difference # => [0, 1, 2]
+ * [0, 1, 2, 3].difference([3, 0], [1, 3]) # => [2]
+ * [0, 1, 2].difference([4]) # => [0, 1, 2]
*
- * Returns a copy of +self+ if no arguments are given.
+ * Returns a copy of +self+ if no arguments given.
*
- * Related: Array#-;
- * see also {Methods for Combining}[rdoc-ref:Array@Methods+for+Combining].
+ * Related: Array#-.
*/
static VALUE
@@ -5572,25 +5676,19 @@ rb_ary_difference_multi(int argc, VALUE *argv, VALUE ary)
/*
* call-seq:
- * self & other_array -> new_array
+ * array & other_array -> new_array
*
- * Returns a new array containing the _intersection_ of +self+ and +other_array+;
- * that is, containing those elements found in both +self+ and +other_array+:
+ * Returns a new \Array containing each element found in both +array+ and \Array +other_array+;
+ * duplicates are omitted; items are compared using <tt>eql?</tt>:
*
* [0, 1, 2, 3] & [1, 2] # => [1, 2]
+ * [0, 1, 0, 1] & [0, 1] # => [0, 1]
*
- * Omits duplicates:
- *
- * [0, 1, 1, 0] & [0, 1] # => [0, 1]
- *
- * Preserves order from +self+:
+ * Preserves order from +array+:
*
* [0, 1, 2] & [3, 2, 1, 0] # => [0, 1, 2]
*
- * Identifies common elements using method <tt>#eql?</tt>
- * (as defined in each element of +self+).
- *
- * Related: see {Methods for Combining}[rdoc-ref:Array@Methods+for+Combining].
+ * Related: Array#intersection.
*/
@@ -5624,29 +5722,29 @@ rb_ary_and(VALUE ary1, VALUE ary2)
rb_ary_push(ary3, v);
}
}
+ ary_recycle_hash(hash);
return ary3;
}
/*
* call-seq:
- * intersection(*other_arrays) -> new_array
+ * array.intersection(*other_arrays) -> new_array
*
- * Returns a new array containing each element in +self+ that is +#eql?+
- * to at least one element in each of the given +other_arrays+;
- * duplicates are omitted:
+ * Returns a new \Array containing each element found both in +self+
+ * and in all of the given Arrays +other_arrays+;
+ * duplicates are omitted; items are compared using <tt>eql?</tt>:
*
+ * [0, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3]) # => [0, 1]
* [0, 0, 1, 1, 2, 3].intersection([0, 1, 2], [0, 1, 3]) # => [0, 1]
*
- * Each element must correctly implement method <tt>#hash</tt>.
- *
- * Order from +self+ is preserved:
+ * Preserves order from +self+:
*
* [0, 1, 2].intersection([2, 1, 0]) # => [0, 1, 2]
*
- * Returns a copy of +self+ if no arguments are given.
+ * Returns a copy of +self+ if no arguments given.
*
- * Related: see {Methods for Combining}[rdoc-ref:Array@Methods+for+Combining].
+ * Related: Array#&.
*/
static VALUE
@@ -5697,7 +5795,7 @@ rb_ary_union_hash(VALUE hash, VALUE ary2)
* call-seq:
* array | other_array -> new_array
*
- * Returns the union of +array+ and +Array+ +other_array+;
+ * Returns the union of +array+ and \Array +other_array+;
* duplicates are removed; order is preserved;
* items are compared using <tt>eql?</tt>:
*
@@ -5711,11 +5809,11 @@ rb_ary_union_hash(VALUE hash, VALUE ary2)
static VALUE
rb_ary_or(VALUE ary1, VALUE ary2)
{
- VALUE hash;
+ VALUE hash, ary3;
ary2 = to_ary(ary2);
if (RARRAY_LEN(ary1) + RARRAY_LEN(ary2) <= SMALL_ARRAY_LEN) {
- VALUE ary3 = rb_ary_new();
+ ary3 = rb_ary_new();
rb_ary_union(ary3, ary1);
rb_ary_union(ary3, ary2);
return ary3;
@@ -5724,14 +5822,16 @@ rb_ary_or(VALUE ary1, VALUE ary2)
hash = ary_make_hash(ary1);
rb_ary_union_hash(hash, ary2);
- return rb_hash_values(hash);
+ ary3 = rb_hash_values(hash);
+ ary_recycle_hash(hash);
+ return ary3;
}
/*
* call-seq:
* array.union(*other_arrays) -> new_array
*
- * Returns a new +Array+ that is the union of +self+ and all given Arrays +other_arrays+;
+ * Returns a new \Array that is the union of +self+ and all given Arrays +other_arrays+;
* duplicates are removed; order is preserved; items are compared using <tt>eql?</tt>:
*
* [0, 1, 2, 3].union([4, 5], [6, 7]) # => [0, 1, 2, 3, 4, 5, 6, 7]
@@ -5748,7 +5848,7 @@ rb_ary_union_multi(int argc, VALUE *argv, VALUE ary)
{
int i;
long sum;
- VALUE hash;
+ VALUE hash, ary_union;
sum = RARRAY_LEN(ary);
for (i = 0; i < argc; i++) {
@@ -5757,7 +5857,7 @@ rb_ary_union_multi(int argc, VALUE *argv, VALUE ary)
}
if (sum <= SMALL_ARRAY_LEN) {
- VALUE ary_union = rb_ary_new();
+ ary_union = rb_ary_new();
rb_ary_union(ary_union, ary);
for (i = 0; i < argc; i++) rb_ary_union(ary_union, argv[i]);
@@ -5768,21 +5868,24 @@ rb_ary_union_multi(int argc, VALUE *argv, VALUE ary)
hash = ary_make_hash(ary);
for (i = 0; i < argc; i++) rb_ary_union_hash(hash, argv[i]);
- return rb_hash_values(hash);
+ ary_union = rb_hash_values(hash);
+ ary_recycle_hash(hash);
+ return ary_union;
}
/*
* call-seq:
- * intersect?(other_array) -> true or false
- *
- * Returns whether +other_array+ has at least one element that is +#eql?+ to some element of +self+:
+ * ary.intersect?(other_ary) -> true or false
*
- * [1, 2, 3].intersect?([3, 4, 5]) # => true
- * [1, 2, 3].intersect?([4, 5, 6]) # => false
+ * Returns +true+ if the array and +other_ary+ have at least one element in
+ * common, otherwise returns +false+:
*
- * Each element must correctly implement method <tt>#hash</tt>.
+ * a = [ 1, 2, 3 ]
+ * b = [ 3, 4, 5 ]
+ * c = [ 5, 6, 7 ]
+ * a.intersect?(b) #=> true
+ * a.intersect?(c) #=> false
*
- * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
*/
static VALUE
@@ -5821,6 +5924,7 @@ rb_ary_intersect_p(VALUE ary1, VALUE ary2)
break;
}
}
+ ary_recycle_hash(hash);
return result;
}
@@ -5916,51 +6020,42 @@ ary_max_opt_string(VALUE ary, long i, VALUE vmax)
/*
* call-seq:
- * max -> element
- * max(n) -> new_array
- * max {|a, b| ... } -> element
- * max(n) {|a, b| ... } -> new_array
+ * array.max -> element
+ * array.max {|a, b| ... } -> element
+ * array.max(n) -> new_array
+ * array.max(n) {|a, b| ... } -> new_array
*
* Returns one of the following:
*
* - The maximum-valued element from +self+.
- * - A new array of maximum-valued elements from +self+.
+ * - A new \Array of maximum-valued elements selected from +self+.
*
- * Does not modify +self+.
- *
- * With no block given, each element in +self+ must respond to method <tt>#<=></tt>
- * with a numeric.
+ * When no block is given, each element in +self+ must respond to method <tt><=></tt>
+ * with an \Integer.
*
* With no argument and no block, returns the element in +self+
- * having the maximum value per method <tt>#<=></tt>:
+ * having the maximum value per method <tt><=></tt>:
*
- * [1, 0, 3, 2].max # => 3
+ * [0, 1, 2].max # => 2
*
- * With non-negative numeric argument +n+ and no block,
- * returns a new array with at most +n+ elements,
- * in descending order, per method <tt>#<=></tt>:
+ * With an argument \Integer +n+ and no block, returns a new \Array with at most +n+ elements,
+ * in descending order per method <tt><=></tt>:
*
- * [1, 0, 3, 2].max(3) # => [3, 2, 1]
- * [1, 0, 3, 2].max(3.0) # => [3, 2, 1]
- * [1, 0, 3, 2].max(9) # => [3, 2, 1, 0]
- * [1, 0, 3, 2].max(0) # => []
+ * [0, 1, 2, 3].max(3) # => [3, 2, 1]
+ * [0, 1, 2, 3].max(6) # => [3, 2, 1, 0]
*
- * With a block given, the block must return a numeric.
+ * When a block is given, the block must return an \Integer.
*
- * With a block and no argument, calls the block <tt>self.size - 1</tt> times to compare elements;
+ * With a block and no argument, calls the block <tt>self.size-1</tt> times to compare elements;
* returns the element having the maximum value per the block:
*
- * ['0', '', '000', '00'].max {|a, b| a.size <=> b.size }
- * # => "000"
+ * ['0', '00', '000'].max {|a, b| a.size <=> b.size } # => "000"
*
- * With non-negative numeric argument +n+ and a block,
- * returns a new array with at most +n+ elements,
- * in descending order, per the block:
+ * With an argument +n+ and a block, returns a new \Array with at most +n+ elements,
+ * in descending order per the block:
*
- * ['0', '', '000', '00'].max(2) {|a, b| a.size <=> b.size }
- * # => ["000", "00"]
+ * ['0', '00', '000'].max(2) {|a, b| a.size <=> b.size } # => ["000", "00"]
*
- * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
*/
static VALUE
rb_ary_max(int argc, VALUE *argv, VALUE ary)
@@ -6093,51 +6188,42 @@ ary_min_opt_string(VALUE ary, long i, VALUE vmin)
/*
* call-seq:
- * min -> element
- * min(n) -> new_array
- * min {|a, b| ... } -> element
- * min(n) {|a, b| ... } -> new_array
+ * array.min -> element
+ * array.min { |a, b| ... } -> element
+ * array.min(n) -> new_array
+ * array.min(n) { |a, b| ... } -> new_array
*
* Returns one of the following:
*
* - The minimum-valued element from +self+.
- * - A new array of minimum-valued elements from +self+.
- *
- * Does not modify +self+.
+ * - A new \Array of minimum-valued elements selected from +self+.
*
- * With no block given, each element in +self+ must respond to method <tt>#<=></tt>
- * with a numeric.
+ * When no block is given, each element in +self+ must respond to method <tt><=></tt>
+ * with an \Integer.
*
* With no argument and no block, returns the element in +self+
- * having the minimum value per method <tt>#<=></tt>:
+ * having the minimum value per method <tt><=></tt>:
*
- * [1, 0, 3, 2].min # => 0
+ * [0, 1, 2].min # => 0
*
- * With non-negative numeric argument +n+ and no block,
- * returns a new array with at most +n+ elements,
- * in ascending order, per method <tt>#<=></tt>:
+ * With \Integer argument +n+ and no block, returns a new \Array with at most +n+ elements,
+ * in ascending order per method <tt><=></tt>:
*
- * [1, 0, 3, 2].min(3) # => [0, 1, 2]
- * [1, 0, 3, 2].min(3.0) # => [0, 1, 2]
- * [1, 0, 3, 2].min(9) # => [0, 1, 2, 3]
- * [1, 0, 3, 2].min(0) # => []
+ * [0, 1, 2, 3].min(3) # => [0, 1, 2]
+ * [0, 1, 2, 3].min(6) # => [0, 1, 2, 3]
*
- * With a block given, the block must return a numeric.
+ * When a block is given, the block must return an Integer.
*
- * With a block and no argument, calls the block <tt>self.size - 1</tt> times to compare elements;
+ * With a block and no argument, calls the block <tt>self.size-1</tt> times to compare elements;
* returns the element having the minimum value per the block:
*
- * ['0', '', '000', '00'].min {|a, b| a.size <=> b.size }
- * # => ""
+ * ['0', '00', '000'].min { |a, b| a.size <=> b.size } # => "0"
*
- * With non-negative numeric argument +n+ and a block,
- * returns a new array with at most +n+ elements,
- * in ascending order, per the block:
+ * With an argument +n+ and a block, returns a new \Array with at most +n+ elements,
+ * in ascending order per the block:
*
- * ['0', '', '000', '00'].min(2) {|a, b| a.size <=> b.size }
- * # => ["", "0"]
+ * ['0', '00', '000'].min(2) {|a, b| a.size <=> b.size } # => ["0", "00"]
*
- * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
*/
static VALUE
rb_ary_min(int argc, VALUE *argv, VALUE ary)
@@ -6181,25 +6267,26 @@ rb_ary_min(int argc, VALUE *argv, VALUE ary)
/*
* call-seq:
- * minmax -> array
- * minmax {|a, b| ... } -> array
+ * array.minmax -> [min_val, max_val]
+ * array.minmax {|a, b| ... } -> [min_val, max_val]
*
- * Returns a 2-element array containing the minimum-valued and maximum-valued
- * elements from +self+;
- * does not modify +self+.
+ * Returns a new 2-element \Array containing the minimum and maximum values
+ * from +self+, either per method <tt><=></tt> or per a given block:.
*
- * With no block given, the minimum and maximum values are determined using method <tt>#<=></tt>:
+ * When no block is given, each element in +self+ must respond to method <tt><=></tt>
+ * with an \Integer;
+ * returns a new 2-element \Array containing the minimum and maximum values
+ * from +self+, per method <tt><=></tt>:
*
- * [1, 0, 3, 2].minmax # => [0, 3]
+ * [0, 1, 2].minmax # => [0, 2]
*
- * With a block given, the block must return a numeric;
- * the block is called <tt>self.size - 1</tt> times to compare elements;
- * returns the elements having the minimum and maximum values per the block:
+ * When a block is given, the block must return an \Integer;
+ * the block is called <tt>self.size-1</tt> times to compare elements;
+ * returns a new 2-element \Array containing the minimum and maximum values
+ * from +self+, per the block:
*
- * ['0', '', '000', '00'].minmax {|a, b| a.size <=> b.size }
- * # => ["", "000"]
+ * ['0', '00', '000'].minmax {|a, b| a.size <=> b.size } # => ["0", "000"]
*
- * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
*/
static VALUE
rb_ary_minmax(VALUE ary)
@@ -6266,12 +6353,13 @@ rb_ary_uniq_bang(VALUE ary)
}
rb_ary_modify_check(ary);
ARY_SET_LEN(ary, 0);
- if (ARY_SHARED_P(ary)) {
+ if (ARY_SHARED_P(ary) && !ARY_EMBED_P(ary)) {
rb_ary_unshare(ary);
FL_SET_EMBED(ary);
}
ary_resize_capa(ary, hash_size);
rb_hash_foreach(hash, push_value, ary);
+ ary_recycle_hash(hash);
return ary;
}
@@ -6281,7 +6369,7 @@ rb_ary_uniq_bang(VALUE ary)
* array.uniq -> new_array
* array.uniq {|element| ... } -> new_array
*
- * Returns a new +Array+ containing those elements from +self+ that are not duplicates,
+ * Returns a new \Array containing those elements from +self+ that are not duplicates,
* the first occurrence always being retained.
*
* With no block given, identifies and omits duplicates using method <tt>eql?</tt>
@@ -6316,24 +6404,20 @@ rb_ary_uniq(VALUE ary)
hash = ary_make_hash(ary);
uniq = rb_hash_values(hash);
}
+ if (hash) {
+ ary_recycle_hash(hash);
+ }
return uniq;
}
/*
* call-seq:
- * compact! -> self or nil
+ * array.compact! -> self or nil
*
- * Removes all +nil+ elements from +self+;
- * Returns +self+ if any elements are removed, +nil+ otherwise:
+ * Removes all +nil+ elements from +self+.
*
- * a = [nil, 0, nil, false, nil, '', nil, [], nil, {}]
- * a.compact! # => [0, false, "", [], {}]
- * a # => [0, false, "", [], {}]
- * a.compact! # => nil
- *
- * Related: Array#compact;
- * see also {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
+ * Returns +self+ if any elements removed, otherwise +nil+.
*/
static VALUE
@@ -6343,14 +6427,14 @@ rb_ary_compact_bang(VALUE ary)
long n;
rb_ary_modify(ary);
- p = t = (VALUE *)RARRAY_CONST_PTR(ary); /* WB: no new reference */
+ p = t = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(ary); /* WB: no new reference */
end = p + RARRAY_LEN(ary);
while (t < end) {
if (NIL_P(*t)) t++;
else *p++ = *t++;
}
- n = p - RARRAY_CONST_PTR(ary);
+ n = p - RARRAY_CONST_PTR_TRANSIENT(ary);
if (RARRAY_LEN(ary) == n) {
return Qnil;
}
@@ -6361,16 +6445,12 @@ rb_ary_compact_bang(VALUE ary)
/*
* call-seq:
- * compact -> new_array
- *
- * Returns a new array containing only the non-+nil+ elements from +self+;
- * element order is preserved:
+ * array.compact -> new_array
*
- * a = [nil, 0, nil, false, nil, '', nil, [], nil, {}]
- * a.compact # => [0, false, "", [], {}]
+ * Returns a new \Array containing all non-+nil+ elements from +self+:
*
- * Related: Array#compact!;
- * see also {Methods for Deleting}[rdoc-ref:Array@Methods+for+Deleting].
+ * a = [nil, 0, nil, 1, nil, 2, nil]
+ * a.compact # => [0, 1, 2]
*/
static VALUE
@@ -6383,29 +6463,29 @@ rb_ary_compact(VALUE ary)
/*
* call-seq:
- * count -> integer
- * count(object) -> integer
- * count {|element| ... } -> integer
+ * array.count -> an_integer
+ * array.count(obj) -> an_integer
+ * array.count {|element| ... } -> an_integer
*
* Returns a count of specified elements.
*
* With no argument and no block, returns the count of all elements:
*
- * [0, :one, 'two', 3, 3.0].count # => 5
+ * [0, 1, 2].count # => 3
+ * [].count # => 0
*
- * With argument +object+ given, returns the count of elements <tt>==</tt> to +object+:
+ * With argument +obj+, returns the count of elements <tt>==</tt> to +obj+:
*
- * [0, :one, 'two', 3, 3.0].count(3) # => 2
+ * [0, 1, 2, 0.0].count(0) # => 2
+ * [0, 1, 2].count(3) # => 0
*
* With no argument and a block given, calls the block with each element;
* returns the count of elements for which the block returns a truthy value:
*
- * [0, 1, 2, 3].count {|element| element > 1 } # => 2
+ * [0, 1, 2, 3].count {|element| element > 1} # => 2
*
- * With argument +object+ and a block given, issues a warning, ignores the block,
- * and returns the count of elements <tt>==</tt> to +object+.
- *
- * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
+ * With argument +obj+ and a block given, issues a warning, ignores the block,
+ * and returns the count of elements <tt>==</tt> to +obj+.
*/
static VALUE
@@ -6442,8 +6522,9 @@ static VALUE
flatten(VALUE ary, int level)
{
long i;
- VALUE stack, result, tmp = 0, elt;
- VALUE memo = Qfalse;
+ VALUE stack, result, tmp = 0, elt, vmemo;
+ st_table *memo = 0;
+ st_data_t id;
for (i = 0; i < RARRAY_LEN(ary); i++) {
elt = RARRAY_AREF(ary, i);
@@ -6457,7 +6538,7 @@ flatten(VALUE ary, int level)
}
result = ary_new(0, RARRAY_LEN(ary));
- ary_memcpy(result, 0, i, RARRAY_CONST_PTR(ary));
+ ary_memcpy(result, 0, i, RARRAY_CONST_PTR_TRANSIENT(ary));
ARY_SET_LEN(result, i);
stack = ary_new(0, ARY_DEFAULT_SIZE);
@@ -6465,9 +6546,12 @@ flatten(VALUE ary, int level)
rb_ary_push(stack, LONG2NUM(i + 1));
if (level < 0) {
- memo = rb_obj_hide(rb_ident_hash_new());
- rb_hash_aset(memo, ary, Qtrue);
- rb_hash_aset(memo, tmp, Qtrue);
+ vmemo = rb_hash_new();
+ RBASIC_CLEAR_CLASS(vmemo);
+ memo = st_init_numtable();
+ rb_hash_st_table_set(vmemo, memo);
+ st_insert(memo, (st_data_t)ary, (st_data_t)Qtrue);
+ st_insert(memo, (st_data_t)tmp, (st_data_t)Qtrue);
}
ary = tmp;
@@ -6482,8 +6566,9 @@ flatten(VALUE ary, int level)
}
tmp = rb_check_array_type(elt);
if (RBASIC(result)->klass) {
- if (RTEST(memo)) {
- rb_hash_clear(memo);
+ if (memo) {
+ RB_GC_GUARD(vmemo);
+ st_clear(memo);
}
rb_raise(rb_eRuntimeError, "flatten reentered");
}
@@ -6492,11 +6577,12 @@ flatten(VALUE ary, int level)
}
else {
if (memo) {
- if (rb_hash_aref(memo, tmp) == Qtrue) {
- rb_hash_clear(memo);
+ id = (st_data_t)tmp;
+ if (st_is_member(memo, id)) {
+ st_clear(memo);
rb_raise(rb_eArgError, "tried to flatten recursive array");
}
- rb_hash_aset(memo, tmp, Qtrue);
+ st_insert(memo, id, (st_data_t)Qtrue);
}
rb_ary_push(stack, ary);
rb_ary_push(stack, LONG2NUM(i));
@@ -6508,7 +6594,8 @@ flatten(VALUE ary, int level)
break;
}
if (memo) {
- rb_hash_delete(memo, ary);
+ id = (st_data_t)ary;
+ st_delete(memo, &id, 0);
}
tmp = rb_ary_pop(stack);
i = NUM2LONG(tmp);
@@ -6516,7 +6603,7 @@ flatten(VALUE ary, int level)
}
if (memo) {
- rb_hash_clear(memo);
+ st_clear(memo);
}
RBASIC_SET_CLASS(result, rb_cArray);
@@ -6525,37 +6612,33 @@ flatten(VALUE ary, int level)
/*
* call-seq:
- * flatten!(depth = nil) -> self or nil
+ * array.flatten! -> self or nil
+ * array.flatten!(level) -> self or nil
*
- * Returns +self+ as a recursively flattening of +self+ to +depth+ levels of recursion;
- * +depth+ must be an
- * {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects],
- * or +nil+.
- * At each level of recursion:
+ * Replaces each nested \Array in +self+ with the elements from that \Array;
+ * returns +self+ if any changes, +nil+ otherwise.
*
- * - Each element that is an array is "flattened"
- * (that is, replaced by its individual array elements).
- * - Each element that is not an array is unchanged
- * (even if the element is an object that has instance method +flatten+).
+ * With non-negative \Integer argument +level+, flattens recursively through +level+ levels:
*
- * Returns +nil+ if no elements were flattened.
+ * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
+ * a.flatten!(1) # => [0, 1, [2, 3], 4, 5]
+ * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
+ * a.flatten!(2) # => [0, 1, 2, 3, 4, 5]
+ * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
+ * a.flatten!(3) # => [0, 1, 2, 3, 4, 5]
+ * [0, 1, 2].flatten!(1) # => nil
*
- * With non-negative integer argument +depth+, flattens recursively through +depth+ levels:
+ * With no argument, a +nil+ argument, or with negative argument +level+, flattens all levels:
*
- * a = [ 0, [ 1, [2, 3], 4 ], 5, {foo: 0}, Set.new([6, 7]) ]
- * a # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.dup.flatten!(1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.dup.flatten!(1.1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.dup.flatten!(2) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.dup.flatten!(3) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
+ * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
+ * a.flatten! # => [0, 1, 2, 3, 4, 5]
+ * [0, 1, 2].flatten! # => nil
+ * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
+ * a.flatten!(-1) # => [0, 1, 2, 3, 4, 5]
+ * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
+ * a.flatten!(-2) # => [0, 1, 2, 3, 4, 5]
+ * [0, 1, 2].flatten!(-1) # => nil
*
- * With +nil+ or negative argument +depth+, flattens all levels:
- *
- * a.dup.flatten! # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.dup.flatten!(-1) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- *
- * Related: Array#flatten;
- * see also {Methods for Assigning}[rdoc-ref:Array@Methods+for+Assigning].
*/
static VALUE
@@ -6573,7 +6656,7 @@ rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary)
if (result == ary) {
return Qnil;
}
- if (!(mod = ARY_EMBED_P(result))) rb_ary_freeze(result);
+ if (!(mod = ARY_EMBED_P(result))) rb_obj_freeze(result);
rb_ary_replace(ary, result);
if (mod) ARY_SET_EMBED_LEN(result, 0);
@@ -6582,37 +6665,35 @@ rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary)
/*
* call-seq:
- * flatten(depth = nil) -> new_array
- *
- * Returns a new array that is a recursive flattening of +self+
- * to +depth+ levels of recursion;
- * +depth+ must be an
- * {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects]
- * or +nil+.
- * At each level of recursion:
+ * array.flatten -> new_array
+ * array.flatten(level) -> new_array
+ *
+ * Returns a new \Array that is a recursive flattening of +self+:
+ * - Each non-Array element is unchanged.
+ * - Each \Array is replaced by its individual elements.
+ *
+ * With non-negative \Integer argument +level+, flattens recursively through +level+ levels:
+ *
+ * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
+ * a.flatten(0) # => [0, [1, [2, 3], 4], 5]
+ * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
+ * a.flatten(1) # => [0, 1, [2, 3], 4, 5]
+ * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
+ * a.flatten(2) # => [0, 1, 2, 3, 4, 5]
+ * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
+ * a.flatten(3) # => [0, 1, 2, 3, 4, 5]
+ *
+ * With no argument, a +nil+ argument, or with negative argument +level+, flattens all levels:
+ *
+ * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
+ * a.flatten # => [0, 1, 2, 3, 4, 5]
+ * [0, 1, 2].flatten # => [0, 1, 2]
+ * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
+ * a.flatten(-1) # => [0, 1, 2, 3, 4, 5]
+ * a = [ 0, [ 1, [2, 3], 4 ], 5 ]
+ * a.flatten(-2) # => [0, 1, 2, 3, 4, 5]
+ * [0, 1, 2].flatten(-1) # => [0, 1, 2]
*
- * - Each element that is an array is "flattened"
- * (that is, replaced by its individual array elements).
- * - Each element that is not an array is unchanged
- * (even if the element is an object that has instance method +flatten+).
- *
- * With non-negative integer argument +depth+, flattens recursively through +depth+ levels:
- *
- * a = [ 0, [ 1, [2, 3], 4 ], 5, {foo: 0}, Set.new([6, 7]) ]
- * a # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.flatten(0) # => [0, [1, [2, 3], 4], 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.flatten(1 ) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.flatten(1.1) # => [0, 1, [2, 3], 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.flatten(2) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.flatten(3) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- *
- * With +nil+ or negative +depth+, flattens all levels.
- *
- * a.flatten # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- * a.flatten(-1) # => [0, 1, 2, 3, 4, 5, {:foo=>0}, #<Set: {6, 7}>]
- *
- * Related: Array#flatten!;
- * see also {Methods for Converting}[rdoc-ref:Array@Methods+for+Converting].
*/
static VALUE
@@ -6647,7 +6728,7 @@ rb_ary_shuffle_bang(rb_execution_context_t *ec, VALUE ary, VALUE randgen)
while (i) {
long j = RAND_UPTO(i);
VALUE tmp;
- if (len != RARRAY_LEN(ary) || ptr != RARRAY_CONST_PTR(ary)) {
+ if (len != RARRAY_LEN(ary) || ptr != RARRAY_CONST_PTR_TRANSIENT(ary)) {
rb_raise(rb_eRuntimeError, "modified during shuffle");
}
tmp = ptr[--i];
@@ -6666,14 +6747,6 @@ rb_ary_shuffle(rb_execution_context_t *ec, VALUE ary, VALUE randgen)
return ary;
}
-static const rb_data_type_t ary_sample_memo_type = {
- .wrap_struct_name = "ary_sample_memo",
- .function = {
- .dfree = (RUBY_DATA_FUNC)st_free_table,
- },
- .flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
-};
-
static VALUE
ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE to_array)
{
@@ -6747,7 +6820,7 @@ ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE
sorted[j] = idx[i] = k;
}
result = rb_ary_new_capa(n);
- RARRAY_PTR_USE(result, ptr_result, {
+ RARRAY_PTR_USE_TRANSIENT(result, ptr_result, {
for (i=0; i<n; i++) {
ptr_result[i] = RARRAY_AREF(ary, idx[i]);
}
@@ -6755,9 +6828,11 @@ ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE
}
else if (n <= memo_threshold / 2) {
long max_idx = 0;
- VALUE vmemo = TypedData_Wrap_Struct(0, &ary_sample_memo_type, 0);
+#undef RUBY_UNTYPED_DATA_WARNING
+#define RUBY_UNTYPED_DATA_WARNING 0
+ VALUE vmemo = Data_Wrap_Struct(0, 0, st_free_table, 0);
st_table *memo = st_init_numtable_with_size(n);
- RTYPEDDATA_DATA(vmemo) = memo;
+ DATA_PTR(vmemo) = memo;
result = rb_ary_new_capa(n);
RARRAY_PTR_USE(result, ptr_result, {
for (i=0; i<n; i++) {
@@ -6768,7 +6843,7 @@ ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE
len = RARRAY_LEN(ary);
if (len <= max_idx) n = 0;
else if (n > len) n = len;
- RARRAY_PTR_USE(ary, ptr_ary, {
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr_ary, {
for (i=0; i<n; i++) {
long j2 = j = ptr_result[i];
long i2 = i;
@@ -6780,9 +6855,8 @@ ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE
}
});
});
- RTYPEDDATA_DATA(vmemo) = 0;
+ DATA_PTR(vmemo) = 0;
st_free_table(memo);
- RB_GC_GUARD(vmemo);
}
else {
result = rb_ary_dup(ary);
@@ -6827,36 +6901,36 @@ rb_ary_cycle_size(VALUE self, VALUE args, VALUE eobj)
/*
* call-seq:
- * cycle(count = nil) {|element| ... } -> nil
- * cycle(count = nil) -> new_enumerator
+ * array.cycle {|element| ... } -> nil
+ * array.cycle(count) {|element| ... } -> nil
+ * array.cycle -> new_enumerator
+ * array.cycle(count) -> new_enumerator
*
- * With a block given, may call the block, depending on the value of argument +count+;
- * +count+ must be an
- * {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects],
- * or +nil+.
- *
- * When +count+ is positive,
- * calls the block with each element, then does so repeatedly,
+ * When called with positive \Integer argument +count+ and a block,
+ * calls the block with each element, then does so again,
* until it has done so +count+ times; returns +nil+:
*
* output = []
* [0, 1].cycle(2) {|element| output.push(element) } # => nil
* output # => [0, 1, 0, 1]
*
- * When +count+ is zero or negative, does not call the block:
+ * If +count+ is zero or negative, does not call the block:
*
- * [0, 1].cycle(0) {|element| fail 'Cannot happen' } # => nil
+ * [0, 1].cycle(0) {|element| fail 'Cannot happen' } # => nil
* [0, 1].cycle(-1) {|element| fail 'Cannot happen' } # => nil
*
- * When +count+ is +nil+, cycles forever:
+ * When a block is given, and argument is omitted or +nil+, cycles forever:
*
* # Prints 0 and 1 forever.
* [0, 1].cycle {|element| puts element }
* [0, 1].cycle(nil) {|element| puts element }
*
- * With no block given, returns a new Enumerator.
+ * When no block is given, returns a new \Enumerator:
+ *
+ * [0, 1].cycle(2) # => #<Enumerator: [0, 1]:cycle(2)>
+ * [0, 1].cycle # => # => #<Enumerator: [0, 1]:cycle>
+ * [0, 1].cycle.first(5) # => [0, 1, 0, 1, 0]
*
- * Related: see {Methods for Iterating}[rdoc-ref:Array@Methods+for+Iterating].
*/
static VALUE
rb_ary_cycle(int argc, VALUE *argv, VALUE ary)
@@ -7008,7 +7082,7 @@ rb_ary_permutation_size(VALUE ary, VALUE args, VALUE eobj)
* When invoked with a block, yield all permutations of elements of +self+; returns +self+.
* The order of permutations is indeterminate.
*
- * When a block and an in-range positive Integer argument +n+ (<tt>0 < n <= self.size</tt>)
+ * When a block and an in-range positive \Integer argument +n+ (<tt>0 < n <= self.size</tt>)
* are given, calls the block with all +n+-tuple permutations of +self+.
*
* Example:
@@ -7039,7 +7113,7 @@ rb_ary_permutation_size(VALUE ary, VALUE args, VALUE eobj)
* [2, 0, 1]
* [2, 1, 0]
*
- * When +n+ is zero, calls the block once with a new empty +Array+:
+ * When +n+ is zero, calls the block once with a new empty \Array:
*
* a = [0, 1, 2]
* a.permutation(0) {|permutation| p permutation }
@@ -7070,7 +7144,7 @@ rb_ary_permutation_size(VALUE ary, VALUE args, VALUE eobj)
* [2, 0, 1]
* [2, 1, 0]
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [0, 1, 2]
* a.permutation # => #<Enumerator: [0, 1, 2]:permutation>
@@ -7148,46 +7222,56 @@ rb_ary_combination_size(VALUE ary, VALUE args, VALUE eobj)
/*
* call-seq:
- * combination(n) {|element| ... } -> self
- * combination(n) -> new_enumerator
+ * array.combination(n) {|element| ... } -> self
+ * array.combination(n) -> new_enumerator
*
- * When a block and a positive
- * {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects]
- * argument +n+ (<tt>0 < n <= self.size</tt>)
- * are given, calls the block with all +n+-tuple combinations of +self+;
- * returns +self+:
+ * Calls the block, if given, with combinations of elements of +self+;
+ * returns +self+. The order of combinations is indeterminate.
+ *
+ * When a block and an in-range positive \Integer argument +n+ (<tt>0 < n <= self.size</tt>)
+ * are given, calls the block with all +n+-tuple combinations of +self+.
+ *
+ * Example:
*
- * a = %w[a b c] # => ["a", "b", "c"]
- * a.combination(2) {|combination| p combination } # => ["a", "b", "c"]
+ * a = [0, 1, 2]
+ * a.combination(2) {|combination| p combination }
*
* Output:
*
- * ["a", "b"]
- * ["a", "c"]
- * ["b", "c"]
+ * [0, 1]
+ * [0, 2]
+ * [1, 2]
*
- * The order of the yielded combinations is not guaranteed.
+ * Another example:
*
- * When +n+ is zero, calls the block once with a new empty array:
+ * a = [0, 1, 2]
+ * a.combination(3) {|combination| p combination }
*
- * a.combination(0) {|combination| p combination }
- * [].combination(0) {|combination| p combination }
+ * Output:
+ *
+ * [0, 1, 2]
+ *
+ * When +n+ is zero, calls the block once with a new empty \Array:
+ *
+ * a = [0, 1, 2]
+ * a1 = a.combination(0) {|combination| p combination }
*
* Output:
*
* []
- * []
*
- * When +n+ is negative or larger than +self.size+ and +self+ is non-empty,
+ * When +n+ is out of range (negative or larger than <tt>self.size</tt>),
* does not call the block:
*
- * a.combination(-1) {|combination| fail 'Cannot happen' } # => ["a", "b", "c"]
- * a.combination(4) {|combination| fail 'Cannot happen' } # => ["a", "b", "c"]
+ * a = [0, 1, 2]
+ * a.combination(-1) {|combination| fail 'Cannot happen' }
+ * a.combination(4) {|combination| fail 'Cannot happen' }
+ *
+ * Returns a new \Enumerator if no block given:
*
- * With no block given, returns a new Enumerator.
+ * a = [0, 1, 2]
+ * a.combination(2) # => #<Enumerator: [0, 1, 2]:combination(2)>
*
- * Related: Array#permutation;
- * see also {Methods for Iterating}[rdoc-ref:Array@Methods+for+Iterating].
*/
static VALUE
@@ -7278,10 +7362,10 @@ rb_ary_repeated_permutation_size(VALUE ary, VALUE args, VALUE eobj)
* array.repeated_permutation(n) -> new_enumerator
*
* Calls the block with each repeated permutation of length +n+ of the elements of +self+;
- * each permutation is an +Array+;
+ * each permutation is an \Array;
* returns +self+. The order of the permutations is indeterminate.
*
- * When a block and a positive Integer argument +n+ are given, calls the block with each
+ * When a block and a positive \Integer argument +n+ are given, calls the block with each
* +n+-tuple repeated permutation of the elements of +self+.
* The number of permutations is <tt>self.size**n</tt>.
*
@@ -7312,13 +7396,13 @@ rb_ary_repeated_permutation_size(VALUE ary, VALUE args, VALUE eobj)
* [2, 1]
* [2, 2]
*
- * If +n+ is zero, calls the block once with an empty +Array+.
+ * If +n+ is zero, calls the block once with an empty \Array.
*
* If +n+ is negative, does not call the block:
*
* a.repeated_permutation(-1) {|permutation| fail 'Cannot happen' }
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [0, 1, 2]
* a.repeated_permutation(2) # => #<Enumerator: [0, 1, 2]:permutation(2)>
@@ -7410,10 +7494,10 @@ rb_ary_repeated_combination_size(VALUE ary, VALUE args, VALUE eobj)
* array.repeated_combination(n) -> new_enumerator
*
* Calls the block with each repeated combination of length +n+ of the elements of +self+;
- * each combination is an +Array+;
+ * each combination is an \Array;
* returns +self+. The order of the combinations is indeterminate.
*
- * When a block and a positive Integer argument +n+ are given, calls the block with each
+ * When a block and a positive \Integer argument +n+ are given, calls the block with each
* +n+-tuple repeated combination of the elements of +self+.
* The number of combinations is <tt>(n+1)(n+2)/2</tt>.
*
@@ -7441,13 +7525,13 @@ rb_ary_repeated_combination_size(VALUE ary, VALUE args, VALUE eobj)
* [1, 2]
* [2, 2]
*
- * If +n+ is zero, calls the block once with an empty +Array+.
+ * If +n+ is zero, calls the block once with an empty \Array.
*
* If +n+ is negative, does not call the block:
*
* a.repeated_combination(-1) {|combination| fail 'Cannot happen' }
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
*
* a = [0, 1, 2]
* a.repeated_combination(2) # => #<Enumerator: [0, 1, 2]:combination(2)>
@@ -7514,7 +7598,7 @@ rb_ary_repeated_combination(VALUE ary, VALUE num)
* including both +self+ and +other_arrays+.
* - The order of the returned combinations is indeterminate.
*
- * When no block is given, returns the combinations as an +Array+ of Arrays:
+ * When no block is given, returns the combinations as an \Array of Arrays:
*
* a = [0, 1, 2]
* a1 = [3, 4]
@@ -7526,14 +7610,14 @@ rb_ary_repeated_combination(VALUE ary, VALUE num)
* p.size # => 12 # a.size * a1.size * a2.size
* p # => [[0, 3, 5], [0, 3, 6], [0, 4, 5], [0, 4, 6], [1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6]]
*
- * If any argument is an empty +Array+, returns an empty +Array+.
+ * If any argument is an empty \Array, returns an empty \Array.
*
- * If no argument is given, returns an +Array+ of 1-element Arrays,
+ * If no argument is given, returns an \Array of 1-element Arrays,
* each containing an element of +self+:
*
* a.product # => [[0], [1], [2]]
*
- * When a block is given, yields each combination as an +Array+; returns +self+:
+ * When a block is given, yields each combination as an \Array; returns +self+:
*
* a.product(a1) {|combination| p combination }
*
@@ -7546,11 +7630,11 @@ rb_ary_repeated_combination(VALUE ary, VALUE num)
* [2, 3]
* [2, 4]
*
- * If any argument is an empty +Array+, does not call the block:
+ * If any argument is an empty \Array, does not call the block:
*
* a.product(a1, a2, []) {|combination| fail 'Cannot happen' }
*
- * If no argument is given, yields each element of +self+ as a 1-element +Array+:
+ * If no argument is given, yields each element of +self+ as a 1-element \Array:
*
* a.product {|combination| p combination }
*
@@ -7654,8 +7738,8 @@ done:
* call-seq:
* array.take(n) -> new_array
*
- * Returns a new +Array+ containing the first +n+ element of +self+,
- * where +n+ is a non-negative Integer;
+ * Returns a new \Array containing the first +n+ element of +self+,
+ * where +n+ is a non-negative \Integer;
* does not modify +self+.
*
* Examples:
@@ -7683,19 +7767,19 @@ rb_ary_take(VALUE obj, VALUE n)
* array.take_while {|element| ... } -> new_array
* array.take_while -> new_enumerator
*
- * Returns a new +Array+ containing zero or more leading elements of +self+;
+ * Returns a new \Array containing zero or more leading elements of +self+;
* does not modify +self+.
*
* With a block given, calls the block with each successive element of +self+;
* stops if the block returns +false+ or +nil+;
- * returns a new +Array+ containing those elements for which the block returned a truthy value:
+ * returns a new \Array containing those elements for which the block returned a truthy value:
*
* a = [0, 1, 2, 3, 4, 5]
* a.take_while {|element| element < 3 } # => [0, 1, 2]
* a.take_while {|element| true } # => [0, 1, 2, 3, 4, 5]
* a # => [0, 1, 2, 3, 4, 5]
*
- * With no block given, returns a new Enumerator:
+ * With no block given, returns a new \Enumerator:
*
* [0, 1].take_while # => #<Enumerator: [0, 1]:take_while>
*
@@ -7715,10 +7799,10 @@ rb_ary_take_while(VALUE ary)
/*
* call-seq:
- * drop(n) -> new_array
+ * array.drop(n) -> new_array
*
- * Returns a new array containing all but the first +n+ element of +self+,
- * where +n+ is a non-negative Integer;
+ * Returns a new \Array containing all but the first +n+ element of +self+,
+ * where +n+ is a non-negative \Integer;
* does not modify +self+.
*
* Examples:
@@ -7727,9 +7811,7 @@ rb_ary_take_while(VALUE ary)
* a.drop(0) # => [0, 1, 2, 3, 4, 5]
* a.drop(1) # => [1, 2, 3, 4, 5]
* a.drop(2) # => [2, 3, 4, 5]
- * a.drop(9) # => []
*
- * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
*/
static VALUE
@@ -7748,20 +7830,23 @@ rb_ary_drop(VALUE ary, VALUE n)
/*
* call-seq:
- * drop_while {|element| ... } -> new_array
- * drop_while -> new_enumerator
+ * array.drop_while {|element| ... } -> new_array
+ * array.drop_while -> new_enumerator
+
+ * Returns a new \Array containing zero or more trailing elements of +self+;
+ * does not modify +self+.
*
* With a block given, calls the block with each successive element of +self+;
* stops if the block returns +false+ or +nil+;
- * returns a new array _omitting_ those elements for which the block returned a truthy value;
- * does not modify +self+:
+ * returns a new \Array _omitting_ those elements for which the block returned a truthy value:
*
* a = [0, 1, 2, 3, 4, 5]
* a.drop_while {|element| element < 3 } # => [3, 4, 5]
*
- * With no block given, returns a new Enumerator.
+ * With no block given, returns a new \Enumerator:
+ *
+ * [0, 1].drop_while # => # => #<Enumerator: [0, 1]:drop_while>
*
- * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
*/
static VALUE
@@ -7778,41 +7863,35 @@ rb_ary_drop_while(VALUE ary)
/*
* call-seq:
- * any? -> true or false
- * any?(object) -> true or false
- * any? {|element| ... } -> true or false
- *
- * Returns whether for any element of +self+, a given criterion is satisfied.
+ * array.any? -> true or false
+ * array.any? {|element| ... } -> true or false
+ * array.any?(obj) -> true or false
*
- * With no block and no argument, returns whether any element of +self+ is truthy:
+ * Returns +true+ if any element of +self+ meets a given criterion.
*
- * [nil, false, []].any? # => true # Array object is truthy.
- * [nil, false, {}].any? # => true # Hash object is truthy.
- * [nil, false, ''].any? # => true # String object is truthy.
- * [nil, false].any? # => false # Nil and false are not truthy.
- *
- * With argument +object+ given,
- * returns whether <tt>object === ele</tt> for any element +ele+ in +self+:
+ * With no block given and no argument, returns +true+ if +self+ has any truthy element,
+ * +false+ otherwise:
*
- * [nil, false, 0].any?(0) # => true
- * [nil, false, 1].any?(0) # => false
- * [nil, false, 'food'].any?(/foo/) # => true
- * [nil, false, 'food'].any?(/bar/) # => false
+ * [nil, 0, false].any? # => true
+ * [nil, false].any? # => false
+ * [].any? # => false
*
- * With a block given,
- * calls the block with each element in +self+;
- * returns whether the block returns any truthy value:
+ * With a block given and no argument, calls the block with each element in +self+;
+ * returns +true+ if the block returns any truthy value, +false+ otherwise:
*
- * [0, 1, 2].any? {|ele| ele < 1 } # => true
- * [0, 1, 2].any? {|ele| ele < 0 } # => false
+ * [0, 1, 2].any? {|element| element > 1 } # => true
+ * [0, 1, 2].any? {|element| element > 2 } # => false
*
- * With both a block and argument +object+ given,
- * ignores the block and uses +object+ as above.
+ * If argument +obj+ is given, returns +true+ if +obj+.<tt>===</tt> any element,
+ * +false+ otherwise:
*
- * <b>Special case</b>: returns +false+ if +self+ is empty
- * (regardless of any given argument or block).
+ * ['food', 'drink'].any?(/foo/) # => true
+ * ['food', 'drink'].any?(/bar/) # => false
+ * [].any?(/foo/) # => false
+ * [0, 1, 2].any?(1) # => true
+ * [0, 1, 2].any?(3) # => false
*
- * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
+ * Related: Enumerable#any?
*/
static VALUE
@@ -7845,41 +7924,34 @@ rb_ary_any_p(int argc, VALUE *argv, VALUE ary)
/*
* call-seq:
- * all? -> true or false
- * all?(object) -> true or false
- * all? {|element| ... } -> true or false
- *
- * Returns whether for every element of +self+,
- * a given criterion is satisfied.
- *
- * With no block and no argument,
- * returns whether every element of +self+ is truthy:
+ * array.all? -> true or false
+ * array.all? {|element| ... } -> true or false
+ * array.all?(obj) -> true or false
*
- * [[], {}, '', 0, 0.0, Object.new].all? # => true # All truthy objects.
- * [[], {}, '', 0, 0.0, nil].all? # => false # nil is not truthy.
- * [[], {}, '', 0, 0.0, false].all? # => false # false is not truthy.
+ * Returns +true+ if all elements of +self+ meet a given criterion.
*
- * With argument +object+ given, returns whether <tt>object === ele</tt>
- * for every element +ele+ in +self+:
+ * With no block given and no argument, returns +true+ if +self+ contains only truthy elements,
+ * +false+ otherwise:
*
- * [0, 0, 0].all?(0) # => true
- * [0, 1, 2].all?(1) # => false
- * ['food', 'fool', 'foot'].all?(/foo/) # => true
- * ['food', 'drink'].all?(/foo/) # => false
+ * [0, 1, :foo].all? # => true
+ * [0, nil, 2].all? # => false
+ * [].all? # => true
*
- * With a block given, calls the block with each element in +self+;
- * returns whether the block returns only truthy values:
+ * With a block given and no argument, calls the block with each element in +self+;
+ * returns +true+ if the block returns only truthy values, +false+ otherwise:
*
- * [0, 1, 2].all? { |ele| ele < 3 } # => true
- * [0, 1, 2].all? { |ele| ele < 2 } # => false
+ * [0, 1, 2].all? { |element| element < 3 } # => true
+ * [0, 1, 2].all? { |element| element < 2 } # => false
*
- * With both a block and argument +object+ given,
- * ignores the block and uses +object+ as above.
+ * If argument +obj+ is given, returns +true+ if <tt>obj.===</tt> every element, +false+ otherwise:
*
- * <b>Special case</b>: returns +true+ if +self+ is empty
- * (regardless of any given argument or block).
+ * ['food', 'fool', 'foot'].all?(/foo/) # => true
+ * ['food', 'drink'].all?(/bar/) # => false
+ * [].all?(/foo/) # => true
+ * [0, 0, 0].all?(0) # => true
+ * [0, 1, 2].all?(1) # => false
*
- * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
+ * Related: Enumerable#all?
*/
static VALUE
@@ -7912,35 +7984,34 @@ rb_ary_all_p(int argc, VALUE *argv, VALUE ary)
/*
* call-seq:
- * none? -> true or false
- * none?(object) -> true or false
- * none? {|element| ... } -> true or false
+ * array.none? -> true or false
+ * array.none? {|element| ... } -> true or false
+ * array.none?(obj) -> true or false
*
- * Returns +true+ if no element of +self+ meets a given criterion, +false+ otherwise.
+ * Returns +true+ if no element of +self+ meet a given criterion.
*
* With no block given and no argument, returns +true+ if +self+ has no truthy elements,
* +false+ otherwise:
*
- * [nil, false].none? # => true
+ * [nil, false].none? # => true
* [nil, 0, false].none? # => false
- * [].none? # => true
- *
- * With argument +object+ given, returns +false+ if for any element +element+,
- * <tt>object === element</tt>; +true+ otherwise:
- *
- * ['food', 'drink'].none?(/bar/) # => true
- * ['food', 'drink'].none?(/foo/) # => false
- * [].none?(/foo/) # => true
- * [0, 1, 2].none?(3) # => true
- * [0, 1, 2].none?(1) # => false
+ * [].none? # => true
*
- * With a block given, calls the block with each element in +self+;
+ * With a block given and no argument, calls the block with each element in +self+;
* returns +true+ if the block returns no truthy value, +false+ otherwise:
*
* [0, 1, 2].none? {|element| element > 3 } # => true
* [0, 1, 2].none? {|element| element > 1 } # => false
*
- * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
+ * If argument +obj+ is given, returns +true+ if <tt>obj.===</tt> no element, +false+ otherwise:
+ *
+ * ['food', 'drink'].none?(/bar/) # => true
+ * ['food', 'drink'].none?(/foo/) # => false
+ * [].none?(/foo/) # => true
+ * [0, 1, 2].none?(3) # => true
+ * [0, 1, 2].none?(1) # => false
+ *
+ * Related: Enumerable#none?
*/
static VALUE
@@ -7973,9 +8044,9 @@ rb_ary_none_p(int argc, VALUE *argv, VALUE ary)
/*
* call-seq:
- * one? -> true or false
- * one? {|element| ... } -> true or false
- * one?(object) -> true or false
+ * array.one? -> true or false
+ * array.one? {|element| ... } -> true or false
+ * array.one?(obj) -> true or false
*
* Returns +true+ if exactly one element of +self+ meets a given criterion.
*
@@ -7987,14 +8058,14 @@ rb_ary_none_p(int argc, VALUE *argv, VALUE ary)
* [nil, nil].one? # => false
* [].one? # => false
*
- * With a block given, calls the block with each element in +self+;
+ * With a block given and no argument, calls the block with each element in +self+;
* returns +true+ if the block a truthy value for exactly one element, +false+ otherwise:
*
* [0, 1, 2].one? {|element| element > 0 } # => false
* [0, 1, 2].one? {|element| element > 1 } # => true
* [0, 1, 2].one? {|element| element > 2 } # => false
*
- * With argument +object+ given, returns +true+ if for exactly one element +element+, <tt>object === element</tt>;
+ * If argument +obj+ is given, returns +true+ if <tt>obj.===</tt> exactly one element,
* +false+ otherwise:
*
* [0, 1, 2].one?(0) # => true
@@ -8004,7 +8075,7 @@ rb_ary_none_p(int argc, VALUE *argv, VALUE ary)
* ['food', 'drink'].one?(/foo/) # => true
* [].one?(/foo/) # => false
*
- * Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
+ * Related: Enumerable#one?
*/
static VALUE
@@ -8049,9 +8120,9 @@ rb_ary_one_p(int argc, VALUE *argv, VALUE ary)
* call-seq:
* array.dig(index, *identifiers) -> object
*
- * Finds and returns the object in nested object
- * specified by +index+ and +identifiers+;
- * the nested objects may be instances of various classes.
+ * Finds and returns the object in nested objects
+ * that is specified by +index+ and +identifiers+.
+ * The nested objects may be instances of various classes.
* See {Dig Methods}[rdoc-ref:dig_methods.rdoc].
*
* Examples:
@@ -8062,7 +8133,6 @@ rb_ary_one_p(int argc, VALUE *argv, VALUE ary)
* a.dig(1, 2, 0) # => :bat
* a.dig(1, 2, 3) # => nil
*
- * Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
*/
static VALUE
@@ -8124,7 +8194,7 @@ finish_exact_sum(long n, VALUE r, VALUE v, int z)
* Notes:
*
* - Array#join and Array#flatten may be faster than Array#sum
- * for an +Array+ of Strings or an +Array+ of Arrays.
+ * for an \Array of Strings or an \Array of Arrays.
* - Array#sum method may not respect method redefinition of "+" methods such as Integer#+.
*
*/
@@ -8145,12 +8215,6 @@ rb_ary_sum(int argc, VALUE *argv, VALUE ary)
n = 0;
r = Qundef;
-
- if (!FIXNUM_P(v) && !RB_BIGNUM_TYPE_P(v) && !RB_TYPE_P(v, T_RATIONAL)) {
- i = 0;
- goto init_is_a_value;
- }
-
for (i = 0; i < RARRAY_LEN(ary); i++) {
e = RARRAY_AREF(ary, i);
if (block_given)
@@ -8235,7 +8299,6 @@ rb_ary_sum(int argc, VALUE *argv, VALUE ary)
}
goto has_some_value;
- init_is_a_value:
for (; i < RARRAY_LEN(ary); i++) {
e = RARRAY_AREF(ary, i);
if (block_given)
@@ -8246,7 +8309,6 @@ rb_ary_sum(int argc, VALUE *argv, VALUE ary)
return v;
}
-/* :nodoc: */
static VALUE
rb_ary_deconstruct(VALUE ary)
{
@@ -8254,13 +8316,13 @@ rb_ary_deconstruct(VALUE ary)
}
/*
- * An +Array+ is an ordered, integer-indexed collection of objects, called _elements_.
+ * An \Array is an ordered, integer-indexed collection of objects, called _elements_.
* Any object (even another array) may be an array element,
* and an array can contain objects of different types.
*
- * == +Array+ Indexes
+ * == \Array Indexes
*
- * +Array+ indexing starts at 0, as in C or Java.
+ * \Array indexing starts at 0, as in C or Java.
*
* A positive index is an offset from the first element:
*
@@ -8287,14 +8349,14 @@ rb_ary_deconstruct(VALUE ary)
* - Index -4 is out of range.
*
* Although the effective index into an array is always an integer,
- * some methods (both within and outside of class +Array+)
+ * some methods (both within and outside of class \Array)
* accept one or more non-integer arguments that are
* {integer-convertible objects}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects].
*
*
* == Creating Arrays
*
- * You can create an +Array+ object explicitly with:
+ * You can create an \Array object explicitly with:
*
* - An {array literal}[rdoc-ref:literals.rdoc@Array+Literals]:
*
@@ -8375,7 +8437,7 @@ rb_ary_deconstruct(VALUE ary)
* == Example Usage
*
* In addition to the methods it mixes in through the Enumerable module, the
- * +Array+ class has proprietary methods for accessing, searching and otherwise
+ * \Array class has proprietary methods for accessing, searching and otherwise
* manipulating arrays.
*
* Some of the more common ones are illustrated below.
@@ -8423,7 +8485,7 @@ rb_ary_deconstruct(VALUE ary)
*
* arr.drop(3) #=> [4, 5, 6]
*
- * == Obtaining Information about an +Array+
+ * == Obtaining Information about an \Array
*
* Arrays keep track of their own length at all times. To query an array
* about the number of elements it contains, use #length, #count or #size.
@@ -8461,7 +8523,7 @@ rb_ary_deconstruct(VALUE ary)
* arr.insert(3, 'orange', 'pear', 'grapefruit')
* #=> [0, 1, 2, "orange", "pear", "grapefruit", "apple", 3, 4, 5, 6]
*
- * == Removing Items from an +Array+
+ * == Removing Items from an \Array
*
* The method #pop removes the last element in an array and returns it:
*
@@ -8503,9 +8565,9 @@ rb_ary_deconstruct(VALUE ary)
*
* == Iterating over Arrays
*
- * Like all classes that include the Enumerable module, +Array+ has an each
+ * Like all classes that include the Enumerable module, \Array has an each
* method, which defines what elements should be iterated over and how. In
- * case of Array's #each, all elements in the +Array+ instance are yielded to
+ * case of Array's #each, all elements in the \Array instance are yielded to
* the supplied block in sequence.
*
* Note that this operation leaves the array unchanged.
@@ -8532,7 +8594,7 @@ rb_ary_deconstruct(VALUE ary)
* arr #=> [1, 4, 9, 16, 25]
*
*
- * == Selecting Items from an +Array+
+ * == Selecting Items from an \Array
*
* Elements can be selected from an array according to criteria defined in a
* block. The selection can happen in a destructive or a non-destructive
@@ -8565,13 +8627,13 @@ rb_ary_deconstruct(VALUE ary)
*
* == What's Here
*
- * First, what's elsewhere. \Class +Array+:
+ * First, what's elsewhere. \Class \Array:
*
* - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
* - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
* which provides dozens of additional methods.
*
- * Here, class +Array+ provides methods that are useful for:
+ * Here, class \Array provides methods that are useful for:
*
* - {Creating an Array}[rdoc-ref:Array@Methods+for+Creating+an+Array]
* - {Querying}[rdoc-ref:Array@Methods+for+Querying]
@@ -8584,17 +8646,15 @@ rb_ary_deconstruct(VALUE ary)
* - {Converting}[rdoc-ref:Array@Methods+for+Converting]
* - {And more....}[rdoc-ref:Array@Other+Methods]
*
- * === Methods for Creating an +Array+
+ * === Methods for Creating an \Array
*
* - ::[]: Returns a new array populated with given objects.
* - ::new: Returns a new array.
* - ::try_convert: Returns a new array created from a given object.
*
- * See also {Creating Arrays}[rdoc-ref:Array@Creating+Arrays].
- *
* === Methods for Querying
*
- * - #length (aliased as #size): Returns the count of elements.
+ * - #length, #size: Returns the count of elements.
* - #include?: Returns whether any element <tt>==</tt> a given object.
* - #empty?: Returns whether there are no elements.
* - #all?: Returns whether all elements meet a given criterion.
@@ -8602,13 +8662,13 @@ rb_ary_deconstruct(VALUE ary)
* - #none?: Returns whether no element <tt>==</tt> a given object.
* - #one?: Returns whether exactly one element <tt>==</tt> a given object.
* - #count: Returns the count of elements that meet a given criterion.
- * - #find_index (aliased as #index): Returns the index of the first element that meets a given criterion.
+ * - #find_index, #index: Returns the index of the first element that meets a given criterion.
* - #rindex: Returns the index of the last element that meets a given criterion.
* - #hash: Returns the integer hash code.
*
* === Methods for Comparing
*
- * - #<=>: Returns -1, 0, or 1, as +self+ is less than, equal to, or
+ * - #<=>: Returns -1, 0, or 1 * as +self+ is less than, equal to, or
* greater than a given object.
* - #==: Returns whether each element in +self+ is <tt>==</tt> to the corresponding element
* in a given object.
@@ -8619,17 +8679,16 @@ rb_ary_deconstruct(VALUE ary)
*
* These methods do not modify +self+.
*
- * - #[] (aliased as #slice): Returns consecutive elements as determined by a given argument.
+ * - #[]: Returns one or more elements.
* - #fetch: Returns the element at a given offset.
- * - #fetch_values: Returns elements at given offsets.
* - #first: Returns one or more leading elements.
* - #last: Returns one or more trailing elements.
* - #max: Returns one or more maximum-valued elements,
- * as determined by <tt>#<=></tt> or a given block.
+ * as determined by <tt><=></tt> or a given block.
* - #min: Returns one or more minimum-valued elements,
- * as determined by <tt>#<=></tt> or a given block.
+ * as determined by <tt><=></tt> or a given block.
* - #minmax: Returns the minimum-valued and maximum-valued elements,
- * as determined by <tt>#<=></tt> or a given block.
+ * as determined by <tt><=></tt> or a given block.
* - #assoc: Returns the first element that is an array
* whose first element <tt>==</tt> a given object.
* - #rassoc: Returns the first element that is an array
@@ -8642,10 +8701,11 @@ rb_ary_deconstruct(VALUE ary)
* - #take: Returns leading elements as determined by a given index.
* - #drop_while: Returns trailing elements as determined by a given block.
* - #take_while: Returns leading elements as determined by a given block.
- * - #sort: Returns all elements in an order determined by <tt>#<=></tt> or a given block.
+ * - #slice: Returns consecutive elements as determined by a given argument.
+ * - #sort: Returns all elements in an order determined by <tt><=></tt> or a given block.
* - #reverse: Returns all elements in reverse order.
* - #compact: Returns an array containing all non-+nil+ elements.
- * - #select (aliased as #filter): Returns an array containing elements selected by a given block.
+ * - #select, #filter: Returns an array containing elements selected by a given block.
* - #uniq: Returns an array containing non-duplicate elements.
* - #rotate: Returns all elements with some rotated from one end to the other.
* - #bsearch: Returns an element selected via a binary search
@@ -8660,19 +8720,17 @@ rb_ary_deconstruct(VALUE ary)
* These methods add, replace, or reorder elements in +self+.
*
* - #[]=: Assigns specified elements with a given object.
- * - #<<: Appends an element.
- * - #push (aliased as #append): Appends elements.
- * - #unshift (aliased as #prepend): Prepends leading elements.
+ * - #push, #append, #<<: Appends trailing elements.
+ * - #unshift, #prepend: Prepends leading elements.
* - #insert: Inserts given objects at a given offset; does not replace elements.
* - #concat: Appends all elements from given arrays.
* - #fill: Replaces specified elements with specified objects.
- * - #flatten!: Replaces each nested array in +self+ with the elements from that array.
- * - #initialize_copy (aliased as #replace): Replaces the content of +self+ with the content of a given array.
+ * - #replace: Replaces the content of +self+ with the content of a given array.
* - #reverse!: Replaces +self+ with its elements reversed.
* - #rotate!: Replaces +self+ with its elements rotated.
* - #shuffle!: Replaces +self+ with its elements in random order.
* - #sort!: Replaces +self+ with its elements sorted,
- * as determined by <tt>#<=></tt> or a given block.
+ * as determined by <tt><=></tt> or a given block.
* - #sort_by!: Replaces +self+ with its elements sorted, as determined by a given block.
*
* === Methods for Deleting
@@ -8685,10 +8743,9 @@ rb_ary_deconstruct(VALUE ary)
* - #delete: Removes elements equal to a given object.
* - #delete_at: Removes the element at a given offset.
* - #delete_if: Removes elements specified by a given block.
- * - #clear: Removes all elements.
* - #keep_if: Removes elements not specified by a given block.
* - #reject!: Removes elements specified by a given block.
- * - #select! (aliased as #filter!): Removes elements not specified by a given block.
+ * - #select!, #filter!: Removes elements not specified by a given block.
* - #slice!: Removes and returns a sequence of elements.
* - #uniq!: Removes duplicates.
*
@@ -8725,10 +8782,11 @@ rb_ary_deconstruct(VALUE ary)
*
* === Methods for Converting
*
- * - #collect (aliased as #map): Returns an array containing the block return-value for each element.
- * - #collect! (aliased as #map!): Replaces each element with a block return-value.
+ * - #map, #collect: Returns an array containing the block return-value for each element.
+ * - #map!, #collect!: Replaces each element with a block return-value.
* - #flatten: Returns an array that is a recursive flattening of +self+.
- * - #inspect (aliased as #to_s): Returns a new String containing the elements.
+ * - #flatten!: Replaces each nested array in +self+ with the elements from that array.
+ * - #inspect, #to_s: Returns a new String containing the elements.
* - #join: Returns a newsString containing the elements joined by the field separator.
* - #to_a: Returns +self+ or a new array containing all elements.
* - #to_ary: Returns +self+.
@@ -8746,6 +8804,7 @@ rb_ary_deconstruct(VALUE ary)
* - With string argument +field_separator+, a new string that is equivalent to
* <tt>join(field_separator)</tt>.
*
+ * - #abbrev: Returns a hash of unambiguous abbreviations for elements.
* - #pack: Packs the elements into a binary sequence.
* - #sum: Returns a sum of elements according to either <tt>+</tt> or a given block.
*/
@@ -8753,8 +8812,6 @@ rb_ary_deconstruct(VALUE ary)
void
Init_Array(void)
{
- fake_ary_flags = init_fake_ary_flags();
-
rb_cArray = rb_define_class("Array", rb_cObject);
rb_include_module(rb_cArray, rb_mEnumerable);
@@ -8779,6 +8836,8 @@ Init_Array(void)
rb_define_method(rb_cArray, "[]=", rb_ary_aset, -1);
rb_define_method(rb_cArray, "at", rb_ary_at, 1);
rb_define_method(rb_cArray, "fetch", rb_ary_fetch, -1);
+ rb_define_method(rb_cArray, "first", rb_ary_first, -1);
+ rb_define_method(rb_cArray, "last", rb_ary_last, -1);
rb_define_method(rb_cArray, "concat", rb_ary_concat_multi, -1);
rb_define_method(rb_cArray, "union", rb_ary_union_multi, -1);
rb_define_method(rb_cArray, "difference", rb_ary_difference_multi, -1);
@@ -8792,6 +8851,7 @@ Init_Array(void)
rb_define_method(rb_cArray, "unshift", rb_ary_unshift_m, -1);
rb_define_alias(rb_cArray, "prepend", "unshift");
rb_define_method(rb_cArray, "insert", rb_ary_insert, -1);
+ rb_define_method(rb_cArray, "each", rb_ary_each, 0);
rb_define_method(rb_cArray, "each_index", rb_ary_each_index, 0);
rb_define_method(rb_cArray, "reverse_each", rb_ary_reverse_each, 0);
rb_define_method(rb_cArray, "length", rb_ary_length, 0);
@@ -8874,12 +8934,8 @@ Init_Array(void)
rb_define_method(rb_cArray, "one?", rb_ary_one_p, -1);
rb_define_method(rb_cArray, "dig", rb_ary_dig, -1);
rb_define_method(rb_cArray, "sum", rb_ary_sum, -1);
- rb_define_method(rb_cArray, "freeze", rb_ary_freeze, 0);
rb_define_method(rb_cArray, "deconstruct", rb_ary_deconstruct, 0);
-
- rb_cArray_empty_frozen = rb_ary_freeze(rb_ary_new());
- rb_vm_register_global_object(rb_cArray_empty_frozen);
}
#include "array.rbinc"
diff --git a/array.rb b/array.rb
index 866d8877c7..b9fa9844e6 100644
--- a/array.rb
+++ b/array.rb
@@ -1,50 +1,5 @@
class Array
# call-seq:
- # each {|element| ... } -> self
- # each -> new_enumerator
- #
- # With a block given, iterates over the elements of +self+,
- # passing each element to the block;
- # returns +self+:
- #
- # a = [:foo, 'bar', 2]
- # a.each {|element| puts "#{element.class} #{element}" }
- #
- # Output:
- #
- # Symbol foo
- # String bar
- # Integer 2
- #
- # Allows the array to be modified during iteration:
- #
- # a = [:foo, 'bar', 2]
- # a.each {|element| puts element; a.clear if element.to_s.start_with?('b') }
- #
- # Output:
- #
- # foo
- # bar
- #
- # With no block given, returns a new Enumerator.
- #
- # Related: see {Methods for Iterating}[rdoc-ref:Array@Methods+for+Iterating].
-
- def each
- Primitive.attr! :inline_block
-
- unless defined?(yield)
- return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, ary_enum_length)'
- end
- _i = 0
- value = nil
- while Primitive.cexpr!(%q{ ary_fetch_next(self, LOCAL_PTR(_i), LOCAL_PTR(value)) })
- yield value
- end
- self
- end
-
- # call-seq:
# array.shuffle!(random: Random) -> array
#
# Shuffles the elements of +self+ in place.
@@ -84,7 +39,7 @@ class Array
# a.sample # => 8
# If +self+ is empty, returns +nil+.
#
- # When argument +n+ is given, returns a new +Array+ containing +n+ random
+ # When argument +n+ is given, returns a new \Array containing +n+ random
# elements from +self+:
# a.sample(3) # => [8, 9, 2]
# a.sample(6) # => [9, 6, 10, 3, 1, 4]
@@ -96,7 +51,7 @@ class Array
# a.sample(a.size * 2) # => [1, 1, 3, 2, 1, 2]
# The argument +n+ must be a non-negative numeric value.
# The order of the result array is unrelated to the order of +self+.
- # Returns a new empty +Array+ if +self+ is empty.
+ # Returns a new empty \Array if +self+ is empty.
#
# The optional +random+ argument will be used as the random number generator:
# a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
@@ -111,115 +66,4 @@ class Array
Primitive.ary_sample(random, n, ary)
end
end
-
- # call-seq:
- # first -> object or nil
- # first(count) -> new_array
- #
- # Returns elements from +self+, or +nil+; does not modify +self+.
- #
- # With no argument given, returns the first element (if available):
- #
- # a = [:foo, 'bar', 2]
- # a.first # => :foo
- # a # => [:foo, "bar", 2]
- #
- # If +self+ is empty, returns +nil+.
- #
- # [].first # => nil
- #
- # With non-negative integer argument +count+ given,
- # returns the first +count+ elements (as available) in a new array:
- #
- # a.first(0) # => []
- # a.first(2) # => [:foo, "bar"]
- # a.first(50) # => [:foo, "bar", 2]
- #
- # Related: see {Methods for Querying}[rdoc-ref:Array@Methods+for+Querying].
- def first n = unspecified = true
- if Primitive.mandatory_only?
- Primitive.attr! :leaf
- Primitive.cexpr! %q{ ary_first(self) }
- else
- if unspecified
- Primitive.cexpr! %q{ ary_first(self) }
- else
- Primitive.cexpr! %q{ ary_take_first_or_last_n(self, NUM2LONG(n), ARY_TAKE_FIRST) }
- end
- end
- end
-
- # call-seq:
- # last -> last_object or nil
- # last(n) -> new_array
- #
- # Returns elements from +self+, or +nil+; +self+ is not modified.
- #
- # With no argument given, returns the last element, or +nil+ if +self+ is empty:
- #
- # a = [:foo, 'bar', 2]
- # a.last # => 2
- # a # => [:foo, "bar", 2]
- # [].last # => nil
- #
- #
- # With non-negative integer argument +n+ is given,
- # returns a new array containing the trailing +n+ elements of +self+, as available:
- #
- # a = [:foo, 'bar', 2]
- # a.last(2) # => ["bar", 2]
- # a.last(50) # => [:foo, "bar", 2]
- # a.last(0) # => []
- # [].last(3) # => []
- #
- # Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
- def last n = unspecified = true
- if Primitive.mandatory_only?
- Primitive.attr! :leaf
- Primitive.cexpr! %q{ ary_last(self) }
- else
- if unspecified
- Primitive.cexpr! %q{ ary_last(self) }
- else
- Primitive.cexpr! %q{ ary_take_first_or_last_n(self, NUM2LONG(n), ARY_TAKE_LAST) }
- end
- end
- end
-
- # call-seq:
- # fetch_values(*indexes) -> new_array
- # fetch_values(*indexes) {|index| ... } -> new_array
- #
- # With no block given, returns a new array containing the elements of +self+
- # at the offsets given by +indexes+;
- # each of the +indexes+ must be an
- # {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects]:
- #
- # a = [:foo, :bar, :baz]
- # a.fetch_values(3, 1) # => [:baz, :foo]
- # a.fetch_values(3.1, 1) # => [:baz, :foo]
- # a.fetch_values # => []
- #
- # For a negative index, counts backwards from the end of the array:
- #
- # a.fetch_values([-2, -1]) # [:bar, :baz]
- #
- # When no block is given, raises an exception if any index is out of range.
- #
- # With a block given, for each index:
- #
- # - If the index in in range, uses an element of +self+ (as above).
- # - Otherwise calls, the block with the index, and uses the block's return value.
- #
- # Example:
- #
- # a = [:foo, :bar, :baz]
- # a.fetch_values(1, 0, 42, 777) {|index| index.to_s}
- # # => [:bar, :foo, "42", "777"]
- #
- # Related: see {Methods for Fetching}[rdoc-ref:Array@Methods+for+Fetching].
- def fetch_values(*indexes, &block)
- indexes.map! { |i| fetch(i, &block) }
- indexes
- end
end
diff --git a/ast.c b/ast.c
index a0c1801de1..adb7287ed3 100644
--- a/ast.c
+++ b/ast.c
@@ -1,6 +1,6 @@
/* indent-tabs-mode: nil */
#include "internal.h"
-#include "internal/ruby_parser.h"
+#include "internal/parse.h"
#include "internal/symbol.h"
#include "internal/warnings.h"
#include "iseq.h"
@@ -14,10 +14,9 @@
static VALUE rb_mAST;
static VALUE rb_cNode;
-static VALUE rb_cLocation;
struct ASTNodeData {
- VALUE ast_value;
+ rb_ast_t *ast;
const NODE *node;
};
@@ -25,16 +24,14 @@ static void
node_gc_mark(void *ptr)
{
struct ASTNodeData *data = (struct ASTNodeData *)ptr;
- rb_gc_mark(data->ast_value);
+ rb_gc_mark((VALUE)data->ast);
}
static size_t
node_memsize(const void *ptr)
{
struct ASTNodeData *data = (struct ASTNodeData *)ptr;
- rb_ast_t *ast = rb_ruby_ast_data_get(data->ast_value);
-
- return sizeof(struct ASTNodeData) + rb_ast_memsize(ast);
+ return rb_ast_memsize(data->ast);
}
static const rb_data_type_t rb_node_type = {
@@ -44,51 +41,25 @@ static const rb_data_type_t rb_node_type = {
RUBY_TYPED_FREE_IMMEDIATELY,
};
-struct ASTLocationData {
- int first_lineno;
- int first_column;
- int last_lineno;
- int last_column;
-};
-
-static void
-location_gc_mark(void *ptr)
-{
-}
-
-static size_t
-location_memsize(const void *ptr)
-{
- return sizeof(struct ASTLocationData);
-}
-
-static const rb_data_type_t rb_location_type = {
- "AST/location",
- {location_gc_mark, RUBY_TYPED_DEFAULT_FREE, location_memsize,},
- 0, 0,
- RUBY_TYPED_FREE_IMMEDIATELY,
-};
-
-
static VALUE rb_ast_node_alloc(VALUE klass);
static void
-setup_node(VALUE obj, VALUE ast_value, const NODE *node)
+setup_node(VALUE obj, rb_ast_t *ast, const NODE *node)
{
struct ASTNodeData *data;
TypedData_Get_Struct(obj, struct ASTNodeData, &rb_node_type, data);
- data->ast_value = ast_value;
+ data->ast = ast;
data->node = node;
}
static VALUE
-ast_new_internal(VALUE ast_value, const NODE *node)
+ast_new_internal(rb_ast_t *ast, const NODE *node)
{
VALUE obj;
obj = rb_ast_node_alloc(rb_cNode);
- setup_node(obj, ast_value, node);
+ setup_node(obj, ast, node);
return obj;
}
@@ -103,16 +74,14 @@ ast_parse_new(void)
}
static VALUE
-ast_parse_done(VALUE ast_value)
+ast_parse_done(rb_ast_t *ast)
{
- rb_ast_t *ast = rb_ruby_ast_data_get(ast_value);
-
if (!ast->body.root) {
rb_ast_dispose(ast);
rb_exc_raise(GET_EC()->errinfo);
}
- return ast_new_internal(ast_value, (NODE *)ast->body.root);
+ return ast_new_internal(ast, (NODE *)ast->body.root);
}
static VALUE
@@ -124,15 +93,15 @@ ast_s_parse(rb_execution_context_t *ec, VALUE module, VALUE str, VALUE keep_scri
static VALUE
rb_ast_parse_str(VALUE str, VALUE keep_script_lines, VALUE error_tolerant, VALUE keep_tokens)
{
- VALUE ast_value;
+ rb_ast_t *ast = 0;
StringValue(str);
VALUE vparser = ast_parse_new();
- if (RTEST(keep_script_lines)) rb_parser_set_script_lines(vparser);
+ if (RTEST(keep_script_lines)) rb_parser_keep_script_lines(vparser);
if (RTEST(error_tolerant)) rb_parser_error_tolerant(vparser);
if (RTEST(keep_tokens)) rb_parser_keep_tokens(vparser);
- ast_value = rb_parser_compile_string_path(vparser, Qnil, str, 1);
- return ast_parse_done(ast_value);
+ ast = rb_parser_compile_string_path(vparser, Qnil, str, 1);
+ return ast_parse_done(ast);
}
static VALUE
@@ -145,35 +114,49 @@ static VALUE
rb_ast_parse_file(VALUE path, VALUE keep_script_lines, VALUE error_tolerant, VALUE keep_tokens)
{
VALUE f;
- VALUE ast_value = Qnil;
+ rb_ast_t *ast = 0;
rb_encoding *enc = rb_utf8_encoding();
+ FilePathValue(path);
f = rb_file_open_str(path, "r");
rb_funcall(f, rb_intern("set_encoding"), 2, rb_enc_from_encoding(enc), rb_str_new_cstr("-"));
VALUE vparser = ast_parse_new();
- if (RTEST(keep_script_lines)) rb_parser_set_script_lines(vparser);
+ if (RTEST(keep_script_lines)) rb_parser_keep_script_lines(vparser);
if (RTEST(error_tolerant)) rb_parser_error_tolerant(vparser);
if (RTEST(keep_tokens)) rb_parser_keep_tokens(vparser);
- ast_value = rb_parser_compile_file_path(vparser, Qnil, f, 1);
+ ast = rb_parser_compile_file_path(vparser, Qnil, f, 1);
rb_io_close(f);
- return ast_parse_done(ast_value);
+ return ast_parse_done(ast);
+}
+
+static VALUE
+lex_array(VALUE array, int index)
+{
+ VALUE str = rb_ary_entry(array, index);
+ if (!NIL_P(str)) {
+ StringValue(str);
+ if (!rb_enc_asciicompat(rb_enc_get(str))) {
+ rb_raise(rb_eArgError, "invalid source encoding");
+ }
+ }
+ return str;
}
static VALUE
rb_ast_parse_array(VALUE array, VALUE keep_script_lines, VALUE error_tolerant, VALUE keep_tokens)
{
- VALUE ast_value = Qnil;
+ rb_ast_t *ast = 0;
array = rb_check_array_type(array);
VALUE vparser = ast_parse_new();
- if (RTEST(keep_script_lines)) rb_parser_set_script_lines(vparser);
+ if (RTEST(keep_script_lines)) rb_parser_keep_script_lines(vparser);
if (RTEST(error_tolerant)) rb_parser_error_tolerant(vparser);
if (RTEST(keep_tokens)) rb_parser_keep_tokens(vparser);
- ast_value = rb_parser_compile_array(vparser, Qnil, array, 1);
- return ast_parse_done(ast_value);
+ ast = rb_parser_compile_generic(vparser, lex_array, Qnil, array, 1);
+ return ast_parse_done(ast);
}
-static VALUE node_children(VALUE, const NODE*);
+static VALUE node_children(rb_ast_t*, const NODE*);
static VALUE
node_find(VALUE self, const int node_id)
@@ -185,7 +168,7 @@ node_find(VALUE self, const int node_id)
if (nd_node_id(data->node) == node_id) return self;
- ary = node_children(data->ast_value, data->node);
+ ary = node_children(data->ast, data->node);
for (i = 0; i < RARRAY_LEN(ary); i++) {
VALUE child = RARRAY_AREF(ary, i);
@@ -202,6 +185,20 @@ node_find(VALUE self, const int node_id)
extern VALUE rb_e_script;
static VALUE
+script_lines(VALUE path)
+{
+ VALUE hash, lines;
+ ID script_lines;
+ CONST_ID(script_lines, "SCRIPT_LINES__");
+ if (!rb_const_defined_at(rb_cObject, script_lines)) return Qnil;
+ hash = rb_const_get_at(rb_cObject, script_lines);
+ if (!RB_TYPE_P(hash, T_HASH)) return Qnil;
+ lines = rb_hash_lookup(hash, path);
+ if (!RB_TYPE_P(lines, T_ARRAY)) return Qnil;
+ return lines;
+}
+
+static VALUE
node_id_for_backtrace_location(rb_execution_context_t *ec, VALUE module, VALUE location)
{
int node_id;
@@ -248,11 +245,6 @@ ast_s_of(rb_execution_context_t *ec, VALUE module, VALUE body, VALUE keep_script
if (!iseq) {
return Qnil;
}
-
- if (ISEQ_BODY(iseq)->prism) {
- rb_raise(rb_eRuntimeError, "cannot get AST for ISEQ compiled by prism");
- }
-
lines = ISEQ_BODY(iseq)->variable.script_lines;
VALUE path = rb_iseq_path(iseq);
@@ -262,7 +254,7 @@ ast_s_of(rb_execution_context_t *ec, VALUE module, VALUE body, VALUE keep_script
rb_raise(rb_eArgError, "cannot get AST for method defined in eval");
}
- if (!NIL_P(lines)) {
+ if (!NIL_P(lines) || !NIL_P(lines = script_lines(path))) {
node = rb_ast_parse_array(lines, keep_script_lines, error_tolerant, keep_tokens);
}
else if (e_option) {
@@ -308,10 +300,10 @@ ast_node_node_id(rb_execution_context_t *ec, VALUE self)
return INT2FIX(nd_node_id(data->node));
}
-#define NEW_CHILD(ast_value, node) (node ? ast_new_internal(ast_value, node) : Qnil)
+#define NEW_CHILD(ast, node) node ? ast_new_internal(ast, node) : Qnil
static VALUE
-rb_ary_new_from_node_args(VALUE ast_value, long n, ...)
+rb_ary_new_from_node_args(rb_ast_t *ast, long n, ...)
{
va_list ar;
VALUE ary;
@@ -323,57 +315,39 @@ rb_ary_new_from_node_args(VALUE ast_value, long n, ...)
for (i=0; i<n; i++) {
NODE *node;
node = va_arg(ar, NODE *);
- rb_ary_push(ary, NEW_CHILD(ast_value, node));
+ rb_ary_push(ary, NEW_CHILD(ast, node));
}
va_end(ar);
return ary;
}
static VALUE
-dump_block(VALUE ast_value, const struct RNode_BLOCK *node)
+dump_block(rb_ast_t *ast, const NODE *node)
{
VALUE ary = rb_ary_new();
do {
- rb_ary_push(ary, NEW_CHILD(ast_value, node->nd_head));
+ rb_ary_push(ary, NEW_CHILD(ast, node->nd_head));
} while (node->nd_next &&
nd_type_p(node->nd_next, NODE_BLOCK) &&
- (node = RNODE_BLOCK(node->nd_next), 1));
+ (node = node->nd_next, 1));
if (node->nd_next) {
- rb_ary_push(ary, NEW_CHILD(ast_value, node->nd_next));
+ rb_ary_push(ary, NEW_CHILD(ast, node->nd_next));
}
return ary;
}
static VALUE
-dump_array(VALUE ast_value, const struct RNode_LIST *node)
+dump_array(rb_ast_t *ast, const NODE *node)
{
VALUE ary = rb_ary_new();
- rb_ary_push(ary, NEW_CHILD(ast_value, node->nd_head));
+ rb_ary_push(ary, NEW_CHILD(ast, node->nd_head));
while (node->nd_next && nd_type_p(node->nd_next, NODE_LIST)) {
- node = RNODE_LIST(node->nd_next);
- rb_ary_push(ary, NEW_CHILD(ast_value, node->nd_head));
- }
- rb_ary_push(ary, NEW_CHILD(ast_value, node->nd_next));
-
- return ary;
-}
-
-static VALUE
-dump_parser_array(VALUE ast_value, rb_parser_ary_t *p_ary)
-{
- VALUE ary;
-
- if (p_ary->data_type != PARSER_ARY_DATA_NODE) {
- rb_bug("unexpected rb_parser_ary_data_type: %d", p_ary->data_type);
- }
-
- ary = rb_ary_new();
-
- for (long i = 0; i < p_ary->len; i++) {
- rb_ary_push(ary, NEW_CHILD(ast_value, p_ary->data[i]));
+ node = node->nd_next;
+ rb_ary_push(ary, NEW_CHILD(ast, node->nd_head));
}
+ rb_ary_push(ary, NEW_CHILD(ast, node->nd_next));
return ary;
}
@@ -395,341 +369,307 @@ no_name_rest(void)
}
static VALUE
-rest_arg(VALUE ast_value, const NODE *rest_arg)
+rest_arg(rb_ast_t *ast, const NODE *rest_arg)
{
- return NODE_NAMED_REST_P(rest_arg) ? NEW_CHILD(ast_value, rest_arg) : no_name_rest();
+ return NODE_NAMED_REST_P(rest_arg) ? NEW_CHILD(ast, rest_arg) : no_name_rest();
}
static VALUE
-node_children(VALUE ast_value, const NODE *node)
+node_children(rb_ast_t *ast, const NODE *node)
{
- char name[sizeof("$") + DECIMAL_SIZE_OF(long)];
+ char name[DECIMAL_SIZE_OF_BITS(sizeof(long) * CHAR_BIT) + 2]; /* including '$' */
enum node_type type = nd_type(node);
switch (type) {
case NODE_BLOCK:
- return dump_block(ast_value, RNODE_BLOCK(node));
+ return dump_block(ast, node);
case NODE_IF:
- return rb_ary_new_from_node_args(ast_value, 3, RNODE_IF(node)->nd_cond, RNODE_IF(node)->nd_body, RNODE_IF(node)->nd_else);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_cond, node->nd_body, node->nd_else);
case NODE_UNLESS:
- return rb_ary_new_from_node_args(ast_value, 3, RNODE_UNLESS(node)->nd_cond, RNODE_UNLESS(node)->nd_body, RNODE_UNLESS(node)->nd_else);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_cond, node->nd_body, node->nd_else);
case NODE_CASE:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_CASE(node)->nd_head, RNODE_CASE(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
case NODE_CASE2:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_CASE2(node)->nd_head, RNODE_CASE2(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
case NODE_CASE3:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_CASE3(node)->nd_head, RNODE_CASE3(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
case NODE_WHEN:
- return rb_ary_new_from_node_args(ast_value, 3, RNODE_WHEN(node)->nd_head, RNODE_WHEN(node)->nd_body, RNODE_WHEN(node)->nd_next);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_head, node->nd_body, node->nd_next);
case NODE_IN:
- return rb_ary_new_from_node_args(ast_value, 3, RNODE_IN(node)->nd_head, RNODE_IN(node)->nd_body, RNODE_IN(node)->nd_next);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_head, node->nd_body, node->nd_next);
case NODE_WHILE:
case NODE_UNTIL:
- return rb_ary_push(rb_ary_new_from_node_args(ast_value, 2, RNODE_WHILE(node)->nd_cond, RNODE_WHILE(node)->nd_body),
- RBOOL(RNODE_WHILE(node)->nd_state));
+ return rb_ary_push(rb_ary_new_from_node_args(ast, 2, node->nd_cond, node->nd_body),
+ RBOOL(node->nd_state));
case NODE_ITER:
case NODE_FOR:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_ITER(node)->nd_iter, RNODE_ITER(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_iter, node->nd_body);
case NODE_FOR_MASGN:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_FOR_MASGN(node)->nd_var);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_var);
case NODE_BREAK:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_BREAK(node)->nd_stts);
case NODE_NEXT:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_NEXT(node)->nd_stts);
case NODE_RETURN:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_RETURN(node)->nd_stts);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_stts);
case NODE_REDO:
- return rb_ary_new_from_node_args(ast_value, 0);
+ return rb_ary_new_from_node_args(ast, 0);
case NODE_RETRY:
- return rb_ary_new_from_node_args(ast_value, 0);
+ return rb_ary_new_from_node_args(ast, 0);
case NODE_BEGIN:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_BEGIN(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_body);
case NODE_RESCUE:
- return rb_ary_new_from_node_args(ast_value, 3, RNODE_RESCUE(node)->nd_head, RNODE_RESCUE(node)->nd_resq, RNODE_RESCUE(node)->nd_else);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_head, node->nd_resq, node->nd_else);
case NODE_RESBODY:
- return rb_ary_new_from_node_args(ast_value, 4, RNODE_RESBODY(node)->nd_args, RNODE_RESBODY(node)->nd_exc_var, RNODE_RESBODY(node)->nd_body, RNODE_RESBODY(node)->nd_next);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_args, node->nd_body, node->nd_head);
case NODE_ENSURE:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_ENSURE(node)->nd_head, RNODE_ENSURE(node)->nd_ensr);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_ensr);
case NODE_AND:
case NODE_OR:
{
VALUE ary = rb_ary_new();
while (1) {
- rb_ary_push(ary, NEW_CHILD(ast_value, RNODE_AND(node)->nd_1st));
- if (!RNODE_AND(node)->nd_2nd || !nd_type_p(RNODE_AND(node)->nd_2nd, type))
+ rb_ary_push(ary, NEW_CHILD(ast, node->nd_1st));
+ if (!node->nd_2nd || !nd_type_p(node->nd_2nd, type))
break;
- node = RNODE_AND(node)->nd_2nd;
+ node = node->nd_2nd;
}
- rb_ary_push(ary, NEW_CHILD(ast_value, RNODE_AND(node)->nd_2nd));
+ rb_ary_push(ary, NEW_CHILD(ast, node->nd_2nd));
return ary;
}
case NODE_MASGN:
- if (NODE_NAMED_REST_P(RNODE_MASGN(node)->nd_args)) {
- return rb_ary_new_from_node_args(ast_value, 3, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head, RNODE_MASGN(node)->nd_args);
+ if (NODE_NAMED_REST_P(node->nd_args)) {
+ return rb_ary_new_from_node_args(ast, 3, node->nd_value, node->nd_head, node->nd_args);
}
else {
- return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_MASGN(node)->nd_value),
- NEW_CHILD(ast_value, RNODE_MASGN(node)->nd_head),
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_value),
+ NEW_CHILD(ast, node->nd_head),
no_name_rest());
}
case NODE_LASGN:
- if (NODE_REQUIRED_KEYWORD_P(RNODE_LASGN(node)->nd_value)) {
- return rb_ary_new_from_args(2, var_name(RNODE_LASGN(node)->nd_vid), ID2SYM(rb_intern("NODE_SPECIAL_REQUIRED_KEYWORD")));
- }
- return rb_ary_new_from_args(2, var_name(RNODE_LASGN(node)->nd_vid), NEW_CHILD(ast_value, RNODE_LASGN(node)->nd_value));
case NODE_DASGN:
- if (NODE_REQUIRED_KEYWORD_P(RNODE_DASGN(node)->nd_value)) {
- return rb_ary_new_from_args(2, var_name(RNODE_DASGN(node)->nd_vid), ID2SYM(rb_intern("NODE_SPECIAL_REQUIRED_KEYWORD")));
- }
- return rb_ary_new_from_args(2, var_name(RNODE_DASGN(node)->nd_vid), NEW_CHILD(ast_value, RNODE_DASGN(node)->nd_value));
case NODE_IASGN:
- return rb_ary_new_from_args(2, var_name(RNODE_IASGN(node)->nd_vid), NEW_CHILD(ast_value, RNODE_IASGN(node)->nd_value));
case NODE_CVASGN:
- return rb_ary_new_from_args(2, var_name(RNODE_CVASGN(node)->nd_vid), NEW_CHILD(ast_value, RNODE_CVASGN(node)->nd_value));
case NODE_GASGN:
- return rb_ary_new_from_args(2, var_name(RNODE_GASGN(node)->nd_vid), NEW_CHILD(ast_value, RNODE_GASGN(node)->nd_value));
+ if (NODE_REQUIRED_KEYWORD_P(node)) {
+ return rb_ary_new_from_args(2, var_name(node->nd_vid), ID2SYM(rb_intern("NODE_SPECIAL_REQUIRED_KEYWORD")));
+ }
+ return rb_ary_new_from_args(2, var_name(node->nd_vid), NEW_CHILD(ast, node->nd_value));
case NODE_CDECL:
- if (RNODE_CDECL(node)->nd_vid) {
- return rb_ary_new_from_args(2, ID2SYM(RNODE_CDECL(node)->nd_vid), NEW_CHILD(ast_value, RNODE_CDECL(node)->nd_value));
+ if (node->nd_vid) {
+ return rb_ary_new_from_args(2, ID2SYM(node->nd_vid), NEW_CHILD(ast, node->nd_value));
}
- return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_CDECL(node)->nd_else), ID2SYM(RNODE_COLON2(RNODE_CDECL(node)->nd_else)->nd_mid), NEW_CHILD(ast_value, RNODE_CDECL(node)->nd_value));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_else), ID2SYM(node->nd_else->nd_mid), NEW_CHILD(ast, node->nd_value));
case NODE_OP_ASGN1:
- return rb_ary_new_from_args(4, NEW_CHILD(ast_value, RNODE_OP_ASGN1(node)->nd_recv),
- ID2SYM(RNODE_OP_ASGN1(node)->nd_mid),
- NEW_CHILD(ast_value, RNODE_OP_ASGN1(node)->nd_index),
- NEW_CHILD(ast_value, RNODE_OP_ASGN1(node)->nd_rvalue));
+ return rb_ary_new_from_args(4, NEW_CHILD(ast, node->nd_recv),
+ ID2SYM(node->nd_mid),
+ NEW_CHILD(ast, node->nd_args->nd_head),
+ NEW_CHILD(ast, node->nd_args->nd_body));
case NODE_OP_ASGN2:
- return rb_ary_new_from_args(5, NEW_CHILD(ast_value, RNODE_OP_ASGN2(node)->nd_recv),
- RBOOL(RNODE_OP_ASGN2(node)->nd_aid),
- ID2SYM(RNODE_OP_ASGN2(node)->nd_vid),
- ID2SYM(RNODE_OP_ASGN2(node)->nd_mid),
- NEW_CHILD(ast_value, RNODE_OP_ASGN2(node)->nd_value));
+ return rb_ary_new_from_args(5, NEW_CHILD(ast, node->nd_recv),
+ RBOOL(node->nd_next->nd_aid),
+ ID2SYM(node->nd_next->nd_vid),
+ ID2SYM(node->nd_next->nd_mid),
+ NEW_CHILD(ast, node->nd_value));
case NODE_OP_ASGN_AND:
- return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_OP_ASGN_AND(node)->nd_head), ID2SYM(idANDOP),
- NEW_CHILD(ast_value, RNODE_OP_ASGN_AND(node)->nd_value));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_head), ID2SYM(idANDOP),
+ NEW_CHILD(ast, node->nd_value));
case NODE_OP_ASGN_OR:
- return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_OP_ASGN_OR(node)->nd_head), ID2SYM(idOROP),
- NEW_CHILD(ast_value, RNODE_OP_ASGN_OR(node)->nd_value));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_head), ID2SYM(idOROP),
+ NEW_CHILD(ast, node->nd_value));
case NODE_OP_CDECL:
- return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_OP_CDECL(node)->nd_head),
- ID2SYM(RNODE_OP_CDECL(node)->nd_aid),
- NEW_CHILD(ast_value, RNODE_OP_CDECL(node)->nd_value));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_head),
+ ID2SYM(node->nd_aid),
+ NEW_CHILD(ast, node->nd_value));
case NODE_CALL:
- return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_CALL(node)->nd_recv),
- ID2SYM(RNODE_CALL(node)->nd_mid),
- NEW_CHILD(ast_value, RNODE_CALL(node)->nd_args));
case NODE_OPCALL:
- return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_OPCALL(node)->nd_recv),
- ID2SYM(RNODE_OPCALL(node)->nd_mid),
- NEW_CHILD(ast_value, RNODE_OPCALL(node)->nd_args));
case NODE_QCALL:
- return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_QCALL(node)->nd_recv),
- ID2SYM(RNODE_QCALL(node)->nd_mid),
- NEW_CHILD(ast_value, RNODE_QCALL(node)->nd_args));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_recv),
+ ID2SYM(node->nd_mid),
+ NEW_CHILD(ast, node->nd_args));
case NODE_FCALL:
- return rb_ary_new_from_args(2, ID2SYM(RNODE_FCALL(node)->nd_mid),
- NEW_CHILD(ast_value, RNODE_FCALL(node)->nd_args));
+ return rb_ary_new_from_args(2, ID2SYM(node->nd_mid),
+ NEW_CHILD(ast, node->nd_args));
case NODE_VCALL:
- return rb_ary_new_from_args(1, ID2SYM(RNODE_VCALL(node)->nd_mid));
+ return rb_ary_new_from_args(1, ID2SYM(node->nd_mid));
case NODE_SUPER:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_SUPER(node)->nd_args);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_args);
case NODE_ZSUPER:
- return rb_ary_new_from_node_args(ast_value, 0);
+ return rb_ary_new_from_node_args(ast, 0);
case NODE_LIST:
- return dump_array(ast_value, RNODE_LIST(node));
+ case NODE_VALUES:
+ return dump_array(ast, node);
case NODE_ZLIST:
- return rb_ary_new_from_node_args(ast_value, 0);
+ return rb_ary_new_from_node_args(ast, 0);
case NODE_HASH:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_HASH(node)->nd_head);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_head);
case NODE_YIELD:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_YIELD(node)->nd_head);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_head);
case NODE_LVAR:
- return rb_ary_new_from_args(1, var_name(RNODE_LVAR(node)->nd_vid));
case NODE_DVAR:
- return rb_ary_new_from_args(1, var_name(RNODE_DVAR(node)->nd_vid));
+ return rb_ary_new_from_args(1, var_name(node->nd_vid));
case NODE_IVAR:
- return rb_ary_new_from_args(1, ID2SYM(RNODE_IVAR(node)->nd_vid));
case NODE_CONST:
- return rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
case NODE_CVAR:
- return rb_ary_new_from_args(1, ID2SYM(RNODE_CVAR(node)->nd_vid));
case NODE_GVAR:
- return rb_ary_new_from_args(1, ID2SYM(RNODE_GVAR(node)->nd_vid));
+ return rb_ary_new_from_args(1, ID2SYM(node->nd_vid));
case NODE_NTH_REF:
- snprintf(name, sizeof(name), "$%ld", RNODE_NTH_REF(node)->nd_nth);
+ snprintf(name, sizeof(name), "$%ld", node->nd_nth);
return rb_ary_new_from_args(1, ID2SYM(rb_intern(name)));
case NODE_BACK_REF:
name[0] = '$';
- name[1] = (char)RNODE_BACK_REF(node)->nd_nth;
+ name[1] = (char)node->nd_nth;
name[2] = '\0';
return rb_ary_new_from_args(1, ID2SYM(rb_intern(name)));
- case NODE_MATCH:
- return rb_ary_new_from_args(1, rb_node_regx_string_val(node));
case NODE_MATCH2:
- if (RNODE_MATCH2(node)->nd_args) {
- return rb_ary_new_from_node_args(ast_value, 3, RNODE_MATCH2(node)->nd_recv, RNODE_MATCH2(node)->nd_value, RNODE_MATCH2(node)->nd_args);
+ if (node->nd_args) {
+ return rb_ary_new_from_node_args(ast, 3, node->nd_recv, node->nd_value, node->nd_args);
}
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_MATCH2(node)->nd_recv, RNODE_MATCH2(node)->nd_value);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_recv, node->nd_value);
case NODE_MATCH3:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_MATCH3(node)->nd_recv, RNODE_MATCH3(node)->nd_value);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_recv, node->nd_value);
+ case NODE_MATCH:
+ case NODE_LIT:
case NODE_STR:
case NODE_XSTR:
- return rb_ary_new_from_args(1, rb_node_str_string_val(node));
- case NODE_INTEGER:
- return rb_ary_new_from_args(1, rb_node_integer_literal_val(node));
- case NODE_FLOAT:
- return rb_ary_new_from_args(1, rb_node_float_literal_val(node));
- case NODE_RATIONAL:
- return rb_ary_new_from_args(1, rb_node_rational_literal_val(node));
- case NODE_IMAGINARY:
- return rb_ary_new_from_args(1, rb_node_imaginary_literal_val(node));
- case NODE_REGX:
- return rb_ary_new_from_args(1, rb_node_regx_string_val(node));
+ return rb_ary_new_from_args(1, node->nd_lit);
case NODE_ONCE:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_ONCE(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_body);
case NODE_DSTR:
case NODE_DXSTR:
case NODE_DREGX:
case NODE_DSYM:
{
- struct RNode_LIST *n = RNODE_DSTR(node)->nd_next;
+ NODE *n = node->nd_next;
VALUE head = Qnil, next = Qnil;
if (n) {
- head = NEW_CHILD(ast_value, n->nd_head);
- next = NEW_CHILD(ast_value, n->nd_next);
+ head = NEW_CHILD(ast, n->nd_head);
+ next = NEW_CHILD(ast, n->nd_next);
}
- return rb_ary_new_from_args(3, rb_node_dstr_string_val(node), head, next);
+ return rb_ary_new_from_args(3, node->nd_lit, head, next);
}
- case NODE_SYM:
- return rb_ary_new_from_args(1, rb_node_sym_string_val(node));
case NODE_EVSTR:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_EVSTR(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_body);
case NODE_ARGSCAT:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_ARGSCAT(node)->nd_head, RNODE_ARGSCAT(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
case NODE_ARGSPUSH:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_ARGSPUSH(node)->nd_head, RNODE_ARGSPUSH(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
case NODE_SPLAT:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_SPLAT(node)->nd_head);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_head);
case NODE_BLOCK_PASS:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_BLOCK_PASS(node)->nd_head, RNODE_BLOCK_PASS(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_head, node->nd_body);
case NODE_DEFN:
- return rb_ary_new_from_args(2, ID2SYM(RNODE_DEFN(node)->nd_mid), NEW_CHILD(ast_value, RNODE_DEFN(node)->nd_defn));
+ return rb_ary_new_from_args(2, ID2SYM(node->nd_mid), NEW_CHILD(ast, node->nd_defn));
case NODE_DEFS:
- return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_DEFS(node)->nd_recv), ID2SYM(RNODE_DEFS(node)->nd_mid), NEW_CHILD(ast_value, RNODE_DEFS(node)->nd_defn));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_recv), ID2SYM(node->nd_mid), NEW_CHILD(ast, node->nd_defn));
case NODE_ALIAS:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_ALIAS(node)->nd_1st, RNODE_ALIAS(node)->nd_2nd);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_1st, node->nd_2nd);
case NODE_VALIAS:
- return rb_ary_new_from_args(2, ID2SYM(RNODE_VALIAS(node)->nd_alias), ID2SYM(RNODE_VALIAS(node)->nd_orig));
+ return rb_ary_new_from_args(2, ID2SYM(node->nd_alias), ID2SYM(node->nd_orig));
case NODE_UNDEF:
- return rb_ary_new_from_args(1, dump_parser_array(ast_value, RNODE_UNDEF(node)->nd_undefs));
+ return rb_ary_new_from_node_args(ast, 1, node->nd_undef);
case NODE_CLASS:
- return rb_ary_new_from_node_args(ast_value, 3, RNODE_CLASS(node)->nd_cpath, RNODE_CLASS(node)->nd_super, RNODE_CLASS(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 3, node->nd_cpath, node->nd_super, node->nd_body);
case NODE_MODULE:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_MODULE(node)->nd_cpath, RNODE_MODULE(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_cpath, node->nd_body);
case NODE_SCLASS:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_SCLASS(node)->nd_recv, RNODE_SCLASS(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_recv, node->nd_body);
case NODE_COLON2:
- return rb_ary_new_from_args(2, NEW_CHILD(ast_value, RNODE_COLON2(node)->nd_head), ID2SYM(RNODE_COLON2(node)->nd_mid));
+ return rb_ary_new_from_args(2, NEW_CHILD(ast, node->nd_head), ID2SYM(node->nd_mid));
case NODE_COLON3:
- return rb_ary_new_from_args(1, ID2SYM(RNODE_COLON3(node)->nd_mid));
+ return rb_ary_new_from_args(1, ID2SYM(node->nd_mid));
case NODE_DOT2:
case NODE_DOT3:
case NODE_FLIP2:
case NODE_FLIP3:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_DOT2(node)->nd_beg, RNODE_DOT2(node)->nd_end);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_beg, node->nd_end);
case NODE_SELF:
- return rb_ary_new_from_node_args(ast_value, 0);
+ return rb_ary_new_from_node_args(ast, 0);
case NODE_NIL:
- return rb_ary_new_from_node_args(ast_value, 0);
+ return rb_ary_new_from_node_args(ast, 0);
case NODE_TRUE:
- return rb_ary_new_from_node_args(ast_value, 0);
+ return rb_ary_new_from_node_args(ast, 0);
case NODE_FALSE:
- return rb_ary_new_from_node_args(ast_value, 0);
+ return rb_ary_new_from_node_args(ast, 0);
case NODE_ERRINFO:
- return rb_ary_new_from_node_args(ast_value, 0);
+ return rb_ary_new_from_node_args(ast, 0);
case NODE_DEFINED:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_DEFINED(node)->nd_head);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_head);
case NODE_POSTEXE:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_POSTEXE(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_body);
case NODE_ATTRASGN:
- return rb_ary_new_from_args(3, NEW_CHILD(ast_value, RNODE_ATTRASGN(node)->nd_recv), ID2SYM(RNODE_ATTRASGN(node)->nd_mid), NEW_CHILD(ast_value, RNODE_ATTRASGN(node)->nd_args));
+ return rb_ary_new_from_args(3, NEW_CHILD(ast, node->nd_recv), ID2SYM(node->nd_mid), NEW_CHILD(ast, node->nd_args));
case NODE_LAMBDA:
- return rb_ary_new_from_node_args(ast_value, 1, RNODE_LAMBDA(node)->nd_body);
+ return rb_ary_new_from_node_args(ast, 1, node->nd_body);
case NODE_OPT_ARG:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_OPT_ARG(node)->nd_body, RNODE_OPT_ARG(node)->nd_next);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_body, node->nd_next);
case NODE_KW_ARG:
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_KW_ARG(node)->nd_body, RNODE_KW_ARG(node)->nd_next);
+ return rb_ary_new_from_node_args(ast, 2, node->nd_body, node->nd_next);
case NODE_POSTARG:
- if (NODE_NAMED_REST_P(RNODE_POSTARG(node)->nd_1st)) {
- return rb_ary_new_from_node_args(ast_value, 2, RNODE_POSTARG(node)->nd_1st, RNODE_POSTARG(node)->nd_2nd);
+ if (NODE_NAMED_REST_P(node->nd_1st)) {
+ return rb_ary_new_from_node_args(ast, 2, node->nd_1st, node->nd_2nd);
}
return rb_ary_new_from_args(2, no_name_rest(),
- NEW_CHILD(ast_value, RNODE_POSTARG(node)->nd_2nd));
+ NEW_CHILD(ast, node->nd_2nd));
case NODE_ARGS:
{
- struct rb_args_info *ainfo = &RNODE_ARGS(node)->nd_ainfo;
+ struct rb_args_info *ainfo = node->nd_ainfo;
return rb_ary_new_from_args(10,
INT2NUM(ainfo->pre_args_num),
- NEW_CHILD(ast_value, ainfo->pre_init),
- NEW_CHILD(ast_value, (NODE *)ainfo->opt_args),
+ NEW_CHILD(ast, ainfo->pre_init),
+ NEW_CHILD(ast, ainfo->opt_args),
var_name(ainfo->first_post_arg),
INT2NUM(ainfo->post_args_num),
- NEW_CHILD(ast_value, ainfo->post_init),
+ NEW_CHILD(ast, ainfo->post_init),
(ainfo->rest_arg == NODE_SPECIAL_EXCESSIVE_COMMA
? ID2SYM(rb_intern("NODE_SPECIAL_EXCESSIVE_COMMA"))
: var_name(ainfo->rest_arg)),
- (ainfo->no_kwarg ? Qfalse : NEW_CHILD(ast_value, (NODE *)ainfo->kw_args)),
- (ainfo->no_kwarg ? Qfalse : NEW_CHILD(ast_value, ainfo->kw_rest_arg)),
+ (ainfo->no_kwarg ? Qfalse : NEW_CHILD(ast, ainfo->kw_args)),
+ (ainfo->no_kwarg ? Qfalse : NEW_CHILD(ast, ainfo->kw_rest_arg)),
var_name(ainfo->block_arg));
}
case NODE_SCOPE:
{
- rb_ast_id_table_t *tbl = RNODE_SCOPE(node)->nd_tbl;
+ rb_ast_id_table_t *tbl = node->nd_tbl;
int i, size = tbl ? tbl->size : 0;
VALUE locals = rb_ary_new_capa(size);
for (i = 0; i < size; i++) {
rb_ary_push(locals, var_name(tbl->ids[i]));
}
- return rb_ary_new_from_args(3, locals, NEW_CHILD(ast_value, (NODE *)RNODE_SCOPE(node)->nd_args), NEW_CHILD(ast_value, RNODE_SCOPE(node)->nd_body));
+ return rb_ary_new_from_args(3, locals, NEW_CHILD(ast, node->nd_args), NEW_CHILD(ast, node->nd_body));
}
case NODE_ARYPTN:
{
- VALUE rest = rest_arg(ast_value, RNODE_ARYPTN(node)->rest_arg);
+ struct rb_ary_pattern_info *apinfo = node->nd_apinfo;
+ VALUE rest = rest_arg(ast, apinfo->rest_arg);
return rb_ary_new_from_args(4,
- NEW_CHILD(ast_value, RNODE_ARYPTN(node)->nd_pconst),
- NEW_CHILD(ast_value, RNODE_ARYPTN(node)->pre_args),
+ NEW_CHILD(ast, node->nd_pconst),
+ NEW_CHILD(ast, apinfo->pre_args),
rest,
- NEW_CHILD(ast_value, RNODE_ARYPTN(node)->post_args));
+ NEW_CHILD(ast, apinfo->post_args));
}
case NODE_FNDPTN:
{
- VALUE pre_rest = rest_arg(ast_value, RNODE_FNDPTN(node)->pre_rest_arg);
- VALUE post_rest = rest_arg(ast_value, RNODE_FNDPTN(node)->post_rest_arg);
+ struct rb_fnd_pattern_info *fpinfo = node->nd_fpinfo;
+ VALUE pre_rest = rest_arg(ast, fpinfo->pre_rest_arg);
+ VALUE post_rest = rest_arg(ast, fpinfo->post_rest_arg);
return rb_ary_new_from_args(4,
- NEW_CHILD(ast_value, RNODE_FNDPTN(node)->nd_pconst),
+ NEW_CHILD(ast, node->nd_pconst),
pre_rest,
- NEW_CHILD(ast_value, RNODE_FNDPTN(node)->args),
+ NEW_CHILD(ast, fpinfo->args),
post_rest);
}
case NODE_HSHPTN:
{
- VALUE kwrest = RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD ? ID2SYM(rb_intern("NODE_SPECIAL_NO_REST_KEYWORD")) :
- NEW_CHILD(ast_value, RNODE_HSHPTN(node)->nd_pkwrestarg);
+ VALUE kwrest = node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD ? ID2SYM(rb_intern("NODE_SPECIAL_NO_REST_KEYWORD")) :
+ NEW_CHILD(ast, node->nd_pkwrestarg);
return rb_ary_new_from_args(3,
- NEW_CHILD(ast_value, RNODE_HSHPTN(node)->nd_pconst),
- NEW_CHILD(ast_value, RNODE_HSHPTN(node)->nd_pkwargs),
+ NEW_CHILD(ast, node->nd_pconst),
+ NEW_CHILD(ast, node->nd_pkwargs),
kwrest);
}
- case NODE_LINE:
- return rb_ary_new_from_args(1, rb_node_line_lineno_val(node));
- case NODE_FILE:
- return rb_ary_new_from_args(1, rb_node_file_path_val(node));
- case NODE_ENCODING:
- return rb_ary_new_from_args(1, rb_node_encoding_val(node));
case NODE_ERROR:
- return rb_ary_new_from_node_args(ast_value, 0);
+ return rb_ary_new_from_node_args(ast, 0);
case NODE_ARGS_AUX:
case NODE_LAST:
break;
@@ -744,148 +684,7 @@ ast_node_children(rb_execution_context_t *ec, VALUE self)
struct ASTNodeData *data;
TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
- return node_children(data->ast_value, data->node);
-}
-
-static int
-null_loc_p(rb_code_location_t *loc)
-{
- return (loc->beg_pos.lineno == 0 && loc->beg_pos.column == -1 && loc->end_pos.lineno == 0 && loc->end_pos.column == -1);
-}
-
-static VALUE
-location_new(rb_code_location_t *loc)
-{
- VALUE obj;
- struct ASTLocationData *data;
-
- if (null_loc_p(loc)) return Qnil;
-
- obj = TypedData_Make_Struct(rb_cLocation, struct ASTLocationData, &rb_location_type, data);
- data->first_lineno = loc->beg_pos.lineno;
- data->first_column = loc->beg_pos.column;
- data->last_lineno = loc->end_pos.lineno;
- data->last_column = loc->end_pos.column;
-
- return obj;
-}
-
-static VALUE
-node_locations(VALUE ast_value, const NODE *node)
-{
- enum node_type type = nd_type(node);
- switch (type) {
- case NODE_ALIAS:
- return rb_ary_new_from_args(2,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_ALIAS(node)->keyword_loc));
- case NODE_AND:
- return rb_ary_new_from_args(2,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_AND(node)->operator_loc));
- case NODE_BLOCK_PASS:
- return rb_ary_new_from_args(2,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_BLOCK_PASS(node)->operator_loc));
-
- case NODE_BREAK:
- return rb_ary_new_from_args(2,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_BREAK(node)->keyword_loc));
- case NODE_CASE:
- return rb_ary_new_from_args(3,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_CASE(node)->case_keyword_loc),
- location_new(&RNODE_CASE(node)->end_keyword_loc));
- case NODE_CASE2:
- return rb_ary_new_from_args(3,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_CASE2(node)->case_keyword_loc),
- location_new(&RNODE_CASE2(node)->end_keyword_loc));
- case NODE_CASE3:
- return rb_ary_new_from_args(3,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_CASE3(node)->case_keyword_loc),
- location_new(&RNODE_CASE3(node)->end_keyword_loc));
- case NODE_NEXT:
- return rb_ary_new_from_args(2,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_NEXT(node)->keyword_loc));
- case NODE_OR:
- return rb_ary_new_from_args(2,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_OR(node)->operator_loc));
- case NODE_OP_ASGN1:
- return rb_ary_new_from_args(5,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_OP_ASGN1(node)->call_operator_loc),
- location_new(&RNODE_OP_ASGN1(node)->opening_loc),
- location_new(&RNODE_OP_ASGN1(node)->closing_loc),
- location_new(&RNODE_OP_ASGN1(node)->binary_operator_loc));
- case NODE_OP_ASGN2:
- return rb_ary_new_from_args(4,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_OP_ASGN2(node)->call_operator_loc),
- location_new(&RNODE_OP_ASGN2(node)->message_loc),
- location_new(&RNODE_OP_ASGN2(node)->binary_operator_loc));
- case NODE_REDO:
- return rb_ary_new_from_args(2,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_REDO(node)->keyword_loc));
- case NODE_RETURN:
- return rb_ary_new_from_args(2,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_RETURN(node)->keyword_loc));
- case NODE_SPLAT:
- return rb_ary_new_from_args(2,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_SPLAT(node)->operator_loc));
- case NODE_UNDEF:
- return rb_ary_new_from_args(2,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_UNDEF(node)->keyword_loc));
- case NODE_UNLESS:
- return rb_ary_new_from_args(4,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_UNLESS(node)->keyword_loc),
- location_new(&RNODE_UNLESS(node)->then_keyword_loc),
- location_new(&RNODE_UNLESS(node)->end_keyword_loc));
- case NODE_VALIAS:
- return rb_ary_new_from_args(2,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_VALIAS(node)->keyword_loc));
- case NODE_WHEN:
- return rb_ary_new_from_args(3,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_WHEN(node)->keyword_loc),
- location_new(&RNODE_WHEN(node)->then_keyword_loc));
- case NODE_WHILE:
- return rb_ary_new_from_args(3,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_WHILE(node)->keyword_loc),
- location_new(&RNODE_WHILE(node)->closing_loc));
- case NODE_UNTIL:
- return rb_ary_new_from_args(3,
- location_new(nd_code_loc(node)),
- location_new(&RNODE_UNTIL(node)->keyword_loc),
- location_new(&RNODE_UNTIL(node)->closing_loc));
- case NODE_ARGS_AUX:
- case NODE_LAST:
- break;
- default:
- return rb_ary_new_from_args(1, location_new(nd_code_loc(node)));
- }
-
- rb_bug("node_locations: unknown node: %s", ruby_node_name(type));
-}
-
-static VALUE
-ast_node_locations(rb_execution_context_t *ec, VALUE self)
-{
- struct ASTNodeData *data;
- TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
-
- return node_locations(data->ast_value, data->node);
+ return node_children(data->ast, data->node);
}
static VALUE
@@ -927,37 +726,10 @@ ast_node_last_column(rb_execution_context_t *ec, VALUE self)
static VALUE
ast_node_all_tokens(rb_execution_context_t *ec, VALUE self)
{
- long i;
struct ASTNodeData *data;
- rb_ast_t *ast;
- rb_parser_ary_t *parser_tokens;
- rb_parser_ast_token_t *parser_token;
- VALUE str, loc, token, all_tokens;
-
TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
- ast = rb_ruby_ast_data_get(data->ast_value);
- parser_tokens = ast->node_buffer->tokens;
- if (parser_tokens == NULL) {
- return Qnil;
- }
-
- all_tokens = rb_ary_new2(parser_tokens->len);
- for (i = 0; i < parser_tokens->len; i++) {
- parser_token = parser_tokens->data[i];
- str = rb_str_new(parser_token->str->ptr, parser_token->str->len);
- loc = rb_ary_new_from_args(4,
- INT2FIX(parser_token->loc.beg_pos.lineno),
- INT2FIX(parser_token->loc.beg_pos.column),
- INT2FIX(parser_token->loc.end_pos.lineno),
- INT2FIX(parser_token->loc.end_pos.column)
- );
- token = rb_ary_new_from_args(4, INT2FIX(parser_token->id), ID2SYM(rb_intern(parser_token->type_name)), str, loc);
- rb_ary_push(all_tokens, token);
- }
- rb_ary_freeze(all_tokens);
-
- return all_tokens;
+ return rb_ast_tokens(data->ast);
}
static VALUE
@@ -984,66 +756,10 @@ static VALUE
ast_node_script_lines(rb_execution_context_t *ec, VALUE self)
{
struct ASTNodeData *data;
- rb_ast_t *ast;
TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
- ast = rb_ruby_ast_data_get(data->ast_value);
- rb_parser_ary_t *ret = ast->body.script_lines;
- return rb_parser_build_script_lines_from(ret);
-}
-
-static VALUE
-ast_location_first_lineno(rb_execution_context_t *ec, VALUE self)
-{
- struct ASTLocationData *data;
- TypedData_Get_Struct(self, struct ASTLocationData, &rb_location_type, data);
-
- return INT2NUM(data->first_lineno);
-}
-
-static VALUE
-ast_location_first_column(rb_execution_context_t *ec, VALUE self)
-{
- struct ASTLocationData *data;
- TypedData_Get_Struct(self, struct ASTLocationData, &rb_location_type, data);
-
- return INT2NUM(data->first_column);
-}
-
-static VALUE
-ast_location_last_lineno(rb_execution_context_t *ec, VALUE self)
-{
- struct ASTLocationData *data;
- TypedData_Get_Struct(self, struct ASTLocationData, &rb_location_type, data);
-
- return INT2NUM(data->last_lineno);
-}
-
-static VALUE
-ast_location_last_column(rb_execution_context_t *ec, VALUE self)
-{
- struct ASTLocationData *data;
- TypedData_Get_Struct(self, struct ASTLocationData, &rb_location_type, data);
-
- return INT2NUM(data->last_column);
-}
-
-static VALUE
-ast_location_inspect(rb_execution_context_t *ec, VALUE self)
-{
- VALUE str;
- VALUE cname;
- struct ASTLocationData *data;
- TypedData_Get_Struct(self, struct ASTLocationData, &rb_location_type, data);
-
- cname = rb_class_path(rb_obj_class(self));
- str = rb_str_new2("#<");
-
- rb_str_append(str, cname);
- rb_str_catf(str, ":@%d:%d-%d:%d>",
- data->first_lineno, data->first_column,
- data->last_lineno, data->last_column);
-
- return str;
+ VALUE ret = data->ast->body.script_lines;
+ if (!RB_TYPE_P(ret, T_ARRAY)) return Qnil;
+ return ret;
}
#include "ast.rbinc"
@@ -1053,7 +769,5 @@ Init_ast(void)
{
rb_mAST = rb_define_module_under(rb_cRubyVM, "AbstractSyntaxTree");
rb_cNode = rb_define_class_under(rb_mAST, "Node", rb_cObject);
- rb_cLocation = rb_define_class_under(rb_mAST, "Location", rb_cObject);
rb_undef_alloc_func(rb_cNode);
- rb_undef_alloc_func(rb_cLocation);
}
diff --git a/ast.rb b/ast.rb
index 3265292f7d..f3f72c747f 100644
--- a/ast.rb
+++ b/ast.rb
@@ -13,13 +13,14 @@
# access children nodes by name, etc.
#
# If you are looking for a stable API or an API working under multiple Ruby
-# implementations, consider using the _prism_ gem, which is the official
-# Ruby API to parse Ruby code.
+# implementations, consider using the _parser_ gem or Ripper. If you would
+# like to make RubyVM::AbstractSyntaxTree stable, please join the discussion
+# at https://bugs.ruby-lang.org/issues/14844.
#
module RubyVM::AbstractSyntaxTree
# call-seq:
- # RubyVM::AbstractSyntaxTree.parse(string, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
+ # RubyVM::AbstractSyntaxTree.parse(string, keep_script_lines: false, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
#
# Parses the given _string_ into an abstract syntax tree,
# returning the root node of that tree.
@@ -52,14 +53,14 @@ module RubyVM::AbstractSyntaxTree
# # (ERROR@1:7-1:11),
# # (LASGN@1:12-1:15 :y (LIT@1:14-1:15 2))]
#
- # Note that parsing continues even after the errored expression.
+ # Note that parsing continues even after the errored expresion.
#
- def self.parse string, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false
+ def self.parse string, keep_script_lines: false, error_tolerant: false, keep_tokens: false
Primitive.ast_s_parse string, keep_script_lines, error_tolerant, keep_tokens
end
# call-seq:
- # RubyVM::AbstractSyntaxTree.parse_file(pathname, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
+ # RubyVM::AbstractSyntaxTree.parse_file(pathname, keep_script_lines: false, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
#
# Reads the file from _pathname_, then parses it like ::parse,
# returning the root node of the abstract syntax tree.
@@ -71,13 +72,13 @@ module RubyVM::AbstractSyntaxTree
# # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-31:3>
#
# See ::parse for explanation of keyword argument meaning and usage.
- def self.parse_file pathname, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false
+ def self.parse_file pathname, keep_script_lines: false, error_tolerant: false, keep_tokens: false
Primitive.ast_s_parse_file pathname, keep_script_lines, error_tolerant, keep_tokens
end
# call-seq:
- # RubyVM::AbstractSyntaxTree.of(proc, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
- # RubyVM::AbstractSyntaxTree.of(method, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
+ # RubyVM::AbstractSyntaxTree.of(proc, keep_script_lines: false, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
+ # RubyVM::AbstractSyntaxTree.of(method, keep_script_lines: false, error_tolerant: false, keep_tokens: false) -> RubyVM::AbstractSyntaxTree::Node
#
# Returns AST nodes of the given _proc_ or _method_.
#
@@ -92,7 +93,7 @@ module RubyVM::AbstractSyntaxTree
# # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-3:3>
#
# See ::parse for explanation of keyword argument meaning and usage.
- def self.of body, keep_script_lines: RubyVM.keep_script_lines, error_tolerant: false, keep_tokens: false
+ def self.of body, keep_script_lines: false, error_tolerant: false, keep_tokens: false
Primitive.ast_s_of body, keep_script_lines, error_tolerant, keep_tokens
end
@@ -264,69 +265,12 @@ module RubyVM::AbstractSyntaxTree
lines = script_lines
if lines
lines = lines[first_lineno - 1 .. last_lineno - 1]
- lines[-1] = lines[-1].byteslice(0...last_column)
- lines[0] = lines[0].byteslice(first_column..-1)
+ lines[-1] = lines[-1][0...last_column]
+ lines[0] = lines[0][first_column..-1]
lines.join
else
nil
end
end
-
- # call-seq:
- # node.locations -> array
- #
- # Returns location objects associated with the AST node.
- # The returned array contains RubyVM::AbstractSyntaxTree::Location.
- def locations
- Primitive.ast_node_locations
- end
- end
-
- # RubyVM::AbstractSyntaxTree::Location instances are created by
- # RubyVM::AbstractSyntaxTree#locations.
- #
- # This class is MRI specific.
- #
- class Location
-
- # call-seq:
- # location.first_lineno -> integer
- #
- # The line number in the source code where this AST's text began.
- def first_lineno
- Primitive.ast_location_first_lineno
- end
-
- # call-seq:
- # location.first_column -> integer
- #
- # The column number in the source code where this AST's text began.
- def first_column
- Primitive.ast_location_first_column
- end
-
- # call-seq:
- # location.last_lineno -> integer
- #
- # The line number in the source code where this AST's text ended.
- def last_lineno
- Primitive.ast_location_last_lineno
- end
-
- # call-seq:
- # location.last_column -> integer
- #
- # The column number in the source code where this AST's text ended.
- def last_column
- Primitive.ast_location_last_column
- end
-
- # call-seq:
- # location.inspect -> string
- #
- # Returns debugging information about this location as a string.
- def inspect
- Primitive.ast_location_inspect
- end
end
end
diff --git a/basictest/test.rb b/basictest/test.rb
index 711e4f4ab3..95875b52a6 100755
--- a/basictest/test.rb
+++ b/basictest/test.rb
@@ -879,7 +879,7 @@ $x.sort!{|a,b| b-a} # reverse sort
test_ok($x == [7,5,3,2,1])
# split test
-$x = +"The Book of Mormon"
+$x = "The Book of Mormon"
test_ok($x.split(//).reverse!.join == $x.reverse)
test_ok($x.reverse == $x.reverse!)
test_ok("1 byte string".split(//).reverse.join(":") == "g:n:i:r:t:s: :e:t:y:b: :1")
@@ -1643,7 +1643,7 @@ test_ok(/^(?:ab+)+/ =~ "ababb" && $& == "ababb")
test_ok(/(\s+\d+){2}/ =~ " 1 2" && $& == " 1 2")
test_ok(/(?:\s+\d+){2}/ =~ " 1 2" && $& == " 1 2")
-$x = +<<END;
+$x = <<END;
ABCD
ABCD
END
@@ -1682,12 +1682,12 @@ test_ok(?a == ?a)
test_ok(?\C-a == "\1")
test_ok(?\M-a == "\341")
test_ok(?\M-\C-a == "\201")
-test_ok("a".dup.upcase![0] == ?A)
-test_ok("A".dup.downcase![0] == ?a)
-test_ok("abc".dup.tr!("a-z", "A-Z") == "ABC")
-test_ok("aabbcccc".dup.tr_s!("a-z", "A-Z") == "ABC")
-test_ok("abcc".dup.squeeze!("a-z") == "abc")
-test_ok("abcd".dup.delete!("bc") == "ad")
+test_ok("a".upcase![0] == ?A)
+test_ok("A".downcase![0] == ?a)
+test_ok("abc".tr!("a-z", "A-Z") == "ABC")
+test_ok("aabbcccc".tr_s!("a-z", "A-Z") == "ABC")
+test_ok("abcc".squeeze!("a-z") == "abc")
+test_ok("abcd".delete!("bc") == "ad")
$x = "abcdef"
$y = [ ?a, ?b, ?c, ?d, ?e, ?f ]
@@ -1700,7 +1700,7 @@ $x.each_byte {|i|
}
test_ok(!$bad)
-s = +"a string"
+s = "a string"
s[0..s.size]="another string"
test_ok(s == "another string")
diff --git a/benchmark/app_aobench.rb b/benchmark/app_aobench.rb
index c1546e08ab..16296af12b 100644
--- a/benchmark/app_aobench.rb
+++ b/benchmark/app_aobench.rb
@@ -151,7 +151,7 @@ def clamp(f)
i.to_i
end
-def orthoBasis(basis, n)
+def otherBasis(basis, n)
basis[2] = Vec.new(n.x, n.y, n.z)
basis[1] = Vec.new(0.0, 0.0, 0.0)
@@ -183,7 +183,7 @@ class Scene
def ambient_occlusion(isect)
basis = Array.new
- orthoBasis(basis, isect.n)
+ otherBasis(basis, isect.n)
ntheta = NAO_SAMPLES
nphi = NAO_SAMPLES
diff --git a/benchmark/array_large_literal.yml b/benchmark/array_large_literal.yml
deleted file mode 100644
index 423d68391f..0000000000
--- a/benchmark/array_large_literal.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-prelude: |
- def def_array(size)
- Object.class_eval(<<-END)
- def array_#{size}
- x = 1
- [#{(['x'] * size).join(',')}]
- end
- END
- end
- def_array(100)
- def_array(1000)
- def_array(10000)
- def_array(100000)
-benchmark:
- array_100: array_100
- array_1000: array_1000
- array_10000: array_10000
- array_100000: array_100000
-
diff --git a/benchmark/enum_sort_by.yml b/benchmark/enum_sort_by.yml
deleted file mode 100644
index d386353888..0000000000
--- a/benchmark/enum_sort_by.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-prelude: |
- array_length = 2
- fixnum_array2 = array_length.times.to_a.map {rand(10000)}
- float_array2 = array_length.times.to_a.map {rand(10000.0).to_f}
- string_array2 = array_length.times.to_a.map {"r" * rand(1..10000)}
- mix_array2 = array_length.times.to_a.map {if rand(1..100) <= 50 then rand(1..10000).to_f else rand(1..10000) end}
- all_zero_array2 =array_length.times.to_a.map {0}
-
- array_length = 10
- fixnum_array10 = array_length.times.to_a.map {rand(10000)}
- float_array10 = array_length.times.to_a.map {rand(10000.0).to_f}
- string_array10 = array_length.times.to_a.map {"r" * rand(1..10000)}
- mix_array10 = array_length.times.to_a.map {if rand(1..100) <= 50 then rand(1..10000).to_f else rand(1..10000) end}
- all_zero_array10 =array_length.times.to_a.map {0}
-
- array_length = 1000
- fixnum_array1000 = array_length.times.to_a.map {rand(10000)}
- float_array1000 = array_length.times.to_a.map {rand(10000.0).to_f}
- string_array1000 = array_length.times.to_a.map {"r" * rand(1..10000)}
- mix_array1000 = array_length.times.to_a.map {if rand(1..100) <= 50 then rand(1..10000).to_f else rand(1..10000) end}
- all_zero_array1000 =array_length.times.to_a.map {0}
-
- array_length = 100000
- fixnum_array100000 = array_length.times.to_a.map {rand(10000)}
- float_array100000 = array_length.times.to_a.map {rand(10000.0).to_f}
- string_array100000 = array_length.times.to_a.map {"r" * rand(1..10000)}
- mix_array100000 = array_length.times.to_a.map {if rand(1..100) <= 50 then rand(1..10000).to_f else rand(1..10000) end}
- all_zero_array100000 =array_length.times.to_a.map {0}
-
-benchmark:
- fixnum_array2.sort_by: fixnum_array2.sort_by {|a| a}
- float_array2.sort_by: float_array2.sort_by {|a| a}
- string_length2.sort_by: string_array2.sort_by {|a| a.length}
- mix_array2.sort_by: mix_array2.sort_by {|a| a}
- all_zero2.sort_by: all_zero_array2.sort_by{|a| a}
-
- fixnum_array10.sort_by: fixnum_array10.sort_by {|a| a}
- float_array10.sort_by: float_array10.sort_by {|a| a}
- string_length10.sort_by: string_array10.sort_by {|a| a.length}
- mix_array10.sort_by: mix_array10.sort_by {|a| a}
- all_zero10.sort_by: all_zero_array10.sort_by{|a| a}
-
- fixnum_array1000.sort_by: fixnum_array1000.sort_by {|a| a}
- float_array1000.sort_by: float_array1000.sort_by {|a| a}
- string_length1000.sort_by: string_array1000.sort_by {|a| a.length}
- mix_array1000.sort_by: mix_array1000.sort_by {|a| a}
- all_zero1000.sort_by: all_zero_array1000.sort_by{|a| a}
-
- fixnum_array100000.sort_by: fixnum_array100000.sort_by {|a| a}
- float_array100000.sort_by: float_array100000.sort_by {|a| a}
- string_length100000.sort_by: string_array100000.sort_by {|a| a.length}
- mix_array100000.sort_by: mix_array100000.sort_by {|a| a}
- all_zero100000.sort_by: all_zero_array100000.sort_by{|a| a}
diff --git a/benchmark/hash_aref_str_lit.yml b/benchmark/hash_aref_str_lit.yml
deleted file mode 100644
index ed8142bcf1..0000000000
--- a/benchmark/hash_aref_str_lit.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-prelude: |
- # frozen_string_literal: true
- hash = 10.times.to_h do |i|
- [i, i]
- end
- dyn_sym = "dynamic_symbol".to_sym
- binary = RubyVM::InstructionSequence.compile("# frozen_string_literal: true\n'iseq_load'").to_binary
- iseq_literal_string = RubyVM::InstructionSequence.load_from_binary(binary).eval
-
- hash[:some_symbol] = 1
- hash[dyn_sym] = 2
- hash["small"] = 3
- hash["frozen_string_literal"] = 4
- hash[iseq_literal_string] = 5
-benchmark:
- symbol: hash[:some_symbol]
- dyn_symbol: hash[dyn_sym]
- small_lit: hash["small"]
- frozen_lit: hash["frozen_string_literal"]
- iseq_lit: hash[iseq_literal_string]
diff --git a/benchmark/hash_key.yml b/benchmark/hash_key.yml
deleted file mode 100644
index cab4cf9ca4..0000000000
--- a/benchmark/hash_key.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-prelude: |
- obj = Object.new
- hash = { obj => true }
-benchmark: hash.key?(obj)
-loop_count: 30000000
diff --git a/benchmark/hash_new.yml b/benchmark/hash_new.yml
deleted file mode 100644
index 9d8e34187f..0000000000
--- a/benchmark/hash_new.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-prelude: |
- has_hash_with_capa = Hash.instance_method(:initialize).parameters.include?([:key, :capacity])
- strings_1k = 1_000.times.map { |i| -i.to_s.freeze }
- strings_100k = 100_000.times.map { |i| -i.to_s.freeze }
-benchmark:
- new: Hash.new
- new_with_capa_1k: |
- h = has_hash_with_capa ? Hash.new(capacity: strings_1k.size) : {}
- strings_1k.each do |x|
- h[x] = true
- end
- new_with_capa_100k: |
- h = has_hash_with_capa ? Hash.new(capacity: strings_100k.size) : {}
- strings_100k.each do |x|
- h[x] = true
- end
diff --git a/benchmark/lib/benchmark_driver/runner/mjit.rb b/benchmark/lib/benchmark_driver/runner/mjit.rb
new file mode 100644
index 0000000000..3a58a620de
--- /dev/null
+++ b/benchmark/lib/benchmark_driver/runner/mjit.rb
@@ -0,0 +1,34 @@
+require 'benchmark_driver/struct'
+require 'benchmark_driver/metric'
+require 'erb'
+
+# A runner to measure after-JIT performance easily
+class BenchmarkDriver::Runner::Mjit < BenchmarkDriver::Runner::Ips
+ # JobParser returns this, `BenchmarkDriver::Runner.runner_for` searches "*::Job"
+ Job = Class.new(BenchmarkDriver::DefaultJob)
+
+ # Dynamically fetched and used by `BenchmarkDriver::JobParser.parse`
+ JobParser = BenchmarkDriver::DefaultJobParser.for(klass: Job, metrics: [METRIC]).extend(Module.new{
+ def parse(**)
+ jobs = super
+ jobs.map do |job|
+ job = job.dup
+ job.prelude = "#{job.prelude}\n#{<<~EOS}"
+ if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled?
+ __bmdv_ruby_i = 0
+ while __bmdv_ruby_i < 10000 # MJIT call threshold
+ #{job.script}
+ __bmdv_ruby_i += 1
+ end
+ RubyVM::MJIT.pause # compile
+ #{job.script}
+ RubyVM::MJIT.resume; RubyVM::MJIT.pause # recompile
+ #{job.script}
+ RubyVM::MJIT.resume; RubyVM::MJIT.pause # recompile 2
+ end
+ EOS
+ job
+ end
+ end
+ })
+end
diff --git a/benchmark/loop_each.yml b/benchmark/loop_each.yml
deleted file mode 100644
index 1c757185a8..0000000000
--- a/benchmark/loop_each.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-prelude: |
- arr = [nil] * 30_000_000
-benchmark:
- loop_each: arr.each{|e|}
diff --git a/benchmark/loop_generator.rb b/benchmark/loop_generator.rb
index 6a3194b670..d3375c744c 100644
--- a/benchmark/loop_generator.rb
+++ b/benchmark/loop_generator.rb
@@ -1,4 +1,4 @@
-max = 6000000
+max = 600000
if defined? Fiber
gen = (1..max).each
diff --git a/benchmark/loop_times_megamorphic.yml b/benchmark/loop_times_megamorphic.yml
deleted file mode 100644
index f9343ba897..0000000000
--- a/benchmark/loop_times_megamorphic.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-prelude: |
- eval(<<~EOS)
- def loop_times_megamorphic
- #{"1.times {|i|};" * 1000}
- end
- EOS
-benchmark: loop_times_megamorphic
diff --git a/benchmark/mjit_exivar.yml b/benchmark/mjit_exivar.yml
new file mode 100644
index 0000000000..2584fa6410
--- /dev/null
+++ b/benchmark/mjit_exivar.yml
@@ -0,0 +1,18 @@
+type: lib/benchmark_driver/runner/mjit
+prelude: |
+ class Bench < Hash
+ def initialize
+ @exivar = nil
+ end
+
+ def exivar
+ @exivar
+ end
+ end
+
+ bench = Bench.new
+
+benchmark:
+ mjit_exivar: bench.exivar
+
+loop_count: 200000000
diff --git a/benchmark/mjit_integer.yml b/benchmark/mjit_integer.yml
new file mode 100644
index 0000000000..a6b5c9ee16
--- /dev/null
+++ b/benchmark/mjit_integer.yml
@@ -0,0 +1,32 @@
+type: lib/benchmark_driver/runner/mjit
+prelude: |
+ def mjit_abs(int) int.abs end
+ def mjit_bit_length(int) int.bit_length end
+ def mjit_comp(int) ~int end
+ def mjit_even?(int) int.even? end
+ def mjit_integer?(int) int.integer? end
+ def mjit_magnitude(int) int.magnitude end
+ def mjit_odd?(int) int.odd? end
+ def mjit_ord(int) int.ord end
+ def mjit_size(int) int.size end
+ def mjit_to_i(int) int.to_i end
+ def mjit_to_int(int) int.to_int end
+ def mjit_uminus(int) -int end
+ def mjit_zero?(int) int.zero? end
+
+benchmark:
+ - mjit_abs(-1)
+ - mjit_bit_length(100)
+ - mjit_comp(1)
+ - mjit_even?(2)
+ - mjit_integer?(0)
+ - mjit_magnitude(-1)
+ - mjit_odd?(1)
+ - mjit_ord(1)
+ - mjit_size(1)
+ - mjit_to_i(1)
+ - mjit_to_int(1)
+ - mjit_uminus(1)
+ - mjit_zero?(0)
+
+loop_count: 40000000
diff --git a/benchmark/mjit_kernel.yml b/benchmark/mjit_kernel.yml
new file mode 100644
index 0000000000..7720e65c2c
--- /dev/null
+++ b/benchmark/mjit_kernel.yml
@@ -0,0 +1,20 @@
+type: lib/benchmark_driver/runner/mjit
+prelude: |
+ def mjit_class(obj)
+ obj.class
+ end
+
+ def mjit_frozen?(obj)
+ obj.frozen?
+ end
+
+ str = ""
+ fstr = "".freeze
+
+benchmark:
+ - mjit_class(self)
+ - mjit_class(1)
+ - mjit_frozen?(str)
+ - mjit_frozen?(fstr)
+
+loop_count: 40000000
diff --git a/benchmark/mjit_leave.yml b/benchmark/mjit_leave.yml
new file mode 100644
index 0000000000..9ac68b164b
--- /dev/null
+++ b/benchmark/mjit_leave.yml
@@ -0,0 +1,8 @@
+type: lib/benchmark_driver/runner/mjit
+prelude: |
+ def leave
+ nil
+ end
+benchmark:
+ mjit_leave: leave
+loop_count: 200000000
diff --git a/benchmark/mjit_opt_cc_insns.yml b/benchmark/mjit_opt_cc_insns.yml
new file mode 100644
index 0000000000..fed6d34bd5
--- /dev/null
+++ b/benchmark/mjit_opt_cc_insns.yml
@@ -0,0 +1,27 @@
+# opt_* insns using vm_method_cfunc_is with send-compatible operands:
+# * opt_nil_p
+# * opt_not
+# * opt_eq
+type: lib/benchmark_driver/runner/mjit
+prelude: |
+ def mjit_nil?(obj)
+ obj.nil?
+ end
+
+ def mjit_not(obj)
+ !obj
+ end
+
+ def mjit_eq(a, b)
+ a == b
+ end
+
+benchmark:
+ - script: mjit_nil?(1)
+ loop_count: 40000000
+ - script: mjit_not(1)
+ loop_count: 40000000
+ - script: mjit_eq(1, nil)
+ loop_count: 8000000
+ - script: mjit_eq(nil, 1)
+ loop_count: 8000000
diff --git a/benchmark/mjit_struct_aref.yml b/benchmark/mjit_struct_aref.yml
new file mode 100644
index 0000000000..bfba1323f2
--- /dev/null
+++ b/benchmark/mjit_struct_aref.yml
@@ -0,0 +1,10 @@
+type: lib/benchmark_driver/runner/mjit
+prelude: |
+ def mjit_struct_aref(struct)
+ struct.aa
+ end
+ struct = Struct.new(:a0, :a1, :a2, :a3, :a4, :a5, :a6, :a7, :a8, :a9, :aa).new
+
+benchmark: mjit_struct_aref(struct)
+
+loop_count: 40000000
diff --git a/benchmark/object_allocate.yml b/benchmark/object_allocate.yml
index bdbd4536db..93ff463e41 100644
--- a/benchmark/object_allocate.yml
+++ b/benchmark/object_allocate.yml
@@ -11,26 +11,6 @@ prelude: |
class OneTwentyEight
128.times { include(Module.new) }
end
- class OnePositional
- def initialize a; end
- end
- class TwoPositional
- def initialize a, b; end
- end
- class ThreePositional
- def initialize a, b, c; end
- end
- class FourPositional
- def initialize a, b, c, d; end
- end
- class KWArg
- def initialize a:, b:, c:, d:
- end
- end
- class Mixed
- def initialize a, b, c:, d:
- end
- end
# Disable GC to see raw throughput:
GC.disable
benchmark:
@@ -38,11 +18,4 @@ benchmark:
allocate_32_deep: ThirtyTwo.new
allocate_64_deep: SixtyFour.new
allocate_128_deep: OneTwentyEight.new
- allocate_1_positional_params: OnePositional.new(1)
- allocate_2_positional_params: TwoPositional.new(1, 2)
- allocate_3_positional_params: ThreePositional.new(1, 2, 3)
- allocate_4_positional_params: FourPositional.new(1, 2, 3, 4)
- allocate_kwarg_params: "KWArg.new(a: 1, b: 2, c: 3, d: 4)"
- allocate_mixed_params: "Mixed.new(1, 2, c: 3, d: 4)"
- allocate_no_params: "Object.new"
loop_count: 100000
diff --git a/benchmark/range_bsearch_bignum.yml b/benchmark/range_bsearch_bignum.yml
deleted file mode 100644
index 5730c93fcf..0000000000
--- a/benchmark/range_bsearch_bignum.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-prelude: |
- first = 2**100
- last = 2**1000
- mid = (first + last) / 2
- r = first..last
-
-benchmark:
- first: r.bsearch { |x| x >= first }
- mid: r.bsearch { |x| x >= mid }
- last: r.bsearch { |x| x >= last }
diff --git a/benchmark/range_bsearch_endpointless.yml b/benchmark/range_bsearch_endpointless.yml
deleted file mode 100644
index 8d7bedb662..0000000000
--- a/benchmark/range_bsearch_endpointless.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-prelude: |
- re = (1..)
- rb = (..0)
-
-benchmark:
- 'endless 10**0': re.bsearch { |x| x >= 1 }
- 'endless 10**1': re.bsearch { |x| x >= 10 }
- 'endless 10**2': re.bsearch { |x| x >= 100 }
- 'endless 10**3': re.bsearch { |x| x >= 1000 }
- 'endless 10**4': re.bsearch { |x| x >= 10000 }
- 'endless 10**5': re.bsearch { |x| x >= 100000 }
- 'endless 10**10': re.bsearch { |x| x >= 10000000000 }
- 'endless 10**100': re.bsearch { |x| x >= 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 }
- 'beginless -10**0': rb.bsearch { |x| x >= -1 }
- 'beginless -10**1': rb.bsearch { |x| x >= -10 }
- 'beginless -10**2': rb.bsearch { |x| x >= -100 }
- 'beginless -10**3': rb.bsearch { |x| x >= -1000 }
- 'beginless -10**4': rb.bsearch { |x| x >= -10000 }
- 'beginless -10**5': rb.bsearch { |x| x >= -100000 }
- 'beginless -10**10': rb.bsearch { |x| x >= -10000000000 }
- 'beginless -10**100': rb.bsearch { |x| x >= -10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 }
diff --git a/benchmark/range_bsearch_fixnum.yml b/benchmark/range_bsearch_fixnum.yml
deleted file mode 100644
index 59416531b9..0000000000
--- a/benchmark/range_bsearch_fixnum.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-prelude: |
- first = 1
- last = 10000
- mid = (first + last) / 2
- r = first..last
-
-benchmark:
- first: r.bsearch { |x| x >= first }
- mid: r.bsearch { |x| x >= mid }
- last: r.bsearch { |x| x >= last }
diff --git a/benchmark/range_count.yml b/benchmark/range_count.yml
deleted file mode 100644
index 58f53a0236..0000000000
--- a/benchmark/range_count.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-prelude: |
- r_1 = 1..1
- r_1k = 1..1000
- r_1m = 1..1000000
- r_str = 'a'..'z'
-
-benchmark:
- 'int 1': r_1.count
- 'int 1K': r_1k.count
- 'int 1M': r_1m.count
- string: r_str.count
diff --git a/benchmark/range_overlap.yml b/benchmark/range_overlap.yml
deleted file mode 100644
index 700a00053c..0000000000
--- a/benchmark/range_overlap.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-prelude: |
- class Range
- unless method_defined?(:overlap?)
- def overlap?(other)
- other.begin == self.begin || cover?(other.begin) || other.cover?(self.begin)
- end
- end
- end
-
-benchmark:
- - (2..3).overlap?(1..1)
- - (2..3).overlap?(2..4)
- - (2..3).overlap?(4..5)
- - (2..3).overlap?(2..1)
- - (2..3).overlap?(0..1)
- - (2..3).overlap?(...1)
- - (2...3).overlap?(..2)
- - (2...3).overlap?(3...)
- - (2..3).overlap?('a'..'d')
diff --git a/benchmark/range_reverse_each.yml b/benchmark/range_reverse_each.yml
deleted file mode 100644
index a32efeccc6..0000000000
--- a/benchmark/range_reverse_each.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-prelude: |
- rf_1 = 0..1
- rf_1k = 0..1000
- rf_1m = 0..1000000
- big = 2**1000
- rb_1 = big..big+1
- rb_1k = big..big+1000
- rb_1m = big..big+1000000
-
-benchmark:
- "Fixnum 1": rf_1.reverse_each { _1 }
- "Fixnum 1K": rf_1k.reverse_each { _1 }
- "Fixnum 1M": rf_1m.reverse_each { _1 }
- "Bignum 1": rb_1.reverse_each { _1 }
- "Bignum 1K": rb_1k.reverse_each { _1 }
- "Bignum 1M": rb_1m.reverse_each { _1 }
diff --git a/benchmark/realpath.yml b/benchmark/realpath.yml
index 6b6a4836b0..90a029d5b9 100644
--- a/benchmark/realpath.yml
+++ b/benchmark/realpath.yml
@@ -12,9 +12,6 @@ prelude: |
relative_dir = 'b/c'
absolute_dir = File.join(pwd, relative_dir)
file_dir = 'c'
-teardown: |
- require 'fileutils'
- FileUtils.rm_rf('b')
benchmark:
relative_nil: "f.realpath(relative, nil)"
absolute_nil: "f.realpath(absolute, nil)"
diff --git a/benchmark/regexp_dup.yml b/benchmark/regexp_dup.yml
deleted file mode 100644
index 52f89991cd..0000000000
--- a/benchmark/regexp_dup.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-prelude: |
- str = "a" * 1000
- re = Regexp.new(str)
-
-benchmark:
- dup: re.dup
diff --git a/benchmark/regexp_new.yml b/benchmark/regexp_new.yml
deleted file mode 100644
index bc9ab3ca21..0000000000
--- a/benchmark/regexp_new.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-prelude: |
- str = "a" * 1000
- re = Regexp.new(str)
-
-benchmark:
- string: Regexp.new(str)
- regexp: Regexp.new(re)
diff --git a/benchmark/so_count_words.yml b/benchmark/so_count_words.yml
index f7322a8541..99683505f9 100644
--- a/benchmark/so_count_words.yml
+++ b/benchmark/so_count_words.yml
@@ -15,13 +15,13 @@ prelude: |
Newsgroups: rec.games.roguelike.nethack
X-Mailer: Mozilla 1.1N (Macintosh; I; 68K)
- Hello there, Izchak Miller was my father. When I was younger I spent
- many a night, hunched over the keyboard with a cup of tea, playing
- nethack with him and my brother. my dad was a philosopher with a strong
- weakness for fantasy/sci fi. I remember when he started to get involved
- with the Nethack team- my brother's Dungeons and Dragons monster book
- found a regular place beside my dad's desk. it's nice to see him living
- on in the game he loved so much :-).
+ Hello there, Izchak Miller was my father. When I was younger I spent
+ many a night, hunched over the keyboard with a cup of tea, playing
+ nethack with him and my brother. my dad was a philosopher with a strong
+ weakness for fantasy/sci fi. I remember when he started to get involved
+ with the Nethack team- my brother's Dungeons and Dragons monster book
+ found a regular place beside my dad's desk. it's nice to see him living
+ on in the game he loved so much :-).
Tamar Miller
The following is a really long word of 5000 characters:
@@ -38,9 +38,8 @@ prelude: |
13.times{
data << data
}
- File.write(wcinput, data)
+ open(wcinput, 'w'){|f| f.write data}
end
- at_exit {File.unlink(wcinput) rescue nil}
end
prepare_wc_input(wc_input_base)
@@ -50,16 +49,16 @@ benchmark:
# $Id: wc-ruby.code,v 1.4 2004/11/13 07:43:32 bfulgham Exp $
# http://www.bagley.org/~doug/shootout/
# with help from Paul Brannan
+ input = open(File.join(File.dirname($0), 'wc.input'), 'rb')
nl = nw = nc = 0
- File.open(File.join(File.dirname($0), 'wc.input'), 'rb') do |input|
- while tmp = input.read(4096)
- data = tmp << (input.gets || "")
- nc += data.length
- nl += data.count("\n")
- ((data.strip! || data).tr!("\n", " ") || data).squeeze!
- nw += data.count(" ") + 1
- end
+ while true
+ tmp = input.read(4096) or break
+ data = tmp << (input.gets || "")
+ nc += data.length
+ nl += data.count("\n")
+ ((data.strip! || data).tr!("\n", " ") || data).squeeze!
+ nw += data.count(" ") + 1
end
# STDERR.puts "#{nl} #{nw} #{nc}"
diff --git a/benchmark/so_meteor_contest.rb b/benchmark/so_meteor_contest.rb
index d8c8e3ab9c..8c136baa6c 100644
--- a/benchmark/so_meteor_contest.rb
+++ b/benchmark/so_meteor_contest.rb
@@ -447,7 +447,7 @@ end
# as an inverse. The inverse will ALWAYS be 3 one of the piece configurations that is exactly 3 rotations away
# (an odd number). Checking even vs odd then produces a higher probability of finding more pieces earlier
# in the cycle. We still need to keep checking all the permutations, but our probability of finding one will
-# diminish over time. Since we are TOLD how many to search for this lets us exit before checking all pieces
+# diminsh over time. Since we are TOLD how many to search for this lets us exit before checking all pieces
# this bennifit is very great when seeking small numbers of solutions and is 0 when looking for more than the
# maximum number
def find_top( rotation_skip)
diff --git a/benchmark/string_concat.yml b/benchmark/string_concat.yml
index f11f95ee9a..e65c00cca9 100644
--- a/benchmark/string_concat.yml
+++ b/benchmark/string_concat.yml
@@ -1,8 +1,6 @@
prelude: |
CHUNK = "a" * 64
UCHUNK = "é" * 32
- SHORT = "a" * (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] / 2)
- LONG = "a" * (GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] * 2)
GC.disable # GC causes a lot of variance
benchmark:
binary_concat_7bit: |
@@ -45,7 +43,3 @@ benchmark:
"#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}" \
"#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}" \
"#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}#{CHUNK}"
- interpolation_same_heap: |
- buffer = "#{SHORT}#{SHORT}"
- interpolation_switching_heaps: |
- buffer = "#{SHORT}#{LONG}"
diff --git a/benchmark/string_dup.yml b/benchmark/string_dup.yml
deleted file mode 100644
index 90793f9f2a..0000000000
--- a/benchmark/string_dup.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-prelude: |
- # frozen_string_literal: true
-benchmark:
- uplus: |
- +"A"
- dup: |
- "A".dup
diff --git a/benchmark/string_rpartition.yml b/benchmark/string_rpartition.yml
deleted file mode 100644
index 37e9d1b071..0000000000
--- a/benchmark/string_rpartition.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-prelude: |
- str1 = [*"a".."z",*"0".."9"].join("")
- str10 = str1 * 10 + ":"
- str100 = str1 * 100 + ":"
- str1000 = str1 * 1000 + ":"
- nonascii1 = [*"\u{e0}".."\u{ff}"].join("")
- nonascii10 = nonascii1 * 10 + ":"
- nonascii100 = nonascii1 * 100 + ":"
- nonascii1000 = nonascii1 * 1000 + ":"
-benchmark:
- rpartition-1: str1.rpartition(":")
- rpartition-10: str10.rpartition(":")
- rpartition-100: str100.rpartition(":")
- rpartition-1000: str1000.rpartition(":")
- rpartition-nonascii1: nonascii1.rpartition(":")
- rpartition-nonascii10: nonascii10.rpartition(":")
- rpartition-nonascii100: nonascii100.rpartition(":")
- rpartition-nonascii1000: nonascii1000.rpartition(":")
diff --git a/benchmark/struct_accessor.yml b/benchmark/struct_accessor.yml
deleted file mode 100644
index 61176cfdd4..0000000000
--- a/benchmark/struct_accessor.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-prelude: |
- C = Struct.new(:x) do
- class_eval <<-END
- def r
- #{'x;'*256}
- end
- def w
- #{'self.x = nil;'*256}
- end
- def rm
- m = method(:x)
- #{'m.call;'*256}
- end
- def wm
- m = method(:x=)
- #{'m.call(nil);'*256}
- end
- END
- end
- obj = C.new(nil)
-benchmark:
- member_reader: "obj.r"
- member_writer: "obj.w"
- member_reader_method: "obj.rm"
- member_writer_method: "obj.wm"
diff --git a/benchmark/time_strftime.yml b/benchmark/time_strftime.yml
deleted file mode 100644
index 28f62aec87..0000000000
--- a/benchmark/time_strftime.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-prelude: |
- # frozen_string_literal: true
- time = Time.now
-benchmark:
- - time.strftime("%FT%T") # 19B
- - time.strftime("%FT%T.%3N") # 23B
- - time.strftime("%FT%T.%6N") # 26B
diff --git a/benchmark/time_xmlschema.yml b/benchmark/time_xmlschema.yml
deleted file mode 100644
index 654e5cfcbc..0000000000
--- a/benchmark/time_xmlschema.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-prelude: |
- # frozen_string_literal
- unless Time.method_defined?(:xmlschema)
- class Time
- def xmlschema(fraction_digits=0)
- fraction_digits = fraction_digits.to_i
- s = strftime("%FT%T")
- if fraction_digits > 0
- s << strftime(".%#{fraction_digits}N")
- end
- s << (utc? ? 'Z' : strftime("%:z"))
- end
- end
- end
- time = Time.now
- utc_time = Time.now.utc
- fraction_sec = Time.at(123456789.quo(9999999999)).getlocal("+09:00")
- future_time = Time.utc(10000)
-benchmark:
- - time.xmlschema
- - utc_time.xmlschema
- - time.xmlschema(6)
- - utc_time.xmlschema(6)
- - time.xmlschema(9)
- - utc_time.xmlschema(9)
- - fraction_sec.xmlschema(10)
- - future_time.xmlschema
diff --git a/benchmark/vm_call_bmethod.yml b/benchmark/vm_call_bmethod.yml
deleted file mode 100644
index 40136e5aa4..0000000000
--- a/benchmark/vm_call_bmethod.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-prelude: |
- define_method(:a0){}
- define_method(:a1){|a| a}
- define_method(:s){|*a| a}
- define_method(:b){|kw: 1| kw}
-
- t0 = 0.times.to_a
- t1 = 1.times.to_a
- t10 = 10.times.to_a
- t100 = 100.times.to_a
- kw = {kw: 2}
-benchmark:
- bmethod_simple_0: |
- a0
- bmethod_simple_1: |
- a1(1)
- bmethod_simple_0_splat: |
- a0(*t0)
- bmethod_simple_1_splat: |
- a1(*t1)
- bmethod_no_splat: |
- s
- bmethod_0_splat: |
- s(*t0)
- bmethod_1_splat: |
- s(*t1)
- bmethod_10_splat: |
- s(*t10)
- bmethod_100_splat: |
- s(*t100)
- bmethod_kw: |
- b(kw: 1)
- bmethod_no_kw: |
- b
- bmethod_kw_splat: |
- b(**kw)
-loop_count: 6000000
diff --git a/benchmark/vm_call_kw_and_kw_splat.yml b/benchmark/vm_call_kw_and_kw_splat.yml
deleted file mode 100644
index aa6e549e0c..0000000000
--- a/benchmark/vm_call_kw_and_kw_splat.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-prelude: |
- h1, h10, h100, h1000 = [1, 10, 100, 1000].map do |n|
- h = {kw: 1}
- n.times{|i| h[i.to_s.to_sym] = i}
- h
- end
- eh = {}
- def kw(kw: nil, **kws) end
-benchmark:
- 1: |
- kw(**h1)
- 1_mutable: |
- kw(**eh, **h1)
- 10: |
- kw(**h10)
- 10_mutable: |
- kw(**eh, **h10)
- 100: |
- kw(**h100)
- 100_mutable: |
- kw(**eh, **h100)
- 1000: |
- kw(**h1000)
- 1000_mutable: |
- kw(**eh, **h1000)
diff --git a/benchmark/vm_call_method_missing.yml b/benchmark/vm_call_method_missing.yml
deleted file mode 100644
index f890796f11..0000000000
--- a/benchmark/vm_call_method_missing.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-prelude: |
- class A0
- def method_missing(m); m end
- end
- class A1
- def method_missing(m, a) a; end
- end
- class S
- def method_missing(m, *a) a; end
- end
- class B
- def method_missing(m, kw: 1) kw end
- end
- class SB
- def method_missing(m, *a, kw: 1) kw end
- end
-
- t0 = 0.times.to_a
- t1 = 1.times.to_a
- t10 = 10.times.to_a
- t200 = 200.times.to_a
- kw = {kw: 2}
-
- a0 = A0.new
- a1 = A1.new
- s = S.new
- b = B.new
- sb = SB.new
-benchmark:
- method_missing_simple_0: |
- a0.()
- method_missing_simple_1: |
- a1.x(1)
- method_missing_simple_0_splat: |
- a0.(*t0)
- method_missing_simple_1_splat: |
- a1.(*t1)
- method_missing_no_splat: |
- s.()
- method_missing_0_splat: |
- s.(*t0)
- method_missing_1_splat: |
- s.(*t1)
- method_missing_10_splat: |
- s.(*t10)
- method_missing_200_splat: |
- s.(*t200)
- method_missing_kw: |
- b.(kw: 1)
- method_missing_no_kw: |
- b.()
- method_missing_kw_splat: |
- b.(**kw)
- method_missing_0_splat_kw: |
- sb.(*t0, **kw)
- method_missing_1_splat_kw: |
- sb.(*t1, **kw)
- method_missing_10_splat_kw: |
- sb.(*t10, **kw)
- method_missing_200_splat_kw: |
- sb.(*t200, **kw)
-loop_count: 1000000
diff --git a/benchmark/vm_call_send_iseq.yml b/benchmark/vm_call_send_iseq.yml
deleted file mode 100644
index 60ff23c475..0000000000
--- a/benchmark/vm_call_send_iseq.yml
+++ /dev/null
@@ -1,77 +0,0 @@
-prelude: |
- def a0; end
- def a1(a) a; end
- def s(*a) a; end
- def b(kw: 1) kw end
- def sb(*a, kw: 1) kw end
-
- t0 = 0.times.to_a
- t1 = 1.times.to_a
- t10 = 10.times.to_a
- t200 = 200.times.to_a
-
- a0_t0 = [:a0, *t0]
- a1_t1 = [:a1, *t1]
- s_t0 = [:s, *t0]
- s_t1 = [:s, *t1]
- s_t10 = [:s, *t10]
- s_t200 = [:s, *t200]
- sb_t0 = [:sb, *t0]
- sb_t1 = [:sb, *t1]
- sb_t10 = [:sb, *t10]
- sb_t200 = [:sb, *t200]
- kw = {kw: 2}
-benchmark:
- send_simple_0: |
- send(:a0)
- send_simple_1: |
- send(:a1, 1)
- send_simple_0_splat: |
- send(:a0, *t0)
- send_simple_1_splat: |
- send(:a1, *t1)
- send_simple_0_splat_comb: |
- send(*a0_t0)
- send_simple_1_splat_comb: |
- send(*a1_t1)
- send_no_splat: |
- send(:s)
- send_0_splat: |
- send(:s, *t0)
- send_1_splat: |
- send(:s, *t1)
- send_10_splat: |
- send(:s, *t10)
- send_200_splat: |
- send(:s, *t200)
- send_0_splat_comb: |
- send(*s_t0)
- send_1_splat_comb: |
- send(*s_t1)
- send_10_splat_comb: |
- send(*s_t10)
- send_200_splat_comb: |
- send(*s_t200)
- send_kw: |
- send(:b, kw: 1)
- send_no_kw: |
- send(:b)
- send_kw_splat: |
- send(:b, **kw)
- send_0_splat_kw: |
- send(:sb, *t0, **kw)
- send_1_splat_kw: |
- send(:sb, *t1, **kw)
- send_10_splat_kw: |
- send(:sb, *t10, **kw)
- send_200_splat_kw: |
- send(:sb, *t200, **kw)
- send_0_splat_comb_kw: |
- send(*sb_t0, **kw)
- send_1_splat_comb_kw: |
- send(*sb_t1, **kw)
- send_10_splat_comb_kw: |
- send(*sb_t10, **kw)
- send_200_splat_comb_kw: |
- send(*sb_t200, **kw)
-loop_count: 3000000
diff --git a/benchmark/vm_call_symproc.yml b/benchmark/vm_call_symproc.yml
deleted file mode 100644
index 16e0ac579e..0000000000
--- a/benchmark/vm_call_symproc.yml
+++ /dev/null
@@ -1,83 +0,0 @@
-prelude: |
- def self.a0; end
- def self.a1(a) a; end
- def self.s(*a) a; end
- def self.b(kw: 1) kw end
- def self.sb(*a, kw: 1) kw end
-
- t0 = 0.times.to_a
- t1 = 1.times.to_a
- t10 = 10.times.to_a
- t200 = 200.times.to_a
-
- a0_t0 = [self, *t0]
- a1_t1 = [self, *t1]
- s_t0 = [self, *t0]
- s_t1 = [self, *t1]
- s_t10 = [self, *t10]
- s_t200 = [self, *t200]
- sb_t0 = [self, *t0]
- sb_t1 = [self, *t1]
- sb_t10 = [self, *t10]
- sb_t200 = [self, *t200]
- kw = {kw: 2}
-
- a0 = :a0.to_proc
- a1 = :a1.to_proc
- s = :s.to_proc
- b = :b.to_proc
- sb = :sb.to_proc
-benchmark:
- symproc_simple_0: |
- a0.(self)
- symproc_simple_1: |
- a1.(self, 1)
- symproc_simple_0_splat: |
- a0.(self, *t0)
- symproc_simple_1_splat: |
- a1.(self, *t1)
- symproc_simple_0_splat_comb: |
- a0.(*a0_t0)
- symproc_simple_1_splat_comb: |
- a1.(*a1_t1)
- symproc_no_splat: |
- s.(self)
- symproc_0_splat: |
- s.(self, *t0)
- symproc_1_splat: |
- s.(self, *t1)
- symproc_10_splat: |
- s.(self, *t10)
- symproc_200_splat: |
- s.(self, *t200)
- symproc_0_splat_comb: |
- s.(*s_t0)
- symproc_1_splat_comb: |
- s.(*s_t1)
- symproc_10_splat_comb: |
- s.(*s_t10)
- symproc_200_splat_comb: |
- s.(*s_t200)
- symproc_kw: |
- b.(self, kw: 1)
- symproc_no_kw: |
- b.(self)
- symproc_kw_splat: |
- b.(self, **kw)
- symproc_0_splat_kw: |
- sb.(self, *t0, **kw)
- symproc_1_splat_kw: |
- sb.(self, *t1, **kw)
- symproc_10_splat_kw: |
- sb.(self, *t10, **kw)
- symproc_200_splat_kw: |
- sb.(self, *t200, **kw)
- symproc_0_splat_comb_kw: |
- sb.(*sb_t0, **kw)
- symproc_1_splat_comb_kw: |
- sb.(*sb_t1, **kw)
- symproc_10_splat_comb_kw: |
- sb.(*sb_t10, **kw)
- symproc_200_splat_comb_kw: |
- sb.(*sb_t200, **kw)
-loop_count: 1000000
diff --git a/benchmark/vm_ivar_ic_miss.yml b/benchmark/vm_ivar_ic_miss.yml
deleted file mode 100644
index 944fb1a9e6..0000000000
--- a/benchmark/vm_ivar_ic_miss.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-prelude: |
- class Foo
- def initialize diverge
- if diverge
- @a = 1
- end
-
- @a0 = @a1 = @a2 = @a3 = @a4 = @a5 = @a6 = @a7 = @a8 = @a9 = @a10 = @a11 = @a12 = @a13 = @a14 = @a15 = @a16 = @a17 = @a18 = @a19 = @a20 = @a21 = @a22 = @a23 = @a24 = @a25 = @a26 = @a27 = @a28 = @a29 = @a30 = @a31 = @a32 = @a33 = @a34 = @a35 = @a36 = @a37 = @a38 = @a39 = @a40 = @a41 = @a42 = @a43 = @a44 = @a45 = @a46 = @a47 = @a48 = @a49 = @a50 = @a51 = @a52 = @a53 = @a54 = @a55 = @a56 = @a57 = @a58 = @a59 = @a60 = @a61 = @a62 = @a63 = @a64 = @a65 = @a66 = @a67 = @a68 = @a69 = @a70 = @a71 = @a72 = @a73 = @a74 = @b = 1
- end
-
- def b; @b; end
- end
-
- a = Foo.new false
- b = Foo.new true
-benchmark:
- vm_ivar_ic_miss: |
- a.b
- b.b
-loop_count: 30000000
diff --git a/benchmark/vm_ivar_memoize.yml b/benchmark/vm_ivar_memoize.yml
deleted file mode 100644
index 90f6b07f05..0000000000
--- a/benchmark/vm_ivar_memoize.yml
+++ /dev/null
@@ -1,85 +0,0 @@
-prelude: |
- IVARS = 60
- class Record
- def initialize(offset = false)
- @offset = 1 if offset
- @first = 0
- IVARS.times do |i|
- instance_variable_set("@ivar_#{i}", i)
- end
- end
-
- def first
- @first
- end
-
- def lazy_set
- @lazy_set ||= 123
- end
-
- def undef
- @undef
- end
- end
-
- Record.new # Need one alloc to right size
-
- BASE = Record.new
- LAZY = Record.new
- LAZY.lazy_set
-
- class Miss < Record
- @first = 0
- IVARS.times do |i|
- instance_variable_set("@i_#{i}", i)
- end
- end
-
- Miss.new # Need one alloc to right size
- MISS = Miss.new
-
- DIVERGENT = Record.new(true)
-
-benchmark:
- vm_ivar_stable_shape: |
- BASE.first
- BASE.first
- BASE.first
- BASE.first
- BASE.first
- BASE.first
- vm_ivar_memoize_unstable_shape: |
- BASE.first
- LAZY.first
- BASE.first
- LAZY.first
- BASE.first
- LAZY.first
- vm_ivar_memoize_unstable_shape_miss: |
- BASE.first
- MISS.first
- BASE.first
- MISS.first
- BASE.first
- MISS.first
- vm_ivar_unstable_undef: |
- BASE.undef
- LAZY.undef
- BASE.undef
- LAZY.undef
- BASE.undef
- LAZY.undef
- vm_ivar_divergent_shape: |
- BASE.first
- DIVERGENT.first
- BASE.first
- DIVERGENT.first
- BASE.first
- DIVERGENT.first
- vm_ivar_divergent_shape_imbalanced: |
- BASE.first
- DIVERGENT.first
- DIVERGENT.first
- DIVERGENT.first
- DIVERGENT.first
- DIVERGENT.first
diff --git a/benchmark/vm_method_splat_calls.yml b/benchmark/vm_method_splat_calls.yml
deleted file mode 100644
index f2f366e99c..0000000000
--- a/benchmark/vm_method_splat_calls.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-prelude: |
- def f(x=0, y: 0) end
- a = [1]
- ea = []
- kw = {y: 1}
- b = lambda{}
-benchmark:
- arg_splat: "f(1, *ea)"
- arg_splat_block: "f(1, *ea, &b)"
- splat_kw_splat: "f(*a, **kw)"
- splat_kw_splat_block: "f(*a, **kw, &b)"
- splat_kw: "f(*a, y: 1)"
- splat_kw_block: "f(*a, y: 1, &b)"
diff --git a/benchmark/vm_method_splat_calls2.yml b/benchmark/vm_method_splat_calls2.yml
deleted file mode 100644
index d33dcd7e8b..0000000000
--- a/benchmark/vm_method_splat_calls2.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-prelude: |
- def named_arg_splat(*a) end
- def named_arg_kw_splat(*a, **kw) end
- def anon_arg_splat(*) end
- def anon_kw_splat(**) end
- def anon_arg_kw_splat(*, **) end
- def anon_fw_to_named(*, **) named_arg_kw_splat(*, **) end
- def fw_to_named(...) named_arg_kw_splat(...) end
- def fw_to_anon_to_named(...) anon_fw_to_named(...) end
- def fw_no_kw(...) named_arg_splat(...) end
- a = [1]
- kw = {y: 1}
-benchmark:
- named_multi_arg_splat: "named_arg_splat(*a, *a)"
- named_post_splat: "named_arg_splat(*a, a)"
- anon_arg_splat: "anon_arg_splat(*a)"
- anon_arg_kw_splat: "anon_arg_kw_splat(*a, **kw)"
- anon_multi_arg_splat: "anon_arg_splat(*a, *a)"
- anon_post_splat: "anon_arg_splat(*a, a)"
- anon_kw_splat: "anon_kw_splat(**kw)"
- anon_fw_to_named_splat: "anon_fw_to_named(*a, **kw)"
- anon_fw_to_named_no_splat: "anon_fw_to_named(1, y: 1)"
- fw_to_named_splat: "fw_to_named(*a, **kw)"
- fw_to_named_no_splat: "fw_to_named(1, y: 1)"
- fw_to_anon_to_named_splat: "fw_to_anon_to_named(*a, **kw)"
- fw_to_anon_to_named_no_splat: "fw_to_anon_to_named(1, y: 1)"
- fw_no_kw: "fw_no_kw(1, 2)"
diff --git a/benchmark/vm_send_cfunc.yml b/benchmark/vm_send_cfunc.yml
index 6f12b65176..b114ac317d 100644
--- a/benchmark/vm_send_cfunc.yml
+++ b/benchmark/vm_send_cfunc.yml
@@ -1,14 +1,3 @@
-prelude: |
- ary = []
- kw = {a: 1}
- empty_kw = {}
- kw_ary = [Hash.ruby2_keywords_hash(a: 1)]
- empty_kw_ary = [Hash.ruby2_keywords_hash({})]
benchmark:
- vm_send_cfunc: itself
- vm_send_cfunc_splat: itself(*ary)
- vm_send_cfunc_splat_kw_hash: equal?(*kw_ary)
- vm_send_cfunc_splat_empty_kw_hash: itself(*empty_kw_ary)
- vm_send_cfunc_splat_kw: equal?(*ary, **kw)
- vm_send_cfunc_splat_empty_kw: itself(*ary, **empty_kw)
-loop_count: 20000000
+ vm_send_cfunc: self.class
+loop_count: 100000000
diff --git a/benchmark/vm_super_splat_calls.yml b/benchmark/vm_super_splat_calls.yml
deleted file mode 100644
index 795e44e4da..0000000000
--- a/benchmark/vm_super_splat_calls.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-prelude: |
- @a = [1].freeze
- @ea = [].freeze
- @kw = {y: 1}.freeze
- @b = lambda{}
- extend(Module.new{def arg_splat(x=0, y: 0) end})
- extend(Module.new{def arg_splat_block(x=0, y: 0) end})
- extend(Module.new{def splat_kw_splat(x=0, y: 0) end})
- extend(Module.new{def splat_kw_splat_block(x=0, y: 0) end})
- extend(Module.new{def splat_kw(x=0, y: 0) end})
- extend(Module.new{def splat_kw_block(x=0, y: 0) end})
-
- extend(Module.new{def arg_splat; super(1, *@ea) end})
- extend(Module.new{def arg_splat_block; super(1, *@ea, &@b) end})
- extend(Module.new{def splat_kw_splat; super(*@a, **@kw) end})
- extend(Module.new{def splat_kw_splat_block; super(*@a, **@kw, &@b) end})
- extend(Module.new{def splat_kw; super(*@a, y: 1) end})
- extend(Module.new{def splat_kw_block; super(*@a, y: 1, &@b) end})
-benchmark:
- arg_splat: "arg_splat"
- arg_splat_block: "arg_splat_block"
- splat_kw_splat: "splat_kw_splat"
- splat_kw_splat_block: "splat_kw_splat_block"
- splat_kw: "splat_kw"
- splat_kw_block: "splat_kw_block"
diff --git a/benchmark/vm_zsuper_splat_calls.yml b/benchmark/vm_zsuper_splat_calls.yml
deleted file mode 100644
index 82dc22349d..0000000000
--- a/benchmark/vm_zsuper_splat_calls.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-prelude: |
- a = [1].freeze
- ea = [].freeze
- kw = {y: 1}.freeze
- b = lambda{}
- extend(Module.new{def arg_splat(x=0, y: 0) end})
- extend(Module.new{def arg_splat_block(x=0, y: 0) end})
- extend(Module.new{def arg_splat_post(x=0, y: 0) end})
- extend(Module.new{def splat_kw_splat(x=0, y: 0) end})
- extend(Module.new{def splat_kw_splat_block(x=0, y: 0) end})
- extend(Module.new{def splat_kw(x=0, y: 0) end})
- extend(Module.new{def splat_kw_block(x=0, y: 0) end})
-
- extend(Module.new{def arg_splat(x, *a) super end})
- extend(Module.new{def arg_splat_block(x, *a, &b) super end})
- extend(Module.new{def arg_splat_post(*a, x) super end})
- extend(Module.new{def splat_kw_splat(*a, **kw) super end})
- extend(Module.new{def splat_kw_splat_block(*a, **kw, &b) super end})
- extend(Module.new{def splat_kw(*a, y: 1) super end})
- extend(Module.new{def splat_kw_block(*a, y: 1, &b) super end})
-benchmark:
- arg_splat: "arg_splat(1, *ea)"
- arg_splat_block: "arg_splat_block(1, *ea, &b)"
- arg_splat_post: "arg_splat_post(1, *ea, &b)"
- splat_kw_splat: "splat_kw_splat(*a, **kw)"
- splat_kw_splat_block: "splat_kw_splat_block(*a, **kw, &b)"
- splat_kw: "splat_kw(*a, y: 1)"
- splat_kw_block: "splat_kw_block(*a, y: 1, &b)"
diff --git a/bignum.c b/bignum.c
index e04843f478..cb2c3b6f07 100644
--- a/bignum.c
+++ b/bignum.c
@@ -30,6 +30,9 @@
# define USE_GMP 0
#endif
#endif
+#if USE_GMP
+# include <gmp.h>
+#endif
#include "id.h"
#include "internal.h"
@@ -45,23 +48,6 @@
#include "ruby/util.h"
#include "ruby_assert.h"
-#if USE_GMP
-RBIMPL_WARNING_PUSH()
-# ifdef _MSC_VER
-RBIMPL_WARNING_IGNORED(4146) /* for mpn_neg() */
-# endif
-# include <gmp.h>
-RBIMPL_WARNING_POP()
-#endif
-
-static const bool debug_integer_pack = (
-#ifdef DEBUG_INTEGER_PACK
- DEBUG_INTEGER_PACK+0
-#else
- RUBY_DEBUG
-#endif
- ) != 0;
-
const char ruby_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
#ifndef SIZEOF_BDIGIT_DBL
@@ -355,7 +341,7 @@ maxpow_in_bdigit_dbl(int base, int *exp_ret)
BDIGIT_DBL maxpow;
int exponent;
- RUBY_ASSERT(2 <= base && base <= 36);
+ assert(2 <= base && base <= 36);
{
#if SIZEOF_BDIGIT_DBL == 2
@@ -387,7 +373,7 @@ maxpow_in_bdigit_dbl(int base, int *exp_ret)
static inline BDIGIT_DBL
bary2bdigitdbl(const BDIGIT *ds, size_t n)
{
- RUBY_ASSERT(n <= 2);
+ assert(n <= 2);
if (n == 2)
return ds[0] | BIGUP(ds[1]);
@@ -399,7 +385,7 @@ bary2bdigitdbl(const BDIGIT *ds, size_t n)
static inline void
bdigitdbl2bary(BDIGIT *ds, size_t n, BDIGIT_DBL num)
{
- RUBY_ASSERT(n == 2);
+ assert(n == 2);
ds[0] = BIGLO(num);
ds[1] = (BDIGIT)BIGDN(num);
@@ -430,7 +416,7 @@ bary_small_lshift(BDIGIT *zds, const BDIGIT *xds, size_t n, int shift)
{
size_t i;
BDIGIT_DBL num = 0;
- RUBY_ASSERT(0 <= shift && shift < BITSPERDIG);
+ assert(0 <= shift && shift < BITSPERDIG);
for (i=0; i<n; i++) {
num = num | (BDIGIT_DBL)*xds++ << shift;
@@ -446,7 +432,7 @@ bary_small_rshift(BDIGIT *zds, const BDIGIT *xds, size_t n, int shift, BDIGIT hi
size_t i;
BDIGIT_DBL num = 0;
- RUBY_ASSERT(0 <= shift && shift < BITSPERDIG);
+ assert(0 <= shift && shift < BITSPERDIG);
num = BIGUP(higher_bdigit);
for (i = 0; i < n; i++) {
@@ -1063,13 +1049,15 @@ integer_unpack_num_bdigits(size_t numwords, size_t wordsize, size_t nails, int *
if (numwords <= (SIZE_MAX - (BITSPERDIG-1)) / CHAR_BIT / wordsize) {
num_bdigits = integer_unpack_num_bdigits_small(numwords, wordsize, nails, nlp_bits_ret);
- if (debug_integer_pack) {
+#ifdef DEBUG_INTEGER_PACK
+ {
int nlp_bits1;
size_t num_bdigits1 = integer_unpack_num_bdigits_generic(numwords, wordsize, nails, &nlp_bits1);
- RUBY_ASSERT(num_bdigits == num_bdigits1);
- RUBY_ASSERT(*nlp_bits_ret == nlp_bits1);
+ assert(num_bdigits == num_bdigits1);
+ assert(*nlp_bits_ret == nlp_bits1);
(void)num_bdigits1;
}
+#endif
}
else {
num_bdigits = integer_unpack_num_bdigits_generic(numwords, wordsize, nails, nlp_bits_ret);
@@ -1277,7 +1265,7 @@ bary_unpack_internal(BDIGIT *bdigits, size_t num_bdigits, const void *words, siz
}
if (dd)
*dp++ = (BDIGIT)dd;
- RUBY_ASSERT(dp <= de);
+ assert(dp <= de);
while (dp < de)
*dp++ = 0;
#undef PUSH_BITS
@@ -1336,7 +1324,7 @@ bary_unpack(BDIGIT *bdigits, size_t num_bdigits, const void *words, size_t numwo
num_bdigits0 = integer_unpack_num_bdigits(numwords, wordsize, nails, &nlp_bits);
- RUBY_ASSERT(num_bdigits0 <= num_bdigits);
+ assert(num_bdigits0 <= num_bdigits);
sign = bary_unpack_internal(bdigits, num_bdigits0, words, numwords, wordsize, nails, flags, nlp_bits);
@@ -1355,8 +1343,8 @@ bary_subb(BDIGIT *zds, size_t zn, const BDIGIT *xds, size_t xn, const BDIGIT *yd
size_t i;
size_t sn;
- RUBY_ASSERT(xn <= zn);
- RUBY_ASSERT(yn <= zn);
+ assert(xn <= zn);
+ assert(yn <= zn);
sn = xn < yn ? xn : yn;
@@ -1417,8 +1405,8 @@ bary_addc(BDIGIT *zds, size_t zn, const BDIGIT *xds, size_t xn, const BDIGIT *yd
BDIGIT_DBL num;
size_t i;
- RUBY_ASSERT(xn <= zn);
- RUBY_ASSERT(yn <= zn);
+ assert(xn <= zn);
+ assert(yn <= zn);
if (xn > yn) {
const BDIGIT *tds;
@@ -1482,7 +1470,7 @@ bary_mul_single(BDIGIT *zds, size_t zn, BDIGIT x, BDIGIT y)
{
BDIGIT_DBL n;
- RUBY_ASSERT(2 <= zn);
+ assert(2 <= zn);
n = (BDIGIT_DBL)x * y;
bdigitdbl2bary(zds, 2, n);
@@ -1496,7 +1484,7 @@ bary_muladd_1xN(BDIGIT *zds, size_t zn, BDIGIT x, const BDIGIT *yds, size_t yn)
BDIGIT_DBL dd;
size_t j;
- RUBY_ASSERT(zn > yn);
+ assert(zn > yn);
if (x == 0)
return 0;
@@ -1531,7 +1519,7 @@ bigdivrem_mulsub(BDIGIT *zds, size_t zn, BDIGIT x, const BDIGIT *yds, size_t yn)
BDIGIT_DBL t2;
BDIGIT_DBL_SIGNED num;
- RUBY_ASSERT(zn == yn + 1);
+ assert(zn == yn + 1);
num = 0;
t2 = 0;
@@ -1556,7 +1544,7 @@ bary_mulsub_1xN(BDIGIT *zds, size_t zn, BDIGIT x, const BDIGIT *yds, size_t yn)
{
BDIGIT_DBL_SIGNED num;
- RUBY_ASSERT(zn == yn + 1);
+ assert(zn == yn + 1);
num = bigdivrem_mulsub(zds, zn, x, yds, yn);
zds[yn] = BIGLO(num);
@@ -1570,7 +1558,7 @@ bary_mul_normal(BDIGIT *zds, size_t zn, const BDIGIT *xds, size_t xn, const BDIG
{
size_t i;
- RUBY_ASSERT(xn + yn <= zn);
+ assert(xn + yn <= zn);
BDIGITS_ZERO(zds, zn);
for (i = 0; i < xn; i++) {
@@ -1601,7 +1589,7 @@ bary_sq_fast(BDIGIT *zds, size_t zn, const BDIGIT *xds, size_t xn)
BDIGIT vl;
int vh;
- RUBY_ASSERT(xn * 2 <= zn);
+ assert(xn * 2 <= zn);
BDIGITS_ZERO(zds, zn);
@@ -1673,9 +1661,9 @@ bary_mul_balance_with_mulfunc(BDIGIT *const zds, const size_t zn,
VALUE work = 0;
size_t n;
- RUBY_ASSERT(xn + yn <= zn);
- RUBY_ASSERT(xn <= yn);
- RUBY_ASSERT(!KARATSUBA_BALANCED(xn, yn) || !TOOM3_BALANCED(xn, yn));
+ assert(xn + yn <= zn);
+ assert(xn <= yn);
+ assert(!KARATSUBA_BALANCED(xn, yn) || !TOOM3_BALANCED(xn, yn));
BDIGITS_ZERO(zds, xn);
@@ -1757,9 +1745,9 @@ bary_mul_karatsuba(BDIGIT *zds, size_t zn, const BDIGIT *xds, size_t xn, const B
const BDIGIT *xds0, *xds1, *yds0, *yds1;
BDIGIT *zds0, *zds1, *zds2, *zds3;
- RUBY_ASSERT(xn + yn <= zn);
- RUBY_ASSERT(xn <= yn);
- RUBY_ASSERT(yn < 2 * xn);
+ assert(xn + yn <= zn);
+ assert(xn <= yn);
+ assert(yn < 2 * xn);
sq = xds == yds && xn == yn;
@@ -1774,7 +1762,7 @@ bary_mul_karatsuba(BDIGIT *zds, size_t zn, const BDIGIT *xds, size_t xn, const B
n = yn / 2;
- RUBY_ASSERT(n < xn);
+ assert(n < xn);
if (wn < n) {
/* This function itself needs only n BDIGITs for work area.
@@ -1895,7 +1883,7 @@ bary_mul_karatsuba(BDIGIT *zds, size_t zn, const BDIGIT *xds, size_t xn, const B
for (x = 0, i = xn-1; 0 <= i; i--) { x <<= SIZEOF_BDIGIT*CHAR_BIT; x |= xds[i]; }
for (y = 0, i = yn-1; 0 <= i; i--) { y <<= SIZEOF_BDIGIT*CHAR_BIT; y |= yds[i]; }
for (z = 0, i = zn-1; 0 <= i; i--) { z <<= SIZEOF_BDIGIT*CHAR_BIT; z |= zds[i]; }
- RUBY_ASSERT(z == x * y);
+ assert(z == x * y);
}
*/
@@ -1963,11 +1951,11 @@ bary_mul_toom3(BDIGIT *zds, size_t zn, const BDIGIT *xds, size_t xn, const BDIGI
int sq = xds == yds && xn == yn;
- RUBY_ASSERT(xn <= yn); /* assume y >= x */
- RUBY_ASSERT(xn + yn <= zn);
+ assert(xn <= yn); /* assume y >= x */
+ assert(xn + yn <= zn);
n = (yn + 2) / 3;
- RUBY_ASSERT(2*n < xn);
+ assert(2*n < xn);
wnc = 0;
@@ -2154,19 +2142,19 @@ bary_mul_toom3(BDIGIT *zds, size_t zn, const BDIGIT *xds, size_t xn, const BDIGI
/* z(1) : t1 <- u1 * v1 */
bary_mul_toom3_start(t1ds, t1n, u1ds, u1n, v1ds, v1n, wds, wn);
t1p = u1p == v1p;
- RUBY_ASSERT(t1ds[t1n-1] == 0);
+ assert(t1ds[t1n-1] == 0);
t1n--;
/* z(-1) : t2 <- u2 * v2 */
bary_mul_toom3_start(t2ds, t2n, u2ds, u2n, v2ds, v2n, wds, wn);
t2p = u2p == v2p;
- RUBY_ASSERT(t2ds[t2n-1] == 0);
+ assert(t2ds[t2n-1] == 0);
t2n--;
/* z(-2) : t3 <- u3 * v3 */
bary_mul_toom3_start(t3ds, t3n, u3ds, u3n, v3ds, v3n, wds, wn);
t3p = u3p == v3p;
- RUBY_ASSERT(t3ds[t3n-1] == 0);
+ assert(t3ds[t3n-1] == 0);
t3n--;
/* z(inf) : t4 <- x2 * y2 */
@@ -2342,7 +2330,7 @@ bary_mul_gmp(BDIGIT *zds, size_t zn, const BDIGIT *xds, size_t xn, const BDIGIT
mpz_t x, y, z;
size_t count;
- RUBY_ASSERT(xn + yn <= zn);
+ assert(xn + yn <= zn);
mpz_init(x);
mpz_init(y);
@@ -2377,7 +2365,7 @@ rb_big_mul_gmp(VALUE x, VALUE y)
static void
bary_short_mul(BDIGIT *zds, size_t zn, const BDIGIT *xds, size_t xn, const BDIGIT *yds, size_t yn)
{
- RUBY_ASSERT(xn + yn <= zn);
+ assert(xn + yn <= zn);
if (xn == 1 && yn == 1) {
bary_mul_single(zds, zn, xds[0], yds[0]);
@@ -2413,7 +2401,7 @@ bary_mul_precheck(BDIGIT **zdsp, size_t *znp, const BDIGIT **xdsp, size_t *xnp,
const BDIGIT *yds = *ydsp;
size_t yn = *ynp;
- RUBY_ASSERT(xn + yn <= zn);
+ assert(xn + yn <= zn);
nlsz = 0;
@@ -2462,7 +2450,7 @@ bary_mul_precheck(BDIGIT **zdsp, size_t *znp, const BDIGIT **xdsp, size_t *xnp,
tds = xds; xds = yds; yds = tds;
tn = xn; xn = yn; yn = tn;
}
- RUBY_ASSERT(xn <= yn);
+ assert(xn <= yn);
if (xn <= 1) {
if (xn == 0) {
@@ -2645,8 +2633,8 @@ rb_big_stop(void *ptr)
static BDIGIT
bigdivrem_single1(BDIGIT *qds, const BDIGIT *xds, size_t xn, BDIGIT x_higher_bdigit, BDIGIT y)
{
- RUBY_ASSERT(0 < xn);
- RUBY_ASSERT(x_higher_bdigit < y);
+ assert(0 < xn);
+ assert(x_higher_bdigit < y);
if (POW2_P(y)) {
BDIGIT r;
r = xds[0] & (y-1);
@@ -2678,9 +2666,9 @@ bigdivrem_restoring(BDIGIT *zds, size_t zn, BDIGIT *yds, size_t yn)
struct big_div_struct bds;
size_t ynzero;
- RUBY_ASSERT(yn < zn);
- RUBY_ASSERT(BDIGIT_MSB(yds[yn-1]));
- RUBY_ASSERT(zds[zn-1] < yds[yn-1]);
+ assert(yn < zn);
+ assert(BDIGIT_MSB(yds[yn-1]));
+ assert(zds[zn-1] < yds[yn-1]);
for (ynzero = 0; !yds[ynzero]; ynzero++);
@@ -2719,9 +2707,9 @@ bary_divmod_normal(BDIGIT *qds, size_t qn, BDIGIT *rds, size_t rn, const BDIGIT
size_t zn;
VALUE tmpyz = 0;
- RUBY_ASSERT(yn < xn || (xn == yn && yds[yn - 1] <= xds[xn - 1]));
- RUBY_ASSERT(qds ? (xn - yn + 1) <= qn : 1);
- RUBY_ASSERT(rds ? yn <= rn : 1);
+ assert(yn < xn || (xn == yn && yds[yn - 1] <= xds[xn - 1]));
+ assert(qds ? (xn - yn + 1) <= qn : 1);
+ assert(rds ? yn <= rn : 1);
zn = xn + BIGDIVREM_EXTRA_WORDS;
@@ -2813,10 +2801,10 @@ bary_divmod_gmp(BDIGIT *qds, size_t qn, BDIGIT *rds, size_t rn, const BDIGIT *xd
mpz_t x, y, q, r;
size_t count;
- RUBY_ASSERT(yn < xn || (xn == yn && yds[yn - 1] <= xds[xn - 1]));
- RUBY_ASSERT(qds ? (xn - yn + 1) <= qn : 1);
- RUBY_ASSERT(rds ? yn <= rn : 1);
- RUBY_ASSERT(qds || rds);
+ assert(yn < xn || (xn == yn && yds[yn - 1] <= xds[xn - 1]));
+ assert(qds ? (xn - yn + 1) <= qn : 1);
+ assert(rds ? yn <= rn : 1);
+ assert(qds || rds);
mpz_init(x);
mpz_init(y);
@@ -2902,8 +2890,8 @@ bary_divmod_branch(BDIGIT *qds, size_t qn, BDIGIT *rds, size_t rn, const BDIGIT
static void
bary_divmod(BDIGIT *qds, size_t qn, BDIGIT *rds, size_t rn, const BDIGIT *xds, size_t xn, const BDIGIT *yds, size_t yn)
{
- RUBY_ASSERT(xn <= qn);
- RUBY_ASSERT(yn <= rn);
+ assert(xn <= qn);
+ assert(yn <= rn);
BARY_TRUNC(yds, yn);
if (yn == 0)
@@ -3035,8 +3023,7 @@ rb_big_resize(VALUE big, size_t len)
static VALUE
bignew_1(VALUE klass, size_t len, int sign)
{
- NEWOBJ_OF(big, struct RBignum, klass,
- T_BIGNUM | (RGENGC_WB_PROTECTED_BIGNUM ? FL_WB_PROTECTED : 0), sizeof(struct RBignum), 0);
+ NEWOBJ_OF(big, struct RBignum, klass, T_BIGNUM | (RGENGC_WB_PROTECTED_BIGNUM ? FL_WB_PROTECTED : 0));
VALUE bigv = (VALUE)big;
BIGNUM_SET_SIGN(bigv, sign);
if (len <= BIGNUM_EMBED_LEN_MAX) {
@@ -3435,13 +3422,15 @@ rb_absint_numwords(VALUE val, size_t word_numbits, size_t *nlz_bits_ret)
if (numbytes <= SIZE_MAX / CHAR_BIT) {
numwords = absint_numwords_small(numbytes, nlz_bits_in_msbyte, word_numbits, &nlz_bits);
- if (debug_integer_pack) {
+#ifdef DEBUG_INTEGER_PACK
+ {
size_t numwords0, nlz_bits0;
numwords0 = absint_numwords_generic(numbytes, nlz_bits_in_msbyte, word_numbits, &nlz_bits0);
- RUBY_ASSERT(numwords0 == numwords);
- RUBY_ASSERT(nlz_bits0 == nlz_bits);
+ assert(numwords0 == numwords);
+ assert(nlz_bits0 == nlz_bits);
(void)numwords0;
}
+#endif
}
else {
numwords = absint_numwords_generic(numbytes, nlz_bits_in_msbyte, word_numbits, &nlz_bits);
@@ -3854,7 +3843,7 @@ str2big_poweroftwo(
if (numbits) {
*dp++ = BIGLO(dd);
}
- RUBY_ASSERT((size_t)(dp - BDIGITS(z)) == num_bdigits);
+ assert((size_t)(dp - BDIGITS(z)) == num_bdigits);
return z;
}
@@ -3897,7 +3886,7 @@ str2big_normal(
}
break;
}
- RUBY_ASSERT(blen <= num_bdigits);
+ assert(blen <= num_bdigits);
}
return z;
@@ -3955,7 +3944,7 @@ str2big_karatsuba(
current_base = 1;
}
}
- RUBY_ASSERT(i == num_bdigits);
+ assert(i == num_bdigits);
for (unit = 2; unit < num_bdigits; unit *= 2) {
for (i = 0; i < num_bdigits; i += unit*2) {
if (2*unit <= num_bdigits - i) {
@@ -4100,8 +4089,8 @@ rb_int_parse_cstr(const char *str, ssize_t len, char **endp, size_t *ndigits,
len -= (n); \
} while (0)
#define ASSERT_LEN() do {\
- RUBY_ASSERT(len != 0); \
- if (len0 >= 0) RUBY_ASSERT(s + len0 == str + len); \
+ assert(len != 0); \
+ if (len0 >= 0) assert(s + len0 == str + len); \
} while (0)
if (!str) {
@@ -4552,7 +4541,7 @@ rb_uint128t2big(uint128_t n)
return big;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_int128t2big(int128_t n)
{
int neg = 0;
@@ -4646,8 +4635,8 @@ big_shift2(VALUE x, int lshift_p, VALUE y)
size_t shift_numdigits;
int shift_numbits;
- RUBY_ASSERT(POW2_P(CHAR_BIT));
- RUBY_ASSERT(POW2_P(BITSPERDIG));
+ assert(POW2_P(CHAR_BIT));
+ assert(POW2_P(BITSPERDIG));
if (BIGZEROP(x))
return INT2FIX(0);
@@ -4734,7 +4723,7 @@ power_cache_get_power(int base, int power_level, size_t *numdigits_ret)
rb_obj_hide(power);
base36_power_cache[base - 2][power_level] = power;
base36_numdigits_cache[base - 2][power_level] = numdigits;
- rb_vm_register_global_object(power);
+ rb_gc_register_mark_object(power);
}
if (numdigits_ret)
*numdigits_ret = base36_numdigits_cache[base - 2][power_level];
@@ -4770,7 +4759,7 @@ big2str_2bdigits(struct big2str_struct *b2s, BDIGIT *xds, size_t xn, size_t tail
int beginning = !b2s->ptr;
size_t len = 0;
- RUBY_ASSERT(xn <= 2);
+ assert(xn <= 2);
num = bary2bdigitdbl(xds, xn);
if (beginning) {
@@ -4898,7 +4887,7 @@ big2str_karatsuba(struct big2str_struct *b2s, BDIGIT *xds, size_t xn, size_t wn,
/* bigdivrem_restoring will modify y.
* So use temporary buffer. */
tds = xds + qn;
- RUBY_ASSERT(qn + bn <= xn + wn);
+ assert(qn + bn <= xn + wn);
bary_small_lshift(tds, bds, bn, shift);
xds[xn] = bary_small_lshift(xds, xds, xn, shift);
}
@@ -4916,7 +4905,7 @@ big2str_karatsuba(struct big2str_struct *b2s, BDIGIT *xds, size_t xn, size_t wn,
}
BARY_TRUNC(qds, qn);
- RUBY_ASSERT(qn <= bn);
+ assert(qn <= bn);
big2str_karatsuba(b2s, qds, qn, xn+wn - (rn+qn), lower_power_level, lower_numdigits+taillen);
BARY_TRUNC(rds, rn);
big2str_karatsuba(b2s, rds, rn, xn+wn - rn, lower_power_level, taillen);
@@ -4981,7 +4970,7 @@ big2str_generic(VALUE x, int base)
invalid_radix(base);
if (xn >= LONG_MAX/BITSPERDIG) {
- rb_raise(rb_eRangeError, "bignum too big to convert into 'string'");
+ rb_raise(rb_eRangeError, "bignum too big to convert into `string'");
}
power_level = 0;
@@ -4991,7 +4980,7 @@ big2str_generic(VALUE x, int base)
power_level++;
power = power_cache_get_power(base, power_level, NULL);
}
- RUBY_ASSERT(power_level != MAX_BASE36_POWER_TABLE_ENTRIES);
+ assert(power_level != MAX_BASE36_POWER_TABLE_ENTRIES);
if ((size_t)BIGNUM_LEN(power) <= xn) {
/*
@@ -5106,7 +5095,7 @@ rb_big2str1(VALUE x, int base)
invalid_radix(base);
if (xn >= LONG_MAX/BITSPERDIG) {
- rb_raise(rb_eRangeError, "bignum too big to convert into 'string'");
+ rb_raise(rb_eRangeError, "bignum too big to convert into `string'");
}
if (POW2_P(base)) {
@@ -5142,7 +5131,7 @@ big2ulong(VALUE x, const char *type)
if (len == 0)
return 0;
if (BIGSIZE(x) > sizeof(long)) {
- rb_raise(rb_eRangeError, "bignum too big to convert into '%s'", type);
+ rb_raise(rb_eRangeError, "bignum too big to convert into `%s'", type);
}
ds = BDIGITS(x);
#if SIZEOF_LONG <= SIZEOF_BDIGIT
@@ -5185,7 +5174,7 @@ rb_big2long(VALUE x)
if (num <= 1+(unsigned long)(-(LONG_MIN+1)))
return -(long)(num-1)-1;
}
- rb_raise(rb_eRangeError, "bignum too big to convert into 'long'");
+ rb_raise(rb_eRangeError, "bignum too big to convert into `long'");
}
#if HAVE_LONG_LONG
@@ -5203,7 +5192,7 @@ big2ull(VALUE x, const char *type)
if (len == 0)
return 0;
if (BIGSIZE(x) > SIZEOF_LONG_LONG)
- rb_raise(rb_eRangeError, "bignum too big to convert into '%s'", type);
+ rb_raise(rb_eRangeError, "bignum too big to convert into `%s'", type);
#if SIZEOF_LONG_LONG <= SIZEOF_BDIGIT
num = (unsigned LONG_LONG)ds[0];
#else
@@ -5244,7 +5233,7 @@ rb_big2ll(VALUE x)
if (num <= 1+(unsigned LONG_LONG)(-(LLONG_MIN+1)))
return -(LONG_LONG)(num-1)-1;
}
- rb_raise(rb_eRangeError, "bignum too big to convert into 'long long'");
+ rb_raise(rb_eRangeError, "bignum too big to convert into `long long'");
}
#endif /* HAVE_LONG_LONG */
@@ -5507,10 +5496,10 @@ big_op(VALUE x, VALUE y, enum big_op_t op)
n = FIX2INT(rel);
switch (op) {
- case big_op_gt: return RBOOL(n > 0);
- case big_op_ge: return RBOOL(n >= 0);
- case big_op_lt: return RBOOL(n < 0);
- case big_op_le: return RBOOL(n <= 0);
+ case big_op_gt: return RBOOL(n > 0);
+ case big_op_ge: return RBOOL(n >= 0);
+ case big_op_lt: return RBOOL(n < 0);
+ case big_op_le: return RBOOL(n <= 0);
}
return Qundef;
}
@@ -5666,7 +5655,7 @@ bigsub_int(VALUE x, long y0)
zds = BDIGITS(z);
#if SIZEOF_BDIGIT >= SIZEOF_LONG
- RUBY_ASSERT(xn == zn);
+ assert(xn == zn);
num = (BDIGIT_DBL_SIGNED)xds[0] - y;
if (xn == 1 && num < 0) {
BIGNUM_NEGATE(z);
@@ -5729,7 +5718,7 @@ bigsub_int(VALUE x, long y0)
goto finish;
finish:
- RUBY_ASSERT(num == 0 || num == -1);
+ assert(num == 0 || num == -1);
if (num < 0) {
get2comp(z);
BIGNUM_NEGATE(z);
@@ -6884,11 +6873,63 @@ BDIGIT rb_bdigit_dbl_isqrt(BDIGIT_DBL);
# define BDIGIT_DBL_TO_DOUBLE(n) (double)(n)
#endif
+static BDIGIT *
+estimate_initial_sqrt(VALUE *xp, const size_t xn, const BDIGIT *nds, size_t len)
+{
+ enum {dbl_per_bdig = roomof(DBL_MANT_DIG,BITSPERDIG)};
+ const int zbits = nlz(nds[len-1]);
+ VALUE x = *xp = bignew_1(0, xn, 1); /* division may release the GVL */
+ BDIGIT *xds = BDIGITS(x);
+ BDIGIT_DBL d = bary2bdigitdbl(nds+len-dbl_per_bdig, dbl_per_bdig);
+ BDIGIT lowbits = 1;
+ int rshift = (int)((BITSPERDIG*2-zbits+(len&BITSPERDIG&1) - DBL_MANT_DIG + 1) & ~1);
+ double f;
+
+ if (rshift > 0) {
+ lowbits = (BDIGIT)d & ~(~(BDIGIT)1U << rshift);
+ d >>= rshift;
+ }
+ else if (rshift < 0) {
+ d <<= -rshift;
+ d |= nds[len-dbl_per_bdig-1] >> (BITSPERDIG+rshift);
+ }
+ f = sqrt(BDIGIT_DBL_TO_DOUBLE(d));
+ d = (BDIGIT_DBL)ceil(f);
+ if (BDIGIT_DBL_TO_DOUBLE(d) == f) {
+ if (lowbits || (lowbits = !bary_zero_p(nds, len-dbl_per_bdig)))
+ ++d;
+ }
+ else {
+ lowbits = 1;
+ }
+ rshift /= 2;
+ rshift += (2-(len&1))*BITSPERDIG/2;
+ if (rshift >= 0) {
+ if (nlz((BDIGIT)d) + rshift >= BITSPERDIG) {
+ /* (d << rshift) does cause overflow.
+ * example: Integer.sqrt(0xffff_ffff_ffff_ffff ** 2)
+ */
+ d = ~(BDIGIT_DBL)0;
+ }
+ else {
+ d <<= rshift;
+ }
+ }
+ BDIGITS_ZERO(xds, xn-2);
+ bdigitdbl2bary(&xds[xn-2], 2, d);
+
+ if (!lowbits) return NULL; /* special case, exact result */
+ return xds;
+}
+
VALUE
rb_big_isqrt(VALUE n)
{
BDIGIT *nds = BDIGITS(n);
size_t len = BIGNUM_LEN(n);
+ size_t xn = (len+1) / 2;
+ VALUE x;
+ BDIGIT *xds;
if (len <= 2) {
BDIGIT sq = rb_bdigit_dbl_isqrt(bary2bdigitdbl(nds, len));
@@ -6898,19 +6939,25 @@ rb_big_isqrt(VALUE n)
return ULONG2NUM(sq);
#endif
}
- else {
- size_t shift = FIX2LONG(rb_big_bit_length(n)) / 4;
- VALUE n2 = rb_int_rshift(n, SIZET2NUM(2 * shift));
- VALUE x = FIXNUM_P(n2) ? LONG2FIX(rb_ulong_isqrt(FIX2ULONG(n2))) : rb_big_isqrt(n2);
- /* x = (x+n/x)/2 */
- x = rb_int_plus(rb_int_lshift(x, SIZET2NUM(shift - 1)), rb_int_idiv(rb_int_rshift(n, SIZET2NUM(shift + 1)), x));
- VALUE xx = rb_int_mul(x, x);
- while (rb_int_gt(xx, n)) {
- xx = rb_int_minus(xx, rb_int_minus(rb_int_plus(x, x), INT2FIX(1)));
- x = rb_int_minus(x, INT2FIX(1));
+ else if ((xds = estimate_initial_sqrt(&x, xn, nds, len)) != 0) {
+ size_t tn = xn + BIGDIVREM_EXTRA_WORDS;
+ VALUE t = bignew_1(0, tn, 1);
+ BDIGIT *tds = BDIGITS(t);
+ tn = BIGNUM_LEN(t);
+
+ /* t = n/x */
+ while (bary_divmod_branch(tds, tn, NULL, 0, nds, len, xds, xn),
+ bary_cmp(tds, tn, xds, xn) < 0) {
+ int carry;
+ BARY_TRUNC(tds, tn);
+ /* x = (x+t)/2 */
+ carry = bary_add(xds, xn, xds, xn, tds, tn);
+ bary_small_rshift(xds, xds, xn, 1, carry);
+ tn = BIGNUM_LEN(t);
}
- return x;
}
+ RBASIC_SET_CLASS_RAW(x, rb_cInteger);
+ return x;
}
#if USE_GMP
@@ -6949,7 +6996,7 @@ int_pow_tmp3(VALUE x, VALUE y, VALUE m, int nega_flg)
if (FIXNUM_P(y)) {
y = rb_int2big(FIX2LONG(y));
}
- RUBY_ASSERT(RB_BIGNUM_TYPE_P(m));
+ assert(RB_BIGNUM_TYPE_P(m));
xn = BIGNUM_LEN(x);
yn = BIGNUM_LEN(y);
mn = BIGNUM_LEN(m);
diff --git a/bin/gem b/bin/gem
index 3ac1d9e623..1c16ea7ddd 100755
--- a/bin/gem
+++ b/bin/gem
@@ -1,6 +1,4 @@
#!/usr/bin/env ruby
-# frozen_string_literal: true
-
#--
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
# All rights reserved.
diff --git a/bootstraptest/runner.rb b/bootstraptest/runner.rb
index 24324fa51f..f9b3e919b8 100755
--- a/bootstraptest/runner.rb
+++ b/bootstraptest/runner.rb
@@ -6,6 +6,7 @@
# Never use optparse in this file.
# Never use test/unit in this file.
# Never use Ruby extensions in this file.
+# Maintain Ruby 1.8 compatibility for now
$start_time = Time.now
@@ -76,9 +77,6 @@ bt = Struct.new(:ruby,
:width,
:indent,
:platform,
- :timeout,
- :timeout_scale,
- :launchable_test_reports
)
BT = Class.new(bt) do
def indent=(n)
@@ -120,7 +118,7 @@ BT = Class.new(bt) do
r = IO.for_fd($1.to_i(10), "rb", autoclose: false)
w = IO.for_fd($2.to_i(10), "wb", autoclose: false)
end
- rescue
+ rescue => e
r.close if r
else
r.close_on_exec = true
@@ -146,10 +144,6 @@ BT = Class.new(bt) do
end
super wn
end
-
- def apply_timeout_scale(timeout)
- timeout&.*(timeout_scale)
- end
end.new
BT_STATE = Struct.new(:count, :error).new
@@ -162,12 +156,6 @@ def main
BT.color = nil
BT.tty = nil
BT.quiet = false
- BT.timeout = 180
- BT.timeout_scale = (defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? ? 3 : 1) # for --jit-wait
- if (ts = (ENV["RUBY_TEST_TIMEOUT_SCALE"] || ENV["RUBY_TEST_SUBPROCESS_TIMEOUT_SCALE"]).to_i) > 1
- BT.timeout_scale *= ts
- end
-
# BT.wn = 1
dir = nil
quiet = false
@@ -198,18 +186,14 @@ def main
warn "unknown --tty argument: #$3" if $3
BT.tty = !$1 || !$2
true
- when /\A(-q|--q(uiet)?)\z/
+ when /\A(-q|--q(uiet))\z/
quiet = true
BT.quiet = true
true
when /\A-j(\d+)?/
BT.wn = $1.to_i
true
- when /\A--timeout=(\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?)(?::(\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?))?/
- BT.timeout = $1.to_f
- BT.timeout_scale = $2.to_f if defined?($2)
- true
- when /\A(-v|--v(erbose)?)\z/
+ when /\A(-v|--v(erbose))\z/
BT.verbose = true
BT.quiet = false
true
@@ -221,7 +205,6 @@ Usage: #{File.basename($0, '.*')} --ruby=PATH [--sets=NAME,NAME,...]
default: /tmp/bootstraptestXXXXX.tmpwd
--color[=WHEN] Colorize the output. WHEN defaults to 'always'
or can be 'never' or 'auto'.
- --timeout=TIMEOUT Default timeout in seconds.
-s, --stress stress test.
-v, --verbose Output test name before exec.
-q, --quiet Don\'t print header message.
@@ -230,19 +213,6 @@ End
exit true
when /\A-j/
true
- when /--launchable-test-reports=(.*)/
- if File.exist?($1)
- # To protect files from overwritten, do nothing when the file exists.
- return true
- end
-
- require_relative '../tool/lib/launchable'
- BT.launchable_test_reports = writer = Launchable::JsonStreamWriter.new($1)
- writer.write_array('testCases')
- at_exit {
- writer.close
- }
- true
else
false
end
@@ -252,7 +222,7 @@ End
end
tests ||= ARGV
tests = Dir.glob("#{File.dirname($0)}/test_*.rb").sort if tests.empty?
- paths = tests.map {|path| File.expand_path(path) }
+ pathes = tests.map {|path| File.expand_path(path) }
BT.progress = %w[- \\ | /]
BT.progress_bs = "\b" * BT.progress[0].size
@@ -296,7 +266,7 @@ End
end
in_temporary_working_directory(dir) do
- exec_test paths
+ exec_test pathes
end
end
@@ -308,8 +278,8 @@ def erase(e = true)
end
end
-def load_test paths
- paths.each do |path|
+def load_test pathes
+ pathes.each do |path|
load File.expand_path(path)
end
end
@@ -359,66 +329,13 @@ def concurrent_exec_test
end
end
-##
-# Module for writing a test file for uploading test results into Launchable.
-# In bootstraptest, we aggregate the test results based on file level.
-module Launchable
- @@last_test_name = nil
- @@failure_log = ''
- @@duration = 0
-
- def show_progress(message = '')
- faildesc, t = super
-
- if writer = BT.launchable_test_reports
- if faildesc
- @@failure_log += faildesc
- end
- repo_path = File.expand_path("#{__dir__}/../")
- relative_path = File.join(__dir__, self.path).delete_prefix("#{repo_path}/")
- if @@last_test_name != nil && @@last_test_name != relative_path
- # The test path is a URL-encoded representation.
- # https://github.com/launchableinc/cli/blob/v1.81.0/launchable/testpath.py#L18
- test_path = "#{encode_test_path_component("file")}=#{encode_test_path_component(@@last_test_name)}"
- if @@failure_log.size > 0
- status = 'TEST_FAILED'
- else
- status = 'TEST_PASSED'
- end
- writer.write_object(
- {
- testPath: test_path,
- status: status,
- duration: t,
- createdAt: Time.now.to_s,
- stderr: @@failure_log,
- stdout: nil,
- data: {
- lineNumber: self.lineno
- }
- }
- )
- @@duration = 0
- @@failure_log.clear
- end
- @@last_test_name = relative_path
- @@duration += t
- end
- end
-
- private
- def encode_test_path_component component
- component.to_s.gsub('%', '%25').gsub('=', '%3D').gsub('#', '%23').gsub('&', '%26')
- end
-end
-
-def exec_test(paths)
+def exec_test(pathes)
# setup
- load_test paths
+ load_test pathes
BT_STATE.count = 0
BT_STATE.error = 0
BT.columns = 0
- BT.width = paths.map {|path| File.basename(path).size}.max + 2
+ BT.width = pathes.map {|path| File.basename(path).size}.max + 2
# execute tests
if BT.wn > 1
@@ -488,7 +405,6 @@ def target_platform
end
class Assertion < Struct.new(:src, :path, :lineno, :proc)
- prepend Launchable
@count = 0
@all = Hash.new{|h, k| h[k] = []}
@errbuf = []
@@ -512,7 +428,7 @@ class Assertion < Struct.new(:src, :path, :lineno, :proc)
def initialize(*args)
super
self.class.add self
- @category = self.path[/\Atest_(.+)\.rb\z/, 1]
+ @category = self.path.match(/test_(.+)\.rb/)[1]
end
def call
@@ -563,9 +479,9 @@ class Assertion < Struct.new(:src, :path, :lineno, :proc)
$stderr.print "#{BT.progress_bs}#{BT.progress[BT_STATE.count % BT.progress.size]}"
end
- t = Time.now if BT.verbose || BT.launchable_test_reports
+ t = Time.now if BT.verbose
faildesc, errout = with_stderr {yield}
- t = Time.now - t if BT.verbose || BT.launchable_test_reports
+ t = Time.now - t if BT.verbose
if !faildesc
# success
@@ -592,8 +508,6 @@ class Assertion < Struct.new(:src, :path, :lineno, :proc)
$stderr.printf("%-*s%s", BT.width, path, BT.progress[BT_STATE.count % BT.progress.size])
end
end
-
- [faildesc, t]
rescue Interrupt
$stderr.puts "\##{@id} #{path}:#{lineno}"
raise
@@ -612,16 +526,14 @@ class Assertion < Struct.new(:src, :path, :lineno, :proc)
end
end
- def get_result_string(opt = '', timeout: BT.timeout, **argh)
+ def get_result_string(opt = '', **argh)
if BT.ruby
- timeout = BT.apply_timeout_scale(timeout)
filename = make_srcfile(**argh)
begin
kw = self.err ? {err: self.err} : {}
out = IO.popen("#{BT.ruby} -W0 #{opt} #{filename}", **kw)
pid = out.pid
- th = Thread.new {out.read.tap {Process.waitpid(pid); out.close}}
- th.value if th.join(timeout)
+ out.read.tap{ Process.waitpid(pid); out.close }
ensure
raise Interrupt if $? and $?.signaled? && $?.termsig == Signal.list["INT"]
@@ -639,14 +551,9 @@ class Assertion < Struct.new(:src, :path, :lineno, :proc)
def make_srcfile(frozen_string_literal: nil)
filename = "bootstraptest.#{self.path}_#{self.lineno}_#{self.id}.rb"
File.open(filename, 'w') {|f|
- f.puts "#frozen_string_literal:#{frozen_string_literal}" unless frozen_string_literal.nil?
- if $stress
- f.puts "GC.stress = true" if $stress
- else
- f.puts ""
- end
- f.puts "class BT_Skip < Exception; end; def skip(msg) = raise(BT_Skip, msg.to_s)"
- f.puts "print(begin; #{self.src}; rescue BT_Skip; $!.message; end)"
+ f.puts "#frozen_string_literal:true" if frozen_string_literal
+ f.puts "GC.stress = true" if $stress
+ f.puts "print(begin; #{self.src}; end)"
}
filename
end
@@ -660,9 +567,9 @@ def add_assertion src, pr
Assertion.new(src, path, lineno, pr)
end
-def assert_equal(expected, testsrc, message = '', opt = '', **kwargs)
+def assert_equal(expected, testsrc, message = '', opt = '', **argh)
add_assertion testsrc, -> as do
- as.assert_check(message, opt, **kwargs) {|result|
+ as.assert_check(message, opt, **argh) {|result|
if expected == result
nil
else
@@ -673,9 +580,9 @@ def assert_equal(expected, testsrc, message = '', opt = '', **kwargs)
end
end
-def assert_match(expected_pattern, testsrc, message = '', **argh)
+def assert_match(expected_pattern, testsrc, message = '')
add_assertion testsrc, -> as do
- as.assert_check(message, **argh) {|result|
+ as.assert_check(message) {|result|
if expected_pattern =~ result
nil
else
@@ -707,9 +614,8 @@ def assert_valid_syntax(testsrc, message = '')
end
end
-def assert_normal_exit(testsrc, *rest, timeout: BT.timeout, **opt)
+def assert_normal_exit(testsrc, *rest, timeout: nil, **opt)
add_assertion testsrc, -> as do
- timeout = BT.apply_timeout_scale(timeout)
message, ignore_signals = rest
message ||= ''
as.show_progress(message) {
@@ -718,19 +624,23 @@ def assert_normal_exit(testsrc, *rest, timeout: BT.timeout, **opt)
timeout_signaled = false
logfile = "assert_normal_exit.#{as.path}.#{as.lineno}.log"
- io = IO.popen("#{BT.ruby} -W0 #{filename}", err: logfile)
- pid = io.pid
- th = Thread.new {
- io.read
- io.close
- $?
- }
- if !th.join(timeout)
- Process.kill :KILL, pid
- timeout_signaled = true
+ begin
+ err = open(logfile, "w")
+ io = IO.popen("#{BT.ruby} -W0 #{filename}", err: err)
+ pid = io.pid
+ th = Thread.new {
+ io.read
+ io.close
+ $?
+ }
+ if !th.join(timeout)
+ Process.kill :KILL, pid
+ timeout_signaled = true
+ end
+ status = th.value
+ ensure
+ err.close
end
- status = th.value
-
if status && status.signaled?
signo = status.termsig
signame = Signal.list.invert[signo]
@@ -759,7 +669,9 @@ end
def assert_finish(timeout_seconds, testsrc, message = '')
add_assertion testsrc, -> as do
- timeout_seconds = BT.apply_timeout_scale(timeout_seconds)
+ if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # for --jit-wait
+ timeout_seconds *= 3
+ end
as.show_progress(message) {
faildesc = nil
@@ -815,8 +727,6 @@ end
def pretty(src, desc, result)
src = src.sub(/\A\s*\n/, '')
- lines = src.lines
- src = lines[0..20].join + "(...snip)\n" if lines.size > 20
(/\n/ =~ src ? "\n#{adjust_indent(src)}" : src) + " #=> #{desc}"
end
@@ -874,13 +784,4 @@ def check_coredump
end
end
-def yjit_enabled?
- ENV.key?('RUBY_YJIT_ENABLE') || ENV.fetch('RUN_OPTS', '').include?('yjit') || BT.ruby.include?('yjit')
-end
-
-def rjit_enabled?
- # Don't check `RubyVM::RJIT.enabled?`. On btest-bruby, target Ruby != runner Ruby.
- ENV.fetch('RUN_OPTS', '').include?('rjit')
-end
-
exit main
diff --git a/bootstraptest/test_autoload.rb b/bootstraptest/test_autoload.rb
index de66f1f3ee..9e0850bc52 100644
--- a/bootstraptest/test_autoload.rb
+++ b/bootstraptest/test_autoload.rb
@@ -11,7 +11,7 @@ assert_equal 'ok', %q{
}, '[ruby-dev:43816]'
assert_equal 'ok', %q{
- File.write('zzz2.rb', '')
+ open('zzz2.rb', 'w') {|f| f.puts '' }
instance_eval do
autoload :ZZZ, './zzz2.rb'
begin
@@ -23,7 +23,7 @@ assert_equal 'ok', %q{
}, '[ruby-dev:43816]'
assert_equal 'ok', %q{
- File.write('zzz3.rb', "class ZZZ; def self.ok;:ok;end;end\n")
+ open('zzz3.rb', 'w') {|f| f.puts 'class ZZZ; def self.ok;:ok;end;end'}
instance_eval do
autoload :ZZZ, './zzz3.rb'
ZZZ.ok
@@ -31,20 +31,20 @@ assert_equal 'ok', %q{
}, '[ruby-dev:43816]'
assert_equal 'ok', %q{
- File.write("zzz4.rb", "class ZZZ; def self.ok;:ok;end;end\n")
+ open("zzz4.rb", "w") {|f| f.puts "class ZZZ; def self.ok;:ok;end;end"}
autoload :ZZZ, "./zzz4.rb"
ZZZ.ok
}
assert_equal 'ok', %q{
- File.write("zzz5.rb", "class ZZZ; def self.ok;:ok;end;end\n")
+ open("zzz5.rb", "w") {|f| f.puts "class ZZZ; def self.ok;:ok;end;end"}
autoload :ZZZ, "./zzz5.rb"
require "./zzz5.rb"
ZZZ.ok
}
assert_equal 'okok', %q{
- File.write("zzz6.rb", "class ZZZ; def self.ok;:ok;end;end\n")
+ open("zzz6.rb", "w") {|f| f.puts "class ZZZ; def self.ok;:ok;end;end"}
autoload :ZZZ, "./zzz6.rb"
t1 = Thread.new {ZZZ.ok}
t2 = Thread.new {ZZZ.ok}
@@ -60,7 +60,7 @@ assert_finish 5, %q{
}, '[ruby-core:21696]'
assert_equal 'A::C', %q{
- File.write("zzz7.rb", "")
+ open("zzz7.rb", "w") {}
class A
autoload :C, "./zzz7"
class C
diff --git a/bootstraptest/test_eval.rb b/bootstraptest/test_eval.rb
index 20bd9615f4..a9f389c673 100644
--- a/bootstraptest/test_eval.rb
+++ b/bootstraptest/test_eval.rb
@@ -217,7 +217,7 @@ assert_equal %q{[10, main]}, %q{
}
%w[break next redo].each do |keyword|
- assert_match %r"Invalid #{keyword}\b", %{
+ assert_match %r"Can't escape from eval with #{keyword}\b", %{
$stderr = STDOUT
begin
eval "0 rescue #{keyword}"
@@ -227,16 +227,6 @@ assert_equal %q{[10, main]}, %q{
}, '[ruby-dev:31372]'
end
-assert_normal_exit %{
- $stderr = STDOUT
- 5000.times do
- begin
- eval "0 rescue break"
- rescue SyntaxError
- end
- end
-}
-
assert_normal_exit %q{
$stderr = STDOUT
class Foo
@@ -364,34 +354,3 @@ assert_normal_exit %q{
end
}, 'check escaping the internal value th->base_block'
-assert_equal "false", <<~RUBY, "literal strings are mutable", "--disable-frozen-string-literal"
- eval("'test'").frozen?
-RUBY
-
-assert_equal "false", <<~RUBY, "literal strings are mutable", "--disable-frozen-string-literal", frozen_string_literal: true
- eval("'test'").frozen?
-RUBY
-
-assert_equal "true", <<~RUBY, "literal strings are frozen", "--enable-frozen-string-literal"
- eval("'test'").frozen?
-RUBY
-
-assert_equal "true", <<~RUBY, "literal strings are frozen", "--enable-frozen-string-literal", frozen_string_literal: false
- eval("'test'").frozen?
-RUBY
-
-assert_equal "false", <<~RUBY, "__FILE__ is mutable", "--disable-frozen-string-literal"
- eval("__FILE__").frozen?
-RUBY
-
-assert_equal "false", <<~RUBY, "__FILE__ is mutable", "--disable-frozen-string-literal", frozen_string_literal: true
- eval("__FILE__").frozen?
-RUBY
-
-assert_equal "true", <<~RUBY, "__FILE__ is frozen", "--enable-frozen-string-literal"
- eval("__FILE__").frozen?
-RUBY
-
-assert_equal "true", <<~RUBY, "__FILE__ is frozen", "--enable-frozen-string-literal", frozen_string_literal: false
- eval("__FILE__").frozen?
-RUBY
diff --git a/bootstraptest/test_exception.rb b/bootstraptest/test_exception.rb
index decfdc08a3..0fb6f552b8 100644
--- a/bootstraptest/test_exception.rb
+++ b/bootstraptest/test_exception.rb
@@ -370,7 +370,7 @@ assert_equal %q{}, %q{
}
##
-assert_match /undefined method 'foo\'/, %q{#`
+assert_match /undefined method `foo\'/, %q{#`
STDERR.reopen(STDOUT)
class C
def inspect
diff --git a/bootstraptest/test_finalizer.rb b/bootstraptest/test_finalizer.rb
index ccfa0b55d6..22a16b1220 100644
--- a/bootstraptest/test_finalizer.rb
+++ b/bootstraptest/test_finalizer.rb
@@ -6,11 +6,3 @@ ObjectSpace.define_finalizer(b1,proc{b1.inspect})
ObjectSpace.define_finalizer(a2,proc{a1.inspect})
ObjectSpace.define_finalizer(a1,proc{})
}, '[ruby-dev:35778]'
-
-assert_equal 'true', %q{
- obj = Object.new
- id = obj.object_id
-
- ObjectSpace.define_finalizer(obj, proc { |i| print(id == i) })
- nil
-}
diff --git a/bootstraptest/test_flow.rb b/bootstraptest/test_flow.rb
index 15528a4213..35f19db588 100644
--- a/bootstraptest/test_flow.rb
+++ b/bootstraptest/test_flow.rb
@@ -363,7 +363,7 @@ assert_equal %q{[1, 2, 3, 5, 2, 3, 5, 7, 8]}, %q{$a = []; begin; ; $a << 1
; $a << 8
; rescue Exception; $a << 99; end; $a}
assert_equal %q{[1, 2, 6, 3, 5, 7, 8]}, %q{$a = []; begin; ; $a << 1
- o = "test".dup; $a << 2
+ o = "test"; $a << 2
def o.test(a); $a << 3
return a; $a << 4
ensure; $a << 5
diff --git a/bootstraptest/test_fork.rb b/bootstraptest/test_fork.rb
index 9e64f1d026..83923dad97 100644
--- a/bootstraptest/test_fork.rb
+++ b/bootstraptest/test_fork.rb
@@ -75,25 +75,3 @@ assert_equal '[1, 2]', %q{
end
}, '[ruby-dev:44005] [Ruby 1.9 - Bug #4950]'
-assert_equal 'ok', %q{
- def now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
-
- Thread.new do
- loop { sleep 0.0001 }
- end
-
- 10.times do
- pid = fork{ exit!(0) }
- deadline = now + 1
- until Process.waitpid(pid, Process::WNOHANG)
- if now > deadline
- Process.kill(:KILL, pid)
- raise "failed"
- end
- sleep 0.001
- end
- rescue NotImplementedError
- end
- :ok
-}, '[Bug #20670]'
-
diff --git a/bootstraptest/test_gc.rb b/bootstraptest/test_gc.rb
index 17bc497822..eb68c9845e 100644
--- a/bootstraptest/test_gc.rb
+++ b/bootstraptest/test_gc.rb
@@ -14,7 +14,7 @@ ms = "a".."k"
o.send(meth)
end
end
-}, '[ruby-dev:39453]' unless rjit_enabled? # speed up RJIT CI
+}, '[ruby-dev:39453]'
assert_normal_exit %q{
a = []
diff --git a/bootstraptest/test_insns.rb b/bootstraptest/test_insns.rb
index 18ab1800bd..91fba9b011 100644
--- a/bootstraptest/test_insns.rb
+++ b/bootstraptest/test_insns.rb
@@ -92,7 +92,7 @@ tests = [
[ 'intern', %q{ :"#{true}" }, ],
[ 'newarray', %q{ ["true"][0] }, ],
- [ 'pushtoarraykwsplat', %q{ [**{x:'true'}][0][:x] }, ],
+ [ 'newarraykwsplat', %q{ [**{x:'true'}][0][:x] }, ],
[ 'duparray', %q{ [ true ][0] }, ],
[ 'expandarray', %q{ y = [ true, false, nil ]; x, = y; x }, ],
[ 'expandarray', %q{ y = [ true, false, nil ]; x, *z = y; x }, ],
@@ -214,11 +214,9 @@ tests = [
'true'.freeze
},
- [ 'opt_newarray_send', %q{ ![ ].hash.nil? }, ],
-
- [ 'opt_newarray_send', %q{ [ ].max.nil? }, ],
- [ 'opt_newarray_send', %q{ [1, x = 2, 3].max == 3 }, ],
- [ 'opt_newarray_send', <<-'},', ], # {
+ [ 'opt_newarray_max', %q{ [ ].max.nil? }, ],
+ [ 'opt_newarray_max', %q{ [1, x = 2, 3].max == 3 }, ],
+ [ 'opt_newarray_max', <<-'},', ], # {
class Array
def max
true
@@ -226,9 +224,9 @@ tests = [
end
[1, x = 2, 3].max
},
- [ 'opt_newarray_send', %q{ [ ].min.nil? }, ],
- [ 'opt_newarray_send', %q{ [3, x = 2, 1].min == 1 }, ],
- [ 'opt_newarray_send', <<-'},', ], # {
+ [ 'opt_newarray_min', %q{ [ ].min.nil? }, ],
+ [ 'opt_newarray_min', %q{ [3, x = 2, 1].min == 1 }, ],
+ [ 'opt_newarray_min', <<-'},', ], # {
class Array
def min
true
@@ -236,48 +234,6 @@ tests = [
end
[3, x = 2, 1].min
},
- [ 'opt_newarray_send', %q{ v = 1.23; [v, v*2].pack("E*").unpack("E*") == [v, v*2] }, ],
- [ 'opt_newarray_send', %q{ v = 4.56; b = +"x"; [v, v*2].pack("E*", buffer: b); b[1..].unpack("E*") == [v, v*2] }, ],
- [ 'opt_newarray_send', <<-'},', ], # {
- v = 7.89;
- b = +"x";
- class Array
- alias _pack pack
- def pack(s, buffer: nil, prefix: "y")
- buffer ||= +"b"
- buffer << prefix
- _pack(s, buffer: buffer)
- end
- end
- tests = []
-
- ret = [v].pack("E*", prefix: "z")
- tests << (ret[0..1] == "bz")
- tests << (ret[2..].unpack("E*") == [v])
-
- ret = [v].pack("E*")
- tests << (ret[0..1] == "by")
- tests << (ret[2..].unpack("E*") == [v])
-
- [v, v*2, v*3].pack("E*", buffer: b)
- tests << (b[0..1] == "xy")
- tests << (b[2..].unpack("E*") == [v, v*2, v*3])
-
- class Array
- def pack(_fmt, buffer:) = buffer
- end
-
- b = nil
- tests << [v].pack("E*", buffer: b).nil?
-
- class Array
- def pack(_fmt, **kw) = kw.empty?
- end
-
- tests << [v].pack("E*") == true
-
- tests.all? or puts tests
- },
[ 'throw', %q{ false.tap { break true } }, ],
[ 'branchif', %q{ x = nil; x ||= true }, ],
@@ -396,7 +352,7 @@ tests = [
[ 'opt_ge', %q{ +0.0.next_float >= 0.0 }, ],
[ 'opt_ge', %q{ ?z >= ?a }, ],
- [ 'opt_ltlt', %q{ +'' << 'true' }, ],
+ [ 'opt_ltlt', %q{ '' << 'true' }, ],
[ 'opt_ltlt', %q{ ([] << 'true').join }, ],
[ 'opt_ltlt', %q{ (1 << 31) == 2147483648 }, ],
@@ -405,7 +361,7 @@ tests = [
[ 'opt_aref', %q{ 'true'[0] == ?t }, ],
[ 'opt_aset', %q{ [][0] = true }, ],
[ 'opt_aset', %q{ {}[0] = true }, ],
- [ 'opt_aset', %q{ x = +'frue'; x[0] = 't'; x }, ],
+ [ 'opt_aset', %q{ x = 'frue'; x[0] = 't'; x }, ],
[ 'opt_aset', <<-'},', ], # {
# opt_aref / opt_aset mixup situation
class X; def x; {}; end; end
diff --git a/bootstraptest/test_io.rb b/bootstraptest/test_io.rb
index 4e5d6d59c9..666e5a011b 100644
--- a/bootstraptest/test_io.rb
+++ b/bootstraptest/test_io.rb
@@ -91,7 +91,7 @@ assert_normal_exit %q{
at_exit { p :foo }
megacontent = "abc" * 12345678
- #File.write("megasrc", megacontent)
+ #File.open("megasrc", "w") {|f| f << megacontent }
t0 = Thread.main
Thread.new { sleep 0.001 until t0.stop?; Process.kill(:INT, $$) }
diff --git a/bootstraptest/test_jump.rb b/bootstraptest/test_jump.rb
index 8751343b1f..d07c47a56d 100644
--- a/bootstraptest/test_jump.rb
+++ b/bootstraptest/test_jump.rb
@@ -292,7 +292,7 @@ assert_equal "true", %q{
end
end
end
- s = +"foo"
+ s = "foo"
s.return_eigenclass == class << s; self; end
}, '[ruby-core:21379]'
diff --git a/bootstraptest/test_literal.rb b/bootstraptest/test_literal.rb
index 7295f7a148..a0d4ee08c6 100644
--- a/bootstraptest/test_literal.rb
+++ b/bootstraptest/test_literal.rb
@@ -70,7 +70,6 @@ if /wasi/ !~ target_platform
assert_equal "foo\n", %q(`echo foo`)
assert_equal "foo\n", %q(s = "foo"; `echo #{s}`)
end
-assert_equal "ECHO FOO", %q(def `(s) s.upcase; end; `echo foo`)
# regexp
assert_equal '', '//.source'
@@ -119,14 +118,14 @@ assert_equal '5', 'a = [1,2,3]; a[1] = 5; a[1]'
assert_equal 'bar', '[*:foo];:bar'
assert_equal '[1, 2]', 'def nil.to_a; [2]; end; [1, *nil]'
assert_equal '[1, 2]', 'def nil.to_a; [1, 2]; end; [*nil]'
-assert_equal '[0, 1, {2 => 3}]', '[0, *[1], 2=>3]', "[ruby-dev:31592]"
+assert_equal '[0, 1, {2=>3}]', '[0, *[1], 2=>3]', "[ruby-dev:31592]"
# hash
assert_equal 'Hash', '{}.class'
assert_equal '{}', '{}.inspect'
assert_equal 'Hash', '{1=>2}.class'
-assert_equal '{1 => 2}', '{1=>2}.inspect'
+assert_equal '{1=>2}', '{1=>2}.inspect'
assert_equal '2', 'h = {1 => 2}; h[1]'
assert_equal '0', 'h = {1 => 2}; h.delete(1); h.size'
assert_equal '', 'h = {1 => 2}; h.delete(1); h[1]'
diff --git a/bootstraptest/test_literal_suffix.rb b/bootstraptest/test_literal_suffix.rb
index 7a4d67d0fa..c36fa7078f 100644
--- a/bootstraptest/test_literal_suffix.rb
+++ b/bootstraptest/test_literal_suffix.rb
@@ -46,9 +46,9 @@ assert_equal '1', '1rescue nil'
assert_equal '10000000000000000001/10000000000000000000',
'1.0000000000000000001r'
-assert_equal 'unexpected local variable or method, expecting end-of-input',
- %q{begin eval('1ir', nil, '', 0); rescue SyntaxError => e; e.message[/(?:\^~*|\A:(?:\d+:)? syntax error,) (.*)/, 1]; end}
-assert_equal 'unexpected local variable or method, expecting end-of-input',
- %q{begin eval('1.2ir', nil, '', 0); rescue SyntaxError => e; e.message[/(?:\^~*|\A:(?:\d+:)? syntax error,) (.*)/, 1]; end}
-assert_equal 'unexpected local variable or method, expecting end-of-input',
- %q{begin eval('1e1r', nil, '', 0); rescue SyntaxError => e; e.message[/(?:\^~*|\A:(?:\d+:)? syntax error,) (.*)/, 1]; end}
+assert_equal 'syntax error, unexpected local variable or method, expecting end-of-input',
+ %q{begin eval('1ir', nil, '', 0); rescue SyntaxError => e; e.message[/\A:(?:\d+:)? (.*)/, 1] end}
+assert_equal 'syntax error, unexpected local variable or method, expecting end-of-input',
+ %q{begin eval('1.2ir', nil, '', 0); rescue SyntaxError => e; e.message[/\A:(?:\d+:)? (.*)/, 1] end}
+assert_equal 'syntax error, unexpected local variable or method, expecting end-of-input',
+ %q{begin eval('1e1r', nil, '', 0); rescue SyntaxError => e; e.message[/\A:(?:\d+:)? (.*)/, 1] end}
diff --git a/bootstraptest/test_load.rb b/bootstraptest/test_load.rb
index 5046d4fcea..e63c93a8f4 100644
--- a/bootstraptest/test_load.rb
+++ b/bootstraptest/test_load.rb
@@ -1,9 +1,9 @@
assert_equal 'ok', %q{
- File.write("require-lock-test.rb", <<-END)
- sleep 0.1
- module M
- end
- END
+ open("require-lock-test.rb", "w") {|f|
+ f.puts "sleep 0.1"
+ f.puts "module M"
+ f.puts "end"
+ }
$:.unshift Dir.pwd
vs = (1..2).map {|i|
Thread.start {
@@ -12,11 +12,11 @@ assert_equal 'ok', %q{
}
}.map {|t| t.value }
vs[0] == M && vs[1] == M ? :ok : :ng
-}, '[ruby-dev:32048]' unless ENV.fetch('RUN_OPTS', '').include?('rjit') # Thread seems to be switching during JIT. To be fixed later.
+}, '[ruby-dev:32048]'
assert_equal 'ok', %q{
%w[a a/foo b].each {|d| Dir.mkdir(d)}
- File.write("b/foo", "$ok = :ok\n")
+ open("b/foo", "w") {|f| f.puts "$ok = :ok"}
$:.replace(%w[a b])
begin
load "foo"
diff --git a/bootstraptest/test_method.rb b/bootstraptest/test_method.rb
index af9443b8c6..04c9eb2d11 100644
--- a/bootstraptest/test_method.rb
+++ b/bootstraptest/test_method.rb
@@ -340,6 +340,24 @@ assert_equal '1', %q( class C; def m() 7 end; private :m end
assert_equal '1', %q( class C; def m() 1 end; private :m end
C.new.send(:m) )
+# with block
+assert_equal '[[:ok1, :foo], [:ok2, :foo, :bar]]',
+%q{
+ class C
+ def [](a)
+ $ary << [yield, a]
+ end
+ def []=(a, b)
+ $ary << [yield, a, b]
+ end
+ end
+
+ $ary = []
+ C.new[:foo, &lambda{:ok1}]
+ C.new[:foo, &lambda{:ok2}] = :bar
+ $ary
+}
+
# with
assert_equal '[:ok1, [:ok2, 11]]', %q{
class C
@@ -386,6 +404,7 @@ $result
# aset and splat
assert_equal '4', %q{class Foo;def []=(a,b,c,d);end;end;Foo.new[1,*a=[2,3]]=4}
+assert_equal '4', %q{class Foo;def []=(a,b,c,d);end;end;def m(&blk)Foo.new[1,*a=[2,3],&blk]=4;end;m{}}
# post test
assert_equal %q{[1, 2, :o1, :o2, [], 3, 4, NilClass, nil, nil]}, %q{
@@ -1088,6 +1107,10 @@ assert_equal 'ok', %q{
'ok'
end
}
+assert_equal 'ok', %q{
+ [0][0, &proc{}] += 21
+ 'ok'
+}, '[ruby-core:30534]'
# should not cache when splat
assert_equal 'ok', %q{
@@ -1167,210 +1190,3 @@ assert_equal 'DC', %q{
test2 o1, [], block
$result.join
}
-
-assert_equal 'ok', %q{
- def foo
- binding
- ["ok"].first
- end
- foo
- foo
-}, '[Bug #20178]'
-
-assert_equal 'ok', %q{
- def bar(x); x; end
- def foo(...); bar(...); end
- foo('ok')
-}
-
-assert_equal 'ok', %q{
- def bar(x); x; end
- def foo(z, ...); bar(...); end
- foo(1, 'ok')
-}
-
-assert_equal 'ok', %q{
- def bar(x, y); x; end
- def foo(...); bar("ok", ...); end
- foo(1)
-}
-
-assert_equal 'ok', %q{
- def bar(x); x; end
- def foo(...); 1.times { return bar(...) }; end
- foo("ok")
-}
-
-assert_equal 'ok', %q{
- def bar(x); x; end
- def foo(...); x = nil; 1.times { x = bar(...) }; x; end
- foo("ok")
-}
-
-assert_equal 'ok', %q{
- def bar(x); yield; end
- def foo(...); bar(...); end
- foo(1) { "ok" }
-}
-
-assert_equal 'ok', %q{
- def baz(x); x; end
- def bar(...); baz(...); end
- def foo(...); bar(...); end
- foo("ok")
-}
-
-assert_equal '[1, 2, 3, 4]', %q{
- def baz(a, b, c, d); [a, b, c, d]; end
- def bar(...); baz(1, ...); end
- def foo(...); bar(2, ...); end
- foo(3, 4)
-}
-
-assert_equal 'ok', %q{
- class Foo; def self.foo(x); x; end; end
- class Bar < Foo; def self.foo(...); super; end; end
- Bar.foo('ok')
-}
-
-assert_equal 'ok', %q{
- class Foo; def self.foo(x); x; end; end
- class Bar < Foo; def self.foo(...); super(...); end; end
- Bar.foo('ok')
-}
-
-assert_equal 'ok', %q{
- class Foo; def self.foo(x, y); x + y; end; end
- class Bar < Foo; def self.foo(...); super("o", ...); end; end
- Bar.foo('k')
-}
-
-assert_equal 'ok', %q{
- def bar(a); a; end
- def foo(...); lambda { bar(...) }; end
- foo("ok").call
-}
-
-assert_equal 'ok', %q{
- class Foo; def self.foo(x, y); x + y; end; end
- class Bar < Foo; def self.y(&b); b; end; def self.foo(...); y { super("o", ...) }; end; end
- Bar.foo('k').call
-}
-
-assert_equal 'ok', %q{
- def baz(n); n; end
- def foo(...); bar = baz(...); lambda { lambda { bar } }; end
- foo("ok").call.call
-}
-
-assert_equal 'ok', %q{
- class A; def self.foo(...); new(...); end; attr_reader :b; def initialize(a, b:"ng"); @a = a; @b = b; end end
- A.foo(1).b
- A.foo(1, b: "ok").b
-}
-
-assert_equal 'ok', %q{
- class A; def initialize; @a = ["ok"]; end; def first(...); @a.first(...); end; end
- def call x; x.first; end
- def call1 x; x.first(1); end
- call(A.new)
- call1(A.new).first
-}
-
-assert_equal 'ok', %q{
- class A; def foo; yield("o"); end; end
- class B < A; def foo(...); super { |x| yield(x + "k") }; end; end
- B.new.foo { |x| x }
-}
-
-assert_equal "[1, 2, 3, 4]", %q{
- def foo(*b) = b
-
- def forward(...)
- splat = [1,2,3]
- foo(*splat, ...)
- end
-
- forward(4)
-}
-
-assert_equal "[1, 2, 3, 4]", %q{
-class A
- def foo(*b) = b
-end
-
-class B < A
- def foo(...)
- splat = [1,2,3]
- super(*splat, ...)
- end
-end
-
-B.new.foo(4)
-}
-
-assert_equal 'ok', %q{
- class A; attr_reader :iv; def initialize(...) = @iv = "ok"; end
- A.new("foo", bar: []).iv
-}
-
-assert_equal 'ok', %q{
- def foo(a, b) = a + b
- def bar(...) = foo(...)
- bar(1, 2)
- bar(1, 2)
- begin
- bar(1, 2, 3)
- "ng"
- rescue ArgumentError
- "ok"
- end
-}
-
-assert_equal 'ok', %q{
- class C
- def foo(...) = :ok
- def bar(...) = __send__(:foo, ...)
- end
-
- C.new.bar
-}
-
-assert_equal 'ok', %q{
- class C
- def method_missing(...) = :ok
- def foo(...) = xyzzy(...)
- end
-
- C.new.foo
-}
-
-assert_equal 'ok', %q{
- class C
- def initialize(a)
- end
- end
-
- def foo(...)
- C.new(...)
- :ok
- end
-
- foo(*["bar"])
- foo("baz")
-}
-
-assert_equal 'ok', %q{
- class C
- def foo(b:)
- b
- end
- end
-
- def foo(...)
- C.new.send(...)
- end
-
- foo(:foo, b: :ok)
- foo(*["foo"], b: :ok)
-}
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index 5caa903b94..67e66b03ee 100644
--- a/bootstraptest/test_ractor.rb
+++ b/bootstraptest/test_ractor.rb
@@ -283,7 +283,9 @@ assert_equal 30.times.map { 'ok' }.to_s, %q{
30.times.map{|i|
test i
}
-} unless (ENV.key?('TRAVIS') && ENV['TRAVIS_CPU_ARCH'] == 'arm64') # https://bugs.ruby-lang.org/issues/17878
+} unless ENV['RUN_OPTS'] =~ /--mjit-call-threshold=5/ || # This always fails with --mjit-wait --mjit-call-threshold=5
+ (ENV.key?('TRAVIS') && ENV['TRAVIS_CPU_ARCH'] == 'arm64') || # https://bugs.ruby-lang.org/issues/17878
+ true # too flaky everywhere http://ci.rvm.jp/results/trunk@ruby-sp1/4321096
# Exception for empty select
assert_match /specify at least one ractor/, %q{
@@ -514,9 +516,9 @@ assert_equal '[true, true, true]', %q{
end
}
received = []
- taken = []
+ take = []
yielded = []
- until received.size == RN && taken.size == RN && yielded.size == RN
+ until rs.empty?
r, v = Ractor.select(CR, *rs, yield_value: 'yield')
case r
when :receive
@@ -524,17 +526,11 @@ assert_equal '[true, true, true]', %q{
when :yield
yielded << v
else
- taken << v
+ take << v
rs.delete r
end
end
- r = [received == ['sendyield'] * RN,
- yielded == [nil] * RN,
- taken == ['take'] * RN,
- ]
-
- STDERR.puts [received, yielded, taken].inspect
- r
+ [received.all?('sendyield'), yielded.all?(nil), take.all?('take')]
}
# multiple Ractors can send to one Ractor
@@ -571,7 +567,7 @@ assert_equal '[RuntimeError, "ok", true]', %q{
}
# threads in a ractor will killed
-assert_equal '{ok: 3}', %q{
+assert_equal '{:ok=>3}', %q{
Ractor.new Ractor.current do |main|
q = Thread::Queue.new
Thread.new do
@@ -601,7 +597,7 @@ assert_equal '{ok: 3}', %q{
end
3.times.map{Ractor.receive}.tally
-} unless yjit_enabled? # `[BUG] Bus Error at 0x000000010b7002d0` in jit_exec()
+}
# unshareable object are copied
assert_equal 'false', %q{
@@ -628,7 +624,7 @@ assert_equal "allocator undefined for Thread", %q{
}
# send shareable and unshareable objects
-assert_equal "ok", <<~'RUBY', frozen_string_literal: false
+assert_equal "ok", %q{
echo_ractor = Ractor.new do
loop do
v = Ractor.receive
@@ -695,10 +691,10 @@ assert_equal "ok", <<~'RUBY', frozen_string_literal: false
else
results.inspect
end
-RUBY
+}
# frozen Objects are shareable
-assert_equal [false, true, false].inspect, <<~'RUBY', frozen_string_literal: false
+assert_equal [false, true, false].inspect, %q{
class C
def initialize freeze
@a = 1
@@ -721,11 +717,11 @@ assert_equal [false, true, false].inspect, <<~'RUBY', frozen_string_literal: fal
results << check(C.new(true)) # false
results << check(C.new(true).freeze) # true
results << check(C.new(false).freeze) # false
-RUBY
+}
# move example2: String
# touching moved object causes an error
-assert_equal 'hello world', <<~'RUBY', frozen_string_literal: false
+assert_equal 'hello world', %q{
# move
r = Ractor.new do
obj = Ractor.receive
@@ -743,7 +739,7 @@ assert_equal 'hello world', <<~'RUBY', frozen_string_literal: false
else
raise 'unreachable'
end
-RUBY
+}
# move example2: Array
assert_equal '[0, 1]', %q{
@@ -946,7 +942,7 @@ assert_equal 'ArgumentError', %q{
}
# ivar in shareable-objects are not allowed to access from non-main Ractor
-assert_equal "can not get unshareable values from instance variables of classes/modules from non-main Ractors", <<~'RUBY', frozen_string_literal: false
+assert_equal "can not get unshareable values from instance variables of classes/modules from non-main Ractors", %q{
class C
@iv = 'str'
end
@@ -957,12 +953,13 @@ assert_equal "can not get unshareable values from instance variables of classes/
end
end
+
begin
r.take
rescue Ractor::RemoteError => e
e.cause.message
end
-RUBY
+}
# ivar in shareable-objects are not allowed to access from non-main Ractor
assert_equal 'can not access instance variables of shareable objects from non-main Ractors', %q{
@@ -1086,41 +1083,6 @@ assert_equal '333', %q{
a + b + c + d + e + f
}
-assert_equal '["instance-variable", "instance-variable", nil]', %q{
- class C
- @iv1 = ""
- @iv2 = 42
- def self.iv1 = defined?(@iv1) # "instance-variable"
- def self.iv2 = defined?(@iv2) # "instance-variable"
- def self.iv3 = defined?(@iv3) # nil
- end
-
- Ractor.new{
- [C.iv1, C.iv2, C.iv3]
- }.take
-}
-
-# moved objects have their shape properly set to original object's shape
-assert_equal '1234', %q{
-class Obj
- attr_accessor :a, :b, :c, :d
- def initialize
- @a = 1
- @b = 2
- @c = 3
- end
-end
-r = Ractor.new do
- obj = receive
- obj.d = 4
- [obj.a, obj.b, obj.c, obj.d]
-end
-obj = Obj.new
-r.send(obj, move: true)
-values = r.take
-values.join
-}
-
# cvar in shareable-objects are not allowed to access from non-main Ractor
assert_equal 'can not access class variables from non-main Ractors', %q{
class C
@@ -1163,7 +1125,7 @@ assert_equal 'can not access class variables from non-main Ractors', %q{
}
# Getting non-shareable objects via constants by other Ractors is not allowed
-assert_equal 'can not access non-shareable objects in constant C::CONST by non-main Ractor.', <<~'RUBY', frozen_string_literal: false
+assert_equal 'can not access non-shareable objects in constant C::CONST by non-main Ractor.', %q{
class C
CONST = 'str'
end
@@ -1175,10 +1137,10 @@ assert_equal 'can not access non-shareable objects in constant C::CONST by non-m
rescue Ractor::RemoteError => e
e.cause.message
end
- RUBY
+}
# Constant cache should care about non-sharable constants
-assert_equal "can not access non-shareable objects in constant Object::STR by non-main Ractor.", <<~'RUBY', frozen_string_literal: false
+assert_equal "can not access non-shareable objects in constant Object::STR by non-main Ractor.", %q{
STR = "hello"
def str; STR; end
s = str() # fill const cache
@@ -1187,10 +1149,10 @@ assert_equal "can not access non-shareable objects in constant Object::STR by no
rescue Ractor::RemoteError => e
e.cause.message
end
-RUBY
+}
# Setting non-shareable objects into constants by other Ractors is not allowed
-assert_equal 'can not set constants with non-shareable objects by non-main Ractors', <<~'RUBY', frozen_string_literal: false
+assert_equal 'can not set constants with non-shareable objects by non-main Ractors', %q{
class C
end
r = Ractor.new do
@@ -1201,7 +1163,7 @@ assert_equal 'can not set constants with non-shareable objects by non-main Racto
rescue Ractor::RemoteError => e
e.cause.message
end
-RUBY
+}
# define_method is not allowed
assert_equal "defined with an un-shareable Proc in a different Ractor", %q{
@@ -1254,7 +1216,7 @@ assert_equal '0', %q{
}
# ObjectSpace._id2ref can not handle unshareable objects with Ractors
-assert_equal 'ok', <<~'RUBY', frozen_string_literal: false
+assert_equal 'ok', %q{
s = 'hello'
Ractor.new s.object_id do |id ;s|
@@ -1264,10 +1226,10 @@ assert_equal 'ok', <<~'RUBY', frozen_string_literal: false
:ok
end
end.take
-RUBY
+}
# Ractor.make_shareable(obj)
-assert_equal 'true', <<~'RUBY', frozen_string_literal: false
+assert_equal 'true', %q{
class C
def initialize
@a = 'foo'
@@ -1338,7 +1300,7 @@ assert_equal 'true', <<~'RUBY', frozen_string_literal: false
}
Ractor.shareable?(a)
-RUBY
+}
# Ractor.make_shareable(obj) doesn't freeze shareable objects
assert_equal 'true', %q{
@@ -1435,14 +1397,14 @@ assert_equal '[false, false, true, true]', %q{
}
# TracePoint with normal Proc should be Ractor local
-assert_equal '[6, 10]', %q{
+assert_equal '[4, 8]', %q{
rs = []
TracePoint.new(:line){|tp| rs << tp.lineno if tp.path == __FILE__}.enable do
- Ractor.new{ # line 5
+ Ractor.new{ # line 4
a = 1
b = 2
}.take
- c = 3 # line 9
+ c = 3 # line 8
end
rs
}
@@ -1480,25 +1442,6 @@ assert_equal '[:ok, :ok]', %q{
end
}
-# Ractor.select is interruptible
-assert_normal_exit %q{
- trap(:INT) do
- exit
- end
-
- r = Ractor.new do
- loop do
- sleep 1
- end
- end
-
- Thread.new do
- sleep 0.5
- Process.kill(:INT, Process.pid)
- end
- Ractor.select(r)
-}
-
# Ractor-local storage
assert_equal '[nil, "b", "a"]', %q{
ans = []
@@ -1529,13 +1472,28 @@ assert_equal "#{N}#{N}", %Q{
}.map{|r| r.take}.join
}
+# enc_table
+assert_equal "100", %Q{
+ Ractor.new do
+ loop do
+ Encoding.find("test-enc-#{rand(5_000)}").inspect
+ rescue ArgumentError => e
+ end
+ end
+
+ src = Encoding.find("UTF-8")
+ 100.times{|i|
+ src.replicate("test-enc-\#{i}")
+ }
+}
+
# Generic ivtbl
n = N/2
assert_equal "#{n}#{n}", %Q{
2.times.map{
Ractor.new do
#{n}.times do
- obj = +''
+ obj = ''
obj.instance_variable_set("@a", 1)
obj.instance_variable_set("@b", 1)
obj.instance_variable_set("@c", 1)
@@ -1547,9 +1505,8 @@ assert_equal "#{n}#{n}", %Q{
# NameError
assert_equal "ok", %q{
- obj = "".freeze # NameError refers the receiver indirectly
begin
- obj.bar
+ bar
rescue => err
end
begin
@@ -1585,7 +1542,7 @@ assert_equal "ok", %q{
1_000.times { idle_worker, tmp_reporter = Ractor.select(*workers) }
"ok"
-} unless yjit_enabled? || rjit_enabled? # flaky
+}
assert_equal "ok", %q{
def foo(*); ->{ super }; end
@@ -1623,7 +1580,6 @@ assert_equal "ok", %q{
end
}
-# check method cache invalidation
assert_equal "ok", %q{
module M
def foo
@@ -1663,176 +1619,10 @@ assert_equal "ok", %q{
"ok"
}
-# check method cache invalidation
-assert_equal 'true', %q{
- class C1; def self.foo = 1; end
- class C2; def self.foo = 2; end
- class C3; def self.foo = 3; end
- class C4; def self.foo = 5; end
- class C5; def self.foo = 7; end
- class C6; def self.foo = 11; end
- class C7; def self.foo = 13; end
- class C8; def self.foo = 17; end
-
- LN = 10_000
- RN = 10
- CS = [C1, C2, C3, C4, C5, C6, C7, C8]
- rs = RN.times.map{|i|
- Ractor.new(CS.shuffle){|cs|
- LN.times.sum{
- cs.inject(1){|r, c| r * c.foo} # c.foo invalidates method cache entry
- }
- }
- }
-
- n = CS.inject(1){|r, c| r * c.foo} * LN
- rs.map{|r| r.take} == Array.new(RN){n}
-}
-
-# check experimental warning
assert_match /\Atest_ractor\.rb:1:\s+warning:\s+Ractor is experimental/, %q{
Warning[:experimental] = $VERBOSE = true
STDERR.reopen(STDOUT)
eval("Ractor.new{}.take", nil, "test_ractor.rb", 1)
-}, frozen_string_literal: false
-
-# check moved object
-assert_equal 'ok', %q{
- r = Ractor.new do
- Ractor.receive
- GC.start
- :ok
- end
-
- obj = begin
- raise
- rescue => e
- e = Marshal.load(Marshal.dump(e))
- end
-
- r.send obj, move: true
- r.take
-}
-
-## Ractor::Selector
-
-# Selector#empty? returns true
-assert_equal 'true', %q{
- skip true unless defined? Ractor::Selector
-
- s = Ractor::Selector.new
- s.empty?
-}
-
-# Selector#empty? returns false if there is target ractors
-assert_equal 'false', %q{
- skip false unless defined? Ractor::Selector
-
- s = Ractor::Selector.new
- s.add Ractor.new{}
- s.empty?
-}
-
-# Selector#clear removes all ractors from the waiting list
-assert_equal 'true', %q{
- skip true unless defined? Ractor::Selector
-
- s = Ractor::Selector.new
- s.add Ractor.new{10}
- s.add Ractor.new{20}
- s.clear
- s.empty?
-}
-
-# Selector#wait can wait multiple ractors
-assert_equal '[10, 20, true]', %q{
- skip [10, 20, true] unless defined? Ractor::Selector
-
- s = Ractor::Selector.new
- s.add Ractor.new{10}
- s.add Ractor.new{20}
- r, v = s.wait
- vs = []
- vs << v
- r, v = s.wait
- vs << v
- [*vs.sort, s.empty?]
-} if defined? Ractor::Selector
-
-# Selector#wait can wait multiple ractors with receiving.
-assert_equal '30', %q{
- skip 30 unless defined? Ractor::Selector
-
- RN = 30
- rs = RN.times.map{
- Ractor.new{ :v }
- }
- s = Ractor::Selector.new(*rs)
-
- results = []
- until s.empty?
- results << s.wait
-
- # Note that s.wait can raise an exception because other Ractors/Threads
- # can take from the same ractors in the waiting set.
- # In this case there is no other takers so `s.wait` doesn't raise an error.
- end
-
- results.size
-} if defined? Ractor::Selector
-
-# Selector#wait can support dynamic addition
-assert_equal '600', %q{
- skip 600 unless defined? Ractor::Selector
-
- RN = 100
- s = Ractor::Selector.new
- rs = RN.times.map{
- Ractor.new{
- Ractor.main << Ractor.new{ Ractor.yield :v3; :v4 }
- Ractor.main << Ractor.new{ Ractor.yield :v5; :v6 }
- Ractor.yield :v1
- :v2
- }
- }
-
- rs.each{|r| s.add(r)}
- h = {v1: 0, v2: 0, v3: 0, v4: 0, v5: 0, v6: 0}
-
- loop do
- case s.wait receive: true
- in :receive, r
- s.add r
- in r, v
- h[v] += 1
- break if h.all?{|k, v| v == RN}
- end
- end
-
- h.sum{|k, v| v}
-} unless yjit_enabled? # http://ci.rvm.jp/results/trunk-yjit@ruby-sp2-docker/4466770
-
-# Selector should be GCed (free'ed) without trouble
-assert_equal 'ok', %q{
- skip :ok unless defined? Ractor::Selector
-
- RN = 30
- rs = RN.times.map{
- Ractor.new{ :v }
- }
- s = Ractor::Selector.new(*rs)
- :ok
}
end # if !ENV['GITHUB_WORKFLOW']
-
-# Chilled strings are not shareable
-assert_equal 'false', %q{
- Ractor.shareable?("chilled")
-}
-
-# Chilled strings can be made shareable
-assert_equal 'true', %q{
- shareable = Ractor.make_shareable("chilled")
- shareable == "chilled" && Ractor.shareable?(shareable)
-}
diff --git a/bootstraptest/test_rjit.rb b/bootstraptest/test_rjit.rb
deleted file mode 100644
index 4c8cd26dff..0000000000
--- a/bootstraptest/test_rjit.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# VM_CALL_OPT_SEND + VM_METHOD_TYPE_ATTRSET
-assert_equal '1', %q{
- class Foo
- attr_writer :foo
-
- def bar
- send(:foo=, 1)
- end
- end
-
- Foo.new.bar
-}
-
-# VM_CALL_OPT_SEND + OPTIMIZED_METHOD_TYPE_CALL
-assert_equal 'foo', %q{
- def bar(&foo)
- foo.send(:call)
- end
-
- bar { :foo }
-}
-
-# VM_CALL_OPT_SEND + OPTIMIZED_METHOD_TYPE_STRUCT_AREF
-assert_equal 'bar', %q{
- def bar(foo)
- foo.send(:bar)
- end
-
- bar(Struct.new(:bar).new(:bar))
-}
-
-# AND with offset DISP32
-assert_equal '2', %q{
- def foo
- a = 6;
- b = {a: 1, b: 1, c: 1, d: 1, e: 1, f: 1, g: 1, h: a&3}
- b[:h]
- end
-
- foo
-}
-
-# OR with offset DISP32
-assert_equal '6', %q{
- def foo
- a = 4;
- b = {a: 1, b: 1, c: 1, d: 1, e: 1, f: 1, g: 1, h: a|2}
- b[:h]
- end
-
- foo
-}
-
-# kwargs default w/ checkkeyword + locals (which shouldn't overwrite unspecified_bits)
-assert_equal '1', %q{
- def foo(bar: 1.to_s)
- _ = 1
- bar
- end
-
- def entry
- foo
- end
-
- entry
-}
-
-# Updating local type in Context
-assert_normal_exit %q{
- def foo(flag, object)
- klass = if flag
- object
- end
- klass ||= object
- return klass.new
- end
-
- foo(false, Object)
- foo(true, Object)
-}
diff --git a/bootstraptest/test_syntax.rb b/bootstraptest/test_syntax.rb
index 8301b344c6..948e2d7809 100644
--- a/bootstraptest/test_syntax.rb
+++ b/bootstraptest/test_syntax.rb
@@ -528,24 +528,24 @@ assert_equal %q{1}, %q{
i
}
def assert_syntax_error expected, code, message = ''
- assert_match /^#{Regexp.escape(expected)}/,
- "begin eval(%q{#{code}}, nil, '', 0)"'; rescue SyntaxError => e; e.message[/(?:\^~*|\A:(?:\d+:)?(?! syntax errors? found)(?: syntax error,)?) (.*)/, 1] end', message
+ assert_equal "#{expected}",
+ "begin eval(%q{#{code}}, nil, '', 0)"'; rescue SyntaxError => e; e.message[/\A:(?:\d+:)? (.*)/, 1] end', message
end
assert_syntax_error "unterminated string meets end of file", '().."', '[ruby-dev:29732]'
assert_equal %q{[]}, %q{$&;[]}, '[ruby-dev:31068]'
-assert_syntax_error "unexpected *, expecting '}'", %q{{*0}}, '[ruby-dev:31072]'
-assert_syntax_error "'@0' is not allowed as an instance variable name", %q{@0..0}, '[ruby-dev:31095]'
-assert_syntax_error "'$00' is not allowed as a global variable name", %q{$00..0}, '[ruby-dev:31100]'
-assert_syntax_error "'$00' is not allowed as a global variable name", %q{0..$00=1}
+assert_syntax_error "syntax error, unexpected *, expecting '}'", %q{{*0}}, '[ruby-dev:31072]'
+assert_syntax_error "`@0' is not allowed as an instance variable name", %q{@0..0}, '[ruby-dev:31095]'
+assert_syntax_error "identifier $00 is not valid to get", %q{$00..0}, '[ruby-dev:31100]'
+assert_syntax_error "identifier $00 is not valid to set", %q{0..$00=1}
assert_equal %q{0}, %q{[*0];0}, '[ruby-dev:31102]'
-assert_syntax_error "unexpected ')'", %q{v0,(*,v1,) = 0}, '[ruby-dev:31104]'
+assert_syntax_error "syntax error, unexpected ')'", %q{v0,(*,v1,) = 0}, '[ruby-dev:31104]'
assert_equal %q{1}, %q{
class << (ary=[]); def []; 0; end; def []=(x); super(0,x);end;end; ary[]+=1
}, '[ruby-dev:31110]'
assert_syntax_error "Can't set variable $1", %q{0..$1=1}, '[ruby-dev:31118]'
assert_valid_syntax %q{1.times{1+(1&&next)}}, '[ruby-dev:31119]'
assert_valid_syntax %q{x=-1;loop{x+=1&&redo if (x+=1).zero?}}, '[ruby-dev:31119]'
-assert_syntax_error %q{unexpected end-of-input}, %q{!}, '[ruby-dev:31243]'
+assert_syntax_error %q{syntax error, unexpected end-of-input}, %q{!}, '[ruby-dev:31243]'
assert_equal %q{[nil]}, %q{[()]}, '[ruby-dev:31252]'
assert_equal %q{true}, %q{!_=()}, '[ruby-dev:31263]'
assert_equal 'ok', %q{while true; redo; end if 1 == 2; :ok}, '[ruby-dev:31360]'
@@ -629,7 +629,7 @@ assert_equal '2', %q{
assert_match /invalid multibyte char/, %q{
$stderr = STDOUT
- eval("\"\xf0".dup.force_encoding("utf-8"))
+ eval("\"\xf0".force_encoding("utf-8"))
}, '[ruby-dev:32429]'
# method ! and !=
@@ -848,7 +848,7 @@ assert_normal_exit %q{
def x(a=1, b, *rest); nil end
end
end
-}, bug2415 unless rjit_enabled? # flaky
+}, bug2415
assert_normal_exit %q{
0.times do
@@ -880,7 +880,7 @@ assert_normal_exit %q{
end
end
end
-}, bug2415 unless rjit_enabled? # flaky
+}, bug2415
assert_normal_exit %q{
a {
@@ -904,35 +904,3 @@ assert_normal_exit %q{
Class
end
}, '[ruby-core:30293]'
-
-assert_equal "false", <<~RUBY, "literal strings are mutable", "--disable-frozen-string-literal"
- 'test'.frozen?
-RUBY
-
-assert_equal "true", <<~RUBY, "literal strings are frozen", "--disable-frozen-string-literal", frozen_string_literal: true
- 'test'.frozen?
-RUBY
-
-assert_equal "true", <<~RUBY, "literal strings are frozen", "--enable-frozen-string-literal"
- 'test'.frozen?
-RUBY
-
-assert_equal "false", <<~RUBY, "literal strings are mutable", "--enable-frozen-string-literal", frozen_string_literal: false
- 'test'.frozen?
-RUBY
-
-assert_equal "false", <<~RUBY, "__FILE__ is mutable", "--disable-frozen-string-literal"
- __FILE__.frozen?
-RUBY
-
-assert_equal "true", <<~RUBY, "__FILE__ is frozen", "--disable-frozen-string-literal", frozen_string_literal: true
- __FILE__.frozen?
-RUBY
-
-assert_equal "true", <<~RUBY, "__FILE__ is frozen", "--enable-frozen-string-literal"
- __FILE__.frozen?
-RUBY
-
-assert_equal "false", <<~RUBY, "__FILE__ is mutable", "--enable-frozen-string-literal", frozen_string_literal: false
- __FILE__.frozen?
-RUBY
diff --git a/bootstraptest/test_thread.rb b/bootstraptest/test_thread.rb
index 4040b68a27..5361828403 100644
--- a/bootstraptest/test_thread.rb
+++ b/bootstraptest/test_thread.rb
@@ -242,22 +242,9 @@ assert_equal 'true', %{
end
}
-assert_equal 'true', %{
- Thread.new{}.join
- begin
- Process.waitpid2 fork{
- Thread.new{
- sleep 0.1
- }.join
- }
- true
- rescue NotImplementedError
- true
- end
-}
-
assert_equal 'ok', %{
- File.write("zzz_t1.rb", <<-END)
+ open("zzz_t1.rb", "w") do |f|
+ f.puts <<-END
begin
Thread.new { fork { GC.start } }.join
pid, status = Process.wait2
@@ -266,6 +253,7 @@ assert_equal 'ok', %{
$result = :ok
end
END
+ end
require "./zzz_t1.rb"
$result
}
@@ -301,7 +289,7 @@ assert_normal_exit %q{
}.each {|t|
t.join
}
-} unless rjit_enabled? # flaky
+}
assert_equal 'ok', %q{
def m
@@ -420,7 +408,8 @@ assert_equal 'ok', %q{
}
assert_equal 'ok', %{
- File.write("zzz_t2.rb", <<-'end;') # do
+ open("zzz_t2.rb", "w") do |f|
+ f.puts <<-'end;' # do
begin
m = Thread::Mutex.new
parent = Thread.current
@@ -442,6 +431,7 @@ assert_equal 'ok', %{
$result = :ok
end
end;
+ end
require "./zzz_t2.rb"
$result
}
@@ -493,7 +483,7 @@ assert_equal 'foo', %q{
[th1, th2].each {|t| t.join }
GC.start
f.call.source
-} unless rjit_enabled? # flaky
+}
assert_normal_exit %q{
class C
def inspect
diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb
index f0192c0414..5c655b8f25 100644
--- a/bootstraptest/test_yjit.rb
+++ b/bootstraptest/test_yjit.rb
@@ -1,271 +1,3 @@
-# To run the tests in this file only, with YJIT enabled:
-# make btest BTESTS=bootstraptest/test_yjit.rb RUN_OPTS="--yjit-call-threshold=1"
-
-# regression test for popping before side exit
-assert_equal "ok", %q{
- def foo(a, *) = a
-
- def call(args, &)
- foo(1) # spill at where the block arg will be
- foo(*args, &)
- end
-
- call([1, 2])
-
- begin
- call([])
- rescue ArgumentError
- :ok
- end
-}
-
-# regression test for send processing before side exit
-assert_equal "ok", %q{
- def foo(a, *) = :foo
-
- def call(args)
- send(:foo, *args)
- end
-
- call([1, 2])
-
- begin
- call([])
- rescue ArgumentError
- :ok
- end
-}
-
-# test discarding extra yield arguments
-assert_equal "2210150001501015", %q{
- def splat_kw(ary) = yield *ary, a: 1
-
- def splat(ary) = yield *ary
-
- def kw = yield 1, 2, a: 0
-
- def simple = yield 0, 1
-
- def calls
- [
- splat([1, 1, 2]) { |x, y| x + y },
- splat([1, 1, 2]) { |y, opt = raise| opt + y},
- splat_kw([0, 1]) { |a:| a },
- kw { |a:| a },
- kw { |a| a },
- simple { 5.itself },
- simple { |a| a },
- simple { |opt = raise| opt },
- simple { |*rest| rest },
- simple { |opt_kw: 5| opt_kw },
- # autosplat ineractions
- [0, 1, 2].yield_self { |a, b| [a, b] },
- [0, 1, 2].yield_self { |a, opt = raise| [a, opt] },
- [1].yield_self { |a, opt = 4| a + opt },
- ]
- end
-
- calls.join
-}
-
-# test autosplat with empty splat
-assert_equal "ok", %q{
- def m(pos, splat) = yield pos, *splat
-
- m([:ok], []) {|v0,| v0 }
-}
-
-# regression test for send stack shifting
-assert_normal_exit %q{
- def foo(a, b)
- a.singleton_methods(b)
- end
-
- def call_foo
- [1, 1, 1, 1, 1, 1, send(:foo, 1, 1)]
- end
-
- call_foo
-}
-
-# regression test for keyword splat with yield
-assert_equal 'nil', %q{
- def splat_kw(kwargs) = yield(**kwargs)
-
- splat_kw({}) { _1 }.inspect
-}
-
-# regression test for arity check with splat
-assert_equal '[:ae, :ae]', %q{
- def req_one(a_, b_ = 1) = raise
-
- def test(args)
- req_one *args
- rescue ArgumentError
- :ae
- end
-
- [test(Array.new 5), test([])]
-} unless rjit_enabled? # Not yet working on RJIT
-
-# regression test for arity check with splat and send
-assert_equal '[:ae, :ae]', %q{
- def two_reqs(a, b_, _ = 1) = a.gsub(a, a)
-
- def test(name, args)
- send(name, *args)
- rescue ArgumentError
- :ae
- end
-
- [test(:two_reqs, ["g", nil, nil, nil]), test(:two_reqs, ["g"])]
-}
-
-# regression test for GC marking stubs in invalidated code
-assert_normal_exit %q{
- skip true unless defined?(GC.compact)
- garbage = Array.new(10_000) { [] } # create garbage to cause iseq movement
- eval(<<~RUBY)
- def foo(n, garbage)
- if n == 2
- # 1.times.each to create a cfunc frame to preserve the JIT frame
- # which will return to a stub housed in an invalidated block
- return 1.times.each do
- Object.define_method(:foo) {}
- garbage.clear
- GC.verify_compaction_references(toward: :empty, expand_heap: true)
- end
- end
-
- foo(n + 1, garbage)
- end
- RUBY
-
- foo(1, garbage)
-}
-
-# regression test for callee block handler overlapping with arguments
-assert_equal '3', %q{
- def foo(_req, *args) = args.last
-
- def call_foo = foo(0, 1, 2, 3, &->{})
-
- call_foo
-}
-
-# call leaf builtin with a block argument
-assert_equal '0', "0.abs(&nil)"
-
-# regression test for invokeblock iseq guard
-assert_equal 'ok', %q{
- skip :ok unless defined?(GC.compact)
- def foo = yield
- 10.times do |i|
- ret = eval("foo { #{i} }")
- raise "failed at #{i}" unless ret == i
- GC.compact
- end
- :ok
-} unless rjit_enabled? # Not yet working on RJIT
-
-# regression test for overly generous guard elision
-assert_equal '[0, :sum, 0, :sum]', %q{
- # In faulty versions, the following happens:
- # 1. YJIT puts object on the temp stack with type knowledge
- # (CArray or CString) about RBASIC_CLASS(object).
- # 2. In iter=0, due to the type knowledge, YJIT generates
- # a call to sum() without any guard on RBASIC_CLASS(object).
- # 3. In iter=1, a singleton class is added to the object,
- # changing RBASIC_CLASS(object), falsifying the type knowledge.
- # 4. Because the code from (1) has no class guard, it is incorrectly
- # reused and the wrong method is invoked.
- # Putting a literal is important for gaining type knowledge.
- def carray(iter)
- array = []
- array.sum(iter.times { def array.sum(_) = :sum })
- end
-
- def cstring(iter)
- string = "".dup
- string.sum(iter.times { def string.sum(_) = :sum })
- end
-
- [carray(0), carray(1), cstring(0), cstring(1)]
-}
-
-# regression test for return type of Integer#/
-# It can return a T_BIGNUM when inputs are T_FIXNUM.
-assert_equal 0x3fffffffffffffff.to_s, %q{
- def call(fixnum_min)
- (fixnum_min / -1) - 1
- end
-
- call(-(2**62))
-}
-
-# regression test for return type of String#<<
-assert_equal 'Sub', %q{
- def call(sub) = (sub << sub).itself
-
- class Sub < String; end
-
- call(Sub.new('o')).class
-}
-
-# test splat filling required and feeding rest
-assert_equal '[0, 1, 2, [3, 4]]', %q{
- public def lead_rest(a, b, *rest)
- [self, a, b, rest]
- end
-
- def call(args) = 0.lead_rest(*args)
-
- call([1, 2, 3, 4])
-}
-
-# test missing opts are nil initialized
-assert_equal '[[0, 1, nil, 3], [0, 1, nil, 3], [0, 1, nil, 3, []], [0, 1, nil, 3, []]]', %q{
- public def lead_opts(a, b=binding.local_variable_get(:c), c=3)
- [self, a, b, c]
- end
-
- public def opts_rest(a=raise, b=binding.local_variable_get(:c), c=3, *rest)
- [self, a, b, c, rest]
- end
-
- def call(args)
- [
- 0.lead_opts(1),
- 0.lead_opts(*args),
-
- 0.opts_rest(1),
- 0.opts_rest(*args),
- ]
- end
-
- call([1])
-}
-
-# test filled optionals with unspecified keyword param
-assert_equal 'ok', %q{
- def opt_rest_opt_kw(_=1, *, k: :ok) = k
-
- def call = opt_rest_opt_kw(0)
-
- call
-}
-
-# test splat empty array with rest param
-assert_equal '[0, 1, 2, []]', %q{
- public def foo(a=1, b=2, *rest)
- [self, a, b, rest]
- end
-
- def call(args) = 0.foo(*args)
-
- call([])
-}
-
# Regression test for yielding with autosplat to block with
# optional parameters. https://github.com/Shopify/yjit/issues/313
assert_equal '[:a, :b, :a, :b]', %q{
@@ -294,7 +26,7 @@ assert_equal '[:ok]', %q{
# Used to crash due to GC run in rb_ensure_iv_list_size()
# not marking the newly allocated [:ok].
RegressionTest.new.extender.itself
-} unless rjit_enabled? # Skip on RJIT since this uncovers a crash
+}
assert_equal 'true', %q{
# regression test for tracking type of locals for too long
@@ -344,7 +76,7 @@ assert_normal_exit %q{
}
assert_normal_exit %q{
- # Test to ensure send on overridden c functions
+ # Test to ensure send on overriden c functions
# doesn't corrupt the stack
class Bar
def bar(x)
@@ -377,80 +109,6 @@ assert_equal '[nil, nil, nil, nil, nil, nil]', %q{
end
}
-assert_equal '[nil, nil, nil, nil, nil, nil]', %q{
- # Tests defined? on non-heap objects
- [NilClass, TrueClass, FalseClass, Integer, Float, Symbol].each do |klass|
- klass.class_eval("def foo = defined?(@foo)")
- end
-
- [nil, true, false, 0xFABCAFE, 0.42, :cake].map do |instance|
- instance.foo
- instance.foo
- end
-}
-
-assert_equal '[nil, "instance-variable", nil, "instance-variable"]', %q{
- # defined? on object that changes shape between calls
- class Foo
- def foo
- defined?(@foo)
- end
-
- def add
- @foo = 1
- end
-
- def remove
- self.remove_instance_variable(:@foo)
- end
- end
-
- obj = Foo.new
- [obj.foo, (obj.add; obj.foo), (obj.remove; obj.foo), (obj.add; obj.foo)]
-}
-
-assert_equal '["instance-variable", 5]', %q{
- # defined? on object too complex for shape information
- class Foo
- def initialize
- 100.times { |i| instance_variable_set("@foo#{i}", i) }
- end
-
- def foo
- [defined?(@foo5), @foo5]
- end
- end
-
- Foo.new.foo
-}
-
-# getinstancevariable with shape too complex
-assert_normal_exit %q{
- class Foo
- def initialize
- @a = 1
- end
-
- def getter
- @foobar
- end
- end
-
- # Initialize ivars in changing order, making the Foo
- # class have shape too complex
- 100.times do |x|
- foo = Foo.new
- foo.instance_variable_set(:"@a#{x}", 1)
- foo.instance_variable_set(:"@foobar", 777)
-
- # The getter method eventually sees shape too complex
- r = foo.getter
- if r != 777
- raise "error"
- end
- end
-}
-
assert_equal '0', %q{
# This is a regression test for incomplete invalidation from
# opt_setinlinecache. This test might be brittle, so
@@ -748,45 +406,6 @@ assert_equal 'false', %q{
less_than 2
}
-# BOP redefinition works on Integer#<=
-assert_equal 'false', %q{
- def le(x, y) = x <= y
-
- le(2, 2)
-
- class Integer
- def <=(_) = false
- end
-
- le(2, 2)
-}
-
-# BOP redefinition works on Integer#>
-assert_equal 'false', %q{
- def gt(x, y) = x > y
-
- gt(3, 2)
-
- class Integer
- def >(_) = false
- end
-
- gt(3, 2)
-}
-
-# BOP redefinition works on Integer#>=
-assert_equal 'false', %q{
- def ge(x, y) = x >= y
-
- ge(2, 2)
-
- class Integer
- def >=(_) = false
- end
-
- ge(2, 2)
-}
-
# Putobject, less-than operator, fixnums
assert_equal '2', %q{
def check_index(index)
@@ -1230,7 +849,6 @@ assert_equal 'special', %q{
# Test that object references in generated code get marked and moved
assert_equal "good", %q{
- skip :good unless defined?(GC.compact)
def bar
"good"
end
@@ -1254,7 +872,7 @@ assert_equal "good", %q{
# Test polymorphic getinstancevariable. T_OBJECT -> T_STRING
assert_equal 'ok', %q{
@hello = @h1 = @h2 = @h3 = @h4 = 'ok'
- str = +""
+ str = ""
str.instance_variable_set(:@hello, 'ok')
public def get
@@ -1398,18 +1016,6 @@ assert_equal '[42, :default]', %q{
]
}
-# Test default value block for Hash with opt_aref_with
-assert_equal "false", <<~RUBY, frozen_string_literal: false
- def index_with_string(h)
- h["foo"]
- end
-
- h = Hash.new { |h, k| k.frozen? }
-
- index_with_string(h)
- index_with_string(h)
-RUBY
-
# A regression test for making sure cfp->sp is proper when
# hitting stubs. See :stub-sp-flush:
assert_equal 'ok', %q{
@@ -1798,7 +1404,7 @@ assert_equal '{}', %q{
}
# test building hash with values
-assert_equal '{foo: :bar}', %q{
+assert_equal '{:foo=>:bar}', %q{
def build_hash(val)
{ foo: val }
end
@@ -1908,7 +1514,7 @@ assert_equal 'foo', %q{
}
# Test that String unary plus returns the same object ID for an unfrozen string.
-assert_equal 'true', <<~RUBY, frozen_string_literal: false
+assert_equal 'true', %q{
def jittable_method
str = "bar"
@@ -1918,7 +1524,7 @@ assert_equal 'true', <<~RUBY, frozen_string_literal: false
uplus_str.object_id == old_obj_id
end
jittable_method
-RUBY
+}
# Test that String unary plus returns a different unfrozen string when given a frozen string
assert_equal 'false', %q{
@@ -2032,85 +1638,6 @@ assert_equal 'true', %q{
jittable_method
}
-# test getbyte on string class
-assert_equal '[97, :nil, 97, :nil, :raised]', %q{
- def getbyte(s, i)
- byte = begin
- s.getbyte(i)
- rescue TypeError
- :raised
- end
-
- byte || :nil
- end
-
- getbyte("a", 0)
- getbyte("a", 0)
-
- [getbyte("a", 0), getbyte("a", 1), getbyte("a", -1), getbyte("a", -2), getbyte("a", "a")]
-} unless rjit_enabled? # Not yet working on RJIT
-
-# Basic test for String#setbyte
-assert_equal 'AoZ', %q{
- s = +"foo"
- s.setbyte(0, 65)
- s.setbyte(-1, 90)
- s
-}
-
-# String#setbyte IndexError
-assert_equal 'String#setbyte', %q{
- def ccall = "".setbyte(1, 0)
- begin
- ccall
- rescue => e
- e.backtrace.first.split("'").last
- end
-}
-
-# String#setbyte TypeError
-assert_equal 'String#setbyte', %q{
- def ccall = "".setbyte(nil, 0)
- begin
- ccall
- rescue => e
- e.backtrace.first.split("'").last
- end
-}
-
-# String#setbyte FrozenError
-assert_equal 'String#setbyte', %q{
- def ccall = "a".freeze.setbyte(0, 0)
- begin
- ccall
- rescue => e
- e.backtrace.first.split("'").last
- end
-}
-
-# non-leaf String#setbyte
-assert_equal 'String#setbyte', %q{
- def to_int
- @caller = caller
- 0
- end
-
- def ccall = "a".dup.setbyte(self, 98)
- ccall
-
- @caller.first.split("'").last
-}
-
-# non-leaf String#byteslice
-assert_equal 'TypeError', %q{
- def ccall = "".byteslice(nil, nil)
- begin
- ccall
- rescue => e
- e.class
- end
-}
-
# Test << operator on string subclass
assert_equal 'abab', %q{
class MyString < String; end
@@ -2256,34 +1783,6 @@ assert_equal '7', %q{
foo(5,2)
}
-# regression test for argument registers with invalidation
-assert_equal '[0, 1, 2]', %q{
- def test(n)
- ret = n
- binding
- ret
- end
-
- [0, 1, 2].map do |n|
- test(n)
- end
-}
-
-# regression test for argument registers
-assert_equal 'true', %q{
- class Foo
- def ==(other)
- other == nil
- end
- end
-
- def test
- [Foo.new].include?(Foo.new)
- end
-
- test
-}
-
# test pattern matching
assert_equal '[:ok, :ok]', %q{
class C
@@ -2349,20 +1848,6 @@ assert_equal '123', %q{
foo(Foo)
}
-# Test EP == BP invalidation with moving ISEQs
-assert_equal 'ok', %q{
- skip :ok unless defined?(GC.compact)
- def entry
- ok = proc { :ok } # set #entry as an EP-escaping ISEQ
- [nil].reverse_each do # avoid exiting the JIT frame on the constant
- GC.compact # move #entry ISEQ
- end
- ok # should be read off of escaped EP
- end
-
- entry.call
-}
-
# invokesuper edge case
assert_equal '[:A, [:A, :B]]', %q{
class B
@@ -2519,50 +2004,6 @@ assert_equal '[:A, :Btwo]', %q{
ins.foo
}
-# invokesuper with a block
-assert_equal 'true', %q{
- class A
- def foo = block_given?
- end
-
- class B < A
- def foo = super()
- end
-
- B.new.foo { }
- B.new.foo { }
-}
-
-# invokesuper in a block
-assert_equal '[0, 2]', %q{
- class A
- def foo(x) = x * 2
- end
-
- class B < A
- def foo
- 2.times.map do |x|
- super(x)
- end
- end
- end
-
- B.new.foo
- B.new.foo
-}
-
-# invokesuper zsuper in a bmethod
-assert_equal 'ok', %q{
- class Foo
- define_method(:itself) { super }
- end
- begin
- Foo.new.itself
- rescue RuntimeError
- :ok
- end
-}
-
# Call to fixnum
assert_equal '[true, false]', %q{
def is_odd(obj)
@@ -2603,16 +2044,6 @@ assert_equal '[true, false, true, false]', %q{
[is_odd(123), is_odd(456), is_odd(bignum), is_odd(bignum+1)]
}
-# Flonum and Flonum
-assert_equal '[2.0, 0.0, 1.0, 4.0]', %q{
- [1.0 + 1.0, 1.0 - 1.0, 1.0 * 1.0, 8.0 / 2.0]
-}
-
-# Flonum and Fixnum
-assert_equal '[2.0, 0.0, 1.0, 4.0]', %q{
- [1.0 + 1, 1.0 - 1, 1.0 * 1, 8.0 / 2]
-}
-
# Call to static and dynamic symbol
assert_equal 'bar', %q{
def to_string(obj)
@@ -2653,30 +2084,6 @@ assert_equal '[1, 2, 3, 4, 5]', %q{
splatarray
}
-# splatkw
-assert_equal '[1, 2]', %q{
- def foo(a:) = [a, yield]
-
- def entry(&block)
- a = { a: 1 }
- foo(**a, &block)
- end
-
- entry { 2 }
-}
-assert_equal '[1, 2]', %q{
- def foo(a:) = [a, yield]
-
- def entry(obj, &block)
- foo(**obj, &block)
- end
-
- entry({ a: 3 }) { 2 }
- obj = Object.new
- def obj.to_hash = { a: 1 }
- entry(obj) { 2 }
-}
-
assert_equal '[1, 1, 2, 1, 2, 3]', %q{
def expandarray
arr = [1, 2, 3]
@@ -2731,23 +2138,6 @@ assert_equal '[:not_array, nil, nil]', %q{
expandarray_not_array(obj)
}
-assert_equal '[1, 2]', %q{
- class NilClass
- private
- def to_ary
- [1, 2]
- end
- end
-
- def expandarray_redefined_nilclass
- a, b = nil
- [a, b]
- end
-
- expandarray_redefined_nilclass
- expandarray_redefined_nilclass
-} unless rjit_enabled?
-
assert_equal '[1, 2, nil]', %q{
def expandarray_rhs_too_small
a, b, c = [1, 2]
@@ -2758,17 +2148,6 @@ assert_equal '[1, 2, nil]', %q{
expandarray_rhs_too_small
}
-assert_equal '[nil, 2, nil]', %q{
- def foo(arr)
- a, b, c = arr
- end
-
- a, b, c1 = foo([0, 1])
- a, b, c2 = foo([0, 1, 2])
- a, b, c3 = foo([0, 1])
- [c1, c2, c3]
-}
-
assert_equal '[1, [2]]', %q{
def expandarray_splat
a, *b = [1, 2]
@@ -2858,7 +2237,7 @@ assert_equal '[[:c_return, :String, :string_alias, "events_to_str"]]', %q{
events.compiled(events)
events
-} unless rjit_enabled? # RJIT calls extra Ruby methods
+} unless defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # MJIT calls extra Ruby methods
# test enabling a TracePoint that targets a particular line in a C method call
assert_equal '[true]', %q{
@@ -2940,7 +2319,7 @@ assert_equal '[[:c_call, :itself]]', %q{
tp.enable { shouldnt_compile }
events
-} unless rjit_enabled? # RJIT calls extra Ruby methods
+} unless defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # MJIT calls extra Ruby methods
# test enabling c_return tracing before compiling
assert_equal '[[:c_return, :itself, main]]', %q{
@@ -2955,7 +2334,7 @@ assert_equal '[[:c_return, :itself, main]]', %q{
tp.enable { shouldnt_compile }
events
-} unless rjit_enabled? # RJIT calls extra Ruby methods
+} unless defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # MJIT calls extra Ruby methods
# test c_call invalidation
assert_equal '[[:c_call, :itself]]', %q{
@@ -3375,7 +2754,7 @@ assert_equal '[[1, 2, 3, 4]]', %q{
}
# cfunc kwargs
-assert_equal '{foo: 123}', %q{
+assert_equal '{:foo=>123}', %q{
def foo(bar)
bar.store(:value, foo: 123)
bar[:value]
@@ -3386,7 +2765,7 @@ assert_equal '{foo: 123}', %q{
}
# cfunc kwargs
-assert_equal '{foo: 123}', %q{
+assert_equal '{:foo=>123}', %q{
def foo(bar)
bar.replace(foo: 123)
end
@@ -3396,7 +2775,7 @@ assert_equal '{foo: 123}', %q{
}
# cfunc kwargs
-assert_equal '{foo: 123, bar: 456}', %q{
+assert_equal '{:foo=>123, :bar=>456}', %q{
def foo(bar)
bar.replace(foo: 123, bar: 456)
end
@@ -3406,7 +2785,7 @@ assert_equal '{foo: 123, bar: 456}', %q{
}
# variadic cfunc kwargs
-assert_equal '{foo: 123}', %q{
+assert_equal '{:foo=>123}', %q{
def foo(bar)
bar.merge(foo: 123)
end
@@ -3530,7 +2909,7 @@ assert_equal "true", %q{
}
# duphash
-assert_equal '{foo: 123}', %q{
+assert_equal '{:foo=>123}', %q{
def foo
{foo: 123}
end
@@ -3540,7 +2919,7 @@ assert_equal '{foo: 123}', %q{
}
# newhash
-assert_equal '{foo: 2}', %q{
+assert_equal '{:foo=>2}', %q{
def foo
{foo: 1+1}
end
@@ -4142,1090 +3521,10 @@ assert_equal 'ok', %q{
cw(4)
}
-assert_equal 'threw', %q{
- def foo(args)
- wrap(*args)
- rescue ArgumentError
- 'threw'
- end
-
- def wrap(a)
- [a]
- end
-
- foo([Hash.ruby2_keywords_hash({})])
-}
-
-assert_equal 'threw', %q{
- # C call
- def bar(args)
- Array(*args)
- rescue ArgumentError
- 'threw'
- end
-
- bar([Hash.ruby2_keywords_hash({})])
-}
-
-# Test instance_of? and is_a?
-assert_equal 'true', %q{
- 1.instance_of?(Integer) && 1.is_a?(Integer)
-}
-
-# Test instance_of? and is_a? for singleton classes
-assert_equal 'true', %q{
- a = []
- def a.test = :test
- a.instance_of?(Array) && a.is_a?(Array)
-}
-
-# Test instance_of? for singleton_class
-# Yes this does really return false
-assert_equal 'false', %q{
- a = []
- def a.test = :test
- a.instance_of?(a.singleton_class)
-}
-
-# Test is_a? for singleton_class
-assert_equal 'true', %q{
- a = []
- def a.test = :test
- a.is_a?(a.singleton_class)
-}
-
-# Test send with splat to a cfunc
-assert_equal 'true', %q{
- 1.send(:==, 1, *[])
-}
-
-# Test empty splat with cfunc
-assert_equal '2', %q{
- def foo
- Integer.sqrt(4, *[])
- end
- # call twice to deal with constant exiting
- foo
- foo
-}
-
-# Test non-empty splat with cfunc
-assert_equal 'Hello World', %q{
- def bar
- args = ["Hello "]
- greeting = +"World"
- greeting.insert(0, *args)
- greeting
- end
- bar
-}
-
-# Regression: this creates a temp stack with > 127 elements
-assert_normal_exit %q{
- def foo(a)
- [
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a, a, a,
- a, a, a, a, a, a, a, a,
- ]
- end
-
- def entry
- foo(1)
- end
-
- entry
-}
-
-# Test that splat and rest combined
-# properly dupe the array
-assert_equal "[]", %q{
- def foo(*rest)
- rest << 1
- end
-
- def test(splat)
- foo(*splat)
- end
-
- EMPTY = []
- custom = Object.new
- def custom.to_a
- EMPTY
- end
-
- test(custom)
- test(custom)
- EMPTY
-}
-
-# Rest with send
-assert_equal '[1, 2, 3]', %q{
- def bar(x, *rest)
- rest.insert(0, x)
- end
- send(:bar, 1, 2, 3)
-}
-
-# Fix splat block arg bad compilation
-assert_equal "foo", %q{
- def literal(*args, &block)
- s = ''.dup
- literal_append(s, *args, &block)
- s
- end
-
- def literal_append(sql, v)
- sql << v
- end
-
- literal("foo")
-}
-
-# regression test for accidentally having a parameter truncated
-# due to Rust/C signature mismatch. Used to crash with
-# > [BUG] rb_vm_insn_addr2insn: invalid insn address ...
-# or
-# > ... `Err` value: TryFromIntError(())'
-assert_normal_exit %q{
- n = 16384
- eval(
- "def foo(arg); " + "_=arg;" * n + '_=1;' + "Object; end"
- )
- foo 1
-}
-
-# Regression test for CantCompile not using starting_ctx
-assert_normal_exit %q{
- class Integer
- def ===(other)
- false
- end
- end
-
- def my_func(x)
- case x
- when 1
- 1
- when 2
- 2
- else
- 3
- end
- end
-
- my_func(1)
-}
-
-# Regression test for CantCompile not using starting_ctx
-assert_equal "ArgumentError", %q{
- def literal(*args, &block)
- s = ''.dup
- args = [1, 2, 3]
- literal_append(s, *args, &block)
- s
- end
-
- def literal_append(sql, v)
- [sql.inspect, v.inspect]
- end
-
- begin
- literal("foo")
- rescue ArgumentError
- "ArgumentError"
- end
-}
-
-# Rest with block
-# Simplified code from railsbench
-assert_equal '[{"/a" => "b", as: :c, via: :post}, [], nil]', %q{
- def match(path, *rest, &block)
- [path, rest, block]
- end
-
- def map_method(method, args, &block)
- options = args.last
- args.pop
- options[:via] = method
- match(*args, options, &block)
- end
-
- def post(*args, &block)
- map_method(:post, args, &block)
- end
-
- post "/a" => "b", as: :c
-}
-
-# Test rest and kw_args
-assert_equal '[true, true, true, true]', %q{
- def my_func(*args, base: nil, sort: true)
- [args, base, sort]
- end
-
- def calling_my_func
- results = []
- results << (my_func("test") == [["test"], nil, true])
- results << (my_func("test", base: :base) == [["test"], :base, true])
- results << (my_func("test", sort: false) == [["test"], nil, false])
- results << (my_func("test", "other", base: :base) == [["test", "other"], :base, true])
- results
- end
- calling_my_func
-}
-
-# Test Integer#[] with 2 args
-assert_equal '0', %q{
- 3[0, 0]
-}
-
-# unspecified_bits + checkkeyword
-assert_equal '2', %q{
- def callee = 1
-
- # checkkeyword should see unspecified_bits=0 (use bar), not Integer 1 (set bar = foo).
- def foo(foo, bar: foo) = bar
-
- def entry(&block)
- # write 1 at stack[3]. Calling #callee spills stack[3].
- 1 + (1 + (1 + (1 + callee)))
- # &block is written to a register instead of stack[3]. When &block is popped and
- # unspecified_bits is pushed, it must be written to stack[3], not to a register.
- foo(1, bar: 2, &block)
- end
-
- entry # call branch_stub_hit (spill temps)
- entry # doesn't call branch_stub_hit (not spill temps)
-}
-
-# Test rest and optional_params
-assert_equal '[true, true, true, true]', %q{
- def my_func(stuff, base=nil, sort=true, *args)
- [stuff, base, sort, args]
- end
-
- def calling_my_func
- results = []
- results << (my_func("test") == ["test", nil, true, []])
- results << (my_func("test", :base) == ["test", :base, true, []])
- results << (my_func("test", :base, false) == ["test", :base, false, []])
- results << (my_func("test", :base, false, "other", "other") == ["test", :base, false, ["other", "other"]])
- results
- end
- calling_my_func
-}
-
-# Test rest and optional_params and splat
-assert_equal '[true, true, true, true, true]', %q{
- def my_func(stuff, base=nil, sort=true, *args)
- [stuff, base, sort, args]
- end
-
- def calling_my_func
- results = []
- splat = ["test"]
- results << (my_func(*splat) == ["test", nil, true, []])
- splat = [:base]
- results << (my_func("test", *splat) == ["test", :base, true, []])
- splat = [:base, false]
- results << (my_func("test", *splat) == ["test", :base, false, []])
- splat = [:base, false, "other", "other"]
- results << (my_func("test", *splat) == ["test", :base, false, ["other", "other"]])
- splat = ["test", :base, false, "other", "other"]
- results << (my_func(*splat) == ["test", :base, false, ["other", "other"]])
- results
- end
- calling_my_func
-}
-
-# Regression test: rest and optional and splat
-assert_equal 'true', %q{
- def my_func(base=nil, *args)
- [base, args]
- end
-
- def calling_my_func
- array = []
- my_func(:base, :rest1, *array) == [:base, [:rest1]]
- end
-
- calling_my_func
-}
-
-# Fix failed case for large splat
-assert_equal 'true', %q{
- def d(a, b=:b)
- end
-
- def calling_func
- ary = 1380888.times;
- d(*ary)
- end
- begin
- calling_func
- rescue ArgumentError
- true
- end
-} unless rjit_enabled? # Not yet working on RJIT
-
-# Regression test: register allocator on expandarray
-assert_equal '[]', %q{
- func = proc { [] }
- proc do
- _x, _y = func.call
- end.call
-}
-
-# Catch TAG_BREAK in a non-FINISH frame with JIT code
-assert_equal '1', %q{
- def entry
- catch_break
- end
-
- def catch_break
- while_true do
- break
- end
- 1
- end
-
- def while_true
- while true
- yield
- end
- end
-
- entry
-}
-
-assert_equal '6', %q{
- class Base
- def number = 1 + yield
- end
-
- class Sub < Base
- def number = super + 2
- end
-
- Sub.new.number { 3 }
-}
-
-# Integer multiplication and overflow
-assert_equal '[6, -6, 9671406556917033397649408, -9671406556917033397649408, 21267647932558653966460912964485513216]', %q{
- def foo(a, b)
- a * b
- end
-
- r1 = foo(2, 3)
- r2 = foo(2, -3)
- r3 = foo(2 << 40, 2 << 41)
- r4 = foo(2 << 40, -2 << 41)
- r5 = foo(1 << 62, 1 << 62)
-
- [r1, r2, r3, r4, r5]
-}
-
-# Integer multiplication and overflow (minimized regression test from test-basic)
-assert_equal '8515157028618240000', %q{2128789257154560000 * 4}
-
-# Inlined method calls
-assert_equal 'nil', %q{
- def putnil = nil
- def entry = putnil
- entry.inspect
-}
-assert_equal '1', %q{
- def putobject_1 = 1
- def entry = putobject_1
- entry
-}
-assert_equal 'false', %q{
- def putobject(_unused_arg1) = false
- def entry = putobject(nil)
- entry
-}
-assert_equal 'true', %q{
- def entry = yield
- entry { true }
-}
-assert_equal 'sym', %q{
- def entry = :sym.to_sym
- entry
-}
-
-assert_normal_exit %q{
- ivars = 1024.times.map { |i| "@iv_#{i} = #{i}\n" }.join
- Foo = Class.new
- Foo.class_eval "def initialize() #{ivars} end"
- Foo.new
-}
+assert_normal_exit %{
+ class Bug20997
+ def foo(&) = self.class.name(&)
-assert_equal '0', %q{
- def spill
- 1.to_i # not inlined
- end
-
- def inline(_stack1, _stack2, _stack3, _stack4, _stack5)
- 0 # inlined
- end
-
- def entry
- # RegTemps is 00111110 prior to the #inline call.
- # Its return value goes to stack_idx=0, which conflicts with stack_idx=5.
- inline(spill, 2, 3, 4, 5)
- end
-
- entry
-}
-
-# Integer succ and overflow
-assert_equal '[2, 4611686018427387904]', %q{
- [1.succ, 4611686018427387903.succ]
-}
-
-# Integer right shift
-assert_equal '[0, 1, -4]', %q{
- [0 >> 1, 2 >> 1, -7 >> 1]
-}
-
-# Integer XOR
-assert_equal '[0, 0, 4]', %q{
- [0 ^ 0, 1 ^ 1, 7 ^ 3]
-}
-
-assert_equal '[nil, "yield"]', %q{
- def defined_yield = defined?(yield)
- [defined_yield, defined_yield {}]
-}
-
-# splat with ruby2_keywords into rest parameter
-assert_equal '[[{a: 1}], {}]', %q{
- ruby2_keywords def foo(*args) = args
-
- def bar(*args, **kw) = [args, kw]
-
- def pass_bar(*args) = bar(*args)
-
- def body
- args = foo(a: 1)
- pass_bar(*args)
- end
-
- body
-}
-
-# concatarray
-assert_equal '[1, 2]', %q{
- def foo(a, b) = [a, b]
- arr = [2]
- foo(*[1], *arr)
-}
-
-# pushtoarray
-assert_equal '[1, 2]', %q{
- def foo(a, b) = [a, b]
- arr = [1]
- foo(*arr, 2)
-}
-
-# pop before fallback
-assert_normal_exit %q{
- class Foo
- attr_reader :foo
-
- def try = foo(0, &nil)
- end
-
- Foo.new.try
-}
-
-# a kwrest case
-assert_equal '[1, 2, {complete: false}]', %q{
- def rest(foo: 1, bar: 2, **kwrest)
- [foo, bar, kwrest]
- end
-
- def callsite = rest(complete: false)
-
- callsite
-}
-
-# splat+kw_splat+opt+rest
-assert_equal '[1, []]', %q{
- def opt_rest(a = 0, *rest) = [a, rest]
-
- def call_site(args) = opt_rest(*args, **nil)
-
- call_site([1])
-}
-
-# splat and nil kw_splat
-assert_equal 'ok', %q{
- def identity(x) = x
-
- def splat_nil_kw_splat(args) = identity(*args, **nil)
-
- splat_nil_kw_splat([:ok])
-}
-
-# empty splat and kwsplat into leaf builtins
-assert_equal '[1, 1, 1]', %q{
- empty = []
- [1.abs(*empty), 1.abs(**nil), 1.bit_length(*empty, **nil)]
-}
-
-# splat into C methods with -1 arity
-assert_equal '[[1, 2, 3], [0, 2, 3], [1, 2, 3], [2, 2, 3], [], [], [{}]]', %q{
- class Foo < Array
- def push(args) = super(1, *args)
- end
-
- def test_cfunc_vargs_splat(sub_instance, array_class, empty_kw_hash)
- splat = [2, 3]
- kw_splat = [empty_kw_hash]
- [
- sub_instance.push(splat),
- array_class[0, *splat, **nil],
- array_class[1, *splat, &nil],
- array_class[2, *splat, **nil, &nil],
- array_class.send(:[], *kw_splat),
- # kw_splat disables keywords hash handling
- array_class[*kw_splat],
- array_class[*kw_splat, **nil],
- ]
- end
-
- test_cfunc_vargs_splat(Foo.new, Array, Hash.ruby2_keywords_hash({}))
-}
-
-# Class#new (arity=-1), splat, and ruby2_keywords
-assert_equal '[0, {1 => 1}]', %q{
- class KwInit
- attr_reader :init_args
- def initialize(x = 0, **kw)
- @init_args = [x, kw]
- end
- end
-
- def test(klass, args)
- klass.new(*args).init_args
- end
-
- test(KwInit, [Hash.ruby2_keywords_hash({1 => 1})])
-}
-
-# Chilled string setivar trigger warning
-assert_equal 'literal string will be frozen in the future', %q{
- Warning[:deprecated] = true
- $VERBOSE = true
- $warning = "no-warning"
- module ::Warning
- def self.warn(message)
- $warning = message.split("warning: ").last.strip
- end
- end
-
- class String
- def setivar!
- @ivar = 42
- end
- end
-
- def setivar!(str)
- str.setivar!
- end
-
- 10.times { setivar!("mutable".dup) }
- 10.times do
- setivar!("frozen".freeze)
- rescue FrozenError
- end
-
- setivar!("chilled") # Emit warning
- $warning
-}
-
-# arity=-2 cfuncs
-assert_equal '["", "1/2", [0, [:ok, 1]]]', %q{
- def test_cases(file, chain)
- new_chain = chain.allocate # to call initialize directly
- new_chain.send(:initialize, [0], ok: 1)
-
- [
- file.join,
- file.join("1", "2"),
- new_chain.to_a,
- ]
- end
-
- test_cases(File, Enumerator::Chain)
-}
-
-# singleton class should invalidate Type::CString assumption
-assert_equal 'foo', %q{
- def define_singleton(str, define)
- if define
- # Wrap a C method frame to avoid exiting JIT code on defineclass
- [nil].reverse_each do
- class << str
- def +(_)
- "foo"
- end
- end
- end
- end
- "bar"
- end
-
- def entry(define)
- str = ""
- # When `define` is false, #+ compiles to rb_str_plus() without a class guard.
- # When the code is reused with `define` is true, the class of `str` is changed
- # to a singleton class, so the block should be invalidated.
- str + define_singleton(str, define)
- end
-
- entry(false)
- entry(true)
-}
-
-assert_equal 'ok', %q{
- def ok
- :ok
- end
-
- def delegator(...)
- ok(...)
- end
-
- def caller
- send(:delegator)
- end
-
- caller
-}
-
-# test inlining of simple iseqs
-assert_equal '[:ok, :ok, :ok]', %q{
- def identity(x) = x
- def foo(x, _) = x
- def bar(_, _, _, _, x) = x
-
- def tests
- [
- identity(:ok),
- foo(:ok, 2),
- bar(1, 2, 3, 4, :ok),
- ]
- end
-
- tests
-}
-
-# test inlining of simple iseqs with kwargs
-assert_equal '[:ok, :ok, :ok, :ok, :ok]', %q{
- def optional_unused(x, opt: :not_ok) = x
- def optional_used(x, opt: :ok) = opt
- def required_unused(x, req:) = x
- def required_used(x, req:) = req
- def unknown(x) = x
-
- def tests
- [
- optional_unused(:ok),
- optional_used(:not_ok),
- required_unused(:ok, req: :not_ok),
- required_used(:not_ok, req: :ok),
- begin unknown(:not_ok, unknown_kwarg: :not_ok) rescue ArgumentError; :ok end,
- ]
- end
-
- tests
-}
-
-# test simple iseqs not eligible for inlining
-assert_equal '[:ok, :ok, :ok, :ok, :ok]', %q{
- def identity(x) = x
- def arg_splat(x, *args) = x
- def kwarg_splat(x, **kwargs) = x
- def block_arg(x, &blk) = x
- def block_iseq(x) = x
- def call_forwarding(...) = identity(...)
-
- def tests
- [
- arg_splat(:ok),
- kwarg_splat(:ok),
- block_arg(:ok, &proc { :not_ok }),
- block_iseq(:ok) { :not_ok },
- call_forwarding(:ok),
- ]
- end
-
- tests
-}
-
-# regression test for invalidating an empty block
-assert_equal '0', %q{
- def foo = (* = 1).pred
-
- foo # compile it
-
- class Integer
- def to_ary = [] # invalidate
- end
-
- foo # try again
-} unless rjit_enabled? # doesn't work on RJIT
-
-# test integer left shift with constant rhs
-assert_equal [0x80000000000, 'a+', :ok].inspect, %q{
- def shift(val) = val << 43
-
- def tests
- int = shift(1)
- str = shift("a")
-
- Integer.define_method(:<<) { |_| :ok }
- redef = shift(1)
-
- [int, str, redef]
- end
-
- tests
-}
-
-# test integer left shift fusion followed by opt_getconstant_path
-assert_equal '33', %q{
- def test(a)
- (a << 5) | (Object; a)
- end
-
- test(1)
-}
-
-# test String#stebyte with arguments that need conversion
-assert_equal "abc", %q{
- str = +"a00"
- def change_bytes(str, one, two)
- str.setbyte(one, "b".ord)
- str.setbyte(2, two)
- end
-
- to_int_1 = Object.new
- to_int_99 = Object.new
- def to_int_1.to_int = 1
- def to_int_99.to_int = 99
-
- change_bytes(str, to_int_1, to_int_99)
- str
-}
-
-# test --yjit-verify-ctx for arrays with a singleton class
-assert_equal "ok", %q{
- class Array
- def foo
- self.singleton_class.define_method(:first) { :ok }
- first
- end
- end
-
- def test = [].foo
-
- test
-}
-
-assert_equal '["raised", "Module", "Object"]', %q{
- def foo(obj)
- obj.superclass.name
- end
-
- ret = []
-
- begin
- foo(Class.allocate)
- rescue TypeError
- ret << 'raised'
- end
-
- ret += [foo(Class), foo(Class.new)]
-}
-
-# test TrueClass#=== before and after redefining TrueClass#==
-assert_equal '[[true, false, false], [true, true, false], [true, :error, :error]]', %q{
- def true_eqq(x)
- true === x
- rescue NoMethodError
- :error
- end
-
- def test
- [
- # first one is always true because rb_equal does object comparison before calling #==
- true_eqq(true),
- # these will use TrueClass#==
- true_eqq(false),
- true_eqq(:truthy),
- ]
- end
-
- results = [test]
-
- class TrueClass
- def ==(x)
- !x
- end
- end
-
- results << test
-
- class TrueClass
- undef_method :==
- end
-
- results << test
-} unless rjit_enabled? # Not yet working on RJIT
-
-# test FalseClass#=== before and after redefining FalseClass#==
-assert_equal '[[true, false, false], [true, false, true], [true, :error, :error]]', %q{
- def case_equal(x, y)
- x === y
- rescue NoMethodError
- :error
- end
-
- def test
- [
- # first one is always true because rb_equal does object comparison before calling #==
- case_equal(false, false),
- # these will use #==
- case_equal(false, true),
- case_equal(false, nil),
- ]
- end
-
- results = [test]
-
- class FalseClass
- def ==(x)
- !x
- end
- end
-
- results << test
-
- class FalseClass
- undef_method :==
- end
-
- results << test
-} unless rjit_enabled? # Not yet working on RJIT
-
-# test NilClass#=== before and after redefining NilClass#==
-assert_equal '[[true, false, false], [true, false, true], [true, :error, :error]]', %q{
- def case_equal(x, y)
- x === y
- rescue NoMethodError
- :error
- end
-
- def test
- [
- # first one is always true because rb_equal does object comparison before calling #==
- case_equal(nil, nil),
- # these will use #==
- case_equal(nil, true),
- case_equal(nil, false),
- ]
- end
-
- results = [test]
-
- class NilClass
- def ==(x)
- !x
- end
- end
-
- results << test
-
- class NilClass
- undef_method :==
- end
-
- results << test
-} unless rjit_enabled? # Not yet working on RJIT
-
-# test struct accessors fire c_call events
-assert_equal '[[:c_call, :x=], [:c_call, :x]]', %q{
- c = Struct.new(:x)
- obj = c.new
-
- events = []
- TracePoint.new(:c_call) do
- events << [_1.event, _1.method_id]
- end.enable do
- obj.x = 100
- obj.x
- end
-
- events
-}
-
-# regression test for splatting empty array
-assert_equal '1', %q{
- def callee(foo) = foo
-
- def test_body(args) = callee(1, *args)
-
- test_body([])
- array = Array.new(100)
- array.clear
- test_body(array)
-}
-
-# regression test for splatting empty array to cfunc
-assert_normal_exit %q{
- def test_body(args) = Array(1, *args)
-
- test_body([])
- 0x100.times do
- array = Array.new(100)
- array.clear
- test_body(array)
+ new.foo
end
}
-
-# compiling code shouldn't emit warnings as it may call into more Ruby code
-assert_equal 'ok', <<~'RUBY'
- # [Bug #20522]
- $VERBOSE = true
- Warning[:performance] = true
-
- module StrictWarnings
- def warn(msg, **)
- raise msg
- end
- end
- Warning.singleton_class.prepend(StrictWarnings)
-
- class A
- def compiled_method(is_private)
- @some_ivar = is_private
- end
- end
-
- shape_max_variations = 8
- if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS) && RubyVM::Shape::SHAPE_MAX_VARIATIONS != shape_max_variations
- raise "Expected SHAPE_MAX_VARIATIONS to be #{shape_max_variations}, got: #{RubyVM::Shape::SHAPE_MAX_VARIATIONS}"
- end
-
- 100.times do |i|
- klass = Class.new(A)
- (shape_max_variations - 1).times do |j|
- obj = klass.new
- obj.instance_variable_set("@base_#{i}", 42)
- obj.instance_variable_set("@ivar_#{j}", 42)
- end
- obj = klass.new
- obj.instance_variable_set("@base_#{i}", 42)
- begin
- obj.compiled_method(true)
- rescue
- # expected
- end
- end
-
- :ok
-RUBY
-
-assert_equal 'ok', <<~'RUBY'
- class MyRelation
- def callee(...)
- :ok
- end
-
- def uncached(...)
- callee(...)
- end
-
- def takes_block(&block)
- # push blockhandler
- uncached(&block) # CI1
- end
- end
-
- relation = MyRelation.new
- relation.takes_block { }
-RUBY
-
-assert_equal 'ok', <<~'RUBY'
- def _exec_scope(...)
- instance_exec(...)
- end
-
- def ok args, body
- _exec_scope(*args, &body)
- end
-
- ok([], -> { "ok" })
-RUBY
-
-assert_equal 'ok', <<~'RUBY'
- def _exec_scope(...)
- instance_exec(...)
- end
-
- def ok args, body
- _exec_scope(*args, &body)
- end
-
- ok(["ok"], ->(x) { x })
-RUBY
-
-assert_equal 'ok', <<~'RUBY'
-def baz(a, b)
- a + b
-end
-
-def bar(...)
- baz(...)
-end
-
-def foo(a, ...)
- bar(a, ...)
-end
-
-def test
- foo("o", "k")
-end
-
-test
-RUBY
-
-assert_equal '[true, true]', <<~'RUBY'
- def pack
- v = 1.23
- [v, v*2, v*3].pack("E*").unpack("E*") == [v, v*2, v*3]
- end
-
- def with_buffer
- v = 4.56
- b = +"x"
- [v, v*2, v*3].pack("E*", buffer: b)
- b[1..].unpack("E*") == [v, v*2, v*3]
- end
-
- [pack, with_buffer]
-RUBY
diff --git a/builtin.c b/builtin.c
index 3bde2408f8..21fff95650 100644
--- a/builtin.c
+++ b/builtin.c
@@ -3,15 +3,15 @@
#include "iseq.h"
#include "builtin.h"
-#include "builtin_binary.inc"
-
-#ifndef BUILTIN_BINARY_SIZE
+#ifdef CROSS_COMPILING
-#define BUILTIN_LOADED(feature_name, iseq) ((void)0)
+#define INCLUDED_BY_BUILTIN_C 1
#include "mini_builtin.c"
#else
+#include "builtin_binary.inc"
+
static const unsigned char *
bin4feature(const struct builtin_binary *bb, const char *feature, size_t *psize)
{
@@ -39,15 +39,15 @@ rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin
size_t size;
const unsigned char *bin = builtin_lookup(feature_name, &size);
if (! bin) {
- rb_bug("builtin_lookup: can not find %s", feature_name);
+ rb_bug("builtin_lookup: can not find %s\n", feature_name);
}
// load binary
rb_vm_t *vm = GET_VM();
if (vm->builtin_function_table != NULL) rb_bug("vm->builtin_function_table should be NULL.");
vm->builtin_function_table = table;
+ vm->builtin_inline_index = 0;
const rb_iseq_t *iseq = rb_iseq_ibf_load_bytes((const char *)bin, size);
- ASSUME(iseq); // otherwise an exception should have raised
vm->builtin_function_table = NULL;
// exec
@@ -57,12 +57,6 @@ rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin
#endif
void
-rb_free_loaded_builtin_table(void)
-{
- // do nothing
-}
-
-void
Init_builtin(void)
{
// nothing
diff --git a/builtin.h b/builtin.h
index 24aa7c2fdb..38ad5a1629 100644
--- a/builtin.h
+++ b/builtin.h
@@ -11,13 +11,17 @@ struct rb_builtin_function {
// for load
const int index;
const char * const name;
+
+ // for jit
+ void (*compiler)(VALUE, long, unsigned, bool);
};
-#define RB_BUILTIN_FUNCTION(_i, _name, _fname, _arity) {\
+#define RB_BUILTIN_FUNCTION(_i, _name, _fname, _arity, _compiler) {\
.name = _i < 0 ? NULL : #_name, \
.func_ptr = (void *)_fname, \
.argc = _arity, \
.index = _i, \
+ .compiler = _compiler, \
}
void rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table);
@@ -106,8 +110,6 @@ rb_vm_lvar(rb_execution_context_t *ec, int index)
#endif
}
-#define LOCAL_PTR(local) local ## __ptr
-
// dump/load
struct builtin_binary {
diff --git a/ccan/list/list.h b/ccan/list/list.h
index bf692a6937..30b2af04e9 100644
--- a/ccan/list/list.h
+++ b/ccan/list/list.h
@@ -635,16 +635,14 @@ static inline void ccan_list_prepend_list_(struct ccan_list_head *to,
/* internal macros, do not use directly */
#define ccan_list_for_each_off_dir_(h, i, off, dir) \
- for (i = 0, \
- i = ccan_list_node_to_off_(ccan_list_debug(h, CCAN_LIST_LOC)->n.dir, \
+ for (i = ccan_list_node_to_off_(ccan_list_debug(h, CCAN_LIST_LOC)->n.dir, \
(off)); \
ccan_list_node_from_off_((void *)i, (off)) != &(h)->n; \
i = ccan_list_node_to_off_(ccan_list_node_from_off_((void *)i, (off))->dir, \
(off)))
#define ccan_list_for_each_safe_off_dir_(h, i, nxt, off, dir) \
- for (i = 0, \
- i = ccan_list_node_to_off_(ccan_list_debug(h, CCAN_LIST_LOC)->n.dir, \
+ for (i = ccan_list_node_to_off_(ccan_list_debug(h, CCAN_LIST_LOC)->n.dir, \
(off)), \
nxt = ccan_list_node_to_off_(ccan_list_node_from_off_(i, (off))->dir, \
(off)); \
diff --git a/class.c b/class.c
index c0920e111d..cf0b7b821f 100644
--- a/class.c
+++ b/class.c
@@ -29,51 +29,8 @@
#include "internal/variable.h"
#include "ruby/st.h"
#include "vm_core.h"
-#include "yjit.h"
-/* Flags of T_CLASS
- *
- * 0: RCLASS_IS_ROOT
- * The class has been added to the VM roots. Will always be marked and pinned.
- * This is done for classes defined from C to allow storing them in global variables.
- * 1: RUBY_FL_SINGLETON
- * This class is a singleton class.
- * 2: RCLASS_SUPERCLASSES_INCLUDE_SELF
- * The RCLASS_SUPERCLASSES contains the class as the last element.
- * This means that this class owns the RCLASS_SUPERCLASSES list.
- * if !SHAPE_IN_BASIC_FLAGS
- * 4-19: SHAPE_FLAG_MASK
- * Shape ID for the class.
- * endif
- */
-
-/* Flags of T_ICLASS
- *
- * 0: RICLASS_IS_ORIGIN
- * 3: RICLASS_ORIGIN_SHARED_MTBL
- * The T_ICLASS does not own the method table.
- * if !SHAPE_IN_BASIC_FLAGS
- * 4-19: SHAPE_FLAG_MASK
- * Shape ID. This is set but not used.
- * endif
- */
-
-/* Flags of T_MODULE
- *
- * 0: RCLASS_IS_ROOT
- * The class has been added to the VM roots. Will always be marked and pinned.
- * This is done for classes defined from C to allow storing them in global variables.
- * 1: RMODULE_ALLOCATED_BUT_NOT_INITIALIZED
- * Module has not been initialized.
- * 2: RCLASS_SUPERCLASSES_INCLUDE_SELF
- * See RCLASS_SUPERCLASSES_INCLUDE_SELF in T_CLASS.
- * 3: RMODULE_IS_REFINEMENT
- * Module is used for refinements.
- * if !SHAPE_IN_BASIC_FLAGS
- * 4-19: SHAPE_FLAG_MASK
- * Shape ID for the module.
- * endif
- */
+#define id_attached id__attached__
#define METACLASS_OF(k) RBASIC(k)->klass
#define SET_METACLASS_OF(k, cls) RBASIC_SET_CLASS(k, cls)
@@ -226,25 +183,34 @@ rb_class_detach_module_subclasses(VALUE klass)
/**
* Allocates a struct RClass for a new class.
*
- * @param flags initial value for basic.flags of the returned class.
- * @param klass the class of the returned class.
- * @return an uninitialized Class object.
- * @pre `klass` must refer `Class` class or an ancestor of Class.
- * @pre `(flags | T_CLASS) != 0`
- * @post the returned class can safely be `#initialize` 'd.
+ * \param flags initial value for basic.flags of the returned class.
+ * \param klass the class of the returned class.
+ * \return an uninitialized Class object.
+ * \pre \p klass must refer \c Class class or an ancestor of Class.
+ * \pre \code (flags | T_CLASS) != 0 \endcode
+ * \post the returned class can safely be \c #initialize 'd.
*
- * @note this function is not Class#allocate.
+ * \note this function is not Class#allocate.
*/
static VALUE
class_alloc(VALUE flags, VALUE klass)
{
- size_t alloc_size = sizeof(struct RClass) + sizeof(rb_classext_t);
+ size_t alloc_size = sizeof(struct RClass);
+
+#if RCLASS_EXT_EMBEDDED
+ alloc_size += sizeof(rb_classext_t);
+#endif
flags &= T_MASK;
+ flags |= FL_PROMOTED1 /* start from age == 2 */;
if (RGENGC_WB_PROTECTED_CLASS) flags |= FL_WB_PROTECTED;
- NEWOBJ_OF(obj, struct RClass, klass, flags, alloc_size, 0);
+ RVARGC_NEWOBJ_OF(obj, struct RClass, klass, flags, alloc_size);
+#if RCLASS_EXT_EMBEDDED
memset(RCLASS_EXT(obj), 0, sizeof(rb_classext_t));
+#else
+ obj->ptr = ZALLOC(rb_classext_t);
+#endif
/* ZALLOC
RCLASS_CONST_TBL(obj) = 0;
@@ -257,7 +223,7 @@ class_alloc(VALUE flags, VALUE klass)
*/
RCLASS_SET_ORIGIN((VALUE)obj, (VALUE)obj);
RB_OBJ_WRITE(obj, &RCLASS_REFINED_CLASS(obj), Qnil);
- RCLASS_SET_ALLOCATOR((VALUE)obj, 0);
+ RCLASS_ALLOCATOR(obj) = 0;
return (VALUE)obj;
}
@@ -268,14 +234,14 @@ RCLASS_M_TBL_INIT(VALUE c)
RCLASS_M_TBL(c) = rb_id_table_create(0);
}
-/**
+/*!
* A utility function that wraps class_alloc.
*
* allocates a class and initializes safely.
- * @param super a class from which the new class derives.
- * @return a class object.
- * @pre `super` must be a class.
- * @post the metaclass of the new class is Class.
+ * \param super a class from which the new class derives.
+ * \return a class object.
+ * \pre \a super must be a class.
+ * \post the metaclass of the new class is Class.
*/
VALUE
rb_class_boot(VALUE super)
@@ -347,7 +313,7 @@ rb_check_inheritable(VALUE super)
rb_raise(rb_eTypeError, "superclass must be an instance of Class (given an instance of %"PRIsVALUE")",
rb_obj_class(super));
}
- if (RCLASS_SINGLETON_P(super)) {
+ if (RBASIC(super)->flags & FL_SINGLETON) {
rb_raise(rb_eTypeError, "can't make subclass of singleton class");
}
if (super == rb_cClass) {
@@ -433,7 +399,7 @@ class_init_copy_check(VALUE clone, VALUE orig)
if (RCLASS_SUPER(clone) != 0 || clone == rb_cBasicObject) {
rb_raise(rb_eTypeError, "already initialized class");
}
- if (RCLASS_SINGLETON_P(orig)) {
+ if (FL_TEST(orig, FL_SINGLETON)) {
rb_raise(rb_eTypeError, "can't copy singleton class");
}
}
@@ -444,8 +410,7 @@ struct cvc_table_copy_ctx {
};
static enum rb_id_table_iterator_result
-cvc_table_copy(ID id, VALUE val, void *data)
-{
+cvc_table_copy(ID id, VALUE val, void *data) {
struct cvc_table_copy_ctx *ctx = (struct cvc_table_copy_ctx *)data;
struct rb_cvar_class_tbl_entry * orig_entry;
orig_entry = (struct rb_cvar_class_tbl_entry *)val;
@@ -505,7 +470,7 @@ static bool ensure_origin(VALUE klass);
/**
* If this flag is set, that module is allocated but not initialized yet.
*/
-enum {RMODULE_ALLOCATED_BUT_NOT_INITIALIZED = RUBY_FL_USER1};
+enum {RMODULE_ALLOCATED_BUT_NOT_INITIALIZED = RUBY_FL_USER5};
static inline bool
RMODULE_UNINITIALIZED(VALUE module)
@@ -548,14 +513,14 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
/* cloned flag is refer at constant inline cache
* see vm_get_const_key_cref() in vm_insnhelper.c
*/
- RCLASS_EXT(clone)->cloned = true;
- RCLASS_EXT(orig)->cloned = true;
+ FL_SET(clone, RCLASS_CLONED);
+ FL_SET(orig , RCLASS_CLONED);
- if (!RCLASS_SINGLETON_P(CLASS_OF(clone))) {
+ if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) {
RBASIC_SET_CLASS(clone, rb_singleton_class_clone(orig));
rb_singleton_class_attached(METACLASS_OF(clone), (VALUE)clone);
}
- RCLASS_SET_ALLOCATOR(clone, RCLASS_ALLOCATOR(orig));
+ RCLASS_ALLOCATOR(clone) = RCLASS_ALLOCATOR(orig);
copy_tables(clone, orig);
if (RCLASS_M_TBL(orig)) {
struct clone_method_arg arg;
@@ -587,14 +552,11 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
rb_bug("non iclass between module/class and origin");
}
clone_p = class_alloc(RBASIC(p)->flags, METACLASS_OF(p));
- /* We should set the m_tbl right after allocation before anything
- * that can trigger GC to avoid clone_p from becoming old and
- * needing to fire write barriers. */
- RCLASS_SET_M_TBL(clone_p, RCLASS_M_TBL(p));
RCLASS_SET_SUPER(prev_clone_p, clone_p);
prev_clone_p = clone_p;
+ RCLASS_M_TBL(clone_p) = RCLASS_M_TBL(p);
RCLASS_CONST_TBL(clone_p) = RCLASS_CONST_TBL(p);
- RCLASS_SET_ALLOCATOR(clone_p, RCLASS_ALLOCATOR(p));
+ RCLASS_ALLOCATOR(clone_p) = RCLASS_ALLOCATOR(p);
if (RB_TYPE_P(clone, T_CLASS)) {
RCLASS_SET_INCLUDER(clone_p, clone);
}
@@ -657,7 +619,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
// attached to an object other than `obj`. In which case `obj` does not have
// a material singleton class attached yet and there is no singleton class
// to clone.
- if (!(RCLASS_SINGLETON_P(klass) && RCLASS_ATTACHED_OBJECT(klass) == obj)) {
+ if (!(FL_TEST(klass, FL_SINGLETON) && rb_attr_get(klass, id_attached) == obj)) {
// nothing to clone
return klass;
}
@@ -679,6 +641,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
}
RCLASS_SET_SUPER(clone, RCLASS_SUPER(klass));
+ RCLASS_ALLOCATOR(clone) = RCLASS_ALLOCATOR(klass);
rb_iv_tbl_copy(clone, klass);
if (RCLASS_CONST_TBL(klass)) {
struct clone_const_arg arg;
@@ -708,8 +671,8 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
void
rb_singleton_class_attached(VALUE klass, VALUE obj)
{
- if (RCLASS_SINGLETON_P(klass)) {
- RCLASS_SET_ATTACHED_OBJECT(klass, obj);
+ if (FL_TEST(klass, FL_SINGLETON)) {
+ rb_class_ivar_set(klass, id_attached, obj);
}
}
@@ -723,17 +686,17 @@ rb_singleton_class_attached(VALUE klass, VALUE obj)
static int
rb_singleton_class_has_metaclass_p(VALUE sklass)
{
- return RCLASS_ATTACHED_OBJECT(METACLASS_OF(sklass)) == sklass;
+ return rb_attr_get(METACLASS_OF(sklass), id_attached) == sklass;
}
int
rb_singleton_class_internal_p(VALUE sklass)
{
- return (RB_TYPE_P(RCLASS_ATTACHED_OBJECT(sklass), T_CLASS) &&
+ return (RB_TYPE_P(rb_attr_get(sklass, id_attached), T_CLASS) &&
!rb_singleton_class_has_metaclass_p(sklass));
}
-/**
+/*!
* whether k has a metaclass
* @retval 1 if \a k has a metaclass
* @retval 0 otherwise
@@ -742,25 +705,25 @@ rb_singleton_class_internal_p(VALUE sklass)
(FL_TEST(METACLASS_OF(k), FL_SINGLETON) && \
rb_singleton_class_has_metaclass_p(k))
-/**
- * ensures `klass` belongs to its own eigenclass.
- * @return the eigenclass of `klass`
- * @post `klass` belongs to the returned eigenclass.
- * i.e. the attached object of the eigenclass is `klass`.
+/*!
+ * ensures \a klass belongs to its own eigenclass.
+ * @return the eigenclass of \a klass
+ * @post \a klass belongs to the returned eigenclass.
+ * i.e. the attached object of the eigenclass is \a klass.
* @note this macro creates a new eigenclass if necessary.
*/
#define ENSURE_EIGENCLASS(klass) \
(HAVE_METACLASS_P(klass) ? METACLASS_OF(klass) : make_metaclass(klass))
-/**
- * Creates a metaclass of `klass`
- * @param klass a class
- * @return created metaclass for the class
- * @pre `klass` is a Class object
- * @pre `klass` has no singleton class.
- * @post the class of `klass` is the returned class.
- * @post the returned class is meta^(n+1)-class when `klass` is a meta^(n)-klass for n >= 0
+/*!
+ * Creates a metaclass of \a klass
+ * \param klass a class
+ * \return created metaclass for the class
+ * \pre \a klass is a Class object
+ * \pre \a klass has no singleton class.
+ * \post the class of \a klass is the returned class.
+ * \post the returned class is meta^(n+1)-class when \a klass is a meta^(n)-klass for n >= 0
*/
static inline VALUE
make_metaclass(VALUE klass)
@@ -791,11 +754,11 @@ make_metaclass(VALUE klass)
return metaclass;
}
-/**
- * Creates a singleton class for `obj`.
- * @pre `obj` must not be an immediate nor a special const.
- * @pre `obj` must not be a Class object.
- * @pre `obj` has no singleton class.
+/*!
+ * Creates a singleton class for \a obj.
+ * \pre \a obj must not a immediate nor a special const.
+ * \pre \a obj must not a Class object.
+ * \pre \a obj has no singleton class.
*/
static inline VALUE
make_singleton_class(VALUE obj)
@@ -806,7 +769,6 @@ make_singleton_class(VALUE obj)
FL_SET(klass, FL_SINGLETON);
RBASIC_SET_CLASS(obj, klass);
rb_singleton_class_attached(klass, obj);
- rb_yjit_invalidate_no_singleton_class(orig_class);
SET_METACLASS_OF(klass, METACLASS_OF(rb_class_real(orig_class)));
return klass;
@@ -820,7 +782,7 @@ boot_defclass(const char *name, VALUE super)
ID id = rb_intern(name);
rb_const_set((rb_cObject ? rb_cObject : obj), id, obj);
- rb_vm_register_global_object(obj);
+ rb_vm_add_root_module(obj);
return obj;
}
@@ -876,33 +838,12 @@ refinement_import_methods(int argc, VALUE *argv, VALUE refinement)
}
# endif
-/*!
- *--
- * \private
- * Initializes the world of objects and classes.
- *
- * At first, the function bootstraps the class hierarchy.
- * It initializes the most fundamental classes and their metaclasses.
- * - \c BasicObject
- * - \c Object
- * - \c Module
- * - \c Class
- * After the bootstrap step, the class hierarchy becomes as the following
- * diagram.
- *
- * \image html boottime-classes.png
- *
- * Then, the function defines classes, modules and methods as usual.
- * \ingroup class
- *++
- */
-
void
Init_class_hierarchy(void)
{
rb_cBasicObject = boot_defclass("BasicObject", 0);
rb_cObject = boot_defclass("Object", rb_cBasicObject);
- rb_vm_register_global_object(rb_cObject);
+ rb_gc_register_mark_object(rb_cObject);
/* resolve class name ASAP for order-independence */
rb_set_class_path_string(rb_cObject, rb_cObject, rb_fstring_lit("Object"));
@@ -927,15 +868,15 @@ Init_class_hierarchy(void)
}
-/**
- * @internal
+/*!
+ * \internal
* Creates a new *singleton class* for an object.
*
- * @pre `obj` has no singleton class.
- * @note DO NOT USE the function in an extension libraries. Use @ref rb_singleton_class.
- * @param obj An object.
- * @param unused ignored.
- * @return The singleton class of the object.
+ * \pre \a obj has no singleton class.
+ * \note DO NOT USE the function in an extension libraries. Use \ref rb_singleton_class.
+ * \param obj An object.
+ * \param unused ignored.
+ * \return The singleton class of the object.
*/
VALUE
rb_make_metaclass(VALUE obj, VALUE unused)
@@ -961,15 +902,15 @@ rb_define_class_id(ID id, VALUE super)
}
-/**
+/*!
* Calls Class#inherited.
- * @param super A class which will be called #inherited.
+ * \param super A class which will be called #inherited.
* NULL means Object class.
- * @param klass A Class object which derived from `super`
- * @return the value `Class#inherited` returns
- * @pre Each of `super` and `klass` must be a `Class` object.
+ * \param klass A Class object which derived from \a super
+ * \return the value \c Class#inherited's returns
+ * \pre Each of \a super and \a klass must be a \c Class object.
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_class_inherited(VALUE super, VALUE klass)
{
ID inherited;
@@ -996,14 +937,14 @@ rb_define_class(const char *name, VALUE super)
}
/* Class may have been defined in Ruby and not pin-rooted */
- rb_vm_register_global_object(klass);
+ rb_vm_add_root_module(klass);
return klass;
}
if (!super) {
- rb_raise(rb_eArgError, "no super class for '%s'", name);
+ rb_raise(rb_eArgError, "no super class for `%s'", name);
}
klass = rb_define_class_id(id, super);
- rb_vm_register_global_object(klass);
+ rb_vm_add_root_module(klass);
rb_const_set(rb_cObject, id, klass);
rb_class_inherited(super, klass);
@@ -1038,7 +979,7 @@ rb_define_class_id_under_no_pin(VALUE outer, ID id, VALUE super)
return klass;
}
if (!super) {
- rb_raise(rb_eArgError, "no super class for '%"PRIsVALUE"::%"PRIsVALUE"'",
+ rb_raise(rb_eArgError, "no super class for `%"PRIsVALUE"::%"PRIsVALUE"'",
rb_class_path(outer), rb_id2str(id));
}
klass = rb_define_class_id(id, super);
@@ -1053,7 +994,7 @@ VALUE
rb_define_class_id_under(VALUE outer, ID id, VALUE super)
{
VALUE klass = rb_define_class_id_under_no_pin(outer, id, super);
- rb_vm_register_global_object(klass);
+ rb_vm_add_root_module(klass);
return klass;
}
@@ -1107,11 +1048,11 @@ rb_define_module(const char *name)
name, rb_obj_class(module));
}
/* Module may have been defined in Ruby and not pin-rooted */
- rb_vm_register_global_object(module);
+ rb_vm_add_root_module(module);
return module;
}
module = rb_module_new();
- rb_vm_register_global_object(module);
+ rb_vm_add_root_module(module);
rb_const_set(rb_cObject, id, module);
return module;
@@ -1136,13 +1077,13 @@ rb_define_module_id_under(VALUE outer, ID id)
outer, rb_id2str(id), rb_obj_class(module));
}
/* Module may have been defined in Ruby and not pin-rooted */
- rb_vm_register_global_object(module);
+ rb_gc_register_mark_object(module);
return module;
}
module = rb_module_new();
rb_const_set(outer, id, module);
rb_set_class_path_string(module, outer, rb_id2str(id));
- rb_vm_register_global_object(module);
+ rb_gc_register_mark_object(module);
return module;
}
@@ -1152,7 +1093,7 @@ rb_include_class_new(VALUE module, VALUE super)
{
VALUE klass = class_alloc(T_ICLASS, rb_cClass);
- RCLASS_SET_M_TBL(klass, RCLASS_M_TBL(module));
+ RCLASS_M_TBL(klass) = RCLASS_M_TBL(module);
RCLASS_SET_ORIGIN(klass, klass);
if (BUILTIN_TYPE(module) == T_ICLASS) {
@@ -1204,8 +1145,8 @@ rb_include_module(VALUE klass, VALUE module)
iclass = iclass->next;
}
- int do_include = 1;
while (iclass) {
+ int do_include = 1;
VALUE check_class = iclass->klass;
/* During lazy sweeping, iclass->klass could be a dead object that
* has not yet been swept. */
@@ -1424,10 +1365,10 @@ ensure_origin(VALUE klass)
VALUE origin = RCLASS_ORIGIN(klass);
if (origin == klass) {
origin = class_alloc(T_ICLASS, klass);
- RCLASS_SET_M_TBL(origin, RCLASS_M_TBL(klass));
RCLASS_SET_SUPER(origin, RCLASS_SUPER(klass));
RCLASS_SET_SUPER(klass, origin);
RCLASS_SET_ORIGIN(klass, origin);
+ RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
RCLASS_M_TBL_INIT(klass);
rb_id_table_foreach(RCLASS_M_TBL(origin), cache_clear_refined_method, (void *)klass);
rb_id_table_foreach(RCLASS_M_TBL(origin), move_refined_method, (void *)klass);
@@ -1611,7 +1552,7 @@ class_descendants_recursive(VALUE klass, VALUE v)
{
struct subclass_traverse_data *data = (struct subclass_traverse_data *) v;
- if (BUILTIN_TYPE(klass) == T_CLASS && !RCLASS_SINGLETON_P(klass)) {
+ if (BUILTIN_TYPE(klass) == T_CLASS && !FL_TEST(klass, FL_SINGLETON)) {
if (data->buffer && data->count < data->maxcount && !rb_objspace_garbage_object_p(klass)) {
// assumes that this does not cause GC as long as the length does not exceed the capacity
rb_ary_push(data->buffer, klass);
@@ -1716,11 +1657,11 @@ rb_class_subclasses(VALUE klass)
VALUE
rb_class_attached_object(VALUE klass)
{
- if (!RCLASS_SINGLETON_P(klass)) {
- rb_raise(rb_eTypeError, "'%"PRIsVALUE"' is not a singleton class", klass);
+ if (!FL_TEST(klass, FL_SINGLETON)) {
+ rb_raise(rb_eTypeError, "`%"PRIsVALUE"' is not a singleton class", klass);
}
- return RCLASS_ATTACHED_OBJECT(klass);
+ return rb_attr_get(klass, id_attached);
}
static void
@@ -1819,7 +1760,7 @@ static bool
particular_class_p(VALUE mod)
{
if (!mod) return false;
- if (RCLASS_SINGLETON_P(mod)) return true;
+ if (FL_TEST(mod, FL_SINGLETON)) return true;
if (BUILTIN_TYPE(mod) == T_ICLASS) return true;
return false;
}
@@ -2096,19 +2037,19 @@ rb_obj_singleton_methods(int argc, const VALUE *argv, VALUE obj)
int recur = TRUE;
if (rb_check_arity(argc, 0, 1)) recur = RTEST(argv[0]);
- if (RCLASS_SINGLETON_P(obj)) {
+ if (RB_TYPE_P(obj, T_CLASS) && FL_TEST(obj, FL_SINGLETON)) {
rb_singleton_class(obj);
}
klass = CLASS_OF(obj);
origin = RCLASS_ORIGIN(klass);
me_arg.list = st_init_numtable();
me_arg.recur = recur;
- if (klass && RCLASS_SINGLETON_P(klass)) {
+ if (klass && FL_TEST(klass, FL_SINGLETON)) {
if ((mtbl = RCLASS_M_TBL(origin)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg);
klass = RCLASS_SUPER(klass);
}
if (recur) {
- while (klass && (RCLASS_SINGLETON_P(klass) || RB_TYPE_P(klass, T_ICLASS))) {
+ while (klass && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) {
if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg);
klass = RCLASS_SUPER(klass);
}
@@ -2212,13 +2153,13 @@ rb_special_singleton_class(VALUE obj)
return special_singleton_class_of(obj);
}
-/**
- * @internal
- * Returns the singleton class of `obj`. Creates it if necessary.
+/*!
+ * \internal
+ * Returns the singleton class of \a obj. Creates it if necessary.
*
- * @note DO NOT expose the returned singleton class to
+ * \note DO NOT expose the returned singleton class to
* outside of class.c.
- * Use @ref rb_singleton_class instead for
+ * Use \ref rb_singleton_class instead for
* consistency of the metaclass hierarchy.
*/
static VALUE
@@ -2242,17 +2183,14 @@ singleton_class_of(VALUE obj)
return klass;
case T_STRING:
- if (CHILLED_STRING_P(obj)) {
- CHILLED_STRING_MUTATED(obj);
- }
- else if (FL_TEST_RAW(obj, RSTRING_FSTR)) {
+ if (FL_TEST_RAW(obj, RSTRING_FSTR)) {
rb_raise(rb_eTypeError, "can't define singleton");
}
}
klass = METACLASS_OF(obj);
- if (!(RCLASS_SINGLETON_P(klass) &&
- RCLASS_ATTACHED_OBJECT(klass) == obj)) {
+ if (!(FL_TEST(klass, FL_SINGLETON) &&
+ rb_attr_get(klass, id_attached) == obj)) {
klass = rb_make_metaclass(obj, klass);
}
@@ -2265,21 +2203,21 @@ void
rb_freeze_singleton_class(VALUE x)
{
/* should not propagate to meta-meta-class, and so on */
- if (!RCLASS_SINGLETON_P(x)) {
+ if (!(RBASIC(x)->flags & FL_SINGLETON)) {
VALUE klass = RBASIC_CLASS(x);
if (klass && // no class when hidden from ObjectSpace
FL_TEST(klass, (FL_SINGLETON|FL_FREEZE)) == FL_SINGLETON) {
- OBJ_FREEZE(klass);
+ OBJ_FREEZE_RAW(klass);
}
}
}
-/**
- * Returns the singleton class of `obj`, or nil if obj is not a
+/*!
+ * Returns the singleton class of \a obj, or nil if obj is not a
* singleton object.
*
- * @param obj an arbitrary object.
- * @return the singleton class or nil.
+ * \param obj an arbitrary object.
+ * \return the singleton class or nil.
*/
VALUE
rb_singleton_class_get(VALUE obj)
@@ -2290,8 +2228,8 @@ rb_singleton_class_get(VALUE obj)
return rb_special_singleton_class(obj);
}
klass = METACLASS_OF(obj);
- if (!RCLASS_SINGLETON_P(klass)) return Qnil;
- if (RCLASS_ATTACHED_OBJECT(klass) != obj) return Qnil;
+ if (!FL_TEST(klass, FL_SINGLETON)) return Qnil;
+ if (rb_attr_get(klass, id_attached) != obj) return Qnil;
return klass;
}
@@ -2355,7 +2293,7 @@ rb_define_attr(VALUE klass, const char *name, int read, int write)
rb_attr(klass, rb_intern(name), read, write, FALSE);
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_keyword_error_new(const char *error, VALUE keys)
{
long i = 0, len = RARRAY_LEN(keys);
diff --git a/common.mk b/common.mk
index 1d3766a8f4..126053c9c8 100644
--- a/common.mk
+++ b/common.mk
@@ -1,12 +1,10 @@
# -*- mode: makefile-gmake; indent-tabs-mode: t -*-
-# This fragment can be used with nmake.exe and with bsdmake.
-# Avoid features specific to GNU Make.
bin: $(PROGRAM) $(WPROGRAM)
lib: $(LIBRUBY)
dll: $(LIBRUBY_SO)
-.SUFFIXES: .rbinc .rbbin .rb .inc .h .c .y .i .$(ASMEXT) .$(DTRACE_EXT)
+.SUFFIXES: .rbinc .rb .inc .h .c .y .i .$(ASMEXT) .$(DTRACE_EXT)
# V=0 quiet, V=1 verbose. other values don't work.
V = 0
@@ -45,15 +43,20 @@ RUN_OPTS = --disable-gems
# GITPULLOPTIONS = --no-tags
-PRISM_SRCDIR = $(srcdir)/prism
-INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir) -I$(srcdir) -I$(PRISM_SRCDIR) -I$(UNICODE_HDR_DIR) $(incflags)
+INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir) -I$(srcdir) -I$(UNICODE_HDR_DIR) $(incflags)
GEM_HOME =
GEM_PATH =
GEM_VENDOR =
BENCHMARK_DRIVER_GIT_URL = https://github.com/benchmark-driver/benchmark-driver
-BENCHMARK_DRIVER_GIT_REF = v0.16.3
+BENCHMARK_DRIVER_GIT_REF = v0.16.0
+SIMPLECOV_GIT_URL = https://github.com/colszowka/simplecov.git
+SIMPLECOV_GIT_REF = v0.17.0
+SIMPLECOV_HTML_GIT_URL = https://github.com/colszowka/simplecov-html.git
+SIMPLECOV_HTML_GIT_REF = v0.10.2
+DOCLIE_GIT_URL = https://github.com/ms-ati/docile.git
+DOCLIE_GIT_REF = v1.3.2
STATIC_RUBY = static-ruby
@@ -64,53 +67,25 @@ LIBRUBY_EXTS = ./.libruby-with-ext.time
REVISION_H = ./.revision.time
PLATFORM_D = $(TIMESTAMPDIR)/.$(PLATFORM_DIR).time
ENC_TRANS_D = $(TIMESTAMPDIR)/.enc-trans.time
-RDOC = $(XRUBY) "$(tooldir)/rdoc-srcdir"
+RDOC = $(XRUBY) "$(srcdir)/libexec/rdoc" --root "$(srcdir)" --encoding=UTF-8 --all
RDOCOUT = $(EXTOUT)/rdoc
HTMLOUT = $(EXTOUT)/html
CAPIOUT = doc/capi
INSTALL_DOC_OPTS = --rdoc-output="$(RDOCOUT)" --html-output="$(HTMLOUT)"
-RDOC_GEN_OPTS = --no-force-update \
+RDOC_GEN_OPTS = --page-dir "$(srcdir)/doc" --no-force-update \
--title "Documentation for Ruby $(RUBY_API_VERSION)" \
- $(empty)
+ --main README.md
INITOBJS = dmyext.$(OBJEXT) dmyenc.$(OBJEXT)
NORMALMAINOBJ = main.$(OBJEXT)
MAINOBJ = $(NORMALMAINOBJ)
DLDOBJS = $(INITOBJS)
EXTSOLIBS =
-MINIOBJS = $(ARCHMINIOBJS) miniinit.$(OBJEXT)
+MINIOBJS = $(ARCHMINIOBJS) miniinit.$(OBJEXT) dmyext.$(OBJEXT)
ENC_MK = enc.mk
MAKE_ENC = -f $(ENC_MK) V="$(V)" UNICODE_HDR_DIR="$(UNICODE_HDR_DIR)" \
RUBY="$(BOOTSTRAPRUBY)" MINIRUBY="$(BOOTSTRAPRUBY)" $(mflags)
-PRISM_BUILD_DIR = prism
-
-PRISM_FILES = prism/api_node.$(OBJEXT) \
- prism/api_pack.$(OBJEXT) \
- prism/diagnostic.$(OBJEXT) \
- prism/encoding.$(OBJEXT) \
- prism/extension.$(OBJEXT) \
- prism/node.$(OBJEXT) \
- prism/options.$(OBJEXT) \
- prism/pack.$(OBJEXT) \
- prism/prettyprint.$(OBJEXT) \
- prism/regexp.$(OBJEXT) \
- prism/serialize.$(OBJEXT) \
- prism/static_literals.$(OBJEXT) \
- prism/token_type.$(OBJEXT) \
- prism/util/pm_buffer.$(OBJEXT) \
- prism/util/pm_char.$(OBJEXT) \
- prism/util/pm_constant_pool.$(OBJEXT) \
- prism/util/pm_integer.$(OBJEXT) \
- prism/util/pm_list.$(OBJEXT) \
- prism/util/pm_memchr.$(OBJEXT) \
- prism/util/pm_newline_list.$(OBJEXT) \
- prism/util/pm_string.$(OBJEXT) \
- prism/util/pm_strncasecmp.$(OBJEXT) \
- prism/util/pm_strpbrk.$(OBJEXT) \
- prism/prism.$(OBJEXT) \
- prism_init.$(OBJEXT)
-
COMMONOBJS = array.$(OBJEXT) \
ast.$(OBJEXT) \
bignum.$(OBJEXT) \
@@ -132,7 +107,6 @@ COMMONOBJS = array.$(OBJEXT) \
gc.$(OBJEXT) \
hash.$(OBJEXT) \
inits.$(OBJEXT) \
- imemo.$(OBJEXT) \
io.$(OBJEXT) \
io_buffer.$(OBJEXT) \
iseq.$(OBJEXT) \
@@ -140,15 +114,13 @@ COMMONOBJS = array.$(OBJEXT) \
marshal.$(OBJEXT) \
math.$(OBJEXT) \
memory_view.$(OBJEXT) \
- rjit.$(OBJEXT) \
- rjit_c.$(OBJEXT) \
+ mjit.$(OBJEXT) \
+ mjit_c.$(OBJEXT) \
node.$(OBJEXT) \
- node_dump.$(OBJEXT) \
numeric.$(OBJEXT) \
object.$(OBJEXT) \
pack.$(OBJEXT) \
parse.$(OBJEXT) \
- parser_st.$(OBJEXT) \
proc.$(OBJEXT) \
process.$(OBJEXT) \
ractor.$(OBJEXT) \
@@ -163,7 +135,6 @@ COMMONOBJS = array.$(OBJEXT) \
regparse.$(OBJEXT) \
regsyntax.$(OBJEXT) \
ruby.$(OBJEXT) \
- ruby_parser.$(OBJEXT) \
scheduler.$(OBJEXT) \
shape.$(OBJEXT) \
signal.$(OBJEXT) \
@@ -176,6 +147,7 @@ COMMONOBJS = array.$(OBJEXT) \
thread.$(OBJEXT) \
time.$(OBJEXT) \
transcode.$(OBJEXT) \
+ transient_heap.$(OBJEXT) \
util.$(OBJEXT) \
variable.$(OBJEXT) \
version.$(OBJEXT) \
@@ -184,106 +156,20 @@ COMMONOBJS = array.$(OBJEXT) \
vm_dump.$(OBJEXT) \
vm_sync.$(OBJEXT) \
vm_trace.$(OBJEXT) \
- weakmap.$(OBJEXT) \
- $(PRISM_FILES) \
$(YJIT_OBJ) \
- $(YJIT_LIBOBJ) \
$(COROUTINE_OBJ) \
$(DTRACE_OBJ) \
$(BUILTIN_ENCOBJS) \
$(BUILTIN_TRANSOBJS) \
$(MISSING)
-$(PRISM_FILES): $(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/util/.time
-
-$(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/util/.time:
- $(Q) $(MAKEDIRS) $(@D)
- @$(NULLCMD) > $@
-
-main: $(srcdir)/lib/prism/compiler.rb
-srcs: $(srcdir)/lib/prism/compiler.rb
-$(srcdir)/lib/prism/compiler.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/compiler.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/compiler.rb $(srcdir)/lib/prism/compiler.rb
-
-main: $(srcdir)/lib/prism/dispatcher.rb
-srcs: $(srcdir)/lib/prism/dispatcher.rb
-$(srcdir)/lib/prism/dispatcher.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/dispatcher.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/dispatcher.rb $(srcdir)/lib/prism/dispatcher.rb
-
-main: $(srcdir)/lib/prism/dsl.rb
-srcs: $(srcdir)/lib/prism/dsl.rb
-$(srcdir)/lib/prism/dsl.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/dsl.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/dsl.rb $(srcdir)/lib/prism/dsl.rb
-
-main: $(srcdir)/lib/prism/inspect_visitor.rb
-srcs: $(srcdir)/lib/prism/inspect_visitor.rb
-$(srcdir)/lib/prism/inspect_visitor.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/inspect_visitor.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/inspect_visitor.rb $(srcdir)/lib/prism/inspect_visitor.rb
-
-main: $(srcdir)/lib/prism/mutation_compiler.rb
-srcs: $(srcdir)/lib/prism/mutation_compiler.rb
-$(srcdir)/lib/prism/mutation_compiler.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/mutation_compiler.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/mutation_compiler.rb $(srcdir)/lib/prism/mutation_compiler.rb
-
-main: $(srcdir)/lib/prism/node.rb
-srcs: $(srcdir)/lib/prism/node.rb
-$(srcdir)/lib/prism/node.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/node.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/node.rb $(srcdir)/lib/prism/node.rb
-
-main: $(srcdir)/lib/prism/reflection.rb
-srcs: $(srcdir)/lib/prism/reflection.rb
-$(srcdir)/lib/prism/reflection.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/reflection.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/reflection.rb $(srcdir)/lib/prism/reflection.rb
-
-main: $(srcdir)/lib/prism/serialize.rb
-srcs: $(srcdir)/lib/prism/serialize.rb
-$(srcdir)/lib/prism/serialize.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/serialize.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/serialize.rb $(srcdir)/lib/prism/serialize.rb
-
-main: $(srcdir)/lib/prism/visitor.rb
-srcs: $(srcdir)/lib/prism/visitor.rb
-$(srcdir)/lib/prism/visitor.rb: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/lib/prism/visitor.rb.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb lib/prism/visitor.rb $(srcdir)/lib/prism/visitor.rb
-
-srcs: prism/api_node.c
-prism/api_node.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/ext/prism/api_node.c.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb ext/prism/api_node.c $@
-
-srcs: prism/ast.h
-prism/ast.h: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/include/prism/ast.h.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb include/prism/ast.h $@
-
-srcs: prism/diagnostic.c
-prism/diagnostic.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/diagnostic.c.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/diagnostic.c $@
-
-srcs: prism/diagnostic.h
-prism/diagnostic.h: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/include/prism/diagnostic.h.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb include/prism/diagnostic.h $@
-
-srcs: prism/node.c
-prism/node.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/node.c.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/node.c $@
-
-srcs: prism/prettyprint.c
-prism/prettyprint.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/prettyprint.c.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/prettyprint.c $@
-
-srcs: prism/serialize.c
-prism/serialize.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/serialize.c.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/serialize.c $@
-
-srcs: prism/token_type.c
-prism/token_type.c: $(PRISM_SRCDIR)/config.yml $(PRISM_SRCDIR)/templates/template.rb $(PRISM_SRCDIR)/templates/src/token_type.c.erb
- $(Q) $(BASERUBY) $(PRISM_SRCDIR)/templates/template.rb src/token_type.c $@
-
EXPORTOBJS = $(DLNOBJ) \
localeinit.$(OBJEXT) \
loadpath.$(OBJEXT) \
$(COMMONOBJS)
OBJS = $(EXPORTOBJS) builtin.$(OBJEXT)
-ALLOBJS = $(OBJS) $(MINIOBJS) $(INITOBJS) $(MAINOBJ)
+ALLOBJS = $(NORMALMAINOBJ) $(MINIOBJS) $(COMMONOBJS) $(INITOBJS)
GOLFOBJS = goruby.$(OBJEXT)
@@ -291,7 +177,7 @@ DEFAULT_PRELUDES = $(GEM_PRELUDE)
PRELUDE_SCRIPTS = $(DEFAULT_PRELUDES)
GEM_PRELUDE =
PRELUDES = {$(srcdir)}miniprelude.c
-GOLFPRELUDES = golf_prelude.rbbin
+GOLFPRELUDES = {$(srcdir)}golf_prelude.c
SCRIPT_ARGS = --dest-dir="$(DESTDIR)" \
--extout="$(EXTOUT)" \
@@ -315,7 +201,7 @@ INSTALL_DATA_MODE = 0644
BOOTSTRAPRUBY_COMMAND = $(BOOTSTRAPRUBY) $(BOOTSTRAPRUBY_OPT)
TESTSDIR = $(srcdir)/test
TOOL_TESTSDIR = $(tooldir)/test
-TEST_EXCLUDES = --excludes-dir=$(TESTSDIR)/.excludes --name=!/memory_leak/
+TEST_EXCLUDES = --excludes-dir=$(TESTSDIR)/excludes --name=!/memory_leak/
TESTWORKDIR = testwork
TESTOPTS = $(RUBY_TESTOPTS)
@@ -339,26 +225,55 @@ YJIT_RUSTC_ARGS = --crate-name=yjit \
--crate-type=staticlib \
--edition=2021 \
-g \
- -C lto=thin \
-C opt-level=3 \
-C overflow-checks=on \
'--out-dir=$(CARGO_TARGET_DIR)/release/' \
$(top_srcdir)/yjit/src/lib.rs
-all: $(SHOWFLAGS) main
+all: $(SHOWFLAGS) main docs
main: $(SHOWFLAGS) exts $(ENCSTATIC:static=lib)encs
@$(NULLCMD)
-main: $(srcdir)/lib/ruby_vm/rjit/instruction.rb
-srcs: $(srcdir)/lib/ruby_vm/rjit/instruction.rb
-$(srcdir)/lib/ruby_vm/rjit/instruction.rb: $(tooldir)/insns2vm.rb $(tooldir)/ruby_vm/views/lib/ruby_vm/rjit/instruction.rb.erb $(srcdir)/insns.def
+main: $(srcdir)/lib/ruby_vm/mjit/instruction.rb
+srcs: $(srcdir)/lib/ruby_vm/mjit/instruction.rb
+$(srcdir)/lib/ruby_vm/mjit/instruction.rb: $(tooldir)/insns2vm.rb $(tooldir)/ruby_vm/views/lib/ruby_vm/mjit/instruction.rb.erb $(srcdir)/insns.def
$(ECHO) generating $@
$(Q) $(BASERUBY) -Ku $(tooldir)/insns2vm.rb --basedir="$(srcdir)" $(INSNS2VMOPT) $@
-.PHONY: rjit-bindgen
-rjit-bindgen:
- $(Q) $(BASERUBY) -rrubygems -C $(srcdir)/tool/rjit bindgen.rb $(CURDIR)
+mjit-headers: $(MJIT_SUPPORT)-mjit-headers
+no-mjit-headers: PHONY
+yes-mjit-headers: mjit_config.h PHONY
+
+mjit.$(OBJEXT): mjit_config.h
+mjit_config.h: Makefile
+
+.PHONY: mjit-bindgen
+mjit-bindgen:
+ $(Q) $(BASERUBY) -rrubygems -C $(srcdir)/tool/mjit bindgen.rb $(CURDIR)
+
+# These rules using MJIT_HEADER_SUFFIX must be in common.mk, not
+# Makefile.in, in order to override the macro in defs/universal.mk.
+
+# Other `-Dxxx`s preceding `-DMJIT_HEADER` will be removed in transform_mjit_header.rb.
+# So `-DMJIT_HEADER` should be passed first when rb_mjit_header.h is generated.
+$(TIMESTAMPDIR)/$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).time: probes.h vm.$(OBJEXT) \
+ $(TIMESTAMPDIR)/$(arch)/.time $(tooldir)/mjit_tabs.rb $(PREP) $(RBCONFIG)
+ $(ECHO) building $(@F:.time=.h)
+ $(Q)$(MINIRUBY) $(tooldir)/mjit_tabs.rb "$(MJIT_TABS)" \
+ $(CPP) -DMJIT_HEADER $(MJIT_HEADER_FLAGS) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(srcdir)/vm.c $(CPPOUTFLAG)$(@F:.time=.h).new
+ $(Q) $(IFCHANGE) "--timestamp=$@" $(@F:.time=.h) $(@F:.time=.h).new
+
+$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).h: $(TIMESTAMPDIR)/$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).time
+
+$(MJIT_MIN_HEADER:.h=)$(MJIT_HEADER_SUFFIX).h: \
+ $(TIMESTAMPDIR)/$(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).time \
+ $(tooldir)/transform_mjit_header.rb $(PREP) \
+ $(MJIT_HEADER:.h=)$(MJIT_HEADER_SUFFIX).h
+ $(ECHO) building $@
+ $(Q)$(MINIRUBY) $(tooldir)/transform_mjit_header.rb "$(CC) $(CFLAGS) -w" $(MJIT_HEADER:.h=)$(MJIT_HEADER_ARCH).h $@
+ $(Q) $(MAKEDIRS) $(MJIT_HEADER_INSTALL_DIR)
+ $(Q) $(MAKE_LINK) $@ $(MJIT_HEADER_INSTALL_DIR)/$(@F)
.PHONY: showflags
exts enc trans: $(SHOWFLAGS)
@@ -414,8 +329,7 @@ configure-ext: $(EXTS_MK)
build-ext: $(EXTS_MK)
$(Q)$(MAKE) -f $(EXTS_MK) $(mflags) libdir="$(libdir)" LIBRUBY_EXTS=$(LIBRUBY_EXTS) \
- EXTENCS="$(ENCOBJS)" BASERUBY="$(BASERUBY)" MINIRUBY="$(MINIRUBY)" \
- $(EXTSTATIC)
+ EXTENCS="$(ENCOBJS)" MINIRUBY="$(MINIRUBY)" UPDATE_LIBRARIES=no $(EXTSTATIC)
$(Q)$(MAKE) $(EXTS_NOTE)
exts-note: $(EXTS_MK)
@@ -431,7 +345,7 @@ programs: $(PROGRAM) $(WPROGRAM) $(arch)-fake.rb
$(PREP): $(MKFILES)
-miniruby$(EXEEXT): config.status $(NORMALMAINOBJ) $(MINIOBJS) $(COMMONOBJS) $(ARCHFILE)
+miniruby$(EXEEXT): config.status $(ALLOBJS) $(ARCHFILE)
objs: $(ALLOBJS)
@@ -458,8 +372,8 @@ Doxyfile: $(srcdir)/template/Doxyfile.tmpl $(PREP) $(tooldir)/generic_erb.rb $(R
$(Q) $(MINIRUBY) $(tooldir)/generic_erb.rb -o $@ $(srcdir)/template/Doxyfile.tmpl \
--srcdir="$(srcdir)" --miniruby="$(MINIRUBY)"
-program: $(SHOWFLAGS) $(DOT_WAIT) $(PROGRAM)
-wprogram: $(SHOWFLAGS) $(DOT_WAIT) $(WPROGRAM)
+program: $(SHOWFLAGS) $(PROGRAM)
+wprogram: $(SHOWFLAGS) $(WPROGRAM)
mini: PHONY miniruby$(EXEEXT)
$(PROGRAM) $(WPROGRAM): $(LIBRUBY) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(SETUP) $(PREP)
@@ -479,17 +393,19 @@ ruby.imp: $(COMMONOBJS)
$(Q){ \
$(NM) -Pgp $(COMMONOBJS) | \
awk 'BEGIN{print "#!"}; $$2~/^[A-TV-Z]$$/&&$$1!~/^$(SYMBOL_PREFIX)(Init_|InitVM_|ruby_static_id_|.*_threadptr_|rb_ec_)|^\./{print $$1}'; \
+ ($(CHDIR) $(srcdir) && \
+ exec sed -n '/^MJIT_FUNC_EXPORTED/!d;N;s/.*\n\(rb_[a-zA-Z_0-9]*\).*/$(SYMBOL_PREFIX)\1/p' cont.c gc.c thread*c vm*.c) \
} | \
sort -u -o $@
install: install-$(INSTALLDOC)
-docs: srcs-doc $(DOCTARGETS)
+docs: $(DOCTARGETS)
pkgconfig-data: $(ruby_pc)
$(ruby_pc): $(srcdir)/template/ruby.pc.in config.status
-install-all: pre-install-all do-install-all post-install-all
+install-all: docs pre-install-all do-install-all post-install-all
pre-install-all:: all pre-install-local pre-install-ext pre-install-gem pre-install-doc
-do-install-all: pre-install-all $(DOT_WAIT) docs
+do-install-all: pre-install-all
$(INSTRUBY) --make="$(MAKE)" $(INSTRUBY_ARGS) --install=all $(INSTALL_DOC_OPTS)
post-install-all:: post-install-local post-install-ext post-install-gem post-install-doc
@$(NULLCMD)
@@ -677,24 +593,18 @@ do-install-dbg: $(PROGRAM) pre-install-dbg
post-install-dbg::
@$(NULLCMD)
-rdoc: PHONY main srcs-doc
+rdoc: PHONY main
@echo Generating RDoc documentation
- $(Q) $(RDOC) --ri --op "$(RDOCOUT)" $(RDOC_GEN_OPTS) $(RDOCFLAGS) .
+ $(Q) $(RDOC) --ri --op "$(RDOCOUT)" $(RDOC_GEN_OPTS) $(RDOCFLAGS) "$(srcdir)"
-html: PHONY main srcs-doc
+html: PHONY main
@echo Generating RDoc HTML files
- $(Q) $(RDOC) --op "$(HTMLOUT)" $(RDOC_GEN_OPTS) $(RDOCFLAGS) .
+ $(Q) $(RDOC) --op "$(HTMLOUT)" $(RDOC_GEN_OPTS) $(RDOCFLAGS) "$(srcdir)"
-rdoc-coverage: PHONY main srcs-doc
+rdoc-coverage: PHONY main
@echo Generating RDoc coverage report
$(Q) $(RDOC) --quiet -C $(RDOCFLAGS) "$(srcdir)"
-undocumented: PHONY main srcs-doc
- $(Q) $(RDOC) --quiet -C $(RDOCFLAGS) "$(srcdir)" | \
- sed -n \
- -e '/^ *# in file /{' -e 's///;N;s/\n/: /p' -e '}' \
- -e 's/^ *\(.*[^ ]\) *# in file \(.*\)/\2: \1/p'
-
RDOCBENCHOUT=/tmp/rdocbench
GCBENCH_ITEM=null
@@ -724,25 +634,20 @@ clear-installed-list: PHONY
clean: clean-ext clean-enc clean-golf clean-docs clean-extout clean-local clean-platform clean-spec
clean-local:: clean-runnable
- $(Q)$(RM) $(ALLOBJS) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES)
+ $(Q)$(RM) $(OBJS) $(MINIOBJS) $(INITOBJS) $(MAINOBJ) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES)
$(Q)$(RM) $(PROGRAM) $(WPROGRAM) miniruby$(EXEEXT) dmyext.$(OBJEXT) dmyenc.$(OBJEXT) $(ARCHFILE) .*.time
$(Q)$(RM) y.tab.c y.output encdb.h transdb.h config.log rbconfig.rb $(ruby_pc) $(COROUTINE_H:/Context.h=/.time)
$(Q)$(RM) probes.h probes.$(OBJEXT) probes.stamp ruby-glommed.$(OBJEXT) ruby.imp ChangeLog $(STATIC_RUBY)$(EXEEXT)
$(Q)$(RM) GNUmakefile.old Makefile.old $(arch)-fake.rb bisect.sh $(ENC_TRANS_D) builtin_binary.inc
- $(Q)$(RM) $(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/*/.time yjit_exit_locations.dump
-$(Q)$(RMALL) yjit/target
- -$(Q) $(RMDIR) enc/jis enc/trans enc $(COROUTINE_H:/Context.h=) coroutine yjit \
- $(PRISM_BUILD_DIR)/*/ $(PRISM_BUILD_DIR) tmp \
- 2> $(NULL) || $(NULLCMD)
+ -$(Q) $(RMDIR) enc/jis enc/trans enc $(COROUTINE_H:/Context.h=) coroutine yjit 2> $(NULL) || $(NULLCMD)
bin/clean-runnable:: PHONY
$(Q)$(CHDIR) bin 2>$(NULL) && $(RM) $(PROGRAM) $(WPROGRAM) $(GORUBY)$(EXEEXT) bin/*.$(DLEXT) 2>$(NULL) || $(NULLCMD)
lib/clean-runnable:: PHONY
- $(Q)$(CHDIR) lib 2>$(NULL) && $(RM) $(LIBRUBY_A) $(LIBRUBY) $(LIBRUBY_ALIASES) $(RUBY_BASE_NAME)/$(ruby_version) $(RUBY_BASE_NAME)/vendor_ruby 2>$(NULL) || $(NULLCMD)
+ $(Q)$(CHDIR) lib 2>$(NULL) && $(RM) $(LIBRUBY_A) $(LIBRUBY) $(LIBRUBY_ALIASES) $(RUBY_BASE_NAME)/$(RUBY_PROGRAM_VERSION) $(RUBY_BASE_NAME)/vendor_ruby 2>$(NULL) || $(NULLCMD)
clean-runnable:: bin/clean-runnable lib/clean-runnable PHONY
$(Q)$(RMDIR) lib/$(RUBY_BASE_NAME) lib bin 2>$(NULL) || $(NULLCMD)
- -$(Q)$(RM) $(EXTOUT)/$(arch)/rbconfig.rb $(EXTOUT)/common/$(arch)
- -$(Q)$(RMALL) exe/
clean-ext:: PHONY
clean-golf: PHONY
$(Q)$(RM) $(GORUBY)$(EXEEXT) $(GOLFOBJS)
@@ -758,7 +663,7 @@ clean-rubyspec: clean-spec
distclean: distclean-ext distclean-enc distclean-golf distclean-docs distclean-extout distclean-local distclean-platform distclean-spec
distclean-local:: clean-local
- $(Q)$(RM) $(MKFILES) yasmdata.rb *.inc $(PRELUDES) *.rbinc *.rbbin
+ $(Q)$(RM) $(MKFILES) yasmdata.rb *.inc $(PRELUDES) *.rbinc
$(Q)$(RM) config.cache config.status config.status.lineno
$(Q)$(RM) *~ *.bak *.stackdump core *.core gmon.out $(PREP)
-$(Q)$(RMALL) $(srcdir)/autom4te.cache
@@ -783,6 +688,8 @@ clean-srcs-local::
$(Q)$(RM) parse.c parse.h lex.c enc/trans/newline.c revision.h
$(Q)$(RM) id.c id.h probes.dmyh probes.h
$(Q)$(RM) encdb.h transdb.h verconf.h ruby-runner.h
+ $(Q)$(RM) mjit_config.h rb_mjit_header.h
+ $(Q)$(RM) $(MJIT_MIN_HEADER) $(MJIT_MIN_HEADER:.h=)$(MJIT_HEADER_SUFFIX:%=*).h
realclean-srcs-local:: clean-srcs-local
$(Q)$(CHDIR) $(srcdir) && $(RM) \
@@ -877,7 +784,7 @@ $(HAVE_BASERUBY:no=)$(arch)-fake.rb: miniruby$(EXEEXT)
# actually depending on other headers more.
$(arch:noarch=ignore)-fake.rb: $(top_srcdir)/revision.h $(top_srcdir)/version.h $(srcdir)/version.c
-$(arch:noarch=ignore)-fake.rb: {$(VPATH)}id.h {$(VPATH)}vm_opts.h $(REVISION_H)
+$(arch:noarch=ignore)-fake.rb: {$(VPATH)}id.h {$(VPATH)}vm_opts.h
$(arch:noarch=ignore)-fake.rb: $(srcdir)/template/fake.rb.in $(tooldir)/generic_erb.rb
$(ECHO) generating $@
@@ -889,7 +796,6 @@ $(arch:noarch=ignore)-fake.rb: $(srcdir)/template/fake.rb.in $(tooldir)/generic_
noarch-fake.rb: # prerequisite of yes-fake
$(Q) exit > $@
-# runner: BASERUBY, target: miniruby
btest: $(TEST_RUNNABLE)-btest
no-btest: PHONY
yes-btest: yes-fake miniruby$(EXEEXT) PHONY
@@ -897,7 +803,6 @@ yes-btest: yes-fake miniruby$(EXEEXT) PHONY
$(Q)$(gnumake_recursive)$(exec) $(BOOTSTRAPRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(BTESTRUBY) $(RUN_OPTS)" $(OPTS) $(TESTOPTS) $(BTESTS)
$(ACTIONS_ENDGROUP)
-# runner: ruby, target: ruby
btest-ruby: $(TEST_RUNNABLE)-btest-ruby
no-btest-ruby: PHONY
yes-btest-ruby: prog PHONY
@@ -905,12 +810,6 @@ yes-btest-ruby: prog PHONY
$(Q)$(gnumake_recursive)$(exec) $(RUNRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(PROGRAM) -I$(srcdir)/lib $(RUN_OPTS)" $(OPTS) $(TESTOPTS) $(BTESTS)
$(ACTIONS_ENDGROUP)
-# runner: BASERUBY, target: ruby
-btest-bruby: prog PHONY
- $(ACTIONS_GROUP)
- $(Q)$(gnumake_recursive)$(exec) $(BOOTSTRAPRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(PROGRAM) -I$(srcdir)/lib $(RUN_OPTS)" $(OPTS) $(TESTOPTS) $(BTESTS)
- $(ACTIONS_ENDGROUP)
-
rtest: yes-fake miniruby$(EXEEXT) PHONY
$(ACTIONS_GROUP)
$(Q)$(exec) $(BOOTSTRAPRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(BTESTRUBY) $(RUN_OPTS)" --sets=ractor -v
@@ -949,28 +848,16 @@ test-sample: test-basic # backward compatibility for mswin-build
test-short: btest-ruby $(DOT_WAIT) test-knownbug $(DOT_WAIT) test-basic
test: test-short
-# Separate to skip updating encs and exts by `make -o test-precheck`
-# for GNU make.
-test-precheck: $(ENCSTATIC:static=lib)encs exts PHONY $(DOT_WAIT)
-yes-test-all-precheck: programs $(DOT_WAIT) test-precheck
-
-PRECHECK_TEST_ALL = yes-test-all-precheck
-
# $ make test-all TESTOPTS="--help" displays more detail
# for example, make test-all TESTOPTS="-j2 -v -n test-name -- test-file-name"
test-all: $(TEST_RUNNABLE)-test-all
-yes-test-all: $(PRECHECK_TEST_ALL)
+yes-test-all: programs PHONY
$(ACTIONS_GROUP)
- $(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) -r$(tooldir)/lib/_tmpdir \
- "$(TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" \
- $(TEST_EXCLUDES) $(TESTOPTS) $(TESTS)
+ $(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) "$(TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" $(TEST_EXCLUDES) $(TESTOPTS) $(TESTS)
$(ACTIONS_ENDGROUP)
TESTS_BUILD = mkmf
no-test-all: PHONY
- $(ACTIONS_GROUP)
- $(gnumake_recursive)$(MINIRUBY) -I"$(srcdir)/lib" -r$(tooldir)/lib/_tmpdir \
- "$(TESTSDIR)/runner.rb" $(TESTOPTS) $(TESTS_BUILD)
- $(ACTIONS_ENDGROUP)
+ $(gnumake_recursive)$(MINIRUBY) -I"$(srcdir)/lib" "$(TESTSDIR)/runner.rb" $(TESTOPTS) $(TESTS_BUILD)
test-almost: test-all
yes-test-almost: yes-test-all
@@ -1006,14 +893,13 @@ $(RBCONFIG): $(tooldir)/mkconfig.rb config.status $(srcdir)/version.h $(srcdir)/
test-rubyspec: test-spec
yes-test-rubyspec: yes-test-spec
-yes-test-spec-precheck: yes-test-all-precheck yes-fake
+test-spec-precheck: programs yes-fake
test-spec: $(TEST_RUNNABLE)-test-spec
-yes-test-spec: yes-test-spec-precheck
+yes-test-spec: test-spec-precheck
$(ACTIONS_GROUP)
$(gnumake_recursive)$(Q) \
- $(RUNRUBY) -r./$(arch)-fake -r$(tooldir)/lib/_tmpdir \
- $(srcdir)/spec/mspec/bin/mspec run -B $(srcdir)/spec/default.mspec $(MSPECOPT) $(SPECOPTS)
+ $(RUNRUBY) -r./$(arch)-fake $(srcdir)/spec/mspec/bin/mspec run -B $(srcdir)/spec/default.mspec $(MSPECOPT) $(SPECOPTS)
$(ACTIONS_ENDGROUP)
no-test-spec:
@@ -1057,19 +943,23 @@ $(ENC_MK): $(srcdir)/enc/make_encmake.rb $(srcdir)/enc/Makefile.in $(srcdir)/enc
PHONY:
-{$(VPATH)}parse.c: {$(VPATH)}parse.y {$(VPATH)}id.h
+{$(VPATH)}parse.c: {$(VPATH)}parse.y $(tooldir)/ytab.sed {$(VPATH)}id.h
{$(VPATH)}parse.h: {$(VPATH)}parse.c
{$(srcdir)}.y.c:
$(ECHO) generating $@
- $(Q)$(BASERUBY) $(tooldir)/id2token.rb $(SRC_FILE) | \
- $(YACC) $(YFLAGS) -o$@ -H$*.h - parse.y
+ $(Q)$(BASERUBY) $(tooldir)/id2token.rb $(SRC_FILE) > parse.tmp.y
+ $(Q)$(YACC) -d $(YFLAGS) -o y.tab.c parse.tmp.y
+ $(Q)$(RM) parse.tmp.y
+ $(Q)sed -f $(tooldir)/ytab.sed -e "/^#/s|parse\.tmp\.[iy]|$(SRC_FILE)|" -e "/^#/s!y\.tab\.c!$@!" y.tab.c > $@.new
+ $(Q)$(MV) $@.new $@
+ $(Q)sed -e "/^#line.*y\.tab\.h/d;/^#line.*parse.*\.y/d" y.tab.h > $(@:.c=.h)
+ $(Q)$(RM) y.tab.c y.tab.h
$(PLATFORM_D):
$(Q) $(MAKEDIRS) $(PLATFORM_DIR) $(@D)
@$(NULLCMD) > $@
-exe/$(PROGRAM): $(TIMESTAMPDIR)/$(arch)/.time
exe/$(PROGRAM): ruby-runner.c ruby-runner.h exe/.time $(PREP) {$(VPATH)}config.h
$(Q) $(CC) $(CFLAGS) $(INCFLAGS) $(CPPFLAGS) -DRUBY_INSTALL_NAME=$(@F) $(COUTFLAG)ruby-runner.$(OBJEXT) -c $(CSRCFLAG)$(srcdir)/ruby-runner.c
$(Q) $(PURIFY) $(CC) $(CFLAGS) $(LDFLAGS) $(OUTFLAG)$@ ruby-runner.$(OBJEXT) $(LIBS)
@@ -1082,8 +972,6 @@ exe/$(PROGRAM): ruby-runner.c ruby-runner.h exe/.time $(PREP) {$(VPATH)}config.h
-e ' File.symlink(prog, dest)' \
-e 'end' \
$(@F) $(@D) $(RUBY_INSTALL_NAME)$(EXEEXT)
- $(Q) $(BOOTSTRAPRUBY) -r$(srcdir)/lib/fileutils \
- -e 'FileUtils::Verbose.ln_sr(*ARGV, force: true)' rbconfig.rb $(EXTOUT)/$(arch)
exe/.time:
$(Q) $(MAKEDIRS) $(@D)
@@ -1151,7 +1039,7 @@ parse.$(OBJEXT): {$(VPATH)}parse.c
miniprelude.$(OBJEXT): {$(VPATH)}miniprelude.c
# dependencies for optional sources.
-compile.$(OBJEXT): {$(VPATH)}optunifs.inc
+compile.$(OBJEXT): {$(VPATH)}opt_sc.inc {$(VPATH)}optunifs.inc
win32/win32.$(OBJEXT): {$(VPATH)}win32/win32.c {$(VPATH)}win32/file.h \
{$(VPATH)}dln.h {$(VPATH)}dln_find.c {$(VPATH)}encindex.h \
@@ -1178,6 +1066,7 @@ INSNS2VMOPT = --srcdir="$(srcdir)"
srcs_vpath = {$(VPATH)}
inc_common_headers = $(tooldir)/ruby_vm/views/_copyright.erb $(tooldir)/ruby_vm/views/_notice.erb
+$(srcs_vpath)opt_sc.inc: $(tooldir)/ruby_vm/views/opt_sc.inc.erb $(inc_common_headers)
$(srcs_vpath)optinsn.inc: $(tooldir)/ruby_vm/views/optinsn.inc.erb $(inc_common_headers)
$(srcs_vpath)optunifs.inc: $(tooldir)/ruby_vm/views/optunifs.inc.erb $(inc_common_headers)
$(srcs_vpath)insns.inc: $(tooldir)/ruby_vm/views/insns.inc.erb $(inc_common_headers)
@@ -1189,6 +1078,7 @@ $(srcs_vpath)insns_info.inc: $(tooldir)/ruby_vm/views/insns_info.inc.erb $(inc_c
$(srcs_vpath)vmtc.inc: $(tooldir)/ruby_vm/views/vmtc.inc.erb $(inc_common_headers)
$(srcs_vpath)vm.inc: $(tooldir)/ruby_vm/views/vm.inc.erb $(inc_common_headers) \
$(tooldir)/ruby_vm/views/_insn_entry.erb $(tooldir)/ruby_vm/views/_trace_instruction.erb
+$(srcs_vpath)mjit_sp_inc.inc: $(tooldir)/ruby_vm/views/mjit_sp_inc.inc.erb
BUILTIN_RB_SRCS = \
$(srcdir)/ast.rb \
@@ -1197,13 +1087,12 @@ BUILTIN_RB_SRCS = \
$(srcdir)/numeric.rb \
$(srcdir)/io.rb \
$(srcdir)/marshal.rb \
- $(srcdir)/rjit.rb \
- $(srcdir)/rjit_c.rb \
+ $(srcdir)/mjit.rb \
+ $(srcdir)/mjit_c.rb \
$(srcdir)/pack.rb \
$(srcdir)/trace_point.rb \
$(srcdir)/warning.rb \
$(srcdir)/array.rb \
- $(srcdir)/hash.rb \
$(srcdir)/kernel.rb \
$(srcdir)/ractor.rb \
$(srcdir)/symbol.rb \
@@ -1222,16 +1111,9 @@ common-srcs: $(srcs_vpath)parse.c $(srcs_vpath)lex.c $(srcs_vpath)enc/trans/newl
missing-srcs: $(srcdir)/missing/des_tables.c
-srcs: common-srcs missing-srcs srcs-enc srcs-doc
+srcs: common-srcs missing-srcs srcs-enc
-RIPPER_SRCS = $(srcdir)/ext/ripper/ripper.c \
- $(srcdir)/ext/ripper/ripper_init.c \
- $(srcdir)/ext/ripper/eventids1.h \
- $(srcdir)/ext/ripper/eventids1.c \
- $(srcdir)/ext/ripper/eventids2table.c \
- # RIPPER_SRCS
-
-EXT_SRCS = ripper_srcs \
+EXT_SRCS = $(srcdir)/ext/ripper/ripper.c \
$(srcdir)/ext/rbconfig/sizeof/sizes.c \
$(srcdir)/ext/rbconfig/sizeof/limits.c \
$(srcdir)/ext/socket/constdefs.c \
@@ -1277,9 +1159,9 @@ id.c: $(tooldir)/generic_erb.rb $(srcdir)/template/id.c.tmpl $(srcdir)/defs/id.d
$(Q) $(BASERUBY) $(tooldir)/generic_erb.rb --output=$@ \
$(srcdir)/template/id.c.tmpl
-node_name.inc: $(tooldir)/node_name.rb $(srcdir)/rubyparser.h
+node_name.inc: $(tooldir)/node_name.rb $(srcdir)/node.h
$(ECHO) generating $@
- $(Q) $(BASERUBY) -n $(tooldir)/node_name.rb < $(srcdir)/rubyparser.h > $@
+ $(Q) $(BASERUBY) -n $(tooldir)/node_name.rb < $(srcdir)/node.h > $@
encdb.h: $(RBCONFIG) $(tooldir)/generic_erb.rb $(srcdir)/template/encdb.h.tmpl
$(ECHO) generating $@
@@ -1304,7 +1186,10 @@ $(MINIPRELUDE_C): $(COMPILE_PRELUDE) $(BUILTIN_RB_SRCS)
$(Q) $(BASERUBY) $(tooldir)/generic_erb.rb -I$(srcdir) -o $@ \
$(srcdir)/template/prelude.c.tmpl $(BUILTIN_RB_SRCS)
-golf_prelude.rbbin: {$(srcdir)}golf_prelude.rb $(tooldir)/mk_rbbin.rb $(PREP)
+$(GOLF_PRELUDE_C): $(COMPILE_PRELUDE) {$(srcdir)}golf_prelude.rb
+ $(ECHO) generating $@
+ $(Q) $(BASERUBY) $(tooldir)/generic_erb.rb -I$(srcdir) -c -o $@ \
+ $(srcdir)/template/prelude.c.tmpl golf_prelude.rb
MAINCPPFLAGS = $(ENABLE_DEBUG_ENV:yes=-DRUBY_DEBUG_ENV=1)
@@ -1322,22 +1207,15 @@ probes.h: {$(VPATH)}probes.$(DTRACE_EXT)
prereq: incs srcs preludes PHONY
preludes: {$(VPATH)}miniprelude.c
-
-{$(srcdir)}.rb.rbbin:
- $(ECHO) making $@
- $(Q) $(MINIRUBY) $(tooldir)/mk_rbbin.rb $< > $@
+preludes: {$(srcdir)}golf_prelude.c
{$(srcdir)}.rb.rbinc:
$(ECHO) making $@
$(Q) $(BASERUBY) $(tooldir)/mk_builtin_loader.rb $<
-$(BUILTIN_BINARY:yes=built)in_binary.inc: $(PREP) $(BUILTIN_RB_SRCS) $(srcdir)/template/builtin_binary.inc.tmpl
+builtin_binary.inc: $(PREP) $(BUILTIN_RB_SRCS) $(srcdir)/template/builtin_binary.inc.tmpl
$(Q) $(MINIRUBY) $(tooldir)/generic_erb.rb -o $@ \
- $(srcdir)/template/builtin_binary.inc.tmpl
- -$(Q) sha256sum $@ 2> $(NULL) || $(NULLCMD)
-
-$(BUILTIN_BINARY:no=builtin)_binary.inc:
- $(Q) echo> $@ // empty $(@F)
+ $(srcdir)/template/builtin_binary.inc.tmpl -- --cross=$(CROSS_COMPILING)
$(BUILTIN_RB_INCS): $(top_srcdir)/tool/mk_builtin_loader.rb
@@ -1348,20 +1226,13 @@ $(REVISION_H)$(no_baseruby:no=~disabled~):
$(REVISION_H)$(yes_baseruby:yes=~disabled~):
$(Q) exit > $@
-# uncommon.mk: $(REVISION_H)
-# $(MKFILES): $(REVISION_H)
-
-ripper_srcs: $(RIPPER_SRCS)
-
-$(RIPPER_SRCS): $(srcdir)/parse.y $(srcdir)/defs/id.def
-$(RIPPER_SRCS): $(srcdir)/ext/ripper/tools/preproc.rb $(srcdir)/ext/ripper/tools/dsl.rb
-$(RIPPER_SRCS): $(srcdir)/ext/ripper/ripper_init.c.tmpl $(srcdir)/ext/ripper/eventids2.c
+$(srcdir)/ext/ripper/ripper.c: $(srcdir)/ext/ripper/tools/preproc.rb $(srcdir)/parse.y $(srcdir)/defs/id.def $(srcdir)/ext/ripper/depend
$(ECHO) generating $@
$(Q) $(CHDIR) $(@D) && \
$(CAT_DEPEND) depend | \
$(exec) $(MAKE) -f - $(mflags) \
- Q=$(Q) ECHO=$(ECHO) RM="$(RM1)" top_srcdir=../.. srcdir=. VPATH=../.. \
- RUBY="$(BASERUBY)" BASERUBY="$(BASERUBY)" PATH_SEPARATOR="$(PATH_SEPARATOR)" LANG=C
+ Q=$(Q) ECHO=$(ECHO) RM="$(RM1)" BISON="$(YACC)" top_srcdir=../.. srcdir=. VPATH=../.. \
+ RUBY="$(BASERUBY)" PATH_SEPARATOR="$(PATH_SEPARATOR)" LANG=C
$(srcdir)/ext/json/parser/parser.c: $(srcdir)/ext/json/parser/parser.rl $(srcdir)/ext/json/parser/prereq.mk
$(ECHO) generating $@
@@ -1389,7 +1260,7 @@ $(srcdir)/ext/rbconfig/sizeof/limits.c: $(srcdir)/ext/rbconfig/sizeof/depend \
$(exec) $(MAKE) -f - $(mflags) \
Q=$(Q) ECHO=$(ECHO) top_srcdir=../../.. srcdir=. VPATH=../../.. RUBY="$(BASERUBY)" $(@F)
-$(srcdir)/ext/socket/constdefs.c: $(srcdir)/ext/socket/depend $(srcdir)/ext/socket/mkconstants.rb
+$(srcdir)/ext/socket/constdefs.c: $(srcdir)/ext/socket/depend
$(Q) $(CHDIR) $(@D) && \
$(CAT_DEPEND) depend | \
$(exec) $(MAKE) -f - $(mflags) \
@@ -1451,10 +1322,9 @@ run.gdb:
echo ' quit' >> run.gdb
echo end >> run.gdb
-GDB = gdb
gdb: miniruby$(EXEEXT) run.gdb PHONY
- $(GDB) -x run.gdb --quiet --args $(MINIRUBY) $(RUNOPT0) $(TESTRUN_SCRIPT) $(RUNOPT)
+ gdb -x run.gdb --quiet --args $(MINIRUBY) $(RUNOPT0) $(TESTRUN_SCRIPT) $(RUNOPT)
gdb-ruby: $(PROGRAM) run.gdb PHONY
$(Q) $(RUNRUBY_COMMAND) $(RUNRUBY_DEBUGGER) -- $(RUNOPT0) $(TESTRUN_SCRIPT) $(RUNOPT)
@@ -1477,7 +1347,7 @@ dist:
up:: update-remote
-up$(DOT_WAIT)::
+up::
-$(Q)$(MAKE) $(mflags) Q=$(Q) REVISION_FORCE=PHONY ALWAYS_UPDATE_UNICODE= after-update
yes::
@@ -1504,10 +1374,6 @@ update-config_files: PHONY
$(Q) $(BASERUBY) -C "$(srcdir)" tool/downloader.rb -d tool --cache-dir=$(CACHE_DIR) -e gnu \
config.guess config.sub
-update-coverage: main PHONY
- $(XRUBY) -C "$(srcdir)" bin/gem install --no-document \
- --install-dir .bundle --conservative "simplecov"
-
refresh-gems: update-bundled_gems prepare-gems
prepare-gems: $(HAVE_BASERUBY:yes=update-gems) $(HAVE_BASERUBY:yes=extract-gems)
extract-gems: $(HAVE_BASERUBY:yes=update-gems)
@@ -1534,32 +1400,16 @@ extract-gems$(gnumake:yes=-sequential): PHONY
-e 'gem, ver, _, rev = *$$F' \
-e 'next if !ver or /^#/=~gem' \
-e 'g = "#{gem}-#{ver}"' \
- -e 'unless File.directory?("#{d}/#{g}")' \
- -e 'if rev and File.exist?(gs = "gems/src/#{gem}/#{gem}.gemspec")' \
- -e 'BundledGem.build(gs, ver, "gems")' \
- -e 'end' \
+ -e 'if File.directory?("#{d}/#{g}")' \
+ -e 'elsif rev and File.exist?(gs = "gems/src/#{gem}/#{gem}.gemspec")' \
+ -e 'BundledGem.copy(gs, ".bundle")' \
+ -e 'else' \
-e 'BundledGem.unpack("gems/#{g}.gem", ".bundle")' \
-e 'end' \
gems/bundled_gems
-extract-gems$(gnumake:yes=-sequential): $(HAVE_GIT:yes=clone-bundled-gems-src)
-
-clone-bundled-gems-src: PHONY
- $(Q) $(BASERUBY) -C "$(srcdir)" \
- -Itool/lib -rbundled_gem -answ \
- -e 'BEGIN {git = $$git}' \
- -e 'gem, _, repo, rev = *$$F' \
- -e 'next if !rev or /^#/=~gem' \
- -e 'gemdir = "gems/src/#{gem}"' \
- -e 'BundledGem.checkout(gemdir, repo, rev, git: git)' \
- -e 'BundledGem.dummy_gemspec("#{gemdir}/#{gem}.gemspec")' \
- -- -git="$(GIT)" \
- gems/bundled_gems
-
outdate-bundled-gems: PHONY
- $(Q) $(BASERUBY) $(tooldir)/$@.rb --make="$(MAKE)" --mflags="$(MFLAGS)" \
- --ruby-platform=$(arch) --ruby-version=$(ruby_version) \
- "$(srcdir)"
+ $(Q) $(BASERUBY) $(tooldir)/$@.rb --make="$(MAKE)" --mflags="$(MFLAGS)" "$(srcdir)"
update-bundled_gems: PHONY
$(Q) $(RUNRUBY) -rrubygems \
@@ -1587,11 +1437,11 @@ no-test-bundled-gems-prepare: no-test-bundled-gems-precheck
yes-test-bundled-gems-prepare: yes-test-bundled-gems-precheck
$(ACTIONS_GROUP)
$(XRUBY) -C "$(srcdir)" bin/gem install --no-document \
- --install-dir .bundle --conservative "hoe" "json-schema" "test-unit-rr"
+ --install-dir .bundle --conservative "bundler" "minitest:~> 5" "test-unit" "rake" "hoe" "rexml" "json-schema:5.1.0" "test-unit-rr"
$(ACTIONS_ENDGROUP)
PREPARE_BUNDLED_GEMS = test-bundled-gems-prepare
-test-bundled-gems: $(TEST_RUNNABLE)-test-bundled-gems $(DOT_WAIT) $(TEST_RUNNABLE)-test-bundled-gems-spec
+test-bundled-gems: $(TEST_RUNNABLE)-test-bundled-gems
yes-test-bundled-gems: test-bundled-gems-run
no-test-bundled-gems:
@@ -1599,31 +1449,36 @@ no-test-bundled-gems:
# TEST_BUNDLED_GEMS_ALLOW_FAILURES =
BUNDLED_GEMS =
-test-bundled-gems-run: $(TEST_RUNNABLE)-test-bundled-gems-run
-yes-test-bundled-gems-run: $(PREPARE_BUNDLED_GEMS)
+test-bundled-gems-run: $(PREPARE_BUNDLED_GEMS)
$(gnumake_recursive)$(Q) $(XRUBY) $(tooldir)/test-bundled-gems.rb $(BUNDLED_GEMS)
-no-test-bundled-gems-run: $(PREPARE_BUNDLED_GEMS)
-test-bundled-gems-spec: $(TEST_RUNNABLE)-test-bundled-gems-spec
-yes-test-bundled-gems-spec: yes-test-spec-precheck $(PREPARE_BUNDLED_GEMS)
+test-syntax-suggest-precheck: $(TEST_RUNNABLE)-test-syntax-suggest-precheck
+no-test-syntax-suggest-precheck:
+yes-test-syntax-suggest-precheck: main
+
+test-syntax-suggest-prepare: $(TEST_RUNNABLE)-test-syntax-suggest-prepare
+no-test-syntax-suggest-prepare: no-test-syntax-suggest-precheck
+yes-test-syntax-suggest-prepare: yes-test-syntax-suggest-precheck
$(ACTIONS_GROUP)
- $(gnumake_recursive)$(Q) \
- $(RUNRUBY) -r./$(arch)-fake -r$(tooldir)/lib/_tmpdir \
- $(srcdir)/spec/mspec/bin/mspec run -B $(srcdir)/spec/bundled_gems.mspec $(MSPECOPT) $(SPECOPTS)
+ $(XRUBY) -C "$(srcdir)" bin/gem install --no-document \
+ --install-dir .bundle --conservative "bundler" "rake" "rspec:~> 3" #"ruby-prof"
$(ACTIONS_ENDGROUP)
-no-test-bundled-gems-spec:
-
-test-syntax-suggest:
+RSPECOPTS =
+SYNTAX_SUGGEST_SPECS =
+PREPARE_SYNTAX_SUGGEST = test-syntax-suggest-prepare
+test-syntax-suggest: $(TEST_RUNNABLE)-test-syntax-suggest
+yes-test-syntax-suggest: yes-$(PREPARE_SYNTAX_SUGGEST)
+ $(XRUBY) -C $(srcdir) -Ispec/syntax_suggest .bundle/bin/rspec \
+ --require spec_helper $(RSPECOPTS) spec/syntax_suggest/$(SYNTAX_SUGGEST_SPECS)
+no-test-syntax-suggest:
-check: $(DOT_WAIT) $(PREPARE_SYNTAX_SUGGEST) test-syntax-suggest
+check: $(DOT_WAIT) $(TEST_RUNNABLE)-$(PREPARE_SYNTAX_SUGGEST) test-syntax-suggest
test-bundler-precheck: $(TEST_RUNNABLE)-test-bundler-precheck
no-test-bundler-precheck:
yes-test-bundler-precheck: main $(arch)-fake.rb
-yes-test-bundler-parallel-precheck: yes-test-bundler-precheck
-test-bundler-prepare: $(TEST_RUNNABLE)-test-bundler-prepare
no-test-bundler-prepare: no-test-bundler-precheck
yes-test-bundler-prepare: yes-test-bundler-precheck
$(ACTIONS_GROUP)
@@ -1632,24 +1487,23 @@ yes-test-bundler-prepare: yes-test-bundler-precheck
-e 'ENV["BUNDLE_APP_CONFIG"] = File.expand_path(".bundle")' \
-e 'ENV["BUNDLE_PATH__SYSTEM"] = "true"' \
-e 'ENV["BUNDLE_WITHOUT"] = "lint doc"' \
- -e 'load "spec/bundler/support/bundle.rb"' -- install --quiet --gemfile=tool/bundler/dev_gems.rb
+ -e 'load "spec/bundler/support/bundle.rb"' -- install --gemfile=tool/bundler/dev_gems.rb
$(ACTIONS_ENDGROUP)
RSPECOPTS =
BUNDLER_SPECS =
-PREPARE_BUNDLER = $(TEST_RUNNABLE)-test-bundler-prepare
test-bundler: $(TEST_RUNNABLE)-test-bundler
-yes-test-bundler: $(PREPARE_BUNDLER)
+yes-test-bundler: yes-test-bundler-prepare
$(gnumake_recursive)$(XRUBY) \
-r./$(arch)-fake \
-e "exec(*ARGV)" -- \
- $(XRUBY) -C $(srcdir) -Ispec/bundler:spec/lib .bundle/bin/rspec \
- --require spec_helper --require formatter_overrides $(RSPECOPTS) spec/bundler/$(BUNDLER_SPECS)
+ $(XRUBY) -C $(srcdir) -Ispec/bundler .bundle/bin/rspec \
+ --require spec_helper $(RSPECOPTS) spec/bundler/$(BUNDLER_SPECS)
no-test-bundler:
PARALLELRSPECOPTS = --runtime-log $(srcdir)/tmp/parallel_runtime_rspec.log
test-bundler-parallel: $(TEST_RUNNABLE)-test-bundler-parallel
-yes-test-bundler-parallel: $(PREPARE_BUNDLER)
+yes-test-bundler-parallel: yes-test-bundler-prepare
$(gnumake_recursive)$(XRUBY) \
-r./$(arch)-fake \
-e "ARGV[-1] = File.expand_path(ARGV[-1])" \
@@ -1657,17 +1511,17 @@ yes-test-bundler-parallel: $(PREPARE_BUNDLER)
$(XRUBY) -I$(srcdir)/spec/bundler \
-e "ENV['PARALLEL_TESTS_EXECUTABLE'] = ARGV.shift" \
-e "load ARGV.shift" \
- "$(XRUBY) -C $(srcdir) -Ispec/bundler:spec/lib .bundle/bin/rspec" \
+ "$(XRUBY) -C $(srcdir) -Ispec/bundler .bundle/bin/rspec" \
$(srcdir)/.bundle/bin/parallel_rspec \
- -o "--require spec_helper --require formatter_overrides" \
+ -o "--require spec_helper" \
$(PARALLELRSPECOPTS) $(srcdir)/spec/bundler/$(BUNDLER_SPECS)
no-test-bundler-parallel:
# The annocheck supports ELF format binaries compiled for any OS and for any
# architecture. It is designed to be independent of the host OS and the
# architecture. The test-annocheck.sh requires docker or podman.
-test-annocheck: $(PROGRAM) $(LIBRUBY_SO)
- $(tooldir)/test-annocheck.sh $(PROGRAM) $(LIBRUBY_SO)
+test-annocheck: $(PROGRAM)
+ $(tooldir)/test-annocheck.sh $(PROGRAM)
GEM = up
sync-default-gems:
@@ -1809,16 +1663,6 @@ $(UNICODE_HDR_DIR)/name2ctype.h:
$(UNICODE_SRC_DATA_DIR) $(UNICODE_SRC_EMOJI_DATA_DIR) > $@.new
$(MV) $@.new $@
-srcs-doc: $(srcdir)/doc/regexp/unicode_properties.rdoc
-$(srcdir)/doc/regexp/$(ALWAYS_UPDATE_UNICODE:yes=unicode_properties.rdoc): \
- $(UNICODE_HDR_DIR)/name2ctype.h $(UNICODE_PROPERTY_FILES)
-
-$(srcdir)/doc/regexp/unicode_properties.rdoc:
- $(Q) $(BOOTSTRAPRUBY) $(tooldir)/generic_erb.rb -c -o $@ \
- $(srcdir)/template/unicode_properties.rdoc.tmpl \
- $(UNICODE_SRC_DATA_DIR) $(UNICODE_HDR_DIR)/name2ctype.h || \
- $(TOUCH) $@
-
# the next non-comment line was:
# $(UNICODE_HDR_DIR)/casefold.h: $(tooldir)/enc-case-folding.rb \
# but was changed to make sure CI works on systems that don't have gperf
@@ -1861,8 +1705,6 @@ info-arch: PHONY
@echo arch=$(arch)
exam: check
-exam: $(DOT_WAIT) test-bundler-parallel
-exam: $(DOT_WAIT) test-bundled-gems
love: sudo-precheck up all test exam install
@echo love is all you need
@@ -1884,39 +1726,11 @@ update-man-date: PHONY
ChangeLog:
$(ECHO) Generating $@
-$(Q) $(BASERUBY) -I"$(tooldir)/lib" -rvcs \
- -e 'VCS.detect(ARGV[0]).export_changelog(path: ARGV[1])' \
+ -e 'VCS.detect(ARGV[0]).export_changelog("@", nil, nil, ARGV[1])' \
"$(srcdir)" $@
-# CAUTION: If using GNU make 3 which does not support `.WAIT`, this
-# recipe with multiple jobs makes build and `git reset` run
-# simultaneously, and will cause inconsistent results. Run with `-j1`
-# or update GNU make.
-nightly: yesterday $(DOT_WAIT) install
- $(NULLCMD)
-
-# Rewind to the last commit "yesterday". "Yesterday" means here the
-# period where `RUBY_RELEASE_DATE` is the day before the date to be
-# generated now. In short, the yesterday in JST-9 time zone.
-yesterday: rewindable
-
-rewindable:
- $(GIT) -C $(srcdir) status --porcelain
- $(GIT) -C $(srcdir) diff --quiet
-
HELP_EXTRA_TASKS = ""
-shared-gc: probes.h
- $(Q) if test -z $(shared_gc_dir); then \
- echo "You must configure with --with-shared-gc to use shared GC"; \
- exit 1; \
- elif test -z $(SHARED_GC); then \
- echo "You must specify SHARED_GC with the GC to build"; \
- exit 1; \
- fi
- $(ECHO) generating $(shared_gc_dir)librubygc.$(SHARED_GC).$(SOEXT)
- $(Q) $(MAKEDIRS) $(shared_gc_dir)
- $(Q) $(LDSHARED) -I$(srcdir)/include -I$(srcdir) -I$(arch_hdrdir) $(XDLDFLAGS) $(cflags) -DBUILDING_SHARED_GC -fPIC -o $(shared_gc_dir)librubygc.$(SHARED_GC).$(SOEXT) $(srcdir)/gc/$(SHARED_GC).c
-
help: PHONY
$(MESSAGE_BEGIN) \
" Makefile of Ruby" \
@@ -1933,16 +1747,13 @@ help: PHONY
" runruby: runs test.rb by ruby you just built" \
" gdb: runs test.rb by miniruby under gdb" \
" gdb-ruby: runs test.rb by ruby under gdb" \
- " runirb: starts irb on built ruby (not installed ruby)" \
- " exam: equals make check test-bundler-parallel test-bundled-gems" \
- " check: equals make test test-tool test-all test-spec test-syntax-suggest" \
+ " check: equals make test test-tool test-all test-spec" \
" test: ruby core tests [BTESTS=<bootstraptest files>]" \
" test-all: all ruby tests [TESTOPTS=-j4 TESTS=<test files>]" \
" test-spec: run the Ruby spec suite [SPECOPTS=<specs, opts>]" \
" test-bundler: run the Bundler spec" \
" test-bundler-parallel: run the Bundler spec with parallel" \
- " test-syntax-suggest: run the SyntaxSuggest spec" \
- " test-bundled-gems: run the test suite of bundled gems [BUNDLED_GEMS=<gems>]" \
+ " test-bundled-gems: run the test suite of bundled gems" \
" test-tool: tests under the tool/test" \
" update-gems: download files of the bundled gems" \
" update-bundled_gems: update the latest version of bundled gems" \
@@ -1953,12 +1764,12 @@ help: PHONY
" install: install all ruby distributions" \
" install-nodoc: install without rdoc" \
" install-cross: install cross compiling stuff" \
- " clean: clean up to the state before build" \
- " distclean: clean up to the state before configure" \
+ " clean: clean for tarball" \
+ " distclean: clean for repository" \
" golf: build goruby for golfers" \
$(HELP_EXTRA_TASKS) \
"see DeveloperHowto for more detail: " \
- " https://github.com/ruby/ruby/wiki/Developer-How-To" \
+ " https://bugs.ruby-lang.org/projects/ruby/wiki/DeveloperHowto" \
$(MESSAGE_END)
$(CROSS_COMPILING:yes=)builtin.$(OBJEXT): {$(VPATH)}mini_builtin.c
@@ -1990,7 +1801,6 @@ addr2line.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
addr2line.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
addr2line.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
addr2line.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-addr2line.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
addr2line.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
addr2line.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
addr2line.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -2020,10 +1830,6 @@ addr2line.$(OBJEXT): {$(VPATH)}internal/stdbool.h
addr2line.$(OBJEXT): {$(VPATH)}internal/warning_push.h
addr2line.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
addr2line.$(OBJEXT): {$(VPATH)}missing.h
-array.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-array.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-array.$(OBJEXT): $(CCAN_DIR)/list/list.h
-array.$(OBJEXT): $(CCAN_DIR)/str/str.h
array.$(OBJEXT): $(hdrdir)/ruby/ruby.h
array.$(OBJEXT): $(top_srcdir)/internal/array.h
array.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
@@ -2036,12 +1842,10 @@ array.$(OBJEXT): $(top_srcdir)/internal/enum.h
array.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
array.$(OBJEXT): $(top_srcdir)/internal/gc.h
array.$(OBJEXT): $(top_srcdir)/internal/hash.h
-array.$(OBJEXT): $(top_srcdir)/internal/imemo.h
array.$(OBJEXT): $(top_srcdir)/internal/numeric.h
array.$(OBJEXT): $(top_srcdir)/internal/object.h
array.$(OBJEXT): $(top_srcdir)/internal/proc.h
array.$(OBJEXT): $(top_srcdir)/internal/rational.h
-array.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
array.$(OBJEXT): $(top_srcdir)/internal/serial.h
array.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
array.$(OBJEXT): $(top_srcdir)/internal/variable.h
@@ -2050,7 +1854,6 @@ array.$(OBJEXT): $(top_srcdir)/internal/warnings.h
array.$(OBJEXT): {$(VPATH)}array.c
array.$(OBJEXT): {$(VPATH)}array.rbinc
array.$(OBJEXT): {$(VPATH)}assert.h
-array.$(OBJEXT): {$(VPATH)}atomic.h
array.$(OBJEXT): {$(VPATH)}backward/2/assume.h
array.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
array.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -2108,7 +1911,6 @@ array.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
array.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
array.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
array.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-array.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
array.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
array.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
array.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -2177,6 +1979,7 @@ array.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
array.$(OBJEXT): {$(VPATH)}internal/intern/error.h
array.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
array.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+array.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
array.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
array.$(OBJEXT): {$(VPATH)}internal/intern/io.h
array.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -2207,36 +2010,29 @@ array.$(OBJEXT): {$(VPATH)}internal/memory.h
array.$(OBJEXT): {$(VPATH)}internal/method.h
array.$(OBJEXT): {$(VPATH)}internal/module.h
array.$(OBJEXT): {$(VPATH)}internal/newobj.h
+array.$(OBJEXT): {$(VPATH)}internal/rgengc.h
array.$(OBJEXT): {$(VPATH)}internal/scan_args.h
array.$(OBJEXT): {$(VPATH)}internal/special_consts.h
array.$(OBJEXT): {$(VPATH)}internal/static_assert.h
array.$(OBJEXT): {$(VPATH)}internal/stdalign.h
array.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-array.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
array.$(OBJEXT): {$(VPATH)}internal/symbol.h
array.$(OBJEXT): {$(VPATH)}internal/value.h
array.$(OBJEXT): {$(VPATH)}internal/value_type.h
array.$(OBJEXT): {$(VPATH)}internal/variable.h
array.$(OBJEXT): {$(VPATH)}internal/warning_push.h
array.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-array.$(OBJEXT): {$(VPATH)}method.h
array.$(OBJEXT): {$(VPATH)}missing.h
-array.$(OBJEXT): {$(VPATH)}node.h
array.$(OBJEXT): {$(VPATH)}onigmo.h
array.$(OBJEXT): {$(VPATH)}oniguruma.h
array.$(OBJEXT): {$(VPATH)}probes.dmyh
array.$(OBJEXT): {$(VPATH)}probes.h
array.$(OBJEXT): {$(VPATH)}ruby_assert.h
-array.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-array.$(OBJEXT): {$(VPATH)}rubyparser.h
array.$(OBJEXT): {$(VPATH)}shape.h
array.$(OBJEXT): {$(VPATH)}st.h
array.$(OBJEXT): {$(VPATH)}subst.h
-array.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-array.$(OBJEXT): {$(VPATH)}thread_native.h
+array.$(OBJEXT): {$(VPATH)}transient_heap.h
array.$(OBJEXT): {$(VPATH)}util.h
-array.$(OBJEXT): {$(VPATH)}vm_core.h
-array.$(OBJEXT): {$(VPATH)}vm_opts.h
ast.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
ast.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
ast.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -2245,44 +2041,16 @@ ast.$(OBJEXT): $(hdrdir)/ruby.h
ast.$(OBJEXT): $(hdrdir)/ruby/ruby.h
ast.$(OBJEXT): $(top_srcdir)/internal/array.h
ast.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-ast.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-ast.$(OBJEXT): $(top_srcdir)/internal/bits.h
ast.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-ast.$(OBJEXT): $(top_srcdir)/internal/complex.h
-ast.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
ast.$(OBJEXT): $(top_srcdir)/internal/gc.h
ast.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-ast.$(OBJEXT): $(top_srcdir)/internal/numeric.h
ast.$(OBJEXT): $(top_srcdir)/internal/parse.h
-ast.$(OBJEXT): $(top_srcdir)/internal/rational.h
-ast.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-ast.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
ast.$(OBJEXT): $(top_srcdir)/internal/serial.h
ast.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
ast.$(OBJEXT): $(top_srcdir)/internal/symbol.h
ast.$(OBJEXT): $(top_srcdir)/internal/variable.h
ast.$(OBJEXT): $(top_srcdir)/internal/vm.h
ast.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-ast.$(OBJEXT): $(top_srcdir)/prism/defines.h
-ast.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-ast.$(OBJEXT): $(top_srcdir)/prism/node.h
-ast.$(OBJEXT): $(top_srcdir)/prism/options.h
-ast.$(OBJEXT): $(top_srcdir)/prism/pack.h
-ast.$(OBJEXT): $(top_srcdir)/prism/parser.h
-ast.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-ast.$(OBJEXT): $(top_srcdir)/prism/prism.h
-ast.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-ast.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-ast.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
ast.$(OBJEXT): {$(VPATH)}assert.h
ast.$(OBJEXT): {$(VPATH)}ast.c
ast.$(OBJEXT): {$(VPATH)}ast.rbinc
@@ -2343,7 +2111,6 @@ ast.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
ast.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
ast.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
ast.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-ast.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
ast.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
ast.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
ast.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -2412,6 +2179,7 @@ ast.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
ast.$(OBJEXT): {$(VPATH)}internal/intern/error.h
ast.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
ast.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+ast.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
ast.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
ast.$(OBJEXT): {$(VPATH)}internal/intern/io.h
ast.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -2442,12 +2210,12 @@ ast.$(OBJEXT): {$(VPATH)}internal/memory.h
ast.$(OBJEXT): {$(VPATH)}internal/method.h
ast.$(OBJEXT): {$(VPATH)}internal/module.h
ast.$(OBJEXT): {$(VPATH)}internal/newobj.h
+ast.$(OBJEXT): {$(VPATH)}internal/rgengc.h
ast.$(OBJEXT): {$(VPATH)}internal/scan_args.h
ast.$(OBJEXT): {$(VPATH)}internal/special_consts.h
ast.$(OBJEXT): {$(VPATH)}internal/static_assert.h
ast.$(OBJEXT): {$(VPATH)}internal/stdalign.h
ast.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-ast.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
ast.$(OBJEXT): {$(VPATH)}internal/symbol.h
ast.$(OBJEXT): {$(VPATH)}internal/value.h
ast.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -2460,13 +2228,8 @@ ast.$(OBJEXT): {$(VPATH)}missing.h
ast.$(OBJEXT): {$(VPATH)}node.h
ast.$(OBJEXT): {$(VPATH)}onigmo.h
ast.$(OBJEXT): {$(VPATH)}oniguruma.h
-ast.$(OBJEXT): {$(VPATH)}prism/ast.h
-ast.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-ast.$(OBJEXT): {$(VPATH)}prism/version.h
-ast.$(OBJEXT): {$(VPATH)}prism_compile.h
ast.$(OBJEXT): {$(VPATH)}ruby_assert.h
ast.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-ast.$(OBJEXT): {$(VPATH)}rubyparser.h
ast.$(OBJEXT): {$(VPATH)}shape.h
ast.$(OBJEXT): {$(VPATH)}st.h
ast.$(OBJEXT): {$(VPATH)}subst.h
@@ -2475,13 +2238,7 @@ ast.$(OBJEXT): {$(VPATH)}thread_native.h
ast.$(OBJEXT): {$(VPATH)}util.h
ast.$(OBJEXT): {$(VPATH)}vm_core.h
ast.$(OBJEXT): {$(VPATH)}vm_opts.h
-bignum.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-bignum.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-bignum.$(OBJEXT): $(CCAN_DIR)/list/list.h
-bignum.$(OBJEXT): $(CCAN_DIR)/str/str.h
bignum.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-bignum.$(OBJEXT): $(top_srcdir)/internal/array.h
-bignum.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
bignum.$(OBJEXT): $(top_srcdir)/internal/bignum.h
bignum.$(OBJEXT): $(top_srcdir)/internal/bits.h
bignum.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -2489,7 +2246,6 @@ bignum.$(OBJEXT): $(top_srcdir)/internal/compilers.h
bignum.$(OBJEXT): $(top_srcdir)/internal/complex.h
bignum.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
bignum.$(OBJEXT): $(top_srcdir)/internal/gc.h
-bignum.$(OBJEXT): $(top_srcdir)/internal/imemo.h
bignum.$(OBJEXT): $(top_srcdir)/internal/numeric.h
bignum.$(OBJEXT): $(top_srcdir)/internal/object.h
bignum.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@@ -2499,7 +2255,6 @@ bignum.$(OBJEXT): $(top_srcdir)/internal/variable.h
bignum.$(OBJEXT): $(top_srcdir)/internal/vm.h
bignum.$(OBJEXT): $(top_srcdir)/internal/warnings.h
bignum.$(OBJEXT): {$(VPATH)}assert.h
-bignum.$(OBJEXT): {$(VPATH)}atomic.h
bignum.$(OBJEXT): {$(VPATH)}backward/2/assume.h
bignum.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
bignum.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -2513,7 +2268,6 @@ bignum.$(OBJEXT): {$(VPATH)}bignum.c
bignum.$(OBJEXT): {$(VPATH)}config.h
bignum.$(OBJEXT): {$(VPATH)}constant.h
bignum.$(OBJEXT): {$(VPATH)}defines.h
-bignum.$(OBJEXT): {$(VPATH)}encoding.h
bignum.$(OBJEXT): {$(VPATH)}id.h
bignum.$(OBJEXT): {$(VPATH)}id_table.h
bignum.$(OBJEXT): {$(VPATH)}intern.h
@@ -2556,7 +2310,6 @@ bignum.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
bignum.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
bignum.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
bignum.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-bignum.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
bignum.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
bignum.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
bignum.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -2589,15 +2342,6 @@ bignum.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
bignum.$(OBJEXT): {$(VPATH)}internal/ctype.h
bignum.$(OBJEXT): {$(VPATH)}internal/dllexport.h
bignum.$(OBJEXT): {$(VPATH)}internal/dosish.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-bignum.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
bignum.$(OBJEXT): {$(VPATH)}internal/error.h
bignum.$(OBJEXT): {$(VPATH)}internal/eval.h
bignum.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -2625,6 +2369,7 @@ bignum.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
bignum.$(OBJEXT): {$(VPATH)}internal/intern/error.h
bignum.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
bignum.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+bignum.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
bignum.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
bignum.$(OBJEXT): {$(VPATH)}internal/intern/io.h
bignum.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -2655,35 +2400,25 @@ bignum.$(OBJEXT): {$(VPATH)}internal/memory.h
bignum.$(OBJEXT): {$(VPATH)}internal/method.h
bignum.$(OBJEXT): {$(VPATH)}internal/module.h
bignum.$(OBJEXT): {$(VPATH)}internal/newobj.h
+bignum.$(OBJEXT): {$(VPATH)}internal/rgengc.h
bignum.$(OBJEXT): {$(VPATH)}internal/scan_args.h
bignum.$(OBJEXT): {$(VPATH)}internal/special_consts.h
bignum.$(OBJEXT): {$(VPATH)}internal/static_assert.h
bignum.$(OBJEXT): {$(VPATH)}internal/stdalign.h
bignum.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-bignum.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
bignum.$(OBJEXT): {$(VPATH)}internal/symbol.h
bignum.$(OBJEXT): {$(VPATH)}internal/value.h
bignum.$(OBJEXT): {$(VPATH)}internal/value_type.h
bignum.$(OBJEXT): {$(VPATH)}internal/variable.h
bignum.$(OBJEXT): {$(VPATH)}internal/warning_push.h
bignum.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-bignum.$(OBJEXT): {$(VPATH)}method.h
bignum.$(OBJEXT): {$(VPATH)}missing.h
-bignum.$(OBJEXT): {$(VPATH)}node.h
-bignum.$(OBJEXT): {$(VPATH)}onigmo.h
-bignum.$(OBJEXT): {$(VPATH)}oniguruma.h
bignum.$(OBJEXT): {$(VPATH)}ruby_assert.h
-bignum.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-bignum.$(OBJEXT): {$(VPATH)}rubyparser.h
bignum.$(OBJEXT): {$(VPATH)}shape.h
bignum.$(OBJEXT): {$(VPATH)}st.h
bignum.$(OBJEXT): {$(VPATH)}subst.h
bignum.$(OBJEXT): {$(VPATH)}thread.h
-bignum.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-bignum.$(OBJEXT): {$(VPATH)}thread_native.h
bignum.$(OBJEXT): {$(VPATH)}util.h
-bignum.$(OBJEXT): {$(VPATH)}vm_core.h
-bignum.$(OBJEXT): {$(VPATH)}vm_opts.h
builtin.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
builtin.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
builtin.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -2694,32 +2429,11 @@ builtin.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
builtin.$(OBJEXT): $(top_srcdir)/internal/compilers.h
builtin.$(OBJEXT): $(top_srcdir)/internal/gc.h
builtin.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-builtin.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
builtin.$(OBJEXT): $(top_srcdir)/internal/serial.h
builtin.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
builtin.$(OBJEXT): $(top_srcdir)/internal/variable.h
builtin.$(OBJEXT): $(top_srcdir)/internal/vm.h
builtin.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/defines.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/node.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/options.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/pack.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/parser.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/prism.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-builtin.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
builtin.$(OBJEXT): {$(VPATH)}assert.h
builtin.$(OBJEXT): {$(VPATH)}atomic.h
builtin.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -2737,7 +2451,6 @@ builtin.$(OBJEXT): {$(VPATH)}builtin_binary.inc
builtin.$(OBJEXT): {$(VPATH)}config.h
builtin.$(OBJEXT): {$(VPATH)}constant.h
builtin.$(OBJEXT): {$(VPATH)}defines.h
-builtin.$(OBJEXT): {$(VPATH)}encoding.h
builtin.$(OBJEXT): {$(VPATH)}id.h
builtin.$(OBJEXT): {$(VPATH)}id_table.h
builtin.$(OBJEXT): {$(VPATH)}intern.h
@@ -2780,7 +2493,6 @@ builtin.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
builtin.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
builtin.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
builtin.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-builtin.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
builtin.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
builtin.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
builtin.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -2813,15 +2525,6 @@ builtin.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
builtin.$(OBJEXT): {$(VPATH)}internal/ctype.h
builtin.$(OBJEXT): {$(VPATH)}internal/dllexport.h
builtin.$(OBJEXT): {$(VPATH)}internal/dosish.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-builtin.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
builtin.$(OBJEXT): {$(VPATH)}internal/error.h
builtin.$(OBJEXT): {$(VPATH)}internal/eval.h
builtin.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -2849,6 +2552,7 @@ builtin.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
builtin.$(OBJEXT): {$(VPATH)}internal/intern/error.h
builtin.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
builtin.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+builtin.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
builtin.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
builtin.$(OBJEXT): {$(VPATH)}internal/intern/io.h
builtin.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -2879,12 +2583,12 @@ builtin.$(OBJEXT): {$(VPATH)}internal/memory.h
builtin.$(OBJEXT): {$(VPATH)}internal/method.h
builtin.$(OBJEXT): {$(VPATH)}internal/module.h
builtin.$(OBJEXT): {$(VPATH)}internal/newobj.h
+builtin.$(OBJEXT): {$(VPATH)}internal/rgengc.h
builtin.$(OBJEXT): {$(VPATH)}internal/scan_args.h
builtin.$(OBJEXT): {$(VPATH)}internal/special_consts.h
builtin.$(OBJEXT): {$(VPATH)}internal/static_assert.h
builtin.$(OBJEXT): {$(VPATH)}internal/stdalign.h
builtin.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-builtin.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
builtin.$(OBJEXT): {$(VPATH)}internal/symbol.h
builtin.$(OBJEXT): {$(VPATH)}internal/value.h
builtin.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -2895,15 +2599,8 @@ builtin.$(OBJEXT): {$(VPATH)}iseq.h
builtin.$(OBJEXT): {$(VPATH)}method.h
builtin.$(OBJEXT): {$(VPATH)}missing.h
builtin.$(OBJEXT): {$(VPATH)}node.h
-builtin.$(OBJEXT): {$(VPATH)}onigmo.h
-builtin.$(OBJEXT): {$(VPATH)}oniguruma.h
-builtin.$(OBJEXT): {$(VPATH)}prism/ast.h
-builtin.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-builtin.$(OBJEXT): {$(VPATH)}prism/version.h
-builtin.$(OBJEXT): {$(VPATH)}prism_compile.h
builtin.$(OBJEXT): {$(VPATH)}ruby_assert.h
builtin.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-builtin.$(OBJEXT): {$(VPATH)}rubyparser.h
builtin.$(OBJEXT): {$(VPATH)}shape.h
builtin.$(OBJEXT): {$(VPATH)}st.h
builtin.$(OBJEXT): {$(VPATH)}subst.h
@@ -2925,7 +2622,6 @@ class.$(OBJEXT): $(top_srcdir)/internal/gc.h
class.$(OBJEXT): $(top_srcdir)/internal/hash.h
class.$(OBJEXT): $(top_srcdir)/internal/imemo.h
class.$(OBJEXT): $(top_srcdir)/internal/object.h
-class.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
class.$(OBJEXT): $(top_srcdir)/internal/serial.h
class.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
class.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -2991,7 +2687,6 @@ class.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
class.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
class.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
class.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-class.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
class.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
class.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
class.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -3060,6 +2755,7 @@ class.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
class.$(OBJEXT): {$(VPATH)}internal/intern/error.h
class.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
class.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+class.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
class.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
class.$(OBJEXT): {$(VPATH)}internal/intern/io.h
class.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -3090,12 +2786,12 @@ class.$(OBJEXT): {$(VPATH)}internal/memory.h
class.$(OBJEXT): {$(VPATH)}internal/method.h
class.$(OBJEXT): {$(VPATH)}internal/module.h
class.$(OBJEXT): {$(VPATH)}internal/newobj.h
+class.$(OBJEXT): {$(VPATH)}internal/rgengc.h
class.$(OBJEXT): {$(VPATH)}internal/scan_args.h
class.$(OBJEXT): {$(VPATH)}internal/special_consts.h
class.$(OBJEXT): {$(VPATH)}internal/static_assert.h
class.$(OBJEXT): {$(VPATH)}internal/stdalign.h
class.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-class.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
class.$(OBJEXT): {$(VPATH)}internal/symbol.h
class.$(OBJEXT): {$(VPATH)}internal/value.h
class.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -3109,19 +2805,14 @@ class.$(OBJEXT): {$(VPATH)}onigmo.h
class.$(OBJEXT): {$(VPATH)}oniguruma.h
class.$(OBJEXT): {$(VPATH)}ruby_assert.h
class.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-class.$(OBJEXT): {$(VPATH)}rubyparser.h
class.$(OBJEXT): {$(VPATH)}shape.h
class.$(OBJEXT): {$(VPATH)}st.h
class.$(OBJEXT): {$(VPATH)}subst.h
class.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
class.$(OBJEXT): {$(VPATH)}thread_native.h
class.$(OBJEXT): {$(VPATH)}vm_core.h
-class.$(OBJEXT): {$(VPATH)}vm_debug.h
class.$(OBJEXT): {$(VPATH)}vm_opts.h
-class.$(OBJEXT): {$(VPATH)}vm_sync.h
-class.$(OBJEXT): {$(VPATH)}yjit.h
compar.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-compar.$(OBJEXT): $(hdrdir)/ruby/version.h
compar.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
compar.$(OBJEXT): $(top_srcdir)/internal/compar.h
compar.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -3185,7 +2876,6 @@ compar.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
compar.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
compar.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
compar.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-compar.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
compar.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
compar.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
compar.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -3254,6 +2944,7 @@ compar.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
compar.$(OBJEXT): {$(VPATH)}internal/intern/error.h
compar.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
compar.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+compar.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
compar.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
compar.$(OBJEXT): {$(VPATH)}internal/intern/io.h
compar.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -3284,12 +2975,12 @@ compar.$(OBJEXT): {$(VPATH)}internal/memory.h
compar.$(OBJEXT): {$(VPATH)}internal/method.h
compar.$(OBJEXT): {$(VPATH)}internal/module.h
compar.$(OBJEXT): {$(VPATH)}internal/newobj.h
+compar.$(OBJEXT): {$(VPATH)}internal/rgengc.h
compar.$(OBJEXT): {$(VPATH)}internal/scan_args.h
compar.$(OBJEXT): {$(VPATH)}internal/special_consts.h
compar.$(OBJEXT): {$(VPATH)}internal/static_assert.h
compar.$(OBJEXT): {$(VPATH)}internal/stdalign.h
compar.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-compar.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
compar.$(OBJEXT): {$(VPATH)}internal/symbol.h
compar.$(OBJEXT): {$(VPATH)}internal/value.h
compar.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -3306,7 +2997,6 @@ compile.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
compile.$(OBJEXT): $(CCAN_DIR)/list/list.h
compile.$(OBJEXT): $(CCAN_DIR)/str/str.h
compile.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-compile.$(OBJEXT): $(hdrdir)/ruby/version.h
compile.$(OBJEXT): $(top_srcdir)/internal/array.h
compile.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
compile.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -3321,14 +3011,10 @@ compile.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
compile.$(OBJEXT): $(top_srcdir)/internal/gc.h
compile.$(OBJEXT): $(top_srcdir)/internal/hash.h
compile.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-compile.$(OBJEXT): $(top_srcdir)/internal/io.h
compile.$(OBJEXT): $(top_srcdir)/internal/numeric.h
compile.$(OBJEXT): $(top_srcdir)/internal/object.h
-compile.$(OBJEXT): $(top_srcdir)/internal/parse.h
compile.$(OBJEXT): $(top_srcdir)/internal/rational.h
compile.$(OBJEXT): $(top_srcdir)/internal/re.h
-compile.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-compile.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
compile.$(OBJEXT): $(top_srcdir)/internal/serial.h
compile.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
compile.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -3337,27 +3023,6 @@ compile.$(OBJEXT): $(top_srcdir)/internal/thread.h
compile.$(OBJEXT): $(top_srcdir)/internal/variable.h
compile.$(OBJEXT): $(top_srcdir)/internal/vm.h
compile.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-compile.$(OBJEXT): $(top_srcdir)/prism/defines.h
-compile.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-compile.$(OBJEXT): $(top_srcdir)/prism/node.h
-compile.$(OBJEXT): $(top_srcdir)/prism/options.h
-compile.$(OBJEXT): $(top_srcdir)/prism/pack.h
-compile.$(OBJEXT): $(top_srcdir)/prism/parser.h
-compile.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-compile.$(OBJEXT): $(top_srcdir)/prism/prism.h
-compile.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-compile.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-compile.$(OBJEXT): $(top_srcdir)/prism_compile.c
compile.$(OBJEXT): {$(VPATH)}assert.h
compile.$(OBJEXT): {$(VPATH)}atomic.h
compile.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -3377,6 +3042,7 @@ compile.$(OBJEXT): {$(VPATH)}debug_counter.h
compile.$(OBJEXT): {$(VPATH)}defines.h
compile.$(OBJEXT): {$(VPATH)}encindex.h
compile.$(OBJEXT): {$(VPATH)}encoding.h
+compile.$(OBJEXT): {$(VPATH)}gc.h
compile.$(OBJEXT): {$(VPATH)}id.h
compile.$(OBJEXT): {$(VPATH)}id_table.h
compile.$(OBJEXT): {$(VPATH)}insns.def
@@ -3422,7 +3088,6 @@ compile.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
compile.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
compile.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
compile.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-compile.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
compile.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
compile.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
compile.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -3492,6 +3157,7 @@ compile.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
compile.$(OBJEXT): {$(VPATH)}internal/intern/error.h
compile.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
compile.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+compile.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
compile.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
compile.$(OBJEXT): {$(VPATH)}internal/intern/io.h
compile.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -3522,19 +3188,18 @@ compile.$(OBJEXT): {$(VPATH)}internal/memory.h
compile.$(OBJEXT): {$(VPATH)}internal/method.h
compile.$(OBJEXT): {$(VPATH)}internal/module.h
compile.$(OBJEXT): {$(VPATH)}internal/newobj.h
+compile.$(OBJEXT): {$(VPATH)}internal/rgengc.h
compile.$(OBJEXT): {$(VPATH)}internal/scan_args.h
compile.$(OBJEXT): {$(VPATH)}internal/special_consts.h
compile.$(OBJEXT): {$(VPATH)}internal/static_assert.h
compile.$(OBJEXT): {$(VPATH)}internal/stdalign.h
compile.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-compile.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
compile.$(OBJEXT): {$(VPATH)}internal/symbol.h
compile.$(OBJEXT): {$(VPATH)}internal/value.h
compile.$(OBJEXT): {$(VPATH)}internal/value_type.h
compile.$(OBJEXT): {$(VPATH)}internal/variable.h
compile.$(OBJEXT): {$(VPATH)}internal/warning_push.h
compile.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-compile.$(OBJEXT): {$(VPATH)}io.h
compile.$(OBJEXT): {$(VPATH)}iseq.h
compile.$(OBJEXT): {$(VPATH)}method.h
compile.$(OBJEXT): {$(VPATH)}missing.h
@@ -3542,18 +3207,10 @@ compile.$(OBJEXT): {$(VPATH)}node.h
compile.$(OBJEXT): {$(VPATH)}onigmo.h
compile.$(OBJEXT): {$(VPATH)}oniguruma.h
compile.$(OBJEXT): {$(VPATH)}optinsn.inc
-compile.$(OBJEXT): {$(VPATH)}prism/ast.h
-compile.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-compile.$(OBJEXT): {$(VPATH)}prism/prism.h
-compile.$(OBJEXT): {$(VPATH)}prism/version.h
-compile.$(OBJEXT): {$(VPATH)}prism_compile.c
-compile.$(OBJEXT): {$(VPATH)}prism_compile.h
-compile.$(OBJEXT): {$(VPATH)}ractor.h
compile.$(OBJEXT): {$(VPATH)}re.h
compile.$(OBJEXT): {$(VPATH)}regex.h
compile.$(OBJEXT): {$(VPATH)}ruby_assert.h
compile.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-compile.$(OBJEXT): {$(VPATH)}rubyparser.h
compile.$(OBJEXT): {$(VPATH)}shape.h
compile.$(OBJEXT): {$(VPATH)}st.h
compile.$(OBJEXT): {$(VPATH)}subst.h
@@ -3564,8 +3221,6 @@ compile.$(OBJEXT): {$(VPATH)}vm_callinfo.h
compile.$(OBJEXT): {$(VPATH)}vm_core.h
compile.$(OBJEXT): {$(VPATH)}vm_debug.h
compile.$(OBJEXT): {$(VPATH)}vm_opts.h
-compile.$(OBJEXT): {$(VPATH)}vm_sync.h
-compile.$(OBJEXT): {$(VPATH)}yjit.h
complex.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
complex.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
complex.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -3585,10 +3240,8 @@ complex.$(OBJEXT): $(top_srcdir)/internal/math.h
complex.$(OBJEXT): $(top_srcdir)/internal/numeric.h
complex.$(OBJEXT): $(top_srcdir)/internal/object.h
complex.$(OBJEXT): $(top_srcdir)/internal/rational.h
-complex.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
complex.$(OBJEXT): $(top_srcdir)/internal/serial.h
complex.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-complex.$(OBJEXT): $(top_srcdir)/internal/string.h
complex.$(OBJEXT): $(top_srcdir)/internal/variable.h
complex.$(OBJEXT): $(top_srcdir)/internal/vm.h
complex.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -3606,9 +3259,7 @@ complex.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
complex.$(OBJEXT): {$(VPATH)}complex.c
complex.$(OBJEXT): {$(VPATH)}config.h
complex.$(OBJEXT): {$(VPATH)}constant.h
-complex.$(OBJEXT): {$(VPATH)}debug_counter.h
complex.$(OBJEXT): {$(VPATH)}defines.h
-complex.$(OBJEXT): {$(VPATH)}encoding.h
complex.$(OBJEXT): {$(VPATH)}id.h
complex.$(OBJEXT): {$(VPATH)}id_table.h
complex.$(OBJEXT): {$(VPATH)}intern.h
@@ -3651,7 +3302,6 @@ complex.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
complex.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
complex.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
complex.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-complex.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
complex.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
complex.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
complex.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -3684,15 +3334,6 @@ complex.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
complex.$(OBJEXT): {$(VPATH)}internal/ctype.h
complex.$(OBJEXT): {$(VPATH)}internal/dllexport.h
complex.$(OBJEXT): {$(VPATH)}internal/dosish.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-complex.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
complex.$(OBJEXT): {$(VPATH)}internal/error.h
complex.$(OBJEXT): {$(VPATH)}internal/eval.h
complex.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -3720,6 +3361,7 @@ complex.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
complex.$(OBJEXT): {$(VPATH)}internal/intern/error.h
complex.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
complex.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+complex.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
complex.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
complex.$(OBJEXT): {$(VPATH)}internal/intern/io.h
complex.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -3750,12 +3392,12 @@ complex.$(OBJEXT): {$(VPATH)}internal/memory.h
complex.$(OBJEXT): {$(VPATH)}internal/method.h
complex.$(OBJEXT): {$(VPATH)}internal/module.h
complex.$(OBJEXT): {$(VPATH)}internal/newobj.h
+complex.$(OBJEXT): {$(VPATH)}internal/rgengc.h
complex.$(OBJEXT): {$(VPATH)}internal/scan_args.h
complex.$(OBJEXT): {$(VPATH)}internal/special_consts.h
complex.$(OBJEXT): {$(VPATH)}internal/static_assert.h
complex.$(OBJEXT): {$(VPATH)}internal/stdalign.h
complex.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-complex.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
complex.$(OBJEXT): {$(VPATH)}internal/symbol.h
complex.$(OBJEXT): {$(VPATH)}internal/value.h
complex.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -3765,27 +3407,21 @@ complex.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
complex.$(OBJEXT): {$(VPATH)}method.h
complex.$(OBJEXT): {$(VPATH)}missing.h
complex.$(OBJEXT): {$(VPATH)}node.h
-complex.$(OBJEXT): {$(VPATH)}onigmo.h
-complex.$(OBJEXT): {$(VPATH)}oniguruma.h
complex.$(OBJEXT): {$(VPATH)}ruby_assert.h
complex.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-complex.$(OBJEXT): {$(VPATH)}rubyparser.h
complex.$(OBJEXT): {$(VPATH)}shape.h
complex.$(OBJEXT): {$(VPATH)}st.h
complex.$(OBJEXT): {$(VPATH)}subst.h
complex.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
complex.$(OBJEXT): {$(VPATH)}thread_native.h
complex.$(OBJEXT): {$(VPATH)}vm_core.h
-complex.$(OBJEXT): {$(VPATH)}vm_debug.h
complex.$(OBJEXT): {$(VPATH)}vm_opts.h
-complex.$(OBJEXT): {$(VPATH)}vm_sync.h
cont.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
cont.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
cont.$(OBJEXT): $(CCAN_DIR)/list/list.h
cont.$(OBJEXT): $(CCAN_DIR)/str/str.h
cont.$(OBJEXT): $(hdrdir)/ruby.h
cont.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-cont.$(OBJEXT): $(hdrdir)/ruby/version.h
cont.$(OBJEXT): $(top_srcdir)/internal/array.h
cont.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
cont.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -3798,30 +3434,9 @@ cont.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
cont.$(OBJEXT): $(top_srcdir)/internal/serial.h
cont.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
cont.$(OBJEXT): $(top_srcdir)/internal/string.h
-cont.$(OBJEXT): $(top_srcdir)/internal/thread.h
cont.$(OBJEXT): $(top_srcdir)/internal/variable.h
cont.$(OBJEXT): $(top_srcdir)/internal/vm.h
cont.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-cont.$(OBJEXT): $(top_srcdir)/prism/defines.h
-cont.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-cont.$(OBJEXT): $(top_srcdir)/prism/node.h
-cont.$(OBJEXT): $(top_srcdir)/prism/options.h
-cont.$(OBJEXT): $(top_srcdir)/prism/pack.h
-cont.$(OBJEXT): $(top_srcdir)/prism/parser.h
-cont.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-cont.$(OBJEXT): $(top_srcdir)/prism/prism.h
-cont.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-cont.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-cont.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
cont.$(OBJEXT): {$(VPATH)}$(COROUTINE_H)
cont.$(OBJEXT): {$(VPATH)}assert.h
cont.$(OBJEXT): {$(VPATH)}atomic.h
@@ -3842,6 +3457,7 @@ cont.$(OBJEXT): {$(VPATH)}defines.h
cont.$(OBJEXT): {$(VPATH)}encoding.h
cont.$(OBJEXT): {$(VPATH)}eval_intern.h
cont.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
+cont.$(OBJEXT): {$(VPATH)}gc.h
cont.$(OBJEXT): {$(VPATH)}id.h
cont.$(OBJEXT): {$(VPATH)}id_table.h
cont.$(OBJEXT): {$(VPATH)}intern.h
@@ -3884,7 +3500,6 @@ cont.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
cont.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
cont.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
cont.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-cont.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
cont.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
cont.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
cont.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -3953,6 +3568,7 @@ cont.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
cont.$(OBJEXT): {$(VPATH)}internal/intern/error.h
cont.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
cont.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+cont.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
cont.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
cont.$(OBJEXT): {$(VPATH)}internal/intern/io.h
cont.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -3983,12 +3599,12 @@ cont.$(OBJEXT): {$(VPATH)}internal/memory.h
cont.$(OBJEXT): {$(VPATH)}internal/method.h
cont.$(OBJEXT): {$(VPATH)}internal/module.h
cont.$(OBJEXT): {$(VPATH)}internal/newobj.h
+cont.$(OBJEXT): {$(VPATH)}internal/rgengc.h
cont.$(OBJEXT): {$(VPATH)}internal/scan_args.h
cont.$(OBJEXT): {$(VPATH)}internal/special_consts.h
cont.$(OBJEXT): {$(VPATH)}internal/static_assert.h
cont.$(OBJEXT): {$(VPATH)}internal/stdalign.h
cont.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-cont.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
cont.$(OBJEXT): {$(VPATH)}internal/symbol.h
cont.$(OBJEXT): {$(VPATH)}internal/value.h
cont.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -3998,19 +3614,14 @@ cont.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
cont.$(OBJEXT): {$(VPATH)}iseq.h
cont.$(OBJEXT): {$(VPATH)}method.h
cont.$(OBJEXT): {$(VPATH)}missing.h
+cont.$(OBJEXT): {$(VPATH)}mjit.h
cont.$(OBJEXT): {$(VPATH)}node.h
cont.$(OBJEXT): {$(VPATH)}onigmo.h
cont.$(OBJEXT): {$(VPATH)}oniguruma.h
-cont.$(OBJEXT): {$(VPATH)}prism/ast.h
-cont.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-cont.$(OBJEXT): {$(VPATH)}prism/version.h
-cont.$(OBJEXT): {$(VPATH)}prism_compile.h
cont.$(OBJEXT): {$(VPATH)}ractor.h
cont.$(OBJEXT): {$(VPATH)}ractor_core.h
-cont.$(OBJEXT): {$(VPATH)}rjit.h
cont.$(OBJEXT): {$(VPATH)}ruby_assert.h
cont.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-cont.$(OBJEXT): {$(VPATH)}rubyparser.h
cont.$(OBJEXT): {$(VPATH)}shape.h
cont.$(OBJEXT): {$(VPATH)}st.h
cont.$(OBJEXT): {$(VPATH)}subst.h
@@ -4032,7 +3643,6 @@ debug.$(OBJEXT): $(top_srcdir)/internal/class.h
debug.$(OBJEXT): $(top_srcdir)/internal/compilers.h
debug.$(OBJEXT): $(top_srcdir)/internal/gc.h
debug.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-debug.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
debug.$(OBJEXT): $(top_srcdir)/internal/serial.h
debug.$(OBJEXT): $(top_srcdir)/internal/signal.h
debug.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
@@ -4058,6 +3668,7 @@ debug.$(OBJEXT): {$(VPATH)}defines.h
debug.$(OBJEXT): {$(VPATH)}encindex.h
debug.$(OBJEXT): {$(VPATH)}encoding.h
debug.$(OBJEXT): {$(VPATH)}eval_intern.h
+debug.$(OBJEXT): {$(VPATH)}gc.h
debug.$(OBJEXT): {$(VPATH)}id.h
debug.$(OBJEXT): {$(VPATH)}id_table.h
debug.$(OBJEXT): {$(VPATH)}intern.h
@@ -4100,7 +3711,6 @@ debug.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
debug.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
debug.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
debug.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-debug.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
debug.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
debug.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
debug.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -4169,6 +3779,7 @@ debug.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
debug.$(OBJEXT): {$(VPATH)}internal/intern/error.h
debug.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
debug.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+debug.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
debug.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
debug.$(OBJEXT): {$(VPATH)}internal/intern/io.h
debug.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -4199,12 +3810,12 @@ debug.$(OBJEXT): {$(VPATH)}internal/memory.h
debug.$(OBJEXT): {$(VPATH)}internal/method.h
debug.$(OBJEXT): {$(VPATH)}internal/module.h
debug.$(OBJEXT): {$(VPATH)}internal/newobj.h
+debug.$(OBJEXT): {$(VPATH)}internal/rgengc.h
debug.$(OBJEXT): {$(VPATH)}internal/scan_args.h
debug.$(OBJEXT): {$(VPATH)}internal/special_consts.h
debug.$(OBJEXT): {$(VPATH)}internal/static_assert.h
debug.$(OBJEXT): {$(VPATH)}internal/stdalign.h
debug.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-debug.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
debug.$(OBJEXT): {$(VPATH)}internal/symbol.h
debug.$(OBJEXT): {$(VPATH)}internal/value.h
debug.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -4221,7 +3832,6 @@ debug.$(OBJEXT): {$(VPATH)}ractor.h
debug.$(OBJEXT): {$(VPATH)}ractor_core.h
debug.$(OBJEXT): {$(VPATH)}ruby_assert.h
debug.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-debug.$(OBJEXT): {$(VPATH)}rubyparser.h
debug.$(OBJEXT): {$(VPATH)}shape.h
debug.$(OBJEXT): {$(VPATH)}st.h
debug.$(OBJEXT): {$(VPATH)}subst.h
@@ -4233,7 +3843,6 @@ debug.$(OBJEXT): {$(VPATH)}vm_callinfo.h
debug.$(OBJEXT): {$(VPATH)}vm_core.h
debug.$(OBJEXT): {$(VPATH)}vm_debug.h
debug.$(OBJEXT): {$(VPATH)}vm_opts.h
-debug.$(OBJEXT): {$(VPATH)}vm_sync.h
debug_counter.$(OBJEXT): $(hdrdir)/ruby/ruby.h
debug_counter.$(OBJEXT): {$(VPATH)}assert.h
debug_counter.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -4288,7 +3897,6 @@ debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -4348,6 +3956,7 @@ debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/error.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/io.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -4378,12 +3987,12 @@ debug_counter.$(OBJEXT): {$(VPATH)}internal/memory.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/method.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/module.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/newobj.h
+debug_counter.$(OBJEXT): {$(VPATH)}internal/rgengc.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/scan_args.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/special_consts.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/static_assert.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/stdalign.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-debug_counter.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/symbol.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/value.h
debug_counter.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -4394,14 +4003,8 @@ debug_counter.$(OBJEXT): {$(VPATH)}missing.h
debug_counter.$(OBJEXT): {$(VPATH)}st.h
debug_counter.$(OBJEXT): {$(VPATH)}subst.h
debug_counter.$(OBJEXT): {$(VPATH)}thread_native.h
-dir.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-dir.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-dir.$(OBJEXT): $(CCAN_DIR)/list/list.h
-dir.$(OBJEXT): $(CCAN_DIR)/str/str.h
dir.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-dir.$(OBJEXT): $(hdrdir)/ruby/version.h
dir.$(OBJEXT): $(top_srcdir)/internal/array.h
-dir.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
dir.$(OBJEXT): $(top_srcdir)/internal/class.h
dir.$(OBJEXT): $(top_srcdir)/internal/compilers.h
dir.$(OBJEXT): $(top_srcdir)/internal/dir.h
@@ -4409,10 +4012,8 @@ dir.$(OBJEXT): $(top_srcdir)/internal/encoding.h
dir.$(OBJEXT): $(top_srcdir)/internal/error.h
dir.$(OBJEXT): $(top_srcdir)/internal/file.h
dir.$(OBJEXT): $(top_srcdir)/internal/gc.h
-dir.$(OBJEXT): $(top_srcdir)/internal/imemo.h
dir.$(OBJEXT): $(top_srcdir)/internal/io.h
dir.$(OBJEXT): $(top_srcdir)/internal/object.h
-dir.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
dir.$(OBJEXT): $(top_srcdir)/internal/serial.h
dir.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
dir.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -4420,7 +4021,6 @@ dir.$(OBJEXT): $(top_srcdir)/internal/variable.h
dir.$(OBJEXT): $(top_srcdir)/internal/vm.h
dir.$(OBJEXT): $(top_srcdir)/internal/warnings.h
dir.$(OBJEXT): {$(VPATH)}assert.h
-dir.$(OBJEXT): {$(VPATH)}atomic.h
dir.$(OBJEXT): {$(VPATH)}backward/2/assume.h
dir.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
dir.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -4480,7 +4080,6 @@ dir.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
dir.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
dir.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
dir.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-dir.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
dir.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
dir.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
dir.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -4549,6 +4148,7 @@ dir.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
dir.$(OBJEXT): {$(VPATH)}internal/intern/error.h
dir.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
dir.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+dir.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
dir.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
dir.$(OBJEXT): {$(VPATH)}internal/intern/io.h
dir.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -4579,12 +4179,12 @@ dir.$(OBJEXT): {$(VPATH)}internal/memory.h
dir.$(OBJEXT): {$(VPATH)}internal/method.h
dir.$(OBJEXT): {$(VPATH)}internal/module.h
dir.$(OBJEXT): {$(VPATH)}internal/newobj.h
+dir.$(OBJEXT): {$(VPATH)}internal/rgengc.h
dir.$(OBJEXT): {$(VPATH)}internal/scan_args.h
dir.$(OBJEXT): {$(VPATH)}internal/special_consts.h
dir.$(OBJEXT): {$(VPATH)}internal/static_assert.h
dir.$(OBJEXT): {$(VPATH)}internal/stdalign.h
dir.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-dir.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
dir.$(OBJEXT): {$(VPATH)}internal/symbol.h
dir.$(OBJEXT): {$(VPATH)}internal/value.h
dir.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -4592,23 +4192,14 @@ dir.$(OBJEXT): {$(VPATH)}internal/variable.h
dir.$(OBJEXT): {$(VPATH)}internal/warning_push.h
dir.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
dir.$(OBJEXT): {$(VPATH)}io.h
-dir.$(OBJEXT): {$(VPATH)}method.h
dir.$(OBJEXT): {$(VPATH)}missing.h
-dir.$(OBJEXT): {$(VPATH)}node.h
dir.$(OBJEXT): {$(VPATH)}onigmo.h
dir.$(OBJEXT): {$(VPATH)}oniguruma.h
-dir.$(OBJEXT): {$(VPATH)}ruby_assert.h
-dir.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-dir.$(OBJEXT): {$(VPATH)}rubyparser.h
dir.$(OBJEXT): {$(VPATH)}shape.h
dir.$(OBJEXT): {$(VPATH)}st.h
dir.$(OBJEXT): {$(VPATH)}subst.h
dir.$(OBJEXT): {$(VPATH)}thread.h
-dir.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-dir.$(OBJEXT): {$(VPATH)}thread_native.h
dir.$(OBJEXT): {$(VPATH)}util.h
-dir.$(OBJEXT): {$(VPATH)}vm_core.h
-dir.$(OBJEXT): {$(VPATH)}vm_opts.h
dln.$(OBJEXT): $(hdrdir)/ruby/ruby.h
dln.$(OBJEXT): $(top_srcdir)/internal/compilers.h
dln.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -4666,7 +4257,6 @@ dln.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
dln.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
dln.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
dln.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-dln.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
dln.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
dln.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
dln.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -4726,6 +4316,7 @@ dln.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
dln.$(OBJEXT): {$(VPATH)}internal/intern/error.h
dln.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
dln.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+dln.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
dln.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
dln.$(OBJEXT): {$(VPATH)}internal/intern/io.h
dln.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -4756,12 +4347,12 @@ dln.$(OBJEXT): {$(VPATH)}internal/memory.h
dln.$(OBJEXT): {$(VPATH)}internal/method.h
dln.$(OBJEXT): {$(VPATH)}internal/module.h
dln.$(OBJEXT): {$(VPATH)}internal/newobj.h
+dln.$(OBJEXT): {$(VPATH)}internal/rgengc.h
dln.$(OBJEXT): {$(VPATH)}internal/scan_args.h
dln.$(OBJEXT): {$(VPATH)}internal/special_consts.h
dln.$(OBJEXT): {$(VPATH)}internal/static_assert.h
dln.$(OBJEXT): {$(VPATH)}internal/stdalign.h
dln.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-dln.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
dln.$(OBJEXT): {$(VPATH)}internal/symbol.h
dln.$(OBJEXT): {$(VPATH)}internal/value.h
dln.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -4824,7 +4415,6 @@ dln_find.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
dln_find.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
dln_find.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
dln_find.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
dln_find.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
dln_find.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
dln_find.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -4884,6 +4474,7 @@ dln_find.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
dln_find.$(OBJEXT): {$(VPATH)}internal/intern/error.h
dln_find.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
dln_find.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
dln_find.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
dln_find.$(OBJEXT): {$(VPATH)}internal/intern/io.h
dln_find.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -4914,12 +4505,12 @@ dln_find.$(OBJEXT): {$(VPATH)}internal/memory.h
dln_find.$(OBJEXT): {$(VPATH)}internal/method.h
dln_find.$(OBJEXT): {$(VPATH)}internal/module.h
dln_find.$(OBJEXT): {$(VPATH)}internal/newobj.h
+dln_find.$(OBJEXT): {$(VPATH)}internal/rgengc.h
dln_find.$(OBJEXT): {$(VPATH)}internal/scan_args.h
dln_find.$(OBJEXT): {$(VPATH)}internal/special_consts.h
dln_find.$(OBJEXT): {$(VPATH)}internal/static_assert.h
dln_find.$(OBJEXT): {$(VPATH)}internal/stdalign.h
dln_find.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-dln_find.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
dln_find.$(OBJEXT): {$(VPATH)}internal/symbol.h
dln_find.$(OBJEXT): {$(VPATH)}internal/value.h
dln_find.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -4981,7 +4572,6 @@ dmydln.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
dmydln.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
dmydln.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
dmydln.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
dmydln.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
dmydln.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
dmydln.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -5041,6 +4631,7 @@ dmydln.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
dmydln.$(OBJEXT): {$(VPATH)}internal/intern/error.h
dmydln.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
dmydln.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
dmydln.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
dmydln.$(OBJEXT): {$(VPATH)}internal/intern/io.h
dmydln.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -5071,12 +4662,12 @@ dmydln.$(OBJEXT): {$(VPATH)}internal/memory.h
dmydln.$(OBJEXT): {$(VPATH)}internal/method.h
dmydln.$(OBJEXT): {$(VPATH)}internal/module.h
dmydln.$(OBJEXT): {$(VPATH)}internal/newobj.h
+dmydln.$(OBJEXT): {$(VPATH)}internal/rgengc.h
dmydln.$(OBJEXT): {$(VPATH)}internal/scan_args.h
dmydln.$(OBJEXT): {$(VPATH)}internal/special_consts.h
dmydln.$(OBJEXT): {$(VPATH)}internal/static_assert.h
dmydln.$(OBJEXT): {$(VPATH)}internal/stdalign.h
dmydln.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-dmydln.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
dmydln.$(OBJEXT): {$(VPATH)}internal/symbol.h
dmydln.$(OBJEXT): {$(VPATH)}internal/value.h
dmydln.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -5209,6 +4800,7 @@ enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -5239,6 +4831,7 @@ enc/ascii.$(OBJEXT): {$(VPATH)}internal/memory.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/method.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/module.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enc/ascii.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enc/ascii.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -5366,6 +4959,7 @@ enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -5396,6 +4990,7 @@ enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/memory.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/method.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/module.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enc/trans/newline.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -5523,6 +5118,7 @@ enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -5553,6 +5149,7 @@ enc/unicode.$(OBJEXT): {$(VPATH)}internal/memory.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/method.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/module.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enc/unicode.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enc/unicode.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -5691,6 +5288,7 @@ enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -5721,6 +5319,7 @@ enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/memory.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/method.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/module.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enc/us_ascii.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -5859,6 +5458,7 @@ enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -5889,6 +5489,7 @@ enc/utf_8.$(OBJEXT): {$(VPATH)}internal/memory.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/method.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/module.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enc/utf_8.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enc/utf_8.$(OBJEXT): {$(VPATH)}internal/static_assert.h
@@ -5906,22 +5507,14 @@ enc/utf_8.$(OBJEXT): {$(VPATH)}oniguruma.h
enc/utf_8.$(OBJEXT): {$(VPATH)}regenc.h
enc/utf_8.$(OBJEXT): {$(VPATH)}st.h
enc/utf_8.$(OBJEXT): {$(VPATH)}subst.h
-encoding.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-encoding.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-encoding.$(OBJEXT): $(CCAN_DIR)/list/list.h
-encoding.$(OBJEXT): $(CCAN_DIR)/str/str.h
encoding.$(OBJEXT): $(hdrdir)/ruby.h
encoding.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-encoding.$(OBJEXT): $(hdrdir)/ruby/version.h
-encoding.$(OBJEXT): $(top_srcdir)/internal/array.h
-encoding.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
encoding.$(OBJEXT): $(top_srcdir)/internal/class.h
encoding.$(OBJEXT): $(top_srcdir)/internal/compilers.h
encoding.$(OBJEXT): $(top_srcdir)/internal/enc.h
encoding.$(OBJEXT): $(top_srcdir)/internal/encoding.h
encoding.$(OBJEXT): $(top_srcdir)/internal/error.h
encoding.$(OBJEXT): $(top_srcdir)/internal/gc.h
-encoding.$(OBJEXT): $(top_srcdir)/internal/imemo.h
encoding.$(OBJEXT): $(top_srcdir)/internal/inits.h
encoding.$(OBJEXT): $(top_srcdir)/internal/load.h
encoding.$(OBJEXT): $(top_srcdir)/internal/object.h
@@ -5932,7 +5525,6 @@ encoding.$(OBJEXT): $(top_srcdir)/internal/variable.h
encoding.$(OBJEXT): $(top_srcdir)/internal/vm.h
encoding.$(OBJEXT): $(top_srcdir)/internal/warnings.h
encoding.$(OBJEXT): {$(VPATH)}assert.h
-encoding.$(OBJEXT): {$(VPATH)}atomic.h
encoding.$(OBJEXT): {$(VPATH)}backward/2/assume.h
encoding.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
encoding.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -5949,7 +5541,6 @@ encoding.$(OBJEXT): {$(VPATH)}defines.h
encoding.$(OBJEXT): {$(VPATH)}encindex.h
encoding.$(OBJEXT): {$(VPATH)}encoding.c
encoding.$(OBJEXT): {$(VPATH)}encoding.h
-encoding.$(OBJEXT): {$(VPATH)}id.h
encoding.$(OBJEXT): {$(VPATH)}id_table.h
encoding.$(OBJEXT): {$(VPATH)}intern.h
encoding.$(OBJEXT): {$(VPATH)}internal.h
@@ -5991,7 +5582,6 @@ encoding.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
encoding.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
encoding.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
encoding.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-encoding.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
encoding.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
encoding.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
encoding.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -6060,6 +5650,7 @@ encoding.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
encoding.$(OBJEXT): {$(VPATH)}internal/intern/error.h
encoding.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
encoding.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+encoding.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
encoding.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
encoding.$(OBJEXT): {$(VPATH)}internal/intern/io.h
encoding.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -6090,36 +5681,28 @@ encoding.$(OBJEXT): {$(VPATH)}internal/memory.h
encoding.$(OBJEXT): {$(VPATH)}internal/method.h
encoding.$(OBJEXT): {$(VPATH)}internal/module.h
encoding.$(OBJEXT): {$(VPATH)}internal/newobj.h
+encoding.$(OBJEXT): {$(VPATH)}internal/rgengc.h
encoding.$(OBJEXT): {$(VPATH)}internal/scan_args.h
encoding.$(OBJEXT): {$(VPATH)}internal/special_consts.h
encoding.$(OBJEXT): {$(VPATH)}internal/static_assert.h
encoding.$(OBJEXT): {$(VPATH)}internal/stdalign.h
encoding.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-encoding.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
encoding.$(OBJEXT): {$(VPATH)}internal/symbol.h
encoding.$(OBJEXT): {$(VPATH)}internal/value.h
encoding.$(OBJEXT): {$(VPATH)}internal/value_type.h
encoding.$(OBJEXT): {$(VPATH)}internal/variable.h
encoding.$(OBJEXT): {$(VPATH)}internal/warning_push.h
encoding.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-encoding.$(OBJEXT): {$(VPATH)}method.h
encoding.$(OBJEXT): {$(VPATH)}missing.h
-encoding.$(OBJEXT): {$(VPATH)}node.h
encoding.$(OBJEXT): {$(VPATH)}onigmo.h
encoding.$(OBJEXT): {$(VPATH)}oniguruma.h
encoding.$(OBJEXT): {$(VPATH)}regenc.h
encoding.$(OBJEXT): {$(VPATH)}ruby_assert.h
-encoding.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-encoding.$(OBJEXT): {$(VPATH)}rubyparser.h
encoding.$(OBJEXT): {$(VPATH)}shape.h
encoding.$(OBJEXT): {$(VPATH)}st.h
encoding.$(OBJEXT): {$(VPATH)}subst.h
-encoding.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-encoding.$(OBJEXT): {$(VPATH)}thread_native.h
encoding.$(OBJEXT): {$(VPATH)}util.h
-encoding.$(OBJEXT): {$(VPATH)}vm_core.h
encoding.$(OBJEXT): {$(VPATH)}vm_debug.h
-encoding.$(OBJEXT): {$(VPATH)}vm_opts.h
encoding.$(OBJEXT): {$(VPATH)}vm_sync.h
enum.$(OBJEXT): $(hdrdir)/ruby/ruby.h
enum.$(OBJEXT): $(top_srcdir)/internal/array.h
@@ -6201,7 +5784,6 @@ enum.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
enum.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
enum.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
enum.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-enum.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
enum.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
enum.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
enum.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -6270,6 +5852,7 @@ enum.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enum.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enum.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enum.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enum.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enum.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enum.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enum.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -6300,12 +5883,12 @@ enum.$(OBJEXT): {$(VPATH)}internal/memory.h
enum.$(OBJEXT): {$(VPATH)}internal/method.h
enum.$(OBJEXT): {$(VPATH)}internal/module.h
enum.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enum.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enum.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enum.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enum.$(OBJEXT): {$(VPATH)}internal/static_assert.h
enum.$(OBJEXT): {$(VPATH)}internal/stdalign.h
enum.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-enum.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
enum.$(OBJEXT): {$(VPATH)}internal/symbol.h
enum.$(OBJEXT): {$(VPATH)}internal/value.h
enum.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -6326,7 +5909,6 @@ enumerator.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
enumerator.$(OBJEXT): $(CCAN_DIR)/list/list.h
enumerator.$(OBJEXT): $(CCAN_DIR)/str/str.h
enumerator.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-enumerator.$(OBJEXT): $(hdrdir)/ruby/version.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/array.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -6342,12 +5924,10 @@ enumerator.$(OBJEXT): $(top_srcdir)/internal/imemo.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/numeric.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/range.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/rational.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/serial.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/string.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/struct.h
-enumerator.$(OBJEXT): $(top_srcdir)/internal/variable.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/vm.h
enumerator.$(OBJEXT): $(top_srcdir)/internal/warnings.h
enumerator.$(OBJEXT): {$(VPATH)}assert.h
@@ -6362,8 +5942,6 @@ enumerator.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
enumerator.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
enumerator.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
enumerator.$(OBJEXT): {$(VPATH)}config.h
-enumerator.$(OBJEXT): {$(VPATH)}constant.h
-enumerator.$(OBJEXT): {$(VPATH)}debug_counter.h
enumerator.$(OBJEXT): {$(VPATH)}defines.h
enumerator.$(OBJEXT): {$(VPATH)}encoding.h
enumerator.$(OBJEXT): {$(VPATH)}enumerator.c
@@ -6409,7 +5987,6 @@ enumerator.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
enumerator.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
enumerator.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
enumerator.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
enumerator.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
enumerator.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
enumerator.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -6478,6 +6055,7 @@ enumerator.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
enumerator.$(OBJEXT): {$(VPATH)}internal/intern/error.h
enumerator.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
enumerator.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
enumerator.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
enumerator.$(OBJEXT): {$(VPATH)}internal/intern/io.h
enumerator.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -6508,12 +6086,12 @@ enumerator.$(OBJEXT): {$(VPATH)}internal/memory.h
enumerator.$(OBJEXT): {$(VPATH)}internal/method.h
enumerator.$(OBJEXT): {$(VPATH)}internal/module.h
enumerator.$(OBJEXT): {$(VPATH)}internal/newobj.h
+enumerator.$(OBJEXT): {$(VPATH)}internal/rgengc.h
enumerator.$(OBJEXT): {$(VPATH)}internal/scan_args.h
enumerator.$(OBJEXT): {$(VPATH)}internal/special_consts.h
enumerator.$(OBJEXT): {$(VPATH)}internal/static_assert.h
enumerator.$(OBJEXT): {$(VPATH)}internal/stdalign.h
enumerator.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-enumerator.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
enumerator.$(OBJEXT): {$(VPATH)}internal/symbol.h
enumerator.$(OBJEXT): {$(VPATH)}internal/value.h
enumerator.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -6527,22 +6105,18 @@ enumerator.$(OBJEXT): {$(VPATH)}onigmo.h
enumerator.$(OBJEXT): {$(VPATH)}oniguruma.h
enumerator.$(OBJEXT): {$(VPATH)}ruby_assert.h
enumerator.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-enumerator.$(OBJEXT): {$(VPATH)}rubyparser.h
enumerator.$(OBJEXT): {$(VPATH)}shape.h
enumerator.$(OBJEXT): {$(VPATH)}st.h
enumerator.$(OBJEXT): {$(VPATH)}subst.h
enumerator.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
enumerator.$(OBJEXT): {$(VPATH)}thread_native.h
enumerator.$(OBJEXT): {$(VPATH)}vm_core.h
-enumerator.$(OBJEXT): {$(VPATH)}vm_debug.h
enumerator.$(OBJEXT): {$(VPATH)}vm_opts.h
-enumerator.$(OBJEXT): {$(VPATH)}vm_sync.h
error.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
error.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
error.$(OBJEXT): $(CCAN_DIR)/list/list.h
error.$(OBJEXT): $(CCAN_DIR)/str/str.h
error.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-error.$(OBJEXT): $(hdrdir)/ruby/version.h
error.$(OBJEXT): $(top_srcdir)/internal/array.h
error.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
error.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -6555,8 +6129,6 @@ error.$(OBJEXT): $(top_srcdir)/internal/imemo.h
error.$(OBJEXT): $(top_srcdir)/internal/io.h
error.$(OBJEXT): $(top_srcdir)/internal/load.h
error.$(OBJEXT): $(top_srcdir)/internal/object.h
-error.$(OBJEXT): $(top_srcdir)/internal/process.h
-error.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
error.$(OBJEXT): $(top_srcdir)/internal/serial.h
error.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
error.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -6579,7 +6151,6 @@ error.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
error.$(OBJEXT): {$(VPATH)}builtin.h
error.$(OBJEXT): {$(VPATH)}config.h
error.$(OBJEXT): {$(VPATH)}constant.h
-error.$(OBJEXT): {$(VPATH)}debug_counter.h
error.$(OBJEXT): {$(VPATH)}defines.h
error.$(OBJEXT): {$(VPATH)}encoding.h
error.$(OBJEXT): {$(VPATH)}error.c
@@ -6625,7 +6196,6 @@ error.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
error.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
error.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
error.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-error.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
error.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
error.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
error.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -6694,6 +6264,7 @@ error.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
error.$(OBJEXT): {$(VPATH)}internal/intern/error.h
error.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
error.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+error.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
error.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
error.$(OBJEXT): {$(VPATH)}internal/intern/io.h
error.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -6724,12 +6295,12 @@ error.$(OBJEXT): {$(VPATH)}internal/memory.h
error.$(OBJEXT): {$(VPATH)}internal/method.h
error.$(OBJEXT): {$(VPATH)}internal/module.h
error.$(OBJEXT): {$(VPATH)}internal/newobj.h
+error.$(OBJEXT): {$(VPATH)}internal/rgengc.h
error.$(OBJEXT): {$(VPATH)}internal/scan_args.h
error.$(OBJEXT): {$(VPATH)}internal/special_consts.h
error.$(OBJEXT): {$(VPATH)}internal/static_assert.h
error.$(OBJEXT): {$(VPATH)}internal/stdalign.h
error.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-error.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
error.$(OBJEXT): {$(VPATH)}internal/symbol.h
error.$(OBJEXT): {$(VPATH)}internal/value.h
error.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -6745,26 +6316,20 @@ error.$(OBJEXT): {$(VPATH)}onigmo.h
error.$(OBJEXT): {$(VPATH)}oniguruma.h
error.$(OBJEXT): {$(VPATH)}ruby_assert.h
error.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-error.$(OBJEXT): {$(VPATH)}rubyparser.h
error.$(OBJEXT): {$(VPATH)}shape.h
error.$(OBJEXT): {$(VPATH)}st.h
error.$(OBJEXT): {$(VPATH)}subst.h
error.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
error.$(OBJEXT): {$(VPATH)}thread_native.h
-error.$(OBJEXT): {$(VPATH)}util.h
error.$(OBJEXT): {$(VPATH)}vm_core.h
-error.$(OBJEXT): {$(VPATH)}vm_debug.h
error.$(OBJEXT): {$(VPATH)}vm_opts.h
-error.$(OBJEXT): {$(VPATH)}vm_sync.h
error.$(OBJEXT): {$(VPATH)}warning.rbinc
-error.$(OBJEXT): {$(VPATH)}yjit.h
eval.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
eval.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
eval.$(OBJEXT): $(CCAN_DIR)/list/list.h
eval.$(OBJEXT): $(CCAN_DIR)/str/str.h
eval.$(OBJEXT): $(hdrdir)/ruby.h
eval.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-eval.$(OBJEXT): $(hdrdir)/ruby/version.h
eval.$(OBJEXT): $(top_srcdir)/internal/array.h
eval.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
eval.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -6778,7 +6343,6 @@ eval.$(OBJEXT): $(top_srcdir)/internal/imemo.h
eval.$(OBJEXT): $(top_srcdir)/internal/inits.h
eval.$(OBJEXT): $(top_srcdir)/internal/io.h
eval.$(OBJEXT): $(top_srcdir)/internal/object.h
-eval.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
eval.$(OBJEXT): $(top_srcdir)/internal/serial.h
eval.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
eval.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -6786,26 +6350,6 @@ eval.$(OBJEXT): $(top_srcdir)/internal/thread.h
eval.$(OBJEXT): $(top_srcdir)/internal/variable.h
eval.$(OBJEXT): $(top_srcdir)/internal/vm.h
eval.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-eval.$(OBJEXT): $(top_srcdir)/prism/defines.h
-eval.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-eval.$(OBJEXT): $(top_srcdir)/prism/node.h
-eval.$(OBJEXT): $(top_srcdir)/prism/options.h
-eval.$(OBJEXT): $(top_srcdir)/prism/pack.h
-eval.$(OBJEXT): $(top_srcdir)/prism/parser.h
-eval.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-eval.$(OBJEXT): $(top_srcdir)/prism/prism.h
-eval.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-eval.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-eval.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
eval.$(OBJEXT): {$(VPATH)}assert.h
eval.$(OBJEXT): {$(VPATH)}atomic.h
eval.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -6827,6 +6371,7 @@ eval.$(OBJEXT): {$(VPATH)}eval_error.c
eval.$(OBJEXT): {$(VPATH)}eval_intern.h
eval.$(OBJEXT): {$(VPATH)}eval_jump.c
eval.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
+eval.$(OBJEXT): {$(VPATH)}gc.h
eval.$(OBJEXT): {$(VPATH)}id.h
eval.$(OBJEXT): {$(VPATH)}id_table.h
eval.$(OBJEXT): {$(VPATH)}intern.h
@@ -6869,7 +6414,6 @@ eval.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
eval.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
eval.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
eval.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-eval.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
eval.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
eval.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
eval.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -6938,6 +6482,7 @@ eval.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
eval.$(OBJEXT): {$(VPATH)}internal/intern/error.h
eval.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
eval.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+eval.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
eval.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
eval.$(OBJEXT): {$(VPATH)}internal/intern/io.h
eval.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -6968,12 +6513,12 @@ eval.$(OBJEXT): {$(VPATH)}internal/memory.h
eval.$(OBJEXT): {$(VPATH)}internal/method.h
eval.$(OBJEXT): {$(VPATH)}internal/module.h
eval.$(OBJEXT): {$(VPATH)}internal/newobj.h
+eval.$(OBJEXT): {$(VPATH)}internal/rgengc.h
eval.$(OBJEXT): {$(VPATH)}internal/scan_args.h
eval.$(OBJEXT): {$(VPATH)}internal/special_consts.h
eval.$(OBJEXT): {$(VPATH)}internal/static_assert.h
eval.$(OBJEXT): {$(VPATH)}internal/stdalign.h
eval.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-eval.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
eval.$(OBJEXT): {$(VPATH)}internal/symbol.h
eval.$(OBJEXT): {$(VPATH)}internal/value.h
eval.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -6984,22 +6529,17 @@ eval.$(OBJEXT): {$(VPATH)}io.h
eval.$(OBJEXT): {$(VPATH)}iseq.h
eval.$(OBJEXT): {$(VPATH)}method.h
eval.$(OBJEXT): {$(VPATH)}missing.h
+eval.$(OBJEXT): {$(VPATH)}mjit.h
eval.$(OBJEXT): {$(VPATH)}node.h
eval.$(OBJEXT): {$(VPATH)}onigmo.h
eval.$(OBJEXT): {$(VPATH)}oniguruma.h
-eval.$(OBJEXT): {$(VPATH)}prism/ast.h
-eval.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-eval.$(OBJEXT): {$(VPATH)}prism/version.h
-eval.$(OBJEXT): {$(VPATH)}prism_compile.h
eval.$(OBJEXT): {$(VPATH)}probes.dmyh
eval.$(OBJEXT): {$(VPATH)}probes.h
eval.$(OBJEXT): {$(VPATH)}probes_helper.h
eval.$(OBJEXT): {$(VPATH)}ractor.h
eval.$(OBJEXT): {$(VPATH)}ractor_core.h
-eval.$(OBJEXT): {$(VPATH)}rjit.h
eval.$(OBJEXT): {$(VPATH)}ruby_assert.h
eval.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-eval.$(OBJEXT): {$(VPATH)}rubyparser.h
eval.$(OBJEXT): {$(VPATH)}shape.h
eval.$(OBJEXT): {$(VPATH)}st.h
eval.$(OBJEXT): {$(VPATH)}subst.h
@@ -7009,7 +6549,6 @@ eval.$(OBJEXT): {$(VPATH)}vm.h
eval.$(OBJEXT): {$(VPATH)}vm_core.h
eval.$(OBJEXT): {$(VPATH)}vm_debug.h
eval.$(OBJEXT): {$(VPATH)}vm_opts.h
-eval.$(OBJEXT): {$(VPATH)}vm_sync.h
explicit_bzero.$(OBJEXT): {$(VPATH)}config.h
explicit_bzero.$(OBJEXT): {$(VPATH)}explicit_bzero.c
explicit_bzero.$(OBJEXT): {$(VPATH)}internal/attr/format.h
@@ -7025,12 +6564,7 @@ explicit_bzero.$(OBJEXT): {$(VPATH)}internal/config.h
explicit_bzero.$(OBJEXT): {$(VPATH)}internal/dllexport.h
explicit_bzero.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
explicit_bzero.$(OBJEXT): {$(VPATH)}missing.h
-file.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-file.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-file.$(OBJEXT): $(CCAN_DIR)/list/list.h
-file.$(OBJEXT): $(CCAN_DIR)/str/str.h
file.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-file.$(OBJEXT): $(hdrdir)/ruby/version.h
file.$(OBJEXT): $(top_srcdir)/internal/array.h
file.$(OBJEXT): $(top_srcdir)/internal/class.h
file.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -7109,7 +6643,6 @@ file.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
file.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
file.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
file.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-file.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
file.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
file.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
file.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -7178,6 +6711,7 @@ file.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
file.$(OBJEXT): {$(VPATH)}internal/intern/error.h
file.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
file.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+file.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
file.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
file.$(OBJEXT): {$(VPATH)}internal/intern/io.h
file.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -7208,12 +6742,12 @@ file.$(OBJEXT): {$(VPATH)}internal/memory.h
file.$(OBJEXT): {$(VPATH)}internal/method.h
file.$(OBJEXT): {$(VPATH)}internal/module.h
file.$(OBJEXT): {$(VPATH)}internal/newobj.h
+file.$(OBJEXT): {$(VPATH)}internal/rgengc.h
file.$(OBJEXT): {$(VPATH)}internal/scan_args.h
file.$(OBJEXT): {$(VPATH)}internal/special_consts.h
file.$(OBJEXT): {$(VPATH)}internal/static_assert.h
file.$(OBJEXT): {$(VPATH)}internal/stdalign.h
file.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-file.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
file.$(OBJEXT): {$(VPATH)}internal/symbol.h
file.$(OBJEXT): {$(VPATH)}internal/value.h
file.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -7228,7 +6762,6 @@ file.$(OBJEXT): {$(VPATH)}shape.h
file.$(OBJEXT): {$(VPATH)}st.h
file.$(OBJEXT): {$(VPATH)}subst.h
file.$(OBJEXT): {$(VPATH)}thread.h
-file.$(OBJEXT): {$(VPATH)}thread_native.h
file.$(OBJEXT): {$(VPATH)}util.h
gc.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
gc.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
@@ -7236,16 +6769,11 @@ gc.$(OBJEXT): $(CCAN_DIR)/list/list.h
gc.$(OBJEXT): $(CCAN_DIR)/str/str.h
gc.$(OBJEXT): $(hdrdir)/ruby.h
gc.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-gc.$(OBJEXT): $(hdrdir)/ruby/version.h
-gc.$(OBJEXT): $(top_srcdir)/gc/default.c
-gc.$(OBJEXT): $(top_srcdir)/gc/gc.h
-gc.$(OBJEXT): $(top_srcdir)/gc/gc_impl.h
gc.$(OBJEXT): $(top_srcdir)/internal/array.h
gc.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
gc.$(OBJEXT): $(top_srcdir)/internal/bignum.h
gc.$(OBJEXT): $(top_srcdir)/internal/bits.h
gc.$(OBJEXT): $(top_srcdir)/internal/class.h
-gc.$(OBJEXT): $(top_srcdir)/internal/compile.h
gc.$(OBJEXT): $(top_srcdir)/internal/compilers.h
gc.$(OBJEXT): $(top_srcdir)/internal/complex.h
gc.$(OBJEXT): $(top_srcdir)/internal/cont.h
@@ -7270,26 +6798,6 @@ gc.$(OBJEXT): $(top_srcdir)/internal/thread.h
gc.$(OBJEXT): $(top_srcdir)/internal/variable.h
gc.$(OBJEXT): $(top_srcdir)/internal/vm.h
gc.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-gc.$(OBJEXT): $(top_srcdir)/prism/defines.h
-gc.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-gc.$(OBJEXT): $(top_srcdir)/prism/node.h
-gc.$(OBJEXT): $(top_srcdir)/prism/options.h
-gc.$(OBJEXT): $(top_srcdir)/prism/pack.h
-gc.$(OBJEXT): $(top_srcdir)/prism/parser.h
-gc.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-gc.$(OBJEXT): $(top_srcdir)/prism/prism.h
-gc.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-gc.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-gc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
gc.$(OBJEXT): {$(VPATH)}assert.h
gc.$(OBJEXT): {$(VPATH)}atomic.h
gc.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -7304,13 +6812,13 @@ gc.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
gc.$(OBJEXT): {$(VPATH)}builtin.h
gc.$(OBJEXT): {$(VPATH)}config.h
gc.$(OBJEXT): {$(VPATH)}constant.h
-gc.$(OBJEXT): {$(VPATH)}darray.h
gc.$(OBJEXT): {$(VPATH)}debug.h
gc.$(OBJEXT): {$(VPATH)}debug_counter.h
gc.$(OBJEXT): {$(VPATH)}defines.h
gc.$(OBJEXT): {$(VPATH)}encoding.h
gc.$(OBJEXT): {$(VPATH)}eval_intern.h
gc.$(OBJEXT): {$(VPATH)}gc.c
+gc.$(OBJEXT): {$(VPATH)}gc.h
gc.$(OBJEXT): {$(VPATH)}gc.rbinc
gc.$(OBJEXT): {$(VPATH)}id.h
gc.$(OBJEXT): {$(VPATH)}id_table.h
@@ -7354,7 +6862,6 @@ gc.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
gc.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
gc.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
gc.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-gc.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
gc.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
gc.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
gc.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -7424,6 +6931,7 @@ gc.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
gc.$(OBJEXT): {$(VPATH)}internal/intern/error.h
gc.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
gc.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+gc.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
gc.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
gc.$(OBJEXT): {$(VPATH)}internal/intern/io.h
gc.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -7454,12 +6962,12 @@ gc.$(OBJEXT): {$(VPATH)}internal/memory.h
gc.$(OBJEXT): {$(VPATH)}internal/method.h
gc.$(OBJEXT): {$(VPATH)}internal/module.h
gc.$(OBJEXT): {$(VPATH)}internal/newobj.h
+gc.$(OBJEXT): {$(VPATH)}internal/rgengc.h
gc.$(OBJEXT): {$(VPATH)}internal/scan_args.h
gc.$(OBJEXT): {$(VPATH)}internal/special_consts.h
gc.$(OBJEXT): {$(VPATH)}internal/static_assert.h
gc.$(OBJEXT): {$(VPATH)}internal/stdalign.h
gc.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-gc.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
gc.$(OBJEXT): {$(VPATH)}internal/symbol.h
gc.$(OBJEXT): {$(VPATH)}internal/value.h
gc.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -7470,13 +6978,10 @@ gc.$(OBJEXT): {$(VPATH)}io.h
gc.$(OBJEXT): {$(VPATH)}iseq.h
gc.$(OBJEXT): {$(VPATH)}method.h
gc.$(OBJEXT): {$(VPATH)}missing.h
+gc.$(OBJEXT): {$(VPATH)}mjit.h
gc.$(OBJEXT): {$(VPATH)}node.h
gc.$(OBJEXT): {$(VPATH)}onigmo.h
gc.$(OBJEXT): {$(VPATH)}oniguruma.h
-gc.$(OBJEXT): {$(VPATH)}prism/ast.h
-gc.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-gc.$(OBJEXT): {$(VPATH)}prism/version.h
-gc.$(OBJEXT): {$(VPATH)}prism_compile.h
gc.$(OBJEXT): {$(VPATH)}probes.dmyh
gc.$(OBJEXT): {$(VPATH)}probes.h
gc.$(OBJEXT): {$(VPATH)}ractor.h
@@ -7485,10 +6990,8 @@ gc.$(OBJEXT): {$(VPATH)}re.h
gc.$(OBJEXT): {$(VPATH)}regenc.h
gc.$(OBJEXT): {$(VPATH)}regex.h
gc.$(OBJEXT): {$(VPATH)}regint.h
-gc.$(OBJEXT): {$(VPATH)}rjit.h
gc.$(OBJEXT): {$(VPATH)}ruby_assert.h
gc.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-gc.$(OBJEXT): {$(VPATH)}rubyparser.h
gc.$(OBJEXT): {$(VPATH)}shape.h
gc.$(OBJEXT): {$(VPATH)}st.h
gc.$(OBJEXT): {$(VPATH)}subst.h
@@ -7496,14 +6999,13 @@ gc.$(OBJEXT): {$(VPATH)}symbol.h
gc.$(OBJEXT): {$(VPATH)}thread.h
gc.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
gc.$(OBJEXT): {$(VPATH)}thread_native.h
+gc.$(OBJEXT): {$(VPATH)}transient_heap.h
gc.$(OBJEXT): {$(VPATH)}util.h
-gc.$(OBJEXT): {$(VPATH)}vm.h
gc.$(OBJEXT): {$(VPATH)}vm_callinfo.h
gc.$(OBJEXT): {$(VPATH)}vm_core.h
gc.$(OBJEXT): {$(VPATH)}vm_debug.h
gc.$(OBJEXT): {$(VPATH)}vm_opts.h
gc.$(OBJEXT): {$(VPATH)}vm_sync.h
-gc.$(OBJEXT): {$(VPATH)}yjit.h
goruby.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
goruby.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
goruby.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -7512,43 +7014,14 @@ goruby.$(OBJEXT): $(hdrdir)/ruby.h
goruby.$(OBJEXT): $(hdrdir)/ruby/ruby.h
goruby.$(OBJEXT): $(top_srcdir)/internal/array.h
goruby.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/bits.h
goruby.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/complex.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
goruby.$(OBJEXT): $(top_srcdir)/internal/gc.h
goruby.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/parse.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/rational.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-goruby.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
goruby.$(OBJEXT): $(top_srcdir)/internal/serial.h
goruby.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
goruby.$(OBJEXT): $(top_srcdir)/internal/variable.h
goruby.$(OBJEXT): $(top_srcdir)/internal/vm.h
goruby.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/defines.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/node.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/options.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/pack.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/parser.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/prism.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-goruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
goruby.$(OBJEXT): {$(VPATH)}assert.h
goruby.$(OBJEXT): {$(VPATH)}atomic.h
goruby.$(OBJEXT): {$(VPATH)}backward.h
@@ -7564,8 +7037,7 @@ goruby.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
goruby.$(OBJEXT): {$(VPATH)}config.h
goruby.$(OBJEXT): {$(VPATH)}constant.h
goruby.$(OBJEXT): {$(VPATH)}defines.h
-goruby.$(OBJEXT): {$(VPATH)}encoding.h
-goruby.$(OBJEXT): {$(VPATH)}golf_prelude.rbbin
+goruby.$(OBJEXT): {$(VPATH)}golf_prelude.c
goruby.$(OBJEXT): {$(VPATH)}goruby.c
goruby.$(OBJEXT): {$(VPATH)}id.h
goruby.$(OBJEXT): {$(VPATH)}id_table.h
@@ -7608,8 +7080,8 @@ goruby.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+goruby.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-goruby.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
goruby.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -7642,15 +7114,6 @@ goruby.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
goruby.$(OBJEXT): {$(VPATH)}internal/ctype.h
goruby.$(OBJEXT): {$(VPATH)}internal/dllexport.h
goruby.$(OBJEXT): {$(VPATH)}internal/dosish.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-goruby.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
goruby.$(OBJEXT): {$(VPATH)}internal/error.h
goruby.$(OBJEXT): {$(VPATH)}internal/eval.h
goruby.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -7678,6 +7141,7 @@ goruby.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
goruby.$(OBJEXT): {$(VPATH)}internal/intern/error.h
goruby.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
goruby.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+goruby.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
goruby.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
goruby.$(OBJEXT): {$(VPATH)}internal/intern/io.h
goruby.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -7708,12 +7172,12 @@ goruby.$(OBJEXT): {$(VPATH)}internal/memory.h
goruby.$(OBJEXT): {$(VPATH)}internal/method.h
goruby.$(OBJEXT): {$(VPATH)}internal/module.h
goruby.$(OBJEXT): {$(VPATH)}internal/newobj.h
+goruby.$(OBJEXT): {$(VPATH)}internal/rgengc.h
goruby.$(OBJEXT): {$(VPATH)}internal/scan_args.h
goruby.$(OBJEXT): {$(VPATH)}internal/special_consts.h
goruby.$(OBJEXT): {$(VPATH)}internal/static_assert.h
goruby.$(OBJEXT): {$(VPATH)}internal/stdalign.h
goruby.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-goruby.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
goruby.$(OBJEXT): {$(VPATH)}internal/symbol.h
goruby.$(OBJEXT): {$(VPATH)}internal/value.h
goruby.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -7725,15 +7189,8 @@ goruby.$(OBJEXT): {$(VPATH)}main.c
goruby.$(OBJEXT): {$(VPATH)}method.h
goruby.$(OBJEXT): {$(VPATH)}missing.h
goruby.$(OBJEXT): {$(VPATH)}node.h
-goruby.$(OBJEXT): {$(VPATH)}onigmo.h
-goruby.$(OBJEXT): {$(VPATH)}oniguruma.h
-goruby.$(OBJEXT): {$(VPATH)}prism/ast.h
-goruby.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-goruby.$(OBJEXT): {$(VPATH)}prism/version.h
-goruby.$(OBJEXT): {$(VPATH)}prism_compile.h
goruby.$(OBJEXT): {$(VPATH)}ruby_assert.h
goruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-goruby.$(OBJEXT): {$(VPATH)}rubyparser.h
goruby.$(OBJEXT): {$(VPATH)}shape.h
goruby.$(OBJEXT): {$(VPATH)}st.h
goruby.$(OBJEXT): {$(VPATH)}subst.h
@@ -7747,7 +7204,6 @@ hash.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
hash.$(OBJEXT): $(CCAN_DIR)/list/list.h
hash.$(OBJEXT): $(CCAN_DIR)/str/str.h
hash.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-hash.$(OBJEXT): $(hdrdir)/ruby/version.h
hash.$(OBJEXT): $(top_srcdir)/internal/array.h
hash.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
hash.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -7761,9 +7217,7 @@ hash.$(OBJEXT): $(top_srcdir)/internal/hash.h
hash.$(OBJEXT): $(top_srcdir)/internal/imemo.h
hash.$(OBJEXT): $(top_srcdir)/internal/object.h
hash.$(OBJEXT): $(top_srcdir)/internal/proc.h
-hash.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
hash.$(OBJEXT): $(top_srcdir)/internal/serial.h
-hash.$(OBJEXT): $(top_srcdir)/internal/st.h
hash.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
hash.$(OBJEXT): $(top_srcdir)/internal/string.h
hash.$(OBJEXT): $(top_srcdir)/internal/symbol.h
@@ -7772,26 +7226,6 @@ hash.$(OBJEXT): $(top_srcdir)/internal/time.h
hash.$(OBJEXT): $(top_srcdir)/internal/variable.h
hash.$(OBJEXT): $(top_srcdir)/internal/vm.h
hash.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-hash.$(OBJEXT): $(top_srcdir)/prism/defines.h
-hash.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-hash.$(OBJEXT): $(top_srcdir)/prism/node.h
-hash.$(OBJEXT): $(top_srcdir)/prism/options.h
-hash.$(OBJEXT): $(top_srcdir)/prism/pack.h
-hash.$(OBJEXT): $(top_srcdir)/prism/parser.h
-hash.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-hash.$(OBJEXT): $(top_srcdir)/prism/prism.h
-hash.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-hash.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-hash.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
hash.$(OBJEXT): {$(VPATH)}assert.h
hash.$(OBJEXT): {$(VPATH)}atomic.h
hash.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -7803,14 +7237,12 @@ hash.$(OBJEXT): {$(VPATH)}backward/2/limits.h
hash.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
hash.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
hash.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-hash.$(OBJEXT): {$(VPATH)}builtin.h
hash.$(OBJEXT): {$(VPATH)}config.h
hash.$(OBJEXT): {$(VPATH)}constant.h
hash.$(OBJEXT): {$(VPATH)}debug_counter.h
hash.$(OBJEXT): {$(VPATH)}defines.h
hash.$(OBJEXT): {$(VPATH)}encoding.h
hash.$(OBJEXT): {$(VPATH)}hash.c
-hash.$(OBJEXT): {$(VPATH)}hash.rbinc
hash.$(OBJEXT): {$(VPATH)}id.h
hash.$(OBJEXT): {$(VPATH)}id_table.h
hash.$(OBJEXT): {$(VPATH)}intern.h
@@ -7853,7 +7285,6 @@ hash.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
hash.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
hash.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
hash.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-hash.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
hash.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
hash.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
hash.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -7922,6 +7353,7 @@ hash.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
hash.$(OBJEXT): {$(VPATH)}internal/intern/error.h
hash.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
hash.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+hash.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
hash.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
hash.$(OBJEXT): {$(VPATH)}internal/intern/io.h
hash.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -7952,13 +7384,12 @@ hash.$(OBJEXT): {$(VPATH)}internal/memory.h
hash.$(OBJEXT): {$(VPATH)}internal/method.h
hash.$(OBJEXT): {$(VPATH)}internal/module.h
hash.$(OBJEXT): {$(VPATH)}internal/newobj.h
+hash.$(OBJEXT): {$(VPATH)}internal/rgengc.h
hash.$(OBJEXT): {$(VPATH)}internal/scan_args.h
hash.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-hash.$(OBJEXT): {$(VPATH)}internal/st.h
hash.$(OBJEXT): {$(VPATH)}internal/static_assert.h
hash.$(OBJEXT): {$(VPATH)}internal/stdalign.h
hash.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-hash.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
hash.$(OBJEXT): {$(VPATH)}internal/symbol.h
hash.$(OBJEXT): {$(VPATH)}internal/value.h
hash.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -7971,232 +7402,23 @@ hash.$(OBJEXT): {$(VPATH)}missing.h
hash.$(OBJEXT): {$(VPATH)}node.h
hash.$(OBJEXT): {$(VPATH)}onigmo.h
hash.$(OBJEXT): {$(VPATH)}oniguruma.h
-hash.$(OBJEXT): {$(VPATH)}prism/ast.h
-hash.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-hash.$(OBJEXT): {$(VPATH)}prism/version.h
-hash.$(OBJEXT): {$(VPATH)}prism_compile.h
hash.$(OBJEXT): {$(VPATH)}probes.dmyh
hash.$(OBJEXT): {$(VPATH)}probes.h
hash.$(OBJEXT): {$(VPATH)}ractor.h
hash.$(OBJEXT): {$(VPATH)}ruby_assert.h
hash.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-hash.$(OBJEXT): {$(VPATH)}rubyparser.h
hash.$(OBJEXT): {$(VPATH)}shape.h
hash.$(OBJEXT): {$(VPATH)}st.h
hash.$(OBJEXT): {$(VPATH)}subst.h
hash.$(OBJEXT): {$(VPATH)}symbol.h
hash.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
hash.$(OBJEXT): {$(VPATH)}thread_native.h
+hash.$(OBJEXT): {$(VPATH)}transient_heap.h
hash.$(OBJEXT): {$(VPATH)}util.h
hash.$(OBJEXT): {$(VPATH)}vm_core.h
hash.$(OBJEXT): {$(VPATH)}vm_debug.h
hash.$(OBJEXT): {$(VPATH)}vm_opts.h
hash.$(OBJEXT): {$(VPATH)}vm_sync.h
-imemo.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-imemo.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-imemo.$(OBJEXT): $(CCAN_DIR)/list/list.h
-imemo.$(OBJEXT): $(CCAN_DIR)/str/str.h
-imemo.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/array.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/class.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/gc.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/serial.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/variable.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/vm.h
-imemo.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-imemo.$(OBJEXT): {$(VPATH)}assert.h
-imemo.$(OBJEXT): {$(VPATH)}atomic.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-imemo.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-imemo.$(OBJEXT): {$(VPATH)}config.h
-imemo.$(OBJEXT): {$(VPATH)}constant.h
-imemo.$(OBJEXT): {$(VPATH)}debug_counter.h
-imemo.$(OBJEXT): {$(VPATH)}defines.h
-imemo.$(OBJEXT): {$(VPATH)}encoding.h
-imemo.$(OBJEXT): {$(VPATH)}id.h
-imemo.$(OBJEXT): {$(VPATH)}id_table.h
-imemo.$(OBJEXT): {$(VPATH)}imemo.c
-imemo.$(OBJEXT): {$(VPATH)}intern.h
-imemo.$(OBJEXT): {$(VPATH)}internal.h
-imemo.$(OBJEXT): {$(VPATH)}internal/abi.h
-imemo.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-imemo.$(OBJEXT): {$(VPATH)}internal/assume.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-imemo.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-imemo.$(OBJEXT): {$(VPATH)}internal/cast.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-imemo.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-imemo.$(OBJEXT): {$(VPATH)}internal/config.h
-imemo.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-imemo.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-imemo.$(OBJEXT): {$(VPATH)}internal/ctype.h
-imemo.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-imemo.$(OBJEXT): {$(VPATH)}internal/dosish.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-imemo.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-imemo.$(OBJEXT): {$(VPATH)}internal/error.h
-imemo.$(OBJEXT): {$(VPATH)}internal/eval.h
-imemo.$(OBJEXT): {$(VPATH)}internal/event.h
-imemo.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-imemo.$(OBJEXT): {$(VPATH)}internal/gc.h
-imemo.$(OBJEXT): {$(VPATH)}internal/glob.h
-imemo.$(OBJEXT): {$(VPATH)}internal/globals.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-imemo.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-imemo.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-imemo.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-imemo.$(OBJEXT): {$(VPATH)}internal/iterator.h
-imemo.$(OBJEXT): {$(VPATH)}internal/memory.h
-imemo.$(OBJEXT): {$(VPATH)}internal/method.h
-imemo.$(OBJEXT): {$(VPATH)}internal/module.h
-imemo.$(OBJEXT): {$(VPATH)}internal/newobj.h
-imemo.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-imemo.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-imemo.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-imemo.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-imemo.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-imemo.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-imemo.$(OBJEXT): {$(VPATH)}internal/symbol.h
-imemo.$(OBJEXT): {$(VPATH)}internal/value.h
-imemo.$(OBJEXT): {$(VPATH)}internal/value_type.h
-imemo.$(OBJEXT): {$(VPATH)}internal/variable.h
-imemo.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-imemo.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-imemo.$(OBJEXT): {$(VPATH)}method.h
-imemo.$(OBJEXT): {$(VPATH)}missing.h
-imemo.$(OBJEXT): {$(VPATH)}node.h
-imemo.$(OBJEXT): {$(VPATH)}onigmo.h
-imemo.$(OBJEXT): {$(VPATH)}oniguruma.h
-imemo.$(OBJEXT): {$(VPATH)}ruby_assert.h
-imemo.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-imemo.$(OBJEXT): {$(VPATH)}rubyparser.h
-imemo.$(OBJEXT): {$(VPATH)}shape.h
-imemo.$(OBJEXT): {$(VPATH)}st.h
-imemo.$(OBJEXT): {$(VPATH)}subst.h
-imemo.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-imemo.$(OBJEXT): {$(VPATH)}thread_native.h
-imemo.$(OBJEXT): {$(VPATH)}vm_callinfo.h
-imemo.$(OBJEXT): {$(VPATH)}vm_core.h
-imemo.$(OBJEXT): {$(VPATH)}vm_debug.h
-imemo.$(OBJEXT): {$(VPATH)}vm_opts.h
-imemo.$(OBJEXT): {$(VPATH)}vm_sync.h
inits.$(OBJEXT): $(hdrdir)/ruby.h
inits.$(OBJEXT): $(hdrdir)/ruby/ruby.h
inits.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -8255,7 +7477,6 @@ inits.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
inits.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
inits.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
inits.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-inits.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
inits.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
inits.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
inits.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -8315,6 +7536,7 @@ inits.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
inits.$(OBJEXT): {$(VPATH)}internal/intern/error.h
inits.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
inits.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+inits.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
inits.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
inits.$(OBJEXT): {$(VPATH)}internal/intern/io.h
inits.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -8345,12 +7567,12 @@ inits.$(OBJEXT): {$(VPATH)}internal/memory.h
inits.$(OBJEXT): {$(VPATH)}internal/method.h
inits.$(OBJEXT): {$(VPATH)}internal/module.h
inits.$(OBJEXT): {$(VPATH)}internal/newobj.h
+inits.$(OBJEXT): {$(VPATH)}internal/rgengc.h
inits.$(OBJEXT): {$(VPATH)}internal/scan_args.h
inits.$(OBJEXT): {$(VPATH)}internal/special_consts.h
inits.$(OBJEXT): {$(VPATH)}internal/static_assert.h
inits.$(OBJEXT): {$(VPATH)}internal/stdalign.h
inits.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-inits.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
inits.$(OBJEXT): {$(VPATH)}internal/symbol.h
inits.$(OBJEXT): {$(VPATH)}internal/value.h
inits.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -8366,7 +7588,6 @@ io.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
io.$(OBJEXT): $(CCAN_DIR)/list/list.h
io.$(OBJEXT): $(CCAN_DIR)/str/str.h
io.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-io.$(OBJEXT): $(hdrdir)/ruby/version.h
io.$(OBJEXT): $(top_srcdir)/internal/array.h
io.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
io.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -8383,7 +7604,6 @@ io.$(OBJEXT): $(top_srcdir)/internal/io.h
io.$(OBJEXT): $(top_srcdir)/internal/numeric.h
io.$(OBJEXT): $(top_srcdir)/internal/object.h
io.$(OBJEXT): $(top_srcdir)/internal/process.h
-io.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
io.$(OBJEXT): $(top_srcdir)/internal/serial.h
io.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
io.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -8406,7 +7626,6 @@ io.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
io.$(OBJEXT): {$(VPATH)}builtin.h
io.$(OBJEXT): {$(VPATH)}config.h
io.$(OBJEXT): {$(VPATH)}constant.h
-io.$(OBJEXT): {$(VPATH)}debug_counter.h
io.$(OBJEXT): {$(VPATH)}defines.h
io.$(OBJEXT): {$(VPATH)}dln.h
io.$(OBJEXT): {$(VPATH)}encindex.h
@@ -8454,7 +7673,6 @@ io.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
io.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
io.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
io.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-io.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
io.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
io.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
io.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -8523,6 +7741,7 @@ io.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
io.$(OBJEXT): {$(VPATH)}internal/intern/error.h
io.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
io.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+io.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
io.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
io.$(OBJEXT): {$(VPATH)}internal/intern/io.h
io.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -8553,12 +7772,12 @@ io.$(OBJEXT): {$(VPATH)}internal/memory.h
io.$(OBJEXT): {$(VPATH)}internal/method.h
io.$(OBJEXT): {$(VPATH)}internal/module.h
io.$(OBJEXT): {$(VPATH)}internal/newobj.h
+io.$(OBJEXT): {$(VPATH)}internal/rgengc.h
io.$(OBJEXT): {$(VPATH)}internal/scan_args.h
io.$(OBJEXT): {$(VPATH)}internal/special_consts.h
io.$(OBJEXT): {$(VPATH)}internal/static_assert.h
io.$(OBJEXT): {$(VPATH)}internal/stdalign.h
io.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-io.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
io.$(OBJEXT): {$(VPATH)}internal/symbol.h
io.$(OBJEXT): {$(VPATH)}internal/value.h
io.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -8577,7 +7796,6 @@ io.$(OBJEXT): {$(VPATH)}oniguruma.h
io.$(OBJEXT): {$(VPATH)}ractor.h
io.$(OBJEXT): {$(VPATH)}ruby_assert.h
io.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-io.$(OBJEXT): {$(VPATH)}rubyparser.h
io.$(OBJEXT): {$(VPATH)}shape.h
io.$(OBJEXT): {$(VPATH)}st.h
io.$(OBJEXT): {$(VPATH)}subst.h
@@ -8586,22 +7804,14 @@ io.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
io.$(OBJEXT): {$(VPATH)}thread_native.h
io.$(OBJEXT): {$(VPATH)}util.h
io.$(OBJEXT): {$(VPATH)}vm_core.h
-io.$(OBJEXT): {$(VPATH)}vm_debug.h
io.$(OBJEXT): {$(VPATH)}vm_opts.h
-io.$(OBJEXT): {$(VPATH)}vm_sync.h
-io_buffer.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-io_buffer.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-io_buffer.$(OBJEXT): $(CCAN_DIR)/list/list.h
-io_buffer.$(OBJEXT): $(CCAN_DIR)/str/str.h
io_buffer.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-io_buffer.$(OBJEXT): $(hdrdir)/ruby/version.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/array.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/bignum.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/bits.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/compilers.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/error.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-io_buffer.$(OBJEXT): $(top_srcdir)/internal/io.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/numeric.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/serial.h
io_buffer.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
@@ -8662,7 +7872,6 @@ io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -8731,6 +7940,7 @@ io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/error.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/io.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -8761,12 +7971,12 @@ io_buffer.$(OBJEXT): {$(VPATH)}internal/memory.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/method.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/module.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/newobj.h
+io_buffer.$(OBJEXT): {$(VPATH)}internal/rgengc.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/scan_args.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/special_consts.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/static_assert.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/stdalign.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-io_buffer.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/symbol.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/value.h
io_buffer.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -8781,33 +7991,24 @@ io_buffer.$(OBJEXT): {$(VPATH)}onigmo.h
io_buffer.$(OBJEXT): {$(VPATH)}oniguruma.h
io_buffer.$(OBJEXT): {$(VPATH)}st.h
io_buffer.$(OBJEXT): {$(VPATH)}subst.h
-io_buffer.$(OBJEXT): {$(VPATH)}thread_native.h
iseq.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
iseq.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
iseq.$(OBJEXT): $(CCAN_DIR)/list/list.h
iseq.$(OBJEXT): $(CCAN_DIR)/str/str.h
iseq.$(OBJEXT): $(hdrdir)/ruby.h
iseq.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-iseq.$(OBJEXT): $(hdrdir)/ruby/version.h
iseq.$(OBJEXT): $(top_srcdir)/internal/array.h
iseq.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/bignum.h
iseq.$(OBJEXT): $(top_srcdir)/internal/bits.h
iseq.$(OBJEXT): $(top_srcdir)/internal/class.h
iseq.$(OBJEXT): $(top_srcdir)/internal/compile.h
iseq.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/complex.h
iseq.$(OBJEXT): $(top_srcdir)/internal/error.h
iseq.$(OBJEXT): $(top_srcdir)/internal/file.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
iseq.$(OBJEXT): $(top_srcdir)/internal/gc.h
iseq.$(OBJEXT): $(top_srcdir)/internal/hash.h
iseq.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/io.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/numeric.h
iseq.$(OBJEXT): $(top_srcdir)/internal/parse.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/rational.h
-iseq.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
iseq.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
iseq.$(OBJEXT): $(top_srcdir)/internal/serial.h
iseq.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
@@ -8817,26 +8018,6 @@ iseq.$(OBJEXT): $(top_srcdir)/internal/thread.h
iseq.$(OBJEXT): $(top_srcdir)/internal/variable.h
iseq.$(OBJEXT): $(top_srcdir)/internal/vm.h
iseq.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/defines.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/node.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/options.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/pack.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/parser.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/prism.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-iseq.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
iseq.$(OBJEXT): {$(VPATH)}assert.h
iseq.$(OBJEXT): {$(VPATH)}atomic.h
iseq.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -8855,6 +8036,7 @@ iseq.$(OBJEXT): {$(VPATH)}debug_counter.h
iseq.$(OBJEXT): {$(VPATH)}defines.h
iseq.$(OBJEXT): {$(VPATH)}encoding.h
iseq.$(OBJEXT): {$(VPATH)}eval_intern.h
+iseq.$(OBJEXT): {$(VPATH)}gc.h
iseq.$(OBJEXT): {$(VPATH)}id.h
iseq.$(OBJEXT): {$(VPATH)}id_table.h
iseq.$(OBJEXT): {$(VPATH)}insns.def
@@ -8900,7 +8082,6 @@ iseq.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
iseq.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
iseq.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
iseq.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-iseq.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
iseq.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
iseq.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
iseq.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -8969,6 +8150,7 @@ iseq.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
iseq.$(OBJEXT): {$(VPATH)}internal/intern/error.h
iseq.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
iseq.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+iseq.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
iseq.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
iseq.$(OBJEXT): {$(VPATH)}internal/intern/io.h
iseq.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -8999,36 +8181,30 @@ iseq.$(OBJEXT): {$(VPATH)}internal/memory.h
iseq.$(OBJEXT): {$(VPATH)}internal/method.h
iseq.$(OBJEXT): {$(VPATH)}internal/module.h
iseq.$(OBJEXT): {$(VPATH)}internal/newobj.h
+iseq.$(OBJEXT): {$(VPATH)}internal/rgengc.h
iseq.$(OBJEXT): {$(VPATH)}internal/scan_args.h
iseq.$(OBJEXT): {$(VPATH)}internal/special_consts.h
iseq.$(OBJEXT): {$(VPATH)}internal/static_assert.h
iseq.$(OBJEXT): {$(VPATH)}internal/stdalign.h
iseq.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-iseq.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
iseq.$(OBJEXT): {$(VPATH)}internal/symbol.h
iseq.$(OBJEXT): {$(VPATH)}internal/value.h
iseq.$(OBJEXT): {$(VPATH)}internal/value_type.h
iseq.$(OBJEXT): {$(VPATH)}internal/variable.h
iseq.$(OBJEXT): {$(VPATH)}internal/warning_push.h
iseq.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-iseq.$(OBJEXT): {$(VPATH)}io.h
iseq.$(OBJEXT): {$(VPATH)}iseq.c
iseq.$(OBJEXT): {$(VPATH)}iseq.h
iseq.$(OBJEXT): {$(VPATH)}method.h
iseq.$(OBJEXT): {$(VPATH)}missing.h
+iseq.$(OBJEXT): {$(VPATH)}mjit.h
iseq.$(OBJEXT): {$(VPATH)}node.h
+iseq.$(OBJEXT): {$(VPATH)}node_name.inc
iseq.$(OBJEXT): {$(VPATH)}onigmo.h
iseq.$(OBJEXT): {$(VPATH)}oniguruma.h
-iseq.$(OBJEXT): {$(VPATH)}prism/ast.h
-iseq.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-iseq.$(OBJEXT): {$(VPATH)}prism/prism.h
-iseq.$(OBJEXT): {$(VPATH)}prism/version.h
-iseq.$(OBJEXT): {$(VPATH)}prism_compile.h
iseq.$(OBJEXT): {$(VPATH)}ractor.h
-iseq.$(OBJEXT): {$(VPATH)}rjit.h
iseq.$(OBJEXT): {$(VPATH)}ruby_assert.h
iseq.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-iseq.$(OBJEXT): {$(VPATH)}rubyparser.h
iseq.$(OBJEXT): {$(VPATH)}shape.h
iseq.$(OBJEXT): {$(VPATH)}st.h
iseq.$(OBJEXT): {$(VPATH)}subst.h
@@ -9037,35 +8213,23 @@ iseq.$(OBJEXT): {$(VPATH)}thread_native.h
iseq.$(OBJEXT): {$(VPATH)}util.h
iseq.$(OBJEXT): {$(VPATH)}vm_callinfo.h
iseq.$(OBJEXT): {$(VPATH)}vm_core.h
-iseq.$(OBJEXT): {$(VPATH)}vm_debug.h
iseq.$(OBJEXT): {$(VPATH)}vm_opts.h
-iseq.$(OBJEXT): {$(VPATH)}vm_sync.h
iseq.$(OBJEXT): {$(VPATH)}yjit.h
load.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
load.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
load.$(OBJEXT): $(CCAN_DIR)/list/list.h
load.$(OBJEXT): $(CCAN_DIR)/str/str.h
load.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-load.$(OBJEXT): $(hdrdir)/ruby/version.h
load.$(OBJEXT): $(top_srcdir)/internal/array.h
load.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-load.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-load.$(OBJEXT): $(top_srcdir)/internal/bits.h
load.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-load.$(OBJEXT): $(top_srcdir)/internal/complex.h
load.$(OBJEXT): $(top_srcdir)/internal/dir.h
load.$(OBJEXT): $(top_srcdir)/internal/error.h
load.$(OBJEXT): $(top_srcdir)/internal/file.h
-load.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
load.$(OBJEXT): $(top_srcdir)/internal/gc.h
-load.$(OBJEXT): $(top_srcdir)/internal/hash.h
load.$(OBJEXT): $(top_srcdir)/internal/imemo.h
load.$(OBJEXT): $(top_srcdir)/internal/load.h
-load.$(OBJEXT): $(top_srcdir)/internal/numeric.h
load.$(OBJEXT): $(top_srcdir)/internal/parse.h
-load.$(OBJEXT): $(top_srcdir)/internal/rational.h
-load.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-load.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
load.$(OBJEXT): $(top_srcdir)/internal/serial.h
load.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
load.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -9073,26 +8237,6 @@ load.$(OBJEXT): $(top_srcdir)/internal/thread.h
load.$(OBJEXT): $(top_srcdir)/internal/variable.h
load.$(OBJEXT): $(top_srcdir)/internal/vm.h
load.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-load.$(OBJEXT): $(top_srcdir)/prism/defines.h
-load.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-load.$(OBJEXT): $(top_srcdir)/prism/node.h
-load.$(OBJEXT): $(top_srcdir)/prism/options.h
-load.$(OBJEXT): $(top_srcdir)/prism/pack.h
-load.$(OBJEXT): $(top_srcdir)/prism/parser.h
-load.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-load.$(OBJEXT): $(top_srcdir)/prism/prism.h
-load.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-load.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-load.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
load.$(OBJEXT): {$(VPATH)}assert.h
load.$(OBJEXT): {$(VPATH)}atomic.h
load.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -9153,7 +8297,6 @@ load.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
load.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
load.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
load.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-load.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
load.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
load.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
load.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -9222,6 +8365,7 @@ load.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
load.$(OBJEXT): {$(VPATH)}internal/intern/error.h
load.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
load.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+load.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
load.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
load.$(OBJEXT): {$(VPATH)}internal/intern/io.h
load.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -9252,12 +8396,12 @@ load.$(OBJEXT): {$(VPATH)}internal/memory.h
load.$(OBJEXT): {$(VPATH)}internal/method.h
load.$(OBJEXT): {$(VPATH)}internal/module.h
load.$(OBJEXT): {$(VPATH)}internal/newobj.h
+load.$(OBJEXT): {$(VPATH)}internal/rgengc.h
load.$(OBJEXT): {$(VPATH)}internal/scan_args.h
load.$(OBJEXT): {$(VPATH)}internal/special_consts.h
load.$(OBJEXT): {$(VPATH)}internal/static_assert.h
load.$(OBJEXT): {$(VPATH)}internal/stdalign.h
load.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-load.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
load.$(OBJEXT): {$(VPATH)}internal/symbol.h
load.$(OBJEXT): {$(VPATH)}internal/value.h
load.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -9271,15 +8415,10 @@ load.$(OBJEXT): {$(VPATH)}missing.h
load.$(OBJEXT): {$(VPATH)}node.h
load.$(OBJEXT): {$(VPATH)}onigmo.h
load.$(OBJEXT): {$(VPATH)}oniguruma.h
-load.$(OBJEXT): {$(VPATH)}prism/ast.h
-load.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-load.$(OBJEXT): {$(VPATH)}prism/version.h
-load.$(OBJEXT): {$(VPATH)}prism_compile.h
load.$(OBJEXT): {$(VPATH)}probes.dmyh
load.$(OBJEXT): {$(VPATH)}probes.h
load.$(OBJEXT): {$(VPATH)}ruby_assert.h
load.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-load.$(OBJEXT): {$(VPATH)}rubyparser.h
load.$(OBJEXT): {$(VPATH)}shape.h
load.$(OBJEXT): {$(VPATH)}st.h
load.$(OBJEXT): {$(VPATH)}subst.h
@@ -9341,7 +8480,6 @@ loadpath.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
loadpath.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
loadpath.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
loadpath.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
loadpath.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
loadpath.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
loadpath.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -9401,6 +8539,7 @@ loadpath.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
loadpath.$(OBJEXT): {$(VPATH)}internal/intern/error.h
loadpath.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
loadpath.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
loadpath.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
loadpath.$(OBJEXT): {$(VPATH)}internal/intern/io.h
loadpath.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -9431,12 +8570,12 @@ loadpath.$(OBJEXT): {$(VPATH)}internal/memory.h
loadpath.$(OBJEXT): {$(VPATH)}internal/method.h
loadpath.$(OBJEXT): {$(VPATH)}internal/module.h
loadpath.$(OBJEXT): {$(VPATH)}internal/newobj.h
+loadpath.$(OBJEXT): {$(VPATH)}internal/rgengc.h
loadpath.$(OBJEXT): {$(VPATH)}internal/scan_args.h
loadpath.$(OBJEXT): {$(VPATH)}internal/special_consts.h
loadpath.$(OBJEXT): {$(VPATH)}internal/static_assert.h
loadpath.$(OBJEXT): {$(VPATH)}internal/stdalign.h
loadpath.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-loadpath.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
loadpath.$(OBJEXT): {$(VPATH)}internal/symbol.h
loadpath.$(OBJEXT): {$(VPATH)}internal/value.h
loadpath.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -9502,7 +8641,6 @@ localeinit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
localeinit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
localeinit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
localeinit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
localeinit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
localeinit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
localeinit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -9571,6 +8709,7 @@ localeinit.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
localeinit.$(OBJEXT): {$(VPATH)}internal/intern/error.h
localeinit.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
localeinit.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
localeinit.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
localeinit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
localeinit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -9601,12 +8740,12 @@ localeinit.$(OBJEXT): {$(VPATH)}internal/memory.h
localeinit.$(OBJEXT): {$(VPATH)}internal/method.h
localeinit.$(OBJEXT): {$(VPATH)}internal/module.h
localeinit.$(OBJEXT): {$(VPATH)}internal/newobj.h
+localeinit.$(OBJEXT): {$(VPATH)}internal/rgengc.h
localeinit.$(OBJEXT): {$(VPATH)}internal/scan_args.h
localeinit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
localeinit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
localeinit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
localeinit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-localeinit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
localeinit.$(OBJEXT): {$(VPATH)}internal/symbol.h
localeinit.$(OBJEXT): {$(VPATH)}internal/value.h
localeinit.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -9621,15 +8760,11 @@ localeinit.$(OBJEXT): {$(VPATH)}st.h
localeinit.$(OBJEXT): {$(VPATH)}subst.h
main.$(OBJEXT): $(hdrdir)/ruby.h
main.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-main.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-main.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-main.$(OBJEXT): $(top_srcdir)/internal/warnings.h
main.$(OBJEXT): {$(VPATH)}assert.h
main.$(OBJEXT): {$(VPATH)}backward.h
main.$(OBJEXT): {$(VPATH)}backward/2/assume.h
main.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
main.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-main.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
main.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
main.$(OBJEXT): {$(VPATH)}backward/2/limits.h
main.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
@@ -9676,7 +8811,6 @@ main.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
main.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
main.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
main.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-main.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
main.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
main.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
main.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -9736,6 +8870,7 @@ main.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
main.$(OBJEXT): {$(VPATH)}internal/intern/error.h
main.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
main.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+main.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
main.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
main.$(OBJEXT): {$(VPATH)}internal/intern/io.h
main.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -9766,12 +8901,12 @@ main.$(OBJEXT): {$(VPATH)}internal/memory.h
main.$(OBJEXT): {$(VPATH)}internal/method.h
main.$(OBJEXT): {$(VPATH)}internal/module.h
main.$(OBJEXT): {$(VPATH)}internal/newobj.h
+main.$(OBJEXT): {$(VPATH)}internal/rgengc.h
main.$(OBJEXT): {$(VPATH)}internal/scan_args.h
main.$(OBJEXT): {$(VPATH)}internal/special_consts.h
main.$(OBJEXT): {$(VPATH)}internal/static_assert.h
main.$(OBJEXT): {$(VPATH)}internal/stdalign.h
main.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-main.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
main.$(OBJEXT): {$(VPATH)}internal/symbol.h
main.$(OBJEXT): {$(VPATH)}internal/value.h
main.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -9788,7 +8923,6 @@ marshal.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
marshal.$(OBJEXT): $(CCAN_DIR)/list/list.h
marshal.$(OBJEXT): $(CCAN_DIR)/str/str.h
marshal.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-marshal.$(OBJEXT): $(hdrdir)/ruby/version.h
marshal.$(OBJEXT): $(top_srcdir)/internal/array.h
marshal.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
marshal.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -9803,7 +8937,6 @@ marshal.$(OBJEXT): $(top_srcdir)/internal/hash.h
marshal.$(OBJEXT): $(top_srcdir)/internal/imemo.h
marshal.$(OBJEXT): $(top_srcdir)/internal/numeric.h
marshal.$(OBJEXT): $(top_srcdir)/internal/object.h
-marshal.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
marshal.$(OBJEXT): $(top_srcdir)/internal/serial.h
marshal.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
marshal.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -9827,7 +8960,6 @@ marshal.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
marshal.$(OBJEXT): {$(VPATH)}builtin.h
marshal.$(OBJEXT): {$(VPATH)}config.h
marshal.$(OBJEXT): {$(VPATH)}constant.h
-marshal.$(OBJEXT): {$(VPATH)}debug_counter.h
marshal.$(OBJEXT): {$(VPATH)}defines.h
marshal.$(OBJEXT): {$(VPATH)}encindex.h
marshal.$(OBJEXT): {$(VPATH)}encoding.h
@@ -9872,8 +9004,8 @@ marshal.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+marshal.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-marshal.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
marshal.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -9942,6 +9074,7 @@ marshal.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
marshal.$(OBJEXT): {$(VPATH)}internal/intern/error.h
marshal.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
marshal.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+marshal.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
marshal.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
marshal.$(OBJEXT): {$(VPATH)}internal/intern/io.h
marshal.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -9972,12 +9105,12 @@ marshal.$(OBJEXT): {$(VPATH)}internal/memory.h
marshal.$(OBJEXT): {$(VPATH)}internal/method.h
marshal.$(OBJEXT): {$(VPATH)}internal/module.h
marshal.$(OBJEXT): {$(VPATH)}internal/newobj.h
+marshal.$(OBJEXT): {$(VPATH)}internal/rgengc.h
marshal.$(OBJEXT): {$(VPATH)}internal/scan_args.h
marshal.$(OBJEXT): {$(VPATH)}internal/special_consts.h
marshal.$(OBJEXT): {$(VPATH)}internal/static_assert.h
marshal.$(OBJEXT): {$(VPATH)}internal/stdalign.h
marshal.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-marshal.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
marshal.$(OBJEXT): {$(VPATH)}internal/symbol.h
marshal.$(OBJEXT): {$(VPATH)}internal/value.h
marshal.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -9994,7 +9127,6 @@ marshal.$(OBJEXT): {$(VPATH)}onigmo.h
marshal.$(OBJEXT): {$(VPATH)}oniguruma.h
marshal.$(OBJEXT): {$(VPATH)}ruby_assert.h
marshal.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-marshal.$(OBJEXT): {$(VPATH)}rubyparser.h
marshal.$(OBJEXT): {$(VPATH)}shape.h
marshal.$(OBJEXT): {$(VPATH)}st.h
marshal.$(OBJEXT): {$(VPATH)}subst.h
@@ -10002,9 +9134,7 @@ marshal.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
marshal.$(OBJEXT): {$(VPATH)}thread_native.h
marshal.$(OBJEXT): {$(VPATH)}util.h
marshal.$(OBJEXT): {$(VPATH)}vm_core.h
-marshal.$(OBJEXT): {$(VPATH)}vm_debug.h
marshal.$(OBJEXT): {$(VPATH)}vm_opts.h
-marshal.$(OBJEXT): {$(VPATH)}vm_sync.h
math.$(OBJEXT): $(hdrdir)/ruby/ruby.h
math.$(OBJEXT): $(top_srcdir)/internal/bignum.h
math.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -10072,7 +9202,6 @@ math.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
math.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
math.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
math.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-math.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
math.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
math.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
math.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -10132,6 +9261,7 @@ math.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
math.$(OBJEXT): {$(VPATH)}internal/intern/error.h
math.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
math.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+math.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
math.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
math.$(OBJEXT): {$(VPATH)}internal/intern/io.h
math.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -10162,12 +9292,12 @@ math.$(OBJEXT): {$(VPATH)}internal/memory.h
math.$(OBJEXT): {$(VPATH)}internal/method.h
math.$(OBJEXT): {$(VPATH)}internal/module.h
math.$(OBJEXT): {$(VPATH)}internal/newobj.h
+math.$(OBJEXT): {$(VPATH)}internal/rgengc.h
math.$(OBJEXT): {$(VPATH)}internal/scan_args.h
math.$(OBJEXT): {$(VPATH)}internal/special_consts.h
math.$(OBJEXT): {$(VPATH)}internal/static_assert.h
math.$(OBJEXT): {$(VPATH)}internal/stdalign.h
math.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-math.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
math.$(OBJEXT): {$(VPATH)}internal/symbol.h
math.$(OBJEXT): {$(VPATH)}internal/value.h
math.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -10179,25 +9309,13 @@ math.$(OBJEXT): {$(VPATH)}missing.h
math.$(OBJEXT): {$(VPATH)}shape.h
math.$(OBJEXT): {$(VPATH)}st.h
math.$(OBJEXT): {$(VPATH)}subst.h
-memory_view.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-memory_view.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-memory_view.$(OBJEXT): $(CCAN_DIR)/list/list.h
-memory_view.$(OBJEXT): $(CCAN_DIR)/str/str.h
memory_view.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/array.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/compilers.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/gc.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/hash.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/serial.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/variable.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/vm.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/warnings.h
memory_view.$(OBJEXT): {$(VPATH)}assert.h
-memory_view.$(OBJEXT): {$(VPATH)}atomic.h
memory_view.$(OBJEXT): {$(VPATH)}backward/2/assume.h
memory_view.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
memory_view.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -10211,8 +9329,6 @@ memory_view.$(OBJEXT): {$(VPATH)}config.h
memory_view.$(OBJEXT): {$(VPATH)}constant.h
memory_view.$(OBJEXT): {$(VPATH)}debug_counter.h
memory_view.$(OBJEXT): {$(VPATH)}defines.h
-memory_view.$(OBJEXT): {$(VPATH)}encoding.h
-memory_view.$(OBJEXT): {$(VPATH)}id.h
memory_view.$(OBJEXT): {$(VPATH)}id_table.h
memory_view.$(OBJEXT): {$(VPATH)}intern.h
memory_view.$(OBJEXT): {$(VPATH)}internal.h
@@ -10254,7 +9370,6 @@ memory_view.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
memory_view.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
memory_view.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
memory_view.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
memory_view.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
memory_view.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
memory_view.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -10287,15 +9402,6 @@ memory_view.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
memory_view.$(OBJEXT): {$(VPATH)}internal/ctype.h
memory_view.$(OBJEXT): {$(VPATH)}internal/dllexport.h
memory_view.$(OBJEXT): {$(VPATH)}internal/dosish.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
memory_view.$(OBJEXT): {$(VPATH)}internal/error.h
memory_view.$(OBJEXT): {$(VPATH)}internal/eval.h
memory_view.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -10323,6 +9429,7 @@ memory_view.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
memory_view.$(OBJEXT): {$(VPATH)}internal/intern/error.h
memory_view.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
memory_view.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
memory_view.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
memory_view.$(OBJEXT): {$(VPATH)}internal/intern/io.h
memory_view.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -10353,12 +9460,12 @@ memory_view.$(OBJEXT): {$(VPATH)}internal/memory.h
memory_view.$(OBJEXT): {$(VPATH)}internal/method.h
memory_view.$(OBJEXT): {$(VPATH)}internal/module.h
memory_view.$(OBJEXT): {$(VPATH)}internal/newobj.h
+memory_view.$(OBJEXT): {$(VPATH)}internal/rgengc.h
memory_view.$(OBJEXT): {$(VPATH)}internal/scan_args.h
memory_view.$(OBJEXT): {$(VPATH)}internal/special_consts.h
memory_view.$(OBJEXT): {$(VPATH)}internal/static_assert.h
memory_view.$(OBJEXT): {$(VPATH)}internal/stdalign.h
memory_view.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-memory_view.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
memory_view.$(OBJEXT): {$(VPATH)}internal/symbol.h
memory_view.$(OBJEXT): {$(VPATH)}internal/value.h
memory_view.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -10367,69 +9474,29 @@ memory_view.$(OBJEXT): {$(VPATH)}internal/warning_push.h
memory_view.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
memory_view.$(OBJEXT): {$(VPATH)}memory_view.c
memory_view.$(OBJEXT): {$(VPATH)}memory_view.h
-memory_view.$(OBJEXT): {$(VPATH)}method.h
memory_view.$(OBJEXT): {$(VPATH)}missing.h
-memory_view.$(OBJEXT): {$(VPATH)}node.h
-memory_view.$(OBJEXT): {$(VPATH)}onigmo.h
-memory_view.$(OBJEXT): {$(VPATH)}oniguruma.h
-memory_view.$(OBJEXT): {$(VPATH)}ruby_assert.h
-memory_view.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-memory_view.$(OBJEXT): {$(VPATH)}rubyparser.h
memory_view.$(OBJEXT): {$(VPATH)}shape.h
memory_view.$(OBJEXT): {$(VPATH)}st.h
memory_view.$(OBJEXT): {$(VPATH)}subst.h
-memory_view.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-memory_view.$(OBJEXT): {$(VPATH)}thread_native.h
memory_view.$(OBJEXT): {$(VPATH)}util.h
-memory_view.$(OBJEXT): {$(VPATH)}vm_core.h
memory_view.$(OBJEXT): {$(VPATH)}vm_debug.h
-memory_view.$(OBJEXT): {$(VPATH)}vm_opts.h
memory_view.$(OBJEXT): {$(VPATH)}vm_sync.h
miniinit.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
miniinit.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
miniinit.$(OBJEXT): $(CCAN_DIR)/list/list.h
miniinit.$(OBJEXT): $(CCAN_DIR)/str/str.h
miniinit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-miniinit.$(OBJEXT): $(srcdir)/rjit_c.rb
+miniinit.$(OBJEXT): $(srcdir)/mjit_c.rb
miniinit.$(OBJEXT): $(top_srcdir)/internal/array.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/bits.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/complex.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/gc.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/parse.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/rational.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-miniinit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/serial.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/variable.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/vm.h
miniinit.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/defines.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/node.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/options.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/pack.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/parser.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/prism.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-miniinit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
miniinit.$(OBJEXT): {$(VPATH)}array.rb
miniinit.$(OBJEXT): {$(VPATH)}assert.h
miniinit.$(OBJEXT): {$(VPATH)}ast.rb
@@ -10492,8 +9559,8 @@ miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
miniinit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -10562,6 +9629,7 @@ miniinit.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
miniinit.$(OBJEXT): {$(VPATH)}internal/intern/error.h
miniinit.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
miniinit.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
miniinit.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
miniinit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
miniinit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -10592,12 +9660,12 @@ miniinit.$(OBJEXT): {$(VPATH)}internal/memory.h
miniinit.$(OBJEXT): {$(VPATH)}internal/method.h
miniinit.$(OBJEXT): {$(VPATH)}internal/module.h
miniinit.$(OBJEXT): {$(VPATH)}internal/newobj.h
+miniinit.$(OBJEXT): {$(VPATH)}internal/rgengc.h
miniinit.$(OBJEXT): {$(VPATH)}internal/scan_args.h
miniinit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
miniinit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
miniinit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
miniinit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-miniinit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
miniinit.$(OBJEXT): {$(VPATH)}internal/symbol.h
miniinit.$(OBJEXT): {$(VPATH)}internal/value.h
miniinit.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -10613,6 +9681,8 @@ miniinit.$(OBJEXT): {$(VPATH)}mini_builtin.c
miniinit.$(OBJEXT): {$(VPATH)}miniinit.c
miniinit.$(OBJEXT): {$(VPATH)}miniprelude.c
miniinit.$(OBJEXT): {$(VPATH)}missing.h
+miniinit.$(OBJEXT): {$(VPATH)}mjit.rb
+miniinit.$(OBJEXT): {$(VPATH)}mjit_c.rb
miniinit.$(OBJEXT): {$(VPATH)}nilclass.rb
miniinit.$(OBJEXT): {$(VPATH)}node.h
miniinit.$(OBJEXT): {$(VPATH)}numeric.rb
@@ -10620,16 +9690,9 @@ miniinit.$(OBJEXT): {$(VPATH)}onigmo.h
miniinit.$(OBJEXT): {$(VPATH)}oniguruma.h
miniinit.$(OBJEXT): {$(VPATH)}pack.rb
miniinit.$(OBJEXT): {$(VPATH)}prelude.rb
-miniinit.$(OBJEXT): {$(VPATH)}prism/ast.h
-miniinit.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-miniinit.$(OBJEXT): {$(VPATH)}prism/version.h
-miniinit.$(OBJEXT): {$(VPATH)}prism_compile.h
miniinit.$(OBJEXT): {$(VPATH)}ractor.rb
-miniinit.$(OBJEXT): {$(VPATH)}rjit.rb
-miniinit.$(OBJEXT): {$(VPATH)}rjit_c.rb
miniinit.$(OBJEXT): {$(VPATH)}ruby_assert.h
miniinit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-miniinit.$(OBJEXT): {$(VPATH)}rubyparser.h
miniinit.$(OBJEXT): {$(VPATH)}shape.h
miniinit.$(OBJEXT): {$(VPATH)}st.h
miniinit.$(OBJEXT): {$(VPATH)}subst.h
@@ -10643,6 +9706,441 @@ miniinit.$(OBJEXT): {$(VPATH)}vm_core.h
miniinit.$(OBJEXT): {$(VPATH)}vm_opts.h
miniinit.$(OBJEXT): {$(VPATH)}warning.rb
miniinit.$(OBJEXT): {$(VPATH)}yjit.rb
+mjit.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+mjit.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+mjit.$(OBJEXT): $(CCAN_DIR)/list/list.h
+mjit.$(OBJEXT): $(CCAN_DIR)/str/str.h
+mjit.$(OBJEXT): $(hdrdir)/ruby.h
+mjit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+mjit.$(OBJEXT): $(hdrdir)/ruby/version.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/array.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/class.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/compile.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/cont.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/file.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/gc.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/hash.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/process.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/serial.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/variable.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/vm.h
+mjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+mjit.$(OBJEXT): {$(VPATH)}assert.h
+mjit.$(OBJEXT): {$(VPATH)}atomic.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+mjit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+mjit.$(OBJEXT): {$(VPATH)}builtin.h
+mjit.$(OBJEXT): {$(VPATH)}config.h
+mjit.$(OBJEXT): {$(VPATH)}constant.h
+mjit.$(OBJEXT): {$(VPATH)}debug.h
+mjit.$(OBJEXT): {$(VPATH)}debug_counter.h
+mjit.$(OBJEXT): {$(VPATH)}defines.h
+mjit.$(OBJEXT): {$(VPATH)}dln.h
+mjit.$(OBJEXT): {$(VPATH)}encoding.h
+mjit.$(OBJEXT): {$(VPATH)}gc.h
+mjit.$(OBJEXT): {$(VPATH)}id.h
+mjit.$(OBJEXT): {$(VPATH)}id_table.h
+mjit.$(OBJEXT): {$(VPATH)}insns.def
+mjit.$(OBJEXT): {$(VPATH)}insns.inc
+mjit.$(OBJEXT): {$(VPATH)}insns_info.inc
+mjit.$(OBJEXT): {$(VPATH)}intern.h
+mjit.$(OBJEXT): {$(VPATH)}internal.h
+mjit.$(OBJEXT): {$(VPATH)}internal/abi.h
+mjit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+mjit.$(OBJEXT): {$(VPATH)}internal/assume.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+mjit.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+mjit.$(OBJEXT): {$(VPATH)}internal/cast.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+mjit.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+mjit.$(OBJEXT): {$(VPATH)}internal/config.h
+mjit.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+mjit.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+mjit.$(OBJEXT): {$(VPATH)}internal/ctype.h
+mjit.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+mjit.$(OBJEXT): {$(VPATH)}internal/dosish.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+mjit.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+mjit.$(OBJEXT): {$(VPATH)}internal/error.h
+mjit.$(OBJEXT): {$(VPATH)}internal/eval.h
+mjit.$(OBJEXT): {$(VPATH)}internal/event.h
+mjit.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+mjit.$(OBJEXT): {$(VPATH)}internal/gc.h
+mjit.$(OBJEXT): {$(VPATH)}internal/glob.h
+mjit.$(OBJEXT): {$(VPATH)}internal/globals.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+mjit.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+mjit.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+mjit.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+mjit.$(OBJEXT): {$(VPATH)}internal/iterator.h
+mjit.$(OBJEXT): {$(VPATH)}internal/memory.h
+mjit.$(OBJEXT): {$(VPATH)}internal/method.h
+mjit.$(OBJEXT): {$(VPATH)}internal/module.h
+mjit.$(OBJEXT): {$(VPATH)}internal/newobj.h
+mjit.$(OBJEXT): {$(VPATH)}internal/rgengc.h
+mjit.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+mjit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+mjit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+mjit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+mjit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+mjit.$(OBJEXT): {$(VPATH)}internal/symbol.h
+mjit.$(OBJEXT): {$(VPATH)}internal/value.h
+mjit.$(OBJEXT): {$(VPATH)}internal/value_type.h
+mjit.$(OBJEXT): {$(VPATH)}internal/variable.h
+mjit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+mjit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+mjit.$(OBJEXT): {$(VPATH)}iseq.h
+mjit.$(OBJEXT): {$(VPATH)}method.h
+mjit.$(OBJEXT): {$(VPATH)}missing.h
+mjit.$(OBJEXT): {$(VPATH)}mjit.c
+mjit.$(OBJEXT): {$(VPATH)}mjit.h
+mjit.$(OBJEXT): {$(VPATH)}mjit.rbinc
+mjit.$(OBJEXT): {$(VPATH)}mjit_c.h
+mjit.$(OBJEXT): {$(VPATH)}mjit_config.h
+mjit.$(OBJEXT): {$(VPATH)}node.h
+mjit.$(OBJEXT): {$(VPATH)}onigmo.h
+mjit.$(OBJEXT): {$(VPATH)}oniguruma.h
+mjit.$(OBJEXT): {$(VPATH)}ractor.h
+mjit.$(OBJEXT): {$(VPATH)}ractor_core.h
+mjit.$(OBJEXT): {$(VPATH)}ruby_assert.h
+mjit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+mjit.$(OBJEXT): {$(VPATH)}shape.h
+mjit.$(OBJEXT): {$(VPATH)}st.h
+mjit.$(OBJEXT): {$(VPATH)}subst.h
+mjit.$(OBJEXT): {$(VPATH)}thread.h
+mjit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+mjit.$(OBJEXT): {$(VPATH)}thread_native.h
+mjit.$(OBJEXT): {$(VPATH)}util.h
+mjit.$(OBJEXT): {$(VPATH)}vm_callinfo.h
+mjit.$(OBJEXT): {$(VPATH)}vm_core.h
+mjit.$(OBJEXT): {$(VPATH)}vm_debug.h
+mjit.$(OBJEXT): {$(VPATH)}vm_opts.h
+mjit.$(OBJEXT): {$(VPATH)}vm_sync.h
+mjit.$(OBJEXT): {$(VPATH)}yjit.h
+mjit_c.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+mjit_c.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+mjit_c.$(OBJEXT): $(CCAN_DIR)/list/list.h
+mjit_c.$(OBJEXT): $(CCAN_DIR)/str/str.h
+mjit_c.$(OBJEXT): $(hdrdir)/ruby.h
+mjit_c.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+mjit_c.$(OBJEXT): $(srcdir)/mjit_c.rb
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/array.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/class.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/compile.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/gc.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/hash.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/object.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/serial.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/variable.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/vm.h
+mjit_c.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+mjit_c.$(OBJEXT): {$(VPATH)}assert.h
+mjit_c.$(OBJEXT): {$(VPATH)}atomic.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+mjit_c.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+mjit_c.$(OBJEXT): {$(VPATH)}builtin.h
+mjit_c.$(OBJEXT): {$(VPATH)}config.h
+mjit_c.$(OBJEXT): {$(VPATH)}constant.h
+mjit_c.$(OBJEXT): {$(VPATH)}debug_counter.h
+mjit_c.$(OBJEXT): {$(VPATH)}defines.h
+mjit_c.$(OBJEXT): {$(VPATH)}id.h
+mjit_c.$(OBJEXT): {$(VPATH)}id_table.h
+mjit_c.$(OBJEXT): {$(VPATH)}insns.def
+mjit_c.$(OBJEXT): {$(VPATH)}insns.inc
+mjit_c.$(OBJEXT): {$(VPATH)}insns_info.inc
+mjit_c.$(OBJEXT): {$(VPATH)}intern.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/abi.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/assume.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/cast.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/config.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/ctype.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/dosish.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/error.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/eval.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/event.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/gc.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/glob.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/globals.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/iterator.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/memory.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/method.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/module.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/newobj.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/rgengc.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/symbol.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/value.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/value_type.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/variable.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+mjit_c.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+mjit_c.$(OBJEXT): {$(VPATH)}iseq.h
+mjit_c.$(OBJEXT): {$(VPATH)}method.h
+mjit_c.$(OBJEXT): {$(VPATH)}missing.h
+mjit_c.$(OBJEXT): {$(VPATH)}mjit.h
+mjit_c.$(OBJEXT): {$(VPATH)}mjit_c.c
+mjit_c.$(OBJEXT): {$(VPATH)}mjit_c.h
+mjit_c.$(OBJEXT): {$(VPATH)}mjit_c.rb
+mjit_c.$(OBJEXT): {$(VPATH)}mjit_c.rbinc
+mjit_c.$(OBJEXT): {$(VPATH)}mjit_sp_inc.inc
+mjit_c.$(OBJEXT): {$(VPATH)}node.h
+mjit_c.$(OBJEXT): {$(VPATH)}ruby_assert.h
+mjit_c.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+mjit_c.$(OBJEXT): {$(VPATH)}shape.h
+mjit_c.$(OBJEXT): {$(VPATH)}st.h
+mjit_c.$(OBJEXT): {$(VPATH)}subst.h
+mjit_c.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+mjit_c.$(OBJEXT): {$(VPATH)}thread_native.h
+mjit_c.$(OBJEXT): {$(VPATH)}vm_callinfo.h
+mjit_c.$(OBJEXT): {$(VPATH)}vm_core.h
+mjit_c.$(OBJEXT): {$(VPATH)}vm_exec.h
+mjit_c.$(OBJEXT): {$(VPATH)}vm_insnhelper.h
+mjit_c.$(OBJEXT): {$(VPATH)}vm_opts.h
+mjit_c.$(OBJEXT): {$(VPATH)}yjit.h
node.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
node.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
node.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -10654,7 +10152,6 @@ node.$(OBJEXT): $(top_srcdir)/internal/compilers.h
node.$(OBJEXT): $(top_srcdir)/internal/gc.h
node.$(OBJEXT): $(top_srcdir)/internal/hash.h
node.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-node.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
node.$(OBJEXT): $(top_srcdir)/internal/serial.h
node.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
node.$(OBJEXT): $(top_srcdir)/internal/variable.h
@@ -10674,7 +10171,6 @@ node.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
node.$(OBJEXT): {$(VPATH)}config.h
node.$(OBJEXT): {$(VPATH)}constant.h
node.$(OBJEXT): {$(VPATH)}defines.h
-node.$(OBJEXT): {$(VPATH)}encoding.h
node.$(OBJEXT): {$(VPATH)}id.h
node.$(OBJEXT): {$(VPATH)}id_table.h
node.$(OBJEXT): {$(VPATH)}intern.h
@@ -10717,7 +10213,6 @@ node.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
node.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
node.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
node.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-node.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
node.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
node.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
node.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -10750,15 +10245,6 @@ node.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
node.$(OBJEXT): {$(VPATH)}internal/ctype.h
node.$(OBJEXT): {$(VPATH)}internal/dllexport.h
node.$(OBJEXT): {$(VPATH)}internal/dosish.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-node.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
node.$(OBJEXT): {$(VPATH)}internal/error.h
node.$(OBJEXT): {$(VPATH)}internal/eval.h
node.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -10786,6 +10272,7 @@ node.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
node.$(OBJEXT): {$(VPATH)}internal/intern/error.h
node.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
node.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+node.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
node.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
node.$(OBJEXT): {$(VPATH)}internal/intern/io.h
node.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -10816,12 +10303,12 @@ node.$(OBJEXT): {$(VPATH)}internal/memory.h
node.$(OBJEXT): {$(VPATH)}internal/method.h
node.$(OBJEXT): {$(VPATH)}internal/module.h
node.$(OBJEXT): {$(VPATH)}internal/newobj.h
+node.$(OBJEXT): {$(VPATH)}internal/rgengc.h
node.$(OBJEXT): {$(VPATH)}internal/scan_args.h
node.$(OBJEXT): {$(VPATH)}internal/special_consts.h
node.$(OBJEXT): {$(VPATH)}internal/static_assert.h
node.$(OBJEXT): {$(VPATH)}internal/stdalign.h
node.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-node.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
node.$(OBJEXT): {$(VPATH)}internal/symbol.h
node.$(OBJEXT): {$(VPATH)}internal/value.h
node.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -10832,12 +10319,8 @@ node.$(OBJEXT): {$(VPATH)}method.h
node.$(OBJEXT): {$(VPATH)}missing.h
node.$(OBJEXT): {$(VPATH)}node.c
node.$(OBJEXT): {$(VPATH)}node.h
-node.$(OBJEXT): {$(VPATH)}node_name.inc
-node.$(OBJEXT): {$(VPATH)}onigmo.h
-node.$(OBJEXT): {$(VPATH)}oniguruma.h
node.$(OBJEXT): {$(VPATH)}ruby_assert.h
node.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-node.$(OBJEXT): {$(VPATH)}rubyparser.h
node.$(OBJEXT): {$(VPATH)}shape.h
node.$(OBJEXT): {$(VPATH)}st.h
node.$(OBJEXT): {$(VPATH)}subst.h
@@ -10845,226 +10328,8 @@ node.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
node.$(OBJEXT): {$(VPATH)}thread_native.h
node.$(OBJEXT): {$(VPATH)}vm_core.h
node.$(OBJEXT): {$(VPATH)}vm_opts.h
-node_dump.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-node_dump.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-node_dump.$(OBJEXT): $(CCAN_DIR)/list/list.h
-node_dump.$(OBJEXT): $(CCAN_DIR)/str/str.h
-node_dump.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/array.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/bits.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/class.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/complex.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/gc.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/hash.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/parse.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/rational.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/serial.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/variable.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/vm.h
-node_dump.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-node_dump.$(OBJEXT): {$(VPATH)}assert.h
-node_dump.$(OBJEXT): {$(VPATH)}atomic.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-node_dump.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-node_dump.$(OBJEXT): {$(VPATH)}config.h
-node_dump.$(OBJEXT): {$(VPATH)}constant.h
-node_dump.$(OBJEXT): {$(VPATH)}debug_counter.h
-node_dump.$(OBJEXT): {$(VPATH)}defines.h
-node_dump.$(OBJEXT): {$(VPATH)}encoding.h
-node_dump.$(OBJEXT): {$(VPATH)}id.h
-node_dump.$(OBJEXT): {$(VPATH)}id_table.h
-node_dump.$(OBJEXT): {$(VPATH)}intern.h
-node_dump.$(OBJEXT): {$(VPATH)}internal.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/abi.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/assume.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/cast.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/config.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/ctype.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/dosish.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/error.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/eval.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/event.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/gc.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/glob.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/globals.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/iterator.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/memory.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/method.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/module.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/newobj.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/symbol.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/value.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/value_type.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/variable.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-node_dump.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-node_dump.$(OBJEXT): {$(VPATH)}method.h
-node_dump.$(OBJEXT): {$(VPATH)}missing.h
-node_dump.$(OBJEXT): {$(VPATH)}node.h
-node_dump.$(OBJEXT): {$(VPATH)}node_dump.c
-node_dump.$(OBJEXT): {$(VPATH)}onigmo.h
-node_dump.$(OBJEXT): {$(VPATH)}oniguruma.h
-node_dump.$(OBJEXT): {$(VPATH)}ruby_assert.h
-node_dump.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-node_dump.$(OBJEXT): {$(VPATH)}rubyparser.h
-node_dump.$(OBJEXT): {$(VPATH)}shape.h
-node_dump.$(OBJEXT): {$(VPATH)}st.h
-node_dump.$(OBJEXT): {$(VPATH)}subst.h
-node_dump.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-node_dump.$(OBJEXT): {$(VPATH)}thread_native.h
-node_dump.$(OBJEXT): {$(VPATH)}vm_core.h
-node_dump.$(OBJEXT): {$(VPATH)}vm_debug.h
-node_dump.$(OBJEXT): {$(VPATH)}vm_opts.h
-node_dump.$(OBJEXT): {$(VPATH)}vm_sync.h
-numeric.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-numeric.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-numeric.$(OBJEXT): $(CCAN_DIR)/list/list.h
-numeric.$(OBJEXT): $(CCAN_DIR)/str/str.h
numeric.$(OBJEXT): $(hdrdir)/ruby/ruby.h
numeric.$(OBJEXT): $(top_srcdir)/internal/array.h
-numeric.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
numeric.$(OBJEXT): $(top_srcdir)/internal/bignum.h
numeric.$(OBJEXT): $(top_srcdir)/internal/bits.h
numeric.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -11074,11 +10339,9 @@ numeric.$(OBJEXT): $(top_srcdir)/internal/enumerator.h
numeric.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
numeric.$(OBJEXT): $(top_srcdir)/internal/gc.h
numeric.$(OBJEXT): $(top_srcdir)/internal/hash.h
-numeric.$(OBJEXT): $(top_srcdir)/internal/imemo.h
numeric.$(OBJEXT): $(top_srcdir)/internal/numeric.h
numeric.$(OBJEXT): $(top_srcdir)/internal/object.h
numeric.$(OBJEXT): $(top_srcdir)/internal/rational.h
-numeric.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
numeric.$(OBJEXT): $(top_srcdir)/internal/serial.h
numeric.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
numeric.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -11087,7 +10350,6 @@ numeric.$(OBJEXT): $(top_srcdir)/internal/variable.h
numeric.$(OBJEXT): $(top_srcdir)/internal/vm.h
numeric.$(OBJEXT): $(top_srcdir)/internal/warnings.h
numeric.$(OBJEXT): {$(VPATH)}assert.h
-numeric.$(OBJEXT): {$(VPATH)}atomic.h
numeric.$(OBJEXT): {$(VPATH)}backward/2/assume.h
numeric.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
numeric.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -11144,7 +10406,6 @@ numeric.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
numeric.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
numeric.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
numeric.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-numeric.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
numeric.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
numeric.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
numeric.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -11213,6 +10474,7 @@ numeric.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
numeric.$(OBJEXT): {$(VPATH)}internal/intern/error.h
numeric.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
numeric.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+numeric.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
numeric.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
numeric.$(OBJEXT): {$(VPATH)}internal/intern/io.h
numeric.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -11243,42 +10505,33 @@ numeric.$(OBJEXT): {$(VPATH)}internal/memory.h
numeric.$(OBJEXT): {$(VPATH)}internal/method.h
numeric.$(OBJEXT): {$(VPATH)}internal/module.h
numeric.$(OBJEXT): {$(VPATH)}internal/newobj.h
+numeric.$(OBJEXT): {$(VPATH)}internal/rgengc.h
numeric.$(OBJEXT): {$(VPATH)}internal/scan_args.h
numeric.$(OBJEXT): {$(VPATH)}internal/special_consts.h
numeric.$(OBJEXT): {$(VPATH)}internal/static_assert.h
numeric.$(OBJEXT): {$(VPATH)}internal/stdalign.h
numeric.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-numeric.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
numeric.$(OBJEXT): {$(VPATH)}internal/symbol.h
numeric.$(OBJEXT): {$(VPATH)}internal/value.h
numeric.$(OBJEXT): {$(VPATH)}internal/value_type.h
numeric.$(OBJEXT): {$(VPATH)}internal/variable.h
numeric.$(OBJEXT): {$(VPATH)}internal/warning_push.h
numeric.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-numeric.$(OBJEXT): {$(VPATH)}method.h
numeric.$(OBJEXT): {$(VPATH)}missing.h
-numeric.$(OBJEXT): {$(VPATH)}node.h
numeric.$(OBJEXT): {$(VPATH)}numeric.c
numeric.$(OBJEXT): {$(VPATH)}numeric.rbinc
numeric.$(OBJEXT): {$(VPATH)}onigmo.h
numeric.$(OBJEXT): {$(VPATH)}oniguruma.h
numeric.$(OBJEXT): {$(VPATH)}ruby_assert.h
-numeric.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-numeric.$(OBJEXT): {$(VPATH)}rubyparser.h
numeric.$(OBJEXT): {$(VPATH)}shape.h
numeric.$(OBJEXT): {$(VPATH)}st.h
numeric.$(OBJEXT): {$(VPATH)}subst.h
-numeric.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-numeric.$(OBJEXT): {$(VPATH)}thread_native.h
numeric.$(OBJEXT): {$(VPATH)}util.h
-numeric.$(OBJEXT): {$(VPATH)}vm_core.h
-numeric.$(OBJEXT): {$(VPATH)}vm_opts.h
object.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
object.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
object.$(OBJEXT): $(CCAN_DIR)/list/list.h
object.$(OBJEXT): $(CCAN_DIR)/str/str.h
object.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-object.$(OBJEXT): $(hdrdir)/ruby/version.h
object.$(OBJEXT): $(top_srcdir)/internal/array.h
object.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
object.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -11293,9 +10546,7 @@ object.$(OBJEXT): $(top_srcdir)/internal/imemo.h
object.$(OBJEXT): $(top_srcdir)/internal/inits.h
object.$(OBJEXT): $(top_srcdir)/internal/numeric.h
object.$(OBJEXT): $(top_srcdir)/internal/object.h
-object.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
object.$(OBJEXT): $(top_srcdir)/internal/serial.h
-object.$(OBJEXT): $(top_srcdir)/internal/st.h
object.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
object.$(OBJEXT): $(top_srcdir)/internal/string.h
object.$(OBJEXT): $(top_srcdir)/internal/struct.h
@@ -11317,7 +10568,6 @@ object.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
object.$(OBJEXT): {$(VPATH)}builtin.h
object.$(OBJEXT): {$(VPATH)}config.h
object.$(OBJEXT): {$(VPATH)}constant.h
-object.$(OBJEXT): {$(VPATH)}debug_counter.h
object.$(OBJEXT): {$(VPATH)}defines.h
object.$(OBJEXT): {$(VPATH)}encoding.h
object.$(OBJEXT): {$(VPATH)}id.h
@@ -11362,7 +10612,6 @@ object.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
object.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
object.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
object.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-object.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
object.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
object.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
object.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -11431,6 +10680,7 @@ object.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
object.$(OBJEXT): {$(VPATH)}internal/intern/error.h
object.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
object.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+object.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
object.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
object.$(OBJEXT): {$(VPATH)}internal/intern/io.h
object.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -11461,13 +10711,12 @@ object.$(OBJEXT): {$(VPATH)}internal/memory.h
object.$(OBJEXT): {$(VPATH)}internal/method.h
object.$(OBJEXT): {$(VPATH)}internal/module.h
object.$(OBJEXT): {$(VPATH)}internal/newobj.h
+object.$(OBJEXT): {$(VPATH)}internal/rgengc.h
object.$(OBJEXT): {$(VPATH)}internal/scan_args.h
object.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-object.$(OBJEXT): {$(VPATH)}internal/st.h
object.$(OBJEXT): {$(VPATH)}internal/static_assert.h
object.$(OBJEXT): {$(VPATH)}internal/stdalign.h
object.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-object.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
object.$(OBJEXT): {$(VPATH)}internal/symbol.h
object.$(OBJEXT): {$(VPATH)}internal/value.h
object.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -11486,7 +10735,6 @@ object.$(OBJEXT): {$(VPATH)}probes.dmyh
object.$(OBJEXT): {$(VPATH)}probes.h
object.$(OBJEXT): {$(VPATH)}ruby_assert.h
object.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-object.$(OBJEXT): {$(VPATH)}rubyparser.h
object.$(OBJEXT): {$(VPATH)}shape.h
object.$(OBJEXT): {$(VPATH)}st.h
object.$(OBJEXT): {$(VPATH)}subst.h
@@ -11495,31 +10743,18 @@ object.$(OBJEXT): {$(VPATH)}thread_native.h
object.$(OBJEXT): {$(VPATH)}util.h
object.$(OBJEXT): {$(VPATH)}variable.h
object.$(OBJEXT): {$(VPATH)}vm_core.h
-object.$(OBJEXT): {$(VPATH)}vm_debug.h
object.$(OBJEXT): {$(VPATH)}vm_opts.h
-object.$(OBJEXT): {$(VPATH)}vm_sync.h
-object.$(OBJEXT): {$(VPATH)}yjit.h
-pack.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-pack.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-pack.$(OBJEXT): $(CCAN_DIR)/list/list.h
-pack.$(OBJEXT): $(CCAN_DIR)/str/str.h
pack.$(OBJEXT): $(hdrdir)/ruby/ruby.h
pack.$(OBJEXT): $(top_srcdir)/internal/array.h
-pack.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
pack.$(OBJEXT): $(top_srcdir)/internal/bits.h
pack.$(OBJEXT): $(top_srcdir)/internal/compilers.h
pack.$(OBJEXT): $(top_srcdir)/internal/gc.h
-pack.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-pack.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-pack.$(OBJEXT): $(top_srcdir)/internal/serial.h
pack.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
pack.$(OBJEXT): $(top_srcdir)/internal/string.h
pack.$(OBJEXT): $(top_srcdir)/internal/symbol.h
pack.$(OBJEXT): $(top_srcdir)/internal/variable.h
-pack.$(OBJEXT): $(top_srcdir)/internal/vm.h
pack.$(OBJEXT): $(top_srcdir)/internal/warnings.h
pack.$(OBJEXT): {$(VPATH)}assert.h
-pack.$(OBJEXT): {$(VPATH)}atomic.h
pack.$(OBJEXT): {$(VPATH)}backward/2/assume.h
pack.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
pack.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -11534,7 +10769,6 @@ pack.$(OBJEXT): {$(VPATH)}config.h
pack.$(OBJEXT): {$(VPATH)}constant.h
pack.$(OBJEXT): {$(VPATH)}defines.h
pack.$(OBJEXT): {$(VPATH)}encoding.h
-pack.$(OBJEXT): {$(VPATH)}id.h
pack.$(OBJEXT): {$(VPATH)}id_table.h
pack.$(OBJEXT): {$(VPATH)}intern.h
pack.$(OBJEXT): {$(VPATH)}internal.h
@@ -11576,7 +10810,6 @@ pack.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
pack.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
pack.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
pack.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-pack.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
pack.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
pack.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
pack.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -11645,6 +10878,7 @@ pack.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
pack.$(OBJEXT): {$(VPATH)}internal/intern/error.h
pack.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
pack.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+pack.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
pack.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
pack.$(OBJEXT): {$(VPATH)}internal/intern/io.h
pack.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -11675,45 +10909,30 @@ pack.$(OBJEXT): {$(VPATH)}internal/memory.h
pack.$(OBJEXT): {$(VPATH)}internal/method.h
pack.$(OBJEXT): {$(VPATH)}internal/module.h
pack.$(OBJEXT): {$(VPATH)}internal/newobj.h
+pack.$(OBJEXT): {$(VPATH)}internal/rgengc.h
pack.$(OBJEXT): {$(VPATH)}internal/scan_args.h
pack.$(OBJEXT): {$(VPATH)}internal/special_consts.h
pack.$(OBJEXT): {$(VPATH)}internal/static_assert.h
pack.$(OBJEXT): {$(VPATH)}internal/stdalign.h
pack.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-pack.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
pack.$(OBJEXT): {$(VPATH)}internal/symbol.h
pack.$(OBJEXT): {$(VPATH)}internal/value.h
pack.$(OBJEXT): {$(VPATH)}internal/value_type.h
pack.$(OBJEXT): {$(VPATH)}internal/variable.h
pack.$(OBJEXT): {$(VPATH)}internal/warning_push.h
pack.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-pack.$(OBJEXT): {$(VPATH)}method.h
pack.$(OBJEXT): {$(VPATH)}missing.h
-pack.$(OBJEXT): {$(VPATH)}node.h
pack.$(OBJEXT): {$(VPATH)}onigmo.h
pack.$(OBJEXT): {$(VPATH)}oniguruma.h
pack.$(OBJEXT): {$(VPATH)}pack.c
pack.$(OBJEXT): {$(VPATH)}pack.rbinc
-pack.$(OBJEXT): {$(VPATH)}ruby_assert.h
-pack.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-pack.$(OBJEXT): {$(VPATH)}rubyparser.h
pack.$(OBJEXT): {$(VPATH)}shape.h
pack.$(OBJEXT): {$(VPATH)}st.h
pack.$(OBJEXT): {$(VPATH)}subst.h
-pack.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-pack.$(OBJEXT): {$(VPATH)}thread_native.h
pack.$(OBJEXT): {$(VPATH)}util.h
-pack.$(OBJEXT): {$(VPATH)}vm_core.h
-pack.$(OBJEXT): {$(VPATH)}vm_opts.h
-parse.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-parse.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-parse.$(OBJEXT): $(CCAN_DIR)/list/list.h
-parse.$(OBJEXT): $(CCAN_DIR)/str/str.h
parse.$(OBJEXT): $(hdrdir)/ruby.h
parse.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-parse.$(OBJEXT): $(hdrdir)/ruby/version.h
parse.$(OBJEXT): $(top_srcdir)/internal/array.h
-parse.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
parse.$(OBJEXT): $(top_srcdir)/internal/bignum.h
parse.$(OBJEXT): $(top_srcdir)/internal/bits.h
parse.$(OBJEXT): $(top_srcdir)/internal/compile.h
@@ -11730,8 +10949,6 @@ parse.$(OBJEXT): $(top_srcdir)/internal/numeric.h
parse.$(OBJEXT): $(top_srcdir)/internal/parse.h
parse.$(OBJEXT): $(top_srcdir)/internal/rational.h
parse.$(OBJEXT): $(top_srcdir)/internal/re.h
-parse.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-parse.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
parse.$(OBJEXT): $(top_srcdir)/internal/serial.h
parse.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
parse.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -11741,7 +10958,6 @@ parse.$(OBJEXT): $(top_srcdir)/internal/variable.h
parse.$(OBJEXT): $(top_srcdir)/internal/vm.h
parse.$(OBJEXT): $(top_srcdir)/internal/warnings.h
parse.$(OBJEXT): {$(VPATH)}assert.h
-parse.$(OBJEXT): {$(VPATH)}atomic.h
parse.$(OBJEXT): {$(VPATH)}backward/2/assume.h
parse.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
parse.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -11798,7 +11014,6 @@ parse.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
parse.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
parse.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
parse.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-parse.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
parse.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
parse.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
parse.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -11867,6 +11082,7 @@ parse.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
parse.$(OBJEXT): {$(VPATH)}internal/intern/error.h
parse.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
parse.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+parse.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
parse.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
parse.$(OBJEXT): {$(VPATH)}internal/intern/io.h
parse.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -11897,12 +11113,12 @@ parse.$(OBJEXT): {$(VPATH)}internal/memory.h
parse.$(OBJEXT): {$(VPATH)}internal/method.h
parse.$(OBJEXT): {$(VPATH)}internal/module.h
parse.$(OBJEXT): {$(VPATH)}internal/newobj.h
+parse.$(OBJEXT): {$(VPATH)}internal/rgengc.h
parse.$(OBJEXT): {$(VPATH)}internal/scan_args.h
parse.$(OBJEXT): {$(VPATH)}internal/special_consts.h
parse.$(OBJEXT): {$(VPATH)}internal/static_assert.h
parse.$(OBJEXT): {$(VPATH)}internal/stdalign.h
parse.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-parse.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
parse.$(OBJEXT): {$(VPATH)}internal/symbol.h
parse.$(OBJEXT): {$(VPATH)}internal/value.h
parse.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -11911,7 +11127,6 @@ parse.$(OBJEXT): {$(VPATH)}internal/warning_push.h
parse.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
parse.$(OBJEXT): {$(VPATH)}io.h
parse.$(OBJEXT): {$(VPATH)}lex.c
-parse.$(OBJEXT): {$(VPATH)}method.h
parse.$(OBJEXT): {$(VPATH)}missing.h
parse.$(OBJEXT): {$(VPATH)}node.h
parse.$(OBJEXT): {$(VPATH)}onigmo.h
@@ -11919,1081 +11134,22 @@ parse.$(OBJEXT): {$(VPATH)}oniguruma.h
parse.$(OBJEXT): {$(VPATH)}parse.c
parse.$(OBJEXT): {$(VPATH)}parse.h
parse.$(OBJEXT): {$(VPATH)}parse.y
-parse.$(OBJEXT): {$(VPATH)}parser_node.h
-parse.$(OBJEXT): {$(VPATH)}parser_st.h
parse.$(OBJEXT): {$(VPATH)}probes.dmyh
parse.$(OBJEXT): {$(VPATH)}probes.h
parse.$(OBJEXT): {$(VPATH)}ractor.h
parse.$(OBJEXT): {$(VPATH)}regenc.h
parse.$(OBJEXT): {$(VPATH)}regex.h
parse.$(OBJEXT): {$(VPATH)}ruby_assert.h
-parse.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-parse.$(OBJEXT): {$(VPATH)}rubyparser.h
parse.$(OBJEXT): {$(VPATH)}shape.h
parse.$(OBJEXT): {$(VPATH)}st.h
parse.$(OBJEXT): {$(VPATH)}subst.h
parse.$(OBJEXT): {$(VPATH)}symbol.h
-parse.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-parse.$(OBJEXT): {$(VPATH)}thread_native.h
parse.$(OBJEXT): {$(VPATH)}util.h
-parse.$(OBJEXT): {$(VPATH)}vm_core.h
-parse.$(OBJEXT): {$(VPATH)}vm_opts.h
-parser_st.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-parser_st.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-parser_st.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-parser_st.$(OBJEXT): {$(VPATH)}assert.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-parser_st.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-parser_st.$(OBJEXT): {$(VPATH)}config.h
-parser_st.$(OBJEXT): {$(VPATH)}defines.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/assume.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/cast.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/config.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/dosish.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-parser_st.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-parser_st.$(OBJEXT): {$(VPATH)}missing.h
-parser_st.$(OBJEXT): {$(VPATH)}parser_bits.h
-parser_st.$(OBJEXT): {$(VPATH)}parser_st.c
-parser_st.$(OBJEXT): {$(VPATH)}parser_st.h
-parser_st.$(OBJEXT): {$(VPATH)}parser_value.h
-parser_st.$(OBJEXT): {$(VPATH)}st.c
-prism/api_node.$(OBJEXT): $(hdrdir)/ruby.h
-prism/api_node.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/extension.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/api_node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/api_node.$(OBJEXT): {$(VPATH)}assert.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-prism/api_node.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-prism/api_node.$(OBJEXT): {$(VPATH)}config.h
-prism/api_node.$(OBJEXT): {$(VPATH)}defines.h
-prism/api_node.$(OBJEXT): {$(VPATH)}encoding.h
-prism/api_node.$(OBJEXT): {$(VPATH)}intern.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/abi.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/assume.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/cast.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/config.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/ctype.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/dosish.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/error.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/eval.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/event.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/gc.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/glob.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/globals.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/iterator.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/memory.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/method.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/module.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/newobj.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/symbol.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/value.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/value_type.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/variable.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-prism/api_node.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-prism/api_node.$(OBJEXT): {$(VPATH)}missing.h
-prism/api_node.$(OBJEXT): {$(VPATH)}onigmo.h
-prism/api_node.$(OBJEXT): {$(VPATH)}oniguruma.h
-prism/api_node.$(OBJEXT): {$(VPATH)}prism/api_node.c
-prism/api_node.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/api_node.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-prism/api_node.$(OBJEXT): {$(VPATH)}prism/version.h
-prism/api_node.$(OBJEXT): {$(VPATH)}st.h
-prism/api_node.$(OBJEXT): {$(VPATH)}subst.h
-prism/api_pack.$(OBJEXT): $(hdrdir)/ruby.h
-prism/api_pack.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/api_pack.c
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/extension.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/api_pack.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}assert.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}config.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}defines.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}encoding.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}intern.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/abi.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/assume.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/cast.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/config.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/ctype.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/dosish.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/error.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/eval.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/event.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/gc.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/glob.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/globals.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/iterator.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/memory.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/method.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/module.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/newobj.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/symbol.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/value.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/value_type.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/variable.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}missing.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}onigmo.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}oniguruma.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}prism/version.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}st.h
-prism/api_pack.$(OBJEXT): {$(VPATH)}subst.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/diagnostic.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/diagnostic.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/diagnostic.$(OBJEXT): {$(VPATH)}prism/diagnostic.c
-prism/diagnostic.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-prism/encoding.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/encoding.$(OBJEXT): $(top_srcdir)/prism/encoding.c
-prism/encoding.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/encoding.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/extension.$(OBJEXT): $(hdrdir)/ruby.h
-prism/extension.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/extension.c
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/extension.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/extension.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/extension.$(OBJEXT): {$(VPATH)}assert.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-prism/extension.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-prism/extension.$(OBJEXT): {$(VPATH)}config.h
-prism/extension.$(OBJEXT): {$(VPATH)}defines.h
-prism/extension.$(OBJEXT): {$(VPATH)}encoding.h
-prism/extension.$(OBJEXT): {$(VPATH)}intern.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/abi.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/assume.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/cast.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/config.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/ctype.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/dosish.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/error.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/eval.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/event.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/gc.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/glob.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/globals.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/iterator.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/memory.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/method.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/module.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/newobj.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/symbol.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/value.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/value_type.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/variable.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-prism/extension.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-prism/extension.$(OBJEXT): {$(VPATH)}missing.h
-prism/extension.$(OBJEXT): {$(VPATH)}onigmo.h
-prism/extension.$(OBJEXT): {$(VPATH)}oniguruma.h
-prism/extension.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/extension.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-prism/extension.$(OBJEXT): {$(VPATH)}prism/version.h
-prism/extension.$(OBJEXT): {$(VPATH)}st.h
-prism/extension.$(OBJEXT): {$(VPATH)}subst.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/node.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/node.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/node.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-prism/node.$(OBJEXT): {$(VPATH)}prism/node.c
-prism/options.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/options.$(OBJEXT): $(top_srcdir)/prism/options.c
-prism/options.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/options.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/options.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/options.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/pack.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/pack.$(OBJEXT): $(top_srcdir)/prism/pack.c
-prism/pack.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/prettyprint.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/prettyprint.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/prettyprint.$(OBJEXT): {$(VPATH)}prism/prettyprint.c
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/prism.c
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/prism.$(OBJEXT): $(top_srcdir)/prism/version.h
-prism/prism.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/prism.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-prism/prism.$(OBJEXT): {$(VPATH)}prism/version.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/regexp.c
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/regexp.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/regexp.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/serialize.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/serialize.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/serialize.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-prism/serialize.$(OBJEXT): {$(VPATH)}prism/serialize.c
-prism/serialize.$(OBJEXT): {$(VPATH)}prism/version.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/static_literals.c
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/static_literals.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/static_literals.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/token_type.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/token_type.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/token_type.$(OBJEXT): {$(VPATH)}prism/token_type.c
-prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.c
-prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/util/pm_buffer.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/util/pm_char.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_char.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.c
-prism/util/pm_char.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/util/pm_char.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/util/pm_constant_pool.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_constant_pool.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.c
-prism/util/pm_constant_pool.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.c
-prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/util/pm_integer.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/util/pm_list.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.c
-prism/util/pm_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.c
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/util/pm_memchr.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/util/pm_memchr.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/util/pm_newline_list.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_newline_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.c
-prism/util/pm_newline_list.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/util/pm_string.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_string.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.c
-prism/util/pm_string.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/util/pm_strncasecmp.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_strncasecmp.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.c
-prism/util/pm_strncasecmp.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.c
-prism/util/pm_strpbrk.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism/util/pm_strpbrk.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-prism_init.$(OBJEXT): $(hdrdir)/ruby.h
-prism_init.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/defines.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/extension.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/node.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/options.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/pack.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/parser.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/prism.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-prism_init.$(OBJEXT): $(top_srcdir)/prism_init.c
-prism_init.$(OBJEXT): {$(VPATH)}assert.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-prism_init.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-prism_init.$(OBJEXT): {$(VPATH)}config.h
-prism_init.$(OBJEXT): {$(VPATH)}defines.h
-prism_init.$(OBJEXT): {$(VPATH)}encoding.h
-prism_init.$(OBJEXT): {$(VPATH)}intern.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/abi.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/assume.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/cast.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/config.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/ctype.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/dosish.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/error.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/eval.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/event.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/gc.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/glob.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/globals.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/iterator.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/memory.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/method.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/module.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/newobj.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/symbol.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/value.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/value_type.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/variable.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-prism_init.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-prism_init.$(OBJEXT): {$(VPATH)}missing.h
-prism_init.$(OBJEXT): {$(VPATH)}onigmo.h
-prism_init.$(OBJEXT): {$(VPATH)}oniguruma.h
-prism_init.$(OBJEXT): {$(VPATH)}prism/ast.h
-prism_init.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-prism_init.$(OBJEXT): {$(VPATH)}prism/version.h
-prism_init.$(OBJEXT): {$(VPATH)}prism_init.c
-prism_init.$(OBJEXT): {$(VPATH)}st.h
-prism_init.$(OBJEXT): {$(VPATH)}subst.h
proc.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
proc.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
proc.$(OBJEXT): $(CCAN_DIR)/list/list.h
proc.$(OBJEXT): $(CCAN_DIR)/str/str.h
proc.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-proc.$(OBJEXT): $(hdrdir)/ruby/version.h
proc.$(OBJEXT): $(top_srcdir)/internal/array.h
proc.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
proc.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -13001,10 +11157,10 @@ proc.$(OBJEXT): $(top_srcdir)/internal/compilers.h
proc.$(OBJEXT): $(top_srcdir)/internal/error.h
proc.$(OBJEXT): $(top_srcdir)/internal/eval.h
proc.$(OBJEXT): $(top_srcdir)/internal/gc.h
+proc.$(OBJEXT): $(top_srcdir)/internal/hash.h
proc.$(OBJEXT): $(top_srcdir)/internal/imemo.h
proc.$(OBJEXT): $(top_srcdir)/internal/object.h
proc.$(OBJEXT): $(top_srcdir)/internal/proc.h
-proc.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
proc.$(OBJEXT): $(top_srcdir)/internal/serial.h
proc.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
proc.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -13012,26 +11168,6 @@ proc.$(OBJEXT): $(top_srcdir)/internal/symbol.h
proc.$(OBJEXT): $(top_srcdir)/internal/variable.h
proc.$(OBJEXT): $(top_srcdir)/internal/vm.h
proc.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-proc.$(OBJEXT): $(top_srcdir)/prism/defines.h
-proc.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-proc.$(OBJEXT): $(top_srcdir)/prism/node.h
-proc.$(OBJEXT): $(top_srcdir)/prism/options.h
-proc.$(OBJEXT): $(top_srcdir)/prism/pack.h
-proc.$(OBJEXT): $(top_srcdir)/prism/parser.h
-proc.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-proc.$(OBJEXT): $(top_srcdir)/prism/prism.h
-proc.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-proc.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-proc.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
proc.$(OBJEXT): {$(VPATH)}assert.h
proc.$(OBJEXT): {$(VPATH)}atomic.h
proc.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -13045,10 +11181,10 @@ proc.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
proc.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
proc.$(OBJEXT): {$(VPATH)}config.h
proc.$(OBJEXT): {$(VPATH)}constant.h
-proc.$(OBJEXT): {$(VPATH)}debug_counter.h
proc.$(OBJEXT): {$(VPATH)}defines.h
proc.$(OBJEXT): {$(VPATH)}encoding.h
proc.$(OBJEXT): {$(VPATH)}eval_intern.h
+proc.$(OBJEXT): {$(VPATH)}gc.h
proc.$(OBJEXT): {$(VPATH)}id.h
proc.$(OBJEXT): {$(VPATH)}id_table.h
proc.$(OBJEXT): {$(VPATH)}intern.h
@@ -13091,7 +11227,6 @@ proc.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
proc.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
proc.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
proc.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-proc.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
proc.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
proc.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
proc.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -13160,6 +11295,7 @@ proc.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
proc.$(OBJEXT): {$(VPATH)}internal/intern/error.h
proc.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
proc.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+proc.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
proc.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
proc.$(OBJEXT): {$(VPATH)}internal/intern/io.h
proc.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -13190,12 +11326,12 @@ proc.$(OBJEXT): {$(VPATH)}internal/memory.h
proc.$(OBJEXT): {$(VPATH)}internal/method.h
proc.$(OBJEXT): {$(VPATH)}internal/module.h
proc.$(OBJEXT): {$(VPATH)}internal/newobj.h
+proc.$(OBJEXT): {$(VPATH)}internal/rgengc.h
proc.$(OBJEXT): {$(VPATH)}internal/scan_args.h
proc.$(OBJEXT): {$(VPATH)}internal/special_consts.h
proc.$(OBJEXT): {$(VPATH)}internal/static_assert.h
proc.$(OBJEXT): {$(VPATH)}internal/stdalign.h
proc.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-proc.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
proc.$(OBJEXT): {$(VPATH)}internal/symbol.h
proc.$(OBJEXT): {$(VPATH)}internal/value.h
proc.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -13208,23 +11344,16 @@ proc.$(OBJEXT): {$(VPATH)}missing.h
proc.$(OBJEXT): {$(VPATH)}node.h
proc.$(OBJEXT): {$(VPATH)}onigmo.h
proc.$(OBJEXT): {$(VPATH)}oniguruma.h
-proc.$(OBJEXT): {$(VPATH)}prism/ast.h
-proc.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-proc.$(OBJEXT): {$(VPATH)}prism/version.h
-proc.$(OBJEXT): {$(VPATH)}prism_compile.h
proc.$(OBJEXT): {$(VPATH)}proc.c
proc.$(OBJEXT): {$(VPATH)}ruby_assert.h
proc.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-proc.$(OBJEXT): {$(VPATH)}rubyparser.h
proc.$(OBJEXT): {$(VPATH)}shape.h
proc.$(OBJEXT): {$(VPATH)}st.h
proc.$(OBJEXT): {$(VPATH)}subst.h
proc.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
proc.$(OBJEXT): {$(VPATH)}thread_native.h
proc.$(OBJEXT): {$(VPATH)}vm_core.h
-proc.$(OBJEXT): {$(VPATH)}vm_debug.h
proc.$(OBJEXT): {$(VPATH)}vm_opts.h
-proc.$(OBJEXT): {$(VPATH)}vm_sync.h
proc.$(OBJEXT): {$(VPATH)}yjit.h
process.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
process.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
@@ -13232,7 +11361,6 @@ process.$(OBJEXT): $(CCAN_DIR)/list/list.h
process.$(OBJEXT): $(CCAN_DIR)/str/str.h
process.$(OBJEXT): $(hdrdir)/ruby.h
process.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-process.$(OBJEXT): $(hdrdir)/ruby/version.h
process.$(OBJEXT): $(top_srcdir)/internal/array.h
process.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
process.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -13246,11 +11374,9 @@ process.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
process.$(OBJEXT): $(top_srcdir)/internal/gc.h
process.$(OBJEXT): $(top_srcdir)/internal/hash.h
process.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-process.$(OBJEXT): $(top_srcdir)/internal/io.h
process.$(OBJEXT): $(top_srcdir)/internal/numeric.h
process.$(OBJEXT): $(top_srcdir)/internal/object.h
process.$(OBJEXT): $(top_srcdir)/internal/process.h
-process.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
process.$(OBJEXT): $(top_srcdir)/internal/serial.h
process.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
process.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -13320,7 +11446,6 @@ process.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
process.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
process.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
process.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-process.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
process.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
process.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
process.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -13389,6 +11514,7 @@ process.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
process.$(OBJEXT): {$(VPATH)}internal/intern/error.h
process.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
process.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+process.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
process.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
process.$(OBJEXT): {$(VPATH)}internal/intern/io.h
process.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -13419,12 +11545,12 @@ process.$(OBJEXT): {$(VPATH)}internal/memory.h
process.$(OBJEXT): {$(VPATH)}internal/method.h
process.$(OBJEXT): {$(VPATH)}internal/module.h
process.$(OBJEXT): {$(VPATH)}internal/newobj.h
+process.$(OBJEXT): {$(VPATH)}internal/rgengc.h
process.$(OBJEXT): {$(VPATH)}internal/scan_args.h
process.$(OBJEXT): {$(VPATH)}internal/special_consts.h
process.$(OBJEXT): {$(VPATH)}internal/static_assert.h
process.$(OBJEXT): {$(VPATH)}internal/stdalign.h
process.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-process.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
process.$(OBJEXT): {$(VPATH)}internal/symbol.h
process.$(OBJEXT): {$(VPATH)}internal/value.h
process.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -13434,15 +11560,14 @@ process.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
process.$(OBJEXT): {$(VPATH)}io.h
process.$(OBJEXT): {$(VPATH)}method.h
process.$(OBJEXT): {$(VPATH)}missing.h
+process.$(OBJEXT): {$(VPATH)}mjit.h
process.$(OBJEXT): {$(VPATH)}node.h
process.$(OBJEXT): {$(VPATH)}onigmo.h
process.$(OBJEXT): {$(VPATH)}oniguruma.h
process.$(OBJEXT): {$(VPATH)}process.c
process.$(OBJEXT): {$(VPATH)}ractor.h
-process.$(OBJEXT): {$(VPATH)}rjit.h
process.$(OBJEXT): {$(VPATH)}ruby_assert.h
process.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-process.$(OBJEXT): {$(VPATH)}rubyparser.h
process.$(OBJEXT): {$(VPATH)}shape.h
process.$(OBJEXT): {$(VPATH)}st.h
process.$(OBJEXT): {$(VPATH)}subst.h
@@ -13451,16 +11576,13 @@ process.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
process.$(OBJEXT): {$(VPATH)}thread_native.h
process.$(OBJEXT): {$(VPATH)}util.h
process.$(OBJEXT): {$(VPATH)}vm_core.h
-process.$(OBJEXT): {$(VPATH)}vm_debug.h
process.$(OBJEXT): {$(VPATH)}vm_opts.h
-process.$(OBJEXT): {$(VPATH)}vm_sync.h
ractor.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
ractor.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
ractor.$(OBJEXT): $(CCAN_DIR)/list/list.h
ractor.$(OBJEXT): $(CCAN_DIR)/str/str.h
ractor.$(OBJEXT): $(hdrdir)/ruby.h
ractor.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-ractor.$(OBJEXT): $(hdrdir)/ruby/version.h
ractor.$(OBJEXT): $(top_srcdir)/internal/array.h
ractor.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
ractor.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -13474,7 +11596,6 @@ ractor.$(OBJEXT): $(top_srcdir)/internal/hash.h
ractor.$(OBJEXT): $(top_srcdir)/internal/imemo.h
ractor.$(OBJEXT): $(top_srcdir)/internal/numeric.h
ractor.$(OBJEXT): $(top_srcdir)/internal/rational.h
-ractor.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
ractor.$(OBJEXT): $(top_srcdir)/internal/serial.h
ractor.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
ractor.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -13500,7 +11621,7 @@ ractor.$(OBJEXT): {$(VPATH)}constant.h
ractor.$(OBJEXT): {$(VPATH)}debug_counter.h
ractor.$(OBJEXT): {$(VPATH)}defines.h
ractor.$(OBJEXT): {$(VPATH)}encoding.h
-ractor.$(OBJEXT): {$(VPATH)}eval_intern.h
+ractor.$(OBJEXT): {$(VPATH)}gc.h
ractor.$(OBJEXT): {$(VPATH)}id.h
ractor.$(OBJEXT): {$(VPATH)}id_table.h
ractor.$(OBJEXT): {$(VPATH)}intern.h
@@ -13543,7 +11664,6 @@ ractor.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
ractor.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
ractor.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
ractor.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-ractor.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
ractor.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
ractor.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
ractor.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -13612,6 +11732,7 @@ ractor.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
ractor.$(OBJEXT): {$(VPATH)}internal/intern/error.h
ractor.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
ractor.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+ractor.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
ractor.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
ractor.$(OBJEXT): {$(VPATH)}internal/intern/io.h
ractor.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -13642,12 +11763,12 @@ ractor.$(OBJEXT): {$(VPATH)}internal/memory.h
ractor.$(OBJEXT): {$(VPATH)}internal/method.h
ractor.$(OBJEXT): {$(VPATH)}internal/module.h
ractor.$(OBJEXT): {$(VPATH)}internal/newobj.h
+ractor.$(OBJEXT): {$(VPATH)}internal/rgengc.h
ractor.$(OBJEXT): {$(VPATH)}internal/scan_args.h
ractor.$(OBJEXT): {$(VPATH)}internal/special_consts.h
ractor.$(OBJEXT): {$(VPATH)}internal/static_assert.h
ractor.$(OBJEXT): {$(VPATH)}internal/stdalign.h
ractor.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-ractor.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
ractor.$(OBJEXT): {$(VPATH)}internal/symbol.h
ractor.$(OBJEXT): {$(VPATH)}internal/value.h
ractor.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -13656,6 +11777,7 @@ ractor.$(OBJEXT): {$(VPATH)}internal/warning_push.h
ractor.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
ractor.$(OBJEXT): {$(VPATH)}method.h
ractor.$(OBJEXT): {$(VPATH)}missing.h
+ractor.$(OBJEXT): {$(VPATH)}mjit.h
ractor.$(OBJEXT): {$(VPATH)}node.h
ractor.$(OBJEXT): {$(VPATH)}onigmo.h
ractor.$(OBJEXT): {$(VPATH)}oniguruma.h
@@ -13663,35 +11785,28 @@ ractor.$(OBJEXT): {$(VPATH)}ractor.c
ractor.$(OBJEXT): {$(VPATH)}ractor.h
ractor.$(OBJEXT): {$(VPATH)}ractor.rbinc
ractor.$(OBJEXT): {$(VPATH)}ractor_core.h
-ractor.$(OBJEXT): {$(VPATH)}rjit.h
ractor.$(OBJEXT): {$(VPATH)}ruby_assert.h
ractor.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-ractor.$(OBJEXT): {$(VPATH)}rubyparser.h
ractor.$(OBJEXT): {$(VPATH)}shape.h
ractor.$(OBJEXT): {$(VPATH)}st.h
ractor.$(OBJEXT): {$(VPATH)}subst.h
ractor.$(OBJEXT): {$(VPATH)}thread.h
ractor.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
ractor.$(OBJEXT): {$(VPATH)}thread_native.h
+ractor.$(OBJEXT): {$(VPATH)}transient_heap.h
ractor.$(OBJEXT): {$(VPATH)}variable.h
ractor.$(OBJEXT): {$(VPATH)}vm_core.h
ractor.$(OBJEXT): {$(VPATH)}vm_debug.h
ractor.$(OBJEXT): {$(VPATH)}vm_opts.h
ractor.$(OBJEXT): {$(VPATH)}vm_sync.h
ractor.$(OBJEXT): {$(VPATH)}yjit.h
-random.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-random.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-random.$(OBJEXT): $(CCAN_DIR)/list/list.h
-random.$(OBJEXT): $(CCAN_DIR)/str/str.h
random.$(OBJEXT): $(hdrdir)/ruby/ruby.h
random.$(OBJEXT): $(top_srcdir)/internal/array.h
-random.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
random.$(OBJEXT): $(top_srcdir)/internal/bignum.h
random.$(OBJEXT): $(top_srcdir)/internal/bits.h
random.$(OBJEXT): $(top_srcdir)/internal/compilers.h
random.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
random.$(OBJEXT): $(top_srcdir)/internal/gc.h
-random.$(OBJEXT): $(top_srcdir)/internal/imemo.h
random.$(OBJEXT): $(top_srcdir)/internal/numeric.h
random.$(OBJEXT): $(top_srcdir)/internal/random.h
random.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
@@ -13714,8 +11829,6 @@ random.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
random.$(OBJEXT): {$(VPATH)}config.h
random.$(OBJEXT): {$(VPATH)}constant.h
random.$(OBJEXT): {$(VPATH)}defines.h
-random.$(OBJEXT): {$(VPATH)}encoding.h
-random.$(OBJEXT): {$(VPATH)}id.h
random.$(OBJEXT): {$(VPATH)}id_table.h
random.$(OBJEXT): {$(VPATH)}intern.h
random.$(OBJEXT): {$(VPATH)}internal.h
@@ -13757,7 +11870,6 @@ random.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
random.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
random.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
random.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-random.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
random.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
random.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
random.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -13790,15 +11902,6 @@ random.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
random.$(OBJEXT): {$(VPATH)}internal/ctype.h
random.$(OBJEXT): {$(VPATH)}internal/dllexport.h
random.$(OBJEXT): {$(VPATH)}internal/dosish.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-random.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
random.$(OBJEXT): {$(VPATH)}internal/error.h
random.$(OBJEXT): {$(VPATH)}internal/eval.h
random.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -13826,6 +11929,7 @@ random.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
random.$(OBJEXT): {$(VPATH)}internal/intern/error.h
random.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
random.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+random.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
random.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
random.$(OBJEXT): {$(VPATH)}internal/intern/io.h
random.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -13856,41 +11960,30 @@ random.$(OBJEXT): {$(VPATH)}internal/memory.h
random.$(OBJEXT): {$(VPATH)}internal/method.h
random.$(OBJEXT): {$(VPATH)}internal/module.h
random.$(OBJEXT): {$(VPATH)}internal/newobj.h
+random.$(OBJEXT): {$(VPATH)}internal/rgengc.h
random.$(OBJEXT): {$(VPATH)}internal/scan_args.h
random.$(OBJEXT): {$(VPATH)}internal/special_consts.h
random.$(OBJEXT): {$(VPATH)}internal/static_assert.h
random.$(OBJEXT): {$(VPATH)}internal/stdalign.h
random.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-random.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
random.$(OBJEXT): {$(VPATH)}internal/symbol.h
random.$(OBJEXT): {$(VPATH)}internal/value.h
random.$(OBJEXT): {$(VPATH)}internal/value_type.h
random.$(OBJEXT): {$(VPATH)}internal/variable.h
random.$(OBJEXT): {$(VPATH)}internal/warning_push.h
random.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-random.$(OBJEXT): {$(VPATH)}method.h
random.$(OBJEXT): {$(VPATH)}missing.h
random.$(OBJEXT): {$(VPATH)}mt19937.c
-random.$(OBJEXT): {$(VPATH)}node.h
-random.$(OBJEXT): {$(VPATH)}onigmo.h
-random.$(OBJEXT): {$(VPATH)}oniguruma.h
random.$(OBJEXT): {$(VPATH)}ractor.h
random.$(OBJEXT): {$(VPATH)}random.c
random.$(OBJEXT): {$(VPATH)}random.h
-random.$(OBJEXT): {$(VPATH)}ruby_assert.h
random.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-random.$(OBJEXT): {$(VPATH)}rubyparser.h
random.$(OBJEXT): {$(VPATH)}shape.h
random.$(OBJEXT): {$(VPATH)}siphash.c
random.$(OBJEXT): {$(VPATH)}siphash.h
random.$(OBJEXT): {$(VPATH)}st.h
random.$(OBJEXT): {$(VPATH)}subst.h
-random.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-random.$(OBJEXT): {$(VPATH)}thread_native.h
-random.$(OBJEXT): {$(VPATH)}vm_core.h
-random.$(OBJEXT): {$(VPATH)}vm_opts.h
range.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-range.$(OBJEXT): $(hdrdir)/ruby/version.h
range.$(OBJEXT): $(top_srcdir)/internal/array.h
range.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
range.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -13964,7 +12057,6 @@ range.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
range.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
range.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
range.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-range.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
range.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
range.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
range.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -14033,6 +12125,7 @@ range.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
range.$(OBJEXT): {$(VPATH)}internal/intern/error.h
range.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
range.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+range.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
range.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
range.$(OBJEXT): {$(VPATH)}internal/intern/io.h
range.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -14063,12 +12156,12 @@ range.$(OBJEXT): {$(VPATH)}internal/memory.h
range.$(OBJEXT): {$(VPATH)}internal/method.h
range.$(OBJEXT): {$(VPATH)}internal/module.h
range.$(OBJEXT): {$(VPATH)}internal/newobj.h
+range.$(OBJEXT): {$(VPATH)}internal/rgengc.h
range.$(OBJEXT): {$(VPATH)}internal/scan_args.h
range.$(OBJEXT): {$(VPATH)}internal/special_consts.h
range.$(OBJEXT): {$(VPATH)}internal/static_assert.h
range.$(OBJEXT): {$(VPATH)}internal/stdalign.h
range.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-range.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
range.$(OBJEXT): {$(VPATH)}internal/symbol.h
range.$(OBJEXT): {$(VPATH)}internal/value.h
range.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -14082,13 +12175,8 @@ range.$(OBJEXT): {$(VPATH)}range.c
range.$(OBJEXT): {$(VPATH)}shape.h
range.$(OBJEXT): {$(VPATH)}st.h
range.$(OBJEXT): {$(VPATH)}subst.h
-rational.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-rational.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-rational.$(OBJEXT): $(CCAN_DIR)/list/list.h
-rational.$(OBJEXT): $(CCAN_DIR)/str/str.h
rational.$(OBJEXT): $(hdrdir)/ruby/ruby.h
rational.$(OBJEXT): $(top_srcdir)/internal/array.h
-rational.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
rational.$(OBJEXT): $(top_srcdir)/internal/bignum.h
rational.$(OBJEXT): $(top_srcdir)/internal/bits.h
rational.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -14096,18 +12184,15 @@ rational.$(OBJEXT): $(top_srcdir)/internal/compilers.h
rational.$(OBJEXT): $(top_srcdir)/internal/complex.h
rational.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
rational.$(OBJEXT): $(top_srcdir)/internal/gc.h
-rational.$(OBJEXT): $(top_srcdir)/internal/imemo.h
rational.$(OBJEXT): $(top_srcdir)/internal/numeric.h
rational.$(OBJEXT): $(top_srcdir)/internal/object.h
rational.$(OBJEXT): $(top_srcdir)/internal/rational.h
-rational.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
rational.$(OBJEXT): $(top_srcdir)/internal/serial.h
rational.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
rational.$(OBJEXT): $(top_srcdir)/internal/variable.h
rational.$(OBJEXT): $(top_srcdir)/internal/vm.h
rational.$(OBJEXT): $(top_srcdir)/internal/warnings.h
rational.$(OBJEXT): {$(VPATH)}assert.h
-rational.$(OBJEXT): {$(VPATH)}atomic.h
rational.$(OBJEXT): {$(VPATH)}backward/2/assume.h
rational.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
rational.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -14120,7 +12205,6 @@ rational.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
rational.$(OBJEXT): {$(VPATH)}config.h
rational.$(OBJEXT): {$(VPATH)}constant.h
rational.$(OBJEXT): {$(VPATH)}defines.h
-rational.$(OBJEXT): {$(VPATH)}encoding.h
rational.$(OBJEXT): {$(VPATH)}id.h
rational.$(OBJEXT): {$(VPATH)}id_table.h
rational.$(OBJEXT): {$(VPATH)}intern.h
@@ -14163,7 +12247,6 @@ rational.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
rational.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
rational.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
rational.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-rational.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
rational.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
rational.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
rational.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -14196,15 +12279,6 @@ rational.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
rational.$(OBJEXT): {$(VPATH)}internal/ctype.h
rational.$(OBJEXT): {$(VPATH)}internal/dllexport.h
rational.$(OBJEXT): {$(VPATH)}internal/dosish.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-rational.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
rational.$(OBJEXT): {$(VPATH)}internal/error.h
rational.$(OBJEXT): {$(VPATH)}internal/eval.h
rational.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -14232,6 +12306,7 @@ rational.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
rational.$(OBJEXT): {$(VPATH)}internal/intern/error.h
rational.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
rational.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+rational.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
rational.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
rational.$(OBJEXT): {$(VPATH)}internal/intern/io.h
rational.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -14262,42 +12337,27 @@ rational.$(OBJEXT): {$(VPATH)}internal/memory.h
rational.$(OBJEXT): {$(VPATH)}internal/method.h
rational.$(OBJEXT): {$(VPATH)}internal/module.h
rational.$(OBJEXT): {$(VPATH)}internal/newobj.h
+rational.$(OBJEXT): {$(VPATH)}internal/rgengc.h
rational.$(OBJEXT): {$(VPATH)}internal/scan_args.h
rational.$(OBJEXT): {$(VPATH)}internal/special_consts.h
rational.$(OBJEXT): {$(VPATH)}internal/static_assert.h
rational.$(OBJEXT): {$(VPATH)}internal/stdalign.h
rational.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-rational.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
rational.$(OBJEXT): {$(VPATH)}internal/symbol.h
rational.$(OBJEXT): {$(VPATH)}internal/value.h
rational.$(OBJEXT): {$(VPATH)}internal/value_type.h
rational.$(OBJEXT): {$(VPATH)}internal/variable.h
rational.$(OBJEXT): {$(VPATH)}internal/warning_push.h
rational.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-rational.$(OBJEXT): {$(VPATH)}method.h
rational.$(OBJEXT): {$(VPATH)}missing.h
-rational.$(OBJEXT): {$(VPATH)}node.h
-rational.$(OBJEXT): {$(VPATH)}onigmo.h
-rational.$(OBJEXT): {$(VPATH)}oniguruma.h
rational.$(OBJEXT): {$(VPATH)}rational.c
rational.$(OBJEXT): {$(VPATH)}ruby_assert.h
-rational.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-rational.$(OBJEXT): {$(VPATH)}rubyparser.h
rational.$(OBJEXT): {$(VPATH)}shape.h
rational.$(OBJEXT): {$(VPATH)}st.h
rational.$(OBJEXT): {$(VPATH)}subst.h
-rational.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-rational.$(OBJEXT): {$(VPATH)}thread_native.h
-rational.$(OBJEXT): {$(VPATH)}vm_core.h
-rational.$(OBJEXT): {$(VPATH)}vm_opts.h
-re.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-re.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-re.$(OBJEXT): $(CCAN_DIR)/list/list.h
-re.$(OBJEXT): $(CCAN_DIR)/str/str.h
re.$(OBJEXT): $(hdrdir)/ruby.h
re.$(OBJEXT): $(hdrdir)/ruby/ruby.h
re.$(OBJEXT): $(top_srcdir)/internal/array.h
-re.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
re.$(OBJEXT): $(top_srcdir)/internal/bits.h
re.$(OBJEXT): $(top_srcdir)/internal/class.h
re.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -14308,16 +12368,13 @@ re.$(OBJEXT): $(top_srcdir)/internal/imemo.h
re.$(OBJEXT): $(top_srcdir)/internal/object.h
re.$(OBJEXT): $(top_srcdir)/internal/ractor.h
re.$(OBJEXT): $(top_srcdir)/internal/re.h
-re.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
re.$(OBJEXT): $(top_srcdir)/internal/serial.h
re.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
re.$(OBJEXT): $(top_srcdir)/internal/string.h
re.$(OBJEXT): $(top_srcdir)/internal/time.h
re.$(OBJEXT): $(top_srcdir)/internal/variable.h
-re.$(OBJEXT): $(top_srcdir)/internal/vm.h
re.$(OBJEXT): $(top_srcdir)/internal/warnings.h
re.$(OBJEXT): {$(VPATH)}assert.h
-re.$(OBJEXT): {$(VPATH)}atomic.h
re.$(OBJEXT): {$(VPATH)}backward/2/assume.h
re.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
re.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -14333,7 +12390,6 @@ re.$(OBJEXT): {$(VPATH)}defines.h
re.$(OBJEXT): {$(VPATH)}encindex.h
re.$(OBJEXT): {$(VPATH)}encoding.h
re.$(OBJEXT): {$(VPATH)}hrtime.h
-re.$(OBJEXT): {$(VPATH)}id.h
re.$(OBJEXT): {$(VPATH)}id_table.h
re.$(OBJEXT): {$(VPATH)}intern.h
re.$(OBJEXT): {$(VPATH)}internal.h
@@ -14375,7 +12431,6 @@ re.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
re.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
re.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
re.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-re.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
re.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
re.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
re.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -14445,6 +12500,7 @@ re.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
re.$(OBJEXT): {$(VPATH)}internal/intern/error.h
re.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
re.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+re.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
re.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
re.$(OBJEXT): {$(VPATH)}internal/intern/io.h
re.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -14475,21 +12531,19 @@ re.$(OBJEXT): {$(VPATH)}internal/memory.h
re.$(OBJEXT): {$(VPATH)}internal/method.h
re.$(OBJEXT): {$(VPATH)}internal/module.h
re.$(OBJEXT): {$(VPATH)}internal/newobj.h
+re.$(OBJEXT): {$(VPATH)}internal/rgengc.h
re.$(OBJEXT): {$(VPATH)}internal/scan_args.h
re.$(OBJEXT): {$(VPATH)}internal/special_consts.h
re.$(OBJEXT): {$(VPATH)}internal/static_assert.h
re.$(OBJEXT): {$(VPATH)}internal/stdalign.h
re.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-re.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
re.$(OBJEXT): {$(VPATH)}internal/symbol.h
re.$(OBJEXT): {$(VPATH)}internal/value.h
re.$(OBJEXT): {$(VPATH)}internal/value_type.h
re.$(OBJEXT): {$(VPATH)}internal/variable.h
re.$(OBJEXT): {$(VPATH)}internal/warning_push.h
re.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-re.$(OBJEXT): {$(VPATH)}method.h
re.$(OBJEXT): {$(VPATH)}missing.h
-re.$(OBJEXT): {$(VPATH)}node.h
re.$(OBJEXT): {$(VPATH)}onigmo.h
re.$(OBJEXT): {$(VPATH)}oniguruma.h
re.$(OBJEXT): {$(VPATH)}re.c
@@ -14497,17 +12551,10 @@ re.$(OBJEXT): {$(VPATH)}re.h
re.$(OBJEXT): {$(VPATH)}regenc.h
re.$(OBJEXT): {$(VPATH)}regex.h
re.$(OBJEXT): {$(VPATH)}regint.h
-re.$(OBJEXT): {$(VPATH)}ruby_assert.h
-re.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-re.$(OBJEXT): {$(VPATH)}rubyparser.h
re.$(OBJEXT): {$(VPATH)}shape.h
re.$(OBJEXT): {$(VPATH)}st.h
re.$(OBJEXT): {$(VPATH)}subst.h
-re.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-re.$(OBJEXT): {$(VPATH)}thread_native.h
re.$(OBJEXT): {$(VPATH)}util.h
-re.$(OBJEXT): {$(VPATH)}vm_core.h
-re.$(OBJEXT): {$(VPATH)}vm_opts.h
regcomp.$(OBJEXT): $(hdrdir)/ruby.h
regcomp.$(OBJEXT): $(hdrdir)/ruby/ruby.h
regcomp.$(OBJEXT): {$(VPATH)}assert.h
@@ -14560,7 +12607,6 @@ regcomp.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
regcomp.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
regcomp.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
regcomp.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
regcomp.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
regcomp.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
regcomp.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -14620,6 +12666,7 @@ regcomp.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
regcomp.$(OBJEXT): {$(VPATH)}internal/intern/error.h
regcomp.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
regcomp.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
regcomp.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
regcomp.$(OBJEXT): {$(VPATH)}internal/intern/io.h
regcomp.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -14650,12 +12697,12 @@ regcomp.$(OBJEXT): {$(VPATH)}internal/memory.h
regcomp.$(OBJEXT): {$(VPATH)}internal/method.h
regcomp.$(OBJEXT): {$(VPATH)}internal/module.h
regcomp.$(OBJEXT): {$(VPATH)}internal/newobj.h
+regcomp.$(OBJEXT): {$(VPATH)}internal/rgengc.h
regcomp.$(OBJEXT): {$(VPATH)}internal/scan_args.h
regcomp.$(OBJEXT): {$(VPATH)}internal/special_consts.h
regcomp.$(OBJEXT): {$(VPATH)}internal/static_assert.h
regcomp.$(OBJEXT): {$(VPATH)}internal/stdalign.h
regcomp.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-regcomp.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
regcomp.$(OBJEXT): {$(VPATH)}internal/symbol.h
regcomp.$(OBJEXT): {$(VPATH)}internal/value.h
regcomp.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -14722,7 +12769,6 @@ regenc.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
regenc.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
regenc.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
regenc.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-regenc.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
regenc.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
regenc.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
regenc.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -14782,6 +12828,7 @@ regenc.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
regenc.$(OBJEXT): {$(VPATH)}internal/intern/error.h
regenc.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
regenc.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+regenc.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
regenc.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
regenc.$(OBJEXT): {$(VPATH)}internal/intern/io.h
regenc.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -14812,12 +12859,12 @@ regenc.$(OBJEXT): {$(VPATH)}internal/memory.h
regenc.$(OBJEXT): {$(VPATH)}internal/method.h
regenc.$(OBJEXT): {$(VPATH)}internal/module.h
regenc.$(OBJEXT): {$(VPATH)}internal/newobj.h
+regenc.$(OBJEXT): {$(VPATH)}internal/rgengc.h
regenc.$(OBJEXT): {$(VPATH)}internal/scan_args.h
regenc.$(OBJEXT): {$(VPATH)}internal/special_consts.h
regenc.$(OBJEXT): {$(VPATH)}internal/static_assert.h
regenc.$(OBJEXT): {$(VPATH)}internal/stdalign.h
regenc.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-regenc.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
regenc.$(OBJEXT): {$(VPATH)}internal/symbol.h
regenc.$(OBJEXT): {$(VPATH)}internal/value.h
regenc.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -14883,7 +12930,6 @@ regerror.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
regerror.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
regerror.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
regerror.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-regerror.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
regerror.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
regerror.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
regerror.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -14943,6 +12989,7 @@ regerror.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
regerror.$(OBJEXT): {$(VPATH)}internal/intern/error.h
regerror.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
regerror.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+regerror.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
regerror.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
regerror.$(OBJEXT): {$(VPATH)}internal/intern/io.h
regerror.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -14973,12 +13020,12 @@ regerror.$(OBJEXT): {$(VPATH)}internal/memory.h
regerror.$(OBJEXT): {$(VPATH)}internal/method.h
regerror.$(OBJEXT): {$(VPATH)}internal/module.h
regerror.$(OBJEXT): {$(VPATH)}internal/newobj.h
+regerror.$(OBJEXT): {$(VPATH)}internal/rgengc.h
regerror.$(OBJEXT): {$(VPATH)}internal/scan_args.h
regerror.$(OBJEXT): {$(VPATH)}internal/special_consts.h
regerror.$(OBJEXT): {$(VPATH)}internal/static_assert.h
regerror.$(OBJEXT): {$(VPATH)}internal/stdalign.h
regerror.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-regerror.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
regerror.$(OBJEXT): {$(VPATH)}internal/symbol.h
regerror.$(OBJEXT): {$(VPATH)}internal/value.h
regerror.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -15044,7 +13091,6 @@ regexec.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
regexec.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
regexec.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
regexec.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-regexec.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
regexec.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
regexec.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
regexec.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -15104,6 +13150,7 @@ regexec.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
regexec.$(OBJEXT): {$(VPATH)}internal/intern/error.h
regexec.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
regexec.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+regexec.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
regexec.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
regexec.$(OBJEXT): {$(VPATH)}internal/intern/io.h
regexec.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -15134,12 +13181,12 @@ regexec.$(OBJEXT): {$(VPATH)}internal/memory.h
regexec.$(OBJEXT): {$(VPATH)}internal/method.h
regexec.$(OBJEXT): {$(VPATH)}internal/module.h
regexec.$(OBJEXT): {$(VPATH)}internal/newobj.h
+regexec.$(OBJEXT): {$(VPATH)}internal/rgengc.h
regexec.$(OBJEXT): {$(VPATH)}internal/scan_args.h
regexec.$(OBJEXT): {$(VPATH)}internal/special_consts.h
regexec.$(OBJEXT): {$(VPATH)}internal/static_assert.h
regexec.$(OBJEXT): {$(VPATH)}internal/stdalign.h
regexec.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-regexec.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
regexec.$(OBJEXT): {$(VPATH)}internal/symbol.h
regexec.$(OBJEXT): {$(VPATH)}internal/value.h
regexec.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -15209,7 +13256,6 @@ regparse.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
regparse.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
regparse.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
regparse.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-regparse.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
regparse.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
regparse.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
regparse.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -15269,6 +13315,7 @@ regparse.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
regparse.$(OBJEXT): {$(VPATH)}internal/intern/error.h
regparse.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
regparse.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+regparse.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
regparse.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
regparse.$(OBJEXT): {$(VPATH)}internal/intern/io.h
regparse.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -15299,12 +13346,12 @@ regparse.$(OBJEXT): {$(VPATH)}internal/memory.h
regparse.$(OBJEXT): {$(VPATH)}internal/method.h
regparse.$(OBJEXT): {$(VPATH)}internal/module.h
regparse.$(OBJEXT): {$(VPATH)}internal/newobj.h
+regparse.$(OBJEXT): {$(VPATH)}internal/rgengc.h
regparse.$(OBJEXT): {$(VPATH)}internal/scan_args.h
regparse.$(OBJEXT): {$(VPATH)}internal/special_consts.h
regparse.$(OBJEXT): {$(VPATH)}internal/static_assert.h
regparse.$(OBJEXT): {$(VPATH)}internal/stdalign.h
regparse.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-regparse.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
regparse.$(OBJEXT): {$(VPATH)}internal/symbol.h
regparse.$(OBJEXT): {$(VPATH)}internal/value.h
regparse.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -15371,7 +13418,6 @@ regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -15431,6 +13477,7 @@ regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/error.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/io.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -15461,12 +13508,12 @@ regsyntax.$(OBJEXT): {$(VPATH)}internal/memory.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/method.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/module.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/newobj.h
+regsyntax.$(OBJEXT): {$(VPATH)}internal/rgengc.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/scan_args.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/special_consts.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/static_assert.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/stdalign.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-regsyntax.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/symbol.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/value.h
regsyntax.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -15480,514 +13527,6 @@ regsyntax.$(OBJEXT): {$(VPATH)}regint.h
regsyntax.$(OBJEXT): {$(VPATH)}regsyntax.c
regsyntax.$(OBJEXT): {$(VPATH)}st.h
regsyntax.$(OBJEXT): {$(VPATH)}subst.h
-rjit.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-rjit.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-rjit.$(OBJEXT): $(CCAN_DIR)/list/list.h
-rjit.$(OBJEXT): $(CCAN_DIR)/str/str.h
-rjit.$(OBJEXT): $(hdrdir)/ruby.h
-rjit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-rjit.$(OBJEXT): $(hdrdir)/ruby/version.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/array.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/class.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/compile.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/cont.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/file.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/gc.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/hash.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/process.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/serial.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/string.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/struct.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/variable.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/vm.h
-rjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/defines.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/node.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/options.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/pack.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/parser.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/prism.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-rjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-rjit.$(OBJEXT): {$(VPATH)}assert.h
-rjit.$(OBJEXT): {$(VPATH)}atomic.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-rjit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-rjit.$(OBJEXT): {$(VPATH)}builtin.h
-rjit.$(OBJEXT): {$(VPATH)}config.h
-rjit.$(OBJEXT): {$(VPATH)}constant.h
-rjit.$(OBJEXT): {$(VPATH)}debug.h
-rjit.$(OBJEXT): {$(VPATH)}debug_counter.h
-rjit.$(OBJEXT): {$(VPATH)}defines.h
-rjit.$(OBJEXT): {$(VPATH)}dln.h
-rjit.$(OBJEXT): {$(VPATH)}encoding.h
-rjit.$(OBJEXT): {$(VPATH)}id.h
-rjit.$(OBJEXT): {$(VPATH)}id_table.h
-rjit.$(OBJEXT): {$(VPATH)}insns.def
-rjit.$(OBJEXT): {$(VPATH)}insns.inc
-rjit.$(OBJEXT): {$(VPATH)}insns_info.inc
-rjit.$(OBJEXT): {$(VPATH)}intern.h
-rjit.$(OBJEXT): {$(VPATH)}internal.h
-rjit.$(OBJEXT): {$(VPATH)}internal/abi.h
-rjit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-rjit.$(OBJEXT): {$(VPATH)}internal/assume.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-rjit.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-rjit.$(OBJEXT): {$(VPATH)}internal/cast.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-rjit.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-rjit.$(OBJEXT): {$(VPATH)}internal/config.h
-rjit.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-rjit.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-rjit.$(OBJEXT): {$(VPATH)}internal/ctype.h
-rjit.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-rjit.$(OBJEXT): {$(VPATH)}internal/dosish.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-rjit.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-rjit.$(OBJEXT): {$(VPATH)}internal/error.h
-rjit.$(OBJEXT): {$(VPATH)}internal/eval.h
-rjit.$(OBJEXT): {$(VPATH)}internal/event.h
-rjit.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-rjit.$(OBJEXT): {$(VPATH)}internal/gc.h
-rjit.$(OBJEXT): {$(VPATH)}internal/glob.h
-rjit.$(OBJEXT): {$(VPATH)}internal/globals.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-rjit.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-rjit.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-rjit.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-rjit.$(OBJEXT): {$(VPATH)}internal/iterator.h
-rjit.$(OBJEXT): {$(VPATH)}internal/memory.h
-rjit.$(OBJEXT): {$(VPATH)}internal/method.h
-rjit.$(OBJEXT): {$(VPATH)}internal/module.h
-rjit.$(OBJEXT): {$(VPATH)}internal/newobj.h
-rjit.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-rjit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-rjit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-rjit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-rjit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-rjit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-rjit.$(OBJEXT): {$(VPATH)}internal/symbol.h
-rjit.$(OBJEXT): {$(VPATH)}internal/value.h
-rjit.$(OBJEXT): {$(VPATH)}internal/value_type.h
-rjit.$(OBJEXT): {$(VPATH)}internal/variable.h
-rjit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-rjit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-rjit.$(OBJEXT): {$(VPATH)}iseq.h
-rjit.$(OBJEXT): {$(VPATH)}method.h
-rjit.$(OBJEXT): {$(VPATH)}missing.h
-rjit.$(OBJEXT): {$(VPATH)}node.h
-rjit.$(OBJEXT): {$(VPATH)}onigmo.h
-rjit.$(OBJEXT): {$(VPATH)}oniguruma.h
-rjit.$(OBJEXT): {$(VPATH)}prism/ast.h
-rjit.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-rjit.$(OBJEXT): {$(VPATH)}prism/version.h
-rjit.$(OBJEXT): {$(VPATH)}prism_compile.h
-rjit.$(OBJEXT): {$(VPATH)}ractor.h
-rjit.$(OBJEXT): {$(VPATH)}ractor_core.h
-rjit.$(OBJEXT): {$(VPATH)}rjit.c
-rjit.$(OBJEXT): {$(VPATH)}rjit.h
-rjit.$(OBJEXT): {$(VPATH)}rjit.rbinc
-rjit.$(OBJEXT): {$(VPATH)}rjit_c.h
-rjit.$(OBJEXT): {$(VPATH)}ruby_assert.h
-rjit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-rjit.$(OBJEXT): {$(VPATH)}rubyparser.h
-rjit.$(OBJEXT): {$(VPATH)}shape.h
-rjit.$(OBJEXT): {$(VPATH)}st.h
-rjit.$(OBJEXT): {$(VPATH)}subst.h
-rjit.$(OBJEXT): {$(VPATH)}thread.h
-rjit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-rjit.$(OBJEXT): {$(VPATH)}thread_native.h
-rjit.$(OBJEXT): {$(VPATH)}util.h
-rjit.$(OBJEXT): {$(VPATH)}vm_callinfo.h
-rjit.$(OBJEXT): {$(VPATH)}vm_core.h
-rjit.$(OBJEXT): {$(VPATH)}vm_debug.h
-rjit.$(OBJEXT): {$(VPATH)}vm_opts.h
-rjit.$(OBJEXT): {$(VPATH)}vm_sync.h
-rjit.$(OBJEXT): {$(VPATH)}yjit.h
-rjit_c.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-rjit_c.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-rjit_c.$(OBJEXT): $(CCAN_DIR)/list/list.h
-rjit_c.$(OBJEXT): $(CCAN_DIR)/str/str.h
-rjit_c.$(OBJEXT): $(hdrdir)/ruby.h
-rjit_c.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-rjit_c.$(OBJEXT): $(srcdir)/rjit_c.rb
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/array.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/class.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/compile.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/gc.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/hash.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/object.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/proc.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/serial.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/string.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/struct.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/variable.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/vm.h
-rjit_c.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/defines.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/node.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/options.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/pack.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/parser.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/prism.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-rjit_c.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-rjit_c.$(OBJEXT): {$(VPATH)}assert.h
-rjit_c.$(OBJEXT): {$(VPATH)}atomic.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-rjit_c.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-rjit_c.$(OBJEXT): {$(VPATH)}builtin.h
-rjit_c.$(OBJEXT): {$(VPATH)}config.h
-rjit_c.$(OBJEXT): {$(VPATH)}constant.h
-rjit_c.$(OBJEXT): {$(VPATH)}debug.h
-rjit_c.$(OBJEXT): {$(VPATH)}debug_counter.h
-rjit_c.$(OBJEXT): {$(VPATH)}defines.h
-rjit_c.$(OBJEXT): {$(VPATH)}encoding.h
-rjit_c.$(OBJEXT): {$(VPATH)}id.h
-rjit_c.$(OBJEXT): {$(VPATH)}id_table.h
-rjit_c.$(OBJEXT): {$(VPATH)}insns.def
-rjit_c.$(OBJEXT): {$(VPATH)}insns.inc
-rjit_c.$(OBJEXT): {$(VPATH)}insns_info.inc
-rjit_c.$(OBJEXT): {$(VPATH)}intern.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/abi.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/assume.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/cast.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/config.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/ctype.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/dosish.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/error.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/eval.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/event.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/gc.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/glob.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/globals.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/iterator.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/memory.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/method.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/module.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/newobj.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/symbol.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/value.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/value_type.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/variable.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-rjit_c.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-rjit_c.$(OBJEXT): {$(VPATH)}iseq.h
-rjit_c.$(OBJEXT): {$(VPATH)}method.h
-rjit_c.$(OBJEXT): {$(VPATH)}missing.h
-rjit_c.$(OBJEXT): {$(VPATH)}node.h
-rjit_c.$(OBJEXT): {$(VPATH)}onigmo.h
-rjit_c.$(OBJEXT): {$(VPATH)}oniguruma.h
-rjit_c.$(OBJEXT): {$(VPATH)}prism/ast.h
-rjit_c.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-rjit_c.$(OBJEXT): {$(VPATH)}prism/version.h
-rjit_c.$(OBJEXT): {$(VPATH)}prism_compile.h
-rjit_c.$(OBJEXT): {$(VPATH)}probes.dmyh
-rjit_c.$(OBJEXT): {$(VPATH)}probes.h
-rjit_c.$(OBJEXT): {$(VPATH)}probes_helper.h
-rjit_c.$(OBJEXT): {$(VPATH)}rjit.h
-rjit_c.$(OBJEXT): {$(VPATH)}rjit_c.c
-rjit_c.$(OBJEXT): {$(VPATH)}rjit_c.h
-rjit_c.$(OBJEXT): {$(VPATH)}rjit_c.rb
-rjit_c.$(OBJEXT): {$(VPATH)}rjit_c.rbinc
-rjit_c.$(OBJEXT): {$(VPATH)}ruby_assert.h
-rjit_c.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-rjit_c.$(OBJEXT): {$(VPATH)}rubyparser.h
-rjit_c.$(OBJEXT): {$(VPATH)}shape.h
-rjit_c.$(OBJEXT): {$(VPATH)}st.h
-rjit_c.$(OBJEXT): {$(VPATH)}subst.h
-rjit_c.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-rjit_c.$(OBJEXT): {$(VPATH)}thread_native.h
-rjit_c.$(OBJEXT): {$(VPATH)}vm_callinfo.h
-rjit_c.$(OBJEXT): {$(VPATH)}vm_core.h
-rjit_c.$(OBJEXT): {$(VPATH)}vm_debug.h
-rjit_c.$(OBJEXT): {$(VPATH)}vm_exec.h
-rjit_c.$(OBJEXT): {$(VPATH)}vm_insnhelper.h
-rjit_c.$(OBJEXT): {$(VPATH)}vm_opts.h
-rjit_c.$(OBJEXT): {$(VPATH)}vm_sync.h
-rjit_c.$(OBJEXT): {$(VPATH)}yjit.h
ruby-runner.$(OBJEXT): {$(VPATH)}config.h
ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
ruby-runner.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
@@ -16009,16 +13548,12 @@ ruby.$(OBJEXT): $(hdrdir)/ruby/ruby.h
ruby.$(OBJEXT): $(hdrdir)/ruby/version.h
ruby.$(OBJEXT): $(top_srcdir)/internal/array.h
ruby.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/bits.h
ruby.$(OBJEXT): $(top_srcdir)/internal/class.h
ruby.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h
ruby.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/complex.h
ruby.$(OBJEXT): $(top_srcdir)/internal/cont.h
ruby.$(OBJEXT): $(top_srcdir)/internal/error.h
ruby.$(OBJEXT): $(top_srcdir)/internal/file.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
ruby.$(OBJEXT): $(top_srcdir)/internal/gc.h
ruby.$(OBJEXT): $(top_srcdir)/internal/imemo.h
ruby.$(OBJEXT): $(top_srcdir)/internal/inits.h
@@ -16026,39 +13561,15 @@ ruby.$(OBJEXT): $(top_srcdir)/internal/io.h
ruby.$(OBJEXT): $(top_srcdir)/internal/load.h
ruby.$(OBJEXT): $(top_srcdir)/internal/loadpath.h
ruby.$(OBJEXT): $(top_srcdir)/internal/missing.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/numeric.h
ruby.$(OBJEXT): $(top_srcdir)/internal/object.h
ruby.$(OBJEXT): $(top_srcdir)/internal/parse.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/rational.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+ruby.$(OBJEXT): $(top_srcdir)/internal/process.h
ruby.$(OBJEXT): $(top_srcdir)/internal/serial.h
ruby.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
ruby.$(OBJEXT): $(top_srcdir)/internal/string.h
-ruby.$(OBJEXT): $(top_srcdir)/internal/thread.h
ruby.$(OBJEXT): $(top_srcdir)/internal/variable.h
ruby.$(OBJEXT): $(top_srcdir)/internal/vm.h
ruby.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/defines.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/node.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/options.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/pack.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/parser.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/prism.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
ruby.$(OBJEXT): {$(VPATH)}assert.h
ruby.$(OBJEXT): {$(VPATH)}atomic.h
ruby.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -16119,7 +13630,6 @@ ruby.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
ruby.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
ruby.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
ruby.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-ruby.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
ruby.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
ruby.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
ruby.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -16188,6 +13698,7 @@ ruby.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
ruby.$(OBJEXT): {$(VPATH)}internal/intern/error.h
ruby.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
ruby.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+ruby.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
ruby.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
ruby.$(OBJEXT): {$(VPATH)}internal/intern/io.h
ruby.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -16218,12 +13729,12 @@ ruby.$(OBJEXT): {$(VPATH)}internal/memory.h
ruby.$(OBJEXT): {$(VPATH)}internal/method.h
ruby.$(OBJEXT): {$(VPATH)}internal/module.h
ruby.$(OBJEXT): {$(VPATH)}internal/newobj.h
+ruby.$(OBJEXT): {$(VPATH)}internal/rgengc.h
ruby.$(OBJEXT): {$(VPATH)}internal/scan_args.h
ruby.$(OBJEXT): {$(VPATH)}internal/special_consts.h
ruby.$(OBJEXT): {$(VPATH)}internal/static_assert.h
ruby.$(OBJEXT): {$(VPATH)}internal/stdalign.h
ruby.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-ruby.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
ruby.$(OBJEXT): {$(VPATH)}internal/symbol.h
ruby.$(OBJEXT): {$(VPATH)}internal/value.h
ruby.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -16234,18 +13745,13 @@ ruby.$(OBJEXT): {$(VPATH)}io.h
ruby.$(OBJEXT): {$(VPATH)}iseq.h
ruby.$(OBJEXT): {$(VPATH)}method.h
ruby.$(OBJEXT): {$(VPATH)}missing.h
+ruby.$(OBJEXT): {$(VPATH)}mjit.h
ruby.$(OBJEXT): {$(VPATH)}node.h
ruby.$(OBJEXT): {$(VPATH)}onigmo.h
ruby.$(OBJEXT): {$(VPATH)}oniguruma.h
-ruby.$(OBJEXT): {$(VPATH)}prism/ast.h
-ruby.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-ruby.$(OBJEXT): {$(VPATH)}prism/version.h
-ruby.$(OBJEXT): {$(VPATH)}prism_compile.h
-ruby.$(OBJEXT): {$(VPATH)}rjit.h
ruby.$(OBJEXT): {$(VPATH)}ruby.c
ruby.$(OBJEXT): {$(VPATH)}ruby_assert.h
ruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-ruby.$(OBJEXT): {$(VPATH)}rubyparser.h
ruby.$(OBJEXT): {$(VPATH)}shape.h
ruby.$(OBJEXT): {$(VPATH)}st.h
ruby.$(OBJEXT): {$(VPATH)}subst.h
@@ -16256,197 +13762,6 @@ ruby.$(OBJEXT): {$(VPATH)}util.h
ruby.$(OBJEXT): {$(VPATH)}vm_core.h
ruby.$(OBJEXT): {$(VPATH)}vm_opts.h
ruby.$(OBJEXT): {$(VPATH)}yjit.h
-ruby_parser.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/array.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/bits.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/complex.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/error.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/numeric.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/parse.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/rational.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/re.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/serial.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/string.h
-ruby_parser.$(OBJEXT): $(top_srcdir)/internal/vm.h
-ruby_parser.$(OBJEXT): {$(VPATH)}assert.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-ruby_parser.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-ruby_parser.$(OBJEXT): {$(VPATH)}config.h
-ruby_parser.$(OBJEXT): {$(VPATH)}defines.h
-ruby_parser.$(OBJEXT): {$(VPATH)}encoding.h
-ruby_parser.$(OBJEXT): {$(VPATH)}intern.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/abi.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/assume.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/cast.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/config.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/ctype.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/dosish.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/error.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/eval.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/event.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/gc.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/glob.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/globals.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/iterator.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/memory.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/method.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/module.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/newobj.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/symbol.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/value.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/value_type.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/variable.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-ruby_parser.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-ruby_parser.$(OBJEXT): {$(VPATH)}missing.h
-ruby_parser.$(OBJEXT): {$(VPATH)}node.h
-ruby_parser.$(OBJEXT): {$(VPATH)}onigmo.h
-ruby_parser.$(OBJEXT): {$(VPATH)}oniguruma.h
-ruby_parser.$(OBJEXT): {$(VPATH)}ruby_assert.h
-ruby_parser.$(OBJEXT): {$(VPATH)}ruby_parser.c
-ruby_parser.$(OBJEXT): {$(VPATH)}rubyparser.h
-ruby_parser.$(OBJEXT): {$(VPATH)}st.h
-ruby_parser.$(OBJEXT): {$(VPATH)}subst.h
scheduler.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
scheduler.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
scheduler.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -16457,7 +13772,6 @@ scheduler.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/compilers.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/gc.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-scheduler.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/serial.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
scheduler.$(OBJEXT): $(top_srcdir)/internal/thread.h
@@ -16522,7 +13836,6 @@ scheduler.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
scheduler.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
scheduler.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
scheduler.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
scheduler.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
scheduler.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
scheduler.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -16591,6 +13904,7 @@ scheduler.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
scheduler.$(OBJEXT): {$(VPATH)}internal/intern/error.h
scheduler.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
scheduler.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
scheduler.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
scheduler.$(OBJEXT): {$(VPATH)}internal/intern/io.h
scheduler.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -16621,12 +13935,12 @@ scheduler.$(OBJEXT): {$(VPATH)}internal/memory.h
scheduler.$(OBJEXT): {$(VPATH)}internal/method.h
scheduler.$(OBJEXT): {$(VPATH)}internal/module.h
scheduler.$(OBJEXT): {$(VPATH)}internal/newobj.h
+scheduler.$(OBJEXT): {$(VPATH)}internal/rgengc.h
scheduler.$(OBJEXT): {$(VPATH)}internal/scan_args.h
scheduler.$(OBJEXT): {$(VPATH)}internal/special_consts.h
scheduler.$(OBJEXT): {$(VPATH)}internal/static_assert.h
scheduler.$(OBJEXT): {$(VPATH)}internal/stdalign.h
scheduler.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-scheduler.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
scheduler.$(OBJEXT): {$(VPATH)}internal/symbol.h
scheduler.$(OBJEXT): {$(VPATH)}internal/value.h
scheduler.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -16642,7 +13956,6 @@ scheduler.$(OBJEXT): {$(VPATH)}onigmo.h
scheduler.$(OBJEXT): {$(VPATH)}oniguruma.h
scheduler.$(OBJEXT): {$(VPATH)}ruby_assert.h
scheduler.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-scheduler.$(OBJEXT): {$(VPATH)}rubyparser.h
scheduler.$(OBJEXT): {$(VPATH)}scheduler.c
scheduler.$(OBJEXT): {$(VPATH)}shape.h
scheduler.$(OBJEXT): {$(VPATH)}st.h
@@ -16703,7 +14016,6 @@ setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -16763,6 +14075,7 @@ setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/error.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/io.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -16793,12 +14106,12 @@ setproctitle.$(OBJEXT): {$(VPATH)}internal/memory.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/method.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/module.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/newobj.h
+setproctitle.$(OBJEXT): {$(VPATH)}internal/rgengc.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/scan_args.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/special_consts.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/static_assert.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/stdalign.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-setproctitle.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/symbol.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/value.h
setproctitle.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -16815,19 +14128,14 @@ shape.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
shape.$(OBJEXT): $(CCAN_DIR)/list/list.h
shape.$(OBJEXT): $(CCAN_DIR)/str/str.h
shape.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-shape.$(OBJEXT): $(hdrdir)/ruby/version.h
shape.$(OBJEXT): $(top_srcdir)/internal/array.h
shape.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
shape.$(OBJEXT): $(top_srcdir)/internal/class.h
shape.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-shape.$(OBJEXT): $(top_srcdir)/internal/error.h
shape.$(OBJEXT): $(top_srcdir)/internal/gc.h
shape.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-shape.$(OBJEXT): $(top_srcdir)/internal/object.h
-shape.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
shape.$(OBJEXT): $(top_srcdir)/internal/serial.h
shape.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-shape.$(OBJEXT): $(top_srcdir)/internal/string.h
shape.$(OBJEXT): $(top_srcdir)/internal/symbol.h
shape.$(OBJEXT): $(top_srcdir)/internal/variable.h
shape.$(OBJEXT): $(top_srcdir)/internal/vm.h
@@ -16848,6 +14156,7 @@ shape.$(OBJEXT): {$(VPATH)}constant.h
shape.$(OBJEXT): {$(VPATH)}debug_counter.h
shape.$(OBJEXT): {$(VPATH)}defines.h
shape.$(OBJEXT): {$(VPATH)}encoding.h
+shape.$(OBJEXT): {$(VPATH)}gc.h
shape.$(OBJEXT): {$(VPATH)}id.h
shape.$(OBJEXT): {$(VPATH)}id_table.h
shape.$(OBJEXT): {$(VPATH)}intern.h
@@ -16890,7 +14199,6 @@ shape.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
shape.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
shape.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
shape.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-shape.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
shape.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
shape.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
shape.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -16959,6 +14267,7 @@ shape.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
shape.$(OBJEXT): {$(VPATH)}internal/intern/error.h
shape.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
shape.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+shape.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
shape.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
shape.$(OBJEXT): {$(VPATH)}internal/intern/io.h
shape.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -16989,12 +14298,12 @@ shape.$(OBJEXT): {$(VPATH)}internal/memory.h
shape.$(OBJEXT): {$(VPATH)}internal/method.h
shape.$(OBJEXT): {$(VPATH)}internal/module.h
shape.$(OBJEXT): {$(VPATH)}internal/newobj.h
+shape.$(OBJEXT): {$(VPATH)}internal/rgengc.h
shape.$(OBJEXT): {$(VPATH)}internal/scan_args.h
shape.$(OBJEXT): {$(VPATH)}internal/special_consts.h
shape.$(OBJEXT): {$(VPATH)}internal/static_assert.h
shape.$(OBJEXT): {$(VPATH)}internal/stdalign.h
shape.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-shape.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
shape.$(OBJEXT): {$(VPATH)}internal/symbol.h
shape.$(OBJEXT): {$(VPATH)}internal/value.h
shape.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -17008,7 +14317,6 @@ shape.$(OBJEXT): {$(VPATH)}onigmo.h
shape.$(OBJEXT): {$(VPATH)}oniguruma.h
shape.$(OBJEXT): {$(VPATH)}ruby_assert.h
shape.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-shape.$(OBJEXT): {$(VPATH)}rubyparser.h
shape.$(OBJEXT): {$(VPATH)}shape.c
shape.$(OBJEXT): {$(VPATH)}shape.h
shape.$(OBJEXT): {$(VPATH)}st.h
@@ -17026,11 +14334,9 @@ signal.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
signal.$(OBJEXT): $(CCAN_DIR)/list/list.h
signal.$(OBJEXT): $(CCAN_DIR)/str/str.h
signal.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-signal.$(OBJEXT): $(hdrdir)/ruby/version.h
signal.$(OBJEXT): $(top_srcdir)/internal/array.h
signal.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
signal.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-signal.$(OBJEXT): $(top_srcdir)/internal/error.h
signal.$(OBJEXT): $(top_srcdir)/internal/eval.h
signal.$(OBJEXT): $(top_srcdir)/internal/gc.h
signal.$(OBJEXT): $(top_srcdir)/internal/imemo.h
@@ -17101,8 +14407,8 @@ signal.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+signal.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-signal.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
signal.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -17171,6 +14477,7 @@ signal.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
signal.$(OBJEXT): {$(VPATH)}internal/intern/error.h
signal.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
signal.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+signal.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
signal.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
signal.$(OBJEXT): {$(VPATH)}internal/intern/io.h
signal.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -17201,12 +14508,12 @@ signal.$(OBJEXT): {$(VPATH)}internal/memory.h
signal.$(OBJEXT): {$(VPATH)}internal/method.h
signal.$(OBJEXT): {$(VPATH)}internal/module.h
signal.$(OBJEXT): {$(VPATH)}internal/newobj.h
+signal.$(OBJEXT): {$(VPATH)}internal/rgengc.h
signal.$(OBJEXT): {$(VPATH)}internal/scan_args.h
signal.$(OBJEXT): {$(VPATH)}internal/special_consts.h
signal.$(OBJEXT): {$(VPATH)}internal/static_assert.h
signal.$(OBJEXT): {$(VPATH)}internal/stdalign.h
signal.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-signal.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
signal.$(OBJEXT): {$(VPATH)}internal/symbol.h
signal.$(OBJEXT): {$(VPATH)}internal/value.h
signal.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -17222,7 +14529,6 @@ signal.$(OBJEXT): {$(VPATH)}ractor.h
signal.$(OBJEXT): {$(VPATH)}ractor_core.h
signal.$(OBJEXT): {$(VPATH)}ruby_assert.h
signal.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-signal.$(OBJEXT): {$(VPATH)}rubyparser.h
signal.$(OBJEXT): {$(VPATH)}shape.h
signal.$(OBJEXT): {$(VPATH)}signal.c
signal.$(OBJEXT): {$(VPATH)}st.h
@@ -17233,7 +14539,6 @@ signal.$(OBJEXT): {$(VPATH)}vm_core.h
signal.$(OBJEXT): {$(VPATH)}vm_debug.h
signal.$(OBJEXT): {$(VPATH)}vm_opts.h
sprintf.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-sprintf.$(OBJEXT): $(hdrdir)/ruby/version.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/bignum.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/bits.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -17308,7 +14613,6 @@ sprintf.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
sprintf.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
sprintf.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
sprintf.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
sprintf.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
sprintf.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
sprintf.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -17378,6 +14682,7 @@ sprintf.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
sprintf.$(OBJEXT): {$(VPATH)}internal/intern/error.h
sprintf.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
sprintf.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
sprintf.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
sprintf.$(OBJEXT): {$(VPATH)}internal/intern/io.h
sprintf.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -17408,12 +14713,12 @@ sprintf.$(OBJEXT): {$(VPATH)}internal/memory.h
sprintf.$(OBJEXT): {$(VPATH)}internal/method.h
sprintf.$(OBJEXT): {$(VPATH)}internal/module.h
sprintf.$(OBJEXT): {$(VPATH)}internal/newobj.h
+sprintf.$(OBJEXT): {$(VPATH)}internal/rgengc.h
sprintf.$(OBJEXT): {$(VPATH)}internal/scan_args.h
sprintf.$(OBJEXT): {$(VPATH)}internal/special_consts.h
sprintf.$(OBJEXT): {$(VPATH)}internal/static_assert.h
sprintf.$(OBJEXT): {$(VPATH)}internal/stdalign.h
sprintf.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-sprintf.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
sprintf.$(OBJEXT): {$(VPATH)}internal/symbol.h
sprintf.$(OBJEXT): {$(VPATH)}internal/value.h
sprintf.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -17436,7 +14741,6 @@ st.$(OBJEXT): $(top_srcdir)/internal/bits.h
st.$(OBJEXT): $(top_srcdir)/internal/compilers.h
st.$(OBJEXT): $(top_srcdir)/internal/hash.h
st.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-st.$(OBJEXT): $(top_srcdir)/internal/st.h
st.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
st.$(OBJEXT): $(top_srcdir)/internal/warnings.h
st.$(OBJEXT): {$(VPATH)}assert.h
@@ -17491,7 +14795,6 @@ st.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
st.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
st.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
st.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-st.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
st.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
st.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
st.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -17551,6 +14854,7 @@ st.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
st.$(OBJEXT): {$(VPATH)}internal/intern/error.h
st.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
st.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+st.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
st.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
st.$(OBJEXT): {$(VPATH)}internal/intern/io.h
st.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -17581,13 +14885,12 @@ st.$(OBJEXT): {$(VPATH)}internal/memory.h
st.$(OBJEXT): {$(VPATH)}internal/method.h
st.$(OBJEXT): {$(VPATH)}internal/module.h
st.$(OBJEXT): {$(VPATH)}internal/newobj.h
+st.$(OBJEXT): {$(VPATH)}internal/rgengc.h
st.$(OBJEXT): {$(VPATH)}internal/scan_args.h
st.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-st.$(OBJEXT): {$(VPATH)}internal/st.h
st.$(OBJEXT): {$(VPATH)}internal/static_assert.h
st.$(OBJEXT): {$(VPATH)}internal/stdalign.h
st.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-st.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
st.$(OBJEXT): {$(VPATH)}internal/symbol.h
st.$(OBJEXT): {$(VPATH)}internal/value.h
st.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -17595,6 +14898,7 @@ st.$(OBJEXT): {$(VPATH)}internal/variable.h
st.$(OBJEXT): {$(VPATH)}internal/warning_push.h
st.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
st.$(OBJEXT): {$(VPATH)}missing.h
+st.$(OBJEXT): {$(VPATH)}ruby_assert.h
st.$(OBJEXT): {$(VPATH)}st.c
st.$(OBJEXT): {$(VPATH)}st.h
st.$(OBJEXT): {$(VPATH)}subst.h
@@ -17658,7 +14962,6 @@ strftime.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
strftime.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
strftime.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
strftime.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-strftime.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
strftime.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
strftime.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
strftime.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -17727,6 +15030,7 @@ strftime.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
strftime.$(OBJEXT): {$(VPATH)}internal/intern/error.h
strftime.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
strftime.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+strftime.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
strftime.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
strftime.$(OBJEXT): {$(VPATH)}internal/intern/io.h
strftime.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -17757,12 +15061,12 @@ strftime.$(OBJEXT): {$(VPATH)}internal/memory.h
strftime.$(OBJEXT): {$(VPATH)}internal/method.h
strftime.$(OBJEXT): {$(VPATH)}internal/module.h
strftime.$(OBJEXT): {$(VPATH)}internal/newobj.h
+strftime.$(OBJEXT): {$(VPATH)}internal/rgengc.h
strftime.$(OBJEXT): {$(VPATH)}internal/scan_args.h
strftime.$(OBJEXT): {$(VPATH)}internal/special_consts.h
strftime.$(OBJEXT): {$(VPATH)}internal/static_assert.h
strftime.$(OBJEXT): {$(VPATH)}internal/stdalign.h
strftime.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-strftime.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
strftime.$(OBJEXT): {$(VPATH)}internal/symbol.h
strftime.$(OBJEXT): {$(VPATH)}internal/value.h
strftime.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -17777,12 +15081,7 @@ strftime.$(OBJEXT): {$(VPATH)}strftime.c
strftime.$(OBJEXT): {$(VPATH)}subst.h
strftime.$(OBJEXT): {$(VPATH)}timev.h
strftime.$(OBJEXT): {$(VPATH)}util.h
-string.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-string.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-string.$(OBJEXT): $(CCAN_DIR)/list/list.h
-string.$(OBJEXT): $(CCAN_DIR)/str/str.h
string.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-string.$(OBJEXT): $(hdrdir)/ruby/version.h
string.$(OBJEXT): $(top_srcdir)/internal/array.h
string.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
string.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -17794,7 +15093,6 @@ string.$(OBJEXT): $(top_srcdir)/internal/encoding.h
string.$(OBJEXT): $(top_srcdir)/internal/error.h
string.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
string.$(OBJEXT): $(top_srcdir)/internal/gc.h
-string.$(OBJEXT): $(top_srcdir)/internal/imemo.h
string.$(OBJEXT): $(top_srcdir)/internal/numeric.h
string.$(OBJEXT): $(top_srcdir)/internal/object.h
string.$(OBJEXT): $(top_srcdir)/internal/proc.h
@@ -17824,6 +15122,7 @@ string.$(OBJEXT): {$(VPATH)}debug_counter.h
string.$(OBJEXT): {$(VPATH)}defines.h
string.$(OBJEXT): {$(VPATH)}encindex.h
string.$(OBJEXT): {$(VPATH)}encoding.h
+string.$(OBJEXT): {$(VPATH)}gc.h
string.$(OBJEXT): {$(VPATH)}id.h
string.$(OBJEXT): {$(VPATH)}id_table.h
string.$(OBJEXT): {$(VPATH)}intern.h
@@ -17865,8 +15164,8 @@ string.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
string.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
string.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
string.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+string.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
string.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-string.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
string.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
string.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
string.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -17936,6 +15235,7 @@ string.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
string.$(OBJEXT): {$(VPATH)}internal/intern/error.h
string.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
string.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+string.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
string.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
string.$(OBJEXT): {$(VPATH)}internal/intern/io.h
string.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -17966,21 +15266,19 @@ string.$(OBJEXT): {$(VPATH)}internal/memory.h
string.$(OBJEXT): {$(VPATH)}internal/method.h
string.$(OBJEXT): {$(VPATH)}internal/module.h
string.$(OBJEXT): {$(VPATH)}internal/newobj.h
+string.$(OBJEXT): {$(VPATH)}internal/rgengc.h
string.$(OBJEXT): {$(VPATH)}internal/scan_args.h
string.$(OBJEXT): {$(VPATH)}internal/special_consts.h
string.$(OBJEXT): {$(VPATH)}internal/static_assert.h
string.$(OBJEXT): {$(VPATH)}internal/stdalign.h
string.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-string.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
string.$(OBJEXT): {$(VPATH)}internal/symbol.h
string.$(OBJEXT): {$(VPATH)}internal/value.h
string.$(OBJEXT): {$(VPATH)}internal/value_type.h
string.$(OBJEXT): {$(VPATH)}internal/variable.h
string.$(OBJEXT): {$(VPATH)}internal/warning_push.h
string.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-string.$(OBJEXT): {$(VPATH)}method.h
string.$(OBJEXT): {$(VPATH)}missing.h
-string.$(OBJEXT): {$(VPATH)}node.h
string.$(OBJEXT): {$(VPATH)}onigmo.h
string.$(OBJEXT): {$(VPATH)}oniguruma.h
string.$(OBJEXT): {$(VPATH)}probes.dmyh
@@ -17988,18 +15286,13 @@ string.$(OBJEXT): {$(VPATH)}probes.h
string.$(OBJEXT): {$(VPATH)}re.h
string.$(OBJEXT): {$(VPATH)}regex.h
string.$(OBJEXT): {$(VPATH)}ruby_assert.h
-string.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-string.$(OBJEXT): {$(VPATH)}rubyparser.h
string.$(OBJEXT): {$(VPATH)}shape.h
string.$(OBJEXT): {$(VPATH)}st.h
string.$(OBJEXT): {$(VPATH)}string.c
string.$(OBJEXT): {$(VPATH)}subst.h
-string.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
string.$(OBJEXT): {$(VPATH)}thread_native.h
string.$(OBJEXT): {$(VPATH)}util.h
-string.$(OBJEXT): {$(VPATH)}vm_core.h
string.$(OBJEXT): {$(VPATH)}vm_debug.h
-string.$(OBJEXT): {$(VPATH)}vm_opts.h
string.$(OBJEXT): {$(VPATH)}vm_sync.h
strlcat.$(OBJEXT): {$(VPATH)}config.h
strlcat.$(OBJEXT): {$(VPATH)}internal/attr/format.h
@@ -18036,7 +15329,6 @@ struct.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
struct.$(OBJEXT): $(CCAN_DIR)/list/list.h
struct.$(OBJEXT): $(CCAN_DIR)/str/str.h
struct.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-struct.$(OBJEXT): $(hdrdir)/ruby/version.h
struct.$(OBJEXT): $(top_srcdir)/internal/array.h
struct.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
struct.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -18047,7 +15339,6 @@ struct.$(OBJEXT): $(top_srcdir)/internal/hash.h
struct.$(OBJEXT): $(top_srcdir)/internal/imemo.h
struct.$(OBJEXT): $(top_srcdir)/internal/object.h
struct.$(OBJEXT): $(top_srcdir)/internal/proc.h
-struct.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
struct.$(OBJEXT): $(top_srcdir)/internal/serial.h
struct.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
struct.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -18070,7 +15361,6 @@ struct.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
struct.$(OBJEXT): {$(VPATH)}builtin.h
struct.$(OBJEXT): {$(VPATH)}config.h
struct.$(OBJEXT): {$(VPATH)}constant.h
-struct.$(OBJEXT): {$(VPATH)}debug_counter.h
struct.$(OBJEXT): {$(VPATH)}defines.h
struct.$(OBJEXT): {$(VPATH)}encoding.h
struct.$(OBJEXT): {$(VPATH)}id.h
@@ -18115,7 +15405,6 @@ struct.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
struct.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
struct.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
struct.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-struct.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
struct.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
struct.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
struct.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -18184,6 +15473,7 @@ struct.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
struct.$(OBJEXT): {$(VPATH)}internal/intern/error.h
struct.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
struct.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+struct.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
struct.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
struct.$(OBJEXT): {$(VPATH)}internal/intern/io.h
struct.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -18214,12 +15504,12 @@ struct.$(OBJEXT): {$(VPATH)}internal/memory.h
struct.$(OBJEXT): {$(VPATH)}internal/method.h
struct.$(OBJEXT): {$(VPATH)}internal/module.h
struct.$(OBJEXT): {$(VPATH)}internal/newobj.h
+struct.$(OBJEXT): {$(VPATH)}internal/rgengc.h
struct.$(OBJEXT): {$(VPATH)}internal/scan_args.h
struct.$(OBJEXT): {$(VPATH)}internal/special_consts.h
struct.$(OBJEXT): {$(VPATH)}internal/static_assert.h
struct.$(OBJEXT): {$(VPATH)}internal/stdalign.h
struct.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-struct.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
struct.$(OBJEXT): {$(VPATH)}internal/symbol.h
struct.$(OBJEXT): {$(VPATH)}internal/value.h
struct.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -18233,33 +15523,22 @@ struct.$(OBJEXT): {$(VPATH)}onigmo.h
struct.$(OBJEXT): {$(VPATH)}oniguruma.h
struct.$(OBJEXT): {$(VPATH)}ruby_assert.h
struct.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-struct.$(OBJEXT): {$(VPATH)}rubyparser.h
struct.$(OBJEXT): {$(VPATH)}shape.h
struct.$(OBJEXT): {$(VPATH)}st.h
struct.$(OBJEXT): {$(VPATH)}struct.c
struct.$(OBJEXT): {$(VPATH)}subst.h
struct.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
struct.$(OBJEXT): {$(VPATH)}thread_native.h
+struct.$(OBJEXT): {$(VPATH)}transient_heap.h
struct.$(OBJEXT): {$(VPATH)}vm_core.h
-struct.$(OBJEXT): {$(VPATH)}vm_debug.h
struct.$(OBJEXT): {$(VPATH)}vm_opts.h
-struct.$(OBJEXT): {$(VPATH)}vm_sync.h
-symbol.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-symbol.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-symbol.$(OBJEXT): $(CCAN_DIR)/list/list.h
-symbol.$(OBJEXT): $(CCAN_DIR)/str/str.h
symbol.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-symbol.$(OBJEXT): $(hdrdir)/ruby/version.h
-symbol.$(OBJEXT): $(top_srcdir)/internal/array.h
-symbol.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
symbol.$(OBJEXT): $(top_srcdir)/internal/class.h
symbol.$(OBJEXT): $(top_srcdir)/internal/compilers.h
symbol.$(OBJEXT): $(top_srcdir)/internal/error.h
symbol.$(OBJEXT): $(top_srcdir)/internal/gc.h
symbol.$(OBJEXT): $(top_srcdir)/internal/hash.h
-symbol.$(OBJEXT): $(top_srcdir)/internal/imemo.h
symbol.$(OBJEXT): $(top_srcdir)/internal/object.h
-symbol.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
symbol.$(OBJEXT): $(top_srcdir)/internal/serial.h
symbol.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
symbol.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -18268,7 +15547,6 @@ symbol.$(OBJEXT): $(top_srcdir)/internal/variable.h
symbol.$(OBJEXT): $(top_srcdir)/internal/vm.h
symbol.$(OBJEXT): $(top_srcdir)/internal/warnings.h
symbol.$(OBJEXT): {$(VPATH)}assert.h
-symbol.$(OBJEXT): {$(VPATH)}atomic.h
symbol.$(OBJEXT): {$(VPATH)}backward/2/assume.h
symbol.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
symbol.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -18284,6 +15562,7 @@ symbol.$(OBJEXT): {$(VPATH)}constant.h
symbol.$(OBJEXT): {$(VPATH)}debug_counter.h
symbol.$(OBJEXT): {$(VPATH)}defines.h
symbol.$(OBJEXT): {$(VPATH)}encoding.h
+symbol.$(OBJEXT): {$(VPATH)}gc.h
symbol.$(OBJEXT): {$(VPATH)}id.c
symbol.$(OBJEXT): {$(VPATH)}id.h
symbol.$(OBJEXT): {$(VPATH)}id_table.c
@@ -18327,8 +15606,8 @@ symbol.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+symbol.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-symbol.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
symbol.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -18397,6 +15676,7 @@ symbol.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
symbol.$(OBJEXT): {$(VPATH)}internal/intern/error.h
symbol.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
symbol.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+symbol.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
symbol.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
symbol.$(OBJEXT): {$(VPATH)}internal/intern/io.h
symbol.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -18427,28 +15707,24 @@ symbol.$(OBJEXT): {$(VPATH)}internal/memory.h
symbol.$(OBJEXT): {$(VPATH)}internal/method.h
symbol.$(OBJEXT): {$(VPATH)}internal/module.h
symbol.$(OBJEXT): {$(VPATH)}internal/newobj.h
+symbol.$(OBJEXT): {$(VPATH)}internal/rgengc.h
symbol.$(OBJEXT): {$(VPATH)}internal/scan_args.h
symbol.$(OBJEXT): {$(VPATH)}internal/special_consts.h
symbol.$(OBJEXT): {$(VPATH)}internal/static_assert.h
symbol.$(OBJEXT): {$(VPATH)}internal/stdalign.h
symbol.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-symbol.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
symbol.$(OBJEXT): {$(VPATH)}internal/symbol.h
symbol.$(OBJEXT): {$(VPATH)}internal/value.h
symbol.$(OBJEXT): {$(VPATH)}internal/value_type.h
symbol.$(OBJEXT): {$(VPATH)}internal/variable.h
symbol.$(OBJEXT): {$(VPATH)}internal/warning_push.h
symbol.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-symbol.$(OBJEXT): {$(VPATH)}method.h
symbol.$(OBJEXT): {$(VPATH)}missing.h
-symbol.$(OBJEXT): {$(VPATH)}node.h
symbol.$(OBJEXT): {$(VPATH)}onigmo.h
symbol.$(OBJEXT): {$(VPATH)}oniguruma.h
symbol.$(OBJEXT): {$(VPATH)}probes.dmyh
symbol.$(OBJEXT): {$(VPATH)}probes.h
symbol.$(OBJEXT): {$(VPATH)}ruby_assert.h
-symbol.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-symbol.$(OBJEXT): {$(VPATH)}rubyparser.h
symbol.$(OBJEXT): {$(VPATH)}shape.h
symbol.$(OBJEXT): {$(VPATH)}st.h
symbol.$(OBJEXT): {$(VPATH)}subst.h
@@ -18456,11 +15732,7 @@ symbol.$(OBJEXT): {$(VPATH)}symbol.c
symbol.$(OBJEXT): {$(VPATH)}symbol.h
symbol.$(OBJEXT): {$(VPATH)}symbol.rb
symbol.$(OBJEXT): {$(VPATH)}symbol.rbinc
-symbol.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-symbol.$(OBJEXT): {$(VPATH)}thread_native.h
-symbol.$(OBJEXT): {$(VPATH)}vm_core.h
symbol.$(OBJEXT): {$(VPATH)}vm_debug.h
-symbol.$(OBJEXT): {$(VPATH)}vm_opts.h
symbol.$(OBJEXT): {$(VPATH)}vm_sync.h
thread.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
thread.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
@@ -18468,7 +15740,6 @@ thread.$(OBJEXT): $(CCAN_DIR)/list/list.h
thread.$(OBJEXT): $(CCAN_DIR)/str/str.h
thread.$(OBJEXT): $(hdrdir)/ruby.h
thread.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-thread.$(OBJEXT): $(hdrdir)/ruby/version.h
thread.$(OBJEXT): $(top_srcdir)/internal/array.h
thread.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
thread.$(OBJEXT): $(top_srcdir)/internal/bits.h
@@ -18482,7 +15753,6 @@ thread.$(OBJEXT): $(top_srcdir)/internal/imemo.h
thread.$(OBJEXT): $(top_srcdir)/internal/io.h
thread.$(OBJEXT): $(top_srcdir)/internal/object.h
thread.$(OBJEXT): $(top_srcdir)/internal/proc.h
-thread.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
thread.$(OBJEXT): $(top_srcdir)/internal/serial.h
thread.$(OBJEXT): $(top_srcdir)/internal/signal.h
thread.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
@@ -18492,27 +15762,6 @@ thread.$(OBJEXT): $(top_srcdir)/internal/time.h
thread.$(OBJEXT): $(top_srcdir)/internal/variable.h
thread.$(OBJEXT): $(top_srcdir)/internal/vm.h
thread.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-thread.$(OBJEXT): $(top_srcdir)/prism/defines.h
-thread.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-thread.$(OBJEXT): $(top_srcdir)/prism/node.h
-thread.$(OBJEXT): $(top_srcdir)/prism/options.h
-thread.$(OBJEXT): $(top_srcdir)/prism/pack.h
-thread.$(OBJEXT): $(top_srcdir)/prism/parser.h
-thread.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-thread.$(OBJEXT): $(top_srcdir)/prism/prism.h
-thread.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-thread.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-thread.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
-thread.$(OBJEXT): {$(VPATH)}$(COROUTINE_H)
thread.$(OBJEXT): {$(VPATH)}assert.h
thread.$(OBJEXT): {$(VPATH)}atomic.h
thread.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -18533,6 +15782,7 @@ thread.$(OBJEXT): {$(VPATH)}defines.h
thread.$(OBJEXT): {$(VPATH)}encoding.h
thread.$(OBJEXT): {$(VPATH)}eval_intern.h
thread.$(OBJEXT): {$(VPATH)}fiber/scheduler.h
+thread.$(OBJEXT): {$(VPATH)}gc.h
thread.$(OBJEXT): {$(VPATH)}hrtime.h
thread.$(OBJEXT): {$(VPATH)}id.h
thread.$(OBJEXT): {$(VPATH)}id_table.h
@@ -18576,7 +15826,6 @@ thread.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
thread.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
thread.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
thread.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-thread.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
thread.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
thread.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
thread.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -18645,6 +15894,7 @@ thread.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
thread.$(OBJEXT): {$(VPATH)}internal/intern/error.h
thread.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
thread.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+thread.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
thread.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
thread.$(OBJEXT): {$(VPATH)}internal/intern/io.h
thread.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -18675,12 +15925,12 @@ thread.$(OBJEXT): {$(VPATH)}internal/memory.h
thread.$(OBJEXT): {$(VPATH)}internal/method.h
thread.$(OBJEXT): {$(VPATH)}internal/module.h
thread.$(OBJEXT): {$(VPATH)}internal/newobj.h
+thread.$(OBJEXT): {$(VPATH)}internal/rgengc.h
thread.$(OBJEXT): {$(VPATH)}internal/scan_args.h
thread.$(OBJEXT): {$(VPATH)}internal/special_consts.h
thread.$(OBJEXT): {$(VPATH)}internal/static_assert.h
thread.$(OBJEXT): {$(VPATH)}internal/stdalign.h
thread.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-thread.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
thread.$(OBJEXT): {$(VPATH)}internal/symbol.h
thread.$(OBJEXT): {$(VPATH)}internal/value.h
thread.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -18691,19 +15941,14 @@ thread.$(OBJEXT): {$(VPATH)}io.h
thread.$(OBJEXT): {$(VPATH)}iseq.h
thread.$(OBJEXT): {$(VPATH)}method.h
thread.$(OBJEXT): {$(VPATH)}missing.h
+thread.$(OBJEXT): {$(VPATH)}mjit.h
thread.$(OBJEXT): {$(VPATH)}node.h
thread.$(OBJEXT): {$(VPATH)}onigmo.h
thread.$(OBJEXT): {$(VPATH)}oniguruma.h
-thread.$(OBJEXT): {$(VPATH)}prism/ast.h
-thread.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-thread.$(OBJEXT): {$(VPATH)}prism/version.h
-thread.$(OBJEXT): {$(VPATH)}prism_compile.h
thread.$(OBJEXT): {$(VPATH)}ractor.h
thread.$(OBJEXT): {$(VPATH)}ractor_core.h
-thread.$(OBJEXT): {$(VPATH)}rjit.h
thread.$(OBJEXT): {$(VPATH)}ruby_assert.h
thread.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-thread.$(OBJEXT): {$(VPATH)}rubyparser.h
thread.$(OBJEXT): {$(VPATH)}shape.h
thread.$(OBJEXT): {$(VPATH)}st.h
thread.$(OBJEXT): {$(VPATH)}subst.h
@@ -18712,7 +15957,6 @@ thread.$(OBJEXT): {$(VPATH)}thread.h
thread.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).c
thread.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
thread.$(OBJEXT): {$(VPATH)}thread_native.h
-thread.$(OBJEXT): {$(VPATH)}thread_pthread_mn.c
thread.$(OBJEXT): {$(VPATH)}thread_sync.c
thread.$(OBJEXT): {$(VPATH)}thread_sync.rbinc
thread.$(OBJEXT): {$(VPATH)}timev.h
@@ -18720,10 +15964,6 @@ thread.$(OBJEXT): {$(VPATH)}vm_core.h
thread.$(OBJEXT): {$(VPATH)}vm_debug.h
thread.$(OBJEXT): {$(VPATH)}vm_opts.h
thread.$(OBJEXT): {$(VPATH)}vm_sync.h
-time.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-time.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-time.$(OBJEXT): $(CCAN_DIR)/list/list.h
-time.$(OBJEXT): $(CCAN_DIR)/str/str.h
time.$(OBJEXT): $(hdrdir)/ruby/ruby.h
time.$(OBJEXT): $(top_srcdir)/internal/array.h
time.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
@@ -18734,10 +15974,8 @@ time.$(OBJEXT): $(top_srcdir)/internal/compilers.h
time.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
time.$(OBJEXT): $(top_srcdir)/internal/gc.h
time.$(OBJEXT): $(top_srcdir)/internal/hash.h
-time.$(OBJEXT): $(top_srcdir)/internal/imemo.h
time.$(OBJEXT): $(top_srcdir)/internal/numeric.h
time.$(OBJEXT): $(top_srcdir)/internal/rational.h
-time.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
time.$(OBJEXT): $(top_srcdir)/internal/serial.h
time.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
time.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -18746,7 +15984,6 @@ time.$(OBJEXT): $(top_srcdir)/internal/variable.h
time.$(OBJEXT): $(top_srcdir)/internal/vm.h
time.$(OBJEXT): $(top_srcdir)/internal/warnings.h
time.$(OBJEXT): {$(VPATH)}assert.h
-time.$(OBJEXT): {$(VPATH)}atomic.h
time.$(OBJEXT): {$(VPATH)}backward/2/assume.h
time.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
time.$(OBJEXT): {$(VPATH)}backward/2/bool.h
@@ -18803,7 +16040,6 @@ time.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
time.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
time.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
time.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-time.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
time.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
time.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
time.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -18872,6 +16108,7 @@ time.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
time.$(OBJEXT): {$(VPATH)}internal/intern/error.h
time.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
time.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+time.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
time.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
time.$(OBJEXT): {$(VPATH)}internal/intern/io.h
time.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -18902,37 +16139,28 @@ time.$(OBJEXT): {$(VPATH)}internal/memory.h
time.$(OBJEXT): {$(VPATH)}internal/method.h
time.$(OBJEXT): {$(VPATH)}internal/module.h
time.$(OBJEXT): {$(VPATH)}internal/newobj.h
+time.$(OBJEXT): {$(VPATH)}internal/rgengc.h
time.$(OBJEXT): {$(VPATH)}internal/scan_args.h
time.$(OBJEXT): {$(VPATH)}internal/special_consts.h
time.$(OBJEXT): {$(VPATH)}internal/static_assert.h
time.$(OBJEXT): {$(VPATH)}internal/stdalign.h
time.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-time.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
time.$(OBJEXT): {$(VPATH)}internal/symbol.h
time.$(OBJEXT): {$(VPATH)}internal/value.h
time.$(OBJEXT): {$(VPATH)}internal/value_type.h
time.$(OBJEXT): {$(VPATH)}internal/variable.h
time.$(OBJEXT): {$(VPATH)}internal/warning_push.h
time.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-time.$(OBJEXT): {$(VPATH)}method.h
time.$(OBJEXT): {$(VPATH)}missing.h
-time.$(OBJEXT): {$(VPATH)}node.h
time.$(OBJEXT): {$(VPATH)}onigmo.h
time.$(OBJEXT): {$(VPATH)}oniguruma.h
time.$(OBJEXT): {$(VPATH)}ruby_assert.h
-time.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-time.$(OBJEXT): {$(VPATH)}rubyparser.h
time.$(OBJEXT): {$(VPATH)}shape.h
time.$(OBJEXT): {$(VPATH)}st.h
time.$(OBJEXT): {$(VPATH)}subst.h
-time.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-time.$(OBJEXT): {$(VPATH)}thread_native.h
time.$(OBJEXT): {$(VPATH)}time.c
time.$(OBJEXT): {$(VPATH)}timev.h
time.$(OBJEXT): {$(VPATH)}timev.rbinc
-time.$(OBJEXT): {$(VPATH)}util.h
-time.$(OBJEXT): {$(VPATH)}vm_core.h
-time.$(OBJEXT): {$(VPATH)}vm_opts.h
transcode.$(OBJEXT): $(hdrdir)/ruby/ruby.h
transcode.$(OBJEXT): $(top_srcdir)/internal/array.h
transcode.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -19002,7 +16230,6 @@ transcode.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
transcode.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
transcode.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
transcode.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-transcode.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
transcode.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
transcode.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
transcode.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -19071,6 +16298,7 @@ transcode.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
transcode.$(OBJEXT): {$(VPATH)}internal/intern/error.h
transcode.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
transcode.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+transcode.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
transcode.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
transcode.$(OBJEXT): {$(VPATH)}internal/intern/io.h
transcode.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -19101,12 +16329,12 @@ transcode.$(OBJEXT): {$(VPATH)}internal/memory.h
transcode.$(OBJEXT): {$(VPATH)}internal/method.h
transcode.$(OBJEXT): {$(VPATH)}internal/module.h
transcode.$(OBJEXT): {$(VPATH)}internal/newobj.h
+transcode.$(OBJEXT): {$(VPATH)}internal/rgengc.h
transcode.$(OBJEXT): {$(VPATH)}internal/scan_args.h
transcode.$(OBJEXT): {$(VPATH)}internal/special_consts.h
transcode.$(OBJEXT): {$(VPATH)}internal/static_assert.h
transcode.$(OBJEXT): {$(VPATH)}internal/stdalign.h
transcode.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-transcode.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
transcode.$(OBJEXT): {$(VPATH)}internal/symbol.h
transcode.$(OBJEXT): {$(VPATH)}internal/value.h
transcode.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -19121,12 +16349,187 @@ transcode.$(OBJEXT): {$(VPATH)}st.h
transcode.$(OBJEXT): {$(VPATH)}subst.h
transcode.$(OBJEXT): {$(VPATH)}transcode.c
transcode.$(OBJEXT): {$(VPATH)}transcode_data.h
+transient_heap.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/array.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/gc.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/hash.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/struct.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/variable.h
+transient_heap.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+transient_heap.$(OBJEXT): {$(VPATH)}assert.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+transient_heap.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+transient_heap.$(OBJEXT): {$(VPATH)}config.h
+transient_heap.$(OBJEXT): {$(VPATH)}constant.h
+transient_heap.$(OBJEXT): {$(VPATH)}debug.h
+transient_heap.$(OBJEXT): {$(VPATH)}debug_counter.h
+transient_heap.$(OBJEXT): {$(VPATH)}defines.h
+transient_heap.$(OBJEXT): {$(VPATH)}gc.h
+transient_heap.$(OBJEXT): {$(VPATH)}id_table.h
+transient_heap.$(OBJEXT): {$(VPATH)}intern.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/abi.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/assume.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/cast.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/config.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/ctype.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/dosish.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/error.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/eval.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/event.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/gc.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/glob.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/globals.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/iterator.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/memory.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/method.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/module.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/newobj.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/rgengc.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/symbol.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/value.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/value_type.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/variable.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+transient_heap.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+transient_heap.$(OBJEXT): {$(VPATH)}missing.h
+transient_heap.$(OBJEXT): {$(VPATH)}ruby_assert.h
+transient_heap.$(OBJEXT): {$(VPATH)}shape.h
+transient_heap.$(OBJEXT): {$(VPATH)}st.h
+transient_heap.$(OBJEXT): {$(VPATH)}subst.h
+transient_heap.$(OBJEXT): {$(VPATH)}transient_heap.c
+transient_heap.$(OBJEXT): {$(VPATH)}transient_heap.h
+transient_heap.$(OBJEXT): {$(VPATH)}vm_debug.h
+transient_heap.$(OBJEXT): {$(VPATH)}vm_sync.h
util.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-util.$(OBJEXT): $(top_srcdir)/internal/array.h
util.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-util.$(OBJEXT): $(top_srcdir)/internal/imemo.h
util.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-util.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
util.$(OBJEXT): $(top_srcdir)/internal/util.h
util.$(OBJEXT): $(top_srcdir)/internal/warnings.h
util.$(OBJEXT): {$(VPATH)}assert.h
@@ -19183,7 +16586,6 @@ util.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
util.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
util.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
util.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-util.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
util.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
util.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
util.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -19243,6 +16645,7 @@ util.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
util.$(OBJEXT): {$(VPATH)}internal/intern/error.h
util.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
util.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+util.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
util.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
util.$(OBJEXT): {$(VPATH)}internal/intern/io.h
util.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -19273,12 +16676,12 @@ util.$(OBJEXT): {$(VPATH)}internal/memory.h
util.$(OBJEXT): {$(VPATH)}internal/method.h
util.$(OBJEXT): {$(VPATH)}internal/module.h
util.$(OBJEXT): {$(VPATH)}internal/newobj.h
+util.$(OBJEXT): {$(VPATH)}internal/rgengc.h
util.$(OBJEXT): {$(VPATH)}internal/scan_args.h
util.$(OBJEXT): {$(VPATH)}internal/special_consts.h
util.$(OBJEXT): {$(VPATH)}internal/static_assert.h
util.$(OBJEXT): {$(VPATH)}internal/stdalign.h
util.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-util.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
util.$(OBJEXT): {$(VPATH)}internal/symbol.h
util.$(OBJEXT): {$(VPATH)}internal/value.h
util.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -19296,7 +16699,6 @@ variable.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
variable.$(OBJEXT): $(CCAN_DIR)/list/list.h
variable.$(OBJEXT): $(CCAN_DIR)/str/str.h
variable.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-variable.$(OBJEXT): $(hdrdir)/ruby/version.h
variable.$(OBJEXT): $(top_srcdir)/internal/array.h
variable.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
variable.$(OBJEXT): $(top_srcdir)/internal/class.h
@@ -19308,7 +16710,6 @@ variable.$(OBJEXT): $(top_srcdir)/internal/hash.h
variable.$(OBJEXT): $(top_srcdir)/internal/imemo.h
variable.$(OBJEXT): $(top_srcdir)/internal/object.h
variable.$(OBJEXT): $(top_srcdir)/internal/re.h
-variable.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
variable.$(OBJEXT): $(top_srcdir)/internal/serial.h
variable.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
variable.$(OBJEXT): $(top_srcdir)/internal/string.h
@@ -19375,7 +16776,6 @@ variable.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
variable.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
variable.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
variable.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-variable.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
variable.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
variable.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
variable.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -19444,6 +16844,7 @@ variable.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
variable.$(OBJEXT): {$(VPATH)}internal/intern/error.h
variable.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
variable.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+variable.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
variable.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
variable.$(OBJEXT): {$(VPATH)}internal/intern/io.h
variable.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -19474,12 +16875,12 @@ variable.$(OBJEXT): {$(VPATH)}internal/memory.h
variable.$(OBJEXT): {$(VPATH)}internal/method.h
variable.$(OBJEXT): {$(VPATH)}internal/module.h
variable.$(OBJEXT): {$(VPATH)}internal/newobj.h
+variable.$(OBJEXT): {$(VPATH)}internal/rgengc.h
variable.$(OBJEXT): {$(VPATH)}internal/scan_args.h
variable.$(OBJEXT): {$(VPATH)}internal/special_consts.h
variable.$(OBJEXT): {$(VPATH)}internal/static_assert.h
variable.$(OBJEXT): {$(VPATH)}internal/stdalign.h
variable.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-variable.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
variable.$(OBJEXT): {$(VPATH)}internal/symbol.h
variable.$(OBJEXT): {$(VPATH)}internal/value.h
variable.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -19495,13 +16896,12 @@ variable.$(OBJEXT): {$(VPATH)}ractor.h
variable.$(OBJEXT): {$(VPATH)}ractor_core.h
variable.$(OBJEXT): {$(VPATH)}ruby_assert.h
variable.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-variable.$(OBJEXT): {$(VPATH)}rubyparser.h
variable.$(OBJEXT): {$(VPATH)}shape.h
variable.$(OBJEXT): {$(VPATH)}st.h
variable.$(OBJEXT): {$(VPATH)}subst.h
-variable.$(OBJEXT): {$(VPATH)}symbol.h
variable.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
variable.$(OBJEXT): {$(VPATH)}thread_native.h
+variable.$(OBJEXT): {$(VPATH)}transient_heap.h
variable.$(OBJEXT): {$(VPATH)}util.h
variable.$(OBJEXT): {$(VPATH)}variable.c
variable.$(OBJEXT): {$(VPATH)}variable.h
@@ -19522,8 +16922,6 @@ version.$(OBJEXT): $(top_srcdir)/internal/cmdlineopt.h
version.$(OBJEXT): $(top_srcdir)/internal/compilers.h
version.$(OBJEXT): $(top_srcdir)/internal/gc.h
version.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-version.$(OBJEXT): $(top_srcdir)/internal/parse.h
-version.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
version.$(OBJEXT): $(top_srcdir)/internal/serial.h
version.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
version.$(OBJEXT): $(top_srcdir)/internal/variable.h
@@ -19545,7 +16943,6 @@ version.$(OBJEXT): {$(VPATH)}config.h
version.$(OBJEXT): {$(VPATH)}constant.h
version.$(OBJEXT): {$(VPATH)}debug_counter.h
version.$(OBJEXT): {$(VPATH)}defines.h
-version.$(OBJEXT): {$(VPATH)}encoding.h
version.$(OBJEXT): {$(VPATH)}id.h
version.$(OBJEXT): {$(VPATH)}id_table.h
version.$(OBJEXT): {$(VPATH)}intern.h
@@ -19588,7 +16985,6 @@ version.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
version.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
version.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
version.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-version.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
version.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
version.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
version.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -19621,15 +17017,6 @@ version.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
version.$(OBJEXT): {$(VPATH)}internal/ctype.h
version.$(OBJEXT): {$(VPATH)}internal/dllexport.h
version.$(OBJEXT): {$(VPATH)}internal/dosish.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-version.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
version.$(OBJEXT): {$(VPATH)}internal/error.h
version.$(OBJEXT): {$(VPATH)}internal/eval.h
version.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -19657,6 +17044,7 @@ version.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
version.$(OBJEXT): {$(VPATH)}internal/intern/error.h
version.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
version.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+version.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
version.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
version.$(OBJEXT): {$(VPATH)}internal/intern/io.h
version.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -19687,12 +17075,12 @@ version.$(OBJEXT): {$(VPATH)}internal/memory.h
version.$(OBJEXT): {$(VPATH)}internal/method.h
version.$(OBJEXT): {$(VPATH)}internal/module.h
version.$(OBJEXT): {$(VPATH)}internal/newobj.h
+version.$(OBJEXT): {$(VPATH)}internal/rgengc.h
version.$(OBJEXT): {$(VPATH)}internal/scan_args.h
version.$(OBJEXT): {$(VPATH)}internal/special_consts.h
version.$(OBJEXT): {$(VPATH)}internal/static_assert.h
version.$(OBJEXT): {$(VPATH)}internal/stdalign.h
version.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-version.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
version.$(OBJEXT): {$(VPATH)}internal/symbol.h
version.$(OBJEXT): {$(VPATH)}internal/value.h
version.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -19701,14 +17089,11 @@ version.$(OBJEXT): {$(VPATH)}internal/warning_push.h
version.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
version.$(OBJEXT): {$(VPATH)}method.h
version.$(OBJEXT): {$(VPATH)}missing.h
+version.$(OBJEXT): {$(VPATH)}mjit.h
version.$(OBJEXT): {$(VPATH)}node.h
-version.$(OBJEXT): {$(VPATH)}onigmo.h
-version.$(OBJEXT): {$(VPATH)}oniguruma.h
version.$(OBJEXT): {$(VPATH)}revision.h
-version.$(OBJEXT): {$(VPATH)}rjit.h
version.$(OBJEXT): {$(VPATH)}ruby_assert.h
version.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-version.$(OBJEXT): {$(VPATH)}rubyparser.h
version.$(OBJEXT): {$(VPATH)}shape.h
version.$(OBJEXT): {$(VPATH)}st.h
version.$(OBJEXT): {$(VPATH)}subst.h
@@ -19724,7 +17109,6 @@ vm.$(OBJEXT): $(CCAN_DIR)/list/list.h
vm.$(OBJEXT): $(CCAN_DIR)/str/str.h
vm.$(OBJEXT): $(hdrdir)/ruby.h
vm.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-vm.$(OBJEXT): $(hdrdir)/ruby/version.h
vm.$(OBJEXT): $(top_srcdir)/internal/array.h
vm.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
vm.$(OBJEXT): $(top_srcdir)/internal/bignum.h
@@ -19733,9 +17117,7 @@ vm.$(OBJEXT): $(top_srcdir)/internal/class.h
vm.$(OBJEXT): $(top_srcdir)/internal/compar.h
vm.$(OBJEXT): $(top_srcdir)/internal/compile.h
vm.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-vm.$(OBJEXT): $(top_srcdir)/internal/complex.h
vm.$(OBJEXT): $(top_srcdir)/internal/cont.h
-vm.$(OBJEXT): $(top_srcdir)/internal/encoding.h
vm.$(OBJEXT): $(top_srcdir)/internal/error.h
vm.$(OBJEXT): $(top_srcdir)/internal/eval.h
vm.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
@@ -19743,15 +17125,12 @@ vm.$(OBJEXT): $(top_srcdir)/internal/gc.h
vm.$(OBJEXT): $(top_srcdir)/internal/hash.h
vm.$(OBJEXT): $(top_srcdir)/internal/imemo.h
vm.$(OBJEXT): $(top_srcdir)/internal/inits.h
-vm.$(OBJEXT): $(top_srcdir)/internal/missing.h
vm.$(OBJEXT): $(top_srcdir)/internal/numeric.h
vm.$(OBJEXT): $(top_srcdir)/internal/object.h
vm.$(OBJEXT): $(top_srcdir)/internal/parse.h
vm.$(OBJEXT): $(top_srcdir)/internal/proc.h
vm.$(OBJEXT): $(top_srcdir)/internal/random.h
-vm.$(OBJEXT): $(top_srcdir)/internal/rational.h
vm.$(OBJEXT): $(top_srcdir)/internal/re.h
-vm.$(OBJEXT): $(top_srcdir)/internal/ruby_parser.h
vm.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
@@ -19759,30 +17138,9 @@ vm.$(OBJEXT): $(top_srcdir)/internal/string.h
vm.$(OBJEXT): $(top_srcdir)/internal/struct.h
vm.$(OBJEXT): $(top_srcdir)/internal/symbol.h
vm.$(OBJEXT): $(top_srcdir)/internal/thread.h
-vm.$(OBJEXT): $(top_srcdir)/internal/transcode.h
vm.$(OBJEXT): $(top_srcdir)/internal/variable.h
vm.$(OBJEXT): $(top_srcdir)/internal/vm.h
vm.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-vm.$(OBJEXT): $(top_srcdir)/prism/defines.h
-vm.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-vm.$(OBJEXT): $(top_srcdir)/prism/node.h
-vm.$(OBJEXT): $(top_srcdir)/prism/options.h
-vm.$(OBJEXT): $(top_srcdir)/prism/pack.h
-vm.$(OBJEXT): $(top_srcdir)/prism/parser.h
-vm.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-vm.$(OBJEXT): $(top_srcdir)/prism/prism.h
-vm.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-vm.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-vm.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
vm.$(OBJEXT): {$(VPATH)}assert.h
vm.$(OBJEXT): {$(VPATH)}atomic.h
vm.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -19802,6 +17160,7 @@ vm.$(OBJEXT): {$(VPATH)}defines.h
vm.$(OBJEXT): {$(VPATH)}defs/opt_operand.def
vm.$(OBJEXT): {$(VPATH)}encoding.h
vm.$(OBJEXT): {$(VPATH)}eval_intern.h
+vm.$(OBJEXT): {$(VPATH)}gc.h
vm.$(OBJEXT): {$(VPATH)}id.h
vm.$(OBJEXT): {$(VPATH)}id_table.h
vm.$(OBJEXT): {$(VPATH)}insns.def
@@ -19847,7 +17206,6 @@ vm.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
vm.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
vm.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
vm.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-vm.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
vm.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
vm.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
vm.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -19916,6 +17274,7 @@ vm.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
vm.$(OBJEXT): {$(VPATH)}internal/intern/error.h
vm.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
vm.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+vm.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
vm.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
vm.$(OBJEXT): {$(VPATH)}internal/intern/io.h
vm.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -19946,12 +17305,12 @@ vm.$(OBJEXT): {$(VPATH)}internal/memory.h
vm.$(OBJEXT): {$(VPATH)}internal/method.h
vm.$(OBJEXT): {$(VPATH)}internal/module.h
vm.$(OBJEXT): {$(VPATH)}internal/newobj.h
+vm.$(OBJEXT): {$(VPATH)}internal/rgengc.h
vm.$(OBJEXT): {$(VPATH)}internal/scan_args.h
vm.$(OBJEXT): {$(VPATH)}internal/special_consts.h
vm.$(OBJEXT): {$(VPATH)}internal/static_assert.h
vm.$(OBJEXT): {$(VPATH)}internal/stdalign.h
vm.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-vm.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
vm.$(OBJEXT): {$(VPATH)}internal/symbol.h
vm.$(OBJEXT): {$(VPATH)}internal/value.h
vm.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -19961,22 +17320,17 @@ vm.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
vm.$(OBJEXT): {$(VPATH)}iseq.h
vm.$(OBJEXT): {$(VPATH)}method.h
vm.$(OBJEXT): {$(VPATH)}missing.h
+vm.$(OBJEXT): {$(VPATH)}mjit.h
vm.$(OBJEXT): {$(VPATH)}node.h
vm.$(OBJEXT): {$(VPATH)}onigmo.h
vm.$(OBJEXT): {$(VPATH)}oniguruma.h
-vm.$(OBJEXT): {$(VPATH)}prism/ast.h
-vm.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-vm.$(OBJEXT): {$(VPATH)}prism/version.h
-vm.$(OBJEXT): {$(VPATH)}prism_compile.h
vm.$(OBJEXT): {$(VPATH)}probes.dmyh
vm.$(OBJEXT): {$(VPATH)}probes.h
vm.$(OBJEXT): {$(VPATH)}probes_helper.h
vm.$(OBJEXT): {$(VPATH)}ractor.h
vm.$(OBJEXT): {$(VPATH)}ractor_core.h
-vm.$(OBJEXT): {$(VPATH)}rjit.h
vm.$(OBJEXT): {$(VPATH)}ruby_assert.h
vm.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-vm.$(OBJEXT): {$(VPATH)}rubyparser.h
vm.$(OBJEXT): {$(VPATH)}shape.h
vm.$(OBJEXT): {$(VPATH)}st.h
vm.$(OBJEXT): {$(VPATH)}subst.h
@@ -20006,41 +17360,18 @@ vm_backtrace.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
vm_backtrace.$(OBJEXT): $(CCAN_DIR)/list/list.h
vm_backtrace.$(OBJEXT): $(CCAN_DIR)/str/str.h
vm_backtrace.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-vm_backtrace.$(OBJEXT): $(hdrdir)/ruby/version.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/array.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/class.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/compilers.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/error.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/gc.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/string.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/variable.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/vm.h
vm_backtrace.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/defines.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/node.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/options.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/pack.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/parser.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/prism.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-vm_backtrace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
vm_backtrace.$(OBJEXT): {$(VPATH)}assert.h
vm_backtrace.$(OBJEXT): {$(VPATH)}atomic.h
vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -20055,7 +17386,6 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
vm_backtrace.$(OBJEXT): {$(VPATH)}config.h
vm_backtrace.$(OBJEXT): {$(VPATH)}constant.h
vm_backtrace.$(OBJEXT): {$(VPATH)}debug.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}debug_counter.h
vm_backtrace.$(OBJEXT): {$(VPATH)}defines.h
vm_backtrace.$(OBJEXT): {$(VPATH)}encoding.h
vm_backtrace.$(OBJEXT): {$(VPATH)}eval_intern.h
@@ -20101,7 +17431,6 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -20170,6 +17499,7 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/error.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/io.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -20200,12 +17530,12 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}internal/memory.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/method.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/module.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/newobj.h
+vm_backtrace.$(OBJEXT): {$(VPATH)}internal/rgengc.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/scan_args.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/special_consts.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/static_assert.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/stdalign.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/symbol.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/value.h
vm_backtrace.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -20218,13 +17548,8 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}missing.h
vm_backtrace.$(OBJEXT): {$(VPATH)}node.h
vm_backtrace.$(OBJEXT): {$(VPATH)}onigmo.h
vm_backtrace.$(OBJEXT): {$(VPATH)}oniguruma.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}prism/ast.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}prism/version.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}prism_compile.h
vm_backtrace.$(OBJEXT): {$(VPATH)}ruby_assert.h
vm_backtrace.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}rubyparser.h
vm_backtrace.$(OBJEXT): {$(VPATH)}shape.h
vm_backtrace.$(OBJEXT): {$(VPATH)}st.h
vm_backtrace.$(OBJEXT): {$(VPATH)}subst.h
@@ -20232,9 +17557,7 @@ vm_backtrace.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
vm_backtrace.$(OBJEXT): {$(VPATH)}thread_native.h
vm_backtrace.$(OBJEXT): {$(VPATH)}vm_backtrace.c
vm_backtrace.$(OBJEXT): {$(VPATH)}vm_core.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}vm_debug.h
vm_backtrace.$(OBJEXT): {$(VPATH)}vm_opts.h
-vm_backtrace.$(OBJEXT): {$(VPATH)}vm_sync.h
vm_dump.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
vm_dump.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
vm_dump.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -20245,32 +17568,11 @@ vm_dump.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/compilers.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/gc.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-vm_dump.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/variable.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/vm.h
vm_dump.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/defines.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/node.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/options.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/pack.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/parser.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/prism.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-vm_dump.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
vm_dump.$(OBJEXT): {$(VPATH)}addr2line.h
vm_dump.$(OBJEXT): {$(VPATH)}assert.h
vm_dump.$(OBJEXT): {$(VPATH)}atomic.h
@@ -20286,7 +17588,7 @@ vm_dump.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
vm_dump.$(OBJEXT): {$(VPATH)}config.h
vm_dump.$(OBJEXT): {$(VPATH)}constant.h
vm_dump.$(OBJEXT): {$(VPATH)}defines.h
-vm_dump.$(OBJEXT): {$(VPATH)}encoding.h
+vm_dump.$(OBJEXT): {$(VPATH)}gc.h
vm_dump.$(OBJEXT): {$(VPATH)}id.h
vm_dump.$(OBJEXT): {$(VPATH)}id_table.h
vm_dump.$(OBJEXT): {$(VPATH)}intern.h
@@ -20329,7 +17631,6 @@ vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -20362,15 +17663,6 @@ vm_dump.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/ctype.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/dllexport.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/dosish.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/error.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/eval.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -20398,6 +17690,7 @@ vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/error.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/io.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -20428,12 +17721,12 @@ vm_dump.$(OBJEXT): {$(VPATH)}internal/memory.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/method.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/module.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/newobj.h
+vm_dump.$(OBJEXT): {$(VPATH)}internal/rgengc.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/scan_args.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/special_consts.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/static_assert.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/stdalign.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-vm_dump.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/symbol.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/value.h
vm_dump.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -20444,18 +17737,11 @@ vm_dump.$(OBJEXT): {$(VPATH)}iseq.h
vm_dump.$(OBJEXT): {$(VPATH)}method.h
vm_dump.$(OBJEXT): {$(VPATH)}missing.h
vm_dump.$(OBJEXT): {$(VPATH)}node.h
-vm_dump.$(OBJEXT): {$(VPATH)}onigmo.h
-vm_dump.$(OBJEXT): {$(VPATH)}oniguruma.h
-vm_dump.$(OBJEXT): {$(VPATH)}prism/ast.h
-vm_dump.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-vm_dump.$(OBJEXT): {$(VPATH)}prism/version.h
-vm_dump.$(OBJEXT): {$(VPATH)}prism_compile.h
vm_dump.$(OBJEXT): {$(VPATH)}procstat_vm.c
vm_dump.$(OBJEXT): {$(VPATH)}ractor.h
vm_dump.$(OBJEXT): {$(VPATH)}ractor_core.h
vm_dump.$(OBJEXT): {$(VPATH)}ruby_assert.h
vm_dump.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-vm_dump.$(OBJEXT): {$(VPATH)}rubyparser.h
vm_dump.$(OBJEXT): {$(VPATH)}shape.h
vm_dump.$(OBJEXT): {$(VPATH)}st.h
vm_dump.$(OBJEXT): {$(VPATH)}subst.h
@@ -20475,10 +17761,8 @@ vm_sync.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/compilers.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/gc.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-vm_sync.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-vm_sync.$(OBJEXT): $(top_srcdir)/internal/thread.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/variable.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/vm.h
vm_sync.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -20497,7 +17781,7 @@ vm_sync.$(OBJEXT): {$(VPATH)}config.h
vm_sync.$(OBJEXT): {$(VPATH)}constant.h
vm_sync.$(OBJEXT): {$(VPATH)}debug_counter.h
vm_sync.$(OBJEXT): {$(VPATH)}defines.h
-vm_sync.$(OBJEXT): {$(VPATH)}encoding.h
+vm_sync.$(OBJEXT): {$(VPATH)}gc.h
vm_sync.$(OBJEXT): {$(VPATH)}id.h
vm_sync.$(OBJEXT): {$(VPATH)}id_table.h
vm_sync.$(OBJEXT): {$(VPATH)}intern.h
@@ -20540,7 +17824,6 @@ vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -20573,15 +17856,6 @@ vm_sync.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/ctype.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/dllexport.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/dosish.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/error.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/eval.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/event.h
@@ -20609,6 +17883,7 @@ vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/error.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/io.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -20639,12 +17914,12 @@ vm_sync.$(OBJEXT): {$(VPATH)}internal/memory.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/method.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/module.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/newobj.h
+vm_sync.$(OBJEXT): {$(VPATH)}internal/rgengc.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/scan_args.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/special_consts.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/static_assert.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/stdalign.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-vm_sync.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/symbol.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/value.h
vm_sync.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -20654,13 +17929,10 @@ vm_sync.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
vm_sync.$(OBJEXT): {$(VPATH)}method.h
vm_sync.$(OBJEXT): {$(VPATH)}missing.h
vm_sync.$(OBJEXT): {$(VPATH)}node.h
-vm_sync.$(OBJEXT): {$(VPATH)}onigmo.h
-vm_sync.$(OBJEXT): {$(VPATH)}oniguruma.h
vm_sync.$(OBJEXT): {$(VPATH)}ractor.h
vm_sync.$(OBJEXT): {$(VPATH)}ractor_core.h
vm_sync.$(OBJEXT): {$(VPATH)}ruby_assert.h
vm_sync.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-vm_sync.$(OBJEXT): {$(VPATH)}rubyparser.h
vm_sync.$(OBJEXT): {$(VPATH)}shape.h
vm_sync.$(OBJEXT): {$(VPATH)}st.h
vm_sync.$(OBJEXT): {$(VPATH)}subst.h
@@ -20679,40 +17951,16 @@ vm_trace.$(OBJEXT): $(hdrdir)/ruby.h
vm_trace.$(OBJEXT): $(hdrdir)/ruby/ruby.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/array.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-vm_trace.$(OBJEXT): $(top_srcdir)/internal/bits.h
-vm_trace.$(OBJEXT): $(top_srcdir)/internal/class.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/compilers.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/gc.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/hash.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-vm_trace.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-vm_trace.$(OBJEXT): $(top_srcdir)/internal/thread.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/variable.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/vm.h
vm_trace.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/defines.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/node.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/options.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/pack.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/parser.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/prism.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-vm_trace.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
vm_trace.$(OBJEXT): {$(VPATH)}assert.h
vm_trace.$(OBJEXT): {$(VPATH)}atomic.h
vm_trace.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -20774,7 +18022,6 @@ vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -20843,6 +18090,7 @@ vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/error.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/io.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -20873,12 +18121,12 @@ vm_trace.$(OBJEXT): {$(VPATH)}internal/memory.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/method.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/module.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/newobj.h
+vm_trace.$(OBJEXT): {$(VPATH)}internal/rgengc.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/scan_args.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/special_consts.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/static_assert.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/stdalign.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-vm_trace.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/symbol.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/value.h
vm_trace.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -20888,18 +18136,13 @@ vm_trace.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
vm_trace.$(OBJEXT): {$(VPATH)}iseq.h
vm_trace.$(OBJEXT): {$(VPATH)}method.h
vm_trace.$(OBJEXT): {$(VPATH)}missing.h
+vm_trace.$(OBJEXT): {$(VPATH)}mjit.h
vm_trace.$(OBJEXT): {$(VPATH)}node.h
vm_trace.$(OBJEXT): {$(VPATH)}onigmo.h
vm_trace.$(OBJEXT): {$(VPATH)}oniguruma.h
-vm_trace.$(OBJEXT): {$(VPATH)}prism/ast.h
-vm_trace.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-vm_trace.$(OBJEXT): {$(VPATH)}prism/version.h
-vm_trace.$(OBJEXT): {$(VPATH)}prism_compile.h
vm_trace.$(OBJEXT): {$(VPATH)}ractor.h
-vm_trace.$(OBJEXT): {$(VPATH)}rjit.h
vm_trace.$(OBJEXT): {$(VPATH)}ruby_assert.h
vm_trace.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-vm_trace.$(OBJEXT): {$(VPATH)}rubyparser.h
vm_trace.$(OBJEXT): {$(VPATH)}shape.h
vm_trace.$(OBJEXT): {$(VPATH)}st.h
vm_trace.$(OBJEXT): {$(VPATH)}subst.h
@@ -20907,209 +18150,9 @@ vm_trace.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
vm_trace.$(OBJEXT): {$(VPATH)}thread_native.h
vm_trace.$(OBJEXT): {$(VPATH)}trace_point.rbinc
vm_trace.$(OBJEXT): {$(VPATH)}vm_core.h
-vm_trace.$(OBJEXT): {$(VPATH)}vm_debug.h
vm_trace.$(OBJEXT): {$(VPATH)}vm_opts.h
-vm_trace.$(OBJEXT): {$(VPATH)}vm_sync.h
vm_trace.$(OBJEXT): {$(VPATH)}vm_trace.c
vm_trace.$(OBJEXT): {$(VPATH)}yjit.h
-weakmap.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-weakmap.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-weakmap.$(OBJEXT): $(CCAN_DIR)/list/list.h
-weakmap.$(OBJEXT): $(CCAN_DIR)/str/str.h
-weakmap.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/array.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/gc.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/hash.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/proc.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/serial.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/vm.h
-weakmap.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-weakmap.$(OBJEXT): {$(VPATH)}assert.h
-weakmap.$(OBJEXT): {$(VPATH)}atomic.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-weakmap.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-weakmap.$(OBJEXT): {$(VPATH)}config.h
-weakmap.$(OBJEXT): {$(VPATH)}defines.h
-weakmap.$(OBJEXT): {$(VPATH)}encoding.h
-weakmap.$(OBJEXT): {$(VPATH)}id.h
-weakmap.$(OBJEXT): {$(VPATH)}intern.h
-weakmap.$(OBJEXT): {$(VPATH)}internal.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/abi.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/assume.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/cast.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/config.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/ctype.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/dosish.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/error.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/eval.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/event.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/gc.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/glob.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/globals.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/iterator.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/memory.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/method.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/module.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/newobj.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/symbol.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/value.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/value_type.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/variable.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-weakmap.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-weakmap.$(OBJEXT): {$(VPATH)}method.h
-weakmap.$(OBJEXT): {$(VPATH)}missing.h
-weakmap.$(OBJEXT): {$(VPATH)}node.h
-weakmap.$(OBJEXT): {$(VPATH)}onigmo.h
-weakmap.$(OBJEXT): {$(VPATH)}oniguruma.h
-weakmap.$(OBJEXT): {$(VPATH)}ruby_assert.h
-weakmap.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-weakmap.$(OBJEXT): {$(VPATH)}rubyparser.h
-weakmap.$(OBJEXT): {$(VPATH)}st.h
-weakmap.$(OBJEXT): {$(VPATH)}subst.h
-weakmap.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-weakmap.$(OBJEXT): {$(VPATH)}thread_native.h
-weakmap.$(OBJEXT): {$(VPATH)}vm_core.h
-weakmap.$(OBJEXT): {$(VPATH)}vm_opts.h
-weakmap.$(OBJEXT): {$(VPATH)}weakmap.c
yjit.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
yjit.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
yjit.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -21117,8 +18160,6 @@ yjit.$(OBJEXT): $(CCAN_DIR)/str/str.h
yjit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
yjit.$(OBJEXT): $(top_srcdir)/internal/array.h
yjit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
-yjit.$(OBJEXT): $(top_srcdir)/internal/bignum.h
-yjit.$(OBJEXT): $(top_srcdir)/internal/bits.h
yjit.$(OBJEXT): $(top_srcdir)/internal/class.h
yjit.$(OBJEXT): $(top_srcdir)/internal/compile.h
yjit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
@@ -21127,7 +18168,6 @@ yjit.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
yjit.$(OBJEXT): $(top_srcdir)/internal/gc.h
yjit.$(OBJEXT): $(top_srcdir)/internal/hash.h
yjit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-yjit.$(OBJEXT): $(top_srcdir)/internal/numeric.h
yjit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
yjit.$(OBJEXT): $(top_srcdir)/internal/serial.h
yjit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
@@ -21135,26 +18175,6 @@ yjit.$(OBJEXT): $(top_srcdir)/internal/string.h
yjit.$(OBJEXT): $(top_srcdir)/internal/variable.h
yjit.$(OBJEXT): $(top_srcdir)/internal/vm.h
yjit.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/defines.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/encoding.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/node.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/options.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/pack.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/parser.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/prism.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/regexp.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
-yjit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
yjit.$(OBJEXT): {$(VPATH)}assert.h
yjit.$(OBJEXT): {$(VPATH)}atomic.h
yjit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -21173,6 +18193,7 @@ yjit.$(OBJEXT): {$(VPATH)}debug.h
yjit.$(OBJEXT): {$(VPATH)}debug_counter.h
yjit.$(OBJEXT): {$(VPATH)}defines.h
yjit.$(OBJEXT): {$(VPATH)}encoding.h
+yjit.$(OBJEXT): {$(VPATH)}gc.h
yjit.$(OBJEXT): {$(VPATH)}id.h
yjit.$(OBJEXT): {$(VPATH)}id_table.h
yjit.$(OBJEXT): {$(VPATH)}insns.def
@@ -21218,7 +18239,6 @@ yjit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
yjit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
yjit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
yjit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-yjit.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
yjit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
yjit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
yjit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
@@ -21287,6 +18307,7 @@ yjit.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
yjit.$(OBJEXT): {$(VPATH)}internal/intern/error.h
yjit.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
yjit.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+yjit.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
yjit.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
yjit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
yjit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
@@ -21317,13 +18338,12 @@ yjit.$(OBJEXT): {$(VPATH)}internal/memory.h
yjit.$(OBJEXT): {$(VPATH)}internal/method.h
yjit.$(OBJEXT): {$(VPATH)}internal/module.h
yjit.$(OBJEXT): {$(VPATH)}internal/newobj.h
-yjit.$(OBJEXT): {$(VPATH)}internal/numeric.h
+yjit.$(OBJEXT): {$(VPATH)}internal/rgengc.h
yjit.$(OBJEXT): {$(VPATH)}internal/scan_args.h
yjit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
yjit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
yjit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
yjit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-yjit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
yjit.$(OBJEXT): {$(VPATH)}internal/symbol.h
yjit.$(OBJEXT): {$(VPATH)}internal/value.h
yjit.$(OBJEXT): {$(VPATH)}internal/value_type.h
@@ -21336,16 +18356,11 @@ yjit.$(OBJEXT): {$(VPATH)}missing.h
yjit.$(OBJEXT): {$(VPATH)}node.h
yjit.$(OBJEXT): {$(VPATH)}onigmo.h
yjit.$(OBJEXT): {$(VPATH)}oniguruma.h
-yjit.$(OBJEXT): {$(VPATH)}prism/ast.h
-yjit.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
-yjit.$(OBJEXT): {$(VPATH)}prism/version.h
-yjit.$(OBJEXT): {$(VPATH)}prism_compile.h
yjit.$(OBJEXT): {$(VPATH)}probes.dmyh
yjit.$(OBJEXT): {$(VPATH)}probes.h
yjit.$(OBJEXT): {$(VPATH)}probes_helper.h
yjit.$(OBJEXT): {$(VPATH)}ruby_assert.h
yjit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-yjit.$(OBJEXT): {$(VPATH)}rubyparser.h
yjit.$(OBJEXT): {$(VPATH)}shape.h
yjit.$(OBJEXT): {$(VPATH)}st.h
yjit.$(OBJEXT): {$(VPATH)}subst.h
diff --git a/compar.c b/compar.c
index 8d7a208185..040f77975e 100644
--- a/compar.c
+++ b/compar.c
@@ -187,12 +187,6 @@ cmp_between(VALUE x, VALUE min, VALUE max)
* 'd'.clamp('a', 'f') #=> 'd'
* 'z'.clamp('a', 'f') #=> 'f'
*
- * If _min_ is +nil+, it is considered smaller than _obj_,
- * and if _max_ is +nil+, it is considered greater than _obj_.
- *
- * -20.clamp(0, nil) #=> 0
- * 523.clamp(nil, 100) #=> 100
- *
* In <code>(range)</code> form, returns _range.begin_ if _obj_
* <code><=></code> _range.begin_ is less than zero, _range.end_
* if _obj_ <code><=></code> _range.end_ is greater than zero, and
@@ -235,7 +229,7 @@ cmp_clamp(int argc, VALUE *argv, VALUE x)
}
}
if (!NIL_P(min) && !NIL_P(max) && cmpint(min, max) > 0) {
- rb_raise(rb_eArgError, "min argument must be less than or equal to max argument");
+ rb_raise(rb_eArgError, "min argument must be smaller than max argument");
}
if (!NIL_P(min)) {
@@ -263,28 +257,25 @@ cmp_clamp(int argc, VALUE *argv, VALUE x)
* <code>==</code>, <code>>=</code>, and <code>></code>) and the
* method <code>between?</code>.
*
- * class StringSorter
+ * class SizeMatters
* include Comparable
- *
* attr :str
* def <=>(other)
* str.size <=> other.str.size
* end
- *
* def initialize(str)
* @str = str
* end
- *
* def inspect
* @str
* end
* end
*
- * s1 = StringSorter.new("Z")
- * s2 = StringSorter.new("YY")
- * s3 = StringSorter.new("XXX")
- * s4 = StringSorter.new("WWWW")
- * s5 = StringSorter.new("VVVVV")
+ * s1 = SizeMatters.new("Z")
+ * s2 = SizeMatters.new("YY")
+ * s3 = SizeMatters.new("XXX")
+ * s4 = SizeMatters.new("WWWW")
+ * s5 = SizeMatters.new("VVVVV")
*
* s1 < s2 #=> true
* s4.between?(s1, s3) #=> false
@@ -293,13 +284,13 @@ cmp_clamp(int argc, VALUE *argv, VALUE x)
*
* == What's Here
*
- * \Module \Comparable provides these methods, all of which use method <tt>#<=></tt>:
+ * \Module \Comparable provides these methods, all of which use method <tt><=></tt>:
*
* - #<: Returns whether +self+ is less than the given object.
* - #<=: Returns whether +self+ is less than or equal to the given object.
* - #==: Returns whether +self+ is equal to the given object.
- * - #>: Returns whether +self+ is greater than the given object.
- * - #>=: Returns whether +self+ is greater than or equal to the given object.
+ * - #>: Returns whether +self+ is greater than or equal to the given object.
+ * - #>=: Returns whether +self+ is greater than the given object.
* - #between?: Returns +true+ if +self+ is between two given objects.
* - #clamp: For given objects +min+ and +max+, or range <tt>(min..max)</tt>, returns:
*
diff --git a/compile.c b/compile.c
index 5434a0cf05..0452305923 100644
--- a/compile.c
+++ b/compile.c
@@ -17,6 +17,7 @@
#endif
#include "encindex.h"
+#include "gc.h"
#include "id_table.h"
#include "internal.h"
#include "internal/array.h"
@@ -24,30 +25,28 @@
#include "internal/complex.h"
#include "internal/encoding.h"
#include "internal/error.h"
-#include "internal/gc.h"
#include "internal/hash.h"
-#include "internal/io.h"
#include "internal/numeric.h"
#include "internal/object.h"
#include "internal/rational.h"
#include "internal/re.h"
-#include "internal/ruby_parser.h"
#include "internal/symbol.h"
#include "internal/thread.h"
#include "internal/variable.h"
#include "iseq.h"
-#include "ruby/ractor.h"
#include "ruby/re.h"
#include "ruby/util.h"
#include "vm_core.h"
#include "vm_callinfo.h"
#include "vm_debug.h"
-#include "yjit.h"
#include "builtin.h"
#include "insns.inc"
#include "insns_info.inc"
+#undef RUBY_UNTYPED_DATA_WARNING
+#define RUBY_UNTYPED_DATA_WARNING 0
+
#define FIXNUM_INC(n, i) ((n)+(INT2FIX(i)&~FIXNUM_FLAG))
#define FIXNUM_OR(n, i) ((n)|INT2FIX(i))
@@ -119,7 +118,7 @@ struct ensure_range {
};
struct iseq_compile_data_ensure_node_stack {
- const void *ensure_node;
+ const NODE *ensure_node;
struct iseq_compile_data_ensure_node_stack *prev;
struct ensure_range *erange;
};
@@ -220,34 +219,30 @@ const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
/* add an instruction */
#define ADD_INSN(seq, line_node, insn) \
- ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 0))
-
-/* add an instruction with the given line number and node id */
-#define ADD_SYNTHETIC_INSN(seq, line_no, node_id, insn) \
- ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_no), (node_id), BIN(insn), 0))
+ ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
/* insert an instruction before next */
-#define INSERT_BEFORE_INSN(next, line_no, node_id, insn) \
- ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
+#define INSERT_BEFORE_INSN(next, line_node, insn) \
+ ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
/* insert an instruction after prev */
-#define INSERT_AFTER_INSN(prev, line_no, node_id, insn) \
- ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, line_no, node_id, BIN(insn), 0))
+#define INSERT_AFTER_INSN(prev, line_node, insn) \
+ ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) new_insn_body(iseq, (line_node), BIN(insn), 0))
/* add an instruction with some operands (1, 2, 3, 5) */
#define ADD_INSN1(seq, line_node, insn, op1) \
ADD_ELEM((seq), (LINK_ELEMENT *) \
- new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 1, (VALUE)(op1)))
+ new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
/* insert an instruction with some operands (1, 2, 3, 5) before next */
-#define INSERT_BEFORE_INSN1(next, line_no, node_id, insn, op1) \
+#define INSERT_BEFORE_INSN1(next, line_node, insn, op1) \
ELEM_INSERT_PREV(&(next)->link, (LINK_ELEMENT *) \
- new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
+ new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
/* insert an instruction with some operands (1, 2, 3, 5) after prev */
-#define INSERT_AFTER_INSN1(prev, line_no, node_id, insn, op1) \
+#define INSERT_AFTER_INSN1(prev, line_node, insn, op1) \
ELEM_INSERT_NEXT(&(prev)->link, (LINK_ELEMENT *) \
- new_insn_body(iseq, line_no, node_id, BIN(insn), 1, (VALUE)(op1)))
+ new_insn_body(iseq, (line_node), BIN(insn), 1, (VALUE)(op1)))
#define LABEL_REF(label) ((label)->refcnt++)
@@ -256,11 +251,11 @@ const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
#define ADD_INSN2(seq, line_node, insn, op1, op2) \
ADD_ELEM((seq), (LINK_ELEMENT *) \
- new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
+ new_insn_body(iseq, (line_node), BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
#define ADD_INSN3(seq, line_node, insn, op1, op2, op3) \
ADD_ELEM((seq), (LINK_ELEMENT *) \
- new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
+ new_insn_body(iseq, (line_node), BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
/* Specific Insn factory */
#define ADD_SEND(seq, line_node, id, argc) \
@@ -282,7 +277,7 @@ const ID rb_iseq_shared_exc_local_tbl[] = {idERROR_INFO};
ADD_SEND_R((seq), (line_node), (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
#define ADD_SEND_R(seq, line_node, id, argc, block, flag, keywords) \
- ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
+ ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, (line_node), (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
#define ADD_TRACE(seq, event) \
ADD_ELEM((seq), (LINK_ELEMENT *)new_trace_body(iseq, (event), 0))
@@ -337,10 +332,10 @@ static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NOD
(debug_compile("== " desc "\n", \
iseq_compile_each(iseq, (anchor), (node), (popped))))
-#define COMPILE_RECV(anchor, desc, node, recv) \
+#define COMPILE_RECV(anchor, desc, node) \
(private_recv_p(node) ? \
(ADD_INSN(anchor, node, putself), VM_CALL_FCALL) : \
- COMPILE(anchor, desc, recv) ? 0 : -1)
+ COMPILE(anchor, desc, node->nd_recv) ? 0 : -1)
#define OPERAND_AT(insn, idx) \
(((INSN*)(insn))->operands[(idx)])
@@ -475,7 +470,7 @@ static void dump_disasm_list(const LINK_ELEMENT *elem);
static int insn_data_length(INSN *iobj);
static int calc_sp_depth(int depth, INSN *iobj);
-static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...);
+static INSN *new_insn_body(rb_iseq_t *iseq, const NODE *const line_node, enum ruby_vminsn_type insn_id, int argc, ...);
static LABEL *new_label_body(rb_iseq_t *iseq, long line);
static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line);
static TRACE *new_trace_body(rb_iseq_t *iseq, rb_event_flag_t event, long data);
@@ -487,15 +482,16 @@ static int iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
-static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args);
+static int iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl);
static int iseq_set_exception_local_table(rb_iseq_t *iseq);
static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const anchor, const NODE *const node);
+static int iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor);
static int iseq_set_exception_table(rb_iseq_t *iseq);
static int iseq_set_optargs_table(rb_iseq_t *iseq);
-static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore);
+static int compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr);
static int compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int method_call_keywords, int popped);
/*
@@ -609,28 +605,13 @@ branch_coverage_valid_p(rb_iseq_t *iseq, int first_line)
return 1;
}
-#define PTR2NUM(x) (rb_int2inum((intptr_t)(void *)(x)))
-
static VALUE
-setup_branch(const rb_code_location_t *loc, const char *type, VALUE structure, VALUE key)
+decl_branch_base(rb_iseq_t *iseq, const NODE *node, const char *type)
{
- const int first_lineno = loc->beg_pos.lineno, first_column = loc->beg_pos.column;
- const int last_lineno = loc->end_pos.lineno, last_column = loc->end_pos.column;
- VALUE branch = rb_ary_hidden_new(6);
-
- rb_hash_aset(structure, key, branch);
- rb_ary_push(branch, ID2SYM(rb_intern(type)));
- rb_ary_push(branch, INT2FIX(first_lineno));
- rb_ary_push(branch, INT2FIX(first_column));
- rb_ary_push(branch, INT2FIX(last_lineno));
- rb_ary_push(branch, INT2FIX(last_column));
- return branch;
-}
+ const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
+ const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
-static VALUE
-decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, const char *type)
-{
- if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return Qundef;
+ if (!branch_coverage_valid_p(iseq, first_lineno)) return Qundef;
/*
* if !structure[node]
@@ -641,11 +622,18 @@ decl_branch_base(rb_iseq_t *iseq, VALUE key, const rb_code_location_t *loc, cons
*/
VALUE structure = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 0);
+ VALUE key = (VALUE)node | 1; // FIXNUM for hash key
VALUE branch_base = rb_hash_aref(structure, key);
VALUE branches;
if (NIL_P(branch_base)) {
- branch_base = setup_branch(loc, type, structure, key);
+ branch_base = rb_ary_hidden_new(6);
+ rb_hash_aset(structure, key, branch_base);
+ rb_ary_push(branch_base, ID2SYM(rb_intern(type)));
+ rb_ary_push(branch_base, INT2FIX(first_lineno));
+ rb_ary_push(branch_base, INT2FIX(first_column));
+ rb_ary_push(branch_base, INT2FIX(last_lineno));
+ rb_ary_push(branch_base, INT2FIX(last_column));
branches = rb_hash_new();
rb_obj_hide(branches);
rb_ary_push(branch_base, branches);
@@ -667,9 +655,12 @@ generate_dummy_line_node(int lineno, int node_id)
}
static void
-add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code_location_t *loc, int node_id, int branch_id, const char *type, VALUE branches)
+add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *node, int branch_id, const char *type, VALUE branches)
{
- if (!branch_coverage_valid_p(iseq, loc->beg_pos.lineno)) return;
+ const int first_lineno = nd_first_lineno(node), first_column = nd_first_column(node);
+ const int last_lineno = nd_last_lineno(node), last_column = nd_last_column(node);
+
+ if (!branch_coverage_valid_p(iseq, first_lineno)) return;
/*
* if !branches[branch_id]
@@ -684,7 +675,13 @@ add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code
long counter_idx;
if (NIL_P(branch)) {
- branch = setup_branch(loc, type, branches, key);
+ branch = rb_ary_hidden_new(6);
+ rb_hash_aset(branches, key, branch);
+ rb_ary_push(branch, ID2SYM(rb_intern(type)));
+ rb_ary_push(branch, INT2FIX(first_lineno));
+ rb_ary_push(branch, INT2FIX(first_column));
+ rb_ary_push(branch, INT2FIX(last_lineno));
+ rb_ary_push(branch, INT2FIX(last_column));
VALUE counters = RARRAY_AREF(ISEQ_BRANCH_COVERAGE(iseq), 1);
counter_idx = RARRAY_LEN(counters);
rb_ary_push(branch, LONG2FIX(counter_idx));
@@ -695,7 +692,9 @@ add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const rb_code
}
ADD_TRACE_WITH_DATA(seq, RUBY_EVENT_COVERAGE_BRANCH, counter_idx);
- ADD_SYNTHETIC_INSN(seq, loc->end_pos.lineno, node_id, nop);
+
+ NODE dummy_line_node = generate_dummy_line_node(last_lineno, nd_node_id(node));
+ ADD_INSN(seq, &dummy_line_node, nop);
}
#define ISEQ_LAST_LINE(iseq) (ISEQ_COMPILE_DATA(iseq)->last_line)
@@ -722,129 +721,6 @@ validate_labels(rb_iseq_t *iseq, st_table *labels_table)
st_free_table(labels_table);
}
-static NODE *
-get_nd_recv(const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_CALL:
- return RNODE_CALL(node)->nd_recv;
- case NODE_OPCALL:
- return RNODE_OPCALL(node)->nd_recv;
- case NODE_FCALL:
- return 0;
- case NODE_QCALL:
- return RNODE_QCALL(node)->nd_recv;
- case NODE_VCALL:
- return 0;
- case NODE_ATTRASGN:
- return RNODE_ATTRASGN(node)->nd_recv;
- case NODE_OP_ASGN1:
- return RNODE_OP_ASGN1(node)->nd_recv;
- case NODE_OP_ASGN2:
- return RNODE_OP_ASGN2(node)->nd_recv;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- }
-}
-
-static ID
-get_node_call_nd_mid(const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_CALL:
- return RNODE_CALL(node)->nd_mid;
- case NODE_OPCALL:
- return RNODE_OPCALL(node)->nd_mid;
- case NODE_FCALL:
- return RNODE_FCALL(node)->nd_mid;
- case NODE_QCALL:
- return RNODE_QCALL(node)->nd_mid;
- case NODE_VCALL:
- return RNODE_VCALL(node)->nd_mid;
- case NODE_ATTRASGN:
- return RNODE_ATTRASGN(node)->nd_mid;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- }
-}
-
-static NODE *
-get_nd_args(const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_CALL:
- return RNODE_CALL(node)->nd_args;
- case NODE_OPCALL:
- return RNODE_OPCALL(node)->nd_args;
- case NODE_FCALL:
- return RNODE_FCALL(node)->nd_args;
- case NODE_QCALL:
- return RNODE_QCALL(node)->nd_args;
- case NODE_VCALL:
- return 0;
- case NODE_ATTRASGN:
- return RNODE_ATTRASGN(node)->nd_args;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- }
-}
-
-static ID
-get_node_colon_nd_mid(const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_COLON2:
- return RNODE_COLON2(node)->nd_mid;
- case NODE_COLON3:
- return RNODE_COLON3(node)->nd_mid;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- }
-}
-
-static ID
-get_nd_vid(const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_LASGN:
- return RNODE_LASGN(node)->nd_vid;
- case NODE_DASGN:
- return RNODE_DASGN(node)->nd_vid;
- case NODE_IASGN:
- return RNODE_IASGN(node)->nd_vid;
- case NODE_CVASGN:
- return RNODE_CVASGN(node)->nd_vid;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- }
-}
-
-static NODE *
-get_nd_value(const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_LASGN:
- return RNODE_LASGN(node)->nd_value;
- case NODE_DASGN:
- return RNODE_DASGN(node)->nd_value;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- }
-}
-
-static VALUE
-get_string_value(const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_STR:
- return rb_node_str_string_val(node);
- case NODE_FILE:
- return rb_node_file_path_val(node);
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- }
-}
-
VALUE
rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback_callback_func * ifunc)
{
@@ -853,29 +729,32 @@ rb_iseq_compile_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_callback
(*ifunc->func)(iseq, ret, ifunc->data);
- ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
+ NODE dummy_line_node = generate_dummy_line_node(ISEQ_COMPILE_DATA(iseq)->last_line, -1);
+ ADD_INSN(ret, &dummy_line_node, leave);
CHECK(iseq_setup_insn(iseq, ret));
return iseq_setup(iseq, ret);
}
-static bool drop_unreachable_return(LINK_ANCHOR *ret);
-
VALUE
rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
{
DECL_ANCHOR(ret);
INIT_ANCHOR(ret);
+ if (IMEMO_TYPE_P(node, imemo_ifunc)) {
+ rb_raise(rb_eArgError, "unexpected imemo_ifunc");
+ }
+
if (node == 0) {
NO_CHECK(COMPILE(ret, "nil", node));
- iseq_set_local_table(iseq, 0, 0);
+ iseq_set_local_table(iseq, 0);
}
/* assume node is T_NODE */
else if (nd_type_p(node, NODE_SCOPE)) {
/* iseq type of top, method, class, block */
- iseq_set_local_table(iseq, RNODE_SCOPE(node)->nd_tbl, (NODE *)RNODE_SCOPE(node)->nd_args);
- iseq_set_arguments(iseq, ret, (NODE *)RNODE_SCOPE(node)->nd_args);
+ iseq_set_local_table(iseq, node->nd_tbl);
+ iseq_set_arguments(iseq, ret, node->nd_args);
switch (ISEQ_BODY(iseq)->type) {
case ISEQ_TYPE_BLOCK:
@@ -887,9 +766,10 @@ rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
end->rescued = LABEL_RESCUE_END;
ADD_TRACE(ret, RUBY_EVENT_B_CALL);
- ADD_SYNTHETIC_INSN(ret, ISEQ_BODY(iseq)->location.first_lineno, -1, nop);
+ NODE dummy_line_node = generate_dummy_line_node(ISEQ_BODY(iseq)->location.first_lineno, -1);
+ ADD_INSN (ret, &dummy_line_node, nop);
ADD_LABEL(ret, start);
- CHECK(COMPILE(ret, "block body", RNODE_SCOPE(node)->nd_body));
+ CHECK(COMPILE(ret, "block body", node->nd_body));
ADD_LABEL(ret, end);
ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
ISEQ_COMPILE_DATA(iseq)->last_line = ISEQ_BODY(iseq)->location.code_location.end_pos.lineno;
@@ -902,23 +782,23 @@ rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
case ISEQ_TYPE_CLASS:
{
ADD_TRACE(ret, RUBY_EVENT_CLASS);
- CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
+ CHECK(COMPILE(ret, "scoped node", node->nd_body));
ADD_TRACE(ret, RUBY_EVENT_END);
ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
break;
}
case ISEQ_TYPE_METHOD:
{
- ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
+ ISEQ_COMPILE_DATA(iseq)->root_node = node->nd_body;
ADD_TRACE(ret, RUBY_EVENT_CALL);
- CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
- ISEQ_COMPILE_DATA(iseq)->root_node = RNODE_SCOPE(node)->nd_body;
+ CHECK(COMPILE(ret, "scoped node", node->nd_body));
+ ISEQ_COMPILE_DATA(iseq)->root_node = node->nd_body;
ADD_TRACE(ret, RUBY_EVENT_RETURN);
ISEQ_COMPILE_DATA(iseq)->last_line = nd_line(node);
break;
}
default: {
- CHECK(COMPILE(ret, "scoped node", RNODE_SCOPE(node)->nd_body));
+ CHECK(COMPILE(ret, "scoped node", node->nd_body));
break;
}
}
@@ -960,8 +840,9 @@ rb_iseq_compile_node(rb_iseq_t *iseq, const NODE *node)
ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0) /* continue throw */ );
}
- else if (!drop_unreachable_return(ret)) {
- ADD_SYNTHETIC_INSN(ret, ISEQ_COMPILE_DATA(iseq)->last_line, -1, leave);
+ else {
+ NODE dummy_line_node = generate_dummy_line_node(ISEQ_COMPILE_DATA(iseq)->last_line, -1);
+ ADD_INSN(ret, &dummy_line_node, leave);
}
#if OPT_SUPPORT_JOKE
@@ -991,12 +872,6 @@ rb_iseq_translate_threaded_code(rb_iseq_t *iseq)
}
FL_SET((VALUE)iseq, ISEQ_TRANSLATED);
#endif
-
-#if USE_YJIT
- rb_yjit_live_iseq_count++;
- rb_yjit_iseq_alloc_count++;
-#endif
-
return COMPILE_OK;
}
@@ -1353,7 +1228,6 @@ new_label_body(rb_iseq_t *iseq, long line)
labelobj->set = 0;
labelobj->rescued = LABEL_RESCUE_NONE;
labelobj->unremovable = 0;
- labelobj->position = -1;
return labelobj;
}
@@ -1370,7 +1244,7 @@ new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line)
}
static void
-iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE, VALUE), VALUE data)
+iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE *, VALUE), VALUE data)
{
const char *types = insn_op_types(insn->insn_id);
for (int j = 0; types[j]; j++) {
@@ -1381,7 +1255,7 @@ iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE, VALUE), VALUE dat
case TS_VALUE:
case TS_IC: // constant path array
case TS_CALLDATA: // ci is stored.
- func(OPERAND_AT(insn, j), data);
+ func(&OPERAND_AT(insn, j), data);
break;
default:
break;
@@ -1390,13 +1264,14 @@ iseq_insn_each_markable_object(INSN *insn, void (*func)(VALUE, VALUE), VALUE dat
}
static void
-iseq_insn_each_object_write_barrier(VALUE obj, VALUE iseq)
+iseq_insn_each_object_write_barrier(VALUE *obj_ptr, VALUE iseq)
{
- RB_OBJ_WRITTEN(iseq, Qundef, obj);
+ RB_OBJ_WRITTEN(iseq, Qundef, *obj_ptr);
}
static INSN *
-new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc, VALUE *argv)
+new_insn_core(rb_iseq_t *iseq, const NODE *line_node,
+ int insn_id, int argc, VALUE *argv)
{
INSN *iobj = compile_data_alloc_insn(iseq);
@@ -1405,8 +1280,8 @@ new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc,
iobj->link.type = ISEQ_ELEMENT_INSN;
iobj->link.next = 0;
iobj->insn_id = insn_id;
- iobj->insn_info.line_no = line_no;
- iobj->insn_info.node_id = node_id;
+ iobj->insn_info.line_no = nd_line(line_node);
+ iobj->insn_info.node_id = nd_node_id(line_node);
iobj->insn_info.events = 0;
iobj->operands = argv;
iobj->operand_size = argc;
@@ -1418,7 +1293,7 @@ new_insn_core(rb_iseq_t *iseq, int line_no, int node_id, int insn_id, int argc,
}
static INSN *
-new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type insn_id, int argc, ...)
+new_insn_body(rb_iseq_t *iseq, const NODE *const line_node, enum ruby_vminsn_type insn_id, int argc, ...)
{
VALUE *operands = 0;
va_list argv;
@@ -1432,7 +1307,7 @@ new_insn_body(rb_iseq_t *iseq, int line_no, int node_id, enum ruby_vminsn_type i
}
va_end(argv);
}
- return new_insn_core(iseq, line_no, node_id, insn_id, argc, operands);
+ return new_insn_core(iseq, line_node, insn_id, argc, operands);
}
static const struct rb_callinfo *
@@ -1440,16 +1315,16 @@ new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_cal
{
VM_ASSERT(argc >= 0);
+ if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT)) &&
+ kw_arg == NULL && !has_blockiseq) {
+ flag |= VM_CALL_ARGS_SIMPLE;
+ }
+
if (kw_arg) {
flag |= VM_CALL_KWARG;
argc += kw_arg->keyword_len;
}
- if (!(flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KWARG | VM_CALL_KW_SPLAT | VM_CALL_FORWARDING))
- && !has_blockiseq) {
- flag |= VM_CALL_ARGS_SIMPLE;
- }
-
ISEQ_BODY(iseq)->ci_size++;
const struct rb_callinfo *ci = vm_ci_new(mid, flag, argc, kw_arg);
RB_OBJ_WRITTEN(iseq, Qundef, ci);
@@ -1457,7 +1332,7 @@ new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_cal
}
static INSN *
-new_insn_send(rb_iseq_t *iseq, int line_no, int node_id, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
+new_insn_send(rb_iseq_t *iseq, const NODE *const line_node, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_callinfo_kwarg *keywords)
{
VALUE *operands = compile_data_calloc2(iseq, sizeof(VALUE), 2);
VALUE ci = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
@@ -1466,16 +1341,7 @@ new_insn_send(rb_iseq_t *iseq, int line_no, int node_id, ID id, VALUE argc, cons
if (blockiseq) {
RB_OBJ_WRITTEN(iseq, Qundef, blockiseq);
}
-
- INSN *insn;
-
- if (vm_ci_flag((struct rb_callinfo *)ci) & VM_CALL_FORWARDING) {
- insn = new_insn_core(iseq, line_no, node_id, BIN(sendforward), 2, operands);
- }
- else {
- insn = new_insn_core(iseq, line_no, node_id, BIN(send), 2, operands);
- }
-
+ INSN *insn = new_insn_core(iseq, line_node, BIN(send), 2, operands);
RB_OBJ_WRITTEN(iseq, Qundef, ci);
RB_GC_GUARD(ci);
return insn;
@@ -1486,16 +1352,19 @@ new_child_iseq(rb_iseq_t *iseq, const NODE *const node,
VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
{
rb_iseq_t *ret_iseq;
- VALUE ast_value = rb_ruby_ast_new(node);
+ rb_ast_body_t ast;
+
+ ast.root = node;
+ ast.compile_option = 0;
+ ast.script_lines = ISEQ_BODY(iseq)->variable.script_lines;
debugs("[new_child_iseq]> ---------------------------------------\n");
int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
- ret_iseq = rb_iseq_new_with_opt(ast_value, name,
+ ret_iseq = rb_iseq_new_with_opt(&ast, name,
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
line_no, parent,
isolated_depth ? isolated_depth + 1 : 0,
- type, ISEQ_COMPILE_DATA(iseq)->option,
- ISEQ_BODY(iseq)->variable.script_lines);
+ type, ISEQ_COMPILE_DATA(iseq)->option);
debugs("[new_child_iseq]< ---------------------------------------\n");
return ret_iseq;
}
@@ -1515,14 +1384,11 @@ new_child_iseq_with_callback(rb_iseq_t *iseq, const struct rb_iseq_new_with_call
}
static void
-set_catch_except_p(rb_iseq_t *iseq)
+set_catch_except_p(struct rb_iseq_constant_body *body)
{
- RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
- ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
- if (ISEQ_BODY(iseq)->parent_iseq != NULL) {
- if (ISEQ_COMPILE_DATA(ISEQ_BODY(iseq)->parent_iseq)) {
- set_catch_except_p((rb_iseq_t *) ISEQ_BODY(iseq)->parent_iseq);
- }
+ body->catch_except_p = true;
+ if (body->parent_iseq != NULL) {
+ set_catch_except_p(ISEQ_BODY(body->parent_iseq));
}
}
@@ -1534,7 +1400,7 @@ set_catch_except_p(rb_iseq_t *iseq)
So this function sets true for limited ISeqs with break/next/redo catch table entries
whose child ISeq would really raise an exception. */
static void
-update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
+update_catch_except_flags(struct rb_iseq_constant_body *body)
{
unsigned int pos;
size_t i;
@@ -1547,7 +1413,7 @@ update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
while (pos < body->iseq_size) {
insn = rb_vm_insn_decode(body->iseq_encoded[pos]);
if (insn == BIN(throw)) {
- set_catch_except_p(iseq);
+ set_catch_except_p(body);
break;
}
pos += insn_len(insn);
@@ -1562,8 +1428,7 @@ update_catch_except_flags(rb_iseq_t *iseq, struct rb_iseq_constant_body *body)
if (entry->type != CATCH_TYPE_BREAK
&& entry->type != CATCH_TYPE_NEXT
&& entry->type != CATCH_TYPE_REDO) {
- RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
- ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
+ body->catch_except_p = true;
break;
}
}
@@ -1575,9 +1440,9 @@ iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
if (NIL_P(catch_table_ary)) return;
unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary);
- const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary);
+ const VALUE *tptr = RARRAY_CONST_PTR_TRANSIENT(catch_table_ary);
for (i = 0; i < tlen; i++) {
- const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]);
+ const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]);
LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1);
LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1);
LINK_ELEMENT *e;
@@ -1590,15 +1455,14 @@ iseq_insert_nop_between_end_and_cont(rb_iseq_t *iseq)
for (e = end; e && (IS_LABEL(e) || IS_TRACE(e)); e = e->next) {
if (e == cont) {
- INSN *nop = new_insn_core(iseq, 0, -1, BIN(nop), 0, 0);
+ NODE dummy_line_node = generate_dummy_line_node(0, -1);
+ INSN *nop = new_insn_core(iseq, &dummy_line_node, BIN(nop), 0, 0);
ELEM_INSERT_NEXT(end, &nop->link);
break;
}
}
}
}
-
- RB_GC_GUARD(catch_table_ary);
}
static int
@@ -1625,6 +1489,13 @@ iseq_setup_insn(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
dump_disasm_list(FIRST_ELEMENT(anchor));
}
+ if (ISEQ_COMPILE_DATA(iseq)->option->stack_caching) {
+ debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n");
+ iseq_set_sequence_stackcaching(iseq, anchor);
+ if (compile_debug > 5)
+ dump_disasm_list(FIRST_ELEMENT(anchor));
+ }
+
debugs("[compile step 3.4 (iseq_insert_nop_between_end_and_cont)]\n");
iseq_insert_nop_between_end_and_cont(iseq);
if (compile_debug > 5)
@@ -1654,12 +1525,10 @@ iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
debugs("[compile step 6 (update_catch_except_flags)] \n");
- RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
- update_catch_except_flags(iseq, ISEQ_BODY(iseq));
+ update_catch_except_flags(ISEQ_BODY(iseq));
debugs("[compile step 6.1 (remove unused catch tables)] \n");
- RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
- if (!ISEQ_COMPILE_DATA(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
+ if (!ISEQ_BODY(iseq)->catch_except_p && ISEQ_BODY(iseq)->catch_table) {
xfree(ISEQ_BODY(iseq)->catch_table);
ISEQ_BODY(iseq)->catch_table = NULL;
}
@@ -1795,7 +1664,7 @@ access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
}
else {
- COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable '%s' from isolated Proc", rb_id2name(id));
+ COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable `%s' from isolated Proc", rb_id2name(id));
}
}
@@ -1900,7 +1769,7 @@ static int
iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
const struct rb_args_info *args, int arg_size)
{
- const rb_node_kw_arg_t *node = args->kw_args;
+ const NODE *node = args->kw_args;
struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
struct rb_iseq_param_keyword *keyword;
const VALUE default_values = rb_ary_hidden_new(1);
@@ -1919,7 +1788,7 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
node = args->kw_args;
while (node) {
- const NODE *val_node = get_nd_value(node->nd_body);
+ const NODE *val_node = node->nd_body->nd_value;
VALUE dv;
if (val_node == NODE_SPECIAL_REQUIRED_KEYWORD) {
@@ -1927,29 +1796,8 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
}
else {
switch (nd_type(val_node)) {
- case NODE_SYM:
- dv = rb_node_sym_string_val(val_node);
- break;
- case NODE_REGX:
- dv = rb_node_regx_string_val(val_node);
- break;
- case NODE_LINE:
- dv = rb_node_line_lineno_val(val_node);
- break;
- case NODE_INTEGER:
- dv = rb_node_integer_literal_val(val_node);
- break;
- case NODE_FLOAT:
- dv = rb_node_float_literal_val(val_node);
- break;
- case NODE_RATIONAL:
- dv = rb_node_rational_literal_val(val_node);
- break;
- case NODE_IMAGINARY:
- dv = rb_node_imaginary_literal_val(val_node);
- break;
- case NODE_ENCODING:
- dv = rb_node_encoding_val(val_node);
+ case NODE_LIT:
+ dv = val_node->nd_lit;
break;
case NODE_NIL:
dv = Qnil;
@@ -1961,7 +1809,7 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
dv = Qfalse;
break;
default:
- NO_CHECK(COMPILE_POPPED(optargs, "kwarg", RNODE(node))); /* nd_type_p(node, NODE_KW_ARG) */
+ NO_CHECK(COMPILE_POPPED(optargs, "kwarg", node)); /* nd_type_p(node, NODE_KW_ARG) */
dv = complex_mark;
}
@@ -1974,23 +1822,23 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
keyword->num = kw;
- if (RNODE_DVAR(args->kw_rest_arg)->nd_vid != 0) {
- ID kw_id = iseq->body->local_table[arg_size];
+ if (args->kw_rest_arg->nd_vid != 0) {
keyword->rest_start = arg_size++;
body->param.flags.has_kwrest = TRUE;
-
- if (kw_id == idPow) body->param.flags.anon_kwrest = TRUE;
}
keyword->required_num = rkw;
keyword->table = &body->local_table[keyword->bits_start - keyword->num];
- if (RARRAY_LEN(default_values)) {
+ {
VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
for (i = 0; i < RARRAY_LEN(default_values); i++) {
VALUE dv = RARRAY_AREF(default_values, i);
if (dv == complex_mark) dv = Qundef;
- RB_OBJ_WRITE(iseq, &dvs[i], dv);
+ if (!SPECIAL_CONST_P(dv)) {
+ RB_OBJ_WRITTEN(iseq, Qundef, dv);
+ }
+ dvs[i] = dv;
}
keyword->default_values = dvs;
@@ -1998,22 +1846,6 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs,
return arg_size;
}
-static void
-iseq_set_use_block(rb_iseq_t *iseq)
-{
- struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
- if (!body->param.flags.use_block) {
- body->param.flags.use_block = 1;
-
- rb_vm_t *vm = GET_VM();
-
- if (!vm->unused_block_warning_strict) {
- st_data_t key = (st_data_t)rb_intern_str(body->location.label); // String -> ID
- st_insert(vm->unused_block_warning_table, key, 1);
- }
- }
-}
-
static int
iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *const node_args)
{
@@ -2021,7 +1853,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
if (node_args) {
struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
- struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
+ struct rb_args_info *args = node_args->nd_ainfo;
ID rest_id = 0;
int last_comma = 0;
ID block_id = 0;
@@ -2041,22 +1873,15 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
}
block_id = args->block_arg;
- bool optimized_forward = (args->forwarding && args->pre_args_num == 0 && !args->opt_args);
-
- if (optimized_forward) {
- rest_id = 0;
- block_id = 0;
- }
-
if (args->opt_args) {
- const rb_node_opt_arg_t *node = args->opt_args;
+ const NODE *node = args->opt_args;
LABEL *label;
VALUE labels = rb_ary_hidden_new(1);
VALUE *opt_table;
int i = 0, j;
while (node) {
- label = NEW_LABEL(nd_line(RNODE(node)));
+ label = NEW_LABEL(nd_line(node));
rb_ary_push(labels, (VALUE)label | 1);
ADD_LABEL(optargs, label);
NO_CHECK(COMPILE_POPPED(optargs, "optarg", node->nd_body));
@@ -2071,7 +1896,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
opt_table = ALLOC_N(VALUE, i+1);
- MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1);
+ MEMCPY(opt_table, RARRAY_CONST_PTR_TRANSIENT(labels), VALUE, i+1);
for (j = 0; j < i+1; j++) {
opt_table[j] &= ~1;
}
@@ -2086,8 +1911,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
if (rest_id) {
body->param.rest_start = arg_size++;
body->param.flags.has_rest = TRUE;
- if (rest_id == '*') body->param.flags.anon_rest = TRUE;
- RUBY_ASSERT(body->param.rest_start != -1);
+ assert(body->param.rest_start != -1);
}
if (args->first_post_arg) {
@@ -2104,16 +1928,11 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
if (args->kw_args) {
arg_size = iseq_set_arguments_keywords(iseq, optargs, args, arg_size);
}
- else if (args->kw_rest_arg && !optimized_forward) {
- ID kw_id = iseq->body->local_table[arg_size];
+ else if (args->kw_rest_arg) {
struct rb_iseq_param_keyword *keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
keyword->rest_start = arg_size++;
body->param.keyword = keyword;
body->param.flags.has_kwrest = TRUE;
-
- static ID anon_kwrest = 0;
- if (!anon_kwrest) anon_kwrest = rb_intern("**");
- if (kw_id == anon_kwrest) body->param.flags.anon_kwrest = TRUE;
}
else if (args->no_kwarg) {
body->param.flags.accepts_no_kwarg = TRUE;
@@ -2122,14 +1941,6 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
if (block_id) {
body->param.block_start = arg_size++;
body->param.flags.has_block = TRUE;
- iseq_set_use_block(iseq);
- }
-
- // Only optimize specifically methods like this: `foo(...)`
- if (optimized_forward) {
- body->param.flags.use_block = 1;
- body->param.flags.forwardable = TRUE;
- arg_size = 1;
}
iseq_calc_param_size(iseq);
@@ -2161,26 +1972,13 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
}
static int
-iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *const node_args)
+iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl)
{
unsigned int size = tbl ? tbl->size : 0;
- unsigned int offset = 0;
-
- if (node_args) {
- struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
-
- // If we have a function that only has `...` as the parameter,
- // then its local table should only be `...`
- // FIXME: I think this should be fixed in the AST rather than special case here.
- if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
- size -= 3;
- offset += 3;
- }
- }
if (size > 0) {
ID *ids = (ID *)ALLOC_N(ID, size);
- MEMCPY(ids, tbl->ids + offset, ID, size);
+ MEMCPY(ids, tbl->ids, ID, size);
ISEQ_BODY(iseq)->local_table = ids;
}
ISEQ_BODY(iseq)->local_table_size = size;
@@ -2464,7 +2262,6 @@ add_adjust_info(struct iseq_insn_info_entry *insns_info, unsigned int *positions
int insns_info_index, int code_index, const ADJUST *adjust)
{
insns_info[insns_info_index].line_no = adjust->line_no;
- insns_info[insns_info_index].node_id = -1;
insns_info[insns_info_index].events = 0;
positions[insns_info_index] = code_index;
return TRUE;
@@ -2585,12 +2382,7 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
generated_iseq = ALLOC_N(VALUE, code_index);
insns_info = ALLOC_N(struct iseq_insn_info_entry, insn_num);
positions = ALLOC_N(unsigned int, insn_num);
- if (ISEQ_IS_SIZE(body)) {
- body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
- }
- else {
- body->is_entries = NULL;
- }
+ body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(body));
body->call_data = ZALLOC_N(struct rb_call_data, body->ci_size);
ISEQ_COMPILE_DATA(iseq)->ci_index = 0;
@@ -2726,11 +2518,11 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
break;
}
- case TS_CALLDATA:
+ case TS_CALLDATA:
{
const struct rb_callinfo *source_ci = (const struct rb_callinfo *)operands[j];
- RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
struct rb_call_data *cd = &body->call_data[ISEQ_COMPILE_DATA(iseq)->ci_index++];
+ assert(ISEQ_COMPILE_DATA(iseq)->ci_index <= body->ci_size);
cd->ci = source_ci;
cd->cc = vm_cc_empty();
generated_iseq[code_index + 1 + j] = (VALUE)cd;
@@ -2872,23 +2664,18 @@ iseq_set_exception_table(rb_iseq_t *iseq)
VALUE catch_table_ary = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
if (NIL_P(catch_table_ary)) return COMPILE_OK;
tlen = (int)RARRAY_LEN(catch_table_ary);
- tptr = RARRAY_CONST_PTR(catch_table_ary);
+ tptr = RARRAY_CONST_PTR_TRANSIENT(catch_table_ary);
if (tlen > 0) {
struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen));
table->size = tlen;
for (i = 0; i < table->size; i++) {
- int pos;
- ptr = RARRAY_CONST_PTR(tptr[i]);
+ ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]);
entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
entry->type = (enum rb_catch_type)(ptr[0] & 0xffff);
- pos = label_get_position((LABEL *)(ptr[1] & ~1));
- RUBY_ASSERT(pos >= 0);
- entry->start = (unsigned int)pos;
- pos = label_get_position((LABEL *)(ptr[2] & ~1));
- RUBY_ASSERT(pos >= 0);
- entry->end = (unsigned int)pos;
+ entry->start = label_get_position((LABEL *)(ptr[1] & ~1));
+ entry->end = label_get_position((LABEL *)(ptr[2] & ~1));
entry->iseq = (rb_iseq_t *)ptr[3];
RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq);
@@ -2902,7 +2689,6 @@ iseq_set_exception_table(rb_iseq_t *iseq)
if (entry->type == CATCH_TYPE_RESCUE ||
entry->type == CATCH_TYPE_BREAK ||
entry->type == CATCH_TYPE_NEXT) {
- RUBY_ASSERT(entry->sp > 0);
entry->sp--;
}
}
@@ -3012,18 +2798,16 @@ unref_destination(INSN *iobj, int pos)
if (!lobj->refcnt) ELEM_REMOVE(&lobj->link);
}
-static bool
+static void
replace_destination(INSN *dobj, INSN *nobj)
{
VALUE n = OPERAND_AT(nobj, 0);
LABEL *dl = (LABEL *)OPERAND_AT(dobj, 0);
LABEL *nl = (LABEL *)n;
- if (dl == nl) return false;
--dl->refcnt;
++nl->refcnt;
OPERAND_AT(dobj, 0) = n;
if (!dl->refcnt) ELEM_REMOVE(&dl->link);
- return true;
}
static LABEL*
@@ -3117,7 +2901,7 @@ iseq_pop_newarray(rb_iseq_t *iseq, INSN *iobj)
static int
is_frozen_putstring(INSN *insn, VALUE *op)
{
- if (IS_INSN_ID(insn, putstring) || IS_INSN_ID(insn, putchilledstring)) {
+ if (IS_INSN_ID(insn, putstring)) {
*op = OPERAND_AT(insn, 0);
return 1;
}
@@ -3159,7 +2943,6 @@ optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
switch (INSN_OF(iobj)) {
case BIN(putstring):
- case BIN(putchilledstring):
type = INT2FIX(T_STRING);
break;
case BIN(putnil):
@@ -3200,6 +2983,7 @@ optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
}
line = ciobj->insn_info.line_no;
node_id = ciobj->insn_info.node_id;
+ NODE dummy_line_node = generate_dummy_line_node(line, node_id);
if (!dest) {
if (niobj->link.next && IS_LABEL(niobj->link.next)) {
dest = (LABEL *)niobj->link.next; /* reuse label */
@@ -3209,9 +2993,9 @@ optimize_checktype(rb_iseq_t *iseq, INSN *iobj)
ELEM_INSERT_NEXT(&niobj->link, &dest->link);
}
}
- INSERT_AFTER_INSN1(iobj, line, node_id, jump, dest);
+ INSERT_AFTER_INSN1(iobj, &dummy_line_node, jump, dest);
LABEL_REF(dest);
- if (!dup) INSERT_AFTER_INSN(iobj, line, node_id, pop);
+ if (!dup) INSERT_AFTER_INSN(iobj, &dummy_line_node, pop);
return TRUE;
}
@@ -3237,8 +3021,6 @@ ci_argc_set(const rb_iseq_t *iseq, const struct rb_callinfo *ci, int argc)
return nci;
}
-#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
-
static int
iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
{
@@ -3277,10 +3059,9 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
* => in this case, first jump instruction should jump to
* LABEL2 directly
*/
- if (replace_destination(iobj, diobj)) {
- remove_unreachable_chunk(iseq, iobj->link.next);
- goto again;
- }
+ replace_destination(iobj, diobj);
+ remove_unreachable_chunk(iseq, iobj->link.next);
+ goto again;
}
else if (IS_INSN_ID(diobj, leave)) {
/*
@@ -3325,7 +3106,8 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
*/
piobj->insn_id = (IS_INSN_ID(piobj, branchif))
? BIN(branchunless) : BIN(branchif);
- if (replace_destination(piobj, iobj) && refcnt <= 1) {
+ replace_destination(piobj, iobj);
+ if (refcnt <= 1) {
ELEM_REMOVE(&iobj->link);
}
else {
@@ -3347,7 +3129,8 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
* pop
* jump L1
*/
- INSN *popiobj = new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, BIN(pop), 0, 0);
+ NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
+ INSN *popiobj = new_insn_core(iseq, &dummy_line_node, BIN(pop), 0, 0);
ELEM_REPLACE(&piobj->link, &popiobj->link);
}
}
@@ -3392,117 +3175,19 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
/*
* ...
* duparray [...]
- * concatarray | concattoarray
+ * concatarray
* =>
* ...
* putobject [...]
- * concatarray | concattoarray
+ * concatarray
*/
if (IS_INSN_ID(iobj, duparray)) {
LINK_ELEMENT *next = iobj->link.next;
- if (IS_INSN(next) && (IS_INSN_ID(next, concatarray) || IS_INSN_ID(next, concattoarray))) {
+ if (IS_INSN(next) && IS_INSN_ID(next, concatarray)) {
iobj->insn_id = BIN(putobject);
}
}
- /*
- * duparray [...]
- * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
- * =>
- * opt_ary_freeze [...], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
- */
- if (IS_INSN_ID(iobj, duparray)) {
- LINK_ELEMENT *next = iobj->link.next;
- if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
- const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
- const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
-
- if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
- VALUE ary = iobj->operands[0];
- rb_obj_reveal(ary, rb_cArray);
-
- iobj->insn_id = BIN(opt_ary_freeze);
- iobj->operand_size = 2;
- iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
- iobj->operands[0] = ary;
- iobj->operands[1] = (VALUE)ci;
- ELEM_REMOVE(next);
- }
- }
- }
-
- /*
- * duphash {...}
- * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
- * =>
- * opt_hash_freeze {...}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
- */
- if (IS_INSN_ID(iobj, duphash)) {
- LINK_ELEMENT *next = iobj->link.next;
- if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
- const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
- const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
-
- if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
- VALUE hash = iobj->operands[0];
- rb_obj_reveal(hash, rb_cHash);
-
- iobj->insn_id = BIN(opt_hash_freeze);
- iobj->operand_size = 2;
- iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
- iobj->operands[0] = hash;
- iobj->operands[1] = (VALUE)ci;
- ELEM_REMOVE(next);
- }
- }
- }
-
- /*
- * newarray 0
- * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
- * =>
- * opt_ary_freeze [], <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
- */
- if (IS_INSN_ID(iobj, newarray) && iobj->operands[0] == INT2FIX(0)) {
- LINK_ELEMENT *next = iobj->link.next;
- if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
- const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
- const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
-
- if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
- iobj->insn_id = BIN(opt_ary_freeze);
- iobj->operand_size = 2;
- iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
- iobj->operands[0] = rb_cArray_empty_frozen;
- iobj->operands[1] = (VALUE)ci;
- ELEM_REMOVE(next);
- }
- }
- }
-
- /*
- * newhash 0
- * send <calldata!mid:freeze, argc:0, ARGS_SIMPLE>, nil
- * =>
- * opt_hash_freeze {}, <calldata!mid:freeze, argc:0, ARGS_SIMPLE>
- */
- if (IS_INSN_ID(iobj, newhash) && iobj->operands[0] == INT2FIX(0)) {
- LINK_ELEMENT *next = iobj->link.next;
- if (IS_INSN(next) && (IS_INSN_ID(next, send))) {
- const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(next, 0);
- const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(next, 1);
-
- if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && blockiseq == NULL && vm_ci_mid(ci) == idFreeze) {
- iobj->insn_id = BIN(opt_hash_freeze);
- iobj->operand_size = 2;
- iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
- iobj->operands[0] = rb_cHash_empty_frozen;
- iobj->operands[1] = (VALUE)ci;
- ELEM_REMOVE(next);
- }
- }
- }
-
if (IS_INSN_ID(iobj, branchif) ||
IS_INSN_ID(iobj, branchnil) ||
IS_INSN_ID(iobj, branchunless)) {
@@ -3552,7 +3237,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
for (;;) {
if (IS_INSN(&nobj->link) && IS_INSN_ID(nobj, jump)) {
- if (!replace_destination(iobj, nobj)) break;
+ replace_destination(iobj, nobj);
}
else if (prev_dup && IS_INSN_ID(nobj, dup) &&
!!(nobj = (INSN *)nobj->link.next) &&
@@ -3573,7 +3258,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
* dup
* if L2
*/
- if (!replace_destination(iobj, nobj)) break;
+ replace_destination(iobj, nobj);
}
else if (pobj) {
/*
@@ -3624,12 +3309,14 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
ELEM_REMOVE(iobj->link.prev);
}
else if (!iseq_pop_newarray(iseq, pobj)) {
- pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(pop), 0, NULL);
+ NODE dummy_line_node = generate_dummy_line_node(pobj->insn_info.line_no, pobj->insn_info.node_id);
+ pobj = new_insn_core(iseq, &dummy_line_node, BIN(pop), 0, NULL);
ELEM_INSERT_PREV(&iobj->link, &pobj->link);
}
if (cond) {
if (prev_dup) {
- pobj = new_insn_core(iseq, pobj->insn_info.line_no, pobj->insn_info.node_id, BIN(putnil), 0, NULL);
+ NODE dummy_line_node = generate_dummy_line_node(pobj->insn_info.line_no, pobj->insn_info.node_id);
+ pobj = new_insn_core(iseq, &dummy_line_node, BIN(putnil), 0, NULL);
ELEM_INSERT_NEXT(&iobj->link, &pobj->link);
}
iobj->insn_id = BIN(jump);
@@ -3659,12 +3346,11 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
enum ruby_vminsn_type previ = ((INSN *)prev)->insn_id;
if (previ == BIN(putobject) || previ == BIN(putnil) ||
previ == BIN(putself) || previ == BIN(putstring) ||
- previ == BIN(putchilledstring) ||
previ == BIN(dup) ||
previ == BIN(getlocal) ||
previ == BIN(getblockparam) ||
previ == BIN(getblockparamproxy) ||
- previ == BIN(getinstancevariable) ||
+ /* getinstancevariable may issue a warning */
previ == BIN(duparray)) {
/* just push operand or static value and pop soon, no
* side effects */
@@ -3676,7 +3362,8 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
}
else if (previ == BIN(concatarray)) {
INSN *piobj = (INSN *)prev;
- INSERT_BEFORE_INSN1(piobj, piobj->insn_info.line_no, piobj->insn_info.node_id, splatarray, Qfalse);
+ NODE dummy_line_node = generate_dummy_line_node(piobj->insn_info.line_no, piobj->insn_info.node_id);
+ INSERT_BEFORE_INSN1(piobj, &dummy_line_node, splatarray, Qfalse);
INSN_OF(piobj) = BIN(pop);
}
else if (previ == BIN(concatstrings)) {
@@ -3693,6 +3380,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if (IS_INSN_ID(iobj, newarray) ||
IS_INSN_ID(iobj, duparray) ||
+ IS_INSN_ID(iobj, expandarray) ||
IS_INSN_ID(iobj, concatarray) ||
IS_INSN_ID(iobj, splatarray) ||
0) {
@@ -3741,6 +3429,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
}
}
else {
+ NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
long diff = FIX2LONG(op1) - FIX2LONG(op2);
INSN_OF(iobj) = BIN(opt_reverse);
OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
@@ -3754,7 +3443,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
* opt_reverse Y
*/
for (; diff > 0; diff--) {
- INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, pop);
+ INSERT_BEFORE_INSN(iobj, &dummy_line_node, pop);
}
}
else { /* (op1 < op2) */
@@ -3766,7 +3455,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
* opt_reverse Y
*/
for (; diff < 0; diff++) {
- INSERT_BEFORE_INSN(iobj, iobj->insn_info.line_no, iobj->insn_info.node_id, putnil);
+ INSERT_BEFORE_INSN(iobj, &dummy_line_node, putnil);
}
}
}
@@ -3801,7 +3490,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
}
}
- if (IS_INSN_ID(iobj, putstring) || IS_INSN_ID(iobj, putchilledstring) ||
+ if (IS_INSN_ID(iobj, putstring) ||
(IS_INSN_ID(iobj, putobject) && RB_TYPE_P(OPERAND_AT(iobj, 0), T_STRING))) {
/*
* putstring ""
@@ -3988,10 +3677,6 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if (IS_TRACE(iobj->link.next)) {
if (IS_NEXT_INSN_ID(iobj->link.next, leave)) {
iobj->insn_id = BIN(opt_invokebuiltin_delegate_leave);
- const struct rb_builtin_function *bf = (const struct rb_builtin_function *)iobj->operands[0];
- if (iobj == (INSN *)list && bf->argc == 0 && (iseq->body->builtin_attrs & BUILTIN_ATTR_LEAF)) {
- iseq->body->builtin_attrs |= BUILTIN_ATTR_SINGLE_NOARG_LEAF;
- }
}
}
}
@@ -4009,64 +3694,6 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
}
}
- if (IS_INSN_ID(iobj, splatarray) && OPERAND_AT(iobj, 0) == false) {
- LINK_ELEMENT *niobj = &iobj->link;
- if (IS_NEXT_INSN_ID(niobj, duphash)) {
- niobj = niobj->next;
- LINK_ELEMENT *siobj;
- unsigned int set_flags = 0, unset_flags = 0;
-
- /*
- * Eliminate hash allocation for f(*a, kw: 1)
- *
- * splatarray false
- * duphash
- * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT and not ARGS_BLOCKARG
- * =>
- * splatarray false
- * putobject
- * send ARGS_SPLAT|KW_SPLAT
- */
- if (IS_NEXT_INSN_ID(niobj, send)) {
- siobj = niobj->next;
- set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT;
- unset_flags = VM_CALL_ARGS_BLOCKARG;
- }
- /*
- * Eliminate hash allocation for f(*a, kw: 1, &{arg,lvar,@iv})
- *
- * splatarray false
- * duphash
- * getlocal / getinstancevariable / getblockparamproxy
- * send ARGS_SPLAT|KW_SPLAT|KW_SPLAT_MUT|ARGS_BLOCKARG
- * =>
- * splatarray false
- * putobject
- * getlocal / getinstancevariable / getblockparamproxy
- * send ARGS_SPLAT|KW_SPLAT|ARGS_BLOCKARG
- */
- else if ((IS_NEXT_INSN_ID(niobj, getlocal) || IS_NEXT_INSN_ID(niobj, getinstancevariable) ||
- IS_NEXT_INSN_ID(niobj, getblockparamproxy)) && (IS_NEXT_INSN_ID(niobj->next, send))) {
- siobj = niobj->next->next;
- set_flags = VM_CALL_ARGS_SPLAT|VM_CALL_KW_SPLAT|VM_CALL_KW_SPLAT_MUT|VM_CALL_ARGS_BLOCKARG;
- }
-
- if (set_flags) {
- const struct rb_callinfo *ci = (const struct rb_callinfo *)OPERAND_AT(siobj, 0);
- unsigned int flags = vm_ci_flag(ci);
- if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
- ((INSN*)niobj)->insn_id = BIN(putobject);
- OPERAND_AT(niobj, 0) = rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)));
-
- const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
- flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
- RB_OBJ_WRITTEN(iseq, ci, nci);
- OPERAND_AT(siobj, 0) = (VALUE)nci;
- }
- }
- }
- }
-
return COMPILE_OK;
}
@@ -4094,82 +3721,24 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
if (IS_INSN_ID(iobj, newarray) && iobj->link.next &&
IS_INSN(iobj->link.next)) {
/*
- * [a, b, ...].max/min -> a, b, c, opt_newarray_send max/min
+ * [a, b, ...].max/min -> a, b, c, opt_newarray_max/min
*/
INSN *niobj = (INSN *)iobj->link.next;
if (IS_INSN_ID(niobj, send)) {
const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
- if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
- VALUE method = INT2FIX(0);
+ if ((vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) && vm_ci_argc(ci) == 0) {
switch (vm_ci_mid(ci)) {
case idMax:
- method = INT2FIX(VM_OPT_NEWARRAY_SEND_MAX);
- break;
+ iobj->insn_id = BIN(opt_newarray_max);
+ ELEM_REMOVE(&niobj->link);
+ return COMPILE_OK;
case idMin:
- method = INT2FIX(VM_OPT_NEWARRAY_SEND_MIN);
- break;
- case idHash:
- method = INT2FIX(VM_OPT_NEWARRAY_SEND_HASH);
- break;
- }
-
- if (method != INT2FIX(0)) {
- VALUE num = iobj->operands[0];
- int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
- iobj->insn_id = BIN(opt_newarray_send);
- iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
- iobj->operands[0] = num;
- iobj->operands[1] = method;
- iobj->operand_size = operand_len;
+ iobj->insn_id = BIN(opt_newarray_min);
ELEM_REMOVE(&niobj->link);
return COMPILE_OK;
}
}
}
- else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
- (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
- IS_NEXT_INSN_ID(&niobj->link, send)) {
- const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
- if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
- VALUE num = iobj->operands[0];
- int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
- iobj->insn_id = BIN(opt_newarray_send);
- iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
- iobj->operands[0] = FIXNUM_INC(num, 1);
- iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK);
- iobj->operand_size = operand_len;
- ELEM_REMOVE(&iobj->link);
- ELEM_REMOVE(niobj->link.next);
- ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
- return COMPILE_OK;
- }
- }
- // newarray n, putchilledstring "E", getlocal b, send :pack with {buffer: b}
- // -> putchilledstring "E", getlocal b, opt_newarray_send n+2, :pack, :buffer
- else if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
- (IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
- IS_NEXT_INSN_ID(&niobj->link, getlocal) &&
- (niobj->link.next && IS_NEXT_INSN_ID(niobj->link.next, send))) {
- const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)(niobj->link.next)->next, 0);
- const struct rb_callinfo_kwarg *kwarg = vm_ci_kwarg(ci);
- if (vm_ci_mid(ci) == idPack && vm_ci_argc(ci) == 2 &&
- (kwarg && kwarg->keyword_len == 1 && kwarg->keywords[0] == rb_id2sym(idBuffer))) {
- VALUE num = iobj->operands[0];
- int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
- iobj->insn_id = BIN(opt_newarray_send);
- iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
- iobj->operands[0] = FIXNUM_INC(num, 2);
- iobj->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_PACK_BUFFER);
- iobj->operand_size = operand_len;
- // Remove the "send" insn.
- ELEM_REMOVE((niobj->link.next)->next);
- // Remove the modified insn from its original "newarray" position...
- ELEM_REMOVE(&iobj->link);
- // and insert it after the buffer insn.
- ELEM_INSERT_NEXT(niobj->link.next, &iobj->link);
- return COMPILE_OK;
- }
- }
}
if (IS_INSN_ID(iobj, send)) {
@@ -4177,7 +3746,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
- if (vm_ci_simple(ci)) {
+ if (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) {
switch (vm_ci_argc(ci)) {
case 0:
switch (vm_ci_mid(ci)) {
@@ -4217,7 +3786,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
}
}
- if ((vm_ci_flag(ci) & (VM_CALL_ARGS_BLOCKARG | VM_CALL_FORWARDING)) == 0 && blockiseq == NULL) {
+ if ((vm_ci_flag(ci) & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) {
iobj->insn_id = BIN(opt_send_without_block);
iobj->operand_size = insn_len(iobj->insn_id) - 1;
}
@@ -4260,7 +3829,7 @@ iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
int do_block_optimization = 0;
- if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK && !ISEQ_COMPILE_DATA(iseq)->catch_except_p) {
+ if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_BLOCK && !ISEQ_BODY(iseq)->catch_except_p) {
do_block_optimization = 1;
}
@@ -4337,7 +3906,8 @@ new_unified_insn(rb_iseq_t *iseq,
list = list->next;
}
- return new_insn_core(iseq, iobj->insn_info.line_no, iobj->insn_info.node_id, insn_id, argc, operands);
+ NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
+ return new_insn_core(iseq, &dummy_line_node, insn_id, argc, operands);
}
#endif
@@ -4397,24 +3967,185 @@ iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
return COMPILE_OK;
}
+#if OPT_STACK_CACHING
+
+#define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)]
+#define SC_NEXT(insn) sc_insn_next[(insn)]
+
+#include "opt_sc.inc"
+
+static int
+insn_set_sc_state(rb_iseq_t *iseq, const LINK_ELEMENT *anchor, INSN *iobj, int state)
+{
+ int nstate;
+ int insn_id;
+
+ insn_id = iobj->insn_id;
+ iobj->insn_id = SC_INSN(insn_id, state);
+ nstate = SC_NEXT(iobj->insn_id);
+
+ if (insn_id == BIN(jump) ||
+ insn_id == BIN(branchif) || insn_id == BIN(branchunless)) {
+ LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0);
+
+ if (lobj->sc_state != 0) {
+ if (lobj->sc_state != nstate) {
+ BADINSN_DUMP(anchor, iobj, lobj);
+ COMPILE_ERROR(iseq, iobj->insn_info.line_no,
+ "insn_set_sc_state error: %d at "LABEL_FORMAT
+ ", %d expected\n",
+ lobj->sc_state, lobj->label_no, nstate);
+ return COMPILE_NG;
+ }
+ }
+ else {
+ lobj->sc_state = nstate;
+ }
+ if (insn_id == BIN(jump)) {
+ nstate = SCS_XX;
+ }
+ }
+ else if (insn_id == BIN(leave)) {
+ nstate = SCS_XX;
+ }
+
+ return nstate;
+}
+
+static int
+label_set_sc_state(LABEL *lobj, int state)
+{
+ if (lobj->sc_state != 0) {
+ if (lobj->sc_state != state) {
+ state = lobj->sc_state;
+ }
+ }
+ else {
+ lobj->sc_state = state;
+ }
+
+ return state;
+}
+
+
+#endif
+
+static int
+iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *const anchor)
+{
+#if OPT_STACK_CACHING
+ LINK_ELEMENT *list;
+ int state, insn_id;
+
+ /* initialize */
+ state = SCS_XX;
+ list = FIRST_ELEMENT(anchor);
+ /* dump_disasm_list(list); */
+
+ /* for each list element */
+ while (list) {
+ redo_point:
+ switch (list->type) {
+ case ISEQ_ELEMENT_INSN:
+ {
+ INSN *iobj = (INSN *)list;
+ insn_id = iobj->insn_id;
+
+ /* dump_disasm_list(list); */
+
+ switch (insn_id) {
+ case BIN(nop):
+ {
+ /* exception merge point */
+ if (state != SCS_AX) {
+ NODE dummy_line_node = generate_dummy_line_node(0, -1);
+ INSN *rpobj =
+ new_insn_body(iseq, &dummy_line_node, BIN(reput), 0);
+
+ /* replace this insn */
+ ELEM_REPLACE(list, (LINK_ELEMENT *)rpobj);
+ list = (LINK_ELEMENT *)rpobj;
+ goto redo_point;
+ }
+ break;
+ }
+ case BIN(swap):
+ {
+ if (state == SCS_AB || state == SCS_BA) {
+ state = (state == SCS_AB ? SCS_BA : SCS_AB);
+
+ ELEM_REMOVE(list);
+ list = list->next;
+ goto redo_point;
+ }
+ break;
+ }
+ case BIN(pop):
+ {
+ switch (state) {
+ case SCS_AX:
+ case SCS_BX:
+ state = SCS_XX;
+ break;
+ case SCS_AB:
+ state = SCS_AX;
+ break;
+ case SCS_BA:
+ state = SCS_BX;
+ break;
+ case SCS_XX:
+ goto normal_insn;
+ default:
+ COMPILE_ERROR(iseq, iobj->insn_info.line_no,
+ "unreachable");
+ return COMPILE_NG;
+ }
+ /* remove useless pop */
+ ELEM_REMOVE(list);
+ list = list->next;
+ goto redo_point;
+ }
+ default:;
+ /* none */
+ } /* end of switch */
+ normal_insn:
+ state = insn_set_sc_state(iseq, anchor, iobj, state);
+ break;
+ }
+ case ISEQ_ELEMENT_LABEL:
+ {
+ LABEL *lobj;
+ lobj = (LABEL *)list;
+
+ state = label_set_sc_state(lobj, state);
+ }
+ default:
+ break;
+ }
+ list = list->next;
+ }
+#endif
+ return COMPILE_OK;
+}
+
static int
all_string_result_p(const NODE *node)
{
if (!node) return FALSE;
switch (nd_type(node)) {
- case NODE_STR: case NODE_DSTR: case NODE_FILE:
+ case NODE_STR: case NODE_DSTR:
return TRUE;
case NODE_IF: case NODE_UNLESS:
- if (!RNODE_IF(node)->nd_body || !RNODE_IF(node)->nd_else) return FALSE;
- if (all_string_result_p(RNODE_IF(node)->nd_body))
- return all_string_result_p(RNODE_IF(node)->nd_else);
+ if (!node->nd_body || !node->nd_else) return FALSE;
+ if (all_string_result_p(node->nd_body))
+ return all_string_result_p(node->nd_else);
return FALSE;
case NODE_AND: case NODE_OR:
- if (!RNODE_AND(node)->nd_2nd)
- return all_string_result_p(RNODE_AND(node)->nd_1st);
- if (!all_string_result_p(RNODE_AND(node)->nd_1st))
+ if (!node->nd_2nd)
+ return all_string_result_p(node->nd_1st);
+ if (!all_string_result_p(node->nd_1st))
return FALSE;
- return all_string_result_p(RNODE_AND(node)->nd_2nd);
+ return all_string_result_p(node->nd_2nd);
default:
return FALSE;
}
@@ -4423,8 +4154,8 @@ all_string_result_p(const NODE *node)
static int
compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int *cntp)
{
- const struct RNode_LIST *list = RNODE_DSTR(node)->nd_next;
- VALUE lit = rb_node_dstr_string_val(node);
+ const NODE *list = node->nd_next;
+ VALUE lit = node->nd_lit;
LINK_ELEMENT *first_lit = 0;
int cnt = 0;
@@ -4445,7 +4176,7 @@ compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cons
while (list) {
const NODE *const head = list->nd_head;
if (nd_type_p(head, NODE_STR)) {
- lit = rb_node_str_string_val(head);
+ lit = rb_fstring(head->nd_lit);
ADD_INSN1(ret, head, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
lit = Qnil;
@@ -4454,7 +4185,7 @@ compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cons
CHECK(COMPILE(ret, "each string", head));
}
cnt++;
- list = (struct RNode_LIST *)list->nd_next;
+ list = list->nd_next;
}
if (NIL_P(lit) && first_lit) {
ELEM_REMOVE(first_lit);
@@ -4469,12 +4200,12 @@ static int
compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
{
while (node && nd_type_p(node, NODE_BLOCK)) {
- CHECK(COMPILE_(ret, "BLOCK body", RNODE_BLOCK(node)->nd_head,
- (RNODE_BLOCK(node)->nd_next ? 1 : popped)));
- node = RNODE_BLOCK(node)->nd_next;
+ CHECK(COMPILE_(ret, "BLOCK body", node->nd_head,
+ (node->nd_next ? 1 : popped)));
+ node = node->nd_next;
}
if (node) {
- CHECK(COMPILE_(ret, "BLOCK next", RNODE_BLOCK(node)->nd_next, popped));
+ CHECK(COMPILE_(ret, "BLOCK next", node->nd_next, popped));
}
return COMPILE_OK;
}
@@ -4483,8 +4214,8 @@ static int
compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
{
int cnt;
- if (!RNODE_DSTR(node)->nd_next) {
- VALUE lit = rb_node_dstr_string_val(node);
+ if (!node->nd_next) {
+ VALUE lit = rb_fstring(node->nd_lit);
ADD_INSN1(ret, node, putstring, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
}
@@ -4496,28 +4227,11 @@ compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
}
static int
-compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
+compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
{
int cnt;
- int cflag = (int)RNODE_DREGX(node)->as.nd_cflag;
-
- if (!RNODE_DREGX(node)->nd_next) {
- if (!popped) {
- VALUE src = rb_node_dregx_string_val(node);
- VALUE match = rb_reg_compile(src, cflag, NULL, 0);
- ADD_INSN1(ret, node, putobject, match);
- RB_OBJ_WRITTEN(iseq, Qundef, match);
- }
- return COMPILE_OK;
- }
-
CHECK(compile_dstr_fragments(iseq, ret, node, &cnt));
- ADD_INSN2(ret, node, toregexp, INT2FIX(cflag), INT2FIX(cnt));
-
- if (popped) {
- ADD_INSN(ret, node, pop);
- }
-
+ ADD_INSN2(ret, node, toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt));
return COMPILE_OK;
}
@@ -4535,7 +4249,7 @@ compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const nod
ADD_INSNL(ret, node, branchif, lend);
/* *flip == 0 */
- CHECK(COMPILE(ret, "flip2 beg", RNODE_FLIP2(node)->nd_beg));
+ CHECK(COMPILE(ret, "flip2 beg", node->nd_beg));
ADD_INSNL(ret, node, branchunless, else_label);
ADD_INSN1(ret, node, putobject, Qtrue);
ADD_INSN1(ret, node, setspecial, key);
@@ -4545,7 +4259,7 @@ compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const nod
/* *flip == 1 */
ADD_LABEL(ret, lend);
- CHECK(COMPILE(ret, "flip2 end", RNODE_FLIP2(node)->nd_end));
+ CHECK(COMPILE(ret, "flip2 end", node->nd_end));
ADD_INSNL(ret, node, branchunless, then_label);
ADD_INSN1(ret, node, putobject, Qfalse);
ADD_INSN1(ret, node, setspecial, key);
@@ -4555,73 +4269,40 @@ compile_flip_flop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const nod
}
static int
-compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
- LABEL *then_label, LABEL *else_label);
-
-#define COMPILE_SINGLE 2
-static int
-compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
- LABEL *then_label, LABEL *else_label)
-{
- DECL_ANCHOR(seq);
- INIT_ANCHOR(seq);
- LABEL *label = NEW_LABEL(nd_line(cond));
- if (!then_label) then_label = label;
- else if (!else_label) else_label = label;
-
- CHECK(compile_branch_condition(iseq, seq, cond, then_label, else_label));
-
- if (LIST_INSN_SIZE_ONE(seq)) {
- INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
- if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
- return COMPILE_OK;
- }
- if (!label->refcnt) {
- return COMPILE_SINGLE;
- }
- ADD_LABEL(seq, label);
- ADD_SEQ(ret, seq);
- return COMPILE_OK;
-}
-
-static int
-compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
+compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cond,
LABEL *then_label, LABEL *else_label)
{
- int ok;
- DECL_ANCHOR(ignore);
-
again:
switch (nd_type(cond)) {
case NODE_AND:
- CHECK(ok = compile_logical(iseq, ret, RNODE_AND(cond)->nd_1st, NULL, else_label));
- cond = RNODE_AND(cond)->nd_2nd;
- if (ok == COMPILE_SINGLE) {
- INIT_ANCHOR(ignore);
- ret = ignore;
- then_label = NEW_LABEL(nd_line(cond));
- }
- goto again;
+ {
+ LABEL *label = NEW_LABEL(nd_line(cond));
+ CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, label,
+ else_label));
+ if (!label->refcnt) {
+ ADD_INSN(ret, cond, putnil);
+ break;
+ }
+ ADD_LABEL(ret, label);
+ cond = cond->nd_2nd;
+ goto again;
+ }
case NODE_OR:
- CHECK(ok = compile_logical(iseq, ret, RNODE_OR(cond)->nd_1st, then_label, NULL));
- cond = RNODE_OR(cond)->nd_2nd;
- if (ok == COMPILE_SINGLE) {
- INIT_ANCHOR(ignore);
- ret = ignore;
- else_label = NEW_LABEL(nd_line(cond));
- }
- goto again;
- case NODE_SYM:
- case NODE_LINE:
- case NODE_FILE:
- case NODE_ENCODING:
- case NODE_INTEGER: /* NODE_INTEGER is always true */
- case NODE_FLOAT: /* NODE_FLOAT is always true */
- case NODE_RATIONAL: /* NODE_RATIONAL is always true */
- case NODE_IMAGINARY: /* NODE_IMAGINARY is always true */
+ {
+ LABEL *label = NEW_LABEL(nd_line(cond));
+ CHECK(compile_branch_condition(iseq, ret, cond->nd_1st, then_label,
+ label));
+ if (!label->refcnt) {
+ ADD_INSN(ret, cond, putnil);
+ break;
+ }
+ ADD_LABEL(ret, label);
+ cond = cond->nd_2nd;
+ goto again;
+ }
+ case NODE_LIT: /* NODE_LIT is always true */
case NODE_TRUE:
case NODE_STR:
- case NODE_REGX:
case NODE_ZLIST:
case NODE_LAMBDA:
/* printf("useless condition eliminate (%s)\n", ruby_node_name(nd_type(cond))); */
@@ -4646,31 +4327,10 @@ compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
CHECK(compile_flip_flop(iseq, ret, cond, FALSE, then_label, else_label));
return COMPILE_OK;
case NODE_DEFINED:
- CHECK(compile_defined_expr(iseq, ret, cond, Qfalse, ret == ignore));
+ CHECK(compile_defined_expr(iseq, ret, cond, Qfalse));
break;
default:
- {
- DECL_ANCHOR(cond_seq);
- INIT_ANCHOR(cond_seq);
-
- CHECK(COMPILE(cond_seq, "branch condition", cond));
-
- if (LIST_INSN_SIZE_ONE(cond_seq)) {
- INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
- if (insn->insn_id == BIN(putobject)) {
- if (RTEST(insn->operands[0])) {
- ADD_INSNL(ret, cond, jump, then_label);
- // maybe unreachable
- return COMPILE_OK;
- }
- else {
- ADD_INSNL(ret, cond, jump, else_label);
- return COMPILE_OK;
- }
- }
- }
- ADD_SEQ(ret, cond_seq);
- }
+ CHECK(COMPILE(ret, "branch condition", cond));
break;
}
@@ -4684,68 +4344,33 @@ compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *cond,
static int
keyword_node_p(const NODE *const node)
{
- return nd_type_p(node, NODE_HASH) && (RNODE_HASH(node)->nd_brace & HASH_BRACE) != HASH_BRACE;
-}
-
-static VALUE
-get_symbol_value(rb_iseq_t *iseq, const NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_SYM:
- return rb_node_sym_string_val(node);
- default:
- UNKNOWN_NODE("get_symbol_value", node, Qnil);
- }
-}
-
-static VALUE
-node_hash_unique_key_index(rb_iseq_t *iseq, rb_node_hash_t *node_hash, int *count_ptr)
-{
- NODE *node = node_hash->nd_head;
- VALUE hash = rb_hash_new();
- VALUE ary = rb_ary_new();
-
- for (int i = 0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
- VALUE key = get_symbol_value(iseq, RNODE_LIST(node)->nd_head);
- VALUE idx = rb_hash_aref(hash, key);
- if (!NIL_P(idx)) {
- rb_ary_store(ary, FIX2INT(idx), Qfalse);
- (*count_ptr)--;
- }
- rb_hash_aset(hash, key, INT2FIX(i));
- rb_ary_store(ary, i, Qtrue);
- (*count_ptr)++;
- }
-
- return ary;
+ return nd_type_p(node, NODE_HASH) && (node->nd_brace & HASH_BRACE) != HASH_BRACE;
}
static int
compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
- const NODE *const root_node,
- struct rb_callinfo_kwarg **const kw_arg_ptr,
- unsigned int *flag)
+ const NODE *const root_node,
+ struct rb_callinfo_kwarg **const kw_arg_ptr,
+ unsigned int *flag)
{
- RUBY_ASSERT(nd_type_p(root_node, NODE_HASH));
- RUBY_ASSERT(kw_arg_ptr != NULL);
- RUBY_ASSERT(flag != NULL);
+ if (kw_arg_ptr == NULL) return FALSE;
- if (RNODE_HASH(root_node)->nd_head && nd_type_p(RNODE_HASH(root_node)->nd_head, NODE_LIST)) {
- const NODE *node = RNODE_HASH(root_node)->nd_head;
+ if (root_node->nd_head && nd_type_p(root_node->nd_head, NODE_LIST)) {
+ const NODE *node = root_node->nd_head;
int seen_nodes = 0;
while (node) {
- const NODE *key_node = RNODE_LIST(node)->nd_head;
+ const NODE *key_node = node->nd_head;
seen_nodes++;
- RUBY_ASSERT(nd_type_p(node, NODE_LIST));
- if (key_node && nd_type_p(key_node, NODE_SYM)) {
+ assert(nd_type_p(node, NODE_LIST));
+ if (key_node && nd_type_p(key_node, NODE_LIT) && SYMBOL_P(key_node->nd_lit)) {
/* can be keywords */
}
else {
if (flag) {
*flag |= VM_CALL_KW_SPLAT;
- if (seen_nodes > 1 || RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
+ if (seen_nodes > 1 || node->nd_next->nd_next) {
/* A new hash will be created for the keyword arguments
* in this case, so mark the method as passing mutable
* keyword splat.
@@ -4755,37 +4380,29 @@ compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
}
return FALSE;
}
- node = RNODE_LIST(node)->nd_next; /* skip value node */
- node = RNODE_LIST(node)->nd_next;
+ node = node->nd_next; /* skip value node */
+ node = node->nd_next;
}
/* may be keywords */
- node = RNODE_HASH(root_node)->nd_head;
+ node = root_node->nd_head;
{
- int len = 0;
- VALUE key_index = node_hash_unique_key_index(iseq, RNODE_HASH(root_node), &len);
+ int len = (int)node->nd_alen / 2;
struct rb_callinfo_kwarg *kw_arg =
rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
VALUE *keywords = kw_arg->keywords;
int i = 0;
- int j = 0;
- kw_arg->references = 0;
kw_arg->keyword_len = len;
*kw_arg_ptr = kw_arg;
- for (i=0; node != NULL; i++, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
- const NODE *key_node = RNODE_LIST(node)->nd_head;
- const NODE *val_node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
- int popped = TRUE;
- if (rb_ary_entry(key_index, i)) {
- keywords[j] = get_symbol_value(iseq, key_node);
- j++;
- popped = FALSE;
- }
- NO_CHECK(COMPILE_(ret, "keyword values", val_node, popped));
+ for (i=0; node != NULL; i++, node = node->nd_next->nd_next) {
+ const NODE *key_node = node->nd_head;
+ const NODE *val_node = node->nd_next->nd_head;
+ keywords[i] = key_node->nd_lit;
+ NO_CHECK(COMPILE(ret, "keyword values", val_node));
}
- RUBY_ASSERT(j == len);
+ assert(i == len);
return TRUE;
}
}
@@ -4793,52 +4410,43 @@ compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
}
static int
-compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, NODE **kwnode_ptr)
+compile_args(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node,
+ struct rb_callinfo_kwarg **keywords_ptr, unsigned int *flag)
{
int len = 0;
- for (; node; len++, node = RNODE_LIST(node)->nd_next) {
+ for (; node; len++, node = node->nd_next) {
if (CPDEBUG > 0) {
EXPECT_NODE("compile_args", node, NODE_LIST, -1);
}
- if (RNODE_LIST(node)->nd_next == NULL && keyword_node_p(RNODE_LIST(node)->nd_head)) { /* last node is kwnode */
- *kwnode_ptr = RNODE_LIST(node)->nd_head;
+ if (node->nd_next == NULL && keyword_node_p(node->nd_head)) { /* last node */
+ if (compile_keyword_arg(iseq, ret, node->nd_head, keywords_ptr, flag)) {
+ len--;
+ }
+ else {
+ compile_hash(iseq, ret, node->nd_head, TRUE, FALSE);
+ }
}
else {
- RUBY_ASSERT(!keyword_node_p(RNODE_LIST(node)->nd_head));
- NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, FALSE));
+ NO_CHECK(COMPILE_(ret, "array element", node->nd_head, FALSE));
}
}
return len;
}
-static inline bool
-frozen_string_literal_p(const rb_iseq_t *iseq)
-{
- return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal > 0;
-}
-
-static inline bool
-static_literal_node_p(const NODE *node, const rb_iseq_t *iseq, bool hash_key)
+static inline int
+static_literal_node_p(const NODE *node, const rb_iseq_t *iseq)
{
switch (nd_type(node)) {
- case NODE_SYM:
- case NODE_REGX:
- case NODE_LINE:
- case NODE_ENCODING:
- case NODE_INTEGER:
- case NODE_FLOAT:
- case NODE_RATIONAL:
- case NODE_IMAGINARY:
+ case NODE_LIT:
case NODE_NIL:
case NODE_TRUE:
case NODE_FALSE:
return TRUE;
case NODE_STR:
- case NODE_FILE:
- return hash_key || frozen_string_literal_p(iseq);
+ return ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal;
default:
return FALSE;
}
@@ -4848,46 +4456,30 @@ static inline VALUE
static_literal_value(const NODE *node, rb_iseq_t *iseq)
{
switch (nd_type(node)) {
- case NODE_INTEGER:
- return rb_node_integer_literal_val(node);
- case NODE_FLOAT:
- return rb_node_float_literal_val(node);
- case NODE_RATIONAL:
- return rb_node_rational_literal_val(node);
- case NODE_IMAGINARY:
- return rb_node_imaginary_literal_val(node);
case NODE_NIL:
return Qnil;
case NODE_TRUE:
return Qtrue;
case NODE_FALSE:
return Qfalse;
- case NODE_SYM:
- return rb_node_sym_string_val(node);
- case NODE_REGX:
- return rb_node_regx_string_val(node);
- case NODE_LINE:
- return rb_node_line_lineno_val(node);
- case NODE_ENCODING:
- return rb_node_encoding_val(node);
- case NODE_FILE:
case NODE_STR:
if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
+ VALUE lit;
VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX((int)nd_line(node)));
- VALUE lit = rb_str_dup(get_string_value(node));
- rb_ivar_set(lit, id_debug_created_info, rb_ary_freeze(debug_info));
+ lit = rb_str_dup(node->nd_lit);
+ rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
return rb_str_freeze(lit);
}
else {
- return get_string_value(node);
+ return rb_fstring(node->nd_lit);
}
default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
+ return node->nd_lit;
}
}
static int
-compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped, bool first_chunk)
+compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
{
const NODE *line_node = node;
@@ -4901,8 +4493,8 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop
EXPECT_NODE("compile_array", node, NODE_LIST, -1);
if (popped) {
- for (; node; node = RNODE_LIST(node)->nd_next) {
- NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, popped));
+ for (; node; node = node->nd_next) {
+ NO_CHECK(COMPILE_(ret, "array element", node->nd_head, popped));
}
return 1;
}
@@ -4922,8 +4514,8 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop
*
* [x1,x2,...,x10000] =>
* push x1 ; push x2 ; ...; push x256; newarray 256;
- * push x257; push x258; ...; push x512; pushtoarray 256;
- * push x513; push x514; ...; push x768; pushtoarray 256;
+ * push x257; push x258; ...; push x512; newarray 256; concatarray;
+ * push x513; push x514; ...; push x768; newarray 256; concatarray;
* ...
*
* - Long subarray can be optimized by pre-allocating a hidden array.
@@ -4933,38 +4525,38 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop
*
* [x, 1,2,3,...,100, z] =>
* push x; newarray 1;
- * putobject [1,2,3,...,100] (<- hidden array); concattoarray;
- * push z; pushtoarray 1;
+ * putobject [1,2,3,...,100] (<- hidden array); concatarray;
+ * push z; newarray 1; concatarray
*
- * - If the last element is a keyword, pushtoarraykwsplat should be emitted
- * to only push it onto the array if it is not empty
+ * - If the last element is a keyword, newarraykwsplat should be emitted
+ * to check and remove empty keyword arguments hash from array.
* (Note: a keyword is NODE_HASH which is not static_literal_node_p.)
*
* [1,2,3,**kw] =>
- * putobject 1; putobject 2; putobject 3; newarray 3; ...; pushtoarraykwsplat kw
+ * putobject 1; putobject 2; putobject 3; push kw; newarraykwsplat
*/
const int max_stack_len = 0x100;
const int min_tmp_ary_len = 0x40;
int stack_len = 0;
+ int first_chunk = 1;
- /* Either create a new array, or push to the existing array */
-#define FLUSH_CHUNK \
+ /* Convert pushed elements to an array, and concatarray if needed */
+#define FLUSH_CHUNK(newarrayinsn) \
if (stack_len) { \
- if (first_chunk) ADD_INSN1(ret, line_node, newarray, INT2FIX(stack_len)); \
- else ADD_INSN1(ret, line_node, pushtoarray, INT2FIX(stack_len)); \
- first_chunk = FALSE; \
- stack_len = 0; \
+ ADD_INSN1(ret, line_node, newarrayinsn, INT2FIX(stack_len)); \
+ if (!first_chunk) ADD_INSN(ret, line_node, concatarray); \
+ first_chunk = stack_len = 0; \
}
while (node) {
int count = 1;
/* pre-allocation check (this branch can be omittable) */
- if (static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, false)) {
+ if (static_literal_node_p(node->nd_head, iseq)) {
/* count the elements that are optimizable */
- const NODE *node_tmp = RNODE_LIST(node)->nd_next;
- for (; node_tmp && static_literal_node_p(RNODE_LIST(node_tmp)->nd_head, iseq, false); node_tmp = RNODE_LIST(node_tmp)->nd_next)
+ const NODE *node_tmp = node->nd_next;
+ for (; node_tmp && static_literal_node_p(node_tmp->nd_head, iseq); node_tmp = node_tmp->nd_next)
count++;
if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) {
@@ -4972,61 +4564,77 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop
VALUE ary = rb_ary_hidden_new(count);
/* Create a hidden array */
- for (; count; count--, node = RNODE_LIST(node)->nd_next)
- rb_ary_push(ary, static_literal_value(RNODE_LIST(node)->nd_head, iseq));
+ for (; count; count--, node = node->nd_next)
+ rb_ary_push(ary, static_literal_value(node->nd_head, iseq));
OBJ_FREEZE(ary);
/* Emit optimized code */
- FLUSH_CHUNK;
+ FLUSH_CHUNK(newarray);
if (first_chunk) {
ADD_INSN1(ret, line_node, duparray, ary);
- first_chunk = FALSE;
+ first_chunk = 0;
}
else {
ADD_INSN1(ret, line_node, putobject, ary);
- ADD_INSN(ret, line_node, concattoarray);
+ ADD_INSN(ret, line_node, concatarray);
}
RB_OBJ_WRITTEN(iseq, Qundef, ary);
}
}
/* Base case: Compile "count" elements */
- for (; count; count--, node = RNODE_LIST(node)->nd_next) {
+ for (; count; count--, node = node->nd_next) {
if (CPDEBUG > 0) {
EXPECT_NODE("compile_array", node, NODE_LIST, -1);
}
- if (!RNODE_LIST(node)->nd_next && keyword_node_p(RNODE_LIST(node)->nd_head)) {
- /* Create array or push existing non-keyword elements onto array */
- if (stack_len == 0 && first_chunk) {
- ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
- }
- else {
- FLUSH_CHUNK;
- }
- NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
- ADD_INSN(ret, line_node, pushtoarraykwsplat);
+ NO_CHECK(COMPILE_(ret, "array element", node->nd_head, 0));
+ stack_len++;
+
+ if (!node->nd_next && keyword_node_p(node->nd_head)) {
+ /* Reached the end, and the last element is a keyword */
+ FLUSH_CHUNK(newarraykwsplat);
return 1;
}
- else {
- NO_CHECK(COMPILE_(ret, "array element", RNODE_LIST(node)->nd_head, 0));
- stack_len++;
- }
/* If there are many pushed elements, flush them to avoid stack overflow */
- if (stack_len >= max_stack_len) FLUSH_CHUNK;
+ if (stack_len >= max_stack_len) FLUSH_CHUNK(newarray);
}
}
- FLUSH_CHUNK;
+ FLUSH_CHUNK(newarray);
#undef FLUSH_CHUNK
return 1;
}
+/* Compile an array containing the single element represented by node */
+static int
+compile_array_1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node)
+{
+ if (static_literal_node_p(node, iseq)) {
+ VALUE ary = rb_ary_hidden_new(1);
+ rb_ary_push(ary, static_literal_value(node, iseq));
+ OBJ_FREEZE(ary);
+
+ ADD_INSN1(ret, node, duparray, ary);
+ }
+ else {
+ CHECK(COMPILE_(ret, "array element", node, FALSE));
+ if (keyword_node_p(node)) {
+ ADD_INSN1(ret, node, newarraykwsplat, INT2FIX(1));
+ }
+ else {
+ ADD_INSN1(ret, node, newarray, INT2FIX(1));
+ }
+ }
+
+ return 1;
+}
+
static inline int
static_literal_node_pair_p(const NODE *node, const rb_iseq_t *iseq)
{
- return RNODE_LIST(node)->nd_head && static_literal_node_p(RNODE_LIST(node)->nd_head, iseq, true) && static_literal_node_p(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq, false);
+ return node->nd_head && static_literal_node_p(node->nd_head, iseq) && static_literal_node_p(node->nd_next->nd_head, iseq);
}
static int
@@ -5034,7 +4642,7 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
{
const NODE *line_node = node;
- node = RNODE_HASH(node)->nd_head;
+ node = node->nd_head;
if (!node || nd_type_p(node, NODE_ZLIST)) {
if (!popped) {
@@ -5046,8 +4654,8 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
if (popped) {
- for (; node; node = RNODE_LIST(node)->nd_next) {
- NO_CHECK(COMPILE_(ret, "hash element", RNODE_LIST(node)->nd_head, popped));
+ for (; node; node = node->nd_next) {
+ NO_CHECK(COMPILE_(ret, "hash element", node->nd_head, popped));
}
return 1;
}
@@ -5100,8 +4708,8 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
/* pre-allocation check (this branch can be omittable) */
if (static_literal_node_pair_p(node, iseq)) {
/* count the elements that are optimizable */
- const NODE *node_tmp = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next;
- for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = RNODE_LIST(RNODE_LIST(node_tmp)->nd_next)->nd_next)
+ const NODE *node_tmp = node->nd_next->nd_next;
+ for (; node_tmp && static_literal_node_pair_p(node_tmp, iseq); node_tmp = node_tmp->nd_next->nd_next)
count++;
if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) {
@@ -5109,14 +4717,14 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
VALUE ary = rb_ary_hidden_new(count);
/* Create a hidden hash */
- for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
+ for (; count; count--, node = node->nd_next->nd_next) {
VALUE elem[2];
- elem[0] = static_literal_value(RNODE_LIST(node)->nd_head, iseq);
- elem[1] = static_literal_value(RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, iseq);
+ elem[0] = static_literal_value(node->nd_head, iseq);
+ elem[1] = static_literal_value(node->nd_next->nd_head, iseq);
rb_ary_cat(ary, elem, 2);
}
VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
- rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
+ rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR_TRANSIENT(ary), hash);
hash = rb_obj_hide(hash);
OBJ_FREEZE(hash);
@@ -5139,16 +4747,16 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
}
/* Base case: Compile "count" elements */
- for (; count; count--, node = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next) {
+ for (; count; count--, node = node->nd_next->nd_next) {
if (CPDEBUG > 0) {
EXPECT_NODE("compile_hash", node, NODE_LIST, -1);
}
- if (RNODE_LIST(node)->nd_head) {
+ if (node->nd_head) {
/* Normal key-value pair */
- NO_CHECK(COMPILE_(anchor, "hash key element", RNODE_LIST(node)->nd_head, 0));
- NO_CHECK(COMPILE_(anchor, "hash value element", RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head, 0));
+ NO_CHECK(COMPILE_(anchor, "hash key element", node->nd_head, 0));
+ NO_CHECK(COMPILE_(anchor, "hash value element", node->nd_next->nd_head, 0));
stack_len += 2;
/* If there are many pushed elements, flush them to avoid stack overflow */
@@ -5158,13 +4766,12 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth
/* kwsplat case: foo(..., **kw, ...) */
FLUSH_CHUNK();
- const NODE *kw = RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_head;
- int empty_kw = nd_type_p(kw, NODE_HASH) && (!RNODE_HASH(kw)->nd_head); /* foo( ..., **{}, ...) */
+ const NODE *kw = node->nd_next->nd_head;
+ int empty_kw = nd_type_p(kw, NODE_LIT) && RB_TYPE_P(kw->nd_lit, T_HASH); /* foo( ..., **{}, ...) */
int first_kw = first_chunk && stack_len == 0; /* foo(1,2,3, **kw, ...) */
- int last_kw = !RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next; /* foo( ..., **kw) */
+ int last_kw = !node->nd_next->nd_next; /* foo( ..., **kw) */
int only_kw = last_kw && first_kw; /* foo(1,2,3, **kw) */
- empty_kw = empty_kw || nd_type_p(kw, NODE_NIL); /* foo( ..., **nil, ...) */
if (empty_kw) {
if (only_kw && method_call_keywords) {
/* **{} appears at the only keyword argument in method call,
@@ -5224,34 +4831,29 @@ VALUE
rb_node_case_when_optimizable_literal(const NODE *const node)
{
switch (nd_type(node)) {
- case NODE_INTEGER:
- return rb_node_integer_literal_val(node);
- case NODE_FLOAT: {
- VALUE v = rb_node_float_literal_val(node);
+ case NODE_LIT: {
+ VALUE v = node->nd_lit;
double ival;
-
- if (modf(RFLOAT_VALUE(v), &ival) == 0.0) {
+ if (RB_FLOAT_TYPE_P(v) &&
+ modf(RFLOAT_VALUE(v), &ival) == 0.0) {
return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
}
- return v;
+ if (RB_TYPE_P(v, T_RATIONAL) || RB_TYPE_P(v, T_COMPLEX)) {
+ return Qundef;
+ }
+ if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) {
+ return v;
+ }
+ break;
}
- case NODE_RATIONAL:
- case NODE_IMAGINARY:
- return Qundef;
case NODE_NIL:
return Qnil;
case NODE_TRUE:
return Qtrue;
case NODE_FALSE:
return Qfalse;
- case NODE_SYM:
- return rb_node_sym_string_val(node);
- case NODE_LINE:
- return rb_node_line_lineno_val(node);
case NODE_STR:
- return rb_node_str_string_val(node);
- case NODE_FILE:
- return rb_node_file_path_val(node);
+ return rb_fstring(node->nd_lit);
}
return Qundef;
}
@@ -5261,7 +4863,7 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
LABEL *l1, int only_special_literals, VALUE literals)
{
while (vals) {
- const NODE *val = RNODE_LIST(vals)->nd_head;
+ const NODE *val = vals->nd_head;
VALUE lit = rb_node_case_when_optimizable_literal(val);
if (UNDEF_P(lit)) {
@@ -5271,9 +4873,9 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
rb_hash_aset(literals, lit, (VALUE)(l1) | 1);
}
- if (nd_type_p(val, NODE_STR) || nd_type_p(val, NODE_FILE)) {
- debugp_param("nd_lit", get_string_value(val));
- lit = get_string_value(val);
+ if (nd_type_p(val, NODE_STR)) {
+ debugp_param("nd_lit", val->nd_lit);
+ lit = rb_fstring(val->nd_lit);
ADD_INSN1(cond_seq, val, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
}
@@ -5281,11 +4883,11 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
if (!COMPILE(cond_seq, "when cond", val)) return -1;
}
- // Emit pattern === target
+ // Emit patern === target
ADD_INSN1(cond_seq, vals, topn, INT2FIX(1));
ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1));
ADD_INSNL(cond_seq, val, branchif, l1);
- vals = RNODE_LIST(vals)->nd_next;
+ vals = vals->nd_next;
}
return only_special_literals;
}
@@ -5303,19 +4905,19 @@ when_splat_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals,
break;
case NODE_SPLAT:
ADD_INSN (cond_seq, line_node, dup);
- CHECK(COMPILE(cond_seq, "when splat", RNODE_SPLAT(vals)->nd_head));
+ CHECK(COMPILE(cond_seq, "when splat", vals->nd_head));
ADD_INSN1(cond_seq, line_node, splatarray, Qfalse);
ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
ADD_INSNL(cond_seq, line_node, branchif, l1);
break;
case NODE_ARGSCAT:
- CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_head, l1, only_special_literals, literals));
- CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSCAT(vals)->nd_body, l1, only_special_literals, literals));
+ CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
+ CHECK(when_splat_vals(iseq, cond_seq, vals->nd_body, l1, only_special_literals, literals));
break;
case NODE_ARGSPUSH:
- CHECK(when_splat_vals(iseq, cond_seq, RNODE_ARGSPUSH(vals)->nd_head, l1, only_special_literals, literals));
+ CHECK(when_splat_vals(iseq, cond_seq, vals->nd_head, l1, only_special_literals, literals));
ADD_INSN (cond_seq, line_node, dup);
- CHECK(COMPILE(cond_seq, "when argspush body", RNODE_ARGSPUSH(vals)->nd_body));
+ CHECK(COMPILE(cond_seq, "when argspush body", vals->nd_body));
ADD_INSN1(cond_seq, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
ADD_INSNL(cond_seq, line_node, branchif, l1);
break;
@@ -5508,35 +5110,11 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const
for (lhs->last = &iobj->link; lhs->last->next; lhs->last = lhs->last->next);
if (vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT) {
int argc = vm_ci_argc(ci);
- bool dupsplat = false;
ci = ci_argc_set(iseq, ci, argc - 1);
- if (!(vm_ci_flag(ci) & VM_CALL_ARGS_SPLAT_MUT)) {
- /* Given h[*a], _ = ary
- * setup_args sets VM_CALL_ARGS_SPLAT and not VM_CALL_ARGS_SPLAT_MUT
- * `a` must be dupped, because it will be appended with ary[0]
- * Since you are dupping `a`, you can set VM_CALL_ARGS_SPLAT_MUT
- */
- dupsplat = true;
- ci = ci_flag_set(iseq, ci, VM_CALL_ARGS_SPLAT_MUT);
- }
OPERAND_AT(iobj, 0) = (VALUE)ci;
RB_OBJ_WRITTEN(iseq, Qundef, iobj);
-
- /* Given: h[*a], h[*b, 1] = ary
- * h[*a] uses splatarray false and does not set VM_CALL_ARGS_SPLAT_MUT,
- * so this uses splatarray true on a to dup it before using pushtoarray
- * h[*b, 1] uses splatarray true and sets VM_CALL_ARGS_SPLAT_MUT,
- * so you can use pushtoarray directly
- */
- int line_no = nd_line(line_node);
- int node_id = nd_node_id(line_node);
-
- if (dupsplat) {
- INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
- INSERT_BEFORE_INSN1(iobj, line_no, node_id, splatarray, Qtrue);
- INSERT_BEFORE_INSN(iobj, line_no, node_id, swap);
- }
- INSERT_BEFORE_INSN1(iobj, line_no, node_id, pushtoarray, INT2FIX(1));
+ INSERT_BEFORE_INSN1(iobj, line_node, newarray, INT2FIX(1));
+ INSERT_BEFORE_INSN(iobj, line_node, concatarray);
}
if (!safenav_call) {
ADD_INSN(lhs, line_node, pop);
@@ -5568,7 +5146,7 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const
break;
}
case NODE_CDECL:
- if (!RNODE_CDECL(node)->nd_vid) {
+ if (!node->nd_vid) {
/* Special handling only needed for expr::C, not for C */
INSN *iobj;
@@ -5606,8 +5184,8 @@ static int
compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *lhsn)
{
if (lhsn) {
- CHECK(compile_massign_opt_lhs(iseq, ret, RNODE_LIST(lhsn)->nd_next));
- CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, RNODE_LIST(lhsn)->nd_head, NULL, 0));
+ CHECK(compile_massign_opt_lhs(iseq, ret, lhsn->nd_next));
+ CHECK(compile_massign_lhs(iseq, ret, ret, ret, ret, lhsn->nd_head, NULL, 0));
}
return COMPILE_OK;
}
@@ -5637,29 +5215,31 @@ compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
}
while (lhsn) {
- const NODE *ln = RNODE_LIST(lhsn)->nd_head;
+ const NODE *ln = lhsn->nd_head;
switch (nd_type(ln)) {
case NODE_LASGN:
+ MEMORY(ln->nd_vid);
+ break;
case NODE_DASGN:
case NODE_IASGN:
case NODE_CVASGN:
- MEMORY(get_nd_vid(ln));
+ MEMORY(ln->nd_vid);
break;
default:
return 0;
}
- lhsn = RNODE_LIST(lhsn)->nd_next;
+ lhsn = lhsn->nd_next;
llen++;
}
while (rhsn) {
if (llen <= rlen) {
- NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", RNODE_LIST(rhsn)->nd_head));
+ NO_CHECK(COMPILE_POPPED(ret, "masgn val (popped)", rhsn->nd_head));
}
else {
- NO_CHECK(COMPILE(ret, "masgn val", RNODE_LIST(rhsn)->nd_head));
+ NO_CHECK(COMPILE(ret, "masgn val", rhsn->nd_head));
}
- rhsn = RNODE_LIST(rhsn)->nd_next;
+ rhsn = rhsn->nd_next;
rlen++;
}
@@ -5676,31 +5256,32 @@ compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
static int
compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs, LINK_ANCHOR *const lhs, LINK_ANCHOR *const post, const NODE *const node, struct masgn_state *state, int popped)
{
- const NODE *rhsn = RNODE_MASGN(node)->nd_value;
- const NODE *splatn = RNODE_MASGN(node)->nd_args;
- const NODE *lhsn = RNODE_MASGN(node)->nd_head;
+ const NODE *rhsn = node->nd_value;
+ const NODE *splatn = node->nd_args;
+ const NODE *lhsn = node->nd_head;
const NODE *lhsn_count = lhsn;
int lhs_splat = (splatn && NODE_NAMED_REST_P(splatn)) ? 1 : 0;
int llen = 0;
int lpos = 0;
+ int expand = 1;
while (lhsn_count) {
llen++;
- lhsn_count = RNODE_LIST(lhsn_count)->nd_next;
+ lhsn_count = lhsn_count->nd_next;
}
while (lhsn) {
- CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(lhsn)->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
+ CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, lhsn->nd_head, state, (llen - lpos) + lhs_splat + state->lhs_level));
lpos++;
- lhsn = RNODE_LIST(lhsn)->nd_next;
+ lhsn = lhsn->nd_next;
}
if (lhs_splat) {
if (nd_type_p(splatn, NODE_POSTARG)) {
/*a, b, *r, p1, p2 */
- const NODE *postn = RNODE_POSTARG(splatn)->nd_2nd;
- const NODE *restn = RNODE_POSTARG(splatn)->nd_1st;
- int plen = (int)RNODE_LIST(postn)->as.nd_alen;
+ const NODE *postn = splatn->nd_2nd;
+ const NODE *restn = splatn->nd_1st;
+ int plen = (int)postn->nd_alen;
int ppos = 0;
int flag = 0x02 | (NODE_NAMED_REST_P(restn) ? 0x01 : 0x00);
@@ -5710,9 +5291,9 @@ compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs
CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, restn, state, 1 + plen + state->lhs_level));
}
while (postn) {
- CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, RNODE_LIST(postn)->nd_head, state, (plen - ppos) + state->lhs_level));
+ CHECK(compile_massign_lhs(iseq, pre, rhs, lhs, post, postn->nd_head, state, (plen - ppos) + state->lhs_level));
ppos++;
- postn = RNODE_LIST(postn)->nd_next;
+ postn = postn->nd_next;
}
}
else {
@@ -5721,6 +5302,7 @@ compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs
}
}
+
if (!state->nested) {
NO_CHECK(COMPILE(rhs, "normal masgn rhs", rhsn));
}
@@ -5728,14 +5310,16 @@ compile_massign0(rb_iseq_t *iseq, LINK_ANCHOR *const pre, LINK_ANCHOR *const rhs
if (!popped) {
ADD_INSN(rhs, node, dup);
}
- ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
+ if (expand) {
+ ADD_INSN2(rhs, node, expandarray, INT2FIX(llen), INT2FIX(lhs_splat));
+ }
return COMPILE_OK;
}
static int
compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
{
- if (!popped || RNODE_MASGN(node)->nd_args || !compile_massign_opt(iseq, ret, RNODE_MASGN(node)->nd_value, RNODE_MASGN(node)->nd_head)) {
+ if (!popped || node->nd_args || !compile_massign_opt(iseq, ret, node->nd_value, node->nd_head)) {
struct masgn_state state;
state.lhs_level = popped ? 0 : 1;
state.nested = 0;
@@ -5757,7 +5341,7 @@ compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
while (memo) {
VALUE topn_arg = INT2FIX((state.num_args - memo->argn) + memo->lhs_pos);
for (int i = 0; i < memo->num_args; i++) {
- INSERT_BEFORE_INSN1(memo->before_insn, nd_line(memo->line_node), nd_node_id(memo->line_node), topn, topn_arg);
+ INSERT_BEFORE_INSN1(memo->before_insn, memo->line_node, topn, topn_arg);
}
tmp_memo = memo->next;
free(memo);
@@ -5784,15 +5368,15 @@ collect_const_segments(rb_iseq_t *iseq, const NODE *node)
for (;;) {
switch (nd_type(node)) {
case NODE_CONST:
- rb_ary_unshift(arr, ID2SYM(RNODE_CONST(node)->nd_vid));
+ rb_ary_unshift(arr, ID2SYM(node->nd_vid));
return arr;
case NODE_COLON3:
- rb_ary_unshift(arr, ID2SYM(RNODE_COLON3(node)->nd_mid));
+ rb_ary_unshift(arr, ID2SYM(node->nd_mid));
rb_ary_unshift(arr, ID2SYM(idNULL));
return arr;
case NODE_COLON2:
- rb_ary_unshift(arr, ID2SYM(RNODE_COLON2(node)->nd_mid));
- node = RNODE_COLON2(node)->nd_head;
+ rb_ary_unshift(arr, ID2SYM(node->nd_mid));
+ node = node->nd_head;
break;
default:
return Qfalse;
@@ -5806,22 +5390,22 @@ compile_const_prefix(rb_iseq_t *iseq, const NODE *const node,
{
switch (nd_type(node)) {
case NODE_CONST:
- debugi("compile_const_prefix - colon", RNODE_CONST(node)->nd_vid);
+ debugi("compile_const_prefix - colon", node->nd_vid);
ADD_INSN1(body, node, putobject, Qtrue);
- ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
+ ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_vid));
break;
case NODE_COLON3:
- debugi("compile_const_prefix - colon3", RNODE_COLON3(node)->nd_mid);
+ debugi("compile_const_prefix - colon3", node->nd_mid);
ADD_INSN(body, node, pop);
ADD_INSN1(body, node, putobject, rb_cObject);
ADD_INSN1(body, node, putobject, Qtrue);
- ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
+ ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_mid));
break;
case NODE_COLON2:
- CHECK(compile_const_prefix(iseq, RNODE_COLON2(node)->nd_head, pref, body));
- debugi("compile_const_prefix - colon2", RNODE_COLON2(node)->nd_mid);
+ CHECK(compile_const_prefix(iseq, node->nd_head, pref, body));
+ debugi("compile_const_prefix - colon2", node->nd_mid);
ADD_INSN1(body, node, putobject, Qfalse);
- ADD_INSN1(body, node, getconstant, ID2SYM(RNODE_COLON2(node)->nd_mid));
+ ADD_INSN1(body, node, getconstant, ID2SYM(node->nd_mid));
break;
default:
CHECK(COMPILE(pref, "const colon2 prefix", node));
@@ -5838,9 +5422,9 @@ compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
ADD_INSN1(ret, cpath, putobject, rb_cObject);
return VM_DEFINECLASS_FLAG_SCOPED;
}
- else if (nd_type_p(cpath, NODE_COLON2) && RNODE_COLON2(cpath)->nd_head) {
+ else if (cpath->nd_head) {
/* Bar::Foo */
- NO_CHECK(COMPILE(ret, "nd_else->nd_head", RNODE_COLON2(cpath)->nd_head));
+ NO_CHECK(COMPILE(ret, "nd_else->nd_head", cpath->nd_head));
return VM_DEFINECLASS_FLAG_SCOPED;
}
else {
@@ -5854,16 +5438,16 @@ compile_cpath(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const NODE *cpath)
static inline int
private_recv_p(const NODE *node)
{
- NODE *recv = get_nd_recv(node);
- if (recv && nd_type_p(recv, NODE_SELF)) {
- return RNODE_SELF(recv)->nd_state != 0;
+ if (nd_type_p(node->nd_recv, NODE_SELF)) {
+ NODE *self = node->nd_recv;
+ return self->nd_state != 0;
}
return 0;
}
static void
defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
- const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore);
+ const NODE *const node, LABEL **lfinish, VALUE needstr);
static int
compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const enum node_type type, const NODE *const line_node, int popped, bool assume_receiver);
@@ -5894,34 +5478,21 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
expr_type = DEFINED_FALSE;
break;
- case NODE_HASH:
case NODE_LIST:{
- const NODE *vals = (nd_type(node) == NODE_HASH) ? RNODE_HASH(node)->nd_head : node;
+ const NODE *vals = node;
- if (vals) {
- do {
- if (RNODE_LIST(vals)->nd_head) {
- defined_expr0(iseq, ret, RNODE_LIST(vals)->nd_head, lfinish, Qfalse, false);
+ do {
+ defined_expr0(iseq, ret, vals->nd_head, lfinish, Qfalse, false);
- if (!lfinish[1]) {
- lfinish[1] = NEW_LABEL(line);
- }
- ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
- }
- } while ((vals = RNODE_LIST(vals)->nd_next) != NULL);
- }
+ if (!lfinish[1]) {
+ lfinish[1] = NEW_LABEL(line);
+ }
+ ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
+ } while ((vals = vals->nd_next) != NULL);
}
/* fall through */
case NODE_STR:
- case NODE_SYM:
- case NODE_REGX:
- case NODE_LINE:
- case NODE_FILE:
- case NODE_ENCODING:
- case NODE_INTEGER:
- case NODE_FLOAT:
- case NODE_RATIONAL:
- case NODE_IMAGINARY:
+ case NODE_LIT:
case NODE_ZLIST:
case NODE_AND:
case NODE_OR:
@@ -5929,15 +5500,6 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
expr_type = DEFINED_EXPR;
break;
- case NODE_SPLAT:
- defined_expr0(iseq, ret, RNODE_LIST(node)->nd_head, lfinish, Qfalse, false);
- if (!lfinish[1]) {
- lfinish[1] = NEW_LABEL(line);
- }
- ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
- expr_type = DEFINED_EXPR;
- break;
-
/* variables */
case NODE_LVAR:
case NODE_DVAR:
@@ -5946,48 +5508,49 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
#define PUSH_VAL(type) (needstr == Qfalse ? Qtrue : rb_iseq_defined_string(type))
case NODE_IVAR:
- ADD_INSN3(ret, line_node, definedivar,
- ID2SYM(RNODE_IVAR(node)->nd_vid), get_ivar_ic_value(iseq,RNODE_IVAR(node)->nd_vid), PUSH_VAL(DEFINED_IVAR));
+ ADD_INSN(ret, line_node, putnil);
+ ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_IVAR),
+ ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_IVAR));
return;
case NODE_GVAR:
ADD_INSN(ret, line_node, putnil);
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_GVAR),
- ID2SYM(RNODE_GVAR(node)->nd_vid), PUSH_VAL(DEFINED_GVAR));
+ ID2SYM(node->nd_entry), PUSH_VAL(DEFINED_GVAR));
return;
case NODE_CVAR:
ADD_INSN(ret, line_node, putnil);
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CVAR),
- ID2SYM(RNODE_CVAR(node)->nd_vid), PUSH_VAL(DEFINED_CVAR));
+ ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_CVAR));
return;
case NODE_CONST:
ADD_INSN(ret, line_node, putnil);
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST),
- ID2SYM(RNODE_CONST(node)->nd_vid), PUSH_VAL(DEFINED_CONST));
+ ID2SYM(node->nd_vid), PUSH_VAL(DEFINED_CONST));
return;
case NODE_COLON2:
if (!lfinish[1]) {
lfinish[1] = NEW_LABEL(line);
}
- defined_expr0(iseq, ret, RNODE_COLON2(node)->nd_head, lfinish, Qfalse, false);
+ defined_expr0(iseq, ret, node->nd_head, lfinish, Qfalse, false);
ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
- NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", RNODE_COLON2(node)->nd_head));
+ NO_CHECK(COMPILE(ret, "defined/colon2#nd_head", node->nd_head));
- if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
+ if (rb_is_const_id(node->nd_mid)) {
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
- ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
+ ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_CONST));
}
else {
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
- ID2SYM(RNODE_COLON2(node)->nd_mid), PUSH_VAL(DEFINED_METHOD));
+ ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
}
return;
case NODE_COLON3:
ADD_INSN1(ret, line_node, putobject, rb_cObject);
ADD_INSN3(ret, line_node, defined,
- INT2FIX(DEFINED_CONST_FROM), ID2SYM(RNODE_COLON3(node)->nd_mid), PUSH_VAL(DEFINED_CONST));
+ INT2FIX(DEFINED_CONST_FROM), ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_CONST));
return;
/* method dispatch */
@@ -6000,7 +5563,7 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
(type == NODE_CALL || type == NODE_OPCALL ||
(type == NODE_ATTRASGN && !private_recv_p(node)));
- if (get_nd_args(node) || explicit_receiver) {
+ if (node->nd_args || explicit_receiver) {
if (!lfinish[1]) {
lfinish[1] = NEW_LABEL(line);
}
@@ -6008,31 +5571,31 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
lfinish[2] = NEW_LABEL(line);
}
}
- if (get_nd_args(node)) {
- defined_expr0(iseq, ret, get_nd_args(node), lfinish, Qfalse, false);
+ if (node->nd_args) {
+ defined_expr0(iseq, ret, node->nd_args, lfinish, Qfalse, false);
ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
}
if (explicit_receiver) {
- defined_expr0(iseq, ret, get_nd_recv(node), lfinish, Qfalse, true);
- switch (nd_type(get_nd_recv(node))) {
+ defined_expr0(iseq, ret, node->nd_recv, lfinish, Qfalse, true);
+ switch (nd_type(node->nd_recv)) {
case NODE_CALL:
case NODE_OPCALL:
case NODE_VCALL:
case NODE_FCALL:
case NODE_ATTRASGN:
ADD_INSNL(ret, line_node, branchunless, lfinish[2]);
- compile_call(iseq, ret, get_nd_recv(node), nd_type(get_nd_recv(node)), line_node, 0, true);
+ compile_call(iseq, ret, node->nd_recv, nd_type(node->nd_recv), line_node, 0, true);
break;
default:
ADD_INSNL(ret, line_node, branchunless, lfinish[1]);
- NO_CHECK(COMPILE(ret, "defined/recv", get_nd_recv(node)));
+ NO_CHECK(COMPILE(ret, "defined/recv", node->nd_recv));
break;
}
if (keep_result) {
ADD_INSN(ret, line_node, dup);
}
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_METHOD),
- ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
+ ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
}
else {
ADD_INSN(ret, line_node, putself);
@@ -6040,7 +5603,7 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
ADD_INSN(ret, line_node, dup);
}
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_FUNC),
- ID2SYM(get_node_call_nd_mid(node)), PUSH_VAL(DEFINED_METHOD));
+ ID2SYM(node->nd_mid), PUSH_VAL(DEFINED_METHOD));
}
return;
}
@@ -6049,14 +5612,13 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
ADD_INSN(ret, line_node, putnil);
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_YIELD), 0,
PUSH_VAL(DEFINED_YIELD));
- iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
return;
case NODE_BACK_REF:
case NODE_NTH_REF:
ADD_INSN(ret, line_node, putnil);
ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_REF),
- INT2FIX((RNODE_BACK_REF(node)->nd_nth << 1) | (type == NODE_BACK_REF)),
+ INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)),
PUSH_VAL(DEFINED_GVAR));
return;
@@ -6079,12 +5641,11 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
case NODE_IASGN:
case NODE_CDECL:
case NODE_CVASGN:
- case NODE_OP_CDECL:
expr_type = DEFINED_ASGN;
break;
}
- RUBY_ASSERT(expr_type != DEFINED_NOT_DEFINED);
+ assert(expr_type != DEFINED_NOT_DEFINED);
if (needstr != Qfalse) {
VALUE str = rb_iseq_defined_string(expr_type);
@@ -6098,13 +5659,14 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
static void
build_defined_rescue_iseq(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const void *unused)
{
- ADD_SYNTHETIC_INSN(ret, 0, -1, putnil);
+ NODE dummy_line_node = generate_dummy_line_node(0, -1);
+ ADD_INSN(ret, &dummy_line_node, putnil);
iseq_set_exception_local_table(iseq);
}
static void
defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
- const NODE *const node, LABEL **lfinish, VALUE needstr, bool ignore)
+ const NODE *const node, LABEL **lfinish, VALUE needstr)
{
LINK_ELEMENT *lcur = ret->last;
defined_expr0(iseq, ret, node, lfinish, needstr, false);
@@ -6123,18 +5685,16 @@ defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
lend->rescued = LABEL_RESCUE_END;
APPEND_LABEL(ret, lcur, lstart);
ADD_LABEL(ret, lend);
- if (!ignore) {
- ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
- }
+ ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
}
}
static int
-compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr, bool ignore)
+compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE needstr)
{
const int line = nd_line(node);
const NODE *line_node = node;
- if (!RNODE_DEFINED(node)->nd_head) {
+ if (!node->nd_head) {
VALUE str = rb_iseq_defined_string(DEFINED_NIL);
ADD_INSN1(ret, line_node, putobject, str);
}
@@ -6144,9 +5704,9 @@ compile_defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const
lfinish[0] = NEW_LABEL(line);
lfinish[1] = 0;
lfinish[2] = 0;
- defined_expr(iseq, ret, RNODE_DEFINED(node)->nd_head, lfinish, needstr, ignore);
+ defined_expr(iseq, ret, node->nd_head, lfinish, needstr);
if (lfinish[1]) {
- ELEM_INSERT_NEXT(last, &new_insn_body(iseq, nd_line(line_node), nd_node_id(line_node), BIN(putnil), 0)->link);
+ ELEM_INSERT_NEXT(last, &new_insn_body(iseq, line_node, BIN(putnil), 0)->link);
ADD_INSN(ret, line_node, swap);
if (lfinish[2]) {
ADD_LABEL(ret, lfinish[2]);
@@ -6185,7 +5745,7 @@ make_name_for_block(const rb_iseq_t *orig_iseq)
static void
push_ensure_entry(rb_iseq_t *iseq,
struct iseq_compile_data_ensure_node_stack *enl,
- struct ensure_range *er, const void *const node)
+ struct ensure_range *er, const NODE *const node)
{
enl->ensure_node = node;
enl->prev = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack; /* prev */
@@ -6227,7 +5787,7 @@ can_add_ensure_iseq(const rb_iseq_t *iseq)
static void
add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
{
- RUBY_ASSERT(can_add_ensure_iseq(iseq));
+ assert(can_add_ensure_iseq(iseq));
struct iseq_compile_data_ensure_node_stack *enlp =
ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
@@ -6261,205 +5821,79 @@ add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return)
ADD_SEQ(ret, ensure);
}
-#if RUBY_DEBUG
static int
check_keyword(const NODE *node)
{
/* This check is essentially a code clone of compile_keyword_arg. */
if (nd_type_p(node, NODE_LIST)) {
- while (RNODE_LIST(node)->nd_next) {
- node = RNODE_LIST(node)->nd_next;
+ while (node->nd_next) {
+ node = node->nd_next;
}
- node = RNODE_LIST(node)->nd_head;
+ node = node->nd_head;
}
return keyword_node_p(node);
}
-#endif
-static bool
-keyword_node_single_splat_p(NODE *kwnode)
-{
- RUBY_ASSERT(keyword_node_p(kwnode));
-
- NODE *node = RNODE_HASH(kwnode)->nd_head;
- return RNODE_LIST(node)->nd_head == NULL &&
- RNODE_LIST(RNODE_LIST(node)->nd_next)->nd_next == NULL;
-}
-
-static void
-compile_single_keyword_splat_mutable(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
- NODE *kwnode, unsigned int *flag_ptr)
-{
- *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
- ADD_INSN1(args, argn, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(args, argn, newhash, INT2FIX(0));
- compile_hash(iseq, args, kwnode, TRUE, FALSE);
- ADD_SEND(args, argn, id_core_hash_merge_kwd, INT2FIX(2));
-}
-
-#define SPLATARRAY_FALSE 0
-#define SPLATARRAY_TRUE 1
-#define DUP_SINGLE_KW_SPLAT 2
-
-static int
+static VALUE
setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
- unsigned int *dup_rest, unsigned int *flag_ptr, struct rb_callinfo_kwarg **kwarg_ptr)
+ int dup_rest, unsigned int *flag, struct rb_callinfo_kwarg **keywords)
{
- if (!argn) return 0;
-
- NODE *kwnode = NULL;
-
- switch (nd_type(argn)) {
- case NODE_LIST: {
- // f(x, y, z)
- int len = compile_args(iseq, args, argn, &kwnode);
- RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_ARGS_SPLAT) == 0);
-
- if (kwnode) {
- if (compile_keyword_arg(iseq, args, kwnode, kwarg_ptr, flag_ptr)) {
- len -= 1;
+ if (argn) {
+ switch (nd_type(argn)) {
+ case NODE_SPLAT: {
+ NO_CHECK(COMPILE(args, "args (splat)", argn->nd_head));
+ ADD_INSN1(args, argn, splatarray, RBOOL(dup_rest));
+ if (flag) *flag |= VM_CALL_ARGS_SPLAT;
+ return INT2FIX(1);
+ }
+ case NODE_ARGSCAT:
+ case NODE_ARGSPUSH: {
+ int next_is_list = (nd_type_p(argn->nd_head, NODE_LIST));
+ VALUE argc = setup_args_core(iseq, args, argn->nd_head, 1, NULL, NULL);
+ if (nd_type_p(argn->nd_body, NODE_LIST)) {
+ /* This branch is needed to avoid "newarraykwsplat" [Bug #16442] */
+ int rest_len = compile_args(iseq, args, argn->nd_body, NULL, NULL);
+ ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
}
else {
- if (keyword_node_single_splat_p(kwnode) && (*dup_rest & DUP_SINGLE_KW_SPLAT)) {
- compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
+ NO_CHECK(COMPILE(args, "args (cat: splat)", argn->nd_body));
+ }
+ if (flag) {
+ *flag |= VM_CALL_ARGS_SPLAT;
+ /* This is a dirty hack. It traverses the AST twice.
+ * In a long term, it should be fixed by a redesign of keyword arguments */
+ if (check_keyword(argn->nd_body))
+ *flag |= VM_CALL_KW_SPLAT;
+ }
+ if (nd_type_p(argn, NODE_ARGSCAT)) {
+ if (next_is_list) {
+ ADD_INSN1(args, argn, splatarray, Qtrue);
+ return INT2FIX(FIX2INT(argc) + 1);
}
else {
- compile_hash(iseq, args, kwnode, TRUE, FALSE);
+ ADD_INSN1(args, argn, splatarray, Qfalse);
+ ADD_INSN(args, argn, concatarray);
+ return argc;
}
}
- }
-
- return len;
- }
- case NODE_SPLAT: {
- // f(*a)
- NO_CHECK(COMPILE(args, "args (splat)", RNODE_SPLAT(argn)->nd_head));
- ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
- if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
- if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
- RUBY_ASSERT(flag_ptr == NULL || (*flag_ptr & VM_CALL_KW_SPLAT) == 0);
- return 1;
- }
- case NODE_ARGSCAT: {
- if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
- int argc = setup_args_core(iseq, args, RNODE_ARGSCAT(argn)->nd_head, dup_rest, NULL, NULL);
- bool args_pushed = false;
-
- if (nd_type_p(RNODE_ARGSCAT(argn)->nd_body, NODE_LIST)) {
- int rest_len = compile_args(iseq, args, RNODE_ARGSCAT(argn)->nd_body, &kwnode);
- if (kwnode) rest_len--;
- ADD_INSN1(args, argn, pushtoarray, INT2FIX(rest_len));
- args_pushed = true;
- }
- else {
- RUBY_ASSERT(!check_keyword(RNODE_ARGSCAT(argn)->nd_body));
- NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSCAT(argn)->nd_body));
- }
-
- if (nd_type_p(RNODE_ARGSCAT(argn)->nd_head, NODE_LIST)) {
- ADD_INSN1(args, argn, splatarray, RBOOL(*dup_rest & SPLATARRAY_TRUE));
- if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
- argc += 1;
- }
- else if (!args_pushed) {
- ADD_INSN(args, argn, concattoarray);
- }
-
- // f(..., *a, ..., k1:1, ...) #=> f(..., *[*a, ...], **{k1:1, ...})
- if (kwnode) {
- // kwsplat
- *flag_ptr |= VM_CALL_KW_SPLAT;
- compile_hash(iseq, args, kwnode, TRUE, FALSE);
- argc += 1;
- }
-
- return argc;
- }
- case NODE_ARGSPUSH: {
- if (flag_ptr) *flag_ptr |= VM_CALL_ARGS_SPLAT;
- int argc = setup_args_core(iseq, args, RNODE_ARGSPUSH(argn)->nd_head, dup_rest, NULL, NULL);
-
- if (nd_type_p(RNODE_ARGSPUSH(argn)->nd_body, NODE_LIST)) {
- int rest_len = compile_args(iseq, args, RNODE_ARGSPUSH(argn)->nd_body, &kwnode);
- if (kwnode) rest_len--;
- ADD_INSN1(args, argn, newarray, INT2FIX(rest_len));
- ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
- }
- else {
- if (keyword_node_p(RNODE_ARGSPUSH(argn)->nd_body)) {
- kwnode = RNODE_ARGSPUSH(argn)->nd_body;
- }
else {
- NO_CHECK(COMPILE(args, "args (cat: splat)", RNODE_ARGSPUSH(argn)->nd_body));
- ADD_INSN1(args, argn, pushtoarray, INT2FIX(1));
- }
- }
-
- if (kwnode) {
- // f(*a, k:1)
- *flag_ptr |= VM_CALL_KW_SPLAT;
- if (!keyword_node_single_splat_p(kwnode)) {
- *flag_ptr |= VM_CALL_KW_SPLAT_MUT;
- compile_hash(iseq, args, kwnode, TRUE, FALSE);
- }
- else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
- compile_single_keyword_splat_mutable(iseq, args, argn, kwnode, flag_ptr);
+ ADD_INSN1(args, argn, newarray, INT2FIX(1));
+ ADD_INSN(args, argn, concatarray);
+ return argc;
}
- else {
- compile_hash(iseq, args, kwnode, TRUE, FALSE);
- }
- argc += 1;
+ }
+ case NODE_LIST: {
+ int len = compile_args(iseq, args, argn, keywords, flag);
+ return INT2FIX(len);
+ }
+ default: {
+ UNKNOWN_NODE("setup_arg", argn, Qnil);
+ }
}
-
- return argc;
- }
- default: {
- UNKNOWN_NODE("setup_arg", argn, Qnil);
- }
- }
-}
-
-static void
-setup_args_splat_mut(unsigned int *flag, int dup_rest, int initial_dup_rest)
-{
- if ((*flag & VM_CALL_ARGS_SPLAT) && dup_rest != initial_dup_rest) {
- *flag |= VM_CALL_ARGS_SPLAT_MUT;
- }
-}
-
-static bool
-setup_args_dup_rest_p(const NODE *argn)
-{
- switch(nd_type(argn)) {
- case NODE_LVAR:
- case NODE_DVAR:
- case NODE_GVAR:
- case NODE_IVAR:
- case NODE_CVAR:
- case NODE_CONST:
- case NODE_COLON3:
- case NODE_INTEGER:
- case NODE_FLOAT:
- case NODE_RATIONAL:
- case NODE_IMAGINARY:
- case NODE_STR:
- case NODE_SYM:
- case NODE_REGX:
- case NODE_SELF:
- case NODE_NIL:
- case NODE_TRUE:
- case NODE_FALSE:
- case NODE_LAMBDA:
- case NODE_NTH_REF:
- case NODE_BACK_REF:
- return false;
- case NODE_COLON2:
- return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
- default:
- return true;
}
+ return INT2FIX(0);
}
static VALUE
@@ -6467,94 +5901,13 @@ setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
unsigned int *flag, struct rb_callinfo_kwarg **keywords)
{
VALUE ret;
- unsigned int dup_rest = SPLATARRAY_TRUE, initial_dup_rest;
-
- if (argn) {
- const NODE *check_arg = nd_type_p(argn, NODE_BLOCK_PASS) ?
- RNODE_BLOCK_PASS(argn)->nd_head : argn;
-
- if (check_arg) {
- switch(nd_type(check_arg)) {
- case(NODE_SPLAT):
- // avoid caller side array allocation for f(*arg)
- dup_rest = SPLATARRAY_FALSE;
- break;
- case(NODE_ARGSCAT):
- // avoid caller side array allocation for f(1, *arg)
- dup_rest = !nd_type_p(RNODE_ARGSCAT(check_arg)->nd_head, NODE_LIST);
- break;
- case(NODE_ARGSPUSH):
- // avoid caller side array allocation for f(*arg, **hash) and f(1, *arg, **hash)
- dup_rest = !((nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_SPLAT) ||
- (nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_head, NODE_ARGSCAT) &&
- nd_type_p(RNODE_ARGSCAT(RNODE_ARGSPUSH(check_arg)->nd_head)->nd_head, NODE_LIST))) &&
- nd_type_p(RNODE_ARGSPUSH(check_arg)->nd_body, NODE_HASH) &&
- !RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_brace);
-
- if (dup_rest == SPLATARRAY_FALSE) {
- // require allocation for keyword key/value/splat that may modify splatted argument
- NODE *node = RNODE_HASH(RNODE_ARGSPUSH(check_arg)->nd_body)->nd_head;
- while (node) {
- NODE *key_node = RNODE_LIST(node)->nd_head;
- if (key_node && setup_args_dup_rest_p(key_node)) {
- dup_rest = SPLATARRAY_TRUE;
- break;
- }
-
- node = RNODE_LIST(node)->nd_next;
- NODE *value_node = RNODE_LIST(node)->nd_head;
- if (setup_args_dup_rest_p(value_node)) {
- dup_rest = SPLATARRAY_TRUE;
- break;
- }
-
- node = RNODE_LIST(node)->nd_next;
- }
- }
- break;
- default:
- break;
- }
- }
-
- if (check_arg != argn && setup_args_dup_rest_p(RNODE_BLOCK_PASS(argn)->nd_body)) {
- // for block pass that may modify splatted argument, dup rest and kwrest if given
- dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
- }
- }
- initial_dup_rest = dup_rest;
-
if (argn && nd_type_p(argn, NODE_BLOCK_PASS)) {
+ unsigned int dup_rest = 1;
DECL_ANCHOR(arg_block);
INIT_ANCHOR(arg_block);
+ NO_CHECK(COMPILE(arg_block, "block", argn->nd_body));
- if (RNODE_BLOCK_PASS(argn)->forwarding && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
- int idx = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size;// - get_local_var_idx(iseq, idDot3);
-
- RUBY_ASSERT(nd_type_p(RNODE_BLOCK_PASS(argn)->nd_head, NODE_ARGSPUSH));
- const NODE * arg_node =
- RNODE_ARGSPUSH(RNODE_BLOCK_PASS(argn)->nd_head)->nd_head;
-
- int argc = 0;
-
- // Only compile leading args:
- // foo(x, y, ...)
- // ^^^^
- if (nd_type_p(arg_node, NODE_ARGSCAT)) {
- argc += setup_args_core(iseq, args, RNODE_ARGSCAT(arg_node)->nd_head, &dup_rest, flag, keywords);
- }
-
- *flag |= VM_CALL_FORWARDING;
-
- ADD_GETLOCAL(args, argn, idx, get_lvar_level(iseq));
- setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
- return INT2FIX(argc);
- }
- else {
- *flag |= VM_CALL_ARGS_BLOCKARG;
-
- NO_CHECK(COMPILE(arg_block, "block", RNODE_BLOCK_PASS(argn)->nd_body));
- }
+ *flag |= VM_CALL_ARGS_BLOCKARG;
if (LIST_INSN_SIZE_ONE(arg_block)) {
LINK_ELEMENT *elem = FIRST_ELEMENT(arg_block);
@@ -6563,15 +5916,15 @@ setup_args(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
if (iobj->insn_id == BIN(getblockparam)) {
iobj->insn_id = BIN(getblockparamproxy);
}
+ dup_rest = 0;
}
}
- ret = INT2FIX(setup_args_core(iseq, args, RNODE_BLOCK_PASS(argn)->nd_head, &dup_rest, flag, keywords));
+ ret = setup_args_core(iseq, args, argn->nd_head, dup_rest, flag, keywords);
ADD_SEQ(args, arg_block);
}
else {
- ret = INT2FIX(setup_args_core(iseq, args, argn, &dup_rest, flag, keywords));
+ ret = setup_args_core(iseq, args, argn, 0, flag, keywords);
}
- setup_args_splat_mut(flag, dup_rest, initial_dup_rest);
return ret;
}
@@ -6586,7 +5939,7 @@ build_postexe_iseq(rb_iseq_t *iseq, LINK_ANCHOR *ret, const void *ptr)
ADD_INSN1(ret, body, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
ADD_CALL_WITH_BLOCK(ret, body, id_core_set_postexe, argc, block);
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
- iseq_set_local_table(iseq, 0, 0);
+ iseq_set_local_table(iseq, 0);
}
static void
@@ -6606,19 +5959,19 @@ compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE
ADD_INSN(ret, line_node, dup);
ADD_INSNL(ret, line_node, branchunless, fail_label);
- for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
+ for (vars = node; vars; vars = vars->nd_next) {
INSN *cap;
- if (RNODE_BLOCK(vars)->nd_next) {
+ if (vars->nd_next) {
ADD_INSN(ret, line_node, dup);
}
last = ret->last;
- NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
+ NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
last = last->next; /* putobject :var */
- cap = new_insn_send(iseq, nd_line(line_node), nd_node_id(line_node), idAREF, INT2FIX(1),
+ cap = new_insn_send(iseq, line_node, idAREF, INT2FIX(1),
NULL, INT2FIX(0), NULL);
ELEM_INSERT_PREV(last->next, (LINK_ELEMENT *)cap);
#if !defined(NAMED_CAPTURE_SINGLE_OPT) || NAMED_CAPTURE_SINGLE_OPT-0
- if (!RNODE_BLOCK(vars)->nd_next && vars == node) {
+ if (!vars->nd_next && vars == node) {
/* only one name */
DECL_ANCHOR(nom);
@@ -6639,9 +5992,9 @@ compile_named_capture_assign(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE
ADD_INSNL(ret, line_node, jump, end_label);
ADD_LABEL(ret, fail_label);
ADD_INSN(ret, line_node, pop);
- for (vars = node; vars; vars = RNODE_BLOCK(vars)->nd_next) {
+ for (vars = node; vars; vars = vars->nd_next) {
last = ret->last;
- NO_CHECK(COMPILE_POPPED(ret, "capture", RNODE_BLOCK(vars)->nd_head));
+ NO_CHECK(COMPILE_POPPED(ret, "capture", vars->nd_head));
last = last->next; /* putobject :var */
((INSN*)last)->insn_id = BIN(putnil);
((INSN*)last)->operand_size = 0;
@@ -6654,10 +6007,8 @@ optimizable_range_item_p(const NODE *n)
{
if (!n) return FALSE;
switch (nd_type(n)) {
- case NODE_LINE:
- return TRUE;
- case NODE_INTEGER:
- return TRUE;
+ case NODE_LIT:
+ return RB_INTEGER_TYPE_P(n->nd_lit);
case NODE_NIL:
return TRUE;
default:
@@ -6665,70 +6016,69 @@ optimizable_range_item_p(const NODE *n)
}
}
-static VALUE
-optimized_range_item(const NODE *n)
-{
- switch (nd_type(n)) {
- case NODE_LINE:
- return rb_node_line_lineno_val(n);
- case NODE_INTEGER:
- return rb_node_integer_literal_val(n);
- case NODE_FLOAT:
- return rb_node_float_literal_val(n);
- case NODE_RATIONAL:
- return rb_node_rational_literal_val(n);
- case NODE_IMAGINARY:
- return rb_node_imaginary_literal_val(n);
- case NODE_NIL:
- return Qnil;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(n)));
- }
-}
-
static int
compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
{
- const NODE *const node_body = type == NODE_IF ? RNODE_IF(node)->nd_body : RNODE_UNLESS(node)->nd_else;
- const NODE *const node_else = type == NODE_IF ? RNODE_IF(node)->nd_else : RNODE_UNLESS(node)->nd_body;
+ struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
+ const NODE *const node_body = type == NODE_IF ? node->nd_body : node->nd_else;
+ const NODE *const node_else = type == NODE_IF ? node->nd_else : node->nd_body;
const int line = nd_line(node);
const NODE *line_node = node;
DECL_ANCHOR(cond_seq);
+ DECL_ANCHOR(then_seq);
+ DECL_ANCHOR(else_seq);
LABEL *then_label, *else_label, *end_label;
VALUE branches = Qfalse;
+ int ci_size;
+ VALUE catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
+ long catch_table_size = NIL_P(catch_table) ? 0 : RARRAY_LEN(catch_table);
INIT_ANCHOR(cond_seq);
+ INIT_ANCHOR(then_seq);
+ INIT_ANCHOR(else_seq);
then_label = NEW_LABEL(line);
else_label = NEW_LABEL(line);
end_label = 0;
- NODE *cond = RNODE_IF(node)->nd_cond;
- if (nd_type(cond) == NODE_BLOCK) {
- cond = RNODE_BLOCK(cond)->nd_head;
+ compile_branch_condition(iseq, cond_seq, node->nd_cond,
+ then_label, else_label);
+
+ ci_size = body->ci_size;
+ CHECK(COMPILE_(then_seq, "then", node_body, popped));
+ catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
+ if (!then_label->refcnt) {
+ body->ci_size = ci_size;
+ if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
+ }
+ else {
+ if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
+ }
+
+ ci_size = body->ci_size;
+ CHECK(COMPILE_(else_seq, "else", node_else, popped));
+ catch_table = ISEQ_COMPILE_DATA(iseq)->catch_table_ary;
+ if (!else_label->refcnt) {
+ body->ci_size = ci_size;
+ if (!NIL_P(catch_table)) rb_ary_set_len(catch_table, catch_table_size);
+ }
+ else {
+ if (!NIL_P(catch_table)) catch_table_size = RARRAY_LEN(catch_table);
}
- CHECK(compile_branch_condition(iseq, cond_seq, cond, then_label, else_label));
ADD_SEQ(ret, cond_seq);
if (then_label->refcnt && else_label->refcnt) {
- branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_IF ? "if" : "unless");
+ branches = decl_branch_base(iseq, node, type == NODE_IF ? "if" : "unless");
}
if (then_label->refcnt) {
ADD_LABEL(ret, then_label);
-
- DECL_ANCHOR(then_seq);
- INIT_ANCHOR(then_seq);
- CHECK(COMPILE_(then_seq, "then", node_body, popped));
-
if (else_label->refcnt) {
- const NODE *const coverage_node = node_body ? node_body : node;
add_trace_branch_coverage(
iseq,
ret,
- nd_code_loc(coverage_node),
- nd_node_id(coverage_node),
+ node_body ? node_body : node,
0,
type == NODE_IF ? "then" : "else",
branches);
@@ -6743,18 +6093,11 @@ compile_if(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int
if (else_label->refcnt) {
ADD_LABEL(ret, else_label);
-
- DECL_ANCHOR(else_seq);
- INIT_ANCHOR(else_seq);
- CHECK(COMPILE_(else_seq, "else", node_else, popped));
-
if (then_label->refcnt) {
- const NODE *const coverage_node = node_else ? node_else : node;
add_trace_branch_coverage(
iseq,
ret,
- nd_code_loc(coverage_node),
- nd_node_id(coverage_node),
+ node_else ? node_else : node,
1,
type == NODE_IF ? "else" : "then",
branches);
@@ -6792,11 +6135,11 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
RHASH_TBL_RAW(literals)->type = &cdhash_type;
- CHECK(COMPILE(head, "case base", RNODE_CASE(node)->nd_head));
+ CHECK(COMPILE(head, "case base", node->nd_head));
- branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
+ branches = decl_branch_base(iseq, node, "case");
- node = RNODE_CASE(node)->nd_body;
+ node = node->nd_body;
EXPECT_NODE("NODE_CASE", node, NODE_WHEN, COMPILE_NG);
type = nd_type(node);
line = nd_line(node);
@@ -6813,21 +6156,17 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
l1 = NEW_LABEL(line);
ADD_LABEL(body_seq, l1);
ADD_INSN(body_seq, line_node, pop);
-
- const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
add_trace_branch_coverage(
iseq,
body_seq,
- nd_code_loc(coverage_node),
- nd_node_id(coverage_node),
+ node->nd_body ? node->nd_body : node,
branch_id++,
"when",
branches);
-
- CHECK(COMPILE_(body_seq, "when body", RNODE_WHEN(node)->nd_body, popped));
+ CHECK(COMPILE_(body_seq, "when body", node->nd_body, popped));
ADD_INSNL(body_seq, line_node, jump, endlabel);
- vals = RNODE_WHEN(node)->nd_head;
+ vals = node->nd_head;
if (vals) {
switch (nd_type(vals)) {
case NODE_LIST:
@@ -6848,7 +6187,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
EXPECT_NODE_NONULL("NODE_CASE", node, NODE_LIST, COMPILE_NG);
}
- node = RNODE_WHEN(node)->nd_next;
+ node = node->nd_next;
if (!node) {
break;
}
@@ -6860,7 +6199,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
if (node) {
ADD_LABEL(cond_seq, elselabel);
ADD_INSN(cond_seq, line_node, pop);
- add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
+ add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
CHECK(COMPILE_(cond_seq, "else", node, popped));
ADD_INSNL(cond_seq, line_node, jump, endlabel);
}
@@ -6868,7 +6207,7 @@ compile_case(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_nod
debugs("== else (implicit)\n");
ADD_LABEL(cond_seq, elselabel);
ADD_INSN(cond_seq, orig_node, pop);
- add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
+ add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
if (!popped) {
ADD_INSN(cond_seq, orig_node, putnil);
}
@@ -6893,13 +6232,13 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
{
const NODE *vals;
const NODE *val;
- const NODE *node = RNODE_CASE2(orig_node)->nd_body;
+ const NODE *node = orig_node->nd_body;
LABEL *endlabel;
DECL_ANCHOR(body_seq);
VALUE branches = Qfalse;
int branch_id = 0;
- branches = decl_branch_base(iseq, PTR2NUM(orig_node), nd_code_loc(orig_node), "case");
+ branches = decl_branch_base(iseq, orig_node, "case");
INIT_ANCHOR(body_seq);
endlabel = NEW_LABEL(nd_line(node));
@@ -6908,21 +6247,17 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
const int line = nd_line(node);
LABEL *l1 = NEW_LABEL(line);
ADD_LABEL(body_seq, l1);
-
- const NODE *const coverage_node = RNODE_WHEN(node)->nd_body ? RNODE_WHEN(node)->nd_body : node;
add_trace_branch_coverage(
iseq,
body_seq,
- nd_code_loc(coverage_node),
- nd_node_id(coverage_node),
+ node->nd_body ? node->nd_body : node,
branch_id++,
"when",
branches);
-
- CHECK(COMPILE_(body_seq, "when", RNODE_WHEN(node)->nd_body, popped));
+ CHECK(COMPILE_(body_seq, "when", node->nd_body, popped));
ADD_INSNL(body_seq, node, jump, endlabel);
- vals = RNODE_WHEN(node)->nd_head;
+ vals = node->nd_head;
if (!vals) {
EXPECT_NODE_NONULL("NODE_WHEN", node, NODE_LIST, COMPILE_NG);
}
@@ -6930,12 +6265,12 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
case NODE_LIST:
while (vals) {
LABEL *lnext;
- val = RNODE_LIST(vals)->nd_head;
+ val = vals->nd_head;
lnext = NEW_LABEL(nd_line(val));
debug_compile("== when2\n", (void)0);
CHECK(compile_branch_condition(iseq, ret, val, l1, lnext));
ADD_LABEL(ret, lnext);
- vals = RNODE_LIST(vals)->nd_next;
+ vals = vals->nd_next;
}
break;
case NODE_SPLAT:
@@ -6949,15 +6284,13 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
default:
UNKNOWN_NODE("NODE_WHEN", vals, COMPILE_NG);
}
- node = RNODE_WHEN(node)->nd_next;
+ node = node->nd_next;
}
/* else */
- const NODE *const coverage_node = node ? node : orig_node;
add_trace_branch_coverage(
iseq,
ret,
- nd_code_loc(coverage_node),
- nd_node_id(coverage_node),
+ node ? node : orig_node,
branch_id,
"else",
branches);
@@ -7043,13 +6376,14 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
* match_failed:
* goto unmatched
*/
- const NODE *args = RNODE_ARYPTN(node)->pre_args;
- const int pre_args_num = RNODE_ARYPTN(node)->pre_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->pre_args)->as.nd_alen) : 0;
- const int post_args_num = RNODE_ARYPTN(node)->post_args ? rb_long2int(RNODE_LIST(RNODE_ARYPTN(node)->post_args)->as.nd_alen) : 0;
+ struct rb_ary_pattern_info *apinfo = node->nd_apinfo;
+ const NODE *args = apinfo->pre_args;
+ const int pre_args_num = apinfo->pre_args ? rb_long2int(apinfo->pre_args->nd_alen) : 0;
+ const int post_args_num = apinfo->post_args ? rb_long2int(apinfo->post_args->nd_alen) : 0;
const int min_argc = pre_args_num + post_args_num;
- const int use_rest_num = RNODE_ARYPTN(node)->rest_arg && (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) ||
- (!NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg) && post_args_num > 0));
+ const int use_rest_num = apinfo->rest_arg && (NODE_NAMED_REST_P(apinfo->rest_arg) ||
+ (!NODE_NAMED_REST_P(apinfo->rest_arg) && post_args_num > 0));
LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
int i;
@@ -7073,10 +6407,10 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN(ret, line_node, dup);
ADD_SEND(ret, line_node, idLength, INT2FIX(0));
ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
- ADD_SEND(ret, line_node, RNODE_ARYPTN(node)->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
+ ADD_SEND(ret, line_node, apinfo->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
if (in_single_pattern) {
CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
- RNODE_ARYPTN(node)->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
+ apinfo->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
INT2FIX(min_argc), base_index + 1 /* (1) */));
}
@@ -7086,12 +6420,12 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN(ret, line_node, dup);
ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (2) */, false));
- args = RNODE_LIST(args)->nd_next;
+ CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (2) */, false));
+ args = args->nd_next;
}
- if (RNODE_ARYPTN(node)->rest_arg) {
- if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
+ if (apinfo->rest_arg) {
+ if (NODE_NAMED_REST_P(apinfo->rest_arg)) {
ADD_INSN(ret, line_node, dup);
ADD_INSN1(ret, line_node, putobject, INT2FIX(pre_args_num));
ADD_INSN1(ret, line_node, topn, INT2FIX(1));
@@ -7101,7 +6435,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN1(ret, line_node, setn, INT2FIX(4));
ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_ARYPTN(node)->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (3) */, false));
+ CHECK(iseq_compile_pattern_match(iseq, ret, apinfo->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (3) */, false));
}
else {
if (post_args_num > 0) {
@@ -7115,7 +6449,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
}
}
- args = RNODE_ARYPTN(node)->post_args;
+ args = apinfo->post_args;
for (i = 0; i < post_args_num; i++) {
ADD_INSN(ret, line_node, dup);
@@ -7124,8 +6458,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (4) */, false));
- args = RNODE_LIST(args)->nd_next;
+ CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (4) */, false));
+ args = args->nd_next;
}
ADD_INSN(ret, line_node, pop);
@@ -7203,8 +6537,9 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
* match_failed:
* goto unmatched
*/
- const NODE *args = RNODE_FNDPTN(node)->args;
- const int args_num = RNODE_FNDPTN(node)->args ? rb_long2int(RNODE_LIST(RNODE_FNDPTN(node)->args)->as.nd_alen) : 0;
+ struct rb_fnd_pattern_info *fpinfo = node->nd_fpinfo;
+ const NODE *args = fpinfo->args;
+ const int args_num = fpinfo->args ? rb_long2int(fpinfo->args->nd_alen) : 0;
LABEL *match_failed, *type_error, *deconstruct, *deconstructed;
match_failed = NEW_LABEL(line);
@@ -7257,25 +6592,25 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
}
ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(args)->nd_head, next_loop, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (5) */, false));
- args = RNODE_LIST(args)->nd_next;
+ CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, next_loop, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (5) */, false));
+ args = args->nd_next;
}
- if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
+ if (NODE_NAMED_REST_P(fpinfo->pre_rest_arg)) {
ADD_INSN1(ret, line_node, topn, INT2FIX(3));
ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
ADD_INSN1(ret, line_node, topn, INT2FIX(2));
ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_FNDPTN(node)->pre_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (6) */, false));
+ CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->pre_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (6) */, false));
}
- if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
+ if (NODE_NAMED_REST_P(fpinfo->post_rest_arg)) {
ADD_INSN1(ret, line_node, topn, INT2FIX(3));
ADD_INSN1(ret, line_node, topn, INT2FIX(1));
ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
ADD_INSN1(ret, line_node, topn, INT2FIX(3));
ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_FNDPTN(node)->post_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3),(4), (7) */, false));
+ CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->post_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3),(4), (7) */, false));
}
ADD_INSNL(ret, line_node, jump, find_succeeded);
@@ -7389,12 +6724,12 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
match_failed = NEW_LABEL(line);
type_error = NEW_LABEL(line);
- if (RNODE_HSHPTN(node)->nd_pkwargs && !RNODE_HSHPTN(node)->nd_pkwrestarg) {
- const NODE *kw_args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
- keys = rb_ary_new_capa(kw_args ? RNODE_LIST(kw_args)->as.nd_alen/2 : 0);
+ if (node->nd_pkwargs && !node->nd_pkwrestarg) {
+ const NODE *kw_args = node->nd_pkwargs->nd_head;
+ keys = rb_ary_new_capa(kw_args ? kw_args->nd_alen/2 : 0);
while (kw_args) {
- rb_ary_push(keys, get_symbol_value(iseq, RNODE_LIST(kw_args)->nd_head));
- kw_args = RNODE_LIST(RNODE_LIST(kw_args)->nd_next)->nd_next;
+ rb_ary_push(keys, kw_args->nd_head->nd_lit);
+ kw_args = kw_args->nd_next->nd_next;
}
}
@@ -7421,23 +6756,28 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
ADD_INSNL(ret, line_node, branchunless, type_error);
- if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
+ if (node->nd_pkwrestarg) {
ADD_SEND(ret, line_node, rb_intern("dup"), INT2FIX(0));
}
- if (RNODE_HSHPTN(node)->nd_pkwargs) {
+ if (node->nd_pkwargs) {
int i;
int keys_num;
const NODE *args;
- args = RNODE_HASH(RNODE_HSHPTN(node)->nd_pkwargs)->nd_head;
+ args = node->nd_pkwargs->nd_head;
if (args) {
DECL_ANCHOR(match_values);
INIT_ANCHOR(match_values);
- keys_num = rb_long2int(RNODE_LIST(args)->as.nd_alen) / 2;
+ keys_num = rb_long2int(args->nd_alen) / 2;
for (i = 0; i < keys_num; i++) {
- NODE *key_node = RNODE_LIST(args)->nd_head;
- NODE *value_node = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_head;
- VALUE key = get_symbol_value(iseq, key_node);
+ NODE *key_node = args->nd_head;
+ NODE *value_node = args->nd_next->nd_head;
+ VALUE key;
+
+ if (!nd_type_p(key_node, NODE_LIT)) {
+ UNKNOWN_NODE("NODE_IN", key_node, COMPILE_NG);
+ }
+ key = key_node->nd_lit;
ADD_INSN(ret, line_node, dup);
ADD_INSN1(ret, line_node, putobject, key);
@@ -7466,9 +6806,9 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN(match_values, line_node, dup);
ADD_INSN1(match_values, line_node, putobject, key);
- ADD_SEND(match_values, line_node, RNODE_HSHPTN(node)->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
+ ADD_SEND(match_values, line_node, node->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
- args = RNODE_LIST(RNODE_LIST(args)->nd_next)->nd_next;
+ args = args->nd_next->nd_next;
}
ADD_SEQ(ret, match_values);
}
@@ -7482,8 +6822,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSNL(ret, line_node, branchunless, match_failed);
}
- if (RNODE_HSHPTN(node)->nd_pkwrestarg) {
- if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
+ if (node->nd_pkwrestarg) {
+ if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
ADD_INSN(ret, line_node, dup);
ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
if (in_single_pattern) {
@@ -7493,7 +6833,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
}
else {
ADD_INSN(ret, line_node, dup); // (11)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_HSHPTN(node)->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (11) */, false));
+ CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (11) */, false));
}
}
@@ -7513,15 +6853,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSNL(ret, line_node, jump, unmatched);
break;
}
- case NODE_SYM:
- case NODE_REGX:
- case NODE_LINE:
- case NODE_INTEGER:
- case NODE_FLOAT:
- case NODE_RATIONAL:
- case NODE_IMAGINARY:
- case NODE_FILE:
- case NODE_ENCODING:
+ case NODE_LIT:
case NODE_STR:
case NODE_XSTR:
case NODE_DSTR:
@@ -7545,8 +6877,6 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
case NODE_COLON2:
case NODE_COLON3:
case NODE_BEGIN:
- case NODE_BLOCK:
- case NODE_ONCE:
CHECK(COMPILE(ret, "case in literal", node)); // (1)
if (in_single_pattern) {
ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
@@ -7560,7 +6890,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
break;
case NODE_LASGN: {
struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
- ID id = RNODE_LASGN(node)->nd_vid;
+ ID id = node->nd_vid;
int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
if (in_alt_pattern) {
@@ -7578,7 +6908,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
}
case NODE_DASGN: {
int idx, lv, ls;
- ID id = RNODE_DASGN(node)->nd_vid;
+ ID id = node->nd_vid;
idx = get_dyna_var_idx(iseq, id, &lv, &ls);
@@ -7604,8 +6934,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
case NODE_UNLESS: {
LABEL *match_failed;
match_failed = unmatched;
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_IF(node)->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
- CHECK(COMPILE(ret, "case in if", RNODE_IF(node)->nd_cond));
+ CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
+ CHECK(COMPILE(ret, "case in if", node->nd_cond));
if (in_single_pattern) {
LABEL *match_succeeded;
match_succeeded = NEW_LABEL(line);
@@ -7642,15 +6972,15 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
LABEL *match_failed;
match_failed = NEW_LABEL(line);
- n = RNODE_HASH(node)->nd_head;
- if (! (nd_type_p(n, NODE_LIST) && RNODE_LIST(n)->as.nd_alen == 2)) {
+ n = node->nd_head;
+ if (! (nd_type_p(n, NODE_LIST) && n->nd_alen == 2)) {
COMPILE_ERROR(ERROR_ARGS "unexpected node");
return COMPILE_NG;
}
ADD_INSN(ret, line_node, dup); // (1)
- CHECK(iseq_compile_pattern_match(iseq, ret, RNODE_LIST(n)->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (1) */, use_deconstructed_cache));
- CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head, matched, match_failed, in_single_pattern, in_alt_pattern, base_index, false));
+ CHECK(iseq_compile_pattern_match(iseq, ret, n->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (1) */, use_deconstructed_cache));
+ CHECK(iseq_compile_pattern_each(iseq, ret, n->nd_next->nd_head, matched, match_failed, in_single_pattern, in_alt_pattern, base_index, false));
ADD_INSN(ret, line_node, putnil);
ADD_LABEL(ret, match_failed);
@@ -7664,13 +6994,13 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
fin = NEW_LABEL(line);
ADD_INSN(ret, line_node, dup); // (1)
- CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_1st, match_succeeded, fin, in_single_pattern, true, base_index + 1 /* (1) */, use_deconstructed_cache));
+ CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_1st, match_succeeded, fin, in_single_pattern, true, base_index + 1 /* (1) */, use_deconstructed_cache));
ADD_LABEL(ret, match_succeeded);
ADD_INSN(ret, line_node, pop);
ADD_INSNL(ret, line_node, jump, matched);
ADD_INSN(ret, line_node, putnil);
ADD_LABEL(ret, fin);
- CHECK(iseq_compile_pattern_each(iseq, ret, RNODE_OR(node)->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
+ CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
break;
}
default:
@@ -7693,9 +7023,9 @@ iseq_compile_pattern_constant(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NOD
{
const NODE *line_node = node;
- if (RNODE_ARYPTN(node)->nd_pconst) {
+ if (node->nd_pconst) {
ADD_INSN(ret, line_node, dup); // (1)
- CHECK(COMPILE(ret, "constant", RNODE_ARYPTN(node)->nd_pconst)); // (2)
+ CHECK(COMPILE(ret, "constant", node->nd_pconst)); // (2)
if (in_single_pattern) {
ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
}
@@ -7896,14 +7226,14 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
INIT_ANCHOR(body_seq);
INIT_ANCHOR(cond_seq);
- branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "case");
+ branches = decl_branch_base(iseq, node, "case");
- node = RNODE_CASE3(node)->nd_body;
+ node = node->nd_body;
EXPECT_NODE("NODE_CASE3", node, NODE_IN, COMPILE_NG);
type = nd_type(node);
line = nd_line(node);
line_node = node;
- single_pattern = !RNODE_IN(node)->nd_next;
+ single_pattern = !node->nd_next;
endlabel = NEW_LABEL(line);
elselabel = NEW_LABEL(line);
@@ -7917,7 +7247,7 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
}
ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
- CHECK(COMPILE(head, "case base", RNODE_CASE3(orig_node)->nd_head));
+ CHECK(COMPILE(head, "case base", orig_node->nd_head));
ADD_SEQ(ret, head); /* case VAL */
@@ -7930,21 +7260,17 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
l1 = NEW_LABEL(line);
ADD_LABEL(body_seq, l1);
ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
-
- const NODE *const coverage_node = RNODE_IN(node)->nd_body ? RNODE_IN(node)->nd_body : node;
add_trace_branch_coverage(
iseq,
body_seq,
- nd_code_loc(coverage_node),
- nd_node_id(coverage_node),
+ node->nd_body ? node->nd_body : node,
branch_id++,
"in",
branches);
-
- CHECK(COMPILE_(body_seq, "in body", RNODE_IN(node)->nd_body, popped));
+ CHECK(COMPILE_(body_seq, "in body", node->nd_body, popped));
ADD_INSNL(body_seq, line_node, jump, endlabel);
- pattern = RNODE_IN(node)->nd_head;
+ pattern = node->nd_head;
if (pattern) {
int pat_line = nd_line(pattern);
LABEL *next_pat = NEW_LABEL(pat_line);
@@ -7959,7 +7285,7 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
return COMPILE_NG;
}
- node = RNODE_IN(node)->nd_next;
+ node = node->nd_next;
if (!node) {
break;
}
@@ -7972,7 +7298,7 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
ADD_LABEL(cond_seq, elselabel);
ADD_INSN(cond_seq, line_node, pop);
ADD_INSN(cond_seq, line_node, pop); /* discard cached #deconstruct value */
- add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(node), nd_node_id(node), branch_id, "else", branches);
+ add_trace_branch_coverage(iseq, cond_seq, node, branch_id, "else", branches);
CHECK(COMPILE_(cond_seq, "else", node, popped));
ADD_INSNL(cond_seq, line_node, jump, endlabel);
ADD_INSN(cond_seq, line_node, putnil);
@@ -7983,7 +7309,7 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
else {
debugs("== else (implicit)\n");
ADD_LABEL(cond_seq, elselabel);
- add_trace_branch_coverage(iseq, cond_seq, nd_code_loc(orig_node), nd_node_id(orig_node), branch_id, "else", branches);
+ add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
if (single_pattern) {
@@ -8001,7 +7327,6 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
fin = NEW_LABEL(line);
kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
- kw_arg->references = 0;
kw_arg->keyword_len = 2;
kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
@@ -8085,7 +7410,7 @@ compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
ISEQ_COMPILE_DATA(iseq)->loopval_popped = 0;
push_ensure_entry(iseq, &enl, NULL, NULL);
- if (RNODE_WHILE(node)->nd_state == 1) {
+ if (node->nd_state == 1) {
ADD_INSNL(ret, line_node, jump, next_label);
}
else {
@@ -8100,35 +7425,31 @@ compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
if (tmp_label) ADD_LABEL(ret, tmp_label);
ADD_LABEL(ret, redo_label);
- branches = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), type == NODE_WHILE ? "while" : "until");
-
- const NODE *const coverage_node = RNODE_WHILE(node)->nd_body ? RNODE_WHILE(node)->nd_body : node;
+ branches = decl_branch_base(iseq, node, type == NODE_WHILE ? "while" : "until");
add_trace_branch_coverage(
iseq,
ret,
- nd_code_loc(coverage_node),
- nd_node_id(coverage_node),
+ node->nd_body ? node->nd_body : node,
0,
"body",
branches);
-
- CHECK(COMPILE_POPPED(ret, "while body", RNODE_WHILE(node)->nd_body));
+ CHECK(COMPILE_POPPED(ret, "while body", node->nd_body));
ADD_LABEL(ret, next_label); /* next */
if (type == NODE_WHILE) {
- CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
- redo_label, end_label));
+ compile_branch_condition(iseq, ret, node->nd_cond,
+ redo_label, end_label);
}
else {
/* until */
- CHECK(compile_branch_condition(iseq, ret, RNODE_WHILE(node)->nd_cond,
- end_label, redo_label));
+ compile_branch_condition(iseq, ret, node->nd_cond,
+ end_label, redo_label);
}
ADD_LABEL(ret, end_label);
ADD_ADJUST_RESTORE(ret, adjust_label);
- if (UNDEF_P(RNODE_WHILE(node)->nd_state)) {
+ if (UNDEF_P(node->nd_state)) {
/* ADD_INSN(ret, line_node, putundef); */
COMPILE_ERROR(ERROR_ARGS "unsupported: putundef");
return COMPILE_NG;
@@ -8170,18 +7491,18 @@ compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
ADD_LABEL(ret, retry_label);
if (nd_type_p(node, NODE_FOR)) {
- CHECK(COMPILE(ret, "iter caller (for)", RNODE_FOR(node)->nd_iter));
+ CHECK(COMPILE(ret, "iter caller (for)", node->nd_iter));
ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
- NEW_CHILD_ISEQ(RNODE_FOR(node)->nd_body, make_name_for_block(iseq),
+ NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
ISEQ_TYPE_BLOCK, line);
ADD_SEND_WITH_BLOCK(ret, line_node, idEach, INT2FIX(0), child_iseq);
}
else {
ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq =
- NEW_CHILD_ISEQ(RNODE_ITER(node)->nd_body, make_name_for_block(iseq),
+ NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq),
ISEQ_TYPE_BLOCK, line);
- CHECK(COMPILE(ret, "iter caller", RNODE_ITER(node)->nd_iter));
+ CHECK(COMPILE(ret, "iter caller", node->nd_iter));
}
{
@@ -8192,11 +7513,11 @@ compile_iter(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
// Normally, "send" instruction is at the last.
// However, qcall under branch coverage measurement adds some instructions after the "send".
//
- // Note that "invokesuper", "invokesuperforward" appears instead of "send".
+ // Note that "invokesuper" appears instead of "send".
INSN *iobj;
LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
- while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
+ while (INSN_OF(iobj) != BIN(send) && INSN_OF(iobj) != BIN(invokesuper)) {
iobj = (INSN*) get_prev_insn(iobj);
}
ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
@@ -8225,7 +7546,7 @@ compile_for_masgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const nod
* (args.length == 1 && Array.try_convert(args[0])) || args
*/
const NODE *line_node = node;
- const NODE *var = RNODE_FOR_MASGN(node)->nd_var;
+ const NODE *var = node->nd_var;
LABEL *not_single = NEW_LABEL(nd_line(var));
LABEL *not_ary = NEW_LABEL(nd_line(var));
CHECK(COMPILE(ret, "for var", var));
@@ -8260,7 +7581,7 @@ compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
LABEL *splabel = NEW_LABEL(0);
ADD_LABEL(ret, splabel);
ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
- CHECK(COMPILE_(ret, "break val (while/until)", RNODE_BREAK(node)->nd_stts,
+ CHECK(COMPILE_(ret, "break val (while/until)", node->nd_stts,
ISEQ_COMPILE_DATA(iseq)->loopval_popped));
add_ensure_iseq(ret, iseq, 0);
ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
@@ -8295,7 +7616,7 @@ compile_break(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
}
/* escape from block */
- CHECK(COMPILE(ret, "break val (block)", RNODE_BREAK(node)->nd_stts));
+ CHECK(COMPILE(ret, "break val (block)", node->nd_stts));
ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
if (popped) {
ADD_INSN(ret, line_node, pop);
@@ -8318,7 +7639,7 @@ compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
LABEL *splabel = NEW_LABEL(0);
debugs("next in while loop\n");
ADD_LABEL(ret, splabel);
- CHECK(COMPILE(ret, "next val/valid syntax?", RNODE_NEXT(node)->nd_stts));
+ CHECK(COMPILE(ret, "next val/valid syntax?", node->nd_stts));
add_ensure_iseq(ret, iseq, 0);
ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
@@ -8332,7 +7653,7 @@ compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
debugs("next in block\n");
ADD_LABEL(ret, splabel);
ADD_ADJUST(ret, line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
- CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
+ CHECK(COMPILE(ret, "next val", node->nd_stts));
add_ensure_iseq(ret, iseq, 0);
ADD_INSNL(ret, line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
ADD_ADJUST_RESTORE(ret, splabel);
@@ -8366,7 +7687,7 @@ compile_next(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
ip = ISEQ_BODY(ip)->parent_iseq;
}
if (ip != 0) {
- CHECK(COMPILE(ret, "next val", RNODE_NEXT(node)->nd_stts));
+ CHECK(COMPILE(ret, "next val", node->nd_stts));
ADD_INSN1(ret, line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
if (popped) {
@@ -8478,7 +7799,7 @@ compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
LABEL *lstart = NEW_LABEL(line);
LABEL *lend = NEW_LABEL(line);
LABEL *lcont = NEW_LABEL(line);
- const rb_iseq_t *rescue = NEW_CHILD_ISEQ(RNODE_RESCUE(node)->nd_resq,
+ const rb_iseq_t *rescue = NEW_CHILD_ISEQ(node->nd_resq,
rb_str_concat(rb_str_new2("rescue in "),
ISEQ_BODY(iseq)->location.label),
ISEQ_TYPE_RESCUE, line);
@@ -8490,14 +7811,14 @@ compile_rescue(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
{
- CHECK(COMPILE(ret, "rescue head", RNODE_RESCUE(node)->nd_head));
+ CHECK(COMPILE(ret, "rescue head", node->nd_head));
}
ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
ADD_LABEL(ret, lend);
- if (RNODE_RESCUE(node)->nd_else) {
+ if (node->nd_else) {
ADD_INSN(ret, line_node, pop);
- CHECK(COMPILE(ret, "rescue else", RNODE_RESCUE(node)->nd_else));
+ CHECK(COMPILE(ret, "rescue else", node->nd_else));
}
ADD_INSN(ret, line_node, nop);
ADD_LABEL(ret, lcont);
@@ -8525,16 +7846,16 @@ compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
label_miss = NEW_LABEL(line);
label_hit = NEW_LABEL(line);
- narg = RNODE_RESBODY(resq)->nd_args;
+ narg = resq->nd_args;
if (narg) {
switch (nd_type(narg)) {
case NODE_LIST:
while (narg) {
ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
- CHECK(COMPILE(ret, "rescue arg", RNODE_LIST(narg)->nd_head));
+ CHECK(COMPILE(ret, "rescue arg", narg->nd_head));
ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
ADD_INSNL(ret, line_node, branchif, label_hit);
- narg = RNODE_LIST(narg)->nd_next;
+ narg = narg->nd_next;
}
break;
case NODE_SPLAT:
@@ -8557,26 +7878,13 @@ compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
}
ADD_INSNL(ret, line_node, jump, label_miss);
ADD_LABEL(ret, label_hit);
- ADD_TRACE(ret, RUBY_EVENT_RESCUE);
-
- if (RNODE_RESBODY(resq)->nd_exc_var) {
- CHECK(COMPILE_POPPED(ret, "resbody exc_var", RNODE_RESBODY(resq)->nd_exc_var));
- }
-
- if (nd_type(RNODE_RESBODY(resq)->nd_body) == NODE_BEGIN && RNODE_BEGIN(RNODE_RESBODY(resq)->nd_body)->nd_body == NULL && !RNODE_RESBODY(resq)->nd_exc_var) {
- // empty body
- ADD_SYNTHETIC_INSN(ret, nd_line(RNODE_RESBODY(resq)->nd_body), -1, putnil);
- }
- else {
- CHECK(COMPILE(ret, "resbody body", RNODE_RESBODY(resq)->nd_body));
- }
-
+ CHECK(COMPILE(ret, "resbody body", resq->nd_body));
if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
ADD_INSN(ret, line_node, nop);
}
ADD_INSN(ret, line_node, leave);
ADD_LABEL(ret, label_miss);
- resq = RNODE_RESBODY(resq)->nd_next;
+ resq = resq->nd_head;
}
return COMPILE_OK;
}
@@ -8584,10 +7892,10 @@ compile_resbody(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
static int
compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
{
- const int line = nd_line(RNODE_ENSURE(node)->nd_ensr);
+ const int line = nd_line(node);
const NODE *line_node = node;
DECL_ANCHOR(ensr);
- const rb_iseq_t *ensure = NEW_CHILD_ISEQ(RNODE_ENSURE(node)->nd_ensr,
+ const rb_iseq_t *ensure = NEW_CHILD_ISEQ(node->nd_ensr,
rb_str_concat(rb_str_new2 ("ensure in "), ISEQ_BODY(iseq)->location.label),
ISEQ_TYPE_ENSURE, line);
LABEL *lstart = NEW_LABEL(line);
@@ -8600,17 +7908,17 @@ compile_ensure(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
struct ensure_range *erange;
INIT_ANCHOR(ensr);
- CHECK(COMPILE_POPPED(ensr, "ensure ensr", RNODE_ENSURE(node)->nd_ensr));
+ CHECK(COMPILE_POPPED(ensr, "ensure ensr", node->nd_ensr));
last = ensr->last;
last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
er.begin = lstart;
er.end = lend;
er.next = 0;
- push_ensure_entry(iseq, &enl, &er, RNODE_ENSURE(node)->nd_ensr);
+ push_ensure_entry(iseq, &enl, &er, node->nd_ensr);
ADD_LABEL(ret, lstart);
- CHECK(COMPILE_(ret, "ensure head", RNODE_ENSURE(node)->nd_head, (popped | last_leave)));
+ CHECK(COMPILE_(ret, "ensure head", node->nd_head, (popped | last_leave)));
ADD_LABEL(ret, lend);
ADD_SEQ(ret, ensr);
if (!popped && last_leave) ADD_INSN(ret, line_node, putnil);
@@ -8639,7 +7947,7 @@ compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
const rb_iseq_t *is = iseq;
enum rb_iseq_type t = type;
- const NODE *retval = RNODE_RETURN(node)->nd_stts;
+ const NODE *retval = node->nd_stts;
LABEL *splabel = 0;
while (t == ISEQ_TYPE_RESCUE || t == ISEQ_TYPE_ENSURE) {
@@ -8689,27 +7997,6 @@ compile_return(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
return COMPILE_OK;
}
-static bool
-drop_unreachable_return(LINK_ANCHOR *ret)
-{
- LINK_ELEMENT *i = ret->last, *last;
- if (!i) return false;
- if (IS_TRACE(i)) i = i->prev;
- if (!IS_INSN(i) || !IS_INSN_ID(i, putnil)) return false;
- last = i = i->prev;
- if (IS_ADJUST(i)) i = i->prev;
- if (!IS_INSN(i)) return false;
- switch (INSN_OF(i)) {
- case BIN(leave):
- case BIN(jump):
- break;
- default:
- return false;
- }
- (ret->last = last->prev)->next = NULL;
- return true;
-}
-
static int
compile_evstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
{
@@ -8743,11 +8030,11 @@ qcall_branch_start(rb_iseq_t *iseq, LINK_ANCHOR *const recv, VALUE *branches, co
LABEL *else_label = NEW_LABEL(nd_line(line_node));
VALUE br = 0;
- br = decl_branch_base(iseq, PTR2NUM(node), nd_code_loc(node), "&.");
+ br = decl_branch_base(iseq, node, "&.");
*branches = br;
ADD_INSN(recv, line_node, dup);
ADD_INSNL(recv, line_node, branchnil, else_label);
- add_trace_branch_coverage(iseq, recv, nd_code_loc(node), nd_node_id(node), 0, "then", br);
+ add_trace_branch_coverage(iseq, recv, node, 0, "then", br);
return else_label;
}
@@ -8759,7 +8046,7 @@ qcall_branch_end(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *else_label, VAL
end_label = NEW_LABEL(nd_line(line_node));
ADD_INSNL(ret, line_node, jump, end_label);
ADD_LABEL(ret, else_label);
- add_trace_branch_coverage(iseq, ret, nd_code_loc(node), nd_node_id(node), 1, "else", branches);
+ add_trace_branch_coverage(iseq, ret, node, 1, "else", branches);
ADD_LABEL(ret, end_label);
}
@@ -8769,14 +8056,13 @@ compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE
/* optimization shortcut
* "literal".freeze -> opt_str_freeze("literal")
*/
- if (get_nd_recv(node) &&
- (nd_type_p(get_nd_recv(node), NODE_STR) || nd_type_p(get_nd_recv(node), NODE_FILE)) &&
- (get_node_call_nd_mid(node) == idFreeze || get_node_call_nd_mid(node) == idUMinus) &&
- get_nd_args(node) == NULL &&
+ if (node->nd_recv && nd_type_p(node->nd_recv, NODE_STR) &&
+ (node->nd_mid == idFreeze || node->nd_mid == idUMinus) &&
+ node->nd_args == NULL &&
ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
- VALUE str = get_string_value(get_nd_recv(node));
- if (get_node_call_nd_mid(node) == idUMinus) {
+ VALUE str = rb_fstring(node->nd_recv->nd_lit);
+ if (node->nd_mid == idUMinus) {
ADD_INSN2(ret, line_node, opt_str_uminus, str,
new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE));
}
@@ -8793,14 +8079,14 @@ compile_call_precheck_freeze(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE
/* optimization shortcut
* obj["literal"] -> opt_aref_with(obj, "literal")
*/
- if (get_node_call_nd_mid(node) == idAREF && !private_recv_p(node) && get_nd_args(node) &&
- nd_type_p(get_nd_args(node), NODE_LIST) && RNODE_LIST(get_nd_args(node))->as.nd_alen == 1 &&
- (nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(get_nd_args(node))->nd_head, NODE_FILE)) &&
+ if (node->nd_mid == idAREF && !private_recv_p(node) && node->nd_args &&
+ nd_type_p(node->nd_args, NODE_LIST) && node->nd_args->nd_alen == 1 &&
+ nd_type_p(node->nd_args->nd_head, NODE_STR) &&
ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
- !frozen_string_literal_p(iseq) &&
+ !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
- VALUE str = get_string_value(RNODE_LIST(get_nd_args(node))->nd_head);
- CHECK(COMPILE(ret, "recv", get_nd_recv(node)));
+ VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
+ CHECK(COMPILE(ret, "recv", node->nd_recv));
ADD_INSN2(ret, line_node, opt_aref_with, str,
new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE));
RB_OBJ_WRITTEN(iseq, Qundef, str);
@@ -8843,12 +8129,12 @@ iseq_builtin_function_name(const enum node_type type, const NODE *recv, ID mid)
if (recv) {
switch (nd_type(recv)) {
case NODE_VCALL:
- if (RNODE_VCALL(recv)->nd_mid == rb_intern("__builtin")) {
+ if (recv->nd_mid == rb_intern("__builtin")) {
return name;
}
break;
case NODE_CONST:
- if (RNODE_CONST(recv)->nd_vid == rb_intern("Primitive")) {
+ if (recv->nd_vid == rb_intern("Primitive")) {
return name;
}
break;
@@ -8929,75 +8215,16 @@ delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *arg
}
}
-// Compile Primitive.attr! :leaf, ...
-static int
-compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
-{
- VALUE symbol;
- VALUE string;
- if (!node) goto no_arg;
- while (node) {
- if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
- const NODE *next = RNODE_LIST(node)->nd_next;
-
- node = RNODE_LIST(node)->nd_head;
- if (!node) goto no_arg;
- switch (nd_type(node)) {
- case NODE_SYM:
- symbol = rb_node_sym_string_val(node);
- break;
- default:
- goto bad_arg;
- }
-
- if (!SYMBOL_P(symbol)) goto non_symbol_arg;
-
- string = rb_sym_to_s(symbol);
- if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
- ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
- }
- else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
- ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
- }
- else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
- iseq_set_use_block(iseq);
- }
- else {
- goto unknown_arg;
- }
- node = next;
- }
- return COMPILE_OK;
- no_arg:
- COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
- return COMPILE_NG;
- non_symbol_arg:
- COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
- return COMPILE_NG;
- unknown_arg:
- COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
- return COMPILE_NG;
- bad_arg:
- UNKNOWN_NODE("attr!", node, COMPILE_NG);
-}
-
static int
compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
{
- VALUE name;
-
if (!node) goto no_arg;
if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
- if (RNODE_LIST(node)->nd_next) goto too_many_arg;
- node = RNODE_LIST(node)->nd_head;
+ if (node->nd_next) goto too_many_arg;
+ node = node->nd_head;
if (!node) goto no_arg;
- switch (nd_type(node)) {
- case NODE_SYM:
- name = rb_node_sym_string_val(node);
- break;
- default:
- goto bad_arg;
- }
+ if (!nd_type_p(node, NODE_LIT)) goto bad_arg;
+ VALUE name = node->nd_lit;
if (!SYMBOL_P(name)) goto non_symbol_arg;
if (!popped) {
compile_lvar(iseq, ret, line_node, SYM2ID(name));
@@ -9021,8 +8248,8 @@ static NODE *
mandatory_node(const rb_iseq_t *iseq, const NODE *cond_node)
{
const NODE *node = ISEQ_COMPILE_DATA(iseq)->root_node;
- if (nd_type(node) == NODE_IF && RNODE_IF(node)->nd_cond == cond_node) {
- return RNODE_IF(node)->nd_body;
+ if (nd_type(node) == NODE_IF && node->nd_cond == cond_node) {
+ return node->nd_body;
}
else {
rb_bug("mandatory_node: can't find mandatory node");
@@ -9036,9 +8263,8 @@ compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const N
struct rb_args_info args = {
.pre_args_num = ISEQ_BODY(iseq)->param.lead_num,
};
- rb_node_args_t args_node;
- rb_node_init(RNODE(&args_node), NODE_ARGS);
- args_node.nd_ainfo = args;
+ NODE args_node;
+ rb_node_init(&args_node, NODE_ARGS, 0, 0, (VALUE)&args);
// local table without non-mandatory parameters
const int skip_local_size = ISEQ_BODY(iseq)->param.size - ISEQ_BODY(iseq)->param.lead_num;
@@ -9059,21 +8285,24 @@ compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const N
tbl->ids[i] = ISEQ_BODY(iseq)->local_table[i + skip_local_size];
}
- rb_node_scope_t scope_node;
- rb_node_init(RNODE(&scope_node), NODE_SCOPE);
- scope_node.nd_tbl = tbl;
- scope_node.nd_body = mandatory_node(iseq, node);
- scope_node.nd_args = &args_node;
+ NODE scope_node;
+ rb_node_init(&scope_node, NODE_SCOPE, (VALUE)tbl, (VALUE)mandatory_node(iseq, node), (VALUE)&args_node);
- VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
+ rb_ast_body_t ast = {
+ .root = &scope_node,
+ .compile_option = 0,
+ .script_lines = ISEQ_BODY(iseq)->variable.script_lines,
+ };
+
+ int prev_inline_index = GET_VM()->builtin_inline_index;
ISEQ_BODY(iseq)->mandatory_only_iseq =
- rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
+ rb_iseq_new_with_opt(&ast, rb_iseq_base_label(iseq),
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
nd_line(line_node), NULL, 0,
- ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
- ISEQ_BODY(iseq)->variable.script_lines);
+ ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option);
+ GET_VM()->builtin_inline_index = prev_inline_index;
ALLOCV_END(idtmp);
return COMPILE_OK;
}
@@ -9082,15 +8311,15 @@ static int
compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, const NODE *line_node, int popped,
const rb_iseq_t *parent_block, LINK_ANCHOR *args, const char *builtin_func)
{
- NODE *args_node = get_nd_args(node);
+ NODE *args_node = node->nd_args;
if (parent_block != NULL) {
- COMPILE_ERROR(ERROR_ARGS_AT(line_node) "should not call builtins here.");
+ COMPILE_ERROR(iseq, nd_line(line_node), "should not call builtins here.");
return COMPILE_NG;
}
else {
# define BUILTIN_INLINE_PREFIX "_bi"
- char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
+ char inline_func[DECIMAL_SIZE_OF_BITS(sizeof(int) * CHAR_BIT) + sizeof(BUILTIN_INLINE_PREFIX)];
bool cconst = false;
retry:;
const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
@@ -9105,10 +8334,13 @@ compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NOD
}
else if (strcmp("cinit!", builtin_func) == 0) {
// ignore
+ GET_VM()->builtin_inline_index++;
return COMPILE_OK;
}
else if (strcmp("attr!", builtin_func) == 0) {
- return compile_builtin_attr(iseq, args_node);
+ // There's only "inline" attribute for now
+ ISEQ_BODY(iseq)->builtin_inline_p = true;
+ return COMPILE_OK;
}
else if (strcmp("arg!", builtin_func) == 0) {
return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
@@ -9132,7 +8364,10 @@ compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NOD
return COMPILE_NG;
}
- int inline_index = nd_line(node);
+ if (GET_VM()->builtin_inline_index == INT_MAX) {
+ rb_bug("builtin inline function index overflow:%s", builtin_func);
+ }
+ int inline_index = GET_VM()->builtin_inline_index++;
snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
builtin_func = inline_func;
args_node = NULL;
@@ -9181,7 +8416,7 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
*/
DECL_ANCHOR(recv);
DECL_ANCHOR(args);
- ID mid = get_node_call_nd_mid(node);
+ ID mid = node->nd_mid;
VALUE argc;
unsigned int flag = 0;
struct rb_callinfo_kwarg *keywords = NULL;
@@ -9229,7 +8464,20 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
labels_table = st_init_numtable();
ISEQ_COMPILE_DATA(iseq)->labels_table = labels_table;
}
- {
+ if (nd_type_p(node->nd_args->nd_head, NODE_LIT) &&
+ SYMBOL_P(node->nd_args->nd_head->nd_lit)) {
+
+ label_name = node->nd_args->nd_head->nd_lit;
+ if (!st_lookup(labels_table, (st_data_t)label_name, &data)) {
+ label = NEW_LABEL(nd_line(line_node));
+ label->position = nd_line(line_node);
+ st_insert(labels_table, (st_data_t)label_name, (st_data_t)label);
+ }
+ else {
+ label = (LABEL *)data;
+ }
+ }
+ else {
COMPILE_ERROR(ERROR_ARGS "invalid goto/label format");
return COMPILE_NG;
}
@@ -9247,7 +8495,7 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
const char *builtin_func;
if (UNLIKELY(iseq_has_builtin_function_table(iseq)) &&
- (builtin_func = iseq_builtin_function_name(type, get_nd_recv(node), mid)) != NULL) {
+ (builtin_func = iseq_builtin_function_name(type, node->nd_recv, mid)) != NULL) {
return compile_builtin_function_call(iseq, ret, node, line_node, popped, parent_block, args, builtin_func);
}
@@ -9257,16 +8505,16 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
int idx, level;
if (mid == idCall &&
- nd_type_p(get_nd_recv(node), NODE_LVAR) &&
- iseq_block_param_id_p(iseq, RNODE_LVAR(get_nd_recv(node))->nd_vid, &idx, &level)) {
- ADD_INSN2(recv, get_nd_recv(node), getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
+ nd_type_p(node->nd_recv, NODE_LVAR) &&
+ iseq_block_param_id_p(iseq, node->nd_recv->nd_vid, &idx, &level)) {
+ ADD_INSN2(recv, node->nd_recv, getblockparamproxy, INT2FIX(idx + VM_ENV_DATA_SIZE - 1), INT2FIX(level));
}
else if (private_recv_p(node)) {
ADD_INSN(recv, node, putself);
flag |= VM_CALL_FCALL;
}
else {
- CHECK(COMPILE(recv, "recv", get_nd_recv(node)));
+ CHECK(COMPILE(recv, "recv", node->nd_recv));
}
if (type == NODE_QCALL) {
@@ -9280,7 +8528,7 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
/* args */
if (type != NODE_VCALL) {
- argc = setup_args(iseq, args, get_nd_args(node), &flag, &keywords);
+ argc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
CHECK(!NIL_P(argc));
}
else {
@@ -9301,9 +8549,6 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
flag |= VM_CALL_FCALL;
}
- if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
- ADD_INSN(ret, line_node, splatkw);
- }
ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
@@ -9320,7 +8565,8 @@ compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
VALUE argc;
unsigned int flag = 0;
int asgnflag = 0;
- ID id = RNODE_OP_ASGN1(node)->nd_mid;
+ ID id = node->nd_mid;
+ int boff = 0;
/*
* a[x] (op)= y
@@ -9348,20 +8594,22 @@ compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
if (!popped) {
ADD_INSN(ret, node, putnil);
}
- asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node, RNODE_OP_ASGN1(node)->nd_recv);
+ asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node);
CHECK(asgnflag != -1);
- switch (nd_type(RNODE_OP_ASGN1(node)->nd_index)) {
+ switch (nd_type(node->nd_args->nd_head)) {
case NODE_ZLIST:
argc = INT2FIX(0);
break;
+ case NODE_BLOCK_PASS:
+ boff = 1;
+ /* fall through */
default:
- argc = setup_args(iseq, ret, RNODE_OP_ASGN1(node)->nd_index, &flag, NULL);
+ argc = setup_args(iseq, ret, node->nd_args->nd_head, &flag, NULL);
CHECK(!NIL_P(argc));
}
- int dup_argn = FIX2INT(argc) + 1;
- ADD_INSN1(ret, node, dupn, INT2FIX(dup_argn));
+ ADD_INSN1(ret, node, dupn, FIXNUM_INC(argc, 1 + boff));
flag |= asgnflag;
- ADD_SEND_R(ret, node, idAREF, argc, NULL, INT2FIX(flag & ~VM_CALL_ARGS_SPLAT_MUT), NULL);
+ ADD_SEND_WITH_FLAG(ret, node, idAREF, argc, INT2FIX(flag));
if (id == idOROP || id == idANDOP) {
/* a[x] ||= y or a[x] &&= y
@@ -9384,63 +8632,64 @@ compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
}
ADD_INSN(ret, node, pop);
- CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
+ CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
if (!popped) {
- ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
+ ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
}
if (flag & VM_CALL_ARGS_SPLAT) {
- if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
+ ADD_INSN1(ret, node, newarray, INT2FIX(1));
+ if (boff > 0) {
+ ADD_INSN1(ret, node, dupn, INT2FIX(3));
ADD_INSN(ret, node, swap);
- ADD_INSN1(ret, node, splatarray, Qtrue);
- ADD_INSN(ret, node, swap);
- flag |= VM_CALL_ARGS_SPLAT_MUT;
+ ADD_INSN(ret, node, pop);
}
- ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
- ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
+ ADD_INSN(ret, node, concatarray);
+ if (boff > 0) {
+ ADD_INSN1(ret, node, setn, INT2FIX(3));
+ ADD_INSN(ret, node, pop);
+ ADD_INSN(ret, node, pop);
+ }
+ ADD_SEND_WITH_FLAG(ret, node, idASET, argc, INT2FIX(flag));
}
else {
- ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
+ if (boff > 0)
+ ADD_INSN(ret, node, swap);
+ ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
}
ADD_INSN(ret, node, pop);
ADD_INSNL(ret, node, jump, lfin);
ADD_LABEL(ret, label);
if (!popped) {
- ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
+ ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
}
- ADD_INSN1(ret, node, adjuststack, INT2FIX(dup_argn+1));
+ ADD_INSN1(ret, node, adjuststack, FIXNUM_INC(argc, 2+boff));
ADD_LABEL(ret, lfin);
}
else {
- CHECK(COMPILE(ret, "NODE_OP_ASGN1 nd_rvalue: ", RNODE_OP_ASGN1(node)->nd_rvalue));
+ CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
ADD_SEND(ret, node, id, INT2FIX(1));
if (!popped) {
- ADD_INSN1(ret, node, setn, INT2FIX(dup_argn+1));
+ ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
}
if (flag & VM_CALL_ARGS_SPLAT) {
- if (flag & VM_CALL_KW_SPLAT) {
- ADD_INSN1(ret, node, topn, INT2FIX(2));
- if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
- ADD_INSN1(ret, node, splatarray, Qtrue);
- flag |= VM_CALL_ARGS_SPLAT_MUT;
- }
+ ADD_INSN1(ret, node, newarray, INT2FIX(1));
+ if (boff > 0) {
+ ADD_INSN1(ret, node, dupn, INT2FIX(3));
ADD_INSN(ret, node, swap);
- ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
- ADD_INSN1(ret, node, setn, INT2FIX(2));
ADD_INSN(ret, node, pop);
}
- else {
- if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
- ADD_INSN(ret, node, swap);
- ADD_INSN1(ret, node, splatarray, Qtrue);
- ADD_INSN(ret, node, swap);
- flag |= VM_CALL_ARGS_SPLAT_MUT;
- }
- ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
+ ADD_INSN(ret, node, concatarray);
+ if (boff > 0) {
+ ADD_INSN1(ret, node, setn, INT2FIX(3));
+ ADD_INSN(ret, node, pop);
+ ADD_INSN(ret, node, pop);
}
- ADD_SEND_R(ret, node, idASET, argc, NULL, INT2FIX(flag), NULL);
+ ADD_SEND_WITH_FLAG(ret, node, idASET, argc, INT2FIX(flag));
}
else {
- ADD_SEND_R(ret, node, idASET, FIXNUM_INC(argc, 1), NULL, INT2FIX(flag), NULL);
+ if (boff > 0)
+ ADD_INSN(ret, node, swap);
+ ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
}
ADD_INSN(ret, node, pop);
}
@@ -9451,8 +8700,8 @@ static int
compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
{
const int line = nd_line(node);
- ID atype = RNODE_OP_ASGN2(node)->nd_mid;
- ID vid = RNODE_OP_ASGN2(node)->nd_vid, aid = rb_id_attrset(vid);
+ ID atype = node->nd_next->nd_mid;
+ ID vid = node->nd_next->nd_vid, aid = rb_id_attrset(vid);
int asgnflag;
LABEL *lfin = NEW_LABEL(line);
LABEL *lcfin = NEW_LABEL(line);
@@ -9510,9 +8759,9 @@ compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
*/
- asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node, RNODE_OP_ASGN2(node)->nd_recv);
+ asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node);
CHECK(asgnflag != -1);
- if (RNODE_OP_ASGN2(node)->nd_aid) {
+ if (node->nd_next->nd_aid) {
lskip = NEW_LABEL(line);
ADD_INSN(ret, node, dup);
ADD_INSNL(ret, node, branchnil, lskip);
@@ -9533,7 +8782,7 @@ compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
if (!popped) {
ADD_INSN(ret, node, pop);
}
- CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
+ CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
if (!popped) {
ADD_INSN(ret, node, swap);
ADD_INSN1(ret, node, topn, INT2FIX(1));
@@ -9549,7 +8798,7 @@ compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
ADD_LABEL(ret, lfin);
}
else {
- CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", RNODE_OP_ASGN2(node)->nd_value));
+ CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
ADD_SEND(ret, node, atype, INT2FIX(1));
if (!popped) {
ADD_INSN(ret, node, swap);
@@ -9567,8 +8816,6 @@ compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
return COMPILE_OK;
}
-static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
-
static int
compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
{
@@ -9577,21 +8824,21 @@ compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
LABEL *lassign = 0;
ID mid;
- switch (nd_type(RNODE_OP_CDECL(node)->nd_head)) {
+ switch (nd_type(node->nd_head)) {
case NODE_COLON3:
ADD_INSN1(ret, node, putobject, rb_cObject);
break;
case NODE_COLON2:
- CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", RNODE_COLON2(RNODE_OP_CDECL(node)->nd_head)->nd_head));
+ CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head));
break;
default:
COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
- ruby_node_name(nd_type(RNODE_OP_CDECL(node)->nd_head)));
+ ruby_node_name(nd_type(node->nd_head)));
return COMPILE_NG;
}
- mid = get_node_colon_nd_mid(RNODE_OP_CDECL(node)->nd_head);
+ mid = node->nd_head->nd_mid;
/* cref */
- if (RNODE_OP_CDECL(node)->nd_aid == idOROP) {
+ if (node->nd_aid == idOROP) {
lassign = NEW_LABEL(line);
ADD_INSN(ret, node, dup); /* cref cref */
ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
@@ -9602,17 +8849,17 @@ compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
ADD_INSN1(ret, node, putobject, Qtrue);
ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
- if (RNODE_OP_CDECL(node)->nd_aid == idOROP || RNODE_OP_CDECL(node)->nd_aid == idANDOP) {
+ if (node->nd_aid == idOROP || node->nd_aid == idANDOP) {
lfin = NEW_LABEL(line);
if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
- if (RNODE_OP_CDECL(node)->nd_aid == idOROP)
+ if (node->nd_aid == idOROP)
ADD_INSNL(ret, node, branchif, lfin);
else /* idANDOP */
ADD_INSNL(ret, node, branchunless, lfin);
/* cref [obj] */
if (!popped) ADD_INSN(ret, node, pop); /* cref */
if (lassign) ADD_LABEL(ret, lassign);
- CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
+ CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
/* cref value */
if (popped)
ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
@@ -9626,9 +8873,9 @@ compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
ADD_INSN(ret, node, pop); /* [value] */
}
else {
- CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
+ CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
/* cref obj value */
- ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
+ ADD_CALL(ret, node, node->nd_aid, INT2FIX(1));
/* cref value */
ADD_INSN(ret, node, swap); /* value cref */
if (!popped) {
@@ -9647,11 +8894,11 @@ compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
LABEL *lfin = NEW_LABEL(line);
LABEL *lassign;
- if (type == NODE_OP_ASGN_OR && !nd_type_p(RNODE_OP_ASGN_OR(node)->nd_head, NODE_IVAR)) {
+ if (type == NODE_OP_ASGN_OR && !nd_type_p(node->nd_head, NODE_IVAR)) {
LABEL *lfinish[2];
lfinish[0] = lfin;
lfinish[1] = 0;
- defined_expr(iseq, ret, RNODE_OP_ASGN_OR(node)->nd_head, lfinish, Qfalse, false);
+ defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
lassign = lfinish[1];
if (!lassign) {
lassign = NEW_LABEL(line);
@@ -9662,7 +8909,7 @@ compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
lassign = NEW_LABEL(line);
}
- CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", RNODE_OP_ASGN_OR(node)->nd_head));
+ CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head));
if (!popped) {
ADD_INSN(ret, node, dup);
@@ -9680,7 +8927,7 @@ compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
}
ADD_LABEL(ret, lassign);
- CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", RNODE_OP_ASGN_OR(node)->nd_value, popped));
+ CHECK(COMPILE_(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value, popped));
ADD_LABEL(ret, lfin);
return COMPILE_OK;
}
@@ -9694,22 +8941,13 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
unsigned int flag = 0;
struct rb_callinfo_kwarg *keywords = NULL;
const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
- int use_block = 1;
INIT_ANCHOR(args);
ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
-
if (type == NODE_SUPER) {
- VALUE vargc = setup_args(iseq, args, RNODE_SUPER(node)->nd_args, &flag, &keywords);
+ VALUE vargc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
CHECK(!NIL_P(vargc));
argc = FIX2INT(vargc);
- if ((flag & VM_CALL_ARGS_BLOCKARG) && (flag & VM_CALL_KW_SPLAT) && !(flag & VM_CALL_KW_SPLAT_MUT)) {
- ADD_INSN(args, node, splatkw);
- }
-
- if (flag & VM_CALL_ARGS_BLOCKARG) {
- use_block = 0;
- }
}
else {
/* NODE_ZSUPER */
@@ -9727,13 +8965,6 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
ADD_GETLOCAL(args, node, idx, lvar_level);
}
- /* forward ... */
- if (local_body->param.flags.forwardable) {
- flag |= VM_CALL_FORWARDING;
- int idx = local_body->local_table_size - get_local_var_idx(liseq, idDot3);
- ADD_GETLOCAL(args, node, idx, lvar_level);
- }
-
if (local_body->param.flags.has_opt) {
/* optional arguments */
int j;
@@ -9748,7 +8979,7 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
/* rest argument */
int idx = local_body->local_table_size - local_body->param.rest_start;
ADD_GETLOCAL(args, node, idx, lvar_level);
- ADD_INSN1(args, node, splatarray, RBOOL(local_body->param.flags.has_post));
+ ADD_INSN1(args, node, splatarray, Qfalse);
argc = local_body->param.rest_start + 1;
flag |= VM_CALL_ARGS_SPLAT;
@@ -9764,8 +8995,8 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
int idx = local_body->local_table_size - (post_start + j);
ADD_GETLOCAL(args, node, idx, lvar_level);
}
- ADD_INSN1(args, node, pushtoarray, INT2FIX(j));
- flag |= VM_CALL_ARGS_SPLAT_MUT;
+ ADD_INSN1(args, node, newarray, INT2FIX(j));
+ ADD_INSN (args, node, concatarray);
/* argc is settled at above */
}
else {
@@ -9787,11 +9018,14 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
if (local_body->param.flags.has_kwrest) {
int idx = local_body->local_table_size - local_kwd->rest_start;
ADD_GETLOCAL(args, node, idx, lvar_level);
- RUBY_ASSERT(local_kwd->num > 0);
- ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
+ if (local_kwd->num > 0) {
+ ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
+ flag |= VM_CALL_KW_SPLAT_MUT;
+ }
}
else {
ADD_INSN1(args, node, newhash, INT2FIX(0));
+ flag |= VM_CALL_KW_SPLAT_MUT;
}
for (i = 0; i < local_kwd->num; ++i) {
ID id = local_kwd->table[i];
@@ -9800,33 +9034,35 @@ compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
ADD_GETLOCAL(args, node, idx, lvar_level);
}
ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
- flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
+ if (local_body->param.flags.has_rest) {
+ ADD_INSN1(args, node, newarray, INT2FIX(1));
+ ADD_INSN (args, node, concatarray);
+ --argc;
+ }
+ flag |= VM_CALL_KW_SPLAT;
}
else if (local_body->param.flags.has_kwrest) {
int idx = local_body->local_table_size - local_kwd->rest_start;
ADD_GETLOCAL(args, node, idx, lvar_level);
- argc++;
+
+ if (local_body->param.flags.has_rest) {
+ ADD_INSN1(args, node, newarray, INT2FIX(1));
+ ADD_INSN (args, node, concatarray);
+ }
+ else {
+ argc++;
+ }
flag |= VM_CALL_KW_SPLAT;
}
}
- if (use_block && parent_block == NULL) {
- iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
- }
-
flag |= VM_CALL_SUPER | VM_CALL_FCALL;
if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
ADD_INSN(ret, node, putself);
ADD_SEQ(ret, args);
-
- const struct rb_callinfo * ci = new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL);
-
- if (vm_ci_flag(ci) & VM_CALL_FORWARDING) {
- ADD_INSN2(ret, node, invokesuperforward, ci, parent_block);
- }
- else {
- ADD_INSN2(ret, node, invokesuper, ci, parent_block);
- }
+ ADD_INSN2(ret, node, invokesuper,
+ new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL),
+ parent_block);
if (popped) {
ADD_INSN(ret, node, pop);
@@ -9853,8 +9089,8 @@ compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
default: /* valid */;
}
- if (RNODE_YIELD(node)->nd_head) {
- argc = setup_args(iseq, args, RNODE_YIELD(node)->nd_head, &flag, &keywords);
+ if (node->nd_head) {
+ argc = setup_args(iseq, args, node->nd_head, &flag, &keywords);
CHECK(!NIL_P(argc));
}
else {
@@ -9863,7 +9099,6 @@ compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
ADD_SEQ(ret, args);
ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
- iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
if (popped) {
ADD_INSN(ret, node, pop);
@@ -9889,17 +9124,17 @@ compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
INIT_ANCHOR(val);
switch ((int)type) {
case NODE_MATCH:
- ADD_INSN1(recv, node, putobject, rb_node_regx_string_val(node));
+ ADD_INSN1(recv, node, putobject, node->nd_lit);
ADD_INSN2(val, node, getspecial, INT2FIX(0),
INT2FIX(0));
break;
case NODE_MATCH2:
- CHECK(COMPILE(recv, "receiver", RNODE_MATCH2(node)->nd_recv));
- CHECK(COMPILE(val, "value", RNODE_MATCH2(node)->nd_value));
+ CHECK(COMPILE(recv, "receiver", node->nd_recv));
+ CHECK(COMPILE(val, "value", node->nd_value));
break;
case NODE_MATCH3:
- CHECK(COMPILE(recv, "receiver", RNODE_MATCH3(node)->nd_value));
- CHECK(COMPILE(val, "value", RNODE_MATCH3(node)->nd_recv));
+ CHECK(COMPILE(recv, "receiver", node->nd_value));
+ CHECK(COMPILE(val, "value", node->nd_recv));
break;
}
@@ -9907,8 +9142,8 @@ compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
ADD_SEQ(ret, val);
ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
- if (nd_type_p(node, NODE_MATCH2) && RNODE_MATCH2(node)->nd_args) {
- compile_named_capture_assign(iseq, ret, RNODE_MATCH2(node)->nd_args);
+ if (node->nd_args) {
+ compile_named_capture_assign(iseq, ret, node->nd_args);
}
if (popped) {
@@ -9920,7 +9155,7 @@ compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, i
static int
compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
{
- if (rb_is_const_id(RNODE_COLON2(node)->nd_mid)) {
+ if (rb_is_const_id(node->nd_mid)) {
/* constant */
VALUE segments;
if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache &&
@@ -9950,8 +9185,8 @@ compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
else {
/* function call */
ADD_CALL_RECEIVER(ret, node);
- CHECK(COMPILE(ret, "colon2#nd_head", RNODE_COLON2(node)->nd_head));
- ADD_CALL(ret, node, RNODE_COLON2(node)->nd_mid, INT2FIX(1));
+ CHECK(COMPILE(ret, "colon2#nd_head", node->nd_head));
+ ADD_CALL(ret, node, node->nd_mid, INT2FIX(1));
}
if (popped) {
ADD_INSN(ret, node, pop);
@@ -9962,19 +9197,19 @@ compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
static int
compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
{
- debugi("colon3#nd_mid", RNODE_COLON3(node)->nd_mid);
+ debugi("colon3#nd_mid", node->nd_mid);
/* add cache insn */
if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
ISEQ_BODY(iseq)->ic_size++;
- VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(RNODE_COLON3(node)->nd_mid));
+ VALUE segments = rb_ary_new_from_args(2, ID2SYM(idNULL), ID2SYM(node->nd_mid));
ADD_INSN1(ret, node, opt_getconstant_path, segments);
RB_OBJ_WRITTEN(iseq, Qundef, segments);
}
else {
ADD_INSN1(ret, node, putobject, rb_cObject);
ADD_INSN1(ret, node, putobject, Qtrue);
- ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_COLON3(node)->nd_mid));
+ ADD_INSN1(ret, node, getconstant, ID2SYM(node->nd_mid));
}
if (popped) {
@@ -9987,13 +9222,13 @@ static int
compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
{
VALUE flag = INT2FIX(excl);
- const NODE *b = RNODE_DOT2(node)->nd_beg;
- const NODE *e = RNODE_DOT2(node)->nd_end;
+ const NODE *b = node->nd_beg;
+ const NODE *e = node->nd_end;
if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
if (!popped) {
- VALUE bv = optimized_range_item(b);
- VALUE ev = optimized_range_item(e);
+ VALUE bv = nd_type_p(b, NODE_LIT) ? b->nd_lit : Qnil;
+ VALUE ev = nd_type_p(e, NODE_LIT) ? e->nd_lit : Qnil;
VALUE val = rb_range_new(bv, ev, excl);
ADD_INSN1(ret, node, putobject, val);
RB_OBJ_WRITTEN(iseq, Qundef, val);
@@ -10042,20 +9277,14 @@ compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
{
struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
LABEL *end_label = NEW_LABEL(nd_line(node));
- const NODE *default_value = get_nd_value(RNODE_KW_ARG(node)->nd_body);
+ const NODE *default_value = node->nd_body->nd_value;
if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
/* required argument. do nothing */
COMPILE_ERROR(ERROR_ARGS "unreachable");
return COMPILE_NG;
}
- else if (nd_type_p(default_value, NODE_SYM) ||
- nd_type_p(default_value, NODE_REGX) ||
- nd_type_p(default_value, NODE_LINE) ||
- nd_type_p(default_value, NODE_INTEGER) ||
- nd_type_p(default_value, NODE_FLOAT) ||
- nd_type_p(default_value, NODE_RATIONAL) ||
- nd_type_p(default_value, NODE_IMAGINARY) ||
+ else if (nd_type_p(default_value, NODE_LIT) ||
nd_type_p(default_value, NODE_NIL) ||
nd_type_p(default_value, NODE_TRUE) ||
nd_type_p(default_value, NODE_FALSE)) {
@@ -10072,7 +9301,7 @@ compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node,
ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
ADD_INSNL(ret, node, branchif, end_label);
- CHECK(COMPILE_POPPED(ret, "keyword default argument", RNODE_KW_ARG(node)->nd_body));
+ CHECK(COMPILE_POPPED(ret, "keyword default argument", node->nd_body));
ADD_LABEL(ret, end_label);
}
return COMPILE_OK;
@@ -10084,7 +9313,7 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
DECL_ANCHOR(recv);
DECL_ANCHOR(args);
unsigned int flag = 0;
- ID mid = RNODE_ATTRASGN(node)->nd_mid;
+ ID mid = node->nd_mid;
VALUE argc;
LABEL *else_label = NULL;
VALUE branches = Qfalse;
@@ -10092,16 +9321,17 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
/* optimization shortcut
* obj["literal"] = value -> opt_aset_with(obj, "literal", value)
*/
- if (mid == idASET && !private_recv_p(node) && RNODE_ATTRASGN(node)->nd_args &&
- nd_type_p(RNODE_ATTRASGN(node)->nd_args, NODE_LIST) && RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->as.nd_alen == 2 &&
- (nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_STR) || nd_type_p(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head, NODE_FILE)) &&
+ if (!ISEQ_COMPILE_DATA(iseq)->in_masgn &&
+ mid == idASET && !private_recv_p(node) && node->nd_args &&
+ nd_type_p(node->nd_args, NODE_LIST) && node->nd_args->nd_alen == 2 &&
+ nd_type_p(node->nd_args->nd_head, NODE_STR) &&
ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
- !frozen_string_literal_p(iseq) &&
+ !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
{
- VALUE str = get_string_value(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_head);
- CHECK(COMPILE(ret, "recv", RNODE_ATTRASGN(node)->nd_recv));
- CHECK(COMPILE(ret, "value", RNODE_LIST(RNODE_LIST(RNODE_ATTRASGN(node)->nd_args)->nd_next)->nd_head));
+ VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
+ CHECK(COMPILE(ret, "recv", node->nd_recv));
+ CHECK(COMPILE(ret, "value", node->nd_args->nd_next->nd_head));
if (!popped) {
ADD_INSN(ret, node, swap);
ADD_INSN1(ret, node, topn, INT2FIX(1));
@@ -10115,10 +9345,10 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
INIT_ANCHOR(recv);
INIT_ANCHOR(args);
- argc = setup_args(iseq, args, RNODE_ATTRASGN(node)->nd_args, &flag, NULL);
+ argc = setup_args(iseq, args, node->nd_args, &flag, NULL);
CHECK(!NIL_P(argc));
- int asgnflag = COMPILE_RECV(recv, "recv", node, RNODE_ATTRASGN(node)->nd_recv);
+ int asgnflag = COMPILE_RECV(recv, "recv", node);
CHECK(asgnflag != -1);
flag |= (unsigned int)asgnflag;
@@ -10135,7 +9365,16 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
ADD_SEQ(ret, recv);
ADD_SEQ(ret, args);
- if (flag & VM_CALL_ARGS_SPLAT) {
+ if (flag & VM_CALL_ARGS_BLOCKARG) {
+ ADD_INSN1(ret, node, topn, INT2FIX(1));
+ if (flag & VM_CALL_ARGS_SPLAT) {
+ ADD_INSN1(ret, node, putobject, INT2FIX(-1));
+ ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
+ }
+ ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 3));
+ ADD_INSN (ret, node, pop);
+ }
+ else if (flag & VM_CALL_ARGS_SPLAT) {
ADD_INSN(ret, node, dup);
ADD_INSN1(ret, node, putobject, INT2FIX(-1));
ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
@@ -10156,367 +9395,6 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
return COMPILE_OK;
}
-static int
-compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
-{
- ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_SEQ(ret, sub);
-
- if (copy) {
- /*
- * NEW_CALL(fcore, rb_intern("make_shareable_copy"),
- * NEW_LIST(value, loc), loc);
- */
- ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
- }
- else {
- /*
- * NEW_CALL(fcore, rb_intern("make_shareable"),
- * NEW_LIST(value, loc), loc);
- */
- ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
- }
-
- return COMPILE_OK;
-}
-
-static VALUE
-node_const_decl_val(const NODE *node)
-{
- VALUE path;
- switch (nd_type(node)) {
- case NODE_CDECL:
- if (RNODE_CDECL(node)->nd_vid) {
- path = rb_id2str(RNODE_CDECL(node)->nd_vid);
- goto end;
- }
- else {
- node = RNODE_CDECL(node)->nd_else;
- }
- break;
- case NODE_COLON2:
- break;
- case NODE_COLON3:
- // ::Const
- path = rb_str_new_cstr("::");
- rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
- goto end;
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- UNREACHABLE_RETURN(0);
- }
-
- path = rb_ary_new();
- if (node) {
- for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
- rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
- }
- if (node && nd_type_p(node, NODE_CONST)) {
- // Const::Name
- rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
- }
- else if (node && nd_type_p(node, NODE_COLON3)) {
- // ::Const::Name
- rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
- rb_ary_push(path, rb_str_new(0, 0));
- }
- else {
- // expression::Name
- rb_ary_push(path, rb_str_new_cstr("..."));
- }
- path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
- }
- end:
- path = rb_fstring(path);
- return path;
-}
-
-static VALUE
-const_decl_path(NODE *dest)
-{
- VALUE path = Qnil;
- if (!nd_type_p(dest, NODE_CALL)) {
- path = node_const_decl_val(dest);
- }
- return path;
-}
-
-static int
-compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
-{
- /*
- *. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
- */
- VALUE path = const_decl_path(dest);
- ADD_INSN1(ret, value, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
- ADD_INSN1(ret, value, putobject, path);
- RB_OBJ_WRITTEN(iseq, Qundef, path);
- ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
-
- return COMPILE_OK;
-}
-
-#ifndef SHAREABLE_BARE_EXPRESSION
-#define SHAREABLE_BARE_EXPRESSION 1
-#endif
-
-static int
-compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, NODE *dest, const NODE *node, size_t level, VALUE *value_p, int *shareable_literal_p)
-{
-# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
- compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
- VALUE lit = Qnil;
- DECL_ANCHOR(anchor);
-
- enum node_type type = nd_type(node);
- switch (type) {
- case NODE_TRUE:
- *value_p = Qtrue;
- goto compile;
- case NODE_FALSE:
- *value_p = Qfalse;
- goto compile;
- case NODE_NIL:
- *value_p = Qnil;
- goto compile;
- case NODE_SYM:
- *value_p = rb_node_sym_string_val(node);
- goto compile;
- case NODE_REGX:
- *value_p = rb_node_regx_string_val(node);
- goto compile;
- case NODE_LINE:
- *value_p = rb_node_line_lineno_val(node);
- goto compile;
- case NODE_INTEGER:
- *value_p = rb_node_integer_literal_val(node);
- goto compile;
- case NODE_FLOAT:
- *value_p = rb_node_float_literal_val(node);
- goto compile;
- case NODE_RATIONAL:
- *value_p = rb_node_rational_literal_val(node);
- goto compile;
- case NODE_IMAGINARY:
- *value_p = rb_node_imaginary_literal_val(node);
- goto compile;
- case NODE_ENCODING:
- *value_p = rb_node_encoding_val(node);
-
- compile:
- CHECK(COMPILE(ret, "shareable_literal_constant", node));
- *shareable_literal_p = 1;
- return COMPILE_OK;
-
- case NODE_DSTR:
- CHECK(COMPILE(ret, "shareable_literal_constant", node));
- if (shareable == rb_parser_shareable_literal) {
- /*
- * NEW_CALL(node, idUMinus, 0, loc);
- *
- * -"#{var}"
- */
- ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
- }
- *value_p = Qundef;
- *shareable_literal_p = 1;
- return COMPILE_OK;
-
- case NODE_STR:{
- VALUE lit = rb_node_str_string_val(node);
- ADD_INSN1(ret, node, putobject, lit);
- RB_OBJ_WRITTEN(iseq, Qundef, lit);
- *value_p = lit;
- *shareable_literal_p = 1;
-
- return COMPILE_OK;
- }
-
- case NODE_FILE:{
- VALUE lit = rb_node_file_path_val(node);
- ADD_INSN1(ret, node, putobject, lit);
- RB_OBJ_WRITTEN(iseq, Qundef, lit);
- *value_p = lit;
- *shareable_literal_p = 1;
-
- return COMPILE_OK;
- }
-
- case NODE_ZLIST:{
- VALUE lit = rb_ary_new();
- OBJ_FREEZE(lit);
- ADD_INSN1(ret, node, putobject, lit);
- RB_OBJ_WRITTEN(iseq, Qundef, lit);
- *value_p = lit;
- *shareable_literal_p = 1;
-
- return COMPILE_OK;
- }
-
- case NODE_LIST:{
- INIT_ANCHOR(anchor);
- lit = rb_ary_new();
- for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
- VALUE val;
- int shareable_literal_p2;
- NODE *elt = RNODE_LIST(n)->nd_head;
- if (elt) {
- CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
- if (shareable_literal_p2) {
- /* noop */
- }
- else if (RTEST(lit)) {
- rb_ary_clear(lit);
- lit = Qfalse;
- }
- }
- if (RTEST(lit)) {
- if (!UNDEF_P(val)) {
- rb_ary_push(lit, val);
- }
- else {
- rb_ary_clear(lit);
- lit = Qnil; /* make shareable at runtime */
- }
- }
- }
- break;
- }
- case NODE_HASH:{
- if (!RNODE_HASH(node)->nd_brace) {
- *value_p = Qundef;
- *shareable_literal_p = 0;
- return COMPILE_OK;
- }
-
- INIT_ANCHOR(anchor);
- lit = rb_hash_new();
- for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
- VALUE key_val;
- VALUE value_val;
- int shareable_literal_p2;
- NODE *key = RNODE_LIST(n)->nd_head;
- NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
- if (key) {
- CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
- if (shareable_literal_p2) {
- /* noop */
- }
- else if (RTEST(lit)) {
- rb_hash_clear(lit);
- lit = Qfalse;
- }
- }
- if (val) {
- CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
- if (shareable_literal_p2) {
- /* noop */
- }
- else if (RTEST(lit)) {
- rb_hash_clear(lit);
- lit = Qfalse;
- }
- }
- if (RTEST(lit)) {
- if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
- rb_hash_aset(lit, key_val, value_val);
- }
- else {
- rb_hash_clear(lit);
- lit = Qnil; /* make shareable at runtime */
- }
- }
- }
- break;
- }
-
- default:
- if (shareable == rb_parser_shareable_literal &&
- (SHAREABLE_BARE_EXPRESSION || level > 0)) {
- CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
- *value_p = Qundef;
- *shareable_literal_p = 1;
- return COMPILE_OK;
- }
- CHECK(COMPILE(ret, "shareable_literal_constant", node));
- *value_p = Qundef;
- *shareable_literal_p = 0;
- return COMPILE_OK;
- }
-
- /* Array or Hash */
- if (!lit) {
- if (nd_type(node) == NODE_LIST) {
- ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
- }
- else if (nd_type(node) == NODE_HASH) {
- int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
- ADD_INSN1(anchor, node, newhash, INT2FIX(len));
- }
- *value_p = Qundef;
- *shareable_literal_p = 0;
- ADD_SEQ(ret, anchor);
- return COMPILE_OK;
- }
- if (NIL_P(lit)) {
- // if shareable_literal, all elements should have been ensured
- // as shareable
- if (nd_type(node) == NODE_LIST) {
- ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
- }
- else if (nd_type(node) == NODE_HASH) {
- int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
- ADD_INSN1(anchor, node, newhash, INT2FIX(len));
- }
- CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
- *value_p = Qundef;
- *shareable_literal_p = 1;
- }
- else {
- VALUE val = rb_ractor_make_shareable(lit);
- ADD_INSN1(ret, node, putobject, val);
- RB_OBJ_WRITTEN(iseq, Qundef, val);
- *value_p = val;
- *shareable_literal_p = 1;
- }
-
- return COMPILE_OK;
-}
-
-static int
-compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
-{
- int literal_p = 0;
- VALUE val;
- DECL_ANCHOR(anchor);
- INIT_ANCHOR(anchor);
-
- switch (shareable) {
- case rb_parser_shareable_none:
- CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
- return COMPILE_OK;
-
- case rb_parser_shareable_literal:
- CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
- ADD_SEQ(ret, anchor);
- return COMPILE_OK;
-
- case rb_parser_shareable_copy:
- case rb_parser_shareable_everything:
- CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
- if (!literal_p) {
- CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
- }
- else {
- ADD_SEQ(ret, anchor);
- }
- return COMPILE_OK;
- default:
- rb_bug("unexpected rb_parser_shareability: %d", shareable);
- }
-}
-
static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
/**
compile each node
@@ -10533,7 +9411,8 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int poppe
int lineno = ISEQ_COMPILE_DATA(iseq)->last_line;
if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq));
debugs("node: NODE_NIL(implicit)\n");
- ADD_SYNTHETIC_INSN(ret, lineno, -1, putnil);
+ NODE dummy_line_node = generate_dummy_line_node(lineno, -1);
+ ADD_INSN(ret, &dummy_line_node, putnil);
}
return COMPILE_OK;
}
@@ -10551,7 +9430,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
/* ignore */
}
else {
- if (nd_fl_newline(node)) {
+ if (node->flags & NODE_FL_NEWLINE) {
int event = RUBY_EVENT_LINE;
ISEQ_COMPILE_DATA(iseq)->last_line = line;
if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
@@ -10606,7 +9485,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
CHECK(compile_retry(iseq, ret, node, popped));
break;
case NODE_BEGIN:{
- CHECK(COMPILE_(ret, "NODE_BEGIN", RNODE_BEGIN(node)->nd_body, popped));
+ CHECK(COMPILE_(ret, "NODE_BEGIN", node->nd_body, popped));
break;
}
case NODE_RESCUE:
@@ -10622,7 +9501,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
case NODE_AND:
case NODE_OR:{
LABEL *end_label = NEW_LABEL(line);
- CHECK(COMPILE(ret, "nd_1st", RNODE_OR(node)->nd_1st));
+ CHECK(COMPILE(ret, "nd_1st", node->nd_1st));
if (!popped) {
ADD_INSN(ret, node, dup);
}
@@ -10635,22 +9514,25 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
if (!popped) {
ADD_INSN(ret, node, pop);
}
- CHECK(COMPILE_(ret, "nd_2nd", RNODE_OR(node)->nd_2nd, popped));
+ CHECK(COMPILE_(ret, "nd_2nd", node->nd_2nd, popped));
ADD_LABEL(ret, end_label);
break;
}
case NODE_MASGN:{
+ bool prev_in_masgn = ISEQ_COMPILE_DATA(iseq)->in_masgn;
+ ISEQ_COMPILE_DATA(iseq)->in_masgn = true;
compile_massign(iseq, ret, node, popped);
+ ISEQ_COMPILE_DATA(iseq)->in_masgn = prev_in_masgn;
break;
}
case NODE_LASGN:{
- ID id = RNODE_LASGN(node)->nd_vid;
+ ID id = node->nd_vid;
int idx = ISEQ_BODY(body->local_iseq)->local_table_size - get_local_var_idx(iseq, id);
debugs("lvar: %s idx: %d\n", rb_id2name(id), idx);
- CHECK(COMPILE(ret, "rvalue", RNODE_LASGN(node)->nd_value));
+ CHECK(COMPILE(ret, "rvalue", node->nd_value));
if (!popped) {
ADD_INSN(ret, node, dup);
@@ -10660,8 +9542,8 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_DASGN: {
int idx, lv, ls;
- ID id = RNODE_DASGN(node)->nd_vid;
- CHECK(COMPILE(ret, "dvalue", RNODE_DASGN(node)->nd_value));
+ ID id = node->nd_vid;
+ CHECK(COMPILE(ret, "dvalue", node->nd_value));
debugi("dassn id", rb_id2str(id) ? id : '*');
if (!popped) {
@@ -10679,27 +9561,27 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_GASGN:{
- CHECK(COMPILE(ret, "lvalue", RNODE_GASGN(node)->nd_value));
+ CHECK(COMPILE(ret, "lvalue", node->nd_value));
if (!popped) {
ADD_INSN(ret, node, dup);
}
- ADD_INSN1(ret, node, setglobal, ID2SYM(RNODE_GASGN(node)->nd_vid));
+ ADD_INSN1(ret, node, setglobal, ID2SYM(node->nd_entry));
break;
}
case NODE_IASGN:{
- CHECK(COMPILE(ret, "lvalue", RNODE_IASGN(node)->nd_value));
+ CHECK(COMPILE(ret, "lvalue", node->nd_value));
if (!popped) {
ADD_INSN(ret, node, dup);
}
ADD_INSN2(ret, node, setinstancevariable,
- ID2SYM(RNODE_IASGN(node)->nd_vid),
- get_ivar_ic_value(iseq,RNODE_IASGN(node)->nd_vid));
+ ID2SYM(node->nd_vid),
+ get_ivar_ic_value(iseq,node->nd_vid));
break;
}
case NODE_CDECL:{
- if (RNODE_CDECL(node)->nd_vid) {
- CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
+ if (node->nd_vid) {
+ CHECK(COMPILE(ret, "lvalue", node->nd_value));
if (!popped) {
ADD_INSN(ret, node, dup);
@@ -10707,11 +9589,11 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- ADD_INSN1(ret, node, setconstant, ID2SYM(RNODE_CDECL(node)->nd_vid));
+ ADD_INSN1(ret, node, setconstant, ID2SYM(node->nd_vid));
}
else {
- compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
- CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
+ compile_cpath(ret, iseq, node->nd_else);
+ CHECK(COMPILE(ret, "lvalue", node->nd_value));
ADD_INSN(ret, node, swap);
if (!popped) {
@@ -10719,18 +9601,18 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
ADD_INSN(ret, node, swap);
}
- ADD_INSN1(ret, node, setconstant, ID2SYM(get_node_colon_nd_mid(RNODE_CDECL(node)->nd_else)));
+ ADD_INSN1(ret, node, setconstant, ID2SYM(node->nd_else->nd_mid));
}
break;
}
case NODE_CVASGN:{
- CHECK(COMPILE(ret, "cvasgn val", RNODE_CVASGN(node)->nd_value));
+ CHECK(COMPILE(ret, "cvasgn val", node->nd_value));
if (!popped) {
ADD_INSN(ret, node, dup);
}
ADD_INSN2(ret, node, setclassvariable,
- ID2SYM(RNODE_CVASGN(node)->nd_vid),
- get_cvar_ic_value(iseq, RNODE_CVASGN(node)->nd_vid));
+ ID2SYM(node->nd_vid),
+ get_cvar_ic_value(iseq,node->nd_vid));
break;
}
case NODE_OP_ASGN1:
@@ -10763,7 +9645,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
CHECK(compile_super(iseq, ret, node, popped, type));
break;
case NODE_LIST:{
- CHECK(compile_array(iseq, ret, node, popped, TRUE) >= 0);
+ CHECK(compile_array(iseq, ret, node, popped) >= 0);
break;
}
case NODE_ZLIST:{
@@ -10772,6 +9654,18 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
break;
}
+ case NODE_VALUES:{
+ const NODE *n = node;
+ if (popped) {
+ COMPILE_ERROR(ERROR_ARGS "NODE_VALUES: must not be popped");
+ }
+ while (n) {
+ CHECK(COMPILE(ret, "values item", n->nd_head));
+ n = n->nd_next;
+ }
+ ADD_INSN1(ret, node, newarray, INT2FIX(node->nd_alen));
+ break;
+ }
case NODE_HASH:
CHECK(compile_hash(iseq, ret, node, FALSE, popped) >= 0);
break;
@@ -10783,18 +9677,18 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
case NODE_LVAR:{
if (!popped) {
- compile_lvar(iseq, ret, node, RNODE_LVAR(node)->nd_vid);
+ compile_lvar(iseq, ret, node, node->nd_vid);
}
break;
}
case NODE_DVAR:{
int lv, idx, ls;
- debugi("nd_vid", RNODE_DVAR(node)->nd_vid);
+ debugi("nd_vid", node->nd_vid);
if (!popped) {
- idx = get_dyna_var_idx(iseq, RNODE_DVAR(node)->nd_vid, &lv, &ls);
+ idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls);
if (idx < 0) {
COMPILE_ERROR(ERROR_ARGS "unknown dvar (%"PRIsVALUE")",
- rb_id2str(RNODE_DVAR(node)->nd_vid));
+ rb_id2str(node->nd_vid));
goto ng;
}
ADD_GETLOCAL(ret, node, ls - idx, lv);
@@ -10802,34 +9696,34 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_GVAR:{
- ADD_INSN1(ret, node, getglobal, ID2SYM(RNODE_GVAR(node)->nd_vid));
+ ADD_INSN1(ret, node, getglobal, ID2SYM(node->nd_entry));
if (popped) {
ADD_INSN(ret, node, pop);
}
break;
}
case NODE_IVAR:{
- debugi("nd_vid", RNODE_IVAR(node)->nd_vid);
+ debugi("nd_vid", node->nd_vid);
if (!popped) {
ADD_INSN2(ret, node, getinstancevariable,
- ID2SYM(RNODE_IVAR(node)->nd_vid),
- get_ivar_ic_value(iseq, RNODE_IVAR(node)->nd_vid));
+ ID2SYM(node->nd_vid),
+ get_ivar_ic_value(iseq,node->nd_vid));
}
break;
}
case NODE_CONST:{
- debugi("nd_vid", RNODE_CONST(node)->nd_vid);
+ debugi("nd_vid", node->nd_vid);
if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
body->ic_size++;
- VALUE segments = rb_ary_new_from_args(1, ID2SYM(RNODE_CONST(node)->nd_vid));
+ VALUE segments = rb_ary_new_from_args(1, ID2SYM(node->nd_vid));
ADD_INSN1(ret, node, opt_getconstant_path, segments);
RB_OBJ_WRITTEN(iseq, Qundef, segments);
}
else {
ADD_INSN(ret, node, putnil);
ADD_INSN1(ret, node, putobject, Qtrue);
- ADD_INSN1(ret, node, getconstant, ID2SYM(RNODE_CONST(node)->nd_vid));
+ ADD_INSN1(ret, node, getconstant, ID2SYM(node->nd_vid));
}
if (popped) {
@@ -10840,26 +9734,26 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
case NODE_CVAR:{
if (!popped) {
ADD_INSN2(ret, node, getclassvariable,
- ID2SYM(RNODE_CVAR(node)->nd_vid),
- get_cvar_ic_value(iseq, RNODE_CVAR(node)->nd_vid));
+ ID2SYM(node->nd_vid),
+ get_cvar_ic_value(iseq,node->nd_vid));
}
break;
}
case NODE_NTH_REF:{
if (!popped) {
- if (!RNODE_NTH_REF(node)->nd_nth) {
+ if (!node->nd_nth) {
ADD_INSN(ret, node, putnil);
break;
}
ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
- INT2FIX(RNODE_NTH_REF(node)->nd_nth << 1));
+ INT2FIX(node->nd_nth << 1));
}
break;
}
case NODE_BACK_REF:{
if (!popped) {
ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
- INT2FIX(0x01 | (RNODE_BACK_REF(node)->nd_nth << 1)));
+ INT2FIX(0x01 | (node->nd_nth << 1)));
}
break;
}
@@ -10868,86 +9762,40 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
case NODE_MATCH3:
CHECK(compile_match(iseq, ret, node, popped, type));
break;
- case NODE_SYM:{
- if (!popped) {
- ADD_INSN1(ret, node, putobject, rb_node_sym_string_val(node));
- }
- break;
- }
- case NODE_LINE:{
- if (!popped) {
- ADD_INSN1(ret, node, putobject, rb_node_line_lineno_val(node));
- }
- break;
- }
- case NODE_ENCODING:{
- if (!popped) {
- ADD_INSN1(ret, node, putobject, rb_node_encoding_val(node));
- }
- break;
- }
- case NODE_INTEGER:{
- VALUE lit = rb_node_integer_literal_val(node);
- debugp_param("integer", lit);
- if (!popped) {
- ADD_INSN1(ret, node, putobject, lit);
- RB_OBJ_WRITTEN(iseq, Qundef, lit);
- }
- break;
- }
- case NODE_FLOAT:{
- VALUE lit = rb_node_float_literal_val(node);
- debugp_param("float", lit);
+ case NODE_LIT:{
+ debugp_param("lit", node->nd_lit);
if (!popped) {
- ADD_INSN1(ret, node, putobject, lit);
- RB_OBJ_WRITTEN(iseq, Qundef, lit);
- }
- break;
- }
- case NODE_RATIONAL:{
- VALUE lit = rb_node_rational_literal_val(node);
- debugp_param("rational", lit);
- if (!popped) {
- ADD_INSN1(ret, node, putobject, lit);
- RB_OBJ_WRITTEN(iseq, Qundef, lit);
- }
- break;
- }
- case NODE_IMAGINARY:{
- VALUE lit = rb_node_imaginary_literal_val(node);
- debugp_param("imaginary", lit);
- if (!popped) {
- ADD_INSN1(ret, node, putobject, lit);
- RB_OBJ_WRITTEN(iseq, Qundef, lit);
+ if (UNLIKELY(node->nd_lit == rb_mRubyVMFrozenCore)) {
+ ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); // [Bug #20569]
+ }
+ else {
+ ADD_INSN1(ret, node, putobject, node->nd_lit);
+ }
+ RB_OBJ_WRITTEN(iseq, Qundef, node->nd_lit);
}
break;
}
- case NODE_FILE:
case NODE_STR:{
- debugp_param("nd_lit", get_string_value(node));
+ debugp_param("nd_lit", node->nd_lit);
if (!popped) {
- VALUE lit = get_string_value(node);
- switch (ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
- case ISEQ_FROZEN_STRING_LITERAL_UNSET:
- ADD_INSN1(ret, node, putchilledstring, lit);
- RB_OBJ_WRITTEN(iseq, Qundef, lit);
- break;
- case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
+ VALUE lit = node->nd_lit;
+ if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
+ lit = rb_fstring(lit);
ADD_INSN1(ret, node, putstring, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
- break;
- case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
+ }
+ else {
if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line));
lit = rb_str_dup(lit);
- rb_ivar_set(lit, id_debug_created_info, rb_ary_freeze(debug_info));
+ rb_ivar_set(lit, id_debug_created_info, rb_obj_freeze(debug_info));
lit = rb_str_freeze(lit);
}
+ else {
+ lit = rb_fstring(lit);
+ }
ADD_INSN1(ret, node, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
- break;
- default:
- rb_bug("invalid frozen_string_literal");
}
}
break;
@@ -10962,7 +9810,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_XSTR:{
ADD_CALL_RECEIVER(ret, node);
- VALUE str = rb_node_str_string_val(node);
+ VALUE str = rb_fstring(node->nd_lit);
ADD_INSN1(ret, node, putobject, str);
RB_OBJ_WRITTEN(iseq, Qundef, str);
ADD_CALL(ret, node, idBackquote, INT2FIX(1));
@@ -10983,23 +9831,20 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_EVSTR:
- CHECK(compile_evstr(iseq, ret, RNODE_EVSTR(node)->nd_body, popped));
+ CHECK(compile_evstr(iseq, ret, node->nd_body, popped));
break;
- case NODE_REGX:{
- if (!popped) {
- VALUE lit = rb_node_regx_string_val(node);
- ADD_INSN1(ret, node, putobject, lit);
- RB_OBJ_WRITTEN(iseq, Qundef, lit);
+ case NODE_DREGX:{
+ compile_dregx(iseq, ret, node);
+
+ if (popped) {
+ ADD_INSN(ret, node, pop);
}
break;
}
- case NODE_DREGX:
- compile_dregx(iseq, ret, node, popped);
- break;
case NODE_ONCE:{
int ic_index = body->ise_size++;
const rb_iseq_t *block_iseq;
- block_iseq = NEW_CHILD_ISEQ(RNODE_ONCE(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
+ block_iseq = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
@@ -11011,53 +9856,36 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_ARGSCAT:{
if (popped) {
- CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
+ CHECK(COMPILE(ret, "argscat head", node->nd_head));
ADD_INSN1(ret, node, splatarray, Qfalse);
ADD_INSN(ret, node, pop);
- CHECK(COMPILE(ret, "argscat body", RNODE_ARGSCAT(node)->nd_body));
+ CHECK(COMPILE(ret, "argscat body", node->nd_body));
ADD_INSN1(ret, node, splatarray, Qfalse);
ADD_INSN(ret, node, pop);
}
else {
- CHECK(COMPILE(ret, "argscat head", RNODE_ARGSCAT(node)->nd_head));
- const NODE *body_node = RNODE_ARGSCAT(node)->nd_body;
- if (nd_type_p(body_node, NODE_LIST)) {
- CHECK(compile_array(iseq, ret, body_node, popped, FALSE) >= 0);
- }
- else {
- CHECK(COMPILE(ret, "argscat body", body_node));
- ADD_INSN(ret, node, concattoarray);
- }
+ CHECK(COMPILE(ret, "argscat head", node->nd_head));
+ CHECK(COMPILE(ret, "argscat body", node->nd_body));
+ ADD_INSN(ret, node, concatarray);
}
break;
}
case NODE_ARGSPUSH:{
if (popped) {
- CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
+ CHECK(COMPILE(ret, "argspush head", node->nd_head));
ADD_INSN1(ret, node, splatarray, Qfalse);
ADD_INSN(ret, node, pop);
- CHECK(COMPILE_(ret, "argspush body", RNODE_ARGSPUSH(node)->nd_body, popped));
+ CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
}
else {
- CHECK(COMPILE(ret, "argspush head", RNODE_ARGSPUSH(node)->nd_head));
- const NODE *body_node = RNODE_ARGSPUSH(node)->nd_body;
- if (keyword_node_p(body_node)) {
- CHECK(COMPILE_(ret, "array element", body_node, FALSE));
- ADD_INSN(ret, node, pushtoarraykwsplat);
- }
- else if (static_literal_node_p(body_node, iseq, false)) {
- ADD_INSN1(ret, body_node, putobject, static_literal_value(body_node, iseq));
- ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
- }
- else {
- CHECK(COMPILE_(ret, "array element", body_node, FALSE));
- ADD_INSN1(ret, node, pushtoarray, INT2FIX(1));
- }
+ CHECK(COMPILE(ret, "argspush head", node->nd_head));
+ CHECK(compile_array_1(iseq, ret, node->nd_body));
+ ADD_INSN(ret, node, concatarray);
}
break;
}
case NODE_SPLAT:{
- CHECK(COMPILE(ret, "splat", RNODE_SPLAT(node)->nd_head));
+ CHECK(COMPILE(ret, "splat", node->nd_head));
ADD_INSN1(ret, node, splatarray, Qtrue);
if (popped) {
@@ -11066,8 +9894,8 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_DEFN:{
- ID mid = RNODE_DEFN(node)->nd_mid;
- const rb_iseq_t *method_iseq = NEW_ISEQ(RNODE_DEFN(node)->nd_defn,
+ ID mid = node->nd_mid;
+ const rb_iseq_t *method_iseq = NEW_ISEQ(node->nd_defn,
rb_id2str(mid),
ISEQ_TYPE_METHOD, line);
@@ -11082,13 +9910,13 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_DEFS:{
- ID mid = RNODE_DEFS(node)->nd_mid;
- const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(RNODE_DEFS(node)->nd_defn,
+ ID mid = node->nd_mid;
+ const rb_iseq_t * singleton_method_iseq = NEW_ISEQ(node->nd_defn,
rb_id2str(mid),
ISEQ_TYPE_METHOD, line);
debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
- CHECK(COMPILE(ret, "defs: recv", RNODE_DEFS(node)->nd_recv));
+ CHECK(COMPILE(ret, "defs: recv", node->nd_recv));
ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
@@ -11100,8 +9928,8 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
case NODE_ALIAS:{
ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
- CHECK(COMPILE(ret, "alias arg1", RNODE_ALIAS(node)->nd_1st));
- CHECK(COMPILE(ret, "alias arg2", RNODE_ALIAS(node)->nd_2nd));
+ CHECK(COMPILE(ret, "alias arg1", node->nd_1st));
+ CHECK(COMPILE(ret, "alias arg2", node->nd_2nd));
ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
if (popped) {
@@ -11111,8 +9939,8 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_VALIAS:{
ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_alias));
- ADD_INSN1(ret, node, putobject, ID2SYM(RNODE_VALIAS(node)->nd_orig));
+ ADD_INSN1(ret, node, putobject, ID2SYM(node->nd_alias));
+ ADD_INSN1(ret, node, putobject, ID2SYM(node->nd_orig));
ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
if (popped) {
@@ -11121,18 +9949,10 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_UNDEF:{
- const rb_parser_ary_t *ary = RNODE_UNDEF(node)->nd_undefs;
-
- for (long i = 0; i < ary->len; i++) {
- ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
- CHECK(COMPILE(ret, "undef arg", ary->data[i]));
- ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
-
- if (i < ary->len - 1) {
- ADD_INSN(ret, node, pop);
- }
- }
+ ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
+ CHECK(COMPILE(ret, "undef arg", node->nd_undef));
+ ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
if (popped) {
ADD_INSN(ret, node, pop);
@@ -11140,15 +9960,15 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_CLASS:{
- const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(RNODE_CLASS(node)->nd_body,
- rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)))),
+ const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(node->nd_body,
+ rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid))),
ISEQ_TYPE_CLASS, line);
const int flags = VM_DEFINECLASS_TYPE_CLASS |
- (RNODE_CLASS(node)->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
- compile_cpath(ret, iseq, RNODE_CLASS(node)->nd_cpath);
+ (node->nd_super ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
+ compile_cpath(ret, iseq, node->nd_cpath);
- CHECK(COMPILE(ret, "super", RNODE_CLASS(node)->nd_super));
- ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_CLASS(node)->nd_cpath)), class_iseq, INT2FIX(flags));
+ CHECK(COMPILE(ret, "super", node->nd_super));
+ ADD_INSN3(ret, node, defineclass, ID2SYM(node->nd_cpath->nd_mid), class_iseq, INT2FIX(flags));
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
if (popped) {
@@ -11157,14 +9977,14 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
}
case NODE_MODULE:{
- const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(RNODE_MODULE(node)->nd_body,
- rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)))),
+ const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(node->nd_body,
+ rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(node->nd_cpath->nd_mid))),
ISEQ_TYPE_CLASS, line);
const int flags = VM_DEFINECLASS_TYPE_MODULE |
- compile_cpath(ret, iseq, RNODE_MODULE(node)->nd_cpath);
+ compile_cpath(ret, iseq, node->nd_cpath);
ADD_INSN (ret, node, putnil); /* dummy */
- ADD_INSN3(ret, node, defineclass, ID2SYM(get_node_colon_nd_mid(RNODE_MODULE(node)->nd_cpath)), module_iseq, INT2FIX(flags));
+ ADD_INSN3(ret, node, defineclass, ID2SYM(node->nd_cpath->nd_mid), module_iseq, INT2FIX(flags));
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
if (popped) {
@@ -11174,10 +9994,10 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_SCLASS:{
ID singletonclass;
- const rb_iseq_t *singleton_class = NEW_ISEQ(RNODE_SCLASS(node)->nd_body, rb_fstring_lit("singleton class"),
+ const rb_iseq_t *singleton_class = NEW_ISEQ(node->nd_body, rb_fstring_lit("singleton class"),
ISEQ_TYPE_CLASS, line);
- CHECK(COMPILE(ret, "sclass#recv", RNODE_SCLASS(node)->nd_recv));
+ CHECK(COMPILE(ret, "sclass#recv", node->nd_recv));
ADD_INSN (ret, node, putnil);
CONST_ID(singletonclass, "singletonclass");
ADD_INSN3(ret, node, defineclass,
@@ -11246,7 +10066,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
case NODE_DEFINED:
if (!popped) {
- CHECK(compile_defined_expr(iseq, ret, node, Qtrue, false));
+ CHECK(compile_defined_expr(iseq, ret, node, Qtrue));
}
break;
case NODE_POSTEXE:{
@@ -11255,7 +10075,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
*/
int is_index = body->ise_size++;
struct rb_iseq_new_with_callback_callback_func *ifunc =
- rb_iseq_new_with_callback_new_callback(build_postexe_iseq, RNODE_POSTEXE(node)->nd_body);
+ rb_iseq_new_with_callback_new_callback(build_postexe_iseq, node->nd_body);
const rb_iseq_t *once_iseq =
new_child_iseq_with_callback(iseq, ifunc,
rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
@@ -11286,7 +10106,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
break;
case NODE_LAMBDA:{
/* compile same as lambda{...} */
- const rb_iseq_t *block = NEW_CHILD_ISEQ(RNODE_LAMBDA(node)->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
+ const rb_iseq_t *block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
VALUE argc = INT2FIX(0);
ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
@@ -11471,7 +10291,7 @@ dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr,
case ISEQ_ELEMENT_LABEL:
{
lobj = (LABEL *)link;
- printf(LABEL_FORMAT" [sp: %d, unremovable: %d, refcnt: %d]%s\n", lobj->label_no, lobj->sp, lobj->unremovable, lobj->refcnt,
+ printf(LABEL_FORMAT" [sp: %d]%s\n", lobj->label_no, lobj->sp,
dest == lobj ? " <---" : "");
break;
}
@@ -11489,7 +10309,7 @@ dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr,
}
default:
/* ignore */
- rb_raise(rb_eSyntaxError, "dump_disasm_list error: %d\n", (int)link->type);
+ rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type));
}
link = link->next;
}
@@ -11497,12 +10317,6 @@ dump_disasm_list_with_cursor(const LINK_ELEMENT *link, const LINK_ELEMENT *curr,
fflush(stdout);
}
-int
-rb_insn_len(VALUE insn)
-{
- return insn_len(insn);
-}
-
const char *
rb_insns_name(int i)
{
@@ -11517,7 +10331,7 @@ rb_insns_name_array(void)
for (i = 0; i < VM_INSTRUCTION_SIZE; i++) {
rb_ary_push(ary, rb_fstring_cstr(insn_name(i)));
}
- return rb_ary_freeze(ary);
+ return rb_obj_freeze(ary);
}
static LABEL *
@@ -11666,7 +10480,6 @@ iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
size_t n = rb_callinfo_kwarg_bytes(len);
kw_arg = xmalloc(n);
- kw_arg->references = 0;
kw_arg->keyword_len = len;
for (i = 0; i < len; i++) {
VALUE kw = RARRAY_AREF(vkw_arg, i);
@@ -11692,7 +10505,6 @@ event_name_to_flag(VALUE sym)
CHECK_EVENT(RUBY_EVENT_RETURN);
CHECK_EVENT(RUBY_EVENT_B_CALL);
CHECK_EVENT(RUBY_EVENT_B_RETURN);
- CHECK_EVENT(RUBY_EVENT_RESCUE);
#undef CHECK_EVENT
return RUBY_EVENT_NONE;
}
@@ -11703,7 +10515,7 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
{
/* TODO: body should be frozen */
long i, len = RARRAY_LEN(body);
- struct st_table *labels_table = RTYPEDDATA_DATA(labels_wrapper);
+ struct st_table *labels_table = DATA_PTR(labels_wrapper);
int j;
int line_no = 0, node_id = -1, insn_idx = 0;
int ret = COMPILE_OK;
@@ -11763,8 +10575,9 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
argv = compile_data_calloc2(iseq, sizeof(VALUE), argc);
// add element before operand setup to make GC root
+ NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
ADD_ELEM(anchor,
- (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
+ (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
(enum ruby_vminsn_type)insn_id, argc, argv));
for (j=0; j<argc; j++) {
@@ -11872,8 +10685,9 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
}
}
else {
+ NODE dummy_line_node = generate_dummy_line_node(line_no, node_id);
ADD_ELEM(anchor,
- (LINK_ELEMENT*)new_insn_core(iseq, line_no, node_id,
+ (LINK_ELEMENT*)new_insn_core(iseq, &dummy_line_node,
(enum ruby_vminsn_type)insn_id, argc, NULL));
}
}
@@ -11881,8 +10695,7 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *const anchor,
rb_raise(rb_eTypeError, "unexpected object for instruction");
}
}
- RTYPEDDATA_DATA(labels_wrapper) = 0;
- RB_GC_GUARD(labels_wrapper);
+ DATA_PTR(labels_wrapper) = 0;
validate_labels(iseq, labels_table);
if (!ret) return ret;
return iseq_setup(iseq, anchor);
@@ -11966,7 +10779,7 @@ iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
rb_raise(rb_eTypeError, "keyword default has unsupported len %+"PRIsVALUE, key);
}
ids[i] = SYM2ID(sym);
- RB_OBJ_WRITE(iseq, &dvs[j], default_val);
+ dvs[j] = default_val;
}
keyword->table = ids;
@@ -11976,13 +10789,13 @@ iseq_build_kw(rb_iseq_t *iseq, VALUE params, VALUE keywords)
}
static void
-iseq_insn_each_object_mark_and_pin(VALUE obj, VALUE _)
+iseq_insn_each_object_mark(VALUE *obj_ptr, VALUE _)
{
- rb_gc_mark(obj);
+ rb_gc_mark(*obj_ptr);
}
void
-rb_iseq_mark_and_pin_insn_storage(struct iseq_compile_data_storage *storage)
+rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *storage)
{
INSN *iobj = 0;
size_t size = sizeof(INSN);
@@ -12007,22 +10820,13 @@ rb_iseq_mark_and_pin_insn_storage(struct iseq_compile_data_storage *storage)
iobj = (INSN *)&storage->buff[pos];
if (iobj->operands) {
- iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark_and_pin, (VALUE)0);
+ iseq_insn_each_markable_object(iobj, iseq_insn_each_object_mark, (VALUE)0);
}
pos += (int)size;
}
}
}
-static const rb_data_type_t labels_wrapper_type = {
- .wrap_struct_name = "compiler/labels_wrapper",
- .function = {
- .dmark = (RUBY_DATA_FUNC)rb_mark_set,
- .dfree = (RUBY_DATA_FUNC)st_free_table,
- },
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
-};
-
void
rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
VALUE exception, VALUE body)
@@ -12032,7 +10836,7 @@ rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
unsigned int arg_size, local_size, stack_max;
ID *tbl;
struct st_table *labels_table = st_init_numtable();
- VALUE labels_wrapper = TypedData_Wrap_Struct(0, &labels_wrapper_type, labels_table);
+ VALUE labels_wrapper = Data_Wrap_Struct(0, rb_mark_set, st_free_table, labels_table);
VALUE arg_opt_labels = rb_hash_aref(params, SYM(opt));
VALUE keywords = rb_hash_aref(params, SYM(keyword));
VALUE sym_arg_rest = ID2SYM(rb_intern_const("#arg_rest"));
@@ -12114,10 +10918,6 @@ rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc, VALUE locals, VALUE params,
ISEQ_BODY(iseq)->param.flags.ambiguous_param0 = TRUE;
}
- if (Qtrue == rb_hash_aref(params, SYM(use_block))) {
- ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
- }
-
if (int_param(&i, params, SYM(kwrest))) {
struct rb_iseq_param_keyword *keyword = (struct rb_iseq_param_keyword *)ISEQ_BODY(iseq)->param.keyword;
if (keyword == NULL) {
@@ -12193,7 +10993,7 @@ rb_local_defined(ID id, const rb_iseq_t *iseq)
#define IBF_ISEQ_ENABLE_LOCAL_BUFFER 0
#endif
-typedef uint32_t ibf_offset_t;
+typedef unsigned int ibf_offset_t;
#define IBF_OFFSET(ptr) ((ibf_offset_t)(VALUE)(ptr))
#define IBF_MAJOR_VERSION ISEQ_MAJOR_VERSION
@@ -12204,27 +11004,17 @@ typedef uint32_t ibf_offset_t;
#define IBF_MINOR_VERSION ISEQ_MINOR_VERSION
#endif
-static const char IBF_ENDIAN_MARK =
-#ifdef WORDS_BIGENDIAN
- 'b'
-#else
- 'l'
-#endif
- ;
-
struct ibf_header {
char magic[4]; /* YARB */
- uint32_t major_version;
- uint32_t minor_version;
- uint32_t size;
- uint32_t extra_size;
+ unsigned int major_version;
+ unsigned int minor_version;
+ unsigned int size;
+ unsigned int extra_size;
- uint32_t iseq_list_size;
- uint32_t global_object_list_size;
+ unsigned int iseq_list_size;
+ unsigned int global_object_list_size;
ibf_offset_t iseq_list_offset;
ibf_offset_t global_object_list_offset;
- uint8_t endian;
- uint8_t wordsize; /* assume no 2048-bit CPU */
};
struct ibf_dump_buffer {
@@ -12259,7 +11049,7 @@ struct ibf_load {
struct pinned_list {
long size;
- VALUE buffer[1];
+ VALUE * buffer;
};
static void
@@ -12274,14 +11064,25 @@ pinned_list_mark(void *ptr)
}
}
+static void
+pinned_list_free(void *ptr)
+{
+ struct pinned_list *list = (struct pinned_list *)ptr;
+ xfree(list->buffer);
+ xfree(ptr);
+}
+
+static size_t
+pinned_list_memsize(const void *ptr)
+{
+ struct pinned_list *list = (struct pinned_list *)ptr;
+ return sizeof(struct pinned_list) + (list->size * sizeof(VALUE *));
+}
+
static const rb_data_type_t pinned_list_type = {
"pinned_list",
- {
- pinned_list_mark,
- RUBY_DEFAULT_FREE,
- NULL, // No external memory to report,
- },
- 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
+ {pinned_list_mark, pinned_list_free, pinned_list_memsize,},
+ 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
};
static VALUE
@@ -12315,10 +11116,13 @@ pinned_list_store(VALUE list, long offset, VALUE object)
static VALUE
pinned_list_new(long size)
{
- size_t memsize = offsetof(struct pinned_list, buffer) + size * sizeof(VALUE);
- VALUE obj_list = rb_data_typed_object_zalloc(0, memsize, &pinned_list_type);
- struct pinned_list * ptr = RTYPEDDATA_GET_DATA(obj_list);
+ struct pinned_list * ptr;
+ VALUE obj_list =
+ TypedData_Make_Struct(0, struct pinned_list, &pinned_list_type, ptr);
+
+ ptr->buffer = xcalloc(size, sizeof(VALUE));
ptr->size = size;
+
return obj_list;
}
@@ -12467,10 +11271,6 @@ ibf_load_id(const struct ibf_load *load, const ID id_index)
return 0;
}
VALUE sym = ibf_load_object(load, id_index);
- if (rb_integer_type_p(sym)) {
- /* Load hidden local variables as indexes */
- return NUM2ULONG(sym);
- }
return rb_sym2id(sym);
}
@@ -12670,7 +11470,7 @@ ibf_dump_code(struct ibf_dump *dump, const rb_iseq_t *iseq)
ibf_dump_write_small_value(dump, wv);
skip_wv:;
}
- RUBY_ASSERT(insn_len(insn) == op_index+1);
+ assert(insn_len(insn) == op_index+1);
}
return offset;
@@ -12835,8 +11635,8 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
}
}
- RUBY_ASSERT(code_index == iseq_size);
- RUBY_ASSERT(reading_pos == bytecode_offset + bytecode_size);
+ assert(code_index == iseq_size);
+ assert(reading_pos == bytecode_offset + bytecode_size);
return code;
}
@@ -12899,7 +11699,7 @@ ibf_load_param_keyword(const struct ibf_load *load, ibf_offset_t param_keyword_o
struct rb_iseq_param_keyword *kw = IBF_R(param_keyword_offset, struct rb_iseq_param_keyword, 1);
ID *ids = IBF_R(kw->table, ID, kw->num);
int dv_num = kw->num - kw->required_num;
- VALUE *dvs = dv_num ? IBF_R(kw->default_values, VALUE, dv_num) : NULL;
+ VALUE *dvs = IBF_R(kw->default_values, VALUE, dv_num);
int i;
for (i=0; i<kw->num; i++) {
@@ -12994,12 +11794,7 @@ ibf_dump_local_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
int i;
for (i=0; i<size; i++) {
- VALUE v = ibf_dump_id(dump, body->local_table[i]);
- if (v == 0) {
- /* Dump hidden local variables as indexes, so load_from_binary will work with them */
- v = ibf_dump_object(dump, ULONG2NUM(body->local_table[i]));
- }
- table[i] = v;
+ table[i] = ibf_dump_id(dump, body->local_table[i]);
}
IBF_W_ALIGN(ID);
@@ -13120,34 +11915,13 @@ ibf_dump_ci_entries(struct ibf_dump *dump, const rb_iseq_t *iseq)
return offset;
}
-struct outer_variable_pair {
- ID id;
- VALUE name;
- VALUE val;
-};
-
-struct outer_variable_list {
- size_t num;
- struct outer_variable_pair pairs[1];
-};
-
static enum rb_id_table_iterator_result
-store_outer_variable(ID id, VALUE val, void *dump)
+dump_outer_variable(ID id, VALUE val, void *dump)
{
- struct outer_variable_list *ovlist = dump;
- struct outer_variable_pair *pair = &ovlist->pairs[ovlist->num++];
- pair->id = id;
- pair->name = rb_id2str(id);
- pair->val = val;
- return ID_TABLE_CONTINUE;
-}
+ ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
+ ibf_dump_write_small_value(dump, val);
-static int
-outer_variable_cmp(const void *a, const void *b, void *arg)
-{
- const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
- const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
- return rb_str_cmp(ap->name, bp->name);
+ return ID_TABLE_CONTINUE;
}
static ibf_offset_t
@@ -13157,24 +11931,12 @@ ibf_dump_outer_variables(struct ibf_dump *dump, const rb_iseq_t *iseq)
ibf_offset_t offset = ibf_dump_pos(dump);
- size_t size = ovs ? rb_id_table_size(ovs) : 0;
- ibf_dump_write_small_value(dump, (VALUE)size);
- if (size > 0) {
- VALUE buff;
- size_t buffsize =
- rb_size_mul_add_or_raise(sizeof(struct outer_variable_pair), size,
- offsetof(struct outer_variable_list, pairs),
- rb_eArgError);
- struct outer_variable_list *ovlist = RB_ALLOCV(buff, buffsize);
- ovlist->num = 0;
- rb_id_table_foreach(ovs, store_outer_variable, ovlist);
- ruby_qsort(ovlist->pairs, size, sizeof(struct outer_variable_pair), outer_variable_cmp, NULL);
- for (size_t i = 0; i < size; ++i) {
- ID id = ovlist->pairs[i].id;
- ID val = ovlist->pairs[i].val;
- ibf_dump_write_small_value(dump, ibf_dump_id(dump, id));
- ibf_dump_write_small_value(dump, val);
- }
+ if (ovs) {
+ ibf_dump_write_small_value(dump, (VALUE)rb_id_table_size(ovs));
+ rb_id_table_foreach(ovs, dump_outer_variable, (void *)dump);
+ }
+ else {
+ ibf_dump_write_small_value(dump, (VALUE)0);
}
return offset;
@@ -13205,7 +11967,6 @@ ibf_load_ci_entries(const struct ibf_load *load,
int kwlen = (int)ibf_load_small_value(load, &reading_pos);
if (kwlen > 0) {
kwarg = rb_xmalloc_mul_add(kwlen, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
- kwarg->references = 0;
kwarg->keyword_len = kwlen;
for (int j=0; j<kwlen; j++) {
VALUE keyword = ibf_load_small_value(load, &reading_pos);
@@ -13251,7 +12012,7 @@ ibf_load_outer_variables(const struct ibf_load * load, ibf_offset_t outer_variab
static ibf_offset_t
ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
{
- RUBY_ASSERT(dump->current_buffer == &dump->global_buffer);
+ assert(dump->current_buffer == &dump->global_buffer);
unsigned int *positions;
@@ -13310,11 +12071,7 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
(body->param.flags.has_block << 6) |
(body->param.flags.ambiguous_param0 << 7) |
(body->param.flags.accepts_no_kwarg << 8) |
- (body->param.flags.ruby2_keywords << 9) |
- (body->param.flags.anon_rest << 10) |
- (body->param.flags.anon_kwrest << 11) |
- (body->param.flags.use_block << 12) |
- (body->param.flags.forwardable << 13) ;
+ (body->param.flags.ruby2_keywords << 9);
#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
# define IBF_BODY_OFFSET(x) (x)
@@ -13364,8 +12121,8 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
ibf_dump_write_small_value(dump, body->ic_size);
ibf_dump_write_small_value(dump, body->ci_size);
ibf_dump_write_small_value(dump, body->stack_max);
- ibf_dump_write_small_value(dump, body->builtin_attrs);
- ibf_dump_write_small_value(dump, body->prism ? 1 : 0);
+ ibf_dump_write_small_value(dump, body->catch_except_p);
+ ibf_dump_write_small_value(dump, body->builtin_inline_p);
#undef IBF_BODY_OFFSET
@@ -13477,8 +12234,8 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
- const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
- const bool prism = (bool)ibf_load_small_value(load, &reading_pos);
+ const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos);
+ const bool builtin_inline_p = (bool)ibf_load_small_value(load, &reading_pos);
// setup fname and dummy frame
VALUE path = ibf_load_object(load, location_pathobj_index);
@@ -13528,10 +12285,6 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
load_body->param.flags.ambiguous_param0 = (param_flags >> 7) & 1;
load_body->param.flags.accepts_no_kwarg = (param_flags >> 8) & 1;
load_body->param.flags.ruby2_keywords = (param_flags >> 9) & 1;
- load_body->param.flags.anon_rest = (param_flags >> 10) & 1;
- load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
- load_body->param.flags.use_block = (param_flags >> 12) & 1;
- load_body->param.flags.forwardable = (param_flags >> 13) & 1;
load_body->param.size = param_size;
load_body->param.lead_num = param_lead_num;
load_body->param.opt_num = param_opt_num;
@@ -13554,20 +12307,14 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
load_body->location.code_location.beg_pos.column = location_code_location_beg_pos_column;
load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
- load_body->builtin_attrs = builtin_attrs;
- load_body->prism = prism;
+ load_body->catch_except_p = catch_except_p;
+ load_body->builtin_inline_p = builtin_inline_p;
load_body->ivc_size = ivc_size;
load_body->icvarc_size = icvarc_size;
load_body->ise_size = ise_size;
load_body->ic_size = ic_size;
-
- if (ISEQ_IS_SIZE(load_body)) {
- load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
- }
- else {
- load_body->is_entries = NULL;
- }
+ load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, ISEQ_IS_SIZE(load_body));
ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
load_body->outer_variables = ibf_load_outer_variables(load, outer_variables_offset);
load_body->param.opt_table = ibf_load_param_opt_table(load, param_opt_table_offset, param_opt_num);
@@ -13840,7 +12587,7 @@ ibf_load_object_string(const struct ibf_load *load, const struct ibf_object_head
VALUE str;
if (header->frozen && !header->internal) {
- str = rb_enc_literal_str(ptr, len, rb_enc_from_index(encindex));
+ str = rb_enc_interned_str(ptr, len, rb_enc_from_index(encindex));
}
else {
str = rb_enc_str_new(ptr, len, rb_enc_from_index(encindex));
@@ -13905,7 +12652,7 @@ ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_heade
rb_ary_push(ary, ibf_load_object(load, index));
}
- if (header->frozen) rb_ary_freeze(ary);
+ if (header->frozen) rb_obj_freeze(ary);
return ary;
}
@@ -14007,12 +12754,8 @@ ibf_load_object_bignum(const struct ibf_load *load, const struct ibf_object_head
const struct ibf_object_bignum *bignum = IBF_OBJBODY(struct ibf_object_bignum, offset);
int sign = bignum->slen > 0;
ssize_t len = sign > 0 ? bignum->slen : -1 * bignum->slen;
- const int big_unpack_flags = /* c.f. rb_big_unpack() */
- INTEGER_PACK_LSWORD_FIRST |
- INTEGER_PACK_NATIVE_BYTE_ORDER;
- VALUE obj = rb_integer_unpack(bignum->digits, len, sizeof(BDIGIT), 0,
- big_unpack_flags |
- (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
+ VALUE obj = rb_integer_unpack(bignum->digits, len * 2, 2, 0,
+ INTEGER_PACK_LITTLE_ENDIAN | (sign == 0 ? INTEGER_PACK_NEGATIVE : 0));
if (header->internal) rb_obj_hide(obj);
if (header->frozen) rb_obj_freeze(obj);
return obj;
@@ -14104,7 +12847,7 @@ ibf_load_object_symbol(const struct ibf_load *load, const struct ibf_object_head
}
typedef void (*ibf_dump_object_function)(struct ibf_dump *dump, VALUE obj);
-static const ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
+static ibf_dump_object_function dump_object_functions[RUBY_T_MASK+1] = {
ibf_dump_object_unsupported, /* T_NONE */
ibf_dump_object_unsupported, /* T_OBJECT */
ibf_dump_object_class, /* T_CLASS */
@@ -14197,7 +12940,7 @@ ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
}
typedef VALUE (*ibf_load_object_function)(const struct ibf_load *load, const struct ibf_object_header *header, ibf_offset_t offset);
-static const ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
+static ibf_load_object_function load_object_functions[RUBY_T_MASK+1] = {
ibf_load_object_unsupported, /* T_NONE */
ibf_load_object_unsupported, /* T_OBJECT */
ibf_load_object_class, /* T_CLASS */
@@ -14340,13 +13083,14 @@ ibf_dump_free(void *ptr)
st_free_table(dump->iseq_table);
dump->iseq_table = 0;
}
+ ruby_xfree(dump);
}
static size_t
ibf_dump_memsize(const void *ptr)
{
struct ibf_dump *dump = (struct ibf_dump *)ptr;
- size_t size = 0;
+ size_t size = sizeof(*dump);
if (dump->iseq_table) size += st_memsize(dump->iseq_table);
if (dump->global_buffer.obj_table) size += st_memsize(dump->global_buffer.obj_table);
return size;
@@ -14355,7 +13099,7 @@ ibf_dump_memsize(const void *ptr)
static const rb_data_type_t ibf_dump_type = {
"ibf_dump",
{ibf_dump_mark, ibf_dump_free, ibf_dump_memsize,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static void
@@ -14391,6 +13135,7 @@ rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
ibf_dump_setup(dump, dump_obj);
ibf_dump_write(dump, &header, sizeof(header));
+ ibf_dump_write(dump, RUBY_PLATFORM, strlen(RUBY_PLATFORM) + 1);
ibf_dump_iseq(dump, iseq);
header.magic[0] = 'Y'; /* YARB */
@@ -14399,8 +13144,6 @@ rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
header.magic[3] = 'B';
header.major_version = IBF_MAJOR_VERSION;
header.minor_version = IBF_MINOR_VERSION;
- header.endian = IBF_ENDIAN_MARK;
- header.wordsize = (uint8_t)SIZEOF_VALUE;
ibf_dump_iseq_list(dump, &header);
ibf_dump_object_list(dump, &header.global_object_list_offset, &header.global_object_list_size);
header.size = ibf_dump_pos(dump);
@@ -14418,6 +13161,8 @@ rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt)
ibf_dump_overwrite(dump, &header, sizeof(header), 0);
str = dump->global_buffer.str;
+ ibf_dump_free(dump);
+ DATA_PTR(dump_obj) = NULL;
RB_GC_GUARD(dump_obj);
return str;
}
@@ -14448,7 +13193,7 @@ rb_ibf_load_iseq_complete(rb_iseq_t *iseq)
}
#if USE_LAZY_LOAD
-const rb_iseq_t *
+MJIT_FUNC_EXPORTED const rb_iseq_t *
rb_iseq_complete(const rb_iseq_t *iseq)
{
rb_ibf_load_iseq_complete((rb_iseq_t *)iseq);
@@ -14491,12 +13236,16 @@ ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
#endif
pinned_list_store(load->iseq_list, iseq_index, (VALUE)iseq);
- if (!USE_LAZY_LOAD || GET_VM()->builtin_function_table) {
+#if !USE_LAZY_LOAD
#if IBF_ISEQ_DEBUG
- fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
+ fprintf(stderr, "ibf_load_iseq: loading iseq=%p\n", (void *)iseq);
#endif
+ rb_ibf_load_iseq_complete(iseq);
+#else
+ if (GET_VM()->builtin_function_table) {
rb_ibf_load_iseq_complete(iseq);
}
+#endif /* !USE_LAZY_LOAD */
#if IBF_ISEQ_DEBUG
fprintf(stderr, "ibf_load_iseq: iseq=%p loaded %p\n",
@@ -14510,39 +13259,35 @@ ibf_load_iseq(const struct ibf_load *load, const rb_iseq_t *index_iseq)
static void
ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes, size_t size)
{
- struct ibf_header *header = (struct ibf_header *)bytes;
load->loader_obj = loader_obj;
load->global_buffer.buff = bytes;
- load->header = header;
- load->global_buffer.size = header->size;
- load->global_buffer.obj_list_offset = header->global_object_list_offset;
- load->global_buffer.obj_list_size = header->global_object_list_size;
- RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(header->iseq_list_size));
+ load->header = (struct ibf_header *)load->global_buffer.buff;
+ load->global_buffer.size = load->header->size;
+ load->global_buffer.obj_list_offset = load->header->global_object_list_offset;
+ load->global_buffer.obj_list_size = load->header->global_object_list_size;
+ RB_OBJ_WRITE(loader_obj, &load->iseq_list, pinned_list_new(load->header->iseq_list_size));
RB_OBJ_WRITE(loader_obj, &load->global_buffer.obj_list, pinned_list_new(load->global_buffer.obj_list_size));
load->iseq = NULL;
load->current_buffer = &load->global_buffer;
- if (size < header->size) {
+ if (size < load->header->size) {
rb_raise(rb_eRuntimeError, "broken binary format");
}
- if (strncmp(header->magic, "YARB", 4) != 0) {
+ if (strncmp(load->header->magic, "YARB", 4) != 0) {
rb_raise(rb_eRuntimeError, "unknown binary format");
}
- if (header->major_version != IBF_MAJOR_VERSION ||
- header->minor_version != IBF_MINOR_VERSION) {
+ if (load->header->major_version != IBF_MAJOR_VERSION ||
+ load->header->minor_version != IBF_MINOR_VERSION) {
rb_raise(rb_eRuntimeError, "unmatched version file (%u.%u for %u.%u)",
- header->major_version, header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
- }
- if (header->endian != IBF_ENDIAN_MARK) {
- rb_raise(rb_eRuntimeError, "unmatched endian: %c", header->endian);
+ load->header->major_version, load->header->minor_version, IBF_MAJOR_VERSION, IBF_MINOR_VERSION);
}
- if (header->wordsize != SIZEOF_VALUE) {
- rb_raise(rb_eRuntimeError, "unmatched word size: %d", header->wordsize);
+ if (strcmp(load->global_buffer.buff + sizeof(struct ibf_header), RUBY_PLATFORM) != 0) {
+ rb_raise(rb_eRuntimeError, "unmatched platform");
}
- if (header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
+ if (load->header->iseq_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
rb_raise(rb_eArgError, "unaligned iseq list offset: %u",
- header->iseq_list_offset);
+ load->header->iseq_list_offset);
}
if (load->global_buffer.obj_list_offset % RUBY_ALIGNOF(ibf_offset_t)) {
rb_raise(rb_eArgError, "unaligned object list offset: %u",
@@ -14553,15 +13298,13 @@ ibf_load_setup_bytes(struct ibf_load *load, VALUE loader_obj, const char *bytes,
static void
ibf_load_setup(struct ibf_load *load, VALUE loader_obj, VALUE str)
{
- StringValue(str);
-
if (RSTRING_LENINT(str) < (int)sizeof(struct ibf_header)) {
rb_raise(rb_eRuntimeError, "broken binary format");
}
- if (USE_LAZY_LOAD) {
- str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
- }
+#if USE_LAZY_LOAD
+ str = rb_str_new(RSTRING_PTR(str), RSTRING_LEN(str));
+#endif
ibf_load_setup_bytes(load, loader_obj, StringValuePtr(str), RSTRING_LEN(str));
RB_OBJ_WRITE(loader_obj, &load->str, str);
@@ -14635,5 +13378,3 @@ rb_iseq_ibf_load_extra_data(VALUE str)
RB_GC_GUARD(loader_obj);
return extra_str;
}
-
-#include "prism_compile.c"
diff --git a/complex.c b/complex.c
index b89c6f1f93..a227cb0a58 100644
--- a/complex.c
+++ b/complex.c
@@ -24,7 +24,6 @@
#include "internal/numeric.h"
#include "internal/object.h"
#include "internal/rational.h"
-#include "internal/string.h"
#include "ruby_assert.h"
#define ZERO INT2FIX(0)
@@ -392,12 +391,11 @@ k_numeric_p(VALUE x)
inline static VALUE
nucomp_s_new_internal(VALUE klass, VALUE real, VALUE imag)
{
- NEWOBJ_OF(obj, struct RComplex, klass,
- T_COMPLEX | (RGENGC_WB_PROTECTED_COMPLEX ? FL_WB_PROTECTED : 0), sizeof(struct RComplex), 0);
+ NEWOBJ_OF(obj, struct RComplex, klass, T_COMPLEX | (RGENGC_WB_PROTECTED_COMPLEX ? FL_WB_PROTECTED : 0));
RCOMPLEX_SET_REAL(obj, real);
RCOMPLEX_SET_IMAG(obj, imag);
- OBJ_FREEZE((VALUE)obj);
+ OBJ_FREEZE_RAW((VALUE)obj);
return (VALUE)obj;
}
@@ -411,15 +409,15 @@ nucomp_s_alloc(VALUE klass)
inline static VALUE
f_complex_new_bang1(VALUE klass, VALUE x)
{
- RUBY_ASSERT(!RB_TYPE_P(x, T_COMPLEX));
+ assert(!RB_TYPE_P(x, T_COMPLEX));
return nucomp_s_new_internal(klass, x, ZERO);
}
inline static VALUE
f_complex_new_bang2(VALUE klass, VALUE x, VALUE y)
{
- RUBY_ASSERT(!RB_TYPE_P(x, T_COMPLEX));
- RUBY_ASSERT(!RB_TYPE_P(y, T_COMPLEX));
+ assert(!RB_TYPE_P(x, T_COMPLEX));
+ assert(!RB_TYPE_P(y, T_COMPLEX));
return nucomp_s_new_internal(klass, x, y);
}
@@ -432,7 +430,7 @@ nucomp_real_check(VALUE num)
!RB_TYPE_P(num, T_RATIONAL)) {
if (RB_TYPE_P(num, T_COMPLEX) && nucomp_real_p(num)) {
VALUE real = RCOMPLEX(num)->real;
- RUBY_ASSERT(!RB_TYPE_P(real, T_COMPLEX));
+ assert(!RB_TYPE_P(real, T_COMPLEX));
return real;
}
if (!k_numeric_p(num) || !f_real_p(num))
@@ -475,19 +473,12 @@ nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag)
/*
* call-seq:
- * Complex.rect(real, imag = 0) -> complex
+ * Complex.rect(real[, imag]) -> complex
+ * Complex.rectangular(real[, imag]) -> complex
*
- * Returns a new \Complex object formed from the arguments,
- * each of which must be an instance of Numeric,
- * or an instance of one of its subclasses:
- * \Complex, Float, Integer, Rational;
- * see {Rectangular Coordinates}[rdoc-ref:Complex@Rectangular+Coordinates]:
+ * Returns a complex object which denotes the given rectangular form.
*
- * Complex.rect(3) # => (3+0i)
- * Complex.rect(3, Math::PI) # => (3+3.141592653589793i)
- * Complex.rect(-3, -Math::PI) # => (-3-3.141592653589793i)
- *
- * \Complex.rectangular is an alias for \Complex.rect.
+ * Complex.rectangular(1, 2) #=> (1+2i)
*/
static VALUE
nucomp_s_new(int argc, VALUE *argv, VALUE klass)
@@ -524,54 +515,39 @@ static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
/*
* call-seq:
- * Complex(real, imag = 0, exception: true) -> complex or nil
- * Complex(s, exception: true) -> complex or nil
- *
- * Returns a new \Complex object if the arguments are valid;
- * otherwise raises an exception if +exception+ is +true+;
- * otherwise returns +nil+.
- *
- * With Numeric arguments +real+ and +imag+,
- * returns <tt>Complex.rect(real, imag)</tt> if the arguments are valid.
- *
- * With string argument +s+, returns a new \Complex object if the argument is valid;
- * the string may have:
- *
- * - One or two numeric substrings,
- * each of which specifies a Complex, Float, Integer, Numeric, or Rational value,
- * specifying {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates]:
- *
- * - Sign-separated real and imaginary numeric substrings
- * (with trailing character <tt>'i'</tt>):
- *
- * Complex('1+2i') # => (1+2i)
- * Complex('+1+2i') # => (1+2i)
- * Complex('+1-2i') # => (1-2i)
- * Complex('-1+2i') # => (-1+2i)
- * Complex('-1-2i') # => (-1-2i)
- *
- * - Real-only numeric string (without trailing character <tt>'i'</tt>):
- *
- * Complex('1') # => (1+0i)
- * Complex('+1') # => (1+0i)
- * Complex('-1') # => (-1+0i)
- *
- * - Imaginary-only numeric string (with trailing character <tt>'i'</tt>):
- *
- * Complex('1i') # => (0+1i)
- * Complex('+1i') # => (0+1i)
- * Complex('-1i') # => (0-1i)
- *
- * - At-sign separated real and imaginary rational substrings,
- * each of which specifies a Rational value,
- * specifying {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
- *
- * Complex('1/2@3/4') # => (0.36584443443691045+0.34081938001166706i)
- * Complex('+1/2@+3/4') # => (0.36584443443691045+0.34081938001166706i)
- * Complex('+1/2@-3/4') # => (0.36584443443691045-0.34081938001166706i)
- * Complex('-1/2@+3/4') # => (-0.36584443443691045-0.34081938001166706i)
- * Complex('-1/2@-3/4') # => (-0.36584443443691045+0.34081938001166706i)
- *
+ * Complex(x[, y], exception: true) -> numeric or nil
+ *
+ * Returns x+i*y;
+ *
+ * Complex(1, 2) #=> (1+2i)
+ * Complex('1+2i') #=> (1+2i)
+ * Complex(nil) #=> TypeError
+ * Complex(1, nil) #=> TypeError
+ *
+ * Complex(1, nil, exception: false) #=> nil
+ * Complex('1+2', exception: false) #=> nil
+ *
+ * Syntax of string form:
+ *
+ * string form = extra spaces , complex , extra spaces ;
+ * complex = real part | [ sign ] , imaginary part
+ * | real part , sign , imaginary part
+ * | rational , "@" , rational ;
+ * real part = rational ;
+ * imaginary part = imaginary unit | unsigned rational , imaginary unit ;
+ * rational = [ sign ] , unsigned rational ;
+ * unsigned rational = numerator | numerator , "/" , denominator ;
+ * numerator = integer part | fractional part | integer part , fractional part ;
+ * denominator = digits ;
+ * integer part = digits ;
+ * fractional part = "." , digits , [ ( "e" | "E" ) , [ sign ] , digits ] ;
+ * imaginary unit = "i" | "I" | "j" | "J" ;
+ * sign = "-" | "+" ;
+ * digits = digit , { digit | "_" , digit };
+ * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
+ * extra spaces = ? \s* ? ;
+ *
+ * See String#to_c.
*/
static VALUE
nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
@@ -721,19 +697,14 @@ rb_dbl_complex_new_polar_pi(double abs, double ang)
/*
* call-seq:
- * Complex.polar(abs, arg = 0) -> complex
+ * Complex.polar(abs[, arg]) -> complex
*
- * Returns a new \Complex object formed from the arguments,
- * each of which must be an instance of Numeric,
- * or an instance of one of its subclasses:
- * \Complex, Float, Integer, Rational.
- * Argument +arg+ is given in radians;
- * see {Polar Coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
- *
- * Complex.polar(3) # => (3+0i)
- * Complex.polar(3, 2.0) # => (-1.2484405096414273+2.727892280477045i)
- * Complex.polar(-3, -2.0) # => (1.2484405096414273+2.727892280477045i)
+ * Returns a complex object which denotes the given polar form.
*
+ * Complex.polar(3, 0) #=> (3.0+0.0i)
+ * Complex.polar(3, Math::PI/2) #=> (1.836909530733566e-16+3.0i)
+ * Complex.polar(3, Math::PI) #=> (-3.0+3.673819061467132e-16i)
+ * Complex.polar(3, -Math::PI/2) #=> (1.836909530733566e-16-3.0i)
*/
static VALUE
nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
@@ -753,19 +724,12 @@ nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
/*
* call-seq:
- * real -> numeric
- *
- * Returns the real value for +self+:
- *
- * Complex.rect(7).real # => 7
- * Complex.rect(9, -4).real # => 9
+ * cmp.real -> real
*
- * If +self+ was created with
- * {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value
- * is computed, and may be inexact:
- *
- * Complex.polar(1, Math::PI/4).real # => 0.7071067811865476 # Square root of 2.
+ * Returns the real part.
*
+ * Complex(7).real #=> 7
+ * Complex(9, -4).real #=> 9
*/
VALUE
rb_complex_real(VALUE self)
@@ -776,19 +740,13 @@ rb_complex_real(VALUE self)
/*
* call-seq:
- * imag -> numeric
- *
- * Returns the imaginary value for +self+:
+ * cmp.imag -> real
+ * cmp.imaginary -> real
*
- * Complex.rect(7).imag # => 0
- * Complex.rect(9, -4).imag # => -4
- *
- * If +self+ was created with
- * {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value
- * is computed, and may be inexact:
- *
- * Complex.polar(1, Math::PI/4).imag # => 0.7071067811865476 # Square root of 2.
+ * Returns the imaginary part.
*
+ * Complex(7).imaginary #=> 0
+ * Complex(9, -4).imaginary #=> -4
*/
VALUE
rb_complex_imag(VALUE self)
@@ -799,13 +757,11 @@ rb_complex_imag(VALUE self)
/*
* call-seq:
- * -complex -> new_complex
- *
- * Returns the negation of +self+, which is the negation of each of its parts:
+ * -cmp -> complex
*
- * -Complex.rect(1, 2) # => (-1-2i)
- * -Complex.rect(-1, -2) # => (1+2i)
+ * Returns negation of the value.
*
+ * -Complex(1, 2) #=> (-1-2i)
*/
VALUE
rb_complex_uminus(VALUE self)
@@ -817,16 +773,15 @@ rb_complex_uminus(VALUE self)
/*
* call-seq:
- * complex + numeric -> new_complex
+ * cmp + numeric -> complex
*
- * Returns the sum of +self+ and +numeric+:
- *
- * Complex.rect(2, 3) + Complex.rect(2, 3) # => (4+6i)
- * Complex.rect(900) + Complex.rect(1) # => (901+0i)
- * Complex.rect(-2, 9) + Complex.rect(-9, 2) # => (-11+11i)
- * Complex.rect(9, 8) + 4 # => (13+8i)
- * Complex.rect(20, 9) + 9.8 # => (29.8+9i)
+ * Performs addition.
*
+ * Complex(2, 3) + Complex(2, 3) #=> (4+6i)
+ * Complex(900) + Complex(1) #=> (901+0i)
+ * Complex(-2, 9) + Complex(-9, 2) #=> (-11+11i)
+ * Complex(9, 8) + 4 #=> (13+8i)
+ * Complex(20, 9) + 9.8 #=> (29.8+9i)
*/
VALUE
rb_complex_plus(VALUE self, VALUE other)
@@ -852,16 +807,15 @@ rb_complex_plus(VALUE self, VALUE other)
/*
* call-seq:
- * complex - numeric -> new_complex
- *
- * Returns the difference of +self+ and +numeric+:
+ * cmp - numeric -> complex
*
- * Complex.rect(2, 3) - Complex.rect(2, 3) # => (0+0i)
- * Complex.rect(900) - Complex.rect(1) # => (899+0i)
- * Complex.rect(-2, 9) - Complex.rect(-9, 2) # => (7+7i)
- * Complex.rect(9, 8) - 4 # => (5+8i)
- * Complex.rect(20, 9) - 9.8 # => (10.2+9i)
+ * Performs subtraction.
*
+ * Complex(2, 3) - Complex(2, 3) #=> (0+0i)
+ * Complex(900) - Complex(1) #=> (899+0i)
+ * Complex(-2, 9) - Complex(-9, 2) #=> (7+7i)
+ * Complex(9, 8) - 4 #=> (5+8i)
+ * Complex(20, 9) - 9.8 #=> (10.2+9i)
*/
VALUE
rb_complex_minus(VALUE self, VALUE other)
@@ -913,16 +867,15 @@ comp_mul(VALUE areal, VALUE aimag, VALUE breal, VALUE bimag, VALUE *real, VALUE
/*
* call-seq:
- * complex * numeric -> new_complex
+ * cmp * numeric -> complex
*
- * Returns the product of +self+ and +numeric+:
- *
- * Complex.rect(2, 3) * Complex.rect(2, 3) # => (-5+12i)
- * Complex.rect(900) * Complex.rect(1) # => (900+0i)
- * Complex.rect(-2, 9) * Complex.rect(-9, 2) # => (0-85i)
- * Complex.rect(9, 8) * 4 # => (36+32i)
- * Complex.rect(20, 9) * 9.8 # => (196.0+88.2i)
+ * Performs multiplication.
*
+ * Complex(2, 3) * Complex(2, 3) #=> (-5+12i)
+ * Complex(900) * Complex(1) #=> (900+0i)
+ * Complex(-2, 9) * Complex(-9, 2) #=> (0-85i)
+ * Complex(9, 8) * 4 #=> (36+32i)
+ * Complex(20, 9) * 9.8 #=> (196.0+88.2i)
*/
VALUE
rb_complex_mul(VALUE self, VALUE other)
@@ -989,16 +942,16 @@ f_divide(VALUE self, VALUE other,
/*
* call-seq:
- * complex / numeric -> new_complex
- *
- * Returns the quotient of +self+ and +numeric+:
+ * cmp / numeric -> complex
+ * cmp.quo(numeric) -> complex
*
- * Complex.rect(2, 3) / Complex.rect(2, 3) # => (1+0i)
- * Complex.rect(900) / Complex.rect(1) # => (900+0i)
- * Complex.rect(-2, 9) / Complex.rect(-9, 2) # => ((36/85)-(77/85)*i)
- * Complex.rect(9, 8) / 4 # => ((9/4)+2i)
- * Complex.rect(20, 9) / 9.8 # => (2.0408163265306123+0.9183673469387754i)
+ * Performs division.
*
+ * Complex(2, 3) / Complex(2, 3) #=> ((1/1)+(0/1)*i)
+ * Complex(900) / Complex(1) #=> ((900/1)+(0/1)*i)
+ * Complex(-2, 9) / Complex(-9, 2) #=> ((36/85)-(77/85)*i)
+ * Complex(9, 8) / 4 #=> ((9/4)+(2/1)*i)
+ * Complex(20, 9) / 9.8 #=> (2.0408163265306123+0.9183673469387754i)
*/
VALUE
rb_complex_div(VALUE self, VALUE other)
@@ -1010,12 +963,11 @@ rb_complex_div(VALUE self, VALUE other)
/*
* call-seq:
- * fdiv(numeric) -> new_complex
- *
- * Returns <tt>Complex.rect(self.real/numeric, self.imag/numeric)</tt>:
+ * cmp.fdiv(numeric) -> complex
*
- * Complex.rect(11, 22).fdiv(3) # => (3.6666666666666665+7.333333333333333i)
+ * Performs division as each part is a float, never returns a float.
*
+ * Complex(11, 22).fdiv(3) #=> (3.6666666666666665+7.333333333333333i)
*/
static VALUE
nucomp_fdiv(VALUE self, VALUE other)
@@ -1029,95 +981,14 @@ f_reciprocal(VALUE x)
return f_quo(ONE, x);
}
-static VALUE
-zero_for(VALUE x)
-{
- if (RB_FLOAT_TYPE_P(x))
- return DBL2NUM(0);
- if (RB_TYPE_P(x, T_RATIONAL))
- return rb_rational_new(INT2FIX(0), INT2FIX(1));
-
- return INT2FIX(0);
-}
-
-static VALUE
-complex_pow_for_special_angle(VALUE self, VALUE other)
-{
- if (!rb_integer_type_p(other)) {
- return Qundef;
- }
-
- get_dat1(self);
- VALUE x = Qundef;
- int dir;
- if (f_zero_p(dat->imag)) {
- x = dat->real;
- dir = 0;
- }
- else if (f_zero_p(dat->real)) {
- x = dat->imag;
- dir = 2;
- }
- else if (f_eqeq_p(dat->real, dat->imag)) {
- x = dat->real;
- dir = 1;
- }
- else if (f_eqeq_p(dat->real, f_negate(dat->imag))) {
- x = dat->imag;
- dir = 3;
- } else {
- dir = 0;
- }
-
- if (UNDEF_P(x)) return x;
-
- if (f_negative_p(x)) {
- x = f_negate(x);
- dir += 4;
- }
-
- VALUE zx;
- if (dir % 2 == 0) {
- zx = rb_num_pow(x, other);
- }
- else {
- zx = rb_num_pow(
- rb_funcall(rb_int_mul(TWO, x), '*', 1, x),
- rb_int_div(other, TWO)
- );
- if (rb_int_odd_p(other)) {
- zx = rb_funcall(zx, '*', 1, x);
- }
- }
- static const int dirs[][2] = {
- {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}
- };
- int z_dir = FIX2INT(rb_int_modulo(rb_int_mul(INT2FIX(dir), other), INT2FIX(8)));
-
- VALUE zr = Qfalse, zi = Qfalse;
- switch (dirs[z_dir][0]) {
- case 0: zr = zero_for(zx); break;
- case 1: zr = zx; break;
- case -1: zr = f_negate(zx); break;
- }
- switch (dirs[z_dir][1]) {
- case 0: zi = zero_for(zx); break;
- case 1: zi = zx; break;
- case -1: zi = f_negate(zx); break;
- }
- return nucomp_s_new_internal(CLASS_OF(self), zr, zi);
-}
-
-
/*
* call-seq:
- * complex ** numeric -> new_complex
+ * cmp ** numeric -> complex
*
- * Returns +self+ raised to power +numeric+:
- *
- * Complex.rect(0, 1) ** 2 # => (-1+0i)
- * Complex.rect(-8) ** Rational(1, 3) # => (1.0000000000000002+1.7320508075688772i)
+ * Performs exponentiation.
*
+ * Complex('i') ** 2 #=> (-1+0i)
+ * Complex(-8) ** Rational(1, 3) #=> (1.0000000000000002+1.7320508075688772i)
*/
VALUE
rb_complex_pow(VALUE self, VALUE other)
@@ -1135,14 +1006,6 @@ rb_complex_pow(VALUE self, VALUE other)
other = dat->real; /* c14n */
}
- if (other == ONE) {
- get_dat1(self);
- return nucomp_s_new_internal(CLASS_OF(self), dat->real, dat->imag);
- }
-
- VALUE result = complex_pow_for_special_angle(self, other);
- if (!UNDEF_P(result)) return result;
-
if (RB_TYPE_P(other, T_COMPLEX)) {
VALUE r, theta, nr, ntheta;
@@ -1215,13 +1078,15 @@ rb_complex_pow(VALUE self, VALUE other)
/*
* call-seq:
- * complex == object -> true or false
+ * cmp == object -> true or false
*
- * Returns +true+ if <tt>self.real == object.real</tt>
- * and <tt>self.imag == object.imag</tt>:
- *
- * Complex.rect(2, 3) == Complex.rect(2.0, 3.0) # => true
+ * Returns true if cmp equals object numerically.
*
+ * Complex(2, 3) == Complex(2, 3) #=> true
+ * Complex(5) == 5 #=> true
+ * Complex(0) == 0.0 #=> true
+ * Complex('1/3') == 0.33 #=> false
+ * Complex('1/2') == '1/2' #=> false
*/
static VALUE
nucomp_eqeq_p(VALUE self, VALUE other)
@@ -1249,26 +1114,17 @@ nucomp_real_p(VALUE self)
/*
* call-seq:
- * complex <=> object -> -1, 0, 1, or nil
- *
- * Returns:
+ * cmp <=> object -> 0, 1, -1, or nil
*
- * - <tt>self.real <=> object.real</tt> if both of the following are true:
- *
- * - <tt>self.imag == 0</tt>.
- * - <tt>object.imag == 0</tt>. # Always true if object is numeric but not complex.
- *
- * - +nil+ otherwise.
- *
- * Examples:
- *
- * Complex.rect(2) <=> 3 # => -1
- * Complex.rect(2) <=> 2 # => 0
- * Complex.rect(2) <=> 1 # => 1
- * Complex.rect(2, 1) <=> 1 # => nil # self.imag not zero.
- * Complex.rect(1) <=> Complex.rect(1, 1) # => nil # object.imag not zero.
- * Complex.rect(1) <=> 'Foo' # => nil # object.imag not defined.
+ * If +cmp+'s imaginary part is zero, and +object+ is also a
+ * real number (or a Complex number where the imaginary part is zero),
+ * compare the real part of +cmp+ to object. Otherwise, return nil.
*
+ * Complex(2, 3) <=> Complex(2, 3) #=> nil
+ * Complex(2, 3) <=> 1 #=> nil
+ * Complex(2) <=> 1 #=> 1
+ * Complex(2) <=> 2 #=> 0
+ * Complex(2) <=> 3 #=> -1
*/
static VALUE
nucomp_cmp(VALUE self, VALUE other)
@@ -1313,19 +1169,13 @@ nucomp_coerce(VALUE self, VALUE other)
/*
* call-seq:
- * abs -> float
- *
- * Returns the absolute value (magnitude) for +self+;
- * see {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
+ * cmp.abs -> real
+ * cmp.magnitude -> real
*
- * Complex.polar(-1, 0).abs # => 1.0
- *
- * If +self+ was created with
- * {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
- * is computed, and may be inexact:
- *
- * Complex.rectangular(1, 1).abs # => 1.4142135623730951 # The square root of 2.
+ * Returns the absolute part of its polar form.
*
+ * Complex(-1).abs #=> 1
+ * Complex(3.0, -4.0).abs #=> 5.0
*/
VALUE
rb_complex_abs(VALUE self)
@@ -1349,19 +1199,12 @@ rb_complex_abs(VALUE self)
/*
* call-seq:
- * abs2 -> float
- *
- * Returns square of the absolute value (magnitude) for +self+;
- * see {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
- *
- * Complex.polar(2, 2).abs2 # => 4.0
+ * cmp.abs2 -> real
*
- * If +self+ was created with
- * {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
- * is computed, and may be inexact:
- *
- * Complex.rectangular(1.0/3, 1.0/3).abs2 # => 0.2222222222222222
+ * Returns square of the absolute value.
*
+ * Complex(-1).abs2 #=> 1
+ * Complex(3.0, -4.0).abs2 #=> 25.0
*/
static VALUE
nucomp_abs2(VALUE self)
@@ -1373,19 +1216,13 @@ nucomp_abs2(VALUE self)
/*
* call-seq:
- * arg -> float
- *
- * Returns the argument (angle) for +self+ in radians;
- * see {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
- *
- * Complex.polar(3, Math::PI/2).arg # => 1.57079632679489660
+ * cmp.arg -> float
+ * cmp.angle -> float
+ * cmp.phase -> float
*
- * If +self+ was created with
- * {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
- * is computed, and may be inexact:
- *
- * Complex.polar(1, 1.0/3).arg # => 0.33333333333333326
+ * Returns the angle part of its polar form.
*
+ * Complex.polar(3, Math::PI/2).arg #=> 1.5707963267948966
*/
VALUE
rb_complex_arg(VALUE self)
@@ -1396,22 +1233,12 @@ rb_complex_arg(VALUE self)
/*
* call-seq:
- * rect -> array
- *
- * Returns the array <tt>[self.real, self.imag]</tt>:
+ * cmp.rect -> array
+ * cmp.rectangular -> array
*
- * Complex.rect(1, 2).rect # => [1, 2]
+ * Returns an array; [cmp.real, cmp.imag].
*
- * See {Rectangular Coordinates}[rdoc-ref:Complex@Rectangular+Coordinates].
- *
- * If +self+ was created with
- * {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value
- * is computed, and may be inexact:
- *
- * Complex.polar(1.0, 1.0).rect # => [0.5403023058681398, 0.8414709848078965]
- *
- *
- * Complex#rectangular is an alias for Complex#rect.
+ * Complex(1, 2).rectangular #=> [1, 2]
*/
static VALUE
nucomp_rect(VALUE self)
@@ -1422,20 +1249,11 @@ nucomp_rect(VALUE self)
/*
* call-seq:
- * polar -> array
- *
- * Returns the array <tt>[self.abs, self.arg]</tt>:
+ * cmp.polar -> array
*
- * Complex.polar(1, 2).polar # => [1.0, 2.0]
- *
- * See {Polar Coordinates}[rdoc-ref:Complex@Polar+Coordinates].
- *
- * If +self+ was created with
- * {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
- * is computed, and may be inexact:
- *
- * Complex.rect(1, 1).polar # => [1.4142135623730951, 0.7853981633974483]
+ * Returns an array; [cmp.abs, cmp.arg].
*
+ * Complex(1, 2).polar #=> [2.23606797749979, 1.1071487177940904]
*/
static VALUE
nucomp_polar(VALUE self)
@@ -1445,12 +1263,12 @@ nucomp_polar(VALUE self)
/*
* call-seq:
- * conj -> complex
+ * cmp.conj -> complex
+ * cmp.conjugate -> complex
*
- * Returns the conjugate of +self+, <tt>Complex.rect(self.imag, self.real)</tt>:
- *
- * Complex.rect(1, 2).conj # => (1-2i)
+ * Returns the complex conjugate.
*
+ * Complex(1, 2).conjugate #=> (1-2i)
*/
VALUE
rb_complex_conjugate(VALUE self)
@@ -1461,9 +1279,10 @@ rb_complex_conjugate(VALUE self)
/*
* call-seq:
- * real? -> false
+ * Complex(1).real? -> false
+ * Complex(1, 2).real? -> false
*
- * Returns +false+; for compatibility with Numeric#real?.
+ * Returns false, even if the complex number has no imaginary part.
*/
static VALUE
nucomp_real_p_m(VALUE self)
@@ -1473,17 +1292,11 @@ nucomp_real_p_m(VALUE self)
/*
* call-seq:
- * denominator -> integer
- *
- * Returns the denominator of +self+, which is
- * the {least common multiple}[https://en.wikipedia.org/wiki/Least_common_multiple]
- * of <tt>self.real.denominator</tt> and <tt>self.imag.denominator</tt>:
+ * cmp.denominator -> integer
*
- * Complex.rect(Rational(1, 2), Rational(2, 3)).denominator # => 6
+ * Returns the denominator (lcm of both denominator - real and imag).
*
- * Note that <tt>n.denominator</tt> of a non-rational numeric is +1+.
- *
- * Related: Complex#numerator.
+ * See numerator.
*/
static VALUE
nucomp_denominator(VALUE self)
@@ -1494,23 +1307,21 @@ nucomp_denominator(VALUE self)
/*
* call-seq:
- * numerator -> new_complex
- *
- * Returns the \Complex object created from the numerators
- * of the real and imaginary parts of +self+,
- * after converting each part to the
- * {lowest common denominator}[https://en.wikipedia.org/wiki/Lowest_common_denominator]
- * of the two:
+ * cmp.numerator -> numeric
*
- * c = Complex.rect(Rational(2, 3), Rational(3, 4)) # => ((2/3)+(3/4)*i)
- * c.numerator # => (8+9i)
+ * Returns the numerator.
*
- * In this example, the lowest common denominator of the two parts is 12;
- * the two converted parts may be thought of as \Rational(8, 12) and \Rational(9, 12),
- * whose numerators, respectively, are 8 and 9;
- * so the returned value of <tt>c.numerator</tt> is <tt>Complex.rect(8, 9)</tt>.
+ * 1 2 3+4i <- numerator
+ * - + -i -> ----
+ * 2 3 6 <- denominator
*
- * Related: Complex#denominator.
+ * c = Complex('1/2+2/3i') #=> ((1/2)+(2/3)*i)
+ * n = c.numerator #=> (3+4i)
+ * d = c.denominator #=> 6
+ * n / d #=> ((1/2)+(2/3)*i)
+ * Complex(Rational(n.real, d), Rational(n.imag, d))
+ * #=> ((1/2)+(2/3)*i)
+ * See denominator.
*/
static VALUE
nucomp_numerator(VALUE self)
@@ -1543,18 +1354,6 @@ rb_complex_hash(VALUE self)
return v;
}
-/*
- * :call-seq:
- * hash -> integer
- *
- * Returns the integer hash value for +self+.
- *
- * Two \Complex objects created from the same values will have the same hash value
- * (and will compare using #eql?):
- *
- * Complex.rect(1, 2).hash == Complex.rect(1, 2).hash # => true
- *
- */
static VALUE
nucomp_hash(VALUE self)
{
@@ -1593,15 +1392,16 @@ f_tpositive_p(VALUE x)
}
static VALUE
-f_format(VALUE self, VALUE s, VALUE (*func)(VALUE))
+f_format(VALUE self, VALUE (*func)(VALUE))
{
+ VALUE s;
int impos;
get_dat1(self);
impos = f_tpositive_p(dat->imag);
- rb_str_concat(s, (*func)(dat->real));
+ s = (*func)(dat->real);
rb_str_cat2(s, !impos ? "-" : "+");
rb_str_concat(s, (*func)(f_abs(dat->imag)));
@@ -1614,35 +1414,33 @@ f_format(VALUE self, VALUE s, VALUE (*func)(VALUE))
/*
* call-seq:
- * to_s -> string
- *
- * Returns a string representation of +self+:
+ * cmp.to_s -> string
*
- * Complex.rect(2).to_s # => "2+0i"
- * Complex.rect(-8, 6).to_s # => "-8+6i"
- * Complex.rect(0, Rational(1, 2)).to_s # => "0+1/2i"
- * Complex.rect(0, Float::INFINITY).to_s # => "0+Infinity*i"
- * Complex.rect(Float::NAN, Float::NAN).to_s # => "NaN+NaN*i"
+ * Returns the value as a string.
*
+ * Complex(2).to_s #=> "2+0i"
+ * Complex('-8/6').to_s #=> "-4/3+0i"
+ * Complex('1/2i').to_s #=> "0+1/2i"
+ * Complex(0, Float::INFINITY).to_s #=> "0+Infinity*i"
+ * Complex(Float::NAN, Float::NAN).to_s #=> "NaN+NaN*i"
*/
static VALUE
nucomp_to_s(VALUE self)
{
- return f_format(self, rb_usascii_str_new2(""), rb_String);
+ return f_format(self, rb_String);
}
/*
* call-seq:
- * inspect -> string
+ * cmp.inspect -> string
*
- * Returns a string representation of +self+:
- *
- * Complex.rect(2).inspect # => "(2+0i)"
- * Complex.rect(-8, 6).inspect # => "(-8+6i)"
- * Complex.rect(0, Rational(1, 2)).inspect # => "(0+(1/2)*i)"
- * Complex.rect(0, Float::INFINITY).inspect # => "(0+Infinity*i)"
- * Complex.rect(Float::NAN, Float::NAN).inspect # => "(NaN+NaN*i)"
+ * Returns the value as a string for inspection.
*
+ * Complex(2).inspect #=> "(2+0i)"
+ * Complex('-8/6').inspect #=> "((-4/3)+0i)"
+ * Complex('1/2i').inspect #=> "(0+(1/2)*i)"
+ * Complex(0, Float::INFINITY).inspect #=> "(0+Infinity*i)"
+ * Complex(Float::NAN, Float::NAN).inspect #=> "(NaN+NaN*i)"
*/
static VALUE
nucomp_inspect(VALUE self)
@@ -1650,7 +1448,7 @@ nucomp_inspect(VALUE self)
VALUE s;
s = rb_usascii_str_new2("(");
- f_format(self, s, rb_inspect);
+ rb_str_concat(s, f_format(self, rb_inspect));
rb_str_cat2(s, ")");
return s;
@@ -1660,15 +1458,10 @@ nucomp_inspect(VALUE self)
/*
* call-seq:
- * finite? -> true or false
- *
- * Returns +true+ if both <tt>self.real.finite?</tt> and <tt>self.imag.finite?</tt>
- * are true, +false+ otherwise:
- *
- * Complex.rect(1, 1).finite? # => true
- * Complex.rect(Float::INFINITY, 0).finite? # => false
+ * cmp.finite? -> true or false
*
- * Related: Numeric#finite?, Float#finite?.
+ * Returns +true+ if +cmp+'s real and imaginary parts are both finite numbers,
+ * otherwise returns +false+.
*/
static VALUE
rb_complex_finite_p(VALUE self)
@@ -1680,15 +1473,15 @@ rb_complex_finite_p(VALUE self)
/*
* call-seq:
- * infinite? -> 1 or nil
+ * cmp.infinite? -> nil or 1
*
- * Returns +1+ if either <tt>self.real.infinite?</tt> or <tt>self.imag.infinite?</tt>
- * is true, +nil+ otherwise:
+ * Returns +1+ if +cmp+'s real or imaginary part is an infinite number,
+ * otherwise returns +nil+.
*
- * Complex.rect(Float::INFINITY, 0).infinite? # => 1
- * Complex.rect(1, 1).infinite? # => nil
+ * For example:
*
- * Related: Numeric#infinite?, Float#infinite?.
+ * (1+1i).infinite? #=> nil
+ * (Float::INFINITY + 1i).infinite? #=> 1
*/
static VALUE
rb_complex_infinite_p(VALUE self)
@@ -1716,7 +1509,7 @@ nucomp_loader(VALUE self, VALUE a)
RCOMPLEX_SET_REAL(dat, rb_ivar_get(a, id_i_real));
RCOMPLEX_SET_IMAG(dat, rb_ivar_get(a, id_i_imag));
- OBJ_FREEZE(self);
+ OBJ_FREEZE_RAW(self);
return self;
}
@@ -1786,15 +1579,14 @@ rb_dbl_complex_new(double real, double imag)
/*
* call-seq:
- * to_i -> integer
- *
- * Returns the value of <tt>self.real</tt> as an Integer, if possible:
+ * cmp.to_i -> integer
*
- * Complex.rect(1, 0).to_i # => 1
- * Complex.rect(1, Rational(0, 1)).to_i # => 1
+ * Returns the value as an integer if possible (the imaginary part
+ * should be exactly zero).
*
- * Raises RangeError if <tt>self.imag</tt> is not exactly zero
- * (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>).
+ * Complex(1, 0).to_i #=> 1
+ * Complex(1, 0.0).to_i # RangeError
+ * Complex(1, 2).to_i # RangeError
*/
static VALUE
nucomp_to_i(VALUE self)
@@ -1810,15 +1602,14 @@ nucomp_to_i(VALUE self)
/*
* call-seq:
- * to_f -> float
+ * cmp.to_f -> float
*
- * Returns the value of <tt>self.real</tt> as a Float, if possible:
+ * Returns the value as a float if possible (the imaginary part should
+ * be exactly zero).
*
- * Complex.rect(1, 0).to_f # => 1.0
- * Complex.rect(1, Rational(0, 1)).to_f # => 1.0
- *
- * Raises RangeError if <tt>self.imag</tt> is not exactly zero
- * (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>).
+ * Complex(1, 0).to_f #=> 1.0
+ * Complex(1, 0.0).to_f # RangeError
+ * Complex(1, 2).to_f # RangeError
*/
static VALUE
nucomp_to_f(VALUE self)
@@ -1834,69 +1625,41 @@ nucomp_to_f(VALUE self)
/*
* call-seq:
- * to_r -> rational
- *
- * Returns the value of <tt>self.real</tt> as a Rational, if possible:
+ * cmp.to_r -> rational
*
- * Complex.rect(1, 0).to_r # => (1/1)
- * Complex.rect(1, Rational(0, 1)).to_r # => (1/1)
- * Complex.rect(1, 0.0).to_r # => (1/1)
+ * Returns the value as a rational if possible (the imaginary part
+ * should be exactly zero).
*
- * Raises RangeError if <tt>self.imag</tt> is not exactly zero
- * (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>)
- * and <tt>self.imag.to_r</tt> is not exactly zero.
+ * Complex(1, 0).to_r #=> (1/1)
+ * Complex(1, 0.0).to_r # RangeError
+ * Complex(1, 2).to_r # RangeError
*
- * Related: Complex#rationalize.
+ * See rationalize.
*/
static VALUE
nucomp_to_r(VALUE self)
{
get_dat1(self);
- if (RB_FLOAT_TYPE_P(dat->imag) && FLOAT_ZERO_P(dat->imag)) {
- /* Do nothing here */
- }
- else if (!k_exact_zero_p(dat->imag)) {
- VALUE imag = rb_check_convert_type_with_id(dat->imag, T_RATIONAL, "Rational", idTo_r);
- if (NIL_P(imag) || !k_exact_zero_p(imag)) {
- rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
- self);
- }
+ if (!k_exact_zero_p(dat->imag)) {
+ rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
+ self);
}
return f_to_r(dat->real);
}
/*
* call-seq:
- * rationalize(epsilon = nil) -> rational
- *
- * Returns a Rational object whose value is exactly or approximately
- * equivalent to that of <tt>self.real</tt>.
- *
- * With no argument +epsilon+ given, returns a \Rational object
- * whose value is exactly equal to that of <tt>self.real.rationalize</tt>:
- *
- * Complex.rect(1, 0).rationalize # => (1/1)
- * Complex.rect(1, Rational(0, 1)).rationalize # => (1/1)
- * Complex.rect(3.14159, 0).rationalize # => (314159/100000)
- *
- * With argument +epsilon+ given, returns a \Rational object
- * whose value is exactly or approximately equal to that of <tt>self.real</tt>
- * to the given precision:
- *
- * Complex.rect(3.14159, 0).rationalize(0.1) # => (16/5)
- * Complex.rect(3.14159, 0).rationalize(0.01) # => (22/7)
- * Complex.rect(3.14159, 0).rationalize(0.001) # => (201/64)
- * Complex.rect(3.14159, 0).rationalize(0.0001) # => (333/106)
- * Complex.rect(3.14159, 0).rationalize(0.00001) # => (355/113)
- * Complex.rect(3.14159, 0).rationalize(0.000001) # => (7433/2366)
- * Complex.rect(3.14159, 0).rationalize(0.0000001) # => (9208/2931)
- * Complex.rect(3.14159, 0).rationalize(0.00000001) # => (47460/15107)
- * Complex.rect(3.14159, 0).rationalize(0.000000001) # => (76149/24239)
- * Complex.rect(3.14159, 0).rationalize(0.0000000001) # => (314159/100000)
- * Complex.rect(3.14159, 0).rationalize(0.0) # => (3537115888337719/1125899906842624)
- *
- * Related: Complex#to_r.
+ * cmp.rationalize([eps]) -> rational
+ *
+ * Returns the value as a rational if possible (the imaginary part
+ * should be exactly zero).
+ *
+ * Complex(1.0/3, 0).rationalize #=> (1/3)
+ * Complex(1, 0.0).rationalize # RangeError
+ * Complex(1, 2).rationalize # RangeError
+ *
+ * See to_r.
*/
static VALUE
nucomp_rationalize(int argc, VALUE *argv, VALUE self)
@@ -1914,9 +1677,12 @@ nucomp_rationalize(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * to_c -> self
+ * complex.to_c -> self
*
- * Returns +self+.
+ * Returns self.
+ *
+ * Complex(2).to_c #=> (2+0i)
+ * Complex(-8, 6).to_c #=> (-8+6i)
*/
static VALUE
nucomp_to_c(VALUE self)
@@ -1926,12 +1692,9 @@ nucomp_to_c(VALUE self)
/*
* call-seq:
- * to_c -> (0+0i)
- *
- * Returns zero as a Complex:
- *
- * nil.to_c # => (0+0i)
+ * nil.to_c -> (0+0i)
*
+ * Returns zero as a complex.
*/
static VALUE
nilclass_to_c(VALUE self)
@@ -1941,9 +1704,9 @@ nilclass_to_c(VALUE self)
/*
* call-seq:
- * to_c -> complex
+ * num.to_c -> complex
*
- * Returns +self+ as a Complex object.
+ * Returns the value as a complex.
*/
static VALUE
numeric_to_c(VALUE self)
@@ -2223,14 +1986,23 @@ string_to_c_strict(VALUE self, int raise)
rb_must_asciicompat(self);
- if (raise) {
- s = StringValueCStr(self);
+ s = RSTRING_PTR(self);
+
+ if (!s || memchr(s, '\0', RSTRING_LEN(self))) {
+ if (!raise) return Qnil;
+ rb_raise(rb_eArgError, "string contains null byte");
}
- else if (!(s = rb_str_to_cstr(self))) {
- return Qnil;
+
+ if (s && s[RSTRING_LEN(self)]) {
+ rb_str_modify(self);
+ s = RSTRING_PTR(self);
+ s[RSTRING_LEN(self)] = '\0';
}
- if (!parse_comp(s, TRUE, &num)) {
+ if (!s)
+ s = (char *)"";
+
+ if (!parse_comp(s, 1, &num)) {
if (!raise) return Qnil;
rb_raise(rb_eArgError, "invalid value for convert(): %+"PRIsVALUE,
self);
@@ -2241,39 +2013,53 @@ string_to_c_strict(VALUE self, int raise)
/*
* call-seq:
- * to_c -> complex
- *
- * Returns +self+ interpreted as a Complex object;
- * leading whitespace and trailing garbage are ignored:
- *
- * '9'.to_c # => (9+0i)
- * '2.5'.to_c # => (2.5+0i)
- * '2.5/1'.to_c # => ((5/2)+0i)
- * '-3/2'.to_c # => ((-3/2)+0i)
- * '-i'.to_c # => (0-1i)
- * '45i'.to_c # => (0+45i)
- * '3-4i'.to_c # => (3-4i)
- * '-4e2-4e-2i'.to_c # => (-400.0-0.04i)
- * '-0.0-0.0i'.to_c # => (-0.0-0.0i)
- * '1/2+3/4i'.to_c # => ((1/2)+(3/4)*i)
- * '1.0@0'.to_c # => (1+0.0i)
- * "1.0@#{Math::PI/2}".to_c # => (0.0+1i)
- * "1.0@#{Math::PI}".to_c # => (-1+0.0i)
- *
- * Returns \Complex zero if the string cannot be converted:
- *
- * 'ruby'.to_c # => (0+0i)
- *
- * See Kernel#Complex.
+ * str.to_c -> complex
+ *
+ * Returns a complex which denotes the string form. The parser
+ * ignores leading whitespaces and trailing garbage. Any digit
+ * sequences can be separated by an underscore. Returns zero for null
+ * or garbage string.
+ *
+ * '9'.to_c #=> (9+0i)
+ * '2.5'.to_c #=> (2.5+0i)
+ * '2.5/1'.to_c #=> ((5/2)+0i)
+ * '-3/2'.to_c #=> ((-3/2)+0i)
+ * '-i'.to_c #=> (0-1i)
+ * '45i'.to_c #=> (0+45i)
+ * '3-4i'.to_c #=> (3-4i)
+ * '-4e2-4e-2i'.to_c #=> (-400.0-0.04i)
+ * '-0.0-0.0i'.to_c #=> (-0.0-0.0i)
+ * '1/2+3/4i'.to_c #=> ((1/2)+(3/4)*i)
+ * 'ruby'.to_c #=> (0+0i)
+ *
+ * Polar form:
+ * include Math
+ * "1.0@0".to_c #=> (1+0.0i)
+ * "1.0@#{PI/2}".to_c #=> (0.0+1i)
+ * "1.0@#{PI}".to_c #=> (-1+0.0i)
+ *
+ * See Kernel.Complex.
*/
static VALUE
string_to_c(VALUE self)
{
+ char *s;
VALUE num;
rb_must_asciicompat(self);
- (void)parse_comp(rb_str_fill_terminator(self, 1), FALSE, &num);
+ s = RSTRING_PTR(self);
+
+ if (s && s[RSTRING_LEN(self)]) {
+ rb_str_modify(self);
+ s = RSTRING_PTR(self);
+ s[RSTRING_LEN(self)] = '\0';
+ }
+
+ if (!s)
+ s = (char *)"";
+
+ (void)parse_comp(s, 0, &num);
return num;
}
@@ -2378,9 +2164,9 @@ nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
/*
* call-seq:
- * abs2 -> real
+ * num.abs2 -> real
*
- * Returns the square of +self+.
+ * Returns square of self.
*/
static VALUE
numeric_abs2(VALUE self)
@@ -2390,9 +2176,11 @@ numeric_abs2(VALUE self)
/*
* call-seq:
- * arg -> 0 or Math::PI
+ * num.arg -> 0 or float
+ * num.angle -> 0 or float
+ * num.phase -> 0 or float
*
- * Returns zero if +self+ is positive, Math::PI otherwise.
+ * Returns 0 if the value is positive, pi otherwise.
*/
static VALUE
numeric_arg(VALUE self)
@@ -2404,9 +2192,10 @@ numeric_arg(VALUE self)
/*
* call-seq:
- * rect -> array
+ * num.rect -> array
+ * num.rectangular -> array
*
- * Returns array <tt>[self, 0]</tt>.
+ * Returns an array; [num, 0].
*/
static VALUE
numeric_rect(VALUE self)
@@ -2416,9 +2205,9 @@ numeric_rect(VALUE self)
/*
* call-seq:
- * polar -> array
+ * num.polar -> array
*
- * Returns array <tt>[self.abs, self.arg]</tt>.
+ * Returns an array; [num.abs, num.arg].
*/
static VALUE
numeric_polar(VALUE self)
@@ -2446,9 +2235,11 @@ numeric_polar(VALUE self)
/*
* call-seq:
- * arg -> 0 or Math::PI
+ * flo.arg -> 0 or float
+ * flo.angle -> 0 or float
+ * flo.phase -> 0 or float
*
- * Returns 0 if +self+ is positive, Math::PI otherwise.
+ * Returns 0 if the value is positive, pi otherwise.
*/
static VALUE
float_arg(VALUE self)
@@ -2461,137 +2252,45 @@ float_arg(VALUE self)
}
/*
- * A \Complex object houses a pair of values,
- * given when the object is created as either <i>rectangular coordinates</i>
- * or <i>polar coordinates</i>.
- *
- * == Rectangular Coordinates
- *
- * The rectangular coordinates of a complex number
- * are called the _real_ and _imaginary_ parts;
- * see {Complex number definition}[https://en.wikipedia.org/wiki/Complex_number#Definition_and_basic_operations].
- *
- * You can create a \Complex object from rectangular coordinates with:
- *
- * - A {complex literal}[rdoc-ref:doc/syntax/literals.rdoc@Complex+Literals].
- * - \Method Complex.rect.
- * - \Method Kernel#Complex, either with numeric arguments or with certain string arguments.
- * - \Method String#to_c, for certain strings.
- *
- * Note that each of the stored parts may be a an instance one of the classes
- * Complex, Float, Integer, or Rational;
- * they may be retrieved:
- *
- * - Separately, with methods Complex#real and Complex#imaginary.
- * - Together, with method Complex#rect.
- *
- * The corresponding (computed) polar values may be retrieved:
- *
- * - Separately, with methods Complex#abs and Complex#arg.
- * - Together, with method Complex#polar.
- *
- * == Polar Coordinates
- *
- * The polar coordinates of a complex number
- * are called the _absolute_ and _argument_ parts;
- * see {Complex polar plane}[https://en.wikipedia.org/wiki/Complex_number#Polar_form].
- *
- * In this class, the argument part
- * in expressed {radians}[https://en.wikipedia.org/wiki/Radian]
- * (not {degrees}[https://en.wikipedia.org/wiki/Degree_(angle)]).
- *
- * You can create a \Complex object from polar coordinates with:
- *
- * - \Method Complex.polar.
- * - \Method Kernel#Complex, with certain string arguments.
- * - \Method String#to_c, for certain strings.
- *
- * Note that each of the stored parts may be a an instance one of the classes
- * Complex, Float, Integer, or Rational;
- * they may be retrieved:
- *
- * - Separately, with methods Complex#abs and Complex#arg.
- * - Together, with method Complex#polar.
- *
- * The corresponding (computed) rectangular values may be retrieved:
- *
- * - Separately, with methods Complex#real and Complex#imag.
- * - Together, with method Complex#rect.
- *
- * == What's Here
- *
- * First, what's elsewhere:
- *
- * - \Class \Complex inherits (directly or indirectly)
- * from classes {Numeric}[rdoc-ref:Numeric@What-27s+Here]
- * and {Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes (indirectly) module {Comparable}[rdoc-ref:Comparable@What-27s+Here].
- *
- * Here, class \Complex has methods for:
- *
- * === Creating \Complex Objects
- *
- * - ::polar: Returns a new \Complex object based on given polar coordinates.
- * - ::rect (and its alias ::rectangular):
- * Returns a new \Complex object based on given rectangular coordinates.
- *
- * === Querying
- *
- * - #abs (and its alias #magnitude): Returns the absolute value for +self+.
- * - #arg (and its aliases #angle and #phase):
- * Returns the argument (angle) for +self+ in radians.
- * - #denominator: Returns the denominator of +self+.
- * - #finite?: Returns whether both +self.real+ and +self.image+ are finite.
- * - #hash: Returns the integer hash value for +self+.
- * - #imag (and its alias #imaginary): Returns the imaginary value for +self+.
- * - #infinite?: Returns whether +self.real+ or +self.image+ is infinite.
- * - #numerator: Returns the numerator of +self+.
- * - #polar: Returns the array <tt>[self.abs, self.arg]</tt>.
- * - #inspect: Returns a string representation of +self+.
- * - #real: Returns the real value for +self+.
- * - #real?: Returns +false+; for compatibility with Numeric#real?.
- * - #rect (and its alias #rectangular):
- * Returns the array <tt>[self.real, self.imag]</tt>.
+ * A complex number can be represented as a paired real number with
+ * imaginary unit; a+bi. Where a is real part, b is imaginary part
+ * and i is imaginary unit. Real a equals complex a+0i
+ * mathematically.
*
- * === Comparing
+ * You can create a \Complex object explicitly with:
*
- * - #<=>: Returns whether +self+ is less than, equal to, or greater than the given argument.
- * - #==: Returns whether +self+ is equal to the given argument.
+ * - A {complex literal}[rdoc-ref:syntax/literals.rdoc@Complex+Literals].
*
- * === Converting
+ * You can convert certain objects to \Complex objects with:
*
- * - #rationalize: Returns a Rational object whose value is exactly
- * or approximately equivalent to that of <tt>self.real</tt>.
- * - #to_c: Returns +self+.
- * - #to_d: Returns the value as a BigDecimal object.
- * - #to_f: Returns the value of <tt>self.real</tt> as a Float, if possible.
- * - #to_i: Returns the value of <tt>self.real</tt> as an Integer, if possible.
- * - #to_r: Returns the value of <tt>self.real</tt> as a Rational, if possible.
- * - #to_s: Returns a string representation of +self+.
+ * - \Method #Complex.
*
- * === Performing Complex Arithmetic
+ * Complex object can be created as literal, and also by using
+ * Kernel#Complex, Complex::rect, Complex::polar or to_c method.
*
- * - #*: Returns the product of +self+ and the given numeric.
- * - #**: Returns +self+ raised to power of the given numeric.
- * - #+: Returns the sum of +self+ and the given numeric.
- * - #-: Returns the difference of +self+ and the given numeric.
- * - #-@: Returns the negation of +self+.
- * - #/: Returns the quotient of +self+ and the given numeric.
- * - #abs2: Returns square of the absolute value (magnitude) for +self+.
- * - #conj (and its alias #conjugate): Returns the conjugate of +self+.
- * - #fdiv: Returns <tt>Complex.rect(self.real/numeric, self.imag/numeric)</tt>.
+ * 2+1i #=> (2+1i)
+ * Complex(1) #=> (1+0i)
+ * Complex(2, 3) #=> (2+3i)
+ * Complex.polar(2, 3) #=> (-1.9799849932008908+0.2822400161197344i)
+ * 3.to_c #=> (3+0i)
*
- * === Working with JSON
+ * You can also create complex object from floating-point numbers or
+ * strings.
*
- * - ::json_create: Returns a new \Complex object,
- * deserialized from the given serialized hash.
- * - #as_json: Returns a serialized hash constructed from +self+.
- * - #to_json: Returns a JSON string representing +self+.
+ * Complex(0.3) #=> (0.3+0i)
+ * Complex('0.3-0.5i') #=> (0.3-0.5i)
+ * Complex('2/3+3/4i') #=> ((2/3)+(3/4)*i)
+ * Complex('1@2') #=> (-0.4161468365471424+0.9092974268256817i)
*
- * These methods are provided by the {JSON gem}[https://github.com/flori/json]. To make these methods available:
+ * 0.3.to_c #=> (0.3+0i)
+ * '0.3-0.5i'.to_c #=> (0.3-0.5i)
+ * '2/3+3/4i'.to_c #=> ((2/3)+(3/4)*i)
+ * '1@2'.to_c #=> (-0.4161468365471424+0.9092974268256817i)
*
- * require 'json/add/complex'
+ * A complex object is either an exact or an inexact number.
*
+ * Complex(1, 1) / 2 #=> ((1/2)+(1/2)*i)
+ * Complex(1, 1) / 2.0 #=> (0.5+0.5i)
*/
void
Init_Complex(void)
@@ -2712,17 +2411,13 @@ Init_Complex(void)
rb_define_method(rb_cFloat, "phase", float_arg, 0);
/*
- * Equivalent
- * to <tt>Complex.rect(0, 1)</tt>:
- *
- * Complex::I # => (0+1i)
- *
+ * The imaginary unit.
*/
rb_define_const(rb_cComplex, "I",
f_complex_new_bang2(rb_cComplex, ZERO, ONE));
#if !USE_FLONUM
- rb_vm_register_global_object(RFLOAT_0 = DBL2NUM(0.0));
+ rb_gc_register_mark_object(RFLOAT_0 = DBL2NUM(0.0));
#endif
rb_provide("complex.so"); /* for backward compatibility */
diff --git a/configure.ac b/configure.ac
index d099b62679..220392d120 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9,67 +9,49 @@ tooldir="$srcdir/tool"
AC_DISABLE_OPTION_CHECKING
-m4_define([RUBY_M4_INCLUDED], [])dnl
-AC_DEFUN([RUBY_M4_INCLUDE], [m4_include([tool/m4/$1])dnl
- m4_append([RUBY_M4_INCLUDED], [ \
- $(tooldir)/m4/$1])dnl
-])
-RUBY_M4_INCLUDE([_colorize_result_prepare.m4])dnl
-RUBY_M4_INCLUDE([ac_msg_result.m4])dnl
-RUBY_M4_INCLUDE([colorize_result.m4])dnl
-RUBY_M4_INCLUDE([ruby_append_option.m4])dnl
-RUBY_M4_INCLUDE([ruby_append_options.m4])dnl
-RUBY_M4_INCLUDE([ruby_check_builtin_func.m4])dnl
-RUBY_M4_INCLUDE([ruby_check_builtin_setjmp.m4])dnl
-RUBY_M4_INCLUDE([ruby_check_header.m4])dnl
-RUBY_M4_INCLUDE([ruby_check_printf_prefix.m4])dnl
-RUBY_M4_INCLUDE([ruby_check_setjmp.m4])dnl
-RUBY_M4_INCLUDE([ruby_check_signedness.m4])dnl
-RUBY_M4_INCLUDE([ruby_check_sizeof.m4])dnl
-RUBY_M4_INCLUDE([ruby_check_sysconf.m4])dnl
-RUBY_M4_INCLUDE([ruby_cppoutfile.m4])dnl
-RUBY_M4_INCLUDE([ruby_decl_attribute.m4])dnl
-RUBY_M4_INCLUDE([ruby_default_arch.m4])dnl
-RUBY_M4_INCLUDE([ruby_define_if.m4])dnl
-RUBY_M4_INCLUDE([ruby_defint.m4])dnl
-RUBY_M4_INCLUDE([ruby_dtrace_available.m4])dnl
-RUBY_M4_INCLUDE([ruby_dtrace_postprocess.m4])dnl
-RUBY_M4_INCLUDE([ruby_func_attribute.m4])dnl
-RUBY_M4_INCLUDE([ruby_mingw32.m4])dnl
-RUBY_M4_INCLUDE([ruby_prepend_option.m4])dnl
-RUBY_M4_INCLUDE([ruby_prog_gnu_ld.m4])dnl
-RUBY_M4_INCLUDE([ruby_prog_makedirs.m4])dnl
-RUBY_M4_INCLUDE([ruby_replace_funcs.m4])dnl
-RUBY_M4_INCLUDE([ruby_replace_type.m4])dnl
-RUBY_M4_INCLUDE([ruby_require_funcs.m4])dnl
-RUBY_M4_INCLUDE([ruby_rm_recursive.m4])dnl
-RUBY_M4_INCLUDE([ruby_setjmp_type.m4])dnl
-RUBY_M4_INCLUDE([ruby_shared_gc.m4])dnl
-RUBY_M4_INCLUDE([ruby_stack_grow_direction.m4])dnl
-RUBY_M4_INCLUDE([ruby_thread.m4])dnl
-RUBY_M4_INCLUDE([ruby_try_cflags.m4])dnl
-RUBY_M4_INCLUDE([ruby_try_cxxflags.m4])dnl
-RUBY_M4_INCLUDE([ruby_try_ldflags.m4])dnl
-RUBY_M4_INCLUDE([ruby_universal_arch.m4])dnl
-RUBY_M4_INCLUDE([ruby_wasm_tools.m4])dnl
-RUBY_M4_INCLUDE([ruby_werror_flag.m4])dnl
-
-AS_IF([test "x${GITHUB_ACTIONS}" = xtrue],
-[AC_REQUIRE([_COLORIZE_RESULT_PREPARE])dnl
-dnl 93(bright yellow) is copied from .github/workflows/mingw.yml
- begin_group() { AS_ECHO(["::group::@<:@93m$[]1@<:@m"]);}
- end_group() { AS_ECHO(["::endgroup::"]);}
-],
-[dnl
- begin_group() { :;}
- end_group() { :;}
-])
+m4_include([tool/m4/_colorize_result_prepare.m4])dnl
+m4_include([tool/m4/ac_msg_result.m4])dnl
+m4_include([tool/m4/colorize_result.m4])dnl
+m4_include([tool/m4/ruby_append_option.m4])dnl
+m4_include([tool/m4/ruby_append_options.m4])dnl
+m4_include([tool/m4/ruby_check_builtin_func.m4])dnl
+m4_include([tool/m4/ruby_check_builtin_setjmp.m4])dnl
+m4_include([tool/m4/ruby_check_printf_prefix.m4])dnl
+m4_include([tool/m4/ruby_check_setjmp.m4])dnl
+m4_include([tool/m4/ruby_check_signedness.m4])dnl
+m4_include([tool/m4/ruby_check_sizeof.m4])dnl
+m4_include([tool/m4/ruby_check_sysconf.m4])dnl
+m4_include([tool/m4/ruby_cppoutfile.m4])dnl
+m4_include([tool/m4/ruby_decl_attribute.m4])dnl
+m4_include([tool/m4/ruby_default_arch.m4])dnl
+m4_include([tool/m4/ruby_define_if.m4])dnl
+m4_include([tool/m4/ruby_defint.m4])dnl
+m4_include([tool/m4/ruby_dtrace_available.m4])dnl
+m4_include([tool/m4/ruby_dtrace_postprocess.m4])dnl
+m4_include([tool/m4/ruby_func_attribute.m4])dnl
+m4_include([tool/m4/ruby_mingw32.m4])dnl
+m4_include([tool/m4/ruby_prepend_option.m4])dnl
+m4_include([tool/m4/ruby_prog_gnu_ld.m4])dnl
+m4_include([tool/m4/ruby_prog_makedirs.m4])dnl
+m4_include([tool/m4/ruby_replace_funcs.m4])dnl
+m4_include([tool/m4/ruby_replace_type.m4])dnl
+m4_include([tool/m4/ruby_require_funcs.m4])dnl
+m4_include([tool/m4/ruby_rm_recursive.m4])dnl
+m4_include([tool/m4/ruby_setjmp_type.m4])dnl
+m4_include([tool/m4/ruby_stack_grow_direction.m4])dnl
+m4_include([tool/m4/ruby_thread.m4])dnl
+m4_include([tool/m4/ruby_try_cflags.m4])dnl
+m4_include([tool/m4/ruby_try_cxxflags.m4])dnl
+m4_include([tool/m4/ruby_try_ldflags.m4])dnl
+m4_include([tool/m4/ruby_universal_arch.m4])dnl
+m4_include([tool/m4/ruby_wasm_tools.m4])dnl
+m4_include([tool/m4/ruby_werror_flag.m4])dnl
AC_ARG_VAR([cflags], [additional CFLAGS (ignored when CFLAGS is given)])dnl
AC_ARG_VAR([cppflags], [additional CPPFLAGS (ignored when CPPFLAGS is given)])dnl
AC_ARG_VAR([cxxflags], [additional CXXFLAGS (ignored when CXXFLAGS is given)])dnl
-[begin]_group "environment section" && {
+: "environment section" && {
HAVE_BASERUBY=yes
BASERUBY_VERSION=
AC_ARG_WITH(baseruby,
@@ -82,21 +64,21 @@ AC_ARG_WITH(baseruby,
[
AC_PATH_PROG([BASERUBY], [ruby], [false])
])
-AS_IF([test "$HAVE_BASERUBY" != no], [
- RUBYOPT=- $BASERUBY --disable=gems -rerb -rfileutils -rtempfile "${tooldir}/missing-baseruby.bat" || HAVE_BASERUBY=no
-])
-AS_IF([test "${HAVE_BASERUBY:=no}" != no], [
+# BASERUBY must be >= 2.2.0. Note that `"2.2.0" > "2.2"` is true.
+AS_IF([test "$HAVE_BASERUBY" != no -a "`RUBYOPT=- $BASERUBY --disable=gems -e 'print 42 if RUBY_VERSION > "2.2"' 2>/dev/null`" = 42], [
AS_CASE(["$build_os"], [mingw*], [
# Can MSys shell run a command with a drive letter?
RUBYOPT=- `cygpath -ma "$BASERUBY"` --disable=gems -e exit 2>/dev/null || HAVE_BASERUBY=no
])
- RUBY_APPEND_OPTION(BASERUBY, "--disable=gems")
+ BASERUBY="$BASERUBY --disable=gems"
BASERUBY_VERSION=`$BASERUBY -v`
$BASERUBY -C "$srcdir" tool/downloader.rb -d tool -e gnu config.guess config.sub >&AS_MESSAGE_FD
+], [
+ HAVE_BASERUBY=no
])
AS_IF([test "$HAVE_BASERUBY" = no], [
AS_IF([test "$cross_compiling" = yes], [AC_MSG_ERROR([executable host ruby is required for cross-compiling])])
- BASERUBY=${tooldir}/missing-baseruby.bat
+ BASERUBY="echo executable host ruby is required. use --with-baseruby option.; false"
])
AC_SUBST(BASERUBY)
AC_SUBST(HAVE_BASERUBY)
@@ -261,7 +243,7 @@ AS_CASE(["${build_os}"],
AC_PATH_TOOL([NM], [nm], [/usr/ccs/bin/nm], [/usr/ccs/bin:$PATH])
])
AS_CASE(["${target_os}"],
-[cygwin*|msys*|mingw*|darwin*], [
+[cygwin*|msys*|mingw*], [
ac_cv_prog_ac_ct_OBJCOPY=":"
])
@@ -280,14 +262,10 @@ AC_CHECK_TOOLS([AR], [gar ar])
AC_CHECK_TOOLS([AS], [gas as])
AC_CHECK_TOOLS([LD], [gld ld]) # ... try gold ?
AC_CHECK_TOOLS([NM], [gnm nm])
-AC_CHECK_TOOLS([OBJCOPY], [gobjcopy objcopy], [:])
+AC_CHECK_TOOLS([OBJCOPY], [gobjcopy objcopy])
AC_CHECK_TOOLS([OBJDUMP], [gobjdump objdump])
AC_CHECK_TOOLS([STRIP], [gstrip strip], [:])
-# nm errors with Rust's LLVM bitcode when Rust uses a newer LLVM version than nm.
-# In case we're working with llvm-nm, tell it to not worry about the bitcode.
-AS_IF([${NM} --help 2>&1 | grep -q 'llvm-bc'], [NM="$NM --no-llvm-bc"])
-
AS_IF([test ! $rb_test_CFLAGS], [AS_UNSET(CFLAGS)]); AS_UNSET(rb_test_CFLAGS)
AS_IF([test ! $rb_test_CXXFLAGS], [AS_UNSET(CXXFLAGS)]); AS_UNSET(rb_save_CXXFLAGS)
@@ -360,7 +338,7 @@ test -z "$warnflags" ||
AS_IF([test -z "${CFLAGS+set}"], [
cflags=`echo " $cflags " | sed "$cflagspat;s/^ *//;s/ *$//"`
orig_cflags="$cflags"
- cflags='${hardenflags} '"$cflags "'${optflags} ${debugflags} ${warnflags}'
+ cflags="$cflags "'${optflags} ${debugflags} ${warnflags}'
])
dnl AS_IF([test -z "${CXXFLAGS+set}"], [
dnl cxxflags=`echo " $cxxflags " | sed "$cflagspat;s/^ *//;s/ *$//"`
@@ -415,6 +393,13 @@ AS_IF([test "$GCC" = yes], [
AS_IF([test "$gcc_major" -lt 4], [
AC_MSG_ERROR([too old GCC: $gcc_major.$gcc_minor])
])
+
+ AC_CACHE_CHECK([if thread-local storage is supported], [rb_cv_tls_supported],
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM([[int __thread conftest;]])],
+ [rb_cv_tls_supported=yes],
+ [rb_cv_tls_supported=no])])
+ AS_IF([test x"$rb_cv_tls_supported" != xyes],
+ [AC_DEFINE(RB_THREAD_LOCAL_SPECIFIER_IS_UNSUPPORTED)])
], [
linker_flag=
])
@@ -429,26 +414,33 @@ AC_SUBST(OUTFLAG)
AC_SUBST(COUTFLAG)
AC_SUBST(CSRCFLAG)
+: ${MJIT_CC=$CC}
+AS_IF([test "x$cross_compiling" = xno], [
+ AC_PATH_PROG([MJIT_CC], ${MJIT_CC})
+
+ # if $CC is in /usr/lib/ccache/$CC, search original $CC (disable ccache)
+ AS_IF([echo $RUBY_DEBUG | grep ci > /dev/null &&
+ echo $MJIT_CC | grep ^/usr/lib/ccache > /dev/null], [
+ PATH=`echo $PATH | sed "s/\/usr\/lib\/ccache://"` MJIT_CC=`which $CC`])
+
+ AS_CASE([$target_os],
+ [*mingw*], [command -v cygpath > /dev/null && MJIT_CC=`cygpath -ma $MJIT_CC`])
+ shift 2
+ MJIT_CC="$MJIT_CC${1+ }$*"
+])
+
AS_CASE(["$build_os"],
- [darwin*], [
- # gcc 13 warns duplicate -l options, which are added by the
- # default spec.
+ [darwin1*.*], [
# Xcode linker warns for deprecated architecture and wrongly
# installed TBD files.
- AC_MSG_CHECKING(for $CC linker warning)
- suppress_ld_waring=no
+ CC_WRAPPER=""
echo 'int main(void) {return 0;}' > conftest.c
AS_IF([$CC -framework Foundation -o conftest conftest.c 2>&1 |
- grep \
- -e '^ld: warning: ignoring duplicate libraries:' \
- -e '^ld: warning: text-based stub file' \
- -e '^ld: warning: -multiply_defined is obsolete' \
- >/dev/null], [
- suppress_ld_waring=yes
+ grep '^ld: warning: text-based stub file' >/dev/null], [
+ CC_WRAPPER=`cd -P "${tooldir}" && pwd`/darwin-cc
+ CC="$CC_WRAPPER $CC"
])
rm -fr conftest*
- test $suppress_ld_waring = yes && warnflags="${warnflags:+${warnflags} }-Wl,-w"
- AC_MSG_RESULT($suppress_ld_waring)
])
AS_CASE(["$target_os"],
[wasi*], [
@@ -475,8 +467,8 @@ AC_SUBST(CC_VERSION_MESSAGE, $cc_version_message)
: ${DLDFLAGS="$LDFLAGS"}
RUBY_UNIVERSAL_ARCH
-AS_IF([test "$target_cpu" != "$host_cpu" -a "$GCC" = yes -a "${universal_binary:-no}" = no], [
- RUBY_DEFAULT_ARCH($target_cpu)
+AS_IF([test "$target_cpu" != "$host_cpu" -a "$GCC" = yes -a "$cross_compiling" = no -a "${universal_binary:-no}" = no], [
+ RUBY_DEFAULT_ARCH("$target_cpu")
])
host_os=$target_os
host_vendor=$target_vendor
@@ -489,6 +481,7 @@ AC_CACHE_CHECK([for $AR flags], [rb_cv_arflags], [
[rb_cv_arflags=rcD], [rb_cv_arflags=rcu])
])
AC_SUBST(ARFLAGS, ["$rb_cv_arflags "])
+AC_SUBST(ASFLAGS)
AS_CASE(["$target_os"],
[cygwin*|msys*|mingw*], [
@@ -519,7 +512,6 @@ AS_CASE(["$target_os"],
])
rb_cv_binary_elf=no
: ${enable_shared=yes}
- AS_IF([$WINDRES --version | grep LLVM > /dev/null], [USE_LLVM_WINDRES=yes], [USE_LLVM_WINDRES=no])
],
[hiuxmpp*], [AC_DEFINE(__HIUX_MPP__)]) # by TOYODA Eizi <toyoda@npd.kishou.go.jp>
@@ -603,7 +595,7 @@ AC_MSG_RESULT([$CHDIR])
AC_SUBST(CHDIR)
}
-[begin]_group "compiler section" && {
+: "compiler section" && {
RUBY_WERROR_FLAG([
AC_MSG_CHECKING([whether CFLAGS is valid])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
@@ -662,9 +654,9 @@ RUBY_WERROR_FLAG([
[enable_rpath=$enableval], [enable_rpath="$rb_cv_binary_elf"])
AS_IF([test "$enable_rpath:${RPATHFLAG}" = yes:], [
- RPATHFLAG="${rpathflag:+${rpathflag}%1\$-s}"
+ RPATHFLAG="${rpathflag:+ ${rpathflag}%1\$-s}"
])
- AS_CASE([${RPATHFLAG}],[*'%1$'*],[: ${LIBPATHFLAG='-L%1$-s'}],[: ${LIBPATHFLAG='-L%s'}])
+ AS_CASE([${RPATHFLAG}],[*'%1$'*],[: ${LIBPATHFLAG=' -L%1$-s'}],[: ${LIBPATHFLAG=' -L%s'}])
}
RUBY_TRY_LDFLAGS(-fdeclspec, [fdeclspec=yes], [fdeclspec=no])
@@ -698,10 +690,6 @@ AS_CASE(["$GCC:${warnflags+set}:${extra_warnflags:+set}:"],
AS_IF([test $gcc_major -le 6], [
extra_warnflags="$extra_warnflags -Wno-maybe-uninitialized"
])
- AS_CASE([ $CFLAGS ], [*" -save-temps="*|*" -save-temps "*], [], [
- extra_warnflags="$extra_warnflags -Werror=misleading-indentation"
- ])
-
# ICC doesn't support -Werror=
AS_IF([test $icc_version -gt 0], [
particular_werror_flags=no
@@ -713,6 +701,7 @@ AS_CASE(["$GCC:${warnflags+set}:${extra_warnflags:+set}:"],
-Werror=duplicated-cond \
-Werror=implicit-function-declaration \
-Werror=implicit-int \
+ -Werror=misleading-indentation \
-Werror=pointer-arith \
-Werror=shorten-64-to-32 \
-Werror=write-strings \
@@ -812,10 +801,12 @@ AS_IF([test "$GCC" = yes], [
[fortify_source=$enableval])
AS_IF([test "x$fortify_source" != xno], [
RUBY_TRY_CFLAGS([$optflags -D_FORTIFY_SOURCE=2],
- [RUBY_PREPEND_OPTION(hardenflags, -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2)], [],
+ [RUBY_APPEND_OPTION(XCFLAGS, -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2)], [],
[@%:@include <stdio.h>])
])
+ : ${MJIT_HEADER_FLAGS='-P -dD'}
+
# -fstack-protector
AS_CASE(["$target_os"],
[emscripten*|wasi*], [
@@ -833,45 +824,18 @@ AS_IF([test "$GCC" = yes], [
AC_MSG_CHECKING([for -fstack-protector])
AC_MSG_RESULT(["$stack_protector"])
AS_CASE(["$stack_protector"], [-*], [
- RUBY_PREPEND_OPTION(hardenflags, $stack_protector)
- RUBY_APPEND_OPTION(XLDFLAGS, $stack_protector)
- RUBY_APPEND_OPTION(LDFLAGS, $stack_protector)
+ RUBY_APPEND_OPTION(XCFLAGS, $stack_protector)
+ RUBY_APPEND_OPTION(XLDFLAGS, $stack_protector)
+ RUBY_APPEND_OPTION(LDFLAGS, $stack_protector)
])
# aarch64 branch protection
- AS_CASE(["$target_cpu"], [aarch64|arm64], [
- # LLVM libunwind is not actually capable of unwinding code compiled with pointer
- # authentication unless it's built without LIBUNWIND_ENABLE_CROSS_UNWINDING (see
- # https://github.com/llvm/llvm-project/blob/8e35c86977ce5529a9387657321ac9fefcdae5b5/libunwind/src/DwarfInstructions.hpp#L294)
- # It seems that macOS ships LLVM compiled this way.
- # Detect this and disable automatic insertion of pac-ret flags in that case, since we assume
- # that reliable backtraces are more important than hardening flags.
- AC_MSG_CHECKING([for a broken LLVM libunwind that cannot unwind code with RA signing])
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
- @%:@include <libunwind.h>
- int foo = UNW_ECROSSRASIGNING;
- ]])],
- # If compilation succeeds, that means we a) had libunwind, and b) it was NOT native only
- [rb_cv_libunwind_broken_ra_signing=yes],
- # if compilation fails, that means we either a) do not have libunwind, or b) have it in
- # native only mode (which is good!)
- [rb_cv_libunwind_broken_ra_signing=no]
- )
- AC_MSG_RESULT(["$rb_cv_libunwind_broken_ra_signing"])
- AS_IF([test "x$rb_cv_libunwind_broken_ra_signing" = "xno"], [
- AS_FOR(option, opt, [-mbranch-protection=pac-ret -msign-return-address=all], [
- # Try these flags in the _prepended_ position - i.e. we want to try building a program
- # with CFLAGS="-mbranch-protection=pac-ret $CFLAGS". If the builder has provided different
- # branch protection flags in CFLAGS, we don't want to overwrite those. We just want to
- # find some branch protection flags which work if none were provided.
- RUBY_TRY_CFLAGS_PREPEND(option, [branch_protection=yes], [branch_protection=no])
- AS_IF([test "x$branch_protection" = xyes], [
- # _prepend_ the options to CFLAGS, so that user-provided flags will overwrite them.
- # These CFLAGS are used during the configure script to compile further test programs;
- # however, $harden_flags is prepended separately to CFLAGS at the end of the script.
- RUBY_PREPEND_OPTION(hardenflags, $opt)
- break
- ])
+ AS_CASE(["$target_cpu"], [aarch64], [
+ AS_FOR(option, opt, [-mbranch-protection=pac-ret -msign-return-address=all], [
+ RUBY_TRY_CFLAGS(option, [branch_protection=yes], [branch_protection=no])
+ AS_IF([test "x$branch_protection" = xyes], [
+ RUBY_APPEND_OPTION(XCFLAGS, option)
+ break
])
])
])
@@ -927,9 +891,9 @@ AS_IF([test "$GCC" = yes], [
# suppress annoying -Wstrict-overflow warnings
RUBY_TRY_CFLAGS(-fno-strict-overflow, [RUBY_APPEND_OPTION(XCFLAGS, -fno-strict-overflow)])
- test "${debugflags+set}" || {RUBY_TRY_LDFLAGS(-ggdb3, [debugflags=-ggdb3])}
- test "${debugflags+set}" || {RUBY_TRY_LDFLAGS(-ggdb, [debugflags=-ggdb])}
- test "${debugflags+set}" || {RUBY_TRY_LDFLAGS(-g3, [debugflags=-g3])}
+ test "${debugflags+set}" || {RUBY_TRY_CFLAGS(-ggdb3, [debugflags=-ggdb3])}
+ test "${debugflags+set}" || {RUBY_TRY_CFLAGS(-ggdb, [debugflags=-ggdb])}
+ test "${debugflags+set}" || {RUBY_TRY_CFLAGS(-g3, [debugflags=-g3])}
])
test $ac_cv_prog_cc_g = yes && : ${debugflags=-g}
@@ -946,6 +910,7 @@ AS_IF([test "$GCC" = yes], [
], [
RUBY_TRY_LDFLAGS([-Wl,-unexported_symbol,_Init_*], [visibility_option=ld], [visibility_option=no])
])
+ test "$visibility_option" = no || OBJCOPY=:
])
AS_IF([test "$GCC" = yes], [
@@ -1001,17 +966,9 @@ AC_ARG_WITH(opt-dir,
[OPT_DIR="${OPT_DIR:+$OPT_DIR$PATH_SEPARATOR}$withval"], [])
AS_IF([test "x$OPT_DIR" != x], [
- save_IFS="$IFS" IFS="$PATH_SEPARATOR" val= PWD=
- for dir in $OPT_DIR; do
- test -z "$dir" && continue
- dir=`eval $CHDIR '"$dir"' && pwd` || continue
- val="${val:+$val$PATH_SEPARATOR}$dir"
- done
- IFS="$save_IFS" OPT_DIR="$val"
- unset PWD
- unset save_IFS
val=`IFS="$PATH_SEPARATOR"
for dir in $OPT_DIR; do
+ test -z "$dir" && continue
echo x ${LIBPATHFLAG} ${RPATHFLAG} |
sed "s/^x *//;s${IFS}"'%1\\$-s'"${IFS}${dir}/lib${IFS}g;s${IFS}%s${IFS}${dir}/lib${IFS}g"
done | tr '\012' ' ' | sed 's/ *$//'`
@@ -1025,7 +982,7 @@ AC_SUBST(incflags, "$INCFLAGS")
test -z "${ac_env_CFLAGS_set}" -a -n "${cflags+set}" && eval CFLAGS="\"$cflags $ARCH_FLAG\""
test -z "${ac_env_CXXFLAGS_set}" -a -n "${cxxflags+set}" && eval CXXFLAGS="\"$cxxflags $ARCH_FLAG\""
-
+}
AC_CACHE_CHECK([whether compiler has statement and declarations in expressions],
rb_cv_have_stmt_and_decl_in_expr,
@@ -1035,9 +992,8 @@ AC_CACHE_CHECK([whether compiler has statement and declarations in expressions],
AS_IF([test "$rb_cv_have_stmt_and_decl_in_expr" = yes], [
AC_DEFINE(HAVE_STMT_AND_DECL_IN_EXPR)
])
-}
-[begin]_group "header and library section" && {
+: "header and library section" && {
AC_ARG_WITH(winnt-ver,
AS_HELP_STRING([--with-winnt-ver=0xXXXX], [target Windows NT version (default to 0x0600)]),
[with_winnt_ver="$withval"], [with_winnt_ver="0x0600"])
@@ -1092,6 +1048,7 @@ AS_CASE(["$target_os"],
AS_IF([test $gcc_major -eq 4 -a $gcc_minor -lt 3], [
ac_cv_func___builtin_setjmp=no
])
+ with_setjmp_type=sigsetjmp # to hijack SIGCHLD handler
AC_CACHE_CHECK(for broken crypt with 8bit chars, rb_cv_broken_crypt,
[AC_RUN_IFELSE([AC_LANG_SOURCE([[
#include <stdio.h>
@@ -1139,23 +1096,21 @@ main()
])
POSTLINK=""
AC_CHECK_PROGS(codesign, codesign)
- dsymutils=
- AS_CASE("$CC_NO_WRAPPER", [gcc*-1[[3-9]]], [
- dsymutils=${CC_NO_WRAPPER@%:@gcc}
- dsymutils=dsymutil${dsymutils%-1*}
- dsymutils="$dsymutils-19 $dsymutils-18 $dsymutils-17"
- ])
- AC_CHECK_PROGS(dsymutil, $dsymutils dsymutil)
+ AC_CHECK_PROGS(dsymutil, dsymutil)
AS_IF([test -n "$codesign"], [
- POSTLINK="{ test -z '\$(RUBY_CODESIGN)' || $codesign -s '\$(RUBY_CODESIGN)' \$@; }${POSTLINK:+; $POSTLINK}"
+ POSTLINK="{ test -z '\$(RUBY_CODESIGN)' || $codesign -s '\$(RUBY_CODESIGN)' -f \$@; }${POSTLINK:+; $POSTLINK}"
])
AS_IF([test -n "$dsymutil"], [
- POSTLINK="$dsymutil \$@ 2>/dev/null${POSTLINK:+; $POSTLINK}"
+ POSTLINK="$dsymutil \$@${POSTLINK:+; $POSTLINK}"
+ ])
+ AS_IF([test -n "${POSTLINK}"], [
+ LINK_SO="$LINK_SO
+\$(POSTLINK)"
])
AC_CHECK_HEADERS(crt_externs.h, [], [], [
#include <crt_externs.h>
])
- cleanlibs='$(TARGET_SO:=.dSYM)'
+ cleanlibs='$(TARGET_SO).dSYM'
],
[solaris*], [ LIBS="-lm $LIBS"
ac_cv_func_vfork=no
@@ -1248,8 +1203,6 @@ main()
ac_cv_func_gmtime_r=yes
rb_cv_large_fd_select=yes
ac_cv_type_struct_timeval=yes
- ac_cv_func_clock_gettime=yes
- ac_cv_func_clock_getres=yes
ac_cv_func_malloc_usable_size=no
ac_cv_type_off_t=yes
ac_cv_sizeof_off_t=8
@@ -1290,11 +1243,10 @@ main()
# __builtin_longjmp in ppc64* Linux does not restore
# the TOC register (r2), which is problematic
# when a global exit happens from JITted .so code.
- # __builtin_setjmp can have issues on arm64 linux (see [Bug #14480]).
- AS_CASE(["$target_cpu"], [powerpc64*|arm64|aarch64], [
+ AS_CASE(["$target_cpu"], [powerpc64*], [
ac_cv_func___builtin_setjmp=no
])
- # With gcc-8's -fcf-protection, RJIT's __builtin_longjmp fails.
+ # With gcc-8's -fcf-protection, MJIT's __builtin_longjmp fails.
AS_CASE(["$CC $CFLAGS "], [*" -fcf-protection "*], [cf_protection=yes], [cf_protection=no])
AS_IF([test "$cf_protection" = yes], [
ac_cv_func___builtin_setjmp=no
@@ -1309,7 +1261,7 @@ main()
[wasi*],[ LIBS="-lm -lwasi-emulated-mman -lwasi-emulated-signal -lwasi-emulated-getpid -lwasi-emulated-process-clocks $LIBS"
RUBY_APPEND_OPTIONS(CFLAGS, -D_WASI_EMULATED_SIGNAL -D_WASI_EMULATED_MMAN -D_WASI_EMULATED_GETPID -D_WASI_EMULATED_PROCESS_CLOCKS)
RUBY_APPEND_OPTIONS(CPPFLAGS, -D_WASI_EMULATED_SIGNAL -D_WASI_EMULATED_MMAN -D_WASI_EMULATED_GETPID -D_WASI_EMULATED_PROCESS_CLOCKS)
- POSTLINK="\$(WASMOPT) --asyncify \$(wasmoptflags) -o \$@ \$@${POSTLINK:+; $POSTLINK}"
+ POSTLINK="\$(WASMOPT) --asyncify \$(wasmoptflags) --pass-arg=asyncify-ignore-imports -o \$@ \$@${POSTLINK:+; $POSTLINK}"
# wasi-libc's sys/socket.h is not compatible with -std=gnu99,
# so re-declare shutdown in include/ruby/missing.h
ac_cv_func_shutdown=no
@@ -1317,13 +1269,6 @@ main()
[ LIBS="-lm $LIBS"])
: ${ORIG_LIBS=$LIBS}
-AS_IF([test -n "${POSTLINK}"], [
- # NOTE: A (part of) link commands used link shared extension libraries. If
- # the first line of the value is empty, mkmf prepends default link steps.
- LINK_SO="$LINK_SO
-\$(POSTLINK)"
-])
-
AS_IF([test -n "${rb_there_is_in_fact_no_gplusplus_but_autoconf_is_cheating_us}"], [
AC_MSG_NOTICE([Test skipped due to lack of a C++ compiler.])
],
@@ -1403,18 +1348,15 @@ AC_CHECK_HEADERS(syscall.h)
AC_CHECK_HEADERS(time.h)
AC_CHECK_HEADERS(ucontext.h)
AC_CHECK_HEADERS(utime.h)
-AC_CHECK_HEADERS(sys/epoll.h)
-AC_CHECK_HEADERS(sys/event.h)
-AC_CHECK_HEADERS(stdckdint.h)
AC_CHECK_HEADERS(stdatomic.h)
-AS_CASE("$target_cpu", [x64|x86_64|[i[3-6]86*]], [
+AS_CASE("$target_cpu", [x64|x86_64|i[3-6]86*], [
AC_CHECK_HEADERS(x86intrin.h)
])
RUBY_UNIVERSAL_CHECK_HEADER([x86_64, i386], x86intrin.h)
AS_IF([test "x$with_gmp" != xno],
- [RUBY_CHECK_HEADER(gmp.h)
+ [AC_CHECK_HEADERS(gmp.h)
AS_IF([test "x$ac_cv_header_gmp_h" != xno],
AC_SEARCH_LIBS([__gmpz_init], [gmp],
[AC_DEFINE(HAVE_LIBGMP, 1)]))])
@@ -1484,7 +1426,7 @@ AC_SYS_LARGEFILE
# which is not added by AC_SYS_LARGEFILE.
AS_IF([test x"$enable_largefile" != xno], [
AS_CASE(["$target_os"], [solaris*], [
- AC_MSG_CHECKING([whether _LARGEFILE_SOURCE should be defined])
+ AC_MSG_CHECKING([wheather _LARGEFILE_SOURCE should be defined])
AS_CASE(["${ac_cv_sys_file_offset_bits}:${ac_cv_sys_large_files}"],
["64:"|"64:no"|"64:unknown"], [
# insert _LARGEFILE_SOURCE before _FILE_OFFSET_BITS line
@@ -1545,25 +1487,6 @@ RUBY_CHECK_SIZEOF(float)
RUBY_CHECK_SIZEOF(double)
RUBY_CHECK_SIZEOF(time_t, [long "long long"], [], [@%:@include <time.h>])
RUBY_CHECK_SIZEOF(clock_t, [], [], [@%:@include <time.h>])
-AC_SUBST(X_BUILTIN_BINARY, yes)
-AS_IF([test "$cross_compiling" = yes],
-[dnl miniruby cannot run if cross compiling
- X_BUILTIN_BINARY=no
-],
-[
- AS_CASE([ac_cv_sizeof_voidp],
- [[1-9]*], [dnl fixed value
- ],
- [
- AC_CACHE_CHECK([word size], [rb_cv_word_size],
- [for w in 4 8; do
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@if SIZEOF_VOIDP != ${w}
- @%:@error SIZEOF_VOIDP
- @%:@endif]])], [rb_cv_word_size=${w}; break])
- done])
- AS_IF([test -z $rb_cv_word_size], [X_BUILTIN_BINARY=no])
- ])
-])
AC_CACHE_CHECK(packed struct attribute, rb_cv_packed_struct,
[rb_cv_packed_struct=no
@@ -1576,9 +1499,10 @@ AC_CACHE_CHECK(packed struct attribute, rb_cv_packed_struct,
[rb_cv_packed_struct=$mac; break])
done])
AS_IF([test "$rb_cv_packed_struct" != no], [
- AC_DEFINE_UNQUOTED([RBIMPL_ATTR_PACKED_STRUCT_BEGIN()], [`echo " $rb_cv_packed_struct " | sed 's/ x .*//;s/^ *//'`])
- AC_DEFINE_UNQUOTED([RBIMPL_ATTR_PACKED_STRUCT_END()], [`echo " $rb_cv_packed_struct " | sed 's/.* x //;s/ *$//'`])
+ AC_DEFINE_UNQUOTED([PACKED_STRUCT(x)], [$rb_cv_packed_struct])
RUBY_TRY_CFLAGS(-Wno-address-of-packed-member, [AC_DEFINE(USE_UNALIGNED_MEMBER_ACCESS)])
+], [
+ AC_DEFINE_UNQUOTED([PACKED_STRUCT(x)], x)
])
AS_IF([test "x$ac_cv_type_long_long" = xyes], [
@@ -1683,7 +1607,7 @@ AS_IF([test "$rb_cv_func_weak" != x], [
AC_DEFINE(HAVE_FUNC_WEAK)
])
-AC_CACHE_CHECK([for __attribute__((__deprecated__(msg))) in C++],
+AC_CACHE_CHECK([for __attribute__((__depreacted__(msg))) in C++],
rb_cv_CentOS6_CXX_workaround,
RUBY_WERROR_FLAG([
AC_LANG_PUSH([C++])
@@ -1793,7 +1717,7 @@ AS_IF([test "$GCC" = yes], [
AC_CACHE_CHECK(for exported function attribute, rb_cv_func_exported, [
rb_cv_func_exported=no
RUBY_WERROR_FLAG([
-for mac in '__declspec(dllexport)' '__attribute__ ((__visibility__("default")))'; do
+for mac in '__attribute__ ((__visibility__("default")))' '__declspec(dllexport)'; do
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@define RUBY_FUNC_EXPORTED $mac extern
RUBY_FUNC_EXPORTED void conftest_attribute_check(void);]], [[]])],
[rb_cv_func_exported="$mac"; break])
@@ -1819,7 +1743,7 @@ AC_CACHE_CHECK(for function name string predefined identifier,
[AS_CASE(["$target_os"],[openbsd*],[
rb_cv_function_name_string=__func__
],[
- rb_cv_function_name_string=no
+ rb_cv_function_name_string=no
RUBY_WERROR_FLAG([
for func in __func__ __FUNCTION__; do
AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include <stdio.h>]],
@@ -1827,8 +1751,7 @@ AC_CACHE_CHECK(for function name string predefined identifier,
[rb_cv_function_name_string=$func
break])
done
- ])
- ])]
+ ])])]
)
AS_IF([test "$rb_cv_function_name_string" != no], [
AC_DEFINE_UNQUOTED(RUBY_FUNCTION_NAME_STRING, [$rb_cv_function_name_string])
@@ -2088,7 +2011,7 @@ AC_CHECK_FUNCS(_longjmp) # used for AC_ARG_WITH(setjmp-type)
test x$ac_cv_func__longjmp = xno && ac_cv_func__setjmp=no
AC_CHECK_FUNCS(arc4random_buf)
AC_CHECK_FUNCS(atan2l atan2f)
-AC_CHECK_DECLS(atomic_signal_fence, [], [], [@%:@include <stdatomic.h>])
+AC_CHECK_DECLS(atomic_signal_fence, [], [], [#include <stdatomic.h>])
AC_CHECK_FUNCS(chmod)
AC_CHECK_FUNCS(chown)
AC_CHECK_FUNCS(chroot)
@@ -2112,7 +2035,6 @@ AC_CHECK_FUNCS(execv)
AC_CHECK_FUNCS(execve)
AC_CHECK_FUNCS(explicit_memset)
AC_CHECK_FUNCS(fcopyfile)
-AC_CHECK_FUNCS(fchdir)
AC_CHECK_FUNCS(fchmod)
AC_CHECK_FUNCS(fchown)
AC_CHECK_FUNCS(fcntl)
@@ -2153,6 +2075,7 @@ AC_CHECK_FUNCS(gettimeofday) # for making ac_cv_func_gettimeofday
AC_CHECK_FUNCS(getuid)
AC_CHECK_FUNCS(getuidx)
AC_CHECK_FUNCS(gmtime_r)
+AC_CHECK_FUNCS(grantpt)
AC_CHECK_FUNCS(initgroups)
AC_CHECK_FUNCS(ioctl)
AC_CHECK_FUNCS(isfinite)
@@ -2169,7 +2092,6 @@ AC_CHECK_FUNCS(lstat)
AC_CHECK_FUNCS(lutimes)
AC_CHECK_FUNCS(malloc_usable_size)
AC_CHECK_FUNCS(malloc_size)
-AC_CHECK_FUNCS(malloc_trim)
AC_CHECK_FUNCS(mblen)
AC_CHECK_FUNCS(memalign)
AC_CHECK_FUNCS(memset_s)
@@ -2223,7 +2145,6 @@ AC_CHECK_FUNCS(sigaction)
AC_CHECK_FUNCS(sigaltstack)
AC_CHECK_FUNCS(sigprocmask)
AC_CHECK_FUNCS(sinh)
-AC_CHECK_FUNCS(snprintf)
AC_CHECK_FUNCS(spawnv)
AC_CHECK_FUNCS(symlink)
AC_CHECK_FUNCS(syscall)
@@ -2248,6 +2169,9 @@ AC_CHECK_FUNCS(__sinpi)
AS_IF([test "x$ac_cv_member_struct_statx_stx_btime" = xyes],
[AC_CHECK_FUNCS(statx)])
+AS_CASE(["$ac_cv_func_memset_s:$ac_cv_func_qsort_s"], [*yes*],
+ [RUBY_DEFINE_IF([!defined __STDC_WANT_LIB_EXT1__], [__STDC_WANT_LIB_EXT1__], 1)])
+
AS_IF([test "$ac_cv_func_getcwd" = yes], [
AC_CACHE_CHECK(if getcwd allocates buffer if NULL is given, [rb_cv_getcwd_malloc],
[AC_RUN_IFELSE([AC_LANG_SOURCE([[
@@ -2316,27 +2240,6 @@ RUBY_CHECK_BUILTIN_FUNC(__builtin_types_compatible_p, [__builtin_types_compatibl
RUBY_CHECK_BUILTIN_FUNC(__builtin_trap, [__builtin_trap()])
RUBY_CHECK_BUILTIN_FUNC(__builtin_expect, [__builtin_expect(0, 0)])
-AS_IF([test "$rb_cv_builtin___builtin_mul_overflow" != no], [
- AC_CACHE_CHECK(for __builtin_mul_overflow with long long arguments, rb_cv_use___builtin_mul_overflow_long_long, [
- AC_LINK_IFELSE([AC_LANG_SOURCE([[
-#pragma clang optimize off
-
-int
-main(void)
-{
- long long x = 0, y;
- __builtin_mul_overflow(x, x, &y);
-
- return 0;
-}
-]])],
- rb_cv_use___builtin_mul_overflow_long_long=yes,
- rb_cv_use___builtin_mul_overflow_long_long=no)])
-])
-AS_IF([test "$rb_cv_use___builtin_mul_overflow_long_long" = yes], [
- AC_DEFINE(USE___BUILTIN_MUL_OVERFLOW_LONG_LONG, 1)
-])
-
AS_IF([test "$ac_cv_func_qsort_r" != no], [
AC_CACHE_CHECK(whether qsort_r is GNU version, rb_cv_gnu_qsort_r,
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
@@ -2724,9 +2627,6 @@ AS_CASE([$coroutine_type], [yes|''], [
[*86-mingw*], [
coroutine_type=win32
],
- [aarch64-mingw*], [
- coroutine_type=arm64
- ],
[arm*-linux*], [
coroutine_type=arm32
],
@@ -2739,9 +2639,6 @@ AS_CASE([$coroutine_type], [yes|''], [
[riscv64-linux*], [
coroutine_type=riscv64
],
- [loongarch64-linux*], [
- coroutine_type=loongarch64
- ],
[x86_64-freebsd*], [
coroutine_type=amd64
],
@@ -2751,12 +2648,6 @@ AS_CASE([$coroutine_type], [yes|''], [
[aarch64-freebsd*], [
coroutine_type=arm64
],
- [powerpc64-freebsd*], [
- coroutine_type=ppc64le
- ],
- [powerpc64le-freebsd*], [
- coroutine_type=ppc64le
- ],
[x86_64-netbsd*], [
coroutine_type=amd64
],
@@ -2772,9 +2663,6 @@ AS_CASE([$coroutine_type], [yes|''], [
[i386-openbsd*], [
coroutine_type=x86
],
- [aarch64-openbsd*], [
- coroutine_type=arm64
- ],
[*-openbsd*], [
coroutine_type=pthread
],
@@ -2872,22 +2760,6 @@ AS_IF([test "$THREAD_MODEL" = pthread], [
AC_DEFINE_UNQUOTED(SET_ANOTHER_THREAD_NAME(thid,name), $set_another_thread_name)
])
])
-
- AC_CACHE_CHECK([for thread-local storage specifier], [rb_cv_tls_specifier],
- rb_cv_tls_specifier=none
- RUBY_WERROR_FLAG([
- for attr in \
- _Thread_local \
- __thread \
- ; do
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[$attr int conftest;]])],
- [rb_cv_tls_specifier=$attr; break])
- done
- ])
- )
- AS_IF([test x"${rb_cv_tls_specifier}" != xnone],
- [AC_DEFINE_UNQUOTED(RB_THREAD_LOCAL_SPECIFIER, ${rb_cv_tls_specifier})]
- )
])
AS_IF([test x"$ac_cv_header_ucontext_h" = xno], [
@@ -3031,8 +2903,8 @@ AS_IF([test "x$ac_cv_func_ioctl" = xyes], [
}
-[begin]_group "runtime section" && {
-dnl whether use dln_a_out or not
+: "runtime section" && {
+dnl wheather use dln_a_out or not
AC_ARG_WITH(dln-a-out,
AS_HELP_STRING([--with-dln-a-out], [dln_a_out is deprecated]),
[
@@ -3065,8 +2937,22 @@ AS_CASE(["$target_os"],
])])
LIBEXT=a
+AC_ARG_WITH(mjit-tabs,
+ AS_HELP_STRING([--without-mjit-tabs], [expand tabs in mjit header]),
+ [AS_IF([test $withval = no], [MJIT_TABS=false])])
+AC_SUBST(MJIT_TABS)dnl
AC_SUBST(DLDFLAGS)dnl
AC_SUBST(ARCH_FLAG)dnl
+AC_SUBST(MJIT_HEADER_FLAGS)dnl
+AC_SUBST(MJIT_HEADER_INSTALL_DIR)dnl
+AC_SUBST(MJIT_CC)dnl
+AS_CASE(["$GCC:$target_os"],
+ [yes:aix*], [mjit_std_cflag="-std=gnu99"],
+ [mjit_std_cflag=])
+AC_SUBST(MJIT_CFLAGS, [${MJIT_CFLAGS-"-w ${mjit_std_cflag} ${orig_cflags}"}])dnl
+AC_SUBST(MJIT_OPTFLAGS, [${MJIT_OPTFLAGS-'$(optflags)'}])dnl
+AC_SUBST(MJIT_DEBUGFLAGS, [${MJIT_DEBUGFLAGS-'$(debugflags)'}])dnl
+AC_SUBST(MJIT_LDSHARED)dnl
AC_SUBST(STATIC)dnl
AC_SUBST(CCDLFLAGS)dnl
@@ -3183,7 +3069,8 @@ AC_SUBST(EXTOBJS)
: ${LIBPATHENV=DYLD_LIBRARY_PATH}
: ${PRELOADENV=DYLD_INSERT_LIBRARIES}
AS_IF([test x"$enable_shared" = xyes], [
- # Resolve symbols from libruby.dylib in $(LIBS) when --enable-shared
+ # Resolve symbols from libruby.dylib when --enable-shared
+ EXTDLDFLAGS='$(LIBRUBYARG_SHARED)'
], [test "x$EXTSTATIC" = x], [
# When building exts as bundles, a mach-o bundle needs to know its loader
# program to bind symbols from the ruby executable
@@ -3219,7 +3106,6 @@ AC_SUBST(EXTOBJS)
[hiuxmpp], [ : ${LDSHARED='$(LD) -r'}],
[atheos*], [ : ${LDSHARED='$(CC) -shared'}
rb_cv_dlopen=yes],
- [wasi*], [ : ${LDSHARED='$(LD) -shared -Xlinker --export-dynamic'}],
[ : ${LDSHARED='$(LD)'}])
AC_MSG_RESULT($rb_cv_dlopen)
}
@@ -3475,7 +3361,7 @@ done
BTESTRUBY='$(MINIRUBY)'
AS_IF([test x"$cross_compiling" = xyes], [
- test x"$MINIRUBY" = x && MINIRUBY="${RUBY-$BASERUBY} -I${ac_abs_builddir-.} "-r'$(arch)-fake'
+ test x"$MINIRUBY" = x && MINIRUBY="${RUBY-$BASERUBY} -I`$CHDIR .; pwd` "-r'$(arch)-fake'
XRUBY_LIBDIR=`${RUBY-$BASERUBY} -rrbconfig -e ['puts RbConfig::CONFIG["libdir"]']`
XRUBY_RUBYLIBDIR=`${RUBY-$BASERUBY} -rrbconfig -e ['puts RbConfig::CONFIG["rubylibdir"]']`
XRUBY_RUBYHDRDIR=`${RUBY-$BASERUBY} -rrbconfig -e ['puts RbConfig::CONFIG["rubyhdrdir"]']`
@@ -3533,6 +3419,9 @@ AC_ARG_ENABLE(multiarch,
[multiarch=], [unset multiarch])
AS_IF([test ${multiarch+set}], [
AC_DEFINE(ENABLE_MULTIARCH)
+ MJIT_HEADER_INSTALL_DIR=include/'${arch}/${RUBY_VERSION_NAME}'
+], [
+ MJIT_HEADER_INSTALL_DIR=include/'${RUBY_VERSION_NAME}/${arch}'
])
archlibdir='${libdir}/${arch}'
@@ -3553,7 +3442,7 @@ AC_ARG_WITH(soname,
],
[mingw*], [
RUBY_SO_NAME="${rb_cv_msvcrt}"'-$(RUBY_BASE_NAME)$(MAJOR)$(MINOR)0'
- AS_IF([test x"${target_cpu}" != xi386 || test x"${rb_cv_msvcrt}" != xmsvcrt], [
+ AS_IF([test x"${target_cpu}" != xi386], [
RUBY_SO_NAME="${target_cpu}-${RUBY_SO_NAME}"
])
],
@@ -3618,7 +3507,7 @@ AS_CASE("$enable_shared", [yes], [
RUBY_APPEND_OPTIONS(LIBRUBY_DLDFLAGS, ['-Wl,-soname,$(LIBRUBY_SONAME)' "$LDFLAGS_OPTDIR"])
LIBRUBY_ALIASES='$(LIBRUBY_SONAME) lib$(RUBY_SO_NAME).$(SOEXT)'
AS_IF([test "$load_relative" = yes], [
- libprefix="'\$\${ORIGIN}/../${multiarch+../../}${libdir_basename}'"
+ libprefix="'\$\${ORIGIN}/../${libdir_basename}'"
LIBRUBY_RPATHFLAGS="-Wl,-rpath,${libprefix}"
LIBRUBY_RELATIVE=yes
])
@@ -3630,7 +3519,7 @@ AS_CASE("$enable_shared", [yes], [
LIBRUBY_SO="$LIBRUBY_SO.\$(TEENY)"
LIBRUBY_ALIASES=''
], [test "$load_relative" = yes], [
- libprefix="'\$\$ORIGIN/../${multiarch+../../}${libdir_basename}'"
+ libprefix="'\$\$ORIGIN/../${libdir_basename}'"
LIBRUBY_RPATHFLAGS="-Wl,-rpath,${libprefix}"
LIBRUBY_RELATIVE=yes
])
@@ -3654,7 +3543,7 @@ AS_CASE("$enable_shared", [yes], [
LIBRUBY_ALIASES='$(LIBRUBY_SONAME) lib$(RUBY_SO_NAME).$(SOEXT)'
RUBY_APPEND_OPTIONS(LIBRUBY_DLDFLAGS, ["${linker_flag}-h${linker_flag:+,}"'$(@F)'])
AS_IF([test "$load_relative" = yes], [
- libprefix="'\$\$ORIGIN/../${multiarch+../../}${libdir_basename}'"
+ libprefix="'\$\$ORIGIN/../${libdir_basename}'"
LIBRUBY_RPATHFLAGS="-R${libprefix}"
LIBRUBY_RELATIVE=yes
], [
@@ -3671,7 +3560,7 @@ AS_CASE("$enable_shared", [yes], [
LIBRUBY_SONAME='$(LIBRUBY_SO)'
LIBRUBY_ALIASES='lib$(RUBY_INSTALL_NAME).$(SOEXT)'
AS_IF([test "$load_relative" = yes], [
- libprefix="@executable_path/../${multiarch+../../}${libdir_basename}"
+ libprefix="@executable_path/../${libdir_basename}"
LIBRUBY_RELATIVE=yes
])
LIBRUBY_DLDFLAGS="$LIBRUBY_DLDFLAGS -install_name ${libprefix}"'/$(LIBRUBY_SONAME)'
@@ -3719,16 +3608,16 @@ AS_CASE("$enable_shared", [yes], [
])
])
AS_IF([test "$enable_rpath" = yes], [
- AS_CASE(["${cross_compiling}${load_relative}"],
- [*yes*], [rpathflag="${RPATHFLAG}"],
- [rpathflag="$RPATHFLAG${LIBPATHFLAG:+${RPATHFLAG:+ }$LIBPATHFLAG}"])
+ test -z "$LIBRUBY_RPATHFLAGS" || LIBRUBY_RPATHFLAGS="$LIBRUBY_RPATHFLAGS "
+ rpathflag="${RPATHFLAG}"
+ AS_CASE(["${cross_compiling}${load_relative}"], [*yes*], [], [rpathflag="$RPATHFLAG$LIBPATHFLAG"])
rpathflag=`IFS="$PATH_SEPARATOR"
echo x "$rpathflag" |
sed "s/^x *//;s${IFS}"'%1\\$-s'"${IFS}${libprefix}${IFS}g;s${IFS}%s${IFS}${libprefix}${IFS}g"
`
- LIBRUBY_RPATHFLAGS="${LIBRUBY_RPATHFLAGS:+$LIBRUBY_RPATHFLAGS }${rpathflag}"
- LIBRUBYARG_SHARED="${LIBRUBY_RPATHFLAGS:+$LIBRUBY_RPATHFLAGS }$LIBRUBYARG_SHARED"
- LIBRUBYARG_STATIC="${LIBRUBY_RPATHFLAGS:+$LIBRUBY_RPATHFLAGS }$LIBRUBYARG_STATIC"
+ LIBRUBY_RPATHFLAGS="$LIBRUBY_RPATHFLAGS${rpathflag}"
+ LIBRUBYARG_SHARED="$LIBRUBY_RPATHFLAGS $LIBRUBYARG_SHARED"
+ LIBRUBYARG_STATIC="$LIBRUBY_RPATHFLAGS $LIBRUBYARG_STATIC"
])
AC_SUBST(LIBRUBY_RELATIVE)
@@ -3805,15 +3694,14 @@ AC_ARG_ENABLE(gcov,
AS_HELP_STRING([--enable-gcov], [enable coverage measurement by gcov]),
[gcov=yes])
AS_IF([test x"$gcov" = xyes], [
- CFLAGS="$CFLAGS -coverage -fprofile-update=atomic"
+ CFLAGS="$CFLAGS -coverage"
LDFLAGS="$LDFLAGS -coverage"
])
RUBY_SETJMP_TYPE
-RUBY_SHARED_GC
}
-[begin]_group "installation section" && {
+: "build section" && {
dnl build rdoc index if requested
RDOCTARGET=""
CAPITARGET=""
@@ -3861,19 +3749,20 @@ AC_SUBST(CAPITARGET)
AS_CASE(["$RDOCTARGET:$CAPITARGET"],[nodoc:nodoc],[INSTALLDOC=nodoc],[INSTALLDOC=all])
AC_SUBST(INSTALLDOC)
-AC_ARG_ENABLE(install-static-library,
- AS_HELP_STRING([--disable-install-static-library], [do not install static ruby library]),
- [INSTALL_STATIC_LIBRARY=$enableval
- AS_IF([test x"$enable_shared" = xno -a x"$INSTALL_STATIC_LIBRARY" = xno],
- [AC_MSG_ERROR([must install either static or shared library])],
- [])],
- AS_IF([test x"$enable_shared" = xyes],
- [INSTALL_STATIC_LIBRARY=no],
- [INSTALL_STATIC_LIBRARY=yes]))
-AC_SUBST(INSTALL_STATIC_LIBRARY)
-}
+AC_ARG_ENABLE(jit-support,
+ AS_HELP_STRING([--disable-jit-support], [disable JIT features]),
+ [MJIT_SUPPORT=$enableval],
+ [AS_CASE(["$target_os"],
+ [wasi | mingw* | solaris*], [MJIT_SUPPORT=no],
+ [MJIT_SUPPORT=yes]
+ )])
+
+AS_IF([test x"$MJIT_SUPPORT" = "xyes"],
+ [AC_DEFINE(USE_MJIT, 1)],
+ [AC_DEFINE(USE_MJIT, 0)])
+
+AC_SUBST(MJIT_SUPPORT)
-[begin]_group "JIT section" && {
AC_CHECK_PROG(RUSTC, [rustc], [rustc], [no]) dnl no ac_tool_prefix
dnl check if rustc is recent enough to build YJIT (rustc >= 1.58.0)
@@ -3919,8 +3808,8 @@ AC_ARG_ENABLE(yjit,
AS_HELP_STRING([--enable-yjit],
[enable in-process JIT compiler that requires Rust build tools. enabled by default on supported platforms if rustc 1.58.0+ is available]),
[YJIT_SUPPORT=$enableval],
- [AS_CASE(["$YJIT_TARGET_OK:$YJIT_RUSTC_OK"],
- [yes:yes], [
+ [AS_CASE(["$enable_jit_support:$YJIT_TARGET_OK:$YJIT_RUSTC_OK"],
+ [yes:yes:yes|:yes:yes], [
YJIT_SUPPORT=yes
],
[YJIT_SUPPORT=no]
@@ -3932,6 +3821,9 @@ CARGO_BUILD_ARGS=
YJIT_LIBS=
AS_CASE(["${YJIT_SUPPORT}"],
[yes|dev|stats|dev_nodebug], [
+ AS_IF([test x"$enable_jit_support" = "xno"],
+ AC_MSG_ERROR([--disable-jit-support but --enable-yjit. YJIT requires JIT support])
+ )
AS_IF([test x"$RUSTC" = "xno"],
AC_MSG_ERROR([rustc is required. Installation instructions available at https://www.rust-lang.org/tools/install])
)
@@ -3942,17 +3834,16 @@ AS_CASE(["${YJIT_SUPPORT}"],
],
[dev], [
rb_rust_target_subdir=debug
- CARGO_BUILD_ARGS='--features disasm,runtime_checks'
+ CARGO_BUILD_ARGS='--features stats,disasm'
AC_DEFINE(RUBY_DEBUG, 1)
],
[dev_nodebug], [
rb_rust_target_subdir=dev_nodebug
- CARGO_BUILD_ARGS='--profile dev_nodebug --features disasm'
- AC_DEFINE(YJIT_STATS, 1)
+ CARGO_BUILD_ARGS='--profile dev_nodebug --features stats,disasm'
],
[stats], [
rb_rust_target_subdir=stats
- CARGO_BUILD_ARGS='--profile stats'
+ CARGO_BUILD_ARGS='--profile stats --features stats'
AC_DEFINE(YJIT_STATS, 1)
])
@@ -3972,9 +3863,7 @@ AS_CASE(["${YJIT_SUPPORT}"],
AC_DEFINE_UNQUOTED(YJIT_SUPPORT, [$YJIT_SUPPORT])
])
AC_DEFINE(USE_YJIT, 1)
-], [
- AC_DEFINE(USE_YJIT, 0)
-])
+], [AC_DEFINE(USE_YJIT, 0)])
dnl These variables end up in ::RbConfig::CONFIG
AC_SUBST(YJIT_SUPPORT)dnl what flavor of YJIT the Ruby build includes
@@ -3984,53 +3873,17 @@ AC_SUBST(CARGO_BUILD_ARGS)dnl for selecting Rust build profiles
AC_SUBST(YJIT_LIBS)dnl for optionally building the Rust parts of YJIT
AC_SUBST(YJIT_OBJ)dnl for optionally building the C parts of YJIT
-dnl RJIT supports only x86_64 platforms, but allows arm64/aarch64 for custom JITs.
-RJIT_TARGET_OK=no
-AS_IF([test "$cross_compiling" = no],
- AS_CASE(["$target_cpu-$target_os"],
- [*android*], [
- RJIT_TARGET_OK=no
- ],
- [arm64-darwin*|aarch64-darwin*|x86_64-darwin*], [
- RJIT_TARGET_OK=yes
- ],
- [arm64-*linux*|aarch64-*linux*|x86_64-*linux*], [
- RJIT_TARGET_OK=yes
- ],
- [arm64-*bsd*|aarch64-*bsd*|x86_64-*bsd*], [
- RJIT_TARGET_OK=yes
- ]
- )
-)
-
-dnl Build RJIT on supported platforms or if --enable-rjit is specified.
-AC_ARG_ENABLE(rjit,
- AS_HELP_STRING([--enable-rjit],
- [enable pure-Ruby JIT compiler. enabled by default on Unix x86_64 platforms]),
- [RJIT_SUPPORT=$enableval],
- [AS_CASE(["$RJIT_TARGET_OK"],
- [yes], [RJIT_SUPPORT=yes],
- [RJIT_SUPPORT=no]
- )]
-)
-
-AS_CASE(["$RJIT_SUPPORT"],
-[yes|dev], [
- AS_CASE(["$RJIT_SUPPORT"],
- [dev], [
- # Link libcapstone for --rjit-dump-disasm
- AC_CHECK_LIB([capstone], [cs_disasm])
- ])
-
- AC_DEFINE(USE_RJIT, 1)
-], [
- AC_DEFINE(USE_RJIT, 0)
-])
-
-AC_SUBST(RJIT_SUPPORT)
-}
+AC_ARG_ENABLE(install-static-library,
+ AS_HELP_STRING([--disable-install-static-library], [do not install static ruby library]),
+ [INSTALL_STATIC_LIBRARY=$enableval
+ AS_IF([test x"$enable_shared" = xno -a x"$INSTALL_STATIC_LIBRARY" = xno],
+ [AC_MSG_ERROR([must install either static or shared library])],
+ [])],
+ AS_IF([test x"$enable_shared" = xyes],
+ [INSTALL_STATIC_LIBRARY=no],
+ [INSTALL_STATIC_LIBRARY=yes]))
+AC_SUBST(INSTALL_STATIC_LIBRARY)
-[begin]_group "build section" && {
AC_CACHE_CHECK([for prefix of external symbols], rb_cv_symbol_prefix, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[extern void conftest_external(void) {}]], [[]])],[
rb_cv_symbol_prefix=`$NM conftest.$ac_objext |
@@ -4041,25 +3894,6 @@ AC_CACHE_CHECK([for prefix of external symbols], rb_cv_symbol_prefix, [
])
SYMBOL_PREFIX="$rb_cv_symbol_prefix"
test "x$SYMBOL_PREFIX" = xNONE && SYMBOL_PREFIX=''
-
-AS_IF([test x"$SOEXT" = xdll], [
- # DLL on Windows is managed by win32/mkexports.rb
-], [test x"$enable_shared" = xyes], [
- AC_CACHE_CHECK([for default symbols in empty shared library], rb_cv_symbols_in_emptylib, [
- save_CC="$CC"
- eval CC=\"`printf "%s" "${DLDSHARED}" | sed ['s/\$(CC)/${CC}/']`\"
- AC_LINK_IFELSE([AC_LANG_PROGRAM()],[
- rb_cv_symbols_in_emptylib=`$NM -Pgp conftest$ac_exeext |
- sed ["/ [A-TV-Z] .*/!d;s///;s/^${SYMBOL_PREFIX}//;/^main$/d"]`
- ])
- set dummy ${rb_cv_symbols_in_emptylib}
- shift
- rb_cv_symbols_in_emptylib="$*"
- CC="$save_CC"
- ])
-])
-AC_SUBST(XSYMBOLS_IN_EMPTYLIB, "${rb_cv_symbols_in_emptylib}")
-
DLNOBJ=dln.o
AC_ARG_ENABLE(dln,
AS_HELP_STRING([--disable-dln], [disable dynamic link feature]),
@@ -4127,7 +3961,6 @@ enum {
[mingw*], [
AS_IF([test x"$enable_shared" = xyes], [
LIBRUBY_SO='$(RUBY_SO_NAME)'.dll
- LIBRUBY_SONAME=''
LIBRUBY_DLDFLAGS="${LIBRUBY_DLDFLAGS}"' $(RUBYDEF)'
])
EXPORT_PREFIX=' '
@@ -4238,9 +4071,8 @@ AS_IF([test "${universal_binary-no}" = yes ], [
const char arch[[]] = __ARCHITECTURE__;]], [[puts(arch);]])],
[rb_cv_architecture_available=yes], [rb_cv_architecture_available=no]))
])
-}
-[end]_group
+: ${MJIT_LDSHARED=`echo "$LDSHARED" | sed ['s|\$(LD)|'"${LD}"'|g;s|\$(CC)|$(MJIT_CC)|g']`}
MAINLIBS="$LIBS"
LIBS=$ORIG_LIBS
@@ -4268,13 +4100,12 @@ AS_IF([test "${ARCH_FLAG}"], [
rb_cv_warnflags=`echo "$rb_cv_warnflags" | sed 's/^ *//;s/ *$//'`
warnflags="$rb_cv_warnflags"
AC_SUBST(cppflags)dnl
-AC_SUBST(cflags, ['${hardenflags} '"${orig_cflags:+$orig_cflags }"' ${optflags} ${debugflags} ${warnflags}'])dnl
+AC_SUBST(cflags, ["${orig_cflags:+$orig_cflags }"'${optflags} ${debugflags} ${warnflags}'])dnl
AC_SUBST(cxxflags)dnl
AC_SUBST(optflags)dnl
AC_SUBST(debugflags)dnl
AC_SUBST(warnflags)dnl
AC_SUBST(strict_warnflags)dnl
-AC_SUBST(hardenflags)dnl
AC_SUBST(XCFLAGS)dnl
AC_SUBST(XLDFLAGS)dnl
AC_SUBST(EXTLDFLAGS)dnl
@@ -4307,7 +4138,6 @@ AC_SUBST(MINIOBJS)
AC_SUBST(THREAD_MODEL)
AC_SUBST(COROUTINE_TYPE, ${coroutine_type})
AC_SUBST(PLATFORM_DIR)
-AC_SUBST(USE_LLVM_WINDRES)
firstmf=`echo $FIRSTMAKEFILE | sed 's/:.*//'`
firsttmpl=`echo $FIRSTMAKEFILE | sed 's/.*://'`
@@ -4459,10 +4289,6 @@ AS_IF([test "${universal_binary-no}" = yes ], [
arch="${target_cpu}-${target_os}"
])
AC_DEFINE_UNQUOTED(RUBY_PLATFORM, "$arch")
-
- AS_IF([test "$arch" = "s390x-linux"], [
- AC_DEFINE_UNQUOTED(USE_MN_THREADS, 0)
- ])
])
unset sitearch
@@ -4567,7 +4393,7 @@ guard=INCLUDE_RUBY_CONFIG_H
{
echo "#ifndef $guard"
echo "#define $guard 1"
- sed "/^@%:@define PACKAGE_/d;s/ *$//" confdefs.h
+ grep -v "^#define PACKAGE_" confdefs.h
echo "#endif /* $guard */"
} | tr -d '\015' |
(
@@ -4655,9 +4481,6 @@ AC_CONFIG_FILES(Makefile:template/Makefile.in, [
], [
echo 'distclean-local::; @$(RM) GNUmakefile uncommon.mk'
])
-
- echo; echo '$(srcdir)/$(CONFIGURE):RUBY_M4_INCLUDED \
- $(empty)'
} > $tmpmk && AS_IF([! grep '^ruby:' $tmpmk > /dev/null], [
AS_IF([test "${gnumake}" = yes], [
tmpgmk=confgmk$$.tmp
@@ -4688,6 +4511,7 @@ AC_SUBST(DESTDIR)
AC_OUTPUT
}
+}
AS_IF([test "$silent" = yes], [], [
AS_IF([${FOLD+:} false], [], [
@@ -4724,7 +4548,6 @@ config_summary "target OS" "$target_os"
config_summary "compiler" "$CC"
config_summary "with thread" "$THREAD_MODEL"
config_summary "with coroutine" "$coroutine_type"
-config_summary "with shared GC" "$shared_gc_summary"
config_summary "enable shared libs" "$ENABLE_SHARED"
config_summary "dynamic library ext" "$DLEXT"
config_summary "CFLAGS" "$cflags"
@@ -4734,11 +4557,10 @@ config_summary "DLDFLAGS" "$DLDFLAGS"
config_summary "optflags" "$optflags"
config_summary "debugflags" "$debugflags"
config_summary "warnflags" "$warnflags"
-config_summary "hardenflags" "$hardenflags"
config_summary "strip command" "$STRIP"
config_summary "install doc" "$DOCTARGETS"
+config_summary "MJIT support" "$MJIT_SUPPORT"
config_summary "YJIT support" "$YJIT_SUPPORT"
-config_summary "RJIT support" "$RJIT_SUPPORT"
config_summary "man page type" "$MANTYPE"
config_summary "search path" "$search_path"
config_summary "static-linked-ext" ${EXTSTATIC:+"yes"}
diff --git a/constant.h b/constant.h
index 90a68d447a..e0d36909e1 100644
--- a/constant.h
+++ b/constant.h
@@ -43,11 +43,13 @@ VALUE rb_mod_deprecate_constant(int argc, const VALUE *argv, VALUE obj);
void rb_free_const_table(struct rb_id_table *tbl);
VALUE rb_const_source_location(VALUE, ID);
+MJIT_SYMBOL_EXPORT_BEGIN
int rb_autoloading_value(VALUE mod, ID id, VALUE *value, rb_const_flag_t *flag);
rb_const_entry_t *rb_const_lookup(VALUE klass, ID id);
VALUE rb_public_const_get_at(VALUE klass, ID id);
VALUE rb_public_const_get_from(VALUE klass, ID id);
int rb_public_const_defined_from(VALUE klass, ID id);
VALUE rb_const_source_location_at(VALUE, ID);
+MJIT_SYMBOL_EXPORT_END
#endif /* CONSTANT_H */
diff --git a/cont.c b/cont.c
index e08bff49d9..5375d1945b 100644
--- a/cont.c
+++ b/cont.c
@@ -26,16 +26,15 @@ extern int madvise(caddr_t, size_t, int);
#include COROUTINE_H
#include "eval_intern.h"
+#include "gc.h"
#include "internal.h"
#include "internal/cont.h"
-#include "internal/thread.h"
#include "internal/error.h"
-#include "internal/gc.h"
#include "internal/proc.h"
#include "internal/sanitizers.h"
#include "internal/warnings.h"
#include "ruby/fiber/scheduler.h"
-#include "rjit.h"
+#include "mjit.h"
#include "yjit.h"
#include "vm_core.h"
#include "vm_sync.h"
@@ -71,6 +70,8 @@ static VALUE rb_cFiberPool;
#define FIBER_POOL_ALLOCATION_FREE
#endif
+#define jit_cont_enabled (mjit_enabled || rb_yjit_enabled_p())
+
enum context_type {
CONTINUATION_CONTEXT = 0,
FIBER_CONTEXT = 1
@@ -177,7 +178,7 @@ struct fiber_pool {
// A singly-linked list of allocations which contain 1 or more stacks each.
struct fiber_pool_allocation * allocations;
- // Free list that provides O(1) stack "allocation".
+ // Provides O(1) stack "allocation":
struct fiber_pool_vacancy * vacancies;
// The size of the stack allocations (excluding any guard page).
@@ -189,15 +190,13 @@ struct fiber_pool {
// The initial number of stacks to allocate.
size_t initial_count;
- // Whether to madvise(free) the stack or not.
- // If this value is set to 1, the stack will be madvise(free)ed
- // (or equivalent), where possible, when it is returned to the pool.
+ // Whether to madvise(free) the stack or not:
int free_stacks;
// The number of stacks that have been used in this pool.
size_t used;
- // The amount to allocate for the vm_stack.
+ // The amount to allocate for the vm_stack:
size_t vm_stack_size;
};
@@ -226,21 +225,22 @@ typedef struct rb_context_struct {
} machine;
rb_execution_context_t saved_ec;
rb_jmpbuf_t jmpbuf;
+ rb_ensure_entry_t *ensure_array;
struct rb_jit_cont *jit_cont; // Continuation contexts for JITs
} rb_context_t;
+
/*
* Fiber status:
- * [Fiber.new] ------> FIBER_CREATED ----> [Fiber#kill] --> |
- * | [Fiber#resume] |
- * v |
- * +--> FIBER_RESUMED ----> [return] ------> |
- * [Fiber#resume] | | [Fiber.yield/transfer] |
- * [Fiber#transfer] | v |
- * +--- FIBER_SUSPENDED --> [Fiber#kill] --> |
- * |
- * |
- * FIBER_TERMINATED <-------------------+
+ * [Fiber.new] ------> FIBER_CREATED
+ * | [Fiber#resume]
+ * v
+ * +--> FIBER_RESUMED ----+
+ * [Fiber#resume] | | [Fiber.yield] |
+ * | v |
+ * +-- FIBER_SUSPENDED | [Terminate]
+ * |
+ * FIBER_TERMINATED <-+
*/
enum fiber_status {
FIBER_CREATED,
@@ -266,20 +266,12 @@ struct rb_fiber_struct {
unsigned int yielding : 1;
unsigned int blocking : 1;
- unsigned int killed : 1;
-
struct coroutine_context context;
struct fiber_pool_stack stack;
};
static struct fiber_pool shared_fiber_pool = {NULL, NULL, 0, 0, 0, 0};
-void
-rb_free_shared_fiber_pool(void)
-{
- xfree(shared_fiber_pool.allocations);
-}
-
static ID fiber_initialize_keywords[3] = {0};
/*
@@ -700,9 +692,7 @@ fiber_pool_stack_free(struct fiber_pool_stack * stack)
// If this is not true, the vacancy information will almost certainly be destroyed:
VM_ASSERT(size <= (stack->size - RB_PAGE_SIZE));
- int advice = stack->pool->free_stacks >> 1;
-
- if (DEBUG) fprintf(stderr, "fiber_pool_stack_free: %p+%"PRIuSIZE" [base=%p, size=%"PRIuSIZE"] advice=%d\n", base, size, stack->base, stack->size, advice);
+ if (DEBUG) fprintf(stderr, "fiber_pool_stack_free: %p+%"PRIuSIZE" [base=%p, size=%"PRIuSIZE"]\n", base, size, stack->base, stack->size);
// The pages being used by the stack can be returned back to the system.
// That doesn't change the page mapping, but it does allow the system to
@@ -716,29 +706,24 @@ fiber_pool_stack_free(struct fiber_pool_stack * stack)
#ifdef __wasi__
// WebAssembly doesn't support madvise, so we just don't do anything.
#elif VM_CHECK_MODE > 0 && defined(MADV_DONTNEED)
- if (!advice) advice = MADV_DONTNEED;
// This immediately discards the pages and the memory is reset to zero.
- madvise(base, size, advice);
+ madvise(base, size, MADV_DONTNEED);
#elif defined(MADV_FREE_REUSABLE)
- if (!advice) advice = MADV_FREE_REUSABLE;
// Darwin / macOS / iOS.
// Acknowledge the kernel down to the task info api we make this
// page reusable for future use.
- // As for MADV_FREE_REUSABLE below we ensure in the rare occasions the task was not
+ // As for MADV_FREE_REUSE below we ensure in the rare occasions the task was not
// completed at the time of the call to re-iterate.
- while (madvise(base, size, advice) == -1 && errno == EAGAIN);
+ while (madvise(base, size, MADV_FREE_REUSABLE) == -1 && errno == EAGAIN);
#elif defined(MADV_FREE)
- if (!advice) advice = MADV_FREE;
// Recent Linux.
- madvise(base, size, advice);
+ madvise(base, size, MADV_FREE);
#elif defined(MADV_DONTNEED)
- if (!advice) advice = MADV_DONTNEED;
// Old Linux.
- madvise(base, size, advice);
+ madvise(base, size, MADV_DONTNEED);
#elif defined(POSIX_MADV_DONTNEED)
- if (!advice) advice = POSIX_MADV_DONTNEED;
// Solaris?
- posix_madvise(base, size, advice);
+ posix_madvise(base, size, POSIX_MADV_DONTNEED);
#elif defined(_WIN32)
VirtualAlloc(base, size, MEM_RESET, PAGE_READWRITE);
// Not available in all versions of Windows.
@@ -795,9 +780,6 @@ static inline void
ec_switch(rb_thread_t *th, rb_fiber_t *fiber)
{
rb_execution_context_t *ec = &fiber->cont.saved_ec;
-#ifdef RUBY_ASAN_ENABLED
- ec->machine.asan_fake_stack_handle = asan_get_thread_fake_stack_handle();
-#endif
rb_ractor_set_current_ec(th->ractor, th->ec = ec);
// ruby_current_execution_context_ptr = th->ec = ec;
@@ -1025,8 +1007,13 @@ cont_mark(void *ptr)
cont->machine.stack + cont->machine.stack_size);
}
else {
- /* fiber machine context is marked as part of rb_execution_context_mark, no need to
- * do anything here. */
+ /* fiber */
+ const rb_fiber_t *fiber = (rb_fiber_t*)cont;
+
+ if (!FIBER_TERMINATED_P(fiber)) {
+ rb_gc_mark_locations(cont->machine.stack,
+ cont->machine.stack + cont->machine.stack_size);
+ }
}
}
@@ -1052,6 +1039,7 @@ cont_free(void *ptr)
if (cont->type == CONTINUATION_CONTEXT) {
ruby_xfree(cont->saved_ec.vm_stack);
+ ruby_xfree(cont->ensure_array);
RUBY_FREE_UNLESS_NULL(cont->machine.stack);
}
else {
@@ -1062,8 +1050,10 @@ cont_free(void *ptr)
RUBY_FREE_UNLESS_NULL(cont->saved_vm_stack.ptr);
- VM_ASSERT(cont->jit_cont != NULL);
- jit_cont_free(cont->jit_cont);
+ if (jit_cont_enabled) {
+ VM_ASSERT(cont->jit_cont != NULL);
+ jit_cont_free(cont->jit_cont);
+ }
/* free rb_cont_t or rb_fiber_t */
ruby_xfree(ptr);
RUBY_FREE_LEAVE("cont");
@@ -1292,42 +1282,26 @@ rb_jit_cont_each_iseq(rb_iseq_callback callback, void *data)
if (cont->ec->vm_stack == NULL)
continue;
- const rb_control_frame_t *cfp = cont->ec->cfp;
- while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(cont->ec, cfp)) {
- if (cfp->pc && cfp->iseq && imemo_type((VALUE)cfp->iseq) == imemo_iseq) {
- callback(cfp->iseq, data);
+ const rb_control_frame_t *cfp;
+ for (cfp = RUBY_VM_END_CONTROL_FRAME(cont->ec) - 1; ; cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
+ const rb_iseq_t *iseq;
+ if (cfp->pc && (iseq = cfp->iseq) != NULL && imemo_type((VALUE)iseq) == imemo_iseq) {
+ callback(iseq, data);
}
- cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
- }
- }
-}
-
-#if USE_YJIT
-// Update the jit_return of all CFPs to leave_exit unless it's leave_exception or not set.
-// This prevents jit_exec_exception from jumping to the caller after invalidation.
-void
-rb_yjit_cancel_jit_return(void *leave_exit, void *leave_exception)
-{
- struct rb_jit_cont *cont;
- for (cont = first_jit_cont; cont != NULL; cont = cont->next) {
- if (cont->ec->vm_stack == NULL)
- continue;
- const rb_control_frame_t *cfp = cont->ec->cfp;
- while (!RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(cont->ec, cfp)) {
- if (cfp->jit_return && cfp->jit_return != leave_exception) {
- ((rb_control_frame_t *)cfp)->jit_return = leave_exit;
- }
- cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+ if (cfp == cont->ec->cfp)
+ break; // reached the most recent cfp
}
}
}
-#endif
// Finish working with jit_cont.
void
rb_jit_cont_finish(void)
{
+ if (!jit_cont_enabled)
+ return;
+
struct rb_jit_cont *cont, *next;
for (cont = first_jit_cont; cont != NULL; cont = next) {
next = cont->next;
@@ -1340,8 +1314,9 @@ static void
cont_init_jit_cont(rb_context_t *cont)
{
VM_ASSERT(cont->jit_cont == NULL);
- // We always allocate this since YJIT may be enabled later
- cont->jit_cont = jit_cont_new(&(cont->saved_ec));
+ if (jit_cont_enabled) {
+ cont->jit_cont = jit_cont_new(&(cont->saved_ec));
+ }
}
struct rb_execution_context_struct *
@@ -1388,11 +1363,15 @@ rb_fiberptr_blocking(struct rb_fiber_struct *fiber)
return fiber->blocking;
}
-// Initialize the jit_cont_lock
+// Start working with jit_cont.
void
rb_jit_cont_init(void)
{
+ if (!jit_cont_enabled)
+ return;
+
rb_native_mutex_initialize(&jit_cont_lock);
+ cont_init_jit_cont(&GET_EC()->fiber_ptr->cont);
}
#if 0
@@ -1456,6 +1435,22 @@ cont_capture(volatile int *volatile stat)
VM_ASSERT(cont->saved_ec.cfp != NULL);
cont_save_machine_stack(th, cont);
+ /* backup ensure_list to array for search in another context */
+ {
+ rb_ensure_list_t *p;
+ int size = 0;
+ rb_ensure_entry_t *entry;
+ for (p=th->ec->ensure_list; p; p=p->next)
+ size++;
+ entry = cont->ensure_array = ALLOC_N(rb_ensure_entry_t,size+1);
+ for (p=th->ec->ensure_list; p; p=p->next) {
+ if (!p->entry.marker)
+ p->entry.marker = rb_ary_hidden_new(0); /* dummy object */
+ *entry++ = p->entry;
+ }
+ entry->marker = 0;
+ }
+
if (ruby_setjmp(cont->jmpbuf)) {
VALUE value;
@@ -1516,6 +1511,7 @@ cont_restore_thread(rb_context_t *cont)
th->ec->tag = sec->tag;
th->ec->root_lep = sec->root_lep;
th->ec->root_svar = sec->root_svar;
+ th->ec->ensure_list = sec->ensure_list;
th->ec->errinfo = sec->errinfo;
VM_ASSERT(th->ec->vm_stack != NULL);
@@ -1547,10 +1543,11 @@ fiber_setcontext(rb_fiber_t *new_fiber, rb_fiber_t *old_fiber)
}
}
- /* these values are used in rb_gc_mark_machine_context to mark the fiber's stack. */
+ /* exchange machine_stack_start between old_fiber and new_fiber */
old_fiber->cont.saved_ec.machine.stack_start = th->ec->machine.stack_start;
- old_fiber->cont.saved_ec.machine.stack_end = FIBER_TERMINATED_P(old_fiber) ? NULL : th->ec->machine.stack_end;
+ /* old_fiber->machine.stack_end should be NULL */
+ old_fiber->cont.saved_ec.machine.stack_end = NULL;
// if (DEBUG) fprintf(stderr, "fiber_setcontext: %p[%p] -> %p[%p]\n", (void*)old_fiber, old_fiber->stack.base, (void*)new_fiber, new_fiber->stack.base);
@@ -1753,13 +1750,6 @@ rb_callcc(VALUE self)
return rb_yield(val);
}
}
-#ifdef RUBY_ASAN_ENABLED
-/* callcc can't possibly work with ASAN; see bug #20273. Also this function
- * definition below avoids a "defined and not used" warning. */
-MAYBE_UNUSED(static void notusing_callcc(void)) { rb_callcc(Qnil); }
-# define rb_callcc rb_f_notimplement
-#endif
-
static VALUE
make_passing_arg(int argc, const VALUE *argv)
@@ -1778,6 +1768,80 @@ make_passing_arg(int argc, const VALUE *argv)
typedef VALUE e_proc(VALUE);
+/* CAUTION!! : Currently, error in rollback_func is not supported */
+/* same as rb_protect if set rollback_func to NULL */
+void
+ruby_register_rollback_func_for_ensure(e_proc *ensure_func, e_proc *rollback_func)
+{
+ st_table **table_p = &GET_VM()->ensure_rollback_table;
+ if (UNLIKELY(*table_p == NULL)) {
+ *table_p = st_init_numtable();
+ }
+ st_insert(*table_p, (st_data_t)ensure_func, (st_data_t)rollback_func);
+}
+
+static inline e_proc *
+lookup_rollback_func(e_proc *ensure_func)
+{
+ st_table *table = GET_VM()->ensure_rollback_table;
+ st_data_t val;
+ if (table && st_lookup(table, (st_data_t)ensure_func, &val))
+ return (e_proc *) val;
+ return (e_proc *) Qundef;
+}
+
+
+static inline void
+rollback_ensure_stack(VALUE self,rb_ensure_list_t *current,rb_ensure_entry_t *target)
+{
+ rb_ensure_list_t *p;
+ rb_ensure_entry_t *entry;
+ size_t i, j;
+ size_t cur_size;
+ size_t target_size;
+ size_t base_point;
+ e_proc *func;
+
+ cur_size = 0;
+ for (p=current; p; p=p->next)
+ cur_size++;
+ target_size = 0;
+ for (entry=target; entry->marker; entry++)
+ target_size++;
+
+ /* search common stack point */
+ p = current;
+ base_point = cur_size;
+ while (base_point) {
+ if (target_size >= base_point &&
+ p->entry.marker == target[target_size - base_point].marker)
+ break;
+ base_point --;
+ p = p->next;
+ }
+
+ /* rollback function check */
+ for (i=0; i < target_size - base_point; i++) {
+ if (!lookup_rollback_func(target[i].e_proc)) {
+ rb_raise(rb_eRuntimeError, "continuation called from out of critical rb_ensure scope");
+ }
+ }
+ /* pop ensure stack */
+ while (cur_size > base_point) {
+ /* escape from ensure block */
+ (*current->entry.e_proc)(current->entry.data2);
+ current = current->next;
+ cur_size--;
+ }
+ /* push ensure stack */
+ for (j = 0; j < i; j++) {
+ func = lookup_rollback_func(target[i - j - 1].e_proc);
+ if (!UNDEF_P((VALUE)func)) {
+ (*func)(target[i - j - 1].data2);
+ }
+ }
+}
+
NORETURN(static VALUE rb_cont_call(int argc, VALUE *argv, VALUE contval));
/*
@@ -1809,6 +1873,7 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval)
rb_raise(rb_eRuntimeError, "continuation called across fiber");
}
}
+ rollback_ensure_stack(contval, th->ec->ensure_list, cont->ensure_array);
cont->argc = argc;
cont->value = make_passing_arg(argc, argv);
@@ -1931,7 +1996,6 @@ fiber_t_alloc(VALUE fiber_value, unsigned int blocking)
fiber->cont.self = fiber_value;
fiber->cont.type = FIBER_CONTEXT;
fiber->blocking = blocking;
- fiber->killed = 0;
cont_init(&fiber->cont, th);
fiber->cont.saved_ec.fiber_ptr = fiber;
@@ -1997,10 +2061,10 @@ fiber_storage_set(struct rb_fiber_struct *fiber, VALUE storage)
}
static inline VALUE
-fiber_storage_get(rb_fiber_t *fiber, int allocate)
+fiber_storage_get(rb_fiber_t *fiber)
{
VALUE storage = fiber->cont.saved_ec.storage;
- if (storage == Qnil && allocate) {
+ if (storage == Qnil) {
storage = rb_hash_new();
fiber_storage_set(fiber, storage);
}
@@ -2027,15 +2091,7 @@ static VALUE
rb_fiber_storage_get(VALUE self)
{
storage_access_must_be_from_same_fiber(self);
-
- VALUE storage = fiber_storage_get(fiber_ptr(self), FALSE);
-
- if (storage == Qnil) {
- return Qnil;
- }
- else {
- return rb_obj_dup(storage);
- }
+ return rb_obj_dup(fiber_storage_get(fiber_ptr(self)));
}
static int
@@ -2115,7 +2171,8 @@ rb_fiber_storage_aref(VALUE class, VALUE key)
{
Check_Type(key, T_SYMBOL);
- VALUE storage = fiber_storage_get(fiber_current(), FALSE);
+ VALUE storage = fiber_storage_get(fiber_current());
+
if (storage == Qnil) return Qnil;
return rb_hash_aref(storage, key);
@@ -2136,15 +2193,9 @@ rb_fiber_storage_aset(VALUE class, VALUE key, VALUE value)
{
Check_Type(key, T_SYMBOL);
- VALUE storage = fiber_storage_get(fiber_current(), value != Qnil);
- if (storage == Qnil) return Qnil;
+ VALUE storage = fiber_storage_get(fiber_current());
- if (value == Qnil) {
- return rb_hash_delete(storage, key);
- }
- else {
- return rb_hash_aset(storage, key, value);
- }
+ return rb_hash_aset(storage, key, value);
}
static VALUE
@@ -2422,6 +2473,7 @@ rb_fiber_start(rb_fiber_t *fiber)
rb_proc_t *proc;
enum ruby_tag_type state;
+ int need_interrupt = TRUE;
VM_ASSERT(th->ec == GET_EC());
VM_ASSERT(FIBER_RESUMED_P(fiber));
@@ -2447,7 +2499,6 @@ rb_fiber_start(rb_fiber_t *fiber)
}
EC_POP_TAG();
- int need_interrupt = TRUE;
VALUE err = Qfalse;
if (state) {
err = th->ec->errinfo;
@@ -2456,16 +2507,13 @@ rb_fiber_start(rb_fiber_t *fiber)
if (state == TAG_RAISE) {
// noop...
}
- else if (state == TAG_FATAL && err == RUBY_FATAL_FIBER_KILLED) {
- need_interrupt = FALSE;
- err = Qfalse;
- }
else if (state == TAG_FATAL) {
rb_threadptr_pending_interrupt_enque(th, err);
}
else {
err = rb_vm_make_jump_tag_but_local_jump(state, err);
}
+ need_interrupt = TRUE;
}
rb_fiber_terminate(fiber, need_interrupt, err);
@@ -2475,17 +2523,21 @@ rb_fiber_start(rb_fiber_t *fiber)
void
rb_threadptr_root_fiber_setup(rb_thread_t *th)
{
- rb_fiber_t *fiber = ruby_mimcalloc(1, sizeof(rb_fiber_t));
+ rb_fiber_t *fiber = ruby_mimmalloc(sizeof(rb_fiber_t));
if (!fiber) {
rb_bug("%s", strerror(errno)); /* ... is it possible to call rb_bug here? */
}
+ MEMZERO(fiber, rb_fiber_t, 1);
fiber->cont.type = FIBER_CONTEXT;
fiber->cont.saved_ec.fiber_ptr = fiber;
fiber->cont.saved_ec.thread_ptr = th;
fiber->blocking = 1;
- fiber->killed = 0;
fiber_status_set(fiber, FIBER_RESUMED); /* skip CREATED */
th->ec = &fiber->cont.saved_ec;
+ // When rb_threadptr_root_fiber_setup is called for the first time, mjit_enabled and
+ // rb_yjit_enabled_p() are still false. So this does nothing and rb_jit_cont_init() that is
+ // called later will take care of it. However, you still have to call cont_init_jit_cont()
+ // here for other Ractors, which are not initialized by rb_jit_cont_init().
cont_init_jit_cont(&fiber->cont);
}
@@ -2496,12 +2548,12 @@ rb_threadptr_root_fiber_release(rb_thread_t *th)
/* ignore. A root fiber object will free th->ec */
}
else {
- rb_execution_context_t *ec = rb_current_execution_context(false);
+ rb_execution_context_t *ec = GET_EC();
VM_ASSERT(th->ec->fiber_ptr->cont.type == FIBER_CONTEXT);
VM_ASSERT(th->ec->fiber_ptr->cont.self == 0);
- if (ec && th->ec == ec) {
+ if (th->ec == ec) {
rb_ractor_set_current_ec(th->ractor, NULL);
}
fiber_free(th->ec->fiber_ptr);
@@ -2582,19 +2634,6 @@ fiber_store(rb_fiber_t *next_fiber, rb_thread_t *th)
fiber_setcontext(next_fiber, fiber);
}
-static void
-fiber_check_killed(rb_fiber_t *fiber)
-{
- VM_ASSERT(fiber == fiber_current());
-
- if (fiber->killed) {
- rb_thread_t *thread = fiber->cont.saved_ec.thread_ptr;
-
- thread->ec->errinfo = RUBY_FATAL_FIBER_KILLED;
- EC_JUMP_TAG(thread->ec, RUBY_TAG_FATAL);
- }
-}
-
static inline VALUE
fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fiber_t *resuming_fiber, bool yielding)
{
@@ -2683,14 +2722,7 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, rb_fi
current_fiber = th->ec->fiber_ptr;
value = current_fiber->cont.value;
-
- fiber_check_killed(current_fiber);
-
- if (current_fiber->cont.argc == -1) {
- // Fiber#raise will trigger this path.
- rb_exc_raise(value);
- }
-
+ if (current_fiber->cont.argc == -1) rb_exc_raise(value);
return value;
}
@@ -2726,8 +2758,6 @@ fiber_blocking_yield(VALUE fiber_value)
rb_fiber_t *fiber = fiber_ptr(fiber_value);
rb_thread_t * volatile th = fiber->cont.saved_ec.thread_ptr;
- VM_ASSERT(fiber->blocking == 0);
-
// fiber->blocking is `unsigned int : 1`, so we use it as a boolean:
fiber->blocking = 1;
@@ -3130,13 +3160,12 @@ rb_fiber_s_yield(int argc, VALUE *argv, VALUE klass)
}
static VALUE
-fiber_raise(rb_fiber_t *fiber, VALUE exception)
+fiber_raise(rb_fiber_t *fiber, int argc, const VALUE *argv)
{
- if (fiber == fiber_current()) {
- rb_exc_raise(exception);
- }
- else if (fiber->resuming_fiber) {
- return fiber_raise(fiber->resuming_fiber, exception);
+ VALUE exception = rb_make_exception(argc, argv);
+
+ if (fiber->resuming_fiber) {
+ rb_raise(rb_eFiberError, "attempt to raise a resuming fiber");
}
else if (FIBER_SUSPENDED_P(fiber) && !fiber->yielding) {
return fiber_transfer_kw(fiber, -1, &exception, RB_NO_KEYWORDS);
@@ -3149,9 +3178,7 @@ fiber_raise(rb_fiber_t *fiber, VALUE exception)
VALUE
rb_fiber_raise(VALUE fiber, int argc, const VALUE *argv)
{
- VALUE exception = rb_make_exception(argc, argv);
-
- return fiber_raise(fiber_ptr(fiber), exception);
+ return fiber_raise(fiber_ptr(fiber), argc, argv);
}
/*
@@ -3174,10 +3201,6 @@ rb_fiber_raise(VALUE fiber, int argc, const VALUE *argv)
* the exception, and the third parameter is an array of callback information.
* Exceptions are caught by the +rescue+ clause of <code>begin...end</code>
* blocks.
- *
- * Raises +FiberError+ if called on a Fiber belonging to another +Thread+.
- *
- * See Kernel#raise for more information.
*/
static VALUE
rb_fiber_m_raise(int argc, VALUE *argv, VALUE self)
@@ -3187,46 +3210,6 @@ rb_fiber_m_raise(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * fiber.kill -> nil
- *
- * Terminates the fiber by raising an uncatchable exception.
- * It only terminates the given fiber and no other fiber, returning +nil+ to
- * another fiber if that fiber was calling #resume or #transfer.
- *
- * <tt>Fiber#kill</tt> only interrupts another fiber when it is in Fiber.yield.
- * If called on the current fiber then it raises that exception at the <tt>Fiber#kill</tt> call site.
- *
- * If the fiber has not been started, transition directly to the terminated state.
- *
- * If the fiber is already terminated, does nothing.
- *
- * Raises FiberError if called on a fiber belonging to another thread.
- */
-static VALUE
-rb_fiber_m_kill(VALUE self)
-{
- rb_fiber_t *fiber = fiber_ptr(self);
-
- if (fiber->killed) return Qfalse;
- fiber->killed = 1;
-
- if (fiber->status == FIBER_CREATED) {
- fiber->status = FIBER_TERMINATED;
- }
- else if (fiber->status != FIBER_TERMINATED) {
- if (fiber_current() == fiber) {
- fiber_check_killed(fiber);
- }
- else {
- fiber_raise(fiber_ptr(self), Qnil);
- }
- }
-
- return self;
-}
-
-/*
- * call-seq:
* Fiber.current -> fiber
*
* Returns the current fiber. If you are not running in the context of
@@ -3383,15 +3366,6 @@ Init_Cont(void)
const char *fiber_shared_fiber_pool_free_stacks = getenv("RUBY_SHARED_FIBER_POOL_FREE_STACKS");
if (fiber_shared_fiber_pool_free_stacks) {
shared_fiber_pool.free_stacks = atoi(fiber_shared_fiber_pool_free_stacks);
-
- if (shared_fiber_pool.free_stacks < 0) {
- rb_warn("Setting RUBY_SHARED_FIBER_POOL_FREE_STACKS to a negative value is not allowed.");
- shared_fiber_pool.free_stacks = 0;
- }
-
- if (shared_fiber_pool.free_stacks > 1) {
- rb_warn("Setting RUBY_SHARED_FIBER_POOL_FREE_STACKS to a value greater than 1 is operating system specific, and may cause crashes.");
- }
}
rb_cFiber = rb_define_class("Fiber", rb_cObject);
@@ -3409,7 +3383,6 @@ Init_Cont(void)
rb_define_method(rb_cFiber, "storage=", rb_fiber_storage_set, 1);
rb_define_method(rb_cFiber, "resume", rb_fiber_m_resume, -1);
rb_define_method(rb_cFiber, "raise", rb_fiber_m_raise, -1);
- rb_define_method(rb_cFiber, "kill", rb_fiber_m_kill, 0);
rb_define_method(rb_cFiber, "backtrace", rb_fiber_backtrace, -1);
rb_define_method(rb_cFiber, "backtrace_locations", rb_fiber_backtrace_locations, -1);
rb_define_method(rb_cFiber, "to_s", fiber_to_s, 0);
diff --git a/coroutine/amd64/Context.S b/coroutine/amd64/Context.S
index eebf9bf18e..d50732adbc 100644
--- a/coroutine/amd64/Context.S
+++ b/coroutine/amd64/Context.S
@@ -5,10 +5,6 @@
## Copyright, 2018, by Samuel Williams.
##
-/* Important - do _not_ include <cet.h> in this file; doing so will
- * cause an incorrect .note.gnu.property section to be emitted. We have
- * one at the bottom of this file */
-
#define TOKEN_PASTE(x,y) x##y
#define PREFIXED_SYMBOL(prefix,name) TOKEN_PASTE(prefix,name)
@@ -17,40 +13,29 @@
.globl PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer)
PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer):
-#if defined(__CET__) && (__CET__ & 0x01) != 0
- /* IBT landing pad */
- endbr64
-#endif
-
- # Make space on the stack for 6 registers:
- subq $48, %rsp
+ # Save caller state
+ pushq %rbp
+ pushq %rbx
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
- # Save caller state:
- movq %rbp, 40(%rsp)
- movq %rbx, 32(%rsp)
- movq %r12, 24(%rsp)
- movq %r13, 16(%rsp)
- movq %r14, 8(%rsp)
- movq %r15, (%rsp)
-
- # Save caller stack pointer:
+ # Save caller stack pointer
movq %rsp, (%rdi)
- # Restore callee stack pointer:
+ # Restore callee stack pointer
movq (%rsi), %rsp
# Restore callee state
- movq 40(%rsp), %rbp
- movq 32(%rsp), %rbx
- movq 24(%rsp), %r12
- movq 16(%rsp), %r13
- movq 8(%rsp), %r14
- movq (%rsp), %r15
-
- # Adjust stack pointer back:
- addq $48, %rsp
-
- # Put the first argument into the return value:
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %rbx
+ popq %rbp
+
+ # Put the first argument into the return value
movq %rdi, %rax
# We pop the return address and jump to it
@@ -59,31 +44,3 @@ PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer):
#if (defined(__linux__) || defined(__FreeBSD__)) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
-
-#if defined(__ELF__)
-
-#if defined(__CET__) && (__CET__ & 0x01) != 0
-# define IBT_FLAG 0x01
-#else
-# define IBT_FLAG 0x00
-#endif
-
-/* We do _NOT_ support CET shadow-stack. Do _not_ add the property for
- * this to the Context.o object. If you require CET shadow-stack support,
- * for now, consider building with --with-coroutine=ucontext */
-#define SHSTK_FLAG 0x00
-
-.pushsection .note.gnu.property, "a"
-.p2align 3
-.long 0x4 /* Name size ("GNU\0") */
-.long 0x10 /* Descriptor size */
-.long 0x5 /* Type: NT_GNU_PROPERTY_TYPE_0 */
-.asciz "GNU" /* Name */
-# Begin descriptor
-.long 0xc0000002 /* Property type: GNU_PROPERTY_X86_FEATURE_1_AND */
-.long 0x4 /* Property size */
-.long (IBT_FLAG | SHSTK_FLAG)
-.long 0x0 /* 8-byte alignment padding */
-/* End descriptor */
-.popsection
-#endif
diff --git a/coroutine/arm64/Context.S b/coroutine/arm64/Context.S
index 2391333cae..07d50d30df 100644
--- a/coroutine/arm64/Context.S
+++ b/coroutine/arm64/Context.S
@@ -18,29 +18,11 @@
.align 2
#endif
-#if defined(__ARM_FEATURE_PAC_DEFAULT) && (__ARM_FEATURE_PAC_DEFAULT & 0x02) != 0
-# error "-mbranch-protection flag specified b-key but Context.S does not support this"
-#endif
-
-## NOTE(PAC): Use we HINT mnemonics instead of PAC mnemonics to
-## keep compatibility with those assemblers that don't support PAC.
-##
-## See "Providing protection for complex software" for more details about PAC/BTI
-## https://developer.arm.com/architectures/learn-the-architecture/providing-protection-for-complex-software
-
.global PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer)
PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer):
-#if defined(__ARM_FEATURE_PAC_DEFAULT) && (__ARM_FEATURE_PAC_DEFAULT != 0)
- # paciasp (it also acts as BTI landing pad, so no need to insert BTI also)
- hint #25
-#elif defined(__ARM_FEATURE_BTI_DEFAULT) && (__ARM_FEATURE_BTI_DEFAULT != 0)
- # For the case PAC is not enabled but BTI is.
- # bti c
- hint #34
-#endif
# Make space on the stack for caller registers
- sub sp, sp, 0xa0
+ sub sp, sp, 0xb0
# Save caller registers
stp d8, d9, [sp, 0x00]
@@ -54,6 +36,9 @@ PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer):
stp x27, x28, [sp, 0x80]
stp x29, x30, [sp, 0x90]
+ # Save return address
+ str x30, [sp, 0xa0]
+
# Save stack pointer to x0 (first argument)
mov x2, sp
str x2, [x0, 0]
@@ -74,53 +59,15 @@ PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer):
ldp x27, x28, [sp, 0x80]
ldp x29, x30, [sp, 0x90]
- # Pop stack frame
- add sp, sp, 0xa0
+ # Load return address into x4
+ ldr x4, [sp, 0xa0]
-#if defined(__ARM_FEATURE_PAC_DEFAULT) && (__ARM_FEATURE_PAC_DEFAULT != 0)
- # autiasp: Authenticate x30 (LR) with SP and key A
- hint #29
-#endif
+ # Pop stack frame
+ add sp, sp, 0xb0
- # Jump to return address (in x30)
- ret
+ # Jump to return address (in x4)
+ ret x4
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
-
-#if (defined(__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT != 0) || (defined(__ARM_FEATURE_PAC_DEFAULT) && __ARM_FEATURE_PAC_DEFAULT != 0)
-#if defined(__ELF__)
-/* See "ELF for the Arm 64-bit Architecture (AArch64)"
- https://github.com/ARM-software/abi-aa/blob/2023Q3/aaelf64/aaelf64.rst#program-property */
-# define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1<<0)
-# define GNU_PROPERTY_AARCH64_FEATURE_1_PAC (1<<1)
-
-# if defined(__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT != 0
-# define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI
-# else
-# define BTI_FLAG 0
-# endif
-# if defined(__ARM_FEATURE_PAC_DEFAULT) && __ARM_FEATURE_PAC_DEFAULT != 0
-# define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC
-# else
-# define PAC_FLAG 0
-# endif
-
- # The note section format is described by Note Section in Chapter 5
- # of "System V Application Binary Interface, Edition 4.1".
- .pushsection .note.gnu.property, "a"
- .p2align 3
- .long 0x4 /* Name size ("GNU\0") */
- .long 0x10 /* Descriptor size */
- .long 0x5 /* Type: NT_GNU_PROPERTY_TYPE_0 */
- .asciz "GNU" /* Name */
- # Begin descriptor
- .long 0xc0000000 /* Property type: GNU_PROPERTY_AARCH64_FEATURE_1_AND */
- .long 0x4 /* Property size */
- .long (BTI_FLAG|PAC_FLAG)
- .long 0x0 /* 8-byte alignment padding */
- # End descriptor
- .popsection
-#endif
-#endif
diff --git a/coroutine/arm64/Context.h b/coroutine/arm64/Context.h
index eb66fbea0f..1472621f48 100644
--- a/coroutine/arm64/Context.h
+++ b/coroutine/arm64/Context.h
@@ -17,7 +17,7 @@
#define COROUTINE __attribute__((noreturn)) void
-enum {COROUTINE_REGISTERS = 0xa0 / 8};
+enum {COROUTINE_REGISTERS = 0xb0 / 8};
#if defined(__SANITIZE_ADDRESS__)
#define COROUTINE_SANITIZE_ADDRESS
@@ -50,20 +50,6 @@ static inline void coroutine_initialize_main(struct coroutine_context * context)
context->stack_pointer = NULL;
}
-static inline void *ptrauth_sign_instruction_addr(void *addr, void *modifier) {
-#if defined(__ARM_FEATURE_PAC_DEFAULT) && __ARM_FEATURE_PAC_DEFAULT != 0
- // Sign the given instruction address with the given modifier and key A
- register void *r17 __asm("r17") = addr;
- register void *r16 __asm("r16") = modifier;
- // Use HINT mnemonic instead of PACIA1716 for compatibility with older assemblers.
- __asm ("hint #8;" : "+r"(r17) : "r"(r16));
- addr = r17;
-#else
- // No-op if PAC is not enabled
-#endif
- return addr;
-}
-
static inline void coroutine_initialize(
struct coroutine_context *context,
coroutine_start start,
@@ -80,13 +66,12 @@ static inline void coroutine_initialize(
// Stack grows down. Force 16-byte alignment.
char * top = (char*)stack + size;
- top = (char *)((uintptr_t)top & ~0xF);
- context->stack_pointer = (void**)top;
+ context->stack_pointer = (void**)((uintptr_t)top & ~0xF);
context->stack_pointer -= COROUTINE_REGISTERS;
memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
- context->stack_pointer[0x98 / 8] = ptrauth_sign_instruction_addr((void*)start, (void*)top);
+ context->stack_pointer[0xa0 / 8] = (void*)start;
}
struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
diff --git a/coroutine/loongarch64/Context.S b/coroutine/loongarch64/Context.S
deleted file mode 100644
index 662f5dfb6c..0000000000
--- a/coroutine/loongarch64/Context.S
+++ /dev/null
@@ -1,73 +0,0 @@
-#define TOKEN_PASTE(x,y) x##y
-#define PREFIXED_SYMBOL(prefix,name) TOKEN_PASTE(prefix,name)
-
-.text
-.align 2
-
-.global PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer)
-PREFIXED_SYMBOL(SYMBOL_PREFIX,coroutine_transfer):
-
- # Make space on the stack for caller registers
- addi.d $sp, $sp, -0xa0
-
- # Save caller registers
- st.d $s0, $sp, 0x00
- st.d $s1, $sp, 0x08
- st.d $s2, $sp, 0x10
- st.d $s3, $sp, 0x18
- st.d $s4, $sp, 0x20
- st.d $s5, $sp, 0x28
- st.d $s6, $sp, 0x30
- st.d $s7, $sp, 0x38
- st.d $s8, $sp, 0x40
- st.d $fp, $sp, 0x48
- fst.d $fs0, $sp, 0x50
- fst.d $fs1, $sp, 0x58
- fst.d $fs2, $sp, 0x60
- fst.d $fs3, $sp, 0x68
- fst.d $fs4, $sp, 0x70
- fst.d $fs5, $sp, 0x78
- fst.d $fs6, $sp, 0x80
- fst.d $fs7, $sp, 0x88
-
- # Save return address
- st.d $ra, $sp, 0x90
-
- # Save stack pointer to a0 (first argument)
- st.d $sp, $a0, 0x00
-
- # Load stack pointer from a1 (second argument)
- ld.d $sp, $a1, 0x00
-
- # Restore caller registers
- ld.d $s0, $sp, 0x00
- ld.d $s1, $sp, 0x08
- ld.d $s2, $sp, 0x10
- ld.d $s3, $sp, 0x18
- ld.d $s4, $sp, 0x20
- ld.d $s5, $sp, 0x28
- ld.d $s6, $sp, 0x30
- ld.d $s7, $sp, 0x38
- ld.d $s8, $sp, 0x40
- ld.d $fp, $sp, 0x48
- fld.d $fs0, $sp, 0x50
- fld.d $fs1, $sp, 0x58
- fld.d $fs2, $sp, 0x60
- fld.d $fs3, $sp, 0x68
- fld.d $fs4, $sp, 0x70
- fld.d $fs5, $sp, 0x78
- fld.d $fs6, $sp, 0x80
- fld.d $fs7, $sp, 0x88
-
- # Load return address
- ld.d $ra, $sp, 0x90
-
- # Pop stack frame
- addi.d $sp, $sp, 0xa0
-
- # Jump to return address
- jr $ra
-
-#if defined(__linux__) && defined(__ELF__)
-.section .note.GNU-stack,"",%progbits
-#endif
diff --git a/coroutine/loongarch64/Context.h b/coroutine/loongarch64/Context.h
deleted file mode 100644
index 668c9a965e..0000000000
--- a/coroutine/loongarch64/Context.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#pragma once
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
-
-#define COROUTINE __attribute__((noreturn)) void
-
-enum {COROUTINE_REGISTERS = 0xa0 / 8};
-
-struct coroutine_context
-{
- void **stack_pointer;
- void *argument;
-};
-
-typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
-
-static inline void coroutine_initialize_main(struct coroutine_context * context) {
- context->stack_pointer = NULL;
-}
-
-static inline void coroutine_initialize(
- struct coroutine_context *context,
- coroutine_start start,
- void *stack,
- size_t size
-) {
- assert(start && stack && size >= 1024);
-
- // Stack grows down. Force 16-byte alignment.
- char * top = (char*)stack + size;
- context->stack_pointer = (void**)((uintptr_t)top & ~0xF);
-
- context->stack_pointer -= COROUTINE_REGISTERS;
- memset(context->stack_pointer, 0, sizeof(void*) * COROUTINE_REGISTERS);
-
- context->stack_pointer[0x90 / 8] = (void*)start;
-}
-
-struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target);
-
-static inline void coroutine_destroy(struct coroutine_context * context)
-{
-}
diff --git a/coroutine/ppc/Context.S b/coroutine/ppc/Context.S
index e2431a9250..cdda93e179 100644
--- a/coroutine/ppc/Context.S
+++ b/coroutine/ppc/Context.S
@@ -3,7 +3,7 @@
; Some relevant examples: https://github.com/gcc-mirror/gcc/blob/master/libphobos/libdruntime/config/powerpc/switchcontext.S
; https://github.com/gcc-mirror/gcc/blob/master/libgcc/config/rs6000/darwin-gpsave.S
; https://www.ibm.com/docs/en/aix/7.2?topic=epilogs-saving-gprs-only
-; ppc32 version may be re-written compactly with stmw/lwm, but the code won't be faster, see: https://github.com/ruby/ruby/pull/5927#issuecomment-1139730541
+; ppc32 version may be re-written compactly with stmw/lwm, but the code wonʼt be faster, see: https://github.com/ruby/ruby/pull/5927#issuecomment-1139730541
; Notice that this code is only for Darwin (macOS). Darwin ABI differs from AIX and ELF.
; To add support for AIX, *BSD or *Linux, please make separate implementations.
diff --git a/coroutine/ppc/Context.h b/coroutine/ppc/Context.h
index 8035d08556..1fce112579 100644
--- a/coroutine/ppc/Context.h
+++ b/coroutine/ppc/Context.h
@@ -13,7 +13,7 @@
enum {
COROUTINE_REGISTERS =
- 20 /* 19 general purpose registers (r13-r31) and 1 return address */
+ 20 /* 19 general purpose registers (r13–r31) and 1 return address */
+ 4 /* space for fiber_entry() to store the link register */
};
diff --git a/coroutine/ppc64/Context.h b/coroutine/ppc64/Context.h
index 085b475ed5..3e6f77f55a 100644
--- a/coroutine/ppc64/Context.h
+++ b/coroutine/ppc64/Context.h
@@ -12,7 +12,7 @@
enum {
COROUTINE_REGISTERS =
- 20 /* 19 general purpose registers (r13-r31) and 1 return address */
+ 20 /* 19 general purpose registers (r13–r31) and 1 return address */
+ 4 /* space for fiber_entry() to store the link register */
};
diff --git a/coroutine/win64/Context.h b/coroutine/win64/Context.h
index d85ebf8e0e..aaa4caeaf9 100644
--- a/coroutine/win64/Context.h
+++ b/coroutine/win64/Context.h
@@ -30,7 +30,7 @@ struct coroutine_context
typedef void(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
-void coroutine_trampoline(void);
+void coroutine_trampoline();
static inline void coroutine_initialize_main(struct coroutine_context * context) {
context->stack_pointer = NULL;
diff --git a/cygwin/GNUmakefile.in b/cygwin/GNUmakefile.in
index 192a8cc711..f342d2fcf7 100644
--- a/cygwin/GNUmakefile.in
+++ b/cygwin/GNUmakefile.in
@@ -2,15 +2,13 @@ gnumake = yes
include Makefile
+MUNICODE_FLAG := $(if $(filter mingw%,$(target_os)),-municode)
+override EXE_LDFLAGS += $(MUNICODE_FLAG)
+
DLLWRAP = @DLLWRAP@ --target=$(target_os) --driver-name="$(CC)"
-ifeq (@USE_LLVM_WINDRES@,yes) # USE_LLVM_WINDRES
- # llvm-windres fails when preprocessor options are added
- windres-cpp :=
-else
- windres-cpp := $(CPP) -xc
- windres-cpp := --preprocessor=$(firstword $(windres-cpp)) \
- $(addprefix --preprocessor-arg=,$(wordlist 2,$(words $(windres-cpp)),$(windres-cpp)))
-endif
+windres-cpp := $(CPP) -xc
+windres-cpp := --preprocessor=$(firstword $(windres-cpp)) \
+ $(addprefix --preprocessor-arg=,$(wordlist 2,$(words $(windres-cpp)),$(windres-cpp)))
WINDRES = @WINDRES@ $(windres-cpp) -DRC_INVOKED
STRIP = @STRIP@
@@ -46,7 +44,6 @@ SOLIBS := $(DLL_BASE_NAME).res.$(OBJEXT) $(SOLIBS)
override EXTOBJS += $(if $(filter-out $(RUBYW_INSTALL_NAME),$(@:$(EXEEXT)=)),$(RUBY_INSTALL_NAME),$(@:$(EXEEXT)=)).res.$(OBJEXT)
RCFILES = $(RUBY_INSTALL_NAME).rc $(RUBYW_INSTALL_NAME).rc $(DLL_BASE_NAME).rc
RUBYDEF = $(DLL_BASE_NAME).def
-override LIBRUBY_FOR_LEAKED_GLOBALS := # DLL shows symbols from import library
ruby: $(PROGRAM)
rubyw: $(WPROGRAM)
@@ -69,7 +66,7 @@ $(PROGRAM): $(RUBY_INSTALL_NAME).res.$(OBJEXT)
$(WPROGRAM): $(RUBYW_INSTALL_NAME).res.$(OBJEXT)
@rm -f $@
$(ECHO) linking $@
- $(Q) $(PURIFY) $(CC) -mwindows -e $(SYMBOL_PREFIX)mainCRTStartup $(LDFLAGS) $(XLDFLAGS) \
+ $(Q) $(PURIFY) $(CC) $(MUNICODE_FLAG) -mwindows -e $(SYMBOL_PREFIX)mainCRTStartup $(LDFLAGS) $(XLDFLAGS) \
$(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(LIBS) -o $@
$(STUBPROGRAM): $(RUBY_INSTALL_NAME).res.$(OBJEXT)
diff --git a/darray.h b/darray.h
index 08b53d8cd1..c9a53f1e01 100644
--- a/darray.h
+++ b/darray.h
@@ -5,8 +5,6 @@
#include <stddef.h>
#include <stdlib.h>
-#include "internal/bits.h"
-
// Type for a dynamic array. Use to declare a dynamic array.
// It is a pointer so it fits in st_table nicely. Designed
// to be fairly type-safe.
@@ -39,13 +37,12 @@
//
#define rb_darray_ref(ary, idx) (&((ary)->data[(idx)]))
-/* Copy a new element into the array. ptr_to_ary is evaluated multiple times.
- *
- * void rb_darray_append(rb_darray(T) *ptr_to_ary, T element);
- */
+// Copy a new element into the array. ptr_to_ary is evaluated multiple times.
+//
+// void rb_darray_append(rb_darray(T) *ptr_to_ary, T element);
+//
#define rb_darray_append(ptr_to_ary, element) do { \
- rb_darray_ensure_space((ptr_to_ary), \
- sizeof(**(ptr_to_ary)), \
+ rb_darray_ensure_space((ptr_to_ary), sizeof(**(ptr_to_ary)), \
sizeof((*(ptr_to_ary))->data[0])); \
rb_darray_set(*(ptr_to_ary), \
(*(ptr_to_ary))->meta.size, \
@@ -53,65 +50,53 @@
(*(ptr_to_ary))->meta.size++; \
} while (0)
-#define rb_darray_insert(ptr_to_ary, idx, element) do { \
- rb_darray_ensure_space((ptr_to_ary), \
- sizeof(**(ptr_to_ary)), \
- sizeof((*(ptr_to_ary))->data[0])); \
- MEMMOVE( \
- rb_darray_ref(*(ptr_to_ary), idx + 1), \
- rb_darray_ref(*(ptr_to_ary), idx), \
- sizeof((*(ptr_to_ary))->data[0]), \
- rb_darray_size(*(ptr_to_ary)) - idx); \
- rb_darray_set(*(ptr_to_ary), idx, element); \
- (*(ptr_to_ary))->meta.size++; \
-} while (0)
+
+// Last element of the array
+//
+#define rb_darray_back(ary) ((ary)->data[(ary)->meta.size - 1])
+
+// Remove the last element of the array.
+//
+#define rb_darray_pop_back(ary) ((ary)->meta.size--)
+
+// Remove element at idx and replace it by the last element
+#define rb_darray_remove_unordered(ary, idx) do { \
+ rb_darray_set(ary, idx, rb_darray_back(ary)); \
+ rb_darray_pop_back(ary); \
+} while (0);
// Iterate over items of the array in a for loop
//
#define rb_darray_foreach(ary, idx_name, elem_ptr_var) \
for (size_t idx_name = 0; idx_name < rb_darray_size(ary) && ((elem_ptr_var) = rb_darray_ref(ary, idx_name)); ++idx_name)
-// Iterate over valid indices in the array in a for loop
+// Iterate over valid indicies in the array in a for loop
//
#define rb_darray_for(ary, idx_name) \
for (size_t idx_name = 0; idx_name < rb_darray_size(ary); ++idx_name)
-/* Make a dynamic array of a certain size. All bytes backing the elements are set to zero.
- * Return 1 on success and 0 on failure.
- *
- * Note that NULL is a valid empty dynamic array.
- *
- * void rb_darray_make(rb_darray(T) *ptr_to_ary, size_t size);
- */
+// Make a dynamic array of a certain size. All bytes backing the elements are set to zero.
+//
+// Note that NULL is a valid empty dynamic array.
+//
+// void rb_darray_make(rb_darray(T) *ptr_to_ary, size_t size);
+//
#define rb_darray_make(ptr_to_ary, size) \
- rb_darray_make_impl((ptr_to_ary), size, sizeof(**(ptr_to_ary)), sizeof((*(ptr_to_ary))->data[0]))
-
-/* Resize the darray to a new capacity. The new capacity must be greater than
- * or equal to the size of the darray.
- *
- * void rb_darray_resize_capa(rb_darray(T) *ptr_to_ary, size_t capa);
- */
-#define rb_darray_resize_capa(ptr_to_ary, capa) \
- rb_darray_resize_capa_impl((ptr_to_ary), capa, sizeof(**(ptr_to_ary)), sizeof((*(ptr_to_ary))->data[0]))
+ rb_darray_make_impl((ptr_to_ary), size, sizeof(**(ptr_to_ary)), \
+ sizeof((*(ptr_to_ary))->data[0]))
#define rb_darray_data_ptr(ary) ((ary)->data)
+// Set the size of the array to zero without freeing the backing memory.
+// Allows reusing the same array.
+//
+#define rb_darray_clear(ary) (ary->meta.size = 0)
+
typedef struct rb_darray_meta {
size_t size;
size_t capa;
} rb_darray_meta_t;
-/* Set the size of the array to zero without freeing the backing memory.
- * Allows reusing the same array. */
-static inline void
-rb_darray_clear(void *ary)
-{
- rb_darray_meta_t *meta = ary;
- if (meta) {
- meta->size = 0;
- }
-}
-
// Get the size of the dynamic array.
//
static inline size_t
@@ -121,14 +106,6 @@ rb_darray_size(const void *ary)
return meta ? meta->size : 0;
}
-
-static inline void
-rb_darray_pop(void *ary, size_t count)
-{
- rb_darray_meta_t *meta = ary;
- meta->size -= count;
-}
-
// Get the capacity of the dynamic array.
//
static inline size_t
@@ -138,36 +115,13 @@ rb_darray_capa(const void *ary)
return meta ? meta->capa : 0;
}
-/* Free the dynamic array. */
+// Free the dynamic array.
+//
static inline void
rb_darray_free(void *ary)
{
- xfree(ary);
-}
-
-/* Internal function. Resizes the capacity of a darray. The new capacity must
- * be greater than or equal to the size of the darray. */
-static inline void
-rb_darray_resize_capa_impl(void *ptr_to_ary, size_t new_capa, size_t header_size, size_t element_size)
-{
- rb_darray_meta_t **ptr_to_ptr_to_meta = ptr_to_ary;
- rb_darray_meta_t *meta = *ptr_to_ptr_to_meta;
-
- rb_darray_meta_t *new_ary = xrealloc(meta, new_capa * element_size + header_size);
-
- if (meta == NULL) {
- /* First allocation. Initialize size. On subsequence allocations
- * realloc takes care of carrying over the size. */
- new_ary->size = 0;
- }
-
- RUBY_ASSERT(new_ary->size <= new_capa);
-
- new_ary->capa = new_capa;
-
- // We don't have access to the type of the dynamic array in function context.
- // Write out result with memcpy to avoid strict aliasing issue.
- memcpy(ptr_to_ary, &new_ary, sizeof(new_ary));
+ rb_darray_meta_t *meta = ary;
+ ruby_sized_xfree(ary, meta->capa);
}
// Internal function
@@ -184,7 +138,21 @@ rb_darray_ensure_space(void *ptr_to_ary, size_t header_size, size_t element_size
// Double the capacity
size_t new_capa = current_capa == 0 ? 1 : current_capa * 2;
- rb_darray_resize_capa_impl(ptr_to_ary, new_capa, header_size, element_size);
+ rb_darray_meta_t *doubled_ary = rb_xrealloc_mul_add(meta, new_capa, element_size, header_size);
+ // rb_xrealloc functions guarantee that NULL is not returned
+ assert(doubled_ary != NULL);
+
+ if (meta == NULL) {
+ // First allocation. Initialize size. On subsequence allocations
+ // realloc takes care of carrying over the size.
+ doubled_ary->size = 0;
+ }
+
+ doubled_ary->capa = new_capa;
+
+ // We don't have access to the type of the dynamic array in function context.
+ // Write out result with memcpy to avoid strict aliasing issue.
+ memcpy(ptr_to_ary, &doubled_ary, sizeof(doubled_ary));
}
static inline void
@@ -196,7 +164,9 @@ rb_darray_make_impl(void *ptr_to_ary, size_t array_size, size_t header_size, siz
return;
}
- rb_darray_meta_t *meta = xcalloc(array_size * element_size + header_size, 1);
+ rb_darray_meta_t *meta = rb_xcalloc_mul_add(array_size, element_size, header_size);
+ // rb_xcalloc functions guarantee that NULL is not returned
+ assert(meta != NULL);
meta->size = array_size;
meta->capa = array_size;
diff --git a/debug.c b/debug.c
index 4717a0bc9c..3dd0f71906 100644
--- a/debug.c
+++ b/debug.c
@@ -53,8 +53,14 @@ const union {
rb_econv_result_t econv_result;
enum ruby_preserved_encindex encoding_index;
enum ruby_robject_flags robject_flags;
+#if !USE_RVARGC
+ enum ruby_robject_consts robject_consts;
+#endif
enum ruby_rmodule_flags rmodule_flags;
enum ruby_rstring_flags rstring_flags;
+#if !USE_RVARGC
+ enum ruby_rstring_consts rstring_consts;
+#endif
enum ruby_rarray_flags rarray_flags;
enum ruby_rarray_consts rarray_consts;
enum {
@@ -70,7 +76,7 @@ const union {
RUBY_FMODE_NOREVLOOKUP = 0x00000100,
RUBY_FMODE_TRUNC = FMODE_TRUNC,
RUBY_FMODE_TEXTMODE = FMODE_TEXTMODE,
- RUBY_FMODE_EXTERNAL = 0x00010000,
+ RUBY_FMODE_PREP = 0x00010000,
RUBY_FMODE_SETENC_BY_BOM = FMODE_SETENC_BY_BOM,
RUBY_FMODE_UNIX = 0x00200000,
RUBY_FMODE_INET = 0x00400000,
@@ -112,7 +118,7 @@ ruby_debug_printf(const char *format, ...)
va_end(ap);
}
-#include "internal/gc.h"
+#include "gc.h"
VALUE
ruby_debug_print_value(int level, int debug_level, const char *header, VALUE obj)
@@ -147,21 +153,13 @@ NODE *
ruby_debug_print_node(int level, int debug_level, const char *header, const NODE *node)
{
if (level < debug_level) {
- fprintf(stderr, "DBG> %s: %s (id: %d, line: %d, location: (%d,%d)-(%d,%d))\n",
- header, ruby_node_name(nd_type(node)), nd_node_id(node), nd_line(node),
- nd_first_lineno(node), nd_first_column(node),
- nd_last_lineno(node), nd_last_column(node));
+ fprintf(stderr, "DBG> %s: %s (%u)\n", header,
+ ruby_node_name(nd_type(node)), nd_line(node));
}
return (NODE *)node;
}
void
-ruby_debug_print_n(const NODE *node)
-{
- ruby_debug_print_node(0, 1, "", node);
-}
-
-void
ruby_debug_breakpoint(void)
{
/* */
@@ -185,9 +183,9 @@ ruby_env_debug_option(const char *str, int len, void *arg)
int ov;
size_t retlen;
unsigned long n;
-#define NAME_MATCH(name) (len == sizeof(name) - 1 && strncmp(str, (name), len) == 0)
#define SET_WHEN(name, var, val) do { \
- if (NAME_MATCH(name)) { \
+ if (len == sizeof(name) - 1 && \
+ strncmp(str, (name), len) == 0) { \
(var) = (val); \
return 1; \
} \
@@ -215,31 +213,31 @@ ruby_env_debug_option(const char *str, int len, void *arg)
--len; \
} \
if (len > 0) { \
- fprintf(stderr, "ignored "name" option: '%.*s'\n", len, str); \
+ fprintf(stderr, "ignored "name" option: `%.*s'\n", len, str); \
} \
} while (0)
#define SET_WHEN_UINT(name, vals, num, req) \
- if (NAME_MATCH_VALUE(name)) { \
- if (!len) req; \
- else SET_UINT_LIST(name, vals, num); \
- return 1; \
- }
+ if (NAME_MATCH_VALUE(name)) SET_UINT_LIST(name, vals, num);
- if (NAME_MATCH("gc_stress")) {
- rb_gc_initial_stress_set(Qtrue);
- return 1;
- }
+ SET_WHEN("gc_stress", *ruby_initial_gc_stress_ptr, Qtrue);
SET_WHEN("core", ruby_enable_coredump, 1);
SET_WHEN("ci", ruby_on_ci, 1);
- SET_WHEN_UINT("rgengc", &ruby_rgengc_debug, 1, ruby_rgengc_debug = 1);
+ if (NAME_MATCH_VALUE("rgengc")) {
+ if (!len) ruby_rgengc_debug = 1;
+ else SET_UINT_LIST("rgengc", &ruby_rgengc_debug, 1);
+ return 1;
+ }
#if defined _WIN32
# if RUBY_MSVCRT_VERSION >= 80
SET_WHEN("rtc_error", ruby_w32_rtc_error, 1);
# endif
#endif
#if defined _WIN32 || defined __CYGWIN__
- SET_WHEN_UINT("codepage", ruby_w32_codepage, numberof(ruby_w32_codepage),
- fprintf(stderr, "missing codepage argument"));
+ if (NAME_MATCH_VALUE("codepage")) {
+ if (!len) fprintf(stderr, "missing codepage argument");
+ else SET_UINT_LIST("codepage", ruby_w32_codepage, numberof(ruby_w32_codepage));
+ return 1;
+ }
#endif
return 0;
}
@@ -293,20 +291,12 @@ static const char *dlf_type_names[] = {
"func",
};
-#ifdef MAX_PATH
-#define DEBUG_LOG_MAX_PATH (MAX_PATH-1)
-#else
-#define DEBUG_LOG_MAX_PATH 255
-#endif
-
static struct {
char *mem;
unsigned int cnt;
struct debug_log_filter filters[MAX_DEBUG_LOG_FILTER_NUM];
unsigned int filters_num;
- bool show_pid;
rb_nativethread_lock_t lock;
- char output_file[DEBUG_LOG_MAX_PATH+1];
FILE *output;
} debug_log;
@@ -408,39 +398,7 @@ setup_debug_log(void)
}
else {
ruby_debug_log_mode |= ruby_debug_log_file;
-
- // pid extension with %p
- unsigned long len = strlen(log_config);
-
- for (unsigned long i=0, j=0; i<len; i++) {
- const char c = log_config[i];
-
- if (c == '%') {
- i++;
- switch (log_config[i]) {
- case '%':
- debug_log.output_file[j++] = '%';
- break;
- case 'p':
- snprintf(debug_log.output_file + j, DEBUG_LOG_MAX_PATH - j, "%d", getpid());
- j = strlen(debug_log.output_file);
- break;
- default:
- fprintf(stderr, "can not parse RUBY_DEBUG_LOG filename: %s\n", log_config);
- exit(1);
- }
- }
- else {
- debug_log.output_file[j++] = c;
- }
-
- if (j >= DEBUG_LOG_MAX_PATH) {
- fprintf(stderr, "RUBY_DEBUG_LOG=%s is too long\n", log_config);
- exit(1);
- }
- }
-
- if ((debug_log.output = fopen(debug_log.output_file, "w")) == NULL) {
+ if ((debug_log.output = fopen(log_config, "w")) == NULL) {
fprintf(stderr, "can not open %s for RUBY_DEBUG_LOG\n", log_config);
exit(1);
}
@@ -451,17 +409,9 @@ setup_debug_log(void)
(ruby_debug_log_mode & ruby_debug_log_memory) ? "[mem]" : "",
(ruby_debug_log_mode & ruby_debug_log_stderr) ? "[stderr]" : "",
(ruby_debug_log_mode & ruby_debug_log_file) ? "[file]" : "");
- if (debug_log.output_file[0]) {
- fprintf(stderr, "RUBY_DEBUG_LOG filename=%s\n", debug_log.output_file);
- }
-
rb_nativethread_lock_initialize(&debug_log.lock);
setup_debug_log_filter();
-
- if (getenv("RUBY_DEBUG_LOG_PID")) {
- debug_log.show_pid = true;
- }
}
}
@@ -500,7 +450,7 @@ check_filter(const char *str, const struct debug_log_filter *filter, bool *state
// (func_name or file_name) contains baz or boo
//
// RUBY_DEBUG_LOG_FILTER=foo,bar,-baz,-boo
-// returns true if
+// retunrs true if
// (func_name or file_name) contains foo or bar
// or
// (func_name or file_name) doesn't contain baz and
@@ -557,16 +507,10 @@ ruby_debug_log(const char *file, int line, const char *func_name, const char *fm
int len = 0;
int r = 0;
- if (debug_log.show_pid) {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN, "pid:%d\t", getpid());
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
- len += r;
- }
-
// message title
if (func_name && len < MAX_DEBUG_LOG_MESSAGE_LEN) {
r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN, "%s\t", func_name);
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
+ if (r < 0) rb_bug("ruby_debug_log returns %d\n", r);
len += r;
}
@@ -585,67 +529,41 @@ ruby_debug_log(const char *file, int line, const char *func_name, const char *fm
// C location
if (file && len < MAX_DEBUG_LOG_MESSAGE_LEN) {
r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN, "\t%s:%d", pretty_filename(file), line);
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
+ if (r < 0) rb_bug("ruby_debug_log returns %d\n", r);
len += r;
}
- rb_execution_context_t *ec = rb_current_execution_context(false);
-
- // Ruby location
- int ruby_line;
- const char *ruby_file = ec ? rb_source_location_cstr(&ruby_line) : NULL;
-
- if (len < MAX_DEBUG_LOG_MESSAGE_LEN) {
- if (ruby_file) {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\t%s:%d", pretty_filename(ruby_file), ruby_line);
- }
- else {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\t");
+ if (rb_current_execution_context(false)) {
+ // Ruby location
+ int ruby_line;
+ const char *ruby_file = rb_source_location_cstr(&ruby_line);
+ if (len < MAX_DEBUG_LOG_MESSAGE_LEN) {
+ if (ruby_file) {
+ r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\t%s:%d", pretty_filename(ruby_file), ruby_line);
+ }
+ else {
+ r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\t");
+ }
+ if (r < 0) rb_bug("ruby_debug_log returns %d\n", r);
+ len += r;
}
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
- len += r;
- }
-
-#ifdef RUBY_NT_SERIAL
- // native thread information
- if (len < MAX_DEBUG_LOG_MESSAGE_LEN) {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tnt:%d", ruby_nt_serial);
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
- len += r;
- }
-#endif
-
- if (ec) {
- rb_thread_t *th = ec ? rb_ec_thread_ptr(ec) : NULL;
// ractor information
if (ruby_single_main_ractor == NULL) {
- rb_ractor_t *cr = th ? th->ractor : NULL;
- rb_vm_t *vm = GET_VM();
-
+ rb_ractor_t *cr = GET_RACTOR();
if (r && len < MAX_DEBUG_LOG_MESSAGE_LEN) {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tr:#%d/%u (%u)",
- cr ? (int)rb_ractor_id(cr) : -1, vm->ractor.cnt, vm->ractor.sched.running_cnt);
-
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
+ r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tr:#%u/%u",
+ (unsigned int)rb_ractor_id(cr), GET_VM()->ractor.cnt);
+ if (r < 0) rb_bug("ruby_debug_log returns %d\n", r);
len += r;
}
}
// thread information
- if (th && r && len < MAX_DEBUG_LOG_MESSAGE_LEN) {
- rb_execution_context_t *rec = th->ractor ? th->ractor->threads.running_ec : NULL;
- const rb_thread_t *rth = rec ? rec->thread_ptr : NULL;
- const rb_thread_t *sth = th->ractor ? th->ractor->threads.sched.running : NULL;
-
- if (rth != th || sth != th) {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tth:%u (rth:%d,sth:%d)",
- rb_th_serial(th), rth ? (int)rb_th_serial(rth) : -1, sth ? (int)rb_th_serial(sth) : -1);
- }
- else {
- r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tth:%u", rb_th_serial(th));
- }
- if (r < 0) rb_bug("ruby_debug_log returns %d", r);
+ const rb_thread_t *th = GET_THREAD();
+ if (r && len < MAX_DEBUG_LOG_MESSAGE_LEN) {
+ r = snprintf(buff + len, MAX_DEBUG_LOG_MESSAGE_LEN - len, "\tth:%u", rb_th_serial(th));
+ if (r < 0) rb_bug("ruby_debug_log returns %d\n", r);
len += r;
}
}
@@ -683,7 +601,7 @@ debug_log_dump(FILE *out, unsigned int n)
int index = current_index - size + i;
if (index < 0) index += MAX_DEBUG_LOG;
VM_ASSERT(index <= MAX_DEBUG_LOG);
- const char *mesg = RUBY_DEBUG_LOG_MEM_ENTRY(index);
+ const char *mesg = RUBY_DEBUG_LOG_MEM_ENTRY(index);;
fprintf(out, "%4u: %s\n", debug_log.cnt - size + i, mesg);
}
}
diff --git a/debug_counter.c b/debug_counter.c
index 3dcc4c6a3a..463bebf849 100644
--- a/debug_counter.c
+++ b/debug_counter.c
@@ -25,8 +25,10 @@ const char *const rb_debug_counter_names[] = {
#undef RB_DEBUG_COUNTER
};
+MJIT_SYMBOL_EXPORT_BEGIN
size_t rb_debug_counter[numberof(rb_debug_counter_names)];
void rb_debug_counter_add_atomic(enum rb_debug_counter_type type, int add);
+MJIT_SYMBOL_EXPORT_END
static rb_nativethread_lock_t debug_counter_lock;
diff --git a/debug_counter.h b/debug_counter.h
index 481a0727e6..6e0b8dee60 100644
--- a/debug_counter.h
+++ b/debug_counter.h
@@ -100,13 +100,6 @@ RB_DEBUG_COUNTER(ccf_opt_block_call)
RB_DEBUG_COUNTER(ccf_opt_struct_aref)
RB_DEBUG_COUNTER(ccf_opt_struct_aset)
RB_DEBUG_COUNTER(ccf_super_method)
-RB_DEBUG_COUNTER(ccf_cfunc_other)
-RB_DEBUG_COUNTER(ccf_cfunc_only_splat)
-RB_DEBUG_COUNTER(ccf_cfunc_only_splat_kw)
-RB_DEBUG_COUNTER(ccf_iseq_bmethod)
-RB_DEBUG_COUNTER(ccf_noniseq_bmethod)
-RB_DEBUG_COUNTER(ccf_opt_send_complex)
-RB_DEBUG_COUNTER(ccf_opt_send_simple)
/*
* control frame push counts.
@@ -134,22 +127,29 @@ RB_DEBUG_COUNTER(frame_R2C)
RB_DEBUG_COUNTER(frame_C2C)
RB_DEBUG_COUNTER(frame_C2R)
-/* instance variable counts */
-RB_DEBUG_COUNTER(ivar_get_obj_hit) // Only T_OBJECT hits
-RB_DEBUG_COUNTER(ivar_get_obj_miss) // Only T_OBJECT misses
-RB_DEBUG_COUNTER(ivar_get_ic_hit) // All hits
-RB_DEBUG_COUNTER(ivar_get_ic_miss) // All misses
-RB_DEBUG_COUNTER(ivar_set_ic_hit) // All hits
-RB_DEBUG_COUNTER(ivar_set_obj_hit) // Only T_OBJECT hits
-RB_DEBUG_COUNTER(ivar_set_obj_miss) // Only T_OBJECT misses
-RB_DEBUG_COUNTER(ivar_set_ic_miss) // All misses
-RB_DEBUG_COUNTER(ivar_set_ic_miss_noobject) // Miss because non T_OBJECT
-RB_DEBUG_COUNTER(ivar_get_base) // Calls to `rb_ivar_get` (very slow path)
-RB_DEBUG_COUNTER(ivar_set_base) // Calls to `ivar_set` (very slow path)
-RB_DEBUG_COUNTER(ivar_get_ic_miss_set) // Misses on IV reads where the cache was wrong
-RB_DEBUG_COUNTER(ivar_get_cc_miss_set) // Misses on attr_reader where the cache was wrong
-RB_DEBUG_COUNTER(ivar_get_ic_miss_unset) // Misses on IV read where the cache wasn't set
-RB_DEBUG_COUNTER(ivar_get_cc_miss_unset) // Misses on attr_reader where the cache wasn't set
+/* instance variable counts
+ *
+ * * ivar_get_ic_hit/miss: ivar_get inline cache (ic) hit/miss counts (VM insn)
+ * * ivar_get_ic_miss_unset: ... by unset (VM insn)
+ * * ivar_get_ic_miss_noobject: ... by "not T_OBJECT" (VM insn)
+ * * ivar_set_...: same counts with ivar_set (VM insn)
+ * * ivar_get/set_base: call counts of "rb_ivar_get/set()".
+ * because of (1) ic miss.
+ * (2) direct call by C extensions.
+ */
+RB_DEBUG_COUNTER(ivar_get_ic_hit)
+RB_DEBUG_COUNTER(ivar_get_ic_miss)
+RB_DEBUG_COUNTER(ivar_get_ic_miss_noobject)
+RB_DEBUG_COUNTER(ivar_set_ic_hit)
+RB_DEBUG_COUNTER(ivar_set_ic_miss)
+RB_DEBUG_COUNTER(ivar_set_ic_miss_iv_hit)
+RB_DEBUG_COUNTER(ivar_set_ic_miss_noobject)
+RB_DEBUG_COUNTER(ivar_get_base)
+RB_DEBUG_COUNTER(ivar_set_base)
+RB_DEBUG_COUNTER(ivar_get_ic_miss_set)
+RB_DEBUG_COUNTER(ivar_get_cc_miss_set)
+RB_DEBUG_COUNTER(ivar_get_ic_miss_unset)
+RB_DEBUG_COUNTER(ivar_get_cc_miss_unset)
/* local variable counts
*
@@ -185,7 +185,8 @@ RB_DEBUG_COUNTER(gc_major_force)
RB_DEBUG_COUNTER(gc_major_oldmalloc)
RB_DEBUG_COUNTER(gc_enter_start)
-RB_DEBUG_COUNTER(gc_enter_continue)
+RB_DEBUG_COUNTER(gc_enter_mark_continue)
+RB_DEBUG_COUNTER(gc_enter_sweep_continue)
RB_DEBUG_COUNTER(gc_enter_rest)
RB_DEBUG_COUNTER(gc_enter_finalizer)
@@ -214,6 +215,7 @@ RB_DEBUG_COUNTER(gc_isptr_maybe)
* * [attr]
* * _ptr: R?? is not embed.
* * _embed: R?? is embed.
+ * * _transient: R?? uses transient heap.
* * type specific attr.
* * str_shared: str is shared.
* * str_nofree: nofree
@@ -239,6 +241,7 @@ RB_DEBUG_COUNTER(obj_promote)
RB_DEBUG_COUNTER(obj_wb_unprotect)
RB_DEBUG_COUNTER(obj_obj_embed)
+RB_DEBUG_COUNTER(obj_obj_transient)
RB_DEBUG_COUNTER(obj_obj_ptr)
RB_DEBUG_COUNTER(obj_obj_too_complex)
@@ -249,6 +252,7 @@ RB_DEBUG_COUNTER(obj_str_nofree)
RB_DEBUG_COUNTER(obj_str_fstr)
RB_DEBUG_COUNTER(obj_ary_embed)
+RB_DEBUG_COUNTER(obj_ary_transient)
RB_DEBUG_COUNTER(obj_ary_ptr)
RB_DEBUG_COUNTER(obj_ary_extracapa)
/*
@@ -272,9 +276,11 @@ RB_DEBUG_COUNTER(obj_hash_g8)
RB_DEBUG_COUNTER(obj_hash_null)
RB_DEBUG_COUNTER(obj_hash_ar)
RB_DEBUG_COUNTER(obj_hash_st)
+RB_DEBUG_COUNTER(obj_hash_transient)
RB_DEBUG_COUNTER(obj_hash_force_convert)
RB_DEBUG_COUNTER(obj_struct_embed)
+RB_DEBUG_COUNTER(obj_struct_transient)
RB_DEBUG_COUNTER(obj_struct_ptr)
RB_DEBUG_COUNTER(obj_data_empty)
@@ -329,6 +335,11 @@ RB_DEBUG_COUNTER(heap_xmalloc)
RB_DEBUG_COUNTER(heap_xrealloc)
RB_DEBUG_COUNTER(heap_xfree)
+/* transient_heap */
+RB_DEBUG_COUNTER(theap_alloc)
+RB_DEBUG_COUNTER(theap_alloc_fail)
+RB_DEBUG_COUNTER(theap_evacuate)
+
// VM sync
RB_DEBUG_COUNTER(vm_sync_lock)
RB_DEBUG_COUNTER(vm_sync_lock_enter)
@@ -356,7 +367,7 @@ RB_DEBUG_COUNTER(load_path_is_not_realpath)
enum rb_debug_counter_type {
#define RB_DEBUG_COUNTER(name) RB_DEBUG_COUNTER_##name,
-#include "debug_counter.h"
+#include __FILE__
RB_DEBUG_COUNTER_MAX
#undef RB_DEBUG_COUNTER
};
diff --git a/defs/gmake.mk b/defs/gmake.mk
index b34e8420ba..54fef6685f 100644
--- a/defs/gmake.mk
+++ b/defs/gmake.mk
@@ -1,19 +1,20 @@
# -*- mode: makefile-gmake; indent-tabs-mode: t -*-
reconfig config.status: export MAKE:=$(MAKE)
-export BASERUBY:=$(BASERUBY)
override gnumake_recursive := $(if $(findstring n,$(firstword $(MFLAGS))),,+)
override mflags := $(filter-out -j%,$(MFLAGS))
MSPECOPT += $(if $(filter -j%,$(MFLAGS)),-j)
nproc = $(subst -j,,$(filter -j%,$(MFLAGS)))
ifeq ($(GITHUB_ACTIONS),true)
-# 93(bright yellow) is copied from .github/workflows/mingw.yml
-override ACTIONS_GROUP = @echo "::group::$(@:yes-%=%)"
-override ACTIONS_ENDGROUP = @echo "::endgroup::"
+override ACTIONS_GROUP = @echo "\#\#[group]$(patsubst yes-%,%,$@)"
+override ACTIONS_ENDGROUP = @echo "\#\#[endgroup]"
endif
ifneq ($(filter darwin%,$(target_os)),)
+# Remove debug option not to generate thousands of .dSYM
+MJIT_DEBUGFLAGS := $(filter-out -g%,$(MJIT_DEBUGFLAGS))
+
INSTRUBY_ENV += SDKROOT=
endif
INSTRUBY_ARGS += --gnumake
@@ -25,7 +26,7 @@ TEST_TARGETS := $(filter $(CHECK_TARGETS),$(MAKECMDGOALS))
TEST_DEPENDS := $(filter-out commit $(TEST_TARGETS),$(MAKECMDGOALS))
TEST_TARGETS := $(patsubst great,exam,$(TEST_TARGETS))
TEST_DEPENDS := $(filter-out great $(TEST_TARGETS),$(TEST_DEPENDS))
-TEST_TARGETS := $(patsubst exam,test-bundled-gems test-bundler-parallel check,$(TEST_TARGETS))
+TEST_TARGETS := $(patsubst exam,check,$(TEST_TARGETS))
TEST_TARGETS := $(patsubst check,test-syntax-suggest test-spec test-all test-tool test-short,$(TEST_TARGETS))
TEST_TARGETS := $(patsubst test-rubyspec,test-spec,$(TEST_TARGETS))
TEST_DEPENDS := $(filter-out exam check test-spec $(TEST_TARGETS),$(TEST_DEPENDS))
@@ -36,15 +37,12 @@ TEST_DEPENDS := $(filter-out test-all $(TEST_TARGETS),$(TEST_DEPENDS))
TEST_TARGETS := $(patsubst test,test-short,$(TEST_TARGETS))
TEST_DEPENDS := $(filter-out test $(TEST_TARGETS),$(TEST_DEPENDS))
TEST_TARGETS := $(patsubst test-short,btest-ruby test-knownbug test-basic,$(TEST_TARGETS))
-TEST_TARGETS := $(patsubst test-basic,test-basic test-leaked-globals,$(TEST_TARGETS))
-TEST_TARGETS := $(patsubst test-bundled-gems,test-bundled-gems-spec test-bundled-gems-run,$(TEST_TARGETS))
+TEST_TARGETS := $(patsubst test-bundled-gems,test-bundled-gems-run,$(TEST_TARGETS))
TEST_TARGETS := $(patsubst test-bundled-gems-run,test-bundled-gems-run $(PREPARE_BUNDLED_GEMS),$(TEST_TARGETS))
TEST_TARGETS := $(patsubst test-bundled-gems-prepare,test-bundled-gems-prepare $(PRECHECK_BUNDLED_GEMS) test-bundled-gems-fetch,$(TEST_TARGETS))
-TEST_TARGETS := $(patsubst test-bundler-parallel,test-bundler-parallel $(PREPARE_BUNDLER),$(TEST_TARGETS))
TEST_TARGETS := $(patsubst test-syntax-suggest,test-syntax-suggest $(PREPARE_SYNTAX_SUGGEST),$(TEST_TARGETS))
TEST_DEPENDS := $(filter-out test-short $(TEST_TARGETS),$(TEST_DEPENDS))
TEST_DEPENDS += $(if $(filter great exam love check,$(MAKECMDGOALS)),all exts)
-TEST_TARGETS := $(patsubst yes-%,%,$(filter-out no-%,$(TEST_TARGETS)))
endif
in-srcdir := $(if $(filter-out .,$(srcdir)),$(CHDIR) $(srcdir) &&)
@@ -57,13 +55,6 @@ ifeq ($(if $(filter all main exts enc trans libencs libenc libtrans \
-include $(SHOWFLAGS)
endif
-ifeq ($(HAVE_BASERUBY):$(HAVE_GIT),yes:yes)
-override modified := $(shell $(BASERUBY) -C $(srcdir) tool/file2lastrev.rb --modified='%Y %m %d')
-override RUBY_RELEASE_YEAR := $(word 1,$(modified))
-override RUBY_RELEASE_MONTH := $(word 2,$(modified))
-override RUBY_RELEASE_DAY := $(word 3,$(modified))
-endif
-
ifneq ($(filter universal-%,$(arch)),)
define archcmd
%.$(1).S: %.c
@@ -79,7 +70,7 @@ define archcmd
%.i: %.$(1).i
endef
-$(foreach arch,$(filter -arch=%,$(subst -arch ,-arch=,$(ARCH_FLAG))),\
+$(foreach arch,$(arch_flags),\
$(eval $(call archcmd,$(patsubst -arch=%,%,$(value arch)),$(patsubst -arch=%,-arch %,$(value arch)))))
endif
@@ -91,32 +82,16 @@ $(addprefix yes-,$(TEST_TARGETS)): $(TEST_DEPENDS)
endif
ORDERED_TEST_TARGETS := $(filter $(TEST_TARGETS), \
- btest-ruby test-knownbug test-leaked-globals test-basic \
+ btest-ruby test-knownbug test-basic \
test-testframework test-tool test-ruby test-all \
test-spec test-syntax-suggest-prepare test-syntax-suggest \
test-bundler-prepare test-bundler test-bundler-parallel \
test-bundled-gems-precheck test-bundled-gems-fetch \
test-bundled-gems-prepare test-bundled-gems-run \
- test-bundled-gems-spec \
)
-
-# grep ^yes-test-.*-precheck: template/Makefile.in defs/gmake.mk common.mk
-test_prechecks := $(filter $(ORDERED_TEST_TARGETS),\
- test-leaked-globals \
- test-all \
- test-spec \
- test-syntax-suggest \
- test-bundler \
- test-bundler-parallel \
- test-bundled-gems\
- )
-prev_test := $(subst test-bundler-parallel,test-bundler,$(test_prechecks))
-prev_test := $(addsuffix -precheck,$(prev_test))
-first_test_prechecks := $(prev_test)
-
+prev_test := $(if $(filter test-spec,$(ORDERED_TEST_TARGETS)),test-spec-precheck)
$(foreach test,$(ORDERED_TEST_TARGETS), \
- $(eval yes-$(value test): $(addprefix yes-,$(value prev_test))); \
- $(eval no-$(value test): $(addprefix no-,$(value prev_test))); \
+ $(eval yes-$(value test) no-$(value test): $(value prev_test)); \
$(eval prev_test := $(value test)))
endif
@@ -194,22 +169,15 @@ $(SCRIPTBINDIR):
$(Q) mkdir $@
.PHONY: commit
-COMMIT_PREPARE := $(subst :,\:,$(filter-out commit do-commit,$(MAKECMDGOALS))) up
-
-commit: pre-commit $(DOT_WAIT) do-commit $(DOT_WAIT) post_commit
-pre-commit: $(COMMIT_PREPARE)
-do-commit: $(if $(DOT_WAIT),,pre-commit)
+commit: $(if $(filter commit,$(MAKECMDGOALS)),$(filter-out commit,$(MAKECMDGOALS))) up
@$(BASERUBY) -C "$(srcdir)" -I./tool/lib -rvcs -e 'VCS.detect(".").commit'
-post-commit: $(if $(DOT_WAIT),,do-commit)
+$(Q) \
{ \
$(in-srcdir) \
exec sed -f tool/prereq.status defs/gmake.mk template/Makefile.in common.mk; \
} | \
- $(MAKE) $(mflags) Q=$(Q) ECHO=$(ECHO) \
- top_srcdir="$(top_srcdir)" srcdir="$(srcdir)" srcs_vpath="" CHDIR="$(CHDIR)" \
- BOOTSTRAPRUBY="$(BOOTSTRAPRUBY)" BOOTSTRAPRUBY_OPT="$(BOOTSTRAPRUBY_OPT)" \
- MINIRUBY="$(BASERUBY)" BASERUBY="$(BASERUBY)" HAVE_BASERUBY="$(HAVE_BASERUBY)" \
+ $(MAKE) $(mflags) Q=$(Q) ECHO=$(ECHO) srcdir="$(srcdir)" srcs_vpath="" CHDIR="$(CHDIR)" \
+ BOOTSTRAPRUBY="$(BOOTSTRAPRUBY)" MINIRUBY="$(BASERUBY)" BASERUBY="$(BASERUBY)" \
VCSUP="" ENC_MK=.top-enc.mk REVISION_FORCE=PHONY CONFIGURE="$(CONFIGURE)" -f - \
update-src srcs all-incs
@@ -300,7 +268,6 @@ HELP_EXTRA_TASKS = \
" checkout-github: checkout GitHub Pull Request [PR=1234]" \
" pull-github: rebase GitHub Pull Request to new worktree [PR=1234]" \
" update-github: merge master branch and push it to Pull Request [PR=1234]" \
- " tags: generate TAGS file" \
""
# 1. squeeze spaces
@@ -325,13 +292,12 @@ foreach-bundled-gems-rev = \
foreach-bundled-gems-rev-0 = \
$(call $(1),$(word 1,$(2)),$(word 2,$(2)),$(word 3,$(2)),$(word 4,$(2)))
bundled-gem-gemfile = $(srcdir)/gems/$(1)-$(2).gem
-bundled-gem-gemspec = $(srcdir)/gems/src/$(1)/$(1).gemspec
+bundled-gem-srcdir = $(srcdir)/gems/src/$(1)
bundled-gem-extracted = $(srcdir)/.bundle/gems/$(1)-$(2)
-bundled-gem-revision = $(srcdir)/.bundle/.timestamp/$(1).revision
update-gems: | $(patsubst %,$(srcdir)/gems/%.gem,$(bundled-gems))
update-gems: | $(call foreach-bundled-gems-rev,bundled-gem-gemfile)
-update-gems: | $(call foreach-bundled-gems-rev,bundled-gem-gemspec)
+update-gems: | $(call foreach-bundled-gems-rev,bundled-gem-srcdir)
test-bundler-precheck: | $(srcdir)/.bundle/cache
@@ -359,44 +325,27 @@ $(srcdir)/.bundle/gems/%: $(srcdir)/gems/%.gem | .bundle/gems
-Itool/lib -rbundled_gem \
-e 'BundledGem.unpack("gems/$(@F).gem", ".bundle")'
-$(srcdir)/.bundle/.timestamp:
- $(MAKEDIRS) $@
-
-define build-gem
-$(srcdir)/gems/src/$(1)/.git: | $(srcdir)/gems/src
+define copy-gem
+$(srcdir)/gems/src/$(1): | $(srcdir)/gems/src
$(ECHO) Cloning $(4)
- $(Q) $(GIT) clone $(4) $$(@D)
+ $(Q) $(GIT) clone $(4) $$(@)
-$(bundled-gem-revision): \
- $(if $(if $(wildcard $$(@)),$(filter $(3),$(shell cat $$(@)))),,PHONY) \
- | $(srcdir)/.bundle/.timestamp $(srcdir)/gems/src/$(1)/.git
- $(ECHO) Update $(1) to $(3)
+$(srcdir)/.bundle/gems/$(1)-$(2): | $(srcdir)/gems/src/$(1) .bundle/gems
+ $(ECHO) Copying $(1)@$(3) to $$(@F)
$(Q) $(CHDIR) "$(srcdir)/gems/src/$(1)" && \
- if [ `$(GIT) rev-parse HEAD` != $(3) ]; then \
- $(GIT) fetch origin $(3) && \
- $(GIT) checkout --detach $(3) && \
- :; \
- fi
- echo $(3) | $(IFCHANGE) $$(@) -
-
-# The repository of minitest does not include minitest.gemspec because it uses hoe.
-# This creates a dummy gemspec.
-$(bundled-gem-gemspec): $(bundled-gem-revision) \
- | $(srcdir)/gems/src/$(1)/.git
- $(Q) $(BASERUBY) -I$(tooldir)/lib -rbundled_gem -e 'BundledGem.dummy_gemspec(*ARGV)' $$(@)
-
-$(bundled-gem-gemfile): $(bundled-gem-gemspec) $(bundled-gem-revision)
- $(ECHO) Building $(1)@$(3) to $$(@)
+ $(GIT) fetch origin $(3) && \
+ $(GIT) checkout --detach $(3) && \
+ :
$(Q) $(BASERUBY) -C "$(srcdir)" \
-Itool/lib -rbundled_gem \
- -e 'BundledGem.build("gems/src/$(1)/$(1).gemspec", "$(2)", "gems", validation: false)'
+ -e 'BundledGem.copy("gems/src/$(1)/$(1).gemspec", ".bundle")'
endef
-define build-gem-0
-$(eval $(call build-gem,$(1),$(2),$(3),$(4)))
+define copy-gem-0
+$(eval $(call copy-gem,$(1),$(2),$(3),$(4)))
endef
-$(call foreach-bundled-gems-rev,build-gem-0)
+$(call foreach-bundled-gems-rev,copy-gem-0)
$(srcdir)/gems/src:
$(MAKEDIRS) $@
@@ -404,36 +353,49 @@ $(srcdir)/gems/src:
$(srcdir)/.bundle/gems:
$(MAKEDIRS) $@
-ifneq ($(DOT_WAIT),)
-up:: $(DOT_WAIT) after-update
-endif
-
ifneq ($(filter update-bundled_gems refresh-gems,$(MAKECMDGOALS)),)
update-gems: update-bundled_gems
endif
+ifeq ($(filter 0 1,$(words $(arch_flags))),)
+$(foreach x,$(patsubst -arch=%,%,$(arch_flags)), \
+ $(eval $$(MJIT_HEADER:.h=)-$(value x).h \
+ $$(MJIT_MIN_HEADER:.h=)-$(value x).h \
+ $$(TIMESTAMPDIR)/$$(MJIT_HEADER:.h=)-$(value x).time \
+ : ARCH_FLAG := -arch $(value x)))
+
+$(foreach x,$(patsubst -arch=%,%,$(arch_flags)), \
+ $(eval $$(MJIT_HEADER:.h=)-$(value x).h: \
+ $$(TIMESTAMPDIR)/$$(MJIT_HEADER:.h=)-$(value x).time))
+
+mjit_min_headers := $(patsubst -arch=%,$(MJIT_MIN_HEADER:.h=-%.h),$(arch_flags))
+$(MJIT_MIN_HEADER): $(mjit_min_headers) $(PREP)
+ @ set -e; set $(patsubst -arch=%,%,$(arch_flags)); \
+ cd $(@D); h=$(@F:.h=); \
+ exec > $(@F).new; \
+ echo '#if 0'; \
+ for arch; do\
+ echo "#elif defined __$${arch}__"; \
+ echo "# include \"$$h-$$arch.h\""; \
+ done; \
+ echo "#else"; echo "# error unsupported platform"; echo "#endif"
+ $(IFCHANGE) $@ $@.new
+ $(Q) $(MAKEDIRS) $(MJIT_HEADER_INSTALL_DIR)
+ $(Q) $(MAKE_LINK) $@ $(MJIT_HEADER_INSTALL_DIR)/$(@F)
+
+endif
+
.SECONDARY: update-unicode-files
.SECONDARY: update-unicode-auxiliary-files
.SECONDARY: update-unicode-ucd-emoji-files
.SECONDARY: update-unicode-emoji-files
-ifneq ($(DOT_WAIT),)
-.NOTPARALLEL: update-unicode
-.NOTPARALLEL: update-unicode-files
-.NOTPARALLEL: update-unicode-auxiliary-files
-.NOTPARALLEL: update-unicode-ucd-emoji-files
-.NOTPARALLEL: update-unicode-emoji-files
-.NOTPARALLEL: $(UNICODE_FILES) $(UNICODE_PROPERTY_FILES)
-.NOTPARALLEL: $(UNICODE_AUXILIARY_FILES)
-.NOTPARALLEL: $(UNICODE_UCD_EMOJI_FILES) $(UNICODE_EMOJI_FILES)
-endif
-
ifeq ($(HAVE_GIT),yes)
REVISION_LATEST := $(shell $(CHDIR) $(srcdir) && $(GIT) log -1 --format=%H 2>/dev/null)
else
REVISION_LATEST := update
endif
-REVISION_IN_HEADER := $(shell sed '/^\#define RUBY_FULL_REVISION "\(.*\)"/!d;s//\1/;q' $(wildcard $(srcdir)/revision.h revision.h) /dev/null 2>/dev/null)
+REVISION_IN_HEADER := $(shell sed -n 's/^\#define RUBY_FULL_REVISION "\(.*\)"/\1/p' $(wildcard $(srcdir)/revision.h revision.h) /dev/null 2>/dev/null)
ifeq ($(REVISION_IN_HEADER),)
REVISION_IN_HEADER := none
endif
@@ -470,10 +432,6 @@ benchmark/%: miniruby$(EXEEXT) update-benchmark-driver PHONY
--executables="built-ruby::$(BENCH_RUBY) --disable-gem" \
$(srcdir)/$@ $(BENCH_OPTS) $(OPTS)
-clean-local:: TARGET_SO = $(PROGRAM) $(WPROGRAM) $(LIBRUBY_SO) $(STATIC_RUBY) miniruby goruby
-clean-local::
- -$(Q)$(RMALL) $(cleanlibs)
-
clean-srcs-ext::
$(Q)$(RM) $(patsubst $(srcdir)/%,%,$(EXT_SRCS))
@@ -508,18 +466,13 @@ update-deps:
$(RUBYSPEC_CAPIEXT)/%.$(DLEXT): $(srcdir)/$(RUBYSPEC_CAPIEXT)/%.c $(srcdir)/$(RUBYSPEC_CAPIEXT)/rubyspec.h $(RUBY_H_INCLUDES) $(LIBRUBY)
$(ECHO) building $@
$(Q) $(MAKEDIRS) $(@D)
- $(Q) $(DLDSHARED) -L. $(XDLDFLAGS) $(XLDFLAGS) $(LDFLAGS) $(INCFLAGS) $(CPPFLAGS) $(OUTFLAG)$@ $< $(LIBRUBYARG)
-ifneq ($(POSTLINK),)
- $(Q) $(POSTLINK)
-endif
+ $(Q) $(DLDSHARED) $(XDLDFLAGS) $(XLDFLAGS) $(LDFLAGS) $(INCFLAGS) $(CPPFLAGS) $(OUTFLAG)$@ $< $(LIBRUBYARG)
$(Q) $(RMALL) $@.*
-RUBYSPEC_CAPIEXT_SO := $(patsubst %.c,$(RUBYSPEC_CAPIEXT)/%.$(DLEXT),$(notdir $(wildcard $(srcdir)/$(RUBYSPEC_CAPIEXT)/*.c)))
-rubyspec-capiext: $(RUBYSPEC_CAPIEXT_SO)
+rubyspec-capiext: $(patsubst %.c,$(RUBYSPEC_CAPIEXT)/%.$(DLEXT),$(notdir $(wildcard $(srcdir)/$(RUBYSPEC_CAPIEXT)/*.c)))
@ $(NULLCMD)
ifeq ($(ENABLE_SHARED),yes)
-ruby: $(if $(LIBRUBY_SO_UPDATE),$(RUBYSPEC_CAPIEXT_SO))
exts: rubyspec-capiext
endif
@@ -527,44 +480,3 @@ spec/%/ spec/%_spec.rb: programs exts PHONY
+$(RUNRUBY) -r./$(arch)-fake $(srcdir)/spec/mspec/bin/mspec-run -B $(srcdir)/spec/default.mspec $(SPECOPTS) $(patsubst %,$(srcdir)/%,$@)
ruby.pc: $(filter-out ruby.pc,$(ruby_pc))
-
-matz: up
- $(eval OLD := $(MAJOR).$(MINOR).0)
- $(eval MINOR := $(shell expr $(MINOR) + 1))
- $(eval NEW := $(MAJOR).$(MINOR).0)
- $(eval message := Development of $(NEW) started.)
- $(eval files := include/ruby/version.h include/ruby/internal/abi.h)
- $(GIT) -C $(srcdir) mv -f NEWS.md doc/NEWS/NEWS-$(OLD).md
- $(GIT) -C $(srcdir) commit -m "[DOC] Flush NEWS.md"
- sed -i~ \
- -e "s/^\(#define RUBY_API_VERSION_MINOR\) .*/\1 $(MINOR)/" \
- -e "s/^\(#define RUBY_ABI_VERSION\) .*/\1 0/" \
- $(files:%=$(srcdir)/%)
- $(GIT) -C $(srcdir) add $(files)
- $(BASERUBY) -C $(srcdir) -p -00 \
- -e 'BEGIN {old, new = ARGV.shift(2); STDOUT.reopen("NEWS.md")}' \
- -e 'case $$.' \
- -e 'when 1; $$_.sub!(/Ruby \K[0-9.]+/, new)' \
- -e 'when 2; $$_.sub!(/\*\*\K[0-9.]+(?=\*\*)/, old)' \
- -e 'end' \
- -e 'next if /^[\[ *]/ =~ $$_' \
- -e '$$_.sub!(/\n{2,}\z/, "\n\n")' \
- $(OLD) $(NEW) doc/NEWS/NEWS-$(OLD).md
- $(GIT) -C $(srcdir) add NEWS.md
- $(GIT) -C $(srcdir) commit -m "$(message)"
-
-tags:
- $(MAKE) GIT="$(GIT)" -C "$(srcdir)" -f defs/tags.mk
-
-
-# ripper_srcs makes all sources at once. invoking this target multiple
-# times in parallel means all sources will be built for the number of
-# sources times respectively.
-ifneq ($(DOT_WAIT),)
-.NOTPARALLEL: ripper_srcs
-else
-ripper_src =
-$(foreach r,$(RIPPER_SRCS),$(eval $(value r): | $(value ripper_src))\
- $(eval ripper_src := $(value r)))
-ripper_srcs: $(ripper_src)
-endif
diff --git a/defs/id.def b/defs/id.def
index 73dd7840e4..ebf00506ea 100644
--- a/defs/id.def
+++ b/defs/id.def
@@ -2,7 +2,6 @@
firstline, predefined = __LINE__+1, %[\
max
min
- hash
freeze
nil?
inspect
@@ -26,6 +25,7 @@ firstline, predefined = __LINE__+1, %[\
lambda
send
__send__
+ __attached__
__recursive_key__
initialize
initialize_copy
@@ -59,8 +59,6 @@ firstline, predefined = __LINE__+1, %[\
name
nil
path
- pack
- buffer
_ UScore
diff --git a/defs/known_errors.def b/defs/known_errors.def
index 23e9e53507..e9694cfbda 100644
--- a/defs/known_errors.def
+++ b/defs/known_errors.def
@@ -1,157 +1,157 @@
-E2BIG Argument list too long
-EACCES Permission denied
-EADDRINUSE Address already in use
-EADDRNOTAVAIL Address not available
-EADV Advertise error
-EAFNOSUPPORT Address family not supported
-EAGAIN Resource temporarily unavailable, try again (may be the same value as EWOULDBLOCK)
-EALREADY Connection already in progress
-EAUTH Authentication error
-EBADARCH Bad CPU type in executable
-EBADE Bad exchange
-EBADEXEC Bad executable
-EBADF Bad file descriptor
-EBADFD File descriptor in bad state
-EBADMACHO Malformed Macho file
-EBADMSG Bad message
-EBADR Invalid request descriptor
-EBADRPC RPC struct is bad
-EBADRQC Invalid request code
-EBADSLT Invalid slot
-EBFONT Bad font file format
-EBUSY Device or resource busy
-ECANCELED Operation canceled
-ECAPMODE Not permitted in capability mode
-ECHILD No child processes
-ECHRNG Channel number out of range
-ECOMM Communication error on send
-ECONNABORTED Connection aborted
-ECONNREFUSED Connection refused
-ECONNRESET Connection reset
-EDEADLK Resource deadlock avoided
-EDEADLOCK File locking deadlock error
-EDESTADDRREQ Destination address required
-EDEVERR Device error; e.g., printer paper out
-EDOM Mathematics argument out of domain of function
-EDOOFUS Improper function use
-EDOTDOT RFS specific error
-EDQUOT Disk quota exceeded
-EEXIST File exists
-EFAULT Bad address
-EFBIG File too large
-EFTYPE Invalid file type or format
-EHOSTDOWN Host is down
-EHOSTUNREACH Host is unreachable
-EHWPOISON Memory page has hardware error
-EIDRM Identifier removed
-EILSEQ Invalid or incomplete multibyte or wide character
-EINPROGRESS Operation in progress
-EINTR Interrupted function call
-EINVAL Invalid argument
-EIO Input/output error
-EIPSEC IPsec processing failure
-EISCONN Socket is connected
-EISDIR Is a directory
-EISNAM Is a named file type
-EKEYEXPIRED Key has expired
-EKEYREJECTED Key was rejected by service
-EKEYREVOKED Key has been revoked
-EL2HLT Level 2 halted
-EL2NSYNC Level 2 not synchronized
-EL3HLT Level 3 halted
-EL3RST Level 3 reset
-ELIBACC Cannot access a needed shared library
-ELIBBAD Accessing a corrupted shared library
-ELIBEXEC Cannot exec a shared library directly
-ELIBMAX Attempting to link in too many shared libraries
-ELIBSCN .lib section in a.out corrupted
-ELNRNG Link number out of range
-ELOOP Too many levels of symbolic links
-EMEDIUMTYPE Wrong medium type
-EMFILE Too many open files
-EMLINK Too many links
-EMSGSIZE Message too long
-EMULTIHOP Multihop attempted
-ENAMETOOLONG Filename too long
-ENAVAIL No XENIX semaphores available
-ENEEDAUTH Need authenticator
-ENETDOWN Network is down
-ENETRESET Connection aborted by network
-ENETUNREACH Network unreachable
-ENFILE Too many open files in system
-ENOANO No anode
-ENOATTR Attribute not found
-ENOBUFS No buffer space available
-ENOCSI No CSI structure available
-ENODATA No data available
-ENODEV No such device
-ENOENT No such file or directory
-ENOEXEC Exec format error
-ENOKEY Required key not available
-ENOLCK No locks available
-ENOLINK Link has been severed
-ENOMEDIUM No medium found
-ENOMEM Not enough space/cannot allocate memory
-ENOMSG No message of the desired type
-ENONET Machine is not on the network
-ENOPKG Package not installed
-ENOPOLICY No such policy
-ENOPROTOOPT Protocol not available
-ENOSPC No space left on device
-ENOSR No STREAM resources
-ENOSTR Not a STREAM
-ENOSYS Functionality not implemented
-ENOTBLK Block device required
-ENOTCAPABLE Capabilities insufficient
-ENOTCONN The socket is not connected
-ENOTDIR Not a directory
-ENOTEMPTY Directory not empty
-ENOTNAM Not a XENIX named type file
-ENOTRECOVERABLE State not recoverable
-ENOTSOCK Not a socket
-ENOTSUP Operation not supported
-ENOTTY Inappropriate I/O control operation
-ENOTUNIQ Name not unique on network
-ENXIO No such device or address
-EOPNOTSUPP Operation not supported on socket
-EOVERFLOW Value too large to be stored in data type
-EOWNERDEAD Owner died
-EPERM Operation not permitted
-EPFNOSUPPORT Protocol family not supported
-EPIPE Broken pipe
-EPROCLIM Too many processes
-EPROCUNAVAIL Bad procedure for program
-EPROGMISMATCH Program version wrong
-EPROGUNAVAIL RPC program isn't available
-EPROTO Protocol error
-EPROTONOSUPPORT Protocol not supported
-EPROTOTYPE Protocol wrong type for socket
-EPWROFF Device power is off
-EQFULL Interface output queue is full
-ERANGE Result too large
-EREMCHG Remote address changed
-EREMOTE Object is remote
-EREMOTEIO Remote I/O error
-ERESTART Interrupted system call should be restarted
-ERFKILL Operation not possible due to RF-kill
-EROFS Read-only file system
-ERPCMISMATCH RPC version wrong
-ESHLIBVERS Shared library version mismatch
-ESHUTDOWN Cannot send after transport endpoint shutdown
-ESOCKTNOSUPPORT Socket type not supported
-ESPIPE Illegal seek
-ESRCH No such process
-ESRMNT Server mount error
-ESTALE Stale file handle
-ESTRPIPE Streams pipe error
-ETIME Timer expired
-ETIMEDOUT Connection timed out
-ETOOMANYREFS Too many references: cannot splice
-ETXTBSY Text file busy
-EUCLEAN Structure needs cleaning
-EUNATCH Protocol driver not attached
-EUSERS Too many users
-EWOULDBLOCK Operation would block
-EXDEV Invalid cross-device link
-EXFULL Exchange full
-ELAST Largest errno value
+E2BIG
+EACCES
+EADDRINUSE
+EADDRNOTAVAIL
+EADV
+EAFNOSUPPORT
+EAGAIN
+EALREADY
+EAUTH
+EBADARCH
+EBADE
+EBADEXEC
+EBADF
+EBADFD
+EBADMACHO
+EBADMSG
+EBADR
+EBADRPC
+EBADRQC
+EBADSLT
+EBFONT
+EBUSY
+ECANCELED
+ECAPMODE
+ECHILD
+ECHRNG
+ECOMM
+ECONNABORTED
+ECONNREFUSED
+ECONNRESET
+EDEADLK
+EDEADLOCK
+EDESTADDRREQ
+EDEVERR
+EDOM
+EDOOFUS
+EDOTDOT
+EDQUOT
+EEXIST
+EFAULT
+EFBIG
+EFTYPE
+EHOSTDOWN
+EHOSTUNREACH
+EHWPOISON
+EIDRM
+EILSEQ
+EINPROGRESS
+EINTR
+EINVAL
+EIO
+EIPSEC
+EISCONN
+EISDIR
+EISNAM
+EKEYEXPIRED
+EKEYREJECTED
+EKEYREVOKED
+EL2HLT
+EL2NSYNC
+EL3HLT
+EL3RST
+ELAST
+ELIBACC
+ELIBBAD
+ELIBEXEC
+ELIBMAX
+ELIBSCN
+ELNRNG
+ELOOP
+EMEDIUMTYPE
+EMFILE
+EMLINK
+EMSGSIZE
+EMULTIHOP
+ENAMETOOLONG
+ENAVAIL
+ENEEDAUTH
+ENETDOWN
+ENETRESET
+ENETUNREACH
+ENFILE
+ENOANO
+ENOATTR
+ENOBUFS
+ENOCSI
+ENODATA
+ENODEV
+ENOENT
+ENOEXEC
+ENOKEY
+ENOLCK
+ENOLINK
+ENOMEDIUM
+ENOMEM
+ENOMSG
+ENONET
+ENOPKG
+ENOPOLICY
+ENOPROTOOPT
+ENOSPC
+ENOSR
+ENOSTR
+ENOSYS
+ENOTBLK
+ENOTCAPABLE
+ENOTCONN
+ENOTDIR
+ENOTEMPTY
+ENOTNAM
+ENOTRECOVERABLE
+ENOTSOCK
+ENOTSUP
+ENOTTY
+ENOTUNIQ
+ENXIO
+EOPNOTSUPP
+EOVERFLOW
+EOWNERDEAD
+EPERM
+EPFNOSUPPORT
+EPIPE
+EPROCLIM
+EPROCUNAVAIL
+EPROGMISMATCH
+EPROGUNAVAIL
+EPROTO
+EPROTONOSUPPORT
+EPROTOTYPE
+EPWROFF
+EQFULL
+ERANGE
+EREMCHG
+EREMOTE
+EREMOTEIO
+ERESTART
+ERFKILL
+EROFS
+ERPCMISMATCH
+ESHLIBVERS
+ESHUTDOWN
+ESOCKTNOSUPPORT
+ESPIPE
+ESRCH
+ESRMNT
+ESTALE
+ESTRPIPE
+ETIME
+ETIMEDOUT
+ETOOMANYREFS
+ETXTBSY
+EUCLEAN
+EUNATCH
+EUSERS
+EWOULDBLOCK
+EXDEV
+EXFULL
diff --git a/defs/tags.mk b/defs/tags.mk
deleted file mode 100644
index d29260c294..0000000000
--- a/defs/tags.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-# -*- mode: makefile-gmake; indent-tabs-mode: t -*-
-
-SRCS := $(shell $(GIT) ls-files \
- *.[chy] *.def *.inc *.rb \
- ccan/ coroutine/ include/ internal/ missing/ \
- 'enc/**/*.[ch]' 'win32/**/*.[ch]' \
- )
-
-TAGS: $(SRCS)
- @echo updating $@
- @tmp=$$(mktemp); \
- trap 'rm -f "$$tmp"' 0; \
- { \
- $(GIT) grep -h --no-line-number -o '^ *# *define *RBIMPL_ATTR_[A-Z_]*(*' -- include | \
- sed 's/^ *# *define *//;/_H$$/d;y/(/+/' | sort -u && \
- echo 'NORETURN+'; \
- } > "$$tmp" && \
- ctags -e -I@"$$tmp" -h .def.inc --langmap=c:+.y.def.inc $(^)
diff --git a/defs/universal.mk b/defs/universal.mk
new file mode 100644
index 0000000000..c34a31b356
--- /dev/null
+++ b/defs/universal.mk
@@ -0,0 +1,5 @@
+arch_flags := $(filter -arch=%,$(subst -arch ,-arch=,$(ARCH_FLAG)))
+ifeq ($(filter 0 1,$(words $(arch_flags))),)
+override MJIT_HEADER_SUFFIX = -%
+override MJIT_HEADER_ARCH = -$(word 2,$(ARCH_FLAG))
+endif
diff --git a/dir.c b/dir.c
index 24eec8dc15..3f73f83fc5 100644
--- a/dir.c
+++ b/dir.c
@@ -113,7 +113,6 @@ char *strchr(char*,char);
#include "internal/gc.h"
#include "internal/io.h"
#include "internal/object.h"
-#include "internal/imemo.h"
#include "internal/vm.h"
#include "ruby/encoding.h"
#include "ruby/ruby.h"
@@ -143,50 +142,6 @@ char *strchr(char*,char);
# define IS_WIN32 0
#endif
-#ifdef HAVE_GETATTRLIST
-struct getattrlist_args {
- const char *path;
- int fd;
- struct attrlist *list;
- void *buf;
- size_t size;
- unsigned int options;
-};
-
-# define GETATTRLIST_ARGS(list_, buf_, options_) (struct getattrlist_args) \
- {.list = list_, .buf = buf_, .size = sizeof(buf_), .options = options_}
-
-static void *
-nogvl_getattrlist(void *args)
-{
- struct getattrlist_args *arg = args;
- return (void *)(VALUE)getattrlist(arg->path, arg->list, arg->buf, arg->size, arg->options);
-}
-
-static int
-gvl_getattrlist(struct getattrlist_args *args, const char *path)
-{
- args->path = path;
- return IO_WITHOUT_GVL_INT(nogvl_getattrlist, args);
-}
-
-# ifdef HAVE_FGETATTRLIST
-static void *
-nogvl_fgetattrlist(void *args)
-{
- struct getattrlist_args *arg = args;
- return (void *)(VALUE)fgetattrlist(arg->fd, arg->list, arg->buf, arg->size, arg->options);
-}
-
-static int
-gvl_fgetattrlist(struct getattrlist_args *args, int fd)
-{
- args->fd = fd;
- return IO_WITHOUT_GVL_INT(nogvl_fgetattrlist, args);
-}
-# endif
-#endif
-
#if NORMALIZE_UTF8PATH
# if defined HAVE_FGETATTRLIST || !defined HAVE_GETATTRLIST
# define need_normalization(dirp, path) need_normalization(dirp)
@@ -199,11 +154,10 @@ need_normalization(DIR *dirp, const char *path)
# if defined HAVE_FGETATTRLIST || defined HAVE_GETATTRLIST
u_int32_t attrbuf[SIZEUP32(fsobj_tag_t)];
struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_OBJTAG,};
- struct getattrlist_args args = GETATTRLIST_ARGS(&al, attrbuf, 0);
# if defined HAVE_FGETATTRLIST
- int ret = gvl_fgetattrlist(&args, dirfd(dirp));
+ int ret = fgetattrlist(dirfd(dirp), &al, attrbuf, sizeof(attrbuf), 0);
# else
- int ret = gvl_getattrlist(&args, path);
+ int ret = getattrlist(path, &al, attrbuf, sizeof(attrbuf), 0);
# endif
if (!ret) {
const fsobj_tag_t *tag = (void *)(attrbuf+1);
@@ -512,26 +466,31 @@ struct dir_data {
};
static void
+dir_mark(void *ptr)
+{
+ struct dir_data *dir = ptr;
+ rb_gc_mark(dir->path);
+}
+
+static void
dir_free(void *ptr)
{
struct dir_data *dir = ptr;
if (dir->dir) closedir(dir->dir);
+ xfree(dir);
}
-RUBY_REFERENCES(dir_refs) = {
- RUBY_REF_EDGE(struct dir_data, path),
- RUBY_REF_END
-};
+static size_t
+dir_memsize(const void *ptr)
+{
+ return sizeof(struct dir_data);
+}
static const rb_data_type_t dir_data_type = {
"dir",
- {
- RUBY_REFS_LIST_PTR(dir_refs),
- dir_free,
- NULL, // Nothing allocated externally, so don't need a memsize function
- },
- 0, NULL, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
+ {dir_mark, dir_free, dir_memsize,},
+ 0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
};
static VALUE dir_close(VALUE);
@@ -554,7 +513,7 @@ nogvl_opendir(void *ptr)
{
const char *path = ptr;
- return opendir(path);
+ return (void *)opendir(path);
}
static DIR *
@@ -565,31 +524,12 @@ opendir_without_gvl(const char *path)
u.in = path;
- return IO_WITHOUT_GVL(nogvl_opendir, u.out);
+ return rb_thread_call_without_gvl(nogvl_opendir, u.out, RUBY_UBF_IO, 0);
}
else
return opendir(path);
}
-static void
-close_dir_data(struct dir_data *dp)
-{
- if (dp->dir) {
- if (closedir(dp->dir) < 0) {
- dp->dir = NULL;
- rb_sys_fail("closedir");
- }
- dp->dir = NULL;
- }
-}
-
-static void
-check_closedir(DIR *dirp)
-{
- if (closedir(dirp) < 0)
- rb_sys_fail("closedir");
-}
-
static VALUE
dir_initialize(rb_execution_context_t *ec, VALUE dir, VALUE dirname, VALUE enc)
{
@@ -604,7 +544,8 @@ dir_initialize(rb_execution_context_t *ec, VALUE dir, VALUE dirname, VALUE enc)
dirname = rb_str_dup_frozen(dirname);
TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dp);
- close_dir_data(dp);
+ if (dp->dir) closedir(dp->dir);
+ dp->dir = NULL;
RB_OBJ_WRITE(dir, &dp->path, Qnil);
dp->enc = fsenc;
path = RSTRING_PTR(dirname);
@@ -618,8 +559,7 @@ dir_initialize(rb_execution_context_t *ec, VALUE dir, VALUE dirname, VALUE enc)
else if (e == EIO) {
u_int32_t attrbuf[1];
struct attrlist al = {ATTR_BIT_MAP_COUNT, 0};
- struct getattrlist_args args = GETATTRLIST_ARGS(&al, attrbuf, FSOPT_NOFOLLOW);
- if (gvl_getattrlist(&args, path) == 0) {
+ if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW) == 0) {
dp->dir = opendir_without_gvl(path);
}
}
@@ -651,51 +591,6 @@ dir_s_close(rb_execution_context_t *ec, VALUE klass, VALUE dir)
return dir_close(dir);
}
-# if defined(HAVE_FDOPENDIR) && defined(HAVE_DIRFD)
-static void *
-nogvl_fdopendir(void *fd)
-{
- return fdopendir((int)(VALUE)fd);
-}
-
-/*
- * call-seq:
- * Dir.for_fd(fd) -> dir
- *
- * Returns a new \Dir object representing the directory specified by the given
- * integer directory file descriptor +fd+:
- *
- * d0 = Dir.new('..')
- * d1 = Dir.for_fd(d0.fileno)
- *
- * Note that the returned +d1+ does not have an associated path:
- *
- * d0.path # => '..'
- * d1.path # => nil
- *
- * This method uses the
- * {fdopendir()}[https://www.man7.org/linux/man-pages/man3/fdopendir.3p.html]
- * function defined by POSIX 2008;
- * the method is not implemented on non-POSIX platforms (raises NotImplementedError).
- */
-static VALUE
-dir_s_for_fd(VALUE klass, VALUE fd)
-{
- struct dir_data *dp;
- VALUE dir = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dp);
-
- if (!(dp->dir = IO_WITHOUT_GVL(nogvl_fdopendir, (void *)(VALUE)NUM2INT(fd)))) {
- rb_sys_fail("fdopendir");
- UNREACHABLE_RETURN(Qnil);
- }
-
- RB_OBJ_WRITE(dir, &dp->path, Qnil);
- return dir;
-}
-#else
-#define dir_s_for_fd rb_f_notimplement
-#endif
-
NORETURN(static void dir_closed(void));
static void
@@ -723,13 +618,10 @@ dir_check(VALUE dir)
/*
- * call-seq:
- * inspect -> string
- *
- * Returns a string description of +self+:
- *
- * Dir.new('example').inspect # => "#<Dir:example>"
+ * call-seq:
+ * dir.inspect -> string
*
+ * Return a string describing this Dir object.
*/
static VALUE
dir_inspect(VALUE dir)
@@ -763,18 +655,18 @@ dir_inspect(VALUE dir)
#ifdef HAVE_DIRFD
/*
- * call-seq:
- * fileno -> integer
+ * call-seq:
+ * dir.fileno -> integer
*
- * Returns the file descriptor used in <em>dir</em>.
+ * Returns the file descriptor used in <em>dir</em>.
*
- * d = Dir.new('..')
- * d.fileno # => 8
+ * d = Dir.new("..")
+ * d.fileno #=> 8
+ *
+ * This method uses dirfd() function defined by POSIX 2008.
+ * NotImplementedError is raised on other platforms, such as Windows,
+ * which doesn't provide the function.
*
- * This method uses the
- * {dirfd()}[https://www.man7.org/linux/man-pages/man3/dirfd.3.html]
- * function defined by POSIX 2008;
- * the method is not implemented on non-POSIX platforms (raises NotImplementedError).
*/
static VALUE
dir_fileno(VALUE dir)
@@ -793,14 +685,14 @@ dir_fileno(VALUE dir)
#endif
/*
- * call-seq:
- * path -> string or nil
- *
- * Returns the +dirpath+ string that was used to create +self+
- * (or +nil+ if created by method Dir.for_fd):
+ * call-seq:
+ * dir.path -> string or nil
+ * dir.to_path -> string or nil
*
- * Dir.new('example').path # => "example"
+ * Returns the path parameter passed to <em>dir</em>'s constructor.
*
+ * d = Dir.new("..")
+ * d.path #=> ".."
*/
static VALUE
dir_path(VALUE dir)
@@ -826,28 +718,8 @@ fundamental_encoding_p(rb_encoding *enc)
}
}
# define READDIR(dir, enc) rb_w32_readdir((dir), (enc))
-# define READDIR_NOGVL READDIR
#else
-NORETURN(static void *sys_failure(void *function));
-static void *
-sys_failure(void *function)
-{
- rb_sys_fail(function);
-}
-
-static void *
-nogvl_readdir(void *dir)
-{
- rb_errno_set(0);
- if ((dir = readdir(dir)) == NULL) {
- if (rb_errno())
- rb_thread_call_with_gvl(sys_failure, (void *)"readdir");
- }
- return dir;
-}
-
-# define READDIR(dir, enc) IO_WITHOUT_GVL(nogvl_readdir, (void *)(dir))
-# define READDIR_NOGVL(dir, enc) nogvl_readdir((dir))
+# define READDIR(dir, enc) readdir((dir))
#endif
/* safe to use without GVL */
@@ -874,18 +746,16 @@ to_be_skipped(const struct dirent *dp)
}
/*
- * call-seq:
- * read -> string or nil
- *
- * Reads and returns the next entry name from +self+;
- * returns +nil+ if at end-of-stream;
- * see {Dir As Stream-Like}[rdoc-ref:Dir@Dir+As+Stream-Like]:
+ * call-seq:
+ * dir.read -> string or nil
*
- * dir = Dir.new('example')
- * dir.read # => "."
- * dir.read # => ".."
- * dir.read # => "config.h"
+ * Reads the next entry from <em>dir</em> and returns it as a string.
+ * Returns <code>nil</code> at the end of the stream.
*
+ * d = Dir.new("testdir")
+ * d.read #=> "."
+ * d.read #=> ".."
+ * d.read #=> "config.h"
*/
static VALUE
dir_read(VALUE dir)
@@ -894,7 +764,7 @@ dir_read(VALUE dir)
struct dirent *dp;
GetDIR(dir, dirp);
- rb_errno_set(0);
+ errno = 0;
if ((dp = READDIR(dirp->dir, dirp->enc)) != NULL) {
return rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc);
}
@@ -914,23 +784,24 @@ dir_yield(VALUE arg, VALUE path)
}
/*
- * call-seq:
- * each {|entry_name| ... } -> self
+ * call-seq:
+ * dir.each { |filename| block } -> dir
+ * dir.each -> an_enumerator
*
- * Calls the block with each entry name in +self+:
+ * Calls the block once for each entry in this directory, passing the
+ * filename of each entry as a parameter to the block.
*
- * Dir.new('example').each {|entry_name| p entry_name }
+ * If no block is given, an enumerator is returned instead.
*
- * Output:
-
- * "."
- * ".."
- * "config.h"
- * "lib"
- * "main.rb"
+ * d = Dir.new("testdir")
+ * d.each {|x| puts "Got #{x}" }
*
- * With no block given, returns an Enumerator.
+ * <em>produces:</em>
*
+ * Got .
+ * Got ..
+ * Got config.h
+ * Got main.rb
*/
static VALUE
dir_each(VALUE dir)
@@ -973,17 +844,16 @@ dir_each_entry(VALUE dir, VALUE (*each)(VALUE, VALUE), VALUE arg, int children_o
#ifdef HAVE_TELLDIR
/*
- * call-seq:
- * tell -> integer
- *
- * Returns the current position of +self+;
- * see {Dir As Stream-Like}[rdoc-ref:Dir@Dir+As+Stream-Like]:
+ * call-seq:
+ * dir.pos -> integer
+ * dir.tell -> integer
*
- * dir = Dir.new('example')
- * dir.tell # => 0
- * dir.read # => "."
- * dir.tell # => 1
+ * Returns the current position in <em>dir</em>. See also Dir#seek.
*
+ * d = Dir.new("testdir")
+ * d.tell #=> 0
+ * d.read #=> "."
+ * d.tell #=> 12
*/
static VALUE
dir_tell(VALUE dir)
@@ -992,8 +862,7 @@ dir_tell(VALUE dir)
long pos;
GetDIR(dir, dirp);
- if((pos = telldir(dirp->dir)) < 0)
- rb_sys_fail("telldir");
+ pos = telldir(dirp->dir);
return rb_int2inum(pos);
}
#else
@@ -1002,24 +871,18 @@ dir_tell(VALUE dir)
#ifdef HAVE_SEEKDIR
/*
- * call-seq:
- * seek(position) -> self
- *
- * Sets the position in +self+ and returns +self+.
- * The value of +position+ should have been returned from an earlier call to #tell;
- * if not, the return values from subsequent calls to #read are unspecified.
- *
- * See {Dir As Stream-Like}[rdoc-ref:Dir@Dir+As+Stream-Like].
- *
- * Examples:
- *
- * dir = Dir.new('example')
- * dir.pos # => 0
- * dir.seek(3) # => #<Dir:example>
- * dir.pos # => 3
- * dir.seek(30) # => #<Dir:example>
- * dir.pos # => 5
- *
+ * call-seq:
+ * dir.seek( integer ) -> dir
+ *
+ * Seeks to a particular location in <em>dir</em>. <i>integer</i>
+ * must be a value returned by Dir#tell.
+ *
+ * d = Dir.new("testdir") #=> #<Dir:0x401b3c40>
+ * d.read #=> "."
+ * i = d.tell #=> 12
+ * d.read #=> ".."
+ * d.seek(i) #=> #<Dir:0x401b3c40>
+ * d.read #=> ".."
*/
static VALUE
dir_seek(VALUE dir, VALUE pos)
@@ -1037,24 +900,17 @@ dir_seek(VALUE dir, VALUE pos)
#ifdef HAVE_SEEKDIR
/*
- * call-seq:
- * pos = position -> integer
- *
- * Sets the position in +self+ and returns +position+.
- * The value of +position+ should have been returned from an earlier call to #tell;
- * if not, the return values from subsequent calls to #read are unspecified.
- *
- * See {Dir As Stream-Like}[rdoc-ref:Dir@Dir+As+Stream-Like].
+ * call-seq:
+ * dir.pos = integer -> integer
*
- * Examples:
- *
- * dir = Dir.new('example')
- * dir.pos # => 0
- * dir.pos = 3 # => 3
- * dir.pos # => 3
- * dir.pos = 30 # => 30
- * dir.pos # => 5
+ * Synonym for Dir#seek, but returns the position parameter.
*
+ * d = Dir.new("testdir") #=> #<Dir:0x401b3c40>
+ * d.read #=> "."
+ * i = d.pos #=> 12
+ * d.read #=> ".."
+ * d.pos = i #=> 12
+ * d.read #=> ".."
*/
static VALUE
dir_set_pos(VALUE dir, VALUE pos)
@@ -1067,19 +923,15 @@ dir_set_pos(VALUE dir, VALUE pos)
#endif
/*
- * call-seq:
- * rewind -> self
- *
- * Sets the position in +self+ to zero;
- * see {Dir As Stream-Like}[rdoc-ref:Dir@Dir+As+Stream-Like]:
+ * call-seq:
+ * dir.rewind -> dir
*
- * dir = Dir.new('example')
- * dir.read # => "."
- * dir.read # => ".."
- * dir.pos # => 2
- * dir.rewind # => #<Dir:example>
- * dir.pos # => 0
+ * Repositions <em>dir</em> to the first entry.
*
+ * d = Dir.new("testdir")
+ * d.read #=> "."
+ * d.rewind #=> #<Dir:0x401b3fb0>
+ * d.read #=> "."
*/
static VALUE
dir_rewind(VALUE dir)
@@ -1092,18 +944,14 @@ dir_rewind(VALUE dir)
}
/*
- * call-seq:
- * close -> nil
- *
- * Closes the stream in +self+, if it is open, and returns +nil+;
- * ignored if +self+ is already closed:
+ * call-seq:
+ * dir.close -> nil
*
- * dir = Dir.new('example')
- * dir.read # => "."
- * dir.close # => nil
- * dir.close # => nil
- * dir.read # Raises IOError.
+ * Closes the directory stream.
+ * Calling this method on closed Dir object is ignored since Ruby 2.3.
*
+ * d = Dir.new("testdir")
+ * d.close #=> nil
*/
static VALUE
dir_close(VALUE dir)
@@ -1112,7 +960,8 @@ dir_close(VALUE dir)
dirp = dir_get(dir);
if (!dirp->dir) return Qnil;
- close_dir_data(dirp);
+ closedir(dirp->dir);
+ dirp->dir = NULL;
return Qnil;
}
@@ -1126,80 +975,30 @@ nogvl_chdir(void *ptr)
}
static void
-dir_chdir0(VALUE path)
+dir_chdir(VALUE path)
{
- if (IO_WITHOUT_GVL_INT(nogvl_chdir, (void*)RSTRING_PTR(path)) < 0)
+ if (chdir(RSTRING_PTR(path)) < 0)
rb_sys_fail_path(path);
}
-static struct {
- VALUE thread;
- VALUE path;
- int line;
- int blocking;
-} chdir_lock = {
- .blocking = 0, .thread = Qnil,
- .path = Qnil, .line = 0,
-};
-
-static void
-chdir_enter(void)
-{
- if (chdir_lock.blocking == 0) {
- chdir_lock.path = rb_source_location(&chdir_lock.line);
- }
- chdir_lock.blocking++;
- if (NIL_P(chdir_lock.thread)) {
- chdir_lock.thread = rb_thread_current();
- }
-}
-
-static void
-chdir_leave(void)
-{
- chdir_lock.blocking--;
- if (chdir_lock.blocking == 0) {
- chdir_lock.thread = Qnil;
- chdir_lock.path = Qnil;
- chdir_lock.line = 0;
- }
-}
-
-static int
-chdir_alone_block_p(void)
-{
- int block_given = rb_block_given_p();
- if (chdir_lock.blocking > 0) {
- if (rb_thread_current() != chdir_lock.thread)
- rb_raise(rb_eRuntimeError, "conflicting chdir during another chdir block");
- if (!block_given) {
- if (!NIL_P(chdir_lock.path)) {
- rb_warn("conflicting chdir during another chdir block\n"
- "%" PRIsVALUE ":%d: note: previous chdir was here",
- chdir_lock.path, chdir_lock.line);
- }
- else {
- rb_warn("conflicting chdir during another chdir block");
- }
- }
- }
- return block_given;
-}
+static int chdir_blocking = 0;
+static VALUE chdir_thread = Qnil;
struct chdir_data {
VALUE old_path, new_path;
int done;
- bool yield_path;
};
static VALUE
chdir_yield(VALUE v)
{
struct chdir_data *args = (void *)v;
- dir_chdir0(args->new_path);
+ dir_chdir(args->new_path);
args->done = TRUE;
- chdir_enter();
- return args->yield_path ? rb_yield(args->new_path) : rb_yield_values2(0, NULL);
+ chdir_blocking++;
+ if (NIL_P(chdir_thread))
+ chdir_thread = rb_thread_current();
+ return rb_yield(args->new_path);
}
static VALUE
@@ -1207,96 +1006,53 @@ chdir_restore(VALUE v)
{
struct chdir_data *args = (void *)v;
if (args->done) {
- chdir_leave();
- dir_chdir0(args->old_path);
+ chdir_blocking--;
+ if (chdir_blocking == 0)
+ chdir_thread = Qnil;
+ dir_chdir(args->old_path);
}
return Qnil;
}
-static VALUE
-chdir_path(VALUE path, bool yield_path)
-{
- if (chdir_alone_block_p()) {
- struct chdir_data args;
-
- args.old_path = rb_str_encode_ospath(rb_dir_getwd());
- args.new_path = path;
- args.done = FALSE;
- args.yield_path = yield_path;
- return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
- }
- else {
- char *p = RSTRING_PTR(path);
- int r = IO_WITHOUT_GVL_INT(nogvl_chdir, p);
- if (r < 0)
- rb_sys_fail_path(path);
- }
-
- return INT2FIX(0);
-}
-
/*
- * call-seq:
- * Dir.chdir(new_dirpath) -> 0
- * Dir.chdir -> 0
- * Dir.chdir(new_dirpath) {|new_dirpath| ... } -> object
- * Dir.chdir {|cur_dirpath| ... } -> object
- *
- * Changes the current working directory.
- *
- * With argument +new_dirpath+ and no block,
- * changes to the given +dirpath+:
- *
- * Dir.pwd # => "/example"
- * Dir.chdir('..') # => 0
- * Dir.pwd # => "/"
- *
- * With no argument and no block:
- *
- * - Changes to the value of environment variable +HOME+ if defined.
- * - Otherwise changes to the value of environment variable +LOGDIR+ if defined.
- * - Otherwise makes no change.
- *
- * With argument +new_dirpath+ and a block, temporarily changes the working directory:
- *
- * - Calls the block with the argument.
- * - Changes to the given directory.
- * - Executes the block (yielding the new path).
- * - Restores the previous working directory.
- * - Returns the block's return value.
- *
- * Example:
- *
- * Dir.chdir('/var/spool/mail')
- * Dir.pwd # => "/var/spool/mail"
- * Dir.chdir('/tmp') do
- * Dir.pwd # => "/tmp"
- * end
- * Dir.pwd # => "/var/spool/mail"
- *
- * With no argument and a block,
- * calls the block with the current working directory (string)
- * and returns the block's return value.
- *
- * Calls to \Dir.chdir with blocks may be nested:
- *
- * Dir.chdir('/var/spool/mail')
- * Dir.pwd # => "/var/spool/mail"
- * Dir.chdir('/tmp') do
- * Dir.pwd # => "/tmp"
- * Dir.chdir('/usr') do
- * Dir.pwd # => "/usr"
+ * call-seq:
+ * Dir.chdir( [ string] ) -> 0
+ * Dir.chdir( [ string] ) {| path | block } -> anObject
+ *
+ * Changes the current working directory of the process to the given
+ * string. When called without an argument, changes the directory to
+ * the value of the environment variable <code>HOME</code>, or
+ * <code>LOGDIR</code>. SystemCallError (probably Errno::ENOENT) if
+ * the target directory does not exist.
+ *
+ * If a block is given, it is passed the name of the new current
+ * directory, and the block is executed with that as the current
+ * directory. The original working directory is restored when the block
+ * exits. The return value of <code>chdir</code> is the value of the
+ * block. <code>chdir</code> blocks can be nested, but in a
+ * multi-threaded program an error will be raised if a thread attempts
+ * to open a <code>chdir</code> block while another thread has one
+ * open or a call to <code>chdir</code> without a block occurs inside
+ * a block passed to <code>chdir</code> (even in the same thread).
+ *
+ * Dir.chdir("/var/spool/mail")
+ * puts Dir.pwd
+ * Dir.chdir("/tmp") do
+ * puts Dir.pwd
+ * Dir.chdir("/usr") do
+ * puts Dir.pwd
+ * end
+ * puts Dir.pwd
* end
- * Dir.pwd # => "/tmp"
- * end
- * Dir.pwd # => "/var/spool/mail"
+ * puts Dir.pwd
*
- * In a multi-threaded program an error is raised if a thread attempts
- * to open a +chdir+ block while another thread has one open,
- * or a call to +chdir+ without a block occurs inside
- * a block passed to +chdir+ (even in the same thread).
+ * <em>produces:</em>
*
- * Raises an exception if the target directory does not exist.
+ * /var/spool/mail
+ * /tmp
+ * /usr
+ * /tmp
+ * /var/spool/mail
*/
static VALUE
dir_s_chdir(int argc, VALUE *argv, VALUE obj)
@@ -1315,162 +1071,31 @@ dir_s_chdir(int argc, VALUE *argv, VALUE obj)
path = rb_str_new2(dist);
}
- return chdir_path(path, true);
-}
-
-#if defined(HAVE_FCHDIR) && defined(HAVE_DIRFD) && HAVE_FCHDIR && HAVE_DIRFD
-static void *
-nogvl_fchdir(void *ptr)
-{
- const int *fd = ptr;
-
- return (void *)(VALUE)fchdir(*fd);
-}
-
-static void
-dir_fchdir(int fd)
-{
- if (IO_WITHOUT_GVL_INT(nogvl_fchdir, (void *)&fd) < 0)
- rb_sys_fail("fchdir");
-}
-
-struct fchdir_data {
- VALUE old_dir;
- int fd;
- int done;
-};
-
-static VALUE
-fchdir_yield(VALUE v)
-{
- struct fchdir_data *args = (void *)v;
- dir_fchdir(args->fd);
- args->done = TRUE;
- chdir_enter();
- return rb_yield_values(0);
-}
-
-static VALUE
-fchdir_restore(VALUE v)
-{
- struct fchdir_data *args = (void *)v;
- if (args->done) {
- chdir_leave();
- dir_fchdir(RB_NUM2INT(dir_fileno(args->old_dir)));
+ if (chdir_blocking > 0) {
+ if (rb_thread_current() != chdir_thread)
+ rb_raise(rb_eRuntimeError, "conflicting chdir during another chdir block");
+ if (!rb_block_given_p())
+ rb_warn("conflicting chdir during another chdir block");
}
- dir_close(args->old_dir);
- return Qnil;
-}
-/*
- * call-seq:
- * Dir.fchdir(fd) -> 0
- * Dir.fchdir(fd) { ... } -> object
- *
- * Changes the current working directory to the directory
- * specified by the integer file descriptor +fd+.
- *
- * When passing a file descriptor over a UNIX socket or to a child process,
- * using +fchdir+ instead of +chdir+ avoids the
- * {time-of-check to time-of-use vulnerability}[https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use]
- *
- * With no block, changes to the directory given by +fd+:
- *
- * Dir.chdir('/var/spool/mail')
- * Dir.pwd # => "/var/spool/mail"
- * dir = Dir.new('/usr')
- * fd = dir.fileno
- * Dir.fchdir(fd)
- * Dir.pwd # => "/usr"
- *
- * With a block, temporarily changes the working directory:
- *
- * - Calls the block with the argument.
- * - Changes to the given directory.
- * - Executes the block (yields no args).
- * - Restores the previous working directory.
- * - Returns the block's return value.
- *
- * Example:
- *
- * Dir.chdir('/var/spool/mail')
- * Dir.pwd # => "/var/spool/mail"
- * dir = Dir.new('/tmp')
- * fd = dir.fileno
- * Dir.fchdir(fd) do
- * Dir.pwd # => "/tmp"
- * end
- * Dir.pwd # => "/var/spool/mail"
- *
- * This method uses the
- * {fchdir()}[https://www.man7.org/linux/man-pages/man3/fchdir.3p.html]
- * function defined by POSIX 2008;
- * the method is not implemented on non-POSIX platforms (raises NotImplementedError).
- *
- * Raises an exception if the file descriptor is not valid.
- *
- * In a multi-threaded program an error is raised if a thread attempts
- * to open a +chdir+ block while another thread has one open,
- * or a call to +chdir+ without a block occurs inside
- * a block passed to +chdir+ (even in the same thread).
- */
-static VALUE
-dir_s_fchdir(VALUE klass, VALUE fd_value)
-{
- int fd = RB_NUM2INT(fd_value);
+ if (rb_block_given_p()) {
+ struct chdir_data args;
- if (chdir_alone_block_p()) {
- struct fchdir_data args;
- args.old_dir = dir_s_alloc(klass);
- dir_initialize(NULL, args.old_dir, rb_fstring_cstr("."), Qnil);
- args.fd = fd;
+ args.old_path = rb_str_encode_ospath(rb_dir_getwd());
+ args.new_path = path;
args.done = FALSE;
- return rb_ensure(fchdir_yield, (VALUE)&args, fchdir_restore, (VALUE)&args);
+ return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
}
else {
- int r = IO_WITHOUT_GVL_INT(nogvl_fchdir, &fd);
+ char *p = RSTRING_PTR(path);
+ int r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_chdir, p,
+ RUBY_UBF_IO, 0);
if (r < 0)
- rb_sys_fail("fchdir");
+ rb_sys_fail_path(path);
}
return INT2FIX(0);
}
-#else
-#define dir_s_fchdir rb_f_notimplement
-#endif
-
-/*
- * call-seq:
- * chdir -> 0
- * chdir { ... } -> object
- *
- * Changes the current working directory to +self+:
- *
- * Dir.pwd # => "/"
- * dir = Dir.new('example')
- * dir.chdir
- * Dir.pwd # => "/example"
- *
- * With a block, temporarily changes the working directory:
- *
- * - Calls the block.
- * - Changes to the given directory.
- * - Executes the block (yields no args).
- * - Restores the previous working directory.
- * - Returns the block's return value.
- *
- * Uses Dir.fchdir if available, and Dir.chdir if not, see those
- * methods for caveats.
- */
-static VALUE
-dir_chdir(VALUE dir)
-{
-#if defined(HAVE_FCHDIR) && defined(HAVE_DIRFD) && HAVE_FCHDIR && HAVE_DIRFD
- return dir_s_fchdir(rb_cDir, dir_fileno(dir));
-#else
- return chdir_path(dir_get(dir)->path, false);
-#endif
-}
#ifndef _WIN32
VALUE
@@ -1480,15 +1105,19 @@ rb_dir_getwd_ospath(void)
VALUE cwd;
VALUE path_guard;
- path_guard = rb_imemo_tmpbuf_auto_free_pointer();
+#undef RUBY_UNTYPED_DATA_WARNING
+#define RUBY_UNTYPED_DATA_WARNING 0
+ path_guard = Data_Wrap_Struct((VALUE)0, NULL, RUBY_DEFAULT_FREE, NULL);
path = ruby_getcwd();
- rb_imemo_tmpbuf_set_ptr(path_guard, path);
+ DATA_PTR(path_guard) = path;
#ifdef __APPLE__
cwd = rb_str_normalize_ospath(path, strlen(path));
#else
cwd = rb_str_new2(path);
#endif
- rb_free_tmp_buffer(&path_guard);
+ DATA_PTR(path_guard) = 0;
+
+ xfree(path);
return cwd;
}
#endif
@@ -1514,14 +1143,16 @@ rb_dir_getwd(void)
}
/*
- * call-seq:
- * Dir.pwd -> string
+ * call-seq:
+ * Dir.getwd -> string
+ * Dir.pwd -> string
*
- * Returns the path to the current working directory:
- *
- * Dir.chdir("/tmp") # => 0
- * Dir.pwd # => "/tmp"
+ * Returns the path to the current working directory of this process as
+ * a string.
*
+ * Dir.chdir("/tmp") #=> 0
+ * Dir.getwd #=> "/tmp"
+ * Dir.pwd #=> "/tmp"
*/
static VALUE
dir_s_getwd(VALUE dir)
@@ -1550,29 +1181,20 @@ check_dirname(VALUE dir)
}
#if defined(HAVE_CHROOT)
-static void *
-nogvl_chroot(void *dirname)
-{
- return (void *)(VALUE)chroot((const char *)dirname);
-}
-
/*
- * call-seq:
- * Dir.chroot(dirpath) -> 0
- *
- * Changes the root directory of the calling process to that specified in +dirpath+.
- * The new root directory is used for pathnames beginning with <tt>'/'</tt>.
- * The root directory is inherited by all children of the calling process.
+ * call-seq:
+ * Dir.chroot( string ) -> 0
*
- * Only a privileged process may call +chroot+.
- *
- * See {Linux chroot}[https://man7.org/linux/man-pages/man2/chroot.2.html].
+ * Changes this process's idea of the file system root. Only a
+ * privileged process may make this call. Not available on all
+ * platforms. On Unix systems, see <code>chroot(2)</code> for more
+ * information.
*/
static VALUE
dir_s_chroot(VALUE dir, VALUE path)
{
path = check_dirname(path);
- if (IO_WITHOUT_GVL_INT(nogvl_chroot, (void *)RSTRING_PTR(path)) == -1)
+ if (chroot(RSTRING_PTR(path)) == -1)
rb_sys_fail_path(path);
return INT2FIX(0);
@@ -1595,20 +1217,18 @@ nogvl_mkdir(void *ptr)
}
/*
- * call-seq:
- * Dir.mkdir(dirpath, permissions = 0775) -> 0
+ * call-seq:
+ * Dir.mkdir( string [, integer] ) -> 0
*
- * Creates a directory in the underlying file system
- * at +dirpath+ with the given +permissions+;
- * returns zero:
+ * Makes a new directory named by <i>string</i>, with permissions
+ * specified by the optional parameter <i>anInteger</i>. The
+ * permissions may be modified by the value of File::umask, and are
+ * ignored on NT. Raises a SystemCallError if the directory cannot be
+ * created. See also the discussion of permissions in the class
+ * documentation for File.
*
- * Dir.mkdir('foo')
- * File.stat(Dir.new('foo')).mode.to_s(8)[1..4] # => "0755"
- * Dir.mkdir('bar', 0644)
- * File.stat(Dir.new('bar')).mode.to_s(8)[1..4] # => "0644"
+ * Dir.mkdir(File.join(Dir.home, ".foo"), 0700) #=> 0
*
- * See {File Permissions}[rdoc-ref:File@File+Permissions].
- * Note that argument +permissions+ is ignored on Windows.
*/
static VALUE
dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
@@ -1626,7 +1246,7 @@ dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
path = check_dirname(path);
m.path = RSTRING_PTR(path);
- r = IO_WITHOUT_GVL_INT(nogvl_mkdir, &m);
+ r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_mkdir, &m, RUBY_UBF_IO, 0);
if (r < 0)
rb_sys_fail_path(path);
@@ -1642,14 +1262,13 @@ nogvl_rmdir(void *ptr)
}
/*
- * call-seq:
- * Dir.rmdir(dirpath) -> 0
- *
- * Removes the directory at +dirpath+ from the underlying file system:
+ * call-seq:
+ * Dir.delete( string ) -> 0
+ * Dir.rmdir( string ) -> 0
+ * Dir.unlink( string ) -> 0
*
- * Dir.rmdir('foo') # => 0
- *
- * Raises an exception if the directory is not empty.
+ * Deletes the named directory. Raises a subclass of SystemCallError
+ * if the directory isn't empty.
*/
static VALUE
dir_s_rmdir(VALUE obj, VALUE dir)
@@ -1659,7 +1278,7 @@ dir_s_rmdir(VALUE obj, VALUE dir)
dir = check_dirname(dir);
p = RSTRING_PTR(dir);
- r = IO_WITHOUT_GVL_INT(nogvl_rmdir, (void *)p);
+ r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_rmdir, (void *)p, RUBY_UBF_IO, 0);
if (r < 0)
rb_sys_fail_path(dir);
@@ -1749,11 +1368,11 @@ to_be_ignored(int e)
}
#ifdef _WIN32
-#define STAT(args) (int)(VALUE)nogvl_stat(&(args))
-#define LSTAT(args) (int)(VALUE)nogvl_lstat(&(args))
+#define STAT(p, s) rb_w32_ustati128((p), (s))
+#undef lstat
+#define lstat(p, s) rb_w32_ulstati128((p), (s))
#else
-#define STAT(args) IO_WITHOUT_GVL_INT(nogvl_stat, (void *)&(args))
-#define LSTAT(args) IO_WITHOUT_GVL_INT(nogvl_lstat, (void *)&(args))
+#define STAT(p, s) stat((p), (s))
#endif
typedef int ruby_glob_errfunc(const char*, VALUE, const void*, int);
@@ -1774,50 +1393,14 @@ at_subpath(int fd, size_t baselen, const char *path)
return *path ? path : ".";
}
-#if USE_OPENDIR_AT
-struct fstatat_args {
- int fd;
- int flag;
- const char *path;
- struct stat *pst;
-};
-
-static void *
-nogvl_fstatat(void *args)
-{
- struct fstatat_args *arg = (struct fstatat_args *)args;
- return (void *)(VALUE)fstatat(arg->fd, arg->path, arg->pst, arg->flag);
-}
-#else
-struct stat_args {
- const char *path;
- struct stat *pst;
-};
-
-static void *
-nogvl_stat(void *args)
-{
- struct stat_args *arg = (struct stat_args *)args;
- return (void *)(VALUE)stat(arg->path, arg->pst);
-}
-#endif
-
/* System call with warning */
static int
do_stat(int fd, size_t baselen, const char *path, struct stat *pst, int flags, rb_encoding *enc)
{
#if USE_OPENDIR_AT
- struct fstatat_args args;
- args.fd = fd;
- args.path = path;
- args.pst = pst;
- args.flag = 0;
- int ret = IO_WITHOUT_GVL_INT(nogvl_fstatat, (void *)&args);
+ int ret = fstatat(fd, at_subpath(fd, baselen, path), pst, 0);
#else
- struct stat_args args;
- args.path = path;
- args.pst = pst;
- int ret = STAT(args);
+ int ret = STAT(path, pst);
#endif
if (ret < 0 && !to_be_ignored(errno))
sys_warning(path, enc);
@@ -1826,30 +1409,13 @@ do_stat(int fd, size_t baselen, const char *path, struct stat *pst, int flags, r
}
#if defined HAVE_LSTAT || defined lstat || USE_OPENDIR_AT
-#if !USE_OPENDIR_AT
-static void *
-nogvl_lstat(void *args)
-{
- struct stat_args *arg = (struct stat_args *)args;
- return (void *)(VALUE)lstat(arg->path, arg->pst);
-}
-#endif
-
static int
do_lstat(int fd, size_t baselen, const char *path, struct stat *pst, int flags, rb_encoding *enc)
{
#if USE_OPENDIR_AT
- struct fstatat_args args;
- args.fd = fd;
- args.path = path;
- args.pst = pst;
- args.flag = AT_SYMLINK_NOFOLLOW;
- int ret = IO_WITHOUT_GVL_INT(nogvl_fstatat, (void *)&args);
+ int ret = fstatat(fd, at_subpath(fd, baselen, path), pst, AT_SYMLINK_NOFOLLOW);
#else
- struct stat_args args;
- args.path = path;
- args.pst = pst;
- int ret = LSTAT(args);
+ int ret = lstat(path, pst);
#endif
if (ret < 0 && !to_be_ignored(errno))
sys_warning(path, enc);
@@ -1910,7 +1476,7 @@ nogvl_opendir_at(void *ptr)
/* fallthrough*/
case 0:
if (fd >= 0) close(fd);
- rb_errno_set(e);
+ errno = e;
}
}
#else /* !USE_OPENDIR_AT */
@@ -1931,7 +1497,7 @@ opendir_at(int basefd, const char *path)
oaa.path = path;
if (vm_initialized)
- return IO_WITHOUT_GVL(nogvl_opendir_at, &oaa);
+ return rb_thread_call_without_gvl(nogvl_opendir_at, &oaa, RUBY_UBF_IO, 0);
else
return nogvl_opendir_at(&oaa);
}
@@ -2210,15 +1776,14 @@ is_case_sensitive(DIR *dirp, const char *path)
const vol_capabilities_attr_t *const cap = attrbuf[0].cap;
const int idx = VOL_CAPABILITIES_FORMAT;
const uint32_t mask = VOL_CAP_FMT_CASE_SENSITIVE;
- struct getattrlist_args args = GETATTRLIST_ARGS(&al, attrbuf, FSOPT_NOFOLLOW);
+
# if defined HAVE_FGETATTRLIST
- int ret = gvl_fgetattrlist(&args, dirfd(dirp));
+ if (fgetattrlist(dirfd(dirp), &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW))
+ return -1;
# else
- int ret = gvl_getattrlist(&args, path);
-# endif
- if (ret)
+ if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW))
return -1;
-
+# endif
if (!(cap->valid[idx] & mask))
return -1;
return (cap->capabilities[idx] & mask) != 0;
@@ -2241,8 +1806,7 @@ replace_real_basename(char *path, long base, rb_encoding *enc, int norm_p, int f
IF_NORMALIZE_UTF8PATH(VALUE utf8str = Qnil);
*type = path_noent;
- struct getattrlist_args args = GETATTRLIST_ARGS(&al, attrbuf, FSOPT_NOFOLLOW);
- if (gvl_getattrlist(&args, path)) {
+ if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), FSOPT_NOFOLLOW)) {
if (!to_be_ignored(errno))
sys_warning(path, enc);
return path;
@@ -2615,7 +2179,7 @@ static void
glob_dir_finish(ruby_glob_entries_t *ent, int flags)
{
if (flags & FNM_GLOB_NOSORT) {
- check_closedir(ent->nosort.dirp);
+ closedir(ent->nosort.dirp);
ent->nosort.dirp = NULL;
}
else if (ent->sort.entries) {
@@ -2646,7 +2210,7 @@ glob_opendir(ruby_glob_entries_t *ent, DIR *dirp, int flags, rb_encoding *enc)
#ifdef _WIN32
if ((capacity = dirp->nfiles) > 0) {
if (!(newp = GLOB_ALLOC_N(rb_dirent_t, capacity))) {
- check_closedir(dirp);
+ closedir(dirp);
return NULL;
}
ent->sort.entries = newp;
@@ -2666,7 +2230,7 @@ glob_opendir(ruby_glob_entries_t *ent, DIR *dirp, int flags, rb_encoding *enc)
ent->sort.entries[count++] = rdp;
ent->sort.count = count;
}
- check_closedir(dirp);
+ closedir(dirp);
if (count < capacity) {
if (!(newp = GLOB_REALLOC_N(ent->sort.entries, count))) {
glob_dir_finish(ent, 0);
@@ -2681,7 +2245,7 @@ glob_opendir(ruby_glob_entries_t *ent, DIR *dirp, int flags, rb_encoding *enc)
nomem:
glob_dir_finish(ent, 0);
- check_closedir(dirp);
+ closedir(dirp);
return NULL;
}
@@ -2844,7 +2408,7 @@ glob_helper(
# if NORMALIZE_UTF8PATH
if (!(norm_p || magical || recursive)) {
- check_closedir(dirp);
+ closedir(dirp);
goto literally;
}
# endif
@@ -3305,7 +2869,7 @@ push_glob(VALUE ary, VALUE str, VALUE base, int flags)
fd = AT_FDCWD;
if (!NIL_P(base)) {
if (!RB_TYPE_P(base, T_STRING) || !rb_enc_check(str, base)) {
- struct dir_data *dirp = RTYPEDDATA_GET_DATA(base);
+ struct dir_data *dirp = DATA_PTR(base);
if (!dirp->dir) dir_closed();
#ifdef HAVE_DIRFD
if ((fd = dirfd(dirp->dir)) == -1)
@@ -3429,35 +2993,26 @@ dir_open_dir(int argc, VALUE *argv)
/*
- * call-seq:
- * Dir.foreach(dirpath, encoding: 'UTF-8') {|entry_name| ... } -> nil
- *
- * Calls the block with each entry name in the directory at +dirpath+;
- * sets the given encoding onto each passed +entry_name+:
- *
- * Dir.foreach('/example') {|entry_name| p entry_name }
+ * call-seq:
+ * Dir.foreach( dirname ) {| filename | block } -> nil
+ * Dir.foreach( dirname, encoding: enc ) {| filename | block } -> nil
+ * Dir.foreach( dirname ) -> an_enumerator
+ * Dir.foreach( dirname, encoding: enc ) -> an_enumerator
*
- * Output:
+ * Calls the block once for each entry in the named directory, passing
+ * the filename of each entry as a parameter to the block.
*
- * "config.h"
- * "lib"
- * "main.rb"
- * ".."
- * "."
+ * If no block is given, an enumerator is returned instead.
*
- * Encoding:
+ * Dir.foreach("testdir") {|x| puts "Got #{x}" }
*
- * Dir.foreach('/example') {|entry_name| p entry_name.encoding; break }
- * Dir.foreach('/example', encoding: 'US-ASCII') {|entry_name| p entry_name.encoding; break }
+ * <em>produces:</em>
*
- * Output:
+ * Got .
+ * Got ..
+ * Got config.h
+ * Got main.rb
*
- * #<Encoding:UTF-8>
- * #<Encoding:US-ASCII>
- *
- * See {String Encoding}[rdoc-ref:encodings.rdoc@String+Encoding].
- *
- * Returns an enumerator if no block is given.
*/
static VALUE
dir_foreach(int argc, VALUE *argv, VALUE io)
@@ -3479,21 +3034,19 @@ dir_collect(VALUE dir)
}
/*
- * call-seq:
- * Dir.entries(dirname, encoding: 'UTF-8') -> array
+ * call-seq:
+ * Dir.entries( dirname ) -> array
+ * Dir.entries( dirname, encoding: enc ) -> array
*
- * Returns an array of the entry names in the directory at +dirpath+;
- * sets the given encoding onto each returned entry name:
+ * Returns an array containing all of the filenames in the given
+ * directory. Will raise a SystemCallError if the named directory
+ * doesn't exist.
*
- * Dir.entries('/example') # => ["config.h", "lib", "main.rb", "..", "."]
- * Dir.entries('/example').first.encoding
- * # => #<Encoding:UTF-8>
- * Dir.entries('/example', encoding: 'US-ASCII').first.encoding
- * # => #<Encoding:US-ASCII>
+ * The optional <i>encoding</i> keyword argument specifies the encoding of the
+ * directory. If not specified, the filesystem encoding is used.
*
- * See {String Encoding}[rdoc-ref:encodings.rdoc@String+Encoding].
+ * Dir.entries("testdir") #=> [".", "..", "config.h", "main.rb"]
*
- * Raises an exception if the directory does not exist.
*/
static VALUE
dir_entries(int argc, VALUE *argv, VALUE io)
@@ -3511,12 +3064,25 @@ dir_each_child(VALUE dir)
}
/*
- * call-seq:
- * Dir.each_child(dirpath) {|entry_name| ... } -> nil
- * Dir.each_child(dirpath, encoding: 'UTF-8') {|entry_name| ... } -> nil
+ * call-seq:
+ * Dir.each_child( dirname ) {| filename | block } -> nil
+ * Dir.each_child( dirname, encoding: enc ) {| filename | block } -> nil
+ * Dir.each_child( dirname ) -> an_enumerator
+ * Dir.each_child( dirname, encoding: enc ) -> an_enumerator
+ *
+ * Calls the block once for each entry except for "." and ".." in the
+ * named directory, passing the filename of each entry as a parameter
+ * to the block.
+ *
+ * If no block is given, an enumerator is returned instead.
+ *
+ * Dir.each_child("testdir") {|x| puts "Got #{x}" }
+ *
+ * <em>produces:</em>
+ *
+ * Got config.h
+ * Got main.rb
*
- * Like Dir.foreach, except that entries <tt>'.'</tt> and <tt>'..'</tt>
- * are not included.
*/
static VALUE
dir_s_each_child(int argc, VALUE *argv, VALUE io)
@@ -3530,22 +3096,24 @@ dir_s_each_child(int argc, VALUE *argv, VALUE io)
}
/*
- * call-seq:
- * each_child {|entry_name| ... } -> self
+ * call-seq:
+ * dir.each_child {| filename | block } -> dir
+ * dir.each_child -> an_enumerator
+ *
+ * Calls the block once for each entry except for "." and ".." in
+ * this directory, passing the filename of each entry as a parameter
+ * to the block.
*
- * Calls the block with each entry name in +self+
- * except <tt>'.'</tt> and <tt>'..'</tt>:
+ * If no block is given, an enumerator is returned instead.
*
- * dir = Dir.new('/example')
- * dir.each_child {|entry_name| p entry_name }
+ * d = Dir.new("testdir")
+ * d.each_child {|x| puts "Got #{x}" }
*
- * Output:
+ * <em>produces:</em>
*
- * "config.h"
- * "lib"
- * "main.rb"
+ * Got config.h
+ * Got main.rb
*
- * If no block is given, returns an enumerator.
*/
static VALUE
dir_each_child_m(VALUE dir)
@@ -3555,14 +3123,14 @@ dir_each_child_m(VALUE dir)
}
/*
- * call-seq:
- * children -> array
+ * call-seq:
+ * dir.children -> array
*
- * Returns an array of the entry names in +self+
- * except for <tt>'.'</tt> and <tt>'..'</tt>:
+ * Returns an array containing all of the filenames except for "."
+ * and ".." in this directory.
*
- * dir = Dir.new('/example')
- * dir.children # => ["config.h", "lib", "main.rb"]
+ * d = Dir.new("testdir")
+ * d.children #=> ["config.h", "main.rb"]
*
*/
static VALUE
@@ -3574,23 +3142,19 @@ dir_collect_children(VALUE dir)
}
/*
- * call-seq:
- * Dir.children(dirpath) -> array
- * Dir.children(dirpath, encoding: 'UTF-8') -> array
+ * call-seq:
+ * Dir.children( dirname ) -> array
+ * Dir.children( dirname, encoding: enc ) -> array
*
- * Returns an array of the entry names in the directory at +dirpath+
- * except for <tt>'.'</tt> and <tt>'..'</tt>;
- * sets the given encoding onto each returned entry name:
+ * Returns an array containing all of the filenames except for "."
+ * and ".." in the given directory. Will raise a SystemCallError if
+ * the named directory doesn't exist.
*
- * Dir.children('/example') # => ["config.h", "lib", "main.rb"]
- * Dir.children('/example').first.encoding
- * # => #<Encoding:UTF-8>
- * Dir.children('/example', encoding: 'US-ASCII').first.encoding
- * # => #<Encoding:US-ASCII>
+ * The optional <i>encoding</i> keyword argument specifies the encoding of the
+ * directory. If not specified, the filesystem encoding is used.
*
- * See {String Encoding}[rdoc-ref:encodings.rdoc@String+Encoding].
+ * Dir.children("testdir") #=> ["config.h", "main.rb"]
*
- * Raises an exception if the directory does not exist.
*/
static VALUE
dir_s_children(int argc, VALUE *argv, VALUE io)
@@ -3664,16 +3228,12 @@ file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
}
/*
- * call-seq:
- * Dir.home(user_name = nil) -> dirpath
+ * call-seq:
+ * Dir.home() -> "/home/me"
+ * Dir.home("root") -> "/root"
*
- * Returns the home directory path of the user specified with +user_name+
- * if it is not +nil+, or the current login user:
- *
- * Dir.home # => "/home/me"
- * Dir.home('root') # => "/root"
- *
- * Raises ArgumentError if +user_name+ is not a user name.
+ * Returns the home directory of the current user or the named user
+ * if given.
*/
static VALUE
dir_s_home(int argc, VALUE *argv, VALUE obj)
@@ -3684,7 +3244,7 @@ dir_s_home(int argc, VALUE *argv, VALUE obj)
rb_check_arity(argc, 0, 1);
user = (argc > 0) ? argv[0] : Qnil;
if (!NIL_P(user)) {
- StringValue(user);
+ SafeStringValue(user);
rb_must_asciicompat(user);
u = StringValueCStr(user);
if (*u) {
@@ -3698,15 +3258,10 @@ dir_s_home(int argc, VALUE *argv, VALUE obj)
#if 0
/*
* call-seq:
- * Dir.exist?(dirpath) -> true or false
- *
- * Returns whether +dirpath+ is a directory in the underlying file system:
- *
- * Dir.exist?('/example') # => true
- * Dir.exist?('/nosuch') # => false
- * Dir.exist?('/example/main.rb') # => false
+ * Dir.exist?(file_name) -> true or false
*
- * Same as File.directory?.
+ * Returns <code>true</code> if the named file is a directory,
+ * <code>false</code> otherwise.
*
*/
VALUE
@@ -3733,33 +3288,26 @@ nogvl_dir_empty_p(void *ptr)
/* fall through */
case 0:
if (e == ENOTDIR) return (void *)Qfalse;
- return (void *)INT2FIX(e);
+ errno = e; /* for rb_sys_fail_path */
+ return (void *)Qundef;
}
}
- while ((dp = READDIR_NOGVL(dir, NULL)) != NULL) {
+ while ((dp = READDIR(dir, NULL)) != NULL) {
if (!to_be_skipped(dp)) {
result = Qfalse;
break;
}
}
- check_closedir(dir);
+ closedir(dir);
return (void *)result;
}
/*
* call-seq:
- * Dir.empty?(dirpath) -> true or false
+ * Dir.empty?(path_name) -> true or false
*
- * Returns whether +dirpath+ specifies an empty directory:
- *
- * dirpath = '/tmp/foo'
- * Dir.mkdir(dirpath)
- * Dir.empty?(dirpath) # => true
- * Dir.empty?('/example') # => false
- * Dir.empty?('/example/main.rb') # => false
- *
- * Raises an exception if +dirpath+ does not specify a directory or file
- * in the underlying file system.
+ * Returns <code>true</code> if the named file is an empty directory,
+ * <code>false</code> if it is not a directory or non-empty.
*/
static VALUE
rb_dir_s_empty_p(VALUE obj, VALUE dirname)
@@ -3778,13 +3326,12 @@ rb_dir_s_empty_p(VALUE obj, VALUE dirname)
{
u_int32_t attrbuf[SIZEUP32(fsobj_tag_t)];
struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_OBJTAG,};
- struct getattrlist_args args = GETATTRLIST_ARGS(&al, attrbuf, 0);
- if (gvl_getattrlist(&args, path) != 0)
+ if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), 0) != 0)
rb_sys_fail_path(orig);
if (*(const fsobj_tag_t *)(attrbuf+1) == VT_HFS) {
al.commonattr = 0;
al.dirattr = ATTR_DIR_ENTRYCOUNT;
- if (gvl_getattrlist(&args, path) == 0) {
+ if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), 0) == 0) {
if (attrbuf[0] >= 2 * sizeof(u_int32_t))
return RBOOL(attrbuf[1] == 0);
if (false_on_notdir) return Qfalse;
@@ -3794,9 +3341,10 @@ rb_dir_s_empty_p(VALUE obj, VALUE dirname)
}
#endif
- result = (VALUE)IO_WITHOUT_GVL(nogvl_dir_empty_p, (void *)path);
- if (FIXNUM_P(result)) {
- rb_syserr_fail_path((int)FIX2LONG(result), orig);
+ result = (VALUE)rb_thread_call_without_gvl(nogvl_dir_empty_p, (void *)path,
+ RUBY_UBF_IO, 0);
+ if (UNDEF_P(result)) {
+ rb_sys_fail_path(orig);
}
return result;
}
@@ -3804,15 +3352,11 @@ rb_dir_s_empty_p(VALUE obj, VALUE dirname)
void
Init_Dir(void)
{
- rb_gc_register_address(&chdir_lock.path);
- rb_gc_register_address(&chdir_lock.thread);
-
rb_cDir = rb_define_class("Dir", rb_cObject);
rb_include_module(rb_cDir, rb_mEnumerable);
rb_define_alloc_func(rb_cDir, dir_s_alloc);
- rb_define_singleton_method(rb_cDir,"for_fd", dir_s_for_fd, 1);
rb_define_singleton_method(rb_cDir, "foreach", dir_foreach, -1);
rb_define_singleton_method(rb_cDir, "entries", dir_entries, -1);
rb_define_singleton_method(rb_cDir, "each_child", dir_s_each_child, -1);
@@ -3832,9 +3376,7 @@ Init_Dir(void)
rb_define_method(rb_cDir,"pos", dir_tell, 0);
rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
rb_define_method(rb_cDir,"close", dir_close, 0);
- rb_define_method(rb_cDir,"chdir", dir_chdir, 0);
- rb_define_singleton_method(rb_cDir,"fchdir", dir_s_fchdir, 1);
rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
rb_define_singleton_method(rb_cDir,"getwd", dir_s_getwd, 0);
rb_define_singleton_method(rb_cDir,"pwd", dir_s_getwd, 0);
@@ -3851,26 +3393,51 @@ Init_Dir(void)
rb_define_singleton_method(rb_cFile,"fnmatch", file_s_fnmatch, -1);
rb_define_singleton_method(rb_cFile,"fnmatch?", file_s_fnmatch, -1);
- /* Document-const: FNM_NOESCAPE
- * {File::FNM_NOESCAPE}[rdoc-ref:File::Constants@File-3A-3AFNM_NOESCAPE] */
+ /* Document-const: File::Constants::FNM_NOESCAPE
+ *
+ * Disables escapes in File.fnmatch and Dir.glob patterns
+ */
rb_file_const("FNM_NOESCAPE", INT2FIX(FNM_NOESCAPE));
- /* Document-const: FNM_PATHNAME
- * {File::FNM_PATHNAME}[rdoc-ref:File::Constants@File-3A-3AFNM_PATHNAME] */
+
+ /* Document-const: File::Constants::FNM_PATHNAME
+ *
+ * Wildcards in File.fnmatch and Dir.glob patterns do not match directory
+ * separators
+ */
rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
- /* Document-const: FNM_DOTMATCH
- * {File::FNM_DOTMATCH}[rdoc-ref:File::Constants@File-3A-3AFNM_DOTMATCH] */
+
+ /* Document-const: File::Constants::FNM_DOTMATCH
+ *
+ * The '*' wildcard matches filenames starting with "." in File.fnmatch
+ * and Dir.glob patterns
+ */
rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
- /* Document-const: FNM_CASEFOLD
- * {File::FNM_CASEFOLD}[rdoc-ref:File::Constants@File-3A-3AFNM_CASEFOLD] */
+
+ /* Document-const: File::Constants::FNM_CASEFOLD
+ *
+ * Makes File.fnmatch patterns case insensitive (but not Dir.glob
+ * patterns).
+ */
rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
- /* Document-const: FNM_EXTGLOB
- * {File::FNM_EXTGLOB}[rdoc-ref:File::Constants@File-3A-3AFNM_EXTGLOB] */
+
+ /* Document-const: File::Constants::FNM_EXTGLOB
+ *
+ * Allows file globbing through "{a,b}" in File.fnmatch patterns.
+ */
rb_file_const("FNM_EXTGLOB", INT2FIX(FNM_EXTGLOB));
- /* Document-const: FNM_SYSCASE
- * {File::FNM_SYSCASE}[rdoc-ref:File::Constants@File-3A-3AFNM_SYSCASE] */
+
+ /* Document-const: File::Constants::FNM_SYSCASE
+ *
+ * System default case insensitiveness, equals to FNM_CASEFOLD or
+ * 0.
+ */
rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE));
- /* Document-const: FNM_SHORTNAME
- * {File::FNM_SHORTNAME}[rdoc-ref:File::Constants@File-3A-3AFNM_SHORTNAME] */
+
+ /* Document-const: File::Constants::FNM_SHORTNAME
+ *
+ * Makes patterns to match short names if existing. Valid only
+ * on Microsoft Windows.
+ */
rb_file_const("FNM_SHORTNAME", INT2FIX(FNM_SHORTNAME));
}
diff --git a/dir.rb b/dir.rb
index 42b475ab2c..2e426b0881 100644
--- a/dir.rb
+++ b/dir.rb
@@ -1,85 +1,11 @@
-# An object of class \Dir represents a directory in the underlying file system.
+# Objects of class Dir are directory streams representing
+# directories in the underlying file system. They provide a variety
+# of ways to list directories and their contents. See also File.
#
-# It consists mainly of:
-#
-# - A string _path_, given when the object is created,
-# that specifies a directory in the underlying file system;
-# method #path returns the path.
-# - A collection of string <i>entry names</i>,
-# each of which is the name of a directory or file in the underlying file system;
-# the entry names may be retrieved
-# in an {array-like fashion}[rdoc-ref:Dir@Dir+As+Array-Like]
-# or in a {stream-like fashion}[rdoc-ref:Dir@Dir+As+Stream-Like].
-#
-# == About the Examples
-#
-# Some examples on this page use this simple file tree:
-#
-# example/
-# ├── config.h
-# ├── lib/
-# │ ├── song/
-# │ │ └── karaoke.rb
-# │ └── song.rb
-# └── main.rb
-#
-# Others use the file tree for the
-# {Ruby project itself}[https://github.com/ruby/ruby].
-#
-# == \Dir As \Array-Like
-#
-# A \Dir object is in some ways array-like:
-#
-# - It has instance methods #children, #each, and #each_child.
-# - It includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here].
-#
-# == \Dir As Stream-Like
-#
-# A \Dir object is in some ways stream-like.
-#
-# The stream is initially open for reading,
-# but may be closed manually (using method #close),
-# and will be closed on block exit if created by Dir.open called with a block.
-# The closed stream may not be further manipulated,
-# and may not be reopened.
-#
-# The stream has a _position_, which is the index of an entry in the directory:
-#
-# - The initial position is zero (before the first entry).
-# - \Method #tell (aliased as #pos) returns the position.
-# - \Method #pos= sets the position (but ignores a value outside the stream),
-# and returns the position.
-# - \Method #seek is like #pos=, but returns +self+ (convenient for chaining).
-# - \Method #read, if not at end-of-stream, reads the next entry and increments
-# the position;
-# if at end-of-stream, does not increment the position.
-# - \Method #rewind sets the position to zero.
-#
-# Examples (using the {simple file tree}[rdoc-ref:Dir@About+the+Examples]):
-#
-# dir = Dir.new('example') # => #<Dir:example>
-# dir.pos # => 0
-#
-# dir.read # => "."
-# dir.read # => ".."
-# dir.read # => "config.h"
-# dir.read # => "lib"
-# dir.read # => "main.rb"
-# dir.pos # => 5
-# dir.read # => nil
-# dir.pos # => 5
-#
-# dir.rewind # => #<Dir:example>
-# dir.pos # => 0
-#
-# dir.pos = 3 # => 3
-# dir.pos # => 3
-#
-# dir.seek(4) # => #<Dir:example>
-# dir.pos # => 4
-#
-# dir.close # => nil
-# dir.read # Raises IOError.
+# The directory used in these examples contains the two regular files
+# (<code>config.h</code> and <code>main.rb</code>), the parent
+# directory (<code>..</code>), and the directory itself
+# (<code>.</code>).
#
# == What's Here
#
@@ -154,32 +80,20 @@
# closing it upon block exit.
# - ::unlink (aliased as ::delete and ::rmdir): Removes the given directory.
# - #inspect: Returns a string description of +self+.
-#
class Dir
# call-seq:
- # Dir.open(dirpath) -> dir
- # Dir.open(dirpath, encoding: nil) -> dir
- # Dir.open(dirpath) {|dir| ... } -> object
- # Dir.open(dirpath, encoding: nil) {|dir| ... } -> object
- #
- # Creates a new \Dir object _dir_ for the directory at +dirpath+.
- #
- # With no block, the method equivalent to Dir.new(dirpath, encoding):
- #
- # Dir.open('.') # => #<Dir:.>
- #
- # With a block given, the block is called with the created _dir_;
- # on block exit _dir_ is closed and the block's value is returned:
- #
- # Dir.open('.') {|dir| dir.inspect } # => "#<Dir:.>"
- #
- # The value given with optional keyword argument +encoding+
- # specifies the encoding for the directory entry names;
- # if +nil+ (the default), the file system's encoding is used:
- #
- # Dir.open('.').read.encoding # => #<Encoding:UTF-8>
- # Dir.open('.', encoding: 'US-ASCII').read.encoding # => #<Encoding:US-ASCII>
- #
+ # Dir.open( string ) -> aDir
+ # Dir.open( string, encoding: enc ) -> aDir
+ # Dir.open( string ) {| aDir | block } -> anObject
+ # Dir.open( string, encoding: enc ) {| aDir | block } -> anObject
+ #
+ # The optional <i>encoding</i> keyword argument specifies the encoding of the directory.
+ # If not specified, the filesystem encoding is used.
+ #
+ # With no block, <code>open</code> is a synonym for Dir::new. If a
+ # block is present, it is passed <i>aDir</i> as a parameter. The
+ # directory is closed at the end of the block, and Dir::open returns
+ # the value of the block.
def self.open(name, encoding: nil, &block)
dir = Primitive.dir_s_open(name, encoding)
if block
@@ -194,221 +108,115 @@ class Dir
end
# call-seq:
- # Dir.new(dirpath) -> dir
- # Dir.new(dirpath, encoding: nil) -> dir
- #
- # Returns a new \Dir object for the directory at +dirpath+:
- #
- # Dir.new('.') # => #<Dir:.>
+ # Dir.new( string ) -> aDir
+ # Dir.new( string, encoding: enc ) -> aDir
#
- # The value given with optional keyword argument +encoding+
- # specifies the encoding for the directory entry names;
- # if +nil+ (the default), the file system's encoding is used:
- #
- # Dir.new('.').read.encoding # => #<Encoding:UTF-8>
- # Dir.new('.', encoding: 'US-ASCII').read.encoding # => #<Encoding:US-ASCII>
+ # Returns a new directory object for the named directory.
#
+ # The optional <i>encoding</i> keyword argument specifies the encoding of the directory.
+ # If not specified, the filesystem encoding is used.
def initialize(name, encoding: nil)
Primitive.dir_initialize(name, encoding)
end
# call-seq:
- # Dir[*patterns, base: nil, sort: true] -> array
- #
- # Calls Dir.glob with argument +patterns+
- # and the values of keyword arguments +base+ and +sort+;
- # returns the array of selected entry names.
+ # Dir[ string [, string ...] [, base: path] [, sort: true] ] -> array
#
+ # Equivalent to calling
+ # <code>Dir.glob([</code><i>string,...</i><code>], 0)</code>.
def self.[](*args, base: nil, sort: true)
Primitive.dir_s_aref(args, base, sort)
end
# call-seq:
- # Dir.glob(*patterns, flags: 0, base: nil, sort: true) -> array
- # Dir.glob(*patterns, flags: 0, base: nil, sort: true) {|entry_name| ... } -> nil
- #
- # Forms an array _entry_names_ of the entry names selected by the arguments.
- #
- # Argument +patterns+ is a string pattern or an array of string patterns;
- # note that these are not regexps; see below.
- #
- # Notes for the following examples:
- #
- # - <tt>'*'</tt> is the pattern that matches any entry name
- # except those that begin with <tt>'.'</tt>.
- # - We use method Array#take to shorten returned arrays
- # that otherwise would be very large.
- #
- # With no block, returns array _entry_names_;
- # example (using the {simple file tree}[rdoc-ref:Dir@About+the+Examples]):
- #
- # Dir.glob('*') # => ["config.h", "lib", "main.rb"]
- #
- # With a block, calls the block with each of the _entry_names_
- # and returns +nil+:
- #
- # Dir.glob('*') {|entry_name| puts entry_name } # => nil
+ # Dir.glob( pattern, [flags], [base: path] [, sort: true] ) -> array
+ # Dir.glob( pattern, [flags], [base: path] [, sort: true] ) { |filename| block } -> nil
#
- # Output:
+ # Expands +pattern+, which is a pattern string or an Array of pattern
+ # strings, and returns an array containing the matching filenames.
+ # If a block is given, calls the block once for each matching filename,
+ # passing the filename as a parameter to the block.
#
- # config.h
- # lib
- # main.rb
+ # The optional +base+ keyword argument specifies the base directory for
+ # interpreting relative pathnames instead of the current working directory.
+ # As the results are not prefixed with the base directory name in this
+ # case, you will need to prepend the base directory name if you want real
+ # paths.
#
- # If optional keyword argument +flags+ is given,
- # the value modifies the matching; see below.
+ # The results which matched single wildcard or character set are sorted in
+ # binary ascending order, unless +false+ is given as the optional +sort+
+ # keyword argument. The order of an Array of pattern strings and braces
+ # are preserved.
#
- # If optional keyword argument +base+ is given,
- # its value specifies the base directory.
- # Each pattern string specifies entries relative to the base directory;
- # the default is <tt>'.'</tt>.
- # The base directory is not prepended to the entry names in the result:
+ # Note that the pattern is not a regexp, it's closer to a shell glob.
+ # See File::fnmatch for the meaning of the +flags+ parameter.
+ # Case sensitivity depends on your system (+File::FNM_CASEFOLD+ is ignored).
#
- # Dir.glob(pattern, base: 'lib').take(5)
- # # => ["abbrev.gemspec", "abbrev.rb", "base64.gemspec", "base64.rb", "benchmark.gemspec"]
- # Dir.glob(pattern, base: 'lib/irb').take(5)
- # # => ["cmd", "color.rb", "color_printer.rb", "completion.rb", "context.rb"]
- #
- # If optional keyword +sort+ is given, its value specifies whether
- # the array is to be sorted; the default is +true+.
- # Passing value +false+ with that keyword disables sorting
- # (though the underlying file system may already have sorted the array).
- #
- # <b>Patterns</b>
- #
- # Each pattern string is expanded
- # according to certain metacharacters;
- # examples below use the {Ruby file tree}[rdoc-ref:Dir@About+the+Examples]:
- #
- # - <tt>'*'</tt>: Matches any substring in an entry name,
- # similar in meaning to regexp <tt>/.*/mx</tt>;
- # may be restricted by other values in the pattern strings:
- #
- # - <tt>'*'</tt> matches all entry names:
- #
- # Dir.glob('*').take(3) # => ["BSDL", "CONTRIBUTING.md", "COPYING"]
- #
- # - <tt>'c*'</tt> matches entry names beginning with <tt>'c'</tt>:
- #
- # Dir.glob('c*').take(3) # => ["CONTRIBUTING.md", "COPYING", "COPYING.ja"]
- #
- # - <tt>'*c'</tt> matches entry names ending with <tt>'c'</tt>:
- #
- # Dir.glob('*c').take(3) # => ["addr2line.c", "array.c", "ast.c"]
- #
- # - <tt>'\*c\*'</tt> matches entry names that contain <tt>'c'</tt>,
- # even at the beginning or end:
- #
- # Dir.glob('*c*').take(3) # => ["CONTRIBUTING.md", "COPYING", "COPYING.ja"]
- #
- # Does not match Unix-like hidden entry names ("dot files").
- # To include those in the matched entry names,
- # use flag IO::FNM_DOTMATCH or something like <tt>'{*,.*}'</tt>.
- #
- # - <tt>'**'</tt>: Matches entry names recursively
- # if followed by the slash character <tt>'/'</tt>:
- #
- # Dir.glob('**/').take(3) # => ["basictest/", "benchmark/", "benchmark/gc/"]
- #
- # If the string pattern contains other characters
- # or is not followed by a slash character,
- # it is equivalent to <tt>'*'</tt>.
- #
- # - <tt>'?'</tt> Matches any single character;
- # similar in meaning to regexp <tt>/./</tt>:
- #
- # Dir.glob('io.?') # => ["io.c"]
- #
- # - <tt>'[_set_]'</tt>: Matches any one character in the string _set_;
- # behaves like a {Regexp character class}[rdoc-ref:Regexp@Character+Classes],
- # including set negation (<tt>'[^a-z]'</tt>):
- #
- # Dir.glob('*.[a-z][a-z]').take(3)
- # # => ["CONTRIBUTING.md", "COPYING.ja", "KNOWNBUGS.rb"]
- #
- # - <tt>'{_abc_,_xyz_}'</tt>:
- # Matches either string _abc_ or string _xyz_;
- # behaves like {Regexp alternation}[rdoc-ref:Regexp@Alternation]:
- #
- # Dir.glob('{LEGAL,BSDL}') # => ["LEGAL", "BSDL"]
- #
- # More than two alternatives may be given.
- #
- # - <tt>\\</tt>: Escapes the following metacharacter.
- #
- # Note that on Windows, the backslash character may not be used
- # in a string pattern:
- # <tt>Dir['c:\\foo*']</tt> will not work, use <tt>Dir['c:/foo*']</tt> instead.
- #
- # More examples (using the {simple file tree}[rdoc-ref:Dir@About+the+Examples]):
- #
- # # We're in the example directory.
- # File.basename(Dir.pwd) # => "example"
- # Dir.glob('config.?') # => ["config.h"]
- # Dir.glob('*.[a-z][a-z]') # => ["main.rb"]
- # Dir.glob('*.[^r]*') # => ["config.h"]
- # Dir.glob('*.{rb,h}') # => ["main.rb", "config.h"]
- # Dir.glob('*') # => ["config.h", "lib", "main.rb"]
- # Dir.glob('*', File::FNM_DOTMATCH) # => [".", "config.h", "lib", "main.rb"]
- # Dir.glob(["*.rb", "*.h"]) # => ["main.rb", "config.h"]
- #
- # Dir.glob('**/*.rb')
- # => ["lib/song/karaoke.rb", "lib/song.rb", "main.rb"]
- #
- # Dir.glob('**/*.rb', base: 'lib') # => ["song/karaoke.rb", "song.rb"]
- #
- # Dir.glob('**/lib') # => ["lib"]
+ # <code>*</code>::
+ # Matches any file. Can be restricted by other values in the glob.
+ # Equivalent to <code>/.*/mx</code> in regexp.
#
- # Dir.glob('**/lib/**/*.rb') # => ["lib/song/karaoke.rb", "lib/song.rb"]
+ # <code>*</code>:: Matches all files
+ # <code>c*</code>:: Matches all files beginning with <code>c</code>
+ # <code>*c</code>:: Matches all files ending with <code>c</code>
+ # <code>\*c\*</code>:: Match all files that have <code>c</code> in them
+ # (including at the beginning or end).
#
- # Dir.glob('**/lib/*.rb') # => ["lib/song.rb"]
+ # Note, this will not match Unix-like hidden files (dotfiles). In order
+ # to include those in the match results, you must use the
+ # File::FNM_DOTMATCH flag or something like <code>"{*,.*}"</code>.
#
- # <b>Flags</b>
+ # <code>**</code>::
+ # Matches directories recursively if followed by <code>/</code>. If
+ # this path segment contains any other characters, it is the same as the
+ # usual <code>*</code>.
#
- # If optional keyword argument +flags+ is given (the default is zero -- no flags),
- # its value should be the bitwise OR of one or more of the constants
- # defined in module File::Constants.
+ # <code>?</code>::
+ # Matches any one character. Equivalent to <code>/.{1}/</code> in regexp.
#
- # Example:
+ # <code>[set]</code>::
+ # Matches any one character in +set+. Behaves exactly like character sets
+ # in Regexp, including set negation (<code>[^a-z]</code>).
#
- # flags = File::FNM_EXTGLOB | File::FNM_DOTMATCH
+ # <code>{p,q}</code>::
+ # Matches either literal <code>p</code> or literal <code>q</code>.
+ # Equivalent to pattern alternation in regexp.
#
- # Specifying flags can extend, restrict, or otherwise modify the matching.
+ # Matching literals may be more than one character in length. More than
+ # two literals may be specified.
#
- # The flags for this method (other constants in File::Constants do not apply):
+ # <code>\\</code>::
+ # Escapes the next metacharacter.
#
- # - File::FNM_DOTMATCH:
- # specifies that entry names beginning with <tt>'.'</tt>
- # should be considered for matching:
+ # Note that this means you cannot use backslash on windows as part of a
+ # glob, i.e. <code>Dir["c:\\foo*"]</code> will not work, use
+ # <code>Dir["c:/foo*"]</code> instead.
#
- # Dir.glob('*').take(5)
- # # => ["BSDL", "CONTRIBUTING.md", "COPYING", "COPYING.ja", "GPL"]
- # Dir.glob('*', flags: File::FNM_DOTMATCH).take(5)
- # # => [".", ".appveyor.yml", ".cirrus.yml", ".dir-locals.el", ".document"]
+ # Examples:
#
- # - File::FNM_EXTGLOB:
- # enables the pattern extension
- # <tt>'{_a_,_b_}'</tt>, which matches pattern _a_ and pattern _b_;
- # behaves like a
- # {regexp union}[rdoc-ref:Regexp.union]
- # (e.g., <tt>'(?:_a_|_b_)'</tt>):
+ # Dir["config.?"] #=> ["config.h"]
+ # Dir.glob("config.?") #=> ["config.h"]
+ # Dir.glob("*.[a-z][a-z]") #=> ["main.rb"]
+ # Dir.glob("*.[^r]*") #=> ["config.h"]
+ # Dir.glob("*.{rb,h}") #=> ["main.rb", "config.h"]
+ # Dir.glob("*") #=> ["config.h", "main.rb"]
+ # Dir.glob("*", File::FNM_DOTMATCH) #=> [".", "config.h", "main.rb"]
+ # Dir.glob(["*.rb", "*.h"]) #=> ["main.rb", "config.h"]
#
- # pattern = '{LEGAL,BSDL}'
- # Dir.glob(pattern) # => ["LEGAL", "BSDL"]
+ # Dir.glob("**/*.rb") #=> ["main.rb",
+ # # "lib/song.rb",
+ # # "lib/song/karaoke.rb"]
#
- # - File::FNM_NOESCAPE:
- # specifies that escaping with the backslash character <tt>'\'</tt>
- # is disabled; the character is not an escape character.
+ # Dir.glob("**/*.rb", base: "lib") #=> ["song.rb",
+ # # "song/karaoke.rb"]
#
- # - File::FNM_PATHNAME:
- # specifies that metacharacters <tt>'*'</tt> and <tt>'?'</tt>
- # do not match directory separators.
+ # Dir.glob("**/lib") #=> ["lib"]
#
- # - File::FNM_SHORTNAME:
- # specifies that patterns may match short names if they exist; Windows only.
+ # Dir.glob("**/lib/**/*.rb") #=> ["lib/song.rb",
+ # # "lib/song/karaoke.rb"]
#
+ # Dir.glob("**/lib/*.rb") #=> ["lib/song.rb"]
def self.glob(pattern, _flags = 0, flags: _flags, base: nil, sort: true)
- Primitive.attr! :use_block
Primitive.dir_s_glob(pattern, flags, base, sort)
end
end
diff --git a/dln.c b/dln.c
index db6ea5aa0f..0edd709bbe 100644
--- a/dln.c
+++ b/dln.c
@@ -107,45 +107,36 @@ dln_loaderror(const char *format, ...)
#endif
#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
-struct string_part {
- const char *ptr;
- size_t len;
-};
-
-static struct string_part
-init_funcname_len(const char *file)
+static size_t
+init_funcname_len(const char **file)
{
- const char *p = file, *base, *dot = NULL;
+ const char *p = *file, *base, *dot = NULL;
/* Load the file as an object one */
for (base = p; *p; p++) { /* Find position of last '/' */
if (*p == '.' && !dot) dot = p;
if (isdirsep(*p)) base = p+1, dot = NULL;
}
+ *file = base;
/* Delete suffix if it exists */
- const size_t len = (dot ? dot : p) - base;
- return (struct string_part){base, len};
-}
-
-static inline char *
-concat_funcname(char *buf, const char *prefix, size_t plen, const struct string_part base)
-{
- if (!buf) {
- dln_memerror();
- }
- memcpy(buf, prefix, plen);
- memcpy(buf + plen, base.ptr, base.len);
- buf[plen + base.len] = '\0';
- return buf;
+ return (dot ? dot : p) - base;
}
-#define build_funcname(prefix, buf, file) do {\
- const struct string_part f = init_funcname_len(file);\
- const size_t plen = sizeof(prefix "") - 1;\
- *(buf) = concat_funcname(ALLOCA_N(char, plen+f.len+1), prefix, plen, f);\
+static const char funcname_prefix[sizeof(FUNCNAME_PREFIX) - 1] = FUNCNAME_PREFIX;
+
+#define init_funcname(buf, file) do {\
+ const char *base = (file);\
+ const size_t flen = init_funcname_len(&base);\
+ const size_t plen = sizeof(funcname_prefix);\
+ char *const tmp = ALLOCA_N(char, plen+flen+1);\
+ if (!tmp) {\
+ dln_memerror();\
+ }\
+ memcpy(tmp, funcname_prefix, plen);\
+ memcpy(tmp+plen, base, flen);\
+ tmp[plen+flen] = '\0';\
+ *(buf) = tmp;\
} while (0)
-
-#define init_funcname(buf, file) build_funcname(FUNCNAME_PREFIX, buf, file)
#endif
#ifdef USE_DLN_DLOPEN
@@ -281,15 +272,13 @@ rb_w32_check_imported(HMODULE ext, HMODULE mine)
static bool
dln_incompatible_func(void *handle, const char *funcname, void *const fp, const char **libname)
{
+ Dl_info dli;
void *ex = dlsym(handle, funcname);
if (!ex) return false;
if (ex == fp) return false;
-# if defined(HAVE_DLADDR)
- Dl_info dli;
if (dladdr(ex, &dli)) {
*libname = dli.dli_fname;
}
-# endif
return true;
}
@@ -403,12 +392,6 @@ dln_open(const char *file)
dln_fatalerror("%s - %s", incompatible, file);
}
else {
- if (libruby_name) {
- const size_t len = strlen(libruby_name);
- char *const tmp = ALLOCA_N(char, len + 1);
- if (tmp) memcpy(tmp, libruby_name, len + 1);
- libruby_name = tmp;
- }
dlclose(handle);
if (libruby_name) {
dln_loaderror("linked to incompatible %s - %s", libruby_name, file);
@@ -430,63 +413,33 @@ dln_open(const char *file)
static void *
dln_sym(void *handle, const char *symbol)
{
-#if defined(_WIN32)
- return GetProcAddress(handle, symbol);
-#elif defined(USE_DLN_DLOPEN)
- return dlsym(handle, symbol);
-#endif
-}
+ void *func;
+ const char *error;
-static void *
-dln_sym_func(void *handle, const char *symbol)
-{
- void *func = dln_sym(handle, symbol);
+#if defined(_WIN32)
+ char message[1024];
+ func = GetProcAddress(handle, symbol);
if (func == NULL) {
- const char *error;
-#if defined(_WIN32)
- char message[1024];
error = dln_strerror();
+ goto failed;
+ }
+
#elif defined(USE_DLN_DLOPEN)
+ func = dlsym(handle, symbol);
+ if (func == NULL) {
const size_t errlen = strlen(error = dln_strerror()) + 1;
error = memcpy(ALLOCA_N(char, errlen), error, errlen);
-#endif
- dln_loaderror("%s - %s", error, symbol);
+ goto failed;
}
- return func;
-}
-
-#define dln_sym_callable(rettype, argtype, handle, symbol) \
- (*(rettype (*)argtype)dln_sym_func(handle, symbol))
#endif
-void *
-dln_symbol(void *handle, const char *symbol)
-{
-#if defined(_WIN32) || defined(USE_DLN_DLOPEN)
- if (EXTERNAL_PREFIX[0]) {
- const size_t symlen = strlen(symbol);
- char *const tmp = ALLOCA_N(char, symlen + sizeof(EXTERNAL_PREFIX));
- if (!tmp) dln_memerror();
- memcpy(tmp, EXTERNAL_PREFIX, sizeof(EXTERNAL_PREFIX) - 1);
- memcpy(tmp + sizeof(EXTERNAL_PREFIX) - 1, symbol, symlen + 1);
- symbol = tmp;
- }
- if (handle == NULL) {
-# if defined(USE_DLN_DLOPEN)
- handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
-# elif defined(_WIN32)
- handle = rb_libruby_handle();
-# else
- return NULL;
-# endif
- }
- return dln_sym(handle, symbol);
-#else
- return NULL;
-#endif
-}
+ return func;
+ failed:
+ dln_loaderror("%s - %s", error, symbol);
+}
+#endif
#if defined(RUBY_DLN_CHECK_ABI) && defined(USE_DLN_DLOPEN)
static bool
@@ -504,19 +457,19 @@ dln_load(const char *file)
void *handle = dln_open(file);
#ifdef RUBY_DLN_CHECK_ABI
- typedef unsigned long long abi_version_number;
- abi_version_number binary_abi_version =
- dln_sym_callable(abi_version_number, (void), handle, EXTERNAL_PREFIX "ruby_abi_version")();
- if (binary_abi_version != RUBY_ABI_VERSION && abi_check_enabled_p()) {
+ unsigned long long (*abi_version_fct)(void) = (unsigned long long(*)(void))dln_sym(handle, "ruby_abi_version");
+ unsigned long long binary_abi_version = (*abi_version_fct)();
+ if (binary_abi_version != ruby_abi_version() && abi_check_enabled_p()) {
dln_loaderror("incompatible ABI version of binary - %s", file);
}
#endif
char *init_fct_name;
init_funcname(&init_fct_name, file);
+ void (*init_fct)(void) = (void(*)(void))dln_sym(handle, init_fct_name);
/* Call the init code */
- dln_sym_callable(void, (void), handle, init_fct_name)();
+ (*init_fct)();
return handle;
diff --git a/dln.h b/dln.h
index d624bb6611..902f753450 100644
--- a/dln.h
+++ b/dln.h
@@ -25,7 +25,6 @@ RUBY_SYMBOL_EXPORT_BEGIN
char *dln_find_exe_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL);
char *dln_find_file_r(const char*,const char*,char*,size_t DLN_FIND_EXTRA_ARG_DECL);
void *dln_load(const char*);
-void *dln_symbol(void*,const char*);
RUBY_SYMBOL_EXPORT_END
diff --git a/dln_find.c b/dln_find.c
index ae37b9dde4..5d380f5d39 100644
--- a/dln_find.c
+++ b/dln_find.c
@@ -11,9 +11,11 @@
#ifdef RUBY_EXPORT
#include "ruby/ruby.h"
-#define dln_warning(...) rb_warning(__VA_ARGS__)
+#define dln_warning rb_warning
+#define dln_warning_arg
#else
-#define dln_warning(...) fprintf(stderr, __VA_ARGS__)
+#define dln_warning fprintf
+#define dln_warning_arg stderr,
#endif
#include "dln.h"
@@ -73,7 +75,7 @@ dln_find_exe_r(const char *fname, const char *path, char *buf, size_t size
".";
}
buf = dln_find_1(fname, path, buf, size, 1 DLN_FIND_EXTRA_ARG);
- free(envpath);
+ if (envpath) free(envpath);
return buf;
}
@@ -107,7 +109,7 @@ dln_find_1(const char *fname, const char *path, char *fbuf, size_t size,
static const char pathname_too_long[] = "openpath: pathname too long (ignored)\n\
\tDirectory \"%.*s\"%s\n\tFile \"%.*s\"%s\n";
-#define PATHNAME_TOO_LONG() dln_warning(pathname_too_long, \
+#define PATHNAME_TOO_LONG() dln_warning(dln_warning_arg pathname_too_long, \
((bp - fbuf) > 100 ? 100 : (int)(bp - fbuf)), fbuf, \
((bp - fbuf) > 100 ? "..." : ""), \
(fnlen > 100 ? 100 : (int)fnlen), fname, \
@@ -118,7 +120,8 @@ dln_find_1(const char *fname, const char *path, char *fbuf, size_t size,
RETURN_IF(!fname);
fnlen = strlen(fname);
if (fnlen >= size) {
- dln_warning("openpath: pathname too long (ignored)\n\tFile \"%.*s\"%s\n",
+ dln_warning(dln_warning_arg
+ "openpath: pathname too long (ignored)\n\tFile \"%.*s\"%s\n",
(fnlen > 100 ? 100 : (int)fnlen), fname,
(fnlen > 100 ? "..." : ""));
return NULL;
diff --git a/dmydln.c b/dmydln.c
index 35824ebec8..d05cda0b8e 100644
--- a/dmydln.c
+++ b/dmydln.c
@@ -1,6 +1,3 @@
-// This file is used by miniruby, not ruby.
-// ruby uses dln.c.
-
#include "ruby/ruby.h"
NORETURN(void *dln_load(const char *));
@@ -11,12 +8,3 @@ dln_load(const char *file)
UNREACHABLE_RETURN(NULL);
}
-
-NORETURN(void *dln_symbol(void*,const char*));
-void*
-dln_symbol(void *handle, const char *symbol)
-{
- rb_loaderror("this executable file can't load extension libraries");
-
- UNREACHABLE_RETURN(NULL);
-}
diff --git a/dmyenc.c b/dmyenc.c
index 4771841281..75b8a2da43 100644
--- a/dmyenc.c
+++ b/dmyenc.c
@@ -1,17 +1,3 @@
-// This file is used by dynamically-linked ruby, which has no
-// statically-linked encodings other than the builtin encodings.
-//
-// - miniruby does not use this Init_enc. Instead, "miniinit.c"
-// provides Init_enc, which defines only the builtin encodings.
-//
-// - Dynamically-linked ruby uses this Init_enc, which requires
-// "enc/encdb.so" to load the builtin encodings and set up the
-// optional encodings.
-//
-// - Statically-linked ruby does not use this Init_enc. Instead,
-// "enc/encinit.c" (which is a generated file) defines Init_enc,
-// which activates the encodings.
-
#define require(name) ruby_require_internal(name, (unsigned int)sizeof(name)-1)
int ruby_require_internal(const char *, int);
diff --git a/dmyext.c b/dmyext.c
index 66be95ab4e..4d273f7faf 100644
--- a/dmyext.c
+++ b/dmyext.c
@@ -1,17 +1,3 @@
-// This file is used by dynamically-linked ruby, which has no
-// statically-linked extension libraries.
-//
-// - miniruby does not use this Init_ext. Instead, "miniinit.c"
-// provides Init_enc, which does nothing too. It does not support
-// require'ing extension libraries.
-//
-// - Dynamically-linked ruby uses this Init_ext, which does
-// nothing. It loads extension libraries by dlopen, etc.
-//
-// - Statically-linked ruby does not use this Init_ext. Instead,
-// "ext/extinit.c" (which is a generated file) defines Init_ext,
-// which activates the (statically-linked) extension libraries.
-
void
Init_ext(void)
{
diff --git a/doc/.document b/doc/.document
index 8174394f48..f589dda07c 100644
--- a/doc/.document
+++ b/doc/.document
@@ -1,12 +1,9 @@
*.md
*.rb
-[^_]*.rdoc
+*.rdoc
contributing
NEWS
syntax
optparse
rdoc
-regexp
-rjit
yjit
-ruby
diff --git a/doc/ChangeLog/ChangeLog-0.06_to_0.52 b/doc/ChangeLog-0.06_to_0.52
index 63826081b3..63826081b3 100644
--- a/doc/ChangeLog/ChangeLog-0.06_to_0.52
+++ b/doc/ChangeLog-0.06_to_0.52
diff --git a/doc/ChangeLog/ChangeLog-0.50_to_0.60 b/doc/ChangeLog-0.50_to_0.60
index 5f5b03ff40..5f5b03ff40 100644
--- a/doc/ChangeLog/ChangeLog-0.50_to_0.60
+++ b/doc/ChangeLog-0.50_to_0.60
diff --git a/doc/ChangeLog/ChangeLog-0.60_to_1.1 b/doc/ChangeLog-0.60_to_1.1
index 59d195e780..59d195e780 100644
--- a/doc/ChangeLog/ChangeLog-0.60_to_1.1
+++ b/doc/ChangeLog-0.60_to_1.1
diff --git a/doc/ChangeLog/ChangeLog-1.8.0 b/doc/ChangeLog-1.8.0
index 6d9453d011..6d9453d011 100644
--- a/doc/ChangeLog/ChangeLog-1.8.0
+++ b/doc/ChangeLog-1.8.0
diff --git a/doc/ChangeLog/ChangeLog-1.9.3 b/doc/ChangeLog-1.9.3
index 0f80eed2d5..0f80eed2d5 100644
--- a/doc/ChangeLog/ChangeLog-1.9.3
+++ b/doc/ChangeLog-1.9.3
diff --git a/doc/ChangeLog/ChangeLog-2.0.0 b/doc/ChangeLog-2.0.0
index 9e654db189..9e654db189 100644
--- a/doc/ChangeLog/ChangeLog-2.0.0
+++ b/doc/ChangeLog-2.0.0
diff --git a/doc/ChangeLog-2.1.0 b/doc/ChangeLog-2.1.0
new file mode 100644
index 0000000000..5b670b31c9
--- /dev/null
+++ b/doc/ChangeLog-2.1.0
@@ -0,0 +1,18060 @@
+Fri Dec 20 17:52:50 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_method.c: check definition of
+ GLOBAL_METHOD_CACHE_SIZE and GLOBAL_METHOD_CACHE_MASK.
+
+Fri Dec 20 17:03:10 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: rename OBJ_WRITE and OBJ_WRITTEN into
+ RB_OBJ_WRITE and RB_OBJ_WRITTEN.
+
+ * array.c, class.c, compile.c, hash.c, internal.h, iseq.c,
+ proc.c, process.c, re.c, string.c, variable.c, vm.c,
+ vm_eval.c, vm_insnhelper.c, vm_insnhelper.h,
+ vm_method.c: catch up this change.
+
+Fri Dec 20 16:01:35 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: add a comment for WB interfaces.
+
+Fri Dec 20 16:00:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: DLDFLAGS is defined in --with-opt-dir handler, so
+ ${DLDFLAGS=} does not work now. use RUBY_APPEND_OPTIONS instead.
+ [ruby-dev:47855] [Bug #9256]
+
+Fri Dec 20 14:19:12 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in (AC_ARG_WITH): use withval directly.
+ fix failure on FreeBSD.
+ http://fb32.rubyci.org/~chkbuild/ruby-trunk/log/20131217T070301Z.diff.html.gz
+
+Fri Dec 20 14:00:01 2013 Aman Gupta <ruby@tmm1.net>
+
+ * include/ruby/ruby.h (struct RClass): add super, remove iv_index_tbl.
+ since RCLASS_SUPER() is commonly used inside while loops, we move it
+ back inside struct RClass to improve cache hits. this provides a
+ small improvement (1%) in hotspots like rb_obj_is_kind_of()
+ * internal.h (struct rb_classext_struct): remove super, add
+ iv_index_table
+ * internal.h (RCLASS_SUPER): update for new location
+ * internal.h (RCLASS_SET_SUPER): ditto
+ * internal.h (RCLASS_IV_INDEX_TBL): ditto
+ * object.c (rb_class_get_superclass): ditto
+ * include/ruby/backward/classext.h (RCLASS_SUPER): ditto
+
+Fri Dec 20 07:07:35 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 03d6ae7. Changes include:
+
+ * Fixed typos.
+
+ * Relaxed Gem.ruby test for ruby packagers that do not use `ruby`.
+
+ * test/rubygems: ditto.
+
+Thu Dec 19 14:03:04 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (heap_get_freeobj): improve hot path performance.
+
+ * gc.c (heap_get_freeobj_from_next_freepage): replace with
+ heap_get_freepage(). It returns freeobj instead of freepage.
+ This is not on hot path.
+
+Thu Dec 19 12:05:17 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master af60443. Changes include:
+
+ * Improved speed of `gem install --ignore-dependencies`.
+
+ * Open read-write for exclusive flock. [ruby-trunk - Bug #9257]
+
+ * Remove specification before install to prevent infinite loop.
+
+Thu Dec 19 11:23:49 2013 Aman Gupta <ruby@tmm1.net>
+
+ * vm_insnhelper.c (vm_call_iseq_setup_normal): simple for loop
+ condition optimization. this area shows up as a hotspot in VM
+ profiles.
+
+Thu Dec 19 10:50:13 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (newobj_of): don't need to RBASIC_SET_CLASS() which includes WB
+ here because created obj is always YOUNG/INFANT.
+
+Thu Dec 19 10:48:37 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/gc/gcbench.rb: check GC::OPTS availability
+ for not MRI 2.1.0.
+
+Thu Dec 19 03:10:30 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c (heap_get_freeobj): remove redundant assignment. heap->freelist
+ is set after the while() loop already.
+
+Thu Dec 19 01:54:30 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/runner.rb: fix commit miss on r44278.
+
+Thu Dec 19 00:26:11 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (garbage_collect_body): lazy_sweep setting should work
+ without USE_RGENGC.
+
+Wed Dec 18 23:31:04 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_profile_dump_major_reason): fix this function because major_reason
+ can be OR of multiple reasons.
+
+ * gc.c (gc_profile_dump_on): ditto.
+
+Wed Dec 18 17:03:00 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_profile_record_get): should return an empty array
+ when profiling is active.
+
+Wed Dec 18 16:49:40 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_profile_clear, gc_profile_enable): remove rest_sweep().
+
+ * gc.c: check objspace->profile.current_record before inserting
+ profiling record by new macro gc_prof_enabled().
+
+Wed Dec 18 14:32:06 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_exec.h (VM_DEBUG_STACKOVERFLOW): added.
+ disable stack overflow check for every stack pushing as default.
+
+ * vm_exec.c (vm_stack_overflow_for_insn): ditto.
+
+Wed Dec 18 10:00:22 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master d8f12e2. This increases the
+ speed of `gem install --ignore-dependencies` which helps bundler
+ tests.
+ * test/rubygems: ditto.
+
+Wed Dec 18 09:00:17 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_gc.rb (test_expand_heap): allow +/-1 diff.
+
+Tue Dec 17 23:44:15 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * test/ruby/test_io.rb: fix duplicated test name.
+
+Tue Dec 17 20:15:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash_reject): revert to deprecated behavior, with
+ warnings, due to compatibility for HashWithDifferentAccess.
+ [ruby-core:59154] [Bug #9223]
+
+Tue Dec 17 17:30:56 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-electric.el: Import version 2.1.1 from
+ https://github.com/knu/ruby-electric.el.
+
+ * ruby-electric-delete-backward-char: Enable support for number
+ prefix.
+
+ * ruby-electric-curlies: Fix electric operation after an open
+ curly.
+
+Tue Dec 17 16:19:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_trace.c (rb_postponed_job_flush): isolate exceptions in
+ postponed jobs and restore outer ones. based on a patch by
+ tarui. [ruby-core:58652] [Bug #9168]
+
+Tue Dec 17 10:48:04 2013 Aman Gupta <ruby@tmm1.net>
+
+ * configure.in (RUBY_DTRACE_POSTPROCESS): Fix compatibility with
+ systemtap on linux. stap requires `dtrace -G` post-processing, but
+ the dtrace compatibility wrapper is very strict about probes.d
+ syntax.
+
+Tue Dec 17 05:18:17 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 1c5f4b3. Allows rubygems
+ repackagers to disable backward-compatible shared gem directory
+ behavior.
+ * test/rubygems: ditto.
+
+Tue Dec 17 05:14:35 2013 Eric Hodel <drbrain@segment7.net>
+
+ * NEWS (RDoc): Update version number so I don't have to change it
+ for the final release.
+
+Mon Dec 16 19:19:19 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_objspace_markable_object_p): should check special_const_p
+ first (by is_markable_object()).
+
+Mon Dec 16 19:12:54 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/objspace.c (reachable_object_from_root_i): use
+ compare_by_identity hash to avoid hash modify problem
+ during iteration.
+ [Bug #9252]
+
+ * ext/objspace/objspace.c (reachable_objects_from_root): ditto.
+
+Mon Dec 16 18:16:28 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_verify_internal_consistency): should not use
+ rb_objspace_each_objects() because it call rest_sweep().
+
+Mon Dec 16 18:07:30 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_objspace_markable_object_p): fix last commit (build error).
+
+Mon Dec 16 18:04:28 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_objspace_markable_object_p): it should be live objects.
+
+Mon Dec 16 18:00:51 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_objspace_each_objects): should not clear dont_lazy_sweep
+ flag in nested case.
+
+Mon Dec 16 16:40:35 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_method.c (rb_method_entry_make): fix WB miss.
+ Note that rb_method_entry_t::klass is not constified.
+ We may constify this field.
+
+ * test/ruby/test_alias.rb: add a test.
+
+Mon Dec 16 14:14:22 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: use gc_verify_internal_consistency() instead of
+ gc_check_before_marks_i() for check consistency
+ on RGENGC_CHECK_MODE >= 2.
+
+Mon Dec 16 14:01:48 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * process.c (make_clock_result): add :second as a unit for
+ Process.clock_gettime.
+
+Mon Dec 16 13:10:54 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: introduce GC.verify_internal_consistency method to verify GC
+ internal data structure.
+
+ Now this method only checks generation (old/young) consistency.
+
+Mon Dec 16 11:49:26 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c (gc_info_decode): Fix build errors when compiled with
+ RGENGC_ESTIMATE_OLDMALLOC=0
+ * gc.c (objspace_malloc_increase): ditto
+
+Sun Dec 15 13:38:29 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/objspace.c (reachable_object_from_root_i):
+ reachable objects should not include categories and
+ category_objects because it is noisy information.
+
+ In fact, objects created after calling
+ ObjectSpace.reachable_objects_from_root should not be included
+ as a returning hash objects. Currently, mswin64 platform has a
+ problem because of this behavior. Should we trace new objects?
+
+Sun Dec 15 07:09:28 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc: Update to RDoc master 263a9e5. This improves the
+ accessibility of the search box.
+
+Sat Dec 14 17:39:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_callee_setup_arg_complex): count post
+ arguments as mandatory arguments. [ruby-core:57706] [Bug #8993]
+
+ * vm_insnhelper.c (vm_yield_setup_block_args): ditto.
+
+Sat Dec 14 16:26:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (rubylibprefix): replace exec_prefix as well as
+ bindir and libdir. a patch by kimuraw (Wataru Kimura) at
+ [ruby-dev:47852]. [Bug #9160]
+
+Sat Dec 14 14:42:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/logger.rb (lock_shift_log): no need to rotate the log file
+ if it has been rotated by another process. based on the patch
+ by no6v (Nobuhiro IMAI) in [ruby-core:58620]. [Bug #9133]
+
+Sat Dec 14 13:01:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (mnew_from_me): method by respond_to_missing? should be
+ owned by the original class.
+
+Sat Dec 14 11:55:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/scanf.rb (IO#scanf): fix mistaken use of rescue modifier.
+ a patch by Mon_Ouie at [ruby-core:52813]. [Bug #7940]
+
+Sat Dec 14 11:44:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * util.c (ruby_qsort): fix potential stack overflow on a large
+ machine. based on the patch by Conrad Irwin <conrad.irwin AT
+ gmail.com> at [ruby-core:51816]. [Bug #7772]
+
+Sat Dec 14 11:25:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_mod_const_defined): support nested class path as
+ well as const_get. [Feature #7414]
+
+Sat Dec 14 01:31:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_rescue2): reuse tags pushed for body proc to protect
+ rescue proc too.
+
+Sat Dec 14 01:15:51 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (wmap_final_func): Bugfix. Should update *value to new pointer.
+
+Sat Dec 14 01:05:46 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/lib/socket.rb: Don't test $! in "ensure" clause because
+ it may be set before the body.
+ Reported by ko1 and mrkn. [ruby-core:59088] [Bug #9247]
+
+ * lib/cgi/core.rb: Ditto.
+
+ * lib/drb/ssl.rb: Ditto.
+
+Sat Dec 14 00:34:31 2013 Naohisa Goto <ngotogenome@gmail.com>
+
+ * internal.h (ruby_sized_xrealloc2): fix typo introduced in r44117,
+ which cause compile error on Solaris.
+
+Sat Dec 14 00:22:16 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c: (exec_recursive): use rb_catch_protect() instead of
+ rb_catch_obj() and PUSH_TAG(), and reduce pushing tags and
+ machine stack usage.
+
+Sat Dec 14 00:18:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (mnew_from_me): achieve the original defined_class from
+ prepended iclass, to fix inherited owner.
+
+ * proc.c (method_owner): return the defined class, but not the
+ class which the method object is created from.
+
+Fri Dec 13 22:29:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (method_owner): return the class where alias is defined, not
+ the class original method is defined.
+
+ * vm_method.c (rb_method_entry_make, rb_alias): store the originally
+ defined class in me. [Bug #7993] [Bug #7842] [Bug #9236]
+
+ * vm_method.c (rb_method_entry_get_without_cache): cache included
+ module but not iclass.
+
+Fri Dec 13 16:27:17 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c (gc_info_decode): Use :major_by=>:nofree as fallback reason
+ when other trigger conditions are present.
+
+Fri Dec 13 13:25:30 2013 Koichi Sasada <ko1@atdot.net>
+
+ * error.c: add Exception#backtrace_locations.
+ Now, there are no setter and independent from Exception#backtrace.
+ [Feature #8960]
+
+ * eval.c (setup_exception): set backtrace locations for `bt_location'
+ special attribute.
+
+ * vm_backtrace.c (rb_backtrace_to_location_ary): added.
+
+ * internal.h: ditto.
+
+ * test/ruby/test_backtrace.rb: add a test for
+ Exception#backtrace_locations.
+
+Fri Dec 13 12:01:07 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (garbage_collect_body): use rb_bug() and explicit error message
+ instead of using assert().
+ [Bug #9222]
+
+Fri Dec 13 11:52:41 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c: fix comment to remove the word "shady".
+
+ * variable.c: ditto.
+
+Fri Dec 13 11:33:55 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename *shady* func/macros.
+ * RVALUE_RAW_SHADY() -> RVALUE_WB_PROTECTED_RAW()
+ * RVALUE_SHADY() -> RVALUE_RAW_SHADY()
+ * rgengc_check_shady() -> rgengc_check_relation().
+ And fix some messages using "shady" to "non-WB-protected".
+
+Fri Dec 13 10:04:23 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/request_set/lockfile.rb: Import RubyGems master a8d0669
+ with a 1.8.7 compatibility fix.
+ * test/rubygems/test_gem_request_set_lockfile.rb: ditto.
+
+Fri Dec 13 09:50:49 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master ddac51f. Changes:
+
+ * Allow override for the shared gem installation directory for
+ rubygems packagers.
+
+ * Lock gem cache files for read and write to improve thread safety.
+
+ * Use io/console when available.
+
+ * Minor cleanup.
+
+ * test/rubygems: ditto.
+
+Fri Dec 13 08:15:31 2013 Aman Gupta <ruby@tmm1.net>
+
+ * class.c (include_modules_at): use RCLASS_M_TBL_WRAPPER for
+ equality checks. this avoids an unnecessary deference inside a tight
+ loop, fixing a performance regression from r43973.
+ * object.c (rb_obj_is_kind_of): ditto.
+ * object.c (rb_class_inherited_p): ditto.
+
+Wed Dec 13 02:00:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (VpSetPTR): fix for limitation of the resulting
+ precision.
+ [ruby-core:50269] [Bug #7458]
+
+ * test/bigdecimal/test_bigdecimal.rb (test_limit): add tests for the above
+ change.
+
+Wed Dec 13 01:56:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (VpAddAbs): put out a conditional branch from
+ the inside of while-loop.
+
+ * ext/bigdecimal/bigdecimal.c (VpSubAbs): ditto.
+
+Wed Dec 13 01:53:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (VPrint): be a static function, support another
+ dump formats, and add more information of the given bigdecimal.
+
+ * ext/bigdecimal/bigdecimal.h: ditto.
+
+Wed Dec 11 16:45:58 2013 Koichi Sasada <ko1@atdot.net>
+
+ * eval.c (rb_raise_jump): call c_return hook immediately after
+ popping `raise' frame.
+ Patches by deivid (David Rodriguez). [Bug #8886]
+
+ * test/ruby/test_settracefunc.rb: catch up this fix.
+
+Wed Dec 11 16:01:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash_reject): return a plain hash, without copying
+ the class, default value, instance variables, and taintedness.
+ they had been copied just by accident.
+ [ruby-core:59045] [Bug #9223]
+
+Wed Dec 11 15:36:15 2013 Aman Gupta <ruby@tmm1.net>
+
+ * compile.c (iseq_specialized_instruction): emit opt_aset instruction
+ to optimize Hash#[]= and Array#[]= when called with Fixnum argument.
+ [Bug #9227] [ruby-core:58956]
+
+Wed Dec 11 04:54:03 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master ec8ed22. Notable changes
+ include:
+
+ * Renamed extension_install_dir to extension_dir (backwards
+ compatible).
+
+ * Fixed creation of gem.deps.rb.lock file from
+ TestGemRequestSet#test_install_from_gemdeps_install_dir
+
+ * Fixed a typo and some documentation.
+
+ * test/rubygems: ditto.
+
+Wed Dec 11 03:18:08 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * insns.def: Fix optimization bug of Float#/ [Bug #9238]
+
+Tue Dec 10 23:58:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/date/date_strptime.c (date__strptime_internal): unset
+ case-insensitive flag for [:alpha:], which already implies both
+ cases, to get rid of backtrack explosion. [ruby-core:58984]
+ [Bug #9221]
+
+Tue Dec 10 23:44:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_hash): add salt to differentiate false and empty
+ array. [ruby-core:58993] [Bug #9231]
+
+ * hash.c (rb_any_hash, rb_hash_hash): ditto.
+
+Tue Dec 10 18:16:09 2013 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * man/ruby.1: [DOC] Use www.ruby-toolbox.com instead of RAA.
+
+Tue Dec 10 17:21:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (wmap_finalize, wmap_aset_update): use simple malloced array
+ instead of T_ARRAY, to reduce GC pressure.
+
+Tue Dec 10 15:56:48 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c (reflist_add): revert changes from r44109. it is unnecessary
+ after r44113
+ * gc.c (allrefs_i): fix whitespace
+ * gc.c (allrefs_roots_i): fix whitespace
+
+Tue Dec 10 15:46:03 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (allrefs_add): push obj only if allrefs table doesn't have
+ obj.
+
+ * gc.c (allrefs_roots_i): ditto.
+
+Tue Dec 10 15:28:10 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (RGENGC_CHECK_MODE): separate checkers to different modes.
+ * 2: enable generational bits check (for debugging)
+ * 3: enable livness check
+ * 4: show all references
+
+Tue Dec 10 15:15:37 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_marks_check): disable GC during checking and
+ restore malloc_increase info.
+
+Tue Dec 10 14:41:53 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c (reflist_add): return 0 if reference already exists
+ * gc.c (allrefs_add): return 1 on newly added references
+ * gc.c (allrefs_i): follow references to construct complete object
+ graph. before this patch, RGENGC_CHECK could fail to verify some WB
+ miss issues. [Bug #9226] [ruby-core:58959]
+
+Tue Dec 10 11:20:56 2013 Aman Gupta <ruby@tmm1.net>
+
+ * ext/objspace/objspace_dump.c (dump_object): include fstring flag on
+ strings. include gc flags (old, remembered, wb_protected) on all objects.
+ * ext/objspace/objspace_dump.c (Init_objspace_dump): initialize lazy
+ IDs before first use.
+ * gc.c (rb_obj_gc_flags): new function to retrieve object flags
+ * internal.h (RB_OBJ_GC_FLAGS_MAX): maximum flags allowed for one obj
+ * test/objspace/test_objspace.rb (test_dump_flags): test for above
+ * test/objspace/test_objspace.rb (test_trace_object_allocations):
+ resolve name before dump (for rb_class_path_cached)
+
+Tue Dec 10 07:48:29 2013 Aman Gupta <ruby@tmm1.net>
+
+ * vm_method.c (rb_clear_method_cache_by_class): fire
+ ruby::method-cache-clear probe on global or klass-level method cache
+ clear [Bug #9190]
+ * probes.d (provider ruby): new dtrace probe
+ * doc/dtrace_probes.rdoc: docs for new probe
+ * test/dtrace/test_method_cache.rb: test for new probe
+
+Tue Dec 10 06:14:11 2013 Eric Hodel <drbrain@segment7.net>
+
+ * ext/.document: Remove curses from documentable directories.
+
+Tue Dec 10 04:55:36 2013 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/lib/openssl/digest.rb: Deprecate OpenSSL::Digest::Digest
+ [Fixes GH-446] https://github.com/ruby/ruby/pull/446
+
+Tue Dec 10 00:41:42 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * ext/thread/thread.c: [DOC] add call-seq alias for Queue#enq, #<<, etc.
+
+ * ext/thread/thread.c (Init_thread): use rb_define_alias instead of
+ rb_alias to document alias.
+
+Mon Dec 9 20:00:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * internal.h (RCLASS_SERIAL): Add RCLASS_SERIAL as a convenience
+ accessor for RCLASS_EXT(klass)->class_serial.
+
+ * class.c, vm_insnhelper.c, vm_method.c: Use RCLASS_SERIAL
+
+Mon Dec 9 19:50:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * compile.c, insns.def, test/ruby/test_rubyvm.rb, vm.c, vm_core.h,
+ vm_insnhelper.c, vm_insnhelper.h, vm_method.c: Rename method_serial
+ to global_method_state and constant_serial to global_constant_state
+ after discussion with ko1.
+
+Mon Dec 9 18:50:43 2013 Aman Gupta <ruby@tmm1.net>
+
+ * hash.c (rb_hash_replace): fix segv on `{}.replace({})` introduced
+ in r44060 [Bug #9230] [ruby-core:58991]
+ * test/ruby/test_hash.rb: regression test for above
+
+Mon Dec 9 18:10:10 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (vm_stat): renamed from ruby_vm_stat.
+ Should not use ruby_ prefix here.
+
+Mon Dec 9 16:13:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (wmap_size): add ObjectSpace::WeakMap#size and #length.
+
+Mon Dec 9 15:26:17 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * test/test_curses.rb: removed.
+
+Mon Dec 9 13:36:55 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * ext/curses, sample/curses: removed curses.
+
+ * NEWS: added an entry for the above change.
+
+Mon Dec 9 12:26:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/objspace/object_tracing.c (newobj_i): use cached class path
+ only to get rid object allocation during NEWOBJ hook.
+ [ruby-core:58853] [Bug #9212]
+
+ * variable.c (rb_class_path_cached): returns cached class path
+ only, without searching and allocating new class path string.
+
+Mon Dec 9 11:14:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/date/date_parse.c (parse_time): unset case-insensitive flag
+ for [:alpha:], which already implies both cases, to get rid of
+ backtrack explosion. [ruby-core:58876] [Bug #9221]
+
+Mon Dec 9 08:40:40 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master bf37240. Fixes useless
+ error message with `gem install -g` with no gem dependencies file.
+ * test/rubygems: ditto.
+
+Mon Dec 9 04:52:25 2013 Eric Hodel <drbrain@segment7.net>
+
+ * NEWS: Update RubyGems entry with notable features.
+
+Mon Dec 9 04:43:54 2013 Eric Hodel <drbrain@segment7.net>
+
+ * ext/.document: Add syslog/lib and thread/thread.c to documentable
+ items. [ruby-trunk - Bug #9228]
+
+Mon Dec 9 04:28:50 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 096db36. Changes include
+ support for PATH in Gemfile.lock and a typo fix from Akira Matsuda.
+ * test/rubygems: ditto.
+
+Mon Dec 9 02:10:32 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/net/http/responses.rb:
+ Add `HTTPIMUsed`, as it is also supported by rack/rails.
+ RFC - http://tools.ietf.org/html/rfc3229
+ by Vipul A M <vipulnsward@gmail.com>
+ https://github.com/ruby/ruby/pull/447 fix GH-447
+
+Sun Dec 8 20:47:35 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (rb_get_kwargs): when values is non-null, remove
+ extracted keywords from the rest keyword argument.
+
+Sun Dec 8 20:26:54 2013 Yutaka Kanemoto <kanemoto@ruby-lang.org>
+
+ * common.mk (ruby.imp): avoid circular dependency on AIX
+
+Sun Dec 8 20:21:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * bigdecimal.c (BigDecimal_coerce): convert a Float to a BigDecimal instead
+ of converting the receiver to a Float. The reason is there are BigDecimal
+ instances with precisions that is smaller than the Float's precision.
+ [ruby-core:58756] [Bug #9192]
+
+ * test/bigdecimal/test_bigdecimal.rb: add tests for the above change.
+
+Sun Dec 8 18:28:20 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * NEWS: [DOC] update NEWS about GC.
+
+Sun Dec 8 17:52:24 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * object.c: [DOC] document Module#singleton_class?.
+
+Sun Dec 8 16:19:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (rb_get_kwargs): if optional is negative, unknown
+ keywords are allowed.
+
+ * vm_insnhelper.c (vm_callee_setup_keyword_arg): check unknown
+ keywords.
+
+Sun Dec 8 14:55:12 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * array.c (rb_ary_shuffle_bang, rb_ary_sample): rename local variables.
+
+Sun Dec 8 13:59:38 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * array.c (rb_ary_shuffle_bang, rb_ary_sample): check
+ unknown keywords.
+
+ * test/ruby/test_array.rb (test_shuffle, test_sample): tests for
+ the above.
+
+Sun Dec 8 13:01:11 2013 Aman Gupta <ruby@tmm1.net>
+
+ * vm.c (ruby_vm_stat): add RubyVM.stat() for access to internal cache
+ counters. this methods behaves like GC.stat, accepting an optional
+ hash or symbol argument. [Bug #9190] [ruby-core:58750]
+ * test/ruby/test_rubyvm.rb: test for new method
+
+Sun Dec 8 11:59:40 2013 Aman Gupta <ruby@tmm1.net>
+
+ * hash.c (rb_hash_replace): add a write barrier to fix GC mark miss on
+ hashes using Hash#replace [Bug #9226] [ruby-core:58948]
+
+Sun Dec 8 11:21:00 2013 Aman Gupta <ruby@tmm1.net>
+
+ * include/ruby/ruby.h: add RGENGC_WB_PROTECTED_NODE_CREF setting
+ In a large app, this reduces the size of
+ remembered_shady_object_count by 80%. [Bug #9225] [ruby-core:58947]
+ * gc.c (rb_node_newnode): add FL_WB_PROTECTED flag to NODE_CREF
+ * class.c (rewrite_cref_stack): insert OBJ_WRITE for NODE_CREF
+ * iseq.c (set_relation): ditto
+ * iseq.c (rb_iseq_clone): ditto
+ * vm_eval.c (rb_yield_refine_block): ditto
+ * vm_insnhelper.c (vm_cref_push): ditto
+ * vm_insnhelper.h (COPY_CREF): ditto
+
+Sun Dec 8 10:45:05 2013 Aman Gupta <ruby@tmm1.net>
+
+ * hash.c (hash_aset_str): revert r43870 due to performance issue
+ [Bug #9188] [ruby-core:58730]
+ * parse.y (assoc): convert literal string hash keys to fstrings
+ * test/ruby/test_hash.rb (class TestHash): expand test
+
+Sun Dec 8 10:22:38 2013 Aman Gupta <ruby@tmm1.net>
+
+ * parse.y (register_symid_str): use fstrings in symbol table
+ [Bug #9171] [ruby-core:58656]
+ * parse.y (rb_id2str): ditto
+ * string.c (rb_fstring): create frozen_strings on first usage. this
+ allows rb_fstring() calls from the parser (before cString is created)
+ * string.c (fstring_set_class_i): set klass on fstrings generated
+ before cString was defined
+ * string.c (Init_String): convert frozen_strings table to String
+ objects after boot
+ * ext/-test-/symbol/type.c (bug_sym_id2str): expose rb_id2str()
+ * test/-ext-/symbol/test_type.rb (module Test_Symbol): verify symbol
+ table entries are fstrings
+
+Sun Dec 8 10:24:20 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems.rb: Update version for upcoming ruby 2.1.0 RC.
+
+Sun Dec 8 10:21:36 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 14749ce. This fixes bugs
+ handling of gem dependencies lockfiles (Gemfile.lock).
+
+ * test/rubygems: ditto.
+
+Sun Dec 8 09:40:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * array.c (rb_ary_or): use RHASH_TBL_RAW instead of RHASH_TBL
+
+ * process.c (rb_execarg_fixup): use RHASH_TBL_RAW and insert write
+ barriers where appropriate
+
+ * vm.c (kwmerge_i): use RHASH_TBL_RAW
+
+ * vm.c (HASH_ASET): use rb_hash_aset instead of calling directly into
+ st_insert
+
+Sat Dec 7 11:15:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash_reject): copy unrejected elements only to new hash,
+ so that the change on the original receiver can affect.
+ [ruby-core:58914] [Bug #9223]
+
+Sat Dec 7 08:25:00 2013 Richo Healey <richo@psych0tik.net>
+
+ * test/ruby/test_struct.rb: Add regression test for question marks and
+ bangs in struct members. [Closes GH-468]
+
+Fri Dec 6 19:33:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (rb_extract_keywords, rb_get_kwargs): move from
+ vm_insnhelper.c.
+
+Fri Dec 6 19:18:02 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: change oldmalloc meaning.
+ Increase oldmalloc_increase with malloc_increase
+ instead of using obj_memsize_of().
+
+ This change will avoid the danger of memory full without major GC.
+
+Fri Dec 6 19:08:48 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (atomic_sub_nounderflow): not 0 but val itself.
+
+Fri Dec 6 18:37:11 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_objspace_alloc, Init_heap): initialize
+ oldmalloc_increase_limit at Init_heap.
+
+ rb_objspace_alloc() is not called on some platforms.
+
+Fri Dec 6 18:33:39 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (garbage_collect_body): bug fix.
+ initialize after recording.
+
+Fri Dec 6 17:49:46 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (atomic_sub_nounderflow): added to simplify atomic sub with
+ care about underflow.
+
+ * gc.c (objspace_malloc_increase): use it.
+
+Fri Dec 6 17:10:44 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (rb_get_kwargs): get keyword argument values from an
+ option hash, not only checking keys.
+
+ * dir.c (dir_initialize): use rb_get_kwargs.
+
+ * gc.c (gc_start_internal): ditto.
+
+Fri Dec 6 16:47:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * misc/ruby-mode.el (ruby-brace-to-do-end): split single line block.
+
+ * misc/ruby-mode.el (ruby-do-end-to-brace): shrink single line block
+ to one line.
+
+Fri Dec 6 16:16:30 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_start_internal): do not use rb_gc_start() and rb_gc().
+
+Fri Dec 6 15:24:30 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_start_internal, rb_gc): do not need
+ heap_pages_free_unused_pages() here.
+ It was done in after_sweep().
+
+ * gc.c (rb_gc): The reason is now GPR_FLAG_CAPI.
+
+Fri Dec 6 14:05:19 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c (gc_start_internal): GC.start() now accepts two optional
+ keyword arguments. These can be used to disable full_mark (minor
+ mark only) or disable immediate_sweep (use lazy sweep). These new
+ options are useful for benchmarking GC behavior, or performing minor
+ GC out-of-band.
+ * test/ruby/test_gc.rb (class TestGc): tests for new options.
+
+Fri Dec 6 11:51:28 2013 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/erb.rb: [DOC] fix broken link, Use rubygems.org and www.ruby-toolbox.com instead of RAA.
+ [Bug #9197]
+
+Fri Dec 6 10:50:54 2013 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/webrick/httprequest.rb: [DOC] Fix broken link of CGI specification by @udzura [fix GH-466]
+
+Thu Dec 6 01:27:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (GetVpValueWithPrec):
+ treat 0.0 and -0.0 of floating-point numbers specially for an optimization
+ and to correctly propagate its signbit to the result.
+ [Bug #9214] [ruby-core:58858]
+
+ * test/bigdecimal/test_bigdecimal.rb: add tests case for the above change.
+
+ * test/bigdecimal/test_bigdecimal_util.rb: ditto.
+
+Thu Dec 5 22:18:01 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (configuration): strip destdir part from prefix to get
+ rid of duplication. a patch by arton at [ruby-core:58859].
+ [ruby-core:58856] [Bug #9213]
+
+Thu Dec 5 21:53:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_or): lhs elements are preferred, so should not
+ replace with rhs elements.
+
+ * test/ruby/test_array.rb (test_OR_in_order): import the test failed
+ by r43969 from rubyspec/core/array/union_spec.rb.
+
+Thu Dec 5 21:05:42 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_info_decode): fix to avoid syntax error on VS2012.
+
+Thu Dec 5 19:35:35 2013 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * st.c: tweaked comment
+
+Thu Dec 5 19:21:10 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c (struct rb_objspace): rename internal last_collection_flags to
+ latest_gc_info
+ * gc.c (gc_latest_collection_info): add GC.latest_gc_info() with similar
+ behavior to GC.stat()
+ * gc.c (rb_gc_latest_gc_info): new c-api for above
+ * gc.c (gc_stat_internal): remove :last_collection_flags from GC.stat
+ * gc.c (gc_profile_decode_flags): remove GC::Profiler.decode_flags
+ * include/ruby/intern.h (rb_gc_latest_gc_info): export new c-api
+ * test/ruby/test_gc.rb (class TestGc): test for new behavior
+ * NEWS: note about new api
+
+ * gc.c (gc_stat_internal): raise TypeError on wrong type
+ * gc.c (gc_stat): fix error message
+
+Thu Dec 5 18:18:08 2013 Aman Gupta <ruby@tmm1.net>
+
+ * ext/objspace/gc_hook.c: remove this file
+ * ext/-test-/tracepoint/gc_hook.c: new filename for above
+ * ext/objspace/objspace.c: remove ObjectSpace.after_gc_start_hook=
+ * test/objspace/test_objspace.rb: remove test
+ * test/-ext-/tracepoint/test_tracepoint.rb: add above test for
+ tracepoint re-entry
+
+Thu Dec 5 17:44:53 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: change function names vm_ prefix to objspace_ prefix.
+ They are objspace_ functionality.
+
+Thu Dec 5 16:11:04 2013 Aman Gupta <ruby@tmm1.net>
+
+ * include/ruby/intern.h: add rb_gc_stat() for access to GC.stat
+ variables from c-api
+ * gc.c (rb_gc_stat): new c-api method. accepts either VALUE hash like
+ GC.stat, or VALUE symbol key and returns size_t directly. the second
+ form is useful to avoid allocations, i.e. for usage inside
+ INTERNAL_EVENT_GC tracepoints.
+ * gc.c (gc_stat): add GC.stat(:key) to return single value instead of hash
+ * gc.c (gc_stat_internal): helper method to retrieve single or all stat values
+ * test/ruby/test_gc.rb (class TestGc): test for new behavior
+ * NEWS: note about this new api
+
+Thu Dec 5 14:40:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash): revert r43981 and bail out to the outermost frame
+ when recursion is detected.
+
+Thu Dec 5 13:47:15 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (vm_malloc_size): added.
+ return malloc_usable_size() if possible.
+
+ * gc.c (MALLOC_ALLOCATED_SIZE): add new setting macro to enable
+ GC.allocated_size.
+ If platform supports `malloc_usable_size()' (or similar one),
+ GC.allocated_size can be implemented with this function.
+ Default is 0.
+
+ * gc.c (vm_xmalloc, vm_xrealloc, vm_xfree): use vm_malloc_size()
+ to detect collect allocated size.
+
+ * gc.c (vm_malloc_increase): refactoring.
+
+Thu Dec 5 13:19:03 2013 Aman Gupta <ruby@tmm1.net>
+
+ * include/ruby/ruby.h: remove INTERNAL_EVENT_GC_END and replace with
+ two new events: GC_END_MARK and GC_END_SWEEP
+ * gc.c (gc_after_sweep): emit GC_END_SWEEP after lazy sweep is done
+ * gc.c (gc_marks_body): emit GC_END_MARK at end of minor/major mark
+ * ext/-test-/tracepoint/tracepoint.c (struct tracepoint_track): tests
+ for new events.
+ * test/-ext-/tracepoint/test_tracepoint.rb (class TestTracepointObj):
+ ditto.
+ * NEWS: remove ObjectSpace.after_gc_*_hook. These are only a sample,
+ and will be removed before ruby 2.1.
+ * ext/objspace/gc_hook.c: remove ObjectSpace.after_gc_end_hook=
+
+Thu Dec 5 10:47:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby_atomic.h (ATOMIC_PTR_EXCHANGE): atomic exchange function for
+ a generic pointer.
+
+Thu Dec 5 10:47:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (finalize_deferred): flush all deferred finalizers while other
+ finalizers can get ready to run newly by lazy sweep.
+ [ruby-core:58833] [Bug #9205]
+
+Thu Dec 5 09:07:59 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c (ruby_gc_set_params): Accept safe_level argument so GC tuning
+ settings can be applied before rb_safe_level() is available.
+ * internal.h (rb_gc_set_params): ditto.
+ * ruby.c (process_options): Apply GC tuning early during boot process
+ so boot-time allocations can benefit. This also benefits any code
+ loaded in via `ruby -r`.
+
+Wed Dec 4 13:02:13 2013 Aman Gupta <ruby@tmm1.net>
+
+ * vm_trace.c (rb_suppress_tracing): Fix initialization of stack
+ allocated rb_trace_arg_t structure. Without this patch, sometimes
+ INTERNAL_EVENT_GC would be skipped accidentally inside
+ rb_threadptr_exec_event_hooks_orig().
+
+Wed Dec 4 12:57:24 2013 Aman Gupta <ruby@tmm1.net>
+
+ * string.c (fstr_update_callback): Improve implementation in r43968
+ based on feedback from @nagachika. In the existing case, we can
+ return ST_STOP to prevent any hash modification. In the !existing
+ case, set both key and value to the fstr.
+
+Wed Dec 4 12:47:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/delegate.rb (Delegator#method_missing): ignore the target if not
+ set, and delegate to global methods. [ruby-core:58572] [Bug #9155]
+
+ * lib/delegate.rb (Delegator#respond_to_missing): ditto.
+
+ * lib/delegate.rb (SimpleDelegator#__getobj__): yield and return if
+ not delegated but a block is given, like as Hash#fetch.
+
+ * lib/delegate.rb (DelegateClass#__getobj__): ditto.
+
+Tue Dec 3 23:48:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: check malloc_size() availability.
+
+ * gc.c: use malloc_size() with malloc/malloc.h if available.
+
+Tue Dec 3 23:06:20 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * object.c (rb_obj_clone): don't copy FL_WB_PROTECTED of a
+ original object.
+
+Tue Dec 3 22:32:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash_recursive): make similar (recursive) constructs
+ return same hash value. execute recursively, and rewind to the
+ topmost frame with an object which .eql? to the recursive
+ object, if recursion is detected.
+
+ * hash.c (rb_hash): detect recursion for all `hash' methods. each
+ `hash' methods no longer need to use rb_exec_recursive().
+
+Tue Dec 3 21:53:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (rb_catch_protect): new function similar to
+ rb_catch_obj(), but protect from all global jumps like as
+ rb_load_protect(), rb_protect(), etc.
+
+Tue Dec 3 20:18:46 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * object.c (rb_obj_clone): Protect FL_PROMOTED and FL_WB_PROTECTED
+ flags of a destination object.
+
+Tue Dec 3 20:16:38 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_hash_rehash): use hash_alloc() instead of rb_hash_new(),
+ to hide temporary object from ObjectSpace. [Bug #9187]
+
+Tue Dec 3 17:11:47 2013 Aman Gupta <ruby@tmm1.net>
+
+ * load.c (features_index_add_single): Move loaded_features_index array values off
+ the ruby heap. [Bug #9201] [ruby-core:58805]
+ * load.c (loaded_features_index_clear_i): Clean up off-heap array structure.
+ * vm.c (rb_vm_mark): Remove unnecessary mark_tbl for loaded_features_index.
+ This improves minor GC time by 15% in a large application.
+
+Tue Dec 3 17:01:45 2013 Aman Gupta <ruby@tmm1.net>
+
+ * include/ruby/ruby.h (struct RClass): Add wrapper struct around
+ RClass->m_tbl with serial. This prevents double marking method
+ tables, since many classes/modules can share the same method table.
+ This improves minor mark time in a large application by 30%.
+ * internal.h (struct method_table_wrapper): Define new
+ wrapper struct with additional serial.
+ * internal.h (RCLASS_M_TBL_INIT): New macro for initializing method
+ table wrapper and st_table.
+ * method.h (void rb_sweep_method_entry): Rename rb_free_m_table to
+ rb_free_m_tbl for consistency
+ * .gdbinit (define rb_method_entry): Update rb_method_entry gdb helper
+ for new method table structure.
+ * class.c: Use RCLASS_M_TBL_WRAPPER and
+ RCLASS_M_TBL_INIT macros.
+ * class.c (rb_include_class_new): Share WRAPPER between module and
+ iclass, so serial can prevent double marking.
+ * eval.c (rb_prepend_module): ditto.
+ * eval.c (rb_using_refinement): ditto.
+ * gc.c: Mark and free new wrapper struct.
+ * gc.c (obj_memsize_of): Count size of additional wrapper struct.
+
+Tue Dec 3 14:05:49 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_uniq_bang): remove duplicate code.
+
+Tue Dec 3 13:40:42 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (ary_add_hash): set and return values because string keys
+ will be frozen. [ruby-core:58809] [Bug #9202]
+
+ * array.c (rb_ary_uniq_bang): ditto.
+
+ * array.c (rb_ary_or): ditto.
+
+ * array.c (rb_ary_uniq): ditto.
+
+ * test/ruby/test_array.rb: tests for above.
+
+ The patch is from normalperson (Eric Wong).
+
+Tue Dec 3 12:20:21 2013 Aman Gupta <ruby@tmm1.net>
+
+ * string.c (rb_fstring): Use st_update instead of st_lookup +
+ st_insert.
+ * string.c (fstr_update_callback): New callback for st_update.
+
+Tue Dec 3 12:17:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/rdoc/constant.rb (RDoc::Constant#documented?): workaround for
+ NoMethodError when the original of alias is not found.
+
+Tue Dec 3 10:43:58 2013 Eric Hodel <drbrain@segment7.net>
+
+ * ext/openssl/lib/openssl/buffering.rb: Return ASCII-8BIT strings from
+ SSLSocket methods. [ruby-trunk - Bug #9028]
+ * test/openssl/test_ssl.rb: Test for the above.
+
+Tue Dec 3 09:42:27 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc: Update to RDoc master 900de99. Changes include:
+
+ Fixed documentation display of constants
+
+ Fixed handling of unknown parsers
+
+ * test/rdoc: ditto.
+
+Mon Dec 2 22:30:10 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * hash.c (getenv): fixed test failures introduced by r43950.
+ [ruby-core:58774] [Bug #9195] reported by phasis68 (Heesob Park).
+
+Mon Dec 2 21:49:19 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_rehash): make temporary st_table under the control
+ of GC. [Bug #9187]
+
+ * test/ruby/test_hash.rb: add a test for above.
+
+Mon Dec 2 17:23:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * variable.c (rb_mod_constants): when calling Module#constants with
+ inherit=false, there is no need to use a hashtable to deduplicate
+ constant names. [Feature #9196] [ruby-core:58786]
+
+Mon Dec 2 14:16:52 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/net/smtp.rb (Net::SMTP#critical): Always return a
+ Net::SMTP::Response. Patch by Pawel Veselov.
+ [ruby-trunk - Bug #9125]
+ * test/net/smtp/test_smtp.rb: Test for the above.
+
+Mon Dec 2 05:52:33 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master baa965b. Notable changes:
+
+ Copy directories to lib/ when installing extensions. This completes
+ the fix for [ruby-trunk - Bug #9106]
+
+ * test/rubygems: ditto.
+
+Mon Dec 2 02:03:47 2013 Shota Fukumori <her@sorah.jp>
+
+ * test/ruby/test_case.rb (test_nomethoderror):
+ Add test related to r43913, r43914
+
+Mon Dec 2 00:53:01 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * hash.c (getenv): use ANSI codepage version of getenv() for miniruby
+ on Windows.
+ [ruby-core:58732] [Bug #9189] reported by phasis68 (Heesob Park).
+
+Sun Dec 1 22:14:27 2013 Zachary Scott <e@zzak.io>
+
+ * doc/contributors.rdoc: [DOC] Import contributors from redmine wiki
+ Many wiki pages have become outdated and spam-ridden, we will import
+ these to trunk and begin maintaining them in ruby-trunk. This will
+ also allow new contributors to easily contribute patches to update
+ these pages, where previously a redmine account with wiki access was
+ required. Another bonus is having a contributors file to show thanks
+ to all of the people who have submitted a patch to Ruby.
+
+Sun Dec 1 18:03:26 2013 Zachary Scott <e@zzak.io>
+
+ * doc/maintainers.rdoc: [DOC] Current maintainers of Ruby
+
+Sun Dec 1 17:17:36 2013 Zachary Scott <e@zzak.io>
+
+ * doc/contributing.rdoc: [DOC] Current branch maintainers
+
+Sun Dec 1 17:16:36 2013 Zachary Scott <e@zzak.io>
+
+ * doc/contributing.rdoc: [DOC] Reporting other (ruby-lang.org) issues
+
+Sun Dec 1 17:15:51 2013 Zachary Scott <e@zzak.io>
+
+ * doc/contributing.rdoc: [DOC] Current platform maintainers
+
+Sun Dec 1 17:14:55 2013 Zachary Scott <e@zzak.io>
+
+ * doc/contributing.rdoc: [DOC] Reporting downstream distro issues
+
+Sun Dec 1 14:37:20 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_to_a): specify array capa.
+
+Sun Dec 1 14:15:36 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_rehash): fix to free new st_table when exception
+ is raised in do_hash(). [Bug #9187]
+
+Sun Dec 1 11:57:59 2013 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/lib/openssl/buffering.rb: Fix warning in copyright
+
+Sun Dec 1 08:27:28 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 66e5c39. Notable changes:
+
+ Implement gem.deps.rb (Gemfile) .lock support
+
+ Fixed `gem uninstall` for a relative directory in GEM_HOME.
+
+ * test/rubygems: ditto.
+
+Sun Dec 1 06:00:49 2013 Aman Gupta <ruby@tmm1.net>
+
+ * test/ruby/test_gc.rb (test_gc_reason): Force minor GC by consuming
+ free slots to fix test.
+
+Sat Nov 30 21:22:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (dir_initialize): check unknown keywords. [ruby-dev:47152]
+ [Bug #8060]
+
+Sat Nov 30 18:05:38 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32ole/win32ole.c (hash2named_arg): correct declaration to fix
+ build failure. a patch by phasis68 (Heesob Park) at
+ [ruby-core:58710]. [Bug #9184]
+
+Sat Nov 30 17:46:35 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (ruby_cleanup): determine exit status and signal to terminate
+ before finalization, to get rid of access destroyed T_DATA exception
+ object. [ruby-core:58643] [Bug #9167]
+
+Sat Nov 30 16:25:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enumerator.c (enumerator_with_index): should not store local variable
+ address to memoize the arguments. it is invalidated after the return.
+ [ruby-core:58692] [Bug #9178]
+
+Sat Nov 30 13:28:13 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * siphash.c (sip_hash24): fix for aligned word access little endian
+ platforms. [ruby-core:58658] [Bug #9172]
+
+Sat Nov 30 13:21:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (rb_yield_block): implement non-nil block argument.
+
+Fri Nov 29 20:59:39 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * vm_dump.c (rb_vmdebug_debug_print_pre): Bugfix. Get PC directly.
+ PC is cached into local stack and cfp->pc is incorrect at next of
+ branch or jump.
+ * vm_exec.h (DEBUG_ENTER_INSN): catch up this change.
+ * vm_core.h: update signature of rb_vmdebug_debug_print_pre.
+
+Fri Nov 29 20:43:57 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * compile.c: Bugsfix for dump_disasm_list.
+ rb_inspect denies a hidden object. So, insert wrapper that creates
+ the unhidden one.
+ adjust->label is null sometimes.
+ insn_data_line_no makes no sense at all.
+
+Fri Nov 29 18:06:45 2013 Shota Fukumori <her@sorah.jp>
+
+ * test/ruby/test_case.rb (test_method_missing): Test for r43913.
+
+Fri Nov 29 17:53:22 2013 Shota Fukumori <her@sorah.jp>
+
+ * vm_insnhelper.c (check_match): Fix SEGV with VM_CHECKMATCH_TYPE_CASE
+ and class of `pattern` has `method_missing`
+ [Bug #8872] [ruby-core:58606]
+
+Fri Nov 29 17:06:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (rb_yield_block): yield block with rb_block_call_func
+ arguments.
+
+ * range.c (range_each): use rb_yield_block.
+
+ * include/ruby/ruby.h (RB_BLOCK_CALL_FUNC_ARGLIST): constify argv.
+
+ * enum.c (rb_enum_values_pack): ditto.
+
+ * vm_eval.c (rb_block_call, rb_check_block_call): ditto.
+
+ * include/ruby/ruby.h (RB_BLOCK_CALL_FUNC_ARGLIST): for declaration
+ argument list of rb_block_call_func.
+
+Fri Nov 29 11:26:43 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_block_call_func): add blockarg. block
+ function can take block argument, e.g., proc {|&blockarg| ...}.
+
+Thu Nov 28 21:43:48 2013 Zachary Scott <e@zzak.io>
+
+ * doc/dtrace_probes.rdoc: [DOC] Import dtrace probes doc from wiki
+
+Thu Nov 28 21:17:32 2013 Zachary Scott <e@zzak.io>
+
+ * doc/contributing.rdoc: [DOC] Add heading above ChangeLog tips to
+ setup entry for commits, its not required. Actually easier if
+ contributors don't include a ChangeLog entry.
+
+Thu Nov 28 21:16:18 2013 Zachary Scott <e@zzak.io>
+
+ * doc/contributing.rdoc: [DOC] Add coding style heading for patch
+ rules
+
+Thu Nov 28 21:15:45 2013 Zachary Scott <e@zzak.io>
+
+ * doc/contributing.rdoc: [DOC] Add notes about deciding what to patch
+
+Thu Nov 28 19:43:45 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * benchmark/bm_hash_flatten.rb: added. r43896 is about 4 times faster
+ than 2.0.0p353.
+
+ * benchmark/bm_hash_keys.rb: added. r43896 is about 5 times faster
+ than 2.0.0p353.
+
+ * benchmark/bm_hash_values.rb: added. r43896 is about 5 times faster
+ than 2.0.0p353.
+
+Thu Nov 28 19:29:04 2013 Zachary Scott <e@zzak.io>
+
+ * doc/contributing.rdoc: [DOC] Add notes about slideshow proposals
+ from wiki page: HowToRequestFeatures
+
+Thu Nov 28 17:34:42 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * st.c: add st_values() and st_values_check().
+
+ * include/ruby/st.h: add prototypes for above.
+
+ * hash.c (rb_hash_values): use st_values_check() for performance
+ improvement if VALUE and st_data_t are compatible.
+
+Thu Nov 28 17:14:14 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * st.c (st_keys): fix not to use Qundef in st.c.
+
+ * include/ruby/st.h: define modified prototype.
+
+ * hash.c (rb_hash_keys): use modified st_keys().
+
+Thu Nov 28 16:34:43 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c: Expose details about last garbage collection via GC.stat.
+ * gc.c (gc_stat): Add :last_collection_flags for reason/trigger/type of
+ last GC run.
+ * gc.c (gc_prof_sweep_timer_stop): Record HAVE_FINALIZE GPR even
+ without GC_PROFILE_MORE_DETAIL.
+ * gc.c (gc_profile_flags): Add GC::Profiler.decode_flags to make sense
+ of GC.stat[:last_collection_flags]
+ * test/ruby/test_gc.rb (class TestGc): Test for above.
+
+Thu Nov 28 16:15:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_dup2): extract from rb_cloexec_dup2() and
+ redirect_dup2().
+
+Tue Nov 28 14:40:00 2013 Akira Matsuda <ronnie@dio.jp>
+
+ * lib/drb/ssl.rb: [Doc] Fix typo
+
+Thu Nov 28 13:56:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (Doxyfile): tool/file2lastrev.rb needs running with
+ BASERUBY since r43617. [ruby-dev:47823] [Bug #9169]
+
+Thu Nov 28 09:18:39 2013 Koichi Sasada <ko1@atdot.net>
+
+ * string.c (rb_fstring): fstrings should be ELTS_SHARED.
+ If we resurrect dying objects (non-marked, but not swept yet),
+ pointing shared string can be collected.
+ To avoid such issue, fstrings (recorded to fstring_table)
+ should not be ELTS_SHARED (should not have a shared string).
+
+Thu Nov 28 01:35:08 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * st.c (st_keys): fix to use st_index_t for size of hash.
+
+Thu Nov 28 00:36:52 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * st.c (st_keys): define st_keys(). it writes each key to buffer.
+
+ * hash.c (rb_hash_keys): use st_keys() for performance improvement
+ if st_data_t and VALUE are compatible.
+
+ * include/ruby/st.h: define macro ST_DATA_COMPATIBLE_P() to predicate
+ whether st_data_t and passed type are compatible.
+
+ * configure.in: check existence of builtin function to use in
+ ST_DATA_COMPATIBLE_P().
+
+Thu Nov 28 00:07:28 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * ruby_atomic.h: remove duplicate definitions between ATOMIC_XXX
+ and ATOMIC_SIZE_XXX.
+
+Wed Nov 27 23:55:50 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * ruby_atomic.h: define ATOMIC_SIZE_CAS() with
+ __atomic_compare_exchange_n() and refactoring.
+
+Tue Nov 27 21:43:00 2013 Akira Matsuda <ronnie@dio.jp>
+
+ * lib/irb/notifier.rb: [Doc] Fix typo
+ * ext/json/lib/json/common.rb: Ditto.
+
+Tue Nov 27 18:04:57 2013 Akira Matsuda <ronnie@dio.jp>
+
+ * lib/irb/notifier.rb: Fix typo
+
+Wed Nov 27 17:54:57 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_mark_stacked_objects): check only when check_mode > 0.
+
+Wed Nov 27 16:07:19 2013 Aman Gupta <ruby@tmm1.net>
+
+ * test/ruby/test_gc.rb (class TestGc): Fix warning in
+ test_expand_heap.
+
+Wed Nov 27 15:55:52 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c (Init_GC): Add new GC::INTERNAL_CONSTANTS for information about
+ GC heap/page/slot sizing.
+ * test/ruby/test_gc.rb (class TestGc): test for above.
+
+Wed Nov 27 15:21:17 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c (gc_page_sweep): Fix compile warning from last commit.
+ * hash.c (hash_aset_str): Re-use existing variable to avoid
+ unnecessary pointer dereferencing.
+
+Wed Nov 27 15:12:55 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_page_sweep): disable debug print.
+
+Wed Nov 27 15:05:59 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat): add new information heap_eden_page_length and
+ heap_tomb_page_length.
+
+ * test/ruby/test_gc.rb: fix to use GC.stat[:heap_eden_page_length]
+ instead of GC.stat[:heap_length].
+ This test expects `heap_eden_page_length' (used pages size).
+
+Wed Nov 27 15:02:53 2013 Aman Gupta <ruby@tmm1.net>
+
+ * test/ruby/test_eval.rb (class TestEval): Use assert_same instead of
+ assert_equal.
+ * test/ruby/test_hash.rb (class TestHash): ditto.
+ * test/ruby/test_iseq.rb (class TestISeq): ditto.
+
+Wed Nov 27 14:50:02 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rinda/ring.rb: Announce RingServer for the same process.
+ [ruby-trunk - Bug #9163]
+ * test/rinda/test_rinda.rb: Tests for the above.
+
+Wed Nov 27 14:37:33 2013 Aman Gupta <ruby@tmm1.net>
+
+ * test/ruby/test_eval.rb (class TestEval): Add test for shared eval
+ filenames via rb_fstring().
+ * test/ruby/test_iseq.rb (class TestISeq): Add test for shared
+ iseq labels via rb_fstring(). [Bug #9159]
+
+Wed Nov 27 14:24:55 2013 Aman Gupta <ruby@tmm1.net>
+
+ * hash.c (hash_aset_str): Use rb_fstring() to de-duplicate hash string
+ keys. Patch by Eric Wong. [Bug #8998] [ruby-core:57727]
+ * test/ruby/test_hash.rb (class TestHash): test for above.
+
+Wed Nov 27 10:39:39 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c: Rename rb_heap_t members:
+ used -> page_length
+ limit -> total_slots
+
+Wed Nov 27 08:24:49 2013 Aman Gupta <ruby@tmm1.net>
+
+ * compile.c: Use rb_fstring() to de-duplicate string literals in code.
+ [ruby-core:58599] [Bug #9159] [ruby-core:54405]
+ * iseq.c (prepare_iseq_build): De-duplicate iseq labels and source
+ locations.
+ * re.c (rb_reg_initialize): Use rb_fstring() for regex string.
+ * string.c (rb_fstring): Handle non-string and already-fstr arguments.
+ * vm_eval.c (eval_string_with_cref): De-duplicate eval source
+ filename.
+
+Wed Nov 27 07:13:54 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych.rb: psych version 2.0.2
+ * ext/psych/psych.gemspec: ditto
+
+Wed Nov 27 06:40:18 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/scalar_scanner.rb: fix support for negative
+ years.
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: ditto
+ * test/psych/test_date_time.rb: test for change.
+ Fixes: https://github.com/tenderlove/psych/issues/168
+
+Wed Nov 27 04:46:55 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/scalar_scanner.rb: fix regexp for matching TIME
+ strings.
+ * test/psych/test_date_time.rb: test for change.
+ Fixes: https://github.com/tenderlove/psych/issues/171
+
+Wed Nov 27 02:26:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (str_new4): copy the original capacity so that memsize of
+ frozen shared string returns correct size.
+
+Wed Nov 27 02:20:13 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_hash): should not ignore the rest of recursive
+ constructs.
+
+ * hash.c (rb_hash_hash): ditto.
+
+ * range.c (range_hash): ditto.
+
+ * struct.c (rb_struct_hash): ditto.
+
+ * test/-ext-/test_recursion.rb (TestRecursion): separate from
+ test/ruby/test_thread.rb.
+
+Tue Nov 26 22:43:36 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash): cut off if recursion detected to get rid of stack
+ overflow. [ruby-core:58567] [Bug #9151]
+
+Tue Nov 26 20:02:39 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_settracefunc.rb: add tests for a_call/a_return
+ by Brandur <brandur@mutelight.org> [Feature #9120]
+
+Tue Nov 26 19:29:52 2013 Koichi Sasada <ko1@atdot.net>
+
+ * common.mk: add useful config "set breakpoint pending on"
+ for run.gdb.
+
+Tue Nov 26 19:17:47 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/object_tracing.c (newobj_i): skip class_path if class
+ is frozen.
+
+ rb_class_path() can modify frozen classes (and causes errors).
+ This patch is temporary. We need no-modification/no-allocation
+ class path function.
+
+Tue Nov 26 18:12:13 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_trace.c: skip "exception check" and "reentrant check (only normal
+ events) for internal events.
+
+ Reentrant check for internal events are remaining.
+
+Tue Nov 26 17:38:16 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_trace.c: prohibit to specify normal events and internal events
+ simultaneously.
+ I will introduce special care for internal events later.
+
+ * ext/-test-/tracepoint/tracepoint.c: test this behavior.
+
+ * test/-ext-/tracepoint/test_tracepoint.rb: ditto.
+
+Tue Nov 26 16:30:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_readlink): fix buffer overflow on a long symlink. since
+ rb_str_modify_expand() expands from its length but not its capacity,
+ need to set the length properly for each expansion.
+ [ruby-core:58592] [Bug #9157]
+
+Tue Nov 26 14:23:17 2013 Aman Gupta <ruby@tmm1.net>
+
+ * ext/objspace/objspace_dump.c (dump_append_string_value): Escape
+ control characters for strict json parsers.
+ * ext/objspace/objspace_dump.c (objspace_dump): Document File/IO
+ output option.
+
+Tue Nov 26 11:43:19 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * ruby_atomic.h: use __atomic builtin functions supported by GCC.
+ __sync family are legacy functions now and it is recommended
+ that new code use the __atomic functions.
+ http://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
+
+ * configure.in: check existence of __atomic functions.
+
+Tue Nov 26 10:57:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.gemspec: revert Gem::Specification#date
+ for snapshot/release tarballs.
+
+Tue Nov 26 06:42:50 2013 Aman Gupta <ruby@tmm1.net>
+
+ * NEWS: Add ObjectSpace.after_gc_{start,end}_hook=
+ * ext/objspace/objspace_dump.c: [DOC] catch up dump/dump_all to r43679
+
+Tue Nov 26 04:12:10 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 612f85a. Notable changes:
+
+ Fixed installation and activation of git: and path: gems via
+ Gem.use_gemdeps
+
+ Improved documentation coverage
+
+ * test/rubygems: ditto.
+
+Mon Nov 25 22:23:03 2013 Zachary Scott <e@zzak.io>
+
+ * lib/xmlrpc.rb: [DOC] Fix link to xmlrpc4r site [Bug #9148]
+ Patch by Giorgos Tsiftsis
+
+Mon Nov 25 19:48:10 2013 Zachary Scott <e@zzak.io>
+
+ * lib/uri/common.rb: [DOC] typo fixes by @vipulnsward [Fixes GH-456]
+ https://github.com/ruby/ruby/pull/456
+ * lib/uri/generic.rb: [DOC] ditto.
+
+Mon Nov 25 14:34:42 2013 Zachary Scott <e@zzak.io>
+
+ * ext/bigdecimal/bigdecimal.gemspec: bump BigDecimal to 1.2.3 for
+ proper release date in RubyGems
+
+Mon Nov 25 14:25:08 2013 Zachary Scott <e@zzak.io>
+
+ * ext/bigdecimal/bigdecimal.gemspec: Remove Gem::Specification#date
+ We should rely on rubygems to create the date the gem was released
+ for each version.
+
+Mon Nov 25 06:53:30 2013 Koichi Sasada <ko1@atdot.net>
+
+ * internal.h: do not use ruby_sized_xrealloc() and ruby_sized_xfree()
+ if HAVE_MALLOC_USABLE_SIZE (or _WIN32) is defined.
+
+ We don't need these function if malloc_usable_size() is available.
+
+ * gc.c: catch up this change.
+
+ * gc.c: define HAVE_MALLOC_USABLE_SIZE on _WIN32.
+
+ * array.c (ary_resize_capa): do not use ruby_sized_xfree() with
+ local variable to avoid "unused local variable" warning.
+ This change only has few impact.
+
+ * string.c (rb_str_resize): ditto.
+
+Mon Nov 25 05:05:04 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/-ext-/tracepoint/test_tracepoint.rb: catch up GC.stat changes
+ at r43835.
+
+Mon Nov 25 04:45:59 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: continue to change OLDSPACE -> OLDMALLOC.
+ RGENGC_ESTIMATE_OLDSPACE -> RGENGC_ESTIMATE_OLDMALLOC.
+
+ * gc.c: add a new major GC reason GPR_FLAG_MAJOR_BY_OLDMALLOC.
+
+Mon Nov 25 04:16:09 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: change terminology "..._num" to "..._slots" about slot operation.
+ * final_num -> final_slots
+ * objspace_live_num() -> objspace_live_slots()
+ * objspace_limit_num() -> objspace_limit_slots()
+ * objspace_free_num() -> objspace_free_slots()
+
+Mon Nov 25 04:03:12 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat): add internal information.
+ * heap_swept_slot
+ * malloc_increase
+ * malloc_limit
+ * remembered_shady_object
+ * remembered_shady_object_limit
+ * old_object
+ * old_object_limit
+ * oldmalloc_increase
+ * oldmalloc_limit
+
+ * gc.c (gc_stat): rename names.
+ * heap_live_num -> heap_live_slot
+ * heap_free_num -> heap_free_slot
+ * heap_final_slot -> heap_final_slot
+
+ Quote from RDoc of GC.stat():
+ "The contents of the hash are implementation specific and may
+ be changed in the future."
+
+ * test/ruby/test_gc.rb: catch up this change.
+
+Mon Nov 25 03:59:45 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_gc.rb: catch up last commit.
+ Now RUBY_GC_OLDSPACE_LIMIT(...) is RUBY_GC_OLDMALLOC_LIMIT(...).
+
+Mon Nov 25 03:10:46 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: change terminology OLDSPACE -> OLDMALLOC.
+ (oldspace -> oldmalloc for variable names)
+
+ OLDSPACE is confusing because it is not includes slots.
+ To more clearly, rename such as (oldspace_limit -> oldmalloc_limit).
+ It is clear that it measures (estimates) malloc()'ed size.
+
+Mon Nov 25 00:50:03 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * internal.h: use __builtin_bswap16() if possible.
+
+ * configure.in: check existence of __builtin_bswap16().
+
+Sun Nov 24 22:24:19 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigxor_int): Apply BIGLO for long in a BDIGIT expression.
+ (bigor_int): Ditto.
+ (bigand_int): Ditto.
+
+Sun Nov 24 18:13:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/defines.h (SIZEOF_ACTUAL_BDIGIT): Defined.
+
+ * include/ruby/ruby.h (RBIGNUM_EMBED_LEN_MAX): Use
+ SIZEOF_ACTUAL_BDIGIT instead of SIZEOF_BDIGITS.
+ SIZEOF_BDIGITS can be different to sizeof(BDIGIT).
+
+Sun Nov 24 13:49:08 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/defines.h: Don't use int128_t for Bignum.
+ It's not always faster.
+
+ * bignum.c: Ditto.
+
+Sun Nov 24 10:18:15 2013 Aman Gupta <ruby@tmm1.net>
+
+ * NEWS: Add details about new debugging features and APIs.
+
+Sun Nov 24 09:37:20 2013 Andrew Vit <andrew@avit.ca>
+
+ * lib/csv.rb: Optimize header hashes by freezing string keys.
+ [ruby-core:58510]
+
+Sun Nov 24 09:18:06 2013 Aman Gupta <ruby@tmm1.net>
+
+ * ext/objspace/objspace_dump.c (dump_object): Use PRIuSIZE to print
+ size_t for better win32 compatibility.
+ * test/objspace/test_objspace.rb (test_dump_all): Hold reference to
+ test string to avoid failure due to GC. Reduce size of failure message
+ using grep(/TEST STRING/).
+
+Sun Nov 24 08:38:00 2013 Kyle Stevens <kstevens715@gmail.com>
+
+ * lib/csv.rb: If skip_lines is set to a String, convert it to a Regexp
+ to prevent the alternative, which is that each line in the CSV gets
+ converted to a Regexp when calling skip_lines#match.
+
+Sun Nov 24 01:03:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_power): Use FIX2LONG instead
+ of FIX2INT to avoid conversion error.
+
+Sun Nov 24 00:44:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (RBIGNUM_EMBED_LEN_MAX): define by macros
+ defined in defines.h, instead of complex and repeated expression.
+
+Sat Nov 23 22:22:26 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/ruby.h (RBIGNUM_EMBED_LEN_MAX): Limit the value to
+ less than 8.
+
+Sat Nov 23 19:52:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/lib/bigdecimal/math.rb (BigMath.E): Use BigMath.exp.
+ [Feature #6857] [ruby-core:47130]
+
+Sat Nov 23 19:46:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigMath_s_exp): Optimize the
+ calculation algorithm to reduce the number of divisions.
+ This optimization was proposed by Rafal Michalski.
+ [Feature #6857] [ruby-core:47130]
+
+Sat Nov 23 19:20:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_div2): The signature was
+ changed to allow us to pass arguments directly.
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_div3): Added for the role of
+ the old BigDecimal_div2.
+
+Sat Nov 23 12:31:00 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: fix global variable name.
+ Now we have following environments (and related variable names).
+
+ * RUBY_GC_HEAP_INIT_SLOTS
+ * RUBY_GC_HEAP_FREE_SLOTS
+ * RUBY_GC_HEAP_GROWTH_FACTOR (new from 2.1)
+ * RUBY_GC_HEAP_GROWTH_MAX_SLOTS (new from 2.1)
+
+ * obsolete
+ * RUBY_FREE_MIN -> RUBY_GC_HEAP_FREE_SLOTS (from 2.1)
+ * RUBY_HEAP_MIN_SLOTS -> RUBY_GC_HEAP_INIT_SLOTS (from 2.1)
+
+ * RUBY_GC_MALLOC_LIMIT
+ * RUBY_GC_MALLOC_LIMIT_MAX (new from 2.1)
+ * RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR (new from 2.1)
+
+ * RUBY_GC_OLDSPACE_LIMIT (new from 2.1)
+ * RUBY_GC_OLDSPACE_LIMIT_MAX (new from 2.1)
+ * RUBY_GC_OLDSPACE_LIMIT_GROWTH_FACTOR (new from 2.1)
+
+ * test/ruby/test_gc.rb: catch up this change.
+
+Sat Nov 23 09:45:49 2013 Aman Gupta <ruby@tmm1.net>
+
+ * marshal.c (w_object): Use HASH_PROC_DEFAULT directly from internal.h
+
+Sat Nov 23 08:43:23 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c: Rename heap_pages_swept_num to heap_pages_swept_slots to
+ clarify meaning (number of slots, not pages).
+
+Sat Nov 23 08:23:23 2013 Aman Gupta <ruby@tmm1.net>
+
+ * lib/set.rb (class SortedSet): Fix source_location for methods
+ defined via eval.
+
+Sat Nov 23 03:44:03 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master dcce4ff. Important changes
+ in this commit:
+
+ Remove automatic detection of gem dependencies files. This prevents a
+ security hole as described in [ruby-core:58490]
+
+ Fixed bugs for installing git gems.
+
+ * test/rubygems: ditto.
+
+Fri Nov 22 22:30:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_power):
+ Round the result value only if the precision is given.
+
+Fri Nov 22 17:20:50 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * transcode.c (str_transcode0): don't scrub invalid chars if
+ str.encode doesn't have explicit invalid: :replace.
+ workaround fix for see #8995
+
+Fri Nov 22 17:11:26 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * include/ruby/intern.h, internal.h: Expose rb_gc_count().
+
+Fri Nov 22 17:07:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.gemspec: version 1.2.2.
+
+Fri Nov 22 17:04:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_data_type):
+ Use RUBY_TYPED_FREE_IMMEDIATELY only if it is available.
+
+Fri Nov 22 16:49:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_power): Round the result value.
+ [Bug #8818] [ruby-core:56802]
+
+ * test/bigdecimal/test_bigdecimal.rb: Add a test for the above fix.
+
+Fri Nov 22 16:25:43 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (heap_set_increment): accept minimum additional page number.
+
+ * gc.c (gc_after_sweep): allocate pages to allocate at least
+ RUBY_HEAP_MIN_SLOTS.
+ [Bug #9137]
+
+Fri Nov 22 16:19:52 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * include/ruby/intern.h (rb_gc_set_params): Deprecate
+ rb_gc_set_params because it's only used in ruby internal.
+
+ * internal.h (ruby_gc_set_params): Declare rb_gc_set_params's
+ alias function.
+
+ * gc.c: ditto.
+
+ * ruby.c: use ruby_gc_set_params.
+
+Fri Nov 22 14:55:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigMath_s_exp): Insert rb_thread_check_ints.
+
+Fri Nov 22 14:35:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigMath_s_exp): Fix the inserting points
+ of RB_GC_GUARDs.
+
+Fri Nov 22 14:31:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c: Fix indentation.
+
+Fri Nov 22 14:03:00 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/nkf: merge nkf 2.1.3 2a2f2c5.
+
+Fri Nov 22 12:43:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * util.c (ruby_strtod): ignore too long fraction part, which does not
+ affect the result.
+
+Fri Nov 22 12:17:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/openssl/lib/openssl/buffering.rb (OpenSSL::Buffering#initialize):
+ initialize of a module should pass arguments to super.
+
+Fri Nov 22 12:02:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_settracefunc.rb: Ignore events from other threads.
+
+Fri Nov 22 10:35:57 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (ruby_vm_destruct): do not use ruby_xfree() after freeing
+ objspace.
+
+ * gc.c (ruby_mimfree): added. It is similar to ruby_mimmalloc().
+
+ * internal.h: ditto.
+
+Fri Nov 22 09:42:35 2013 Zachary Scott <e@zzak.io>
+
+ * test/digest/test_digest.rb: Reverse order of assert_equal
+ Reported by @splattael
+
+Fri Nov 22 09:03:16 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * gc.c: fix build failure on FreeBSD introduced by r43763.
+ malloc_usable_size() is defined by malloc_np.h on FreeBSD.
+
+ * configure.in: check malloc.h and malloc_np.h.
+
+Fri Nov 22 08:27:13 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 50a8210. Important changes
+ in this commit:
+
+ RubyGems now automatically checks for gem.deps.rb or Gemfile when
+ running ruby executables. This behavior is similar to `bundle exec
+ rake`. This change may be reverted before Ruby 2.1.0 if too many bugs
+ are found.
+
+ * test/rubygems: ditto.
+
+Thu Nov 21 22:33:59 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: RGENGC_CHECK_MODE should be 0.
+
+Thu Nov 21 21:40:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (VpAlloc): Fix the expr to adjust the size
+ of the digit array.
+
+Thu Nov 21 21:36:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_sqrt): Fix the precision of
+ the result BigDecimal of sqrt.
+ [Bug #5266] [ruby-dev:44450]
+
+ * test/bigdecimal/test_bigdecimal.rb: add tests for the above changes.
+
+Thu Nov 21 18:49:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (vm_xrealloc, vm_xfree): use malloc_usable_size() to obtain old
+ size if available.
+
+Thu Nov 21 18:47:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/delegate.rb (SimpleDelegator#__getobj__): target object must be set.
+
+ * lib/delegate.rb (DelegateClass#__getobj__): ditto.
+
+Thu Nov 21 18:28:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/tempfile.rb (Tempfile#initialize): use class method to get rid
+ of warnings when $VERBOSE.
+
+Thu Nov 21 17:43:29 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename initial_xxx variables to gc_params.xxx.
+ They are not only used initial values.
+
+ Chikanaga-san: Congratulations on RubyPrize!
+
+Thu Nov 21 17:16:00 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: enable "RGENGC_ESTIMATE_OLDSPACE" option as default.
+ Without this option, some application consumes huge memory.
+ (and there are only a few performance down)
+
+ Introduced new environment variables:
+ * RUBY_GC_HEAP_OLDSPACE (default 16MB)
+ * RUBY_GC_HEAP_OLDSPACE_MAX (default 128 MB)
+ * RUBY_GC_HEAP_OLDSPACE_GROWTH_FACTOR (default 1.2)
+
+ * gc.c (initial_malloc_limit): rename to initial_malloc_limit_min.
+
+Thu Nov 21 16:51:34 2013 Zachary Scott <e@zzak.io>
+
+ * ext/digest/bubblebabble/bubblebabble.c: Teach RDoc digest/bubblebabble
+
+Thu Nov 21 16:50:16 2013 Zachary Scott <e@zzak.io>
+
+ * test/digest/test_digest.rb: Add more tests for digest/bubblebabble
+
+Thu Nov 21 16:32:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/delegate.rb (Delegator#method_missing): try private methods defined in
+ Kernel after the target. [Fixes GH-449]
+
+Thu Nov 21 16:25:08 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * test/uri/test_generic.rb (URI#test_merge): Test uri + URI(path)
+ in addition to uri + path.
+
+Thu Nov 21 15:36:08 2013 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/lib/openssl/buffering.rb: [DOC] Fix HEREDOC comment for
+ OpenSSL::Buffering which breaks overview because of RDoc bug
+
+Thu Nov 21 14:46:57 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * eval_intern.h (SAVE_ROOT_JMPBUF): workaround for the failure of
+ test/ruby/test_exception.rb on Windows.
+ wrap by __try and __exception statements on mswin to raise SIGSEGV
+ when EXCEPTION_STACK_OVERFLOW is occurred, because MSVCRT doesn't
+ handle the exception.
+ however, (1) mingw-gcc doesn't support __try and __exception
+ statements, and (2) we cannot retry SystemStackError after this
+ change yet (maybe crashed) because SEH and longjmp() are too
+ uncongenial.
+
+ * signal.c (check_stack_overflow, CHECK_STACK_OVERFLOW): now defined on
+ Windows, too.
+
+ * thread_win32.c (ruby_stack_overflowed_p): ditto.
+
+Thu Nov 21 14:18:24 2013 Zachary Scott <e@zzak.io>
+
+ * object.c: [DOC] Clarify Object#dup vs #clone [Bug #9128]
+ Moving existing doc for this comparison to separate section of #dup
+ Adding examples to document behavior of #dup with Module#extend.
+ Based on a patch by stevegoobermanhill
+
+Thu Nov 21 14:06:02 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_marks_check): do not dump all refs.
+
+ * gc.c (allrefs_dump_i): fix output format.
+
+Thu Nov 21 13:43:07 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: change RGENGC_CHECK_MODE (>= 2) logic.
+ Basically, make an object graph of all of living objects before and
+ after marking and check status.
+
+ [Before marking: check WB sanity]
+ If there is a non-old object `obj' pointed from old object
+ (`parent') then `parent' or `obj' should be remembered.
+
+ [After marking: check marking miss]
+ Traversible objects with the object graph should be marked.
+ (However, this alert about objects pointed by machine context
+ can be false positive. We only display alert.)
+
+ [Implementation memo]
+ objspace_allrefs() creates an object graph.
+ The object graph is represented by st_table, key is object (VALUE)
+ and value is referring objects. Referring objects are stored by
+ "struct reflist".
+
+ * gc.c (init_mark_stack): do not use push_mark_stack_chunk() at init.
+ This pre-allocation causes failure on is_mark_stack_empty()
+ without any pushing.
+
+Thu Nov 21 13:40:20 2013 Zachary Scott <e@zzak.io>
+
+ * lib/observer.rb: [DOC] Clarify default observer method.
+ By @edward [Fixes GH-450] https://github.com/ruby/ruby/pull/450
+
+Thu Nov 21 13:32:53 2013 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/ossl_engine.c: [DOC] Documentation for OpenSSL::Engine
+ This patch is based off work by @vbatts in GH-436 completing the
+ documentation for this class and its methods.
+ https://github.com/ruby/ruby/pull/436
+
+Thu Nov 21 10:45:22 2013 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/lib/openssl/buffering.rb: Remove unused arguments from
+ OpenSSL::Buffering.new [Fixes GH-445]
+
+Thu Nov 21 10:30:47 2013 Zachary Scott <e@zzak.io>
+
+ * test/digest/test_digest.rb: Add test for Digest::SHA256.bubblebabble
+
+Wed Nov 20 20:54:01 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * tool/instruction.rb : fix typo.
+
+Wed Nov 20 19:45:22 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c (rand_init): Make it possible to specify arbitrary array
+ for init_genrand().
+
+Wed Nov 20 17:34:13 2013 Koichi Sasada <ko1@atdot.net>
+
+ * parse.y (rb_gc_mark_symbols): set global_symbols.minor_marked only
+ when full_mark is 0.
+ rb_gc_mark_symbols() (with full_mark == 1) can be called by other
+ than GC (such as rb_objspace_reachable_objects_from_root()).
+
+Wed Nov 20 11:46:38 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/json: merge JSON 1.8.1.
+ https://github.com/nurse/json/compare/002ac2771ce32776b32ccd2d06e5604de6c36dcd...e09ffc0d7da25d0393873936c118c188c78dbac3
+ * Remove Rubinius exception since transcoding should be working now.
+ * Fix https://github.com/flori/json/issues/162 reported by Marc-Andre
+ Lafortune <github_rocks@marc-andre.ca>. Thanks!
+ * Applied patches by Yui NARUSE <naruse@airemix.jp> to suppress
+ warning with -Wchar-subscripts and better validate UTF-8 strings.
+ * Applied patch by ginriki@github to remove unnecessary if.
+ * Add load/dump interface to JSON::GenericObject to make
+ serialize :some_attribute, JSON::GenericObject
+ work in Rails active models for convenient
+ SomeModel#some_attribute.foo.bar access to serialised JSON data.
+
+Wed Nov 20 01:39:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/rdoc/constant.rb (RDoc::Constant#documented?): workaround for
+ NoMethodError when the original of alias is not found.
+
+Tue Nov 19 23:38:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (--with-os-version-style): option to transform target
+ OS version string.
+
+Tue Nov 19 21:27:33 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/net/http/utils.rb (spawn_server): Specify zero for port to
+ avoid reusing an allocated port.
+
+ * test/net/http/test_http.rb: Don't specify port here.
+
+ * test/net/http/test_https.rb: Ditto.
+
+Tue Nov 19 18:52:10 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (heap_is_swept_object): use heap_page::before_sweep flag.
+
+Tue Nov 19 18:49:32 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_objspace_reachable_objects_from_root): do major marking.
+
+Tue Nov 19 18:45:40 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_gc_resurrect): added.
+ rb_fstring() used rb_gc_mark() to avoid freeing used string.
+ However, rb_gc_mark() set mark bit *and* pushes mark_stack.
+ rb_gc_resurrect() does only set mark bit if it is before sweeping.
+
+ * string.c (rb_fstring): use rb_gc_resurrect.
+
+ * internal.h: add decl.
+
+Tue Nov 19 09:47:02 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc: Update to RDoc master a1195ce. Changes include:
+
+ Improved accessibility of the main sidebar navigation.
+
+ Fixed handling of regexp options in HTML source highlighting.
+
+ * test/rdoc: ditto.
+
+Tue Nov 19 09:33:52 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 6a3d9f9. Changes include:
+
+ Compatibly renamed Gem::DependencyResolver to Gem::Resolver.
+
+ Added support for git gems in gem.deps.rb and Gemfile.
+
+ Fixed resolver bugs.
+
+ * test/rubygems: ditto.
+
+ * lib/rubygems/LICENSE.txt: Updated to license from RubyGems trunk.
+ [ruby-trunk - Bug #9086]
+
+ * lib/rubygems/commands/which_command.rb: RubyGems now indicates
+ failure when any file is missing. [ruby-trunk - Bug #9004]
+
+ * lib/rubygems/ext/builder: Extensions are now installed into the
+ extension install directory and the first directory in the require
+ path from the gem. This allows backwards compatibility with msgpack
+ and other gems that calculate full require paths.
+ [ruby-trunk - Bug #9106]
+
+
+Tue Nov 19 07:21:56 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in (LOCALTIME_OVERFLOW_PROBLEM): Define it for cross
+ compiling.
+ [ruby-core:58391] [Bug #9119] Reported by Luis Lavena.
+ Analyzed by Heesob Park.
+
+Tue Nov 19 05:55:05 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc/rubygems_hook.rb: Remove debugging puts committed by
+ accident.
+
+Mon Nov 18 22:47:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval_intern.h (TH_PUSH_TAG, TH_EXEC_TAG): refine stack overflow
+ detection. chain local tag after setjmp() successed on it, because
+ calling setjmp() also can overflow the stack.
+ [ruby-dev:47804] [Bug #9109]
+
+ * vm_eval.c (rb_catch_obj): now th->tag points previous tag until
+ TH_EXEC_TAG().
+
+ * thread_pthread.c (ruby_init_stack): set stack_start properly by
+ get_main_stack() if possible.
+
+Mon Nov 18 22:45:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval_jump.c (rb_exec_end_proc): unlink and free procs data before
+ calling for each procs. [Bug #9110]
+
+Sun Nov 17 06:33:32 2013 Shota Fukumori <her@sorah.jp>
+
+ * configure.in: Use $LIBS for base of $SOLIBS, also in darwin.
+ By this fix, environment that libgmp is located in $LIBS can build
+ ruby.
+
+Sun Nov 17 01:56:32 2013 Tanaka Akira <akr@fsij.org>
+
+ * thread_pthread.c (rb_thread_create_timer_thread): Show error
+ message instead of error number.
+ (thread_create_core): Ditto.
+
+ * cont.c (fiber_machine_stack_alloc): Ditto.
+
+Sat Nov 16 18:28:08 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/ultralightparser.rb
+ (REXML::Parsers::UltraLightParser#parse): Fix wrong :start_doctype
+ position.
+ [Bug #9061] [ruby-dev:47778]
+ Patch by Ippei Obayashi. Thanks!!!
+
+ * test/rexml/parser/test_ultra_light.rb: Add a test for this case.
+
+Sat Nov 16 02:13:56 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * cont.c : Introduce ensure rollback mechanism. Please see below.
+
+ * internal.h (ruby_register_rollback_func_for_ensure): catch up above change.
+ Add rollback mechanism API.
+
+ * vm_core.h (typedef struct rb_vm_struct): catch up above change.
+ Introduce ensure-rollback relation table.
+
+ * vm_core.h (typedef struct rb_thread_struct): catch up above change.
+ Introduce ensure stack.
+
+ * eval.c (rb_ensure): catch up above change.
+ Introduce ensure stack.
+
+ * hash.c : New function for rollback ensure, and register it to
+ ensure-rollback relation table. [ruby-dev:47803] [Bug #9105]
+
+ Ensure Rollback Mechanism:
+ A rollback's function is a function to rollback a state before ensure's
+ function execution.
+ When the jump of callcc is across the scope of rb_ensure,
+ ensure's functions and rollback's functions are executed appropriately
+ for keeping consistency.
+
+ Current API is unstable, and only internal use.
+
+ ruby_register_rollback_func_for_ensure(ensure_func,rollback_func)
+ This API create relation ensure's function to rollback's function.
+ By registered rollback's function, it is executed When jumping into
+ corresponding rb_ensure scope.
+
+Sat Nov 16 00:18:36 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * eval_jump.c (rb_exec_end_proc): fix double free or corruption error
+ when reentering by callcc. [ruby-core:58329] [Bug #9110]
+
+ * test/ruby/test_beginendblock.rb: test for above.
+
+Fri Nov 15 01:06:04 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/objspace/objspace_dump.c (dump_output): allow IO object as
+ output, and use Tempfile.create and return open file instead of
+ mkstemp() and path name for :file output.
+ [ruby-core:58266] [Bug #9102]
+
+ * test/objspace/test_objspace.rb (TestObjSpace#dump_my_heap_please):
+ remove temporary output file.
+
+Thu Nov 14 23:39:00 2013 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * ext/bigdecimal/lib/bigdecimal/util.rb: [DOC] remove example of
+ Rational#to_d without argument. [Bug #8958]
+
+Thu Nov 14 20:24:15 2013 Naohisa Goto <ngotogenome@gmail.com>
+
+ * ruby_atomic.h (ATOMIC_SIZE_CAS): fix compile error on Solaris
+ since r43460.
+
+Thu Nov 14 19:53:00 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/openssl/test_cipher.rb (test_aes_gcm_wrong_tag): Don't use
+ String#succ because it can make modified (wrong) auth_tag longer
+ than 16 bytes. The longer auth_tag makes that
+ EVP_CIPHER_CTX_ctrl (and internally aes_gcm_ctrl) fail.
+ [ruby-core:55143] [Bug #8439] reported by Vit Ondruch.
+
+Thu Nov 14 11:33:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (foreach_safe_i, hash_foreach_iter): deal with error detected
+ by ST_CHECK.
+
+ * st.c (st_foreach_check): call with non-error argument in normal case.
+
+Thu Nov 14 02:37:14 2013 Zachary Scott <e@zzak.io>
+
+ * ext/thread/thread.c: [DOC] This patch accomplishes the following:
+
+ - Teach RDoc about ConditionVariable
+ - Teach RDoc about Queue
+ - Teach RDoc about SizedQueue
+ - Use fully-qualified namespace for Document-method
+ This is necessary to separate definitions between classes
+ - Fix rdoc bug in call_seq vs. call-seq
+ - Correct doc for SizedQueue#pop patch by @jackdanger [Bug #8988]
+
+Thu Nov 14 01:11:54 2013 Zachary Scott <e@zzak.io>
+
+ * ext/bigdecimal/lib/bigdecimal/util.rb: [DOC] +precision+ is required
+
+Wed Nov 13 19:21:36 2013 Zachary Scott <e@zzak.io>
+
+ * ext/bigdecimal/lib/bigdecimal/util.rb: [DOC] Document the required
+ +precision+ argument for Rational#to_d [Bug #8958]
+
+Wed Nov 13 19:02:05 2013 Zachary Scott <e@zzak.io>
+
+ * ext/digest/*: [DOC] Fix several typos and broken http links.
+ Improved examples for Digest overview and fixed a broken example in
+ Digest::HMAC overview. This patch also adds a description of
+ Digest::SHA256.bubblebabble to the Digest overview.
+
+ Patched by @stomar [Bug #9027]
+
+Wed Nov 13 18:32:12 2013 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/ossl_config.c: [DOC] Document the following:
+
+ - OpenSSL::ConfigError
+ - OpenSSL::Config::DEFAULT_CONFIG_FILE
+
+ Patched by @vbatts via GH-436
+ https://github.com/ruby/ruby/pull/436
+
+Wed Nov 13 18:03:00 2013 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/ossl_asn1.c: [DOC] Document parts of
+ OpenSSL::ASN1::ObjectId included a fix for the class overview, which
+ previously showed the documentation for Constructive due to missing
+ ObjectId overview. This patch also includes a note for Primitive.
+
+ Based on a patch by @vbatts via GH-436
+ https://github.com/ruby/ruby/pull/436
+
+Wed Nov 13 17:19:36 2013 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/lib/openssl/config.rb: In #parse use +string+ for +str+
+
+Wed Nov 13 17:09:45 2013 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/lib/openssl/*.rb: [DOC] Document the following:
+
+ - Integer#to_bn
+ - OpenSSL::Buffering module
+ - Deprecated OpenSSL::Digest::Digest compatibility class
+ - OpenSSL::Config
+
+ These changes were based on a patch by @vbatts via GH-436
+ https://github.com/ruby/ruby/pull/436
+
+Wed Nov 13 10:55:43 2013 Zachary Scott <e@zzak.io>
+
+ * doc/regexp.rdoc: [DOC] Fix typo in Special global variables section.
+ Reported by Alex Johnson on ruby-doc.org
+
+Wed Nov 13 10:43:19 2013 Zachary Scott <e@zzak.io>
+
+ * hash.c: [DOC] Adds an example for Hash#store
+
+Wed Nov 13 09:03:40 2013 Zachary Scott <e@zzak.io>
+
+ * doc/regexp.rdoc: [DOC] add note about Bug #4044 as suggested by
+ duerst-san in [ruby-core:43612] [Fixes GH-443] Patched by @rosenfeld
+ https://github.com/ruby/ruby/pull/443
+
+Tue Nov 12 10:15:14 2013 Eric Hodel <drbrain@segment7.net>
+
+ * test/rubygems/insure_session.rb: Remove unused test file.
+
+Tue Nov 12 09:16:24 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master b9213d7. Changes include:
+
+ Fixed tests on Windows (I hope) by forcing platform for
+ platform-dependent tests.
+
+ Fixed File.exists? warnings.
+
+ Improved testing infrastructure.
+
+ * test/rubygems: ditto.
+
+ * test/rdoc/test_rdoc_rubygems_hook.rb: Switch to util_spec like
+ RubyGems.
+
+Mon Nov 11 18:31:12 2013 Aman Gupta <ruby@tmm1.net>
+
+ * internal.h: move common string/hash flags to include file.
+ * ext/objspace/objspace_dump.c: remove flags shared above.
+ * hash.c: ditto.
+ * string.c: ditto.
+
+Mon Nov 11 04:36:14 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/specification.rb: Include 2.2.0.preview.2 when checking
+ if extensions should be built. Fixes a ruby-ci failure.
+ * test/rubygems/test_gem_specification.rb: Test for the above.
+
+Mon Nov 11 03:15:56 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_trace.c (symbol2event_flag): add secret feature.
+ add a_call/a_return events.
+ a_call is call | b_call | c_call, and same as a_return.
+
+Mon Nov 11 02:51:17 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 4bdc4f2. Important changes
+ in this commit:
+
+ RubyGems now chooses the test server port reliably. Patch by akr.
+
+ Partial implementation of bundler's Gemfile format.
+
+ Refactorings to improve the new resolver.
+
+ Fixes bugs in the resolver.
+
+ * test/rubygems: Tests for the above.
+
+Mon Nov 11 01:02:06 2013 Zachary Scott <e@zzak.io>
+
+ * lib/timeout.rb: [DOC] Add note about change from #8730 [Fixes GH-440]
+ * NEWS: [DOC] Improve grammar on change to Timeout
+ Patched by @srawlins in https://github.com/ruby/ruby/pull/440
+
+Sun Nov 10 23:47:05 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * gc.c (rb_gcdebug_print_obj_condition): catch up recent changes
+ to compile on GC_DEBUG.
+
+Sun Nov 10 22:16:19 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (exc_cause): captured previous exception.
+
+ * eval.c (make_exception): capture previous exception automagically.
+ [Feature #8257]
+
+Sun Nov 10 08:37:20 2013 Zachary Scott <e@zzak.io>
+
+ * thread.c: [DOC] Remove duplicate reference
+
+Sun Nov 10 08:09:29 2013 Zachary Scott <e@zzak.io>
+
+ * lib/drb/drb.rb: [DOC] promote better windows-safe filename regular
+ expression in DRb Logger example. Reported by Chris Pheonix
+ [Bug #9074]
+
+Sun Nov 10 08:03:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (rb_define_finalizer, rb_undefine_finalizer): rename and export
+ finalizer functions.
+
+Sun Nov 10 07:41:22 2013 Zachary Scott <e@zzak.io>
+
+ * lib/weakref.rb: [DOC] fix typos by @xaviershay [Fixes GH-439]
+ https://github.com/ruby/ruby/pull/439
+
+Sun Nov 10 06:14:39 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * compile.c (iseq_compile_each): emit opt_str_freeze if the #freeze
+ method is called on a static string literal with no arguments.
+
+ * defs/id.def (firstline): add freeze so idFreeze is available
+
+ * insns.def (opt_str_freeze): add opt_str_freeze instruction which
+ pushes a frozen string literal without allocating a new object if
+ String#freeze is not overridden
+
+ * string.c (Init_String): define String#freeze
+
+ * vm.c (vm_init_redefined_flag): define BOP_FREEZE on String class as
+ a basic operation
+
+ * vm_insnhelper.h: ditto
+
+ [Feature #8992] [ruby-core:57705]
+
+Sun Nov 10 01:34:14 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (vm_malloc_increase): sweep immediately on GC due to malloc().
+ To reduce memory usage, sweep as soon as possible.
+ This behavior is same as Ruby 2.0.0 and before.
+
+Sun Nov 10 00:39:26 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/gc/gcbench.rb: output version description and GC::OPTS.
+
+Sun Nov 10 00:36:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (should_be_callable): allow private call since rb_eval_cmd
+ calls even private methods.
+
+Sun Nov 10 00:33:17 2013 Zachary Scott <e@zzak.io>
+
+ * lib/racc/rdoc/grammar.en.rdoc: [DOC] fix typo by Tsuyoshi Sawada
+ [Bug #9077]
+
+Sat Nov 9 22:35:35 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/rbinstall.rb (Gem::Specification.load): obtain spec date from
+ VCS for the case using git, RUBY_RELEASE_DATE is the last resort.
+ probably fixes [Bug #9085].
+
+Sat Nov 9 20:56:12 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * ext/objspace/object_tracing.c: use declarations in internal.h.
+
+ * ext/objspace/objspace.c: ditto
+
+Sat Nov 9 20:32:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/objspace/test_objspace.rb (test_dump_all): Make the test string
+ shorter to be an embedded string on 32bit environment as well as
+ 64bit environment.
+
+Sat Nov 9 15:00:16 2013 Zachary Scott <e@zzak.io>
+
+ * io.c: [DOC] ARGF.gets may return nil [Bug #9029] patch by znz
+
+Sat Nov 9 14:54:52 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rss/*: [DOC] document various constants @steveklabnik [Bug #8812]
+
+Sat Nov 9 14:50:09 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rss/rss.rb: [DOC] document Time#w3cdtf by @steveklabnik
+ [Bug #8821]
+
+Sat Nov 9 14:29:04 2013 Zachary Scott <e@zzak.io>
+
+ * ext/dl/cfunc.c: [DOC] fix typo in example [Bug #8944]
+ Patched by Heesob Park
+
+Sat Nov 9 13:59:58 2013 Zachary Scott <e@zzak.io>
+
+ * lib/test/unit/assertions.rb: [DOC] better example for assert_send()
+ Patch by Andrew Grimm [Bug #8975]
+
+Sat Nov 9 12:45:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * insns.def: unify ic_constant_serial and ic_class_serial into one field
+ ic_serial. This is possible because these fields are only ever used
+ exclusively with each other.
+
+ * insns.def: ditto
+ * vm_core.h: ditto
+ * vm_insnhelper.c: ditto
+
+Sat Nov 9 12:31:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * class.c: unify names of vm state version counters to 'serial'.
+ This includes renaming 'vm_state_version_t' to 'rb_serial_t',
+ 'method_state' to 'method_serial', 'seq' to 'class_serial',
+ 'vmstat' to 'constant_serial', etc.
+
+ * insns.def: ditto
+ * internal.h: ditto
+ * vm.c: ditto
+ * vm_core.h: ditto
+ * vm_insnhelper.c: ditto
+ * vm_insnhelper.h: ditto
+ * vm_method.c: ditto
+
+Sat Nov 9 09:22:29 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (gc_page_sweep, rgengc_rememberset_mark): Refactoring.
+ Get bitmaps directly.
+
+Sat Nov 9 09:16:36 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (RVALUE_PROMOTE_INFANT): Refactoring. Remove duplicated nonsense
+ code.
+
+Sat Nov 9 09:04:48 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (gc_marks_test): Bugfix. Fix a struct member name for build
+ with RGENGC_CHECK_MODE.
+
+Sat Nov 9 08:58:23 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c : Add GC_PROFILE_DETAIL_MEMORY option.
+ If GC_PROFILE_MORE_DETAIL && GC_PROFILE_DETAIL_MEMORY,
+ maxrss, minflt and majflt are added to each profile record.
+
+Sat Nov 9 07:41:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * internal.h (rb_vm_backtrace_object, rb_gc_count): make prototype
+ declarations, not old-K&R style.
+
+Sat Nov 9 06:11:14 2013 vo.x (Vit Ondruch) <vondruch@redhat.com>
+
+ * tool/rbinstall.rb (Gem::Specification#collect): make stable
+ Gem::Specification.files in default .gemspecs the different order of
+ "files" in .gemspec files makes them different therefore possibly
+ conflicting in multilib scenario. patch by vo.x (Vit Ondruch) at
+ [ruby-core:57544] [Bug #8623].
+
+Sat Nov 9 01:59:18 2013 Aman Gupta <ruby@tmm1.net>
+
+ * ext/objspace/objspace_dump.c: Add experimental methods to
+ dump objectspace as json: ObjectSpace.dump_all and
+ ObjectSpace.dump(obj). These methods are useful for debugging
+ reference leaks and memory growth in large ruby applications.
+ [Bug #9026] [ruby-core:57893] [Fixes GH-423]
+ * test/objspace/test_objspace.rb: tests for above.
+
+Sat Nov 9 00:26:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (GetLastError): already defined in windows.h on nowadays
+ cygwin, and caused the confliction with the system provided
+ definition on cygwin64. by @kou1okada [Fixes GH-433].
+
+Fri Nov 8 18:35:31 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * lib/open3.rb: receive arguments as keyword arguments.
+
+Fri Nov 8 13:19:26 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * io.c (rb_io_open_with_args): use RARRAY_CONST_PTR().
+
+ * io.c (rb_scan_open_args): use const qualifier for above.
+
+ * io.c (rb_open_file): ditto.
+
+ * io.c (rb_io_open_with_args): ditto.
+
+Fri Nov 8 11:35:06 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * dir.c, pack.c, ruby.c, struct.c, vm_eval.c: use RARRAY_CONST_PTR().
+
+Fri Nov 8 10:58:02 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * compile.c (iseq_build_from_ary_exception): use RARRAY_CONST_PTR().
+
+ * compile.c (iseq_build_from_ary_body): ditto.
+
+Fri Nov 8 10:49:34 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * enumerator.c (append_method): use RARRAY_CONST_PTR().
+
+ * enumerator.c (lazy_init_iterator): ditto.
+
+Fri Nov 8 02:44:29 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (vm_malloc_increase): check GVL before gc_rest_sweep().
+ vm_malloc_increase() can be called without GVL.
+ However, gc_rest_sweep() assumes acquiring GVL.
+ To avoid this problem, check GVL before gc_rest_sweep().
+ [Bug #9090]
+
+ This workaround introduces possibility to set malloc_limit as
+ wrong value (*1). However, this may be rare case. So I commit it.
+
+ *1: Without rest_sweep() here, gc_rest_sweep() can decrease
+ malloc_increase due to ruby_sized_xfree().
+
+Fri Nov 8 02:50:25 2013 Zachary Scott <e@zzak.io>
+
+ * lib/securerandom.rb: [DOC] specify arguments passed to ::random_bytes
+ By @chastell [Fixes GH-412] https://github.com/ruby/ruby/pull/412
+
+Fri Nov 8 02:43:01 2013 Zachary Scott <e@zzak.io>
+
+ * ext/objspace/object_tracing.c: [DOC] trace_object_allocations_stop
+ By @srawlins [Fixes GH-421] https://github.com/ruby/ruby/pull/421
+
+Fri Nov 8 02:34:20 2013 Zachary Scott <e@zzak.io>
+
+ * lib/net/ftp.rb: [DOC] Document Net::FTP.mdtm and .set_socket and fix
+ spelling typo, based on patch by @artfuldodger [Fixes GH-426]
+ https://github.com/ruby/ruby/pull/426
+
+Fri Nov 8 02:14:37 2013 Zachary Scott <e@zzak.io>
+
+ * array.c: [DOC] Add note about negative indices in Array overview
+ By @ckaenzig [Fixes GH-427] https://github.com/ruby/ruby/pull/427
+
+Fri Nov 8 02:09:12 2013 Zachary Scott <e@zzak.io>
+
+ * lib/csv.rb: [DOC] Fix typo in CSV.parse_line by @funky-bibimbap
+ [Fixes GH-430] https://github.com/ruby/ruby/pull/430
+
+Fri Nov 8 01:01:54 2013 Zachary Scott <e@zzak.io>
+
+ * golf_prelude.rb: syntax formatting for whitespace [Fixes GH-425]
+ Patch by @edward https://github.com/ruby/ruby/pull/425
+
+Thu Nov 7 19:36:09 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: modify malloc_limit strategy.
+
+ * fix default values:
+ GC_MALLOC_LIMIT_GROWTH_FACTOR
+ GC_MALLOC_LIMIT: 8MB -> 16MB
+ GC_MALLOC_LIMIT_MAX: 384MB -> 32MB
+
+ * algorithm of malloc_limit increment.
+ if (malloc_increase < malloc_limit) {
+ next_malloc_limit = malloc_limit * factor
+ if (malloc_limit > malloc_limit_max) {
+ malloc_limit = malloc_increase
+ }
+ }
+ This algorithm change malloc_limit from
+ 16MB -> 32MB slowly.
+ If malloc_limit exceeds malloc_limit_max, then
+ increase with malloc_increase.
+
+Thu Nov 7 11:06:05 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_shuffle_bang): use RARRAY_PTR_USE() without WB
+ because there are not new relations.
+
+Thu Nov 7 10:34:12 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_sample): use rb_ary_dup().
+
+Thu Nov 7 09:39:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_trace.c (rb_threadptr_exec_event_hooks_orig): errinfo should not
+ be propagated to trace blocks so that no argument raise does not
+ throw internal objects. [ruby-dev:47793] [Bug #9088]
+
+Wed Nov 6 21:30:55 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (gc_before_sweep): Change algorithm of malloc_limit to
+ conservative for closing to memory consumption of ruby 2.0.
+
+ * gc.c (GC_MALLOC_LIMIT, GC_MALLOC_LIMIT_GROWTH_FACTOR):
+ Adjust parameters for new algorithm.
+
+Wed Nov 6 21:16:51 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_shift_m): use RARRAY_PTR_USE() without WB because
+ there are not new relations.
+
+Wed Nov 6 21:05:20 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_reverse): use RARRAY_PTR_USE().
+
+Wed Nov 6 19:30:44 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * common.mk (help): add texts about gcbench.
+
+Wed Nov 6 16:32:32 2013 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/open3.rb: tweaked grammar in comments
+
+Wed Nov 6 11:46:36 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_sample): use RARRAY_AREF() and RARRAY_PTR_USE()
+ instead of RARRAY_PTR().
+
+Wed Nov 6 10:37:07 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_and): defer hash creation and some refactoring.
+
+Wed Nov 6 09:14:31 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/bm_vm1_gc_short_lived.rb: added.
+ These GC benchmarks do not reflect practical applications.
+ They are only for tuning.
+
+ * benchmark/bm_vm1_gc_short_with_complex_long.rb: added.
+
+ * benchmark/bm_vm1_gc_short_with_long.rb: added.
+
+ * benchmark/bm_vm1_gc_short_with_symbol.rb: added.
+
+ * benchmark/bm_vm1_gc_wb_ary.rb: added.
+
+ * benchmark/bm_vm1_gc_wb_obj.rb: added.
+
+ * benchmark/bm_vm_thread_queue.rb: added.
+ This benchmark is added to know how fast C version of thread.so.
+
+Wed Nov 6 09:13:32 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: define RGENGC_ESTIMATE_OLDSPACE == 0 if USE_RGENGC is 0.
+
+Wed Nov 6 07:13:18 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (Init_GC): add GC::OPTS to show options.
+
+Wed Nov 6 07:12:17 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/gc/gcbench.rb: add some options to make quiet.
+
+Wed Nov 6 04:14:25 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/to_ruby.rb: process merge keys before
+ reviving objects. Fixes GH psych #168
+ * test/psych/test_merge_keys.rb: test for change
+ https://github.com/tenderlove/psych/issues/168
+
+Tue Nov 5 21:21:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_thread.rb (test_thread_join_in_trap):
+ Run the test in a different process.
+
+Tue Nov 5 20:14:32 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (is_live_object): A hidden object may be a live object.
+ [ruby-dev:47788] [Bug #9072]
+
+Tue Nov 5 13:37:19 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: add support to estimate increase of oldspace memory usage.
+ This is another approach to solve an issue discussed at r43530.
+ This feature is disabled as default.
+
+ This feature measures an increment of memory consumption by oldgen
+ objects. It measures memory consumption for each objects when
+ the object is promoted. However, measurement of memory consumption
+ is not accurate now. So that this measurement is `estimation'.
+
+ To implement this feature, move memsize_of() function from
+ ext/objspace/objspace.c and expose rb_obj_memsize_of().
+
+ Some memsize() functions for T_DATA (T_TYPEDDATA) have problem to
+ measure memory size, so that we ignores T_DATA objects now.
+ For example, some functions skip NULL check for pointer.
+
+ The macro RGENGC_ESTIMATE_OLDSPACE enables/disables this feature,
+ and turned off as default.
+
+ We need to compare 3gen GC and this feature carefully.
+ (it is possible to enable both feature)
+ We need a help to compare them.
+
+ * internal.h: expose rb_obj_memsize_of().
+
+ * ext/objspace/objspace.c: use rb_obj_memsize_of() function.
+
+ * cont.c (fiber_memsize): fix to check NULL.
+
+ * variable.c (autoload_memsize): ditto.
+
+ * vm.c (vm_memsize): ditto.
+
+Tue Nov 5 04:03:07 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (GC_MALLOC_LIMIT_MAX): fix default value 512MB -> 384MB.
+ 512MB is huge.
+
+Tue Nov 5 03:31:23 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: add 3gen GC patch, but disabled as default.
+
+ RGenGC is designed as 2 generational GC, young and old generation.
+ Young objects will be promoted to old objects after one GC.
+ Old objects are not collect until major (full) GC.
+
+ The issue of this approach is some objects can promote as old
+ objects accidentally and not freed until major GC.
+ Major GC is not frequently so short-lived but accidentally becoming
+ old objects are not freed.
+
+ For example, the program "loop{Array.new(1_000_000)}" consumes huge
+ memories because short lived objects (an array which has 1M
+ elements) are promoted while GC and they are not freed before major
+ GC.
+
+ To solve this problem, generational GC with more generations
+ technique is known. This patch implements three generations gen GC.
+
+ At first, newly created objects are "Infant" objects.
+ After surviving one GC, "Infant" objects are promoted to "Young"
+ objects.
+ "Young" objects are promoted to "Old" objects after surviving
+ next GC.
+ "Infant" and "Young" objects are collected if it is not marked
+ while minor GC. So that this technique solves this problem.
+
+ Representation of generations:
+ * Infant: !FL_PROMOTED and !oldgen_bitmap [00]
+ * Young : FL_PROMOTED and !oldgen_bitmap [10]
+ * Old : FL_PROMOTED and oldgen_bitmap [11]
+
+ The macro "RGENGC_THREEGEN" enables/disables this feature, and
+ turned off as default because there are several problems.
+ (1) Failed sometimes (Heisenbugs).
+ (2) Performance down.
+ Especially on write barriers. We need to detect Young or Old
+ object by oldgen_bitmap. It is slower than checking flags.
+
+ To evaluate this feature on more applications, I commit this patch.
+ Reports are very welcome.
+
+ This patch includes some refactoring (renaming names, etc).
+
+ * include/ruby/ruby.h: catch up 3gen GC.
+
+ * .gdbinit: fix to show a prompt "[PROMOTED]" for promoted objects.
+
+Tue Nov 5 00:05:51 2013 Koichi Sasada <ko1@atdot.net>
+
+ * node.h: catch up comments for last commit.
+
+Tue Nov 5 00:02:00 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: rename FL_OLDGEN to FL_PROMOTED.
+ This flag represents that "this object is promoted at least once."
+
+ * gc.c, debug.c, object.c: catch up this change.
+
+Mon Nov 4 22:20:16 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/xmlrpc: Don't use fixed ports: 8070 and 8071.
+
+Mon Nov 4 15:25:52 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/xmlrpc/webrick_testing.rb (start_server): Initialize the server
+ at main thread to fail early.
+
+Mon Nov 4 10:08:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval_intern.h (TH_EXEC_TAG, TH_JUMP_TAG): get rid of undefined
+ behavior of setjmp() in rhs of assignment expression.
+ [ISO/IEC 9899:1999] 7.13.1.1
+
+Sun Nov 3 23:06:51 2013 Tanaka Akira <akr@fsij.org>
+
+ * sample/test.rb: Make temporary file names unique.
+
+Sun Nov 3 20:41:17 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/xmlrpc: Wrap definitions by TestXMLRPC module.
+
+Sun Nov 3 20:23:38 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/xmlrpc/webrick_testing.rb (stop_server): Don't try to shutdown
+ the server if the server is not started.
+
+Sun Nov 3 09:35:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * load.c (rb_feature_p): deal with default loadable suffixes.
+
+ * load.c (load_lock): initialize statically linked extensions.
+
+ * load.c (search_required, rb_require_safe): deal with statically
+ linked extensions.
+
+ * load.c (ruby_init_ext): defer initialization of statically linked
+ extensions until required actually. [Bug #8883]
+
+Sat Nov 2 15:14:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/logger.rb (Logger::LogDevice::LogDeviceMutex#lock_shift_log):
+ open file can't be removed or renamed on Windows. [ruby-dev:47790]
+ [Bug #9046]
+
+ * test/logger/test_logger.rb (TestLogDevice#run_children): don't use
+ fork.
+
+Sat Nov 2 07:08:43 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/logger.rb: Inter-process locking for log rotation
+ Current implementation fails log rotation on multi process env.
+ by sonots <sonots@gmail.com>
+ https://github.com/ruby/ruby/pull/428 fix GH-428 [Bug #9046]
+
+Fri Nov 1 23:24:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (wmap_mark_map): mark live objects only, but delete zombies.
+ [ruby-dev:47787] [Bug #9069]
+
+Fri Nov 1 22:45:54 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (struct heap_page, gc_page_sweep, gc_sweep): Refactoring for
+ performance. Add before_sweep condition to heap_page structure.
+
+ * gc.c (rb_gc_force_recycle): Use before_sweep member.
+
+ * gc.c (heap_is_before_sweep, is_before_sweep): Remove. They have not
+ already been used.
+
+Fri Nov 1 22:20:28 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (make_deferred): Refactoring. Collect codes which should be
+ atomic.
+
+ * gc.c (make_io_deferred, obj_free, rb_objspace_call_finalizer,
+ gc_page_sweep): Correspond to the above.
+
+Fri Nov 1 21:40:35 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (typedef struct rb_objspace): Refactoring. Move some members
+ into profile member.
+
+ * gc.c (newobj_of): Correspond to the above.
+
+ * gc.c (finalize_list): Ditto.
+
+ * gc.c (objspace_live_num): Ditto.
+
+ * gc.c (gc_page_sweep): Ditto.
+
+ * gc.c (rb_gc_force_recycle): Ditto.
+
+ * gc.c (garbage_collect_body): Ditto.
+
+ * gc.c (rb_gc_count): Ditto.
+
+ * gc.c (gc_stat): Ditto.
+
+ * gc.c (gc_prof_set_heap_info): Ditto.
+
+ * gc.c (gc_profile_dump_on): Ditto.
+
+Fri Nov 1 20:53:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_scrub): fix typo, should yield invalid byte
+ sequence to be scrubbed. reported by znz at IRC.
+
+Fri Nov 1 17:25:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (is_live_object): finalizer may not run because of lazy-sweep.
+ [ruby-dev:47786] [Bug #9069]
+
+Fri Nov 1 16:55:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_scrub): export with fixed length arguments, and
+ allow nil as replacement string instead of omitting.
+
+Fri Nov 1 06:20:44 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread.c (rb_mutex_struct): reduce rb_mutex_t size by 8 bytes
+ on 64bit platform. Patch by Eric Wong. [Feature #9068][ruby-core:58114]
+
+Fri Nov 1 01:08:33 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/gc/gcbench.rb: print HWM (high water mark) if possible.
+
+Thu Oct 31 21:48:31 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/streamparser.rb: Add dependency file require.
+ [Bug #9062] [ruby-dev:47779]
+ Reported by Ippei Obayashi. Thanks!!!
+
+Thu Oct 31 14:09:32 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_method.c (rb_method_entry_make): fix to pass an ISeq value.
+ OBJ_WRITTEN() accepts only VALUE.
+
+Wed Oct 30 19:07:57 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-additional.el (ruby-brace-to-do-end)
+ (ruby-do-end-to-brace, ruby-toggle-block): Remove functions that
+ are already in the latest released version of Emacs (24.3).
+ [Bug #7565]
+
+Wed Oct 30 12:44:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/Makefile.sub (config.status): add missing variables,
+ PLATFORM_DIR and THREAD_MODEL.
+
+Wed Oct 30 12:20:32 2013 Tanaka Akira <akr@fsij.org>
+
+ * time.c (v2w): Normalize a rational value to an integer if possible.
+ [ruby-core:58070] [Bug #9059] reported by Isaac Schwabacher.
+
+Wed Oct 30 12:08:41 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_uniq_bang): use rb_ary_modify_check() instead of
+ rb_ary_modify() because the array will be unshared soon.
+
+Wed Oct 30 03:25:10 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: make less garbage when
+ testing if a string is binary.
+
+Wed Oct 30 03:08:24 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: string subclasses should
+ not be considered to be binary. Fixes Psych / GH 166
+ https://github.com/tenderlove/psych/issues/166
+
+ * test/psych/test_string.rb: test for fix
+
+Tue Oct 29 23:01:18 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_zip): some refactoring.
+
+Tue Oct 29 22:11:37 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_uniq_bang): use st_foreach() instead of for loop.
+
+Tue Oct 29 20:01:58 2013 Koichi Sasada <ko1@atdot.net>
+
+ * add RUBY_TYPED_FREE_IMMEDIATELY to data types which only use
+ safe functions during garbage collection such as xfree().
+
+ On default, T_DATA objects are freed at same points as finalizers.
+ This approach protects issues such as reported by [ruby-dev:35578].
+ However, freeing T_DATA objects immediately helps heap usage.
+
+ Most of T_DATA (in other words, most of dfree functions) are safe.
+ However, we turned off RUBY_TYPED_FREE_IMMEDIATELY by default
+ for safety.
+
+ * cont.c: ditto.
+
+ * dir.c: ditto.
+
+ * encoding.c: ditto.
+
+ * enumerator.c: ditto.
+
+ * error.c: ditto.
+
+ * file.c: ditto.
+
+ * gc.c: ditto.
+
+ * io.c: ditto.
+
+ * iseq.c: ditto.
+
+ * marshal.c: ditto.
+
+ * parse.y: ditto.
+
+ * proc.c: ditto.
+
+ * process.c: ditto.
+
+ * random.c: ditto.
+
+ * thread.c: ditto.
+
+ * time.c: ditto.
+
+ * transcode.c: ditto.
+
+ * variable.c: ditto.
+
+ * vm.c: ditto.
+
+ * vm_backtrace.c: ditto.
+
+ * vm_trace.c: ditto.
+
+ * ext/bigdecimal/bigdecimal.c: ditto.
+
+ * ext/objspace/objspace.c: ditto.
+
+ * ext/stringio/stringio.c: ditto.
+
+ * ext/strscan/strscan.c: ditto.
+
+Tue Oct 29 19:48:33 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: fix typo (FL_WB_PROTECT -> FL_WB_PROTECTED).
+
+Tue Oct 29 18:45:08 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_trace.c (tp_free): removed because empty free function.
+ Use RUBY_TYPED_NEVER_FREE instead.
+
+Tue Oct 29 18:37:33 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: introduce new flags for T_TYPEDDATA.
+ * RUBY_TYPED_FREE_IMMEDIATELY: free the data given by DATA_PTR()
+ with dfree function immediately. Otherwise (default), the data
+ freed at finalization point.
+ * RUBY_TYPED_WB_PROTECTED: make this object with FL_WB_PROTECT
+ (not shady).
+
+ * gc.c (obj_free): support RUBY_TYPED_FREE_IMMEDIATELY.
+
+Tue Oct 29 16:49:03 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (vm_malloc_increase): decrease it more carefully.
+
+Tue Oct 29 16:24:52 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (heap_page_resurrect): return a page in tomb heap even if
+ freelist is NULL.
+
+Tue Oct 29 15:46:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby_atomic.h (ATOMIC_SIZE_CAS): new macro, compare and swap size_t.
+
+Tue Oct 29 12:08:05 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/readline/readline.c (readline_getc): Consider
+ NULL as input.
+
+Tue Oct 29 11:10:08 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c (gc_profile_total_time): fix off-by-one error in
+ GC::Profiler.total_time.
+ * test/ruby/test_gc.rb (class TestGc): test for above.
+
+Tue Oct 29 09:53:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * insns.def, vm.c, vm_insnhelper.c, vm_insnhelper.h, vm_method.c: split
+ ruby_vm_global_state_version into two separate counters - one for the
+ global method state and one for the global constant state. This means
+ changes to constants do not affect method caches, and changes to
+ methods do not affect constant caches. In particular, this means
+ inclusions of modules containing constants no longer globally
+ invalidate the method cache.
+
+ * class.c, eval.c, include/ruby/intern.h, insns.def, vm.c, vm_method.c:
+ rename rb_clear_cache_by_class to rb_clear_method_cache_by_class
+
+ * class.c, include/ruby/intern.h, variable.c, vm_method.c: add
+ rb_clear_constant_cache
+
+ * compile.c, vm_core.h, vm_insnhelper.c: rename vmstat field in
+ rb_call_info_struct to method_state
+
+ * vm_method.c: rename vmstat field in struct cache_entry to method_state
+
+Mon Oct 28 23:26:04 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/readline/test_readline.rb (teardown): Clear Readline.input and
+ Readline.output.
+
+Mon Oct 28 21:35:31 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/-test-/file/depend, ext/-test-/postponed_job/depend,
+ ext/-test-/tracepoint/depend: New files for dependencies.
+
+Mon Oct 28 15:32:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/openssl/depend (ossl.o): work around of dependency of
+ thread_native.h, which depends on headers by THREAD_MODEL.
+ [ruby-dev:47777]
+
+ * ext/openssl/extconf.rb: need THREAD_MODEL.
+
+Mon Oct 28 14:57:01 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * load.c (ruby_init_ext): share feature names between frame name and
+ provided features.
+
+Mon Oct 28 14:41:27 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-electric.el: Import ruby-electric.el 2.1 from
+ https://github.com/knu/ruby-electric.el.
+
+ * Hitting the newline-and-indent key within a comment fires
+ comment-indent-new-line.
+
+ * Introduce a new feature
+ `ruby-electric-autoindent-on-closing-char`.
+
+ * Fix fallback behavior of ruby-electric-space/return that
+ caused error with auto-complete.
+
+Mon Oct 28 13:17:17 2013 Or Cohen <orc@fewbytes.com>
+
+ * error.c (name_err_to_s): remove no longer needed overriding, since
+ r30455 which made exc_to_s almost same. Fixes [GH-413].
+
+Mon Oct 28 12:42:11 2013 Tanaka Akira <akr@fsij.org>
+
+ * common.mk, ext/objspace/depend, ext/coverage/depend,
+ ext/-test-/debug/depend, ext/date/depend: Update dependencies.
+
+Mon Oct 28 09:29:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * vm.c: vm_clear_all_cache is not necessary now we use a 64 bit counter
+ for global state version.
+
+ * vm_insnhelper.h: ruby_vm_global_state_version overflow is unnecessary
+
+Mon Oct 28 07:47:32 2013 Aman Gupta <ruby@tmm1.net>
+
+ * vm_backtrace.c (rb_profile_frame_classpath): do not use rb_inspect
+ directly, since it might have a custom implementation or show ivars.
+
+Mon Oct 28 04:10:41 2013 Aman Gupta <ruby@tmm1.net>
+
+ * vm_backtrace.c (rb_profile_frame_classpath): handle singleton
+ methods defined directly on an object.
+ * test/-ext-/debug/test_profile_frames.rb: test for above.
+
+Mon Oct 28 00:52:36 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * struct.c (new_struct): fix warning message, class name and encoding.
+
+Sun Oct 27 20:53:08 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/readline/readline.c: Include ruby/thread.h for
+ rb_thread_call_without_gvl2.
+ (readline_rl_instream, readline_rl_outstream): Record FILE
+ structures allocated by this extension.
+ (getc_body): New function extracted from readline_getc.
+ (getc_func): New function.
+ (readline_getc): Use rb_thread_call_without_gvl2 to invoke getc_func.
+ [ruby-dev:47033] [Bug #8749]
+ (clear_rl_instream, clear_rl_outstream): Close FILE structure
+ allocated by this extension reliably. [ruby-core:57951] [Bug #9040]
+ (readline_readline): Use clear_rl_instream and clear_rl_outstream.
+ (readline_s_set_input): Set readline_rl_instream.
+ (readline_s_set_output): Set readline_rl_outstream.
+ (Init_readline): Don't call readline_s_set_input because
+ readline_getc doesn't block other threads for any FILE structure now.
+
+ [ruby-dev:47033] [Bug #8749] reported by Nobuhiro IMAI.
+ [ruby-core:57951] [Bug #9040] reported by Eamonn Webster.
+
+Sat Oct 26 19:31:28 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * gc.c: catch up recent changes to compile on GC_DEBUG,
+ RGENGC_CHECK_MODE.
+
+Sat Oct 26 19:08:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * range.c (range_initialize_copy): disallow to modify after
+ initialized.
+
+Sat Oct 26 17:48:54 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/open-uri.rb (meta_add_field): : Re-implemented.
+ [ruby-core:58017] [Bug #9051] patch by Eamonn Webster.
+
+Sat Oct 26 14:35:09 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_profile_dump_on): use "Page" terminology.
+
+Sat Oct 26 13:25:45 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_sweep, gc_heap_lazy_sweep): fix measurement code.
+ We only need one sweep time measurement without lazy sweep.
+
+Sat Oct 26 11:59:13 2013 Tanaka Akira <akr@fsij.org>
+
+ * addr2line.c: Include ELF header after system headers (especially
+ sys/types.h) to avoid compilation failure,
+ "usr/include/sh3/elf_machdep.h:4:2: error: #error Define _BYTE_ORDER!",
+ on NetBSD/sh3 (dreamcast, hpcsh, landisk, mmeye).
+
+Sat Oct 26 11:35:22 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: tuning parameters.
+
+ * gc.c (GC_MALLOC_LIMIT): change default value to 16MB.
+
+ * gc.c (GC_MALLOC_LIMIT_GROWTH_FACTOR): change default value to 2.0.
+
+ * gc.c (gc_before_sweep): change decrease ratio of `malloc_limit'
+ from 1/4 to 1/10.
+
+Sat Oct 26 11:30:07 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (vm_malloc_increase): do gc_rest_sweep() before GC.
+ gc_rest_sweep() can reduce malloc_increase, so try it before GC.
+ Otherwise, malloc_increase can be less than malloc_limit at
+ gc_before_sweep(). This means that re-calculation of malloc_limit
+ may be wrong value.
+
+Sat Oct 26 06:35:41 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (gc_before_heap_sweep): Restructure code to mean clearly.
+ heap->freelist is connected to end of list.
+
+Sat Oct 26 04:01:35 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_before_heap_sweep): fix freelist management.
+ After rb_gc_force_recycle() for a object belonging to heap->freelist,
+ `heap->using_page->freelist' is not null.
+
+Thu Oct 24 21:57:24 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * parse.y: Remove +(binary) and -(binary) special cases
+ [Feature #9048]
+
+Thu Oct 24 12:45:53 2013 Zachary Scott <e@zzak.io>
+
+ * object.c: [DOC] Document first argument also takes string for:
+
+ rb_mod_const_get, rb_mod_const_set, rb_mod_const_defined
+
+ Also added note about NameError exception for invalid constant name
+
+Thu Oct 24 12:23:58 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread.c (rb_thread_terminate_all): add a comment why we need
+ state check and call terminate_i again.
+
+Thu Oct 24 12:15:02 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread.c (rb_thread_terminate_all): add a comment why infinite
+ sleep is safe.
+
+Thu Oct 24 07:41:42 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c: add new initial_growth_max tuning parameter.
+ [ruby-core:57928] [Bug #9035]
+ * gc.c (heap_set_increment): when initial_growth_max is set,
+ do not grow number of slots by more than growth_max at a time.
+ * gc.c (rb_gc_set_params): load optional new tuning value from
+ RUBY_HEAP_SLOTS_GROWTH_MAX environment variable.
+ * test/ruby/test_gc.rb (class TestGc): test for above.
+
+Thu Oct 24 01:34:12 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/win32.h (rb_infinity_float): suppress overflow in
+ constant arithmetic warnings. [ruby-core:57981] [Bug #9044]
+
+Thu Oct 24 00:11:24 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/ostruct.rb: raise NoMethodError with a #name and #args.
+ Raise RuntimeError when modifying frozen instances
+ instead of TypeError.
+ (OpenStruct#each_pair): Return an enumerator with size
+ (OpenStruct#delete): Use the converted argument.
+ Patches by Kenichi Kamiya. [Fixes GH-383]
+
+ * test/ostruct/test_ostruct.rb: Added tests for above.
+
+Thu Oct 24 00:10:22 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * array.c: Add Array#to_h [Feature #7292]
+
+ * enum.c: Add Enumerable#to_h
+
+Wed Oct 23 23:48:28 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c: Rename free_min to min_free_slots and free_min_page to
+ max_free_slots. The algorithm for heap growth is:
+ if (swept_slots < min_free_slots) pages++
+ if (swept_slots > max_free_slots) pages--
+
+Wed Oct 23 22:51:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/Makefile.sub (config.h): VC 2013 supports C99 mathematics
+ functions. [ruby-core:57981] [Bug #9044]
+
+Wed Oct 23 19:13:18 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: move increment from heap to heap_pages.
+ Share `increment' information with heaps.
+
+ * gc.c: change ratio of heap_pages_free_min_page
+ to 0.80.
+ This change means slow down page freeing speed.
+
+Wed Oct 23 17:52:03 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (heap_pages_free_unused_pages): cast to (int) for size_t
+ variable `i'.
+
+Wed Oct 23 17:39:35 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: introduce tomb heap.
+ Tomb heap is where zombie objects and ghost (freed slot) lived in.
+ Separate from other heaps (now there is only eden heap) at sweeping
+ helps freeing pages more efficiently.
+ Before this patch, even if there is an empty page at former phase
+ of sweeping, we can't free it.
+
+ Algorithm:
+ (1) Sweeping all pages in a heap and move empty pages from the
+ heap to tomb_heap.
+ (2) Check all existing pages and free a page
+ if all slots of this page are empty and
+ there is enough empty slots (checking by swept_num)
+
+ To introduce this patch, there are several tuning of GC parameters.
+
+Wed Oct 23 14:20:56 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_prof_sweep_timer_stop): catch up recent changes
+ to compile on GC_PROFILE_MORE_DETAIL=1.
+
+Wed Oct 23 11:43:27 2013 Zachary Scott <e@zzak.io>
+
+ * file.c: [DOC] fix rdoc format of File#expand_path from r43386
+
+Tue Oct 22 21:58:28 2013 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * vm_core.h (enum): avoid syntax error.
+
+ * method.h: ditto.
+
+ * internal.h: ditto.
+
+Tue Oct 22 19:53:16 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (Init_heap): move logics from heap_pages_init() and remove
+ heap_pages_init().
+
+Tue Oct 22 19:19:05 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: allow multiple heaps.
+ Now, objects are managed by page. And a set of pages is called heap.
+ This commit supports multiple heaps in the object space.
+
+ * Functions heap_* and rb_heap_t manages heap data structure.
+ * Functions heap_page_* and struct heap_page manage page data
+ structure.
+ * Functions heap_pages_* and struct rb_objspace_t::heap_pages
+ maintains all pages.
+ For example, pages are allocated from the heap_pages.
+
+ See https://bugs.ruby-lang.org/projects/ruby-master/wiki/GC_design
+ and https://bugs.ruby-lang.org/attachments/4015/data-heap_structure_with_multiple_heaps.png
+ for more details.
+
+ Now, there is only one heap called `eden', which is a space for all
+ new generated objects.
+
+Tue Oct 22 18:26:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/pp.rb (object_address_group): Use Kernel#to_s to obtain the class
+ name and object address.
+ This fix a problem caused by %p in C generates variable length
+ address.
+ Reported by ko1 via IRC.
+
+Tue Oct 22 16:57:48 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * file.c (File#expand_path): [DOC] improve documentation of File#expand_path.
+ Based on patch by Prathamesh Sonpatki. [ruby-core:57734] [Bug #9002]
+
+Tue Oct 22 15:59:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (glob_helper): don't skip current directories if FNM_DOTMATCH
+ is given. [ruby-core:53108] [Bug #8006]
+
+Tue Oct 22 14:53:11 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_trace.c: exterminate Zombies.
+ There is a bug that T_ZOMBIE objects are not collected.
+ Because there is a pass to miss finalizer postponed job
+ with multi-threading. This patch solve this issue.
+
+ * vm_trace.c (rb_postponed_job_register_one): set
+ RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(th) if another same job
+ is registered.
+ There is a possibility to remain a postponed job without
+ interrupt flag.
+
+ * vm_trace.c (rb_postponed_job_register_one): check interrupt
+ carefully.
+
+ * vm_trace.c (rb_postponed_job_register_one): use additional space
+ to avoid buffer full.
+
+ * gc.c (gc_finalize_deferred_register): check failure.
+
+ * thread.c (rb_threadptr_execute_interrupts): check
+ `postponed_job_interrupt' immediately. There is a possibility
+ to miss this flag.
+
+Tue Oct 22 12:11:16 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: check if the given CFLAGS and LDFLAGS are working, and
+ bail out early if not.
+
+Tue Oct 22 00:06:57 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_file_exists_p): warn deprecated name. [Bug #9041]
+
+Mon Oct 21 23:57:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * encoding.c (load_encoding): should preserve outer errinfo, so that
+ expected exception may not be lost. [ruby-core:57949] [Bug #9038]
+
+Sun Oct 20 15:41:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (rb_io_reopen): create a new, temporary FD via rb_sysopen and
+ call rb_cloexec_dup2 on it to atomically replace the file fptr->fd
+ points to. This leaves no possible window where fptr->fd is invalid
+ to userspace (even for any threads running w/o GVL). based on the
+ patch by Eric Wong <normalperson@yhbt.net> at [ruby-core:57943].
+ [Bug #9036]
+
+Sun Oct 20 15:29:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (rb_syserr_fail_path_in): new function split from
+ rb_sys_fail_path_in to raise SystemCallError without errno.
+
+ * internal.h (rb_syserr_fail_path): like rb_sys_fail_path but without
+ errno.
+
+Sun Oct 20 13:58:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_obj_wb_unprotect, rb_obj_written),
+ (rb_obj_write): suppress unused-parameter warnings.
+
+Sun Oct 20 10:32:48 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update RubyGems to master 0886307. This commit
+ improves documentation and should bring ruby above 75% documented on
+ rubyci.
+
+Sun Oct 20 09:30:56 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 3de7e0f. Changes:
+
+ Only attempt to build extensions for newly-installed gems. This
+ prevents compilation attempts at gem activation time for gems that
+ already have extensions built.
+
+ Fix crash in the dependency resolver for dependencies that cannot be
+ resolved.
+
+ * test/rubygems: ditto.
+
+Sun Oct 20 05:24:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * variable.c (rb_class2name): should return real class name, not
+ singleton class or iclass.
+
+Sun Oct 20 04:18:48 2013 Aman Gupta <ruby@tmm1.net>
+
+ * variable.c (rb_class2name): call rb_tmp_class_path() directly to
+ avoid extra rb_str_dup() from rb_class_name().
+
+Sat Oct 19 19:59:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/file.c (code_page): use simple array instead of st_table.
+
+ * encoding.c (rb_locale_encindex): defer initialization of win32 code
+ page table until encoding db loaded.
+
+Sat Oct 19 08:25:05 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: fix rb_objspace_t.
+ * make "struct heap" and move most of variables
+ in rb_objspace_t::heap.
+ * rename rb_objspace_t::heap::sorted to
+ rb_objspace_t::heap_sorted_pages
+ and make a macro heap_sorted_pages.
+ * rename rb_objspace_t::heap::range to
+ rb_objspace_t::heap_range and rename macros
+ lomem/himem to heap_lomem/heap_himem.
+
+Sat Oct 19 07:14:40 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 42543b6. Changes:
+
+ Fix `gem update` for gems with multiple platforms.
+
+ * test/rubygems: ditto.
+
+Sat Oct 19 06:55:52 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 0a3814b. Changes:
+
+ Fixed extension directory in Gem::Specification#require_paths.
+
+ Allow installation of gems when $HOME is nonexistent or unwritable.
+
+ Use proper API in InstallCommand.
+
+ Improve support for path option in gem dependency files.
+
+ Remove warnings.
+
+ * test/rubygems: ditto.
+
+Fri Oct 18 15:23:34 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: change terminology of heap.
+ Change "slot" to "page". "Slot" is a space of RVALUE.
+ 1. "Heap" consists of a set of "heap_page"s (pages).
+ 2. Each "heap_page" has "heap_page_body".
+ 3. "heap_page_body" has RVALUE (a.k.a. "slot") spaces.
+ 4. "sorted" is a sorted array of "heap_page"s, sorted
+ by address of heap_page_body (for "is_pointer_to_heap").
+
+ See https://bugs.ruby-lang.org/attachments/4008/data-heap_structure.png.
+
+Fri Oct 18 09:40:43 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master cee6788. Changes:
+
+ Fix test failure on vc10-x64 Server on rubyci.org due to attempting
+ to File.chmod where it is not supported.
+
+ Continuing work on improved gem dependencies file (Gemfile) support.
+
+ * test: ditto.
+
+Fri Oct 18 06:02:49 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master f738c67. Changes:
+
+ Fixed test bug for ruby with ENABLE_SHARED = no
+
+ * test/rubygems: ditto.
+
+Fri Oct 18 00:57:07 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/tsort.rb (TSort.tsort): Extracted from TSort#tsort.
+ (TSort.tsort_each): Extracted from TSort#tsort_each.
+ (TSort.strongly_connected_components): Extracted from
+ TSort#strongly_connected_components.
+ (TSort.each_strongly_connected_component): Extracted from
+ TSort#each_strongly_connected_component.
+
+Thu Oct 17 18:50:08 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (CALC_EXACT_MALLOC_SIZE_CHECK_OLD_SIZE): introduced.
+ This macro enable checker compare with allocated memory and
+ declared old_size of sized_xfree and sized_xrealloc.
+
+Thu Oct 17 18:45:41 2013 Koichi Sasada <ko1@atdot.net>
+
+ * string.c (STR_HEAP_SIZE): includes TERM_LEN(str).
+
+ * string.c (rb_str_memsize): use STR_HEAP_SIZE().
+
+Thu Oct 17 17:43:00 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_call_method): set ci->me to 0 when the
+ original method of a refined method is undef to avoid SEGV.
+
+ * vm_method.c (rb_method_entry_without_refinements): return 0 when
+ the original method of a refined method is undef to avoid SEGV.
+
+ * test/ruby/test_refinement.rb: related test.
+
+Thu Oct 17 17:38:36 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c, internal.h: rename ruby_xsizefree/realloc to
+ rb_sized_free/realloc.
+
+ * array.c: catch up these changes.
+
+ * string.c: ditto.
+
+Thu Oct 17 17:32:51 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c, string.c: use ruby_xsizedfree() and ruby_xsizedrealloc().
+
+ * internal.h (SIZED_REALLOC_N): define a macro as REALLOC_N().
+
+Thu Oct 17 17:11:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (console_emulator_p): check by comparison between
+ module handle of WriteConsoleW and kernel32.dll.
+
+ * configure.in, win32/Makefile.sub, win32/setup.mak: no longer need
+ psapi.lib.
+
+Thu Oct 17 16:53:30 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c, internal.h: add new internal memory management functions.
+ * void *ruby_xsizedrealloc(void *ptr, size_t new_size, size_t old_size)
+ * void ruby_xsizedfree(void *x, size_t size)
+ These functions accept additional size parameter to calculate more
+ accurate malloc_increase parameter which control GC timing.
+ [Feature #8985]
+
+Thu Oct 17 14:21:34 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/file.c (rb_file_expand_path_internal): fix memory leaks at
+ a non-absolute home exception.
+
+Thu Oct 17 14:06:39 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/object_tracing.c (newobj_i): fix memory leak.
+ There is possibility to remain info due to missing FREEOBJ event.
+ FREEOBJ events are skipped while suppress_tracing state, for example,
+ during trace events are invoking.
+
+Thu Oct 17 12:30:16 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/tsort.rb (TSort.each_strongly_connected_component_from):
+ Extracted from TSort#each_strongly_connected_component_from.
+
+Thu Oct 17 11:07:06 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 941c21a. Changes:
+
+ Restored method bundler wants to remove for compatibility.
+
+ Improvements to Gemfile compatibility.
+
+ * test/rubygems: ditto.
+
+Thu Oct 17 08:08:11 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/object_tracing.c (newobj_i): add workaround.
+ some bugs hits this check.
+
+ * ext/objspace/object_tracing.c (object_allocations_reporter_i): cast as pointer.
+
+Thu Oct 17 07:36:53 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 2abce58. Changes:
+
+ Fixed documentation generation when sdoc and json are installed as
+ gems.
+
+ Added some missing documentation.
+
+Thu Oct 17 07:10:26 2013 Zachary Scott <e@zzak.io>
+
+ * ext/curses/curses.c: [DOC] Cleaned up formatting consistency of rdoc
+ comments for Curses, including period spacing and column width.
+
+ This patch also fixed some typos. Thanks to @postmodern for the patch!
+ [Fixes GH-420] https://github.com/ruby/ruby/pull/420
+
+Thu Oct 17 06:58:42 2013 Zachary Scott <e@zzak.io>
+
+ * ext/date/date_core.c: [DOC] plural grammar fixed by @scott113341
+ Contributed via documenting-ruby.org: documenting-ruby/ruby#16
+ https://github.com/documenting-ruby/ruby/pull/16
+
+Thu Oct 17 05:52:31 2013 Zachary Scott <e@zzak.io>
+
+ * ext/io/nonblock/nonblock.c: [DOC] Document io/nonblock by reprah
+ [Fixes GH-418] https://github.com/ruby/ruby/pull/418 based on the
+ original discussion from documenting-ruby/ruby#18
+
+Thu Oct 17 05:40:33 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (objspace_each_objects): do not skip empty RVALUEs.
+
+Thu Oct 17 05:31:31 2013 Koichi Sasada <ko1@atdot.net>
+
+ * error.c (rb_bug_reporter_add): return simply 0 if failed.
+ Please check return value.
+
+Thu Oct 17 05:17:33 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/object_tracing.c: add new method
+ ObjectSpace.trace_object_allocations_debug_start for GC debugging.
+ If you encounter the BUG "... is T_NONE" (and so on) on your
+ application, please try this method at the beginning of your app.
+
+Wed Oct 16 22:35:27 2013 Zachary Scott <e@zzak.io>
+
+ * ext/io/nonblock/nonblock.c: use rb_cIO instead of VALUE
+
+Wed Oct 16 17:45:13 2013 Koichi Sasada <ko1@atdot.net>
+
+ * bootstraptest/runner.rb: check nil before calling `signal?'
+ for a process status.
+
+Wed Oct 16 17:37:17 2013 Koichi Sasada <ko1@atdot.net>
+
+ * error.c, internal.h (rb_bug_reporter_add): add a new C-API.
+ rb_bug_reporter_add() allows to register a function which
+ is called at rb_bug() called.
+
+ * ext/-test-/bug_reporter/bug_reporter.c: add a test for this C-API.
+
+ * ext/-test-/bug_reporter/extconf.rb: ditto.
+
+ * test/-ext-/bug_reporter/test_bug_reporter.rb: ditto.
+
+Wed Oct 16 15:14:21 2013 Koichi Sasada <ko1@atdot.net>
+
+ * NEWS: add a line into NEWS for last commit.
+
+Wed Oct 16 15:09:14 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/objspace.c: add a new method `reachable_objects_from_root'.
+ ObjectSpace.reachable_objects_from_root returns all objects referred
+ from root (called "root objects").
+ This feature is for deep object analysis.
+
+ * test/objspace/test_objspace.rb: add a test.
+
+Wed Oct 16 15:00:21 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master b955554. Changes:
+
+ Fixed NameError for Gem::Ext due to re-entering file lookup in
+ RubyGems' overridden require. Bug by Koichi Sasada.
+
+ Fixed possible circular require warning in tests.
+
+ Used existing constant for `gem install -g` dependency file list.
+
+ * test/rubygems: ditto.
+
+Wed Oct 16 09:42:42 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 278d00d. Changes:
+
+ Fixes building extensions without a "clean" make rule
+
+ Adds gem dependency file autodetection to "gem install -g"
+
+ * test/rubygems: Tests for the above.
+
+Wed Oct 16 09:12:23 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master commit 2a74263. This fixes
+ several bugs in RubyGems 2.2.0.preview.1.
+
+ * test/rubygems: ditto.
+
+Wed Oct 16 07:25:02 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c (gc_mark_roots): rename roots to be categories
+ instead of function names.
+
+Tue Oct 15 19:18:13 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.h (rb_objspace_reachable_objects_from_root): added.
+ This API provides information which objects are root objects.
+ `category' shows what kind of root objects.
+
+ * gc.c (gc_mark_roots): separate from gc_marks_body().
+
+Tue Oct 15 17:47:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c: Fix a typo. MacOS X doesn't have ENOTSUPP.
+
+Mon Oct 14 12:32:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (process_options): load statically linked extensions before
+ rubygems, because of ext/thread.
+
+ * ruby.c (process_options): use gem_prelude instead of requiring
+ rubygems directly when --enable=gems is given.
+
+ * Makefile.in (DEFAULT_PRELUDES): always use gem_prelude regardless of
+ --disable-rubygems.
+
+Mon Oct 14 11:07:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (have_framework): should append framework options to
+ $LIBS, not $LDFLAGS. The former is propagated to exts.mk when
+ enable-static-linked-ext.
+
+ * lib/mkmf.rb (create_makefile): ranlib on static library, not DLLIB.
+
+Sun Oct 13 23:53:40 2013 Andrew Grimm <andrew.j.grimm@gmail.com>
+
+ * vsnprintf.c: Fix spelling from compliment to complement.
+ Patch by @agrimm.
+
+ * include/ruby/ruby.h: ditto
+
+Sun Oct 13 20:59:27 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm.c (Init_BareVM): initialize defined_module_hash here,
+ Init_top_self() is too late to register core classes/modules.
+
+ * compile.c (compile_array_): no hash to merge if it is empty.
+
+ * vm.c (m_core_hash_merge_kwd): just check keys if only one argument
+ is given, without merging.
+
+Sat Oct 12 06:35:01 2013-10-11 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rake: Update to rake 10.1.0
+ * bin/rake: ditto.
+ * test/rake: ditto.
+
+ * NEWS: Update NEWS to include rake 10.1.0 and links to release notes.
+
+Sat Oct 12 03:26:04 2013 Koichi Sasada <ko1@atdot.net>
+
+ * class.c, variable.c, gc.c (rb_class_tbl): removed.
+
+ * vm.c, vm_core.h (rb_vm_add_root_module): added to register as a
+ defined root module or class.
+ This guard helps mark miss from defined classes/modules they are
+ only referred from C's global variables in C-exts.
+ Basically, it is extension's bug.
+ Register to hash object VM has.
+ Marking a hash objects allows generational GC supports.
+
+ * gc.c (RGENGC_PRINT_TICK): disable (revert).
+
+Sat Oct 12 03:24:49 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_method.c (rb_gc_mark_unlinked_live_method_entries):
+ revert last commit to introduce debug prints.
+
+Fri Oct 11 21:05:19 2013 Koichi Sasada <ko1@atdot.net>
+
+ * internal.h, parse.y: use `full_mark' instead of `full_marking'.
+
+Fri Oct 11 20:58:16 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: use terminology `full_mark' instead of `minor_gc'
+ in mark functions.
+
+Fri Oct 11 20:46:09 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: use __GNUC__ instead of __GCC__.
+
+Fri Oct 11 20:35:59 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c, parse.y: support generational Symbol related marking.
+ Each symbols has String objects respectively to represent
+ Symbols.
+ These objects are marked only when:
+ * full marking
+ * new symbols are added
+ This hack reduce symbols (related strings) marking time.
+ For example, on my Linux environment, the following code
+ "20_000_000.times{''}"
+ with 40k symbols (similar symbol number on Rails 3.2.14 app,
+ @jugyo tells me) boosts, from 7.3sec to 4.2sec.
+
+ * internal.h: change prototype of rb_gc_mark_symbols().
+
+Fri Oct 11 19:27:22 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-electric.el: Import ruby-electric.el 2.0.1 which fixes
+ a bug and a flaw with auto-end introduced in the revamp.
+
+ * ruby-forward-sexp is inappropriate here because it moves the
+ cursor past the keyword.
+
+ * Fix a reversed looking-back check in
+ ruby-electric--block-beg-keyword-at-point-p.
+
+ * Do not add end again if space or return is hit repeatedly
+ after a block beginning keyword.
+
+Fri Oct 11 18:12:47 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/gc_hook.c: prohibit reentrant.
+
+Fri Oct 11 18:11:34 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_trace.c (rb_postponed_job_flush): fix bit operation.
+
+Fri Oct 11 17:33:24 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-electric.el: Import ruby-electric.el 2.0 from
+ https://github.com/knu/ruby-electric.el which integrates changes
+ from another fork by @qoobaa.
+
+ * Allow ruby-electric-mode to be disabled by introducing a
+ dedicated key map. Electric key bindings are now defined in
+ ruby-electric-mode-map instead of overwriting ruby-mode-map.
+
+ * Add ruby-electric-mode-hook.
+
+ * Use a remap in binding ruby-electric-delete-backward-char.
+
+ * Totally revamp electric keywords and then introduce electric
+ return. Modifier keywords are now properly detected making
+ use of ruby-mode's indentation level calculator, and
+
+ * block-mid keywords (then, else, elsif, when, rescue and
+ ensure) also become electric with automatic reindentation.
+
+ * Add standardized comments for ELPA integration.
+
+ * Fix interaction with smartparens-mode by disabling its end
+ keyword completion, since ruby-electric has become more clever
+ at it.
+
+ * The custom variable `ruby-electric-keywords` is changed to
+ `ruby-electric-keywords-alist`, allowing user to fine-grained
+ configuration.
+
+Fri Oct 11 16:53:28 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_trace.c (rb_postponed_job_flush): simplify.
+
+Fri Oct 11 03:36:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (rb_threadptr_execute_interrupts): flush postponed job only
+ once at last.
+
+ * vm_trace.c (rb_postponed_job_flush): defer calling postponed jobs
+ registered while flushing to get rid of infinite reentrance of
+ ObjectSpace.after_gc_start_hook. [ruby-dev:47400] [Bug #8492]
+
+Thu Oct 10 23:04:00 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_or): remove unused variables.
+
+Thu Oct 10 23:01:16 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_or): use rb_hash_keys().
+
+Thu Oct 10 21:36:16 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_compact_bang): use ary_resize_smaller().
+
+Thu Oct 10 17:25:28 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (vm_exec): support :b_return event for "lambda{return}.call".
+ [Bug #8622]
+
+ * test/ruby/test_settracefunc.rb: add a test.
+
+Thu Oct 10 13:52:37 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_trace.c (postponed_job): use preallocated buffer.
+ Pre-allocate MAX_POSTPONED_JOB (1024) sized buffer
+ and use it.
+ If rb_postponed_job_register() cause overflow, simply it
+ fails and returns 0.
+ And maybe rb_postponed_job_register() is signal safe.
+
+ * vm_core.h: change data structure.
+
+Thu Oct 10 11:11:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm.c (Init_VM): hide also the singleton class of frozen-core, not
+ only frozen-core itself.
+
+Thu Oct 10 06:02:08 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_rand.rb: fix r43224. local variable `e' is
+ no longer available.
+
+Thu Oct 10 00:02:35 2013 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * numeric.c (fix_aref): avoid a possible undefined behavior.
+ 1L << 63 on 64-bit platform is undefined, at least, according to
+ ISO/IEC 9899 (C99) 6.5.7.
+
+Wed Oct 9 23:57:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (id_for_attr): avoid inadvertent symbol creation.
+
+Wed Oct 9 18:03:01 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_method.c (rb_attr): preserve encoding of the attribute ID in
+ error message.
+
+Wed Oct 9 17:40:16 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_fstring): because of lazy sweep, str may be unmarked
+ already and swept at next time, so mark it for the time being.
+ [ruby-core:57756]
+
+Wed Oct 9 13:53:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compar.c (cmp_eq): fail if recursion. [ruby-core:57736] [Bug #9003]
+
+ * thread.c (rb_exec_recursive_paired_outer): new function which is
+ combination of paired and outer variants.
+
+Wed Oct 9 09:18:14 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/debug.h,
+ vm_backtrace.c (rb_profile_frame_full_label): add new C API
+ rb_profile_frame_full_label() which returns label with
+ qualified method name.
+ Note that in future version of Ruby label() may return
+ same return value of full_label().
+
+ * ext/-test-/debug/profile_frames.c,
+ test/-ext-/debug/test_profile_frames.rb: fix a test for this change.
+
+
+Wed Oct 9 00:55:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * load.c (load_lock): display backtrace to $stderr at circular
+ require.
+
+ * vm_backtrace.c (rb_backtrace_print_to): new function to print
+ backtrace to the given output.
+
+Tue Oct 8 21:03:35 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_backtrace.c, include/ruby/debug.h: add new APIs
+ * VALUE rb_profile_frame_method_name(VALUE frame)
+ * VALUE rb_profile_frame_qualified_method_name(VALUE frame)
+
+ * iseq.c (rb_iseq_klass), internal.h: add new internal function
+ rb_iseq_method_name().
+
+ * ext/-test-/debug/profile_frames.c (profile_frames),
+ test/-ext-/debug/test_profile_frames.rb: add a test.
+
+Tue Oct 8 16:11:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_uniq): use rb_hash_values(), as well as the case no
+ block is given.
+
+ * internal.h: define rb_hash_values() as internal API.
+
+Tue Oct 8 13:53:21 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_uniq): use rb_hash_keys().
+
+ * internal.h: define rb_hash_keys() as internal API.
+
+ * hash.c (rb_hash_keys): ditto.
+
+Tue Oct 8 10:56:39 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * cont.c: disable FIBER_USE_NATIVE on GNU/Hurd because it doesn't
+ support a combination getcontext() and threads. Patch by
+ Gabriele Giacone (1o5g4r8o@gmail.com). [Bug #8990][ruby-core:57685]
+
+Tue Oct 8 05:58:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (Time.strptime): Time.strptime('0', '%s') returns local
+ time Time object as Ruby 2.0 and before.
+
+Tue Oct 8 05:40:37 2013 Eric Hodel <drbrain@segment7.net>
+
+ * .travis.yml: Rebuild Travis CI's "ruby-head" version on successful
+ build. Patch by Konstantin Haase. [Fixes GH-417]
+ https://github.com/ruby/ruby/pull/417
+
+Tue Oct 8 04:28:25 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-mode.el: Use preceding-char/following-char
+ (returning 0 at BOF/EOF) instead of char-before/char-after
+ (returning nil at BOF/EOF) to avoid error from char-syntax when
+ at BOF/EOF.
+
+Tue Oct 8 04:12:45 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-additional.el (ruby-mode-set-encoding): Add a missing
+ else clause to unbreak with `cp932`, etc.
+
+ * misc/ruby-mode.el (ruby-mode-set-encoding): Ditto.
+
+Tue Oct 8 03:57:34 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-additional.el (ruby-mode-set-encoding): Use
+ `default-buffer-file-coding-system` if the :prefer-utf-8
+ property is not available.
+
+ * misc/ruby-mode.el (ruby-mode-set-encoding): Ditto.
+
+ * misc/ruby-additional.el (ruby-encoding-map): Override the
+ default value.
+
+Tue Oct 8 03:19:19 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-additional.el (ruby-mode-set-encoding): Add support
+ for `prefer-utf-8` which was introduced in Emacs trunk.
+
+ * misc/ruby-additional.el (ruby-encoding-map): Add a mapping from
+ `japanese-cp932` to `cp932` to fix the problem where saving a
+ source file written in Shift_JIS twice would end up having
+ `coding: japanese-cp932` which Ruby could not recognize.
+
+ * misc/ruby-additional.el (ruby-mode-set-encoding): Add support
+ for encodings mapped to nil in `ruby-encoding-map`.
+
+ * misc/ruby-additional.el (ruby-encoding-map): Map `us-ascii` and
+ `utf-8` to nil by default, meaning they need not be explicitly
+ declared in magic comment.
+
+ * misc/ruby-additional.el (ruby-encoding-map): Add type
+ declaration for better customize UI.
+
+ * misc/ruby-mode.el: Ditto for the above.
+
+Tue Oct 8 00:14:53 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-additional.el: Add a standard header and footer,
+ including (provide 'ruby-additional).
+
+Mon Oct 7 22:52:45 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-electric.el (ruby-electric-space-can-be-expanded-p):
+ Return nil to avoid "end" insertion when in smartparens-mode
+ that is configured to insert "end" for the same keyword.
+
+ * misc/ruby-electric.el (ruby-electric-keywords): New custom
+ variable to replace `ruby-electric-simple-keywords-re` with.
+
+Mon Oct 7 22:52:16 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-additional.el: Use preceding-char/following-char
+ (returning 0 at BOF/EOF) instead of char-before/char-after
+ (returning nil at BOF/EOF) to avoid error from char-syntax when
+ at BOF/EOF.
+
+Mon Oct 7 22:45:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * cont.c (FIBER_USE_NATIVE): split long conditions.
+
+Mon Oct 7 20:29:31 2013 Zachary Scott <e@zzak.io>
+
+ * lib/time.rb: [DOC] typo in Time.rb overview by @srt32 [Fixes GH-416]
+ https://github.com/ruby/ruby/pull/416
+
+Mon Oct 7 20:07:20 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (Time.strptime): Use :offset.
+ Patch by Felipe Contreras. [ruby-core:57694]
+
+Mon Oct 7 16:47:27 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/-ext-/debug/test_profile_frames.rb: rename class C to
+ something long name because one test depends on absence of
+ class ::C.
+
+Mon Oct 7 16:33:10 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/-test-/debug/profile_frames.c:
+ test/-ext-/debug/test_profile_frames.rb: add a test for new C-APIs.
+
+Mon Oct 7 16:12:36 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/debug.h: add backtrace collecting APIs for profiler.
+ * int rb_profile_frames(int start, int limit, VALUE *buff, int *lines);
+ Collect information of frame information.
+
+ * VALUE rb_profile_frame_path(VALUE frame);
+ * VALUE rb_profile_frame_absolute_path(VALUE frame);
+ * VALUE rb_profile_frame_label(VALUE frame);
+ * VALUE rb_profile_frame_base_label(VALUE frame);
+ * VALUE rb_profile_frame_first_lineno(VALUE frame);
+ * VALUE rb_profile_frame_classpath(VALUE frame);
+ * VALUE rb_profile_frame_singleton_method_p(VALUE frame);
+ Get information about each frame.
+
+ These APIs are designed for profilers, for example, no object allocation,
+ and enough information for profilers.
+ In this version, this API collects only Ruby level frames.
+ This issue will be fixed after Ruby 2.1.
+
+ * vm_backtrace.c: implement above APIs.
+
+ * iseq.c (rb_iseq_klass): return local_iseq's class.
+
+Mon Oct 7 14:26:01 2013 Koichi Sasada <ko1@atdot.net>
+
+ * proc.c: catch up last commit.
+ Type of return value of rb_iseq_first_lineno() is now VALUE.
+
+ * vm_insnhelper.c (argument_error): ditto.
+
+ * vm_method.c (rb_method_entry_make): ditto.
+
+Mon Oct 7 14:07:45 2013 Koichi Sasada <ko1@atdot.net>
+
+ * iseq.c, internal.h: change to public (but internal) functions
+ * VALUE rb_iseq_path(VALUE iseqval);
+ * VALUE rb_iseq_absolute_path(VALUE iseqval);
+ * VALUE rb_iseq_label(VALUE iseqval);
+ * VALUE rb_iseq_base_label(VALUE iseqval);
+ * VALUE rb_iseq_first_lineno(VALUE iseqval);
+ And new (temporary) function:
+ * VALUE rb_iseq_klass(VALUE iseqval);
+
+ * iseq.c. vm_core.h (int rb_iseq_first_lineno): remove
+ function `int rb_iseq_first_lineno(const rb_iseq_t *iseq)'.
+ Use `VALUE rb_iseq_first_lineno(VALUE iseqval)' instead.
+
+ * proc.c. vm_insnhelper.c, vm_method.c: catch up this change.
+
+Sun Oct 6 08:37:39 2013 Zachary Scott <e@zzak.io>
+
+ * lib/webrick.rb: [DOC] fix grammar in WEBrick overview [Fixes GH-413]
+ Based on patch by @chastell https://github.com/ruby/ruby/pull/413
+
+Sat Oct 5 11:21:01 2013 Aaron Pfeifer <aaron.pfeifer@gmail.com>
+
+ * thread.c (terminate_atfork_i): fix locking mutexes not unlocked in
+ forks when not tracked in thread. [ruby-core:55102] [Bug #8433]
+
+Fri Oct 4 19:54:09 2013 Zachary Scott <e@zzak.io>
+
+ * ext/dbm/dbm.c: [DOC] Fix wrong constant name in DBM by @edward
+ [Fixes GH-409] https://github.com/ruby/ruby/pull/409
+
+Fri Oct 4 19:49:42 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c: rename heap.free_num as heap.swept_num to clarify meaning and
+ avoid confusion with objspace_free_num().
+
+Fri Oct 4 19:02:01 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c (objspace_free_num): new method for available/free slots on
+ heap. [ruby-core:57633] [Bug #8983]
+ * gc.c (gc_stat): change heap_free_num definition to use new method.
+ * test/ruby/test_gc.rb: test for above.
+
+Fri Oct 4 18:53:42 2013 Aman Gupta <ruby@tmm1.net>
+
+ * gc.c: add rb_objspace.limit to keep accurate count of total heap
+ slots [ruby-core:57633] [Bug #8983]
+
+Fri Oct 4 09:32:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/csv.rb (CSV.foreach): support enumerator. based on a patch by
+ Hanmac (Hans Mackowiak) at [ruby-core:57643]. [ruby-core:57283]
+ [Feature #8929]
+
+Thu Oct 3 18:20:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (console_emulator_p, constat_handle): disable built-in
+ console colorizing when console-emulator-like DLL is injected.
+ [Feature #8201]
+
+Thu Oct 3 18:01:44 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: define gc_profile_record::allocated_size if
+ CALC_EXACT_MALLOC_SIZE is true.
+
+Thu Oct 3 13:42:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (yes-test-sample): use RUNRUBY instead of MINIRUBY to set
+ runtime library path and run the built ruby. [Bug #8971]
+
+Thu Oct 3 00:17:15 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-additional.el: Properly quote the body. An unquoted
+ body given to eval-after-load is evaluated immediately!
+
+Wed Oct 2 21:38:30 2013 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * ext/socket/ifaddr.c (rsock_getifaddrs): fix possible memory leak.
+ When a system had no interface, this function used xmalloc for root
+ but did not return any reference to it. This patch fixes it by
+ immediately returning an empty array if no interface is found.
+ Coverity Scan found this bug.
+
+Wed Oct 2 21:37:04 2013 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * random.c (make_seed_value): a local array declaration was accessed
+ out of scope. Coverity Scan found this bug.
+
+Wed Oct 2 18:52:40 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: relax GC condition due to malloc_limit.
+
+ * gc.c (GC_MALLOC_LIMIT_MAX): change default value
+ (256MB -> 512MB) and permit zero to ignore max value.
+
+ * gc.c (vm_malloc_increase, vm_xrealloc): do not cause GC on realloc.
+
+ * gc.c (gc_before_sweep): change debug messages.
+
+Wed Oct 2 16:26:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (rb_io_close_read): duplex IO should wait its child process
+ even after close_read.
+
+Wed Oct 2 15:39:13 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_core.h: use __has_attribute() instead of __clang__major__ because
+ clang says "Note that marketing version numbers should not be used
+ to check for language features, as different vendors use different
+ numbering schemes. Instead, use the Feature Checking Macros."
+ http://clang.llvm.org/docs/LanguageExtensions.html
+
+Wed Oct 2 14:19:57 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (rb_io_close_write): detach tied IO for writing before closing
+ to get rid of race condition. [ruby-list:49598]
+
+ * io.c (rb_io_close_read): keep fptr in write_io to be discarded, to
+ fix freed pointer access when it is in use by other threads, and get
+ rid of potential memory/fd leak.
+
+Tue Oct 1 23:44:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * vm_core.h: use __attribute__((unused)) in UNINITIALIZED_VAR on clang
+ 4.0+ instead of just on 4.2. Clang has supported the unused attribute
+ since before version 4, so this should be safe.
+
+Tue Oct 1 22:03:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/tempfile.rb (Tempfile#unlink): finalizer is no longer needed
+ after unlinking. patched by by normalperson (Eric Wong) at
+ [ruby-core:56521] [Bug #8768]
+
+Tue Oct 1 20:54:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (stat_new_0): constify.
+
+ * file.c (rb_stat_new): constify and export. based on a patch by
+ Hanmac (Hans Mackowiak) at [ruby-core:53225]. [Feature #8050]
+
+Tue Oct 1 16:03:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (ruby_safe_level_4_warning): needed by extension
+ libraries which check safe level 4. [ruby-dev:47517] [Bug #8652]
+
+Mon Sep 30 23:14:36 2013 Zachary Scott <e@zzak.io>
+
+ * ext/objspace/objspace.c: [DOC] Cleaned up many rdoc formatting
+ issues and several duplicate grammar bugs.
+
+Mon Sep 30 23:01:01 2013 Zachary Scott <e@zzak.io>
+
+ * ext/objspace/object_tracing.c: [DOC] Adjust rdoc formatting and fix
+ small grammar typo
+
+Mon Sep 30 17:28:39 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/object_tracing.c: [DOC] add some notes for
+ ObjectSpace::trace_object_allocations.
+
+Mon Sep 30 16:46:58 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/object_tracing.c: add new 3 methods to control tracing.
+ * ObjectSpace::trace_object_allocations_start
+ * ObjectSpace::trace_object_allocations_stop
+ * ObjectSpace::trace_object_allocations_clear
+ And some refactoring.
+
+ * test/objspace/test_objspace.rb: add a test for new methods.
+
+ * NEWS: add a description for new methods.
+
+Mon Sep 30 11:18:04 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_gc_disable): do rest_sweep() before disable GC.
+ This fix may solve a failure of
+ TestTracepointObj#test_tracks_objspace_events
+ [test/-ext-/tracepoint/test_tracepoint.rb:43].
+
+Mon Sep 30 10:40:20 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * vm_method.c (rb_undef): raise a NameError if the original method
+ of a refined method is not defined.
+
+ * vm_insnhelper.c (rb_method_entry_eq): added NULL check to avoid SEGV.
+
+ * test/ruby/test_refinement.rb: related test.
+
+Sun Sep 29 23:45:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (rb_id_attrset, intern_str): allow junk attrset ID for
+ Struct.
+
+ * parse.y (rb_id_attrset): fix inconsistency with literals, allow
+ ID_ATTRSET and return it itself, but ID_JUNK cannot make ID_ATTRSET.
+ and raise a NameError instead of rb_bug() for invalid argument.
+
+Sun Sep 29 18:45:05 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * vm_insnhelper.c (vm_callee_setup_arg_complex, vm_yield_setup_block_args):
+ clear keyword arguments to prevent GC bug which occurs
+ while marking VM stack.
+ [ruby-dev:47729] [Bug #8964]
+
+ * test/ruby/test_keyword.rb: tests for the above.
+
+Sat Sep 28 23:25:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * math.c (math_log, math_log2, math_log10): fix for Bignum argument.
+ numbits should be add only when right shifted.
+
+Sat Sep 28 14:30:29 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * test/dl/test_base.rb: {libc, libm} detection now handle GNU/Hurd
+ correctly. Patch by Gabriele Giacone (1o5g4r8o@gmail.com).
+ [Bug #8937][ruby-core:57311]
+ * test/fiddle/helper.rb: ditto.
+
+Sat Sep 28 00:19:41 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * ext/curses/extconf.rb: check the size of chtype.
+
+ * ext/curses/curses.c (NUM2CH, CH2NUM): use proper macros for
+ the size of chtype.
+
+ [ruby-core:56090] [Bug #8659]
+
+Fri Sep 27 18:33:23 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: add two GC tuning environment variables.
+ RUBY_GC_MALLOC_LIMIT_MAX and RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR.
+ See r43067 for details.
+
+ * gc.c (rb_gc_set_params): refactoring. And change verbose notation.
+ Mostly duplicated functions get_envparam_int/double is not cool.
+ Please rewrite it.
+
+ * test/ruby/test_gc.rb: fix a test for this change.
+
+Fri Sep 27 17:44:41 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (GC_MALLOC_LIMIT): 8,000,000 -> 8 * 1,024 * 1,024.
+
+Fri Sep 27 17:19:39 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_before_sweep): cast to size_t to suppress warnings.
+
+Fri Sep 27 17:07:55 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: add some fine-grained profiling codes to tuning marking phase.
+ If you enable RGENGC_PRINT_TICK to 1, then profiling results by RDTSC
+ (on x86/amd64 environment) are printed at last.
+ Thanks Yoshii-san.
+
+Fri Sep 27 16:32:27 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: simplify threshold of GC caused by malloc_increase.
+ Now, malloc_limit is increased/decreased by mysterious logic.
+ This fix simplify malloc_limit increase/decrease logic such as:
+ if (malloc_increase > malloc_limit) /* so many malloc */
+ malloc_limit += malloc_limit * (GC_MALLOC_LIMIT_FACTOR-1);
+ else
+ malloc_limit -= malloc_limit * (GC_MALLOC_LIMIT_FACTOR-1)/4;
+ Default value of GC_MALLOC_LIMIT_FACTOR is 1.8.
+ malloc_limit is bounded by GC_MALLOC_LIMIT_MAX (256MB by default).
+ This logic runs at gc_before_sweep(). So there are no effect from
+ caused by lazy sweep. And we can remove malloc_increase2.
+
+ * gc.c (HEAP_MIN_SLOTS, FREE_MIN, HEAP_GROWTH_FACTOR): rename to
+ GC_HEAP_MIN_SLOTS, GC_FREE_MIN, GC_HEAP_GROWTH_FACTOR respectively.
+ Check them by `#ifndef' so you can specify these values outside gc.c.
+
+ * gc.c (ruby_gc_params_t): add initial_malloc_limit_factor and
+ initial_malloc_limit_max.
+
+ * gc.c (vm_malloc_prepare, vm_xrealloc): use vm_malloc_increase to
+ add and check malloc_increase.
+
+Fri Sep 27 01:05:00 2013 Zachary Scott <e@zzak.io>
+
+ * re.c: [DOC] arguments of Regexp::union receive #to_regexp [Bug #8205]
+
+Fri Sep 27 00:39:27 2013 Zachary Scott <e@zzak.io>
+
+ * struct.c: [DOC] grammar of ArgumentError in Struct.new [Bug #8936]
+ Patch by Prathamesh Sonpatki
+
+Thu Sep 26 22:11:56 2013 Zachary Scott <e@zzak.io>
+
+ * ext/bigdecimal/bigdecimal.c: [DOC] several fixes by @chastell
+ This includes fixing the capitalization of Infinity, return value of
+ example "BigDecimal.new('NaN') == 0.0", and code style in example.
+ [Fixes GH-398] https://github.com/ruby/ruby/pull/398
+
+Thu Sep 26 22:08:11 2013 Zachary Scott <e@zzak.io>
+
+ * lib/observer.rb: [DOC] syntax improvement in example by @chastell
+ [Fixes GH-400] https://github.com/ruby/ruby/pull/400
+
+Thu Sep 26 22:03:15 2013 Zachary Scott <e@zzak.io>
+
+ * ext/digest/digest.c: [DOC] typo in overview by @chastell
+ [Fixes GH-399] https://github.com/ruby/ruby/pull/399
+
+Thu Sep 26 22:00:42 2013 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/ossl.c: [DOC] typo in example by @zoranzaric
+ [Fixes GH-401] https://github.com/ruby/ruby/pull/401
+
+Thu Sep 26 21:07:49 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-electric.el (ruby-electric-delete-backward-char): Add
+ support for smartparens-mode.
+
+ * misc/ruby-electric.el (ruby-electric-cua-replace-region-maybe)
+ (ruby-electric-cua-delete-region-maybe): New functions that
+ combine `ruby-electric-cua-*-region` with
+ `ruby-electric-cua-*-region-p`, using a slightly better way to
+ detect if it is in cua-mode.
+
+Thu Sep 26 16:51:00 2013 Shota Fukumori <her@sorah.jp>
+
+ * insns.def (opt_regexpmatch2): Check String#=~ hasn't overridden
+ before calling rb_reg_match().
+
+ * test/ruby/test_string.rb: Test for above.
+
+ * vm.c (vm_init_redefined_flag): Add BOP flag for String#=~
+
+ [ruby-core:57385] [Bug #8953]
+
+Thu Sep 26 16:43:42 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-electric.el: Avoid use of the interactive function
+ `self-insert-command` which fires `post-self-insert-hook` and
+ `post-command-hook`, to make the ruby-electric commands work
+ nicely with those minor modes that make use of them to do
+ similar input assistance, such as electric-pair-mode,
+ autopair-mode and smartparens-mode.
+
+Thu Sep 26 16:24:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * insns.def (opt_regexpmatch1): check Regexp#=~ is not defined before
+ calling rb_reg_match()
+
+ * test/ruby/test_regexp.rb: add test
+
+ * vm.c (ruby_vm_redefined_flag): change type to short[]
+
+ * vm.c (vm_redefinition_check_flag): return REGEXP_REDEFINED_OP_FLAG if
+ klass == rb_cRegexp
+
+ * vm.c (vm_init_redefined_flag): setup BOP flag for Regexp#=~
+
+ * vm_insnhelper.h: add REGEXP_REDEFINED_OP_FLAG
+
+ [ruby-core:57385] [Bug #8953]
+
+Thu Sep 26 14:46:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (mark_locations_array): disable AddressSanitizer. based on a
+ patch by halfie (Ruby Guy) at [ruby-core:57372].
+ [ruby-core:56155] [Bug #8680]
+
+Wed Sep 25 17:41:29 2013 Koichi Sasada <ko1@atdot.net>
+
+ * README.EXT, README.EXT.ja: remove description of RARRAY_PTR()
+ and add a caution of accessing internal data structure directly.
+ Also add a description of rb_ary_store().
+ [Bug #8399]
+
+Wed Sep 25 17:12:08 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: rename RARRAY_RAWPTR() to RARRAY_CONST_PTR().
+ RARRAY_RAWPTR(ary) returns (const VALUE *) type pointer and
+ usecase of this macro is not acquire raw pointer, but acquire
+ read-only pointer. So we rename to better name.
+ RSTRUCT_RAWPTR() is also renamed to RSTRUCT_CONST_PTR()
+ (I expect that nobody use it).
+
+ * array.c, compile.c, cont.c, enumerator.c, gc.c, proc.c, random.c,
+ string.c, struct.c, thread.c, vm_eval.c, vm_insnhelper.c:
+ catch up this change.
+
+Wed Sep 25 16:58:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * internal.h (rb_float_value, rb_float_new): move inline functions
+ from ruby/ruby.h.
+
+ * numeric.c (rb_float_value, rb_float_new): define external functions
+ for extension libraries.
+
+Wed Sep 25 15:37:02 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/rdoc/test_rdoc_generator_darkfish.rb: add a guard for windows.
+
+Wed Sep 25 09:53:11 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Fix CVE-2013-4363. Miscellaneous minor improvements.
+
+ * test/rubygems: Tests for the above.
+
+Tue Sep 24 17:38:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_inspect): get rid of out-of-bound access.
+
+ * string.c (rb_str_inspect): when a UTF-16/32 string doesn't have a
+ BOM, inspect as a dummy encoding string.
+
+Tue Sep 24 17:15:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enc/encdb.c (ENC_DUMMY_UNICODE): make BOM-encodings dummy.
+
+ * encoding.c (enc_autoload): keep dummy encodings dummy.
+
+Tue Sep 24 16:41:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32/lib/win32/registry.rb (Win32::Registry#write): data size
+ is in bytes, not chars. terminators should be placed automatically.
+
+Tue Sep 24 16:39:36 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32/lib/win32/registry.rb (Win32::Registry#each_value): encode
+ name.
+
+ * ext/win32/lib/win32/registry.rb (Win32::Registry#each_key): ditto.
+
+ * ext/win32/lib/win32/registry.rb (Win32::Registry#export_string):
+ encode to locale encoding if default internal is not set.
+
+Tue Sep 24 16:35:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32/lib/win32/registry.rb (Win32::Registry::API#EnumKey):
+ size of the name is in WCHARs, not in bytes.
+
+Tue Sep 24 14:07:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * gc.c (free_method_cache_entry_i): unused function
+
+ * gc.c (rb_free_mc_table): ditto
+
+ * internal.h (method_cache_entry_t): unused struct
+
+ * vm_method.c (verify_method_cache): remove unused variable
+
+ * vm_method.c (rb_method_entry): ditto
+
+Tue Sep 24 14:01:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * class.c (class_alloc): remove mc_tbl
+
+ * gc.c (obj_free): ditto
+
+ * internal.h (struct rb_classext_struct): ditto
+
+ * method.h (rb_method_entry): remove ent param
+
+ * vm_method.c: restore the global method cache. Per class cache tables
+ turned out to be far too slow.
+
+ [ruby-core:57289] [Bug #8930]
+
+Tue Sep 24 12:51:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32/lib/win32/registry.rb (Win32::Registry::API): need
+ Constants.
+
+ * ext/win32/lib/win32/registry.rb (Win32::Registry::API#EnumValue):
+ size of the name is in WCHARs, not in bytes.
+
+Mon Sep 23 22:16:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enc/encdb.c, enc/utf_16_32.h (ENC_DUMMY_UNICODE): Unicode with BOM
+ must be based on big endian variants, so that actual encodings would
+ work. [ruby-core:57318] [Bug #8940]
+
+Mon Sep 23 12:11:26 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (env_each_pair): do not call rb_assoc_new() if
+ it isn't needed.
+
+Mon Sep 23 10:42:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/ruby/test_module.rb (TestModule#test_include_toplevel): test
+ for top level main.include. based on a part of the patch by
+ kyrylo at [GH-395].
+
+Mon Sep 23 05:07:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/intern.h (rb_ary_cat): move from internal.h, since it
+ is described in README.EXT.
+
+Sun Sep 22 20:55:20 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * vm_insnhelper.c (vm_make_proc_with_iseq): fix bug message.
+ This is follow up to changes in r42637.
+
+Sun Sep 22 20:35:38 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * ext/-test-/tracepoint/tracepoint.c (Init_tracepoint): prevent from GC.
+
+Sun Sep 22 19:00:28 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * benchmark/bm_app_answer.rb: revert r42990, benchmark scripts should
+ be self-contained and avoid dependencies, especially such small one.
+ See https://github.com/ruby/ruby/pull/393#issuecomment-24861301.
+
+Sat Sep 21 20:11:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (rb_fork_internal): remove cloexec setting on pipes
+ created by rb_cloexec_pipe. patch by normalperson (Eric Wong) at
+ [ruby-core:56523]. [Bug #8769]
+
+Sat Sep 21 01:04:25 2013 Zachary Scott <e@zzak.io>
+
+ * lib/benchmark.rb: [DOC] grammar of Benchmark#bm [Bug #8888]
+ Patch by Prathamesh Sonpatki
+
+Sat Sep 21 00:50:02 2013 Zachary Scott <e@zzak.io>
+
+ * enumerator.c: [DOC] Enumerator#each arguments documentation [GH-388]
+ Patch by @kachick https://github.com/ruby/ruby/pull/388
+
+Sat Sep 21 00:49:16 2013 Zachary Scott <e@zzak.io>
+
+ * enum.c: [DOC] Enumerable#to_a accepts arguments [GH-388]
+ Patch by @kachick https://github.com/ruby/ruby/pull/388
+
+Sat Sep 21 00:47:44 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_conv_enc_opts): make sure to scan coderange to get
+ rid of unnecessary conversion.
+
+Sat Sep 21 00:21:08 2013 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/lib/openssl/ssl.rb: [DOC] Document OpenSSL::SSLServer
+ Based on a patch by Rafal Lisowski [Bug #8758]
+
+Fri Sep 20 23:54:03 2013 Zachary Scott <e@zzak.io>
+
+ * lib/gserver.rb: [DOC] correct gserver.rb license [Bug #8913]
+
+Fri Sep 20 23:48:34 2013 Zachary Scott <e@zzak.io>
+
+ * ext/psych/yaml/yaml.h: [DOC] merge upstream typo fix by @GreenGeorge
+ https://github.com/tenderlove/psych/pull/161
+
+Fri Sep 20 23:37:40 2013 Zachary Scott <e@zzak.io>
+
+ * lib/securerandom.rb: [DOC] SecureRandom.hex length argument
+ [Fixes GH-394] Patch by @avdi https://github.com/ruby/ruby/pull/394
+
+Fri Sep 20 23:34:48 2013 Zachary Scott <e@zzak.io>
+
+ * benchmark/bm_app_answer.rb: removed duplicate code [Fixes GH-393]
+ Patch by @gouravtiwari https://github.com/ruby/ruby/pull/393
+
+Fri Sep 20 23:24:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (btest, btest-ruby, test-knownbug): add $(RUN_OPTS) to
+ ruby to be run, so that tests are runnable before making exts.
+
+ * common.mk (test-sample): ditto, and use $(MINIRUBY) as rubytest.rb
+ does not need extension libraries.
+
+ * tool/rubytest.rb: pass $(RUN_OPTS) to testing ruby using --run-opt.
+
+Fri Sep 20 15:01:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (intern_str): sigil only names are junk, at least one
+ identifier character is needed. [ruby-dev:47723] [Bug #8928]
+
+ * parse.y (rb_enc_symname_type): fix out of bound access.
+
+Fri Sep 20 14:14:32 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/-test-/printf/printf.c (printf_test_call): Fix an end of buffer
+ argument.
+
+Thu Sep 19 16:59:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (lambda): adjust position to the beginning of the block.
+
+Thu Sep 19 16:25:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vsnprintf.c (BSD_vfprintf): initialize cp so that size is 0 in the
+ commented case. fix an accidental bug at r16716.
+
+Thu Sep 19 14:33:14 2013 Koichi Sasada <ko1@atdot.net>
+
+ * NEWS: add a news for r42974.
+
+Thu Sep 19 14:12:02 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: make Symbol objects frozen.
+ [Feature #8906]
+ I want to freeze this good day, too.
+
+ * test/ruby/test_eval.rb: catch up this change.
+
+ * test/ruby/test_symbol.rb: add a test to check frozen symbols.
+
+Thu Sep 19 09:11:33 2013 Eric Hodel <drbrain@segment7.net>
+
+ * NEWS: Update for RDoc 4.1.0.preview.1 and RubyGems 2.2.0.preview.1
+
+Thu Sep 19 08:59:41 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc/markdown/literals_1_9.rb: Fix trailing whitespace.
+
+ Previously kpeg (which generates this file) added trailing
+ whitespace, but this bug is now fixed.
+
+ * lib/rdoc/markdown.rb: ditto.
+
+Thu Sep 19 08:33:14 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc: Update to RDoc 4.1.0.preview.1
+
+ RDoc 4.1.0 contains a number of enhancements including a new default
+ style and accessibility support. You can see the changelog here:
+
+ https://github.com/rdoc/rdoc/blob/v4.1.0.preview.1/History.rdoc
+
+ * test/rdoc: ditto.
+
+Thu Sep 19 07:16:26 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych.rb: updating Psych version
+
+ * ext/psych/psych.gemspec: ditto
+
+Thu Sep 19 06:39:40 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/dependency_resolver.rb: Switch the iterative resolver
+ algorithm from recursive to iterative to avoid possible
+ SystemStackError.
+
+Thu Sep 19 06:29:30 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems 2.2.0.preview.1
+
+ This brings several new features to RubyGems summarized here:
+
+ https://github.com/rubygems/rubygems/blob/v2.2.0.preview.1/History.txt
+
+ * test/rubygems: ditto.
+
+Wed Sep 18 23:14:58 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * string.c (rb_str_enumerate_lines): make String#each_line and
+ #lines not raise invalid byte sequence error when it is called
+ with an argument. The patch also causes performance improvement.
+ [ruby-dev:47549] [Bug #8698]
+
+ * test/ruby/test_m17n_comb.rb (test_str_each_line): remove
+ assertions which check that String#each_line and #lines will
+ raise an error if the receiver includes invalid byte sequence.
+
+Wed Sep 18 16:32:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (mnew_from_me): allocate structs after allocated wrapper
+ object successfully, to get rid of potential memory leak.
+
+Tue Sep 17 15:54:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/shell/command-processor.rb (Shell::CommandProcessor#find_system_command):
+ return executable file only, should ignore directories and
+ unexecutable files. [ruby-core:57235] [Bug #8918]
+
+ * lib/test/unit/assertions.rb (Test::Unit::Assertions#assert_throw):
+ assertion for throw. MiniTest::Assertions#assert_throws discards
+ the caught value.
+
+ * lib/test/unit/assertions.rb (Test::Unit::Assertions#assert_nothing_thrown):
+ returns the result of the given block.
+
+Tue Sep 17 12:55:58 2013 Eric Hodel <drbrain@segment7.net>
+
+ * doc/regexp.rdoc: [DOC] Replace paragraphs in verbatim sections with
+ plain paragraphs to improve readability as ri and HTML.
+
+Mon Sep 16 07:32:35 2013 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * complex.c: removed meaningless lines.
+ * rational.c: ditto.
+
+Mon Sep 16 00:44:23 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * ext/socket/mkconstants.rb: define MSG_FASTOPEN.
+ [ruby-core:57138] [Feature #8897]
+
+Sun Sep 15 13:31:23 2013 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * rational.c (nurat_div): reverted r28844, r28886 and r28887.
+ REASON: Nobuyoshi Nakada <nobu@ruby-lang.org>'s commits are buggy.
+ So Rational#/ may produce exact number with inexact number.
+ Moreover, without reducing.
+ REALLY NONSENSE COMMITS.
+ A bug report by me [ruby-dev:44710] is also caused by this behavior.
+ Kenta Murata <mrkn@mrkn.jp> patched it up.
+ But he did not fix the origin.
+ Today, the bug is still alive in ruby 1.9.3 and 2.0.0.
+
+Sat Sep 14 06:08:10 2013 Eric Hodel <drbrain@segment7.net>
+
+ * dir.c (dir_s_glob): [DOC] Improve wording and layout.
+
+ * dir.c (file_s_fnmatch): ditto.
+
+ * dir.c (Init_Dir): [DOC] Document File::Constants::FNM_XXX
+ constants. (These won't show up in RDoc until a new RDoc is
+ imported.)
+
+Thu Sep 12 14:58:58 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/generic.rb (URI::Generic.find_proxy): return nil if
+ http_proxy environment variable is empty string.
+ [ruby-core:57140] [Bug #8898]
+
+Fri Sep 13 10:40:28 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems 2.1.3
+
+ Fixed installing platform gems
+
+ Restored concurrent requires
+
+ Fixed installing gems with extensions with --install-dir
+
+ Fixed `gem fetch -v` to install the latest version
+
+ Fixed installing gems with "./" in their files entries
+
+ * test/rubygems/test_gem_package.rb: Tests for the above.
+
+ * NEWS: Updated for RubyGems 2.1.3
+
+Thu Sep 12 22:40:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_CHECK_SIGNEDNESS): macro to check signedness of a
+ type.
+
+ * configure.in (size_t): must be unsigned.
+ [ruby-core:57149] [Feature #8890]
+
+Thu Sep 12 22:37:08 2013 Anton Ovchinnikov <revolver112@gmail.com>
+
+ * ext/bigdecimal/bigdecimal.c, ext/digest/md5/md5.c,
+ ext/json/fbuffer/fbuffer.h, ext/json/generator/generator.c:
+ Eliminate less-than-zero checks for unsigned variables.
+ According to section 4.1.5 of C89 standard, size_t is an unsigned
+ type. These checks were found with 'cppcheck' static analysis tool.
+ [ruby-core:57117] [Feature #8890]
+
+Thu Sep 12 21:35:46 2013 Naohisa Goto <ngotogenome@gmail.com>
+
+ * Makefile.in (libruby-static.a): change LDFLAGS order. LDFLAGS may
+ include library path that should be specified before LIBS.
+ [ruby-dev:47707] [Bug #8901]
+
+Thu Sep 12 20:07:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vsnprintf.c (MAXEXP, MAXFRACT): calculate depending on constants in
+ float.h.
+
+ * vsnprintf.c (BSD_vfprintf): limit length for cvt() to get rid of
+ buffer overflow. [ruby-core:57023] [Bug #8864]
+
+ * vsnprintf.c (exponent): make expbuf size more precise.
+
+Wed Sep 11 17:30:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUNRUBY): append -- only after runruby.rb, not
+ cross-compiling baseruby, so that $(RUN_OPT) can be command line
+ options. [ruby-dev:47703] [Bug #8893]
+
+Wed Sep 11 07:55:17 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread.c (rb_mutex_unlock): Mutex#unlock no longer raise
+ an exception even if uses on trap. [Bug #8891]
+
+Tue Sep 10 14:37:01 2013 Shota Fukumori <sorah@tubusu.net>
+
+ * vm_backtrace.c (vm_backtrace_to_ary): Ignore the second argument if
+ it is nil. [Bug #8884] [ruby-core:57094]
+
+ * test/ruby/test_backtrace.rb (test_caller_with_nil_length):
+ Test for above.
+
+Tue Sep 10 12:39:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (method_entry_i): should exclude refined methods from
+ instance method list. [ruby-core:57080] [Bug #8881]
+
+Tue Sep 10 12:05:04 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * io.c (rb_f_printf): [DOC] add missing parenthesis in rdoc.
+
+Tue Sep 10 10:08:00 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * NEWS: Update RubyGems note.
+
+Tue Sep 10 09:51:22 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems 2.1.0. Fixes CVE-2013-4287.
+
+ See http://rubygems.rubyforge.org/rubygems-update/CVE-2013-4287_txt.html
+ for CVE information.
+
+ See http://rubygems.rubyforge.org/rubygems-update/History_txt.html#label-2.1.0+%2F+2013-09-09
+ for release notes.
+
+ * test/rubygems: Tests for the above.
+
+Mon Sep 9 21:31:45 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c: Remove spaces between SI prefix and unit to follow
+ SI brochure.
+ http://www.bipm.org/en/si/si_brochure/
+ https://www.nmij.jp/library/units/si/
+
+ * time.c: Ditto.
+
+ * ext/socket/ancdata.c: Ditto.
+
+Mon Sep 9 16:55:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_method.c (rb_add_refined_method_entry): clear cache in the
+ refined class since refining a method entry is modifying the class.
+ [ruby-core:57079] [Bug #8880]
+
+Mon Sep 9 09:14:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/rbinstall.rb (Gem::Specification#initialize): default date to
+ RUBY_RELEASE_DATE. [ruby-core:57072] [Bug #8878]
+
+ * tool/rbinstall.rb (Gem::Specification#to_ruby): add date.
+
+Sun Sep 8 16:01:54 2013 Tanaka Akira <akr@fsij.org>
+
+ * rational.c (f_gcd): Relax the condition to use GMP.
+
+Sun Sep 8 13:56:38 2013 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (folevariant_initialize): check type of
+ element of array.
+
+ * test/win32ole/test_win32ole_variant.rb (test_s_new_ary): ditto.
+
+Sat Sep 7 21:33:10 2013 Tanaka Akira <akr@fsij.org>
+
+ * math.c (math_log): Test the sign for bignums.
+ (math_log2): Ditto.
+ (math_log10): Ditto.
+
+Sat Sep 7 20:25:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * math.c (math_log): Support bignums bigger than 2**1024.
+ (math_log2): Ditto.
+ (math_log10): Ditto.
+
+Sat Sep 7 15:36:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * vm_eval.c (vm_call0): fix prototype, the id parameter should be of
+ type ID, not VALUE
+
+ * vm_insnhelper.c (check_match): the rb_funcall family of functions
+ does not care about refinements. We need to use
+ rb_method_entry_with_refinements instead to call === with
+ refinements. Thanks to Jon Conley for reporting this bug.
+ [ruby-core:57051] [Bug #8872]
+
+ * test/ruby/test_refinement.rb: add test
+
+Sat Sep 7 13:49:40 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * variable.c (classname): the name of class that has
+ non class id should not be nil. This bug was introduced
+ in r36577.
+
+ * test/thread/test_cv.rb: test for change.
+
+Sat Sep 7 13:29:22 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * lib/find.rb (Find.find): respect the encodings of arguments.
+ [ruby-dev:47530] [Feature #8657]
+
+ * test/test_find.rb: add tests.
+
+Sat Sep 7 10:40:32 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/mkconstants.rb (TCP_FASTOPEN): Defined for TCP fast open.
+ [ruby-core:57048] [Feature #8871] patch by Masaki Matsushita.
+
+Fri Sep 6 23:53:31 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * common.mk: use RUNRUBY instead of MINIRUBY because MINIRUBY can't
+ require extension libraries. The patch is from nobu
+ (Nobuyoshi Nakada).
+
+ * ext/thread/extconf.rb: for build ext/thread/thread.c.
+
+ * include/ruby/intern.h: ditto.
+
+ * thread.c: ditto.
+
+ * lib/thread.rb: removed and replaced by ext/thread/thread.c.
+
+ * ext/thread/thread.c: Queue, SizedQueue and ConditionVariable
+ implementations in C. This patch is based on patches from panaggio
+ (Ricardo Panaggio) and funny_falcon (Yura Sokolov) and ko1
+ (Koichi Sasada). [ruby-core:31513] [Feature #3620]
+
+ * test/thread/test_queue.rb (test_queue_thread_raise): add a test for
+ ensuring that killed thread should be removed from waiting threads.
+ It is based on a code by ko1 (Koichi Sasada). [ruby-core:45950]
+
+Fri Sep 6 22:47:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Define ac_cv_func_clock_getres to yes for mingw*.
+
+Fri Sep 6 21:04:10 2013 Tanaka Akira <akr@fsij.org>
+
+ * rational.c: Include gmp.h if GMP is used.
+ (GMP_GCD_DIGITS): New macro.
+ (rb_gcd_gmp): New function.
+ (f_gcd_normal): Renamed from f_gcd.
+ (rb_gcd_normal): New function.
+ (f_gcd): Invoke rb_gcd_gmp or f_gcd_normal.
+
+ * internal.h (rb_gcd_normal): Declared.
+ (rb_gcd_gmp): Ditto.
+
+ * ext/-test-/rational: New directory.
+
+ * test/-ext-/rational: New directory.
+
+Fri Sep 6 14:23:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (clock_getres): required as well as clock_gettime().
+ [ruby-dev:47699] [Bug #8869]
+
+Fri Sep 6 11:45:27 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * transcode.c (rb_econv_append): new function to append a string data
+ with converting its encoding. split from rb_econv_substr_append.
+
+Fri Sep 6 02:37:22 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: use double quotes when
+ strings start with special characters.
+ https://github.com/tenderlove/psych/issues/157
+
+ * test/psych/test_string.rb: test for change.
+
+Fri Sep 6 00:05:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (rewrite_cref_stack): remove recursion.
+
+Thu Sep 5 18:05:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * string.c (fstring_cmp): take string encoding into account when
+ comparing fstrings [ruby-core:57037] [Bug #8866]
+
+ * test/ruby/test_string.rb: add test
+
+Thu Sep 5 17:25:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_fstring, rb_str_free): use st_data_t instead of VALUE.
+
+ * string.c (rb_fstring): get rid of duplicating already frozen object.
+
+Thu Sep 5 14:01:22 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/optparse.rb: The Integer acceptable now allows binary and
+ hexadecimal numbers per the documentation. [ruby-trunk - Bug #8865]
+
+ DecimalInteger, OctalInteger, DecimalNumeric now validate their input
+ before converting to a number. [ruby-trunk - Bug #8865]
+
+ * test/optparse/test_acceptable.rb: Tests for the above, tests for all
+ numeric acceptables for existing behavior.
+
+Thu Sep 5 13:49:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * include/ruby/ruby.h: add RSTRING_FSTR flag
+
+ * internal.h: add rb_fstring() prototype
+
+ * string.c (rb_fstring): deduplicate frozen string literals
+
+ * string.c (rb_str_free): delete fstrings from frozen_strings table when
+ they are GC'd
+
+ * string.c (Init_String): initialize frozen_strings table
+
+Thu Sep 5 12:48:00 2013 Kenta Murata <mrkn@cookpad.com>
+
+ * configure.in (with_gmp): set with_gmp no if it is empty.
+
+Thu Sep 5 10:41:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_getivar): use class sequence to check class
+ identity, instead of pointer + vm state
+
+ * vm_insnhelper.c (vm_setivar): ditto
+
+Thu Sep 5 08:20:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (GMP_DIV_DIGITS): New macro.
+ (bary_divmod_gmp): New function.
+ (rb_big_divrem_gmp): Ditto.
+ (bary_divmod_branch): Ditto.
+ (bary_divmod): Use bary_divmod_branch.
+ (bigdivrem): Ditto.
+
+ * internal.h (rb_big_divrem_gmp): Declared.
+
+Thu Sep 5 06:22:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_divmod_normal): Reduce temporary array allocations.
+
+Thu Sep 5 02:17:06 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_divrem_normal): Add GC guards.
+
+Thu Sep 5 00:38:32 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_divrem_normal): New function.
+
+ * internal.h (rb_big_divrem_normal): Declared.
+
+ * ext/-test-/bignum/div.c: New file.
+
+ * test/-ext-/bignum/test_div.rb: New file.
+
+Thu Sep 5 00:08:44 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem_normal): Removed.
+ (bary_divmod_normal): New function.
+ (bary_divmod): Use bary_divmod_normal.
+ (bigdivrem): Use bary_divmod_normal.
+
+Wed Sep 4 23:02:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem): Useless declaration removed.
+
+Wed Sep 4 22:56:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (NUM_STEP_GET_INF): split from NUM_STEP_SCAN_ARGS(), since
+ inf is not used in num_step_size().
+
+Wed Sep 4 20:22:43 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem_normal): Add assertions.
+
+Wed Sep 4 19:18:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * internal.h (vm_state_version_t): prefer LONG_LONG to uint64_t.
+
+Wed Sep 4 16:28:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * internal.h (vm_state_version_t): use uint64_t when it is larger than
+ LONG_LONG, and fallback to unsigned long.
+
+Wed Sep 4 15:37:05 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * enc/trans/utf8_mac-tbl.rb: fix r42789.
+ Fix conversion table and logic. [ruby-dev:47680]
+
+Wed Sep 4 14:08:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
+ variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
+ vm_method.c: Implement class hierarchy method cache invalidation.
+
+ [ruby-core:55053] [Feature #8426] [GH-387]
+
+Wed Sep 4 11:13:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (str_gsub): use BEG(0) for whole matched position not
+ return value from rb_reg_search(), for \K matching.
+ [ruby-dev:47694] [Bug #8856]
+
+Wed Sep 4 11:11:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (SOLIBS): LIBRUBY_SO also needs linking with gmp, to
+ run worker processes in test-all on non-ELF platforms.
+
+Tue Sep 3 23:01:41 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/parser/test_tree.rb
+ (TestTreeParser::TestInvalid#test_unmatched_close_tag):
+ Compute expected value from test value.
+
+Tue Sep 3 22:59:58 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/treeparser.rb (REXML::Parsers::TreeParser#parse):
+ Add source information to parse exception on no close tag error.
+ [Bug #8844] [ruby-dev:47672]
+ Patch by Ippei Obayashi. Thanks!!!
+ * test/rexml/parser/test_tree.rb: Add a test for the above case.
+
+Tue Sep 3 22:57:57 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/parser/test_tree.rb: Fix test name to describe test
+ content.
+
+Tue Sep 3 22:54:46 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/treeparser.rb (REXML::Parsers::TreeParser#parse):
+ Remove needless nested parse exception information.
+ [Bug #8844] [ruby-dev:47672]
+ Reported by Ippei Obayashi. Thanks!!!
+ * test/rexml/parser/test_tree.rb: Add a test for the above case.
+
+Tue Sep 3 22:03:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_enc_str_new_cstr): new function to create a string from
+ the C-string pointer with the specified encoding.
+
+Tue Sep 3 21:41:37 2013 Akira Matsuda <ronnie@dio.jp>
+
+ * eval.c (Init_eval): Make Module#include and Module#prepend public
+ [Feature #8846]
+
+ * test/ruby/test_module.rb (class TestModule): Test for above
+
+Tue Sep 3 21:35:19 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread_pthread.c (sys/dyntune.h): for gettune().
+
+ * thread_pthread.c (hpux_attr_getstackaddr): fix missing *.
+ [ruby-core:56983] [Feature #8793]
+
+Tue Sep 3 20:12:46 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (GMP_STR2BIG_DIGITS): New macro.
+ (str2big_gmp): New function.
+ (rb_cstr_to_inum): Use str2big_gmp for big bignums.
+ (rb_str2big_gmp): New function.
+
+ * internal.h (rb_str2big_gmp): Declared.
+
+Tue Sep 3 19:44:40 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/win32/lib/win32/registry.rb (Win32::Registry#values): added.
+ [Feature #7763] [ruby-core:51783]
+
+Tue Sep 3 18:26:00 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/inf-ruby.el (inf-ruby-keys, run-ruby): Add magic autoload
+ comments.
+
+ * misc/rdoc-mode.el (rdoc-mode): Ditto.
+
+ * misc/ruby-electric.el (ruby-electric-mode): Ditto.
+
+ * misc/ruby-style.el (ruby-style-c-mode): Ditto.
+
+Tue Sep 3 17:06:15 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/ruby/test_rubyoptions.rb
+ (TestRubyOptions::SEGVTest::ExpectedStderr): the URL was changed at
+ r42800.
+
+Tue Sep 3 14:48:25 2013 Zachary Scott <e@zzak.io>
+
+ * lib/thread.rb: [DOC] CV#wait typo by @avdi [Fixes GH-386]
+ https://github.com/ruby/ruby/pull/386
+
+Tue Sep 3 14:37:53 2013 Zachary Scott <e@zzak.io>
+
+ * error.c: [DOC] Update bug tracker url by @ScotterC [Fixes GH-390]
+ https://github.com/ruby/ruby/pull/390
+
+Tue Sep 3 12:45:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_str2big_poweroftwo): New function.
+ (rb_str2big_normal): Ditto.
+ (rb_str2big_karatsuba): Ditto.
+
+ * internal.h (rb_str2big_poweroftwo): Declared.
+ (rb_str2big_normal): Ditto.
+ (rb_str2big_karatsuba): Ditto.
+
+ * ext/-test-/bignum/str2big.c: New file.
+
+ * test/-ext-/bignum/test_str2big.rb: New file.
+
+ * ext/-test-/bignum/depend: Add the dependency for str2big.c.
+
+Tue Sep 3 12:09:08 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_clock_gettime): Support times() based monotonic clock.
+ (rb_clock_getres): Ditto.
+
+Tue Sep 3 12:03:02 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (str2big_scan_digits): Extracted from rb_cstr_to_inum.
+
+Tue Sep 3 11:23:57 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_select_with_thread): rounding up the fraction of
+ tv_usec instead of rounding down.
+ this change is an experiment to get rid of failures on vc10-x64 CI.
+
+Tue Sep 3 11:00:28 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (do_select): constify timeout.
+
+ * win32/win32.c (rb_w32_select_with_thread): constify 10ms wait and
+ 0ms wait structs.
+
+Tue Sep 3 10:03:42 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/openssl/test_pair.rb
+ (OpenSSL::TestPair#test_write_nonblock_no_exceptions): on some CIs
+ such as Debian 6.0, Ubuntu 10.04, CentOS and vc10-x64 (maybe depend
+ on OpenSSL version), writing to SSLSocket after SSL_ERROR_WANT_WRITE
+ causes SSL_ERROR_SSL "bad write retry".
+
+Tue Sep 3 08:20:46 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * enc/trans/utf8_mac-tbl.rb: update conversion table to recent OS X.
+ Previous table is used on Mac OS X 10.1 or prior.
+ This table is used on 10.2 or later. [ruby-dev:47680]
+
+Tue Sep 3 07:49:25 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * numeric.c (NUM_STEP_SCAN_ARGS): On second thought, keep
+ Numeric#step backward compatible in that it raises TypeError
+ when nil is given as second argument.
+
+ * test/ruby/test_float.rb (TestFloat#test_num2dbl): Revert.
+
+ * test/ruby/test_numeric.rb (TestNumeric#test_step): Fix test
+ cases for the above change.
+
+Tue Sep 3 07:39:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bytes_2comp): Define it only for little endian
+ environment.
+
+Tue Sep 3 07:31:29 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * numeric.c (NUM_STEP_SCAN_ARGS): Numeric#step should raise
+ TypeError if a non-numeric parameter is given.
+
+ * test/ruby/test_float.rb (TestFloat#test_num2dbl): Allow nil as
+ step, as with the keyword argument.
+
+ * test/ruby/test_numeric.rb (TestNumeric#test_step): Add tests for
+ nil as step or limit.
+
+Tue Sep 3 07:28:49 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (bit_length): Add casts to fix compilation error with
+ clang 3.0 -Werror,-Wshorten-64-to-32.
+ [ruby-dev:47687] reported by SASADA Koichi.
+
+Tue Sep 3 03:17:26 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_insnhelper.c (vm_search_super_method): use ci->argc instead of
+ ci->orig_argc. ci->argc can be changed by splat arguments.
+ [ruby-list:49575]
+ This fix should be applied to Ruby 2.0.0 series.
+
+ * test/ruby/test_super.rb: add a test for above.
+
+Mon Sep 2 23:46:29 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * numeric.c (num_step): Default the limit argument to infinity and
+ allow it to be omitted. Keyword arguments (by: and to:) are
+ introduced for ease of use. [Feature #8838] [ruby-dev:47662]
+ [ruby-dev:42194]
+
+ * numeric.c (num_step): Optimize for infinite loop.
+
+Mon Sep 2 22:55:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (ISDIGIT): Unused macro removed.
+
+Mon Sep 2 22:49:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (str2big_poweroftwo): Extracted from rb_cstr_to_inum.
+ (str2big_normal): Ditto.
+ (str2big_karatsuba): Ditto.
+
+Mon Sep 2 14:39:29 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * ruby.c (Process#setproctitle): [DOC] Fix and improve rdoc.
+
+ * ruby.c (Process#argv0): [DOC] Improve rdoc.
+
+Mon Sep 2 14:15:00 2013 Kenta Murata <mrkn@cookpad.com>
+
+ * NEWS: fix description of number literal suffixes.
+
+Mon Sep 2 14:01:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * test/rake/test_rake_rules.rb: add space after string literal to
+ prevent conflict with string options syntax "foo"opts
+
+ * test/rss/rss-assertions.rb: ditto
+
+Mon Sep 2 12:28:38 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_bignum.rb (test_interrupt_during_to_s): Disable it
+ when GMP is used.
+
+Mon Sep 2 07:02:10 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (Init_Bignum): Define Bignum::GMP_VERSION when GMP is used.
+
+Mon Sep 2 01:46:14 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_generic): Reduce arguments.
+ (big2str_gmp): Ditto.
+ (rb_big2str1): Follow the above change.
+
+Mon Sep 2 00:08:08 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (get_mach_timebase_info): Extracted from rb_clock_gettime.
+ (rb_clock_gettime): Use get_mach_timebase_info.
+ (rb_clock_getres): Support MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC.
+
+Sun Sep 1 23:30:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (GMP_BIG2STR_DIGITS): New constant.
+ (big2str_gmp): New function.
+ (rb_big2str1): Use big2str_gmp for big bignums.
+
+ * internal.h (rb_big2str_gmp): Declared.
+
+ * ext/-test-/bignum/big2str.c (big2str_gmp): New method.
+
+Sun Sep 1 22:37:51 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul_gmp): Use mpz_init and mpz_clear instead of
+ mpz_inits and mpz_clears.
+ Older GMP don't have them.
+
+Sun Sep 1 21:17:54 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/net/http/test_http.rb (test_bind_to_local_port): Choose an open
+ port more reliably.
+
+Sun Sep 1 20:32:40 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_base_poweroftwo): Renamed from
+ big2str_base_powerof2.
+ (rb_big2str_poweroftwo): New function for test.
+ (big2str_generic): Extracted from rb_big2str1.
+ (rb_big2str_generic): New function for test.
+
+ * internal.h (rb_big2str_poweroftwo): Declared.
+ (rb_big2str_generic): Ditto.
+
+ * ext/-test-/bignum/big2str.c: New file.
+
+ * test/-ext-/bignum/test_big2str.rb: New file.
+
+Sun Sep 1 15:21:21 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_2bdigits): Renamed from big2str_orig.
+
+Sun Sep 1 13:02:24 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: Remove BITSPERDIG >= INT_MAX test. The static assertion,
+ SIZEOF_BDIGITS <= sizeof(BDIGIT) is enough.
+
+Sun Sep 1 11:38:26 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (maxpow_in_bdigit): Removed.
+
+Sun Sep 1 10:30:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_fix_bit_length): Moved from bignum.c.
+
+Sun Sep 1 09:55:45 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (bit_length): Moved from bignum.c.
+ (nlz_int): Ditto.
+ (nlz_long): Ditto.
+ (nlz_long_long): Ditto.
+ (nlz_int128): Ditto.
+
+Sun Sep 1 03:32:22 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bit_length): Renamed from bitsize.
+
+Sun Sep 1 00:07:09 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_bit_length): New method.
+ (rb_fix_bit_length): Ditto.
+ [ruby-core:56247] [Feature #8700]
+
+Sat Aug 31 22:18:29 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_clock_getres): New method.
+ (timetick2dblnum_reciprocal): New function.
+
+ * configure.in: Check clock_getres.
+
+ [ruby-core:56780] [Feature #8809] accepted as a CRuby feature at
+ DevelopersMeeting20130831Japan
+ https://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20130831Japan
+
+Sat Aug 31 21:02:07 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: Use GMP to accelerate big Bignum multiplication.
+ (bary_mul_gmp): New function.
+ (bary_mul): Use bary_mul_gmp.
+ (bigsq): Use different threshold with GMP.
+
+ * configure.in: Detect GMP.
+
+ [ruby-core:56658] [Feature #8796]
+
+Sat Aug 31 15:03:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * compile.c (NODE_MATCH3): pass CALL_INFO to opt_regexpmatch2
+
+ * insns.def (opt_regexpmatch2): use CALL_SIMPLE_METHOD to call =~ if
+ the receiver is not a T_STRING [Bug #8847] [ruby-core:56916]
+
+Sat Aug 31 14:07:11 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/securerandom.rb (random_bytes): Use Process.clock_gettime.
+
+Sat Aug 31 00:25:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/encoding.h (rb_{ascii8bit,utf8,usascii}_encindex): get
+ rid of conflict with macros defined in internal.h.
+
+Fri Aug 30 22:37:57 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread_pthread.c (native_thread_init_stack): wait the creator thread
+ to fill machine stack info, if get_stack_of() is available.
+
+ * thread_pthread.c (native_thread_create): fill the created thread
+ stack info after starting, if get_stack_of() is available.
+
+ * thread_pthread.c (native_thread_create): define attr only if it is
+ used, and merge pthread_create() calls.
+
+ * thread_pthread.c (get_main_stack): separate function to get stack of
+ main thread.
+
+Thu Aug 29 18:05:33 2013 Koichi Sasada <ko1@atdot.net>
+
+ * struct.c (rb_struct_define_without_accessor_under): added.
+ This function is similar to rb_define_class_under() against
+ rb_define_class().
+
+ * include/ruby/intern.h: add a declaration of this function.
+
+Thu Aug 29 17:03:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_call_method): a method entry refers the based
+ class/module, so should search superclass from the origin i-class
+ where the entry belongs to, to get rid of infinite loop when zsuper
+ in a prepended class/module. [ruby-core:54105] [Bug #8238]
+
+Thu Aug 29 05:35:58 2013 Eric Hodel <drbrain@segment7.net>
+
+ * ext/zlib/zlib.c (zstream_run): Fix handling of deflate streams that
+ need a dictionary but are being decompressed by Zlib::Inflate.inflate
+ (which has no option to set a dictionary). Now Zlib::NeedDict is
+ raised instead of crashing. [ruby-trunk - Bug #8829]
+ * test/zlib/test_zlib.rb (TestZlibInflate): Test for the above.
+
+Thu Aug 29 02:40:45 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/scalar_scanner.rb: invalid floats should be
+ treated as strings.
+ https://github.com/tenderlove/psych/issues/156
+
+ * test/psych/test_string.rb: test for change
+
+Wed Aug 28 17:20:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread_pthread.c (hpux_attr_getstackaddr): basic support for the
+ get_stack() under HP-UX. based on the patch by michal@rokos.cz
+ (Michal Rokos) at [ruby-core:56645]. [Feature #8793]
+
+Wed Aug 28 11:24:20 2013 Michal Rokos <michal@rokos.cz>
+
+ * configure.in (sys/pstat.h): fix missing header check for
+ missing/setproctitle.c on HP-UX. [ruby-core:56644] [Bug #8792]
+
+Wed Aug 28 04:54:33 2013 Eric Hodel <drbrain@segment7.net>
+
+ * ext/openssl/ossl_ssl.c (ossl_ssl_read): Replace duplicate
+ wait_writable with wait_readable.
+
+Tue Aug 27 17:18:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/timeout.rb (Timeout#timeout): skip rescue clause only when no
+ exception class is given.
+
+Tue Aug 27 17:02:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (copy_stream_body): should write in binary mode. based on a
+ patch by godfat (Lin Jen-Shin) at [ruby-core:56556].
+ [ruby-core:56518] [Bug #8767]
+
+Tue Aug 27 17:02:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (copy_stream_body): move common open flags.
+
+Tue Aug 27 16:56:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enumerator.c (enumerator_size): use rb_check_funcall() instead of
+ respond_to? and call.
+
+ * enumerator.c (enumerator_each): ensure that argument array size
+ does not overflow at appending.
+
+Tue Aug 27 16:46:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_index, rb_ary_rindex): use optimized equality to
+ improve performance. [Feature #8820]
+
+ * vm_insnhelper.c (rb_equal_opt): optimized equality function.
+
+Tue Aug 27 16:11:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (opt_eq_func): use RBASIC_CLASS() instead of HEAP_CLASS_OF().
+
+ * insns.def (opt_plus, opt_minus, opt_mult, opt_div, opt_mod, opt_lt),
+ (opt_gt, opt_ltlt, opt_aref, opt_aset, opt_length, opt_size),
+ (opt_empty_p, opt_succ): ditto.
+
+Tue Aug 27 16:08:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (rb_check_funcall, rb_check_funcall_with_hook): constify
+ argv.
+
+Tue Aug 27 13:03:33 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/stringio/stringio.c (strio_read_nonblock): declare local
+ variables at the first of function.
+
+Tue Aug 27 11:51:37 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * enumerator.c: Allow Enumerator size argument to be any callable.
+ Patch by Avdi Grimm. [bug #8641] [ruby-core:56032] [fix GH-362]
+
+ * test/ruby/test_enumerator.rb: Test for above
+
+Tue Aug 27 11:46:31 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_profile_clear): do rest_sweep() before clearing
+ profile.current_record.
+
+Tue Aug 27 07:35:05 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * io.c (io_read_nonblock): support non-blocking reads without raising
+ exceptions. As in: `io.read_nonblock(size, exception: false)`
+ [ruby-core:38666] [Feature #5138]
+ * ext/openssl/ossl_ssl.c (ossl_ssl_read_internal): ditto
+ * ext/stringio/stringio.c (strio_sysread): ditto
+ * io.c (rb_io_write_nonblock): support non-blocking writes without
+ raising an exception.
+ * ext/openssl/ossl_ssl.c (ossl_ssl_write_internal): ditto
+ * test/openssl/test_pair.rb (class OpenSSL): tests
+ * test/ruby/test_io.rb (class TestIO): ditto
+ * test/socket/test_nonblock.rb (class TestSocketNonblock): ditto
+ * test/stringio/test_stringio.rb (class TestStringIO): ditto
+
+Tue Aug 27 05:24:34 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Import RubyGems 2.1.0 Release Candidate
+ * test/rubygems: ditto.
+
+Mon Aug 26 16:24:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_nextc): warn carriage return in middle of line.
+ [ruby-core:56240] [Feature #8699]
+
+Mon Aug 26 15:27:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/timeout.rb (Timeout#timeout): should not be caught by rescue
+ clause. [Bug #8730]
+
+Mon Aug 26 14:44:26 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (rb_ary_splice): use RARRAY_PTR_USE() without WB because
+ there are not new relations.
+
+ * enum.c (enum_sort_by): ditto.
+
+ * struct.c (setup_struct): use RARRAY_RAWPTR().
+
+ * vm_eval.c (yield_under): ditto.
+
+ * ext/pathname/pathname.c (path_entries): use RARRAY_AREF().
+
+ * ext/pathname/pathname.c (path_s_glob): ditto.
+
+Mon Aug 26 13:11:10 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * array.c (ary_ensure_room_for_push): fix typo in r42658.
+
+Mon Aug 26 12:37:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * template/sizes.c.tmpl: generate automatically by extracting
+ RUBY_CHECK_SIZEOF from configure.in.
+
+Mon Aug 26 10:16:59 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * process.c (gcd_timetick_int): Renamed from gcd_timtick_int.
+
+Sun Aug 25 21:02:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * sizes.c (Init_sizes): Define the size of clock_t.
+
+Sun Aug 25 01:47:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (BARY_SHORT_MUL): Renamed from BARY_MUL1.
+ (bary_short_mul): Renamed from bary_mul1.
+
+Sat Aug 24 10:35:09 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_clock_gettime): The emulated clock names changed.
+
+Fri Aug 23 22:22:07 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_clock_gettime): Add a cast to fix compile error by
+ -Werror,-Wshorten-64-to-32.
+
+Fri Aug 23 22:12:13 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (rb_intern): no symbol cache while initialization.
+
+Fri Aug 23 22:07:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (clock_t): needs time.h.
+
+Fri Aug 23 21:37:28 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (reduce_factors): New function.
+ (timetick2dblnum): Use reduce_factors.
+ (timetick2integer): Ditto.
+ (make_clock_result): Follow the above change.
+ (rb_clock_gettime): Ditto.
+
+Fri Aug 23 21:00:55 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (timetick_int_t): Renamed from timetick_giga_count_t.
+ (gcd_timtick_int): Renamed from gcd_ul and make the arguments
+ timetick_giga_count_t.
+ (reduce_fraction): Make the arguments timetick_int_t.
+ (timetick2integer): Ditto.
+ (make_clock_result): Ditto.
+ (timetick2dblnum): Fix the return type.
+ (rb_clock_gettime): Use timetick_int_t.
+
+Fri Aug 23 20:50:40 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (gcd_ul): New function.
+ (reduce_fraction): Ditto.
+ (reduce_fraction): Ditto.
+ (timetick2dblnum): Ditto.
+ (timetick2integer): Ditto.
+ (make_clock_result): Use timetick2dblnum and timetick2integer.
+ (rb_clock_gettime): Follow the make_clock_result change.
+
+Fri Aug 23 18:39:04 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (ary_make_shared): shared ary as shady. Need more effort to
+ make it normal object.
+
+ * array.c (rb_ary_modify): use RARRAY_PTR_USE() without WB because
+ there are not new relations.
+
+ * array.c (ary_ensure_room_for_unshift): use RARRAY_RAWPTR() because
+ there are not new relations.
+
+Fri Aug 23 11:25:57 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c: introduce ARY_SHARED_OCCUPIED(shared).
+
+Fri Aug 23 11:07:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/Makefile.sub (config.h): now SIZEOF_CLOCK_T is needed for
+ unsigned_clock_t.
+
+Thu Aug 22 22:01:04 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_clock_gettime): Strip "s" from unit names.
+
+Thu Aug 22 20:14:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (unsigned_clock_t): Defined.
+ (rb_clock_gettime): Consider clock_t overflow for
+ ISO_C_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID.
+
+ * configure.in: Check the size of clock_t.
+
+Thu Aug 22 16:22:48 2013 Koichi Sasada <ko1@atdot.net>
+
+ * compile.c (build_postexe_iseq): fix to setup the local table.
+
+Thu Aug 22 15:42:43 2013 Koichi Sasada <ko1@atdot.net>
+
+ * compile.c (rb_iseq_compile_node): accept NODE_IFUNC to support
+ custom compilation.
+
+ * compile.c (NODE_POSTEXE): compile to
+ "ONCE{ VMFrozenCore::core#set_postexe{...} }" with a new custom
+ compiler `build_postexe_iseq()'.
+
+ * vm.c (m_core_set_postexe): remove parameters (passed by a block).
+
+Thu Aug 22 06:54:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_clock_gettime): Change emulation symbols for
+ Process.clock_gettime.
+
+Thu Aug 22 06:24:54 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (make_clock_result): Extracted from rb_clock_gettime.
+
+Wed Aug 21 22:30:51 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_clock_gettime): clock() based CLOCK_PROCESS_CPUTIME_ID
+ emulation implemented.
+
+Wed Aug 21 21:02:37 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_proc_times): Use RB_GC_GUARD to guard objects from GC.
+
+Wed Aug 21 20:33:01 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (get_clk_tck): Extracted from rb_proc_times.
+ (rb_clock_gettime): times() based CLOCK_PROCESS_CPUTIME_ID emulation
+ is implemented.
+
+Wed Aug 21 19:31:48 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c: POSIX_GETTIMEOFDAY_CLOCK_REALTIME is renamed to
+ SUS_GETTIMEOFDAY_CLOCK_REALTIME.
+
+Wed Aug 21 19:17:46 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_clock_gettime): CLOCK_PROCESS_CPUTIME_ID emulation
+ using getrusage is implemented.
+
+Wed Aug 21 17:34:27 2013 Tanaka Akira <akr@fsij.org>
+
+ * gc.c (getrusage_time): Fallback clock_gettime to getrusage when
+ clock_gettime fails.
+ Reported by Eric Saxby. [ruby-core:56762] [Bug #8805]
+
+Wed Aug 21 02:32:32 2013 Koichi Sasada <ko1@atdot.net>
+
+ * insns.def: fix regexp's once option behavior.
+ fix [ruby-trunk - Bug #6701]
+
+ * insns.def: remove `onceinlinecache' and introduce `once' instruction.
+ `once' doesn't use `setinlinecache' insn any more.
+
+ * vm_core.h: `union iseq_inline_storage_entry' to store once data.
+
+ * compile.c: catch up above changes.
+
+ * iseq.c: ditto.
+
+ * vm.c, vm_insnhelper.c: ditto. fix `m_core_set_postexe()' which
+ is depend on `onceinlinecache' insn.
+
+ * test/ruby/test_regexp.rb: add tests.
+
+ * iseq.c: ISEQ_MINOR_VERSION to 1 (should increment major?)
+
+Wed Aug 21 02:30:15 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_gcdebug_print_obj_condition): add printing information.
+
+Tue Aug 20 13:38:00 2013 Naohisa Goto <ngotogenome@gmail.com>
+
+ * test/gdbm/test_gdbm.rb: skip TestGDBM#test_s_open_lock on Solaris.
+ On Solaris (and platforms which do not have flock and have lockf),
+ with GDBM 1.10, gdbm_open(3) blocks when opening already locked
+ gdbm file. [Bug #8790] [ruby-dev:47631]
+
+Tue Aug 20 02:32:52 2013 Zachary Scott <e@zzak.io>
+
+ * lib/test/: [DOC] Document Test::Unit, hide most submodules and
+ classes from rdoc. Since lib/test is only present as a compatibility
+ layer with the legacy test suite many test/unit users will be using
+ minitest or the test/unit gem instead. It is recommended to use one
+ of these alternatives for writing new tests.
+
+ This patch was based on a patch submitted by Steve Klabnik.
+ [ruby-core:56694] [Bug #8778]
+
+Tue Aug 20 02:10:19 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rss/rss.rb: [DOC] Document for constants by Steve Klabnik
+ [ruby-core:56705] [Bug #8798]
+
+Tue Aug 20 02:01:10 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rss/xmlparser.rb: [DOC] Hide legacy constant from rdoc
+ Patch by Steve Klabnik [ruby-core:56708] [Bug #8799]
+
+Tue Aug 20 01:52:05 2013 Zachary Scott <e@zzak.io>
+
+ * ext/socket/unixserver.c: [DOC] Document #accept
+ * ext/socket/tcpserver.c: ditto
+ * ext/socket/udpsocket.c: [DOC] Fix indentation of documentation
+ * ext/socket/socket.c: ditto
+ Patches by David Rodr'iguez [ruby-core:56734] [Bug #8802]
+
+Tue Aug 20 01:19:22 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Define ac_cv_func_clock_gettime to yes for mingw*.
+
+Mon Aug 19 21:31:35 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/defines.h: Fix a compilation error with
+ i586-mingw32msvc-gcc of gcc-mingw32 package on Debian squeeze.
+ ruby/missing.h should be included before include/ruby/win32.h
+ because struct timespec, used in the clock_gettime declaration in
+ include/ruby/win32.h, is defined in ruby/missing.h instead of
+ system headers.
+
+Mon Aug 19 20:55:12 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: fix around GC_DEBUG.
+
+ * gc.c (RVALUE::line): should be VALUE. On some environment
+ (such as mswin64), `int' introduces alignment mismatch.
+
+ * gc.c (newobj_of): add an assertion to check VALUE alignment.
+
+ * gc.c (aligned_malloc): `&' is low priority than `=='.
+
+ * gc.c: define GC_DEBUG everytime and use it as value 0 or 1.
+
+Mon Aug 19 17:43:44 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_fiber.rb: collect garbage fibers immediately.
+
+Mon Aug 19 17:41:49 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/profile_test_all.rb: add `failed?' information.
+
+Mon Aug 19 17:00:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (retry_fork): retry with GC if ENOMEM occurred, to free
+ swap/kernel space.
+
+Mon Aug 19 13:28:47 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * include/ruby/win32.h (CLOCK_MONOTONIC): typo.
+
+ * win32/win32.c: removed duplicated declarations.
+
+Mon Aug 19 13:03:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (clock_gettime): should not overwrite cache variable
+ with different condition. otherwise -lrt is not linked and the link
+ fails, after reconfig.
+
+Mon Aug 19 12:56:49 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (Init_process): Add constants: CLOCK_REALTIME_ALARM and
+ CLOCK_BOOTTIME_ALARM.
+
+Sun Aug 18 20:17:41 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * variable.c, vm_method.c: remove dead code.
+
+ * test/ruby/test_fiber.rb, test/ruby/test_thread.rb:
+ change accordingly.
+
+Sun Aug 18 19:32:26 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * error.c, file.c, gc.c, hash.c, thread.c, variable.c, vm_eval.c, bin/erb:
+ $SAFE=4 is obsolete.
+
+Sun Aug 18 14:30:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_clock_gettime): Rename POSIX_TIME_CLOCK_REALTIME to
+ ISO_C_TIME_CLOCK_REALTIME.
+
+Sun Aug 18 14:22:45 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Revert r42604. It causes linking librt on systems
+ with newer glibc uselessly.
+
+Sun Aug 18 13:18:38 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (Init_process): Add constants: CLOCK_REALTIME_COARSE,
+ CLOCK_MONOTONIC_COARSE and CLOCK_BOOTTIME.
+
+Sun Aug 18 12:41:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (clock_gettime): need to check with -lrt prior to check
+ for the function only. otherwise -lrt is not linked and the link
+ fails, when ac_cv_func_clock_gettime is cached as yes.
+
+Sun Aug 18 10:05:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big2str1): Make an expression more explicit.
+
+Sun Aug 18 03:18:45 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big2str1): Use power_level instead of bitsize(xn).
+
+Sun Aug 18 00:44:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (BIGDIVREM_EXTRA_WORDS): Redefine to 1.
+ (bigdivrem_num_extra_words): Removed.
+ (bigdivrem_normal): Simplified.
+ (big2str_karatsuba): Ditto.
+
+Sat Aug 17 23:25:19 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * test/ruby/test_time.rb: use the in_timezone() helper
+ and define it at the top with other helpers.
+
+Sat Aug 17 22:20:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * time.c (time_mload): ignore auxiliary data, offset and zone, if
+ invalid. [ruby-core:56648] [Bug #8795]
+
+Sat Aug 17 20:11:49 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * process.c: [DOC] MACH_ABSOLUTE_TIME_CLOCK_MONOTONIC is an
+ available emulation for a monotonic clock on Darwin.
+ https://developer.apple.com/library/mac/qa/qa1398/_index.html
+
+Fri Aug 16 18:12:05 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/profile_test_all.rb: fix typo.
+
+Fri Aug 16 18:09:20 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/profile_test_all.rb: remove space characters from test names.
+
+Fri Aug 16 17:32:02 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/profile_test_all.rb: refactoring memory profiling tool for
+ test-all.
+ Add profiling targets /proc/meminfo and /proc/self/status.
+
+ * test/runner.rb: accept other than 'true'.
+
+Fri Aug 16 11:23:35 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * file.c (rb_file_size, rb_file_flock): improve performance of Windows.
+
+ * file.c (rb_file_truncate): removed unnecessary #ifdef.
+
+ * test/test_file.rb (TestFile#test_truncate_size): added an assertion
+ for File#size.
+
+Fri Aug 16 10:07:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem_single1): Renamed from bigdivrem_single. Add
+ x_higher_bdigit argument.
+ (bigdivrem_single): Just call bigdivrem_single1.
+ (bigdivrem_restoring): Use bigdivrem_single1 to avoid memmove.
+
+Fri Aug 16 09:17:00 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_small_rshift): Specify the higher BDIGIT instead of
+ sign bit.
+ (big_shift3): Follow the above change.
+
+Fri Aug 16 02:20:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul_toom3): Reduce a branch.
+
+Fri Aug 16 02:14:09 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * process.c (rb_clock_gettime): add CLOCK_MONOTONIC support on OS X.
+ http://developer.apple.com/library/mac/qa/qa1398/_index.html
+ [Feature #8658]
+
+Fri Aug 16 01:37:43 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem_single): Use shift when y is a power of two.
+
+Fri Aug 16 01:09:33 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem_restoring): Use bigdivrem_single if non-topmost
+ BDIGITs of y are zero.
+
+Fri Aug 16 00:33:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big2str1): Truncate topmost zeros of x.
+
+Fri Aug 16 00:00:57 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_divmod): Simplify an expression.
+
+Thu Aug 15 23:26:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem_normal): Remove a local variable.
+
+Thu Aug 15 23:08:32 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_karatsuba): Use bigdivrem_restoring directly to
+ reduce working buffer and memory copy.
+ (rb_big2str1): Allocate working buffer for big2str_karatsuba here.
+
+Thu Aug 15 20:51:29 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * io.c, internal.h (rb_io_flush_raw): new function to select calling
+ fsync() (on Windows).
+
+ * io.c (rb_io_flush_raw): use above function.
+
+ * file.c (rb_file_truncate): use above function.
+
+ * test/ruby/test_file.rb (TestFile#test_truncate_size): test for
+ above changes.
+
+Thu Aug 15 18:39:31 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (clock_gettime): improve precision when freq is less
+ than and nearly equals 10**9.
+
+Thu Aug 15 17:43:15 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_lazy_sweep): remove heap_increment() here because heap_inc
+ may be 0.
+
+Thu Aug 15 16:59:56 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * io.c (rb_io_rewind): remove fsync() for Windows to improve the
+ performance.
+
+Thu Aug 15 16:30:23 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/fileutils/test_fileutils.rb (TestFileUtils#test_rmdir):
+ FileUtils.rmdir ignores Errno::ENOTEMPTY, so, in such cases, this
+ assertion is nonsense.
+
+Thu Aug 15 15:49:35 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_clock_gettime): [DOC] FreeBSD 7.1 supports
+ CLOCK_THREAD_CPUTIME_ID.
+ http://www.freebsd.org/releases/7.1R/relnotes.html
+
+Thu Aug 15 14:30:23 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * include/ruby/win32.h, win32/Makefile.sub, win32/win32.c
+ (clock_gettime): [experimental] emulates clock_gettime(2) of posix.
+
+Thu Aug 15 02:32:40 2013 Zachary Scott <e@zzak.io>
+
+ * hash.c (rb_hash_aset): [DOC] Document key dup patch by @kachick
+ [Fixes GH-382] https://github.com/ruby/ruby/pull/382
+
+Wed Aug 14 14:28:39 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * proc.c (rb_mod_define_method): now they return the symbols of the
+ defined methods, not the methods/procs themselves.
+ [ruby-dev:42151] [Feature #3753]
+
+ * NEWS: documents about above change and def-expr (see r42337).
+
+ * test/ruby/test_module.rb: tests about above change.
+
+Wed Aug 14 00:51:14 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem_restoring): xn argument removed.
+ (bigdivrem_normal): Follow the above change.
+
+Wed Aug 14 00:18:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big_div_struct): Remove xn and j field. Add zn field.
+ (bigdivrem1): Follow the above change.
+ (bigdivrem_restoring): Ditto.
+
+Tue Aug 13 23:38:17 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big_div_struct): ynzero field removed.
+ (bigdivrem1): Follow the above change.
+ (bigdivrem_restoring): Ditto.
+
+Tue Aug 13 23:01:16 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem_restoring): Extracted from bigdivrem_normal.
+
+Tue Aug 13 22:12:59 2013 Kenichi Kamiya <kachick1@gmail.com>
+
+ * random.c (rb_random_ulong_limited): coerce before check negative.
+ [Fixes GH-379]
+
+Tue Aug 13 21:52:15 2013 Kenichi Kamiya <kachick1@gmail.com>
+
+ * object.c (Init_Object): undef Module#prepend_features on Class, as
+ well as Module#append_features. [Fixes GH-376]
+
+ * test_class.rb: Added test for above. And ensure type checking
+ on similar methods as module_function.
+
+Tue Aug 13 08:52:18 2013 Zachary Scott <e@zzak.io>
+
+ * doc/syntax/literals.rdoc: [DOC] String literal concat by @cknadler
+ [Fixes GH-380] https://github.com/ruby/ruby/pull/380
+
+Mon Aug 12 23:07:21 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (gc_marks_test): inhibit gc for st's operation.
+
+Mon Aug 12 15:59:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_whole_match_p): treat CR in middle of a line as a
+ mere whitespace.
+
+Mon Aug 12 15:16:58 2013 Koichi Sasada <ko1@atdot.net>
+
+ * class.c (rb_prepend_module): make T_ICLASS object shady because
+ this T_ICLASS object seems to share method table with other class
+ objects. It was causes WB miss.
+ TODO: need to know the data structure.
+
+ * test/ruby/test_module.rb: add a test for WB miss.
+
+Mon Aug 12 13:47:54 2013 Zachary Scott <e@zzak.io>
+
+ * process.c: [DOC] RDoc formatting of Process.clock_gettime
+
+Mon Aug 12 13:29:09 2013 Zachary Scott <e@zzak.io>
+
+ * lib/yaml/dbm.rb: [DOC] Document call-seq for YAML::DBM
+
+Mon Aug 12 12:57:26 2013 Zachary Scott <e@zzak.io>
+
+ * ext/dbm/extconf.rb: [DOC] Hide from RDoc
+ Some libraries might want to document extconf.rb so RDoc treats it
+ like any other ruby program. However, DBM users shouldn't care about
+ these methods.
+
+Mon Aug 12 12:53:39 2013 Zachary Scott <e@zzak.io>
+
+ * ext/dbm/dbm.c: [DOC] Reformat headings of DBM class
+
+Mon Aug 12 12:46:31 2013 Zachary Scott <e@zzak.io>
+
+ * lib/yaml.rb, lib/yaml/: [DOC] Document YAML::DBM#key and add
+ references to similar methods with more detail. This patch brings
+ lib/yaml to 100% documentation coverage.
+
+Mon Aug 12 02:51:32 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/readline/readline.c (readline_s_set_input): on OS X with editline,
+ Readline.readline doesn't work because readline_get doesn't use
+ rl_getc. The difference is introduced by r42402 [ruby-dev:47509]
+ [Bug #8644]. Before it rb_io_stdio_file set ifp->stdio_file.
+ Therefore add manually setting the value.
+
+ * ext/readline/readline.c (readline_s_set_output): ditto.
+
+Sun Aug 11 23:27:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_str_encode_ospath): OS path encoding on Mac OS X is also
+ fixed.
+
+Sun Aug 11 22:57:24 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/ruby/test_require.rb (assert_require_nonascii_path): OS path
+ encoding on Windows is fixed, so encoding of __FILE__ should be it.
+ [ruby-core:56498] [Bug #8764]
+
+Sun Aug 11 19:11:45 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/parser/test_sax2.rb: Expand abbreviated class name.
+
+Sun Aug 11 19:06:03 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/sax2listener.rb (REXML::SAX2Listener#notationdecl): Fix
+ wrong number of arguments in the template listener.
+ [Bug #8731] [ruby-dev:47582]
+ Reported by Ippei Obayashi.
+ * test/rexml/parser/test_sax2.rb: Add tests for parsing notation
+ declarations with SAX2 API.
+
+Sun Aug 11 18:44:04 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/sax2listener.rb (REXML::SAX2Listener#elementdecl): Fix wrong
+ examples. [Bug #8731] [ruby-dev:47582]
+ Reported by Ippei Obayashi.
+
+Sun Aug 11 18:42:13 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/sax2parser.rb
+ (REXML::Parsers::SAX2Parser#handle_entitydecl): Extract.
+
+Sun Aug 11 18:40:25 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/sax2parser.rb (REXML::Parsers::SAX2Parser#parse):
+ Fix wrong "%" position in parameter entity declaration event argument.
+ * test/rexml/parser/test_sax2.rb: Add tests for the above case.
+
+Sun Aug 11 18:08:40 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/sax2parser.rb (REXML::Parsers::SAX2Parser#parse):
+ Support NDATA in external ID entity declaration.
+ * test/rexml/parser/test_sax2.rb: Add tests for the above case.
+
+Sun Aug 11 18:07:39 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/baseparser.rb
+ (REXML::Parsers::BaseParser#pull_event): Support optional NDATA
+ in external ID entity declaration.
+
+Sun Aug 11 17:54:07 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * NEWS (REXML::Parsers::SAX2Parser): Add about this change.
+ * lib/rexml/parsers/sax2parser.rb (REXML::Parsers::SAX2Parser#parse):
+ Fix wrong number of arguments. Document says "an array of the
+ entity declaration" but it passes two or more arguments.
+ This is a bug but it break backward compatibility.
+ Reported by Ippei Obayashi. [Bug #8731] [ruby-dev:47582]
+ * lib/rexml/sax2listener.rb (REXML::SAX2Listener#entitydecl): ditto.
+ The listener template accepted two arguments.
+ * test/rexml/parser/test_sax2.rb: Add tests for external ID case.
+
+Sun Aug 11 17:41:41 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/parser/test_sax2.rb: Add SAX2 API test.
+
+Sun Aug 11 15:10:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (rb_enc_symname_type): allow ID_ATTRSET for ID_INSTANCE,
+ ID_GLOBAL, ID_CLASS, ID_JUNK too. [Bug #8756]
+
+Sun Aug 11 13:17:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * include/ruby/encoding.h: Reduce ENCODING_INLINE_MAX to 127 as this
+ should be sufficient to represent all the encodings Ruby supports.
+
+Sun Aug 11 11:54:38 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_clock_gettime): New method.
+ This is accepted in the meeting:
+ https://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20130809
+ This method is accepted as a CRuby feature.
+ I.e. Other Ruby implementations don't need to implement it.
+ [ruby-core:56087] [Feature #8658]
+
+Sun Aug 11 10:40:48 2013 Zachary Scott <e@zzak.io>
+
+ * lib/time.rb: [DOC] Correcting rdoc visibility of time.rb constants
+ Reported by Tanaka Akira [ruby-core:56517]
+
+Sun Aug 11 04:48:14 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * file.c (rb_str_normalize_ospath):
+ HFS Plus (Mac OS Extended) uses a variant of Normal Form D in which
+ U+2000 through U+2FFF, U+F900 through U+FAFF, and U+2F800 through
+ U+2FAFF are not decomposed (this avoids problems with round trip
+ conversions from old Mac text encodings).
+ http://developer.apple.com/library/mac/qa/qa1173/_index.html
+ Therefore fix r42457 to exclude the range.
+
+Sun Aug 11 03:26:07 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bitsize): Fix a conditional expression.
+
+Sun Aug 11 02:44:03 2013 Zachary Scott <e@zzak.io>
+
+ * lib/time.rb: [DOC] Document constants by @markijbema [Fixes GH-377]
+ https://github.com/ruby/ruby/pull/377
+
+Sun Aug 11 01:28:52 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Revert r42458.
+ It removes the HAVE_CLOCK_GETTIME from config.h.
+ http://www.rubyist.net/~akr/chkbuild/debian/ruby-trunk/log/20130809T044800Z.diff.html.gz
+
+Sat Aug 10 13:53:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (rb_id_attrset): allow other than ID_ATTRSET.
+
+ * parse.y (intern_str): ditto. try stem ID for ID_INSTANCE,
+ ID_GLOBAL, ID_CLASS, ID_JUNK too. [Bug #8756]
+
+Sat Aug 10 12:49:50 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/baseparser.rb
+ (REXML::Parsers::BaseParser::CDATA_END): Use "\A" instead of "^".
+ It is not an used constant but I fix it. (Or should I remove it?)
+
+Sat Aug 10 12:47:19 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/baseparser.rb (REXML::Parsers::BaseParser):
+ Fix wrong constant name. "]>" pattern match is the same but
+ it is used for "<!DOCTYPE" end mark not "<![CDATA[" end mark.
+
+Sat Aug 10 12:43:15 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/baseparser.rb (REXML::Parsers::BaseParser):
+ Use "\A" instead of "^" in document type declaration patterns
+ because they are used as the head match in content not the head
+ match in line. They don't cause any problems in the current code
+ but it should be fixed.
+
+Sat Aug 10 12:39:00 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/parse/test_document_type_declaration.rb: Add tests for
+ parsing document type declaration.
+
+Sat Aug 10 12:00:45 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/baseparser.rb (REXML::Parsers::BaseParser::SYSTEM):
+ Fix loose "head" match regular expression. It doesn't cause any
+ problem in the current code but it should be fixed because readers
+ may confuse it.
+ Patch by Ippei Obayashi. Thanks!!!
+
+Sat Aug 10 11:58:24 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/parse/test_notation_declaration.rb (#test_system_public):
+ Add a test for PUBLIC notation and SYSTEM notation order case.
+
+Sat Aug 10 11:31:35 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/baseparser.rb (REXML::Parsers::BaseParser::PUBLIC):
+ Fix loose "head" match regular expression.
+ [Bug #8701] [ruby-dev:47551]
+ Patch by Ippei Obayashi. Thanks!!!
+ * test/rexml/parse/test_notation_declaration.rb (#test_system_public):
+ Add a test for the above case.
+
+Sat Aug 10 09:20:21 2013 Zachary Scott <e@zzak.io>
+
+ * NEWS: [DOC] typo in example reported by @moretea
+ https://github.com/ruby/ruby/commit/a39e724#commitcomment-3831489
+
+Sat Aug 10 09:19:04 2013 Zachary Scott <e@zzak.io>
+
+ * proc.c: [DOC] rdoc code formatting
+
+Sat Aug 10 09:12:01 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (rb_id_attrset): check if the argument is valid type as an
+ attribute.
+
+Sat Aug 10 05:44:08 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rss/trackback.rb: [DOC] Hide RSS::Trackback from rdoc
+ Patch by Steve Klabnik [Bug #8755] [ruby-core:56456]
+
+Sat Aug 10 04:52:21 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big_div_struct): Use size_t.
+ (bigdivrem1): Ditto.
+ (bigdivrem_num_extra_words): Ditto.
+ (bigdivrem_single): Ditto.
+ (bigdivrem_normal): Ditto.
+ (bary_divmod): Ditto.
+
+Fri Aug 9 23:47:15 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rss/rexmlparser.rb: Remove needless REXML version check.
+ Both RSS Parser and REXML are bundled in Ruby. RSS Parser can
+ always use the latest REXML. [Bug #8754] [ruby-core:56454]
+ Patch by Steve Klabnik. Thanks!!!
+
+Fri Aug 9 22:51:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (XLDFLAGS, LIBRUBYARG_STATIC): CoreFoundation framework
+ option is now needed always, regardless enable-shared.
+ [ruby-core:56467] [Bug #8759]
+
+Fri Aug 9 22:20:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (load_file_internal): use rb_parser_compile_string_path and
+ rb_parser_compile_file_path, String path name versions. [Bug #8753]
+
+Fri Aug 9 07:16:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * ext/io/console/console.c: delete redefinition of rb_cloexec_open.
+ drop support for 1.8 and 1.9 from the next release of io-console gem.
+
+Fri Aug 9 19:13:54 2013 Koichi Sasada <ko1@atdot.net>
+
+ * NEWS: update about new methods for Binding.
+
+Fri Aug 9 18:48:09 2013 Koichi Sasada <ko1@atdot.net>
+
+ * proc.c: add Binding#local_variable_get/set/defined?
+ to access local variables which a binding contains.
+ Most part of implementation by nobu.
+
+ * test/ruby/test_proc.rb: add a tests for above.
+
+ * vm.c, vm_core.h (rb_binding_add_dynavars): add a new function
+ to add a new environment to create space for new local variables.
+
+Fri Aug 9 14:02:01 2013 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * tool/make-snapshot: Fix order of priority for option parameter.
+
+Fri Aug 9 12:06:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_str_normalize_ospath): normalize to Normalization Form C
+ using CFString.
+
+Fri Aug 9 10:53:57 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * time.c (get_timeval, get_new_timeval): use rb_obj_class()
+ instead of CLASS_OF() because CLASS_OF() may return
+ a singleton class.
+
+Fri Aug 9 10:42:11 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * vm_insnhelper.c (vm_invoke_block): returning from lambda proc
+ now always exits from the Proc. [ruby-core:56193] [Feature #8693]
+
+ * NEWS, test/ruby/test_lambda.rb: ditto. Patch by nobu.
+
+Fri Aug 9 00:10:32 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enumerator.c (lazy_zip_func): fix non-single argument. fix
+ out-of-bound access and pack multiple yielded values.
+ [ruby-core:56383] [Bug #8735]
+
+Thu Aug 8 23:01:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_mod_singleton_p): new method Module#singleton_class? to
+ return whether the receiver is a singleton class or not.
+ [ruby-core:51087] [Feature #7609]
+
+Thu Aug 8 21:56:44 2013 Tanaka Akira <akr@fsij.org>
+
+ * time.c (time_overflow_p): Avoid signed integer overflow.
+ (rb_time_new): Fix overflow condition.
+
+Thu Aug 8 19:58:02 2013 Koichi Sasada <ko1@atdot.net>
+
+ * thread.c (rb_threadptr_pending_interrupt_check_mask):
+ use RARRAY_RAWPTR() instead of RARRAY_PTR() because
+ there is no new reference.
+
+Thu Aug 8 19:56:52 2013 Koichi Sasada <ko1@atdot.net>
+
+ * string.c (rb_str_format_m): use RARRAY_RAWPTR() instead of
+ RARRAY_PTR() because there is no new reference.
+
+Thu Aug 8 19:55:51 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: define USE_RGENGC_LOGGING_WB_UNPROTECT.
+
+Thu Aug 8 16:44:25 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: add old macro name `RUBY_EVENT_SWITCH'.
+ This macro name is obsolete because it is renamed to
+ RUBY_INTERNAL_EVENT_SWITCH, but it has compatibility problem
+ using this macro name like ruby-prof.
+ I want to remove this macro after ruby 2.1.
+
+Thu Aug 8 15:37:53 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/coverage/test_coverage.rb (TestCoverage#test_big_code): use `1'
+ instead of `p' to get rid of a side effect.
+ Kernel#p without any argument seems to do nothing, but flushes stdout.
+ and, if stdout is redirected to file, fsync() will be called on
+ Windows. so, when running test-all on Windows with redirection, such
+ as CI environment, this test took a lot of time.
+
+Thu Aug 8 14:54:18 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * NEWS: add description of incompatibility introduced by r42396.
+ [ruby-core:56329] [Bug #8722]
+
+Thu Aug 8 14:50:36 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * common.mk (mini): portable target to build miniruby
+
+ * common.mk (bisect): run git-bisect with miniruby
+
+ * common.mk (bisect-ruby): run git-bisect with ruby
+
+ * tool/bisect.sh: script for git-bisect
+
+Thu Aug 8 12:11:43 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/webrick/test_httpresponse.rb (test_send_body_*_chunked): these
+ expectations assumes that the IOs are binmode. fixed test failures
+ introduced at r42427 on Windows.
+
+Thu Aug 8 10:27:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * range.c (range_last): revert r42400. [Bug #8739]
+
+Thu Aug 8 10:26:25 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_str_normalize_ospath): extract and move from dir.c.
+
+Thu Aug 8 05:59:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * test/openssl/test_ssl.rb: Fix test for CVE-2013-4073.
+ Patch by Antonio Terceiro. [Bug #8750] [ruby-core:56437]
+
+Thu Aug 8 03:37:38 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/webrick/httpresponse.rb: Allow #body to be an IO-like object
+ that responds to #readpartial and #read.
+ [ruby-trunk - Feature #8155]
+ * NEWS: NEWS for above
+ * test/webrick/test_httpresponse.rb: Tests for above.
+
+Wed Aug 7 23:06:26 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * ruby.c (Process.argv0): New method to return the original value
+ of $0. [Feature #8696]
+
+Wed Aug 7 23:05:55 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * ruby.c (Process.setproctitle): New method to change the title of
+ the running process that is shown in ps(1). [Feature #8696]
+
+Wed Aug 7 20:05:38 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_odd_p): Check the bignum length.
+ (rb_big_even_p): Ditto.
+
+Wed Aug 7 19:29:26 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (dbl2big): A condition simplified.
+
+Wed Aug 7 16:34:30 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/webrick/test_cgi.rb (TestWEBrickCGI#{start_cgi_server,test_cgi}):
+ mswin is not only mswin32 but also mswin64. [Bug #8746]
+
+Wed Aug 7 16:19:12 2013 Koichi Sasada <ko1@atdot.net>
+
+ * cont.c (rb_fiber_start): use RARRAY_RAWPTR() instead of
+ RARRAY_PTR() because there is no new reference.
+
+ * proc.c (curry): ditto.
+
+ * proc.c (rb_proc_call): remove line break.
+
+Wed Aug 7 13:20:12 2013 Koichi Sasada <ko1@atdot.net>
+
+ * random.c (random_load): use RARRAY_RAWPTR() instead of
+ RARRAY_PTR() because there is no new reference.
+
+Wed Aug 7 12:58:23 2013 Koichi Sasada <ko1@atdot.net>
+
+ * thread.c (thread_start_func_2): use RARRAY_RAWPTR() instead of
+ RARRAY_PTR() because there is no new reference.
+
+Wed Aug 7 09:00:24 2013 Zachary Scott <e@zzak.io>
+
+ * string.c: [DOC] Description of rb_str_equal [Fixes GH-375]
+ Based on a patch by @markijbema
+ https://github.com/ruby/ruby/pull/375
+
+Wed Aug 7 08:30:38 2013 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/ossl_hmac.c: [DOC] Documentation for OpenSSL::HMAC
+ based on a patch by @repah documenting-ruby/ruby#14
+ https://github.com/documenting-ruby/ruby/pull/14
+
+Wed Aug 7 07:46:23 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rss/utils.rb: [DOC] RSS::Utils by Steve Klabnik [Bug #8745]
+
+Wed Aug 7 07:38:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (nlz16): Removed.
+ (nlz32): Ditto.
+ (nlz64): Ditto.
+ (nlz128): Ditto.
+ (nlz_int): New function.
+ (nlz_long): New function.
+ (nlz_long_long): New function.
+ (nlz_int128): New function.
+ (nlz): Follow above changes.
+ (bitsize): Follow above changes.
+
+Tue Aug 6 22:38:15 2013 Zachary Scott <e@zzak.io>
+
+ * time.c: [DOC] Typo in Time overview by @sparr [Fixes GH-374]
+ https://github.com/ruby/ruby/pull/374
+
+Tue Aug 6 22:35:32 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rss/1.0.rb: [DOC] Document RSS10 by Steve Klabnik [Bug #8740]
+
+Tue Aug 6 22:14:11 2013 Kouji Takao <kouji.takao@gmail.com>
+
+ * ext/readline/readline.c (readline_s_delete_text): remove
+ checking "$SAFE == 4".
+
+ * ext/readline/readline.c: fix rdoc, remove "Raises SecurityError"
+ and add "Raises NotImplementedError".
+
+Tue Aug 6 22:04:38 2013 Kouji Takao <kouji.takao@gmail.com>
+
+ * ext/readline/readline.c, test/readline/test_readline.rb: fix
+ indent.
+
+Tue Aug 6 21:59:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * range.c (range_last): return nil for empty range, or in the case the
+ predecessor is smaller than the begin. [Bug #8739]
+
+Tue Aug 6 21:48:31 2013 Kouji Takao <kouji.takao@gmail.com>
+
+ * ext/readline/readline.c (readline_s_set_point, Init_readline):
+ add Readline.point=(pos). Patched by naruse. [ruby-dev:47535]
+ [Feature #8675]
+
+Tue Aug 6 21:14:11 2013 Kouji Takao <kouji.takao@gmail.com>
+
+ * ext/readline/readline.c (Init_readline, readline_s_set_output)
+ (clear_rl_outstream, readline_s_set_input, clear_rl_instream)
+ (readline_readline): fix causing SEGV if closed IO object that is
+ set Readline.input or Readline.output. Patched by akr
+ [ruby-dev:47509] [Bug #8644]
+
+Tue Aug 6 17:56:40 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_insnhelper.c (vm_push_frame): change type of stack_max to size_t.
+
+Tue Aug 6 17:42:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * range.c (range_last): exclude the last number of the exclusive range
+ if the end is Numeric. [ruby-dev:47587] [Bug #8739]
+
+Tue Aug 6 17:42:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_conv_from_wchar): converted string to CP_UTF8
+ should have UTF-8 encoding. otherwise no conversion takes place
+ later.
+
+Tue Aug 6 17:21:38 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_insnhelper.c (vm_push_frame): fix stack overflow check codes.
+ Stack overflow check should be done *after* pushing a stack frame.
+ However, some stack overflow checking codes checked *before*
+ pushing a stack frame with iseq->stack_max.
+ To solve this problem, add a new parameter `stack_max' to specify
+ a possible consuming stack size.
+
+ * vm_core.h (CHECK_VM_STACK_OVERFLOW0): add to share the stack overflow
+ checking code.
+
+ * insns.def: catch up this change.
+
+ * vm.c, vm_eval.c: ditto.
+
+ * test/ruby/test_exception.rb: add a stack overflow test.
+ This code is reported by nobu.
+
+Tue Aug 6 17:02:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_conv_from_wchar): use WideCharToMultiByte(),
+ as like as mbstr_to_wstr(), in the first step of the conversion from
+ WCHAR.
+
+Tue Aug 6 16:14:32 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * vm_eval.c (eval_string_with_cref): copy cref to limit the scope of
+ refinements in the eval string. [ruby-core:56329] [Bug #8722]
+
+ * test/ruby/test_refinement.rb: related test.
+
+Tue Aug 6 12:23:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_realloc): Use VALGRIND_MAKE_MEM_UNDEFINED to
+ declare undefined memory area.
+ (bignew_1): Ditto.
+
+ * internal.h (VALGRIND_MAKE_MEM_DEFINED): Moved from gc.c
+ (VALGRIND_MAKE_MEM_UNDEFINED): Ditto.
+
+Tue Aug 6 01:40:37 2013 Zachary Scott <e@zzak.io>
+
+ * process.c: [DOC] Document caveats of command form of Process.spawn
+ with regard to the shell and OS. Patched by Steve Klabnik [Bug #8550]
+
+Tue Aug 6 01:28:35 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rss/0.9.rb: [DOC] Typo in example [Bug #8732]
+
+Tue Aug 6 01:22:37 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rss/2.0.rb: [DOC] Document RSS::Rss by Steve Klabnik #8740
+ * lib/rss/atom.rb: [DOC] Typo in rdoc by Steve Klabnik
+
+Mon Aug 5 23:47:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: Rename local variables.
+
+Mon Aug 5 22:23:59 2013 Zachary Scott <e@zzak.io>
+
+ * vm_trace.c: [DOC] Fix TracePoint return values in examples
+ Based on a patch by @sho-h [Fixes GH-373]
+ https://github.com/ruby/ruby/pull/373
+
+Mon Aug 5 17:38:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_write_console): use MultiByteToWideChar() for
+ the last step of conversion to WCHAR, to get rid of warnings from
+ rb_enc_find() in miniruby. [ruby-dev:47584] [Bug #8733]
+
+ * win32/win32.c (wstr_to_mbstr, mbstr_to_wstr): fix wrong trimming.
+ WideCharToMultiByte() and MultiByteToWideChar() do not count
+ NUL-terminator in the size for conversion result, unless the input
+ length is -1.
+
+Mon Aug 5 11:51:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * include/ruby/encoding.h: document which user flags are used by
+ ENCODING_MASK for better greppability
+
+Mon Aug 5 10:01:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * object.c (rb_class_inherited_p): allow iclasses to be tested for
+ inheritance. [Bug #8686] [ruby-core:56174]
+
+ * test/ruby/test_method.rb: add test
+
+Mon Aug 5 06:13:48 2013 Zachary Scott <e@zzak.io>
+
+ * enumerator.c: [DOC] Remove reference to Enumerator::Lazy#cycle
+ Patch by @kachick [Fixes GH-372]
+ https://github.com/ruby/ruby/pull/372
+
+Mon Aug 5 03:57:16 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rss/0.9.rb: [DOC] Document RSS09 by Steve Klabnik [Bug #8732]
+
+Mon Aug 5 03:35:11 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rexml/attribute.rb: [DOC] Update example for #namespace
+ Patch by Ippei Obayashi [Bug #8685] [ruby-core:56173]
+
+Sun Aug 4 21:08:29 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_zip): performance implement by using
+ ALLOCA_N() to allocate tmp buffer.
+
+Sun Aug 4 07:14:49 2013 Tanaka Akira <akr@fsij.org>
+
+ * README.EXT, README.EXT.ja: Mention rb_integer_pack and
+ rb_integer_unpack.
+
+Sun Aug 4 01:54:45 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (BARY_TRUNC): New macro.
+ (bary_cmp): Use BARY_TRUNC.
+ (bary_mul_toom3): Ditto.
+ (bary_divmod): Ditto.
+ (abs2twocomp): Ditto.
+ (bigfixize): Ditto.
+ (rb_cstr_to_inum): Ditto.
+ (big2str_karatsuba): Ditto.
+ (bigdivrem): Ditto.
+
+Sun Aug 4 00:57:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_karatsuba): Don't allocate new temporary buffer
+ if the buffer is enough for current invocation.
+
+Sun Aug 4 00:22:34 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary2bdigitdbl): New function.
+ (bdigitdbl2bary): Ditto.
+ (bary_mul_single): Use bdigitdbl2bary.
+ (power_cache_get_power): Ditto.
+ (bary_divmod): Use bary2bdigitdbl.
+ (big2str_orig): Ditto.
+ (bigdivrem): Ditto.
+
+Sat Aug 3 22:47:11 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: The branch condition of selecting multiplication
+ algorithms should check smaller argument because Karatsuba and Toom3
+ is effective only if both arguments are big.
+ (bary_mul_toom3_branch): Compare the smaller argument to
+ TOOM3_MUL_DIGITS.
+ (bary_mul): Compare the smaller argument to KARATSUBA_MUL_DIGITS.
+
+Sat Aug 3 22:23:31 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_orig): Receive the number to stringize as
+ BDIGIT array and size.
+ (big2str_karatsuba): Receive the number to stringize as BDIGIT array
+ and size. Use an temporary array of BDIGIT.
+ (rb_big2str1): Follow the above change.
+
+Sat Aug 3 13:30:04 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (MAX_BASE36_POWER_TABLE_ENTRIES): Renamed from
+ MAX_BIG2STR_TABLE_ENTRIES.
+ (base36_power_cache): Renamed from big2str_power_cache.
+ (base36_numdigits_cache): Renamed from big2str_numdigits_cache.
+
+Sat Aug 3 10:33:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_set_integer_literal): use rb_rational_raw1() for
+ integral rational because no reduction is needed with 1.
+
+Sat Aug 3 09:46:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/etc/etc.c (setup_passwd, setup_group): set proper encodings to
+ string members.
+
+Sat Aug 3 09:30:57 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * struct.c (rb_struct_define_under): new function to define Struct
+ under the given namespace, not under Struct. [Feature #8264]
+
+ * ext/etc/etc.c: use rb_struct_define_under.
+
+Sat Aug 3 06:55:29 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * parse.y (value_expr_gen): now NODE_DEFN and NODE_DEFS are not void
+ value expressions. get rid of wrong warning with -w, and make to
+ pass tests with chkbuild. ref. [Feature #3753]
+
+Sat Aug 3 04:23:48 2013 Eric Hodel <drbrain@segment7.net>
+
+ * doc/syntax/refinements.rdoc: Remove mention of instance_eval and
+ module_eval from scope section per:
+ http://twitter.com/shugomaeda/status/363219951336693761
+
+Sat Aug 3 02:22:05 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_orig): Refactored.
+
+Sat Aug 3 01:20:19 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigadd_core): Removed.
+ (bigadd): Use bary_add instead of bigadd_core.
+
+Sat Aug 3 00:52:43 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big2str1): Simplify power_level calculation.
+
+Sat Aug 3 00:34:20 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_zip): use rb_ary_new2() to create buffer
+ if rb_block_arity() > 1.
+
+Sat Aug 3 00:12:00 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * NEWS: Add the description that IO#seek supports SEEK_DATA
+ and SEEK_HOLE.
+
+Fri Aug 2 23:57:57 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * vm.c (m_core_define_method, m_core_define_singleton_method): now
+ the value of def-expr is the Symbol of the name of the method, not
+ nil.
+ ref. [ruby-dev:42151] [Feature #3753]
+
+ * test/ruby/test_syntax.rb (TestSyntax#test_value_of_def): test for
+ above changes.
+
+Fri Aug 2 23:54:11 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_zip): performance improvement by avoiding
+ array creation if rb_block_arity() > 1.
+
+Fri Aug 2 23:50:53 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (power_cache_get_power): Apply bigtrunc to the result of
+ bigsq.
+ (big2str_karatsuba): Fix number of leading zero characters.
+
+Fri Aug 2 23:48:36 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_yylex): calculate denominator directly as powers of
+ ten, not parsing string.
+
+ * parse.y (parser_number_literal_suffix): return bit set of found
+ suffixes.
+
+ * parse.y (parser_set_number_literal, parser_set_integer_literal):
+ split from parser_number_literal_suffix to set yylval.
+
+ * parse.y (parser_yylex): parse rational number literal with decimal
+ point precisely.
+
+ * parse.y (simple_numeric): integrate numeric literals and simplify
+ numeric rules.
+
+ * ext/ripper/eventids2.c (ripper_init_eventids2): ripper support for
+ new literals, tRATIONAL and tIMAGINARY.
+
+Fri Aug 2 18:33:28 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_karatsuba): Reduce power_level more than one at
+ recursion, if possible.
+ (rb_big2str1): Follow the above change.
+
+Fri Aug 2 12:25:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul): Swap x and y for bary_mul1 if x is longer than y.
+ [ruby-dev:47565] [Bug #8719] Reported by Narihiro Nakamura.
+
+Fri Aug 2 10:39:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * parse.y (negate_lit): add T_RATIONAL and T_COMPLEX to the switch
+ statement, and call rb_bug() if an unknown type is passed to
+ negate_lit(). [ruby-core:56316] [Bug #8717]
+
+ * bootstraptest/test_literal_suffix.rb (assert_equal): add test
+
+Fri Aug 2 09:14:47 2013 Eric Hodel <drbrain@segment7.net>
+
+ * doc/syntax/refinements.rdoc: Improve description of where you may
+ activate refinements.
+
+Fri Aug 2 07:45:55 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_orig): Remove len argument.
+ (big2str_karatsuba): Ditto.
+ (rb_big2str1): Follow above change.
+
+Thu Aug 2 02:32:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * NEWS: Add the description of number literal suffixes.
+
+Thu Aug 2 00:02:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * bootstraptest/test_literal_suffix.rb: add two test cases to
+ examine that "1if true" and "1rescue nil" are recognized as 1.
+
+Thu Aug 1 23:45:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * rational.c (rb_flt_rationalize_with_prec): new public C function
+ to rationalize a Float instance with a precision.
+
+ * rational.c (rb_flt_rationalize): new public C function to
+ rationalize a Float instance. A precision is calculated from
+ the given float number.
+
+ * include/ruby/intern.h: Add rb_flt_rationalize_with_prec and
+ rb_flt_rationalize.
+
+ * parse.y: implement number literal suffixes, 'r' and 'i'.
+ [ruby-core:55096] [Feature #8430]
+
+ * bootstraptest/test_literal_suffix.rb: add tests for parser to scan
+ number literals with the above tsuffixes.
+
+Thu Aug 1 23:55:08 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big2str1): Remove a local variable.
+
+Thu Aug 1 23:33:01 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_cstr_to_inum): Use power_cache_get_power.
+
+Thu Aug 1 21:02:48 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big2str1): Raise an error for too big number.
+
+Thu Aug 1 20:46:29 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (power_cache_get_power): Hide cached Bignum objects.
+
+Thu Aug 1 19:15:05 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big2str1): Remove non-trim mode.
+ (rb_big2str0): Non-trim mode implemented here.
+ (big2str_find_n1): Change the result type to long again.
+ (big2str_base_powerof2): Don't take arguments: len and trim.
+ (rb_big2str): Follow above change.
+
+Thu Aug 1 12:37:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_alloc): New function to allocate the result string.
+ It is called after actual length is calculated.
+ (big2str_struct): Add fields: negative, result and ptr.
+ (big2str_orig): Write out the result via b2s->ptr.
+ (big2str_orig): Ditto.
+ (rb_big2str1): Don't allocate the result string at beginning.
+
+Thu Aug 1 07:36:27 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_orig): Use temporary buffer when trim mode.
+
+Thu Aug 1 06:28:48 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_orig): Simplified because RBIGNUM_LEN(x) <= 2 now.
+ (big2str_struct): Two fields added: hbase2, hbase2_numdigits.
+ (rb_big2str1): Initialize above fields.
+
+Thu Aug 1 04:06:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/rdoc/options.rb (RDoc#finish): include root path in include
+ paths, to work in another directory than the source directory.
+ [ruby-core:56282] [Bug #8712]
+
+ * test/test_rdoc_markup_pre_process.rb (TestRDocMarkupPreProcess#setup):
+ fix input_file_name, as the test script is not pre-processed.
+
+Thu Aug 1 01:45:18 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_karatsuba): Fix a condition of power_level.
+
+Thu Aug 1 01:09:02 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (LOG2_KARATSUBA_BIG2STR_DIGITS): Removed.
+ (KARATSUBA_BIG2STR_DIGITS): Removed.
+ (big2str_numdigits_cache): New variable.
+ (power_cache_get_power): Merged with power_cache_get_power0.
+ This function returns maxpow_in_bdigit_dbl(base)**(2**power_level).
+ (rb_big2str1): use power_cache_get_power.
+
+Wed Jul 31 23:59:28 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_find_n1): Change the return type to size_t.
+ (big2str_orig): Ditto.
+ (big2str_karatsuba): Ditto.
+ (rb_big2str1): Follow the above changes.
+
+Wed Jul 31 23:19:06 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (power_cache_get_power): Change numdigits_ret to size_t *.
+ (big2str_orig): Change len argument to size_t.
+ (big2str_karatsuba): Ditto.
+ (rb_big2str1): Follow the above changes.
+
+Wed Jul 31 22:59:47 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/parse/test_notation_declaration.rb: Change class
+ name to follow file name change.
+
+Wed Jul 31 22:57:50 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_notationdecl_parsetest.rb: Rename to ...
+ * test/rexml/parse/test_notation_declaration.rb: ... this.
+
+Wed Jul 31 22:54:39 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_notationdecl_mixin.rb: Remove duplicated tests.
+
+Wed Jul 31 22:52:55 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_notationdecl_parsetest.rb: Fix typos in expected
+ value.
+ pubilc ->
+ public
+ ^^
+
+Wed Jul 31 22:50:51 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_notationdecl_parsetest.rb: Add tests that focus
+ system literal in external ID system notation declaration.
+
+Wed Jul 31 22:36:21 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_cmp): Extracted from rb_big_cmp.
+ (power_cache_get_power): Change n1 argument (number of digits) to
+ power_level which is just passed to power_cache_get_power0.
+ (big2str_karatsuba): Ditto.
+ (rb_big2str1): Calculate the initial power_level.
+
+Wed Jul 31 22:04:36 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_notationdecl_parsetest.rb: Fix a typo.
+ Extern ID ->
+ ExternalID
+ ^^
+
+Wed Jul 31 22:01:36 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_notationdecl_parsetest.rb: Add tests that focus
+ public ID in external ID notation declaration.
+
+Wed Jul 31 22:01:24 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * parse.y: fix build error with bison-3.0.
+
+Wed Jul 31 21:58:53 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_notationdecl_parsetest.rb: Split test patterns.
+
+Wed Jul 31 21:42:33 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_notationdecl_parsetest.rb: Group tests.
+
+Wed Jul 31 21:37:51 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_notationdecl_mixin.rb (TestNotationDecl#test_name):
+ Move to ...
+ * test/rexml/test_notationdecl_parsetest.rb
+ (TestNotationDecl#test_name): ... here.
+
+Wed Jul 31 21:37:47 2013 Kouhei Sutou <kou@cozmixng.org>
+
+Wed Jul 31 21:31:49 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_notationdecl_parsetest.rb: Remove setup because it
+ doesn't share anything with other tests.
+
+Wed Jul 31 21:24:55 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_attributes_mixin.rb: Remove a needless shebang.
+ * test/rexml/test_notationdecl_mixin.rb: ditto.
+ * test/rexml/test_doctype.rb: ditto.
+ * test/rexml/test_xml_declaration.rb: ditto.
+ * test/rexml/test_changing_encoding.rb: ditto.
+
+Wed Jul 31 21:20:08 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_notationdecl_parsetest.rb: remove a needless shebang.
+
+Wed Jul 31 20:11:01 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * string.c (rb_str_rindex): fix bug introduced in r42269.
+ "".rindex("") should return 0.
+ (str_rindex): ditto.
+
+Wed Jul 31 19:55:33 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (MAX_BIG2STR_TABLE_ENTRIES): Use SIZEOF_SIZE_T.
+ (power_cache_get_power0): Add rb_bug call for too bit i argument.
+ (power_cache_get_power): Simplified.
+
+Wed Jul 31 18:32:25 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/uri/common.rb (URI.decode_www_form_component): Use String#b.
+
+Wed Jul 31 18:24:02 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * eval.c (rb_mod_refine, mod_using, top_using): don't show
+ warnings because Refinements are no longer experimental.
+ [ruby-core:55993] [Feature #8632]
+
+ * test/ruby/test_refinement.rb: related test.
+
+ * NEWS: fixes for the above change.
+
+Wed Jul 31 17:55:55 2013 Shota Fukumori <her@sorah.jp>
+
+ * lib/uri/common.rb (URI.decode_www_form_component):
+ Don't raise error when str includes multibyte characters.
+
+Wed Jul 31 17:45:39 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * string.c (rb_str_rindex): performance improvement by using
+ memrchr(3).
+
+Wed Jul 31 16:43:30 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * string.c (rb_str_rindex): refactoring and avoid to call str_nth() if
+ pos == 0.
+
+Wed Jul 31 14:41:36 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb: [DOC] Add a couple of notes on Hash as storage.
+ ref. [Feature #6589]
+
+Wed Jul 31 14:38:52 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb: [DOC] Fix example result. Hash is now ordered.
+
+Wed Jul 31 14:38:10 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb: [DOC] Use the term "sorted" instead of "ordered"
+ when mentioning SortSet.
+
+Wed Jul 31 12:18:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_struct): New structure.
+ (big2str_orig): Use big2str_struct.
+ (big2str_karatsuba): Ditto.
+ (rb_big2str1): Ditto.
+
+Wed Jul 31 12:02:16 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rubygems.rb: [DOC] typo in url patch by @Red54 [Fixes #369]
+ https://github.com/ruby/ruby/pull/369
+
+Wed Jul 31 07:09:07 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Import RubyGems from master as of commit 523551c
+ * test/rubygems: ditto.
+
+Tue Jul 30 22:21:54 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * test/ruby/test_hash.rb: add a test for enumeration order of Hash.
+
+Tue Jul 30 18:52:27 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb (Set#intersect?, Set#disjoint?): Add new methods for
+ testing if two sets have any element in common.
+ [ruby-core:45641] [Feature #6588] Based on the code by marcandre.
+
+Tue Jul 30 17:16:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * sprintf.c (ruby__sfvextra): add QUOTE flag to escape unprintable
+ characters.
+
+Tue Jul 30 11:00:52 2013 Zachary Scott <e@zzak.io>
+
+ * ext/curses/extconf.rb: [DOC] nodoc to reduce Object pollution
+
+Tue Jul 30 08:19:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * sizes.c (Init_sizes): Define sizes only if the type actually exists.
+
+Mon Jul 29 22:55:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * sizes.c (Init_sizes): define RbConfig::SIZEOF. [Feature #8568]
+
+Mon Jul 29 22:25:20 2013 Zachary Scott <e@zzak.io>
+
+ * ext/curses/curses.c: [DOC] Update location of samples
+ * samples/curses/*: Move Curses samples and refactor from mixin
+ The samples are included in rdoc for module and use of mixin is
+ confusing
+
+Mon Jul 29 22:16:11 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (LOG2_KARATSUBA_BIG2STR_DIGITS): Renamed from
+ LOG2_KARATSUBA_DIGITS.
+ (KARATSUBA_BIG2STR_DIGITS): Renamed from KARATSUBA_DIGITS.
+
+Mon Jul 29 22:04:45 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_compare_by_id): add function prototype.
+
+Mon Jul 29 21:53:41 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_compare_by_id): don't call rb_hash_rehash()
+ if self.compare_by_identity? == true.
+
+Mon Jul 29 21:29:48 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_assoc): performance improvement by replacing
+ compare function in RHASH(hash)->ntbl->type temporarily like r42224.
+ it falls back to rb_hash_foreach() if st_lookup() doesn't find the key.
+
+ * test/ruby/test_hash.rb: add a test for above.
+
+Mon Jul 29 21:15:30 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * test/ruby/test_lazy_enumerator.rb
+ (TestLazyEnumerator#test_initialize): Make sure
+ Enumerator::Lazy#initialize raises error if the object is
+ frozen. The check was performed by rb_ivar_set() before
+ rb_check_frozen() was added to enumerator_init().
+
+Mon Jul 29 21:06:42 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * enumerator.c (enumerator_init): Add a frozenness check to
+ prevent a frozen Enumerator object from being reinitialized with
+ a different enumerable object. This is the least we should do,
+ and more fixes will follow. [Fixes GH-368] Patch by Kenichi
+ Kamiya.
+
+ * enumerator.c (generator_init): Ditto.
+
+Mon Jul 29 20:14:24 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_assoc): revert r42224. table->type->compare is
+ called only if hashes are matched.
+
+ * test/ruby/test_hash.rb: add a test to check using #== to compare.
+
+Mon Jul 29 17:00:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (yycompile): store file name as String to keep the encoding.
+
+ * parse.y (rb_parser_compile_string_path, rb_parser_compile_file_path):
+ new functions to pass file name as a String.
+
+ * parse.y (gettable_gen): return a copy of the original file name, not
+ a copy in filesystem encoding.
+
+ * vm_eval.c (eval_string_with_cref): use Qundef instead of "(eval)".
+
+Mon Jul 29 16:53:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash_initialize_copy): copy st_table type even if empty.
+ [ruby-core:56256] [Bug #8703]
+
+Mon Jul 29 16:34:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash_initialize_copy): clear old table before copy new
+ table.
+
+Mon Jul 29 16:34:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash_assoc): aggregate object can be initialized only
+ with link time constants.
+
+Mon Jul 29 14:54:44 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_assoc): performance improvement by replacing
+ compare function in RHASH(hash)->ntbl->type temporarily.
+
+Mon Jul 29 14:52:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (xsystem): expand environment variable in all macros not
+ expanded with RbConfig. [Bug #8702]
+
+ * test/mkmf/test_framework.rb (create_framework): replace all $@ not
+ only once.
+
+Mon Jul 29 06:54:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_pipe): use enum for compile time constants,
+ instead of const int for debugging.
+
+Mon Jul 29 00:11:49 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem): Specialized implementation added for
+ nx == 2 && ny == 2
+
+Sun Jul 28 20:28:41 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * io.c (io_getpartial): use rb_str_locktmp_ensure().
+ [ruby-core:56121] [Bug #8669]
+
+ * io.c (rb_io_sysread): ditto.
+
+ * test/ruby/test_io.rb: add tests for above.
+
+Sun Jul 28 20:10:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb (extmake): should make static libraries for extensions
+ to be statically linked. [Bug #7948]
+
+Sun Jul 28 17:38:32 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * string.c: add internal API rb_str_locktmp_ensure().
+
+ * io.c (io_fread): use rb_str_locktmp_ensure().
+ [ruby-core:56121] [Bug #8669]
+
+ * test/ruby/test_io.rb: add a test for above.
+
+Sun Jul 28 13:04:39 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * io.c (interpret_seek_whence): support SEEK_DATA and SEEK_HOLE.
+ These are whences for lseek(2) supported by Linux since version 3.1.
+ [ruby-core:56123] [Feature #8671]
+
+ * test/ruby/test_io.rb: Add tests for above.
+
+Sun Jul 28 12:41:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (absint_numwords_generic): The char_bit variable changed
+ to static constant.
+
+Sun Jul 28 12:03:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: Constify bary_* functions.
+
+Sun Jul 28 11:12:07 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/intern.h (rb_absint_size): Declaration moved from
+ internal.h to calculate required buffer size to pack integers.
+ (rb_absint_numwords): Ditto.
+ (rb_absint_singlebit_p): Ditto.
+ [ruby-core:42813] [Feature #6065]
+
+Sun Jul 28 10:54:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_pipe): fix pipe name formatting. as "%x" may
+ not contain '0' at all, fill at fixed position instead.
+
+Sun Jul 28 00:35:14 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_size): Return the bignum "bytewise" size.
+ [ruby-core:55578] [Feature #8553]
+ This is accepted by matz on DevelopersMeeting20130727Japan.
+
+Sun Jul 28 00:07:48 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/intern.h (rb_integer_pack): Declaration moved from
+ internal.h.
+ (rb_integer_unpack): Ditto.
+ [ruby-core:42813] [Feature #6065]
+
+Fri Jul 26 23:18:13 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * NEWS: Add a new feature that REXML::Parsers::StreamParser
+ supports "entity" event.
+
+Fri Jul 26 23:14:31 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/parsers/streamparser.rb
+ (REXML::Parsers::StreamParser#parse): Add "entity" event support to
+ listener. [Bug #8689] [ruby-dev:47542]
+ Reported by Ippei Obayashi.
+ * test/rexml/test_stream.rb (StreamTester#entity): Add a test for
+ the above case.
+
+Fri Jul 26 23:05:27 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_yylex): separate numeric literal from succeeding
+ token, and treat 'e' as floating point number only if followed by
+ exponent part.
+
+Fri Jul 26 22:14:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_exec.h (CHECK_VM_STACK_OVERFLOW_FOR_INSN): surround with
+ do/while (0), and remove unnecessary casts.
+
+Fri Jul 26 20:12:07 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/syslog/lib/syslog/logger.rb (Syslog::Logger): Add facility
+ to Syslog::Logger. [Fixes GH-305] patch by Max Shytikov
+ https://github.com/ruby/ruby/pull/305
+
+Fri Jul 26 19:25:17 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_exec.h, tool/instruction.rb: not an error, but a BUG if stack
+ overflow checking failed just before/after the beginning of an
+ instruction. It should be treated as a BUG.
+ Please tell us if your code cause BUG with this problem.
+ This check will removed soon (for performance).
+
+Fri Jul 26 18:30:14 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (ary_memcpy): cast to int to suppress a warning.
+
+Fri Jul 26 18:21:58 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (ary_memcpy): try to enable optimization.
+ At least on my environments, I don't see any errors
+ with many trials. Please tell us if you find any GC bugs.
+
+Fri Jul 26 17:49:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/file.c (fix_string_encoding): fix target encoding. the
+ parameter `encoding' is not the target encoding but the original
+ encoding.
+
+Fri Jul 26 14:05:19 2013 Zachary Scott <e@zzak.io>
+
+ * ext/fiddle/*: [DOC] More doc on dlopen and RTLD_DEFAULT from r42184
+
+Fri Jul 26 13:08:53 2013 Zachary Scott <e@zzak.io>
+
+ * ext/fiddle/lib/fiddle.rb: [DOC] Document Fiddle.dlopen(nil)
+ * ext/fiddle/handle.c: [DOC] Document Fiddle::Handle.new(nil)
+
+Fri Jul 26 13:04:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * load.c (rb_load_internal): use rb_load_file_str() to keep path
+ encoding.
+
+ * load.c (rb_require_safe): search in OS path encoding for Windows.
+
+ * ruby.c (rb_load_file_str): load file with keeping path encoding.
+
+ * win32/file.c (rb_file_load_ok): use WCHAR type API assuming incoming
+ path is encoded in UTF-8. [ruby-core:56136] [Bug #8676]
+
+ * file.c (rb_str_encode_ospath): simplify using rb_str_conv_enc().
+
+ * win32/file.c (fix_string_encoding): simplify with rb_str_conv_enc().
+
+ * win32/file.c (convert_mb_to_wchar): use bare pointer instead of
+ VALUE, and remove useless argument.
+
+Fri Jul 26 11:42:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * rational.c (f_round_common): Rational is expected to be returned by
+ Rational#*, but mathn.rb breaks that assumption. [ruby-core:56177]
+ [Bug #8687]
+
+Fri Jul 26 01:37:45 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * include/ruby/ruby.h: check defined(USE_RGENGC_LOGGING_WB_UNPROTECT)
+
+Fri Jul 26 01:21:41 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * file.c (rb_file_expand_path_internal): fix r42160; skip '~'.
+
+Thu Jul 25 17:53:18 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/net/http.rb (Net::HTTP#connect): disable Nagle's algorithm on
+ HTTP connection. [ruby-core:56158] [Feature #8681]
+
+Thu Jul 25 17:49:42 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * re.c (rb_reg_to_s): convert closing parenthesis to the target encoding
+ if it is ASCII incompatible encoding. [ruby-core:56063] [Bug #8650]
+
+Thu Jul 25 17:21:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * encoding.c (is_obj_encoding): new macro to check if obj is an
+ Encoding. obj can be any type while is_data_encoding expects T_DATA
+ only.
+
+Thu Jul 25 17:17:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_file_expand_path_internal): should clear coderange after
+ copying user name as binary data.
+
+Thu Jul 25 16:17:55 2013 Koichi Sasada <ko1@atdot.net>
+
+ * encoding.c (check_encoding): Check T_DATA or not.
+ is_data_encoding(obj) assumes that `obj' is T_DATA.
+
+Thu Jul 25 13:06:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (dir_s_home): use rb_home_dir_of and rb_default_home_dir.
+
+ * file.c (rb_home_dir_of): split from rb_home_dir() for the home
+ directry of the given user, and the user name is a VALUE, not a bare
+ pointer. should raise if the user does not exist.
+
+ * file.c (rb_default_home_dir): split from rb_home_dir() for the home
+ directry of the current user.
+
+Thu Jul 25 12:32:11 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/openssl/ossl.c: support additional three thread synchronization
+ functions. [ruby-trunk - Bug #8386]
+
+Thu Jul 25 07:15:58 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Import RubyGems from master as of commit 4ff70cc
+ * test/rubygems: ditto.
+
+Wed Jul 24 20:57:44 2013 Koichi Sasada <ko1@atdot.net>
+
+ * compile.c (iseq_set_arguments): use RARRAY_RAWPTR() instead of
+ RARRAY_PTR() because there is no new reference.
+
+ * compile.c (iseq_set_exception_table): ditto.
+
+Wed Jul 24 19:49:54 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/generic.rb (find_proxy): raise BadURIError if the URI is
+ a relative URI. [Bug #8645]
+
+Wed Jul 24 18:56:06 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_insnhelper.c (vm_expandarray): use RARRAY_RAWPTR() instead of
+ RARRAY_PTR() because there is no new reference.
+
+ * vm_insnhelper.c (vm_caller_setup_args): ditto.
+
+ * vm_insnhelper.c (vm_yield_setup_block_args): ditto.
+
+Wed Jul 24 18:40:11 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c, gc.c: move ary_unprotect_logging() into
+ rb_gc_unprotect_logging() which is general version
+
+ * include/ruby/ruby.h: add USE_RGENGC_LOGGING_WB_UNPROTECT
+ to enable.
+
+Wed Jul 24 17:37:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_file_expand_path_internal): preserve the file name
+ encoding in an exception message.
+
+Wed Jul 24 08:04:49 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/-ext-/tracepoint/test_tracepoint.rb: add GC on/off to count
+ GC events strictly.
+
+Tue Jul 23 23:19:24 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/openssl/extconf.rb (CRYPTO_THREADID): check exist or not.
+
+ * ext/openssl/ossl.c (ossl_thread_id): use rb_nativethread_self()
+ implemented at r42137 to allow threads which doesn't associated with
+ Ruby thread to use openssl functions.
+
+ * ext/openssl/ossl.c (Init_ossl_locks): If CRYPTO_THREADID is defined
+ (OpenSSL 1.0.0 or later has it) use CRYPTO_THREADID_set_callback()
+ instead of CRYPTO_set_id_callback() because its argument is
+ unsigned long; it may cause id collision on mswin64
+ whose sizeof(unsigned long) < sizeof(void*).
+ http://www.openssl.org/docs/crypto/threads.html
+
+ * ext/openssl/ossl.c (ossl_threadid_func): defined for above.
+
+Tue Jul 23 20:47:36 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: Move functions.
+
+Tue Jul 23 20:14:55 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_divmod): Add special cases for x < y easily detected
+ and nx == 2 && ny == 2.
+
+Tue Jul 23 19:48:38 2013 Koichi Sasada <ko1@atdot.net>
+
+ * thread_(pthread|win32).h: rename rb_thread_cond_t to
+ rb_nativethread_cond_t.
+
+ * thread.c, thread_pthread.c, thread_win32.c, vm_core.h: catch up
+ renaming.
+
+Tue Jul 23 19:44:32 2013 Koichi Sasada <ko1@atdot.net>
+
+ * thread_native.h: add rb_nativethread_self() which returns
+ current running native thread identifier.
+
+ * thread_[pthread|win32].c: implement rb_nativethread_self().
+
+Tue Jul 23 19:34:11 2013 Koichi Sasada <ko1@atdot.net>
+
+ * thread_pthread.h, thread_win32.h: rename rb_thread_id_t to
+ rb_nativethread_id_t.
+
+ * thread_pthread.c, vm_core.h: use rb_nativethread_id_t.
+
+Tue Jul 23 18:56:11 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/openssl/ossl.c: use system native (system provided)
+ thread locking APIs added by last commit.
+ This patch fixes [Bug #8386].
+ "rb_mutex_*" APIs control only "Ruby" threads.
+ Not for native threads.
+
+Tue Jul 23 18:44:15 2013 Koichi Sasada <ko1@atdot.net>
+
+ * thread_native.h: added.
+ Move native thread related lines from vm_core.h.
+ And declare several functions "rb_nativethread_lock_*",
+ manipulate locking.
+
+ * common.mk: add thread_native.h.
+
+ * thread.c: add functions "rb_nativethread_lock_*".
+
+ * thread.c, thread_[pthread,win32].[ch]: rename rb_thread_lock_t
+ to rb_nativethread_lock_t to make it clear that this lock is for
+ native threads, not for ruby threads.
+
+Tue Jul 23 16:14:57 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_before_sweep): fix spacing.
+
+Tue Jul 23 15:57:11 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (heap_get_freeobj): clear slot->freelist here.
+ This means that this slot doesn't have any free objects.
+ And store this slot with objspace->heap.using_slot.
+
+ * gc.c (gc_before_sweep): restore objspace->freelist
+ into objspace->heap.using_slot->freelist.
+ This means that using_slot has free objects which are
+ pointed from objspace->freelist.
+
+ * gc.c (gc_slot_sweep): do not need to clear slot->freelist.
+
+Tue Jul 23 09:34:49 2013 Zachary Scott <e@zzak.io>
+
+ * sample/drb/README*.rdoc: [DOC] migrate DRb sample READMEs to rdoc
+
+Tue Jul 23 09:28:05 2013 Zachary Scott <e@zzak.io>
+
+ * lib/drb/invokemethod.rb: [DOC] nodoc InvokeMethod18Mixin
+
+Tue Jul 23 08:44:37 2013 Eric Hodel <drbrain@segment7.net>
+
+ * ext/openssl/ossl_asn1.c (asn1time_to_time): Implement YYMMDDhhmmZ
+ format for ASN.1 UTCTime. [ruby-trunk - Bug #8664]
+ * test/openssl/test_asn1.rb: Test for the above.
+
+Tue Jul 23 08:11:32 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rexml/streamlistener.rb: [DOC] Fix examples in
+ REXML::StreamListener#entitydecl patch by Ippei Obayashi [Bug #8665]
+
+Tue Jul 23 07:44:59 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Import RubyGems from master as of commit b165260
+ * test/rubygems: ditto.
+
+Tue Jul 23 07:14:31 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mulsub_1xN): New function.
+ (bary_mul_toom3): Use bary_mulsub_1xN.
+
+Tue Jul 23 03:32:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (KARATSUBA_BALANCED): New macro.
+ (TOOM3_BALANCED): Ditto.
+ (bary_mul_balance_with_mulfunc): Use KARATSUBA_BALANCED and
+ TOOM3_BALANCED.
+ (rb_big_mul_balance): Relax a condition.
+ (rb_big_mul_karatsuba): Use KARATSUBA_BALANCED.
+ (rb_big_mul_toom3): Use TOOM3_BALANCED.
+ (bary_mul_karatsuba_branch): Use KARATSUBA_BALANCED.
+ (bary_mul_toom3_branch): Use TOOM3_BALANCED.
+
+Tue Jul 23 01:34:45 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem_mulsub): Extracted from bigdivrem1.
+ (bigdivrem1): Use bary_add.
+
+Mon Jul 22 18:39:52 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * string.c (rb_str_enumerate_chars): specify array capa
+ with str_strlen().
+
+ * string.c (rb_str_enumerate_codepoints): ditto.
+
+Mon Jul 22 18:01:33 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * string.c (rb_str_enumerate_chars): specify array capa.
+
+Mon Jul 22 17:24:14 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * string.c (rb_str_each_char_size): performance improvement by
+ using rb_str_length().
+
+Mon Jul 22 16:32:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (eval_string_with_cref): check by Check_TypedStruct
+ instead of rb_obj_is_kind_of.
+
+Mon Jul 22 13:19:22 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (ary_resize_capa): use RARRAY_RAWPTR() because
+ this code creates no new references.
+
+Mon Jul 22 12:58:18 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (ary_memfill): added.
+
+ * array.c (rb_ary_initialize): use ary_memfill().
+
+ * array.c (rb_ary_fill): ditto.
+
+ * array.c (rb_ary_slice_bang): use RARRAY_RAWPTR() because
+ this code creates no new references.
+
+Mon Jul 22 10:09:46 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_slot_sweep): need to add empty RVALUE as freeobj.
+
+Mon Jul 22 09:48:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (eval_string_with_cref): use the given file name unless
+ eval even if scope is given. additional fix for [Bug #8436].
+ based on the patch by srawlins at [ruby-core:56099] [Bug #8662].
+
+Mon Jul 22 09:24:19 2013 Kouji Takao <kouji@takao7.net>
+
+ * ext/readline/readline.c (Init_readline): added
+ Readline.delete_text. [ruby-dev:45789] [Feature #6626]
+ * ext/readline/extconf.rb: check for rl_delete_text() in Readline library.
+
+ Thanks, Nobuyoshi Nakada, for the patch.
+
+Mon Jul 22 03:15:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/date/date_parse.c (rfc2822_cb): check if wday is given, since it
+ can be omitted.
+
+Mon Jul 22 00:15:20 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_sq_fast): Refine expressions.
+
+Sun Jul 21 21:08:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul): Use simple multiplication if yl is small.
+ (rb_cstr_to_inum): Invoke bigsq instead of bigmul0.
+ (bigsq): Re-implemented.
+ (bigmul0): Invoke bigsq if two arguments are identical.
+
+Sun Jul 21 09:58:19 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul_toom3): New function based on bigmul1_toom3.
+ (bary_mul_toom3_branch): Call bary_mul_toom3.
+ (rb_big_mul_toom3): Ditto.
+ (bigmul1_toom3): Removed.
+ (big_real_len): Ditto.
+ (big_split): Ditto.
+ (big_split3): Ditto.
+
+Sun Jul 21 08:12:16 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * proc.c (proc_to_s): use PRIsVALUE to preserve the result encoding.
+
+Sun Jul 21 03:36:18 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * hash.c (rb_hash_flatten): use NUM2INT to raise TypeError on 32bit
+ platform. it's introduced by r42039
+
+Sun Jul 21 01:07:45 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * common.mk (help): Fix environment variable name and argument.
+ Actually it can also be a directory or any argument for
+ test/unit runner. [Fixes GH-363]
+
+Sat Jul 20 22:44:50 2013 Zachary Scott <e@zzak.io>
+
+ * common.mk: Document running a single test [Fixes GH-363]
+ Patch by Avdi Grimm https://github.com/ruby/ruby/pull/363
+
+Sat Jul 20 22:39:56 2013 Zachary Scott <e@zzak.io>
+
+ * sample/*: whitespace patch by Sergio Campama [Fixes GH-364]
+ https://github.com/ruby/ruby/pull/364
+
+Sat Jul 20 22:33:13 2013 Zachary Scott <e@zzak.io>
+
+ * doc/regexp.rdoc: [DOC] Fix typo in example [Fixes GH-365]
+ Patch by Juanito Fatas https://github.com/ruby/ruby/pull/365
+
+Sat Jul 20 17:46:03 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (rb_str_succ): add missing case NEIGHBOR_WRAPPED.
+ r42078 caused buggy behavior like "\xFF".b -> "\x01\xFF".b
+
+Sat Jul 20 15:22:38 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (rb_ary_resize): use simple memcpy because there are no new
+ references.
+
+Sat Jul 20 15:02:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * safe.c (ruby_safe_level_4_warning): define for old extension
+ libraries. [Bug #8652]
+
+Sat Jul 20 14:38:00 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (ary_make_shared): make shared array shady.
+ Making non-shady shared array causes SEGV (see rubyci).
+ It seems a bug around shared array.
+
+Sat Jul 20 12:14:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (enc_succ_char, enc_pred_char): consider wchar case.
+ [ruby-core:56071] [Bug #8653]
+
+ * string.c (rb_str_succ): do not replace with invalid char.
+
+ * encoding.c (rb_enc_code_to_mbclen): add new function which returns
+ mbclen from codepoint like as rb_enc_codelen() but 0 for invalid
+ char.
+
+ * include/ruby/encoding.h (rb_enc_code_to_mbclen): declaration and
+ shortcut macro.
+
+Fri Jul 19 21:59:12 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: declare type_name() at the beginning of file.
+
+Fri Jul 19 21:35:09 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c: reduce shady operations.
+
+ * array.c (rb_ary_modify, ary_make_partial, rb_ary_splice,
+ rb_ary_replace, rb_ary_eql, rb_ary_compact_bang):
+ use RARRAY_RAWPTR() instead of RARRAY_PTR().
+
+ * array.c (rb_ary_shift): use RARRAY_PTR_USE() without WB because
+ there are not new relations.
+
+ * array.c (ary_ensure_room_for_unshift): ditto.
+
+ * array.c (rb_ary_sort_bang): ditto.
+
+ * array.c (rb_ary_delete_at): ditto.
+
+ * array.c (rb_ary_reverse_m): use RARRAY_RAWPTR() because
+ there are not new relations.
+
+Fri Jul 19 20:58:20 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c: reduce shade operations.
+
+ * array.c (rb_ary_modify): use RARRAY_RAWPTR().
+
+ * array.c (ary_make_substitution, rb_ary_s_create, ary_make_partial,
+ rb_ary_splice, rb_ary_resize, rb_ary_rotate_m, rb_ary_times):
+ use ary_memcpy().
+
+Fri Jul 19 19:55:28 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (ary_mem_clear): added. This operation doesn't need WB
+ because this operation creates a reference to Qnil.
+
+ * array.c (ary_make_shared, rb_ary_store, rb_ary_shift_m,
+ rb_ary_splice, rb_ary_resize, rb_ary_fill): use ary_mem_clear()
+ instead of rb_mem_clear().
+
+ * array.c (ary_make_shared): use RARRAY_RAWPTR() instead of RARRAY_PTR().
+
+Fri Jul 19 19:18:51 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c: fix commit miss.
+ RGENGC_UNPROTECT_LOGGING should be 0.
+
+Fri Jul 19 19:15:30 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (rb_ary_resurrect): use RARRAY_RAWPTR() because there is no
+ writing.
+
+ * array.c (rb_ary_new_from_values): use ary_memcpy().
+
+Fri Jul 19 19:07:31 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (ary_memcpy): add a function to copy VALUEs into ary
+ with write barrier. If ary is promoted, use write barrier correctly.
+
+ * array.c (rb_ary_cat, rb_ary_unshift_m, rb_ary_dup,
+ rb_ary_sort_bang, rb_ary_replace, rb_ary_plus): use ary_memcpy().
+
+Fri Jul 19 15:32:57 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (rb_ary_store): use RARRAY_PTR_USE() instead of RARRAY_PTR().
+ Clearing memory space doesn't need WBs.
+
+Fri Jul 19 15:19:37 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (ary_ensure_room_for_push): use RARRAY_RAWPTR() instead of
+ RARRAY_PTR. In this code, there are no "write" operation.
+
+ * array.c (rb_ary_equal): ditto.
+
+ * array.c (recursive_equal): ditto.
+
+Fri Jul 19 15:09:22 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c, internal.h (rb_gc_writebarrier_remember_promoted): add a new
+ function to remember an specified object. This api is only
+ experimental (strongly depend on WB/rgengc strategy).
+
+Fri Jul 19 14:56:00 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (ary_unprotect_logging): use (void *) for first parameter
+ because VALUE is not defined before including ruby/ruby.h.
+
+Fri Jul 19 14:19:48 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * ext/pathname/pathname.c (path_inspect): use PRIsVALUE to preserve
+ the result encoding.
+
+Fri Jul 19 12:35:41 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/socket/test_tcp.rb (test_initialize_failure): Use EADDRNOTAVAIL
+ to test an error message generated by bind() failure.
+
+Fri Jul 19 11:27:38 2013 Zachary Scott <e@zzak.io>
+
+ * lib/racc/parser.rb: [DOC] Capitalize "Ruby" in documentation
+ Patch by Dave Worth https://github.com/ruby/ruby/pull/341
+
+Fri Jul 19 11:26:28 2013 Zachary Scott <e@zzak.io>
+
+ * ext/psych/lib/psych*: [DOC] Capitalize "Ruby" in documentation
+ Patch by Dave Worth https://github.com/ruby/ruby/pull/341
+
+Fri Jul 19 11:25:12 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rdoc/*: [DOC] Capitalize "Ruby" in documentation
+ Patch by Dave Worth https://github.com/ruby/ruby/pull/341
+
+Fri Jul 19 11:23:55 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rubygems*: [DOC] Capitalize "Ruby" in documentation
+ Patch by Dave Worth https://github.com/ruby/ruby/pull/341
+
+Fri Jul 19 11:16:54 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb (Set#to_set): Define Set#to_set so that aSet.to_set
+ returns self. [Fixes GH-359]
+
+Fri Jul 19 11:10:23 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rake/*: [DOC] Capitalize "Ruby" in documentation
+ Patch by Dave Worth https://github.com/ruby/ruby/pull/341
+
+Fri Jul 19 01:04:14 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/-test-/bignum/intpack.c: Renamed from ext/-test-/bignum/pack.c.
+ (Init_intpack): Renamed from Init_pack.
+ Reported by Naohisa Goto. [ruby-dev:47526] [Bug #8655]
+
+Fri Jul 19 00:54:27 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * test/ruby/test_array.rb (test_count): add a test case for #count
+ with an argument. See Bug #8654.
+
+Thu Jul 18 23:45:06 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_eql): compare RARRAY_PTR() for performance
+ improvement in case of that self and other are shared.
+
+Thu Jul 18 22:46:42 2013 Zachary Scott <e@zzak.io>
+
+ * lib/cgi.rb: [DOC] Capitalize "Ruby" in documentation [Fixes GH-341]
+ Patch by Dave Worth https://github.com/ruby/ruby/pull/341
+ * lib/webrick.rb: ditto
+ * lib/scanf.rb: ditto
+ * lib/xmlrpc/config.rb: ditto
+ * lib/resolv.rb: ditto
+ * lib/e2mmap.rb: ditto
+ * lib/fileutils.rb: ditto
+ * lib/mkmf.rb: ditto
+ * lib/cgi/session.rb: ditto
+ * lib/yaml.rb: ditto
+ * lib/erb.rb: ditto
+ * lib/irb.rb: ditto
+ * lib/tracer.rb: ditto
+ * lib/net/http.rb: ditto
+ * ext/syslog/lib/syslog/logger.rb: ditto
+ * sample/pty/expect_sample.rb: ditto
+
+Thu Jul 18 21:30:50 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_sq_fast): Specialize the last iteration of the
+ outer loop.
+ (bigfixize): A condition simplified.
+
+Thu Jul 18 21:15:41 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_equal): compare RARRAY_PTR() for performance
+ improvement in case of that self and other are shared.
+
+Thu Jul 18 20:44:51 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_fill): use memfill().
+
+Thu Jul 18 20:35:14 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * array.c (rb_ary_count): check length to avoid SEGV
+ while iterating. Remove other pointer loop when arg is given.
+
+ * test/ruby/test_array.rb (test_count): add test for bug.
+ [ruby-core:56072] [Bug #8654]
+
+Thu Jul 18 18:14:36 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_count): iterate items appropriately.
+ [Bug #8654]
+
+Thu Jul 18 17:35:41 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_flatten): performance improvement by not using
+ rb_hash_to_a() to avoid array creation with rb_assoc_new().
+
+Thu Jul 18 16:16:17 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c: add logging feature for RGenGC's write barrier unprotect
+ event.
+
+Thu Jul 18 15:45:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (RUBY_SAFE_LEVEL_CHECK): make only
+ rb_set_safe_level(4) an error always but make rb_secure(4) an error
+ only in the core. [ruby-dev:47517] [Bug #8652]
+
+Thu Jul 18 15:42:01 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: fix spell miss.
+
+Thu Jul 18 15:11:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (ruby_safe_level_4): get rid of special
+ character. [ruby-dev:47512] [misc #8646]
+
+Thu Jul 18 14:51:39 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (ary_alloc): slim setup process.
+
+Thu Jul 18 14:37:57 2013 Koichi Sasada <ko1@atdot.net>
+
+ * string.c (str_alloc): no need to clear RString (already cleared).
+
+Thu Jul 18 12:57:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (BDIGITS_ZERO): Defined.
+ (bary_pack): Use BDIGITS_ZERO.
+ (bary_unpack): Ditto.
+ (bary_mul_single): Ditto.
+ (bary_mul_normal): Ditto.
+ (bary_sq_fast): Ditto.
+ (bary_mul_balance_with_mulfunc): Ditto.
+ (bary_mul_precheck): Ditto.
+ (bary_mul_toom3_branch): Ditto.
+ (rb_cstr_to_inum): Ditto.
+ (big_shift3): Ditto.
+ (bigmul1_toom3): Ditto.
+ (bary_divmod): Ditto.
+
+Thu Jul 18 06:30:02 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename gc related functions with prefix "gc_".
+ * before_gc_sweep() -> gc_before_sweep().
+ * after_gc_sweep() -> gc_after_sweep().
+ * lazy_sweep() -> gc_lazy_sweep().
+ * rest_sweep() -> gc_rest_sweep().
+ * slot_sweep() -> gc_slot_sweep().
+
+ * gc.c: rename a heap management function with prefix "heap_".
+ * get_freeobj() -> heap_get_freeobj().
+
+ * gc.c: rename markable_object_p() to is_markable_object().
+
+Wed Jul 17 22:57:40 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (delete_if_i): use ST_DELETE.
+
+Wed Jul 17 22:34:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: An static assertion for relation of SIZEOF_LONG and
+ SIZEOF_BDIGITS is added.
+ (bary_mul_precheck): Reduce comparisons.
+ (bary_mul): Invoke bary_sq_fast or bary_mul1 if the bignum size is
+ small.
+ (bigfixize): Resize the argument bignum here.
+ (bignorm): Don't call bigtrunc after bigfixize.
+
+Wed Jul 17 22:13:26 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_replace): performance improvement by using
+ st_copy().
+
+Wed Jul 17 17:19:54 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename heap management functions with prefix "heap_".
+ * allocate_sorted_array() -> heap_allocate_sorted_array().
+ * slot_add_freeobj() -> heap_slot_add_freeobj().
+ * assign_heap_slot() -> heap_assign_slot().
+ * add_heap_slots() -> heap_add_slots().
+ * init_heap() -> heap_init().
+ * set_heap_increment() -> heap_set_increment().
+
+ * gc.c (initial_expand_heap): inlined in rb_gc_set_params().
+
+Wed Jul 17 17:12:23 2013 Matthew M. Boedicker <matthewm@boedicker.org>
+
+ * hash.c (env_fetch): Add key name to message on ENV.fetch KeyError,
+ as well as Hash#fetch. [ruby-core:56062] [Feature #8649]
+
+Wed Jul 17 15:59:33 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: catch up last changes for debugging/checking mode.
+
+Wed Jul 17 15:50:10 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_objspace_free): free slot itself.
+
+ * gc.c (objspace_each_objects): fix condition.
+ Use slot->body instead of slot.
+
+ * gc.c (count_objects): use "slot" variable.
+
+Wed Jul 17 15:21:10 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (unlink_heap_slot): fix memory leak.
+ free slot itself at free_heap_slot().
+
+ Reproduce-able code is here:
+ N1 = 100_000; N2 = 1_000_000
+ N1.times{ary = []; N2.times{ary << ''}}
+ Maybe this problem is remaining in Ruby 2.0.0.
+
+ * gc.c (unlink_heap_slot): remove not working code.
+
+Wed Jul 17 14:31:13 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: re-design the heap structure.
+
+ (1) The heap is consists of a set of slots.
+ (2) Each "slot" has a "slot_body".
+ slot::start and slot::limit specify RVALUE beginning address
+ and number of RVALUE in a "slot_body".
+ (3) "slot_body" contains a pointer to slot (slot_body::header::slot)
+ and an array of RVALUE.
+ (4) heap::sorted is an array of "slots", sorted by an address of
+ slot::body.
+
+ See https://bugs.ruby-lang.org/projects/ruby-master/wiki/GC_design
+ for more details (figure).
+
+ * gc.c: Avoid "heaps" terminology. It is ambiguous.
+
+Wed Jul 17 13:29:16 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: fix heaps_header and heaps_slot to reduce memory consumption.
+ (1) move heaps_header::start and limit to heaps_slot.
+ (2) remove heaps_header::end which can be calculated by start+limit.
+
+ * gc.c: catch up above change.
+
+Wed Jul 17 12:30:05 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/st.h (st_strcasecmp): Macro defined for compatibility.
+ (st_strncasecmp): Ditto.
+
+Wed Jul 17 11:57:45 2013 Takeyuki FUJIOKA <xibbar@ruby-lang.org>
+
+ * lib/cgi/util.rb (CGI::Util#escape, unescape): Avoid use of regexp
+ special global variable. [Feature #8648] Thanks to fotos.
+
+Wed Jul 17 11:57:10 2013 Takeyuki FUJIOKA <xibbar@ruby-lang.org>
+
+ * lib/erb.rb (ERB::Util#url_encode): Avoid use of regexp special global
+ variable. [Feature #8648] Thanks to fotos.
+
+Wed Jul 17 08:12:41 2013 Tanaka Akira <akr@fsij.org>
+
+ * st.c (st_locale_insensitive_strcasecmp): Renamed from st_strcasecmp.
+ (st_locale_insensitive_strncasecmp): Renamed from st_strncasecmp.
+
+ * include/ruby/st.h: Follow above changes.
+
+ * include/ruby/ruby.h: Ditto.
+
+Wed Jul 17 00:14:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigmul1_toom3): Use bigdivrem_single instead of bigdivrem.
+ (big_three): Removed.
+ (Init_Bignum): Don't initialize big_three.
+
+Tue Jul 16 21:46:03 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * configure.in: revert r42008. strcasecmp() uses the current locale.
+
+ * include/ruby/ruby.h: ditto.
+
+ * st.c (st_strcasecmp): ditto.
+
+Tue Jul 16 21:07:04 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * configure.in: check strcasecmp().
+
+ * include/ruby/ruby.h: use strcasecmp() as st_strcasecmp() if it
+ exists.
+
+ * st.c (st_strcasecmp): define the function only if strcasecmp()
+ doesn't exist.
+
+Tue Jul 16 20:21:28 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigsq): Renamed from bigsqr.
+
+Tue Jul 16 19:42:08 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (USHORT): Unused macro removed.
+
+Tue Jul 16 19:18:51 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: slim a path of newobj_of().
+
+ * gc.c (objspace): add a new field objspace::freelist, which contains
+ available RVALUEs.
+
+ * gc.c (newobj_of): simply call new function `get_freeobj()'.
+ get_freeobj() returns objspace::freelist. If objspace::freelist
+ is not available, refill objspace::freelist with a slot pointed by
+ objspace::heap::free_slots.
+
+ * gc.c (before_gc_sweep): clear objspace::freelist.
+
+ * gc.c (slot_sweep): clear slot::freelist.
+
+ * gc.c (heaps_prepare_freeslot): renamed to heaps_prepare_freeslot.
+
+ * gc.c (unlink_free_heap_slot): remove unused function.
+
+ * gc.c (rb_free_const_table): remove unused function.
+
+Tue Jul 16 19:05:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big_shift3): Big shift width is not a problem for right
+ shift.
+
+Tue Jul 16 18:50:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_count): [DOC] fix typo. Array#count uses ==, not
+ ===. a question at asakusa.rb ML.
+
+Tue Jul 16 18:35:48 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul_karatsuba): Avoid duplicate calculation when
+ squaring.
+ (bary_mul_toom3_branch): Ditto.
+
+Tue Jul 16 17:43:22 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (link_free_heap_slot): removed.
+
+ * gc.c (slot_sweep): use `heaps_add_freeslot' instead of
+ `link_free_heap_slot'.
+
+ * gc.c (assign_heap_slot): use local variable `slot' instead of
+ `heaps'.
+
+Tue Jul 16 17:21:39 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (assign_heap_slot): refactoring variable names.
+
+ * gc.c (slot_add_freeobj): added.
+
+ * gc.c (heaps_add_freeslot): added.
+
+ * gc.c (finalize_list, rb_gc_force_recycle, slot_sweep): use
+ `slot_add_freeobj' instead of modifying linked list directly.
+
+Tue Jul 16 16:30:58 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (lazy_sweep): refactoring.
+
+Tue Jul 16 13:32:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * encoding.c (enc_set_index): since r41967, old terminator is dealt
+ with in str_fill_term(). should not consider it here because this
+ function is called before any encoding is set.
+
+Tue Jul 16 11:12:03 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * proc.c (rb_block_arity): raise ArgumentError if no block given.
+
+Tue Jul 16 08:15:22 2013 Zachary Scott <e@zzak.io>
+
+ * ext/bigdecimal/lib/bigdecimal/util.rb: [DOC] document top-level
+ classes from BigDecimal utils native extensions
+
+Tue Jul 16 03:23:03 2013 Zachary Scott <e@zzak.io>
+
+ * numeric.c: [DOC] improve rdoc formatting for parameters and links
+
+Mon Jul 15 14:40:00 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/intern.h (rb_big2str0): Deprecated.
+
+ * bignum.c (rb_big2str1): Renamed from rb_big2str0.
+ (rb_big2str0): Deprecated wrapper for rb_big2str1.
+ (rb_big2str): Invoke rb_big2str1 instead of rb_big2str0.
+
+Mon Jul 15 14:13:02 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * struct.c (rb_struct_each_pair): use rb_yield_values(2, key, value)
+ instead of rb_yield(rb_assoc_new(key, value)) if rb_block_arity()
+ is greater than 1.
+
+Mon Jul 15 13:46:26 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: Add static assertions.
+
+Mon Jul 15 13:36:02 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_each_pair): performance improvement by using
+ rb_block_arity().
+
+Mon Jul 15 13:15:37 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * proc.c (rb_block_arity): create internal API rb_block_arity().
+ it returns arity of given block.
+
+Mon Jul 15 13:07:27 2013 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * lib/prime.rb (Prime::EratosthenesGenerator,
+ Prime::EratosthenesSieve): New implementation by
+ robertjlooby <robertjlooby AT gmail.com>.
+
+ * test/test_prime.rb: updated with new method name
+
+Mon Jul 15 11:32:46 2013 Zachary Scott <e@zzak.io>
+
+ * numeric.c (rb_cNumeric): [DOC] Added comment for Numeric to fix doc
+
+Mon Jul 15 11:24:48 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (maxpow_in_bdigit_dbl): Useless #if removed.
+
+Mon Jul 15 11:10:46 2013 Zachary Scott <e@zzak.io>
+
+ * bignum.c (rb_big_coerce): [DOC] Add docs for Bignum#coerce
+ Based on patch by Juanito Fatas [Fixes GH-360]
+ https://github.com/ruby/ruby/pull/360
+
+Mon Jul 15 10:56:01 2013 Zachary Scott <e@zzak.io>
+
+ * thread.c (mutex_sleep): [DOC] Awake thread will reacquire lock
+ By Tim Abdulla [Fixes GH-342] https://github.com/ruby/ruby/pull/342
+
+Mon Jul 15 10:45:09 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (nlz16): Use __builtin_clz if possible.
+ (nlz32): Use __builtin_clz or __builtin_clzl if possible.
+ (nlz64): Use __builtin_clzl or __builtin_clzll if possible.
+ (nlz128): Use __builtin_clzll if possible.
+
+ * configure.in: Check __builtin_clz, __builtin_clzl and
+ __builtin_clzll.
+
+Mon Jul 15 09:39:07 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (power_cache_get_power): Use bitsize instead of ceil_log2.
+ (ones): Removed.
+ (next_pow2): Removed.
+ (floor_log2): Removed.
+ (ceil_log2): Removed.
+
+ * configure.in (__builtin_popcountl): Don't check.
+
+Mon Jul 15 02:47:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * localeinit.c (rb_locale_charmap, Init_enc_set_filesystem_encoding):
+ move from encoding.c.
+
+ * miniinit.c (rb_locale_charmap, Init_enc_set_filesystem_encoding):
+ define miniruby specific functions only.
+
+Mon Jul 15 02:32:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * encoding.c (rb_enc_init): no longer needs NO_PRESERVED_ENCODING.
+
+ * encoding.c (enc_inspect): defer loading autoloaded encoding.
+
+ * encoding.c (enc_check_encoding): use is_data_encoding() to check
+ type consistently.
+
+ * encoding.c (must_encoding): return rb_encoding* instead of encoding
+ index.
+
+ * encoding.c (enc_check_encoding): use is_data_encoding() to check
+ type consistently.
+
+ * encoding.c (must_encoding): return rb_encoding* instead of encoding
+ index.
+
+Mon Jul 15 02:21:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (str_fill_term): consider old terminator length, and should
+ not use rb_enc_ascget since it depends on the current encoding which
+ may not be compatible with the new terminator. [Bug #8634]
+
+ * encoding.c (enc_inspect): use PRIsVALUE to preserve the result
+ encoding.
+
+Sun Jul 14 23:21:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Check __builtin_popcountl, __builtin_bswap32 and
+ __builtin_bswap64.
+
+ * internal.h (swap32): Use the configure result for the condition to
+ use __builtin_bswap32.
+ (swap64): Use the configure result for the condition to use
+ __builtin_bswap64.
+
+ * bignum.c (ones): Use the configure result for the condition to use
+ __builtin_popcountl.
+ (bary_unpack_internal): Use appropriate types for swap argument.
+
+Sun Jul 14 22:21:11 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_subb): Support xn < yn.
+ (bigsub_core): Removed.
+ (bigsub): Don't compare before subtraction. Just subtract and
+ get the two's complement if the subtraction causes a borrow.
+
+Sun Jul 14 00:36:03 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (DIGSPERLONG): Unused macro removed.
+ (DIGSPERLL): Ditto.
+
+Sun Jul 14 00:32:51 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_aref): Less scan when the number is negative.
+
+Sun Jul 14 00:17:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big_shift): Avoid signed integer overflow.
+
+Sun Jul 14 00:14:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul_precheck): Use bary_small_lshift or
+ bary_mul_normal if xl is 1.
+
+Sat Jul 13 22:58:16 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big_shift3): New function.
+ big_lshift and big_rshift are merged.
+ (big_shift2): New function.
+ (big_lshift): Use big_shift3.
+ (big_rshift): Ditto.
+ (check_shiftdown): Removed.
+ (rb_big_lshift): Use big_shift2 and big_shift3.
+ (rb_big_rshift): Ditto.
+ (big_lshift): Removed.
+ (big_rshift): Ditto.
+
+Sat Jul 13 15:51:38 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_small_lshift): Use size_t instead of long.
+ (bary_small_rshift): Ditto.
+
+Sat Jul 13 15:33:33 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_small_lshift): Functions moved to remove
+ declaration.
+ (bary_small_rshift): Ditto.
+
+Sat Jul 13 12:27:34 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * encoding.c (rb_enc_associate_index): fill new terminator length, not
+ old one.
+
+Sat Jul 13 12:24:24 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32: move from ext/dl and ext/fiddle. since ext/extmk.rb
+ builds extensions in alphabetical order, compiled?('fiddle') under
+ ext/dl makes no sense.
+
+Sat Jul 13 09:26:09 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (biglsh_bang): Removed.
+ (bigrsh_bang): Ditto.
+ (bigmul1_toom3): Use bary_small_lshift and bary_small_rshift.
+
+Sat Jul 13 01:04:43 2013 Zachary Scott <e@zzak.io>
+
+ * lib/rubygems/psych_additions.rb: Ignore Psych docs here
+
+Fri Jul 12 18:10:46 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/fiddle/win32/lib/win32/registry.rb
+ (Win32::Registry::API#make_wstr): same as r41922.
+
+Fri Jul 12 16:28:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * encoding.c (rb_enc_associate_index): refill the terminator if it
+ becomes longer than before. [ruby-dev:47500] [Bug #8624]
+
+ * string.c (str_null_char, str_fill_term): get rid of out of bound
+ access.
+
+ * string.c (rb_str_fill_terminator): add a parameter for the length of
+ new terminator.
+
+Fri Jul 12 11:26:25 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_reject_bang): do not call rb_hash_foreach() if RHash
+ has ntbl and it is empty.
+
+Fri Jul 12 11:17:41 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (recursive_hash): use RHASH_SIZE() to check hash size.
+
+Fri Jul 12 00:20:00 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_size): use RHASH_SIZE().
+
+Fri Jul 12 00:08:24 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_values): set array capa to RHASH_SIZE().
+
+Thu Jul 11 23:54:45 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_keys): set array capa to RHASH_SIZE().
+
+Thu Jul 11 21:30:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_pow): undef pow to get rid of infinite
+ recursive call. re-fix [Bug #8495]. [ruby-core:55923] [Bug #8621]
+
+Thu Jul 11 20:18:13 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/dl/win32/lib/win32/registry.rb (Win32::Registry::API#make_wstr):
+ remove workaround to append WCHAR terminator.
+
+ * transcode.c (str_encode_associate): fill terminator after conversion.
+
+ * string.c (rb_enc_str_new, rb_str_set_len, rb_str_resize): fill
+ minimum length of the encoding as the terminator.
+
+ * string.c (str_buf_cat, rb_str_buf_append, rb_str_splice_0): ditto.
+
+ * string.c (str_make_independent_expand, rb_str_modify_expand): make
+ the capacity enough for multi-byte terminator.
+
+ * string.c (rb_string_value_cstr): fill minimum length of the encoding
+ as the terminator.
+
+ * string.c (rb_string_value_cstr): check null char in char, not in
+ byte.
+
+Thu Jul 11 14:48:35 2013 Zachary Scott <e@zzak.io>
+
+ * array.c: Replace confusing example for #reverse_each in overview
+ Patch by Earl St Sauver [Fixes documenting-ruby/ruby-12]
+ https://github.com/documenting-ruby/ruby/pull/12
+
+Thu Jul 11 14:22:37 2013 Zachary Scott <e@zzak.io>
+
+ * test/drb/ut_eq.rb: Use localhost for drb tests [Bug #7311]
+ Patch by Vit Ondruch [ruby-core:49101]
+ * test/drb/ut_array.rb: ditto
+ * test/drb/ut_array_drbssl.rb: ditto
+
+Thu Jul 11 13:48:03 2013 Zachary Scott <e@zzak.io>
+
+ * sprintf.c: Fix typo patch by @hynkle [Fixes GH-357]
+ https://github.com/ruby/ruby/pull/357
+
+Thu Jul 11 13:00:34 2013 Zachary Scott <e@zzak.io>
+
+ * lib/securerandom.rb: Refactor conditions by Rafal Chmiel
+ [Fixes GH-326] https://github.com/ruby/ruby/pull/326
+
+Thu Jul 11 12:04:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: Don't use toom3 after once karatsuba is chosen.
+ (mulfunc_t): New type.
+ (bary_mul_toom3_start): Renamed from bary_mul.
+ (bary_mul_karatsuba_start): Renamed from bary_mul.
+ (bary_mul_balance_with_mulfunc): Renamed from bary_mul_balance and
+ new argument, mulfunc, is added.
+ (rb_big_mul_balance): Invoke bary_mul_balance_with_mulfunc with
+ bary_mul_toom3_start.
+ (bary_mul_karatsuba): Invoke bary_mul_karatsuba_start instead of
+ bary_mul.
+ (bary_mul_precheck): Extracted from bary_mul.
+ (bary_mul_karatsuba_branch): Extracted from bary_mul.
+ (bary_mul_karatsuba_start): New function to call bary_mul_precheck
+ and bary_mul_karatsuba_branch.
+ (bary_mul_toom3_branch): Extracted from bary_mul.
+ (bary_mul_toom3_start): New function to call bary_mul_precheck and
+ bary_mul_toom3_branch.
+ (bary_mul): Just call bary_mul_toom3_start.
+ Arguments for work memory are removed.
+ (rb_cstr_to_inum): Follow the bary_mul change.
+ (bigmul0): Ditto.
+
+Thu Jul 11 10:46:38 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/probes_to_wiki.rb: fix usage comment. use Enumerable#grep
+ which yields each elements to reduce unnecessary array.
+
+Thu Jul 11 10:09:18 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * process.c (rb_daemon): daemon(3) is implemented with fork(2).
+ Therefore it needs rb_thread_atfork(). (and revert r41903)
+
+Thu Jul 11 03:22:10 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * tool/probes_to_wiki.rb: adding a script to convert probes.d to wiki
+ format for easy wiki updates.
+
+Thu Jul 11 00:54:07 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * man/ri.1: Incorrect use of .Dd macro [Bug #8620] by Tristan Hill
+
+Thu Jul 11 00:48:29 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/delegate.rb: Add example for __setobj__ and __getobj__
+ [Bug #8615] Patch by Caleb Thompson
+
+Wed Jul 10 23:29:22 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/logger.rb: Use :call-seq: for method signature rdoc
+
+Wed Jul 10 23:23:18 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/logger.rb (#add): Remove incorrect rdoc for return value
+ [Bug #8567] Reported by Tim Pease.
+
+Wed Jul 10 23:12:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_subpos): make public function.
+
+Wed Jul 10 22:44:19 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: Add a static assertion for RBIGNUM_EMBED_LEN_MAX.
+
+Wed Jul 10 22:31:25 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * string.c (rb_str_index): cache single byte flag and some
+ cosmetic changes.
+
+Wed Jul 10 22:03:27 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_2comp): Don't use bary_plus_one.
+ (bary_add_one): Replaced by the implementation of bary_plus_one.
+
+Wed Jul 10 20:48:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (sizeof_bdigit_dbl): check sizeof(BDIGIT_DBL).
+
+ * internal.h (STATIC_ASSERT): move from enum.c.
+
+Wed Jul 10 20:08:21 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (SIZEOF_BDIGIT_DBL): Add a ifdef guard for test.
+
+Wed Jul 10 14:18:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (fork_daemon): kill the other threads all and abandon the
+ kept mutexes.
+
+Wed Jul 10 11:35:36 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/net/http/test_http.rb (TestNetHTTP_v1_2#test_get,
+ TestNetHTTP_v1_2_chunked#test_get): shouldn't check
+ HttpResponse#decode_content if Zlib is not available.
+ ko1 complained via IRC.
+
+Wed Jul 10 10:20:07 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/rbinstall.rb: always require rubygems to stabilize rubygems
+ related status like whether Gem::Specification is defined or not.
+
+ * tool/rbinstall.rb (Gem::Specification.unresolved_deps): define stub.
+
+Wed Jul 10 08:21:15 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Import RubyGems 2.1
+ * test/rubygems: Ditto.
+
+Wed Jul 10 07:34:34 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/ext/ext_conf_builder.rb: Remove siteconf file after
+ building the gem.
+ * test/rubygems/test_gem_ext_ext_conf_builder.rb: Test for the above.
+
+ * lib/rubygems/psych_tree.rb (module Gem): Add backward compatibility
+ for r41148
+
+ * test/rubygems/test_gem_package.rb: Add backward compatibility for
+ double-slash elimination.
+
+Wed Jul 10 06:22:27 2013 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * ext/date/date_parse.c (date_zone_to_diff): [ruby-core:55831].
+
+Wed Jul 10 00:41:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul): x*1 is x.
+
+Tue Jul 9 22:24:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul1): No need to invoke MEMZERO at last.
+ (bary_mul_single): Invoke MEMZERO here.
+
+Tue Jul 9 21:40:01 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_text.rb: Add missing tests for Text#<<.
+ Reported by nagachika. Thanks!!!
+
+Tue Jul 9 18:02:38 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/fileutils.rb (FileUtils#chown_R): Do not skip traversal even
+ if user and group are both nil, to be consistent with #chown and
+ other commands.
+
+Tue Jul 9 17:58:26 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * test/fileutils/test_fileutils.rb
+ (TestFileUtils#assert_output_lines): New utility assertion
+ method for testing verbose output.
+
+Tue Jul 9 17:43:57 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/test_tracer.rb: catch up recent rubygems changes.
+
+Tue Jul 9 16:58:30 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/{dl,fiddle}/win32/lib/win32/registry.rb: hope that the final
+ resolution to fix the failure of test-all. and includes Win64
+ support (fixed a potential bug).
+
+Tue Jul 9 15:57:20 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * object.c: Fix rdoc for Kernel#<=>. [Fixes GH-352]
+
+Tue Jul 9 15:53:51 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/fileutils.rb (FileUtils#mode_to_s): Define mode_to_s() also
+ as singleton method, or FileUtils.chmod fails in verbose mode.
+
+Tue Jul 9 15:16:02 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * test/fileutils/fileasserts.rb
+ (Test::Unit::FileAssertions#assert_not_symlink): Add a missing
+ optional argument "message".
+
+Tue Jul 9 15:03:24 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/fileutils.rb (FileUtils#chown, FileUtils#chown_R): If user
+ and group are both nil, print ":".
+
+Tue Jul 9 12:47:08 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * io.c (appendline): use READ_CHAR_PENDING_XXX macros and
+ RSTRING_END().
+
+ * io.c (rb_io_getline_1): rewrite nested if statement into one
+ statement.
+
+Tue Jul 9 11:04:35 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/{dl,fiddle}/win32/lib/win32/registry.rb (Win32::Registry#check):
+ should report the position of the error.
+
+ * ext/{dl,fiddle}/win32/lib/win32/registry.rb
+ (Win32::Registry#QueryValue): workaround for test-all crash.
+
+Tue Jul 9 10:27:56 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/{dl,fiddle}/win32/lib/win32/registry.rb
+ (Win32::Registry.expand_environ): use suitable encoding for the
+ string.
+
+ * ext/{dl,fiddle}/win32/lib/win32/registry.rb (Win32::Registry#read):
+ should return REG_SZ, REG_EXPAND_SZ and REG_MULTI_SZ values with
+ the expected encoding -- assumed as the same encoding of name.
+
+Tue Jul 9 10:02:45 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/{dl,fiddle}/win32/lib/win32/registry.rb
+ (Win32::Registry::Error#initialize): use suitable encoding for the
+ string.
+
+Tue Jul 9 09:46:53 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/dl/win32/lib/win32/registry.rb (Win32::Registry.expand_environ):
+ use suitable encoding for the string. fixed a test-all error of
+ r41838.
+
+ * ext/fiddle/win32/lib/win32/registry.rb: same changes of r41838 and
+ this revision of dl's win32/registry.rb.
+
+Tue Jul 9 07:39:45 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems 2.0.4. See
+ https://github.com/rubygems/rubygems/blob/2.0/History.txt for changes
+
+Tue Jul 9 01:47:16 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (biglsh_bang): Don't shift a BDIGIT with BITSPERDIG bits.
+ (bigrsh_bang): Ditto.
+
+Tue Jul 9 01:17:57 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigrsh_bang): Fix bignum digits overrun.
+
+Tue Jul 9 00:46:22 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (biglsh_bang): Fix bignum digits under-run.
+
+Mon Jul 8 23:36:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/dl/win32/lib/win32/registry.rb (Error, API): use WCHAR
+ interfaces. c.f. [Bug #8508]
+
+Mon Jul 8 23:13:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_pow): move from win32.h and disable strict
+ ANSI mode macro to let _controlfp() stuff defined.
+ [ruby-core:55312] [Bug #8495]
+
+ * numeric.c (finite): add declaration for strict ANSI.
+ [ruby-core:55312] [Bug #8495]
+
+ * thread_win32.c (w32_thread_start_func, thread_start_func_1),
+ (timer_thread_func): use __stdcall instead of _stdcall which is
+ unavailable in strict ANSI mode. [ruby-core:55312] [Bug #8495]
+
+ * win32/win32.c (gettimeofday): use __cdecl instead of _cdecl.
+
+Mon Jul 8 22:41:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul): Arguments for work memory added.
+ (bary_mul_balance): Ditto.
+ (bary_mul_karatsuba): Ditto.
+
+Mon Jul 8 22:03:30 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_sq_fast): New function for testing.
+ (rb_big_mul_toom3): Ditto.
+
+ * internal.h (rb_big_sq_fast): Declared.
+ (rb_big_mul_toom3): Ditto.
+
+Mon Jul 8 21:59:34 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul_balance): Initialize a local variable to suppress
+ a warning.
+
+Mon Jul 8 20:55:22 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul_balance): Reduce work memory.
+
+Mon Jul 8 08:26:15 2013 Martin Bosslet <Martin.Bosslet@gmail.com>
+
+ * test/openssl/test_pkey_ec.rb: Skip tests for "Oakley" curves as
+ they are not suitable for ECDSA.
+ [ruby-core:54881] [Bug #8384]
+
+Mon Jul 8 08:03:01 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul): Add a RB_GC_GUARD.
+
+Sun Jul 7 23:56:32 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul_karatsuba): Unreachable code removed. Remove
+ several branches.
+
+Sun Jul 7 22:59:06 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (rb_big_mul_normal): Declared.
+ (rb_big_mul_balance): Ditto.
+ (rb_big_mul_karatsuba): Ditto.
+
+ * bignum.c (rb_big_mul_normal): New function for tests.
+ (rb_big_mul_balance): Ditto.
+ (rb_big_mul_karatsuba): Ditto.
+
+Sun Jul 7 19:21:30 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: Reorder functions to decrease forward reference.
+
+Sun Jul 7 14:41:57 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: (bigsub_core): Use bary_sub.
+ (bary_sub): Returns a borrow flag. Use bary_subb.
+ (bary_subb): New function for actually calculating subtraction with
+ borrow.
+ (bary_sub_one): New function.
+ (bigadd_core): Use bary_add.
+ (bary_add): Returns a carry flag. Use bary_addc.
+ (bary_addc): New function for actually calculating addition with
+ carry.
+ (bary_add_one): New function.
+ (bary_muladd_1xN): Extracted from bary_mul_normal.
+ (bigmul1_normal): Removed.
+ (bary_mul_karatsuba): New function.
+ (bary_mul1): Invoke rb_thread_check_ints after bary_mul_normal.
+ (bary_mul): Remove most and least significant zeros before actual
+ multiplication. Use bary_sq_fast, bary_mul_balance,
+ bary_mul_karatsuba and bigmul1_toom3 as bigmul0.
+ (bigmul1_balance): Removed.
+ (bigmul1_karatsuba): Removed.
+ (bigsqr_fast): Removed.
+ (bary_sparse_p): Extracted from big_sparse_p.
+ (big_sparse_p): Removed.
+ (bigmul0): Use bary_mul.
+
+Sun Jul 7 11:54:33 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * NEWS: Add REXML::Text#<< related updates.
+
+Sun Jul 7 11:49:19 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/text.rb (REXML::Text#<<): Support appending in not
+ "raw" mode. [Bug #8602] [ruby-dev:47482]
+ Reported by Ippei Obayashi. Thanks!!!
+
+Sun Jul 7 11:43:13 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/text.rb (REXML::Text#<<): Support method chain use by "<<"
+ like other objects.
+
+Sun Jul 7 11:34:18 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/text.rb (REXML::Text#clear_cache): Extract common
+ cache clear code.
+
+Sun Jul 7 11:01:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_DTRACE_POSTPROCESS): dtrace version SUN D 1.11
+ introduces a check in the dtrace compiler to ensure that probes
+ actually exist. If there are no probes, then the -G step will
+ fail. As this test is only being used to determine whether -G is
+ necessary (for instance, on OSX it is not), adding a real probe to
+ the conftest allows it to succeed on newer versions of dtrace.
+ Patch by Eric Saxby <sax AT livinginthepast.org> at
+ [ruby-core:55826]. [Fixes GH-351], [Bug #8606].
+
+Sun Jul 7 10:07:22 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_sq_fast): Extracted from bigsqr_fast and
+ ensure not to access zds[2*xn].
+ (bigsqr_fast): Allocate the result bignum with 2*xn words.
+
+Sat Jul 6 07:37:43 2013 Martin Bosslet <Martin.Bosslet@gmail.com>
+
+ * ext/openssl/ossl_pkey_ec.c: Ensure compatibility to builds of
+ OpenSSL with OPENSSL_NO_EC2M defined, but OPENSSL_NO_EC not
+ defined.
+ * test/openssl/test_pkey_ec.rb: Iterate over built-in curves
+ (and assert their non-emptiness!) instead of hard-coding them, as
+ this may cause problems with respect to the different availability
+ of individual curves in individual OpenSSL builds.
+ [ruby-core:54881] [Bug #8384]
+
+ Thanks to Vit Ondruch for providing the patch!
+
+Sat Jul 6 07:12:39 2013 Martin Bosslet <Martin.Bosslet@gmail.com>
+
+ * test/openssl/test_x509crl.rb: Remove unused variable.
+ [ruby-core:53501] [Bug #8114]
+
+ Thanks, Vipul Amler, for pointing this out!
+
+Sat Jul 6 06:37:10 2013 Martin Bosslet <Martin.Bosslet@gmail.com>
+
+ * ext/openssl/ossl.c: Provide CRYPTO_set_locking_callback() and
+ CRYPTO_set_id_callback() callback functions ossl_thread_id and
+ ossl_lock_callback to ensure the OpenSSL extension is usable in
+ multi-threaded environments.
+ [ruby-core:54900] [Bug #8386]
+
+ Thanks, Dirkjan Bussink, for the patch!
+
+Sat Jul 6 06:06:16 2013 Martin Bosslet <Martin.Bosslet@gmail.com>
+
+ * lib/openssl/ssl.rb: Fix SSL client connection crash for SAN marked
+ critical.
+ The patch for CVE-2013-4073 caused SSL crash when a SSL server returns
+ the certificate that has critical SAN value. X509 extension could
+ include 2 or 3 elements in it:
+
+ [id, criticality, octet_string] if critical,
+ [id, octet_string] if not.
+
+ Making sure to pick the last element of X509 extension and use it as
+ SAN value.
+ [ruby-core:55685] [Bug #8575]
+
+ Thank you @nahi for providing the patch!
+
+Sat Jul 6 04:49:38 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: register time objects so
+ they are referenced as ids during output.
+ * test/psych/test_date_time.rb: corresponding test.
+
+Fri Jul 5 20:46:39 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/ruby/test_unicode_escape.rb (TestUnicodeEscape#test_basic): this
+ assertion doesn't seems to be checking the unicode string on command
+ line, but seems to be checking how to treat the unicode string from
+ stdin. so, should escape '\' before 'u'. this fixes a test failure
+ on Windows.
+
+Fri Jul 5 19:05:40 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/fileutils.rb (FileUtils#chown, FileUtils#chown_R): Fix the
+ wrong output message when user is nil, which should be "chown
+ :group file" instead of "chown group file".
+
+Fri Jul 5 16:21:56 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * test/ruby/test_regexp.rb
+ (TestRegexp#test_options_in_look_behind)
+ (TestRegexp#assert_match_at): Add tests for another problem
+ fixed in Onigmo 5.13.5. Previously Onigmo did not allow option
+ enclosures in look-behind, which makes it impossible to
+ interpolate a regexp into another in the middle of a look-behind
+ pattern. cf. https://github.com/k-takata/Onigmo/pull/17
+
+ * test/ruby/test_regexp.rb
+ (TestRegexp#test_options_in_look_behind)
+ (TestRegexp#assert_match_at): Parse regexps in run time rather
+ than in compile time.
+
+Fri Jul 5 12:14:40 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/ruby/test_rubyoptions.rb (TestRubyOptions#test_notfound): after
+ r41710, the path of command uses backslash as the separator on
+ Windows.
+
+Fri Jul 5 11:29:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/test/unit/assertions.rb (assert_raise_with_message): move from
+ test/fileutils/test_fileutils.rb. this is still experimental and
+ the interface may be changed.
+
+Fri Jul 5 11:08:00 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (w32_spawn): r41710 made that if the command starts with
+ a quote and includes slash, removed the top quote and NOT removed the
+ last quote.
+ this fixes test failures on test/ruby/test_process.rb and
+ test/webrick.
+
+Fri Jul 5 09:53:15 2013 NARUSE, Yui <naruse@ruby-lang.org>
+ * lib/mkmf.rb (CONFIG['CPPOUTFILE']): fix r41769; CONFIG['CPPOUTFILE']
+ may be nil.
+
+Fri Jul 5 05:39:53 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (BARY_MUL1): Renamed from BARY_MUL.
+ (bary_mul1): Renamed from bary_mul.
+ (bary_mul): Renamed from bary_mul2.
+
+Fri Jul 5 04:58:05 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul_balance): Extracted from bigmul1_balance and
+ use bary_mul2 and bary_add to decrease allocations.
+
+Fri Jul 5 02:14:00 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/fileutils.rb (FileUtils#symbolic_modes_to_i): Fix the wrong
+ character class [+-=], which happened to match all desired
+ characters but also match undesired characters.
+
+ * lib/fileutils.rb (FileUtils.chmod{,_R}): Enhance the symbolic
+ mode parser to support the permission symbols u/g/o and multiple
+ actions as defined in SUS, so that chmod("g=o+w", file) works as
+ expected. Invalid symbolic modes are now rejected with
+ ArgumentError.
+
+Fri Jul 5 00:25:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (have_framework): allow header file to check.
+ [ruby-core:55745] [Bug #8593]
+
+Thu Jul 4 22:31:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * object.c (rb_obj_equal): Fixed an rb_obj_equal documentation typo
+ where "a" was used instead of "obj".
+ Fixes GH-349. Patch by @adnandoric
+
+Thu Jul 4 20:39:20 2013 Tanaka Akira <akr@fsij.org>
+
+ * tool/make-snapshot: Exit with EXIT_FAILURE when it fails.
+
+Thu Jul 4 20:20:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (maxpow_in_bdigit_dbl): Use tables if available.
+ (maxpow_in_bdigit): Ditto.
+ (U16): New macro.
+ (U32): Ditto.
+ (U64): Ditto.
+ (U128): Ditto.
+ (maxpow16_exp): New table.
+ (maxpow16_num): New table.
+ (maxpow32_exp): New table.
+ (maxpow32_num): New table.
+ (maxpow64_exp): New table.
+ (maxpow64_num): New table.
+ (maxpow128_exp): New table.
+ (maxpow128_num): New table.
+
+Thu Jul 4 18:25:25 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_cstr_to_inum): Avoid temporary buffer allocation except
+ very big base non-power-of-2 numbers.
+
+Thu Jul 4 15:51:56 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (rb_str_succ): use ONIGENC_MBCLEN_CHARFOUND_P correctly.
+
+ * string.c (rb_str_dump): ditto.
+
+Thu Jul 4 10:04:11 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * regcomp.c (): Merge Onigmo 5.13.5 23b523076d6f1161.
+
+ * [bug] (thanks Akinori MUSHA and Ippei Obayashi)
+ Fix a renumbering bug in condition regexp with a named
+ capture. [Bug #8583]
+ * [spec] (thanks Akinori MUSHA)
+ Allow ENCLOSE_OPTION in look-behind.
+
+Thu Jul 4 00:36:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * internal.h (SIGNED_INTEGER_MAX): suppress warning C4146 on VC6.
+ seems a logical ORed expression becomes unsigned.
+
+Thu Jul 4 00:13:01 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby_atomic.h (rb_w32_atomic_cas): call InterlockedCompareExchange
+ directly.
+
+ * ruby_atomic.h (ATOMIC_CAS): fix missing function call.
+
+Wed Jul 3 23:47:35 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby_atomic.h (ATOMIC_CAS): suppress C4022 and C4047 warnings in
+ VC6. only InterlockedCompareExchange is declared using PVOID.
+
+Wed Jul 3 22:29:20 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (ruby_digit36_to_number_table): Declared.
+
+ * util.c (ruby_digit36_to_number_table): Moved from scan_digits.
+
+ * bignum.c (conv_digit): Use ruby_digit36_to_number_table.
+
+ * pack.c (hex2num): Ditto.
+
+Wed Jul 3 18:12:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (install_dirs): revert DESTDIR prefix by r39841, since
+ it is fixed by r41648. [ruby-core:55760] [Bug #8115]
+
+Wed Jul 3 14:15:25 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (do_stat): use rb_w32_ustati64() in win32.c to get rid of
+ mysterious behavior of FindFirstFile() Windows API which treat "<"
+ and ">" like as wildcard characters. [ruby-core:55764] [Bug #8597]
+
+Wed Jul 3 12:06:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (maxpow_in_bdigit): Renamed from calc_hbase and return
+ maxpow.
+
+Tue Jul 2 23:47:50 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (roomof): Cast to long.
+ (rb_ull2big): Fix bignew arguments.
+
+Tue Jul 2 21:17:37 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_cstr_to_inum): Merge two temporary buffers.
+
+Tue Jul 2 20:25:04 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_cstr_to_inum): Use BDIGIT_DBL to collect adjacent digits.
+ (BDIGIT_DBL_MAX): New macro.
+ (maxpow_in_bdigit_dbl): New function.
+
+Tue Jul 2 17:23:33 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * doc/syntax/refinements.rdoc: add description of Module#using and
+ refinement inheritance by module inclusion.
+
+Tue Jul 2 17:22:44 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * internal.h: add EUC-JP and Windows-31J.
+
+ * re.c (rb_char_to_option_kcode): use built-in encoding indexes in
+ internal.h.
+
+ * internal.h: add UTF8-MAC.
+
+ * dir.c (rb_utf8mac_encoding): use built-in encoding indexes in
+ internal.h.
+
+ * internal.h: add UTF-{16,32} dummy encodings.
+
+ * string.c (rb_str_inspect, str_scrub0): use built-in encoding indexes
+ in internal.h.
+
+ * internal.h: add UTF-{16,32}{BE,LE}.
+
+ * io.c (io_strip_bom): use built-in encoding indexes in internal.h.
+
+ * internal.h (rb_{ascii8bit,utf8,usascii}_encindex): use built-in
+ encoding indexes for optimization.
+
+ * encoding.c (enc_inspect, rb_locale_encindex),
+ (enc_set_filesystem_encoding, rb_filesystem_encindex): use built-in
+ encoding indexes directly.
+
+ * encoding.c (rb_enc_set_index, rb_enc_associate_index): validate
+ argument encoding index.
+
+ * include/ruby/encoding.h (ENCODING_SET): use rb_enc_set_index()
+ instead of setting inlined bits directly.
+
+ * encoding.c (rb_enc_init): register preserved indexes.
+
+ * internal.h (ruby_preserved_encindex): move from encoding.c.
+
+Tue Jul 2 11:14:36 2013 Shota Fukumori <sorah@cookpad.com>
+
+ * lib/mkmf.rb (try_config): Fix to not replace $LDFLAGS with $libs
+ (1.9.3 behavior) [ruby-core:55752] [Bug #8595]
+
+Tue Jul 2 00:39:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/ipsocket.c (init_inetsock_internal): Don't try mismatched
+ address family if already failed.
+
+Mon Jul 1 23:07:38 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * template/encdb.h.tmpl: define encoding index macros to use the index
+ statically from C source.
+
+Mon Jul 1 22:57:19 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul2): New function.
+ (rb_cstr_to_inum): Use a better algorithm to compose the result
+ if input length is very long.
+
+Mon Jul 1 20:22:00 2013 Kenta Murata <mrkn@cookpad.com>
+
+ * ext/bigdecimal/bigdecimal.h (RB_UNUSED_VAR, UNREACHABLE):
+ import macros from ruby.h for 1.9.3.
+ [Bug #8588] [ruby-core:55730]
+
+ * ext/bigdecimal/bigdecimal.gemspec: Bump version to 1.2.1.
+
+Mon Jul 1 20:03:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/ipsocket.c (init_inetsock_internal): Use an address
+ family for local address which is different to the remote
+ address if no other choice.
+
+Mon Jul 1 15:05:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/csv.rb (CSV#<<): use StringIO#set_encoding instead of creating
+ new StringIO instance with String#force_encoding, forcing encoding
+ discards the cached coderange bits and can make further operations
+ very slow. [ruby-core:55714] [Bug #8585]
+
+ * ext/stringio/stringio.c (strio_write): keep coderange of
+ ptr->string.
+
+ * string.c (rb_enc_cr_str_buf_cat, rb_str_append): consider an empty
+ string 7bit-clean and should not discard cached coderange of string
+ to be appended.
+
+Mon Jul 1 12:56:41 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * eval.c (rb_using_module): activate refinements in the ancestors of
+ the argument module to support refinement inheritance by
+ Module#include. [ruby-core:55671] [Feature #8571]
+
+ * test/ruby/test_refinement.rb: related test.
+
+Mon Jul 1 12:02:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_cstr_to_inum): Skip leading zeros.
+
+Mon Jul 1 00:59:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (nlz16): New function.
+ (nlz32): Ditto.
+ (nlz64): Ditto.
+ (nlz128): Ditto.
+ (nlz): Redefined using an above function.
+ (bitsize): New macro.
+ (rb_cstr_to_inum): Use bitsize instead of nlz.
+
+Sun Jun 30 22:40:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * lib/prime.rb: Corrected a few comments. Patch by @Nullset14.
+ Fixes GH-346.
+
+Sun Jun 30 21:53:38 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_cstr_to_inum): Use rb_integer_unpack if base is a power
+ of 2.
+
+Sun Jun 30 10:59:23 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (join_argv): use backslash instead of slash in program
+ path, otherwise cannot invoke "./c\u{1ee7}a.exe" for some reason.
+ [ruby-core:24309] [Bug #1771]
+
+ * io.c (spawnv, spawn): use UTF-8 spawn family. [Bug #1771]
+
+ * process.c (proc_exec_sh, proc_spawn_cmd, proc_spawn_sh): ditto.
+
+ * win32/win32.c (translate_char, join_argv, has_redirection): make
+ codepage aware.
+
+ * win32/win32.c (rb_w32_udln_find_exe_r, rb_w32_udln_find_file_r):
+ codepage independent versions.
+
+ * win32/win32.c (w32_spawn): extract codepage aware code from
+ rb_w32_spawn().
+
+ * win32/win32.c (rb_w32_uspawn): add UTF-8 version function.
+
+ * win32/win32.c (w32_aspawn_flags): extract codepage aware code from
+ rb_w32_aspawn_flags().
+
+ * win32/win32.c (rb_w32_uaspawn_flags, rb_w32_uaspawn_flags): add
+ UTF-8 version functions.
+
+ * win32/win32.c (w32_getenv): extract codepage aware code from
+ rb_w32_ugetenv() and rb_w32_getenv().
+
+ * win32/win32.c (w32_stati64): extract codepage aware code from
+ rb_w32_ustati64() and rb_w32_stati64().
+
+ * dln.h (DLN_FIND_EXTRA_ARG, DLN_FIND_EXTRA_ARG_DECL): allow extra
+ arguments to dln_find_{exe,file}_r().
+
+ * dln_find.c (dln_find_exe_r, dln_find_file_r): add extract arguments.
+
+ * process.c (EXPORT_STR, EXPORT_DUP): convert to default process
+ encoding if defined.
+
+ * process.c (check_exec_env_i): convert environment variables too.
+
+ * process.c (rb_exec_fillarg): convert program path and arguments too.
+
+Sun Jun 30 01:57:08 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big_rshift): Use abs2twocomp and twocomp2abs_bang.
+
+Sun Jun 30 00:14:20 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (RBIGNUM_SET_NEGATIVE_SIGN): New macro.
+ (RBIGNUM_SET_POSITIVE_SIGN): Ditto.
+ (rb_big_neg): Inline get2comp to avoid double negation.
+
+Sat Jun 29 23:26:41 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_neg): Extracted from bary_2comp.
+ (bary_plus_one): Extracted from bary_2comp.
+ (bary_2comp): Use bary_neg and bary_plus_one.
+ (big_extend_carry): Extracted from get2comp.
+ (get2comp): Use big_extend_carry.
+ (rb_integer_unpack): Use big_extend_carry.
+ (rb_big_neg): Use bary_neg.
+
+Sat Jun 29 22:31:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_2comp): Simplified.
+
+Sat Jun 29 09:33:53 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigor_int): Return -1 if y == -1.
+
+Sat Jun 29 09:07:16 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigor_int): Use RB_GC_GUARD.
+ (bigxor_int): Take xn and hibitsx arguments. Use twocomp2abs_bang.
+ (rb_big_xor): Use abs2twocomp and twocomp2abs_bang.
+
+Sat Jun 29 08:19:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigand_int): Don't apply bitwise and for BDIGIT and long.
+ (bigor_int): Take xn and hibitsx arguments. Use twocomp2abs_bang.
+ (rb_big_or): Use abs2twocomp and twocomp2abs_bang.
+
+Fri Jun 29 01:08:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * numeric.c (fix_mul): remove FIT_SQRT_LONG test as it was causing
+ fix_mul to return an incorrect result for -2147483648*-2147483648
+ on 64 bit platforms
+
+ * test/ruby/test_integer_comb.rb (class TestIntegerComb): add test case
+
+Fri Jun 28 12:26:53 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_and): Allocate new bignum with same size to shorter
+ argument if it's high bits are zero.
+
+Fri Jun 28 12:14:04 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/ipsocket.c (init_inetsock_internal): Don't use local
+ addresses which address family is different to remote address.
+
+Fri Jun 28 08:06:22 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigand_int): Add arguments, xn and hibitsx.
+ Use twocomp2abs_bang.
+
+Thu Jun 27 23:58:13 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (abs2twocomp_bang): Removed.
+ (abs2twocomp): Take n_ret argument to return actual length.
+ (rb_big_and): Follow above change.
+
+Thu Jun 27 22:52:19 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (get2comp): Use bary_2comp.
+ (abs2twocomp_bang): New function.
+ (abs2twocomp): New function.
+ (twocomp2abs_bang): New function.
+ (rb_big_and): Use abs2twocomp and twocomp2abs_bang.
+
+Thu Jun 27 20:03:13 2013 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * ext/openssl/lib/openssl/ssl.rb (verify_certificate_identity): fix
+ hostname verification. Patched by nahi.
+
+ * test/openssl/test_ssl.rb (test_verify_certificate_identity): test for
+ above.
+
+
+Thu Jun 27 00:23:57 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_pow): Retry if y is a Bignum and it is
+ representable as a Fixnum.
+ Use rb_absint_numwords.
+
+Wed Jun 26 23:53:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_save_rounding_mode): fix typo.
+ Fixes GH-343. Patch by @jgarber.
+
+Wed Jun 26 23:22:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enumerator.c (rb_enumeratorize_with_size): use strict definition
+ rb_enumerator_size_func.
+
+Wed Jun 26 23:11:14 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * gc.c (is_before_sweep): Add a missing space before a parenthesis.
+ * gc.c (rb_gc_force_recycle): Add a missing space around a parenthesis.
+
+Wed Jun 26 22:44:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/intern.h (rb_enumeratorize_with_size): cast for
+ backward compatibility.
+
+ * include/ruby/intern.h (rb_enumerator_size_func): define strict
+ function declaration for rb_enumeratorize_with_size().
+
+Wed Jun 26 21:01:22 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * test/ruby/test_io.rb (TestIO#test_write_32bit_boundary): skip if
+ writing a file is slow.
+ [ruby-core:55541] [Bug #8519]
+
+Wed Jun 26 16:42:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb: should use expanded values for header directories
+ unless extmk. patch by vo.x (Vit Ondruch) at [ruby-core:55653]
+ [Bug #8115], rhbz#921650.
+
+Wed Jun 26 12:48:22 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigxor_int): Fix a buffer over read.
+
+Wed Jun 26 12:13:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigand_int): Consider negative values.
+ (bigor_int): The allocated bignum should have enough size
+ to store long.
+ This fixes (bignum fits in a BDIGIT) | (fixnum bigger than BDIGIT)
+ on platforms which SIZEOF_BDIGITS < SIZEOF_LONG,
+ such as LP64 with 32bit BDIGIT (no int128).
+
+Wed Jun 26 12:08:51 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/socket/test_udp.rb: Close sockets explicitly.
+ Don't use fixed port number.
+
+Wed Jun 26 07:27:17 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigand_int): Fix a buffer over read.
+
+Wed Jun 26 06:48:07 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigadd_int): Fix a buffer over read.
+
+Wed Jun 26 01:18:13 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (is_before_sweep): Add new helper function that check the object
+ is before sweep?
+ * gc.c (rb_gc_force_recycle): Have to clear mark bit if object's slot
+ already ready to minor sweep.
+
+Wed Jun 26 01:17:29 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigsub_int): Fix a buffer over read.
+
+Tue Jun 25 22:45:43 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_absint_singlebit_p): Use POW2_P.
+ (bary_pack): Ditto.
+ (rb_big2str0): Ditto.
+ (POW2_P): Moved to top.
+
+Tue Jun 25 22:28:07 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/rubygems/ext/builder.rb (Gem::Ext::Builder.make): Pass
+ DESTDIR via command line to override what's in MAKEFLAGS. This
+ fixes an installation problem under a package building
+ environment where DESTDIR is specified in the (parent) command
+ line. [Fixes GH-327]
+
+Tue Jun 25 21:43:13 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2dbl): Use (BDIGIT)1 instead of 1UL.
+ (bary_mul_normal): Remove a useless cast.
+
+Tue Jun 25 21:26:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigMath_s_exp): Fix for the cases when
+ the argument x is not a BigDecimal.
+ This change is based on the patch made by Heesob Park and Garth Snyder.
+ [Bug #6862] [ruby-core:47145]
+ [Fixes GH-332] https://github.com/ruby/ruby/pull/332
+
+Tue Jun 25 20:36:31 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2ulong): "check" argument removed.
+ (rb_big2ulong): Follow above change.
+ (rb_big2long): Ditto.
+ (rb_big_rshift): Ditto.
+ (rb_big_aref): Ditto.
+
+Tue Jun 25 20:08:29 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big2ulong_pack): Use rb_integer_pack.
+ (rb_big_aref): Call big2ulong with TRUE for "check" argument.
+ It should be non-effective.
+
+Tue Jun 25 19:07:33 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (LSHIFTX): Revert r41611.
+ The redundant expression suppresses a warning, C4293, by Visual
+ Studio.
+ http://ruby-mswin.cloudapp.net/vc10-x64/ruby-trunk/log/20130625T072854Z.log.html.gz#miniruby
+
+Tue Jun 25 19:03:00 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2ulong): Add a cast.
+ (big2ull): Add a specialized code for SIZEOF_LONG_LONG <=
+ SIZEOF_BDIGITS.
+
+Tue Jun 25 12:42:57 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (integer_unpack_single_bdigit): Use "1 + ~u" instead of
+ "-u" to suppress warning (C4146) by Visual Studio.
+ Reported by ko1 via IRC.
+
+Tue Jun 25 12:28:57 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2ulong): Add code specialized for SIZEOF_LONG <=
+ SIZEOF_BDIGITS.
+ This prevents shift width warning from "num <<= BITSPERDIG".
+
+Tue Jun 25 12:23:30 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: fix oldgen/remembered_shady counting algorithm.
+
+ * gc.c (rgengc_check_shady): increment
+ `objspace->rgengc.remembered_shady_object_count' here.
+
+ * gc.c (rgengc_remember): return FALSE if obj is already remembered.
+
+ * gc.c (rgengc_rememberset_mark): make it void.
+
+ * gc.c (gc_mark_children): fix to double counting oldgen_object_count
+ at minor GC.
+
+Tue Jun 25 12:07:18 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (MSB): Removed.
+ (BDIGIT_MSB): Defined using BIGRAD_HALF.
+ (bary_2comp): Apply BIGLO after possible over flow of BDIGIT.
+ (get2comp): Ditto.
+ (bary_unpack_internal): Use BDIGIT_MSB.
+ Apply BIGLO after possible over flow of BDIGIT.
+ (rb_integer_unpack): Use BDIGIT_MSB.
+ (calc_hbase): Use BDIGMAX.
+ (big2dbl): Use BDIGMAX.
+ Apply BIGLO after possible over flow of BDIGIT.
+ (rb_big_neg): Apply BIGLO after possible over flow of BDIGIT.
+ (biglsh_bang): Ditto.
+ (bigrsh_bang): Ditto.
+ (bary_divmod): Use BDIGIT_MSB.
+ (bigdivrem): Ditto.
+ (bigxor_int): Apply BIGLO after possible over flow of BDIGIT.
+
+ * marshal.c (shortlen): Use SIZEOF_BDIGITS instead of sizeof(BDIGIT).
+
+ * ext/openssl/ossl_bn.c (ossl_bn_initialize): Use SIZEOF_BDIGITS
+ instead of sizeof(BDIGIT).
+
+Tue Jun 25 11:40:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (big2ulong): suppress shorten-64-to-32 warning. BDIGIT can
+ be bigger than long now.
+
+ * bignum.c (LSHIFTX): remove redundant never-true expression.
+
+Tue Jun 25 00:55:54 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (typedef struct rb_objspace): Change members for monitor objects.
+ * gc.c (gc_marks_test): Check all WriteBarrier Errors and track them in obj-tree.
+ * gc.c (rgengc_check_shady): Ditto.
+ * gc.c (gc_marks): Move 2 function calls to gc_marks_test for test initialize.
+
+Mon Jun 24 23:30:31 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (integer_unpack_single_bdigit): Refine code to filling
+ higher bits and use BIGLO.
+
+Mon Jun 24 22:26:31 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * test/rinda/test_rinda.rb (RingIPv6#prepare_ipv6):
+ ifindex() function may not be implemented on Windows. We use another
+ check for the case.
+
+Mon Jun 24 22:11:37 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * test/gdbm/test_gdbm.rb (TestGDBM#test_s_open_nolock):
+ skip a failing test on Windows because flock() implementation is
+ different from Unix.
+
+Mon Jun 24 22:06:14 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * test/rubygems/test_gem_installer.rb (test_install_extension_flat):
+ use ruby in build directory in case ruby is not installed.
+ [ruby-core:53265] [Bug #8058]
+
+Mon Jun 24 22:04:02 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * ext/dl/cfunc.c (rb_dlcfunc_call): fix conversion from Bignum to
+ pointer. sizeof(DLSTACK_TYPE) is larger than sizeof(long) on
+ Windows x64 and higher bits over sizeof(long) of DLSTACK_TYPE was
+ zero even if a pointer value was over 32 bits which causes SEGV on
+ DL::TestCPtr#test_to_ptr_io. Adding a cast solves the bug.
+
+Mon Jun 24 22:04:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * eval_error.c (warn_printf): use rb_vsprintf instead so ruby specific
+ extensions like PRIsVALUE can be used in format strings
+ * eval_error.c (error_print): use warn_print_str (alias for
+ rb_write_error_str) to print a string value instead of using
+ RSTRING_PTR and RSTRING_LEN manually
+ * eval.c (setup_exception): use PRIsVALUE instead of %s and RSTRING_PTR
+
+Mon Jun 24 20:31:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * compile.c (make_name_for_block): use PRIsVALUE in format string
+ instead of %s and RSTRING_PTR to protect objects from being garbage
+ collected too soon
+ * encoding.c (str_to_encindex): ditto
+ * hash.c (rb_hash_fetch_m): ditto
+ * io.c (rb_io_reopen): ditto
+ * parse.y (reg_fragment_check_gen): ditto
+ * parse.y (reg_compile_gen): ditto
+ * parse.y (ripper_assert_Qundef): ditto
+ * re.c (rb_reg_raise): ditto
+ * ruby.c (set_option_encoding_once): ditto
+ * vm_eval.c (rb_throw_obj): ditto
+
+Mon Jun 24 07:57:18 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (after_gc_sweep): Have to record malloc info before reset.
+ * gc.c (gc_prof_timer_start): Pick out part of new record creation as gc_prof_setup_new_record.
+ * gc.c (gc_prof_set_malloc_info): Move point of recording allocation size to front of mark.
+
+Mon Jun 24 02:53:09 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * array.c: Return value in Array overview example found by @PragTob
+ [Fixes GH-336] https://github.com/ruby/ruby/pull/336
+
+Mon Jun 24 02:45:51 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * array.c (rb_ary_zip): typo by @PragTob [Fixes GH-337]
+ https://github.com/ruby/ruby/pull/337
+
+Mon Jun 24 02:42:01 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * win32/README.win32: grammar typo by @blankenshipz [Fixes GH-334]
+ https://github.com/ruby/ruby/pull/334
+
+Mon Jun 24 00:59:35 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (BIGUP): Use LSHIFTX and avoid cast to consider the type
+ of x is bigger than BDIGIT_DBL.
+ (big2ulong): Use unsigned long to store the result.
+ (big2ull): Use unsigned LONG_LONG to store the result.
+ (bigand_int): Use long for num to avoid data loss.
+ (bigor_int): Ditto.
+ (bigxor_int): Ditto.
+
+Sun Jun 23 23:05:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/defines.h (BDIGIT): Define it only if it is not defined
+ yet. This eases tests and debug.
+ (SIZEOF_BDIGITS): Ditto.
+ (BDIGIT_DBL): Ditto.
+ (BDIGIT_DBL_SIGNED): Ditto.
+ (PRI_BDIGIT_PREFIX): Ditto.
+ (PRI_BDIGIT_DBL_PREFIX): Ditto.
+ (PRIdBDIGIT): Define it only if PRI_BDIGIT_PREFIX is defined.
+ (PRIiBDIGIT): Ditto.
+ (PRIoBDIGIT): Ditto.
+ (PRIuBDIGIT): Ditto.
+ (PRIxBDIGIT): Ditto.
+ (PRIXBDIGIT): Ditto.
+ (PRIdBDIGIT_DBL): Ditto.
+ (PRIiBDIGIT_DBL): Ditto.
+ (PRIoBDIGIT_DBL): Ditto.
+ (PRIuBDIGIT_DBL): Ditto.
+ (PRIxBDIGIT_DBL): Ditto.
+ (PRIXBDIGIT_DBL): Ditto.
+
+ * include/ruby/ruby.h (RBIGNUM_EMBED_LEN_MAX): Define it only if it is
+ not defined yet.
+
+Sun Jun 23 17:29:51 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (integer_unpack_single_bdigit): Use a cast.
+
+Sun Jun 23 15:38:07 2013 Koichi Sasada <ko1@atdot.net>
+
+ * bootstraptest/test_thread.rb: rescue resource limitation errors.
+
+Sun Jun 23 08:19:27 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (integer_unpack_single_bdigit): Extracted from
+ bary_unpack_internal.
+
+Sun Jun 23 07:41:52 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_unpack_internal): Suppress warnings (C4146) on Visual Studio.
+ Reported by ko1 via IRC.
+
+Sun Jun 23 06:49:28 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h, gc.c: rename macros and functions:
+ OBJ_WB_GIVEUP() -> OBJ_WB_UNPROTECT(),
+ rb_obj_wb_giveup() -> rb_obj_wb_unprotect(),
+ rb_gc_giveup_promoted_writebarrier() ->
+ rb_gc_writebarrier_unprotect_promoted(),
+
+ * class.c, eval.c, hash.c: use OBJ_WB_UNPROTECT().
+
+Sun Jun 23 05:41:32 2013 Koichi Sasada <ko1@atdot.net>
+
+ * class.c (rb_include_class_new), eval.c (rb_using_refinement):
+ make classes/modules (who share method table) shady.
+ If module `a' and `b' shares method table m_tbl and new method
+ with iseq is added, then write barrier is applied only `a' or `b'.
+ To avoid this issue, shade such classes/modules.
+
+ * vm_method.c (rb_method_entry_make): add write barriers.
+
+Sun Jun 23 01:27:54 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bytes_zero_p): Removed.
+ (bary_pack): Don't call bytes_zero_p.
+
+Sun Jun 23 00:51:29 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bytes_zero_p): Extracted from bary_pack.
+ (bary_pack): Use bytes_zero_p.
+
+Sun Jun 23 00:16:57 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (MSB): New macro.
+ (bary_unpack_internal): Use MSB.
+ (bary_divmod): Ditto.
+ (bigdivrem): Ditto.
+
+Sat Jun 22 23:45:22 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_swap): New function.
+ (bary_pack): Use bary_swap.
+ (bary_unpack_internal): Ditto.
+
+Sat Jun 22 23:18:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bytes_2comp): Renamed from quad_buf_complement.
+ (bary_pack): Use bytes_2comp.
+ (rb_quad_pack): Use rb_integer_pack.
+ (rb_quad_unpack): Use rb_integer_unpack.
+
+Sat Jun 22 21:46:18 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_integer_unpack): Don't allocate a Bignum if possible.
+
+Sat Jun 22 21:03:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * pack.c (pack_unpack): Remove specialized unpackers for integers.
+
+Sat Jun 22 20:36:50 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_unpack_internal): Specialized unpacker implemented.
+ (bary_unpack): Support INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION.
+ (rb_integer_unpack): Support INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION.
+
+Sat Jun 22 18:53:10 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_pack): Support
+ INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION flag.
+ Fix byte order and word order handling in code specialized for
+ wordsize % SIZEOF_BDIGITS == 0.
+
+ * internal.h (INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION): Defined.
+
+Sat Jun 22 15:41:25 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rgengc_check_shady): add new WB miss checking
+ on RGENGC_CHECK_MODE >= 2.
+
+ (1) Save bitmaps before marking
+ (2) Run full marking
+ (3) On each traceable object,
+ (a) object was not oldgen (== newly or shady object) &&
+ (b) parent object was oldgen &&
+ (c) parent object was not remembered &&
+ (d) object was not remembered
+ then, it should be WB miss.
+
+ This idea of this checker is by Masaya Tarui <tarui@ruby-lang.org>.
+
+Sat Jun 22 15:25:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * ext/etc/etc.c (setup_passwd): revert r41560, unnecessary
+
+Sat Jun 22 14:39:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * ext/etc/etc.c (Init_etc): omit 'passwd' from definition of Etc::Passwd
+ if HAVE_STRUCT_PASSWD_PW_PASSWD is not defined to prevent mismatch of
+ fields and values in setup_passwd
+
+Sat Jun 22 14:35:40 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/dl/cfunc.c (rb_dlcfunc_call): Use rb_big_pack instead of
+ rb_big2ulong_pack and rb_big2ull.
+
+ * include/ruby/intern.h (rb_big2ulong_pack): Deprecated.
+
+Sat Jun 22 14:31:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * ext/etc/etc.c (setup_passwd): pass 0 as VALUE to rb_struct_new to
+ prevent segfault if the compiler passes it as a 32 bit integer on
+ a 64 bit ruby
+
+Sat Jun 22 13:47:13 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_pack): MEMZERO can be used even if nails is not zero.
+
+Sat Jun 22 13:43:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * ext/etc/etc.c (etc_getpwnam): use PRIsVALUE in format string instead
+ of %s and RSTRING_PTR
+
+ * ext/etc/etc.c (etc_getgrnam): ditto
+
+Sat Jun 22 13:07:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (CLEAR_LOWBITS): Rewritten without RSHIFTX.
+ (RSHIFTX): Removed.
+
+Sat Jun 22 10:38:03 2013 Tanaka Akira <akr@fsij.org>
+
+ * pack.c (num2i32): Removed.
+ (pack_pack): Don't use num2i32.
+
+Sat Jun 22 09:55:13 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (LSHIFTX): Defined to suppress a warning.
+ (RSHIFTX): Ditto.
+ (CLEAR_LOWBITS): Use LSHIFTX and RSHIFTX.
+ (FILL_LOWBITS): Use LSHIFTX.
+ Reported by ko1 via IRC.
+
+Sat Jun 22 09:11:33 2013 Ryan Davis <ryand-ruby@zenspider.com>
+
+ * lib/minitest/*: Imported minitest 4.7.5 (r8724)
+ * test/minitest/*: ditto
+
+Sat Jun 22 07:20:30 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_prof_set_heap_info, after_gc_sweep): call
+ gc_prof_set_heap_info() just after sweeping to calculate
+ live object number correctly.
+ (live object number = total generated number (before marking) -
+ total freed number (after sweeping))
+
+ * gc.c (gc_marks): record `oldgen_object_count' into current profile`
+ record directly.
+
+ * gc.c (rgengc_rememberset_mark): same for remembered_normal_objects
+ and remembered_shady_objects.
+
+Sat Jun 22 06:46:04 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_objspace::profile): rename rb_objspace::profile::record to
+ records (because it points a set of records) and add a field
+ rb_objspace::profile::current_record to point a current profiling
+ record.
+
+ * gc.c: use above fields.
+
+Sat Jun 22 06:05:36 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_gc_giveup_promoted_writebarrier): remove `rest_sweep()'
+ because all of remembered objects are called for gc_mark_children().
+
+Sat Jun 22 05:08:03 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rgengc_rememberset_mark): call gc_mark_children() for
+ remembered objects directly instead of pushing on the mark stack.
+
+Sat Jun 22 04:48:53 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h (OBJ_WRITE): cast to (VALUE *) for second
+ parameter `slot'. You don't need to write a cast (VALUE *) any more.
+
+ * class.c, compile.c, hash.c, iseq.c, proc.c, re.c, variable.c,
+ vm.c, vm_method.c: remove cast expressions for OBJ_WRITE().
+
+Sat Jun 22 04:37:08 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (slot_sweep_body): rename to slot_sweep().
+ No need to separate major/minor GC.
+
+ * gc.c (gc_setup_mark_bits): remove gc_clear_mark_bits() and unify to
+ this function.
+
+Sat Jun 22 04:20:21 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (check_bitmap_consistency): add to check flag and bitmap consistency.
+ Use this function in several places.
+
+Sat Jun 22 02:18:07 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_pack): Specialized packers implemented.
+ (HOST_BIGENDIAN_P): New macro.
+ (ALIGNOF): New macro.
+ (CLEAR_LOWBITS): New macro.
+ (FILL_LOWBITS): New macro.
+ (swap_bdigit): New macro.
+ (bary_2comp): Returns an int.
+
+ * internal.h (swap16): Moved from pack.c
+ (swap32): Ditto.
+ (swap64): Ditto.
+
+Fri Jun 21 21:29:49 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (typedef enum): Introduce flags of major gc reason.
+ * gc.c (garbage_collect_body): Ditto.
+ * gc.c (gc_profile_flags): Ditto.
+ * gc.c (gc_profile_dump_on): Ditto.
+
+Fri Jun 21 21:11:53 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (allocate_sorted_heaps): remove unused variable `add'.
+
+Fri Jun 21 20:50:32 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: constify RArray::as::ary and RArray::heap::ptr.
+ Use RARRAY_ASET() or RARRAY_PTR_USE() to modify Array objects.
+
+ * array.c, gc.c: catch up above changes.
+
+Fri Jun 21 20:32:13 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_eval.c (eval_string_with_cref): fix WB miss.
+
+Fri Jun 21 20:15:49 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: support write barrier protection for T_STRUCT.
+ Introduce the following C APIs:
+ * RSTRUCT_RAWPTR(st) returns pointer (do WB on your risk).
+ The type of returned pointer is (const VALUE *).
+ * RSTRUCT_GET(st, idx) returns idx-th value of struct.
+ * RSTRUCT_SET(st, idx, v) set idx-th value by v with WB.
+ And
+ * RSTRUCT_PTR(st) returns pointer with shady operation.
+ The type of returned pointer is (VALUE *).
+
+ * struct.c, re.c, gc.c, marshal.c: rewrite with above APIs.
+
+Fri Jun 21 19:38:37 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (BDIGMAX): Use BIGRAD.
+ (BIGLO): Use BDIGMAX.
+ (bigdivrem1): Ditto.
+ (bigor_int): Ditto.
+ (rb_big_or): Ditto.
+
+Fri Jun 21 19:18:48 2013 Tanaka Akira <akr@fsij.org>
+
+ * pack.c (pack_pack): Move the implementation for 'c' directive after
+ pack_integer label.
+
+Fri Jun 21 19:11:56 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h, re.c: support write barrier for T_REGEXP.
+
+ Note: T_MATCH object is also easy to support write barriers.
+ However, most of T_MATCH objects are short-lived objects.
+ So I skipped to support non-shady T_MATCH.
+
+Fri Jun 21 18:56:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigsub_int): Use bdigit_roomof.
+ (bigadd_int): Ditto.
+ (bigand_int): Ditto.
+ (bigor_int): Ditto.
+ (bigxor_int): Ditto.
+
+Fri Jun 21 17:56:25 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/gc/gcbench.rb: fix summary of benchmark result notation.
+
+Fri Jun 21 16:38:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * ext/openssl/ossl_x509attr.c: change OSSL_X509ATTR_IS_SINGLE and
+ OSSL_X509ATTR_SET_SINGLE macros to use ->value.set rather than
+ ->set to fix compile failure
+
+Fri Jun 21 15:26:45 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_sweep): profile sweep time correctly when LAZY_SWEEP is
+ disabled.
+
+ * gc.c (gc_marks_test): store oldgen count and shady count
+ before test marking and restore them after marking.
+
+Fri Jun 21 15:07:42 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: enable lazy sweep (commit miss).
+
+Fri Jun 21 14:31:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (ruby_setenv): refine error message so include the variable
+ name.
+
+Fri Jun 21 14:15:08 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: fix to use total_allocated_object_num and heaps_used
+ at the GC time for profiler.
+
+Fri Jun 21 12:35:35 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: RGENGC_CHECK_MODE should be 0.
+
+Fri Jun 21 11:18:25 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_marks_body): fix to get `th' in this function.
+
+Fri Jun 21 10:21:44 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (heaps_header/heaps_slot): embed bitmaps into heaps_slot.
+ no need to maintain allocation/free bitmaps.
+
+Fri Jun 21 09:22:16 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (slot_sweep_body): add counters at a time.
+
+ * gc.c (gc_profile_dump_on): fix line break position.
+
+Fri Jun 21 08:14:00 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c: refactoring bitmaps. introduce bits_t type and some Consts.
+
+Fri Jun 21 08:04:32 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: fix to support USE_RGENGC == 0 (disable RGenGC).
+ If USE_RGENGC==0, it caused compilation error.
+
+Fri Jun 21 08:08:11 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (lazy_sweep): Use is_lazy_sweeping()
+ * gc.c (rest_sweep): Ditto.
+ * gc.c (gc_prepare_free_objects): Ditto.
+
+Fri Jun 21 07:34:47 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_profile_record::oldgen_objects): added.
+
+ * gc.c (gc_profile_dump_on): print the following information:
+ * Living object counts
+ * Free object counts
+ If RGENGC_PROFILE > 0 then
+ * Oldgen object counts
+ * Remembered normal object counts
+ * Remembered shady object counts
+
+Fri Jun 21 06:43:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_ull2big): Refactored.
+ (rb_uint2big): Useless code removed.
+
+Fri Jun 21 05:37:39 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_prof_sweep_timer_stop): accumulate sweep time only when
+ record->gc_time > 0.
+
+Fri Jun 21 00:37:31 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/bigdecimal: Workaround fix for bigdecimal test failures caused
+ by [ruby-dev:47413] [Feature #8509]
+
+ * ext/bigdecimal/bigdecimal.h (BDIGIT): Make it independent from the
+ definition for bignum.c.
+ (SIZEOF_BDIGITS): Ditto.
+ (BDIGIT_DBL): Ditto.
+ (BDIGIT_DBL_SIGNED): Ditto.
+ (PRI_BDIGIT_PREFIX): Undefine the definition.
+ (PRI_BDIGIT_DBL_PREFIX): Ditto.
+
+ * ext/bigdecimal/bigdecimal.c (RBIGNUM_ZERO_P): Use rb_bigzero_p.
+ (bigzero_p): Removed.
+ (is_even): Use rb_big_pack.
+
+Thu Jun 20 22:52:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigmul1_toom3): Don't call bignorm twice.
+
+Thu Jun 20 22:49:27 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bignorm): Don't call bigtrunc if the result is a fixnum.
+
+Thu Jun 20 22:29:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_uint2big): Refactored.
+
+Thu Jun 20 22:24:41 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (dump_bignum): Use SIZEOF_BDIGITS.
+
+Thu Jun 20 22:22:46 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2ulong): Change the return type to unsigned long.
+ (rb_big2ulong_pack): Follow the above change.
+ (rb_big2long): Ditto.
+ (rb_big_lshift): Ditto.
+ (rb_big_rshift): Ditto.
+ (rb_big_aref): Ditto.
+
+Thu Jun 20 22:02:46 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_unpack_internal): Return -2 when negative overflow.
+ (bary_unpack): Set the overflowed bit if an extra BDIGIT exists.
+ (rb_integer_unpack): Set the overflowed bit.
+
+Thu Jun 20 21:17:19 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rgengc_rememberset_mark): record
+ (1) normal objects count in remember set
+ (2) shady objects count in remember set
+ each GC timing.
+
+ * gc.c (gc_profile_record_get): enable to access above information
+ and REMOVING_OBJECTS, EMPTY_OBJECTS.
+
+Thu Jun 20 18:29:26 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/gc/gcbench.rb: Do not use GC::Profiler::disable because
+ GC::Profiler::disable prohibit to access profiling data. It should
+ be spec bug.
+
+ Skip GC::Profiler::report if RUBY_VERSION < '2.0.0'
+
+Thu Jun 20 17:59:08 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/gc/gcbench.rb: stop GC::Profiler before output results.
+ Generating GC::Profiler result under profiling causes infinite loop.
+
+Thu Jun 20 17:24:24 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/gc/gcbench.rb: don't use __dir__ to make compatible
+ with ruby 1.9.3.
+
+Thu Jun 20 16:57:19 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/bm_app_aobench.rb: use attr_accessor/reader instead of
+ defining methods.
+
+Thu Jun 20 16:46:46 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/bm_app_aobench.rb: added.
+
+ * benchmark/gc/aobench.rb: added.
+
+Thu Jun 20 16:28:33 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/bm_so_binary_trees.rb: disable `puts' method
+ and change iteration parameter to increase execution time.
+
+ * benchmark/gc/binarytree.rb: added.
+
+Thu Jun 20 16:06:37 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/gc/pentomino.rb: added.
+ Simply load pentomino puzzle in the benchmark/ directory.
+
+Thu Jun 20 15:32:56 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/gc/redblack.rb: import red black tree benchmark from
+ https://github.com/jruby/rubybench/blob/master/time/bench_red_black.rb
+
+ * benchmark/gc/ring.rb: add a benchmark. This benchmark create many
+ old objects.
+
+Thu Jun 20 15:14:00 2013 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/gc: create a directory to store GC related benchmark.
+
+ * benchmark/gc/gcbench.rb: moved from tool/gcbench.rb.
+
+ * benchmark/gc/hash(1|2).rb: ditto.
+
+ * benchmark/gc/rdoc.rb: ditto.
+
+ * benchmark/gc/null.rb: added.
+
+ * common.mk: fix rule.
+
+Thu Jun 20 14:09:54 2013 Koichi Sasada <ko1@atdot.net>
+
+ * tool/hashbench1.rb: fix parameter too. Increase temporary objects.
+
+Thu Jun 20 14:01:35 2013 Koichi Sasada <ko1@atdot.net>
+
+ * tool/hashbench1.rb: fix parameters.
+
+Thu Jun 20 14:00:34 2013 Koichi Sasada <ko1@atdot.net>
+
+ * common.mk: remove dependency from ruby.
+
+Thu Jun 20 13:14:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (rb_check_backtrace): evaluate RARRAY_AREF only once.
+ the first argument of RB_TYPE_P is expanded twice for non-immediate
+ types.
+
+Thu Jun 20 08:09:29 2013 Koichi Sasada <ko1@atdot.net>
+
+ * tool/gcbench.rb: Summary in one line.
+
+ * common.mk: separate gcbench-hash to gcbench-hash1 and gcbench-hash2.
+
+Thu Jun 20 08:07:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (BIGSIZE): New macro.
+ (bigfixize): Use BIGSIZE.
+ (big2ulong): Ditto.
+ (check_shiftdown): Ditto.
+ (rb_big_aref): Ditto.
+
+Thu Jun 20 07:46:48 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (rb_gc_writebarrier): give up rescan A and register B directly
+ if A has huge number of children.
+
+Thu Jun 20 07:30:35 2013 Koichi Sasada <ko1@atdot.net>
+
+ * common.mk: add new rules `gcbench-rdoc', `gcbench-hash'.
+
+ * tool/gcbench.rb: separate GC bench framework and process.
+
+ * tool/hashbench1.rb, tool/hashbench2.rb: add two types GC bench.
+ hashbench1: many temporal objects (GC by newobj)
+ hashbench2: hash size becomes bigger and bigger (GC by malloc)
+ Two benches are executed by `gcbench-hash' rule.
+
+ * tool/rdocbench.rb: separated.
+
+Thu Jun 20 06:25:39 2013 Koichi Sasada <ko1@atdot.net>
+
+ * tool/rdocbench.rb: add summary.
+
+Thu Jun 20 06:18:01 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_profile_total_time): check objspace->profile.next_index > 0.
+
+Thu Jun 20 05:47:41 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_prof_sweep_timer_start): fix merge miss.
+
+ * gc.c (GC_PROFILE_MORE_DETAIL): set it 0.
+
+Thu Jun 20 05:38:56 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: Accumulate sweep time to GC time.
+ Now [GC time] is [mark time] + [sweep time] + [misc].
+ ([GC time] >= [mark time] + [sweep time])
+
+ * gc.c (gc_prof_sweep_slot_timer_start/stop): rename to
+ gc_prof_sweep_timer_start/stop and locate at lazy_sweep().
+
+ * gc.c (elapsed_time_from): add a utility function.
+
+Thu Jun 20 05:08:53 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_marks): fix wrong option. FALSE means major/full GC.
+ It should be TRUE (minor marking).
+
+Thu Jun 20 02:44:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (waitpid): should not return 0 but wait until exit
+ unless WNOHANG is given. waiting huge process may return while
+ active, for some reason.
+
+Thu Jun 20 01:34:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bdigit_roomof): Use SIZEOF_BDIGITS.
+ (bigfixize): Refine an ifdef condition.
+ (rb_absint_size): Use bdigit_roomof.
+ (rb_absint_singlebit_p): Ditto.
+ (rb_integer_pack): Ditto.
+ (integer_pack_fill_dd): Use BITSPERDIG.
+ (integer_unpack_push_bits): Use BITSPERDIG, BIGLO and BIGDN.
+
+Thu Jun 20 01:07:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (MARKED_IN_BITMAP, FL_TEST2): return boolean value since always
+ used as boolean value.
+
+ * gc.c (MARK_IN_BITMAP, CLEAR_IN_BITMAP): evaluate bits once.
+
+Thu Jun 20 00:05:07 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (RVALUE_PROMOTED): fix type.
+
+Wed Jun 19 23:39:01 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_marks_test): rewrite checking code.
+ When RGENGC_CHECK_MODE >= 2, all minor marking, run normal minor
+ marking *and* major/full marking. After that, compare the results
+ and shows BUG if a object living with major/full marking but dead
+ with minor marking.
+ After detecting bugs, print references information.
+ (RGENGC_CHECK_MODE == 2, show references to dead object)
+ (RGENGC_CHECK_MODE == 3, show all references)
+
+Wed Jun 19 23:51:48 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigfixize): Use rb_absint_size.
+ (check_shiftdown): Ditto.
+ (big2ulong): Use bdigit_roomof.
+
+Wed Jun 19 23:32:23 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (RVALUE_PROMOTED): check consistency between oldgen flag and
+ oldgen bitmap if RGENGC_CHECK_MODE > 0.
+
+Wed Jun 19 23:29:29 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_gc_force_recycle): clear oldgen bitmap, too.
+
+Wed Jun 19 21:02:13 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_uint2big): Consider environments BDIGIT is bigger than
+ long.
+ (big2ulong): Ditto.
+ (rb_big_aref): Ditto.
+ (rb_big_pack): Just call rb_integer_pack.
+ (rb_big_unpack): Just call rb_integer_unpack.
+
+Wed Jun 19 20:51:21 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * gc.c (gc_stress_get): GC.stress can be Fixnum.
+
+Wed Jun 19 19:31:30 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (DIGSPERLONG): Don't define if BDIGIT is bigger than long.
+ (DIGSPERLL): Don't define if BDIGIT is bigger than LONG_LONG
+ (rb_absint_size): Consider environments BDIGIT is bigger than long.
+ Use BIGLO and BIGDN.
+ (rb_absint_singlebit_p): Ditto.
+ (rb_integer_pack): Ditto.
+ (bigsub_int): Consider environments BDIGIT is bigger than long.
+ Use SIZEOF_BDIGITS instead of sizeof(BDIGIT).
+ (bigadd_int): Ditto.
+ (bigand_int): Ditto.
+ (bigor_int): Ditto.
+ (bigxor_int): Ditto.
+
+Wed Jun 19 15:14:30 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h (struct rb_data_type_struct), gc.c: add
+ rb_data_type_struct::flags. Now, this flags is passed
+ at T_DATA object creation. You can specify FL_WB_PROTECTED
+ on this flag.
+
+ * iseq.c: making non-shady iseq objects.
+
+ * class.c, compile.c, proc.c, vm.c: add WB for iseq objects.
+
+ * vm_core.h, iseq.h: constify fields to detect WB insertion.
+
+Wed Jun 19 15:11:13 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (gc_mark_children): show more info for broken object.
+
+Wed Jun 19 14:04:41 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * test/ruby/envutil.rb (EnvUtil#rubybin): remove unnecessary
+ unless expression.
+
+Wed Jun 19 07:47:48 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (garbage_collect_body): use FIX2INT for ruby_gc_stress.
+
+Wed Jun 19 07:44:31 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_objspace::gc_stress): int -> VALUE to store Fixnum object.
+
+Wed Jun 19 07:25:35 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (make_deferred): clear flags to T_ZOMBIE.
+
+ * gc.c (slot_sweep_body): fix indent.
+
+Wed Jun 19 07:18:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_aref): Apply BIGLO to ~xds[i] for environment which
+ BDIGIT is 16bit.
+
+Wed Jun 19 07:09:26 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rgengc_remember): fix output level.
+
+ * gc.c (rgengc_rememberset_mark): fix to output clear count.
+ (shady_object_count + clear_count = count of remembered objects)
+
+Wed Jun 19 07:06:21 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rgengc_remember): check T_NONE and T_ZOMBIE
+ if RGENGC_CHECK_MODE > 0.
+
+Wed Jun 19 07:02:19 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (RGENGC_CHECK_MODE): add new check mode `3'.
+ In this mode, show all references if there is
+ a miss-corrected object.
+
+Wed Jun 19 06:31:08 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stress_set): add special option of GC.stress.
+ `GC.stress=(flag)' accepts integer to control behavior of GC.
+ See code for details. Of course, this feature is only for MRI.
+
+ You can debug RGenGC (WB) using `GC.stress = 1'.
+ Using this option, do minor marking at all possible places.
+
+ GC::STRESS_MINOR_MARK = 1 and GC::STRESS_LAZY_SWEEP = 2
+ seem good to add.
+
+Wed Jun 19 06:29:31 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (kwmerge_i): add WB.
+
+Wed Jun 19 06:26:49 2013 Koichi Sasada <ko1@atdot.net>
+
+ * hash.c: `st_update()' also has same issue of last fix.
+ write barriers at callback function are too early.
+ All write barriers are executed after `st_update()'
+
+Wed Jun 19 04:33:22 2013 Koichi Sasada <ko1@atdot.net>
+
+ * variable.c (rb_const_set): fix WB miss.
+
+ WBs had located before creating reference between a klass
+ and constant value. It causes GC bug.
+
+ # pseudo code:
+ WB(klass, value); # WB and remember klass
+ st_insert(klass->const_table, const_id, value);
+
+ `st_insert()' can cause GC before inserting `value' and
+ forget `klass' from the remember set. After that, relationship
+ between `klass' and `value' are created with constant table.
+ Now, `value' can be young (shady) object and `klass' can be old
+ object, without remembering `klass' object.
+ At the next GC, old `klass' object will be skipped and
+ young (shady) `value' will be miss-collected. -> GC bug
+
+ Lesson: The place of a WB is important.
+
+Tue Jun 18 22:01:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_call_method): ensure methods of type
+ VM_METHOD_TYPE_ATTR_SET are called with 1 argument
+
+ * test/ruby/test_module.rb
+ (TestModule#test_attr_writer_with_no_arguments): add test
+ [ruby-core:55543] [Bug #8540]
+
+Tue Jun 18 22:36:23 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (gc_profile_record_flag): fix typo.
+
+Tue Jun 18 22:08:53 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/objspace/object_tracing.c: Return for ::allocation_generation
+
+Tue Jun 18 22:04:35 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/objspace/object_tracing.c: Document object_tracing methods.
+
+Tue Jun 18 21:58:17 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * gc.c: Rename rb_mObSpace -> rb_mObjSpace
+
+Tue Jun 18 20:55:05 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/objspace/objspace.c: Document ObjectSpace::InternalObjectWrapper.
+
+Tue Jun 18 20:39:04 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/objspace/object_tracing.c: Teach rdoc object_tracing.c [Bug #8537]
+
+Tue Jun 18 20:29:47 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/.document: add object_tracing.c to document file
+
+Tue Jun 18 20:20:27 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/objspace/objspace.c: rdoc on require to overview from r41355
+
+Tue Jun 18 18:39:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Check __int128.
+
+ * include/ruby/defines.h (BDIGIT_DBL): Use uint128_t if it is available.
+ (BDIGIT): Use uint64_t if uint128_t is available.
+ (SIZEOF_BDIGITS): Defined for above case.
+ (BDIGIT_DBL_SIGNED): Ditto.
+ (PRI_BDIGIT_PREFIX): Ditto.
+
+ * include/ruby/ruby.h (PRI_64_PREFIX): Defined.
+
+ * bignum.c (rb_big_pow): Don't use BITSPERDIG for the condition which
+ rb_big_pow returns Float or Bignum.
+
+ [ruby-dev:47413] [Feature #8509]
+
+Tue Jun 18 16:43:44 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_heredoc_restore): clear lex_strterm always to get
+ rid of marking recycled node. this bug is revealed by r41372 with
+ GC.stress=true.
+
+Tue Jun 18 12:53:25 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (nlz): Cast the result explicitly.
+ (big2dbl): Don't assign BDIGIT values to int variable.
+
+Tue Jun 18 12:25:16 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_xor): Non-effective code removed.
+
+Tue Jun 18 11:26:05 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat): add `generated_normal_object_count_types' for
+ RGENGC_PROFILE >= 2.
+
+Tue Jun 18 11:02:18 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_mark_maybe): check to skip T_NONE.
+
+ * gc.c (markable_object_p): do not need to check (flags == 0) here.
+
+Tue Jun 18 10:17:37 2013 Koichi Sasada <ko1@atdot.net>
+
+ * variable.c (rb_autoload): fix WB miss.
+
+Tue Jun 18 04:20:18 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_mark_children): don't need to care about T_ZOMBIE here.
+
+Mon Jun 17 22:16:02 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * test/ruby/test_proc.rb (TestProc#test_block_given_method_to_proc):
+ run test for r41359.
+
+Mon Jun 17 21:42:18 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * include/ruby/ruby.h, vm_eval.c (rb_funcall_with_block):
+ new function to invoke a method with a block passed
+ as an argument.
+
+ * string.c (sym_call): use the above function to avoid
+ a block sharing. [ruby-dev:47438] [Bug #8531]
+
+ * vm_insnhelper.c (vm_yield_with_cfunc): don't set block
+ in the frame.
+
+ * test/ruby/test_symbol.rb (TestSymbol#test_block_given_to_proc):
+ run related tests.
+
+Mon Jun 17 21:33:27 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * include/ruby/intern.h, proc.c (rb_method_call_with_block):
+ new function to invoke a Method object with a block passed
+ as an argument.
+
+ * proc.c (bmcall): use the above function to avoid a block sharing.
+ [ruby-core:54626] [Bug #8341]
+
+ * test/ruby/test_proc.rb (TestProc#test_block_persist_between_calls):
+ run related tests.
+
+Mon Jun 17 20:53:21 2013 Tanaka Akira <akr@fsij.org>
+
+ * loadpath.c (RUBY_REVISION): Defined to suppress revision.h
+ inclusion actually. r41352 removes the dependency.
+
+Mon Jun 17 18:15:57 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * ext/objspace/objspace.c: let rdoc know about objspace methods.
+ Specify 'objspace' should be required. See #8537.
+
+Mon Jun 17 17:44:31 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * gc.c (ObjectSpace): is a module not a class.
+
+ * ext/objspace/objspace.c: try to include overview in rdoc,
+ see #8537.
+
+Mon Jun 17 17:38:24 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * gc.c: fix example of ObjectSpace.define_finalizer in overview
+
+Mon Jun 17 16:59:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/tk/tkutil/tkutil.c: use rb_sprintf(), rb_id2str(), and
+ rb_intern_str() instead of rb_intern() and RSTRING_PTR() with
+ RB_GC_GUARD(), to prevent temporary objects from GC.
+ [ruby-core:39000] [Bug #5199]
+
+Mon Jun 17 14:27:54 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * vm_backtrace.c: Update rdoc for Backtrace#label with @_ko1
+
+Mon Jun 17 13:04:01 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * tool/ifchange (until): Fix the condition, although harmless in
+ this case.
+
+Mon Jun 17 11:50:29 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_mark_maybe): added. check `is_pointer_to_heap()' and
+ type is not T_ZOMBIE.
+
+ * gc.c: use `gc_mark_maybe()'. T_ZOMBIE objects should not be pushed
+ to the mark stack.
+
+Mon Jun 17 07:56:24 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_small_lshift): Renamed from bdigs_small_lshift.
+ (bary_small_rshift): Renamed from bdigs_small_rshift.
+
+Mon Jun 17 07:38:48 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (absint_numwords_bytes): Removed.
+ (rb_absint_numwords): Don't call absint_numwords_bytes.
+
+Sun Jun 16 23:14:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (BARY_ADD): New macro.
+ (BARY_SUB): Ditto.
+ (BARY_MUL): Ditto.
+ (BARY_DIVMOD): Ditto.
+ (BARY_ZERO_P): Ditto.
+ (absint_numwords_generic): Use these macros.
+
+Sun Jun 16 21:41:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_2comp): Extracted from get2comp.
+ (integer_unpack_num_bdigits): Extracted from
+ rb_integer_unpack_internal.
+ (bary_unpack_internal): Renamed from bary_unpack and support
+ INTEGER_PACK_2COMP.
+ (bary_unpack): New function to validate arguments and invoke
+ bary_unpack_internal.
+ (rb_integer_unpack_internal): Removed.
+ (rb_integer_unpack): Invoke bary_unpack_internal.
+ (rb_integer_unpack_2comp): Removed.
+
+ * internal.h (rb_integer_unpack_2comp): Removed.
+
+ * pack.c: Follow the above change.
+
+Sun Jun 16 18:41:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (INTEGER_PACK_2COMP): Defined.
+ (rb_integer_pack_2comp): Removed.
+
+ * bignum.c (bary_pack): Support INTEGER_PACK_2COMP.
+ (rb_integer_pack): Invoke bary_pack directly.
+ (rb_integer_pack_2comp): Removed.
+ (rb_integer_pack_internal): Ditto.
+ (absint_numwords_generic): Follow the above change.
+
+ * pack.c (pack_pack): Ditto.
+
+ * sprintf.c (rb_str_format): Ditto.
+
+Sun Jun 16 17:48:14 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (absint_numwords_generic): rb_funcall invocations removed.
+
+Sun Jun 16 16:04:38 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/config_files.rb: use URI.read to allow it runs with Ruby 1.8.5.
+
+Sun Jun 16 14:32:25 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_pack) Extracted from rb_integer_pack_internal.
+ (absint_numwords_generic): Use bary_pack.
+
+Sun Jun 16 11:01:57 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * NEWS (XMLRPC::Client#http): Add.
+ [ruby-core:55197] [Feature #8461]
+
+Sun Jun 16 10:38:45 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_add): New function.
+ (bary_zero_p): Extracted from bigzero_p.
+ (absint_numwords_generic): Use bary_zero_p and bary_add.
+ (bary_mul): Fix an argument for bary_mul_single.
+ (bary_divmod): Use size_t for arguments.
+
+Sun Jun 16 08:55:22 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem): Use a BDIGIT variable to store the return
+ value of bigdivrem_single.
+
+Sun Jun 16 08:43:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_divmod): New function.
+ (absint_numwords_generic): Use bary_divmod.
+ (bigdivrem_num_extra_words): Extracted from bigdivrem.
+ (bigdivrem_single): Ditto.
+ (bigdivrem_normal): Ditto.
+ (BIGDIVREM_EXTRA_WORDS): Defined.
+
+Sun Jun 16 05:51:51 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c: Fixup around GC by MALLOC.
+ Add allocate size to malloc_increase before GC
+ for updating limit in after_gc_sweep.
+ Reset malloc_increase into garbage_collect()
+ for preventing GC again soon.
+
+Sun Jun 16 05:15:36 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c: Add some columns to more detail profile.
+ new columns: Allocated size, Prepare Time, Removing Objects, Empty Objects
+
+Sun Jun 16 02:04:40 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (gc_prof_timer_stop): Merge function codes of GC_PROFILE_MORE_DETAIL and !GC_PROFILE_MORE_DETAIL.
+ * gc.c (gc_prof_mark_timer_start): Ditto.
+ * gc.c (gc_prof_mark_timer_stop): Ditto.
+ * gc.c (gc_prof_sweep_slot_timer_start): Ditto.
+ * gc.c (gc_prof_sweep_slot_timer_stop): Ditto.
+ * gc.c (gc_prof_set_malloc_info): Ditto.
+ * gc.c (gc_prof_set_heap_info): Ditto.
+
+Sat Jun 15 23:50:24 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_sub): New function.
+ (absint_numwords_generic): Use bary_sub.
+ (bigsub_core): Skip unnecessary copy.
+
+Sat Jun 15 22:05:30 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul): New function.
+ (absint_numwords_generic): Use bary_mul.
+ (bary_mul_single): Extracted from bigmul1_single.
+ (bary_mul_normal): Extracted from bigmul1_normal.
+
+Sat Jun 15 20:13:46 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_unpack): Extracted from rb_integer_unpack_internal.
+ (absint_numwords_generic): Use bary_unpack.
+ (roomof): Defined.
+ (bdigit_roomof): Defined.
+ (BARY_ARGS): Defined.
+ (bary_unpack): Declared.
+
+Sat Jun 15 19:35:04 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (absint_numwords_bytes): Make it static.
+ (absint_numwords_small): Ditto.
+ (absint_numwords_generic): Ditto.
+
+Sat Jun 15 17:14:32 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigmul1_normal): Shrink the result Bignum length.
+
+Sat Jun 15 10:19:42 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/bigdecimal/bigdecimal.c: Update overview formatting of headers
+
+Sat Jun 15 10:19:06 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/bigdecimal/bigdecimal.gemspec: Update authors
+
+Sat Jun 15 10:02:26 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bdigs_small_rshift): Extracted from big_rshift.
+ (bigdivrem): Use bdigs_small_rshift.
+
+Sat Jun 15 08:37:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (eval_string_with_cref): propagate absolute path from the
+ binding if it is given explicitly. patch by Gat (Dawid Janczak) at
+ [ruby-core:55123]. [Bug #8436]
+
+Sat Jun 15 02:40:18 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bdigs_small_lshift): Extracted from big_lshift.
+ (bigdivrem): Use bdigs_small_lshift.
+
+Fri Jun 14 20:47:41 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem): Reduce number of digits before bignew() for div.
+
+Fri Jun 14 20:12:37 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem): Use bignew when ny == 1.
+
+Fri Jun 14 18:52:51 2013 Koichi Sasada <ko1@atdot.net>
+
+ * compile.c (rb_iseq_compile_node): fix location of a `trace'
+ instruction (b_return event).
+ [ruby-core:55305] [ruby-trunk - Bug #8489]
+ (need a backport to 2.0.0?)
+
+ * test/ruby/test_settracefunc.rb: add a test.
+
+Fri Jun 14 18:18:07 2013 Koichi Sasada <ko1@atdot.net>
+
+ * class.c, include/ruby/ruby.h: add write barriers for T_CLASS,
+ T_MODULE, T_ICLASS.
+
+ * constant.h: constify rb_const_entry_t::value and file to detect
+ assignment.
+
+ * variable.c, internal.h (rb_st_insert_id_and_value, rb_st_copy):
+ added. update table with write barrier.
+
+ * method.h: constify some variables to detect assignment.
+
+ * object.c (init_copy): add WBs.
+
+ * variable.c: ditto.
+
+ * vm_method.c (rb_add_method): ditto.
+
+Fri Jun 14 14:33:47 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * NEWS: add a note for Module#using.
+
+Fri Jun 14 13:40:27 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * .travis.yml (before_script): update config files.
+
+ * common.mk ($(srcdir)/tool/config.{guess,sub}): use get-config_files.
+
+ * tool/config_files.rb: split get-config_files.
+
+ * common.mk (update-config_files): rule to download config files.
+
+ * tool/config.guess, tool/config.sub: remove and download from the
+ upstream.
+
+ * tool/config_files.rb: download config files from GNU.
+
+Fri Jun 14 12:21:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (RUBY_SAFE_LEVEL_CHECK): suppress warnings
+ "left-hand operand of comma expression has no effect", on gcc 4.4.
+
+Fri Jun 14 09:48:48 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * NEWS: add notes for $SAFE.
+
+ * doc/security.rdoc: remove the description of $SAFE=4.
+
+Fri Jun 14 00:14:29 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem): Zero test condition simplified.
+
+Thu Jun 13 23:43:11 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/bigdecimal/*: improve documentation, nodoc samples with @mrkn
+
+Thu Jun 13 23:02:14 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/xmlrpc/client.rb (XMLRPC::Client#http): Add reader for raw
+ Net::HTTP. [ruby-core:55197] [Feature #8461]
+ Reported by Herwin Weststrate. Thanks!!!
+
+Thu Jun 13 22:44:52 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/xmlrpc/client.rb (XMLRPC::Client#parse_set_cookies): Support
+ multiple names in a response. [ruby-core:41711] [Bug #5774]
+ Reported by Roman Riha. Thanks!!!
+ * test/xmlrpc/test_client.rb (XMLRPC::ClientTest#test_cookie_override):
+ Add a test of the above case.
+
+Thu Jun 13 22:35:50 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/xmlrpc/client.rb (XMLRPC::Client#parse_set_cookies): Use
+ guard style.
+
+Thu Jun 13 22:12:32 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/fileutils.rb (FileUtils#rmdir): fix traversal loop, not trying
+ remove same directory only.
+
+Thu Jun 13 21:30:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (opt-dir), tool/ifchange: get rid of "alternate value"
+ expansion for legacy sh. [ruby-dev:47420] [Bug #8524]
+
+Thu Jun 13 21:24:09 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem): Refactored to use ALLOCV_N for temporary
+ buffers.
+
+Thu Jun 13 18:54:11 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * bignum.c (integer_unpack_num_bdigits_generic): reorder terms (but not
+ changed the intention of the expression) because VC++ reports a
+ warning for it. reported by ko1 via IRC.
+
+Thu Jun 13 18:53:14 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_thread.rb (test_thread_local_security): Don't create
+ an unused thread.
+
+Thu Jun 13 18:34:20 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bigdivrem): Use nlz.
+
+Thu Jun 13 14:51:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (RUBY_SAFE_LEVEL_CHECK): check constant safe
+ level at compile time.
+
+Thu Jun 13 14:39:08 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * test/-ext-/test_printf.rb, test/rss/test_parser.rb,
+ test/ruby/test_array.rb, test/ruby/test_hash.rb,
+ test/ruby/test_m17n.rb, test/ruby/test_marshal.rb,
+ test/ruby/test_object.rb, test/ruby/test_string.rb: don't use
+ untrusted?, untrust, and trust to avoid warnings in case $VERBOSE is
+ true.
+
+Thu Jun 13 10:47:16 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * bootstraptest/test_autoload.rb, bootstraptest/test_method.rb:
+ remove tests for $SAFE=4.
+
+ * lib/pp.rb: use taint instead of untrust to avoid warnings when
+ $VERBOSE is set to true.
+
+Thu Jun 13 06:12:18 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (integer_unpack_num_bdigits_small): Fix a compile error on
+ clang -Werror,-Wshorten-64-to-32
+ Reported by Eric Hodel. [ruby-core:55467] [Bug #8522]
+
+Thu Jun 13 05:32:13 2013 Eric Hodel <drbrain@segment7.net>
+
+ * ext/socket/extconf.rb: Enable RFC 3542 IPV6 socket options for OS X
+ 10.7+. [ruby-trunk - Bug #8517]
+
+Thu Jun 13 00:17:18 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_integer_unpack_2comp): New function.
+ (rb_integer_unpack_internal): Extracted from rb_integer_unpack and
+ nlp_bits_ret argument added.
+ (integer_unpack_num_bdigits_small): nlp_bits_ret argument added to
+ return number of leading padding bits.
+ (integer_unpack_num_bdigits_generic): Ditto.
+
+ * internal.h (rb_integer_unpack_2comp): Declared.
+
+ * pack.c (pack_unpack): Use rb_integer_unpack_2comp and
+ rb_integer_unpack.
+
+Wed Jun 12 23:27:03 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * eval.c (mod_using): new method Module#using, which activates
+ refinements of the specified module only in the current class or
+ module definition. [ruby-core:55273] [Feature #8481]
+
+ * test/ruby/test_refinement.rb: related test.
+
+Wed Jun 12 22:58:48 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * safe.c (rb_set_safe_level, safe_setter): raise an ArgumentError
+ when $SAFE is set to 4. $SAFE=4 is now obsolete.
+ [ruby-core:55222] [Feature #8468]
+
+ * object.c (rb_obj_untrusted, rb_obj_untrust, rb_obj_trust):
+ Kernel#untrusted?, untrust, and trust are now deprecated.
+ Their behavior is same as tainted?, taint, and untaint,
+ respectively.
+
+ * include/ruby/ruby.h (OBJ_UNTRUSTED, OBJ_UNTRUST): OBJ_UNTRUSTED()
+ and OBJ_UNTRUST() are aliases of OBJ_TAINTED() and OBJ_TAINT(),
+ respectively.
+
+ * array.c, class.c, debug.c, dir.c, encoding.c, error.c, eval.c,
+ ext/curses/curses.c, ext/dbm/dbm.c, ext/dl/cfunc.c,
+ ext/dl/cptr.c, ext/dl/dl.c, ext/etc/etc.c, ext/fiddle/fiddle.c,
+ ext/fiddle/pointer.c, ext/gdbm/gdbm.c, ext/readline/readline.c,
+ ext/sdbm/init.c, ext/socket/ancdata.c, ext/socket/basicsocket.c,
+ ext/socket/socket.c, ext/socket/udpsocket.c,
+ ext/stringio/stringio.c, ext/syslog/syslog.c, ext/tk/tcltklib.c,
+ ext/win32ole/win32ole.c, file.c, gc.c, hash.c, io.c, iseq.c,
+ load.c, marshal.c, object.c, proc.c, process.c, random.c, re.c,
+ safe.c, string.c, thread.c, transcode.c, variable.c,
+ vm_insnhelper.c, vm_method.c, vm_trace.c: remove code for
+ $SAFE=4.
+
+ * test/dl/test_dl2.rb, test/erb/test_erb.rb,
+ test/readline/test_readline.rb,
+ test/readline/test_readline_history.rb, test/ruby/test_alias.rb,
+ test/ruby/test_array.rb, test/ruby/test_dir.rb,
+ test/ruby/test_encoding.rb, test/ruby/test_env.rb,
+ test/ruby/test_eval.rb, test/ruby/test_exception.rb,
+ test/ruby/test_file_exhaustive.rb, test/ruby/test_hash.rb,
+ test/ruby/test_io.rb, test/ruby/test_method.rb,
+ test/ruby/test_module.rb, test/ruby/test_object.rb,
+ test/ruby/test_pack.rb, test/ruby/test_rand.rb,
+ test/ruby/test_regexp.rb, test/ruby/test_settracefunc.rb,
+ test/ruby/test_struct.rb, test/ruby/test_thread.rb,
+ test/ruby/test_time.rb: remove tests for $SAFE=4.
+
+Wed Jun 12 22:18:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (integer_unpack_num_bdigits_generic): Rewritten without
+ rb_funcall.
+ (integer_unpack_num_bdigits_bytes): Removed.
+ (rb_integer_unpack): integer_unpack_num_bdigits_bytes invocation
+ removed.
+
+Wed Jun 12 20:18:03 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/xmlrpc/client.rb (XMLRPC::Client#parse_set_cookies): Extract.
+
+Wed Jun 12 18:19:41 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (validate_integer_pack_format): supported_flags argument
+ added and validate given flags.
+ (rb_integer_pack_internal): Specify supported_flags.
+ (rb_integer_unpack): Ditto.
+
+Wed Jun 12 16:41:38 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_sort_bang): remove duplicated assertions.
+ ARY_HEAP_PTR() implies ary not to be embedded. [ruby-dev:47419]
+ [Bug #8518]
+
+Wed Jun 12 12:44:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (io_getc): fix 7bit coderange condition, check if ascii read
+ data instead of read length. [ruby-core:55444] [Bug #8516]
+
+Wed Jun 12 12:35:13 2013 Tanaka Akira <akr@fsij.org>
+
+ * pack.c (pack_pack): Use rb_integer_pack_2comp.
+
+Wed Jun 12 12:07:04 2013 Tanaka Akira <akr@fsij.org>
+
+ * sprintf.c (rb_str_format): Fix a dynamic format string.
+
+Wed Jun 12 12:04:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_uniq_bang): must not be modified once frozen even in
+ a callback method.
+
+Wed Jun 12 12:03:43 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_sort_bang): must not be modified once frozen even in
+ a callback method.
+
+Wed Jun 12 12:00:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (FL_SET_EMBED): shared object is frozen even when get
+ unshared.
+
+ * array.c (rb_ary_modify): ARY_SET_CAPA needs unshared array.
+
+Wed Jun 12 07:32:01 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c (rand_int): Use rb_big_uminus.
+
+Wed Jun 12 07:12:54 2013 Eric Hodel <drbrain@segment7.net>
+
+ * struct.c: Improve documentation: replace "instance variable" with
+ "member", recommend the use of a block to customize structs, note
+ that member accessors are created, general cleanup.
+
+Wed Jun 12 06:35:01 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (INTEGER_PACK_NEGATIVE): Defined.
+ (rb_integer_unpack): sign argument removed.
+
+ * bignum.c (rb_integer_unpack): sign argument removed.
+ Non-negative integers generated by default.
+ INTEGER_PACK_NEGATIVE flag is used to generate non-positive integers.
+
+ * pack.c (pack_unpack): Follow the above change.
+
+ * random.c (int_pair_to_real_inclusive): Ditto.
+ (make_seed_value): Ditto.
+ (mt_state): Ditto.
+ (limited_big_rand): Ditto.
+
+ * marshal.c (r_object0): Ditto.
+
+Wed Jun 12 00:07:46 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/xmlrpc/test_client.rb (XMLRPC::ClientTest#test_cookie_simple):
+ Add a test for the extracted method.
+
+Tue Jun 11 23:56:24 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/xmlrpc/test_client.rb (XMLRPC::ClientTest::Fake::HTTP#started):
+ Add a missing empty line.
+
+Tue Jun 11 23:37:19 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (validate_integer_pack_format): Don't require a word order
+ flag if numwords is 1 or less.
+ (absint_numwords_generic): Don't specify a word order for
+ rb_integer_pack.
+
+ * hash.c (rb_hash): Ditto.
+
+ * time.c (v2w_bignum): Ditto.
+
+Tue Jun 11 23:01:57 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (validate_integer_pack_format): Refine error messages.
+
+Tue Jun 11 22:25:04 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (validate_integer_pack_format): numwords argument added.
+ Move a varidation from rb_integer_pack_internal and rb_integer_unpack.
+ (rb_integer_pack_internal): Follow above change.
+ (rb_integer_unpack): Ditto.
+
+Tue Jun 11 20:52:43 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_integer_pack_internal): Renamed from rb_integer_pack
+ and overflow_2comp argument added.
+ (rb_integer_pack): Just call rb_integer_pack_internal.
+ (rb_integer_pack_2comp): New function.
+
+ * internal.h (rb_integer_pack_2comp): Declared.
+
+ * sprintf.c (rb_str_format): Use rb_integer_pack and
+ rb_integer_pack_2comp to format binary/octal/hexadecimal integers.
+ (ruby_digitmap): Declared.
+ (remove_sign_bits): Removed.
+ (BITSPERDIG): Ditto.
+ (EXTENDSIGN): Ditto.
+
+Tue Jun 11 16:15:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (ary_shrink_capa): shrink the capacity so it fits just with
+ the length.
+
+ * array.c (ary_make_shared): release never used elements from frozen
+ array to be shared. [ruby-dev:47416] [Bug #8510]
+
+Tue Jun 11 12:49:01 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * doc/re.rdoc: Rename to doc/regexp.rdoc
+ * re.c: Update rdoc include for rename of file
+
+Tue Jun 11 07:13:13 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * eval_error.c (error_print): keep that errat is non-shady object.
+ and guard errat from GC.
+
+Tue Jun 11 05:04:25 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * ext/racc/cparse/cparse.c: use rb_ary_entry() and
+ rb_ary_subseq() instead of RARRAY_PTR.
+ Based on a patch by Dirkjan Bussink. See Bug #8399.
+
+Mon Jun 10 23:51:51 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * array.c (rb_ary_new_from_values): fix a typo. pointed out by
+ nagachika.
+ http://d.hatena.ne.jp/nagachika/20130610/ruby_trunk_changes_41199_41220
+
+Mon Jun 10 21:51:03 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * ext/socket/raddrinfo.c (nogvl_getaddrinfo): Fix indent.
+
+Mon Jun 10 21:49:43 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * ext/socket/raddrinfo.c (nogvl_getaddrinfo): Add missing return
+ value assignment.
+
+Mon Jun 10 20:58:11 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/socket/raddrinfo.c (nogvl_getaddrinfo): work around for Ubuntu
+ 13.04's getaddrinfo issue with mdns4. [ruby-list:49420]
+
+Mon Jun 10 19:34:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_integer_pack): Returns sign instead of words.
+ (absint_numwords_generic): Follow the above change.
+ (big2str_base_powerof2): Follow the above change.
+
+ * internal.h: Ditto.
+
+ * hash.c (rb_hash): Ditto.
+
+ * pack.c (pack_pack): Ditto.
+
+ * random.c (int_pair_to_real_inclusive): Ditto.
+ (rand_init): Ditto.
+ (random_load): Ditto.
+ (limited_big_rand): Ditto.
+
+ * time.c (v2w_bignum): Ditto.
+
+Mon Jun 10 17:20:01 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rgengc_remember): permit promoted object.
+ (rb_gc_writebarrier -> remember)
+
+Mon Jun 10 17:14:01 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (RVALUE_PROMOTE): fix parameter name (`x' to `obj')
+ and make it inline function (like RVALUE_PROMOTE).
+
+Mon Jun 10 16:22:50 2013 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (rb_ary_new_from_values): add assertion
+ (ary should be young object).
+
+Mon Jun 10 16:05:59 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (wmap_mark): check allocation of `w->obj2wmap'.
+ (no-allocation `w->obj2wmap' will be NULL pointer reference)
+
+Mon Jun 10 15:36:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval_error.c (error_print): use checking functions instead of
+ catching exceptions.
+
+ * eval_error.c (error_print): restore errinfo for the case new
+ exception raised while printing the message. [ruby-core:55365]
+ [Bug #8501]
+
+ * eval_error.c (error_print): reduce calling setjmp.
+
+Mon Jun 10 12:10:06 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (integer_unpack_num_bdigits_small: Extracted from
+ rb_integer_unpack.
+ (integer_unpack_num_bdigits_generic): Ditto.
+ (integer_unpack_num_bdigits_bytes): New function.
+ (rb_integer_unpack): Use above functions.
+ Return a Bignum for INTEGER_PACK_FORCE_BIGNUM even when the result
+ is zero.
+
+Mon Jun 10 05:38:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (absint_numwords_small): New function.
+ (absint_numwords_generic): Use absint_numwords_small if possible.
+
+Mon Jun 10 01:07:57 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (absint_numwords_bytes): New function.
+ (absint_numwords_generic): Extracted from rb_absint_numwords.
+ (rb_absint_numwords): Use absint_numwords_bytes if possible.
+
+Sun Jun 9 21:33:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_absint_numwords): Return (size_t)-1 when overflow.
+ Refine variable names.
+ (rb_absint_size): Refine variable names.
+
+ * internal.h (rb_absint_size): Refine an argument name.
+ (rb_absint_numwords): Ditto.
+
+Sun Jun 9 16:51:41 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_absint_numwords): Renamed from rb_absint_size_in_word.
+
+ * internal.h (rb_absint_numwords): Follow the above change.
+
+ * pack.c (pack_pack): Ditto.
+
+ * random.c (rand_init): Ditto.
+ (limited_big_rand): Ditto.
+
+Sun Jun 9 14:41:05 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_integer_pack): numwords_allocated argument removed.
+
+ * internal.h (rb_integer_pack): Follow the above change.
+
+ * hash.c (rb_hash): Ditto.
+
+ * time.c (v2w_bignum): Ditto.
+
+ * pack.c (pack_pack): Ditto.
+
+ * random.c (int_pair_to_real_inclusive): Ditto.
+ (rand_init): Ditto.
+ (random_load): Ditto.
+ (limited_big_rand): Ditto.
+
+Sun Jun 9 09:34:44 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big2str_base_powerof2): New function.
+ (rb_big2str0): Use big2str_base_powerof2 if base is 2, 4, 8, 16 or 32.
+
+Sun Jun 9 00:59:04 2013 Tanaka Akira <akr@fsij.org>
+
+ * hash.c (rb_hash): Use rb_integer_pack to obtain least significant
+ long integer.
+
+Sat Jun 8 23:56:00 2013 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_num_to_uint): Use rb_absint_size instead of
+ RBIGNUM_LEN.
+
+Sat Jun 8 22:53:45 2013 Tanaka Akira <akr@fsij.org>
+
+ * marshal.c (r_object0): Use rb_integer_unpack.
+
+Sat Jun 8 22:18:57 2013 Tanaka Akira <akr@fsij.org>
+
+ * time.c (v2w): Use rb_absint_size instead of RBIGNUM_LEN.
+
+Sat Jun 8 21:47:33 2013 Tanaka Akira <akr@fsij.org>
+
+ * time.c (v2w_bignum): Simplified using rb_integer_pack.
+ (rb_big_abs_find_maxbit): Removed.
+
+Sat Jun 8 21:03:40 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_absint_singlebit_p): New function.
+
+ * internal.h (rb_absint_singlebit_p): Declared.
+
+ * time.c (v2w_bignum): Use rb_absint_singlebit_p instead of
+ rb_big_abs_find_minbit.
+ (rb_big_abs_find_minbit): Removed.
+
+Sat Jun 8 20:24:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * time.c (rb_big_abs_find_maxbit): Use rb_absint_size.
+ (bdigit_find_maxbit): Removed.
+
+Sat Jun 8 19:47:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * class.c (include_modules_at): invalidate method cache if included
+ module contains constants
+
+ * test/ruby/test_module.rb: add test
+
+Sat Jun 8 19:31:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * random.c (limited_big_rand): declare rnd, lim and mask as uint32_t
+ to avoid 64 bit to 32 bit shorten warnings.
+
+Sat Jun 8 19:23:53 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * win32/Makefile.sub: r41163 changed win32/win32.c and configure.in
+ but it didn't treat about mswin32/mswin64, so fix it.
+ NOTE: this needs a review by usa whether additional condition is
+ required or not.
+
+Sat Jun 8 19:06:26 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c: Unused RBignum internal accessing macros removed.
+
+Sat Jun 8 19:04:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c (limited_big_rand): The argument, limit, is changed to
+ VALUE. Use rb_integer_pack and rb_integer_unpack.
+
+Sat Jun 8 17:15:18 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c (make_seed_value): Fix the length given for
+ rb_integer_unpack.
+
+Sat Jun 8 16:38:02 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_integer_unpack): Don't use rb_funcall if possible.
+
+ * random.c: Use uint32_t for elements of seed.
+ (make_seed_value): Use rb_integer_unpack.
+
+Sat Jun 8 15:58:18 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c (rand_init): Add a cast to fix clang compile error:
+ random.c:410:32: error: implicit conversion loses integer precision:
+ 'size_t' (aka 'unsigned long') to 'int' [-Werror,-Wshorten-64-to-32]
+ This cast doesn't cause a problem because len is not bigger than
+ MT_MAX_STATE.
+
+Sat Jun 8 15:30:03 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c (rand_init): Use rb_integer_pack.
+ (roomof): Removed.
+
+Sat Jun 8 14:58:32 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (INTEGER_PACK_FORCE_BIGNUM): New flag constant.
+
+ * bignum.c (rb_integer_unpack): Support INTEGER_PACK_FORCE_BIGNUM.
+
+ * random.c (int_pair_to_real_inclusive): Use
+ INTEGER_PACK_FORCE_BIGNUM to use rb_big_mul instead of rb_funcall.
+
+Sat Jun 8 14:17:01 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: check for NET_LUID. header macro varies across
+ compiler versions.
+
+ * win32/win32.c: use configured macro.
+
+Sat Jun 8 11:59:55 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c (int_pair_to_real_inclusive): Use rb_funcall instead of
+ rb_big_mul because rb_integer_unpack can return a Fixnum.
+
+Sat Jun 8 11:17:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c (int_pair_to_real_inclusive): Use rb_integer_pack.
+
+Sat Jun 8 09:49:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c (int_pair_to_real_inclusive): Use rb_integer_unpack.
+
+Sat Jun 8 08:12:22 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c (random_load): Use rb_integer_pack.
+
+Sat Jun 8 06:15:46 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c (numberof): Removed.
+
+Sat Jun 8 06:00:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c: include internal.h.
+ (mt_state): Use rb_integer_unpack.
+
+Sat Jun 8 00:55:51 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (integer_pack_loop_setup): word_num_nailbytes_ret argument
+ removed.
+ (rb_integer_pack): Follow the above change.
+ (rb_integer_unpack): Follow the above change.
+
+Sat Jun 8 00:37:32 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (validate_integer_pack_format): Renamed from
+ validate_integer_format.
+ (integer_pack_loop_setup): Renamed from integer_format_loop_setup.
+ (integer_pack_fill_dd): Renamed from int_export_fill_dd.
+ (integer_pack_take_lowbits): Renamed from int_export_take_lowbits.
+ (integer_unpack_push_bits): Renamed from int_import_push_bits.
+
+Fri Jun 7 23:58:06 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_integer_pack): Arguments changed. Use flags to
+ specify word order and byte order.
+ (rb_integer_unpack): Ditto.
+ (validate_integer_format): Follow the above change.
+ (integer_format_loop_setup): Ditto.
+
+ * pack.c: Ditto.
+
+ * internal.h: Ditto.
+ (INTEGER_PACK_MSWORD_FIRST): Defined.
+ (INTEGER_PACK_LSWORD_FIRST): Ditto.
+ (INTEGER_PACK_MSBYTE_FIRST): Ditto.
+ (INTEGER_PACK_LSBYTE_FIRST): Ditto.
+ (INTEGER_PACK_NATIVE_BYTE_ORDER): Ditto.
+ (INTEGER_PACK_LITTLE_ENDIAN): Ditto.
+ (INTEGER_PACK_BIG_ENDIAN): Ditto.
+
+Fri Jun 7 22:10:50 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/rubygems/specification.rb (Gem::Specification#to_yaml):
+ use Gem::NoAliasYAMLTree.create instead of Gem::NoAliasYAMLTree.new
+ to suppress deprecated warnings.
+
+Fri Jun 7 21:39:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_integer_pack): Renamed from rb_int_export.
+ (rb_integer_unpack): Renamed from rb_int_import.
+
+ * internal.h, pack.c: Follow the above change.
+
+Fri Jun 7 21:05:26 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (integer_format_loop_setup): Extracted from rb_int_export
+ and rb_int_import.
+
+Fri Jun 7 19:48:38 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (validate_integer_format): Extracted from rb_int_export and
+ rb_int_import.
+
+Fri Jun 7 19:23:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_absint_size): Use numberof.
+ (rb_int_export): Ditto.
+
+Fri Jun 7 18:58:56 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (numberof): Gathered from various files.
+
+ * array.c, math.c, thread_pthread.c, iseq.c, enum.c, string.c, io.c,
+ load.c, compile.c, struct.c, eval.c, gc.c, parse.y, process.c,
+ error.c, ruby.c: Remove the definitions of numberof.
+
+Fri Jun 7 18:24:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_absint_size): Declare a variable, i, just before used
+ to suppress a warning.
+ (rb_int_export): Ditto.
+
+Fri Jun 7 17:41:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * bignum.c (rb_absint_size): explicit cast to BDIGIT to avoid implicit
+ 64 bit to 32 bit shortening warning
+ * bignum.c (rb_int_export): ditto
+ * bignum.c (int_import_push_bits): ditto
+
+Fri Jun 7 17:31:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * internal.h (RCLASS_SUPER): use descriptive variable name
+ * internal.h (RCLASS_SET_SUPER): ditto
+
+Fri Jun 7 13:25:27 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/json/fbuffer/fbuffer.h (fbuffer_append_str): change the place of
+ RB_GC_GUARD. it should be after the object is used.
+
+Fri Jun 7 13:22:43 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * gc.c (before_gc_sweep): noinline can also avoid the segv instead of
+ -O0 of r41084. this way is expected less slow.
+
+Fri Jun 7 11:45:42 2013 Kenta Murata <mrkn@cookpad.com>
+
+ * rational.c (numeric_quo): move num_quo in numeric.c to numeric_quo
+ in rational.c to refer canonicalization state for mathn support.
+ [ruby-core:41575] [Bug #5736]
+
+ * numeric.c (num_quo): ditto.
+
+ * test/test_mathn.rb: add a test for the change at r41109.
+
+Fri Jun 7 11:41:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: revert r41106. size_t may not be unsigned
+
+ * bignum.c (rb_absint_size_in_word, rb_int_export, rb_int_import): use
+ NUM2SIZET() and SIZET2NUM() already defined in ruby/ruby.h.
+
+Fri Jun 7 11:28:37 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c: use oldgen bitmap as initial mark bitmap when major gc.
+ so can skip oldgen bitmap check around mark & sweep.
+ * gc.c (slot_sweep_body): change scan algorithm for performance:
+ from object's pointer base to bitmap one.
+
+Fri Jun 7 11:25:56 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c: introduce oldgen bitmap for preparing performance tuning.
+
+Fri Jun 7 11:20:57 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (MARKED_IN_BITMAP, MARK_IN_BITMAP, CLEAR_IN_BITMAP): bring
+ bitmap macros in one place, and introduce BITMAP_BIT.
+
+Fri Jun 7 11:18:35 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * array.c (ary_new): change order of allocation in order
+ to remove FL_OLDGEN operation.
+
+Fri Jun 7 11:16:28 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * tool/rdocbench.rb: add gc total time information.
+
+Fri Jun 7 10:12:01 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: remove "Sunny" terminology.
+ "Sunny" doesn't mean antonym of "Shady" (questionable, doubtful, etc).
+ Instead of "Sunny", use "non-shady" or "normal".
+
+Fri Jun 7 09:29:33 2013 Kenta Murata <mrkn@cookpad.com>
+
+ * bignum.c (rb_int_import): explicitly casting BDIGIT_DBL to BDIGIT
+ to prevent warning.
+
+Fri Jun 7 07:29:33 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (rb_int_export): countp argument is split into
+ wordcount_allocated and wordcount.
+
+ * bignum.c (rb_int_export): Follow the above change.
+
+ * pack.c (pack_pack): Ditto.
+
+Fri Jun 7 07:17:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * NEWS: describe a compatibility issue of Numeric#quo
+ introduced at r41109.
+
+Fri Jun 7 07:15:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * NEWS: fix style.
+
+Fri Jun 7 06:48:17 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * numeric.c: remove unused ID id_to_r introduced in r41109.
+
+Fri Jun 7 06:15:31 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_int_import): New function.
+ (int_import_push_bits): Ditto.
+
+ * internal.h (rb_int_import): Declared.
+
+ * pack.c (pack_unpack): Use rb_int_import for BER compressed integer.
+
+Thu Jun 6 22:24:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * numeric.c (num_quo): Use to_r method to convert the receiver to
+ rational. [ruby-core:41575] [Bug #5736]
+
+ * test/ruby/test_numeric.rb: add a test for the above change.
+
+Thu Jun 6 20:40:17 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Invoke RUBY_REPLACE_TYPE for size_t.
+ Don't invoke RUBY_CHECK_PRINTF_PREFIX for size_t to avoid conflict
+ with RUBY_REPLACE_TYPE.
+
+ * internal.h (rb_absint_size): Declared.
+ (rb_absint_size_in_word): Ditto.
+ (rb_int_export): Ditto.
+
+ * bignum.c (rb_absint_size): New function.
+ (rb_absint_size_in_word): Ditto.
+ (int_export_fill_dd): Ditto.
+ (int_export_take_lowbits): Ditto.
+ (rb_int_export): Ditto.
+
+ * pack.c (pack_pack): Use rb_int_export for BER compressed integer.
+
+Thu Jun 6 19:31:33 2013 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * ext/date/date_core.c: fixed coding error [ruby-core:55337].
+ reported by Riley Lynch.
+
+Thu Jun 6 14:16:37 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * ext/objspace/object_tracing.c: rename allocation_info to
+ lookup_allocation_info. At times I confused "struct
+ allocation_info" with "function allocation_info".
+
+Thu Jun 6 13:57:06 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * ext/objspace/object_tracing.c: allocation_info function isn't
+ called by any other file.
+
+Thu Jun 6 09:41:00 2013 Kenta Murata <mrkn@cookpad.com>
+
+ * numeric.c (num_quo): should return a Float for a Float argument.
+ [ruby-dev:44710] [Bug #5515]
+
+ * test/ruby/test_fixnum.rb: Add an assertion for the above change.
+
+ * test/ruby/test_bignum.rb: ditto.
+
+Thu Jun 6 00:59:44 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (gc_mark): get rid of pushing useless objects.
+ * gc.c (rgengc_rememberset_mark): bypass gc_mark() in order to push
+ sunny old object at minor gc.
+ * gc.c (gc_mark_children): move sunny old check to gc_mark().
+ * gc.c (rgengc_check_shady): remove DEMOTE that already unnecessary.
+ * gc.c (rb_gc_writebarrier): ditto.
+
+ change sunny old check point in order to save mark stack and
+ remove unnatural rest_sweep & demote.
+
+Thu Jun 6 00:52:42 2013 Masaya Tarui <tarui@ruby-lang.org>
+
+ * gc.c (rgengc_rememberset_mark): change scan algorithm for performance:
+ from object's pointer base to bitmap one.
+
+Thu Jun 6 00:30:04 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * win32/win32.c (NET_LUID): define it on MinGW32.
+ mingw-w64 has NET_LUID but mingw32 (mingw.org) still doesn't have
+ NET_LUID. reported by taco on IRC
+
+Thu Jun 6 00:05:08 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * string.c (String#b): Allow code range scan to happen later so
+ ascii_only? on a result string returns the correct value.
+ [ruby-core:55315] [Bug #8496]
+
+Wed Jun 5 22:40:42 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap.rb (capability_response): should ignore trailing
+ spaces. Thanks, Peter Kovacs. [ruby-core:55024] [Bug #8415]
+
+ * test/net/imap/test_imap_response_parser.rb: related test.
+
+Wed Jun 5 21:17:08 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (big_fdiv): Use nlz() instead of bdigbitsize().
+ (bdigbitsize): Removed.
+
+Wed Jun 5 20:32:00 2013 Kenta Murata <mrkn@cookpad.com>
+
+ * include/ruby/ruby.h: fix alignment in comment.
+
+Wed Jun 5 20:05:29 2013 Tanaka Akira <akr@fsij.org>
+
+ * random.c (int_pair_to_real_inclusive): Add a cast to BDIGIT.
+ (random_load): Fix shift width for fixnums.
+ Re-implement bignum extraction without ifdefs.
+
+Wed Jun 5 15:26:10 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * gc.c (before_gc_sweep): don't optimize it to avoid segv on Ubuntu
+ 10.04 gcc 4.4.
+ http://u32.rubyci.org/~chkbuild/ruby-trunk/log/20130527T190301Z.diff.html.gz
+
+Wed Jun 5 09:46:46 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * test/fileutils/test_fileutils.rb (TestFileUtils#test_mkdir): add
+ EACCES for Windows.
+
+Wed Jun 5 08:13:37 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_pow): Don't need to multiply SIZEOF_BDIGITS.
+ Use nlz instead of bitlength_bdigit.
+ (bitlength_bdigit): Removed.
+
+Wed Jun 5 07:14:18 2013 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * ext/date/date_core.c (d_lite_cmp, d_lite_equal): simplified.
+
+Wed Jun 5 07:07:01 2013 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * ext/date/date_core.c: fixed a bug [ruby-core:55295]. reported
+ by Riley Lynch.
+
+Wed Jun 5 06:44:08 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems 2.0.3
+
+ * test/rubygems: Tests for the above.
+
+ * NEWS: Added RubyGems 2.0.3 note.
+
+Wed Jun 5 06:35:15 2013 Eric Hodel <drbrain@segment7.net>
+
+ * doc/marshal.rdoc: Add description of Marshal format.
+
+Wed Jun 5 01:16:09 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * array.c (Array#+): fix documentation example.
+ Patch by Logan Serman. [Fixes GH-324]
+
+Wed Jun 5 00:21:54 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * lib/irb/lc/ja/help-message: update help messages.
+ following r41028. [ruby-dev:46707] [Feature #7510]
+
+Wed Jun 5 00:09:32 2013 Tanaka Akira <akr@fsij.org>
+
+ * marshal.c (r_object0): Generalize a round up expression.
+ Use BDIGIT instead of int.
+
+Tue Jun 4 23:44:02 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * object.c (rb_Hash): fix docs. patched by Stefan Sch"ussler.
+ [ruby-core:55299] [Bug #8487]
+
+Tue Jun 4 23:16:49 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * lib/irb/completion.rb: Use %w literal construction for long lists.
+ Patch by Dave Goodchild. [Fixes GH-299]
+
+Tue Jun 4 23:08:42 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * ext/objspace/objspace.c: improve wording and remove duplicated comment.
+ Based on a patch by Dave Goodchild. [Fixes GH-299]
+
+Tue Jun 4 18:41:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bitlength_bdigit): Fix an off-by-one error.
+
+Tue Jun 4 15:30:00 2013 Kenta Murata <mrkn@cookpad.com>
+
+ * ext/bigdecimal/lib/bigdecimal/util.rb (Float#to_d): fix the number
+ of figures. Patch by Vipul A M <vipulnsward@gmail.com>.
+ https://github.com/ruby/ruby/pull/323 fix GH-323
+
+ * test/bigdecimal/test_bigdecimal_util.rb: fix for the above change.
+
+Tue Jun 4 00:44:27 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * test/fileutils/test_fileutils.rb (TestFileUtils#test_mkdir): add
+ EEXIST for Linux. (suggested by nurse)
+
+Mon Jun 3 23:58:19 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * lib/fileutils.rb (FileUtils.rmdir): use remove_tailing_slash.
+ * test/fileutils/test_fileutils.rb: test for above.
+
+Mon Jun 3 23:47:55 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bitlength_bdigit): New function.
+ (rb_big_pow): Use bitlength_bdigit instead of ffs.
+
+Mon Jun 3 23:11:19 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * lib/fileutils.rb: fix behavior when mkdir/mkdir_p accepted "/".
+ * test/fileutils/test_fileutils.rb: add test for above change.
+ Patched by Mitsunori Komatsu. [GH-319]
+
+Mon Jun 3 19:02:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (is_hfs): use the file descriptor instead of a path.
+
+Mon Jun 3 07:15:17 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: removes AC_CHECK_FUNCS(readdir_r). readdir_r()
+ is only used from dir.c and it doesn't need readdir_r().
+ * configure.in (SIZEOF_STRUCT_DIRENT_TOO_SMALL): removed. It is
+ only used for readdir_r.
+ * dir.c: removes NAME_MAX_FOR_STRUCT_DIRENT. It is not right way
+ to detect maximum length of path len. POSIX require to use
+ fpathconf(). IOW, it might have lead to make a vulnerability
+ using stack smashing. Moreover, readdir() works enough for our
+ usage.
+ * dir.c (READDIR): removes an implementation which uses
+ readdir_r() and parenthesize in a macro body correctly.
+ * dir.c (dir_read): removes IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT
+ entry), it is used only for readdir_r().
+ * dir.c (dir_each): ditto.
+ * dir.c (glob_helper): ditto.
+
+ * dir.c (READDIR): removes entry and dp argument.
+ * dir.c (dir_read): adjust for the above change.
+ * dir.c (dir_each): ditto.
+ * dir.c (glob_helper): ditto.
+
+Mon Jun 3 03:40:29 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_yield_setup_block_args): partially revert r41019.
+ The code is not useless.
+
+Mon Jun 3 01:25:25 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * test/socket/test_sockopt.rb: change test name. follow r41037.
+
+Mon Jun 3 01:08:43 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * test/rinda/test_rinda.rb: rename functions introduced in r41009.
+
+Sun Jun 2 23:33:42 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * enc/trans/japanese_euc.trans, test/ruby/test_transcode.rb,
+ tool/transcode-tblgen.rb: change EUC-JP-2004 to EUC-JIS-2004.
+ This is follow up to changes in r41024.
+
+Sun Jun 2 22:44:42 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/socket/option.c: rename functions introduced in r41009
+ s/ip/ipv4/g because they are ipv4 functions.
+ (there's a policy that the name "ip" is for methods which supports
+ both ipv4 and ipv6)
+
+Sun Jun 2 16:15:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dln_find.c (dln_find_exe, dln_find_file): remove deprecated
+ non-reentrant functions.
+
+Sun Jun 2 15:04:35 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/cgi/util.rb, lib/erb.rb: Use String#b [Feature #8394] by znz
+
+Sun Jun 2 14:10:21 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/irb/lc/help-message: Apply english updates for irb --help #7510
+
+Sun Jun 2 12:03:58 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * range.c: Fix rdoc on Range#bsearch [Bug #8242] [ruby-core:54143]
+
+Sun Jun 2 02:08:37 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * enc/euc_jp.c: fix typo: the name of EUC-JIS-2004.
+
+Sat Jun 1 23:17:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * vm_eval.c (rb_mod_module_eval): mention in docs that arguments passed
+ to the method are passed to the block
+
+Sat Jun 1 17:58:13 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb (Set#freeze, taint, untaint): Save a "self" by
+ utilizing super returning self, and add tests while at it.
+
+Sat Jun 1 17:24:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_set_arguments): not a simple single argument if any
+ keyword arguments exist. [ruby-core:55203] [Bug #8463]
+
+ * vm_insnhelper.c (vm_yield_setup_block_args): split single parameter
+ if any keyword arguments exist, and then extract keyword arguments.
+ [ruby-core:55203] [Bug #8463]
+
+Sat Jun 1 11:16:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (rb_exc_new_cstr): rename from rb_exc_new2.
+
+ * error.c (rb_exc_new_str): rename from rb_exc_new3.
+
+Sat Jun 1 10:13:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_new[2-5], rb_{tainted,usascii}_str_new2),
+ (rb_str_buf_new2): remove old interfaces.
+
+Sat Jun 1 08:00:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/zlib/zlib.c (gzfile_read, gzfile_read_all, gzfile_getc),
+ (gzreader_gets): check EOF. [ruby-core:55220] [Bug #8467]
+
+Sat Jun 1 07:32:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: Use BDIGIT type for hbase.
+
+Sat Jun 1 02:37:35 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/socket/option.c (sockopt_s_byte): constructor of the sockopt
+ whose value's is byte.
+
+ * ext/socket/option.c (sockopt_byte): getter for above.
+
+ * ext/socket/option.c (inspect_byte): inspect for above.
+
+ * ext/socket/option.c (sockopt_s_ip_multicast_loop): constructor of
+ the sockopt whose optname is IP_MULTICAST_LOOP.
+
+ * ext/socket/option.c (sockopt_ip_multicast_loop): getter for above.
+
+ * ext/socket/option.c (sockopt_s_ip_multicast_ttl): constructor of
+ the sockopt whose optname is IP_MULTICAST_TTL.
+
+ * ext/socket/option.c (sockopt_ip_multicast_ttl): getter for above.
+
+ * ext/socket/option.c (sockopt_inspect): use above.
+
+Sat Jun 01 01:50:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_power): use rb_dbl2big
+ to convert a double value to a Bignum.
+
+Sat Jun 1 00:19:50 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (calc_hbase): Make hbase the maximum power of base
+ representable in BDIGIT.
+
+Fri May 31 23:56:13 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (calc_hbase): Extracted from rb_big2str0.
+
+Fri May 31 23:22:24 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c: Don't hard code SIZEOF_BDIGITS for log_base(hbase).
+ (big2str_orig): hbase_numdigits argument added.
+ (big2str_karatsuba): Ditto.
+ (rb_big2str0): Calculate hbase_numdigits.
+
+Fri May 31 17:57:21 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * process.c: Improve Process::exec documentation
+
+Fri May 31 17:26:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (rb_funcallv): add better names of rb_funcall2.
+
+ * vm_eval.c (rb_funcallv_public): ditto for rb_funcall3.
+
+Fri May 31 17:04:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_new_capa): add better names of rb_ary_new2.
+
+ * array.c (rb_ary_new_from_args): ditto for rb_ary_new3.
+
+ * array.c (rb_ary_new_from_values): ditto for rb_ary_new4.
+
+Fri May 31 16:35:44 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (HAVE_ATTRIBUTE_FUNCTION_ALIAS): define to tell if
+ alias attribute is available.
+
+Fri May 31 16:03:23 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * object.c, proc.c: s/call_seq/call-seq in rdoc. [Fixes GH-322]
+
+Fri May 31 15:56:36 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/openssl/ossl_ssl.c: Add missing paren in rdoc [Fixes GH-321]
+
+Fri May 31 11:58:24 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_method.c (set_visibility): extract from rb_mod_public(),
+ rb_mod_protected() and rb_mod_private().
+
+Thu May 30 19:47:42 2013 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * vm_insnhelper.c (vm_callee_setup_keyword_arg,
+ vm_callee_setup_arg_complex): consider a hash argument for keyword
+ only when the number of arguments is more than the expected
+ mandatory parameters. [ruby-core:53199] [ruby-trunk - Bug #8040]
+
+ * test/ruby/test_keyword.rb: update a test for above.
+
+Thu May 30 17:55:04 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * process.c: RDoc on Process.spawn
+
+Thu May 30 00:08:14 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_profile_enable): rest_sweep() to finish last GC.
+ Profiling record is allocated at first of marking phase.
+ Enable at lazy sweeping may cause an error (SEGV).
+
+Wed May 29 10:33:27 2013 Koichi Sasada <ko1@atdot.net>
+
+ * hash.c: fix WB bug.
+ (1) Hash's key also needs WB.
+ (2) callback parameter *key and *value of st_update() is not a
+ storage of st_table itself (only local variable). So that
+ OBJ_WRITE() is not suitable, especially for `!existing'.
+ OBJ_WRITTEN() is used instead of OBJ_WRITE().
+
+Tue May 28 12:31:21 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/object_tracing.c: fix a bug reported at
+ "[ruby-core:55182] [ruby-trunk - Bug #8456][Open] Sugfault in Ruby Head"
+ Care about the case TracePoint#path #=> `nil'.
+
+ * ext/objspace/object_tracing.c: add two new methods:
+ * ObjectSpace.allocation_class_path(o)
+ * ObjectSpace.allocation_method_id(o)
+ They are not useful for Object.new because they are always
+ "Class" and :new.
+ To trace more useful information, we need to maintain call-tree
+ using call/return hooks, which is implemented by
+ ll-prof <http://sunagae.net/wiki/doku.php?id=software:llprof>
+
+ * test/objspace/test_objspace.rb: add a test.
+
+Tue May 28 11:30:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb (extmake): leave makefiles untouched if the content is
+ not changed, to get rid of unnecessary re-linking.
+
+Tue May 28 03:11:02 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/gc_hook.c, ext/objspace/objspace.c: add new methods to
+ hook GC invocation.
+ * ObjectSpace.after_gc_start_hook=(proc)
+ * ObjectSpace.after_gc_end_hook=(proc)
+
+ Note that hooks are not kicked immediately. Procs are kicked
+ at postponed_job.
+
+ This feature is a sample of new internal event and
+ rb_postponed_job API.
+
+Tue May 28 02:56:15 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat): remove wrong rest_sweep().
+
+Tue May 28 02:44:23 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (garbage_collect_body): fix GC_ENABLE_LAZY_SWEEP condition.
+
+ * gc.c (GC_NOTIFY): move debug print location and use stderr instead
+ of stdout.
+
+Tue May 28 02:07:21 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_trace.c (rb_postponed_job_register_one): fix iteration bug.
+
+ * ext/-test-/postponed_job/postponed_job.c,
+ test/-ext-/postponed_job/test_postponed_job.rb: add a test.
+
+Tue May 28 00:34:23 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h, gc.c: add new internal event
+ RUBY_INTERNAL_EVENT_GC_END. This event invokes at the end of
+ after_sweep().
+ Time chart with lazy sweep is:
+ (1) Kick RUBY_INTERNAL_EVENT_GC_START
+ (2) [gc_marks()]
+ (3) [lazy_sweep()]
+ (4) [... run Ruby program (mutator) with lazy_sweep() ...]
+ (5) [after_sweep()]
+ (6) Kick RUBY_INTERNAL_EVENT_GC_END
+ (7) [... run Ruby program (mutator), and go to (1) ...]
+ Time chart without lazy sweep (GC.start, etc) is:
+ (1) Kick RUBY_INTERNAL_EVENT_GC_START
+ (2) [gc_marks()]
+ (3) [gc_sweep()]
+ (4) [after_sweep()]
+ (5) Kick RUBY_INTERNAL_EVENT_GC_END
+ (6) [... run Ruby program (mutator), and go to (1) ...]
+
+ * ext/-test-/tracepoint/tracepoint.c,
+ test/-ext-/tracepoint/test_tracepoint.rb: modify a test.
+
+Tue May 28 00:18:57 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_trace.c (rb_postponed_job_flush): remove a wrong comment.
+
+Mon May 27 22:09:33 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/ruby.h (RHASH_SIZE): Add a cast to suppress a
+ warning, comparison between signed and unsigned integer
+ expressions [-Wsign-compare], on ILP32.
+
+Mon May 27 19:25:47 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: rename RUBY_INTERNAL_EVENT_FREE to
+ RUBY_INTERNAL_EVENT_FREEOBJ.
+
+ * ext/-test-/tracepoint/tracepoint.c,
+ ext/objspace/object_tracing.c,
+ gc.c, vm_trace.c: catch up this change.
+
+Mon May 27 18:57:28 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/objspace.c: support ObjectSpace.trace_object_allocations.
+ Read the following test to know HOWTO.
+ This feature is a sample of RUBY_INTERNAL_EVENT.
+
+ * test/objspace/test_objspace.rb: add a test.
+
+ * ext/objspace/object_tracing.c: ditto.
+
+ * gc.c (rb_gc_count): add. This function returns GC count.
+
+ * internal.h: add decl. of rb_gc_count(). Same as `GC.count'.
+
+Mon May 27 17:33:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/rbinstall.rb (install_recursive): add maxdepth option.
+
+ * tool/rbinstall.rb (bin-comm): limit depth of bindir and reject empty
+ files. [ruby-core:55101] [Bug #8432]
+
+Mon May 27 16:16:18 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_trace.c (rb_postponed_job_flush, rb_postponed_job_register): use
+ ruby_xmalloc/xfree. It is safe during GC.
+
+Mon May 27 09:24:03 2013 Koichi Sasada <ko1@atdot.net>
+
+ * test/-ext-/postponed_job/test_postponed_job.rb: fix typo and class name.
+
+Mon May 27 09:05:17 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h, gc.c, vm_trace.c: add internal events.
+ * RUBY_INTERNAL_EVENT_NEWOBJ: object created.
+ * RUBY_INTERNAL_EVENT_FREE: object freed.
+ * RUBY_INTERNAL_EVENT_GC_START: GC started.
+ And rename `RUBY_EVENT_SWITCH' to `RUBY_INTERNAL_EVENT_SWITCH'.
+
+ Internal events can not invoke any Ruby program because the tracing
+ timing may be critical (under huge restriction).
+ These events can be hooked only by C-extensions.
+ We recommend to use rb_postponed_job_register() API to call Ruby
+ program safely.
+
+ This change is mostly written by Aman Gupta (tmm1).
+ https://bugs.ruby-lang.org/issues/8107#note-12
+ [Feature #8107]
+
+ * include/ruby/debug.h, vm_trace.c: added two new APIs.
+ * rb_tracearg_event_flag() returns rb_event_flag_t of this event.
+ * rb_tracearg_object() returns created/freed object.
+
+ * ext/-test-/tracepoint/extconf.rb,
+ ext/-test-/tracepoint/tracepoint.c,
+ test/-ext-/tracepoint/test_tracepoint.rb: add a test.
+
+Mon May 27 08:38:21 2013 Koichi Sasada <ko1@atdot.net>
+
+ * ext/-test-/postponed_job/postponed_job.c: fix `init' function name.
+
+Mon May 27 06:22:41 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/debug.h, vm_trace.c: add rb_postponed_job API.
+ Postponed jobs are registered with this API. Registered jobs
+ are invoked at `ruby-running-safe-point' as soon as possible.
+ This timing is completely same as finalizer timing.
+
+ There are two APIs:
+ * rb_postponed_job_register(flags, func, data): register a
+ postponed job with data. flags are reserved.
+ * rb_postponed_job_register_one(flags, func, data): same as
+ `rb_postponed_job_register', but only one `func' job is
+ registered (skip if `func' is already registered).
+
+ This change is mostly written by Aman Gupta (tmm1).
+ https://bugs.ruby-lang.org/issues/8107#note-15
+ [Feature #8107]
+
+ * gc.c: use postponed job API for finalizer.
+
+ * common.mk: add dependency from vm_trace.c to debug.h.
+
+ * ext/-test-/postponed_job/extconf.rb, postponed_job.c,
+ test/-ext-/postponed_job/test_postponed_job.rb: add a test.
+
+ * thread.c: implement postponed API.
+
+ * vm_core.h: ditto.
+
+Mon May 27 02:26:02 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat): collect promote_operation_count and
+ types (RGENGC_PROFILE >= 2).
+
+Mon May 27 01:40:58 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat): collect shade_operation_count,
+ remembered_sunny_object_count and remembered_shady_object_count
+ for each types when RGENGC_PROFILE >= 2.
+ They are informative for optimization.
+
+Mon May 27 01:15:22 2013 Koichi Sasada <ko1@atdot.net>
+
+ * hash.c (rb_hash_tbl_raw), internal.h: added.
+ Returns st_table without shading hash.
+
+ * array.c: use rb_hash_tbl_raw() for read-only purpose.
+
+ * compile.c (iseq_compile_each): ditto.
+
+ * gc.c (count_objects): ditto.
+
+ * insns.def: ditto.
+
+ * process.c: ditto.
+
+ * thread.c (clear_coverage): ditto.
+
+ * vm_insnhelper.c: ditto.
+
+Mon May 27 00:31:09 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/make-snapshot: use ENV["AUTOCONF"] instead of directly using
+ literal "autoconf".
+
+Sun May 26 21:31:46 2013 Koichi Sasada <ko1@atdot.net>
+
+ * hash.c, include/ruby/ruby.h: support WB protected hash.
+ * constify RHash::ifnone and make new macro RHASH_SET_IFNONE().
+ * insert write barrier for st_update().
+
+ * include/ruby/intern.h: declare rb_hash_set_ifnone(hash, ifnone).
+
+ * marshal.c (r_object0): use RHASH_SET_IFNONE().
+
+ * ext/openssl/ossl_x509name.c (Init_ossl_x509name): ditto.
+
+Sat May 25 23:22:38 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * test/fiddle/test_c_struct_entry.rb,
+ test/fiddle/test_c_union_entity.rb,
+ test/fiddle/test_cparser.rb, test/fiddle/test_func.rb,
+ test/fiddle/test_handle.rb, test/fiddle/test_import.rb,
+ test/fiddle/test_pointer.rb: don't run test if the system
+ don't support fiddle.
+
+Sat May 25 21:29:34 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/pty/pty.c (get_device_once): FreeBSD 10-current and 9-stable
+ added O_CLOEXEC support to posix_openpt, so assume FreeBSD 9.2 or
+ later supports it.
+ http://www.freebsd.org/cgi/query-pr.cgi?pr=162374
+
+Sat May 25 18:46:23 2013 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * proc.c (rb_method_entry_min_max_arity): fix missing break in switch.
+ This was introduced in r38236, which is not intentional apparently.
+ This has caused no actual harm because VM_METHOD_TYPE_OPTIMIZED is
+ not used except for OPTIMIZED_METHOD_TYPE_SEND, but may do in
+ future. Coverity Scan found this inadequacy.
+
+Sat May 25 18:08:06 2013 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * dir.c (bracket): fix copy-paste error. When the first and last
+ characters of fnmatch range have different length, fnmatch may
+ have wrongly matched a path that does not really match.
+ Coverity Scan found this bug.
+
+Sat May 25 17:06:25 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (after_gc_sweep): reduce full GC timing.
+
+Sat May 25 11:28:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * variable.c (set_const_visibility): return without clearing method
+ cache if no arguments.
+
+ * vm_method.c (set_method_visibility): ditto.
+
+Sat May 25 11:27:32 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_method.c (set_method_visibility): quote unprintable method name.
+
+Sat May 25 11:24:24 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_frame_callee): returns the called name of the current
+ frame, not the previous frame.
+
+ * eval.c (prev_frame_callee, prev_frame_func): rename and make static,
+ as these are used by rb_f_method_name() and rb_f_callee_name() only.
+
+ * variable.c (set_const_visibility): use the called name.
+
+Sat May 25 08:58:23 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_quote_unprintable): check if argument is a string.
+
+Fri May 24 19:32:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * variable.c (set_const_visibility): use rb_frame_this_func() instead
+ of rb_frame_callee() for getting the name of the called method
+
+ * test/ruby/test_module.rb: add test for private_constant with no args
+
+Fri May 24 18:53:10 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: do major/full GC when:
+ * number of oldgen object is bigger than twice of
+ number of oldgen object at last full GC.
+ * number of remembered shady object is bigger than twice of
+ number of remembered shady object at last full GC.
+ * number of oldgen object and remembered shady object is bigger
+ than half of total object space.
+ (please fix my English!)
+
+Fri May 24 17:07:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * intern.h: remove dangling rb_class_init_copy declaration
+ [ruby-core:55120] [Bug #8434]
+
+Fri May 24 16:31:23 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/strscan/strscan.c (strscan_aref): raise error if given
+ name reference is not found.
+
+Fri May 24 15:48:18 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (after_gc_sweep, garbage_collect_body): do major GC (full GC)
+ before extending heaps.
+ TODO: do major GC when there are many old (promoted) objects.
+
+ * gc.c (after_gc_sweep): remove TODO comments.
+
+Fri May 24 11:04:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (LIBRUBY_RPATHFLAGS): do not append -L option with
+ runtime library directory if cross compiling, but only -R option.
+ runtime path makes no sense on the host system. [ruby-dev:47363]
+ [Bug #8443]
+
+Fri May 24 02:57:17 2013 Koichi Sasada <ko1@atdot.net>
+
+ * object.c (rb_obj_clone): should not propagate OLDGEN status.
+ This propagation had caused WB miss for class.
+
+Thu May 23 17:35:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * load.c (loaded_feature_path): fix invalid read by index underflow.
+ the beginning of name is also a boundary as well as just after '/'.
+
+Thu May 23 17:21:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (gc_profile_dump_on): revert r40898. ok to show the record
+ accumulating while lazy_sweep().
+
+Wed May 22 16:50:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (gc_profile_dump_on): use size_t to get rid of overflow and
+ show the header when next_index > 0, instead of next_index != 1.
+
+Wed May 22 15:18:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (setup_overlapped): check the error code in addition
+ to the result of SetFilePointer() to determine if an error occurred,
+ because INVALID_SET_FILE_POINTER is a valid value.
+ [ruby-core:55098] [Bug #8431]
+
+ * win32/win32.c (setup_overlapped, finish_overlapped): extract from
+ rb_w32_read() and rb_w32_write().
+
+Wed May 22 14:19:56 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_prepare_free_objects, rest_sweep, lazy_sweep): fix position
+ of `during_gc' setting.
+
+Wed May 22 07:36:08 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (garbage_collect): all GC is start from garbage_collect()
+ (or garbage_collect_body()). `garbage_collect()' accept additional
+ two parameters `full_mark' and `immediate_sweep'.
+ If `full_mark' is TRUE, then force it full gc (major gc), otherwise,
+ it depends on status of object space. Now, it will be minor gc.
+ If `immediate_sweep' is TRUE, then disable lazy sweep.
+ To allocate free memory, `full_mark' and `immediate_sweep' should be
+ TRUE. Otherwise, they should be FALSE.
+
+ * gc.c (gc_prepare_free_objects): use `garbage_collect_body()'.
+
+ * gc.c (slot_sweep, before_gc_sweep, after_gc_sweep): add logging code.
+
+Tue May 21 22:47:06 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/strscan/strscan.c (strscan_aref): support named captures.
+ patched by Konstantin Haase [ruby-core:54664] [Feature #8343]
+
+Tue May 21 21:48:44 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/ruby/test_dir_m17n.rb (TestDir_M17N#test_entries_compose):
+ Use #each instead of #map just for iteration.
+
+Tue May 21 19:57:22 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest/lib/digest.rb (Digest::Class.file): Take optional
+ arguments that are passed to the constructor of the digest
+ class.
+
+Tue May 21 17:21:12 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: remove gc_profile_record::is_marked. always true.
+
+Tue May 21 17:13:40 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: fix to collect additional information for GC::Profiler.
+ * major/minor GC
+ * trigger reason of GC
+
+ * gc.c (gc_profile_dump_on): change reporting format with
+ added information.
+
+ * gc.c (gc_profile_record_get): return added information by
+ :GC_FLAGS => array.
+
+Tue May 21 16:45:31 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: GC::Profiler's sweeping time is accumulated all slot
+ sweeping time. At lazy GC, GC::Profiler makes new record entry
+ for each lazy_sweep(). In this change, accumulating all
+ slot_sweep() time.
+ And change indentation.
+
+Tue May 21 16:29:09 2013 Koichi Sasada <ko1@atdot.net>
+
+ * common.mk (rdoc-bench): add a benchmark rule
+ using RDoc. Generate all rdoc related files
+ (same as `make rdoc') in temporary directory
+ and remove them. Execution time, GC::Profiler
+ and results of GC.stat are printed.
+
+ * tool/rdocbench.rb: added for `rdoc-bench'.
+
+Tue May 21 16:25:05 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_profile_dump_on): `count' should be (int) because it
+ can be negative number.
+ And use pointer for `record' (don't copy).
+
+Tue May 21 03:11:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (dir_each): compose HFS file names from
+ UTF8-MAC. [ruby-core:48745] [Bug #7267]
+
+Tue May 21 03:08:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/ruby/envutil.rb (assert_separately): require envutil in the
+ child process too.
+
+Tue May 21 03:07:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_conv_enc_opts): should infect.
+
+Mon May 20 22:24:45 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb (Set#delete_if, Set#keep_if): Avoid blockless call of
+ proc, which is not portable to JRuby. Replace &method() with
+ faster and simpler literal blocks while at it.
+
+Mon May 20 22:00:31 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/e2mmap.rb: Format of E2MM documentation
+
+Mon May 20 21:41:15 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/extmk.rb: nodoc this file
+
+Mon May 20 20:43:32 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/cmath.rb: Remove duplicate RDoc heading from overview
+
+Mon May 20 20:36:19 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/securerandom.rb: Update position of overview for RDoc
+
+Mon May 20 19:33:55 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * math.c: improve and fix documentation of sin, tan and log
+
+Mon May 20 19:31:49 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * lib/logger.rb (Logger::Application): show namespace in documentation
+
+Mon May 20 11:50:12 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/pp.rb: Revert part of r40834 and nodoc PP::ObjectMixin
+ [ruby-core:55068]
+
+Mon May 20 10:40:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/webrick/htmlutils.rb (WEBrick::HTMLUtils#escape): replace HTML
+ meta chars even in non-ascii string. [Bug #8425] [ruby-core:55052]
+
+ * lib/webrick/httputils.rb (WEBrick::HTTPUtils#{_escape,_unescape}):
+ fix %-escape encodings. [Bug #8425] [ruby-core:55052]
+
+ * lib/webrick/httpservlet/filehandler.rb (set_dir_list): revert r20152
+ partially and fix misuse of bytesize and regexp repetition operator.
+
+Mon May 20 08:03:51 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/profiler.rb: Document Profiler__ methods
+
+Mon May 20 08:02:13 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/tempfile.rb: nodoc Tempfile#inspect
+
+Mon May 20 07:48:24 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/stringio/stringio.c: Correct position of method rdoc
+
+Mon May 20 07:27:41 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * math.c: RDoc formatting of Math core docs with domains and codomains
+ Patch by @eLobato [Fixes GH-309]
+
+Mon May 20 05:58:12 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/bigdecimal/bigdecimal.c: Formatting for BigMath [Fixes GH-306]
+ Based on a patch by @eLobato.
+ * ext/bigdecimal/lib/bigdecimal/math.rb: ditto
+
+Mon May 20 04:56:59 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/forwardable.rb: Forwardable examples in overview were broken
+ Based on patch by @joem [Fixes GH-303] [Bug #8392]
+
+Mon May 20 03:35:26 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/optparse.rb: nodoc OptionParser::Version and SPLAT_PROC
+
+Mon May 20 03:16:52 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/pp.rb: Document PP::ObjectMixin [Fixes GH-312]
+
+Sun May 19 23:52:22 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * test/webrick/test_htmlutils.rb: add test for WEBrick::HTMLUtils.
+
+Sun May 19 23:12:07 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * encoding.c: document fix, change default script encoding.
+ patched by @windwiny [Fixes GH-310]
+
+Sun May 19 17:29:07 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb (Set#delete_if, Set#keep_if): Add comments.
+
+Sun May 19 11:37:36 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * ext/fiddle/extconf.rb: ignore rc version of libffi to fix build failure.
+
+Sun May 19 10:38:50 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-electric.el (ruby-electric-delete-backward-char): Use
+ delete-char instead of delete-backward-char, which is an
+ interactive function.
+
+Sun May 19 03:59:29 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (str_scrub0): added for refactoring.
+
+Sun May 19 03:48:26 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/common.rb (URI.decode_www_form): scrub string if decoded
+ bytes are invalid for the encoding.
+
+Sun May 19 02:46:32 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb (Set#delete_if, Set#keep_if): Make Set#delete_if and
+ Set#keep_if more space and time efficient by avoiding to_a.
+
+Sun May 19 02:33:09 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-electric.el (ruby-electric-setup-keymap): Make
+ backquotes electric as well. It was listed in
+ ruby-electric-expand-delimiters-list but not activated.
+
+ * misc/ruby-electric.el (ruby-electric-delete-backward-char):
+ Introduce electric DEL that deletes what the previous electric
+ command has input.
+
+ * misc/ruby-electric.el (ruby-electric-matching-char): Make
+ electric quotes work again at the end of buffer.
+
+Sun May 19 01:39:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (setjmp-type): check if setjmpex() is really available.
+ workaround for i686-w64-mingw32 which declares it but lacks its
+ definition.
+
+ * include/ruby/defines.h: include setjmpex.h only if also setjmpex()
+ is available.
+
+Sat May 18 23:57:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (setjmp-type): use setjmpex() on w64-mingw32 to get rid
+ of -Wclobbered warnings.
+
+ * include/ruby/defines.h: include setjmpex.h here becase setjmp.h is
+ included from win32.h via intrin.h, winnt.h, and so on.
+
+Sat May 18 20:28:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/mkconstants.rb (INTEGER2NUM): Make less comparisons.
+
+Sat May 18 20:15:28 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (str_scrub_bang): add String#scrub!. [Feature #8414]
+
+Sat May 18 16:59:52 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/mkconstants.rb (INTEGER2NUM): Renamed from INTEGER2VALUE.
+
+Sat May 18 16:57:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/mkconstants.rb (INTEGER2VALUE): Suppress a warning:
+ comparison between signed and unsigned integer expressions
+
+Sat May 18 16:38:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_compile_each): forward anonymous and first keyword
+ rest argument one. [ruby-core:55033] [Bug #8416].
+
+Sat May 18 15:49:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_core.h (rb_vm_tag): move jmpbuf between tag and prev so ensure to
+ be accessible.
+
+Sat May 18 11:05:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enumerator.c (inspect_enumerator): use VALUE instead of mere char*
+ by using rb_sprintf() and rb_id2str().
+
+ * enumerator.c (append_method): extract from inspect_enumerator().
+
+Sat May 18 09:00:32 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/mkconstants.rb (INTEGER2VALUE): Use LONG2FIX if possible.
+
+Sat May 18 00:38:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/mkconstants.rb: Convert integer constants bigger than int
+ correctly.
+
+Fri May 17 22:02:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/ifaddr.c: Use unsigned LONG_LONG to represent flags
+ because SunOS 5.11 (OpenIndiana) defines ifa_flags as uint64_t.
+
+Fri May 17 21:47:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * cont.c: Typo in constant MAX_MACHINE_STACK_CACHE from '..MAHINE..'
+ patch by @schmurfy [Fixes GH-307]
+
+Fri May 17 19:18:24 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-electric.el (ruby-electric-matching-char): Do not put
+ a closing quote when the quote typed does not start a string, as
+ in $', ?\' or ?\".
+
+Fri May 17 18:06:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Consider error messages to find out version option of
+ C compiler.
+ The C compiler of Sun Studio C emits "Warning: Option -qversion
+ passed to ld, if ld is invoked, ignored otherwise" and exit
+ successfully.
+
+Fri May 17 17:34:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (rb_gc_guarded_ptr): unoptimize on other compilers than gcc and
+ msvc.
+
+Fri May 17 11:06:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval_intern.h (TH_PUSH_TAG): ensure jmpbuf to be accessible before
+ pushing tag to get rid of unaccessible tag by stack overflow.
+
+Thu May 16 17:15:32 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_eval.c (rb_catch_obj): add volatile to tag to prevent crash
+ experimentally.
+ http://www.rubyist.net/~akr/chkbuild/debian/ruby-trunk/log/20130515T133500Z.log.html.gz
+
+Thu May 16 16:19:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/Makefile.sub (verconf.in): no longer used.
+
+ * win32/Makefile.sub (config.status): fix typo.
+
+ * configure.in, template/verconf.h.in (RUBY_EXEC_PREFIX): fix for
+ default prefix.
+
+Thu May 16 13:12:27 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * template/verconf.h.in: generate verconf.h from the template and
+ rbconfig.rb.
+
+Thu May 16 05:47:18 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: fix syntax error.
+ Thanks @spastorino! [ruby-core:55011]
+
+Thu May 16 03:05:45 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_node_newnode): use newobj_of() instead of rb_newobj().
+
+Thu May 16 02:03:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/depend: Add a dependency for ifaddr.o.
+
+Thu May 16 01:44:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (verconf.h): $< cannot be used in explicit rules with
+ nmake.
+
+ * win32/Makefile.sub (CONFIG_H): create verconf.in instead of
+ verconf.h.
+
+Thu May 16 01:25:07 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: only emit warnings when
+ -w is enabled.
+
+Wed May 15 18:58:17 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (newobj): rename to `newobj_of' and accept additional
+ three parameters v1, v2, v3. newobj_of() do OBJSETUP() and
+ fill values with v1, v2, v3.
+
+ * gc.c (rb_data_object_alloc, rb_data_typed_object_alloc):
+ use newobj_of().
+
+Wed May 15 17:55:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_PLATFORM): move to config.h as needed by
+ version.c.
+
+Wed May 15 17:04:11 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: add an additional RGENGC_PROFILE mode (2).
+ Profiling result can be check by GC.stat.
+
+ * gc.c (type_name): separate from obj_type_name().
+
+Wed May 15 16:58:24 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: save configured load path values into verconf.in.
+
+ * common.mk (verconf.h): create from verconf.in with shvar_to_cpp.rb.
+
+ * tool/shvar_to_cpp.rb: turn shell variables into C macros.
+ [Bug #7959]
+
+ * loadpath.c: split load path staffs from version.c.
+
+ * dmyloadpath.c: miniruby has no builtin load paths, so verconf.h is
+ not needed.
+
+Wed May 15 03:56:09 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: adding backwards
+ compatible YAMLTree.new method
+
+Wed May 15 02:22:16 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych.rb: Adding Psych.safe_load for loading a user
+ defined, restricted subset of Ruby object types.
+ * ext/psych/lib/psych/class_loader.rb: A class loader for
+ encapsulating the logic for which objects are allowed to be
+ deserialized.
+ * ext/psych/lib/psych/deprecated.rb: Changes to use the class loader
+ * ext/psych/lib/psych/exception.rb: ditto
+ * ext/psych/lib/psych/json/stream.rb: ditto
+ * ext/psych/lib/psych/nodes/node.rb: ditto
+ * ext/psych/lib/psych/scalar_scanner.rb: ditto
+ * ext/psych/lib/psych/stream.rb: ditto
+ * ext/psych/lib/psych/streaming.rb: ditto
+ * ext/psych/lib/psych/visitors/json_tree.rb: ditto
+ * ext/psych/lib/psych/visitors/to_ruby.rb: ditto
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: ditto
+ * ext/psych/psych_to_ruby.c: ditto
+ * test/psych/helper.rb: ditto
+ * test/psych/test_safe_load.rb: tests for restricted subset.
+ * test/psych/test_scalar_scanner.rb: ditto
+ * test/psych/visitors/test_to_ruby.rb: ditto
+ * test/psych/visitors/test_yaml_tree.rb: ditto
+
+Wed May 15 02:06:35 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * test/psych/helper.rb: envutil is not available outside Ruby, so
+ port the functions from envutil to the test helper.
+
+ * test/psych/test_deprecated.rb: ditto
+
+ * test/psych/test_encoding.rb: ditto
+
+Wed May 15 00:42:54 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * signal.c: need to include unistd.h for write(2).
+ unistd.h is now included via ruby/defines.h, but should explicitly
+ include here. (suggested by kosaki)
+
+Tue May 14 23:43:05 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/.document: Add ifaddr.c.
+
+Tue May 14 23:24:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/extconf.rb: check for if_nametoindex() for
+ i686-w64-mingw32, and check for declarations of if_indextoname() and
+ if_nametoindex().
+
+ * ext/socket/ifaddr.c (ifaddr_ifindex): not-implement unless
+ if_nametoindex() is available.
+
+ * ext/socket/rubysocket.h: declare if_indextoname() and
+ if_nametoindex() if available but not declared.
+
+Tue May 14 19:58:17 2013 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * ext/dl/lib/dl/func.rb (DL::Function#call): check tainted when
+ $SAFE > 0.
+ * ext/fiddle/function.c (function_call): check tainted when $SAFE > 0.
+ * test/fiddle/test_func.rb (module Fiddle): add test for above.
+
+
+Tue May 14 14:51:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/win32.h (INTPTR_MAX, INTPTR_MIN, UINTPTR_MAX): split
+ from intptr_t and uintptr_t, since VC9 defines the latter only in
+ crtdefs.h.
+
+Tue May 14 12:21:28 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (NET_LUID): mingw may have NET_LUID and not defined
+ _IFDEF_.
+
+Tue May 14 03:33:17 2013 Koichi Sasada <ko1@atdot.net>
+
+ * string.c (rb_str_new_frozen): remove debug print.
+
+Tue May 14 03:22:51 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: enable to generate write barrier protected
+ arrays (T_ARRAY).
+
+Tue May 14 03:21:42 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: enable to generate write barrier protected
+ strings (T_STRING).
+
+Tue May 14 03:19:59 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: enable to generate write barrier protected
+ objects (T_OBJECT).
+
+Tue May 14 03:17:15 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: enable to generate write barrier protected
+ objects for numeric types (Float, Complex, Rational, Bignum).
+
+Tue May 14 03:10:59 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: enable RGENGC (USE_RGENGC)
+ but no type creates write protected (sunny) objects
+ (RGENGC_WB_PROTECTED_* == 0).
+
+Tue May 14 02:47:30 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: support RGENGC. [ruby-trunk - Feature #8339]
+ See this ticket about RGENGC.
+
+ * gc.c: Add several flags:
+ * RGENGC_DEBUG: if >0, then prints debug information.
+ * RGENGC_CHECK_MODE: if >0, add assertions.
+ * RGENGC_PROFILE: if >0, add profiling features.
+ check GC.stat and GC::Profiler.
+
+ * include/ruby/ruby.h: disable RGENGC by default (USE_RGENGC == 0).
+
+ * array.c: add write barriers for T_ARRAY and generate sunny objects.
+
+ * include/ruby/ruby.h (RARRAY_PTR_USE): added. Use this macro if
+ you want to access raw pointers. If you modify the contents which
+ pointer pointed, then you need to care write barrier.
+
+ * bignum.c, marshal.c, random.c: generate T_BIGNUM sunny objects.
+
+ * complex.c, include/ruby/ruby.h: add write barriers for T_COMPLEX
+ and generate sunny objects.
+
+ * rational.c (nurat_s_new_internal), include/ruby/ruby.h: add write
+ barriers for T_RATIONAL and generate sunny objects.
+
+ * internal.h: add write barriers for RBasic::klass.
+
+ * numeric.c (rb_float_new_in_heap): generate sunny T_FLOAT objects.
+
+ * object.c (rb_class_allocate_instance), range.c:
+ generate sunny T_OBJECT objects.
+
+ * string.c: add write barriers for T_STRING and generate sunny objects.
+
+ * variable.c: add write barriers for ivars.
+
+ * vm_insnhelper.c (vm_setivar): ditto.
+
+ * include/ruby/ruby.h, debug.c: use two flags
+ FL_WB_PROTECTED and FL_OLDGEN.
+
+ * node.h (NODE_FL_CREF_PUSHED_BY_EVAL, NODE_FL_CREF_OMOD_SHARED):
+ move flag bits.
+
+Tue May 14 01:54:48 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: remove rb_objspace_t::marked_num.
+ We can use `objspace_live_num()' instead of removed `marked_num'
+ if it is after `after_gc_sweep()' function call.
+
+ * gc.c (after_gc_sweep): use objspace_live_num() instead of removed
+ rb_objspace_t::marked_num.
+
+ * gc.c (gc_mark_ptr, gc_marks): remove rb_objspace_t::marked_num code.
+
+ * gc.c (gc_prepare_free_objects): do not call set_heaps_increment()
+ with checking objspace->heap.marked_num. At this point, we only
+ need to check availability of free-cell.
+
+ * gc.c (lazy_sweep): call after_gc_sweep() if there are no sweep_able entry.
+
+ * gc.c (rest_sweep, gc_prepare_free_objects): remove after_gc_sweep() call.
+
+Tue May 14 01:50:41 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: disable GC_PROFILE_MORE_DETAIL (fix last commit).
+
+ * gc.c (gc_prof_set_malloc_info): fix "objspace->heap.live_num" to
+ "objspace_live_num(objspace)". There is no such member variable.
+
+Tue May 14 01:25:55 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: refactoring GC::Profiler.
+
+ * gc.c (gc_prof_sweep_timer_start/stop): removed because
+ they doesn't support lazy sweep.
+
+ * gc.c (gc_prof_sweep_slot_timer_start/stop): added.
+ redefine `sweeping time' to accumulated time of all of
+ slot_sweep().
+
+ * gc.c (rb_objspace_t::profile::count): renamed to
+ rb_objspace_t::profile::next_index. `counter' seems ambiguous.
+ increment it when next record is acquired.
+
+Tue May 14 00:48:55 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: constify RRational::(num,den) and
+ RComplex::(real,imag).
+ Add macro to set these values:
+ * RRATIONAL_SET_NUM()
+ * RRATIONAL_SET_DEN()
+ * RCOMPLEX_SET_REAL()
+ * RCOMPLEX_SET_IMAG()
+ This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
+
+ TODO: API design. RRATIONAL_SET(rat,num,den) is enough?
+ TODO: Setting constify variable with cast has same issue of r40691.
+
+ * complex.c, rational.c: use above macros.
+
+Mon May 13 21:49:17 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: Check socketpair again.
+ It is required on Unix.
+
+Mon May 13 21:20:32 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (getipaddrs): use alternative interface name if
+ available, because if_nametoindex() requires them.
+
+Mon May 13 20:23:24 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c, include/ruby/win32.h (getipaddrs): [experimental]
+ emulate getipaddrs(3) on Unix.
+
+ * win32/Makefile.sub, configure.in (LIBS): need iphlpapi.lib for above
+ function.
+
+ * include/ruby/win32.h (socketpair): rb_w32_socketpair() doesn't
+ substitute for any function, so use non-prefixed name.
+
+ * ext/socket/extconf.rb (socketpair); follow above change.
+
+Mon May 13 20:11:06 2013 Koichi Sasada <ko1@atdot.net>
+
+ * iseq.c (prepare_iseq_build): remove additional line break.
+
+Mon May 13 19:29:54 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: constify RBasic::klass and add
+ RBASIC_CLASS(obj) macro which returns a class of `obj'.
+ This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
+
+ * object.c: add new function rb_obj_reveal().
+ This function reveal internal (hidden) object by rb_obj_hide().
+ Note that do not change class before and after hiding.
+ Only permitted example is:
+ klass = RBASIC_CLASS(obj);
+ rb_obj_hide(obj);
+ ....
+ rb_obj_reveal(obj, klass);
+
+ TODO: API design. rb_obj_reveal() should be replaced with others.
+
+ TODO: modify constified variables using cast may be harmful for
+ compiler's analysis and optimization.
+ Any idea to prohibit inserting RBasic::klass directly?
+ If rename RBasic::klass and force to use RBASIC_CLASS(obj),
+ then all codes such as `RBASIC(obj)->klass' will be
+ compilation error. Is it acceptable? (We have similar
+ experience at Ruby 1.9,
+ for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
+
+ * internal.h: add some macros.
+ * RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
+ object.
+ * RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
+ * RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
+ without write barrier (planned).
+ * RCLASS_SET_SUPER(a, b) set super class of a.
+
+ * array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
+ file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
+ parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
+ string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
+ Use above macros and functions to access RBasic::klass.
+
+ * ext/coverage/coverage.c, ext/readline/readline.c,
+ ext/socket/ancdata.c, ext/socket/init.c,
+ * ext/zlib/zlib.c: ditto.
+
+Mon May 13 18:44:14 2013 Koichi Sasada <ko1@atdot.net>
+
+ * *.c, parse.y, insns.def: use RARRAY_AREF/ASET macro
+ instead of using RARRAY_PTR().
+
+Mon May 13 16:53:53 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: add new utility macros to access
+ Array's element.
+ * RARRAY_AREF(a, i) returns i-th element of an array `a'
+ * RARRAY_ASET(a, i, v) set i-th element of `a' to `v'
+ This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
+
+Mon May 13 15:31:10 2013 Koichi Sasada <ko1@atdot.net>
+
+ * object.c (rb_obj_setup): added.
+
+ * include/ruby/ruby.h (OBJSETUP): use rb_obj_setup() instead of
+ a macro.
+
+Mon May 13 15:24:16 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_data_object_alloc): check klass only if klass is not 0.
+ klass==0 means internal object.
+
+Mon May 13 14:57:28 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_data_object_alloc, rb_data_typed_object_alloc):
+ use NEWOBJ_OF() instead of NEWOBJ().
+
+Mon May 13 14:51:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (rb_obj_singleton_method): new method Kernel#singleton_method
+ which returns a Method object of the singleton method.
+ non-singleton method causes NameError, but not aliased or zsuper
+ method, right now.
+ [ruby-core:54914] [Feature #8391]
+
+ * vm_method.c (rb_method_entry_at): return the method entry for id at
+ klass, without ancestors.
+
+ * class.c (rb_singleton_class_get): get the singleton class if exists,
+ or nil.
+
+Mon May 13 10:20:59 2013 Yuki Yugui Sonoda <yugui@google.com>
+
+ * ext/openssl/ossl_ssl.c: Disabled OpenSSL::SSL::SSLSocket if
+ defined(OPENSSL_NO_SOCK).
+
+ This fixes a linkage error on platforms which do not have socket.
+ OpenSSL itself is still useful as a set of cryptographic functions
+ even on such platforms.
+
+Mon May 13 10:30:04 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * hash.c: Hash[] and {} are not equivalent by @eam [Fixes GH-301]
+
+Mon May 13 10:04:22 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * random.c: Document Random::DEFAULT by @eLobato [Fixes GH-304]
+
+Sun May 12 21:12:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (OFFT2NUM): RUBY_REPLACE_TYPE also defines macro
+ to convert int type to VALUE if found.
+
+Wed May 8 13:46:52 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * include/ruby/intern.h (rb_iv_set, rb_iv_get): removed. Because
+ ruby.h has a declaration for that.
+
+Wed May 8 13:49:06 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * include/ruby/intern.h (rb_uint2big, rb_int2big, rb_uint2inum)
+ (rb_int2inum, rb_ll2inum, rb_ull2inum): removed because ruby.h
+ has a declaration for these.
+
+Sun May 12 17:52:23 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: removes 'ac_cv_func_fseeko=yes' form MinGW
+ specific definitions.
+
+Sun May 12 17:25:46 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * file.c (rb_file_s_truncate): use correct type. chsize takes
+ a long.
+
+Sun May 12 17:18:46 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * process.c: move '#define HAVE_SPAWNV 1' to win32/Makefile.sub.
+ * win32/Makefile.sub: see above.
+
+Sun May 12 17:13:32 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: removes AC_CHECK_FUNCS(setitimer) because it's
+ unused.
+
+Sun May 12 17:08:16 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: removes AC_CHECK_FUNCS(pause) because it's unused.
+
+Sun May 12 17:05:18 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * signal.c (rb_f_kill): fixes typo. s/HAS_KILLPG/HAVE_KILLPG/.
+
+Sun May 12 17:03:27 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: abort if gettimeofday doesn't exist.
+
+Sun May 12 16:31:27 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: adds RUBY_REPLACE_TYPE(off_t) for creating
+ NUM2OFFT.
+ * file.c (rb_file_truncate): use correct type. chsize() take
+ a long.
+ * include/ruby/ruby.h (NUM2OFFT): use a definition created by
+ a configure script by default.
+
+Sun May 12 16:03:41 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: removes AC_CHECK_FUNC(fseeko, fseeko64, ftello,
+ ftello64). They are not used from anywhere.
+
+ * win32/win32.c (fseeko): removes.
+ * win32/win32.c (rb_w32_ftello): removes.
+ * include/ruby/win32.h: removes declarations of rb_w32_ftello and
+ rb_w32_fseeko.
+ * win32/Makefile.sub: removes '#define HAVE_FTELLO 1'.
+
+Sun May 12 15:51:47 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: remove AC_CHECK_FUNC(close). It is not used from
+ anywhere.
+
+Sun May 12 15:50:45 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: adds comments for setjmp check.
+
+Sun May 12 15:38:09 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: move clock_gettime() check into regular place.
+
+Wed May 8 13:45:53 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: add getenv() declaration check.
+ * dln_find.c: add HAVE_DECL_GETENV test.
+
+Sun May 12 15:33:18 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: sorts AC_CHECK_FUNCS()s as alphabetical order.
+
+Wed May 8 13:41:57 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * bignum.c: remove redundant decl for big_lshift() big_rshift().
+
+Sun May 12 16:06:43 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/socket/rubysocket.h (rsock_inspect_sockaddr): as r40646
+ check HAVE_TYPE_STRUCT_SOCKADDR_DL.
+
+Sat May 11 23:01:58 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/socket/rubysocket.h (HAVE_TYPE_STRUCT_SOCKADDR_DL):
+ MSVC has struct sockaddr_dl, but its content is broken.
+ http://ruby-mswin.cloudapp.net/vc10-x64/ruby-trunk/log/20130511T103938Z.log.html.gz
+
+Sat May 11 22:07:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/rinda/test_rinda.rb: Socket.getifaddrs may returns an interface
+ which #addr method returns nil for venet0 in OpenVZ.
+
+Sat May 11 21:56:34 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/raddrinfo.c (rsock_inspect_sockaddr): Add casts to
+ suppress warnings.
+
+Sat May 11 17:28:51 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket: New method, Socket.getifaddrs, implemented.
+ [ruby-core:54777] [Feature #8368]
+
+Sat May 11 00:47:22 2013 Tanaka Akira <akr@fsij.org>
+
+ * gc.h (SET_MACHINE_STACK_END): Add !defined(_ILP32) to a defining
+ condition to avoid compilation error on x32.
+ https://sites.google.com/site/x32abi/
+
+Fri May 10 23:56:34 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_peek_variable_name): treat invalid global, class,
+ and instance variable names as mere strings rather than errors.
+ [ruby-core:54885] [Bug #8375]
+
+Fri May 10 20:22:40 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Move library checks into "Checks for libraries." part.
+
+Fri May 10 19:32:01 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Reformat arguments of AC_CHECK_HEADERS and
+ AC_CHECK_FUNCS to track modifications easily.
+
+Fri May 10 12:01:36 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Don't link librt if clock_gettime is available in
+ the main C library.
+ glibc 2.17 moves clock_* from librt to the main C library.
+ http://sourceware.org/ml/libc-announce/2012/msg00001.html
+
+Thu May 9 22:00:35 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/ancdata.c (bsock_sendmsg_internal): controls_num should
+ not be negative.
+
+Thu May 9 21:09:57 2013 Tanaka Akira <akr@fsij.org>
+
+ * file.c, ext/etc/etc.c, ext/socket/unixsocket.c,
+ ext/openssl/ossl.h, ext/openssl/openssl_missing.c: Use
+ HAVE_AGGREGATE_MEMBER instead of HAVE_ST_MEMBER.
+
+Thu May 9 20:43:41 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/ancdata.c (bsock_sendmsg_internal): Always set
+ controls_num to raise NotImplementedError appropriately.
+ (bsock_recvmsg_internal): Raise NotImplementedError if
+ :scm_rights=>true is given on platforms which don't have
+ 4.4BSD style control message.
+
+Thu May 9 12:06:07 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/rubysocket.h, ext/socket/unixsocket.c,
+ ext/socket/ancdata.c: Use HAVE_STRUCT_MSGHDR_MSG_CONTROL instead
+ of HAVE_ST_MSG_CONTROL.
+
+Thu May 9 11:30:02 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * string.c: Add call-seq alias for String#=== [Bug #8381]
+
+Thu May 9 11:14:18 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * doc/contributing.rdoc: Add guide for contributing to CRuby
+
+Thu May 9 04:55:49 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Check socket library again. shutdown() is used in
+ io.c.
+
+Thu May 9 01:52:31 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Don't check socketpair. socketpair is not used in
+ ruby command itself.
+
+Thu May 9 01:05:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (rb_mod_included_modules): should not include non-modules.
+ [ruby-core:53158] [Bug #8025]
+
+Wed May 8 22:46:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (rb_mod_included_modules): should not include the original
+ module itself. [ruby-core:53158] [Bug #8025]
+
+Wed May 8 17:43:55 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * io.c (rb_io_ext_int_to_encs): ignore internal encoding if external
+ encoding is ASCII-8BIT. [Bug #8342]
+
+Wed May 8 13:49:38 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/json/generator/generator.c (isArrayOrObject): cast char to
+ unsigned char. [Bug #8378]
+
+Wed May 8 13:46:10 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/json/generator/depend: fix dependencies [Bug #8379]
+
+ * ext/json/parser/depend: ditto.
+
+Wed May 8 13:07:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_yylex): fail if $, @, @@ are not followed by a valid
+ name character. [ruby-core:54846] [Bug #8375].
+
+Wed May 8 13:06:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (ISGRAPH): add missing macro.
+
+Wed May 8 06:42:56 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/socket/socket.c (socket_s_ip_address_list): fix wrongly filled
+ sin6_scope_id on KAME introduced by r40593 for OpenIndiana.
+ KAME uses fe80:<scope_id>::<interface id> for link-local address
+ internally.
+ Setting sin6_scope_id causes it leaked.
+ see also comments of sockaddr_obj().
+
+Tue May 7 22:12:34 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/readline/readline.c (insert_ignore_escape): Add a cast to
+ unsigned char * before dereference.
+ This suppress a warning on Cygwin.
+
+Tue May 7 12:15:24 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/ancdata.c (bsock_recvmsg_internal): Add a cast to
+ suppress warning.
+ Bionic defines socklen_t as int.
+ Bionic defines msg_controllen as unsigned int (__kernel_size_t)
+ instead of socklen_t as POSIX.
+
+Tue May 7 12:12:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/ancdata.c (ancillary_inspect): Don't call
+ anc_inspect_ipv6_pktinfo if !HAVE_TYPE_STRUCT_IN6_PKTINFO.
+ anc_inspect_ipv6_pktinfo is not defined in the case.
+
+Tue May 7 12:10:52 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/socket.c (socket_s_ip_address_list): Cast EXTRA_SPACE as
+ int. This suppress a warning.
+
+Tue May 7 12:09:29 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: Set close_fds false for Cygwin.
+ Cygwin doesn't support fd passing.
+ This enables socket extension library cross-compilable by default.
+
+Tue May 7 12:07:35 2013 Tanaka Akira <akr@fsij.org>
+
+ * pack.c (swap32): Don't redefine it if it is already defined.
+ Bionic defines it.
+ (swap64): Ditto.
+
+Mon May 6 20:50:37 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/socket.c (socket_s_ip_address_list): Fill sin6_scope_id
+ if getifaddrs() returns an IPv6 link local address which
+ sin6_scope_id is zero, such as on OpenIndiana SunOS 5.11.
+
+Sun May 5 18:56:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * insns.def (defined): use vm_search_superclass() like as normal super
+ call. based on a patch <https://gist.github.com/wanabe/5520026> by
+ wanabe.
+
+ * vm_insnhelper.c (vm_search_superclass): return error but not raise
+ exceptions.
+
+ * vm_insnhelper.c (vm_search_super_method): check the result of
+ vm_search_superclass and raise exceptions on error.
+
+Sun May 5 16:29:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * insns.def (defined): get method entry from the method top level
+ frame, not block frame. [ruby-core:54769] [Bug #8367]
+
+Sun May 5 13:28:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * template/ruby.pc.in (Cflags): use rubyarchhdrdir for multiarch.
+ [Bug #7874]
+
+Sat May 4 07:20:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * doc/security.rdoc: Add note about reporting security vulns
+
+Sat May 4 04:13:27 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * include/ruby/defines.h (RUBY_ATTR_ALLOC_SIZE): New for
+ attribute((alloc_size(params))).
+
+ * include/ruby/defines.h (xmalloc, xmalloc2, xcalloc)
+ (xrealloc, xrealloc2): Annotated by RUBY_ATTR_ALLOC_SIZE.
+ * include/ruby/ruby.h (rb_alloc_tmp_buffer): ditto.
+
+Fri May 3 19:32:13 2013 Takeyuki FUJIOKA <xibbar@ruby-lang.org>
+
+ * lib/cgi/util.rb: All class methods modulized.
+ We can use these methods like a function when "include CGI::Util".
+ [Feature #8354]
+
+Fri May 3 14:09:45 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: Make default_ipv6 true for Cygwin.
+ Cygwin supports IPv6 since Cygwin 1.7.1 (2009-12).
+ http://cygwin.com/ml/cygwin-announce/2009-12/msg00027.html
+
+Fri May 3 13:35:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/{getaddrinfo,getnameinfo}.c: define socklen_t if not
+ defined, e.g., older VC.
+
+Fri May 3 13:29:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/win32.h (INTPTR_MAX, INTPTR_MIN, UINTPTR_MAX): also
+ should be defined when defining intptr_t and uintptr_t.
+ bigdecimal.c requires the former two now.
+
+Fri May 3 13:22:12 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (poll_child_status): fix build error on older mingw.
+
+Fri May 3 00:15:58 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * common.mk: remove timestamps in distclean-ext realclean-ext.
+
+Thu May 2 23:23:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_obj_is_kind_of): skip prepending modules.
+ [ruby-core:54742] [Bug #8357]
+
+ * object.c (rb_class_inherited_p): ditto.
+ [ruby-core:54736] [Bug #8357]
+
+Thu May 2 22:11:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bin/irb: remove dead code from sample/irb.rb.
+
+Thu May 2 17:32:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (copy_ivar_i): get rid of overwriting already copied
+ instance variables. c.f. [Bug #8276]
+
+Thu May 2 16:55:43 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (id_locals): use cached ID.
+
+ * vm.c (ruby_thread_init): ditto.
+
+ * defs/id.def: add more predefined IDs used in core.
+
+Thu May 2 13:42:42 2013 Ryan Davis <ryand-ruby@zenspider.com>
+
+ * lib/minitest/*: Imported minitest 4.7.4 (r8483)
+ * test/minitest/*: ditto
+
+Thu May 2 11:32:22 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (poll_child_status): [experimental] set the cause of
+ a child's death to status if its exitcode seems to be an error.
+
+ * test/ruby/test_process.rb (TestProcess#test_no_curdir): maybe now
+ we can test it.
+
+ * test/ruby/test_thread.rb (TestThread#test_thread_timer_and_interrupt):
+ ditto.
+
+Thu May 2 11:24:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/yaml.rb: nodoc EngineManager, add History doc #8344
+
+Wed May 1 21:11:17 2013 Tanaka Akira <akr@fsij.org>
+
+ * time.c (localtime_with_gmtoff_zone): musl libc may return NULL for
+ tm_zone.
+
+Wed May 1 18:59:36 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * enum.c (Enumerable#chunk): fix grammar of error message
+ for symbols beginning with an underscore [Bug #8351]
+
+Wed May 1 16:47:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/curses/extconf.rb (curses_version): try once for each tests, a
+ function or a variable. fallback to variable for old SVR4.
+
+Wed May 1 16:17:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb (extmake): extensions not to be installed should not
+ make static libraries, but make dynamic libraries always.
+
+Wed May 1 12:20:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/rake/version.rb: Fix RDoc warning with :include: [Bug #8347]
+
+Wed May 1 11:40:25 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * defs/id.def (predefined): add "idProc".
+
+ * eval.c (frame_func_id): use predefined IDs.
+
+ * proc.c (mnew, mproc, mlambda): use predefined IDs.
+
+ * vm.c (rb_vm_control_frame_id_and_class): ditto.
+
+ * vm.c (Init_VM): ditto.
+
+Tue Apr 30 23:18:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/benchmark.rb: Update Benchmark results on newer CPU
+
+Tue Apr 30 12:31:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (mproc, mlambda): use frozen core methods instead of plain
+ global methods, so that methods cannot be overridden.
+ [ruby-core:54687] [Bug #8345]
+
+ * vm.c (Init_VM): define proc and lambda on the frozen core object.
+
+ * include/ruby/intern.h (rb_block_lambda): add declaration instead of
+ deprecated rb_f_lambda.
+
+Mon Apr 29 17:02:30 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/nkf/nkf-utf8/nkf.h: Bionic libc doesn't have locale.
+ [Feature #8338]
+
+
+Mon Apr 29 06:58:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/openssl/ossl_bn.c (ossl_bn_initialize): no need of alloca for
+ small fixed size array.
+
+ * ext/openssl/ossl_bn.c (ossl_bn_initialize): check overflow first,
+ and use alloca for small size input.
+
+Mon Apr 29 00:40:13 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * lib/yaml.rb: Clarify documentation about YAML being always Psych.
+ Give a tip about using Syck. See #8344.
+
+Sun Apr 28 23:34:01 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * lib/yaml.rb: Use another trick to define the YAML module.
+ https://twitter.com/n0kada/status/328342207511801856
+
+Sun Apr 28 23:19:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/pp.rb: Update PP module overview by @geopet
+
+Sun Apr 28 22:04:37 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * ext/openssl/ossl_bn.c (ossl_bn_initialize): fix buffer overflow on
+ x64 Windows and memory leak when initializing with integer.
+ [ruby-core:54615] [Bug #8337]
+
+Sun Apr 28 12:38:04 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * README.EXT: correct method name to be used. [Bug #7982]
+
+ * README.EXT.ja: add notes too.
+
+Sun Apr 28 10:35:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * object.c: With feedback from Steve Klabnik, reverted a change to
+ #untrusted? and #tainted?. Also adjusted grammar for $SAFE levels
+
+Sun Apr 28 10:10:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/yaml.rb: Disable setting YAML const twice [ruby-core:54642]
+
+Sun Apr 28 09:50:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * object.c: Documentation for taint and trust [Bug #8162]
+
+Sun Apr 28 09:40:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * README.EXT: Copy note from r40505 for rb_sprintf() [Bug #7982]
+
+Sun Apr 28 08:28:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/curses/curses.c: Update Curses::Window example for nicer output
+ Patch by Michal Suchanek [Bug #8121] [ruby-core:53520]
+
+Sun Apr 28 08:10:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * README.EXT: Update note from r40504, by Jeremy Evans [Bug #7982]
+
+Sun Apr 28 08:02:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * README.EXT: Add note to warn use of %i in Exceptions [Bug #7982]
+
+Sun Apr 28 02:41:05 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Fix a typo. Should check endgrent() instead of
+ endgrnam().
+
+Sun Apr 28 00:35:45 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c (obj2gid): Don't call endgrent() if not exist.
+ Bionic (Android's libc) don't have endgrent().
+
+ * configure.in: Check endgrnam function.
+
+Sat Apr 27 23:53:00 2013 Charlie Somerville <charlie@charliesomerville.com>
+
+ * lib/yaml.rb: add security warning to YAML documentation
+
+Sat Apr 27 23:25:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/yaml.rb: Documentation for YAML module [Bug #8213]
+
+Sat Apr 27 20:19:21 2013 Tanaka Akira <akr@fsij.org>
+
+ * thread_pthread.c (ruby_init_stack): Add STACK_GROW_DIR_DETECTION.
+ This fixes a compilation failure while cross-compiling for Tensilica
+ Xtensa Processor.
+
+Sat Apr 27 19:32:44 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * thread.c: fix typos and documentation
+
+Sat Apr 27 19:04:55 2013 Tanaka Akira <akr@fsij.org>
+
+ * sparc.c: Use __asm__ instead of asm for gcc.
+ gcc doesn't provide asm keyword if -ansi option is given.
+ http://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html
+
+Sat Apr 27 17:22:50 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: Redundant test removed.
+
+Sat Apr 27 16:00:10 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb (test_recvmsg_with_msg_peek_creates_fds):
+ Extracted.
+
+Sat Apr 27 15:50:40 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (SIGNED_INTEGER_TYPE_P): New macro.
+ (SIGNED_INTEGER_MAX): Ditto.
+ (SIGNED_INTEGER_MIN): Ditto.
+ (UNSIGNED_INTEGER_MAX): Ditto.
+ (TIMET_MAX): Use SIGNED_INTEGER_MAX and UNSIGNED_INTEGER_MAX.
+ (TIMET_MIN): Use SIGNED_INTEGER_MIN.
+
+ * thread.c (TIMEVAL_SEC_MAX): Use SIGNED_INTEGER_MAX.
+ (TIMEVAL_SEC_MIN): Use SIGNED_INTEGER_MIN.
+
+Sat Apr 27 10:52:52 2013 Tanaka Akira <akr@fsij.org>
+
+ * thread.c (TIMEVAL_SEC_MAX, TIMEVAL_SEC_MIN): Consider environments,
+ sizeof(time_t) is smaller than sizeof(tv_sec), such as
+ OpenBSD 5.2 (amd64).
+
+Fri Apr 26 23:34:59 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/text.rb (REXML::Text.normalize): Fix a bug that all
+ entity filters are ignored. [ruby-dev:47278] [Bug #8302]
+ Patch by Ippei Obayashi. Thanks!!!
+ * test/rexml/test_entity.rb (EntityTester#test_entity_filter): Add
+ a test of the above change.
+
+Fri Apr 26 22:53:55 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/element.rb (REXML::Attributes#to_a): Support
+ namespaced attributes. [ruby-dev:47277] [Bug #8301]
+ Patch by Ippei Obayashi. Thanks!!!
+ * test/rexml/test_attributes.rb
+ (AttributesTester#test_to_a_with_namespaces): Add a test of the
+ above change.
+
+Fri Apr 26 21:48:29 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rss/atom.rb (RSS::Atom::Entry): Fix indent of document comment.
+
+Fri Apr 26 21:21:17 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rss/maker.rb (RSS::Maker): Fix indent of document comment.
+
+Fri Apr 26 18:41:04 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: Use a block of enable_config() for
+ --{enable,disable}-close-fds-by-recvmsg-with-peek configure option
+
+Fri Apr 26 18:08:08 2013 Tanaka Akira <akr@fsij.org>
+
+ * dir.c (dir_set_pos): Fix a compilation error when seekdir() is not
+ exist.
+
+Fri Apr 26 17:41:17 2013 Tanaka Akira <akr@fsij.org>
+
+ * thread_pthread.c (ruby_init_stack): Add STACK_GROW_DIR_DETECTION.
+ This fixes a compilation failure while cross-compiling for ARM.
+
+Fri Apr 26 14:35:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/rss/atom.rb: Documentation for RSS::Atom based on a patch by
+ Michael Denomy
+ * lib/rss/maker.rb: Documentation for RSS::Maker also by @mdenomy
+
+Fri Apr 26 12:41:22 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/curses/extconf.rb: Test linkability of curses_version at first.
+
+ * ext/socket/extconf.rb: Test the behavior of fd passing with MSG_PEEK
+ only if recvmsg(), msg_control member, AF_UNIX and SCM_RIGHTS are
+ available.
+
+Fri Apr 26 00:07:52 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * lib/rinda/ring.rb (Rinda::RingServer#initialize): accept array
+ arguments of address to specify multicast interface.
+
+ * lib/rinda/ring.rb (Rinda::RingServer#make_socket): add optional
+ arguments for multicast interface.
+
+ * test/rinda/test_rinda.rb
+ (TestRingFinger#test_ring_server_ipv4_multicast,
+ TestRingFinger#test_ring_server_ipv6_multicast): add tests for
+ above change.
+
+ * test/rinda/test_rinda.rb
+ (TestRingServer#test_make_socket_ipv4_multicast,
+ TestRingServer#test_make_socket_ipv6_multicast): change bound
+ interface address because multicast address is not allowed on Linux
+ or Windows.
+ [ruby-core:53692] [Bug #8159]
+
+Thu Apr 25 23:45:02 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * lib/rinda/ring.rb (Rinda::RingServer#initialize): add a socket
+ to @sockets in make_socket() to close sockets on shutdown even if
+ make_socket() is called after initialize.
+
+ * lib/rinda/ring.rb (Rinda::RingServer#make_socket): ditto.
+
+Thu Apr 25 23:39:42 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * test/rinda/test_rinda.rb (TupleSpaceProxyTest#test_take_bug_8215):
+ use KILL on Windows since TERM doen't work and ruby process remains
+ after test-all on Windows.
+
+Thu Apr 25 23:16:28 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/curses/extconf.rb: Implement
+ --with-curses-version={function,variable} configure option for
+ cross-compiling.
+
+Thu Apr 25 18:15:46 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: Don't use WIDE getaddrinfo by default.
+
+Thu Apr 25 17:56:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: Remove obsolete options: ---with-ipv6-lib and
+ --with-ipv6-libdir.
+
+Thu Apr 25 17:43:49 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: Implement
+ --{enable,disable}-close-fds-by-recvmsg-with-peek configure option
+ for cross-compiling.
+ Make --{enable,disable}-wide-getaddrinfo configure option
+ cross-compiling friendly.
+
+Thu Apr 25 16:11:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (rb_io_ext_int_to_encs, parse_mode_enc): bom-prefixed name is
+ not a real encoding name, just a fallback. so the proper conversion
+ should take place even if if the internal encoding is equal to the
+ bom-prefixed name, unless actual encoding is equal to the internal
+ encoding. [ruby-core:54563] [Bug #8323]
+
+ * io.c (io_set_encoding_by_bom): reset extenal encoding if no BOM
+ found. [ruby-core:54569]
+
+Thu Apr 25 14:35:01 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/openssl/ossl_bn.c (ossl_bn_initialize): allow Fixnum and Bignum.
+ [ruby-core:53986] [Feature #8217]
+
+Thu Apr 25 14:26:32 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/common.rb (URI.decode_www_form): follow current URL Standard.
+ It gets encoding argument to specify the character encoding.
+ It now allows loose percent encoded strings, but denies ;-separator.
+ [ruby-core:53475] [Bug #8103]
+
+ * lib/uri/common.rb (URI.decode_www_form): follow current URL Standard.
+ It gets encoding argument to convert before percent encode.
+ Now UTF-16 strings aren't converted to UTF-8 before percent encode
+ by default.
+
+Wed Apr 25 14:26:00 2013 Charlie Somerville <charlie@charliesomerville.com>
+
+ * benchmark/bm_hash_shift.rb: add benchmark for Hash#shift
+
+ * hash.c (rb_hash_shift): use st_shift if hash is not being iterated to
+ delete element without iterating the whole hash.
+
+ * hash.c (shift_i): remove function
+
+ * include/ruby/st.h (st_shift): add st_shift function
+
+ * st.c (st_shift): ditto
+
+ [Bug #8312] [ruby-core:54524] Patch by funny-falcon
+
+Thu Apr 25 12:03:38 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: Extract C programs as toplevel constants.
+
+Thu Apr 25 02:23:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_RM_RECURSIVE): this hack is needed by only
+ autoconf 2.69 or earlier on darwin.
+
+Thu Apr 25 01:22:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/tracer.rb (get_line): simply read by File.readlines.
+
+ * lib/debug.rb (script_lines): get source lines from SCRIPT_LINES__ or
+ read from the file.
+
+ * lib/debug.rb (display_list): use script_lines instead of recursion.
+ [Bug #8318]
+
+ * lib/debug.rb (line_at): use script_lines same as display_list.
+
+ * lib/debug.rb (display_list): Fix debug listing when called from the
+ same file it has been required. patch by Dario Bertini <berdario AT
+ gmail.com> [Bug #8318] [fix GH-280]
+
+Wed Apr 24 21:51:13 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Check mblen().
+ mblen() is optional in uClibc.
+
+ * eval_intern.h (CharNext): Don't use mblen() is not available.
+
+Wed Apr 24 15:55:06 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * io.c (rb_fd_fix_cloexec): use rb_update_max_fd().
+
+Wed Apr 24 14:08:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * numeric.c: Fix wiki link on Float imprecision in overview, patched
+ by Makoto Kishimoto [Bug #8304] [ruby-dev:47280]
+
+Wed Apr 24 14:03:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_yylex): disallow $- without following identifier
+ character. [ruby-talk:406969]
+
+ * parse.y (is_special_global_name): mere $- is not a valid global
+ variable name.
+
+Wed Apr 24 13:54:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * string.c: Document String#setbyte return value by @gjmurakami-10gen
+ [Fixes GH-294]
+
+Wed Apr 24 13:45:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * class.c: Example of Object#methods by @windwiny [Fixes GH-293]
+ * ruby.c: Document return values of Kernel #sub, #gsub, and #chop
+
+Wed Apr 24 12:54:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/socket/lib/socket.rb: Doc typos by @vipulnsward [Fixes GH-292]
+
+
+Wed Apr 24 12:54:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/socket/lib/socket.rb: Doc typos by @vipulnsward [Fixes GH-292]
+
+Wed Apr 24 12:27:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * array.c: Fix documentation for Array#index and #replace aliases
+ Based on a patch by @phiggins [Fixes GH-282]
+
+Tue Apr 23 21:14:38 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (rb_str_inspect): refix r40413, on Ruby 1.9 usual character
+ escape uses hex/Unicode escapes, so fix to use Unicode escape on
+ Unicode strings and hex on others. [ruby-core:54458] [Bug #8290]
+
+Tue Apr 23 20:10:02 2013 Tanaka Akira <akr@fsij.org>
+
+ * missing/isnan.c (isnan): Don't define if isnan() macro is defined.
+ This fixes a compilation failure on uClibc based Gentoo system.
+
+Tue Apr 23 17:40:40 2013 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/rexml/document.rb, lib/rexml/element.rb,
+ lib/rexml/formatters/pretty.rb: remove opinionated
+ language in documentation. [Bug #8309],
+ reported by Charles Beckmann
+
+Tue Apr 23 14:04:44 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap.rb (getacl_response): parse the mailbox of an ACL
+ response correctly. [ruby-core:54365] [Bug #8281]
+
+Tue Apr 23 11:58:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_scrub): fix for UTF-32. strlen() on strings
+ contain NUL returns wrong result, use sizeof operator instead.
+ [ruby-dev:45975] [Feature #6752]
+
+Tue Apr 23 10:26:50 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * test/ruby/test_module.rb
+ (TestModule#test_const_get_invalid_name)
+ (test_const_defined_invalid_name): Fix expected values.
+
+Tue Apr 23 09:51:26 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * string.c (rb_str_inspect): NUL should not be represented as "\0"
+ when octal digits may follow. [ruby-core:54458] [Bug #8290]
+
+Mon Apr 22 22:54:00 2013 Charlie Somerville <charlie@charliesomerville.com>
+
+ * insns.def (opt_mod): Use % operator if both operands are positive for
+ a significant performance improvement. Thanks to @samsaffron.
+
+Mon Apr 22 17:09:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (r_object0): copy all instance variables not only generic
+ ivars, before calling post proc. [ruby-core:51163] [Bug #7627]
+
+Mon Apr 22 10:25:21 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * util.c (ruby_hdtoa): revert r29729.
+ If you want ruby to behave as before on x86, specify to use SSE like
+ -msse2 -mfpmath=sse for gcc.
+
+Sun Apr 21 23:19:00 2013 Charlie Somerville <charlie@charliesomerville.com>
+
+ * configure.in: Revert using sigsetjmp by default due to performance
+ problems on some systems (eg. older Linux)
+
+Sun Apr 21 21:35:00 2013 Charlie Somerville <charlie@charliesomerville.com>
+
+ * configure.in: Use sigsetjmp by default so jumping out of signal
+ handlers properly restores the signal mask and SS_ONSTACK flag.
+ [ruby-core:54175] [Bug #8254]
+
+ * configure.in: Manually check for presence of sigsetjmp. It is not a
+ function on some systems, so AC_CHECK_FUNCS cannot be used.
+
+Sun Apr 21 08:00:55 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/csv/test_features.rb, test/logger/test_logger.rb
+ test/mkmf/test_have_macro.rb, test/net/http/test_http.rb,
+ test/openssl/test_config.rb, test/psych/test_encoding.rb,
+ test/psych/test_exception.rb, test/psych/test_psych.rb,
+ test/psych/test_tainted.rb, test/readline/test_readline.rb,
+ test/rexml/test_contrib.rb, test/ruby/test_autoload.rb,
+ test/ruby/test_beginendblock.rb, test/ruby/test_exception.rb,
+ test/ruby/test_file.rb, test/ruby/test_io.rb,
+ test/ruby/test_marshal.rb, test/ruby/test_process.rb,
+ test/ruby/test_require.rb, test/ruby/test_rubyoptions.rb,
+ test/syslog/test_syslog_logger.rb, test/webrick/test_httpauth.rb,
+ test/zlib/test_zlib.rb: Use Tempfile.create.
+
+Sun Apr 21 00:15:36 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/tempfile.rb (Tempfile.create): Close when the block exits.
+
+Sat Apr 20 23:38:14 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/webrick/httpauth/htpasswd.rb: Use Tempfile.create to avoid
+ unintentional unlink() by the finalizer.
+ lib/webrick/httpauth/htdigest.rb: Ditto.
+
+Sat Apr 20 22:47:48 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/tempfile.rb (Tempfile.create): New method.
+ The method name is proposed by Shugo Maeda. [ruby-dev:47220]
+ [ruby-core:41478] [Feature #5707]
+
+Sat Apr 20 14:22:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (w_object): dump no ivars to the original by marshal_dump.
+ [ruby-core:54334] [Bug #8276]
+
+ * marshal.c (r_object0): copy all ivars of marshal_dump data to the
+ result object instead. [ruby-core:51163] [Bug #7627]
+
+Sat Apr 20 02:33:27 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (str_scrub): add ruby method String#scrub which verify and
+ fix invalid byte sequence. [ruby-dev:45975] [Feature #6752]
+
+ * string.c (str_compat_and_valid): check given string is compatible
+ and valid with given encoding.
+
+ * transcode.c (str_transcode0): If invalid: :replace is specified for
+ String#encode, replace invalid byte sequence even if the destination
+ encoding equals to the source encoding.
+
+Fri Apr 19 21:55:40 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * README.EXT.ja (Data_Wrap_Struct): Remove a description about
+ orphan argument. Oh, I renamed the argument name without
+ changing description at r36180... Sorry....
+ Patch by Makoto Kishimoto. Thanks!!! [ruby-dev:47269] [Bug #8292]
+ * README.EXT.ja (Data_Make_Struct): Add a sample code that describes
+ how it works.
+ Patch by Makoto Kishimoto. Thanks!!! [ruby-dev:47269] [Bug #8292]
+
+Fri Apr 19 17:54:57 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap.rb (body_type_msg): should accept
+ message/delivery-status with extra data.
+ [ruby-core:53741] [Bug #8167]
+
+ * test/net/imap/test_imap_response_parser.rb: related test.
+
+Fri Apr 19 13:03:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (w_object): do not dump encoding which is dumped with
+ marshal_dump data. [ruby-core:54334] [Bug #8276]
+
+Fri Apr 19 11:36:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (stack_protector): control use of -fstack-protector.
+
+ * configure.in (debugflags): let -fstack-protector precede and disable
+ debugflags, because they can't work together on SmartOS. [Bug #8268]
+
+Fri Apr 19 07:43:52 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * test/openssl/test_cipher.rb: Correct a typo
+ by jgls <joerg@joergleis.com>
+ https://github.com/ruby/ruby/pull/291 fix GH-291
+
+Thu Apr 18 16:58:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_method.c (rb_mod_public_method): fix visibility on anonymous
+ module. set visibility of singleton method, not method in base
+ class. [ruby-core:54404] [Bug #8284]
+
+Thu Apr 18 16:20:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (glob_helper): should skip dot directories only for recursion,
+ but should not if matching to the given pattern. [ruby-core:54387]
+ [Bug #8283]
+
+Thu Apr 18 16:20:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * pack.c (pack_unpack): increase buffer size to fix buffer overflow,
+ and fix garbage just after unpacking without missing paddings.
+ [Bug #8286]
+
+Thu Apr 18 13:35:54 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * pack.c (pack_unpack): output characters even if the input doesn't
+ have paddings. [Bug #8286]
+
+Thu Apr 18 08:20:48 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * common.mk (clean-ext): remove timestamps.
+
+Wed Apr 17 22:07:50 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/rubysocket.h (SOCKLEN_MAX): Expression simplified.
+
+Wed Apr 17 20:09:19 2013 Aman Gupta <ruby@tmm1.net>
+
+ * compile.c (iseq_add_mark_object): Use new rb_iseq_add_mark_object().
+
+ * insns.def (setinlinecache): Ditto.
+
+ * iseq.c (rb_iseq_add_mark_object): New function to allocate
+ iseq->mark_ary on demand. [Bug #8142]
+
+ * iseq.h (rb_iseq_add_mark_object): Ditto.
+
+ * iseq.c (prepare_iseq_build): Avoid allocating mark_ary until needed.
+
+ * iseq.c (rb_iseq_build_for_ruby2cext): Ditto.
+
+Wed Apr 17 20:00:18 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/rubysocket.h (SOCKLEN_MAX): Defined.
+
+ * ext/socket/raddrinfo.c (ext/socket/raddrinfo.c): Reject too long
+ Linux abstract socket name.
+
+Wed Apr 17 19:45:27 2013 Aman Gupta <tmm1@ruby-lang.org>
+
+ * iseq.c (iseq_location_setup): re-use existing string when iseq has
+ the same path and absolute_path. [Bug #8149]
+
+Wed Apr 17 11:38:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/test/unit/assertions.rb (Test::Unit::Assertions#assert):
+ UNASSIGNED is not a valid message.
+
+Wed Apr 17 10:58:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (sleep_timeval): get rid of overflow on Windows where
+ timeval.tv_sec is not time_t but mere long.
+
+Tue Apr 16 23:07:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/unixsocket.c (unix_send_io): Suppress a warning by clang.
+ (unix_recv_io): Ditto.
+
+Tue Apr 16 12:27:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/sdbm/init.c: Fix comment indentation, by windwiny [Fixes GH-277]
+
+Tue Apr 16 12:25:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/socket/option.c: Document synonymous methods, by windwiny [GH-277]
+ * ext/stringio/stringio.c: ditto
+ * ext/io/wait/wait.c: ditto
+ * ext/gdbm/gdbm.c: ditto
+ * ext/dl/cfunc.c: ditto
+ * ext/zlib/zlib.c: ditto
+ * ext/win32ole/win32ole.c: ditto
+ * ext/dbm/dbm.c: ditto
+ * ext/json/generator/generator.c: ditto
+ * ext/date/date_core.c: ditto
+
+Tue Apr 16 11:23:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/openssl/*: Document synonymous methods, by windwiny [GH-277]
+
+Mon Apr 15 22:21:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/fiddle/depend: New file.
+
+Mon Apr 15 22:01:02 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-electric.el (ruby-electric-insert): Check
+ ruby-electric-is-last-command-char-expandable-punct-p here.
+
+ * misc/ruby-electric.el (ruby-electric-closing-char): New
+ interactive function bound to closing characters. Typing one of
+ those closing characters right after the matching counterpart
+ cancels the effect of automatic closing. For example, typing
+ "{" followed by "}" simply makes "{}" instead of "{ } }".
+
+Mon Apr 15 12:54:42 2013 Martin Bosslet <Martin.Bosslet@gmail.com>
+
+ * ext/openssl/ossl_ssl.c: Correct shutdown behavior w.r.t GC.
+
+ * test/openssl/test_ssl.rb: Add tests to verify correct behavior.
+
+ [Bug #8240] Patch provided by Shugo Maeda. Thanks!
+
+Mon Apr 15 10:23:39 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/coverage/depend: fix id.h place as r40283.
+
+ * ext/coverage/extconf.rb: add topdir and topsrcdir to VPATH.
+
+Sun Apr 14 19:46:14 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/-test-/debug/depend: New file.
+
+ * ext/-test-/exception/depend: Ditto.
+
+ * ext/-test-/printf/depend: Ditto.
+
+ * ext/-test-/string/depend: Ditto.
+
+ * ext/coverage/depend: Ditto.
+
+ * ext/io/console/depend: Ditto.
+
+ * ext/io/nonblock/depend: Ditto.
+
+ * ext/io/wait/depend: Ditto.
+
+ * ext/openssl/depend: Ditto.
+
+ * ext/pathname/depend: Ditto.
+
+ * ext/psych/depend: Ditto.
+
+ * ext/zlib/depend: Ditto.
+
+Sun Apr 14 02:46:50 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/mkmf.rb (MakeMakefile#create_makefile): remove {$(VPATH)} other
+ than nmake.
+
+ * ext/ripper/depend: use VPATH expecting removed by above.
+
+Sat Apr 13 23:06:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (timestamp_file): gather timestamp files in one
+ directory from each extension directories.
+
+Sat Apr 13 21:09:02 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/mkmf.rb (MakeMakefile#create_makefile): output new macro
+ disthdrdir to specify the path of id.h, parse.h and etc.
+
+ * ext/ripper/depend: use above macro.
+
+Sat Apr 13 20:28:08 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * Merge Onigmo 5.13.4 f22cf2e566712cace60d17f84d63119d7c5764ee.
+ [bug] fix problem with optimization of \z (Issue #16) [Bug #8210]
+
+Sat Apr 13 18:56:15 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/ripper/depend: parse.h and id.h may be created on topdir.
+
+Sat Apr 13 12:08:16 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Add Vector#cross_product, patch by Luis Ezcurdia
+ [fix GH-276] [rubyspec:81eec89a124]
+
+Sat Apr 13 10:20:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * struct.c (rb_struct_define_without_accessor, rb_struct_define),
+ (rb_struct_s_def): hide member names array.
+
+ * struct.c (anonymous_struct, new_struct, setup_struct): split
+ make_struct() for each purpose.
+
+Sat Apr 13 09:34:31 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/mkmf.rb: Add ruby/ruby.h, ruby/missing.h, ruby/intern.h,
+ ruby/st.h and ruby/subst.h for ruby_headers in generated Makefile.
+
+ * ext/-test-/old_thread_select/depend: Update dependencies.
+
+ * ext/-test-/wait_for_single_fd/depend: Ditto.
+
+ * ext/bigdecimal/depend: Ditto.
+
+ * ext/curses/depend: Ditto.
+
+ * ext/digest/bubblebabble/depend: Ditto.
+
+ * ext/digest/depend: Ditto.
+
+ * ext/digest/md5/depend: Ditto.
+
+ * ext/digest/rmd160/depend: Ditto.
+
+ * ext/digest/sha1/depend: Ditto.
+
+ * ext/digest/sha2/depend: Ditto.
+
+ * ext/dl/callback/depend: Ditto.
+
+ * ext/dl/depend: Ditto.
+
+ * ext/etc/depend: Ditto.
+
+ * ext/nkf/depend: Ditto.
+
+ * ext/objspace/depend: Ditto.
+
+ * ext/pty/depend: Ditto.
+
+ * ext/readline/depend: Ditto.
+
+ * ext/ripper/depend: Ditto.
+
+ * ext/sdbm/depend: Ditto.
+
+ * ext/socket/depend: Ditto.
+
+ * ext/stringio/depend: Ditto.
+
+ * ext/strscan/depend: Ditto.
+
+ * ext/syslog/depend: Ditto.
+
+ * ext/-test-/num2int/depend: Removed.
+
+ * ext/dbm/depend: Ditto.
+
+ * ext/fcntl/depend: Ditto.
+
+ * ext/gdbm/depend: Ditto.
+
+ * ext/racc/cparse/depend: Ditto.
+
+Sat Apr 13 00:15:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/etc/etc.c (Init_etc): move Passwd and Group under Etc namespace
+ as primary names.
+
+Fri Apr 12 21:06:55 2013 Tanaka Akira <akr@fsij.org>
+
+ * common.mk: pack.o depends on internal.h.
+
+Fri Apr 12 20:59:24 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (ones): Use __builtin_popcountl if available.
+
+ * internal.h (GCC_VERSION_SINCE): Macro moved from pack.c.
+
+ * pack.c: Include internal.h for GCC_VERSION_SINCE.
+
+Fri Apr 12 18:29:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * common.mk: version.o depends on $(srcdir)/include/ruby/version.h
+ instead of {$(VPATH)}version.h to avoid confusion by VPATH between
+ top level version.h and include/ruby/version.h for build in-place.
+ [ruby-dev:47249] [Bug #8256]
+
+Fri Apr 12 15:21:24 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_callee_setup_keyword_arg): non-symbol key is not
+ a keyword argument, keep it as a positional argument.
+
+Fri Apr 12 11:58:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * array.c: Document synonymous methods, by windwiny [GH-277]
+ * bignum.c: ditto
+ * complex.c: ditto
+ * dir.c: ditto
+ * encoding.c: ditto
+ * enumerator.c: ditto
+ * numeric.c: ditto
+ * proc.c: ditto
+ * re.c: ditto
+ * string.c: ditto
+
+Thu Apr 11 23:41:46 2013 Tanaka Akira <akr@fsij.org>
+
+ * common.mk: Add dependencies for include/ruby.h
+
+ * tool/update-deps: Use "make -p all miniruby ruby golf" to extract
+ dependencies in makefiles.
+
+Thu Apr 11 23:21:17 2013 Tanaka Akira <akr@fsij.org>
+
+ * tool/update-deps: Use "make -p all golf" to extract dependencies in
+ makefiles.
+
+Thu Apr 11 21:02:19 2013 Tanaka Akira <akr@fsij.org>
+
+ * common.mk: Dependency updated.
+
+ * tool/update-deps: Rewritten.
+
+Thu Apr 11 19:59:48 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * common.mk: partially revert r40183, which breaks building on
+ other than source directory. (its commit log also says the same
+ thing, but such failure is not reproducible on my environment
+ and the commit breaks build on my environment)
+
+Thu Apr 11 16:10:01 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/fiddle/closure.c (USE_FFI_CLOSURE_ALLOC): define 0 on
+ Mac OS X and Linux [Bug #3371]
+
+Thu Apr 11 13:19:22 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/drb/drbtest.rb (Drb{Core,Ary}#teardown): retry Process.kill
+ if it fails with Errno::EPERM on Windows (workaround).
+ [ruby-dev:47245] [Bug #8251]
+
+Thu Apr 11 11:11:38 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * dir.c: Fix a typo.
+
+Thu Apr 11 10:39:34 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/fiddle/closure.c (USE_FFI_CLOSURE_ALLOC): add missing case:
+ RUBY_LIBFFI_MODVERSION is not defined (usually on Windows).
+
+Thu Apr 11 09:27:04 2013 Konstantin Haase <me@rkh.im>
+
+ * dir.c (file_s_fnmatch): Document File::FNM_EXTGLOB flag.
+
+Thu Apr 11 09:17:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * README: Fix typo by Benjamin Winkler [Fixes GH-281]
+
+Thu Apr 11 06:15:51 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * regint.h: fix typo: _M_AMD86 -> _M_AMD64.
+
+ * siphash.c: ditto.
+
+ * st.c: ditto.
+
+Thu Apr 11 06:09:57 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/fiddle/extconf.rb: define RUBY_LIBFFI_MODVERSION macro.
+
+ * ext/fiddle/closure.c (USE_FFI_CLOSURE_ALLOC): define 0 or 1
+ with platform and libffi's version. [Bug #3371]
+
+Thu Apr 11 05:30:43 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/mkmf.rb (pkg_config): Add optional argument "option".
+ If it is given, it returns the result of
+ `pkg-config --<option> <pkgname>`.
+
+Thu Apr 11 03:33:05 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/fiddle/closure.c (initialize): check mprotect's return value.
+ If mprotect is failed because of PaX or something, its function call
+ will cause SEGV.
+ http://c5664.rubyci.org/~chkbuild/ruby-trunk/log/20130401T210301Z.diff.html.gz
+
+Wed Apr 10 17:39:13 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/bigdecimal/bigdecimal.c (VpCtoV): Initialize a local variable
+ even when overflow.
+
+Wed Apr 10 12:32:37 2013 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_ll2big): Don't overflow on signed integer negation.
+
+ * ext/bigdecimal/bigdecimal.c (MUL_OVERFLOW_SIGNED_VALUE_P): New
+ macro.
+ (AddExponent): Don't overflow on signed integer multiplication.
+ (VpCtoV): Don't overflow on signed integer arithmetic.
+ (VpCtoV): Don't overflow on signed integer arithmetic.
+
+Wed Apr 10 06:32:12 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (MUL_OVERFLOW_INT_P): New macro.
+
+ * sprintf.c (GETNUM): Don't overflow on signed integer multiplication.
+
+Tue Apr 9 20:38:20 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (MUL_OVERFLOW_SIGNED_INTEGER_P): New macro.
+ (MUL_OVERFLOW_FIXNUM_P): Ditto.
+ (MUL_OVERFLOW_LONG_P): Ditto.
+
+ * array.c (rb_ary_product): Don't overflow on signed integer
+ multiplication.
+
+ * numeric.c (fix_mul): Ditto.
+ (int_pow): Ditto.
+
+ * rational.c (f_imul): Ditto.
+
+ * insns.def (opt_mult): Ditto.
+
+ * thread.c (sleep_timeval): Don't overflow on signed integer addition.
+
+ * bignum.c (rb_int2big): Don't overflow on signed integer negation.
+ (rb_big2ulong): Ditto.
+ (rb_big2long): Ditto.
+ (rb_big2ull): Ditto.
+ (rb_big2ll): Ditto.
+
+Tue Apr 9 19:45:44 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/open-uri.rb: Support multiple fields with same field
+ name (like Set-Cookie).
+ (OpenURI::Meta#metas): New accessor to obtain fields as a Hash from
+ field name (string) to field values (array of strings).
+ [ruby-core:37734] [Bug #4964] reported by ren li.
+
+Tue Apr 9 15:26:12 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_compile_each): append keyword hash to argument array
+ to splat if needed. [ruby-core:54094] [Bug #8236]
+
+Tue Apr 9 10:02:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (timestamp_file): gather timestamp files in one
+ directory from each extension directories, with considering
+ target_prefix.
+
+Tue Apr 9 04:57:59 JST 2013 Charles Oliver Nutter <headius@headius.com>
+
+ * error.c: Capture EAGAIN, EWOULDBLOCK, EINPROGRESS exceptions and
+ export them for use in WaitReadable/Writable exceptions.
+ * io.c: Create versions of EAGAIN, EWOULDBLOCK, EINPROGRESS that
+ include WaitReadable and WaitWritable. Add rb_readwrite_sys_fail
+ for nonblocking failures using those exceptions. Use that
+ function in io_getpartial and io_write_nonblock instead of
+ rb_mod_sys_fail
+ * ext/openssl/ossl_ssl.c: Add new SSLError subclasses that include
+ WaitReadable and WaitWritable. Use those classes for
+ write_would_block and read_would_block instead of rb_mod_sys_fail.
+ * ext/socket/ancdata.c: Use rb_readwrite_sys_fail instead of
+ rb_mod_sys_fail in bsock_sendmsg_internal and
+ bsock_recvmsg_internal.
+ * ext/socket/init.c: Use rb_readwrite_sys_fail instead of
+ rb_mod_sys_fail in rsock_s_recvfrom_nonblock and
+ rsock_s_connect_nonblock.
+ * ext/socket/socket.c: Use rb_readwrite_sys_fail instead of
+ rb_mod_sys_fail in sock_connect_nonblock.
+ * include/ruby/ruby.h: Export rb_readwrite_sys_fail for use instead
+ of rb_mod_sys_fail. Introduce new constants RB_IO_WAIT_READABLE and
+ RB_IO_WAIT_WRITABLE for first arg to rb_readwrite_sys_fail.
+
+Tue Apr 9 02:44:32 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/extconf.rb: $defs needs -D or -U. nothing is added
+ otherwize.
+
+ * ext/socket/extconf.rb: check struct in_addr6, which is defined in
+ VC6 instead of in6_addr.
+
+ * ext/socket/option.c (optname_to_sym): fix macro name.
+
+ * ext/socket/constants.c (rsock_cmsg_type_arg): fix macro name.
+
+Mon Apr 8 23:57:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (id_for_setter): extract common code from const, class
+ variable, instance variable setters.
+
+Mon Apr 8 23:55:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/depend (ENCOBJS, TRANSOBJS): use explicit path to ruby.h for
+ nmake.
+
+ * ext/depend (ENCOBJS, TRANSOBJS): fix header dependency, VPATH has
+ $(srcdir)/include/ruby but not $(srcdir)/include, so cannot find out
+ ruby/ruby.h. use ruby.h instead and ../ruby for include/ruby.h.
+
+Mon Apr 8 20:30:37 2013 Yuki Yugui Sonoda <yugui@google.com>
+
+ * ext/depend (ENCOBJS, TRANSOBJS): Add missing dependencies.
+
+Mon Apr 8 17:19:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32ole/win32ole.c (fole_missing): should check actual argument
+ count before accessing.
+
+Mon Apr 8 16:03:55 2013 Yuki Yugui Sonoda <yugui@google.com>
+
+ Fixes a build failure of ext/ripper/ripper.c on building out of place.
+ * common.mk (id.h, id.c): Always generated in $(srcdir).
+ (ext/ripper/ripper.c): Passes $(PATH_SEPARATOR) too to the sub make.
+
+Mon Apr 8 12:05:02 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * object.c (rb_obj_ivar_set): call to_str for string only once.
+ to_str was called from rb_is_const_name and rb_to_id before.
+
+ * object.c (rb_mod_const_set): ditto.
+
+ * object.c (rb_mod_cvar_set): ditto.
+
+Sun Apr 7 13:56:16 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * test/ruby/test_require.rb (TestRequire#test_require_nonascii_path):
+ RUBY_PLATFORM should escape as Regexp,
+ because RUBY_PLATFORM may contain '.'.
+
+Sun Apr 7 10:44:01 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/defines.h: Simplify the logic to include sys/select.h.
+ This fixes a compilation error on Haiku (gcc2 and gcc4).
+
+ * configure.in: Use shared linker as $(CC) for Haiku.
+ This fixes a build error on Haiku (gcc2).
+
+Sun Apr 7 10:41:30 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb (MDNSOneShot#sender): Delete an unused variable.
+
+Sun Apr 7 03:24:36 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c: use more generic type:
+ * u_char -> unsigned char
+ * u_short -> unsigned short
+ * u_int -> unsigned int
+ * u_long -> unsigned long
+ * quad_t -> int64_t
+ * u_quad_t -> uint64_t
+
+ * addr2line.c (imax): inline is defined by configure.
+
+Sun Apr 7 01:40:39 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-electric.el (ruby-electric-hash): New electric
+ function that expands a hash sign inside a string or regexp to
+ "#{}".
+
+ * misc/ruby-electric.el (ruby-electric-curlies): Do not insert
+ spaces inside when the curly brace is a delimiter of %r, %w,
+ etc.
+
+ * misc/ruby-electric.el (ruby-electric-curlies): Insert another
+ space before a closing curly brace when
+ ruby-electric-newline-before-closing-bracket is nil.
+
+Sun Apr 7 01:01:26 2013 Tanaka Akira <akr@fsij.org>
+
+ * strftime.c (rb_strftime_with_timespec): Test yday range.
+ [ruby-core:44088] [Bug #6247] reported by Ruby Submit.
+
+Sat Apr 6 23:46:54 2013 Naohisa Goto <ngotogenome@gmail.com>
+
+ * configure.in (AC_CHECK_HEADERS): atomic.h for Solaris atomic_ops.
+
+ * ruby_atomic.h: Skip using Solaris10 atomic_ops on Solaris 9 or
+ earlier if atomic.h is not available. [ruby-dev:47229] [Bug #8228]
+
+Sat Apr 6 23:40:40 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb: Support LOC resources.
+ [ruby-core:23361] [Feature #1436] by JB Smith.
+
+Sat Apr 6 23:38:09 2013 Naohisa Goto <ngotogenome@gmail.com>
+
+ * addr2line.c: quad_t and u_quad_t is not available on Solaris.
+ __inline is not available with old compilers on Solaris.
+ [ruby-dev:47229] [Bug #8227]
+
+Sat Apr 6 23:31:38 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb: Add one-shot multicast DNS support.
+ [ruby-core:53387] [Feature #8089] by Eric Hodel.
+
+Sat Apr 6 22:12:01 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb (Resolv::DNS.fetch_resource): New method to obtain
+ full result.
+ [ruby-dev:43587] [Feature #4788] proposed by Makoto Kishimoto.
+
+Sat Apr 6 20:17:51 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/socket.c (rsock_sys_fail_raddrinfo): Renamed from
+ rsock_sys_fail_addrinfo.
+ (rsock_sys_fail_raddrinfo_or_sockaddr): Renamed from
+ rsock_sys_fail_addrinfo_or_sockaddr.
+
+ * ext/socket/rubysocket.h: Follow the above change.
+
+Sat Apr 6 19:24:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/socket.c (rsock_sys_fail_sockaddr): Takes struct sockaddr
+ and socklen_t instead of String object.
+ (rsock_sys_fail_addrinfo_or_sockaddr): Follow the above change.
+
+ * ext/socket/rubysocket.h (rsock_sys_fail_sockaddr): Follow the above
+ change.
+
+Sat Apr 6 14:28:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/rubysocket.h (SockAddrStringValueWithAddrinfo): New macro.
+ (rsock_sockaddr_string_value_with_addrinfo): New declaration.
+ (rsock_addrinfo_inspect_sockaddr): Ditto.
+ (rsock_sys_fail_addrinfo): Ditto.
+ (rsock_sys_fail_sockaddr_or_addrinfo): Ditto.
+
+ * ext/socket/raddrinfo.c (rsock_addrinfo_inspect_sockaddr): Renamed
+ from addrinfo_inspect_sockaddr and exported.
+ (rsock_sockaddr_string_value_with_addrinfo): New function to obtain
+ string and possibly addrinfo object.
+
+ * ext/socket/socket.c (rsock_sys_fail_sockaddr): Don't use
+ rsock_sys_fail_host_port which is IP dependent. Invoke
+ rsock_sys_fail_addrinfo.
+ (rsock_sys_fail_addrinfo): New function using
+ rsock_addrinfo_inspect_sockaddr.
+ (rsock_sys_fail_addrinfo_or_sockaddr): New function.
+ (sock_connect): Use SockAddrStringValueWithAddrinfo and
+ rsock_sys_fail_addrinfo_or_sockaddr.
+ (sock_connect_nonblock): Ditto.
+ (sock_bind): Ditto.
+
+Sat Apr 6 13:34:20 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/socket.c (rsock_sys_fail_sockaddr): Delete 2nd argument.
+
+ * ext/socket/rubysocket.h (rsock_sys_fail_sockaddr): Follow above
+ change.
+
+Sat Apr 6 13:13:39 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/socket.c (rsock_sys_fail_path): Use rb_str_inspect only
+ for String to avoid SEGV.
+
+Sat Apr 6 12:40:16 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/rubysocket.h (rsock_sys_fail_host_port): Wrap by NORETURN.
+ (rsock_sys_fail_path): Ditto.
+ (rsock_sys_fail_sockaddr): Ditto.
+
+Sat Apr 6 11:49:35 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/socket.c (rsock_sys_fail_path): Use rb_str_inspect if the
+ path contains a NUL.
+
+Sat Apr 6 11:39:19 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket: Improve socket exception message to show socket address.
+ [ruby-core:45617] [Feature #6583] proposed Eric Hodel.
+
+ * ext/socket/rubysocket.h (rsock_sys_fail_host_port): Declared.
+ (rsock_sys_fail_path): Ditto.
+ (rsock_sys_fail_sockaddr): Ditto.
+
+ * ext/socket/udpsocket.c (udp_connect): Use rsock_sys_fail_host_port.
+ (udp_bind): Ditto.
+ (udp_send): Ditto.
+
+ * ext/socket/init.c (rsock_init_sock): Specify a string for rb_sys_fail
+ argument.
+ (make_fd_nonblock): Ditto.
+ (rsock_s_accept): Ditto.
+
+ * ext/socket/ipsocket.c (init_inetsock_internal): Use
+ rsock_sys_fail_host_port.
+
+ * ext/socket/socket.c (rsock_sys_fail_host_port): Defined.
+ (rsock_sys_fail_path): Ditto.
+ (rsock_sys_fail_sockaddr): Ditto.
+ (setup_domain_and_type): Use rsock_sys_fail_sockaddr.
+ (sock_connect_nonblock): Ditto.
+ (sock_bind): Ditto.
+ (sock_gethostname): Specify a string for rb_sys_fail argument.
+ (socket_s_ip_address_list): Ditto.
+
+ * ext/socket/basicsocket.c (bsock_shutdown): Specify a string for
+ rb_sys_fail argument.
+ (bsock_setsockopt): Use rsock_sys_fail_path.
+ (bsock_getsockopt): Ditto.
+ (bsock_getpeereid): Refine the argument for rb_sys_fail.
+
+ * ext/socket/unixsocket.c (rsock_init_unixsock): Use
+ rsock_sys_fail_path.
+ (unix_path): Ditto.
+ (unix_send_io): Ditto.
+ (unix_recv_io): Ditto.
+ (unix_addr): Ditto.
+ (unix_peeraddr): Ditto.
+
+Sat Apr 6 11:23:18 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * test/ruby/test_require.rb (TestRequire#test_require_nonascii_path):
+ fix load path for encoding to run the test as stand-alone.
+
+Sat Apr 6 09:54:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * pack.c (NATINT_LEN): fix definition order, must be after
+ NATINT_PACK.
+
+Sat Apr 6 03:11:07 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: fix symbol keys in coder
+ emission. Thanks @tjwallace
+ * test/psych/test_coder.rb: test for change
+
+Sat Apr 6 02:54:08 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/exception.rb: there should be only one exception
+ base class. Fixes tenderlove/psych #125
+ * ext/psych/lib/psych.rb: require the correct exception class
+ * ext/psych/lib/psych/syntax_error.rb: ditto
+ * ext/psych/lib/psych/visitors/to_ruby.rb: ditto
+
+Sat Apr 6 02:30:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (new_defined): remove all extra parentheses, and return
+ "nil" for defined? with empty expression.
+ [ruby-core:54024] [Bug #8224]
+
+Sat Apr 6 02:06:04 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/to_ruby.rb: correctly register
+ self-referential strings. Fixes tenderlove/psych #135
+
+ * test/psych/test_string.rb: appropriate test.
+
+Sat Apr 6 01:21:56 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/init.c (cloexec_accept): Fix a compile error on
+ Debian GNU/kFreeBSD. Consider HAVE_ACCEPT4 is defined
+ but SOCK_CLOEXEC is not defined.
+
+Sat Apr 6 00:19:30 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * load.c (features_index_add): use rb_str_subseq() to specify C string
+ position properly to fix require non ascii path.
+ [ruby-core:53733] [Bug #8165]
+
+ * test/ruby/test_require.rb (TestRequire#test_require_nonascii_path):
+ a test for the above.
+
+Fri Apr 5 20:41:49 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/defines.h (HAVE_TRUE_LONG_LONG): Defined to distinguish
+ availability of long long and availability of 64bit integer type.
+
+ * pack.c: Use HAVE_TRUE_LONG_LONG to distinguish q! and Q! support.
+
+Fri Apr 5 20:19:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * addr2line.c: Include ruby/missing.h to fix compile error on Debian.
+
+Fri Apr 5 19:39:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_compile_each): fix of defined? with empty
+ expression. [ruby-core:53999] [Bug #8220]
+
+Fri Apr 5 13:22:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/curses/curses.c (Init_curses): fix implementation function,
+ crmode should be same as cbreak. [ruby-core:54013] [Bug #8222]
+
+Fri Apr 5 12:06:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/curses/hello.rb: Typo in Curses example by Drew Blas
+ [Fixes GH-273]
+
+Thu Apr 4 23:45:13 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb (bind_random_port): Rescue EACCES for SunOS.
+ bind() on SunOS for port 2049 (nfs) and 4045 (lockd) causes
+ EACCES with unprivileged process. cf. PRIV_SYS_NFS in privileges(5)
+ [ruby-core:48064] [Bug #7183] reported by Frank Meier.
+
+Thu Apr 4 23:24:45 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: Remove condition for bcc.
+
+Thu Apr 4 22:53:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/ruby.h (FIX2LONG): Parenthesize the macro body.
+
+Thu Apr 4 22:32:32 2013 Tanaka Akira <akr@fsij.org>
+
+ * time.c (time_strftime): Describe %L and %N truncates digits under
+ the specified length.
+ [ruby-core:52130] [Bug #7829]
+
+Thu Apr 4 22:08:46 2013 Tanaka Akira <akr@fsij.org>
+
+ * object.c (rb_mod_cvar_set): Reverted "avoid inadvertent
+ symbol creation" to avoid SEGV by
+ Class.new.class_variable_set(1, 2).
+
+Thu Apr 4 20:07:19 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/pathname/pathname.c (path_write): New method.
+ (path_binwrite): Ditto.
+ [ruby-core:49468] [Feature #7378]
+
+Thu Apr 4 16:51:29 2013 Yuki Yugui Sonoda <yugui@google.com>
+
+ * thread_pthread.c: Fixes wrong scopes of #if USE_SLEEPY_TIMER_THREAD
+ .. #endif sections. This fixes a build error on NativeClient.
+
+Wed Apr 3 17:25:31 2013 Yuki Yugui Sonoda <yugui@google.com>
+
+ * thread_pthread.c (ruby_init_stack): Avoid using uninitialized value.
+ stackaddr and size are not set if get_stack() fails.
+
+Thu Apr 4 16:55:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * struct.c (make_struct): avoid inadvertent symbol creation.
+ (rb_struct_aref): ditto.
+ (rb_struct_aset): ditto.
+
+Thu Apr 4 16:54:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_mod_const_set): avoid inadvertent symbol creation.
+ (rb_obj_ivar_set): ditto.
+ (rb_mod_cvar_set): ditto.
+
+Thu Apr 4 15:46:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enum.c (enum_inject): avoid inadvertent symbol creation.
+
+Thu Apr 4 14:37:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (rb_thread_aref): avoid inadvertent symbol creation.
+ (rb_thread_variable_get): ditto.
+ (rb_thread_key_p): ditto.
+ (rb_thread_variable_p): ditto.
+
+Thu Apr 4 11:33:57 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/openssl/ossl_bn.c (ossl_bn_to_i): Use bn2hex to speed up.
+ In general, binary to/from decimal needs extra cost.
+
+Thu Apr 4 07:24:18 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: Specify arguments to test functions.
+
+Thu Apr 4 03:25:09 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/openssl/ossl_bn.c (ossl_bn_initialize): fix can't create from bn.
+
+Wed Apr 3 22:09:25 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: Test functions and libraries after headers.
+
+Wed Apr 3 21:23:29 2013 Tanaka Akira <akr@fsij.org>
+
+ * io.c (rb_io_seek_m): Accept :CUR, :END, :SET as "whence" argument.
+ (interpret_seek_whence): New function.
+ [ruby-dev:45818] [Feature #6643]
+
+Wed Apr 3 20:52:49 2013 Tanaka Akira <akr@fsij.org>
+
+ * process.c: Describe the behavior which Ruby invokes a commandline
+ directly without shell if the commandline is simple enough.
+ [ruby-core:50459] [Bug #7489]
+
+Wed Apr 3 20:27:37 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/extmk.rb (extmake): Invoke Logging::log_close in a ensure
+ clause.
+
+Wed Apr 3 18:53:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/extmk.rb (extmake): Use Logging.open to switch stdout and
+ stderr. Delay Logging::log_close until the failure message is
+ written. Write the failure message only if log file is opened.
+
+ * lib/mkmf.rb (Logging.log_opened?): New method.
+
+ [ruby-dev:47215] [Bug #8209]
+
+Wed Apr 3 17:11:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (constat_apply): pass through unknown sequence which
+ starts with ESC but is not followed by a bracket. [ruby-core:53879]
+ [Bug #8201]
+
+Wed Apr 3 16:35:32 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_big_eq): hide intermediate Bignums not just freeing
+ memory. [ruby-core:53893] [Bug #8204]
+
+ * object.c (rb_obj_hide): hide an object by clearing klass.
+
+ * bignum.c (rb_big_eq): test as Fixnum if possible and get rid of zero
+ length Bignum. [ruby-core:53893] [Bug #8204]
+
+Tue Apr 2 23:56:03 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/securerandom.rb (SecureRandom.random_bytes): Use
+ OpenSSL::Random.random_add instead of OpenSSL::Random.seed and
+ specify 0.0 as the entropy.
+ [ruby-core:47308] [Bug #6928]
+
+Tue Apr 2 20:24:52 2013 Tanaka Akira <akr@fsij.org>
+
+ * pack.c: Support Q! and q! for long long.
+ (natstr): Moved to toplevel. Add q and Q if there is long long type.
+ (endstr): Moved to toplevel.
+ (NATINT_PACK): Consider long long.
+ (NATINT_LEN_Q): New macro.
+ (pack_pack): Support Q! and q!.
+ (pack_unpack): Ditto.
+ [ruby-dev:43970] [Feature #3946]
+
+Tue Apr 2 19:24:26 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/-test-/num2int/num2int.c: Define utility methods
+ as module methods of Num2int.
+
+ * test/-ext-/num2int/test_num2int.rb: Follow the above change.
+
+Tue Apr 2 18:49:01 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/securerandom.rb: Don't use Array#to_s.
+ [ruby-core:52058] [Bug #7811] fixed by zzak (Zachary Scott).
+
+Tue Apr 2 17:38:20 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * re.c (rb_reg_to_s): suppress duplicated charclass warning.
+ Regexp#to_s suppress extra its whole regexp options by calling
+ onig_new with its source, but it doesn't call rb_reg_preprocess.
+ Therefore its Unicode escapes (\u{XXXX}) are given as is,
+ and it may cause duplicated charclass warning for example
+ "[\u{33}]" (3 is duplicated) or "[\u{a}\u{b}]" (u is duplicated).
+ [ruby-core:53649] [Bug #8151]
+
+Tue Apr 2 16:00:06 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_dump.c (rb_print_backtrace): separate to ease showing C backtrace.
+
+ * internal.h (rb_print_backtrace): ditto.
+
+Tue Apr 2 15:22:09 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * test/ruby/envutil.rb (assert_separately): stop_auto_run of
+ Test::Unit::Runner to prevent auto runner use ARGV.
+
+ * test/ruby/envutil.rb (assert_separately): add $: to separate process.
+
+ * test/ruby/envutil.rb (assert_separately): fail if stderr is not
+ empty and ignore_stderr is false.
+
+Tue Apr 2 06:46:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/-test-/num2int/num2int.c: Rename utility methods
+ to global functions to ease manual experiments.
+
+ * test/-ext-/num2int/test_num2int.rb: Follow the above change.
+
+Mon Apr 1 22:26:17 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/zlib/zlib.c (rb_gzfile_set_mtime): Use NUM2UINT.
+ The old logic doesn't work well on LP64 platforms as:
+ .. -2**63-1 => error,
+ -2**63 .. -2**62-1 => success,
+ -2**62 .. -2**31-1 => error,
+ -2**31 .. 2**31-1 => success,
+ 2**31 .. 2**62-1 => error,
+ 2**62 .. 2**64-1 => success,
+ 2**64 .. => error.
+
+Mon Apr 1 22:08:02 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * ext/zlib/zlib.c (Zlib::Inflate.new):
+ Fix documentation syntax and naming errors.
+ Based on patch by Robin Dupret. Fix GH-271.
+
+Mon Apr 1 21:22:31 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/-ext-/num2int/test_num2int.rb: Test small bignums.
+
+Mon Apr 1 21:10:56 2013 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_num2ulong_internal): Don't cast a negative double value
+ into unsigned long, which is undefined behavior.
+ (rb_num2ull): Don't cast a value bigger than LLONG_MAX into
+ long long, which is undefined behavior.
+
+Mon Apr 1 20:57:57 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/-test-/num2int/num2int.c: Return string for result, instead of
+ printing.
+
+ * test/-ext-/num2int/test_num2int.rb: updated to follow above change.
+
+Mon Apr 1 20:08:07 2013 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_num2long): Don't use SIGNED_VALUE uselessly.
+ (check_int): Ditto.
+ (check_short): Ditto.
+ (rb_num2fix): Ditto.
+ (rb_num2ulong_internal): Add a cast.
+
+Mon Apr 1 18:41:35 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: skip autoconf 2.64 and 2.66, 2.67 seems short-lived
+ but stick on it for Debian Squeeze.
+
+Mon Apr 1 14:22:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: check clang version by predefined macro values.
+ [Bug #8192]
+
+Mon Apr 1 12:05:15 2013 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (check_uint): Take the 1st argument as unsigned long,
+ instead of VALUE. Refine the validity test conditions.
+ (check_ushort): Ditto.
+
+Mon Apr 1 07:15:03 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * configure.in: use quadrigraph to put '[' or ']'. [Bug #8192]
+
+Mon Apr 1 04:16:41 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: kick old clang. [ruby-dev:47204] [Bug #8192]
+
+Mon Apr 1 01:12:46 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/ruby.h (FIX2ULONG): Make it consistent with NUM2ULONG.
+
+ * ext/-test-/num2int/num2int.c: Add utility methods for FIX2XXX tests.
+
+ * test/-ext-/num2int/test_num2int.rb: Add tests for FIX2XXX.
+
+Sun Mar 31 17:17:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (rb_mod_define_method): consider visibility in define_method.
+ patch by mashiro <mail AT mashiro.org>. fix GH-268.
+
+Sun Mar 31 15:40:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/configure.bat: try to fix option arguments split by commas and
+ equals here. this batch file no longer run with old command.com.
+
+ * tool/mkconfig.rb: no hacks for cmd.exe.
+
+Sun Mar 31 13:47:04 2013 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_num2ulong_internal): New function similar to
+ rb_num2ulong but integer wrap around flag is also returned.
+ (rb_num2ulong): Use rb_num2ulong_internal.
+ (rb_num2uint): Use rb_num2ulong_internal and the wrap around flag is
+ used instead of negative_int_p(val).
+ (rb_num2ushort): ditto.
+
+Sun Mar 31 06:27:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (HAVE_METACLASS_P): should check FL_SINGLETON flag before get
+ instance variable to get rid of wrong warning about __attached__.
+ [ruby-core:53839] [Bug #8188]
+
+Sat Mar 30 14:11:28 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * bcc32: removed. agreed at
+ http://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20130223Japan
+
+Sat Mar 30 03:58:00 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/file.c (code_page): use cp1252 instead of cp20127 as US-ASCII.
+ fix [ruby-core:53079] [Bug #7996]
+ reported and patched by mmeltner (Michael Meltner).
+
+Sat Mar 30 03:49:21 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (wrename): use MoveFileExW instead of MoveFileW,
+ because the latter fails on cross device file move of some
+ environments.
+ fix [ruby-core:53492] [Bug #8109]
+ reported by mitchellh (Mitchell Hashimoto).
+
+Fri Mar 29 22:09:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (rb_mutex_synchronize_m): yield no block params. patch by
+ splattael (Peter Suschlik) in [ruby-core:53773] [Bug #8097].
+ fix GH-266.
+
+Fri Mar 29 16:51:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (argf_next_argv): set init flag if succeeded to forward, after
+ skipping.
+
+ * io.c (argf_block_call_i, argf_block_call): no more forwarding if
+ forwarded after skipping. [ruby-list:49185]
+
+ * io.c (argf_close): deal with init flag.
+
+ * io.c (argf_block_call_i, argf_block_call): forward next file if
+ skipped while iteration, to get rid of IOError. [ruby-list:49185]
+
+Fri Mar 29 11:09:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (configuration): not include all CFLAGS in CXXFLAGS, to
+ use different set than C for C++. [ruby-core:45273] [Bug #6504]
+
+Fri Mar 29 10:24:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/io.h: undef POSIX compliant names on AIX, which are no
+ longer needed. patch suggested by edelsohn (David Edelsohn) in
+ [ruby-core:53815]. [Bug #8174]
+
+Fri Mar 29 06:39:42 2013 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_num2ull): Cast double to unsigned LONG_LONG via
+ LONG_LONG instead of double to unsigned LONG_LONG directly.
+ This is a challenge to fix a test_num2ull(TestNum2int)
+ failure (NUM2ULL(-1.0) should be "18446744073709551615" but was "0")
+ on Mac OS X with 32bit clang.
+ http://a.mrkn.jp/~mrkn/chkbuild/mountain_lion/ruby-trunk-m32-o0/log/20130328T191100Z.diff.html.gz
+
+Fri Mar 29 00:54:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (MAIN_DOES_NOTHING): ensure symbols for tests to be
+ preserved. [ruby-core:53745] [Bug #8169]
+
+Thu Mar 28 23:11:25 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb: Test Windows platform by detecting LoadError when
+ require 'win32/resolv' suggested by Nobuyoshi Nakada [ruby-core:53389].
+ [ruby-core:53388] [Feature #8090] Reported by Charles Nutter.
+
+Thu Mar 28 23:10:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/io.h: rename SVR3,4 member names as POSIX compliant,
+ to get rid of conflict on AIX. [ruby-core:53765] [Bug #8174]
+
+Thu Mar 28 18:22:21 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/-ext-/num2int/test_num2int.rb: extract
+ assert_num2i_success_internal and assert_num2i_error_internal and
+ provide assertion messages as "NUM2XXX(NNN)".
+
+Thu Mar 28 07:05:25 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/intern.h: Delete redundant inclusions caused by
+ AC_INCLUDES_DEFAULT in defines.h.
+
+ * include/ruby/defines.h: Ditto.
+
+ * include/ruby/ruby.h: Ditto.
+
+ * include/ruby/st.h: Ditto.
+
+Thu Mar 28 06:51:31 2013 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/defines.h: Fix a compilation error on NetBSD,
+ "type of formal parameter 1 is incomplete" for the rb_thread_wait_for
+ invocation in rb_file_flock, by including header files as
+ AC_INCLUDES_DEFAULT of autoconf.
+
+Wed Mar 27 22:09:14 2013 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (LONG_MIN_MINUS_ONE_IS_LESS_THAN): New macro.
+ (LLONG_MIN_MINUS_ONE_IS_LESS_THAN): Ditto.
+ (rb_num2long): Use LONG_MIN_MINUS_ONE_IS_LESS_THAN.
+ (rb_num2ulong): Ditto.
+ (rb_num2ll): Use LLONG_MIN_MINUS_ONE_IS_LESS_THAN.
+ (rb_num2ull): Ditto.
+
+ * test/-ext-/num2int/test_num2int.rb (assert_num2i_success): Test the
+ value converted into a Float if Float can represent the value
+ exactly.
+ (assert_num2i_error): Ditto.
+
+Wed Mar 27 20:59:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/-ext-/num2int/test_num2int.rb (assert_num2i_success): New
+ utility method.
+ (assert_num2i_error): Ditto.
+
+Wed Mar 27 20:37:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * time.c (num_exact): Use to_r method only if to_int method is
+ available.
+ [ruby-core:53764] [Bug #8173] Reported by Hiro Asari.
+
+Wed Mar 27 12:07:40 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/-ext-/num2int/test_num2int.rb (test_num2ll): test LLONG_MIN,
+ not LONG_MIN.
+
+Wed Mar 27 12:02:45 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (TIMET_MAX_PLUS_ONE): definition simplified.
+
+Wed Mar 27 06:39:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (MAIN_DOES_NOTHING): force to refer symbols for tests
+ to be preserved. [ruby-core:53745] [Bug #8169]
+
+Wed Mar 27 05:15:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_REPLACE_TYPE): define SIGNEDNESS_OF_type same as
+ check_signedness of mkmf.rb.
+
+ * internal.h (TIMET_MAX, TIMET_MIN, TIMET_MAX_PLUS_ONE): use
+ SIGNEDNESS_OF_TIME_T.
+
+Wed Mar 27 00:28:45 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (TIMET_MAX_PLUS_ONE): Defined.
+
+ * thread.c (double2timeval): Saturate out-of-range values.
+
+Tue Mar 26 23:41:18 2013 Tanaka Akira <akr@fsij.org>
+
+ * internal.h: Define TIMET_MAX and TIMET_MIN here.
+
+ * time.c: Remove TIMET_MAX and TIMET_MIN definitions.
+
+ * thread.c: Ditto.
+
+ * thread_pthread.c: Remove TIMET_MAX definition.
+
+ * thread_win32.c: Ditto.
+
+Tue Mar 26 22:31:10 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/socket.c (sockaddr_len): return the shortest length for
+ unknown socket address.
+
+Tue Mar 26 22:14:46 2013 Tanaka Akira <akr@fsij.org>
+
+ * thread.c (double2timeval): convert the infinity to TIME_MAX to avoid
+ SEGV by Thread.new {}.join(Float::INFINITY) on
+ Debian GNU/Linux (amd64).
+
+Mon Mar 25 07:09:20 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rinda/tuplespace.rb: Only return tuple entry once on move,
+ either through port or regular return, not both. This results in a
+ 120% speedup when combined with #8125. Patch by Joel VanderWerf.
+ [ruby-trunk - Feature #8119]
+
+Mon Mar 25 06:59:01 2013 Eric Hodel <drbrain@segment7.net>
+
+ * test/rinda/test_rinda.rb: Skip IPv6 tests if no IPv6 addresses
+ exist. Skip fork-dependent test if fork is not available.
+ [ruby-trunk - Bug #8159]
+
+Sun Mar 24 10:38:24 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * addr2line.c (putce): suppress unused return value warning.
+
+Mon Mar 25 02:01:03 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * proc.c (bm_free): need to clean up the mark flag of a free and
+ unlinked method entry. [Bug #8100] [ruby-core:53439]
+
+Sun Mar 24 22:13:51 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (rb_str_rpartition): revert r39903, and convert byte offset
+ to char offset; the return value of rb_reg_search is byte offset,
+ but other than it of rb_str_rpartition expects char offset.
+ [Bug #8138] [ruby-dev:47183]
+
+Sun Mar 24 18:29:46 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * string.c (rb_str_rpartition): Fix String#rpartition(/re/)
+ against a multibyte string. [Bug #8138] [ruby-dev:47183]
+
+Sun Mar 24 13:42:24 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * gc.c (GC_ENABLE_LAZY_SWEEP): new macro to switch lazy sweeping
+ for debugging. [Feature #8024] [ruby-dev:47135]
+
+Sun Mar 24 12:55:47 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * gc.c: We have no chance to expand the heap when lazy sweeping is
+ restricted. So collecting is often invoked if there is not
+ enough free space in the heap. Try to expand heap when this is
+ the case.
+
+Sun Mar 24 11:03:31 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_require.rb: Remove temporally files in the tests.
+
+ * test/ruby/test_rubyoptions.rb: Ditto.
+
+ * test/logger/test_logger.rb: Ditto.
+
+ * test/psych/test_psych.rb: Ditto.
+
+ * test/readline/test_readline.rb: Ditto.
+
+ * test/syslog/test_syslog_logger.rb: Ditto.
+
+ * test/webrick/test_httpauth.rb: Ditto.
+
+ * test/zlib/test_zlib.rb: Ditto.
+
+Sun Mar 24 05:36:29 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rinda/ring.rb: Added documentation for multicast support.
+
+ * NEWS: Point to above documentation.
+
+Sun Mar 24 05:32:39 2013 Eric Hodel <drbrain@segment7.net>
+
+ * test/rinda/test_rinda.rb: Restore tests commented out while fixing
+ test slowdown bug before r39895.
+
+Sun Mar 24 05:03:36 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rinda/ring.rb: Add multicast support to Rinda::RingFinger and
+ Rinda::RingServer. [ruby-trunk - Bug #8073]
+ * test/rinda/test_rinda.rb: Test for the above.
+
+ * NEWS: Update with Rinda multicast support
+
+Sun Mar 24 04:13:27 2013 Eric Hodel <drbrain@segment7.net>
+
+ * test/rinda/test_rinda.rb: Fixed test failures in r39890 and r39891
+ due to stopping DRb service.
+
+Sun Mar 24 03:34:02 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rinda/rinda.rb: Fixed loss of tuple when remote is alive but the
+ call stack was unwound. Patch by Joel VanderWerf.
+ [ruby-trunk - Bug #8125]
+ * test/rinda/test_rinda.rb: Test for the above.
+
+Sun Mar 24 02:14:53 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/mkmf/test_have_macro.rb: remove temporally files in the tests.
+
+Sat Mar 23 23:50:04 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (kprintf): added from FreeBSD libstand's printf.
+ this is consided as async signal safe function.
+
+ * addr2line.c (rb_dump_backtrace_with_lines): use kfprintf.
+ [Bug #8144] [ruby-core:53632]
+
+Sat Mar 23 23:28:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_divide): Use Qnil and NIL_P
+ instead of (VALUE)0 as a return value.
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_div): ditto.
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_divremain): ditto.
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_remainder): ditto.
+
+Sat Mar 23 17:39:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (check_funcall_respond_to): preserve passed_block, which
+ is modified in vm_call0_body() via vm_call0(), and caused a bug of
+ rb_check_funcall() by false negative result of rb_block_given_p().
+ re-fix [ruby-core:53650] [Bug #8153].
+ [ruby-core:53653] [Bug #8154]
+
+Fri Mar 22 17:48:34 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/forwardable.rb (Forwardable::FILE_REGEXP): create regexp object
+ outside sources for eval, to reduce allocations in def_delegators
+ wrappers. //o option does not make each regexps shared. patch by
+ tmm1 (Aman Gupta) in [ruby-core:53620] [Bug #8143].
+
+Fri Mar 22 17:38:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * load.c (rb_feature_p), vm_core.h (rb_vm_struct): turn
+ loaded_features_index into st_table. patches by tmm1 (Aman Gupta)
+ in [ruby-core:53251] and [ruby-core:53274] [Bug #8048]
+
+Fri Mar 22 10:29:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c: Fix style.
+
+Fri Mar 22 05:30:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (ambiguous_operator): refine warning message, since this
+ warning is shown after literal too.
+
+Fri Mar 22 04:51:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_callee_setup_keyword_arg): should check required
+ keyword arguments even if rest hash is defined. [ruby-core:53608]
+ [Bug #8139]
+
+Fri Mar 22 01:00:17 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * process.c (rb_execarg_addopt, run_exec_pgroup): use rb_pid_t
+ instead of pid_t.
+
+ * ext/pty/pty.c (raise_from_check, pty_check): ditto.
+
+Fri Mar 22 00:04:15 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (rb_dump_backtrace_with_lines): output line at once.
+
+Thu Mar 21 23:17:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (ruby_kill): get rid of deadlock on signal 0.
+ [ruby-dev:47182] [Bug #8137]
+
+Thu Mar 21 22:39:46 2013 Naohisa Goto <ngotogenome@gmail.com>
+
+ * marshal.c (marshal_dump, marshal_load): workaround for segv on
+ Intel Solaris compiled with Oracle SolarisStudio 12.3.
+ Partly revert r38174. [ruby-core:52042] [Bug #7805]
+
+Thu Mar 21 16:48:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (simple_re_meta): escape all closing characters, not only
+ round parenthesis. [ruby-core:53578] [Bug #8133]
+
+Thu Mar 21 13:50:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_core.h (UNINITIALIZED_VAR): suppress warnings by clang 4.2.
+ [ruby-core:51742] [Bug #7756]
+
+Thu Mar 21 07:34:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/date/date_core.c: Typo in Date::MONTHNAMES by Matt Gauger
+ [GH fixes #261]
+
+Wed Mar 20 22:53:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (find_library): fix to format message.
+ [ruby-core:53568] [Bug #8130]
+
+Wed Mar 20 22:52:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (install_dirs, with_destdir): prefix with DESTDIR
+ directories to install only unless bundled extension libraries.
+ [ruby-core:53502] [Bug #8115]
+
+Wed Mar 20 17:47:53 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/win32ole/test_err_in_callback.rb (TestErrInCallBack#setup):
+ allow using different root for source and build directories.
+ this may fixes a minor problem of r39834.
+
+Wed Mar 20 16:40:48 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * test/ruby/test_signal.rb (test_hup_me): skip if HUP isn't supported.
+ On Windows this test causes ArgumentError.
+
+Wed Mar 20 16:24:12 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * test/rubygems/test_gem_installer.rb (test_install_extension_flat):
+ use ruby in build directory in case ruby is not installed.
+ [ruby-core:53265] [Bug #8058]
+
+Wed Mar 20 15:22:07 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/win32ole/test_err_in_callback.rb (TestErrInCallBack#setup): use
+ relative path to get rid of "too long commandline" error.
+
+Wed Mar 20 04:27:42 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * test/rinda/test_rinda.rb: remove unused variables.
+ patched by Vipul A M <vipulnsward@gmail.com>
+
+Wed Mar 20 04:15:32 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * ext/bigdecimal/bigdecimal.c: fixed typo.
+ patched by Vipul A M <vipulnsward@gmail.com>
+
+Sat Mar 16 03:40:49 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * test/ruby/test_signal.rb (test_hup_me): added a few comments.
+
+Sat Mar 16 03:39:38 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread.c (ruby_kill): added a few comments.
+
+Sat Mar 16 03:36:56 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread.c (ruby_kill): release GVL while waiting signal delivered.
+
+Tue Mar 19 19:50:48 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ruby_kill (internal.h, thread.c): use rb_pid_t instead of pid_t.
+ this fixes the build failure of mswin introduced at r39819.
+
+Tue Mar 19 17:09:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_conv_enc_opts): convert with one converter, instead
+ of re-creating converters for each buffer expansion.
+
+Tue Mar 19 17:06:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (glob_helper): compose HFS file names from UTF8-MAC.
+ [ruby-core:48745] [Bug #7267]
+
+Sat Mar 16 01:44:29 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * internal.h: added a declaration of ruby_kill().
+ * thread.c (ruby_kill): helper function of kill().
+
+ * signal.c (rb_f_kill): use ruby_kill() instead of kill().
+ * signal.c (rb_f_kill): call rb_thread_execute_interrupts()
+ to ensure that make SignalException if sent a signal
+ to myself. [Bug #7951] [ruby-core:52864]
+
+ * vm_core.h (typedef struct rb_thread_struct): added
+ th->interrupt_cond.
+ * thread.c (rb_threadptr_interrupt_common): added to
+ initialization of th->interrupt_cond.
+ * thread.c (thread_create_core): ditto.
+
+ * test/ruby/test_signal.rb (TestSignal#test_hup_me): test for
+ the above.
+
+Sat Mar 16 00:42:39 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * io.c (linux_iocparm_len): enable only exist _IOC_SIZE().
+ Because musl libc doesn't have it. [Bug #8051] [ruby-core:53229]
+
+Tue Mar 19 10:05:04 2013 Shota Fukumori <her@sorah.jp>
+
+ * ext/objspace/objspace.c: Fix typo in doc. Patch by Sho Hashimoto.
+ [Bug #8116] [ruby-dev:47177]
+
+Tue Mar 19 02:13:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * configure.in: set ac_cv_prog_cxx if CXX is supplied.
+
+Tue Mar 19 01:18:00 2013 Kenta Murata <mrkn@mrkn.jp>
+
+ * configure.in: Fix c++ compiler auto-selection not only for
+ Darwin 11.x, but also the other versions of Darwin.
+
+Tue Mar 19 00:26:22 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * gc.c: Improve accuracy of objspace_live_num() and
+ allocated/freed counters. patched by tmm1(Aman Gupta).
+ [Bug #8092] [ruby-core:53392]
+
+Mon Mar 18 21:42:48 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * gc.c: Avoid unnecessary heap growth. patched by tmm1(Aman Gupta).
+ [Bug #8093] [ruby-core:53393]
+
+Mon Mar 18 17:58:36 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * gc.c: Fix unlimited memory growth with large values of
+ RUBY_FREE_MIN. patched by tmm1(Aman Gupta).
+ [Bug #8095] [ruby-core:53405]
+
+Mon Mar 18 14:46:19 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/win32ole/test_err_in_callback.rb
+ (TestErrInCallBack#test_err_in_callback): shouldn't create a file in
+ the top of build directory.
+
+Mon Mar 18 13:29:52 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_dump.c (backtrace): on darwin use custom backtrace() to trace
+ beyond _sigtramp. darwin's backtrace can't trace beyond signal
+ trampoline with sigaltstack.
+
+ * configure.in: check execinfo.h on darwin.
+
+Mon Mar 18 11:03:23 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_exec.h (END_INSN): revert r39517 because the segv seems fixed by
+ r39806.
+
+Mon Mar 18 10:41:06 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_exec.c: Correct predefined macro name. This typo is introduced by
+ r36534 and should be backported to ruby_2_0_0.
+
+Mon Mar 18 03:18:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * array.c: Typo in Array#delete by Timo Sand [GH fixes #258]
+
+Mon Mar 18 01:14:56 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * io.c (io_fillbuf): show fd number on failure to debug.
+ http://c5632.rubyci.org/~chkbuild/ruby-trunk/log/20130316T050302Z.diff.html.gz
+
+Sun Mar 17 02:38:21 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * ext/date/date_core.c: include sys/time.h for avoiding implicit
+ declaration of gettimeofday().
+
+Sun Mar 17 00:55:31 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * include/ruby/missing.h: removed __linux__. it's unnecessary.
+
+Fri Mar 15 14:57:16 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread.c: disabled _FORTIFY_SOURCE for avoid to hit glibc bug.
+ [Bug #8080] [ruby-core:53349]
+ * test/ruby/test_io.rb (TestIO#test_io_select_with_many_files):
+ test for the above.
+
+Wed Mar 13 15:16:35 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * include/ruby/missing.h (__syscall): moved to...
+ * io.c: here. because __syscall() is only used from io.c.
+
+ * include/ruby/missing.h: move "#include <sys/type.h>" to ....
+ * include/ruby/intern.h: here. because it was introduced for
+ fixing NFDBITS issue. [ruby-core:05179].
+
+Wed Mar 13 14:38:53 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * include/ruby/missing.h (struct timespec): include <sys/time.h>
+
+Wed Mar 13 13:54:45 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in: check struct timeval exist or not.
+ * include/ruby/missing.h (struct timeval): check HAVE_STRUCT_TIMEVAL
+ properly. and don't include sys/time.h if struct timeval exist.
+
+ * file.c: include sys/time.h explicitly.
+ * random.c: ditto.
+ * thread_pthread.c: ditto.
+ * time.c: ditto.
+ * ext/date/date_strftime.c: ditto.
+
+Fri Mar 15 14:45:02 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * configure.in (_FORTIFY_SOURCE): added a few comments.
+
+Fri Mar 15 14:17:55 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread_pthread.c (numberof): renamed from ARRAY_SIZE() because
+ other all files use numberof().
+
+Say Mar 15 01:33:00 2013 Charles Oliver Nutter <headius@headius.com>
+
+ * test/ruby/test_lazy_enumerator.rb (TestLazyEnumerator#test_drop_while):
+ Modify while condition to show dropping remains off after first false
+ value. This change was made in 39711.
+
+Fri Mar 15 23:06:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * time.c (GetTimeval): check if already initialized instance.
+
+ * time.c (GetNewTimeval): check if newly created instance.
+
+ * time.c (time_init_0, time_init_1, time_init_copy, time_mload): must
+ be newly created instance. [ruby-core:53436] [Bug #8099]
+
+Fri Mar 15 14:51:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_sys_fail_path_with_func): share same function, and path
+ may be nil.
+
+Fri Mar 15 08:24:51 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * io.c (rb_sys_fail_path): define & use rb_sys_fail_path0 like r39752
+
+Fri Mar 15 04:08:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * proc.c: Typo in Proc.arity found by Jack Nagel [Bug #8094]
+
+Thu Mar 14 16:59:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (rb_cv_function_name_string): macro for function name
+ string predefined identifier, __func__ in C99, or __FUNCTION__ in
+ gcc.
+
+ * file.c (rb_sys_fail_path): use RUBY_FUNCTION_NAME_STRING.
+
+Thu Mar 14 14:12:34 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * file.c (rb_sys_fail_path): use rb_sys_fail_path0 only on GCC.
+ __func__ is C99 feature.
+
+Thu Mar 14 12:59:59 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * file.c (rb_sys_fail_path0): add to append the name of called function
+ to ease debugging for example blow umask_spec failure.
+ http://fbsd.rubyci.org/~chkbuild/ruby-trunk/log/20130309T010202Z.diff.html.gz
+
+ * file.c (rb_sys_fail_path): use rb_sys_fail_path0.
+
+Thu Mar 14 12:53:15 2013 Luis Lavena <luislavena@gmail.com>
+
+ * win32/file.c (get_user_from_path): add internal function that retrieves
+ username from supplied path (refactored).
+ * win32/file.c (rb_file_expand_path_internal): refactor expansion of user
+ home to use get_user_from_path and cover dir_string corner cases.
+ [ruby-core:53168] [Bug #8034]
+
+Thu Mar 14 11:53:01 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * NEWS: describe RUBY_HEAP_SLOTS_GROWTH_FACTOR.
+
+Thu Mar 14 10:01:12 2013 Eric Hodel <drbrain@segment7.net>
+
+ * doc/globals.rdoc: $? is thread-local
+
+Wed Mar 13 23:25:59 2013 Narihiro Nakamura <authornari@gmail.com>
+
+ * gc.c: allow to tune growth of heap by environment variable
+ RUBY_HEAP_SLOTS_GROWTH_FACTOR. patched by tmm1(Aman Gupta).
+ [Feature #8015] [ruby-core:53131]
+
+Wed Mar 13 19:43:46 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * doc/irb/irb.rd.ja: fix typo
+
+ * ext/tk/MANUAL_tcltklib.eng: fix typos
+
+ * ext/tk/sample/tktextframe.rb (Tk#component_delegates): fix typo
+
+Wed Mar 13 15:13:04 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (rb_obj_singleton_methods): collect methods from the origin
+ class. [ruby-core:53207] [Bug #8044]
+
+Wed Mar 13 14:51:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_method.c (rb_export_method): directly override the flag of method
+ defined in prepending class too, not adding zsuper entry.
+ [ruby-core:53106] [Bug #8005]
+
+Wed Mar 13 13:06:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (rm, shvar_to_cpp, unexpand_shvar): local is not
+ available on old shells.
+
+ * configure.in (shvar_to_cpp): escape quotes for old shells.
+ [Bug #7959] [Bug #8071]
+
+Wed Mar 13 11:11:07 2013 Shugo Maeda <shugo@ruby-lang.org>
+
+ * object.c (Init_Object): remove Module#used, which has been
+ introduced in Ruby 2.0 by mistake. [Bug #7916] [ruby-core:52719]
+
+Wed Mar 13 05:49:29 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/irb.rb: Fix typo
+
+Tue Mar 12 22:20:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_set_arguments, iseq_compile_each): support required
+ keyword arguments. [ruby-core:51454] [Feature #7701]
+
+ * iseq.c (rb_iseq_parameters): ditto.
+
+ * parse.y (f_kw, f_block_kw): ditto. this syntax is still
+ experimental, the notation may change.
+
+ * vm_core.h (rb_iseq_struct): ditto.
+
+ * vm_insnhelper.c (vm_callee_setup_keyword_arg): ditto.
+
+Tue Mar 12 17:02:53 2013 TAKANO Mitsuhiro <tak@no32.tk>
+
+ * date_core.c: clearly specify operator precedence.
+
+Tue Mar 12 17:00:45 2013 TAKANO Mitsuhiro <tak@no32.tk>
+
+ * insns.def: fix condition.
+
+Tue Mar 12 16:48:19 2013 TAKANO Mitsuhiro <tak@no32.tk>
+
+ * rational.c: fix dangling if, else-if and else.
+
+Tue Mar 12 06:27:59 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/commands/setup_command.rb: Don't delete non-rubygems
+ files when installing RubyGems.
+ * test/rubygems/test_gem_commands_setup_command.rb: Test for the
+ above.
+
+ * lib/rubygems/ext/ext_conf_builder.rb: Use full path to siteconf.rb
+ in case the extconf.rb changes directories (like memcached does).
+
+ * lib/rubygems/package.rb: Remove double slash from path.
+ * test/rubygems/test_gem_package.rb: Test for the above.
+ * test/rubygems/test_gem_package_old.rb: ditto.
+
+ * lib/rubygems/source.rb: Revert automatic HTTPS upgrade
+ * lib/rubygems/spec_fetcher.rb: ditto.
+ * test/rubygems/test_gem_remote_fetcher.rb: ditto.
+ * test/rubygems/test_gem_source.rb: ditto.
+ * test/rubygems/test_gem_spec_fetcher.rb: ditto.
+
+Tue Mar 12 02:25:19 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/net/smtp.rb: Added Net::SMTP#rset method to implement the SMTP
+ RSET command. [ruby-trunk - Feature #5373]
+ * NEWS: ditto.
+ * test/net/smtp/test_smtp.rb: Test for the above.
+
+Mon Mar 11 22:44:57 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv-replace.rb (TCPSocket#initialize): resolve the 3rd
+ argument only if non-nil value is given.
+ [ruby-dev:47150] [ruby-trunk - Bug #8054] reported and analyzed by
+ mrkn.
+
+Mon Mar 11 19:22:54 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/mkmf/base.rb: class name conflict.
+
+Mon Mar 11 18:45:09 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * enumerator.c (enumerator_with_index): try to convert given offset to
+ integer. fix bug introduced in r39594.
+
+Mon Mar 11 17:27:57 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * test/ruby/envutil.rb (EnvUtil.with_default_external): add for
+ changing Encoding.default_external without warnings.
+
+ * test/ruby/envutil.rb (EnvUtil.with_default_internal): ditto.
+
+ * test/ruby/test_io_m17n.rb: use above with_default_external.
+
+Mon Mar 11 16:57:00 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * io.c (extract_binmode): raise error even if binmode and textmode
+ don't conflict. [Bug #5918] [ruby-core:42199]
+
+Mon Mar 11 12:25:12 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * Merge Onigmo d4bad41e16e3eccd97ccce6f1f96712e557c4518.
+ fix lookbehind assertion fails with /m mode enabled. [Bug #8023]
+ fix \Z matches where it shouldn't. [Bug #8001]
+
+Mon Mar 11 11:53:35 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (MakeMakefile#dir_config, MakeMakefile#_libdir_basename):
+ defer use of instance variable until needed. [Bug #8074]
+
+Thu Mar 7 10:42:28 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * lib/thread.rb (Queue#clear): return self.
+ Patch by Cubing Cube. Thank you! [Bug #7947] [ruby-dev:47098]
+ * lib/thread.rb (Queue#push): ditto.
+ * lib/thread.rb (SizedQueue#push): ditto.
+ * test/thread/test_queue.rb: add tests for the above.
+
+Thu Mar 7 10:40:49 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * tool/change_maker.rb (#diff2index): check Encoding::BINARY.
+ BASERUBY may still be 1.8.x.
+
+Thu Mar 7 08:47:42 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * NEWS (Mutex#owned?): no longer experimental.
+
+Sun Mar 10 23:38:15 2013 Luis Lavena <luislavena@gmail.com>
+
+ * win32/file.c (rb_file_expand_path_internal): Expand home directory when
+ used as second parameter (dir_string). [ruby-core:53168] [Bug #8034]
+ * test/ruby/test_file_exhaustive.rb: add test to verify.
+
+Sun Mar 10 23:27:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/rubygems/ext/ext_conf_builder.rb (Gem::Ext::ExtConfBuilder.build):
+ it is impossible to predict which file will be installed to where,
+ by the arguments, so use intermediate destination directory always.
+ [Bug #7698]
+
+Sun Mar 10 17:00:22 2013 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * complex.c: edited rdoc.
+ * rational.c: ditto.
+
+Sun Mar 10 15:02:39 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * process.c (setup_communication_pipe): remove unused function.
+ it was unintentionally added r39683.
+
+Wed Mar 6 00:30:40 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * tool/gen_ruby_tapset.rb: add tapset generator.
+
+Wed Mar 6 03:27:43 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * probes.d (symbol-create): change argument name `string' to
+ `str'. `string' is a keyword for systemtap.
+
+Tue Mar 5 22:23:01 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * probes.d: added argument name
+
+Thu Mar 7 01:17:00 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * test/thread/test_queue.rb (TestQueue#test_thr_kill): reduce
+ iterations from 2000 to 250. When running on uniprocessor
+ systems, every th.kill needs TIME_QUANTUM_USEC time (i.e.
+ 100msec on posix systems). Because, "r.read 1" is 3 steps
+ operations that 1) release GVL 2) read 3) acquire gvl and
+ (1) invoke context switch to main thread. and then, main
+ thread's th.kill resume (1), but not (2). Thus read interrupt
+ need TIME_QUANTUM_USEC. Then maximum iteration is 30sec/100msec
+ = 300.
+
+Thu Mar 7 00:14:51 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * io.c (rb_update_max_fd): use ATOMIC_CAS because this function
+ is used from timer thread too.
+
+Wed Mar 6 23:30:21 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread_pthread.c (ARRAY_SIZE): new.
+ * thread_pthread.c (gvl_acquire_common): use low priority
+ notification for avoiding timer thread interval confusion.
+ If we use timer_thread_pipe[1], every gvl_yield() request
+ one more gvl_yield(). It lead to thread starvation.
+ [Bug #7999] [ruby-core:53095]
+ * thread_pthread.c (rb_reserved_fd_p): adds timer_thread_pipe_low
+ to reserved fds.
+
+Wed Mar 6 22:36:19 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread_pthread.c (rb_thread_wakeup_timer_thread_fd): add fd
+ argument and remove hardcoded dependency of timer_thread_pipe[1].
+ * thread_pthread.c (consume_communication_pipe): add fd argument.
+ * thread_pthread.c (close_communication_pipe): ditto.
+
+ * thread_pthread.c (timer_thread_sleep): adjust the above changes.
+
+ * thread_pthread.c (setup_communication_pipe_internal): factor
+ out pipe initialize logic.
+
+Wed Mar 6 22:56:14 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread_pthread.c (ubf_select): add to small comments why we
+ need to call rb_thread_wakeup_timer_thread().
+
+Wed Mar 6 21:42:24 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread_pthread.c (rb_thread_create_timer_thread): factor out
+ creating communication pipe logic into separate function.
+ * thread_pthread.c (setup_communication_pipe): new helper function.
+ * thread_pthread.c (set_nonblock): moves a definition before
+ setup_communication_pipe.
+
+Sun Mar 3 02:42:29 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread_pthread.c (consume_communication_pipe): retry when
+ read returned CCP_READ_BUFF_SIZE.
+
+Wed Mar 6 21:31:35 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread_pthread.c (timer_thread_sleep): use poll() instead of
+ select(). select doesn't work if timer_thread_pipe[0] is
+ greater than FD_SETSIZE.
+ * thread_pthread.c (USE_SLEEPY_TIMER_THREAD): add a dependency
+ against poll.
+
+Wed Mar 6 21:00:23 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread_pthread.c (USE_SLEEPY_TIMER_THREAD): use more accurate
+ ifdef conditions.
+
+Sun Mar 3 02:30:36 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * thread_pthread.c (set_nonblock): new helper function for set
+ O_NONBLOCK.
+ * thread_pthread.c (rb_thread_create_timer_thread): set O_NONBLOCK
+ to timer_thread_pipe[0] too.
+
+Sun Mar 10 09:12:51 2013 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * complex.c: described syntax of string form.
+ * rational.c: ditto.
+
+Sat Mar 9 11:58:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (w_extended): check for prepended object.
+ [ruby-core:53206] [Bug #8043]
+
+Sat Mar 9 08:36:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * load.c (features_index_add_single, rb_feature_p): store single index
+ as Fixnum to reduce the number of arrays for the indexes. based on
+ the patch by tmm1 (Aman Gupta) in [ruby-core:53216] [Bug #8048].
+
+Sat Mar 9 00:25:57 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (r_object0): load prepended objects. treat the class of
+ extended object in the included modules as prepended singleton
+ class. [ruby-core:53202] [Bug #8041]
+
+Fri Mar 8 19:44:00 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * man/rake.1, man/ruby.1: Use the Pa macro to make URLs stand out.
+
+Fri Mar 8 13:20:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/pathname/pathname.c (path_f_pathname): rdoc for Pathname()
+
+Fri Mar 8 12:00:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * man/rake.1: Document ENVIRONMENT variables on RAKE(1) manpage
+
+Fri Mar 8 10:44:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/webrick/httpproxy.rb: Fix typos in HTTPProxyServer [Bug #8013]
+ Patch by Nobuhiro IMAI [ruby-core:53127]
+
+Fri Mar 8 03:16:15 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * class.c (rb_mod_ancestors): Include singleton_class in ancestors
+ list [Feature #8035]
+
+ * test/ruby/test_module.rb (class): test for above
+
+ * test/ruby/marshaltestlib.rb (module): adapt test
+
+ * NEWS: list change
+
+Thu Mar 7 14:21:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_compile_each): pass keyword arguments to zsuper,
+ with current values. [ruby-core:53114] [Bug #8008]
+
+Thu Mar 7 12:53:47 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/commands/setup_command.rb: Install .pem files.
+ * test/rubygems/test_gem_commands_setup_command.rb: Test for the
+ above.
+
+ * lib/rubygems/spec_fetcher.rb: Test HTTPS upgrade with URI::HTTPS,
+ not URI::HTTP. Fixes bug in automatic HTTPS upgrade.
+ * test/rubygems/test_gem_spec_fetcher.rb: Test for the above.
+
+ * lib/rubygems.rb: Version 2.0.2
+
+ * lib/rubygems/test_utilities.rb: Ensure scheme and uri class match.
+
+Thu Mar 7 10:39:04 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/rbinstall.rb (gem): Gem.ensure_gem_subdirectories now has mode
+ option since r39607. refix of r38870.
+
+Wed Mar 6 13:14:28 2013 Eric Hodel <drbrain@segment7.net>
+
+ * test/rubygems/test_gem_spec_fetcher.rb: Removed unused variable.
+
+Wed Mar 6 08:10:15 2013 Eric Hodel <drbrain@segment7.net>
+
+ * test/rubygems/test_require.rb: Fix tests when 'a.rb' exists.
+ [ruby-trunk - Bug #7749]
+
+Wed Mar 6 08:00:59 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems.rb: Allow specification of directory permissions.
+ [ruby-trunk - Bug #7713]
+ * test/rubygems/test_gem.rb: Test for the above.
+
+Wed Mar 6 07:40:21 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/commands/query_command.rb: Only fetch remote specs when
+ showing details. [ruby-trunk - Bug #8019] RubyGems bug #487
+ * lib/rubygems/remote_fetcher.rb: ditto.
+ * lib/rubygems/security/policy.rb: ditto.
+ * test/rubygems/test_gem_commands_query_command.rb: Test for the
+ above.
+
+ * lib/rubygems/security.rb: Make OpenSSL optional for RubyGems.
+ * lib/rubygems/commands/cert_command.rb: ditto.
+
+ * lib/rubygems/config_file.rb: Display file with YAML error, not
+ ~/.gemrc
+
+ * lib/rubygems/remote_fetcher.rb: Only create gem subdirectories when
+ installing gems.
+ * lib/rubygems/dependency_resolver.rb: ditto.
+ * lib/rubygems/test_utilities.rb: ditto.
+ * test/rubygems/test_gem_commands_fetch_command.rb: Test for the
+ above.
+
+ * lib/rubygems/spec_fetcher.rb: Only try to upgrade
+ http://rubygems.org to HTTPS
+ * test/rubygems/test_gem_spec_fetcher.rb: Test for the above.
+
+ * lib/rubygems.rb: Update win_platform? check for JRuby compatibility.
+
+ * test/rubygems/test_gem_installer.rb: Update for Ruby 1.9.2
+ compatibility
+
+Wed Mar 6 01:19:28 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * enumerator.c (enumerator_with_index, lazy_take): use INT2FIX(0)
+ instead of INT2NUM(0).
+
+ * ext/bigdecimal/bigdecimal.c (BigMath_s_exp): ditto.
+
+ * ext/fiddle/function.c (function_call): ditto.
+
+ * ext/openssl/ossl_x509store.c (ossl_x509store_initialize): ditto.
+
+ * process.c (proc_getsid): ditto.
+
+ * transcode.c (econv_finish): ditto.
+
+Tue Mar 5 21:36:43 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (rb_prepend_module): check redefinition of built-in optimized
+ methods. [ruby-dev:47124] [Bug #7983]
+
+ * vm.c (rb_vm_check_redefinition_by_prepend): ditto.
+
+Tue Mar 5 20:29:25 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (mnew): revert r39224. [ruby-core:53038] [Bug #7988]
+
+Tue Mar 5 20:23:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/intern.h (rb_check_arity): make a static inline
+ function so it can be used as an expression and argc would be
+ evaluated only once.
+
+Tue Mar 5 12:30:55 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems.rb: Bump version to 2.0.1 for upcoming bugfix release
+
+ * lib/rubygems/ext/ext_conf_builder.rb: Restore ruby 1.8 compatibility
+ for [Bug #7698]
+ * test/rubygems/test_gem_installer.rb: Ditto.
+
+ * lib/rubygems/package.rb: Restore ruby 1.8 compatibility.
+
+ * test/rubygems/test_gem_dependency_installer.rb: Fix warnings
+
+Tue Mar 5 12:24:23 2013 Eric Hodel <drbrain@segment7.net>
+
+ * enumerator.c (enumerator_with_index): Restore handling of a nil memo
+ from r39594.
+
+Tue Mar 5 10:40:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/objspace/objspace.c (count_nodes): count also newly added nodes,
+ and fix key for unknown node. patch by tmm1 (Aman Gupta) in
+ [ruby-core:53130] [Bug #8014]
+
+Tue Mar 5 10:20:16 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enumerator.c (enumerator_with_index_i): allow Bignum as offset, to
+ get rid of conversion exception and integer overflow.
+ [ruby-dev:47131] [Bug #8010]
+
+ * numeric.c (rb_int_succ, rb_int_pred): shortcut optimization for
+ Bignum.
+
+Tue Mar 5 10:02:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/rubygems/ext/ext_conf_builder.rb (Gem::Ext::ExtConfBuilder.build):
+ clear DESTDIR so RUBYARCHDIR and RUBYLIBDIR are not be overridden.
+ [Bug #7698]
+
+Mon Mar 4 15:33:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/rubygems/ext/ext_conf_builder.rb (Gem::Ext::ExtConfBuilder.build):
+ fix for unusual cases again. install to a temporary directory once
+ and move installed files to the destination directory, if it is same
+ as the current directory. [Bug #7698]
+
+Mon Mar 4 14:13:36 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * Makefile.in (miniruby, ruby): move MAINLIBC because linker arguments
+ must appear after object files with newer versions of gcc. patch by
+ tmm1 (Aman Gupta) in [ruby-core:53121] [Bug #8009]
+
+Mon Mar 4 10:23:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * encoding.c: Typo in Encoding overview by Tom Wardrop [GH fixes #255]
+
+Sun Mar 3 12:35:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (MakeMakefile#libpath_env): set runtime library path for
+ the case rpath is disabled.
+
+Sun Mar 3 12:17:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/rubygems/ext/ext_conf_builder.rb
+ (Gem::Ext::ExtConfBuilder.hack_for_obsolete_style_gems): remove
+ circular dependencies in install-so too. [ruby-core:52882]
+ [Bug #7698]
+
+Sun Mar 3 07:33:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/socket/tcpserver.c: Grammar for TCPServer.new from r39554
+
+Sun Mar 3 01:17:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/rubygems/ext/ext_conf_builder.rb
+ (Gem::Ext::ExtConfBuilder.hack_for_obsolete_style_gems): remove
+ circular dependencies for old style gems which locate extconf.rb on
+ the toplevel. [ruby-core:53059] [ruby-trunk - Bug #7698]
+
+ * lib/rubygems/ext/ext_conf_builder.rb (Gem::Ext::ExtConfBuilder.build):
+ use RUBYOPT instead of -r option, and revert some tests. [Bug #7698]
+
+ * lib/rubygems/ext/ext_conf_builder.rb (Gem::Ext::ExtConfBuilder.build):
+ revert use of temporary directory for build, to work some buggy
+ extconf.rb which cannot build outside the source directory.
+ [ruby-core:53056] [Bug #7698]
+
+Sun Mar 3 00:04:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enc/depend (CPPFLAGS), lib/mkmf.rb (MakeMakefile#create_makefile):
+ define RUBY_EXPORT for static-linked-ext mswin. [Bug #7960]
+
+Sat Mar 2 22:49:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/Makefile.sub (ENCOBJS, EXTOBJS, config.h): definitions for
+ static-linked-ext. [Bug #7960]
+
+Sat Mar 2 17:34:19 2013 Tanaka Akira <akr@fsij.org>
+
+ * lib/webrick/utils.rb: use Socket.tcp_server_sockets to create server
+ sockets.
+ fix [Bug #7100] https://bugs.ruby-lang.org/issues/7100
+ reported by sho-h (Sho Hashimoto).
+
+Sat Mar 2 02:45:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * array.c: typo in comment patch by Nami-Doc [Github fixes #253]
+
+Sat Mar 2 01:33:17 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * Merge Onigmo 0fe387da2fee089254f6b04990541c731a26757f
+ v5.13.3 [Bug#7972] [Bug#7974]
+
+Fri Mar 1 11:09:06 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/fileutils.rb: Revert r34669 which altered the way
+ metaprogramming in FileUtils occurred. [ruby-trunk - Bug #7958]
+
+ * test/fileutils/visibility_tests.rb: Refactored tests of FileUtils
+ options modules to expose bug found in #7958
+ * test/fileutils/test_dryrun.rb: ditto.
+ * test/fileutils/test_nowrite.rb: ditto.
+ * test/fileutils/test_verbose.rb: ditto.
+
+Fri Mar 1 09:18:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/psych.rb: specify in rdoc what object is returned in parser
+ By Adam Stankiewicz [Github tenderlove/psych#133]
+
+Fri Mar 1 07:21:41 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/ext/builder.rb: Fix incompatibilities when installing
+ extensions. Patch by Nobu.
+ [ruby-trunk - Bug #7698] [ruby-trunk - Bug #7971]
+ * lib/rubygems/ext/ext_conf_builder.rb: ditto.
+ * lib/rubygems/installer.rb: ditto.
+ * test/rubygems/test_gem_ext_ext_conf_builder.rb: Test for the above.
+ * test/rubygems/test_gem_installer.rb: ditto.
+
+ * lib/rubygems/commands/sources_command.rb: Prefer HTTPS over HTTP.
+ * lib/rubygems/defaults.rb: ditto
+ * lib/rubygems/dependency_resolver.rb: Ditto.
+ * lib/rubygems/source.rb: ditto.
+ * lib/rubygems/spec_fetcher.rb: ditto.
+ * lib/rubygems/specification.rb: ditto.
+ * lib/rubygems/test_utilities.rb: ditto.
+ * test/rubygems/test_gem.rb: Test for the above.
+ * test/rubygems/test_gem_commands_sources_command.rb: ditto.
+ * test/rubygems/test_gem_dependency_resolver_api_set.rb: ditto.
+ * test/rubygems/test_gem_remote_fetcher.rb: ditto.
+ * test/rubygems/test_gem_source.rb: ditto.
+ * test/rubygems/test_gem_spec_fetcher.rb: ditto.
+
+Fri Mar 1 03:25:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/psych/lib/psych.rb: rdoc for Psych overview by Adam Stankiewicz
+ [Github tenderlove/psych#134]
+
+Thu Feb 28 22:57:48 2013 Koichi Sasada <ko1@atdot.net>
+
+ * compile.c (iseq_compile_each): remove redundant trace(line)
+ instruction. for example, at the following script
+ def m()
+ p:xyzzy
+ 1
+ 2
+ end
+ compiler ignores `1' because there is no effect. However,
+ `trace(line)' instruction remains in bytecode.
+ This modification removes such redundant trace(line) instruction.
+
+ * test/ruby/test_iseq.rb: add a test.
+
+Thu Feb 28 22:23:27 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/raddrinfo.c (inspect_sockaddr): don't show that Unix
+ domain socket filename is bigger than sizeof(sun_path).
+ This limit is not rigid on some platforms such as Darwin and SunOS.
+
+Thu Feb 28 21:33:01 2013 WATANABE Hirofumi <eban@ruby-lang.org>
+
+ * configure.in(AC_DISABLE_OPTION_CHECKING): avoid warning "WARNING:
+ Unrecognized options: --with-PACKAGE".
+
+Thu Feb 28 20:22:04 2013 Koichi Sasada <ko1@atdot.net>
+
+ * iseq.c (iseq_data_to_ary): fix condition.
+ r34303 introduces a bug to avoid all line information from
+ a result of ISeq#to_a. This is a regression problem from 2.0.0p0.
+
+ * test/ruby/test_iseq.rb: add a test of lines after ISeq#to_a.
+
+Thu Feb 28 08:20:33 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/available_set.rb: Undent for style
+
+ * lib/rubygems/dependency_installer.rb: Pick latest prerelease gem to
+ install. Fixes RubyGems bug #468.
+ * test/rubygems/test_gem_dependency_installer.rb: Test for the above.
+
+ * lib/rubygems/dependency_installer.rb: Don't display "Done installing
+ documentation" if documentation will not be installed.
+ * lib/rubygems/rdoc.rb: ditto
+
+ * lib/rubygems/dependency_list.rb: Use Array#concat for Ruby 1.x
+ performance.
+
+ * lib/rubygems/installer.rb: Use formatted program name when comparing
+ executables. RubyGems pull request #471
+ * test/rubygems/test_gem_installer.rb: Test for the above.
+
+ * lib/rubygems/package.rb: Use more explicit feature check to work
+ around JRuby bug #552
+
+ * lib/rubygems/ssl_certs/GeoTrust_Global_CA.pem: Added GeoTrust root
+ certificate.
+
+ * test/rubygems/test_gem_source_list.rb: Use "example" instead of real
+ hostname
+
+Thu Feb 28 05:57:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * thread.c: rdoc formatting for Thread, ThreadGroup, and ThreadError
+
+Thu Feb 28 02:42:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * vm.c: Typo in overview for example of Thread#status returning false
+ Reported by Lee Jarvis
+
+Wed Feb 27 22:54:27 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/rubysocket.h (union_sockaddr): make it longer for SunOS
+ and Darwin.
+
+Wed Feb 27 21:14:34 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/security.rb (REXML::Security): create.
+ * lib/rexml/rexml.rb: move entity_expansion_limit and
+ entity_expansion_text_limit accessors to ...
+ * lib/rexml/security.rb: ... here.
+ * lib/rexml/document.rb: use REXML::Security.
+ * lib/rexml/text.rb: use REXML::Security.
+ * test/rexml/test_document.rb: use REXML::Security.
+
+Wed Feb 27 19:53:32 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * vm.c (Thread): fix typos in overview
+
+Wed Feb 27 13:21:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * vm.c (Thread): Typo in overview, swap setting and getting
+
+Wed Feb 27 13:02:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * vm.c (Thread): Documentation overview of Thread class
+
+Wed Feb 27 12:57:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * thread.c (rb_thread_wakeup): rdoc formatting
+
+Wed Feb 27 12:53:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * thread.c (rb_thread_group): rdoc formatting
+
+Wed Feb 27 12:33:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/ostruct.rb: Typo in OpenStruct overview [Github Fixes #251]
+ Patch by Chun-wei Kuo
+
+Wed Feb 27 12:13:32 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_exec.h (END_INSN): llvm-gcc may optimize out reg_cfp and cause
+ Stack/cfp consistency error when the instruction doesn't use reg_cfp.
+ Usually instructions use PUSH() but for example trace doesn't.
+ This hack cause speed down but you shouldn't use llvm-gcc, use clang.
+ [Bug #7938]
+
+Wed Feb 27 10:23:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * thread.c (thread_raise_m): rdoc formatting
+
+Tue Feb 26 23:32:44 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/document.rb: move entity_expansion_limit accessor to ...
+ * lib/rexml/rexml.rb: ... here for consistency.
+ * lib/rexml/document.rb (REXML::Document.entity_expansion_limit):
+ deprecated.
+ * lib/rexml/document.rb (REXML::Document.entity_expansion_limit=):
+ deprecated.
+
+Tue Feb 26 23:26:13 2013 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/document.rb: move entity_expansion_text_limit accessor to ...
+ * lib/rexml/rexml.rb: ... here to make rexml/text independent from
+ REXML::Document. It causes circular require.
+ * lib/rexml/document.rb (REXML::Document.entity_expansion_text_limit):
+ deprecated.
+ * lib/rexml/document.rb (REXML::Document.entity_expansion_text_limit=):
+ deprecated.
+ * lib/rexml/text.rb: add missing require "rexml/rexml" for
+ REXML.entity_expansion_text_limit.
+ Reported by Robert Ulejczyk. Thanks!!! [ruby-core:52895] [Bug #7961]
+
+Tue Feb 26 15:12:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/mkconfig.rb: reconstruct comma separated list values. a
+ command line to Windows batch file is split not only by spaces
+ and equal signs but also by commas and semicolons.
+
+Tue Feb 26 15:04:19 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (unexpand_shvar): get rid of non-portable shell
+ behavior on OpenBSD, so no extra quotes. [Bug #7959]
+
+Tue Feb 26 10:24:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (IS_LABEL_POSSIBLE): allow labels for keyword arguments just
+ after method definition without a parenthesis. [ruby-core:52820]
+ [Bug #7942]
+
+Tue Feb 26 04:50:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * error.c: clarify reason for sleep in SignalException example
+
+Tue Feb 26 03:47:00 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * error.c: clarify a document of SignalException. Process.kill()
+ doesn't have any guarantee when signal will be delivered.
+ [Bug #7951] [ruby-core:52864]
+
+Mon Feb 25 23:51:04 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/version.h: bump RUBY_API_VERSION same as RUBY_VERSION.
+
+Mon Feb 25 21:03:34 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (str_byte_substr): don't set coderange if it's not known.
+ [Bug #7954] [ruby-dev:47108]
+
+Mon Feb 25 16:47:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (realclean-local): miniprelude.c is made by srcs, so it
+ should not removed by distclean but by realclean. [Bug #6807]
+
+Mon Feb 25 16:30:30 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/config_file.rb: Lazily load .gem/credentials to only
+ check permissions when necessary. RubyGems bug #465
+ * test/rubygems/test_gem_config_file.rb: Test for the above.
+
+ * test/rubygems/test_gem_commands_push_command.rb: Remove duplicated
+ test.
+
+Mon Feb 25 15:47:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enc/depend (ARFLAGS): VisualC++ linker does not allow spaces between
+ output option and the output file name. [Bug #7950]
+
+ * enc/depend (RANLIB): set default command to do nothing, or make the
+ entire line a label on Windows.
+
+Mon Feb 25 14:41:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (MakeMakefile#init_mkmf): default libdirname to libdir.
+
+ * tool/rbinstall.rb: ditto.
+
+Mon Feb 25 13:12:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (setup): find Setup file from target_os 1. by
+ suffix (e.g. Setup.nacl, Setup.atheos), 2. by "platform"
+ option (e.g. Setup.nt, Setup.emx), and 3. default Setup. And
+ Setup.dj had been removed.
+
+Mon Feb 25 12:48:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * thread.c: Document Thread::new, clean up ::fork and mention calling
+ super if subclassing Thread
+
+Mon Feb 25 12:38:50 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: don't test ss_family and ss_len member of
+ struct sockaddr_storage. They are not used now except SunOS
+ specific code.
+
+Mon Feb 25 11:03:38 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * configure.in (unexpand_shvar): Use the numeric comparison
+ operator instead of '==' which is a ksh extension. [Bug #7941]
+
+Mon Feb 25 02:37:56 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket: define and use union_sockaddr instead of struct
+ sockaddr_storage for less casts.
+
+ * ext/socket/rubysocket.h (union_sockaddr): defined.
+
+ * ext/socket/socket.c (sock_accept): use union_sockaddr.
+ (sock_accept_nonblock): ditto.
+ (sock_sysaccept): ditto.
+ (sock_s_getnameinfo): ditto.
+
+ * ext/socket/basicsocket.c (bsock_getsockname): ditto.
+ (bsock_getpeername): ditto.
+ (bsock_local_address): ditto.
+ (bsock_remote_address): ditto.
+
+ * ext/socket/ancdata.c (bsock_recvmsg_internal): ditto.
+
+ * ext/socket/init.c (recvfrom_arg): ditto.
+ (recvfrom_blocking): ditto.
+ (rsock_s_recvfrom): ditto.
+ (rsock_s_recvfrom_nonblock): ditto.
+ (rsock_getfamily): ditto.
+
+ * ext/socket/raddrinfo.c (rb_addrinfo_t): ditto.
+ (ai_get_afamily): ditto.
+ (inspect_sockaddr): ditto.
+ (addrinfo_mdump): ditto.
+ (addrinfo_mload): ditto.
+ (addrinfo_getnameinfo): ditto.
+ (addrinfo_ip_port): ditto.
+ (extract_in_addr): ditto.
+ (addrinfo_ipv6_to_ipv4): ditto.
+ (addrinfo_unix_path): ditto.
+
+ * ext/socket/tcpserver.c (tcp_accept): ditto.
+ (tcp_accept_nonblock): ditto.
+ (tcp_sysaccept): ditto.
+
+ * ext/socket/ipsocket.c (ip_addr): ditto.
+ (ip_peeraddr): ditto.
+ (ip_s_getaddress): ditto.
+
+Sun Feb 24 21:15:05 2013 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * ext/date/date_core.c: [ruby-core:52303]
+
+Sun Feb 24 15:33:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * random.c (rb_random_ulong_limited): limit is inclusive, but generic
+ rand method should return a number less than it, so increase for the
+ difference. [ruby-core:52779] [Bug #7935]
+
+Sun Feb 24 15:32:36 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * random.c (rb_random_ulong_limited): limit is inclusive, but generic
+ rand method should return a number less than it, so increase for the
+ difference. [ruby-core:52779] [Bug #7935]
+
+Sun Feb 24 15:14:43 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/net/http.rb: Removed duplicate Accept-Encoding in Net::HTTP#get.
+ [ruby-trunk - Bug #7924]
+ * test/net/http/test_http.rb: Test for the above.
+
+Wed Feb 20 14:28:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * thread.c: Document ThreadGroup::Default
+
+Wed Feb 20 14:23:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * thread.c: Grammar for #backtrace_locations and ::handle_interrupt
+
+Sun Feb 24 13:35:57 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_call_method): block level control frame does not
+ have method entry, so obtain the method entry from method top-level
+ control frame to be compared with refined method entry.
+ [ruby-core:52750] [Bug #7925]
+
+Wed Feb 20 13:23:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * object.c: Document methods receiving string and convert to symbol
+ Patch by Stefan Rusterholz
+ * vm_eval.c: ditto
+ * vm_method.c: ditto
+
+Wed Feb 20 07:20:56 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * signal.c (sigsegv): suppress unused result warning. Because
+ write(2) is marked __warn_unused_result__ on Linux glibc.
+
+Sun Feb 24 07:50:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_set_arguments): no keyword check if any keyword rest
+ argument exists, even unnamed. [ruby-core:52744] [Bug #7922]
+
+Sat Feb 23 16:51:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * thread.c: Documentation for Thread#backtrace_locations
+
+Sat Feb 23 16:05:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * vm.c: Typo in ObjectSpace::WeakMap overview
+
+Sat Feb 23 16:00:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * thread.c: Improved rdoc for ::handle_interrupt, ::pending_interrupt?
+ and #pending_interrupt?
+
+Sat Feb 23 12:26:43 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * misc/ruby-electric.el (ruby-electric-curlies)
+ (ruby-electric-matching-char, ruby-electric-bar): Avoid electric
+ insertion when there is a prefix argument.
+
+ * misc/ruby-electric.el (ruby-electric-insert)
+ (ruby-electric-cua-replace-region-p)
+ (ruby-electric-cua-replace-region): Avoid electric insertion and
+ fall back when cua-mode is enabled and a region is active.
+
+Sat Feb 23 12:35:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * array.c: Document #<=> return values and formatting
+ * bignum.c: ditto
+ * file.c: ditto
+ * object.c: ditto
+ * numeric.c: ditto
+ * rational.c: ditto
+ * string.c: ditto
+ * time.c: ditto
+
+Sat Feb 23 10:50:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * array.c (rb_ary_diff, rb_ary_and, rb_ary_or): Document return order
+ [RubySpec #7803]
+
+Sat Feb 23 10:17:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * object.c (rb_obj_comp): Documenting Object#<=> return values
+ Patch by Stefan Rusterholz
+
+Sat Feb 23 09:48:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (file_s_fnmatch, fnmatch_brace): encoding-incompatible pattern
+ and string do not match, instead of exception. [ruby-dev:47069]
+ [Bug #7911]
+
+Sat Feb 23 08:57:46 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * doc/NEWS-*: Update NEWS from their respective branches
+
+Sat Feb 23 08:14:43 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * NEWS: many additions for Ruby 2.0.0
+
+ * object.c: Add doc for Module.prepended
+
+Sat Feb 23 07:52:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * template/ruby.pc.in: reorder library flags which may refer library
+ names. [Bug #7913]
+
+Fri Feb 22 23:46:20 2013 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * lib/rexml/document.rb (REXML::Document.entity_expansion_text_limit):
+ fix a typo in comment in r39384.
+
+Fri Feb 22 18:31:46 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * lib/rexml/document.rb (REXML::Document.entity_expansion_text_limit):
+ new attribute to read/write entity expansion text limit. the default
+ limit is 10Kb.
+
+ * lib/rexml/text.rb (REXML::Text.unnormalize): check above attribute.
+
+Fri Feb 22 17:36:23 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * test/test_rbconfig.rb (TestRbConfig): fix r39372.
+ It must see RbConfig::CONFIG instead of CONFIG.
+
+Fri Feb 22 14:55:41 2013 Naohisa Goto <ngotogenome@gmail.com>
+
+ * signal.c (ruby_abort): fix typo in r39354 [Bug #5014]
+
+Fri Feb 22 12:46:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * random.c (rb_random_ulong_limited): fix error message for negative
+ value. [ruby-dev:47061] [Bug #7903]
+
+Fri Feb 22 11:36:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/test_rbconfig.rb (TestRbConfig): skip user defined values by
+ configuration options. [Bug #7902]
+
+Fri Feb 22 11:33:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (MakeMakefile#init_mkmf): adjust default library path
+ for multiarch. [Bug #7874]
+
+Fri Feb 22 11:10:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * enum.c (Enumerable#chunk: Improved examples, grammar, and formatting
+ Patch by Dan Bernier and Rich Bruchal of newhaven.rb
+ [Github documenting-ruby/ruby#8]
+
+Fri Feb 22 11:00:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * numeric.c: Examples and formatting for Numeric and Float
+ Based on a patch by Zach Morek and Oren K of newhaven.rb
+ [Github documenting-ruby/ruby#5]
+
+Fri Feb 22 07:04:41 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/installer.rb (build_extensions): Create extension
+ install destination before building extension. Patch by Kenta Murata.
+ [ruby-trunk - Bug #7897]
+ * test/rubygems/test_gem_installer.rb: Test for the above.
+
+Fri Feb 22 06:30:57 2013 Eric Hodel <drbrain@segment7.net>
+
+ * doc/globals.rdoc: Document what setting $DEBUG does.
+
+ * doc/globals.rdoc: Added pointer to $-d for full documentation.
+
+Fri Feb 22 06:27:07 2013 Eric Hodel <drbrain@segment7.net>
+
+ * doc/globals.rdoc: Document what setting $VERBOSE does. [Bug #7899]
+
+ * doc/globals.rdoc: Added pointer to $-w and $-v for full
+ documentation.
+
+Fri Feb 22 02:33:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/abbrev.rb: Add words parameter to Abbrev::abbrev
+ Patch by Devin Weaver [Github documenting-ruby/ruby#7]
+
+Thu Feb 21 17:28:14 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/merger.rb: add interaction when only ChangeLog is modified.
+
+Thu Feb 21 16:34:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (check_stack_overflow): extract duplicated code and get rid
+ of declaration-after-statement. [Bug #5014]
+
+Thu Feb 21 14:14:13 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * signal.c (sigsegv): avoid to use async signal unsafe functions
+ when nested sigsegv is happen.
+ [Bug #5014] [ruby-dev:44082]
+
+Thu Feb 21 13:47:59 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * file.c (rb_group_member): added an error check. SUS says,
+ getgroups(small_value) may return EINVAL.
+
+Thu Feb 21 13:37:07 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * process.c (RB_MAX_GROUPS): moved to
+ * internal.h (RB_MAX_GROUPS): here.
+
+ * file.c (rb_group_member): use RB_MAX_GROUPS instead of
+ RUBY_GROUP_MAX. They are the same.
+
+Thu Feb 21 13:15:40 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * file.c (access_internal): removed.
+ * file.c (rb_file_readable_real): use access() instead of
+ access_internal().
+ * file.c (rb_file_writable_real): ditto.
+ * file.c (rb_file_executable_real): ditto.
+
+Thu Feb 21 13:04:59 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * file.c (eaccess): use access() when not using setuid nor setgid.
+ This is minor optimization.
+
+Thu Feb 21 12:56:19 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * file.c (rb_group_member): get rid of NGROUPS dependency.
+ [Bug #7886] [ruby-core:52537]
+
+Thu Feb 21 12:45:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (ruby_init_loadpath_safe): try two levels upper for stripping
+ libdir name. [Bug #7874]
+
+ * configure.in (libdir_basename): expand with multiarch in configure,
+ not to defer the expansion till ruby.pc.in and mkmf.rb. [Bug #7874]
+
+ * configure.in (libdir_basename): also -rpath and -install_name flags
+ are affected when libruby directory changes. [Bug #7874]
+
+Wed Feb 20 19:27:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (HAVE_RB_SCAN_ARGS_OPTIONAL_HASH): for
+ rb_scan_args() optional hash feature. [Bug #7861]
+
+Wed Feb 20 18:02:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (target_os): do not strip -gnu suffix on Linux if
+ --target is given explicitly. [Bug #7874]
+
+ * configure.in (libdirname): adjust library path name which libruby
+ files will be installed. [Bug #7874]
+
+ * tool/rbinstall.rb (libdir): ditto.
+
+Wed Feb 20 13:37:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/pty/pty.c: Documentation for the PTY module
+
+Wed Feb 20 12:18:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * object.c: Document Data class [Bug #7890] [ruby-core:52549]
+ Patch by Matthew Mongeau
+
+Wed Feb 20 11:50:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/mutex_m.rb: Add rdoc for Mutex_m module
+
+Wed Feb 20 09:34:43 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/commands/update_command.rb: Create the installer after
+ options are processed. [ruby-trunk - Bug #7779]
+ * test/rubygems/test_gem_commands_update_command.rb: Test for the
+ above.
+
+Wed Feb 20 07:51:19 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/installer.rb: Use gsub instead of gsub! to avoid
+ altering @bin_dir. Fixes tests on windows. [ruby-trunk - Bug #7885]
+
+Tue Feb 19 20:50:00 2013 Kenta MURATA <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.gemspec: bump to 1.2.0.
+ [ruby-core:51777] [Bug #7761]
+
+Tue Feb 19 13:07:25 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/syslog/syslog.c (Init_syslog): Define inspect as a singleton
+ method and remove it as an instance method. [Bug #6502]
+
+Tue Feb 19 12:30:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * object.c: rdoc formatting for Kernel#Array()
+ * array.c: Add rdoc for Array() method to Creating Arrays section
+
+Tue Feb 19 10:35:52 2013 Eric Hodel <drbrain@segment7.net>
+
+ * ext/openssl/ossl.c (class OpenSSL): Use only inner parenthesis in
+ create_extension examples.
+
+Tue Feb 19 10:27:12 2013 Eric Hodel <drbrain@segment7.net>
+
+ * ext/openssl/ossl.c (class OpenSSL): Fixed ExtensionFactory example.
+ Patch by Richard Bradley. [ruby-trunk - Bug #7551]
+
+Tue Feb 19 08:32:11 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_eval.c (vm_call0_body): check interrupts after method dispatch
+ from C methods. [Bug #7878]
+
+Tue Feb 19 08:14:40 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/installer.rb: Fixed placement of executables with
+ --user-install. [ruby-trunk - Bug #7779]
+ * test/rubygems/test_gem_installer.rb: Test for above.
+
+Tue Feb 19 06:04:06 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_dump: FreeBSD ports' libexecinfo's backtrace(3) can't trace
+ beyond signal trampoline, and as described in r38342 it can't
+ trace on -O because it see stack frame pointers.
+ libunwind unw_backtrace see dwarf information in the binary
+ and it works with -O (without frame pointers).
+
+ * configure.in: remove r38342's hack and check libunwind.
+
+Tue Feb 19 04:26:29 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: check whether backtrace(3) works well or not.
+
+ * vm_dump.c: set HAVE_BACKTRACE 0 if BROKEN_BACKTRACE.
+
+Mon Feb 18 16:30:18 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/ipaddr.rb (IPAddr#in6_addr): Fix a typo with the closing
+ parenthesis.
+
+Mon Feb 18 12:32:24 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/ipaddr.rb (IPAddr#in6_addr): Fix the parser so that it can
+ recognize IPv6 addresses with only one edge 16-bit piece
+ compressed, like [::2:3:4:5:6:7:8] or [1:2:3:4:5:6:7::].
+ [Bug #7477]
+
+Mon Feb 18 10:09:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (unexpand_shvar): regularize a shell variable by
+ unexpanding shell variables in it.
+
+Sun Feb 17 20:55:44 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compar.c (rb_invcmp): compare by inversed comparison, with preventing
+ from infinite recursion. [ruby-core:52305] [Bug #7870]
+
+ * string.c (rb_str_cmp_m), time.c (time_cmp): get rid of infinite
+ recursion.
+
+Sun Feb 17 17:23:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb: remove extra topdir in VPATH, which was in
+ win32/Makefile.sub for some reason and moved from there.
+ [ruby-dev:46998] [Bug #7864]
+
+Sun Feb 17 01:19:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * ext/psych/lib/psych/y.rb: Document Kernel#y by Adam Stankiewicz
+ [Github tenderlove/psych#127]
+
+Sun Feb 17 00:52:14 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/mkconfig.rb: remove prefix from rubyarchdir.
+ r39267 expands variables, it changes expansion timing,
+ breaks RbConfig::CONFIG["includedir"] and building
+ extension libraries with installed ruby.
+
+Sat Feb 16 20:51:17 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * vm.c (ENV_IN_HEAP_P): fix off-by-one error.
+
+Sat Feb 16 20:47:16 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * configure.in (LIBRUBY_DLDFLAGS): Fix a bug where --with-opt-dir
+ options given were not reflected to LIBRUBY_DLDFLAGS on many
+ platforms including Linux and other GNU-based systems, NetBSD,
+ AIX and BeOS.
+
+Sat Feb 16 20:43:20 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/ancdata.c (rsock_recvmsg): ignore truncated part of
+ socket address returned from recvmsg().
+
+ * ext/socket/init.c (recvfrom_blocking): ignore truncated part of
+ socket address returned from recvfrom().
+ (rsock_s_recvfrom_nonblock): ditto.
+
+Sat Feb 16 20:05:26 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * test/ruby/test_thread.rb: fixed typo
+ patched by Hiroki Matsue via https://github.com/ruby/ruby/pull/248
+
+Sat Feb 16 16:08:35 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (rb_thread_mark): mark a working Proc of bmethod
+ (a method defined by define_method) even if the method was removed.
+ We could not trace working Proc object which represents the body
+ of bmethod if the method was removed (alias/undef/overridden).
+ Simply, it was mark miss.
+ This patch by Kazuki Tsujimoto. [Bug #7825]
+
+ NOTE: We can brush up this marking because we do not need to mark
+ `me' on each living control frame. We need to mark `me's
+ only if `me' was free'ed. This is future work after Ruby 2.0.0.
+
+ * test/ruby/test_method.rb: add a test.
+
+Sat Feb 16 15:45:56 2013 Koichi Sasada <ko1@atdot.net>
+
+ * proc.c (rb_binding_new_with_cfp): create binding object even if
+ the frame is IFUNC. But return a ruby-level binding to keep
+ compatibility.
+ This patch fix degradation introduced from r39067.
+ [Bug #7774] [ruby-dev:46960]
+
+ * test/ruby/test_settracefunc.rb: add a test.
+
+Sat Feb 16 13:40:13 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (shvar_to_cpp): do not substitute exec_prefix itself
+ with RUBY_EXEC_PREFIX, which cause recursive definition.
+ [ruby-core:52296] [Bug #7860]
+
+Sat Feb 16 13:13:04 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/io/console/io-console.gemspec: bump to 0.4.2. now explicitly
+ requires ruby 1.9.3 or later. [Bug #7847]
+
+ * ext/io/console/console.c (console_dev): compatibility with ruby 1.8.
+
+ * ext/io/console/console.c (rawmode_opt, console_dev): compatibility
+ with ruby 1.9. [ruby-core:52220] [Bug #7847]
+
+Sat Feb 16 12:45:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: unexpand arch sitearch and exec_prefix values, so
+ directly specified bindir, libdir, rubyprefix, etc can be properly
+ substituted. [ruby-core:52296] [Bug #7860]
+
+Sat Feb 16 12:15:20 2013 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * parse.y: add dtrace probe for symbol create.
+
+ * probes.d: ditto
+
+Sat Feb 16 09:27:37 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: don't test sys/feature_tests.h which is not
+ used now.
+ It was included in r7901 as "bug of gcc 3.0 on Solaris 8 ?".
+
+Sat Feb 16 09:24:37 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: reorder header tests to consider inclusion
+ order in rubysocket.h.
+
+Sat Feb 16 08:42:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in, ext/socket/extconf.rb: test netinet/in_systm.h in
+ ext/socket/extconf.rb instead of configure.in.
+
+ Originally, netinet/in_systm.h is included for NextStep, OpenStep,
+ and Rhapsody. [ruby-core:1596]
+
+Sat Feb 16 07:55:40 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: don't test xti.h here.
+
+ * ext/socket/extconf.rb: test xti.h here.
+
+ Originally, xti.h is included for IRIX [ruby-core:14447].
+
+Sat Feb 16 07:16:49 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: test struct sockaddr_un and its member,
+ sun_len.
+
+ * ext/socket/sockport.h (INIT_SOCKADDR_UN): new macro defined.
+
+ * ext/socket/socket.c (sock_s_pack_sockaddr_un): use INIT_SOCKADDR_UN.
+
+ * ext/socket/unixsocket.c (rsock_init_unixsock): ditto.
+
+ * ext/socket/raddrinfo.c (init_unix_addrinfo): ditto.
+ (addrinfo_mload): ditto.
+
+Sat Feb 16 07:05:59 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/sockport.h (INIT_SOCKADDR_IN): don't need family
+ argument. it is always AF_INET.
+
+ * ext/socket/raddrinfo.c (make_inetaddr): follow INIT_SOCKADDR_IN
+ change.
+ (addrinfo_ipv6_to_ipv4): ditto.
+
+Sat Feb 16 04:21:07 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/socket/extconf.rb: workaround for mswin/mingw build problem.
+ sendmsg emulation in win32/win32.c is not enough.
+
+Sat Feb 16 00:19:20 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: use all all tested available headers for
+ have_func.
+
+Fri Feb 15 22:21:37 2013 Akinori MUSHA <knu@iDaemons.org>
+
+ * configure.in: Fix a bug introduced in r38342 that the cflagspat
+ substitution is messed up by the way CFLAGS and optflags are
+ modified, which affected FreeBSD and NetBSD/amd64 when
+ configured to use libexecinfo. This bug resulted in CFLAGS and
+ CXXFLAGS in RbConfig::CONFIG having warnflags expanded in them,
+ forcing third-party C/C++ extensions to follow what warnflags
+ demands, like ANSI/ISO-C90 conformance. ref [Bug #7101]
+
+Fri Feb 15 20:29:11 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/sockport.h (SET_SIN_LEN): defined for strict-aliasing
+ rule.
+ (INIT_SOCKADDR_IN): ditto.
+
+ * ext/socket/raddrinfo.c (make_inetaddr): use INIT_SOCKADDR_IN.
+ (addrinfo_ipv6_to_ipv4): ditto.
+
+Fri Feb 15 18:24:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (MakeMakefile#try_run): bail out explicitly if cross
+ compiling, because it cannot work of course.
+
+Fri Feb 15 12:34:58 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: test struct sockaddr_storage directly.
+
+ * ext/socket/rubysocket.h: use HAVE_TYPE_STRUCT_SOCKADDR_STORAGE.
+
+Fri Feb 15 12:26:13 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/getaddrinfo.c (GET_AI): don't cast 1st argument for
+ INIT_SOCKADDR.
+
+Fri Feb 15 08:12:11 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/sockport.h (SET_SS_LEN): removed.
+ (SET_SIN_LEN): removed.
+ (INIT_SOCKADDR): new macro.
+
+ * ext/socket/ancdata.c (extract_ipv6_pktinfo): use INIT_SOCKADDR.
+
+ * ext/socket/raddrinfo.c (make_inetaddr): use INIT_SOCKADDR.
+ (addrinfo_ipv6_to_ipv4): ditto.
+
+ * ext/socket/getaddrinfo.c (GET_AI): use INIT_SOCKADDR.
+
+Fri Feb 15 07:49:27 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc.rb: Update to release version of 4.0.0
+
+ * lib/rubygems.rb: Update to release version of 2.0.0
+
+Fri Feb 15 07:07:27 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/sockport.h (SA_LEN): removed because unused now.
+ (SS_LEN): ditto.
+ (SIN_LEN): ditto.
+
+Thu Feb 14 10:45:31 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * test/ruby/test_process.rb (test_setsid): Added a workaround for
+ MacOS X. Patch by nagachika. [Bug #7826] [ruby-core:52126]
+
+Fri Feb 15 00:15:31 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/sockport.h (VALIDATE_SOCKLEN): new macro to validate
+ sa_len member of 4.4BSD socket address.
+
+ * ext/socket/getnameinfo.c (getnameinfo): use VALIDATE_SOCKLEN,
+ instead of SA_LEN.
+
+ * ext/socket/socket.c (sock_s_getnameinfo): use VALIDATE_SOCKLEN
+ instead of SS_LEN.
+
+Thu Feb 14 22:25:54 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/socket.c (sockaddr_len): extracted from sockaddr_obj.
+ (sockaddr_obj): add an argument to length of socket address.
+ (socket_s_ip_address_list): call sockaddr_obj with actual socket
+ address length if given, use sockaddr_len otherwise.
+
+Thu Feb 14 20:11:23 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket: always operate length of socket address companion with
+ socket address.
+
+ * ext/socket/rubysocket.h (rsock_make_ipaddr): add an argument for
+ socket address length.
+ (rsock_ipaddr): ditto.
+
+ * ext/socket/ipsocket.c (ip_addr): pass length to rsock_ipaddr.
+ (ip_peeraddr): ditto.
+ (ip_s_getaddress): pass length to rsock_make_ipaddr.
+
+ * ext/socket/socket.c (make_addrinfo): pass length to rsock_ipaddr.
+ (sock_s_getnameinfo): pass actual address length to rb_getnameinfo.
+ (sock_s_unpack_sockaddr_in): pass length to rsock_make_ipaddr.
+
+ * ext/socket/init.c (rsock_s_recvfrom): pass length to rsock_ipaddr.
+ (rsock_s_recvfrom_nonblock): ditto.
+
+ * ext/socket/tcpsocket.c (tcp_sockaddr): pass length to
+ rsock_make_ipaddr.
+
+ * ext/socket/raddrinfo.c (make_ipaddr0): add an argument for socket
+ address length. pass the length to rb_getnameinfo.
+ (rsock_ipaddr): ditto.
+ (rsock_make_ipaddr): add an argument for socket address length.
+ pass the length to make_ipaddr0.
+ (make_inetaddr): pass length to make_ipaddr0.
+ a local variable renamed.
+ (host_str): a local variable renamed.
+ (port_str): ditto.
+
+Thu Feb 14 14:31:43 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/net/http.rb: Removed OpenSSL dependency from Net::HTTP.
+
+ * test/net/http/test_http.rb: Remove Zlib dependency from tests.
+ * test/net/http/test_http_request.rb: ditto.
+
+Thu Feb 14 11:08:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (include_modules_at): detect cyclic prepend with original
+ method table. [ruby-core:52205] [Bug #7841]
+
+Thu Feb 14 10:30:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_method.c: call method_removed hook on called class, not on
+ prepending iclass. [ruby-core:52207] [Bug #7843]
+
+Thu Feb 14 10:05:57 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/net/http: Do not handle Content-Encoding when the user sets
+ Accept-Encoding. This allows users to handle Content-Encoding for
+ themselves. This restores backwards-compatibility with Ruby 1.x.
+ [ruby-trunk - Bug #7831]
+ * lib/net/http/generic_request.rb: ditto.
+ * lib/net/http/response.rb: ditto
+ * test/net/http/test_http.rb: Test for the above.
+ * test/net/http/test_http_request.rb: ditto.
+ * test/net/http/test_httpresponse.rb: ditto.
+
+Thu Feb 14 08:18:47 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: don't define HAVE_SA_LEN and HAVE_SA_LEN.
+ use HAVE_STRUCT_SOCKADDR_SA_LEN and HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ instead.
+
+Wed Feb 13 20:59:48 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: don't define socklen_t here, just test.
+
+ * ext/socket/rubysocket.h: define socklen_t if not available.
+
+Wed Feb 13 18:37:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (mnew): skip prepending modules and return the method bound
+ on the given class. [ruby-core:52160] [Bug #7836]
+
+Wed Feb 13 18:11:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (method_original_name): new methods Method#original_name and
+ UnboundMethod#original_name. [ruby-core:52048] [Bug #7806]
+ [EXPERIMENTAL]
+
+ * proc.c (method_inspect): show the given name primarily, and
+ original_id if aliased. [ruby-core:52048] [Bug #7806]
+
+Wed Feb 13 17:56:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (warnflags): disable -Werror by default unless
+ development. [ruby-core:52131] [Bug #7830]
+
+Wed Feb 13 06:05:52 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems.rb: Return BINARY strings from Gem.gzip and Gem.gunzip.
+ Fixes intermittent test failures. RubyGems issue #450 by Jeremey
+ Kemper.
+ * test/rubygems/test_gem.rb: Test for the above.
+
+Wed Feb 13 05:49:21 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: test functions just after struct members.
+
+Tue Feb 12 12:02:35 2013 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/json: merge JSON 1.7.7.
+ This includes security fix. [CVE-2013-0269]
+ https://github.com/flori/json/commit/d0a62f3ced7560daba2ad546d83f0479a5ae2cf2
+ https://groups.google.com/d/topic/rubyonrails-security/4_YvCpLzL58/discussion
+
+Mon Feb 11 23:08:48 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: enable rb_cv_page_size_log test for MirOS BSD.
+
+Mon Feb 11 20:06:38 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: use -pthread on mirbsd*.
+
+Mon Feb 11 16:07:09 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: add SOLIBS and LIBRUBY_SO definition for mirbsd*.
+
+Mon Feb 11 13:17:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (rubysitearchprefix): sitearchdir and vendorarchdir
+ should use sitearch, not arch. [ruby-dev:46964] [Bug #7823]
+
+ * win32/Makefile.sub (config.status): site and vendor directories
+ should use sitearch, not arch. [ruby-dev:46964] [Bug #7823]
+
+Mon Feb 11 12:31:25 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: move OS specific header/function knowledge before
+ automatic header tests.
+
+Mon Feb 11 11:04:29 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: move the test for -march=i486 just after
+ RUBY_UNIVERSAL_ARCH/RUBY_DEFAULT_ARCH.
+
+Sun Feb 10 23:42:26 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: test structure members just after types test.
+
+Sun Feb 10 20:58:17 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: test types just after headers test.
+
+Sun Feb 10 16:00:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/rake/doc/MIT-LICENSE: Add license file from upstream
+ * lib/rake/doc/README.rdoc: Link to license file from Rake README
+ * lib/rake/version.rb: Include README rdoc for Rake module overview
+
+Sun Feb 10 15:26:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/rake/doc/*: Sync Rake rdoc files from upstream
+
+Sun Feb 10 15:50:02 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * vm_exec.h (DISPATCH_ARCH_DEPEND_WAY): use __asm__ __volatile__
+ instead of asm volatile.
+
+Sun Feb 10 15:50:02 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * gc.h (SET_MACHINE_STACK_END): use __volatile__ instead of volatile.
+
+Sun Feb 10 14:25:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * doc/rake/, lib/rake/doc/: Move Rake rdoc files to lib/rake
+
+Sun Feb 10 12:10:25 2013 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: test headers at first.
+
+Sun Feb 10 12:00:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * doc/rake/*: Removed stale Rake static files
+
+Sun Feb 10 09:10:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * lib/pp.rb, lib/prettyprint.rb: Documentation for PP and PrettyPrint
+ Based on a patch by Vincent Batts [ruby-core:51253] [Bug #7656]
+
+Sat Feb 9 21:11:21 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: move header files check to the beginning of
+ "header and library section".
+ test rlim_t with sys/types.h and sys/time.h for MirOS BSD.
+ sys/types.h and sys/time.h is guarded by #ifdef and the above
+ move is required for this change.
+
+Sat Feb 9 17:45:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in, version.c: prevent duplicated load paths by empty
+ version string, it does not work right now.
+
+Sat Feb 9 17:38:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: fix arch parameters in help message. [Bug #7804]
+
+Sat Feb 9 13:13:00 2013 Zachary Scott <zachary@zacharyscott.net>
+
+ * vm_trace.c: Note about TracePoint events set, and comment on
+ Kernel#set_trace_func to prefer new TracePoint API
+
+Sat Feb 9 10:07:47 2013 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * BSDL: update copyright notice for 2013.
+
+Sat Feb 9 09:24:38 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/package/old.rb: Fix behavior only on ruby 1.8.
+
+ * lib/rubygems/package.rb: Include checksums.yaml.gz signatures for
+ verification.
+ * test/rubygems/test_gem_package.rb: Test for the above.
+
+Sat Feb 9 01:23:24 2013 Tanaka Akira <akr@fsij.org>
+
+ * test/fiddle/helper.rb: specify libc and libm locations for MirOS BSD.
+
+ * test/dl/test_base.rb: ditto.
+
+Fri Feb 8 23:25:33 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: change CFLAGS temporally to test
+ ARCH_FLAG="-march=i486".
+
+Fri Feb 8 21:19:41 2013 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: don't define ARCH_FLAG="-march=i486" if it causes
+ compilation problem.
+
+For the changes before 2.0.0, see doc/ChangeLog-2.0.0
+For the changes before 1.9.3, see doc/ChangeLog-1.9.3
+For the changes before 1.8.0, see doc/ChangeLog-1.8.0
+
+Local variables:
+coding: us-ascii
+add-log-time-format: (lambda ()
+ (let* ((time (current-time))
+ (system-time-locale "C")
+ (diff (+ (cadr time) 32400))
+ (lo (% diff 65536))
+ (hi (+ (car time) (/ diff 65536))))
+ (format-time-string "%a %b %e %H:%M:%S %Y" (list hi lo) t)))
+indent-tabs-mode: t
+tab-width: 8
+change-log-indent-text: 2
+end:
+vim: tabstop=8 shiftwidth=2
diff --git a/doc/ChangeLog-2.2.0 b/doc/ChangeLog-2.2.0
new file mode 100644
index 0000000000..5a7dbf826d
--- /dev/null
+++ b/doc/ChangeLog-2.2.0
@@ -0,0 +1,12157 @@
+Thu Dec 25 16:01:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_file_expand_path_internal): drop characters ignored
+ by filesystem on Mac OS X.
+
+Thu Dec 25 15:36:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (replace_real_basename): get the real name and replace the
+ base name with it by getattrlist(2) if available.
+ suggested by Matthew Draper at [ruby-core:67116]. [Bug #10015]
+
+ * dir.c (glob_helper): get the real name of the whole path, not
+ only the last name.
+
+Thu Dec 25 13:59:17 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (NET_LUID): include also ifdef.h as a workaround of
+ a bug in mingw-w64 header. [ruby-core:67103] [Bug #10640]
+
+Thu Dec 25 12:47:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (gettable_gen): warn possible reference to a local
+ variable defined in a past scope.
+
+Thu Dec 25 10:09:14 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/io/console/console.c (console_dev): id_console is not a
+ constant name, use rb_const_remove() to get rid of NameError.
+
+Thu Dec 25 09:18:55 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/resolv/test_dns.rb (TestResolvDNS#test_query_ipv4_address):
+ set timeout for recvfrom because if client thread is crashed, it
+ waits infinity.
+
+Thu Dec 25 08:42:11 2014 Eric Wong <e@80x24.org>
+
+ * lib/uri/generic.rb (split_userinfo): fstring for 1-byte split
+ (set_port): reduce bytecode size
+ (check_path): reduce garbage via opt_str_freeze
+ (query=): ditto
+ (fragment=): ditto
+ [misc #10628]
+ * lib/uri/rfc3986_parser.rb (regexp): cache as attr
+ (initialize): setup and freeze regexp attr once
+ (split): reduce bytecode size, use opt_str_freeze
+ (parse): minor bytecode and garbage reduction
+ (default_regexp): rename for initialize
+
+Wed Dec 24 20:38:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (glob_make_pattern): restrict searching case-insensitive
+ name from the filesystem to only last part, for the performance.
+ [ruby-core:63591] [Bug #10015]
+
+Wed Dec 24 18:21:27 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: remove unused rb_objspace_t::rgengc::old_objects_at_gc_start.
+
+Wed Dec 24 13:25:22 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/redmine-backporter.rb: require view_changesets permission.
+
+Wed Dec 24 13:00:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/downloader.rb (Downloader.download): fix the exception to
+ re-raise. initialize methods of subclasses of Exception may
+ have different parameters. [ruby-core:67086] [Bug #10639]
+
+Wed Dec 24 12:16:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.h (rb_data_type_t): revert r48647 and revise parent member.
+ [ruby-core:66969] [Bug #10621]
+
+Wed Dec 24 05:40:52 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/downloader.rb: use config.guess in gcc repo.
+
+Wed Dec 24 11:50:19 2014 Koichi Sasada <ko1@atdot.net>
+
+ * hash.c (rb_hash_delete): return Qnil if there are no corresponding
+ entry. [Bug #10623]
+
+ * hash.c (rb_hash_delete_entry): try delete and return Qundef if there
+ are no corresponding entry.
+
+ * internal.h: add rb_hash_delete_entry()'s declaration.
+
+ * symbol.c: use rb_hash_delete_entry().
+
+ * thread.c: use rb_hash_delete_entry().
+
+ * ext/-test-/hash/delete.c: use rb_hash_delete_entry().
+
+Wed Dec 24 09:35:11 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/fiddle/extconf.rb: remove ffitarget.h generated by configure on
+ mswin, because it's not normal file (cygwin's symlink) and have
+ system attribute.
+
+Wed Dec 24 05:40:52 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/downloader.rb: support ruby 1.8.
+
+Wed Dec 24 02:44:06 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/net/http/response.rb (Net::HTTPResponse): require one or more
+ spaces [Bug #10591].
+ by leriksen <leif.eriksen.au@gmail.com>
+ https://github.com/ruby/ruby/pull/782 fix GH-782
+ NOTE: graph.facebook.com returns without SP Reason-Phrase.
+
+Wed Dec 24 02:12:22 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/make-snapshot (package): VCS#branch_list expects glob a
+ pattern string but not a regexp. based on the patch by Vit
+ Ondruch. in [ruby-core:67064]. [Bug #10636]
+
+ * tool/vcs.rb (VCS::SVN#branch_list): strip newlines.
+
+ * tool/vcs.rb (VCS::GIT.get_revisions): retrieve modified time
+ from toplevel log too.
+
+ * tool/vcs.rb (VCS::GIT#branch_list): yield for each lines.
+
+Wed Dec 24 00:23:13 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * tool/extlibs.rb (do_extract): the pipe should be binmode.
+
+Wed Dec 24 00:21:44 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * Makefile.in, common.mk: move common-srcs to Makefile.in because
+ it breaks build on mswin.
+
+Wed Dec 24 00:04:45 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/open-uri.rb (OpenURI.open_http): accept multiple certs path in
+ ssl_ca_certs.
+
+ * tool/downloader.rb: use certs of rubygems for downloading gems.
+
+Tue Dec 23 22:39:11 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/fiddle/extlibs: libffi-3.2.1 and patch for mswin.
+
+Tue Dec 23 22:04:38 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/generic.rb (URI::Generic#query=): don't escape [\]^
+ on both rfc2396 and rfc3986. [Bug #10619]
+
+Tue Dec 23 16:03:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32/lib/win32/registry.rb (Win32::Registry::Error#initialize):
+ try en_US message if the default message cannot be encoded to
+ locale. [ruby-core:65295] [Bug #10300]
+
+Tue Dec 23 11:42:14 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/openssl/ossl_cipher.c (ossl_cipher_update_long): update huge
+ data gradually not to exceed INT_MAX. workaround of OpenSSL API
+ limitation. [ruby-core:67043] [Bug #10633]
+
+Mon Dec 22 21:30:16 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * test/win32ole/test_win32ole_event.rb: some tests are
+ executed on standard Windows OS without ADO.
+
+Mon Dec 22 14:08:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (received_signal): fix condition to define.
+ [ruby-core:67032] [Bug #10629]
+
+Sun Dec 21 10:51:51 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * test/win32ole/test_win32ole_event.rb: test_s_new_exception is
+ executed on standard Windows OS without ADO.
+
+Sun Dec 21 08:35:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (jemalloc): fix option argument, should use
+ `$withval` but not `yes` always. [ruby-core:66994] [Bug #10625]
+
+ * configure.in (jemalloc): defer adding the liner option to get
+ rid of linking contest against jemalloc, so that it works
+ without runtime dynamic load path.
+
+Sat Dec 20 17:49:03 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/tmpdir.rb (Dir.mktmpdir): Accept nil again, as Ruby 2.1.
+ [ruby-core:66943] [Bug #10616] Fixed by Alex Slynko.
+
+Sat Dec 20 11:22:58 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/fiddle/depend, ext/fiddle/extconf.rb: try to build bundled
+ libffi if existing.
+
+Sat Dec 20 05:21:00 2014 Eric Wong <e@80x24.org>
+
+ * test/test_weakref.rb (test_repeated_object_leak): increase timeout
+ [Bug #10618]
+
+Fri Dec 19 22:33:13 2014 Tanaka Akira <akr@fsij.org>
+
+ * tool/update-deps: Use $(hdrdir) if possible.
+
+Fri Dec 19 22:10:00 2014 Kenta Murata <mrkn@cookpad.com>
+
+ * ext/bigdecimal/depend: Fix dependencies to make bigdecimal
+ installable by rubygems.
+
+ * ext/bigdecimal/bigdecimal.gemspec: version 1.2.6.
+
+Fri Dec 19 20:00:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (PRIsVALUE): put a space after string
+ literals not to be confused with C++11 string literal suffix.
+ https://github.com/ruby/ruby/commit/a9f3eb7#commitcomment-9040169
+
+Fri Dec 19 15:36:02 2014 Simon Genier <simon.genier@shopify.com>
+
+ * hash.c (hash_equal): prefer true than the result of implicit
+ conversion from int returned by rb_eql() to VALUE. [Fix GH-789]
+
+Thu Dec 18 17:45:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (rb_cv_binary_elf): get rid of -e option of cat
+ which is not available on BusyBox, use tr instead.
+ [ruby-core:64824] [Bug #10210]
+
+Thu Dec 18 14:25:17 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * signal.c (ruby_signal): since SIGKILL is not supported by MSVCRT,
+ should be treated before calling signal(3).
+ [Bug #10615]
+
+Wed Dec 17 12:20:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (rb_method_for_self_aref, rb_method_for_self_aset):
+ move from iseq.c to build from node instead of arrays.
+
+Wed Dec 17 10:50:09 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/gdbm/test_gdbm.rb: Added test for each_key called without a block.
+ Patch by @joeyates [fix GH-783]
+
+Wed Dec 17 10:18:42 2014 Koichi Sasada <ko1@atdot.net>
+
+ * compile.c (iseq_compile_each): check
+ iseq->compile_data->option->specialized_instruction for opt_* insn.
+
+ * test/ruby/test_iseq.rb: check no specialized_instructions option.
+
+Wed Dec 17 09:48:57 2014 Eric Wong <e@80x24.org>
+
+ * compile.c (iseq_compile_each): only emit opt_str_freeze,
+ opt_aref_with, and opt_aset_with insn when no block is given
+ [Bug #10557] [ruby-core:66595]
+ * test/ruby/test_optimization.rb (test_block_given_aset_aref):
+ new test for bug thanks to Bartosz Kopinski.
+ (test_string_freeze): additional assertion for object_id
+
+Wed Dec 17 01:06:47 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/win32/lib/Win32API.rb (Win32API#call): need to splat. hmm, when
+ was this broken?
+
+Tue Dec 16 15:18:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * iseq.c (rb_method_for_self_aref, rb_method_for_self_aset): call
+ accessor functions directly, not to be affected by [] and []=
+ methods. [ruby-core:66846] [Bug #10601]
+
+ * struct.c (define_aref_method, define_aset_method): ditto.
+
+ * vm_insnhelper.c (rb_vm_opt_struct_aref, rb_vm_opt_struct_aset):
+ direct accessors of Struct.
+
+Tue Dec 16 12:01:29 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking):
+ extend timeout seconds to 60 for RGENGC_CHECK_MODE > 0 environment.
+
+Tue Dec 16 08:53:12 2014 Eric Wong <e@80x24.org>
+
+ * tool/vcs.rb: fix Ruby 1.8 compatibility harder
+
+Tue Dec 16 07:37:18 2014 Eric Wong <e@80x24.org>
+
+ * gc.c (GC_HEAP_FREE_SLOTS): move definition to match use order
+ (RUBY_GC_HEAP_GROWTH_SLOTS): s/factor/number of slots/
+
+ * man/ruby.1: add section for GC environment variables
+ [Feature #10197]
+
+Tue Dec 16 05:41:46 2014 Eric Wong <e@80x24.org>
+
+ * tool/vcs.rb: fix Ruby 1.8 compatibility
+
+Mon Dec 15 17:51:28 2014 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/objspace.c: ObjectSpace.memsize_of(obj) returns
+ with sizeof(RVALUE). [Bug #8984]
+
+ * gc.c (obj_memsize_of): ditto.
+
+ * NEWS: add a NEWS entry.
+
+ * test/objspace/test_objspace.rb: catch up this fix.
+
+ * test/ruby/test_file_exhaustive.rb: ditto.
+
+Mon Dec 15 16:19:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_enc_str_coderange): dummy wchar, non-endianness
+ encoding string cannot be ascii only.
+ [ruby-core:66835] [Bug #10598]
+
+Sun Dec 14 20:11:42 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (primary): restore current_arg so that circular
+ reference after a method definition is also warned.
+ [ruby-core:61299] [Bug #9593]
+
+Sat Dec 13 20:41:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_trace.c (rb_postponed_job_flush): mask signal trap interrupt
+ too to defer handling after finalizers finished.
+ [ruby-core:66825] [Bug #10595]
+
+Sat Dec 13 18:33:25 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/openssl/test_pkey_ec.rb: ignored tests with old OpenSSL.
+
+Sat Dec 13 18:01:57 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (check_stack_overflow): check sp also on i386/x86_64
+ FreeBSD.
+
+Sat Dec 13 09:58:41 2014 Eric Wong <e@80x24.org>
+
+ * gc.c (define_final0): avoid duplicate blocks
+ [Bug #10537]
+ * test/test_weakref.rb (test_repeated_object_leak): new test
+
+Sat Dec 13 04:59:20 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bin/erb (ERB::Main#run): get rid of shadowing outer local
+ variables. [ruby-core:65772] [Feature #10395]
+
+Fri Dec 12 21:56:44 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * gems/bundled_gems: Upgrade to test-unit 3.0.8. assert_throw and
+ assert_nothing_thrown in test-unit 3.0.7 were broken by
+ UncaughtThrowError change introduced in Ruby 2.2.0
+ preview2. These assertions in test-unit 3.0.8 work well with
+ UncaughtThrowError in Ruby 2.2.0 preview2.
+
+Fri Dec 12 19:48:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bin/erb (ARGV.switch, ERB::Main#run): allow variables to be set
+ from the command line. [ruby-core:65772] [Feature #10395]
+
+Fri Dec 12 19:31:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/erb.rb (ERB#lineno): accessor for line number to eval.
+
+ * lib/erb.rb (ERB#location=): setter of file name and line number.
+
+Fri Dec 12 13:09:13 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_latest_gc_info): return :state field to show current
+ GC state (none/marking/sweeping).
+ [Feature #10590]
+
+Fri Dec 12 10:49:18 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_crypt): check arguments more strictly.
+ * crypt() is not for wide char strings
+ * salt bytes should not be NUL
+
+Fri Dec 12 08:16:01 2014 Matt Hoyle <matt@deployable.co>
+
+ * io.c (io_read) Fix spelling in docco for read. [Fix GH-781]
+ try > tries
+
+Thu Dec 11 19:06:01 2014 Koichi Sasada <ko1@atdot.net>
+
+ * class.c (class_alloc): Start from age == 2.
+ Class and Module objects can be living long life.
+
+ * iseq.c: Same for ISeq objects.
+
+ * gc.c (RVALUE_AGE_RESET): added.
+
+ * gc.c (newobj_of): allow to generate (age != 0) objects.
+
+ * gc.c (rb_copy_wb_protected_attribute): reset age for wb unprotected
+ objects.
+
+ * include/ruby/ruby.h: add RUBY_TYPED_PROMOTED1 as an unrecommended
+ flag.
+
+Thu Dec 11 05:37:52 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/prime.rb: Remove useless loop and block capture.
+ See [#10354]
+
+Thu Dec 11 04:27:24 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm_core.h: introduce new field
+ rb_thread_t::local_storage_recursive_hash_for_trace to store
+ recursive hash to avoid creating new recursive (nested) hashes
+ for each trace events.
+ [Bug #10511]
+
+ * vm_trace.c (rb_threadptr_exec_event_hooks_orig): use it.
+
+ * cont.c: catch up this fix.
+
+ * vm.c (rb_thread_mark): ditto.
+
+Wed Dec 10 13:39:27 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * struct.c (define_aref_method, define_aset_method): use iseq
+ VALUE instead of rb_iseq_t to prevent from GC, as RB_GC_GUARD
+ makes sense only for local variables. [Feature #10575]
+
+Wed Dec 10 09:38:40 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (exec_recursive): use the same last method name as
+ recursive_push in the error message when recursive_pop failed.
+ [ruby-core:66742] [Bug #10579]
+
+Wed Dec 10 02:48:46 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/net/http/test_https.rb
+ (TestNetHTTPS#test_certificate_verify_failure): on Windows,
+ Errno::ECONNRESET will be raised when the verify is failure at the
+ client side, and it'll be eaten by WEBrick.
+
+ * test/open-uri/test_ssl.rb (TestOpenURISSL#test_validation_failure):
+ ditto.
+
+Wed Dec 10 00:42:13 2014 Eric Wong <e@80x24.org>
+
+ * iseq.c (rb_method_for_self_aref, rb_method_for_self_aset):
+ new methods to generate bytecode for struct.c
+ [Feature #10575]
+ * struct.c (rb_struct_ref, rb_struct_set): remove
+ (define_aref_method, define_aset_method): new functions
+ (setup_struct): use new functions
+ * test/ruby/test_struct.rb: add test for struct >10 members
+ * benchmark/bm_vm2_struct_big_aref_hi.rb: new benchmark
+ * benchmark/bm_vm2_struct_big_aref_lo.rb: ditto
+ * benchmark/bm_vm2_struct_big_aset.rb: ditto
+ * benchmark/bm_vm2_struct_small_aref.rb: ditto
+ * benchmark/bm_vm2_struct_small_aset.rb: ditto
+
+Tue Dec 9 20:24:41 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * string.c: [DOC] Add missing documentation around String#chomp.
+ Patch by @stderr [ci skip][fix GH-780]
+
+Tue Dec 9 18:20:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c: [DOC] Revise documentation by Marcus Stollsteimer at
+ [ruby-core:66368]. [Bug #10526]
+
+ * #inspect: be more specific about generated string, remove
+ obsolete example.
+ * #nil?: use code examples instead of different call-seq's.
+ * #tap: clarify what is yielded.
+ * Integer(): be more specific about to_int and to_i, remove
+ reference to Ruby 1.8.
+ * Array(): fix error.
+ * Class: fix variable name style and indentation in example.
+ * improve consistency, fix typos and formatting.
+
+Tue Dec 9 12:48:32 2014 Josef Simanek <josef.simanek@gmail.com>
+
+ * vm_eval.c (rb_eval_string_wrap): [DOC] Fix `rb_eval_string_wrap`
+ documentation. It is referencing `require` instead of `load`.
+ The former does not have the optional argument. [Fix GH-779]
+
+Tue Dec 9 10:16:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_frame_last_func): return the most recent frame method
+ name.
+
+ * thread.c (recursive_list_access): use the last method name,
+ instead of the current method name which can be unset in some
+ cases, not to use a symbol by the invalid ID.
+ [ruby-core:66742] [Bug #10579]
+
+Sun Dec 7 19:36:12 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * ext/socket/basicsocket.c, ext/socket/sockssocket.c:
+ remove code for $SAFE=4.
+
+Sun Dec 7 10:20:55 2014 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc: Update to RDoc 4.2.0.
+ * test/rdoc: ditto.
+
+Sun Dec 7 09:52:30 2014 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems 2.4.5.
+ * test/rubygems: ditto.
+
+Sat Dec 6 10:05:08 2014 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap.rb: Fix undefined variable usage & refactor/DRY
+ code. Patch by @aledovsky. [Fixes GH-770]
+
+ * test/net/test_imap.rb: related test.
+
+Sat Dec 6 10:09:44 2014 Eric Wong <e@80x24.org>
+
+ * thread.c (do_select): rename parameters to avoid shadowing
+
+Sat Dec 6 09:22:45 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rake: Update to rake 10.4.2
+ * test/rake: ditto.
+
+Sat Dec 6 06:48:03 2014 Eric Wong <e@80x24.org>
+
+ * compile.c (rb_iseq_build_from_ary): remove misc handling
+
+Sat Dec 6 06:14:23 2014 Vit Ondruch <vondruch@redhat.com>
+
+ * configure.in (RUBY_LIB_VERSION): Fix --with-ruby-version
+ configuration option. get rid of quoting in config.status.
+
+ * template/verconf.h.tmpl: quote RUBY_LIB_VERSION here.
+ [ruby-core:66724] [Bug #10572]
+
+Sat Dec 6 04:33:52 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/pp.rb (File::Stat#pretty_print): some platforms (such as Windows)
+ does not have major/minor parts of device.
+
+Fri Dec 5 22:43:04 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * ext/psych/lib/psych.rb: bump version to 2.0.8
+ * ext/psych/psych.gemspec: ditto.
+ * ext/psych/psych_emitter.c: ditto.
+ * ext/psych/psych_parser.c: ditto.
+
+Fri Dec 5 17:09:09 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/option.c (inet_ntop): link aliased inet_ntop in
+ libruby on mswin not rb_w32_inet_ntop which fails to link for
+ unknown reason.
+
+Fri Dec 5 11:09:54 2014 Eric Wong <e@80x24.org>
+
+ * iseq.c (prepare_iseq_build): remove unused block_opt param
+ (rb_iseq_new_with_bopt_and_opt): remove
+ (rb_iseq_new_with_opt): inline removed function
+ (rb_iseq_new_with_bopt): remove
+ (iseq_load): adjust prepare_iseq_build call
+ [Feature #10565]
+
+Fri Dec 5 09:46:05 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_yylex): fix lex_state after tLABEL_END, should
+ be EXPR_LABELARG to be followed by "paren with arg".
+ [ruby-core:66705] [Feature #4935]
+
+Fri Dec 5 02:27:47 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb: as all extension objects including initializations
+ of ext and enc should be linked to libruby if enable-shared,
+ EXTOBJS should not be linked to main programs.
+ [ruby-core:66675] [Bug #10566]
+
+Thu Dec 4 07:06:02 2014 Eric Wong <e@80x24.org>
+
+ * compile.c (rb_iseq_build_from_exception): entry->sp is unsigned
+ (iseq_build_callinfo_from_hash): account for kw_arg
+ (iseq_build_from_ary_body): update for r35459
+ (CHECK_STRING, CHECK_INTEGER): remove unused checks
+ (int_param): new function for checking new `params' hash
+ (iseq_build_kw): new function for loading rb_iseq_param_keyword
+ (rb_iseq_build_from_ary): account for `misc' entry and general
+ structure changes
+ [Feature #8543]
+ * iseq.c (CHECK_HASH): new macro (for `misc' and `param' entries)
+ (iseq_load): account for `misc' and `params' hashes
+ (iseq_data_to_ary): add final opt to arg_opt_labels,
+ fix kw support, account for unsigned entry->sp
+ * ext/-test-/iseq_load/iseq_load.c: new ext for test
+ * ext/-test-/iseq_load/extconf.rb: ditto
+ * test/-ext-/iseq_load/test_iseq_load.rb: new test
+
+Thu Dec 4 06:56:57 2014 Eric Wong <e@80x24.org>
+
+ * iseq.c (iseq_free): avoid segfault on incomplete iseq
+ * test/ruby/test_syntax.rb (test_invalid_next): new test
+ for syntax error, not segfault
+
+Thu Dec 4 04:20:34 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * load.c (ruby_require_internal): ignore error detail, just return
+ an error.
+
+Wed Dec 3 17:13:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * encoding.c (load_encoding): use rb_require_internal instead of
+ calling rb_require_safe with protection.
+
+Wed Dec 3 16:47:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * load.c (register_init_ext, ruby_init_ext): defer running the
+ registered initialization function until required, not to enable
+ extensions which have global effects just by loading, e.g.,
+ mathn/complex and mathn/rational. fix `make test` with
+ --with-static-linked-ext.
+
+ * enc/encinit.c.erb (Init_enc): initialize encdb and transdb
+ directly.
+
+Wed Dec 3 14:51:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * load.c (ruby_require_internal): separate from rb_require_safe,
+ not to raise exceptions.
+
+ * ruby.c (process_options): remove unnatural encoding search.
+
+Wed Dec 3 14:34:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (setup_fake_str): fake string does not share another
+ string, but just should not free.
+
+Wed Dec 3 11:14:14 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (w32_spawn): `v2` is used not only for `shell` but also
+ `cmd`, so must not free before using `cmd`.
+ [ruby-core:66648] [Bug #10563]
+
+Wed Dec 3 09:48:57 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/racc/cparse/cparse.c (cparse_params_type): use typed data.
+
+Tue Dec 2 21:33:56 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: use typed data for com_hash.
+
+Tue Dec 2 15:30:30 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * array.c (rb_ary_plus): in documentation, added note about
+ inefficiency of repeated += operations.
+
+Tue Dec 2 07:20:21 2014 Eric Wong <e@80x24.org>
+
+ * iseq.c (iseq_data_to_ary): keep hidden variables
+ Thanks to wanabe [ruby-core:66566]
+
+Tue Dec 2 06:46:57 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych.rb: bumping version
+
+ * ext/psych/psych.gemspec: ditto
+
+Tue Dec 2 06:34:08 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/to_ruby.rb: support objects that are
+ marshalable, but inherit from basic object.
+ Thanks Sean Griffin <sean@thoughtbot.com>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: ditto
+
+ * test/psych/test_marshalable.rb: test for fix
+
+Tue Dec 2 06:32:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (ripper_flush_string_content): preserve the dispatched
+ results at tSTRING_CONTENT. [ruby-dev:48714] [Bug #10437]
+
+ * parse.y (regexp_contents): check in ripper only if the whole
+ content is a single regexp without interpolation.
+ [ruby-dev:48714] [Bug #10437]
+
+Tue Dec 2 06:30:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * re.c (rb_reg_region_copy): new function to try with GC if copy
+ failed and return the error.
+
+Tue Dec 2 04:43:08 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * re.c (CHECK_REGION_COPIED): onig_region_copy() can fail when
+ memory exhausted but returns nothing, so check by if allocated.
+
+Tue Dec 2 02:53:00 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (magic_comment_encoding): enable in ripper, since the
+ encoding is necessary to parse non-default encoding scripts.
+
+Tue Dec 2 02:30:25 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/generic.rb (URI::Generic.build):
+ use hostname= to detect and wrap IPv6 hosts.
+ Build is accepting URI components and users may not expect
+ that a host component needs to be wrapped with square brackets
+ since it's not providing a URI.
+ Note: initialize with arg_check => true does not wrap IPv6 hosts.
+ by Joe Rafaniello <jrafanie@redhat.com>
+ https://github.com/ruby/ruby/pull/765 fix GH-765
+
+ * test/uri/test_generic.rb: Add more tests
+
+Mon Dec 1 20:01:12 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: use typed data for WIN32OLE.
+ * ext/win32ole/win32ole.h: ditto.
+ * ext/win32ole/win32ole_event.c: ditto.
+
+Mon Dec 1 17:20:42 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/Makefile.sub (verconf.h): so depends on verconf.mk, which
+ is rebuilt by setup.mak.
+
+Mon Dec 1 11:05:46 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * proc.c: fix grammar by @BenMorganIO [fix GH-764][ci skip]
+
+Mon Dec 1 10:49:53 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * man/rake.1: Update latest man content by @aledovsky
+ [fix GH-771][ci skip]
+
+Mon Dec 1 10:42:31 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * doc/syntax/refinements.rdoc: refinements are no longer experimental.
+ patch by @gaurish [fix GH-775][ci skip]
+
+Sun Nov 30 20:05:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (regexp_contents): fix a typo. pointed out by wanabe.
+ [ruby-dev:48741] [Bug #10543]
+
+Sun Nov 30 18:55:32 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking):
+ Don't raise Interrupt.
+
+Sun Nov 30 17:11:05 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking): Use
+ assert_separately.
+
+Sun Nov 30 00:02:52 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (process_options, ruby_script): transcode script name and
+ program name to locale encoding as well as argv.
+ [ruby-dev:48752] [Bug #10555]
+
+ * ruby.c (translit_char_bin): should not use code page dependent
+ CharNext on UTF-8 string. [ruby-dev:48752] [Bug #10555]
+
+Sat Nov 29 16:53:14 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (ruby_set_argv): convert argv from UTF-8.
+
+ * win32/win32.c (rb_w32_sysinit, cmdglob, w32_cmdvector): convert
+ wide char command line to UTF-8 argv, and glob in UTF-8 so that
+ metacharacters would match multibyte characters.
+ [ruby-dev:48752] [Bug #10555]
+
+Sat Nov 29 10:49:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (win32_direct_conv, rb_w32_readdir): convert UTF-8
+ and filesystem code page by using Win32 API directly.
+
+Sat Nov 29 09:37:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (syserr_initialize): simplify message building and get
+ rid of potential invalid byte sequence.
+
+Sat Nov 29 06:09:44 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * eval_error.c (error_print): respect the encoding of the message.
+
+ * io.c (rb_write_error_str): use rb_w32_write_console() on Windows
+ if stderr is a tty.
+
+Fri Nov 28 05:10:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (--with-setup): add option to select ext/Setup file.
+
+Fri Nov 28 05:02:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dmyenc.c (Init_enc): separate from dmyext.c for statically
+ linked extension excluding encoding libraries.
+
+Thu Nov 27 21:58:30 2014 Tanaka Akira <akr@fsij.org>
+
+ * common.mk (miniprelude.c): It does not depend on prelude.rb now.
+
+Thu Nov 27 21:49:49 2014 Tanaka Akira <akr@fsij.org>
+
+ * tool/update-deps: List up files built always in the source directory
+ and source files built always in the build directory.
+
+Thu Nov 27 21:24:55 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * NEWS: add obsolete callcc.
+
+Thu Nov 27 19:59:49 2014 Koichi Sasada <ko1@atdot.net>
+
+ * compile.c (iseq_compile_each): remove duplicated line event.
+ [Bug #10449]
+
+ * test/ruby/test_settracefunc.rb: add and fix tests.
+
+Thu Nov 27 19:04:50 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm_args.c: fix backtrace location for keyword related exceptions.
+
+ For example, the following program
+ def foo(k1: 1); end # line 1
+ foo(k2: 2) # line 2
+ causes "unknown keyword: k2 (ArgumentError)".
+
+ Before this patch, the backtrace location is only line 2.
+ However, error should be located at line 1 (over line 2 in
+ stack trace). This patch fix this problem.
+
+ * class.c (rb_keyword_error_new): separate exception creation logic
+ from rb_keyword_error(), to use in vm_args.c.
+
+ * vm_insnhelper.c (rb_arg_error_new): rename to rb_arity_error_new().
+
+ * vm_args.c (argument_arity_error): rename to argument_arity_error().
+
+ * vm_args.c (argument_kw_error): added to fix backtrace.
+
+ * test/ruby/test_keyword.rb: add tests.
+
+Thu Nov 27 17:31:58 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (prelude.c): no longer depends on miniruby, since not
+ depending on rbconfig.rb.
+
+Thu Nov 27 17:12:14 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (miniprelude.c): miniruby needs no preludes.
+
+Thu Nov 27 17:10:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * template/prelude.c.tmpl: no code if no prelude code is given.
+
+Thu Nov 27 13:11:00 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (objspace_malloc_increase): enable lazy sweep on GC by malloc()
+ (malloc_increase) to make GC incrementally.
+
+ This change can increase memory consumption. Report us if you find
+ any problem.
+
+Thu Nov 27 12:46:38 2014 Tanaka Akira <akr@fsij.org>
+
+ * time.c (time_s_mkutc): [DOC] Time.utc's 10 arguments form
+ doesn't examine wday, yday, isdst and tz.
+ (time_s_mktime): [DOC] Time.mktime's 10 arguments form
+ doesn't examine wday, yday and tz.
+ Suggested by naruse.
+
+Thu Nov 27 11:45:33 2014 Eric Wong <e@80x24.org>
+
+ * iseq.c (iseq_data_to_ary): add missing GC guard
+
+Thu Nov 27 10:51:59 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm_core.h: add rb_thread_t::local_storage_recursive_hash
+ to speed up Thread#[:__recursive_key__] access.
+ [Bug #10511]
+
+ * thread.c (threadptr_local_aref): add fast path for
+ :__recursive_data__.
+
+ * thread.c (threadptr_recursive_hash, threadptr_recursive_hash_set):
+ add special accessor for recursive hash.
+
+ * cont.c: store/restore local_storage_recursive_hash.
+
+ * vm.c: init and mark local_storage_recursive_hash.
+
+ * vm_trace.c (rb_threadptr_exec_event_hooks_orig): clear and restore
+ local_storage_recursive_hash directly.
+
+Thu Nov 27 07:11:00 2014 Eric Wong <e@80x24.org>
+
+ * compile.c (iseq_calc_param_size): hoist out of iseq_set_arguments
+
+Wed Nov 26 22:28:12 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_get_kwargs, rb_extract_keywords): export
+ keyword argument functions.
+
+Wed Nov 26 21:18:40 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/inlinetest.rb: removed unused test helper.
+
+Wed Nov 26 20:47:28 2014 Masaya Tarui <tarui@ruby-lang.org>
+
+ * ext/continuation/continuation.c (Init_continuation): obsolete callcc.
+ first step of [Feature #10548].
+
+Wed Nov 26 19:57:54 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_gc.rb (test_latest_gc_info): do test separately
+ to avoid mysterious behavior.
+
+Wed Nov 26 19:54:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (constat_reset): do nothing on non-standard
+ console emulators. [ruby-core:66471] [Bug #10546]
+
+Wed Nov 26 19:44:13 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/tsort.rb: Returns an enumerator if no block is given.
+ [ruby-core:66270] [Feature #10508] Proposed by Andrey Savchenko.
+
+Wed Nov 26 17:25:45 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (f_label, f_kw, formal_argument_gen): ignore invalid
+ formal argument in keyword argument definition.
+ [ruby-dev:48742] [Bug #10545]
+
+Wed Nov 26 15:32:06 2014 Koichi Sasada <ko1@atdot.net>
+
+ * compile.c (iseq_set_sequence): use "nop" insn instead of
+ "jump to next insn".
+ https://bugs.ruby-lang.org/issues/8543#change-50085
+
+Wed Nov 26 11:01:35 2014 Eric Wong <e@80x24.org>
+
+ * iseq.c (iseq_s_compile_file): close IO when done
+
+Wed Nov 26 06:06:23 2014 Tanaka Akira <akr@fsij.org>
+
+ * common.mk: encdb.h and transdb.h depends on $(PREP).
+ So prebuild files for them in tarball are useless.
+
+Wed Nov 26 02:08:44 2014 Tanaka Akira <akr@fsij.org>
+
+ * tool/make-snapshot: Don't generate enc/trans/newline.c in tarball.
+
+Wed Nov 26 00:41:44 2014 Tanaka Akira <akr@fsij.org>
+
+ * common.mk (prereq): Don't depends on prelude.c and golf_prelude.c.
+ Since they depend on $(PREP) which is miniruby, they are rebuilt
+ after miniruby is built, even if tarball contains them.
+
+Wed Nov 26 00:20:48 2014 Tanaka Akira <akr@fsij.org>
+
+ * template/prelude.c.tmpl: Don't expand RbConfig::Config[...].
+ It is not used now.
+
+ * common.mk: prelude.c and golf_prelude.c doesn't depend on rbconfig.
+
+Tue Nov 25 17:07:06 2014 Koichi Sasada <ko1@atdot.net>
+
+ * NEWS: add an "Implementation changes" section.
+
+Tue Nov 25 16:09:28 2014 Eric Hodel <drbrain@segment7.net>
+
+ * lib/net/http.rb: Do not attempt SSL session resumption when the
+ session is expired. [Bug #10533]
+
+Tue Nov 25 15:59:46 2014 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rake: Update to rake 10.4.0
+ * test/rake: ditto.
+ * NEWS: ditto.
+
+ * test/lib/minitest/unit.rb: Add compatibility shim for minitest 5.
+ This only provides minitest 5 unit test naming compatibility.
+
+Tue Nov 25 15:26:33 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/vcs.rb (get_revisions): use Time.new instead of Time.mktime
+ which does not accept UTC offset, and offset manually for older
+ versions than 1.9.
+
+Tue Nov 25 12:14:43 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (Init_process): initialize static IDs before constant
+ definitions. [ruby-core:66445]
+
+Tue Nov 25 10:32:23 2014 Eric Wong <e@80x24.org>
+
+ * compile.c (iseq_build_callinfo_from_hash): hoist out
+ (iseq_build_from_ary_body): shorten callinfo case
+
+Mon Nov 24 23:03:21 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * gems/bundled_gems: Update to test-unit 3.0.7.
+
+Mon Nov 24 12:44:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (check_exec_redirect_fd, check_exec_redirect),
+ (rb_execarg_addopt): get rid of inadvertent ID pindown.
+
+Mon Nov 24 02:03:40 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_setter): preserve encoding of global variable
+ name in error message.
+
+Mon Nov 24 02:03:30 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * iseq.c (rb_insn_operand_intern): preserve encoding of method
+ name in CALL_INFO at disassembling.
+
+Mon Nov 24 02:02:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (must_respond_to): preserve encodings of variable name and
+ class name in warning message.
+
+Sun Nov 23 10:46:23 2014 Eric Wong <e@80x24.org>
+
+ * internal.h (struct rb_execarg): 160 => 144 bytes on x86-64
+ * ruby.c (struct load_file_arg): 48 => 40 bytes on x86-64
+ * vm_args.c (struct args_info): ditto
+
+Sun Nov 23 07:46:54 2014 Andy Maloney <asmaloney@gmail.com>
+
+ * io.c (rb_io_sysread): Remove redundant assignment of 'n'.
+ [Fix GH-767]
+
+Sat Nov 22 09:48:33 2014 Tanaka Akira <akr@fsij.org>
+
+ * tool/make-snapshot: Specify PWD macro for make.
+ PWD environment variable may not exist.
+
+Fri Nov 21 11:58:58 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * lib/resolv.rb: fall back if canonicalization fails.
+ Thanks Vit Ondruch for the patch! [ruby-core:65836]
+
+ * test/resolv/test_dns.rb: test for patch
+
+Sat Nov 22 01:11:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_mod_const_get, rb_mod_const_defined): ditto.
+
+ * variable.c (rb_const_missing, rb_mod_const_missing): call
+ const_missing without new ID to get rid of inadvertent ID
+ creation.
+
+Fri Nov 21 19:32:57 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * common.mk (ext/ripper/ripper.c): revert about srcdir and top_srcdir.
+
+ * common.mk (ext/ripper/ripper.c): use $(PWD) for Unix,
+ $(MAKEDIR) for Windows.
+
+Fri Nov 21 18:12:37 2014 Tanaka Akira <akr@fsij.org>
+
+ * tool/update-deps: Refactored.
+
+Fri Nov 21 14:25:40 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/Makefile.sub (top_srcdir): added because lacking this macro
+ causes build error at r48526.
+
+Fri Nov 21 12:00:58 2014 Tanaka Akira <akr@fsij.org>
+
+ * tool/update-deps (in_makefile): Use FILES_NEED_VPATH and
+ FILES_CONFUSING.
+
+ * ext/objspace/extconf.rb: Add VPATH for id.h
+
+Fri Nov 21 09:10:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (ext/ripper/ripper.c): fix dependencies for the case
+ to make ripper.y and id.h under the build directory.
+
+Fri Nov 21 08:42:21 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * common.mk (ext/ripper/ripper.c): id.h in VPATH may exist in the build
+ directory.
+
+ * common.mk (ext/ripper/ripper.c): $(RM) was not defined.
+
+Fri Nov 21 00:36:09 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/openssl/lib/openssl/x509.rb
+ (OpenSSL::X509::Name::RFC2253DN::StringChar): get rid of a false
+ positive assertion in ripper's test.
+
+Fri Nov 21 00:29:51 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/net/imap.rb (Net::IMAP::ResponseParser::BEG_REGEXP): no need to
+ use embed string.
+
+Fri Nov 21 00:19:17 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/uri/mailto.rb (URI::MailTo::EMAIL_REGEXP): should escape `#`.
+
+Thu Nov 20 23:17:11 2014 Tanaka Akira <akr@fsij.org>
+
+ * tool/update-deps: Insert all dependencies found by compiler.
+
+Thu Nov 20 15:51:01 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/nkf/depend (nkf.o): add nkf.c as dependency.
+ bsdmake tries to make nkf.o with nkf-utf8/nkf.c without this.
+
+Thu Nov 20 08:54:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (struct parser_params): reduce size by reordering
+ members and an unused member.
+
+Thu Nov 20 02:44:27 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Vector#independent? and associated class method
+ patch by gogo tanaka [#10451]
+
+Thu Nov 20 02:32:34 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Add Vector#angle_with
+ Patch by Egunov Dmitriy [#10442]
+
+Thu Nov 20 02:10:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (ripper_flush_string_content, parser_parse_string):
+ preserve parsed string content. [ruby-dev:48714] [Bug #10437]
+
+ * parse.y (ripper_new_yylval): abstract function to create ripper
+ wrapper, and make it able to hold another object.
+
+Thu Nov 20 01:00:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (reg_named_capture_assign_gen): use predefined ID
+ instead of rb_intern.
+
+Thu Nov 20 00:54:57 2014 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (ruby_init_setproctitle): Declare here.
+
+Thu Nov 20 00:26:37 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_here_document): append byte sequence directly to
+ the delayed content instead of creating an intermediate string
+ object.
+
+Wed Nov 19 21:11:01 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * common.mk (ext/json/parser/parser.c): don't touch parse.c,
+ ruby repo is a downstream.
+
+Wed Nov 19 20:38:11 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * common.mk (ext/ripper/ripper.c): use $(PWD) to get
+ <build-directory>/ext/ripper.
+
+Wed Nov 19 18:12:17 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/downloader.rb (RubyGems.download): Don't download gem if the
+ version is already downloaded. A gem file is versioned and
+ it must be identical if the version is the same.
+
+Wed Nov 19 17:59:25 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * common.mk (ext/ripper/ripper.c): pass build directory as VPATH.
+
+ * ext/ripper/depend (.y.c): use VPATH for y.tab.c.
+
+Wed Nov 19 10:07:57 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * template/prelude.c.tmpl (Prelude#translate): strip VPATH prefix
+ from prelude names, so that srcdir differences do not make the
+ generated code different.
+
+Wed Nov 19 07:45:11 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_write): should set the error of
+ GetOverlappedResult()'s, not WriteFile()'s (it's always
+ ERROR_IO_PENDING, of course).
+
+Tue Nov 18 14:16:47 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_record): add information for debug print.
+
+Wed Nov 19 04:49:07 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * debug.c (set_debug_option): need the declaration.
+
+ * debug.c (set_debug_option): use the same macro with the implementation
+ at win32/win32.c.
+
+Wed Nov 19 04:16:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (symbol_list): fix the node type of literal symbol list
+ with no interpolation. [ruby-core:66343]
+
+Wed Nov 19 00:26:15 2014 Tanaka Akira <akr@fsij.org>
+
+ * tool/update-deps: Sort dependencies.
+
+Wed Nov 19 00:24:18 2014 Tanaka Akira <akr@fsij.org>
+
+ * enc/encdb.c: Include internal.h.
+
+Tue Nov 18 23:23:45 2014 Tanaka Akira <akr@fsij.org>
+
+ * internal.h: Gather declarations in non-header files.
+
+Tue Nov 18 23:45:52 2014 Tanaka Akira <akr@fsij.org>
+
+ * debug.c (SET_WHEN): Don't declare debug variables here.
+ ruby_initial_gc_stress_ptr is changed int* to VALUE* at r41406.
+
+ * internal.h (ruby_initial_gc_stress_ptr): Declared.
+ (ruby_enable_coredump): Ditto.
+
+Tue Nov 18 18:06:43 2014 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/io.h (FMODE_WSPLIT): Removed. The write() system call
+ is not required to split. It was useful to avoid whole process
+ blocking in Ruby 1.8 but not useful since write() is invoked without
+ GVL.
+ (FMODE_WSPLIT_INITIALIZED): Ditto.
+
+ * io.c (wsplit_p): Removed.
+ (io_writable_length): Removed.
+ (rb_fcntl): Don't update the removed flags.
+
+Tue Nov 18 03:23:06 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (check_setter_id): show the original argument instead
+ of nil on TypeError.
+
+Tue Nov 18 03:20:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * symbol.h (is_{local,global,instance,attrset,const,class,junk}_sym):
+ fix ID type names.
+
+Mon Nov 17 20:17:59 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_event.c: use typed data.
+
+Mon Nov 17 12:54:56 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rubygems/*, test/rubygems/*: Update to RubyGems 2.4.4
+ master (2f6e42e).
+
+Mon Nov 17 06:13:06 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (proc_binding): use the original iseq on a binding from
+ proc from method object to get the location.
+
+Sun Nov 16 19:38:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (rb_current_receiver): new function to return the
+ receiver in the current control frame. [Feature #10195]
+
+Sun Nov 16 19:11:04 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/timeout.rb (Timeout::ExitException#exception): rescue
+ UncaughtThrowError which is specific for throw, instead of
+ ArgumentError.
+
+Sun Nov 16 18:22:18 2014 Eric Wong <e@80x24.org>
+
+ * tool/update-deps: warning to disable ccache
+
+Sun Nov 16 13:11:35 2014 Tanaka Akira <akr@fsij.org>
+
+ * common.mk (CCAN_LIST_INCLUDES): Unused variable removed.
+ (ENCODING_H_INCLUDES): Ditto.
+ (PROBES_H_INCLUDES): Ditto.
+ (VM_CORE_H_INCLUDES): Ditto.
+
+Sun Nov 16 11:07:25 2014 Eric Wong <e@80x24.org>
+
+ * test/ruby/test_io.rb (test_readpartial_locktmp):
+ remove unnecessary begin/end
+
+Sun Nov 16 00:45:23 2014 Tanaka Akira <akr@fsij.org>
+
+ * common.mk: Specify dependencies for generated C sources.
+
+Sat Nov 15 23:10:45 2014 Tanaka Akira <akr@fsij.org>
+
+ * common.mk: No need to declare dependencies which
+ will be detected by inference rules.
+
+Sat Nov 15 20:34:23 2014 Tanaka Akira <akr@fsij.org>
+
+ * internal.h: Include ruby.h and ruby/encoding.h to be
+ includable without prior inclusion.
+
+Sat Nov 15 20:46:44 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_document.rb
+ (REXMLTests::TestDocument::EntityExpansionLimitTest):
+ Group tests by general entity and parameter entity.
+
+Sat Nov 15 20:43:31 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_document.rb
+ (REXMLTests::TestDocument::EntityExpansionLimitTest): Define
+ test XML in each test method because (1) each XML in used only
+ one test and (2) related data and code should be close.
+
+Sat Nov 15 20:39:06 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_document.rb
+ (REXMLTests::TestDocument::EntityExpansionLimitTest): Use
+ one test method for one test.
+
+Sat Nov 15 20:16:59 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_document.rb
+ (REXMLTests::TestDocument::EntityExpansionLimitTest): Use
+ setup and teardown instead of ensure in test.
+
+Sat Nov 15 20:11:34 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_document.rb (REXMLTests::TestDocument): Group
+ entity expansion limit related tests.
+
+Sat Nov 15 20:09:00 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_document.rb (REXMLTests::TestDocument::BomTest):
+ Fix wrong parent class. It doesn't need inherit tests in
+ TestDocument class.
+
+Sat Nov 15 19:48:59 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/mkmf.rb (depend_rules): support comments during a line.
+
+ * lib/mkmf.rb (depend_rules): apply RULE_SUBST even if the dependency
+ file contains path.
+
+Sat Nov 15 19:25:46 2014 Tanaka Akira <akr@fsij.org>
+
+ * common.mk: Remove comments in Dependency lines.
+ Notified by usa.
+
+ * enc/depend: Ditto.
+
+ * ext/**/depend: Ditto.
+
+Sat Nov 15 16:28:05 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (rb_throw_obj): throw UncaughtThrowError instead of
+ ArgumentError. [Feature #10480]
+
+Sat Nov 15 14:13:38 2014 Tanaka Akira <akr@fsij.org>
+
+ * tool/update-deps: Extend to fix dependencies.
+
+ * common.mk: Dependencies updated by tool/update-deps.
+
+ * enc/depend: Ditto.
+
+ * ext/**/depend: Ditto.
+
+Fri Nov 14 17:36:48 2014 Tanaka Akira <akr@fsij.org>
+
+ * tool/update-deps: Support GNU Make 4.0.
+
+Fri Nov 14 16:59:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (default_proc_for_compat_func): check arguments number and
+ type, and get rid of reentering this default proc.
+
+Fri Nov 14 16:33:06 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat_internal): support compatible layer for
+ GC.stat(symbol) type access.
+
+Fri Nov 14 16:19:08 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat_internal): add compatible layer.
+ From Ruby 2.2, keys of GC.stat are changed [Feature #9924].
+ To provide compatible layer, GC.stat add a default_proc
+ (if default_proc of given Hash object is not set).
+
+ At first use of this compatible layer of interpreter process,
+ show a warning message like that:
+ program: GC.stat[:total_allocated_object]
+ warning message: "warning: GC.stat keys were changed from Ruby
+ 2.1. In this case, you refer to obsolete `total_allocated_object'
+ (new key is `total_allocated_objects').
+ Please check <https://bugs.ruby-lang.org/issues/9924>
+ for more information."
+
+ Please correct my English message :)
+
+ * hash.c (rb_hash_set_default_proc): export (in internal).
+
+ * internal.h: ditto.
+
+Fri Nov 14 10:41:25 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: guard by #if/#endif with GC_ENABLE_INCREMENTAL_MARK
+ to hide unused codes.
+
+ * gc.c: similar to GC_ENABLE_LAZY_SWEEP.
+
+Fri Nov 14 10:23:35 2014 Eric Wong <e@80x24.org>
+
+ * vm_eval.c (rb_eval_cmd): use pre-defined idCall
+
+Fri Nov 14 09:25:44 2014 Eric Wong <e@80x24.org>
+
+ * vm_eval.c (rb_yield_splat): add missing GC guard
+ [Bug #10509]
+
+Fri Nov 14 08:12:40 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * gc.c: fix build error caused by implicit conversion with clang.
+
+Fri Nov 14 06:54:06 2014 Eric Wong <e@80x24.org>
+
+ * insns.def (opt_succ): remove Time#succ optimization
+ [Feature #10501]
+
+Fri Nov 14 05:29:46 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: refactoring.
+
+ * gc.c: use GC_ENABLE_INCREMENTAL_MARK instead of USE_RINCGC.
+
+ * gc.c (gc_start): check FORCE_MAJOR_GC.
+
+Fri Nov 14 04:51:18 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: Tuning RincGC parameters.
+
+ Before this patch, gc_marks_step() marks (white -> grey) fixed
+ number objects. However, this strategy does not fit practical
+ cases, for example too slow to make progress.
+
+ This patch changes this strategy how many objects the
+ gc_marks_step() should handle.
+
+ We can estimate how many times gc_marks_step() is called during
+ this major marking (== C) with the free slot number in pooled
+ pages. We also can estimate the living object number (== L)
+ using last marked_slots value. We can solve this problem (how
+ many objects should be process in gc_marks_step()) by L/C.
+
+ * gc.c (rb_objspace_t): add rb_objspace_t::rincgc::pooled_slots and
+ step_slots.
+
+Fri Nov 14 01:26:47 2014 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap.rb (search_response): parse MODSEQ in SEARCH
+ responses properly. [ruby-core:64203] [Bug #10112]
+
+Fri Nov 14 01:03:17 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/envutil.rb: Moved from test/ruby/.
+
+ * test/lib/find_executable.rb: Ditto.
+
+ * test/lib/memory_status.rb: Ditto.
+
+ * test/lib/test/unit.rb: require envutil.
+
+ * test/: Don't require envutil in test files.
+
+Thu Nov 13 21:59:58 2014 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * lib/rexml/document.rb: add REXML::Document#document.
+ reported by Tomas Hoger <thoger@redhat.com> and patched by nahi.
+
+Thu Nov 13 21:51:56 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/monitor/test_monitor.rb: Use assert_join_threads.
+
+Thu Nov 13 21:45:13 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/openssl: Don't specify port number.
+
+Thu Nov 13 21:22:35 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/openssl/ssl_server.rb: Unused file removed.
+ It is not used since r16111, Ruby 1.9.1.
+
+Thu Nov 13 18:50:14 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_ensure): remove obsolete prot_tag comment. patch by
+ Jack Danger at [ruby-core:66238]. [misc #10502]
+
+Thu Nov 13 18:10:38 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm.c (rb_vm_make_proc_lambda): similar to rb_vm_make_proc() with
+ is_lambda argument.
+
+Thu Nov 13 12:11:18 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_fstat{,i64}): speed up. adjusting
+ timestamps in this function is to get rid of the side effect of
+ ENV["TZ"]. then, if ENV["TZ"] is not set, no need to adjust.
+ this change makes File#stat about 60% faster.
+
+Thu Nov 13 11:56:12 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * st.c: include "internal.h" for STATIC_ASSERT.
+
+Thu Nov 13 03:56:38 2014 Eric Wong <e@80x24.org>
+
+ * gc.c (struct heap_page): trivial packing
+ 304 => 296 bytes on x86-64
+
+Wed Nov 12 22:50:12 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * gems/bundled_gems: Update to test-unit 3.0.6 and minitest 5.4.3.
+
+Wed Nov 12 22:30:52 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rubygems/*: Update to RubyGems 2.4.3 master (7b1f684).
+
+Wed Nov 12 00:26:37 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_object.rb: Specify an exception class for rescue clause.
+
+ * test/dbm/test_dbm.rb: Ditto.
+
+ * test/gdbm/test_gdbm.rb: Ditto.
+
+ * test/sdbm/test_sdbm.rb: Ditto.
+
+Tue Nov 11 23:43:51 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/fileutils/test_fileutils.rb: Use assert_join_threads.
+
+Tue Nov 11 22:51:14 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/resolv/test_dns.rb: Use assert_join_threads.
+
+Tue Nov 11 22:33:08 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/net/pop/test_pop.rb: Use assert_join_threads.
+
+Tue Nov 11 22:07:20 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/net/http/test_https_proxy.rb: Use assert_join_threads.
+
+Tue Nov 11 18:09:11 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * template/prelude.c.tmpl: move from tool/compile_prelude.rb and
+ expand by generic_erb.rb.
+
+Tue Nov 11 13:01:31 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/rubygems/commands/contents_command.rb (files_in_default_gem):
+ remove useless sort. show_files will sort the result and
+ another branch, files_in_gem, doesn't sort.
+ it should be removed for consistency.
+
+ * test/rubygems/test_gem_commands_contents_command.rb
+ (test_execute_default_gem): adjust the sort algorithm with
+ Gem::Commands::ContentsCommand#show_files, which sort items
+ as array of [prefix, basename] not strings.
+
+Tue Nov 11 10:37:09 2014 Koichi Sasada <ko1@atdot.net>
+
+ * string.c (sym_equal): use rb_obj_equal().
+ rb_obj_equal() is specially optimized in
+ opt_eq_func()@vm_insnhelper.c.
+
+ This fix is made from this discussion:
+ https://www.omniref.com/ruby/2.1.4/symbols/Symbol/%3D%3D#line=8361.
+
+Tue Nov 11 09:38:55 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rdoc/known_classes.rb: reverted regression changes of
+ rdoc known class.
+
+Tue Nov 11 00:21:50 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/net/imap/test_imap.rb: Don't ignore exceptions on server
+ threads.
+
+Mon Nov 10 23:34:13 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/net/ftp/test_ftp.rb (create_ftp_server): Don't ignore
+ exceptions on server thread.
+ Delete read_timeout method call to fix NoMethodError.
+
+Mon Nov 10 20:20:53 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_read): retry with reduced length if cannot to
+ write any data but no error occurs.
+
+Mon Nov 10 20:04:16 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/webrick/server.rb: Setup shutdown pipe in listen method.
+
+Mon Nov 10 19:37:09 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c, include/win32/win32.h (rb_w32_set_nonblock): new
+ function to support nonblock-mode of pipes.
+
+ * win32/win32.c (rb_w32_read): nonblock-mode pipe returns ERROR_NO_DATA
+ if there is no data, but also returns it if remote-end is closed.
+
+ * win32/win32.c (rb_w32_write): if cannot to write any data, it may be
+ blocking.
+
+ * io.c (rb_io_set_nonblock): use rb_w32_set_nonblock for Windows.
+
+ * ext/io/nonblock/nonblock.c (rb_io_nonblock_set): use ruby's API when
+ setting nonblock-mode.
+
+ * test/ruby/test_io.rb: test nonblock pipes on Windows.
+
+Mon Nov 10 17:24:34 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/etc/etc.c (etc_getlogin): set login name encoding properly.
+ [ruby-core:66163] [Bug #10493]
+
+Mon Nov 10 16:20:42 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rubygems/*.rb: Update to RubyGems master(3e36528).
+
+Mon Nov 10 16:09:43 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (rb_f_kill): [DOC] mention known signal list.
+ [ruby-core:66162] [Bug #10492]
+
+Mon Nov 10 14:17:58 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rdoc/*.rb: Update to RDoc 4.2.0.alpha(579a11c)
+
+Mon Nov 10 12:44:39 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/webrick/server.rb: Less instance variables.
+
+Mon Nov 10 12:19:43 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/webrick/server.rb (shutdown): Use close() on @shutdown_pipe_w to
+ notify readability on the read side of the pipe.
+ write_nonblock() is not usable for pipe on Windows.
+ (cleanup_shutdown_pipe): Rescue IOError for @shutdown_pipe_w.close.
+
+Mon Nov 10 07:31:59 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/webrick/server.rb (initialize): Initialize shutdown pipe here
+ to avoid race condition.
+ (cleanup_shutdown_pipe): New private method.
+ (cleanup_listener): Extracted from shutdown method.
+ Call this method from start method to avoid race condition.
+
+Mon Nov 10 05:57:53 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/webrick/webrick.cgi: Don't use debug mode.
+
+ * test/webrick/webrick_long_filename.cgi: Ditto.
+
+Sun Nov 9 23:25:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (vm_call_super): allow bound proc method to call super
+ method.
+
+ * vm_insnhelper.c (vm_yield_with_cfunc): push defined class and
+ bound proc method entry to the control frame.
+
+Sun Nov 9 22:46:13 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/open-uri: Test server log in server thread.
+
+ * test/webrick: Ditto.
+
+Sun Nov 9 22:28:34 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/webrick/httpstatus.rb: require webrick/accesslog for AccessLog.
+
+Sun Nov 9 21:03:59 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/webrick: Fix the argument order of assert_equal.
+
+Sun Nov 9 20:29:01 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/webrick: Store log in an array.
+
+ * test/net/http: Ditto.
+
+ * test/open-uri: Ditto.
+
+Sun Nov 9 18:35:36 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/xmlrpc: Refine log test.
+
+Sun Nov 9 18:33:33 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize/normalize.rb: Replaced if-else by
+ case in self.normalized? in parallel to r48309.
+
+Sun Nov 9 18:07:00 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/xmlrpc: Use assert_join_threads.
+
+Sun Nov 9 14:06:13 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/xmlrpc: Test webrick error log is empty.
+
+Sun Nov 9 13:47:02 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (is_incremental_marking): use #if/#else because
+ rb_objspace_t::flags::during_incremental_marking is not defined
+ when GC_ENABLE_INCREMENTAL_MARK is 0.
+
+ * gc.c (will_be_incremental_marking, is_full_marking): similar fix.
+
+Sun Nov 9 12:16:22 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/securerandom.rb (SecureRandom.gen_random): separate
+ implementation details and select at the load time.
+
+Sun Nov 9 12:09:38 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32/lib/win32/registry.rb (Win32::Registry::API#Enum{Value,Key):
+ ditto.
+
+Sun Nov 9 11:48:40 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/net/http: Examine webrick log.
+
+Sun Nov 9 11:45:19 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * gems/bundled_gems: upgraded to test-unit 3.0.5.
+
+Sun Nov 9 11:40:50 2014 Tanaka Akira <akr@fsij.org>
+
+ * defs/known_errors.def: More errors for FreeBSD.
+
+Sun Nov 9 11:25:11 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * gems/bundled_gems: upgraded to power_assert 0.2.0.
+
+Sun Nov 9 10:31:03 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/securerandom.rb: set the script encoding to make a string
+ literal in SecureRandom::Kernel32.last_error_message single byte
+ encoding so msg[] works in bytes, since FormatMessage() returns
+ the size in TCHARs, not in characters.
+
+Sun Nov 9 09:50:22 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/webrick: Refine log tests.
+
+Sun Nov 9 08:58:05 2014 Tanaka Akira <akr@fsij.org>
+
+ * defs/known_errors.def (EHWPOISON): New errno symbol.
+ It is defined by glibc-2.16.
+
+Sun Nov 9 05:00:23 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/securerandom.rb (initialize): call the special method for Win32
+ before checking `/dev/urandom` because we know windows doesn't have it.
+
+Sun Nov 9 04:01:46 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/securerandom.rb (SecureRandom::AdvApi32): split from `initialize`.
+ thanks @zzak to remember it.
+
+Sun Nov 9 02:05:33 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/net/http/utils.rb: Don't connect to spawned server
+ before actual test.
+
+Sun Nov 9 01:51:50 2014 Benoit Daloze <eregontp@gmail.com>
+
+ * object.c (Module#const_defined?): [DOC] Revise the documentation.
+ Patch by Xavier Noria.
+ [Fixes GH-754] https://github.com/ruby/ruby/pull/754
+
+Sun Nov 9 00:37:44 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/webrick: Examine log and use assert_join_threads.
+
+Fri Nov 7 00:00:12 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * template/unicode_norm_gen.tmpl: expand kompatible_table so that
+ recursive expansion is not needed at runtime.
+
+Thu Nov 6 23:58:40 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * pack.c (pack_pack): escape unprintable characters and preserve
+ the encoding of warning message.
+
+Thu Nov 6 23:55:18 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (sym_printable): QUOTE() should not raise an exception
+ even on invalid byte sequence.
+
+Thu Nov 6 21:44:36 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/test_unicode_normalize.rb: Rename TestNormalize to
+ TestUnicodeNormalize.
+ Define constants under TestUnicodeNormalize.
+
+Thu Nov 6 21:22:59 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/open-uri/test_open-uri.rb: Check empty webrick log.
+
+Thu Nov 6 19:27:34 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * re.c (unescape_nonascii): cast -1 for the case char is unsigned char.
+ If char is signed char, for example gcc for ARM or ppc64, it caused
+ infinite loop.
+ http://kmuto.jp/build-ruby/arm/ruby-trunk/log/20141106T013005Z.fail.html.gz
+ http://rubyci.blob.core.windows.net/f19p8/ruby-trunk/log/20141106T090217Z.fail.html.gz
+
+Thu Nov 6 09:53:18 2014 Eric Wong <e@80x24.org>
+
+ * lib/uri/rfc2396_parser.rb (initialize): reduce bytecode size
+ 2088 => 1332 bytes on 32-bit x86
+
+Thu Nov 6 08:49:49 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize/normalize.rb: Comment clarification.
+
+Wed Nov 5 23:43:24 2014 Naohisa Goto <ngotogenome@gmail.com>
+
+ * compile.c (compile_data_alloc): add padding when strict alignment
+ is required for memory access. Currently, the padding is enabled
+ only when the CPU is 32-bit SPARC and the compiler is GCC.
+ [Bug #9681] [ruby-core:61715]
+
+ * compile.c (STRICT_ALIGNMENT): defined if strict alignment is required
+
+ * compile.c (ALIGNMENT_SIZE, ALIGNMENT_SIZE_MASK, PADDING_SIZE_MAX):
+ new macros for alignment word size, bit mask, max size of padding.
+
+ * compile.c (calc_padding): new function to calculate padding size.
+
+Wed Nov 5 23:24:45 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/open-uri/test_open-uri.rb: Don't ignore webrick's log.
+
+Wed Nov 5 19:20:08 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/webrick/server.rb: Stop listener loop properly.
+ [ruby-core:66085] [Bug #10478] Fixed by Charles Nutter.
+
+Wed Nov 5 17:20:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/intern.h (rb_disable_super, rb_enable_super): warn
+ as deprecated at build time, instead of ignoring silently or
+ warning at runtime only.
+
+Wed Nov 5 16:55:52 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (rb_f_lambda): remove deprecated function, which has been
+ unavailable from extension libraries.
+
+Wed Nov 5 16:26:58 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/intern.h (rb_clear_cache): mark as deprecated, not
+ only warnings at runtime.
+
+Wed Nov 5 15:05:12 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_{,l,r}strip_bang): rb_str_subseq() will not
+ NUL-terminate the result string, in the future, so it will not
+ be needed in other cases.
+
+Wed Nov 5 14:11:30 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (lib/unicode_normalize/tables.rb): do nothing unless
+ BASERUBY is available. MINIRUBY cannot load extension libraries,
+ so cannot update Unicode data.
+
+Wed Nov 5 12:13:54 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_lstrip, rb_str_strip): reduce memory copy by
+ copying necessary part only.
+
+ * string.c (rb_str_strip_bang, rb_str_strip): ditto.
+
+Wed Nov 5 12:13:48 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_lstrip, rb_str_strip): reduce memory copy by
+ copying necessary part only.
+
+ * string.c (rb_str_strip_bang, rb_str_strip): ditto.
+
+Wed Nov 5 10:54:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_lstrip_bang, rb_str_rstrip_bang): terminate
+ wchar strings with wchar 0.
+
+Tue Nov 4 21:23:22 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/win32/lib/Win32API.rb: Fiddle::Importer is defined in
+ fiddle/import.rb and it's not loaded implicitly.
+
+ * ext/win32/lib/Win32API.rb (Win32API#initialize): `import` is a string.
+
+ * ext/win32/lib/Win32API.rb (Win32API#initialize):
+ Fiddle::Importer::CALL_TYPE_TO_ABI is private constant.
+
+Tue Nov 4 21:20:07 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/securerandom.rb (SecureRandom.random_bytes): use fiddle directly
+ instead of using Win32API.
+
+Tue Nov 4 21:04:30 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/rubygems/test_gem_request_set_lockfile.rb
+ (test_relative_path_from): driveletter support.
+
+Tue Nov 4 16:23:57 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/rubygems/test_gem_remote_fetcher.rb (RemoteFetcherCleanup):
+ close all pooled connections for each tests to fix leaked file
+ descriptors.
+
+Tue Nov 4 12:51:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (PRIsVALUE), vsnprintf.c (BSD_vfprintf): add
+ RUBY_PRI_VALUE_MARK to reduce danger of accidental conflict with
+ plain "%i". binary incompatible with extension libraries using
+ PRIsVALUE and built for 2.1 and earlier. [EXPERIMENTAL]
+
+Tue Nov 4 12:33:44 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * object.c: fix document of Kernel#String by @suzukaze
+ [fix GH-743][ci skip]
+
+Tue Nov 4 12:21:45 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/csv.rb: added documentation for skip_blanks option by @decasia
+ [fix GH-744][ci skip]
+
+Tue Nov 4 12:09:18 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/open3.rb: fix code formatting in documentation by @JoshCheek
+ [fix GH-747][ci skip]
+
+Tue Nov 4 08:57:37 2014 Eric Wong <e@80x24.org>
+
+ * encoding.c (enc_memsize): remove unnecessary function
+ [ruby-core:65304]
+
+Mon Nov 3 18:09:39 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/openssl/utils.rb: The default of :ignore_listener_error is
+ changed to false.
+
+Mon Nov 3 14:42:37 2014 Koichi Sasada <ko1@atdot.net>
+
+ * iseq.c (iseq_free): resolve memory leak.
+
+Mon Nov 3 13:49:18 2014 Koichi Sasada <ko1@atdot.net>
+
+ * iseq.c (iseq_memsize): catch up recent changes.
+
+Mon Nov 3 13:38:28 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm_core.h: change semantics of opt_num and opt_table.
+ `opt_num' was the number of optional parameters + 1.
+ `opt_table' has "opt_num" entries.
+
+ Change them to:
+ `opt_num' is the number of optional parameters.
+ `opt_table' has "opt_num + 1" entries.
+
+ This change simplify parameter fitting logics.
+
+ * compile.c: catch up this change.
+
+ * iseq.c: ditto.
+
+ * proc.c: ditto.
+
+ * vm_args.c: ditto.
+
+Mon Nov 3 11:47:44 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * NEWS: added period into Matrix section. [ci skip]
+ [misc #10446][ruby-core:65987]
+
+Mon Nov 3 09:43:30 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * vm_args.c: fixed build error with clang
+
+Mon Nov 3 09:32:46 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/rfc3986_parser.rb (URI::RFC3986_Parser::RFC3986_URI):
+ allow '[' and ']' for URI input (and escape). [Bug #10402]
+
+ * lib/uri/generic.rb (URI#query=): escape '[', '\', and ']'.
+
+Mon Nov 3 07:49:34 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm_core.h: change iseq parameter data structure.
+ https://bugs.ruby-lang.org/issues/10440#change-49694
+
+ * change terminology `arg' to `param'.
+ * move rb_iseq_t::arg_* to rb_iseq_t::param.
+ * move rb_iseq_t::arg_size to rb_iseq_t::param::size.
+ * move rb_iseq_t::argc to rb_iseq_t::param::lead_num.
+ * move rb_iseq_t::arg_opts to rb_iseq_t::param::opt_num.
+ * move rb_iseq_t::arg_rest to rb_iseq_t::param::rest_start.
+ * move rb_iseq_t::arg_post_num to rb_iseq_t::param::post_num.
+ * move rb_iseq_t::arg_post_start to rb_iseq_t::param::post_start.
+ * move rb_iseq_t::arg_block to rb_iseq_t::param::block_start.
+ * move rb_iseq_t::arg_keyword* to rb_iseq_t::param::keyword.
+ rb_iseq_t::param::keyword is allocated only when keyword
+ parameters are available.
+ * introduce rb_iseq_t::param::flags to represent parameter
+ availability. For example, rb_iseq_t::param::flags::has_kw
+ represents that this iseq has keyword parameters and
+ rb_iseq_t::param::keyword is allocated.
+ We don't need to compare with -1 to check availability.
+ * remove rb_iseq_t::arg_simple.
+
+ * compile.c: catch up this change.
+
+ * iseq.c: ditto.
+
+ * proc.c: ditto.
+
+ * vm.c, vm_args.c, vm_dump.c, vm_insnhelper.c: ditto.
+
+ * iseq.c (iseq_data_to_ary): support keyword argument.
+
+Mon Nov 3 03:39:04 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_method.rb: r48239 makes this test green.
+
+Mon Nov 03 03:02:38 2014 Koichi Sasada <ko1@atdot.net>
+
+ * rewrite method/block parameter fitting logic to optimize
+ keyword arguments/parameters and a splat argument.
+ [Feature #10440] (Details are described in this ticket)
+
+ Most of complex part is moved to vm_args.c.
+
+ Now, ISeq#to_a does not catch up new instruction format.
+
+ * vm_core.h: change iseq data structures.
+
+ * introduce rb_call_info_kw_arg_t to represent keyword arguments.
+ * add rb_call_info_t::kw_arg.
+ * rename rb_iseq_t::arg_post_len to rb_iseq_t::arg_post_num.
+ * rename rb_iseq_t::arg_keywords to arg_keyword_num.
+ * rename rb_iseq_t::arg_keyword to rb_iseq_t::arg_keyword_bits.
+ to represent keyword bitmap parameter index.
+ This bitmap parameter shows that which keyword parameters are given
+ or not given (0 for given).
+ It is referred by `checkkeyword' instruction described bellow.
+ * rename rb_iseq_t::arg_keyword_check to rb_iseq_t::arg_keyword_rest
+ to represent keyword rest parameter index.
+ * add rb_iseq_t::arg_keyword_default_values to represent default
+ keyword values.
+ * rename VM_CALL_ARGS_SKIP_SETUP to VM_CALL_ARGS_SIMPLE
+ to represent
+ (ci->flag & (SPLAT|BLOCKARG)) &&
+ ci->blockiseq == NULL &&
+ ci->kw_arg == NULL.
+
+ * vm_insnhelper.c, vm_args.c: rewrite with refactoring.
+
+ * rewrite splat argument code.
+ * rewrite keyword arguments/parameters code.
+ * merge method and block parameter fitting code into one code base.
+
+ * vm.c, vm_eval.c: catch up these changes.
+
+ * compile.c (new_callinfo): callinfo requires kw_arg parameter.
+
+ * compile.c (compile_array_): check the last argument Hash object or
+ not. If Hash object and all keys are Symbol literals, they are
+ compiled to keyword arguments.
+
+ * insns.def (checkkeyword): add new instruction.
+ This instruction check the availability of corresponding keyword.
+
+ For example, a method "def foo k1: 'v1'; end" is compiled to the
+ following instructions.
+
+ 0000 checkkeyword 2, 0 # check k1 is given.
+ 0003 branchif 9 # if given, jump to address #9
+ 0005 putstring "v1"
+ 0007 setlocal_OP__WC__0 3 # k1 = 'v1'
+ 0009 trace 8
+ 0011 putnil
+ 0012 trace 16
+ 0014 leave
+
+ * insns.def (opt_send_simple): removed and add new instruction
+ "opt_send_without_block".
+
+ * parse.y (new_args_tail_gen): reorder variables.
+ Before this patch, a method "def foo(k1: 1, kr1:, k2: 2, **krest, &b)"
+ has parameter variables "k1, kr1, k2, &b, internal_id, krest",
+ but this patch reorders to "kr1, k1, k2, internal_id, krest, &b".
+ (locate a block variable at last)
+
+ * parse.y (vtable_pop): added.
+ This function remove latest `n' variables from vtable.
+
+ * iseq.c: catch up iseq data changes.
+
+ * proc.c: ditto.
+
+ * class.c (keyword_error): export as rb_keyword_error().
+
+ * common.mk: depend vm_args.c for vm.o.
+
+ * hash.c (rb_hash_has_key): export.
+
+ * internal.h: ditto.
+
+Mon Nov 3 02:35:32 2014 Koichi Sasada <ko1@atdot.net>
+
+ * sample/simple-bench.rb: added to measure performance of simple
+ lines.
+
+Mon Nov 3 02:33:43 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (obj_info): show T_STRING more details.
+
+Sun Nov 2 01:30:32 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/openssl/test_ssl.rb: Don't ignore errors on listener threads,
+ as much as possible.
+
+ * test/openssl/test_ssl_session.rb: Ditto.
+
+ * test/openssl/test_partial_record_read.rb: Ditto.
+
+Sat Nov 1 23:11:05 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/openssl/utils.rb (start_server): Don't close sockets before
+ threads finished.
+
+Sat Nov 1 22:06:24 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/openssl/test_ssl_session.rb (test_ctx_client_session_cb): Don't
+ ignore errors of SSL accept.
+ (test_ctx_server_session_cb): Ditto.
+
+ * test/openssl/utils.rb (server_loop): Add ignore_ssl_accept_error
+ argument.
+ (start_server): Refine threads waits.
+
+ * test/ruby/envutil.rb (assert_join_threads): Show a thread before
+ backtrace.
+
+Sat Nov 1 20:40:18 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/openssl/utils.rb (start_server, server_loop): Use a
+ pipe to stop server instead of shutdown/close a listening socket.
+
+Sat Nov 1 19:24:59 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/envutil.rb (assert_join_threads): New assertion to
+ join multiple threads without exceptions.
+
+Sat Nov 1 17:09:32 2014 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (bary_mul_balance_with_mulfunc): Fix free work area
+ location.
+ [ruby-dev:48723] [Bug #10464]
+ [ruby-core:66044] [Bug #10465]
+ Reported by Kohji Nishihama.
+
+Sat Nov 1 15:45:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parse_atmark): mere atmark and two atmarks without
+ succeeding identifiers are invalid as instance/class variable
+ names.
+
+Sat Nov 1 06:31:41 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_variant.c: use typed data.
+
+Fri Oct 31 13:55:28 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/dl/*: remove DL as it is replaced by Fiddle.
+ [Feature #5458] Thanks to Jonan Scheffler <jonanscheffler@gmail.com>
+ for this patch
+
+ * test/dl/*: ditto.
+
+Fri Oct 31 15:26:02 2014 Charles Oliver Nutter <headius@headius.com>
+
+ * test/openssl/test_ssl.rb: Add certificate verification chain
+ test from JRuby community.
+
+Fri Oct 31 18:58:02 2014 Charles Oliver Nutter <headius@headius.com>
+
+ * test/psych/test_emitter.rb: Fix line_width test...initial value
+ is impl-specific and attr assignment always returns LHS.
+
+Fri Oct 31 22:19:30 2014 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest/lib/digest.rb (Digest()): This function should now be
+ thread-safe. If you have a problem with regard to on-demand
+ loading under a multi-threaded environment, preload "digest/*"
+ modules on boot or use this method instead of directly
+ referencing Digest::*. [Bug #9494]
+ cf. https://github.com/aws/aws-sdk-ruby/issues/525
+
+Fri Oct 31 21:33:17 2014 Akinori MUSHA <knu@iDaemons.org>
+
+ * test/digest/test_digest.rb: Drop #!. This no longer runs
+ stand-alone because it depends on ruby/envutil.
+
+Fri Oct 31 17:22:19 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/setup.mak: $(APPEND) with some arguments insert a space before
+ the arguments, so it causes error if the arguments are expected to be
+ a macro definition. this fix resolve the build error introduced at
+ r48210.
+
+Fri Oct 31 16:47:35 2014 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/syslog/lib/syslog/logger.rb (Syslog::Logger::VERSION): Bump
+ the VERSION to 2.1.0. [ruby-core:64483] [Bug #10159]
+
+Fri Oct 31 16:33:46 2014 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/net/imap.rb (Net::IMAP#fetch): [DOC] Document that
+ Net::IMAP#fetch will return nil instead of an empty array.
+
+Fri Oct 31 12:54:43 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (.unicode-tables.time): needs Unicode files always,
+ and should update after downloading these files.
+ [ruby-core:66026] [Bug #10461]
+
+Fri Oct 31 10:16:42 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * .travis.yml: reverted r48199, it's unrelated configuration.
+
+Fri Oct 31 09:58:14 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/test_unicode_normalize.rb: added unicode version number to
+ test data location.
+
+Fri Oct 31 09:56:41 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * .gitignore: ignored unicode data with version directories.
+
+Fri Oct 31 09:35:30 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * .travis.yml: tweak build scripts for unicode_normalize.rb.
+
+Thu Oct 30 18:47:04 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * common.mk: fix for the case ALWAYS_UPDATE_UNICODE=no
+
+Thu Oct 30 13:23:23 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/downloader.rb: changed Unicode data download location
+ from latest Unicode version to Unicode 7.0.0.
+
+Thu Oct 30 11:16:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_callee_setup_arg{_complex,}): try conversion
+ by to_ary for a lambda, as well as a proc.
+ [ruby-core:65887] [Bug #9605]
+
+Wed Oct 29 21:13:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (gettable_gen): warn circular argument reference, for
+ transition from 2.1 and earlier. [ruby-core:65990] [Bug #10314]
+
+Wed Oct 29 20:41:01 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_params): remove unused member `cur_mid`.
+ this has been taken over by `in_def` since 1.6.
+
+Wed Oct 29 14:44:27 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * load.c (rb_f_load): path name needs to be transcoded to OS path
+ encoding. [ruby-list:49994]
+
+Wed Oct 29 11:48:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (__builtin_setjmp): disable with gcc/clang earlier
+ than 4.3 on Mac OS X. [ruby-core:65174] [Bug #10272]
+
+Wed Oct 29 11:43:43 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Generalize Vector#cross_product to arbitrary
+ dimensions
+ based on a patch by gogo tanaka [#10074]
+
+Wed Oct 29 11:43:11 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Add Matrix#adjucate
+ patch by gogo tanaka [#10056]
+
+Wed Oct 29 11:42:33 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Add aliases for Vector#cross & dot
+ patch by gogo tanaka [#10352]
+
+Wed Oct 29 10:00:18 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * gems/bundled_gems: Update latest version of bundled gems.
+
+Tue Oct 28 16:52:07 2014 Eric Wong <e@80x24.org>
+
+ * signal.c (install_sighandler): remove rb_disable_interrupt and
+ rb_enable_interrupt calls
+ (init_sigchld): ditto
+ (Init_signal): disable and enable interrupt once around all
+ install_sighandler and init_sigchld to reduce syscalls at start
+ [Feature #9345] [ruby-core:59480]
+
+Tue Oct 28 16:22:41 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (process_options, load_file_internal2): should not
+ require other files when dump option is given.
+ [ruby-dev:48712] [Bug #10435]
+
+Tue Oct 28 14:51:38 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: remove apple-gcc4.2 from CC candidates.
+
+Mon Oct 27 20:13:37 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/rexml/entity.rb: keep the entity size within the limitation.
+ reported by Willis Vandevanter <will@silentrobots.com> and
+ patched by nahi.
+
+Mon Oct 27 17:17:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (method_proc): the receiver of binding from method should
+ be same as the receiver of the method.
+ [ruby-core:65917] [Bug #10432]
+
+Mon Oct 27 16:26:37 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_super.rb: add a test to check block passing.
+
+Mon Oct 27 15:59:26 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: is_incremental_marking(), will_be_incremental_marking():
+ use `&&' with GC_ENABLE_INCREMENTAL_MARK instead of using
+ #if/#else/#endif.
+
+Mon Oct 27 13:40:11 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (gc_sweep_rest): sweep rest pages regardless of whether
+ lazy sweep is enabled or not. based on the patch by Masahiro
+ Ide at [ruby-dev:48706]. [Bug #10431]
+
+Mon Oct 27 11:18:32 2014 Eric Wong <e@80x24.org>
+
+ * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking):
+ reduce garbage during forks
+
+Sun Oct 25 12:26:26 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * template/insns.inc.tmpl, insns_info.inc.tmpl, known_errors.inc.tmpl,
+ minsns.inc.tmpl: fixed path of generating script.
+
+Sun Oct 26 12:24:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/ripper/lib/ripper/sexp.rb (Ripper.sexp, Ripper.sexp_raw):
+ return nil on error. [ruby-dev:48678] [Bug #10405]
+
+Sun Oct 25 11:24:24 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: improved comment.
+
+Sun Oct 26 07:40:11 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_val2variant, ole_invoke): refactoring.
+ use ole_variant2variant to convert WIN32OLE_VARIANT object to
+ VARIANT object.
+
+ * ext/win32ole/win32ole_variant.c: refactoring. add
+ ole_variant2variant.
+ * ext/win32ole/win32ole_variant.h: ditto.
+
+Sat Oct 25 22:28:17 2014 Tanaka Akira <akr@fsij.org>
+
+ * io.c (io_binwrite_string): Test writev() failure.
+
+Sat Oct 25 20:19:19 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/test-unicode_normalize.rb: added test_us_ascii.
+
+Sat Oct 25 20:09:09 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize/normalize.rb: added US_ASCII
+ as trivially supported encoding (is always normalized,
+ and may appear mixed in with UTF-8 or other Unicode
+ encodings).
+
+Sat Oct 25 20:01:01 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/test-unicode_normalize.rb: added
+ test_raise_exception_for_non_unicode_encoding.
+
+Sat Oct 25 19:30:30 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/test-unicode_normalize.rb: removed unused function.
+
+Sat Oct 25 18:41:41 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * template/unicode_norm_gen.tmpl: Adjusted name of generating file.
+
+Fri Oct 24 22:49:42 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_yylex): dispatch newline and space at fluent
+ interface, so that the following identifier does not include the
+ space. [ruby-dev:48684] [Bug #10411]
+
+Fri Oct 24 20:41:36 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * signal.c (check_reserved_signal_): fix write count since r47991.
+
+Thu Oct 23 21:42:54 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash_delete): now does not call the block given to
+ the current method. [ruby-core:65861] [Bug #10413]
+
+Thu Oct 23 19:13:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_method.c (rb_method_entry_make): warn redefinition only for
+ already defined methods, but not for undefined methods.
+ [ruby-dev:48691] [Bug #10421]
+
+Thu Oct 23 17:19:04 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/source.rb (REXML::IOSource#encoding_updated): Fix a
+ bug that can't parse XML correctly when
+ Encoding.default_internal is different with XML
+ encoding. REXML::Source converts XML encoding on read. So IO
+ should not convert XML encoding.
+ Based on patch by NAKAMURA Usaku.
+ [ruby-dev:48686] [Bug #10418]
+
+ * test/rexml/test_encoding.rb
+ (REXMLTests::EncodingTester#test_parse_utf16_with_utf8_default_internal):
+ Add the for the above case.
+
+Thu Oct 23 16:29:02 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_encoding.rb
+ (REXMLTests::EncodingTester#test_parse_utf16): Use meaningful
+ test name. "ticket" in the old test name means the ticket in
+ REXML's issue tracker. The REXML's issue tracker was gone. So
+ "ticket" is meaningless.
+
+ * test/rexml/data/ticket_110_utf16.xml: Rename to ...
+ * test/rexml/data/utf16.xml: ... this.
+
+Thu Oct 23 16:18:11 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_encoding.rb
+ (REXMLTests::EncodingTester#test_ticket_110): Fix expected and
+ actual order.
+ Patch by NAKAMURA Usaku. Thanks!!!
+
+Thu Oct 23 10:47:16 2014 Eric Wong <e@80x24.org>
+
+ * insns.def (getlocal,setlocal): add comment to def/opt_operand.def
+
+Thu Oct 23 10:22:41 2014 Eric Wong <e@80x24.org>
+
+ * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking):
+ use IO#wait_readable instead of timeout
+
+Thu Oct 23 10:22:24 2014 Eric Wong <e@80x24.org>
+
+ * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking):
+ ensure exit! during fork failure
+
+Thu Oct 23 10:21:21 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * NEWS: Added String#unicode_normalize(|!|d?) [ci skip]
+
+Thu Oct 23 03:41:51 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (unknown_keyword_error): delete expected keywords
+ directly from raw table, so that the given block is not called.
+ [ruby-core:65837] [Bug #10413]
+
+Thu Oct 23 02:33:01 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (update-unicode): invert dependency to run every times.
+ [ruby-core:65842] [Bug #10415]
+
+ * common.mk (after-update): update files under source tree.
+ [ruby-core:65840] [Bug #10414]
+
+Wed Oct 22 22:38:59 2014 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * ext/openssl/lib/openssl/ssl.rb (DEFAULT_PARAMS): override
+ options even if OpenSSL::SSL::OP_NO_SSLv3 is not defined.
+ this is pointed out by Stephen Touset. [ruby-core:65711] [Bug #9424]
+
+Wed Oct 22 21:31:56 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * common.mk (prelude.c): add dependency to LIB_SRCS because
+ enc/prelude.rb requires lib/unicode_normalize.rb, and it's also
+ requires lib/unicode_normalize/tables.rb (=LIB_SRCS).
+
+Wed Oct 22 21:09:51 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * configure.in (nacl_cv_cpu_nick): fix typo in PNaCl.
+ (XCFLAGS) Add -isystem flag to pnacl and nacl-newlib
+ (CXX): added
+
+ * nacl/GNUmakefile.in (CXX): Added
+ (PPROGRAM): Use clang++ instead of clang because libnacl_io
+ depends on c++ std lib.
+
+Wed Oct 22 21:07:32 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * common.mk (build-ext): avoid trying to build dynamic libraries
+ if configured --with-static-linked-ext.
+
+Wed Oct 22 20:33:33 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * common.mk: Fixed grammar in comment [ci skip]
+
+Wed Oct 22 19:18:18 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/unicode_norm_gen.rb: Fixed escaping of backslash and
+ double quote ('\\\&' -> "\\\\\\\&"; double quoted string
+ is needed to make \& mean last match; double double
+ backslashes are needed because of two layers of escaping).
+
+Wed Oct 22 18:13:29 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/test-unicode_normalize.rb: as often said, ruby is sometimes built
+ at non-srcdir.
+
+Wed Oct 22 18:12:12 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/test-unicode_normalize.rb: Adjusted path for test
+ data file (now ../enc/unicode/data/NormalizationTest.txt).
+
+Wed Oct 22 18:07:07 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/test-unicode_normalize.rb: Removed explicit require,
+ changed method names, adjusted copyright.
+
+Wed Oct 22 18:00:00 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/test-unicode_normalize.rb: Importing from
+ https://github.com/duerst/eprun/blob/master/test/test_normalize.rb.
+ (removing trailing whitespace, fixing EOLs and adding EOL property)
+
+Wed Oct 22 08:21:09 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * nacl/pepper_main.c (Instance_DidCreate): mount devfs and rebind fd 0
+ .. 2 so that stderr goes to the console of the browser.
+
+Wed Oct 22 03:47:43 2014 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * ext/etc/etc.c (etc_nprocessors_affin): maximum "n" should be 16384.
+
+Wed Oct 22 03:37:00 2014 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * ext/etc/etc.c (etc_nprocessors_affin): minor spell fix.
+
+Wed Oct 22 03:33:58 2014 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * ext/etc/etc.c (etc_nprocessors_affin): optimize memory usage a
+ bit. Typical rubyist never use 8k cpus machine.
+
+Wed Oct 22 00:01:09 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * configure.in (XCFLAGS): Add include path for NaCl libraries.
+ (XLDFLAGS): ditto.
+ (NACL_LIB_PATH): new substitution
+
+ * nacl/nacl-config.rb: support NACL_LIB_PATH
+
+ * nacl/package.rb: ditto.
+
+ * nacl/pepper_main.c: replace old implementations with nacl_io.
+
+ * nacl/GNUmakefile.in: link nacl_io to pepper_ruby
+
+ * ruby.c (rb_load_file): remove __attribute__((weak)) because the old
+ override hack was replaced with nacl_io.
+
+ * file.c (rb_file_load_ok): ditto.
+
+Tue Oct 21 17:32:32 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * common.mk: Adding explicit creation of directory
+ enc/unicode/data because git doesn't handle empty
+ directories. [patch by Masahiro Ide, filed with r48073]
+
+Tue Oct 21 17:12:12 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize/tables.rb: Committing to make version
+ update easier and more predictable, and reducing compilation
+ time.
+
+Tue Oct 21 15:56:56 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize/normalize.rb: Added comment to point to
+ relevant portion of Unicode standard for Hangul (de)composition
+ identifiers and algorithm.
+
+Tue Oct 21 11:49:16 2014 Andreas Schwab <schwab@suse.de>
+
+ * gc.c (mark_current_machine_context) [__mc68000__]: Update stack
+ marking.
+ (rb_gc_mark_machine_stack) [__mc68000__]: Also handle it here.
+
+Mon Oct 20 23:59:38 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * enc/prelude.rb: we sometimes run ruby without library path (especially
+ for test), so should permit to run ruby if unicode_normalize.rb is
+ missing.
+
+Mon Oct 20 23:57:58 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * common.mk (lib/unicode_normalize/tables.rb): enable running (n)make
+ in non-srcdir.
+
+Mon Oct 20 23:58:04 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/downloader.rb: add -a option to always download regardless
+ existing files.
+
+Mon Oct 20 23:18:18 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/mkmf.rb: no need to convert path separator for COPY because it's
+ ruby -run cp and it can treat '/' on any platform.
+
+Mon Oct 20 19:54:54 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * config.mk: Added missing data files as targets for
+ prerequisite update_unicode.
+
+Mon Oct 20 19:06:06 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize.rb: revert r48046. The s in sIndex
+ is not hungarian notation. The variable name sIndex is
+ directly taken from the relevant part of the Unicode
+ Standard, where it is written SIndex and stands for
+ 'syllable index'. See pp. 144/145 of
+ http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf.
+
+Mon Oct 20 12:46:46 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize.rb: removing unnecessary 'self'.
+
+Mon Oct 20 12:37:37 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize.rb: change method names
+ in commented-out code. Followup to r48027.
+
+Mon Oct 20 02:23:27 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * variable.c (rb_ivar_get), vm_insnhelper.c (vm_getivar): improve
+ instance variable retrieval performance by checking ruby_verbose
+ before call of rb_warning and evaluation of its argument.
+ [ruby-core:65786] [Feature #10396]
+
+Sun Oct 19 23:31:29 2014 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * lib/unicode_normalize.rb: (unicode_normalize!): change method name.
+ catch up the method name change at r48014. [Feature #10084]
+
+Sun Oct 19 20:05:58 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * ext/tk/lib/tkextlib/tile/treeview.rb: fix syntax error.
+
+Sun Oct 19 18:39:39 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/prelude.rb: Added automatic loading of
+ lib/unicode_normalize.rb. This makes sure that all
+ the methods that are available on String are
+ available without explicit require.
+
+Sun Oct 19 18:35:35 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize/normalize.rb: Added a missing
+ file extension in require statement.
+
+Sun Oct 19 18:13:13 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * common.mk: Added a rule to generate
+ lib/unicode_normalize/tables.rb. This rule still
+ needs to be integrated into the overall make process.
+
+Sun Oct 19 17:53:53 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize.rb: Changed to dynamic
+ loading of actual normalization code and tables.
+
+Sun Oct 19 17:37:37 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize.rb: Small documentation fix.
+
+Sun Oct 19 17:26:26 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize.rb: Added documentation.
+
+Sun Oct 19 11:09:09 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/unicode_norm_gen.rb, lib/unicode_normalize.rb:
+ File name change from lib/unicode_normalize/normalize_tables.rb
+ to lib/unicode_normalize/tables.rb.
+
+Sun Oct 19 10:12:12 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize.rb: Changing method names, see
+ https://bugs.ruby-lang.org/issues/10084#note-7
+
+Sun Oct 19 10:10:10 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize.rb: Changing module name.
+
+Sun Oct 19 10:08:08 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize.rb: Changing require statement,
+ adjusting copyright.
+
+Sun Oct 19 10:04:04 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize.rb: Importing from
+ https://github.com/duerst/eprun/blob/master/lib/string_normalize.rb.
+ (removing trailing whitespace, fixing EOLs and adding EOL property)
+
+Sun Oct 19 09:56:56 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/unicode_norm_gen.rb: Changed module name.
+
+Sun Oct 19 09:48:48 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize/normalize.rb: Changed module name,
+ adjusted copyright.
+
+Sun Oct 19 09:38:38 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize/normalize.rb: Importing from
+ https://github.com/duerst/eprun/blob/master/lib/normalize.rb.
+
+Sat Oct 18 20:40:52 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * vm_core.h, proc.c, vm_backtrace.c, vm_trace.c:
+ remove rb_binding_new_with_cfp, and use rb_vm_make_binding instead.
+
+Sat Oct 18 20:38:48 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * vm_core.h, vm.c, proc.c: fix GC mark miss on bindings.
+ [ruby-dev:48616] [Bug #10368]
+
+ * test/ruby/test_eval.rb: add a test code.
+
+Fri Oct 17 22:47:11 2014 Tanaka Akira <akr@fsij.org>
+
+ * pack.c (pack_unpack): Add casts for char references for 'u'.
+ Fix line ending recognition algorithm.
+
+Fri Oct 17 21:49:52 2014 Tanaka Akira <akr@fsij.org>
+
+ * pack.c (pack_unpack): Add casts for char references for 'b' and 'h'.
+
+Fri Oct 17 17:50:10 2014 Tanaka Akira <akr@fsij.org>
+
+ * Avoid undefined behaviors found by gcc -fsanitize=undefined.
+ gcc (Debian 4.9.1-16) 4.9.1
+
+ * string.c (rb_str_sum): Avoid undefined behavior.
+
+Fri Oct 17 17:43:50 2014 Tanaka Akira <akr@fsij.org>
+
+ * Avoid undefined behaviors found by gcc -fsanitize=undefined.
+ gcc (Debian 4.9.1-16) 4.9.1
+
+ * include/ruby/ruby.h (INT2FIX): Avoid undefined behavior.
+
+ * node.h (nd_set_line): Ditto.
+
+ * pack.c (encodes): Ditto.
+ (pack_unpack): Ditto.
+
+ * regint.h (BIT_STATUS_AT): Ditto.
+ (BS_BIT): Ditto.
+
+ * time.c (time_mdump): Ditto.
+ (time_mload): Ditto.
+
+ * vm_core.h (VM_FRAME_MAGIC_MASK): Ditto.
+
+ * vm_trace.c (recalc_add_ruby_vm_event_flags): Ditto.
+
+Fri Oct 17 15:06:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * re.c (unescape_nonascii): make dynamically compiled US-ASCII
+ regexps ASCII-8BIT encoding if binary (hexadecimal, control,
+ meta) escapes are contained, as well as literal regexps.
+ [ruby-dev:48626] [Bug #10382]
+
+Fri Oct 17 03:05:08 2014 Eric Wong <e@80x24.org>
+
+ * test/-ext-/bug_reporter/test_bug_reporter.rb
+ (test_bug_reporter_add): revert r47972
+ * test/ruby/test_rubyoptions.rb (test_segv_test): revert r47971
+ [ruby-core:65764]
+
+Thu Oct 16 23:17:40 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (rb_sigaltstack_size): double default size to get rid
+ of heap corruption by alternate stack overflow in SEGV handler.
+ typically happened at fprintf() in control_frame_dump().
+
+Thu Oct 16 22:43:12 2014 Tanaka Akira <akr@fsij.org>
+
+ * vm_backtrace.c (id2str): Fix a variable name.
+ [ruby-dev:48642] [Bug #10389]
+
+Thu Oct 16 20:01:26 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/envutil.rb (assert_pattern_list): Show number of matched
+ patterns and characters.
+
+Thu Oct 16 16:26:09 2014 Eric Wong <e@80x24.org>
+
+ * cont.c (fiber_store): fix WIN32 fibers
+ [ruby-core:65745] [ruby-core:65758]
+
+Thu Oct 16 15:05:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_here_document): do not append already appended
+ and disposed code fragment. [ruby-dev:48647] [Bug #10392]
+
+Thu Oct 16 10:35:33 2014 Eric Wong <e@80x24.org>
+
+ * test/-ext-/bug_reporter/test_bug_reporter.rb
+ (test_bug_reporter_add): fix race
+
+Thu Oct 16 10:09:02 2014 Eric Wong <e@80x24.org>
+
+ * test/ruby/test_rubyoptions.rb (test_segv_test): fix race
+
+Thu Oct 16 09:17:48 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * cont.c (rb_fiber_t): fix compile error caused by move to
+ vm_core.h at r47964. [Feature #10341]
+
+Thu Oct 16 08:58:11 2014 Eric Wong <e@80x24.org>
+
+ * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking):
+ avoid killing wrong parent
+
+Thu Oct 16 08:40:04 2014 Eric Wong <e@80x24.org>
+
+ * cont.c (fiber_store): restore references to next_fib (fix typo)
+
+Thu Oct 16 08:26:08 2014 Eric Wong <e@80x24.org>
+
+ * cont.c (fiber_store): remove references to nextfib
+ fix build when FIBER_USE_NATIVE is 0
+
+Thu Oct 16 06:51:35 2014 Knut Franke <Knut.Franke@gmx.de>
+
+ * vm_core.h: declare rb_fiber_t typedef
+ (rb_thread_t): fiber and root_fiber become rb_fiber_t * (from VALUE)
+ * vm.c (rb_thread_mark): use rb_fiber_mark_self
+ * cont.c (rb_fiber_t): prev becomes rb_fiber_t * (from VALUE)
+ (cont_mark, cont_free): simplify conditions
+ (rb_fiber_mark_self): new function
+ (fiber_mark): use rb_fiber_mark_self
+ (cont_save_thread, cont_restore_thread): inline
+ (cont_restore_thread): simplify
+ (fiber_setcontext): simplify conditions
+ (rb_cont_call): remove dereference
+ (fiber_t_alloc): update for rb_fiber_t->prev type change
+ (rb_fiber_start): ditto
+ (fiber_current): extract from rb_fiber_current
+ (return_fiber): move, simplify type checks
+ (rb_fiber_current): use fiber_current
+ (fiber_store): simplify type checks
+ (fiber_switch): ditto, simplify call to fiber_setcontext,
+ use fiber_current
+ (rb_fiber_transfer): update for type changes
+ (rb_fiber_terminate): move, use fiber_switch
+ (rb_fiber_resume): update for type changes
+ (rb_fiber_reset_root_local_storage): ditto
+ (rb_fiber_yield): use rb_fiber_switch instead of rb_fiber_transfer
+ (rb_fiber_m_transfer): ditto
+ [ruby-core:65518] [Feature #10341]
+
+Thu Oct 16 06:25:29 2014 Knut Franke <Knut.Franke@gmx.de>
+
+ * cont.c (rb_context_t): comment on saved_thread
+ (cont_save_thread): sparse copy
+ (cont_init): copy extra fields
+ (fiber_init): use current thread VM stack size
+ [ruby-core:65518] [Feature #10341]
+
+Thu Oct 16 06:13:09 2014 Knut Franke <Knut.Franke@gmx.de>
+
+ * cont.c (cont_capture): remove unnecessary variable
+ [ruby-core:65518] [Feature #10341]
+
+Thu Oct 16 05:02:31 2014 Knut Franke <Knut.Franke@gmx.de>
+
+ * cont.c (fiber_store, fiber_switch): simplify
+ [ruby-core:65518] [Feature #10341]
+
+Thu Oct 16 04:28:41 2014 Knut Franke <Knut.Franke@gmx.de>
+
+ * cont.c (rb_fiber_t): remove prev_fiber/next_fiber
+ (fiber_link_join, fiber_link_remove): remove functions
+ (fiber_free, fiber_init, root_fiber_alloc):
+ remove references to removed fields and functions
+ [ruby-core:65518] [Feature #10341]
+
+Wed Oct 15 22:08:37 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/etc/etc.c (etc_nprocessors_affin): Test CPU_ALLOC availability.
+ CentOS 5 don't have CPU_ALLOC().
+
+Wed Oct 15 18:26:19 2014 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * ext/etc/etc.c (etc_nprocessors_affinity): use sched_getaffinity
+ for getting precious number of available cpus.
+
+ * ext/etc/etc.c (etc_nprocessors): use etc_nprocessors_affinity if
+ possible.
+
+ [Feature #10267] etc-nprocessors-kosaki2.patch
+
+Wed Oct 15 17:53:28 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/envutil.rb (assert_pattern_list) Renamed from
+ assert_regexp_list.
+ Show multiline string in multi lines.
+
+ * test/-ext-/bug_reporter/test_bug_reporter.rb: Use
+ assert_pattern_list.
+
+Wed Oct 15 12:26:58 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/envutil.rb (assert_regexp_list): New assertion method.
+
+ * test/ruby/test_rubyoptions.rb: Use assert_regexp_list.
+
+Wed Oct 15 07:21:09 2014 Tanaka Akira <akr@fsij.org>
+
+ * enum.c: min(n) drops elements bigger than the n-th maximum element.
+ (struct nmin_data): New field to record the n-th maximum element, limit
+ (nmin_filter): Update limit field.
+ (nmin_i): Drop too big elements.
+ (nmin_run): Initialize limit field.
+
+Wed Oct 15 07:00:14 2014 Eric Wong <e@80x24.org>
+
+ * test/ruby/test_optimization.rb (test_string_size): new test
+
+Wed Oct 15 06:51:13 2014 Eric Wong <e@80x24.org>
+
+ * test/ruby/test_optimization.rb (test_string_eq_neq): new test
+ (test_string_ltlt): ditto
+
+Wed Oct 15 06:50:29 2014 Eric Wong <e@80x24.org>
+
+ * test/ruby/test_optimization.rb (test_hash_aset_with):
+ assert assignment
+
+Wed Oct 15 04:56:27 2014 Zachary Scott <e@zzak.io>
+
+ * gc.c (rb_obj_id): [DOC] Fix typo, clean up sentence, and wrap cols
+
+Wed Oct 15 04:53:30 2014 Zachary Scott <e@zzak.io>
+
+ * error.c: [DOC] Fix case of type in exception message by @tricknotes
+ [Fixes GH-740] https://github.com/ruby/ruby/pull/740
+
+ * object.c: ditto
+
+Tue Oct 14 21:39:16 2014 Vit Ondruch <vondruch@redhat.com>
+
+ * tool/rbinstall.rb (gem): Fix permissions of bundled gems
+ specification files. [ruby-core:65700] [Bug #10383]
+
+Tue Oct 14 19:15:31 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_record.c: use typed data.
+
+Tue Oct 14 16:23:12 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * symbol.c (global_symbols): make ids two-dimensional array of
+ strings and symbols, for write-barrier.
+
+ * symbol.c (global_symbols): make IDs immortal always, instead
+ of treating dynamic symbols as IDs.
+
+ * iseq.c, marshal.c, string.c: use rb_str_intern instead of
+ rb_str_dynamic_intern.
+
+ * symbol.c (rb_str_intern): rename rb_str_dynamic_intern.
+
+Tue Oct 14 10:19:10 2014 Eric Wong <e@80x24.org>
+
+ * test/ruby/test_optimization.rb (test_string_freeze): new test
+ (test_hash_aref_with): ditto
+ (test_hash_aset_with): ditto
+
+Tue Oct 14 01:27:54 2014 Tanaka Akira <akr@fsij.org>
+
+ * enum.c (nmin_run): max(n) and max_by(n) returns an array in
+ descending order.
+ [ruby-core:65452] Suggested by David Grayson.
+
+Mon Oct 13 20:44:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (update-gems): chdir to the target directory and then
+ add the tool directory to load paths, for older BASERUBY.
+ [Bug #10372][ruby-core:65630]
+
+Mon Oct 13 17:53:01 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/xmlrpc/parser.rb: added new parser class using libxml-ruby gem.
+ [Feature #9379][ruby-core:59633]
+ * lib/xmlrpc/config.rb: ditto.
+
+Mon Oct 13 16:32:56 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/find.rb (Find.find): Call to_path for arguments to obtain
+ strings.
+ [ruby-core:63713] [Bug #10035] Reported by Herwin.
+
+Mon Oct 13 15:42:25 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * common.mk: use relative load path for bundled_gems directory.
+ [Bug #10372][ruby-core:65630]
+
+Mon Oct 13 08:44:06 2014 Zachary Scott <e@zzak.io>
+
+ * README.EXT: [DOC] fix example missing typedef with patch by
+ @steveklabnik [Fixes GH-739] https://github.com/ruby/ruby/pull/739
+
+ * README.EXT.ja: ditto.
+
+Mon Oct 13 06:52:09 2014 Eric Wong <e@80x24.org>
+
+ * array.c (ary_recycle_hash): add RB_GC_GUARD
+ (rb_ary_diff): remove volatile
+ [Bug #10369]
+
+Mon Oct 13 03:20:23 2014 Zachary Scott <e@zzak.io>
+
+ * ext/date/date_core.c: [DOC] Clean up whitespace, examples, and typos
+ in date_core based on a patch by @vipulnsward [Fixes GH-724]
+ https://github.com/ruby/ruby/pull/724
+
+Mon Oct 13 02:39:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (remove_duplicate_keys): should not simply eliminate all
+ value nodes, which may have side effects.
+ [ruby-core:65625] [Bug #10315]
+
+Sun Oct 12 10:39:16 2014 Zachary Scott <e@zzak.io>
+
+ * vm.c: [DOC] fix typo by @yui-knk [Fixes GH-738]
+ https://github.com/ruby/ruby/pull/738
+
+Sun Oct 12 09:24:15 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/test/unit.rb: Hide skips by default.
+
+Sun Oct 12 01:37:11 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * file.c: include sys/time.h only if HAVE_SYS_TIME_H
+
+Sat Oct 11 22:29:40 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * file.c (HAVE_UTIMENSAT): disabled for NativeClient.
+ Fixes build error.
+
+Sat Oct 11 22:11:58 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * ext/extmk.rb: generates the rule for extinit.$(OBJEXT).
+ extinit.$(OBJEXT) used to be generated by the builtin rule, thus
+ didn't accept custom $(CC) and caused linkage error for cross
+ compiling.
+
+Sat Oct 11 18:46:50 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * include/ruby/intern.h (rb_fd_select): declare struct timeval, or the
+ struct gets local to the function in C99.
+
+ * file.c (#include): add nacl/stat.h for PNaCl.
+ (utimes): added a declaration for PNaCl.
+ (stat_atimespec): stat::st_atimensec is long long but
+ timespec::tv_nsec is long in PNaCl.
+ (stat_mtimespec, stat_ctimespec): ditto.
+ (rb_group_member): disable getgroups unless HAVE_GETGROUPS.
+ (eaccess): unify the fallback to generic defined(USE_GETEUID).
+
+ * io.c: include sys/time.h for struct timeval.
+ (rb_close_before_exec): nothing we can do if F_GETFD is not
+ available.
+ (ioctl): pnacl newlib actually doesn't have ioctl.
+
+ * process.c (maxgroups): it is used iff
+ defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX) but not
+ defined(HAVE_GETGROUPS) || defined(HAVE_SETGROUPS).
+ (obj2gid): fail unless the object is a Fixnum if getgrnam is not
+ available.
+ (disable_child_handler_fork_child): sigaction is not available in
+ PNaCl newlib.
+
+ * configure.in (warnflags, strict_warnflags): avoid -ansi for strlcpy.
+ (rb_cv_gcc_atomic_builtins): also check
+ __atomic_or_etch because it is used in ruby_atomic.h.
+ (rb_cv_gcc_sync_builtins): ditto.
+ (HAVE_GETGRNAM): added.
+
+Sat Oct 11 15:32:08 2014 Eric Wong <e@80x24.org>
+
+ * compile.c (iseq_build_from_ary_exception): move RB_GC_GUARD
+ (iseq_build_from_ary_body): use PRIsVALUE instead of RB_GC_GUARD
+
+Sat Oct 11 14:57:08 2014 Eric Wong <e@80x24.org>
+
+ * string.c (rb_str_intern): remove unnecessary RB_GC_GUARD
+
+Sat Oct 11 13:47:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (remove_duplicate_keys): remove duplicate literal keys,
+ i.e., symbols and strings. [ruby-core:65368] [Bug #10315]
+
+ * vm.c (kwmerge_i): override existing keys by new keys.
+ [ruby-core:65368] [Bug #10315]
+
+ * parse.y (assocs): concatenate splatted literal hashes. the
+ former key has precedence even if duplicated literal keys
+ follow. [ruby-core:65368] [Bug #10315]
+
+Sat Oct 11 12:27:03 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * configure.in (RUBY_NACL): automatically locate pnacl-clang.
+ (RUBY_PLATFORM): pnacl instead of le32-nacl.
+
+Sat Oct 11 11:27:14 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * io.c: fix issues in the last two commits. don't disable cloexec for
+ platforms other than NativeClient.
+
+ * ChangeLog: ditto. add entries for the last two commits.
+
+Sat Oct 11 11:12:00 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * signal.c (install_signalhandler, init_sigchld): allow failure because it
+ always fails with ENOSYS on NaCl.
+
+Sat Oct 11 11:11:53 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
+
+ * configure.in (RUBY_NACL and others): merge patch from naclports. Supports PNaCl.
+
+ * dln.c: ditto. replace the old hacky dynamic loading over HTTP with nacl_io.
+
+ * file.c: ditto. tentatively use access(2) instead of eaccess.
+ (rb_file_load_ok): weaken with attribute but not by postprocess.
+
+ * io.c: ditto.
+ (socket.h): now NaCl has socket.h
+ (flock): disable here instead of nacl/ioctl.h
+
+ * nacl/GNUmakefile.in: ditto.
+ (CC, LD, NM, AR, AS, RANLIB, OBJDUMP, OBJCOPY):
+ respect path to them if they are absolute.
+ This helps naclports to build ruby in their source tree.
+ (PROGRAM_NMF, .SUFFIXES): support .pnexe for PNaCl.
+ (ruby.o, file.o): move the hack to attributes in ruby.c and file.c
+
+ * nacl/ioctl.h: ditto. removed. move the hack to io.c.
+
+ * nacl/nacl-config.rb: ditto. support arm, pnacl and others.
+
+ * nacl/pepper_main.c: ditto. support build in a naclports tree.
+
+ * ruby.c (rb_load_file): ditto. weaken with attribute but not by postprocess.
+
+Sat Oct 11 09:32:00 2014 Zachary Scott <e@zzak.io>
+
+ * ext/socket/unixsocket.c: [DOC] Fix example to render in HTML
+ properly, with a patch by @eval [Fixes GH-733]
+ https://github.com/ruby/ruby/pull/733
+
+Sat Oct 11 04:14:41 2014 Kir Shatrov <shatrov@me.com>
+
+ * lib/open-uri.rb (OpenURI::Options): add :open_timeout default
+ * (def OpenURI.open_http): check :open_timeout option
+ * (module OpenURI): rdoc for :open_timeout
+ * test/open-uri/test_open-uri.rb (test_open_timeout): new test
+ [Feature #10361]
+
+Fri Oct 10 11:27:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/io.h (rb_io_mode_flags, rb_io_modenum_flags):
+ deprecate old macros for compatibility for ruby 1.8 and older.
+
+Thu Oct 9 23:31:47 2014 Naohisa Goto <ngotogenome@gmail.com>
+
+ * bignum.c (absint_numwords_generic): set an array element after
+ definition of a variable to fix compile error with older version
+ of fcc (Fujitsu C Compiler) 5.6 on Solaris 10 on Sparc.
+ [Bug #10350] [ruby-dev:48608]
+
+Thu Oct 9 16:15:26 2014 Eric Wong <e@80x24.org>
+
+ * ext/-test-/st/foreach/extconf.rb: new file
+ * ext/-test-/st/foreach/foreach.c: ditto
+ * test/-ext-/st/test_foreach.rb: ditto
+ [Feature #10321]
+
+Thu Oct 9 12:40:28 2014 Eric Wong <e@80x24.org>
+
+ * benchmark/bm_hash_aref_sym*.rb: force static symbols
+
+Thu Oct 9 12:38:28 2014 Eric Wong <e@80x24.org>
+
+ * hash.c (rb_any_hash): remove unnecessary dsym check
+
+Thu Oct 9 07:20:30 2014 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * missing/setproctitle.c: Avoid invalidating argv[1], argv[2],
+ etc. until the first call to Process.setproctitle, because
+ the ps command of AIX refers to the argv array.
+ [Bug #10090]
+
+Thu Oct 9 00:53:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (dir_s_aref): fix rdoc. `Dir.glob` allows an array but
+ `Dir[]` not. the former accepts an optional parameter `flags`,
+ while the latter accepts arbitrary number of arguments but no
+ `flags`. [ruby-core:65265] [Bug #10294]
+
+Wed Oct 8 21:44:10 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_variable.c: use typed data.
+
+Wed Oct 8 16:36:47 2014 gogo tanaka <mail@tanakakazuki.com>
+
+ * test/ruby/test_syntax.rb: added syntax tests of underscore
+ arguments. [Feature #10340][ruby-core:65496]
+
+Wed Oct 8 07:42:39 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/generic.rb (URI#inspect): remove Object id.
+ URI is considered that it doesn't require id.
+
+Wed Oct 8 05:22:42 2014 Eric Wong <e@80x24.org>
+
+ * ext/etc/etc.c (etc_systmpdir): set default tmplen correctly
+ Fixup r47826
+
+Wed Oct 8 05:16:32 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Add @- and @+ for Matrix and Vector.
+ patch by gogo tanaka [#10068] [#10069]
+
+Wed Oct 8 04:58:48 2014 John Bachir <j@jjb.cc>
+
+ * bootstraptest/test_io.rb (assert_finish):
+ normalize rescue for Timeout::Error
+ * lib/net/ftp.rb (Net#read_timeout): ditto for doc
+ * lib/resolv.rb (Resolv::ResolvTimeout): ditto for subclass
+ * lib/webrick/httprequest.rb (_read_data): ditto for rescue
+ * sample/timeout.rb (p timeout): ditto for call
+ * test/drb/drbtest.rb (test_06_timeout): ditto
+ * test/ruby/test_readpartial.rb (test_open_pipe): ditto
+ * test/thread/test_queue.rb (test_queue_thread_raise): ditto
+ * thread.c (rb_thread_s_handle_interrupt): ditto for doc
+ [ruby-core:65481] [misc #10339]
+
+Wed Oct 8 04:38:29 2014 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/ruby/test_process.rb (TestProcess#test_setsid): AIX
+ does not allow Process::getsid(pid) when pid is in a
+ different session.
+
+Wed Oct 8 04:33:04 2014 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/ruby/test_rubyoptions.rb (TestRubyOptions#test_encoding):
+ On AIX, locale_charmap is ISO-8859-1 with LANG=C. This means
+ the source encoding of stdin is ISO-8859-1, so "invalid
+ multibyte char" error does not occur.
+
+Wed Oct 8 04:30:29 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Add Matrix#laplace_expansion.
+ patch by gogo tanaka [#10073]
+
+Wed Oct 8 04:29:21 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Add Vector.basis.
+ Based on patch by gogo tanaka [#10072]
+
+Tue Oct 7 23:40:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (rb_f_kill): get rid of deadlock as unhandled and
+ discarded signals do not make interrupt_cond signaled.
+ based on the patch by Kazuki Tsujimoto at [ruby-dev:48606].
+ [Bug #9820]
+
+Tue Oct 7 22:43:44 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_method.c: use typed data.
+
+Tue Oct 7 21:47:05 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_param.c: refactoring.
+
+Tue Oct 7 21:40:17 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_method.c: refactoring. add
+ olemethod_data_get_struct to wrap Data_Get_Struct.
+ * ext/win32ole/win32ole_method.h: ditto.
+
+ * ext/win32ole/win32ole_param.c (oleparam_ole_param):
+ call olemethod_data_get_struct instead of Data_Get_Struct.
+
+Tue Oct 7 11:17:08 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/etc/etc.c (etc_systmpdir): try user temporary directory by
+ confstr() on Mac OS X.
+ c.f. http://www.opensource.apple.com/source/ruby/ruby-104/patches/ext_etc_etc.c.diff
+
+Tue Oct 7 10:48:17 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (struct stat.st_size): prefer off_t over int, long,
+ and so on. inspired by
+ http://www.opensource.apple.com/source/ruby/ruby-104/patches/config.h.ed
+
+Tue Oct 7 10:37:39 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_UNIVERSAL_ARCH): fix missing quoting
+ brackets. incorporated from
+ http://www.opensource.apple.com/source/ruby/ruby-104/patches/configure.diff
+
+Mon Oct 6 23:34:42 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_param.c: use typed data.
+
+Mon Oct 6 22:37:09 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * symbol.h (struct RSymbol): move from internal.h.
+
+Mon Oct 6 21:43:03 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * error.c: update exception tree. [DOC]
+ reported by @hemge via twitter.
+
+Mon Oct 6 18:43:03 2014 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * configure.in: Fix typo. [Bug #9914]
+
+Mon Oct 6 16:23:30 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (rb_f_kill): should not ignore signal unless the
+ default handler is registered. [ruby-dev:48592] [Bug #9820]
+
+Mon Oct 6 16:07:11 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/ruby/test_string.rb (test_LSHIFT_neary_long_max): enable
+ only on platforms where string size range is smaller than memory
+ space. this test does not make sense but just wastes memory and
+ time on other platforms, as it is hardly possible that a string
+ size becomes neary LONG_MAX if long size equals pointer size.
+ [ruby-core:65410] [Bug #10325]
+
+Mon Oct 6 11:21:21 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/unicode_norm_gen.rb: Adding/tweaking comments.
+
+Mon Oct 6 10:57:57 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/unicode_norm_gen.rb: Adjusted directory paths.
+
+Mon Oct 6 10:27:27 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/unicode_norm_gen.rb: Data generation script imported from
+ https://github.com/duerst/eprun/blob/master/lib/generate.rb
+
+Mon Oct 6 10:15:15 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/downloader.rb: Adjust example in documentation for
+ Downloader.download.
+
+Mon Oct 6 10:07:07 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize: New folder for Unicode normalization
+ functionality
+
+Sun Oct 5 11:04:13 2014 Luiz Angelo Daros de Luca <luizluca@gmail.com>
+
+ * ext/digest/{md5,rmd160,sha1,sha2}/extconf.rb: configure OpenSSL
+ only if bundled libraries is not used, so that OpenSSL is not
+ linked unnecessarily. [ruby-core:65404] [Bug #10324]
+
+Sun Oct 5 10:39:11 2014 Luiz Angelo Daros de Luca <luizluca@gmail.com>
+
+ * ext/digest/rmd160/extconf.rb: fix transform function name to
+ check. [ruby-core:65091] [Bug #10252]
+
+Sun Oct 5 05:46:00 2014 Eric Wong <e@80x24.org>
+
+ * ext/zlib/zlib.c (zstream_mark, zstream_free): update signature
+ (gzfile_mark, gzfile_free): ditto
+ (zstream_memsize): new function for rb_data_type->dsize
+ (gzfile_memsize): ditto
+ (zstream_data_type, gzfile_data_type): new data types
+ (zstream_new): Data_Make_Struct => TypedData_Make_Struct
+ (gzfile_new): ditto
+ (get_zstream, get_gzfile): Data_Get_Struct => TypedData_Get_Struct
+ (rb_zstream_flush_next_in): ditto
+ (rb_zstream_flush_next_out): ditto
+ (rb_zstream_avail_out): ditto
+ (rb_zstream_avail_in): ditto
+ (rb_zstream_closed_p): ditto
+ (rb_deflate_initialize): ditto
+ (rb_deflate_init_copy): ditto
+ (rb_inflate_initialize): ditto
+ (gzfile_ensure_close): ditto
+ (rb_gzfile_closed_p): ditto
+ (rb_gzfile_path): ditto
+ (rb_gzwriter_initialize): ditto
+ (rb_gzreader_initialize): ditto
+ (rb_gzreader_unused): ditto
+ [ruby-core:65377] [Feature #10319]
+
+Sat Oct 4 16:24:41 2014 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/test_syslog.rb (TestSyslog#test_log): In AIX, each output
+ line of LOG_PERROR to stderr has an additional empty line appended,
+ so skip that line.
+
+Sat Oct 4 16:05:49 2014 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/socket/test_unix.rb (TestSocket_UNIXSocket#test_too_long_path):
+ sockaddr_un.sun_path in AIX is defined as char[1024],
+ so "a" * 300 is not too long. "a" * 3000 would be enough.
+
+Sat Oct 4 09:12:03 2014 Zachary Scott <e@zzak.io>
+
+ * ext/win32ole/sample/example*.rb: Add wait input to quit for examples
+ with patch provided by @windwiny [Fixes GH-705]
+ https://github.com/ruby/ruby/pull/705
+
+Sat Oct 4 09:08:18 2014 Zachary Scott <e@zzak.io>
+
+ * ext/win32ole/win32ole.c: [DOC] Fix typo in :nodoc: reported by
+ @windwiny to [Fix GH-705] https://github.com/ruby/ruby/pull/705
+
+ * ext/pty/pty.c: ditto
+
+Sat Oct 4 08:59:45 2014 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/ossl_rand.c: [DOC] Add call signature for pseudo_bytes
+ and random_bytes, wrap lines at 80 chars, and remove useless
+ comments.
+
+Sat Oct 4 08:49:34 2014 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/ossl_rand.c: [DOC] Add rdoc for method descriptions
+ By @vipulnsward [Fixes GH-657] https://github.com/ruby/ruby/pull/657
+
+Sat Oct 4 08:23:48 2014 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/ossl_rand.c: Use rb_define_module_function instead of
+ macro. [Fixes GH-686] https://github.com/ruby/ruby/pull/686
+
+Sat Oct 4 06:04:56 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_method.c(olemethod_set_member): remove
+ redundant NULL check.
+ * ext/win32ole/win32ole_type.c(oletype_set_member): ditto.
+
+Sat Oct 4 00:25:04 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * .travis.yml: removed needless preparation for gcc.
+
+Fri Oct 3 23:41:20 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * .travis.yml: enabled gcc build with osx on travis.
+
+Fri Oct 3 23:22:23 2014 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * template/fake.rb.in: fix make install failure due to MSYS path
+ with mingw on MSYS environment.
+ [ruby-core:64965] [Bug #10230]
+
+Fri Oct 3 21:02:32 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/ruby/test_io.rb (TestIO#test_advise): avoid to infinite loop.
+
+Fri Oct 3 19:26:01 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * .travis.yml: enabled test results of linux.
+
+Fri Oct 3 18:52:16 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/ruby/test_io.rb (TestIO#test_advise): added workaround of fadvise(2)
+ with tmpfs and old linux kernel. [ruby-core:65355][Bug #10313]
+
+Fri Oct 3 18:22:45 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * .travis.yml: Disabled to generate document on travis.
+ Reduce test running time.
+
+Fri Oct 3 12:42:15 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Add hstack & vstack methods.
+ Based on a patch by creasywuqiong. [Fix GH-344]
+
+Fri Oct 3 12:37:48 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Fix Matrix.rows copy bug.
+ Patch by Arron Mabrey. [Fix GH-707]
+
+Fri Oct 3 06:06:28 2014 Eric Wong <e@80x24.org>
+
+ * st.c (next_pow2): new function (from old bignum.c)
+ (new_size): use next_pow2 function
+
+Fri Oct 3 05:58:58 2014 Eric Wong <e@80x24.org>
+
+ * vm_trace.c (rb_tp_t): pack 56 => 48 bytes on 64-bit
+
+Thu Oct 2 18:41:45 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/etc/etc.c (etc_nprocessors): Windows support.
+ see [Feature #10267]
+
+Thu Oct 2 12:21:52 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/etc/etc.c (etc_nprocessors): New method.
+ Accepted by matz at RubyKaigi 2014.
+ [ruby-core:65142] [Feature #10267]
+
+Thu Oct 2 07:56:49 2014 Eric Wong <e@80x24.org>
+
+ * iseq.c (rb_iseq_line_trace_each): explicit cast
+ Fix https://travis-ci.org/ruby/ruby/jobs/36814282
+
+Thu Oct 2 05:40:05 2014 Eric Wong <e@80x24.org>
+
+ * ruby.h: set rb_event_flag_t to uint32_t
+ [ruby-core:65315] [misc #10249]
+
+Thu Oct 2 05:32:17 2014 Eric Wong <e@80x24.org>
+
+ * io.c (fptr_finalize): free memory before GC sweep
+ [ruby-core:65269] [Feature #10295]
+
+Thu Oct 2 05:27:24 2014 Eric Wong <e@80x24.org>
+
+ * marshal.c (w_class): check dump_arg->compat_tbl before lookup
+ (w_object): lazy init ->compat_tbl before insert
+ (obj_alloc_by_class): ditto
+ (clear_dump_arg): free only non-NULL ->compat_tbl
+ (clear_load_arg): ditto for ->compat_tbl
+ (marshal_dump): ->compat_tbl defaults to zero
+ (marshal_load): ditto for ->compat_tbl
+ (r_entry0): check l->compat_tbl before lookup
+ (r_fixup_compat): ditto
+ [ruby-core:65305] [Feature #10302]
+
+Wed Oct 1 21:14:34 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_type.c: use typed data.
+
+Wed Oct 1 18:15:42 2014 Nolan Evans <nolane@gmail.com>
+
+ * compile.c: remove commented out code.
+
+Wed Oct 1 17:38:53 2014 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/fileutils/test_fileutils.rb: AIX does not allow
+ a sticky bit on a regular file.
+
+Wed Oct 1 17:31:41 2014 Eric Hodel <drbrain@segment7.net>
+
+ * NEWS: Add RubyGems update.
+
+Wed Oct 1 17:28:58 2014 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems 2.4.2.
+ * test/rubygems: ditto.
+
+Tue Sep 30 22:25:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_data_type): separate ripper data type for from
+ parser.
+
+Tue Sep 30 18:46:31 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_typelib.c: use typed data.
+
+Tue Sep 30 09:51:46 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * common.mk: fixed broken reference of update-config_files task
+
+Mon Sep 29 22:54:51 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/file.c (append_wstr): set expanded length, not length of
+ appended string. fix "probable buffer overflow" bug.
+ [ruby-core:65317] [Bug #10304]
+
+ * string.c (str_make_independent_expand): drop NOFREE flag after
+ reallocation, static buffer is not pointed anymore.
+ [ruby-core:65317] [Bug #10304]
+
+Sun Sep 28 23:59:17 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * gc.c (rb_gcdebug_print_obj_condition): use RVALUE_REMEMBERED
+ because GET_HEAP_REMEMBERSET_BITS is obsoleted.
+
+Sun Sep 28 11:14:14 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * common.mk: Created new target update-unicode to download
+ some Unicode data files.
+
+Fri Sep 26 15:03:19 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * lib/uri/rfc3986_parser.rb: raise URI::InvalidURIError when
+ uri doesn't respond to #to_str. [ruby-core:64453] [Bug #10150]
+
+ * test/uri/test_parser.rb: test for above.
+
+Sat Sep 27 10:31:48 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * gems/bundled_gems: upgraded to power_assert 0.1.4.
+
+Fri Sep 26 12:52:36 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/stringio/stringio.c (strio_write): ASCII-8BIT StringIO
+ should be writable any encoding strings, without conversion.
+ [ruby-core:65240] [Bug #10285]
+
+Fri Sep 26 05:21:01 2014 Eric Wong <e@80x24.org>
+
+ * object.c (rb_class_real): do not dereference 0 VALUE
+
+ * test/ruby/test_module.rb (test_inspect_segfault):
+ Test case and bug report by Thomas Stratmann.
+ [ruby-core:65214] [Bug #10282]
+
+Fri Sep 26 05:12:10 2014 Eric Wong <e@80x24.org>
+
+ * man/ruby.1: document stack size env variables
+ [Feature #10197]
+
+Thu Sep 25 19:37:34 2014 Eric Wong <e@80x24.org>
+
+ * io.c (free_io_buffer): new function for a common pattern
+ (clear_readconv): use free_io_buffer
+ (rb_io_fptr_finalize): ditto
+
+Thu Sep 25 07:51:07 2014 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * lib/matrix.rb: Fix docs. Patched by Ben Woodall. [GH-726]
+
+Wed Sep 24 19:04:04 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/data: New directory for downloaded Unicode
+ data files.
+
+Wed Sep 24 18:59:59 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/downloader.rb: Adjusting example for
+ Downloader.download to implementation changes in r47693.
+
+Wed Sep 24 18:06:06 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/downloader.rb: Removing unused method
+ Downloader.download_if_modified_since.
+ (if ever used, just replace with Downloader.download)
+
+Wed Sep 24 17:59:59 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/downloader.rb: Fixing raise after return.
+
+Wed Sep 24 17:55:55 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/downloader.rb: Made Unicode data file location available
+ via :unicode Symbol.
+
+Wed Sep 24 10:45:45 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/downloader.rb: Small fix to documentation comment.
+
+Tue Sep 23 22:00:20 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parse_ident): just after a label, new expression should
+ start, cannot be a modifier. [ruby-core:65211] [Bug #10279]
+
+Tue Sep 23 16:07:07 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/downloader.rb: added Downloader.download_if_modified_since
+ to reduce downloads of large files that change only rarely.
+ [ruby-core:65164] [CommonRuby - Feature #10084]
+
+Tue Sep 23 11:55:09 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * .travis.yml: added rubyspec into travis tasks and eliminate to stdout.
+
+Mon Sep 22 20:00:29 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * test/win32ole/test_win32ole_variant.rb
+ (test_conversion_time2date_with_msec): test by using only
+ assert_in_delta to avoid to fail when converting Time object with
+ 999999999 nanoseconds into VT_DATE Variant.
+
+Mon Sep 22 19:49:12 2014 Zachary Scott <e@zzak.io>
+
+ * doc/syntax/methods.rdoc: [DOC] [] and []= methods by @process
+ [Fixes GH-662] https://github.com/ruby/ruby/pull/662
+
+Mon Sep 22 18:21:35 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * .travis.yml: Only osx build is enabled. linux builds is random failure
+ and test results of major linux is covered by rubyci.
+
+Mon Sep 22 12:10:29 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_time_tz.rb: Fix test error with tzdata-2014g.
+ [ruby-core:65058] [Bug #10245] Reported by Vit Ondruch.
+
+Mon Sep 22 09:28:43 2014 Eric Wong <e@80x24.org>
+
+ * ext/socket/ancdata.c ({send,recv}msg_args_struct): 24 => 16 bytes
+ * ext/socket/init.c (connect_arg): ditto
+ * ext/socket/raddrinfo.c (getnameinfo_arg): 56 => 48 bytes
+ (reductions only for 64-bit systems)
+
+Mon Sep 22 02:04:25 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/drb/drb.rb: Support graceful shutdown.
+ (DRbTCPSocket#initialize): Create a pipe for shutdown notification.
+ (DRbTCPSocket#close): Invoke close_shutdown_pipe.
+ (DRbTCPSocket#close_shutdown_pipe): New private method.
+ (DRbTCPSocket#accept): Use accept_or_shutdown.
+ (DRbTCPSocket#accept_or_shutdown): New private method which returns
+ nil on shutdown.
+ (DRbServer#stop_service): Use shutdown instead of Thread#kill.
+ (DRbServer#run): Break infinite loop when main_loop returns nil.
+ (DRbServer#main_loop): @protocol.accept may return nil.
+
+ * lib/drb/ssl.rb: Follow above change.
+
+ * lib/drb/unix.rb: Ditto.
+
+Sun Sep 21 13:54:36 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * time.c: raise exception when minutes of utc_offset is out of 00-59.
+ patch is from Kenichi Kamiya.
+ [ruby-dev:47539] [Bug #8679]
+
+ * test/ruby/test_time.rb: test for above.
+ patch is from Kenichi Kamiya.
+
+Sun Sep 21 19:04:08 2014 Narihiro Nakamura <authornari@gmail.com>
+
+ * st.c (do_hash_bin): unused macro.
+
+Sun Sep 21 18:45:01 2014 Narihiro Nakamura <authornari@gmail.com>
+
+ * parse.y (parser_class_nest): unused variable after YARV
+ merged (r11439).
+
+Sun Sep 21 18:14:03 2014 Narihiro Nakamura <authornari@gmail.com>
+
+ * st.c (numberof): unused. internal.h has same macro.
+
+ * node.c (F_CUSTOM2): unused.
+
+Sun Sep 21 14:11:23 2014 Tanaka Akira <akr@fsij.org>
+
+ * thread_pthread.c (native_set_thread_name): New function to
+ set thread name visible with ps command on GNU/Linux.
+ Ex. ps -o %c -L
+
+ * thread.c (thread_start_func_2): Call native_set_thread_name at
+ beginning.
+ (rb_thread_inspect_msg): Extract from rb_thread_inspect.
+
+Sun Sep 21 12:49:11 2014 Eric Wong <e@80x24.org>
+
+ * iseq.c (rb_iseq_defined_string): trim redundant semi-colon
+
+Sun Sep 21 12:19:29 2014 Eric Wong <e@80x24.org>
+
+ * file.c (rb_find_file_ext_safe): clear tmp buffer on failure
+ (rb_find_file_safe): ditto
+
+Sat Sep 20 04:42:18 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * lib/csv.rb: avoid unnecessary object allocations.
+ patch is from Andrew Vit. [ruby-core:63215] [Feature #9952]
+
+Sun Sep 21 12:10:18 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rexml/**/*.rb: removed commented-out code.
+
+Sat Sep 20 03:46:58 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c: use rb_equal_opt() for performance improvement.
+ [ruby-core:64954] [Feature #10227]
+
+Sun Sep 21 11:16:56 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (rbtime2vtdate, vtdate2rbtime): fix
+ the bug in conversion of milliseconds. [Bug #10258]
+
+ * test/win32ole/test_win32ole_variant.rb
+ (test_conversion_dbl2date_with_msec,
+ test_conversion_time2date_with_msec): use assert_in_delta instead
+ of assert_equal to treat an acceptable error range.
+
+Sun Sep 21 11:03:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (ruby_signal): although "EINVAL from sigaction(2) is
+ not a bug", but even it is a failure. pointed at toRuby/guRuby
+ in RubyHiroba.
+
+Sat Sep 20 03:00:26 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * lib/tempfile.rb: define parameters appropriately and some
+ refactoring.
+
+ * lib/tmpdir.rb: ditto.
+
+Sat Sep 20 23:58:21 2014 Tanaka Akira <akr@fsij.org>
+
+ * enum.c (enum_chunk): Deprecate the state management.
+ (enum_slice_before): Ditto.
+
+Sat Sep 20 15:39:11 2014 Tanaka Akira <akr@fsij.org>
+
+ * enum.c (enum_slice_when): New method: Enumerable#slice_when.
+ (slicewhen_i): New function.
+ (slicewhen_ii): New function.
+
+ * enumerator.c (InitVM_Enumerator): New method:
+ Enumerator::Lazy#slice_when.
+
+ [ruby-core:62499] [Feature #9826]
+
+Sat Sep 20 11:55:19 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * .travis.yml: added new configurations for osx on travis ci.
+ [fix GH-723]
+ * test/ruby/test_object.rb: tweaked to memory leak limit for osx build.
+
+Sat Sep 20 10:48:41 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (assoc): allow quoted ID as a key of a hash literal.
+ [ruby-core:34453] [Feature #4276]
+
+Sat Sep 20 10:23:00 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_set_arguments): store local variable IDs in
+ temporary list as Symbols. previously these are stored as
+ Fixnums to prevent from GC, but IDs of dynamic symbols can
+ exceed Fixnum range and cause RangeError at inverting from
+ Fixnum. [ruby-dev:48564] [Bug #10266]
+
+Sat Sep 20 10:02:51 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/openssl/lib/openssl/x509.rb (OpenSSL::X509::Name#pretty_print):
+ New method.
+ (OpenSSL::X509::Certificate#pretty_print): Ditto.
+
+ * ext/openssl/lib/openssl/bn.rb (OpenSSL::BN#pretty_print): Ditto.
+
+Sat Sep 20 07:55:57 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (eval_string_with_cref): fix super from eval with
+ scope. set klass in the current control frame to the class of
+ the receiver in the context to be evaluated, this class/module
+ must match the actual receiver to call super.
+ [ruby-core:65122] [Bug #10263]
+
+Fri Sep 19 20:06:00 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * symbol.c (rb_str_dynamic_intern): check if the stem ID of
+ attrset ID is already registered as a static ID.
+ [ruby-dev:48559] [Bug #10259]
+
+Fri Sep 19 15:48:09 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/Makefile.sub (VCSUP): nothing to do if this worktree is not
+ under any VCS (it means that the worktree may be from the release
+ package).
+
+Fri Sep 19 10:47:03 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/ruby/test_math.rb (TestMath#assert_infinity): Float#finite?
+ returns true also for NaN, so use Float#infinite? instead.
+ [ruby-core:65117] [Feature #10261]
+
+Fri Sep 19 05:36:16 2014 Eric Wong <e@80x24.org>
+
+ * NEWS: note --with-jemalloc option [ci skip]
+
+Thu Sep 18 16:26:27 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/rubygems/test_gem_commands_setup_command.rb: @ui uses StringIO
+ as its streams, and Encoding.default_external does not effect to
+ StringIOs already exist. so, we need to set external_encoding of
+ @ui.outs directly. this problem (test failure) does not appear in
+ the environments default_external is us-ascii or utf-8.
+
+Thu Sep 18 15:02:15 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/rubygems/test_gem_specification.rb: '/' is not always the root.
+
+Thu Sep 18 09:36:37 2014 Scott Francis <scott.francis@shopify.com>
+
+ * vm_method.c (Init_Method): make global method cache size
+ configurable by environment variable
+ "RUBY_GLOBAL_METHOD_CACHE_SIZE" [Fix GH-719]
+
+Thu Sep 18 07:03:36 2014 Eric Wong <e@80x24.org>
+
+ * test/-ext-/string/test_modify_expand.rb: increase limit
+ for {je,tc}malloc [Bug #10236]
+
+Thu Sep 18 06:41:18 2014 Eric Wong <e@80x24.org>
+
+ * ext/zlib/zlib.c (struct gzfile): pack (288 => 272 bytes) on 64-bit
+
+Thu Sep 18 05:44:05 2014 Eric Wong <e@80x24.org>
+
+ * ext/socket/init.c (rsock_connect): refactor for blocking
+ (wait_connectable): clear error before wait
+ [Bug #9356]
+
+Wed Sep 17 23:12:36 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/rfc3986_parser.rb: specify a regexp for :OPAQUE; generic.rb
+ assumes it is present, and will refuse all values otherwise.
+ by Matthew Draper <matthew@trebex.net>
+ https://github.com/ruby/ruby/pull/718 fix GH-718
+
+Wed Sep 17 16:22:58 2014 Eric Wong <e@80x24.org>
+
+ * ext/zlib/zlib.c (zlib_mem_alloc): check overflow
+
+Wed Sep 17 11:33:35 2014 Laurent Arnoud <laurent@spkdev.net>
+
+ * test/fiddle/test_import.rb (Fiddle::TestImport#test_sizeof):
+ added test for long long [fix GH-716]
+
+Wed Sep 17 11:09:21 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * tool/rbinstall.rb: fixed invalid options with latest rubygems.
+ https://github.com/rubygems/rubygems/issues/1013
+
+Tue Sep 16 19:19:00 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * benchmark/bm_app_aobench.rb: update outdated links to the
+ original program. [ruby-dev:48550] [Feature #10247]
+
+Tue Sep 16 01:06:40 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * reg*.c: Merge Onigmo 5.15.0 38a870960aa7370051a3544
+
+Mon Sep 15 16:21:10 2014 Eric Wong <e@80x24.org>
+
+ * io.c (struct io_advise_struct): 32 => 24 bytes on 64-bit
+ * io.c (struct io_internal_writev_struct): 24 => 16 bytes on 64-bit
+ * process.c (struct waitpid_arg): ditto
+
+Mon Sep 15 10:29:25 2014 Natalie Weizenbaum <nweiz@google.com>
+
+ * ext/pathname/lib/pathname.rb (SAME_PATHS):
+ Pathname#relative_path_from uses String#casecmp to compare strings
+ on case-insensitive filesystem platforms (e.g., Windows). This can
+ return nil for strings with different encodings, and the code
+ previously assumed that it always returned a Fixnum. [Fix GH-713]
+
+Mon Sep 15 09:43:18 2014 Sho Hashimoto <sho.hsmt@gmail.com>
+
+ * ext/fiddle/lib/fiddle/import.rb (Fiddle::Importer#sizeof): fix typo,
+ SIZEOF_LONG_LON. [Fix GH-714]
+
+Mon Sep 15 08:13:40 2014 Matthew Draper <matthew@trebex.net>
+
+ * sprintf.c (rb_str_format): rational 'f' format works for more
+ values. [fix GH-717]
+
+Sun Sep 14 16:57:27 2014 Eric Wong <e@80x24.org>
+
+ * template/vm.inc.tmpl: "insns.c" => "insns.def"
+ * tool/instruction.rb: typo fix
+
+Sun Sep 14 12:29:52 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/test_tracer.rb: fixed testcase for rubygems update.
+
+Sun Sep 14 12:29:02 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rubygems: Update to RubyGems 2.4.1 master(713ab65)
+ Complete history at:
+ https://github.com/rubygems/rubygems/blob/master/History.txt#L3-L216
+
+ * test/rubygems: ditto.
+
+Sun Sep 14 11:03:24 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych.rb: update version
+ * ext/psych/psych.gemspec: ditto
+
+Sun Sep 14 08:43:37 2014 Eric Wong <e@80x24.org>
+
+ * ccan/container_of/container_of.h (container_of_or_null): added
+ [ccan 7ec5b8e06b2fd5fa98b1fcde1158c286d2d429d8] (David Gibson)
+
+Sun Sep 14 08:41:44 2014 Eric Wong <e@80x24.org>
+
+ * ccan/list/list.h (list_del_init, list_node_init): new functions
+ for multiple list_del() calls
+ [ccan ec8654d94d3c5c47aa5f82698f7e8048c79765b1] (Rusty Russell)
+
+Sat Sep 13 22:19:26 2014 Bernard Potocki <bernard.potocki@imanel.org>
+
+ * hash.c (rb_hash_aset): fix misleading example which may suggest
+ that Hash.store will return self instead of value - Hash#store
+ is returning value and update itself, as well as Hash#[]=.
+ [Fix GH-715]
+
+Sat Sep 13 15:16:31 2014 Eric Wong <e@80x24.org>
+
+ * class.c: use ALLOC(rb_subclass_entry_t)
+
+Sat Sep 13 14:14:00 2014 Eric Wong <e@80x24.org>
+
+ * process.c (free_exec_arg): remove
+ (memsize_exec_arg): ptr is never NULL
+ (exec_arg_data_type): use RUBY_TYPED_DEFAULT_FREE
+
+ * variable.c (autoload_i_free): remove
+ (autoload_data_i_type): use RUBY_TYPED_DEFAULT_FREE
+ (autoload_memsize): ptr is never NULL
+
+ * vm_backtrace.c (location_free): remove
+ (location_mark): ptr is never NULL
+ (location_data_type): use RUBY_TYPED_DEFAULT_FREE
+ (backtrace_mark): ditto
+ (backtrace_free): ditto
+
+Sat Sep 13 13:43:07 2014 Eric Wong <e@80x24.org>
+
+ * doc/NEWS-2.0.0: fix typo for default RUBY_FIBER_MACHINE_STACK_SIZE
+ [ci skip]
+
+Sat Sep 13 11:16:58 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_event.c(ev_advise, ole_event_free,
+ fev_s_allocate, fev_unadvise): avoid segmentation fault when COM
+ server freed before calling Unadvise from WIN32OLE_EVENT object.
+ * ext/win32ole/win32ole.c: ditto.
+
+Sat Sep 13 09:47:44 2014 Eric Wong <e@80x24.org>
+
+ * man/ruby.1: use https for *.ruby-lang.org links
+
+Sat Sep 13 06:31:23 2014 Eric Wong <e@80x24.org>
+
+ * vm.c (thread_alloc): remove needless volatile
+
+Sat Sep 13 06:13:55 2014 Eric Wong <e@80x24.org>
+
+ * proc.c (proc_free): remove, use RUBY_TYPED_DEFAULT_FREE
+ (proc_mark, proc_memsize): remove needless branching
+
+ * vm.c (env_free): remove, use RUBY_TYPED_DEFAULT_FREE
+ (env_mark, env_memsize): remove needless branching
+
+Sat Sep 13 05:52:15 2014 Eric Wong <e@80x24.org>
+
+ * proc.c (rb_proc_alloc): inline and move to vm.c
+ (rb_proc_wrap): new wrapper function used by rb_proc_alloc
+ (proc_dup): simplify alloc + copy + wrap operation
+ [ruby-core:64994]
+
+ * vm.c (rb_proc_alloc): new inline function
+ (rb_vm_make_proc): call rb_proc_alloc
+
+ * vm_core.h: remove rb_proc_alloc, add rb_proc_wrap
+
+ * benchmark/bm_vm2_newlambda.rb: short test to show difference
+
+Sat Sep 13 04:40:04 2014 Eric Wong <e@80x24.org>
+
+ * process.c (Init_process): subclass Thread as Process::Waiter
+ (rb_detach_process): use Process::Waiter instead of singleton class
+ Thanks to headius and nobu. [Bug #10231]
+
+ * test/ruby/test_process.rb (test_process_detach): new test
+
+ * inits.c (rb_call_inits): call Init_Thread before Init_process to
+ ensure Process::Waiter may be a subclass of Thread
+
+Fri Sep 12 18:14:28 2014 Eric Wong <e@80x24.org>
+
+ * vm.c (env_alloc): inline to avoid extra zeroing
+ tiny speedup [ruby-core:64980]
+
+Fri Sep 12 17:13:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_method.c (rb_method_entry_make, remove_method): ditto.
+
+Fri Sep 12 14:39:55 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * gems/bundled_gems: Upgraded to test-unit-3.0.1 and minitest-5.4.1
+
+Fri Sep 12 06:55:40 2014 Eric Wong <e@80x24.org>
+
+ * string.c (Init_frozen_strings): use st_init_table_with_size
+
+Fri Sep 12 06:15:37 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (sym_find): remove Symbol.find because we have Symbol GC now.
+ https://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20140904Japan
+ If you still want this, request again on Redmine. [Feature #7854]
+ https://bugs.ruby-lang.org/issues/7854
+
+ * ext/-test-/symbol/init.c (sym_find): moved from string.c for tests.
+
+Fri Sep 12 04:24:03 2014 Eric Wong <e@80x24.org>
+
+ * insns.def (once): define and use fake RUNNING_THREAD_ONCE_DONE
+ pointer to indicate is->once.running_thread is done.
+
+ * vm_core.h (iseq_inline_storage_entry): remove done field,
+ allowing the union to be reduced from 24=>16 bytes on 64-bit
+ [Feature #10187]
+
+Thu Sep 11 20:10:00 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (rb_thread_mark): use rb_gc_mark_values() to mark VM stack.
+
+Thu Sep 11 19:50:57 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (rb_vm_register_special_exception): make new function to
+ make and register special exceptions.
+
+ * vm.c (rb_vm_mark): do not need to mark special exceptions
+ because they are registered by rb_gc_register_mark_object().
+
+ * eval.c (Init_eval): use rb_vm_register_special_exception().
+
+ * gc.c (Init_GC): ditto.
+
+ * proc.c (Init_Proc): ditto.
+
+ * thread.c (Init_Thread): ditto.
+
+Thu Sep 11 19:32:30 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_gc_mark_values): added.
+ This function is similar to rb_gc_mark_locations(), but not
+ conservative.
+
+ * internal.h: ditto.
+
+ * vm.c (env_mark): use rb_gc_mark_values() because env values should
+ be Ruby VALUEs.
+
+Thu Sep 11 19:16:39 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_mark_ptr): rename to gc_mark_set.
+
+ * gc.c (gc_mark): add gc_mark_ptr() to skip is_markable_object()
+ check. gc_mark_maybe() can use gc_mark_ptr() directly because
+ passed pointer is checked by is_pointer_to_heap().
+
+Thu Sep 11 18:40:16 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * .gitignore: ignored temporary files and coverage results.
+
+Thu Sep 11 18:15:30 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * .gitignore: ignored only simplecov.
+ * coverage/README: Added coverage docs.
+
+Thu Sep 11 17:25:31 2014 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h, gc.c: add new internal events
+ RUBY_INTERNAL_EVENT_GC_ENTER and
+ RUBY_INTERNAL_EVENT_GC_EXIT.
+
+ When invoking GC process, GC_ENTER event is called.
+ When exiting from GC process, GC_EXIT event is called.
+
+ Incremental GC (incremental marking and lazy sweep) can call
+ these events many times.
+
+ For example (minor marking):
+ (1) GC_ENTER
+ - (2) GC_START (minor GC)
+ (minor marking)
+ - (3) GC_END_MARK
+ (start lazy sweep)
+ (4) GC_EXIT
+ (ruby process)
+ (5) GC_ENTER
+ (lazy sweep)
+ (6) GC_EXIT
+ (ruby process)
+ (... repeat (5), (6))
+ (7) GC_ENTER
+ (finish lazy sweep)
+ - (8) GC_END_SWEEP
+ (9) GC_EXIT
+
+ 2nd example (incremental major marking):
+ (1) GC_ENTER
+ - (2) GC_START (minor GC)
+ (start incremental marking)
+ (3) GC_EXIT
+ (ruby process)
+ (4) GC_ENTER
+ (incremental marking)
+ (5) GC_EXIT
+ (ruby process)
+ (... repeat (4), (5))
+ (6) GC_ENTER
+ (finish incremental marking)
+ - (7) GC_END_MARK
+ (start lazy sweep)
+ (8) GC_EXIT
+ (ruby process)
+ (9) GC_ENTER
+ (lazy sweep)
+ (10) GC_EXIT
+ (ruby process)
+ (... repeat (9), (10))
+ (11) GC_ENTER
+ (finish lazy marking)
+ - (12) GC_STOP_SWEEP
+ (13) GC_EXIT
+
+ These internal events enable to measure GC pause time completely.
+
+Thu Sep 11 17:04:54 2014 Eric Wong <e@80x24.org>
+
+ * lib/benchmark.rb: remove CLOCK_MONOTONIC_RAW support
+ Thanks to Vit Ondruch for reporting the issue on ARM.
+ [Bug #10202]
+
+Thu Sep 11 14:31:57 2014 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h: freeze nil/true/false.
+ [Feature #8923]
+
+ * gc.c (should_be_finalizable): check frozen after checkin FL_ABLE.
+
+ * object.c (rb_obj_taint): check
+ OBJ_TAINTABLE(obj).
+
+ * object.c (rb_obj_freeze): remove immediate_frozen_tbl
+ because all of immediate values are frozen. YAY!
+
+ * object.c (rb_obj_frozen_p): ditto.
+
+ * test/ruby/test_eval.rb: skip instance_variable_set for
+ frozen objects.
+
+ * test/ruby/test_weakmap.rb: check ArgumentError instead of
+ RuntimeError.
+
+Thu Sep 11 10:03:16 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rdoc.rb, lib/rdoc, test/rdoc: Update to RDoc 4.2.0.alpha(21b241a)
+
+Wed Sep 10 17:52:25 2014 Koichi Sasada <ko1@atdot.net>
+
+ * compile.c (rb_vm_addr2insn): rename to rb_vm_insn_addr2insn
+ to clear what address.
+
+Wed Sep 10 16:22:26 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_gc.rb: fix condition.
+
+Wed Sep 10 15:29:46 2014 Eric Wong <e@80x24.org>
+
+ * vm_core.h (rb_call_info_t): ci->flag becomes 32-bit unsigned int
+ ci->index becomes a 32-bit signed int (from signed long).
+ Reorder for better packing on 64-bit, giving an 8 byte reduction
+ from 104 to 96 bytes for each ci.
+ [Feature #10187]
+
+ * compile.c (new_callinfo, setup_args, iseq_compile_each,
+ iseq_build_from_ary_body): adjust for type changes
+
+ * vm_insnhelper.c (vm_getivar): ditto
+
+Wed Sep 10 15:07:35 2014 Eric Wong <e@80x24.org>
+
+ * compile.c (rb_iseq_translate_threaded_code):
+ modify in-place w/o copy
+ (rb_vm_addr2insn): new function for debug
+ (rb_iseq_original_iseq): ditto
+ (iseq_set_sequence): assign iseq_encoded directly
+ [Feature #10185]
+
+ * vm_core (rb_iseq_t): move original ->iseq to bottom
+
+ * iseq.c (iseq_free, iseq_free): adjust for new layout
+ (rb_iseq_disasm): use original iseq for dump
+ (iseq_data_to_ary): ditto
+ (rb_iseq_line_trace_each): ditto
+ (rb_iseq_build_for_ruby2cext): use iseq_encoded directly
+
+ * vm_dump.c (rb_vmdebug_debug_print_pre): use original iseq
+
+Wed Sep 10 15:00:11 2014 Eric Wong <e@80x24.org>
+
+ * time.c (time_mark): remove NULL check
+ (time_memsize): ditto
+ (time_free): remove, use RUBY_TYPED_DEFAULT_FREE instead
+ [Feature #10219]
+
+Wed Sep 10 14:14:57 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * common.mk (encs enc trans libencs libenc libtrans): force to run
+ enk.mk because common.mk does not know the dependency, but enk.mk
+ knows. [ruby-dev:48530] [Bug #10220]
+
+Wed Sep 10 11:59:10 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat): update rdoc.
+
+Wed Sep 10 11:52:08 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat_internal): rename:
+ * malloc_increase -> malloc_increase_bytes
+ * malloc_limit -> malloc_increase_bytes_limit
+ * oldmalloc_increase -> oldmalloc_increase_bytes
+ * oldmalloc_limit -> oldmalloc_increase_bytes_limit
+ ref: [Feature #9924]
+
+Wed Sep 10 11:45:40 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat_internal): rename `heap_used' to `heap_allocated_pages'.
+ ref: [Feature #9924]
+
+ * test/ruby/test_gc.rb: add constraints test for gc stat information.
+
+Wed Sep 10 11:31:16 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat_internal): rename:
+ * remembered_shady_object -> remembered_wb_unprotected_objects
+ * remembered_shady_object_limit -> remembered_wb_unprotected_objects_limit
+ * old_object -> old_objects
+ * old_object_limit -> old_objects_limit
+ ref: [Feature #9924]
+
+Wed Sep 10 11:12:25 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat_internal): support:
+ * total_allocated_pages
+ * total_freed_pages
+ ref: [Feature #9924]
+
+Wed Sep 10 10:48:04 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_gc.rb: catch up last fix.
+
+Wed Sep 10 10:36:08 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (objspace_total_slot): rename objspace_available_slots.
+
+ * gc.c (objspace_live_slot, objspace_free_slot): rename
+ ..._slot() to ..._slots().
+
+ * gc.c (objspace_free_slot): should subtract heap_pages_final_slots.
+
+ * gc.c (gc_stat_internal):
+ * add `heap_available_slots' field
+ * rename heap_live_slot to heap_live_slots
+ * rename heap_free_slot to heap_free_slots
+ ref: [Feature #9924]
+
+Wed Sep 10 07:22:53 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: refactoring for RGENGC_PROFILE > 0.
+
+ * rename rb_objspace_t::profile::..._count
+ to rb_objspace_t::profile::total_..._count
+ * rename promote_infant_types to promote_types
+
+ * gc.c (gc_remember_unprotected): count remembered shady objects here.
+
+Wed Sep 10 03:12:12 2014 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * gc.c (init_mark_stack): MEMZERO() receive type as 2nd argument instead
+ of size.
+ Coverity Scan found this bug.
+
+Tue Sep 9 21:55:39 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/sample/excel2.rb: remove some commented-out code.
+ rotate graph more slowly to see graph clearly.
+
+Tue Sep 9 19:52:33 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename rb_objspace_t::marked_objects to marked_slots.
+
+ * gc.c (gc_marks_start): should be clear first.
+
+ * gc.c (gc_marks_start): remembered shady objects are also marked.
+
+ * gc.c (gc_stat_internal): add heap_marked_slots.
+
+Tue Sep 9 18:58:48 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename
+ * total_allocated_object_num -> total_allocated_objects
+ * total_allocated_object_num_at_gc_start -> total_allocated_objects_at_gc_start
+ * total_freed_object_num -> total_freed_objects
+
+ * gc.c (gc_stat_internal):
+ * rename total_allocated_object -> total_allocated_objects
+ * rename total_freed_object -> total_freed_objects
+
+Tue Sep 9 18:51:36 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat_internal): fix symbol names
+ * heap_final_slot -> heap_final_slots
+ * heap_swept_slot -> heap_swept_slots
+
+Tue Sep 9 18:18:07 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_objspace_t::heap_pages): rename field names:
+ * used -> allocated_pages
+ * increment -> allocatable_pages
+ * length -> sorted_length
+ And remove unused `limit' field.
+
+ * gc.c: rename macros:
+ * heap_pages_used -> heap_allocated_pages
+ * heap_pages_length -> heap_pages_sorted_length
+ * heap_pages_increment -> heap_allocatable_pages
+
+ * gc.c (gc_stat_internal): fix symbol names
+ * heap_used -> heap_allocated_pages
+ * heap_eden_page_length -> heap_eden_pages
+ * heap_tomb_page_length -> heap_tomb_pages
+ * heap_increment -> heap_allocatable_pages
+ * heap_length -> heap_sorted_length
+
+ ref: [Feature #9924]
+ https://docs.google.com/spreadsheets/d/11Ua4uBr6o0k-nORrZLEIIUkHJ9JRzRR0NyZfrhEEnc8/edit?usp=sharing
+ Yellow color fields in this table are changed.
+
+ * test/ruby/test_gc.rb: catch up this change.
+
+Tue Sep 9 14:56:03 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: continue layout changing.
+
+ newobj_of() also touch:
+ (4) increment total_allocated_object_num
+ (5) check hook_events
+
+ And gather fields related to marking phase.
+
+Tue Sep 9 14:21:50 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: fix layout of rb_objspace_t to improve cache locality.
+
+ newobj_of() accesses:
+ (1) rb_objspace_t::flags
+ (2) rb_objspace_t::eden_heap::freelist
+ (3) and rb_objspace_t::eden_heap::free_pages if freelist is NULL.
+
+Tue Sep 9 14:09:36 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: move rb_objspace_t::flags::gc_stressful after during_gc
+ to make accessing both parameters easy.
+
+ * gc.c (heap_get_freeobj): add LIKELY() hint.
+
+ * gc.c (heap_get_freeobj_from_next_freepage): ditto.
+
+ * gc.c (newobj_of): check both parameters at once for exceptional
+ case.
+
+Tue Sep 9 13:51:32 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: add rb_objspace_t::flags::gc_stressful and
+ ruby_gc_stressful macro.
+ Rename objspace->gc_stress to objspace->gc_stress_mode.
+
+ If objspace->gc_stress_mode is true (!nil and !false) then
+ ruby_gc_stressful becomes TRUE.
+
+ ruby_gc_stressful will speedup newobj_of() slightly.
+
+ * gc.c: initialize ruby_gc_stress(full|_mode) by gc_params.gc_stress
+ even if ENABLE_VM_OBJSPACE is false.
+
+Tue Sep 9 13:05:50 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: remove ruby_disable_gc_stress and add ruby_disable_gc
+ to speed-up newobj_of().
+
+ * gc.c (ready_to_gc): check ruby_disable_gc.
+
+ * signal.c: use ruby_disable_gc.
+
+Tue Sep 9 12:11:41 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename gc_stat entries and check stat transition.
+
+Tue Sep 9 12:06:03 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_sweep_rest): remove wrong modification of during_gc flag.
+
+Tue Sep 9 11:39:41 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: pack boolean values into rb_objspace_t::flags with bit fields
+ to improve cache locality.
+
+Tue Sep 9 11:11:05 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_object.rb: extend timeout.
+
+Tue Sep 9 09:02:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (MakeMakefile#pkg_config): append --cflags to also
+ $CXXFLAGS, as they are often used by C++ compiler.
+ [ruby-core:54532] [Bug #8315]
+
+Tue Sep 9 07:03:22 2014 Eric Wong <e@80x24.org>
+
+ * compile.c: remove needless SYM2ID <-> ID2SYM conversions
+ [misc #10207]
+
+Tue Sep 9 05:48:42 2014 Eric Wong <e@80x24.org>
+
+ * symbol.c (rb_intern_cstr_without_pindown): check dsymbol on return
+ This is not a complete fix for bug 10206, but seems to reduce
+ that crash and also looks correct.
+
+Tue Sep 9 04:36:24 2014 Eric Wong <e@80x24.org>
+
+ * vm_core.h (rb_env_t): use flexible array
+ This reduces allocations and speeds up the lambda calculus
+ fizzbuzz (bm_app_lc_fizzbuzz.rb) benchmark [ruby-core:64858]
+ * proc.c (get_local_variable_ptr): deconst to adjust for flex array
+ * vm.c (env_mark, env_free, env_memsize): remove check for env->env
+ * vm.c (env_alloc): single allocation for flex array
+ * vm.c (vm_make_env_each): adjust env_alloc call
+
+Mon Sep 8 16:08:22 2014 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/bm_app_lc_fizzbuzz.rb: should skip output on benchmark.
+
+Mon Sep 8 16:04:02 2014 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/bm_app_lc_fizzbuzz.rb: `answer.to_a' does not return
+ a string, but an array.
+
+Mon Sep 8 13:18:37 2014 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/bm_app_lc_fizzbuzz.rb: added.
+
+ This program is described closely in "Understanding Computation"
+ chapter 6 by Tom Stuart. <http://computationbook.com/>
+
+ Japanese translation will be published soon.
+ <http://www.oreilly.co.jp/books/9784873116976/>
+
+Mon Sep 8 12:01:39 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: add incremental GC algorithm. [Feature #10137]
+
+ Please refer this ticket for details.
+
+ This change also introduces the following changes.
+
+ * Remove RGENGC_AGE2_PROMOTION and introduce object age (0 to 3).
+ Age can be count with FL_PROMOTE0 and FL_PROMOTE1 flags in
+ RBasic::flags (2 bit). Age == 3 objects become old objects.
+ * WB_PROTECTED flag in RBasic to WB_UNPROTECTED bitmap.
+ * LONG_LIVED bitmap to represent living objects while minor GCs
+ It specifies (1) Old objects and (2) remembered shady objects.
+ * Introduce rb_objspace_t::marked_objects which counts marked
+ objects in current marking phase. marking count is needed to
+ introduce incremental marking.
+ * rename mark related function and sweep related function to
+ gc_(marks|sweep)_(start|finish|step|rest|continue).
+ * rename rgengc_report() to gc_report().
+ * Add obj_info() function to get cstr of object details.
+ * Add MEASURE_LINE() macro to measure execution time of specific line.
+ * and many small fixes.
+
+ * include/ruby/ruby.h: add flag USE_RINCGC.
+ Now USE_RINCGC can be set only with USE_RGENGC.
+
+ * include/ruby/ruby.h: introduce FL_PROMOTED0 and add FL_PROMOTED1
+ to count object age.
+
+ * include/ruby/ruby.h: rewrite write barriers for incremental marking.
+
+ * debug.c: catch up flag name changes.
+
+ * internal.h: add rb_gc_writebarrier_remember() instead of
+ rb_gc_writebarrier_remember_promoted().
+
+ * array.c (ary_memcpy0): use rb_gc_writebarrier_remember().
+
+ * array.c (rb_ary_modify): ditto.
+
+ * hash.c (rb_hash_keys): ditto.
+
+ * hash.c (rb_hash_values): ditto.
+
+ * object.c (init_copy): use rb_copy_wb_protected_attribute() because
+ FL_WB_PROTECTED is moved from RBasic::flags.
+
+ * test/objspace/test_objspace.rb: catch up ObjectSpace.dump() changes.
+
+Sun Sep 7 12:47:06 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c: PTHREAD_CANCEL_DISABLE is not defined on Android.
+
+Sat Sep 6 20:59:06 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (has_privilege): The gid zero is not a privilege.
+
+Sat Sep 6 20:19:16 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (struct child_handler_disabler_state): cancelstate field
+ added.
+ (disable_child_handler_before_fork): Record cancelstate.
+ (disable_child_handler_fork_parent): Restore cancelstate.
+
+Sat Sep 6 19:27:10 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (struct child_handler_disabler_state): Defined.
+
+Sat Sep 6 18:31:32 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rake.rb, lib/rake/*, test/rake/*: Update latest rake master(e47d023)
+
+Sat Sep 6 16:38:08 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_variant.c (ole_val2variant_err,
+ ole_val2variantdata, Init_win32ole_variant): support VT_ERROR
+ variant with error code. add WIN32OLE_VARIANT::NoParam.
+ * test/win32ole/test_win32ole_variant.rb(test_c_noparam,
+ test_vt_error_noparam): ditto.
+ * ext/win32ole/win32ole.c: ditto.
+
+Sat Sep 6 11:08:52 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (arg_ambiguous_gen): fix warning message, "even" does
+ not mean the number of spaces here. state the place to put a
+ space and the operator. [ruby-core:64790] [Bug #10204]
+
+Sat Sep 6 08:44:40 2014 Zachary Scott <e@zzak.io>
+
+ * lib/rdoc/generator/template/darkfish/js/jquery.js: Backport
+ rdoc/rdoc@74f60fcb04fee1778fe2694d1a0ea6513f8e67b7
+
+Sat Sep 6 08:10:44 2014 Eric Wong <e@80x24.org>
+
+ * test/ruby/test_io.rb (test_readpartial_locktmp): use IO#nonblock=
+ Old fcntl invocation may drop necessary flags on some platforms.
+
+Sat Sep 6 07:46:51 2014 Eric Wong <e@80x24.org>
+
+ * test/ruby/test_io.rb (test_readpartial_locktmp): avoid EBADF
+ [ruby-core:64773] [ruby-core:64775]
+
+Sat Sep 6 01:34:31 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_f_exec): Call before_exec_async_signal_safe and
+ after_exec_async_signal_safe around rb_exec_async_signal_safe.
+ (rb_exec_async_signal_safe): Don't call
+ before_exec_async_signal_safe and after_exec_async_signal_safe.
+ (rb_exec_without_timer_thread): Call before_exec and
+ after_exec.
+ (disable_child_handler_fork_child): Make SIGPIPE handler SIG_DFL.
+
+Sat Sep 6 00:49:41 2014 Tanaka Akira <akr@fsij.org>
+
+ * signal.c (ruby_signal): Don't set SA_SIGINFO for SIG_IGN and
+ SIG_DFL.
+
+Fri Sep 5 21:45:33 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (disable_child_handler_before_fork): New function.
+ (disable_child_handler_fork_parent): Ditto.
+ (disable_child_handler_fork_child): Ditto.
+ (retry_fork_async_signal_safe): Call above functions to disable
+ signal handlers in child process.
+
+Fri Sep 5 21:02:54 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (handle_fork_error): Make try_gc_p argument volatile to
+ suppress "clobbered" warning.
+
+Fri Sep 5 20:48:06 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (handle_fork_error): Don't need state_p argument.
+
+Fri Sep 5 20:35:52 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (has_privilege): Fix a return value.
+
+Fri Sep 5 19:00:40 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/shellwords.rb: proofreading documentation.
+ [Bug #10155][ruby-core:64471]
+
+Fri Sep 5 18:34:33 2014 Laurent Arnoud <laurent@spkdev.net>
+
+ * test/csv/test_row.rb: Added some missing tests in CSV.
+ [fix GH-710]
+ * test/csv/test_table.rb: ditto.
+
+Fri Sep 5 12:57:52 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (has_privilege): Refine uid/gid check.
+
+Fri Sep 5 12:40:55 2014 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Check sys/id.h, getuidx and getgidx for AIX.
+
+ * process.c (getresuid): Defined for AIX.
+ (getresgid): Ditto
+ AIX don't have getresuid/getresgid but getuidx/getgidx.
+
+Fri Sep 5 12:28:21 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (has_privilege): Fix assignments.
+
+Fri Sep 5 11:10:13 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rdoc/generator/pot/po.rb: fixed broken tests for trailing whitespace.
+ * test/rdoc/test_rdoc_generator_pot.rb: ditto.
+ * test/rdoc/test_rdoc_generator_pot_po.rb: ditto.
+
+Fri Sep 5 10:41:07 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/rdoc/test_rdoc_rdoc.rb (TestRDocRDoc#test_parse_file_encoding):
+ typofix.
+
+Fri Sep 5 10:39:14 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rdoc.rb, lib/rdoc, test/rdoc: Update to RDoc 4.2.0.alpha(313287)
+
+Fri Sep 5 06:04:22 2014 Eric Wong <e@80x24.org>
+
+ * vm.c: remove unused USE_THREAD_RECYCLE [misc #10198]
+
+Fri Sep 5 00:29:08 2014 Tanaka Akira <akr@fsij.org>
+
+ * configure.in (dirfd): Check function.
+
+ * dir.c (dir_fileno): New method.
+ [ruby-dev:48265] [Feature #9880]
+
+Thu Sep 4 23:39:52 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (has_privilege): New function.
+ (retry_fork_async_signal_safe): Don't use vfork() for privileged
+ process.
+
+ * configure.in (getresuid): Check function.
+ (getresgid): Ditto.
+
+Thu Sep 4 20:22:14 2014 Laurent Arnoud <laurent@spkdev.net>
+
+ * test/pathname/test_pathname.rb: added testcase for Pathname#mountpoint?.
+ [fix GH-709]
+
+Thu Sep 4 20:09:21 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * symbian/*: removed Symbian support.
+ [Feature #10199][ruby-core:64725]
+ * dln.c: ditto.
+ * include/ruby/defines.h: ditto.
+ * thread_pthread.c: ditto.
+ * vm.c: ditto.
+
+Thu Sep 4 17:44:40 2014 Koichi Sasada <ko1@atdot.net>
+
+ * dir.c (glob_helper): use #ifdef instead of #if.
+ gcc's -Wundef option shows warning for undefined macro.
+
+ * numeric.c (flo_is_finite_p): ditto.
+
+ * vm_dump.c (rb_vmdebug_thread_dump_state): ditto.
+
+ * vm_core.h: define VM_DEBUG_VERIFY_METHOD_CACHE to 0.
+
+Thu Sep 4 03:57:46 2014 Eric Wong <e@80x24.org>
+
+ * man/ruby.1: spelling fix ("bellow" => "below") [ci-skip]
+
+Thu Sep 4 03:52:16 2014 Eric Wong <e@80x24.org>
+
+ * man/ruby.1: add trailing slash to URLs [ci-skip]
+
+Wed Sep 3 19:10:28 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (before_fork_ruby): Renamed from before_fork.
+ (after_fork_ruby): Renamed from after_fork.
+
+Wed Sep 3 18:56:05 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (forked_child): Removed.
+
+Wed Sep 3 16:56:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_obj_copy_ivar): allocate no memory for empty
+ instance variables. [ruby-core:64700] [Bug #10191]
+
+Wed Sep 3 12:05:17 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (retry_fork_async_signal_safe): Use vfork() if available.
+ vfork() is still faster than fork() especially when the parent
+ process uses big memory.
+
+ ruby -rbenchmark -e 'a = "a" * 1_000_000_000; puts Benchmark.measure { system("true") }'
+ fork: 0.000000 0.010000 0.010000 ( 0.014968)
+ vfork: 0.000000 0.000000 0.000000 ( 0.000912)
+ on Debian sid.
+
+Wed Sep 3 11:33:08 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/openssl/test_pkey_rsa.rb (OpenSSL#test_sign_verify_memory_leak):
+ added timeout into testcase for low performance environment.
+ [Bug #9984][ruby-core:63367]
+
+Wed Sep 3 07:50:15 2014 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Use AC_FUNC_FORK.
+
+ * io.c: Use HAVE_WORKING_FORK instead of HAVE_FORK.
+
+ * process.c: Ditto.
+
+Wed Sep 3 00:12:44 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (retry_fork_async_signal_safe): Don't return on in child
+ process.
+
+Tue Sep 2 23:47:35 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (retry_fork_async_signal_safe): Specialized version of
+ retry_fork respect to rb_fork_async_signal_safe.
+ (retry_fork_ruby): Specialized version of retry_fork respect to
+ rb_fork_ruby.
+ (rb_fork_ruby): Removed.
+
+Tue Sep 2 23:26:26 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (send_child_error): Simplified.
+ (recv_child_error): Ditto.
+
+Tue Sep 2 22:56:25 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (rb_fork_async_signal_safe): Inline rb_fork_internal.
+ (rb_fork_ruby): Ditto.
+ (rb_fork_internal): Removed.
+ (chfunc_protect): Removed.
+
+Tue Sep 2 22:43:52 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_io.rb (test_new_with_block): Set autoclose to avoid
+ EBADF.
+
+Tue Sep 2 22:01:51 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * Makefile.in (update-coverage): Remove a never executed line.
+
+Tue Sep 2 19:48:26 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (handle_fork_error): Extracted from retry_fork.
+
+Tue Sep 2 17:02:53 2014 Vit Ondruch <v.ondruch@tiscali.cz>
+
+ * tool/rbinstall.rb: fixed error of local installation.
+ [Bug #10192][ruby-core:64702]
+
+Tue Sep 2 16:58:03 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/runner.rb: reporting test coverage for test-all with COVERAGE env.
+ [Feature #10189][ruby-core:64681][fix GH-708]
+ * Makefile.in: added task for coverage report.
+ * common.mk: added definition of forked simplecov url.
+ * .gitignore: ignored coverage directory.
+
+Mon Sep 1 20:11:02 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (rbtime2vtdate): try to convert millisecond
+ of Time object to millisecond of VT_DATE VARIANT.
+ * test/win32ole/test_win32ole_variant.rb
+ (test_conversion_time2date_with_msec): ditto.
+
+Sun Aug 31 16:58:49 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/benchmark.rb: Fix a syntax error.
+
+Sun Aug 31 08:46:44 2014 Eric Wong <e@80x24.org>
+
+ * ext/zlib/zlib.c (gzfile_reset): preserve ZSTREAM_FLAG_GZFILE
+ [Bug #10101]
+
+ * test/zlib/test_zlib.rb (test_rewind): test each_byte
+
+Sat Aug 30 19:22:47 2014 Eric Wong <e@80x24.org>
+
+ * symbol.c (rb_sym2id): do not return garbage object
+
+Sat Aug 30 06:39:48 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: fix NameError dumping and
+ loading. Fixes GH #85. Thanks @brentdax for the patch!
+ * test/psych/test_exception.rb: test for fix
+
+Sat Aug 30 06:23:40 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/scalar_scanner.rb: fix loading strings that
+ look like integers but have a newline. Fixes GH #189
+ * test/psych/test_string.rb: test for fix
+
+Sat Aug 30 06:10:39 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/to_ruby.rb: merge keys with a hash
+ should merge the hash in to the parent.
+ * test/psych/test_merge_keys.rb: test for change. Fixes GH #202
+
+Sat Aug 30 06:00:26 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/to_ruby.rb: quoted "<<" strings
+ should not be treated as merge keys.
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: hashes with keys
+ containing "<<" should roundtrip.
+ * test/psych/test_merge_keys.rb: test for change. Fixes GH #203
+
+Fri Aug 29 17:56:44 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/net/imap/test_imap_response_parser.rb: removed needless code.
+
+Fri Aug 29 17:36:58 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/rinda/test_rinda.rb: removed useless assignment variables.
+ * test/rss/rss-assertions.rb: ditto.
+ * test/rss/test_maker_itunes.rb: ditto.
+
+Fri Aug 29 16:18:26 2014 Eric Wong <e@80x24.org>
+
+ * string.c: revert part of r47311, add rb_vm_fstring_table(),
+ remove vm_core.h dependency. [ruby-core:64627]
+
+Fri Aug 29 15:17:13 2014 Eric Wong <e@80x24.org>
+
+ * string.c: remove static frozen_strings
+ * string.c (Init_frozen_strings): new function
+ * string.c (rb_fstring): remove check for frozen strings,
+ use per-VM table
+ * string.c (rb_str_free): use per-VM table
+ * string.c (Init_String): use per-VM table
+ * vm_core.h (rb_vm_t): add frozen_strings table
+ * internal.h (Init_frozen_strings): new function prototype
+ * eval.c (ruby_setup): call Init_frozen_strings
+ [Feature #10182]
+
+Wed Aug 27 23:10:24 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * lib/tempfile.rb: remove "require 'thread'". its features are no
+ longer used.
+
+Wed Aug 27 21:19:40 2014 gogo tanaka <mail@tanakakazuki.com>
+
+ * lib/drb/acl.rb: Removed meaningless #to_s methods in interpolation.
+ [Feature #10174][ruby-core:64584]
+ * lib/erb.rb: ditto.
+ * lib/observer.rb: ditto.
+ * lib/rake/invocation_chain.rb: ditto.
+ * lib/rubygems/command_manager.rb: ditto.
+ * lib/rubygems/config_file.rb: ditto.
+ * lib/uri/common.rb: ditto.
+
+Wed Aug 27 21:08:20 2014 gogo tanaka <mail@tanakakazuki.com>
+
+ * lib/drb/drb.rb: use attr_reader instead of Module#attr.
+ [Feature #10172][ruby-core:64582]
+ * lib/irb/ruby-token.rb: ditto.
+ * lib/net/telnet.rb: ditto.
+ * lib/rdoc/ruby_token.rb: ditto.
+ * lib/thwait.rb: ditto.
+
+Wed Aug 27 19:52:33 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (vtdate2rbtime): try to convert millisecond
+ of VT_DATE VARIANT to nsec of Time object.
+ * test/win32ole/test_win32ole_variant.rb
+ (test_conversion_dbl2date_with_msec): ditto.
+
+Wed Aug 27 09:57:29 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/ruby/test_complex.rb: removed unreachable code.
+ * test/ruby/test_rational.rb: ditto.
+
+Wed Aug 27 07:59:17 2014 Eric Wong <e@80x24.org>
+
+ * compile.c (iseq_set_sequence): check for multiplication overflow
+
+Tue Aug 26 22:07:42 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/ruby/test_complex.rb: cherry-picked working assertions from r47251.
+ * test/ruby/test_rational.rb: cherry-picked working assertions from r47263.
+
+Tue Aug 26 21:07:56 2014 gogo tanaka <mail@tanakakazuki.com>
+
+ * lib/mathn.rb (Fixnum#**, Bignum#**, Float#**, Rational#**):
+ remove as these are now built-in. [ruby-core:63973] [Bug #10086]
+
+Tue Aug 26 20:46:55 2014 Tanaka Akira <akr@fsij.org>
+
+ * time.c (rb_time_unmagnify_to_float): Avoid double rounding.
+ Reported by Tsuyoshi Sawada.
+ https://bugs.ruby-lang.org/issues/10135#note-1
+
+Tue Aug 26 17:12:47 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (io_close): ignore only "closed stream" IOError and
+ NoMethodError, do not swallow other exceptions at the end of
+ block. [ruby-core:64463] [Bug #10153]
+
+Tue Aug 26 13:46:33 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * template/fake.rb.in: fix failed to make install when @srcdir@ is
+ absolute path.
+
+Tue Aug 26 13:43:50 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/ruby/test_range.rb: added workaround for VERBOSE message.
+
+Tue Aug 26 12:38:02 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/test_mathn.rb: added workaround for VERBOSE messages.
+
+Tue Aug 26 11:44:04 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/shell/process-controller.rb: removed commented-out code.
+
+Tue Aug 26 11:39:01 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/thwait.rb (ThreadsWait): removed needless constant.
+
+Tue Aug 26 09:27:10 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/mathn.rb: mathn library is deprecated on ruby 2.2.
+ [Feature #10169][ruby-core:64553]
+
+Tue Aug 26 09:25:03 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/mathn.rb: removed commented-out code.
+
+Mon Aug 25 20:15:50 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c(fole_s_connect, fole_initialize): raise a
+ security error with the tainted string object.
+ * ext/win32ole/win32ole_event.c(ev_advise): ditto.
+ * test/win32ole/test_win32ole.rb(test_s_new_exc_svr_tainted,
+ test_s_new_exc_host_tainted): ditto.
+ * test/win32ole/test_win32ole_event.rb(test_s_new_exc_tainted): ditto.
+
+Mon Aug 25 12:56:54 2014 Ivan Korunkov <ivankorunkov@ya.ru>
+
+ * lib/logger.rb (format_datetime): use "%6N" to show microsecond.
+ [Fix GH-704]
+
+Mon Aug 25 11:02:07 2014 Eric Wong <e@80x24.org>
+
+ * vm_core.h (rb_iseq_location_t): change first_lineno type to VALUE
+ * iseq.c (rb_iseq_build_for_ruby2cext): update based on argument
+
+Sun Aug 24 16:14:46 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/e2mmap.rb: remove needless instance variables.
+ * lib/irb.rb: ditto.
+ * lib/irb/**/*.rb: ditto.
+ * lib/shell.rb: ditto.
+
+Sun Aug 24 12:44:26 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/ruby/test_complex.rb: removed needless conditions.
+ * test/ruby/test_rational.rb: ditto.
+
+Sun Aug 24 11:47:39 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/ruby/test_rational.rb: fixed indent.
+
+Sun Aug 24 11:44:11 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/ruby/test_rational.rb: remove commented-out code.
+
+Sun Aug 24 11:09:29 2014 Eric Wong <e@80x24.org>
+
+ * lib/benchmark.rb (measure): reduce allocations as in r47260
+
+Sun Aug 24 10:35:54 2014 Pete Higgins <pete@peterhiggins.org>
+
+ * lib/benchmark.rb (module Benchmark): define BENCHMARK_CLOCK
+ (realtime): use Process.clock_gettime(BENCHMARK_CLOCK)
+ Reduces allocations to improve performance [Feature #10165]
+
+ * test/benchmark/test_benchmark.rb (test_realtime_output): new test
+
+Fri Aug 22 20:23:54 2014 Koichi Sasada <ko1@atdot.net>
+
+ * string.c (rb_fstring): fix condition (easy to cause infinite loop!).
+
+Fri Aug 22 20:07:43 2014 Koichi Sasada <ko1@atdot.net>
+
+ * string.c (rb_fstring, fstr_update_callback): simply delete garbage
+ key first.
+
+ Garbage keys can be swept by lazy sweeping invoked by creating new
+ fstring. So that simply do:
+ (1) delete garbage key and return `fstr_update_callback' immediately
+ (2) try again `fstr_update_callback()' to create a new fstr.
+
+ This bug can be cause memory corruption, reported by
+ http://u64.rubyci.org/~chkbuild/ruby-trunk/log/20140821T220302Z.fail.html.gz
+
+Fri Aug 22 19:30:39 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/ruby/test_complex.rb: removed commented-out code.
+
+Fri Aug 22 19:25:28 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/ruby/test_complex.rb: fixed broken tests. Math is not
+ compatible CMath now.
+
+Fri Aug 22 15:36:09 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (Doxyfile): revert r43888, not to require preinstalled
+ ruby. [ruby-core:64488] [Bug #10161]
+
+Fri Aug 22 12:32:15 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/shell.rb: removed commented-out code.
+ * lib/shell/builtin-command.rb: ditto.
+ * lib/shell/command-processor.rb: ditto.
+
+Fri Aug 22 12:21:46 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/complex.rb: removed deprecated library.
+ * lib/rational.rb: ditto.
+
+Fri Aug 22 11:38:49 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/prettyprint.rb: removed PrettyPrint#first?
+ because it is obsoleted method since Ruby 1.8.2
+
+Thu Aug 21 17:10:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (constat_attr): manage reverse video internally
+ since Windows console window does not manage it. based on the
+ patch by white leaf in [ruby-dev:48483]. [Bug #10158]
+
+Thu Aug 21 14:45:41 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/e2mmap.rb: removed commented-out code.
+
+Thu Aug 21 13:23:34 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rinda/ring.rb: split executable code into sample directory.
+ * sample/rinda-ring.rb: ditto.
+
+Thu Aug 21 13:21:45 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/drb/acl.rb: split executable code into sample directory.
+ * sample/drb/acl.rb: ditto.
+
+Thu Aug 21 12:55:35 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * .gitignore: ignored temporary file for Changelog.
+ http://mkosaki.blog46.fc2.com/blog-entry-1284.html
+
+Thu Aug 21 12:40:22 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/net/imap.rb: split executable code into sample directory.
+ * sample/net-imap.rb: ditto.
+
+Thu Aug 21 12:23:56 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/net/imap.rb: removed commented-out code.
+
+Wed Aug 20 17:27:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_TRY_CFLAGS, RUBY_TRY_LDFLAGS),
+ (RUBY_CHECK_BUILTIN_SETJMP, RUBY_SETJMP_TYPE),
+ (RUBY_STACK_GROW_DIRECTION): quote defun names, for some
+ versions of autoconf possibly. [ruby-core:64473] [Bug #10156]
+
+Tue Aug 19 22:28:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * sprintf.c (rb_str_format): fix condition to round.
+ [ruby-core:64454] [Bug #10151]
+
+Tue Aug 19 22:22:45 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enc/trans/euckr-tbl.rb (EUCKR_TO_UCS_TBL): add missing euro and
+ registered signs. [ruby-core:64452] [Bug #10149]
+
+Tue Aug 19 13:59:43 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compar.c (rb_cmperr): preserve encodings of arguments in the
+ message.
+
+Tue Aug 19 10:13:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/thread/thread.c (get_array): check instance variables are
+ initialized properly. [ruby-core:63826][Bug #10062]
+
+Mon Aug 18 17:06:27 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * sprintf.c (rb_str_format): support rational 'f' format.
+ [ruby-core:64382] [Bug #10136]
+
+Mon Aug 18 08:03:46 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * spec/default.mspec: use 2.2 definition.
+
+Sun Aug 17 19:41:40 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * gc.c (obj_memsize_of): don't calculate memsize of T_NODE
+ when called from check_gen_consistency. It fixes segmentation
+ fault on RGENGC_CHECK_MODE >= 1 introduced by r47188.
+
+Sun Aug 17 17:08:12 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_invoke): use RHASH_SIZE instead of
+ calling Hash#length method.
+
+Sat Aug 16 19:32:06 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_event.c (evs_length): use RARRAY_LEN instead
+ of calling Array#length method.
+
+Sat Aug 16 10:20:17 2014 Eric Wong <e@80x24.org>
+
+ * time.c (time_timespec): fix tv_nsec overflow
+ [Bug #10144]
+
+Fri Aug 15 20:34:17 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: separate WIN32OLE_EVENT src from
+ win32ole.c.
+ * ext/win32ole/win32ole.h: ditto.
+ * ext/win32ole/win32ole_event.c: ditto.
+ * ext/win32ole/win32ole_event.h: ditto.
+ * ext/win32ole/depend: ditto.
+
+Fri Aug 15 19:38:00 2014 Koichi Sasada <ko1@atdot.net>
+
+ * iseq.c (rb_iseq_clone): Should not insert write barrier from
+ non-RVALUE data (to non-RVALUE data, of course).
+
+ Ruby 2.1 also has a same problem.
+
+Fri Aug 15 19:34:33 2014 Koichi Sasada <ko1@atdot.net>
+
+ * string.c (setup_fake_str): fake strings should not set class by
+ RBASIC_SET_CLASS() because it insert write barriers to fake
+ (non-RVALUE) structure.
+
+ It can cause unexpected behaviour.
+
+ Ruby 2.1 also have a same problem (setup_fake_str() in parse.y).
+
+ * symbol.c (setup_fake_str): ditto.
+
+Fri Aug 15 19:27:25 2014 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (rb_ary_tmp_new_fill): added.
+ This function creates internal use only array (which is completely
+ hided by ObjectSpace.each_object) with filling nil.
+
+ Otherwise, it can be includes strange VALUEs.
+
+ * internal.h: added.
+
+ * node.h: use rb_ary_tmp_new_fill() for MEMO.
+
+Fri Aug 15 10:13:37 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/gserver.rb: removed unmaintained code.
+ [ruby-core:40313][Feature #5480]
+ * lib/xmlrpc/httpserver.rb: ditto.
+
+Fri Aug 15 09:22:12 2014 Eric Wong <e@80x24.org>
+
+ * vm_core.h (rb_thread_struct): reorder to pack
+ * cont.c (rb_context_struct, rb_fiber_struct): ditto
+ On x86-64, these changes reduces:
+ rb_thread_struct to 1000 bytes (from 1016)
+ rb_context_struct to 1288 bytes (from 1312)
+ rb_fiber_struct to 2272 bytes (from 2304)
+
+Fri Aug 15 09:06:31 2014 Eric Wong <e@80x24.org>
+
+ * thread_pthread.h: define RB_NATIVETHREAD_LOCK_INIT and
+ RB_NATIVETHREAD_COND_INIT macros
+
+ * thread_pthread.c (native_mutex_lock, native_mutex_unlock,
+ native_mutex_trylock, native_mutex_initialize,
+ native_mutex_destroy, native_cond_wait):
+ use rb_nativethread_lock_t instead of pthread_mutex_t
+ [Feature #10134]
+
+ * thread_pthread.c (native_mutex_debug): make argument type-agnostic
+ to avoid later cast.
+
+ * thread_pthread.c (register_cached_thread_and_wait):
+ replace PTHREAD_COND_INITIALIZER with RB_NATIVETHREAD_COND_INIT,
+ use native_mutex_{lock,unlock}
+
+ * thread_pthread.c (use_cached_thread):
+ use native_mutex_{lock,unlock}
+
+ * thread_pthread.c (native_sleep):
+ use rb_nativethread_lock_t to match th->interrupt_lock,
+ use native_mutex_{lock,unlock}
+
+ * thread_pthread.c (timer_thread_lock): use rb_nativethread_lock_t type
+
+Fri Aug 15 08:10:29 2014 Eric Wong <e@80x24.org>
+
+ * cont.c (cont_mark): fix typo in unused path [ci skip]
+
+Fri Aug 15 06:00:56 2014 Eric Wong <e@80x24.org>
+
+ * vm.c (rb_thread_mark): update comment about marking `me'
+ [ruby-core:64340] [ruby-core:64341]
+
+Fri Aug 15 05:53:59 2014 Eric Wong <e@80x24.org>
+
+ * README.EXT: preliminary documentation for RB_GC_GUARD
+ [Bug #10100] [ruby-core:60741]
+
+Thu Aug 14 00:26:19 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: separate WIN32OLE_RECORD src from
+ win32ole.c
+ * ext/win32ole/win32ole.h: ditto.
+ * ext/win32ole/win32ole_record.c: ditto.
+ * ext/win32ole/win32ole_record.h: ditto.
+ * ext/win32ole/depend: ditto.
+
+Wed Aug 13 21:41:04 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: separate WIN32OLE_VARIANT src from
+ win32ole.c.
+ * ext/win32ole/win32ole.h: ditto.
+ * ext/win32ole/win32ole_variant.c: ditto.
+ * ext/win32ole/win32ole_variant.c: ditto.
+ * ext/win32ole/depend: ditto.
+
+Wed Aug 13 20:09:37 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: remove unused variable.
+
+Wed Aug 13 19:31:27 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_search_handler_method, rescue_callback,
+ folerecord_inspect): use PRIsVALUE in rb_sprintf.
+
+ * ext/win32ole/win32ole_param.c (foleparam_inspect): ditto.
+
+ * ext/win32ole/win32ole_variable.c (folevariable_inspect): use
+ PRIsVALUE in rb_sprintf, use rb_inspect.
+
+Wed Aug 13 11:54:41 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/irb/completion.rb: reverted r47163.
+ because another case can't be show completion target.
+
+Wed Aug 13 11:17:00 2014 Shimpei Makimoto <github@makimoto.org>
+
+ * lib/irb.rb: Prevent irb from crashing when exception with
+ nil backtrace is raised.
+ [fix GH-434][ruby-core:58078][Bug #9063]
+ * test/irb/test_raise_no_backtrace_exception.rb: ditto.
+
+Wed Aug 13 11:08:55 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/irb/completion.rb: fixed broken completion list with
+ String including spaces. Contributed from @dunric. [fix GH-465]
+
+Wed Aug 13 00:07:01 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: separate WIN32OLE_PARAM src from win32ole.c
+ * ext/win32ole/win32ole.h: ditto.
+ * ext/win32ole/win32ole_param.c: ditto.
+ * ext/win32ole/win32ole_param.h: ditto.
+ * ext/win32ole/depend: ditto.
+
+Tue Aug 12 23:17:47 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: refactoring. move some methods
+ into win32ole_type.c / win32ole_method.c
+ * ext/win32ole/win32ole.h: ditto.
+ * ext/win32ole/win32ole_method.c: ditto.
+ * ext/win32ole/win32ole_method.h: ditto.
+ * ext/win32ole/win32ole_type.h: ditto.
+ * ext/win32ole/win32ole_type.h: ditto.
+
+Tue Aug 12 22:59:48 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: refactoring. move
+ ole_typelib_from_itypeinfo into win32ole_typelib.c.
+ * ext/win32ole/win32ole.h: ditto.
+ * ext/win32ole/win32ole_typelib.h: ditto.
+ * ext/win32ole/win32ole_typelib.h: ditto.
+
+Tue Aug 12 21:49:40 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_create_dcom): use the converted
+ result if the argument can be converted to a string, to get rid
+ of invalid access. Thanks to nobu. [ruby-dev:48467] [Bug #10127]
+
+Tue Aug 12 14:22:58 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * configure.in: ignored working directory same as prefix value.
+ [ruby-core:54999] [Bug #8409]
+
+Tue Aug 12 13:34:25 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/fileutils.rb: enable to remove with non-owner directory.
+ [ruby-dev:45976] [Bug #6756]
+ * test/fileutils/test_fileutils.rb: add testcase for #6756.
+
+Tue Aug 12 12:57:28 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * vm_exec.c: improve performance in ppc64 arch.
+ [ruby-core:63437] [Feature #9997]
+
+Tue Aug 12 12:14:52 2014 Akira Matsuda <ronnie@dio.jp>
+
+ * lib/fileutils.rb: fix typo.
+ [ruby-dev:47831] [Bug #9180]
+
+Tue Aug 12 10:10:42 2014 Eric Wong <e@80x24.org>
+
+ * vm_method.c (release_method_definition): use rb_free_method_entry
+
+Tue Aug 12 06:16:09 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: separate WIN32OLE_METHOD src from
+ win32ole.c.
+ * ext/win32ole/win32ole.h: ditto.
+ * ext/win32ole/win32ole_method.c: ditto.
+ * ext/win32ole/win32ole_method.h: ditto.
+ * ext/win32ole/depend: ditto.
+
+Mon Aug 11 22:19:15 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_variable.c (folevariable_inspect): refactoring.
+
+Mon Aug 11 20:47:27 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: separate WIN32OLE_VARIABLE src from
+ win32ole.c
+ * ext/win32ole/win32ole.h: ditto.
+ * ext/win32ole/win32ole_variable.c: ditto.
+ * ext/win32ole/win32ole_variable.h: ditto.
+ * ext/win32ole/depend: ditto.
+
+Mon Aug 11 16:17:21 2014 Tony Miller <mcfiredrill@gmail.com>
+
+ * dir.c (rb_dir_exists_p): [DOC] Document that Dir.exists? is
+ deprecated. [ruby-core:64135] [Bug #10102]
+
+Mon Aug 11 11:26:33 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/tempfile.rb: start rdoc parsing inside singleton class
+ definition to include the document there.
+ [ruby-core:64157] [Bug #10105]
+
+Sun Aug 10 12:22:43 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_type.c: refactoring.
+
+Sun Aug 10 10:34:00 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/cgi/session/pstore.rb: separated sample code.
+ * lib/open3.rb: ditto.
+
+Sun Aug 10 10:03:24 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/irb/ext/multi-irb.rb: removed commented-out code.
+
+Sat Aug 9 11:02:07 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/irb.rb: removed commented-out code.
+ * lib/irb/**/*.rb: ditto.
+
+Sat Aug 9 10:35:30 2014 Laurent Arnoud <laurent@spkdev.net>
+
+ * lib/cmath.rb: fixed indent. [fix GH-696]
+ * lib/drb/ssl.rb: ditto.
+ * lib/irb/**/*.rb: ditto.
+
+Sat Aug 9 10:28:03 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/minitest/test_minitest_unit.rb: removed obsoleted condition
+ for Ruby 1.8.
+ * test/ruby/test_time_tz.rb: ditto.
+
+Sat Aug 9 10:18:00 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/cgi/test_cgi_core.rb: removed obsoleted condition for Ruby 1.8.
+ * test/cgi/test_cgi_header.rb: ditto.
+ * test/cgi/test_cgi_multipart.rb: ditto.
+ * test/cgi/test_cgi_tag_helper.rb: ditto.
+
+Sat Aug 9 00:34:37 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: separate WIN32OLE_TYPE src from win32ole.c.
+ * ext/win32ole/win32ole.h: ditto.
+ * ext/win32ole/win32ole_type.c: ditto.
+ * ext/win32ole/win32ole_type.h: ditto.
+ * ext/win32ole/depend: ditto.
+
+Fri Aug 8 01:53:37 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * lib/securerandom.rb: use OpenSSL::BN for performance improvement.
+
+ * benchmark/bm_securerandom.rb: benchmark script.
+
+Fri Aug 8 17:19:57 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/open-uri.rb: remove needless condition for old ruby version.
+ * test/open-uri/test_open-uri.rb: ditto.
+
+Fri Aug 8 16:40:59 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/irb/init.rb: removed unreachable code.
+
+Fri Aug 8 16:34:22 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/drb/drb.rb: removed unreachable code.
+
+Fri Aug 8 14:33:49 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/webrick/httpproxy.rb: remove needless condition
+ for old ruby version.
+
+Fri Aug 8 01:07:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_yylex): fix invalid char in eval, should raise
+ an syntax error too, as well as directly coded.
+ [ruby-core:64243] [Bug #10117]
+
+Thu Aug 7 23:25:29 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * lib/open3.rb: avoid unnecessary write if stdin_data is empty.
+
+Thu Aug 7 21:42:49 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole_typelib.c (foletypelib_version): return
+ version string.
+
+ * test/win32ole/test_win32ole_typelib.rb (test_version): ditto.
+
+Thu Aug 7 15:13:13 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/cgi.rb: remove needless condition for old ruby version.
+
+Thu Aug 7 06:04:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_yyerror): preserve source code encoding in
+ syntax error messages. [ruby-core:64228] [Bug #10114]
+
+Wed Aug 6 20:56:02 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: separate src of WIN32OLE_TYPELIB from
+ win32ole.c
+
+ * ext/win32ole/win32ole.h: ditto.
+ * ext/win32ole/win32ole_typelib.c: ditto.
+ * ext/win32ole/win32ole_typelib.h: ditto.
+ * ext/win32ole/depend: ditto.
+
+Wed Aug 6 20:44:07 2014 Akinori MUSHA <knu@iDaemons.org>
+
+ * enum.c (enum_one): [DOC] Move enum.one? documentation before the
+ relevant method. Submitted by @vipulnsward. [Fixes GH-687]
+ https://github.com/ruby/ruby/pull/687
+
+Wed Aug 6 20:25:47 2014 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb (Set#replace): Check if an object given is enumerable
+ before clearing self. Reported by yui-knk. [GH-675]
+ https://github.com/ruby/ruby/pull/675
+
+Wed Aug 6 20:07:26 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (olerecord_ivar_set): remove rb_str_subseq.
+
+Wed Aug 6 19:09:27 2014 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb (Set): Implement Set#clone by splitting
+ initialize_copy into initialize_dup and initialize_clone.
+ Submitted by yui-knk. [Fixes GH-661]
+ https://github.com/ruby/ruby/pull/661
+
+Wed Aug 6 18:42:58 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: separate src of WIN32OLERuntimeError
+ from win32ole.c.
+
+ * ext/win32ole/win32ole.h: ditto
+ * ext/win32ole/depend: ditto.
+ * ext/win32ole/win32ole_error.c: ditto.
+ * ext/win32ole/win32ole_error.h: ditto.
+
+Wed Aug 6 04:33:58 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/net/http.rb (Net::HTTP.proxy_uri): use initializer instead
+ of parser to handle IPv6 address. [Bug #9129]
+
+Wed Aug 6 04:16:05 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/net/http/requests.rb (Net::HTTP::Options::RESPONSE_HAS_BODY):
+ OPTIONS requests may have response bodies. [Feature #8429]
+ http://tools.ietf.org/html/rfc7231#section-4.3.7
+
+Wed Aug 6 03:18:04 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/net/http/generic_request.rb (Net::HTTP::GenericRequest#exec):
+ handle req['host'] in update_uri.
+
+ * lib/net/http/generic_request.rb
+ (Net::HTTP::GenericRequest#update_uri):
+ use req['host'] if it is explicitly set. Even if URI is given,
+ it is already used for the initial value of req['host'].
+ Therefore overwritten value should be respected. [Bug #10054]
+
+Wed Aug 6 03:17:34 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/net/http/generic_request.rb
+ (Net::HTTP::GenericRequest#update_uri):
+ handle scheme, host, and port to reflect connection to @uri.
+
+ * lib/net/http.rb (Net::HTTP#begin_transport): move trivial handling
+ to Net::HTTP::GenericRequest#update_uri.
+
+
+Wed Aug 6 02:16:43 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/net/http/generic_request.rb
+ (Net::HTTP::GenericRequest#initialize):
+ optimize object allocation.
+
+Wed Aug 6 01:16:47 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/generic.rb (URI::Generic#path_query): remove a private method.
+
+Wed Aug 6 01:15:47 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/generic.rb (URI::Generic#normalize!): use String#empty?
+
+ * lib/uri/generic.rb (URI::Generic#path_query): optimized.
+
+ * lib/uri/generic.rb (URI::Generic#to_s): optimized.
+
+Wed Aug 6 00:15:10 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/http.rb (URI::HTTP#request_uri): optimized.
+ decrease object allocation, and ensure always create at least one new
+ object for return value.
+
+Wed Aug 6 03:41:21 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/to_ruby.rb: backwards compatibility for
+ hashes emitted by Syck. Github #198
+ * test/psych/test_hash.rb: test for change.
+
+Tue Aug 5 19:27:59 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_invoke): skip VariantClear when
+ argument is VT_RECORD variant.
+
+Tue Aug 5 15:52:51 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * gems/bundled_gems: Upgrade to test-unit-3.0.0 and minitest-5.4.0.
+
+Mon Aug 4 21:50:09 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * test/win32ole/test_win32ole_record.rb: add for WIN32OLE_RECORD
+ test(need .NET Framework 3.5 to run test).
+
+Mon Aug 4 19:49:34 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_invoke): call rb_hash_foreach instead
+ of rb_block_call.
+
+ * ext/win32ole/win32ole.c: add comment for rdoc of WIN32OLE_VARIANT
+ class.
+
+Mon Aug 4 09:12:47 2014 Eric Wong <e@80x24.org>
+
+ * variable.c: cleanup to use rb_const_lookup
+ [Feature #10107]
+
+ * vm_insnhelper.c: ditto
+
+Sun Aug 3 10:55:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/encoding.h (rb_check_symbol_cstr): ditto.
+
+Sun Aug 3 10:43:08 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_call_method): unusable super class should cause
+ method missing when BasicObject is refined but not been using.
+ [ruby-core:64166] [Bug #10106]
+
+Sat Aug 2 23:47:45 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: separate WIN32OLE::VARIANT src file
+ from win32ole.c
+ * ext/win32ole/win32ole.h: ditto.
+ * ext/win32ole/win32ole_variant_m.c: ditto.
+ * ext/win32ole/win32ole_variant_m.h: ditto.
+ * ext/win32ole/depend: ditto.
+ * ext/.document: ditto.
+
+Sat Aug 2 14:34:58 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: add comments for rdoc.
+
+Sat Aug 2 10:26:57 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_obj_itself): new method Object#itself. based on the
+ patch by Rafael Franca in [ruby-core:64156].
+ [EXPERIMENTAL] this method may be renamed due to compatibilities.
+ [ruby-core:44704] [Feature #6373]
+
+Fri Aug 1 22:30:40 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (folerecord_initialize): accept
+ only 2 arguments. The 2nd argument should be WIN32OLE object or
+ WIN32OLE_RECORD object.
+
+Fri Aug 1 20:17:33 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_variant2val): call
+ folerecord_s_allocate instead of WIN32OLE_RECORD.new.
+
+Fri Aug 1 18:39:57 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/date/test_date.rb: remove commented-out code.
+ * test/date/test_date_arith.rb: ditto.
+ * test/date/test_date_attr.rb: ditto.
+ * test/date/test_date_parse.rb: ditto.
+
+Fri Aug 1 16:35:32 2014 Evan Miller <evan@squareup.com>
+
+ * numeric.c (flodivmod): all results are NaN if divisor is NaN.
+ [fix GH-692]
+
+Thu Aug 01 07:28:12 2014 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c: [DOC] Add description of
+ `BigDecimal.new` exceptions. Patched by @joker1007 and
+ @prathamesh-sonpatki [Fixes GH-690]
+ https://github.com/ruby/ruby/pull/690
+
+Thu Jul 31 22:20:12 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: add WIN32OLE_RECORD#inspect.
+
+Thu Jul 31 20:35:32 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: add
+ WIN32OLE_RECORD#ole_instance_variable_set and
+ WIN32OLE_RECORD#ole_instance_variable_get
+
+Wed Jul 30 23:28:10 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * sprintf.c (rb_str_format): like r47006, get rid of
+ function calls in RSTRING_PTR().
+
+Wed Jul 30 22:10:29 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * process.c (rlimit_resource_type, rlimit_resource_value):
+ get rid of inadvertent dynamic symbol pin-down.
+
+ * re.c (match_backref_number): ditto.
+
+ * signal.c (esignal_init, rb_f_kill, trap_signm): ditto.
+
+ * transcode.c (econv_opts): ditto.
+
+ * vm_trace.c (symbol2event_flag): ditto.
+
+Wed Jul 30 21:29:39 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_invoke): pass WIN32OLE_RECORD variant
+ by reference when invoke OLE methods at first.
+
+ * ext/win32ole/win32ole.c (olerecord_set_ivar): release
+ IRecordInfo interface before setting another IRecordInfo interface.
+
+Wed Jul 30 13:17:35 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: remove unused macros.
+
+Tue Jul 29 22:21:37 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (hash2olerec): ignore WIN32OLE_RECORD
+ instance variable if the variable is nil.
+
+Tue Jul 29 19:43:27 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (folerecord_method_missing): refactoring.
+ divide functionality of folerecord_method_missing into
+ olerecord_ivar_set and olerecord_ivar_get.
+
+Mon Jul 28 20:20:08 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win23ole.c (folerecord_method_missing): support
+ setter of member of WIN32OLE_RECORD object.
+
+Mon Jul 28 06:37:19 2014 Zachary Scott <e@zzak.io>
+
+ * vm_eval.c: [DOC] Fix rdoc formatting of patch from [Bug #9551]
+
+Mon Jul 28 06:34:43 2014 Zachary Scott <e@zzak.io>
+
+ * vm_eval.c: [DOC] [Bug #9551] Improve clarity of Kernel::catch
+ documentation, patch by Jesse Sielaff.
+
+Mon Jul 28 06:24:54 2014 Zachary Scott <e@zzak.io>
+
+ * lib/uri/common.rb: [DOC] [Bug #9563] Recommend using URI.escape
+ before parsing a uri to avoid invalid characters. Reported by
+ Evgeniy Serykh.
+
+Mon Jul 28 05:55:56 2014 Zachary Scott <e@zzak.io>
+
+ * time.c: [DOC] Clarify %Y in strftime, which can accept any digits
+ and will output at least 4 digits as the year. Reported by Yury
+ Trofimenko [Bug #10049]
+
+ * lib/time.rb: ditto
+
+Mon Jul 28 05:32:06 2014 Zachary Scott <e@zzak.io>
+
+ * lib/uri/common.rb: [DOC] [Bug #10075] Clarify how URI.join arguments
+ are handled by RFC3986, originally reported by John Feminella.
+
+Mon Jul 28 05:21:41 2014 Zachary Scott <e@zzak.io>
+
+ * file.c: [DOC] Clarify how File.file? handles symbolic links. Also
+ cleaned up the rdoc style for this method, more to follow.
+ Originally reported by Michael Renner [Bug #10067]
+
+Mon Jul 28 05:12:22 2014 Zachary Scott <e@zzak.io>
+
+ * time.c: [DOC] Remove dead link and old bug report, which hasn't been
+ reproduced in a few years. Reported by Federico Builes [Bug #10071]
+
+Mon Jul 28 04:39:58 2014 Zachary Scott <e@zzak.io>
+
+ * ext/zlib/zlib.c: [DOC] Remove default value of Zlib constants, as
+ they may change in the implementation without notice. Patched by
+ @robin850 [Fixes GH-682] https://github.com/ruby/ruby/pull/682
+
+Mon Jul 28 04:35:35 2014 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/ossl_hmac.c: Fix NO_HMAC warning [Fixes GH-665]
+ Patched by @vipulnsward https://github.com/ruby/ruby/pull/665
+
+Sun Jul 27 19:49:36 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/cgi/core.rb: remove unused variables.
+ * lib/erb.rb: ditto.
+ * lib/mkmf.rb: ditto.
+ * lib/net/http/response.rb: ditto.
+ * lib/optparse/version.rb: ditto.
+ * lib/prime.rb: ditto.
+ * lib/racc/parser.rb: ditto.
+ * lib/rexml/document.rb: ditto.
+ * lib/rexml/dtd/dtd.rb: ditto.
+ * lib/rexml/element.rb: ditto.
+ * lib/rexml/functions.rb: ditto.
+ * lib/rexml/parsers/xpathparser.rb: ditto.
+
+Sun Jul 27 05:11:21 2014 Zachary Scott <e@zzak.io>
+
+ * lib/irb.rb: [DOC] PROMPT_I cannot be nil, patch by @hgillane
+ Fixes documenting-ruby/ruby#37
+ https://github.com/documenting-ruby/ruby/pull/37
+
+Sun Jul 27 02:41:50 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/shell/command-processor.rb: remove unused variable.
+ * lib/shell/system-command.rb: ditto.
+ * lib/tmpdir.rb: ditto.
+ * lib/uri/generic.rb: ditto.
+
+Sun Jul 27 02:08:31 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/weakref.rb: split executable code into sample directory.
+ * sample/weakref.rb: ditto.
+
+Sun Jul 27 02:06:55 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/delegate.rb: split executable code into sample directory.
+ * sample/delegate.rb: ditto.
+
+Sun Jul 27 01:46:34 2014 Zachary Scott <e@zzak.io>
+
+ * proc.c (method_super_method): [DOC] Method#super_method
+
+Sun Jul 27 01:22:39 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (method_super_method): new method Method#super_method,
+ which returns a method object of the method to be called by
+ `super` in the receiver method object.
+ [ruby-core:62202] [Feature #9781]
+
+Sat Jul 26 17:22:14 2014 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * ext/objspace/objspace_dump.c (dump_append): avoid fflush.
+
+ because dump_append_string_value() iterates over each chars,
+ fflush()-ing here effectively issues system calls on every single
+ bytes exist in a ruby process.
+
+Sat Jul 26 16:55:18 2014 Eric Wong <e@80x24.org>
+
+ * iseq.h (struct iseq_compile_data_storage): reduce overhead
+ to 16 bytes (from 32) on 64-bit
+
+Sat Jul 26 16:28:06 2014 Eric Wong <e@80x24.org>
+
+ * vm_core.h (struct rb_iseq_struct): reduce to 280 bytes
+ (from 288 bytes) on 64-bit
+
+Sat Jul 26 06:44:43 2014 Eric Wong <e@80x24.org>
+
+ * parse.y (struct parse_params): shrink to 320 to 304 bytes on 64-bit
+
+Sat Jul 26 05:58:35 2014 Eric Wong <e@80x24.org>
+
+ * include/ruby/ruby.h (ZALLOC, ZALLOC_N): implement
+ (Data_Make_Struct, TypedData_Make_Struct):
+ ZALLOC replaces ALLOC+memset
+ [ruby-core:63951][Feature #10082]
+ * compile.c (iseq_seq_sequence): ZALLOC_N replaces ALLOC_N+MEMZERO
+ * cont.c (fiber_t_alloc): ZALLOC replaces ALLOC+MEMZERO
+ * io.c (rb_io_reopen): ditto
+ * iseq.c (prepare_iseq_build): ditto
+ * parse.y (new_args_tail_gen, parser_new, ripper_s_allocate): ditto
+ * re.c (match_alloc): ditto
+ * variable.c (rb_const_set): ditto
+ * ext/socket/raddrinfo.c (get_addrinfo): ditto
+ * ext/strscan/strscan.c (strscan_s_allocate): ditto
+ * gc.c (rb_objspace_alloc): calloc replaces malloc+MEMZERO
+
+Sat Jul 26 05:54:54 2014 Eric Wong <e@80x24.org>
+
+ * symbol.c (dsymbol_check): remove unneeded semi-colon
+
+Fri Jul 25 14:07:27 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: change objspace::rgengc::parent_object_is_old (boolean)
+ to objspace::rgengc::parent_object (VALUE).
+ Use Qfalse or RVALUE pointer instead of FALSE and TRUE.
+
+ * gc.c (gc_marks_body): should clear parent_object just before
+ gc_mark_roots() because there are no parents objects
+ for root objects.
+
+Fri Jul 25 13:45:39 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_gc_writebarrier_remember_promoted): should remember only
+ OLD objects on RGENGC_AGE2_PROMOTION.
+
+Fri Jul 25 13:42:02 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_mark_stacked_objects): fix error message.
+
+Fri Jul 25 13:18:00 2014 Will Farrington <wfarrington@digitalocean.com>
+
+ * ext/socket/socket.c (sock_gethostname): Use NI_MAXHOST to support
+ hostnames longer than 64 characters if the system supports it.
+ [fixes GH-683]
+
+Fri Jul 25 12:21:11 2014 Santiago Pastorino <santiago@wyeworks.com>
+
+ * compile.c (defined_expr): make the condition if the receiver
+ is explicit or implicit cleaner. [fix GH-681]
+
+Fri Jul 25 03:53:52 2014 Eric Hodel <drbrain@segment7.net>
+
+ * doc/keywords.rdoc: [DOC] Describe each keyword.
+
+Thu Jul 24 22:40:24 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (Init_win32ole): add WIN32OLE_RECORD#initialize
+ method.
+
+ * ext/win32ole/win32ole.c (ole_val2variant): convert WIN32OLE_RECORD
+ object to VT_RECORD variant.
+
+Thu Jul 24 20:10:59 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: fix major GC flags.
+ * add GPR_FLAG_MAJOR_BY_FORCE, which indicates
+ major GC by METHOD, CAPI and so on (see GC_BY).
+ * remove GPR_FLAG_MAJOR_BY_RESCAN because not used.
+ * remove GPR_FLAG_MAJOR_BY_STRESS, use FORCE instead.
+
+ * test/ruby/test_gc.rb: catch up.
+
+Thu Jul 24 15:55:02 2014 Naohisa Goto <ngotogenome@gmail.com>
+
+ * include/ruby/io.h (struct rb_io_buffer_t): PACKED_STRUCT should not
+ be used for platform-specific optimization. PACKED_STRUCT_UNALIGNED
+ should be used. [ruby-core:63988] [Bug #10088]
+
+Thu Jul 24 04:42:13 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/benchmark.rb: split executable code into sample directory.
+ * sample/benchmark.rb: ditto.
+
+Thu Jul 24 04:36:49 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/tempfile.rb: split executable code into sample directory.
+ * sample/tempfile.rb: ditto.
+
+Thu Jul 24 04:29:36 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/pstore.rb: split executable code into sample directory.
+ * sample/pstore.rb: ditto.
+
+Wed Jul 23 23:50:11 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/defines.h, siphash.c, st.c (UNALIGNED_WORD_ACCESS):
+ add PowerPC64 too, which is capable to access unaligned words.
+ patched by Gustavo Frederico Temple Pedrosa in [ruby-core:63937].
+ [Feature #10081]
+
+ * regint.h (PLATFORM_UNALIGNED_WORD_ACCESS): ditto.
+
+Wed Jul 23 04:04:38 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/drb/extserv.rb: remove duplicate code with sample directory.
+ contributed from @vipulnsward. [fix GH-679]
+
+Tue Jul 22 12:56:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_count): fix wrong single-byte optimization.
+ 7bit ascii can be a trailing byte in Shift_JIS.
+ [ruby-dev:48442] [Bug #10078]
+
+Tue Jul 22 01:48:38 2014 Eric Wong <e@80x24.org>
+
+ * include/ruby/io.h (rb_io_buffer_t): fix packing on gcc
+ r46892 caused packing to be a no-op on gcc (4.7.2-5, Debian)
+ [Bug #10079][ruby-core:63912]
+
+Mon Jul 21 15:55:42 2014 fuji70 <fujifuji70@gmail.com>
+
+ * lib/optparse.rb (getopts): print default values and descriptions
+ in the help message. [fix GH-676]
+
+Sun Jul 20 14:26:27 2014 Eric Wong <e@80x24.org>
+
+ * vm_core.h (rb_proc_t): reduce to 64 bytes from 72 on 64-bit
+
+Sun Jul 20 13:50:34 2014 Eric Wong <e@80x24.org>
+
+ * transcode.c (rb_econv_t): reduce to 184 bytes from 200 on 64-bit
+
+Sun Jul 20 12:44:23 2014 Eric Wong <e@80x24.org>
+
+ * include/ruby/io.h (rb_io_buffer_t): pack structure
+ Reduces rb_io_t from 200 to 192 bytes, allowing rb_io_t to
+ occupy one less cache line.
+ [Feature #10050]
+
+Sun Jul 20 12:41:53 2014 Eric Wong <e@80x24.org>
+
+ * include/ruby/io.h (rb_io_t): shrink to 200 bytes from 216 on 64-bit
+ This puts us within 8 bytes of being three cache lines instead of
+ four lines on x86-64. This breaks the ABI.
+ [Feature #10050]
+
+Sun Jul 20 12:36:46 2014 Eric Wong <e@80x24.org>
+
+ * include/ruby/oniguruma.h (struct re_pattern_buffer): shrink to 448
+ bytes from 464 bytes on 64-bit. This breaks the ABI.
+ [Feature #10034]
+
+Sun Jul 20 01:06:06 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * ext/openssl/ossl.c: use encryptor instead of encrypter in doc.
+ contributed from @vipulnsward. [fix GH-663]
+
+Sun Jul 20 00:32:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (rb_io_initialize): [DOC] fix rdoc of append mode. it does
+ not move the pointer at open. [ruby-core:63747] [Bug #10039]
+
+Sat Jul 19 12:40:50 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_compile_each): allow to access private attribute
+ reader in op_assign. [ruby-core:63817] [Bug #10060]
+
+Sat Jul 19 11:56:36 2014 Grey Baker <greysteil@gmail.com>
+
+ * lib/time.rb (Time#apply_offset): Guards against a `nil` return
+ value from `Time.month_days` when offsetting date. Out of range
+ values are then caught when `Time.utc` is called (as usual).
+
+ Previously a `nil` return value from `Time.month_days` would
+ have the `<` operator called on it, and raise `NoMethodError`.
+ [fix GH-667]
+
+ * lib/rdoc/parser/changelog.rb (RDoc#parse_entries): fix dirty hack.
+
+Sat Jul 19 06:19:01 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: refactoring.
+
+Fri Jul 18 22:34:41 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (folevariant_initialize): WIN32OLE_VARIANT
+ does not support VT_RECORD. VT_RECORD should be supported in
+ WIN32OLE_RECORD.
+
+ * test/win32ole/test_win32ole_variant.rb (test_s_new_vt_record_exc):
+ ditto.
+
+Fri Jul 18 19:54:03 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (folevariant_initialize): remove unnecessary
+ code.
+
+Fri Jul 18 19:11:03 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix/eigenvalue_decomposition: Style fix
+ Patch by Gogo Tanaka [#10058]
+
+Fri Jul 18 19:03:53 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Avoid using `and`.
+ Patch by gogo tanaka [#10058]
+
+Fri Jul 18 17:41:54 2014 GoGo tanaka <qlli.illb@gmail.com>
+
+ * test/matrix/test_matrix.rb: Add tests for Matrix class.
+ [Feature #10057][ruby-core:63809]
+
+Fri Jul 18 10:14:42 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/fileutils.rb: added missing options of FileUtils.touch by @Domon.
+ [fix GH-669]
+
+Thu Jul 17 19:57:27 2014 Herwin <herwin@quarantainenet.nl>
+
+ * ext/thread/thread.c (rb_szqueue_push): add optional parameter,
+ non_block defaulted to false. [ruby-core:63794] [Feature #10052]
+
+Wed Jul 16 23:01:43 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_variant2val): support array of
+ VT_RECORD variant.
+
+Wed Jul 16 20:21:49 2014 Naohisa Goto <ngotogenome@gmail.com>
+
+ * vm_core.h (struct rb_iseq_struct): stack_max is changed to int
+ because all calculations related to stack_max in compile.c
+ (iseq_set_sequence) and vm_insnhelper.c (vm_push_frame) are
+ conducted by using int. This partly reverts r23945.
+ * vm_insnhelper.c (vm_push_frame): ditto. This reverts r42401.
+
+Wed Jul 16 19:55:32 2014 Naohisa Goto <ngotogenome@gmail.com>
+
+ * vm_core.h (struct rb_iseq_struct): temporal workaround of [Bug 10037].
+ Add padding on big-endian 64-bit architecture (e.g. sparc64).
+
+Wed Jul 16 19:32:23 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (fole_record_method_missing): call
+ rb_hash_fetch instead of rb_hash_aref.
+
+Wed Jul 16 18:08:47 2014 Koichi Sasada <ko1@atdot.net>
+
+ * iseq.c (rb_iseq_defined_string): use rb_gc_mark_object() instead of
+ marking from vm_mark().
+
+ * vm.c (rb_vm_mark): ditto.
+
+Wed Jul 16 18:03:50 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_mark_roots): call rb_vm_mark directly.
+
+ * vm.c: remove mark function for RubyVM object because
+ RubyVM object marked manually.
+
+Wed Jul 16 12:25:39 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * regcomp.c: Merge Onigmo 5.14.1 25a8a69fc05ae3b56a09.
+ this includes Support for Unicode 7.0 [Bug #9092].
+
+Tue Jul 15 23:59:27 2014 Jared Jennings <jared.jennings.ctr@us.af.mil>
+
+ * ext/digest: make built-in digest function implementations
+ indicate success or failure of init and final functions.
+ [ruby-core:61614] [Bug #9659]
+
+ * ext/digest/digest.c: expect digest init and finish functions to
+ indicate success or failure; raise exception on failure.
+ [ruby-core:61614] [Bug #9659]
+
+Tue Jul 15 20:31:40 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: modify document for WIN32OLE_RECORD.
+
+Tue Jul 15 12:42:23 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * defs/default_gems: change version definition file of rake.
+
+Tue Jul 15 12:00:03 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rake.rb, lib/rake/*.rb: Upgrade to rake-10.3.2
+ [fix GH-668]
+ * test/rake/*.rb: ditto.
+
+Mon Jul 14 19:14:51 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: modify WIN32OLE class document and
+ add comment for constants of WIN32OLE.
+
+Mon Jul 14 16:38:45 2014 Eric Wong <e@80x24.org>
+
+ * vm_core.h (struct rb_iseq_struct): reduce to 288 bytes
+ on x86-64 (from 296 bytes)
+
+Mon Jul 14 16:07:25 2014 Eric Wong <e@80x24.org>
+
+ * iseq.h (struct iseq_catch_table_entry): shrink to 32 bytes
+ on x86-64 (from 48 bytes)
+
+Mon Jul 14 16:04:41 2014 Eric Wong <e@80x24.org>
+
+ * iseq.h (struct iseq_catch_table): new flexible array struct
+ (iseq_catch_table_bytes): allocated size function
+ * vm_core.h (struct rb_iseq_struct): update catch_table member
+ This reduces the struct from 304 to 296 bytes on x86-64.
+ * compile.c (iseq_set_exception_table): update for struct changes
+ * iseq.c (iseq_free): ditto
+ * iseq.c (iseq_memsize): ditto
+ * iseq.c (rb_iseq_disasm): ditto
+ * iseq.c (iseq_data_to_ary): ditto
+ * iseq.c (rb_iseq_build_for_ruby2cext): ditto (untested)
+ * vm.c (vm_exec): ditto
+ * vm_core.h (struct rb_iseq_struct): ditto
+ * vm_insnhelper.c (vm_throw): ditto
+
+Sun Jul 13 17:49:52 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * ext/openssl/ossl_cipher.c: Fix call to ciphers class method and
+ spell out `encryption` by @vipulnsward [fix GH-664]
+
+Sun Jul 13 17:31:51 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * ext/gdbm/gdbm.c: fix wrong arguments in GetDBM2 macro.
+ * ext/sdbm/init.c: ditto.
+
+Sun Jul 13 17:25:50 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * ext/dbm/dbm.c: fix wrong arguments in GetDBM2 macro by @v2e4lisp.
+ [fix GH-655]
+
+Sun Jul 13 16:44:56 2014 Eric Wong <e@80x24.org>
+
+ * vm_core.h (struct rb_call_info_struct): improve packing
+ This reduces the struct from 112 to 104 bytes on x86-64.
+
+Sun Jul 13 15:53:25 2014 Eric Wong <e@80x24.org>
+
+ * vm_core.h (struct rb_iseq_struct): stack_max is uint32_t
+ This reduces the struct from 312 to 304 bytes on x86-64.
+
+Sun Jul 13 10:56:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (rb_cv_broken_backtrace): exit with failure
+ normally, no needs to abort. [ruby-core:63678] [Bug #10008]
+
+Sat Jul 12 15:10:22 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (fole_record_method_missing): correct
+ fields Hash key.
+
+Sat Jul 12 04:17:40 2014 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * lib/net/smtp.rb (Net::SMTP#data): enable buffering while
+ 'data' send for optimizing Net::SMTP#send_message.
+ [ruby-dev:48329] [misc #9981]
+ patch by Masahiro Tomita.
+
+Sat Jul 12 01:13:45 2014 Naohisa Goto <ngotogenome@gmail.com>
+
+ * test/ruby/envutil.rb (assert_no_memory_leak): On Solaris 9 or later,
+ if possible, execute child ruby with environment variables
+ LD_PRELOAD=libumem.so UMEM_OPTIONS="backend=mmap". With these
+ variables, freed memory is immediately returned to the OS.
+ [Bug #10020] [ruby-dev:48391]
+
+Fri Jul 11 20:49:10 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c: add WIN32OLE_RECORD class to support
+ VT_RECORD OLE variables.
+
+Fri Jul 11 17:15:08 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/abbrev.rb: remove executable.
+
+Fri Jul 11 16:45:39 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/fileutils.rb: handle ENOENT error with symlink targeted to
+ non-exists file. [ruby-dev:45933] [Bug #6716]
+
+Fri Jul 11 15:59:42 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * array.c: Clarify documentation for Array#insert.
+ [ruby-core:62934] [Bug #9901]
+
+Fri Jul 11 15:39:36 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * io.c: Improve Documentation by @dapplebeforedawn.
+ [fix GH-658] [ruby-core:63579] [Bug #10012]
+
+Fri Jul 11 14:19:14 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Fix sign for cross_product [#9499]
+
+Fri Jul 11 11:11:50 2014 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/prepare_so_k_nucleotide.rb: use require_relative.
+
+ * benchmark/prepare_so_reverse_complement.rb: ditto.
+
+Fri Jul 11 10:09:03 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * pack.c (encodes): fix buffer overrun by tail_lf. Thanks to
+ Mamoru Tasaka and Tomas Hoger. [ruby-core:63604] [Bug #10019]
+
+Thu Jul 10 23:51:36 2014 Naohisa Goto <ngotogenome@gmail.com>
+
+ * hash.c (ruby_setenv): Fix TestEnv#test_aset failure on Solaris 9.
+ When name contains '=', ruby_setenv raises Errno::EINVAL.
+ That is the same behavior as Solaris 10.
+ NULL check for malloc return value is also added.
+
+Thu Jul 10 15:02:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_callee_setup_keyword_arg): adjust VM stack
+ pointer to get rid of overwriting splat arguments by arguments
+ for `to_hash` conversion. [ruby-core:63593] [Bug #10016]
+
+Thu Jul 10 01:09:57 2014 Koichi Sasada <ko1@atdot.net>
+
+ * symbol.c: remove rb_gc_mark_symbols().
+
+ fstrings referred by static symbols and pinned dynamic symbols
+ are registered by rb_gc_register_mark_object().
+
+ fstrings referred by dynamic symbols (not pinned symbols)
+ are referred from global_symbols.dsymbol_fstr_hash (Hash object).
+
+ Note that fstrings referred from dynamic symbols must live logger
+ than symbol objects themselves because rb_gc_free_dsymbol() uses
+ fstrings to remove from symbol tables.
+ This is why we can not mark fstrings from dynamic symbols.
+
+ This technique reduces root objects for GC marking.
+
+ * gc.c (gc_mark_roots): ditto.
+
+ * internal.h: ditto.
+
+Thu Jul 10 00:24:18 2014 Naohisa Goto <ngotogenome@gmail.com>
+
+ * common.mk (DTRACE_DEPENDENT_OBJS): fix build failure on Solaris
+ introduced in r46768. Object files containing dtrace probes should
+ be listed in DTRACE_DEPENDENT_OBJS.
+
+Wed Jul 9 17:07:28 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * symbol.c, symbol.h: Symbol class implementation and internals,
+ split from parse.y.
+
+Wed Jul 9 14:45:39 2014 Koichi Sasada <ko1@atdot.net>
+
+ * parse.y: change Symbol <-> ID relationship to avoid
+ exposing IDs from collectable symbols.
+ [Bug #10014]
+
+ Now, rb_check_id() returns 0 if corresponding symbol is
+ pinned dynamic symbol.
+
+ There is remaining intern_cstr_without_pindown(), it can return
+ IDs from collectable symbols. We must be careful to use it
+ (only used in parse.y). I think it should be removed if
+ it does not have impact for performance.
+
+ * parse.y:
+ add:
+ * STATIC_SYM2ID()
+ * STATIC_ID2SYM()
+ rename:
+ * rb_pin_dynamic_symbol() -> dsymbol_pindown()
+
+ * internal.h:
+ remove:
+ * rb_check_id_without_pindown()
+ * rb_sym2id_without_pindown()
+ add:
+ * rb_check_symbol()
+ * rb_check_symbol_cstr()
+
+ * load.c: use rb_check_id() or rb_check_id_cstr().
+
+ * object.c: ditto.
+
+ * struct.c: ditto.
+
+ * thread.c: ditto.
+
+ * vm_method.c: ditto.
+
+ * string.c (sym_find): use only rb_check_symbol().
+
+ * sprintf.c (rb_str_format): use rb_check_symbol_cstr().
+
+Wed Jul 9 12:21:55 2014 Koichi Sasada <ko1@atdot.net>
+
+ * parse.y (symbols_i): delete garbage symbols for Symbol.all_symbols.
+
+Wed Jul 9 05:49:08 2014 Eric Wong <e@80x24.org>
+
+ * thread_pthread.h (struct rb_global_vm_lock_struct):
+ do not expose pthread type for lock
+
+Wed Jul 9 05:41:40 2014 Eric Wong <e@80x24.org>
+
+ * thread_pthread.h: remove unneeded semaphore.h include
+
+Wed Jul 9 00:12:28 2014 Keiju Ishitsuka <keiju@ishitsuka.com>
+
+ * lib/irb/ruby-lex.rb: fix counting indent in identify_string_dvar.
+
+Tue Jul 8 16:58:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/ruby/memory_status.rb (Memory::PSCMD): use ps command which
+ outputs expected result. [ruby-dev:48370] [Bug #10010]
+
+Tue Jul 8 14:45:17 2014 Koichi Sasada <ko1@atdot.net>
+
+ * parse.y (dsymbol_alloc): set global_symbols.minor_marked to 0.
+
+ * parse.y (dsymbol_check): set RSYMBOL(sym)->fstr to 0
+ because we should not touch fstr after that.
+
+ * parse.y (rb_gc_free_dsymbol): skip deleting str and sym
+ from tables if fstr == 0.
+
+Mon Jul 7 14:31:52 2014 Koichi Sasada <ko1@atdot.net>
+
+ * parse.y: remove global_symbols::pinned_dsym
+ (and ::pinned_dsym_minor_marked).
+
+ Mark pinned dsymbols by rb_gc_register_mark_object() because
+ they are immortal.
+
+ * parse.y (rb_gc_free_dsymbol): rename parameter name `ptr' to `sym'.
+
+Mon Jul 7 12:45:51 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: revert miss-commit.
+
+Mon Jul 7 12:40:59 2014 Koichi Sasada <ko1@atdot.net>
+
+ * parse.y: need to use updated (re-created) symbols.
+
+Mon Jul 7 11:02:55 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/mkconfig.rb: remove not to require rbconfig/obsolete.rb.
+
+ * lib/rbconfig/obsolete.rb: removed.
+
+Mon Jul 7 10:52:03 2014 Koichi Sasada <ko1@atdot.net>
+
+ * parse.y: do not use rb_gc_resurrect(), but create a new dynamic
+ symbol for garbage dynamic symbol.
+
+ * common.mk: use gc.h by parse.y.
+
+Mon Jul 7 02:18:42 2014 Koichi Sasada <ko1@atdot.net>
+
+ * string.c (fstr_update_callback): do not use rb_gc_resurrect()
+ any more.
+
+ Make new frozen string and replace with garbage frozen string.
+
+ * common.mk: use gc.h from string.c.
+
+Mon Jul 7 00:36:13 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename is_dying_object() to is_garbage_object().
+
+ * gc.h: rb_objspace_garbage_object_p() as an exported function.
+
+Sun Jul 6 21:30:35 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (is_dying_object): fix missed condition.
+
+ * gc.c (is_live_object): move frequent path first.
+
+Sun Jul 6 21:00:11 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename is_dead_object() to is_dying_object().
+ This function is not opposite against is_live_object()
+ because is_dying_object() does *not* check object type.
+
+ * gc.c (is_dying_object): change condition.
+
+ * gc.c (is_live_object): use T_NONE instead of 0.
+
+ * gc.c (rb_objspace_dying_object_p): added.
+
+Sun Jul 6 13:37:27 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_gc_register_mark_object): change data structure.
+ From single array, to array of arrays. Each array only has 1024
+ entries.
+
+ * vm.c (Init_vm_objects): change default capa from 1 to 128.
+
+Sat Jul 5 05:05:53 2014 Vipul A M <vipulnsward@gmail.com>
+
+ * lib/irb/locale.rb (IRB::Locale#modifier): fix wrong attr_reader
+ `modifieer` => `modifier` from irb locale. [fix GH-656]
+
+Fri Jul 4 20:45:26 2014 Koichi Sasada <ko1@atdot.net>
+
+ * parse.y: rename symbols::sym_id to symbols::str_id.
+ This table is not {Symbol => ID} table, but
+ {String => ID} table.
+
+ * parse.y (lookup_sym_id): also rename lookup_sym_id() to
+ lookup_str_id() because key is not Symbol, but String.
+
+Fri Jul 4 18:42:04 2014 Koichi Sasada <ko1@atdot.net>
+
+ * parse.y (must_be_dynamic_symbol): fix missed-condition.
+
+Fri Jul 4 18:38:11 2014 Koichi Sasada <ko1@atdot.net>
+
+ * parse.y (rb_pin_dynamic_symbol): should be `static' function.
+
+Fri Jul 4 18:03:35 2014 Koichi Sasada <ko1@atdot.net>
+
+ * parse.y (must_be_dynamic_symbol): refactoring.
+ * add `inline'.
+ * use UNLIKELY().
+ * check only DYNAMIC_SYM_P(), otherwise it is a bug.
+ * lookup_id_str() is not needed in second condition.
+
+Fri Jul 4 11:53:56 2014 Koichi Sasada <ko1@atdot.net>
+
+ * parse.y: remove unused code
+ surrounded by `#if ENABLE_SELECTOR_NAMESPACE'
+
+Fri Jul 4 10:08:24 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/rubygems/test_gem_package.rb: avoid tempfile leaks using Tempfile#close!
+ * test/rubygems/test_gem_request_set.rb: ditto.
+ * test/rubygems/test_gem_request_set_gem_dependency_api.rb: ditto.
+
+Fri Jul 4 04:42:05 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/net/http/response.rb (Net::Inflater#inflate_adapter):
+ prevent automatic encoding conversion.
+
+Fri Jul 4 04:39:52 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/net/http/response.rb (Net::HTTPResponse.each_response_header):
+ raise first exception even if inflate_body_io.finish raises error.
+ when begin block raises error, finish usually raises error too.
+
+Fri Jul 4 02:56:04 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/generic.rb (URI::Generic#query=): remove validation, just
+ escape. [Feature #2542]
+
+ * lib/uri/generic.rb (URI::Generic#fragment=): ditto.
+
+ * lib/uri/generic.rb (URI::Generic#check_query): removed.
+
+ * lib/uri/generic.rb (URI::Generic#set_query): ditto.
+
+ * lib/uri/generic.rb (URI::Generic#check_fragment): ditto.
+
+ * lib/uri/generic.rb (URI::Generic#set_fragment): ditto.
+
+Thu Jul 3 12:40:22 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (--with-static-linked-ext): fix for extensions to
+ be linked statically.
+
+ * Makefile.in, common.mk: use ENCSTATIC for enc directory.
+
+ * ext/extmk.rb: supply dependencies of statically linked extension
+ libraries.
+
+Wed Jul 2 15:45:49 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_heap_lazy_sweep): simplify logic.
+
+ * gc.c (gc_page_sweep): return TRUE if empty slots are available.
+
+Wed Jul 2 09:48:42 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * logger.rb: removed unmaintained code.
+ [Feature #9860][ruby-core:62724]
+ * test/logger/test_application.rb: ditto.
+
+Wed Jul 2 03:20:00 2014 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * node.c (dump_node): handle nd_value == (NODE *)-1 to mean this
+ keyword argument is required
+
+Wed Jul 2 02:57:27 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm.c (rb_vm_env_local_variables): returns array of local
+ variable name symbols in the environment by envval.
+
+ * proc.c (bind_local_variables): use rb_vm_env_local_variables.
+
+Wed Jul 2 02:23:52 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (bind_receiver): new method to return the bound receiver
+ of the binding object. [ruby-dev:47613] [Feature #8779]
+
+Wed Jul 2 02:14:37 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (bind_local_variables): update env from envval for each
+ iterations. [ruby-dev:48351] [Bug #10001]
+
+Tue Jul 1 23:46:34 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * NEWS: [DOC] mention about Binding#local_variables, introduced at
+ r44392 (see [Feature #8773]).
+
+Tue Jul 1 23:30:51 2014 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * numeric.c (num_step_scan_args): table argument of rb_get_kwargs() is
+ array of IDs, not Symbols. [ruby-dev:48353] [Bug #9811]
+
+Tue Jul 1 16:18:22 2014 Akinori MUSHA <knu@iDaemons.org>
+
+ * ext/digest/lib/digest/hmac.rb, test/digest/test_digest_hmac.rb:
+ Digest::HMAC is finally removed as previously noticed.
+ [fix GH-648]
+
+Tue Jul 1 11:13:43 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * ext/date/lib/date/format.rb: removed empty file by @vipulnsward.
+ * ext/date/lib/date.rb: removed needless require.
+ [fix GH-647]
+
+Mon Jun 30 16:42:52 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_stat_internal): return size_t value instead of VALUE
+ and remove `out' parameter.
+
+ * gc.c: add braces for `if' statements.
+
+ * gc.c (gc_stat_internal): fix comment.
+
+Mon Jun 30 15:07:34 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: support `USE_RGENGC == 0'.
+
+ * test/ruby/test_gc.rb: ditto.
+
+Mon Jun 30 11:36:04 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * file.c: [DOC] document File.join returns a string.
+ Contributed by @dapplebeforedawn. [fix GH-646]
+
+Sat Jun 28 22:57:01 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/pathname/pathname.c (path_birthtime): Windows support.
+ see [Feature #9857] [ruby-dev:48339]
+
+Sat Jun 28 22:44:16 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/pathname/pathname.c (path_birthtime): New method,
+ Pathname#birthtime.
+ Proposed by Kazuhiro NISHIYAMA. [ruby-dev:48232] [Feature #9857]
+
+Sat Jun 28 20:29:03 2014 Simon Baird <simon.baird@gmail.com>
+
+ * ext/bigdecimal/lib/bigdecimal/math.rb (BigMath#PI): change error
+ message about zero or negative precision for clarity and
+ consistency with other methods. [GH-644]
+
+Sat Jun 28 15:32:57 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/webrick/utils.rb (create_listeners): Close socket objects.
+
+Sat Jun 28 13:58:48 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (setup_exception): should not overwrite SystemStackError
+ backtrace if set already. [ruby-core:63377] [Feature #6216]
+
+ * eval.c (setup_exception): get rid of method calls before raising
+ stack overflow, not to cause stack overflow again.
+
+ * defs/id.def: add IDs for backtraces.
+
+Sat Jun 28 04:08:22 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/mailto.rb: update to latest specs, RFC 6068 and HTML5.
+
+ * lib/uri/mailto.rb (HEADER_PATTERN): removed.
+
+ * lib/uri/mailto.rb (HEADER_REGEXP): use RFC 6068 hfields.
+
+ * lib/uri/mailto.rb (EMAIL_REGEXP): use HTML5 email regexp.
+
+ * lib/uri/mailto.rb (URI::MailTo.build): support multiple to addresses.
+
+ * lib/uri/mailto.rb (URI::MailTo#initialize): Support multiple to
+ addresses. Don't check with regexp, only split.
+
+ * lib/uri/mailto.rb (URI::MailTo#check_to): verify by matching
+ URI path-rootless and HTML5 email regexp with unescaped one.
+
+ * lib/uri/mailto.rb (URI::MailTo#check_headers): verify only by
+ HEADER_REGEXP.
+
+ * lib/uri/mailto.rb (URI::MailTo#set_headers): don't check by
+ HEADER_REGEXP, only split it.
+
+Sat Jun 28 00:35:10 2014 Lauri Tirkkonen <lotheac@iki.fi>
+
+ * tool/mkconfig.rb: fix empty RbConfig::CONFIG["prefix"] when
+ configured --with-rubyarchprefix, remove prefix from rubyarchdir
+ after expansion for the case it does not start with '$(prefix)'.
+ [fix GH-643]
+
+Fri Jun 27 15:20:12 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rubygems/test_case.rb: rescue Gem::LoadError in Gem::TestCase.
+ because it's effected by removing minitest from stdlib.
+
+Fri Jun 27 12:29:37 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/rubygems/specification.rb: fixed broken condition caused
+ by removing YAML::ENGINE.
+ * lib/rubygems/package/old.rb: ditto.
+
+Fri Jun 27 05:33:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (env_shift): fix memory leak on Windows, free environment
+ strings block always. [ruby-dev:48332] [Bug #9983]
+
+Fri Jun 27 03:41:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * sprintf.c (GETASTER): should not use the numbered argument to be
+ formatted, raise ArgumentError instead.
+ [ruby-dev:48330] [Bug #9982]
+
+Thu Jun 26 18:18:28 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/with_different_ofs.rb: move into test library directory.
+ * test/csv/base.rb: fix require path for with_different_ofs.rb.
+ * test/digest/test_digest_extend.rb: ditto.
+
+Thu Jun 26 18:06:50 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/profile_test_all.rb: move into test library directory.
+ * test/runner.rb: fix require path for profile_test_all.rb.
+
+Thu Jun 26 17:57:57 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/webrick/httpproxy.rb: remove useless assigned variables.
+ * lib/webrick/httpservlet/cgihandler.rb: ditto.
+ * lib/webrick/httpservlet/erbhandler.rb: ditto.
+ * lib/webrick/server.rb: ditto.
+
+Thu Jun 26 08:28:01 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (env_select): fix memory leak and crash on Windows, make
+ keys array first instead of iterating on environ directly.
+ [ruby-dev:48325] [Bug #9978]
+
+Thu Jun 26 02:45:04 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval_error.c (error_print): put a newline after an anonymous
+ exception class name.
+
+Wed Jun 25 22:31:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (ruby_setenv): fix memory leak on Windows, free
+ environment strings block after check for the size.
+ [ruby-dev:48323] [Bug #9977]
+
+Wed Jun 25 15:44:12 2014 Eric Wong <e@80x24.org>
+
+ * ccan/container_of/container_of.h (container_off_var):
+ avoid warning with -Wcast-qual
+ [ccan ba5ad771af4aa9e085498de6c3c665c52694460f (Rusty Russell)]
+
+Wed Jun 25 10:19:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (env_aset, env_has_key, env_assoc, env_has_value),
+ (env_rassoc, env_key): prohibit tainted strings if $SAFE is
+ non-zero. [Bug #9976]
+
+Tue Jun 24 14:46:17 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/gserver.rb: remove redundant use of to_s in interpolation.
+ * lib/logger.rb: ditto.
+ * lib/optparse.rb: ditto.
+ * lib/rbconfig/obsolete.rb: ditto.
+ * lib/resolv.rb: ditto.
+ * lib/webrick/httpresponse.rb: ditto.
+
+Tue Jun 24 10:50:06 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (env_path_str_new): make PATH environment variable
+ string, to be frozen.
+
+Tue Jun 24 10:40:52 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * tool/make-snapshot: download bundle gems when package making.
+ [Feature #9852][ruby-core:62676]
+ * gems/bundled_gems: listed bundled gems for Ruby 2.2.
+
+Tue Jun 24 10:20:35 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * tool/downloader.rb: make Downloader class to general download utility.
+ It can be used without config.guess and config.sub.
+ * tool/get-config_files: ditto.
+ * tool/make-snapshot: ditto.
+
+Tue Jun 24 06:17:52 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * eval.c (setup_exception): "mesg == sysstack_error" and
+ sysstack_error_p(mesg) are duplicated.
+ r46502 seems to want to use latter.
+
+Tue Jun 24 06:15:36 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/tk/tcltklib.c: fix format specifiers for VALUE and
+ Tcl_Interp*. [ruby-core:63283] [Bug #9972]
+
+Tue Jun 24 05:40:41 2014 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
+
+ * nacl/nacl-config.rb: Use File.exist? instead of executable?
+ for irt_core. Recent nacl_sdk has non-executable irt_core.
+ Patch by Shinichiro Hamaji.
+ [Fixes GH-529] https://github.com/ruby/ruby/pull/529
+
+Mon Jun 23 18:44:45 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * tool/config_files.rb: rename class ConfigFiles to Downloader.
+ * tool/get-config_files: ditto.
+ * tool/make-snapshot: ditto.
+
+Mon Jun 23 18:03:13 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * tool/rbinstall.rb: support to install bundle gems.
+
+Mon Jun 23 17:33:11 2014 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/net/imap.rb (Net::IMAP#fetch): [DOC] Describe how a range in
+ +set+ is interpreted, and mention -1 which can be used for '*'.
+
+Mon Jun 23 16:22:50 2014 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * include/ruby/ruby.h (struct RHash): no longer. [Feature #9889]
+
+ * include/ruby/ruby.h (RHASH): ditto.
+
+ * include/ruby/ruby.h (RHASH_ITER_LEV): deprecated. Will be deleted later.
+
+ * include/ruby/ruby.h (RHASH_IFNONE): ditto.
+
+ * internal.h (struct RHash): moved here.
+
+ * internal.h (RHASH): ditto.
+
+ * hash.c (rb_hash_iter_lev): do not use this.
+
+ * hash.c (rb_hash_ifnone): ditto.
+
+Mon Jun 23 13:30:11 2014 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * include/ruby/ruby.h (struct RComplex): no longer. [Feature #9888]
+
+ * include/ruby/ruby.h (RCOMPLEX): ditto.
+
+ * include/ruby/ruby.h (RCOMPLEX_SET_REAL): deprecated. Will be deleted later.
+
+ * include/ruby/ruby.h (RCOMPLEX_SET_IMAG): ditto.
+
+ * internal.h (struct RFloat): moved here.
+
+ * internal.h (RCOMPLEX): ditto.
+
+ * complex.c (rb_complex_set_real): do not use this.
+
+ * complex.c (rb_complex_set_imag): ditto.
+
+Mon Jun 23 13:10:15 2014 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * include/ruby/ruby.h (struct RFloat): no longer. [Feature #9863]
+
+ * include/ruby/ruby.h (RFLOAT): ditto.
+
+ * internal.h (struct RFloat): moved here.
+
+ * internal.h (RFLOAT): ditto.
+
+Mon Jun 23 12:01:42 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/generic.rb (check_port): allow strings for port= as
+ described in rdoc.
+
+ * lib/uri/rfc3986_parser.rb (regexp): implementation detail of above.
+
+Mon Jun 23 11:35:01 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (setup_exception): set backtrace in system stack error
+ other than the pre-allocated sysstack_error. [Feature #6216]
+
+ * proc.c (Init_Proc): freeze the pre-allocated sysstack_error.
+
+ * vm_insnhelper.c (vm_stackoverflow): raise new instance for each
+ times without calling any methods to keep the backtrace with no
+ further stack overflow.
+
+ * object.c (rb_obj_copy_ivar): extract function to copy instance
+ variables only for T_OBJECT from init_copy.
+
+Mon Jun 23 11:11:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (check_stack_overflow): drop the last tag too close to
+ the fault page, to get rid of stack overflow deadlock.
+ [Bug #9971]
+
+Sun Jun 22 09:11:15 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/generic.rb: remove registry.
+ 'registry' is not used and RFC3986 doesn't use it.
+
+Sun Jun 22 09:10:09 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/rfc3986_parser.rb: raise exception when given a URI string
+ has non ASCII in order to keep the regexp compiled for US-ASCII.
+
+Sun Jun 22 09:05:42 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/common.rb (URI::REGEXP): move to lib/uri/rfc2396_parser.rb.
+
+ * lib/uri/common.rb (URI::Parser): ditto.
+
+ * lib/uri/common.rb (URI.split): use RFC3986_Parser. [Feature #2542]
+
+ * lib/uri/common.rb (URI.parse): ditto.
+
+ * lib/uri/common.rb (URI.join): ditto.
+
+ * lib/uri/common.rb (URI.extract): deprecated.
+
+ * lib/uri/common.rb (URI.regexp): ditto.
+
+ * lib/uri/rfc2396_parser.rb: added.
+
+ * lib/uri/rfc3986_parser.rb: added.
+
+Sun Jun 22 09:04:50 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/mailto.rb (initialize): as previous commit, fix arg_check
+
+Sun Jun 22 09:01:47 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/ftp.rb (initialize): argument checking flag is arg_check,
+ but arg[-1] is fragment.
+
+ * lib/uri/ftp.rb (initialize): explicitly specify arguments.
+
+Sat Jun 21 12:50:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/fiddle/extconf.rb: supply 0 to fill RUBY_LIBFFI_MODVERSION
+ with 3-digit. libffi 3.1 returns just 2-digit.
+ [ruby-core:62920] [Bug #9897]
+
+Sat Jun 21 07:06:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * encoding.c (enc_find): [DOC] never accepted a symbol.
+ [ruby-dev:48308] [Bug #9966]
+
+Fri Jun 20 17:15:43 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/lib/tracepointchecker.rb: add to check TracePoint healthiness.
+
+ * test/runner.rb: use it.
+
+Fri Jun 20 07:26:44 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_settracefunc.rb: rewrite tests with
+ assert_consistent_call_return().
+
+ assert_consistent_call_return() is also modified to check
+ consistency.
+
+Fri Jun 20 07:07:28 2014 Koichi Sasada <ko1@atdot.net>
+
+ * compile.c (rb_iseq_compile_node): put start label of block after
+ trace (b_call).
+ [Bug #9964]
+
+ * test/ruby/test_settracefunc.rb: add a test.
+
+ added assert_consistent_call_return() method check call/return
+ consistency.
+
+Fri Jun 20 05:26:27 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm_eval.c (rb_catch_protect): fix same problem of [Bug #9961].
+
+ * vm_eval.c (rb_iterate): ditto.
+
+Thu Jun 19 21:41:30 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (rb_vm_rewind_cfp): add new function to rewind specified cfp
+ with invoking RUBY_EVENT_C_RETURN.
+ [Bug #9961]
+
+ * vm_core.h: ditto.
+
+ * eval.c (rb_protect): use it.
+
+ * eval.c (rb_rescue2): ditto.
+
+ * vm_eval.c (rb_iterate): ditto.
+
+ * test/ruby/test_settracefunc.rb: add a test.
+
+ * vm_core.h (rb_vm_rewind_cfp): add the prototype declaration.
+
+Thu Jun 19 19:47:21 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (invoke_block_from_c): move call/return event timing for
+ bmethod. It can invoke inconsistent call event if this call raises
+ argument error.
+ [Bug #9959]
+
+ * vm_insnhelper.c (vm_call_bmethod_body): ditto.
+
+ * test/ruby/test_settracefunc.rb: add a test.
+
+Thu Jun 19 18:14:47 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm_core.h: add VM_FRAME_MAGIC_RESCUE to recognize normal block or
+ rescue clause.
+
+ * vm.c (vm_exec): use VM_FRAME_MAGIC_RESCUE on at rescue/ensure.
+
+ * test/ruby/test_settracefunc.rb: should not invoke b_return at rescue
+ clause.
+ [Bug #9957]
+
+ * vm_dump.c (control_frame_dump): check VM_FRAME_MAGIC_RESCUE.
+
+ * vm_dump.c (vm_stack_dump_each): ditto.
+
+Thu Jun 19 13:39:11 2014 Arne Brasseur <arne@arnebrasseur.net>
+
+ * proc.c (rb_method_curry): Implement Method#curry, which delegates
+ to to_proc.curry. [ruby-core:62212] [Feature #9783]
+
+Tue Jun 17 16:41:49 2014 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/ftp.rb (gets, readline): read lines without LF properly.
+ [ruby-core:63205] [Bug #9949]
+
+ * test/net/ftp/test_buffered_socket.rb: related test.
+
+Tue Jun 17 12:35:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (extract_raise_opts): pass unknown options to the
+ exception, so that exception class can receive a hash argument.
+ [ruby-core:63203] [Feature #8257]
+
+Tue Jun 17 12:24:57 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (obj_memsize_of): memsize_of(T_ZOMBIE) returns 0, not a rb_bug.
+ ObjectSpace.count_objects_size() uses memsize_of(T_ZOMBIE).
+
+ This bug introduced at r46348.
+
+Mon Jun 16 19:00:11 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/runner.rb: failure message should be passed as an argument.
+
+Mon Jun 16 18:42:57 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/runner.rb: capture TracePoint stat before setup and compare
+ it after teardown.
+
+Mon Jun 16 14:33:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (open): use UTF-8 version function to support
+ non-ascii path properly. [ruby-core:63185] [Bug #9946]
+
+Sat Jun 14 10:54:08 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rcombinate0): remove recursion, by looping with indexes
+ stored in `p`.
+
+ * array.c (rpermute0): remove recursion, by looping with indexes
+ stored in `p`.
+
+ * array.c (permute0): remove recursion, by looping with indexes
+ stored in `p`. [ruby-core:63103] [Bug #9932]
+
+Sat Jun 14 10:52:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_resize): update capa only when buffer get
+ reallocated.
+ http://d.hatena.ne.jp/nagachika/20140613/ruby_trunk_changes_46413_46420#r46413
+
+Sat Jun 14 08:28:59 2014 Zachary Scott <e@zzak.io>
+
+ * man/rake.1: [DOC] Update links for Rake, patch by @hsbt [Bug #9904]
+ [Fixes GH-628] https://github.com/ruby/ruby/pull/628
+
+Fri Jun 13 17:58:58 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm_trace.c: add new method TracePoint.stat to debug
+ TracePoint mechanism.
+
+ Ruby users should not use this method. So I don't note this method
+ in the NEWS file.
+
+ * test/runner.rb: detect zombie active TracePoints with
+ TracePoint.stat.
+
+Fri Jun 13 17:46:31 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm_trace.c: clear and restore recursive checking thread local data
+ to avoid unexpected throw from TracePoint.
+ [Bug #9940]
+
+ * test/ruby/test_settracefunc.rb: add a test.
+
+ * thread.c: added
+ * rb_threadptr_reset_recursive_data(rb_thread_t *th);
+ * rb_threadptr_restore_recursive_data(rb_thread_t *th, VALUE old);
+
+ * vm_core.h: ditto.
+
+Fri Jun 13 17:33:14 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_combination): iterate on a shared copy, and use
+ array of indexes instead of array of chosen objects.
+ [ruby-core:63149] [Bug #9939]
+
+ * array.c (yield_indexed_values): extract from permute0(),
+ rpermute0(), and rcombinate0().
+
+Fri Jun 13 13:42:58 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_permutation): `p` is the array of size `r`, as
+ commented at permute0(). since `n >= r` here, buffer overflow
+ never happened, just reduce unnecessary allocation though.
+
+Thu Jun 12 20:32:28 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_resize): should consider the capacity instead
+ of the old length, as pointed out by nagachika.
+
+Thu Jun 12 18:31:01 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/net/http/responses.rb: added Net::HTTPPermanentRedirect(308)
+ Contributed by @yorkie [fix GH-638]
+
+Thu Jun 12 13:27:38 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_freeze): shrink the buffer before freezing, as
+ pointed out by Eric Wong at [ruby-core:63119].
+
+Thu Jun 12 13:09:03 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (expand_path): shrink expanded path which no longer needs
+ rooms to append. [ruby-core:63114] [Bug #9934]
+
+Wed Jun 11 17:37:48 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (rb_cv_scalar_pthread_t): pthread_t is not required
+ to be a scalar type.
+
+ * thread.c (fill_thread_id_string, thread_id_str): dump pthread_t
+ in hexadecimal form if it is not a scalar type, assume it can be
+ represented in a pointer form otherwise. based on the patch by
+ Rei Odaira at [ruby-core:62867]. [ruby-core:62857] [Bug #9884]
+
+ * thread_pthread.c (Init_native_thread, thread_start_func_1),
+ (native_thread_create): set thread_id_str if needed.
+
+ * vm_core.h (rb_thread_t): add thread_id_string if needed.
+
+Wed Jun 11 01:53:22 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: invoke GC before memory allocation (xmalloc/xrealloc)
+ when GC.stress = true.
+ [Bug #9859]
+
+ * test/ruby/test_gc.rb: add a test.
+
+Tue Jun 10 13:20:14 2014 Takeyuki FUJIOKA <xibbar@ruby-lang.org>
+
+ * lib/cgi/core.rb: Provide a mechanism to specify the
+ max_multipart_length of multipart data.
+ [Feature #8370] patch by Leif Eriksen <leif.eriksen.au@gmail.com>
+
+Tue Jun 10 10:57:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/csv.rb (CSV#<<): honor explicitly given encoding. based on
+ the patch by DAISUKE TANIWAKI <daisuketaniwaki AT gmail.com> at
+ [ruby-core:62113]. [Bug #9766]
+
+Mon Jun 9 20:40:48 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: change full GC timing to keep lower memory usage.
+
+ Extend heap only at
+ (1) after major GC
+ or
+ (2) after several (two times, at current) minor GC
+
+ Details in https://bugs.ruby-lang.org/issues/9607#note-9
+ [Bug #9607]
+
+Mon Jun 9 16:01:41 2014 Masahiro Ide <imasahiro9@gmail.com>
+
+ * gc.c (gcdebug_sentinel): fix typo, "sentinel" not "sential".
+ [fix GH-634]
+
+Mon Jun 9 00:04:25 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (posix_fadvise): disable use of posix_fadvise
+ itself on 32-bit AIX. [ruby-core:62968] [Bug #9914]
+
+Sun Jun 8 23:28:00 2014 <kanemoto@ruby-lang.org>
+
+ * io.c (rb_io_advise): AIX currently does not support a 32-bit call to
+ posix_fadvise() if _LARGE_FILES is defined. Patch by Rei Odaira.
+ [ruby-core:62968] [Bug #9914]
+
+Sun Jun 8 04:52:40 2014 Jun Hiroe <Jun.Hiroe@gmail.com>
+
+ * string.c (rb_str_slice_bang): [DOC] update return value against
+ a fixnum, which has changed because of M17N. [fix GH-631]
+
+Sat Jun 7 22:13:42 2014 Benoit Daloze <eregontp@gmail.com>
+
+ * numeric.c (do_coerce): Add a warning when an exception is raised
+ or an invalid value is returned in #coerce called by
+ numeric comparison operators and the exception
+ thrown by the caller has no information on the failure.
+ In the next release such exception should not be rescued or
+ should be the cause of the caller exception. nil is accepted
+ as the "no possible coercion" return value. See #7688.
+
+ * test/ruby/test_numeric.rb: Add corresponding test.
+
+Sat Jun 7 18:15:33 2014 Benoit Daloze <eregontp@gmail.com>
+
+ * numeric.c (bit_coerce): remove constant parameter `err'
+ (always TRUE) of bit_coerce().
+
+Sat Jun 7 16:01:57 2014 Yutaka Kanemoto <kanemoto@ruby-lang.org>
+
+ * cont.c (rb_fiber_struct): keep context.uc_stack.ss_sp and context.uc_stack.ss_size
+ for later use. Patch by Rei Odaira. [ruby-core:62945] [Bug #9905]
+
+Sat Jun 7 12:51:51 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (read_all): truncate the buffer before appending read data,
+ instead of truncating before reading.
+ [ruby-core:55951] [Bug #8625]
+
+Sat Jun 7 12:28:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/digest/digest.c (rb_digest_instance_equal): no need to call
+ `to_s` twice. [Bug #9913]
+
+Sat Jun 7 11:35:01 2014 Tanaka Akira <akr@fsij.org>
+
+ * object.c (rb_mod_initialize_clone): Override Kernel#initialize_clone
+ to avoid an exception on Class.new.freeze.clone.to_s.
+ Reported by Andrew Grimm. [ruby-core:41858] [Bug #5828]
+
+Sat Jun 7 06:03:11 2014 Benoit Daloze <eregontp@gmail.com>
+
+ * ext/digest/digest.c (rb_digest_instance_equal):
+ fix #== for non-string arguments. [ruby-core:62967] [Bug #9913]
+
+ * test/digest/test_digest.rb: add test for above.
+
+Fri Jun 6 22:19:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (private_recv_p): check by node type, instead of a
+ magic number.
+
+ * node.h (NODE_PRIVATE_RECV), parse.y (attrset_gen): remove
+
+Fri Jun 6 17:07:08 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_compile_each), parse.y (new_attr_op_assign_gen):
+ allow op assign to a private attribute.
+ [ruby-core:62949] [Bug #9907]
+
+Fri Jun 6 13:39:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (io_setstrbuf, io_read): should not shorten the given buffer until
+ read succeeds. [ruby-core:55951] [Bug #8625]
+
+Fri Jun 6 07:41:41 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: dump empty symbols with a
+ tag so that they can be parsed on input. [Bug #9873] [ruby-core:62825]
+ * test/psych/test_symbol.rb: test for change
+
+Thu Jun 5 16:08:39 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_page_sweep): refactoring.
+
+ * gc.c (gc_page_sweep): should not set, but add final_slots into
+ sweep_page->final_slots.
+
+Thu Jun 5 14:36:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (jemalloc): check for the header regardless drop-in
+ libjemalloc is found, for `malloc_conf` declaration.
+
+ * version.c (ruby_show_version): show `malloc_conf` if set.
+ [Feature #9113]
+
+ * configure.in (with-jemalloc): also check for header, for ABIs
+ which JEMALLOC_MANGLE is needed, i.e., Mach-O and PE-COFF
+ platforms. [ruby-core:62939] [Feature #9113]
+
+ * include/ruby/missing.h: include alternative malloc header to
+ replace memory management functions.
+
+ * dln.c, io.c, parse.y, st.c: undef malloc family before
+ re-definition to suppress warnings.
+
+Thu Jun 5 12:52:18 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * man/ruby.1: remove rubyforge entry.
+
+Thu Jun 5 12:45:32 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * misc/README: use github link instead of rubyforge.
+
+Thu Jun 5 10:03:29 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (obj_free): check also FL_PROMOTED bit by RVALUE_OLD_P().
+
+Thu Jun 5 03:45:28 2014 Eric Wong <e@80x24.org>
+
+ * configure.in: add --with-jemalloc option
+ [ruby-core:62912]
+
+Wed Jun 4 22:28:14 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: introduce RZombie to manage zombie objects.
+ Rewrite finalizing logics with this type.
+
+ * gc.c (gc_verify_internal_consistency): verify zombie (finalizing)
+ objects count.
+
+Wed Jun 4 22:09:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * re.c (match_aref, rb_reg_regsub): consider encoding of captured
+ names, encoding-incompatible should not match.
+ [ruby-dev:48278] [Bug #9903]
+
+Wed Jun 4 21:23:52 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * re.c (match_aref): should not ignore name after NUL byte.
+ [ruby-dev:48275] [Bug #9902]
+
+Wed Jun 4 04:08:37 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm.c (core_hash_merge_kwd): should return the result hash, which
+ may be converted from and differ from the given argument.
+ [ruby-core:62921] [Bug #9898]
+
+Tue Jun 3 23:32:34 2014 Tanaka Akira <akr@fsij.org>
+
+ * ruby.c (load_file_internal2): Extracted from load_file_internal.
+ (load_file_internal): Invoke load_file_internal2 using rb_protect.
+ Close an opened FD if load_file_internal2 raises an exception.
+
+Tue Jun 3 19:11:45 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_objspace_free): should not rest_sweep() here.
+ Some data structures are already freed.
+
+Tue Jun 3 18:43:51 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_gc.rb: allocate more objects to invoke GC by newobj.
+ GC allows extending pages depends on heap_increment.
+
+Tue Jun 3 18:01:27 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_gc_call_finalizer_at_exit): add
+ gc_verify_internal_consistency() when RGENGC_CHECK_MODE >= 2.
+
+Tue Jun 3 17:54:21 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: change the counting method for young objects.
+ clear counter at the beginning of every GC and
+ count promoted (infant->young) objects.
+
+ Some promotions (infant->young) are transition of promoting to old
+ objects. We should not count such promotions.
+
+ With this technique, we don't need to check young objects
+ at obj_free().
+
+Tue Jun 3 16:38:19 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: add verifying counters code in gc_verify_internal_consistency().
+ gc_verify_internal_consistency() counts all
+ - live objects
+ - young objects (if age2 promotion)
+ - old objects
+ in all pages and compares with objspace managing counters.
+
+ * gc.c (gc_after_sweep): do gc_verify_internal_consistency()
+ when RGENGC_CHECK_MODE >= 2.
+
+Tue Jun 3 13:14:04 2014 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/imap.rb (body_type_1part): Gmail IMAP reports a body
+ type as "MIXED" followed immediately by params
+ [ruby-core:62864] [Bug #9885]
+ Patch by @rayners (David Raynes). [Fixes GH-622]
+ https://github.com/ruby/ruby/pull/622
+
+Tue Jun 3 13:18:24 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (objspace_live_slot): live slot count should not include final
+ slot (contains T_ZOMBIE) count.
+
+Tue Jun 3 13:03:21 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (obj_free): fix spacing.
+
+Tue Jun 3 12:59:32 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (check_gen_consistency): fix error message.
+
+Tue Jun 3 12:40:23 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: count old/young objects more correctly.
+
+ * gc.c (RVALUE_DEMOTE_FROM_OLD): decrement old object count.
+
+ * gc.c (RVALUE_DEMOTE_FROM_YOUNG): decrement young object count.
+
+ * gc.c (rb_gc_resurrect): increment old object count.
+
+ * gc.c (gc_marks_body): should not add old object count.
+ This code is completely my misunderstanding.
+
+ * gc.c (rb_gc_force_recycle): decrement young or old object count
+ correctly.
+
+Tue Jun 3 12:26:47 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/memory_status.rb: add $LOAD_PATH to load test/unit
+ correctly for fiddle/import unavailable environments.
+
+Tue Jun 3 09:45:13 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/openssl/test_ssl.rb (OpenSSL::TestSSL#test_verify_result):
+ shouldn't use same server for respective tests, because the 1st
+ test sometimes kills the server main loop silently.
+ [Bug #9881] [ruby-dev:48266]
+
+Tue Jun 3 01:34:59 2014 Zachary Scott <e@zzak.io>
+
+ * README.EXT: [DOC] Add rb_call_super when subclassing from @robin850
+ [Fixes GH-623] https://github.com/ruby/ruby/pull/623
+
+Mon Jun 2 17:14:49 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (ruby_vm_destruct): remove useless call of
+ rb_gc_force_recycle().
+
+ At this line, a VM object is already freed
+ (is changed to T_NONE) by rb_gc_call_finalizer_at_exit().
+
+Mon Jun 2 15:50:24 2014 Koichi Sasada <ko1@atdot.net>
+
+ * eval.c (rb_using_refinement): add write-barriers for
+ cref->nd_refinements.
+
+Mon Jun 2 12:26:08 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * CONTRIBUTING.md: added contributing guide for github. [fix GH-625]
+
+Mon Jun 2 07:30:33 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/envutil.rb (default_warning): New method.
+
+ * test/ruby/test_autoload.rb: Use EnvUtil.default_warning.
+
+Mon Jun 2 07:05:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/encoding.h: constify `rb_encoding` arguments.
+
+ * include/ruby/oniguruma.h: constify `OnigEncoding` arguments.
+
+Sun Jun 1 12:05:10 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/drb: Wrap tests definitions by DRbTests module. This makes
+ several tests (ACLEntryTest, TestBug4409, etc.) easier to understand
+ that they are tests for DRb.
+
+Sun Jun 1 11:36:25 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/rinda/ring.rb (RingFinger#make_socket): Close the socket on
+ exception.
+
+Sun Jun 1 06:55:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (intern_str): dynamic attrset ID is registered by
+ `rb_id_attrset()` already, so no further registration is needed.
+ [ruby-core:62861]
+
+Sun Jun 1 04:52:47 2014 Zachary Scott <e@zzak.io>
+
+ * lib/English.rb: [DOC] $LOADED_FEATURES moved to load.c [Fixes GH-620]
+ Patch submitted by @leafac in https://github.com/ruby/ruby/pull/620
+ * doc/globals.rdoc: Added $LOADED_FEATURES to list
+
+Sat May 31 22:30:14 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/leakchecker.rb: Leak checker extracted from
+ test/lib/minitest/unit.rb.
+
+Sat May 31 21:15:43 2014 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * thread.c (rb_thread_atfork_internal): My compiler complains
+ about this variable being used before initialized. I looked at
+ the code and expanded the macro and turned out it was actually
+ USED for pointer arithmetic, not dereferenced. So this was
+ never a serious bug. But is annoying indeed to see warnings
+ every time. I added `=0` and all went healthy.
+
+ * configure.in: Also, I found that the problematic macro expansion
+ only happens when we lack __typeof__ C extension, which shall
+ not be the case of my compiler. I added AC_C_TYPEOF to kick ass.
+
+Sat May 31 16:32:50 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/ipaddr.rb: extracted inline tests into test dir.
+ * test/test_ipaddr.rb: ditto.
+
+Sat May 31 16:29:21 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * ext/digest/lib/digest/hmac.rb: extracted inline tests into test dir.
+ * test/digest/test_digest_hmac.rb: ditto.
+
+Sat May 31 16:02:03 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/test_syslog.rb: remove executable.
+
+Sat May 31 08:58:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enc/unicode.c (init_case_fold_table): no longer need to
+ initialize tables at runtime.
+
+ * enc/unicode/case-folding.rb (lookup_hash): make perfect hash to
+ lookup case unfolding table 3.
+
+ * enc/unicode/case-folding.rb (lookup_hash): make perfect hash to
+ lookup case unfolding table 2.
+
+ * enc/unicode/case-folding.rb (lookup_hash): make perfect hash to
+ lookup case unfolding table 1.
+
+ * enc/unicode/case-folding.rb (lookup_hash): make perfect hash to
+ lookup case folding table.
+
+ * enc/unicode/case-folding.rb (print_table): merge non-locale and
+ locale tables, and reduce initializing loops.
+
+ * enc/unicode/case-folding.rb (CaseFolding): modularize, and add
+ --output-file option.
+
+ * enc/unicode/case-folding.rb: script to convert CaseFolding.txt,
+ translated from CaseFolding.py.
+
+Sat May 31 08:31:41 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb: Check Tempfile leaks for each test method
+ again.
+
+Sat May 31 03:50:50 2014 Zachary Scott <e@zzak.io>
+
+ * lib/delegate.rb: [DOC] Document raise in Delegator class
+ Patch by @lucasmazza. [Fixes GH-621]
+ https://github.com/ruby/ruby/pull/621
+
+Fri May 30 21:23:26 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/webrick/server.rb: Use a pipe to detect server shutdown.
+ shutdown() or close() for listening socket is not a reliable.
+ Actually, both doesn't work (doesn't wake up select()) on
+ DragonFly BSD 3.6.2.
+
+ * test/webrick/utils.rb: :ShutdownSocketWithoutClose is not required
+ now to immediate server shutdown detection.
+ This fixes fd leaks.
+
+ * test/net/http/utils.rb: Ditto.
+
+Fri May 30 20:58:37 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb (check_fd_leak): Sort the inspected
+ objects list for a FD.
+
+Fri May 30 18:06:55 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb (check_fd_leak): Try GC to delete leaked
+ FDs.
+
+Fri May 30 12:05:59 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * test/lib/test/unit/parallel.rb (_run_suite): orig_stdout may be nil
+ though I don't know the reason.
+
+Fri May 30 11:33:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_substr): need to reset code range for shared
+ string too, not only copied string.
+ [ruby-core:62842] [Bug #9882]
+
+Fri May 30 10:22:21 2014 Mark Lorenz <mlorenz@covermymeds.com>
+
+ * lib/erb.rb (result): [DOC] no longer accepts a Proc, as
+ Kernel.eval does not. [fix GH-619]
+
+Fri May 30 07:25:46 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/-test-/dir: Dir#fileno implemented.
+
+ * test/lib/minitest/unit.rb (find_fds): Don't return the fd used to
+ scan /proc/$$/fd.
+
+Fri May 30 04:48:00 2014 Eric Wong <e@80x24.org>
+
+ * parse.y (rb_gc_mark_parser): remove, empty since r8758
+ * internal.h: ditto, not usable from extensions since 2.0.0
+ * gc.c (gc_mark_roots): remove checkpoint for parser
+
+Thu May 29 23:27:50 2014 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * signal.c (ruby_signal): should return either `old.sa_sigaction`
+ or `old.sa_handler`, depending on whether `SA_SIGINFO` is set in
+ `old.sa_flags`, because they may not be a union.
+ [ruby-core:62836] [Bug #9878]
+
+Thu May 29 23:11:20 2014 Tanaka Akira <akr@fsij.org>
+
+ * io.c (pipe_open): Close pipes when rb_execarg_fixup() raises
+ an exception.
+ (rb_execarg_fixup_v): New function.
+
+Thu May 29 22:18:57 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb (capture_subprocess_io): Close fds.
+
+Thu May 29 19:47:08 2014 Tanaka Akira <akr@fsij.org>
+
+ * io.c (rb_io_s_pipe): Close pipes if io_encoding_set() raises an
+ exception.
+ (io_encoding_set_v): New function.
+
+Thu May 29 19:42:49 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/csv.rb (CSV.open): Close the opened file when an exception
+ occur.
+
+Thu May 29 19:31:10 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/openssl/lib/openssl/ssl.rb (SSLServer#accept): Close a socket
+ if any exception occur.
+
+Thu May 29 05:05:29 2014 Eric Wong <e@80x24.org>
+
+ * include/ruby/ruby.h: Hide Symbol internals.
+ (struct RSymbol): moved to internal.h
+ (RSYMBOL): ditto
+
+Thu May 29 00:28:56 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/unixsocket.c (rsock_init_unixsock): Open a socket
+ after path length check.
+ This fixes a fd leak by TestSocket_UNIXSocket#test_too_long_path.
+
+Wed May 28 23:04:35 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_io.rb (test_flush_in_finalizer1): Use
+ ObjectSpace.each_object to close files.
+ GC.start is not reliable.
+
+Wed May 28 19:00:31 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/net/imap.rb (Net::IMAP#initialize): Close the opened socket when
+ any exception occur.
+ This fixes a fd leak by IMAPTest#test_imaps_post_connection_check
+ which start_tls_session() raises an exception.
+
+Wed May 28 18:06:13 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/openssl/ossl_ssl.c (ossl_ssl_close): Fix sync_close to work
+ when SSL is not started.
+ This fix the fd leak by test_https_proxy_authentication in
+ test/net/http/test_https_proxy.rb.
+
+Wed May 28 10:29:28 2014 Eric Wong <e@80x24.org>
+
+ * vm.c (rb_vm_living_threads_foreach): remove function
+ [ruby-core:62745]
+ * thread.c (terminate_i): remove
+ * thread.c (terminate_all): implement (inlines old terminate_i)
+ * thread.c (rb_thread_terminate_all): use terminate_all
+ * thread.c (rb_thread_fd_close_i): remove
+ * thread.c (rb_thread_fd_close): iterate inline
+ * thread.c (thread_list_i): remove
+ * thread.c (rb_thread_list): iterate inline
+ * thread.c (rb_thread_atfork_internal): iterate inline
+ * thread.c (terminate_atfork_i): update types to remove casts
+ * thread.c (terminate_atfork_before_exec_i): ditto
+ * thread.c (struct thgroup_list_params): remove definition
+ * thread.c (thgroup_list_i): remove
+ * thread.c (thgroup_list): iterate inline
+ * thread.c (check_deadlock_i): remove
+ * thread.c (debug_deadlock_check): implement (inlines check_deadlock_i)
+ * thread.c (debug_i): remove
+ * thread.c (rb_check_deadlock): iterate inline
+ * vm.c (vm_mark_each_thread_func): remove
+ * vm.c (rb_vm_mark): iterate inline
+ * vm_core.h (rb_vm_living_threads_remove): remove
+ * vm_trace.c (clear_trace_func_i): remove
+ * vm_trace.c (rb_clear_trace_func): iterate inline
+
+Wed May 28 09:30:51 2014 Eric Wong <e@80x24.org>
+
+ * signal.c (signal_exec): ignore immediate cmd for SIG_IGN
+ * signal.c (trap_handler): set cmd to true for SIG_IGN
+ * signal.c (trap): handle nil and true values for oldcmd
+ [Bug #9835]
+
+Wed May 28 01:02:54 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/tempfile.rb (Tempfile#inspect): Show "(closed)" if the tempfile
+ is closed.
+
+Wed May 28 00:38:09 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb: Use Tempfile#close! instead of
+ Tempfile#unlink to close file descriptors.
+
+ * test/openssl/test_config.rb: Ditto.
+
+ * test/ruby/test_io.rb: Ditto.
+
+Wed May 28 00:06:18 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/net/ftp.rb (transfercmd): Close TCP server socket even if an
+ exception occur.
+
+Tue May 27 23:50:07 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/cgi/core.rb: Use Tempfile#close! instead of Tempfile#unlink
+ to close file descriptors.
+
+Tue May 27 23:06:46 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_number_literal_suffix): refine error message for
+ extra dot and digits.
+
+Tue May 27 22:44:20 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/rexml: Avoid fd leaks.
+
+Tue May 27 22:24:25 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_document.rb: Indent.
+
+Tue May 27 22:15:29 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_document.rb: Wrap by REXMLTests module.
+
+Tue May 27 22:11:10 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_encoding_2.rb: Remove a needless file.
+
+Tue May 27 22:10:30 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_contrib.rb: Indent.
+
+Tue May 27 21:28:16 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/socket/ifaddr.c (ifaddr_inspect_flags): support IFF_SIMPLEX.
+
+Tue May 27 21:03:03 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/: Use REXMLTests as wrapping module for REXML tests.
+ I avoid using the same module for library in test because
+ it provides "include REXML" environment in test. Normally,
+ users don't use REXML on "include REXML" environment. So I
+ don't want to write tests on "include REXML" environment.
+
+Tue May 27 20:59:37 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_comment.rb: Remove needless REXML module wrapping.
+
+Tue May 27 20:56:49 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/openssl/test_pkcs7.rb: Fix inverted expected and actual values.
+
+Tue May 27 20:26:06 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/ruby/test_io.rb (test_flush_in_finalizer1): some opened fds are
+ remain before GC, so unlink the tempfile is failed.
+
+Tue May 27 19:07:26 2014 Tanaka Akira <akr@fsij.org>
+
+ * io.c (rb_io_autoclose_p): Don't raise on frozen IO.
+
+ * test/lib/minitest/unit.rb: IO#autoclose? may raise IOError.
+
+Tue May 27 19:01:49 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/openssl/test_pair.rb: Modify TestSSL#test_read_and_write
+ to handle partial sysreads. [Bug #7398][ruby-core:49563]
+ * test/openssl/test_ssl.rb: ditto.
+
+Tue May 27 18:46:23 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/openssl/test_pkcs7.rb: Add tests for PKCS7#type= and add_data.
+ [Feature #7399][ruby-core:49565]
+
+Tue May 27 17:45:09 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/openssl/test_hmac.rb (test_binary_update): Added Test for
+ HMAC signing with UTF-8 String. [Bug #7512][ruby-core:50559]
+
+Tue May 27 17:10:14 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/runner.rb: fixed randomly test failure.
+ [Bug #6573][ruby-core:45563]
+
+Tue May 27 16:58:12 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/test_timeout.rb (test_timeout): inverted test condition.
+ [Bug #8523]
+
+Tue May 27 12:24:22 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb: Show leaked file descriptors.
+
+Tue May 27 11:12:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (rb_io_fileno, rb_io_inspect): non-modification does not
+ error on frozen IO. [ruby-dev:48241] [Bug #9865]
+
+Tue May 27 00:00:21 2014 yui-knk <spiketeika@gmail.com>
+
+ * insns.def (defineclass): fix typo in the instruction comment.
+ [fix GH-618]
+
+Mon May 26 16:33:15 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/ruby/test_file.rb: skip the test of atime on Windows, because
+ Windows delays updating atime about 1 hour.
+ see more details:
+ http://msdn.microsoft.com/en-us/library/windows/desktop/ms724290%28v=vs.85%29.aspx
+
+Mon May 26 12:25:36 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optionparser.rb, lib/optparse.rb (OptParse): aliases.
+ [ruby-core:62751] [Feature #9864]
+
+Mon May 26 07:59:34 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb: Show Finished threads line-by-line.
+
+Mon May 26 01:39:02 2014 Zachary Scott <e@zzak.io>
+
+ * lib/csv.rb: Reject nil as data source for CSV.new, patch by @Peeja.
+ [Fixes GH-580] https://github.com/ruby/ruby/pull/580
+
+Mon May 26 01:07:51 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb: Show leaked threads and tempfiles
+ line-by-line.
+
+Sun May 25 23:02:06 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb (MiniTest::Assertions#diff): Remove
+ tempfiles.
+
+Sun May 25 22:42:27 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb: Check tempfile leak for each test class.
+
+Sun May 25 20:31:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (ac_cv_func_{getcontext,setcontext}): do not
+ disable ucontext.h entirely, but disable use of functions only.
+ `ucontext_t` is necessary in the signal handler now.
+
+Sun May 25 20:00:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (check_stack_overflow): revert part of r46100, the
+ previous condition was correct, and fix compilation error on
+ other architecture linux. [ruby-core:62746] [Bug #9862]
+
+Sun May 25 17:09:13 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb: Less ObjectSpace.each_object(Tempfile)
+ invocation.
+
+Sun May 25 16:54:06 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb: Use Thread.list instead of
+ ObjectSpace.each_object(Thread).
+
+Sun May 25 15:53:54 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/rinda/ring.rb (Rinda::RingServer#shutdown): Join the killed
+ threads.
+
+Sun May 25 15:26:17 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/webrick/utils.rb: Override the inspect method of the thread
+ used in WEBrick::Utils::TimeoutHandler.
+
+Sun May 25 14:22:30 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/openssl: Join threads.
+
+Sun May 25 12:46:47 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (rb_bug_context): new function to report bug with
+ context.
+
+ * vm_dump.c (rb_vm_bugreport): accepts `ucontext_t` argument to
+ dump machine registers. based on [GH-584].
+
+ * signal.c (sigbus, sigsegv): dump machine registers if available.
+
+Sun May 25 12:32:42 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb: Sort leaked threads and tempfiles.
+
+Sun May 25 12:15:30 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (check_stack_overflow): fix condition to use ucontext
+ register, mcontext_t dereference, and its member names, on Mac
+ OS X.
+
+Sun May 25 11:58:26 2014 Zachary Scott <e@zzak.io>
+
+ * enumerator.c: [DOC] Fix example to show Enumerator#peek behavior
+ Patch by Erik Hollembeak [Bug #9814]
+
+Sun May 25 11:56:33 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vsnprintf.c (BSD_vfprintf): fix string width when precision is
+ given. as the result of `memchr` is NULL or its offset from the
+ start cannot exceed the size, the comparison was always false.
+ [ruby-core:62737] [Bug #9861]
+
+Sun May 25 11:32:42 2014 Zachary Scott <e@zzak.io>
+
+ * lib/yaml.rb: Remove Psych::EngineManager [Bug #8344]
+ * test/psych/*: ditto.
+
+Sun May 25 10:34:15 2014 Zachary Scott <e@zzak.io>
+
+ * doc/regexp.rdoc: [DOC] Clarify whitespace matching by @allolex
+ [Fixes GH-606] https://github.com/ruby/ruby/pull/606
+
+Sun May 25 10:19:34 2014 Zachary Scott <e@zzak.io>
+
+ * enum.c: [DOC] Use #find in example to clarify alias by @rachellogie
+ Patch submitted via documenting-ruby/ruby#34
+
+Sun May 25 10:16:43 2014 Zachary Scott <e@zzak.io>
+
+ * cont.c: [DOC] Fix rdoc in example for Fiber#transfer by @majjoha
+ Patch submitted via documenting-ruby/ruby#33
+
+Sun May 25 10:01:11 2014 Zachary Scott <e@zzak.io>
+
+ * lib/irb.rb: [DOC] Fixed syntax error in example by @jasdeepsingh.
+ Patch submitted via documenting-ruby/ruby#32
+
+Sun May 25 09:58:02 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/fileutils/test_fileutils.rb (test_chown_R): Add tests for
+ chown_R. [Feature #9383][ruby-core:59641]
+
+Sun May 25 09:57:09 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/fileutils/test_fileutils.rb: Added recursively chown tests.
+ [Feature #9303][ruby-core:59325]
+
+Sun May 25 09:41:56 2014 Zachary Scott <e@zzak.io>
+
+ * class.c: [DOC] Fixed grammar and examples of instance_methods.
+ By @alex-frost via documenting-ruby/ruby#31
+
+Sun May 25 09:40:44 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb: Show leaked threads and tempfiles.
+
+Sun May 25 08:54:38 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/openssl/test_partial_record_read.rb: Testing read_nonblock on
+ a partial TLS record results in IO::WaitReadable by @mohamedhafez.
+ [fix GH-547]
+
+Sun May 25 08:43:16 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * lib/logger.rb: refactored to include Logger::Period.
+
+Sun May 25 06:50:19 2014 Zachary Scott <e@zzak.io>
+
+ * vm_eval.c: [DOC] Improve instance_eval description when given a
+ block or String arguments. By @nathanl via documenting-ruby/ruby#28
+
+Sun May 25 06:29:39 2014 Zachary Scott <e@zzak.io>
+
+ * array.c: [DOC] Clarify default argument for Array.new.
+ By @Elffers [Fixes GH-610]
+
+Sat May 24 22:37:20 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * array.c: [DOC] Add more documents to shuffle! and shuffle.
+ Contributed by @JuanitoFatas [ci skip][fix GH-612]
+
+Sat May 24 22:28:55 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/lib/minitest/.document: removed unused configuration.
+
+Sat May 24 19:08:47 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/spec.rb: Unused file removed.
+
+ * test/lib/minitest/autorun.rb: Don't require minitest/spec.
+
+ * test/lib/minitest/benchmark.rb: Ditto.
+
+Sat May 24 18:45:30 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/benchmark/test_benchmark.rb: Use test/unit.
+
+Sat May 24 16:20:59 2014 Eric Wong <e@80x24.org>
+
+ * process.c (proc_getgroups, proc_setgroups): use ALLOCV_N
+ [Bug #9856]
+
+Sat May 24 15:49:39 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/unit.rb (parallelize_me!): Removed.
+ This fixes the line-by-line structure of the test result in verbose
+ mode. [ruby-core:54905]
+
+ * test/lib/minitest/parallel_each.rb: Removed.
+
+ * test/minitest/test_minitest_mock.rb: Don't call parallelize_me!.
+
+ * test/minitest/test_minitest_spec.rb: Ditto.
+
+ * test/minitest/test_minitest_unit.rb: Ditto.
+ Tests for parallel feature removed.
+
+Sat May 24 15:29:10 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest/hell.rb: Unused file removed.
+
+ * test/lib/minitest/pride.rb: Ditto.
+
+Sat May 24 15:05:32 2014 yui-knk <spiketeika@gmail.com>
+
+ * enumerator.c (yielder_yield_push): Insert a break after the
+ method return value. [fix GH-617]
+
+Sat May 24 14:59:12 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/minitest: Remove comments not appropriate now.
+
+ * test/minitest: Ditto.
+
+Sat May 24 14:02:04 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * NEWS: added minitest changes.
+
+Sat May 24 13:42:46 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/lib/test/unit/test-unit.gemspec: removed needless gemspec file.
+
+Sat May 24 09:39:06 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * defs/default_gems: removed minitest entry.
+
+Sat May 24 06:17:33 2014 Ryan Davis <ryand-ruby@zenspider.com>
+
+ * lib/minitest: minitest 4.7.5 removed. Need to support proper
+ gem packaging / installation before minitest 5 can be added.
+
+Sat May 24 05:54:06 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/mkconstants.rb: More constants
+
+Sat May 24 00:25:34 2014 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * NEWS: add information of incompatibility about Prime.prime?
+ * lib/prime.rb: fix docs.
+
+Fri May 23 21:36:28 2014 Josh Goebel <dreamer3@gmail.com>
+
+ * net/protocol.rb (using_each_crlf_line): fix SMTP dot-stuffing
+ for messages not ending with a new-line.
+ [ruby-core:61441] [Bug #9627] [fix GH-616]
+
+Fri May 23 03:48:08 2014 Eric Wong <e@80x24.org>
+
+ * gc.c (rb_free_m_tbl): mark function as static
+
+ * method.h (rb_free_m_tbl): remove prototype
+
+Thu May 22 22:58:27 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/mkconstants.rb: More TCP option constants.
+ Describe Linux and glibc versions.
+
+Thu May 22 20:38:10 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * file.c (stat_birthtime): add birthtime support [Feature #9647]
+
+ * file.c (rb_stat_birthtime): add File::Stat.birthtime
+
+ * file.c (rb_file_s_birthtime): add File.birthtime
+
+ * file.c (rb_file_birthtime): add File#birthtime
+
+ * configure.in: check struct stat.st_birthtimespec.
+
+Thu May 22 19:38:14 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * file.c: remove IO::Statfs because of reject. [Feature #9772]
+
+Thu May 22 14:02:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enc/jis/props.kwd: constify character property tables of JIS
+ based encodings by perfect hash.
+
+ * enc/euc_jp.c, enc/shift_jis.c: use character property functions.
+
+Wed May 21 12:21:10 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/option.c: Fix compilation error on Android.
+ Bionic doesn't define TCP state constants.
+
+Wed May 21 11:42:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: workaround for Info.plist to get rid of `dsymutil`
+ crash by wrong files in parent directories.
+ [ruby-core:62594] [Bug #9840]
+
+Tue May 20 20:57:34 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/ruby/test_dir.rb (test_glob): added testcase of double
+ slash path.
+
+Tue May 20 04:58:54 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: Don't check fields of struct tcp_info if the
+ structure is not available.
+
+Mon May 19 23:13:33 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/option.c (inspect_tcp_info): Permit longer data. (glibc
+ 2.7 adds tcpi_rcv_rtt, tcpi_rcv_space and tcpi_total_retrans to
+ struct tcp_info.)
+
+Mon May 19 20:49:07 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/option.c (inspect_tcp_info): New function to inspect
+ struct tcp_info.
+ (sockopt_inspect): Use inspect_tcp_info.
+
+ * ext/socket/extconf.rb: Check tcp_info related things.
+
+ * ext/socket/rubysocket.h: Include netinet/tcp_fsm.h if available.
+
+Mon May 19 19:36:39 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/dbm/test_dbm.rb: Use Etc.uname.
+
+ * test/gdbm/test_gdbm.rb: Ditto.
+
+Mon May 19 16:54:22 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/etc/etc.c (etc_uname): add support for Windows using
+ GetVersionExW(), GetSystemInfo(), and GetComputerNameExW() with
+ `ComputerNameDnsHostname`. [Feature #9842]
+
+Mon May 19 16:29:48 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_pat_search): advance by byte offset but not by char
+ offset. [ruby-core:62669] [Bug #9849]
+
+Mon May 19 14:06:18 2014 Shota Fukumori <her@sorah.jp>
+
+ * bin/testrb: Removed. Forgot to remove in r45971.
+ [Feature #9711] [ruby-core:62620]
+
+Sun May 18 16:42:08 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_m17n_comb.rb (test_str_crypt): Use Etc.confstr to
+ detect the glibc version.
+ libc.so is not an executable on Debian GNU/kFreeBSD 7.0 (wheezy).
+
+Sun May 18 12:15:54 2014 Jonathan Mukai-Heidt <johnnymukai@gmail.com>
+
+ * io.c (argf_each_line, argf_inplace_mode_set): [DOC] Update ARGF
+ documentation examples. `ARGF.lines` has been deprecated in
+ favor of `ARGF.each_line`. [Fixes GH-615]
+
+Sun May 18 11:59:25 2014 Tanaka Akira <akr@fsij.org>
+
+ * missing/nextafter.c: Include ruby/missing.h.
+
+Sun May 18 11:09:28 2014 Tanaka Akira <akr@fsij.org>
+
+ * win32/Makefile.sub: Add nextafter.obj to MISSING.
+
+Sun May 18 10:46:04 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/etc/etc.c: Etc.sysconf, Etc.confstr and IO#pathconf implemented.
+
+ * ext/etc/extconf.rb: Check sysconf(), confstr() and fpathconf().
+
+ * ext/etc/mkconstants.rb: New file.
+
+ [ruby-core:62600] [Feature #9842]
+
+Sun May 18 09:58:17 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/etc/etc.c: Etc.uname method implemented.
+
+ * ext/etc/extconf.rb: Check uname() function.
+
+ [ruby-core:62139] [Feature #9770]
+
+Sun May 18 09:16:33 2014 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Check nextafter() availability.
+
+ * include/ruby/missing.h (nextafter): New optional declaration.
+
+ * missing/nextafter.c: New file.
+
+ * numeric.c: Float#next_float and Float#prev_float implemented.
+
+ [ruby-core:62562] [Feature #9834]
+
+Sun May 18 09:02:17 2014 Tanaka Akira <akr@fsij.org>
+
+ * enum.c: Enumerable#slice_after implemented.
+
+ * enumerator.c: Enumerator::Lazy#slice_after implemented.
+
+ Requested by Tsuyoshi Sawada. [ruby-core:58123] [Feature #9071]
+
+Sun May 18 08:22:25 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (io_setstrbuf): always check if the buffer is modifiable.
+ [ruby-core:62643] [Bug #9847]
+
+Sun May 18 01:21:23 2014 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/ruby.h: Hide Rational internal.
+ (RRational): Moved to internal.h
+ (RRATIONAL): Ditto.
+ (RRATIONAL_SET_NUM): Moved to rational.c.
+ (RRATIONAL_SET_DEN): Ditto.
+
+ * rational.c (rb_rational_num): New function.
+ (rb_rational_den): Ditto.
+
+ * include/ruby/intern.h (rb_rational_num): Declared.
+ (rb_rational_den): Ditto.
+
+ * ext/bigdecimal/bigdecimal.c: Follow the above change.
+
+ * ext/date/date_core.c: Ditto.
+
+ [ruby-core:60665] [Feature #9513]
+
+Sat May 17 17:04:32 2014 Shota Fukumori <her@sorah.jp>
+
+ * NEWS: Add news about removal of lib/test/**/*.rb.
+
+Sat May 17 16:57:33 2014 Shota Fukumori <her@sorah.jp>
+
+ * lib/test: Removed because ruby's test cases now independent to
+ lib/test by r45970. [Feature #9711] [ruby-core:62620]
+
+ I'm still considering about the future of lib/minitest, lib/test.
+ (bundling gems?)
+
+Sat May 17 15:06:40 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/runner.rb: remove dependency test-unit and minitest
+ from stdlib when running with test-all.
+ [Feature #9711][ruby-core:61890]
+ * test/testunit/*.rb: ditto.
+ * test/lib: ditto.
+
+Sat May 17 11:02:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (glob_helper): try match PLAIN as well as ALPHA, which are
+ separated by previous commits. [ruby-core:61552] [Bug #9648]
+
+ * dir.c (glob_make_pattern): set PLAIN for non-magical path to
+ skip parts which not need to glob.
+ [ruby-core:61552] [Bug #9648]
+
+ * dir.c (has_magic): return ALPHA at alphabetical name regardless
+ FNM_CASEFOLD flag.
+
+ * dir.c (glob_helper): fix conditions for ALPHA.
+ [ruby-core:61552] [Bug #9648]
+
+Sat May 17 01:49:27 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (glob_helper): reduce matching at non-magical path on
+ Windows.
+
+Sat May 17 01:49:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (glob_pattern_type): separate names with alphabet but no
+ magical from plain.
+
+ * dir.c (glob_helper): match plain names as-is to treat super-root
+ same as the root. [ruby-core:61552] [Bug #9648]
+
+Fri May 16 17:38:22 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_marks, gc_marks_body): increase the counter of young objects
+ at the major GC because AGE2Promotion changes all old objects into
+ young objects at major GC.
+
+Fri May 16 17:26:24 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_before_sweep): heap_pages_swept_slots should contains
+ heap_pages_increment.
+
+ For example, GC by exceeding malloc_limit can remain
+ heap_pages_increment.
+
+Thu May 15 21:18:43 2014 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * configure.in: enable SSE2 on mingw. target='i386-pc-mingw32'.
+ [ruby-core:62095] [Bug #8358]
+
+Thu May 15 21:04:06 2014 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * lib/test/unit/parallel.rb: fix test-all parallel failure if a test
+ is skipped after raise.
+ DL::TestFunc#test_sinf is skipped after raise on mingw ruby.
+ But it causes Marshal.load failure due to undefined class/module
+ DL::DLError when doing test-all parallel and test-all doesn't
+ complete. We create new MiniTest::Skip object to avoid Marshal.load
+ failure.
+ [ruby-core:62133] [Bug #9767]
+
+ * test/testunit/test_parallel.rb (TestParallel): add a test.
+
+ * test/testunit/tests_for_parallel/ptest_forth.rb: ditto.
+
+Thu May 15 18:57:23 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (garbage_collect_body): move gc_heap_prepare_minimum_pages()
+ from gc_sweep().
+
+Thu May 15 18:51:25 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (heap_extend_pages): calculate next growing heap size.
+
+ * gc.c (heap_set_increment): accept addition pages instead of
+ minimum pages.
+
+ * gc.c (gc_after_sweep): use heap_etend_pages().
+
+ * gc.c (gc_heap_prepare_minimum_pages): add only 1 page.
+
+ * gc.c (heap_ready_to_gc): add only 1 page.
+
+Thu May 15 18:42:49 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: introduce macros to remove magic number.
+
+ GC_HEAP_FREE_SLOTS_MIN_RATIO = 0.3: guarantee minimum empty slots
+ ratio after sweep.
+ GC_HEAP_FREE_SLOTS_MAX_RATIO = 0.8: allow to free pages 0.2 (= 1-0.8)
+ of current existing slots.
+
+Thu May 15 17:32:51 2014 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * thread_win32.c (rb_w32_stack_overflow_handler): use Structured
+ Exception Handling by AddVectoredExceptionHandler() for machine
+ stack overflow on mingw.
+ This would be equivalent to the handling using __try and __except
+ on mswin introduced by r43748.
+
+Wed May 14 19:31:03 2014 Koichi Sasada <ko1@atdot.net>
+
+ * ext/openssl/depend: remove dependency from internal headers.
+ [Feature #9612]
+
+ * ext/openssl/ossl.c (ossl_fips_mode_set): ditto.
+
+ * ext/coverage/depend: ditto.
+
+ * include/ruby/thread_native.h: added.
+
+ This header file only provides wrapper functions to control
+ native threads. These wrapper functions are used by MRI
+ implementation.
+
+ * vm_core.h: use include/ruby/thread_native.h.
+
+ * thread.c: ditto.
+
+ * thread_pthread.h: ditto.
+
+ * thread_win32.h: ditto.
+
+ * thread_native.h: removed.
+
+Wed May 14 18:03:28 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: enable RGENGC_AGE2_PROMOTION.
+
+Wed May 14 18:02:30 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rgengc_rememberset_mark): promote remembered object earlier.
+
+Mon May 12 23:57:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (rb_cv_atan2_inf_c99): check whether runtime atan2
+ handles Inf as C99. [ruby-core:62536] [Bug #9831]
+
+Mon May 12 20:33:01 2014 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Invoke AC_REPLACE_FUNCS for each function.
+
+Mon May 12 19:52:11 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: count young object correctly and show it in GC.stat
+ on RGENGC_AGE2_PROMOTION.
+
+ * gc.c (RVALUE_PROMOTE_YOUNG): decrement young object count on
+ YOUNG->OLD.
+
+ * gc.c (obj_free): decrement young object count when young object
+ freed.
+
+ * gc.c (gc_marks): should not clear young object count.
+
+ * gc.c (gc_stat_internal): GC.stat :young_object information.
+
+Mon May 12 01:30:59 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/ifaddr.c (IS_IFADDRS): Unused macro removed.
+
+ * ext/strscan/strscan.c (BUFSIZE): Ditto.
+
+ * ext/zlib/zlib.c (OBJ_IS_FREED): Ditto.
+
+Sun May 11 22:27:18 2014 Tanaka Akira <akr@fsij.org>
+
+ * compile.c (BUFSIZE): Unused macro removed.
+
+ * vm.c (BUFSIZE): Ditto.
+
+ * pack.c (INT64toNUM): Ditto.
+ (UINT64toNUM): Ditto.
+ (BYTEWIDTH): Ditto.
+
+ * time.c (lshift): Ditto.
+ (UINT64toNUM): Ditto.
+ (id_lshift): Unused variable removed.
+
+Sun May 11 21:23:27 2014 Tanaka Akira <akr@fsij.org>
+
+ * pack.c (swaps): Unused macro removed.
+ (swapi): Ditto.
+ (swapl): Ditto.
+ (swapll): Ditto.
+
+Sun May 11 08:02:49 2014 Eric Wong <e@80x24.org>
+
+ * vm_core.h (rb_vm_t): list_head and counter for living_threads
+ (rb_thread_t): vmlt_node for living_threads linkage
+ (rb_vm_living_threads_init): new function wrapper
+ (rb_vm_living_threads_insert): ditto
+ (rb_vm_living_threads_remove): ditto
+ * vm.c (rb_vm_living_threads_foreach): new function wrapper
+ * thread.c (terminate_i, thread_start_func_2, thread_create_core,
+ thread_fd_close_i, thread_fd_close): update to use new APIs
+ * vm.c (vm_mark_each_thread_func, rb_vm_mark, ruby_vm_destruct,
+ vm_memsize, vm_init2, Init_VM): ditto
+ * vm_trace.c (clear_trace_func_i, rb_clear_trace_func): ditto
+ * benchmark/bm_vm_thread_close.rb: added to show improvement
+ * ccan/build_assert/build_assert.h: added as a dependency of list.h
+ * ccan/check_type/check_type.h: ditto
+ * ccan/container_of/container_of.h: ditto
+ * ccan/licenses/BSD-MIT: ditto
+ * ccan/licenses/CC0: ditto
+ * ccan/str/str.h: ditto (stripped of unused macros)
+ * ccan/list/list.h: ditto
+ * common.mk: add CCAN_LIST_INCLUDES
+ [ruby-core:61871][Feature #9632 (part 1)]
+
+Sun May 11 01:10:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (rb_f_kill): directly enqueue an ignored signal to self,
+ except for SIGSEGV and SIGBUS. [ruby-dev:48203] [Bug #9820]
+
+Sat May 10 22:37:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (push_glob): match in UTF-8 on Mac OS X.
+ [ruby-dev:48213] [Bug #9825]
+
+Sat May 10 13:32:18 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (thread_start_func_2): stop if forked in a sub-thread,
+ the thread has become the main thread.
+ [ruby-core:62070] [Bug #9751]
+
+Sat May 10 09:32:19 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * man/ruby.1: remove deadlink. [ruby-core:62145][Bug #9773]
+
+Sat May 10 08:47:36 2014 Tanaka Akira <akr@fsij.org>
+
+ * signal.c (trap): Return "SYSTEM_DEFAULT" if SIG_DFL is set.
+
+Fri May 9 14:27:05 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_SETJMP_TYPE): check for setjmp type after
+ CCDLFLAGS is appended to CFLAGS, since __builtin_setjmp can be
+ affected. [ruby-core:62469] [Bug #9818]
+
+Fri May 9 03:59:06 2014 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * lib/delegate.rb: Fix example of using delegator.
+ patched from Andrey Koleshko. [Fixes GH-505]
+
+Fri May 9 03:42:43 2014 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * lib/shell.rb: add documentation in lib/shell.rb
+ patched from reprah. [Fixes GH-516]
+
+Fri May 9 03:28:04 2014 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * lib/fileutils.rb: show fileutils require at top.
+ patched from Richard Schneeman. [Fixes GH-604]
+
+Fri May 9 03:07:09 2014 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * lib/prime.rb (Prime#prime?): negative numbers can't be primes
+ by definition. reported by Ivan Kataitsev. [Bug #7395]
+ * test/test_prime.rb: add test.
+
+Thu May 8 14:34:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (rb_mod_init_copy): always clear instance variable,
+ constant and method tables first, regardless the source tables.
+ [ruby-dev:48182] [Bug #9813]
+
+Thu May 8 10:53:14 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: OpenBSD needs to include sys/param.h before include
+ sys/mount.h. [ruby-dev:48167]
+
+Thu May 8 10:17:04 2014 Karsten Sperling <karsten@sperling.co.nz>
+
+ * lib/webrick/httpserver.rb (WEBrick::HTTPServer#run): stop
+ handling requests on shutdown, even if the socket is readable
+ and IO.select() returns true. [Fixes GH-607]
+
+ * lib/webrick/server.rb (WEBrick::GenericServer#start): IO.select()
+ raises ENOTSOCK on shutdown on Windows.
+
+Wed May 7 21:45:00 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/openssl/lib/openssl/ssl.rb (OpenSSL::SSL::SSLServer#accept):
+ Consider Socket#accept as well as TCPServer#accept.
+ Reported by Sam Stelfox. [ruby-core:62064] [Bug #9750]
+
+Wed May 7 17:24:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (num_step_scan_args): check keyword arguments and fail
+ if they conflict with positional arguments.
+ [ruby-dev:48177] [Bug #9811]
+
+Wed May 7 12:06:14 2014 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/driver.rb: remove debug output and output results into
+ specified file.
+
+Wed May 7 11:55:40 2014 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/driver.rb: add '--rawdata-output=[FILE] option to output
+ raw results into FILE.
+
+Wed May 7 11:25:41 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (rb_f_local_variables): exclude variables hidden by
+ shadowing. [ruby-core:60501] [Bug #9486]
+
+ * vm.c (collect_local_variables_in_iseq): ditto.
+
+Tue May 6 23:29:05 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (new_bv_gen): no duplicated names, if already added in
+ shadowing_lvar().
+
+ * parse.y (local_tbl_gen): remove local variables duplicated with
+ arguments.
+ [ruby-core:60501] [Bug #9486]
+
+Tue May 6 18:48:50 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (Time.make_time): Adjust the time zone of "now".
+
+Tue May 6 18:33:12 2014 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * io.c (io_{read,write}_nonblock): use rb_get_kwargs instead of
+ rb_hash_aref.
+
+Tue May 6 18:03:05 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (Time.make_time): Argument validation code moved from
+ Time.parse and Time.strptime.
+
+Tue May 6 17:27:06 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (Time.parse): [DOC] Fix an example in the documentation
+ to use EST.
+ Reported by Marcus Stollsteimer.
+ [ruby-core:60778] [Bug #9521] and [ruby-core:61718] [Bug #9682]
+
+Tue May 6 04:31:48 2014 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * file.c (rb_f_test): removed meaningless "case 'a'".
+
+Tue May 6 01:28:14 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/open-uri.rb (OpenURI.open_uri): Call StringIO#close only if
+ the StringIO object is not closed yet.
+ Reported by Jordi Massaguer Pla. [ruby-core:42538] [Bug #6010]
+
+Tue May 6 01:08:01 2014 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/driver.rb: define File::NULL if not defined and /dev/null
+ is available to run benchmark driver on ruby 1.9.2.
+
+Mon May 5 23:53:24 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/mkconstants.rb: Add IP_TRANSPARENT.
+ IP_TRANSPARENT is provieded since glibc-2.12.
+ Reported by Eliezer Croitoru. [ruby-core:50372] [Bug #7476]
+
+Mon May 5 22:29:47 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (check_exec_redirect): Open the file in write mode for
+ redirect from [:out, :err].
+ Proposed and implemented by Yusuke Endoh.
+ [ruby-dev:41430] [Feature #3348]
+
+Mon May 5 21:52:35 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/pathname/lib/pathname.rb (cleanpath_aggressive): make all
+ separators File::SEPARATOR from File::ALT_SEPARATOR.
+ Reported by Daniel Rikowski.
+ Fixed by Nobuyoshi Nakada. [Bug #9618]
+
+ * ext/pathname/lib/pathname.rb (cleanpath_conservative): ditto.
+
+Mon May 5 21:48:04 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/pathname/lib/pathname.rb (Pathname#/): Aliased to Pathname#+.
+ Suggested by Alexey Muranov. [ruby-core:61432] [Feature #9625]
+
+Mon May 5 17:26:09 2014 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * math.c (rb_math_sqrt): omitted exporting an unused function,
+ anyway.
+ * internal.h: follows the above change.
+
+Mon May 5 11:44:03 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (Time.strptime): Raise ArgumentError if Date._strptime
+ doesn't extract date information.
+ Reported by tadayoshi funaba. [ruby-core:62349]
+
+Mon May 5 01:12:27 2014 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * ext/date/date_core.c (rt_rewrite_frags): a new feature (not a
+ bug fix) of strptime. applies offset even if the given date is
+ not local time (%s and %Q). This is an exceptional feature and
+ I do NOT recommend to use this at all. Thank you git community.
+
+Sun May 4 20:51:32 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (Time.force_zone!): Use usual local time if it has
+ expected offset from UTC.
+
+Sun May 4 17:58:12 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (Time.force_zone!): New private method.
+ (Time.make_time): Use Time.force_zone!.
+ (Time.strptime): Ditto.
+ (Time.rfc2822): Ditto.
+ (Time.xmlschema): Ditto.
+
+ * lib/rss/rss.rb (Time.w3cdtf): Use Time.force_zone!.
+
+Sun May 4 10:22:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * math.c (math_atan2): return values like as expected by C99 if
+ both two arguments are infinity. based on the patch by cremno
+ phobia <cremno AT mail.ru> in [ruby-core:62310]. [Feature #9799]
+
+Sun May 4 03:46:42 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (Time.httpdate): Always return a UTC Time object.
+
+Sun May 4 03:26:39 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (Time.make_time): Refactored.
+
+Sun May 4 02:53:17 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (Time.rfc2822): Fix year completion.
+ Produce fixed-offset time object if appropriate.
+ (Time.xmlschema): Produce fixed-offset time object if appropriate.
+
+Sat May 3 23:52:20 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (make_time): Produce fixed-offset time object if
+ appropriate.
+ (Time.strptime): Use d[:zone] instead of d[:offset].
+
+ * lib/rss/rss.rb (Time.w3cdtf): Produce fixed-offset time object if
+ appropriate.
+
+Sat May 3 20:21:38 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (Time.strptime): Use d[:offset] if d[:seconds] is not
+ given.
+ Reported by tadayoshi funaba. [ruby-core:62322]
+
+Sat May 3 04:04:16 2014 Eric Wong <e@80x24.org>
+
+ * complex.c (parse_comp): replace ALLOCA_N with ALLOCV_N/ALLOCV_END
+ [Bug #9608]
+ * rational.c (read_digits): ditto
+
+Sat May 3 00:06:30 2014 Naohisa Goto <ngotogenome@gmail.com>
+
+ * file.c (HAVE_STRUCT_STATVFS_F_BASETYPE): File::Statfs#fstypename
+ is supported on AIX, HP-UX, and Solaris, by using the value of
+ struct statvfs.f_basetype.
+
+ * configure.in (HAVE_STRUCT_STATVFS_F_BASETYPE): check struct
+ statvfs.f_basetype which is available on AIX, HP-UX, and Solaris.
+
+Fri May 2 21:04:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (next_id): no reason to set ID_STATIC_SYM here, as ID
+ returned by rb_intern3 can be a dynamic symbol and the static
+ symbol flag is set otherwise. [Bug #9787]
+
+Fri May 2 11:32:51 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/ruby/test_io.rb (test_seek, test_seek_symwhence): defer
+ File::Statfs#type call which may not be implemented, to mitigate
+ errors on platforms where SEEK_DATA is available but f_type in
+ struct statfs is not. [ruby-dev:48154] [Bug #9789]
+
+Fri May 2 10:37:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (rb_id_attrset): turn dynamically interned Symbol into
+ an ID, since rb_str_dynamic_intern returns a Symbol but not an
+ ID. [ruby-core:62226] [Bug #9787]
+
+Thu May 1 22:19:34 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * file.c: Change AND condition to nested condition.
+
+Thu May 1 00:36:26 2014 Naohisa Goto <ngotogenome@gmail.com>
+
+ * file.c (FSTATFS): check availability of struct statfs and
+ struct statvfs in addition to fstatfs(2) and fstatvfs(2).
+ This fixes error in Solaris. [Bug #9788] [ruby-dev:48145]
+
+Wed Apr 30 19:46:23 2014 Narihiro Nakamura <authornari@gmail.com>
+
+ * gc.c (gc_after_sweep): suppress unnecessary expanding heap.
+ Tomb heap pages are freed pages here, so expanding heap is
+ not required.
+
+Wed Apr 30 17:58:40 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (invoke_block_from_c): add VM_FRAME_FLAG_BMETHOD to record
+ it is bmethod frame.
+
+ * vm.c (vm_exec): invoke RUBY_EVENT_RETURN event if rollbacked frame
+ is VM_FRAME_FLAG_BMETHOD.
+ [Bug #9759]
+
+ * test/ruby/test_settracefunc.rb: add a test for TracePoint/set_trace_func.
+
+ * vm_core.h: rename rb_thread_t::passed_me to
+ rb_thread_t::passed_bmethod_me to clarify the usage.
+
+ * vm_insnhelper.c (vm_call_bmethod_body): use renamed member.
+
+Wed Apr 30 17:06:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (rb_id_attrset): pin down dynamic symbol only. it is
+ possible that attrset ID can be registered as a static symbol
+ after the corresponding attrget ID has been registered as a
+ dynamic, and then the latter may be collected.
+ [ruby-core:62226] [Bug #9787]
+
+Tue Apr 29 14:17:57 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/tmpdir.rb: Rescue LoadError on etc.so for miniruby.
+ Revert r45707, r45711, r45717.
+
+Tue Apr 29 12:50:02 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/fileutils.rb: Don't need to define fu_get_gid and fu_get_gid in
+ rescue LoadError on 'etc'.
+
+Tue Apr 29 10:21:38 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * parse.y (symbols_i): like r45492, call rb_gc_resurrect().
+
+Tue Apr 29 04:29:05 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * file.c (HAVE_STRUCT_STATFS_T_F_FSTYPENAME): Add new macro for
+ statfs_t.
+ * file.c (HAVE_STRUCT_STATFS_T_F_TYPE): ditto.
+
+ * file.c (rb_io_statfs): check FSTATFS macro only instead of
+ HAVE_FSTATFS and HAVE_FSTATVFS.
+
+ * file.c (statfs_type): use new macro.
+ * file.c (statfs_fstypename): ditto.
+ * file.c (statfs_inspect): ditto.
+
+Tue Apr 29 00:20:26 2014 Rajarshi Das <rajarshid@cybage.com>
+
+ * bootstraptest/test_literal.rb: fix typo of "dynamic". [ci skip]
+
+ * regexp.rdoc: fix typo of "organized". [ci skip]
+
+ * lib/session.rb: fix typo of "recognized". [ci skip]
+
+Mon Apr 28 21:40:27 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in (HAVE_STRUCT_STATFS_F_TYPE): check struct statfs.f_type
+ to support OpenBSD.
+
+ * file.c (statfs_type): use above macro to switch.
+
+ * file.c (statfs_inspect): ditto.
+
+Mon Apr 28 18:06:08 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: check struct statvfs and struct statvfs.f_fstypename.
+
+ * configure.in: on NetBSD fstatfs is obsoleted.
+
+ * file.c: support NetBSD for File::Statfs.
+
+Mon Apr 28 17:42:42 2014 Narihiro Nakamura <authornari@gmail.com>
+
+ * gc.c: This argument must be a pointer.
+
+Mon Apr 28 17:40:15 2014 Narihiro Nakamura <authornari@gmail.com>
+
+ * gc.c: Fix typos. These are undefined variables.
+
+Sun Apr 27 19:39:42 2014 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * ext/date/date_strptime.c (date__strptime_internal): do not
+ overwrite century.
+
+Sat Apr 26 11:50:08 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/ruby/test_enum.rb (test_flat_map): Added test for flat_map.
+ Contribute from @igaiga. [fix GH-598]
+
+Sat Apr 26 10:55:33 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (compile_array_): make copy a first hash not to modify
+ the argument itself. keyword splat should be non-destructive.
+ [ruby-core:62161] [Bug #9776]
+
+Sat Apr 26 08:05:36 2014 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_process.rb (test_rlimit_nofile): Don't limit
+ RLIMIT_NOFILE too small.
+ This fix sporadic "[ASYNC BUG] thread_timer: select" on GNU/Linux.
+
+Fri Apr 25 22:54:34 2014 Naohisa Goto <ngotogenome@gmail.com>
+
+ * lib/fileutils.rb (rmdir): rescue Errno::EEXIST in addition to
+ ENOTEMPTY (and ENOENT), because SUSv3 describes that "If the
+ directory is not an empty directory, rmdir() shall fail and set
+ errno to [EEXIST] or [ENOTEMPTY]" and Solaris uses EEXIST.
+ [Bug #9571] [ruby-dev:48017]
+
+Fri Apr 25 19:16:30 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/webrick/utils.rb: Don't rescue LoadError for 'etc' extension.
+
+Fri Apr 25 14:55:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (rb_cv_func___builtin_unreachable): try with an
+ external variable not only by a warning, which might not be
+ shown due to the optimization. [ruby-core:61647] [Bug #9665]
+
+Fri Apr 25 13:11:49 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: NetBSD's ksh, used by configure, needs escapes.
+
+Fri Apr 25 12:51:08 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: correct pthread_setname_np's prototype on NetBSD.
+ [Bug #9586]
+
+Thu Apr 24 23:17:25 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/fileutils.rb (fu_get_uid, fu_get_gid): Etc.getpwnam/getgrnam may
+ returns nil.
+
+ * lib/webrick/utils.rb (su): ditto.
+
+Thu Apr 24 22:55:22 2014 Tanaka Akira <akr@fsij.org>
+
+ * bootstraptest/test_io.rb: Add etc.so to $" before require 'tmpdir'.
+
+Thu Apr 24 21:09:55 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * man/ruby.1: fix broken link.
+
+Thu Apr 24 20:53:02 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/tmpdir.rb: Don't need to rescue LoadError for etc.so.
+
+Thu Apr 24 17:39:53 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * file.c (statfs_inspect): suppress warnings.
+ assume those values won't be larger than LONG_LONG_MAX.
+
+Thu Apr 24 11:53:28 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/openssl/ossl_asn1.c (ossl_asn1_initialize): SYMID on a value
+ other than Symbol is an undefined behavior. fix up r31699.
+ [ruby-core:62142] [Bug #9771]
+
+Thu Apr 24 11:21:37 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (rb_sym2id, rb_sym2id_without_pindown): return 0 for
+ non-symbol values, for the time being.
+
+Thu Apr 24 05:50:13 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * parse.y (dsym_node_gen): like r45492, call rb_gc_resurrect().
+
+Wed Apr 23 20:36:22 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/etc/extconf.rb: Build ext/etc unconditionally.
+
+Wed Apr 23 14:10:50 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * file.c (statfs_fsid): remove statfs.f_fsid because it doesn't return
+ meaningful value portably. http://togetter.com/li/658517
+
+Wed Apr 23 11:03:41 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/stringio/stringio.c (strio_write): use rb_str_append to
+ reuse coderange bits other than ASCII-8BIT, and keep
+ taintedness. [ruby-dev:48118] [Bug #9769]
+
+Wed Apr 23 00:43:00 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c, include/ruby/win32.h (ustatfs): implementation of
+ statfs(2) clone. [EXPERIMENTAL]
+
+ * file.c (rb_io_statfs): use above function.
+
+ * configure.in, win32/Makefile.sub (struct statfs): available.
+
+Tue Apr 22 23:56:24 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * file.c (rb_io_stafs): use statfs(2) if fstatfs(2) is unavailable.
+
+ * configure.in (fstatfs): check it.
+
+Tue Apr 22 22:15:51 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * file.c (rb_io_statfs): need to define even if the system doesn't have
+ fstatfs(2).
+
+ * test/ruby/test_file.rb (TestFile#test_statfs): skip if IO#stafs is not
+ implemented.
+
+Tue Apr 22 19:32:48 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * file.c: newly added a class File::Statfs. (experimental)
+
+Tue Apr 22 08:22:33 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (objspace_malloc_increase): don't cause GC by malloc_increase
+ when memop type is MEMOP_TYPE_REALLOC.
+
+ GC at realloc is not well maintained.
+ We need a time to make it safe.
+ [ruby-dev:48117]
+
+Tue Apr 22 06:54:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (objspace_malloc_increase): run full mark if 0x04 bit is
+ set in ruby_gc_stress. [ruby-core:62103] [Feature #9761]
+
+ * gc.c (objspace_malloc_increase): run GC after realloc not only
+ malloc and calloc by GC.stress. [ruby-core:62103] [Feature #9761]
+
+Mon Apr 21 19:12:20 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (rb_str_coderange_scan_restartable): coderange is always
+ ENC_CODERANGE_VALID if the string is ASCII-8BIT and already has a non
+ ASCII character.
+
+Mon Apr 21 19:02:44 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (coderange_scan): remove useless condition `p < e` after
+ search_nonascii.
+
+ * string.c (rb_str_coderange_scan_restartable): ditto.
+
+Mon Apr 21 18:55:21 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/-test-/string/coderange.c: add Bug::String.new#coderange_scan
+ to explicitly scan coderange.
+
+Mon Apr 21 18:19:35 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (coderange_scan): remove unused logic.
+
+ * string.c (rb_str_coderange_scan_restartable): ditto.
+
+Mon Apr 21 14:11:48 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/stringio/stringio.c (strio_putc): fix for non-ascii
+ encoding, like as IO#putc. [ruby-dev:48114] [Bug #9765]
+
+Sun Apr 20 12:57:15 2014 Masaya Tarui <tarui@ruby-lang.org>
+
+ * st.c (st_foreach_check): change start point of search at check
+ from top to current. [ruby-dev:48047] [Bug #9646]
+
+Sun Apr 20 08:41:33 2014 Andrew DeMaria <ademariad@gmail.com>
+
+ * lib/mkmf.rb (link_command, libpathflag, create_makefile): prefer
+ user specified `$LIBPATH` than `$DEFLIBPATH`. [ruby-core:62100]
+ [ruby-trunk - Bug #9760]
+
+Sun Apr 20 06:01:18 2014 Eric Wong <e@80x24.org>
+
+ * gc.c (rb_gc_writebarrier): drop special case for big hash/array
+ [Bug #9518]
+
+Sat Apr 19 15:38:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (primary): flush cmdarg flags inside left-paren in a
+ command argument, to allow parenthesed do-block as an argument
+ without arguments parentheses. [ruby-core:61950] [Bug #9726]
+
+Sat Apr 19 10:07:24 2014 Tanaka Akira <akr@fsij.org>
+
+ * internal.h (struct RBignum): Use size_t for len.
+
+ * include/ruby/intern.h (rb_big_new): Use size_t instead of long to
+ specify the size of bignum.
+ (rb_big_resize): Ditto.
+
+ * bignum.c: Follow above changes.
+
+ * rational.c: Follow above changes.
+
+ * marshal.c: Follow above changes.
+
+Sat Apr 19 00:32:07 2014 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_num2long): Returns a long.
+ (rb_num2ulong): Returns a unsigned long.
+
+ * bignum.c (rb_big2long): Returns a long.
+ (rb_big2ulong): Returns a unsigned long.
+
+ * include/ruby/intern.h: Follow above changes.
+
+ * include/ruby/ruby.h: Follow above changes.
+ (rb_num2long_inline): No need to cast.
+ (rb_num2ulong_inline): Ditto.
+
+Sat Apr 19 00:17:20 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (SHARABLE_SUBSTRING_P): predicate if substring can be
+ shared with the original string. true if just at the end of the
+ original string, for the time being. all substring will be able to
+ be shared in the future.
+
+Fri Apr 18 21:48:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_new_frozen): consider the shared string at
+ middle.
+
+ * string.c (rb_str_subseq, rb_str_substr, str_byte_substr): share
+ middle of a string.
+
+Fri Apr 18 15:40:05 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c: use uintptr_t instead of VALUE because they are not ruby
+ object.
+
+Fri Apr 18 14:51:42 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c: check str_strlen's argument, and add comment or
+ use NULL if simply it uses str's enc.
+
+Fri Apr 18 14:32:40 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (str_strlen): use enc_strlen if the coderange is known.
+
+Fri Apr 18 14:21:21 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (enc_strlen): move UTF-8 optimization from str_strlen to
+ enc_strlen.
+
+Fri Apr 18 08:50:18 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (rb_cv_getcwd_malloc): check if getcwd allocates
+ buffer if NULL is given [ruby-core:62072] [Bug #9752]
+
+Thu Apr 17 16:28:10 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * prelude.rb: [DOC] Update Thread::exclusive docs by @stevenharman.
+
+Thu Apr 17 10:03:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/fileutils.rb (FileUtils#copy_entry): update rdoc about
+ preserve option and permissions, following r31123.
+ [ruby-core:62065] [Bug #9748]
+
+Wed Apr 16 23:47:36 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enum.c (dont_recycle_block_arg): fix condition to recycle block
+ argument. lambda with rest can get internal array directly.
+ [ruby-core:62060] [Bug #9749]
+
+Wed Apr 16 09:51:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/openssl/ossl_pkey.c (ossl_pkey_verify): as EVP_VerifyFinal()
+ finalizes only a copy of the digest context, the context must be
+ cleaned up after initialization by EVP_MD_CTX_cleanup() or a
+ memory leak will occur. [ruby-core:62038] [Bug #9743]
+
+Tue Apr 15 19:36:42 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * include/ruby/win32.h (rb_w32_cmdvector): removed.
+
+ * win32/win32.c (rb_w32_sysinit): use WCHAR version of GetCommandLine()
+ internally.
+
+ * win32/win32.c (w32_cmdvector): renamed from rb_w32_cmdvector. use
+ WCHAR* instead of char* internally.
+
+ these changes are expected to not changing the behavior yet.
+
+Tue Apr 15 19:26:05 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/extmk.rb: Re-generate extmk.mk and dummy makefiles only if
+ really required.
+ This fixes a problem to run multiple test-all concurrently as:
+ make test-all & make test-all & make test-all & ...
+
+Tue Apr 15 12:49:53 2014 Sam Rawlins <sam.rawlins@gmail.com>
+
+ * enum.c (enum_each_slice, enum_each_cons): make more efficient by
+ allocating less and recycling block argument arrays if possible.
+ [Fixes GH-596]
+
+Mon Apr 14 18:44:45 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (fill_lines): get base addrs in fill_lines to use it
+ with dladdr_fbases introduced at r45563.
+ it didn't get before if the executable is not pie.
+
+Mon Apr 14 18:05:48 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (main_exe_path): support FreeBSD.
+ At least sh, csh, tcsh, bash, and zsh sets realpath of the main
+ executable for dladdr, but gdb doesn't.
+
+Mon Apr 14 17:20:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (umethod_bind): use the ancestor iclass instead of new
+ iclass to get rid of infinite recursion, if the defined module
+ is already included. [ruby-core:62014] [Bug #9721]
+
+Sun Apr 13 12:46:58 2014 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (SIZEOF_BDIGIT): Renamed from SIZEOF_BDIGITS.
+
+ * internal.h: Ditto.
+
+ * marshal.c: Ditto.
+
+ * rational.c: Ditto.
+
+Sun Apr 13 10:18:09 2014 Tanaka Akira <akr@fsij.org>
+
+ * common.mk: Unused target, $(MKMAIN_CMD), removed.
+
+ * Makefile.in (MKMAIN_CMD): Unused macro removed.
+
+ * win32/Makefile.sub (MKMAIN_CMD): Ditto.
+
+Sat Apr 12 22:11:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (sym_to_proc), proc.c (rb_block_clear_env_self): clear
+ caller's self which is useless, so that it can get collected.
+ [Fixes GH-592]
+
+Sat Apr 12 09:26:48 2014 Eric Hodel <drbrain@segment7.net>
+
+ * ext/openssl/ossl_ocsp.c: [DOC] Document OpenSSL::OCSP.
+
+Fri Apr 11 18:52:38 2014 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (ARY_SET): added.
+
+ ARY_SET() is same functionality of RARRAY_ASET(), but
+ it has an assertion (`ary' doesn't have shared array).
+
+Fri Apr 11 16:54:26 2014 Koichi Sasada <ko1@atdot.net>
+
+ * array.c: make shared arrays WB-protected objects.
+
+ Shared arrays were WB-unprotected object because
+ sharing array can modify shared array's buffer
+ if it occupied shared array.
+
+ [sharing array (ary)] -> [shared array (shared)] -> <buff>
+ | A
+ +---------------------------------------+
+ write `buff' with WB(ary, &buff[i], obj)
+ -> if `ary' and `shared' are old, then only `ary'
+ will be remembered.
+ -> traverse from `ary'. But `shared' is old, so
+ that written `obj' is not marked.
+
+ It cause WB miss so that shared arrays were WB-unprotected.
+ (WB-unprotected objects are marked everytime if it is living)
+
+ This patch insert WB() for `shared' if it is needed.
+
+Fri Apr 11 15:05:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (rb_method_call_with_block, umethod_bind): call with
+ IClass including the module for a module instance method.
+ [ruby-core:61936] [Bug #9721]
+
+ * vm_insnhelper.c (vm_search_super_method): allow bound
+ UnboundMethod case.
+
+Fri Apr 11 12:02:30 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (rb_dump_backtrace_with_lines): set base address
+ which is retrieved from dladdr to dladdr_fbases, to skip already
+ parsed objects.
+
+Fri Apr 11 12:44:50 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (ary_reject): may be turned into a shared array during
+ the given block. [ruby-dev:48101] [Bug #9727]
+
+Thu Apr 10 23:41:21 2014 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/net/ftp.rb (Net::FTP#login): [DOC] The default password for
+ anonymous login was changed to "anonymous@" in r25313.
+
+Thu Apr 10 19:22:58 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_array.rb: remove useless `assert'.
+
+Thu Apr 10 19:11:11 2014 Koichi Sasada <ko1@atdot.net>
+
+ * array.c (rb_ary_modify): remember shared array owner if a shared
+ array owner is promoted and a shared array is not promoted.
+
+ Now, shared array is WB-unprotected so that shared arrays are not
+ promoted. All objects referred from shared array should be marked
+ correctly.
+
+ [ruby-core:61919] [ruby-trunk - Bug #9718]
+
+ * test/ruby/test_array.rb: add a test for above.
+
+Thu Apr 10 18:57:12 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_verify_internal_consistency): move lines and enable
+ allrefs_dump() on RGENGC_CHECK_MODE >= 4.
+
+Thu Apr 10 15:01:06 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (append_obj): clear allocated memory.
+
+ * addr2line.c (rb_dump_backtrace_with_lines): free `base_addrs'.
+
+Thu Apr 10 14:40:18 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_gc_writebarrier_unprotect_promoted): disable to dump debug
+ message when RGENGC_CHECK_MODE == 0.
+
+Thu Apr 10 08:13:47 2014 Tanaka Akira <akr@fsij.org>
+
+ * signal.c (check_stack_overflow): Don't use ucontext_t if ucontext.h
+ is not available.
+ Fixes build on Android (x86).
+
+Wed Apr 9 23:22:44 2014 Tanaka Akira <akr@fsij.org>
+
+ * gc.c (mark_current_machine_context): Call SET_STACK_END.
+ This reverts a hunk of r40703 by ko1.
+ This fixes [ruby-dev:48098] [Bug #9717].
+
+Wed Apr 9 21:02:04 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (OBJ2UID1): Defined even if getpwnam_r is not usable.
+ (OBJ2GID1): Defined even if getgrnam_r is not usable.
+ This fixes compilation error on Android.
+
+Wed Apr 9 15:16:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * encoding.c (rb_enc_default_internal): fix rdoc. `__FILE__` is
+ in filesystem encoding but not `default_internal`.
+ [ruby-core:61894] [Bug #9713]
+
+Wed Apr 9 14:43:00 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_gc.rb: more long timeout.
+ This test failed under RGENGC_CHECK_MODE >= 2.
+
+Wed Apr 9 13:07:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: get rid of __builtin_setjmp/__builtin_longjmp on
+ x64-mingw, which causes SEGV with callcc.
+ [ruby-core:61887] [Bug #9710]
+
+Wed Apr 9 12:44:54 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (str_buf_cat): should round up the capacity by 4KiB,
+ but not number of rooms. [ruby-core:61886] [Bug #9709]
+
+Tue Apr 8 22:55:32 2014 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/mkmf.rb (MakeMakefile#dir_config): [DOC] Improve
+ documentation.
+
+Tue Apr 8 22:31:44 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename `RGENGC_THREEGEN' to `RGENGC_AGE2_PROMOTION'.
+
+ * gc.c (rgengc_rememberset_mark): don't promote, but remain in
+ remember set for infant objects.
+
+ * gc.c (RVALUE_PROMOTE_INFANT, RVALUE_PROMOTE_YOUNG): count numbers
+ in these functions.
+
+Mon Apr 7 21:11:49 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/socket.c (sock_s_getnameinfo): Save errno for EAI_SYSTEM.
+ Reported by Saravana kumar. [ruby-core:61820] [Bug #9697]
+ Fixed by Heesob Park. [ruby-core:61868]
+
+Mon Apr 7 07:20:23 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/xmlrpc/client.rb (do_rpc): don't check body length.
+ If HTTP content-encoding is used, the length may be different.
+ [Bug #8182] [ruby-core:53811]
+
+Mon Apr 7 02:39:48 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/matrix.rb: Add Matrix#cofactor [fix GH-568]
+ Add first_minor [fix GH-568]
+ Handle empty diagonal matrix case [fix GH-576]
+ Patches by gogotanaka
+
+Sun Apr 6 08:52:50 2014 Bugra Barin <bugrabarin@hotmail.com>
+
+ * dln.c (dln_load): use wchar version to load a library in
+ non-ascii path on Windows. based on the patch by Bugra Barin
+ <bugrabarin AT hotmail.com> in [ruby-core:61845]. [Bug #9699]
+
+Sat Apr 5 19:36:33 2014 Tadayoshi Funaba <tadf@dotrb.org>
+
+ * ext/date/date_core.c (d_lite_cmp): should compare with #<.
+
+Sat Apr 5 00:31:21 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/readline/extconf.rb (rl_hook_func_t): check pointer type.
+ [ruby-dev:48089] [Bug #9702]
+
+Fri Apr 4 07:13:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (ac_cv_func___builtin_setjmp): should not skip
+ flags restoration in RUBY_WERROR_FLAG by `break`.
+ [ruby-dev:48086] [Bug #9698]
+
+Wed Apr 2 21:50:06 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (ac_cv_func___builtin_setjmp): __builtin_longjmp()
+ in Apple LLVM 5.1 (LLVM 3.4svn) uses `void**`, not `jmp_buf`.
+ [Bug #9692]
+
+Wed Apr 2 20:57:15 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c, gc.h (rb_objspace_each_objects_without_setup):
+ Add a new (hidden) C-API to iterate objspace snapshot.
+
+ This API is not safe to call any C-APIs in a given callback
+ function. Be careful to use this C-API.
+
+Wed Apr 2 17:43:17 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (ac_cv_func___builtin_setjmp): gcc 4.9 disallows a
+ variable as the second argument of __builtin_longjmp().
+ [ruby-core:61800] [Bug #9692]
+
+Wed Apr 2 15:12:18 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * common.mk: Use redmine-2.x url for DeveloperHowto wiki.
+ [ruby-core:60657] [Bug #9511]
+
+Wed Apr 2 11:46:29 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * ext/pathname/lib/pathname.rb (Pathname#join): Fix error with
+ empty args. Reported by ko1 via IRC.
+
+ * test/pathname/test_pathname.rb (TestPathname#test_join): Add the
+ test for above case.
+
+Tue Apr 1 11:39:57 2014 James Edward Gray II <james@graysoftinc.com>
+
+ * lib/csv.rb: Symbol HeaderConverter: strip leading/trailing space.
+ Reported by Skye Shaw
+ [Fixes GH-575]
+
+Tue Apr 1 11:34:04 2014 James Edward Gray II <james@graysoftinc.com>
+
+ * lib/csv.rb: Don't attempt to convert nil headers.
+ Reported by Skye Shaw
+
+Tue Apr 1 17:29:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/config_files.rb (ConfigFiles.download): show failed URI.
+ [ruby-core:61792] [Bug #9690]
+
+Tue Apr 1 12:06:49 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (rb_dump_backtrace_with_lines): don't depend hard coded
+ symbol '_start'.
+
+ * addr2line.c (fill_lines): instead of above, get a dynamic symbol
+ in the main executable and use it to know the base address.
+
+ * addr2line.c (follow_debuglink0): use obj_info_t instead of
+ line_info_t to handle object related data.
+
+ * addr2line.c (main_exe_path): defined for Linux.
+
+Tue Apr 1 08:58:39 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * parse.y (rb_str_dynamic_intern): set mark bit if dynamic symbol
+ is before sweeping.
+
+Tue Apr 1 07:37:00 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (fill_lines): use dynsym, which is used for dynamic
+ linking and always exists, if there's no symtab.
+
+Tue Apr 1 07:27:15 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_dump.c (rb_print_backtrace): current implementation
+ uses dladdr to get the path of objects.
+
+Mon Mar 31 23:57:45 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/readline/extconf.rb: fix typo, `$defs` not `$DEFS`.
+ [ruby-core:61756] [Bug #9578]
+
+Mon Mar 31 17:23:50 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/ruby/memory_status.rb: require envutil before accessing EnvUtil
+ module. reported by ko1 via twitter.
+
+Mon Mar 31 10:28:01 2014 Eric Wong <e@80x24.org>
+
+ * st.c (st_init_table_with_size): update comment
+ [Feature #9425]
+
+Sun Mar 30 23:39:26 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_accept, open_ifs_socket, socketpair_internal):
+ reset inherit flag of socket to avoid unintentional inheritance of
+ socket. note that the return value of SetHandleInformation() is not
+ verified intentionally because old Windows may return an error.
+ [Bug #9688] [ruby-core:61754]
+
+Sat Mar 29 13:04:22 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_before_sweep): cap `malloc_limit' to
+ gc_params.malloc_limit_max. It can grow and grow with such case:
+ `loop{"a" * (1024 ** 2)}'
+ [Bug #9687]
+
+ This issue is pointed by Tim Robertson.
+ http://www.omniref.com/blog/blog/2014/03/27/ruby-garbage-collection-still-not-ready-for-production/
+
+Fri Mar 28 19:32:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * struct.c (not_a_member): extract name error and use same error
+ messages. based on the patch by Marcus Stollsteimer <sto.mar AT
+ web.de> at [ruby-core:61721]. [Bug #9684]
+
+Fri Mar 28 09:21:54 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * ext/psych/psych.gemspec: update gemspec for psych-2.0.5
+
+Fri Mar 28 09:11:06 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * ext/psych/lib/psych.rb: Merge psych-2.0.5. bump version to
+ libyaml-0.1.6 for CVE-2014-2525.
+ * ext/psych/yaml/config.h: ditto.
+ * ext/psych/yaml/scanner.c: ditto.
+ * ext/psych/yaml/yaml_private.h: ditto.
+
+Thu Mar 27 18:58:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * re.c (match_regexp): set regexp for MatchData from string.
+
+ * re.c (rb_backref_set_string): create MatchData from string and
+ set backref.
+
+ * string.c (rb_pat_search, rb_str_sub, rb_str_sub_bang, str_gsub),
+ (scan_once, rb_str_scan, rb_str_partition): use rb_str_index
+ instead of rb_reg_search() when pattern is a String. based on
+ the patch by Sam Rawlins <sam.rawlins@gmail.com> [Fixes GH-579]
+
+Thu Mar 27 11:58:55 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (fill_lines): check shdr[i].sh_type because even if
+ .symtab section exists, the section's type can be SHT_NOBITS and
+ actual data doesn't exist in the file.
+ revert r45441.
+
+Wed Mar 26 14:57:35 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * parse.y: inline must be static (for mswin).
+ fixed build error introduced at r45426.
+
+Wed Mar 26 14:33:00 2014 Narihiro Nakamura <authornari@gmail.com>
+
+ * internal.h (USE_SYMBOL_GC): enable Symbol GC by default (USE_SYMBOL_GC == 1).
+
+Tue Mar 25 22:57:11 2014 Narihiro Nakamura <authornari@gmail.com>
+
+ * parse.y: support Symbol GC. [ruby-trunk Feature #9634]
+ See this ticket about Symbol GC.
+
+ * include/ruby/ruby.h:
+ Declare few functions.
+ * rb_sym2id: almost same as old SYM2ID but support dynamic symbols.
+ * rb_id2sym: almost same as old ID2SYM but support dynamic symbols.
+ * rb_sym2str: almost same as `rb_id2str(SYM2ID(sym))` but not
+ pin down a dynamic symbol.
+ Declare a new struct.
+ * struct RSymbol: represents a dynamic symbol as object in
+ Ruby's heaps.
+ Add few macros.
+ * STATIC_SYM_P: check a static symbol.
+ * DYNAMIC_SYM_P: check a dynamic symbol.
+ * RSYMBOL: cast to RSymbol
+
+ * gc.c: declare RSymbol. support T_SYMBOL.
+
+ * internal.h: Declare few functions.
+ * rb_gc_free_dsymbol: free up a dynamic symbol. GC call this
+ function at a sweep phase.
+ * rb_str_dynamic_intern: convert a string to a dynamic symbol.
+ * rb_check_id_without_pindown: not pinning function.
+ * rb_sym2id_without_pindown: ditto.
+ * rb_check_id_cstr_without_pindown: ditto.
+
+ * string.c (Init_String): String#intern and String#to_sym use
+ rb_str_dynamic_intern.
+
+ * template/id.h.tmpl: use LSB of ID as a flag for determining a
+ static symbol, so we shift left other ruby_id_types.
+
+ * string.c: use rb_sym2str instead `rb_id2str(SYM2ID(sym))` to
+ avoid pinning.
+
+ * load.c: use xx_without_pindown function at creating temporary ID
+ to avoid pinning.
+
+ * object.c: ditto.
+
+ * sprintf.c: ditto.
+
+ * struct.c: ditto.
+
+ * thread.c: ditto.
+
+ * variable.c: ditto.
+
+ * vm_method.c: ditto.
+
+Wed Mar 26 13:25:54 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (fill_lines): loop reverse order not to overwrite
+ the basis of base addresses comparison.
+
+ * addr2line.c: use uintptr_t instead of intptr_t for pointers.
+
+ * addr2line.c (rb_dump_backtrace_with_lines): don't use syms.
+
+ * vm_dump.c (rb_print_backtrace): ditto.
+
+ * addr2line.h: ditto.
+
+Wed Mar 26 11:20:50 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (w_object): internal objects are not dumpable.
+ [ruby-core:61677] [Bug #9674]
+
+ * ext/thread/thread.c (undumpable): ConditionVariable and Queue
+ are not dumpable. [ruby-core:61677] [Bug #9674]
+
+Wed Mar 26 10:36:39 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (follow_debuglink): show message if it closes opened
+ (and maybe used) elf binary.
+
+Wed Mar 26 10:34:25 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (fill_line): pass and use offset instead of
+ curobj_baseaddr.
+
+Wed Mar 26 09:07:48 2014 Yutaka Kanemoto <kanemoto@ruby-lang.org>
+
+ * configure.in: add --disable-pie. [Feature #9673]
+
+Wed Mar 26 08:47:04 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (fill_lines): don't run fill_lines multiple times.
+
+Wed Mar 26 08:45:00 2014 Sam Rawlins <sam.rawlins@gmail.com>
+
+ * internal.h: add prototype for rb_reg_search0
+
+ * re.c: rename rb_reg_search to rb_reg_search0, add set_backref_str
+ argument to allow callers to indicate that they don't require the
+ backref string to be allocated.
+
+ * string.c: don't allocate backref str if replacement string is provided
+
+ [GH-578] [Bug #9676] [ruby-core:61682]
+
+Wed Mar 26 08:29:43 2014 mo khan <mo@mokhan.ca>
+
+ * lib/rubygems.rb: fix spelling of Jim Weirich. [Fixes GH-577]
+
+Wed Mar 26 01:55:45 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (rb_dump_backtrace_with_lines): a function to get must
+ be a function in the main executable, whose absolute path is not
+ available by dladdr, and ruby get it by /proc/self/exe on Linux.
+
+Wed Mar 26 01:34:50 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (fill_lines): skip if path is NULL.
+
+Tue Mar 25 23:57:17 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_yylex): only a newline after label should be
+ significant. [ruby-core:61658] [Bug #9669]
+
+Tue Mar 25 23:32:25 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * ext/pathname/lib/pathname.rb (Pathname#join): remove unnecessary
+ unshift.
+
+ * test/pathname/test_pathname.rb (TestPathname#test_join): add tests.
+
+Tue Mar 25 16:47:36 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (lex_state_e, parser_params, f_arglist, parser_yylex):
+ separate EXPR_LABELARG from EXPR_BEG and let newline significant,
+ so that required keyword argument can place at the end of
+ argument list without parentheses. [ruby-core:61658] [Bug #9669]
+
+Mon Mar 24 22:19:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (ripper_initialize): filename can not be modified.
+
+Mon Mar 24 15:19:47 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (rb_dump_backtrace_with_lines): fetch path of the
+ executable from /proc/self/exe on Linux.
+
+Mon Mar 24 14:14:37 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * gc.c: Fix up default GC params by @csfrancis [fix GH-556]
+
+Mon Mar 24 13:13:36 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (parse_debug_line_cu): explicitly specify signed char
+ because DWARF's line_Base is signed char and char maybe unsigned.
+ patched by Rei Odaira. [ruby-dev:48068] [Bug #9654]
+
+Sun Mar 23 11:03:50 2014 Kohei Suzuki <eagletmt@gmail.com>
+
+ * vm_method.c (rb_method_entry_get_without_cache): me->klass is 0
+ for a method aliased in a module. [ruby-core:61636] [Bug #9663]
+
+Sun Mar 23 08:12:27 2014 Eric Wong <e@80x24.org>
+
+ * st.c (hash_pos): use bitwise AND to avoid slow modulo op
+ (new_size): power-of-two sizes for hash_pos change
+ (st_numhash): adjust for common keys due to lack of prime modulo
+ [Feature #9425]
+ * hash.c (rb_any_hash): right shift for symbols
+ * benchmark/bm_hash_aref_miss.rb: added to show improvement
+ * benchmark/bm_hash_aref_sym_long.rb: ditto
+ * benchmark/bm_hash_aref_str.rb: ditto
+ * benchmark/bm_hash_aref_sym.rb: ditto
+ * benchmark/bm_hash_ident_num.rb: added to prevent regression
+ * benchmark/bm_hash_ident_obj.rb: ditto
+ * benchmark/bm_hash_ident_str.rb: ditto
+ * benchmark/bm_hash_ident_sym.rb: ditto
+
+Sat Mar 22 22:56:45 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (fill_lines): compare the file names of object in which
+ symbols exist. [Bug #9654] [ruby-dev:48058]
+
+Sat Mar 22 06:46:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/cgi/util.rb (escape_html, unescape_html): make synonyms
+ aliases instead of wrapper methods.
+
+ * lib/cgi/util.rb (escape_element, unescape_element): ditto.
+ [Fixes GH-573]
+
+Fri Mar 21 21:57:34 2014 Akinori MUSHA <knu@iDaemons.org>
+
+ * configure.in: Fix a build problem with clang and --with-opt-dir.
+ If ruby is configured with --with-opt-dir=dir when using clang
+ as compiler, a warning `clang: warning: argument unused during
+ compilation: '-I dir'` is emitted almost every time clang
+ compiles a file. Unfortunately, RUBY_CHECK_PRINTF_PREFIX takes
+ any output from the compiler as fatal error, and the check thus
+ fails due to the warning. This is an attempt to fix the problem
+ by adding a flag -Qunused-arguments to CFLAGS locally in the
+ function to suppress the warning. [ruby-dev:48062] [Bug #9658]
+ [Fixes GH-571] https://github.com/ruby/ruby/pull/571
+
+Fri Mar 21 16:31:56 2014 Zachary Scott <e@zzak.io>
+
+ * gc.c: [DOC] Fix call-seq for GC.start by @jasonrclark [Fixes GH-572]
+ https://github.com/ruby/ruby/pull/572
+
+Thu Mar 20 11:37:28 2014 James Edward Gray II <james@graysoftinc.com>
+
+ * lib/csv.rb: Fixed a broken regular expression that was causing
+ CSV to miss escaping some special meaning characters when used
+ in parsing.
+ Reported by David Unric
+ [ruby-core:54986] [Bug #8405]
+
+Thu Mar 20 16:53:07 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (objspace_malloc_increase): should not invoke
+ garbage_collect_with_gvl() here on non-ruby threads.
+
+ Should just ignore the malloc_increase.
+
+ This issue is pointed by Eric Wong [ruby-core:61519].
+
+Thu Mar 20 13:05:16 2014 Koichi Sasada <ko1@atdot.net>
+
+ * struct.c (rb_struct_alloc): use RARRAY_CONST_PTR() instead of
+ RARRAY_PTR().
+
+Thu Mar 20 12:59:39 2014 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/intern.h (rb_obj_call_init, rb_class_new_instance):
+ constify a parameter (VALUE *).
+ I believe this incompatibility doesn't break any code.
+ However, if you have trouble, please tell us.
+
+ * eval.c, object.c: ditto.
+
+Thu Mar 20 12:31:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_method.c (rb_method_entry_get_without_cache): get rid of
+ infinite recursion at aliases in a subclass and a superclass.
+ return actually defined class for other than singleton class.
+ [ruby-core:60431] [Bug #9475]
+
+Wed Mar 19 17:13:06 2014 Eric Wong <e@80x24.org>
+
+ * time.c (time_mload): freeze and preserve marshal-loaded time zone
+ * test/ruby/test_time.rb: add test for GC on loaded object
+ [Bug #9652]
+
+Tue Mar 18 23:20:12 2014 Shota Fukumori <her@sorah.jp>
+
+ * vm_eval.c (eval_string_with_cref): Unify to use NIL_P.
+
+Tue Mar 18 22:03:41 2014 Shota Fukumori <her@sorah.jp>
+
+ * vm_eval.c (eval_string_with_cref): Use file path even if scope is
+ given. Related to [ruby-core:56099] [Bug #8662] and r42103.
+
+Mon Mar 17 13:17:47 2014 Koichi Sasada <ko1@atdot.net>
+
+ * enumerator.c (enumerator_block_call): use RARRAY_CONST_PTR()
+ instead of RARRAY_PTR().
+
+ * io.c (rb_io_s_popen): ditto.
+
+ * numeric.c (num_step_size): ditto.
+
+ * vm_eval.c (rb_apply): ditto.
+
+ * vm_eval.c (rb_eval_cmd): ditto.
+
+Mon Mar 17 10:11:59 2014 Eric Wong <e@80x24.org>
+
+ * variable.c (rb_const_set): delete existing entry on redefinition
+ [Bug #9645]
+ * test/ruby/test_const.rb (test_redefinition): test for leak
+
+Sun Mar 16 21:33:01 2014 Zachary Scott <e@zzak.io>
+
+ * lib/time.rb: [DOC] Fix timezone in example of Time.parse [Bug #9521]
+ Based on patch by @stomar
+
+Sun Mar 16 13:21:40 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (DLDFLAGS): insert a space between option and its
+ argument for non-GCC compilers. [ruby-core:61429] [Bug #9624]
+
+Sun Mar 16 08:05:06 2014 Eric Wong <e@80x24.org>
+
+ * gc.c (objspace_xcalloc): fix GC accounting
+
+Sun Mar 16 06:33:35 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (fill_lines): return address is just after calling
+ address. Therefore noreturn function with tail call's return
+ address may be in another function.
+
+Sun Mar 16 05:51:55 2014 Zachary Scott <e@zzak.io>
+
+ * lib/gserver.rb: [DOC] Fixed typo in example by @stomar [Bug #9543]
+
+Sat Mar 15 18:54:03 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * ext/.document: remove refinement from documentable directories.
+
+Sat Mar 15 11:02:58 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (DLDFLAGS): check for each options to control
+ symbol resolution. [ruby-core:61429] [Bug #9624]
+
+Sat Mar 15 07:02:35 2014 Eric Wong <e@80x24.org>
+
+ * st.c (st_update): remove unnecessary assignment
+
+Fri Mar 14 14:58:38 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c (fill_lines): fetch symbol names from ELF binary's
+ symbol table if it is built with cc -g and not stripped.
+ Now ruby can show static symbols on Linux though glibc's
+ backtrace_symbols(3) don't show them.
+
+ * addr2line.c (rb_dump_backtrace_with_lines): use dladdr(3) to
+ detect what object file declares the symbol because
+ dl_iterate_phdr can't detect the main executable file
+ and codes on the stack.
+ NOTE: signal trampolines sometimes on the user stack. (FreeBSD)
+
+ * addr2line.c (rb_dump_backtrace_with_lines): stop showing
+ backtrace if the function's name is main.
+ NOTE: FreeBSD's backtrace (libexecinfo) shows _start and
+ an additional address. Why it doesn't remove them on dladdr phase
+ is, dladdr may fail to detect the main function but detect
+ as _start function. Therefore it must be after scanning
+ the symbol table and getting correct name.
+
+
+Fri Mar 14 12:07:46 2014 Zachary Scott <e@zzak.io>
+
+ * doc/syntax/literals.rdoc: [DOC] Single quote strings allows escape
+ of backslash as well, patch by @idupree [Fixes GH-553]
+ https://github.com/ruby/ruby/pull/553
+
+Fri Mar 14 01:18:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm.c (invoke_block_from_c): add splattable argument.
+
+ * vm.c (vm_invoke_proc): disallow to splat when directly invoked.
+
+ * vm_insnhelper.c (vm_callee_setup_arg_complex, vm_callee_setup_arg):
+ relax arity check of yielded lambda. [ruby-core:61340] [Bug #9605]
+
+ * test/ruby/test_yield.rb (TestRubyYieldGen#emu_bind_params): no
+ longer raise ArgumentError when splatting to lambda.
+
+Thu Mar 13 23:51:02 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/-test-/win32/dln/libdlntest.c (dlntest_ordinal): no need to
+ specify export in the source file because .def file do it.
+ get rid of warning on linking.
+
+Wed Mar 12 11:19:03 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_callee_setup_arg): disable fastpath if splat
+ argument, since argc may differ for each calls.
+ [ruby-core:61422] [Bug #9622]
+
+ * vm_insnhelper.c (vm_callee_setup_arg): turn a macro into an
+ inline function.
+
+Wed Mar 12 07:26:05 2014 Eric Wong <e@80x24.org>
+
+ * insns.def (opt_regexpmatch2): respect redefined match op
+ Thanks to Sam Rawlins for the fix.
+ * test/ruby/test_string.rb: test based on Tsuyoshi Sawada's report
+ [Bug #9581]
+
+Tue Mar 11 22:31:25 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * ext/.document: add objspace/objspace_dump.c to document file.
+
+Tue Mar 11 22:22:38 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * test/objspace/test_objspace.rb (TestObjSpace#test_dump_uninitialized_file):
+ remove dependency on json library.
+
+Tue Mar 11 10:55:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * README.EXT{,.ja} (Appendix B): update contents of `ruby_options`
+ and replace `ruby_run` with `ruby_run_node`. based on the patch
+ by Kaneko Yuichiro at [ruby-dev:48030] [Bug #9619].
+
+Tue Mar 11 06:54:00 2014 Scott Francis <scott.francis@shopify.com>
+
+ * ext/objspace/objspace_dump.c: Check fptr before trying to dump RFILE
+ object fd. [GH-562]
+
+ * test/objspace/test_objspace.rb: add test
+
+Tue Mar 11 02:04:36 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_dump.c (rb_vm_bugreport): show vm maps on FreeBSD.
+
+ * vm_dump.c (procstat_vm): copied from FreeBSD.
+ http://svnweb.freebsd.org/base/head/usr.bin/procstat/procstat_vm.c?revision=261780
+
+Mon Mar 10 12:14:26 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: always check dladdr(1).
+
+ * addr2line.c (fill_lines): show the line number in C backtrace if
+ ruby is built without --enable-shared (PIE) on Linux.
+ patch is originally by Shinichiro Hamaji
+ https://twitter.com/shinh/status/441957774264504321
+ NOTE: ld doesn't insert __executable_start for PIE.
+ dladdr(3)'s argument must be a function pointer.
+
+Mon Mar 10 10:51:17 2014 ksss <co000ri@gmail.com>
+
+ * test/ruby/test_enumerator.rb (test_iterators): fix test for hash
+ iterators. [Fixes GH-558]
+
+Sun Mar 9 14:14:49 2014 Eric Wong <e@80x24.org>
+
+ * class.c (rb_class_subclass_add): use xmalloc
+ * class.c (rb_module_add_to_subclasses_list): ditto
+ * class.c (rb_class_remove_from_super_subclasses): use xfree
+ * class.c (rb_class_remove_from_module_subclasses): ditto
+ [Bug #9616]
+
+Sun Mar 9 13:51:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/fiddle/function.c (function_call): fix memory leak when an
+ exception occurs at argument conversion or the function call.
+
+Sun Mar 9 06:42:40 2014 Eric Wong <e@80x24.org>
+
+ * variable.c (struct global_variable): shrink by 8 bytes on 64-bit
+
+Sat Mar 8 17:42:51 2014 Eric Wong <e@80x24.org>
+
+ * vm.c (add_opt_method): cleanup to use rb_method_entry_at
+
+Sat Mar 8 13:46:40 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/dl/cptr.c (dlptr_free), ext/dl/handle.c (dlhandle_free),
+ ext/fiddle/handle.c (fiddle_handle_free),
+ ext/fiddle/pointer.c (fiddle_ptr_free): fix memory leak.
+ based on the patch Heesob Park at [ruby-dev:48021] [Bug #9599].
+
+Sat Mar 8 13:30:39 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (obj2uid, obj2gid): now getpwnam_r() and getgrnam_r()
+ may need larger buffers than sysconf values, so retry with
+ expanding the buffer when ERANGE is returned.
+ [ruby-core:61325] [Bug #9600]
+
+Fri Mar 7 19:29:13 2014 Eric Wong <e@80x24.org>
+
+ * vm_eval.c (vm_call0_body): use RARRAY_CONST_PTR
+ (check_funcall_exec): ditto
+ [ruby-core:61360]
+
+Fri Mar 7 19:14:11 2014 Eric Wong <e@80x24.org>
+
+ * vm_eval.c (vm_call0_body): fix RB_GC_GUARD location
+ (check_funcall_exec): ditto
+ [Bug #9609]
+
+Fri Mar 7 14:48:17 2014 Narihiro Nakamura <authornari@gmail.com>
+
+ * parse.y (ENC_SINGLE): Unused macro removed.
+
+Fri Mar 7 12:06:19 2014 Martin Bosslet <Martin.Bosslet@gmail.com>
+
+ * test/openssl/test_ssl.rb: Reuse TLS default options from
+ OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.
+
+Thu Mar 6 15:15:24 2014 Zachary Scott <e@zzak.io>
+
+ * doc/syntax/assignment.rdoc: [DOC] Fix assignment directions
+ By @idupree [Fixes GH-555] https://github.com/ruby/ruby/pull/555
+
+Thu Mar 6 15:07:18 2014 Zachary Scott <e@zzak.io>
+
+ * doc/syntax/methods.rdoc: [DOC] Fix example for block arguments
+ By @idupree [Fixes GH-554] https://github.com/ruby/ruby/pull/554
+
+Thu Mar 6 10:33:31 2014 Martin Bosslet <Martin.Bosslet@gmail.com>
+
+ * lib/openssl/ssl.rb: Explicitly whitelist the default
+ SSL/TLS ciphers. Forbid SSLv2 and SSLv3, disable
+ compression by default.
+ Reported by Jeff Hodges.
+ [ruby-core:59829] [Bug #9424]
+
+Wed Mar 5 15:56:18 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (f_arg_asgn): define optional arguments as argument
+ variables in the rhs default expressions.
+ [ruby-core:61299] [Bug #9593]
+
+Wed Mar 5 11:58:30 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/openssl/ossl.c (ossl_make_error): check NULL for unknown
+ error reasons with old OpenSSL, and insert a colon iff formatted
+ message is not empty.
+
+Wed Mar 5 00:42:00 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * ext/pathname/lib/pathname.rb (Pathname#find): add "ignore_error"
+ keyword argument defaulted to true as well as Find#find.
+
+Tue Mar 4 23:00:18 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/ruby/test_eval.rb (TestEval#make_test_binding): renamed.
+ it's not test method.
+
+Tue Mar 4 20:50:59 2014 Masaya Tarui <tarui@ruby-lang.org>
+
+ * st.c (st_foreach): fix type of hash. not st_data_t but st_index_t.
+
+Tue Mar 4 19:41:40 2014 Tanaka Akira <akr@fsij.org>
+
+ * Makefile.in: ".DEFAULT" target removed because it is not for
+ specifying default target.
+
+Tue Mar 4 00:25:35 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * lib/find.rb (Find#find): should pass ignore_error option to enumerators.
+
+Mon Mar 3 13:27:35 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/test_find.rb (TestFind#test_unsearchable_dir): ruby cannot make
+ directory unreachable by owner on Windows.
+
+Mon Mar 3 08:10:04 2014 Eric Wong <e@80x24.org>
+
+ * vm_method.c (rb_method_entry_get_without_cache): disable GMC
+ writing if GMC is disabled.
+ [ruby-core:61218]
+
+Mon Mar 3 07:47:17 2014 Eric Wong <e@80x24.org>
+
+ * README.EXT: wrap GetDBM with do/while(0)
+ * README.EXT.ja: ditto
+ * ext/dbm/dbm.c: ditto, likewise for GetDBM2
+ * ext/gdbm/gdbm.c: ditto
+ * ext/sdbm/init.c: ditto
+ [ruby-core:61217]
+
+Mon Mar 3 07:17:31 2014 Zachary Scott <e@zzak.io>
+
+ * NEWS: [DOC] Update doc regarding filesystem load when flushing IO
+
+Mon Mar 3 04:37:50 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * io.c (rb_io_fsync): need to fsync even if on Windows. fixed mistake
+ of r45254 and r45256.
+
+Mon Mar 3 04:21:34 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/win32ole: get rid of warnings (unused variable).
+
+Mon Mar 3 02:53:53 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * io.c (rb_io_flush_raw): [EXPERIMENTAL] remove force syncing for Win32
+ to speed up IO. this may break some tests, and they'll be fixed
+ later.
+ [ruby-core:58570] [Bug #9153]
+
+Mon Mar 3 00:17:43 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/ruby/test_backtrace.rb: get rid of warnings. unused variable,
+ shadowing.
+
+Sun Mar 2 11:15:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/find.rb (Find#find): add "ignore_error" keyword argument
+ defaulted to true. [ruby-core:51025] [Feature #7596]
+
+Sun Mar 2 11:13:30 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/readline/extconf.rb (rl_hook_func_t): define as Function for
+ very old readline versions. [ruby-core:61209] [Bug #9578]
+
+Sun Mar 2 10:47:58 2014 Eric Wong <e@80x24.org>
+
+ * load.c (ruby_init_ext): make idempotent to suppress warnings
+
+Sat Mar 1 19:51:42 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/open3.rb (Open3.capture3): Ignore Errno::EPIPE for writing
+ stdin_data.
+ (Open3.capture2): Ditto.
+ (Open3.capture2e): Ditto.
+
+Sat Mar 1 19:06:47 2014 Eric Wong <e@80x24.org>
+
+ * gc.c (ruby_gc_set_params): simplify condition
+
+Sat Mar 1 16:18:40 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/readline/readline.c (Init_readline): Use rl_hook_func_t instead
+ of Function to support readline-6.3. (rl_hook_func_t is available
+ since readline-4.2.)
+ Reported by Dmitry Medvinsky. [ruby-core:61141] [Bug #9578]
+
+Sat Mar 1 16:05:58 2014 Eric Wong <e@80x24.org>
+
+ * gc.c (ruby_gc_set_params): fix building without RGenGC
+
+Sat Mar 1 11:08:00 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: support dumping Encoding
+ objects.
+
+ * ext/psych/lib/psych/visitors/to_ruby.rb: support loading Encoding
+ objects.
+
+ * test/psych/test_encoding.rb: add test
+
+ * ext/psych/lib/psych.rb: add version
+
+Sat Mar 1 10:52:34 2014 Zachary Scott <e@zzak.io>
+
+ * README.EXT.ja: [DOC] Fix typo "macro macro" @utenmiki [Fixes GH-551]
+ https://github.com/ruby/ruby/pull/551
+
+Fri Feb 28 11:16:55 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * numeric.c: Fix Numeric#step with 0 unit [Bug #9575]
+
+Thu Feb 27 17:59:01 2014 Zachary Scott <e@zzak.io>
+
+ * lib/optparse.rb: [DOC] Add example of generating help with optparse.
+ Patch by @joelmccracken documenting-ruby/ruby#19
+ https://github.com/documenting-ruby/ruby/pull/19
+
+Thu Feb 27 12:10:09 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (ruby_num_interval_step_size): check signs and get rid
+ of implementation dependent behavior of negative division.
+ [ruby-core:61106] [Bug #9570]
+
+Thu Feb 27 03:55:45 2014 Zachary Scott <e@zzak.io>
+
+ * thread.c: [DOC] Typo in comment for _FORTIFY_SOURCE [Fixes GH-548]
+ Patch by @qnet-herwin https://github.com/ruby/ruby/pull/548
+
+Wed Feb 26 18:43:43 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (heap_pages_free_unused_pages): check tomb page availability
+ at first.
+ And return immediately if we don't touch sorted list any more.
+
+Wed Feb 26 14:10:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (setup_exception): preserve exception class name encoding
+ in debug mode messages.
+
+ * eval.c (setup_exception): preserve errinfo across calling #to_s
+ method on the exception. [ruby-core:61091] [Bug #9568]
+
+Wed Feb 26 01:29:27 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (sym_find): Add Symbol.find(str), which returns whether given
+ string is defined as symbol or not. [Feature #7854]
+
+Tue Feb 25 22:52:02 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * ext/dl/dl.c (rb_dl_realloc): use NUM2SIZET instead of NUM2INT.
+
+ * ext/fiddle/fiddle.c (rb_fiddle_realloc): ditto.
+
+Tue Feb 25 22:49:30 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * ext/dl/dl.c (rb_dl_malloc): use NUM2SIZET instead of NUM2INT.
+ Coverity Scan found this bug.
+
+ * ext/fiddle/fiddle.c (rb_fiddle_malloc): ditto.
+
+Tue Feb 25 12:06:13 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * win32/Makefile.sub: define PACKED_STRUCT.
+
+Mon Feb 24 21:41:56 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * README.md, README.ja.md: removed (wrong) mode setting for emacs.
+
+Mon Feb 24 20:05:41 2014 Eric Wong <e@80x24.org>
+
+ * configure.in: define PACKED_STRUCT_UNALIGNED for x86*
+ * timev.h (struct vtm): use PACKED_STRUCT_UNALIGNED
+ * time.c (struct time_object): ditto
+ [Bug #9558] non-x86 cannot safely access unaligned addresses
+
+Mon Feb 24 18:10:02 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/fiddle/test_function.rb: remove unused variables.
+ * test/fileutils/test_fileutils.rb: ditto.
+ * test/io/console/test_io_console.rb: ditto.
+
+Mon Feb 24 12:37:51 2014 Eric Wong <e@80x24.org>
+
+ * configure.in: use -Wno-packed-bitfield-compat for GCC 4.4+
+ use __attribute__((packed)) if available
+ * timev.h: shrink and pack struct vtm
+ * time.c: pack struct time_object and adjust/introduce helpers
+ [ruby-core:60794]
+
+Sun Feb 23 17:55:50 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/xmltokens.rb: Add missing non ASCII valid characters
+ to element name characters. Now, REXML name tokens exactly
+ match "[5] Name" in the XML spec and "[4] NCName" in the
+ Namespaces in XML spec. See comment about the details.
+ [Bug #9539] [ruby-core:60901]
+ Reported by Mario Barcala. Thanks!!!
+
+ * test/rexml/xpath/test_node.rb: Add tests for the above case.
+
+Sun Feb 23 12:18:54 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/raddrinfo.c (inet_pton): use rb_w32_inet_pton, instead of
+ inet_pton directly, which is unavailable on older version Windows.
+
+ * include/ruby/win32.h, win32/win32.c (rb_w32_inet_pton): add a
+ wrapper function for inet_pton minimum supported client is
+ Vista, as well as inet_ntop.
+
+Sun Feb 23 11:33:25 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/net/imap/test_imap.rb: remove unused variables.
+ * test/net/imap/test_imap_response_parser.rb: ditto.
+ * test/net/pop/test_pop.rb: ditto.
+
+Sun Feb 23 02:19:51 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb (bind_random_port): Rescue EPERM for FreeBSD which
+ security.mac.portacl.port_high is changed.
+ See mac_portacl(4) for details.
+ Reported by Jakub Szafranski. [ruby-core:60917] [Bug #9544]
+
+Sat Feb 22 23:17:01 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/xpath_parser.rb: Fix indent.
+
+Sat Feb 22 23:15:35 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/xpath/test_attribute.rb: Simplify.
+
+Sat Feb 22 20:28:47 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * tool/redmine-backporter.rb: more friendly.
+
+Sat Feb 22 20:24:43 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/test_xpath*.rb: Move to ...
+ * test/rexml/xpath/*.rb: ... here.
+
+Sat Feb 22 20:04:41 2014 Kouhei Sutou <kou@cozmixng.org>
+
+ * test/rexml/listener.rb: Untabify.
+
+Sat Feb 22 19:07:31 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/io/console/console.c (console_dev): need read access for conout$
+ because some functions need it. [Bug#9554]
+
+Sat Feb 22 18:40:58 2014 Eric Wong <e@80x24.org>
+
+ * .gitignore: ignore benchmark files
+
+Sat Feb 22 01:22:24 2014 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * bignum.c (bary_mul_precheck): fix a copy-paste error.
+ Coverity Scan found this bug.
+
+Sat Feb 22 00:58:51 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * ext/socket/raddrinfo.c (rb_getaddrinfo): second argument of
+ MEMZERO is type. Coverity Scan found this bug.
+
+Fri Feb 21 23:47:24 2014 Shugo Maeda <shugo@ruby-lang.org>
+
+ * ext/socket/init.c (wait_connectable): break if the socket is
+ writable to avoid infinite loops on FreeBSD and other platforms
+ which conforms to SUSv3. This problem cannot be reproduced with
+ loopback interfaces, so it's hard to write test code.
+ rsock_connect() and wait_connectable() are overly complicated, so
+ they should be refactored, but I commit this fix as a workaround
+ for the release of Ruby 1.9.3 scheduled on Feb 24.
+ [ruby-core:60940] [Bug #9547]
+
+Fri Feb 21 23:03:39 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/redmine-backporter.rb: added to handle redmine tickets.
+
+Fri Feb 21 20:42:01 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (rb_mod_init_copy): do nothing if copying self.
+ [ruby-dev:47989] [Bug #9535]
+
+ * hash.c (rb_hash_initialize_copy): ditto.
+
+Fri Feb 21 16:45:54 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/logger.rb (next_rotate_time, previous_period_end): consider
+ DST change.
+
+ * lib/logger.rb (Logger::LogDevice#check_shift_log): compare the
+ current time with the time for the next rotation to fix rotation
+ miss when date changed between the comparison and log writing.
+ based on the patch by megayu <yuhg2310 AT gmail.com>.
+ [Fixes GH-539]
+
+Fri Feb 21 10:39:33 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/monitor/test_monitor.rb: remove unused variables.
+ * test/resolv/test_dns.rb: ditto.
+ * test/rexml/test_functions.rb: ditto.
+ * test/rss/test_setup_maker_itunes.rb: ditto.
+
+Fri Feb 21 09:48:56 2014 Eric Wong <e@80x24.org>
+
+ * ext/socket/ancdata.c (bsock_sendmsg_internal): only retry on error
+ (bsock_recvmsg_internal): ditto
+ * test/socket/test_unix.rb: test above for infinite loop
+
+Fri Feb 21 08:27:19 2014 Eric Wong <e@80x24.org>
+
+ * include/ruby/ruby.h (RB_GC_GUARD):
+ use rb_gc_guarded_ptr_val on non-GCC/MSC
+ * gc.c (rb_gc_guarded_ptr_val): rename and adjust argument.
+ RB_GC_GUARD should be robust enough for any compiler.
+ [ruby-core:60816] [Bug #7805]
+
+Thu Feb 20 22:21:26 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/raddrinfo.c (numeric_getaddrinfo): Use xcalloc.
+ Suggested by Eric Wong.
+ https://bugs.ruby-lang.org/issues/9525#note-14
+
+Thu Feb 20 11:21:13 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_flatten): fix behavior of flatten(-1).
+ [ruby-dev:47988] [Bug #9533]
+
+ * test/ruby/test_array.rb: test for above.
+
+Wed Feb 19 18:57:02 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket: Bypass getaddrinfo() if node and serv are numeric.
+ Reporeted by Naotoshi Seo. [ruby-core:60801] [Bug #9525]
+
+ * ext/socket/extconf.rb: Detect struct sockaddr_in6.sin6_len.
+
+ * ext/socket/sockport.h (SET_SIN6_LEN): New macro.
+ (INIT_SOCKADDR_IN6): Ditto.
+
+ * ext/socket/rubysocket.h (struct rb_addrinfo): Add
+ allocated_by_malloc field.
+
+ * ext/socket/raddrinfo.c (numeric_getaddrinfo): New function.
+ (rb_getaddrinfo): Call numeric_getaddrinfo at first.
+ (rb_freeaddrinfo): Free struct addrinfo properly when it is
+ allocated by numeric_getaddrinfo.
+
+Wed Feb 19 18:31:48 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket: Wrap struct addrinfo by struct rb_addrinfo.
+
+Wed Feb 19 17:47:01 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/ipsocket.c (ip_s_getaddress): Don't access freed memory.
+
+Wed Feb 19 11:39:41 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: it must see rb_cv_broken_memmem not rb_cv_func_memmem.
+
+Tue Feb 18 23:18:41 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/socket/test_socket.rb: unix socket is required by test case.
+
+Tue Feb 18 20:48:38 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/socket/test_addrinfo.rb: remove unused variables.
+ * test/socket/test_nonblock.rb: ditto.
+ * test/socket/test_socket.rb: ditto.
+ * test/socket/test_unix.rb: ditto.
+ * test/testunit/test_parallel.rb: ditto.
+ * test/webrick/test_filehandler.rb: ditto.
+ * test/xmlrpc/test_features.rb: ditto.
+ * test/zlib/test_zlib.rb: ditto.
+
+Tue Feb 18 14:27:18 2014 Shota Fukumori <her@sorah.jp>
+
+ * lib/test/unit.rb: Requires minitest < 5.0.0 if Gem is available.
+
+Tue Feb 18 14:24:07 2014 Shota Fukumori <her@sorah.jp>
+
+ * lib/test/unit/test-unit.gemspec: Add minitest < 5.0.0 dependency
+
+ * tool/rbinstall.rb: Add empty implementations for `add_dependency`,
+ `add_runtime_dependency`, `add_development_dependency` for
+ Gem::Specification.
+
+Tue Feb 18 12:06:39 2014 Tanaka Akira <akr@fsij.org>
+
+ * configure.in (FILE_COUNT): Removed. (win32.c defines it in itself.)
+ (FILE_READPTR): Ditto.
+
+Tue Feb 18 09:35:44 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/test/psych/test_string.rb: remove unused variables.
+ * test/test/psych/test_yaml.rb: ditto.
+
+Mon Feb 17 21:31:31 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_gc.rb: ignore warning messages for running with -w
+ option such as chkbuild.
+
+Mon Feb 17 20:00:27 2014 Tanaka Akira <akr@fsij.org>
+
+ * internal.h: Move BDIGIT and related definitions from
+ include/ruby/defines.h.
+
+Mon Feb 17 17:41:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (marshal_dump, marshal_load): do not recycle wrapper
+ objects, to prevent from segfault with continuation.
+ [ruby-dev:47970] [Bug #9523]
+
+Mon Feb 17 15:43:59 2014 Zachary Scott <e@zzak.io>
+
+ * doc/keywords.rdoc: [DOC] Add keywords doc by documenting-ruby/ruby#29
+ https://github.com/documenting-ruby/ruby/pull/29
+
+Mon Feb 17 12:31:31 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (get_envparam_double): fix a warning message.
+
+Mon Feb 17 12:09:52 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: introduce new environment variable
+ "RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR" to control major/minor GC
+ frequency.
+
+ Do full GC when the number of old objects is more than R * N
+ where R is this factor and
+ N is the number of old objects just after last full GC.
+
+ * test/ruby/test_gc.rb: add a test.
+
+Mon Feb 17 11:28:40 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/test_pty.rb: ignore warnings to unused variables.
+
+Mon Feb 17 11:27:36 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/test_find.rb: remove unused variables.
+
+Sun Feb 17 02:12:00 2014 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_initialize): Insert GC guard.
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_global_new): ditto.
+
+Sun Feb 16 15:53:36 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/test_securerandom.rb: File.exists? is deprecated. use File.exist?
+
+Sun Feb 16 15:05:00 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/pathname/test_pathname.rb: File.exists? is deprecated. use File.exist?
+
+Sun Feb 16 15:00:28 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
+
+ * test/net/ftp/test_ftp.rb: remove unused variables.
+ * test/logger/test_logger.rb: ditto.
+
+Sun Feb 16 14:52:46 2014 Eric Wong <e@80x24.org>
+
+ * dir.c (dir_s_glob): RB_GC_GUARD instead of volatile
+
+Sun Feb 16 14:33:52 2014 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/ruby.h (RBIGNUM_SIGN): Defined for compatibility.
+ (RBIGNUM_POSITIVE_P): Ditto.
+ (RBIGNUM_NEGATIVE_P): Ditto.
+
+Sun Feb 16 12:46:47 2014 Eric Wong <e@80x24.org>
+
+ * io.c (rb_f_backquote): trade volatile for manual recycle
+ rb_gc_force_recycle ensures object is visible until recycle
+
+Sun Feb 16 11:55:14 2014 Eric Wong <e@80x24.org>
+
+ * marshal.c (marshal_dump): use rb_gc_force_recycle for GC-safety
+ (marshal_load): ditto
+ [ruby-core:60730] [Bug #7805]
+
+Sun Feb 16 08:11:23 2014 Zachary Scott <e@zzak.io>
+
+ * README.EXT.ja: [DOC] Fix typo by @utenmiki [Fixes GH-534]
+ https://github.com/ruby/ruby/pull/534
+
+Sun Feb 16 07:48:20 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/bigdecimal/bigdecimal.c (BIGNUM_ZERO_P): Unused macro removed.
+
+Sun Feb 16 06:12:23 2014 Tanaka Akira <akr@fsij.org>
+
+ * internal.h: Rename macro names: RBIGNUM_FOO to BIGNUM_FOO.
+ (BIGNUM_EMBED_LEN_NUMBITS): Renamed from RBIGNUM_EMBED_LEN_NUMBITS.
+ (BIGNUM_EMBED_LEN_MAX): Renamed from RBIGNUM_EMBED_LEN_MAX.
+ (BIGNUM_SIGN_BIT): Renamed from RBIGNUM_SIGN_BIT.
+ (BIGNUM_SIGN): Renamed from RBIGNUM_SIGN.
+ (BIGNUM_SET_SIGN): Renamed from RBIGNUM_SET_SIGN.
+ (BIGNUM_POSITIVE_P): Renamed from RBIGNUM_POSITIVE_P.
+ (BIGNUM_NEGATIVE_P): Renamed from RBIGNUM_NEGATIVE_P.
+ (BIGNUM_EMBED_FLAG): Renamed from RBIGNUM_EMBED_FLAG.
+ (BIGNUM_EMBED_LEN_MASK): Renamed from RBIGNUM_EMBED_LEN_MASK.
+ (BIGNUM_EMBED_LEN_SHIFT): Renamed from RBIGNUM_EMBED_LEN_SHIFT.
+ (BIGNUM_LEN): Renamed from RBIGNUM_LEN.
+ (RBIGNUM_DIGITS): Renamed from RBIGNUM_DIGITS.
+ (BIGNUM_LENINT): Renamed from RBIGNUM_LENINT.
+
+ * bignum.c: Follow the above change.
+
+ * gc.c: Ditto.
+
+ * marshal.c: Ditto.
+
+ * math.c: Ditto.
+
+ * numeric.c: Ditto.
+
+ * random.c: Ditto.
+
+ * rational.c: Ditto.
+
+ * sprintf.c: Ditto.
+
+ * ext/-test-/bignum/bigzero.c: Ditto.
+
+ * ext/-test-/bignum/intpack.c: Ditto.
+
+ * ext/bigdecimal/bigdecimal.c: Ditto.
+
+Sat Feb 15 20:48:49 2014 Tanaka Akira <akr@fsij.org>
+
+ * configure.in (FILE_READEND): Don't detect it because it is not used.
+
+Sat Feb 15 13:22:28 2014 Eric Wong <e@80x24.org>
+
+ * probes_helper.h (RUBY_DTRACE_HOOK): correct type for _id
+
+Sat Feb 15 11:47:47 2014 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_cmp): Avoid bignum allocation for comparison
+ between bignum and fixnum.
+
+Sat Feb 15 10:55:12 2014 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * ext/-test-/win32/fd_setsize/depend: fix wrong dependencies.
+ [ruby-dev:47253]
+
+Sat Feb 15 00:38:54 2014 Tanaka Akira <akr@fsij.org>
+
+ * enum.c: Enumerable#{min,min_by,max,max_by} extended to take an
+ optional argument.
+ (nmin_cmp): New function.
+ (nmin_block_cmp): Ditto
+ (nmin_filter): Ditto.
+ (nmin_i): Ditto.
+ (nmin_run): Ditto.
+ (enum_min): Call nmin_run if the optional argument is given.
+ (nmin_max): Ditto.
+ (nmin_min_by): Ditto.
+ (nmin_max_by): Ditto.
+
+ * range.c: Range#{min,max} extended to take an optional argument.
+ (range_min): Call range_first if the optional argument is given.
+ (range_max): Call rb_call_super if the optional argument is given.
+
+ [ruby-core:57111] [Feature #8887]
+
+Sat Feb 15 00:27:46 2014 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/ruby.h,
+ internal.h,
+ ext/-test-/bignum/bigzero.c: Hide a Bignum definition.
+ [ruby-core:42891] [Feature #6083]
+
+Sat Feb 15 00:13:14 2014 Tanaka Akira <akr@fsij.org>
+
+ * include/ruby/intern.h,
+ include/ruby/io.h,
+ include/ruby/ruby.h,
+ include/ruby/win32.h,
+ include/ruby/backward/rubysig.h,
+ bignum.c,
+ gc.c,
+ io.c,
+ process.c,
+ safe.c,
+ struct.c,
+ thread.c,
+ ext/socket/rubysocket.h,
+ ext/-test-/old_thread_select: Remove deprecated definitions
+ [ruby-core:60581] [Feature #9502]
+
+Fri Feb 14 18:38:46 2014 Eric Wong <e@80x24.org>
+
+ * string.c (rb_str_format_m): trade volatile for RB_GC_GUARD
+ RB_GC_GUARD meaning is clear and has better code generation.
+ [ruby-core:60688]
+
+Thu Feb 13 23:30:30 2014 Shugo Maeda <shugo@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_call_method): should check ci->me->flag of
+ a refining method in case the method is private.
+ [ruby-core:60111] [Bug #9452]
+
+ * vm_method.c (make_method_entry_refined): set me->flag of a refined
+ method entry to NOEX_PUBLIC in case the original method is private
+ and it is refined as a public method. The original flag is stored
+ in me->def->body.orig_me, so it's OK to make a refined method
+ entry public. [ruby-core:60111] [Bug #9452]
+
+ * test/ruby/test_refinement.rb: related tests.
+
+Thu Feb 13 18:38:15 2014 Eric Wong <e@80x24.org>
+
+ * re.c (rb_reg_raise): remove volatile
+ Unnecessary since r41597
+
+Thu Feb 13 18:28:51 2014 Eric Wong <e@80x24.org>
+
+ * re.c (rb_reg_regcomp): remove volatile
+ Unnecessary since r13261
+
+Thu Feb 13 16:54:32 2014 Zachary Scott <e@zzak.io>
+
+ * test/ruby/test_array.rb: Ensure flatten! is used for test_flatten
+ Patch by @ksss [Fixes GH-530] https://github.com/ruby/ruby/pull/530
+
+Thu Feb 13 15:43:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (IDSET_ATTRSET_FOR_INTERN): fix off-by-one bug.
+
+ * parse.y (rb_enc_symname_type): junk ID succeeded by '=' is also
+ attrset ID. [ruby-core:60668] [Bug #8756]
+
+Thu Feb 13 11:06:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: check if pthread_setname_np is available.
+
+ * thread_pthread.c: pthread_setname_np is not available on old
+ Darwins. [ruby-core:60524] [Bug #9492]
+
+Thu Feb 13 00:56:59 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * configure.in: revert r44922. I should have used AC_CHECK_FUNCS()
+ to just define a symbol if the function is available.
+
+Thu Feb 13 00:20:58 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * configure.in: use AC_CHECK_FUNC instead of AC_CHECK_FUNCS
+ if available.
+
+Thu Feb 13 00:15:10 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * configure.in: fix to undefine HAVE_MEMMEM correctly if it is broken.
+
+Tue Feb 11 23:54:40 2014 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_cmp): Specialize a comparison to zero.
+
+ * ext/bigdecimal/bigdecimal.c (is_negative): Use rb_big_cmp instead of
+ RBIGNUM_NEGATIVE_P.
+ (BigMath_s_log): Ditto.
+
+Tue Feb 11 22:59:10 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/openssl/ossl_bn.c (ossl_bn_initialize): Use rb_integer_pack.
+ Fix SEGV by OpenSSL::BN.new(1 << (2**34)).
+
+Tue Feb 11 17:00:38 2014 Zachary Scott <e@zzak.io>
+
+ * ext/tk/README.tcltklib: [DOC] Fix typo by @xta [Fixes GH-532]
+
+Sun Feb 9 13:59:29 2014 Tanaka Akira <akr@fsij.org>
+
+ * configure.in: Fix compilation error.
+ https://bugs.ruby-lang.org/issues/8358#note-16
+
+Sun Feb 9 05:20:24 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in (rb_cv_gnu_qsort_r): use compile error "conflicting
+ types for 'qsort_r'" instead of AC_RUN_IFELSE.
+
+Sun Feb 9 04:07:34 2014 Zachary Scott <e@zzak.io>
+
+ * lib/yaml.rb: [DOC] Add links to syck and psych on github [Bug #9501]
+ Based on a patch by Giorgos Tsiftsis
+
+Sun Feb 9 02:13:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (OBJ_TAINTABLE, OBJ_TAINT, OBJ_INFECT),
+ marshal.c (r_entry0): all Numerics never be tainted now.
+ [ruby-core:57346] [Bug #8945]
+
+Sat Feb 8 23:40:35 2014 Vit Ondruch <vondruch@redhat.com>
+
+ * configure.in: add quoting brackets and append wildcard for the
+ rest after target_cpu, to properly detect platform for SSE2
+ instructions. [ruby-core:60576] [Bug #8358]
+
+Sat Feb 8 21:44:07 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * configure.in: check qsort_r(3) and whether it is GNU version.
+ BSD version has different prototype.
+
+ * util.h: use qsort_r() as ruby_qsort() if it is GNU version.
+
+ * util.c: define ruby_qsort() if needed.
+
+Sat Feb 8 16:34:36 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb (Resolv::DNS::Message::MessageDecoder#get_labels):
+ Make it iterative.
+
+Sat Feb 8 15:54:12 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c, gc.h (rb_objspace_marked_object_p): added.
+ This function *ONLY* works just after marking phase,
+ before any sweeping.
+ This function is highly depending current GC implementation
+ and can be removed future version.
+
+Sat Feb 8 15:41:37 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb: Don't set CLOEXEC flag explicitly. (Ruby set it by
+ default.)
+
+Sat Feb 8 15:27:02 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb (Resolv::DNS::Message::MessageDecoder): Raise
+ DecodeError if no data before the limit.
+ Reported by Will Bryant. [ruby-core:60557] [Bug #9498]
+
+Sat Feb 8 15:11:21 2014 Tanaka Akira <akr@fsij.org>
+
+ * io.c (SMALLBUF): Unused macro removed.
+
+Fri Feb 7 23:37:49 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb: Ignore name servers which cause EAFNOSUPPORT on
+ socket creation.
+ Reported by Bjoern Rennhak. [ruby-core:60442] [Bug #9477]
+
+Fri Feb 7 21:58:48 2014 Zachary Scott <e@zzak.io>
+
+ * lib/open-uri.rb: [DOC] use lower case version of core classes, same
+ as commit r44878, based on patch by Jonathan Jackson [Bug #9483]
+
+Fri Feb 7 21:54:53 2014 Zachary Scott <e@zzak.io>
+
+ * ext/ripper/lib/ripper/lexer.rb: [DOC] use lower case version of core
+ classes when referring to return value, since we aren't directly
+ talking about the class. Patch by Jonathan Jackson [Bug #9483]
+
+Fri Feb 7 05:28:38 2014 Eric Wong <e@80x24.org>
+
+ * constant.h: reduce rb_const_entry_t size on 64-bit
+ Patch by Adam Avilla [ruby-core:60542] [Feature #9496]
+
+Thu Feb 6 15:27:46 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (get_envparam_int): correct warning messages.
+
+ * gc.c (get_envparam_double): ditto.
+
+Thu Feb 6 15:17:30 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (get_envparam_int): don't accept a value equals to lowerbound
+ (changed by last commit) because "" or "foo" (not a number) strings
+ are parsed as 0. They should be rejected.
+
+ * gc.c (get_envparam_double): ditto.
+
+Thu Feb 6 09:00:35 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (ruby_gc_set_params): if RUBY_GC_OLDMALLOC_LIMIT is provided,
+ then set objspace->rgengc.oldmalloc_increase_limit.
+ Without this fix, the env variable RUBY_GC_OLDMALLOC_LIMIT
+ does not work.
+
+ * gc.c (get_envparam_int): accept a value equals to lowerbound.
+
+ * gc.c (get_envparam_double): ditto.
+
+Thu Feb 6 08:23:28 2014 Eric Wong <e@80x24.org>
+
+ * ext/thread/thread.c (rb_szqueue_max_set): use correct queue and
+ limit wakeups. [Bug #9343][ruby-core:60517]
+ * test/thread/test_queue.rb (test_sized_queue_assign_max):
+ test for bug
+
+Thu Feb 6 07:18:01 2014 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems 2.2.2. Complete history at:
+
+ http://rubygems.rubyforge.org/rubygems-update/History_txt.html#label-2.2.2+%2F+2014-02-05
+
+ * test/rubygems: ditto.
+
+Wed Feb 5 20:56:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * marshal.c (to_be_skipped_id): ignore anonymous attributes.
+
+ * pack.c (Init_pack): use anonymous ID so that associated objects
+ do not appear in the packed result.
+
+ * parse.y (rb_make_internal_id): return an anonymous ID for
+ internal use.
+
+Wed Feb 5 14:41:56 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vsnprintf.c: remove duplicated def of `UNINITIALIZED_VAR()'.
+
+Wed Feb 5 14:40:16 2014 Koichi Sasada <ko1@atdot.net>
+
+ * ext/objspace/objspace_dump.c (dump_object): use STR_SHARED_P()
+ instead of removed STR_NOCAPA_P() macro.
+
+Wed Feb 5 13:51:33 2014 Koichi Sasada <ko1@atdot.net>
+
+ * internal.h, vm_core.h: move LIKELY/UNLIKELY/UNINITIALIZED_VAR()
+ macros from vm_core.h to internal.h.
+
+ * string.c: remove dependency to "vm_core.h".
+
+ * common.mk: ditto.
+
+Wed Feb 5 13:29:01 2014 Koichi Sasada <ko1@atdot.net>
+
+ * string.c (rb_str_free): use FL_TEST(str, STR_SHARED) directly
+ because str is not embed.
+
+ * string.c (str_replace): remove `FL_SET(str, STR_SHARED)' line
+ because STR_SET_SHARED() set STR_SHARED.
+
+Wed Feb 5 13:18:08 2014 Koichi Sasada <ko1@atdot.net>
+
+ * internal.h: remove macros STR_NOCAPA and STR_NOCAPA_P().
+
+ * string.c (rb_str_resize): remove `STR_SET_NOEMBED(str)' because
+ str_make_independent_expand() set NOEMBED flag.
+
+ * string.c (rb_str_resize): remove `STR_NOCAPA_P(str)' check because
+ `str' is independent (not shared).
+
+Wed Feb 5 12:54:25 2014 Koichi Sasada <ko1@atdot.net>
+
+ * string.c: refactoring, especially about string flags.
+
+ * string.c (STR_UNSET_NOCAPA): removed.
+ Use FL_UNSET() with STR_SHARED.
+
+ * string.c (rb_str_capacity): check STR_SHARED directly
+ because it is not a embed string.
+
+ * string.c (rb_str_modify_expand): ditto.
+
+ * string.c (rb_str_shared_replace): use STR_SET_SHARED().
+
+ * string.c (str_make_independent_expand): remove STR_UNSET_NOCAPA()
+ because `str' is not shared string.
+
+Wed Feb 5 12:11:04 2014 Koichi Sasada <ko1@atdot.net>
+
+ * string.c (RESIZE_CAPA): should not resize shared string.
+
+Wed Feb 5 11:46:42 2014 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_mark_children): STR_ASSOC is no longer available.
+ Reported by @nagachika.
+ http://d.hatena.ne.jp/nagachika/20140204
+
+Wed Feb 5 11:27:22 2014 Koichi Sasada <ko1@atdot.net>
+
+ * string.c (rb_str_new_frozen): refactoring code.
+ * Move code from str_new_frozen_with_klass() (and remove it)
+ * `aux.shared' should not be 0 for STR_SHARED strings.
+
+Wed Feb 5 04:23:41 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych.rb: New release of psych.
+ * ext/psych/psych.gemspec: ditto
+
+Wed Feb 5 04:16:41 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/yaml/emitter.c: merge libyaml 0.1.5
+ * ext/psych/yaml/loader.c: ditto
+ * ext/psych/yaml/parser.c: ditto
+ * ext/psych/yaml/reader.c: ditto
+ * ext/psych/yaml/scanner.c: ditto
+ * ext/psych/yaml/writer.c: ditto
+ * ext/psych/yaml/yaml_private.h: ditto
+
+Tue Feb 4 19:10:29 2014 Koichi Sasada <ko1@atdot.net>
+
+ * string.c: use long allocator names instead of numbered
+ allocator names.
+ * rb_str_new2 -> rb_str_new_cstr
+ * rb_str_new4 -> rb_str_new_frozen
+ * rb_str_new5 -> rb_str_new_with_class
+ * str_new3 -> str_new_shared
+ * str_new4 -> str_new_frozen_with_klass
+
+Tue Feb 4 17:20:03 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (glob_helper): return the filename with actual cases on
+ the filesystem if it is case-insensitive. [ruby-core:42469]
+ [Feature #5994]
+
+Tue Feb 4 16:16:58 2014 Koichi Sasada <ko1@atdot.net>
+
+ * string.c: use STR_SHARED instead of ELTS_SHARED.
+ (same value, but more clear meaning)
+
+Tue Feb 4 16:09:14 2014 Koichi Sasada <ko1@atdot.net>
+
+ * string.c: remove STR_ASSOC related code.
+ By r44804, string objects can not have STR_ASSOC flag.
+
+ * internal.h: ditto.
+
+ * ext/objspace/objspace_dump.c (dump_object): ditto.
+
+Tue Feb 4 14:07:20 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * pack.c (str_associate, str_associated): keep associated objects
+ in an instance variables, instead of in the internal structure.
+
+ * string.c (rb_str_associate, rb_str_associated): deprecate.
+
+Tue Feb 4 12:55:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_modify_expand): enable capacity and disable
+ association with packed objects when setting capa, so that
+ pack("p") string fails to unpack properly after modified.
+
+Tue Feb 4 12:45:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (glob_make_pattern): all alphabets are magic characters on
+ case-insensitive filesystems. [ruby-core:42469] [Feature #5994]
+
+Tue Feb 4 09:47:57 2014 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems 2.2.2 prerelease to check fixes to
+ CI.
+ * test/rubygems: ditto.
+
+Mon Feb 3 12:04:47 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * error.c: [DOC] Exception#cause may return nil. [ci skip]
+
+Sun Feb 2 05:48:42 2014 Eric Wong <e@80x24.org>
+
+ * io.c (rb_io_syswrite): add RB_GC_GUARD
+ [Bug #9472][ruby-core:60407]
+
+Sat Feb 1 15:09:16 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_typedesc2val): add VT_RECORD case.
+
+Sat Feb 1 06:38:51 2014 Zachary Scott <e@zzak.io>
+
+ * lib/drb/drb.rb: [DOC] Add note about start_service for each process
+ Based on a patch by @rosenfeld [Fixes GH-514] [ci skip]
+ https://github.com/ruby/ruby/pull/514
+
+Sat Feb 1 06:30:20 2014 Zachary Scott <e@zzak.io>
+
+ * error.c: [DOC] Document Exception#cause by @jasonrclark [ci skip]
+ [Fixes GH-519] https://github.com/ruby/ruby/pull/519
+
+Sat Feb 1 06:10:49 2014 Zachary Scott <e@zzak.io>
+
+ * lib/securerandom.rb: [DOC] Add note on require for examples
+ Based on a patch by @schneems [Fixes GH-518] [ci skip]
+ https://github.com/ruby/ruby/pull/518
+
+Sat Feb 1 06:04:56 2014 Zachary Scott <e@zzak.io>
+
+ * numeric.c: [DOC] Fix typo in example for #step [ci skip]
+ Patch by @ksss [Fixes GH-522] https://github.com/ruby/ruby/pull/522
+
+Fri Jan 31 17:01:47 2014 Eric Wong <e@80x24.org>
+
+ * ext/socket/init.c (rsock_socket0): split out SOCK_CLOEXEC version
+ * ext/socket/socket.c (rsock_socketpair0): ditto
+ [ruby-core:60377]
+
+Fri Jan 31 03:48:40 2014 Eric Wong <e@80x24.org>
+
+ * benchmark/driver: avoid large alloc in driver process
+ [ruby-core:59869] [Bug #9430]
+
+Thu Jan 30 14:45:49 2014 Shugo Maeda <shugo@ruby-lang.org>
+
+ * configure.in: use $@ instead of $(.TARGET) because .TARGET is not
+ supported by GNU make.
+
+Thu Jan 30 08:26:21 2014 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * ext/fiddle/closure.c: use sizeof(*pcl) for correct sizeof value.
+ [ruby-core:57599] [Bug #8978].
+
+Wed Jan 29 20:08:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (nogvl_copy_stream_sendfile): check socket on other than
+ linux, as sendfile(2) on non-socket fd works only on linux.
+ [Feature #9427]
+
+Wed Jan 29 18:09:48 2014 Eric Wong <e@80x24.org>
+
+ * io.c (nogvl_copy_stream_sendfile): remove socket check
+ [ruby-core:59856][Feature #9427]
+
+Wed Jan 29 04:29:54 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/openssl/ossl_ssl.c: pass read_nonblock options to underlying IO
+ when SSL session has not been started.
+
+ * test/openssl/test_ssl.rb: test for change.
+
+Wed Jan 29 03:49:36 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/fiddle/closure.c: use sizeof(*pcl) for correct sizeof value.
+ [ruby-core:57599] [Bug #8978]. Thanks mame!
+
+Wed Jan 29 03:36:42 2014 Eric Wong <e@80x24.org>
+
+ * doc/contributing.rdoc: allow/encourage other git hosts
+ [ruby-core:59807][misc #9421]
+
+Tue Jan 28 23:36:01 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket: Avoid redundant fcntl/fstat syscalls for cloexec
+ sockets.
+ Patch by Eric Wong. [ruby-core:59429] [Feature #9330]
+
+Tue Jan 28 20:51:07 2014 Tanaka Akira <akr@fsij.org>
+
+ * process.c (READ_FROM_CHILD): Apply the last hunk of
+ 0001-process.c-avoid-EINTR-from-Process.spawn.patch written by
+ Eric Wong in [Bug #8770].
+
+Tue Jan 28 16:31:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread_pthread.c (ruby_init_stack, ruby_stack_overflowed_p):
+ place get_stack above others to get stack boundary information.
+ [ruby-core:60113] [Bug #9454]
+
+Tue Jan 28 15:27:36 2014 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * thread_pthread.c: rlimit is only available on Linux.
+ At least r44712 breaks FreeBSD.
+ [ruby-core:60113] [Bug #9454]
+
+Tue Jan 28 15:17:59 2014 Zachary Scott <e@zzak.io>
+
+ * lib/set.rb: [DOC] Add examples for Set#intersect? and Set#disjoint?
+ Patch by xavier nayrac [Bug #9331] [ci skip]
+
+Tue Jan 28 15:12:22 2014 Zachary Scott <e@zzak.io>
+
+ * ext/zlib/zlib.c (rb_zlib_adler32): [DOC] Add example for adler32
+ Patch by Vajrasky Kok [Bug #9307] [ci skip]
+
+Tue Jan 28 08:56:00 2014 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * compile.c (iseq_build_from_ary_body): Use :blockptr instead of :block
+ as hash key when loading serialized instruction sequences from arrays.
+ [Bug #9455] [ruby-core:60146]
+
+Mon Jan 27 21:52:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread_pthread.c: get current main thread stack size, which may
+ be expanded than allocated size at initialization, by rlimit().
+ [ruby-core:60113] [Bug #9454]
+
+Sat Jan 25 22:17:02 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * README.ja.md, README.md: update the controller address of
+ mailing lists.
+
+Sat Jan 25 14:50:42 2014 Eric Wong <normalperson@yhbt.net>
+
+ * process.c (send_child_error): retry write on EINTR to fix
+ occasional Errno::EINTR from Process.spawn.
+
+ * process.c (recv_child_error): retry read on EINTR to fix
+ occasional Errno::EINTR from Process.spawn.
+
+Sat Jan 25 14:21:06 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_compile_each): result of assignment should be
+ its rhs instead of returned value from a method.
+ [ruby-core:60071] [Bug #9448]
+
+Sat Jan 25 11:16:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (rb_extract_keywords): treat nil keyword_hash same as 0,
+ for the case rb_scan_args returns nil if no keyword hash.
+
+Fri Jan 24 15:13:20 2014 Zachary Scott <e@zzak.io>
+
+ * lib/racc/rdoc/grammar.en.rdoc: [DOC] Correct grammar and typos
+ Patch by Giorgos Tsiftsis [Bug #9429] [ci skip]
+
+Thu Jan 23 20:20:17 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/envutil.rb: try to wait a bit (0.1sec) when ruby process
+ exits by signals because some SEGV tests fail because of not enough
+ error output.
+
+Thu Jan 23 20:06:27 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_settracefunc.rb: check the target thread.
+
+Thu Jan 23 19:59:16 2014 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_settracefunc.rb: check the target thread.
+
+Thu Jan 23 14:26:44 2014 Zachary Scott <e@zzak.io>
+
+ * lib/fileutils.rb: [DOC] Fix typo in options_of() example [Bug #9392]
+ Patch by Giorgos Tsiftsis
+
+Thu Jan 23 13:56:16 2014 Zachary Scott <e@zzak.io>
+
+ * README -> README.md: [DOC] Format README with Markdown [Bug #9255]
+ * README.ja -> README.ja.md: ditto
+
+Wed Jan 22 15:59:39 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/thread/thread.c (Init_thread): ConditionVariable and Queue
+ are not able to copy. [ruby-core:59961] [Bug #9440]
+
+Tue Jan 21 20:14:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread_pthread.c (rb_thread_create_timer_thread): fix for platforms
+ where PTHREAD_STACK_MIN is a dynamic value and not a compile-time
+ constant. [ruby-dev:47911] [Bug #9436]
+
+Tue Jan 21 17:55:09 2014 Zachary Scott <e@zzak.io>
+
+ * lib/uri/common.rb: [DOC] Use static w3.org uri [ci skip]
+ Patch by @ykzts [Fix GH-484] https://github.com/ruby/ruby/pull/484
+
+Tue Jan 21 16:43:22 2014 Zachary Scott <e@zzak.io>
+
+ * enum.c: [DOC] Add simple example of Enumerable#zip [ci skip]
+ Patch by @nruth on documenting-ruby/ruby#22
+ https://github.com/documenting-ruby/ruby/pull/22
+
+Tue Jan 21 16:26:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread_pthread.c (rb_thread_create_timer_thread): expand timer
+ thread stack size to get rid of segfault on FreeBSD/powerpc64.
+ based on the patch by Steve Wills at [ruby-core:59923].
+ [ruby-core:56590] [Bug #8783]
+
+Tue Jan 21 04:31:23 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/option.c: Use "int" for IP_MULTICAST_LOOP and
+ IP_MULTICAST_TTL on Mac OS X and Windows.
+
+Tue Jan 21 00:39:15 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/option.c: Use "byte" as default argument for
+ IP_MULTICAST_LOOP and IP_MULTICAST_TTL socket option to follow
+ the original multicast implementation.
+
+Mon Jan 20 20:20:27 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/option.c: Use preprocessor macros to avoid repeated
+ conditionals.
+
+Mon Jan 20 13:55:03 2014 Zachary Scott <e@zzak.io>
+
+ * lib/rubygems/version.rb: [DOC] Use gender-neutral pronouns [ci skip]
+ * lib/rubygems/security.rb: ditto
+
+Sun Jan 19 06:38:48 2014 Benoit Daloze <eregontp@gmail.com>
+
+ * compar.c (cmp_equal): warn for this release and still rescue
+ standard exceptions for a nicer transition. See #7688.
+ Partly reverts r44502.
+
+ * test/ruby/test_comparable.rb: adapt assertion to match new behavior.
+
+Sun Jan 19 06:27:18 2014 Benoit Daloze <eregontp@gmail.com>
+
+ * test/ruby/test_comparable.rb: specify behavior for the different
+ kind of exceptions rescued (or not) by Comparable#==.
+
+Sat Jan 18 23:12:19 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket: Avoid unnecessary ppoll/select on Linux.
+ Patch by Eric Wong. [ruby-core:57950] [Bug #9039]
+
+Sat Jan 18 22:57:44 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb (Resolv::DNS::Resource::TXT#data): Return concatenated
+ string.
+ Patch by Ryan Brunner. [ruby-core:58220] [Bug #9093]
+
+Sat Jan 18 22:35:15 2014 Tanaka Akira <akr@fsij.org>
+
+ * io.c (rb_update_max_fd): Return immediately if the given fd is small
+ enough.
+
+Sat Jan 18 22:25:53 2014 Tanaka Akira <akr@fsij.org>
+
+ * io.c: Test O_CLOEXEC only once.
+ Patch by Eric Wong. [ruby-core:59419] [Feature #9328]
+
+Sat Jan 18 21:24:49 2014 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/option.c: IP_MULTICAST_LOOP and IP_MULTICAST_TTL socket
+ option takes a byte on OpenBSD.
+ Fixed by Jeremy Evans. [ruby-core:59496] [Bug #9350]
+
+Sat Jan 18 21:19:04 2014 Tanaka Akira <akr@fsij.org>
+
+ * lib/open-uri.rb: Make proxy disabling working again.
+ Fixed by Christophe Philemotte. [ruby-core:59650] [Bug #9385]
+
+Fri Jan 17 20:05:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/delegate.rb (Delegator): keep source information methods
+ which start and end with '__'. [ruby-core:59718] [Bug #9403]
+
+Fri Jan 17 17:58:04 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_mod_s_constants): return its own constants for other
+ than Module itself. [ruby-core:59763] [Bug #9413]
+
+Tue Jan 16 00:17:00 2014 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.gemspec: bigdecimal version 1.2.5.
+
+Wed Jan 15 20:30:31 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * io.c (io_binwrite): use writev(2) to avoid double write if available.
+
+ * configure.in: check writev(2)
+
+Wed Jan 15 14:04:33 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (get_encoding): respect BOM on pseudo encodings.
+ [ruby-dev:47895] [Bug #9415]
+
+Wed Jan 15 14:03:47 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (get_actual_encoding): get actual encoding according to
+ the BOM if exists.
+
+ * string.c (rb_str_inspect): use according encoding, instead of
+ pseudo encodings, UTF-{16,32}. [ruby-core:59757] [Bug #8940]
+
+Tue Jan 14 21:07:22 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * ext/thread/thread.c (rb_szqueue_clear): notify SZQUEUE_WAITERS
+ on SizedQueue#clear. [ruby-core:59462] [Bug #9342]
+
+ * test/thread/test_queue.rb: add test. the patch is from
+ Justin Collins.
+
+Tue Jan 14 15:58:43 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (CLASS_NAME): macro to wrap
+ depending on PRIsVALUE for 1.9. [Backport #9406]
+
+ * ext/bigdecimal/bigdecimal.c (DECIMAL_SIZE_OF_BITS): fallback
+ definition for 2.1 or older. [ruby-core:59750] [Backport #9406]
+
+Tue Jan 14 11:28:44 2014 Yuki Yugui Sonoda <yugui@google.com>
+
+ * vm_exec.c (cfp): Fixes a SEGV issue in r44554.
+ r11 can be broken by subroutine and sometimes causes SEGV at
+ runtime. Use r13 instead.
+
+Tue Jan 14 02:20:00 2014 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_divide): Add an additional
+ digit for the quotient to be compatible with bigdecimal 1.2.1 and
+ the former. [ruby-core:59365] [#9316] [#9305]
+
+ * test/bigdecimal/test_bigdecimal.rb: tests for the above change.
+
+ * ext/bigdecimal/bigdecimal.gemspec: bigdecimal version 1.2.4.
+
+Mon Jan 13 14:55:31 2014 Zachary Scott <e@zzak.io>
+
+ * lib/xmlrpc/client.rb: [DOC] Remove note about SSL package on RAA
+ Since RAA has been deprecated, and the SSL package has been replaced
+ with net/https this statement is entirely false and should be
+ deleted. [Bug #9152]
+
+Mon Jan 13 14:47:07 2014 Zachary Scott <e@zzak.io>
+
+ * lib/net/smtp.rb: [DOC] Remove dead link to RAA by Giorgos Tsiftsis
+ Fixes the following bugs: [Bug #9152] [Bug #9268] [Bug #9394]
+ * lib/open-uri.rb: ditto
+
+Mon Jan 13 14:25:55 2014 Zachary Scott <e@zzak.io>
+
+ * ext/openssl/ossl_pkey_dh.c: Fixed typo by Sandor Szuecs [Bug #9243]
+
+Mon Jan 13 12:03:00 2014 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * ext/thread/thread.c (rb_szqueue_push): check GET_SZQUEUE_WAITERS
+ instead of GET_QUEUE_WAITERS to prevent deadlock. Patch by Eric Wong.
+ [Bug #9302] [ruby-core:59324]
+
+ * test/thread/test_queue.rb: add test
+
+Sun Jan 12 16:41:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * iseq.c (iseq_load): keep type_map to get rid of memory leak.
+ based on a patch by Eric Wong at [ruby-core:59699]. [Bug #9399]
+
+Sun Jan 12 09:21:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/util.h (DECIMAL_SIZE_OF_BITS): a preprocessor
+ constant macro to approximate decimal representation size of n-bits
+ integer.
+
+ * iseq.c (register_label): use DECIMAL_SIZE_OF_BITS for better
+ approximation.
+
+ * ext/bigdecimal/bigdecimal.c (BigMath_s_log): ditto.
+
+ * common.mk (iseq.o), ext/bigdecimal/depend (bigdecimal.o): add
+ dependency to ruby/util.h for DECIMAL_SIZE_OF_BITS.
+
+Fri Jan 10 16:27:20 2014 Yuki Yugui Sonoda <yugui@google.com>
+
+ * vm_exec.c (cfp): Avoid generating invalid binary for
+ NativeClient.
+ r15 on x86_64 is reserved by NativeClient. So r15 to cfp used to
+ generate invalid binary under some combinations of compiler
+ optimization flags.
+
+Fri Jan 10 18:01:41 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_search_super_method): allow bound method from a
+ module, yet another method transplanting.
+
+Fri Jan 10 13:34:04 2014 Aman Gupta <ruby@tmm1.net>
+
+ * insns.def (opt_aref_with): new instruction to optimize Hash#[],
+ removing any allocation overhead when used with a string literal
+ key. Patch by normalperson (Eric Wong). [ruby-core:59640] [Bug #9382]
+ * insns.def (opt_aset_with): new instruction to optimize Hash#[]=
+ * compile.c (iseq_compile_each): compiler shortcuts for new
+ instructions
+ * hash.c (static VALUE rb_hash_compare_by_id_p): fix documentation for
+ Hash#compare_by_identity to reflect frozen string sharing
+ * test/ruby/test_hash.rb (class TestHash): test for new behavior
+
+Fri Jan 10 06:23:21 2014 Benoit Daloze <eregontp@gmail.com>
+
+ * range.c (Range#size): [DOC] improve description and add examples.
+ Patch by @skade. [Fixes GH-501]
+
+Fri Jan 10 00:47:52 2014 Josef Stribny <strzibny@gmail.com>
+
+ * ext/tk/extconf.rb: fix to pass arrays instead of strings to
+ libpathflag. patch at [ruby-core:59665]. [Bug #9386]
+
+Thu Jan 9 20:49:22 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: -mstackrealign is necessary for -msse2 working.
+ [ruby-core:54716] [Bug #8349]
+
+ * configure.in: use SSE2 instructions to drop unexpected precisions on
+ other than mingw. [ruby-core:59472] [Bug #8358]
+
+Thu Jan 9 20:31:10 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * hash.c (rb_objid_hash): should return `long'. brushup r44534.
+
+ * object.c (rb_obj_hash): follow above change.
+
+Thu Jan 9 19:12:37 2014 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (rb_vm_pop_cfunc_frame): added. It cares c_return event.
+ The patch base by drkaes (Stefan Kaes).
+ [Bug #9321]
+
+ * variable.c (rb_mod_const_missing): use rb_vm_pop_cfunc_frame()
+ instead of rb_frame_pop().
+
+ * vm_eval.c (raise_method_missing): ditto.
+
+ * vm_eval.c (rb_iterate): ditto.
+
+ * internal.h (rb_vm_pop_cfunc_frame): add decl.
+
+ * test/ruby/test_settracefunc.rb: add tests.
+ provided by drkaes (Stefan Kaes).
+
+ * vm.c, eval.c, include/ruby/intern.h (rb_frame_pop):
+ move definition of rb_frame_pop() and deprecate it.
+ It doesn't care about `return' events.
+
+Thu Jan 9 17:40:28 2014 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * hash.c (rb_any_hash): should treat the return value of rb_objid_hash()
+ as `long', because ruby assumes the hash value of the object id of
+ an object is `long'.
+ this fixes test failures on mswin64 introduced at r44525.
+
+Thu Jan 9 09:55:20 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb: dumping strings with
+ quotes should not have changed. [ruby-core:59316] [Bug #9300]
+
+ * ext/psych/lib/psych.rb: fixed missing require.
+
+ * test/psych/test_string.rb: test
+
+Thu Jan 9 09:51:00 2014 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * ext/psych/lib/psych/visitors/to_ruby.rb: anonymous structs
+ should be able to roundtrip. Thanks @splattael!
+
+ * test/psych/test_object_references.rb: test for change
+
+Wed Jan 8 22:53:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_search_super_method): when super called in a
+ bound UnboundMethod generated from a module, no superclass is
+ found since the current defined class is the module, then call
+ method_missing in that case. [ruby-core:59619] [Bug #9377]
+
+Wed Jan 8 15:55:21 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_objid_hash): return hash value from object ID with a
+ salt, extract from rb_any_hash().
+
+ * object.c (rb_obj_hash): return same value as rb_any_hash().
+ fix r44125. [ruby-core:59638] [Bug #9381]
+
+Wed Jan 8 13:12:41 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/timeout.rb (Timeout::ExitException.catch): pass arguments
+ for new instance.
+
+ * lib/timeout.rb (Timeout::ExitException#exception): fallback to
+ Timeout::Error if couldn't throw. [ruby-dev:47872] [Bug #9380]
+
+ * lib/timeout.rb (Timeout#timeout): initialize ExitException with
+ message for the fallback case.
+
+Tue Jan 7 12:43:06 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/timeout.rb (Timeout#timeout): should not rescue ordinarily
+ raised ExitException, which should not be thrown.
+
+ * lib/timeout.rb (Timeout::ExitException.catch): set @thread only if
+ it ought to be caught.
+
+ * lib/timeout.rb (Timeout#timeout): when a custom exception is given,
+ no instance is needed to be caught, so defer creating new instance
+ until it is raised. [ruby-core:59511] [Bug #9354]
+
+Tue Jan 7 10:16:02 2014 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems: Update to RubyGems master 21e409d / RubyGems 2.2.1.
+
+ See http://rubygems.rubyforge.org/rubygems-update/History_txt.html
+ for a list of bug fixes.
+
+ * test/rubygems: ditto.
+
+Tue Jan 7 10:10:46 2014 Eric Wong <e@80x24.org>
+
+ * ext/json/generator/depend: add build dependencies for json extension
+ [Bug #9374] [ruby-core:59609]
+ * ext/json/parser/depend: ditto
+
+Tue Jan 7 04:35:46 2014 Aman Gupta <ruby@tmm1.net>
+
+ * array.c (ary_add_hash): Fix consistency issue between Array#uniq and
+ Array#uniq! [Bug #9340] [ruby-core:59457]
+ * test/ruby/test_array.rb (class TestArray): regression test for above.
+
+Mon Jan 6 21:28:48 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * .gitignore: ignore *-fake.rb generated even when CROSS_COMPILING = no
+ since r42862.
+
+Sun Jan 5 20:14:14 2014 Benoit Daloze <eregontp@gmail.com>
+
+ * compar.c (cmp_equal): remove error hiding in Comparable#==.
+ Comparable#== no longer rescues exceptions silently.
+ This was the cause of quite a couple bugs. See #7688. [EXPERIMENTAL]
+
+ * test/ruby/test_comparable.rb: adapt assertion to match new behavior.
+
+ * lib/rdoc/method_attr.rb: fix bugs discovered by this change.
+
+ * test/rdoc/test_rdoc_normal_class.rb: fix bugs in tests.
+
+Sat Jan 4 22:44:00 2014 Charlie Somerville <charliesome@ruby-lang.org>
+
+ * struct.c (rb_struct_set): return assigned value from setter method
+ rather than struct object. [Bug #9353] [ruby-core:59509]
+
+ * test/ruby/test_struct.rb (test_setter_method_returns_value): add test
+
+Sat Jan 4 21:44:31 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * test/ruby/test_gc.rb (TestGc#test_latest_gc_info): use
+ GC.stat(:key) instead of GC.stat.
+
+Sat Jan 4 19:15:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/socket.c (rsock_syserr_fail_host_port): use format flags,
+ '+' to inspect, ' ' to quote unprintables.
+
+ * ext/socket/socket.c (rsock_syserr_fail_path): ditto.
+
+ * ext/socket/socket.c (rsock_syserr_fail_raddrinfo): ditto.
+
+ * ext/socket/socket.c (rsock_syserr_fail_host_port): add errno
+ argument version and use rb_syserr_fail_str() instead of
+ rb_sys_fail_str() with restoring errno.
+
+ * ext/socket/socket.c (rsock_syserr_fail_path): ditto, and
+ rb_syserr_fail().
+
+ * ext/socket/socket.c (rsock_sys_fail_sockaddr): ditto, use
+ rsock_syserr_fail_raddrinfo().
+
+ * ext/socket/socket.c (rsock_sys_fail_raddrinfo): ditto.
+
+ * ext/socket/socket.c (setup_domain_and_type): ditto.
+
+Sat Jan 4 17:18:58 2014 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * vm.c (RubyVM::OPTS): get rid of a garbage character.
+
+Sat Jan 4 10:17:54 2014 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rinda/ring.rb (Rinda::RingFinger#make_socket): Use
+ ipv4_multicast_ttl option for portability.
+
+Sat Jan 4 10:15:47 2014 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rinda/ring.rb (Rinda::RingFinger#make_socket): Use
+ ipv4_multicast_loop option for portability. Patch by Jeremy Evans.
+ [ruby-trunk - Bug #9351]
+
+Fri Jan 3 19:09:00 2014 Eric Wong <normalperson@yhbt.net>
+
+ * ext/socket/socket.c (rsock_sys_fail_host_port): save and restore errno
+ before calling rb_sys_fail_str to prevent [BUG] errno == 0.
+ Patch by Eric Wong. [ruby-core:59498] [Bug #9352]
+
+ * ext/socket/socket.c (rsock_sys_fail_path): ditto
+ * ext/socket/socket.c (rsock_sys_fail_sockaddr): ditto
+ * ext/socket/socket.c (rsock_sys_fail_raddrinfo): ditto
+ * ext/socket/socket.c (rsock_sys_fail_raddrinfo_or_sockaddr): ditto
+
+Fri Jan 3 10:43:57 2014 Aman Gupta <ruby@tmm1.net>
+
+ * test/net/imap/cacert.pem: generate new CA cert, since the last one
+ expired. [Bug #9341] [ruby-core:59459]
+ * test/net/imap/server.crt: new server cert signed with updated CA.
+ * test/net/imap/Makefile: add `make regen_certs` to automate this
+ process.
+
+Fri Jan 3 00:09:54 2014 Benoit Daloze <eregontp@gmail.com>
+
+ * ext/bigdecimal: update class method call style from :: to .
+ in documentation and usage.
+
+ * ext/bigdecimal/lib/bigdecimal/math.rb: [DOC] fix examples values.
+ Computations were made using ruby 2.0.0p247 to ensure
+ no effect of the recent BigDecimal bug.
+
+ * ext/bigdecimal/sample/nlsolve.rb: fix indent.
+
+Thu Jan 2 16:07:21 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * io.c (io_fwrite): freeze converted str.
+
+Thu Jan 2 04:15:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_longjmp): remove an extra modifier from the forward
+ declaration to match the actual definition. [ruby-core:59451]
+ [Bug #9338]
+
+Thu Jan 2 01:23:30 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * vm_eval.c (method_missing): use ALLOCV_N() instead of
+ ALLOCA_N() and rb_ary_tmp_new().
+
+Thu Jan 2 00:53:16 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * array.c (rb_ary_zip): use ALLOCV_N() instead of ALLOCA_N().
+
+Thu Jan 2 00:04:29 2014 Masaki Matsushita <glass.saga@gmail.com>
+
+ * hash.c (rb_hash_keys): make rb_hash_keys() static.
+ it is no longer used from array.c since r43969.
+ the patch is from normalperson (Eric Wong).
+ [ruby-core:59449] [Feature #9336]
+
+ * internal.h: remove definition of rb_hash_keys().
+
+Wed Jan 1 18:19:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: reset LDFLAGS and DLDFLAGS for opt-dir again after
+ LIBPATHFLAG and RPATHFLAG are set. [ruby-dev:47868] [Bug #9317]
+
+Wed Jan 1 11:12:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: use SSE2 instructions for drop unexpected
+ precisions. [ruby-core:54738] [Bug #8358]
+
+Tue Dec 31 23:49:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (rb_f_raise): add cause: optional keyword argument.
+ [ruby-core:58610] [Feature #8257] [EXPERIMENTAL]
+
+Tue Dec 31 21:44:17 2013 Akio Tajima <artonx@yahoo.co.jp>
+
+ * win32/Makefile.sub: remove HAVE_FSEEKO because fseeko removed from win32/win32.c
+ Fixed [Bug #9333].
+
+Tue Dec 31 21:02:27 2013 Masaki Matsushita <glass.saga@gmail.com>
+
+ * io.c (io_fwrite): allocate frozen str only when str is not converted.
+
+Tue Dec 31 15:44:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (RbConfig): expand RUBY_SO_NAME for extensions
+ backward compatibility. [ruby-core:59426] [Bug #9329]
+
+Mon Dec 30 23:33:07 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
+
+ * variable.c: [DOC] adding extra example in docs.
+ patched by Steve Klabnik. [Bug #9210]
+
+Mon Dec 30 18:34:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * encoding.c (must_encindex, rb_enc_from_index, rb_obj_encoding): mask
+ encoding index and ignore dummy flags. [ruby-core:59354] [Bug #9314]
+
+Mon Dec 30 16:11:52 2013 WATANABE Hirofumi <eban@ruby-lang.org>
+
+ * tool/make-snapshot: needs CXXFLAGS. [ruby-core:59393][Bug #9320]
+
+Sun Dec 29 18:36:54 2013 Shota Fukumori <her@sorah.jp>
+
+ * lib/mkmf.rb (configuration): Make CXXFLAGS customizable.
+ Patch by Kohei Suzuki (eagletmt). [Fixes GH-492]
+
+Sun Dec 29 12:11:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (mnew_from_me): keep iclass as-is, to make inheritance
+ chain consistent. [ruby-core:59358] [Bug #9315]
+
+ * proc.c (method_owner): return the original defined_class from
+ prepended iclass, instead.
+
+Sun Dec 29 08:47:24 2013 Lucas Allan Amorim <lucas.allan@gmail.com>
+
+ * test/ruby/test_sprintf.rb (test_hash): Added tests for sprintf
+ with a hash as parameter. [Fixes GH-491]
+
+Sun Dec 29 07:27:51 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * compar.c (cmp_eq_recursive): Fix the return value, the value for
+ failed #<=> should be nil. It was raising a NoMethodError for
+ the test case TestComparable#test_no_cmp (undefined method `>'
+ for false:FalseClass). Yet one more reason for #7688.
+
+Sat Dec 28 22:21:59 2013 Benoit Daloze <eregontp@gmail.com>
+
+ * object.c (Kernel#<=>) surround Comparable operators with <code> tags.
+ The #== method was hidden in ri/rdoc's output and was highlighting
+ the line instead.
+
+Sat Dec 28 17:24:00 2013 DV Suresh <e@dvsuresh.me>
+
+ * benchmark/bm_so_meteor_contest.rb: [DOC] Fix a few typos
+ * ext/fiddle/lib/fiddle/import.rb: ditto
+ * ext/psych/lib/psych.rb: ditto
+ * ext/psych/lib/psych/nodes/sequence.rb: ditto
+ * ext/tk/lib/multi-tk.rb: ditto
+ * ext/tk/lib/tcltk.rb: ditto
+
+Sat Dec 28 00:42:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (local_push_gen, local_pop_gen): save cmdarg_stack to
+ isolate command argument state from outer scope.
+ [ruby-core:59342] [Bug #9308]
+
+Fri Dec 27 13:25:03 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/{setup.mak,Makefile.sub}: update fake.rb like
+ template/fake.rb.in.
+
+Thu Dec 26 16:10:41 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/Makefile.sub (fake.rb): should depend on version.h because
+ if RUBY_VERSION is updated, fake.rb need to say the new version
+ to avoid install error in rbconfig.rb.
+
+Thu Dec 26 14:25:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (HASH_REJECT_COPY_EXTRA_STATES): turn off the old
+ behavior, copying extra states by accident.
+
+Thu Dec 26 10:49:14 2013 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * version.h (RUBY_VERSION): 2.2.0 development has started.
+
+Thu Dec 26 10:27:53 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * tool/merger.rb (tag): support 2.1.1 semi-automatic tagging and 2.2.0
+ explicit tagging.
+
+Thu Dec 26 06:35:25 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * proc.c: Having any mandatory keyword argument increases min arity
+ [#9299]
+
+Thu Dec 26 06:27:08 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * proc.c: Having optional keyword arguments makes maximum arity +1,
+ not unlimited [#8072]
+
+Thu Dec 26 01:09:57 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * tool/release.sh: make symbolic links.
+
+Thu Dec 26 00:45:33 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * tool/make-snapshot: support new version scheme.
+
+Wed Dec 25 22:44:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_set_arguments): set arg_keyword_check from
+ nd_cflag, which is set by parser. internal ID is used for
+ unnamed keyword rest argument, which should be separated from no
+ keyword check.
+
+ * iseq.c (rb_iseq_parameters): if no keyword check, keyword rest is
+ present.
+
+ * parse.y (new_args_tail_gen): set keywords check to nd_cflag, which
+ equals to that keyword rest is not present.
+
+Wed Dec 25 22:32:19 2013 Zachary Scott <e@zzak.io>
+
+ * lib/abbrev.rb: [DOC] rdoc format patch by Giorgos Tsiftsis [Bug #9146]
+
+Wed Dec 25 20:30:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * iseq.c (rb_iseq_parameters): push argument type symbol only for
+ unnamed rest keywords argument.
+
+Wed Dec 25 20:28:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (rb_iseq_min_max_arity): maximum argument is unlimited if
+ having rest keywords argument. [ruby-core:53298] [Bug #8072]
+
+Wed Dec 25 18:29:22 2013 Koichi Sasada <ko1@atdot.net>
+
+ * vm_insnhelper.c (argument_error): insert dummy frame to make
+ a backtrace object intead of modify backtrace string array.
+ [Bug #9295]
+
+ * test/ruby/test_backtrace.rb: add a test for this patch.
+ fix test to compare a result of Exception#backtrace with
+ a result of Exception#backtrace_locations.
+
+Wed Dec 25 13:00:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: let mingw do something black-magic, and check if
+ _gmtime64_s() is available actually.
+
+ * win32/win32.c (gmtime_s, localtime_s): use _gmtime64_s() and
+ _localtime64_s() if available, not depending on very confusing
+ mingw variants macros. based on the patch by phasis68 (Heesob
+ Park) at [ruby-core:58764]. [ruby-core:58391] [Bug #9119]
+
+Wed Dec 25 12:33:41 2013 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * sample/trick2013/: added the award-winning entries of TRICK 2013.
+ See https://github.com/tric/trick2013 for the contest outline.
+ (Matz has approved the attachment.)
+
+Wed Dec 25 10:42:02 2013 Yamashita Yuu <yamashita@geishatokyo.com>
+
+ * ext/openssl/ossl_ssl.c (Init_ossl_ssl): Declare a constant
+ `OP_MSIE_SSLV2_RSA_PADDING` only if the macro is defined. The
+ `SSL_OP_MSIE_SSLV2_RSA_PADDING` has been removed from latest
+ snapshot of OpenSSL 1.0.1. [Fixes GH-488]
+
+Wed Dec 25 01:03:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (bind_local_variables): allowing binding to list its
+ local variables. patch by Jack Danger Canty <jackdanger AT
+ squareup.com> at [ruby-core:56543]. [Feature #8773]
+
+Tue Dec 24 23:20:38 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/fileutils/fileasserts.rb (assert_ownership_user): new
+ assertion for user ownership.
+
+ * test/fileutils/test_fileutils.rb (test_chown_error),
+ (test_chown_without_permission, test_chown_with_root):
+ based on the patch by vajrasky (Vajrasky Kok) at
+ [ruby-core:59298]. [Feature #9292]
+
+Tue Dec 24 16:28:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (rb_mod_define_method): consider visibility only if self
+ in the caller is same as the receiver, otherwise make public as
+ well as old behavior. [ruby-core:57747] [Bug #9005]
+ [ruby-core:58497] [Bug #9141]
+
+ * vm.c (rb_vm_cref_in_context): return ruby level cref if self is
+ same.
+
+Tue Dec 24 14:13:14 2013 Koichi Sasada <ko1@atdot.net>
+
+ * README.EXT: add a refer to URL.
+
+Tue Dec 24 13:48:45 2013 Koichi Sasada <ko1@atdot.net>
+
+ * README.EXT: add a document about RGenGC.
+ Reviewed by havenwood.
+ [misc #8962]
+
+ * README.EXT.ja: ditto.
+
+Tue Dec 24 12:11:43 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/ruby.h (RARRAY_ASET): try to avoid compiler warning.
+ [Bug #9287]
+
+Tue Dec 24 05:04:56 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/fileutils/test_fileutils.rb (setup): should not call
+ Process.groups for Windows. get rid of many errors introduced by
+ r44364.
+
+Mon Dec 23 18:37:16 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/fileutils/fileasserts.rb (assert_ownership_group): new
+ assertion for group ownership.
+
+ * test/fileutils/test_fileutils.rb (test_chown{,_verbose,_noop}):
+ based on the patch by vajrasky (Vajrasky Kok) at
+ [ruby-core:59281]. [Feature #9286]
+
+Mon Dec 23 15:53:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (HAS_EXTRA_STATES): warn extra states only when something
+ differ. [ruby-core:59254] [Bug #9275]
+
+Mon Dec 23 12:42:13 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * array.c: Have to_h raise on elements that are not key-value pairs
+ [#9239]
+
+ * enum.c: ditto
+
+Mon Dec 23 05:01:55 2013 Zachary Scott <e@zzak.io>
+
+ * doc/syntax/methods.rdoc: [DOC] Added example for underscore
+ conventions in method names. Also added doc to clarify encoding
+ character set support for Ruby programs and elaborated on defining
+ predicate and bang methods. Based on a patch by @gaurish
+ [Fixes GH-477] https://github.com/ruby/ruby/pull/477
+
+Mon Dec 23 03:18:09 2013 Zachary Scott <e@zzak.io>
+
+ * doc/ChangeLog-1.9.3: [DOC] Fix typos by @dvsuresh
+ [Fixes GH-485] https://github.com/ruby/ruby/pull/485
+ * ext/openssl/ossl_config.c: ditto
+ * lib/rss/utils.rb, lib/time.rb: ditto
+ * test/ruby/envutil.rb: ditto
+
+Sun Dec 22 23:56:56 2013 Zachary Scott <e@zzak.io>
+
+ * lib/{rake,rdoc,rss}/*, test/rexml/test_listener.rb: [DOC] Fix typos
+ by @dvsuresh [Fixes GH-486] https://github.com/ruby/ruby/pull/486
+
+Sun Dec 22 11:08:47 2013 Eric Hodel <drbrain@segment7.net>
+
+ * test/rubygems/test_gem_ext_builder.rb: Fix warning due to ambiguous
+ expression.
+
+Sun Dec 22 11:05:53 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems/commands/install_command.rb: Restore gem install
+ --ignore-dependencies for remote gems
+ * test/rubygems/test_gem_commands_install_command.rb: Test for the
+ above.
+
+Sun Dec 22 10:23:40 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rdoc.rb: Set RDoc to release version.
+
+Sun Dec 22 10:19:07 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems.rb: Set RubyGems to release version.
+
+Sun Dec 22 10:16:08 2013 Eric Hodel <drbrain@segment7.net>
+
+ * lib/rubygems.rb (module Gem): Fix comment for
+ Gem::load_path_insert_index.
+
+Sun Dec 22 04:07:55 2013 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (ruby_gc_set_params): don't show obsolete warnings for
+ RUBY_FREE_MIN/RUBY_HEAP_MIN_SLOTS if
+ RUBY_GC_HEAP_FREE_SLOTS/RUBY_GC_HEAP_INIT_SLOTS are given.
+ [Bug #9276]
+
+Sat Dec 21 13:00:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c: remove unnecessary the source path from EEXIST error
+ messages and show the destination path only. [ruby-core:59202]
+ [Feature #9263]
+
+Sat Dec 21 12:37:19 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/resolv.rb (Resolv::Hosts#lazy_initialize): should not
+ consider encodings in hosts file. [ruby-core:59239] [Bug #9273]
+
+ * lib/resolv.rb (Resolv::Config.parse_resolv_conf): ditto.
+
+Sat Dec 21 05:43:27 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * tool/make-snapshot: replace RUBY_PATCHLEVEL_STR in version.h to
+ show users that this ruby is a preview/rc version.
+
+Sat Dec 21 05:03:49 2013 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/Makefile.sub (fake.rb): fixed wrong RUBY_PLATFORM, to correctly
+ install win32.h.
+ [ruby-core:58801][Bug #9199] reported by arton.
+
+For the changes before 2.1.0, see doc/ChangeLog-2.1.0
+For the changes before 2.0.0, see doc/ChangeLog-2.0.0
+For the changes before 1.9.3, see doc/ChangeLog-1.9.3
+For the changes before 1.8.0, see doc/ChangeLog-1.8.0
+
+Local variables:
+coding: us-ascii
+add-log-time-format: (lambda ()
+ (let* ((time (current-time))
+ (system-time-locale "C")
+ (diff (+ (cadr time) 32400))
+ (lo (% diff 65536))
+ (hi (+ (car time) (/ diff 65536))))
+ (format-time-string "%a %b %e %H:%M:%S %Y" (list hi lo) t)))
+indent-tabs-mode: t
+tab-width: 8
+change-log-indent-text: 2
+end:
+vim: tabstop=8 shiftwidth=2
diff --git a/doc/ChangeLog/ChangeLog-2.3.0 b/doc/ChangeLog-2.3.0
index 94996cffd0..94996cffd0 100644
--- a/doc/ChangeLog/ChangeLog-2.3.0
+++ b/doc/ChangeLog-2.3.0
diff --git a/doc/ChangeLog-2.4.0 b/doc/ChangeLog-2.4.0
new file mode 100644
index 0000000000..a297a579d1
--- /dev/null
+++ b/doc/ChangeLog-2.4.0
@@ -0,0 +1,9492 @@
+Mon Nov 7 00:32:45 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/ruby/test_optimization.rb (test_tailcall_interrupted_by_sigint):
+ ignore on Windows because we cannot handle signaled status of child
+ ruby process on this platform.
+
+Sun Nov 6 23:36:07 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * test/ruby/test_optimization.rb (test_tailcall_interrupted_by_sigint):
+ send SIGKILL if the child process doesn't die within 1 second.
+
+Sun Nov 6 21:54:28 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/vcs.rb (export_changelog): generate ChangeLog file from
+ vcs's log. [Feature #12283]
+
+ * tool/make-snapshot (package): overwrite ChangeLog by generated
+ ChangeLog.
+
+Sun Nov 6 21:36:33 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * NEWS: Added entry for RDoc 5.
+
+Sun Nov 6 21:35:37 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * NEWS: ordered entries and adjust styles.
+
+Sun Nov 6 18:23:31 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * NEWS: Added entry for [Feature #12160][ruby-core:74239]
+
+Sun Nov 6 18:18:25 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * NEWS: Added entry for r56624.
+
+Sun Nov 6 15:53:03 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * configure.in (-Wno-maybe-uninitialized): gcc 6 also shows the same
+ warnings as described in r49410.
+
+Sun Nov 6 14:42:50 2016 takkanm <takkanm@gmail.com>
+
+ * eval.c (rb_mod_include, rb_mod_prepend): check if arguments are
+ given, as well as Kernel#extend. [ruby-dev:49854] [Bug #12887]
+ [Fix GH-1470]
+
+Sun Nov 6 11:59:05 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * test/rinda/test_rinda.rb (test_make_socket_ipv6_multicast,
+ test_make_socket_ipv6_multicast_hops): skip if IPv6 multicast
+ address is not available.
+
+Sun Nov 6 11:53:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/irb.rb (Binding#irb): new method like Binding#pry.
+
+Sun Nov 6 11:48:55 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * test/net/smtp/test_smtp.rb (test_tls_connect, test_tls_connect):
+ use Socket.tcp_server_sockets in case localhost is resolved to ::1.
+
+Sun Nov 6 11:49:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/irb.rb (IRB::Irb#run): split from IRB.start.
+
+Sun Nov 6 11:45:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/e2mmap.rb (E2MM.def_exception): remove old definition if
+ exists so that works multiple times.
+
+Sun Nov 6 10:03:00 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * test/ruby/test_optimization.rb (test_tailcall_interrupted_by_sigint):
+ don't use sleep to run faster.
+
+Sun Nov 6 09:58:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (rb_exec_fillarg): honor the given path environment
+ variable. [ruby-core:53103] [Bug #8004]
+
+Sun Nov 6 01:52:31 2016 Akira Matsuda <ronnie@dio.jp>
+
+ * lib/erb.rb: Alias regist_scanner to register_scanner
+
+Sun Nov 6 01:39:36 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * compile.c (tailcallable_p): disable tail call optimization for
+ toplevel, eval, and load to avoid SEGV when interrupted by SIGINT.
+ [ruby-core:76327] [Bug #12576]
+
+Sun Nov 6 01:28:41 2016 Koichi Sasada <ko1@atdot.net>
+
+ * vm_insnhelper.h: rename REG_(CFP|PC|SP|EP) to VM_REG_....
+ [Bug #12527]
+
+ * vm_exec.c: ditto.
+
+Sun Nov 6 00:25:11 2016 Sho Hashimoto <sho.hsmt@gmail.com>
+
+ * enumerator.c (InitVM_Enumerator): Enumerator::Lazy#chunk_while
+ defined. [Fix GH-1186]
+ https://github.com/ruby/ruby/pull/1186
+
+Sun Nov 6 00:22:51 2016 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * vm_eval.c (vm_call0_cfunc_with_frame): pass method id to
+ dtrace hook. follow up r56592.
+
+Sun Nov 6 00:06:38 2016 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb (Resolv::LOC::Coord.create): fixed.
+ [ruby-core:72567] [Bug #11912] fixed by Eric Wong and Kazuhiro
+ NISHIYAMA.
+
+Sun Nov 6 00:03:09 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in (-Wimplicit-fallthrough): gcc7 introduces case
+ fall through warnings but it is too noisy.
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=7652
+
+Sat Nov 5 23:58:32 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * numeric.c (rb_int_round): cast to SIGNED_VALUE to suppress
+ warnings by -Wsign-compare.
+
+Sat Nov 5 23:48:27 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * file.c (rb_home_dir_of): convert given username into filesystem
+ encoding. [ruby-core:76682] [Bug #12652]
+ patched by Davis Mosans
+
+Sat Nov 5 23:46:03 2016 Tanaka Akira <akr@fsij.org>
+
+ * time.c (vtm_add_offset): Fix yday on last day of year.
+ [ruby-core:72878] [Bug #11994] Fixed by Andrew White.
+
+Sat Nov 5 23:30:41 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/http.rb (Net::HTTP.post): new convenience method to send
+ a POST request. [ruby-core:75484] [Feature #12375]
+
+Sat Nov 5 23:03:54 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/net/http.rb (transport_request): other than HTTPContinue
+ in 1xx (HTTPInformation) also needs to continue. [Bug #12890]
+
+Sat Nov 5 22:51:06 2016 Tanaka Akira <akr@fsij.org>
+
+ * lib/time.rb (make_time): "now" argument as nil works again.
+ This is broken since Ruby 2.2.
+ Mathieu Jobin pointed a problem.
+ https://github.com/ruby/ruby/commit/e4b05d91eb0d48fd172abf015c493bb42d755d07#commitcomment-17421387
+
+Sat Nov 5 22:50:13 2016 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/ipaddr.rb (IPAddr#==): If coercion fails, return false
+ instead of passing through the exception. [ruby-core:77451]
+ [Bug #12799]
+
+ * lib/ipaddr.rb (IPAddr#<=>): If coercion fails, return nil
+ instead of passing through the exception. [ruby-core:77451]
+ [Bug #12799]
+
+Sat Nov 5 22:11:33 2016 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * vm_trace.c (tracepoint_attr_callee_id, rb_tracearg_callee_id):
+ add TracePoint#callee_id. [ruby-core:77241] [Feature #12747]
+
+ * cont.c, eval.c, gc.c, include/ruby/intern.h, insns.def, thread.c,
+ vm.c, vm_backtrace.c, vm_core.h, vm_eval.c, vm_insnhelper.c, vm_trace.c: ditto.
+
+ * test/ruby/test_settracefunc.rb: tests for above.
+
+Sat Nov 5 22:09:48 2016 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * eval.c, method.h, proc.c, vm.c, vm_eval.c, vm_insnhelper.c, vm_method.c:
+ TracePoint#method_id should return method_id, not callee_id.
+ [ruby-core:77241] [Feature #12747]
+
+ * test/ruby/test_settracefunc.rb: change accordingly.
+
+Sat Nov 5 18:49:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (flo_round, int_round): support round-to-nearest-even
+ semantics of IEEE 754 to match sprintf behavior, and add `half:`
+ optional keyword argument for the old behavior.
+ [ruby-core:76273] [Bug #12548]
+
+Sat Nov 5 18:17:54 2016 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/set.rb (Set#compare_by_identity, Set#compare_by_identity?):
+ New methods. [Feature #12210]
+
+Sat Nov 5 18:17:08 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rdoc/*, test/rdoc/*: Update rdoc-5.0.0
+ Release note: https://github.com/rdoc/rdoc/blob/b825775647f62c5b525e9780a28ff2fbb1d5bf6f/History.rdoc#500--2016-11-05
+
+Sat Nov 5 17:29:06 2016 Tanaka Akira <akr@fsij.org>
+
+ * lib/resolv.rb (Resolv::DNS#extract_resources): Use each_resource
+ instead of each_answer.
+ [ruby-core:75461] [Bug #12372] reported by Rafael Fernandez Lopez.
+
+Sat Nov 5 17:18:24 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/-test-/file/fs.c (get_atime_p): Updating of file access times
+ is enabled or not.
+
+Sat Nov 5 16:28:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (extract_getline_opts): extract chomp option.
+ [Feature #12553]
+
+Sat Nov 5 15:58:24 2016 Sho Hashimoto <sho-h@netlab.jp>
+
+ * tool/mkconfig.rb: [DOC] add rbconfig documentation.
+
+Sat Nov 5 15:42:52 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/smtp.rb (tlsconnect): support timeout for TLS handshake.
+ [ruby-core:76893] [Bug #12678]
+
+ * lib/net/protocol.rb (ssl_socket_connect): new method to implement
+ timeout for TLS handshake.
+
+ * lib/net/http.rb (connect): use Net::Protocol#ssl_socket_connect.
+
+Sat Nov 5 14:17:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (brace_body, do_body): since cmdarg_stack is saved in
+ VALUE val, should restore from the same member. on big-endian
+ platforms where VALUE is larger than int, it restored 0 in the
+ upper word. [ruby-core:77920] [Bug #12900]
+
+Sat Nov 5 13:52:52 2016 Akinori MUSHA <knu@iDaemons.org>
+
+ * lib/shellwords.rb (Shellwords#shellsplit): Fix the handling of
+ the backslash in double quotes to conform to the standard.
+ [ruby-core:63807] [Bug #10055]
+
+Sat Nov 5 12:14:31 2016 Tanaka Akira <akr@fsij.org>
+
+ * ext/pathname/pathname.c (Pathname#empty?): New method.
+ [ruby-core:76404] [Feature #12596] Proposed by John Backus.
+
+Sat Nov 5 11:53:02 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * test/ruby/test_refinement.rb (test_refine_alias_in_subclass):
+ add a test to check that alias in subclasses can be refined.
+ [ruby-core:69374] [Bug #11186]
+
+Sat Nov 5 11:20:57 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * cont.c (cont_new): disable optimization if clang's version is
+ 3.8.0. [ruby-core:77894] [Bug #12893]
+
+Sat Nov 5 10:07:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/ruby/test_file.rb (TestFile#test_stat): fix noatime case.
+ [ruby-core:77943] [Bug #12903]
+
+Fri Nov 4 17:52:44 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (heap_page_resurrect): do not return tomb_pages when
+ page->freelist == NULL.
+ [Bug #12670]
+
+Fri Nov 4 16:31:45 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * util.c (ruby_dtoa): round to even, instead of rounding to
+ nearest. [ruby-core:77864] [Bug #12889]
+
+Fri Nov 4 15:31:00 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: Add compiler version message into rbconfig
+ as RbConfig::CONFIG['CC_VERSION_MESSAGE']. [Feature #12896]
+
+Fri Nov 4 13:03:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * numeric.c (rb_int_digits): Fix exception message
+ [ruby-core:77502] [Bug #12815]
+
+Fri Nov 4 10:51:16 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/pathname/pathname.c (path_hash): fix unnormalized Fixnum
+ value bug on mingw/mswin.
+
+Fri Nov 4 10:35:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/fileutils.rb (FileUtils::Entry_#copy): ensure that the
+ source entry exists first, to fix error for non-existent entry.
+ [ruby-core:77885] [Bug #12892]
+
+Thu Nov 3 21:45:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * ext/bigdecimal/bigdecimal.c: Import changes from ruby/bigdecimal
+ repository.
+
+Thu Nov 3 15:01:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c: include sys/sysmacros.h for ArchLinux which deprecated
+ use of major() and minor() in sys/types.h.
+
+Wed Nov 2 08:45:49 2016 Dmitry Gritsay <unseductable@gmail.com>
+
+ * doc/extension.rdoc: set ANYARGS as arguments for func1 and func2.
+
+ * doc/extension.rdoc: mention the exception object which is passed
+ to func2 as the second argument. [Fix GH-1471]
+
+Wed Nov 2 07:34:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (rb_num_coerce_bit): enable bit operations with
+ coercing by non-integer object. [ruby-core:77783] [Bug #12875]
+
+Tue Nov 1 01:31:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (ac_cv_func_round): round(3) in x86_64-w64-mingw32
+ is not accurate in an edge case. [ruby-core:77794] [Bug #12878]
+
+Mon Oct 31 17:36:04 2016 Code Ahss <aycabta@gmail.com>
+
+ * test/test_forwardable.rb (TestForwardable#test_on_private_method):
+ add test for [Bug #12782] [Bug #12840]
+
+Mon Oct 31 11:08:51 2016 Samuel Williams <samuel.williams@oriontransfer.co.nz>
+
+ * lib/uri/generic.rb (URI::Generic#merge): merge merge0.
+ [GH-1469]
+
+Sun Oct 30 15:32:43 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update
+ rubygems to 2.6.8.
+ Release note of 2.6.8: https://github.com/rubygems/rubygems/commit/9fb8880976f5ab998912898b091d88aa10eb1d4a
+
+Sun Oct 30 06:39:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/windows_1254.c: Fix typo. Reported by k-takata at
+ https://github.com/k-takata/Onigmo/commit/ceb59cc. Thanks!
+
+Sat Oct 29 19:59:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (cond0): !-operator is a method call, no warning for
+ literal in condition. [ruby-core:77801] [Bug #12881]
+
+Sat Oct 29 10:09:38 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_compile_each): turn flip-flop in a not-operator
+ into a boolean value. fix up r56315
+
+Sat Oct 29 09:39:14 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (vm_call0_body): follow the original class, not to
+ loop the prepended module. [ruby-core:77784] [Bug #12876]
+
+Sat Oct 29 00:14:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enc/trans/windows-1255-tbl.rb: update mapping from 0xCA to
+ U+05BA. [Feature #12877]
+
+Fri Oct 28 23:22:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enc/depend: extract transcode_tblgen method calls for libraries
+ loaded by dynamically generated names, in single_byte.trans.
+
+Fri Oct 28 16:05:03 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * insns.def (opt_case_dispatch): extract float value only if the
+ Float method is not redefined.
+
+Fri Oct 28 15:58:16 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * internal.h (RB_OBJ_BUILTIN_TYPE): special-const safe
+ BUILTIN_TYPE.
+
+Fri Oct 28 15:20:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * complex.c (id_finite_p, id_infinite_p, id_rationalize, id_PI):
+ initialize static IDs.
+
+ * complex.c (FINITE_TYPE_P): extract predicate.
+
+ * complex.c (rb_complex_finite_p, rb_complex_infinite_p): use
+ dedicated predicates instead of switch by TYPE.
+
+Thu Oct 27 23:28:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_integer_type_p): turn into macro to help
+ clang based on old gcc to eliminate CSE.
+
+Thu Oct 27 16:33:47 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * tool/redmine-backporter.rb (rel): check the exception and show right
+ message.
+
+Thu Oct 27 14:57:33 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/socket/lib/socket.rb (UDPSocket#recvfrom_nonblock): [DOC] Remove
+ a false statement "If _maxlen_ is omitted, its default value is
+ 65536." maxlen, the first parameter, cannot be omitted as the method
+ signature indicates. This hasn't changed ever since it was first
+ implemented.
+
+Thu Oct 27 09:42:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_convert_to_integer): convert a fixable float to a
+ fixnum directly without the conversion method, as well as bignum
+ case.
+
+ * object.c (rb_convert_to_integer): should not drop the converted
+ string.
+
+Wed Oct 26 17:09:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_intern): use prefixed version macro
+ RUBY_CONST_ID_CACHE.
+
+Wed Oct 26 11:28:25 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * NEWS: added several entries which (if I remember correctly) are
+ added in a year.
+
+Tue Oct 25 12:54:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (mnew_internal): follow the original class, not to loop
+ the prepended module. [ruby-core:77591] [Bug #12832]
+
+Mon Oct 24 10:52:17 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/lib/test/unit.rb (Test::Unit::Parallel#deal): update the
+ job status after a task finished, to show idling workers.
+
+Mon Oct 24 10:51:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * complex.c (Init_Complex): undefine methods inherited from
+ Comparable, because Complex does not have <=> method.
+ [Bug #12866]
+
+ * class.c (rb_undef_methods_from): undefine methods defined in
+ super from klass.
+
+Mon Oct 24 10:19:44 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * complex.c (Init_Complex): undefine Complex#clamp, which does not
+ work like other Comparable methods, because Complex does not
+ have <=> method. patched by Tim Peters <zomg.tim AT gmail.com>
+ in [ruby-core:77720]. [Bug #12866]
+
+Sun Oct 23 11:41:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/encoding.h: include "ruby/ruby.h" explicitly for
+ enum ruby_fl_type and VALUE.
+
+Sat Oct 22 23:33:55 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (reg_compile_gen): always append error message to the
+ error buffer.
+
+Sat Oct 22 22:33:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (num_funcall1): check recursion by inverse pair, to
+ fix fake infinite recursion. [ruby-core:77713] [Bug #12864]
+
+Sat Oct 22 18:52:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash_compact_bang): should return nil if no elements
+ is deleted. [ruby-core:77709] [Bug #12863]
+
+Sat Oct 22 10:28:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (DLDFLAGS): fallback to LDFLAGS.
+ [ruby-core:72444] [Bug #11863]
+
+ * configure.in (LIBRUBY_DLDFLAGS): fallback to DLDFLAGS.
+
+ * configure.in (RUBY_APPEND_OPTION, RUBY_PREPEND_OPTION): expand
+ the option to be appended/prepended when matching, as well as
+ RUBY_APPEND_OPTIONS and RUBY_PREPEND_OPTIONS.
+
+Sat Oct 22 09:52:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (setup_args): duplicate splatting array if more
+ arguments present to obey left-to-right execution order.
+ [ruby-core:77701] [Bug# 12860]
+
+Fri Oct 21 16:44:44 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (do_opendir): retry after GC when the limit for open file
+ descriptors reached.
+
+Fri Oct 21 16:06:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (open_load_file): retry after GC when the limit for open
+ file descriptors reached.
+
+Fri Oct 21 11:34:17 2016 Pascal Schmid <Lechindianer@users.noreply.github.com>
+
+ * string.c (rb_str_sub, rb_str_gsub): [DOC] 'backlash' should read
+ 'backslash'. [Fix GH-1461]
+
+Thu Oct 20 17:02:56 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/uri/common.rb: added documentation for deprecated method.
+ [Misc #11960][ruby-core:72733][ci skip]
+
+Thu Oct 20 16:57:23 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * ext/digest/digest.c: Add documentation for Digest.
+ [Feature #10452][ruby-core:66001][ci skip]
+ * remove HMAC from list of digest algorithms,
+ * add MD5 in list of digest algorithms,
+ * add information about writing a C digest implementation using Digest::Base,
+ * add documentation for Digest::Base public methods.
+ * ext/digest/md5/md5init.c: add examples for MD5.
+ * ext/digest/rmd160/rmd160init.c: add examples for Digest::RMD160.
+ * ext/digest/sha1/sha1init.c: add examples for Digest::SHA1.
+
+Thu Oct 20 16:19:51 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/open-uri.rb: Improved documentation grammar for
+ open-uri#open option. [Misc #11329][ruby-core:69868][ci skip]
+
+Wed Oct 19 21:48:40 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * NEWS: mention refinements with Kernel#send and
+ BasicObject#__send__. [Feature #11476]
+
+Wed Oct 19 17:02:15 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_call_opt_send): enable refinements with
+ Kernel#send and BasicObject#__send__. [Feature #11476]
+
+Wed Oct 19 14:22:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * basictest/runner.rb: do not clobber the option by --run-opt with
+ RUBYOPT. reported by Allen Hewes <rallenh AT hotmail.com>.
+
+Wed Oct 19 00:09:06 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * addr2line.c (parse_debug_line_cu): boundary checks for
+ compressed debug sections. [ruby-dev:49840] [Bug #12850]
+
+Tue Oct 18 16:36:40 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (DLDFLAGS): append --compress-debug-sections=zlib
+ if available, which reduces the size of LIBRUBY_SO by half or
+ more.
+
+Mon Oct 17 16:20:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/configure.bat: add option to enable/disable to install
+ static ruby library. defaulted to "no". [Feature #12845]
+
+ * configure.in (install-static-library): add option to enable/
+ disable to install static ruby library. defaulted to "no" if
+ enable-shared. [Feature #12845]
+
+ * tool/rbinstall.rb (local-arch-lib): respect the option.
+
+Sun Oct 16 15:09:06 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/windows_1254.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for Windows-1254.
+
+Sat Oct 15 14:17:05 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_args.c (refine_sym_proc_call): search and call method with
+ refinements.
+
+ * vm_args.c (vm_caller_setup_arg_block): enable refinements when
+ enabled in the caller. [Feature #9451]
+
+Sat Oct 15 00:54:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (proc_exec_cmd): use UTF-8 version aspawn.
+ [ruby-dev:49838] [Bug #12841]
+
+Fri Oct 14 22:26:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse/kwargs.rb (OptionParser#define_by_keywords):
+ [EXPERIMENTAL] extract command line option definitions from the
+ information of keyword arguments.
+
+Fri Oct 14 18:27:18 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * object.c: Improve documentation for Float conversion.
+ [ruby-core:71661][Bug #11736][ci skip]
+
+Fri Oct 14 18:00:20 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/logger.rb: Improve Logger.new option documentation.
+ [Feature #12803][ruby-core:77467]
+
+Fri Oct 14 17:20:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse.rb (make_switch, parse_in_order): unify underscores
+ to hyphens.
+
+Fri Oct 14 10:48:37 2016 Eric Wong <e@80x24.org>
+
+ * lib/webrick/utils.rb (TimeoutHandler): use monotonic clock
+ (watch): ditto
+
+Thu Oct 13 19:41:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (copy_stream_body): use IO to write to copy to duplex IO.
+ http://twitter.com/knu/status/786505317974585344
+
+Thu Oct 13 17:05:57 2016 Dwain Faithfull <dwfaithfull@gmail.com>
+
+ * hash.c (rb_hash_compact, rb_hash_compact_bang): Removes nil
+ values from the original hash, to port Active Support behavior.
+ [Feature #11818]
+
+Thu Oct 13 11:35:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_sort_bang, rb_ary_sort, rb_ary_sort_by_bang):
+ [DOC] describe that sort may not be stable.
+
+ * enum.c (enum_sort, enum_sort_by): ditto.
+
+Thu Oct 13 11:31:40 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/rexml/xpath/test_text.rb (test_ancestors): Array#sort may
+ not be stable. [ruby-core:76088] [Bug #12509]
+
+ * test/rss/test_maker_{0.9,1.0,2.0}.rb (test_items): ditto.
+
+Thu Oct 13 10:37:31 2016 Eric Wong <e@80x24.org>
+
+ * doc/extension.rdoc: wording fix
+
+Thu Oct 13 00:39:08 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/ruby/test_array.rb (test_sort_bang_with_freeze): make a
+ clone to copy a <=> singleton method, instead of dup. which
+ element will be called is not predictable.
+ [ruby-core:76088] [Bug #12509]
+
+Thu Oct 13 00:21:27 2016 Simon Soriano <simon0191@gmail.com>
+
+ * doc/extension.rdoc: Replace "You can defined hooked variables"
+ with "You can define hooked variables". [Fix GH-1460]
+
+Wed Oct 12 21:05:50 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ruby.c (open_load_file): revert r56385. it introduced incompatibility
+ about `DATA.binmode?`.
+
+Wed Oct 12 15:24:53 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * tool/downloader.rb: Removed verification of gem certification.
+ Because signed gem is not working on rubygems ecosystem.
+ * tool/gem-unpack.rb: ditto.
+
+Tue Oct 11 22:08:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (prep_io): fix typo of struct member name.
+ [ruby-core:77550] [Bug #12829]
+
+Tue Oct 11 16:45:24 2016 Tanaka Akira <akr@fsij.org>
+
+ * lib/uri/generic.rb (URI.find_proxy): Add an optional argument, env.
+
+Tue Oct 11 16:38:32 2016 Tanaka Akira <akr@fsij.org>
+
+ * lib/pp.rb (String#pretty_print): Defined to print a string as
+ multiple lines.
+ [ruby-core:76800] [Feature#12664] proposed by Petr Chalupa.
+
+Mon Oct 10 15:22:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (open_load_file): bind the open fd to an IO instance
+ before waiting FIFO, not to leak the fd if interrupted.
+
+Mon Oct 10 12:40:54 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (open_load_file): compare with EXEEXT instead of hard
+ coded name, and do not match with mere EXEEXT.
+
+ * ruby.c (open_load_file): open in binary mode if available, as
+ parser deals with EOLs.
+
+ * io.c (prep_io): reduce isatty call (and its system call) on
+ Cygwin.
+
+Sun Oct 9 23:05:53 2016 Prathamesh Sonpatki <csonpatki@gmail.com>
+
+ * array.c, class.c: Fixed documentation where Fixnum was referred
+ directly to use Integer, as Fixnum and Bignum are now unified
+ into Integer and direct usage is deprecated. [Fix GH-1459]
+
+Sun Oct 9 11:37:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_core.h (VM_ASSERT): stringify expr here before expansion in
+ RUBY_ASSERT_WHEN.
+
+Sat Oct 8 10:54:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/-test-/memory_status/memory_status.c (read_status): use
+ Win32 GetProcessMemoryInfo API.
+
+ * ext/-test-/memory_status/memory_status.c: get memory sizes by
+ mach task_info system call.
+
+Sat Oct 8 09:06:55 2016 Aurelien Jacobs <aurel@gnuage.org>
+
+ * lib/logger.rb (Logger::Period#next_rotate_time): fix monthly log
+ rotate when DST is applied during a month of 31 days.
+ [Fix GH-1458]
+
+Fri Oct 7 20:21:39 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (gc_prof_setup_new_record): fix the condition to get
+ rusage.
+
+ * gc.c (gc_profile_dump_major_reason): remove undefined flags.
+
+Fri Oct 7 19:18:33 2016 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/*.c, ext/win32ole/win32ole.h: use RB_INT2FIX instead of
+ INT2FIX, and so on.
+
+Fri Oct 7 14:18:40 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * basictest/test.rb: Adjust spaces in class declarations
+ with inheritance. [fix GH-1227] Patch by @adrfer
+ * lib/irb/*: ditto.
+ * lib/prime.rb: ditto.
+ * lib/shell/builtin-command.rb: ditto.
+ * object.c: ditto.
+ * sample/*.rb: ditto.
+ * test/-ext-/method/test_arity.rb: ditto.
+
+Thu Oct 6 17:29:44 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * load.c (rb_require_safe): SyntaxError created by the parser just
+ has the message and needs to set up the backtrace.
+ [ruby-core:77491] [Bug #12811]
+
+ * load.c (rb_load_internal0): load/require is not the main
+ script.
+
+Thu Oct 6 13:35:15 2016 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * enum.c: [DOC] Improve doc [ci-skip]
+
+Thu Oct 6 11:38:14 2016 Chris Jones <chris@christopherjones.us>
+
+ * ext/readline/extconf.rb: Update error message with correct words.
+ [fix GH-1453][ci skip] Patch by @magikid
+
+Thu Oct 6 11:01:49 2016 Tieg Zaharia <tieg.zaharia@gmail.com>
+
+ * lib/uri/common.rb (WEB_ENCODINGS_): Update URI::WEB_ENCODINGS_
+ hash, and fix documented command to grab it. [Fix GH-1430]
+
+Thu Oct 6 10:37:13 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * enum.c: Add reduce/inject alias note.
+ [fix GH-1400][ci skip] Patch by @getaaron
+
+Thu Oct 6 10:30:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (update_coverage): check coverage values, and ignore
+ non-fixnum values.
+
+Thu Oct 6 09:19:21 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (fptr_finalize): use dedicated macro RB_INTEGER_TYPE_P.
+
+Wed Oct 5 18:02:44 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/net/http/response.rb: Improve document readability.
+ [fix GH-1411][ci skip] Patch by @stz-seongheon
+
+Wed Oct 5 15:43:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * node.c (dump_node): flatten statements in NODE_BLOCK.
+
+Wed Oct 5 14:27:36 2016 Byron Bowerman <me@bm5k.com>
+
+ * range.c: Add docs for max/min behavior with exclusive range.
+ [fix GH-1433][ci skip] Patch by @BM5k
+
+Wed Oct 5 12:57:21 2016 Richard Schneeman <richard.schneeman+foo@gmail.com>
+
+ * ext/socket/*.c: Add proper require for example to work.
+ [fix GH-1378][ci skip] Patch by @schneems
+
+Wed Oct 5 11:47:19 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * io.c: Fixed equivalent ruby code with core implementation.
+ [fix GH-1429][ci skip] Patch by @sos4nt
+
+Wed Oct 5 11:36:21 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/delegate.rb: Added missing spaces and Removed needless spaces.
+ [fix GH-1454][ci skip] Patch by @bogdanvlviv
+
+Wed Oct 5 03:24:55 2016 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * enum.c: Make Enumerable#chunk with no block return
+ an Enumerator [#2172]
+
+Wed Oct 5 01:19:45 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * internal.h (ST2FIX): new macro to convert st_index_t to Fixnum.
+ a hash value of Object might be Bignum, but it causes many troubles
+ especially the Object is used as a key of a hash. so I've gave up
+ to do so.
+
+ * array.c (rb_ary_hash): use above macro.
+
+ * bignum.c (rb_big_hash): ditto.
+
+ * hash.c (rb_obj_hash, rb_hash_hash): ditto.
+
+ * numeric.c (rb_dbl_hash): ditto.
+
+ * proc.c (proc_hash): ditto.
+
+ * re.c (rb_reg_hash, match_hash): ditto.
+
+ * string.c (rb_str_hash_m): ditto.
+
+Tue Oct 4 12:59:44 2016 Koichi ITO <koic.ito@gmail.com>
+
+ * array.c (rb_ary_dig): [DOC] update an example of error message
+ by Array#dig, because of Integer Unification. [Fix GH-1455]
+
+Tue Oct 4 09:55:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (BigDecimal_div2): need more room
+ for precision to round. [ruby-core:77475] [Bug #12805]
+
+Tue Oct 4 06:05:46 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * regcomp.c (onig_print_compiled_byte_code): make the shown address
+ look relative.
+
+Tue Oct 4 05:53:11 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * regexec.c (OPCODE_EXEC_HOOK): op is p-1 because p is already
+ incremented.
+
+ * regexec.c (OPCODE_EXEC_HOOK): use the exact end address.
+
+ * regexec.c (match_at): don't call OPCODE_EXEC_HOOK in CASE()
+ when it comes from goto fail.
+
+Mon Oct 3 21:24:41 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * NEWS: mention Readline.quoting_detection_proc{,=}.
+
+Mon Oct 3 21:19:46 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * lib/logger.rb: [DOC] Fix default value of shift_age.
+
+Mon Oct 3 17:20:05 2016 George Brocklehurst <ruby@georgebrock.com>
+
+ * ext/readline/readline.c (readline_s_set_quoting_detection_proc):
+ support rl_char_is_quoted_p. [Feature #12659]
+
+ * ext/readline/readline.c (readline_s_get_quoting_detection_proc):
+ ditto.
+
+Sun Oct 2 08:22:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (RB_INT2FIX, RB_LONG2FIX): prefix RB to
+ global symbols to get rid of name conflicts with other headers.
+
+Sun Oct 2 07:51:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_hash_m): hash values may be negative.
+
+Sun Oct 2 02:04:12 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * string.c (rb_str_hash_m): st_index_t is not guaranteed as the same
+ size with int, and of course also not guaranteed the value can be
+ Fixnum.
+
+Sun Oct 2 02:03:06 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * numeric.c (rb_fix2str): detect unnormalized Fixnum value.
+
+Sat Oct 1 23:08:47 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/date/date_parse.c (date_zone_to_diff): it's nonsense and really
+ harm that to use unary minus operator with unsigned value.
+ get rid of test failures introduced at r56312.
+
+Sat Oct 1 22:17:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_compile_each): move numeric literal range
+ optimization from fixup_nodes() in parse.y.
+
+Sat Oct 1 19:19:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (compile_flip_flop): simplify generated code.
+
+ * compile.c (compile_branch_condition): flip-flop can appear only
+ in conditional expressions.
+
+Sat Oct 1 02:02:02 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (poll_child_status): rb_w32_wait_events_blocking() sets
+ errno internally, then should not set it here.
+
+Fri Sep 30 19:06:21 2016 Anton Davydov <mail@davydovanton.com>
+
+ * lib/uri/http.rb: Documentation and code style improvements.
+ * test/uri/test_http.rb: Added test for coverage.
+ [fix GH-1427][ruby-core:77255][Misc #12756]
+
+Fri Sep 30 18:43:20 2016 Jason Yeo <jason@jasonyeo.me>
+
+ * doc/syntax/control_expressions.rdoc: Add missing 'as'
+ [ci skip][fix GH-1448] Patch by @jsyeo
+
+Thu Sep 29 23:38:04 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * lib/yaml/store.rb (YAML::Store#dump): use table argument instead
+ of @table directly.
+
+Thu Sep 29 22:22:22 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * lib/yaml/store.rb (YAML::Store#initialize): Fix arguments.
+ [ruby-dev:49821] [Bug #12800]
+
+ * test/yaml/test_store.rb: Add tests from test/test_pstore.rb.
+
+ * test/yaml/test_store.rb (YAMLStoreTest#test_with_options): Add options test.
+
+ * lib/yaml/store.rb (YAML::Store#dump): Revert to to_yaml.
+
+ * lib/yaml/store.rb (YAML::Store#empty_marshal_data): Use to_yaml with options.
+
+ * lib/yaml/store.rb (YAML::Store#empty_marshal_checksum): Use CHECKSUM_ALGO.
+
+Thu Sep 29 19:34:23 2016 Pete Higgins <pete@peterhiggins.org>
+
+ * thread_sync.c (rb_queue_pop, rb_szqueue_push, rb_szqueue_pop):
+ Document exception types, ThreadError, raised by Queue and
+ SizedQueue. [Fix GH-1451]
+
+Thu Sep 29 19:21:02 2016 Pete Higgins <pete@peterhiggins.org>
+
+ * thread_sync.c (Init_thread_sync): Remove confusing doc comments,
+ which are picked up by rdoc unexpectedly, from Queue and
+ SizedQueue. [Fix GH-1450]
+
+Wed Sep 28 23:14:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/pstore.rb (PStore::CHECKSUM_ALGO): find available hashing
+ algorithm for checksum. MD5 is not available in FIPS mode.
+ [Feature #6943]
+
+Wed Sep 28 13:00:25 2016 ksss <co000ri@gmail.com>
+
+ * signal.c (sig_signame): [DOC] Add documentation in the case of
+ return nil. [Fix GH-1449]
+
+Wed Sep 28 10:43:27 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * .travis.yml: delete comments. They were outdated.
+
+Wed Sep 28 09:57:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update
+ rubygems to 2.6.7.
+ Release note of 2.6.7: https://github.com/rubygems/rubygems/commit/60f35bd1d2359fc30301d2d4cd72bc6833e8d12a
+
+Wed Sep 28 00:21:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (rb_warning_s_warn): the argument must be an
+ ASCII-compatible string. [ruby-core:77430] [Bug #12793]
+
+Tue Sep 27 23:22:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (symbol, dsym, parser_set_number_literal): set state to
+ ENDARG, so that `do` after a literal should be `do_block` and
+ bound to the outer method. [ruby-core:72482] [Bug #11873]
+
+ * parse.y (parse_ident): revert r56198.
+
+ * parse.y (warn_balanced): the state of symbol and numeric
+ literals is now EXPR_ENDARG, do not exclude it.
+
+Tue Sep 27 22:59:42 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * NEWS: news about Warning.warn.
+
+Tue Sep 27 18:10:18 2016 Jeremy Evans <code@jeremyevans.net>
+
+ * error.c: This makes all warnings raised call Warning.warn, which
+ by default does the same thing it does currently
+ (rb_write_error_str). You can override Warning.warn to change
+ the behavior. [ruby-core:75016] [Feature #12299]
+
+Tue Sep 27 17:35:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * iseq.c (iseqw_s_compile_file): deal with syntax error as well as
+ compile, and should not abort when rescued.
+
+Tue Sep 27 12:07:17 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/cgi/cookie.rb (parse): don't allow , as a separator. [Bug #12791]
+
+ * lib/webrick/cookie.rb (parse): ditto.
+
+Mon Sep 26 21:37:21 2016 Akinori MUSHA <knu@iDaemons.org>
+
+ * man/erb.1, man/irb.1, man/ri.1, man/ruby.1: Remove Ns before
+ punctuation.
+
+Mon Sep 26 16:23:49 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/stringio/stringio.c (strio_seek): Avoid signed integer overflow.
+ It's not harmful in practice here, but is still undefined behavior.
+
+ * ext/stringio/stringio.c (strio_extend): Check that the new length does
+ not exceed LONG_MAX. This fixes the invalid write on the overflow.
+
+ * test/stringio/test_stringio.rb (test_write_integer_overflow): Add a
+ test case for the above fix in strio_extend().
+
+Mon Sep 26 15:43:34 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * eval_intern.h (TH_PUSH_TAG): Initialize struct rb_vm_tag::tag with
+ Qundef rather than 0 which is equal to Qfalse. Since Kernel#throw(obj)
+ searches a tag with rb_vm_tag::tag == obj, throw(false) can
+ accidentally find an unrelated tag which is not created by
+ Kernel#catch. [ruby-core:77229] [Bug #12743]
+
+ * test/ruby/test_exception.rb (test_throw_false): Add a test case for
+ this.
+
+Mon Sep 26 14:36:12 2016 Naotoshi Seo <sonots@gmail.com>
+
+ * lib/tempfile.rb: provide default basename parameter for
+ Tempfile.create. [Feature #11965] Patch by Yuki Kurihara
+ * test/test_tempfile.rb: ditto.
+
+Mon Sep 26 14:10:54 2016 Ary Borenszweig <ary@esperanto.org.ar>
+
+ * string.c (lstrip_offset): add a fast path in the case of single
+ byte optimizable strings, as well as rstrip_offset.
+ [ruby-core:77392] [Feature #12788]
+
+Mon Sep 26 12:00:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gems/bundled_gems: update to minitest-5.9.1.
+
+Mon Sep 26 11:50:03 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * tool/rbinstall.rb (gem): Don't install gemspec if no files will be
+ installed for the gem. This happens when the extension library is not
+ compiled.
+
+Mon Sep 26 11:06:47 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * string.c (enc_strlen, rb_enc_strlen_cr): Avoid signed integer
+ overflow. The result type of a pointer subtraction may have the same
+ size as long. This fixes String#size returning an negative value on
+ i686-linux environment:
+
+ str = "\x00" * ((1<<31)-2))
+ str.slice!(-3, 3)
+ str.force_encoding("UTF-32BE")
+ str << 1234
+ p str.size
+
+Sun Sep 25 22:48:06 2016 namusyaka <namusyaka@gmail.com>
+
+ * lib/erb.rb (ERB::Compiler::TrimScanner#stag): The :stag accessor
+ has already been available because it is defined in parent
+ Scanner class. [Fix GH-1445]
+
+Sun Sep 25 19:21:26 2016 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * node.c (dump_array): remove duplicate header of NODE_ARRAY/
+ NODE_VALUES.
+
+Sat Sep 24 22:26:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb (extract_makefile, extmake, configuration): store
+ extra libraries to be installed.
+
+ * tool/rbinstall.rb (ext-arch): install extra libraries.
+
+ * ext/zlib/extconf.rb: install zlib if built.
+
+Sat Sep 24 14:24:55 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * spec/README: update URL.
+
+Sat Sep 24 11:28:22 2016 Koichi ITO <koic.ito@gmail.com>
+
+ * fix typos, "a" before "Integer" to "an". [Fix GH-1438]
+
+Sat Sep 24 10:19:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/misc/test_ruby_mode.rb (assert_indent): since write-region
+ in Emacs 25.1 no longer displays the "Wrote file" message, shows
+ the explicit message to check if successfully finished.
+ [ruby-core:77355] [Bug #12785]
+
+ * test/misc/test_ruby_mode.rb (EXPR_SAVE): use a numeric prefix
+ argument of 0, not to make the previous version into a backup
+ file, instead of backup-inhibited.
+
+ * test/misc/test_ruby_mode.rb (run_emacs): always save the buffer
+ if modified.
+
+Fri Sep 23 23:57:40 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * vm_method.c (make_method_entry_refined): fix wrong use of ||.
+
+Fri Sep 23 21:38:58 2016 Akinori MUSHA <knu@iDaemons.org>
+
+ * tool/mdoc2man.rb (Mdoc2Man#parse_macro): Add support for the
+ `Lk` macro.
+
+ * tool/mdoc2man.rb (Mdoc2Man#shift_arg): A new function to extract
+ a possibly quoted argument.
+
+Fri Sep 23 20:36:05 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * eval.c (rb_mod_refine): refine modules as well.
+ [ruby-core:76199] [Feature #12534]
+
+Fri Sep 23 20:19:09 2016 Akinori MUSHA <knu@iDaemons.org>
+
+ * man/ruby.1: Update the paragraphs in "Rich Libraries" which
+ included a dead link.
+
+Fri Sep 23 20:05:27 2016 Akinori MUSHA <knu@iDaemons.org>
+
+ * man/ruby.1, man/erb.1, man/irb.1, man/ri.1: Use the `Lk` macro
+ for hyperlinks, which has been available since mdocml 1.5.1
+ (released more than seven years ago).
+
+Fri Sep 23 15:47:04 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/forwardable.rb (_delegator_method): allow private methods to
+ be delegated, with warnings. [ruby-core:77341] [Bug #12782]
+
+Fri Sep 23 12:15:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_peephole_optimize): enable tail call
+ optimization inside a conditional block.
+
+Thu Sep 22 13:00:04 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * gc.c (gc_start_internal): [DOC] methods without arguments
+ like r56194. [Bug #12777]
+
+Wed Sep 21 17:43:53 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * process.c (InitVM_process): Support CLOCK_MONOTONIC_RAW_APPROX,
+ CLOCK_UPTIME_RAW, and CLOCK_UPTIME_RAW_APPROX which are introduced
+ by macOS 10.12.
+
+Wed Sep 21 13:47:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (brace_body, do_body): preserve cmdarg_stack so that
+ `do` after cmdarg in a block should be `do_block` and bound to
+ the outer method. [ruby-core:72482] [Bug #11873]
+
+ * parse.y: `do` after cmdarg in parentheses should be `do_block`
+ and bound to the outer method. [ruby-core:72482] [Bug #11873]
+
+ * parse.y (brace_body, do_body): extract block bodies.
+
+Tue Sep 20 23:02:50 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (gc_start_internal): [DOC] add ObjectSpace.garbage_collect
+ and fix GC#garbage_collect. [Bug #12777]
+
+Tue Sep 20 21:24:01 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * doc/extension.ja.rdoc: translate r56189 (rb_gc_adjust_memory_usage).
+
+Tue Sep 20 17:52:28 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * gems/bundled_gems: Update rake-11.3.0
+
+Tue Sep 20 16:52:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (rb_gc_adjust_memory_usage): notify memory usage to the GC
+ engine by extension libraries, to trigger GC. [Feature #12690]
+
+Mon Sep 19 17:05:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (Init_Numeric), bignum.c (Init_Bignum): deprecate
+ Fixnum and Bignum. this may be reverted after previews.
+ [Feature #12739]
+
+Mon Sep 19 10:36:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enumerator.c (lazy_init_yielder): directly call stored functions.
+ [Feature #6183]
+
+ * enumerator.c (lazy_add_method): create lazy enumerator which
+ uses lazy_init_yielder().
+
+Sun Sep 18 22:48:54 2016 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rss/rss.rb (RSS::BaseModel): Remove needless codes.
+ [Bug #12773][ruby-dev:49813]
+ Reported by Kazuhiro NISHIYAMA. Thanks!!!
+
+Sun Sep 18 19:23:47 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * lib/sync.rb: Fix NameError when error.
+
+Sat Sep 17 22:46:02 2016 Koichi ITO <koic.ito@gmail.com>
+
+ * vm_insnhelper.c (vm_throw_start): Remove too much ";"
+ [fix GH-1432]
+
+Sat Sep 17 19:19:06 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * test/openssl/test_ssl.rb (test_ctx_options): Fix test failure on
+ Ubuntu 16.04. The fix in r56147 was incomplete. This is a cherry-pick
+ of the commit b039f3e268c2 at ruby/openssl.
+
+Sat Sep 17 10:49:35 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * doc/extension.ja.rdoc: translate r56130 (rb_check_arity).
+
+Sat Sep 17 02:40:52 2016 Aaron Patterson <tenderlove@ruby-lang.org>
+
+ * ext/objspace/objspace_dump.c: Fix stream processing support for heap
+ dumps. Full heap dumps should use JSON lines (http://jsonlines.org)
+ so that we can process very large heaps without loading the entire
+ heap dump in to memory at once.
+
+Fri Sep 16 22:10:31 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * ext/openssl/ossl_ssl.c (ssl_npn_select_cb_common): Fix compile error
+ with old version of fcc (Fujitsu C Compiler) on Solaris 10.
+ [Bug #12769] [ruby-dev:49809]
+
+Fri Sep 16 21:28:25 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * internal.h (MAYBE_UNUSED): The fallback definition is needed.
+ Fix compile error with some non-GCC compilers such as
+ Oracle Solaris Studio 12.3 on Solaris 10.
+ [Bug #12767] [ruby-dev:49807]
+
+ * internal.h (WARN_UNUSED_RESULT): ditto.
+
+Fri Sep 16 21:19:51 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * hash.c (each_pair_i_fast): Fix compile error with old version of
+ fcc on Solaris 10. [Bug #12768] [ruby-dev:49808]
+
+Fri Sep 16 19:46:05 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/Makefile.sub (config.h): fixed compile error with VC introduced
+ by previous commit.
+
+Fri Sep 16 14:54:34 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * internal.h (WARN_UNUSED_RESULT): moved to configure.in, to
+ actually check its availability rather to check GCC's version.
+
+ * configure.in (WARN_UNUSED_RESULT): moved to here.
+
+ * configure.in (RUBY_FUNC_ATTRIBUTE): change function declaration
+ to return int rather than void, because it makes no sense for a
+ warn_unused_result attributed function to return void.
+
+ Funny thing however is that it also makes no sense for noreturn
+ attributed function to return int. So there is a fundamental
+ conflict between them. While I tested this, I confirmed both
+ GCC 6 and Clang 3.8 prefers int over void to correctly detect
+ necessary attributes under this setup. Maybe subject to change
+ in future.
+
+ * internal.h (UNINITIALIZED_VAR): renamed to MAYBE_UNUSED, then
+ moved to configure.in for the same reason we move
+ WARN_UNUSED_RESULT.
+
+ * configure.in (MAYBE_UNUSED): moved to here.
+
+ * internal.h (__has_attribute): deleted, because it has no use now.
+
+ * string.c (rb_str_enumerate_lines): refactor macro rename.
+
+ * string.c (rb_str_enumerate_bytes): ditto.
+
+ * string.c (rb_str_enumerate_chars): ditto.
+
+ * string.c (rb_str_enumerate_codepoints): ditto.
+
+ * thread.c (do_select): ditto.
+
+ * vm_backtrace.c (rb_debug_inspector_open): ditto.
+
+ * vsnprintf.c (BSD_vfprintf): ditto.
+
+Fri Sep 16 14:35:55 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * ChangeLog (add-log-time-format): Not exactly sure when but
+ recently (25.x maybe), emacs changed its API to take optional
+ two arguments. We have to follow that.
+
+Fri Sep 16 06:43:25 2016 Aaron Patterson <tenderlove@ruby-lang.org>
+
+ * lib/uri/generic.rb (def check_password): don't include bad password
+ in URI exception output
+
+ * test/uri/test_generic.rb (def test_set_component): test for behavior
+
+Thu Sep 15 21:40:03 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * doc/extension.ja.rdoc: Fix file name.
+
+Thu Sep 15 00:59:30 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * benchmark/: add vnmakarov's benchmarks around hash [ruby-core:75265]
+
+Wed Sep 14 07:02:31 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * hash.c (each_pair_i_fast): use rb_yield_values2 to avoid var args.
+
+Tue Sep 13 21:32:54 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * string.c (STR_HEAP_SIZE, RESIZE_CAPA_TERM, str_new0, rb_str_buf_new,
+ str_shared_replace, rb_str_init, str_make_independent_expand,
+ rb_str_resize): Avoid overflow by casting the length to size_t. size_t
+ should be able to represent LONG_MAX+termlen.
+
+ * string.c (rb_str_modify_expand): Check that the new length is in the
+ range of long before resizing. Also refactor to use RESIZE_CAPA_TERM
+ macro.
+
+ * string.c (str_buf_cat): Fix so that it does not create a negative
+ length String. Also fix the condition for 'string sizes too big', the
+ total length can be up to LONG_MAX.
+
+ * string.c (rb_str_plus): Check the resulting String length does not
+ exceed LONG_MAX.
+
+ * string.c (rb_str_dump): Fix integer overflow. The dump result will be
+ longer then the original String.
+
+Tue Sep 13 21:30:53 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * gc.c (heap_extend_pages, get_envparam_size, ruby_malloc_size_overflow,
+ gc_profile_dump_on): Use PRIuSIZE instead of PRIdSIZE as the passed
+ value is size_t, not ssize_t.
+
+ * iseq.c (get_line_info, rb_iseq_disasm_insn): Ditto.
+
+ * sprintf.c (rb_str_format): Ditto.
+
+ * thread_win32.c (native_thread_create): Ditto.
+
+ * vm.c (get_param): Ditto.
+
+ * ext/objspace/objspace_dump.c (dump_append_string_content,
+ dump_object): Ditto.
+
+ * ext/socket/raddrinfo.c (host_str, port_str): Ditto.
+
+Tue Sep 13 21:27:35 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * string.c (STR_EMBEDDABLE_P): Renamed from STR_EMBEDABLE_P(). And use
+ it in more places.
+
+Tue Sep 13 21:23:51 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * README.md: Drop support for BeOS now that Haiku is stable since
+ 2.3.0.
+
+ * README.ja.md: ditto.
+
+Tue Sep 13 21:11:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (STR_EMBEDABLE_P): extract the predicate macro to tell
+ if the given length is capable in an embedded string, and fix
+ possible integer overflow.
+
+Tue Sep 13 18:37:08 2016 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_exception.rb: fix thread issues.
+ * use Queue instead of a local variable for synchronization.
+ * join created thread to solve leaking threads warning.
+
+Tue Sep 13 16:07:26 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * string.c (rb_str_set_len): The buffer overflow check is wrong. The
+ space for termlen is allocated outside the capacity returned by
+ rb_str_capacity(). This fixes r41920 ("string.c: multi-byte
+ terminator", 2013-07-11). [ruby-core:77257] [Bug #12757]
+
+ * test/-ext-/string/test_set_len.rb (test_capacity_equals_to_new_size):
+ Test for this change. Applying only the test will trigger [BUG].
+
+Tue Sep 13 06:03:34 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * common.mk (benchmark): fix lib path.
+
+Tue Sep 13 00:39:47 2016 Aaron Patterson <tenderlove@ruby-lang.org>
+
+ * class.c (singleton_class_of): Copy superclass serial number to
+ singleton class. This improves singleton class IMC hit rates.
+ [Feature #12364] [ruby-core:75425]
+
+Mon Sep 12 13:46:23 2016 Anton Davydov <mail@davydovanton.com>
+
+ * lib/uri/mailto.rb: Removed needless `return` and use `.` instead of `::`
+ with class method.
+ * test/uri/test_mailto.rb: Added tests for coverage.
+ [fix GH-1426][Misc #12750][ruby-core:77242]
+
+Sun Sep 11 21:30:26 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * NEWS: News about Module.used_modules.
+
+Sun Sep 11 19:06:49 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_write_console): should set written length as the
+ return value. [Bug #12748] [ruby-dev:49786]
+
+Fri Sep 9 22:43:29 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * gems/bundled_gems: sort lines.
+
+Fri Sep 9 17:59:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (rb_threadptr_raise): set cause from the called thread,
+ but not from the thread to be interrupted.
+ [ruby-core:77222] [Bug #12741]
+
+Fri Sep 9 13:50:05 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * doc/extension.rdoc, doc/extension.ja.rdoc: fix file name.
+ pointed out by @takkanm in the RubyKaigi talk.
+
+Fri Sep 9 13:14:53 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * News: Announcing update to Unicode version 9.0.0 [ci skip]
+
+Fri Sep 9 10:10:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * variable.c (rb_const_search): warn with the actual class/module
+ name which defines the deprecated constant.
+
+ * variable.c (rb_const_search): raise with the actual class/module
+ name which defines the private constant.
+
+Thu Sep 8 17:47:18 2016 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * array.c (flatten): use rb_obj_class instead of rb_class_of
+ because rb_class_of may return a singleton class.
+ [ruby-dev:49781] [Bug #12738]
+
+Thu Sep 8 17:40:15 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/rbinstall.rb (gem): use the bindir of each gemspec instead
+ of hardcoded 'bin', since rdoc 5.0.0 overrides it.
+
+Thu Sep 8 16:47:03 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * eval.c (rb_mod_s_used_modules): rename Module.used_refinements to
+ Module.used_modules. [Feature #7418] [ruby-core:49805]
+
+Thu Sep 8 14:21:48 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * ext/psych/psych.gemspec, lib/rdoc/rdoc.gemspec: Use file list instead of
+ git output. It shows warning message when invoke `make install`
+ [Bug #12736][ruby-dev:49778]
+
+Thu Sep 8 13:41:46 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * insns.def (setclassvariable, setconstant): warn when self is a
+ refinement. [Bug #10103] [ruby-core:64143]
+
+Thu Sep 8 11:29:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * hash.c (rb_hash_transform_values, rb_hash_transform_values_bang):
+ Rename map_v to transform_values.
+ [Feature #12512] [ruby-core:76095]
+
+ * test/ruby/test_hash.rb: ditto.
+
+Thu Sep 8 10:08:35 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * {ext,test}/openssl: Import Ruby/OpenSSL 2.0.0.beta.2. The full commit
+ history since v2.0.0.beta.1 can be found at:
+ https://github.com/ruby/openssl/compare/v2.0.0.beta.1...v2.0.0.beta.2
+
+Thu Sep 8 07:23:34 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rdoc/*, test/rdoc/*: Update rdoc-5.0.0.beta2
+ Fixed ri parse defect with left-hand matched classes.
+ https://github.com/rdoc/rdoc/pull/420
+
+Thu Sep 8 01:12:47 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * eval.c (rb_mod_s_used_refinements): new method
+ Module.used_refinements. based on the patch by Charlie
+ Somerville. [Feature #7418] [ruby-core:49805]
+
+Wed Sep 7 17:50:38 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/util.h (setenv): remove POSIX-noncompliant
+ definition with 2 arguments.
+
+Wed Sep 7 17:35:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * unicode/8.0.0/casefold.h, name2ctype.h, unicode/data/8.0.0:
+ removing directories/files related to Unicode version 8.0.0
+
+Wed Sep 7 17:21:55 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/timeout.rb (Timeout#timeout): add custom error message
+ argument. [Feature #11650]
+
+Wed Sep 7 17:13:05 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * common.mk: Updated Unicode version to 9.0.0 [Feature #12513]
+
+ * unicode/9.0.0/casefold.h, name2ctype.h, unicode/data/9.0.0:
+ new directories/files for Unicode version 9.0.0
+
+Wed Sep 7 16:00:45 2016 Tanaka Akira <akr@fsij.org>
+
+ * lib/open-uri.rb: Allow http to https redirection.
+ Note that https to http is still forbidden.
+ [ruby-core:20485] [Feature #859] by Roman Shterenzon.
+
+Wed Sep 7 14:56:59 2016 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * lib/csv.rb (CSV::{Row,Table}#{each,delete_if}): returns an enumerator
+ if no block is given. [ruby-core:75346] [Feature #12347]
+
+ * test/csv/test_row.rb: add test for above.
+
+ * test/csv/test_table.rb: ditto.
+
+Wed Sep 7 14:50:01 2016 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * gems/bundled_gems: update to power_assert 0.3.1.
+
+Wed Sep 7 12:16:09 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * ext/psych/*, test/psych/*: Update psych-2.1.1
+ This version fixed following pull requests.
+ https://github.com/tenderlove/psych/pull/284
+ https://github.com/tenderlove/psych/pull/276
+
+Wed Sep 7 11:51:06 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rdoc/*, test/rdoc/*: Update rdoc-5.0.0.beta1
+ This version is mostly same as r56072. It contains to remove code
+ for Ruby 1.8
+
+Tue Sep 6 09:23:06 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rdoc/rdoc.gemspec: partly reverted for default gem installer.
+ upstream configuration is not working on ruby core repository.
+
+Mon Sep 5 19:35:22 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rdoc/*, test/rdoc/*: Update rdoc/rdoc master(f191513)
+ https://github.com/rdoc/rdoc/blob/master/History.rdoc#423--2016--
+ https://github.com/rdoc/rdoc/blob/master/History.rdoc#422--2016-02-09
+
+Sun Sep 4 00:17:55 2016 Sho Hashimoto <sho-h@ruby-lang.org>
+
+ * proc.c: [DOC] fix Object#define_singleton_method and
+ main.define_method return value. [ci skip]
+
+Sat Sep 3 11:28:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread_pthread.c (ruby_init_stack): check stack bounds even if
+ get_main_stack succeeded, on the "co-routine" case.
+ https://github.com/ruby/ruby/commit/53953ee#commitcomment-18887413
+
+Fri Sep 2 16:06:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * internal.h (MEMO_V1_SET, MEMO_V2_SET): fix typos. use the macro
+ parameter, not the local variable.
+
+Fri Sep 2 00:55:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb (timestamp_file): move extmk.rb specific tricks
+ from lib/mkmf.rb. keep RUBYCOMMONDIR prefix not to conflict
+ with a timestamp file in the toplevel.
+
+Thu Sep 1 14:24:16 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb (gems): move dirty hacks for bundled gems from
+ mkmf.rb.
+
+ * lib/mkmf.rb (create_makefile): yield all configuration strings.
+
+Wed Aug 31 17:39:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb (create_makefile): make gem.build_complete file
+ under TARGET_SO_DIR and install it only when the gem build
+ succeeded. [ruby-core:77057] [Bug #12681]
+
+Wed Aug 31 15:36:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb: move TARGET_SO_DIR stuffs to mkmf.rb.
+
+ * lib/mkmf.rb (create_makefile): create target shared object files
+ under $(TARGET_SO_DIR) which is $sodir if it is defined with
+ $extout. [ruby-core:77058] [Bug #12681]
+
+Wed Aug 31 01:56:55 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * doc/extension.ja.rdoc: [DOC] Fix a typo. [ci skip]
+
+Wed Aug 31 00:52:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb: make the gems target directory under the expanded
+ name. [ruby-core:77102] [Bug #12714]
+
+Tue Aug 30 15:27:27 2016 Kouhei Yanagita <yanagi@shakenbu.org>
+
+ * ext/json/lib/json/add/ostruct.rb (OpenStruct.json_create):
+ Correct documentation, fix the name of values. [Fix GH-1421]
+
+Tue Aug 30 14:53:34 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * io.c (nogvl_fsync, nogvl_fdatasync): on Windows, just ignore if the
+ fd is associated to non-disk device. if call fsync and/or fdatasync
+ with such fds, it causes Errno::EBADF exception and the behavior is
+ incompatible with ruby 2.1 and earlier unintentionally introduced.
+
+Tue Aug 30 03:38:35 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_dump.c (backtrace): use rip in the saved context for the case
+ the SIGSEGV is received when the process is in userland.
+ Note that ip in the stack should be used if the signal is received
+ when it is in kernel (when it is calling syscall) [Bug #12711]
+
+Sat Aug 27 10:26:14 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * array.c (rb_ary_concat_multi): take multiple arguments. based
+ on the patch by Satoru Horie. [Feature #12333]
+
+ * string.c (rb_str_concat_multi, rb_str_prepend_multi): ditto.
+
+Thu Aug 25 00:42:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/file.c (append_wstr): remove a codepage argument, and use
+ INVALID_CODE_PAGE for conversion by econv.
+
+ * win32/file.c (append_wstr): exclude the terminator from the
+ result length when input len == -1.
+
+Wed Aug 24 22:41:30 2016 Kouhei Sutou <kou@cozmixng.org>
+
+ * gc.c (gc_reset_malloc_info): Remove too much ";".
+
+Wed Aug 24 20:07:57 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * include/ruby/defines.h (ALWAYS_INLINE): Add alternative definition.
+ Fix compile error with compilers that do not have force inline
+ attribute, including old version of fcc on Solaris 10.
+ [ruby-dev:49773] [Bug #12701]
+
+Wed Aug 24 16:56:26 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * .gdbinit: follow r55766's VM change.
+
+Wed Aug 24 12:57:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_mod_initialize, rb_class_initialize): [DOC] these
+ methods do not invoke module_eval/class_eval, just eval the
+ given block under the new module/class but sharing the context
+ with the surrounding scope like those methods.
+ [ruby-core:77023] [Bug #12696]
+
+Tue Aug 23 10:34:40 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/psych/test_psych.rb (test_load_file_with_fallback): fix
+ Tempfile leak. https://github.com/tenderlove/psych/pull/288
+
+Tue Aug 23 10:15:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_fs_setter): check and convert $; value at
+ assignment.
+
+Tue Aug 23 02:09:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_split_m): show $; name in error message when it
+ is a wrong object.
+
+Mon Aug 22 16:29:52 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/csv.rb (CSV#shift): store partial quoted strings in an array
+ and join at last, to improve performance with very long quoted
+ lines. [ruby-core:76987] [Bug #12691]
+
+Mon Aug 22 14:35:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * man/irb.1: remove useless -width option.
+ [ruby-dev:49767] [Bug #12692]
+
+Mon Aug 22 09:02:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * iseq.c (Init_ISeq): undefine allocator of InstructionSequence,
+ to get rid of segfaults at method call on uninitialized object.
+
+Sat Aug 21 05:47:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * enum.c (enum_sort): prevent wasteful array duplication.
+
+Sat Aug 20 11:20:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * rubystub.c: generalize win32/stub.c.
+
+Fri Aug 19 11:39:06 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (primary): allow parenthesised statement as a method
+ argument. [Feature #12686]
+
+Fri Aug 19 09:12:45 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm.c (vm_set_main_stack): TOPLEVEL_BINDING must be built.
+ http://www.viva64.com/en/b/0414/#ID0EQ1CI [ruby-core:76973]
+
+Fri Aug 19 01:00:53 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * proc.c (mnew_missing): Remove an unused argument.
+ After r51126 rid is not used.
+
+Thu Aug 18 09:26:52 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * gems/bundled_gems: bump to test-unit-3.2.1
+
+Thu Aug 18 02:36:26 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/rbinstall.rb: skip gems which failed to build extensions.
+ [ruby-dev:49764] [Bug #12683]
+
+Wed Aug 17 23:35:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gems/bundled_gems (tk): bump up to 0.1.1.
+
+Wed Aug 17 23:14:42 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb: build gem extensions into separate directories
+
+ * tool/rbinstall.rb: install pre-built gem extension files gem
+ extension directories. [ruby-core:76931] [Bug #12681]
+
+Tue Aug 16 21:04:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (UNICODE_HDR_DIR): separate unicode header files from
+ unicode data files. [ruby-core:76879] [Bug #12677]
+
+Tue Aug 16 11:17:51 2016 Koichi ITO <koic.ito@gmail.com>
+
+ * lib/net/http/header.rb: Fix typo. [ci skip][fix GH-1407]
+ * transcode.c: ditto.
+
+Tue Aug 16 11:02:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/make-snapshot (package): save generated header files from
+ unicode data. [ruby-core:76879] [Bug #12677]
+
+Mon Aug 15 20:31:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * node.c (dump_array): show nd_alen field in NODE_ARRAY only in
+ the first node. it is nd_end in the rest nodes.
+
+Mon Aug 15 16:41:32 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * appveyor.yml: Update libressl version to 2.3.7.
+
+Mon Aug 15 11:46:50 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb (extmake): extension libraries in gems cannot link
+ statically.
+
+Sun Aug 14 22:35:40 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * id_table.c (hash_table_extend): should not shrink the table than
+ the previous capacity. [ruby-core:76534] [Bug #12614]
+
+Sun Aug 14 18:51:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gems/bundled_gems: add gemified tk 0.1.0.
+ this needs `extract-gems` to build.
+
+Sun Aug 14 14:54:14 2016 Kouhei Sutou <kou@cozmixng.org>
+
+ * object.c (InitVM_Object): Update referenced document path.
+
+Sat Aug 13 23:08:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (num_funcall0, num_funcall1): get rid of infinite
+ recursion in fallback methods of Numeric.
+
+Sat Aug 13 11:10:08 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (command_asgn, arg): fix syntax errors with chained
+ assignment with op assign. [Bug #12669]
+
+Sat Aug 13 10:52:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (stmt, arg): rescue modifier in command op assignment
+ should be limited to rhs only. [ruby-core:75621] [Bug #12402]
+
+Sat Aug 13 07:51:40 2016 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_val2variant): fix integer conversion in
+ cygwin64.
+
+Fri Aug 12 21:05:19 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/webrick/config.rb (WEBrick::Config::General):
+ disable reverse lookup by default. [ruby-core:45514] [Feature #6559]
+ Socket.do_not_reverse_lookup is true by default but WEBrick
+ overwrote it.
+ patch by Eric Hodel [ruby-core:45527]
+
+Fri Aug 12 12:50:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (rb_syntax_error_append): fix newline in syntax error
+ message to the beginning, not after file name and line number.
+ [Feature #11951]
+
+Thu Aug 11 16:24:23 2016 Ferdinand Niedermann <nerdinand@nerdinand.com>
+
+ * compar.c (cmp_clamp): Introduce Comparable#clamp. [Feature #10594]
+
+Thu Aug 11 03:16:59 2016 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/prime.rb: Optimize prime?
+ Adapted from patch by Jabari Zakiya [#12665]
+
+ * test/test_prime.rb: Improve test
+
+Wed Aug 10 22:37:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (command_rhs, arg_rhs): introduce new rules to reduce
+ repeated rules with rescue modifier.
+
+Wed Aug 10 17:26:43 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (command_asgn): rescue modifier in command assignment
+ should be limited to rhs only. [ruby-core:75621] [Bug #12402]
+
+Wed Aug 10 15:35:03 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32/resolv/resolv.c: needs windows.h for iphlpapi.h on
+ cygwin. [ruby-core:76791] [Bug #12663]
+
+ * ext/win32/resolv/resolv.c (w32error_make_error): use
+ Win32::Resolv::Error, an alias of Win32::Registry::Error.
+
+Tue Aug 9 17:50:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * hash.c (rb_hash_map_v, rb_hash_map_v_bang): implement Hash#map_v and
+ Hash#map_v! [Feature #12512] [ruby-core:76095]
+
+ * test/ruby/test_hash.rb: add tests for above change.
+
+Tue Aug 9 16:09:03 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_getivar): use always_inline because
+ gcc7 doesn't inline this without always_inline.
+
+Tue Aug 9 15:41:24 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/tk: Tk is removed from stdlib. [Feature #8539]
+ https://github.com/ruby/tk is the new upstream.
+
+Tue Aug 9 00:12:31 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * doc/maintainers.rdoc: Remove moved file section.
+
+Mon Aug 8 20:56:46 2016 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/sample/excel1.rb, ext/win32ole/sample/excel2.rb,
+ ext/win32ole/sample/excel3.rb, ext/win32ole/sample/ie.rb,
+ ext/win32ole/sample/ienavi.rb, ext/win32ole/sample/ienavi2.rb: use
+ true instead of deprecated TRUE. [ci skip]
+
+Mon Aug 8 12:51:12 2016 Zarko Todorovski <zarko@ca.ibm.com>
+
+ * internal.h (RBASIC_CLEAR_CLASS): Reroute ANSI C's strict
+ aliasing rule.
+ [ruby-core:74427][Bug #12191][ruby-core:76747][Bug #12657]
+
+Sun Aug 7 18:08:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (InitVM_Object): deprecate toplevel constants TRUE,
+ FALSE, and NIL. [Feature #12574]
+
+Sun Aug 7 06:48:21 2016 Eric Wong <e@80x24.org>
+
+ * ext/openssl/ossl_ssl.c (ossl_ssl_write_internal):
+ avoid undefined behavior
+ * test/openssl/test_pair.rb (test_write_zero): new test
+ [ruby-core:76751] [Bug #12660]
+
+Sat Aug 6 09:35:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * id_table.h (rb_id_table_iterator_result): add dummy sentinel
+ member because C standard prohibits a trailing comma.
+
+Sat Aug 6 00:39:44 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (env_enc_str_new): make string for an environment
+ variable name or value.
+
+ * hash.c (env_name_new): make environment value string with the
+ encoding for its name.
+
+Fri Aug 5 23:18:35 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * hash.c (env_str_new): taint the string. get rid of a test failure
+ introduced at r55811.
+
+Fri Aug 5 17:04:02 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (w32_getenv): call rb_w32_getenv and rb_w32_ugetenv via
+ this pointer without further comparisons.
+
+Thu Aug 4 11:54:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (env_assoc): the encoding of the value should be the
+ locale, as well as other methods, [], fetch, values, etc.
+
+Wed Aug 3 21:31:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (reg_fragment_enc_error): compile_error is different
+ between parser and ripper. [ruby-core:76397] [Bug #12651]
+
+Wed Aug 3 17:15:06 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_obj_clone2): restrict freeze option to true other
+ than false which only has the effect. [Feature #12300]
+
+Wed Aug 3 10:47:07 2016 Koichi Sasada <ko1@atdot.net>
+
+ * vm_core.h: introduce VM_FRAME_RUBYFRAME_P()
+ and VM_FRAME_CFRAME_P().
+ Most of case, RUBY_VM_NORMAL_ISEQ_P() is no
+ longer needed.
+
+ * vm_core.h: introduce rb_obj_is_iseq().
+
+ * cont.c, vm.c: VM_FRAME_MAGIC_DUMMY with
+ VM_FRAME_FLAG_CFRAME.
+
+Wed Aug 3 09:25:16 2016 Koichi Sasada <ko1@atdot.net>
+
+ * vm_core.h: rename macros and make them inline functions.
+
+ * rename VM_FRAME_TYPE_FINISH_P() to VM_FRAME_FINISHED_P().
+ * rename VM_FRAME_TYPE_BMETHOD_P() to VM_FRAME_BMETHOD_P().
+
+Wed Aug 03 09:15:02 2016 Koichi Sasada <ko1@atdot.net>
+
+ * vm_core.h: introduce VM_FRAME_FLAG_CFRAME to represent cfp->iseq
+ type.
+
+Tue Aug 2 21:42:40 2016 Chia-sheng Chen <qitar888@gmail.com>
+
+ * math.c (tanh): make faster by the extract form if three
+ hyperbolic functions are unavailable. [Feature #12647]
+
+Tue Aug 2 12:37:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/option.c, ext/socket/rubysocket.h (inet_ntop): share
+ the fallback definition. [ruby-core:76646] [Bug #12645]
+
+Tue Aug 2 04:07:29 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (set_pioinfo_extra): use more reliable way to search
+ the position of pioinfo of VC14, and also support debug library of it.
+ patched by davispuh AT gmail.com
+ [ruby-core:76644] [Bug #12644]
+ this fixes also [Bug #12631]
+
+Mon Aug 1 21:39:52 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb: [EXPERIMENTAL] build extension libraries in
+ extracted gems.
+
+Mon Aug 1 16:07:18 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * include/ruby/ruby.h (struct RStruct): no longer.
+
+ * internal.h (struct RStruct): moved here.
+
+ * struct.c (rb_struct_ptr): a compensation function for the lack
+ of RSTRUCT_PTR. But now that we have RSTRUCT_GET/SET, that must
+ not be used anyway. I mark this deprecated. Dont use it.
+
+Mon Aug 1 14:50:06 2016 Jeremy Evans <code@jeremyevans.net>
+
+ * object.c (rb_obj_clone2): Allow Object#clone to take freeze:
+ false keyword argument to not freeze the clone.
+ [ruby-core:75017][Feature #12300]
+
+ * test/ruby/test_object.rb (TestObject): test for it.
+
+Mon Aug 1 12:16:19 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * ext/json/*, test/json/json_parser_test.rb: Update json-2.0.2.
+
+Sun Jul 31 16:17:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32/resolv/resolv.c (get_dns_server_list): [Win32] get DNS
+ servers only for connected network devices by GetNetworkParams
+ API. [Bug #12604]
+
+Sat Jul 30 12:13:26 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c (String#downcase), NEWS: Mentioned that case mapping for all
+ of ISO-8859-1~16 is now supported. [ci skip]
+
+Sat Jul 30 12:00:01 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_2.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for ISO-8859-2, by Yushiro Ishii.
+
+Fri Jul 29 20:57:12 2016 chuanshuo <lilijreey@126.com>
+
+ * *.c: rename rb_funcall2 to rb_funcallv, except for extensions
+ which are/will be/may be gems. [Fix GH-1406]
+
+Fri Jul 29 10:51:34 2016 Koichi Sasada <ko1@atdot.net>
+
+ * proc.c (env_write): remove unused function.
+
+Fri Jul 29 10:49:52 2016 Koichi Sasada <ko1@atdot.net>
+
+ * vm_core.h (VM_LOCAL_P): should return an integer value.
+ reported at
+ http://d.hatena.ne.jp/nagachika/20160728/ruby_trunk_changes_55764_55770
+
+Fri Jul 29 04:23:08 2016 Koichi Sasada <ko1@atdot.net>
+
+ * vm_core.h (VM_ENV_LOCAL_P): return truthy (0 or not) value.
+
+ * vm.c (rb_vm_make_proc_lambda): use VM_ENV_ESCAPED_P() macro.
+
+Fri Jul 29 03:49:04 2016 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c, internal.h: remove RubyVM::Env class and all of env objects
+ are imemo objects (imemo_env).
+
+ * NEWS: describe this change. I believe nobody touch these objects
+ because there are no method defined.
+
+ * vm_core.h: remove the following definitions.
+ * rb_cEnv decl.
+ * GetEnvPtr() because Env is no longer T_DATA object.
+
+ * vm_core.h (rb_env_t): fix layout for imemo values.
+
+ * vm_core.h (vm_assert_env): added.
+
+ * vm_core.h (vm_env_new): added.
+
+Thu Jul 28 19:53:21 2016 Koichi Sasada <ko1@atdot.net>
+
+ * vm_core.h: revisit the structure of frame, block and env.
+ [Bug #12628]
+
+ This patch introduce many changes.
+
+ * Introduce concept of "Block Handler (BH)" to represent
+ passed blocks.
+
+ * move rb_control_frame_t::flag to ep[0] (as a special local
+ variable). This flags represents not only frame type, but also
+ env flags such as escaped.
+
+ * rename `rb_block_t` to `struct rb_block`.
+
+ * Make Proc, Binding and RubyVM::Env objects wb-protected.
+
+ Check [Bug #12628] for more details.
+
+Thu Jul 28 15:05:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (ruby_fl_type): use __extension__ to get rid
+ of pedantic warning against RUBY_FL_USER19.
+ https://github.com/skylightio/skylight-ruby/issues/64
+
+ * include/ruby/ruby.h (rb_mul_size_overflow): ditto for use of
+ int128.
+
+Wed Jul 27 10:32:59 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/windows_1253.c: Remove dead code found by Coverity Scan.
+
+Tue Jul 26 22:43:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (run_finalizer): make saved running finalizer state
+ volatile to ensure not to be clobbered by longjmp.
+
+Tue Jul 26 19:26:00 2016 Koichi Sasada <ko1@atdot.net>
+
+ * vm_insnhelper.c: introduce rb_vm_pop_frame() and use it
+ instead of setting rb_thread_t::cfp directly.
+
+ * vm_insnhelper.c (vm_pop_frame): return the result of
+ finish frame or not.
+
+Tue Jul 26 19:06:39 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (rb_raw_obj_info): support to show Proc obj.
+
+Tue Jul 26 18:55:55 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_mark): add `inline' explicitly.
+ I expected to inline this function implicitly at the loop
+ (ex: marking T_ARRAY objects) but sometimes it remains as
+ normal call.
+
+Tue Jul 26 16:33:16 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/windows_1257.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for Windows-1257, by Sho Koike.
+
+Tue Jul 26 16:19:41 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/windows_1250.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for Windows-1250, by Sho Koike.
+
+ * ChangeLog: Fixed order of previous two entries.
+
+Tue Jul 26 15:54:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/windows_1253.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for Windows-1253, by Takumi Koyama.
+
+Tue Jul 26 15:30:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/windows_1251.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for Windows-1251, by Shunsuke Sato.
+
+Tue Jul 26 13:04:59 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive.rb: Add explicit skip test for
+ availability of Unicode data files.
+
+Mon Jul 25 21:33:13 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * range.c (check_step_domain): check step argument domain by <=>
+ method, instead of < and >.
+
+Mon Jul 25 21:11:32 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * doc/maintainers.rdoc: fix filenames.
+
+Mon Jul 25 16:59:00 2016 Koichi Sasada <ko1@atdot.net>
+
+ * debug.c (ruby_debug_printf): use rb_raw_obj_info()
+ instead of rb_inspect() because it is more robust way
+ to see object internal.
+
+Sun Jul 24 16:33:13 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * regenc.h/c, include/ruby/oniguruma.h, enc/ascii.c, big5.c, cp949.c,
+ emacs_mule.c, euc_jp.c, euc_kr.c, euc_tw.c, gb18030.c, gbk.c,
+ iso_8859_1|2|3|4|5|6|7|8|9|10|11|13|14|15|16.c, koi8_r.c, koi8_u.c,
+ shift_jis.c, unicode.c, us_ascii.c, utf_16|32be|le.c, utf_8.c,
+ windows_1250|51|52|53|54|57.c, windows_31j.c, unicode.c:
+ Remove conditional compilation macro ONIG_CASE_MAPPING. [Feature #12386].
+
+Sun Jul 24 12:53:42 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * doc/maintainers.rdoc: xmlrpc is bundled gem from Ruby 2.4.
+
+Sun Jul 24 12:07:39 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * doc/maintainers.rdoc: Update OpenSSL maintainer.
+
+Sat Jul 23 22:43:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * internal.h (Check_Type): inline check for the object type.
+
+Sat Jul 23 04:06:04 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (RTEST, NIL_P): use RUBY prefixed name in
+ macros.
+
+Sat Jul 23 01:41:29 2016 Eric Wong <e@80x24.org>
+
+ * lib/webrick/httpservlet/cgihandler.rb (do_GET): delete HTTP_PROXY
+ * test/webrick/test_cgi.rb (test_cgi_env): new test
+ * test/webrick/webrick.cgi (do_GET): new endpoint to dump env
+ [ruby-core:76511] [Bug #12610]
+
+Fri Jul 22 19:55:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm.c (vm_set_main_stack): remove unnecessary check. toplevel
+ binding must be initialized. [Bug #12611] (N1)
+
+ * win32/win32.c (w32_symlink): fix return type. [Bug #12611] (N3)
+
+ * string.c (rb_str_split_m): simplify the condition.
+ [Bug #12611](N4)
+
+Fri Jul 22 17:13:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c (String#dump): Change escaping of non-ASCII characters in
+ UTF-8 to use upper-case four-digit hexadecimal escapes without braces
+ where possible [Feature #12419].
+
+ * test/ruby/test_string.rb (test_dump): Add tests for above.
+
+Fri Jul 22 10:35:35 2016 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/rexml/attribute.rb (REXML::Attribute#to_string): Fix wrong
+ entry reference name of double quote.
+ [Bug #12609][ruby-core:76509]
+ Patch by Joseph Marrero. Thanks!!!
+
+Fri Jul 22 10:32:13 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * template/unicode_norm_gen.tmpl: Remove
+ UnicodeNormalize::UNICODE_VERSION at origin [Feature #12546].
+
+Fri Jul 22 09:23:51 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * LEGAL: Added entries for files under the USD license.
+ [Bug #12598][ruby-core:76428][ci skip]
+
+Fri Jul 22 09:19:57 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * LEGAL: Added entry for `lib/rdoc/generator/template/darkfish/css/fonts.css`
+ [Misc #12550][ruby-core:76255][ci skip]
+
+Fri Jul 22 06:28:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (run_finalizer): push and exec tag just once, instead of
+ protecting for each finalizer.
+
+ * gc.c (gc_start_internal, rb_gc_start): set finalizing flag
+ whenever calling deferred finalizers not to recurse.
+
+Thu Jul 21 22:26:40 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * missing/strl{cat,cpy}.c: Update latest upstream files.
+ [Misc #12205][ruby-core:74487]
+ * LEGAL: Update license for missing/strl{cat,cpy}.c.
+
+Thu Jul 21 21:53:30 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * LEGAL: added file list with Public domain license.
+ [ruby-core:76254][Bug #12549]
+
+Wed Jul 20 17:44:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enumerator.c (lazy_uniq): new method Enumerator::Lazy#uniq.
+ [Feature #11090]
+
+ * enum.c (enum_uniq): new method Enumerable#uniq.
+ [Feature #11090]
+
+Wed Jul 20 17:35:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (rb_hash_add_new_element): add new element or do nothing
+ if it is contained already.
+
+ * array.c (ary_add_hash, ary_add_hash_by): use
+ rb_hash_add_new_element.
+
+Tue Jul 19 18:21:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * lib/unicode_normalize/tables.rb: Remove
+ UnicodeNormalize::UNICODE_VERSION (#12546).
+
+Tue Jul 19 15:38:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * variable.c (rb_local_constants_i): exclude private constants
+ when excluding inherited constants too. [Bug #12345]
+
+Sun Jul 17 23:42:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * numeric.c (num_finite_p, num_infinite_p): Add Numeric#finite? and
+ Numeric#infinite? [Feature #12039] [ruby-core:73618]
+
+ * complex.c (rb_complex_finite_p): Add Complex#finite?
+
+ * complex.c (rb_complex_infinite_p): Add Complex#infinite?
+
+ * test/ruby/test_bignum.rb: Add test for Integer#finite? and
+ Integer#infinite?
+
+ * test/ruby/test_fixnum.rb: ditto.
+
+ * test/ruby/test_rational.rb: Add test for Rational#finite? and
+ Rational#infinite?
+
+ * test/ruby/test_complex.rb: Add test for Complex#finite? and
+ Complex#infinite?
+
+Sun Jul 17 20:59:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk, enc/depend (casefold.h, name2ctype.h): move to
+ unicode data directory per version.
+
+Sat Jul 16 06:26:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk, enc/Makefile.in: moved timestamp files for
+ directories under the specific directory, to get rid of match
+ with files under the source directory.
+
+Fri Jul 15 22:05:13 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * string.c (str_buf_cat): Fix potential integer overflow of capa.
+ In addition, termlen is used instead of +1.
+
+Fri Jul 15 21:30:38 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * string.c (str_buf_cat): Fix capa size for embed string.
+ Fix bug in r55547. [Bug #12536]
+
+Fri Jul 15 18:13:15 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * gems/bundled_gems: update latest gems.
+
+Fri Jul 15 17:08:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * util.c (ruby_strtod): do not underflow only by preceding zeros,
+ which may be canceled out by the exponent.
+ http://twitter.com/kazuho/status/753829998767714305
+
+Fri Jul 15 09:53:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enc/unicode/case-folding.rb, tool/enc-unicode.rb: check if
+ Unicode versions are consistent with each other.
+
+Fri Jul 15 08:25:15 2016 Jeremy Evans <code@jeremyevans.net>
+
+ * string.c (STR_BUF_MIN_SIZE): reduce from 128 to 127
+ [ruby-core:76371] [Feature #12025]
+ * string.c (rb_str_buf_new): adjust for above reduction
+
+Thu Jul 14 17:26:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * Makefile.in (enc/unicode/name2ctype.h): remove stale recipe,
+ which did not support Unicode age properties.
+
+ * common.mk (enc/unicode/name2ctype.h): update by --header option
+ of tool/enc-unicode.rb. enc/unicode/name2ctype.kwd file has not
+ been used.
+
+ * common.mk (enc/unicode/name2ctype.kwd): rule to create from
+ Unicode data files, used only when the target does not exist.
+
+Thu Jul 14 13:10:54 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/json/lib/json/ext: remove stale directory. bundled
+ extension libraries are placed under the directory for each
+ architectures, but not mixed with plain text script libraries.
+
+Thu Jul 14 12:48:47 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * ext/json/**/*.rb: merge original files from upstream repository.
+ It only fixes styles of frozen string literal.
+
+Wed Jul 13 22:23:03 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * test/json/json_common_interface_test.rb: use assert_raise instead of
+ assert_raises.
+
+Wed Jul 13 22:14:23 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * test/lib/test/unit.rb: added test files with `_test` suffix for json
+ upstream.
+ * test/json: merge original test files from json upstream.
+
+Wed Jul 13 18:09:42 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_9.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for ISO-8859-9, by Kazuki Iijima.
+
+ * enc/iso_8859_9.c: Exclude dotless i/I with dot from case-insensitive
+ matching because they are not a case pair.
+
+ * test/ruby/enc/test_iso_8859.rb: Make test coverage for ISO-8859-9
+ a bit more complete.
+
+Wed Jul 13 17:21:24 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/windows_1252.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for Windows-1252, by Serina Tai.
+
+ * test/ruby/enc/test_case_comprehensive.rb: Fix order of encodings.
+
+Wed Jul 13 16:19:14 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_7.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for ISO-8859-7, by Kosuke Kurihara.
+
+ * test/ruby/enc/test_case_comprehensive.rb: Fix order of encodings.
+
+Wed Jul 13 16:08:08 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_mark_roots): should mark the VM object itself to mark
+ singleton class of the VM object.
+ Before this patch, we only set mark bit for the VM object and
+ invoke mark function separately.
+ [Bug #12583]
+
+ * test/ruby/test_gc.rb: add a test.
+
+Wed Jul 13 15:59:59 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * math.c (_USE_MATH_DEFINES): it must be set before including internal.h
+ because internal.h includes ruby.h, ruby.h includes win32.h, and
+ win32.h includes system's math.h.
+ this change is to get rid of a compiler warning (redefinition of
+ a macro) introduced at r55641.
+
+Wed Jul 13 15:19:03 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_1.c, enc/iso_8859_4.c: Avoid setting modification flag if
+ there is no modification.
+
+Wed Jul 13 14:40:04 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_5.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for ISO-8859-5, by Masaru Onodera.
+
+ * test/ruby/enc/test_case_comprehensive.rb: Fix order of encodings.
+
+Wed Jul 13 14:28:33 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * math.c (rb_math_sqrt): r55646 must use f_signbit.
+
+Wed Jul 13 14:22:50 2016 Koichi Sasada <ko1@atdot.net>
+
+ * iseq.c (Init_ISeq): undef ISeq.translate and ISeq.load_iseq
+ to prevent calling super classes' methods.
+
+ Without this patch, you can write workaround like:
+
+ class << RubyVM::InstructionSequence
+ def translate; end
+ undef translate
+ end
+
+ * test/ruby/test_iseq.rb: add a test.
+
+Wed Jul 13 14:16:03 2016 Koichi Sasada <ko1@atdot.net>
+
+ * vm_method.c (method_entry_get_without_cache): check
+ undefined method even if ruby_running is FALSE.
+
+ We haven't call "undef"ed methods before ruby_running.
+ So that this issue does not make troubles.
+
+Wed Jul 13 14:15:22 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/windows_1254.c: Adjust variable/macro names.
+
+Wed Jul 13 13:19:12 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_9.c, enc/windows_1254.c: Split Windows-1254 from
+ ISO-8859-9 to be able to implement different case conversions.
+
+Wed Jul 13 13:08:30 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_7.c, enc/windows_1253.c: Split Windows-1253 from
+ ISO-8859-7 to be able to implement different case conversions.
+
+Wed Jul 13 10:50:12 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_13.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for ISO-8859-13, by Kanon Shindo.
+
+Wed Jul 13 10:31:39 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_13.c, enc/windows_1257.c: Split Windows-1257 from
+ ISO-8859-13 to be able to implement different case conversions.
+
+Wed Jul 13 09:02:30 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_3.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for ISO-8859-3, by Takuya Miyamoto.
+
+ * test/ruby/enc/test_case_comprehensive.rb: Extend special treatment
+ for Turkic.
+
+ * enc/iso_8859_3.c: Exclude dotless i/I with dot from case-insensitive
+ matching because they are not a case pair.
+
+Wed Jul 13 08:40:21 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_iso_8859.rb: Exclude dotless i/I with dot from
+ case-insensitive matching because they are not a case pair.
+
+Tue Jul 12 23:13:43 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * math.c (rb_math_sqrt): [EXPERIMENTAL] move Complex sqrt support
+ from mathn.rb.
+
+Tue Jul 12 01:25:09 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * configure.in, lib/mkmf.rb, win32/Makefile.sub (CSRCFLAG): make the
+ compiler option replacable in Makefile.
+
+ * win32/Makefile.sub (OUTFLAG, COUTFLAG): ditto.
+
+ * win32/Makeile.sub, win32/setup.mak (CC): should not append `-nologo`
+ option forcely.
+
+Mon Jul 11 18:05:40 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_1.c: Moved test for lowercase characters without
+ uppercase equivalent.
+
+Mon Jul 11 17:49:25 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_4.c, enc/iso_8859_10.c, enc/iso_8859_14.c,
+ enc/iso_8859_15.c, enc/iso_8859_16.c: Replace case-by-case code with
+ lookup in ENC_ISO_8859_xx_TO_LOWER_CASE table.
+
+Mon Jul 11 16:00:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/stringio/stringio.c (strio_each, strio_readlines): convert
+ arguments just once before reading, instead of conversions for
+ each lines, as r55603.
+
+Sun Jul 10 19:53:41 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_10.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for ISO-8859-10, by Toya Hosokawa.
+
+Sun Jul 10 19:33:47 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive.rb: Changed testing logic to
+ catch unintended modifications of characters that do not have a case
+ equivalent in the respective encoding.
+ * enc/iso_8859_1.c, enc/iso_8859_15.c: Fixed unintended modifications of
+ micro sign and y with diaeresis.
+
+Sun Jul 10 17:05:36 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_4.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for ISO-8859-4, by Kotaro Yoshida.
+
+Sun Jul 10 16:17:47 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive.rb: Fixed a comment
+ (message belongs to last commit). [ci skip]
+
+Sun Jul 10 14:27:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * util.c (ruby_dtoa): [EXPERIMENTAL] adjust the case that the
+ Float value is close to the exact but unrepresentable middle
+ value of two values in the given precision, as r55604.
+
+Sun Jul 10 08:57:20 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * thread.c: Fixed implicit conversion error with Apple clang-800.0.31
+
+Sat Jul 9 12:43:09 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/getoptlong.rb: use false instead of FALSE.
+
+Fri Jul 8 21:49:28 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * thread.c (rb_wait_for_single_fd): Clean up fds.revents every time
+ before calling ppoll(2). [Bug #12575] [ruby-dev:49725]
+
+Fri Jul 8 14:16:48 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * vm_args.c (vm_caller_setup_arg_block): call rb_sym_to_proc()
+ directly to reduce method dispatch overhead.
+
+Fri Jul 8 08:43:31 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * io.c (rb_io_s_read): add description of pipes to the documentation
+ of IO.read.
+
+Fri Jul 8 03:54:22 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_args.c (setup_parameters_complex): don't raise ArgumentError
+ if an array is given for instance_exec with optional argument.
+ [ruby-core:76300] [Bug #12568]
+ https://github.com/rails/rails/pull/25699
+
+Fri Jul 8 00:47:36 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_eval.c (yield_under): change prototype to get argc/argv.
+
+ * vm_eval.c (specific_eval): change for above.
+
+ * vm_eval.c (rb_obj_instance_exec): avoid object allocation.
+
+ * vm_eval.c (rb_mod_module_exec): ditto.
+
+Thu Jul 7 20:08:37 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * vm_args.c (vm_caller_setup_arg_block): disable symbol block
+ argument optimization when tail call optimization is enabled,
+ in order to avoid SEGV. [ruby-core:76288] [Bug #12565]
+
+Thu Jul 7 16:37:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (flo_round): [EXPERIMENTAL] adjust the case that the
+ receiver is close to the exact but unrepresentable middle value
+ of two values in the given precision.
+ http://d.hatena.ne.jp/hnw/20160702
+
+Thu Jul 7 16:31:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (rb_io_s_foreach, rb_io_s_readlines): convert arguments
+ just once before reading, instead of conversions for each lines.
+
+Wed Jul 6 19:54:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_14.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for ISO-8859-14, by Yutaro Tada.
+
+Wed Jul 6 19:24:48 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_1.c, enc/iso_8859_15.c, enc/iso_8859_16.c:
+ Align indenting to onigmo convention.
+
+Wed Jul 6 18:59:13 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_15.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for ISO-8859-15, by Maho Harada.
+
+Wed Jul 6 18:34:21 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_16.c, test/ruby/enc/test_case_comprehensive.rb:
+ Implement non-ASCII case conversion for ISO-8859-16, by Satoshi Kayama.
+
+Wed Jul 6 14:44:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (create_makefile): store $headers in LOCAL_HDRS for
+ depend files.
+
+ * ext/digest/digest_conf.rb (digest_conf): add implementation
+ specific headers to $header.
+
+ * ext/digest/{md5,rmd160,sha1,sha2}/depend: add LOCAL_HDRS to the
+ dependencies.
+
+Wed Jul 6 08:59:35 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/http/generic_request.rb (write_header): A Request-Line must
+ not contain CR or LF.
+
+Wed Jul 6 07:11:27 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/ftp.rb (putline): raise an ArgumentError when
+ CR or LF is included in a line.
+
+Tue Jul 5 20:49:30 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * ext/json/*, test/json/*: Update json-2.0.1.
+ Changes of 2.0.0: https://github.com/flori/json/blob/f679ebd0c69a94e3e70a897ac9a229f5779c2ee1/CHANGES.md#2015-09-11-200
+ Changes of 2.0.1: https://github.com/flori/json/blob/f679ebd0c69a94e3e70a897ac9a229f5779c2ee1/CHANGES.md#2016-07-01-201
+ [Feature #12542][ruby-dev:49706][fix GH-1395]
+
+Tue Jul 5 19:39:49 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * string.c (rb_str_change_terminator_length): New function to change
+ termlen and resize heap for the terminator. This is split from
+ rb_str_fill_terminator (str_fill_term) because filling terminator
+ and changing terminator length are different things. [Bug #12536]
+
+ * internal.h: declaration for rb_str_change_terminator_length.
+
+ * string.c (str_fill_term): Simplify only to zero-fill the terminator.
+ For non-shared strings, it assumes that (capa + termlen) bytes of
+ heap is allocated. This partially reverts r55557.
+
+ * encoding.c (rb_enc_associate_index): rb_str_change_terminator_length
+ is used, and it should be called whenever the termlen is changed.
+
+ * string.c (str_capacity): New static function to return capacity
+ of a string with the given termlen, because the termlen may
+ sometimes be different from TERM_LEN(str) especially during
+ changing termlen or filling terminator with specific termlen.
+
+ * string.c (rb_str_capacity): Use str_capacity.
+
+Tue Jul 5 11:07:14 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * pack.c (pack_pack): use union instead of bare variable to ease
+ optimizations and avoid assigning x87 floating point number.
+ [ruby-core:74496] [Bug #12209]
+
+ * pack.c (pack_unpack): ditto.
+
+Mon Jul 4 13:56:34 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * process.c: define sig_t if not exist.
+ at least Solaris 10 and 11 doesn't have sig_t.
+
+Mon Jul 4 13:08:48 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * random.c (random_ulong_limited): avoid left shift count >= width of
+ type on 32bit environment.
+
+Sun Jul 3 18:51:42 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive.rb, test_regex_casefold.rb,
+ test/test_unicode_normalize.rb: Replace UNICODE_VERSION from
+ UnicodeNormalize with RbConfig::CONFIG['UNICODE_VERSION'] from
+ feature 12460.
+
+Sun Jul 3 06:04:09 2016 Eric Wong <e@80x24.org>
+
+ * process.c (disable_child_handler_fork_child): simplify
+ [ruby-core:75781] [Misc #12439]
+
+Sun Jul 3 05:25:46 2016 Eric Wong <e@80x24.org>
+
+ * tool/asm_parse.rb: add description
+ * tool/change_maker.rb: ditto
+ * tool/downloader.rb: ditto
+ * tool/eval.rb: ditto
+ * tool/expand-config.rb: ditto
+ * tool/extlibs.rb: ditto
+ * tool/fake.rb: ditto
+ * tool/file2lastrev.rb: ditto
+ * tool/gem-unpack.rb: ditto
+ * tool/gen_dummy_probes.rb: ditto
+ * tool/gen_ruby_tapset.rb: ditto
+ * tool/generic_erb.rb: ditto
+ * tool/id2token.rb: ditto
+ * tool/ifchange: ditto
+ * tool/insns2vm.rb: ditto
+ * tool/instruction.rb: ditto
+ * tool/jisx0208.rb: ditto
+ * tool/merger.rb: ditto
+ * tool/mkrunnable.rb: ditto
+ * tool/node_name.rb: ditto
+ * tool/parse.rb: ditto
+ * tool/rbinstall.rb: ditto
+ * tool/rbuninstall.rb: ditto
+ * tool/rmdirs: ditto
+ * tool/runruby.rb: ditto
+ * tool/strip-rdoc.rb: ditto
+ * tool/vcs.rb: ditto
+ * tool/vtlh.rb: ditto
+ * tool/ytab.sed: ditto
+ * tool/enc-unicode.rb: fix typo
+ * tool/mk_call_iseq_optimized.rb: ditto
+ * tool/update-deps: ditto
+ [ruby-core:76215] [Bug #12539]
+ by Noah Gibbs <the.codefolio.guy@gmail.com>
+
+Sat Jul 2 18:04:24 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/mailto.rb (initialize): RFC3986_Parser#split sets opaque
+ only if the URI has path-rootless, not path-empty.
+ [ruby-core:76055] [Bug #12498]
+ patched by Chris Heisterkamp <cheister@squareup.com>
+
+Sat Jul 2 04:26:14 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * regcomp.c (noname_disable_map): don't optimize out group 0
+ Ruby's Regexp doesn't allow normal numbered groups if the regexp
+ has named groups. On such case it optimizes out related NT_ENCLOSE.
+ But even on the case it can use \g<0>.
+ This fix not to remove NT_ENCLOSE whose regnum is 0.
+ [ruby-core:75828] [Bug #12454]
+
+Sat Jul 2 03:09:27 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * string.c: Partially reverts r55547 and r55555.
+ ChangeLog about the reverted changes are also deleted in this file.
+ [Bug #12536] [ruby-dev:49699] [ruby-dev:49702]
+
+Sat Jul 2 02:22:22 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * string.c (str_fill_term): When termlen increases, re-allocation
+ of memory for termlen should always be needed.
+ In this fix, if possible, decrease capa instead of realloc.
+ [Bug #12536] [ruby-dev:49699]
+
+Fri Jul 1 20:20:20 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * string.c: Specify termlen as far as possible.
+ Additional fix for [Bug #12536] [ruby-dev:49699].
+
+ * string.c (str_new_static): Specify termlen from the given encoding
+ when creating a new String object is needed.
+
+ * string.c (rb_tainted_str_new_with_enc): New function to create a
+ tainted String object with the given encoding. This means that
+ the termlen is correctly specified. Currently static function.
+ The function name might be renamed to rb_tainted_enc_str_new
+ or rb_enc_tainted_str_new.
+
+ * string.c (rb_external_str_new_with_enc): Use encoding by using the
+ above rb_tainted_str_new_with_enc().
+
+Fri Jul 1 19:38:57 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * test/fiddle/test_pointer.rb (test_to_str, test_to_s, test_aref_aset):
+ Attempt to use independent strings for destructive tests that
+ directly modify values on memory by using Fiddle::Pointer.
+ [Bug #12537] [ruby-dev:49700]
+
+Fri Jul 1 18:20:00 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * .gdbinit (rb_ps_thread): show the detail of cfunc in ruby level
+ backtrace.
+
+Fri Jul 1 13:26:39 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * string.c (rb_str_subseq, str_substr): When RSTRING_EMBED_LEN_MAX
+ is used, TERM_LEN(str) should be considered with it because
+ embedded strings are also processed by TERM_FILL.
+ Additional fix for [Bug #12536] [ruby-dev:49699].
+
+Fri Jul 1 12:11:01 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * .gdbinit (rb_count_objects): added gdb version of count_objects().
+
+Fri Jul 1 04:32:52 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * .gdbinit (rb_ps_thread): show ruby level backtrace.
+ Usually you can call `rb_ps` to show ruby level backtraces
+ for all living threads.
+ Note that it can call with core file like `gcore <pid>`
+ and `gdb ruby core.<pid>`.
+
+Thu Jun 30 19:15:13 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * string.c: Fix memory corruptions when using UTF-16/32 strings.
+ [Bug #12536] [ruby-dev:49699]
+
+ * string.c (rb_str_new_with_class): Use TERM_LEN of the "obj".
+
+ * string.c (rb_str_plus, rb_str_justify): Use str_new0 which is aware
+ of termlen.
+
+ * string.c (str_shared_replace): Copy +termlen bytes instead of +1.
+
+ * string.c (rb_str_times): termlen should not be included in capa.
+
+ * string.c (RESIZE_CAPA_TERM): When using RSTRING_EMBED_LEN_MAX,
+ termlen should be counted with it because embedded strings are
+ also processed by TERM_FILL.
+
+ * string.c (rb_str_capacity, str_shared_replace, str_buf_cat): ditto.
+
+ * string.c (rb_str_drop_bytes, rb_str_setbyte, str_byte_substr): ditto.
+
+Wed Jun 29 22:24:37 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * ext/psych/lib/psych_jars.rb: removed needless file required to JRuby.
+
+Wed Jun 29 22:21:38 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_ocsp.c: The "reuse" behavior of d2i_ functions does
+ not work well with OpenSSL 1.0.0t. So avoid it.
+
+Wed Jun 29 15:18:28 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * insns.def (opt_succ): optimize like r55515. (but this argument is
+ constant)
+
+Wed Jun 29 12:41:58 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * test/ruby/test_refinement.rb: skip
+ test_prepend_after_refine_wb_miss on ARM or MIPS.
+ [ruby-core:76031] [Bug #12491]
+
+Wed Jun 29 08:45:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (passed_block): convert passed block symbol to proc.
+ based on the patch by Daisuke Sato in [ruby-dev:49695].
+ [Bug #12531]
+
+Wed Jun 29 03:34:41 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * bignum.c (rb_big2ulong): the old logic seems to try to avoid
+ calculating `-(long)(num-1)-1` if `num` is not LONG_MIN. (Note that
+ `-LONG_MIN` may be larger than LONG_MAX) But C compilers can
+ optimize it into single NEG instruction.
+ Therefore those two conditions can be single if-body.
+
+ * bignum.c (rb_big2long): ditto.
+
+ * bignum.c (rb_big2ull): ditto.
+
+ * bignum.c (rb_big2ll): ditto.
+
+Tue Jun 28 22:55:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/pstore.rb (PStore::CHECKSUM_ALGO): extract the algorithm for
+ checksum, instead of qualified names for each times.
+
+Tue Jun 28 22:29:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bootstraptest/runner.rb: do not use safe navigation operator.
+ this runner may run on older ruby. partially revert r53110
+ (GH-1142 patched by @mlarraz).
+
+Tue Jun 28 22:09:09 2016 Akio Tajima <artonx@yahoo.co.jp>
+
+ * lib/fileutils.rb: rescue Errno:EACCES for chown.
+ [Bug #12520]
+
+Tue Jun 28 18:38:09 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * ext/digest/md5/md5ossl.h: Remove excess semicolons.
+ Suppress warning on Solaris with Oracle Solaris Studio 12.
+ [ruby-dev:49692] [Bug #12524]
+
+ * ext/digest/md5/md5cc.h: ditto.
+ * ext/digest/sha1/sha1cc.h: ditto.
+ * ext/digest/sha1/sha1ossl.h: ditto.
+ * ext/digest/sha2/sha2cc.h: ditto.
+ * ext/digest/sha2/sha2ossl.h: ditto.
+ * ext/openssl/ossl_pkey_rsa.c: ditto.
+
+Tue Jun 28 15:56:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/ruby/enc/test_case_comprehensive.rb: noting to test if
+ Unicode data files are available.
+ [ruby-core:76160] [Bug #12433]
+
+ * test/test_unicode_normalize.rb: ditto.
+
+Tue Jun 28 15:20:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/net/http.rb (Net::HTTP#proxy_uri): cache the case no proxy
+ is used.
+
+Tue Jun 28 09:56:29 2016 Stefan Schussler <mail@stefanschuessler.de>
+
+ * object.c (rb_mod_eqq): [DOC] Fix typo in RDoc. [Fix GH-1393]
+
+Tue Jun 28 02:41:32 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * insns.def (opt_plus): use `- 1` instead of `& (~1)` to allow
+ compilers to use x86 LEA instruction (3 operand).
+ Even if 3 operand LEA's latency is 3 cycle after SandyBridge,
+ it reduces code size and can be faster because of super scalar.
+
+ * insns.def (opt_plus): calculate and use rb_int2big.
+ On positive Fixnum overflow, `recv - 1 + obj` doesn't carry
+ because recv's msb and obj's msb are 0, and resulted msb is 1.
+ Therefore simply rshift and cast as signed long works fine.
+ On negative Fixnum overflow, it will carry because both arguments'
+ msb are 1, and resulted msb is also 1.
+ In this case it needs to restore carried sign bit after rshift.
+
+Mon Jun 27 16:58:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/fileutils.rb (FileUtils#install): accecpt symbolic mode, as
+ well as chmod.
+
+ * lib/fileutils.rb (FileUtils#install): add owner and group
+ options.
+
+Mon Jun 27 08:56:55 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (ADD_TRACE): ignore trace instruction on non-positive
+ line.
+
+ * parse.y (coverage): get rid of ArgumentError when the starting
+ line number is not positive. [ruby-core:76141] [Bug #12517]
+
+Sun Jun 26 10:20:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32/lib/Win32API.rb (Win32API#initialize): Cygwin
+ 2.5.2-1 (perhaps) seems to no longer append ".dll" suffix
+ implicitly.
+
+ * ext/win32/lib/win32/resolv.rb (Win32::Resolv): ditto. Fix the
+ error reported by yamataka AT u08.itscom.net in
+ [ruby-list:50339], and pointed out and patched by cerberus AT
+ m3.kcn.ne.jp in [ruby-list:50341].
+
+Sat Jun 25 10:07:52 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * test/openssl/test_ocsp.rb: Ignore errors caused by bugs that exist in
+ LibreSSL >= 2.3.1.
+
+Sat Jun 25 02:33:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_method.c (vm_respond_to): try method_missing if respond_to?
+ is undefined, as if it is the default definition.
+ [ruby-core:75377] [Bug #12353]
+
+Fri Jun 24 17:04:21 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * ext/psych/*, test/psych/*: Update psych 2.1.0
+ This version fixed [Bug #11988][ruby-core:72850]
+
+Fri Jun 24 13:12:41 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*:
+ Update rubygems 2.6.5 and 2.6.6.
+ Release note of 2.6.5: https://github.com/rubygems/rubygems/commit/656f5d94dc888d78d0d00f3598a4fa37391aac80
+ Release note of 2.6.6: https://github.com/rubygems/rubygems/commit/ccb9c3300c063f5b5656669972d24a10ef8afbf5
+
+Fri Jun 24 09:17:15 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (lib/unicode_normalize/tables.rb): should not depend
+ on Unicode data files unless ALWAYS_UPDATE_UNICODE=yes, to get
+ rid of downloading Unicode data unnecessary. [ruby-dev:49681]
+
+ * common.mk (enc/unicode/casefold.h): update Unicode files in a
+ sub-make, not to let the header depend on the files always.
+
+ * enc/unicode/case-folding.rb: if gperf is not usable, assume the
+ existing file is OK.
+
+Tue Jun 21 19:44:54 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_regex_casefold.rb: Add Windows-1251, KOI8-R, and
+ KOI8-U to encodings; definitely removed EUC-JP.
+
+Tue Jun 21 19:32:23 2016 Mark St.Godard <markstgodard@gmail.com>
+
+ * lib/webrick/httprequest.rb (setup_forwarded_info): Use the first
+ value in X-Forwarded-Proto, if header contains multiple comma
+ separated values. Some middlewares may add these values to the
+ list, not replacing. [Fix GH-1386]
+
+Tue Jun 21 17:17:42 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/test_io.rb: Skip test_readpartial_with_not_empty_buffer,
+ test_read_buffer_error, test_read_unlocktmp_ensure,
+ test_readpartial_unlocktmp_ensure, and
+ test_sysread_unlocktmp_ensure on cygwin,
+ because these tests repeatedly hang. This makes test_io.rb
+ complete in finite time on cygwin.
+
+ * ChangeLog: Fix test_in.rb -> test_io.rb (two instances).
+
+Tue Jun 21 16:38:14 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_casemap): do not put code with side effects
+ inside RSTRING_PTR() macro which evaluates the argument multiple
+ times.
+
+Tue Jun 21 16:13:45 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (rb_str_casemap): fix memory leak.
+
+Tue Jun 21 16:12:21 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (rb_str_casemap): int is too small for string size.
+
+Tue Jun 21 15:42:22 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/test_io.rb: Skip test_read_buffer_error on cygwin,
+ because this test repeatedly hangs.
+
+Tue Jun 21 15:35:14 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * LEGAL: Added filenames and copyrights for some files in
+ enc/trans/JIS.
+
+Tue Jun 21 00:56:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (get_special_folder): fix calling convention of
+ SHGetPathFromIDListEx, which should be WINAPI. pointed out by
+ @arton at http://twitter.com/arton/status/744884064277016576
+
+Tue Jun 21 00:22:02 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in, include/ruby/defines.h (RUBY_USE_SETJMPEX):
+ include setjmpex.h only when using setjmpex() for RUBY_SETJMP.
+ the header of mingw32 overrides setjmp() by setjmpex().
+
+Mon Jun 20 18:39:16 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/test_io.rb: Skip test_open_fifo_does_not_block_other_threads
+ on cygwin. Fifos seem to work okay in cygwin, but this test repeatedly
+ hangs.
+
+Mon Jun 20 13:35:06 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * vm.c (invoke_bmethod, invoke_block_from_c_0): revert r52104
+ partially to avoid "self has wrong type to call super in this
+ context" errors.
+ [ruby-core:72724] [Bug #11954]
+
+Mon Jun 20 12:53:38 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * test/rubygems/test_gem_remote_fetcher.rb: OpenSSL::PKey::DH#priv_key=
+ is not defined when ext/openssl is built with OpenSSL 1.1.0.
+ https://github.com/rubygems/rubygems/pull/1648
+ [ruby-core:75225] [Feature #12324]
+
+Sun Jun 19 21:25:43 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_ocsp.c: Add OCSP::SingleResponse that represents an
+ OCSP SingleResponse structure. Also add two new methods #responses
+ and #find_response to OCSP::BasicResponse. A BasicResponse has one or
+ more SingleResponse. We have OCSP::BasicResponse#status that returns
+ them as an array of arrays, each containing the content of a
+ SingleResponse, but this is not useful. When validating an OCSP
+ response, we need to look into the each SingleResponse and check their
+ validity but it is not simple. For example, when validating for a
+ certificate 'cert', the code would be like:
+
+ # certid_target is an OpenSSL::OCSP::CertificateId for cert
+ basic = res.basic
+ result = basic.status.any? do |ary|
+ ary[0].cmp(certid_target) &&
+ ary[4] <= Time.now && (!ary[5] || Time.now <= ary[5])
+ end
+
+ Adding OCSP::SingleResponse at the same time allows exposing
+ OCSP_check_validity(). With this, the code above can be rewritten as:
+
+ basic = res.basic
+ single = basic.find_response(certid_target)
+ result = single.check_validity
+
+ * test/openssl/test_ocsp.rb: Test this.
+
+Sun Jun 19 18:40:19 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_ocsp.c (ossl_ocspbres_add_status): Allow specifying
+ the times (thisUpdate, nextUpdate and revocationTime) with Time
+ objects. Currently they accepts only relative seconds from the current
+ time. This is inconvenience, especially for revocationTime. When
+ Integer is passed, they are still treated as relative times. Since the
+ type check is currently done with rb_Integer(), this is a slightly
+ incompatible change. Hope no one passes a relative time as String or
+ Time object...
+ Also, allow passing nil as nextUpdate. It is optional.
+
+ * ext/openssl/ruby_missing.h: Define RB_INTEGER_TYPE_P() if not defined.
+ openssl gem will be released before Ruby 2.4.0.
+
+Sun Jun 19 18:39:38 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_ocsp.c: Implement OCSP::{CertificateId,Request,
+ BasicResponse,Response}#initialize_copy.
+ [ruby-core:75504] [Bug #12381]
+
+ * test/openssl/test_ocsp.rb: Test them.
+
+Sun Jun 19 18:29:50 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_pkey_dh.c, ext/openssl/ossl_pkey_dsa.c,
+ ext/openssl/ossl_pkey_ec.c, ext/openssl/ossl_pkey_rsa.c: Implement
+ initialize_copy method for OpenSSL::PKey::*.
+ [ruby-core:75504] [Bug #12381]
+
+ * test/openssl/test_pkey_dh.rb, test/openssl/test_pkey_dsa.rb,
+ test/openssl/test_pkey_ec.rb, test/openssl/test_pkey_rsa.rb: Test they
+ actually copy the OpenSSL objects, and modifications to cloned object
+ don't affect the original object.
+
+Sun Jun 19 16:55:16 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/test_dir_m17n.rb: Skip tests with non-UTF-8 encodings
+ on cygwin. Cygwin can use the Unicode PUA (private use area) to store
+ bytes from non-UTF-8 filenames (see
+ https://cygwin.com/cygwin-ug-net/using-specialnames.html#pathnames-specialchars),
+ but we are not supporting this. [Bug #12443]
+
+Sun Jun 19 15:01:18 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * localeinit.c: Fix filesystem encoding for cygwin to UTF-8 (see
+ https://cygwin.com/cygwin-ug-net/using-specialnames.html#pathnames-unusual)
+
+Sun Jun 19 14:31:07 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_pkey.h, ext/openssl/ossl_pkey_dh.c,
+ ext/openssl/ossl_pkey_dsa.c, ext/openssl/ossl_pkey_rsa.c: A few days
+ ago, OpenSSL changed {DH,DSA,RSA}_get0_*() to take const BIGNUM **.
+ https://git.openssl.org/gitweb/?p=openssl.git;a=commit;h=fd809cfdbd6e32b6b67b68c59f6d55fbed7a9327
+ [ruby-core:75225] [Feature #12324]
+
+Sun Jun 19 11:19:43 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * variable.c (rb_path_to_class): consider the string length
+ instead of a terminator.
+
+ * variable.c (rb_path_to_class): search the constant at once
+ instead of checking if defined and then getting it.
+
+Sat Jun 18 14:01:40 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * test/rubygems/test_gem_installer.rb: Fixed broken test with extension
+ build. https://github.com/rubygems/rubygems/pull/1645
+
+Sat Jun 18 13:59:54 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems
+ HEAD(2c6d256). It contains to update vendored Molinillo to 0.5.0.
+ https://github.com/rubygems/rubygems/pull/1638
+
+Sat Jun 18 10:13:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (build-ext), ext/extmk.rb: use variable EXTENCS
+ different than ENCOBJS, to get rid of circular dependency.
+ build libencs when linking encodings statically.
+ [ruby-core:75618] [Bug #12401]
+
+Sat Jun 18 08:52:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/stringio/stringio.c (strio_getline): fix pointer index
+ overflow. reported by Guido Vranken <guido AT guidovranken.nl>.
+
+Thu Jun 16 16:35:35 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (Init_class_hierarchy): prevent rb_cObject which is the
+ class tree root, from GC. [ruby-dev:49666] [Bug #12492]
+
+Thu Jun 16 12:17:52 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (tr_trans): adjust buffer size by processed and rest
+ lengths, instead of doubling repeatedly.
+
+Thu Jun 16 11:15:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (tr_trans): consider terminator length and fix heap
+ overflow. reported by Guido Vranken <guido AT guidovranken.nl>.
+
+Thu Jun 16 00:02:32 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_ocsp.c (ossl_ocspreq_verify, ossl_ocspbres_verify):
+ Use ossl_clear_error() so that they don't print warnings to stderr and
+ leak errors in the OpenSSL error queue. Also, check the return value
+ of OCSP_*_verify() correctly. They can return -1 on verification
+ failure.
+
+Wed Jun 15 19:52:23 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_ocsp.c (ossl_ocspreq_sign, ossl_ocspbres_sign): Allow
+ specifying hash algorithm used in signing. They are hard coded to use
+ SHA-1.
+ Based on a patch provided by Tim Shirley <tidoublemy@gmail.com>.
+ [ruby-core:70915] [Feature #11552] [GH ruby/openssl#28]
+
+ * test/openssl/test_ocsp.rb: Test sign-verify works.
+
+Wed Jun 15 01:46:16 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c: [DOC] fix rdoc directive, and an example of negative
+ value. [ruby-core:76025] [Bug #12487]
+
+Wed Jun 15 01:44:42 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/mkconfig.rb: provide Unicode Version information as
+ RbConfig::CONFIG['UNICODE_VERSION'].
+ [ruby-core:75845] [Feature #12460]
+
+Wed Jun 15 00:01:18 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * test/ruby/enc/test_case_comprehensive.rb
+ (TestComprehensiveCaseFold::read_data): use \A and \z instead of
+ ^ and $ in regexp.
+
+Tue Jun 14 23:43:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/backward.h (rb_cFixnum, rb_cBignum): remove the
+ backward compatibility macros, to fail incompatible extension
+ libraries early. [Bug #12427]
+
+Tue Jun 14 22:22:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * strftime.c (rb_strftime_with_timespec): limit the result string
+ size by the format length, to get rid of unlimited memory use.
+
+Tue Jun 14 22:11:11 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_ocsp.c (ossl_ocspcid_get_issuer_name_hash,
+ ossl_ocspcid_get_issuer_key_hash, ossl_ocspcid_get_hash_algorithm):
+ Add accessor methods OCSP::CertificateId#issuer_name_hash,
+ #issuer_key_hash, #hash_algorithm.
+ Based on a patch provided by Paul Kehrer <paul.l.kehrer@gmail.com>.
+ [ruby-core:48062] [Feature #7181]
+
+ * test/openssl/test_ocsp.rb: Test these new methods.
+
+Tue Jun 14 22:07:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/date/date_strftime.c (date_strftime_with_tmx): reject too
+ large precision to get rid of buffer overflow.
+ reported by Guido Vranken <guido AT guidovranken.nl>.
+
+Tue Jun 14 21:40:42 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_ocsp.c (ossl_ocspbres_to_der, ossl_ocspcid_to_der):
+ Implement #to_der methods for OCSP::BasicResponse and
+ OCSP::CertificateId.
+
+ (ossl_ocspreq_initialize, ossl_ocspres_initialize): Use GetOCSP*()
+ instead of raw DATA_PTR().
+
+ (ossl_ocspbres_initialize, ossl_ocspcid_initialize): Allow
+ initializing from DER string.
+
+ (Init_ossl_ocsp): Define new #to_der methods.
+
+ * test/openssl/test_ocsp.rb: Test these changes. Also add missing tests
+ for OCSP::{Response,Request}#to_der.
+
+Tue Jun 14 21:35:00 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/openssl_missing.h (DH_set0_pqg, RSA_set0_key):
+ DH_set0_pqg() allows 'q' to be NULL. Fix a typo in RSA_set0_key().
+ Fixes r55285. [ruby-core:75225] [Feature #12324]
+
+Mon Jun 14 10:19:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * NEWS: describe Integer#digits.
+
+Mon Jun 13 21:09:40 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * thread.c (debug_deadlock_check): show thread lock dependency and
+ backtrace [Feature #8214] [ruby-dev:47217]
+
+ * thread.c (thread_status_name): show "sleep_forever" instead of
+ "sleep" if called from inspect.
+
+Mon Jun 13 20:50:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (reg_named_capture_assign_iter): remove named capture
+ conflict warnings. it is just annoying rather than useful.
+ [ruby-core:75416] [Bug #12359]
+
+Mon Jun 13 20:04:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * numeric.c (rb_int_digits, rb_fix_digits, rb_int_digits_bigbase):
+ Add Integer#digits to extract columns in place-value notation
+ [Feature #12447] [ruby-core:75799]
+
+ * test/ruby/test_integer.rb: Add tests for the above change.
+
+ * test/ruby/test_bignum.rb: ditto.
+
+Mon Jun 13 20:34:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (RUBY_INTEGER_UNIFICATION): macro to tell if
+ Integer is integrated. [ruby-core:75718][Bug #12427]
+
+ * include/ruby/backward.h, internal.h (rb_cFixnum, rb_cBignum):
+ fallback to rb_cInteger.
+
+ * bignum.c, numeric.c, ext/json/generator/generator.{c,h}: use the
+ macro.
+
+Mon Jun 13 16:58:53 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive.rb: Add tests for full Unicode
+ swapcase.
+
+Sun Jun 12 14:48:00 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive.rb: Add tests for ASCII-only
+ swapcase; store calculated values in hashes.
+
+Sun Jun 12 14:05:45 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_cipher.c (ossl_cipher_get_auth_tag,
+ ossl_cipher_set_auth_tag): Check if the cipher flags retrieved by
+ EVP_CIPHER_CTX_flags() includes EVP_CIPH_FLAG_AEAD_CIPHER to see if
+ the cipher supports AEAD. AES-GCM was the only supported in OpenSSL
+ 1.0.1.
+
+ (Init_ossl_cipher): Fix doc; OpenSSL::Cipher::AES.new(128, :GCM) can't
+ work.
+
+ * ext/openssl/openssl_missing.h: Define EVP_CTRL_AEAD_{GET,SET}_TAG if
+ missing. They are added in OpenSSL 1.1.0, and have the same value as
+ EVP_CTRL_GCM_{GET,SET}_TAG and EVP_CTRL_CCM_{GET,SET}_TAG.
+
+Sun Jun 12 13:47:42 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * test/openssl/test_engine.rb (test_openssl_engine_builtin,
+ test_openssl_engine_by_id_string): Skip test if 'openssl' engine is
+ already loaded. And test the number increased by Engine.load{_by_id,},
+ not the total count of loaded engines. Previously, we called
+ OpenSSL::Engine.cleanup every time running a test case, but we no
+ longer can do it.
+ [ruby-core:75225] [Feature #12324]
+
+Sun Jun 12 09:24:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (append_fspath): normalize directory name to be appended
+ on OS X. [ruby-core:75957] [Ruby trunk Bug#12483]
+ https://github.com/rails/rails/issues/25303#issuecomment-224834804
+
+Sat Jun 11 23:07:32 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * lib/forwardable.rb (_delegator_method): get rid of a warning which
+ causes test failures introduced at r55376.
+
+Sat Jun 11 18:37:58 2016 Marcus Stollsteimer <sto.mar@web.de>
+
+ * ext/json/lib/*.rb: Removed some comments. Because these are unnecessary
+ class description. [ci skip][Bug #12255][ruby-core:74835]
+
+Sat Jun 11 15:19:38 2016 takiy33 <takiy33@users.noreply.github.com>
+
+ * lib/net/smtp.rb: [DOC] Remove dead link on documentation for
+ Japanese of SMTP. [Fix GH-1380]
+
+Sat Jun 11 15:02:45 2016 Grant Hutchins <github@nertzy.com>
+
+ * string.c (rb_str_oct): [DOC] fix typo, hornored -> honored.
+ [Fix GH-1379]
+
+Sat Jun 11 14:04:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/objspace/objspace_dump.c: generate valid JSON for dump_all.
+
+Sat Jun 11 13:52:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/forwardable.rb (_delegator_method): remove __send__ call if
+ possible, so that more optimizations will be enabled.
+
+Sat Jun 11 11:24:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enc/iso_8859.h (SHARP_s): name frequently used codepoint.
+
+Sat Jun 11 09:58:45 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_1.c: Revert to older version of code.
+
+Sat Jun 11 09:46:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/iso_8859_1.c: Implement non-ASCII case mapping.
+
+ * test/ruby/enc/test_case_comprehensive.rb: Tests for above.
+
+ * string.c: Add iso-8859-1 to supported encodings.
+
+Sat Jun 11 09:31:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/forwardable.rb (_delegator_method): leave the backtrace
+ untouched during accessor. forwardable.rb does not appear in
+ the backtrace during delegated method because of tail-call
+ optimization.
+
+Sat Jun 11 01:38:31 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * include/ruby/defines.h (GCC_VERSION_SINCE): Fix logic error by
+ adding parentheses. Fix failures of TestMkmf::TestConvertible
+ with GCC 3.4.3 on Solaris 10. [Bug #12479] [ruby-dev:49660]
+
+Fri Jun 10 21:54:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/forwardable.rb (Forwardable._delegator_method): extract
+ method generator and deal with non-module objects.
+ [ruby-dev:49656] [Bug #12478]
+
+Fri Jun 10 17:35:11 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: Special-case :ascii option in rb_str_capitalize_bang and
+ rb_str_swapcase_bang.
+
+Fri Jun 10 17:12:24 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: Special-case :ascii option in rb_str_upcase_bang (retry).
+
+Fri Jun 10 14:48:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * hash.c (get_env_cstr): ensure NUL-terminated.
+ [ruby-dev:49655] [Bug #12475]
+
+ * string.c (rb_str_fill_terminator): return the pointer to the
+ NUL-terminated content.
+
+Thu Jun 9 21:42:00 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_asn1.c (asn1integer_to_num): Use
+ ASN1_ENUMERATED_to_BN() to convert an ASN1_ENUMERATED to a BN.
+ Starting from OpenSSL 1.1.0, ASN1_INTEGER_to_BN() rejects
+ non-ASN1_INTEGER objects. The format of INTEGER and ENUMERATED are
+ almost identical so they behaved in the same way in OpenSSL <= 1.0.2.
+ [ruby-core:75225] [Feature #12324]
+
+ * test/openssl/test_asn1.rb (test_decode_enumerated): Test that it
+ works.
+
+Thu Jun 9 21:10:04 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * tool/ifchange: fix timestamp error when target without
+ directory.
+
+Thu Jun 9 19:46:22 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_ssl.c: Add define guards for OPENSSL_NO_EC.
+ SSL_CTX_set_ecdh_auto() is defined even when ECDH is disabled in
+ OpenSSL's configuration. This fixes r55214.
+
+ * test/openssl/test_pair.rb (test_ecdh_curves): Skip if the OpenSSL does
+ not support ECDH.
+
+ * test/openssl/utils.rb (start_server): Ignore error in
+ SSLContext#ecdh_curves=.
+
+Thu Jun 9 18:12:42 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * Makefile.in (un-runnable): fail with proper error message.
+ [ruby-core:75905] [Bug #12472]
+
+Thu Jun 9 15:32:17 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (RBCONFIG): use ifchange tool to see if the content is
+ changed and update the timestamp file.
+
+ * tool/mkconfig.rb: remove ifchange features.
+
+ * tool/ifchange: make target directory if it does not exist with
+ its parent directories.
+
+ * win32/ifchange.bat: drop support for command.com used on old
+ systems.
+
+Thu Jun 9 15:03:35 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/extconf.rb: Check for CRYPTO_malloc() and SSL_new().
+ OpenSSL_add_all_digests() and SSL_library_init() are deprecated and
+ converted to macros in OpenSSL 1.1.0.
+ [ruby-core:75225] [Feature #12324]
+
+Wed Jun 8 23:09:51 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * string.c (rb_str_ascii_casemap): fix compile error.
+
+Wed Jun 8 22:22:24 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: Revert previous commit (possibility of endless loop).
+
+Wed Jun 8 21:57:41 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: Special-case :ascii option in rb_str_upcase_bang.
+
+Wed Jun 8 21:28:36 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: New static function rb_str_ascii_casemap; special-casing
+ :ascii option in rb_str_upcase_bang and rb_str_downcase_bang.
+
+ * regenc.c: Fix a bug (wrong use of unnecessary slack at end of string).
+
+ * regenc.h -> include/ruby/oniguruma.h: Move declaration of
+ onigenc_ascii_only_case_map so that it is visible in string.c.
+
+Wed Jun 8 20:33:44 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * include/ruby/intern.h: Remove excess semicolons in PUREFUNC().
+ Fix failure of TestMkmf::TestConvertible on Solaris with
+ Oracle Solaris Studio 12. [ruby-dev:49651] [Bug #12470]
+ * internal.h: ditto.
+
+Wed Jun 8 16:03:09 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * lib/net/smtp.rb (getok, get_response): raise an ArgumentError when
+ CR or LF is included in a line, because they are not allowed in
+ RFC5321. Thanks, Jeremy Daer.
+
+Tue Jun 7 21:27:25 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * test/rubygems/*_{cert,cert_32}.pem: Regenerate test certificates for
+ OpenSSL 1.1.0. This is already in upstream.
+ https://github.com/rubygems/rubygems/commit/9be5c53939440a61c4bba73cfffbeb5cfadf72be
+ [ruby-core:75225] [Feature #12324]
+
+Tue Jun 7 21:27:17 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * test/open-uri/test_ssl.rb: Regenerate test certificates. The test CA
+ certificate was incorrectly generated. A CA certificate must have the
+ basic constraints extension with cA bit set to TRUE. OpenSSL <= 1.0.2
+ allowed the error when the certificate is in the trusted store but
+ OpenSSL 1.1.0 no longer does.
+ [ruby-core:75225] [Feature #12324]
+
+Tue Jun 7 21:20:38 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * test/openssl/test_x509name.rb: Don't register OID for 'emailAddress'
+ and 'serialNumber'. A recent change in OpenSSL made OBJ_create()
+ reject an already existing OID. They were needed to run tests with
+ OpenSSL 0.9.6 which is now unsupported.
+ https://git.openssl.org/gitweb/?p=openssl.git;a=commit;h=52832e470f5fe8c222249ae5b539aeb3c74cdb25
+ [ruby-core:75225] [Feature #12324]
+
+ * test/openssl/test_ssl_session.rb (test_server_session): Duplicate
+ SSL::Session before re-adding to the session store. OpenSSL 1.1.0
+ starts rejecting SSL_SESSION once removed by SSL_CTX_remove_session().
+ https://git.openssl.org/gitweb/?p=openssl.git;a=commit;h=7c2d4fee2547650102cd16d23f8125b76112ae75
+
+ * test/openssl/test_pkey_ec.rb (setup): Remove X25519 from @keys. X25519
+ is new in OpenSSL 1.1.0 but this is for key agreement and not for
+ signing.
+
+ * test/openssl/test_pair.rb, test/openssl/test_ssl.rb,
+ test/openssl/utils.rb: Set security level to 0 when using aNULL cipher
+ suites.
+
+ * test/openssl/utils.rb: Use 1024 bits DSA key for client certificates.
+
+ * test/openssl/test_engine.rb: Run each test in separate process.
+ We can no longer cleanup engines explicitly as ENGINE_cleanup() was
+ removed.
+ https://git.openssl.org/gitweb/?p=openssl.git;a=commit;h=6d4fb1d59e61aacefa25edc4fe5acfe1ac93f743
+
+ * ext/openssl/ossl_engine.c (ossl_engine_s_cleanup): Add a note to the
+ RDoc for Engine.cleanup.
+
+ * ext/openssl/lib/openssl/digest.rb: Don't define constants for DSS,
+ DSS1 and SHA(-0) when using with OpenSSL 1.1.0. They are removed.
+
+ * test/openssl/test_digest.rb, test/openssl/test_pkey_dsa.rb,
+ test/openssl/test_pkey_dsa.rb, test/openssl/test_ssl.rb,
+ test/openssl/test_x509cert.rb, test/openssl/test_x509req.rb: Don't
+ test unsupported hash functions.
+
+Tue Jun 7 17:49:52 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive: Change test for encodings
+ without any non-ASCII case conversions from ASCII-only test
+ to full test.
+
+Tue Jun 7 17:18:39 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c (rb_str_upcase_bang, rb_str_capitalize_bang,
+ rb_str_swapcase_bang): Switch to use primitive.
+
+Tue Jun 7 16:44:16 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c (rb_str_downcase_bang): Switch to use primitive except if
+ conversion can be done ASCII-only.
+
+Tue Jun 7 16:13:36 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive: Add regression tests for
+ current ASCII-only case conversion.
+
+Tue Jun 7 15:28:38 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive: Fix method name
+ (generate_casefold_tests -> generate_case_mapping_tests).
+
+Tue Jun 7 15:05:13 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * regenc.h/c: Rename onigenc_not_support_case_map to
+ onigenc_ascii_only_case_map.
+
+ * regenc.h: Add definition of onigenc_single_byte_ascii_only_case_map.
+
+ * enc/iso_8859_X.c, windows_125X.c, ascii.c, us-ascii.c, koi8_x.c:
+ Replace onigenc_not_support_case_map by
+ onigenc_single_byte_ascii_only_case_map.
+
+ * enc/big5.c, cp949.c, emacs_mule.c, euc_X.c, gbX.c, shift_jis.c,
+ windows_31j.c: Replace onigenc_not_support_case_map by
+ onigenc_ascii_only_case_map.
+
+Tue Jun 7 14:57:09 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/extconf.rb: Check for SSL_CTX_set_min_proto_version()
+ macro added in OpenSSL 1.1.0. Version-specific methods, such as
+ TLSv1_method(), are deprecated in OpenSSL 1.1.0. We need to use
+ version-flexible methods (TLS_*method() or SSLv23_*method()) and
+ disable other protocol versions as necessary.
+ [ruby-core:75225] [Feature #12324]
+
+ * ext/openssl/ossl_ssl.c: Use SSL_CTX_set_{min,max}_proto_version() to
+ fix the protocol version.
+
+Tue Jun 7 12:55:34 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * regenc.c (onigenc_not_support_case_map): Move to end of file;
+ (onigenc_single_byte_ascii_only_case_map): Add new function.
+
+Tue Jun 7 09:26:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * regenc.c (onigenc_not_support_case_map): Rewrite to work correctly
+ in ASCII range.
+
+Mon Jun 6 23:00:00 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * appveyor.yml: Update libressl version to 2.3.5.
+
+Mon Jun 6 18:37:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_throw_start): check if the iseq is symbol
+ proc, class definition should not be a symbol proc.
+ [ruby-core:75856] [Bug #12462]
+
+Mon Jun 6 18:36:34 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: Added UTF-16BE/LE and UTF-32BE/LE to supported encodings
+ for Unicode case mapping.
+
+ * test/ruby/enc/test_case_comprehensive.rb: Tests for above
+ functionality; fixed an encoding issue in assertion error message.
+
+Mon Jun 6 17:29:35 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive.rb: Speed up testing for small
+ encodings by preselecting codepoints.
+
+Mon Jun 6 17:10:50 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_cipher.c (ossl_cipher_free): Use EVP_CIPHER_CTX_free()
+ to free EVP_CIPHER_CTX allocated by EVP_CIPHER_CTX_new().
+ [ruby-core:75225] [Feature #12324]
+
+Mon Jun 6 13:37:08 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c Change rb_str_casemap to use encoding primitive
+ case_map instead of directly calling onigenc_unicode_case_map.
+
+Mon Jun 6 13:16:46 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_mapping.rb:
+ Remove :lithuanian guard for Unicode case mapping.
+
+Mon Jun 6 10:39:56 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/openssl_missing.h: Include ruby/config.h. r55285 added
+ some inline functions but VC does not recognize 'inline' keyword.
+
+Mon Jun 6 09:25:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (thread_start_func_2): report raised exception if
+ report_on_exception flag is set. [Feature #6647]
+
+Mon Jun 6 01:36:24 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/extconf.rb: Check existence of SSL_is_server(). This
+ function was introduced in OpenSSL 1.0.2.
+ [ruby-core:75225] [Feature #12324]
+
+ * ext/openssl/openssl_missing.h: Implement SSL_is_server() if missing.
+
+ * ext/openssl/ossl_ssl.c (ssl_info_cb): Use SSL_is_server() to see if
+ the SSL is server. The state machine in OpenSSL was rewritten and
+ SSL_get_state() no longer returns SSL_ST_ACCEPT.
+
+ (ossl_ssl_cipher_to_ary, ossl_sslctx_session_get_cb): Add some
+ `const`s to suppress warning.
+
+Mon Jun 6 01:18:10 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_asn1.c (decode_bool): Do the same thing as
+ d2i_ASN1_BOOLEAN() does by ourselves. This function is removed in
+ OpenSSL 1.1.0.
+ [ruby-core:75225] [Feature #12324]
+
+Mon Jun 6 00:34:16 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/extconf.rb: Check existence of accessor functions that
+ don't exist in OpenSSL 0.9.8. OpenSSL 1.1.0 made most of its
+ structures opaque and requires use of these accessor functions.
+ [ruby-core:75225] [Feature #12324]
+
+ * ext/openssl/openssl_missing.[ch]: Implement them if missing.
+
+ * ext/openssl/ossl*.c: Use these accessor functions.
+
+ * test/openssl/test_hmac.rb: Add missing test for HMAC#reset.
+
+Mon Jun 6 00:00:13 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/openssl_missing.[ch]: Implement EVP_PKEY_get0_*() and
+ {RSA,DSA,EC_KEY,DH}_get0_*() functions.
+ OpenSSL 1.1.0 makes EVP_PKEY/RSA/DSA/DH opaque. We used to provide
+ setter methods for each parameter of each PKey type, for example
+ PKey::RSA#e=, but this is no longer possible because the new API
+ RSA_set0_key() requires the 'n' at the same time. This commit adds
+ deprecation warning to them and adds PKey::*#set_* methods as direct
+ wrapper for those new APIs. For example, 'rsa.e = 3' now needs to be
+ rewritten as 'rsa.set_key(rsa.n, 3, rsa.d)'.
+ [ruby-core:75225] [Feature #12324]
+
+ * ext/openssl/ossl_pkey*.[ch]: Use the new accessor functions. Implement
+ RSA#set_{key,factors,crt_params}, DSA#set_{key,pqg}, DH#set_{key,pqg}.
+ Emit a warning with rb_warning() when old setter methods are used.
+
+ * test/drb/ut_array_drbssl.rb, test/drb/ut_drb_drbssl.rb,
+ test/rubygems/test_gem_remote_fetcher.rb: Don't set a priv_key for DH
+ object that are used in tmp_dh_callback. Generating a new key pair
+ every time should be fine - actually the private exponent is ignored
+ in OpenSSL >= 1.0.2f/1.0.1r even if we explicitly set.
+ https://www.openssl.org/news/secadv/20160128.txt
+
+Sun Jun 5 22:06:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * configure.in: Fix the timing to detect the appropriate C++ compiler
+ in OS X.
+
+Sun Jun 5 21:42:24 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/extconf.rb: Check absence of CRYPTO_lock() to see if the
+ OpenSSL has the new threading API. In OpenSSL <= 1.0.2, an application
+ had to set locking callbacks to use OpenSSL in a multi-threaded
+ environment. OpenSSL 1.1.0 now finds pthreads or Windows threads so we
+ don't need to do something special.
+ [ruby-core:75225] [Feature #12324]
+
+ Also check existence of *_up_ref(). Some structures in OpenSSL have
+ a reference counter. We used to increment it with CRYPTO_add() which
+ is a part of the old API.
+
+ * ext/openssl/openssl_missing.h: Implement *_up_ref() if missing.
+
+ * ext/openssl/ossl.c: Don't set locking callbacks if unneeded.
+
+ * ext/openssl/ossl_pkey.c, ext/openssl/ossl_ssl.c,
+ ext/openssl/ossl_x509cert.c, ext/openssl/ossl_x509crl.c,
+ ext/openssl/ossl_x509store.c: Use *_up_ref() instead of CRYPTO_add().
+
+Sun Jun 5 21:38:13 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/extconf.rb: Check if RAND_pseudo_bytes() is usable. It is
+ marked as deprecated in OpenSSL 1.1.0.
+ [ruby-core:75225] [Feature #12324]
+
+ * ext/openssl/ossl_rand.c: Disable Random.pseudo_bytes if
+ RAND_pseudo_bytes() is unavailable.
+
+ * test/openssl/test_random.rb: Don't test Random.pseudo_bytes if not
+ defined.
+
+Sun Jun 5 19:06:40 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * NEWS: Add news about Unicode-wide case mapping for
+ String/Symbol#upcase/downcase/swapcase/capitalize(!).
+
+Sun Jun 5 15:24:33 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive.rb:
+ Remove :lithuanian guard for Unicode case mapping.
+
+Sun Jun 5 14:46:34 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: Remove :lithuanian guard for Unicode case mapping.
+
+Sat Jun 4 10:54:52 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * missing/crypt.h (struct crypt_data): remove unnecessary member
+ "initialized".
+
+ * missing/crypt.c (des_setkey_r): nothing to be initialized in
+ crypt_data.
+
+ * configure.in (struct crypt_data): check for "initialized" in
+ struct crypt_data, which may be only in glibc, and isn't on AIX
+ at least.
+
+Sat Jun 4 10:38:39 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c: unify MAX_PATH, _MAX_PATH, and MAXPATHLEN to
+ PATH_MAX, except for MAX_PATH in get_special_folder for an API
+ limit.
+
+Fri Jun 3 21:27:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (process_options): rb_str_conv_enc() never set encoding
+ of the source string, but returns the string itself if the
+ conversion failed. then the instance variable does not need to
+ be set again.
+
+Fri Jun 3 18:04:37 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ruby.c (process_options): need to duplicate path before passing it to
+ rb_str_conv_enc() because the function might call rb_enc_associate()
+ internally. this fixes test failures on Windows introduced at r55260.
+
+Fri Jun 3 17:44:25 2016 Reiner Herrmann <reiner@reiner-h.de>
+
+ * lib/mkmf.rb (create_makefile): sort lists of source and object
+ files in generated Makefile, unless given by extconf.rb.
+ [Fix GH-1367]
+
+Thu Jun 2 21:18:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (get_special_folder): use SHGetPathFromIDListEx if
+ available instead of old SHGetPathFromIDListW, to check the
+ buffer size.
+
+Thu Jun 2 17:05:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (ruby_init_loadpath_safe): remove MAXPATHLEN restriction
+ for Windows 10.
+
+Thu Jun 2 16:51:35 2016 Koichi ITO <koic.ito@gmail.com>
+
+ * misc/ruby-mode.el (ruby-here-doc-beg-re),
+ (ruby-here-doc-beg-match, ruby-parse-partial): Support for
+ `squiggly heredoc' syntax in ruby-mode. [Fix GH-1372]
+
+Thu Jun 2 10:24:48 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: Raise ArgumentError when invalid string is detected in
+ case mapping methods.
+
+ * enc/unicode.c: Check for invalid string and signal with negative
+ length value.
+
+ * test/ruby/enc/test_case_mapping.rb: Add tests for above.
+
+ * test/ruby/test_m17n_comb.rb: Add a message to clarify test failure.
+
+Wed Jun 1 21:41:05 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/extconf.rb: Check existence of ASN1_TIME_adj(). The old
+ ASN1_TIME_set() is not Year 2038 ready on sizeof(time_t) == 4
+ environment. This function was added in OpenSSL 1.0.0.
+ [ruby-core:45552] [Bug #6571]
+
+ * ext/openssl/ossl_asn1.c (ossl_time_split): Added. Split the argument
+ (Time) into the number of days elapsed since the epoch and the
+ remainder seconds to conform to ASN1_TIME_adj().
+ (obj_to_asn1utime, obj_to_asn1gtime): Use ossl_time_split() and
+ ASN1_*TIME_adj().
+
+ * ext/openssl/ossl_asn1.h: Add the function prototype for
+ ossl_time_split().
+
+ * ext/openssl/ossl_x509.[ch]: Add ossl_x509_time_adjust(). Similarly to
+ obj_to_asn1*time(), use X509_time_adj_ex() instead of X509_time_adj().
+
+ * ext/openssl/ossl_x509cert.c, ext/openssl/ossl_x509crl.c,
+ ext/openssl/ossl_x509revoked.c: Use ossl_x509_time_adjust().
+
+Wed Jun 1 15:58:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: revert r55237. replace crypt, not crypt_r, and
+ check if crypt is broken more.
+
+ * missing/crypt.c: move crypt_r.c
+
+ * string.c (rb_str_crypt): use crypt_r if provided by the system.
+
+Wed Jun 1 14:07:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * missing/crypt_r.c (a64toi): initialize statically and fix out of
+ bounds access when salt is not 7bit clean.
+
+Wed Jun 1 11:34:59 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/Makefile.sub (MISSING): fixed build error introduced at r55237.
+
+Wed Jun 1 09:48:06 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_crypt): use reentrant crypt_r.
+
+Wed Jun 1 09:37:26 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * missing/crypt.c (des_setkey): void function never returns any value.
+
+Wed Jun 1 09:16:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * crypt.h: separate header file from missing/crypt.c.
+
+ * missing/crypt.c (crypt_r, setkey_r, encrypt_r): add reentrant
+ versions.
+
+Wed Jun 1 02:25:38 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * missing/crypt.c: fix size macros to use configured values
+ for platforms long is larger than 32bit.
+ [ruby-core:75792] [Bug #12446]
+
+Tue May 31 17:28:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse.rb (OptionParser::Completion.candidate): get rid of
+ nil as key names. [ruby-core:75773] [Bug #12438]
+
+ * lib/optparse.rb (OptionParser#make_switch): char class option
+ cannot be NoArgument, default to RequiredArgument.
+
+Tue May 31 00:30:11 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/socket/raddrinfo.c (host_str, port_str): Use StringValueCStr
+ instead of (Safe)StringValue, to detect NUL byte in the string.
+
+Mon May 30 22:02:01 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_asn1.c (time_to_time_t): Use NUM2TIMET() instead of
+ NUM2LONG(). time_t may be larger than long.
+ [ruby-core:45552] [Bug #6571]
+
+Mon May 30 21:15:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: Document current behavior for other case mapping methods
+ on String. [ci skip]
+
+Mon May 30 20:00:25 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: Document current situation for String#downcase. [ci skip]
+
+Mon May 30 18:29:28 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_ssl.c (ossl_sslctx_s_alloc): Enable the automatic
+ curve selection for ECDH by calling SSL_CTX_set_ecdh_auto(). With
+ this a TLS server automatically selects a curve which both the client
+ and the server support to use in ECDH. This changes the default
+ behavior but users can still disable ECDH by excluding 'ECDH' cipher
+ suites from the cipher list (with SSLContext#ciphers=). This commit
+ also deprecate #tmp_ecdh_callback=. It was added in Ruby 2.3.0. It
+ wraps SSL_CTX_set_tmp_ecdh_callback() which will be removed in OpenSSL
+ 1.1.0. Its callback receives two values 'is_export' and 'keylength'
+ but both are completely useless for determining a curve to use in
+ ECDH. The automatic curve selection was introduced to replace this.
+
+ (ossl_sslctx_setup): Deprecate SSLContext#tmp_ecdh_callback=. Emit a
+ warning if this is in use.
+
+ (ossl_sslctx_set_ecdh_curves): Add SSLContext#ecdh_curves=. Wrap
+ SSL_CTX_set1_curves_list(). If it is not available, this falls back
+ to SSL_CTX_set_tmp_ecdh().
+
+ (Init_ossl_ssl): Define SSLContext#ecdh_curves=.
+
+ * ext/openssl/extconf.rb: Check the existence of EC_curve_nist2nid(),
+ SSL_CTX_set1_curves_list(), SSL_CTX_set_ecdh_auto() and
+ SSL_CTX_set_tmp_ecdh_callback().
+
+ * ext/openssl/openssl_missing.[ch]: Implement EC_curve_nist2nid() if
+ missing.
+
+ * test/openssl/test_pair.rb (test_ecdh_callback): Use
+ EnvUtil.suppress_warning to suppress deprecated warning.
+
+ (test_ecdh_curves): Test that SSLContext#ecdh_curves= works.
+
+ * test/openssl/utils.rb (start_server): Use SSLContext#ecdh_curves=.
+
+Mon May 30 16:28:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/raddrinfo.c (host_str, port_str): use RSTRING_LEN
+ instead of strlen, since RSTRING_PTR StringValueCStr may not be
+ NUL-terminated when SHARABLE_MIDDLE_SUBSTRING=1. reported by
+ @tmtms, http://twitter.com/tmtms/status/736910516229005312
+
+Mon May 30 16:20:26 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (str_fill_term): return new pointer reallocated by
+ filling terminator.
+
+Mon May 30 14:54:58 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/stringio/stringio.c (enc_subseq): share the return value and
+ the buffer as possible.
+
+Mon May 30 14:50:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (str_substr, rb_str_aref): refactor not to create
+ unnecessary empty string.
+
+ * string.c (str_byte_substr, str_byte_aref): ditto.
+
+Mon May 30 00:09:37 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/-test-/auto_ext.rb: fixed a heedless bug introduced at r55198.
+ this change will make RubyCI green.
+
+Sun May 29 22:58:19 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * regexec.c (ONIGENC_IS_MBC_ASCII_WORD): redefine optimized one.
+ WORD of Ruby's ascii compatible encoding is always [a-zA-Z0-9_].
+
+Sun May 29 22:44:19 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * regexec.c (match_at): make compilers optimize harder.
+
+Sun May 29 12:08:42 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/-test-/auto_ext.rb (auto_ext): utility method to create
+ extension libraries for tests.
+
+Sat May 28 20:40:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * misc/ruby-additional.el (ruby-insert-heredoc-code-block): insert
+ here document code block for assert_separately mainly.
+
+Sat May 28 20:34:19 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/test_unicode_normalize.rb: Add test to check for availability of
+ Unicode data file; refactoring; fix an error with tests for destructive
+ method (unicode_normalize!).
+
+Sat May 28 19:08:36 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive.rb: Add error messages to tests
+ for data file availability; refactoring.
+
+Sat May 28 14:00:10 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/lib/openssl/ssl.rb (SSLSocket): Move the implementation of
+ SSLSocket#initialize to C. Initialize the SSL (OpenSSL object) in it.
+ Currently this is delayed until ossl_ssl_setup(), which is called from
+ SSLSocket#accept or #connect. Say we call SSLSocket#hostname= with an
+ illegal value. We expect an exception to be raised in #hostname= but
+ actually we get it in the later SSLSocket#connect. Because the SSL is
+ not ready at #hostname=, the actual call of SSL_set_tlsext_host_name()
+ is also delayed.
+ This also fixes: [ruby-dev:49376] [Bug #11724]
+
+ * ext/openssl/ossl_ssl.c (ossl_ssl_initialize): Added. Almost the same
+ as the Ruby version but this instantiate the SSL object at the same
+ time.
+
+ (ossl_ssl_setup): Adjust to the changes. Just set the underlying IO to
+ the SSL.
+
+ (ssl_started): Added. Make use of SSL_get_fd(). This returns -1 if not
+ yet set by SSL_set_fd().
+
+ (ossl_ssl_data_get_struct): Removed. Now GetSSL() checks that the SSL
+ exists.
+
+ (ossl_ssl_set_session): Don't call ossl_ssl_setup() here as now the
+ SSL is already instantiated in #initialize.
+
+ (ossl_ssl_shutdown, ossl_start_ssl, ossl_ssl_read_internal,
+ ossl_ssl_write_internal, ossl_ssl_stop, ossl_ssl_get_cert,
+ ossl_ssl_get_peer_cert, ossl_ssl_get_peer_cert_chain,
+ ossl_ssl_get_version, ossl_ssl_get_cipher, ossl_ssl_get_state,
+ ossl_ssl_pending, ossl_ssl_session_reused,
+ ossl_ssl_get_verify_result, ossl_ssl_get_client_ca_list,
+ ossl_ssl_npn_protocol, ossl_ssl_alpn_protocol, ossl_ssl_tmp_key): Use
+ GetSSL() instead of ossl_ssl_data_get_struct(). Use ssl_started().
+
+ (Init_ossl_ssl): Add method declarations of SSLSocket#{initialize,
+ hostname=}.
+
+ * ext/openssl/ossl_ssl.h (GetSSL): Check that the SSL is not NULL. It
+ should not be NULL because we now set it in #initialize.
+
+ * ext/openssl/ossl_ssl_session.c (ossl_ssl_session_initialize): No need
+ to check if the SSL is NULL.
+
+Sat May 28 10:47:40 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * gems/bundled_gems: Update latest releases, power_assert-0.3.0,
+ test-unit 3.1.9, minitest 5.9.0, did_you_mean 1.0.1
+
+Sat May 28 10:45:40 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * addr2line.c: drop support for ATARI ST platform. It was
+ discontinued more than two decades ago. [fix GH-1350] Patch by
+ @cremno
+ * include/ruby/ruby.h: ditto.
+ * io.c: ditto.
+
+Sat May 28 10:39:47 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive.rb: Converted exception for
+ unavailable Unicode data files to failed assertion.
+
+Sat May 28 10:26:18 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/cgi/util.rb: added missing quote.
+ [fix GH-1363][ci skip] Patch by @dwaller
+
+Fri May 27 17:38:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * variable.c (rb_local_constants_i): exclude hidden constants.
+ [ruby-core:75575] [Bug #12389]
+
+Fri May 27 17:09:44 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * transcode.c (str_transcode0): scrub in the given encoding when
+ the source encoding is given, not in the encoding of the
+ receiver. [ruby-core:75732] [Bug #12431]
+
+Fri May 27 15:07:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_scan_args): remove nul padding which
+ caused syntax error if fmt is not a string literal.
+
+ * include/ruby/ruby.h (rb_scan_args_verify): suppress array-bounds
+ warnings by old clang.
+
+ * include/ruby/ruby.h (rb_scan_args0): make extractor macros
+ inline functions, which do not validate the format and are
+ unnecessary to be expanded.
+
+Fri May 27 01:00:36 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * symbol.c (is_identchar): use ISDIGIT instead of rb_enc_isalnum.
+ Though rb_enc_isalnum is encoding aware function, its argument here
+ is *m, which is a single byte. Therefore ISDIGIT is faster.
+
+ * symbol.c (is_special_global_name): ditto.
+
+ * symbol.c (rb_enc_symname_type): ditto.
+
+Fri May 27 00:39:40 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_scan_args): add nul padding here to
+ apply to all references.
+
+ * include/ruby/ruby.h (rb_scan_args_verify): move length mismatch
+ check outside conditional operators.
+
+Thu May 26 14:21:10 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_pkey_dh.c (ossl_dh_compute_key): Check that the DH
+ has 'p' (the prime) before calling DH_size(). We can create a DH with
+ no parameter but DH_size() does not check and dereferences NULL.
+ [ruby-core:75720] [Bug #12428]
+
+ * ext/openssl/ossl_pkey_dsa.c (ossl_dsa_sign): Ditto. DSA_size() does
+ not check dsa->q.
+
+ * ext/openssl/ossl_pkey_rsa.c (ossl_rsa_public_encrypt,
+ ossl_rsa_public_decrypt, ossl_rsa_private_encrypt,
+ ossl_rsa_private_decrypt): Ditto. RSA_size() does not check rsa->n.
+
+Thu May 26 14:13:52 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_scan_args_count): verify length with
+ counting variables together.
+
+Thu May 26 09:45:41 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_comprehensive.rb: Add set of comprehensive
+ (across most Unicode characters; later across most character encodings)
+ tests for case mapping.
+
+Thu May 26 05:00:13 2016 Benoit Daloze <eregontp@gmail.com>
+
+ * class.c (rb_define_class): Fix documentation.
+
+Wed May 25 20:50:12 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * re.c (unescape_nonascii): scan hex up to only 3 characters.
+ [Bug #12420] [Bug #12423]
+
+Wed May 25 19:07:19 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Handle DOTLESS_i by hand because it isn't involved in folding.
+
+Wed May 25 18:30:53 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * regparse.c (fetch_token_in_cc): raise error if given octal escaped
+ character is too big. [Bug #12420] [Bug #12423]
+
+Wed May 25 17:45:15 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl, test/openssl: Drop OpenSSL < 0.9.8 support.
+
+Wed May 25 17:43:30 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/openssl_missing.h, ext/openssl/ossl.h: Remove
+ unnecessary 'extern "C"' blocks. We don't use C++ and these headers
+ are local to ext/openssl, so there is no need to enclose with it.
+
+Wed May 25 17:42:58 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/extconf.rb: Remove check of OPENSSL_FIPS macro. This is
+ unneeded because we can check the macro directly in source code,
+ just as we already do for OPENSSL_NO_* macros.
+
+ * ext/openssl/ossl.c: Replace occurrences of HAVE_OPENSSL_FIPS with
+ OPENSSL_FIPS.
+
+Wed May 25 17:13:35 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (rb_scan_args): merge code for n_trail.
+
+Wed May 25 17:11:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_scan_args_validate): move failed
+ condition to the terminal. [ruby-core:75714] [Bug #12426]
+
+Wed May 25 13:13:37 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * regcomp.c: remove condition for debug output because prelude
+ doesn't use regexp now.
+
+Wed May 25 13:10:30 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * regcomp.c (compile_length_tree): return error code immediately
+ if compile_length_tree raised error [Bug #12418]
+
+Wed May 25 08:01:39 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Fix flag error for switch from titlecase to lowercase.
+
+ * test/ruby/enc/test_case_mapping.rb: Tests for above error.
+
+Wed May 25 01:13:55 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_pkey_ec.c (ec_key_new_from_group): Create a new
+ EC_KEY on given EC group. Extracted from ossl_ec_key_initialize().
+ (ossl_ec_key_s_generate): Added. Create a new EC instance and
+ generate a random private and public key.
+ (ossl_ec_key_initialize): Use ec_key_new_from_group().
+ (Init_ossl_ec): Define the new method EC.generate. This change is
+ for consistency with other PKey types. [ruby-core:45541] [Bug #6567]
+
+ * test/openssl/test_pkey_ec.rb: Test that EC.generate works.
+
+Wed May 25 00:37:16 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_pkey_ec.c (ossl_ec_key_generate_key): Fix up RDoc.
+ (Init_ossl_ec): Rename EC#generate_key to EC#generate_key!. Make the
+ old name an alias of #generate_key!. This change is for consistency
+ with other PKey types. [ruby-core:45541] [Bug #6567]
+
+ * test/openssl/test_pkey_ec.rb: Use EC#generate_key! instead of
+ EC#generate_key.
+
+Wed May 25 00:23:05 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_scan_args_set): check the arity after
+ adjusting argc for an option hash, for optimization in simpler
+ cases.
+
+Wed May 25 00:21:52 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (XCFLAGS): merge flags only for ruby itself from
+ ruby_cflags.
+
+Tue May 24 22:04:15 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_cipher.c (ossl_cipher_set_key, ossl_cipher_set_iv):
+ Reject too long values as well as too short ones. Currently they
+ just truncate the input but this would hide bugs and lead to
+ unexpected encryption/decryption results.
+
+ * test/openssl/test_cipher.rb: Test that Cipher#key= and #iv= reject
+ Strings with invalid length.
+
+Tue May 24 21:32:21 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_x509ext.c (ossl_x509ext_set_value): Use
+ ASN1_OCTET_STRING_set() instead of M_ASN1_OCTET_STRING_set(). Macros
+ prefixed by "M_" are discouraged to be used from outside OpenSSL
+ library[1].
+ (ossl_x509ext_get_value): Likewise, use ASN1_STRING_print() instead
+ of M_ASN1_OCTET_STRING_print().
+ [1] https://git.openssl.org/gitweb/?p=openssl.git;a=blob;f=CHANGES;h=bf61913d7b01212b4d8b2f3c13d71d645914f67c;hb=b6079a7835f61daa9fb2cbf9addfa86049523933#l878
+
+ * ext/openssl/ossl.h: Include openssl/asn1.h instead of
+ openssl/asn1_mac.h. It just includes openssl/asn1.h and defines some
+ additional "M_" macros.
+
+Tue May 24 18:52:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_scan_args_verify): verify the format to
+ scan if no invalid chars and variable argument length matching,
+ at the compile time if possible.
+
+Tue May 24 17:18:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/defines.h (ERRORFUNC, WARNINGFUNC): add fallback
+ definitions.
+
+Tue May 24 16:37:43 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in (ruby_cflags): separate from optflags [Bug #12409]
+ -fexcess-precision=standard and -fp-model precise are set to this now.
+
+ * configure.in (cflags): use ruby_cflags.
+
+Tue May 24 16:20:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (ERRORFUNC, WARNINGFUNC): __error__ and __warning__
+ attributes take a parenthesized string literal.
+
+Tue May 24 12:35:56 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
+
+ * common.mk: sort lines, and add missing dependencies suggested
+ by tool/update-deps
+
+Mon May 23 21:33:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/missing.h (isfinite): move from numeric.c.
+
+Mon May 23 21:09:06 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl.c (Init_openssl): Avoid reference to unset global
+ variable. ossl_raise() may be called before dOSSL is set. Since
+ global variables default to 0 and the default value of dOSSL set in
+ Init_openssl() is also Qfalse, there is no real issue but confusing.
+ Patch by Bertram Scharpf <software@bertram-scharpf.de>
+ [ruby-core:58264] [Bug #9101]
+
+Mon May 23 20:32:16 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_asn1.c, ext/openssl/ossl_bn.c,
+ ext/openssl/ossl_cipher.c, ext/openssl/ossl_digest.c
+ ext/openssl/ossl_engine.c, ext/openssl/ossl_ns_spki.c
+ ext/openssl/ossl_pkcs12.c, ext/openssl/ossl_pkcs7.c
+ ext/openssl/ossl_pkey.c, ext/openssl/ossl_pkey_ec.c
+ ext/openssl/ossl_rand.c, ext/openssl/ossl_ssl.c
+ ext/openssl/ossl_x509attr.c, ext/openssl/ossl_x509cert.c
+ ext/openssl/ossl_x509ext.c, ext/openssl/ossl_x509store.c: Use
+ StringValueCStr() where NUL-terminated string is expected.
+
+Mon May 23 20:20:12 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (isfinite): get rid of a warning on
+ cygwin. [Bug #12417][ruby-core:75691]
+
+Mon May 23 19:41:27 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_rand.c (ossl_rand_egd, ossl_rand_egd_bytes):
+ RAND_egd{_bytes,}() return -1 on failure, not 0.
+ Patch by cremno phobia <cremno@mail.ru>
+ [ruby-core:63795] [Bug #10053]
+ (ossl_pseudo_bytes): Similar, RAND_pseudo_bytes() may return 0 or
+ -1 on failure.
+
+Mon May 23 15:52:07 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (isfinite): isfinite does not always
+ exist. fixed build error on Windows introduced at r55123.
+
+Mon May 23 13:19:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_scan_args0): make compile error if the
+ format is wrong or does not match with the variable argument
+ length if possible.
+
+Mon May 23 12:47:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_scan_args0): raise fatal error if
+ variable argument length does not match, it is a bug in the code
+ which uses rb_scan_args, not a runtime error.
+
+Mon May 23 12:30:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/bigdecimal/bigdecimal.c (GetVpValueWithPrec): consider
+ non-finite float values not to raise FloatDomainError.
+ [ruby-core:75682] [Bug #12414]
+
+Mon May 23 12:21:18 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * array.c (rb_ary_fill): suppress warnings: 'item' may be used
+ uninitialized in this function
+
+Mon May 23 07:41:49 2016 Eric Wong <e@80x24.org>
+
+ * dir.c (dir_close): update RDoc for 2.3 #close change
+ [ruby-core:75679] [Bug #12413]
+
+Sun May 22 20:01:21 2016 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/drb/timeridconv.rb: use finalizer trick instead of thread.
+
+ * test/drb/ut_timerholder.rb: ditto.
+
+Sun May 22 17:25:18 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_options.rb: adjust test class name
+ to match file name
+
+Sun May 22 17:24:07 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * rename test/ruby/enc/test_casing_options.rb to test_case_options.rb
+ for consistency
+
+Sun May 22 17:06:55 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * transcode.c (enc_arg, str_transcode_enc_args, econv_args):
+ remove volatile, and add GC guards in callers.
+ [ruby-core:75664] [Bug #12411]
+
+Sun May 22 16:27:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/-test-/integer/core_ext.c: move testutil/integer.c.
+
+ * test/lib/-test-/integer.rb: extract implementation details from
+ test/unit/assertions.rb. [Bug #12408]
+
+Sun May 22 14:57:43 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * include/ruby/oniguruma.h: Extend OnigEncodingTypeDefine to define a
+ new encoding primitive 'case_map' for case mapping
+
+ * enc/utf-8.c, utf_16be/le.c, utf_32be/le.c:
+ add onigenc_unicode_case_map as case_map primitive
+
+ * enc/ascii.c, big5.c, cp949.c, emacs_mule.c, euc_jp/kr/tw.c, gb18030.c,
+ gbk.c, iso_8859_1/2/3/4/5/6/7/8/9/10/11/13/14/15/16.c, koi8_r/u.c,
+ shift_jis.c, us_ascii.c, windows_1250/1251/1252.c:
+ add onigenc_not_support_case_map as case_map primitive
+
+Sun May 22 14:45:45 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * regenc.h/c: Define new function onigenc_not_support_case_map
+
+Sun May 22 12:14:06 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_scan_args): use original rb_scan_args
+ when fmt is dynamic.
+
+Sun May 22 11:41:12 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * class.c (rb_scan_args): moved to bottom of the file to make the
+ effect of `#undef rb_scan_args` the minimum.
+
+ * include/ruby/ruby.h (rb_scan_args): overwrite only if GCC and
+ optimized. Visual C++ 14 or later can compile it but make it
+ conservative.
+
+Sat May 21 22:45:50 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_scan_args): don't use ALWAYS_INLINE with
+ `inline`. if gcc needs this duplication, do in ALWAYS_INLINE macro.
+
+Sat May 21 21:11:56 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_scan_args): use __VA_ARGS__ instead of
+ va_arg to allow compilers optimize more aggressive.
+ https://gustedt.wordpress.com/2011/07/10/avoid-writing-va_arg-functions/
+ rb_scan_args is now expected to be statically resolved.
+
+Sun May 22 02:41:52 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/zlib/zlib.c: remove hacky macro introduced at r30437.
+
+ * ext/zlib/zlib.c (gzfile_make_header): cast as long (instead of int).
+
+ * ext/zlib/zlib.c (gzfile_make_footer): ditto.
+
+Sat May 21 21:07:18 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in (ALWAYS_INLINE): force compilers the function inlined.
+
+Sat May 21 16:16:03 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_ssl.c (ossl_ssl_stop): Don't free the SSL struct
+ here. Since some methods such as SSLSocket#connect releases GVL,
+ there is a chance of use after free if we free the SSL from another
+ thread. SSLSocket#stop was documented as "prepares it for another
+ connection" so this is a slightly incompatible change. However when
+ this sentence was added (r30090, Add toplevel documentation for
+ OpenSSL, 2010-12-06), it didn't actually. The current behavior is
+ from r40304 (Correct shutdown behavior w.r.t GC., 2013-04-15).
+ [ruby-core:74978] [Bug #12292]
+
+ * ext/openssl/lib/openssl/ssl.rb (sysclose): Update doc.
+
+ * test/openssl/test_ssl.rb: Test this.
+
+Sat May 21 14:41:14 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl.c: [DOC] Fix SSL client example. The variable name
+ was wrong. Patch by Andreas Tiefenthaler <at@an-ti.eu> (@pxlpnk).
+ [GH ruby/openssl#32]
+
+Sat May 21 14:25:38 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_pkey_ec.c: rename PKey::EC#private_key? and
+ #public_key? to #private? and #public? for consistency with other
+ PKey types. Old names remain as alias. [ruby-core:45541] [Bug #6567]
+
+ * test/openssl/test_pkey_ec.rb (test_check_key): check private? and
+ public? works correctly.
+
+Sat May 21 12:40:36 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/lib/openssl/buffering.rb (read_nonblock, readpartial):
+ Remove impossible EOFError raise. Patch by Zach Anker
+ <zanker@squareup.com>. [GH ruby/openssl#23]
+
+Sat May 21 11:18:42 2016 Evgeni Golov <evgeni@golov.de>
+
+ * lib/ipaddr.rb: [DOC] fix documentation of IN6MASK to mention
+ IPv6. [Fix GH-1349]
+
+Sat May 21 11:12:53 2016 Dan Martinez <dfm@razorwind.org>
+
+ * io.c (Init_IO): [DOC] define dummy ARGF instead of ARGF.class to
+ re-enable the generation of ARGF documentation. [Fix GH-1358]
+
+Sat May 21 11:07:29 2016 0x01f7 <souk.0x01f7@gmail.com>
+
+ * doc/syntax/methods.rdoc (Method Names): add proper closing tag.
+ [Fix GH-1356]
+
+Sat May 21 09:26:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_CHECK_SETJMP): fix missing macro definition
+ for the configured result. fix up r55021.
+
+Sat May 21 00:36:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (rb_execarg_commandline): build command line string
+ from argument vector in rb_execarg.
+ [ruby-core:75611] [Bug #12398]
+
+Fri May 20 23:25:42 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl.c (ossl_pem_passwd_value): Added. Convert the
+ argument to String with StringValue() and validate the length is in
+ 4..PEM_BUFSIZE. PEM_BUFSIZE is a macro defined in OpenSSL headers.
+ (ossl_pem_passwd_cb): When reading/writing encrypted PEM format, we
+ used to pass the password to PEM_def_callback() directly but it was
+ problematic. It is not NUL character safe. And surprisingly, it
+ silently truncates the password to 1024 bytes. [GH ruby/openssl#51]
+
+ * ext/openssl/ossl.h: Add function prototype declaration of newly
+ added ossl_pem_passwd_value().
+
+ * ext/openssl/ossl_pkey.c (ossl_pkey_new_from_data): Use
+ ossl_pem_passwd_value() to validate the password String.
+
+ * ext/openssl/ossl_pkey_dsa.c (ossl_dsa_initialize, ossl_dsa_export):
+ ditto.
+
+ * ext/openssl/ossl_pkey_ec.c (ossl_ec_key_initialize,
+ ossl_ec_key_to_string): ditto.
+
+ * ext/openssl/ossl_pkey_rsa.c (ossl_rsa_initialize, ossl_rsa_export):
+ ditto.
+
+ * test/openssl/test_pkey_{dsa,ec,rsa}.rb: test this.
+
+Fri May 20 23:45:53 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * id_table.c (list_id_table_init): When unaligned word access is
+ prohibited and sizeof(VALUE) is 8 (64-bit machines),
+ capa should always be even number for 8-byte word alignment
+ of the values of a table. This code assumes that sizeof(ID) is 4,
+ sizeof(VALUE) is 8, and xmalloc() returns 8-byte aligned memory.
+ This fixes bus error on 64-bit SPARC Solaris 10.
+ [Bug #12406][ruby-dev:49631]
+
+Fri May 20 22:30:09 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * symbol.h (rb_id2sym): Use HAVE_BUILTIN___BUILTIN_CONSTANT_P
+
+Fri May 20 22:19:00 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * ext/date/date_core.c: [DOC] fix typos.
+ [fix GH-1360] patched by @soundasleep
+
+Fri May 20 21:26:58 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * include/ruby/defines.h (RB_GNUC_EXTENSION, RB_GNUC_EXTENSION_BLOCK):
+ macros for skipping __extension__ on non-GCC compilers.
+ * eval_error.c (warn_print): use RB_GNUC_EXTENSION_BLOCK instead of
+ __extension__ because __extension__ is a GNU extension.
+ Fix compile error on Solaris 10 with Oracle Solaris Studio 12.x.
+ [Bug #12397] [ruby-dev:49629].
+ * internal.h (rb_fstring_cstr, rb_fstring_enc_cstr): ditto
+ * include/ruby/encoding.h (rb_enc_str_new, rb_enc_str_new_cstr): ditto
+ * include/ruby/intern.h (rb_str_new, rb_str_new_cstr,
+ rb_usascii_str_new, rb_utf8_str_new, rb_tainted_str_new_cstr,
+ rb_usascii_str_new_cstr, rb_utf8_str_new_cstr,
+ rb_external_str_new_cstr, rb_locale_str_new_cstr,
+ rb_str_buf_new_cstr, rb_str_cat_cstr, rb_exc_new_cstr): ditto
+
+Fri May 20 21:17:13 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32ole/win32ole.c (fole_missing): make substring or dup to
+ share the content if possible.
+
+Fri May 20 19:48:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * internal.h (NEW_PARTIAL_MEMO_FOR): shrink buffer array not to
+ mark non-VALUE fields. fix check_rvalue_consistency abort with
+ RGENGC_CHECK_MODE=2.
+
+ * internal.h (NEW_CMP_OPT_MEMO): exclude struct cmp_opt_data from
+ the valid array range.
+
+ * enum.c (slicewhen_i): exclude inverted too.
+
+Thu May 19 21:21:57 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * re.c (rb_reg_match_m_p): [DOC] fix return value in rdoc.
+
+ * test/ruby/test_regexp.rb (TestRegexp#test_match_p): add some
+ tests from document.
+
+Thu May 19 13:22:44 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl.c (Init_openssl): register an ex_data index for
+ X509_STORE and X509_STORE_CTX respectively. Since they don't share
+ the ex_data index registry, we can't use the same index.
+ (ossl_verify_cb): use the correct index.
+
+ * ext/openssl/ossl_ssl.c (ossl_ssl_verify_callback): ditto.
+
+ * ext/openssl/ossl_x509store.c (ossl_x509store_set_vfy_cb): ditto.
+ (ossl_x509stctx_verify): ditto.
+
+ * ext/openssl/ossl.h (void ossl_clear_error): add extern declarations
+ of ossl_store_{ctx_,}ex_verify_cb_idx.
+
+ * ext/openssl/openssl_missing.c: remove X509_STORE_set_ex_data and
+ X509_STORE_get_ex_data.
+
+ * ext/openssl/openssl_missing.h: implement X509_STORE_get_ex_data,
+ X509_STORE_set_ex_data and X509_STORE_get_ex_new_index as macros.
+
+Thu May 19 13:11:35 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_x509attr.c (ossl_x509attr_set_value): check that the
+ argument is an OpenSSL::ASN1::Data before converting to ASN1_TYPE.
+ This fixes SEGV on OpenSSL::X509::Attribute#value=(non-asn1-value).
+
+ * test/openssl/test_x509attr.rb: add tests for OpenSSL::X509::Attribute.
+
+Thu May 19 12:10:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * re.c (rb_reg_match_m_p): fix match against empty string.
+ rb_str_offset returns the end when the position exceeds the
+ length. fix the range parameter of onig_search.
+ [ruby-core:75604] [Bug #12394]
+
+Thu May 19 11:37:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * re.c (rb_reg_match_m_p): should return false if no match, as the
+ document says. [Feature #8110]
+
+Thu May 19 00:17:01 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * re.c (reg_names_iter): specify capacify
+
+Wed May 18 21:29:59 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * thread.c (recursive_list_access): a object id may be a Bignum. so,
+ the list must be a objhash, instead of a identhash.
+ this fixes many test errors on mswin64 CI.
+
+Wed May 18 19:33:54 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * re.c (rb_reg_match_m_p): Introduce Regexp#match?, which returns
+ bool and doesn't save backref.
+
+Wed May 18 16:52:03 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_pkcs12.c (ossl_pkcs12_initialize): pop errors
+ leaked by PKCS12_parse(). This is a bug in OpenSSL, which exists
+ in the versions before the version 1.0.0t, 1.0.1p, 1.0.2d.
+
+Wed May 18 16:04:54 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/downloader.rb (Downloader::RubyGems.download): verify gems
+ only if RubyGems is 2.4 or later. old RubyGems fails to verify
+ almost all of bundled gems.
+
+Wed May 18 14:52:38 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_modify_expand): check integer overflow.
+ [ruby-core:75592] [Bug #12390]
+
+Wed May 18 13:11:44 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * re.c (match_ary_subseq): get subseq of match array without creating
+ temporary array.
+
+ * re.c (match_ary_aref): get element(s) of match array without creating
+ temporary array.
+
+ * re.c (match_aref): Use match_ary_subseq with handling irregulars.
+
+ * re.c (match_values_at): Use match_ary_aref.
+
+Wed May 18 13:03:07 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_x509cert.c (ossl_x509_verify): X509_verify()
+ family may put errors on 0 return (0 means verification failure).
+ Clear OpenSSL error queue before return to Ruby. Since the queue is
+ thread global, remaining errors in the queue can cause an unexpected
+ error in the next OpenSSL operation. [ruby-core:48284] [Bug #7215]
+
+ * ext/openssl/ossl_x509crl.c (ossl_x509crl_verify): ditto.
+
+ * ext/openssl/ossl_x509req.c (ossl_x509req_verify): ditto.
+
+ * ext/openssl/ossl_x509store.c (ossl_x509stctx_verify): ditto.
+
+ * ext/openssl/ossl_pkey_dh.c (dh_generate): clear the OpenSSL error
+ queue before re-raising exception.
+
+ * ext/openssl/ossl_pkey_dsa.c (dsa_generate): ditto.
+
+ * ext/openssl/ossl_pkey_rsa.c (rsa_generate): ditto.
+
+ * ext/openssl/ossl_ssl.c (ossl_start_ssl): ditto.
+
+ * test/openssl: check that OpenSSL.errors is empty every time after
+ running a test case.
+
+Wed May 18 12:07:42 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl.c (ossl_clear_error): Extracted from
+ ossl_make_error(). This prints errors in the OpenSSL error queue if
+ OpenSSL.debug is true, and clears the queue.
+ (ossl_make_error): use ossl_clear_error().
+
+ * ext/openssl/ossl.h: add prototype declaration of ossl_make_error().
+ (OSSL_BIO_reset) use ossl_clear_error() to clear the queue. Clearing
+ silently makes debugging difficult.
+
+ * ext/openssl/ossl_engine.c (ossl_engine_s_by_id): ditto.
+
+ * ext/openssl/ossl_ns_spki.c (ossl_spki_initialize): ditto.
+
+ * ext/openssl/ossl_pkcs7.c (ossl_pkcs7_verify): ditto.
+
+ * ext/openssl/ossl_pkey_dsa.c (ossl_dsa_initialize): ditto.
+
+ * ext/openssl/ossl_pkey_ec.c (ossl_ec_key_initialize): ditto.
+ (ossl_ec_group_initialize): ditto.
+
+ * ext/openssl/ossl_ssl.c (ossl_ssl_shutdown): ditto.
+
+Wed May 18 11:53:49 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_pkey_ec.c (ossl_ec_point_mul): Validate the
+ arguments before passing to EC_POINT(s)_mul(). Add description of this
+ method. [ruby-core:65152] [Bug #10268]
+
+ * test/openssl/test_pkey_ec.rb (test_ec_point_mul): Test that
+ OpenSSL::PKey::EC::Point#mul works.
+
+Wed May 18 11:19:59 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/ossl_bn.c (try_convert_to_bnptr): Extracted from
+ GetBNPtr(). This doesn't raise exception but returns NULL on error.
+ (GetBNPtr): Raise TypeError if conversion fails.
+ (ossl_bn_eq): Implement BN#==.
+ (ossl_bn_eql): #eql? should not raise TypeError even if the argument
+ is not compatible with BN.
+ (ossl_bn_hash): Implement BN#hash.
+
+ * ext/openssl/ossl_bn.c (Init_ossl_bn): Define #== and #hash.
+
+ * test/openssl/test_bn.rb: Test BN#eql?, #== and #hash
+
+Wed May 18 10:17:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (RB_INTEGER_TYPE_P): new macro and
+ underlying inline function to check if the object is an
+ Integer (Fixnum or Bignum).
+
+Wed May 18 09:52:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * enum.c (enum_sum, hash_sum, hash_sum_i, enum_sum_i, sum_iter):
+ Optimize for hashes when each method isn't redefined.
+
+Wed May 18 09:14:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * enum.c (enum_sum, int_range_sum): Extract int_range_sum from
+ enum_sum.
+
+Wed May 18 03:16:06 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * re.c (match_values_at): fix regression at r55036.
+ MatchData#values_at accepts Range.
+
+Wed May 18 02:02:58 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * re.c (match_aref): remove useless condition and call rb_fix2int.
+ rb_reg_nth_match handles negative index.
+
+Wed May 18 01:57:43 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * re.c (match_values_at): MatchData#values_at supports named captures
+ [Feature #9179]
+
+ * re.c (namev_to_backref_number): separated.
+
+Wed May 18 00:05:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * enum.c (enum_sum): Optimize for a range from int to int.
+
+ * test/ruby/test_enum.rb (test_range_sum): Move from test_range.rb,
+ and add assertions for some conditions.
+
+ * test/ruby/test_enum.rb (test_hash_sum): Move from test_hash.rb.
+
+ * test/ruby/test_hash.rb, test/ruby/test_range.rb: Remove test_sum.
+
+Tue May 17 23:08:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * enum.c (enum_sum): [DOC] Write documentation.
+
+Tue May 17 22:53:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * enum.c (enum_sum): Implement Enumerable#sum.
+
+ * test/ruby/test_enum.rb (test_sum): Test sum for Enumerable.
+
+ * test/ruby/test_hash.rb (test_sum): Test sum for Hash.
+
+ * test/ruby/test_range.rb (test_sum): Test sum for Range.
+
+Tue May 17 22:11:41 2016 Tanaka Akira <akr@fsij.org>
+
+ * object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
+ lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
+ lib/rubygems/specification.rb, lib/uri/generic.rb,
+ bootstraptest/test_eval.rb, basictest/test.rb,
+ test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
+ test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
+ test/csv/test_data_converters.rb, test/date/test_date.rb,
+ test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
+ test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
+ test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
+ test/ruby/test_bignum.rb, test/ruby/test_case.rb,
+ test/ruby/test_class.rb, test/ruby/test_complex.rb,
+ test/ruby/test_enum.rb, test/ruby/test_eval.rb,
+ test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
+ test/ruby/test_math.rb, test/ruby/test_module.rb,
+ test/ruby/test_numeric.rb, test/ruby/test_range.rb,
+ test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
+ test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
+ test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
+ test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
+
+Tue May 17 15:26:10 2016 Tanaka Akira <akr@fsij.org>
+
+ * [Feature #12005] Unify Fixnum and Bignum into Integer
+
+ * include/ruby/ruby.h (rb_class_of): Return rb_cInteger for fixnums.
+
+ * insns.def (INTEGER_REDEFINED_OP_FLAG): Unified from
+ FIXNUM_REDEFINED_OP_FLAG and BIGNUM_REDEFINED_OP_FLAG.
+
+ * vm_core.h: Ditto.
+
+ * vm_insnhelper.c (opt_eq_func): Use INTEGER_REDEFINED_OP_FLAG instead
+ of FIXNUM_REDEFINED_OP_FLAG.
+
+ * vm.c (vm_redefinition_check_flag): Use rb_cInteger instead of
+ rb_cFixnum and rb_cBignum.
+ (C): Use Integer instead of Fixnum and Bignum.
+
+ * numeric.c (fix_succ): Removed.
+ (Init_Numeric): Define Fixnum as Integer.
+
+ * bignum.c (bignew): Use rb_cInteger instead of rb_cBignum.
+ (rb_int_coerce): replaced from rb_big_coerce and return fixnums
+ as-is.
+ (Init_Bignum): Define Bignum as Integer.
+ Don't define ===.
+
+ * error.c (builtin_class_name): Return "Integer" for fixnums.
+
+ * sprintf.c (ruby__sfvextra): Use rb_cInteger instead of rb_cFixnum.
+
+ * ext/-test-/testutil: New directory to test.
+ Currently it provides utilities for fixnum and bignum.
+
+ * ext/json/generator/generator.c: Define mInteger_to_json.
+
+ * lib/mathn.rb (Fixnum#/): Redefinition removed.
+
+Tue May 17 11:58:58 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_CHECK_BUILTIN_SETJMP): declare t as NORETURN
+ to suppress warnings by -Wsuggest-attribute=noreturn.
+ [ruby-core:75510] [Bug #12383]
+
+Tue May 17 10:40:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_CHECK_SETJMP): needs the header and proper
+ arguments for builtin setjmp functions.
+
+Mon May 16 20:00:30 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.h: Additional uses of ONIG_CASE_MAPPING compilation switch
+
+Mon May 16 19:46:33 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * include/ruby/oniguruma.h: Introducing ONIG_CASE_MAPPING compilation
+ switch
+
+ * include/ruby/oniguruma.h, enc/unicode.h: Using ONIG_CASE_MAPPING
+ compilation switch
+
+Mon May 16 19:29:31 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * gems/bundled_gems: Update xmlrpc-0.1.1. xmlrpc-0.1.0 didn't allow
+ to install on 2.4.0dev.
+
+Mon May 16 13:28:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (FUNC_STDCALL, FUNC_CDECL, FUNC_FASTCALL): set
+ macro names explicitly to the old names, which are accidentally
+ changed at r54985, for backward compatibilities.
+ fiddle also depends on these names to fallback to ANSI names.
+ [ruby-core:75494] [Bug #12377]
+
+Mon May 16 11:39:02 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/xmlrpc.rb, lib/xmlrpc/*, test/xmlrpc: XMLRPC is bundled gem
+ on Ruby 2.4. It is extracted to https://github.com/ruby/xmlrpc
+ [Feature #12160][ruby-core:74239]
+ * gems/bundled_gems: ditto.
+
+Mon May 16 06:06:21 2016 Eric Wong <e@80x24.org>
+
+ * proc.c: fix RDoc of Proc#===/call/yield/[]
+ [Bug #12332]
+
+Sun May 15 20:55:31 2016 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/drb/timeridconv.rb: don't use keeper thread. [Bug #12342]
+
+ * test/drb/ut_timerholder.rb: ditto.
+
+Sun May 15 16:15:25 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * array.c (rb_ary_entry): extract rb_ary_elt to organize if-conditions
+ and check whether is embedded at once.
+
+Sun May 15 10:57:26 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_get_ev_const): warn deprecated constant even
+ in the class context. [ruby-core:75505] [Bug #12382]
+
+Sun May 15 03:13:01 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * iseq.h (struct iseq_compile_data): use struct rb_id_table
+ instead of st_table.
+
+ * iseq.c (prepare_iseq_build): don't allocate ivar_cache_table
+ until it has at least one element.
+
+ * iseq.c (compile_data_free): free ivar_cache_table only if it
+ is allocated.
+
+ * compile.c (get_ivar_ic_value): allocate if the table is not
+ allocated yet.
+
+Sat May 14 09:04:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (pkg_config): use xsystem consistently to set up
+ library path environment variable as well as latter pkg-config
+ calls. [ruby-dev:49619] [Bug #12379]
+
+Sat May 14 00:16:54 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * random.c (make_seed_value): append leading-zero-guard and get
+ rid of making a local copy of the seed.
+
+Fri May 13 08:46:42 2016 cremno <cremno@mail.ru>
+
+ * NEWS: drop FreeBSD < 4 support. [Fix GH-1339]
+ The most recent version affected by this is 3.5 and was released
+ in 2000.
+ https://www.freebsd.org/releases/3.5R/announce.html
+ https://en.wikipedia.org/wiki/History_of_FreeBSD#Version_history
+
+Fri May 13 03:12:09 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * include/ruby/defines.h (GCC_VERSION_SINCE): moved from internal.h.
+
+Fri May 13 03:11:20 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in (__builtin_constant_p): check.
+
+ * internal.h: Use HAVE_BUILTIN___BUILTIN_CONSTANT_P
+
+Fri May 13 03:10:39 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: use alternative keyword
+ to avoid macros conflicts with them.
+
+Thu May 12 01:54:08 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/mkmf.rb (try_func): get rid of conflict of declarations of
+ main(). checking local symbol reference does not make sense.
+
+Thu May 12 00:18:19 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/Makefile.sub (HAVE_QSORT_S): use qsort_s only for Visual Studio
+ 2012 or later, because VS2010 seems to causes a SEGV in
+ test/ruby/test_enum.rb.
+
+Wed May 11 23:59:47 2016 Masaya Tarui <tarui@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_getivar): describe fast-path explicit
+ (compiler friendly). [Bug #12274].
+
+Wed May 11 21:30:07 2016 Masaya Tarui <tarui@ruby-lang.org>
+
+ * compile.c (iseq_compile_each): share InlineCache during same
+ instance variable accesses. Reducing memory consumption,
+ rising cache hit rate and rising branch prediction hit rate
+ are expected. A part of [Bug #12274].
+
+ * iseq.h (struct iseq_compile_data): introduce instance
+ variable IC table for sharing.
+
+ * iseq.c (prepare_iseq_build, compile_data_free):
+ construct/destruct above table.
+
+Wed May 11 17:18:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * util.c (ruby_qsort): use qsort_s if available, for Microsoft
+ Visual Studio 2005 (msvcr80.dll) and mingw.
+
+Wed May 11 10:33:26 2016 Marcus Stollsteimer <sto.mar@web.de>
+
+ * COPYING: Remove trailing-whitespaces.
+ [ci skip][fix GH-1348]
+
+Tue May 10 21:05:45 2016 Benoit Daloze <eregontp@gmail.com>
+
+ * insns.def (defineclass): Also raise an error when redeclaring the
+ superclass of a class as Object and it has another superclass.
+ [Bug #12367] [ruby-core:75446]
+
+ * test/ruby/test_class.rb: test for above.
+
+Tue May 10 14:57:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * random.c (obj_random_bytes): base on bytes method instead of
+ rand method, not to call toplevel rand method.
+
+Tue May 10 13:07:28 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in (-fexcess-precision=standard): before r54895 -std=c99
+ is specified and it implied -fexcess-precision=standard.
+ Now with -std=gnu99, it should be explicitly specified.
+ https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
+
+Mon May 9 10:51:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (rb_thread_atfork_internal): move th to an argument.
+
+ * thread.c (rb_thread_atfork): do not repeat GET_THREAD().
+
+Mon May 9 10:46:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (rb_thread_atfork, rb_thread_atfork_before_exec): do
+ nothing unless working fork is available.
+
+ * thread_sync.c (rb_mutex_abandon_all): define only if working
+ fork is available.
+
+ * thread_sync.c (rb_mutex_abandon_keeping_mutexes): ditto.
+
+ * thread_sync.c (rb_mutex_abandon_locking_mutex): ditto.
+
+ * thread_win32.c (gvl_init): never used.
+
+Mon May 9 07:18:06 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * include/ruby/{defines,ruby}.h: need to define function attributes
+ alternatives in defines.h instead of ruby.h, because they are used
+ in oniguruma.h and the header used without including ruby.h at
+ encoding library sources.
+
+Mon May 9 06:30:12 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * include/ruby/ruby.h (CONSTFUNC, PUREFUNC): fixed build errors on
+ non-gcc build environments introduced at r54952.
+
+Mon May 9 02:51:51 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * gc.c (rb_gc_unprotect_logging): throw rb_memerror when it cannot
+ allocate memory. This is pointed out by Facebook's Infer.
+
+ * gc.c (gc_prof_setup_new_record): ditto.
+
+ * regparse.c (parse_regexp): ditto.
+
+ * util.c (MALLOC): use xmalloc and xfree like above.
+
+Mon May 9 02:39:16 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: check function attribute const and pure,
+ and define CONSTFUNC and PUREFUNC if available.
+ Note that I don't add those options as default because
+ it still shows many false-positive (it seems not to consider
+ longjmp).
+
+ * vm_eval.c (stack_check): get rb_thread_t* as an argument
+ to avoid duplicate call of GET_THREAD().
+
+Sun May 8 21:01:14 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/openssl/extconf.rb: assume it doesn't have SSLv2 related
+ functions when OPENSSL_NO_SSL2 is defined.
+ Usually openssl's header and the library (libssl) have the same
+ set of functions, but on some environment the library has functions
+ whose headers doesn't declare. (openssl/opensslconf.h and libssl.so
+ aren't be synchronized)
+ To detect such case explicitly check feature macro and remove
+ related functions.
+
+Sun May 8 18:51:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_home_dir_of): return the default home path if the
+ user name is the current user name, on platforms where struct
+ pwd is not supported. a temporary measure against
+ [Bug #12226].
+
+Sun May 8 08:51:38 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: add -Wsuggest-attribute=format and suppress warnings.
+
+Sun May 8 08:31:03 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: add -Wsuggest-attribute=noreturn and suppress warnings.
+
+Sun May 8 08:19:16 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: add -Werror=implicit-int to avoid missing type of
+ function declaration.
+
+Sat May 7 22:22:37 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/webrick/ssl.rb: Accept string value for SSLCertName. It is used
+ to invoke ssl server with command line.
+ [fix GH-1329] Patch by @kerlin
+ * test/webrick/test_ssl_server.rb: Added test for GH-1329
+
+Sat May 7 21:55:12 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * test/webrick/test_ssl_server.rb: Added basic test for `webrick/ssl`
+
+Sat May 7 16:22:13 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * random.c (int_pair_to_real_inclusive): optimize to multiply
+ without Bignum.
+
+Sat May 7 07:58:02 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * process.c (rb_exec_getargs): honor the expected argument types
+ over the conversion method. the basic language functionality
+ should be robust. [ruby-core:75388] [Bug #12355]
+
+Fri May 6 08:16:26 2016 David Silva <david.silva@digital.cabinet-office.gov.uk>
+
+ * enum.c (enum_find): [DOC] add more examples to the documentation
+ of Enumerable#detect, to show that it equals to Enumerable#find.
+ [Fix GH-1340]
+
+Thu May 5 18:08:31 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * test/ruby/test_complexrational.rb: Remove duplicated raise.
+
+Thu May 5 14:41:05 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * string.c (rb_str_sub): Fix a special match variable name.
+ [ci skip]
+
+Thu May 5 12:22:17 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (rb_eval_cmd, rb_catch_obj): use TH_JUMP_TAG with the
+ same rb_thread_t used for TH_PUSH_TAG, instead of JUMP_TAG with
+ the current thread global variable.
+
+Thu May 5 10:49:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * random.c (fill_random_bytes_syscall): use arc4random_buf if
+ available.
+
+Wed May 4 23:13:58 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * numeric.c (fix_plus): Remove rb_nucomp_add prototype
+ declaration.
+
+ * numeric.c (fix_mul): Remove rb_nucomp_mul prototype
+ declaration.
+
+ * internal.h (rb_nucomp_add, rb_nucomp_mul): add prototype
+ declarations.
+
+Wed May 4 18:38:00 2016 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * lib/net/http/header.rb (Net::HTTPHeader#{each_header,each_name,
+ each_capitalized_name,each_value,each_capitalized}): Return
+ sized enumerators.
+
+ * test/net/http/test_httpheader.rb: add test for above.
+
+Wed May 4 17:53:15 2016 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * lib/set.rb (Set#{delete_if,keep_if,collect!,reject!,select!,classify,divide},
+ SortedSet#{delete_if,keep_if}): Return sized enumerators.
+
+ * test/test_set.rb: add test for above.
+
+Tue May 3 23:25:48 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * numeric.c: [DOC] Update result of 123456789 ** -2.
+ [ruby-dev:49606] [Bug #12339]
+
+Tue May 3 23:13:16 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * internal.h (RCOMPLEX_SET_IMAG): undef RCOMPLEX_SET_IMAG
+ instead of duplicated undef RCOMPLEX_SET_REAL.
+
+Tue May 3 22:55:07 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * complex.c (rb_complex_set_imag): Fix to properly set imag
+ of complex.
+
+Tue May 3 22:19:55 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in (warnflags): use -std=gnu99 instead of
+ -std=iso9899:1999. [Feature #12336]
+
+Tue May 3 22:10:09 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (count_utf8_lead_bytes_with_word): Use __builtin_popcount
+ only if it can use SSE 4.2 POPCNT whose latency is 3 cycle.
+
+ * internal.h (rb_popcount64): use __builtin_popcountll because now
+ it is in fast path.
+
+Tue May 3 14:19:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (new_if_gen): set newline flag to NODE_IF to trace all
+ if/elsif statements. [ruby-core:67720] [Bug #10763]
+
+Tue May 3 05:35:54 2016 Eric Wong <e@80x24.org>
+
+ * process.c (disable_child_handler_fork_child):
+ initialize handler for SIGPIPE for !POSIX_SIGNAL
+
+Mon May 2 23:03:42 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c, include/ruby/win32.h (rb_w32_utruncate): implements new
+ truncate alternative which accepts UTF-8 path.
+
+ * file.c (truncate): use above function.
+ [Bug #12340]
+
+Mon May 2 20:59:21 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * re.c (str_coderange): to avoid function call when the string already
+ has coderange information.
+
+ * re.c (rb_reg_prepare_enc): add shortcut path when the regexp has
+ the same encoding of given string.
+
+ * re.c (rb_reg_prepare_re): avoid duplicated allocation of
+ onig_errmsg_buffer.
+
+
+Mon May 2 12:34:52 2016 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_refinement.rb (test_inspect): Use Integer instead of
+ Fixnum.
+
+Mon May 2 06:58:38 2016 Tanaka Akira <akr@fsij.org>
+
+ * complex.c: Don't refer rb_cFixnum and rb_cBignum.
+ (k_fixnum_p): Use FIXNUM_P.
+ (k_bignum_p): Use RB_TYPE_P.
+
+Mon May 2 01:27:59 2016 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_numeric.rb (test_step): Use Integer::FIXNUM_MAX.
+
+Mon May 2 01:15:01 2016 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_module.rb (test_name): Use Integer instead of Fixnum.
+
+Mon May 2 01:00:04 2016 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/test/unit/assertions.rb (assert_fixnum): Defined.
+ (assert_bignum): Defined.
+
+ * test/ruby/test_bignum.rb: Use assert_bignum.
+
+ * test/ruby/test_integer_comb.rb: Use assert_fixnum and assert_bignum.
+
+ * test/ruby/test_optimization.rb: Ditto.
+
+Mon May 2 00:41:53 2016 Tanaka Akira <akr@fsij.org>
+
+ * vm_trace.c (recalc_remove_ruby_vm_event_flags): Add a cast to
+ avoid signed integer overflow.
+
+Mon May 2 00:06:04 2016 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/envutil.rb: Define Integer::{FIXNUM_MIN,FIXNUM_MAX}.
+
+ * test/ruby/test_bignum.rb: Use Integer::{FIXNUM_MIN,FIXNUM_MAX}.
+
+ * test/ruby/test_bignum.rb: Ditto.
+
+ * test/ruby/test_integer_comb.rb: Ditto.
+
+ * test/ruby/test_marshal.rb: Ditto.
+
+ * test/ruby/test_optimization.rb: Ditto.
+
+Sun May 1 23:59:59 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * array.c (rb_ary_sum): fix for mathn
+
+ * test/ruby/test_array.rb (test_sum): ditto.
+
+Sun May 1 23:51:54 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * test/lib/test/unit.rb (Options#non_options): fixed wrong regexp.
+ if both positives and negatives were specified, positives had to
+ be specified from the beginning.
+
+Sun May 1 21:00:07 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c: drop Win2K support.
+
+Sun May 1 20:39:47 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * cont.c, hash.c, random.c, win32/win32.c: cleanup some Win9x/ME/NT4
+ support leftovers.
+ [fix GH-1328] patched by @cremno
+
+Sun May 1 07:30:44 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (search_nonascii): use nlz on big endian environments.
+
+ * internal.h (nlz_intptr): defined.
+
+Sun May 1 00:03:30 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in (__builtin_ctz): check.
+
+ * configure.in (__builtin_ctzll): check.
+
+ * internal.h (rb_popcount32): defined for ntz_int32.
+ it can use __builtin_popcount but this function is not used on
+ GCC environment because it uses __builtin_ctz.
+ When another function uses this, using __builtin_popcount
+ should be re-considered.
+
+ * internal.h (rb_popcount64): ditto.
+
+ * internal.h (ntz_int32): defined for ntz_intptr.
+
+ * internal.h (ntz_int64): defined for ntz_intptr.
+
+ * internal.h (ntz_intptr): defined as ntz for uintptr_t.
+
+ * string.c (search_nonascii): unroll and use ntz.
+
+Sat Apr 30 21:54:13 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (Init_Numeric): Gather Fixnum method definitions.
+
+Sat Apr 30 21:28:14 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_int_div): Define Integer#/.
+
+ * bignum.c (rb_big_div): Don't define Bignum#/.
+
+ * lib/mathn.rb (Integer#/): Replace Integer#/ instead of Bignum#/.
+
+Sat Apr 30 21:11:08 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_int_plus): Define Integer#+.
+
+ * bignum.c (rb_big_plus): Don't define Bignum#+.
+
+Sat Apr 30 21:01:20 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_int_minus): Define Integer#-.
+
+ * bignum.c (rb_big_minus): Don't define Bignum#-.
+
+Sat Apr 30 20:53:33 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_int_mul): Define Integer#*.
+
+ * bignum.c (rb_big_mul): Don't define Bignum#*.
+
+Sat Apr 30 20:30:44 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_int_modulo): Define Integer#%.
+
+ * bignum.c (rb_big_modulo): Don't define Bignum#%.
+
+Sat Apr 30 20:17:08 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_equal): Define Integer#==.
+
+ * bignum.c (rb_big_eq): Don't define Bignum#==.
+
+Sat Apr 30 19:41:15 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_gt): Define Integer#>.
+
+ * bignum.c (rb_big_gt): Don't define Bignum#>.
+ Renamed from big_gt.
+
+ * internal.h (rb_big_gt): Declared.
+
+Sat Apr 30 19:24:40 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_ge): Define Integer#>=.
+
+ * bignum.c (rb_big_ge): Don't define Bignum#>=.
+ Renamed from big_ge.
+
+ * internal.h (rb_big_ge): Declared.
+
+Sat Apr 30 19:20:40 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * doc/standard_library.rdoc: Remove obsoleted classes and modules.
+
+Sat Apr 30 19:09:23 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_lt): Define Integer#<.
+
+ * bignum.c (rb_big_lt): Don't define Bignum#<.
+ Renamed from big_lt.
+
+ * internal.h (rb_big_lt): Declared.
+
+Sat Apr 30 18:44:05 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_le): Define Integer#<=.
+
+ * bignum.c (rb_big_le): Don't define Bignum#<=.
+ Renamed from big_le.
+
+ * internal.h (rb_big_le): Declared.
+
+Sat Apr 30 18:11:44 2016 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (Init_Bignum): Define Integer::GMP_VERSION.
+
+Sat Apr 30 16:58:18 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_remainder): Define Integer#remainder.
+
+ * bignum.c (rb_big_remainder): Don't define Bignum#remainder.
+
+ * internal.h (rb_big_remainder): Declared.
+
+Sat Apr 30 15:29:24 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_int_uminus): {Fixnum,Bignum}#-@ is unified into
+ Integer.
+
+ * bignum.c (rb_big_uminus): Don't define Bignum#-@.
+
+Sat Apr 30 14:42:20 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_int_idiv): {Fixnum,Bignum}#div is unified into
+ Integer.
+
+ * bignum.c (rb_big_idiv): Don't define Bignum#div.
+
+Sat Apr 30 14:25:55 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_int_modulo): {Fixnum,Bignum}#modulo is unified into
+ Integer.
+
+ * bignum.c (rb_big_modulo): Don't define Bignum#modulo.
+
+Sat Apr 30 14:04:30 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_divmod): {Fixnum,Bignum}#divmod is unified into
+ Integer.
+
+ * bignum.c (rb_big_divmod): Don't define Bignum#divmod.
+
+Sat Apr 30 13:20:00 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_fdiv): {Fixnum,Bignum}#fdiv is unified into
+ Integer.
+
+ * bignum.c (rb_big_fdiv): Don't define Bignum#fdiv.
+
+Sat Apr 30 12:25:43 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_int_pow): {Fixnum,Bignum}#** is unified into
+ Integer.
+
+ * bignum.c (rb_big_pow): Don't define Bignum#**.
+
+Sat Apr 30 12:28:59 2016 Tanaka Akira <akr@fsij.org>
+
+ * bignum.c (rb_big_comp): Renamed from rb_big_neg.
+
+ * numeric.c (fix_comp): Renamed from fix_rev.
+
+Sat Apr 30 12:25:43 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_comp): {Fixnum,Bignum}#~ is unified into
+ Integer.
+
+ * bignum.c (rb_big_neg): Don't define Bignum#~.
+
+ * internal.h (rb_big_neg): Declared.
+
+Sat Apr 30 12:07:42 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_and): {Fixnum,Bignum}#& is unified into
+ Integer.
+
+ * bignum.c (rb_big_and): Don't define Bignum#&.
+
+Sat Apr 30 11:56:15 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/thread: removed dummy extension library. thread_sync.c
+ provides "thread.rb" already.
+
+Sat Apr 30 11:53:48 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_or): {Fixnum,Bignum}#| is unified into
+ Integer.
+
+ * bignum.c (rb_big_or): Don't define Bignum#|.
+
+Sat Apr 30 11:18:47 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * vm_trace.c: Fix typos. [ci skip]
+
+Sat Apr 30 10:09:04 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/pty/pty.c (establishShell): honor USER environment variable
+ and login name over uid, one uid can be shared by some login
+ names.
+
+Fri Apr 29 22:40:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * doc/maintainers.rdoc (ext/io/nonblock): still maintained, as
+ well as ext/io/wait, which is the origin.
+
+Fri Apr 29 21:18:12 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * doc/maintainers.rdoc (ext/win32): of course, it's still maintained.
+
+Fri Apr 29 21:03:10 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * gems/bundled_gems: Update latest gems, test-unit-3.1.8 and rake-11.1.2.
+
+Fri Apr 29 20:43:02 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * doc/maintainers.rdoc: Update latest maintainers list on Ruby 2.4
+
+Fri Apr 29 19:52:45 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * doc/maintainers.rdoc: Removed deprecated entries. These are already deleted.
+
+Fri Apr 29 19:48:45 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * doc/maintainers.rdoc: Removed Ruby 1.8 entries. It's not necessary to
+ Ruby 2.4 or later.
+
+Thu Apr 28 17:03:17 2016 Nicholas Maccharoli <nmaccharoli@gmail.com>
+
+ * hash.c (rb_hash_update_{block,func}_callback): dry up hash
+ update callback code. [Fix GH-1338]
+
+Thu Apr 28 16:52:05 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * re.c (rb_reg_prepare_enc): use rb_enc_asciicompat(enc) instead of
+ rb_enc_str_asciicompat_p(str) to avoid useless rb_enc_get(str) call.
+
+Thu Apr 28 16:33:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse.rb: [DOC] fix example code. base on the code by
+ Semyon Gaivoronskiy in [ruby-core:75224]. [Bug #12323]
+
+Thu Apr 28 09:33:03 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems-2.6.4.
+ Please see entries of 2.6.4 on
+ https://github.com/rubygems/rubygems/blob/master/History.txt
+
+Thu Apr 28 04:49:07 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * configure.in (rb_cv_lgamma_r_pm0): check if lgamma_r(+0.0)
+ returns positive infinity, in addition to lgamma_r(-0.0).
+ AIX returns an incorrect result of negative infinity.
+
+ * math.c (ruby_lgamma_r): handle +0.0, in addition to -0.0.
+
+Thu Apr 28 01:11:14 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * time.c: define _DEFAULT_SOURCE because glibc 2.20 deprecates
+ _BSD_SOURCE.
+ https://sourceware.org/glibc/wiki/Release/2.20
+
+Thu Apr 28 00:27:55 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_xor): {Fixnum,Bignum}#^ is unified into
+ Integer.
+
+ * bignum.c (rb_big_xor): Don't define Bignum#^.
+
+Wed Apr 27 20:53:59 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_aref): {Fixnum,Bignum}#[] is unified into
+ Integer.
+
+ * bignum.c (rb_big_aref): Don't define Bignum#<<.
+
+ * internal.h (rb_big_aref): Declared.
+
+Wed Apr 27 16:10:35 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/instruction.rb: fix to follow current implementation.
+
+Wed Apr 27 15:47:54 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/stringio/stringio.c (strio_s_new): warn if a block is given,
+ as well as IO.new.
+
+Wed Apr 27 14:29:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (ruby_only_for_internal_use): raise fatal error when
+ deprecated function only for internal use is called, not just a
+ warning.
+
+Tue Apr 26 23:42:30 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * tool/redmine-backporter.rb (rel): should not raise exceptions even if
+ the user input is wrong. only reports the error and continue process.
+
+Tue Apr 26 23:35:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (process_options): convert -e script to the encoding
+ given by a command line option on Windows. assume it is the
+ expected encoding. [ruby-dev:49461] [Bug #11900]
+
+Tue Apr 26 21:11:02 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_int_lshift): {Fixnum,Bignum}#<< is unified into
+ Integer.
+
+ * bignum.c (rb_big_lshift): Don't define Bignum#<<.
+
+Tue Apr 26 20:59:40 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_int_rshift): {Fixnum,Bignum}#>> is unified into
+ Integer.
+
+ * bignum.c (rb_big_rshift): Don't define Bignum#>>.
+
+Tue Apr 26 20:46:16 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_size): {Fixnum,Bignum}#size is unified into Integer.
+
+ * bignum.c (rb_big_size_m): Don't define Bignum#size.
+
+ * internal.h (rb_big_size_m): Declared.
+
+Tue Apr 26 20:09:08 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (rb_int_bit_length): {Fixnum,Bignum}#bit_length is
+ unified into Integer.
+
+ * bignum.c (rb_big_bit_length): Don't define Bignum#bit_length.
+
+ * internal.h (rb_big_bit_length): Declared.
+
+Tue Apr 26 19:56:16 2016 Tanaka Akira <akr@fsij.org>
+
+ * numeric.c (int_abs): Integer#{abs,magnitude} moved from
+ Fixnum and Bignum.
+
+ * bignum.c (rb_big_abs): Don't define Bignum#{abs,magnitude}.
+
+ * internal.h (rb_big_abs): Declared.
+
+Mon Apr 25 14:39:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/rbconfig/sizeof/extconf.rb: just check the existence of each
+ types, to reduce configuration time, especially cross-compiling.
+
+ * template/sizes.c.tmpl: calculate sizes of checked types at
+ compilation time.
+
+Mon Apr 25 11:27:27 2016 Marcus Stollsteimer <sto.mar@web.de>
+
+ * doc/extension.rdoc: Improvements to english grammars.
+ [Bug #12246][ruby-core:74792][ci skip]
+
+Mon Apr 25 11:17:50 2016 Marcus Stollsteimer <sto.mar@web.de>
+
+ * encoding.c: Fix return value of `Encoding::ISO8859_1.name`
+ [Bug #12313][ruby-core:75147][ci skip]
+ * ext/bigdecimal/bigdecimal.c: Fix code sample of `BigDecimal.new`
+
+Sun Apr 24 23:29:16 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * configure.in: add missing -lm for AIX.
+
+Sun Apr 24 18:33:58 2016 Kazuki Tsujimoto <kazuki@callcc.net>
+
+ * vm_insnhelper.c (INLINE): disable r54738 if __NO_INLINE__ is defined.
+ It caused "undefined reference to `vm_getivar'".
+
+Sun Apr 24 09:32:12 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * test/ruby/test_array.rb: Add test cases for Array#sum with
+ non-numeric objects.
+
+Sun Apr 24 04:21:27 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_insnhelper.c (INLINE): define as `inline` when it is optimized.
+ define as `static inline` when it is not optimized to keep
+ the symbol generated.
+
+ * vm_insnhelper.c (vm_getivar): use `INLINE` to force inline
+ so that a compiler inlines it into vm_getinstancevariable
+ and optimizes out is_attr and related branches.
+
+ * vm_insnhelper.c (vm_getivar): use `inline` to recommend inline.
+ Without this vm1_ivar_set is degraded.
+
+ benchmark results:
+ minimum results in each 5 measurements.
+ Execution time (sec)
+ name ruby 2.4.0dev (2016-04-23 trunk 54727) [x86_64-linux] ruby 2.4.0dev (2016-04-23 trunk 54733) [x86_64-linux] built-ruby
+ loop_whileloop 0.641 0.642 0.646
+ vm1_ivar* 1.002 0.999 0.831
+ vm1_ivar_set* 0.369 1.106 0.362
+
+ Speedup ratio: compare with the result of `ruby 2.4.0dev (2016-04-23
+ trunk 54727) [x86_64-linux]' (greater is better)
+ name ruby 2.4.0dev (2016-04-23 trunk 54733) [x86_64-linux]
+ built-ruby
+ loop_whileloop
+ 0.998 0.991
+ vm1_ivar*
+ 1.003 1.205
+ vm1_ivar_set*
+ 0.334 1.018
+
+Sat Apr 23 18:01:21 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * vm_insnhelper.c (vm_getivar): specify inline instead of static inline.
+ vm_getivar is called by vm_call_ivar and vm_getinstancevariable.
+ At least with GCC 4.8 and 5.3 on Linux, they are inlining it into
+ vm_call_ivar but not vm_getinstancevariable.
+ By `inline`, they correctly inline it and gains performance.
+
+ Speedup ratio: compare with the result of `ruby 2.4.0dev (2016-04-23
+ trunk 54727) [x86_64-linux]' (greater is better)
+ name built-ruby
+ loop_whileloop 1.001
+ vm1_ivar* 1.189
+ vm1_ivar_set* 1.024
+
+ Note the `inline`'s meaning is different between old GCC
+ and C99. Old GCC's inline means C99's extern inline.
+ https://gcc.gnu.org/onlinedocs/gcc/Inline.html
+ Since Ruby specify -std=iso9899:1999, it works like C99.
+
+Sat Apr 23 16:11:39 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_mul_size_overflow): use UNLIKELY
+ by user side to improve generality.
+
+Sat Apr 23 16:10:02 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * include/ruby/ruby.h (RB_LIKELY): use prefix in ruby.h.
+
+ * intern.h (LIKELY): define with RB_LIKELY.
+
+Sat Apr 23 13:27:25 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * NEWS: Add descriptions for Time#to_time updates.
+ [Bug #12271]
+
+Sat Apr 23 13:21:24 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * NEWS: Add descriptions for DateTime#to_time updates.
+ [Bug #12189]
+
+Sat Apr 23 11:21:27 2016 Marcus Stollsteimer <sto.mar@web.de>
+
+ * ext/date/date_core.c (Init_date_core): [DOC] Convert DateTime
+ documentation to RDoc from Markdown.
+ [ruby-core:75136] [Bug #12311]
+
+Sat Apr 23 09:03:35 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c: cygwin does not use w32_cmdvector, command line can be
+ other than UTF-8. [ruby-dev:49519] [Bug #12184]
+
+Sat Apr 23 01:00:03 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * configure.in: don't use the system-provided round(3) on AIX.
+ In AIX, round(0.49999999999999994) returns 1.0.
+ Use round() in numeric.c instead.
+
+Fri Apr 22 21:00:44 2016 Tanaka Akira <akr@fsij.org>
+
+ * test/ruby/test_time_tz.rb: Tests depends on Europe/Moscow removed
+ to avoid test failures due to the tzdata change.
+ https://github.com/eggert/tz/commit/8ee11a301cf173afb0c76e0315b9f9ec8ebb9d95
+ Found by naruse.
+
+Fri Apr 22 20:18:40 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_mul_size_overflow): added to handle
+ mul overflow efficiently.
+
+ * include/ruby/ruby.h (rb_alloc_tmp_buffer2): use rb_mul_size_overflow
+ and avoid division where it can define DSIZE_T.
+
+ * gc.c (xmalloc2_size): moved from ruby.h and use rb_mul_size_overflow.
+
+Fri Apr 22 20:34:04 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * time.c (time_asctime): [DOC] add ctime example, not only
+ asctime. [ruby-core:75126] [Bug #12310]
+
+Fri Apr 22 18:44:32 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * variable.c: use uint32_t instead of long to avoid confusion about
+ the type of ivtbl->numiv.
+
+Fri Apr 22 15:09:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval_jump.c (exec_end_procs_chain): restore previous error info
+ for each end procs. [ruby-core:75038] [Bug #12302]
+
+Fri Apr 22 15:04:56 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * tool/redmine-backporter.rb: the fullpath of merger.rb is too long to
+ copy&paste on Windows. show shorter name instead on the platform.
+ I'm sure that the user of this command on Windows is only me.
+
+Fri Apr 22 14:52:04 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * tool/merger.rb: remove temporary file.
+
+Fri Apr 22 11:27:03 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/net/http.rb: Improve documentation for SSL requests via GET method.
+ [fix GH-1325][ci skip] Patch by @jsyeo
+
+Fri Apr 22 10:51:13 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/webrick/ssl.rb: Support to add SSLCiphers option.
+ [fix GH-1321] Patch by @rhadoo
+
+Fri Apr 22 10:43:19 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * file.c, win32/file.c: Removed obsoleted safe level checks.
+ [fix GH-1327] Patch by @cremno
+
+Fri Apr 22 10:01:48 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * benchmark/bm_so_meteor_contest.rb: fix a typo.
+ [fix GH-1330][ci skip] Patch by @sachin21
+
+Fri Apr 22 04:57:01 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * gc.c (rb_alloc_tmp_buffer_with_count): added like xmalloc2 to
+ avoid duplicated check of size.
+
+ * gc.c (ruby_xmalloc2): added to keep separate layers.
+
+ * include/ruby/ruby.h (rb_alloc_tmp_buffer2): added to check
+ the size more statically.
+
+Fri Apr 22 04:54:40 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * include/ruby/ruby.h (LIKELY): moved from internal.h.
+
+ * include/ruby/ruby.h (UNLIKELY): ditto.
+
+Thu Apr 21 01:44:19 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * gc.c (objspace_malloc_prepare): remove size check because it is
+ used by objspace_xmalloc and objspace_xcalloc.
+ objspace_xmalloc introduces its own check in this commit.
+ objspace_xcalloc checks with xmalloc2_size (ruby_xmalloc2_size).
+
+ * gc.c (objspace_xmalloc0): common xmalloc function.
+
+ * gc.c (objspace_xmalloc): introduce its own size check.
+
+ * gc.c (objspace_xmalloc2): separated from ruby_xmalloc2 to clarify
+ the layer who has the responsibility to check the size.
+
+ * gc.c (objspace_xrealloc): remove duplicated size check.
+
+ * gc.c (ruby_xmalloc2): use objspace_xmalloc2.
+
+ * include/ruby/ruby.h (ruby_xmalloc2_size): follow the size limit
+ as SSIZE_MAX. Note that ISO C says size_t is unsigned integer.
+
+Thu Apr 21 12:14:04 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: check if succeeded in creating config.h.
+
+ * tool/ifchange: ignore failures when TEST_COLORS unmatched. just
+ use the default value if expected name is not contained in it.
+ [ruby-core:75046] [Bug #12303]
+
+Wed Apr 20 17:33:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/cgi/escape/escape.c (cgiesc_unescape): define unescape
+ method instead of _unescape, and should pass the optional
+ argument to the super method.
+
+ * lib/cgi/util.rb (CGI::Util#_unescape): remove intermediate
+ method.
+
+Wed Apr 20 15:52:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (syntax_error_initialize): move the default message,
+ "compile error", from parse.y. the default parameter should
+ belong to the class definition.
+
+ * parse.y (yycompile0): use the default parameter.
+
+Wed Apr 20 10:25:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (append_compile_error): use rb_syntax_error_append.
+
+ * error.c (rb_syntax_error_append): append messages into a
+ SyntaxError exception instance.
+
+ * parse.y (yycompile0): make new SyntaxError instance in main
+ mode, otherwise error_buffer should be a SyntaxError if error
+ has occurred.
+
+Tue Apr 19 17:42:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (err_vcatf): rename, and separate appending message from
+ creating a string buffer.
+
+ * error.c (rb_syntax_error_append): merge rb_error_vsprintf and
+ rb_compile_err_append.
+
+ * parse.y (parser_compile_error): use rb_syntax_error_append.
+
+Tue Apr 19 13:46:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (append_compile_error, compile_bug): pass iseq and get
+ error info and file from it, not by the thread error info.
+
+ * error.c (rb_report_bug_valist): take va_list instead of variadic
+ arguments, and just report the bug but not abort.
+
+Tue Apr 19 13:18:12 2016 Naotoshi Seo <sonots@gmail.com>
+
+ * lib/time.rb: revert r54167 because it would break
+ backward compatibilities, and it is documented that
+ Time.parse does not take into account time zone
+ abbreations other than ones described in RFC 822
+
+Tue Apr 19 13:12:03 2016 Naotoshi Seo <sonots@gmail.com>
+
+ * ChangeLog: Fix dates of previous commits
+
+Tue Apr 19 12:45:03 2016 Naotoshi Seo <sonots@gmail.com>
+
+ * ChangeLog: Add descriptions for logger updates
+ * NEWS: Add descriptions for logger updates
+
+Tue Apr 19 12:45:02 2016 Naotoshi Seo <sonots@gmail.com>
+
+ * lib/logger.rb: Add shift_period_suffix option
+
+Tue Apr 19 12:45:01 2016 Naotoshi Seo <sonots@gmail.com>
+
+ * lib/logger.rb: Allow specifying logger parameters in constructor
+ such as level, progname, datetime_format, formatter.
+
+Mon Apr 18 16:07:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_peephole_optimize): should not replace the
+ current target INSN, not to follow the replaced dangling link in
+ the caller. [ruby-core:74993] [Bug #11816]
+
+Mon Apr 18 12:56:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (flo_truncate): add an optional parameter, digits, as
+ well as Float#round. [Feature #12245]
+
+ * numeric.c (int_truncate): add an optional parameter, digits, as
+ well as Integer#round. [Feature #12245]
+
+Sun Apr 17 04:18:56 2016 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * tool/redmine-backporter.rb: revisions are strings.
+
+Sat Apr 16 14:26:49 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * ext/date/date_core.c : remove not used f_getlocal macro.
+ After r54553 f_getlocal macro is not used.
+
+Sat Apr 16 14:15:24 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * ext/date/date_core.c : remove not used f_utc6 macro.
+ After r54169 f_utc6 macro is not used.
+
+Sat Apr 16 10:00:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * struct.c (struct_make_members_list, rb_struct_s_def): member
+ names should be unique. [ruby-core:74971] [Bug #12291]
+
+ * struct.c (struct_make_members_list): extract making member name
+ list from char* va_list, with creating symbols without
+ intermediate IDs.
+
+Sat Apr 16 01:33:27 2016 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * tool/redmine-backporter.rb: sort revisions.
+
+Sat Apr 16 01:16:02 2016 Tanaka Akira <akr@fsij.org>
+
+ * array.c (rb_ary_sum): Don't yield same element twice.
+ Found by nagachika.
+
+Sat Apr 16 01:03:32 2016 Tanaka Akira <akr@fsij.org>
+
+ * array.c (rb_ary_sum): Fix SEGV by [1/2r, 1].sum.
+
+Fri Apr 15 23:52:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * rational.c (rb_rational_plus): rename from rb_rational_add
+ to be aligned with rb_fix_plus.
+
+ * array.c (rb_ary_sum): ditto.
+
+ * internal.h: ditto.
+
+Fri Apr 15 23:42:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * rational.c (rb_rational_add): rename from nurat_add.
+
+ * array.c (rb_ary_sum): use rb_rational_add directly.
+
+ * test/ruby/test_array.rb (test_sum): add assertions for an array of
+ Rational values.
+
+Fri Apr 15 22:31:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * array.c (rb_ary_sum): apply the precision compensated algorithm
+ for an array in which Rational and Float values are mixed.
+
+ * test/ruby/test_array.rb (test_sum): add assertions for the above
+ change.
+
+Fri Apr 15 22:30:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (rb_thread_setname): defer setting native thread name
+ set in initialize until the native thread is created.
+ [ruby-core:74963] [Bug #12290]
+
+Fri Apr 15 20:27:16 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/irb/ext/save-history.rb: Fix NoMethodError when method is not defined.
+
+Fri Apr 15 15:38:58 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * common.mk (benchmark): order options for built-ruby and compare-ruby.
+
+Fri Apr 15 14:14:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * test/ruby/test_array.rb (test_sum): add assertions for Rational and
+ Complex numbers.
+
+Fri Apr 15 10:07:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/io/console/console.c (console_key_pressed_p): raise the same
+ exception, "unknown virtual key code", for names with nul chars.
+ though console_win32_vk() considers the length and can deal with
+ nul chars, rb_sprintf() raised at PRIsVALUE previously, so quote
+ it if it is unprintable.
+
+Fri Apr 15 09:02:58 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/io/console/console.c (rb_sym2str): fallback definition for
+ older ruby. [ruby-core:74953] [Bug #12284]
+
+Thu Apr 14 21:46:36 2016 Tanaka Akira <akr@fsij.org>
+
+ * array.c (rb_ary_sum): Support the optional argument, init, and
+ block.
+
+Thu Apr 14 19:02:41 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/irb/ext/save-history.rb: suppress warning: method redefined;
+ discarding old save_history=.
+
+Thu Apr 14 14:58:14 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/tk/tkutil/tkutil.c (tk_hash_kv): the third argument can be
+ nil not only an Array. reported by @windwiny at
+ https://github.com/ruby/ruby/commit/cdaa94e#commitcomment-17096618
+
+Thu Apr 14 14:28:55 2016 cremno phobia <cremno@mail.ru>
+
+ * cont.c (fiber_initialize_machine_stack_context): fix wrong
+ _MSC_VER check, should be decimal but not hexadecimal.
+ [ruby-core:74936] [Bug #12279]
+
+Wed Apr 13 22:51:38 2016 Tanaka Akira <akr@fsij.org>
+
+ * array.c (rb_ary_sum): Array#sum is implemented.
+ Kahan's compensated summation algorithm for precise sum of float
+ numbers is moved from ary_inject_op in enum.c.
+
+ * enum.c (ary_inject_op): Don't specialize for float numbers.
+
+ [ruby-core:74569] [Feature #12217] proposed by mrkn.
+
+Wed Apr 13 15:56:35 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (flo_ceil): add an optional parameter, digits, as
+ well as Float#round. [Feature #12245]
+
+ * numeric.c (flo_floor): add an optional parameter, digits, as
+ well as Float#round. [Feature #12245]
+
+ * numeric.c (int_ceil): add an optional parameter, digits, as
+ well as Integer#round. [Feature #12245]
+
+ * numeric.c (int_floor): add an optional parameter, digits, as
+ well as Integer#round. [Feature #12245]
+
+Wed Apr 13 14:47:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (Init_File): add alias File.empty? to File.zero?.
+ [Feature #9969]
+
+Wed Apr 13 14:36:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (assign_in_cond): allow multiple assignment in
+ conditional expression. [Feature #10617]
+
+Wed Apr 13 14:11:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_big_size): add wrapper function of BIGSIZE and
+ rename the method function with _m suffix.
+
+ * numeric.c (int_round_zero_p): extracted from rb_int_round.
+ optimize for Bignum, and convert VALUE returned by Numeric#size
+ to long.
+
+Wed Apr 13 12:00:08 2016 Koichi Sasada <ko1@atdot.net>
+
+ * test/ruby/test_basicinstructions.rb: add a test to check access
+ instance variables on special const objects.
+
+ All of such objects are frozen, so that we can not set instance
+ variables for them. But we can read instance variables and return
+ default value (nil).
+
+Tue Apr 12 20:40:35 2016 Kaneko Yuichiro <spiketeika@gmail.com>
+
+ * ext/date/date_core.c (time_to_time): should preserve timezone
+ info. [ruby-core:74889] [Bug #12271]
+
+Tue Apr 12 11:51:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (new_label_body): initialize bit fields, since
+ compile_data_alloc does not clear the memory. [Bug #12082]
+
+Mon Apr 11 20:18:43 2016 Koichi Sasada <ko1@atdot.net>
+
+ * vm_backtrace.c (frame2klass): filter only for imemo_ment.
+ T_IMEMO/imemo_iseq can be passed here.
+
+Mon Apr 11 17:43:04 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_optimize): disable tail call optimization in
+ rescued, rescue, and ensure blocks.
+ [ruby-core:73871] [Bug #12082]
+
+Mon Apr 11 06:54:39 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (apply2files): apply to a VALUE vector instead of a
+ temporary array.
+
+Sun Apr 10 20:54:16 2016 Joe Swatosh <joe.swatosh@gmail.com>
+
+ * ext/win32/lib/win32/registry.rb (DeleteValue, DeleteKey): fix
+ API names. [ruby-core:74863] [Bug #12264]
+
+Sun Apr 10 17:47:42 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (rb_realpath_internal): no argument conversions since
+ this internal function does not need to_path and encoding
+ conversions, not to be affected by the default internal
+ encoding.
+
+Sat Apr 9 10:03:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * load.c (rb_f_load): raise with the original path name before
+ encoding conversion.
+
+Sat Apr 9 02:05:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * bignum.c (rb_cstr_parse_inum): [EXPERIMENTAL] new function to
+ parse integer in C-string with length. the name and the
+ arguments may be changed in the future.
+
+ * bignum.c (rb_str_to_inum): preserve encoding of the argument in
+ error messages, and no longer needs to copy non-terminated
+ strings.
+
+ * bignum.c (rb_str2big_{poweroftwo,normal,karatsuba,gmp}): ditto.
+
+Thu Apr 7 19:04:03 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * doc/regexp.rdoc (comments): [DOC] terminators cannot appear in
+ comments. [ruby-core:74838] [Bug #12256]
+
+Thu Apr 7 11:24:14 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/tk/tkutil/tkutil.c (cbsubst_initialize): fix out-of-bound
+ access when no arguments given. `p Tk::Event.new` crashed.
+
+Fri Apr 1 01:26:00 2016 Benoit Daloze <eregontp@gmail.com>
+
+ * ext/coverage/coverage.c: Fully reset coverage to not persist global state.
+ It was returning old file coverages as empty arrays to the user.
+ [ruby-core:74596] [Bug #12220]
+
+ * ext/coverage/coverage.c (rb_coverages): remove unused static state.
+
+ * thread.c: Moved and renamed coverage_clear_result_i to reset_coverage_i.
+
+ * test/coverage/test_coverage.rb: improve precision of tests.
+
+Wed Apr 6 22:41:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (rb_cv_lgamma_r_m0): fix the condition for
+ lgamma_r(-0.0). [Bug #12249]
+
+Wed Apr 6 17:38:42 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * tool/downloader.rb (RubyGems.download): follow the change of the
+ rubygems ssl_certs directory tree introduced by previous commit.
+
+Wed Apr 6 15:00:27 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems-2.6.3.
+ Please see entries of 2.6.3 on
+ https://github.com/rubygems/rubygems/blob/master/History.txt
+
+Wed Apr 6 14:13:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (rb_cv_lgamma_r_m0): check if lgamma_r(-0.0)
+ returns negative infinity. [Bug #12249]
+
+ * math.c (ruby_lgamma_r): define by the configured result.
+
+Wed Apr 6 10:56:15 2016 Anton Davydov <antondavydov.o@gmail.com>
+
+ * lib/logger.rb (Logger#level=): remove unnecessary local
+ variable.
+
+ * lib/logger.rb (Logger#initialize, Logger#reopen): [DOC] mention
+ the default values. cherrypicked from [GH-1319].
+
+Wed Apr 6 10:17:53 2016 cremno phobia <cremno@mail.ru>
+
+ * math.c (ruby_lgamma_r): missing/lgamma_r.c is used on Windows,
+ since msvcrt does not provide it.
+
+ * missing/lgamma_r.c (lgamma_r): fix lgamma(-0.0).
+ [ruby-core:74823] [Bug #12249]
+
+Wed Apr 6 01:22:55 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * math.c (ruby_lgamma_r): mswin's lgamma_r also seems to be wrong.
+ cf. [Bug #12249]
+
+Wed Apr 6 00:53:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * math.c (ruby_lgamma_r): fix lgamma(-0.0) on mingw and OSX.
+
+ * math.c (ruby_tgamma): fix tgamma(-0.0) on mingw.
+ [ruby-core:74817] [Bug #12249]
+
+Tue Apr 5 14:50:28 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/nkf/nkf-utf8/nkf.c (mime_putc): fix typo.
+ [Bug #12202] [ruby-core:74802]
+
+Tue Apr 5 00:06:44 2016 Aeris <aeris@imirhil.fr>
+
+ * ext/openssl/ossl_ssl.c (ossl_ssl_tmp_key): Access to ephemeral
+ TLS session key in case of forward secrecy cipher. Only
+ available since OpenSSL 1.0.2. [Fix GH-1318]
+
+ * ext/openssl/extconf.rb: Check for SSL_get_server_tmp_key.
+
+Mon Apr 4 23:37:05 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_core.h (rb_vm_struct): make at_exit a single linked list but
+ not RArray, not to mark the registered functions by the write
+ barrier. based on the patches by Evan Phoenix.
+ [ruby-core:73908] [Bug #12095]
+
+Mon Apr 4 17:43:45 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: change default value of
+ RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO 0.3 -> 0.2
+ RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO 0.8 -> 0.65
+
+ These values are same as Ruby 2.0.0.
+
+ This change cause GC counts.
+ However, generational GC reduced each (minor) GC time and
+ increase memory locality. So that not so big impact on my
+ benchmarking results.
+ (surprisingly, this fix speed up programs on some cases)
+
+ You can change these values by environment variables
+ if you feel wrong.
+
+Mon Apr 4 17:36:52 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (get_envparam_double): take an upper_bound.
+
+ And also take an accept_zero flag which allow to accept zero
+ even if lower_bound is set.
+
+ * gc.c (ruby_gc_set_params): fix parameters.
+
+ RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO set 0.9 as *lower_bound*, so that
+ it should be upper_bound.
+ Set RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO as lower bound.
+
+ Also set lower/upper bound of RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO to
+ RUBY_GC_HEAP_FREE_SLOTS_MIN/MAX_RATIO.
+
+Mon Apr 4 16:41:32 2016 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c (Init_VM): should pass tokens.
+
+Sun Apr 3 09:34:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (flodivmod): round division if it is a finite number
+ and module is required.
+
+ * numeric.c (dbl2ival): do not round here.
+
+ * numeric.c (flo_ceil): use dbl2ival.
+
+ * numeric.c (flo_round): round explicitly.
+
+Sat Apr 2 15:24:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/intern.h (rb_check_arity): returns argc.
+
+Fri Apr 1 20:58:33 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb, casefold.h: Data generation to implement
+ swapcase functionality for titlecase characters. Swapcase isn't defined
+ by Unicode, because the purpose/usage of swapcase is unclear anyway.
+ The implementation follows a proposal from Nobu, swapping the case of
+ each component of a titlecase character individually.
+ This means that the titlecase characters have to be decomposed.
+
+ * enc/unicode.c: Code using the above data.
+
+ * test/ruby/enc/test_case_mapping.rb: Tests for the above.
+
+Fri Apr 1 14:55:28 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * configure.in (AC_CONFIG_FILES): $srcdir/.git can be a file pointing
+ the real git_dir, such as when the git working tree is a "linked
+ working tree" (a working tree created by git-worktree). So use
+ git-rev-parse --git-dir to check if $srcdir is the top-level of a git
+ repository, not just checking if the $srcdir/.git directory does exist
+ or not. [ruby-core:74759] [Bug #12239]
+
+ * tool/change_maker.rb: use tool/vcs.rb to detect VCS. This used to have
+ its own VCS detection code, while we have tool/vcs.rb.
+
+ * tool/vcs.rb (detect): remove code duplication
+
+Fri Apr 1 04:50:44 2016 Eric Wong <e@80x24.org>
+
+ * ext/openssl/ossl_ssl.c (ossl_sslctx_s_alloc):
+ enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER by default
+ [Bug #12126]
+
+Fri Apr 1 01:13:55 2016 Benoit Daloze <eregontp@gmail.com>
+
+ * thread.c (update_coverage): Do not track coverage in loaded files
+ after Coverage.result. Avoids out-of-bounds access. [Bug #12237]
+
+ * ext/coverage/coverage.c (coverage_clear_result_i): document.
+
+Thu Mar 31 19:16:16 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: need to set initial value of GC_HEAP_FREE_SLOTS_GOAL_RATIO.
+
+Thu Mar 31 17:50:27 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: change additional allocation policy.
+
+ Introduce new environment variable
+ RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO (goal_ratio) to calculate the
+ ratio of additional memory.
+
+ Before this change, we add pages with the following formula
+ (when free_slots < total_pages * RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO):
+ next_pages = total_pages * RUBY_GC_HEAP_GROWTH_FACTOR
+
+ This addition can allocate too much.
+
+ With this change, we increase pages to satisfy the following formula:
+ next_free_slots = next_total_slots * goal_ratio
+ where
+ next_free_slots = free_slots + adding_slots
+ next_total_slots = total_slots + adding_slots.
+
+ If you want to prepare many free slots, increase this ratio.
+
+ If this variable is 0, then simply multiply
+ RUBY_GC_HEAP_GROWTH_FACTOR.
+
+ * gc.c (get_envparam_double): enable to accept 0.
+
+Thu Mar 31 17:48:25 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_marks_finish): fix syntax error.
+
+Thu Mar 31 16:49:36 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: simplify allocate/free detecting logic at the end of marking.
+
+ Before this change, heap_pages_min_slots are calculated at the
+ beginning sweeping phase. And this value is used at the end of
+ *next* marking phase.
+
+ To simplify it, we use this value at the end of this marking phase.
+ It means that we don't need to store this value as global state.
+
+ Also heap_pages_max_slots is calculated at the begging of sweeping
+ phase and used at the end of sweeping phase.
+ To simplify this logic, we introduced new global value
+ heap_pages_freeable_pages it means extra pages count we can free.
+ gc_sweep_step() checks this value and moves empty pages to tomb_heap
+ not more than this value.
+
+ Because of this fix, heap_pages_swept_slots is no longer needed.
+
+ * gc.c (rb_objspace_t::heap_pages): restruct the objspace global
+ status.
+
+ remove the following fields
+ * swept_slots (and heap_pages_swept_slots)
+ * min_free_slots (and heap_pages_min_free_slots)
+ * max_free_slots (and heap_pages_max_free_slots)
+ And add the following filed.
+ * freeable_pages (and heap_pages_freeable_pages)
+
+ * gc.c (heap_pages_free_unused_pages): unlink tomb heap pages
+ because tomb heap should have only freeable pages.
+
+ * gc.c (heap_extend_pages): add parameters for future extension.
+
+Thu Mar 31 16:43:02 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: add GC parameters to configure the following values:
+ * RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO:
+ allocate additional pages when free slots is lower than
+ the value (total_slots * (this ratio)).
+ * RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO:
+ allow to free pages when free slots is greater than
+ the value (total_slots * (this ratio)).
+
+ Before this change, these values are hard coded.
+
+ * gc.c (ruby_gc_params_t): ditto.
+
+ * gc.c (ruby_gc_set_params): ditto.
+
+Thu Mar 31 15:59:17 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_verify_heap_page): check the number of zombies.
+
+ * gc.c (gc_verify_heap_pages): check also tomb heap.
+
+Thu Mar 31 15:48:18 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c (gc_page_sweep): return free slots count.
+
+ * gc.c (gc_sweep_step): use returned free slots count.
+
+ * gc.c (gc_sweep_step): change variable name `next'
+ to `next_sweep_page'.
+
+Thu Mar 31 11:33:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/date/date_core.c (d_lite_strftime, dt_lite_strftime): [DOC]
+ fix indent not to be a big sole verbatim.
+
+Thu Mar 31 11:18:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/date/date_core.c (Init_date_core): [DOC] fix misplaced doc
+ of DateTime. [ruby-core:74729] [Bug #12233]
+
+Thu Mar 31 03:41:02 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/nkf/nkf-utf8/nkf.c: Merge upstream 69f7e74dde.
+ fix indent.
+
+Wed Mar 30 16:33:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * extension.rdoc, extension.ja.rdoc: [DOC] Fix some errors.
+ Renamed files, wrong method names or argument types; the example
+ GetDBM macro is now updated to the current version of the actual
+ code. patch by Marcus Stollsteimer in [ruby-core:74690].
+ [Bug #12228]
+
+Wed Mar 30 09:46:01 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/open-uri.rb: Use `userinfo` for authenticated proxy.
+ [fix GH-1148] Patch by @SokichiFujita
+ * test/open-uri/test_open-uri.rb: ditto.
+ [fix GH-1309] Patch by @jdamick
+
+Wed Mar 30 01:56:06 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * ext/nkf/nkf-utf8/nkf.c: Merge upstream 4f3edf80a0.
+ patched by Anton Sivakov [Bug #12201] [Bug #12202]
+
+Wed Mar 30 01:54:30 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/redmine-backporter.rb: add given revision to current changesets
+ on associating the revision to the related ticket.
+
+Wed Mar 30 01:53:17 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/merger.rb: update revision.h before merge.
+
+Tue Mar 29 19:33:54 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * addr2line.c: define toupper for its use. fix r54391.
+
+Tue Mar 29 19:23:46 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * include/ruby/ruby.h (rb_isupper, rb_islower, rb_isalpha, rb_isdigit,
+ rb_isalnum, rb_isxdigit, rb_isblank, rb_isspace, rb_isblank,
+ rb_iscntrl, rb_isprint, rb_ispunct, rb_isgraph,
+ rb_tolower, rb_toupper): use inline function to avoid function call.
+
+ * include/ruby/ruby.h (rb_isascii): use inline function to clarify
+ the logic.
+
+Tue Mar 29 18:56:55 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/redmine-backporter.rb (backport): show merger.rb's path.
+
+ * tool/redmine-backporter.rb (show): show current issue again if no
+ ticket number is given.
+
+ * tool/redmine-backporter.rb (rel): show error message if current
+ bugs.ruby-lang.org doesn't support the API.
+
+Tue Mar 29 18:54:34 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * tool/merger.rb: support to backport header as backport identifier.
+ Now you can specify by 'merge revision(s) 49254: [Backport #10738]'.
+
+Tue Mar 29 16:53:44 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb, casefold.h: Tweaked handling of 6
+ special cases in CaseUnfold_11_Table.
+
+ * enc/unicode.c: Adjustments for above.
+
+ * test/ruby/enc/test_case_mapping.rb: Tests for the above: Some tests in
+ test_titlecase activated; test_greek added. A test in test_cherokee fixed.
+
+Tue Mar 29 13:31:00 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Cleaned up some comments.
+
+Tue Mar 29 13:24:56 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb, casefold.h: Removing data for idempotent
+ titlecasing.
+
+ * enc/unicode.c: Adjust code to data removal.
+
+Tue Mar 29 12:45:18 2016 Laurent Arnoud <laurent@spkdev.net>
+
+ * lib/webrick/httpresponse.rb: Move error_body to method. It allow to
+ override the body more easily. [fix GH-1307]
+ * test/webrick/test_httpresponse.rb: ditto.
+
+Tue Mar 29 06:40:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (rb_compile_err_append): rb_thread_t::base_block is no
+ longer used.
+
+ * iseq.c (rb_iseq_compile_with_option): ditto, no protection is
+ needed.
+
+Tue Mar 29 06:39:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (struct parser_params): move parse_in_eval flag from
+ rb_thread_t.
+
+ * parse.y (rb_parser_set_context): set parsing context, not only
+ mild error flag.
+
+ * iseq.c (rb_iseq_compile_with_option): the parser now refers no
+ thread local states to be restored.
+
+ * vm_eval.c (eval_string_with_cref): ditto.
+
+Mon Mar 28 21:24:02 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * numeric.c (int_pos_p): fix typos.
+
+Mon Mar 28 14:54:49 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Refactoring in preparation for data reduction for
+ titlecase.
+
+Mon Mar 28 14:36:36 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Minor refactoring for I WITH DOT ABOVE.
+
+Mon Mar 28 14:26:24 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Removed code now covered by data from table.
+
+Mon Mar 28 11:49:21 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Adding comments. [ci skip]
+
+Mon Mar 28 11:30:23 2016 Shinichi Maeshima <netwillnet@gmail.com>
+
+ * lib/rubygems.rb: Fix `Gem.find_spec_for_exe` picks oldest gem.
+ https://github.com/travis-ci/travis-ci/issues/5798
+ https://github.com/rubygems/rubygems/pull/1566
+ * test/rubygems/test_gem.rb: ditto.
+
+Mon Mar 28 11:26:31 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems-2.6.2.
+ Please see entries of 2.6.2 on
+ https://github.com/rubygems/rubygems/blob/master/History.txt
+
+Mon Mar 28 11:02:31 2016 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * lib/rubygems/test_case.rb: Fix test on Windows for inconsistent temp path.
+ https://github.com/rubygems/rubygems/pull/1554
+ [Bug #12193][ruby-core:74431]
+
+Mon Mar 28 08:19:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * sprintf.c (rb_str_format): refactor floating point format of
+ Rational by using generic Integer functions.
+
+ * sprintf.c (rb_str_format): fix buffer overflow, length must be
+ greater than precision. reported by William Bowling <will AT
+ wbowling.info>.
+
+Sun Mar 27 12:13:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * sprintf.c (rb_str_format): convert Rational to floating point
+ format by using generic Integer functions, not by methods which
+ can be overwritten.
+
+Sat Mar 26 10:55:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (rb_int2str): conversion function to String for
+ generic Integer.
+
+ * numeric.c (rb_int_round): rounding function for generic
+ Integers.
+
+ * numeric.c (rb_int_{uminus,plus,minus,mul,idiv,modulo}): basic
+ arithmetic functions for generic Integers.
+
+ * numeric.c (FIXNUM_{POSITIVE,NEGATIVE,ZERO}_P): predict macros
+ only for Fixnum.
+
+Sat Mar 26 06:34:24 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * localeinit.c (rb_locale_charmap_index): fix prototype.
+ patched by Andreas Schwab [Bug #12218]
+
+Fri Mar 25 16:40:48 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_mapping.rb: Additional tests title case;
+ some not yet activated.
+
+Fri Mar 25 13:38:11 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * ext/openssl/extconf.rb: check SSL_CTX_set_next_proto_select_cb
+ function rather than OPENSSL_NPN_NEGOTIATED macro. it exists
+ even if it is disabled by OpenSSL configuration.
+ [ruby-core:74384] [Bug #12182]
+
+ * ext/openssl/ossl_ssl.c: update #ifdef(s) as above.
+
+ * test/openssl/test_ssl.rb: skip NPN tests if NPN is disabled.
+
+Fri Mar 25 11:08:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/uri/http.rb (URI::HTTP#initialize): [DOC] fix example,
+ missing mandatory arguments. [ruby-core:74540] [Bug #12215]
+
+Fri Mar 25 01:50:58 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * thread_pthread.c (reserve_stack): fix reserving position where
+ the stack growing bottom to top. [Bug #12118]
+
+Fri Mar 25 01:10:42 2016 Sebastian Schuberth <sschuberth@gmail.com>
+
+ * lib/mkmf.rb (find_executable0): On Windows, it is actually valid
+ to surround individual PATH directory entries with double
+ quotes. Remove these before joining the path as otherwise the
+ literal quotes would become part of the path, resulting in the
+ executable not to be found. [Fix GH-1305]
+
+Thu Mar 24 22:38:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * strftime.c (FMT, FMTV): remove recursive-assignments to get rid
+ of undefined behavior. [ruby-core:74532] [Bug #12213]
+
+Thu Mar 24 17:44:02 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * strftime.c (FMT_PADDING): extract format for padding.
+
+ * strftime.c (FMT_PRECISION): extract precision formula.
+
+ * strftime.c (FMTV): append formatted string to expand the result.
+
+Thu Mar 24 14:20:21 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * strftime.c (STRFTIME): deal with case conversion flags for
+ recursive formats.
+
+Thu Mar 24 12:43:26 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/date/date_core.c (dt_lite_iso8601): strftimev() always
+ returns a String, so append them directly.
+
+ * ext/date/date_core.c (d_lite_jisx0301, iso8601_timediv),
+ (dt_lite_jisx0301): format by the format string in local buffer
+ to prevent intermediate strings from GC.
+
+ * ext/date/date_core.c (mk_inspect_raw, mk_inspect): inspect by
+ "%+"PRIsVALUE, to prevent intermediate strings from GC.
+
+Thu Mar 24 11:43:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * strftime.c (rb_strftime_with_timespec): remove unnecessary
+ check, as `s` equals to `endp` when recursed STRFTIME resized
+ the capacity same as the size.
+
+Wed Mar 23 21:48:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * enum.c (ary_inject_op): put subtract operation out of if-clause.
+
+Wed Mar 23 21:38:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * enum.c (ary_inject_op): Use Kahan's compensated summation algorithm
+ for summing up float values.
+
+Wed Mar 23 20:56:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * strftime.c (rb_strftime_with_timespec): append formatted results
+ to the given string with expanding, and also deal with NUL chars.
+
+ * strftime.c (rb_strftime, rb_strftime_timespec): return formatted
+ string, not the length put in the given buffer.
+
+ * time.c (rb_strftime_alloc): no longer needs to retry with
+ reallocating buffers.
+
+ * time.c (time_strftime): no longer needs to split by NUL chars.
+
+Wed Mar 23 14:23:54 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/rdoc/ri/driver.rb (interactive): rescue NotFoundError raised in
+ expand_name. (display_name rescues NotFoundError by itself,
+ the original logic looks buggy...)
+
+Wed Mar 23 11:44:53 2016 cremno <cremno@mail.ru>
+
+ * marshal.c (r_long): cast to `signed char`, which is used
+ already, instead of SIGN_EXTEND_CHAR.
+
+ * parse.y: SIGN_EXTEND_CHAR is no longer used. [Fix GH-1302]
+
+Wed Mar 23 11:38:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * cygwin/GNUmakefile.in (MSYS2_ARG_CONV_EXCL_PARAM):
+ * add missing parentheses and remove double quotes.
+ * rename to get rid of recursive references.
+ * as --excludes-dir option is for a path name, its argument
+ should be converted.
+ [ruby-dev:49526] [Bug #12199]
+
+Wed Mar 23 10:39:38 2016 Koichi ITO <koic.ito@gmail.com>
+
+ * variable.c: Added documentation about order of `Module#constants`
+ [ci skip][Bug #12121][ruby-dev:49505][fix GH-1301]
+
+Tue Mar 22 21:08:30 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * include/ruby/oniguruma.h: Additional flag for characters that are titlecase.
+
+ * enc/unicode/case-folding.rb, casefold.h: Using above flag in data.
+
+ * enc/unicode.c: Marking capitalized character as unmodified if it is
+ already titlecase.
+
+ * test/ruby/enc/test_case_mapping.rb: Tests for above functionality.
+
+Tue Mar 22 14:18:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (lambda_body, parser_yylex): warn mismatched indentation
+ of lambda block.
+
+Tue Mar 22 11:36:49 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * time.c (wmul): wrong condition.
+ fixed many test failures on 32bit and LLP64 platforms.
+
+Tue Mar 22 10:31:34 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * time.c (wdiv, wmod): wdivmod0() assumes the 3rd and the 4th arguments
+ are valid pointers.
+ maybe checking them in wdivmod0() is better manner, but I guess that
+ passing real dummy pointers may be faster than checking and branching
+ in wdivmod0().
+ this commit fixes SEGV on 32bit and LLP64 platforms.
+
+Tue Mar 22 10:24:04 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * time.c (divmodv): void function never returns any value.
+
+Tue Mar 22 10:11:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/lib/test/unit.rb (Test::Unit::StatusLine#failed): print
+ failed messages only if replacing mode, otherwise defer them
+ until the end, to get rid of interleaving failures with progress
+ messages. refix r54195.
+
+Tue Mar 22 03:45:03 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * time.c (MUL_OVERFLOW_FIXWV_P): defined for FIXWV.
+
+ * time.c (wmul): use MUL_OVERFLOW_FIXWV_P and only switch.
+
+ * time.c (wmul): use mul which has Fixnum optimization.
+
+ * time.c (rb_time_magnify): If WIDEVALUE_IS_WIDER, wmul() has the same
+ optimized logic, else mul() has also the similar logic for Fixnum.
+
+ * time.c (rb_time_unmagnify): almost ditto.
+
+Tue Mar 22 03:10:09 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * time.c (divmodv): add the case both arguments are Fixnum.
+
+ * time.c (wquo): use quo which has Fixnum optimization.
+
+ * time.c (wdivmod0): added for WIDEVALUE_IS_WIDER.
+
+ * time.c (wdivmod): use wdivmod0 and divmodv.
+ divmodv has Fixnum optimization.
+
+ * time.c (wdiv): use wdivmod0 and div to avoid the use of divmodv which
+ calls id_quo whose return value is array.
+
+ * time.c (wmod): use wdivmod0 and mod to avoid the use of divmodv which
+ calls id_quo whose return value is array.
+
+Mon Mar 21 22:32:50 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * internal.h (rb_fix_divmod_fix): like r54213, use FIX2NUM only if
+ x == FIXNUM_MIN && y == -1. This must be a rare case and it is
+ expected compiler to handle well.
+
+Mon Mar 21 22:15:11 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * time.c (mod): Add Fixnum case.
+
+ * time.c (quo): c can be Fixnum except a == FIXNUM_MIN && b == -1.
+ Such case can be optimized out because quo()'s argument is constant.
+
+Mon Mar 21 22:09:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * internal.h (rb_fix_mul_fix): multiply converted values, not
+ object VALUEs.
+
+Mon Mar 21 20:18:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk (TEST_EXCLUDES, EXCLUDE_TESTFRAMEWORK): use full spell
+ long option.
+
+ * cygwin/GNUmakefile.in (MSYS2_ARG_CONV_EXCL): suppress path name
+ conversions by msys2. [ruby-dev:49525] [Bug #12199]
+
+Mon Mar 21 19:09:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (enc_succ_alnum_char): try to skip an invalid character
+ gap between GREEK CAPITAL RHO and SIGMA.
+ [ruby-core:74478] [Bug #12204]
+
+Mon Mar 21 18:55:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * node.c (rb_gc_mark_node): NODE_MATCH2 can have nd_args, u3,
+ since r54100.
+
+Sun Mar 20 21:17:13 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * internal.h (rb_int128t2big): declare only when HAVE_INT128_T.
+ fixed a compile error with VC++ introduced at r54203.
+
+Sun Mar 20 20:10:14 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * internal.h (DLONG): defined if long is 32bit (and LONG_LONG is 64bit;
+ but LONG_LONG is always defined as 64bit), or there's int128_t.
+
+ * internal.h (DL2NUM): defined if DLONG is defined.
+
+ * internal.h (rb_fix_mul_fix): defined for `Fixnum * Fixnum`.
+
+ * insns.def (opt_mul): use rb_fix_mul_fix().
+
+ * numeric.c (fix_mul): ditto.
+
+ * time.c (mul): ditto.
+
+Sun Mar 20 18:53:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (fix_gt, fix_ge, fix_lt, fix_le): optimize comparisons
+ Fixnum against Bignum by rb_big_cmp in inversed order without
+ new Bignum instance.
+
+Sun Mar 20 18:44:52 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * time.c (add): remove FIXABLE() which is in LONG2NUM().
+
+ * time.c (sub): ditto.
+
+ * time.c (mul): ditto.
+
+Sun Mar 20 04:46:02 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * bignum.c (rb_big_cmp): reduce the code.
+
+ * bignum.c (rb_big_eq): If normalized bignum is still bignum,
+ it must be larger than fixnum.
+
+Sat Mar 20 00:58:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * include/ruby/intern.h (rb_big_odd_p, rb_big_even_p): move to
+ internal.h so that they are exported only for ruby itself.
+
+ * internal.h (rb_big_odd_p, rb_big_even_p): ditto.
+
+Sat Mar 19 21:56:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/lib/test/unit.rb (Test::Unit::StatusLine#failed): defer
+ failed messages until the end in verbose mode, to get rid of
+ interleaving failures with progress messages.
+
+Sat Mar 19 21:53:35 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (fix_cmp): invert the result as the comparison is
+ inverted.
+
+Sat Mar 19 18:32:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * numeric.c (int_to_f): raise NotImplementedError when a receiver
+ class is unknown.
+
+ * test/-ext-/integer/test_my_integer.rb (test_my_integer_to_f): modify
+ a test for the above change.
+
+Sat Mar 19 18:21:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * bignum.c (Bignum#<=>): remove it because they are unified with
+ Integer#<=>.
+
+ * numeric.c (Integer#<=>, Fixnum#<=>): move <=> method from Fixnum to
+ Integer.
+
+ * numeric.c (int_cmp): add this method for Integer#<=>.
+
+ * test/-ext-/integer/test_my_integer.rb (test_my_integer_cmp): add a
+ test to examine Integer#<=> for unknown subclasses.
+
+Sat Mar 19 14:46:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * iseq.c (rb_iseq_compile_with_option): make the parser in mild
+ error.
+
+ * load.c (rb_load_internal0): ditto.
+
+ * parse.y (yycompile0): return the error message within the error
+ to be raised. [Feature #11951]
+
+ * parse.y (parser_compile_error): accumulate error messages in the
+ error_buffer.
+
+Sat Mar 19 03:57:13 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * time.c (LOCALTIME): organize #ifdefs.
+
+ * time.c (GMTIME): define only ifndef HAVE_STRUCT_TM_TM_GMTOFF.
+
+Sat Mar 19 03:53:31 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in (rb_cv_member_struct_tm_tm_gmtoff): For Linux (glibc)
+ define _BSD_SOURCE for time.h to define struct tm.tm_gmtoff.
+
+ * time.c: define _BSD_SOURCE at the top.
+
+Sat Mar 19 03:00:50 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/-ext-/time/test_new.rb (test_timespec_new): change a gmtoff
+ test to a better one that does not depend on whether the current
+ time is in summer time or not.
+
+Fri Mar 19 00:00:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * bignum.c (rb_big_to_f, Bignum#to_f): removed them because they are
+ unified with int_to_f and Integer#to_f.
+
+ * numeric.c (int_to_f): treat Bignum values directly.
+
+Fri Mar 18 23:41:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * numeric.c (int_to_f, fix_to_f): rename fix_to_f to int_to_f, and add
+ treatment for subclasses which don't have definitions of to_f method.
+
+ * numeric.c (Integer#to_f, Fixnum#to_f): move to_f method from Fixnum
+ to Integer.
+
+ * ext/-test-/integer/my_integer.c: define helper class for testing
+ to_f method for a subclass of Integer.
+
+ * ext/-test-/integer/extconf.rb: ditto.
+
+ * ext/-test-/integer/init.c: ditto.
+
+ * test/-ext-/integer/test_my_integer.rb: examine to_f method for a
+ subclass of Integer.
+
+Fri Mar 18 22:32:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * include/ruby/intern.h (rb_big_hash): Move to internal.h.
+
+ * internal.h: ditto.
+
+Fri Mar 18 22:10:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * bignum.c (Bignum#eql?): remove its definition because it is unified
+ with Numeric#eql?.
+
+ * numeric.c (num_eql): treat Bignum values directly.
+
+Fri Mar 18 21:57:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * bignum.c (rb_big_to_s, Bignum#to_s): remove its definition because
+ it is unified with Integer#to_s.
+
+ * numeric.c (int_to_s): treat Bignum values directly.
+
+Fri Mar 18 21:30:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * numeric.c (int_to_s): Move from fix_to_s.
+
+ * numeric.c (Integer#to_s): Move from Fixnum#to_s.
+
+Fri Mar 18 16:22:24 2016 Victor Nawothnig <Victor.Nawothnig@gmail.com>
+
+ * parse.y (parse_numvar): NTH_REF must be less than a half of
+ INT_MAX, as it is left-shifted to be ORed with back-ref flag.
+ [ruby-core:74444] [Bug#12192] [Fix GH-1296]
+
+Fri Mar 18 12:25:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * gc.c (tick): fix missing close parenthesis. [Fix GH-1291]
+
+Fri Mar 18 10:24:12 2016 Naotoshi Seo <sonots@gmail.com>
+
+ * ext/date/date_core.c (datetime_to_time): preserve timezone info
+ [Bug #12189] [Fix GH-1295]
+
+Fri Mar 18 10:17:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * bignum.c (rb_big_hash): make it public function to be available in
+ other source files, and remove documentation comment for Bignum#hash.
+
+ * bignum.c (Bignum#hash): remove its definition because it is unified
+ with Object#hash.
+
+ * include/ruby/intern.h (rb_big_hash): add a prototype declaration.
+
+ * hash.c (any_hash): treat Bignum values directly.
+
+Fri Mar 18 02:35:12 2016 Naotoshi Seo <sonots@gmail.com>
+
+ * lib/time.rb (parse, strptime): Fix Time.parse/strptime does not
+ have compatibility with DateTime.parse/strptime in terms of parsing
+ timezone [Bug #12190] [Fix GH-1297]
+
+Fri Mar 18 02:17:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * numeric.c (fix_zero_p, fix_even_p, fix_odd_p): remove needless
+ functions.
+
+Fri Mar 18 02:15:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * numeric.c (int_even_p): treat Fixnum and Bignum values directly.
+
+Fri Mar 18 02:07:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * bignum.c (Bignum#even?, Bignum#odd?): remove definitions
+ because they are unified with Integer#even? and Integer#odd?.
+
+ * numeric.c (Fixnum#zero?, Fixnum#even?, Fixnum#odd?): remove
+ definitions because they are unified with Numeric#zero?,
+ Integer#even?, and Integer#odd?.
+
+ * numeric.c (num_zero_p, int_odd_p): treat Fixnum and
+ Bignum values directly.
+
+ * test/ruby/test_integer.rb (test_odd_p_even_p): remove meaningless
+ test case.
+
+Fri Mar 18 01:51:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * bignum.c (rb_big_even_p, rb_big_odd_p): make them public functions
+ to be available in other source files.
+
+ * include/ruby/intern.h (rb_big_even_p, rb_big_odd_p): add prototype
+ declarations.
+
+Fri Mar 18 00:25:56 2016 Tanaka Akira <akr@fsij.org>
+
+ * enum.c (ary_inject_op): Implement the specialized code for sum of
+ float numbers.
+
+Fri Mar 18 00:15:05 2016 Yusuke Endoh <mame@ruby-lang.org>
+
+ * numeric.c (num_step): use rb_equal for zero check. rb_num_coerce_cmp
+ created an object which caused extra overhead.
+
+Thu Mar 17 22:21:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/ruby.h (RB_GC_GUARD_PTR): remove intermediate
+ macro, and expand for each RB_GC_GUARD. [Fix GH-1293]
+
+Thu Mar 17 22:08:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_specialized_instruction): move specialization
+ for opt_newarray_max/min from translation phase.
+
+Thu Mar 17 21:52:09 2016 Yusuke Endoh <mame@ruby-lang.org>
+
+ * array.c, enum.c: make rdoc format consistent.
+
+Thu Mar 17 21:47:57 2016 Yusuke Endoh <mame@ruby-lang.org>
+
+ * NEWS: add Array#max, #min, and the optimization. [Feature #12172]
+
+Thu Mar 17 21:45:02 2016 Yusuke Endoh <mame@ruby-lang.org>
+
+ * compile.c (NODE_CALL): add optimization shortcut for Array#max/min.
+ Now `[x, y].max` is optimized so that a temporal array object is not
+ created in some condition. [Feature #12172]
+
+ * insns.def (opt_newarray_max, opt_newarray_min): added.
+
+Thu Mar 17 21:35:52 2016 Yusuke Endoh <mame@ruby-lang.org>
+
+ * array.c (rb_ary_max, rb_ary_min): implement Array#max and min with
+ arguments. replace super call with rb_nmin_run.
+
+ * enum.c (nmin_run): exported (as rb_nmin_run).
+
+ * internal.h: added a prototype for rb_nmin_run.
+
+Thu Mar 17 21:24:52 2016 Yusuke Endoh <mame@ruby-lang.org>
+
+ * array.c (rb_ary_max, rb_ary_min): implement a block by itself instead
+ of delegating Enumerable#max/min.
+
+Thu Mar 17 21:09:34 2016 Yusuke Endoh <mame@ruby-lang.org>
+
+ * array.c (rb_ary_max, rb_ary_min): Array#max and Array#min added.
+ [Feature #12172]
+
+ * internal.h (OPTIMIZED_CMP): moved from enum.c so that array.c can
+ use it.
+
+ * test/ruby/test_array.rb (test_max, test_min): tests for Array#max
+ and Array#min.
+
+ * test/ruby/test_enum.rb (test_max, test_min): revised a bit to test
+ Enumerable#max and #min explicitly.
+
+Thu Mar 17 21:02:42 2016 Yusuke Endoh <mame@ruby-lang.org>
+
+ * internal.c: struct cmp_opt_data added for refactoring out a data
+ structure for CMP_OPTIMIZABLE
+
+ * array.c (struct ary_sort_data): use struct cmp_opt_data.
+
+ * enum.c (struct min_t, max_t, min_max_t): use struct cmp_opt_data.
+
+Thu Mar 17 20:55:21 2016 Tanaka Akira <akr@fsij.org>
+
+ * enum.c (ary_inject_op): Extracted from enum_inject.
+
+Thu Mar 17 18:39:04 2016 Tanaka Akira <akr@fsij.org>
+
+ * enum.c (enum_inject): Implement the specialized code for sum of
+ integers including Bignums.
+
+ * internal.h (rb_fix_plus): Declared to be usable from enum_inject.
+
+ * numeric.c (rb_fix_plus): Defined.
+
+Thu Mar 17 17:20:28 2016 Anton Davydov <antondavydov.o@gmail.com>
+
+ * thread_sync.c: [DOC] Update documentation for Queue class
+ description. [Fix GH-1292]
+
+Thu Mar 17 17:14:51 2016 Dinar Valeev <dvaleev@suse.com>
+
+ * gc.c (tick): Use __builtin_ppc_get_timebase for POWER arch.
+ [Fix GH-1291]
+
+Thu Mar 17 11:51:48 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/securerandom.rb (gen_random): to avoid blocking on Windows.
+ On Windows OpenSSL RAND_bytes (underlying implementation is
+ RAND_poll in crypto/rand/rand_win.c) may be blocked at
+ NetStatisticsGet.
+ https://wiki.openssl.org/index.php/Random_Numbers#Windows_Issues
+ Instead of this, use Random.raw_seed directly (whose implementation
+ CryptGenRandom is one of the source of
+ entropy of RAND_poll on Windows).
+ https://wiki.openssl.org/index.php/Random_Numbers
+ Note: CryptGenRandom function is PRNG and doesn't check its entropy,
+ so it won't block. [Bug #12139]
+ https://msdn.microsoft.com/ja-jp/library/windows/desktop/aa379942.aspx
+ https://tools.ietf.org/html/rfc4086#section-7.1.3
+ https://eprint.iacr.org/2007/419.pdf
+ http://www.cs.huji.ac.il/~dolev/pubs/thesis/msc-thesis-leo.pdf
+
+Thu Mar 17 12:09:00 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Fixed two macro definitions.
+ * test/ruby/enc/test_case_mapping.rb: Test cases that detected
+ the above bugs.
+
+Thu Mar 17 11:36:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/option.c (inspect_tcpi_msec): more accurate condition
+ for TCPI msec member inspection function.
+ [ruby-core:74388] [Bug #12185]
+
+Thu Mar 17 08:13:43 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/-ext-/time/test_new.rb (test_timespec_new): Time#gmtoff values
+ are the same only when both or neither of the Time objects are in
+ summer time (daylight-saving time).
+
+Thu Mar 17 07:17:36 2016 Eric Hodel <drbrain@segment7.net>
+
+ * marshal.c (r_object0): raise ArgumentError when linking to undefined
+ object.
+
+Thu Mar 17 00:45:00 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * test/ruby/test_bignum.rb: Make sure to use Bignum values in the tests.
+
+Wed Mar 16 23:10:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * defs/keywords (alias, undef): symbol literals are allowed.
+
+ * parse.y (parse_percent): should parse symbol literals for alias
+ and undef. [ruby-dev:47681] [Bug #8851]
+
+Wed Mar 16 21:39:39 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * enc/trans/JIS: update Unicode's notice. [Bug #11844]
+
+Wed Mar 16 20:03:35 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * proc.c (proc_binding): proc from symbol can not make a binding.
+ [ruby-core:74100] [Bug #12137]
+
+Wed Mar 16 18:42:45 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_mapping.rb: Fixed and activated a test for Cherokee.
+
+Wed Mar 16 17:58:56 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_mapping.rb: Fixed a logical error.
+
+Wed Mar 16 17:57:34 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_mapping.rb: Adding tests for Cherokee.
+ One test not yet working.
+ (with Kimihito Matsui)
+
+Wed Mar 16 15:44:05 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_mapping.rb: Adding tests for actual Unicode
+ case mapping. Fixing some aliasing issues.
+ (with Kimihito Matsui)
+
+Tue Mar 15 21:38:28 2016 Tanaka Akira <akr@fsij.org>
+
+ * enum.c (enum_inject): Consider redefinition of Fixnum#+.
+ [ruby-dev:49510] [Bug#12178] Reported by usa.
+
+Tue Mar 15 20:32:57 2016 Tanaka Akira <akr@fsij.org>
+
+ * enum.c (enum_inject): Implement the specialized code for :+ operator
+ for Fixnums.
+
+Tue Mar 15 20:21:01 2016 Tanaka Akira <akr@fsij.org>
+
+ * enum.c (enum_inject): Implement the specialized code for self is an
+ array and a symbol operator is given.
+
+Tue Mar 15 16:29:51 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Eliminating common code.
+ (with Kimihito Matsui)
+
+Tue Mar 15 16:17:09 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Expansion of some code repetition in preparation for
+ elimination of common code pieces.
+ (with Kimihito Matsui)
+
+Tue Mar 15 13:49:23 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Additional macros and code to use mapping data in
+ CaseMappingSpecials array.
+ (with Kimihito Matsui)
+
+Tue Mar 15 13:41:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * internal.h (rb_gc_mark_global_tbl): should be private,
+ but was accidentally exported.
+
+Tue Mar 15 12:51:06 2016 Marcus Stollsteimer <sto.mar@web.de>
+
+ * doc/extension.ja.rdoc: Fix RDoc markup in doc/extension*.rdoc.
+ [ci skip][Bug #12143][ruby-core:74143]
+ * doc/extension.rdoc: ditto.
+
+Tue Mar 15 09:56:41 2016 Ian Lunderskov <ian.lunderskov@gmail.com>
+
+ * time.c: Minor typo in Time#dst? documentation.
+ [ci skip][fix GH-1290]
+
+Tue Mar 15 04:36:41 2016 Charles Oliver Nutter <headius@headius.com>
+
+ * test/ruby/test_rubyoptions.rb (test_disable): add tests for
+ --disable-gems and --disable-did_you_mean.
+
+Tue Mar 15 03:35:04 2016 Eric Hodel <drbrain@segment7.net>
+
+ * marshal.c (r_object0): Fix Marshal crash for corrupt extended object.
+
+Tue Mar 15 01:22:27 2016 Charles Oliver Nutter <headius@headius.com>
+
+ * test/ruby/test_rubyoptions.rb: make version matching support
+ JRuby's version output.
+
+Mon Mar 14 19:05:39 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * bignum.c (big2str_2bdigits): reduce div instruction.
+
+Mon Mar 14 18:39:53 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * include/ruby/oniguruma.h, enc/unicode.c: Adjusting flag assignments
+ and macros to work with unified CaseMappingSpecials array.
+ (with Kimihito Matsui)
+
+Mon Mar 14 16:53:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (compile_named_capture_assign): optimize named capture
+ assignments, by replacing repeating global variable accesses
+ with `dup`, and by returning the matched result instead of
+ re-getting it from the MatchData.
+
+ * parse.y (reg_named_capture_assign_gen): build just assignment
+ nodes for the optimization.
+
+Mon Mar 14 16:02:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * file.c (ruby_is_fd_loadable): now return -1 if loadable but
+ may block.
+
+ * ruby.c (open_load_file): wait to read by the result of
+ ruby_is_fd_loadable, without fstat.
+
+Mon Mar 14 13:38:38 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * numeric.c (fix2str): improve r54092 like rb_int2big().
+
+Mon Mar 14 10:02:23 2016 Eric Wong <e@80x24.org>
+
+ * ext/openssl/ossl_ssl.c (ossl_sslctx_setup): document as MT-unsafe
+ [ruby-core:73803] [Bug #12069]
+
+Sun Mar 13 09:43:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/win32.h (O_SHARE_DELETE): change to fit Fixnum
+ limit. [ruby-core:74285] [Bug #12171]
+
+Sun Mar 13 09:15:45 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (rb_fix2str): fix edge case, accidentally generated
+ wrong Fixnum from LONG_MIN.
+
+Sat Mar 12 09:50:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (rb_f_catch): [DOC] fix malformed RDoc syntax, "+...+"
+ cannot enclose non-identifier characters.
+ a patch by Sebastian S in [ruby-core:74278]. [Bug#12170]
+
+Sat Mar 12 02:44:48 2016 Tanaka Akira <akr@fsij.org>
+
+ * test/lib/test/unit.rb: describe !/REGEXP/ in the help message.
+
+Fri Mar 11 17:03:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/lib/test/unit.rb (Options#non_options): make regexp name
+ options prefixed with "!" negative filters.
+
+ * common.mk (TEST_EXCLUDES): use negative filter to exclude memory
+ leak tests. -x option excludes test files, not test methods.
+
+Fri Mar 11 16:11:27 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb, casefold.h: Streamlining approach to
+ case mapping data not available from case folding by unifying all
+ three cases (special title, special upper, special lower).
+ * enc/unicode.c: Adjust macro names for above (macros are currently inactive).
+ (with Kimihito Matsui)
+
+Thu Mar 10 17:34:16 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * iseq.c (prepare_iseq_build): enable coverage by coverage_enabled
+ option, not by parse_in_eval flag in the thread context.
+
+ * iseq.h (rb_compile_option_struct): add coverage_enabled flag.
+
+ * parse.y (yycompile0): set coverage_enabled flag if coverage
+ array is made.
+
+Thu Mar 10 15:19:54 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * node.c (dump_option): nd_compile_option is a hidden hash object,
+ cannot call inspect on it.
+
+Thu Mar 10 09:49:54 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/socket/test_socket.rb (test_udp_recvmsg_truncation):
+ AIX does not set the MSG_TRUNC flag for a message partially read
+ by recvmsg(2) with the MSG_PEEK flag set.
+
+Wed Mar 9 16:48:45 2016 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/driver.rb: fix my last commit (syntax error).
+
+Wed Mar 9 16:41:44 2016 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/driver.rb: fix output messages.
+
+ * benchmark/memory_wrapper.rb: use respond_to? because
+ member? does not work well.
+
+Wed Mar 9 16:20:25 2016 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/driver.rb: support memory usage benchmark.
+ use `--measure-target=[target]'.
+ Now, we can use the following targets:
+ * real (default): real time which returns process time in sec.
+ * peak: peak memory usage (physical memory) in bytes.
+ * size: last memory usage (physical memory) in bytes.
+
+ * benchmark/memory_wrapper.rb: ditto.
+
+Wed Mar 9 15:04:22 2016 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/bm_vm3_gc_old_full.rb: add GC.start benchmark.
+
+ * benchmark/bm_vm3_gc_old_immediate.rb: ditto.
+
+ * benchmark/bm_vm3_gc_old_lazy.rb: ditto.
+
+Wed Mar 9 14:59:11 2016 Koichi Sasada <ko1@atdot.net>
+
+ * benchmark/driver.rb: exit benchmarking if a benchmark process
+ receives signals.
+
+Wed Mar 9 13:22:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * test/lib/memory_status.rb: make Memory::Status independent of
+ MiniTest::Skip.
+
+ * test/lib/test/unit/assertions.rb (assert_no_memory_leak): skip
+ if Memory::Status is not available.
+
+Wed Mar 9 09:19:55 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/io/wait/test_io_wait.rb (test_wait_readwrite_timeout):
+ select(2) in AIX returns "readable" for the write-side fd
+ of a pipe, so it is not possible to use a pipe to test
+ the read-write timeout of IO#wait on AIX.
+
+Wed Mar 9 03:35:22 2016 Charles Oliver Nutter <headius@headius.com>
+
+ * test/ruby/test_require.rb (test_require_with_loaded_features_pop):
+ Only remove PATH so threads don't accidentally double-pop.
+
+Wed Mar 9 00:29:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_method.c (rb_alias): the original name should be properly
+ available method_added method, set the name before calling the
+ hook.
+
+Wed Mar 9 00:07:03 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/logger.rb (Logger::LogDevice#initialize): define using
+ keyword arguments.
+
+Tue Mar 8 23:37:07 2016 Charles Oliver Nutter <headius@headius.com>
+
+ * test/ruby/test_array.rb: split out the test for no stack error
+ on large input for test_permutation, test_repeated_permutation,
+ and test_repeated_combination, and make them all timeout:30.
+
+Tue Mar 8 17:20:21 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * intern.h (rb_divmod): assume compilers `/` and `%` comply C99
+ and reduce branching. If a compiler doesn't comply, add #ifdefs.
+
+ * intern.h (rb_div): added for Ruby's behavior.
+
+ * intern.h (rb_mod): added for Ruby's behavior.
+
+ * insns.def (opt_div): use rb_div.
+
+ * insns.def (opt_mod): use rb_mod.
+
+ * numeric.c (fixdivmod): removed.
+
+ * numeric.c (fix_divide): use rb_div.
+
+ * numeric.c (fix_mod): use rb_mod.
+
+ * numeric.c (fix_divmod): use rb_divmod.
+
+Tue Mar 8 17:53:09 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * insns.def (opt_mod): show its method name on ZeroDivisionError.
+ [Bug #12158]
+
+Tue Mar 8 17:33:38 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_write_console): now no need to check
+ ERROR_CALL_NOT_IMPLEMENTED because it is for old Win9X.
+
+Tue Mar 8 16:54:29 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (rb_w32_write_console): stop the VT100 emulation if the
+ console supports it natively.
+
+Tue Mar 8 08:13:01 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/net/imap/test_imap.rb (test_idle_timeout): Because of the
+ timeout specified in "imap.idle(0.2)", there is no guarantee that
+ the server thread has done all the work before the client thread
+ performs the assertions. It depends on the thread scheduling.
+ Add checks to avoid false positives (on AIX, particularly).
+
+Tue Mar 8 00:42:22 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * ruby.c (warn_cr_in_shebang): meaningless check on DOSISH platforms.
+ fixed a test failure introduced at r53998.
+
+Tue Mar 8 00:27:53 2016 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * ext/tk/lib/tkextlib/tcllib/tablelist_tile.rb: fix method name typo.
+ [ruby-core:72513] [Bug #11893] The patch provided by Akira Matsuda.
+
+
+Tue Mar 8 00:25:08 2016 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * ext/tk/lib/tkextlib/tcllib/toolbar.rb: fix method name typo.
+ [ruby-core:72511] [Bug #11891] The patch provided by Akira Matsuda.
+
+
+Tue Mar 8 00:21:58 2016 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * ext/tk/lib/tkextlib/blt/tree.rb: fix method name typo.
+ [ruby-core:72510] [Bug #11890] The patch provided by Akira Matsuda.
+
+
+Tue Mar 8 00:11:47 2016 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * ext/tk/lib/tk/menubar.rb: fix a typo in font name. [ruby-core:72505]
+ [Bug #11886] The patch provided by Akira Matsuda.
+
+ * ext/tk/sample/*.rb: ditto.
+
+Mon Mar 7 13:32:58 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * class.c (rb_define_class, rb_define_class_id_under): raise
+ ArgumentError if super is 0, deprecated behavior which has been
+ warned long time.
+
+Mon Mar 7 13:28:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * internal.h: move function declarations for class internals from
+ include/ruby/intern.h.
+
+Mon Mar 7 10:58:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/win32ole/win32ole_event.c (rescue_callback): use
+ rb_write_error_str instead of rb_write_error, to respect
+ the encoding and prevent the message from GC.
+
+ * internal.h (rb_write_error_str): export.
+
+Mon Mar 7 01:38:41 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/ruby/test_process.rb (test_execopts_gid): Skip a test
+ that is known to fail on AIX. AIX allows setgid to
+ a supplementary group, but Ruby does not allow the "-e"
+ option when setgid'ed, so the test does not work as intended.
+
+Sun Mar 6 22:43:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * io.c (rb_obj_display): [DOC] fix output of Array, as Array#to_s
+ is same as Array#inspect since 1.9.
+
+Sat Mar 5 09:50:58 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/socket/test_addrinfo.rb (test_ipv6_address_predicates):
+ IN6_IS_ADDR_V4COMPAT and IN6_IS_ADDR_V4MAPPED are broken
+ on AIX, so skip related tests.
+
+Sat Mar 5 09:17:54 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/rinda/test_rinda.rb (test_make_socket_ipv4_multicast):
+ The fifth argument to getsockopt(2) should be modified to
+ indicate the actual size of the value on return,
+ but not in AIX. This is a know bug. Skip related tests.
+ * test/rinda/test_rinda.rb (test_ring_server_ipv4_multicast):
+ ditto.
+ * test/rinda/test_rinda.rb (test_make_socket_unicast): ditto.
+ * test/socket/test_basicsocket.rb (test_getsockopt): ditto.
+ * test/socket/test_sockopt.rb (test_bool): ditto.
+
+Sat Mar 5 07:36:27 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/-ext-/float/test_nextafter.rb: In AIX,
+ nextafter(+0.0,-0.0)=+0.0, and nextafter(-0.0,+0.0)=-0.0,
+ but they should return -0.0 and +0.0, respectively. This is
+ a known bug in nextafter(3) on AIX, so skip related tests.
+
+Sat Mar 5 07:14:10 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * test/zlib/test_zlib.rb (test_adler32_combine, test_crc32_combine):
+ Skip two tests on AIX because zconf.h in zlib does not correctly
+ recognize _LARGE_FILES in AIX. The problem was already reported
+ to zlib, and skip these tests until it is fixed.
+
+Sat Mar 5 03:07:40 2016 Rei Odaira <Rei.Odaira@gmail.com>
+
+ * thread_pthread.c (getstack): __pi_stacksize returned by
+ pthread_getthrds_np() is wrong on AIX. Use
+ __pi_stackend - __pi_stackaddr instead.
+
+Fri Mar 4 19:19:42 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: use 2 bits with unsigned int for rb_objspace::flags::mode
+ because it always returns 0 to 2 (non-negative value).
+
+Fri Mar 4 18:42:08 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename "enum gc_stat" to "enum gc_mode"
+ because there is a same name (no related) function gc_stat().
+
+ Also gc_stat_* are renamed to gc_mode_*,
+ gc_stat_transition() to gc_mode_transition(),
+ rb_objspace::flags::stat is renamed to rb_objspace::flags::mode.
+
+ Change rb_objspace::flags::mode from 2 bits to 3 bits because VC++
+ returns negative enum value with 2 bits.
+
+ * gc.c (gc_mode): add a macro to access rb_objspace::flags::mode
+ with verification code (verification is enabled only on
+ RGENGC_CHECK_MODE > 0).
+
+ * gc.c (gc_mode_set): same macro for setter.
+
+Fri Mar 4 09:28:18 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems-2.6.1.
+ Please see entries of 2.6.0 and 2.6.1 on
+ https://github.com/rubygems/rubygems/blob/master/History.txt
+ [fix GH-1270] Patch by @segiddins
+
+Thu Mar 3 14:09:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/ostruct.rb (modifiable?, new_ostruct_member!, table!):
+ rename methods for internal use with suffixes and make private,
+ [ruby-core:71069] [Bug #11587]
+
+Wed Mar 2 16:28:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (method_missing): call by found method entry and get
+ rid of searching the same method entry twice.
+
+ * vm_eval.c (vm_call0_body): calling method_missing method is
+ method_missing().
+
+Wed Mar 2 15:13:33 2016 herwinw <herwin@quarantainenet.nl>
+
+ * lib/xmlrpc.rb: Removed broken parser named XMLScanStreamParser.
+ It's not works with current Ruby version.
+ [fix GH-1271][ruby-core:59588][Bug #9369]
+ * lib/xmlrpc/config.rb: ditto.
+ * lib/xmlrpc/parser.rb: ditto.
+
+Wed Mar 2 15:08:33 2016 herwinw <herwin@quarantainenet.nl>
+
+ * lib/xmlrpc.rb: Removed broken parser named XMLTreeParser.
+ Required gem of its parser didn't compile on newer Ruby versions.
+ [fix GH-1271][ruby-core:59590][Bug #9370]
+ * lib/xmlrpc/config.rb: ditto.
+ * lib/xmlrpc/parser.rb: ditto.
+
+Tue Mar 1 11:25:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/fileutils.rb: use keyword arguments instead of option
+ hashes.
+
+Mon Feb 29 16:50:20 2016 hanachin <hanachin@gmail.com>
+
+ * array.c (rb_ary_push_m): [DOC] Remove trailing comma from
+ Array#push example, as other Array examples doesn't put trailing
+ comma. [Fix GH-1279]
+
+Mon Feb 29 16:31:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * common.mk, tool/mkconfig.rb: set cross_compiling option from
+ Makefile, but not from rbconfig.rb, which is just going to be
+ created by this command.
+
+Sun Feb 28 23:13:49 2016 C.J. Collier <cjcollier@linuxfoundation.org>
+
+ * configure.in: Add summary to end of configure output.
+ [Fix GH-1275]
+
+Sun Feb 28 20:23:36 2016 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/drb/drb.rb (error_print): Add verbose failure messages and
+ avoid infamous DRb::DRbConnError. [Feature #12101]
+
+Sun Feb 28 13:40:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (nometh_err_initialize): add private_call? parameter.
+
+ * error.c (nometh_err_private_call_p): add private_call? method,
+ to tell if the exception raised in private form FCALL or VCALL.
+ [Feature #12043]
+
+ * vm_eval.c (make_no_method_exception): append private_call?
+ argument.
+
+ * vm_insnhelper.c (ci_missing_reason): copy FCALL flag.
+
+Sun Feb 28 10:19:47 2016 Ryan T. Hosford <tad.hosford@gmail.com>
+
+ * array.c (rb_ary_and): clarify that set intersection returns the
+ unique elements common to both arrays.
+
+ * array.c (rb_ary_or): clarify that union preserves the order from
+ the given arrays.
+
+Sat Feb 27 17:05:29 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb, casefold.h: Reducing size of TitleCase
+ table by eliminating duplicates.
+ (with Kimihito Matsui)
+
+Fri Feb 26 14:40:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (num_step_scan_args): comparison String with Numeric
+ should raise TypeError. it is an invalid type, but not a
+ mismatch the number of arguments. [ruby-core:62430] [Bug #9810]
+
+Fri Feb 26 14:39:39 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * doc/extension.rdoc, doc/extension.ja.rdoc: add editor local
+ variables, with commenting out by :enddoc: directives which are
+ just ignored unless code object mode. [Bug #12111]
+
+Fri Feb 26 12:25:56 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * doc/extension.ja.rdoc: removed rendering error caused by editor specific
+ configuration on http://docs.ruby-lang.org/en/trunk/extension_rdoc.html .
+ [Bug #12111][ruby-core:73990]
+
+Fri Feb 26 11:21:41 2016 herwinw <herwin@quarantainenet.nl>
+
+ * lib/xmlrpc.rb: Removed references to NQXML. It's obsoleted parser.
+ [fix GH-1245][ruby-core:59593][Feature #9371]
+ * lib/xmlrpc/config.rb: ditto.
+ * lib/xmlrpc/parser.rb: ditto.
+
+Fri Feb 26 11:10:19 2016 Rick Salevsky <rsalevsky@suse.com>
+
+ * lib/tmpdir.rb: Unify to coding-style for method definition.
+ [fix GH-1252]
+
+Fri Feb 26 11:02:04 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * README.md: update markdown syntax for anchor tag.
+ [fix GH-1265] Patch by @lukBarros
+
+Fri Feb 26 10:52:29 2016 Alex Boyd <alex@opengroove.org>
+
+ * lib/irb.rb: avoid to needless truncation when using back_trace_limit option.
+ [fix GH-1205][ruby-core:72773][Bug #11969]
+
+Fri Feb 26 08:11:58 2016 Aaron Patterson <tenderlove@ruby-lang.org>
+
+ * gem_prelude.rb: Reduce system calls by activating the `did_you_mean`
+ gem before requiring the gem. Activating the gem puts the gem on
+ the load path, where simply requiring the file will search every gem
+ that's installed until it can find a gem that contains the
+ `did_you_mean` file.
+
+Thu Feb 25 19:04:13 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb: Adding possibility for debugging output
+ for TitleCase table in casefold.h.
+ (with Kimihito Matsui)
+
+Wed Feb 24 22:31:13 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * include/ruby/oniguruma.h: Rearranging flag assignments and making
+ space for titlecase indices; adding additional macros to add or
+ extract titlecase index; adding comments for better documentation.
+ * enc/unicode.c: Moving some macros to include/ruby/oniguruma.h;
+ activating use of titlecase indices.
+ (with Kimihito Matsui)
+
+Wed Feb 24 21:03:04 2016 Tanaka Akira <akr@fsij.org>
+
+ * random.c (limited_rand): Add a specialized path for when the limit fits
+ in 32 bit.
+
+Tue Feb 23 21:52:24 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb, casefold.h: Outputting actual titlecase
+ data (new table, with indices from other tables).
+ * enc/unicode.c: Ignoring titlecase data indices for the moment.
+ (with Kimihito Matsui)
+
+Tue Feb 23 15:21:14 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb, casefold.h: Reading casing data from
+ SpecialCasing.txt.
+ (with Kimihito Matsui)
+
+Mon Feb 22 18:33:55 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb, casefold.h: Adding flag for title-case,
+ not yet operational.
+ (with Kimihito Matsui)
+
+Mon Feb 22 18:17:03 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb, casefold.h: Fixed bug that avoided inclusion
+ of compatibility characters in upper-/lower-case mappings.
+ (with Kimihito Matsui)
+
+Sun Feb 21 13:57:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * cgi/escape/escape.c: Optimize CGI.unescape performance by C ext
+ for ASCII-compatible encodings. [Fix GH-1250]
+
+Sun Feb 21 13:56:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * cgi/escape/escape.c: Optimize CGI.unescapeHTML performance by C
+ ext for ASCII-compatible encodings. [Fix GH-1242]
+
+Sat Feb 20 15:38:16 2016 Eric Wong <e@80x24.org>
+
+ * doc/extension.rdoc: update paths for defs/ directory
+
+Sat Feb 20 14:44:15 2016 Lucas Buchala <lucasbuchala@gmail.com>
+
+ * vm_eval.c (rb_mod_module_eval): [DOC] Fix documentation
+ signature for Module#module_eval. [Fix GH-1258]
+
+Sat Feb 20 14:40:44 2016 Adam O'Connor <northband@gmail.com>
+
+ * README.md: a few grammatical changes to the main Ruby README.md.
+ [Fix GH-1259]
+
+Sat Feb 20 13:04:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (push_pattern, push_glob): deal with read paths as UTF-8
+ to stat later, on Windows as well as OS X.
+ [ruby-core:73868] [Bug #12081]
+
+Sat Feb 20 01:53:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_mod_const_get): make error message at uninterned
+ string consistent with symbols. [ruby-dev:49498] [Bug #12089]
+
+Fri Feb 19 23:37:52 2016 Masahiro Tomita <tommy@tmtm.org>
+
+ * lib/find.rb (Find#find): raise with the given path name if it
+ does not exist. [ruby-dev:49497] [Bug #12087]
+
+Fri Feb 19 12:44:57 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Activated use of case mapping data in CaseUnfold_11 array.
+ (with Kimihito Matsui)
+
+Fri Feb 19 11:08:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/extmk.rb: add cygwin case, nothing excluded.
+ [ruby-core:73806] [Bug#12071]
+
+Thu Feb 18 21:32:15 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * man/irb.1: fix output in EXAMPLES.
+
+Thu Feb 18 21:05:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (sym_match_m): delegate to String#match but not
+ String#=~. [ruby-core:72864] [Bug #11991]
+
+Thu Feb 18 14:15:38 2016 Shota Fukumori <her@sorah.jp>
+
+ * re.c: Add MatchData#named_captures
+ [Feature #11999] [ruby-core:72897]
+
+ * test/ruby/test_regexp.rb(test_match_data_named_captures): Test for above.
+
+ * NEWS: News about MatchData#named_captures.
+
+Wed Feb 17 21:41:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * defs/id.def (predefined): add idLASTLINE and idBACKREF for $_
+ and $~ respectively.
+
+ * parse.y: use idLASTLINE and idBACKREF instead of rb_intern.
+
+Wed Feb 17 20:23:38 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_str_init): fix segfault and memory leak, consider
+ wide char encoding terminator.
+
+Wed Feb 17 12:14:59 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (rb_str_init): introduce String.new(capacity: size)
+ [Feature #12024]
+
+Tue Feb 16 19:10:08 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb, casefold.h: Used only first element
+ (rather than all) of target in CaseUnfold_11 array.
+ (with Kimihito Matsui)
+
+Tue Feb 16 18:24:38 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * numeric.c (compare_with_zero): fix variable name, rb_cmperr
+ requires VALUEs but not an ID.
+
+Tue Feb 16 17:34:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (rb_dir_s_empty_p): add Dir.empty? method, which tells the
+ argument is the name of an empty directory. [Feature #10121]
+
+Tue Feb 16 09:51:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/rbinstall.rb (without_destdir): just strip a drive letter
+ which is prepended by with_destdir.
+ pointed out by @DavidEGrayson.
+ https://github.com/ruby/ruby/commit/0e5f9ae#commitcomment-16101763
+
+Tue Feb 16 04:42:13 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * insns.def (opt_plus): simply use LONG2NUM() instead of wrongly
+ complex overflow case.
+
+ * insns.def (opt_sub): ditto.
+
+Tue Feb 16 02:49:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/rbinstall.rb (without_destdir): compare with the destdir
+ after stripping a drive letter, on dosish platforms.
+ pointed out by @DavidEGrayson.
+ https://github.com/ruby/ruby/commit/d0cf23b#commitcomment-16100407
+
+Mon Feb 15 15:44:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parse_ident): allow keyword arguments just after a
+ method where the same name local variable is defined.
+ [ruby-core:73816] [Bug#12073]
+
+Mon Feb 15 14:43:28 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb: Added debugging option
+ (with Kimihito Matsui)
+
+Sun Feb 14 17:31:50 2016 Lars Kanis <lars@greiz-reinsdorf.de>
+
+ * lib/mkmf.rb (with_{cpp,c,ld}flags): copy caller strings not to
+ be modified, in append_{cpp,c,ld}flags respectively.
+ [Fix GH-1246]
+
+Sun Feb 14 16:18:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (setup_exception): set the cause only if it is explicitly
+ given or not set yet. [Bug #12068]
+
+Sat Feb 13 21:44:58 2016 Tanaka Akira <akr@fsij.org>
+
+ * hash.c (rb_hash_invert): [DOC] more examples.
+
+Sat Feb 13 17:30:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/uri/generic.rb (URI::Generic#find_proxy): support CIDR in
+ no_proxy. [ruby-core:73769] [Feature#12062]
+
+Sat Feb 13 17:11:58 2016 Fabian Wiesel <fabian.wiesel@sap.com>
+
+ * lib/uri/generic.rb (find_proxy): exclude white-spaces and allow
+ for a leading dot in the domain name in no_proxy.
+ [ruby-core:54542] [Feature #8317]
+
+Fri Feb 12 12:20:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * error.c (name_err_initialize, nometh_err_initialize): [DOC] fix
+ argument positions. optional parameters except for the message
+ are placed at the last.
+
+Fri Feb 12 11:49:49 2016 Anthony Dmitriyev <antstorm@gmail.com>
+
+ * net/ftp.rb: add NullSocket#closed? to fix closing not opened
+ connection. [Fix GH-1232]
+
+Fri Feb 12 11:17:38 2016 Bogdan <bogdanvlviv@gmail.com>
+
+ * re.c (rb_reg_initialize_m): [DOC] fix missing right bracket.
+ [Fix GH-1243]
+
+Thu Feb 11 14:57:58 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (RUBY_CHECK_SIZEOF, RUBY_DEFINT): fix for types
+ which are conditionally available depending on architectures
+ when universal binary, e.g., __int128.
+
+Thu Feb 11 06:26:18 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in (RUBY_DEFINT): use Parameter Expansion.
+
+Thu Feb 11 05:33:24 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in (int128_t): don't check HAVE_XXX (for example
+ HAVE___INT128) because RUBY_CHECK_SIZEOF() don't define it for
+ config.h and use of $ac_cv_sizeof___int128 alternates the check.
+ (and don't need to define because users shouldn't know that)
+
+Wed Feb 10 12:03:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in (ARFLAGS): check if deterministic mode flag is
+ effective, which is on by default on Ubuntu.
+
+Tue Feb 9 16:36:23 2016 Naotoshi Seo <sonots@gmail.com>
+
+ * lib/logger.rb: Remove block from Logger.add as it's not needed
+ patch provided by Daniel Lobato Garcia [fix GH-1240] [Bug #12054]
+
+Tue Feb 9 14:32:23 2016 Zachary Scott <zzak@ruby-lang.org>
+
+ * ext/zlib/zlib.c: Document mtime header behavior with patch by @schneems
+ Fixes [GH-1129]: https://github.com/ruby/ruby/pull/1129
+
+Tue Feb 9 13:52:49 2016 Zachary Scott <zzak@ruby-lang.org>
+
+ * re.c: Remove deprecated kcode argument from Regexp.new and compile
+ patch provided by Dylan Pulliam [Bug #11495]
+
+Mon Feb 8 21:26:19 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb, enc/unicode/casefold.h: Flags for
+ upper/lower conversion added (titlecase and SpecialCasing still missing)
+ (with Kimihito Matsui)
+
+Mon Feb 8 20:43:57 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c, enc/unicode.c: Disassociating ONIGENC_CASE_FOLD flag from
+ ONIGENC_CASE_DOWNCASE.
+ (with Kimihito Matsui)
+
+Mon Feb 8 13:00:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Shortened macros for enc/unicode/casefold.h to
+ single-letter; use flags in casefold.h for logic.
+
+ * enc/unicode/case-folding.rb: Added flag for case folding.
+ Changed parameter passing.
+
+ * enc/unicode/casefold.h: New flags added.
+ (with Kimihito Matsui)
+
+Mon Feb 8 10:30:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (feature_option): raise a runtime error if ambiguous
+ feature name is given, in the future. [Bug #12050]
+
+Mon Feb 8 09:43:57 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * common.mk: Removed enc/unicode/casefold.h from automatic build because
+ some CI systems don't have gperf. Creation of enc/unicode/casefold.h
+ is now possible with make unicode-up. This is intended as a temporary measure.
+
+Sun Feb 7 22:10:08 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * common.mk: Added two more precondition files for enc/unicode/casefold.h
+
+ * enc/unicode.c: Added shortening macros for enc/unicode/casefold.h
+
+ * enc/unicode/case-folding.rb: Fixed file encoding for CaseFolding.txt
+ to ASCII-8BIT (should fix some ci errors). Clarified usage. Created
+ class MapItem. Partially implemented class CaseMapping.
+ (with Kimihito Matsui)
+
+Sun Feb 7 14:12:32 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb: Fixing parameter passing.
+ (with Kimihito Matsui)
+
+Sun Feb 7 11:44:03 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode/case-folding.rb: New classes CaseMapping/CaseMappingDummy
+ to pass as parameters; not yet implemented or used.
+ (with Kimihito Matsui)
+
+Sun Feb 7 11:16:00 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * common.mk: using new option in recipe for enc/unicode/casefold.h
+
+ * enc/unicode/case-folding.rb: Correctly specify argument to new option.
+ (with Kimihito Matsui)
+
+Sun Feb 7 10:43:27 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ (this commit message applies to the previous commit)
+ * common.mk: explicit recipe for enc/unicode/casefold.h
+
+ * enc/unicode/case-folding.rb: Adding -m option to prepare for using
+ multiple data files.
+ (with Kimihito Matsui)
+
+Sat Feb 6 22:30:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/cgi/util.rb (escapeHTML, unescapeHTML): consider
+ ASCII-incompatible encodings. [Fix GH-1239]
+
+Sat Feb 6 15:18:28 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_regex_casefold.rb: Added data-based testing for
+ String#downcase :fold.
+
+ * enc/unicode.c: Fixed a range error (lowest non-ASCII character affected
+ by case operations is U+00B5, MICRO SIGN)
+
+ * test/ruby/enc/test_case_mapping.rb: Explicit test for case folding of
+ MICRO SIGN to Greek mu.
+ (with Kimihito Matsui)
+
+Sat Feb 6 14:51:23 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_regex_casefold.rb: Tests for three case folding
+ primitives (mbc_case_fold, get_case_fold_codes_by_str,
+ apply_all_case_fold) in the various encodings. Currently only known
+ good encodings are tested to avoid test failures. For bug hunting,
+ start by adding more encodings with
+ generate_test_casefold encoding
+ (with Kimihito Matsui)
+
+Sat Feb 6 14:37:16 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c, test/ruby/enc/test_case_mapping.rb: Implemented :fold
+ option for String#downcase by using case folding data from
+ regular expression engine, and added a few simple tests.
+ (with Kimihito Matsui)
+
+Fri Feb 5 20:08:59 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_case_mapping.rb: added tests for :ascii option.
+ (with Kimihito Matsui)
+
+Fri Feb 5 12:22:20 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * insns.def (opt_mult): Use int128_t for overflow detection.
+
+ * bignum.c (rb_uint128t2big): added for opt_mult.
+
+ * bignum.c (rb_uint128t2big): added for rb_uint128t2big..
+
+ * configure.in: define int128_t, uint128_t and related MACROs.
+ Initially introduced by r41379 but reverted by r50749.
+
+Thu Feb 4 21:05:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Activated :ascii flag for ASCII-only case conversion
+ (with Kimihito Matsui)
+
+Thu Feb 4 17:38:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * re.c (reg_set_source): make source string frozen without
+ copying.
+
+ * re.c (rb_reg_initialize_m): refactor initialization with
+ encoding.
+
+Thu Feb 4 15:35:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * string.c (rb_fstring_enc_new, rb_fstring_enc_cstr): functions to
+ make fstring with encoding.
+
+Thu Feb 4 14:42:29 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * common.mk: Added Unicode data file SpecialCasing.txt to be additionally
+ downloaded (with Kimihito Matsui)
+
+Thu Feb 4 12:39:08 2016 joker1007 <kakyoin.hierophant@gmail.com>
+
+ * cgi/escape/escape.c: Optimize CGI.escape performance by C ext
+ for ASCII-compatible encodings. [Fix GH-1238]
+
+Thu Feb 4 11:53:56 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * common.mk: Introduce two variables (UNICODE_DATA_DIR and
+ UNICODE_SRC_DATA_DIR) to eliminate repetitions.
+
+Wed Feb 3 12:13:20 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * string.c (str_new_frozen): if the given string is embeddedable
+ but not embedded, embed a new copied string. [Bug #11946]
+
+Wed Feb 3 08:25:38 2016 boshan <boshan@subsplash.com>
+
+ * ext/openssl/ossl_pkey.c (Init_ossl_pkey): [DOC] Fix typo
+ "encrypted" to "decrypted". [Fix GH-1235]
+
+Wed Feb 3 08:21:32 2016 Seiei Miyagi <hanachin@gmail.com>
+
+ * ext/ripper/lib/ripper/lexer.rb (on_heredoc_dedent): Fix
+ Ripper.lex error in dedenting squiggly heredoc. heredoc tree is
+ also an array of Elem in the outer tree. [Fix GH-1234]
+
+Wed Feb 3 02:33:39 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * re.c (rb_reg_prepare_enc): use already compiled US-ASCII regexp
+ if given string is ASCII only.
+ 121.2s to 113.9s on my x86_64-freebsd10.2 Intel Core i5 661
+
+Tue Feb 2 13:02:03 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * re.c: Introduce RREGEXP_PTR.
+ patch by dbussink.
+ partially merge https://github.com/ruby/ruby/pull/497
+
+ * include/ruby/ruby.h: ditto.
+
+ * gc.c: ditto.
+
+ * ext/strscan/strscan.c: ditto.
+
+ * parse.y: ditto.
+
+ * string.c: ditto.
+
+Tue Feb 2 09:08:27 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rubygems/specification.rb: `coding` is effective only first
+ line except shebang.
+
+ * lib/rubygems/package.rb, lib/rubygems/package/*: ditto.
+
+Mon Feb 1 21:41:58 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems-2.5.2.
+ It supports to enable frozen string literal and add `--norc` option for
+ disable to `.gemrc` configuration.
+ See 2.5.2 release notes for other fixes and enhancements.
+ https://github.com/rubygems/rubygems/blob/a8aa3bac723f045c52471c7b9328310a048561e0/History.txt#L3
+
+Sun Jan 31 12:33:13 2016 Dan Kreiger <dan@dankreiger.com>
+
+ * test/drb/ut_large.rb (multiply, avg, median): add additional
+ math operations to DRbLarge. [Fix GH-1086]
+
+Sun Jan 31 12:19:15 2016 Kuniaki IGARASHI <igaiga@gmail.com>
+
+ * test/ruby/test_file_exhaustive.rb (test_lstat): Add lacking test
+ for File#lstat. [Fix GH-1231]
+
+Sun Jan 31 12:15:33 2016 Prayag Verma <prayag.verma@gmail.com>
+
+ * doc/standard_library.rdoc: fix typo [Fix GH-1230]
+ Spelling mistakes -
+ outputing > outputting
+ publich > publish
+
+Sat Jan 30 15:18:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_eval.c (rb_check_funcall_with_hook): also should call the
+ given hook before returning Qundef when overridden respond_to?
+ method returned false. [ruby-core:73556] [Bug #12030]
+
+Fri Jan 29 17:40:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/file.c (rb_readlink): drop garbage after the substitute
+ name, as rb_w32_read_reparse_point returns the expected buffer
+ size but "\??\" prefix is dropped from the result.
+
+ * win32/win32.c (w32_readlink): ditto, including NUL-terminator.
+
+Fri Jan 29 17:07:27 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * win32/win32.c (fileattr_to_unixmode, rb_w32_reparse_symlink_p): volume
+ mount point should be treated as directory, not symlink.
+ [ruby-core:72483] [Bug #11874]
+
+ * win32/win32.c (rb_w32_read_reparse_point): check the reparse point is
+ a volume mount point or not.
+
+ * win32/file.c (rb_readlink): follow above change (but this pass won't
+ be used).
+
+Fri Jan 29 16:17:07 2016 Lucas Buchala <lucasbuchala@gmail.com>
+
+ * enum.c (enum_take_while, enum_drop_while): rename block
+ parameter to obj, since they are generic objects. [Fix GH-1226]
+
+Fri Jan 29 14:15:26 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/erb.rb (ERB::Compiler#detect_magic_comment): allow
+ frozen-string-literal in comment as well as encoding.
+
+ * lib/erb.rb (ERB#def_method): insert def line just before the
+ first non-comment and non-empty line, not to leave duplicated
+ and stale magic comments.
+
+Fri Jan 29 11:13:33 2016 Jeremy Evans <code@jeremyevans.net>
+
+ * lib/erb.rb (ERB#set_eoutvar): explicitly make mutable string as
+ a buffer to make ERB work with --enable-frozen-string-literal.
+ [ruby-core:73561] [Bug #12031]
+
+Fri Jan 29 10:44:56 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/net/http/header.rb: Warn nil variable on HTTP Header.
+ It caused to NoMethodError. [fix GH-952][fix GH-641] Patch by @teosz
+ * test/net/http/test_httpheader.rb: Added test for nil HTTP Header.
+
+Thu Jan 28 17:31:43 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/socket.c (sock_gethostname): support unlimited size
+ hostname.
+
+Wed Jan 27 21:03:45 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * test/-ext-/string/test_capacity.rb: Added missing library.
+
+Wed Jan 27 18:53:40 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Fixed bit mask in macro OnigCodePointCount
+
+Wed Jan 27 17:54:42 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Protect code point count by macro, in order to
+ be able to use the remaining bits for flags.
+ (with Kimihito Matsui)
+
+Wed Jan 27 16:34:35 2016 boshan <boshan@subsplash.com>
+
+ * lib/tempfile.rb (Tempfile#initialize): [DOC] the first parameter
+ `basename` is optional and defaulted to an empty string since
+ [GH-523]. [Fix GH-1225]
+
+Wed Jan 27 16:25:54 2016 Koichi ITO <koic.ito@gmail.com>
+
+ * array.c (rb_ary_dig): [DOC] fix the exception class to be raised
+ when intermediate object does not have dig method. TypeError
+ will be raised now. [Fix GH-1224]
+
+Tue Jan 26 19:36:15 2016 Aggelos Avgerinos <evaggelos.avgerinos@gmail.com>
+
+ * array.c (permute0, rpermute0): [DOC] Substitute indexes ->
+ indices in documentation for consistency. [Fix GH-1222]
+
+Tue Jan 26 15:21:37 2016 Eric Wong <e@80x24.org>
+
+ * compile.c (caller_location): use rb_fstring_cstr for "<compiled>"
+ (it is converted to fstring anyways inside rb_iseq_new_with_opt)
+ * iseq.c (iseqw_s_compile): ditto
+ * iseq.c (rb_iseq_new_main): use rb_fstring_cstr for "<main>"
+ * vm.c (Init_VM): ditto, share with with above
+ * iseq.c (iseqw_s_compile_file): rb_fstring before rb_io_t->pathv
+ share "<main>" with above
+ * vm.c (rb_binding_add_dynavars): fstring "<temp>" immediately
+
+Tue Jan 26 15:14:01 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * compile.c (iseq_peephole_optimize): don't apply tailcall
+ optimization to send/invokesuper instructions with blockiseq.
+ This is a follow-up to the changes in r51903; blockiseq is now
+ the third operand of send/invokesuper instructions.
+ [ruby-core:73413] [Bug #12018]
+
+Tue Jan 26 14:26:46 2016 Eric Wong <e@80x24.org>
+
+ * signal.c (sig_list): use fstring for hash key
+ * test/ruby/test_signal.rb (test_signal_list_dedupe_keys): added
+
+Tue Jan 26 13:08:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (rb_f_kill): should immediately deliver reserved
+ signals SIGILL and SIGFPE, not only SIGSEGV and SIGBUS.
+
+Tue Jan 26 07:57:28 2016 Joseph Tibbertsma <josephtibbertsma@gmail.com>
+
+ * gc.c (RVALUE_PAGE_WB_UNPROTECTED): fix a typo of argument name.
+ [Fix GH-1221]
+
+Mon Jan 25 17:26:54 2016 Eric Wong <e@80x24.org>
+
+ * ruby_assert.h (RUBY_ASSERT_WHEN): fix reference to macro name
+ * vm_core.h: include ruby_assert.h before using
+ [ruby-core:73371]
+
+Mon Jan 25 15:55:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * symbol.c (sym_check_asciionly): more informative error message
+ with the encoding name and the inspected content.
+ [ruby-core:73398] [Feature #12016]
+
+Mon Jan 25 09:38:26 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * test/ruby/test_string.rb: added testcase for next!, succ and succ!
+ [fix GH-1213] Patch by @K0mAtoru
+
+Mon Jan 25 09:32:25 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/webrick/httpservlet/filehandler.rb: fix documentation for namespace.
+ [fix GH-1219][ci skip] Patch by @leafac
+
+Sun Jan 24 19:34:23 2016 Eric Wong <e@80x24.org>
+
+ * vm_insnhelper.c (vm_check_if_namespace): tiny size reduction
+
+Sun Jan 24 18:12:36 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * common.mk: Simplifying Unicode data file download logic to make
+ it more reliable (including additional fix not in r53633) [Bug #12007]
+
+Sun Jan 24 16:54:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/io/wait/wait.c (io_wait_readwrite): [EXPERIMENTAL] allow to
+ wait for multiple modes, readable and writable, at once. the
+ arguments may change in the future. [Feature #12013]
+
+Sat Jan 23 22:30:59 2016 K0mA <mctj1218@gmail.com>
+
+ * test/ruby/test_array.rb (test_keep_if): Add test for
+ Array#keep_if separate from Array#select! [Fix GH-1218]
+
+Sat Jan 23 20:54:26 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * common.mk: revert r53633. It broke rubyci and travis.
+ https://travis-ci.org/ruby/ruby/builds/104259623
+
+Sat Jan 23 20:10:29 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * range.c (range_eqq): revert r51585 because rb_call_super() is
+ called in range_include() and thus r51585 doesn't work when the
+ receiver Range object consists of non linear objects such as Date
+ objects.
+ [ruby-core:72908] [Bug #12003]
+
+Sat Jan 23 18:37:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * ChangeLog: Fixing wrong time on previous commit, and adding
+ previous commit message to svn [ci skip]
+
+Sat Jan 23 18:30:30 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * common.mk: Simplifying Unicode data file download logic to make
+ it more reliable [Bug #12007]
+
+Sat Jan 23 16:29:42 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * tool/downloader.rb: Fixed a logical error, improved documentation
+
+Sat Jan 23 11:42:43 2016 Peter Suschlik <ps@neopoly.de>
+
+ * README.md: Use SVG Travis badge over PNG for better quality and
+ device support. [Fix GH-1214] [Fix GH-1216]
+
+Sat Jan 23 11:29:16 2016 Pascal Betz <pascal.betz@simplificator.com>
+
+ * lib/csv.rb: Update documentation of CSV header converter for
+ r45498, [GH-575]. [Fix GH-1215]
+
+Fri Jan 22 17:36:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * vm_core.h (VM_ASSERT): use RUBY_ASSERT instead of rb_bug.
+
+ * error.c (rb_assert_failure): assertion with stack dump.
+
+ * ruby_assert.h (RUBY_ASSERT): new header for the assertion.
+
+Fri Jan 22 00:25:57 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * regparse.c (fetch_name_with_level): allow non word characters
+ at the first character. [Feature #11949]
+
+ * regparse.c (fetch_name): ditto.
+
+Thu Jan 21 17:34:01 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * marshal.c (r_object0): honor Marshal.load post proc
+ value for TYPE_LINK. by Hiroshi Nakamura <nahi@ruby-lang.org>
+ https://github.com/ruby/ruby/pull/1204 fix GH-1204
+
+Thu Jan 21 16:37:50 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * Makefile.in (update-rubyspec): fix r53208 like r53451.
+
+Wed Jan 20 20:58:25 2016 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * common.mk, Makefile.in: update-config_files is only for Unix
+ platforms.
+
+Wed Jan 20 17:13:39 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/extlibs.rb: add --cache option to change cache directory.
+
+Tue Jan 19 17:03:40 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * common.mk: Added Unicode data file CaseFolding.txt to be additionally
+ downloaded (with Kimihito Matsui)
+
+Tue Jan 19 10:09:58 2016 Sho Hashimoto <sho-h@ruby-lang.org>
+
+ * lib/shell.rb (Shell.debug_output_exclusive_unlock): remove
+ because Mutex#exclusive_unlock was already deleted. [fix GH-1185]
+
+Tue Jan 19 09:38:27 2016 Nick Cox <nick@nickcox.me>
+
+ * vm_method.c: fix grammar in respond_to? warning.
+ [fix GH-1047]
+
+Mon Jan 18 14:37:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_here_document): an escaped newline is not an
+ actual newline, and the rest part should not be dedented.
+ [ruby-core:72855] [Bug #11989]
+
+Mon Jan 18 12:04:34 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * test/ruby/test_string.rb: Added extra testcase for test_rstrip_bang
+ and test_lstrip_bang. [fix GH-1178] Patch by @Matrixbirds
+
+Mon Jan 18 11:47:27 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * string.c: fix a typo. [fix GH-1202][ci skip] Patch by @sunboshan
+
+Sun Jan 17 21:15:30 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * configure.in: improve ICC (Intel C Compiler) support.
+
+ * configure.in (CXX): The name of icc's c++ compiler is `icpc`.
+
+ * configure.in (warnings): Add `-diag-disable=2259` to suppress
+ noisy warnings: "non-pointer conversion from "..." to "..." may
+ lose significant bits".
+
+ * configure.in (optflags): Add `-fp-model precise` like -fno-fast-math.
+
+ * lib/mkmf.rb: icc supports -Werror=division-by-zero
+ and -Werror=deprecated-declarations, but doesn't support
+ -Wdivision-by-zero and -Wdeprecated-declarations.
+
+Sun Jan 17 20:40:10 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: Any kind of option is now taking the new code path for
+ upcase/downcase/capitalize/swapcase. :lithuanian can be used for
+ testing if no specific option is desired.
+ * test/ruby/enc/test_case_mapping.rb: Adjusted to above.
+ (with Kimihito Matsui)
+
+Sun Jan 17 20:10:10 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Fixed a logical error and some comments.
+ * test/ruby/enc/test_case_mapping.rb: Made tests more general.
+ (with Kimihito Matsui)
+
+Sun Jan 17 17:41:41 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Removed artificial expansion for Turkic,
+ added hand-coded support for Turkic, fixed logic for swapcase.
+ * string.c: Made use of new case mapping code possible from upcase,
+ capitalize, and swapcase (with :lithuanian as a guard).
+ * test/ruby/enc/test_case_mapping.rb: Adjusted for above.
+ (with Kimihito Matsui)
+
+Sun Jan 17 15:30:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/option.c (sockopt_bool): relax boolean size to be one
+ too not only sizeof(int). Winsock getsockopt() returns a single
+ byte as a boolean socket option. [ruby-core:72730] [Bug #11958]
+
+Sun Jan 17 14:43:01 2016 Kuniaki IGARASHI <igaiga@gmail.com>
+
+ * test/ruby/test_env.rb: [Fix GH-1201]
+ * Extract test code for ENV#keep_if from ENV#select_bang
+ * Add a test case for ENV#select_bang,keep_if
+
+Sun Jan 17 14:42:25 2016 Kuniaki IGARASHI <igaiga@gmail.com>
+
+ * test/ruby/test_env.rb: [Fix GH-1201]
+ * Extract test code for ENV#delete_if from ENV#reject_bang
+ * Add a test case for ENV#reject_bang,delete_if
+
+Sun Jan 17 14:40:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ext/socket/option.c (check_size): extract a macro to check
+ binary data size, with a consistent message.
+
+ * ext/socket/option.c (sockopt_byte): fix error message,
+ sizeof(int) differs from sizeof(unsigned char) in general.
+
+Sat Jan 16 21:16:21 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (xstring): reset heredoc indent after dedenting,
+ so that following string literal would not be dedented.
+ [ruby-core:72857] [Bug #11990]
+
+Sat Jan 16 17:24:24 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * enc/unicode.c: Artificial mapping to test buffer expansion code.
+ * string.c: Fixed buffer expansion logic.
+ * test/ruby/enc/test_case_mapping.rb: Tests for above.
+ (with Kimihito Matsui)
+
+Sat Jan 16 16:47:14 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * ext/openssl/lib/openssl/pkey.rb: Added 2048 bit DH parameter.
+ * test/openssl/test_pkey_dh.rb: ditto.
+
+Sat Jan 16 10:51:19 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * enc/unicode.c: fix implicit conversion error with clang. fixup r53548.
+ * string.c: ditto.
+
+Sat Jan 16 10:31:00 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * common.mk: test-sample was changed to test-basic.
+ [Feature #11982][ruby-core:72823]
+ * basictest/runner.rb: ditto. rename from tool/rubytest.rb.
+ * basictest/test.rb: ditto. rename from sample/test.rb.
+ * defs/gmake.mk: picked from r53540
+ * sample/test.rb: backward compatibility for chkbuild.
+
+Sat Jan 16 10:23:23 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c, enc/unicode.c: New code path as a preparation for Unicode-wide
+ case mapping. The code path is currently guarded by the :lithuanian
+ option to avoid accidental problems in daily use.
+ * test/ruby/enc/test_case_mapping.rb: Test for above.
+ * string.c: function 'check_case_options': fixed logical errors
+ (with Kimihito Matsui)
+
+Fri Jan 15 20:20:20 2016 Naohisa Goto <ngotogenome@gmail.com>
+
+ * regint.h (PLATFORM_UNALIGNED_WORD_ACCESS): The value of
+ UNALIGNED_WORD_ACCESS should be used to determine whether
+ unaligned word access is allowed or not. After this commit,
+ ./configure CPPFLAGS="-DUNALIGNED_WORD_ACCESS=0" disables
+ unaligned word access even on platforms that support the feature.
+
+Fri Jan 15 16:12:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (string1): reset heredoc indent for each string literal
+ so that concatenated string would not be dedented.
+ [ruby-core:72857] [Bug #11990]
+
+Thu Jan 14 20:01:00 2016 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * lib/uri/generic.rb (URI::Generic#to_s): change encoding to
+ UTF-8 as Ruby 2.2/ by Koichi ITO <koic.ito@gmail.com>
+ https://github.com/ruby/ruby/pull/1188 fix GH-1188
+
+Thu Jan 14 17:36:16 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * variable.c (rb_f_global_variables): add matched back references
+ only, as well as defined? operator.
+
+Thu Jan 14 16:12:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * sprintf.c (rb_str_format): format exact number more exactly.
+
+Thu Jan 14 15:08:43 2016 Tony Arcieri <bascule@gmail.com>
+
+ * Remove 512-bit DH group. It's affected by LogJam Attack.
+ https://weakdh.org/
+ [fix GH-1196][Bug #11968][ruby-core:72766]
+
+Thu Jan 14 11:44:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * variable.c (rb_f_global_variables): add $1..$9 only if $~ is
+ set. fix the condition removed at r14014.
+
+Wed Jan 13 17:21:45 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * .travis.yml: removed commented-out code.
+
+Wed Jan 13 17:14:54 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * .travis.yml: removed osx code. follow up with r53517
+
+Wed Jan 13 16:56:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * iseq.c (rb_iseq_mark): mark parent iseq to prevent dynamically
+ generated iseq by eval from GC. [ruby-core:72620] [Bug #11928]
+
+Wed Jan 13 03:42:58 2016 Eric Wong <e@80x24.org>
+
+ * class.c (Init_class_hierarchy): resolve name for rb_cObject ASAP
+ * object.c (rb_mod_const_set): move name resolution to rb_const_set
+ * variable.c (rb_const_set): do class resolution here
+ [ruby-core:72807] [Bug #11977]
+
+Wed Jan 13 00:37:12 2016 Satoshi Ohmori <sachin21dev@gmail.com>
+
+ * man/ruby.1: fix double word typo. [Fix GH-1194]
+
+Tue Jan 12 21:01:09 2016 Benoit Daloze <eregontp@gmail.com>
+
+ * common.mk: update URL and name for the Ruby spec suite.
+
+Tue Jan 12 19:52:19 2016 sorah (Shota Fukumori) <her@sorah.jp>
+
+ * lib/forwardable.rb: Convert given accessors to String.
+
+ r53381 changed to accept only Symbol or String for accessors, but
+ there are several rubygems that pass classes (e.g. Array,
+ Hash, ...) as accessors. Prior r53381, it was accepted because Class#to_s
+ returns its class name. After r53381 given accessors are checked
+ with define_method, but it accepts only Symbol or String, otherwise
+ raises TypeError.
+
+ def_delegator Foo, :some_method
+
+ This change is to revert unexpected incompatibility. But this behavior
+ may change in the future.
+
+Mon Jan 12 18:41:41 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: made a variable name more grammatically correct
+
+Mon Jan 12 18:34:34 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: minor grammar fix [ci skip]
+
+Mon Jan 12 16:09:09 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * test/ruby/enc/test_casing_options.rb: Tests for option
+ parsing/checking for upcase/downcase/capitalize/swapcase
+ (see r53503; with Kimihito Matsui)
+
+Mon Jan 12 16:03:03 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * string.c: Added option parsing/checking for upcase/downcase/
+ capitalize/swapcase (with Kimihito Matsui)
+
+Mon Jan 11 21:28:28 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * include/ruby/oniguruma.h: Added flags needed for upcase/downcase
+ Unicode addition (with Kimihito Matsui)
+
+Mon Jan 11 09:50:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: check if the API version number is consistent with
+ the program version number.
+
+Sun Jan 10 20:57:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (compile_massign_lhs): when index ends with splat,
+ append rhs value to it like POSTARG, since VM_CALL_ARGS_SPLAT
+ splats the last argument only. [ruby-core:72777] [Bug #11970]
+
+Sun Jan 10 15:45:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/missing.h (explicit_bzero_by_memset_s): remove
+ inline implementation by memset_s, which needs a macro before
+ including headers and can cause problems in extension libraries
+ by the order of the macro and headers.
+
+Sun Jan 10 13:41:36 2016 Eric Wong <e@80x24.org>
+
+ * io.c (rb_deferr): remove long obsolete global
+
+Sun Jan 10 09:14:42 2016 Eric Wong <e@80x24.org>
+
+ * ext/psych/lib/psych/visitors/yaml_tree.rb (visit_String):
+ eliminate chomp
+ * lib/net/http.rb (connect): eliminate delete
+ * lib/net/http/header.rb (basic_encode): ditto
+ * lib/net/imap.rb (authenticate): eliminate gsub
+ (self.encode_utf7): shorten delete arg
+ * lib/net/smtp.rb (base64_encode): eliminate gsub
+ * lib/open-uri.rb (OpenURI.open_http): eliminate delete
+ * lib/rss/rss.rb: ditto
+ * lib/securerandom.rb (base64): ditto
+ (urlsafe_base64): eliminate delete!
+ * lib/webrick/httpauth/digestauth.rb (split_param_value):
+ eliminate chop
+ * lib/webrick/httpproxy.rb (do_CONNECT): eliminate delete
+ (setup_upstream_proxy_authentication): ditto
+ [ruby-core:72666] [Feature #11938]
+
+Sat Jan 9 23:19:14 2016 Kuniaki IGARASHI <igaiga@gmail.com>
+
+ * test/ruby/test_hash.rb (test_try_convert): Add test for
+ Hash.try_convert. [Fix GH-1190]
+
+Sat Jan 9 23:15:25 2016 Jon Moss <maclover7@users.noreply.github.com>
+
+ * ext/openssl/ossl.c: Add missing variables to documentation
+ examples. [Fix GH-1189]
+
+Sat Jan 9 18:25:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * symbol.h (is_attrset_id): ASET is an attrset ID. fix
+ unexpected safe call instead of an ordinary ASET.
+
+Sat Jan 9 10:44:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in, win32/setup.mak: extract RUBY_PROGRAM_VERSION from
+ RUBY_VERSION in version.h instead of RUBY_API_VERSION numbers in
+ include/ruby/version.h, and cut it into version numbers.
+
+Sat Jan 9 07:13:33 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename PAGE_* to HEAP_PAGE_* because PAGE_SIZE is used
+ in Mac OS X.
+
+ * test/ruby/test_gc.rb: catch up this fix.
+
+Sat Jan 9 05:45:40 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: PAGE_BITMAP_PLANES (the number of bitmap) is 4, not 3.
+
+Sat Jan 9 05:42:57 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename constant names HEAP_* to PAGE_*.
+
+ Keys of GC::INTERNAL_CONSTANTS are also renamed.
+
+ * test/ruby/test_gc.rb: catch up this fix.
+
+Fri Jan 8 22:30:06 2016 Akinori MUSHA <knu@iDaemons.org>
+
+ * doc/regexp.rdoc: [DOC] Elaborate on the \G anchor. [ci skip]
+
+Fri Jan 8 19:49:27 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: remove heap_page::body. Instead of this field,
+ heap_page::start field works well.
+
+Fri Jan 8 19:31:52 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: rename rb_heap_t::page_length to rb_heap_t::total_pages.
+
+ `page_length' is not clear (we may understand with length of
+ a page).
+
+Fri Jan 8 17:07:14 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: remove heap_page::heap. This field is only used to recognize
+ whether a page is in a tomb or not. Instead of this field,
+ heap_page::flags::in_tomb (1 bit field) is added.
+
+ Also type of heap_page::(total|free|final)_slots are changed from
+ int to short. 2B is enough for them.
+
+Fri Jan 8 09:33:59 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * iseq.c (rb_iseq_compile_with_option): move variable initialization
+ code to avoid maybe-uninitialized warnings by gcc 4.8.
+
+Fri Jan 8 00:03:22 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * enum.c (enum_min, enum_max): do the same optimization as r53454.
+
+Thu Jan 7 22:32:21 2016 Kenta Murata <mrkn@mrkn.jp>
+
+ * ruby.h: undef HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR_CONSTANT_P
+ and HAVE_BUILTIN___BUILTIN_TYPES_COMPATIBLE_P on C++.
+ [ruby-core:72736] [Bug #11962]
+
+Thu Jan 7 22:02:21 2016 Shugo Maeda <shugo@ruby-lang.org>
+
+ * enum.c (enum_minmax): optimize object comparison in
+ Enumerable#minmax.
+
+Thu Jan 7 14:49:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * thread.c (rb_thread_pending_interrupt_p): no pending interrupt
+ before initialization.
+
+ * thread.c (thread_raise_m, rb_thread_kill): uninitialized thread
+ cannot interrupt. [ruby-core:72732] [Bug #11959]
+
+Thu Jan 7 11:34:14 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * include/ruby/backward.h (ruby_show_copyright_to_die): for source
+ code backward compatibility.
+
+ * ruby.c (process_options): return Qtrue to exit the process
+ successfully.
+
+ * version.c (ruby_show_copyright): no longer exit.
+
+Wed Jan 6 17:22:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/optparse.rb (OptionParser#order!): add `into` optional
+ keyword argument to store the results. [Feature #11191]
+
+Tue Jan 5 21:44:37 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * ChangeLog: fix wrong class name.
+
+Tue Jan 5 21:43:50 2016 Kuniaki IGARASHI <igaiga@gmail.com>
+
+ * test/ruby/test_string.rb(test_chr): added test for String#chr
+ [fix GH-1179]
+
+Tue Jan 5 21:32:26 2016 Kuniaki IGARASHI <igaiga@gmail.com>
+
+ * test/ruby/test_numeric.rb (test_nonzero_p): added test for Numeric#nonzero?
+ [fix GH-1187]
+
+Tue Jan 5 11:47:23 2016 Damir Gaynetdinov <damir.gaynetdinov@gmail.com>
+
+ * doc/marshal.rdoc: Clarify object references example, that the
+ reference is same object. [Fix GH-1156]
+
+Tue Jan 5 05:06:51 2016 Eric Wong <e@80x24.org>
+
+ * ext/stringio/stringio.c (strio_binmode): implement to set encoding
+ * test/stringio/test_stringio.rb (test_binmode): new test
+ [ruby-core:72699] [Bug #11945]
+
+Mon Jan 4 15:44:37 2016 Sho Hashimoto <sho-h@ruby-lang.org>
+
+ * variable.c (rb_mod_deprecate_constant): [DOC] added
+ documentation for Module#deprecate_constant. [ci skip]
+
+Mon Jan 4 15:36:38 2016 Sho Hashimoto <sho-h@ruby-lang.org>
+
+ * thread_sync.c: [DOC] remove SizedQueue#close argument.
+ [ci skip]
+
+Mon Jan 4 10:14:24 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * test/coverage/test_coverage.rb: ignored test when enabled to coverage.
+ It lead to crash with `make test-all`.
+
+Mon Jan 4 08:10:44 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * insns.def (opt_case_dispatch): Move a comment to the
+ appropriate position.
+ [ci skip]
+
+Sun Jan 3 23:55:13 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/rubygems/security.rb (DIGEST_ALGORITHM, KEY_ALGORITHM):
+ should check same name as the used constants.
+ [ruby-core:72674] [Bug #11940]
+
+Sun Jan 3 19:22:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * aclocal.m4: add fallback file for non-aclocal environments.
+ [ruby-core:72683] [Bug #11942]
+
+Sun Jan 3 13:56:49 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
+
+ * eval_error.c (rb_print_undef): Use `rb_method_visibility_t`
+ instead of `int`.
+ * eval_intern.h (rb_print_undef): ditto
+ * proc.c (mnew_internal): ditto
+ * vm_method.c (rb_export_method): ditto
+ [Misc #11649] [ruby-core:71311] [fix GH-1078]
+
+Sun Jan 3 12:12:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * acinclude.m4: rename aclocal.m4, which should be generated by
+ aclocal. [ruby-core:72675] [Bug #11941]
+
+Sat Jan 2 21:07:55 2016 Eric Wong <e@80x24.org>
+
+ * thread_sync.c (queue_do_pop): avoid cast with Qfalse
+ (rb_szqueue_push): ditto, use queue_sleep wrapper
+
+Sat Jan 2 16:16:14 2016 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
+
+ * lib/erb.rb: Allow ERB subclass to add token easily.
+ [Feature #11936]
+
+ * test/erb/test_erb.rb: ditto.
+
+Sat Jan 2 14:44:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (regexp): set_yylval_num sets u1, should use nd_tag
+ instead of nd_state. [ruby-core:72638] [Bug #11932]
+
+Sat Jan 2 02:27:22 2016 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/ostruct.rb: Fix case of frozen object with initializer.
+ Bug revealed by RubySpec [ruby-core:72639]
+
+Fri Jan 1 22:01:52 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
+
+ * NEWS: mention CSV's liberal_parsing option.
+
+Fri Jan 1 19:38:23 2016 okkez <okkez000@gmail.com>
+
+ * doc/NEWS-2.3.0: fix double words typo.
+ [ci skip][fix GH-1183]
+
+Fri Jan 1 15:28:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (remove_unreachable_chunk): decrease count of
+ call_info in removed instructions. fix up r53402.
+
+Fri Jan 1 12:05:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (remove_unreachable_chunk): remove unreferred label
+ to optimize away unreachable chunk.
+
+Fri Jan 1 11:42:57 2016 James Edward Gray II <james@graysoftinc.com>
+
+ * lib/csv.rb (CSV): Add a liberal_parsing option.
+ Patch by Braden Anderson. [#11839]
+ * test/csv/test_features.rb: test liberal_parsing
+
+Fri Jan 1 10:27:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * tool/mkconfig.rb (RbConfig): prefix SDKROOT to oldincludedir
+ not includedir, the latter is outside the ruby installation.
+ [ruby-core:72496] [Bug #11881]
+
+Fri Jan 1 08:53:02 2016 Yuki Kurihara <co000ri@gmail.com>
+
+ * test/ruby/test_lazy_enumerator.rb (test_take_bad_arg): Add test
+ code in case of Enumerator::Lazy#take called with negative number.
+ [ruby-dev:49467] [Bug #11933]
+
+Fri Jan 1 05:06:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (parser_here_document): update indent for each line in
+ indented here document with single-quotes.
+ [ruby-core:72479] [Bug #11871]
+
+Fri Jan 1 03:26:44 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/ostruct.rb (freeze): define deferred accessors before
+ freezing to get rid of an error when just reading frozen
+ OpenStruct.
+
+Thu Dec 31 14:36:45 2015 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
+
+ * lib/ostruct.rb: Fix new_ostruct_member to correctly avoid
+ redefinition [#11901]
+
+Thu Dec 31 02:45:12 2015 NARUSE, Yui <naruse@ruby-lang.org>
+
+ * test/ruby/test_module.rb (test_classpath): r53376 may change
+ the order of m.constants.
+ `make TESTS='-v ruby/test_class.rb ruby/test_module.rb' test-all`
+ may fail after that.
+ http://rubyci.s3.amazonaws.com/tk2-243-31075/ruby-trunk/log/20151230T164202Z.log.html.gz
+
+Thu Dec 31 02:20:00 2015 Benoit Daloze <eregontp@gmail.com>
+
+ * common.mk (help): Fix typo.
+
+Wed Dec 30 20:53:09 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/net/http/responses.rb: Added new response class for 451 status code.
+ * lib/net/http.rb: documentation for HTTPUnavailableForLegalReasons
+
+Wed Dec 30 20:45:45 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * lib/webrick/httpstatus.rb: Added HTTP 451 Status Code.
+ [fix GH-1167] Patch by @MuhammetDilmac
+ https://tools.ietf.org/html/draft-tbray-http-legally-restricted-status-00
+
+Wed Dec 30 20:25:52 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * doc/syntax/calling_methods.rdoc: fix old operator for safe navigation
+ operator. [ci skip][fix GH-1182] Patch by @dougo
+
+Wed Dec 30 16:43:23 2015 Kuniaki IGARASHI <igaiga@gmail.com>
+
+ * test/ruby/test_string.rb (test_ord): Add test for String#ord.
+ [Fix GH-1181]
+
+Wed Dec 30 11:28:57 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/forwardable.rb (def_instance_delegator): adjust backtrace of
+ method body by tail call optimization. adjusting the delegated
+ target is still done by deleting backtrace.
+
+ * lib/forwardable.rb (def_single_delegator): ditto.
+
+Wed Dec 30 11:18:42 2015 Elliot Winkler <elliot.winkler@gmail.com>
+
+ * lib/forwardable.rb (def_instance_delegator) fix delegating to
+ 'args' and 'block', clashing with local variables in generated
+ methods. [ruby-core:72579] [Bug #11916]
+
+ * lib/forwardable.rb (def_single_delegator): ditto.
+
+Wed Dec 30 09:58:56 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * object.c (rb_class_inherited_p): search the corresponding
+ ancestor to prepended module from prepending class itself.
+ [ruby-core:72493] [Bug #11878]
+
+Wed Dec 30 09:20:00 2015 Yuki Kurihara <co000ri@gmail.com>
+
+ * test/stringio/test_io.rb (test_flag): add assertion for error when
+ text and binary mode are mixed.
+ [ruby-dev:49465] [Feature #11921]
+
+Wed Dec 30 08:43:59 2015 Yuki Kurihara <co000ri@gmail.com>
+
+ * test/stringio/test_stringio.rb (test_initialize): add test for
+ StringIO#initialize. [ruby-core:72585] [Feature #11920]
+
+Wed Dec 30 05:19:24 2015 Eric Wong <e@80x24.org>
+
+ * class.c (struct clone_const_arg): adjust for id_table
+ (clone_const): ditto
+ (clone_const_i): ditto
+ (rb_mod_init_copy): ditto
+ (rb_singleton_class_clone_and_attach): ditto
+ (rb_include_class_new): ditto
+ (include_modules_at): ditto
+ * constant.h (rb_free_const_table): ditto
+ * gc.c (free_const_entry_i): ditto
+ (rb_free_const_table): ditto
+ (obj_memsize_of): ditto
+ (mark_const_entry_i): ditto
+ (mark_const_tbl): ditto
+ * internal.h (struct rb_classext_struct): ditto
+ * object.c (rb_mod_const_set): resolve class name on assignment
+ * variable.c (const_update): replace with const_tbl_update
+ (const_tbl_update): new function
+ (fc_i): adjust for id_table
+ (find_class_path): ditto
+ (autoload_const_set): st_update => const_tbl_update
+ (rb_const_remove): adjust for id_table
+ (sv_i): ditto
+ (rb_local_constants_i): ditto
+ (rb_local_constants): ditto
+ (rb_mod_const_at): ditto
+ (rb_mod_const_set): ditto
+ (rb_const_lookup): ditto
+ [ruby-core:72112] [Feature #11614]
+
+Wed Dec 30 04:10:13 2015 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
+
+ * thread_pthread.c (rb_thread_create_timer_thread): destroy attr even
+ if pthread_create() failed.
+
+Wed Dec 30 02:55:09 2015 Eric Wong <e@80x24.org>
+
+ * thread_pthread.c (setup_communication_pipe): delay setting owner
+ (rb_thread_create_timer_thread): until thread creation succeeds
+ [ruby-core:72590] [Bug #11922]
+
+Tue Dec 29 19:12:46 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * ruby.c (proc_options): -W command line option should be able to
+ override -w in RUBYOPT environment variable.
+
+Tue Dec 29 17:54:16 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (ignored_block): warn if a block is given to `using`,
+ which is probably for `Module.new`.
+
+Tue Dec 29 12:48:34 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * lib/ostruct.rb (OpenStruct): make respond_to? working on
+ just-allocated objects for workaround of Psych.
+ [ruby-core:72501] [Bug #11884]
+
+Tue Dec 29 10:35:00 2015 Kenta Murata <mrkn@mrkn.jp>
+
+ * test/mkmf/test_have_func.rb (test_have_func):
+ Add assertion to examine the existence of HAVE_RUBY_INIT.
+
+ * test/mkmf/test_have_func.rb (test_not_have_func):
+ Add assertion to examine the absence of HAVE_RUBY_INIT.
+
+Tue Dec 29 06:50:42 2015 Eric Wong <e@80x24.org>
+
+ * thread_sync.c: static classes
+
+Tue Dec 29 05:30:30 2015 Eric Wong <e@80x24.org>
+
+ * lib/resolv.rb (Resolv::IPv6.create): avoid modifying frozen
+ * test/resolv/test_dns.rb (test_ipv6_create): test for above
+ [Bug #11910] [ruby-core:72559]
+
+Mon Dec 28 14:55:57 2015 Kuniaki IGARASHI <igaiga@gmail.com>
+
+ * test/ruby/test_string.rb (TestString#test_rstrip_bang): Add test
+ for String#rstrip!. [Fix GH-1176]
+
+Mon Dec 28 09:18:53 2015 Kuniaki IGARASHI <igaiga@gmail.com>
+
+ * test/ruby/test_string.rb (TestString#test_lstrip_bang): Add test
+ for String#lstrip!. [Fix GH-1176]
+
+Sun Dec 27 23:32:26 2015 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_variant2val): refactoring.
+
+Sun Dec 27 21:14:42 2015 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * process.c (rb_execarg_parent_start1): need to convert the encoding to
+ ospath's one.
+
+Sun Dec 27 20:54:22 2015 NAKAMURA Usaku <usa@ruby-lang.org>
+
+ * process.c: use rb_w32_uchdir() instead of plain chdir() on Windows.
+ reported by naruse via twitter.
+
+ * process.c (rb_execarg_addopt): need to convert the encoding to
+ ospath's one.
+
+Sun Dec 27 20:00:31 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * enc/x_emoji.h: fix dead-link.
+
+Sun Dec 27 19:55:55 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
+
+ * doc/NEWS-2.3.0: fix a typo.
+
+Sun Dec 27 18:08:15 2015 Kuniaki IGARASHI <igaiga@gmail.com>
+
+ * string.c (rb_str_lstrip_bang, rb_str_rstrip_bang): [DOC] Fix
+ ruby-doc comments for String#rstrip! and lstrip!. It looks like
+ dropped bang. [Fix GH-1175]
+
+Sun Dec 27 15:14:20 2015 Eric Wong <e@80x24.org>
+
+ * io.c (io_getpartial): remove unused kwarg from template
+ * test/ruby/test_io.rb (test_readpartial_bad_args): new
+ [Bug #11885]
+
+Sun Dec 27 11:50:53 2015 Kuniaki IGARASHI <igaiga@gmail.com>
+
+ * test/ruby/test_string.rb (test_rstrip, test_lstrip): Add tests
+ for String#lstrip and rstrip. The test cases are used from
+ string.c ruby-doc comments. [Fix GH-1174]
+
+Sun Dec 27 11:47:46 2015 Kuniaki IGARASHI <igaiga@gmail.com>
+
+ * test/ruby/test_string.rb (test_insert): Add test for
+ String#insert. The test cases are written in string.c
+ comments as a reference. [Fix GH-1173]
+
+Sun Dec 27 11:03:33 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * parse.y (show_bitstack): trace stack_type value if yydebug.
+
+Sun Dec 27 10:03:14 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * enc/depend (enc, trans): fix version dependency, shared object
+ files depend on the RUBY_SO_NAME value for runtime link.
+
+Sun Dec 27 09:47:20 2015 Masaki Suketa <masaki.suketa@nifty.ne.jp>
+
+ * ext/win32ole/win32ole.c (ole_vstr2wc, ole_variant2val): fix blank
+ string conversion.
+ [Bug #11880]
+ Thanks Akio Tajima for the patch!
+
+Sun Dec 27 09:34:53 2015 craft4coder <yooobuntu@163.com>
+
+ * doc/extension.rdoc: [DOC] `nul` should be uppercase.
+ change 'nul' => 'NUL'. [Fix GH-1172]
+
+Sat Dec 26 18:29:01 2015 Kouhei Sutou <kou@cozmixng.org>
+
+ * lib/xmlrpc/client.rb: Support SSL options in async methods of
+ XMLRPC::Client.
+ [Bug #11489]
+ Reported by Aleksandar Kostadinov. Thanks!!!
+
+Sat Dec 26 11:26:38 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * miniinit.c (Init_enc): add some common aliases of built-in
+ encodings. [ruby-core:72481] [Bug #11872]
+
+Fri Dec 25 22:43:26 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * configure.in: extract RUBY_RELEASE_DAY at generating Makefile.
+
+ * version.h (RUBY_RELEASE_DATE): construct from RUBY_RELEASE_YEAR,
+ RUBY_RELEASE_MONTH, and RUBY_RELEASE_DAY.
+
+Fri Dec 25 21:33:06 2015 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * version.h (RUBY_VERSION): 2.4.0 development has started.
+
+Fri Dec 25 14:12:12 2015 Martin Duerst <duerst@it.aoyama.ac.jp>
+
+ * doc/ChangeLog-2.3.0, ext/tk/lib/tkextlib/SUPPORT_STATUS,
+ include/ruby/version.h: minor grammar fixes [ci skip]
+
+Fri Dec 25 08:23:22 2015 Tadashi Saito <tad.a.digger@gmail.com>
+
+ * compile.c, cont.c, doc, man: fix common misspelling.
+ [ruby-core:72466] [Bug #11870]
+
+
+For the changes before 2.3.0, see doc/ChangeLog-2.3.0
+For the changes before 2.2.0, see doc/ChangeLog-2.2.0
+For the changes before 2.1.0, see doc/ChangeLog-2.1.0
+For the changes before 2.0.0, see doc/ChangeLog-2.0.0
+For the changes before 1.9.3, see doc/ChangeLog-1.9.3
+For the changes before 1.8.0, see doc/ChangeLog-1.8.0
+
+Local variables:
+coding: us-ascii
+add-log-time-format: (lambda (&optional x y)
+ (let* ((time (or x (current-time)))
+ (system-time-locale "C")
+ (diff (+ (cadr time) 32400))
+ (lo (% diff 65536))
+ (hi (+ (car time) (/ diff 65536))))
+ (format-time-string "%a %b %e %H:%M:%S %Y" (list hi lo) t)))
+indent-tabs-mode: t
+tab-width: 8
+change-log-indent-text: 2
+end:
+vim: tabstop=8 shiftwidth=2
diff --git a/doc/ChangeLog/ChangeLog-YARV b/doc/ChangeLog-YARV
index 83df05c52c..83df05c52c 100644
--- a/doc/ChangeLog/ChangeLog-YARV
+++ b/doc/ChangeLog-YARV
diff --git a/doc/ChangeLog/ChangeLog-2.1.0 b/doc/ChangeLog/ChangeLog-2.1.0
deleted file mode 100644
index 7964a682eb..0000000000
--- a/doc/ChangeLog/ChangeLog-2.1.0
+++ /dev/null
@@ -1,18060 +0,0 @@
-Fri Dec 20 17:52:50 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_method.c: check definition of
- GLOBAL_METHOD_CACHE_SIZE and GLOBAL_METHOD_CACHE_MASK.
-
-Fri Dec 20 17:03:10 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: rename OBJ_WRITE and OBJ_WRITTEN into
- RB_OBJ_WRITE and RB_OBJ_WRITTEN.
-
- * array.c, class.c, compile.c, hash.c, internal.h, iseq.c,
- proc.c, process.c, re.c, string.c, variable.c, vm.c,
- vm_eval.c, vm_insnhelper.c, vm_insnhelper.h,
- vm_method.c: catch up this change.
-
-Fri Dec 20 16:01:35 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: add a comment for WB interfaces.
-
-Fri Dec 20 16:00:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: DLDFLAGS is defined in --with-opt-dir handler, so
- ${DLDFLAGS=} does not work now. use RUBY_APPEND_OPTIONS instead.
- [ruby-dev:47855] [Bug #9256]
-
-Fri Dec 20 14:19:12 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in (AC_ARG_WITH): use withval directly.
- fix failure on FreeBSD.
- http://fb32.rubyci.org/~chkbuild/ruby-trunk/log/20131217T070301Z.diff.html.gz
-
-Fri Dec 20 14:00:01 2013 Aman Gupta <ruby@tmm1.net>
-
- * include/ruby/ruby.h (struct RClass): add super, remove iv_index_tbl.
- since RCLASS_SUPER() is commonly used inside while loops, we move it
- back inside struct RClass to improve cache hits. this provides a
- small improvement (1%) in hotspots like rb_obj_is_kind_of()
- * internal.h (struct rb_classext_struct): remove super, add
- iv_index_table
- * internal.h (RCLASS_SUPER): update for new location
- * internal.h (RCLASS_SET_SUPER): ditto
- * internal.h (RCLASS_IV_INDEX_TBL): ditto
- * object.c (rb_class_get_superclass): ditto
- * include/ruby/backward/classext.h (RCLASS_SUPER): ditto
-
-Fri Dec 20 07:07:35 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 03d6ae7. Changes include:
-
- * Fixed typos.
-
- * Relaxed Gem.ruby test for ruby packagers that do not use `ruby`.
-
- * test/rubygems: ditto.
-
-Thu Dec 19 14:03:04 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (heap_get_freeobj): improve hot path performance.
-
- * gc.c (heap_get_freeobj_from_next_freepage): replace with
- heap_get_freepage(). It returns freeobj instead of freepage.
- This is not on hot path.
-
-Thu Dec 19 12:05:17 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master af60443. Changes include:
-
- * Improved speed of `gem install --ignore-dependencies`.
-
- * Open read-write for exclusive flock. [ruby-trunk - Bug #9257]
-
- * Remove specification before install to prevent infinite loop.
-
-Thu Dec 19 11:23:49 2013 Aman Gupta <ruby@tmm1.net>
-
- * vm_insnhelper.c (vm_call_iseq_setup_normal): simple for loop
- condition optimization. this area shows up as a hotspot in VM
- profiles.
-
-Thu Dec 19 10:50:13 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (newobj_of): don't need to RBASIC_SET_CLASS() which includes WB
- here because created obj is always YOUNG/INFANT.
-
-Thu Dec 19 10:48:37 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/gc/gcbench.rb: check GC::OPTS availability
- for not MRI 2.1.0.
-
-Thu Dec 19 03:10:30 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c (heap_get_freeobj): remove redundant assignment. heap->freelist
- is set after the while() loop already.
-
-Thu Dec 19 01:54:30 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/runner.rb: fix commit miss on r44278.
-
-Thu Dec 19 00:26:11 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (garbage_collect_body): lazy_sweep setting should work
- without USE_RGENGC.
-
-Wed Dec 18 23:31:04 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_profile_dump_major_reason): fix this function because major_reason
- can be OR of multiple reasons.
-
- * gc.c (gc_profile_dump_on): ditto.
-
-Wed Dec 18 17:03:00 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_profile_record_get): should return an empty array
- when profiling is active.
-
-Wed Dec 18 16:49:40 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_profile_clear, gc_profile_enable): remove rest_sweep().
-
- * gc.c: check objspace->profile.current_record before inserting
- profiling record by new macro gc_prof_enabled().
-
-Wed Dec 18 14:32:06 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_exec.h (VM_DEBUG_STACKOVERFLOW): added.
- disable stack overflow check for every stack pushing as default.
-
- * vm_exec.c (vm_stack_overflow_for_insn): ditto.
-
-Wed Dec 18 10:00:22 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master d8f12e2. This increases the
- speed of `gem install --ignore-dependencies` which helps bundler
- tests.
- * test/rubygems: ditto.
-
-Wed Dec 18 09:00:17 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_gc.rb (test_expand_heap): allow +/-1 diff.
-
-Tue Dec 17 23:44:15 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * test/ruby/test_io.rb: fix duplicated test name.
-
-Tue Dec 17 20:15:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (rb_hash_reject): revert to deprecated behavior, with
- warnings, due to compatibility for HashWithDifferentAccess.
- [ruby-core:59154] [Bug #9223]
-
-Tue Dec 17 17:30:56 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-electric.el: Import version 2.1.1 from
- https://github.com/knu/ruby-electric.el.
-
- * ruby-electric-delete-backward-char: Enable support for number
- prefix.
-
- * ruby-electric-curlies: Fix electric operation after an open
- curly.
-
-Tue Dec 17 16:19:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_trace.c (rb_postponed_job_flush): isolate exceptions in
- postponed jobs and restore outer ones. based on a patch by
- tarui. [ruby-core:58652] [Bug #9168]
-
-Tue Dec 17 10:48:04 2013 Aman Gupta <ruby@tmm1.net>
-
- * configure.in (RUBY_DTRACE_POSTPROCESS): Fix compatibility with
- systemtap on linux. stap requires `dtrace -G` post-processing, but
- the dtrace compatibility wrapper is very strict about probes.d
- syntax.
-
-Tue Dec 17 05:18:17 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 1c5f4b3. Allows rubygems
- repackagers to disable backward-compatible shared gem directory
- behavior.
- * test/rubygems: ditto.
-
-Tue Dec 17 05:14:35 2013 Eric Hodel <drbrain@segment7.net>
-
- * NEWS (RDoc): Update version number so I don't have to change it
- for the final release.
-
-Mon Dec 16 19:19:19 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_objspace_markable_object_p): should check special_const_p
- first (by is_markable_object()).
-
-Mon Dec 16 19:12:54 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/objspace.c (reachable_object_from_root_i): use
- compare_by_identity hash to avoid hash modify problem
- during iteration.
- [Bug #9252]
-
- * ext/objspace/objspace.c (reachable_objects_from_root): ditto.
-
-Mon Dec 16 18:16:28 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_verify_internal_consistency): should not use
- rb_objspace_each_objects() because it call rest_sweep().
-
-Mon Dec 16 18:07:30 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_objspace_markable_object_p): fix last commit (build error).
-
-Mon Dec 16 18:04:28 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_objspace_markable_object_p): it should be live objects.
-
-Mon Dec 16 18:00:51 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_objspace_each_objects): should not clear dont_lazy_sweep
- flag in nested case.
-
-Mon Dec 16 16:40:35 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_method.c (rb_method_entry_make): fix WB miss.
- Note that rb_method_entry_t::klass is not constified.
- We may constify this field.
-
- * test/ruby/test_alias.rb: add a test.
-
-Mon Dec 16 14:14:22 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: use gc_verify_internal_consistency() instead of
- gc_check_before_marks_i() for check consistency
- on RGENGC_CHECK_MODE >= 2.
-
-Mon Dec 16 14:01:48 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * process.c (make_clock_result): add :second as a unit for
- Process.clock_gettime.
-
-Mon Dec 16 13:10:54 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: introduce GC.verify_internal_consistency method to verify GC
- internal data structure.
-
- Now this method only checks generation (old/young) consistency.
-
-Mon Dec 16 11:49:26 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c (gc_info_decode): Fix build errors when compiled with
- RGENGC_ESTIMATE_OLDMALLOC=0
- * gc.c (objspace_malloc_increase): ditto
-
-Sun Dec 15 13:38:29 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/objspace.c (reachable_object_from_root_i):
- reachable objects should not include categories and
- category_objects because it is noisy information.
-
- In fact, objects created after calling
- ObjectSpace.reachable_objects_from_root should not be included
- as a returning hash objects. Currently, mswin64 platform has a
- problem because of this behavior. Should we trace new objects?
-
-Sun Dec 15 07:09:28 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rdoc: Update to RDoc master 263a9e5. This improves the
- accessibility of the search box.
-
-Sat Dec 14 17:39:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_callee_setup_arg_complex): count post
- arguments as mandatory arguments. [ruby-core:57706] [Bug #8993]
-
- * vm_insnhelper.c (vm_yield_setup_block_args): ditto.
-
-Sat Dec 14 16:26:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (rubylibprefix): replace exec_prefix as well as
- bindir and libdir. a patch by kimuraw (Wataru Kimura) at
- [ruby-dev:47852]. [Bug #9160]
-
-Sat Dec 14 14:42:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/logger.rb (lock_shift_log): no need to rotate the log file
- if it has been rotated by another process. based on the patch
- by no6v (Nobuhiro IMAI) in [ruby-core:58620]. [Bug #9133]
-
-Sat Dec 14 13:01:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (mnew_from_me): method by respond_to_missing? should be
- owned by the original class.
-
-Sat Dec 14 11:55:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/scanf.rb (IO#scanf): fix mistaken use of rescue modifier.
- a patch by Mon_Ouie at [ruby-core:52813]. [Bug #7940]
-
-Sat Dec 14 11:44:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * util.c (ruby_qsort): fix potential stack overflow on a large
- machine. based on the patch by Conrad Irwin <conrad.irwin AT
- gmail.com> at [ruby-core:51816]. [Bug #7772]
-
-Sat Dec 14 11:25:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (rb_mod_const_defined): support nested class path as
- well as const_get. [Feature #7414]
-
-Sat Dec 14 01:31:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (rb_rescue2): reuse tags pushed for body proc to protect
- rescue proc too.
-
-Sat Dec 14 01:15:51 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (wmap_final_func): Bugfix. Should update *value to new pointer.
-
-Sat Dec 14 01:05:46 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/lib/socket.rb: Don't test $! in "ensure" clause because
- it may be set before the body.
- Reported by ko1 and mrkn. [ruby-core:59088] [Bug #9247]
-
- * lib/cgi/core.rb: Ditto.
-
- * lib/drb/ssl.rb: Ditto.
-
-Sat Dec 14 00:34:31 2013 Naohisa Goto <ngotogenome@gmail.com>
-
- * internal.h (ruby_sized_xrealloc2): fix typo introduced in r44117,
- which cause compile error on Solaris.
-
-Sat Dec 14 00:22:16 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c: (exec_recursive): use rb_catch_protect() instead of
- rb_catch_obj() and PUSH_TAG(), and reduce pushing tags and
- machine stack usage.
-
-Sat Dec 14 00:18:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (mnew_from_me): achieve the original defined_class from
- prepended iclass, to fix inherited owner.
-
- * proc.c (method_owner): return the defined class, but not the
- class which the method object is created from.
-
-Fri Dec 13 22:29:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (method_owner): return the class where alias is defined, not
- the class original method is defined.
-
- * vm_method.c (rb_method_entry_make, rb_alias): store the originally
- defined class in me. [Bug #7993] [Bug #7842] [Bug #9236]
-
- * vm_method.c (rb_method_entry_get_without_cache): cache included
- module but not iclass.
-
-Fri Dec 13 16:27:17 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c (gc_info_decode): Use :major_by=>:nofree as fallback reason
- when other trigger conditions are present.
-
-Fri Dec 13 13:25:30 2013 Koichi Sasada <ko1@atdot.net>
-
- * error.c: add Exception#backtrace_locations.
- Now, there are no setter and independent from Exception#backtrace.
- [Feature #8960]
-
- * eval.c (setup_exception): set backtrace locations for `bt_location'
- special attribute.
-
- * vm_backtrace.c (rb_backtrace_to_location_ary): added.
-
- * internal.h: ditto.
-
- * test/ruby/test_backtrace.rb: add a test for
- Exception#backtrace_locations.
-
-Fri Dec 13 12:01:07 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (garbage_collect_body): use rb_bug() and explicit error message
- instead of using assert().
- [Bug #9222]
-
-Fri Dec 13 11:52:41 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c: fix comment to remove the word "shady".
-
- * variable.c: ditto.
-
-Fri Dec 13 11:33:55 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename *shady* func/macros.
- * RVALUE_RAW_SHADY() -> RVALUE_WB_PROTECTED_RAW()
- * RVALUE_SHADY() -> RVALUE_RAW_SHADY()
- * rgengc_check_shady() -> rgengc_check_relation().
- And fix some messages using "shady" to "non-WB-protected".
-
-Fri Dec 13 10:04:23 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/request_set/lockfile.rb: Import RubyGems master a8d0669
- with a 1.8.7 compatibility fix.
- * test/rubygems/test_gem_request_set_lockfile.rb: ditto.
-
-Fri Dec 13 09:50:49 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master ddac51f. Changes:
-
- * Allow override for the shared gem installation directory for
- rubygems packagers.
-
- * Lock gem cache files for read and write to improve thread safety.
-
- * Use io/console when available.
-
- * Minor cleanup.
-
- * test/rubygems: ditto.
-
-Fri Dec 13 08:15:31 2013 Aman Gupta <ruby@tmm1.net>
-
- * class.c (include_modules_at): use RCLASS_M_TBL_WRAPPER for
- equality checks. this avoids an unnecessary deference inside a tight
- loop, fixing a performance regression from r43973.
- * object.c (rb_obj_is_kind_of): ditto.
- * object.c (rb_class_inherited_p): ditto.
-
-Wed Dec 13 02:00:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (VpSetPTR): fix for limitation of the resulting
- precision.
- [ruby-core:50269] [Bug #7458]
-
- * test/bigdecimal/test_bigdecimal.rb (test_limit): add tests for the above
- change.
-
-Wed Dec 13 01:56:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (VpAddAbs): put out a conditional branch from
- the inside of while-loop.
-
- * ext/bigdecimal/bigdecimal.c (VpSubAbs): ditto.
-
-Wed Dec 13 01:53:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (VPrint): be a static function, support another
- dump formats, and add more information of the given bigdecimal.
-
- * ext/bigdecimal/bigdecimal.h: ditto.
-
-Wed Dec 11 16:45:58 2013 Koichi Sasada <ko1@atdot.net>
-
- * eval.c (rb_raise_jump): call c_return hook immediately after
- popping `raise' frame.
- Patches by deivid (David Rodriguez). [Bug #8886]
-
- * test/ruby/test_settracefunc.rb: catch up this fix.
-
-Wed Dec 11 16:01:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (rb_hash_reject): return a plain hash, without copying
- the class, default value, instance variables, and taintedness.
- they had been copied just by accident.
- [ruby-core:59045] [Bug #9223]
-
-Wed Dec 11 15:36:15 2013 Aman Gupta <ruby@tmm1.net>
-
- * compile.c (iseq_specialized_instruction): emit opt_aset instruction
- to optimize Hash#[]= and Array#[]= when called with Fixnum argument.
- [Bug #9227] [ruby-core:58956]
-
-Wed Dec 11 04:54:03 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master ec8ed22. Notable changes
- include:
-
- * Renamed extension_install_dir to extension_dir (backwards
- compatible).
-
- * Fixed creation of gem.deps.rb.lock file from
- TestGemRequestSet#test_install_from_gemdeps_install_dir
-
- * Fixed a typo and some documentation.
-
- * test/rubygems: ditto.
-
-Wed Dec 11 03:18:08 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * insns.def: Fix optimization bug of Float#/ [Bug #9238]
-
-Tue Dec 10 23:58:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/date/date_strptime.c (date__strptime_internal): unset
- case-insensitive flag for [:alpha:], which already implies both
- cases, to get rid of backtrack explosion. [ruby-core:58984]
- [Bug #9221]
-
-Tue Dec 10 23:44:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_hash): add salt to differentiate false and empty
- array. [ruby-core:58993] [Bug #9231]
-
- * hash.c (rb_any_hash, rb_hash_hash): ditto.
-
-Tue Dec 10 18:16:09 2013 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * man/ruby.1: [DOC] Use www.ruby-toolbox.com instead of RAA.
-
-Tue Dec 10 17:21:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (wmap_finalize, wmap_aset_update): use simple malloced array
- instead of T_ARRAY, to reduce GC pressure.
-
-Tue Dec 10 15:56:48 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c (reflist_add): revert changes from r44109. it is unnecessary
- after r44113
- * gc.c (allrefs_i): fix whitespace
- * gc.c (allrefs_roots_i): fix whitespace
-
-Tue Dec 10 15:46:03 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (allrefs_add): push obj only if allrefs table doesn't have
- obj.
-
- * gc.c (allrefs_roots_i): ditto.
-
-Tue Dec 10 15:28:10 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (RGENGC_CHECK_MODE): separate checkers to different modes.
- * 2: enable generational bits check (for debugging)
- * 3: enable livness check
- * 4: show all references
-
-Tue Dec 10 15:15:37 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_marks_check): disable GC during checking and
- restore malloc_increase info.
-
-Tue Dec 10 14:41:53 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c (reflist_add): return 0 if reference already exists
- * gc.c (allrefs_add): return 1 on newly added references
- * gc.c (allrefs_i): follow references to construct complete object
- graph. before this patch, RGENGC_CHECK could fail to verify some WB
- miss issues. [Bug #9226] [ruby-core:58959]
-
-Tue Dec 10 11:20:56 2013 Aman Gupta <ruby@tmm1.net>
-
- * ext/objspace/objspace_dump.c (dump_object): include fstring flag on
- strings. include gc flags (old, remembered, wb_protected) on all objects.
- * ext/objspace/objspace_dump.c (Init_objspace_dump): initialize lazy
- IDs before first use.
- * gc.c (rb_obj_gc_flags): new function to retrieve object flags
- * internal.h (RB_OBJ_GC_FLAGS_MAX): maximum flags allowed for one obj
- * test/objspace/test_objspace.rb (test_dump_flags): test for above
- * test/objspace/test_objspace.rb (test_trace_object_allocations):
- resolve name before dump (for rb_class_path_cached)
-
-Tue Dec 10 07:48:29 2013 Aman Gupta <ruby@tmm1.net>
-
- * vm_method.c (rb_clear_method_cache_by_class): fire
- ruby::method-cache-clear probe on global or klass-level method cache
- clear [Bug #9190]
- * probes.d (provider ruby): new dtrace probe
- * doc/dtrace_probes.rdoc: docs for new probe
- * test/dtrace/test_method_cache.rb: test for new probe
-
-Tue Dec 10 06:14:11 2013 Eric Hodel <drbrain@segment7.net>
-
- * ext/.document: Remove curses from documentable directories.
-
-Tue Dec 10 04:55:36 2013 Zachary Scott <e@zzak.io>
-
- * ext/openssl/lib/openssl/digest.rb: Deprecate OpenSSL::Digest::Digest
- [Fixes GH-446] https://github.com/ruby/ruby/pull/446
-
-Tue Dec 10 00:41:42 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * ext/thread/thread.c: [DOC] add call-seq alias for Queue#enq, #<<, etc.
-
- * ext/thread/thread.c (Init_thread): use rb_define_alias instead of
- rb_alias to document alias.
-
-Mon Dec 9 20:00:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * internal.h (RCLASS_SERIAL): Add RCLASS_SERIAL as a convenience
- accessor for RCLASS_EXT(klass)->class_serial.
-
- * class.c, vm_insnhelper.c, vm_method.c: Use RCLASS_SERIAL
-
-Mon Dec 9 19:50:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * compile.c, insns.def, test/ruby/test_rubyvm.rb, vm.c, vm_core.h,
- vm_insnhelper.c, vm_insnhelper.h, vm_method.c: Rename method_serial
- to global_method_state and constant_serial to global_constant_state
- after discussion with ko1.
-
-Mon Dec 9 18:50:43 2013 Aman Gupta <ruby@tmm1.net>
-
- * hash.c (rb_hash_replace): fix segv on `{}.replace({})` introduced
- in r44060 [Bug #9230] [ruby-core:58991]
- * test/ruby/test_hash.rb: regression test for above
-
-Mon Dec 9 18:10:10 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm.c (vm_stat): renamed from ruby_vm_stat.
- Should not use ruby_ prefix here.
-
-Mon Dec 9 16:13:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (wmap_size): add ObjectSpace::WeakMap#size and #length.
-
-Mon Dec 9 15:26:17 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * test/test_curses.rb: removed.
-
-Mon Dec 9 13:36:55 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * ext/curses, sample/curses: removed curses.
-
- * NEWS: added an entry for the above change.
-
-Mon Dec 9 12:26:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/objspace/object_tracing.c (newobj_i): use cached class path
- only to get rid object allocation during NEWOBJ hook.
- [ruby-core:58853] [Bug #9212]
-
- * variable.c (rb_class_path_cached): returns cached class path
- only, without searching and allocating new class path string.
-
-Mon Dec 9 11:14:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/date/date_parse.c (parse_time): unset case-insensitive flag
- for [:alpha:], which already implies both cases, to get rid of
- backtrack explosion. [ruby-core:58876] [Bug #9221]
-
-Mon Dec 9 08:40:40 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master bf37240. Fixes useless
- error message with `gem install -g` with no gem dependencies file.
- * test/rubygems: ditto.
-
-Mon Dec 9 04:52:25 2013 Eric Hodel <drbrain@segment7.net>
-
- * NEWS: Update RubyGems entry with notable features.
-
-Mon Dec 9 04:43:54 2013 Eric Hodel <drbrain@segment7.net>
-
- * ext/.document: Add syslog/lib and thread/thread.c to documentable
- items. [ruby-trunk - Bug #9228]
-
-Mon Dec 9 04:28:50 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 096db36. Changes include
- support for PATH in Gemfile.lock and a typo fix from Akira Matsuda.
- * test/rubygems: ditto.
-
-Mon Dec 9 02:10:32 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/net/http/responses.rb:
- Add `HTTPIMUsed`, as it is also supported by rack/rails.
- RFC - https://www.rfc-editor.org/rfc/rfc3229
- by Vipul A M <vipulnsward@gmail.com>
- https://github.com/ruby/ruby/pull/447 fix GH-447
-
-Sun Dec 8 20:47:35 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (rb_get_kwargs): when values is non-null, remove
- extracted keywords from the rest keyword argument.
-
-Sun Dec 8 20:26:54 2013 Yutaka Kanemoto <kanemoto@ruby-lang.org>
-
- * common.mk (ruby.imp): avoid circular dependency on AIX
-
-Sun Dec 8 20:21:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * bigdecimal.c (BigDecimal_coerce): convert a Float to a BigDecimal instead
- of converting the receiver to a Float. The reason is there are BigDecimal
- instances with precisions that is smaller than the Float's precision.
- [ruby-core:58756] [Bug #9192]
-
- * test/bigdecimal/test_bigdecimal.rb: add tests for the above change.
-
-Sun Dec 8 18:28:20 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * NEWS: [DOC] update NEWS about GC.
-
-Sun Dec 8 17:52:24 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * object.c: [DOC] document Module#singleton_class?.
-
-Sun Dec 8 16:19:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (rb_get_kwargs): if optional is negative, unknown
- keywords are allowed.
-
- * vm_insnhelper.c (vm_callee_setup_keyword_arg): check unknown
- keywords.
-
-Sun Dec 8 14:55:12 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * array.c (rb_ary_shuffle_bang, rb_ary_sample): rename local variables.
-
-Sun Dec 8 13:59:38 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * array.c (rb_ary_shuffle_bang, rb_ary_sample): check
- unknown keywords.
-
- * test/ruby/test_array.rb (test_shuffle, test_sample): tests for
- the above.
-
-Sun Dec 8 13:01:11 2013 Aman Gupta <ruby@tmm1.net>
-
- * vm.c (ruby_vm_stat): add RubyVM.stat() for access to internal cache
- counters. this methods behaves like GC.stat, accepting an optional
- hash or symbol argument. [Bug #9190] [ruby-core:58750]
- * test/ruby/test_rubyvm.rb: test for new method
-
-Sun Dec 8 11:59:40 2013 Aman Gupta <ruby@tmm1.net>
-
- * hash.c (rb_hash_replace): add a write barrier to fix GC mark miss on
- hashes using Hash#replace [Bug #9226] [ruby-core:58948]
-
-Sun Dec 8 11:21:00 2013 Aman Gupta <ruby@tmm1.net>
-
- * include/ruby/ruby.h: add RGENGC_WB_PROTECTED_NODE_CREF setting
- In a large app, this reduces the size of
- remembered_shady_object_count by 80%. [Bug #9225] [ruby-core:58947]
- * gc.c (rb_node_newnode): add FL_WB_PROTECTED flag to NODE_CREF
- * class.c (rewrite_cref_stack): insert OBJ_WRITE for NODE_CREF
- * iseq.c (set_relation): ditto
- * iseq.c (rb_iseq_clone): ditto
- * vm_eval.c (rb_yield_refine_block): ditto
- * vm_insnhelper.c (vm_cref_push): ditto
- * vm_insnhelper.h (COPY_CREF): ditto
-
-Sun Dec 8 10:45:05 2013 Aman Gupta <ruby@tmm1.net>
-
- * hash.c (hash_aset_str): revert r43870 due to performance issue
- [Bug #9188] [ruby-core:58730]
- * parse.y (assoc): convert literal string hash keys to fstrings
- * test/ruby/test_hash.rb (class TestHash): expand test
-
-Sun Dec 8 10:22:38 2013 Aman Gupta <ruby@tmm1.net>
-
- * parse.y (register_symid_str): use fstrings in symbol table
- [Bug #9171] [ruby-core:58656]
- * parse.y (rb_id2str): ditto
- * string.c (rb_fstring): create frozen_strings on first usage. this
- allows rb_fstring() calls from the parser (before cString is created)
- * string.c (fstring_set_class_i): set klass on fstrings generated
- before cString was defined
- * string.c (Init_String): convert frozen_strings table to String
- objects after boot
- * ext/-test-/symbol/type.c (bug_sym_id2str): expose rb_id2str()
- * test/-ext-/symbol/test_type.rb (module Test_Symbol): verify symbol
- table entries are fstrings
-
-Sun Dec 8 10:24:20 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems.rb: Update version for upcoming ruby 2.1.0 RC.
-
-Sun Dec 8 10:21:36 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 14749ce. This fixes bugs
- handling of gem dependencies lockfiles (Gemfile.lock).
-
- * test/rubygems: ditto.
-
-Sun Dec 8 09:40:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * array.c (rb_ary_or): use RHASH_TBL_RAW instead of RHASH_TBL
-
- * process.c (rb_execarg_fixup): use RHASH_TBL_RAW and insert write
- barriers where appropriate
-
- * vm.c (kwmerge_i): use RHASH_TBL_RAW
-
- * vm.c (HASH_ASET): use rb_hash_aset instead of calling directly into
- st_insert
-
-Sat Dec 7 11:15:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (rb_hash_reject): copy unrejected elements only to new hash,
- so that the change on the original receiver can affect.
- [ruby-core:58914] [Bug #9223]
-
-Sat Dec 7 08:25:00 2013 Richo Healey <richo@psych0tik.net>
-
- * test/ruby/test_struct.rb: Add regression test for question marks and
- bangs in struct members. [Closes GH-468]
-
-Fri Dec 6 19:33:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (rb_extract_keywords, rb_get_kwargs): move from
- vm_insnhelper.c.
-
-Fri Dec 6 19:18:02 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: change oldmalloc meaning.
- Increase oldmalloc_increase with malloc_increase
- instead of using obj_memsize_of().
-
- This change will avoid the danger of memory full without major GC.
-
-Fri Dec 6 19:08:48 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (atomic_sub_nounderflow): not 0 but val itself.
-
-Fri Dec 6 18:37:11 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_objspace_alloc, Init_heap): initialize
- oldmalloc_increase_limit at Init_heap.
-
- rb_objspace_alloc() is not called on some platforms.
-
-Fri Dec 6 18:33:39 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (garbage_collect_body): bug fix.
- initialize after recording.
-
-Fri Dec 6 17:49:46 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (atomic_sub_nounderflow): added to simplify atomic sub with
- care about underflow.
-
- * gc.c (objspace_malloc_increase): use it.
-
-Fri Dec 6 17:10:44 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (rb_get_kwargs): get keyword argument values from an
- option hash, not only checking keys.
-
- * dir.c (dir_initialize): use rb_get_kwargs.
-
- * gc.c (gc_start_internal): ditto.
-
-Fri Dec 6 16:47:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * misc/ruby-mode.el (ruby-brace-to-do-end): split single line block.
-
- * misc/ruby-mode.el (ruby-do-end-to-brace): shrink single line block
- to one line.
-
-Fri Dec 6 16:16:30 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_start_internal): do not use rb_gc_start() and rb_gc().
-
-Fri Dec 6 15:24:30 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_start_internal, rb_gc): do not need
- heap_pages_free_unused_pages() here.
- It was done in after_sweep().
-
- * gc.c (rb_gc): The reason is now GPR_FLAG_CAPI.
-
-Fri Dec 6 14:05:19 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c (gc_start_internal): GC.start() now accepts two optional
- keyword arguments. These can be used to disable full_mark (minor
- mark only) or disable immediate_sweep (use lazy sweep). These new
- options are useful for benchmarking GC behavior, or performing minor
- GC out-of-band.
- * test/ruby/test_gc.rb (class TestGc): tests for new options.
-
-Fri Dec 6 11:51:28 2013 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/erb.rb: [DOC] fix broken link, Use rubygems.org and www.ruby-toolbox.com instead of RAA.
- [Bug #9197]
-
-Fri Dec 6 10:50:54 2013 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/webrick/httprequest.rb: [DOC] Fix broken link of CGI specification by @udzura [fix GH-466]
-
-Thu Dec 6 01:27:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (GetVpValueWithPrec):
- treat 0.0 and -0.0 of floating-point numbers specially for an optimization
- and to correctly propagate its signbit to the result.
- [Bug #9214] [ruby-core:58858]
-
- * test/bigdecimal/test_bigdecimal.rb: add tests case for the above change.
-
- * test/bigdecimal/test_bigdecimal_util.rb: ditto.
-
-Thu Dec 5 22:18:01 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (configuration): strip destdir part from prefix to get
- rid of duplication. a patch by arton at [ruby-core:58859].
- [ruby-core:58856] [Bug #9213]
-
-Thu Dec 5 21:53:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_or): lhs elements are preferred, so should not
- replace with rhs elements.
-
- * test/ruby/test_array.rb (test_OR_in_order): import the test failed
- by r43969 from rubyspec/core/array/union_spec.rb.
-
-Thu Dec 5 21:05:42 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_info_decode): fix to avoid syntax error on VS2012.
-
-Thu Dec 5 19:35:35 2013 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * st.c: tweaked comment
-
-Thu Dec 5 19:21:10 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c (struct rb_objspace): rename internal last_collection_flags to
- latest_gc_info
- * gc.c (gc_latest_collection_info): add GC.latest_gc_info() with similar
- behavior to GC.stat()
- * gc.c (rb_gc_latest_gc_info): new c-api for above
- * gc.c (gc_stat_internal): remove :last_collection_flags from GC.stat
- * gc.c (gc_profile_decode_flags): remove GC::Profiler.decode_flags
- * include/ruby/intern.h (rb_gc_latest_gc_info): export new c-api
- * test/ruby/test_gc.rb (class TestGc): test for new behavior
- * NEWS: note about new api
-
- * gc.c (gc_stat_internal): raise TypeError on wrong type
- * gc.c (gc_stat): fix error message
-
-Thu Dec 5 18:18:08 2013 Aman Gupta <ruby@tmm1.net>
-
- * ext/objspace/gc_hook.c: remove this file
- * ext/-test-/tracepoint/gc_hook.c: new filename for above
- * ext/objspace/objspace.c: remove ObjectSpace.after_gc_start_hook=
- * test/objspace/test_objspace.rb: remove test
- * test/-ext-/tracepoint/test_tracepoint.rb: add above test for
- tracepoint re-entry
-
-Thu Dec 5 17:44:53 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: change function names vm_ prefix to objspace_ prefix.
- They are objspace_ functionality.
-
-Thu Dec 5 16:11:04 2013 Aman Gupta <ruby@tmm1.net>
-
- * include/ruby/intern.h: add rb_gc_stat() for access to GC.stat
- variables from c-api
- * gc.c (rb_gc_stat): new c-api method. accepts either VALUE hash like
- GC.stat, or VALUE symbol key and returns size_t directly. the second
- form is useful to avoid allocations, i.e. for usage inside
- INTERNAL_EVENT_GC tracepoints.
- * gc.c (gc_stat): add GC.stat(:key) to return single value instead of hash
- * gc.c (gc_stat_internal): helper method to retrieve single or all stat values
- * test/ruby/test_gc.rb (class TestGc): test for new behavior
- * NEWS: note about this new api
-
-Thu Dec 5 14:40:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (rb_hash): revert r43981 and bail out to the outermost frame
- when recursion is detected.
-
-Thu Dec 5 13:47:15 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (vm_malloc_size): added.
- return malloc_usable_size() if possible.
-
- * gc.c (MALLOC_ALLOCATED_SIZE): add new setting macro to enable
- GC.allocated_size.
- If platform supports `malloc_usable_size()' (or similar one),
- GC.allocated_size can be implemented with this function.
- Default is 0.
-
- * gc.c (vm_xmalloc, vm_xrealloc, vm_xfree): use vm_malloc_size()
- to detect collect allocated size.
-
- * gc.c (vm_malloc_increase): refactoring.
-
-Thu Dec 5 13:19:03 2013 Aman Gupta <ruby@tmm1.net>
-
- * include/ruby/ruby.h: remove INTERNAL_EVENT_GC_END and replace with
- two new events: GC_END_MARK and GC_END_SWEEP
- * gc.c (gc_after_sweep): emit GC_END_SWEEP after lazy sweep is done
- * gc.c (gc_marks_body): emit GC_END_MARK at end of minor/major mark
- * ext/-test-/tracepoint/tracepoint.c (struct tracepoint_track): tests
- for new events.
- * test/-ext-/tracepoint/test_tracepoint.rb (class TestTracepointObj):
- ditto.
- * NEWS: remove ObjectSpace.after_gc_*_hook. These are only a sample,
- and will be removed before ruby 2.1.
- * ext/objspace/gc_hook.c: remove ObjectSpace.after_gc_end_hook=
-
-Thu Dec 5 10:47:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby_atomic.h (ATOMIC_PTR_EXCHANGE): atomic exchange function for
- a generic pointer.
-
-Thu Dec 5 10:47:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (finalize_deferred): flush all deferred finalizers while other
- finalizers can get ready to run newly by lazy sweep.
- [ruby-core:58833] [Bug #9205]
-
-Thu Dec 5 09:07:59 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c (ruby_gc_set_params): Accept safe_level argument so GC tuning
- settings can be applied before rb_safe_level() is available.
- * internal.h (rb_gc_set_params): ditto.
- * ruby.c (process_options): Apply GC tuning early during boot process
- so boot-time allocations can benefit. This also benefits any code
- loaded in via `ruby -r`.
-
-Wed Dec 4 13:02:13 2013 Aman Gupta <ruby@tmm1.net>
-
- * vm_trace.c (rb_suppress_tracing): Fix initialization of stack
- allocated rb_trace_arg_t structure. Without this patch, sometimes
- INTERNAL_EVENT_GC would be skipped accidentally inside
- rb_threadptr_exec_event_hooks_orig().
-
-Wed Dec 4 12:57:24 2013 Aman Gupta <ruby@tmm1.net>
-
- * string.c (fstr_update_callback): Improve implementation in r43968
- based on feedback from @nagachika. In the existing case, we can
- return ST_STOP to prevent any hash modification. In the !existing
- case, set both key and value to the fstr.
-
-Wed Dec 4 12:47:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/delegate.rb (Delegator#method_missing): ignore the target if not
- set, and delegate to global methods. [ruby-core:58572] [Bug #9155]
-
- * lib/delegate.rb (Delegator#respond_to_missing): ditto.
-
- * lib/delegate.rb (SimpleDelegator#__getobj__): yield and return if
- not delegated but a block is given, like as Hash#fetch.
-
- * lib/delegate.rb (DelegateClass#__getobj__): ditto.
-
-Tue Dec 3 23:48:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: check malloc_size() availability.
-
- * gc.c: use malloc_size() with malloc/malloc.h if available.
-
-Tue Dec 3 23:06:20 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * object.c (rb_obj_clone): don't copy FL_WB_PROTECTED of a
- original object.
-
-Tue Dec 3 22:32:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (rb_hash_recursive): make similar (recursive) constructs
- return same hash value. execute recursively, and rewind to the
- topmost frame with an object which .eql? to the recursive
- object, if recursion is detected.
-
- * hash.c (rb_hash): detect recursion for all `hash' methods. each
- `hash' methods no longer need to use rb_exec_recursive().
-
-Tue Dec 3 21:53:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (rb_catch_protect): new function similar to
- rb_catch_obj(), but protect from all global jumps like as
- rb_load_protect(), rb_protect(), etc.
-
-Tue Dec 3 20:18:46 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * object.c (rb_obj_clone): Protect FL_PROMOTED and FL_WB_PROTECTED
- flags of a destination object.
-
-Tue Dec 3 20:16:38 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_hash_rehash): use hash_alloc() instead of rb_hash_new(),
- to hide temporary object from ObjectSpace. [Bug #9187]
-
-Tue Dec 3 17:11:47 2013 Aman Gupta <ruby@tmm1.net>
-
- * load.c (features_index_add_single): Move loaded_features_index array values off
- the ruby heap. [Bug #9201] [ruby-core:58805]
- * load.c (loaded_features_index_clear_i): Clean up off-heap array structure.
- * vm.c (rb_vm_mark): Remove unnecessary mark_tbl for loaded_features_index.
- This improves minor GC time by 15% in a large application.
-
-Tue Dec 3 17:01:45 2013 Aman Gupta <ruby@tmm1.net>
-
- * include/ruby/ruby.h (struct RClass): Add wrapper struct around
- RClass->m_tbl with serial. This prevents double marking method
- tables, since many classes/modules can share the same method table.
- This improves minor mark time in a large application by 30%.
- * internal.h (struct method_table_wrapper): Define new
- wrapper struct with additional serial.
- * internal.h (RCLASS_M_TBL_INIT): New macro for initializing method
- table wrapper and st_table.
- * method.h (void rb_sweep_method_entry): Rename rb_free_m_table to
- rb_free_m_tbl for consistency
- * .gdbinit (define rb_method_entry): Update rb_method_entry gdb helper
- for new method table structure.
- * class.c: Use RCLASS_M_TBL_WRAPPER and
- RCLASS_M_TBL_INIT macros.
- * class.c (rb_include_class_new): Share WRAPPER between module and
- iclass, so serial can prevent double marking.
- * eval.c (rb_prepend_module): ditto.
- * eval.c (rb_using_refinement): ditto.
- * gc.c: Mark and free new wrapper struct.
- * gc.c (obj_memsize_of): Count size of additional wrapper struct.
-
-Tue Dec 3 14:05:49 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_uniq_bang): remove duplicate code.
-
-Tue Dec 3 13:40:42 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (ary_add_hash): set and return values because string keys
- will be frozen. [ruby-core:58809] [Bug #9202]
-
- * array.c (rb_ary_uniq_bang): ditto.
-
- * array.c (rb_ary_or): ditto.
-
- * array.c (rb_ary_uniq): ditto.
-
- * test/ruby/test_array.rb: tests for above.
-
- The patch is from normalperson (Eric Wong).
-
-Tue Dec 3 12:20:21 2013 Aman Gupta <ruby@tmm1.net>
-
- * string.c (rb_fstring): Use st_update instead of st_lookup +
- st_insert.
- * string.c (fstr_update_callback): New callback for st_update.
-
-Tue Dec 3 12:17:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/rdoc/constant.rb (RDoc::Constant#documented?): workaround for
- NoMethodError when the original of alias is not found.
-
-Tue Dec 3 10:43:58 2013 Eric Hodel <drbrain@segment7.net>
-
- * ext/openssl/lib/openssl/buffering.rb: Return ASCII-8BIT strings from
- SSLSocket methods. [ruby-trunk - Bug #9028]
- * test/openssl/test_ssl.rb: Test for the above.
-
-Tue Dec 3 09:42:27 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rdoc: Update to RDoc master 900de99. Changes include:
-
- Fixed documentation display of constants
-
- Fixed handling of unknown parsers
-
- * test/rdoc: ditto.
-
-Mon Dec 2 22:30:10 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * hash.c (getenv): fixed test failures introduced by r43950.
- [ruby-core:58774] [Bug #9195] reported by phasis68 (Heesob Park).
-
-Mon Dec 2 21:49:19 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_rehash): make temporary st_table under the control
- of GC. [Bug #9187]
-
- * test/ruby/test_hash.rb: add a test for above.
-
-Mon Dec 2 17:23:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * variable.c (rb_mod_constants): when calling Module#constants with
- inherit=false, there is no need to use a hashtable to deduplicate
- constant names. [Feature #9196] [ruby-core:58786]
-
-Mon Dec 2 14:16:52 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/net/smtp.rb (Net::SMTP#critical): Always return a
- Net::SMTP::Response. Patch by Pawel Veselov.
- [ruby-trunk - Bug #9125]
- * test/net/smtp/test_smtp.rb: Test for the above.
-
-Mon Dec 2 05:52:33 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master baa965b. Notable changes:
-
- Copy directories to lib/ when installing extensions. This completes
- the fix for [ruby-trunk - Bug #9106]
-
- * test/rubygems: ditto.
-
-Mon Dec 2 02:03:47 2013 Shota Fukumori <her@sorah.jp>
-
- * test/ruby/test_case.rb (test_nomethoderror):
- Add test related to r43913, r43914
-
-Mon Dec 2 00:53:01 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * hash.c (getenv): use ANSI codepage version of getenv() for miniruby
- on Windows.
- [ruby-core:58732] [Bug #9189] reported by phasis68 (Heesob Park).
-
-Sun Dec 1 22:14:27 2013 Zachary Scott <e@zzak.io>
-
- * doc/contributors.rdoc: [DOC] Import contributors from redmine wiki
- Many wiki pages have become outdated and spam-ridden, we will import
- these to trunk and begin maintaining them in ruby-trunk. This will
- also allow new contributors to easily contribute patches to update
- these pages, where previously a redmine account with wiki access was
- required. Another bonus is having a contributors file to show thanks
- to all of the people who have submitted a patch to Ruby.
-
-Sun Dec 1 18:03:26 2013 Zachary Scott <e@zzak.io>
-
- * doc/maintainers.rdoc: [DOC] Current maintainers of Ruby
-
-Sun Dec 1 17:17:36 2013 Zachary Scott <e@zzak.io>
-
- * doc/contributing.rdoc: [DOC] Current branch maintainers
-
-Sun Dec 1 17:16:36 2013 Zachary Scott <e@zzak.io>
-
- * doc/contributing.rdoc: [DOC] Reporting other (ruby-lang.org) issues
-
-Sun Dec 1 17:15:51 2013 Zachary Scott <e@zzak.io>
-
- * doc/contributing.rdoc: [DOC] Current platform maintainers
-
-Sun Dec 1 17:14:55 2013 Zachary Scott <e@zzak.io>
-
- * doc/contributing.rdoc: [DOC] Reporting downstream distro issues
-
-Sun Dec 1 14:37:20 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_to_a): specify array capa.
-
-Sun Dec 1 14:15:36 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_rehash): fix to free new st_table when exception
- is raised in do_hash(). [Bug #9187]
-
-Sun Dec 1 11:57:59 2013 Zachary Scott <e@zzak.io>
-
- * ext/openssl/lib/openssl/buffering.rb: Fix warning in copyright
-
-Sun Dec 1 08:27:28 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 66e5c39. Notable changes:
-
- Implement gem.deps.rb (Gemfile) .lock support
-
- Fixed `gem uninstall` for a relative directory in GEM_HOME.
-
- * test/rubygems: ditto.
-
-Sun Dec 1 06:00:49 2013 Aman Gupta <ruby@tmm1.net>
-
- * test/ruby/test_gc.rb (test_gc_reason): Force minor GC by consuming
- free slots to fix test.
-
-Sat Nov 30 21:22:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (dir_initialize): check unknown keywords. [ruby-dev:47152]
- [Bug #8060]
-
-Sat Nov 30 18:05:38 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32ole/win32ole.c (hash2named_arg): correct declaration to fix
- build failure. a patch by phasis68 (Heesob Park) at
- [ruby-core:58710]. [Bug #9184]
-
-Sat Nov 30 17:46:35 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (ruby_cleanup): determine exit status and signal to terminate
- before finalization, to get rid of access destroyed T_DATA exception
- object. [ruby-core:58643] [Bug #9167]
-
-Sat Nov 30 16:25:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enumerator.c (enumerator_with_index): should not store local variable
- address to memoize the arguments. it is invalidated after the return.
- [ruby-core:58692] [Bug #9178]
-
-Sat Nov 30 13:28:13 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * siphash.c (sip_hash24): fix for aligned word access little endian
- platforms. [ruby-core:58658] [Bug #9172]
-
-Sat Nov 30 13:21:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (rb_yield_block): implement non-nil block argument.
-
-Fri Nov 29 20:59:39 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * vm_dump.c (rb_vmdebug_debug_print_pre): Bugfix. Get PC directly.
- PC is cached into local stack and cfp->pc is incorrect at next of
- branch or jump.
- * vm_exec.h (DEBUG_ENTER_INSN): catch up this change.
- * vm_core.h: update signature of rb_vmdebug_debug_print_pre.
-
-Fri Nov 29 20:43:57 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * compile.c: Bugsfix for dump_disasm_list.
- rb_inspect denies a hidden object. So, insert wrapper that creates
- the unhidden one.
- adjust->label is null sometimes.
- insn_data_line_no makes no sense at all.
-
-Fri Nov 29 18:06:45 2013 Shota Fukumori <her@sorah.jp>
-
- * test/ruby/test_case.rb (test_method_missing): Test for r43913.
-
-Fri Nov 29 17:53:22 2013 Shota Fukumori <her@sorah.jp>
-
- * vm_insnhelper.c (check_match): Fix SEGV with VM_CHECKMATCH_TYPE_CASE
- and class of `pattern` has `method_missing`
- [Bug #8872] [ruby-core:58606]
-
-Fri Nov 29 17:06:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (rb_yield_block): yield block with rb_block_call_func
- arguments.
-
- * range.c (range_each): use rb_yield_block.
-
- * include/ruby/ruby.h (RB_BLOCK_CALL_FUNC_ARGLIST): constify argv.
-
- * enum.c (rb_enum_values_pack): ditto.
-
- * vm_eval.c (rb_block_call, rb_check_block_call): ditto.
-
- * include/ruby/ruby.h (RB_BLOCK_CALL_FUNC_ARGLIST): for declaration
- argument list of rb_block_call_func.
-
-Fri Nov 29 11:26:43 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_block_call_func): add blockarg. block
- function can take block argument, e.g., proc {|&blockarg| ...}.
-
-Thu Nov 28 21:43:48 2013 Zachary Scott <e@zzak.io>
-
- * doc/dtrace_probes.rdoc: [DOC] Import dtrace probes doc from wiki
-
-Thu Nov 28 21:17:32 2013 Zachary Scott <e@zzak.io>
-
- * doc/contributing.rdoc: [DOC] Add heading above ChangeLog tips to
- setup entry for commits, its not required. Actually easier if
- contributors don't include a ChangeLog entry.
-
-Thu Nov 28 21:16:18 2013 Zachary Scott <e@zzak.io>
-
- * doc/contributing.rdoc: [DOC] Add coding style heading for patch
- rules
-
-Thu Nov 28 21:15:45 2013 Zachary Scott <e@zzak.io>
-
- * doc/contributing.rdoc: [DOC] Add notes about deciding what to patch
-
-Thu Nov 28 19:43:45 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * benchmark/bm_hash_flatten.rb: added. r43896 is about 4 times faster
- than 2.0.0p353.
-
- * benchmark/bm_hash_keys.rb: added. r43896 is about 5 times faster
- than 2.0.0p353.
-
- * benchmark/bm_hash_values.rb: added. r43896 is about 5 times faster
- than 2.0.0p353.
-
-Thu Nov 28 19:29:04 2013 Zachary Scott <e@zzak.io>
-
- * doc/contributing.rdoc: [DOC] Add notes about slideshow proposals
- from wiki page: HowToRequestFeatures
-
-Thu Nov 28 17:34:42 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * st.c: add st_values() and st_values_check().
-
- * include/ruby/st.h: add prototypes for above.
-
- * hash.c (rb_hash_values): use st_values_check() for performance
- improvement if VALUE and st_data_t are compatible.
-
-Thu Nov 28 17:14:14 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * st.c (st_keys): fix not to use Qundef in st.c.
-
- * include/ruby/st.h: define modified prototype.
-
- * hash.c (rb_hash_keys): use modified st_keys().
-
-Thu Nov 28 16:34:43 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c: Expose details about last garbage collection via GC.stat.
- * gc.c (gc_stat): Add :last_collection_flags for reason/trigger/type of
- last GC run.
- * gc.c (gc_prof_sweep_timer_stop): Record HAVE_FINALIZE GPR even
- without GC_PROFILE_MORE_DETAIL.
- * gc.c (gc_profile_flags): Add GC::Profiler.decode_flags to make sense
- of GC.stat[:last_collection_flags]
- * test/ruby/test_gc.rb (class TestGc): Test for above.
-
-Thu Nov 28 16:15:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (rb_w32_dup2): extract from rb_cloexec_dup2() and
- redirect_dup2().
-
-Tue Nov 28 14:40:00 2013 Akira Matsuda <ronnie@dio.jp>
-
- * lib/drb/ssl.rb: [Doc] Fix typo
-
-Thu Nov 28 13:56:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (Doxyfile): tool/file2lastrev.rb needs running with
- BASERUBY since r43617. [ruby-dev:47823] [Bug #9169]
-
-Thu Nov 28 09:18:39 2013 Koichi Sasada <ko1@atdot.net>
-
- * string.c (rb_fstring): fstrings should be ELTS_SHARED.
- If we resurrect dying objects (non-marked, but not swept yet),
- pointing shared string can be collected.
- To avoid such issue, fstrings (recorded to fstring_table)
- should not be ELTS_SHARED (should not have a shared string).
-
-Thu Nov 28 01:35:08 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * st.c (st_keys): fix to use st_index_t for size of hash.
-
-Thu Nov 28 00:36:52 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * st.c (st_keys): define st_keys(). it writes each key to buffer.
-
- * hash.c (rb_hash_keys): use st_keys() for performance improvement
- if st_data_t and VALUE are compatible.
-
- * include/ruby/st.h: define macro ST_DATA_COMPATIBLE_P() to predicate
- whether st_data_t and passed type are compatible.
-
- * configure.in: check existence of builtin function to use in
- ST_DATA_COMPATIBLE_P().
-
-Thu Nov 28 00:07:28 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * ruby_atomic.h: remove duplicate definitions between ATOMIC_XXX
- and ATOMIC_SIZE_XXX.
-
-Wed Nov 27 23:55:50 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * ruby_atomic.h: define ATOMIC_SIZE_CAS() with
- __atomic_compare_exchange_n() and refactoring.
-
-Tue Nov 27 21:43:00 2013 Akira Matsuda <ronnie@dio.jp>
-
- * lib/irb/notifier.rb: [Doc] Fix typo
- * ext/json/lib/json/common.rb: Ditto.
-
-Tue Nov 27 18:04:57 2013 Akira Matsuda <ronnie@dio.jp>
-
- * lib/irb/notifier.rb: Fix typo
-
-Wed Nov 27 17:54:57 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_mark_stacked_objects): check only when check_mode > 0.
-
-Wed Nov 27 16:07:19 2013 Aman Gupta <ruby@tmm1.net>
-
- * test/ruby/test_gc.rb (class TestGc): Fix warning in
- test_expand_heap.
-
-Wed Nov 27 15:55:52 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c (Init_GC): Add new GC::INTERNAL_CONSTANTS for information about
- GC heap/page/slot sizing.
- * test/ruby/test_gc.rb (class TestGc): test for above.
-
-Wed Nov 27 15:21:17 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c (gc_page_sweep): Fix compile warning from last commit.
- * hash.c (hash_aset_str): Re-use existing variable to avoid
- unnecessary pointer dereferencing.
-
-Wed Nov 27 15:12:55 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_page_sweep): disable debug print.
-
-Wed Nov 27 15:05:59 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat): add new information heap_eden_page_length and
- heap_tomb_page_length.
-
- * test/ruby/test_gc.rb: fix to use GC.stat[:heap_eden_page_length]
- instead of GC.stat[:heap_length].
- This test expects `heap_eden_page_length' (used pages size).
-
-Wed Nov 27 15:02:53 2013 Aman Gupta <ruby@tmm1.net>
-
- * test/ruby/test_eval.rb (class TestEval): Use assert_same instead of
- assert_equal.
- * test/ruby/test_hash.rb (class TestHash): ditto.
- * test/ruby/test_iseq.rb (class TestISeq): ditto.
-
-Wed Nov 27 14:50:02 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rinda/ring.rb: Announce RingServer for the same process.
- [ruby-trunk - Bug #9163]
- * test/rinda/test_rinda.rb: Tests for the above.
-
-Wed Nov 27 14:37:33 2013 Aman Gupta <ruby@tmm1.net>
-
- * test/ruby/test_eval.rb (class TestEval): Add test for shared eval
- filenames via rb_fstring().
- * test/ruby/test_iseq.rb (class TestISeq): Add test for shared
- iseq labels via rb_fstring(). [Bug #9159]
-
-Wed Nov 27 14:24:55 2013 Aman Gupta <ruby@tmm1.net>
-
- * hash.c (hash_aset_str): Use rb_fstring() to de-duplicate hash string
- keys. Patch by Eric Wong. [Bug #8998] [ruby-core:57727]
- * test/ruby/test_hash.rb (class TestHash): test for above.
-
-Wed Nov 27 10:39:39 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c: Rename rb_heap_t members:
- used -> page_length
- limit -> total_slots
-
-Wed Nov 27 08:24:49 2013 Aman Gupta <ruby@tmm1.net>
-
- * compile.c: Use rb_fstring() to de-duplicate string literals in code.
- [ruby-core:58599] [Bug #9159] [ruby-core:54405]
- * iseq.c (prepare_iseq_build): De-duplicate iseq labels and source
- locations.
- * re.c (rb_reg_initialize): Use rb_fstring() for regex string.
- * string.c (rb_fstring): Handle non-string and already-fstr arguments.
- * vm_eval.c (eval_string_with_cref): De-duplicate eval source
- filename.
-
-Wed Nov 27 07:13:54 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych.rb: psych version 2.0.2
- * ext/psych/psych.gemspec: ditto
-
-Wed Nov 27 06:40:18 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/scalar_scanner.rb: fix support for negative
- years.
- * ext/psych/lib/psych/visitors/yaml_tree.rb: ditto
- * test/psych/test_date_time.rb: test for change.
- Fixes: https://github.com/tenderlove/psych/issues/168
-
-Wed Nov 27 04:46:55 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/scalar_scanner.rb: fix regexp for matching TIME
- strings.
- * test/psych/test_date_time.rb: test for change.
- Fixes: https://github.com/tenderlove/psych/issues/171
-
-Wed Nov 27 02:26:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (str_new4): copy the original capacity so that memsize of
- frozen shared string returns correct size.
-
-Wed Nov 27 02:20:13 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_hash): should not ignore the rest of recursive
- constructs.
-
- * hash.c (rb_hash_hash): ditto.
-
- * range.c (range_hash): ditto.
-
- * struct.c (rb_struct_hash): ditto.
-
- * test/-ext-/test_recursion.rb (TestRecursion): separate from
- test/ruby/test_thread.rb.
-
-Tue Nov 26 22:43:36 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (rb_hash): cut off if recursion detected to get rid of stack
- overflow. [ruby-core:58567] [Bug #9151]
-
-Tue Nov 26 20:02:39 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_settracefunc.rb: add tests for a_call/a_return
- by Brandur <brandur@mutelight.org> [Feature #9120]
-
-Tue Nov 26 19:29:52 2013 Koichi Sasada <ko1@atdot.net>
-
- * common.mk: add useful config "set breakpoint pending on"
- for run.gdb.
-
-Tue Nov 26 19:17:47 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/object_tracing.c (newobj_i): skip class_path if class
- is frozen.
-
- rb_class_path() can modify frozen classes (and causes errors).
- This patch is temporary. We need no-modification/no-allocation
- class path function.
-
-Tue Nov 26 18:12:13 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_trace.c: skip "exception check" and "reentrant check (only normal
- events) for internal events.
-
- Reentrant check for internal events are remaining.
-
-Tue Nov 26 17:38:16 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_trace.c: prohibit to specify normal events and internal events
- simultaneously.
- I will introduce special care for internal events later.
-
- * ext/-test-/tracepoint/tracepoint.c: test this behavior.
-
- * test/-ext-/tracepoint/test_tracepoint.rb: ditto.
-
-Tue Nov 26 16:30:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (rb_readlink): fix buffer overflow on a long symlink. since
- rb_str_modify_expand() expands from its length but not its capacity,
- need to set the length properly for each expansion.
- [ruby-core:58592] [Bug #9157]
-
-Tue Nov 26 14:23:17 2013 Aman Gupta <ruby@tmm1.net>
-
- * ext/objspace/objspace_dump.c (dump_append_string_value): Escape
- control characters for strict json parsers.
- * ext/objspace/objspace_dump.c (objspace_dump): Document File/IO
- output option.
-
-Tue Nov 26 11:43:19 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * ruby_atomic.h: use __atomic builtin functions supported by GCC.
- __sync family are legacy functions now and it is recommended
- that new code use the __atomic functions.
- http://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
-
- * configure.in: check existence of __atomic functions.
-
-Tue Nov 26 10:57:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/bigdecimal/bigdecimal.gemspec: revert Gem::Specification#date
- for snapshot/release tarballs.
-
-Tue Nov 26 06:42:50 2013 Aman Gupta <ruby@tmm1.net>
-
- * NEWS: Add ObjectSpace.after_gc_{start,end}_hook=
- * ext/objspace/objspace_dump.c: [DOC] catch up dump/dump_all to r43679
-
-Tue Nov 26 04:12:10 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 612f85a. Notable changes:
-
- Fixed installation and activation of git: and path: gems via
- Gem.use_gemdeps
-
- Improved documentation coverage
-
- * test/rubygems: ditto.
-
-Mon Nov 25 22:23:03 2013 Zachary Scott <e@zzak.io>
-
- * lib/xmlrpc.rb: [DOC] Fix link to xmlrpc4r site [Bug #9148]
- Patch by Giorgos Tsiftsis
-
-Mon Nov 25 19:48:10 2013 Zachary Scott <e@zzak.io>
-
- * lib/uri/common.rb: [DOC] typo fixes by @vipulnsward [Fixes GH-456]
- https://github.com/ruby/ruby/pull/456
- * lib/uri/generic.rb: [DOC] ditto.
-
-Mon Nov 25 14:34:42 2013 Zachary Scott <e@zzak.io>
-
- * ext/bigdecimal/bigdecimal.gemspec: bump BigDecimal to 1.2.3 for
- proper release date in RubyGems
-
-Mon Nov 25 14:25:08 2013 Zachary Scott <e@zzak.io>
-
- * ext/bigdecimal/bigdecimal.gemspec: Remove Gem::Specification#date
- We should rely on rubygems to create the date the gem was released
- for each version.
-
-Mon Nov 25 06:53:30 2013 Koichi Sasada <ko1@atdot.net>
-
- * internal.h: do not use ruby_sized_xrealloc() and ruby_sized_xfree()
- if HAVE_MALLOC_USABLE_SIZE (or _WIN32) is defined.
-
- We don't need these function if malloc_usable_size() is available.
-
- * gc.c: catch up this change.
-
- * gc.c: define HAVE_MALLOC_USABLE_SIZE on _WIN32.
-
- * array.c (ary_resize_capa): do not use ruby_sized_xfree() with
- local variable to avoid "unused local variable" warning.
- This change only has few impact.
-
- * string.c (rb_str_resize): ditto.
-
-Mon Nov 25 05:05:04 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/-ext-/tracepoint/test_tracepoint.rb: catch up GC.stat changes
- at r43835.
-
-Mon Nov 25 04:45:59 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: continue to change OLDSPACE -> OLDMALLOC.
- RGENGC_ESTIMATE_OLDSPACE -> RGENGC_ESTIMATE_OLDMALLOC.
-
- * gc.c: add a new major GC reason GPR_FLAG_MAJOR_BY_OLDMALLOC.
-
-Mon Nov 25 04:16:09 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: change terminology "..._num" to "..._slots" about slot operation.
- * final_num -> final_slots
- * objspace_live_num() -> objspace_live_slots()
- * objspace_limit_num() -> objspace_limit_slots()
- * objspace_free_num() -> objspace_free_slots()
-
-Mon Nov 25 04:03:12 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat): add internal information.
- * heap_swept_slot
- * malloc_increase
- * malloc_limit
- * remembered_shady_object
- * remembered_shady_object_limit
- * old_object
- * old_object_limit
- * oldmalloc_increase
- * oldmalloc_limit
-
- * gc.c (gc_stat): rename names.
- * heap_live_num -> heap_live_slot
- * heap_free_num -> heap_free_slot
- * heap_final_slot -> heap_final_slot
-
- Quote from RDoc of GC.stat():
- "The contents of the hash are implementation specific and may
- be changed in the future."
-
- * test/ruby/test_gc.rb: catch up this change.
-
-Mon Nov 25 03:59:45 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_gc.rb: catch up last commit.
- Now RUBY_GC_OLDSPACE_LIMIT(...) is RUBY_GC_OLDMALLOC_LIMIT(...).
-
-Mon Nov 25 03:10:46 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: change terminology OLDSPACE -> OLDMALLOC.
- (oldspace -> oldmalloc for variable names)
-
- OLDSPACE is confusing because it is not includes slots.
- To more clearly, rename such as (oldspace_limit -> oldmalloc_limit).
- It is clear that it measures (estimates) malloc()'ed size.
-
-Mon Nov 25 00:50:03 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * internal.h: use __builtin_bswap16() if possible.
-
- * configure.in: check existence of __builtin_bswap16().
-
-Sun Nov 24 22:24:19 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigxor_int): Apply BIGLO for long in a BDIGIT expression.
- (bigor_int): Ditto.
- (bigand_int): Ditto.
-
-Sun Nov 24 18:13:23 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/defines.h (SIZEOF_ACTUAL_BDIGIT): Defined.
-
- * include/ruby/ruby.h (RBIGNUM_EMBED_LEN_MAX): Use
- SIZEOF_ACTUAL_BDIGIT instead of SIZEOF_BDIGITS.
- SIZEOF_BDIGITS can be different to sizeof(BDIGIT).
-
-Sun Nov 24 13:49:08 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/defines.h: Don't use int128_t for Bignum.
- It's not always faster.
-
- * bignum.c: Ditto.
-
-Sun Nov 24 10:18:15 2013 Aman Gupta <ruby@tmm1.net>
-
- * NEWS: Add details about new debugging features and APIs.
-
-Sun Nov 24 09:37:20 2013 Andrew Vit <andrew@avit.ca>
-
- * lib/csv.rb: Optimize header hashes by freezing string keys.
- [ruby-core:58510]
-
-Sun Nov 24 09:18:06 2013 Aman Gupta <ruby@tmm1.net>
-
- * ext/objspace/objspace_dump.c (dump_object): Use PRIuSIZE to print
- size_t for better win32 compatibility.
- * test/objspace/test_objspace.rb (test_dump_all): Hold reference to
- test string to avoid failure due to GC. Reduce size of failure message
- using grep(/TEST STRING/).
-
-Sun Nov 24 08:38:00 2013 Kyle Stevens <kstevens715@gmail.com>
-
- * lib/csv.rb: If skip_lines is set to a String, convert it to a Regexp
- to prevent the alternative, which is that each line in the CSV gets
- converted to a Regexp when calling skip_lines#match.
-
-Sun Nov 24 01:03:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_power): Use FIX2LONG instead
- of FIX2INT to avoid conversion error.
-
-Sun Nov 24 00:44:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (RBIGNUM_EMBED_LEN_MAX): define by macros
- defined in defines.h, instead of complex and repeated expression.
-
-Sat Nov 23 22:22:26 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/ruby.h (RBIGNUM_EMBED_LEN_MAX): Limit the value to
- less than 8.
-
-Sat Nov 23 19:52:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/lib/bigdecimal/math.rb (BigMath.E): Use BigMath.exp.
- [Feature #6857] [ruby-core:47130]
-
-Sat Nov 23 19:46:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigMath_s_exp): Optimize the
- calculation algorithm to reduce the number of divisions.
- This optimization was proposed by Rafal Michalski.
- [Feature #6857] [ruby-core:47130]
-
-Sat Nov 23 19:20:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_div2): The signature was
- changed to allow us to pass arguments directly.
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_div3): Added for the role of
- the old BigDecimal_div2.
-
-Sat Nov 23 12:31:00 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: fix global variable name.
- Now we have following environments (and related variable names).
-
- * RUBY_GC_HEAP_INIT_SLOTS
- * RUBY_GC_HEAP_FREE_SLOTS
- * RUBY_GC_HEAP_GROWTH_FACTOR (new from 2.1)
- * RUBY_GC_HEAP_GROWTH_MAX_SLOTS (new from 2.1)
-
- * obsolete
- * RUBY_FREE_MIN -> RUBY_GC_HEAP_FREE_SLOTS (from 2.1)
- * RUBY_HEAP_MIN_SLOTS -> RUBY_GC_HEAP_INIT_SLOTS (from 2.1)
-
- * RUBY_GC_MALLOC_LIMIT
- * RUBY_GC_MALLOC_LIMIT_MAX (new from 2.1)
- * RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR (new from 2.1)
-
- * RUBY_GC_OLDSPACE_LIMIT (new from 2.1)
- * RUBY_GC_OLDSPACE_LIMIT_MAX (new from 2.1)
- * RUBY_GC_OLDSPACE_LIMIT_GROWTH_FACTOR (new from 2.1)
-
- * test/ruby/test_gc.rb: catch up this change.
-
-Sat Nov 23 09:45:49 2013 Aman Gupta <ruby@tmm1.net>
-
- * marshal.c (w_object): Use HASH_PROC_DEFAULT directly from internal.h
-
-Sat Nov 23 08:43:23 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c: Rename heap_pages_swept_num to heap_pages_swept_slots to
- clarify meaning (number of slots, not pages).
-
-Sat Nov 23 08:23:23 2013 Aman Gupta <ruby@tmm1.net>
-
- * lib/set.rb (class SortedSet): Fix source_location for methods
- defined via eval.
-
-Sat Nov 23 03:44:03 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master dcce4ff. Important changes
- in this commit:
-
- Remove automatic detection of gem dependencies files. This prevents a
- security hole as described in [ruby-core:58490]
-
- Fixed bugs for installing git gems.
-
- * test/rubygems: ditto.
-
-Fri Nov 22 22:30:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_power):
- Round the result value only if the precision is given.
-
-Fri Nov 22 17:20:50 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * transcode.c (str_transcode0): don't scrub invalid chars if
- str.encode doesn't have explicit invalid: :replace.
- workaround fix for see #8995
-
-Fri Nov 22 17:11:26 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * include/ruby/intern.h, internal.h: Expose rb_gc_count().
-
-Fri Nov 22 17:07:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.gemspec: version 1.2.2.
-
-Fri Nov 22 17:04:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_data_type):
- Use RUBY_TYPED_FREE_IMMEDIATELY only if it is available.
-
-Fri Nov 22 16:49:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_power): Round the result value.
- [Bug #8818] [ruby-core:56802]
-
- * test/bigdecimal/test_bigdecimal.rb: Add a test for the above fix.
-
-Fri Nov 22 16:25:43 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (heap_set_increment): accept minimum additional page number.
-
- * gc.c (gc_after_sweep): allocate pages to allocate at least
- RUBY_HEAP_MIN_SLOTS.
- [Bug #9137]
-
-Fri Nov 22 16:19:52 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * include/ruby/intern.h (rb_gc_set_params): Deprecate
- rb_gc_set_params because it's only used in ruby internal.
-
- * internal.h (ruby_gc_set_params): Declare rb_gc_set_params's
- alias function.
-
- * gc.c: ditto.
-
- * ruby.c: use ruby_gc_set_params.
-
-Fri Nov 22 14:55:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigMath_s_exp): Insert rb_thread_check_ints.
-
-Fri Nov 22 14:35:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigMath_s_exp): Fix the inserting points
- of RB_GC_GUARDs.
-
-Fri Nov 22 14:31:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c: Fix indentation.
-
-Fri Nov 22 14:03:00 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/nkf: merge nkf 2.1.3 2a2f2c5.
-
-Fri Nov 22 12:43:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * util.c (ruby_strtod): ignore too long fraction part, which does not
- affect the result.
-
-Fri Nov 22 12:17:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/openssl/lib/openssl/buffering.rb (OpenSSL::Buffering#initialize):
- initialize of a module should pass arguments to super.
-
-Fri Nov 22 12:02:58 2013 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_settracefunc.rb: Ignore events from other threads.
-
-Fri Nov 22 10:35:57 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm.c (ruby_vm_destruct): do not use ruby_xfree() after freeing
- objspace.
-
- * gc.c (ruby_mimfree): added. It is similar to ruby_mimmalloc().
-
- * internal.h: ditto.
-
-Fri Nov 22 09:42:35 2013 Zachary Scott <e@zzak.io>
-
- * test/digest/test_digest.rb: Reverse order of assert_equal
- Reported by @splattael
-
-Fri Nov 22 09:03:16 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * gc.c: fix build failure on FreeBSD introduced by r43763.
- malloc_usable_size() is defined by malloc_np.h on FreeBSD.
-
- * configure.in: check malloc.h and malloc_np.h.
-
-Fri Nov 22 08:27:13 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 50a8210. Important changes
- in this commit:
-
- RubyGems now automatically checks for gem.deps.rb or Gemfile when
- running ruby executables. This behavior is similar to `bundle exec
- rake`. This change may be reverted before Ruby 2.1.0 if too many bugs
- are found.
-
- * test/rubygems: ditto.
-
-Thu Nov 21 22:33:59 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: RGENGC_CHECK_MODE should be 0.
-
-Thu Nov 21 21:40:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (VpAlloc): Fix the expr to adjust the size
- of the digit array.
-
-Thu Nov 21 21:36:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_sqrt): Fix the precision of
- the result BigDecimal of sqrt.
- [Bug #5266] [ruby-dev:44450]
-
- * test/bigdecimal/test_bigdecimal.rb: add tests for the above changes.
-
-Thu Nov 21 18:49:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (vm_xrealloc, vm_xfree): use malloc_usable_size() to obtain old
- size if available.
-
-Thu Nov 21 18:47:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/delegate.rb (SimpleDelegator#__getobj__): target object must be set.
-
- * lib/delegate.rb (DelegateClass#__getobj__): ditto.
-
-Thu Nov 21 18:28:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/tempfile.rb (Tempfile#initialize): use class method to get rid
- of warnings when $VERBOSE.
-
-Thu Nov 21 17:43:29 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename initial_xxx variables to gc_params.xxx.
- They are not only used initial values.
-
- Chikanaga-san: Congratulations on RubyPrize!
-
-Thu Nov 21 17:16:00 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: enable "RGENGC_ESTIMATE_OLDSPACE" option as default.
- Without this option, some application consumes huge memory.
- (and there are only a few performance down)
-
- Introduced new environment variables:
- * RUBY_GC_HEAP_OLDSPACE (default 16MB)
- * RUBY_GC_HEAP_OLDSPACE_MAX (default 128 MB)
- * RUBY_GC_HEAP_OLDSPACE_GROWTH_FACTOR (default 1.2)
-
- * gc.c (initial_malloc_limit): rename to initial_malloc_limit_min.
-
-Thu Nov 21 16:51:34 2013 Zachary Scott <e@zzak.io>
-
- * ext/digest/bubblebabble/bubblebabble.c: Teach RDoc digest/bubblebabble
-
-Thu Nov 21 16:50:16 2013 Zachary Scott <e@zzak.io>
-
- * test/digest/test_digest.rb: Add more tests for digest/bubblebabble
-
-Thu Nov 21 16:32:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/delegate.rb (Delegator#method_missing): try private methods defined in
- Kernel after the target. [Fixes GH-449]
-
-Thu Nov 21 16:25:08 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * test/uri/test_generic.rb (URI#test_merge): Test uri + URI(path)
- in addition to uri + path.
-
-Thu Nov 21 15:36:08 2013 Zachary Scott <e@zzak.io>
-
- * ext/openssl/lib/openssl/buffering.rb: [DOC] Fix HEREDOC comment for
- OpenSSL::Buffering which breaks overview because of RDoc bug
-
-Thu Nov 21 14:46:57 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * eval_intern.h (SAVE_ROOT_JMPBUF): workaround for the failure of
- test/ruby/test_exception.rb on Windows.
- wrap by __try and __exception statements on mswin to raise SIGSEGV
- when EXCEPTION_STACK_OVERFLOW is occurred, because MSVCRT doesn't
- handle the exception.
- however, (1) mingw-gcc doesn't support __try and __exception
- statements, and (2) we cannot retry SystemStackError after this
- change yet (maybe crashed) because SEH and longjmp() are too
- uncongenial.
-
- * signal.c (check_stack_overflow, CHECK_STACK_OVERFLOW): now defined on
- Windows, too.
-
- * thread_win32.c (ruby_stack_overflowed_p): ditto.
-
-Thu Nov 21 14:18:24 2013 Zachary Scott <e@zzak.io>
-
- * object.c: [DOC] Clarify Object#dup vs #clone [Bug #9128]
- Moving existing doc for this comparison to separate section of #dup
- Adding examples to document behavior of #dup with Module#extend.
- Based on a patch by stevegoobermanhill
-
-Thu Nov 21 14:06:02 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_marks_check): do not dump all refs.
-
- * gc.c (allrefs_dump_i): fix output format.
-
-Thu Nov 21 13:43:07 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: change RGENGC_CHECK_MODE (>= 2) logic.
- Basically, make an object graph of all of living objects before and
- after marking and check status.
-
- [Before marking: check WB sanity]
- If there is a non-old object `obj' pointed from old object
- (`parent') then `parent' or `obj' should be remembered.
-
- [After marking: check marking miss]
- Traversible objects with the object graph should be marked.
- (However, this alert about objects pointed by machine context
- can be false positive. We only display alert.)
-
- [Implementation memo]
- objspace_allrefs() creates an object graph.
- The object graph is represented by st_table, key is object (VALUE)
- and value is referring objects. Referring objects are stored by
- "struct reflist".
-
- * gc.c (init_mark_stack): do not use push_mark_stack_chunk() at init.
- This pre-allocation causes failure on is_mark_stack_empty()
- without any pushing.
-
-Thu Nov 21 13:40:20 2013 Zachary Scott <e@zzak.io>
-
- * lib/observer.rb: [DOC] Clarify default observer method.
- By @edward [Fixes GH-450] https://github.com/ruby/ruby/pull/450
-
-Thu Nov 21 13:32:53 2013 Zachary Scott <e@zzak.io>
-
- * ext/openssl/ossl_engine.c: [DOC] Documentation for OpenSSL::Engine
- This patch is based off work by @vbatts in GH-436 completing the
- documentation for this class and its methods.
- https://github.com/ruby/ruby/pull/436
-
-Thu Nov 21 10:45:22 2013 Zachary Scott <e@zzak.io>
-
- * ext/openssl/lib/openssl/buffering.rb: Remove unused arguments from
- OpenSSL::Buffering.new [Fixes GH-445]
-
-Thu Nov 21 10:30:47 2013 Zachary Scott <e@zzak.io>
-
- * test/digest/test_digest.rb: Add test for Digest::SHA256.bubblebabble
-
-Wed Nov 20 20:54:01 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * tool/instruction.rb : fix typo.
-
-Wed Nov 20 19:45:22 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c (rand_init): Make it possible to specify arbitrary array
- for init_genrand().
-
-Wed Nov 20 17:34:13 2013 Koichi Sasada <ko1@atdot.net>
-
- * parse.y (rb_gc_mark_symbols): set global_symbols.minor_marked only
- when full_mark is 0.
- rb_gc_mark_symbols() (with full_mark == 1) can be called by other
- than GC (such as rb_objspace_reachable_objects_from_root()).
-
-Wed Nov 20 11:46:38 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/json: merge JSON 1.8.1.
- https://github.com/nurse/json/compare/002ac2771ce32776b32ccd2d06e5604de6c36dcd...e09ffc0d7da25d0393873936c118c188c78dbac3
- * Remove Rubinius exception since transcoding should be working now.
- * Fix https://github.com/flori/json/issues/162 reported by Marc-Andre
- Lafortune <github_rocks@marc-andre.ca>. Thanks!
- * Applied patches by Yui NARUSE <naruse@airemix.jp> to suppress
- warning with -Wchar-subscripts and better validate UTF-8 strings.
- * Applied patch by ginriki@github to remove unnecessary if.
- * Add load/dump interface to JSON::GenericObject to make
- serialize :some_attribute, JSON::GenericObject
- work in Rails active models for convenient
- SomeModel#some_attribute.foo.bar access to serialised JSON data.
-
-Wed Nov 20 01:39:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/rdoc/constant.rb (RDoc::Constant#documented?): workaround for
- NoMethodError when the original of alias is not found.
-
-Tue Nov 19 23:38:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (--with-os-version-style): option to transform target
- OS version string.
-
-Tue Nov 19 21:27:33 2013 Tanaka Akira <akr@fsij.org>
-
- * test/net/http/utils.rb (spawn_server): Specify zero for port to
- avoid reusing an allocated port.
-
- * test/net/http/test_http.rb: Don't specify port here.
-
- * test/net/http/test_https.rb: Ditto.
-
-Tue Nov 19 18:52:10 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (heap_is_swept_object): use heap_page::before_sweep flag.
-
-Tue Nov 19 18:49:32 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_objspace_reachable_objects_from_root): do major marking.
-
-Tue Nov 19 18:45:40 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_gc_resurrect): added.
- rb_fstring() used rb_gc_mark() to avoid freeing used string.
- However, rb_gc_mark() set mark bit *and* pushes mark_stack.
- rb_gc_resurrect() does only set mark bit if it is before sweeping.
-
- * string.c (rb_fstring): use rb_gc_resurrect.
-
- * internal.h: add decl.
-
-Tue Nov 19 09:47:02 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rdoc: Update to RDoc master a1195ce. Changes include:
-
- Improved accessibility of the main sidebar navigation.
-
- Fixed handling of regexp options in HTML source highlighting.
-
- * test/rdoc: ditto.
-
-Tue Nov 19 09:33:52 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 6a3d9f9. Changes include:
-
- Compatibly renamed Gem::DependencyResolver to Gem::Resolver.
-
- Added support for git gems in gem.deps.rb and Gemfile.
-
- Fixed resolver bugs.
-
- * test/rubygems: ditto.
-
- * lib/rubygems/LICENSE.txt: Updated to license from RubyGems trunk.
- [ruby-trunk - Bug #9086]
-
- * lib/rubygems/commands/which_command.rb: RubyGems now indicates
- failure when any file is missing. [ruby-trunk - Bug #9004]
-
- * lib/rubygems/ext/builder: Extensions are now installed into the
- extension install directory and the first directory in the require
- path from the gem. This allows backwards compatibility with msgpack
- and other gems that calculate full require paths.
- [ruby-trunk - Bug #9106]
-
-
-Tue Nov 19 07:21:56 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in (LOCALTIME_OVERFLOW_PROBLEM): Define it for cross
- compiling.
- [ruby-core:58391] [Bug #9119] Reported by Luis Lavena.
- Analyzed by Heesob Park.
-
-Tue Nov 19 05:55:05 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rdoc/rubygems_hook.rb: Remove debugging puts committed by
- accident.
-
-Mon Nov 18 22:47:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval_intern.h (TH_PUSH_TAG, TH_EXEC_TAG): refine stack overflow
- detection. chain local tag after setjmp() successed on it, because
- calling setjmp() also can overflow the stack.
- [ruby-dev:47804] [Bug #9109]
-
- * vm_eval.c (rb_catch_obj): now th->tag points previous tag until
- TH_EXEC_TAG().
-
- * thread_pthread.c (ruby_init_stack): set stack_start properly by
- get_main_stack() if possible.
-
-Mon Nov 18 22:45:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval_jump.c (rb_exec_end_proc): unlink and free procs data before
- calling for each procs. [Bug #9110]
-
-Sun Nov 17 06:33:32 2013 Shota Fukumori <her@sorah.jp>
-
- * configure.in: Use $LIBS for base of $SOLIBS, also in darwin.
- By this fix, environment that libgmp is located in $LIBS can build
- ruby.
-
-Sun Nov 17 01:56:32 2013 Tanaka Akira <akr@fsij.org>
-
- * thread_pthread.c (rb_thread_create_timer_thread): Show error
- message instead of error number.
- (thread_create_core): Ditto.
-
- * cont.c (fiber_machine_stack_alloc): Ditto.
-
-Sat Nov 16 18:28:08 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/ultralightparser.rb
- (REXML::Parsers::UltraLightParser#parse): Fix wrong :start_doctype
- position.
- [Bug #9061] [ruby-dev:47778]
- Patch by Ippei Obayashi. Thanks!!!
-
- * test/rexml/parser/test_ultra_light.rb: Add a test for this case.
-
-Sat Nov 16 02:13:56 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * cont.c : Introduce ensure rollback mechanism. Please see below.
-
- * internal.h (ruby_register_rollback_func_for_ensure): catch up above change.
- Add rollback mechanism API.
-
- * vm_core.h (typedef struct rb_vm_struct): catch up above change.
- Introduce ensure-rollback relation table.
-
- * vm_core.h (typedef struct rb_thread_struct): catch up above change.
- Introduce ensure stack.
-
- * eval.c (rb_ensure): catch up above change.
- Introduce ensure stack.
-
- * hash.c : New function for rollback ensure, and register it to
- ensure-rollback relation table. [ruby-dev:47803] [Bug #9105]
-
- Ensure Rollback Mechanism:
- A rollback's function is a function to rollback a state before ensure's
- function execution.
- When the jump of callcc is across the scope of rb_ensure,
- ensure's functions and rollback's functions are executed appropriately
- for keeping consistency.
-
- Current API is unstable, and only internal use.
-
- ruby_register_rollback_func_for_ensure(ensure_func,rollback_func)
- This API create relation ensure's function to rollback's function.
- By registered rollback's function, it is executed When jumping into
- corresponding rb_ensure scope.
-
-Sat Nov 16 00:18:36 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * eval_jump.c (rb_exec_end_proc): fix double free or corruption error
- when reentering by callcc. [ruby-core:58329] [Bug #9110]
-
- * test/ruby/test_beginendblock.rb: test for above.
-
-Fri Nov 15 01:06:04 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/objspace/objspace_dump.c (dump_output): allow IO object as
- output, and use Tempfile.create and return open file instead of
- mkstemp() and path name for :file output.
- [ruby-core:58266] [Bug #9102]
-
- * test/objspace/test_objspace.rb (TestObjSpace#dump_my_heap_please):
- remove temporary output file.
-
-Thu Nov 14 23:39:00 2013 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * ext/bigdecimal/lib/bigdecimal/util.rb: [DOC] remove example of
- Rational#to_d without argument. [Bug #8958]
-
-Thu Nov 14 20:24:15 2013 Naohisa Goto <ngotogenome@gmail.com>
-
- * ruby_atomic.h (ATOMIC_SIZE_CAS): fix compile error on Solaris
- since r43460.
-
-Thu Nov 14 19:53:00 2013 Tanaka Akira <akr@fsij.org>
-
- * test/openssl/test_cipher.rb (test_aes_gcm_wrong_tag): Don't use
- String#succ because it can make modified (wrong) auth_tag longer
- than 16 bytes. The longer auth_tag makes that
- EVP_CIPHER_CTX_ctrl (and internally aes_gcm_ctrl) fail.
- [ruby-core:55143] [Bug #8439] reported by Vit Ondruch.
-
-Thu Nov 14 11:33:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (foreach_safe_i, hash_foreach_iter): deal with error detected
- by ST_CHECK.
-
- * st.c (st_foreach_check): call with non-error argument in normal case.
-
-Thu Nov 14 02:37:14 2013 Zachary Scott <e@zzak.io>
-
- * ext/thread/thread.c: [DOC] This patch accomplishes the following:
-
- - Teach RDoc about ConditionVariable
- - Teach RDoc about Queue
- - Teach RDoc about SizedQueue
- - Use fully-qualified namespace for Document-method
- This is necessary to separate definitions between classes
- - Fix rdoc bug in call_seq vs. call-seq
- - Correct doc for SizedQueue#pop patch by @jackdanger [Bug #8988]
-
-Thu Nov 14 01:11:54 2013 Zachary Scott <e@zzak.io>
-
- * ext/bigdecimal/lib/bigdecimal/util.rb: [DOC] +precision+ is required
-
-Wed Nov 13 19:21:36 2013 Zachary Scott <e@zzak.io>
-
- * ext/bigdecimal/lib/bigdecimal/util.rb: [DOC] Document the required
- +precision+ argument for Rational#to_d [Bug #8958]
-
-Wed Nov 13 19:02:05 2013 Zachary Scott <e@zzak.io>
-
- * ext/digest/*: [DOC] Fix several typos and broken http links.
- Improved examples for Digest overview and fixed a broken example in
- Digest::HMAC overview. This patch also adds a description of
- Digest::SHA256.bubblebabble to the Digest overview.
-
- Patched by @stomar [Bug #9027]
-
-Wed Nov 13 18:32:12 2013 Zachary Scott <e@zzak.io>
-
- * ext/openssl/ossl_config.c: [DOC] Document the following:
-
- - OpenSSL::ConfigError
- - OpenSSL::Config::DEFAULT_CONFIG_FILE
-
- Patched by @vbatts via GH-436
- https://github.com/ruby/ruby/pull/436
-
-Wed Nov 13 18:03:00 2013 Zachary Scott <e@zzak.io>
-
- * ext/openssl/ossl_asn1.c: [DOC] Document parts of
- OpenSSL::ASN1::ObjectId included a fix for the class overview, which
- previously showed the documentation for Constructive due to missing
- ObjectId overview. This patch also includes a note for Primitive.
-
- Based on a patch by @vbatts via GH-436
- https://github.com/ruby/ruby/pull/436
-
-Wed Nov 13 17:19:36 2013 Zachary Scott <e@zzak.io>
-
- * ext/openssl/lib/openssl/config.rb: In #parse use +string+ for +str+
-
-Wed Nov 13 17:09:45 2013 Zachary Scott <e@zzak.io>
-
- * ext/openssl/lib/openssl/*.rb: [DOC] Document the following:
-
- - Integer#to_bn
- - OpenSSL::Buffering module
- - Deprecated OpenSSL::Digest::Digest compatibility class
- - OpenSSL::Config
-
- These changes were based on a patch by @vbatts via GH-436
- https://github.com/ruby/ruby/pull/436
-
-Wed Nov 13 10:55:43 2013 Zachary Scott <e@zzak.io>
-
- * doc/regexp.rdoc: [DOC] Fix typo in Special global variables section.
- Reported by Alex Johnson on ruby-doc.org
-
-Wed Nov 13 10:43:19 2013 Zachary Scott <e@zzak.io>
-
- * hash.c: [DOC] Adds an example for Hash#store
-
-Wed Nov 13 09:03:40 2013 Zachary Scott <e@zzak.io>
-
- * doc/regexp.rdoc: [DOC] add note about Bug #4044 as suggested by
- duerst-san in [ruby-core:43612] [Fixes GH-443] Patched by @rosenfeld
- https://github.com/ruby/ruby/pull/443
-
-Tue Nov 12 10:15:14 2013 Eric Hodel <drbrain@segment7.net>
-
- * test/rubygems/insure_session.rb: Remove unused test file.
-
-Tue Nov 12 09:16:24 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master b9213d7. Changes include:
-
- Fixed tests on Windows (I hope) by forcing platform for
- platform-dependent tests.
-
- Fixed File.exists? warnings.
-
- Improved testing infrastructure.
-
- * test/rubygems: ditto.
-
- * test/rdoc/test_rdoc_rubygems_hook.rb: Switch to util_spec like
- RubyGems.
-
-Mon Nov 11 18:31:12 2013 Aman Gupta <ruby@tmm1.net>
-
- * internal.h: move common string/hash flags to include file.
- * ext/objspace/objspace_dump.c: remove flags shared above.
- * hash.c: ditto.
- * string.c: ditto.
-
-Mon Nov 11 04:36:14 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/specification.rb: Include 2.2.0.preview.2 when checking
- if extensions should be built. Fixes a ruby-ci failure.
- * test/rubygems/test_gem_specification.rb: Test for the above.
-
-Mon Nov 11 03:15:56 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_trace.c (symbol2event_flag): add secret feature.
- add a_call/a_return events.
- a_call is call | b_call | c_call, and same as a_return.
-
-Mon Nov 11 02:51:17 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 4bdc4f2. Important changes
- in this commit:
-
- RubyGems now chooses the test server port reliably. Patch by akr.
-
- Partial implementation of bundler's Gemfile format.
-
- Refactorings to improve the new resolver.
-
- Fixes bugs in the resolver.
-
- * test/rubygems: Tests for the above.
-
-Mon Nov 11 01:02:06 2013 Zachary Scott <e@zzak.io>
-
- * lib/timeout.rb: [DOC] Add note about change from #8730 [Fixes GH-440]
- * NEWS: [DOC] Improve grammar on change to Timeout
- Patched by @srawlins in https://github.com/ruby/ruby/pull/440
-
-Sun Nov 10 23:47:05 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * gc.c (rb_gcdebug_print_obj_condition): catch up recent changes
- to compile on GC_DEBUG.
-
-Sun Nov 10 22:16:19 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (exc_cause): captured previous exception.
-
- * eval.c (make_exception): capture previous exception automagically.
- [Feature #8257]
-
-Sun Nov 10 08:37:20 2013 Zachary Scott <e@zzak.io>
-
- * thread.c: [DOC] Remove duplicate reference
-
-Sun Nov 10 08:09:29 2013 Zachary Scott <e@zzak.io>
-
- * lib/drb/drb.rb: [DOC] promote better windows-safe filename regular
- expression in DRb Logger example. Reported by Chris Pheonix
- [Bug #9074]
-
-Sun Nov 10 08:03:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (rb_define_finalizer, rb_undefine_finalizer): rename and export
- finalizer functions.
-
-Sun Nov 10 07:41:22 2013 Zachary Scott <e@zzak.io>
-
- * lib/weakref.rb: [DOC] fix typos by @xaviershay [Fixes GH-439]
- https://github.com/ruby/ruby/pull/439
-
-Sun Nov 10 06:14:39 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * compile.c (iseq_compile_each): emit opt_str_freeze if the #freeze
- method is called on a static string literal with no arguments.
-
- * defs/id.def (firstline): add freeze so idFreeze is available
-
- * insns.def (opt_str_freeze): add opt_str_freeze instruction which
- pushes a frozen string literal without allocating a new object if
- String#freeze is not overridden
-
- * string.c (Init_String): define String#freeze
-
- * vm.c (vm_init_redefined_flag): define BOP_FREEZE on String class as
- a basic operation
-
- * vm_insnhelper.h: ditto
-
- [Feature #8992] [ruby-core:57705]
-
-Sun Nov 10 01:34:14 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (vm_malloc_increase): sweep immediately on GC due to malloc().
- To reduce memory usage, sweep as soon as possible.
- This behavior is same as Ruby 2.0.0 and before.
-
-Sun Nov 10 00:39:26 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/gc/gcbench.rb: output version description and GC::OPTS.
-
-Sun Nov 10 00:36:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (should_be_callable): allow private call since rb_eval_cmd
- calls even private methods.
-
-Sun Nov 10 00:33:17 2013 Zachary Scott <e@zzak.io>
-
- * lib/racc/rdoc/grammar.en.rdoc: [DOC] fix typo by Tsuyoshi Sawada
- [Bug #9077]
-
-Sat Nov 9 22:35:35 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/rbinstall.rb (Gem::Specification.load): obtain spec date from
- VCS for the case using git, RUBY_RELEASE_DATE is the last resort.
- probably fixes [Bug #9085].
-
-Sat Nov 9 20:56:12 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * ext/objspace/object_tracing.c: use declarations in internal.h.
-
- * ext/objspace/objspace.c: ditto
-
-Sat Nov 9 20:32:59 2013 Tanaka Akira <akr@fsij.org>
-
- * test/objspace/test_objspace.rb (test_dump_all): Make the test string
- shorter to be an embedded string on 32bit environment as well as
- 64bit environment.
-
-Sat Nov 9 15:00:16 2013 Zachary Scott <e@zzak.io>
-
- * io.c: [DOC] ARGF.gets may return nil [Bug #9029] patch by znz
-
-Sat Nov 9 14:54:52 2013 Zachary Scott <e@zzak.io>
-
- * lib/rss/*: [DOC] document various constants @steveklabnik [Bug #8812]
-
-Sat Nov 9 14:50:09 2013 Zachary Scott <e@zzak.io>
-
- * lib/rss/rss.rb: [DOC] document Time#w3cdtf by @steveklabnik
- [Bug #8821]
-
-Sat Nov 9 14:29:04 2013 Zachary Scott <e@zzak.io>
-
- * ext/dl/cfunc.c: [DOC] fix typo in example [Bug #8944]
- Patched by Heesob Park
-
-Sat Nov 9 13:59:58 2013 Zachary Scott <e@zzak.io>
-
- * lib/test/unit/assertions.rb: [DOC] better example for assert_send()
- Patch by Andrew Grimm [Bug #8975]
-
-Sat Nov 9 12:45:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * insns.def: unify ic_constant_serial and ic_class_serial into one field
- ic_serial. This is possible because these fields are only ever used
- exclusively with each other.
-
- * insns.def: ditto
- * vm_core.h: ditto
- * vm_insnhelper.c: ditto
-
-Sat Nov 9 12:31:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * class.c: unify names of vm state version counters to 'serial'.
- This includes renaming 'vm_state_version_t' to 'rb_serial_t',
- 'method_state' to 'method_serial', 'seq' to 'class_serial',
- 'vmstat' to 'constant_serial', etc.
-
- * insns.def: ditto
- * internal.h: ditto
- * vm.c: ditto
- * vm_core.h: ditto
- * vm_insnhelper.c: ditto
- * vm_insnhelper.h: ditto
- * vm_method.c: ditto
-
-Sat Nov 9 09:22:29 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (gc_page_sweep, rgengc_rememberset_mark): Refactoring.
- Get bitmaps directly.
-
-Sat Nov 9 09:16:36 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (RVALUE_PROMOTE_INFANT): Refactoring. Remove duplicated nonsense
- code.
-
-Sat Nov 9 09:04:48 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (gc_marks_test): Bugfix. Fix a struct member name for build
- with RGENGC_CHECK_MODE.
-
-Sat Nov 9 08:58:23 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c : Add GC_PROFILE_DETAIL_MEMORY option.
- If GC_PROFILE_MORE_DETAIL && GC_PROFILE_DETAIL_MEMORY,
- maxrss, minflt and majflt are added to each profile record.
-
-Sat Nov 9 07:41:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * internal.h (rb_vm_backtrace_object, rb_gc_count): make prototype
- declarations, not old-K&R style.
-
-Sat Nov 9 06:11:14 2013 vo.x (Vit Ondruch) <vondruch@redhat.com>
-
- * tool/rbinstall.rb (Gem::Specification#collect): make stable
- Gem::Specification.files in default .gemspecs the different order of
- "files" in .gemspec files makes them different therefore possibly
- conflicting in multilib scenario. patch by vo.x (Vit Ondruch) at
- [ruby-core:57544] [Bug #8623].
-
-Sat Nov 9 01:59:18 2013 Aman Gupta <ruby@tmm1.net>
-
- * ext/objspace/objspace_dump.c: Add experimental methods to
- dump objectspace as json: ObjectSpace.dump_all and
- ObjectSpace.dump(obj). These methods are useful for debugging
- reference leaks and memory growth in large ruby applications.
- [Bug #9026] [ruby-core:57893] [Fixes GH-423]
- * test/objspace/test_objspace.rb: tests for above.
-
-Sat Nov 9 00:26:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (GetLastError): already defined in windows.h on nowadays
- cygwin, and caused the confliction with the system provided
- definition on cygwin64. by @kou1okada [Fixes GH-433].
-
-Fri Nov 8 18:35:31 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * lib/open3.rb: receive arguments as keyword arguments.
-
-Fri Nov 8 13:19:26 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * io.c (rb_io_open_with_args): use RARRAY_CONST_PTR().
-
- * io.c (rb_scan_open_args): use const qualifier for above.
-
- * io.c (rb_open_file): ditto.
-
- * io.c (rb_io_open_with_args): ditto.
-
-Fri Nov 8 11:35:06 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * dir.c, pack.c, ruby.c, struct.c, vm_eval.c: use RARRAY_CONST_PTR().
-
-Fri Nov 8 10:58:02 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * compile.c (iseq_build_from_ary_exception): use RARRAY_CONST_PTR().
-
- * compile.c (iseq_build_from_ary_body): ditto.
-
-Fri Nov 8 10:49:34 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * enumerator.c (append_method): use RARRAY_CONST_PTR().
-
- * enumerator.c (lazy_init_iterator): ditto.
-
-Fri Nov 8 02:44:29 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (vm_malloc_increase): check GVL before gc_rest_sweep().
- vm_malloc_increase() can be called without GVL.
- However, gc_rest_sweep() assumes acquiring GVL.
- To avoid this problem, check GVL before gc_rest_sweep().
- [Bug #9090]
-
- This workaround introduces possibility to set malloc_limit as
- wrong value (*1). However, this may be rare case. So I commit it.
-
- *1: Without rest_sweep() here, gc_rest_sweep() can decrease
- malloc_increase due to ruby_sized_xfree().
-
-Fri Nov 8 02:50:25 2013 Zachary Scott <e@zzak.io>
-
- * lib/securerandom.rb: [DOC] specify arguments passed to ::random_bytes
- By @chastell [Fixes GH-412] https://github.com/ruby/ruby/pull/412
-
-Fri Nov 8 02:43:01 2013 Zachary Scott <e@zzak.io>
-
- * ext/objspace/object_tracing.c: [DOC] trace_object_allocations_stop
- By @srawlins [Fixes GH-421] https://github.com/ruby/ruby/pull/421
-
-Fri Nov 8 02:34:20 2013 Zachary Scott <e@zzak.io>
-
- * lib/net/ftp.rb: [DOC] Document Net::FTP.mdtm and .set_socket and fix
- spelling typo, based on patch by @artfuldodger [Fixes GH-426]
- https://github.com/ruby/ruby/pull/426
-
-Fri Nov 8 02:14:37 2013 Zachary Scott <e@zzak.io>
-
- * array.c: [DOC] Add note about negative indices in Array overview
- By @ckaenzig [Fixes GH-427] https://github.com/ruby/ruby/pull/427
-
-Fri Nov 8 02:09:12 2013 Zachary Scott <e@zzak.io>
-
- * lib/csv.rb: [DOC] Fix typo in CSV.parse_line by @funky-bibimbap
- [Fixes GH-430] https://github.com/ruby/ruby/pull/430
-
-Fri Nov 8 01:01:54 2013 Zachary Scott <e@zzak.io>
-
- * golf_prelude.rb: syntax formatting for whitespace [Fixes GH-425]
- Patch by @edward https://github.com/ruby/ruby/pull/425
-
-Thu Nov 7 19:36:09 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: modify malloc_limit strategy.
-
- * fix default values:
- GC_MALLOC_LIMIT_GROWTH_FACTOR
- GC_MALLOC_LIMIT: 8MB -> 16MB
- GC_MALLOC_LIMIT_MAX: 384MB -> 32MB
-
- * algorithm of malloc_limit increment.
- if (malloc_increase < malloc_limit) {
- next_malloc_limit = malloc_limit * factor
- if (malloc_limit > malloc_limit_max) {
- malloc_limit = malloc_increase
- }
- }
- This algorithm change malloc_limit from
- 16MB -> 32MB slowly.
- If malloc_limit exceeds malloc_limit_max, then
- increase with malloc_increase.
-
-Thu Nov 7 11:06:05 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_shuffle_bang): use RARRAY_PTR_USE() without WB
- because there are not new relations.
-
-Thu Nov 7 10:34:12 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_sample): use rb_ary_dup().
-
-Thu Nov 7 09:39:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_trace.c (rb_threadptr_exec_event_hooks_orig): errinfo should not
- be propagated to trace blocks so that no argument raise does not
- throw internal objects. [ruby-dev:47793] [Bug #9088]
-
-Wed Nov 6 21:30:55 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (gc_before_sweep): Change algorithm of malloc_limit to
- conservative for closing to memory consumption of ruby 2.0.
-
- * gc.c (GC_MALLOC_LIMIT, GC_MALLOC_LIMIT_GROWTH_FACTOR):
- Adjust parameters for new algorithm.
-
-Wed Nov 6 21:16:51 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_shift_m): use RARRAY_PTR_USE() without WB because
- there are not new relations.
-
-Wed Nov 6 21:05:20 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_reverse): use RARRAY_PTR_USE().
-
-Wed Nov 6 19:30:44 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * common.mk (help): add texts about gcbench.
-
-Wed Nov 6 16:32:32 2013 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/open3.rb: tweaked grammar in comments
-
-Wed Nov 6 11:46:36 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_sample): use RARRAY_AREF() and RARRAY_PTR_USE()
- instead of RARRAY_PTR().
-
-Wed Nov 6 10:37:07 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_and): defer hash creation and some refactoring.
-
-Wed Nov 6 09:14:31 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/bm_vm1_gc_short_lived.rb: added.
- These GC benchmarks do not reflect practical applications.
- They are only for tuning.
-
- * benchmark/bm_vm1_gc_short_with_complex_long.rb: added.
-
- * benchmark/bm_vm1_gc_short_with_long.rb: added.
-
- * benchmark/bm_vm1_gc_short_with_symbol.rb: added.
-
- * benchmark/bm_vm1_gc_wb_ary.rb: added.
-
- * benchmark/bm_vm1_gc_wb_obj.rb: added.
-
- * benchmark/bm_vm_thread_queue.rb: added.
- This benchmark is added to know how fast C version of thread.so.
-
-Wed Nov 6 09:13:32 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: define RGENGC_ESTIMATE_OLDSPACE == 0 if USE_RGENGC is 0.
-
-Wed Nov 6 07:13:18 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (Init_GC): add GC::OPTS to show options.
-
-Wed Nov 6 07:12:17 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/gc/gcbench.rb: add some options to make quiet.
-
-Wed Nov 6 04:14:25 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/to_ruby.rb: process merge keys before
- reviving objects. Fixes GH psych #168
- * test/psych/test_merge_keys.rb: test for change
- https://github.com/tenderlove/psych/issues/168
-
-Tue Nov 5 21:21:47 2013 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_thread.rb (test_thread_join_in_trap):
- Run the test in a different process.
-
-Tue Nov 5 20:14:32 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (is_live_object): A hidden object may be a live object.
- [ruby-dev:47788] [Bug #9072]
-
-Tue Nov 5 13:37:19 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: add support to estimate increase of oldspace memory usage.
- This is another approach to solve an issue discussed at r43530.
- This feature is disabled as default.
-
- This feature measures an increment of memory consumption by oldgen
- objects. It measures memory consumption for each objects when
- the object is promoted. However, measurement of memory consumption
- is not accurate now. So that this measurement is `estimation'.
-
- To implement this feature, move memsize_of() function from
- ext/objspace/objspace.c and expose rb_obj_memsize_of().
-
- Some memsize() functions for T_DATA (T_TYPEDDATA) have problem to
- measure memory size, so that we ignores T_DATA objects now.
- For example, some functions skip NULL check for pointer.
-
- The macro RGENGC_ESTIMATE_OLDSPACE enables/disables this feature,
- and turned off as default.
-
- We need to compare 3gen GC and this feature carefully.
- (it is possible to enable both feature)
- We need a help to compare them.
-
- * internal.h: expose rb_obj_memsize_of().
-
- * ext/objspace/objspace.c: use rb_obj_memsize_of() function.
-
- * cont.c (fiber_memsize): fix to check NULL.
-
- * variable.c (autoload_memsize): ditto.
-
- * vm.c (vm_memsize): ditto.
-
-Tue Nov 5 04:03:07 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (GC_MALLOC_LIMIT_MAX): fix default value 512MB -> 384MB.
- 512MB is huge.
-
-Tue Nov 5 03:31:23 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: add 3gen GC patch, but disabled as default.
-
- RGenGC is designed as 2 generational GC, young and old generation.
- Young objects will be promoted to old objects after one GC.
- Old objects are not collect until major (full) GC.
-
- The issue of this approach is some objects can promote as old
- objects accidentally and not freed until major GC.
- Major GC is not frequently so short-lived but accidentally becoming
- old objects are not freed.
-
- For example, the program "loop{Array.new(1_000_000)}" consumes huge
- memories because short lived objects (an array which has 1M
- elements) are promoted while GC and they are not freed before major
- GC.
-
- To solve this problem, generational GC with more generations
- technique is known. This patch implements three generations gen GC.
-
- At first, newly created objects are "Infant" objects.
- After surviving one GC, "Infant" objects are promoted to "Young"
- objects.
- "Young" objects are promoted to "Old" objects after surviving
- next GC.
- "Infant" and "Young" objects are collected if it is not marked
- while minor GC. So that this technique solves this problem.
-
- Representation of generations:
- * Infant: !FL_PROMOTED and !oldgen_bitmap [00]
- * Young : FL_PROMOTED and !oldgen_bitmap [10]
- * Old : FL_PROMOTED and oldgen_bitmap [11]
-
- The macro "RGENGC_THREEGEN" enables/disables this feature, and
- turned off as default because there are several problems.
- (1) Failed sometimes (Heisenbugs).
- (2) Performance down.
- Especially on write barriers. We need to detect Young or Old
- object by oldgen_bitmap. It is slower than checking flags.
-
- To evaluate this feature on more applications, I commit this patch.
- Reports are very welcome.
-
- This patch includes some refactoring (renaming names, etc).
-
- * include/ruby/ruby.h: catch up 3gen GC.
-
- * .gdbinit: fix to show a prompt "[PROMOTED]" for promoted objects.
-
-Tue Nov 5 00:05:51 2013 Koichi Sasada <ko1@atdot.net>
-
- * node.h: catch up comments for last commit.
-
-Tue Nov 5 00:02:00 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: rename FL_OLDGEN to FL_PROMOTED.
- This flag represents that "this object is promoted at least once."
-
- * gc.c, debug.c, object.c: catch up this change.
-
-Mon Nov 4 22:20:16 2013 Tanaka Akira <akr@fsij.org>
-
- * test/xmlrpc: Don't use fixed ports: 8070 and 8071.
-
-Mon Nov 4 15:25:52 2013 Tanaka Akira <akr@fsij.org>
-
- * test/xmlrpc/webrick_testing.rb (start_server): Initialize the server
- at main thread to fail early.
-
-Mon Nov 4 10:08:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval_intern.h (TH_EXEC_TAG, TH_JUMP_TAG): get rid of undefined
- behavior of setjmp() in rhs of assignment expression.
- [ISO/IEC 9899:1999] 7.13.1.1
-
-Sun Nov 3 23:06:51 2013 Tanaka Akira <akr@fsij.org>
-
- * sample/test.rb: Make temporary file names unique.
-
-Sun Nov 3 20:41:17 2013 Tanaka Akira <akr@fsij.org>
-
- * test/xmlrpc: Wrap definitions by TestXMLRPC module.
-
-Sun Nov 3 20:23:38 2013 Tanaka Akira <akr@fsij.org>
-
- * test/xmlrpc/webrick_testing.rb (stop_server): Don't try to shutdown
- the server if the server is not started.
-
-Sun Nov 3 09:35:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * load.c (rb_feature_p): deal with default loadable suffixes.
-
- * load.c (load_lock): initialize statically linked extensions.
-
- * load.c (search_required, rb_require_safe): deal with statically
- linked extensions.
-
- * load.c (ruby_init_ext): defer initialization of statically linked
- extensions until required actually. [Bug #8883]
-
-Sat Nov 2 15:14:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/logger.rb (Logger::LogDevice::LogDeviceMutex#lock_shift_log):
- open file can't be removed or renamed on Windows. [ruby-dev:47790]
- [Bug #9046]
-
- * test/logger/test_logger.rb (TestLogDevice#run_children): don't use
- fork.
-
-Sat Nov 2 07:08:43 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/logger.rb: Inter-process locking for log rotation
- Current implementation fails log rotation on multi process env.
- by sonots <sonots@gmail.com>
- https://github.com/ruby/ruby/pull/428 fix GH-428 [Bug #9046]
-
-Fri Nov 1 23:24:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (wmap_mark_map): mark live objects only, but delete zombies.
- [ruby-dev:47787] [Bug #9069]
-
-Fri Nov 1 22:45:54 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (struct heap_page, gc_page_sweep, gc_sweep): Refactoring for
- performance. Add before_sweep condition to heap_page structure.
-
- * gc.c (rb_gc_force_recycle): Use before_sweep member.
-
- * gc.c (heap_is_before_sweep, is_before_sweep): Remove. They have not
- already been used.
-
-Fri Nov 1 22:20:28 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (make_deferred): Refactoring. Collect codes which should be
- atomic.
-
- * gc.c (make_io_deferred, obj_free, rb_objspace_call_finalizer,
- gc_page_sweep): Correspond to the above.
-
-Fri Nov 1 21:40:35 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (typedef struct rb_objspace): Refactoring. Move some members
- into profile member.
-
- * gc.c (newobj_of): Correspond to the above.
-
- * gc.c (finalize_list): Ditto.
-
- * gc.c (objspace_live_num): Ditto.
-
- * gc.c (gc_page_sweep): Ditto.
-
- * gc.c (rb_gc_force_recycle): Ditto.
-
- * gc.c (garbage_collect_body): Ditto.
-
- * gc.c (rb_gc_count): Ditto.
-
- * gc.c (gc_stat): Ditto.
-
- * gc.c (gc_prof_set_heap_info): Ditto.
-
- * gc.c (gc_profile_dump_on): Ditto.
-
-Fri Nov 1 20:53:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_scrub): fix typo, should yield invalid byte
- sequence to be scrubbed. reported by znz at IRC.
-
-Fri Nov 1 17:25:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (is_live_object): finalizer may not run because of lazy-sweep.
- [ruby-dev:47786] [Bug #9069]
-
-Fri Nov 1 16:55:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_scrub): export with fixed length arguments, and
- allow nil as replacement string instead of omitting.
-
-Fri Nov 1 06:20:44 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread.c (rb_mutex_struct): reduce rb_mutex_t size by 8 bytes
- on 64bit platform. Patch by Eric Wong. [Feature #9068][ruby-core:58114]
-
-Fri Nov 1 01:08:33 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/gc/gcbench.rb: print HWM (high water mark) if possible.
-
-Thu Oct 31 21:48:31 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/streamparser.rb: Add dependency file require.
- [Bug #9062] [ruby-dev:47779]
- Reported by Ippei Obayashi. Thanks!!!
-
-Thu Oct 31 14:09:32 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_method.c (rb_method_entry_make): fix to pass an ISeq value.
- OBJ_WRITTEN() accepts only VALUE.
-
-Wed Oct 30 19:07:57 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-additional.el (ruby-brace-to-do-end)
- (ruby-do-end-to-brace, ruby-toggle-block): Remove functions that
- are already in the latest released version of Emacs (24.3).
- [Bug #7565]
-
-Wed Oct 30 12:44:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/Makefile.sub (config.status): add missing variables,
- PLATFORM_DIR and THREAD_MODEL.
-
-Wed Oct 30 12:20:32 2013 Tanaka Akira <akr@fsij.org>
-
- * time.c (v2w): Normalize a rational value to an integer if possible.
- [ruby-core:58070] [Bug #9059] reported by Isaac Schwabacher.
-
-Wed Oct 30 12:08:41 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_uniq_bang): use rb_ary_modify_check() instead of
- rb_ary_modify() because the array will be unshared soon.
-
-Wed Oct 30 03:25:10 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb: make less garbage when
- testing if a string is binary.
-
-Wed Oct 30 03:08:24 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb: string subclasses should
- not be considered to be binary. Fixes Psych / GH 166
- https://github.com/tenderlove/psych/issues/166
-
- * test/psych/test_string.rb: test for fix
-
-Tue Oct 29 23:01:18 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_zip): some refactoring.
-
-Tue Oct 29 22:11:37 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_uniq_bang): use st_foreach() instead of for loop.
-
-Tue Oct 29 20:01:58 2013 Koichi Sasada <ko1@atdot.net>
-
- * add RUBY_TYPED_FREE_IMMEDIATELY to data types which only use
- safe functions during garbage collection such as xfree().
-
- On default, T_DATA objects are freed at same points as finalizers.
- This approach protects issues such as reported by [ruby-dev:35578].
- However, freeing T_DATA objects immediately helps heap usage.
-
- Most of T_DATA (in other words, most of dfree functions) are safe.
- However, we turned off RUBY_TYPED_FREE_IMMEDIATELY by default
- for safety.
-
- * cont.c: ditto.
-
- * dir.c: ditto.
-
- * encoding.c: ditto.
-
- * enumerator.c: ditto.
-
- * error.c: ditto.
-
- * file.c: ditto.
-
- * gc.c: ditto.
-
- * io.c: ditto.
-
- * iseq.c: ditto.
-
- * marshal.c: ditto.
-
- * parse.y: ditto.
-
- * proc.c: ditto.
-
- * process.c: ditto.
-
- * random.c: ditto.
-
- * thread.c: ditto.
-
- * time.c: ditto.
-
- * transcode.c: ditto.
-
- * variable.c: ditto.
-
- * vm.c: ditto.
-
- * vm_backtrace.c: ditto.
-
- * vm_trace.c: ditto.
-
- * ext/bigdecimal/bigdecimal.c: ditto.
-
- * ext/objspace/objspace.c: ditto.
-
- * ext/stringio/stringio.c: ditto.
-
- * ext/strscan/strscan.c: ditto.
-
-Tue Oct 29 19:48:33 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: fix typo (FL_WB_PROTECT -> FL_WB_PROTECTED).
-
-Tue Oct 29 18:45:08 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_trace.c (tp_free): removed because empty free function.
- Use RUBY_TYPED_NEVER_FREE instead.
-
-Tue Oct 29 18:37:33 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: introduce new flags for T_TYPEDDATA.
- * RUBY_TYPED_FREE_IMMEDIATELY: free the data given by DATA_PTR()
- with dfree function immediately. Otherwise (default), the data
- freed at finalization point.
- * RUBY_TYPED_WB_PROTECTED: make this object with FL_WB_PROTECT
- (not shady).
-
- * gc.c (obj_free): support RUBY_TYPED_FREE_IMMEDIATELY.
-
-Tue Oct 29 16:49:03 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (vm_malloc_increase): decrease it more carefully.
-
-Tue Oct 29 16:24:52 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (heap_page_resurrect): return a page in tomb heap even if
- freelist is NULL.
-
-Tue Oct 29 15:46:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby_atomic.h (ATOMIC_SIZE_CAS): new macro, compare and swap size_t.
-
-Tue Oct 29 12:08:05 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/readline/readline.c (readline_getc): Consider
- NULL as input.
-
-Tue Oct 29 11:10:08 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c (gc_profile_total_time): fix off-by-one error in
- GC::Profiler.total_time.
- * test/ruby/test_gc.rb (class TestGc): test for above.
-
-Tue Oct 29 09:53:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * insns.def, vm.c, vm_insnhelper.c, vm_insnhelper.h, vm_method.c: split
- ruby_vm_global_state_version into two separate counters - one for the
- global method state and one for the global constant state. This means
- changes to constants do not affect method caches, and changes to
- methods do not affect constant caches. In particular, this means
- inclusions of modules containing constants no longer globally
- invalidate the method cache.
-
- * class.c, eval.c, include/ruby/intern.h, insns.def, vm.c, vm_method.c:
- rename rb_clear_cache_by_class to rb_clear_method_cache_by_class
-
- * class.c, include/ruby/intern.h, variable.c, vm_method.c: add
- rb_clear_constant_cache
-
- * compile.c, vm_core.h, vm_insnhelper.c: rename vmstat field in
- rb_call_info_struct to method_state
-
- * vm_method.c: rename vmstat field in struct cache_entry to method_state
-
-Mon Oct 28 23:26:04 2013 Tanaka Akira <akr@fsij.org>
-
- * test/readline/test_readline.rb (teardown): Clear Readline.input and
- Readline.output.
-
-Mon Oct 28 21:35:31 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/-test-/file/depend, ext/-test-/postponed_job/depend,
- ext/-test-/tracepoint/depend: New files for dependencies.
-
-Mon Oct 28 15:32:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/openssl/depend (ossl.o): work around of dependency of
- thread_native.h, which depends on headers by THREAD_MODEL.
- [ruby-dev:47777]
-
- * ext/openssl/extconf.rb: need THREAD_MODEL.
-
-Mon Oct 28 14:57:01 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * load.c (ruby_init_ext): share feature names between frame name and
- provided features.
-
-Mon Oct 28 14:41:27 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-electric.el: Import ruby-electric.el 2.1 from
- https://github.com/knu/ruby-electric.el.
-
- * Hitting the newline-and-indent key within a comment fires
- comment-indent-new-line.
-
- * Introduce a new feature
- `ruby-electric-autoindent-on-closing-char`.
-
- * Fix fallback behavior of ruby-electric-space/return that
- caused error with auto-complete.
-
-Mon Oct 28 13:17:17 2013 Or Cohen <orc@fewbytes.com>
-
- * error.c (name_err_to_s): remove no longer needed overriding, since
- r30455 which made exc_to_s almost same. Fixes [GH-413].
-
-Mon Oct 28 12:42:11 2013 Tanaka Akira <akr@fsij.org>
-
- * common.mk, ext/objspace/depend, ext/coverage/depend,
- ext/-test-/debug/depend, ext/date/depend: Update dependencies.
-
-Mon Oct 28 09:29:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * vm.c: vm_clear_all_cache is not necessary now we use a 64 bit counter
- for global state version.
-
- * vm_insnhelper.h: ruby_vm_global_state_version overflow is unnecessary
-
-Mon Oct 28 07:47:32 2013 Aman Gupta <ruby@tmm1.net>
-
- * vm_backtrace.c (rb_profile_frame_classpath): do not use rb_inspect
- directly, since it might have a custom implementation or show ivars.
-
-Mon Oct 28 04:10:41 2013 Aman Gupta <ruby@tmm1.net>
-
- * vm_backtrace.c (rb_profile_frame_classpath): handle singleton
- methods defined directly on an object.
- * test/-ext-/debug/test_profile_frames.rb: test for above.
-
-Mon Oct 28 00:52:36 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * struct.c (new_struct): fix warning message, class name and encoding.
-
-Sun Oct 27 20:53:08 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/readline/readline.c: Include ruby/thread.h for
- rb_thread_call_without_gvl2.
- (readline_rl_instream, readline_rl_outstream): Record FILE
- structures allocated by this extension.
- (getc_body): New function extracted from readline_getc.
- (getc_func): New function.
- (readline_getc): Use rb_thread_call_without_gvl2 to invoke getc_func.
- [ruby-dev:47033] [Bug #8749]
- (clear_rl_instream, clear_rl_outstream): Close FILE structure
- allocated by this extension reliably. [ruby-core:57951] [Bug #9040]
- (readline_readline): Use clear_rl_instream and clear_rl_outstream.
- (readline_s_set_input): Set readline_rl_instream.
- (readline_s_set_output): Set readline_rl_outstream.
- (Init_readline): Don't call readline_s_set_input because
- readline_getc doesn't block other threads for any FILE structure now.
-
- [ruby-dev:47033] [Bug #8749] reported by Nobuhiro IMAI.
- [ruby-core:57951] [Bug #9040] reported by Eamonn Webster.
-
-Sat Oct 26 19:31:28 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * gc.c: catch up recent changes to compile on GC_DEBUG,
- RGENGC_CHECK_MODE.
-
-Sat Oct 26 19:08:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * range.c (range_initialize_copy): disallow to modify after
- initialized.
-
-Sat Oct 26 17:48:54 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/open-uri.rb (meta_add_field): : Re-implemented.
- [ruby-core:58017] [Bug #9051] patch by Eamonn Webster.
-
-Sat Oct 26 14:35:09 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_profile_dump_on): use "Page" terminology.
-
-Sat Oct 26 13:25:45 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_sweep, gc_heap_lazy_sweep): fix measurement code.
- We only need one sweep time measurement without lazy sweep.
-
-Sat Oct 26 11:59:13 2013 Tanaka Akira <akr@fsij.org>
-
- * addr2line.c: Include ELF header after system headers (especially
- sys/types.h) to avoid compilation failure,
- "usr/include/sh3/elf_machdep.h:4:2: error: #error Define _BYTE_ORDER!",
- on NetBSD/sh3 (dreamcast, hpcsh, landisk, mmeye).
-
-Sat Oct 26 11:35:22 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: tuning parameters.
-
- * gc.c (GC_MALLOC_LIMIT): change default value to 16MB.
-
- * gc.c (GC_MALLOC_LIMIT_GROWTH_FACTOR): change default value to 2.0.
-
- * gc.c (gc_before_sweep): change decrease ratio of `malloc_limit'
- from 1/4 to 1/10.
-
-Sat Oct 26 11:30:07 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (vm_malloc_increase): do gc_rest_sweep() before GC.
- gc_rest_sweep() can reduce malloc_increase, so try it before GC.
- Otherwise, malloc_increase can be less than malloc_limit at
- gc_before_sweep(). This means that re-calculation of malloc_limit
- may be wrong value.
-
-Sat Oct 26 06:35:41 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (gc_before_heap_sweep): Restructure code to mean clearly.
- heap->freelist is connected to end of list.
-
-Sat Oct 26 04:01:35 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_before_heap_sweep): fix freelist management.
- After rb_gc_force_recycle() for a object belonging to heap->freelist,
- `heap->using_page->freelist' is not null.
-
-Thu Oct 24 21:57:24 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * parse.y: Remove +(binary) and -(binary) special cases
- [Feature #9048]
-
-Thu Oct 24 12:45:53 2013 Zachary Scott <e@zzak.io>
-
- * object.c: [DOC] Document first argument also takes string for:
-
- rb_mod_const_get, rb_mod_const_set, rb_mod_const_defined
-
- Also added note about NameError exception for invalid constant name
-
-Thu Oct 24 12:23:58 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread.c (rb_thread_terminate_all): add a comment why we need
- state check and call terminate_i again.
-
-Thu Oct 24 12:15:02 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread.c (rb_thread_terminate_all): add a comment why infinite
- sleep is safe.
-
-Thu Oct 24 07:41:42 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c: add new initial_growth_max tuning parameter.
- [ruby-core:57928] [Bug #9035]
- * gc.c (heap_set_increment): when initial_growth_max is set,
- do not grow number of slots by more than growth_max at a time.
- * gc.c (rb_gc_set_params): load optional new tuning value from
- RUBY_HEAP_SLOTS_GROWTH_MAX environment variable.
- * test/ruby/test_gc.rb (class TestGc): test for above.
-
-Thu Oct 24 01:34:12 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/win32.h (rb_infinity_float): suppress overflow in
- constant arithmetic warnings. [ruby-core:57981] [Bug #9044]
-
-Thu Oct 24 00:11:24 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/ostruct.rb: raise NoMethodError with a #name and #args.
- Raise RuntimeError when modifying frozen instances
- instead of TypeError.
- (OpenStruct#each_pair): Return an enumerator with size
- (OpenStruct#delete): Use the converted argument.
- Patches by Kenichi Kamiya. [Fixes GH-383]
-
- * test/ostruct/test_ostruct.rb: Added tests for above.
-
-Thu Oct 24 00:10:22 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * array.c: Add Array#to_h [Feature #7292]
-
- * enum.c: Add Enumerable#to_h
-
-Wed Oct 23 23:48:28 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c: Rename free_min to min_free_slots and free_min_page to
- max_free_slots. The algorithm for heap growth is:
- if (swept_slots < min_free_slots) pages++
- if (swept_slots > max_free_slots) pages--
-
-Wed Oct 23 22:51:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/Makefile.sub (config.h): VC 2013 supports C99 mathematics
- functions. [ruby-core:57981] [Bug #9044]
-
-Wed Oct 23 19:13:18 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: move increment from heap to heap_pages.
- Share `increment' information with heaps.
-
- * gc.c: change ratio of heap_pages_free_min_page
- to 0.80.
- This change means slow down page freeing speed.
-
-Wed Oct 23 17:52:03 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (heap_pages_free_unused_pages): cast to (int) for size_t
- variable `i'.
-
-Wed Oct 23 17:39:35 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: introduce tomb heap.
- Tomb heap is where zombie objects and ghost (freed slot) lived in.
- Separate from other heaps (now there is only eden heap) at sweeping
- helps freeing pages more efficiently.
- Before this patch, even if there is an empty page at former phase
- of sweeping, we can't free it.
-
- Algorithm:
- (1) Sweeping all pages in a heap and move empty pages from the
- heap to tomb_heap.
- (2) Check all existing pages and free a page
- if all slots of this page are empty and
- there is enough empty slots (checking by swept_num)
-
- To introduce this patch, there are several tuning of GC parameters.
-
-Wed Oct 23 14:20:56 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_prof_sweep_timer_stop): catch up recent changes
- to compile on GC_PROFILE_MORE_DETAIL=1.
-
-Wed Oct 23 11:43:27 2013 Zachary Scott <e@zzak.io>
-
- * file.c: [DOC] fix rdoc format of File#expand_path from r43386
-
-Tue Oct 22 21:58:28 2013 URABE Shyouhei <shyouhei@ruby-lang.org>
-
- * vm_core.h (enum): avoid syntax error.
-
- * method.h: ditto.
-
- * internal.h: ditto.
-
-Tue Oct 22 19:53:16 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (Init_heap): move logics from heap_pages_init() and remove
- heap_pages_init().
-
-Tue Oct 22 19:19:05 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: allow multiple heaps.
- Now, objects are managed by page. And a set of pages is called heap.
- This commit supports multiple heaps in the object space.
-
- * Functions heap_* and rb_heap_t manages heap data structure.
- * Functions heap_page_* and struct heap_page manage page data
- structure.
- * Functions heap_pages_* and struct rb_objspace_t::heap_pages
- maintains all pages.
- For example, pages are allocated from the heap_pages.
-
- See https://bugs.ruby-lang.org/projects/ruby-master/wiki/GC_design
- and https://bugs.ruby-lang.org/attachments/4015/data-heap_structure_with_multiple_heaps.png
- for more details.
-
- Now, there is only one heap called `eden', which is a space for all
- new generated objects.
-
-Tue Oct 22 18:26:12 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/pp.rb (object_address_group): Use Kernel#to_s to obtain the class
- name and object address.
- This fix a problem caused by %p in C generates variable length
- address.
- Reported by ko1 via IRC.
-
-Tue Oct 22 16:57:48 2013 Benoit Daloze <eregontp@gmail.com>
-
- * file.c (File#expand_path): [DOC] improve documentation of File#expand_path.
- Based on patch by Prathamesh Sonpatki. [ruby-core:57734] [Bug #9002]
-
-Tue Oct 22 15:59:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (glob_helper): don't skip current directories if FNM_DOTMATCH
- is given. [ruby-core:53108] [Bug #8006]
-
-Tue Oct 22 14:53:11 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_trace.c: exterminate Zombies.
- There is a bug that T_ZOMBIE objects are not collected.
- Because there is a pass to miss finalizer postponed job
- with multi-threading. This patch solve this issue.
-
- * vm_trace.c (rb_postponed_job_register_one): set
- RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(th) if another same job
- is registered.
- There is a possibility to remain a postponed job without
- interrupt flag.
-
- * vm_trace.c (rb_postponed_job_register_one): check interrupt
- carefully.
-
- * vm_trace.c (rb_postponed_job_register_one): use additional space
- to avoid buffer full.
-
- * gc.c (gc_finalize_deferred_register): check failure.
-
- * thread.c (rb_threadptr_execute_interrupts): check
- `postponed_job_interrupt' immediately. There is a possibility
- to miss this flag.
-
-Tue Oct 22 12:11:16 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: check if the given CFLAGS and LDFLAGS are working, and
- bail out early if not.
-
-Tue Oct 22 00:06:57 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (rb_file_exists_p): warn deprecated name. [Bug #9041]
-
-Mon Oct 21 23:57:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * encoding.c (load_encoding): should preserve outer errinfo, so that
- expected exception may not be lost. [ruby-core:57949] [Bug #9038]
-
-Sun Oct 20 15:41:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (rb_io_reopen): create a new, temporary FD via rb_sysopen and
- call rb_cloexec_dup2 on it to atomically replace the file fptr->fd
- points to. This leaves no possible window where fptr->fd is invalid
- to userspace (even for any threads running w/o GVL). based on the
- patch by Eric Wong <normalperson@yhbt.net> at [ruby-core:57943].
- [Bug #9036]
-
-Sun Oct 20 15:29:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (rb_syserr_fail_path_in): new function split from
- rb_sys_fail_path_in to raise SystemCallError without errno.
-
- * internal.h (rb_syserr_fail_path): like rb_sys_fail_path but without
- errno.
-
-Sun Oct 20 13:58:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_obj_wb_unprotect, rb_obj_written),
- (rb_obj_write): suppress unused-parameter warnings.
-
-Sun Oct 20 10:32:48 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update RubyGems to master 0886307. This commit
- improves documentation and should bring ruby above 75% documented on
- rubyci.
-
-Sun Oct 20 09:30:56 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 3de7e0f. Changes:
-
- Only attempt to build extensions for newly-installed gems. This
- prevents compilation attempts at gem activation time for gems that
- already have extensions built.
-
- Fix crash in the dependency resolver for dependencies that cannot be
- resolved.
-
- * test/rubygems: ditto.
-
-Sun Oct 20 05:24:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * variable.c (rb_class2name): should return real class name, not
- singleton class or iclass.
-
-Sun Oct 20 04:18:48 2013 Aman Gupta <ruby@tmm1.net>
-
- * variable.c (rb_class2name): call rb_tmp_class_path() directly to
- avoid extra rb_str_dup() from rb_class_name().
-
-Sat Oct 19 19:59:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/file.c (code_page): use simple array instead of st_table.
-
- * encoding.c (rb_locale_encindex): defer initialization of win32 code
- page table until encoding db loaded.
-
-Sat Oct 19 08:25:05 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: fix rb_objspace_t.
- * make "struct heap" and move most of variables
- in rb_objspace_t::heap.
- * rename rb_objspace_t::heap::sorted to
- rb_objspace_t::heap_sorted_pages
- and make a macro heap_sorted_pages.
- * rename rb_objspace_t::heap::range to
- rb_objspace_t::heap_range and rename macros
- lomem/himem to heap_lomem/heap_himem.
-
-Sat Oct 19 07:14:40 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 42543b6. Changes:
-
- Fix `gem update` for gems with multiple platforms.
-
- * test/rubygems: ditto.
-
-Sat Oct 19 06:55:52 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 0a3814b. Changes:
-
- Fixed extension directory in Gem::Specification#require_paths.
-
- Allow installation of gems when $HOME is nonexistent or unwritable.
-
- Use proper API in InstallCommand.
-
- Improve support for path option in gem dependency files.
-
- Remove warnings.
-
- * test/rubygems: ditto.
-
-Fri Oct 18 15:23:34 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: change terminology of heap.
- Change "slot" to "page". "Slot" is a space of RVALUE.
- 1. "Heap" consists of a set of "heap_page"s (pages).
- 2. Each "heap_page" has "heap_page_body".
- 3. "heap_page_body" has RVALUE (a.k.a. "slot") spaces.
- 4. "sorted" is a sorted array of "heap_page"s, sorted
- by address of heap_page_body (for "is_pointer_to_heap").
-
- See https://bugs.ruby-lang.org/attachments/4008/data-heap_structure.png.
-
-Fri Oct 18 09:40:43 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master cee6788. Changes:
-
- Fix test failure on vc10-x64 Server on rubyci.org due to attempting
- to File.chmod where it is not supported.
-
- Continuing work on improved gem dependencies file (Gemfile) support.
-
- * test: ditto.
-
-Fri Oct 18 06:02:49 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master f738c67. Changes:
-
- Fixed test bug for ruby with ENABLE_SHARED = no
-
- * test/rubygems: ditto.
-
-Fri Oct 18 00:57:07 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/tsort.rb (TSort.tsort): Extracted from TSort#tsort.
- (TSort.tsort_each): Extracted from TSort#tsort_each.
- (TSort.strongly_connected_components): Extracted from
- TSort#strongly_connected_components.
- (TSort.each_strongly_connected_component): Extracted from
- TSort#each_strongly_connected_component.
-
-Thu Oct 17 18:50:08 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (CALC_EXACT_MALLOC_SIZE_CHECK_OLD_SIZE): introduced.
- This macro enable checker compare with allocated memory and
- declared old_size of sized_xfree and sized_xrealloc.
-
-Thu Oct 17 18:45:41 2013 Koichi Sasada <ko1@atdot.net>
-
- * string.c (STR_HEAP_SIZE): includes TERM_LEN(str).
-
- * string.c (rb_str_memsize): use STR_HEAP_SIZE().
-
-Thu Oct 17 17:43:00 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * vm_insnhelper.c (vm_call_method): set ci->me to 0 when the
- original method of a refined method is undef to avoid SEGV.
-
- * vm_method.c (rb_method_entry_without_refinements): return 0 when
- the original method of a refined method is undef to avoid SEGV.
-
- * test/ruby/test_refinement.rb: related test.
-
-Thu Oct 17 17:38:36 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c, internal.h: rename ruby_xsizefree/realloc to
- rb_sized_free/realloc.
-
- * array.c: catch up these changes.
-
- * string.c: ditto.
-
-Thu Oct 17 17:32:51 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c, string.c: use ruby_xsizedfree() and ruby_xsizedrealloc().
-
- * internal.h (SIZED_REALLOC_N): define a macro as REALLOC_N().
-
-Thu Oct 17 17:11:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (console_emulator_p): check by comparison between
- module handle of WriteConsoleW and kernel32.dll.
-
- * configure.in, win32/Makefile.sub, win32/setup.mak: no longer need
- psapi.lib.
-
-Thu Oct 17 16:53:30 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c, internal.h: add new internal memory management functions.
- * void *ruby_xsizedrealloc(void *ptr, size_t new_size, size_t old_size)
- * void ruby_xsizedfree(void *x, size_t size)
- These functions accept additional size parameter to calculate more
- accurate malloc_increase parameter which control GC timing.
- [Feature #8985]
-
-Thu Oct 17 14:21:34 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/file.c (rb_file_expand_path_internal): fix memory leaks at
- a non-absolute home exception.
-
-Thu Oct 17 14:06:39 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/object_tracing.c (newobj_i): fix memory leak.
- There is possibility to remain info due to missing FREEOBJ event.
- FREEOBJ events are skipped while suppress_tracing state, for example,
- during trace events are invoking.
-
-Thu Oct 17 12:30:16 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/tsort.rb (TSort.each_strongly_connected_component_from):
- Extracted from TSort#each_strongly_connected_component_from.
-
-Thu Oct 17 11:07:06 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 941c21a. Changes:
-
- Restored method bundler wants to remove for compatibility.
-
- Improvements to Gemfile compatibility.
-
- * test/rubygems: ditto.
-
-Thu Oct 17 08:08:11 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/object_tracing.c (newobj_i): add workaround.
- some bugs hits this check.
-
- * ext/objspace/object_tracing.c (object_allocations_reporter_i): cast as pointer.
-
-Thu Oct 17 07:36:53 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 2abce58. Changes:
-
- Fixed documentation generation when sdoc and json are installed as
- gems.
-
- Added some missing documentation.
-
-Thu Oct 17 07:10:26 2013 Zachary Scott <e@zzak.io>
-
- * ext/curses/curses.c: [DOC] Cleaned up formatting consistency of rdoc
- comments for Curses, including period spacing and column width.
-
- This patch also fixed some typos. Thanks to @postmodern for the patch!
- [Fixes GH-420] https://github.com/ruby/ruby/pull/420
-
-Thu Oct 17 06:58:42 2013 Zachary Scott <e@zzak.io>
-
- * ext/date/date_core.c: [DOC] plural grammar fixed by @scott113341
- Contributed via documenting-ruby.org: documenting-ruby/ruby#16
- https://github.com/documenting-ruby/ruby/pull/16
-
-Thu Oct 17 05:52:31 2013 Zachary Scott <e@zzak.io>
-
- * ext/io/nonblock/nonblock.c: [DOC] Document io/nonblock by reprah
- [Fixes GH-418] https://github.com/ruby/ruby/pull/418 based on the
- original discussion from documenting-ruby/ruby#18
-
-Thu Oct 17 05:40:33 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (objspace_each_objects): do not skip empty RVALUEs.
-
-Thu Oct 17 05:31:31 2013 Koichi Sasada <ko1@atdot.net>
-
- * error.c (rb_bug_reporter_add): return simply 0 if failed.
- Please check return value.
-
-Thu Oct 17 05:17:33 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/object_tracing.c: add new method
- ObjectSpace.trace_object_allocations_debug_start for GC debugging.
- If you encounter the BUG "... is T_NONE" (and so on) on your
- application, please try this method at the beginning of your app.
-
-Wed Oct 16 22:35:27 2013 Zachary Scott <e@zzak.io>
-
- * ext/io/nonblock/nonblock.c: use rb_cIO instead of VALUE
-
-Wed Oct 16 17:45:13 2013 Koichi Sasada <ko1@atdot.net>
-
- * bootstraptest/runner.rb: check nil before calling `signal?'
- for a process status.
-
-Wed Oct 16 17:37:17 2013 Koichi Sasada <ko1@atdot.net>
-
- * error.c, internal.h (rb_bug_reporter_add): add a new C-API.
- rb_bug_reporter_add() allows to register a function which
- is called at rb_bug() called.
-
- * ext/-test-/bug_reporter/bug_reporter.c: add a test for this C-API.
-
- * ext/-test-/bug_reporter/extconf.rb: ditto.
-
- * test/-ext-/bug_reporter/test_bug_reporter.rb: ditto.
-
-Wed Oct 16 15:14:21 2013 Koichi Sasada <ko1@atdot.net>
-
- * NEWS: add a line into NEWS for last commit.
-
-Wed Oct 16 15:09:14 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/objspace.c: add a new method `reachable_objects_from_root'.
- ObjectSpace.reachable_objects_from_root returns all objects referred
- from root (called "root objects").
- This feature is for deep object analysis.
-
- * test/objspace/test_objspace.rb: add a test.
-
-Wed Oct 16 15:00:21 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master b955554. Changes:
-
- Fixed NameError for Gem::Ext due to re-entering file lookup in
- RubyGems' overridden require. Bug by Koichi Sasada.
-
- Fixed possible circular require warning in tests.
-
- Used existing constant for `gem install -g` dependency file list.
-
- * test/rubygems: ditto.
-
-Wed Oct 16 09:42:42 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 278d00d. Changes:
-
- Fixes building extensions without a "clean" make rule
-
- Adds gem dependency file autodetection to "gem install -g"
-
- * test/rubygems: Tests for the above.
-
-Wed Oct 16 09:12:23 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master commit 2a74263. This fixes
- several bugs in RubyGems 2.2.0.preview.1.
-
- * test/rubygems: ditto.
-
-Wed Oct 16 07:25:02 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c (gc_mark_roots): rename roots to be categories
- instead of function names.
-
-Tue Oct 15 19:18:13 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.h (rb_objspace_reachable_objects_from_root): added.
- This API provides information which objects are root objects.
- `category' shows what kind of root objects.
-
- * gc.c (gc_mark_roots): separate from gc_marks_body().
-
-Tue Oct 15 17:47:59 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c: Fix a typo. MacOS X doesn't have ENOTSUPP.
-
-Mon Oct 14 12:32:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (process_options): load statically linked extensions before
- rubygems, because of ext/thread.
-
- * ruby.c (process_options): use gem_prelude instead of requiring
- rubygems directly when --enable=gems is given.
-
- * Makefile.in (DEFAULT_PRELUDES): always use gem_prelude regardless of
- --disable-rubygems.
-
-Mon Oct 14 11:07:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (have_framework): should append framework options to
- $LIBS, not $LDFLAGS. The former is propagated to exts.mk when
- enable-static-linked-ext.
-
- * lib/mkmf.rb (create_makefile): ranlib on static library, not DLLIB.
-
-Sun Oct 13 23:53:40 2013 Andrew Grimm <andrew.j.grimm@gmail.com>
-
- * vsnprintf.c: Fix spelling from compliment to complement.
- Patch by @agrimm.
-
- * include/ruby/ruby.h: ditto
-
-Sun Oct 13 20:59:27 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm.c (Init_BareVM): initialize defined_module_hash here,
- Init_top_self() is too late to register core classes/modules.
-
- * compile.c (compile_array_): no hash to merge if it is empty.
-
- * vm.c (m_core_hash_merge_kwd): just check keys if only one argument
- is given, without merging.
-
-Sat Oct 12 06:35:01 2013-10-11 Eric Hodel <drbrain@segment7.net>
-
- * lib/rake: Update to rake 10.1.0
- * bin/rake: ditto.
- * test/rake: ditto.
-
- * NEWS: Update NEWS to include rake 10.1.0 and links to release notes.
-
-Sat Oct 12 03:26:04 2013 Koichi Sasada <ko1@atdot.net>
-
- * class.c, variable.c, gc.c (rb_class_tbl): removed.
-
- * vm.c, vm_core.h (rb_vm_add_root_module): added to register as a
- defined root module or class.
- This guard helps mark miss from defined classes/modules they are
- only referred from C's global variables in C-exts.
- Basically, it is extension's bug.
- Register to hash object VM has.
- Marking a hash objects allows generational GC supports.
-
- * gc.c (RGENGC_PRINT_TICK): disable (revert).
-
-Sat Oct 12 03:24:49 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_method.c (rb_gc_mark_unlinked_live_method_entries):
- revert last commit to introduce debug prints.
-
-Fri Oct 11 21:05:19 2013 Koichi Sasada <ko1@atdot.net>
-
- * internal.h, parse.y: use `full_mark' instead of `full_marking'.
-
-Fri Oct 11 20:58:16 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: use terminology `full_mark' instead of `minor_gc'
- in mark functions.
-
-Fri Oct 11 20:46:09 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: use __GNUC__ instead of __GCC__.
-
-Fri Oct 11 20:35:59 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c, parse.y: support generational Symbol related marking.
- Each symbols has String objects respectively to represent
- Symbols.
- These objects are marked only when:
- * full marking
- * new symbols are added
- This hack reduce symbols (related strings) marking time.
- For example, on my Linux environment, the following code
- "20_000_000.times{''}"
- with 40k symbols (similar symbol number on Rails 3.2.14 app,
- @jugyo tells me) boosts, from 7.3sec to 4.2sec.
-
- * internal.h: change prototype of rb_gc_mark_symbols().
-
-Fri Oct 11 19:27:22 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-electric.el: Import ruby-electric.el 2.0.1 which fixes
- a bug and a flaw with auto-end introduced in the revamp.
-
- * ruby-forward-sexp is inappropriate here because it moves the
- cursor past the keyword.
-
- * Fix a reversed looking-back check in
- ruby-electric--block-beg-keyword-at-point-p.
-
- * Do not add end again if space or return is hit repeatedly
- after a block beginning keyword.
-
-Fri Oct 11 18:12:47 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/gc_hook.c: prohibit reentrant.
-
-Fri Oct 11 18:11:34 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_trace.c (rb_postponed_job_flush): fix bit operation.
-
-Fri Oct 11 17:33:24 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-electric.el: Import ruby-electric.el 2.0 from
- https://github.com/knu/ruby-electric.el which integrates changes
- from another fork by @qoobaa.
-
- * Allow ruby-electric-mode to be disabled by introducing a
- dedicated key map. Electric key bindings are now defined in
- ruby-electric-mode-map instead of overwriting ruby-mode-map.
-
- * Add ruby-electric-mode-hook.
-
- * Use a remap in binding ruby-electric-delete-backward-char.
-
- * Totally revamp electric keywords and then introduce electric
- return. Modifier keywords are now properly detected making
- use of ruby-mode's indentation level calculator, and
-
- * block-mid keywords (then, else, elsif, when, rescue and
- ensure) also become electric with automatic reindentation.
-
- * Add standardized comments for ELPA integration.
-
- * Fix interaction with smartparens-mode by disabling its end
- keyword completion, since ruby-electric has become more clever
- at it.
-
- * The custom variable `ruby-electric-keywords` is changed to
- `ruby-electric-keywords-alist`, allowing user to fine-grained
- configuration.
-
-Fri Oct 11 16:53:28 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_trace.c (rb_postponed_job_flush): simplify.
-
-Fri Oct 11 03:36:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (rb_threadptr_execute_interrupts): flush postponed job only
- once at last.
-
- * vm_trace.c (rb_postponed_job_flush): defer calling postponed jobs
- registered while flushing to get rid of infinite reentrance of
- ObjectSpace.after_gc_start_hook. [ruby-dev:47400] [Bug #8492]
-
-Thu Oct 10 23:04:00 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_or): remove unused variables.
-
-Thu Oct 10 23:01:16 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_or): use rb_hash_keys().
-
-Thu Oct 10 21:36:16 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_compact_bang): use ary_resize_smaller().
-
-Thu Oct 10 17:25:28 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm.c (vm_exec): support :b_return event for "lambda{return}.call".
- [Bug #8622]
-
- * test/ruby/test_settracefunc.rb: add a test.
-
-Thu Oct 10 13:52:37 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_trace.c (postponed_job): use preallocated buffer.
- Pre-allocate MAX_POSTPONED_JOB (1024) sized buffer
- and use it.
- If rb_postponed_job_register() cause overflow, simply it
- fails and returns 0.
- And maybe rb_postponed_job_register() is signal safe.
-
- * vm_core.h: change data structure.
-
-Thu Oct 10 11:11:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm.c (Init_VM): hide also the singleton class of frozen-core, not
- only frozen-core itself.
-
-Thu Oct 10 06:02:08 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_rand.rb: fix r43224. local variable `e' is
- no longer available.
-
-Thu Oct 10 00:02:35 2013 Yusuke Endoh <mame@tsg.ne.jp>
-
- * numeric.c (fix_aref): avoid a possible undefined behavior.
- 1L << 63 on 64-bit platform is undefined, at least, according to
- ISO/IEC 9899 (C99) 6.5.7.
-
-Wed Oct 9 23:57:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (id_for_attr): avoid inadvertent symbol creation.
-
-Wed Oct 9 18:03:01 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_method.c (rb_attr): preserve encoding of the attribute ID in
- error message.
-
-Wed Oct 9 17:40:16 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_fstring): because of lazy sweep, str may be unmarked
- already and swept at next time, so mark it for the time being.
- [ruby-core:57756]
-
-Wed Oct 9 13:53:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compar.c (cmp_eq): fail if recursion. [ruby-core:57736] [Bug #9003]
-
- * thread.c (rb_exec_recursive_paired_outer): new function which is
- combination of paired and outer variants.
-
-Wed Oct 9 09:18:14 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/debug.h,
- vm_backtrace.c (rb_profile_frame_full_label): add new C API
- rb_profile_frame_full_label() which returns label with
- qualified method name.
- Note that in future version of Ruby label() may return
- same return value of full_label().
-
- * ext/-test-/debug/profile_frames.c,
- test/-ext-/debug/test_profile_frames.rb: fix a test for this change.
-
-
-Wed Oct 9 00:55:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * load.c (load_lock): display backtrace to $stderr at circular
- require.
-
- * vm_backtrace.c (rb_backtrace_print_to): new function to print
- backtrace to the given output.
-
-Tue Oct 8 21:03:35 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_backtrace.c, include/ruby/debug.h: add new APIs
- * VALUE rb_profile_frame_method_name(VALUE frame)
- * VALUE rb_profile_frame_qualified_method_name(VALUE frame)
-
- * iseq.c (rb_iseq_klass), internal.h: add new internal function
- rb_iseq_method_name().
-
- * ext/-test-/debug/profile_frames.c (profile_frames),
- test/-ext-/debug/test_profile_frames.rb: add a test.
-
-Tue Oct 8 16:11:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_uniq): use rb_hash_values(), as well as the case no
- block is given.
-
- * internal.h: define rb_hash_values() as internal API.
-
-Tue Oct 8 13:53:21 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_uniq): use rb_hash_keys().
-
- * internal.h: define rb_hash_keys() as internal API.
-
- * hash.c (rb_hash_keys): ditto.
-
-Tue Oct 8 10:56:39 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * cont.c: disable FIBER_USE_NATIVE on GNU/Hurd because it doesn't
- support a combination getcontext() and threads. Patch by
- Gabriele Giacone (1o5g4r8o@gmail.com). [Bug #8990][ruby-core:57685]
-
-Tue Oct 8 05:58:12 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (Time.strptime): Time.strptime('0', '%s') returns local
- time Time object as Ruby 2.0 and before.
-
-Tue Oct 8 05:40:37 2013 Eric Hodel <drbrain@segment7.net>
-
- * .travis.yml: Rebuild Travis CI's "ruby-head" version on successful
- build. Patch by Konstantin Haase. [Fixes GH-417]
- https://github.com/ruby/ruby/pull/417
-
-Tue Oct 8 04:28:25 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-mode.el: Use preceding-char/following-char
- (returning 0 at BOF/EOF) instead of char-before/char-after
- (returning nil at BOF/EOF) to avoid error from char-syntax when
- at BOF/EOF.
-
-Tue Oct 8 04:12:45 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-additional.el (ruby-mode-set-encoding): Add a missing
- else clause to unbreak with `cp932`, etc.
-
- * misc/ruby-mode.el (ruby-mode-set-encoding): Ditto.
-
-Tue Oct 8 03:57:34 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-additional.el (ruby-mode-set-encoding): Use
- `default-buffer-file-coding-system` if the :prefer-utf-8
- property is not available.
-
- * misc/ruby-mode.el (ruby-mode-set-encoding): Ditto.
-
- * misc/ruby-additional.el (ruby-encoding-map): Override the
- default value.
-
-Tue Oct 8 03:19:19 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-additional.el (ruby-mode-set-encoding): Add support
- for `prefer-utf-8` which was introduced in Emacs trunk.
-
- * misc/ruby-additional.el (ruby-encoding-map): Add a mapping from
- `japanese-cp932` to `cp932` to fix the problem where saving a
- source file written in Shift_JIS twice would end up having
- `coding: japanese-cp932` which Ruby could not recognize.
-
- * misc/ruby-additional.el (ruby-mode-set-encoding): Add support
- for encodings mapped to nil in `ruby-encoding-map`.
-
- * misc/ruby-additional.el (ruby-encoding-map): Map `us-ascii` and
- `utf-8` to nil by default, meaning they need not be explicitly
- declared in magic comment.
-
- * misc/ruby-additional.el (ruby-encoding-map): Add type
- declaration for better customize UI.
-
- * misc/ruby-mode.el: Ditto for the above.
-
-Tue Oct 8 00:14:53 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-additional.el: Add a standard header and footer,
- including (provide 'ruby-additional).
-
-Mon Oct 7 22:52:45 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-electric.el (ruby-electric-space-can-be-expanded-p):
- Return nil to avoid "end" insertion when in smartparens-mode
- that is configured to insert "end" for the same keyword.
-
- * misc/ruby-electric.el (ruby-electric-keywords): New custom
- variable to replace `ruby-electric-simple-keywords-re` with.
-
-Mon Oct 7 22:52:16 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-additional.el: Use preceding-char/following-char
- (returning 0 at BOF/EOF) instead of char-before/char-after
- (returning nil at BOF/EOF) to avoid error from char-syntax when
- at BOF/EOF.
-
-Mon Oct 7 22:45:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * cont.c (FIBER_USE_NATIVE): split long conditions.
-
-Mon Oct 7 20:29:31 2013 Zachary Scott <e@zzak.io>
-
- * lib/time.rb: [DOC] typo in Time.rb overview by @srt32 [Fixes GH-416]
- https://github.com/ruby/ruby/pull/416
-
-Mon Oct 7 20:07:20 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (Time.strptime): Use :offset.
- Patch by Felipe Contreras. [ruby-core:57694]
-
-Mon Oct 7 16:47:27 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/-ext-/debug/test_profile_frames.rb: rename class C to
- something long name because one test depends on absence of
- class ::C.
-
-Mon Oct 7 16:33:10 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/-test-/debug/profile_frames.c:
- test/-ext-/debug/test_profile_frames.rb: add a test for new C-APIs.
-
-Mon Oct 7 16:12:36 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/debug.h: add backtrace collecting APIs for profiler.
- * int rb_profile_frames(int start, int limit, VALUE *buff, int *lines);
- Collect information of frame information.
-
- * VALUE rb_profile_frame_path(VALUE frame);
- * VALUE rb_profile_frame_absolute_path(VALUE frame);
- * VALUE rb_profile_frame_label(VALUE frame);
- * VALUE rb_profile_frame_base_label(VALUE frame);
- * VALUE rb_profile_frame_first_lineno(VALUE frame);
- * VALUE rb_profile_frame_classpath(VALUE frame);
- * VALUE rb_profile_frame_singleton_method_p(VALUE frame);
- Get information about each frame.
-
- These APIs are designed for profilers, for example, no object allocation,
- and enough information for profilers.
- In this version, this API collects only Ruby level frames.
- This issue will be fixed after Ruby 2.1.
-
- * vm_backtrace.c: implement above APIs.
-
- * iseq.c (rb_iseq_klass): return local_iseq's class.
-
-Mon Oct 7 14:26:01 2013 Koichi Sasada <ko1@atdot.net>
-
- * proc.c: catch up last commit.
- Type of return value of rb_iseq_first_lineno() is now VALUE.
-
- * vm_insnhelper.c (argument_error): ditto.
-
- * vm_method.c (rb_method_entry_make): ditto.
-
-Mon Oct 7 14:07:45 2013 Koichi Sasada <ko1@atdot.net>
-
- * iseq.c, internal.h: change to public (but internal) functions
- * VALUE rb_iseq_path(VALUE iseqval);
- * VALUE rb_iseq_absolute_path(VALUE iseqval);
- * VALUE rb_iseq_label(VALUE iseqval);
- * VALUE rb_iseq_base_label(VALUE iseqval);
- * VALUE rb_iseq_first_lineno(VALUE iseqval);
- And new (temporary) function:
- * VALUE rb_iseq_klass(VALUE iseqval);
-
- * iseq.c. vm_core.h (int rb_iseq_first_lineno): remove
- function `int rb_iseq_first_lineno(const rb_iseq_t *iseq)'.
- Use `VALUE rb_iseq_first_lineno(VALUE iseqval)' instead.
-
- * proc.c. vm_insnhelper.c, vm_method.c: catch up this change.
-
-Sun Oct 6 08:37:39 2013 Zachary Scott <e@zzak.io>
-
- * lib/webrick.rb: [DOC] fix grammar in WEBrick overview [Fixes GH-413]
- Based on patch by @chastell https://github.com/ruby/ruby/pull/413
-
-Sat Oct 5 11:21:01 2013 Aaron Pfeifer <aaron.pfeifer@gmail.com>
-
- * thread.c (terminate_atfork_i): fix locking mutexes not unlocked in
- forks when not tracked in thread. [ruby-core:55102] [Bug #8433]
-
-Fri Oct 4 19:54:09 2013 Zachary Scott <e@zzak.io>
-
- * ext/dbm/dbm.c: [DOC] Fix wrong constant name in DBM by @edward
- [Fixes GH-409] https://github.com/ruby/ruby/pull/409
-
-Fri Oct 4 19:49:42 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c: rename heap.free_num as heap.swept_num to clarify meaning and
- avoid confusion with objspace_free_num().
-
-Fri Oct 4 19:02:01 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c (objspace_free_num): new method for available/free slots on
- heap. [ruby-core:57633] [Bug #8983]
- * gc.c (gc_stat): change heap_free_num definition to use new method.
- * test/ruby/test_gc.rb: test for above.
-
-Fri Oct 4 18:53:42 2013 Aman Gupta <ruby@tmm1.net>
-
- * gc.c: add rb_objspace.limit to keep accurate count of total heap
- slots [ruby-core:57633] [Bug #8983]
-
-Fri Oct 4 09:32:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/csv.rb (CSV.foreach): support enumerator. based on a patch by
- Hanmac (Hans Mackowiak) at [ruby-core:57643]. [ruby-core:57283]
- [Feature #8929]
-
-Thu Oct 3 18:20:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (console_emulator_p, constat_handle): disable built-in
- console colorizing when console-emulator-like DLL is injected.
- [Feature #8201]
-
-Thu Oct 3 18:01:44 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: define gc_profile_record::allocated_size if
- CALC_EXACT_MALLOC_SIZE is true.
-
-Thu Oct 3 13:42:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (yes-test-sample): use RUNRUBY instead of MINIRUBY to set
- runtime library path and run the built ruby. [Bug #8971]
-
-Thu Oct 3 00:17:15 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-additional.el: Properly quote the body. An unquoted
- body given to eval-after-load is evaluated immediately!
-
-Wed Oct 2 21:38:30 2013 Yusuke Endoh <mame@tsg.ne.jp>
-
- * ext/socket/ifaddr.c (rsock_getifaddrs): fix possible memory leak.
- When a system had no interface, this function used xmalloc for root
- but did not return any reference to it. This patch fixes it by
- immediately returning an empty array if no interface is found.
- Coverity Scan found this bug.
-
-Wed Oct 2 21:37:04 2013 Yusuke Endoh <mame@tsg.ne.jp>
-
- * random.c (make_seed_value): a local array declaration was accessed
- out of scope. Coverity Scan found this bug.
-
-Wed Oct 2 18:52:40 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: relax GC condition due to malloc_limit.
-
- * gc.c (GC_MALLOC_LIMIT_MAX): change default value
- (256MB -> 512MB) and permit zero to ignore max value.
-
- * gc.c (vm_malloc_increase, vm_xrealloc): do not cause GC on realloc.
-
- * gc.c (gc_before_sweep): change debug messages.
-
-Wed Oct 2 16:26:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (rb_io_close_read): duplex IO should wait its child process
- even after close_read.
-
-Wed Oct 2 15:39:13 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_core.h: use __has_attribute() instead of __clang__major__ because
- clang says "Note that marketing version numbers should not be used
- to check for language features, as different vendors use different
- numbering schemes. Instead, use the Feature Checking Macros."
- http://clang.llvm.org/docs/LanguageExtensions.html
-
-Wed Oct 2 14:19:57 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (rb_io_close_write): detach tied IO for writing before closing
- to get rid of race condition. [ruby-list:49598]
-
- * io.c (rb_io_close_read): keep fptr in write_io to be discarded, to
- fix freed pointer access when it is in use by other threads, and get
- rid of potential memory/fd leak.
-
-Tue Oct 1 23:44:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * vm_core.h: use __attribute__((unused)) in UNINITIALIZED_VAR on clang
- 4.0+ instead of just on 4.2. Clang has supported the unused attribute
- since before version 4, so this should be safe.
-
-Tue Oct 1 22:03:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/tempfile.rb (Tempfile#unlink): finalizer is no longer needed
- after unlinking. patched by by normalperson (Eric Wong) at
- [ruby-core:56521] [Bug #8768]
-
-Tue Oct 1 20:54:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (stat_new_0): constify.
-
- * file.c (rb_stat_new): constify and export. based on a patch by
- Hanmac (Hans Mackowiak) at [ruby-core:53225]. [Feature #8050]
-
-Tue Oct 1 16:03:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (ruby_safe_level_4_warning): needed by extension
- libraries which check safe level 4. [ruby-dev:47517] [Bug #8652]
-
-Mon Sep 30 23:14:36 2013 Zachary Scott <e@zzak.io>
-
- * ext/objspace/objspace.c: [DOC] Cleaned up many rdoc formatting
- issues and several duplicate grammar bugs.
-
-Mon Sep 30 23:01:01 2013 Zachary Scott <e@zzak.io>
-
- * ext/objspace/object_tracing.c: [DOC] Adjust rdoc formatting and fix
- small grammar typo
-
-Mon Sep 30 17:28:39 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/object_tracing.c: [DOC] add some notes for
- ObjectSpace::trace_object_allocations.
-
-Mon Sep 30 16:46:58 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/object_tracing.c: add new 3 methods to control tracing.
- * ObjectSpace::trace_object_allocations_start
- * ObjectSpace::trace_object_allocations_stop
- * ObjectSpace::trace_object_allocations_clear
- And some refactoring.
-
- * test/objspace/test_objspace.rb: add a test for new methods.
-
- * NEWS: add a description for new methods.
-
-Mon Sep 30 11:18:04 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_gc_disable): do rest_sweep() before disable GC.
- This fix may solve a failure of
- TestTracepointObj#test_tracks_objspace_events
- [test/-ext-/tracepoint/test_tracepoint.rb:43].
-
-Mon Sep 30 10:40:20 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * vm_method.c (rb_undef): raise a NameError if the original method
- of a refined method is not defined.
-
- * vm_insnhelper.c (rb_method_entry_eq): added NULL check to avoid SEGV.
-
- * test/ruby/test_refinement.rb: related test.
-
-Sun Sep 29 23:45:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (rb_id_attrset, intern_str): allow junk attrset ID for
- Struct.
-
- * parse.y (rb_id_attrset): fix inconsistency with literals, allow
- ID_ATTRSET and return it itself, but ID_JUNK cannot make ID_ATTRSET.
- and raise a NameError instead of rb_bug() for invalid argument.
-
-Sun Sep 29 18:45:05 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * vm_insnhelper.c (vm_callee_setup_arg_complex, vm_yield_setup_block_args):
- clear keyword arguments to prevent GC bug which occurs
- while marking VM stack.
- [ruby-dev:47729] [Bug #8964]
-
- * test/ruby/test_keyword.rb: tests for the above.
-
-Sat Sep 28 23:25:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * math.c (math_log, math_log2, math_log10): fix for Bignum argument.
- numbits should be add only when right shifted.
-
-Sat Sep 28 14:30:29 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * test/dl/test_base.rb: {libc, libm} detection now handle GNU/Hurd
- correctly. Patch by Gabriele Giacone (1o5g4r8o@gmail.com).
- [Bug #8937][ruby-core:57311]
- * test/fiddle/helper.rb: ditto.
-
-Sat Sep 28 00:19:41 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * ext/curses/extconf.rb: check the size of chtype.
-
- * ext/curses/curses.c (NUM2CH, CH2NUM): use proper macros for
- the size of chtype.
-
- [ruby-core:56090] [Bug #8659]
-
-Fri Sep 27 18:33:23 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: add two GC tuning environment variables.
- RUBY_GC_MALLOC_LIMIT_MAX and RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR.
- See r43067 for details.
-
- * gc.c (rb_gc_set_params): refactoring. And change verbose notation.
- Mostly duplicated functions get_envparam_int/double is not cool.
- Please rewrite it.
-
- * test/ruby/test_gc.rb: fix a test for this change.
-
-Fri Sep 27 17:44:41 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (GC_MALLOC_LIMIT): 8,000,000 -> 8 * 1,024 * 1,024.
-
-Fri Sep 27 17:19:39 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_before_sweep): cast to size_t to suppress warnings.
-
-Fri Sep 27 17:07:55 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: add some fine-grained profiling codes to tuning marking phase.
- If you enable RGENGC_PRINT_TICK to 1, then profiling results by RDTSC
- (on x86/amd64 environment) are printed at last.
- Thanks Yoshii-san.
-
-Fri Sep 27 16:32:27 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: simplify threshold of GC caused by malloc_increase.
- Now, malloc_limit is increased/decreased by mysterious logic.
- This fix simplify malloc_limit increase/decrease logic such as:
- if (malloc_increase > malloc_limit) /* so many malloc */
- malloc_limit += malloc_limit * (GC_MALLOC_LIMIT_FACTOR-1);
- else
- malloc_limit -= malloc_limit * (GC_MALLOC_LIMIT_FACTOR-1)/4;
- Default value of GC_MALLOC_LIMIT_FACTOR is 1.8.
- malloc_limit is bounded by GC_MALLOC_LIMIT_MAX (256MB by default).
- This logic runs at gc_before_sweep(). So there are no effect from
- caused by lazy sweep. And we can remove malloc_increase2.
-
- * gc.c (HEAP_MIN_SLOTS, FREE_MIN, HEAP_GROWTH_FACTOR): rename to
- GC_HEAP_MIN_SLOTS, GC_FREE_MIN, GC_HEAP_GROWTH_FACTOR respectively.
- Check them by `#ifndef' so you can specify these values outside gc.c.
-
- * gc.c (ruby_gc_params_t): add initial_malloc_limit_factor and
- initial_malloc_limit_max.
-
- * gc.c (vm_malloc_prepare, vm_xrealloc): use vm_malloc_increase to
- add and check malloc_increase.
-
-Fri Sep 27 01:05:00 2013 Zachary Scott <e@zzak.io>
-
- * re.c: [DOC] arguments of Regexp::union receive #to_regexp [Bug #8205]
-
-Fri Sep 27 00:39:27 2013 Zachary Scott <e@zzak.io>
-
- * struct.c: [DOC] grammar of ArgumentError in Struct.new [Bug #8936]
- Patch by Prathamesh Sonpatki
-
-Thu Sep 26 22:11:56 2013 Zachary Scott <e@zzak.io>
-
- * ext/bigdecimal/bigdecimal.c: [DOC] several fixes by @chastell
- This includes fixing the capitalization of Infinity, return value of
- example "BigDecimal.new('NaN') == 0.0", and code style in example.
- [Fixes GH-398] https://github.com/ruby/ruby/pull/398
-
-Thu Sep 26 22:08:11 2013 Zachary Scott <e@zzak.io>
-
- * lib/observer.rb: [DOC] syntax improvement in example by @chastell
- [Fixes GH-400] https://github.com/ruby/ruby/pull/400
-
-Thu Sep 26 22:03:15 2013 Zachary Scott <e@zzak.io>
-
- * ext/digest/digest.c: [DOC] typo in overview by @chastell
- [Fixes GH-399] https://github.com/ruby/ruby/pull/399
-
-Thu Sep 26 22:00:42 2013 Zachary Scott <e@zzak.io>
-
- * ext/openssl/ossl.c: [DOC] typo in example by @zoranzaric
- [Fixes GH-401] https://github.com/ruby/ruby/pull/401
-
-Thu Sep 26 21:07:49 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-electric.el (ruby-electric-delete-backward-char): Add
- support for smartparens-mode.
-
- * misc/ruby-electric.el (ruby-electric-cua-replace-region-maybe)
- (ruby-electric-cua-delete-region-maybe): New functions that
- combine `ruby-electric-cua-*-region` with
- `ruby-electric-cua-*-region-p`, using a slightly better way to
- detect if it is in cua-mode.
-
-Thu Sep 26 16:51:00 2013 Shota Fukumori <her@sorah.jp>
-
- * insns.def (opt_regexpmatch2): Check String#=~ hasn't overridden
- before calling rb_reg_match().
-
- * test/ruby/test_string.rb: Test for above.
-
- * vm.c (vm_init_redefined_flag): Add BOP flag for String#=~
-
- [ruby-core:57385] [Bug #8953]
-
-Thu Sep 26 16:43:42 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-electric.el: Avoid use of the interactive function
- `self-insert-command` which fires `post-self-insert-hook` and
- `post-command-hook`, to make the ruby-electric commands work
- nicely with those minor modes that make use of them to do
- similar input assistance, such as electric-pair-mode,
- autopair-mode and smartparens-mode.
-
-Thu Sep 26 16:24:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * insns.def (opt_regexpmatch1): check Regexp#=~ is not defined before
- calling rb_reg_match()
-
- * test/ruby/test_regexp.rb: add test
-
- * vm.c (ruby_vm_redefined_flag): change type to short[]
-
- * vm.c (vm_redefinition_check_flag): return REGEXP_REDEFINED_OP_FLAG if
- klass == rb_cRegexp
-
- * vm.c (vm_init_redefined_flag): setup BOP flag for Regexp#=~
-
- * vm_insnhelper.h: add REGEXP_REDEFINED_OP_FLAG
-
- [ruby-core:57385] [Bug #8953]
-
-Thu Sep 26 14:46:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (mark_locations_array): disable AddressSanitizer. based on a
- patch by halfie (Ruby Guy) at [ruby-core:57372].
- [ruby-core:56155] [Bug #8680]
-
-Wed Sep 25 17:41:29 2013 Koichi Sasada <ko1@atdot.net>
-
- * README.EXT, README.EXT.ja: remove description of RARRAY_PTR()
- and add a caution of accessing internal data structure directly.
- Also add a description of rb_ary_store().
- [Bug #8399]
-
-Wed Sep 25 17:12:08 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: rename RARRAY_RAWPTR() to RARRAY_CONST_PTR().
- RARRAY_RAWPTR(ary) returns (const VALUE *) type pointer and
- usecase of this macro is not acquire raw pointer, but acquire
- read-only pointer. So we rename to better name.
- RSTRUCT_RAWPTR() is also renamed to RSTRUCT_CONST_PTR()
- (I expect that nobody use it).
-
- * array.c, compile.c, cont.c, enumerator.c, gc.c, proc.c, random.c,
- string.c, struct.c, thread.c, vm_eval.c, vm_insnhelper.c:
- catch up this change.
-
-Wed Sep 25 16:58:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * internal.h (rb_float_value, rb_float_new): move inline functions
- from ruby/ruby.h.
-
- * numeric.c (rb_float_value, rb_float_new): define external functions
- for extension libraries.
-
-Wed Sep 25 15:37:02 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/rdoc/test_rdoc_generator_darkfish.rb: add a guard for windows.
-
-Wed Sep 25 09:53:11 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Fix CVE-2013-4363. Miscellaneous minor improvements.
-
- * test/rubygems: Tests for the above.
-
-Tue Sep 24 17:38:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_inspect): get rid of out-of-bound access.
-
- * string.c (rb_str_inspect): when a UTF-16/32 string doesn't have a
- BOM, inspect as a dummy encoding string.
-
-Tue Sep 24 17:15:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enc/encdb.c (ENC_DUMMY_UNICODE): make BOM-encodings dummy.
-
- * encoding.c (enc_autoload): keep dummy encodings dummy.
-
-Tue Sep 24 16:41:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32/lib/win32/registry.rb (Win32::Registry#write): data size
- is in bytes, not chars. terminators should be placed automatically.
-
-Tue Sep 24 16:39:36 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32/lib/win32/registry.rb (Win32::Registry#each_value): encode
- name.
-
- * ext/win32/lib/win32/registry.rb (Win32::Registry#each_key): ditto.
-
- * ext/win32/lib/win32/registry.rb (Win32::Registry#export_string):
- encode to locale encoding if default internal is not set.
-
-Tue Sep 24 16:35:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32/lib/win32/registry.rb (Win32::Registry::API#EnumKey):
- size of the name is in WCHARs, not in bytes.
-
-Tue Sep 24 14:07:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * gc.c (free_method_cache_entry_i): unused function
-
- * gc.c (rb_free_mc_table): ditto
-
- * internal.h (method_cache_entry_t): unused struct
-
- * vm_method.c (verify_method_cache): remove unused variable
-
- * vm_method.c (rb_method_entry): ditto
-
-Tue Sep 24 14:01:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * class.c (class_alloc): remove mc_tbl
-
- * gc.c (obj_free): ditto
-
- * internal.h (struct rb_classext_struct): ditto
-
- * method.h (rb_method_entry): remove ent param
-
- * vm_method.c: restore the global method cache. Per class cache tables
- turned out to be far too slow.
-
- [ruby-core:57289] [Bug #8930]
-
-Tue Sep 24 12:51:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32/lib/win32/registry.rb (Win32::Registry::API): need
- Constants.
-
- * ext/win32/lib/win32/registry.rb (Win32::Registry::API#EnumValue):
- size of the name is in WCHARs, not in bytes.
-
-Mon Sep 23 22:16:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enc/encdb.c, enc/utf_16_32.h (ENC_DUMMY_UNICODE): Unicode with BOM
- must be based on big endian variants, so that actual encodings would
- work. [ruby-core:57318] [Bug #8940]
-
-Mon Sep 23 12:11:26 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (env_each_pair): do not call rb_assoc_new() if
- it isn't needed.
-
-Mon Sep 23 10:42:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/ruby/test_module.rb (TestModule#test_include_toplevel): test
- for top level main.include. based on a part of the patch by
- kyrylo at [GH-395].
-
-Mon Sep 23 05:07:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/intern.h (rb_ary_cat): move from internal.h, since it
- is described in README.EXT.
-
-Sun Sep 22 20:55:20 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * vm_insnhelper.c (vm_make_proc_with_iseq): fix bug message.
- This is follow up to changes in r42637.
-
-Sun Sep 22 20:35:38 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * ext/-test-/tracepoint/tracepoint.c (Init_tracepoint): prevent from GC.
-
-Sun Sep 22 19:00:28 2013 Benoit Daloze <eregontp@gmail.com>
-
- * benchmark/bm_app_answer.rb: revert r42990, benchmark scripts should
- be self-contained and avoid dependencies, especially such small one.
- See https://github.com/ruby/ruby/pull/393#issuecomment-24861301.
-
-Sat Sep 21 20:11:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * process.c (rb_fork_internal): remove cloexec setting on pipes
- created by rb_cloexec_pipe. patch by normalperson (Eric Wong) at
- [ruby-core:56523]. [Bug #8769]
-
-Sat Sep 21 01:04:25 2013 Zachary Scott <e@zzak.io>
-
- * lib/benchmark.rb: [DOC] grammar of Benchmark#bm [Bug #8888]
- Patch by Prathamesh Sonpatki
-
-Sat Sep 21 00:50:02 2013 Zachary Scott <e@zzak.io>
-
- * enumerator.c: [DOC] Enumerator#each arguments documentation [GH-388]
- Patch by @kachick https://github.com/ruby/ruby/pull/388
-
-Sat Sep 21 00:49:16 2013 Zachary Scott <e@zzak.io>
-
- * enum.c: [DOC] Enumerable#to_a accepts arguments [GH-388]
- Patch by @kachick https://github.com/ruby/ruby/pull/388
-
-Sat Sep 21 00:47:44 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_conv_enc_opts): make sure to scan coderange to get
- rid of unnecessary conversion.
-
-Sat Sep 21 00:21:08 2013 Zachary Scott <e@zzak.io>
-
- * ext/openssl/lib/openssl/ssl.rb: [DOC] Document OpenSSL::SSLServer
- Based on a patch by Rafal Lisowski [Bug #8758]
-
-Fri Sep 20 23:54:03 2013 Zachary Scott <e@zzak.io>
-
- * lib/gserver.rb: [DOC] correct gserver.rb license [Bug #8913]
-
-Fri Sep 20 23:48:34 2013 Zachary Scott <e@zzak.io>
-
- * ext/psych/yaml/yaml.h: [DOC] merge upstream typo fix by @GreenGeorge
- https://github.com/tenderlove/psych/pull/161
-
-Fri Sep 20 23:37:40 2013 Zachary Scott <e@zzak.io>
-
- * lib/securerandom.rb: [DOC] SecureRandom.hex length argument
- [Fixes GH-394] Patch by @avdi https://github.com/ruby/ruby/pull/394
-
-Fri Sep 20 23:34:48 2013 Zachary Scott <e@zzak.io>
-
- * benchmark/bm_app_answer.rb: removed duplicate code [Fixes GH-393]
- Patch by @gouravtiwari https://github.com/ruby/ruby/pull/393
-
-Fri Sep 20 23:24:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (btest, btest-ruby, test-knownbug): add $(RUN_OPTS) to
- ruby to be run, so that tests are runnable before making exts.
-
- * common.mk (test-sample): ditto, and use $(MINIRUBY) as rubytest.rb
- does not need extension libraries.
-
- * tool/rubytest.rb: pass $(RUN_OPTS) to testing ruby using --run-opt.
-
-Fri Sep 20 15:01:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (intern_str): sigil only names are junk, at least one
- identifier character is needed. [ruby-dev:47723] [Bug #8928]
-
- * parse.y (rb_enc_symname_type): fix out of bound access.
-
-Fri Sep 20 14:14:32 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/-test-/printf/printf.c (printf_test_call): Fix an end of buffer
- argument.
-
-Thu Sep 19 16:59:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (lambda): adjust position to the beginning of the block.
-
-Thu Sep 19 16:25:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vsnprintf.c (BSD_vfprintf): initialize cp so that size is 0 in the
- commented case. fix an accidental bug at r16716.
-
-Thu Sep 19 14:33:14 2013 Koichi Sasada <ko1@atdot.net>
-
- * NEWS: add a news for r42974.
-
-Thu Sep 19 14:12:02 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: make Symbol objects frozen.
- [Feature #8906]
- I want to freeze this good day, too.
-
- * test/ruby/test_eval.rb: catch up this change.
-
- * test/ruby/test_symbol.rb: add a test to check frozen symbols.
-
-Thu Sep 19 09:11:33 2013 Eric Hodel <drbrain@segment7.net>
-
- * NEWS: Update for RDoc 4.1.0.preview.1 and RubyGems 2.2.0.preview.1
-
-Thu Sep 19 08:59:41 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rdoc/markdown/literals_1_9.rb: Fix trailing whitespace.
-
- Previously kpeg (which generates this file) added trailing
- whitespace, but this bug is now fixed.
-
- * lib/rdoc/markdown.rb: ditto.
-
-Thu Sep 19 08:33:14 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rdoc: Update to RDoc 4.1.0.preview.1
-
- RDoc 4.1.0 contains a number of enhancements including a new default
- style and accessibility support. You can see the changelog here:
-
- https://github.com/rdoc/rdoc/blob/v4.1.0.preview.1/History.rdoc
-
- * test/rdoc: ditto.
-
-Thu Sep 19 07:16:26 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych.rb: updating Psych version
-
- * ext/psych/psych.gemspec: ditto
-
-Thu Sep 19 06:39:40 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/dependency_resolver.rb: Switch the iterative resolver
- algorithm from recursive to iterative to avoid possible
- SystemStackError.
-
-Thu Sep 19 06:29:30 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems 2.2.0.preview.1
-
- This brings several new features to RubyGems summarized here:
-
- https://github.com/rubygems/rubygems/blob/v2.2.0.preview.1/History.txt
-
- * test/rubygems: ditto.
-
-Wed Sep 18 23:14:58 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * string.c (rb_str_enumerate_lines): make String#each_line and
- #lines not raise invalid byte sequence error when it is called
- with an argument. The patch also causes performance improvement.
- [ruby-dev:47549] [Bug #8698]
-
- * test/ruby/test_m17n_comb.rb (test_str_each_line): remove
- assertions which check that String#each_line and #lines will
- raise an error if the receiver includes invalid byte sequence.
-
-Wed Sep 18 16:32:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (mnew_from_me): allocate structs after allocated wrapper
- object successfully, to get rid of potential memory leak.
-
-Tue Sep 17 15:54:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/shell/command-processor.rb (Shell::CommandProcessor#find_system_command):
- return executable file only, should ignore directories and
- unexecutable files. [ruby-core:57235] [Bug #8918]
-
- * lib/test/unit/assertions.rb (Test::Unit::Assertions#assert_throw):
- assertion for throw. MiniTest::Assertions#assert_throws discards
- the caught value.
-
- * lib/test/unit/assertions.rb (Test::Unit::Assertions#assert_nothing_thrown):
- returns the result of the given block.
-
-Tue Sep 17 12:55:58 2013 Eric Hodel <drbrain@segment7.net>
-
- * doc/regexp.rdoc: [DOC] Replace paragraphs in verbatim sections with
- plain paragraphs to improve readability as ri and HTML.
-
-Mon Sep 16 07:32:35 2013 Tadayoshi Funaba <tadf@dotrb.org>
-
- * complex.c: removed meaningless lines.
- * rational.c: ditto.
-
-Mon Sep 16 00:44:23 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * ext/socket/mkconstants.rb: define MSG_FASTOPEN.
- [ruby-core:57138] [Feature #8897]
-
-Sun Sep 15 13:31:23 2013 Tadayoshi Funaba <tadf@dotrb.org>
-
- * rational.c (nurat_div): reverted r28844, r28886 and r28887.
- REASON: Nobuyoshi Nakada <nobu@ruby-lang.org>'s commits are buggy.
- So Rational#/ may produce exact number with inexact number.
- Moreover, without reducing.
- REALLY NONSENSE COMMITS.
- A bug report by me [ruby-dev:44710] is also caused by this behavior.
- Kenta Murata <mrkn@mrkn.jp> patched it up.
- But he did not fix the origin.
- Today, the bug is still alive in ruby 1.9.3 and 2.0.0.
-
-Sat Sep 14 06:08:10 2013 Eric Hodel <drbrain@segment7.net>
-
- * dir.c (dir_s_glob): [DOC] Improve wording and layout.
-
- * dir.c (file_s_fnmatch): ditto.
-
- * dir.c (Init_Dir): [DOC] Document File::Constants::FNM_XXX
- constants. (These won't show up in RDoc until a new RDoc is
- imported.)
-
-Thu Sep 12 14:58:58 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/generic.rb (URI::Generic.find_proxy): return nil if
- http_proxy environment variable is empty string.
- [ruby-core:57140] [Bug #8898]
-
-Fri Sep 13 10:40:28 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems 2.1.3
-
- Fixed installing platform gems
-
- Restored concurrent requires
-
- Fixed installing gems with extensions with --install-dir
-
- Fixed `gem fetch -v` to install the latest version
-
- Fixed installing gems with "./" in their files entries
-
- * test/rubygems/test_gem_package.rb: Tests for the above.
-
- * NEWS: Updated for RubyGems 2.1.3
-
-Thu Sep 12 22:40:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (RUBY_CHECK_SIGNEDNESS): macro to check signedness of a
- type.
-
- * configure.in (size_t): must be unsigned.
- [ruby-core:57149] [Feature #8890]
-
-Thu Sep 12 22:37:08 2013 Anton Ovchinnikov <revolver112@gmail.com>
-
- * ext/bigdecimal/bigdecimal.c, ext/digest/md5/md5.c,
- ext/json/fbuffer/fbuffer.h, ext/json/generator/generator.c:
- Eliminate less-than-zero checks for unsigned variables.
- According to section 4.1.5 of C89 standard, size_t is an unsigned
- type. These checks were found with 'cppcheck' static analysis tool.
- [ruby-core:57117] [Feature #8890]
-
-Thu Sep 12 21:35:46 2013 Naohisa Goto <ngotogenome@gmail.com>
-
- * Makefile.in (libruby-static.a): change LDFLAGS order. LDFLAGS may
- include library path that should be specified before LIBS.
- [ruby-dev:47707] [Bug #8901]
-
-Thu Sep 12 20:07:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vsnprintf.c (MAXEXP, MAXFRACT): calculate depending on constants in
- float.h.
-
- * vsnprintf.c (BSD_vfprintf): limit length for cvt() to get rid of
- buffer overflow. [ruby-core:57023] [Bug #8864]
-
- * vsnprintf.c (exponent): make expbuf size more precise.
-
-Wed Sep 11 17:30:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (RUNRUBY): append -- only after runruby.rb, not
- cross-compiling baseruby, so that $(RUN_OPT) can be command line
- options. [ruby-dev:47703] [Bug #8893]
-
-Wed Sep 11 07:55:17 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread.c (rb_mutex_unlock): Mutex#unlock no longer raise
- an exception even if uses on trap. [Bug #8891]
-
-Tue Sep 10 14:37:01 2013 Shota Fukumori <sorah@tubusu.net>
-
- * vm_backtrace.c (vm_backtrace_to_ary): Ignore the second argument if
- it is nil. [Bug #8884] [ruby-core:57094]
-
- * test/ruby/test_backtrace.rb (test_caller_with_nil_length):
- Test for above.
-
-Tue Sep 10 12:39:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (method_entry_i): should exclude refined methods from
- instance method list. [ruby-core:57080] [Bug #8881]
-
-Tue Sep 10 12:05:04 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * io.c (rb_f_printf): [DOC] add missing parenthesis in rdoc.
-
-Tue Sep 10 10:08:00 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * NEWS: Update RubyGems note.
-
-Tue Sep 10 09:51:22 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems 2.1.0. Fixes CVE-2013-4287.
-
- See http://rubygems.rubyforge.org/rubygems-update/CVE-2013-4287_txt.html
- for CVE information.
-
- See http://rubygems.rubyforge.org/rubygems-update/History_txt.html#label-2.1.0+%2F+2013-09-09
- for release notes.
-
- * test/rubygems: Tests for the above.
-
-Mon Sep 9 21:31:45 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c: Remove spaces between SI prefix and unit to follow
- SI brochure.
- http://www.bipm.org/en/si/si_brochure/
- https://www.nmij.jp/library/units/si/
-
- * time.c: Ditto.
-
- * ext/socket/ancdata.c: Ditto.
-
-Mon Sep 9 16:55:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_method.c (rb_add_refined_method_entry): clear cache in the
- refined class since refining a method entry is modifying the class.
- [ruby-core:57079] [Bug #8880]
-
-Mon Sep 9 09:14:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/rbinstall.rb (Gem::Specification#initialize): default date to
- RUBY_RELEASE_DATE. [ruby-core:57072] [Bug #8878]
-
- * tool/rbinstall.rb (Gem::Specification#to_ruby): add date.
-
-Sun Sep 8 16:01:54 2013 Tanaka Akira <akr@fsij.org>
-
- * rational.c (f_gcd): Relax the condition to use GMP.
-
-Sun Sep 8 13:56:38 2013 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (folevariant_initialize): check type of
- element of array.
-
- * test/win32ole/test_win32ole_variant.rb (test_s_new_ary): ditto.
-
-Sat Sep 7 21:33:10 2013 Tanaka Akira <akr@fsij.org>
-
- * math.c (math_log): Test the sign for bignums.
- (math_log2): Ditto.
- (math_log10): Ditto.
-
-Sat Sep 7 20:25:47 2013 Tanaka Akira <akr@fsij.org>
-
- * math.c (math_log): Support bignums bigger than 2**1024.
- (math_log2): Ditto.
- (math_log10): Ditto.
-
-Sat Sep 7 15:36:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * vm_eval.c (vm_call0): fix prototype, the id parameter should be of
- type ID, not VALUE
-
- * vm_insnhelper.c (check_match): the rb_funcall family of functions
- does not care about refinements. We need to use
- rb_method_entry_with_refinements instead to call === with
- refinements. Thanks to Jon Conley for reporting this bug.
- [ruby-core:57051] [Bug #8872]
-
- * test/ruby/test_refinement.rb: add test
-
-Sat Sep 7 13:49:40 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * variable.c (classname): the name of class that has
- non class id should not be nil. This bug was introduced
- in r36577.
-
- * test/thread/test_cv.rb: test for change.
-
-Sat Sep 7 13:29:22 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * lib/find.rb (Find.find): respect the encodings of arguments.
- [ruby-dev:47530] [Feature #8657]
-
- * test/test_find.rb: add tests.
-
-Sat Sep 7 10:40:32 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/mkconstants.rb (TCP_FASTOPEN): Defined for TCP fast open.
- [ruby-core:57048] [Feature #8871] patch by Masaki Matsushita.
-
-Fri Sep 6 23:53:31 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * common.mk: use RUNRUBY instead of MINIRUBY because MINIRUBY can't
- require extension libraries. The patch is from nobu
- (Nobuyoshi Nakada).
-
- * ext/thread/extconf.rb: for build ext/thread/thread.c.
-
- * include/ruby/intern.h: ditto.
-
- * thread.c: ditto.
-
- * lib/thread.rb: removed and replaced by ext/thread/thread.c.
-
- * ext/thread/thread.c: Queue, SizedQueue and ConditionVariable
- implementations in C. This patch is based on patches from panaggio
- (Ricardo Panaggio) and funny_falcon (Yura Sokolov) and ko1
- (Koichi Sasada). [ruby-core:31513] [Feature #3620]
-
- * test/thread/test_queue.rb (test_queue_thread_raise): add a test for
- ensuring that killed thread should be removed from waiting threads.
- It is based on a code by ko1 (Koichi Sasada). [ruby-core:45950]
-
-Fri Sep 6 22:47:12 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Define ac_cv_func_clock_getres to yes for mingw*.
-
-Fri Sep 6 21:04:10 2013 Tanaka Akira <akr@fsij.org>
-
- * rational.c: Include gmp.h if GMP is used.
- (GMP_GCD_DIGITS): New macro.
- (rb_gcd_gmp): New function.
- (f_gcd_normal): Renamed from f_gcd.
- (rb_gcd_normal): New function.
- (f_gcd): Invoke rb_gcd_gmp or f_gcd_normal.
-
- * internal.h (rb_gcd_normal): Declared.
- (rb_gcd_gmp): Ditto.
-
- * ext/-test-/rational: New directory.
-
- * test/-ext-/rational: New directory.
-
-Fri Sep 6 14:23:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (clock_getres): required as well as clock_gettime().
- [ruby-dev:47699] [Bug #8869]
-
-Fri Sep 6 11:45:27 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * transcode.c (rb_econv_append): new function to append a string data
- with converting its encoding. split from rb_econv_substr_append.
-
-Fri Sep 6 02:37:22 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb: use double quotes when
- strings start with special characters.
- https://github.com/tenderlove/psych/issues/157
-
- * test/psych/test_string.rb: test for change.
-
-Fri Sep 6 00:05:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (rewrite_cref_stack): remove recursion.
-
-Thu Sep 5 18:05:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * string.c (fstring_cmp): take string encoding into account when
- comparing fstrings [ruby-core:57037] [Bug #8866]
-
- * test/ruby/test_string.rb: add test
-
-Thu Sep 5 17:25:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_fstring, rb_str_free): use st_data_t instead of VALUE.
-
- * string.c (rb_fstring): get rid of duplicating already frozen object.
-
-Thu Sep 5 14:01:22 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/optparse.rb: The Integer acceptable now allows binary and
- hexadecimal numbers per the documentation. [ruby-trunk - Bug #8865]
-
- DecimalInteger, OctalInteger, DecimalNumeric now validate their input
- before converting to a number. [ruby-trunk - Bug #8865]
-
- * test/optparse/test_acceptable.rb: Tests for the above, tests for all
- numeric acceptables for existing behavior.
-
-Thu Sep 5 13:49:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * include/ruby/ruby.h: add RSTRING_FSTR flag
-
- * internal.h: add rb_fstring() prototype
-
- * string.c (rb_fstring): deduplicate frozen string literals
-
- * string.c (rb_str_free): delete fstrings from frozen_strings table when
- they are GC'd
-
- * string.c (Init_String): initialize frozen_strings table
-
-Thu Sep 5 12:48:00 2013 Kenta Murata <mrkn@cookpad.com>
-
- * configure.in (with_gmp): set with_gmp no if it is empty.
-
-Thu Sep 5 10:41:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * vm_insnhelper.c (vm_getivar): use class sequence to check class
- identity, instead of pointer + vm state
-
- * vm_insnhelper.c (vm_setivar): ditto
-
-Thu Sep 5 08:20:58 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (GMP_DIV_DIGITS): New macro.
- (bary_divmod_gmp): New function.
- (rb_big_divrem_gmp): Ditto.
- (bary_divmod_branch): Ditto.
- (bary_divmod): Use bary_divmod_branch.
- (bigdivrem): Ditto.
-
- * internal.h (rb_big_divrem_gmp): Declared.
-
-Thu Sep 5 06:22:42 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_divmod_normal): Reduce temporary array allocations.
-
-Thu Sep 5 02:17:06 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_divrem_normal): Add GC guards.
-
-Thu Sep 5 00:38:32 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_divrem_normal): New function.
-
- * internal.h (rb_big_divrem_normal): Declared.
-
- * ext/-test-/bignum/div.c: New file.
-
- * test/-ext-/bignum/test_div.rb: New file.
-
-Thu Sep 5 00:08:44 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem_normal): Removed.
- (bary_divmod_normal): New function.
- (bary_divmod): Use bary_divmod_normal.
- (bigdivrem): Use bary_divmod_normal.
-
-Wed Sep 4 23:02:12 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem): Useless declaration removed.
-
-Wed Sep 4 22:56:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (NUM_STEP_GET_INF): split from NUM_STEP_SCAN_ARGS(), since
- inf is not used in num_step_size().
-
-Wed Sep 4 20:22:43 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem_normal): Add assertions.
-
-Wed Sep 4 19:18:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * internal.h (vm_state_version_t): prefer LONG_LONG to uint64_t.
-
-Wed Sep 4 16:28:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * internal.h (vm_state_version_t): use uint64_t when it is larger than
- LONG_LONG, and fallback to unsigned long.
-
-Wed Sep 4 15:37:05 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * enc/trans/utf8_mac-tbl.rb: fix r42789.
- Fix conversion table and logic. [ruby-dev:47680]
-
-Wed Sep 4 14:08:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * class.c, compile.c, eval.c, gc.h, insns.def, internal.h, method.h,
- variable.c, vm.c, vm_core.c, vm_insnhelper.c, vm_insnhelper.h,
- vm_method.c: Implement class hierarchy method cache invalidation.
-
- [ruby-core:55053] [Feature #8426] [GH-387]
-
-Wed Sep 4 11:13:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (str_gsub): use BEG(0) for whole matched position not
- return value from rb_reg_search(), for \K matching.
- [ruby-dev:47694] [Bug #8856]
-
-Wed Sep 4 11:11:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (SOLIBS): LIBRUBY_SO also needs linking with gmp, to
- run worker processes in test-all on non-ELF platforms.
-
-Tue Sep 3 23:01:41 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/parser/test_tree.rb
- (TestTreeParser::TestInvalid#test_unmatched_close_tag):
- Compute expected value from test value.
-
-Tue Sep 3 22:59:58 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/treeparser.rb (REXML::Parsers::TreeParser#parse):
- Add source information to parse exception on no close tag error.
- [Bug #8844] [ruby-dev:47672]
- Patch by Ippei Obayashi. Thanks!!!
- * test/rexml/parser/test_tree.rb: Add a test for the above case.
-
-Tue Sep 3 22:57:57 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/parser/test_tree.rb: Fix test name to describe test
- content.
-
-Tue Sep 3 22:54:46 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/treeparser.rb (REXML::Parsers::TreeParser#parse):
- Remove needless nested parse exception information.
- [Bug #8844] [ruby-dev:47672]
- Reported by Ippei Obayashi. Thanks!!!
- * test/rexml/parser/test_tree.rb: Add a test for the above case.
-
-Tue Sep 3 22:03:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_enc_str_new_cstr): new function to create a string from
- the C-string pointer with the specified encoding.
-
-Tue Sep 3 21:41:37 2013 Akira Matsuda <ronnie@dio.jp>
-
- * eval.c (Init_eval): Make Module#include and Module#prepend public
- [Feature #8846]
-
- * test/ruby/test_module.rb (class TestModule): Test for above
-
-Tue Sep 3 21:35:19 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread_pthread.c (sys/dyntune.h): for gettune().
-
- * thread_pthread.c (hpux_attr_getstackaddr): fix missing *.
- [ruby-core:56983] [Feature #8793]
-
-Tue Sep 3 20:12:46 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (GMP_STR2BIG_DIGITS): New macro.
- (str2big_gmp): New function.
- (rb_cstr_to_inum): Use str2big_gmp for big bignums.
- (rb_str2big_gmp): New function.
-
- * internal.h (rb_str2big_gmp): Declared.
-
-Tue Sep 3 19:44:40 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/win32/lib/win32/registry.rb (Win32::Registry#values): added.
- [Feature #7763] [ruby-core:51783]
-
-Tue Sep 3 18:26:00 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/inf-ruby.el (inf-ruby-keys, run-ruby): Add magic autoload
- comments.
-
- * misc/rdoc-mode.el (rdoc-mode): Ditto.
-
- * misc/ruby-electric.el (ruby-electric-mode): Ditto.
-
- * misc/ruby-style.el (ruby-style-c-mode): Ditto.
-
-Tue Sep 3 17:06:15 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/ruby/test_rubyoptions.rb
- (TestRubyOptions::SEGVTest::ExpectedStderr): the URL was changed at
- r42800.
-
-Tue Sep 3 14:48:25 2013 Zachary Scott <e@zzak.io>
-
- * lib/thread.rb: [DOC] CV#wait typo by @avdi [Fixes GH-386]
- https://github.com/ruby/ruby/pull/386
-
-Tue Sep 3 14:37:53 2013 Zachary Scott <e@zzak.io>
-
- * error.c: [DOC] Update bug tracker url by @ScotterC [Fixes GH-390]
- https://github.com/ruby/ruby/pull/390
-
-Tue Sep 3 12:45:23 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_str2big_poweroftwo): New function.
- (rb_str2big_normal): Ditto.
- (rb_str2big_karatsuba): Ditto.
-
- * internal.h (rb_str2big_poweroftwo): Declared.
- (rb_str2big_normal): Ditto.
- (rb_str2big_karatsuba): Ditto.
-
- * ext/-test-/bignum/str2big.c: New file.
-
- * test/-ext-/bignum/test_str2big.rb: New file.
-
- * ext/-test-/bignum/depend: Add the dependency for str2big.c.
-
-Tue Sep 3 12:09:08 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_clock_gettime): Support times() based monotonic clock.
- (rb_clock_getres): Ditto.
-
-Tue Sep 3 12:03:02 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (str2big_scan_digits): Extracted from rb_cstr_to_inum.
-
-Tue Sep 3 11:23:57 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (rb_w32_select_with_thread): rounding up the fraction of
- tv_usec instead of rounding down.
- this change is an experiment to get rid of failures on vc10-x64 CI.
-
-Tue Sep 3 11:00:28 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (do_select): constify timeout.
-
- * win32/win32.c (rb_w32_select_with_thread): constify 10ms wait and
- 0ms wait structs.
-
-Tue Sep 3 10:03:42 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/openssl/test_pair.rb
- (OpenSSL::TestPair#test_write_nonblock_no_exceptions): on some CIs
- such as Debian 6.0, Ubuntu 10.04, CentOS and vc10-x64 (maybe depend
- on OpenSSL version), writing to SSLSocket after SSL_ERROR_WANT_WRITE
- causes SSL_ERROR_SSL "bad write retry".
-
-Tue Sep 3 08:20:46 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * enc/trans/utf8_mac-tbl.rb: update conversion table to recent OS X.
- Previous table is used on Mac OS X 10.1 or prior.
- This table is used on 10.2 or later. [ruby-dev:47680]
-
-Tue Sep 3 07:49:25 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * numeric.c (NUM_STEP_SCAN_ARGS): On second thought, keep
- Numeric#step backward compatible in that it raises TypeError
- when nil is given as second argument.
-
- * test/ruby/test_float.rb (TestFloat#test_num2dbl): Revert.
-
- * test/ruby/test_numeric.rb (TestNumeric#test_step): Fix test
- cases for the above change.
-
-Tue Sep 3 07:39:58 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bytes_2comp): Define it only for little endian
- environment.
-
-Tue Sep 3 07:31:29 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * numeric.c (NUM_STEP_SCAN_ARGS): Numeric#step should raise
- TypeError if a non-numeric parameter is given.
-
- * test/ruby/test_float.rb (TestFloat#test_num2dbl): Allow nil as
- step, as with the keyword argument.
-
- * test/ruby/test_numeric.rb (TestNumeric#test_step): Add tests for
- nil as step or limit.
-
-Tue Sep 3 07:28:49 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (bit_length): Add casts to fix compilation error with
- clang 3.0 -Werror,-Wshorten-64-to-32.
- [ruby-dev:47687] reported by SASADA Koichi.
-
-Tue Sep 3 03:17:26 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_insnhelper.c (vm_search_super_method): use ci->argc instead of
- ci->orig_argc. ci->argc can be changed by splat arguments.
- [ruby-list:49575]
- This fix should be applied to Ruby 2.0.0 series.
-
- * test/ruby/test_super.rb: add a test for above.
-
-Mon Sep 2 23:46:29 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * numeric.c (num_step): Default the limit argument to infinity and
- allow it to be omitted. Keyword arguments (by: and to:) are
- introduced for ease of use. [Feature #8838] [ruby-dev:47662]
- [ruby-dev:42194]
-
- * numeric.c (num_step): Optimize for infinite loop.
-
-Mon Sep 2 22:55:59 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (ISDIGIT): Unused macro removed.
-
-Mon Sep 2 22:49:15 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (str2big_poweroftwo): Extracted from rb_cstr_to_inum.
- (str2big_normal): Ditto.
- (str2big_karatsuba): Ditto.
-
-Mon Sep 2 14:39:29 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * ruby.c (Process#setproctitle): [DOC] Fix and improve rdoc.
-
- * ruby.c (Process#argv0): [DOC] Improve rdoc.
-
-Mon Sep 2 14:15:00 2013 Kenta Murata <mrkn@cookpad.com>
-
- * NEWS: fix description of number literal suffixes.
-
-Mon Sep 2 14:01:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * test/rake/test_rake_rules.rb: add space after string literal to
- prevent conflict with string options syntax "foo"opts
-
- * test/rss/rss-assertions.rb: ditto
-
-Mon Sep 2 12:28:38 2013 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_bignum.rb (test_interrupt_during_to_s): Disable it
- when GMP is used.
-
-Mon Sep 2 07:02:10 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (Init_Bignum): Define Bignum::GMP_VERSION when GMP is used.
-
-Mon Sep 2 01:46:14 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_generic): Reduce arguments.
- (big2str_gmp): Ditto.
- (rb_big2str1): Follow the above change.
-
-Mon Sep 2 00:08:08 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (get_mach_timebase_info): Extracted from rb_clock_gettime.
- (rb_clock_gettime): Use get_mach_timebase_info.
- (rb_clock_getres): Support MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC.
-
-Sun Sep 1 23:30:47 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (GMP_BIG2STR_DIGITS): New constant.
- (big2str_gmp): New function.
- (rb_big2str1): Use big2str_gmp for big bignums.
-
- * internal.h (rb_big2str_gmp): Declared.
-
- * ext/-test-/bignum/big2str.c (big2str_gmp): New method.
-
-Sun Sep 1 22:37:51 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul_gmp): Use mpz_init and mpz_clear instead of
- mpz_inits and mpz_clears.
- Older GMP don't have them.
-
-Sun Sep 1 21:17:54 2013 Tanaka Akira <akr@fsij.org>
-
- * test/net/http/test_http.rb (test_bind_to_local_port): Choose an open
- port more reliably.
-
-Sun Sep 1 20:32:40 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_base_poweroftwo): Renamed from
- big2str_base_powerof2.
- (rb_big2str_poweroftwo): New function for test.
- (big2str_generic): Extracted from rb_big2str1.
- (rb_big2str_generic): New function for test.
-
- * internal.h (rb_big2str_poweroftwo): Declared.
- (rb_big2str_generic): Ditto.
-
- * ext/-test-/bignum/big2str.c: New file.
-
- * test/-ext-/bignum/test_big2str.rb: New file.
-
-Sun Sep 1 15:21:21 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_2bdigits): Renamed from big2str_orig.
-
-Sun Sep 1 13:02:24 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: Remove BITSPERDIG >= INT_MAX test. The static assertion,
- SIZEOF_BDIGITS <= sizeof(BDIGIT) is enough.
-
-Sun Sep 1 11:38:26 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (maxpow_in_bdigit): Removed.
-
-Sun Sep 1 10:30:42 2013 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_fix_bit_length): Moved from bignum.c.
-
-Sun Sep 1 09:55:45 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (bit_length): Moved from bignum.c.
- (nlz_int): Ditto.
- (nlz_long): Ditto.
- (nlz_long_long): Ditto.
- (nlz_int128): Ditto.
-
-Sun Sep 1 03:32:22 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bit_length): Renamed from bitsize.
-
-Sun Sep 1 00:07:09 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_bit_length): New method.
- (rb_fix_bit_length): Ditto.
- [ruby-core:56247] [Feature #8700]
-
-Sat Aug 31 22:18:29 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_clock_getres): New method.
- (timetick2dblnum_reciprocal): New function.
-
- * configure.in: Check clock_getres.
-
- [ruby-core:56780] [Feature #8809] accepted as a CRuby feature at
- DevelopersMeeting20130831Japan
- https://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20130831Japan
-
-Sat Aug 31 21:02:07 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: Use GMP to accelerate big Bignum multiplication.
- (bary_mul_gmp): New function.
- (bary_mul): Use bary_mul_gmp.
- (bigsq): Use different threshold with GMP.
-
- * configure.in: Detect GMP.
-
- [ruby-core:56658] [Feature #8796]
-
-Sat Aug 31 15:03:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * compile.c (NODE_MATCH3): pass CALL_INFO to opt_regexpmatch2
-
- * insns.def (opt_regexpmatch2): use CALL_SIMPLE_METHOD to call =~ if
- the receiver is not a T_STRING [Bug #8847] [ruby-core:56916]
-
-Sat Aug 31 14:07:11 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/securerandom.rb (random_bytes): Use Process.clock_gettime.
-
-Sat Aug 31 00:25:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/encoding.h (rb_{ascii8bit,utf8,usascii}_encindex): get
- rid of conflict with macros defined in internal.h.
-
-Fri Aug 30 22:37:57 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread_pthread.c (native_thread_init_stack): wait the creator thread
- to fill machine stack info, if get_stack_of() is available.
-
- * thread_pthread.c (native_thread_create): fill the created thread
- stack info after starting, if get_stack_of() is available.
-
- * thread_pthread.c (native_thread_create): define attr only if it is
- used, and merge pthread_create() calls.
-
- * thread_pthread.c (get_main_stack): separate function to get stack of
- main thread.
-
-Thu Aug 29 18:05:33 2013 Koichi Sasada <ko1@atdot.net>
-
- * struct.c (rb_struct_define_without_accessor_under): added.
- This function is similar to rb_define_class_under() against
- rb_define_class().
-
- * include/ruby/intern.h: add a declaration of this function.
-
-Thu Aug 29 17:03:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_call_method): a method entry refers the based
- class/module, so should search superclass from the origin i-class
- where the entry belongs to, to get rid of infinite loop when zsuper
- in a prepended class/module. [ruby-core:54105] [Bug #8238]
-
-Thu Aug 29 05:35:58 2013 Eric Hodel <drbrain@segment7.net>
-
- * ext/zlib/zlib.c (zstream_run): Fix handling of deflate streams that
- need a dictionary but are being decompressed by Zlib::Inflate.inflate
- (which has no option to set a dictionary). Now Zlib::NeedDict is
- raised instead of crashing. [ruby-trunk - Bug #8829]
- * test/zlib/test_zlib.rb (TestZlibInflate): Test for the above.
-
-Thu Aug 29 02:40:45 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/scalar_scanner.rb: invalid floats should be
- treated as strings.
- https://github.com/tenderlove/psych/issues/156
-
- * test/psych/test_string.rb: test for change
-
-Wed Aug 28 17:20:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread_pthread.c (hpux_attr_getstackaddr): basic support for the
- get_stack() under HP-UX. based on the patch by michal@rokos.cz
- (Michal Rokos) at [ruby-core:56645]. [Feature #8793]
-
-Wed Aug 28 11:24:20 2013 Michal Rokos <michal@rokos.cz>
-
- * configure.in (sys/pstat.h): fix missing header check for
- missing/setproctitle.c on HP-UX. [ruby-core:56644] [Bug #8792]
-
-Wed Aug 28 04:54:33 2013 Eric Hodel <drbrain@segment7.net>
-
- * ext/openssl/ossl_ssl.c (ossl_ssl_read): Replace duplicate
- wait_writable with wait_readable.
-
-Tue Aug 27 17:18:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/timeout.rb (Timeout#timeout): skip rescue clause only when no
- exception class is given.
-
-Tue Aug 27 17:02:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (copy_stream_body): should write in binary mode. based on a
- patch by godfat (Lin Jen-Shin) at [ruby-core:56556].
- [ruby-core:56518] [Bug #8767]
-
-Tue Aug 27 17:02:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (copy_stream_body): move common open flags.
-
-Tue Aug 27 16:56:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enumerator.c (enumerator_size): use rb_check_funcall() instead of
- respond_to? and call.
-
- * enumerator.c (enumerator_each): ensure that argument array size
- does not overflow at appending.
-
-Tue Aug 27 16:46:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_index, rb_ary_rindex): use optimized equality to
- improve performance. [Feature #8820]
-
- * vm_insnhelper.c (rb_equal_opt): optimized equality function.
-
-Tue Aug 27 16:11:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (opt_eq_func): use RBASIC_CLASS() instead of HEAP_CLASS_OF().
-
- * insns.def (opt_plus, opt_minus, opt_mult, opt_div, opt_mod, opt_lt),
- (opt_gt, opt_ltlt, opt_aref, opt_aset, opt_length, opt_size),
- (opt_empty_p, opt_succ): ditto.
-
-Tue Aug 27 16:08:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (rb_check_funcall, rb_check_funcall_with_hook): constify
- argv.
-
-Tue Aug 27 13:03:33 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/stringio/stringio.c (strio_read_nonblock): declare local
- variables at the first of function.
-
-Tue Aug 27 11:51:37 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * enumerator.c: Allow Enumerator size argument to be any callable.
- Patch by Avdi Grimm. [bug #8641] [ruby-core:56032] [fix GH-362]
-
- * test/ruby/test_enumerator.rb: Test for above
-
-Tue Aug 27 11:46:31 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_profile_clear): do rest_sweep() before clearing
- profile.current_record.
-
-Tue Aug 27 07:35:05 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * io.c (io_read_nonblock): support non-blocking reads without raising
- exceptions. As in: `io.read_nonblock(size, exception: false)`
- [ruby-core:38666] [Feature #5138]
- * ext/openssl/ossl_ssl.c (ossl_ssl_read_internal): ditto
- * ext/stringio/stringio.c (strio_sysread): ditto
- * io.c (rb_io_write_nonblock): support non-blocking writes without
- raising an exception.
- * ext/openssl/ossl_ssl.c (ossl_ssl_write_internal): ditto
- * test/openssl/test_pair.rb (class OpenSSL): tests
- * test/ruby/test_io.rb (class TestIO): ditto
- * test/socket/test_nonblock.rb (class TestSocketNonblock): ditto
- * test/stringio/test_stringio.rb (class TestStringIO): ditto
-
-Tue Aug 27 05:24:34 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Import RubyGems 2.1.0 Release Candidate
- * test/rubygems: ditto.
-
-Mon Aug 26 16:24:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_nextc): warn carriage return in middle of line.
- [ruby-core:56240] [Feature #8699]
-
-Mon Aug 26 15:27:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/timeout.rb (Timeout#timeout): should not be caught by rescue
- clause. [Bug #8730]
-
-Mon Aug 26 14:44:26 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (rb_ary_splice): use RARRAY_PTR_USE() without WB because
- there are not new relations.
-
- * enum.c (enum_sort_by): ditto.
-
- * struct.c (setup_struct): use RARRAY_RAWPTR().
-
- * vm_eval.c (yield_under): ditto.
-
- * ext/pathname/pathname.c (path_entries): use RARRAY_AREF().
-
- * ext/pathname/pathname.c (path_s_glob): ditto.
-
-Mon Aug 26 13:11:10 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * array.c (ary_ensure_room_for_push): fix typo in r42658.
-
-Mon Aug 26 12:37:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * template/sizes.c.tmpl: generate automatically by extracting
- RUBY_CHECK_SIZEOF from configure.in.
-
-Mon Aug 26 10:16:59 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * process.c (gcd_timetick_int): Renamed from gcd_timtick_int.
-
-Sun Aug 25 21:02:15 2013 Tanaka Akira <akr@fsij.org>
-
- * sizes.c (Init_sizes): Define the size of clock_t.
-
-Sun Aug 25 01:47:47 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (BARY_SHORT_MUL): Renamed from BARY_MUL1.
- (bary_short_mul): Renamed from bary_mul1.
-
-Sat Aug 24 10:35:09 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_clock_gettime): The emulated clock names changed.
-
-Fri Aug 23 22:22:07 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_clock_gettime): Add a cast to fix compile error by
- -Werror,-Wshorten-64-to-32.
-
-Fri Aug 23 22:12:13 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * process.c (rb_intern): no symbol cache while initialization.
-
-Fri Aug 23 22:07:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (clock_t): needs time.h.
-
-Fri Aug 23 21:37:28 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (reduce_factors): New function.
- (timetick2dblnum): Use reduce_factors.
- (timetick2integer): Ditto.
- (make_clock_result): Follow the above change.
- (rb_clock_gettime): Ditto.
-
-Fri Aug 23 21:00:55 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (timetick_int_t): Renamed from timetick_giga_count_t.
- (gcd_timtick_int): Renamed from gcd_ul and make the arguments
- timetick_giga_count_t.
- (reduce_fraction): Make the arguments timetick_int_t.
- (timetick2integer): Ditto.
- (make_clock_result): Ditto.
- (timetick2dblnum): Fix the return type.
- (rb_clock_gettime): Use timetick_int_t.
-
-Fri Aug 23 20:50:40 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (gcd_ul): New function.
- (reduce_fraction): Ditto.
- (reduce_fraction): Ditto.
- (timetick2dblnum): Ditto.
- (timetick2integer): Ditto.
- (make_clock_result): Use timetick2dblnum and timetick2integer.
- (rb_clock_gettime): Follow the make_clock_result change.
-
-Fri Aug 23 18:39:04 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (ary_make_shared): shared ary as shady. Need more effort to
- make it normal object.
-
- * array.c (rb_ary_modify): use RARRAY_PTR_USE() without WB because
- there are not new relations.
-
- * array.c (ary_ensure_room_for_unshift): use RARRAY_RAWPTR() because
- there are not new relations.
-
-Fri Aug 23 11:25:57 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c: introduce ARY_SHARED_OCCUPIED(shared).
-
-Fri Aug 23 11:07:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/Makefile.sub (config.h): now SIZEOF_CLOCK_T is needed for
- unsigned_clock_t.
-
-Thu Aug 22 22:01:04 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_clock_gettime): Strip "s" from unit names.
-
-Thu Aug 22 20:14:59 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (unsigned_clock_t): Defined.
- (rb_clock_gettime): Consider clock_t overflow for
- ISO_C_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID.
-
- * configure.in: Check the size of clock_t.
-
-Thu Aug 22 16:22:48 2013 Koichi Sasada <ko1@atdot.net>
-
- * compile.c (build_postexe_iseq): fix to setup the local table.
-
-Thu Aug 22 15:42:43 2013 Koichi Sasada <ko1@atdot.net>
-
- * compile.c (rb_iseq_compile_node): accept NODE_IFUNC to support
- custom compilation.
-
- * compile.c (NODE_POSTEXE): compile to
- "ONCE{ VMFrozenCore::core#set_postexe{...} }" with a new custom
- compiler `build_postexe_iseq()'.
-
- * vm.c (m_core_set_postexe): remove parameters (passed by a block).
-
-Thu Aug 22 06:54:15 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_clock_gettime): Change emulation symbols for
- Process.clock_gettime.
-
-Thu Aug 22 06:24:54 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (make_clock_result): Extracted from rb_clock_gettime.
-
-Wed Aug 21 22:30:51 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_clock_gettime): clock() based CLOCK_PROCESS_CPUTIME_ID
- emulation implemented.
-
-Wed Aug 21 21:02:37 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_proc_times): Use RB_GC_GUARD to guard objects from GC.
-
-Wed Aug 21 20:33:01 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (get_clk_tck): Extracted from rb_proc_times.
- (rb_clock_gettime): times() based CLOCK_PROCESS_CPUTIME_ID emulation
- is implemented.
-
-Wed Aug 21 19:31:48 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c: POSIX_GETTIMEOFDAY_CLOCK_REALTIME is renamed to
- SUS_GETTIMEOFDAY_CLOCK_REALTIME.
-
-Wed Aug 21 19:17:46 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_clock_gettime): CLOCK_PROCESS_CPUTIME_ID emulation
- using getrusage is implemented.
-
-Wed Aug 21 17:34:27 2013 Tanaka Akira <akr@fsij.org>
-
- * gc.c (getrusage_time): Fallback clock_gettime to getrusage when
- clock_gettime fails.
- Reported by Eric Saxby. [ruby-core:56762] [Bug #8805]
-
-Wed Aug 21 02:32:32 2013 Koichi Sasada <ko1@atdot.net>
-
- * insns.def: fix regexp's once option behavior.
- fix [ruby-trunk - Bug #6701]
-
- * insns.def: remove `onceinlinecache' and introduce `once' instruction.
- `once' doesn't use `setinlinecache' insn any more.
-
- * vm_core.h: `union iseq_inline_storage_entry' to store once data.
-
- * compile.c: catch up above changes.
-
- * iseq.c: ditto.
-
- * vm.c, vm_insnhelper.c: ditto. fix `m_core_set_postexe()' which
- is depend on `onceinlinecache' insn.
-
- * test/ruby/test_regexp.rb: add tests.
-
- * iseq.c: ISEQ_MINOR_VERSION to 1 (should increment major?)
-
-Wed Aug 21 02:30:15 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_gcdebug_print_obj_condition): add printing information.
-
-Tue Aug 20 13:38:00 2013 Naohisa Goto <ngotogenome@gmail.com>
-
- * test/gdbm/test_gdbm.rb: skip TestGDBM#test_s_open_lock on Solaris.
- On Solaris (and platforms which do not have flock and have lockf),
- with GDBM 1.10, gdbm_open(3) blocks when opening already locked
- gdbm file. [Bug #8790] [ruby-dev:47631]
-
-Tue Aug 20 02:32:52 2013 Zachary Scott <e@zzak.io>
-
- * lib/test/: [DOC] Document Test::Unit, hide most submodules and
- classes from rdoc. Since lib/test is only present as a compatibility
- layer with the legacy test suite many test/unit users will be using
- minitest or the test/unit gem instead. It is recommended to use one
- of these alternatives for writing new tests.
-
- This patch was based on a patch submitted by Steve Klabnik.
- [ruby-core:56694] [Bug #8778]
-
-Tue Aug 20 02:10:19 2013 Zachary Scott <e@zzak.io>
-
- * lib/rss/rss.rb: [DOC] Document for constants by Steve Klabnik
- [ruby-core:56705] [Bug #8798]
-
-Tue Aug 20 02:01:10 2013 Zachary Scott <e@zzak.io>
-
- * lib/rss/xmlparser.rb: [DOC] Hide legacy constant from rdoc
- Patch by Steve Klabnik [ruby-core:56708] [Bug #8799]
-
-Tue Aug 20 01:52:05 2013 Zachary Scott <e@zzak.io>
-
- * ext/socket/unixserver.c: [DOC] Document #accept
- * ext/socket/tcpserver.c: ditto
- * ext/socket/udpsocket.c: [DOC] Fix indentation of documentation
- * ext/socket/socket.c: ditto
- Patches by David Rodr'iguez [ruby-core:56734] [Bug #8802]
-
-Tue Aug 20 01:19:22 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Define ac_cv_func_clock_gettime to yes for mingw*.
-
-Mon Aug 19 21:31:35 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/defines.h: Fix a compilation error with
- i586-mingw32msvc-gcc of gcc-mingw32 package on Debian squeeze.
- ruby/missing.h should be included before include/ruby/win32.h
- because struct timespec, used in the clock_gettime declaration in
- include/ruby/win32.h, is defined in ruby/missing.h instead of
- system headers.
-
-Mon Aug 19 20:55:12 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: fix around GC_DEBUG.
-
- * gc.c (RVALUE::line): should be VALUE. On some environment
- (such as mswin64), `int' introduces alignment mismatch.
-
- * gc.c (newobj_of): add an assertion to check VALUE alignment.
-
- * gc.c (aligned_malloc): `&' is low priority than `=='.
-
- * gc.c: define GC_DEBUG everytime and use it as value 0 or 1.
-
-Mon Aug 19 17:43:44 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_fiber.rb: collect garbage fibers immediately.
-
-Mon Aug 19 17:41:49 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/profile_test_all.rb: add `failed?' information.
-
-Mon Aug 19 17:00:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * process.c (retry_fork): retry with GC if ENOMEM occurred, to free
- swap/kernel space.
-
-Mon Aug 19 13:28:47 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * include/ruby/win32.h (CLOCK_MONOTONIC): typo.
-
- * win32/win32.c: removed duplicated declarations.
-
-Mon Aug 19 13:03:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (clock_gettime): should not overwrite cache variable
- with different condition. otherwise -lrt is not linked and the link
- fails, after reconfig.
-
-Mon Aug 19 12:56:49 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (Init_process): Add constants: CLOCK_REALTIME_ALARM and
- CLOCK_BOOTTIME_ALARM.
-
-Sun Aug 18 20:17:41 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * variable.c, vm_method.c: remove dead code.
-
- * test/ruby/test_fiber.rb, test/ruby/test_thread.rb:
- change accordingly.
-
-Sun Aug 18 19:32:26 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * error.c, file.c, gc.c, hash.c, thread.c, variable.c, vm_eval.c, bin/erb:
- $SAFE=4 is obsolete.
-
-Sun Aug 18 14:30:47 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_clock_gettime): Rename POSIX_TIME_CLOCK_REALTIME to
- ISO_C_TIME_CLOCK_REALTIME.
-
-Sun Aug 18 14:22:45 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Revert r42604. It causes linking librt on systems
- with newer glibc uselessly.
-
-Sun Aug 18 13:18:38 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (Init_process): Add constants: CLOCK_REALTIME_COARSE,
- CLOCK_MONOTONIC_COARSE and CLOCK_BOOTTIME.
-
-Sun Aug 18 12:41:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (clock_gettime): need to check with -lrt prior to check
- for the function only. otherwise -lrt is not linked and the link
- fails, when ac_cv_func_clock_gettime is cached as yes.
-
-Sun Aug 18 10:05:12 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big2str1): Make an expression more explicit.
-
-Sun Aug 18 03:18:45 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big2str1): Use power_level instead of bitsize(xn).
-
-Sun Aug 18 00:44:58 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (BIGDIVREM_EXTRA_WORDS): Redefine to 1.
- (bigdivrem_num_extra_words): Removed.
- (bigdivrem_normal): Simplified.
- (big2str_karatsuba): Ditto.
-
-Sat Aug 17 23:25:19 2013 Benoit Daloze <eregontp@gmail.com>
-
- * test/ruby/test_time.rb: use the in_timezone() helper
- and define it at the top with other helpers.
-
-Sat Aug 17 22:20:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * time.c (time_mload): ignore auxiliary data, offset and zone, if
- invalid. [ruby-core:56648] [Bug #8795]
-
-Sat Aug 17 20:11:49 2013 Benoit Daloze <eregontp@gmail.com>
-
- * process.c: [DOC] MACH_ABSOLUTE_TIME_CLOCK_MONOTONIC is an
- available emulation for a monotonic clock on Darwin.
- https://developer.apple.com/library/mac/qa/qa1398/_index.html
-
-Fri Aug 16 18:12:05 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/profile_test_all.rb: fix typo.
-
-Fri Aug 16 18:09:20 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/profile_test_all.rb: remove space characters from test names.
-
-Fri Aug 16 17:32:02 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/profile_test_all.rb: refactoring memory profiling tool for
- test-all.
- Add profiling targets /proc/meminfo and /proc/self/status.
-
- * test/runner.rb: accept other than 'true'.
-
-Fri Aug 16 11:23:35 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * file.c (rb_file_size, rb_file_flock): improve performance of Windows.
-
- * file.c (rb_file_truncate): removed unnecessary #ifdef.
-
- * test/test_file.rb (TestFile#test_truncate_size): added an assertion
- for File#size.
-
-Fri Aug 16 10:07:59 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem_single1): Renamed from bigdivrem_single. Add
- x_higher_bdigit argument.
- (bigdivrem_single): Just call bigdivrem_single1.
- (bigdivrem_restoring): Use bigdivrem_single1 to avoid memmove.
-
-Fri Aug 16 09:17:00 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_small_rshift): Specify the higher BDIGIT instead of
- sign bit.
- (big_shift3): Follow the above change.
-
-Fri Aug 16 02:20:39 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul_toom3): Reduce a branch.
-
-Fri Aug 16 02:14:09 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * process.c (rb_clock_gettime): add CLOCK_MONOTONIC support on OS X.
- http://developer.apple.com/library/mac/qa/qa1398/_index.html
- [Feature #8658]
-
-Fri Aug 16 01:37:43 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem_single): Use shift when y is a power of two.
-
-Fri Aug 16 01:09:33 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem_restoring): Use bigdivrem_single if non-topmost
- BDIGITs of y are zero.
-
-Fri Aug 16 00:33:12 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big2str1): Truncate topmost zeros of x.
-
-Fri Aug 16 00:00:57 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_divmod): Simplify an expression.
-
-Thu Aug 15 23:26:12 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem_normal): Remove a local variable.
-
-Thu Aug 15 23:08:32 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_karatsuba): Use bigdivrem_restoring directly to
- reduce working buffer and memory copy.
- (rb_big2str1): Allocate working buffer for big2str_karatsuba here.
-
-Thu Aug 15 20:51:29 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * io.c, internal.h (rb_io_flush_raw): new function to select calling
- fsync() (on Windows).
-
- * io.c (rb_io_flush_raw): use above function.
-
- * file.c (rb_file_truncate): use above function.
-
- * test/ruby/test_file.rb (TestFile#test_truncate_size): test for
- above changes.
-
-Thu Aug 15 18:39:31 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (clock_gettime): improve precision when freq is less
- than and nearly equals 10**9.
-
-Thu Aug 15 17:43:15 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_lazy_sweep): remove heap_increment() here because heap_inc
- may be 0.
-
-Thu Aug 15 16:59:56 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * io.c (rb_io_rewind): remove fsync() for Windows to improve the
- performance.
-
-Thu Aug 15 16:30:23 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/fileutils/test_fileutils.rb (TestFileUtils#test_rmdir):
- FileUtils.rmdir ignores Errno::ENOTEMPTY, so, in such cases, this
- assertion is nonsense.
-
-Thu Aug 15 15:49:35 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_clock_gettime): [DOC] FreeBSD 7.1 supports
- CLOCK_THREAD_CPUTIME_ID.
- http://www.freebsd.org/releases/7.1R/relnotes.html
-
-Thu Aug 15 14:30:23 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * include/ruby/win32.h, win32/Makefile.sub, win32/win32.c
- (clock_gettime): [experimental] emulates clock_gettime(2) of posix.
-
-Thu Aug 15 02:32:40 2013 Zachary Scott <e@zzak.io>
-
- * hash.c (rb_hash_aset): [DOC] Document key dup patch by @kachick
- [Fixes GH-382] https://github.com/ruby/ruby/pull/382
-
-Wed Aug 14 14:28:39 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * proc.c (rb_mod_define_method): now they return the symbols of the
- defined methods, not the methods/procs themselves.
- [ruby-dev:42151] [Feature #3753]
-
- * NEWS: documents about above change and def-expr (see r42337).
-
- * test/ruby/test_module.rb: tests about above change.
-
-Wed Aug 14 00:51:14 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem_restoring): xn argument removed.
- (bigdivrem_normal): Follow the above change.
-
-Wed Aug 14 00:18:39 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big_div_struct): Remove xn and j field. Add zn field.
- (bigdivrem1): Follow the above change.
- (bigdivrem_restoring): Ditto.
-
-Tue Aug 13 23:38:17 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big_div_struct): ynzero field removed.
- (bigdivrem1): Follow the above change.
- (bigdivrem_restoring): Ditto.
-
-Tue Aug 13 23:01:16 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem_restoring): Extracted from bigdivrem_normal.
-
-Tue Aug 13 22:12:59 2013 Kenichi Kamiya <kachick1@gmail.com>
-
- * random.c (rb_random_ulong_limited): coerce before check negative.
- [Fixes GH-379]
-
-Tue Aug 13 21:52:15 2013 Kenichi Kamiya <kachick1@gmail.com>
-
- * object.c (Init_Object): undef Module#prepend_features on Class, as
- well as Module#append_features. [Fixes GH-376]
-
- * test_class.rb: Added test for above. And ensure type checking
- on similar methods as module_function.
-
-Tue Aug 13 08:52:18 2013 Zachary Scott <e@zzak.io>
-
- * doc/syntax/literals.rdoc: [DOC] String literal concat by @cknadler
- [Fixes GH-380] https://github.com/ruby/ruby/pull/380
-
-Mon Aug 12 23:07:21 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (gc_marks_test): inhibit gc for st's operation.
-
-Mon Aug 12 15:59:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_whole_match_p): treat CR in middle of a line as a
- mere whitespace.
-
-Mon Aug 12 15:16:58 2013 Koichi Sasada <ko1@atdot.net>
-
- * class.c (rb_prepend_module): make T_ICLASS object shady because
- this T_ICLASS object seems to share method table with other class
- objects. It was causes WB miss.
- TODO: need to know the data structure.
-
- * test/ruby/test_module.rb: add a test for WB miss.
-
-Mon Aug 12 13:47:54 2013 Zachary Scott <e@zzak.io>
-
- * process.c: [DOC] RDoc formatting of Process.clock_gettime
-
-Mon Aug 12 13:29:09 2013 Zachary Scott <e@zzak.io>
-
- * lib/yaml/dbm.rb: [DOC] Document call-seq for YAML::DBM
-
-Mon Aug 12 12:57:26 2013 Zachary Scott <e@zzak.io>
-
- * ext/dbm/extconf.rb: [DOC] Hide from RDoc
- Some libraries might want to document extconf.rb so RDoc treats it
- like any other ruby program. However, DBM users shouldn't care about
- these methods.
-
-Mon Aug 12 12:53:39 2013 Zachary Scott <e@zzak.io>
-
- * ext/dbm/dbm.c: [DOC] Reformat headings of DBM class
-
-Mon Aug 12 12:46:31 2013 Zachary Scott <e@zzak.io>
-
- * lib/yaml.rb, lib/yaml/: [DOC] Document YAML::DBM#key and add
- references to similar methods with more detail. This patch brings
- lib/yaml to 100% documentation coverage.
-
-Mon Aug 12 02:51:32 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/readline/readline.c (readline_s_set_input): on OS X with editline,
- Readline.readline doesn't work because readline_get doesn't use
- rl_getc. The difference is introduced by r42402 [ruby-dev:47509]
- [Bug #8644]. Before it rb_io_stdio_file set ifp->stdio_file.
- Therefore add manually setting the value.
-
- * ext/readline/readline.c (readline_s_set_output): ditto.
-
-Sun Aug 11 23:27:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (rb_str_encode_ospath): OS path encoding on Mac OS X is also
- fixed.
-
-Sun Aug 11 22:57:24 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/ruby/test_require.rb (assert_require_nonascii_path): OS path
- encoding on Windows is fixed, so encoding of __FILE__ should be it.
- [ruby-core:56498] [Bug #8764]
-
-Sun Aug 11 19:11:45 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/parser/test_sax2.rb: Expand abbreviated class name.
-
-Sun Aug 11 19:06:03 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/sax2listener.rb (REXML::SAX2Listener#notationdecl): Fix
- wrong number of arguments in the template listener.
- [Bug #8731] [ruby-dev:47582]
- Reported by Ippei Obayashi.
- * test/rexml/parser/test_sax2.rb: Add tests for parsing notation
- declarations with SAX2 API.
-
-Sun Aug 11 18:44:04 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/sax2listener.rb (REXML::SAX2Listener#elementdecl): Fix wrong
- examples. [Bug #8731] [ruby-dev:47582]
- Reported by Ippei Obayashi.
-
-Sun Aug 11 18:42:13 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/sax2parser.rb
- (REXML::Parsers::SAX2Parser#handle_entitydecl): Extract.
-
-Sun Aug 11 18:40:25 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/sax2parser.rb (REXML::Parsers::SAX2Parser#parse):
- Fix wrong "%" position in parameter entity declaration event argument.
- * test/rexml/parser/test_sax2.rb: Add tests for the above case.
-
-Sun Aug 11 18:08:40 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/sax2parser.rb (REXML::Parsers::SAX2Parser#parse):
- Support NDATA in external ID entity declaration.
- * test/rexml/parser/test_sax2.rb: Add tests for the above case.
-
-Sun Aug 11 18:07:39 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/baseparser.rb
- (REXML::Parsers::BaseParser#pull_event): Support optional NDATA
- in external ID entity declaration.
-
-Sun Aug 11 17:54:07 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * NEWS (REXML::Parsers::SAX2Parser): Add about this change.
- * lib/rexml/parsers/sax2parser.rb (REXML::Parsers::SAX2Parser#parse):
- Fix wrong number of arguments. Document says "an array of the
- entity declaration" but it passes two or more arguments.
- This is a bug but it break backward compatibility.
- Reported by Ippei Obayashi. [Bug #8731] [ruby-dev:47582]
- * lib/rexml/sax2listener.rb (REXML::SAX2Listener#entitydecl): ditto.
- The listener template accepted two arguments.
- * test/rexml/parser/test_sax2.rb: Add tests for external ID case.
-
-Sun Aug 11 17:41:41 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/parser/test_sax2.rb: Add SAX2 API test.
-
-Sun Aug 11 15:10:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (rb_enc_symname_type): allow ID_ATTRSET for ID_INSTANCE,
- ID_GLOBAL, ID_CLASS, ID_JUNK too. [Bug #8756]
-
-Sun Aug 11 13:17:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * include/ruby/encoding.h: Reduce ENCODING_INLINE_MAX to 127 as this
- should be sufficient to represent all the encodings Ruby supports.
-
-Sun Aug 11 11:54:38 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_clock_gettime): New method.
- This is accepted in the meeting:
- https://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20130809
- This method is accepted as a CRuby feature.
- I.e. Other Ruby implementations don't need to implement it.
- [ruby-core:56087] [Feature #8658]
-
-Sun Aug 11 10:40:48 2013 Zachary Scott <e@zzak.io>
-
- * lib/time.rb: [DOC] Correcting rdoc visibility of time.rb constants
- Reported by Tanaka Akira [ruby-core:56517]
-
-Sun Aug 11 04:48:14 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * file.c (rb_str_normalize_ospath):
- HFS Plus (Mac OS Extended) uses a variant of Normal Form D in which
- U+2000 through U+2FFF, U+F900 through U+FAFF, and U+2F800 through
- U+2FAFF are not decomposed (this avoids problems with round trip
- conversions from old Mac text encodings).
- http://developer.apple.com/library/mac/qa/qa1173/_index.html
- Therefore fix r42457 to exclude the range.
-
-Sun Aug 11 03:26:07 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bitsize): Fix a conditional expression.
-
-Sun Aug 11 02:44:03 2013 Zachary Scott <e@zzak.io>
-
- * lib/time.rb: [DOC] Document constants by @markijbema [Fixes GH-377]
- https://github.com/ruby/ruby/pull/377
-
-Sun Aug 11 01:28:52 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Revert r42458.
- It removes the HAVE_CLOCK_GETTIME from config.h.
- http://www.rubyist.net/~akr/chkbuild/debian/ruby-trunk/log/20130809T044800Z.diff.html.gz
-
-Sat Aug 10 13:53:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (rb_id_attrset): allow other than ID_ATTRSET.
-
- * parse.y (intern_str): ditto. try stem ID for ID_INSTANCE,
- ID_GLOBAL, ID_CLASS, ID_JUNK too. [Bug #8756]
-
-Sat Aug 10 12:49:50 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/baseparser.rb
- (REXML::Parsers::BaseParser::CDATA_END): Use "\A" instead of "^".
- It is not an used constant but I fix it. (Or should I remove it?)
-
-Sat Aug 10 12:47:19 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/baseparser.rb (REXML::Parsers::BaseParser):
- Fix wrong constant name. "]>" pattern match is the same but
- it is used for "<!DOCTYPE" end mark not "<![CDATA[" end mark.
-
-Sat Aug 10 12:43:15 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/baseparser.rb (REXML::Parsers::BaseParser):
- Use "\A" instead of "^" in document type declaration patterns
- because they are used as the head match in content not the head
- match in line. They don't cause any problems in the current code
- but it should be fixed.
-
-Sat Aug 10 12:39:00 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/parse/test_document_type_declaration.rb: Add tests for
- parsing document type declaration.
-
-Sat Aug 10 12:00:45 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/baseparser.rb (REXML::Parsers::BaseParser::SYSTEM):
- Fix loose "head" match regular expression. It doesn't cause any
- problem in the current code but it should be fixed because readers
- may confuse it.
- Patch by Ippei Obayashi. Thanks!!!
-
-Sat Aug 10 11:58:24 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/parse/test_notation_declaration.rb (#test_system_public):
- Add a test for PUBLIC notation and SYSTEM notation order case.
-
-Sat Aug 10 11:31:35 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/baseparser.rb (REXML::Parsers::BaseParser::PUBLIC):
- Fix loose "head" match regular expression.
- [Bug #8701] [ruby-dev:47551]
- Patch by Ippei Obayashi. Thanks!!!
- * test/rexml/parse/test_notation_declaration.rb (#test_system_public):
- Add a test for the above case.
-
-Sat Aug 10 09:20:21 2013 Zachary Scott <e@zzak.io>
-
- * NEWS: [DOC] typo in example reported by @moretea
- https://github.com/ruby/ruby/commit/a39e724#commitcomment-3831489
-
-Sat Aug 10 09:19:04 2013 Zachary Scott <e@zzak.io>
-
- * proc.c: [DOC] rdoc code formatting
-
-Sat Aug 10 09:12:01 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (rb_id_attrset): check if the argument is valid type as an
- attribute.
-
-Sat Aug 10 05:44:08 2013 Zachary Scott <e@zzak.io>
-
- * lib/rss/trackback.rb: [DOC] Hide RSS::Trackback from rdoc
- Patch by Steve Klabnik [Bug #8755] [ruby-core:56456]
-
-Sat Aug 10 04:52:21 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big_div_struct): Use size_t.
- (bigdivrem1): Ditto.
- (bigdivrem_num_extra_words): Ditto.
- (bigdivrem_single): Ditto.
- (bigdivrem_normal): Ditto.
- (bary_divmod): Ditto.
-
-Fri Aug 9 23:47:15 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rss/rexmlparser.rb: Remove needless REXML version check.
- Both RSS Parser and REXML are bundled in Ruby. RSS Parser can
- always use the latest REXML. [Bug #8754] [ruby-core:56454]
- Patch by Steve Klabnik. Thanks!!!
-
-Fri Aug 9 22:51:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (XLDFLAGS, LIBRUBYARG_STATIC): CoreFoundation framework
- option is now needed always, regardless enable-shared.
- [ruby-core:56467] [Bug #8759]
-
-Fri Aug 9 22:20:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (load_file_internal): use rb_parser_compile_string_path and
- rb_parser_compile_file_path, String path name versions. [Bug #8753]
-
-Fri Aug 9 07:16:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * ext/io/console/console.c: delete redefinition of rb_cloexec_open.
- drop support for 1.8 and 1.9 from the next release of io-console gem.
-
-Fri Aug 9 19:13:54 2013 Koichi Sasada <ko1@atdot.net>
-
- * NEWS: update about new methods for Binding.
-
-Fri Aug 9 18:48:09 2013 Koichi Sasada <ko1@atdot.net>
-
- * proc.c: add Binding#local_variable_get/set/defined?
- to access local variables which a binding contains.
- Most part of implementation by nobu.
-
- * test/ruby/test_proc.rb: add a tests for above.
-
- * vm.c, vm_core.h (rb_binding_add_dynavars): add a new function
- to add a new environment to create space for new local variables.
-
-Fri Aug 9 14:02:01 2013 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * tool/make-snapshot: Fix order of priority for option parameter.
-
-Fri Aug 9 12:06:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (rb_str_normalize_ospath): normalize to Normalization Form C
- using CFString.
-
-Fri Aug 9 10:53:57 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * time.c (get_timeval, get_new_timeval): use rb_obj_class()
- instead of CLASS_OF() because CLASS_OF() may return
- a singleton class.
-
-Fri Aug 9 10:42:11 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * vm_insnhelper.c (vm_invoke_block): returning from lambda proc
- now always exits from the Proc. [ruby-core:56193] [Feature #8693]
-
- * NEWS, test/ruby/test_lambda.rb: ditto. Patch by nobu.
-
-Fri Aug 9 00:10:32 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enumerator.c (lazy_zip_func): fix non-single argument. fix
- out-of-bound access and pack multiple yielded values.
- [ruby-core:56383] [Bug #8735]
-
-Thu Aug 8 23:01:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (rb_mod_singleton_p): new method Module#singleton_class? to
- return whether the receiver is a singleton class or not.
- [ruby-core:51087] [Feature #7609]
-
-Thu Aug 8 21:56:44 2013 Tanaka Akira <akr@fsij.org>
-
- * time.c (time_overflow_p): Avoid signed integer overflow.
- (rb_time_new): Fix overflow condition.
-
-Thu Aug 8 19:58:02 2013 Koichi Sasada <ko1@atdot.net>
-
- * thread.c (rb_threadptr_pending_interrupt_check_mask):
- use RARRAY_RAWPTR() instead of RARRAY_PTR() because
- there is no new reference.
-
-Thu Aug 8 19:56:52 2013 Koichi Sasada <ko1@atdot.net>
-
- * string.c (rb_str_format_m): use RARRAY_RAWPTR() instead of
- RARRAY_PTR() because there is no new reference.
-
-Thu Aug 8 19:55:51 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: define USE_RGENGC_LOGGING_WB_UNPROTECT.
-
-Thu Aug 8 16:44:25 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: add old macro name `RUBY_EVENT_SWITCH'.
- This macro name is obsolete because it is renamed to
- RUBY_INTERNAL_EVENT_SWITCH, but it has compatibility problem
- using this macro name like ruby-prof.
- I want to remove this macro after ruby 2.1.
-
-Thu Aug 8 15:37:53 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/coverage/test_coverage.rb (TestCoverage#test_big_code): use `1'
- instead of `p' to get rid of a side effect.
- Kernel#p without any argument seems to do nothing, but flushes stdout.
- and, if stdout is redirected to file, fsync() will be called on
- Windows. so, when running test-all on Windows with redirection, such
- as CI environment, this test took a lot of time.
-
-Thu Aug 8 14:54:18 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * NEWS: add description of incompatibility introduced by r42396.
- [ruby-core:56329] [Bug #8722]
-
-Thu Aug 8 14:50:36 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * common.mk (mini): portable target to build miniruby
-
- * common.mk (bisect): run git-bisect with miniruby
-
- * common.mk (bisect-ruby): run git-bisect with ruby
-
- * tool/bisect.sh: script for git-bisect
-
-Thu Aug 8 12:11:43 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/webrick/test_httpresponse.rb (test_send_body_*_chunked): these
- expectations assumes that the IOs are binmode. fixed test failures
- introduced at r42427 on Windows.
-
-Thu Aug 8 10:27:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * range.c (range_last): revert r42400. [Bug #8739]
-
-Thu Aug 8 10:26:25 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (rb_str_normalize_ospath): extract and move from dir.c.
-
-Thu Aug 8 05:59:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * test/openssl/test_ssl.rb: Fix test for CVE-2013-4073.
- Patch by Antonio Terceiro. [Bug #8750] [ruby-core:56437]
-
-Thu Aug 8 03:37:38 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/webrick/httpresponse.rb: Allow #body to be an IO-like object
- that responds to #readpartial and #read.
- [ruby-trunk - Feature #8155]
- * NEWS: NEWS for above
- * test/webrick/test_httpresponse.rb: Tests for above.
-
-Wed Aug 7 23:06:26 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * ruby.c (Process.argv0): New method to return the original value
- of $0. [Feature #8696]
-
-Wed Aug 7 23:05:55 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * ruby.c (Process.setproctitle): New method to change the title of
- the running process that is shown in ps(1). [Feature #8696]
-
-Wed Aug 7 20:05:38 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_odd_p): Check the bignum length.
- (rb_big_even_p): Ditto.
-
-Wed Aug 7 19:29:26 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (dbl2big): A condition simplified.
-
-Wed Aug 7 16:34:30 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/webrick/test_cgi.rb (TestWEBrickCGI#{start_cgi_server,test_cgi}):
- mswin is not only mswin32 but also mswin64. [Bug #8746]
-
-Wed Aug 7 16:19:12 2013 Koichi Sasada <ko1@atdot.net>
-
- * cont.c (rb_fiber_start): use RARRAY_RAWPTR() instead of
- RARRAY_PTR() because there is no new reference.
-
- * proc.c (curry): ditto.
-
- * proc.c (rb_proc_call): remove line break.
-
-Wed Aug 7 13:20:12 2013 Koichi Sasada <ko1@atdot.net>
-
- * random.c (random_load): use RARRAY_RAWPTR() instead of
- RARRAY_PTR() because there is no new reference.
-
-Wed Aug 7 12:58:23 2013 Koichi Sasada <ko1@atdot.net>
-
- * thread.c (thread_start_func_2): use RARRAY_RAWPTR() instead of
- RARRAY_PTR() because there is no new reference.
-
-Wed Aug 7 09:00:24 2013 Zachary Scott <e@zzak.io>
-
- * string.c: [DOC] Description of rb_str_equal [Fixes GH-375]
- Based on a patch by @markijbema
- https://github.com/ruby/ruby/pull/375
-
-Wed Aug 7 08:30:38 2013 Zachary Scott <e@zzak.io>
-
- * ext/openssl/ossl_hmac.c: [DOC] Documentation for OpenSSL::HMAC
- based on a patch by @repah documenting-ruby/ruby#14
- https://github.com/documenting-ruby/ruby/pull/14
-
-Wed Aug 7 07:46:23 2013 Zachary Scott <e@zzak.io>
-
- * lib/rss/utils.rb: [DOC] RSS::Utils by Steve Klabnik [Bug #8745]
-
-Wed Aug 7 07:38:39 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (nlz16): Removed.
- (nlz32): Ditto.
- (nlz64): Ditto.
- (nlz128): Ditto.
- (nlz_int): New function.
- (nlz_long): New function.
- (nlz_long_long): New function.
- (nlz_int128): New function.
- (nlz): Follow above changes.
- (bitsize): Follow above changes.
-
-Tue Aug 6 22:38:15 2013 Zachary Scott <e@zzak.io>
-
- * time.c: [DOC] Typo in Time overview by @sparr [Fixes GH-374]
- https://github.com/ruby/ruby/pull/374
-
-Tue Aug 6 22:35:32 2013 Zachary Scott <e@zzak.io>
-
- * lib/rss/1.0.rb: [DOC] Document RSS10 by Steve Klabnik [Bug #8740]
-
-Tue Aug 6 22:14:11 2013 Kouji Takao <kouji.takao@gmail.com>
-
- * ext/readline/readline.c (readline_s_delete_text): remove
- checking "$SAFE == 4".
-
- * ext/readline/readline.c: fix rdoc, remove "Raises SecurityError"
- and add "Raises NotImplementedError".
-
-Tue Aug 6 22:04:38 2013 Kouji Takao <kouji.takao@gmail.com>
-
- * ext/readline/readline.c, test/readline/test_readline.rb: fix
- indent.
-
-Tue Aug 6 21:59:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * range.c (range_last): return nil for empty range, or in the case the
- predecessor is smaller than the begin. [Bug #8739]
-
-Tue Aug 6 21:48:31 2013 Kouji Takao <kouji.takao@gmail.com>
-
- * ext/readline/readline.c (readline_s_set_point, Init_readline):
- add Readline.point=(pos). Patched by naruse. [ruby-dev:47535]
- [Feature #8675]
-
-Tue Aug 6 21:14:11 2013 Kouji Takao <kouji.takao@gmail.com>
-
- * ext/readline/readline.c (Init_readline, readline_s_set_output)
- (clear_rl_outstream, readline_s_set_input, clear_rl_instream)
- (readline_readline): fix causing SEGV if closed IO object that is
- set Readline.input or Readline.output. Patched by akr
- [ruby-dev:47509] [Bug #8644]
-
-Tue Aug 6 17:56:40 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_insnhelper.c (vm_push_frame): change type of stack_max to size_t.
-
-Tue Aug 6 17:42:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * range.c (range_last): exclude the last number of the exclusive range
- if the end is Numeric. [ruby-dev:47587] [Bug #8739]
-
-Tue Aug 6 17:42:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (rb_w32_conv_from_wchar): converted string to CP_UTF8
- should have UTF-8 encoding. otherwise no conversion takes place
- later.
-
-Tue Aug 6 17:21:38 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_insnhelper.c (vm_push_frame): fix stack overflow check codes.
- Stack overflow check should be done *after* pushing a stack frame.
- However, some stack overflow checking codes checked *before*
- pushing a stack frame with iseq->stack_max.
- To solve this problem, add a new parameter `stack_max' to specify
- a possible consuming stack size.
-
- * vm_core.h (CHECK_VM_STACK_OVERFLOW0): add to share the stack overflow
- checking code.
-
- * insns.def: catch up this change.
-
- * vm.c, vm_eval.c: ditto.
-
- * test/ruby/test_exception.rb: add a stack overflow test.
- This code is reported by nobu.
-
-Tue Aug 6 17:02:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (rb_w32_conv_from_wchar): use WideCharToMultiByte(),
- as like as mbstr_to_wstr(), in the first step of the conversion from
- WCHAR.
-
-Tue Aug 6 16:14:32 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * vm_eval.c (eval_string_with_cref): copy cref to limit the scope of
- refinements in the eval string. [ruby-core:56329] [Bug #8722]
-
- * test/ruby/test_refinement.rb: related test.
-
-Tue Aug 6 12:23:12 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_realloc): Use VALGRIND_MAKE_MEM_UNDEFINED to
- declare undefined memory area.
- (bignew_1): Ditto.
-
- * internal.h (VALGRIND_MAKE_MEM_DEFINED): Moved from gc.c
- (VALGRIND_MAKE_MEM_UNDEFINED): Ditto.
-
-Tue Aug 6 01:40:37 2013 Zachary Scott <e@zzak.io>
-
- * process.c: [DOC] Document caveats of command form of Process.spawn
- with regard to the shell and OS. Patched by Steve Klabnik [Bug #8550]
-
-Tue Aug 6 01:28:35 2013 Zachary Scott <e@zzak.io>
-
- * lib/rss/0.9.rb: [DOC] Typo in example [Bug #8732]
-
-Tue Aug 6 01:22:37 2013 Zachary Scott <e@zzak.io>
-
- * lib/rss/2.0.rb: [DOC] Document RSS::Rss by Steve Klabnik #8740
- * lib/rss/atom.rb: [DOC] Typo in rdoc by Steve Klabnik
-
-Mon Aug 5 23:47:59 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: Rename local variables.
-
-Mon Aug 5 22:23:59 2013 Zachary Scott <e@zzak.io>
-
- * vm_trace.c: [DOC] Fix TracePoint return values in examples
- Based on a patch by @sho-h [Fixes GH-373]
- https://github.com/ruby/ruby/pull/373
-
-Mon Aug 5 17:38:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (rb_w32_write_console): use MultiByteToWideChar() for
- the last step of conversion to WCHAR, to get rid of warnings from
- rb_enc_find() in miniruby. [ruby-dev:47584] [Bug #8733]
-
- * win32/win32.c (wstr_to_mbstr, mbstr_to_wstr): fix wrong trimming.
- WideCharToMultiByte() and MultiByteToWideChar() do not count
- NUL-terminator in the size for conversion result, unless the input
- length is -1.
-
-Mon Aug 5 11:51:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * include/ruby/encoding.h: document which user flags are used by
- ENCODING_MASK for better greppability
-
-Mon Aug 5 10:01:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * object.c (rb_class_inherited_p): allow iclasses to be tested for
- inheritance. [Bug #8686] [ruby-core:56174]
-
- * test/ruby/test_method.rb: add test
-
-Mon Aug 5 06:13:48 2013 Zachary Scott <e@zzak.io>
-
- * enumerator.c: [DOC] Remove reference to Enumerator::Lazy#cycle
- Patch by @kachick [Fixes GH-372]
- https://github.com/ruby/ruby/pull/372
-
-Mon Aug 5 03:57:16 2013 Zachary Scott <e@zzak.io>
-
- * lib/rss/0.9.rb: [DOC] Document RSS09 by Steve Klabnik [Bug #8732]
-
-Mon Aug 5 03:35:11 2013 Zachary Scott <e@zzak.io>
-
- * lib/rexml/attribute.rb: [DOC] Update example for #namespace
- Patch by Ippei Obayashi [Bug #8685] [ruby-core:56173]
-
-Sun Aug 4 21:08:29 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_zip): performance implement by using
- ALLOCA_N() to allocate tmp buffer.
-
-Sun Aug 4 07:14:49 2013 Tanaka Akira <akr@fsij.org>
-
- * README.EXT, README.EXT.ja: Mention rb_integer_pack and
- rb_integer_unpack.
-
-Sun Aug 4 01:54:45 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (BARY_TRUNC): New macro.
- (bary_cmp): Use BARY_TRUNC.
- (bary_mul_toom3): Ditto.
- (bary_divmod): Ditto.
- (abs2twocomp): Ditto.
- (bigfixize): Ditto.
- (rb_cstr_to_inum): Ditto.
- (big2str_karatsuba): Ditto.
- (bigdivrem): Ditto.
-
-Sun Aug 4 00:57:58 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_karatsuba): Don't allocate new temporary buffer
- if the buffer is enough for current invocation.
-
-Sun Aug 4 00:22:34 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary2bdigitdbl): New function.
- (bdigitdbl2bary): Ditto.
- (bary_mul_single): Use bdigitdbl2bary.
- (power_cache_get_power): Ditto.
- (bary_divmod): Use bary2bdigitdbl.
- (big2str_orig): Ditto.
- (bigdivrem): Ditto.
-
-Sat Aug 3 22:47:11 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: The branch condition of selecting multiplication
- algorithms should check smaller argument because Karatsuba and Toom3
- is effective only if both arguments are big.
- (bary_mul_toom3_branch): Compare the smaller argument to
- TOOM3_MUL_DIGITS.
- (bary_mul): Compare the smaller argument to KARATSUBA_MUL_DIGITS.
-
-Sat Aug 3 22:23:31 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_orig): Receive the number to stringize as
- BDIGIT array and size.
- (big2str_karatsuba): Receive the number to stringize as BDIGIT array
- and size. Use an temporary array of BDIGIT.
- (rb_big2str1): Follow the above change.
-
-Sat Aug 3 13:30:04 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (MAX_BASE36_POWER_TABLE_ENTRIES): Renamed from
- MAX_BIG2STR_TABLE_ENTRIES.
- (base36_power_cache): Renamed from big2str_power_cache.
- (base36_numdigits_cache): Renamed from big2str_numdigits_cache.
-
-Sat Aug 3 10:33:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_set_integer_literal): use rb_rational_raw1() for
- integral rational because no reduction is needed with 1.
-
-Sat Aug 3 09:46:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/etc/etc.c (setup_passwd, setup_group): set proper encodings to
- string members.
-
-Sat Aug 3 09:30:57 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * struct.c (rb_struct_define_under): new function to define Struct
- under the given namespace, not under Struct. [Feature #8264]
-
- * ext/etc/etc.c: use rb_struct_define_under.
-
-Sat Aug 3 06:55:29 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * parse.y (value_expr_gen): now NODE_DEFN and NODE_DEFS are not void
- value expressions. get rid of wrong warning with -w, and make to
- pass tests with chkbuild. ref. [Feature #3753]
-
-Sat Aug 3 04:23:48 2013 Eric Hodel <drbrain@segment7.net>
-
- * doc/syntax/refinements.rdoc: Remove mention of instance_eval and
- module_eval from scope section per:
- http://twitter.com/shugomaeda/status/363219951336693761
-
-Sat Aug 3 02:22:05 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_orig): Refactored.
-
-Sat Aug 3 01:20:19 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigadd_core): Removed.
- (bigadd): Use bary_add instead of bigadd_core.
-
-Sat Aug 3 00:52:43 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big2str1): Simplify power_level calculation.
-
-Sat Aug 3 00:34:20 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_zip): use rb_ary_new2() to create buffer
- if rb_block_arity() > 1.
-
-Sat Aug 3 00:12:00 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * NEWS: Add the description that IO#seek supports SEEK_DATA
- and SEEK_HOLE.
-
-Fri Aug 2 23:57:57 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * vm.c (m_core_define_method, m_core_define_singleton_method): now
- the value of def-expr is the Symbol of the name of the method, not
- nil.
- ref. [ruby-dev:42151] [Feature #3753]
-
- * test/ruby/test_syntax.rb (TestSyntax#test_value_of_def): test for
- above changes.
-
-Fri Aug 2 23:54:11 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_zip): performance improvement by avoiding
- array creation if rb_block_arity() > 1.
-
-Fri Aug 2 23:50:53 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (power_cache_get_power): Apply bigtrunc to the result of
- bigsq.
- (big2str_karatsuba): Fix number of leading zero characters.
-
-Fri Aug 2 23:48:36 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_yylex): calculate denominator directly as powers of
- ten, not parsing string.
-
- * parse.y (parser_number_literal_suffix): return bit set of found
- suffixes.
-
- * parse.y (parser_set_number_literal, parser_set_integer_literal):
- split from parser_number_literal_suffix to set yylval.
-
- * parse.y (parser_yylex): parse rational number literal with decimal
- point precisely.
-
- * parse.y (simple_numeric): integrate numeric literals and simplify
- numeric rules.
-
- * ext/ripper/eventids2.c (ripper_init_eventids2): ripper support for
- new literals, tRATIONAL and tIMAGINARY.
-
-Fri Aug 2 18:33:28 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_karatsuba): Reduce power_level more than one at
- recursion, if possible.
- (rb_big2str1): Follow the above change.
-
-Fri Aug 2 12:25:15 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul): Swap x and y for bary_mul1 if x is longer than y.
- [ruby-dev:47565] [Bug #8719] Reported by Narihiro Nakamura.
-
-Fri Aug 2 10:39:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * parse.y (negate_lit): add T_RATIONAL and T_COMPLEX to the switch
- statement, and call rb_bug() if an unknown type is passed to
- negate_lit(). [ruby-core:56316] [Bug #8717]
-
- * bootstraptest/test_literal_suffix.rb (assert_equal): add test
-
-Fri Aug 2 09:14:47 2013 Eric Hodel <drbrain@segment7.net>
-
- * doc/syntax/refinements.rdoc: Improve description of where you may
- activate refinements.
-
-Fri Aug 2 07:45:55 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_orig): Remove len argument.
- (big2str_karatsuba): Ditto.
- (rb_big2str1): Follow above change.
-
-Thu Aug 2 02:32:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * NEWS: Add the description of number literal suffixes.
-
-Thu Aug 2 00:02:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * bootstraptest/test_literal_suffix.rb: add two test cases to
- examine that "1if true" and "1rescue nil" are recognized as 1.
-
-Thu Aug 1 23:45:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * rational.c (rb_flt_rationalize_with_prec): new public C function
- to rationalize a Float instance with a precision.
-
- * rational.c (rb_flt_rationalize): new public C function to
- rationalize a Float instance. A precision is calculated from
- the given float number.
-
- * include/ruby/intern.h: Add rb_flt_rationalize_with_prec and
- rb_flt_rationalize.
-
- * parse.y: implement number literal suffixes, 'r' and 'i'.
- [ruby-core:55096] [Feature #8430]
-
- * bootstraptest/test_literal_suffix.rb: add tests for parser to scan
- number literals with the above tsuffixes.
-
-Thu Aug 1 23:55:08 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big2str1): Remove a local variable.
-
-Thu Aug 1 23:33:01 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_cstr_to_inum): Use power_cache_get_power.
-
-Thu Aug 1 21:02:48 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big2str1): Raise an error for too big number.
-
-Thu Aug 1 20:46:29 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (power_cache_get_power): Hide cached Bignum objects.
-
-Thu Aug 1 19:15:05 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big2str1): Remove non-trim mode.
- (rb_big2str0): Non-trim mode implemented here.
- (big2str_find_n1): Change the result type to long again.
- (big2str_base_powerof2): Don't take arguments: len and trim.
- (rb_big2str): Follow above change.
-
-Thu Aug 1 12:37:58 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_alloc): New function to allocate the result string.
- It is called after actual length is calculated.
- (big2str_struct): Add fields: negative, result and ptr.
- (big2str_orig): Write out the result via b2s->ptr.
- (big2str_orig): Ditto.
- (rb_big2str1): Don't allocate the result string at beginning.
-
-Thu Aug 1 07:36:27 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_orig): Use temporary buffer when trim mode.
-
-Thu Aug 1 06:28:48 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_orig): Simplified because RBIGNUM_LEN(x) <= 2 now.
- (big2str_struct): Two fields added: hbase2, hbase2_numdigits.
- (rb_big2str1): Initialize above fields.
-
-Thu Aug 1 04:06:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/rdoc/options.rb (RDoc#finish): include root path in include
- paths, to work in another directory than the source directory.
- [ruby-core:56282] [Bug #8712]
-
- * test/test_rdoc_markup_pre_process.rb (TestRDocMarkupPreProcess#setup):
- fix input_file_name, as the test script is not pre-processed.
-
-Thu Aug 1 01:45:18 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_karatsuba): Fix a condition of power_level.
-
-Thu Aug 1 01:09:02 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (LOG2_KARATSUBA_BIG2STR_DIGITS): Removed.
- (KARATSUBA_BIG2STR_DIGITS): Removed.
- (big2str_numdigits_cache): New variable.
- (power_cache_get_power): Merged with power_cache_get_power0.
- This function returns maxpow_in_bdigit_dbl(base)**(2**power_level).
- (rb_big2str1): use power_cache_get_power.
-
-Wed Jul 31 23:59:28 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_find_n1): Change the return type to size_t.
- (big2str_orig): Ditto.
- (big2str_karatsuba): Ditto.
- (rb_big2str1): Follow the above changes.
-
-Wed Jul 31 23:19:06 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (power_cache_get_power): Change numdigits_ret to size_t *.
- (big2str_orig): Change len argument to size_t.
- (big2str_karatsuba): Ditto.
- (rb_big2str1): Follow the above changes.
-
-Wed Jul 31 22:59:47 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/parse/test_notation_declaration.rb: Change class
- name to follow file name change.
-
-Wed Jul 31 22:57:50 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_notationdecl_parsetest.rb: Rename to ...
- * test/rexml/parse/test_notation_declaration.rb: ... this.
-
-Wed Jul 31 22:54:39 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_notationdecl_mixin.rb: Remove duplicated tests.
-
-Wed Jul 31 22:52:55 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_notationdecl_parsetest.rb: Fix typos in expected
- value.
- pubilc ->
- public
- ^^
-
-Wed Jul 31 22:50:51 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_notationdecl_parsetest.rb: Add tests that focus
- system literal in external ID system notation declaration.
-
-Wed Jul 31 22:36:21 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_cmp): Extracted from rb_big_cmp.
- (power_cache_get_power): Change n1 argument (number of digits) to
- power_level which is just passed to power_cache_get_power0.
- (big2str_karatsuba): Ditto.
- (rb_big2str1): Calculate the initial power_level.
-
-Wed Jul 31 22:04:36 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_notationdecl_parsetest.rb: Fix a typo.
- Extern ID ->
- ExternalID
- ^^
-
-Wed Jul 31 22:01:36 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_notationdecl_parsetest.rb: Add tests that focus
- public ID in external ID notation declaration.
-
-Wed Jul 31 22:01:24 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * parse.y: fix build error with bison-3.0.
-
-Wed Jul 31 21:58:53 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_notationdecl_parsetest.rb: Split test patterns.
-
-Wed Jul 31 21:42:33 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_notationdecl_parsetest.rb: Group tests.
-
-Wed Jul 31 21:37:51 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_notationdecl_mixin.rb (TestNotationDecl#test_name):
- Move to ...
- * test/rexml/test_notationdecl_parsetest.rb
- (TestNotationDecl#test_name): ... here.
-
-Wed Jul 31 21:37:47 2013 Kouhei Sutou <kou@cozmixng.org>
-
-Wed Jul 31 21:31:49 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_notationdecl_parsetest.rb: Remove setup because it
- doesn't share anything with other tests.
-
-Wed Jul 31 21:24:55 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_attributes_mixin.rb: Remove a needless shebang.
- * test/rexml/test_notationdecl_mixin.rb: ditto.
- * test/rexml/test_doctype.rb: ditto.
- * test/rexml/test_xml_declaration.rb: ditto.
- * test/rexml/test_changing_encoding.rb: ditto.
-
-Wed Jul 31 21:20:08 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_notationdecl_parsetest.rb: remove a needless shebang.
-
-Wed Jul 31 20:11:01 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * string.c (rb_str_rindex): fix bug introduced in r42269.
- "".rindex("") should return 0.
- (str_rindex): ditto.
-
-Wed Jul 31 19:55:33 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (MAX_BIG2STR_TABLE_ENTRIES): Use SIZEOF_SIZE_T.
- (power_cache_get_power0): Add rb_bug call for too bit i argument.
- (power_cache_get_power): Simplified.
-
-Wed Jul 31 18:32:25 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/uri/common.rb (URI.decode_www_form_component): Use String#b.
-
-Wed Jul 31 18:24:02 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * eval.c (rb_mod_refine, mod_using, top_using): don't show
- warnings because Refinements are no longer experimental.
- [ruby-core:55993] [Feature #8632]
-
- * test/ruby/test_refinement.rb: related test.
-
- * NEWS: fixes for the above change.
-
-Wed Jul 31 17:55:55 2013 Shota Fukumori <her@sorah.jp>
-
- * lib/uri/common.rb (URI.decode_www_form_component):
- Don't raise error when str includes multibyte characters.
-
-Wed Jul 31 17:45:39 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * string.c (rb_str_rindex): performance improvement by using
- memrchr(3).
-
-Wed Jul 31 16:43:30 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * string.c (rb_str_rindex): refactoring and avoid to call str_nth() if
- pos == 0.
-
-Wed Jul 31 14:41:36 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/set.rb: [DOC] Add a couple of notes on Hash as storage.
- ref. [Feature #6589]
-
-Wed Jul 31 14:38:52 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/set.rb: [DOC] Fix example result. Hash is now ordered.
-
-Wed Jul 31 14:38:10 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/set.rb: [DOC] Use the term "sorted" instead of "ordered"
- when mentioning SortSet.
-
-Wed Jul 31 12:18:47 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_struct): New structure.
- (big2str_orig): Use big2str_struct.
- (big2str_karatsuba): Ditto.
- (rb_big2str1): Ditto.
-
-Wed Jul 31 12:02:16 2013 Zachary Scott <e@zzak.io>
-
- * lib/rubygems.rb: [DOC] typo in url patch by @Red54 [Fixes #369]
- https://github.com/ruby/ruby/pull/369
-
-Wed Jul 31 07:09:07 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Import RubyGems from master as of commit 523551c
- * test/rubygems: ditto.
-
-Tue Jul 30 22:21:54 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * test/ruby/test_hash.rb: add a test for enumeration order of Hash.
-
-Tue Jul 30 18:52:27 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/set.rb (Set#intersect?, Set#disjoint?): Add new methods for
- testing if two sets have any element in common.
- [ruby-core:45641] [Feature #6588] Based on the code by marcandre.
-
-Tue Jul 30 17:16:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * sprintf.c (ruby__sfvextra): add QUOTE flag to escape unprintable
- characters.
-
-Tue Jul 30 11:00:52 2013 Zachary Scott <e@zzak.io>
-
- * ext/curses/extconf.rb: [DOC] nodoc to reduce Object pollution
-
-Tue Jul 30 08:19:42 2013 Tanaka Akira <akr@fsij.org>
-
- * sizes.c (Init_sizes): Define sizes only if the type actually exists.
-
-Mon Jul 29 22:55:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * sizes.c (Init_sizes): define RbConfig::SIZEOF. [Feature #8568]
-
-Mon Jul 29 22:25:20 2013 Zachary Scott <e@zzak.io>
-
- * ext/curses/curses.c: [DOC] Update location of samples
- * samples/curses/*: Move Curses samples and refactor from mixin
- The samples are included in rdoc for module and use of mixin is
- confusing
-
-Mon Jul 29 22:16:11 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (LOG2_KARATSUBA_BIG2STR_DIGITS): Renamed from
- LOG2_KARATSUBA_DIGITS.
- (KARATSUBA_BIG2STR_DIGITS): Renamed from KARATSUBA_DIGITS.
-
-Mon Jul 29 22:04:45 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_compare_by_id): add function prototype.
-
-Mon Jul 29 21:53:41 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_compare_by_id): don't call rb_hash_rehash()
- if self.compare_by_identity? == true.
-
-Mon Jul 29 21:29:48 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_assoc): performance improvement by replacing
- compare function in RHASH(hash)->ntbl->type temporarily like r42224.
- it falls back to rb_hash_foreach() if st_lookup() doesn't find the key.
-
- * test/ruby/test_hash.rb: add a test for above.
-
-Mon Jul 29 21:15:30 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * test/ruby/test_lazy_enumerator.rb
- (TestLazyEnumerator#test_initialize): Make sure
- Enumerator::Lazy#initialize raises error if the object is
- frozen. The check was performed by rb_ivar_set() before
- rb_check_frozen() was added to enumerator_init().
-
-Mon Jul 29 21:06:42 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * enumerator.c (enumerator_init): Add a frozenness check to
- prevent a frozen Enumerator object from being reinitialized with
- a different enumerable object. This is the least we should do,
- and more fixes will follow. [Fixes GH-368] Patch by Kenichi
- Kamiya.
-
- * enumerator.c (generator_init): Ditto.
-
-Mon Jul 29 20:14:24 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_assoc): revert r42224. table->type->compare is
- called only if hashes are matched.
-
- * test/ruby/test_hash.rb: add a test to check using #== to compare.
-
-Mon Jul 29 17:00:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (yycompile): store file name as String to keep the encoding.
-
- * parse.y (rb_parser_compile_string_path, rb_parser_compile_file_path):
- new functions to pass file name as a String.
-
- * parse.y (gettable_gen): return a copy of the original file name, not
- a copy in filesystem encoding.
-
- * vm_eval.c (eval_string_with_cref): use Qundef instead of "(eval)".
-
-Mon Jul 29 16:53:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (rb_hash_initialize_copy): copy st_table type even if empty.
- [ruby-core:56256] [Bug #8703]
-
-Mon Jul 29 16:34:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (rb_hash_initialize_copy): clear old table before copy new
- table.
-
-Mon Jul 29 16:34:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (rb_hash_assoc): aggregate object can be initialized only
- with link time constants.
-
-Mon Jul 29 14:54:44 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_assoc): performance improvement by replacing
- compare function in RHASH(hash)->ntbl->type temporarily.
-
-Mon Jul 29 14:52:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (xsystem): expand environment variable in all macros not
- expanded with RbConfig. [Bug #8702]
-
- * test/mkmf/test_framework.rb (create_framework): replace all $@ not
- only once.
-
-Mon Jul 29 06:54:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (rb_w32_pipe): use enum for compile time constants,
- instead of const int for debugging.
-
-Mon Jul 29 00:11:49 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem): Specialized implementation added for
- nx == 2 && ny == 2
-
-Sun Jul 28 20:28:41 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * io.c (io_getpartial): use rb_str_locktmp_ensure().
- [ruby-core:56121] [Bug #8669]
-
- * io.c (rb_io_sysread): ditto.
-
- * test/ruby/test_io.rb: add tests for above.
-
-Sun Jul 28 20:10:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb (extmake): should make static libraries for extensions
- to be statically linked. [Bug #7948]
-
-Sun Jul 28 17:38:32 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * string.c: add internal API rb_str_locktmp_ensure().
-
- * io.c (io_fread): use rb_str_locktmp_ensure().
- [ruby-core:56121] [Bug #8669]
-
- * test/ruby/test_io.rb: add a test for above.
-
-Sun Jul 28 13:04:39 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * io.c (interpret_seek_whence): support SEEK_DATA and SEEK_HOLE.
- These are whences for lseek(2) supported by Linux since version 3.1.
- [ruby-core:56123] [Feature #8671]
-
- * test/ruby/test_io.rb: Add tests for above.
-
-Sun Jul 28 12:41:39 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (absint_numwords_generic): The char_bit variable changed
- to static constant.
-
-Sun Jul 28 12:03:23 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: Constify bary_* functions.
-
-Sun Jul 28 11:12:07 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/intern.h (rb_absint_size): Declaration moved from
- internal.h to calculate required buffer size to pack integers.
- (rb_absint_numwords): Ditto.
- (rb_absint_singlebit_p): Ditto.
- [ruby-core:42813] [Feature #6065]
-
-Sun Jul 28 10:54:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (rb_w32_pipe): fix pipe name formatting. as "%x" may
- not contain '0' at all, fill at fixed position instead.
-
-Sun Jul 28 00:35:14 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_size): Return the bignum "bytewise" size.
- [ruby-core:55578] [Feature #8553]
- This is accepted by matz on DevelopersMeeting20130727Japan.
-
-Sun Jul 28 00:07:48 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/intern.h (rb_integer_pack): Declaration moved from
- internal.h.
- (rb_integer_unpack): Ditto.
- [ruby-core:42813] [Feature #6065]
-
-Fri Jul 26 23:18:13 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * NEWS: Add a new feature that REXML::Parsers::StreamParser
- supports "entity" event.
-
-Fri Jul 26 23:14:31 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/parsers/streamparser.rb
- (REXML::Parsers::StreamParser#parse): Add "entity" event support to
- listener. [Bug #8689] [ruby-dev:47542]
- Reported by Ippei Obayashi.
- * test/rexml/test_stream.rb (StreamTester#entity): Add a test for
- the above case.
-
-Fri Jul 26 23:05:27 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_yylex): separate numeric literal from succeeding
- token, and treat 'e' as floating point number only if followed by
- exponent part.
-
-Fri Jul 26 22:14:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_exec.h (CHECK_VM_STACK_OVERFLOW_FOR_INSN): surround with
- do/while (0), and remove unnecessary casts.
-
-Fri Jul 26 20:12:07 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * ext/syslog/lib/syslog/logger.rb (Syslog::Logger): Add facility
- to Syslog::Logger. [Fixes GH-305] patch by Max Shytikov
- https://github.com/ruby/ruby/pull/305
-
-Fri Jul 26 19:25:17 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_exec.h, tool/instruction.rb: not an error, but a BUG if stack
- overflow checking failed just before/after the beginning of an
- instruction. It should be treated as a BUG.
- Please tell us if your code cause BUG with this problem.
- This check will removed soon (for performance).
-
-Fri Jul 26 18:30:14 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (ary_memcpy): cast to int to suppress a warning.
-
-Fri Jul 26 18:21:58 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (ary_memcpy): try to enable optimization.
- At least on my environments, I don't see any errors
- with many trials. Please tell us if you find any GC bugs.
-
-Fri Jul 26 17:49:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/file.c (fix_string_encoding): fix target encoding. the
- parameter `encoding' is not the target encoding but the original
- encoding.
-
-Fri Jul 26 14:05:19 2013 Zachary Scott <e@zzak.io>
-
- * ext/fiddle/*: [DOC] More doc on dlopen and RTLD_DEFAULT from r42184
-
-Fri Jul 26 13:08:53 2013 Zachary Scott <e@zzak.io>
-
- * ext/fiddle/lib/fiddle.rb: [DOC] Document Fiddle.dlopen(nil)
- * ext/fiddle/handle.c: [DOC] Document Fiddle::Handle.new(nil)
-
-Fri Jul 26 13:04:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * load.c (rb_load_internal): use rb_load_file_str() to keep path
- encoding.
-
- * load.c (rb_require_safe): search in OS path encoding for Windows.
-
- * ruby.c (rb_load_file_str): load file with keeping path encoding.
-
- * win32/file.c (rb_file_load_ok): use WCHAR type API assuming incoming
- path is encoded in UTF-8. [ruby-core:56136] [Bug #8676]
-
- * file.c (rb_str_encode_ospath): simplify using rb_str_conv_enc().
-
- * win32/file.c (fix_string_encoding): simplify with rb_str_conv_enc().
-
- * win32/file.c (convert_mb_to_wchar): use bare pointer instead of
- VALUE, and remove useless argument.
-
-Fri Jul 26 11:42:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * rational.c (f_round_common): Rational is expected to be returned by
- Rational#*, but mathn.rb breaks that assumption. [ruby-core:56177]
- [Bug #8687]
-
-Fri Jul 26 01:37:45 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * include/ruby/ruby.h: check defined(USE_RGENGC_LOGGING_WB_UNPROTECT)
-
-Fri Jul 26 01:21:41 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * file.c (rb_file_expand_path_internal): fix r42160; skip '~'.
-
-Thu Jul 25 17:53:18 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/net/http.rb (Net::HTTP#connect): disable Nagle's algorithm on
- HTTP connection. [ruby-core:56158] [Feature #8681]
-
-Thu Jul 25 17:49:42 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * re.c (rb_reg_to_s): convert closing parenthesis to the target encoding
- if it is ASCII incompatible encoding. [ruby-core:56063] [Bug #8650]
-
-Thu Jul 25 17:21:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * encoding.c (is_obj_encoding): new macro to check if obj is an
- Encoding. obj can be any type while is_data_encoding expects T_DATA
- only.
-
-Thu Jul 25 17:17:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (rb_file_expand_path_internal): should clear coderange after
- copying user name as binary data.
-
-Thu Jul 25 16:17:55 2013 Koichi Sasada <ko1@atdot.net>
-
- * encoding.c (check_encoding): Check T_DATA or not.
- is_data_encoding(obj) assumes that `obj' is T_DATA.
-
-Thu Jul 25 13:06:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (dir_s_home): use rb_home_dir_of and rb_default_home_dir.
-
- * file.c (rb_home_dir_of): split from rb_home_dir() for the home
- directry of the given user, and the user name is a VALUE, not a bare
- pointer. should raise if the user does not exist.
-
- * file.c (rb_default_home_dir): split from rb_home_dir() for the home
- directry of the current user.
-
-Thu Jul 25 12:32:11 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/openssl/ossl.c: support additional three thread synchronization
- functions. [ruby-trunk - Bug #8386]
-
-Thu Jul 25 07:15:58 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Import RubyGems from master as of commit 4ff70cc
- * test/rubygems: ditto.
-
-Wed Jul 24 20:57:44 2013 Koichi Sasada <ko1@atdot.net>
-
- * compile.c (iseq_set_arguments): use RARRAY_RAWPTR() instead of
- RARRAY_PTR() because there is no new reference.
-
- * compile.c (iseq_set_exception_table): ditto.
-
-Wed Jul 24 19:49:54 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/generic.rb (find_proxy): raise BadURIError if the URI is
- a relative URI. [Bug #8645]
-
-Wed Jul 24 18:56:06 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_insnhelper.c (vm_expandarray): use RARRAY_RAWPTR() instead of
- RARRAY_PTR() because there is no new reference.
-
- * vm_insnhelper.c (vm_caller_setup_args): ditto.
-
- * vm_insnhelper.c (vm_yield_setup_block_args): ditto.
-
-Wed Jul 24 18:40:11 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c, gc.c: move ary_unprotect_logging() into
- rb_gc_unprotect_logging() which is general version
-
- * include/ruby/ruby.h: add USE_RGENGC_LOGGING_WB_UNPROTECT
- to enable.
-
-Wed Jul 24 17:37:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (rb_file_expand_path_internal): preserve the file name
- encoding in an exception message.
-
-Wed Jul 24 08:04:49 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/-ext-/tracepoint/test_tracepoint.rb: add GC on/off to count
- GC events strictly.
-
-Tue Jul 23 23:19:24 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/openssl/extconf.rb (CRYPTO_THREADID): check exist or not.
-
- * ext/openssl/ossl.c (ossl_thread_id): use rb_nativethread_self()
- implemented at r42137 to allow threads which doesn't associated with
- Ruby thread to use openssl functions.
-
- * ext/openssl/ossl.c (Init_ossl_locks): If CRYPTO_THREADID is defined
- (OpenSSL 1.0.0 or later has it) use CRYPTO_THREADID_set_callback()
- instead of CRYPTO_set_id_callback() because its argument is
- unsigned long; it may cause id collision on mswin64
- whose sizeof(unsigned long) < sizeof(void*).
- http://www.openssl.org/docs/crypto/threads.html
-
- * ext/openssl/ossl.c (ossl_threadid_func): defined for above.
-
-Tue Jul 23 20:47:36 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: Move functions.
-
-Tue Jul 23 20:14:55 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_divmod): Add special cases for x < y easily detected
- and nx == 2 && ny == 2.
-
-Tue Jul 23 19:48:38 2013 Koichi Sasada <ko1@atdot.net>
-
- * thread_(pthread|win32).h: rename rb_thread_cond_t to
- rb_nativethread_cond_t.
-
- * thread.c, thread_pthread.c, thread_win32.c, vm_core.h: catch up
- renaming.
-
-Tue Jul 23 19:44:32 2013 Koichi Sasada <ko1@atdot.net>
-
- * thread_native.h: add rb_nativethread_self() which returns
- current running native thread identifier.
-
- * thread_[pthread|win32].c: implement rb_nativethread_self().
-
-Tue Jul 23 19:34:11 2013 Koichi Sasada <ko1@atdot.net>
-
- * thread_pthread.h, thread_win32.h: rename rb_thread_id_t to
- rb_nativethread_id_t.
-
- * thread_pthread.c, vm_core.h: use rb_nativethread_id_t.
-
-Tue Jul 23 18:56:11 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/openssl/ossl.c: use system native (system provided)
- thread locking APIs added by last commit.
- This patch fixes [Bug #8386].
- "rb_mutex_*" APIs control only "Ruby" threads.
- Not for native threads.
-
-Tue Jul 23 18:44:15 2013 Koichi Sasada <ko1@atdot.net>
-
- * thread_native.h: added.
- Move native thread related lines from vm_core.h.
- And declare several functions "rb_nativethread_lock_*",
- manipulate locking.
-
- * common.mk: add thread_native.h.
-
- * thread.c: add functions "rb_nativethread_lock_*".
-
- * thread.c, thread_[pthread,win32].[ch]: rename rb_thread_lock_t
- to rb_nativethread_lock_t to make it clear that this lock is for
- native threads, not for ruby threads.
-
-Tue Jul 23 16:14:57 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_before_sweep): fix spacing.
-
-Tue Jul 23 15:57:11 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (heap_get_freeobj): clear slot->freelist here.
- This means that this slot doesn't have any free objects.
- And store this slot with objspace->heap.using_slot.
-
- * gc.c (gc_before_sweep): restore objspace->freelist
- into objspace->heap.using_slot->freelist.
- This means that using_slot has free objects which are
- pointed from objspace->freelist.
-
- * gc.c (gc_slot_sweep): do not need to clear slot->freelist.
-
-Tue Jul 23 09:34:49 2013 Zachary Scott <e@zzak.io>
-
- * sample/drb/README*.rdoc: [DOC] migrate DRb sample READMEs to rdoc
-
-Tue Jul 23 09:28:05 2013 Zachary Scott <e@zzak.io>
-
- * lib/drb/invokemethod.rb: [DOC] nodoc InvokeMethod18Mixin
-
-Tue Jul 23 08:44:37 2013 Eric Hodel <drbrain@segment7.net>
-
- * ext/openssl/ossl_asn1.c (asn1time_to_time): Implement YYMMDDhhmmZ
- format for ASN.1 UTCTime. [ruby-trunk - Bug #8664]
- * test/openssl/test_asn1.rb: Test for the above.
-
-Tue Jul 23 08:11:32 2013 Zachary Scott <e@zzak.io>
-
- * lib/rexml/streamlistener.rb: [DOC] Fix examples in
- REXML::StreamListener#entitydecl patch by Ippei Obayashi [Bug #8665]
-
-Tue Jul 23 07:44:59 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Import RubyGems from master as of commit b165260
- * test/rubygems: ditto.
-
-Tue Jul 23 07:14:31 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mulsub_1xN): New function.
- (bary_mul_toom3): Use bary_mulsub_1xN.
-
-Tue Jul 23 03:32:23 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (KARATSUBA_BALANCED): New macro.
- (TOOM3_BALANCED): Ditto.
- (bary_mul_balance_with_mulfunc): Use KARATSUBA_BALANCED and
- TOOM3_BALANCED.
- (rb_big_mul_balance): Relax a condition.
- (rb_big_mul_karatsuba): Use KARATSUBA_BALANCED.
- (rb_big_mul_toom3): Use TOOM3_BALANCED.
- (bary_mul_karatsuba_branch): Use KARATSUBA_BALANCED.
- (bary_mul_toom3_branch): Use TOOM3_BALANCED.
-
-Tue Jul 23 01:34:45 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem_mulsub): Extracted from bigdivrem1.
- (bigdivrem1): Use bary_add.
-
-Mon Jul 22 18:39:52 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * string.c (rb_str_enumerate_chars): specify array capa
- with str_strlen().
-
- * string.c (rb_str_enumerate_codepoints): ditto.
-
-Mon Jul 22 18:01:33 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * string.c (rb_str_enumerate_chars): specify array capa.
-
-Mon Jul 22 17:24:14 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * string.c (rb_str_each_char_size): performance improvement by
- using rb_str_length().
-
-Mon Jul 22 16:32:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (eval_string_with_cref): check by Check_TypedStruct
- instead of rb_obj_is_kind_of.
-
-Mon Jul 22 13:19:22 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (ary_resize_capa): use RARRAY_RAWPTR() because
- this code creates no new references.
-
-Mon Jul 22 12:58:18 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (ary_memfill): added.
-
- * array.c (rb_ary_initialize): use ary_memfill().
-
- * array.c (rb_ary_fill): ditto.
-
- * array.c (rb_ary_slice_bang): use RARRAY_RAWPTR() because
- this code creates no new references.
-
-Mon Jul 22 10:09:46 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_slot_sweep): need to add empty RVALUE as freeobj.
-
-Mon Jul 22 09:48:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (eval_string_with_cref): use the given file name unless
- eval even if scope is given. additional fix for [Bug #8436].
- based on the patch by srawlins at [ruby-core:56099] [Bug #8662].
-
-Mon Jul 22 09:24:19 2013 Kouji Takao <kouji@takao7.net>
-
- * ext/readline/readline.c (Init_readline): added
- Readline.delete_text. [ruby-dev:45789] [Feature #6626]
- * ext/readline/extconf.rb: check for rl_delete_text() in Readline library.
-
- Thanks, Nobuyoshi Nakada, for the patch.
-
-Mon Jul 22 03:15:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/date/date_parse.c (rfc2822_cb): check if wday is given, since it
- can be omitted.
-
-Mon Jul 22 00:15:20 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_sq_fast): Refine expressions.
-
-Sun Jul 21 21:08:59 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul): Use simple multiplication if yl is small.
- (rb_cstr_to_inum): Invoke bigsq instead of bigmul0.
- (bigsq): Re-implemented.
- (bigmul0): Invoke bigsq if two arguments are identical.
-
-Sun Jul 21 09:58:19 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul_toom3): New function based on bigmul1_toom3.
- (bary_mul_toom3_branch): Call bary_mul_toom3.
- (rb_big_mul_toom3): Ditto.
- (bigmul1_toom3): Removed.
- (big_real_len): Ditto.
- (big_split): Ditto.
- (big_split3): Ditto.
-
-Sun Jul 21 08:12:16 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * proc.c (proc_to_s): use PRIsVALUE to preserve the result encoding.
-
-Sun Jul 21 03:36:18 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * hash.c (rb_hash_flatten): use NUM2INT to raise TypeError on 32bit
- platform. it's introduced by r42039
-
-Sun Jul 21 01:07:45 2013 Benoit Daloze <eregontp@gmail.com>
-
- * common.mk (help): Fix environment variable name and argument.
- Actually it can also be a directory or any argument for
- test/unit runner. [Fixes GH-363]
-
-Sat Jul 20 22:44:50 2013 Zachary Scott <e@zzak.io>
-
- * common.mk: Document running a single test [Fixes GH-363]
- Patch by Avdi Grimm https://github.com/ruby/ruby/pull/363
-
-Sat Jul 20 22:39:56 2013 Zachary Scott <e@zzak.io>
-
- * sample/*: whitespace patch by Sergio Campama [Fixes GH-364]
- https://github.com/ruby/ruby/pull/364
-
-Sat Jul 20 22:33:13 2013 Zachary Scott <e@zzak.io>
-
- * doc/regexp.rdoc: [DOC] Fix typo in example [Fixes GH-365]
- Patch by Juanito Fatas https://github.com/ruby/ruby/pull/365
-
-Sat Jul 20 17:46:03 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (rb_str_succ): add missing case NEIGHBOR_WRAPPED.
- r42078 caused buggy behavior like "\xFF".b -> "\x01\xFF".b
-
-Sat Jul 20 15:22:38 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (rb_ary_resize): use simple memcpy because there are no new
- references.
-
-Sat Jul 20 15:02:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * safe.c (ruby_safe_level_4_warning): define for old extension
- libraries. [Bug #8652]
-
-Sat Jul 20 14:38:00 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (ary_make_shared): make shared array shady.
- Making non-shady shared array causes SEGV (see rubyci).
- It seems a bug around shared array.
-
-Sat Jul 20 12:14:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (enc_succ_char, enc_pred_char): consider wchar case.
- [ruby-core:56071] [Bug #8653]
-
- * string.c (rb_str_succ): do not replace with invalid char.
-
- * encoding.c (rb_enc_code_to_mbclen): add new function which returns
- mbclen from codepoint like as rb_enc_codelen() but 0 for invalid
- char.
-
- * include/ruby/encoding.h (rb_enc_code_to_mbclen): declaration and
- shortcut macro.
-
-Fri Jul 19 21:59:12 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: declare type_name() at the beginning of file.
-
-Fri Jul 19 21:35:09 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c: reduce shady operations.
-
- * array.c (rb_ary_modify, ary_make_partial, rb_ary_splice,
- rb_ary_replace, rb_ary_eql, rb_ary_compact_bang):
- use RARRAY_RAWPTR() instead of RARRAY_PTR().
-
- * array.c (rb_ary_shift): use RARRAY_PTR_USE() without WB because
- there are not new relations.
-
- * array.c (ary_ensure_room_for_unshift): ditto.
-
- * array.c (rb_ary_sort_bang): ditto.
-
- * array.c (rb_ary_delete_at): ditto.
-
- * array.c (rb_ary_reverse_m): use RARRAY_RAWPTR() because
- there are not new relations.
-
-Fri Jul 19 20:58:20 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c: reduce shade operations.
-
- * array.c (rb_ary_modify): use RARRAY_RAWPTR().
-
- * array.c (ary_make_substitution, rb_ary_s_create, ary_make_partial,
- rb_ary_splice, rb_ary_resize, rb_ary_rotate_m, rb_ary_times):
- use ary_memcpy().
-
-Fri Jul 19 19:55:28 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (ary_mem_clear): added. This operation doesn't need WB
- because this operation creates a reference to Qnil.
-
- * array.c (ary_make_shared, rb_ary_store, rb_ary_shift_m,
- rb_ary_splice, rb_ary_resize, rb_ary_fill): use ary_mem_clear()
- instead of rb_mem_clear().
-
- * array.c (ary_make_shared): use RARRAY_RAWPTR() instead of RARRAY_PTR().
-
-Fri Jul 19 19:18:51 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c: fix commit miss.
- RGENGC_UNPROTECT_LOGGING should be 0.
-
-Fri Jul 19 19:15:30 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (rb_ary_resurrect): use RARRAY_RAWPTR() because there is no
- writing.
-
- * array.c (rb_ary_new_from_values): use ary_memcpy().
-
-Fri Jul 19 19:07:31 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (ary_memcpy): add a function to copy VALUEs into ary
- with write barrier. If ary is promoted, use write barrier correctly.
-
- * array.c (rb_ary_cat, rb_ary_unshift_m, rb_ary_dup,
- rb_ary_sort_bang, rb_ary_replace, rb_ary_plus): use ary_memcpy().
-
-Fri Jul 19 15:32:57 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (rb_ary_store): use RARRAY_PTR_USE() instead of RARRAY_PTR().
- Clearing memory space doesn't need WBs.
-
-Fri Jul 19 15:19:37 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (ary_ensure_room_for_push): use RARRAY_RAWPTR() instead of
- RARRAY_PTR. In this code, there are no "write" operation.
-
- * array.c (rb_ary_equal): ditto.
-
- * array.c (recursive_equal): ditto.
-
-Fri Jul 19 15:09:22 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c, internal.h (rb_gc_writebarrier_remember_promoted): add a new
- function to remember an specified object. This api is only
- experimental (strongly depend on WB/rgengc strategy).
-
-Fri Jul 19 14:56:00 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (ary_unprotect_logging): use (void *) for first parameter
- because VALUE is not defined before including ruby/ruby.h.
-
-Fri Jul 19 14:19:48 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * ext/pathname/pathname.c (path_inspect): use PRIsVALUE to preserve
- the result encoding.
-
-Fri Jul 19 12:35:41 2013 Tanaka Akira <akr@fsij.org>
-
- * test/socket/test_tcp.rb (test_initialize_failure): Use EADDRNOTAVAIL
- to test an error message generated by bind() failure.
-
-Fri Jul 19 11:27:38 2013 Zachary Scott <e@zzak.io>
-
- * lib/racc/parser.rb: [DOC] Capitalize "Ruby" in documentation
- Patch by Dave Worth https://github.com/ruby/ruby/pull/341
-
-Fri Jul 19 11:26:28 2013 Zachary Scott <e@zzak.io>
-
- * ext/psych/lib/psych*: [DOC] Capitalize "Ruby" in documentation
- Patch by Dave Worth https://github.com/ruby/ruby/pull/341
-
-Fri Jul 19 11:25:12 2013 Zachary Scott <e@zzak.io>
-
- * lib/rdoc/*: [DOC] Capitalize "Ruby" in documentation
- Patch by Dave Worth https://github.com/ruby/ruby/pull/341
-
-Fri Jul 19 11:23:55 2013 Zachary Scott <e@zzak.io>
-
- * lib/rubygems*: [DOC] Capitalize "Ruby" in documentation
- Patch by Dave Worth https://github.com/ruby/ruby/pull/341
-
-Fri Jul 19 11:16:54 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/set.rb (Set#to_set): Define Set#to_set so that aSet.to_set
- returns self. [Fixes GH-359]
-
-Fri Jul 19 11:10:23 2013 Zachary Scott <e@zzak.io>
-
- * lib/rake/*: [DOC] Capitalize "Ruby" in documentation
- Patch by Dave Worth https://github.com/ruby/ruby/pull/341
-
-Fri Jul 19 01:04:14 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/-test-/bignum/intpack.c: Renamed from ext/-test-/bignum/pack.c.
- (Init_intpack): Renamed from Init_pack.
- Reported by Naohisa Goto. [ruby-dev:47526] [Bug #8655]
-
-Fri Jul 19 00:54:27 2013 Benoit Daloze <eregontp@gmail.com>
-
- * test/ruby/test_array.rb (test_count): add a test case for #count
- with an argument. See Bug #8654.
-
-Thu Jul 18 23:45:06 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_eql): compare RARRAY_PTR() for performance
- improvement in case of that self and other are shared.
-
-Thu Jul 18 22:46:42 2013 Zachary Scott <e@zzak.io>
-
- * lib/cgi.rb: [DOC] Capitalize "Ruby" in documentation [Fixes GH-341]
- Patch by Dave Worth https://github.com/ruby/ruby/pull/341
- * lib/webrick.rb: ditto
- * lib/scanf.rb: ditto
- * lib/xmlrpc/config.rb: ditto
- * lib/resolv.rb: ditto
- * lib/e2mmap.rb: ditto
- * lib/fileutils.rb: ditto
- * lib/mkmf.rb: ditto
- * lib/cgi/session.rb: ditto
- * lib/yaml.rb: ditto
- * lib/erb.rb: ditto
- * lib/irb.rb: ditto
- * lib/tracer.rb: ditto
- * lib/net/http.rb: ditto
- * ext/syslog/lib/syslog/logger.rb: ditto
- * sample/pty/expect_sample.rb: ditto
-
-Thu Jul 18 21:30:50 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_sq_fast): Specialize the last iteration of the
- outer loop.
- (bigfixize): A condition simplified.
-
-Thu Jul 18 21:15:41 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_equal): compare RARRAY_PTR() for performance
- improvement in case of that self and other are shared.
-
-Thu Jul 18 20:44:51 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_fill): use memfill().
-
-Thu Jul 18 20:35:14 2013 Benoit Daloze <eregontp@gmail.com>
-
- * array.c (rb_ary_count): check length to avoid SEGV
- while iterating. Remove other pointer loop when arg is given.
-
- * test/ruby/test_array.rb (test_count): add test for bug.
- [ruby-core:56072] [Bug #8654]
-
-Thu Jul 18 18:14:36 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_count): iterate items appropriately.
- [Bug #8654]
-
-Thu Jul 18 17:35:41 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_flatten): performance improvement by not using
- rb_hash_to_a() to avoid array creation with rb_assoc_new().
-
-Thu Jul 18 16:16:17 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c: add logging feature for RGenGC's write barrier unprotect
- event.
-
-Thu Jul 18 15:45:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (RUBY_SAFE_LEVEL_CHECK): make only
- rb_set_safe_level(4) an error always but make rb_secure(4) an error
- only in the core. [ruby-dev:47517] [Bug #8652]
-
-Thu Jul 18 15:42:01 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: fix spell miss.
-
-Thu Jul 18 15:11:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (ruby_safe_level_4): get rid of special
- character. [ruby-dev:47512] [misc #8646]
-
-Thu Jul 18 14:51:39 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (ary_alloc): slim setup process.
-
-Thu Jul 18 14:37:57 2013 Koichi Sasada <ko1@atdot.net>
-
- * string.c (str_alloc): no need to clear RString (already cleared).
-
-Thu Jul 18 12:57:47 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (BDIGITS_ZERO): Defined.
- (bary_pack): Use BDIGITS_ZERO.
- (bary_unpack): Ditto.
- (bary_mul_single): Ditto.
- (bary_mul_normal): Ditto.
- (bary_sq_fast): Ditto.
- (bary_mul_balance_with_mulfunc): Ditto.
- (bary_mul_precheck): Ditto.
- (bary_mul_toom3_branch): Ditto.
- (rb_cstr_to_inum): Ditto.
- (big_shift3): Ditto.
- (bigmul1_toom3): Ditto.
- (bary_divmod): Ditto.
-
-Thu Jul 18 06:30:02 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename gc related functions with prefix "gc_".
- * before_gc_sweep() -> gc_before_sweep().
- * after_gc_sweep() -> gc_after_sweep().
- * lazy_sweep() -> gc_lazy_sweep().
- * rest_sweep() -> gc_rest_sweep().
- * slot_sweep() -> gc_slot_sweep().
-
- * gc.c: rename a heap management function with prefix "heap_".
- * get_freeobj() -> heap_get_freeobj().
-
- * gc.c: rename markable_object_p() to is_markable_object().
-
-Wed Jul 17 22:57:40 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (delete_if_i): use ST_DELETE.
-
-Wed Jul 17 22:34:47 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: An static assertion for relation of SIZEOF_LONG and
- SIZEOF_BDIGITS is added.
- (bary_mul_precheck): Reduce comparisons.
- (bary_mul): Invoke bary_sq_fast or bary_mul1 if the bignum size is
- small.
- (bigfixize): Resize the argument bignum here.
- (bignorm): Don't call bigtrunc after bigfixize.
-
-Wed Jul 17 22:13:26 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_replace): performance improvement by using
- st_copy().
-
-Wed Jul 17 17:19:54 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename heap management functions with prefix "heap_".
- * allocate_sorted_array() -> heap_allocate_sorted_array().
- * slot_add_freeobj() -> heap_slot_add_freeobj().
- * assign_heap_slot() -> heap_assign_slot().
- * add_heap_slots() -> heap_add_slots().
- * init_heap() -> heap_init().
- * set_heap_increment() -> heap_set_increment().
-
- * gc.c (initial_expand_heap): inlined in rb_gc_set_params().
-
-Wed Jul 17 17:12:23 2013 Matthew M. Boedicker <matthewm@boedicker.org>
-
- * hash.c (env_fetch): Add key name to message on ENV.fetch KeyError,
- as well as Hash#fetch. [ruby-core:56062] [Feature #8649]
-
-Wed Jul 17 15:59:33 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: catch up last changes for debugging/checking mode.
-
-Wed Jul 17 15:50:10 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_objspace_free): free slot itself.
-
- * gc.c (objspace_each_objects): fix condition.
- Use slot->body instead of slot.
-
- * gc.c (count_objects): use "slot" variable.
-
-Wed Jul 17 15:21:10 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (unlink_heap_slot): fix memory leak.
- free slot itself at free_heap_slot().
-
- Reproduce-able code is here:
- N1 = 100_000; N2 = 1_000_000
- N1.times{ary = []; N2.times{ary << ''}}
- Maybe this problem is remaining in Ruby 2.0.0.
-
- * gc.c (unlink_heap_slot): remove not working code.
-
-Wed Jul 17 14:31:13 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: re-design the heap structure.
-
- (1) The heap is consists of a set of slots.
- (2) Each "slot" has a "slot_body".
- slot::start and slot::limit specify RVALUE beginning address
- and number of RVALUE in a "slot_body".
- (3) "slot_body" contains a pointer to slot (slot_body::header::slot)
- and an array of RVALUE.
- (4) heap::sorted is an array of "slots", sorted by an address of
- slot::body.
-
- See https://bugs.ruby-lang.org/projects/ruby-master/wiki/GC_design
- for more details (figure).
-
- * gc.c: Avoid "heaps" terminology. It is ambiguous.
-
-Wed Jul 17 13:29:16 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: fix heaps_header and heaps_slot to reduce memory consumption.
- (1) move heaps_header::start and limit to heaps_slot.
- (2) remove heaps_header::end which can be calculated by start+limit.
-
- * gc.c: catch up above change.
-
-Wed Jul 17 12:30:05 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/st.h (st_strcasecmp): Macro defined for compatibility.
- (st_strncasecmp): Ditto.
-
-Wed Jul 17 11:57:45 2013 Takeyuki FUJIOKA <xibbar@ruby-lang.org>
-
- * lib/cgi/util.rb (CGI::Util#escape, unescape): Avoid use of regexp
- special global variable. [Feature #8648] Thanks to fotos.
-
-Wed Jul 17 11:57:10 2013 Takeyuki FUJIOKA <xibbar@ruby-lang.org>
-
- * lib/erb.rb (ERB::Util#url_encode): Avoid use of regexp special global
- variable. [Feature #8648] Thanks to fotos.
-
-Wed Jul 17 08:12:41 2013 Tanaka Akira <akr@fsij.org>
-
- * st.c (st_locale_insensitive_strcasecmp): Renamed from st_strcasecmp.
- (st_locale_insensitive_strncasecmp): Renamed from st_strncasecmp.
-
- * include/ruby/st.h: Follow above changes.
-
- * include/ruby/ruby.h: Ditto.
-
-Wed Jul 17 00:14:59 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigmul1_toom3): Use bigdivrem_single instead of bigdivrem.
- (big_three): Removed.
- (Init_Bignum): Don't initialize big_three.
-
-Tue Jul 16 21:46:03 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * configure.in: revert r42008. strcasecmp() uses the current locale.
-
- * include/ruby/ruby.h: ditto.
-
- * st.c (st_strcasecmp): ditto.
-
-Tue Jul 16 21:07:04 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * configure.in: check strcasecmp().
-
- * include/ruby/ruby.h: use strcasecmp() as st_strcasecmp() if it
- exists.
-
- * st.c (st_strcasecmp): define the function only if strcasecmp()
- doesn't exist.
-
-Tue Jul 16 20:21:28 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigsq): Renamed from bigsqr.
-
-Tue Jul 16 19:42:08 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (USHORT): Unused macro removed.
-
-Tue Jul 16 19:18:51 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: slim a path of newobj_of().
-
- * gc.c (objspace): add a new field objspace::freelist, which contains
- available RVALUEs.
-
- * gc.c (newobj_of): simply call new function `get_freeobj()'.
- get_freeobj() returns objspace::freelist. If objspace::freelist
- is not available, refill objspace::freelist with a slot pointed by
- objspace::heap::free_slots.
-
- * gc.c (before_gc_sweep): clear objspace::freelist.
-
- * gc.c (slot_sweep): clear slot::freelist.
-
- * gc.c (heaps_prepare_freeslot): renamed to heaps_prepare_freeslot.
-
- * gc.c (unlink_free_heap_slot): remove unused function.
-
- * gc.c (rb_free_const_table): remove unused function.
-
-Tue Jul 16 19:05:12 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big_shift3): Big shift width is not a problem for right
- shift.
-
-Tue Jul 16 18:50:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_count): [DOC] fix typo. Array#count uses ==, not
- ===. a question at asakusa.rb ML.
-
-Tue Jul 16 18:35:48 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul_karatsuba): Avoid duplicate calculation when
- squaring.
- (bary_mul_toom3_branch): Ditto.
-
-Tue Jul 16 17:43:22 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (link_free_heap_slot): removed.
-
- * gc.c (slot_sweep): use `heaps_add_freeslot' instead of
- `link_free_heap_slot'.
-
- * gc.c (assign_heap_slot): use local variable `slot' instead of
- `heaps'.
-
-Tue Jul 16 17:21:39 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (assign_heap_slot): refactoring variable names.
-
- * gc.c (slot_add_freeobj): added.
-
- * gc.c (heaps_add_freeslot): added.
-
- * gc.c (finalize_list, rb_gc_force_recycle, slot_sweep): use
- `slot_add_freeobj' instead of modifying linked list directly.
-
-Tue Jul 16 16:30:58 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (lazy_sweep): refactoring.
-
-Tue Jul 16 13:32:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * encoding.c (enc_set_index): since r41967, old terminator is dealt
- with in str_fill_term(). should not consider it here because this
- function is called before any encoding is set.
-
-Tue Jul 16 11:12:03 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * proc.c (rb_block_arity): raise ArgumentError if no block given.
-
-Tue Jul 16 08:15:22 2013 Zachary Scott <e@zzak.io>
-
- * ext/bigdecimal/lib/bigdecimal/util.rb: [DOC] document top-level
- classes from BigDecimal utils native extensions
-
-Tue Jul 16 03:23:03 2013 Zachary Scott <e@zzak.io>
-
- * numeric.c: [DOC] improve rdoc formatting for parameters and links
-
-Mon Jul 15 14:40:00 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/intern.h (rb_big2str0): Deprecated.
-
- * bignum.c (rb_big2str1): Renamed from rb_big2str0.
- (rb_big2str0): Deprecated wrapper for rb_big2str1.
- (rb_big2str): Invoke rb_big2str1 instead of rb_big2str0.
-
-Mon Jul 15 14:13:02 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * struct.c (rb_struct_each_pair): use rb_yield_values(2, key, value)
- instead of rb_yield(rb_assoc_new(key, value)) if rb_block_arity()
- is greater than 1.
-
-Mon Jul 15 13:46:26 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: Add static assertions.
-
-Mon Jul 15 13:36:02 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_each_pair): performance improvement by using
- rb_block_arity().
-
-Mon Jul 15 13:15:37 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * proc.c (rb_block_arity): create internal API rb_block_arity().
- it returns arity of given block.
-
-Mon Jul 15 13:07:27 2013 Yuki Yugui Sonoda <yugui@yugui.jp>
-
- * lib/prime.rb (Prime::EratosthenesGenerator,
- Prime::EratosthenesSieve): New implementation by
- robertjlooby <robertjlooby AT gmail.com>.
-
- * test/test_prime.rb: updated with new method name
-
-Mon Jul 15 11:32:46 2013 Zachary Scott <e@zzak.io>
-
- * numeric.c (rb_cNumeric): [DOC] Added comment for Numeric to fix doc
-
-Mon Jul 15 11:24:48 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (maxpow_in_bdigit_dbl): Useless #if removed.
-
-Mon Jul 15 11:10:46 2013 Zachary Scott <e@zzak.io>
-
- * bignum.c (rb_big_coerce): [DOC] Add docs for Bignum#coerce
- Based on patch by Juanito Fatas [Fixes GH-360]
- https://github.com/ruby/ruby/pull/360
-
-Mon Jul 15 10:56:01 2013 Zachary Scott <e@zzak.io>
-
- * thread.c (mutex_sleep): [DOC] Awake thread will reacquire lock
- By Tim Abdulla [Fixes GH-342] https://github.com/ruby/ruby/pull/342
-
-Mon Jul 15 10:45:09 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (nlz16): Use __builtin_clz if possible.
- (nlz32): Use __builtin_clz or __builtin_clzl if possible.
- (nlz64): Use __builtin_clzl or __builtin_clzll if possible.
- (nlz128): Use __builtin_clzll if possible.
-
- * configure.in: Check __builtin_clz, __builtin_clzl and
- __builtin_clzll.
-
-Mon Jul 15 09:39:07 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (power_cache_get_power): Use bitsize instead of ceil_log2.
- (ones): Removed.
- (next_pow2): Removed.
- (floor_log2): Removed.
- (ceil_log2): Removed.
-
- * configure.in (__builtin_popcountl): Don't check.
-
-Mon Jul 15 02:47:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * localeinit.c (rb_locale_charmap, Init_enc_set_filesystem_encoding):
- move from encoding.c.
-
- * miniinit.c (rb_locale_charmap, Init_enc_set_filesystem_encoding):
- define miniruby specific functions only.
-
-Mon Jul 15 02:32:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * encoding.c (rb_enc_init): no longer needs NO_PRESERVED_ENCODING.
-
- * encoding.c (enc_inspect): defer loading autoloaded encoding.
-
- * encoding.c (enc_check_encoding): use is_data_encoding() to check
- type consistently.
-
- * encoding.c (must_encoding): return rb_encoding* instead of encoding
- index.
-
- * encoding.c (enc_check_encoding): use is_data_encoding() to check
- type consistently.
-
- * encoding.c (must_encoding): return rb_encoding* instead of encoding
- index.
-
-Mon Jul 15 02:21:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (str_fill_term): consider old terminator length, and should
- not use rb_enc_ascget since it depends on the current encoding which
- may not be compatible with the new terminator. [Bug #8634]
-
- * encoding.c (enc_inspect): use PRIsVALUE to preserve the result
- encoding.
-
-Sun Jul 14 23:21:47 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Check __builtin_popcountl, __builtin_bswap32 and
- __builtin_bswap64.
-
- * internal.h (swap32): Use the configure result for the condition to
- use __builtin_bswap32.
- (swap64): Use the configure result for the condition to use
- __builtin_bswap64.
-
- * bignum.c (ones): Use the configure result for the condition to use
- __builtin_popcountl.
- (bary_unpack_internal): Use appropriate types for swap argument.
-
-Sun Jul 14 22:21:11 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_subb): Support xn < yn.
- (bigsub_core): Removed.
- (bigsub): Don't compare before subtraction. Just subtract and
- get the two's complement if the subtraction causes a borrow.
-
-Sun Jul 14 00:36:03 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (DIGSPERLONG): Unused macro removed.
- (DIGSPERLL): Ditto.
-
-Sun Jul 14 00:32:51 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_aref): Less scan when the number is negative.
-
-Sun Jul 14 00:17:42 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big_shift): Avoid signed integer overflow.
-
-Sun Jul 14 00:14:15 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul_precheck): Use bary_small_lshift or
- bary_mul_normal if xl is 1.
-
-Sat Jul 13 22:58:16 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big_shift3): New function.
- big_lshift and big_rshift are merged.
- (big_shift2): New function.
- (big_lshift): Use big_shift3.
- (big_rshift): Ditto.
- (check_shiftdown): Removed.
- (rb_big_lshift): Use big_shift2 and big_shift3.
- (rb_big_rshift): Ditto.
- (big_lshift): Removed.
- (big_rshift): Ditto.
-
-Sat Jul 13 15:51:38 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_small_lshift): Use size_t instead of long.
- (bary_small_rshift): Ditto.
-
-Sat Jul 13 15:33:33 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_small_lshift): Functions moved to remove
- declaration.
- (bary_small_rshift): Ditto.
-
-Sat Jul 13 12:27:34 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * encoding.c (rb_enc_associate_index): fill new terminator length, not
- old one.
-
-Sat Jul 13 12:24:24 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32: move from ext/dl and ext/fiddle. since ext/extmk.rb
- builds extensions in alphabetical order, compiled?('fiddle') under
- ext/dl makes no sense.
-
-Sat Jul 13 09:26:09 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (biglsh_bang): Removed.
- (bigrsh_bang): Ditto.
- (bigmul1_toom3): Use bary_small_lshift and bary_small_rshift.
-
-Sat Jul 13 01:04:43 2013 Zachary Scott <e@zzak.io>
-
- * lib/rubygems/psych_additions.rb: Ignore Psych docs here
-
-Fri Jul 12 18:10:46 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/fiddle/win32/lib/win32/registry.rb
- (Win32::Registry::API#make_wstr): same as r41922.
-
-Fri Jul 12 16:28:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * encoding.c (rb_enc_associate_index): refill the terminator if it
- becomes longer than before. [ruby-dev:47500] [Bug #8624]
-
- * string.c (str_null_char, str_fill_term): get rid of out of bound
- access.
-
- * string.c (rb_str_fill_terminator): add a parameter for the length of
- new terminator.
-
-Fri Jul 12 11:26:25 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_reject_bang): do not call rb_hash_foreach() if RHash
- has ntbl and it is empty.
-
-Fri Jul 12 11:17:41 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (recursive_hash): use RHASH_SIZE() to check hash size.
-
-Fri Jul 12 00:20:00 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_size): use RHASH_SIZE().
-
-Fri Jul 12 00:08:24 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_values): set array capa to RHASH_SIZE().
-
-Thu Jul 11 23:54:45 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_keys): set array capa to RHASH_SIZE().
-
-Thu Jul 11 21:30:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (rb_w32_pow): undef pow to get rid of infinite
- recursive call. re-fix [Bug #8495]. [ruby-core:55923] [Bug #8621]
-
-Thu Jul 11 20:18:13 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/dl/win32/lib/win32/registry.rb (Win32::Registry::API#make_wstr):
- remove workaround to append WCHAR terminator.
-
- * transcode.c (str_encode_associate): fill terminator after conversion.
-
- * string.c (rb_enc_str_new, rb_str_set_len, rb_str_resize): fill
- minimum length of the encoding as the terminator.
-
- * string.c (str_buf_cat, rb_str_buf_append, rb_str_splice_0): ditto.
-
- * string.c (str_make_independent_expand, rb_str_modify_expand): make
- the capacity enough for multi-byte terminator.
-
- * string.c (rb_string_value_cstr): fill minimum length of the encoding
- as the terminator.
-
- * string.c (rb_string_value_cstr): check null char in char, not in
- byte.
-
-Thu Jul 11 14:48:35 2013 Zachary Scott <e@zzak.io>
-
- * array.c: Replace confusing example for #reverse_each in overview
- Patch by Earl St Sauver [Fixes documenting-ruby/ruby-12]
- https://github.com/documenting-ruby/ruby/pull/12
-
-Thu Jul 11 14:22:37 2013 Zachary Scott <e@zzak.io>
-
- * test/drb/ut_eq.rb: Use localhost for drb tests [Bug #7311]
- Patch by Vit Ondruch [ruby-core:49101]
- * test/drb/ut_array.rb: ditto
- * test/drb/ut_array_drbssl.rb: ditto
-
-Thu Jul 11 13:48:03 2013 Zachary Scott <e@zzak.io>
-
- * sprintf.c: Fix typo patch by @hynkle [Fixes GH-357]
- https://github.com/ruby/ruby/pull/357
-
-Thu Jul 11 13:00:34 2013 Zachary Scott <e@zzak.io>
-
- * lib/securerandom.rb: Refactor conditions by Rafal Chmiel
- [Fixes GH-326] https://github.com/ruby/ruby/pull/326
-
-Thu Jul 11 12:04:47 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: Don't use toom3 after once karatsuba is chosen.
- (mulfunc_t): New type.
- (bary_mul_toom3_start): Renamed from bary_mul.
- (bary_mul_karatsuba_start): Renamed from bary_mul.
- (bary_mul_balance_with_mulfunc): Renamed from bary_mul_balance and
- new argument, mulfunc, is added.
- (rb_big_mul_balance): Invoke bary_mul_balance_with_mulfunc with
- bary_mul_toom3_start.
- (bary_mul_karatsuba): Invoke bary_mul_karatsuba_start instead of
- bary_mul.
- (bary_mul_precheck): Extracted from bary_mul.
- (bary_mul_karatsuba_branch): Extracted from bary_mul.
- (bary_mul_karatsuba_start): New function to call bary_mul_precheck
- and bary_mul_karatsuba_branch.
- (bary_mul_toom3_branch): Extracted from bary_mul.
- (bary_mul_toom3_start): New function to call bary_mul_precheck and
- bary_mul_toom3_branch.
- (bary_mul): Just call bary_mul_toom3_start.
- Arguments for work memory are removed.
- (rb_cstr_to_inum): Follow the bary_mul change.
- (bigmul0): Ditto.
-
-Thu Jul 11 10:46:38 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/probes_to_wiki.rb: fix usage comment. use Enumerable#grep
- which yields each elements to reduce unnecessary array.
-
-Thu Jul 11 10:09:18 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * process.c (rb_daemon): daemon(3) is implemented with fork(2).
- Therefore it needs rb_thread_atfork(). (and revert r41903)
-
-Thu Jul 11 03:22:10 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * tool/probes_to_wiki.rb: adding a script to convert probes.d to wiki
- format for easy wiki updates.
-
-Thu Jul 11 00:54:07 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * man/ri.1: Incorrect use of .Dd macro [Bug #8620] by Tristan Hill
-
-Thu Jul 11 00:48:29 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/delegate.rb: Add example for __setobj__ and __getobj__
- [Bug #8615] Patch by Caleb Thompson
-
-Wed Jul 10 23:29:22 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/logger.rb: Use :call-seq: for method signature rdoc
-
-Wed Jul 10 23:23:18 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/logger.rb (#add): Remove incorrect rdoc for return value
- [Bug #8567] Reported by Tim Pease.
-
-Wed Jul 10 23:12:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_subpos): make public function.
-
-Wed Jul 10 22:44:19 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: Add a static assertion for RBIGNUM_EMBED_LEN_MAX.
-
-Wed Jul 10 22:31:25 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * string.c (rb_str_index): cache single byte flag and some
- cosmetic changes.
-
-Wed Jul 10 22:03:27 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_2comp): Don't use bary_plus_one.
- (bary_add_one): Replaced by the implementation of bary_plus_one.
-
-Wed Jul 10 20:48:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * bignum.c (sizeof_bdigit_dbl): check sizeof(BDIGIT_DBL).
-
- * internal.h (STATIC_ASSERT): move from enum.c.
-
-Wed Jul 10 20:08:21 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (SIZEOF_BDIGIT_DBL): Add a ifdef guard for test.
-
-Wed Jul 10 14:18:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * process.c (fork_daemon): kill the other threads all and abandon the
- kept mutexes.
-
-Wed Jul 10 11:35:36 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/net/http/test_http.rb (TestNetHTTP_v1_2#test_get,
- TestNetHTTP_v1_2_chunked#test_get): shouldn't check
- HttpResponse#decode_content if Zlib is not available.
- ko1 complained via IRC.
-
-Wed Jul 10 10:20:07 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/rbinstall.rb: always require rubygems to stabilize rubygems
- related status like whether Gem::Specification is defined or not.
-
- * tool/rbinstall.rb (Gem::Specification.unresolved_deps): define stub.
-
-Wed Jul 10 08:21:15 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Import RubyGems 2.1
- * test/rubygems: Ditto.
-
-Wed Jul 10 07:34:34 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/ext/ext_conf_builder.rb: Remove siteconf file after
- building the gem.
- * test/rubygems/test_gem_ext_ext_conf_builder.rb: Test for the above.
-
- * lib/rubygems/psych_tree.rb (module Gem): Add backward compatibility
- for r41148
-
- * test/rubygems/test_gem_package.rb: Add backward compatibility for
- double-slash elimination.
-
-Wed Jul 10 06:22:27 2013 Tadayoshi Funaba <tadf@dotrb.org>
-
- * ext/date/date_parse.c (date_zone_to_diff): [ruby-core:55831].
-
-Wed Jul 10 00:41:42 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul): x*1 is x.
-
-Tue Jul 9 22:24:39 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul1): No need to invoke MEMZERO at last.
- (bary_mul_single): Invoke MEMZERO here.
-
-Tue Jul 9 21:40:01 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_text.rb: Add missing tests for Text#<<.
- Reported by nagachika. Thanks!!!
-
-Tue Jul 9 18:02:38 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/fileutils.rb (FileUtils#chown_R): Do not skip traversal even
- if user and group are both nil, to be consistent with #chown and
- other commands.
-
-Tue Jul 9 17:58:26 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * test/fileutils/test_fileutils.rb
- (TestFileUtils#assert_output_lines): New utility assertion
- method for testing verbose output.
-
-Tue Jul 9 17:43:57 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/test_tracer.rb: catch up recent rubygems changes.
-
-Tue Jul 9 16:58:30 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/{dl,fiddle}/win32/lib/win32/registry.rb: hope that the final
- resolution to fix the failure of test-all. and includes Win64
- support (fixed a potential bug).
-
-Tue Jul 9 15:57:20 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * object.c: Fix rdoc for Kernel#<=>. [Fixes GH-352]
-
-Tue Jul 9 15:53:51 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/fileutils.rb (FileUtils#mode_to_s): Define mode_to_s() also
- as singleton method, or FileUtils.chmod fails in verbose mode.
-
-Tue Jul 9 15:16:02 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * test/fileutils/fileasserts.rb
- (Test::Unit::FileAssertions#assert_not_symlink): Add a missing
- optional argument "message".
-
-Tue Jul 9 15:03:24 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/fileutils.rb (FileUtils#chown, FileUtils#chown_R): If user
- and group are both nil, print ":".
-
-Tue Jul 9 12:47:08 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * io.c (appendline): use READ_CHAR_PENDING_XXX macros and
- RSTRING_END().
-
- * io.c (rb_io_getline_1): rewrite nested if statement into one
- statement.
-
-Tue Jul 9 11:04:35 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/{dl,fiddle}/win32/lib/win32/registry.rb (Win32::Registry#check):
- should report the position of the error.
-
- * ext/{dl,fiddle}/win32/lib/win32/registry.rb
- (Win32::Registry#QueryValue): workaround for test-all crash.
-
-Tue Jul 9 10:27:56 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/{dl,fiddle}/win32/lib/win32/registry.rb
- (Win32::Registry.expand_environ): use suitable encoding for the
- string.
-
- * ext/{dl,fiddle}/win32/lib/win32/registry.rb (Win32::Registry#read):
- should return REG_SZ, REG_EXPAND_SZ and REG_MULTI_SZ values with
- the expected encoding -- assumed as the same encoding of name.
-
-Tue Jul 9 10:02:45 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/{dl,fiddle}/win32/lib/win32/registry.rb
- (Win32::Registry::Error#initialize): use suitable encoding for the
- string.
-
-Tue Jul 9 09:46:53 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/dl/win32/lib/win32/registry.rb (Win32::Registry.expand_environ):
- use suitable encoding for the string. fixed a test-all error of
- r41838.
-
- * ext/fiddle/win32/lib/win32/registry.rb: same changes of r41838 and
- this revision of dl's win32/registry.rb.
-
-Tue Jul 9 07:39:45 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems 2.0.4. See
- https://github.com/rubygems/rubygems/blob/2.0/History.txt for changes
-
-Tue Jul 9 01:47:16 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (biglsh_bang): Don't shift a BDIGIT with BITSPERDIG bits.
- (bigrsh_bang): Ditto.
-
-Tue Jul 9 01:17:57 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigrsh_bang): Fix bignum digits overrun.
-
-Tue Jul 9 00:46:22 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (biglsh_bang): Fix bignum digits under-run.
-
-Mon Jul 8 23:36:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/dl/win32/lib/win32/registry.rb (Error, API): use WCHAR
- interfaces. c.f. [Bug #8508]
-
-Mon Jul 8 23:13:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (rb_w32_pow): move from win32.h and disable strict
- ANSI mode macro to let _controlfp() stuff defined.
- [ruby-core:55312] [Bug #8495]
-
- * numeric.c (finite): add declaration for strict ANSI.
- [ruby-core:55312] [Bug #8495]
-
- * thread_win32.c (w32_thread_start_func, thread_start_func_1),
- (timer_thread_func): use __stdcall instead of _stdcall which is
- unavailable in strict ANSI mode. [ruby-core:55312] [Bug #8495]
-
- * win32/win32.c (gettimeofday): use __cdecl instead of _cdecl.
-
-Mon Jul 8 22:41:12 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul): Arguments for work memory added.
- (bary_mul_balance): Ditto.
- (bary_mul_karatsuba): Ditto.
-
-Mon Jul 8 22:03:30 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_sq_fast): New function for testing.
- (rb_big_mul_toom3): Ditto.
-
- * internal.h (rb_big_sq_fast): Declared.
- (rb_big_mul_toom3): Ditto.
-
-Mon Jul 8 21:59:34 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul_balance): Initialize a local variable to suppress
- a warning.
-
-Mon Jul 8 20:55:22 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul_balance): Reduce work memory.
-
-Mon Jul 8 08:26:15 2013 Martin Bosslet <Martin.Bosslet@gmail.com>
-
- * test/openssl/test_pkey_ec.rb: Skip tests for "Oakley" curves as
- they are not suitable for ECDSA.
- [ruby-core:54881] [Bug #8384]
-
-Mon Jul 8 08:03:01 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul): Add a RB_GC_GUARD.
-
-Sun Jul 7 23:56:32 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul_karatsuba): Unreachable code removed. Remove
- several branches.
-
-Sun Jul 7 22:59:06 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (rb_big_mul_normal): Declared.
- (rb_big_mul_balance): Ditto.
- (rb_big_mul_karatsuba): Ditto.
-
- * bignum.c (rb_big_mul_normal): New function for tests.
- (rb_big_mul_balance): Ditto.
- (rb_big_mul_karatsuba): Ditto.
-
-Sun Jul 7 19:21:30 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: Reorder functions to decrease forward reference.
-
-Sun Jul 7 14:41:57 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: (bigsub_core): Use bary_sub.
- (bary_sub): Returns a borrow flag. Use bary_subb.
- (bary_subb): New function for actually calculating subtraction with
- borrow.
- (bary_sub_one): New function.
- (bigadd_core): Use bary_add.
- (bary_add): Returns a carry flag. Use bary_addc.
- (bary_addc): New function for actually calculating addition with
- carry.
- (bary_add_one): New function.
- (bary_muladd_1xN): Extracted from bary_mul_normal.
- (bigmul1_normal): Removed.
- (bary_mul_karatsuba): New function.
- (bary_mul1): Invoke rb_thread_check_ints after bary_mul_normal.
- (bary_mul): Remove most and least significant zeros before actual
- multiplication. Use bary_sq_fast, bary_mul_balance,
- bary_mul_karatsuba and bigmul1_toom3 as bigmul0.
- (bigmul1_balance): Removed.
- (bigmul1_karatsuba): Removed.
- (bigsqr_fast): Removed.
- (bary_sparse_p): Extracted from big_sparse_p.
- (big_sparse_p): Removed.
- (bigmul0): Use bary_mul.
-
-Sun Jul 7 11:54:33 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * NEWS: Add REXML::Text#<< related updates.
-
-Sun Jul 7 11:49:19 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/text.rb (REXML::Text#<<): Support appending in not
- "raw" mode. [Bug #8602] [ruby-dev:47482]
- Reported by Ippei Obayashi. Thanks!!!
-
-Sun Jul 7 11:43:13 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/text.rb (REXML::Text#<<): Support method chain use by "<<"
- like other objects.
-
-Sun Jul 7 11:34:18 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/text.rb (REXML::Text#clear_cache): Extract common
- cache clear code.
-
-Sun Jul 7 11:01:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (RUBY_DTRACE_POSTPROCESS): dtrace version SUN D 1.11
- introduces a check in the dtrace compiler to ensure that probes
- actually exist. If there are no probes, then the -G step will
- fail. As this test is only being used to determine whether -G is
- necessary (for instance, on OSX it is not), adding a real probe to
- the conftest allows it to succeed on newer versions of dtrace.
- Patch by Eric Saxby <sax AT livinginthepast.org> at
- [ruby-core:55826]. [Fixes GH-351], [Bug #8606].
-
-Sun Jul 7 10:07:22 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_sq_fast): Extracted from bigsqr_fast and
- ensure not to access zds[2*xn].
- (bigsqr_fast): Allocate the result bignum with 2*xn words.
-
-Sat Jul 6 07:37:43 2013 Martin Bosslet <Martin.Bosslet@gmail.com>
-
- * ext/openssl/ossl_pkey_ec.c: Ensure compatibility to builds of
- OpenSSL with OPENSSL_NO_EC2M defined, but OPENSSL_NO_EC not
- defined.
- * test/openssl/test_pkey_ec.rb: Iterate over built-in curves
- (and assert their non-emptiness!) instead of hard-coding them, as
- this may cause problems with respect to the different availability
- of individual curves in individual OpenSSL builds.
- [ruby-core:54881] [Bug #8384]
-
- Thanks to Vit Ondruch for providing the patch!
-
-Sat Jul 6 07:12:39 2013 Martin Bosslet <Martin.Bosslet@gmail.com>
-
- * test/openssl/test_x509crl.rb: Remove unused variable.
- [ruby-core:53501] [Bug #8114]
-
- Thanks, Vipul Amler, for pointing this out!
-
-Sat Jul 6 06:37:10 2013 Martin Bosslet <Martin.Bosslet@gmail.com>
-
- * ext/openssl/ossl.c: Provide CRYPTO_set_locking_callback() and
- CRYPTO_set_id_callback() callback functions ossl_thread_id and
- ossl_lock_callback to ensure the OpenSSL extension is usable in
- multi-threaded environments.
- [ruby-core:54900] [Bug #8386]
-
- Thanks, Dirkjan Bussink, for the patch!
-
-Sat Jul 6 06:06:16 2013 Martin Bosslet <Martin.Bosslet@gmail.com>
-
- * lib/openssl/ssl.rb: Fix SSL client connection crash for SAN marked
- critical.
- The patch for CVE-2013-4073 caused SSL crash when a SSL server returns
- the certificate that has critical SAN value. X509 extension could
- include 2 or 3 elements in it:
-
- [id, criticality, octet_string] if critical,
- [id, octet_string] if not.
-
- Making sure to pick the last element of X509 extension and use it as
- SAN value.
- [ruby-core:55685] [Bug #8575]
-
- Thank you @nahi for providing the patch!
-
-Sat Jul 6 04:49:38 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb: register time objects so
- they are referenced as ids during output.
- * test/psych/test_date_time.rb: corresponding test.
-
-Fri Jul 5 20:46:39 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/ruby/test_unicode_escape.rb (TestUnicodeEscape#test_basic): this
- assertion doesn't seems to be checking the unicode string on command
- line, but seems to be checking how to treat the unicode string from
- stdin. so, should escape '\' before 'u'. this fixes a test failure
- on Windows.
-
-Fri Jul 5 19:05:40 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/fileutils.rb (FileUtils#chown, FileUtils#chown_R): Fix the
- wrong output message when user is nil, which should be "chown
- :group file" instead of "chown group file".
-
-Fri Jul 5 16:21:56 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * test/ruby/test_regexp.rb
- (TestRegexp#test_options_in_look_behind)
- (TestRegexp#assert_match_at): Add tests for another problem
- fixed in Onigmo 5.13.5. Previously Onigmo did not allow option
- enclosures in look-behind, which makes it impossible to
- interpolate a regexp into another in the middle of a look-behind
- pattern. cf. https://github.com/k-takata/Onigmo/pull/17
-
- * test/ruby/test_regexp.rb
- (TestRegexp#test_options_in_look_behind)
- (TestRegexp#assert_match_at): Parse regexps in run time rather
- than in compile time.
-
-Fri Jul 5 12:14:40 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/ruby/test_rubyoptions.rb (TestRubyOptions#test_notfound): after
- r41710, the path of command uses backslash as the separator on
- Windows.
-
-Fri Jul 5 11:29:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/test/unit/assertions.rb (assert_raise_with_message): move from
- test/fileutils/test_fileutils.rb. this is still experimental and
- the interface may be changed.
-
-Fri Jul 5 11:08:00 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (w32_spawn): r41710 made that if the command starts with
- a quote and includes slash, removed the top quote and NOT removed the
- last quote.
- this fixes test failures on test/ruby/test_process.rb and
- test/webrick.
-
-Fri Jul 5 09:53:15 2013 NARUSE, Yui <naruse@ruby-lang.org>
- * lib/mkmf.rb (CONFIG['CPPOUTFILE']): fix r41769; CONFIG['CPPOUTFILE']
- may be nil.
-
-Fri Jul 5 05:39:53 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (BARY_MUL1): Renamed from BARY_MUL.
- (bary_mul1): Renamed from bary_mul.
- (bary_mul): Renamed from bary_mul2.
-
-Fri Jul 5 04:58:05 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul_balance): Extracted from bigmul1_balance and
- use bary_mul2 and bary_add to decrease allocations.
-
-Fri Jul 5 02:14:00 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/fileutils.rb (FileUtils#symbolic_modes_to_i): Fix the wrong
- character class [+-=], which happened to match all desired
- characters but also match undesired characters.
-
- * lib/fileutils.rb (FileUtils.chmod{,_R}): Enhance the symbolic
- mode parser to support the permission symbols u/g/o and multiple
- actions as defined in SUS, so that chmod("g=o+w", file) works as
- expected. Invalid symbolic modes are now rejected with
- ArgumentError.
-
-Fri Jul 5 00:25:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (have_framework): allow header file to check.
- [ruby-core:55745] [Bug #8593]
-
-Thu Jul 4 22:31:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * object.c (rb_obj_equal): Fixed an rb_obj_equal documentation typo
- where "a" was used instead of "obj".
- Fixes GH-349. Patch by @adnandoric
-
-Thu Jul 4 20:39:20 2013 Tanaka Akira <akr@fsij.org>
-
- * tool/make-snapshot: Exit with EXIT_FAILURE when it fails.
-
-Thu Jul 4 20:20:23 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (maxpow_in_bdigit_dbl): Use tables if available.
- (maxpow_in_bdigit): Ditto.
- (U16): New macro.
- (U32): Ditto.
- (U64): Ditto.
- (U128): Ditto.
- (maxpow16_exp): New table.
- (maxpow16_num): New table.
- (maxpow32_exp): New table.
- (maxpow32_num): New table.
- (maxpow64_exp): New table.
- (maxpow64_num): New table.
- (maxpow128_exp): New table.
- (maxpow128_num): New table.
-
-Thu Jul 4 18:25:25 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_cstr_to_inum): Avoid temporary buffer allocation except
- very big base non-power-of-2 numbers.
-
-Thu Jul 4 15:51:56 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (rb_str_succ): use ONIGENC_MBCLEN_CHARFOUND_P correctly.
-
- * string.c (rb_str_dump): ditto.
-
-Thu Jul 4 10:04:11 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * regcomp.c (): Merge Onigmo 5.13.5 23b523076d6f1161.
-
- * [bug] (thanks Akinori MUSHA and Ippei Obayashi)
- Fix a renumbering bug in condition regexp with a named
- capture. [Bug #8583]
- * [spec] (thanks Akinori MUSHA)
- Allow ENCLOSE_OPTION in look-behind.
-
-Thu Jul 4 00:36:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * internal.h (SIGNED_INTEGER_MAX): suppress warning C4146 on VC6.
- seems a logical ORed expression becomes unsigned.
-
-Thu Jul 4 00:13:01 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby_atomic.h (rb_w32_atomic_cas): call InterlockedCompareExchange
- directly.
-
- * ruby_atomic.h (ATOMIC_CAS): fix missing function call.
-
-Wed Jul 3 23:47:35 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby_atomic.h (ATOMIC_CAS): suppress C4022 and C4047 warnings in
- VC6. only InterlockedCompareExchange is declared using PVOID.
-
-Wed Jul 3 22:29:20 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (ruby_digit36_to_number_table): Declared.
-
- * util.c (ruby_digit36_to_number_table): Moved from scan_digits.
-
- * bignum.c (conv_digit): Use ruby_digit36_to_number_table.
-
- * pack.c (hex2num): Ditto.
-
-Wed Jul 3 18:12:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (install_dirs): revert DESTDIR prefix by r39841, since
- it is fixed by r41648. [ruby-core:55760] [Bug #8115]
-
-Wed Jul 3 14:15:25 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (do_stat): use rb_w32_ustati64() in win32.c to get rid of
- mysterious behavior of FindFirstFile() Windows API which treat "<"
- and ">" like as wildcard characters. [ruby-core:55764] [Bug #8597]
-
-Wed Jul 3 12:06:42 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (maxpow_in_bdigit): Renamed from calc_hbase and return
- maxpow.
-
-Tue Jul 2 23:47:50 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (roomof): Cast to long.
- (rb_ull2big): Fix bignew arguments.
-
-Tue Jul 2 21:17:37 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_cstr_to_inum): Merge two temporary buffers.
-
-Tue Jul 2 20:25:04 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_cstr_to_inum): Use BDIGIT_DBL to collect adjacent digits.
- (BDIGIT_DBL_MAX): New macro.
- (maxpow_in_bdigit_dbl): New function.
-
-Tue Jul 2 17:23:33 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * doc/syntax/refinements.rdoc: add description of Module#using and
- refinement inheritance by module inclusion.
-
-Tue Jul 2 17:22:44 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * internal.h: add EUC-JP and Windows-31J.
-
- * re.c (rb_char_to_option_kcode): use built-in encoding indexes in
- internal.h.
-
- * internal.h: add UTF8-MAC.
-
- * dir.c (rb_utf8mac_encoding): use built-in encoding indexes in
- internal.h.
-
- * internal.h: add UTF-{16,32} dummy encodings.
-
- * string.c (rb_str_inspect, str_scrub0): use built-in encoding indexes
- in internal.h.
-
- * internal.h: add UTF-{16,32}{BE,LE}.
-
- * io.c (io_strip_bom): use built-in encoding indexes in internal.h.
-
- * internal.h (rb_{ascii8bit,utf8,usascii}_encindex): use built-in
- encoding indexes for optimization.
-
- * encoding.c (enc_inspect, rb_locale_encindex),
- (enc_set_filesystem_encoding, rb_filesystem_encindex): use built-in
- encoding indexes directly.
-
- * encoding.c (rb_enc_set_index, rb_enc_associate_index): validate
- argument encoding index.
-
- * include/ruby/encoding.h (ENCODING_SET): use rb_enc_set_index()
- instead of setting inlined bits directly.
-
- * encoding.c (rb_enc_init): register preserved indexes.
-
- * internal.h (ruby_preserved_encindex): move from encoding.c.
-
-Tue Jul 2 11:14:36 2013 Shota Fukumori <sorah@cookpad.com>
-
- * lib/mkmf.rb (try_config): Fix to not replace $LDFLAGS with $libs
- (1.9.3 behavior) [ruby-core:55752] [Bug #8595]
-
-Tue Jul 2 00:39:59 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/ipsocket.c (init_inetsock_internal): Don't try mismatched
- address family if already failed.
-
-Mon Jul 1 23:07:38 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * template/encdb.h.tmpl: define encoding index macros to use the index
- statically from C source.
-
-Mon Jul 1 22:57:19 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul2): New function.
- (rb_cstr_to_inum): Use a better algorithm to compose the result
- if input length is very long.
-
-Mon Jul 1 20:22:00 2013 Kenta Murata <mrkn@cookpad.com>
-
- * ext/bigdecimal/bigdecimal.h (RB_UNUSED_VAR, UNREACHABLE):
- import macros from ruby.h for 1.9.3.
- [Bug #8588] [ruby-core:55730]
-
- * ext/bigdecimal/bigdecimal.gemspec: Bump version to 1.2.1.
-
-Mon Jul 1 20:03:39 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/ipsocket.c (init_inetsock_internal): Use an address
- family for local address which is different to the remote
- address if no other choice.
-
-Mon Jul 1 15:05:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/csv.rb (CSV#<<): use StringIO#set_encoding instead of creating
- new StringIO instance with String#force_encoding, forcing encoding
- discards the cached coderange bits and can make further operations
- very slow. [ruby-core:55714] [Bug #8585]
-
- * ext/stringio/stringio.c (strio_write): keep coderange of
- ptr->string.
-
- * string.c (rb_enc_cr_str_buf_cat, rb_str_append): consider an empty
- string 7bit-clean and should not discard cached coderange of string
- to be appended.
-
-Mon Jul 1 12:56:41 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * eval.c (rb_using_module): activate refinements in the ancestors of
- the argument module to support refinement inheritance by
- Module#include. [ruby-core:55671] [Feature #8571]
-
- * test/ruby/test_refinement.rb: related test.
-
-Mon Jul 1 12:02:39 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_cstr_to_inum): Skip leading zeros.
-
-Mon Jul 1 00:59:23 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (nlz16): New function.
- (nlz32): Ditto.
- (nlz64): Ditto.
- (nlz128): Ditto.
- (nlz): Redefined using an above function.
- (bitsize): New macro.
- (rb_cstr_to_inum): Use bitsize instead of nlz.
-
-Sun Jun 30 22:40:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * lib/prime.rb: Corrected a few comments. Patch by @Nullset14.
- Fixes GH-346.
-
-Sun Jun 30 21:53:38 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_cstr_to_inum): Use rb_integer_unpack if base is a power
- of 2.
-
-Sun Jun 30 10:59:23 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (join_argv): use backslash instead of slash in program
- path, otherwise cannot invoke "./c\u{1ee7}a.exe" for some reason.
- [ruby-core:24309] [Bug #1771]
-
- * io.c (spawnv, spawn): use UTF-8 spawn family. [Bug #1771]
-
- * process.c (proc_exec_sh, proc_spawn_cmd, proc_spawn_sh): ditto.
-
- * win32/win32.c (translate_char, join_argv, has_redirection): make
- codepage aware.
-
- * win32/win32.c (rb_w32_udln_find_exe_r, rb_w32_udln_find_file_r):
- codepage independent versions.
-
- * win32/win32.c (w32_spawn): extract codepage aware code from
- rb_w32_spawn().
-
- * win32/win32.c (rb_w32_uspawn): add UTF-8 version function.
-
- * win32/win32.c (w32_aspawn_flags): extract codepage aware code from
- rb_w32_aspawn_flags().
-
- * win32/win32.c (rb_w32_uaspawn_flags, rb_w32_uaspawn_flags): add
- UTF-8 version functions.
-
- * win32/win32.c (w32_getenv): extract codepage aware code from
- rb_w32_ugetenv() and rb_w32_getenv().
-
- * win32/win32.c (w32_stati64): extract codepage aware code from
- rb_w32_ustati64() and rb_w32_stati64().
-
- * dln.h (DLN_FIND_EXTRA_ARG, DLN_FIND_EXTRA_ARG_DECL): allow extra
- arguments to dln_find_{exe,file}_r().
-
- * dln_find.c (dln_find_exe_r, dln_find_file_r): add extract arguments.
-
- * process.c (EXPORT_STR, EXPORT_DUP): convert to default process
- encoding if defined.
-
- * process.c (check_exec_env_i): convert environment variables too.
-
- * process.c (rb_exec_fillarg): convert program path and arguments too.
-
-Sun Jun 30 01:57:08 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big_rshift): Use abs2twocomp and twocomp2abs_bang.
-
-Sun Jun 30 00:14:20 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (RBIGNUM_SET_NEGATIVE_SIGN): New macro.
- (RBIGNUM_SET_POSITIVE_SIGN): Ditto.
- (rb_big_neg): Inline get2comp to avoid double negation.
-
-Sat Jun 29 23:26:41 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_neg): Extracted from bary_2comp.
- (bary_plus_one): Extracted from bary_2comp.
- (bary_2comp): Use bary_neg and bary_plus_one.
- (big_extend_carry): Extracted from get2comp.
- (get2comp): Use big_extend_carry.
- (rb_integer_unpack): Use big_extend_carry.
- (rb_big_neg): Use bary_neg.
-
-Sat Jun 29 22:31:59 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_2comp): Simplified.
-
-Sat Jun 29 09:33:53 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigor_int): Return -1 if y == -1.
-
-Sat Jun 29 09:07:16 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigor_int): Use RB_GC_GUARD.
- (bigxor_int): Take xn and hibitsx arguments. Use twocomp2abs_bang.
- (rb_big_xor): Use abs2twocomp and twocomp2abs_bang.
-
-Sat Jun 29 08:19:58 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigand_int): Don't apply bitwise and for BDIGIT and long.
- (bigor_int): Take xn and hibitsx arguments. Use twocomp2abs_bang.
- (rb_big_or): Use abs2twocomp and twocomp2abs_bang.
-
-Fri Jun 29 01:08:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * numeric.c (fix_mul): remove FIT_SQRT_LONG test as it was causing
- fix_mul to return an incorrect result for -2147483648*-2147483648
- on 64 bit platforms
-
- * test/ruby/test_integer_comb.rb (class TestIntegerComb): add test case
-
-Fri Jun 28 12:26:53 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_and): Allocate new bignum with same size to shorter
- argument if it's high bits are zero.
-
-Fri Jun 28 12:14:04 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/ipsocket.c (init_inetsock_internal): Don't use local
- addresses which address family is different to remote address.
-
-Fri Jun 28 08:06:22 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigand_int): Add arguments, xn and hibitsx.
- Use twocomp2abs_bang.
-
-Thu Jun 27 23:58:13 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (abs2twocomp_bang): Removed.
- (abs2twocomp): Take n_ret argument to return actual length.
- (rb_big_and): Follow above change.
-
-Thu Jun 27 22:52:19 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (get2comp): Use bary_2comp.
- (abs2twocomp_bang): New function.
- (abs2twocomp): New function.
- (twocomp2abs_bang): New function.
- (rb_big_and): Use abs2twocomp and twocomp2abs_bang.
-
-Thu Jun 27 20:03:13 2013 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * ext/openssl/lib/openssl/ssl.rb (verify_certificate_identity): fix
- hostname verification. Patched by nahi.
-
- * test/openssl/test_ssl.rb (test_verify_certificate_identity): test for
- above.
-
-
-Thu Jun 27 00:23:57 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_pow): Retry if y is a Bignum and it is
- representable as a Fixnum.
- Use rb_absint_numwords.
-
-Wed Jun 26 23:53:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_save_rounding_mode): fix typo.
- Fixes GH-343. Patch by @jgarber.
-
-Wed Jun 26 23:22:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enumerator.c (rb_enumeratorize_with_size): use strict definition
- rb_enumerator_size_func.
-
-Wed Jun 26 23:11:14 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * gc.c (is_before_sweep): Add a missing space before a parenthesis.
- * gc.c (rb_gc_force_recycle): Add a missing space around a parenthesis.
-
-Wed Jun 26 22:44:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/intern.h (rb_enumeratorize_with_size): cast for
- backward compatibility.
-
- * include/ruby/intern.h (rb_enumerator_size_func): define strict
- function declaration for rb_enumeratorize_with_size().
-
-Wed Jun 26 21:01:22 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * test/ruby/test_io.rb (TestIO#test_write_32bit_boundary): skip if
- writing a file is slow.
- [ruby-core:55541] [Bug #8519]
-
-Wed Jun 26 16:42:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb: should use expanded values for header directories
- unless extmk. patch by vo.x (Vit Ondruch) at [ruby-core:55653]
- [Bug #8115], rhbz#921650.
-
-Wed Jun 26 12:48:22 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigxor_int): Fix a buffer over read.
-
-Wed Jun 26 12:13:12 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigand_int): Consider negative values.
- (bigor_int): The allocated bignum should have enough size
- to store long.
- This fixes (bignum fits in a BDIGIT) | (fixnum bigger than BDIGIT)
- on platforms which SIZEOF_BDIGITS < SIZEOF_LONG,
- such as LP64 with 32bit BDIGIT (no int128).
-
-Wed Jun 26 12:08:51 2013 Tanaka Akira <akr@fsij.org>
-
- * test/socket/test_udp.rb: Close sockets explicitly.
- Don't use fixed port number.
-
-Wed Jun 26 07:27:17 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigand_int): Fix a buffer over read.
-
-Wed Jun 26 06:48:07 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigadd_int): Fix a buffer over read.
-
-Wed Jun 26 01:18:13 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (is_before_sweep): Add new helper function that check the object
- is before sweep?
- * gc.c (rb_gc_force_recycle): Have to clear mark bit if object's slot
- already ready to minor sweep.
-
-Wed Jun 26 01:17:29 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigsub_int): Fix a buffer over read.
-
-Tue Jun 25 22:45:43 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_absint_singlebit_p): Use POW2_P.
- (bary_pack): Ditto.
- (rb_big2str0): Ditto.
- (POW2_P): Moved to top.
-
-Tue Jun 25 22:28:07 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/rubygems/ext/builder.rb (Gem::Ext::Builder.make): Pass
- DESTDIR via command line to override what's in MAKEFLAGS. This
- fixes an installation problem under a package building
- environment where DESTDIR is specified in the (parent) command
- line. [Fixes GH-327]
-
-Tue Jun 25 21:43:13 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2dbl): Use (BDIGIT)1 instead of 1UL.
- (bary_mul_normal): Remove a useless cast.
-
-Tue Jun 25 21:26:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigMath_s_exp): Fix for the cases when
- the argument x is not a BigDecimal.
- This change is based on the patch made by Heesob Park and Garth Snyder.
- [Bug #6862] [ruby-core:47145]
- [Fixes GH-332] https://github.com/ruby/ruby/pull/332
-
-Tue Jun 25 20:36:31 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2ulong): "check" argument removed.
- (rb_big2ulong): Follow above change.
- (rb_big2long): Ditto.
- (rb_big_rshift): Ditto.
- (rb_big_aref): Ditto.
-
-Tue Jun 25 20:08:29 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big2ulong_pack): Use rb_integer_pack.
- (rb_big_aref): Call big2ulong with TRUE for "check" argument.
- It should be non-effective.
-
-Tue Jun 25 19:07:33 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (LSHIFTX): Revert r41611.
- The redundant expression suppresses a warning, C4293, by Visual
- Studio.
- http://ruby-mswin.cloudapp.net/vc10-x64/ruby-trunk/log/20130625T072854Z.log.html.gz#miniruby
-
-Tue Jun 25 19:03:00 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2ulong): Add a cast.
- (big2ull): Add a specialized code for SIZEOF_LONG_LONG <=
- SIZEOF_BDIGITS.
-
-Tue Jun 25 12:42:57 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (integer_unpack_single_bdigit): Use "1 + ~u" instead of
- "-u" to suppress warning (C4146) by Visual Studio.
- Reported by ko1 via IRC.
-
-Tue Jun 25 12:28:57 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2ulong): Add code specialized for SIZEOF_LONG <=
- SIZEOF_BDIGITS.
- This prevents shift width warning from "num <<= BITSPERDIG".
-
-Tue Jun 25 12:23:30 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: fix oldgen/remembered_shady counting algorithm.
-
- * gc.c (rgengc_check_shady): increment
- `objspace->rgengc.remembered_shady_object_count' here.
-
- * gc.c (rgengc_remember): return FALSE if obj is already remembered.
-
- * gc.c (rgengc_rememberset_mark): make it void.
-
- * gc.c (gc_mark_children): fix to double counting oldgen_object_count
- at minor GC.
-
-Tue Jun 25 12:07:18 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (MSB): Removed.
- (BDIGIT_MSB): Defined using BIGRAD_HALF.
- (bary_2comp): Apply BIGLO after possible over flow of BDIGIT.
- (get2comp): Ditto.
- (bary_unpack_internal): Use BDIGIT_MSB.
- Apply BIGLO after possible over flow of BDIGIT.
- (rb_integer_unpack): Use BDIGIT_MSB.
- (calc_hbase): Use BDIGMAX.
- (big2dbl): Use BDIGMAX.
- Apply BIGLO after possible over flow of BDIGIT.
- (rb_big_neg): Apply BIGLO after possible over flow of BDIGIT.
- (biglsh_bang): Ditto.
- (bigrsh_bang): Ditto.
- (bary_divmod): Use BDIGIT_MSB.
- (bigdivrem): Ditto.
- (bigxor_int): Apply BIGLO after possible over flow of BDIGIT.
-
- * marshal.c (shortlen): Use SIZEOF_BDIGITS instead of sizeof(BDIGIT).
-
- * ext/openssl/ossl_bn.c (ossl_bn_initialize): Use SIZEOF_BDIGITS
- instead of sizeof(BDIGIT).
-
-Tue Jun 25 11:40:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * bignum.c (big2ulong): suppress shorten-64-to-32 warning. BDIGIT can
- be bigger than long now.
-
- * bignum.c (LSHIFTX): remove redundant never-true expression.
-
-Tue Jun 25 00:55:54 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (typedef struct rb_objspace): Change members for monitor objects.
- * gc.c (gc_marks_test): Check all WriteBarrier Errors and track them in obj-tree.
- * gc.c (rgengc_check_shady): Ditto.
- * gc.c (gc_marks): Move 2 function calls to gc_marks_test for test initialize.
-
-Mon Jun 24 23:30:31 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (integer_unpack_single_bdigit): Refine code to filling
- higher bits and use BIGLO.
-
-Mon Jun 24 22:26:31 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * test/rinda/test_rinda.rb (RingIPv6#prepare_ipv6):
- ifindex() function may not be implemented on Windows. We use another
- check for the case.
-
-Mon Jun 24 22:11:37 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * test/gdbm/test_gdbm.rb (TestGDBM#test_s_open_nolock):
- skip a failing test on Windows because flock() implementation is
- different from Unix.
-
-Mon Jun 24 22:06:14 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * test/rubygems/test_gem_installer.rb (test_install_extension_flat):
- use ruby in build directory in case ruby is not installed.
- [ruby-core:53265] [Bug #8058]
-
-Mon Jun 24 22:04:02 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * ext/dl/cfunc.c (rb_dlcfunc_call): fix conversion from Bignum to
- pointer. sizeof(DLSTACK_TYPE) is larger than sizeof(long) on
- Windows x64 and higher bits over sizeof(long) of DLSTACK_TYPE was
- zero even if a pointer value was over 32 bits which causes SEGV on
- DL::TestCPtr#test_to_ptr_io. Adding a cast solves the bug.
-
-Mon Jun 24 22:04:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * eval_error.c (warn_printf): use rb_vsprintf instead so ruby specific
- extensions like PRIsVALUE can be used in format strings
- * eval_error.c (error_print): use warn_print_str (alias for
- rb_write_error_str) to print a string value instead of using
- RSTRING_PTR and RSTRING_LEN manually
- * eval.c (setup_exception): use PRIsVALUE instead of %s and RSTRING_PTR
-
-Mon Jun 24 20:31:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * compile.c (make_name_for_block): use PRIsVALUE in format string
- instead of %s and RSTRING_PTR to protect objects from being garbage
- collected too soon
- * encoding.c (str_to_encindex): ditto
- * hash.c (rb_hash_fetch_m): ditto
- * io.c (rb_io_reopen): ditto
- * parse.y (reg_fragment_check_gen): ditto
- * parse.y (reg_compile_gen): ditto
- * parse.y (ripper_assert_Qundef): ditto
- * re.c (rb_reg_raise): ditto
- * ruby.c (set_option_encoding_once): ditto
- * vm_eval.c (rb_throw_obj): ditto
-
-Mon Jun 24 07:57:18 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (after_gc_sweep): Have to record malloc info before reset.
- * gc.c (gc_prof_timer_start): Pick out part of new record creation as gc_prof_setup_new_record.
- * gc.c (gc_prof_set_malloc_info): Move point of recording allocation size to front of mark.
-
-Mon Jun 24 02:53:09 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * array.c: Return value in Array overview example found by @PragTob
- [Fixes GH-336] https://github.com/ruby/ruby/pull/336
-
-Mon Jun 24 02:45:51 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * array.c (rb_ary_zip): typo by @PragTob [Fixes GH-337]
- https://github.com/ruby/ruby/pull/337
-
-Mon Jun 24 02:42:01 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * win32/README.win32: grammar typo by @blankenshipz [Fixes GH-334]
- https://github.com/ruby/ruby/pull/334
-
-Mon Jun 24 00:59:35 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (BIGUP): Use LSHIFTX and avoid cast to consider the type
- of x is bigger than BDIGIT_DBL.
- (big2ulong): Use unsigned long to store the result.
- (big2ull): Use unsigned LONG_LONG to store the result.
- (bigand_int): Use long for num to avoid data loss.
- (bigor_int): Ditto.
- (bigxor_int): Ditto.
-
-Sun Jun 23 23:05:58 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/defines.h (BDIGIT): Define it only if it is not defined
- yet. This eases tests and debug.
- (SIZEOF_BDIGITS): Ditto.
- (BDIGIT_DBL): Ditto.
- (BDIGIT_DBL_SIGNED): Ditto.
- (PRI_BDIGIT_PREFIX): Ditto.
- (PRI_BDIGIT_DBL_PREFIX): Ditto.
- (PRIdBDIGIT): Define it only if PRI_BDIGIT_PREFIX is defined.
- (PRIiBDIGIT): Ditto.
- (PRIoBDIGIT): Ditto.
- (PRIuBDIGIT): Ditto.
- (PRIxBDIGIT): Ditto.
- (PRIXBDIGIT): Ditto.
- (PRIdBDIGIT_DBL): Ditto.
- (PRIiBDIGIT_DBL): Ditto.
- (PRIoBDIGIT_DBL): Ditto.
- (PRIuBDIGIT_DBL): Ditto.
- (PRIxBDIGIT_DBL): Ditto.
- (PRIXBDIGIT_DBL): Ditto.
-
- * include/ruby/ruby.h (RBIGNUM_EMBED_LEN_MAX): Define it only if it is
- not defined yet.
-
-Sun Jun 23 17:29:51 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (integer_unpack_single_bdigit): Use a cast.
-
-Sun Jun 23 15:38:07 2013 Koichi Sasada <ko1@atdot.net>
-
- * bootstraptest/test_thread.rb: rescue resource limitation errors.
-
-Sun Jun 23 08:19:27 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (integer_unpack_single_bdigit): Extracted from
- bary_unpack_internal.
-
-Sun Jun 23 07:41:52 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_unpack_internal): Suppress warnings (C4146) on Visual Studio.
- Reported by ko1 via IRC.
-
-Sun Jun 23 06:49:28 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h, gc.c: rename macros and functions:
- OBJ_WB_GIVEUP() -> OBJ_WB_UNPROTECT(),
- rb_obj_wb_giveup() -> rb_obj_wb_unprotect(),
- rb_gc_giveup_promoted_writebarrier() ->
- rb_gc_writebarrier_unprotect_promoted(),
-
- * class.c, eval.c, hash.c: use OBJ_WB_UNPROTECT().
-
-Sun Jun 23 05:41:32 2013 Koichi Sasada <ko1@atdot.net>
-
- * class.c (rb_include_class_new), eval.c (rb_using_refinement):
- make classes/modules (who share method table) shady.
- If module `a' and `b' shares method table m_tbl and new method
- with iseq is added, then write barrier is applied only `a' or `b'.
- To avoid this issue, shade such classes/modules.
-
- * vm_method.c (rb_method_entry_make): add write barriers.
-
-Sun Jun 23 01:27:54 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bytes_zero_p): Removed.
- (bary_pack): Don't call bytes_zero_p.
-
-Sun Jun 23 00:51:29 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bytes_zero_p): Extracted from bary_pack.
- (bary_pack): Use bytes_zero_p.
-
-Sun Jun 23 00:16:57 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (MSB): New macro.
- (bary_unpack_internal): Use MSB.
- (bary_divmod): Ditto.
- (bigdivrem): Ditto.
-
-Sat Jun 22 23:45:22 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_swap): New function.
- (bary_pack): Use bary_swap.
- (bary_unpack_internal): Ditto.
-
-Sat Jun 22 23:18:39 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bytes_2comp): Renamed from quad_buf_complement.
- (bary_pack): Use bytes_2comp.
- (rb_quad_pack): Use rb_integer_pack.
- (rb_quad_unpack): Use rb_integer_unpack.
-
-Sat Jun 22 21:46:18 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_integer_unpack): Don't allocate a Bignum if possible.
-
-Sat Jun 22 21:03:58 2013 Tanaka Akira <akr@fsij.org>
-
- * pack.c (pack_unpack): Remove specialized unpackers for integers.
-
-Sat Jun 22 20:36:50 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_unpack_internal): Specialized unpacker implemented.
- (bary_unpack): Support INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION.
- (rb_integer_unpack): Support INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION.
-
-Sat Jun 22 18:53:10 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_pack): Support
- INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION flag.
- Fix byte order and word order handling in code specialized for
- wordsize % SIZEOF_BDIGITS == 0.
-
- * internal.h (INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION): Defined.
-
-Sat Jun 22 15:41:25 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rgengc_check_shady): add new WB miss checking
- on RGENGC_CHECK_MODE >= 2.
-
- (1) Save bitmaps before marking
- (2) Run full marking
- (3) On each traceable object,
- (a) object was not oldgen (== newly or shady object) &&
- (b) parent object was oldgen &&
- (c) parent object was not remembered &&
- (d) object was not remembered
- then, it should be WB miss.
-
- This idea of this checker is by Masaya Tarui <tarui@ruby-lang.org>.
-
-Sat Jun 22 15:25:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * ext/etc/etc.c (setup_passwd): revert r41560, unnecessary
-
-Sat Jun 22 14:39:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * ext/etc/etc.c (Init_etc): omit 'passwd' from definition of Etc::Passwd
- if HAVE_STRUCT_PASSWD_PW_PASSWD is not defined to prevent mismatch of
- fields and values in setup_passwd
-
-Sat Jun 22 14:35:40 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/dl/cfunc.c (rb_dlcfunc_call): Use rb_big_pack instead of
- rb_big2ulong_pack and rb_big2ull.
-
- * include/ruby/intern.h (rb_big2ulong_pack): Deprecated.
-
-Sat Jun 22 14:31:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * ext/etc/etc.c (setup_passwd): pass 0 as VALUE to rb_struct_new to
- prevent segfault if the compiler passes it as a 32 bit integer on
- a 64 bit ruby
-
-Sat Jun 22 13:47:13 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_pack): MEMZERO can be used even if nails is not zero.
-
-Sat Jun 22 13:43:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * ext/etc/etc.c (etc_getpwnam): use PRIsVALUE in format string instead
- of %s and RSTRING_PTR
-
- * ext/etc/etc.c (etc_getgrnam): ditto
-
-Sat Jun 22 13:07:15 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (CLEAR_LOWBITS): Rewritten without RSHIFTX.
- (RSHIFTX): Removed.
-
-Sat Jun 22 10:38:03 2013 Tanaka Akira <akr@fsij.org>
-
- * pack.c (num2i32): Removed.
- (pack_pack): Don't use num2i32.
-
-Sat Jun 22 09:55:13 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (LSHIFTX): Defined to suppress a warning.
- (RSHIFTX): Ditto.
- (CLEAR_LOWBITS): Use LSHIFTX and RSHIFTX.
- (FILL_LOWBITS): Use LSHIFTX.
- Reported by ko1 via IRC.
-
-Sat Jun 22 09:11:33 2013 Ryan Davis <ryand-ruby@zenspider.com>
-
- * lib/minitest/*: Imported minitest 4.7.5 (r8724)
- * test/minitest/*: ditto
-
-Sat Jun 22 07:20:30 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_prof_set_heap_info, after_gc_sweep): call
- gc_prof_set_heap_info() just after sweeping to calculate
- live object number correctly.
- (live object number = total generated number (before marking) -
- total freed number (after sweeping))
-
- * gc.c (gc_marks): record `oldgen_object_count' into current profile`
- record directly.
-
- * gc.c (rgengc_rememberset_mark): same for remembered_normal_objects
- and remembered_shady_objects.
-
-Sat Jun 22 06:46:04 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_objspace::profile): rename rb_objspace::profile::record to
- records (because it points a set of records) and add a field
- rb_objspace::profile::current_record to point a current profiling
- record.
-
- * gc.c: use above fields.
-
-Sat Jun 22 06:05:36 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_gc_giveup_promoted_writebarrier): remove `rest_sweep()'
- because all of remembered objects are called for gc_mark_children().
-
-Sat Jun 22 05:08:03 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rgengc_rememberset_mark): call gc_mark_children() for
- remembered objects directly instead of pushing on the mark stack.
-
-Sat Jun 22 04:48:53 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h (OBJ_WRITE): cast to (VALUE *) for second
- parameter `slot'. You don't need to write a cast (VALUE *) any more.
-
- * class.c, compile.c, hash.c, iseq.c, proc.c, re.c, variable.c,
- vm.c, vm_method.c: remove cast expressions for OBJ_WRITE().
-
-Sat Jun 22 04:37:08 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (slot_sweep_body): rename to slot_sweep().
- No need to separate major/minor GC.
-
- * gc.c (gc_setup_mark_bits): remove gc_clear_mark_bits() and unify to
- this function.
-
-Sat Jun 22 04:20:21 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (check_bitmap_consistency): add to check flag and bitmap consistency.
- Use this function in several places.
-
-Sat Jun 22 02:18:07 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_pack): Specialized packers implemented.
- (HOST_BIGENDIAN_P): New macro.
- (ALIGNOF): New macro.
- (CLEAR_LOWBITS): New macro.
- (FILL_LOWBITS): New macro.
- (swap_bdigit): New macro.
- (bary_2comp): Returns an int.
-
- * internal.h (swap16): Moved from pack.c
- (swap32): Ditto.
- (swap64): Ditto.
-
-Fri Jun 21 21:29:49 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (typedef enum): Introduce flags of major gc reason.
- * gc.c (garbage_collect_body): Ditto.
- * gc.c (gc_profile_flags): Ditto.
- * gc.c (gc_profile_dump_on): Ditto.
-
-Fri Jun 21 21:11:53 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (allocate_sorted_heaps): remove unused variable `add'.
-
-Fri Jun 21 20:50:32 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: constify RArray::as::ary and RArray::heap::ptr.
- Use RARRAY_ASET() or RARRAY_PTR_USE() to modify Array objects.
-
- * array.c, gc.c: catch up above changes.
-
-Fri Jun 21 20:32:13 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_eval.c (eval_string_with_cref): fix WB miss.
-
-Fri Jun 21 20:15:49 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: support write barrier protection for T_STRUCT.
- Introduce the following C APIs:
- * RSTRUCT_RAWPTR(st) returns pointer (do WB on your risk).
- The type of returned pointer is (const VALUE *).
- * RSTRUCT_GET(st, idx) returns idx-th value of struct.
- * RSTRUCT_SET(st, idx, v) set idx-th value by v with WB.
- And
- * RSTRUCT_PTR(st) returns pointer with shady operation.
- The type of returned pointer is (VALUE *).
-
- * struct.c, re.c, gc.c, marshal.c: rewrite with above APIs.
-
-Fri Jun 21 19:38:37 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (BDIGMAX): Use BIGRAD.
- (BIGLO): Use BDIGMAX.
- (bigdivrem1): Ditto.
- (bigor_int): Ditto.
- (rb_big_or): Ditto.
-
-Fri Jun 21 19:18:48 2013 Tanaka Akira <akr@fsij.org>
-
- * pack.c (pack_pack): Move the implementation for 'c' directive after
- pack_integer label.
-
-Fri Jun 21 19:11:56 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h, re.c: support write barrier for T_REGEXP.
-
- Note: T_MATCH object is also easy to support write barriers.
- However, most of T_MATCH objects are short-lived objects.
- So I skipped to support non-shady T_MATCH.
-
-Fri Jun 21 18:56:58 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigsub_int): Use bdigit_roomof.
- (bigadd_int): Ditto.
- (bigand_int): Ditto.
- (bigor_int): Ditto.
- (bigxor_int): Ditto.
-
-Fri Jun 21 17:56:25 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/gc/gcbench.rb: fix summary of benchmark result notation.
-
-Fri Jun 21 16:38:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * ext/openssl/ossl_x509attr.c: change OSSL_X509ATTR_IS_SINGLE and
- OSSL_X509ATTR_SET_SINGLE macros to use ->value.set rather than
- ->set to fix compile failure
-
-Fri Jun 21 15:26:45 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_sweep): profile sweep time correctly when LAZY_SWEEP is
- disabled.
-
- * gc.c (gc_marks_test): store oldgen count and shady count
- before test marking and restore them after marking.
-
-Fri Jun 21 15:07:42 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: enable lazy sweep (commit miss).
-
-Fri Jun 21 14:31:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (ruby_setenv): refine error message so include the variable
- name.
-
-Fri Jun 21 14:15:08 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: fix to use total_allocated_object_num and heaps_used
- at the GC time for profiler.
-
-Fri Jun 21 12:35:35 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: RGENGC_CHECK_MODE should be 0.
-
-Fri Jun 21 11:18:25 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_marks_body): fix to get `th' in this function.
-
-Fri Jun 21 10:21:44 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (heaps_header/heaps_slot): embed bitmaps into heaps_slot.
- no need to maintain allocation/free bitmaps.
-
-Fri Jun 21 09:22:16 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (slot_sweep_body): add counters at a time.
-
- * gc.c (gc_profile_dump_on): fix line break position.
-
-Fri Jun 21 08:14:00 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c: refactoring bitmaps. introduce bits_t type and some Consts.
-
-Fri Jun 21 08:04:32 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: fix to support USE_RGENGC == 0 (disable RGenGC).
- If USE_RGENGC==0, it caused compilation error.
-
-Fri Jun 21 08:08:11 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (lazy_sweep): Use is_lazy_sweeping()
- * gc.c (rest_sweep): Ditto.
- * gc.c (gc_prepare_free_objects): Ditto.
-
-Fri Jun 21 07:34:47 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_profile_record::oldgen_objects): added.
-
- * gc.c (gc_profile_dump_on): print the following information:
- * Living object counts
- * Free object counts
- If RGENGC_PROFILE > 0 then
- * Oldgen object counts
- * Remembered normal object counts
- * Remembered shady object counts
-
-Fri Jun 21 06:43:59 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_ull2big): Refactored.
- (rb_uint2big): Useless code removed.
-
-Fri Jun 21 05:37:39 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_prof_sweep_timer_stop): accumulate sweep time only when
- record->gc_time > 0.
-
-Fri Jun 21 00:37:31 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/bigdecimal: Workaround fix for bigdecimal test failures caused
- by [ruby-dev:47413] [Feature #8509]
-
- * ext/bigdecimal/bigdecimal.h (BDIGIT): Make it independent from the
- definition for bignum.c.
- (SIZEOF_BDIGITS): Ditto.
- (BDIGIT_DBL): Ditto.
- (BDIGIT_DBL_SIGNED): Ditto.
- (PRI_BDIGIT_PREFIX): Undefine the definition.
- (PRI_BDIGIT_DBL_PREFIX): Ditto.
-
- * ext/bigdecimal/bigdecimal.c (RBIGNUM_ZERO_P): Use rb_bigzero_p.
- (bigzero_p): Removed.
- (is_even): Use rb_big_pack.
-
-Thu Jun 20 22:52:42 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigmul1_toom3): Don't call bignorm twice.
-
-Thu Jun 20 22:49:27 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bignorm): Don't call bigtrunc if the result is a fixnum.
-
-Thu Jun 20 22:29:42 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_uint2big): Refactored.
-
-Thu Jun 20 22:24:41 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (dump_bignum): Use SIZEOF_BDIGITS.
-
-Thu Jun 20 22:22:46 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2ulong): Change the return type to unsigned long.
- (rb_big2ulong_pack): Follow the above change.
- (rb_big2long): Ditto.
- (rb_big_lshift): Ditto.
- (rb_big_rshift): Ditto.
- (rb_big_aref): Ditto.
-
-Thu Jun 20 22:02:46 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_unpack_internal): Return -2 when negative overflow.
- (bary_unpack): Set the overflowed bit if an extra BDIGIT exists.
- (rb_integer_unpack): Set the overflowed bit.
-
-Thu Jun 20 21:17:19 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rgengc_rememberset_mark): record
- (1) normal objects count in remember set
- (2) shady objects count in remember set
- each GC timing.
-
- * gc.c (gc_profile_record_get): enable to access above information
- and REMOVING_OBJECTS, EMPTY_OBJECTS.
-
-Thu Jun 20 18:29:26 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/gc/gcbench.rb: Do not use GC::Profiler::disable because
- GC::Profiler::disable prohibit to access profiling data. It should
- be spec bug.
-
- Skip GC::Profiler::report if RUBY_VERSION < '2.0.0'
-
-Thu Jun 20 17:59:08 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/gc/gcbench.rb: stop GC::Profiler before output results.
- Generating GC::Profiler result under profiling causes infinite loop.
-
-Thu Jun 20 17:24:24 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/gc/gcbench.rb: don't use __dir__ to make compatible
- with ruby 1.9.3.
-
-Thu Jun 20 16:57:19 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/bm_app_aobench.rb: use attr_accessor/reader instead of
- defining methods.
-
-Thu Jun 20 16:46:46 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/bm_app_aobench.rb: added.
-
- * benchmark/gc/aobench.rb: added.
-
-Thu Jun 20 16:28:33 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/bm_so_binary_trees.rb: disable `puts' method
- and change iteration parameter to increase execution time.
-
- * benchmark/gc/binarytree.rb: added.
-
-Thu Jun 20 16:06:37 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/gc/pentomino.rb: added.
- Simply load pentomino puzzle in the benchmark/ directory.
-
-Thu Jun 20 15:32:56 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/gc/redblack.rb: import red black tree benchmark from
- https://github.com/jruby/rubybench/blob/master/time/bench_red_black.rb
-
- * benchmark/gc/ring.rb: add a benchmark. This benchmark create many
- old objects.
-
-Thu Jun 20 15:14:00 2013 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/gc: create a directory to store GC related benchmark.
-
- * benchmark/gc/gcbench.rb: moved from tool/gcbench.rb.
-
- * benchmark/gc/hash(1|2).rb: ditto.
-
- * benchmark/gc/rdoc.rb: ditto.
-
- * benchmark/gc/null.rb: added.
-
- * common.mk: fix rule.
-
-Thu Jun 20 14:09:54 2013 Koichi Sasada <ko1@atdot.net>
-
- * tool/hashbench1.rb: fix parameter too. Increase temporary objects.
-
-Thu Jun 20 14:01:35 2013 Koichi Sasada <ko1@atdot.net>
-
- * tool/hashbench1.rb: fix parameters.
-
-Thu Jun 20 14:00:34 2013 Koichi Sasada <ko1@atdot.net>
-
- * common.mk: remove dependency from ruby.
-
-Thu Jun 20 13:14:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (rb_check_backtrace): evaluate RARRAY_AREF only once.
- the first argument of RB_TYPE_P is expanded twice for non-immediate
- types.
-
-Thu Jun 20 08:09:29 2013 Koichi Sasada <ko1@atdot.net>
-
- * tool/gcbench.rb: Summary in one line.
-
- * common.mk: separate gcbench-hash to gcbench-hash1 and gcbench-hash2.
-
-Thu Jun 20 08:07:23 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (BIGSIZE): New macro.
- (bigfixize): Use BIGSIZE.
- (big2ulong): Ditto.
- (check_shiftdown): Ditto.
- (rb_big_aref): Ditto.
-
-Thu Jun 20 07:46:48 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (rb_gc_writebarrier): give up rescan A and register B directly
- if A has huge number of children.
-
-Thu Jun 20 07:30:35 2013 Koichi Sasada <ko1@atdot.net>
-
- * common.mk: add new rules `gcbench-rdoc', `gcbench-hash'.
-
- * tool/gcbench.rb: separate GC bench framework and process.
-
- * tool/hashbench1.rb, tool/hashbench2.rb: add two types GC bench.
- hashbench1: many temporal objects (GC by newobj)
- hashbench2: hash size becomes bigger and bigger (GC by malloc)
- Two benches are executed by `gcbench-hash' rule.
-
- * tool/rdocbench.rb: separated.
-
-Thu Jun 20 06:25:39 2013 Koichi Sasada <ko1@atdot.net>
-
- * tool/rdocbench.rb: add summary.
-
-Thu Jun 20 06:18:01 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_profile_total_time): check objspace->profile.next_index > 0.
-
-Thu Jun 20 05:47:41 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_prof_sweep_timer_start): fix merge miss.
-
- * gc.c (GC_PROFILE_MORE_DETAIL): set it 0.
-
-Thu Jun 20 05:38:56 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: Accumulate sweep time to GC time.
- Now [GC time] is [mark time] + [sweep time] + [misc].
- ([GC time] >= [mark time] + [sweep time])
-
- * gc.c (gc_prof_sweep_slot_timer_start/stop): rename to
- gc_prof_sweep_timer_start/stop and locate at lazy_sweep().
-
- * gc.c (elapsed_time_from): add a utility function.
-
-Thu Jun 20 05:08:53 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_marks): fix wrong option. FALSE means major/full GC.
- It should be TRUE (minor marking).
-
-Thu Jun 20 02:44:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (waitpid): should not return 0 but wait until exit
- unless WNOHANG is given. waiting huge process may return while
- active, for some reason.
-
-Thu Jun 20 01:34:15 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bdigit_roomof): Use SIZEOF_BDIGITS.
- (bigfixize): Refine an ifdef condition.
- (rb_absint_size): Use bdigit_roomof.
- (rb_absint_singlebit_p): Ditto.
- (rb_integer_pack): Ditto.
- (integer_pack_fill_dd): Use BITSPERDIG.
- (integer_unpack_push_bits): Use BITSPERDIG, BIGLO and BIGDN.
-
-Thu Jun 20 01:07:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (MARKED_IN_BITMAP, FL_TEST2): return boolean value since always
- used as boolean value.
-
- * gc.c (MARK_IN_BITMAP, CLEAR_IN_BITMAP): evaluate bits once.
-
-Thu Jun 20 00:05:07 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (RVALUE_PROMOTED): fix type.
-
-Wed Jun 19 23:39:01 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_marks_test): rewrite checking code.
- When RGENGC_CHECK_MODE >= 2, all minor marking, run normal minor
- marking *and* major/full marking. After that, compare the results
- and shows BUG if a object living with major/full marking but dead
- with minor marking.
- After detecting bugs, print references information.
- (RGENGC_CHECK_MODE == 2, show references to dead object)
- (RGENGC_CHECK_MODE == 3, show all references)
-
-Wed Jun 19 23:51:48 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigfixize): Use rb_absint_size.
- (check_shiftdown): Ditto.
- (big2ulong): Use bdigit_roomof.
-
-Wed Jun 19 23:32:23 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (RVALUE_PROMOTED): check consistency between oldgen flag and
- oldgen bitmap if RGENGC_CHECK_MODE > 0.
-
-Wed Jun 19 23:29:29 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_gc_force_recycle): clear oldgen bitmap, too.
-
-Wed Jun 19 21:02:13 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_uint2big): Consider environments BDIGIT is bigger than
- long.
- (big2ulong): Ditto.
- (rb_big_aref): Ditto.
- (rb_big_pack): Just call rb_integer_pack.
- (rb_big_unpack): Just call rb_integer_unpack.
-
-Wed Jun 19 20:51:21 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * gc.c (gc_stress_get): GC.stress can be Fixnum.
-
-Wed Jun 19 19:31:30 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (DIGSPERLONG): Don't define if BDIGIT is bigger than long.
- (DIGSPERLL): Don't define if BDIGIT is bigger than LONG_LONG
- (rb_absint_size): Consider environments BDIGIT is bigger than long.
- Use BIGLO and BIGDN.
- (rb_absint_singlebit_p): Ditto.
- (rb_integer_pack): Ditto.
- (bigsub_int): Consider environments BDIGIT is bigger than long.
- Use SIZEOF_BDIGITS instead of sizeof(BDIGIT).
- (bigadd_int): Ditto.
- (bigand_int): Ditto.
- (bigor_int): Ditto.
- (bigxor_int): Ditto.
-
-Wed Jun 19 15:14:30 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h (struct rb_data_type_struct), gc.c: add
- rb_data_type_struct::flags. Now, this flags is passed
- at T_DATA object creation. You can specify FL_WB_PROTECTED
- on this flag.
-
- * iseq.c: making non-shady iseq objects.
-
- * class.c, compile.c, proc.c, vm.c: add WB for iseq objects.
-
- * vm_core.h, iseq.h: constify fields to detect WB insertion.
-
-Wed Jun 19 15:11:13 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (gc_mark_children): show more info for broken object.
-
-Wed Jun 19 14:04:41 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * test/ruby/envutil.rb (EnvUtil#rubybin): remove unnecessary
- unless expression.
-
-Wed Jun 19 07:47:48 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (garbage_collect_body): use FIX2INT for ruby_gc_stress.
-
-Wed Jun 19 07:44:31 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_objspace::gc_stress): int -> VALUE to store Fixnum object.
-
-Wed Jun 19 07:25:35 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (make_deferred): clear flags to T_ZOMBIE.
-
- * gc.c (slot_sweep_body): fix indent.
-
-Wed Jun 19 07:18:47 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_aref): Apply BIGLO to ~xds[i] for environment which
- BDIGIT is 16bit.
-
-Wed Jun 19 07:09:26 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rgengc_remember): fix output level.
-
- * gc.c (rgengc_rememberset_mark): fix to output clear count.
- (shady_object_count + clear_count = count of remembered objects)
-
-Wed Jun 19 07:06:21 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rgengc_remember): check T_NONE and T_ZOMBIE
- if RGENGC_CHECK_MODE > 0.
-
-Wed Jun 19 07:02:19 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (RGENGC_CHECK_MODE): add new check mode `3'.
- In this mode, show all references if there is
- a miss-corrected object.
-
-Wed Jun 19 06:31:08 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stress_set): add special option of GC.stress.
- `GC.stress=(flag)' accepts integer to control behavior of GC.
- See code for details. Of course, this feature is only for MRI.
-
- You can debug RGenGC (WB) using `GC.stress = 1'.
- Using this option, do minor marking at all possible places.
-
- GC::STRESS_MINOR_MARK = 1 and GC::STRESS_LAZY_SWEEP = 2
- seem good to add.
-
-Wed Jun 19 06:29:31 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm.c (kwmerge_i): add WB.
-
-Wed Jun 19 06:26:49 2013 Koichi Sasada <ko1@atdot.net>
-
- * hash.c: `st_update()' also has same issue of last fix.
- write barriers at callback function are too early.
- All write barriers are executed after `st_update()'
-
-Wed Jun 19 04:33:22 2013 Koichi Sasada <ko1@atdot.net>
-
- * variable.c (rb_const_set): fix WB miss.
-
- WBs had located before creating reference between a klass
- and constant value. It causes GC bug.
-
- # pseudo code:
- WB(klass, value); # WB and remember klass
- st_insert(klass->const_table, const_id, value);
-
- `st_insert()' can cause GC before inserting `value' and
- forget `klass' from the remember set. After that, relationship
- between `klass' and `value' are created with constant table.
- Now, `value' can be young (shady) object and `klass' can be old
- object, without remembering `klass' object.
- At the next GC, old `klass' object will be skipped and
- young (shady) `value' will be miss-collected. -> GC bug
-
- Lesson: The place of a WB is important.
-
-Tue Jun 18 22:01:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * vm_insnhelper.c (vm_call_method): ensure methods of type
- VM_METHOD_TYPE_ATTR_SET are called with 1 argument
-
- * test/ruby/test_module.rb
- (TestModule#test_attr_writer_with_no_arguments): add test
- [ruby-core:55543] [Bug #8540]
-
-Tue Jun 18 22:36:23 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (gc_profile_record_flag): fix typo.
-
-Tue Jun 18 22:08:53 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/objspace/object_tracing.c: Return for ::allocation_generation
-
-Tue Jun 18 22:04:35 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/objspace/object_tracing.c: Document object_tracing methods.
-
-Tue Jun 18 21:58:17 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * gc.c: Rename rb_mObSpace -> rb_mObjSpace
-
-Tue Jun 18 20:55:05 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/objspace/objspace.c: Document ObjectSpace::InternalObjectWrapper.
-
-Tue Jun 18 20:39:04 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/objspace/object_tracing.c: Teach rdoc object_tracing.c [Bug #8537]
-
-Tue Jun 18 20:29:47 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/.document: add object_tracing.c to document file
-
-Tue Jun 18 20:20:27 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/objspace/objspace.c: rdoc on require to overview from r41355
-
-Tue Jun 18 18:39:58 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Check __int128.
-
- * include/ruby/defines.h (BDIGIT_DBL): Use uint128_t if it is available.
- (BDIGIT): Use uint64_t if uint128_t is available.
- (SIZEOF_BDIGITS): Defined for above case.
- (BDIGIT_DBL_SIGNED): Ditto.
- (PRI_BDIGIT_PREFIX): Ditto.
-
- * include/ruby/ruby.h (PRI_64_PREFIX): Defined.
-
- * bignum.c (rb_big_pow): Don't use BITSPERDIG for the condition which
- rb_big_pow returns Float or Bignum.
-
- [ruby-dev:47413] [Feature #8509]
-
-Tue Jun 18 16:43:44 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_heredoc_restore): clear lex_strterm always to get
- rid of marking recycled node. this bug is revealed by r41372 with
- GC.stress=true.
-
-Tue Jun 18 12:53:25 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (nlz): Cast the result explicitly.
- (big2dbl): Don't assign BDIGIT values to int variable.
-
-Tue Jun 18 12:25:16 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_xor): Non-effective code removed.
-
-Tue Jun 18 11:26:05 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat): add `generated_normal_object_count_types' for
- RGENGC_PROFILE >= 2.
-
-Tue Jun 18 11:02:18 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_mark_maybe): check to skip T_NONE.
-
- * gc.c (markable_object_p): do not need to check (flags == 0) here.
-
-Tue Jun 18 10:17:37 2013 Koichi Sasada <ko1@atdot.net>
-
- * variable.c (rb_autoload): fix WB miss.
-
-Tue Jun 18 04:20:18 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_mark_children): don't need to care about T_ZOMBIE here.
-
-Mon Jun 17 22:16:02 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * test/ruby/test_proc.rb (TestProc#test_block_given_method_to_proc):
- run test for r41359.
-
-Mon Jun 17 21:42:18 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * include/ruby/ruby.h, vm_eval.c (rb_funcall_with_block):
- new function to invoke a method with a block passed
- as an argument.
-
- * string.c (sym_call): use the above function to avoid
- a block sharing. [ruby-dev:47438] [Bug #8531]
-
- * vm_insnhelper.c (vm_yield_with_cfunc): don't set block
- in the frame.
-
- * test/ruby/test_symbol.rb (TestSymbol#test_block_given_to_proc):
- run related tests.
-
-Mon Jun 17 21:33:27 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * include/ruby/intern.h, proc.c (rb_method_call_with_block):
- new function to invoke a Method object with a block passed
- as an argument.
-
- * proc.c (bmcall): use the above function to avoid a block sharing.
- [ruby-core:54626] [Bug #8341]
-
- * test/ruby/test_proc.rb (TestProc#test_block_persist_between_calls):
- run related tests.
-
-Mon Jun 17 20:53:21 2013 Tanaka Akira <akr@fsij.org>
-
- * loadpath.c (RUBY_REVISION): Defined to suppress revision.h
- inclusion actually. r41352 removes the dependency.
-
-Mon Jun 17 18:15:57 2013 Benoit Daloze <eregontp@gmail.com>
-
- * ext/objspace/objspace.c: let rdoc know about objspace methods.
- Specify 'objspace' should be required. See #8537.
-
-Mon Jun 17 17:44:31 2013 Benoit Daloze <eregontp@gmail.com>
-
- * gc.c (ObjectSpace): is a module not a class.
-
- * ext/objspace/objspace.c: try to include overview in rdoc,
- see #8537.
-
-Mon Jun 17 17:38:24 2013 Benoit Daloze <eregontp@gmail.com>
-
- * gc.c: fix example of ObjectSpace.define_finalizer in overview
-
-Mon Jun 17 16:59:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/tk/tkutil/tkutil.c: use rb_sprintf(), rb_id2str(), and
- rb_intern_str() instead of rb_intern() and RSTRING_PTR() with
- RB_GC_GUARD(), to prevent temporary objects from GC.
- [ruby-core:39000] [Bug #5199]
-
-Mon Jun 17 14:27:54 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * vm_backtrace.c: Update rdoc for Backtrace#label with @_ko1
-
-Mon Jun 17 13:04:01 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * tool/ifchange (until): Fix the condition, although harmless in
- this case.
-
-Mon Jun 17 11:50:29 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_mark_maybe): added. check `is_pointer_to_heap()' and
- type is not T_ZOMBIE.
-
- * gc.c: use `gc_mark_maybe()'. T_ZOMBIE objects should not be pushed
- to the mark stack.
-
-Mon Jun 17 07:56:24 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_small_lshift): Renamed from bdigs_small_lshift.
- (bary_small_rshift): Renamed from bdigs_small_rshift.
-
-Mon Jun 17 07:38:48 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (absint_numwords_bytes): Removed.
- (rb_absint_numwords): Don't call absint_numwords_bytes.
-
-Sun Jun 16 23:14:58 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (BARY_ADD): New macro.
- (BARY_SUB): Ditto.
- (BARY_MUL): Ditto.
- (BARY_DIVMOD): Ditto.
- (BARY_ZERO_P): Ditto.
- (absint_numwords_generic): Use these macros.
-
-Sun Jun 16 21:41:39 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_2comp): Extracted from get2comp.
- (integer_unpack_num_bdigits): Extracted from
- rb_integer_unpack_internal.
- (bary_unpack_internal): Renamed from bary_unpack and support
- INTEGER_PACK_2COMP.
- (bary_unpack): New function to validate arguments and invoke
- bary_unpack_internal.
- (rb_integer_unpack_internal): Removed.
- (rb_integer_unpack): Invoke bary_unpack_internal.
- (rb_integer_unpack_2comp): Removed.
-
- * internal.h (rb_integer_unpack_2comp): Removed.
-
- * pack.c: Follow the above change.
-
-Sun Jun 16 18:41:42 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (INTEGER_PACK_2COMP): Defined.
- (rb_integer_pack_2comp): Removed.
-
- * bignum.c (bary_pack): Support INTEGER_PACK_2COMP.
- (rb_integer_pack): Invoke bary_pack directly.
- (rb_integer_pack_2comp): Removed.
- (rb_integer_pack_internal): Ditto.
- (absint_numwords_generic): Follow the above change.
-
- * pack.c (pack_pack): Ditto.
-
- * sprintf.c (rb_str_format): Ditto.
-
-Sun Jun 16 17:48:14 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (absint_numwords_generic): rb_funcall invocations removed.
-
-Sun Jun 16 16:04:38 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/config_files.rb: use URI.read to allow it runs with Ruby 1.8.5.
-
-Sun Jun 16 14:32:25 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_pack) Extracted from rb_integer_pack_internal.
- (absint_numwords_generic): Use bary_pack.
-
-Sun Jun 16 11:01:57 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * NEWS (XMLRPC::Client#http): Add.
- [ruby-core:55197] [Feature #8461]
-
-Sun Jun 16 10:38:45 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_add): New function.
- (bary_zero_p): Extracted from bigzero_p.
- (absint_numwords_generic): Use bary_zero_p and bary_add.
- (bary_mul): Fix an argument for bary_mul_single.
- (bary_divmod): Use size_t for arguments.
-
-Sun Jun 16 08:55:22 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem): Use a BDIGIT variable to store the return
- value of bigdivrem_single.
-
-Sun Jun 16 08:43:59 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_divmod): New function.
- (absint_numwords_generic): Use bary_divmod.
- (bigdivrem_num_extra_words): Extracted from bigdivrem.
- (bigdivrem_single): Ditto.
- (bigdivrem_normal): Ditto.
- (BIGDIVREM_EXTRA_WORDS): Defined.
-
-Sun Jun 16 05:51:51 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c: Fixup around GC by MALLOC.
- Add allocate size to malloc_increase before GC
- for updating limit in after_gc_sweep.
- Reset malloc_increase into garbage_collect()
- for preventing GC again soon.
-
-Sun Jun 16 05:15:36 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c: Add some columns to more detail profile.
- new columns: Allocated size, Prepare Time, Removing Objects, Empty Objects
-
-Sun Jun 16 02:04:40 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (gc_prof_timer_stop): Merge function codes of GC_PROFILE_MORE_DETAIL and !GC_PROFILE_MORE_DETAIL.
- * gc.c (gc_prof_mark_timer_start): Ditto.
- * gc.c (gc_prof_mark_timer_stop): Ditto.
- * gc.c (gc_prof_sweep_slot_timer_start): Ditto.
- * gc.c (gc_prof_sweep_slot_timer_stop): Ditto.
- * gc.c (gc_prof_set_malloc_info): Ditto.
- * gc.c (gc_prof_set_heap_info): Ditto.
-
-Sat Jun 15 23:50:24 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_sub): New function.
- (absint_numwords_generic): Use bary_sub.
- (bigsub_core): Skip unnecessary copy.
-
-Sat Jun 15 22:05:30 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul): New function.
- (absint_numwords_generic): Use bary_mul.
- (bary_mul_single): Extracted from bigmul1_single.
- (bary_mul_normal): Extracted from bigmul1_normal.
-
-Sat Jun 15 20:13:46 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_unpack): Extracted from rb_integer_unpack_internal.
- (absint_numwords_generic): Use bary_unpack.
- (roomof): Defined.
- (bdigit_roomof): Defined.
- (BARY_ARGS): Defined.
- (bary_unpack): Declared.
-
-Sat Jun 15 19:35:04 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (absint_numwords_bytes): Make it static.
- (absint_numwords_small): Ditto.
- (absint_numwords_generic): Ditto.
-
-Sat Jun 15 17:14:32 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigmul1_normal): Shrink the result Bignum length.
-
-Sat Jun 15 10:19:42 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/bigdecimal/bigdecimal.c: Update overview formatting of headers
-
-Sat Jun 15 10:19:06 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/bigdecimal/bigdecimal.gemspec: Update authors
-
-Sat Jun 15 10:02:26 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bdigs_small_rshift): Extracted from big_rshift.
- (bigdivrem): Use bdigs_small_rshift.
-
-Sat Jun 15 08:37:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (eval_string_with_cref): propagate absolute path from the
- binding if it is given explicitly. patch by Gat (Dawid Janczak) at
- [ruby-core:55123]. [Bug #8436]
-
-Sat Jun 15 02:40:18 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bdigs_small_lshift): Extracted from big_lshift.
- (bigdivrem): Use bdigs_small_lshift.
-
-Fri Jun 14 20:47:41 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem): Reduce number of digits before bignew() for div.
-
-Fri Jun 14 20:12:37 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem): Use bignew when ny == 1.
-
-Fri Jun 14 18:52:51 2013 Koichi Sasada <ko1@atdot.net>
-
- * compile.c (rb_iseq_compile_node): fix location of a `trace'
- instruction (b_return event).
- [ruby-core:55305] [ruby-trunk - Bug #8489]
- (need a backport to 2.0.0?)
-
- * test/ruby/test_settracefunc.rb: add a test.
-
-Fri Jun 14 18:18:07 2013 Koichi Sasada <ko1@atdot.net>
-
- * class.c, include/ruby/ruby.h: add write barriers for T_CLASS,
- T_MODULE, T_ICLASS.
-
- * constant.h: constify rb_const_entry_t::value and file to detect
- assignment.
-
- * variable.c, internal.h (rb_st_insert_id_and_value, rb_st_copy):
- added. update table with write barrier.
-
- * method.h: constify some variables to detect assignment.
-
- * object.c (init_copy): add WBs.
-
- * variable.c: ditto.
-
- * vm_method.c (rb_add_method): ditto.
-
-Fri Jun 14 14:33:47 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * NEWS: add a note for Module#using.
-
-Fri Jun 14 13:40:27 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * .travis.yml (before_script): update config files.
-
- * common.mk ($(srcdir)/tool/config.{guess,sub}): use get-config_files.
-
- * tool/config_files.rb: split get-config_files.
-
- * common.mk (update-config_files): rule to download config files.
-
- * tool/config.guess, tool/config.sub: remove and download from the
- upstream.
-
- * tool/config_files.rb: download config files from GNU.
-
-Fri Jun 14 12:21:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (RUBY_SAFE_LEVEL_CHECK): suppress warnings
- "left-hand operand of comma expression has no effect", on gcc 4.4.
-
-Fri Jun 14 09:48:48 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * NEWS: add notes for $SAFE.
-
- * doc/security.rdoc: remove the description of $SAFE=4.
-
-Fri Jun 14 00:14:29 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem): Zero test condition simplified.
-
-Thu Jun 13 23:43:11 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/bigdecimal/*: improve documentation, nodoc samples with @mrkn
-
-Thu Jun 13 23:02:14 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/xmlrpc/client.rb (XMLRPC::Client#http): Add reader for raw
- Net::HTTP. [ruby-core:55197] [Feature #8461]
- Reported by Herwin Weststrate. Thanks!!!
-
-Thu Jun 13 22:44:52 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/xmlrpc/client.rb (XMLRPC::Client#parse_set_cookies): Support
- multiple names in a response. [ruby-core:41711] [Bug #5774]
- Reported by Roman Riha. Thanks!!!
- * test/xmlrpc/test_client.rb (XMLRPC::ClientTest#test_cookie_override):
- Add a test of the above case.
-
-Thu Jun 13 22:35:50 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/xmlrpc/client.rb (XMLRPC::Client#parse_set_cookies): Use
- guard style.
-
-Thu Jun 13 22:12:32 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/fileutils.rb (FileUtils#rmdir): fix traversal loop, not trying
- remove same directory only.
-
-Thu Jun 13 21:30:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (opt-dir), tool/ifchange: get rid of "alternate value"
- expansion for legacy sh. [ruby-dev:47420] [Bug #8524]
-
-Thu Jun 13 21:24:09 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem): Refactored to use ALLOCV_N for temporary
- buffers.
-
-Thu Jun 13 18:54:11 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * bignum.c (integer_unpack_num_bdigits_generic): reorder terms (but not
- changed the intention of the expression) because VC++ reports a
- warning for it. reported by ko1 via IRC.
-
-Thu Jun 13 18:53:14 2013 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_thread.rb (test_thread_local_security): Don't create
- an unused thread.
-
-Thu Jun 13 18:34:20 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bigdivrem): Use nlz.
-
-Thu Jun 13 14:51:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (RUBY_SAFE_LEVEL_CHECK): check constant safe
- level at compile time.
-
-Thu Jun 13 14:39:08 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * test/-ext-/test_printf.rb, test/rss/test_parser.rb,
- test/ruby/test_array.rb, test/ruby/test_hash.rb,
- test/ruby/test_m17n.rb, test/ruby/test_marshal.rb,
- test/ruby/test_object.rb, test/ruby/test_string.rb: don't use
- untrusted?, untrust, and trust to avoid warnings in case $VERBOSE is
- true.
-
-Thu Jun 13 10:47:16 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * bootstraptest/test_autoload.rb, bootstraptest/test_method.rb:
- remove tests for $SAFE=4.
-
- * lib/pp.rb: use taint instead of untrust to avoid warnings when
- $VERBOSE is set to true.
-
-Thu Jun 13 06:12:18 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (integer_unpack_num_bdigits_small): Fix a compile error on
- clang -Werror,-Wshorten-64-to-32
- Reported by Eric Hodel. [ruby-core:55467] [Bug #8522]
-
-Thu Jun 13 05:32:13 2013 Eric Hodel <drbrain@segment7.net>
-
- * ext/socket/extconf.rb: Enable RFC 3542 IPV6 socket options for OS X
- 10.7+. [ruby-trunk - Bug #8517]
-
-Thu Jun 13 00:17:18 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_integer_unpack_2comp): New function.
- (rb_integer_unpack_internal): Extracted from rb_integer_unpack and
- nlp_bits_ret argument added.
- (integer_unpack_num_bdigits_small): nlp_bits_ret argument added to
- return number of leading padding bits.
- (integer_unpack_num_bdigits_generic): Ditto.
-
- * internal.h (rb_integer_unpack_2comp): Declared.
-
- * pack.c (pack_unpack): Use rb_integer_unpack_2comp and
- rb_integer_unpack.
-
-Wed Jun 12 23:27:03 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * eval.c (mod_using): new method Module#using, which activates
- refinements of the specified module only in the current class or
- module definition. [ruby-core:55273] [Feature #8481]
-
- * test/ruby/test_refinement.rb: related test.
-
-Wed Jun 12 22:58:48 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * safe.c (rb_set_safe_level, safe_setter): raise an ArgumentError
- when $SAFE is set to 4. $SAFE=4 is now obsolete.
- [ruby-core:55222] [Feature #8468]
-
- * object.c (rb_obj_untrusted, rb_obj_untrust, rb_obj_trust):
- Kernel#untrusted?, untrust, and trust are now deprecated.
- Their behavior is same as tainted?, taint, and untaint,
- respectively.
-
- * include/ruby/ruby.h (OBJ_UNTRUSTED, OBJ_UNTRUST): OBJ_UNTRUSTED()
- and OBJ_UNTRUST() are aliases of OBJ_TAINTED() and OBJ_TAINT(),
- respectively.
-
- * array.c, class.c, debug.c, dir.c, encoding.c, error.c, eval.c,
- ext/curses/curses.c, ext/dbm/dbm.c, ext/dl/cfunc.c,
- ext/dl/cptr.c, ext/dl/dl.c, ext/etc/etc.c, ext/fiddle/fiddle.c,
- ext/fiddle/pointer.c, ext/gdbm/gdbm.c, ext/readline/readline.c,
- ext/sdbm/init.c, ext/socket/ancdata.c, ext/socket/basicsocket.c,
- ext/socket/socket.c, ext/socket/udpsocket.c,
- ext/stringio/stringio.c, ext/syslog/syslog.c, ext/tk/tcltklib.c,
- ext/win32ole/win32ole.c, file.c, gc.c, hash.c, io.c, iseq.c,
- load.c, marshal.c, object.c, proc.c, process.c, random.c, re.c,
- safe.c, string.c, thread.c, transcode.c, variable.c,
- vm_insnhelper.c, vm_method.c, vm_trace.c: remove code for
- $SAFE=4.
-
- * test/dl/test_dl2.rb, test/erb/test_erb.rb,
- test/readline/test_readline.rb,
- test/readline/test_readline_history.rb, test/ruby/test_alias.rb,
- test/ruby/test_array.rb, test/ruby/test_dir.rb,
- test/ruby/test_encoding.rb, test/ruby/test_env.rb,
- test/ruby/test_eval.rb, test/ruby/test_exception.rb,
- test/ruby/test_file_exhaustive.rb, test/ruby/test_hash.rb,
- test/ruby/test_io.rb, test/ruby/test_method.rb,
- test/ruby/test_module.rb, test/ruby/test_object.rb,
- test/ruby/test_pack.rb, test/ruby/test_rand.rb,
- test/ruby/test_regexp.rb, test/ruby/test_settracefunc.rb,
- test/ruby/test_struct.rb, test/ruby/test_thread.rb,
- test/ruby/test_time.rb: remove tests for $SAFE=4.
-
-Wed Jun 12 22:18:23 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (integer_unpack_num_bdigits_generic): Rewritten without
- rb_funcall.
- (integer_unpack_num_bdigits_bytes): Removed.
- (rb_integer_unpack): integer_unpack_num_bdigits_bytes invocation
- removed.
-
-Wed Jun 12 20:18:03 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/xmlrpc/client.rb (XMLRPC::Client#parse_set_cookies): Extract.
-
-Wed Jun 12 18:19:41 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (validate_integer_pack_format): supported_flags argument
- added and validate given flags.
- (rb_integer_pack_internal): Specify supported_flags.
- (rb_integer_unpack): Ditto.
-
-Wed Jun 12 16:41:38 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_sort_bang): remove duplicated assertions.
- ARY_HEAP_PTR() implies ary not to be embedded. [ruby-dev:47419]
- [Bug #8518]
-
-Wed Jun 12 12:44:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (io_getc): fix 7bit coderange condition, check if ascii read
- data instead of read length. [ruby-core:55444] [Bug #8516]
-
-Wed Jun 12 12:35:13 2013 Tanaka Akira <akr@fsij.org>
-
- * pack.c (pack_pack): Use rb_integer_pack_2comp.
-
-Wed Jun 12 12:07:04 2013 Tanaka Akira <akr@fsij.org>
-
- * sprintf.c (rb_str_format): Fix a dynamic format string.
-
-Wed Jun 12 12:04:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_uniq_bang): must not be modified once frozen even in
- a callback method.
-
-Wed Jun 12 12:03:43 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_sort_bang): must not be modified once frozen even in
- a callback method.
-
-Wed Jun 12 12:00:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (FL_SET_EMBED): shared object is frozen even when get
- unshared.
-
- * array.c (rb_ary_modify): ARY_SET_CAPA needs unshared array.
-
-Wed Jun 12 07:32:01 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c (rand_int): Use rb_big_uminus.
-
-Wed Jun 12 07:12:54 2013 Eric Hodel <drbrain@segment7.net>
-
- * struct.c: Improve documentation: replace "instance variable" with
- "member", recommend the use of a block to customize structs, note
- that member accessors are created, general cleanup.
-
-Wed Jun 12 06:35:01 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (INTEGER_PACK_NEGATIVE): Defined.
- (rb_integer_unpack): sign argument removed.
-
- * bignum.c (rb_integer_unpack): sign argument removed.
- Non-negative integers generated by default.
- INTEGER_PACK_NEGATIVE flag is used to generate non-positive integers.
-
- * pack.c (pack_unpack): Follow the above change.
-
- * random.c (int_pair_to_real_inclusive): Ditto.
- (make_seed_value): Ditto.
- (mt_state): Ditto.
- (limited_big_rand): Ditto.
-
- * marshal.c (r_object0): Ditto.
-
-Wed Jun 12 00:07:46 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/xmlrpc/test_client.rb (XMLRPC::ClientTest#test_cookie_simple):
- Add a test for the extracted method.
-
-Tue Jun 11 23:56:24 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/xmlrpc/test_client.rb (XMLRPC::ClientTest::Fake::HTTP#started):
- Add a missing empty line.
-
-Tue Jun 11 23:37:19 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (validate_integer_pack_format): Don't require a word order
- flag if numwords is 1 or less.
- (absint_numwords_generic): Don't specify a word order for
- rb_integer_pack.
-
- * hash.c (rb_hash): Ditto.
-
- * time.c (v2w_bignum): Ditto.
-
-Tue Jun 11 23:01:57 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (validate_integer_pack_format): Refine error messages.
-
-Tue Jun 11 22:25:04 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (validate_integer_pack_format): numwords argument added.
- Move a varidation from rb_integer_pack_internal and rb_integer_unpack.
- (rb_integer_pack_internal): Follow above change.
- (rb_integer_unpack): Ditto.
-
-Tue Jun 11 20:52:43 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_integer_pack_internal): Renamed from rb_integer_pack
- and overflow_2comp argument added.
- (rb_integer_pack): Just call rb_integer_pack_internal.
- (rb_integer_pack_2comp): New function.
-
- * internal.h (rb_integer_pack_2comp): Declared.
-
- * sprintf.c (rb_str_format): Use rb_integer_pack and
- rb_integer_pack_2comp to format binary/octal/hexadecimal integers.
- (ruby_digitmap): Declared.
- (remove_sign_bits): Removed.
- (BITSPERDIG): Ditto.
- (EXTENDSIGN): Ditto.
-
-Tue Jun 11 16:15:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (ary_shrink_capa): shrink the capacity so it fits just with
- the length.
-
- * array.c (ary_make_shared): release never used elements from frozen
- array to be shared. [ruby-dev:47416] [Bug #8510]
-
-Tue Jun 11 12:49:01 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * doc/re.rdoc: Rename to doc/regexp.rdoc
- * re.c: Update rdoc include for rename of file
-
-Tue Jun 11 07:13:13 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * eval_error.c (error_print): keep that errat is non-shady object.
- and guard errat from GC.
-
-Tue Jun 11 05:04:25 2013 Benoit Daloze <eregontp@gmail.com>
-
- * ext/racc/cparse/cparse.c: use rb_ary_entry() and
- rb_ary_subseq() instead of RARRAY_PTR.
- Based on a patch by Dirkjan Bussink. See Bug #8399.
-
-Mon Jun 10 23:51:51 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * array.c (rb_ary_new_from_values): fix a typo. pointed out by
- nagachika.
- http://d.hatena.ne.jp/nagachika/20130610/ruby_trunk_changes_41199_41220
-
-Mon Jun 10 21:51:03 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * ext/socket/raddrinfo.c (nogvl_getaddrinfo): Fix indent.
-
-Mon Jun 10 21:49:43 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * ext/socket/raddrinfo.c (nogvl_getaddrinfo): Add missing return
- value assignment.
-
-Mon Jun 10 20:58:11 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/socket/raddrinfo.c (nogvl_getaddrinfo): work around for Ubuntu
- 13.04's getaddrinfo issue with mdns4. [ruby-list:49420]
-
-Mon Jun 10 19:34:39 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_integer_pack): Returns sign instead of words.
- (absint_numwords_generic): Follow the above change.
- (big2str_base_powerof2): Follow the above change.
-
- * internal.h: Ditto.
-
- * hash.c (rb_hash): Ditto.
-
- * pack.c (pack_pack): Ditto.
-
- * random.c (int_pair_to_real_inclusive): Ditto.
- (rand_init): Ditto.
- (random_load): Ditto.
- (limited_big_rand): Ditto.
-
- * time.c (v2w_bignum): Ditto.
-
-Mon Jun 10 17:20:01 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rgengc_remember): permit promoted object.
- (rb_gc_writebarrier -> remember)
-
-Mon Jun 10 17:14:01 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (RVALUE_PROMOTE): fix parameter name (`x' to `obj')
- and make it inline function (like RVALUE_PROMOTE).
-
-Mon Jun 10 16:22:50 2013 Koichi Sasada <ko1@atdot.net>
-
- * array.c (rb_ary_new_from_values): add assertion
- (ary should be young object).
-
-Mon Jun 10 16:05:59 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (wmap_mark): check allocation of `w->obj2wmap'.
- (no-allocation `w->obj2wmap' will be NULL pointer reference)
-
-Mon Jun 10 15:36:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval_error.c (error_print): use checking functions instead of
- catching exceptions.
-
- * eval_error.c (error_print): restore errinfo for the case new
- exception raised while printing the message. [ruby-core:55365]
- [Bug #8501]
-
- * eval_error.c (error_print): reduce calling setjmp.
-
-Mon Jun 10 12:10:06 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (integer_unpack_num_bdigits_small: Extracted from
- rb_integer_unpack.
- (integer_unpack_num_bdigits_generic): Ditto.
- (integer_unpack_num_bdigits_bytes): New function.
- (rb_integer_unpack): Use above functions.
- Return a Bignum for INTEGER_PACK_FORCE_BIGNUM even when the result
- is zero.
-
-Mon Jun 10 05:38:23 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (absint_numwords_small): New function.
- (absint_numwords_generic): Use absint_numwords_small if possible.
-
-Mon Jun 10 01:07:57 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (absint_numwords_bytes): New function.
- (absint_numwords_generic): Extracted from rb_absint_numwords.
- (rb_absint_numwords): Use absint_numwords_bytes if possible.
-
-Sun Jun 9 21:33:15 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_absint_numwords): Return (size_t)-1 when overflow.
- Refine variable names.
- (rb_absint_size): Refine variable names.
-
- * internal.h (rb_absint_size): Refine an argument name.
- (rb_absint_numwords): Ditto.
-
-Sun Jun 9 16:51:41 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_absint_numwords): Renamed from rb_absint_size_in_word.
-
- * internal.h (rb_absint_numwords): Follow the above change.
-
- * pack.c (pack_pack): Ditto.
-
- * random.c (rand_init): Ditto.
- (limited_big_rand): Ditto.
-
-Sun Jun 9 14:41:05 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_integer_pack): numwords_allocated argument removed.
-
- * internal.h (rb_integer_pack): Follow the above change.
-
- * hash.c (rb_hash): Ditto.
-
- * time.c (v2w_bignum): Ditto.
-
- * pack.c (pack_pack): Ditto.
-
- * random.c (int_pair_to_real_inclusive): Ditto.
- (rand_init): Ditto.
- (random_load): Ditto.
- (limited_big_rand): Ditto.
-
-Sun Jun 9 09:34:44 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big2str_base_powerof2): New function.
- (rb_big2str0): Use big2str_base_powerof2 if base is 2, 4, 8, 16 or 32.
-
-Sun Jun 9 00:59:04 2013 Tanaka Akira <akr@fsij.org>
-
- * hash.c (rb_hash): Use rb_integer_pack to obtain least significant
- long integer.
-
-Sat Jun 8 23:56:00 2013 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_num_to_uint): Use rb_absint_size instead of
- RBIGNUM_LEN.
-
-Sat Jun 8 22:53:45 2013 Tanaka Akira <akr@fsij.org>
-
- * marshal.c (r_object0): Use rb_integer_unpack.
-
-Sat Jun 8 22:18:57 2013 Tanaka Akira <akr@fsij.org>
-
- * time.c (v2w): Use rb_absint_size instead of RBIGNUM_LEN.
-
-Sat Jun 8 21:47:33 2013 Tanaka Akira <akr@fsij.org>
-
- * time.c (v2w_bignum): Simplified using rb_integer_pack.
- (rb_big_abs_find_maxbit): Removed.
-
-Sat Jun 8 21:03:40 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_absint_singlebit_p): New function.
-
- * internal.h (rb_absint_singlebit_p): Declared.
-
- * time.c (v2w_bignum): Use rb_absint_singlebit_p instead of
- rb_big_abs_find_minbit.
- (rb_big_abs_find_minbit): Removed.
-
-Sat Jun 8 20:24:23 2013 Tanaka Akira <akr@fsij.org>
-
- * time.c (rb_big_abs_find_maxbit): Use rb_absint_size.
- (bdigit_find_maxbit): Removed.
-
-Sat Jun 8 19:47:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * class.c (include_modules_at): invalidate method cache if included
- module contains constants
-
- * test/ruby/test_module.rb: add test
-
-Sat Jun 8 19:31:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * random.c (limited_big_rand): declare rnd, lim and mask as uint32_t
- to avoid 64 bit to 32 bit shorten warnings.
-
-Sat Jun 8 19:23:53 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * win32/Makefile.sub: r41163 changed win32/win32.c and configure.in
- but it didn't treat about mswin32/mswin64, so fix it.
- NOTE: this needs a review by usa whether additional condition is
- required or not.
-
-Sat Jun 8 19:06:26 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c: Unused RBignum internal accessing macros removed.
-
-Sat Jun 8 19:04:15 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c (limited_big_rand): The argument, limit, is changed to
- VALUE. Use rb_integer_pack and rb_integer_unpack.
-
-Sat Jun 8 17:15:18 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c (make_seed_value): Fix the length given for
- rb_integer_unpack.
-
-Sat Jun 8 16:38:02 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_integer_unpack): Don't use rb_funcall if possible.
-
- * random.c: Use uint32_t for elements of seed.
- (make_seed_value): Use rb_integer_unpack.
-
-Sat Jun 8 15:58:18 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c (rand_init): Add a cast to fix clang compile error:
- random.c:410:32: error: implicit conversion loses integer precision:
- 'size_t' (aka 'unsigned long') to 'int' [-Werror,-Wshorten-64-to-32]
- This cast doesn't cause a problem because len is not bigger than
- MT_MAX_STATE.
-
-Sat Jun 8 15:30:03 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c (rand_init): Use rb_integer_pack.
- (roomof): Removed.
-
-Sat Jun 8 14:58:32 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (INTEGER_PACK_FORCE_BIGNUM): New flag constant.
-
- * bignum.c (rb_integer_unpack): Support INTEGER_PACK_FORCE_BIGNUM.
-
- * random.c (int_pair_to_real_inclusive): Use
- INTEGER_PACK_FORCE_BIGNUM to use rb_big_mul instead of rb_funcall.
-
-Sat Jun 8 14:17:01 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: check for NET_LUID. header macro varies across
- compiler versions.
-
- * win32/win32.c: use configured macro.
-
-Sat Jun 8 11:59:55 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c (int_pair_to_real_inclusive): Use rb_funcall instead of
- rb_big_mul because rb_integer_unpack can return a Fixnum.
-
-Sat Jun 8 11:17:39 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c (int_pair_to_real_inclusive): Use rb_integer_pack.
-
-Sat Jun 8 09:49:42 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c (int_pair_to_real_inclusive): Use rb_integer_unpack.
-
-Sat Jun 8 08:12:22 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c (random_load): Use rb_integer_pack.
-
-Sat Jun 8 06:15:46 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c (numberof): Removed.
-
-Sat Jun 8 06:00:47 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c: include internal.h.
- (mt_state): Use rb_integer_unpack.
-
-Sat Jun 8 00:55:51 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (integer_pack_loop_setup): word_num_nailbytes_ret argument
- removed.
- (rb_integer_pack): Follow the above change.
- (rb_integer_unpack): Follow the above change.
-
-Sat Jun 8 00:37:32 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (validate_integer_pack_format): Renamed from
- validate_integer_format.
- (integer_pack_loop_setup): Renamed from integer_format_loop_setup.
- (integer_pack_fill_dd): Renamed from int_export_fill_dd.
- (integer_pack_take_lowbits): Renamed from int_export_take_lowbits.
- (integer_unpack_push_bits): Renamed from int_import_push_bits.
-
-Fri Jun 7 23:58:06 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_integer_pack): Arguments changed. Use flags to
- specify word order and byte order.
- (rb_integer_unpack): Ditto.
- (validate_integer_format): Follow the above change.
- (integer_format_loop_setup): Ditto.
-
- * pack.c: Ditto.
-
- * internal.h: Ditto.
- (INTEGER_PACK_MSWORD_FIRST): Defined.
- (INTEGER_PACK_LSWORD_FIRST): Ditto.
- (INTEGER_PACK_MSBYTE_FIRST): Ditto.
- (INTEGER_PACK_LSBYTE_FIRST): Ditto.
- (INTEGER_PACK_NATIVE_BYTE_ORDER): Ditto.
- (INTEGER_PACK_LITTLE_ENDIAN): Ditto.
- (INTEGER_PACK_BIG_ENDIAN): Ditto.
-
-Fri Jun 7 22:10:50 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/rubygems/specification.rb (Gem::Specification#to_yaml):
- use Gem::NoAliasYAMLTree.create instead of Gem::NoAliasYAMLTree.new
- to suppress deprecated warnings.
-
-Fri Jun 7 21:39:39 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_integer_pack): Renamed from rb_int_export.
- (rb_integer_unpack): Renamed from rb_int_import.
-
- * internal.h, pack.c: Follow the above change.
-
-Fri Jun 7 21:05:26 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (integer_format_loop_setup): Extracted from rb_int_export
- and rb_int_import.
-
-Fri Jun 7 19:48:38 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (validate_integer_format): Extracted from rb_int_export and
- rb_int_import.
-
-Fri Jun 7 19:23:15 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_absint_size): Use numberof.
- (rb_int_export): Ditto.
-
-Fri Jun 7 18:58:56 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (numberof): Gathered from various files.
-
- * array.c, math.c, thread_pthread.c, iseq.c, enum.c, string.c, io.c,
- load.c, compile.c, struct.c, eval.c, gc.c, parse.y, process.c,
- error.c, ruby.c: Remove the definitions of numberof.
-
-Fri Jun 7 18:24:39 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_absint_size): Declare a variable, i, just before used
- to suppress a warning.
- (rb_int_export): Ditto.
-
-Fri Jun 7 17:41:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * bignum.c (rb_absint_size): explicit cast to BDIGIT to avoid implicit
- 64 bit to 32 bit shortening warning
- * bignum.c (rb_int_export): ditto
- * bignum.c (int_import_push_bits): ditto
-
-Fri Jun 7 17:31:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * internal.h (RCLASS_SUPER): use descriptive variable name
- * internal.h (RCLASS_SET_SUPER): ditto
-
-Fri Jun 7 13:25:27 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/json/fbuffer/fbuffer.h (fbuffer_append_str): change the place of
- RB_GC_GUARD. it should be after the object is used.
-
-Fri Jun 7 13:22:43 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * gc.c (before_gc_sweep): noinline can also avoid the segv instead of
- -O0 of r41084. this way is expected less slow.
-
-Fri Jun 7 11:45:42 2013 Kenta Murata <mrkn@cookpad.com>
-
- * rational.c (numeric_quo): move num_quo in numeric.c to numeric_quo
- in rational.c to refer canonicalization state for mathn support.
- [ruby-core:41575] [Bug #5736]
-
- * numeric.c (num_quo): ditto.
-
- * test/test_mathn.rb: add a test for the change at r41109.
-
-Fri Jun 7 11:41:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: revert r41106. size_t may not be unsigned
-
- * bignum.c (rb_absint_size_in_word, rb_int_export, rb_int_import): use
- NUM2SIZET() and SIZET2NUM() already defined in ruby/ruby.h.
-
-Fri Jun 7 11:28:37 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c: use oldgen bitmap as initial mark bitmap when major gc.
- so can skip oldgen bitmap check around mark & sweep.
- * gc.c (slot_sweep_body): change scan algorithm for performance:
- from object's pointer base to bitmap one.
-
-Fri Jun 7 11:25:56 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c: introduce oldgen bitmap for preparing performance tuning.
-
-Fri Jun 7 11:20:57 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (MARKED_IN_BITMAP, MARK_IN_BITMAP, CLEAR_IN_BITMAP): bring
- bitmap macros in one place, and introduce BITMAP_BIT.
-
-Fri Jun 7 11:18:35 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * array.c (ary_new): change order of allocation in order
- to remove FL_OLDGEN operation.
-
-Fri Jun 7 11:16:28 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * tool/rdocbench.rb: add gc total time information.
-
-Fri Jun 7 10:12:01 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: remove "Sunny" terminology.
- "Sunny" doesn't mean antonym of "Shady" (questionable, doubtful, etc).
- Instead of "Sunny", use "non-shady" or "normal".
-
-Fri Jun 7 09:29:33 2013 Kenta Murata <mrkn@cookpad.com>
-
- * bignum.c (rb_int_import): explicitly casting BDIGIT_DBL to BDIGIT
- to prevent warning.
-
-Fri Jun 7 07:29:33 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (rb_int_export): countp argument is split into
- wordcount_allocated and wordcount.
-
- * bignum.c (rb_int_export): Follow the above change.
-
- * pack.c (pack_pack): Ditto.
-
-Fri Jun 7 07:17:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * NEWS: describe a compatibility issue of Numeric#quo
- introduced at r41109.
-
-Fri Jun 7 07:15:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * NEWS: fix style.
-
-Fri Jun 7 06:48:17 2013 Benoit Daloze <eregontp@gmail.com>
-
- * numeric.c: remove unused ID id_to_r introduced in r41109.
-
-Fri Jun 7 06:15:31 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_int_import): New function.
- (int_import_push_bits): Ditto.
-
- * internal.h (rb_int_import): Declared.
-
- * pack.c (pack_unpack): Use rb_int_import for BER compressed integer.
-
-Thu Jun 6 22:24:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * numeric.c (num_quo): Use to_r method to convert the receiver to
- rational. [ruby-core:41575] [Bug #5736]
-
- * test/ruby/test_numeric.rb: add a test for the above change.
-
-Thu Jun 6 20:40:17 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Invoke RUBY_REPLACE_TYPE for size_t.
- Don't invoke RUBY_CHECK_PRINTF_PREFIX for size_t to avoid conflict
- with RUBY_REPLACE_TYPE.
-
- * internal.h (rb_absint_size): Declared.
- (rb_absint_size_in_word): Ditto.
- (rb_int_export): Ditto.
-
- * bignum.c (rb_absint_size): New function.
- (rb_absint_size_in_word): Ditto.
- (int_export_fill_dd): Ditto.
- (int_export_take_lowbits): Ditto.
- (rb_int_export): Ditto.
-
- * pack.c (pack_pack): Use rb_int_export for BER compressed integer.
-
-Thu Jun 6 19:31:33 2013 Tadayoshi Funaba <tadf@dotrb.org>
-
- * ext/date/date_core.c: fixed coding error [ruby-core:55337].
- reported by Riley Lynch.
-
-Thu Jun 6 14:16:37 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * ext/objspace/object_tracing.c: rename allocation_info to
- lookup_allocation_info. At times I confused "struct
- allocation_info" with "function allocation_info".
-
-Thu Jun 6 13:57:06 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * ext/objspace/object_tracing.c: allocation_info function isn't
- called by any other file.
-
-Thu Jun 6 09:41:00 2013 Kenta Murata <mrkn@cookpad.com>
-
- * numeric.c (num_quo): should return a Float for a Float argument.
- [ruby-dev:44710] [Bug #5515]
-
- * test/ruby/test_fixnum.rb: Add an assertion for the above change.
-
- * test/ruby/test_bignum.rb: ditto.
-
-Thu Jun 6 00:59:44 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (gc_mark): get rid of pushing useless objects.
- * gc.c (rgengc_rememberset_mark): bypass gc_mark() in order to push
- sunny old object at minor gc.
- * gc.c (gc_mark_children): move sunny old check to gc_mark().
- * gc.c (rgengc_check_shady): remove DEMOTE that already unnecessary.
- * gc.c (rb_gc_writebarrier): ditto.
-
- change sunny old check point in order to save mark stack and
- remove unnatural rest_sweep & demote.
-
-Thu Jun 6 00:52:42 2013 Masaya Tarui <tarui@ruby-lang.org>
-
- * gc.c (rgengc_rememberset_mark): change scan algorithm for performance:
- from object's pointer base to bitmap one.
-
-Thu Jun 6 00:30:04 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * win32/win32.c (NET_LUID): define it on MinGW32.
- mingw-w64 has NET_LUID but mingw32 (mingw.org) still doesn't have
- NET_LUID. reported by taco on IRC
-
-Thu Jun 6 00:05:08 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * string.c (String#b): Allow code range scan to happen later so
- ascii_only? on a result string returns the correct value.
- [ruby-core:55315] [Bug #8496]
-
-Wed Jun 5 22:40:42 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * lib/net/imap.rb (capability_response): should ignore trailing
- spaces. Thanks, Peter Kovacs. [ruby-core:55024] [Bug #8415]
-
- * test/net/imap/test_imap_response_parser.rb: related test.
-
-Wed Jun 5 21:17:08 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (big_fdiv): Use nlz() instead of bdigbitsize().
- (bdigbitsize): Removed.
-
-Wed Jun 5 20:32:00 2013 Kenta Murata <mrkn@cookpad.com>
-
- * include/ruby/ruby.h: fix alignment in comment.
-
-Wed Jun 5 20:05:29 2013 Tanaka Akira <akr@fsij.org>
-
- * random.c (int_pair_to_real_inclusive): Add a cast to BDIGIT.
- (random_load): Fix shift width for fixnums.
- Re-implement bignum extraction without ifdefs.
-
-Wed Jun 5 15:26:10 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * gc.c (before_gc_sweep): don't optimize it to avoid segv on Ubuntu
- 10.04 gcc 4.4.
- http://u32.rubyci.org/~chkbuild/ruby-trunk/log/20130527T190301Z.diff.html.gz
-
-Wed Jun 5 09:46:46 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * test/fileutils/test_fileutils.rb (TestFileUtils#test_mkdir): add
- EACCES for Windows.
-
-Wed Jun 5 08:13:37 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_pow): Don't need to multiply SIZEOF_BDIGITS.
- Use nlz instead of bitlength_bdigit.
- (bitlength_bdigit): Removed.
-
-Wed Jun 5 07:14:18 2013 Tadayoshi Funaba <tadf@dotrb.org>
-
- * ext/date/date_core.c (d_lite_cmp, d_lite_equal): simplified.
-
-Wed Jun 5 07:07:01 2013 Tadayoshi Funaba <tadf@dotrb.org>
-
- * ext/date/date_core.c: fixed a bug [ruby-core:55295]. reported
- by Riley Lynch.
-
-Wed Jun 5 06:44:08 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems 2.0.3
-
- * test/rubygems: Tests for the above.
-
- * NEWS: Added RubyGems 2.0.3 note.
-
-Wed Jun 5 06:35:15 2013 Eric Hodel <drbrain@segment7.net>
-
- * doc/marshal.rdoc: Add description of Marshal format.
-
-Wed Jun 5 01:16:09 2013 Benoit Daloze <eregontp@gmail.com>
-
- * array.c (Array#+): fix documentation example.
- Patch by Logan Serman. [Fixes GH-324]
-
-Wed Jun 5 00:21:54 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * lib/irb/lc/ja/help-message: update help messages.
- following r41028. [ruby-dev:46707] [Feature #7510]
-
-Wed Jun 5 00:09:32 2013 Tanaka Akira <akr@fsij.org>
-
- * marshal.c (r_object0): Generalize a round up expression.
- Use BDIGIT instead of int.
-
-Tue Jun 4 23:44:02 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * object.c (rb_Hash): fix docs. patched by Stefan Sch"ussler.
- [ruby-core:55299] [Bug #8487]
-
-Tue Jun 4 23:16:49 2013 Benoit Daloze <eregontp@gmail.com>
-
- * lib/irb/completion.rb: Use %w literal construction for long lists.
- Patch by Dave Goodchild. [Fixes GH-299]
-
-Tue Jun 4 23:08:42 2013 Benoit Daloze <eregontp@gmail.com>
-
- * ext/objspace/objspace.c: improve wording and remove duplicated comment.
- Based on a patch by Dave Goodchild. [Fixes GH-299]
-
-Tue Jun 4 18:41:47 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bitlength_bdigit): Fix an off-by-one error.
-
-Tue Jun 4 15:30:00 2013 Kenta Murata <mrkn@cookpad.com>
-
- * ext/bigdecimal/lib/bigdecimal/util.rb (Float#to_d): fix the number
- of figures. Patch by Vipul A M <vipulnsward@gmail.com>.
- https://github.com/ruby/ruby/pull/323 fix GH-323
-
- * test/bigdecimal/test_bigdecimal_util.rb: fix for the above change.
-
-Tue Jun 4 00:44:27 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * test/fileutils/test_fileutils.rb (TestFileUtils#test_mkdir): add
- EEXIST for Linux. (suggested by nurse)
-
-Mon Jun 3 23:58:19 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * lib/fileutils.rb (FileUtils.rmdir): use remove_tailing_slash.
- * test/fileutils/test_fileutils.rb: test for above.
-
-Mon Jun 3 23:47:55 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bitlength_bdigit): New function.
- (rb_big_pow): Use bitlength_bdigit instead of ffs.
-
-Mon Jun 3 23:11:19 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * lib/fileutils.rb: fix behavior when mkdir/mkdir_p accepted "/".
- * test/fileutils/test_fileutils.rb: add test for above change.
- Patched by Mitsunori Komatsu. [GH-319]
-
-Mon Jun 3 19:02:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (is_hfs): use the file descriptor instead of a path.
-
-Mon Jun 3 07:15:17 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in: removes AC_CHECK_FUNCS(readdir_r). readdir_r()
- is only used from dir.c and it doesn't need readdir_r().
- * configure.in (SIZEOF_STRUCT_DIRENT_TOO_SMALL): removed. It is
- only used for readdir_r.
- * dir.c: removes NAME_MAX_FOR_STRUCT_DIRENT. It is not right way
- to detect maximum length of path len. POSIX require to use
- fpathconf(). IOW, it might have lead to make a vulnerability
- using stack smashing. Moreover, readdir() works enough for our
- usage.
- * dir.c (READDIR): removes an implementation which uses
- readdir_r() and parenthesize in a macro body correctly.
- * dir.c (dir_read): removes IF_HAVE_READDIR_R(DEFINE_STRUCT_DIRENT
- entry), it is used only for readdir_r().
- * dir.c (dir_each): ditto.
- * dir.c (glob_helper): ditto.
-
- * dir.c (READDIR): removes entry and dp argument.
- * dir.c (dir_read): adjust for the above change.
- * dir.c (dir_each): ditto.
- * dir.c (glob_helper): ditto.
-
-Mon Jun 3 03:40:29 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_insnhelper.c (vm_yield_setup_block_args): partially revert r41019.
- The code is not useless.
-
-Mon Jun 3 01:25:25 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * test/socket/test_sockopt.rb: change test name. follow r41037.
-
-Mon Jun 3 01:08:43 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * test/rinda/test_rinda.rb: rename functions introduced in r41009.
-
-Sun Jun 2 23:33:42 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * enc/trans/japanese_euc.trans, test/ruby/test_transcode.rb,
- tool/transcode-tblgen.rb: change EUC-JP-2004 to EUC-JIS-2004.
- This is follow up to changes in r41024.
-
-Sun Jun 2 22:44:42 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/socket/option.c: rename functions introduced in r41009
- s/ip/ipv4/g because they are ipv4 functions.
- (there's a policy that the name "ip" is for methods which supports
- both ipv4 and ipv6)
-
-Sun Jun 2 16:15:29 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dln_find.c (dln_find_exe, dln_find_file): remove deprecated
- non-reentrant functions.
-
-Sun Jun 2 15:04:35 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/cgi/util.rb, lib/erb.rb: Use String#b [Feature #8394] by znz
-
-Sun Jun 2 14:10:21 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/irb/lc/help-message: Apply english updates for irb --help #7510
-
-Sun Jun 2 12:03:58 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * range.c: Fix rdoc on Range#bsearch [Bug #8242] [ruby-core:54143]
-
-Sun Jun 2 02:08:37 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * enc/euc_jp.c: fix typo: the name of EUC-JIS-2004.
-
-Sat Jun 1 23:17:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * vm_eval.c (rb_mod_module_eval): mention in docs that arguments passed
- to the method are passed to the block
-
-Sat Jun 1 17:58:13 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/set.rb (Set#freeze, taint, untaint): Save a "self" by
- utilizing super returning self, and add tests while at it.
-
-Sat Jun 1 17:24:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_set_arguments): not a simple single argument if any
- keyword arguments exist. [ruby-core:55203] [Bug #8463]
-
- * vm_insnhelper.c (vm_yield_setup_block_args): split single parameter
- if any keyword arguments exist, and then extract keyword arguments.
- [ruby-core:55203] [Bug #8463]
-
-Sat Jun 1 11:16:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (rb_exc_new_cstr): rename from rb_exc_new2.
-
- * error.c (rb_exc_new_str): rename from rb_exc_new3.
-
-Sat Jun 1 10:13:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_new[2-5], rb_{tainted,usascii}_str_new2),
- (rb_str_buf_new2): remove old interfaces.
-
-Sat Jun 1 08:00:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/zlib/zlib.c (gzfile_read, gzfile_read_all, gzfile_getc),
- (gzreader_gets): check EOF. [ruby-core:55220] [Bug #8467]
-
-Sat Jun 1 07:32:15 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: Use BDIGIT type for hbase.
-
-Sat Jun 1 02:37:35 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/socket/option.c (sockopt_s_byte): constructor of the sockopt
- whose value's is byte.
-
- * ext/socket/option.c (sockopt_byte): getter for above.
-
- * ext/socket/option.c (inspect_byte): inspect for above.
-
- * ext/socket/option.c (sockopt_s_ip_multicast_loop): constructor of
- the sockopt whose optname is IP_MULTICAST_LOOP.
-
- * ext/socket/option.c (sockopt_ip_multicast_loop): getter for above.
-
- * ext/socket/option.c (sockopt_s_ip_multicast_ttl): constructor of
- the sockopt whose optname is IP_MULTICAST_TTL.
-
- * ext/socket/option.c (sockopt_ip_multicast_ttl): getter for above.
-
- * ext/socket/option.c (sockopt_inspect): use above.
-
-Sat Jun 01 01:50:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_power): use rb_dbl2big
- to convert a double value to a Bignum.
-
-Sat Jun 1 00:19:50 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (calc_hbase): Make hbase the maximum power of base
- representable in BDIGIT.
-
-Fri May 31 23:56:13 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (calc_hbase): Extracted from rb_big2str0.
-
-Fri May 31 23:22:24 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c: Don't hard code SIZEOF_BDIGITS for log_base(hbase).
- (big2str_orig): hbase_numdigits argument added.
- (big2str_karatsuba): Ditto.
- (rb_big2str0): Calculate hbase_numdigits.
-
-Fri May 31 17:57:21 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * process.c: Improve Process::exec documentation
-
-Fri May 31 17:26:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (rb_funcallv): add better names of rb_funcall2.
-
- * vm_eval.c (rb_funcallv_public): ditto for rb_funcall3.
-
-Fri May 31 17:04:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_new_capa): add better names of rb_ary_new2.
-
- * array.c (rb_ary_new_from_args): ditto for rb_ary_new3.
-
- * array.c (rb_ary_new_from_values): ditto for rb_ary_new4.
-
-Fri May 31 16:35:44 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (HAVE_ATTRIBUTE_FUNCTION_ALIAS): define to tell if
- alias attribute is available.
-
-Fri May 31 16:03:23 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * object.c, proc.c: s/call_seq/call-seq in rdoc. [Fixes GH-322]
-
-Fri May 31 15:56:36 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/openssl/ossl_ssl.c: Add missing paren in rdoc [Fixes GH-321]
-
-Fri May 31 11:58:24 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_method.c (set_visibility): extract from rb_mod_public(),
- rb_mod_protected() and rb_mod_private().
-
-Thu May 30 19:47:42 2013 Yusuke Endoh <mame@tsg.ne.jp>
-
- * vm_insnhelper.c (vm_callee_setup_keyword_arg,
- vm_callee_setup_arg_complex): consider a hash argument for keyword
- only when the number of arguments is more than the expected
- mandatory parameters. [ruby-core:53199] [ruby-trunk - Bug #8040]
-
- * test/ruby/test_keyword.rb: update a test for above.
-
-Thu May 30 17:55:04 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * process.c: RDoc on Process.spawn
-
-Thu May 30 00:08:14 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_profile_enable): rest_sweep() to finish last GC.
- Profiling record is allocated at first of marking phase.
- Enable at lazy sweeping may cause an error (SEGV).
-
-Wed May 29 10:33:27 2013 Koichi Sasada <ko1@atdot.net>
-
- * hash.c: fix WB bug.
- (1) Hash's key also needs WB.
- (2) callback parameter *key and *value of st_update() is not a
- storage of st_table itself (only local variable). So that
- OBJ_WRITE() is not suitable, especially for `!existing'.
- OBJ_WRITTEN() is used instead of OBJ_WRITE().
-
-Tue May 28 12:31:21 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/object_tracing.c: fix a bug reported at
- "[ruby-core:55182] [ruby-trunk - Bug #8456][Open] Sugfault in Ruby Head"
- Care about the case TracePoint#path #=> `nil'.
-
- * ext/objspace/object_tracing.c: add two new methods:
- * ObjectSpace.allocation_class_path(o)
- * ObjectSpace.allocation_method_id(o)
- They are not useful for Object.new because they are always
- "Class" and :new.
- To trace more useful information, we need to maintain call-tree
- using call/return hooks, which is implemented by
- ll-prof <http://sunagae.net/wiki/doku.php?id=software:llprof>
-
- * test/objspace/test_objspace.rb: add a test.
-
-Tue May 28 11:30:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb (extmake): leave makefiles untouched if the content is
- not changed, to get rid of unnecessary re-linking.
-
-Tue May 28 03:11:02 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/gc_hook.c, ext/objspace/objspace.c: add new methods to
- hook GC invocation.
- * ObjectSpace.after_gc_start_hook=(proc)
- * ObjectSpace.after_gc_end_hook=(proc)
-
- Note that hooks are not kicked immediately. Procs are kicked
- at postponed_job.
-
- This feature is a sample of new internal event and
- rb_postponed_job API.
-
-Tue May 28 02:56:15 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat): remove wrong rest_sweep().
-
-Tue May 28 02:44:23 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (garbage_collect_body): fix GC_ENABLE_LAZY_SWEEP condition.
-
- * gc.c (GC_NOTIFY): move debug print location and use stderr instead
- of stdout.
-
-Tue May 28 02:07:21 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_trace.c (rb_postponed_job_register_one): fix iteration bug.
-
- * ext/-test-/postponed_job/postponed_job.c,
- test/-ext-/postponed_job/test_postponed_job.rb: add a test.
-
-Tue May 28 00:34:23 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h, gc.c: add new internal event
- RUBY_INTERNAL_EVENT_GC_END. This event invokes at the end of
- after_sweep().
- Time chart with lazy sweep is:
- (1) Kick RUBY_INTERNAL_EVENT_GC_START
- (2) [gc_marks()]
- (3) [lazy_sweep()]
- (4) [... run Ruby program (mutator) with lazy_sweep() ...]
- (5) [after_sweep()]
- (6) Kick RUBY_INTERNAL_EVENT_GC_END
- (7) [... run Ruby program (mutator), and go to (1) ...]
- Time chart without lazy sweep (GC.start, etc) is:
- (1) Kick RUBY_INTERNAL_EVENT_GC_START
- (2) [gc_marks()]
- (3) [gc_sweep()]
- (4) [after_sweep()]
- (5) Kick RUBY_INTERNAL_EVENT_GC_END
- (6) [... run Ruby program (mutator), and go to (1) ...]
-
- * ext/-test-/tracepoint/tracepoint.c,
- test/-ext-/tracepoint/test_tracepoint.rb: modify a test.
-
-Tue May 28 00:18:57 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_trace.c (rb_postponed_job_flush): remove a wrong comment.
-
-Mon May 27 22:09:33 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/ruby.h (RHASH_SIZE): Add a cast to suppress a
- warning, comparison between signed and unsigned integer
- expressions [-Wsign-compare], on ILP32.
-
-Mon May 27 19:25:47 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: rename RUBY_INTERNAL_EVENT_FREE to
- RUBY_INTERNAL_EVENT_FREEOBJ.
-
- * ext/-test-/tracepoint/tracepoint.c,
- ext/objspace/object_tracing.c,
- gc.c, vm_trace.c: catch up this change.
-
-Mon May 27 18:57:28 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/objspace.c: support ObjectSpace.trace_object_allocations.
- Read the following test to know HOWTO.
- This feature is a sample of RUBY_INTERNAL_EVENT.
-
- * test/objspace/test_objspace.rb: add a test.
-
- * ext/objspace/object_tracing.c: ditto.
-
- * gc.c (rb_gc_count): add. This function returns GC count.
-
- * internal.h: add decl. of rb_gc_count(). Same as `GC.count'.
-
-Mon May 27 17:33:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/rbinstall.rb (install_recursive): add maxdepth option.
-
- * tool/rbinstall.rb (bin-comm): limit depth of bindir and reject empty
- files. [ruby-core:55101] [Bug #8432]
-
-Mon May 27 16:16:18 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_trace.c (rb_postponed_job_flush, rb_postponed_job_register): use
- ruby_xmalloc/xfree. It is safe during GC.
-
-Mon May 27 09:24:03 2013 Koichi Sasada <ko1@atdot.net>
-
- * test/-ext-/postponed_job/test_postponed_job.rb: fix typo and class name.
-
-Mon May 27 09:05:17 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h, gc.c, vm_trace.c: add internal events.
- * RUBY_INTERNAL_EVENT_NEWOBJ: object created.
- * RUBY_INTERNAL_EVENT_FREE: object freed.
- * RUBY_INTERNAL_EVENT_GC_START: GC started.
- And rename `RUBY_EVENT_SWITCH' to `RUBY_INTERNAL_EVENT_SWITCH'.
-
- Internal events can not invoke any Ruby program because the tracing
- timing may be critical (under huge restriction).
- These events can be hooked only by C-extensions.
- We recommend to use rb_postponed_job_register() API to call Ruby
- program safely.
-
- This change is mostly written by Aman Gupta (tmm1).
- https://bugs.ruby-lang.org/issues/8107#note-12
- [Feature #8107]
-
- * include/ruby/debug.h, vm_trace.c: added two new APIs.
- * rb_tracearg_event_flag() returns rb_event_flag_t of this event.
- * rb_tracearg_object() returns created/freed object.
-
- * ext/-test-/tracepoint/extconf.rb,
- ext/-test-/tracepoint/tracepoint.c,
- test/-ext-/tracepoint/test_tracepoint.rb: add a test.
-
-Mon May 27 08:38:21 2013 Koichi Sasada <ko1@atdot.net>
-
- * ext/-test-/postponed_job/postponed_job.c: fix `init' function name.
-
-Mon May 27 06:22:41 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/debug.h, vm_trace.c: add rb_postponed_job API.
- Postponed jobs are registered with this API. Registered jobs
- are invoked at `ruby-running-safe-point' as soon as possible.
- This timing is completely same as finalizer timing.
-
- There are two APIs:
- * rb_postponed_job_register(flags, func, data): register a
- postponed job with data. flags are reserved.
- * rb_postponed_job_register_one(flags, func, data): same as
- `rb_postponed_job_register', but only one `func' job is
- registered (skip if `func' is already registered).
-
- This change is mostly written by Aman Gupta (tmm1).
- https://bugs.ruby-lang.org/issues/8107#note-15
- [Feature #8107]
-
- * gc.c: use postponed job API for finalizer.
-
- * common.mk: add dependency from vm_trace.c to debug.h.
-
- * ext/-test-/postponed_job/extconf.rb, postponed_job.c,
- test/-ext-/postponed_job/test_postponed_job.rb: add a test.
-
- * thread.c: implement postponed API.
-
- * vm_core.h: ditto.
-
-Mon May 27 02:26:02 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat): collect promote_operation_count and
- types (RGENGC_PROFILE >= 2).
-
-Mon May 27 01:40:58 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat): collect shade_operation_count,
- remembered_sunny_object_count and remembered_shady_object_count
- for each types when RGENGC_PROFILE >= 2.
- They are informative for optimization.
-
-Mon May 27 01:15:22 2013 Koichi Sasada <ko1@atdot.net>
-
- * hash.c (rb_hash_tbl_raw), internal.h: added.
- Returns st_table without shading hash.
-
- * array.c: use rb_hash_tbl_raw() for read-only purpose.
-
- * compile.c (iseq_compile_each): ditto.
-
- * gc.c (count_objects): ditto.
-
- * insns.def: ditto.
-
- * process.c: ditto.
-
- * thread.c (clear_coverage): ditto.
-
- * vm_insnhelper.c: ditto.
-
-Mon May 27 00:31:09 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/make-snapshot: use ENV["AUTOCONF"] instead of directly using
- literal "autoconf".
-
-Sun May 26 21:31:46 2013 Koichi Sasada <ko1@atdot.net>
-
- * hash.c, include/ruby/ruby.h: support WB protected hash.
- * constify RHash::ifnone and make new macro RHASH_SET_IFNONE().
- * insert write barrier for st_update().
-
- * include/ruby/intern.h: declare rb_hash_set_ifnone(hash, ifnone).
-
- * marshal.c (r_object0): use RHASH_SET_IFNONE().
-
- * ext/openssl/ossl_x509name.c (Init_ossl_x509name): ditto.
-
-Sat May 25 23:22:38 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * test/fiddle/test_c_struct_entry.rb,
- test/fiddle/test_c_union_entity.rb,
- test/fiddle/test_cparser.rb, test/fiddle/test_func.rb,
- test/fiddle/test_handle.rb, test/fiddle/test_import.rb,
- test/fiddle/test_pointer.rb: don't run test if the system
- don't support fiddle.
-
-Sat May 25 21:29:34 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/pty/pty.c (get_device_once): FreeBSD 10-current and 9-stable
- added O_CLOEXEC support to posix_openpt, so assume FreeBSD 9.2 or
- later supports it.
- http://www.freebsd.org/cgi/query-pr.cgi?pr=162374
-
-Sat May 25 18:46:23 2013 Yusuke Endoh <mame@tsg.ne.jp>
-
- * proc.c (rb_method_entry_min_max_arity): fix missing break in switch.
- This was introduced in r38236, which is not intentional apparently.
- This has caused no actual harm because VM_METHOD_TYPE_OPTIMIZED is
- not used except for OPTIMIZED_METHOD_TYPE_SEND, but may do in
- future. Coverity Scan found this inadequacy.
-
-Sat May 25 18:08:06 2013 Yusuke Endoh <mame@tsg.ne.jp>
-
- * dir.c (bracket): fix copy-paste error. When the first and last
- characters of fnmatch range have different length, fnmatch may
- have wrongly matched a path that does not really match.
- Coverity Scan found this bug.
-
-Sat May 25 17:06:25 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (after_gc_sweep): reduce full GC timing.
-
-Sat May 25 11:28:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * variable.c (set_const_visibility): return without clearing method
- cache if no arguments.
-
- * vm_method.c (set_method_visibility): ditto.
-
-Sat May 25 11:27:32 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_method.c (set_method_visibility): quote unprintable method name.
-
-Sat May 25 11:24:24 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (rb_frame_callee): returns the called name of the current
- frame, not the previous frame.
-
- * eval.c (prev_frame_callee, prev_frame_func): rename and make static,
- as these are used by rb_f_method_name() and rb_f_callee_name() only.
-
- * variable.c (set_const_visibility): use the called name.
-
-Sat May 25 08:58:23 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_quote_unprintable): check if argument is a string.
-
-Fri May 24 19:32:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * variable.c (set_const_visibility): use rb_frame_this_func() instead
- of rb_frame_callee() for getting the name of the called method
-
- * test/ruby/test_module.rb: add test for private_constant with no args
-
-Fri May 24 18:53:10 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: do major/full GC when:
- * number of oldgen object is bigger than twice of
- number of oldgen object at last full GC.
- * number of remembered shady object is bigger than twice of
- number of remembered shady object at last full GC.
- * number of oldgen object and remembered shady object is bigger
- than half of total object space.
- (please fix my English!)
-
-Fri May 24 17:07:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
-
- * intern.h: remove dangling rb_class_init_copy declaration
- [ruby-core:55120] [Bug #8434]
-
-Fri May 24 16:31:23 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/strscan/strscan.c (strscan_aref): raise error if given
- name reference is not found.
-
-Fri May 24 15:48:18 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (after_gc_sweep, garbage_collect_body): do major GC (full GC)
- before extending heaps.
- TODO: do major GC when there are many old (promoted) objects.
-
- * gc.c (after_gc_sweep): remove TODO comments.
-
-Fri May 24 11:04:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (LIBRUBY_RPATHFLAGS): do not append -L option with
- runtime library directory if cross compiling, but only -R option.
- runtime path makes no sense on the host system. [ruby-dev:47363]
- [Bug #8443]
-
-Fri May 24 02:57:17 2013 Koichi Sasada <ko1@atdot.net>
-
- * object.c (rb_obj_clone): should not propagate OLDGEN status.
- This propagation had caused WB miss for class.
-
-Thu May 23 17:35:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * load.c (loaded_feature_path): fix invalid read by index underflow.
- the beginning of name is also a boundary as well as just after '/'.
-
-Thu May 23 17:21:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (gc_profile_dump_on): revert r40898. ok to show the record
- accumulating while lazy_sweep().
-
-Wed May 22 16:50:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (gc_profile_dump_on): use size_t to get rid of overflow and
- show the header when next_index > 0, instead of next_index != 1.
-
-Wed May 22 15:18:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (setup_overlapped): check the error code in addition
- to the result of SetFilePointer() to determine if an error occurred,
- because INVALID_SET_FILE_POINTER is a valid value.
- [ruby-core:55098] [Bug #8431]
-
- * win32/win32.c (setup_overlapped, finish_overlapped): extract from
- rb_w32_read() and rb_w32_write().
-
-Wed May 22 14:19:56 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_prepare_free_objects, rest_sweep, lazy_sweep): fix position
- of `during_gc' setting.
-
-Wed May 22 07:36:08 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (garbage_collect): all GC is start from garbage_collect()
- (or garbage_collect_body()). `garbage_collect()' accept additional
- two parameters `full_mark' and `immediate_sweep'.
- If `full_mark' is TRUE, then force it full gc (major gc), otherwise,
- it depends on status of object space. Now, it will be minor gc.
- If `immediate_sweep' is TRUE, then disable lazy sweep.
- To allocate free memory, `full_mark' and `immediate_sweep' should be
- TRUE. Otherwise, they should be FALSE.
-
- * gc.c (gc_prepare_free_objects): use `garbage_collect_body()'.
-
- * gc.c (slot_sweep, before_gc_sweep, after_gc_sweep): add logging code.
-
-Tue May 21 22:47:06 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/strscan/strscan.c (strscan_aref): support named captures.
- patched by Konstantin Haase [ruby-core:54664] [Feature #8343]
-
-Tue May 21 21:48:44 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * test/ruby/test_dir_m17n.rb (TestDir_M17N#test_entries_compose):
- Use #each instead of #map just for iteration.
-
-Tue May 21 19:57:22 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * ext/digest/lib/digest.rb (Digest::Class.file): Take optional
- arguments that are passed to the constructor of the digest
- class.
-
-Tue May 21 17:21:12 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: remove gc_profile_record::is_marked. always true.
-
-Tue May 21 17:13:40 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: fix to collect additional information for GC::Profiler.
- * major/minor GC
- * trigger reason of GC
-
- * gc.c (gc_profile_dump_on): change reporting format with
- added information.
-
- * gc.c (gc_profile_record_get): return added information by
- :GC_FLAGS => array.
-
-Tue May 21 16:45:31 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: GC::Profiler's sweeping time is accumulated all slot
- sweeping time. At lazy GC, GC::Profiler makes new record entry
- for each lazy_sweep(). In this change, accumulating all
- slot_sweep() time.
- And change indentation.
-
-Tue May 21 16:29:09 2013 Koichi Sasada <ko1@atdot.net>
-
- * common.mk (rdoc-bench): add a benchmark rule
- using RDoc. Generate all rdoc related files
- (same as `make rdoc') in temporary directory
- and remove them. Execution time, GC::Profiler
- and results of GC.stat are printed.
-
- * tool/rdocbench.rb: added for `rdoc-bench'.
-
-Tue May 21 16:25:05 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_profile_dump_on): `count' should be (int) because it
- can be negative number.
- And use pointer for `record' (don't copy).
-
-Tue May 21 03:11:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (dir_each): compose HFS file names from
- UTF8-MAC. [ruby-core:48745] [Bug #7267]
-
-Tue May 21 03:08:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/ruby/envutil.rb (assert_separately): require envutil in the
- child process too.
-
-Tue May 21 03:07:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_conv_enc_opts): should infect.
-
-Mon May 20 22:24:45 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/set.rb (Set#delete_if, Set#keep_if): Avoid blockless call of
- proc, which is not portable to JRuby. Replace &method() with
- faster and simpler literal blocks while at it.
-
-Mon May 20 22:00:31 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/e2mmap.rb: Format of E2MM documentation
-
-Mon May 20 21:41:15 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/extmk.rb: nodoc this file
-
-Mon May 20 20:43:32 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/cmath.rb: Remove duplicate RDoc heading from overview
-
-Mon May 20 20:36:19 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/securerandom.rb: Update position of overview for RDoc
-
-Mon May 20 19:33:55 2013 Benoit Daloze <eregontp@gmail.com>
-
- * math.c: improve and fix documentation of sin, tan and log
-
-Mon May 20 19:31:49 2013 Benoit Daloze <eregontp@gmail.com>
-
- * lib/logger.rb (Logger::Application): show namespace in documentation
-
-Mon May 20 11:50:12 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/pp.rb: Revert part of r40834 and nodoc PP::ObjectMixin
- [ruby-core:55068]
-
-Mon May 20 10:40:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/webrick/htmlutils.rb (WEBrick::HTMLUtils#escape): replace HTML
- meta chars even in non-ascii string. [Bug #8425] [ruby-core:55052]
-
- * lib/webrick/httputils.rb (WEBrick::HTTPUtils#{_escape,_unescape}):
- fix %-escape encodings. [Bug #8425] [ruby-core:55052]
-
- * lib/webrick/httpservlet/filehandler.rb (set_dir_list): revert r20152
- partially and fix misuse of bytesize and regexp repetition operator.
-
-Mon May 20 08:03:51 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/profiler.rb: Document Profiler__ methods
-
-Mon May 20 08:02:13 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/tempfile.rb: nodoc Tempfile#inspect
-
-Mon May 20 07:48:24 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/stringio/stringio.c: Correct position of method rdoc
-
-Mon May 20 07:27:41 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * math.c: RDoc formatting of Math core docs with domains and codomains
- Patch by @eLobato [Fixes GH-309]
-
-Mon May 20 05:58:12 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/bigdecimal/bigdecimal.c: Formatting for BigMath [Fixes GH-306]
- Based on a patch by @eLobato.
- * ext/bigdecimal/lib/bigdecimal/math.rb: ditto
-
-Mon May 20 04:56:59 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/forwardable.rb: Forwardable examples in overview were broken
- Based on patch by @joem [Fixes GH-303] [Bug #8392]
-
-Mon May 20 03:35:26 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/optparse.rb: nodoc OptionParser::Version and SPLAT_PROC
-
-Mon May 20 03:16:52 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/pp.rb: Document PP::ObjectMixin [Fixes GH-312]
-
-Sun May 19 23:52:22 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * test/webrick/test_htmlutils.rb: add test for WEBrick::HTMLUtils.
-
-Sun May 19 23:12:07 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * encoding.c: document fix, change default script encoding.
- patched by @windwiny [Fixes GH-310]
-
-Sun May 19 17:29:07 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/set.rb (Set#delete_if, Set#keep_if): Add comments.
-
-Sun May 19 11:37:36 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * ext/fiddle/extconf.rb: ignore rc version of libffi to fix build failure.
-
-Sun May 19 10:38:50 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-electric.el (ruby-electric-delete-backward-char): Use
- delete-char instead of delete-backward-char, which is an
- interactive function.
-
-Sun May 19 03:59:29 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (str_scrub0): added for refactoring.
-
-Sun May 19 03:48:26 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/common.rb (URI.decode_www_form): scrub string if decoded
- bytes are invalid for the encoding.
-
-Sun May 19 02:46:32 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/set.rb (Set#delete_if, Set#keep_if): Make Set#delete_if and
- Set#keep_if more space and time efficient by avoiding to_a.
-
-Sun May 19 02:33:09 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-electric.el (ruby-electric-setup-keymap): Make
- backquotes electric as well. It was listed in
- ruby-electric-expand-delimiters-list but not activated.
-
- * misc/ruby-electric.el (ruby-electric-delete-backward-char):
- Introduce electric DEL that deletes what the previous electric
- command has input.
-
- * misc/ruby-electric.el (ruby-electric-matching-char): Make
- electric quotes work again at the end of buffer.
-
-Sun May 19 01:39:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (setjmp-type): check if setjmpex() is really available.
- workaround for i686-w64-mingw32 which declares it but lacks its
- definition.
-
- * include/ruby/defines.h: include setjmpex.h only if also setjmpex()
- is available.
-
-Sat May 18 23:57:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (setjmp-type): use setjmpex() on w64-mingw32 to get rid
- of -Wclobbered warnings.
-
- * include/ruby/defines.h: include setjmpex.h here becase setjmp.h is
- included from win32.h via intrin.h, winnt.h, and so on.
-
-Sat May 18 20:28:12 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/mkconstants.rb (INTEGER2NUM): Make less comparisons.
-
-Sat May 18 20:15:28 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (str_scrub_bang): add String#scrub!. [Feature #8414]
-
-Sat May 18 16:59:52 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/mkconstants.rb (INTEGER2NUM): Renamed from INTEGER2VALUE.
-
-Sat May 18 16:57:58 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/mkconstants.rb (INTEGER2VALUE): Suppress a warning:
- comparison between signed and unsigned integer expressions
-
-Sat May 18 16:38:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_compile_each): forward anonymous and first keyword
- rest argument one. [ruby-core:55033] [Bug #8416].
-
-Sat May 18 15:49:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_core.h (rb_vm_tag): move jmpbuf between tag and prev so ensure to
- be accessible.
-
-Sat May 18 11:05:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enumerator.c (inspect_enumerator): use VALUE instead of mere char*
- by using rb_sprintf() and rb_id2str().
-
- * enumerator.c (append_method): extract from inspect_enumerator().
-
-Sat May 18 09:00:32 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/mkconstants.rb (INTEGER2VALUE): Use LONG2FIX if possible.
-
-Sat May 18 00:38:47 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/mkconstants.rb: Convert integer constants bigger than int
- correctly.
-
-Fri May 17 22:02:15 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/ifaddr.c: Use unsigned LONG_LONG to represent flags
- because SunOS 5.11 (OpenIndiana) defines ifa_flags as uint64_t.
-
-Fri May 17 21:47:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * cont.c: Typo in constant MAX_MACHINE_STACK_CACHE from '..MAHINE..'
- patch by @schmurfy [Fixes GH-307]
-
-Fri May 17 19:18:24 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-electric.el (ruby-electric-matching-char): Do not put
- a closing quote when the quote typed does not start a string, as
- in $', ?\' or ?\".
-
-Fri May 17 18:06:15 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Consider error messages to find out version option of
- C compiler.
- The C compiler of Sun Studio C emits "Warning: Option -qversion
- passed to ld, if ld is invoked, ignored otherwise" and exit
- successfully.
-
-Fri May 17 17:34:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (rb_gc_guarded_ptr): unoptimize on other compilers than gcc and
- msvc.
-
-Fri May 17 11:06:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval_intern.h (TH_PUSH_TAG): ensure jmpbuf to be accessible before
- pushing tag to get rid of unaccessible tag by stack overflow.
-
-Thu May 16 17:15:32 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_eval.c (rb_catch_obj): add volatile to tag to prevent crash
- experimentally.
- http://www.rubyist.net/~akr/chkbuild/debian/ruby-trunk/log/20130515T133500Z.log.html.gz
-
-Thu May 16 16:19:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/Makefile.sub (verconf.in): no longer used.
-
- * win32/Makefile.sub (config.status): fix typo.
-
- * configure.in, template/verconf.h.in (RUBY_EXEC_PREFIX): fix for
- default prefix.
-
-Thu May 16 13:12:27 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * template/verconf.h.in: generate verconf.h from the template and
- rbconfig.rb.
-
-Thu May 16 05:47:18 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb: fix syntax error.
- Thanks @spastorino! [ruby-core:55011]
-
-Thu May 16 03:05:45 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_node_newnode): use newobj_of() instead of rb_newobj().
-
-Thu May 16 02:03:39 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/depend: Add a dependency for ifaddr.o.
-
-Thu May 16 01:44:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (verconf.h): $< cannot be used in explicit rules with
- nmake.
-
- * win32/Makefile.sub (CONFIG_H): create verconf.in instead of
- verconf.h.
-
-Thu May 16 01:25:07 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb: only emit warnings when
- -w is enabled.
-
-Wed May 15 18:58:17 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (newobj): rename to `newobj_of' and accept additional
- three parameters v1, v2, v3. newobj_of() do OBJSETUP() and
- fill values with v1, v2, v3.
-
- * gc.c (rb_data_object_alloc, rb_data_typed_object_alloc):
- use newobj_of().
-
-Wed May 15 17:55:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (RUBY_PLATFORM): move to config.h as needed by
- version.c.
-
-Wed May 15 17:04:11 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: add an additional RGENGC_PROFILE mode (2).
- Profiling result can be check by GC.stat.
-
- * gc.c (type_name): separate from obj_type_name().
-
-Wed May 15 16:58:24 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: save configured load path values into verconf.in.
-
- * common.mk (verconf.h): create from verconf.in with shvar_to_cpp.rb.
-
- * tool/shvar_to_cpp.rb: turn shell variables into C macros.
- [Bug #7959]
-
- * loadpath.c: split load path staffs from version.c.
-
- * dmyloadpath.c: miniruby has no builtin load paths, so verconf.h is
- not needed.
-
-Wed May 15 03:56:09 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb: adding backwards
- compatible YAMLTree.new method
-
-Wed May 15 02:22:16 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych.rb: Adding Psych.safe_load for loading a user
- defined, restricted subset of Ruby object types.
- * ext/psych/lib/psych/class_loader.rb: A class loader for
- encapsulating the logic for which objects are allowed to be
- deserialized.
- * ext/psych/lib/psych/deprecated.rb: Changes to use the class loader
- * ext/psych/lib/psych/exception.rb: ditto
- * ext/psych/lib/psych/json/stream.rb: ditto
- * ext/psych/lib/psych/nodes/node.rb: ditto
- * ext/psych/lib/psych/scalar_scanner.rb: ditto
- * ext/psych/lib/psych/stream.rb: ditto
- * ext/psych/lib/psych/streaming.rb: ditto
- * ext/psych/lib/psych/visitors/json_tree.rb: ditto
- * ext/psych/lib/psych/visitors/to_ruby.rb: ditto
- * ext/psych/lib/psych/visitors/yaml_tree.rb: ditto
- * ext/psych/psych_to_ruby.c: ditto
- * test/psych/helper.rb: ditto
- * test/psych/test_safe_load.rb: tests for restricted subset.
- * test/psych/test_scalar_scanner.rb: ditto
- * test/psych/visitors/test_to_ruby.rb: ditto
- * test/psych/visitors/test_yaml_tree.rb: ditto
-
-Wed May 15 02:06:35 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * test/psych/helper.rb: envutil is not available outside Ruby, so
- port the functions from envutil to the test helper.
-
- * test/psych/test_deprecated.rb: ditto
-
- * test/psych/test_encoding.rb: ditto
-
-Wed May 15 00:42:54 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * signal.c: need to include unistd.h for write(2).
- unistd.h is now included via ruby/defines.h, but should explicitly
- include here. (suggested by kosaki)
-
-Tue May 14 23:43:05 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/.document: Add ifaddr.c.
-
-Tue May 14 23:24:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/socket/extconf.rb: check for if_nametoindex() for
- i686-w64-mingw32, and check for declarations of if_indextoname() and
- if_nametoindex().
-
- * ext/socket/ifaddr.c (ifaddr_ifindex): not-implement unless
- if_nametoindex() is available.
-
- * ext/socket/rubysocket.h: declare if_indextoname() and
- if_nametoindex() if available but not declared.
-
-Tue May 14 19:58:17 2013 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * ext/dl/lib/dl/func.rb (DL::Function#call): check tainted when
- $SAFE > 0.
- * ext/fiddle/function.c (function_call): check tainted when $SAFE > 0.
- * test/fiddle/test_func.rb (module Fiddle): add test for above.
-
-
-Tue May 14 14:51:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/win32.h (INTPTR_MAX, INTPTR_MIN, UINTPTR_MAX): split
- from intptr_t and uintptr_t, since VC9 defines the latter only in
- crtdefs.h.
-
-Tue May 14 12:21:28 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (NET_LUID): mingw may have NET_LUID and not defined
- _IFDEF_.
-
-Tue May 14 03:33:17 2013 Koichi Sasada <ko1@atdot.net>
-
- * string.c (rb_str_new_frozen): remove debug print.
-
-Tue May 14 03:22:51 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: enable to generate write barrier protected
- arrays (T_ARRAY).
-
-Tue May 14 03:21:42 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: enable to generate write barrier protected
- strings (T_STRING).
-
-Tue May 14 03:19:59 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: enable to generate write barrier protected
- objects (T_OBJECT).
-
-Tue May 14 03:17:15 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: enable to generate write barrier protected
- objects for numeric types (Float, Complex, Rational, Bignum).
-
-Tue May 14 03:10:59 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: enable RGENGC (USE_RGENGC)
- but no type creates write protected (sunny) objects
- (RGENGC_WB_PROTECTED_* == 0).
-
-Tue May 14 02:47:30 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: support RGENGC. [ruby-trunk - Feature #8339]
- See this ticket about RGENGC.
-
- * gc.c: Add several flags:
- * RGENGC_DEBUG: if >0, then prints debug information.
- * RGENGC_CHECK_MODE: if >0, add assertions.
- * RGENGC_PROFILE: if >0, add profiling features.
- check GC.stat and GC::Profiler.
-
- * include/ruby/ruby.h: disable RGENGC by default (USE_RGENGC == 0).
-
- * array.c: add write barriers for T_ARRAY and generate sunny objects.
-
- * include/ruby/ruby.h (RARRAY_PTR_USE): added. Use this macro if
- you want to access raw pointers. If you modify the contents which
- pointer pointed, then you need to care write barrier.
-
- * bignum.c, marshal.c, random.c: generate T_BIGNUM sunny objects.
-
- * complex.c, include/ruby/ruby.h: add write barriers for T_COMPLEX
- and generate sunny objects.
-
- * rational.c (nurat_s_new_internal), include/ruby/ruby.h: add write
- barriers for T_RATIONAL and generate sunny objects.
-
- * internal.h: add write barriers for RBasic::klass.
-
- * numeric.c (rb_float_new_in_heap): generate sunny T_FLOAT objects.
-
- * object.c (rb_class_allocate_instance), range.c:
- generate sunny T_OBJECT objects.
-
- * string.c: add write barriers for T_STRING and generate sunny objects.
-
- * variable.c: add write barriers for ivars.
-
- * vm_insnhelper.c (vm_setivar): ditto.
-
- * include/ruby/ruby.h, debug.c: use two flags
- FL_WB_PROTECTED and FL_OLDGEN.
-
- * node.h (NODE_FL_CREF_PUSHED_BY_EVAL, NODE_FL_CREF_OMOD_SHARED):
- move flag bits.
-
-Tue May 14 01:54:48 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: remove rb_objspace_t::marked_num.
- We can use `objspace_live_num()' instead of removed `marked_num'
- if it is after `after_gc_sweep()' function call.
-
- * gc.c (after_gc_sweep): use objspace_live_num() instead of removed
- rb_objspace_t::marked_num.
-
- * gc.c (gc_mark_ptr, gc_marks): remove rb_objspace_t::marked_num code.
-
- * gc.c (gc_prepare_free_objects): do not call set_heaps_increment()
- with checking objspace->heap.marked_num. At this point, we only
- need to check availability of free-cell.
-
- * gc.c (lazy_sweep): call after_gc_sweep() if there are no sweep_able entry.
-
- * gc.c (rest_sweep, gc_prepare_free_objects): remove after_gc_sweep() call.
-
-Tue May 14 01:50:41 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: disable GC_PROFILE_MORE_DETAIL (fix last commit).
-
- * gc.c (gc_prof_set_malloc_info): fix "objspace->heap.live_num" to
- "objspace_live_num(objspace)". There is no such member variable.
-
-Tue May 14 01:25:55 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: refactoring GC::Profiler.
-
- * gc.c (gc_prof_sweep_timer_start/stop): removed because
- they doesn't support lazy sweep.
-
- * gc.c (gc_prof_sweep_slot_timer_start/stop): added.
- redefine `sweeping time' to accumulated time of all of
- slot_sweep().
-
- * gc.c (rb_objspace_t::profile::count): renamed to
- rb_objspace_t::profile::next_index. `counter' seems ambiguous.
- increment it when next record is acquired.
-
-Tue May 14 00:48:55 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: constify RRational::(num,den) and
- RComplex::(real,imag).
- Add macro to set these values:
- * RRATIONAL_SET_NUM()
- * RRATIONAL_SET_DEN()
- * RCOMPLEX_SET_REAL()
- * RCOMPLEX_SET_IMAG()
- This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
-
- TODO: API design. RRATIONAL_SET(rat,num,den) is enough?
- TODO: Setting constify variable with cast has same issue of r40691.
-
- * complex.c, rational.c: use above macros.
-
-Mon May 13 21:49:17 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: Check socketpair again.
- It is required on Unix.
-
-Mon May 13 21:20:32 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (getipaddrs): use alternative interface name if
- available, because if_nametoindex() requires them.
-
-Mon May 13 20:23:24 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c, include/ruby/win32.h (getipaddrs): [experimental]
- emulate getipaddrs(3) on Unix.
-
- * win32/Makefile.sub, configure.in (LIBS): need iphlpapi.lib for above
- function.
-
- * include/ruby/win32.h (socketpair): rb_w32_socketpair() doesn't
- substitute for any function, so use non-prefixed name.
-
- * ext/socket/extconf.rb (socketpair); follow above change.
-
-Mon May 13 20:11:06 2013 Koichi Sasada <ko1@atdot.net>
-
- * iseq.c (prepare_iseq_build): remove additional line break.
-
-Mon May 13 19:29:54 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: constify RBasic::klass and add
- RBASIC_CLASS(obj) macro which returns a class of `obj'.
- This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
-
- * object.c: add new function rb_obj_reveal().
- This function reveal internal (hidden) object by rb_obj_hide().
- Note that do not change class before and after hiding.
- Only permitted example is:
- klass = RBASIC_CLASS(obj);
- rb_obj_hide(obj);
- ....
- rb_obj_reveal(obj, klass);
-
- TODO: API design. rb_obj_reveal() should be replaced with others.
-
- TODO: modify constified variables using cast may be harmful for
- compiler's analysis and optimization.
- Any idea to prohibit inserting RBasic::klass directly?
- If rename RBasic::klass and force to use RBASIC_CLASS(obj),
- then all codes such as `RBASIC(obj)->klass' will be
- compilation error. Is it acceptable? (We have similar
- experience at Ruby 1.9,
- for example "RARRAY(ary)->ptr" to "RARRAY_PTR(ary)".
-
- * internal.h: add some macros.
- * RBASIC_CLEAR_CLASS(obj) clear RBasic::klass to make it internal
- object.
- * RBASIC_SET_CLASS(obj, cls) set RBasic::klass.
- * RBASIC_SET_CLASS_RAW(obj, cls) same as RBASIC_SET_CLASS
- without write barrier (planned).
- * RCLASS_SET_SUPER(a, b) set super class of a.
-
- * array.c, class.c, compile.c, encoding.c, enum.c, error.c, eval.c,
- file.c, gc.c, hash.c, io.c, iseq.c, marshal.c, object.c,
- parse.y, proc.c, process.c, random.c, ruby.c, sprintf.c,
- string.c, thread.c, transcode.c, vm.c, vm_eval.c, win32/file.c:
- Use above macros and functions to access RBasic::klass.
-
- * ext/coverage/coverage.c, ext/readline/readline.c,
- ext/socket/ancdata.c, ext/socket/init.c,
- * ext/zlib/zlib.c: ditto.
-
-Mon May 13 18:44:14 2013 Koichi Sasada <ko1@atdot.net>
-
- * *.c, parse.y, insns.def: use RARRAY_AREF/ASET macro
- instead of using RARRAY_PTR().
-
-Mon May 13 16:53:53 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: add new utility macros to access
- Array's element.
- * RARRAY_AREF(a, i) returns i-th element of an array `a'
- * RARRAY_ASET(a, i, v) set i-th element of `a' to `v'
- This change is a part of RGENGC branch [ruby-trunk - Feature #8339].
-
-Mon May 13 15:31:10 2013 Koichi Sasada <ko1@atdot.net>
-
- * object.c (rb_obj_setup): added.
-
- * include/ruby/ruby.h (OBJSETUP): use rb_obj_setup() instead of
- a macro.
-
-Mon May 13 15:24:16 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_data_object_alloc): check klass only if klass is not 0.
- klass==0 means internal object.
-
-Mon May 13 14:57:28 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_data_object_alloc, rb_data_typed_object_alloc):
- use NEWOBJ_OF() instead of NEWOBJ().
-
-Mon May 13 14:51:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (rb_obj_singleton_method): new method Kernel#singleton_method
- which returns a Method object of the singleton method.
- non-singleton method causes NameError, but not aliased or zsuper
- method, right now.
- [ruby-core:54914] [Feature #8391]
-
- * vm_method.c (rb_method_entry_at): return the method entry for id at
- klass, without ancestors.
-
- * class.c (rb_singleton_class_get): get the singleton class if exists,
- or nil.
-
-Mon May 13 10:20:59 2013 Yuki Yugui Sonoda <yugui@google.com>
-
- * ext/openssl/ossl_ssl.c: Disabled OpenSSL::SSL::SSLSocket if
- defined(OPENSSL_NO_SOCK).
-
- This fixes a linkage error on platforms which do not have socket.
- OpenSSL itself is still useful as a set of cryptographic functions
- even on such platforms.
-
-Mon May 13 10:30:04 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * hash.c: Hash[] and {} are not equivalent by @eam [Fixes GH-301]
-
-Mon May 13 10:04:22 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * random.c: Document Random::DEFAULT by @eLobato [Fixes GH-304]
-
-Sun May 12 21:12:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (OFFT2NUM): RUBY_REPLACE_TYPE also defines macro
- to convert int type to VALUE if found.
-
-Wed May 8 13:46:52 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * include/ruby/intern.h (rb_iv_set, rb_iv_get): removed. Because
- ruby.h has a declaration for that.
-
-Wed May 8 13:49:06 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * include/ruby/intern.h (rb_uint2big, rb_int2big, rb_uint2inum)
- (rb_int2inum, rb_ll2inum, rb_ull2inum): removed because ruby.h
- has a declaration for these.
-
-Sun May 12 17:52:23 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in: removes 'ac_cv_func_fseeko=yes' form MinGW
- specific definitions.
-
-Sun May 12 17:25:46 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * file.c (rb_file_s_truncate): use correct type. chsize takes
- a long.
-
-Sun May 12 17:18:46 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * process.c: move '#define HAVE_SPAWNV 1' to win32/Makefile.sub.
- * win32/Makefile.sub: see above.
-
-Sun May 12 17:13:32 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in: removes AC_CHECK_FUNCS(setitimer) because it's
- unused.
-
-Sun May 12 17:08:16 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in: removes AC_CHECK_FUNCS(pause) because it's unused.
-
-Sun May 12 17:05:18 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * signal.c (rb_f_kill): fixes typo. s/HAS_KILLPG/HAVE_KILLPG/.
-
-Sun May 12 17:03:27 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in: abort if gettimeofday doesn't exist.
-
-Sun May 12 16:31:27 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in: adds RUBY_REPLACE_TYPE(off_t) for creating
- NUM2OFFT.
- * file.c (rb_file_truncate): use correct type. chsize() take
- a long.
- * include/ruby/ruby.h (NUM2OFFT): use a definition created by
- a configure script by default.
-
-Sun May 12 16:03:41 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in: removes AC_CHECK_FUNC(fseeko, fseeko64, ftello,
- ftello64). They are not used from anywhere.
-
- * win32/win32.c (fseeko): removes.
- * win32/win32.c (rb_w32_ftello): removes.
- * include/ruby/win32.h: removes declarations of rb_w32_ftello and
- rb_w32_fseeko.
- * win32/Makefile.sub: removes '#define HAVE_FTELLO 1'.
-
-Sun May 12 15:51:47 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in: remove AC_CHECK_FUNC(close). It is not used from
- anywhere.
-
-Sun May 12 15:50:45 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in: adds comments for setjmp check.
-
-Sun May 12 15:38:09 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in: move clock_gettime() check into regular place.
-
-Wed May 8 13:45:53 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in: add getenv() declaration check.
- * dln_find.c: add HAVE_DECL_GETENV test.
-
-Sun May 12 15:33:18 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in: sorts AC_CHECK_FUNCS()s as alphabetical order.
-
-Wed May 8 13:41:57 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * bignum.c: remove redundant decl for big_lshift() big_rshift().
-
-Sun May 12 16:06:43 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/socket/rubysocket.h (rsock_inspect_sockaddr): as r40646
- check HAVE_TYPE_STRUCT_SOCKADDR_DL.
-
-Sat May 11 23:01:58 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/socket/rubysocket.h (HAVE_TYPE_STRUCT_SOCKADDR_DL):
- MSVC has struct sockaddr_dl, but its content is broken.
- http://ruby-mswin.cloudapp.net/vc10-x64/ruby-trunk/log/20130511T103938Z.log.html.gz
-
-Sat May 11 22:07:42 2013 Tanaka Akira <akr@fsij.org>
-
- * test/rinda/test_rinda.rb: Socket.getifaddrs may returns an interface
- which #addr method returns nil for venet0 in OpenVZ.
-
-Sat May 11 21:56:34 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/raddrinfo.c (rsock_inspect_sockaddr): Add casts to
- suppress warnings.
-
-Sat May 11 17:28:51 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket: New method, Socket.getifaddrs, implemented.
- [ruby-core:54777] [Feature #8368]
-
-Sat May 11 00:47:22 2013 Tanaka Akira <akr@fsij.org>
-
- * gc.h (SET_MACHINE_STACK_END): Add !defined(_ILP32) to a defining
- condition to avoid compilation error on x32.
- https://sites.google.com/site/x32abi/
-
-Fri May 10 23:56:34 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_peek_variable_name): treat invalid global, class,
- and instance variable names as mere strings rather than errors.
- [ruby-core:54885] [Bug #8375]
-
-Fri May 10 20:22:40 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Move library checks into "Checks for libraries." part.
-
-Fri May 10 19:32:01 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Reformat arguments of AC_CHECK_HEADERS and
- AC_CHECK_FUNCS to track modifications easily.
-
-Fri May 10 12:01:36 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Don't link librt if clock_gettime is available in
- the main C library.
- glibc 2.17 moves clock_* from librt to the main C library.
- http://sourceware.org/ml/libc-announce/2012/msg00001.html
-
-Thu May 9 22:00:35 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/ancdata.c (bsock_sendmsg_internal): controls_num should
- not be negative.
-
-Thu May 9 21:09:57 2013 Tanaka Akira <akr@fsij.org>
-
- * file.c, ext/etc/etc.c, ext/socket/unixsocket.c,
- ext/openssl/ossl.h, ext/openssl/openssl_missing.c: Use
- HAVE_AGGREGATE_MEMBER instead of HAVE_ST_MEMBER.
-
-Thu May 9 20:43:41 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/ancdata.c (bsock_sendmsg_internal): Always set
- controls_num to raise NotImplementedError appropriately.
- (bsock_recvmsg_internal): Raise NotImplementedError if
- :scm_rights=>true is given on platforms which don't have
- 4.4BSD style control message.
-
-Thu May 9 12:06:07 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/rubysocket.h, ext/socket/unixsocket.c,
- ext/socket/ancdata.c: Use HAVE_STRUCT_MSGHDR_MSG_CONTROL instead
- of HAVE_ST_MSG_CONTROL.
-
-Thu May 9 11:30:02 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * string.c: Add call-seq alias for String#=== [Bug #8381]
-
-Thu May 9 11:14:18 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * doc/contributing.rdoc: Add guide for contributing to CRuby
-
-Thu May 9 04:55:49 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Check socket library again. shutdown() is used in
- io.c.
-
-Thu May 9 01:52:31 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Don't check socketpair. socketpair is not used in
- ruby command itself.
-
-Thu May 9 01:05:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (rb_mod_included_modules): should not include non-modules.
- [ruby-core:53158] [Bug #8025]
-
-Wed May 8 22:46:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (rb_mod_included_modules): should not include the original
- module itself. [ruby-core:53158] [Bug #8025]
-
-Wed May 8 17:43:55 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * io.c (rb_io_ext_int_to_encs): ignore internal encoding if external
- encoding is ASCII-8BIT. [Bug #8342]
-
-Wed May 8 13:49:38 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/json/generator/generator.c (isArrayOrObject): cast char to
- unsigned char. [Bug #8378]
-
-Wed May 8 13:46:10 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/json/generator/depend: fix dependencies [Bug #8379]
-
- * ext/json/parser/depend: ditto.
-
-Wed May 8 13:07:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_yylex): fail if $, @, @@ are not followed by a valid
- name character. [ruby-core:54846] [Bug #8375].
-
-Wed May 8 13:06:31 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (ISGRAPH): add missing macro.
-
-Wed May 8 06:42:56 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/socket/socket.c (socket_s_ip_address_list): fix wrongly filled
- sin6_scope_id on KAME introduced by r40593 for OpenIndiana.
- KAME uses fe80:<scope_id>::<interface id> for link-local address
- internally.
- Setting sin6_scope_id causes it leaked.
- see also comments of sockaddr_obj().
-
-Tue May 7 22:12:34 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/readline/readline.c (insert_ignore_escape): Add a cast to
- unsigned char * before dereference.
- This suppress a warning on Cygwin.
-
-Tue May 7 12:15:24 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/ancdata.c (bsock_recvmsg_internal): Add a cast to
- suppress warning.
- Bionic defines socklen_t as int.
- Bionic defines msg_controllen as unsigned int (__kernel_size_t)
- instead of socklen_t as POSIX.
-
-Tue May 7 12:12:42 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/ancdata.c (ancillary_inspect): Don't call
- anc_inspect_ipv6_pktinfo if !HAVE_TYPE_STRUCT_IN6_PKTINFO.
- anc_inspect_ipv6_pktinfo is not defined in the case.
-
-Tue May 7 12:10:52 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/socket.c (socket_s_ip_address_list): Cast EXTRA_SPACE as
- int. This suppress a warning.
-
-Tue May 7 12:09:29 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: Set close_fds false for Cygwin.
- Cygwin doesn't support fd passing.
- This enables socket extension library cross-compilable by default.
-
-Tue May 7 12:07:35 2013 Tanaka Akira <akr@fsij.org>
-
- * pack.c (swap32): Don't redefine it if it is already defined.
- Bionic defines it.
- (swap64): Ditto.
-
-Mon May 6 20:50:37 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/socket.c (socket_s_ip_address_list): Fill sin6_scope_id
- if getifaddrs() returns an IPv6 link local address which
- sin6_scope_id is zero, such as on OpenIndiana SunOS 5.11.
-
-Sun May 5 18:56:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * insns.def (defined): use vm_search_superclass() like as normal super
- call. based on a patch <https://gist.github.com/wanabe/5520026> by
- wanabe.
-
- * vm_insnhelper.c (vm_search_superclass): return error but not raise
- exceptions.
-
- * vm_insnhelper.c (vm_search_super_method): check the result of
- vm_search_superclass and raise exceptions on error.
-
-Sun May 5 16:29:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * insns.def (defined): get method entry from the method top level
- frame, not block frame. [ruby-core:54769] [Bug #8367]
-
-Sun May 5 13:28:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * template/ruby.pc.in (Cflags): use rubyarchhdrdir for multiarch.
- [Bug #7874]
-
-Sat May 4 07:20:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * doc/security.rdoc: Add note about reporting security vulns
-
-Sat May 4 04:13:27 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * include/ruby/defines.h (RUBY_ATTR_ALLOC_SIZE): New for
- attribute((alloc_size(params))).
-
- * include/ruby/defines.h (xmalloc, xmalloc2, xcalloc)
- (xrealloc, xrealloc2): Annotated by RUBY_ATTR_ALLOC_SIZE.
- * include/ruby/ruby.h (rb_alloc_tmp_buffer): ditto.
-
-Fri May 3 19:32:13 2013 Takeyuki FUJIOKA <xibbar@ruby-lang.org>
-
- * lib/cgi/util.rb: All class methods modulized.
- We can use these methods like a function when "include CGI::Util".
- [Feature #8354]
-
-Fri May 3 14:09:45 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: Make default_ipv6 true for Cygwin.
- Cygwin supports IPv6 since Cygwin 1.7.1 (2009-12).
- http://cygwin.com/ml/cygwin-announce/2009-12/msg00027.html
-
-Fri May 3 13:35:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/socket/{getaddrinfo,getnameinfo}.c: define socklen_t if not
- defined, e.g., older VC.
-
-Fri May 3 13:29:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/win32.h (INTPTR_MAX, INTPTR_MIN, UINTPTR_MAX): also
- should be defined when defining intptr_t and uintptr_t.
- bigdecimal.c requires the former two now.
-
-Fri May 3 13:22:12 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (poll_child_status): fix build error on older mingw.
-
-Fri May 3 00:15:58 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * common.mk: remove timestamps in distclean-ext realclean-ext.
-
-Thu May 2 23:23:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (rb_obj_is_kind_of): skip prepending modules.
- [ruby-core:54742] [Bug #8357]
-
- * object.c (rb_class_inherited_p): ditto.
- [ruby-core:54736] [Bug #8357]
-
-Thu May 2 22:11:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * bin/irb: remove dead code from sample/irb.rb.
-
-Thu May 2 17:32:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * marshal.c (copy_ivar_i): get rid of overwriting already copied
- instance variables. c.f. [Bug #8276]
-
-Thu May 2 16:55:43 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (id_locals): use cached ID.
-
- * vm.c (ruby_thread_init): ditto.
-
- * defs/id.def: add more predefined IDs used in core.
-
-Thu May 2 13:42:42 2013 Ryan Davis <ryand-ruby@zenspider.com>
-
- * lib/minitest/*: Imported minitest 4.7.4 (r8483)
- * test/minitest/*: ditto
-
-Thu May 2 11:32:22 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (poll_child_status): [experimental] set the cause of
- a child's death to status if its exitcode seems to be an error.
-
- * test/ruby/test_process.rb (TestProcess#test_no_curdir): maybe now
- we can test it.
-
- * test/ruby/test_thread.rb (TestThread#test_thread_timer_and_interrupt):
- ditto.
-
-Thu May 2 11:24:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/yaml.rb: nodoc EngineManager, add History doc #8344
-
-Wed May 1 21:11:17 2013 Tanaka Akira <akr@fsij.org>
-
- * time.c (localtime_with_gmtoff_zone): musl libc may return NULL for
- tm_zone.
-
-Wed May 1 18:59:36 2013 Benoit Daloze <eregontp@gmail.com>
-
- * enum.c (Enumerable#chunk): fix grammar of error message
- for symbols beginning with an underscore [Bug #8351]
-
-Wed May 1 16:47:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/curses/extconf.rb (curses_version): try once for each tests, a
- function or a variable. fallback to variable for old SVR4.
-
-Wed May 1 16:17:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb (extmake): extensions not to be installed should not
- make static libraries, but make dynamic libraries always.
-
-Wed May 1 12:20:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/rake/version.rb: Fix RDoc warning with :include: [Bug #8347]
-
-Wed May 1 11:40:25 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * defs/id.def (predefined): add "idProc".
-
- * eval.c (frame_func_id): use predefined IDs.
-
- * proc.c (mnew, mproc, mlambda): use predefined IDs.
-
- * vm.c (rb_vm_control_frame_id_and_class): ditto.
-
- * vm.c (Init_VM): ditto.
-
-Tue Apr 30 23:18:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/benchmark.rb: Update Benchmark results on newer CPU
-
-Tue Apr 30 12:31:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (mproc, mlambda): use frozen core methods instead of plain
- global methods, so that methods cannot be overridden.
- [ruby-core:54687] [Bug #8345]
-
- * vm.c (Init_VM): define proc and lambda on the frozen core object.
-
- * include/ruby/intern.h (rb_block_lambda): add declaration instead of
- deprecated rb_f_lambda.
-
-Mon Apr 29 17:02:30 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/nkf/nkf-utf8/nkf.h: Bionic libc doesn't have locale.
- [Feature #8338]
-
-
-Mon Apr 29 06:58:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/openssl/ossl_bn.c (ossl_bn_initialize): no need of alloca for
- small fixed size array.
-
- * ext/openssl/ossl_bn.c (ossl_bn_initialize): check overflow first,
- and use alloca for small size input.
-
-Mon Apr 29 00:40:13 2013 Benoit Daloze <eregontp@gmail.com>
-
- * lib/yaml.rb: Clarify documentation about YAML being always Psych.
- Give a tip about using Syck. See #8344.
-
-Sun Apr 28 23:34:01 2013 Benoit Daloze <eregontp@gmail.com>
-
- * lib/yaml.rb: Use another trick to define the YAML module.
- https://twitter.com/n0kada/status/328342207511801856
-
-Sun Apr 28 23:19:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/pp.rb: Update PP module overview by @geopet
-
-Sun Apr 28 22:04:37 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * ext/openssl/ossl_bn.c (ossl_bn_initialize): fix buffer overflow on
- x64 Windows and memory leak when initializing with integer.
- [ruby-core:54615] [Bug #8337]
-
-Sun Apr 28 12:38:04 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * README.EXT: correct method name to be used. [Bug #7982]
-
- * README.EXT.ja: add notes too.
-
-Sun Apr 28 10:35:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * object.c: With feedback from Steve Klabnik, reverted a change to
- #untrusted? and #tainted?. Also adjusted grammar for $SAFE levels
-
-Sun Apr 28 10:10:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/yaml.rb: Disable setting YAML const twice [ruby-core:54642]
-
-Sun Apr 28 09:50:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * object.c: Documentation for taint and trust [Bug #8162]
-
-Sun Apr 28 09:40:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * README.EXT: Copy note from r40505 for rb_sprintf() [Bug #7982]
-
-Sun Apr 28 08:28:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/curses/curses.c: Update Curses::Window example for nicer output
- Patch by Michal Suchanek [Bug #8121] [ruby-core:53520]
-
-Sun Apr 28 08:10:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * README.EXT: Update note from r40504, by Jeremy Evans [Bug #7982]
-
-Sun Apr 28 08:02:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * README.EXT: Add note to warn use of %i in Exceptions [Bug #7982]
-
-Sun Apr 28 02:41:05 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Fix a typo. Should check endgrent() instead of
- endgrnam().
-
-Sun Apr 28 00:35:45 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c (obj2gid): Don't call endgrent() if not exist.
- Bionic (Android's libc) don't have endgrent().
-
- * configure.in: Check endgrnam function.
-
-Sat Apr 27 23:53:00 2013 Charlie Somerville <charlie@charliesomerville.com>
-
- * lib/yaml.rb: add security warning to YAML documentation
-
-Sat Apr 27 23:25:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/yaml.rb: Documentation for YAML module [Bug #8213]
-
-Sat Apr 27 20:19:21 2013 Tanaka Akira <akr@fsij.org>
-
- * thread_pthread.c (ruby_init_stack): Add STACK_GROW_DIR_DETECTION.
- This fixes a compilation failure while cross-compiling for Tensilica
- Xtensa Processor.
-
-Sat Apr 27 19:32:44 2013 Benoit Daloze <eregontp@gmail.com>
-
- * thread.c: fix typos and documentation
-
-Sat Apr 27 19:04:55 2013 Tanaka Akira <akr@fsij.org>
-
- * sparc.c: Use __asm__ instead of asm for gcc.
- gcc doesn't provide asm keyword if -ansi option is given.
- http://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html
-
-Sat Apr 27 17:22:50 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: Redundant test removed.
-
-Sat Apr 27 16:00:10 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb (test_recvmsg_with_msg_peek_creates_fds):
- Extracted.
-
-Sat Apr 27 15:50:40 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (SIGNED_INTEGER_TYPE_P): New macro.
- (SIGNED_INTEGER_MAX): Ditto.
- (SIGNED_INTEGER_MIN): Ditto.
- (UNSIGNED_INTEGER_MAX): Ditto.
- (TIMET_MAX): Use SIGNED_INTEGER_MAX and UNSIGNED_INTEGER_MAX.
- (TIMET_MIN): Use SIGNED_INTEGER_MIN.
-
- * thread.c (TIMEVAL_SEC_MAX): Use SIGNED_INTEGER_MAX.
- (TIMEVAL_SEC_MIN): Use SIGNED_INTEGER_MIN.
-
-Sat Apr 27 10:52:52 2013 Tanaka Akira <akr@fsij.org>
-
- * thread.c (TIMEVAL_SEC_MAX, TIMEVAL_SEC_MIN): Consider environments,
- sizeof(time_t) is smaller than sizeof(tv_sec), such as
- OpenBSD 5.2 (amd64).
-
-Fri Apr 26 23:34:59 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/text.rb (REXML::Text.normalize): Fix a bug that all
- entity filters are ignored. [ruby-dev:47278] [Bug #8302]
- Patch by Ippei Obayashi. Thanks!!!
- * test/rexml/test_entity.rb (EntityTester#test_entity_filter): Add
- a test of the above change.
-
-Fri Apr 26 22:53:55 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/element.rb (REXML::Attributes#to_a): Support
- namespaced attributes. [ruby-dev:47277] [Bug #8301]
- Patch by Ippei Obayashi. Thanks!!!
- * test/rexml/test_attributes.rb
- (AttributesTester#test_to_a_with_namespaces): Add a test of the
- above change.
-
-Fri Apr 26 21:48:29 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rss/atom.rb (RSS::Atom::Entry): Fix indent of document comment.
-
-Fri Apr 26 21:21:17 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rss/maker.rb (RSS::Maker): Fix indent of document comment.
-
-Fri Apr 26 18:41:04 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: Use a block of enable_config() for
- --{enable,disable}-close-fds-by-recvmsg-with-peek configure option
-
-Fri Apr 26 18:08:08 2013 Tanaka Akira <akr@fsij.org>
-
- * dir.c (dir_set_pos): Fix a compilation error when seekdir() is not
- exist.
-
-Fri Apr 26 17:41:17 2013 Tanaka Akira <akr@fsij.org>
-
- * thread_pthread.c (ruby_init_stack): Add STACK_GROW_DIR_DETECTION.
- This fixes a compilation failure while cross-compiling for ARM.
-
-Fri Apr 26 14:35:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/rss/atom.rb: Documentation for RSS::Atom based on a patch by
- Michael Denomy
- * lib/rss/maker.rb: Documentation for RSS::Maker also by @mdenomy
-
-Fri Apr 26 12:41:22 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/curses/extconf.rb: Test linkability of curses_version at first.
-
- * ext/socket/extconf.rb: Test the behavior of fd passing with MSG_PEEK
- only if recvmsg(), msg_control member, AF_UNIX and SCM_RIGHTS are
- available.
-
-Fri Apr 26 00:07:52 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * lib/rinda/ring.rb (Rinda::RingServer#initialize): accept array
- arguments of address to specify multicast interface.
-
- * lib/rinda/ring.rb (Rinda::RingServer#make_socket): add optional
- arguments for multicast interface.
-
- * test/rinda/test_rinda.rb
- (TestRingFinger#test_ring_server_ipv4_multicast,
- TestRingFinger#test_ring_server_ipv6_multicast): add tests for
- above change.
-
- * test/rinda/test_rinda.rb
- (TestRingServer#test_make_socket_ipv4_multicast,
- TestRingServer#test_make_socket_ipv6_multicast): change bound
- interface address because multicast address is not allowed on Linux
- or Windows.
- [ruby-core:53692] [Bug #8159]
-
-Thu Apr 25 23:45:02 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * lib/rinda/ring.rb (Rinda::RingServer#initialize): add a socket
- to @sockets in make_socket() to close sockets on shutdown even if
- make_socket() is called after initialize.
-
- * lib/rinda/ring.rb (Rinda::RingServer#make_socket): ditto.
-
-Thu Apr 25 23:39:42 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * test/rinda/test_rinda.rb (TupleSpaceProxyTest#test_take_bug_8215):
- use KILL on Windows since TERM doen't work and ruby process remains
- after test-all on Windows.
-
-Thu Apr 25 23:16:28 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/curses/extconf.rb: Implement
- --with-curses-version={function,variable} configure option for
- cross-compiling.
-
-Thu Apr 25 18:15:46 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: Don't use WIDE getaddrinfo by default.
-
-Thu Apr 25 17:56:39 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: Remove obsolete options: ---with-ipv6-lib and
- --with-ipv6-libdir.
-
-Thu Apr 25 17:43:49 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: Implement
- --{enable,disable}-close-fds-by-recvmsg-with-peek configure option
- for cross-compiling.
- Make --{enable,disable}-wide-getaddrinfo configure option
- cross-compiling friendly.
-
-Thu Apr 25 16:11:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (rb_io_ext_int_to_encs, parse_mode_enc): bom-prefixed name is
- not a real encoding name, just a fallback. so the proper conversion
- should take place even if if the internal encoding is equal to the
- bom-prefixed name, unless actual encoding is equal to the internal
- encoding. [ruby-core:54563] [Bug #8323]
-
- * io.c (io_set_encoding_by_bom): reset extenal encoding if no BOM
- found. [ruby-core:54569]
-
-Thu Apr 25 14:35:01 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/openssl/ossl_bn.c (ossl_bn_initialize): allow Fixnum and Bignum.
- [ruby-core:53986] [Feature #8217]
-
-Thu Apr 25 14:26:32 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/common.rb (URI.decode_www_form): follow current URL Standard.
- It gets encoding argument to specify the character encoding.
- It now allows loose percent encoded strings, but denies ;-separator.
- [ruby-core:53475] [Bug #8103]
-
- * lib/uri/common.rb (URI.decode_www_form): follow current URL Standard.
- It gets encoding argument to convert before percent encode.
- Now UTF-16 strings aren't converted to UTF-8 before percent encode
- by default.
-
-Wed Apr 25 14:26:00 2013 Charlie Somerville <charlie@charliesomerville.com>
-
- * benchmark/bm_hash_shift.rb: add benchmark for Hash#shift
-
- * hash.c (rb_hash_shift): use st_shift if hash is not being iterated to
- delete element without iterating the whole hash.
-
- * hash.c (shift_i): remove function
-
- * include/ruby/st.h (st_shift): add st_shift function
-
- * st.c (st_shift): ditto
-
- [Bug #8312] [ruby-core:54524] Patch by funny-falcon
-
-Thu Apr 25 12:03:38 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: Extract C programs as toplevel constants.
-
-Thu Apr 25 02:23:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (RUBY_RM_RECURSIVE): this hack is needed by only
- autoconf 2.69 or earlier on darwin.
-
-Thu Apr 25 01:22:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/tracer.rb (get_line): simply read by File.readlines.
-
- * lib/debug.rb (script_lines): get source lines from SCRIPT_LINES__ or
- read from the file.
-
- * lib/debug.rb (display_list): use script_lines instead of recursion.
- [Bug #8318]
-
- * lib/debug.rb (line_at): use script_lines same as display_list.
-
- * lib/debug.rb (display_list): Fix debug listing when called from the
- same file it has been required. patch by Dario Bertini <berdario AT
- gmail.com> [Bug #8318] [fix GH-280]
-
-Wed Apr 24 21:51:13 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Check mblen().
- mblen() is optional in uClibc.
-
- * eval_intern.h (CharNext): Don't use mblen() is not available.
-
-Wed Apr 24 15:55:06 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * io.c (rb_fd_fix_cloexec): use rb_update_max_fd().
-
-Wed Apr 24 14:08:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * numeric.c: Fix wiki link on Float imprecision in overview, patched
- by Makoto Kishimoto [Bug #8304] [ruby-dev:47280]
-
-Wed Apr 24 14:03:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_yylex): disallow $- without following identifier
- character. [ruby-talk:406969]
-
- * parse.y (is_special_global_name): mere $- is not a valid global
- variable name.
-
-Wed Apr 24 13:54:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * string.c: Document String#setbyte return value by @gjmurakami-10gen
- [Fixes GH-294]
-
-Wed Apr 24 13:45:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * class.c: Example of Object#methods by @windwiny [Fixes GH-293]
- * ruby.c: Document return values of Kernel #sub, #gsub, and #chop
-
-Wed Apr 24 12:54:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/socket/lib/socket.rb: Doc typos by @vipulnsward [Fixes GH-292]
-
-
-Wed Apr 24 12:54:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/socket/lib/socket.rb: Doc typos by @vipulnsward [Fixes GH-292]
-
-Wed Apr 24 12:27:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * array.c: Fix documentation for Array#index and #replace aliases
- Based on a patch by @phiggins [Fixes GH-282]
-
-Tue Apr 23 21:14:38 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (rb_str_inspect): refix r40413, on Ruby 1.9 usual character
- escape uses hex/Unicode escapes, so fix to use Unicode escape on
- Unicode strings and hex on others. [ruby-core:54458] [Bug #8290]
-
-Tue Apr 23 20:10:02 2013 Tanaka Akira <akr@fsij.org>
-
- * missing/isnan.c (isnan): Don't define if isnan() macro is defined.
- This fixes a compilation failure on uClibc based Gentoo system.
-
-Tue Apr 23 17:40:40 2013 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/rexml/document.rb, lib/rexml/element.rb,
- lib/rexml/formatters/pretty.rb: remove opinionated
- language in documentation. [Bug #8309],
- reported by Charles Beckmann
-
-Tue Apr 23 14:04:44 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * lib/net/imap.rb (getacl_response): parse the mailbox of an ACL
- response correctly. [ruby-core:54365] [Bug #8281]
-
-Tue Apr 23 11:58:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_scrub): fix for UTF-32. strlen() on strings
- contain NUL returns wrong result, use sizeof operator instead.
- [ruby-dev:45975] [Feature #6752]
-
-Tue Apr 23 10:26:50 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * test/ruby/test_module.rb
- (TestModule#test_const_get_invalid_name)
- (test_const_defined_invalid_name): Fix expected values.
-
-Tue Apr 23 09:51:26 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * string.c (rb_str_inspect): NUL should not be represented as "\0"
- when octal digits may follow. [ruby-core:54458] [Bug #8290]
-
-Mon Apr 22 22:54:00 2013 Charlie Somerville <charlie@charliesomerville.com>
-
- * insns.def (opt_mod): Use % operator if both operands are positive for
- a significant performance improvement. Thanks to @samsaffron.
-
-Mon Apr 22 17:09:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * marshal.c (r_object0): copy all instance variables not only generic
- ivars, before calling post proc. [ruby-core:51163] [Bug #7627]
-
-Mon Apr 22 10:25:21 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * util.c (ruby_hdtoa): revert r29729.
- If you want ruby to behave as before on x86, specify to use SSE like
- -msse2 -mfpmath=sse for gcc.
-
-Sun Apr 21 23:19:00 2013 Charlie Somerville <charlie@charliesomerville.com>
-
- * configure.in: Revert using sigsetjmp by default due to performance
- problems on some systems (eg. older Linux)
-
-Sun Apr 21 21:35:00 2013 Charlie Somerville <charlie@charliesomerville.com>
-
- * configure.in: Use sigsetjmp by default so jumping out of signal
- handlers properly restores the signal mask and SS_ONSTACK flag.
- [ruby-core:54175] [Bug #8254]
-
- * configure.in: Manually check for presence of sigsetjmp. It is not a
- function on some systems, so AC_CHECK_FUNCS cannot be used.
-
-Sun Apr 21 08:00:55 2013 Tanaka Akira <akr@fsij.org>
-
- * test/csv/test_features.rb, test/logger/test_logger.rb
- test/mkmf/test_have_macro.rb, test/net/http/test_http.rb,
- test/openssl/test_config.rb, test/psych/test_encoding.rb,
- test/psych/test_exception.rb, test/psych/test_psych.rb,
- test/psych/test_tainted.rb, test/readline/test_readline.rb,
- test/rexml/test_contrib.rb, test/ruby/test_autoload.rb,
- test/ruby/test_beginendblock.rb, test/ruby/test_exception.rb,
- test/ruby/test_file.rb, test/ruby/test_io.rb,
- test/ruby/test_marshal.rb, test/ruby/test_process.rb,
- test/ruby/test_require.rb, test/ruby/test_rubyoptions.rb,
- test/syslog/test_syslog_logger.rb, test/webrick/test_httpauth.rb,
- test/zlib/test_zlib.rb: Use Tempfile.create.
-
-Sun Apr 21 00:15:36 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/tempfile.rb (Tempfile.create): Close when the block exits.
-
-Sat Apr 20 23:38:14 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/webrick/httpauth/htpasswd.rb: Use Tempfile.create to avoid
- unintentional unlink() by the finalizer.
- lib/webrick/httpauth/htdigest.rb: Ditto.
-
-Sat Apr 20 22:47:48 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/tempfile.rb (Tempfile.create): New method.
- The method name is proposed by Shugo Maeda. [ruby-dev:47220]
- [ruby-core:41478] [Feature #5707]
-
-Sat Apr 20 14:22:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * marshal.c (w_object): dump no ivars to the original by marshal_dump.
- [ruby-core:54334] [Bug #8276]
-
- * marshal.c (r_object0): copy all ivars of marshal_dump data to the
- result object instead. [ruby-core:51163] [Bug #7627]
-
-Sat Apr 20 02:33:27 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (str_scrub): add ruby method String#scrub which verify and
- fix invalid byte sequence. [ruby-dev:45975] [Feature #6752]
-
- * string.c (str_compat_and_valid): check given string is compatible
- and valid with given encoding.
-
- * transcode.c (str_transcode0): If invalid: :replace is specified for
- String#encode, replace invalid byte sequence even if the destination
- encoding equals to the source encoding.
-
-Fri Apr 19 21:55:40 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * README.EXT.ja (Data_Wrap_Struct): Remove a description about
- orphan argument. Oh, I renamed the argument name without
- changing description at r36180... Sorry....
- Patch by Makoto Kishimoto. Thanks!!! [ruby-dev:47269] [Bug #8292]
- * README.EXT.ja (Data_Make_Struct): Add a sample code that describes
- how it works.
- Patch by Makoto Kishimoto. Thanks!!! [ruby-dev:47269] [Bug #8292]
-
-Fri Apr 19 17:54:57 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * lib/net/imap.rb (body_type_msg): should accept
- message/delivery-status with extra data.
- [ruby-core:53741] [Bug #8167]
-
- * test/net/imap/test_imap_response_parser.rb: related test.
-
-Fri Apr 19 13:03:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * marshal.c (w_object): do not dump encoding which is dumped with
- marshal_dump data. [ruby-core:54334] [Bug #8276]
-
-Fri Apr 19 11:36:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (stack_protector): control use of -fstack-protector.
-
- * configure.in (debugflags): let -fstack-protector precede and disable
- debugflags, because they can't work together on SmartOS. [Bug #8268]
-
-Fri Apr 19 07:43:52 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * test/openssl/test_cipher.rb: Correct a typo
- by jgls <joerg@joergleis.com>
- https://github.com/ruby/ruby/pull/291 fix GH-291
-
-Thu Apr 18 16:58:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_method.c (rb_mod_public_method): fix visibility on anonymous
- module. set visibility of singleton method, not method in base
- class. [ruby-core:54404] [Bug #8284]
-
-Thu Apr 18 16:20:51 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (glob_helper): should skip dot directories only for recursion,
- but should not if matching to the given pattern. [ruby-core:54387]
- [Bug #8283]
-
-Thu Apr 18 16:20:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * pack.c (pack_unpack): increase buffer size to fix buffer overflow,
- and fix garbage just after unpacking without missing paddings.
- [Bug #8286]
-
-Thu Apr 18 13:35:54 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * pack.c (pack_unpack): output characters even if the input doesn't
- have paddings. [Bug #8286]
-
-Thu Apr 18 08:20:48 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * common.mk (clean-ext): remove timestamps.
-
-Wed Apr 17 22:07:50 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/rubysocket.h (SOCKLEN_MAX): Expression simplified.
-
-Wed Apr 17 20:09:19 2013 Aman Gupta <ruby@tmm1.net>
-
- * compile.c (iseq_add_mark_object): Use new rb_iseq_add_mark_object().
-
- * insns.def (setinlinecache): Ditto.
-
- * iseq.c (rb_iseq_add_mark_object): New function to allocate
- iseq->mark_ary on demand. [Bug #8142]
-
- * iseq.h (rb_iseq_add_mark_object): Ditto.
-
- * iseq.c (prepare_iseq_build): Avoid allocating mark_ary until needed.
-
- * iseq.c (rb_iseq_build_for_ruby2cext): Ditto.
-
-Wed Apr 17 20:00:18 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/rubysocket.h (SOCKLEN_MAX): Defined.
-
- * ext/socket/raddrinfo.c (ext/socket/raddrinfo.c): Reject too long
- Linux abstract socket name.
-
-Wed Apr 17 19:45:27 2013 Aman Gupta <tmm1@ruby-lang.org>
-
- * iseq.c (iseq_location_setup): re-use existing string when iseq has
- the same path and absolute_path. [Bug #8149]
-
-Wed Apr 17 11:38:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/test/unit/assertions.rb (Test::Unit::Assertions#assert):
- UNASSIGNED is not a valid message.
-
-Wed Apr 17 10:58:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (sleep_timeval): get rid of overflow on Windows where
- timeval.tv_sec is not time_t but mere long.
-
-Tue Apr 16 23:07:12 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/unixsocket.c (unix_send_io): Suppress a warning by clang.
- (unix_recv_io): Ditto.
-
-Tue Apr 16 12:27:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/sdbm/init.c: Fix comment indentation, by windwiny [Fixes GH-277]
-
-Tue Apr 16 12:25:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/socket/option.c: Document synonymous methods, by windwiny [GH-277]
- * ext/stringio/stringio.c: ditto
- * ext/io/wait/wait.c: ditto
- * ext/gdbm/gdbm.c: ditto
- * ext/dl/cfunc.c: ditto
- * ext/zlib/zlib.c: ditto
- * ext/win32ole/win32ole.c: ditto
- * ext/dbm/dbm.c: ditto
- * ext/json/generator/generator.c: ditto
- * ext/date/date_core.c: ditto
-
-Tue Apr 16 11:23:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/openssl/*: Document synonymous methods, by windwiny [GH-277]
-
-Mon Apr 15 22:21:42 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/fiddle/depend: New file.
-
-Mon Apr 15 22:01:02 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-electric.el (ruby-electric-insert): Check
- ruby-electric-is-last-command-char-expandable-punct-p here.
-
- * misc/ruby-electric.el (ruby-electric-closing-char): New
- interactive function bound to closing characters. Typing one of
- those closing characters right after the matching counterpart
- cancels the effect of automatic closing. For example, typing
- "{" followed by "}" simply makes "{}" instead of "{ } }".
-
-Mon Apr 15 12:54:42 2013 Martin Bosslet <Martin.Bosslet@gmail.com>
-
- * ext/openssl/ossl_ssl.c: Correct shutdown behavior w.r.t GC.
-
- * test/openssl/test_ssl.rb: Add tests to verify correct behavior.
-
- [Bug #8240] Patch provided by Shugo Maeda. Thanks!
-
-Mon Apr 15 10:23:39 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/coverage/depend: fix id.h place as r40283.
-
- * ext/coverage/extconf.rb: add topdir and topsrcdir to VPATH.
-
-Sun Apr 14 19:46:14 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/-test-/debug/depend: New file.
-
- * ext/-test-/exception/depend: Ditto.
-
- * ext/-test-/printf/depend: Ditto.
-
- * ext/-test-/string/depend: Ditto.
-
- * ext/coverage/depend: Ditto.
-
- * ext/io/console/depend: Ditto.
-
- * ext/io/nonblock/depend: Ditto.
-
- * ext/io/wait/depend: Ditto.
-
- * ext/openssl/depend: Ditto.
-
- * ext/pathname/depend: Ditto.
-
- * ext/psych/depend: Ditto.
-
- * ext/zlib/depend: Ditto.
-
-Sun Apr 14 02:46:50 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/mkmf.rb (MakeMakefile#create_makefile): remove {$(VPATH)} other
- than nmake.
-
- * ext/ripper/depend: use VPATH expecting removed by above.
-
-Sat Apr 13 23:06:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (timestamp_file): gather timestamp files in one
- directory from each extension directories.
-
-Sat Apr 13 21:09:02 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * lib/mkmf.rb (MakeMakefile#create_makefile): output new macro
- disthdrdir to specify the path of id.h, parse.h and etc.
-
- * ext/ripper/depend: use above macro.
-
-Sat Apr 13 20:28:08 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * Merge Onigmo 5.13.4 f22cf2e566712cace60d17f84d63119d7c5764ee.
- [bug] fix problem with optimization of \z (Issue #16) [Bug #8210]
-
-Sat Apr 13 18:56:15 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/ripper/depend: parse.h and id.h may be created on topdir.
-
-Sat Apr 13 12:08:16 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Add Vector#cross_product, patch by Luis Ezcurdia
- [fix GH-276] [rubyspec:81eec89a124]
-
-Sat Apr 13 10:20:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * struct.c (rb_struct_define_without_accessor, rb_struct_define),
- (rb_struct_s_def): hide member names array.
-
- * struct.c (anonymous_struct, new_struct, setup_struct): split
- make_struct() for each purpose.
-
-Sat Apr 13 09:34:31 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/mkmf.rb: Add ruby/ruby.h, ruby/missing.h, ruby/intern.h,
- ruby/st.h and ruby/subst.h for ruby_headers in generated Makefile.
-
- * ext/-test-/old_thread_select/depend: Update dependencies.
-
- * ext/-test-/wait_for_single_fd/depend: Ditto.
-
- * ext/bigdecimal/depend: Ditto.
-
- * ext/curses/depend: Ditto.
-
- * ext/digest/bubblebabble/depend: Ditto.
-
- * ext/digest/depend: Ditto.
-
- * ext/digest/md5/depend: Ditto.
-
- * ext/digest/rmd160/depend: Ditto.
-
- * ext/digest/sha1/depend: Ditto.
-
- * ext/digest/sha2/depend: Ditto.
-
- * ext/dl/callback/depend: Ditto.
-
- * ext/dl/depend: Ditto.
-
- * ext/etc/depend: Ditto.
-
- * ext/nkf/depend: Ditto.
-
- * ext/objspace/depend: Ditto.
-
- * ext/pty/depend: Ditto.
-
- * ext/readline/depend: Ditto.
-
- * ext/ripper/depend: Ditto.
-
- * ext/sdbm/depend: Ditto.
-
- * ext/socket/depend: Ditto.
-
- * ext/stringio/depend: Ditto.
-
- * ext/strscan/depend: Ditto.
-
- * ext/syslog/depend: Ditto.
-
- * ext/-test-/num2int/depend: Removed.
-
- * ext/dbm/depend: Ditto.
-
- * ext/fcntl/depend: Ditto.
-
- * ext/gdbm/depend: Ditto.
-
- * ext/racc/cparse/depend: Ditto.
-
-Sat Apr 13 00:15:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/etc/etc.c (Init_etc): move Passwd and Group under Etc namespace
- as primary names.
-
-Fri Apr 12 21:06:55 2013 Tanaka Akira <akr@fsij.org>
-
- * common.mk: pack.o depends on internal.h.
-
-Fri Apr 12 20:59:24 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (ones): Use __builtin_popcountl if available.
-
- * internal.h (GCC_VERSION_SINCE): Macro moved from pack.c.
-
- * pack.c: Include internal.h for GCC_VERSION_SINCE.
-
-Fri Apr 12 18:29:42 2013 Tanaka Akira <akr@fsij.org>
-
- * common.mk: version.o depends on $(srcdir)/include/ruby/version.h
- instead of {$(VPATH)}version.h to avoid confusion by VPATH between
- top level version.h and include/ruby/version.h for build in-place.
- [ruby-dev:47249] [Bug #8256]
-
-Fri Apr 12 15:21:24 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_callee_setup_keyword_arg): non-symbol key is not
- a keyword argument, keep it as a positional argument.
-
-Fri Apr 12 11:58:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * array.c: Document synonymous methods, by windwiny [GH-277]
- * bignum.c: ditto
- * complex.c: ditto
- * dir.c: ditto
- * encoding.c: ditto
- * enumerator.c: ditto
- * numeric.c: ditto
- * proc.c: ditto
- * re.c: ditto
- * string.c: ditto
-
-Thu Apr 11 23:41:46 2013 Tanaka Akira <akr@fsij.org>
-
- * common.mk: Add dependencies for include/ruby.h
-
- * tool/update-deps: Use "make -p all miniruby ruby golf" to extract
- dependencies in makefiles.
-
-Thu Apr 11 23:21:17 2013 Tanaka Akira <akr@fsij.org>
-
- * tool/update-deps: Use "make -p all golf" to extract dependencies in
- makefiles.
-
-Thu Apr 11 21:02:19 2013 Tanaka Akira <akr@fsij.org>
-
- * common.mk: Dependency updated.
-
- * tool/update-deps: Rewritten.
-
-Thu Apr 11 19:59:48 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * common.mk: partially revert r40183, which breaks building on
- other than source directory. (its commit log also says the same
- thing, but such failure is not reproducible on my environment
- and the commit breaks build on my environment)
-
-Thu Apr 11 16:10:01 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/fiddle/closure.c (USE_FFI_CLOSURE_ALLOC): define 0 on
- Mac OS X and Linux [Bug #3371]
-
-Thu Apr 11 13:19:22 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/drb/drbtest.rb (Drb{Core,Ary}#teardown): retry Process.kill
- if it fails with Errno::EPERM on Windows (workaround).
- [ruby-dev:47245] [Bug #8251]
-
-Thu Apr 11 11:11:38 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * dir.c: Fix a typo.
-
-Thu Apr 11 10:39:34 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/fiddle/closure.c (USE_FFI_CLOSURE_ALLOC): add missing case:
- RUBY_LIBFFI_MODVERSION is not defined (usually on Windows).
-
-Thu Apr 11 09:27:04 2013 Konstantin Haase <me@rkh.im>
-
- * dir.c (file_s_fnmatch): Document File::FNM_EXTGLOB flag.
-
-Thu Apr 11 09:17:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * README: Fix typo by Benjamin Winkler [Fixes GH-281]
-
-Thu Apr 11 06:15:51 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * regint.h: fix typo: _M_AMD86 -> _M_AMD64.
-
- * siphash.c: ditto.
-
- * st.c: ditto.
-
-Thu Apr 11 06:09:57 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/fiddle/extconf.rb: define RUBY_LIBFFI_MODVERSION macro.
-
- * ext/fiddle/closure.c (USE_FFI_CLOSURE_ALLOC): define 0 or 1
- with platform and libffi's version. [Bug #3371]
-
-Thu Apr 11 05:30:43 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/mkmf.rb (pkg_config): Add optional argument "option".
- If it is given, it returns the result of
- `pkg-config --<option> <pkgname>`.
-
-Thu Apr 11 03:33:05 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/fiddle/closure.c (initialize): check mprotect's return value.
- If mprotect is failed because of PaX or something, its function call
- will cause SEGV.
- http://c5664.rubyci.org/~chkbuild/ruby-trunk/log/20130401T210301Z.diff.html.gz
-
-Wed Apr 10 17:39:13 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/bigdecimal/bigdecimal.c (VpCtoV): Initialize a local variable
- even when overflow.
-
-Wed Apr 10 12:32:37 2013 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_ll2big): Don't overflow on signed integer negation.
-
- * ext/bigdecimal/bigdecimal.c (MUL_OVERFLOW_SIGNED_VALUE_P): New
- macro.
- (AddExponent): Don't overflow on signed integer multiplication.
- (VpCtoV): Don't overflow on signed integer arithmetic.
- (VpCtoV): Don't overflow on signed integer arithmetic.
-
-Wed Apr 10 06:32:12 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (MUL_OVERFLOW_INT_P): New macro.
-
- * sprintf.c (GETNUM): Don't overflow on signed integer multiplication.
-
-Tue Apr 9 20:38:20 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (MUL_OVERFLOW_SIGNED_INTEGER_P): New macro.
- (MUL_OVERFLOW_FIXNUM_P): Ditto.
- (MUL_OVERFLOW_LONG_P): Ditto.
-
- * array.c (rb_ary_product): Don't overflow on signed integer
- multiplication.
-
- * numeric.c (fix_mul): Ditto.
- (int_pow): Ditto.
-
- * rational.c (f_imul): Ditto.
-
- * insns.def (opt_mult): Ditto.
-
- * thread.c (sleep_timeval): Don't overflow on signed integer addition.
-
- * bignum.c (rb_int2big): Don't overflow on signed integer negation.
- (rb_big2ulong): Ditto.
- (rb_big2long): Ditto.
- (rb_big2ull): Ditto.
- (rb_big2ll): Ditto.
-
-Tue Apr 9 19:45:44 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/open-uri.rb: Support multiple fields with same field
- name (like Set-Cookie).
- (OpenURI::Meta#metas): New accessor to obtain fields as a Hash from
- field name (string) to field values (array of strings).
- [ruby-core:37734] [Bug #4964] reported by ren li.
-
-Tue Apr 9 15:26:12 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_compile_each): append keyword hash to argument array
- to splat if needed. [ruby-core:54094] [Bug #8236]
-
-Tue Apr 9 10:02:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (timestamp_file): gather timestamp files in one
- directory from each extension directories, with considering
- target_prefix.
-
-Tue Apr 9 04:57:59 JST 2013 Charles Oliver Nutter <headius@headius.com>
-
- * error.c: Capture EAGAIN, EWOULDBLOCK, EINPROGRESS exceptions and
- export them for use in WaitReadable/Writable exceptions.
- * io.c: Create versions of EAGAIN, EWOULDBLOCK, EINPROGRESS that
- include WaitReadable and WaitWritable. Add rb_readwrite_sys_fail
- for nonblocking failures using those exceptions. Use that
- function in io_getpartial and io_write_nonblock instead of
- rb_mod_sys_fail
- * ext/openssl/ossl_ssl.c: Add new SSLError subclasses that include
- WaitReadable and WaitWritable. Use those classes for
- write_would_block and read_would_block instead of rb_mod_sys_fail.
- * ext/socket/ancdata.c: Use rb_readwrite_sys_fail instead of
- rb_mod_sys_fail in bsock_sendmsg_internal and
- bsock_recvmsg_internal.
- * ext/socket/init.c: Use rb_readwrite_sys_fail instead of
- rb_mod_sys_fail in rsock_s_recvfrom_nonblock and
- rsock_s_connect_nonblock.
- * ext/socket/socket.c: Use rb_readwrite_sys_fail instead of
- rb_mod_sys_fail in sock_connect_nonblock.
- * include/ruby/ruby.h: Export rb_readwrite_sys_fail for use instead
- of rb_mod_sys_fail. Introduce new constants RB_IO_WAIT_READABLE and
- RB_IO_WAIT_WRITABLE for first arg to rb_readwrite_sys_fail.
-
-Tue Apr 9 02:44:32 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/socket/extconf.rb: $defs needs -D or -U. nothing is added
- otherwize.
-
- * ext/socket/extconf.rb: check struct in_addr6, which is defined in
- VC6 instead of in6_addr.
-
- * ext/socket/option.c (optname_to_sym): fix macro name.
-
- * ext/socket/constants.c (rsock_cmsg_type_arg): fix macro name.
-
-Mon Apr 8 23:57:21 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (id_for_setter): extract common code from const, class
- variable, instance variable setters.
-
-Mon Apr 8 23:55:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/depend (ENCOBJS, TRANSOBJS): use explicit path to ruby.h for
- nmake.
-
- * ext/depend (ENCOBJS, TRANSOBJS): fix header dependency, VPATH has
- $(srcdir)/include/ruby but not $(srcdir)/include, so cannot find out
- ruby/ruby.h. use ruby.h instead and ../ruby for include/ruby.h.
-
-Mon Apr 8 20:30:37 2013 Yuki Yugui Sonoda <yugui@google.com>
-
- * ext/depend (ENCOBJS, TRANSOBJS): Add missing dependencies.
-
-Mon Apr 8 17:19:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32ole/win32ole.c (fole_missing): should check actual argument
- count before accessing.
-
-Mon Apr 8 16:03:55 2013 Yuki Yugui Sonoda <yugui@google.com>
-
- Fixes a build failure of ext/ripper/ripper.c on building out of place.
- * common.mk (id.h, id.c): Always generated in $(srcdir).
- (ext/ripper/ripper.c): Passes $(PATH_SEPARATOR) too to the sub make.
-
-Mon Apr 8 12:05:02 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * object.c (rb_obj_ivar_set): call to_str for string only once.
- to_str was called from rb_is_const_name and rb_to_id before.
-
- * object.c (rb_mod_const_set): ditto.
-
- * object.c (rb_mod_cvar_set): ditto.
-
-Sun Apr 7 13:56:16 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * test/ruby/test_require.rb (TestRequire#test_require_nonascii_path):
- RUBY_PLATFORM should escape as Regexp,
- because RUBY_PLATFORM may contain '.'.
-
-Sun Apr 7 10:44:01 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/defines.h: Simplify the logic to include sys/select.h.
- This fixes a compilation error on Haiku (gcc2 and gcc4).
-
- * configure.in: Use shared linker as $(CC) for Haiku.
- This fixes a build error on Haiku (gcc2).
-
-Sun Apr 7 10:41:30 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb (MDNSOneShot#sender): Delete an unused variable.
-
-Sun Apr 7 03:24:36 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c: use more generic type:
- * u_char -> unsigned char
- * u_short -> unsigned short
- * u_int -> unsigned int
- * u_long -> unsigned long
- * quad_t -> int64_t
- * u_quad_t -> uint64_t
-
- * addr2line.c (imax): inline is defined by configure.
-
-Sun Apr 7 01:40:39 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-electric.el (ruby-electric-hash): New electric
- function that expands a hash sign inside a string or regexp to
- "#{}".
-
- * misc/ruby-electric.el (ruby-electric-curlies): Do not insert
- spaces inside when the curly brace is a delimiter of %r, %w,
- etc.
-
- * misc/ruby-electric.el (ruby-electric-curlies): Insert another
- space before a closing curly brace when
- ruby-electric-newline-before-closing-bracket is nil.
-
-Sun Apr 7 01:01:26 2013 Tanaka Akira <akr@fsij.org>
-
- * strftime.c (rb_strftime_with_timespec): Test yday range.
- [ruby-core:44088] [Bug #6247] reported by Ruby Submit.
-
-Sat Apr 6 23:46:54 2013 Naohisa Goto <ngotogenome@gmail.com>
-
- * configure.in (AC_CHECK_HEADERS): atomic.h for Solaris atomic_ops.
-
- * ruby_atomic.h: Skip using Solaris10 atomic_ops on Solaris 9 or
- earlier if atomic.h is not available. [ruby-dev:47229] [Bug #8228]
-
-Sat Apr 6 23:40:40 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb: Support LOC resources.
- [ruby-core:23361] [Feature #1436] by JB Smith.
-
-Sat Apr 6 23:38:09 2013 Naohisa Goto <ngotogenome@gmail.com>
-
- * addr2line.c: quad_t and u_quad_t is not available on Solaris.
- __inline is not available with old compilers on Solaris.
- [ruby-dev:47229] [Bug #8227]
-
-Sat Apr 6 23:31:38 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb: Add one-shot multicast DNS support.
- [ruby-core:53387] [Feature #8089] by Eric Hodel.
-
-Sat Apr 6 22:12:01 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb (Resolv::DNS.fetch_resource): New method to obtain
- full result.
- [ruby-dev:43587] [Feature #4788] proposed by Makoto Kishimoto.
-
-Sat Apr 6 20:17:51 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/socket.c (rsock_sys_fail_raddrinfo): Renamed from
- rsock_sys_fail_addrinfo.
- (rsock_sys_fail_raddrinfo_or_sockaddr): Renamed from
- rsock_sys_fail_addrinfo_or_sockaddr.
-
- * ext/socket/rubysocket.h: Follow the above change.
-
-Sat Apr 6 19:24:59 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/socket.c (rsock_sys_fail_sockaddr): Takes struct sockaddr
- and socklen_t instead of String object.
- (rsock_sys_fail_addrinfo_or_sockaddr): Follow the above change.
-
- * ext/socket/rubysocket.h (rsock_sys_fail_sockaddr): Follow the above
- change.
-
-Sat Apr 6 14:28:23 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/rubysocket.h (SockAddrStringValueWithAddrinfo): New macro.
- (rsock_sockaddr_string_value_with_addrinfo): New declaration.
- (rsock_addrinfo_inspect_sockaddr): Ditto.
- (rsock_sys_fail_addrinfo): Ditto.
- (rsock_sys_fail_sockaddr_or_addrinfo): Ditto.
-
- * ext/socket/raddrinfo.c (rsock_addrinfo_inspect_sockaddr): Renamed
- from addrinfo_inspect_sockaddr and exported.
- (rsock_sockaddr_string_value_with_addrinfo): New function to obtain
- string and possibly addrinfo object.
-
- * ext/socket/socket.c (rsock_sys_fail_sockaddr): Don't use
- rsock_sys_fail_host_port which is IP dependent. Invoke
- rsock_sys_fail_addrinfo.
- (rsock_sys_fail_addrinfo): New function using
- rsock_addrinfo_inspect_sockaddr.
- (rsock_sys_fail_addrinfo_or_sockaddr): New function.
- (sock_connect): Use SockAddrStringValueWithAddrinfo and
- rsock_sys_fail_addrinfo_or_sockaddr.
- (sock_connect_nonblock): Ditto.
- (sock_bind): Ditto.
-
-Sat Apr 6 13:34:20 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/socket.c (rsock_sys_fail_sockaddr): Delete 2nd argument.
-
- * ext/socket/rubysocket.h (rsock_sys_fail_sockaddr): Follow above
- change.
-
-Sat Apr 6 13:13:39 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/socket.c (rsock_sys_fail_path): Use rb_str_inspect only
- for String to avoid SEGV.
-
-Sat Apr 6 12:40:16 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/rubysocket.h (rsock_sys_fail_host_port): Wrap by NORETURN.
- (rsock_sys_fail_path): Ditto.
- (rsock_sys_fail_sockaddr): Ditto.
-
-Sat Apr 6 11:49:35 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/socket.c (rsock_sys_fail_path): Use rb_str_inspect if the
- path contains a NUL.
-
-Sat Apr 6 11:39:19 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket: Improve socket exception message to show socket address.
- [ruby-core:45617] [Feature #6583] proposed Eric Hodel.
-
- * ext/socket/rubysocket.h (rsock_sys_fail_host_port): Declared.
- (rsock_sys_fail_path): Ditto.
- (rsock_sys_fail_sockaddr): Ditto.
-
- * ext/socket/udpsocket.c (udp_connect): Use rsock_sys_fail_host_port.
- (udp_bind): Ditto.
- (udp_send): Ditto.
-
- * ext/socket/init.c (rsock_init_sock): Specify a string for rb_sys_fail
- argument.
- (make_fd_nonblock): Ditto.
- (rsock_s_accept): Ditto.
-
- * ext/socket/ipsocket.c (init_inetsock_internal): Use
- rsock_sys_fail_host_port.
-
- * ext/socket/socket.c (rsock_sys_fail_host_port): Defined.
- (rsock_sys_fail_path): Ditto.
- (rsock_sys_fail_sockaddr): Ditto.
- (setup_domain_and_type): Use rsock_sys_fail_sockaddr.
- (sock_connect_nonblock): Ditto.
- (sock_bind): Ditto.
- (sock_gethostname): Specify a string for rb_sys_fail argument.
- (socket_s_ip_address_list): Ditto.
-
- * ext/socket/basicsocket.c (bsock_shutdown): Specify a string for
- rb_sys_fail argument.
- (bsock_setsockopt): Use rsock_sys_fail_path.
- (bsock_getsockopt): Ditto.
- (bsock_getpeereid): Refine the argument for rb_sys_fail.
-
- * ext/socket/unixsocket.c (rsock_init_unixsock): Use
- rsock_sys_fail_path.
- (unix_path): Ditto.
- (unix_send_io): Ditto.
- (unix_recv_io): Ditto.
- (unix_addr): Ditto.
- (unix_peeraddr): Ditto.
-
-Sat Apr 6 11:23:18 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * test/ruby/test_require.rb (TestRequire#test_require_nonascii_path):
- fix load path for encoding to run the test as stand-alone.
-
-Sat Apr 6 09:54:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * pack.c (NATINT_LEN): fix definition order, must be after
- NATINT_PACK.
-
-Sat Apr 6 03:11:07 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb: fix symbol keys in coder
- emission. Thanks @tjwallace
- * test/psych/test_coder.rb: test for change
-
-Sat Apr 6 02:54:08 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/exception.rb: there should be only one exception
- base class. Fixes tenderlove/psych #125
- * ext/psych/lib/psych.rb: require the correct exception class
- * ext/psych/lib/psych/syntax_error.rb: ditto
- * ext/psych/lib/psych/visitors/to_ruby.rb: ditto
-
-Sat Apr 6 02:30:28 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (new_defined): remove all extra parentheses, and return
- "nil" for defined? with empty expression.
- [ruby-core:54024] [Bug #8224]
-
-Sat Apr 6 02:06:04 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/to_ruby.rb: correctly register
- self-referential strings. Fixes tenderlove/psych #135
-
- * test/psych/test_string.rb: appropriate test.
-
-Sat Apr 6 01:21:56 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/init.c (cloexec_accept): Fix a compile error on
- Debian GNU/kFreeBSD. Consider HAVE_ACCEPT4 is defined
- but SOCK_CLOEXEC is not defined.
-
-Sat Apr 6 00:19:30 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * load.c (features_index_add): use rb_str_subseq() to specify C string
- position properly to fix require non ascii path.
- [ruby-core:53733] [Bug #8165]
-
- * test/ruby/test_require.rb (TestRequire#test_require_nonascii_path):
- a test for the above.
-
-Fri Apr 5 20:41:49 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/defines.h (HAVE_TRUE_LONG_LONG): Defined to distinguish
- availability of long long and availability of 64bit integer type.
-
- * pack.c: Use HAVE_TRUE_LONG_LONG to distinguish q! and Q! support.
-
-Fri Apr 5 20:19:42 2013 Tanaka Akira <akr@fsij.org>
-
- * addr2line.c: Include ruby/missing.h to fix compile error on Debian.
-
-Fri Apr 5 19:39:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_compile_each): fix of defined? with empty
- expression. [ruby-core:53999] [Bug #8220]
-
-Fri Apr 5 13:22:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/curses/curses.c (Init_curses): fix implementation function,
- crmode should be same as cbreak. [ruby-core:54013] [Bug #8222]
-
-Fri Apr 5 12:06:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/curses/hello.rb: Typo in Curses example by Drew Blas
- [Fixes GH-273]
-
-Thu Apr 4 23:45:13 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb (bind_random_port): Rescue EACCES for SunOS.
- bind() on SunOS for port 2049 (nfs) and 4045 (lockd) causes
- EACCES with unprivileged process. cf. PRIV_SYS_NFS in privileges(5)
- [ruby-core:48064] [Bug #7183] reported by Frank Meier.
-
-Thu Apr 4 23:24:45 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: Remove condition for bcc.
-
-Thu Apr 4 22:53:23 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/ruby.h (FIX2LONG): Parenthesize the macro body.
-
-Thu Apr 4 22:32:32 2013 Tanaka Akira <akr@fsij.org>
-
- * time.c (time_strftime): Describe %L and %N truncates digits under
- the specified length.
- [ruby-core:52130] [Bug #7829]
-
-Thu Apr 4 22:08:46 2013 Tanaka Akira <akr@fsij.org>
-
- * object.c (rb_mod_cvar_set): Reverted "avoid inadvertent
- symbol creation" to avoid SEGV by
- Class.new.class_variable_set(1, 2).
-
-Thu Apr 4 20:07:19 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/pathname/pathname.c (path_write): New method.
- (path_binwrite): Ditto.
- [ruby-core:49468] [Feature #7378]
-
-Thu Apr 4 16:51:29 2013 Yuki Yugui Sonoda <yugui@google.com>
-
- * thread_pthread.c: Fixes wrong scopes of #if USE_SLEEPY_TIMER_THREAD
- .. #endif sections. This fixes a build error on NativeClient.
-
-Wed Apr 3 17:25:31 2013 Yuki Yugui Sonoda <yugui@google.com>
-
- * thread_pthread.c (ruby_init_stack): Avoid using uninitialized value.
- stackaddr and size are not set if get_stack() fails.
-
-Thu Apr 4 16:55:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * struct.c (make_struct): avoid inadvertent symbol creation.
- (rb_struct_aref): ditto.
- (rb_struct_aset): ditto.
-
-Thu Apr 4 16:54:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (rb_mod_const_set): avoid inadvertent symbol creation.
- (rb_obj_ivar_set): ditto.
- (rb_mod_cvar_set): ditto.
-
-Thu Apr 4 15:46:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enum.c (enum_inject): avoid inadvertent symbol creation.
-
-Thu Apr 4 14:37:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (rb_thread_aref): avoid inadvertent symbol creation.
- (rb_thread_variable_get): ditto.
- (rb_thread_key_p): ditto.
- (rb_thread_variable_p): ditto.
-
-Thu Apr 4 11:33:57 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/openssl/ossl_bn.c (ossl_bn_to_i): Use bn2hex to speed up.
- In general, binary to/from decimal needs extra cost.
-
-Thu Apr 4 07:24:18 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: Specify arguments to test functions.
-
-Thu Apr 4 03:25:09 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/openssl/ossl_bn.c (ossl_bn_initialize): fix can't create from bn.
-
-Wed Apr 3 22:09:25 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: Test functions and libraries after headers.
-
-Wed Apr 3 21:23:29 2013 Tanaka Akira <akr@fsij.org>
-
- * io.c (rb_io_seek_m): Accept :CUR, :END, :SET as "whence" argument.
- (interpret_seek_whence): New function.
- [ruby-dev:45818] [Feature #6643]
-
-Wed Apr 3 20:52:49 2013 Tanaka Akira <akr@fsij.org>
-
- * process.c: Describe the behavior which Ruby invokes a commandline
- directly without shell if the commandline is simple enough.
- [ruby-core:50459] [Bug #7489]
-
-Wed Apr 3 20:27:37 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/extmk.rb (extmake): Invoke Logging::log_close in a ensure
- clause.
-
-Wed Apr 3 18:53:58 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/extmk.rb (extmake): Use Logging.open to switch stdout and
- stderr. Delay Logging::log_close until the failure message is
- written. Write the failure message only if log file is opened.
-
- * lib/mkmf.rb (Logging.log_opened?): New method.
-
- [ruby-dev:47215] [Bug #8209]
-
-Wed Apr 3 17:11:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (constat_apply): pass through unknown sequence which
- starts with ESC but is not followed by a bracket. [ruby-core:53879]
- [Bug #8201]
-
-Wed Apr 3 16:35:32 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * bignum.c (rb_big_eq): hide intermediate Bignums not just freeing
- memory. [ruby-core:53893] [Bug #8204]
-
- * object.c (rb_obj_hide): hide an object by clearing klass.
-
- * bignum.c (rb_big_eq): test as Fixnum if possible and get rid of zero
- length Bignum. [ruby-core:53893] [Bug #8204]
-
-Tue Apr 2 23:56:03 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/securerandom.rb (SecureRandom.random_bytes): Use
- OpenSSL::Random.random_add instead of OpenSSL::Random.seed and
- specify 0.0 as the entropy.
- [ruby-core:47308] [Bug #6928]
-
-Tue Apr 2 20:24:52 2013 Tanaka Akira <akr@fsij.org>
-
- * pack.c: Support Q! and q! for long long.
- (natstr): Moved to toplevel. Add q and Q if there is long long type.
- (endstr): Moved to toplevel.
- (NATINT_PACK): Consider long long.
- (NATINT_LEN_Q): New macro.
- (pack_pack): Support Q! and q!.
- (pack_unpack): Ditto.
- [ruby-dev:43970] [Feature #3946]
-
-Tue Apr 2 19:24:26 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/-test-/num2int/num2int.c: Define utility methods
- as module methods of Num2int.
-
- * test/-ext-/num2int/test_num2int.rb: Follow the above change.
-
-Tue Apr 2 18:49:01 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/securerandom.rb: Don't use Array#to_s.
- [ruby-core:52058] [Bug #7811] fixed by zzak (Zachary Scott).
-
-Tue Apr 2 17:38:20 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * re.c (rb_reg_to_s): suppress duplicated charclass warning.
- Regexp#to_s suppress extra its whole regexp options by calling
- onig_new with its source, but it doesn't call rb_reg_preprocess.
- Therefore its Unicode escapes (\u{XXXX}) are given as is,
- and it may cause duplicated charclass warning for example
- "[\u{33}]" (3 is duplicated) or "[\u{a}\u{b}]" (u is duplicated).
- [ruby-core:53649] [Bug #8151]
-
-Tue Apr 2 16:00:06 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_dump.c (rb_print_backtrace): separate to ease showing C backtrace.
-
- * internal.h (rb_print_backtrace): ditto.
-
-Tue Apr 2 15:22:09 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * test/ruby/envutil.rb (assert_separately): stop_auto_run of
- Test::Unit::Runner to prevent auto runner use ARGV.
-
- * test/ruby/envutil.rb (assert_separately): add $: to separate process.
-
- * test/ruby/envutil.rb (assert_separately): fail if stderr is not
- empty and ignore_stderr is false.
-
-Tue Apr 2 06:46:59 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/-test-/num2int/num2int.c: Rename utility methods
- to global functions to ease manual experiments.
-
- * test/-ext-/num2int/test_num2int.rb: Follow the above change.
-
-Mon Apr 1 22:26:17 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/zlib/zlib.c (rb_gzfile_set_mtime): Use NUM2UINT.
- The old logic doesn't work well on LP64 platforms as:
- .. -2**63-1 => error,
- -2**63 .. -2**62-1 => success,
- -2**62 .. -2**31-1 => error,
- -2**31 .. 2**31-1 => success,
- 2**31 .. 2**62-1 => error,
- 2**62 .. 2**64-1 => success,
- 2**64 .. => error.
-
-Mon Apr 1 22:08:02 2013 Benoit Daloze <eregontp@gmail.com>
-
- * ext/zlib/zlib.c (Zlib::Inflate.new):
- Fix documentation syntax and naming errors.
- Based on patch by Robin Dupret. Fix GH-271.
-
-Mon Apr 1 21:22:31 2013 Tanaka Akira <akr@fsij.org>
-
- * test/-ext-/num2int/test_num2int.rb: Test small bignums.
-
-Mon Apr 1 21:10:56 2013 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_num2ulong_internal): Don't cast a negative double value
- into unsigned long, which is undefined behavior.
- (rb_num2ull): Don't cast a value bigger than LLONG_MAX into
- long long, which is undefined behavior.
-
-Mon Apr 1 20:57:57 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/-test-/num2int/num2int.c: Return string for result, instead of
- printing.
-
- * test/-ext-/num2int/test_num2int.rb: updated to follow above change.
-
-Mon Apr 1 20:08:07 2013 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_num2long): Don't use SIGNED_VALUE uselessly.
- (check_int): Ditto.
- (check_short): Ditto.
- (rb_num2fix): Ditto.
- (rb_num2ulong_internal): Add a cast.
-
-Mon Apr 1 18:41:35 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: skip autoconf 2.64 and 2.66, 2.67 seems short-lived
- but stick on it for Debian Squeeze.
-
-Mon Apr 1 14:22:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: check clang version by predefined macro values.
- [Bug #8192]
-
-Mon Apr 1 12:05:15 2013 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (check_uint): Take the 1st argument as unsigned long,
- instead of VALUE. Refine the validity test conditions.
- (check_ushort): Ditto.
-
-Mon Apr 1 07:15:03 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * configure.in: use quadrigraph to put '[' or ']'. [Bug #8192]
-
-Mon Apr 1 04:16:41 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: kick old clang. [ruby-dev:47204] [Bug #8192]
-
-Mon Apr 1 01:12:46 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/ruby.h (FIX2ULONG): Make it consistent with NUM2ULONG.
-
- * ext/-test-/num2int/num2int.c: Add utility methods for FIX2XXX tests.
-
- * test/-ext-/num2int/test_num2int.rb: Add tests for FIX2XXX.
-
-Sun Mar 31 17:17:56 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (rb_mod_define_method): consider visibility in define_method.
- patch by mashiro <mail AT mashiro.org>. fix GH-268.
-
-Sun Mar 31 15:40:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/configure.bat: try to fix option arguments split by commas and
- equals here. this batch file no longer run with old command.com.
-
- * tool/mkconfig.rb: no hacks for cmd.exe.
-
-Sun Mar 31 13:47:04 2013 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_num2ulong_internal): New function similar to
- rb_num2ulong but integer wrap around flag is also returned.
- (rb_num2ulong): Use rb_num2ulong_internal.
- (rb_num2uint): Use rb_num2ulong_internal and the wrap around flag is
- used instead of negative_int_p(val).
- (rb_num2ushort): ditto.
-
-Sun Mar 31 06:27:17 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (HAVE_METACLASS_P): should check FL_SINGLETON flag before get
- instance variable to get rid of wrong warning about __attached__.
- [ruby-core:53839] [Bug #8188]
-
-Sat Mar 30 14:11:28 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * bcc32: removed. agreed at
- http://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20130223Japan
-
-Sat Mar 30 03:58:00 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/file.c (code_page): use cp1252 instead of cp20127 as US-ASCII.
- fix [ruby-core:53079] [Bug #7996]
- reported and patched by mmeltner (Michael Meltner).
-
-Sat Mar 30 03:49:21 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (wrename): use MoveFileExW instead of MoveFileW,
- because the latter fails on cross device file move of some
- environments.
- fix [ruby-core:53492] [Bug #8109]
- reported by mitchellh (Mitchell Hashimoto).
-
-Fri Mar 29 22:09:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (rb_mutex_synchronize_m): yield no block params. patch by
- splattael (Peter Suschlik) in [ruby-core:53773] [Bug #8097].
- fix GH-266.
-
-Fri Mar 29 16:51:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (argf_next_argv): set init flag if succeeded to forward, after
- skipping.
-
- * io.c (argf_block_call_i, argf_block_call): no more forwarding if
- forwarded after skipping. [ruby-list:49185]
-
- * io.c (argf_close): deal with init flag.
-
- * io.c (argf_block_call_i, argf_block_call): forward next file if
- skipped while iteration, to get rid of IOError. [ruby-list:49185]
-
-Fri Mar 29 11:09:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (configuration): not include all CFLAGS in CXXFLAGS, to
- use different set than C for C++. [ruby-core:45273] [Bug #6504]
-
-Fri Mar 29 10:24:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/io.h: undef POSIX compliant names on AIX, which are no
- longer needed. patch suggested by edelsohn (David Edelsohn) in
- [ruby-core:53815]. [Bug #8174]
-
-Fri Mar 29 06:39:42 2013 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_num2ull): Cast double to unsigned LONG_LONG via
- LONG_LONG instead of double to unsigned LONG_LONG directly.
- This is a challenge to fix a test_num2ull(TestNum2int)
- failure (NUM2ULL(-1.0) should be "18446744073709551615" but was "0")
- on Mac OS X with 32bit clang.
- http://a.mrkn.jp/~mrkn/chkbuild/mountain_lion/ruby-trunk-m32-o0/log/20130328T191100Z.diff.html.gz
-
-Fri Mar 29 00:54:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (MAIN_DOES_NOTHING): ensure symbols for tests to be
- preserved. [ruby-core:53745] [Bug #8169]
-
-Thu Mar 28 23:11:25 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb: Test Windows platform by detecting LoadError when
- require 'win32/resolv' suggested by Nobuyoshi Nakada [ruby-core:53389].
- [ruby-core:53388] [Feature #8090] Reported by Charles Nutter.
-
-Thu Mar 28 23:10:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/io.h: rename SVR3,4 member names as POSIX compliant,
- to get rid of conflict on AIX. [ruby-core:53765] [Bug #8174]
-
-Thu Mar 28 18:22:21 2013 Tanaka Akira <akr@fsij.org>
-
- * test/-ext-/num2int/test_num2int.rb: extract
- assert_num2i_success_internal and assert_num2i_error_internal and
- provide assertion messages as "NUM2XXX(NNN)".
-
-Thu Mar 28 07:05:25 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/intern.h: Delete redundant inclusions caused by
- AC_INCLUDES_DEFAULT in defines.h.
-
- * include/ruby/defines.h: Ditto.
-
- * include/ruby/ruby.h: Ditto.
-
- * include/ruby/st.h: Ditto.
-
-Thu Mar 28 06:51:31 2013 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/defines.h: Fix a compilation error on NetBSD,
- "type of formal parameter 1 is incomplete" for the rb_thread_wait_for
- invocation in rb_file_flock, by including header files as
- AC_INCLUDES_DEFAULT of autoconf.
-
-Wed Mar 27 22:09:14 2013 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (LONG_MIN_MINUS_ONE_IS_LESS_THAN): New macro.
- (LLONG_MIN_MINUS_ONE_IS_LESS_THAN): Ditto.
- (rb_num2long): Use LONG_MIN_MINUS_ONE_IS_LESS_THAN.
- (rb_num2ulong): Ditto.
- (rb_num2ll): Use LLONG_MIN_MINUS_ONE_IS_LESS_THAN.
- (rb_num2ull): Ditto.
-
- * test/-ext-/num2int/test_num2int.rb (assert_num2i_success): Test the
- value converted into a Float if Float can represent the value
- exactly.
- (assert_num2i_error): Ditto.
-
-Wed Mar 27 20:59:47 2013 Tanaka Akira <akr@fsij.org>
-
- * test/-ext-/num2int/test_num2int.rb (assert_num2i_success): New
- utility method.
- (assert_num2i_error): Ditto.
-
-Wed Mar 27 20:37:59 2013 Tanaka Akira <akr@fsij.org>
-
- * time.c (num_exact): Use to_r method only if to_int method is
- available.
- [ruby-core:53764] [Bug #8173] Reported by Hiro Asari.
-
-Wed Mar 27 12:07:40 2013 Tanaka Akira <akr@fsij.org>
-
- * test/-ext-/num2int/test_num2int.rb (test_num2ll): test LLONG_MIN,
- not LONG_MIN.
-
-Wed Mar 27 12:02:45 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (TIMET_MAX_PLUS_ONE): definition simplified.
-
-Wed Mar 27 06:39:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (MAIN_DOES_NOTHING): force to refer symbols for tests
- to be preserved. [ruby-core:53745] [Bug #8169]
-
-Wed Mar 27 05:15:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (RUBY_REPLACE_TYPE): define SIGNEDNESS_OF_type same as
- check_signedness of mkmf.rb.
-
- * internal.h (TIMET_MAX, TIMET_MIN, TIMET_MAX_PLUS_ONE): use
- SIGNEDNESS_OF_TIME_T.
-
-Wed Mar 27 00:28:45 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h (TIMET_MAX_PLUS_ONE): Defined.
-
- * thread.c (double2timeval): Saturate out-of-range values.
-
-Tue Mar 26 23:41:18 2013 Tanaka Akira <akr@fsij.org>
-
- * internal.h: Define TIMET_MAX and TIMET_MIN here.
-
- * time.c: Remove TIMET_MAX and TIMET_MIN definitions.
-
- * thread.c: Ditto.
-
- * thread_pthread.c: Remove TIMET_MAX definition.
-
- * thread_win32.c: Ditto.
-
-Tue Mar 26 22:31:10 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/socket.c (sockaddr_len): return the shortest length for
- unknown socket address.
-
-Tue Mar 26 22:14:46 2013 Tanaka Akira <akr@fsij.org>
-
- * thread.c (double2timeval): convert the infinity to TIME_MAX to avoid
- SEGV by Thread.new {}.join(Float::INFINITY) on
- Debian GNU/Linux (amd64).
-
-Mon Mar 25 07:09:20 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rinda/tuplespace.rb: Only return tuple entry once on move,
- either through port or regular return, not both. This results in a
- 120% speedup when combined with #8125. Patch by Joel VanderWerf.
- [ruby-trunk - Feature #8119]
-
-Mon Mar 25 06:59:01 2013 Eric Hodel <drbrain@segment7.net>
-
- * test/rinda/test_rinda.rb: Skip IPv6 tests if no IPv6 addresses
- exist. Skip fork-dependent test if fork is not available.
- [ruby-trunk - Bug #8159]
-
-Sun Mar 24 10:38:24 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * addr2line.c (putce): suppress unused return value warning.
-
-Mon Mar 25 02:01:03 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * proc.c (bm_free): need to clean up the mark flag of a free and
- unlinked method entry. [Bug #8100] [ruby-core:53439]
-
-Sun Mar 24 22:13:51 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (rb_str_rpartition): revert r39903, and convert byte offset
- to char offset; the return value of rb_reg_search is byte offset,
- but other than it of rb_str_rpartition expects char offset.
- [Bug #8138] [ruby-dev:47183]
-
-Sun Mar 24 18:29:46 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * string.c (rb_str_rpartition): Fix String#rpartition(/re/)
- against a multibyte string. [Bug #8138] [ruby-dev:47183]
-
-Sun Mar 24 13:42:24 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * gc.c (GC_ENABLE_LAZY_SWEEP): new macro to switch lazy sweeping
- for debugging. [Feature #8024] [ruby-dev:47135]
-
-Sun Mar 24 12:55:47 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * gc.c: We have no chance to expand the heap when lazy sweeping is
- restricted. So collecting is often invoked if there is not
- enough free space in the heap. Try to expand heap when this is
- the case.
-
-Sun Mar 24 11:03:31 2013 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_require.rb: Remove temporally files in the tests.
-
- * test/ruby/test_rubyoptions.rb: Ditto.
-
- * test/logger/test_logger.rb: Ditto.
-
- * test/psych/test_psych.rb: Ditto.
-
- * test/readline/test_readline.rb: Ditto.
-
- * test/syslog/test_syslog_logger.rb: Ditto.
-
- * test/webrick/test_httpauth.rb: Ditto.
-
- * test/zlib/test_zlib.rb: Ditto.
-
-Sun Mar 24 05:36:29 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rinda/ring.rb: Added documentation for multicast support.
-
- * NEWS: Point to above documentation.
-
-Sun Mar 24 05:32:39 2013 Eric Hodel <drbrain@segment7.net>
-
- * test/rinda/test_rinda.rb: Restore tests commented out while fixing
- test slowdown bug before r39895.
-
-Sun Mar 24 05:03:36 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rinda/ring.rb: Add multicast support to Rinda::RingFinger and
- Rinda::RingServer. [ruby-trunk - Bug #8073]
- * test/rinda/test_rinda.rb: Test for the above.
-
- * NEWS: Update with Rinda multicast support
-
-Sun Mar 24 04:13:27 2013 Eric Hodel <drbrain@segment7.net>
-
- * test/rinda/test_rinda.rb: Fixed test failures in r39890 and r39891
- due to stopping DRb service.
-
-Sun Mar 24 03:34:02 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rinda/rinda.rb: Fixed loss of tuple when remote is alive but the
- call stack was unwound. Patch by Joel VanderWerf.
- [ruby-trunk - Bug #8125]
- * test/rinda/test_rinda.rb: Test for the above.
-
-Sun Mar 24 02:14:53 2013 Tanaka Akira <akr@fsij.org>
-
- * test/mkmf/test_have_macro.rb: remove temporally files in the tests.
-
-Sat Mar 23 23:50:04 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (kprintf): added from FreeBSD libstand's printf.
- this is consided as async signal safe function.
-
- * addr2line.c (rb_dump_backtrace_with_lines): use kfprintf.
- [Bug #8144] [ruby-core:53632]
-
-Sat Mar 23 23:28:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_divide): Use Qnil and NIL_P
- instead of (VALUE)0 as a return value.
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_div): ditto.
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_divremain): ditto.
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_remainder): ditto.
-
-Sat Mar 23 17:39:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (check_funcall_respond_to): preserve passed_block, which
- is modified in vm_call0_body() via vm_call0(), and caused a bug of
- rb_check_funcall() by false negative result of rb_block_given_p().
- re-fix [ruby-core:53650] [Bug #8153].
- [ruby-core:53653] [Bug #8154]
-
-Fri Mar 22 17:48:34 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/forwardable.rb (Forwardable::FILE_REGEXP): create regexp object
- outside sources for eval, to reduce allocations in def_delegators
- wrappers. //o option does not make each regexps shared. patch by
- tmm1 (Aman Gupta) in [ruby-core:53620] [Bug #8143].
-
-Fri Mar 22 17:38:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * load.c (rb_feature_p), vm_core.h (rb_vm_struct): turn
- loaded_features_index into st_table. patches by tmm1 (Aman Gupta)
- in [ruby-core:53251] and [ruby-core:53274] [Bug #8048]
-
-Fri Mar 22 10:29:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/bigdecimal/bigdecimal.c: Fix style.
-
-Fri Mar 22 05:30:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (ambiguous_operator): refine warning message, since this
- warning is shown after literal too.
-
-Fri Mar 22 04:51:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_callee_setup_keyword_arg): should check required
- keyword arguments even if rest hash is defined. [ruby-core:53608]
- [Bug #8139]
-
-Fri Mar 22 01:00:17 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * process.c (rb_execarg_addopt, run_exec_pgroup): use rb_pid_t
- instead of pid_t.
-
- * ext/pty/pty.c (raise_from_check, pty_check): ditto.
-
-Fri Mar 22 00:04:15 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (rb_dump_backtrace_with_lines): output line at once.
-
-Thu Mar 21 23:17:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (ruby_kill): get rid of deadlock on signal 0.
- [ruby-dev:47182] [Bug #8137]
-
-Thu Mar 21 22:39:46 2013 Naohisa Goto <ngotogenome@gmail.com>
-
- * marshal.c (marshal_dump, marshal_load): workaround for segv on
- Intel Solaris compiled with Oracle SolarisStudio 12.3.
- Partly revert r38174. [ruby-core:52042] [Bug #7805]
-
-Thu Mar 21 16:48:06 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (simple_re_meta): escape all closing characters, not only
- round parenthesis. [ruby-core:53578] [Bug #8133]
-
-Thu Mar 21 13:50:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_core.h (UNINITIALIZED_VAR): suppress warnings by clang 4.2.
- [ruby-core:51742] [Bug #7756]
-
-Thu Mar 21 07:34:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/date/date_core.c: Typo in Date::MONTHNAMES by Matt Gauger
- [GH fixes #261]
-
-Wed Mar 20 22:53:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (find_library): fix to format message.
- [ruby-core:53568] [Bug #8130]
-
-Wed Mar 20 22:52:52 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (install_dirs, with_destdir): prefix with DESTDIR
- directories to install only unless bundled extension libraries.
- [ruby-core:53502] [Bug #8115]
-
-Wed Mar 20 17:47:53 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/win32ole/test_err_in_callback.rb (TestErrInCallBack#setup):
- allow using different root for source and build directories.
- this may fixes a minor problem of r39834.
-
-Wed Mar 20 16:40:48 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * test/ruby/test_signal.rb (test_hup_me): skip if HUP isn't supported.
- On Windows this test causes ArgumentError.
-
-Wed Mar 20 16:24:12 2013 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * test/rubygems/test_gem_installer.rb (test_install_extension_flat):
- use ruby in build directory in case ruby is not installed.
- [ruby-core:53265] [Bug #8058]
-
-Wed Mar 20 15:22:07 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/win32ole/test_err_in_callback.rb (TestErrInCallBack#setup): use
- relative path to get rid of "too long commandline" error.
-
-Wed Mar 20 04:27:42 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * test/rinda/test_rinda.rb: remove unused variables.
- patched by Vipul A M <vipulnsward@gmail.com>
-
-Wed Mar 20 04:15:32 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * ext/bigdecimal/bigdecimal.c: fixed typo.
- patched by Vipul A M <vipulnsward@gmail.com>
-
-Sat Mar 16 03:40:49 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * test/ruby/test_signal.rb (test_hup_me): added a few comments.
-
-Sat Mar 16 03:39:38 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread.c (ruby_kill): added a few comments.
-
-Sat Mar 16 03:36:56 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread.c (ruby_kill): release GVL while waiting signal delivered.
-
-Tue Mar 19 19:50:48 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ruby_kill (internal.h, thread.c): use rb_pid_t instead of pid_t.
- this fixes the build failure of mswin introduced at r39819.
-
-Tue Mar 19 17:09:30 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_conv_enc_opts): convert with one converter, instead
- of re-creating converters for each buffer expansion.
-
-Tue Mar 19 17:06:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (glob_helper): compose HFS file names from UTF8-MAC.
- [ruby-core:48745] [Bug #7267]
-
-Sat Mar 16 01:44:29 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * internal.h: added a declaration of ruby_kill().
- * thread.c (ruby_kill): helper function of kill().
-
- * signal.c (rb_f_kill): use ruby_kill() instead of kill().
- * signal.c (rb_f_kill): call rb_thread_execute_interrupts()
- to ensure that make SignalException if sent a signal
- to myself. [Bug #7951] [ruby-core:52864]
-
- * vm_core.h (typedef struct rb_thread_struct): added
- th->interrupt_cond.
- * thread.c (rb_threadptr_interrupt_common): added to
- initialization of th->interrupt_cond.
- * thread.c (thread_create_core): ditto.
-
- * test/ruby/test_signal.rb (TestSignal#test_hup_me): test for
- the above.
-
-Sat Mar 16 00:42:39 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * io.c (linux_iocparm_len): enable only exist _IOC_SIZE().
- Because musl libc doesn't have it. [Bug #8051] [ruby-core:53229]
-
-Tue Mar 19 10:05:04 2013 Shota Fukumori <her@sorah.jp>
-
- * ext/objspace/objspace.c: Fix typo in doc. Patch by Sho Hashimoto.
- [Bug #8116] [ruby-dev:47177]
-
-Tue Mar 19 02:13:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * configure.in: set ac_cv_prog_cxx if CXX is supplied.
-
-Tue Mar 19 01:18:00 2013 Kenta Murata <mrkn@mrkn.jp>
-
- * configure.in: Fix c++ compiler auto-selection not only for
- Darwin 11.x, but also the other versions of Darwin.
-
-Tue Mar 19 00:26:22 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * gc.c: Improve accuracy of objspace_live_num() and
- allocated/freed counters. patched by tmm1(Aman Gupta).
- [Bug #8092] [ruby-core:53392]
-
-Mon Mar 18 21:42:48 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * gc.c: Avoid unnecessary heap growth. patched by tmm1(Aman Gupta).
- [Bug #8093] [ruby-core:53393]
-
-Mon Mar 18 17:58:36 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * gc.c: Fix unlimited memory growth with large values of
- RUBY_FREE_MIN. patched by tmm1(Aman Gupta).
- [Bug #8095] [ruby-core:53405]
-
-Mon Mar 18 14:46:19 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/win32ole/test_err_in_callback.rb
- (TestErrInCallBack#test_err_in_callback): shouldn't create a file in
- the top of build directory.
-
-Mon Mar 18 13:29:52 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_dump.c (backtrace): on darwin use custom backtrace() to trace
- beyond _sigtramp. darwin's backtrace can't trace beyond signal
- trampoline with sigaltstack.
-
- * configure.in: check execinfo.h on darwin.
-
-Mon Mar 18 11:03:23 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_exec.h (END_INSN): revert r39517 because the segv seems fixed by
- r39806.
-
-Mon Mar 18 10:41:06 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_exec.c: Correct predefined macro name. This typo is introduced by
- r36534 and should be backported to ruby_2_0_0.
-
-Mon Mar 18 03:18:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * array.c: Typo in Array#delete by Timo Sand [GH fixes #258]
-
-Mon Mar 18 01:14:56 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * io.c (io_fillbuf): show fd number on failure to debug.
- http://c5632.rubyci.org/~chkbuild/ruby-trunk/log/20130316T050302Z.diff.html.gz
-
-Sun Mar 17 02:38:21 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * ext/date/date_core.c: include sys/time.h for avoiding implicit
- declaration of gettimeofday().
-
-Sun Mar 17 00:55:31 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * include/ruby/missing.h: removed __linux__. it's unnecessary.
-
-Fri Mar 15 14:57:16 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread.c: disabled _FORTIFY_SOURCE for avoid to hit glibc bug.
- [Bug #8080] [ruby-core:53349]
- * test/ruby/test_io.rb (TestIO#test_io_select_with_many_files):
- test for the above.
-
-Wed Mar 13 15:16:35 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * include/ruby/missing.h (__syscall): moved to...
- * io.c: here. because __syscall() is only used from io.c.
-
- * include/ruby/missing.h: move "#include <sys/type.h>" to ....
- * include/ruby/intern.h: here. because it was introduced for
- fixing NFDBITS issue. [ruby-core:05179].
-
-Wed Mar 13 14:38:53 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * include/ruby/missing.h (struct timespec): include <sys/time.h>
-
-Wed Mar 13 13:54:45 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in: check struct timeval exist or not.
- * include/ruby/missing.h (struct timeval): check HAVE_STRUCT_TIMEVAL
- properly. and don't include sys/time.h if struct timeval exist.
-
- * file.c: include sys/time.h explicitly.
- * random.c: ditto.
- * thread_pthread.c: ditto.
- * time.c: ditto.
- * ext/date/date_strftime.c: ditto.
-
-Fri Mar 15 14:45:02 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * configure.in (_FORTIFY_SOURCE): added a few comments.
-
-Fri Mar 15 14:17:55 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread_pthread.c (numberof): renamed from ARRAY_SIZE() because
- other all files use numberof().
-
-Say Mar 15 01:33:00 2013 Charles Oliver Nutter <headius@headius.com>
-
- * test/ruby/test_lazy_enumerator.rb (TestLazyEnumerator#test_drop_while):
- Modify while condition to show dropping remains off after first false
- value. This change was made in 39711.
-
-Fri Mar 15 23:06:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * time.c (GetTimeval): check if already initialized instance.
-
- * time.c (GetNewTimeval): check if newly created instance.
-
- * time.c (time_init_0, time_init_1, time_init_copy, time_mload): must
- be newly created instance. [ruby-core:53436] [Bug #8099]
-
-Fri Mar 15 14:51:33 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (rb_sys_fail_path_with_func): share same function, and path
- may be nil.
-
-Fri Mar 15 08:24:51 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * io.c (rb_sys_fail_path): define & use rb_sys_fail_path0 like r39752
-
-Fri Mar 15 04:08:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * proc.c: Typo in Proc.arity found by Jack Nagel [Bug #8094]
-
-Thu Mar 14 16:59:09 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (rb_cv_function_name_string): macro for function name
- string predefined identifier, __func__ in C99, or __FUNCTION__ in
- gcc.
-
- * file.c (rb_sys_fail_path): use RUBY_FUNCTION_NAME_STRING.
-
-Thu Mar 14 14:12:34 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * file.c (rb_sys_fail_path): use rb_sys_fail_path0 only on GCC.
- __func__ is C99 feature.
-
-Thu Mar 14 12:59:59 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * file.c (rb_sys_fail_path0): add to append the name of called function
- to ease debugging for example blow umask_spec failure.
- http://fbsd.rubyci.org/~chkbuild/ruby-trunk/log/20130309T010202Z.diff.html.gz
-
- * file.c (rb_sys_fail_path): use rb_sys_fail_path0.
-
-Thu Mar 14 12:53:15 2013 Luis Lavena <luislavena@gmail.com>
-
- * win32/file.c (get_user_from_path): add internal function that retrieves
- username from supplied path (refactored).
- * win32/file.c (rb_file_expand_path_internal): refactor expansion of user
- home to use get_user_from_path and cover dir_string corner cases.
- [ruby-core:53168] [Bug #8034]
-
-Thu Mar 14 11:53:01 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * NEWS: describe RUBY_HEAP_SLOTS_GROWTH_FACTOR.
-
-Thu Mar 14 10:01:12 2013 Eric Hodel <drbrain@segment7.net>
-
- * doc/globals.rdoc: $? is thread-local
-
-Wed Mar 13 23:25:59 2013 Narihiro Nakamura <authornari@gmail.com>
-
- * gc.c: allow to tune growth of heap by environment variable
- RUBY_HEAP_SLOTS_GROWTH_FACTOR. patched by tmm1(Aman Gupta).
- [Feature #8015] [ruby-core:53131]
-
-Wed Mar 13 19:43:46 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * doc/irb/irb.rd.ja: fix typo
-
- * ext/tk/MANUAL_tcltklib.eng: fix typos
-
- * ext/tk/sample/tktextframe.rb (Tk#component_delegates): fix typo
-
-Wed Mar 13 15:13:04 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (rb_obj_singleton_methods): collect methods from the origin
- class. [ruby-core:53207] [Bug #8044]
-
-Wed Mar 13 14:51:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_method.c (rb_export_method): directly override the flag of method
- defined in prepending class too, not adding zsuper entry.
- [ruby-core:53106] [Bug #8005]
-
-Wed Mar 13 13:06:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (rm, shvar_to_cpp, unexpand_shvar): local is not
- available on old shells.
-
- * configure.in (shvar_to_cpp): escape quotes for old shells.
- [Bug #7959] [Bug #8071]
-
-Wed Mar 13 11:11:07 2013 Shugo Maeda <shugo@ruby-lang.org>
-
- * object.c (Init_Object): remove Module#used, which has been
- introduced in Ruby 2.0 by mistake. [Bug #7916] [ruby-core:52719]
-
-Wed Mar 13 05:49:29 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/irb.rb: Fix typo
-
-Tue Mar 12 22:20:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_set_arguments, iseq_compile_each): support required
- keyword arguments. [ruby-core:51454] [Feature #7701]
-
- * iseq.c (rb_iseq_parameters): ditto.
-
- * parse.y (f_kw, f_block_kw): ditto. this syntax is still
- experimental, the notation may change.
-
- * vm_core.h (rb_iseq_struct): ditto.
-
- * vm_insnhelper.c (vm_callee_setup_keyword_arg): ditto.
-
-Tue Mar 12 17:02:53 2013 TAKANO Mitsuhiro <tak@no32.tk>
-
- * date_core.c: clearly specify operator precedence.
-
-Tue Mar 12 17:00:45 2013 TAKANO Mitsuhiro <tak@no32.tk>
-
- * insns.def: fix condition.
-
-Tue Mar 12 16:48:19 2013 TAKANO Mitsuhiro <tak@no32.tk>
-
- * rational.c: fix dangling if, else-if and else.
-
-Tue Mar 12 06:27:59 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/commands/setup_command.rb: Don't delete non-rubygems
- files when installing RubyGems.
- * test/rubygems/test_gem_commands_setup_command.rb: Test for the
- above.
-
- * lib/rubygems/ext/ext_conf_builder.rb: Use full path to siteconf.rb
- in case the extconf.rb changes directories (like memcached does).
-
- * lib/rubygems/package.rb: Remove double slash from path.
- * test/rubygems/test_gem_package.rb: Test for the above.
- * test/rubygems/test_gem_package_old.rb: ditto.
-
- * lib/rubygems/source.rb: Revert automatic HTTPS upgrade
- * lib/rubygems/spec_fetcher.rb: ditto.
- * test/rubygems/test_gem_remote_fetcher.rb: ditto.
- * test/rubygems/test_gem_source.rb: ditto.
- * test/rubygems/test_gem_spec_fetcher.rb: ditto.
-
-Tue Mar 12 02:25:19 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/net/smtp.rb: Added Net::SMTP#rset method to implement the SMTP
- RSET command. [ruby-trunk - Feature #5373]
- * NEWS: ditto.
- * test/net/smtp/test_smtp.rb: Test for the above.
-
-Mon Mar 11 22:44:57 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv-replace.rb (TCPSocket#initialize): resolve the 3rd
- argument only if non-nil value is given.
- [ruby-dev:47150] [ruby-trunk - Bug #8054] reported and analyzed by
- mrkn.
-
-Mon Mar 11 19:22:54 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/mkmf/base.rb: class name conflict.
-
-Mon Mar 11 18:45:09 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * enumerator.c (enumerator_with_index): try to convert given offset to
- integer. fix bug introduced in r39594.
-
-Mon Mar 11 17:27:57 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * test/ruby/envutil.rb (EnvUtil.with_default_external): add for
- changing Encoding.default_external without warnings.
-
- * test/ruby/envutil.rb (EnvUtil.with_default_internal): ditto.
-
- * test/ruby/test_io_m17n.rb: use above with_default_external.
-
-Mon Mar 11 16:57:00 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * io.c (extract_binmode): raise error even if binmode and textmode
- don't conflict. [Bug #5918] [ruby-core:42199]
-
-Mon Mar 11 12:25:12 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * Merge Onigmo d4bad41e16e3eccd97ccce6f1f96712e557c4518.
- fix lookbehind assertion fails with /m mode enabled. [Bug #8023]
- fix \Z matches where it shouldn't. [Bug #8001]
-
-Mon Mar 11 11:53:35 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (MakeMakefile#dir_config, MakeMakefile#_libdir_basename):
- defer use of instance variable until needed. [Bug #8074]
-
-Thu Mar 7 10:42:28 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * lib/thread.rb (Queue#clear): return self.
- Patch by Cubing Cube. Thank you! [Bug #7947] [ruby-dev:47098]
- * lib/thread.rb (Queue#push): ditto.
- * lib/thread.rb (SizedQueue#push): ditto.
- * test/thread/test_queue.rb: add tests for the above.
-
-Thu Mar 7 10:40:49 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * tool/change_maker.rb (#diff2index): check Encoding::BINARY.
- BASERUBY may still be 1.8.x.
-
-Thu Mar 7 08:47:42 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * NEWS (Mutex#owned?): no longer experimental.
-
-Sun Mar 10 23:38:15 2013 Luis Lavena <luislavena@gmail.com>
-
- * win32/file.c (rb_file_expand_path_internal): Expand home directory when
- used as second parameter (dir_string). [ruby-core:53168] [Bug #8034]
- * test/ruby/test_file_exhaustive.rb: add test to verify.
-
-Sun Mar 10 23:27:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/rubygems/ext/ext_conf_builder.rb (Gem::Ext::ExtConfBuilder.build):
- it is impossible to predict which file will be installed to where,
- by the arguments, so use intermediate destination directory always.
- [Bug #7698]
-
-Sun Mar 10 17:00:22 2013 Tadayoshi Funaba <tadf@dotrb.org>
-
- * complex.c: edited rdoc.
- * rational.c: ditto.
-
-Sun Mar 10 15:02:39 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * process.c (setup_communication_pipe): remove unused function.
- it was unintentionally added r39683.
-
-Wed Mar 6 00:30:40 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * tool/gen_ruby_tapset.rb: add tapset generator.
-
-Wed Mar 6 03:27:43 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * probes.d (symbol-create): change argument name `string' to
- `str'. `string' is a keyword for systemtap.
-
-Tue Mar 5 22:23:01 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * probes.d: added argument name
-
-Thu Mar 7 01:17:00 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * test/thread/test_queue.rb (TestQueue#test_thr_kill): reduce
- iterations from 2000 to 250. When running on uniprocessor
- systems, every th.kill needs TIME_QUANTUM_USEC time (i.e.
- 100msec on posix systems). Because, "r.read 1" is 3 steps
- operations that 1) release GVL 2) read 3) acquire gvl and
- (1) invoke context switch to main thread. and then, main
- thread's th.kill resume (1), but not (2). Thus read interrupt
- need TIME_QUANTUM_USEC. Then maximum iteration is 30sec/100msec
- = 300.
-
-Thu Mar 7 00:14:51 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * io.c (rb_update_max_fd): use ATOMIC_CAS because this function
- is used from timer thread too.
-
-Wed Mar 6 23:30:21 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread_pthread.c (ARRAY_SIZE): new.
- * thread_pthread.c (gvl_acquire_common): use low priority
- notification for avoiding timer thread interval confusion.
- If we use timer_thread_pipe[1], every gvl_yield() request
- one more gvl_yield(). It lead to thread starvation.
- [Bug #7999] [ruby-core:53095]
- * thread_pthread.c (rb_reserved_fd_p): adds timer_thread_pipe_low
- to reserved fds.
-
-Wed Mar 6 22:36:19 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread_pthread.c (rb_thread_wakeup_timer_thread_fd): add fd
- argument and remove hardcoded dependency of timer_thread_pipe[1].
- * thread_pthread.c (consume_communication_pipe): add fd argument.
- * thread_pthread.c (close_communication_pipe): ditto.
-
- * thread_pthread.c (timer_thread_sleep): adjust the above changes.
-
- * thread_pthread.c (setup_communication_pipe_internal): factor
- out pipe initialize logic.
-
-Wed Mar 6 22:56:14 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread_pthread.c (ubf_select): add to small comments why we
- need to call rb_thread_wakeup_timer_thread().
-
-Wed Mar 6 21:42:24 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread_pthread.c (rb_thread_create_timer_thread): factor out
- creating communication pipe logic into separate function.
- * thread_pthread.c (setup_communication_pipe): new helper function.
- * thread_pthread.c (set_nonblock): moves a definition before
- setup_communication_pipe.
-
-Sun Mar 3 02:42:29 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread_pthread.c (consume_communication_pipe): retry when
- read returned CCP_READ_BUFF_SIZE.
-
-Wed Mar 6 21:31:35 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread_pthread.c (timer_thread_sleep): use poll() instead of
- select(). select doesn't work if timer_thread_pipe[0] is
- greater than FD_SETSIZE.
- * thread_pthread.c (USE_SLEEPY_TIMER_THREAD): add a dependency
- against poll.
-
-Wed Mar 6 21:00:23 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread_pthread.c (USE_SLEEPY_TIMER_THREAD): use more accurate
- ifdef conditions.
-
-Sun Mar 3 02:30:36 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * thread_pthread.c (set_nonblock): new helper function for set
- O_NONBLOCK.
- * thread_pthread.c (rb_thread_create_timer_thread): set O_NONBLOCK
- to timer_thread_pipe[0] too.
-
-Sun Mar 10 09:12:51 2013 Tadayoshi Funaba <tadf@dotrb.org>
-
- * complex.c: described syntax of string form.
- * rational.c: ditto.
-
-Sat Mar 9 11:58:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * marshal.c (w_extended): check for prepended object.
- [ruby-core:53206] [Bug #8043]
-
-Sat Mar 9 08:36:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * load.c (features_index_add_single, rb_feature_p): store single index
- as Fixnum to reduce the number of arrays for the indexes. based on
- the patch by tmm1 (Aman Gupta) in [ruby-core:53216] [Bug #8048].
-
-Sat Mar 9 00:25:57 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * marshal.c (r_object0): load prepended objects. treat the class of
- extended object in the included modules as prepended singleton
- class. [ruby-core:53202] [Bug #8041]
-
-Fri Mar 8 19:44:00 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * man/rake.1, man/ruby.1: Use the Pa macro to make URLs stand out.
-
-Fri Mar 8 13:20:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/pathname/pathname.c (path_f_pathname): rdoc for Pathname()
-
-Fri Mar 8 12:00:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * man/rake.1: Document ENVIRONMENT variables on RAKE(1) manpage
-
-Fri Mar 8 10:44:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/webrick/httpproxy.rb: Fix typos in HTTPProxyServer [Bug #8013]
- Patch by Nobuhiro IMAI [ruby-core:53127]
-
-Fri Mar 8 03:16:15 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * class.c (rb_mod_ancestors): Include singleton_class in ancestors
- list [Feature #8035]
-
- * test/ruby/test_module.rb (class): test for above
-
- * test/ruby/marshaltestlib.rb (module): adapt test
-
- * NEWS: list change
-
-Thu Mar 7 14:21:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_compile_each): pass keyword arguments to zsuper,
- with current values. [ruby-core:53114] [Bug #8008]
-
-Thu Mar 7 12:53:47 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/commands/setup_command.rb: Install .pem files.
- * test/rubygems/test_gem_commands_setup_command.rb: Test for the
- above.
-
- * lib/rubygems/spec_fetcher.rb: Test HTTPS upgrade with URI::HTTPS,
- not URI::HTTP. Fixes bug in automatic HTTPS upgrade.
- * test/rubygems/test_gem_spec_fetcher.rb: Test for the above.
-
- * lib/rubygems.rb: Version 2.0.2
-
- * lib/rubygems/test_utilities.rb: Ensure scheme and uri class match.
-
-Thu Mar 7 10:39:04 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/rbinstall.rb (gem): Gem.ensure_gem_subdirectories now has mode
- option since r39607. refix of r38870.
-
-Wed Mar 6 13:14:28 2013 Eric Hodel <drbrain@segment7.net>
-
- * test/rubygems/test_gem_spec_fetcher.rb: Removed unused variable.
-
-Wed Mar 6 08:10:15 2013 Eric Hodel <drbrain@segment7.net>
-
- * test/rubygems/test_require.rb: Fix tests when 'a.rb' exists.
- [ruby-trunk - Bug #7749]
-
-Wed Mar 6 08:00:59 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems.rb: Allow specification of directory permissions.
- [ruby-trunk - Bug #7713]
- * test/rubygems/test_gem.rb: Test for the above.
-
-Wed Mar 6 07:40:21 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/commands/query_command.rb: Only fetch remote specs when
- showing details. [ruby-trunk - Bug #8019] RubyGems bug #487
- * lib/rubygems/remote_fetcher.rb: ditto.
- * lib/rubygems/security/policy.rb: ditto.
- * test/rubygems/test_gem_commands_query_command.rb: Test for the
- above.
-
- * lib/rubygems/security.rb: Make OpenSSL optional for RubyGems.
- * lib/rubygems/commands/cert_command.rb: ditto.
-
- * lib/rubygems/config_file.rb: Display file with YAML error, not
- ~/.gemrc
-
- * lib/rubygems/remote_fetcher.rb: Only create gem subdirectories when
- installing gems.
- * lib/rubygems/dependency_resolver.rb: ditto.
- * lib/rubygems/test_utilities.rb: ditto.
- * test/rubygems/test_gem_commands_fetch_command.rb: Test for the
- above.
-
- * lib/rubygems/spec_fetcher.rb: Only try to upgrade
- http://rubygems.org to HTTPS
- * test/rubygems/test_gem_spec_fetcher.rb: Test for the above.
-
- * lib/rubygems.rb: Update win_platform? check for JRuby compatibility.
-
- * test/rubygems/test_gem_installer.rb: Update for Ruby 1.9.2
- compatibility
-
-Wed Mar 6 01:19:28 2013 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * enumerator.c (enumerator_with_index, lazy_take): use INT2FIX(0)
- instead of INT2NUM(0).
-
- * ext/bigdecimal/bigdecimal.c (BigMath_s_exp): ditto.
-
- * ext/fiddle/function.c (function_call): ditto.
-
- * ext/openssl/ossl_x509store.c (ossl_x509store_initialize): ditto.
-
- * process.c (proc_getsid): ditto.
-
- * transcode.c (econv_finish): ditto.
-
-Tue Mar 5 21:36:43 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (rb_prepend_module): check redefinition of built-in optimized
- methods. [ruby-dev:47124] [Bug #7983]
-
- * vm.c (rb_vm_check_redefinition_by_prepend): ditto.
-
-Tue Mar 5 20:29:25 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (mnew): revert r39224. [ruby-core:53038] [Bug #7988]
-
-Tue Mar 5 20:23:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/intern.h (rb_check_arity): make a static inline
- function so it can be used as an expression and argc would be
- evaluated only once.
-
-Tue Mar 5 12:30:55 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems.rb: Bump version to 2.0.1 for upcoming bugfix release
-
- * lib/rubygems/ext/ext_conf_builder.rb: Restore ruby 1.8 compatibility
- for [Bug #7698]
- * test/rubygems/test_gem_installer.rb: Ditto.
-
- * lib/rubygems/package.rb: Restore ruby 1.8 compatibility.
-
- * test/rubygems/test_gem_dependency_installer.rb: Fix warnings
-
-Tue Mar 5 12:24:23 2013 Eric Hodel <drbrain@segment7.net>
-
- * enumerator.c (enumerator_with_index): Restore handling of a nil memo
- from r39594.
-
-Tue Mar 5 10:40:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/objspace/objspace.c (count_nodes): count also newly added nodes,
- and fix key for unknown node. patch by tmm1 (Aman Gupta) in
- [ruby-core:53130] [Bug #8014]
-
-Tue Mar 5 10:20:16 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enumerator.c (enumerator_with_index_i): allow Bignum as offset, to
- get rid of conversion exception and integer overflow.
- [ruby-dev:47131] [Bug #8010]
-
- * numeric.c (rb_int_succ, rb_int_pred): shortcut optimization for
- Bignum.
-
-Tue Mar 5 10:02:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/rubygems/ext/ext_conf_builder.rb (Gem::Ext::ExtConfBuilder.build):
- clear DESTDIR so RUBYARCHDIR and RUBYLIBDIR are not be overridden.
- [Bug #7698]
-
-Mon Mar 4 15:33:40 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/rubygems/ext/ext_conf_builder.rb (Gem::Ext::ExtConfBuilder.build):
- fix for unusual cases again. install to a temporary directory once
- and move installed files to the destination directory, if it is same
- as the current directory. [Bug #7698]
-
-Mon Mar 4 14:13:36 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * Makefile.in (miniruby, ruby): move MAINLIBC because linker arguments
- must appear after object files with newer versions of gcc. patch by
- tmm1 (Aman Gupta) in [ruby-core:53121] [Bug #8009]
-
-Mon Mar 4 10:23:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * encoding.c: Typo in Encoding overview by Tom Wardrop [GH fixes #255]
-
-Sun Mar 3 12:35:08 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (MakeMakefile#libpath_env): set runtime library path for
- the case rpath is disabled.
-
-Sun Mar 3 12:17:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/rubygems/ext/ext_conf_builder.rb
- (Gem::Ext::ExtConfBuilder.hack_for_obsolete_style_gems): remove
- circular dependencies in install-so too. [ruby-core:52882]
- [Bug #7698]
-
-Sun Mar 3 07:33:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/socket/tcpserver.c: Grammar for TCPServer.new from r39554
-
-Sun Mar 3 01:17:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/rubygems/ext/ext_conf_builder.rb
- (Gem::Ext::ExtConfBuilder.hack_for_obsolete_style_gems): remove
- circular dependencies for old style gems which locate extconf.rb on
- the toplevel. [ruby-core:53059] [ruby-trunk - Bug #7698]
-
- * lib/rubygems/ext/ext_conf_builder.rb (Gem::Ext::ExtConfBuilder.build):
- use RUBYOPT instead of -r option, and revert some tests. [Bug #7698]
-
- * lib/rubygems/ext/ext_conf_builder.rb (Gem::Ext::ExtConfBuilder.build):
- revert use of temporary directory for build, to work some buggy
- extconf.rb which cannot build outside the source directory.
- [ruby-core:53056] [Bug #7698]
-
-Sun Mar 3 00:04:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enc/depend (CPPFLAGS), lib/mkmf.rb (MakeMakefile#create_makefile):
- define RUBY_EXPORT for static-linked-ext mswin. [Bug #7960]
-
-Sat Mar 2 22:49:47 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/Makefile.sub (ENCOBJS, EXTOBJS, config.h): definitions for
- static-linked-ext. [Bug #7960]
-
-Sat Mar 2 17:34:19 2013 Tanaka Akira <akr@fsij.org>
-
- * lib/webrick/utils.rb: use Socket.tcp_server_sockets to create server
- sockets.
- fix [Bug #7100] https://bugs.ruby-lang.org/issues/7100
- reported by sho-h (Sho Hashimoto).
-
-Sat Mar 2 02:45:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * array.c: typo in comment patch by Nami-Doc [Github fixes #253]
-
-Sat Mar 2 01:33:17 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * Merge Onigmo 0fe387da2fee089254f6b04990541c731a26757f
- v5.13.3 [Bug#7972] [Bug#7974]
-
-Fri Mar 1 11:09:06 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/fileutils.rb: Revert r34669 which altered the way
- metaprogramming in FileUtils occurred. [ruby-trunk - Bug #7958]
-
- * test/fileutils/visibility_tests.rb: Refactored tests of FileUtils
- options modules to expose bug found in #7958
- * test/fileutils/test_dryrun.rb: ditto.
- * test/fileutils/test_nowrite.rb: ditto.
- * test/fileutils/test_verbose.rb: ditto.
-
-Fri Mar 1 09:18:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/psych.rb: specify in rdoc what object is returned in parser
- By Adam Stankiewicz [Github tenderlove/psych#133]
-
-Fri Mar 1 07:21:41 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/ext/builder.rb: Fix incompatibilities when installing
- extensions. Patch by Nobu.
- [ruby-trunk - Bug #7698] [ruby-trunk - Bug #7971]
- * lib/rubygems/ext/ext_conf_builder.rb: ditto.
- * lib/rubygems/installer.rb: ditto.
- * test/rubygems/test_gem_ext_ext_conf_builder.rb: Test for the above.
- * test/rubygems/test_gem_installer.rb: ditto.
-
- * lib/rubygems/commands/sources_command.rb: Prefer HTTPS over HTTP.
- * lib/rubygems/defaults.rb: ditto
- * lib/rubygems/dependency_resolver.rb: Ditto.
- * lib/rubygems/source.rb: ditto.
- * lib/rubygems/spec_fetcher.rb: ditto.
- * lib/rubygems/specification.rb: ditto.
- * lib/rubygems/test_utilities.rb: ditto.
- * test/rubygems/test_gem.rb: Test for the above.
- * test/rubygems/test_gem_commands_sources_command.rb: ditto.
- * test/rubygems/test_gem_dependency_resolver_api_set.rb: ditto.
- * test/rubygems/test_gem_remote_fetcher.rb: ditto.
- * test/rubygems/test_gem_source.rb: ditto.
- * test/rubygems/test_gem_spec_fetcher.rb: ditto.
-
-Fri Mar 1 03:25:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/psych/lib/psych.rb: rdoc for Psych overview by Adam Stankiewicz
- [Github tenderlove/psych#134]
-
-Thu Feb 28 22:57:48 2013 Koichi Sasada <ko1@atdot.net>
-
- * compile.c (iseq_compile_each): remove redundant trace(line)
- instruction. for example, at the following script
- def m()
- p:xyzzy
- 1
- 2
- end
- compiler ignores `1' because there is no effect. However,
- `trace(line)' instruction remains in bytecode.
- This modification removes such redundant trace(line) instruction.
-
- * test/ruby/test_iseq.rb: add a test.
-
-Thu Feb 28 22:23:27 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/raddrinfo.c (inspect_sockaddr): don't show that Unix
- domain socket filename is bigger than sizeof(sun_path).
- This limit is not rigid on some platforms such as Darwin and SunOS.
-
-Thu Feb 28 21:33:01 2013 WATANABE Hirofumi <eban@ruby-lang.org>
-
- * configure.in(AC_DISABLE_OPTION_CHECKING): avoid warning "WARNING:
- Unrecognized options: --with-PACKAGE".
-
-Thu Feb 28 20:22:04 2013 Koichi Sasada <ko1@atdot.net>
-
- * iseq.c (iseq_data_to_ary): fix condition.
- r34303 introduces a bug to avoid all line information from
- a result of ISeq#to_a. This is a regression problem from 2.0.0p0.
-
- * test/ruby/test_iseq.rb: add a test of lines after ISeq#to_a.
-
-Thu Feb 28 08:20:33 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/available_set.rb: Undent for style
-
- * lib/rubygems/dependency_installer.rb: Pick latest prerelease gem to
- install. Fixes RubyGems bug #468.
- * test/rubygems/test_gem_dependency_installer.rb: Test for the above.
-
- * lib/rubygems/dependency_installer.rb: Don't display "Done installing
- documentation" if documentation will not be installed.
- * lib/rubygems/rdoc.rb: ditto
-
- * lib/rubygems/dependency_list.rb: Use Array#concat for Ruby 1.x
- performance.
-
- * lib/rubygems/installer.rb: Use formatted program name when comparing
- executables. RubyGems pull request #471
- * test/rubygems/test_gem_installer.rb: Test for the above.
-
- * lib/rubygems/package.rb: Use more explicit feature check to work
- around JRuby bug #552
-
- * lib/rubygems/ssl_certs/GeoTrust_Global_CA.pem: Added GeoTrust root
- certificate.
-
- * test/rubygems/test_gem_source_list.rb: Use "example" instead of real
- hostname
-
-Thu Feb 28 05:57:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * thread.c: rdoc formatting for Thread, ThreadGroup, and ThreadError
-
-Thu Feb 28 02:42:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * vm.c: Typo in overview for example of Thread#status returning false
- Reported by Lee Jarvis
-
-Wed Feb 27 22:54:27 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/rubysocket.h (union_sockaddr): make it longer for SunOS
- and Darwin.
-
-Wed Feb 27 21:14:34 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/security.rb (REXML::Security): create.
- * lib/rexml/rexml.rb: move entity_expansion_limit and
- entity_expansion_text_limit accessors to ...
- * lib/rexml/security.rb: ... here.
- * lib/rexml/document.rb: use REXML::Security.
- * lib/rexml/text.rb: use REXML::Security.
- * test/rexml/test_document.rb: use REXML::Security.
-
-Wed Feb 27 19:53:32 2013 Benoit Daloze <eregontp@gmail.com>
-
- * vm.c (Thread): fix typos in overview
-
-Wed Feb 27 13:21:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * vm.c (Thread): Typo in overview, swap setting and getting
-
-Wed Feb 27 13:02:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * vm.c (Thread): Documentation overview of Thread class
-
-Wed Feb 27 12:57:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * thread.c (rb_thread_wakeup): rdoc formatting
-
-Wed Feb 27 12:53:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * thread.c (rb_thread_group): rdoc formatting
-
-Wed Feb 27 12:33:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/ostruct.rb: Typo in OpenStruct overview [Github Fixes #251]
- Patch by Chun-wei Kuo
-
-Wed Feb 27 12:13:32 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_exec.h (END_INSN): llvm-gcc may optimize out reg_cfp and cause
- Stack/cfp consistency error when the instruction doesn't use reg_cfp.
- Usually instructions use PUSH() but for example trace doesn't.
- This hack cause speed down but you shouldn't use llvm-gcc, use clang.
- [Bug #7938]
-
-Wed Feb 27 10:23:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * thread.c (thread_raise_m): rdoc formatting
-
-Tue Feb 26 23:32:44 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/document.rb: move entity_expansion_limit accessor to ...
- * lib/rexml/rexml.rb: ... here for consistency.
- * lib/rexml/document.rb (REXML::Document.entity_expansion_limit):
- deprecated.
- * lib/rexml/document.rb (REXML::Document.entity_expansion_limit=):
- deprecated.
-
-Tue Feb 26 23:26:13 2013 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/document.rb: move entity_expansion_text_limit accessor to ...
- * lib/rexml/rexml.rb: ... here to make rexml/text independent from
- REXML::Document. It causes circular require.
- * lib/rexml/document.rb (REXML::Document.entity_expansion_text_limit):
- deprecated.
- * lib/rexml/document.rb (REXML::Document.entity_expansion_text_limit=):
- deprecated.
- * lib/rexml/text.rb: add missing require "rexml/rexml" for
- REXML.entity_expansion_text_limit.
- Reported by Robert Ulejczyk. Thanks!!! [ruby-core:52895] [Bug #7961]
-
-Tue Feb 26 15:12:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/mkconfig.rb: reconstruct comma separated list values. a
- command line to Windows batch file is split not only by spaces
- and equal signs but also by commas and semicolons.
-
-Tue Feb 26 15:04:19 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (unexpand_shvar): get rid of non-portable shell
- behavior on OpenBSD, so no extra quotes. [Bug #7959]
-
-Tue Feb 26 10:24:49 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (IS_LABEL_POSSIBLE): allow labels for keyword arguments just
- after method definition without a parenthesis. [ruby-core:52820]
- [Bug #7942]
-
-Tue Feb 26 04:50:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * error.c: clarify reason for sleep in SignalException example
-
-Tue Feb 26 03:47:00 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * error.c: clarify a document of SignalException. Process.kill()
- doesn't have any guarantee when signal will be delivered.
- [Bug #7951] [ruby-core:52864]
-
-Mon Feb 25 23:51:04 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/version.h: bump RUBY_API_VERSION same as RUBY_VERSION.
-
-Mon Feb 25 21:03:34 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (str_byte_substr): don't set coderange if it's not known.
- [Bug #7954] [ruby-dev:47108]
-
-Mon Feb 25 16:47:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (realclean-local): miniprelude.c is made by srcs, so it
- should not removed by distclean but by realclean. [Bug #6807]
-
-Mon Feb 25 16:30:30 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/config_file.rb: Lazily load .gem/credentials to only
- check permissions when necessary. RubyGems bug #465
- * test/rubygems/test_gem_config_file.rb: Test for the above.
-
- * test/rubygems/test_gem_commands_push_command.rb: Remove duplicated
- test.
-
-Mon Feb 25 15:47:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enc/depend (ARFLAGS): VisualC++ linker does not allow spaces between
- output option and the output file name. [Bug #7950]
-
- * enc/depend (RANLIB): set default command to do nothing, or make the
- entire line a label on Windows.
-
-Mon Feb 25 14:41:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (MakeMakefile#init_mkmf): default libdirname to libdir.
-
- * tool/rbinstall.rb: ditto.
-
-Mon Feb 25 13:12:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (setup): find Setup file from target_os 1. by
- suffix (e.g. Setup.nacl, Setup.atheos), 2. by "platform"
- option (e.g. Setup.nt, Setup.emx), and 3. default Setup. And
- Setup.dj had been removed.
-
-Mon Feb 25 12:48:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * thread.c: Document Thread::new, clean up ::fork and mention calling
- super if subclassing Thread
-
-Mon Feb 25 12:38:50 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: don't test ss_family and ss_len member of
- struct sockaddr_storage. They are not used now except SunOS
- specific code.
-
-Mon Feb 25 11:03:38 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * configure.in (unexpand_shvar): Use the numeric comparison
- operator instead of '==' which is a ksh extension. [Bug #7941]
-
-Mon Feb 25 02:37:56 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket: define and use union_sockaddr instead of struct
- sockaddr_storage for less casts.
-
- * ext/socket/rubysocket.h (union_sockaddr): defined.
-
- * ext/socket/socket.c (sock_accept): use union_sockaddr.
- (sock_accept_nonblock): ditto.
- (sock_sysaccept): ditto.
- (sock_s_getnameinfo): ditto.
-
- * ext/socket/basicsocket.c (bsock_getsockname): ditto.
- (bsock_getpeername): ditto.
- (bsock_local_address): ditto.
- (bsock_remote_address): ditto.
-
- * ext/socket/ancdata.c (bsock_recvmsg_internal): ditto.
-
- * ext/socket/init.c (recvfrom_arg): ditto.
- (recvfrom_blocking): ditto.
- (rsock_s_recvfrom): ditto.
- (rsock_s_recvfrom_nonblock): ditto.
- (rsock_getfamily): ditto.
-
- * ext/socket/raddrinfo.c (rb_addrinfo_t): ditto.
- (ai_get_afamily): ditto.
- (inspect_sockaddr): ditto.
- (addrinfo_mdump): ditto.
- (addrinfo_mload): ditto.
- (addrinfo_getnameinfo): ditto.
- (addrinfo_ip_port): ditto.
- (extract_in_addr): ditto.
- (addrinfo_ipv6_to_ipv4): ditto.
- (addrinfo_unix_path): ditto.
-
- * ext/socket/tcpserver.c (tcp_accept): ditto.
- (tcp_accept_nonblock): ditto.
- (tcp_sysaccept): ditto.
-
- * ext/socket/ipsocket.c (ip_addr): ditto.
- (ip_peeraddr): ditto.
- (ip_s_getaddress): ditto.
-
-Sun Feb 24 21:15:05 2013 Tadayoshi Funaba <tadf@dotrb.org>
-
- * ext/date/date_core.c: [ruby-core:52303]
-
-Sun Feb 24 15:33:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * random.c (rb_random_ulong_limited): limit is inclusive, but generic
- rand method should return a number less than it, so increase for the
- difference. [ruby-core:52779] [Bug #7935]
-
-Sun Feb 24 15:32:36 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * random.c (rb_random_ulong_limited): limit is inclusive, but generic
- rand method should return a number less than it, so increase for the
- difference. [ruby-core:52779] [Bug #7935]
-
-Sun Feb 24 15:14:43 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/net/http.rb: Removed duplicate Accept-Encoding in Net::HTTP#get.
- [ruby-trunk - Bug #7924]
- * test/net/http/test_http.rb: Test for the above.
-
-Wed Feb 20 14:28:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * thread.c: Document ThreadGroup::Default
-
-Wed Feb 20 14:23:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * thread.c: Grammar for #backtrace_locations and ::handle_interrupt
-
-Sun Feb 24 13:35:57 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_call_method): block level control frame does not
- have method entry, so obtain the method entry from method top-level
- control frame to be compared with refined method entry.
- [ruby-core:52750] [Bug #7925]
-
-Wed Feb 20 13:23:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * object.c: Document methods receiving string and convert to symbol
- Patch by Stefan Rusterholz
- * vm_eval.c: ditto
- * vm_method.c: ditto
-
-Wed Feb 20 07:20:56 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * signal.c (sigsegv): suppress unused result warning. Because
- write(2) is marked __warn_unused_result__ on Linux glibc.
-
-Sun Feb 24 07:50:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_set_arguments): no keyword check if any keyword rest
- argument exists, even unnamed. [ruby-core:52744] [Bug #7922]
-
-Sat Feb 23 16:51:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * thread.c: Documentation for Thread#backtrace_locations
-
-Sat Feb 23 16:05:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * vm.c: Typo in ObjectSpace::WeakMap overview
-
-Sat Feb 23 16:00:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * thread.c: Improved rdoc for ::handle_interrupt, ::pending_interrupt?
- and #pending_interrupt?
-
-Sat Feb 23 12:26:43 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * misc/ruby-electric.el (ruby-electric-curlies)
- (ruby-electric-matching-char, ruby-electric-bar): Avoid electric
- insertion when there is a prefix argument.
-
- * misc/ruby-electric.el (ruby-electric-insert)
- (ruby-electric-cua-replace-region-p)
- (ruby-electric-cua-replace-region): Avoid electric insertion and
- fall back when cua-mode is enabled and a region is active.
-
-Sat Feb 23 12:35:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * array.c: Document #<=> return values and formatting
- * bignum.c: ditto
- * file.c: ditto
- * object.c: ditto
- * numeric.c: ditto
- * rational.c: ditto
- * string.c: ditto
- * time.c: ditto
-
-Sat Feb 23 10:50:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * array.c (rb_ary_diff, rb_ary_and, rb_ary_or): Document return order
- [RubySpec #7803]
-
-Sat Feb 23 10:17:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * object.c (rb_obj_comp): Documenting Object#<=> return values
- Patch by Stefan Rusterholz
-
-Sat Feb 23 09:48:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (file_s_fnmatch, fnmatch_brace): encoding-incompatible pattern
- and string do not match, instead of exception. [ruby-dev:47069]
- [Bug #7911]
-
-Sat Feb 23 08:57:46 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * doc/NEWS-*: Update NEWS from their respective branches
-
-Sat Feb 23 08:14:43 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * NEWS: many additions for Ruby 2.0.0
-
- * object.c: Add doc for Module.prepended
-
-Sat Feb 23 07:52:53 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * template/ruby.pc.in: reorder library flags which may refer library
- names. [Bug #7913]
-
-Fri Feb 22 23:46:20 2013 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * lib/rexml/document.rb (REXML::Document.entity_expansion_text_limit):
- fix a typo in comment in r39384.
-
-Fri Feb 22 18:31:46 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * lib/rexml/document.rb (REXML::Document.entity_expansion_text_limit):
- new attribute to read/write entity expansion text limit. the default
- limit is 10Kb.
-
- * lib/rexml/text.rb (REXML::Text.unnormalize): check above attribute.
-
-Fri Feb 22 17:36:23 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * test/test_rbconfig.rb (TestRbConfig): fix r39372.
- It must see RbConfig::CONFIG instead of CONFIG.
-
-Fri Feb 22 14:55:41 2013 Naohisa Goto <ngotogenome@gmail.com>
-
- * signal.c (ruby_abort): fix typo in r39354 [Bug #5014]
-
-Fri Feb 22 12:46:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * random.c (rb_random_ulong_limited): fix error message for negative
- value. [ruby-dev:47061] [Bug #7903]
-
-Fri Feb 22 11:36:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/test_rbconfig.rb (TestRbConfig): skip user defined values by
- configuration options. [Bug #7902]
-
-Fri Feb 22 11:33:42 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (MakeMakefile#init_mkmf): adjust default library path
- for multiarch. [Bug #7874]
-
-Fri Feb 22 11:10:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * enum.c (Enumerable#chunk: Improved examples, grammar, and formatting
- Patch by Dan Bernier and Rich Bruchal of newhaven.rb
- [Github documenting-ruby/ruby#8]
-
-Fri Feb 22 11:00:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * numeric.c: Examples and formatting for Numeric and Float
- Based on a patch by Zach Morek and Oren K of newhaven.rb
- [Github documenting-ruby/ruby#5]
-
-Fri Feb 22 07:04:41 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/installer.rb (build_extensions): Create extension
- install destination before building extension. Patch by Kenta Murata.
- [ruby-trunk - Bug #7897]
- * test/rubygems/test_gem_installer.rb: Test for the above.
-
-Fri Feb 22 06:30:57 2013 Eric Hodel <drbrain@segment7.net>
-
- * doc/globals.rdoc: Document what setting $DEBUG does.
-
- * doc/globals.rdoc: Added pointer to $-d for full documentation.
-
-Fri Feb 22 06:27:07 2013 Eric Hodel <drbrain@segment7.net>
-
- * doc/globals.rdoc: Document what setting $VERBOSE does. [Bug #7899]
-
- * doc/globals.rdoc: Added pointer to $-w and $-v for full
- documentation.
-
-Fri Feb 22 02:33:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/abbrev.rb: Add words parameter to Abbrev::abbrev
- Patch by Devin Weaver [Github documenting-ruby/ruby#7]
-
-Thu Feb 21 17:28:14 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/merger.rb: add interaction when only ChangeLog is modified.
-
-Thu Feb 21 16:34:46 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * signal.c (check_stack_overflow): extract duplicated code and get rid
- of declaration-after-statement. [Bug #5014]
-
-Thu Feb 21 14:14:13 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * signal.c (sigsegv): avoid to use async signal unsafe functions
- when nested sigsegv is happen.
- [Bug #5014] [ruby-dev:44082]
-
-Thu Feb 21 13:47:59 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * file.c (rb_group_member): added an error check. SUS says,
- getgroups(small_value) may return EINVAL.
-
-Thu Feb 21 13:37:07 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * process.c (RB_MAX_GROUPS): moved to
- * internal.h (RB_MAX_GROUPS): here.
-
- * file.c (rb_group_member): use RB_MAX_GROUPS instead of
- RUBY_GROUP_MAX. They are the same.
-
-Thu Feb 21 13:15:40 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * file.c (access_internal): removed.
- * file.c (rb_file_readable_real): use access() instead of
- access_internal().
- * file.c (rb_file_writable_real): ditto.
- * file.c (rb_file_executable_real): ditto.
-
-Thu Feb 21 13:04:59 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * file.c (eaccess): use access() when not using setuid nor setgid.
- This is minor optimization.
-
-Thu Feb 21 12:56:19 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * file.c (rb_group_member): get rid of NGROUPS dependency.
- [Bug #7886] [ruby-core:52537]
-
-Thu Feb 21 12:45:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (ruby_init_loadpath_safe): try two levels upper for stripping
- libdir name. [Bug #7874]
-
- * configure.in (libdir_basename): expand with multiarch in configure,
- not to defer the expansion till ruby.pc.in and mkmf.rb. [Bug #7874]
-
- * configure.in (libdir_basename): also -rpath and -install_name flags
- are affected when libruby directory changes. [Bug #7874]
-
-Wed Feb 20 19:27:02 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (HAVE_RB_SCAN_ARGS_OPTIONAL_HASH): for
- rb_scan_args() optional hash feature. [Bug #7861]
-
-Wed Feb 20 18:02:26 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (target_os): do not strip -gnu suffix on Linux if
- --target is given explicitly. [Bug #7874]
-
- * configure.in (libdirname): adjust library path name which libruby
- files will be installed. [Bug #7874]
-
- * tool/rbinstall.rb (libdir): ditto.
-
-Wed Feb 20 13:37:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/pty/pty.c: Documentation for the PTY module
-
-Wed Feb 20 12:18:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * object.c: Document Data class [Bug #7890] [ruby-core:52549]
- Patch by Matthew Mongeau
-
-Wed Feb 20 11:50:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/mutex_m.rb: Add rdoc for Mutex_m module
-
-Wed Feb 20 09:34:43 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/commands/update_command.rb: Create the installer after
- options are processed. [ruby-trunk - Bug #7779]
- * test/rubygems/test_gem_commands_update_command.rb: Test for the
- above.
-
-Wed Feb 20 07:51:19 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/installer.rb: Use gsub instead of gsub! to avoid
- altering @bin_dir. Fixes tests on windows. [ruby-trunk - Bug #7885]
-
-Tue Feb 19 20:50:00 2013 Kenta MURATA <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.gemspec: bump to 1.2.0.
- [ruby-core:51777] [Bug #7761]
-
-Tue Feb 19 13:07:25 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * ext/syslog/syslog.c (Init_syslog): Define inspect as a singleton
- method and remove it as an instance method. [Bug #6502]
-
-Tue Feb 19 12:30:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * object.c: rdoc formatting for Kernel#Array()
- * array.c: Add rdoc for Array() method to Creating Arrays section
-
-Tue Feb 19 10:35:52 2013 Eric Hodel <drbrain@segment7.net>
-
- * ext/openssl/ossl.c (class OpenSSL): Use only inner parenthesis in
- create_extension examples.
-
-Tue Feb 19 10:27:12 2013 Eric Hodel <drbrain@segment7.net>
-
- * ext/openssl/ossl.c (class OpenSSL): Fixed ExtensionFactory example.
- Patch by Richard Bradley. [ruby-trunk - Bug #7551]
-
-Tue Feb 19 08:32:11 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_eval.c (vm_call0_body): check interrupts after method dispatch
- from C methods. [Bug #7878]
-
-Tue Feb 19 08:14:40 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/installer.rb: Fixed placement of executables with
- --user-install. [ruby-trunk - Bug #7779]
- * test/rubygems/test_gem_installer.rb: Test for above.
-
-Tue Feb 19 06:04:06 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_dump: FreeBSD ports' libexecinfo's backtrace(3) can't trace
- beyond signal trampoline, and as described in r38342 it can't
- trace on -O because it see stack frame pointers.
- libunwind unw_backtrace see dwarf information in the binary
- and it works with -O (without frame pointers).
-
- * configure.in: remove r38342's hack and check libunwind.
-
-Tue Feb 19 04:26:29 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: check whether backtrace(3) works well or not.
-
- * vm_dump.c: set HAVE_BACKTRACE 0 if BROKEN_BACKTRACE.
-
-Mon Feb 18 16:30:18 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/ipaddr.rb (IPAddr#in6_addr): Fix a typo with the closing
- parenthesis.
-
-Mon Feb 18 12:32:24 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/ipaddr.rb (IPAddr#in6_addr): Fix the parser so that it can
- recognize IPv6 addresses with only one edge 16-bit piece
- compressed, like [::2:3:4:5:6:7:8] or [1:2:3:4:5:6:7::].
- [Bug #7477]
-
-Mon Feb 18 10:09:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (unexpand_shvar): regularize a shell variable by
- unexpanding shell variables in it.
-
-Sun Feb 17 20:55:44 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compar.c (rb_invcmp): compare by inversed comparison, with preventing
- from infinite recursion. [ruby-core:52305] [Bug #7870]
-
- * string.c (rb_str_cmp_m), time.c (time_cmp): get rid of infinite
- recursion.
-
-Sun Feb 17 17:23:22 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb: remove extra topdir in VPATH, which was in
- win32/Makefile.sub for some reason and moved from there.
- [ruby-dev:46998] [Bug #7864]
-
-Sun Feb 17 01:19:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * ext/psych/lib/psych/y.rb: Document Kernel#y by Adam Stankiewicz
- [Github tenderlove/psych#127]
-
-Sun Feb 17 00:52:14 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/mkconfig.rb: remove prefix from rubyarchdir.
- r39267 expands variables, it changes expansion timing,
- breaks RbConfig::CONFIG["includedir"] and building
- extension libraries with installed ruby.
-
-Sat Feb 16 20:51:17 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * vm.c (ENV_IN_HEAP_P): fix off-by-one error.
-
-Sat Feb 16 20:47:16 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * configure.in (LIBRUBY_DLDFLAGS): Fix a bug where --with-opt-dir
- options given were not reflected to LIBRUBY_DLDFLAGS on many
- platforms including Linux and other GNU-based systems, NetBSD,
- AIX and BeOS.
-
-Sat Feb 16 20:43:20 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/ancdata.c (rsock_recvmsg): ignore truncated part of
- socket address returned from recvmsg().
-
- * ext/socket/init.c (recvfrom_blocking): ignore truncated part of
- socket address returned from recvfrom().
- (rsock_s_recvfrom_nonblock): ditto.
-
-Sat Feb 16 20:05:26 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * test/ruby/test_thread.rb: fixed typo
- patched by Hiroki Matsue via https://github.com/ruby/ruby/pull/248
-
-Sat Feb 16 16:08:35 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm.c (rb_thread_mark): mark a working Proc of bmethod
- (a method defined by define_method) even if the method was removed.
- We could not trace working Proc object which represents the body
- of bmethod if the method was removed (alias/undef/overridden).
- Simply, it was mark miss.
- This patch by Kazuki Tsujimoto. [Bug #7825]
-
- NOTE: We can brush up this marking because we do not need to mark
- `me' on each living control frame. We need to mark `me's
- only if `me' was free'ed. This is future work after Ruby 2.0.0.
-
- * test/ruby/test_method.rb: add a test.
-
-Sat Feb 16 15:45:56 2013 Koichi Sasada <ko1@atdot.net>
-
- * proc.c (rb_binding_new_with_cfp): create binding object even if
- the frame is IFUNC. But return a ruby-level binding to keep
- compatibility.
- This patch fix degradation introduced from r39067.
- [Bug #7774] [ruby-dev:46960]
-
- * test/ruby/test_settracefunc.rb: add a test.
-
-Sat Feb 16 13:40:13 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (shvar_to_cpp): do not substitute exec_prefix itself
- with RUBY_EXEC_PREFIX, which cause recursive definition.
- [ruby-core:52296] [Bug #7860]
-
-Sat Feb 16 13:13:04 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/io/console/io-console.gemspec: bump to 0.4.2. now explicitly
- requires ruby 1.9.3 or later. [Bug #7847]
-
- * ext/io/console/console.c (console_dev): compatibility with ruby 1.8.
-
- * ext/io/console/console.c (rawmode_opt, console_dev): compatibility
- with ruby 1.9. [ruby-core:52220] [Bug #7847]
-
-Sat Feb 16 12:45:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: unexpand arch sitearch and exec_prefix values, so
- directly specified bindir, libdir, rubyprefix, etc can be properly
- substituted. [ruby-core:52296] [Bug #7860]
-
-Sat Feb 16 12:15:20 2013 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * parse.y: add dtrace probe for symbol create.
-
- * probes.d: ditto
-
-Sat Feb 16 09:27:37 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: don't test sys/feature_tests.h which is not
- used now.
- It was included in r7901 as "bug of gcc 3.0 on Solaris 8 ?".
-
-Sat Feb 16 09:24:37 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: reorder header tests to consider inclusion
- order in rubysocket.h.
-
-Sat Feb 16 08:42:58 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in, ext/socket/extconf.rb: test netinet/in_systm.h in
- ext/socket/extconf.rb instead of configure.in.
-
- Originally, netinet/in_systm.h is included for NextStep, OpenStep,
- and Rhapsody. [ruby-core:1596]
-
-Sat Feb 16 07:55:40 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: don't test xti.h here.
-
- * ext/socket/extconf.rb: test xti.h here.
-
- Originally, xti.h is included for IRIX [ruby-core:14447].
-
-Sat Feb 16 07:16:49 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: test struct sockaddr_un and its member,
- sun_len.
-
- * ext/socket/sockport.h (INIT_SOCKADDR_UN): new macro defined.
-
- * ext/socket/socket.c (sock_s_pack_sockaddr_un): use INIT_SOCKADDR_UN.
-
- * ext/socket/unixsocket.c (rsock_init_unixsock): ditto.
-
- * ext/socket/raddrinfo.c (init_unix_addrinfo): ditto.
- (addrinfo_mload): ditto.
-
-Sat Feb 16 07:05:59 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/sockport.h (INIT_SOCKADDR_IN): don't need family
- argument. it is always AF_INET.
-
- * ext/socket/raddrinfo.c (make_inetaddr): follow INIT_SOCKADDR_IN
- change.
- (addrinfo_ipv6_to_ipv4): ditto.
-
-Sat Feb 16 04:21:07 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/socket/extconf.rb: workaround for mswin/mingw build problem.
- sendmsg emulation in win32/win32.c is not enough.
-
-Sat Feb 16 00:19:20 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: use all all tested available headers for
- have_func.
-
-Fri Feb 15 22:21:37 2013 Akinori MUSHA <knu@iDaemons.org>
-
- * configure.in: Fix a bug introduced in r38342 that the cflagspat
- substitution is messed up by the way CFLAGS and optflags are
- modified, which affected FreeBSD and NetBSD/amd64 when
- configured to use libexecinfo. This bug resulted in CFLAGS and
- CXXFLAGS in RbConfig::CONFIG having warnflags expanded in them,
- forcing third-party C/C++ extensions to follow what warnflags
- demands, like ANSI/ISO-C90 conformance. ref [Bug #7101]
-
-Fri Feb 15 20:29:11 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/sockport.h (SET_SIN_LEN): defined for strict-aliasing
- rule.
- (INIT_SOCKADDR_IN): ditto.
-
- * ext/socket/raddrinfo.c (make_inetaddr): use INIT_SOCKADDR_IN.
- (addrinfo_ipv6_to_ipv4): ditto.
-
-Fri Feb 15 18:24:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (MakeMakefile#try_run): bail out explicitly if cross
- compiling, because it cannot work of course.
-
-Fri Feb 15 12:34:58 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: test struct sockaddr_storage directly.
-
- * ext/socket/rubysocket.h: use HAVE_TYPE_STRUCT_SOCKADDR_STORAGE.
-
-Fri Feb 15 12:26:13 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/getaddrinfo.c (GET_AI): don't cast 1st argument for
- INIT_SOCKADDR.
-
-Fri Feb 15 08:12:11 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/sockport.h (SET_SS_LEN): removed.
- (SET_SIN_LEN): removed.
- (INIT_SOCKADDR): new macro.
-
- * ext/socket/ancdata.c (extract_ipv6_pktinfo): use INIT_SOCKADDR.
-
- * ext/socket/raddrinfo.c (make_inetaddr): use INIT_SOCKADDR.
- (addrinfo_ipv6_to_ipv4): ditto.
-
- * ext/socket/getaddrinfo.c (GET_AI): use INIT_SOCKADDR.
-
-Fri Feb 15 07:49:27 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rdoc.rb: Update to release version of 4.0.0
-
- * lib/rubygems.rb: Update to release version of 2.0.0
-
-Fri Feb 15 07:07:27 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/sockport.h (SA_LEN): removed because unused now.
- (SS_LEN): ditto.
- (SIN_LEN): ditto.
-
-Thu Feb 14 10:45:31 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * test/ruby/test_process.rb (test_setsid): Added a workaround for
- MacOS X. Patch by nagachika. [Bug #7826] [ruby-core:52126]
-
-Fri Feb 15 00:15:31 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/sockport.h (VALIDATE_SOCKLEN): new macro to validate
- sa_len member of 4.4BSD socket address.
-
- * ext/socket/getnameinfo.c (getnameinfo): use VALIDATE_SOCKLEN,
- instead of SA_LEN.
-
- * ext/socket/socket.c (sock_s_getnameinfo): use VALIDATE_SOCKLEN
- instead of SS_LEN.
-
-Thu Feb 14 22:25:54 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/socket.c (sockaddr_len): extracted from sockaddr_obj.
- (sockaddr_obj): add an argument to length of socket address.
- (socket_s_ip_address_list): call sockaddr_obj with actual socket
- address length if given, use sockaddr_len otherwise.
-
-Thu Feb 14 20:11:23 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket: always operate length of socket address companion with
- socket address.
-
- * ext/socket/rubysocket.h (rsock_make_ipaddr): add an argument for
- socket address length.
- (rsock_ipaddr): ditto.
-
- * ext/socket/ipsocket.c (ip_addr): pass length to rsock_ipaddr.
- (ip_peeraddr): ditto.
- (ip_s_getaddress): pass length to rsock_make_ipaddr.
-
- * ext/socket/socket.c (make_addrinfo): pass length to rsock_ipaddr.
- (sock_s_getnameinfo): pass actual address length to rb_getnameinfo.
- (sock_s_unpack_sockaddr_in): pass length to rsock_make_ipaddr.
-
- * ext/socket/init.c (rsock_s_recvfrom): pass length to rsock_ipaddr.
- (rsock_s_recvfrom_nonblock): ditto.
-
- * ext/socket/tcpsocket.c (tcp_sockaddr): pass length to
- rsock_make_ipaddr.
-
- * ext/socket/raddrinfo.c (make_ipaddr0): add an argument for socket
- address length. pass the length to rb_getnameinfo.
- (rsock_ipaddr): ditto.
- (rsock_make_ipaddr): add an argument for socket address length.
- pass the length to make_ipaddr0.
- (make_inetaddr): pass length to make_ipaddr0.
- a local variable renamed.
- (host_str): a local variable renamed.
- (port_str): ditto.
-
-Thu Feb 14 14:31:43 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/net/http.rb: Removed OpenSSL dependency from Net::HTTP.
-
- * test/net/http/test_http.rb: Remove Zlib dependency from tests.
- * test/net/http/test_http_request.rb: ditto.
-
-Thu Feb 14 11:08:15 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (include_modules_at): detect cyclic prepend with original
- method table. [ruby-core:52205] [Bug #7841]
-
-Thu Feb 14 10:30:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_method.c: call method_removed hook on called class, not on
- prepending iclass. [ruby-core:52207] [Bug #7843]
-
-Thu Feb 14 10:05:57 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/net/http: Do not handle Content-Encoding when the user sets
- Accept-Encoding. This allows users to handle Content-Encoding for
- themselves. This restores backwards-compatibility with Ruby 1.x.
- [ruby-trunk - Bug #7831]
- * lib/net/http/generic_request.rb: ditto.
- * lib/net/http/response.rb: ditto
- * test/net/http/test_http.rb: Test for the above.
- * test/net/http/test_http_request.rb: ditto.
- * test/net/http/test_httpresponse.rb: ditto.
-
-Thu Feb 14 08:18:47 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: don't define HAVE_SA_LEN and HAVE_SA_LEN.
- use HAVE_STRUCT_SOCKADDR_SA_LEN and HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- instead.
-
-Wed Feb 13 20:59:48 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: don't define socklen_t here, just test.
-
- * ext/socket/rubysocket.h: define socklen_t if not available.
-
-Wed Feb 13 18:37:50 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (mnew): skip prepending modules and return the method bound
- on the given class. [ruby-core:52160] [Bug #7836]
-
-Wed Feb 13 18:11:59 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (method_original_name): new methods Method#original_name and
- UnboundMethod#original_name. [ruby-core:52048] [Bug #7806]
- [EXPERIMENTAL]
-
- * proc.c (method_inspect): show the given name primarily, and
- original_id if aliased. [ruby-core:52048] [Bug #7806]
-
-Wed Feb 13 17:56:39 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (warnflags): disable -Werror by default unless
- development. [ruby-core:52131] [Bug #7830]
-
-Wed Feb 13 06:05:52 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems.rb: Return BINARY strings from Gem.gzip and Gem.gunzip.
- Fixes intermittent test failures. RubyGems issue #450 by Jeremey
- Kemper.
- * test/rubygems/test_gem.rb: Test for the above.
-
-Wed Feb 13 05:49:21 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: test functions just after struct members.
-
-Tue Feb 12 12:02:35 2013 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/json: merge JSON 1.7.7.
- This includes security fix. [CVE-2013-0269]
- https://github.com/flori/json/commit/d0a62f3ced7560daba2ad546d83f0479a5ae2cf2
- https://groups.google.com/d/topic/rubyonrails-security/4_YvCpLzL58/discussion
-
-Mon Feb 11 23:08:48 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: enable rb_cv_page_size_log test for MirOS BSD.
-
-Mon Feb 11 20:06:38 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: use -pthread on mirbsd*.
-
-Mon Feb 11 16:07:09 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: add SOLIBS and LIBRUBY_SO definition for mirbsd*.
-
-Mon Feb 11 13:17:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (rubysitearchprefix): sitearchdir and vendorarchdir
- should use sitearch, not arch. [ruby-dev:46964] [Bug #7823]
-
- * win32/Makefile.sub (config.status): site and vendor directories
- should use sitearch, not arch. [ruby-dev:46964] [Bug #7823]
-
-Mon Feb 11 12:31:25 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: move OS specific header/function knowledge before
- automatic header tests.
-
-Mon Feb 11 11:04:29 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: move the test for -march=i486 just after
- RUBY_UNIVERSAL_ARCH/RUBY_DEFAULT_ARCH.
-
-Sun Feb 10 23:42:26 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: test structure members just after types test.
-
-Sun Feb 10 20:58:17 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: test types just after headers test.
-
-Sun Feb 10 16:00:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/rake/doc/MIT-LICENSE: Add license file from upstream
- * lib/rake/doc/README.rdoc: Link to license file from Rake README
- * lib/rake/version.rb: Include README rdoc for Rake module overview
-
-Sun Feb 10 15:26:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/rake/doc/*: Sync Rake rdoc files from upstream
-
-Sun Feb 10 15:50:02 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * vm_exec.h (DISPATCH_ARCH_DEPEND_WAY): use __asm__ __volatile__
- instead of asm volatile.
-
-Sun Feb 10 15:50:02 2013 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * gc.h (SET_MACHINE_STACK_END): use __volatile__ instead of volatile.
-
-Sun Feb 10 14:25:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * doc/rake/, lib/rake/doc/: Move Rake rdoc files to lib/rake
-
-Sun Feb 10 12:10:25 2013 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: test headers at first.
-
-Sun Feb 10 12:00:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * doc/rake/*: Removed stale Rake static files
-
-Sun Feb 10 09:10:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * lib/pp.rb, lib/prettyprint.rb: Documentation for PP and PrettyPrint
- Based on a patch by Vincent Batts [ruby-core:51253] [Bug #7656]
-
-Sat Feb 9 21:11:21 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: move header files check to the beginning of
- "header and library section".
- test rlim_t with sys/types.h and sys/time.h for MirOS BSD.
- sys/types.h and sys/time.h is guarded by #ifdef and the above
- move is required for this change.
-
-Sat Feb 9 17:45:58 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in, version.c: prevent duplicated load paths by empty
- version string, it does not work right now.
-
-Sat Feb 9 17:38:41 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: fix arch parameters in help message. [Bug #7804]
-
-Sat Feb 9 13:13:00 2013 Zachary Scott <zachary@zacharyscott.net>
-
- * vm_trace.c: Note about TracePoint events set, and comment on
- Kernel#set_trace_func to prefer new TracePoint API
-
-Sat Feb 9 10:07:47 2013 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * BSDL: update copyright notice for 2013.
-
-Sat Feb 9 09:24:38 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/package/old.rb: Fix behavior only on ruby 1.8.
-
- * lib/rubygems/package.rb: Include checksums.yaml.gz signatures for
- verification.
- * test/rubygems/test_gem_package.rb: Test for the above.
-
-Sat Feb 9 01:23:24 2013 Tanaka Akira <akr@fsij.org>
-
- * test/fiddle/helper.rb: specify libc and libm locations for MirOS BSD.
-
- * test/dl/test_base.rb: ditto.
-
-Fri Feb 8 23:25:33 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: change CFLAGS temporally to test
- ARCH_FLAG="-march=i486".
-
-Fri Feb 8 21:19:41 2013 Tanaka Akira <akr@fsij.org>
-
- * configure.in: don't define ARCH_FLAG="-march=i486" if it causes
- compilation problem.
-
-For the changes before 2.0.0, see doc/ChangeLog-2.0.0
-For the changes before 1.9.3, see doc/ChangeLog-1.9.3
-For the changes before 1.8.0, see doc/ChangeLog-1.8.0
-
-Local variables:
-coding: us-ascii
-add-log-time-format: (lambda ()
- (let* ((time (current-time))
- (system-time-locale "C")
- (diff (+ (cadr time) 32400))
- (lo (% diff 65536))
- (hi (+ (car time) (/ diff 65536))))
- (format-time-string "%a %b %e %H:%M:%S %Y" (list hi lo) t)))
-indent-tabs-mode: t
-tab-width: 8
-change-log-indent-text: 2
-end:
-vim: tabstop=8 shiftwidth=2
diff --git a/doc/ChangeLog/ChangeLog-2.2.0 b/doc/ChangeLog/ChangeLog-2.2.0
deleted file mode 100644
index 0edcf0122b..0000000000
--- a/doc/ChangeLog/ChangeLog-2.2.0
+++ /dev/null
@@ -1,12157 +0,0 @@
-Thu Dec 25 16:01:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (rb_file_expand_path_internal): drop characters ignored
- by filesystem on Mac OS X.
-
-Thu Dec 25 15:36:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (replace_real_basename): get the real name and replace the
- base name with it by getattrlist(2) if available.
- suggested by Matthew Draper at [ruby-core:67116]. [Bug #10015]
-
- * dir.c (glob_helper): get the real name of the whole path, not
- only the last name.
-
-Thu Dec 25 13:59:17 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (NET_LUID): include also ifdef.h as a workaround of
- a bug in mingw-w64 header. [ruby-core:67103] [Bug #10640]
-
-Thu Dec 25 12:47:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (gettable_gen): warn possible reference to a local
- variable defined in a past scope.
-
-Thu Dec 25 10:09:14 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/io/console/console.c (console_dev): id_console is not a
- constant name, use rb_const_remove() to get rid of NameError.
-
-Thu Dec 25 09:18:55 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/resolv/test_dns.rb (TestResolvDNS#test_query_ipv4_address):
- set timeout for recvfrom because if client thread is crashed, it
- waits infinity.
-
-Thu Dec 25 08:42:11 2014 Eric Wong <e@80x24.org>
-
- * lib/uri/generic.rb (split_userinfo): fstring for 1-byte split
- (set_port): reduce bytecode size
- (check_path): reduce garbage via opt_str_freeze
- (query=): ditto
- (fragment=): ditto
- [misc #10628]
- * lib/uri/rfc3986_parser.rb (regexp): cache as attr
- (initialize): setup and freeze regexp attr once
- (split): reduce bytecode size, use opt_str_freeze
- (parse): minor bytecode and garbage reduction
- (default_regexp): rename for initialize
-
-Wed Dec 24 20:38:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (glob_make_pattern): restrict searching case-insensitive
- name from the filesystem to only last part, for the performance.
- [ruby-core:63591] [Bug #10015]
-
-Wed Dec 24 18:21:27 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: remove unused rb_objspace_t::rgengc::old_objects_at_gc_start.
-
-Wed Dec 24 13:25:22 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/redmine-backporter.rb: require view_changesets permission.
-
-Wed Dec 24 13:00:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/downloader.rb (Downloader.download): fix the exception to
- re-raise. initialize methods of subclasses of Exception may
- have different parameters. [ruby-core:67086] [Bug #10639]
-
-Wed Dec 24 12:16:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.h (rb_data_type_t): revert r48647 and revise parent member.
- [ruby-core:66969] [Bug #10621]
-
-Wed Dec 24 05:40:52 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/downloader.rb: use config.guess in gcc repo.
-
-Wed Dec 24 11:50:19 2014 Koichi Sasada <ko1@atdot.net>
-
- * hash.c (rb_hash_delete): return Qnil if there are no corresponding
- entry. [Bug #10623]
-
- * hash.c (rb_hash_delete_entry): try delete and return Qundef if there
- are no corresponding entry.
-
- * internal.h: add rb_hash_delete_entry()'s declaration.
-
- * symbol.c: use rb_hash_delete_entry().
-
- * thread.c: use rb_hash_delete_entry().
-
- * ext/-test-/hash/delete.c: use rb_hash_delete_entry().
-
-Wed Dec 24 09:35:11 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/fiddle/extconf.rb: remove ffitarget.h generated by configure on
- mswin, because it's not normal file (cygwin's symlink) and have
- system attribute.
-
-Wed Dec 24 05:40:52 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/downloader.rb: support ruby 1.8.
-
-Wed Dec 24 02:44:06 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/net/http/response.rb (Net::HTTPResponse): require one or more
- spaces [Bug #10591].
- by leriksen <leif.eriksen.au@gmail.com>
- https://github.com/ruby/ruby/pull/782 fix GH-782
- NOTE: graph.facebook.com returns without SP Reason-Phrase.
-
-Wed Dec 24 02:12:22 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/make-snapshot (package): VCS#branch_list expects glob a
- pattern string but not a regexp. based on the patch by Vit
- Ondruch. in [ruby-core:67064]. [Bug #10636]
-
- * tool/vcs.rb (VCS::SVN#branch_list): strip newlines.
-
- * tool/vcs.rb (VCS::GIT.get_revisions): retrieve modified time
- from toplevel log too.
-
- * tool/vcs.rb (VCS::GIT#branch_list): yield for each lines.
-
-Wed Dec 24 00:23:13 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * tool/extlibs.rb (do_extract): the pipe should be binmode.
-
-Wed Dec 24 00:21:44 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * Makefile.in, common.mk: move common-srcs to Makefile.in because
- it breaks build on mswin.
-
-Wed Dec 24 00:04:45 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * lib/open-uri.rb (OpenURI.open_http): accept multiple certs path in
- ssl_ca_certs.
-
- * tool/downloader.rb: use certs of rubygems for downloading gems.
-
-Tue Dec 23 22:39:11 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/fiddle/extlibs: libffi-3.2.1 and patch for mswin.
-
-Tue Dec 23 22:04:38 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/generic.rb (URI::Generic#query=): don't escape [\]^
- on both rfc2396 and rfc3986. [Bug #10619]
-
-Tue Dec 23 16:03:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32/lib/win32/registry.rb (Win32::Registry::Error#initialize):
- try en_US message if the default message cannot be encoded to
- locale. [ruby-core:65295] [Bug #10300]
-
-Tue Dec 23 11:42:14 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/openssl/ossl_cipher.c (ossl_cipher_update_long): update huge
- data gradually not to exceed INT_MAX. workaround of OpenSSL API
- limitation. [ruby-core:67043] [Bug #10633]
-
-Mon Dec 22 21:30:16 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * test/win32ole/test_win32ole_event.rb: some tests are
- executed on standard Windows OS without ADO.
-
-Mon Dec 22 14:08:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * signal.c (received_signal): fix condition to define.
- [ruby-core:67032] [Bug #10629]
-
-Sun Dec 21 10:51:51 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * test/win32ole/test_win32ole_event.rb: test_s_new_exception is
- executed on standard Windows OS without ADO.
-
-Sun Dec 21 08:35:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (jemalloc): fix option argument, should use
- `$withval` but not `yes` always. [ruby-core:66994] [Bug #10625]
-
- * configure.in (jemalloc): defer adding the liner option to get
- rid of linking contest against jemalloc, so that it works
- without runtime dynamic load path.
-
-Sat Dec 20 17:49:03 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/tmpdir.rb (Dir.mktmpdir): Accept nil again, as Ruby 2.1.
- [ruby-core:66943] [Bug #10616] Fixed by Alex Slynko.
-
-Sat Dec 20 11:22:58 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/fiddle/depend, ext/fiddle/extconf.rb: try to build bundled
- libffi if existing.
-
-Sat Dec 20 05:21:00 2014 Eric Wong <e@80x24.org>
-
- * test/test_weakref.rb (test_repeated_object_leak): increase timeout
- [Bug #10618]
-
-Fri Dec 19 22:33:13 2014 Tanaka Akira <akr@fsij.org>
-
- * tool/update-deps: Use $(hdrdir) if possible.
-
-Fri Dec 19 22:10:00 2014 Kenta Murata <mrkn@cookpad.com>
-
- * ext/bigdecimal/depend: Fix dependencies to make bigdecimal
- installable by rubygems.
-
- * ext/bigdecimal/bigdecimal.gemspec: version 1.2.6.
-
-Fri Dec 19 20:00:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (PRIsVALUE): put a space after string
- literals not to be confused with C++11 string literal suffix.
- https://github.com/ruby/ruby/commit/a9f3eb7#commitcomment-9040169
-
-Fri Dec 19 15:36:02 2014 Simon Genier <simon.genier@shopify.com>
-
- * hash.c (hash_equal): prefer true than the result of implicit
- conversion from int returned by rb_eql() to VALUE. [Fix GH-789]
-
-Thu Dec 18 17:45:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (rb_cv_binary_elf): get rid of -e option of cat
- which is not available on BusyBox, use tr instead.
- [ruby-core:64824] [Bug #10210]
-
-Thu Dec 18 14:25:17 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * signal.c (ruby_signal): since SIGKILL is not supported by MSVCRT,
- should be treated before calling signal(3).
- [Bug #10615]
-
-Wed Dec 17 12:20:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (rb_method_for_self_aref, rb_method_for_self_aset):
- move from iseq.c to build from node instead of arrays.
-
-Wed Dec 17 10:50:09 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/gdbm/test_gdbm.rb: Added test for each_key called without a block.
- Patch by @joeyates [fix GH-783]
-
-Wed Dec 17 10:18:42 2014 Koichi Sasada <ko1@atdot.net>
-
- * compile.c (iseq_compile_each): check
- iseq->compile_data->option->specialized_instruction for opt_* insn.
-
- * test/ruby/test_iseq.rb: check no specialized_instructions option.
-
-Wed Dec 17 09:48:57 2014 Eric Wong <e@80x24.org>
-
- * compile.c (iseq_compile_each): only emit opt_str_freeze,
- opt_aref_with, and opt_aset_with insn when no block is given
- [Bug #10557] [ruby-core:66595]
- * test/ruby/test_optimization.rb (test_block_given_aset_aref):
- new test for bug thanks to Bartosz Kopinski.
- (test_string_freeze): additional assertion for object_id
-
-Wed Dec 17 01:06:47 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/win32/lib/Win32API.rb (Win32API#call): need to splat. hmm, when
- was this broken?
-
-Tue Dec 16 15:18:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * iseq.c (rb_method_for_self_aref, rb_method_for_self_aset): call
- accessor functions directly, not to be affected by [] and []=
- methods. [ruby-core:66846] [Bug #10601]
-
- * struct.c (define_aref_method, define_aset_method): ditto.
-
- * vm_insnhelper.c (rb_vm_opt_struct_aref, rb_vm_opt_struct_aset):
- direct accessors of Struct.
-
-Tue Dec 16 12:01:29 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking):
- extend timeout seconds to 60 for RGENGC_CHECK_MODE > 0 environment.
-
-Tue Dec 16 08:53:12 2014 Eric Wong <e@80x24.org>
-
- * tool/vcs.rb: fix Ruby 1.8 compatibility harder
-
-Tue Dec 16 07:37:18 2014 Eric Wong <e@80x24.org>
-
- * gc.c (GC_HEAP_FREE_SLOTS): move definition to match use order
- (RUBY_GC_HEAP_GROWTH_SLOTS): s/factor/number of slots/
-
- * man/ruby.1: add section for GC environment variables
- [Feature #10197]
-
-Tue Dec 16 05:41:46 2014 Eric Wong <e@80x24.org>
-
- * tool/vcs.rb: fix Ruby 1.8 compatibility
-
-Mon Dec 15 17:51:28 2014 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/objspace.c: ObjectSpace.memsize_of(obj) returns
- with sizeof(RVALUE). [Bug #8984]
-
- * gc.c (obj_memsize_of): ditto.
-
- * NEWS: add a NEWS entry.
-
- * test/objspace/test_objspace.rb: catch up this fix.
-
- * test/ruby/test_file_exhaustive.rb: ditto.
-
-Mon Dec 15 16:19:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_enc_str_coderange): dummy wchar, non-endianness
- encoding string cannot be ascii only.
- [ruby-core:66835] [Bug #10598]
-
-Sun Dec 14 20:11:42 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (primary): restore current_arg so that circular
- reference after a method definition is also warned.
- [ruby-core:61299] [Bug #9593]
-
-Sat Dec 13 20:41:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_trace.c (rb_postponed_job_flush): mask signal trap interrupt
- too to defer handling after finalizers finished.
- [ruby-core:66825] [Bug #10595]
-
-Sat Dec 13 18:33:25 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/openssl/test_pkey_ec.rb: ignored tests with old OpenSSL.
-
-Sat Dec 13 18:01:57 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * signal.c (check_stack_overflow): check sp also on i386/x86_64
- FreeBSD.
-
-Sat Dec 13 09:58:41 2014 Eric Wong <e@80x24.org>
-
- * gc.c (define_final0): avoid duplicate blocks
- [Bug #10537]
- * test/test_weakref.rb (test_repeated_object_leak): new test
-
-Sat Dec 13 04:59:20 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * bin/erb (ERB::Main#run): get rid of shadowing outer local
- variables. [ruby-core:65772] [Feature #10395]
-
-Fri Dec 12 21:56:44 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * gems/bundled_gems: Upgrade to test-unit 3.0.8. assert_throw and
- assert_nothing_thrown in test-unit 3.0.7 were broken by
- UncaughtThrowError change introduced in Ruby 2.2.0
- preview2. These assertions in test-unit 3.0.8 work well with
- UncaughtThrowError in Ruby 2.2.0 preview2.
-
-Fri Dec 12 19:48:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * bin/erb (ARGV.switch, ERB::Main#run): allow variables to be set
- from the command line. [ruby-core:65772] [Feature #10395]
-
-Fri Dec 12 19:31:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/erb.rb (ERB#lineno): accessor for line number to eval.
-
- * lib/erb.rb (ERB#location=): setter of file name and line number.
-
-Fri Dec 12 13:09:13 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_latest_gc_info): return :state field to show current
- GC state (none/marking/sweeping).
- [Feature #10590]
-
-Fri Dec 12 10:49:18 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_crypt): check arguments more strictly.
- * crypt() is not for wide char strings
- * salt bytes should not be NUL
-
-Fri Dec 12 08:16:01 2014 Matt Hoyle <matt@deployable.co>
-
- * io.c (io_read) Fix spelling in docco for read. [Fix GH-781]
- try > tries
-
-Thu Dec 11 19:06:01 2014 Koichi Sasada <ko1@atdot.net>
-
- * class.c (class_alloc): Start from age == 2.
- Class and Module objects can be living long life.
-
- * iseq.c: Same for ISeq objects.
-
- * gc.c (RVALUE_AGE_RESET): added.
-
- * gc.c (newobj_of): allow to generate (age != 0) objects.
-
- * gc.c (rb_copy_wb_protected_attribute): reset age for wb unprotected
- objects.
-
- * include/ruby/ruby.h: add RUBY_TYPED_PROMOTED1 as an unrecommended
- flag.
-
-Thu Dec 11 05:37:52 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/prime.rb: Remove useless loop and block capture.
- See [#10354]
-
-Thu Dec 11 04:27:24 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm_core.h: introduce new field
- rb_thread_t::local_storage_recursive_hash_for_trace to store
- recursive hash to avoid creating new recursive (nested) hashes
- for each trace events.
- [Bug #10511]
-
- * vm_trace.c (rb_threadptr_exec_event_hooks_orig): use it.
-
- * cont.c: catch up this fix.
-
- * vm.c (rb_thread_mark): ditto.
-
-Wed Dec 10 13:39:27 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * struct.c (define_aref_method, define_aset_method): use iseq
- VALUE instead of rb_iseq_t to prevent from GC, as RB_GC_GUARD
- makes sense only for local variables. [Feature #10575]
-
-Wed Dec 10 09:38:40 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (exec_recursive): use the same last method name as
- recursive_push in the error message when recursive_pop failed.
- [ruby-core:66742] [Bug #10579]
-
-Wed Dec 10 02:48:46 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/net/http/test_https.rb
- (TestNetHTTPS#test_certificate_verify_failure): on Windows,
- Errno::ECONNRESET will be raised when the verify is failure at the
- client side, and it'll be eaten by WEBrick.
-
- * test/open-uri/test_ssl.rb (TestOpenURISSL#test_validation_failure):
- ditto.
-
-Wed Dec 10 00:42:13 2014 Eric Wong <e@80x24.org>
-
- * iseq.c (rb_method_for_self_aref, rb_method_for_self_aset):
- new methods to generate bytecode for struct.c
- [Feature #10575]
- * struct.c (rb_struct_ref, rb_struct_set): remove
- (define_aref_method, define_aset_method): new functions
- (setup_struct): use new functions
- * test/ruby/test_struct.rb: add test for struct >10 members
- * benchmark/bm_vm2_struct_big_aref_hi.rb: new benchmark
- * benchmark/bm_vm2_struct_big_aref_lo.rb: ditto
- * benchmark/bm_vm2_struct_big_aset.rb: ditto
- * benchmark/bm_vm2_struct_small_aref.rb: ditto
- * benchmark/bm_vm2_struct_small_aset.rb: ditto
-
-Tue Dec 9 20:24:41 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * string.c: [DOC] Add missing documentation around String#chomp.
- Patch by @stderr [ci skip][fix GH-780]
-
-Tue Dec 9 18:20:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c: [DOC] Revise documentation by Marcus Stollsteimer at
- [ruby-core:66368]. [Bug #10526]
-
- * #inspect: be more specific about generated string, remove
- obsolete example.
- * #nil?: use code examples instead of different call-seq's.
- * #tap: clarify what is yielded.
- * Integer(): be more specific about to_int and to_i, remove
- reference to Ruby 1.8.
- * Array(): fix error.
- * Class: fix variable name style and indentation in example.
- * improve consistency, fix typos and formatting.
-
-Tue Dec 9 12:48:32 2014 Josef Simanek <josef.simanek@gmail.com>
-
- * vm_eval.c (rb_eval_string_wrap): [DOC] Fix `rb_eval_string_wrap`
- documentation. It is referencing `require` instead of `load`.
- The former does not have the optional argument. [Fix GH-779]
-
-Tue Dec 9 10:16:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (rb_frame_last_func): return the most recent frame method
- name.
-
- * thread.c (recursive_list_access): use the last method name,
- instead of the current method name which can be unset in some
- cases, not to use a symbol by the invalid ID.
- [ruby-core:66742] [Bug #10579]
-
-Sun Dec 7 19:36:12 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * ext/socket/basicsocket.c, ext/socket/sockssocket.c:
- remove code for $SAFE=4.
-
-Sun Dec 7 10:20:55 2014 Eric Hodel <drbrain@segment7.net>
-
- * lib/rdoc: Update to RDoc 4.2.0.
- * test/rdoc: ditto.
-
-Sun Dec 7 09:52:30 2014 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems 2.4.5.
- * test/rubygems: ditto.
-
-Sat Dec 6 10:05:08 2014 Shugo Maeda <shugo@ruby-lang.org>
-
- * lib/net/imap.rb: Fix undefined variable usage & refactor/DRY
- code. Patch by @aledovsky. [Fixes GH-770]
-
- * test/net/test_imap.rb: related test.
-
-Sat Dec 6 10:09:44 2014 Eric Wong <e@80x24.org>
-
- * thread.c (do_select): rename parameters to avoid shadowing
-
-Sat Dec 6 09:22:45 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rake: Update to rake 10.4.2
- * test/rake: ditto.
-
-Sat Dec 6 06:48:03 2014 Eric Wong <e@80x24.org>
-
- * compile.c (rb_iseq_build_from_ary): remove misc handling
-
-Sat Dec 6 06:14:23 2014 Vit Ondruch <vondruch@redhat.com>
-
- * configure.in (RUBY_LIB_VERSION): Fix --with-ruby-version
- configuration option. get rid of quoting in config.status.
-
- * template/verconf.h.tmpl: quote RUBY_LIB_VERSION here.
- [ruby-core:66724] [Bug #10572]
-
-Sat Dec 6 04:33:52 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * lib/pp.rb (File::Stat#pretty_print): some platforms (such as Windows)
- does not have major/minor parts of device.
-
-Fri Dec 5 22:43:04 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * ext/psych/lib/psych.rb: bump version to 2.0.8
- * ext/psych/psych.gemspec: ditto.
- * ext/psych/psych_emitter.c: ditto.
- * ext/psych/psych_parser.c: ditto.
-
-Fri Dec 5 17:09:09 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/socket/option.c (inet_ntop): link aliased inet_ntop in
- libruby on mswin not rb_w32_inet_ntop which fails to link for
- unknown reason.
-
-Fri Dec 5 11:09:54 2014 Eric Wong <e@80x24.org>
-
- * iseq.c (prepare_iseq_build): remove unused block_opt param
- (rb_iseq_new_with_bopt_and_opt): remove
- (rb_iseq_new_with_opt): inline removed function
- (rb_iseq_new_with_bopt): remove
- (iseq_load): adjust prepare_iseq_build call
- [Feature #10565]
-
-Fri Dec 5 09:46:05 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_yylex): fix lex_state after tLABEL_END, should
- be EXPR_LABELARG to be followed by "paren with arg".
- [ruby-core:66705] [Feature #4935]
-
-Fri Dec 5 02:27:47 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb: as all extension objects including initializations
- of ext and enc should be linked to libruby if enable-shared,
- EXTOBJS should not be linked to main programs.
- [ruby-core:66675] [Bug #10566]
-
-Thu Dec 4 07:06:02 2014 Eric Wong <e@80x24.org>
-
- * compile.c (rb_iseq_build_from_exception): entry->sp is unsigned
- (iseq_build_callinfo_from_hash): account for kw_arg
- (iseq_build_from_ary_body): update for r35459
- (CHECK_STRING, CHECK_INTEGER): remove unused checks
- (int_param): new function for checking new `params' hash
- (iseq_build_kw): new function for loading rb_iseq_param_keyword
- (rb_iseq_build_from_ary): account for `misc' entry and general
- structure changes
- [Feature #8543]
- * iseq.c (CHECK_HASH): new macro (for `misc' and `param' entries)
- (iseq_load): account for `misc' and `params' hashes
- (iseq_data_to_ary): add final opt to arg_opt_labels,
- fix kw support, account for unsigned entry->sp
- * ext/-test-/iseq_load/iseq_load.c: new ext for test
- * ext/-test-/iseq_load/extconf.rb: ditto
- * test/-ext-/iseq_load/test_iseq_load.rb: new test
-
-Thu Dec 4 06:56:57 2014 Eric Wong <e@80x24.org>
-
- * iseq.c (iseq_free): avoid segfault on incomplete iseq
- * test/ruby/test_syntax.rb (test_invalid_next): new test
- for syntax error, not segfault
-
-Thu Dec 4 04:20:34 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * load.c (ruby_require_internal): ignore error detail, just return
- an error.
-
-Wed Dec 3 17:13:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * encoding.c (load_encoding): use rb_require_internal instead of
- calling rb_require_safe with protection.
-
-Wed Dec 3 16:47:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * load.c (register_init_ext, ruby_init_ext): defer running the
- registered initialization function until required, not to enable
- extensions which have global effects just by loading, e.g.,
- mathn/complex and mathn/rational. fix `make test` with
- --with-static-linked-ext.
-
- * enc/encinit.c.erb (Init_enc): initialize encdb and transdb
- directly.
-
-Wed Dec 3 14:51:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * load.c (ruby_require_internal): separate from rb_require_safe,
- not to raise exceptions.
-
- * ruby.c (process_options): remove unnatural encoding search.
-
-Wed Dec 3 14:34:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (setup_fake_str): fake string does not share another
- string, but just should not free.
-
-Wed Dec 3 11:14:14 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (w32_spawn): `v2` is used not only for `shell` but also
- `cmd`, so must not free before using `cmd`.
- [ruby-core:66648] [Bug #10563]
-
-Wed Dec 3 09:48:57 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/racc/cparse/cparse.c (cparse_params_type): use typed data.
-
-Tue Dec 2 21:33:56 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: use typed data for com_hash.
-
-Tue Dec 2 15:30:30 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * array.c (rb_ary_plus): in documentation, added note about
- inefficiency of repeated += operations.
-
-Tue Dec 2 07:20:21 2014 Eric Wong <e@80x24.org>
-
- * iseq.c (iseq_data_to_ary): keep hidden variables
- Thanks to wanabe [ruby-core:66566]
-
-Tue Dec 2 06:46:57 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych.rb: bumping version
-
- * ext/psych/psych.gemspec: ditto
-
-Tue Dec 2 06:34:08 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/to_ruby.rb: support objects that are
- marshalable, but inherit from basic object.
- Thanks Sean Griffin <sean@thoughtbot.com>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb: ditto
-
- * test/psych/test_marshalable.rb: test for fix
-
-Tue Dec 2 06:32:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (ripper_flush_string_content): preserve the dispatched
- results at tSTRING_CONTENT. [ruby-dev:48714] [Bug #10437]
-
- * parse.y (regexp_contents): check in ripper only if the whole
- content is a single regexp without interpolation.
- [ruby-dev:48714] [Bug #10437]
-
-Tue Dec 2 06:30:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * re.c (rb_reg_region_copy): new function to try with GC if copy
- failed and return the error.
-
-Tue Dec 2 04:43:08 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * re.c (CHECK_REGION_COPIED): onig_region_copy() can fail when
- memory exhausted but returns nothing, so check by if allocated.
-
-Tue Dec 2 02:53:00 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (magic_comment_encoding): enable in ripper, since the
- encoding is necessary to parse non-default encoding scripts.
-
-Tue Dec 2 02:30:25 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/generic.rb (URI::Generic.build):
- use hostname= to detect and wrap IPv6 hosts.
- Build is accepting URI components and users may not expect
- that a host component needs to be wrapped with square brackets
- since it's not providing a URI.
- Note: initialize with arg_check => true does not wrap IPv6 hosts.
- by Joe Rafaniello <jrafanie@redhat.com>
- https://github.com/ruby/ruby/pull/765 fix GH-765
-
- * test/uri/test_generic.rb: Add more tests
-
-Mon Dec 1 20:01:12 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: use typed data for WIN32OLE.
- * ext/win32ole/win32ole.h: ditto.
- * ext/win32ole/win32ole_event.c: ditto.
-
-Mon Dec 1 17:20:42 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/Makefile.sub (verconf.h): so depends on verconf.mk, which
- is rebuilt by setup.mak.
-
-Mon Dec 1 11:05:46 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * proc.c: fix grammar by @BenMorganIO [fix GH-764][ci skip]
-
-Mon Dec 1 10:49:53 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * man/rake.1: Update latest man content by @aledovsky
- [fix GH-771][ci skip]
-
-Mon Dec 1 10:42:31 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * doc/syntax/refinements.rdoc: refinements are no longer experimental.
- patch by @gaurish [fix GH-775][ci skip]
-
-Sun Nov 30 20:05:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (regexp_contents): fix a typo. pointed out by wanabe.
- [ruby-dev:48741] [Bug #10543]
-
-Sun Nov 30 18:55:32 2014 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking):
- Don't raise Interrupt.
-
-Sun Nov 30 17:11:05 2014 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking): Use
- assert_separately.
-
-Sun Nov 30 00:02:52 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (process_options, ruby_script): transcode script name and
- program name to locale encoding as well as argv.
- [ruby-dev:48752] [Bug #10555]
-
- * ruby.c (translit_char_bin): should not use code page dependent
- CharNext on UTF-8 string. [ruby-dev:48752] [Bug #10555]
-
-Sat Nov 29 16:53:14 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (ruby_set_argv): convert argv from UTF-8.
-
- * win32/win32.c (rb_w32_sysinit, cmdglob, w32_cmdvector): convert
- wide char command line to UTF-8 argv, and glob in UTF-8 so that
- metacharacters would match multibyte characters.
- [ruby-dev:48752] [Bug #10555]
-
-Sat Nov 29 10:49:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (win32_direct_conv, rb_w32_readdir): convert UTF-8
- and filesystem code page by using Win32 API directly.
-
-Sat Nov 29 09:37:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (syserr_initialize): simplify message building and get
- rid of potential invalid byte sequence.
-
-Sat Nov 29 06:09:44 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * eval_error.c (error_print): respect the encoding of the message.
-
- * io.c (rb_write_error_str): use rb_w32_write_console() on Windows
- if stderr is a tty.
-
-Fri Nov 28 05:10:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (--with-setup): add option to select ext/Setup file.
-
-Fri Nov 28 05:02:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dmyenc.c (Init_enc): separate from dmyext.c for statically
- linked extension excluding encoding libraries.
-
-Thu Nov 27 21:58:30 2014 Tanaka Akira <akr@fsij.org>
-
- * common.mk (miniprelude.c): It does not depend on prelude.rb now.
-
-Thu Nov 27 21:49:49 2014 Tanaka Akira <akr@fsij.org>
-
- * tool/update-deps: List up files built always in the source directory
- and source files built always in the build directory.
-
-Thu Nov 27 21:24:55 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * NEWS: add obsolete callcc.
-
-Thu Nov 27 19:59:49 2014 Koichi Sasada <ko1@atdot.net>
-
- * compile.c (iseq_compile_each): remove duplicated line event.
- [Bug #10449]
-
- * test/ruby/test_settracefunc.rb: add and fix tests.
-
-Thu Nov 27 19:04:50 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm_args.c: fix backtrace location for keyword related exceptions.
-
- For example, the following program
- def foo(k1: 1); end # line 1
- foo(k2: 2) # line 2
- causes "unknown keyword: k2 (ArgumentError)".
-
- Before this patch, the backtrace location is only line 2.
- However, error should be located at line 1 (over line 2 in
- stack trace). This patch fix this problem.
-
- * class.c (rb_keyword_error_new): separate exception creation logic
- from rb_keyword_error(), to use in vm_args.c.
-
- * vm_insnhelper.c (rb_arg_error_new): rename to rb_arity_error_new().
-
- * vm_args.c (argument_arity_error): rename to argument_arity_error().
-
- * vm_args.c (argument_kw_error): added to fix backtrace.
-
- * test/ruby/test_keyword.rb: add tests.
-
-Thu Nov 27 17:31:58 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (prelude.c): no longer depends on miniruby, since not
- depending on rbconfig.rb.
-
-Thu Nov 27 17:12:14 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (miniprelude.c): miniruby needs no preludes.
-
-Thu Nov 27 17:10:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * template/prelude.c.tmpl: no code if no prelude code is given.
-
-Thu Nov 27 13:11:00 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (objspace_malloc_increase): enable lazy sweep on GC by malloc()
- (malloc_increase) to make GC incrementally.
-
- This change can increase memory consumption. Report us if you find
- any problem.
-
-Thu Nov 27 12:46:38 2014 Tanaka Akira <akr@fsij.org>
-
- * time.c (time_s_mkutc): [DOC] Time.utc's 10 arguments form
- doesn't examine wday, yday, isdst and tz.
- (time_s_mktime): [DOC] Time.mktime's 10 arguments form
- doesn't examine wday, yday and tz.
- Suggested by naruse.
-
-Thu Nov 27 11:45:33 2014 Eric Wong <e@80x24.org>
-
- * iseq.c (iseq_data_to_ary): add missing GC guard
-
-Thu Nov 27 10:51:59 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm_core.h: add rb_thread_t::local_storage_recursive_hash
- to speed up Thread#[:__recursive_key__] access.
- [Bug #10511]
-
- * thread.c (threadptr_local_aref): add fast path for
- :__recursive_data__.
-
- * thread.c (threadptr_recursive_hash, threadptr_recursive_hash_set):
- add special accessor for recursive hash.
-
- * cont.c: store/restore local_storage_recursive_hash.
-
- * vm.c: init and mark local_storage_recursive_hash.
-
- * vm_trace.c (rb_threadptr_exec_event_hooks_orig): clear and restore
- local_storage_recursive_hash directly.
-
-Thu Nov 27 07:11:00 2014 Eric Wong <e@80x24.org>
-
- * compile.c (iseq_calc_param_size): hoist out of iseq_set_arguments
-
-Wed Nov 26 22:28:12 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_get_kwargs, rb_extract_keywords): export
- keyword argument functions.
-
-Wed Nov 26 21:18:40 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/inlinetest.rb: removed unused test helper.
-
-Wed Nov 26 20:47:28 2014 Masaya Tarui <tarui@ruby-lang.org>
-
- * ext/continuation/continuation.c (Init_continuation): obsolete callcc.
- first step of [Feature #10548].
-
-Wed Nov 26 19:57:54 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_gc.rb (test_latest_gc_info): do test separately
- to avoid mysterious behavior.
-
-Wed Nov 26 19:54:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (constat_reset): do nothing on non-standard
- console emulators. [ruby-core:66471] [Bug #10546]
-
-Wed Nov 26 19:44:13 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/tsort.rb: Returns an enumerator if no block is given.
- [ruby-core:66270] [Feature #10508] Proposed by Andrey Savchenko.
-
-Wed Nov 26 17:25:45 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (f_label, f_kw, formal_argument_gen): ignore invalid
- formal argument in keyword argument definition.
- [ruby-dev:48742] [Bug #10545]
-
-Wed Nov 26 15:32:06 2014 Koichi Sasada <ko1@atdot.net>
-
- * compile.c (iseq_set_sequence): use "nop" insn instead of
- "jump to next insn".
- https://bugs.ruby-lang.org/issues/8543#change-50085
-
-Wed Nov 26 11:01:35 2014 Eric Wong <e@80x24.org>
-
- * iseq.c (iseq_s_compile_file): close IO when done
-
-Wed Nov 26 06:06:23 2014 Tanaka Akira <akr@fsij.org>
-
- * common.mk: encdb.h and transdb.h depends on $(PREP).
- So prebuild files for them in tarball are useless.
-
-Wed Nov 26 02:08:44 2014 Tanaka Akira <akr@fsij.org>
-
- * tool/make-snapshot: Don't generate enc/trans/newline.c in tarball.
-
-Wed Nov 26 00:41:44 2014 Tanaka Akira <akr@fsij.org>
-
- * common.mk (prereq): Don't depends on prelude.c and golf_prelude.c.
- Since they depend on $(PREP) which is miniruby, they are rebuilt
- after miniruby is built, even if tarball contains them.
-
-Wed Nov 26 00:20:48 2014 Tanaka Akira <akr@fsij.org>
-
- * template/prelude.c.tmpl: Don't expand RbConfig::Config[...].
- It is not used now.
-
- * common.mk: prelude.c and golf_prelude.c doesn't depend on rbconfig.
-
-Tue Nov 25 17:07:06 2014 Koichi Sasada <ko1@atdot.net>
-
- * NEWS: add an "Implementation changes" section.
-
-Tue Nov 25 16:09:28 2014 Eric Hodel <drbrain@segment7.net>
-
- * lib/net/http.rb: Do not attempt SSL session resumption when the
- session is expired. [Bug #10533]
-
-Tue Nov 25 15:59:46 2014 Eric Hodel <drbrain@segment7.net>
-
- * lib/rake: Update to rake 10.4.0
- * test/rake: ditto.
- * NEWS: ditto.
-
- * test/lib/minitest/unit.rb: Add compatibility shim for minitest 5.
- This only provides minitest 5 unit test naming compatibility.
-
-Tue Nov 25 15:26:33 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/vcs.rb (get_revisions): use Time.new instead of Time.mktime
- which does not accept UTC offset, and offset manually for older
- versions than 1.9.
-
-Tue Nov 25 12:14:43 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * process.c (Init_process): initialize static IDs before constant
- definitions. [ruby-core:66445]
-
-Tue Nov 25 10:32:23 2014 Eric Wong <e@80x24.org>
-
- * compile.c (iseq_build_callinfo_from_hash): hoist out
- (iseq_build_from_ary_body): shorten callinfo case
-
-Mon Nov 24 23:03:21 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * gems/bundled_gems: Update to test-unit 3.0.7.
-
-Mon Nov 24 12:44:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * process.c (check_exec_redirect_fd, check_exec_redirect),
- (rb_execarg_addopt): get rid of inadvertent ID pindown.
-
-Mon Nov 24 02:03:40 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_setter): preserve encoding of global variable
- name in error message.
-
-Mon Nov 24 02:03:30 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * iseq.c (rb_insn_operand_intern): preserve encoding of method
- name in CALL_INFO at disassembling.
-
-Mon Nov 24 02:02:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (must_respond_to): preserve encodings of variable name and
- class name in warning message.
-
-Sun Nov 23 10:46:23 2014 Eric Wong <e@80x24.org>
-
- * internal.h (struct rb_execarg): 160 => 144 bytes on x86-64
- * ruby.c (struct load_file_arg): 48 => 40 bytes on x86-64
- * vm_args.c (struct args_info): ditto
-
-Sun Nov 23 07:46:54 2014 Andy Maloney <asmaloney@gmail.com>
-
- * io.c (rb_io_sysread): Remove redundant assignment of 'n'.
- [Fix GH-767]
-
-Sat Nov 22 09:48:33 2014 Tanaka Akira <akr@fsij.org>
-
- * tool/make-snapshot: Specify PWD macro for make.
- PWD environment variable may not exist.
-
-Fri Nov 21 11:58:58 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * lib/resolv.rb: fall back if canonicalization fails.
- Thanks Vit Ondruch for the patch! [ruby-core:65836]
-
- * test/resolv/test_dns.rb: test for patch
-
-Sat Nov 22 01:11:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (rb_mod_const_get, rb_mod_const_defined): ditto.
-
- * variable.c (rb_const_missing, rb_mod_const_missing): call
- const_missing without new ID to get rid of inadvertent ID
- creation.
-
-Fri Nov 21 19:32:57 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * common.mk (ext/ripper/ripper.c): revert about srcdir and top_srcdir.
-
- * common.mk (ext/ripper/ripper.c): use $(PWD) for Unix,
- $(MAKEDIR) for Windows.
-
-Fri Nov 21 18:12:37 2014 Tanaka Akira <akr@fsij.org>
-
- * tool/update-deps: Refactored.
-
-Fri Nov 21 14:25:40 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/Makefile.sub (top_srcdir): added because lacking this macro
- causes build error at r48526.
-
-Fri Nov 21 12:00:58 2014 Tanaka Akira <akr@fsij.org>
-
- * tool/update-deps (in_makefile): Use FILES_NEED_VPATH and
- FILES_CONFUSING.
-
- * ext/objspace/extconf.rb: Add VPATH for id.h
-
-Fri Nov 21 09:10:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (ext/ripper/ripper.c): fix dependencies for the case
- to make ripper.y and id.h under the build directory.
-
-Fri Nov 21 08:42:21 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * common.mk (ext/ripper/ripper.c): id.h in VPATH may exist in the build
- directory.
-
- * common.mk (ext/ripper/ripper.c): $(RM) was not defined.
-
-Fri Nov 21 00:36:09 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/openssl/lib/openssl/x509.rb
- (OpenSSL::X509::Name::RFC2253DN::StringChar): get rid of a false
- positive assertion in ripper's test.
-
-Fri Nov 21 00:29:51 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * lib/net/imap.rb (Net::IMAP::ResponseParser::BEG_REGEXP): no need to
- use embed string.
-
-Fri Nov 21 00:19:17 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * lib/uri/mailto.rb (URI::MailTo::EMAIL_REGEXP): should escape `#`.
-
-Thu Nov 20 23:17:11 2014 Tanaka Akira <akr@fsij.org>
-
- * tool/update-deps: Insert all dependencies found by compiler.
-
-Thu Nov 20 15:51:01 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/nkf/depend (nkf.o): add nkf.c as dependency.
- bsdmake tries to make nkf.o with nkf-utf8/nkf.c without this.
-
-Thu Nov 20 08:54:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (struct parser_params): reduce size by reordering
- members and an unused member.
-
-Thu Nov 20 02:44:27 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Vector#independent? and associated class method
- patch by gogo tanaka [#10451]
-
-Thu Nov 20 02:32:34 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Add Vector#angle_with
- Patch by Egunov Dmitriy [#10442]
-
-Thu Nov 20 02:10:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (ripper_flush_string_content, parser_parse_string):
- preserve parsed string content. [ruby-dev:48714] [Bug #10437]
-
- * parse.y (ripper_new_yylval): abstract function to create ripper
- wrapper, and make it able to hold another object.
-
-Thu Nov 20 01:00:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (reg_named_capture_assign_gen): use predefined ID
- instead of rb_intern.
-
-Thu Nov 20 00:54:57 2014 Tanaka Akira <akr@fsij.org>
-
- * internal.h (ruby_init_setproctitle): Declare here.
-
-Thu Nov 20 00:26:37 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_here_document): append byte sequence directly to
- the delayed content instead of creating an intermediate string
- object.
-
-Wed Nov 19 21:11:01 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * common.mk (ext/json/parser/parser.c): don't touch parse.c,
- ruby repo is a downstream.
-
-Wed Nov 19 20:38:11 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * common.mk (ext/ripper/ripper.c): use $(PWD) to get
- <build-directory>/ext/ripper.
-
-Wed Nov 19 18:12:17 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/downloader.rb (RubyGems.download): Don't download gem if the
- version is already downloaded. A gem file is versioned and
- it must be identical if the version is the same.
-
-Wed Nov 19 17:59:25 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * common.mk (ext/ripper/ripper.c): pass build directory as VPATH.
-
- * ext/ripper/depend (.y.c): use VPATH for y.tab.c.
-
-Wed Nov 19 10:07:57 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * template/prelude.c.tmpl (Prelude#translate): strip VPATH prefix
- from prelude names, so that srcdir differences do not make the
- generated code different.
-
-Wed Nov 19 07:45:11 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (rb_w32_write): should set the error of
- GetOverlappedResult()'s, not WriteFile()'s (it's always
- ERROR_IO_PENDING, of course).
-
-Tue Nov 18 14:16:47 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_record): add information for debug print.
-
-Wed Nov 19 04:49:07 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * debug.c (set_debug_option): need the declaration.
-
- * debug.c (set_debug_option): use the same macro with the implementation
- at win32/win32.c.
-
-Wed Nov 19 04:16:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (symbol_list): fix the node type of literal symbol list
- with no interpolation. [ruby-core:66343]
-
-Wed Nov 19 00:26:15 2014 Tanaka Akira <akr@fsij.org>
-
- * tool/update-deps: Sort dependencies.
-
-Wed Nov 19 00:24:18 2014 Tanaka Akira <akr@fsij.org>
-
- * enc/encdb.c: Include internal.h.
-
-Tue Nov 18 23:23:45 2014 Tanaka Akira <akr@fsij.org>
-
- * internal.h: Gather declarations in non-header files.
-
-Tue Nov 18 23:45:52 2014 Tanaka Akira <akr@fsij.org>
-
- * debug.c (SET_WHEN): Don't declare debug variables here.
- ruby_initial_gc_stress_ptr is changed int* to VALUE* at r41406.
-
- * internal.h (ruby_initial_gc_stress_ptr): Declared.
- (ruby_enable_coredump): Ditto.
-
-Tue Nov 18 18:06:43 2014 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/io.h (FMODE_WSPLIT): Removed. The write() system call
- is not required to split. It was useful to avoid whole process
- blocking in Ruby 1.8 but not useful since write() is invoked without
- GVL.
- (FMODE_WSPLIT_INITIALIZED): Ditto.
-
- * io.c (wsplit_p): Removed.
- (io_writable_length): Removed.
- (rb_fcntl): Don't update the removed flags.
-
-Tue Nov 18 03:23:06 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (check_setter_id): show the original argument instead
- of nil on TypeError.
-
-Tue Nov 18 03:20:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * symbol.h (is_{local,global,instance,attrset,const,class,junk}_sym):
- fix ID type names.
-
-Mon Nov 17 20:17:59 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_event.c: use typed data.
-
-Mon Nov 17 12:54:56 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rubygems/*, test/rubygems/*: Update to RubyGems 2.4.4
- master (2f6e42e).
-
-Mon Nov 17 06:13:06 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (proc_binding): use the original iseq on a binding from
- proc from method object to get the location.
-
-Sun Nov 16 19:38:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (rb_current_receiver): new function to return the
- receiver in the current control frame. [Feature #10195]
-
-Sun Nov 16 19:11:04 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/timeout.rb (Timeout::ExitException#exception): rescue
- UncaughtThrowError which is specific for throw, instead of
- ArgumentError.
-
-Sun Nov 16 18:22:18 2014 Eric Wong <e@80x24.org>
-
- * tool/update-deps: warning to disable ccache
-
-Sun Nov 16 13:11:35 2014 Tanaka Akira <akr@fsij.org>
-
- * common.mk (CCAN_LIST_INCLUDES): Unused variable removed.
- (ENCODING_H_INCLUDES): Ditto.
- (PROBES_H_INCLUDES): Ditto.
- (VM_CORE_H_INCLUDES): Ditto.
-
-Sun Nov 16 11:07:25 2014 Eric Wong <e@80x24.org>
-
- * test/ruby/test_io.rb (test_readpartial_locktmp):
- remove unnecessary begin/end
-
-Sun Nov 16 00:45:23 2014 Tanaka Akira <akr@fsij.org>
-
- * common.mk: Specify dependencies for generated C sources.
-
-Sat Nov 15 23:10:45 2014 Tanaka Akira <akr@fsij.org>
-
- * common.mk: No need to declare dependencies which
- will be detected by inference rules.
-
-Sat Nov 15 20:34:23 2014 Tanaka Akira <akr@fsij.org>
-
- * internal.h: Include ruby.h and ruby/encoding.h to be
- includable without prior inclusion.
-
-Sat Nov 15 20:46:44 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_document.rb
- (REXMLTests::TestDocument::EntityExpansionLimitTest):
- Group tests by general entity and parameter entity.
-
-Sat Nov 15 20:43:31 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_document.rb
- (REXMLTests::TestDocument::EntityExpansionLimitTest): Define
- test XML in each test method because (1) each XML in used only
- one test and (2) related data and code should be close.
-
-Sat Nov 15 20:39:06 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_document.rb
- (REXMLTests::TestDocument::EntityExpansionLimitTest): Use
- one test method for one test.
-
-Sat Nov 15 20:16:59 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_document.rb
- (REXMLTests::TestDocument::EntityExpansionLimitTest): Use
- setup and teardown instead of ensure in test.
-
-Sat Nov 15 20:11:34 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_document.rb (REXMLTests::TestDocument): Group
- entity expansion limit related tests.
-
-Sat Nov 15 20:09:00 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_document.rb (REXMLTests::TestDocument::BomTest):
- Fix wrong parent class. It doesn't need inherit tests in
- TestDocument class.
-
-Sat Nov 15 19:48:59 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * lib/mkmf.rb (depend_rules): support comments during a line.
-
- * lib/mkmf.rb (depend_rules): apply RULE_SUBST even if the dependency
- file contains path.
-
-Sat Nov 15 19:25:46 2014 Tanaka Akira <akr@fsij.org>
-
- * common.mk: Remove comments in Dependency lines.
- Notified by usa.
-
- * enc/depend: Ditto.
-
- * ext/**/depend: Ditto.
-
-Sat Nov 15 16:28:05 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (rb_throw_obj): throw UncaughtThrowError instead of
- ArgumentError. [Feature #10480]
-
-Sat Nov 15 14:13:38 2014 Tanaka Akira <akr@fsij.org>
-
- * tool/update-deps: Extend to fix dependencies.
-
- * common.mk: Dependencies updated by tool/update-deps.
-
- * enc/depend: Ditto.
-
- * ext/**/depend: Ditto.
-
-Fri Nov 14 17:36:48 2014 Tanaka Akira <akr@fsij.org>
-
- * tool/update-deps: Support GNU Make 4.0.
-
-Fri Nov 14 16:59:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (default_proc_for_compat_func): check arguments number and
- type, and get rid of reentering this default proc.
-
-Fri Nov 14 16:33:06 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat_internal): support compatible layer for
- GC.stat(symbol) type access.
-
-Fri Nov 14 16:19:08 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat_internal): add compatible layer.
- From Ruby 2.2, keys of GC.stat are changed [Feature #9924].
- To provide compatible layer, GC.stat add a default_proc
- (if default_proc of given Hash object is not set).
-
- At first use of this compatible layer of interpreter process,
- show a warning message like that:
- program: GC.stat[:total_allocated_object]
- warning message: "warning: GC.stat keys were changed from Ruby
- 2.1. In this case, you refer to obsolete `total_allocated_object'
- (new key is `total_allocated_objects').
- Please check <https://bugs.ruby-lang.org/issues/9924>
- for more information."
-
- Please correct my English message :)
-
- * hash.c (rb_hash_set_default_proc): export (in internal).
-
- * internal.h: ditto.
-
-Fri Nov 14 10:41:25 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: guard by #if/#endif with GC_ENABLE_INCREMENTAL_MARK
- to hide unused codes.
-
- * gc.c: similar to GC_ENABLE_LAZY_SWEEP.
-
-Fri Nov 14 10:23:35 2014 Eric Wong <e@80x24.org>
-
- * vm_eval.c (rb_eval_cmd): use pre-defined idCall
-
-Fri Nov 14 09:25:44 2014 Eric Wong <e@80x24.org>
-
- * vm_eval.c (rb_yield_splat): add missing GC guard
- [Bug #10509]
-
-Fri Nov 14 08:12:40 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * gc.c: fix build error caused by implicit conversion with clang.
-
-Fri Nov 14 06:54:06 2014 Eric Wong <e@80x24.org>
-
- * insns.def (opt_succ): remove Time#succ optimization
- [Feature #10501]
-
-Fri Nov 14 05:29:46 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: refactoring.
-
- * gc.c: use GC_ENABLE_INCREMENTAL_MARK instead of USE_RINCGC.
-
- * gc.c (gc_start): check FORCE_MAJOR_GC.
-
-Fri Nov 14 04:51:18 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: Tuning RincGC parameters.
-
- Before this patch, gc_marks_step() marks (white -> grey) fixed
- number objects. However, this strategy does not fit practical
- cases, for example too slow to make progress.
-
- This patch changes this strategy how many objects the
- gc_marks_step() should handle.
-
- We can estimate how many times gc_marks_step() is called during
- this major marking (== C) with the free slot number in pooled
- pages. We also can estimate the living object number (== L)
- using last marked_slots value. We can solve this problem (how
- many objects should be process in gc_marks_step()) by L/C.
-
- * gc.c (rb_objspace_t): add rb_objspace_t::rincgc::pooled_slots and
- step_slots.
-
-Fri Nov 14 01:26:47 2014 Shugo Maeda <shugo@ruby-lang.org>
-
- * lib/net/imap.rb (search_response): parse MODSEQ in SEARCH
- responses properly. [ruby-core:64203] [Bug #10112]
-
-Fri Nov 14 01:03:17 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/envutil.rb: Moved from test/ruby/.
-
- * test/lib/find_executable.rb: Ditto.
-
- * test/lib/memory_status.rb: Ditto.
-
- * test/lib/test/unit.rb: require envutil.
-
- * test/: Don't require envutil in test files.
-
-Thu Nov 13 21:59:58 2014 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * lib/rexml/document.rb: add REXML::Document#document.
- reported by Tomas Hoger <thoger@redhat.com> and patched by nahi.
-
-Thu Nov 13 21:51:56 2014 Tanaka Akira <akr@fsij.org>
-
- * test/monitor/test_monitor.rb: Use assert_join_threads.
-
-Thu Nov 13 21:45:13 2014 Tanaka Akira <akr@fsij.org>
-
- * test/openssl: Don't specify port number.
-
-Thu Nov 13 21:22:35 2014 Tanaka Akira <akr@fsij.org>
-
- * test/openssl/ssl_server.rb: Unused file removed.
- It is not used since r16111, Ruby 1.9.1.
-
-Thu Nov 13 18:50:14 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (rb_ensure): remove obsolete prot_tag comment. patch by
- Jack Danger at [ruby-core:66238]. [misc #10502]
-
-Thu Nov 13 18:10:38 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm.c (rb_vm_make_proc_lambda): similar to rb_vm_make_proc() with
- is_lambda argument.
-
-Thu Nov 13 12:11:18 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (rb_w32_fstat{,i64}): speed up. adjusting
- timestamps in this function is to get rid of the side effect of
- ENV["TZ"]. then, if ENV["TZ"] is not set, no need to adjust.
- this change makes File#stat about 60% faster.
-
-Thu Nov 13 11:56:12 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * st.c: include "internal.h" for STATIC_ASSERT.
-
-Thu Nov 13 03:56:38 2014 Eric Wong <e@80x24.org>
-
- * gc.c (struct heap_page): trivial packing
- 304 => 296 bytes on x86-64
-
-Wed Nov 12 22:50:12 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * gems/bundled_gems: Update to test-unit 3.0.6 and minitest 5.4.3.
-
-Wed Nov 12 22:30:52 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rubygems/*: Update to RubyGems 2.4.3 master (7b1f684).
-
-Wed Nov 12 00:26:37 2014 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_object.rb: Specify an exception class for rescue clause.
-
- * test/dbm/test_dbm.rb: Ditto.
-
- * test/gdbm/test_gdbm.rb: Ditto.
-
- * test/sdbm/test_sdbm.rb: Ditto.
-
-Tue Nov 11 23:43:51 2014 Tanaka Akira <akr@fsij.org>
-
- * test/fileutils/test_fileutils.rb: Use assert_join_threads.
-
-Tue Nov 11 22:51:14 2014 Tanaka Akira <akr@fsij.org>
-
- * test/resolv/test_dns.rb: Use assert_join_threads.
-
-Tue Nov 11 22:33:08 2014 Tanaka Akira <akr@fsij.org>
-
- * test/net/pop/test_pop.rb: Use assert_join_threads.
-
-Tue Nov 11 22:07:20 2014 Tanaka Akira <akr@fsij.org>
-
- * test/net/http/test_https_proxy.rb: Use assert_join_threads.
-
-Tue Nov 11 18:09:11 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * template/prelude.c.tmpl: move from tool/compile_prelude.rb and
- expand by generic_erb.rb.
-
-Tue Nov 11 13:01:31 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/rubygems/commands/contents_command.rb (files_in_default_gem):
- remove useless sort. show_files will sort the result and
- another branch, files_in_gem, doesn't sort.
- it should be removed for consistency.
-
- * test/rubygems/test_gem_commands_contents_command.rb
- (test_execute_default_gem): adjust the sort algorithm with
- Gem::Commands::ContentsCommand#show_files, which sort items
- as array of [prefix, basename] not strings.
-
-Tue Nov 11 10:37:09 2014 Koichi Sasada <ko1@atdot.net>
-
- * string.c (sym_equal): use rb_obj_equal().
- rb_obj_equal() is specially optimized in
- opt_eq_func()@vm_insnhelper.c.
-
- This fix is made from this discussion:
- https://www.omniref.com/ruby/2.1.4/symbols/Symbol/%3D%3D#line=8361.
-
-Tue Nov 11 09:38:55 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rdoc/known_classes.rb: reverted regression changes of
- rdoc known class.
-
-Tue Nov 11 00:21:50 2014 Tanaka Akira <akr@fsij.org>
-
- * test/net/imap/test_imap.rb: Don't ignore exceptions on server
- threads.
-
-Mon Nov 10 23:34:13 2014 Tanaka Akira <akr@fsij.org>
-
- * test/net/ftp/test_ftp.rb (create_ftp_server): Don't ignore
- exceptions on server thread.
- Delete read_timeout method call to fix NoMethodError.
-
-Mon Nov 10 20:20:53 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (rb_w32_read): retry with reduced length if cannot to
- write any data but no error occurs.
-
-Mon Nov 10 20:04:16 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/webrick/server.rb: Setup shutdown pipe in listen method.
-
-Mon Nov 10 19:37:09 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c, include/win32/win32.h (rb_w32_set_nonblock): new
- function to support nonblock-mode of pipes.
-
- * win32/win32.c (rb_w32_read): nonblock-mode pipe returns ERROR_NO_DATA
- if there is no data, but also returns it if remote-end is closed.
-
- * win32/win32.c (rb_w32_write): if cannot to write any data, it may be
- blocking.
-
- * io.c (rb_io_set_nonblock): use rb_w32_set_nonblock for Windows.
-
- * ext/io/nonblock/nonblock.c (rb_io_nonblock_set): use ruby's API when
- setting nonblock-mode.
-
- * test/ruby/test_io.rb: test nonblock pipes on Windows.
-
-Mon Nov 10 17:24:34 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/etc/etc.c (etc_getlogin): set login name encoding properly.
- [ruby-core:66163] [Bug #10493]
-
-Mon Nov 10 16:20:42 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rubygems/*.rb: Update to RubyGems master(3e36528).
-
-Mon Nov 10 16:09:43 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * signal.c (rb_f_kill): [DOC] mention known signal list.
- [ruby-core:66162] [Bug #10492]
-
-Mon Nov 10 14:17:58 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rdoc/*.rb: Update to RDoc 4.2.0.alpha(579a11c)
-
-Mon Nov 10 12:44:39 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/webrick/server.rb: Less instance variables.
-
-Mon Nov 10 12:19:43 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/webrick/server.rb (shutdown): Use close() on @shutdown_pipe_w to
- notify readability on the read side of the pipe.
- write_nonblock() is not usable for pipe on Windows.
- (cleanup_shutdown_pipe): Rescue IOError for @shutdown_pipe_w.close.
-
-Mon Nov 10 07:31:59 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/webrick/server.rb (initialize): Initialize shutdown pipe here
- to avoid race condition.
- (cleanup_shutdown_pipe): New private method.
- (cleanup_listener): Extracted from shutdown method.
- Call this method from start method to avoid race condition.
-
-Mon Nov 10 05:57:53 2014 Tanaka Akira <akr@fsij.org>
-
- * test/webrick/webrick.cgi: Don't use debug mode.
-
- * test/webrick/webrick_long_filename.cgi: Ditto.
-
-Sun Nov 9 23:25:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (vm_call_super): allow bound proc method to call super
- method.
-
- * vm_insnhelper.c (vm_yield_with_cfunc): push defined class and
- bound proc method entry to the control frame.
-
-Sun Nov 9 22:46:13 2014 Tanaka Akira <akr@fsij.org>
-
- * test/open-uri: Test server log in server thread.
-
- * test/webrick: Ditto.
-
-Sun Nov 9 22:28:34 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/webrick/httpstatus.rb: require webrick/accesslog for AccessLog.
-
-Sun Nov 9 21:03:59 2014 Tanaka Akira <akr@fsij.org>
-
- * test/webrick: Fix the argument order of assert_equal.
-
-Sun Nov 9 20:29:01 2014 Tanaka Akira <akr@fsij.org>
-
- * test/webrick: Store log in an array.
-
- * test/net/http: Ditto.
-
- * test/open-uri: Ditto.
-
-Sun Nov 9 18:35:36 2014 Tanaka Akira <akr@fsij.org>
-
- * test/xmlrpc: Refine log test.
-
-Sun Nov 9 18:33:33 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize/normalize.rb: Replaced if-else by
- case in self.normalized? in parallel to r48309.
-
-Sun Nov 9 18:07:00 2014 Tanaka Akira <akr@fsij.org>
-
- * test/xmlrpc: Use assert_join_threads.
-
-Sun Nov 9 14:06:13 2014 Tanaka Akira <akr@fsij.org>
-
- * test/xmlrpc: Test webrick error log is empty.
-
-Sun Nov 9 13:47:02 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (is_incremental_marking): use #if/#else because
- rb_objspace_t::flags::during_incremental_marking is not defined
- when GC_ENABLE_INCREMENTAL_MARK is 0.
-
- * gc.c (will_be_incremental_marking, is_full_marking): similar fix.
-
-Sun Nov 9 12:16:22 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/securerandom.rb (SecureRandom.gen_random): separate
- implementation details and select at the load time.
-
-Sun Nov 9 12:09:38 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32/lib/win32/registry.rb (Win32::Registry::API#Enum{Value,Key):
- ditto.
-
-Sun Nov 9 11:48:40 2014 Tanaka Akira <akr@fsij.org>
-
- * test/net/http: Examine webrick log.
-
-Sun Nov 9 11:45:19 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * gems/bundled_gems: upgraded to test-unit 3.0.5.
-
-Sun Nov 9 11:40:50 2014 Tanaka Akira <akr@fsij.org>
-
- * defs/known_errors.def: More errors for FreeBSD.
-
-Sun Nov 9 11:25:11 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * gems/bundled_gems: upgraded to power_assert 0.2.0.
-
-Sun Nov 9 10:31:03 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/securerandom.rb: set the script encoding to make a string
- literal in SecureRandom::Kernel32.last_error_message single byte
- encoding so msg[] works in bytes, since FormatMessage() returns
- the size in TCHARs, not in characters.
-
-Sun Nov 9 09:50:22 2014 Tanaka Akira <akr@fsij.org>
-
- * test/webrick: Refine log tests.
-
-Sun Nov 9 08:58:05 2014 Tanaka Akira <akr@fsij.org>
-
- * defs/known_errors.def (EHWPOISON): New errno symbol.
- It is defined by glibc-2.16.
-
-Sun Nov 9 05:00:23 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * lib/securerandom.rb (initialize): call the special method for Win32
- before checking `/dev/urandom` because we know windows doesn't have it.
-
-Sun Nov 9 04:01:46 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * lib/securerandom.rb (SecureRandom::AdvApi32): split from `initialize`.
- thanks @zzak to remember it.
-
-Sun Nov 9 02:05:33 2014 Tanaka Akira <akr@fsij.org>
-
- * test/net/http/utils.rb: Don't connect to spawned server
- before actual test.
-
-Sun Nov 9 01:51:50 2014 Benoit Daloze <eregontp@gmail.com>
-
- * object.c (Module#const_defined?): [DOC] Revise the documentation.
- Patch by Xavier Noria.
- [Fixes GH-754] https://github.com/ruby/ruby/pull/754
-
-Sun Nov 9 00:37:44 2014 Tanaka Akira <akr@fsij.org>
-
- * test/webrick: Examine log and use assert_join_threads.
-
-Fri Nov 7 00:00:12 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * template/unicode_norm_gen.tmpl: expand kompatible_table so that
- recursive expansion is not needed at runtime.
-
-Thu Nov 6 23:58:40 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * pack.c (pack_pack): escape unprintable characters and preserve
- the encoding of warning message.
-
-Thu Nov 6 23:55:18 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (sym_printable): QUOTE() should not raise an exception
- even on invalid byte sequence.
-
-Thu Nov 6 21:44:36 2014 Tanaka Akira <akr@fsij.org>
-
- * test/test_unicode_normalize.rb: Rename TestNormalize to
- TestUnicodeNormalize.
- Define constants under TestUnicodeNormalize.
-
-Thu Nov 6 21:22:59 2014 Tanaka Akira <akr@fsij.org>
-
- * test/open-uri/test_open-uri.rb: Check empty webrick log.
-
-Thu Nov 6 19:27:34 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * re.c (unescape_nonascii): cast -1 for the case char is unsigned char.
- If char is signed char, for example gcc for ARM or ppc64, it caused
- infinite loop.
- http://kmuto.jp/build-ruby/arm/ruby-trunk/log/20141106T013005Z.fail.html.gz
- http://rubyci.blob.core.windows.net/f19p8/ruby-trunk/log/20141106T090217Z.fail.html.gz
-
-Thu Nov 6 09:53:18 2014 Eric Wong <e@80x24.org>
-
- * lib/uri/rfc2396_parser.rb (initialize): reduce bytecode size
- 2088 => 1332 bytes on 32-bit x86
-
-Thu Nov 6 08:49:49 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize/normalize.rb: Comment clarification.
-
-Wed Nov 5 23:43:24 2014 Naohisa Goto <ngotogenome@gmail.com>
-
- * compile.c (compile_data_alloc): add padding when strict alignment
- is required for memory access. Currently, the padding is enabled
- only when the CPU is 32-bit SPARC and the compiler is GCC.
- [Bug #9681] [ruby-core:61715]
-
- * compile.c (STRICT_ALIGNMENT): defined if strict alignment is required
-
- * compile.c (ALIGNMENT_SIZE, ALIGNMENT_SIZE_MASK, PADDING_SIZE_MAX):
- new macros for alignment word size, bit mask, max size of padding.
-
- * compile.c (calc_padding): new function to calculate padding size.
-
-Wed Nov 5 23:24:45 2014 Tanaka Akira <akr@fsij.org>
-
- * test/open-uri/test_open-uri.rb: Don't ignore webrick's log.
-
-Wed Nov 5 19:20:08 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/webrick/server.rb: Stop listener loop properly.
- [ruby-core:66085] [Bug #10478] Fixed by Charles Nutter.
-
-Wed Nov 5 17:20:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/intern.h (rb_disable_super, rb_enable_super): warn
- as deprecated at build time, instead of ignoring silently or
- warning at runtime only.
-
-Wed Nov 5 16:55:52 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (rb_f_lambda): remove deprecated function, which has been
- unavailable from extension libraries.
-
-Wed Nov 5 16:26:58 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/intern.h (rb_clear_cache): mark as deprecated, not
- only warnings at runtime.
-
-Wed Nov 5 15:05:12 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_{,l,r}strip_bang): rb_str_subseq() will not
- NUL-terminate the result string, in the future, so it will not
- be needed in other cases.
-
-Wed Nov 5 14:11:30 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (lib/unicode_normalize/tables.rb): do nothing unless
- BASERUBY is available. MINIRUBY cannot load extension libraries,
- so cannot update Unicode data.
-
-Wed Nov 5 12:13:54 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_lstrip, rb_str_strip): reduce memory copy by
- copying necessary part only.
-
- * string.c (rb_str_strip_bang, rb_str_strip): ditto.
-
-Wed Nov 5 12:13:48 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_lstrip, rb_str_strip): reduce memory copy by
- copying necessary part only.
-
- * string.c (rb_str_strip_bang, rb_str_strip): ditto.
-
-Wed Nov 5 10:54:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_lstrip_bang, rb_str_rstrip_bang): terminate
- wchar strings with wchar 0.
-
-Tue Nov 4 21:23:22 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/win32/lib/Win32API.rb: Fiddle::Importer is defined in
- fiddle/import.rb and it's not loaded implicitly.
-
- * ext/win32/lib/Win32API.rb (Win32API#initialize): `import` is a string.
-
- * ext/win32/lib/Win32API.rb (Win32API#initialize):
- Fiddle::Importer::CALL_TYPE_TO_ABI is private constant.
-
-Tue Nov 4 21:20:07 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * lib/securerandom.rb (SecureRandom.random_bytes): use fiddle directly
- instead of using Win32API.
-
-Tue Nov 4 21:04:30 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/rubygems/test_gem_request_set_lockfile.rb
- (test_relative_path_from): driveletter support.
-
-Tue Nov 4 16:23:57 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/rubygems/test_gem_remote_fetcher.rb (RemoteFetcherCleanup):
- close all pooled connections for each tests to fix leaked file
- descriptors.
-
-Tue Nov 4 12:51:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (PRIsVALUE), vsnprintf.c (BSD_vfprintf): add
- RUBY_PRI_VALUE_MARK to reduce danger of accidental conflict with
- plain "%i". binary incompatible with extension libraries using
- PRIsVALUE and built for 2.1 and earlier. [EXPERIMENTAL]
-
-Tue Nov 4 12:33:44 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * object.c: fix document of Kernel#String by @suzukaze
- [fix GH-743][ci skip]
-
-Tue Nov 4 12:21:45 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/csv.rb: added documentation for skip_blanks option by @decasia
- [fix GH-744][ci skip]
-
-Tue Nov 4 12:09:18 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/open3.rb: fix code formatting in documentation by @JoshCheek
- [fix GH-747][ci skip]
-
-Tue Nov 4 08:57:37 2014 Eric Wong <e@80x24.org>
-
- * encoding.c (enc_memsize): remove unnecessary function
- [ruby-core:65304]
-
-Mon Nov 3 18:09:39 2014 Tanaka Akira <akr@fsij.org>
-
- * test/openssl/utils.rb: The default of :ignore_listener_error is
- changed to false.
-
-Mon Nov 3 14:42:37 2014 Koichi Sasada <ko1@atdot.net>
-
- * iseq.c (iseq_free): resolve memory leak.
-
-Mon Nov 3 13:49:18 2014 Koichi Sasada <ko1@atdot.net>
-
- * iseq.c (iseq_memsize): catch up recent changes.
-
-Mon Nov 3 13:38:28 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm_core.h: change semantics of opt_num and opt_table.
- `opt_num' was the number of optional parameters + 1.
- `opt_table' has "opt_num" entries.
-
- Change them to:
- `opt_num' is the number of optional parameters.
- `opt_table' has "opt_num + 1" entries.
-
- This change simplify parameter fitting logics.
-
- * compile.c: catch up this change.
-
- * iseq.c: ditto.
-
- * proc.c: ditto.
-
- * vm_args.c: ditto.
-
-Mon Nov 3 11:47:44 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * NEWS: added period into Matrix section. [ci skip]
- [misc #10446][ruby-core:65987]
-
-Mon Nov 3 09:43:30 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * vm_args.c: fixed build error with clang
-
-Mon Nov 3 09:32:46 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/rfc3986_parser.rb (URI::RFC3986_Parser::RFC3986_URI):
- allow '[' and ']' for URI input (and escape). [Bug #10402]
-
- * lib/uri/generic.rb (URI#query=): escape '[', '\', and ']'.
-
-Mon Nov 3 07:49:34 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm_core.h: change iseq parameter data structure.
- https://bugs.ruby-lang.org/issues/10440#change-49694
-
- * change terminology `arg' to `param'.
- * move rb_iseq_t::arg_* to rb_iseq_t::param.
- * move rb_iseq_t::arg_size to rb_iseq_t::param::size.
- * move rb_iseq_t::argc to rb_iseq_t::param::lead_num.
- * move rb_iseq_t::arg_opts to rb_iseq_t::param::opt_num.
- * move rb_iseq_t::arg_rest to rb_iseq_t::param::rest_start.
- * move rb_iseq_t::arg_post_num to rb_iseq_t::param::post_num.
- * move rb_iseq_t::arg_post_start to rb_iseq_t::param::post_start.
- * move rb_iseq_t::arg_block to rb_iseq_t::param::block_start.
- * move rb_iseq_t::arg_keyword* to rb_iseq_t::param::keyword.
- rb_iseq_t::param::keyword is allocated only when keyword
- parameters are available.
- * introduce rb_iseq_t::param::flags to represent parameter
- availability. For example, rb_iseq_t::param::flags::has_kw
- represents that this iseq has keyword parameters and
- rb_iseq_t::param::keyword is allocated.
- We don't need to compare with -1 to check availability.
- * remove rb_iseq_t::arg_simple.
-
- * compile.c: catch up this change.
-
- * iseq.c: ditto.
-
- * proc.c: ditto.
-
- * vm.c, vm_args.c, vm_dump.c, vm_insnhelper.c: ditto.
-
- * iseq.c (iseq_data_to_ary): support keyword argument.
-
-Mon Nov 3 03:39:04 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_method.rb: r48239 makes this test green.
-
-Mon Nov 03 03:02:38 2014 Koichi Sasada <ko1@atdot.net>
-
- * rewrite method/block parameter fitting logic to optimize
- keyword arguments/parameters and a splat argument.
- [Feature #10440] (Details are described in this ticket)
-
- Most of complex part is moved to vm_args.c.
-
- Now, ISeq#to_a does not catch up new instruction format.
-
- * vm_core.h: change iseq data structures.
-
- * introduce rb_call_info_kw_arg_t to represent keyword arguments.
- * add rb_call_info_t::kw_arg.
- * rename rb_iseq_t::arg_post_len to rb_iseq_t::arg_post_num.
- * rename rb_iseq_t::arg_keywords to arg_keyword_num.
- * rename rb_iseq_t::arg_keyword to rb_iseq_t::arg_keyword_bits.
- to represent keyword bitmap parameter index.
- This bitmap parameter shows that which keyword parameters are given
- or not given (0 for given).
- It is referred by `checkkeyword' instruction described bellow.
- * rename rb_iseq_t::arg_keyword_check to rb_iseq_t::arg_keyword_rest
- to represent keyword rest parameter index.
- * add rb_iseq_t::arg_keyword_default_values to represent default
- keyword values.
- * rename VM_CALL_ARGS_SKIP_SETUP to VM_CALL_ARGS_SIMPLE
- to represent
- (ci->flag & (SPLAT|BLOCKARG)) &&
- ci->blockiseq == NULL &&
- ci->kw_arg == NULL.
-
- * vm_insnhelper.c, vm_args.c: rewrite with refactoring.
-
- * rewrite splat argument code.
- * rewrite keyword arguments/parameters code.
- * merge method and block parameter fitting code into one code base.
-
- * vm.c, vm_eval.c: catch up these changes.
-
- * compile.c (new_callinfo): callinfo requires kw_arg parameter.
-
- * compile.c (compile_array_): check the last argument Hash object or
- not. If Hash object and all keys are Symbol literals, they are
- compiled to keyword arguments.
-
- * insns.def (checkkeyword): add new instruction.
- This instruction check the availability of corresponding keyword.
-
- For example, a method "def foo k1: 'v1'; end" is compiled to the
- following instructions.
-
- 0000 checkkeyword 2, 0 # check k1 is given.
- 0003 branchif 9 # if given, jump to address #9
- 0005 putstring "v1"
- 0007 setlocal_OP__WC__0 3 # k1 = 'v1'
- 0009 trace 8
- 0011 putnil
- 0012 trace 16
- 0014 leave
-
- * insns.def (opt_send_simple): removed and add new instruction
- "opt_send_without_block".
-
- * parse.y (new_args_tail_gen): reorder variables.
- Before this patch, a method "def foo(k1: 1, kr1:, k2: 2, **krest, &b)"
- has parameter variables "k1, kr1, k2, &b, internal_id, krest",
- but this patch reorders to "kr1, k1, k2, internal_id, krest, &b".
- (locate a block variable at last)
-
- * parse.y (vtable_pop): added.
- This function remove latest `n' variables from vtable.
-
- * iseq.c: catch up iseq data changes.
-
- * proc.c: ditto.
-
- * class.c (keyword_error): export as rb_keyword_error().
-
- * common.mk: depend vm_args.c for vm.o.
-
- * hash.c (rb_hash_has_key): export.
-
- * internal.h: ditto.
-
-Mon Nov 3 02:35:32 2014 Koichi Sasada <ko1@atdot.net>
-
- * sample/simple-bench.rb: added to measure performance of simple
- lines.
-
-Mon Nov 3 02:33:43 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (obj_info): show T_STRING more details.
-
-Sun Nov 2 01:30:32 2014 Tanaka Akira <akr@fsij.org>
-
- * test/openssl/test_ssl.rb: Don't ignore errors on listener threads,
- as much as possible.
-
- * test/openssl/test_ssl_session.rb: Ditto.
-
- * test/openssl/test_partial_record_read.rb: Ditto.
-
-Sat Nov 1 23:11:05 2014 Tanaka Akira <akr@fsij.org>
-
- * test/openssl/utils.rb (start_server): Don't close sockets before
- threads finished.
-
-Sat Nov 1 22:06:24 2014 Tanaka Akira <akr@fsij.org>
-
- * test/openssl/test_ssl_session.rb (test_ctx_client_session_cb): Don't
- ignore errors of SSL accept.
- (test_ctx_server_session_cb): Ditto.
-
- * test/openssl/utils.rb (server_loop): Add ignore_ssl_accept_error
- argument.
- (start_server): Refine threads waits.
-
- * test/ruby/envutil.rb (assert_join_threads): Show a thread before
- backtrace.
-
-Sat Nov 1 20:40:18 2014 Tanaka Akira <akr@fsij.org>
-
- * test/openssl/utils.rb (start_server, server_loop): Use a
- pipe to stop server instead of shutdown/close a listening socket.
-
-Sat Nov 1 19:24:59 2014 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/envutil.rb (assert_join_threads): New assertion to
- join multiple threads without exceptions.
-
-Sat Nov 1 17:09:32 2014 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (bary_mul_balance_with_mulfunc): Fix free work area
- location.
- [ruby-dev:48723] [Bug #10464]
- [ruby-core:66044] [Bug #10465]
- Reported by Kohji Nishihama.
-
-Sat Nov 1 15:45:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parse_atmark): mere atmark and two atmarks without
- succeeding identifiers are invalid as instance/class variable
- names.
-
-Sat Nov 1 06:31:41 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_variant.c: use typed data.
-
-Fri Oct 31 13:55:28 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/dl/*: remove DL as it is replaced by Fiddle.
- [Feature #5458] Thanks to Jonan Scheffler <jonanscheffler@gmail.com>
- for this patch
-
- * test/dl/*: ditto.
-
-Fri Oct 31 15:26:02 2014 Charles Oliver Nutter <headius@headius.com>
-
- * test/openssl/test_ssl.rb: Add certificate verification chain
- test from JRuby community.
-
-Fri Oct 31 18:58:02 2014 Charles Oliver Nutter <headius@headius.com>
-
- * test/psych/test_emitter.rb: Fix line_width test...initial value
- is impl-specific and attr assignment always returns LHS.
-
-Fri Oct 31 22:19:30 2014 Akinori MUSHA <knu@iDaemons.org>
-
- * ext/digest/lib/digest.rb (Digest()): This function should now be
- thread-safe. If you have a problem with regard to on-demand
- loading under a multi-threaded environment, preload "digest/*"
- modules on boot or use this method instead of directly
- referencing Digest::*. [Bug #9494]
- cf. https://github.com/aws/aws-sdk-ruby/issues/525
-
-Fri Oct 31 21:33:17 2014 Akinori MUSHA <knu@iDaemons.org>
-
- * test/digest/test_digest.rb: Drop #!. This no longer runs
- stand-alone because it depends on ruby/envutil.
-
-Fri Oct 31 17:22:19 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/setup.mak: $(APPEND) with some arguments insert a space before
- the arguments, so it causes error if the arguments are expected to be
- a macro definition. this fix resolve the build error introduced at
- r48210.
-
-Fri Oct 31 16:47:35 2014 Akinori MUSHA <knu@iDaemons.org>
-
- * ext/syslog/lib/syslog/logger.rb (Syslog::Logger::VERSION): Bump
- the VERSION to 2.1.0. [ruby-core:64483] [Bug #10159]
-
-Fri Oct 31 16:33:46 2014 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/net/imap.rb (Net::IMAP#fetch): [DOC] Document that
- Net::IMAP#fetch will return nil instead of an empty array.
-
-Fri Oct 31 12:54:43 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (.unicode-tables.time): needs Unicode files always,
- and should update after downloading these files.
- [ruby-core:66026] [Bug #10461]
-
-Fri Oct 31 10:16:42 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * .travis.yml: reverted r48199, it's unrelated configuration.
-
-Fri Oct 31 09:58:14 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/test_unicode_normalize.rb: added unicode version number to
- test data location.
-
-Fri Oct 31 09:56:41 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * .gitignore: ignored unicode data with version directories.
-
-Fri Oct 31 09:35:30 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * .travis.yml: tweak build scripts for unicode_normalize.rb.
-
-Thu Oct 30 18:47:04 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * common.mk: fix for the case ALWAYS_UPDATE_UNICODE=no
-
-Thu Oct 30 13:23:23 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/downloader.rb: changed Unicode data download location
- from latest Unicode version to Unicode 7.0.0.
-
-Thu Oct 30 11:16:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_callee_setup_arg{_complex,}): try conversion
- by to_ary for a lambda, as well as a proc.
- [ruby-core:65887] [Bug #9605]
-
-Wed Oct 29 21:13:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (gettable_gen): warn circular argument reference, for
- transition from 2.1 and earlier. [ruby-core:65990] [Bug #10314]
-
-Wed Oct 29 20:41:01 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_params): remove unused member `cur_mid`.
- this has been taken over by `in_def` since 1.6.
-
-Wed Oct 29 14:44:27 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * load.c (rb_f_load): path name needs to be transcoded to OS path
- encoding. [ruby-list:49994]
-
-Wed Oct 29 11:48:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (__builtin_setjmp): disable with gcc/clang earlier
- than 4.3 on Mac OS X. [ruby-core:65174] [Bug #10272]
-
-Wed Oct 29 11:43:43 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Generalize Vector#cross_product to arbitrary
- dimensions
- based on a patch by gogo tanaka [#10074]
-
-Wed Oct 29 11:43:11 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Add Matrix#adjucate
- patch by gogo tanaka [#10056]
-
-Wed Oct 29 11:42:33 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Add aliases for Vector#cross & dot
- patch by gogo tanaka [#10352]
-
-Wed Oct 29 10:00:18 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * gems/bundled_gems: Update latest version of bundled gems.
-
-Tue Oct 28 16:52:07 2014 Eric Wong <e@80x24.org>
-
- * signal.c (install_sighandler): remove rb_disable_interrupt and
- rb_enable_interrupt calls
- (init_sigchld): ditto
- (Init_signal): disable and enable interrupt once around all
- install_sighandler and init_sigchld to reduce syscalls at start
- [Feature #9345] [ruby-core:59480]
-
-Tue Oct 28 16:22:41 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (process_options, load_file_internal2): should not
- require other files when dump option is given.
- [ruby-dev:48712] [Bug #10435]
-
-Tue Oct 28 14:51:38 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: remove apple-gcc4.2 from CC candidates.
-
-Mon Oct 27 20:13:37 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * lib/rexml/entity.rb: keep the entity size within the limitation.
- reported by Willis Vandevanter <will@silentrobots.com> and
- patched by nahi.
-
-Mon Oct 27 17:17:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (method_proc): the receiver of binding from method should
- be same as the receiver of the method.
- [ruby-core:65917] [Bug #10432]
-
-Mon Oct 27 16:26:37 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_super.rb: add a test to check block passing.
-
-Mon Oct 27 15:59:26 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: is_incremental_marking(), will_be_incremental_marking():
- use `&&' with GC_ENABLE_INCREMENTAL_MARK instead of using
- #if/#else/#endif.
-
-Mon Oct 27 13:40:11 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (gc_sweep_rest): sweep rest pages regardless of whether
- lazy sweep is enabled or not. based on the patch by Masahiro
- Ide at [ruby-dev:48706]. [Bug #10431]
-
-Mon Oct 27 11:18:32 2014 Eric Wong <e@80x24.org>
-
- * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking):
- reduce garbage during forks
-
-Sun Oct 25 12:26:26 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * template/insns.inc.tmpl, insns_info.inc.tmpl, known_errors.inc.tmpl,
- minsns.inc.tmpl: fixed path of generating script.
-
-Sun Oct 26 12:24:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/ripper/lib/ripper/sexp.rb (Ripper.sexp, Ripper.sexp_raw):
- return nil on error. [ruby-dev:48678] [Bug #10405]
-
-Sun Oct 25 11:24:24 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: improved comment.
-
-Sun Oct 26 07:40:11 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (ole_val2variant, ole_invoke): refactoring.
- use ole_variant2variant to convert WIN32OLE_VARIANT object to
- VARIANT object.
-
- * ext/win32ole/win32ole_variant.c: refactoring. add
- ole_variant2variant.
- * ext/win32ole/win32ole_variant.h: ditto.
-
-Sat Oct 25 22:28:17 2014 Tanaka Akira <akr@fsij.org>
-
- * io.c (io_binwrite_string): Test writev() failure.
-
-Sat Oct 25 20:19:19 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/test-unicode_normalize.rb: added test_us_ascii.
-
-Sat Oct 25 20:09:09 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize/normalize.rb: added US_ASCII
- as trivially supported encoding (is always normalized,
- and may appear mixed in with UTF-8 or other Unicode
- encodings).
-
-Sat Oct 25 20:01:01 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/test-unicode_normalize.rb: added
- test_raise_exception_for_non_unicode_encoding.
-
-Sat Oct 25 19:30:30 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/test-unicode_normalize.rb: removed unused function.
-
-Sat Oct 25 18:41:41 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * template/unicode_norm_gen.tmpl: Adjusted name of generating file.
-
-Fri Oct 24 22:49:42 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_yylex): dispatch newline and space at fluent
- interface, so that the following identifier does not include the
- space. [ruby-dev:48684] [Bug #10411]
-
-Fri Oct 24 20:41:36 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * signal.c (check_reserved_signal_): fix write count since r47991.
-
-Thu Oct 23 21:42:54 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (rb_hash_delete): now does not call the block given to
- the current method. [ruby-core:65861] [Bug #10413]
-
-Thu Oct 23 19:13:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_method.c (rb_method_entry_make): warn redefinition only for
- already defined methods, but not for undefined methods.
- [ruby-dev:48691] [Bug #10421]
-
-Thu Oct 23 17:19:04 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/source.rb (REXML::IOSource#encoding_updated): Fix a
- bug that can't parse XML correctly when
- Encoding.default_internal is different with XML
- encoding. REXML::Source converts XML encoding on read. So IO
- should not convert XML encoding.
- Based on patch by NAKAMURA Usaku.
- [ruby-dev:48686] [Bug #10418]
-
- * test/rexml/test_encoding.rb
- (REXMLTests::EncodingTester#test_parse_utf16_with_utf8_default_internal):
- Add the for the above case.
-
-Thu Oct 23 16:29:02 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_encoding.rb
- (REXMLTests::EncodingTester#test_parse_utf16): Use meaningful
- test name. "ticket" in the old test name means the ticket in
- REXML's issue tracker. The REXML's issue tracker was gone. So
- "ticket" is meaningless.
-
- * test/rexml/data/ticket_110_utf16.xml: Rename to ...
- * test/rexml/data/utf16.xml: ... this.
-
-Thu Oct 23 16:18:11 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_encoding.rb
- (REXMLTests::EncodingTester#test_ticket_110): Fix expected and
- actual order.
- Patch by NAKAMURA Usaku. Thanks!!!
-
-Thu Oct 23 10:47:16 2014 Eric Wong <e@80x24.org>
-
- * insns.def (getlocal,setlocal): add comment to def/opt_operand.def
-
-Thu Oct 23 10:22:41 2014 Eric Wong <e@80x24.org>
-
- * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking):
- use IO#wait_readable instead of timeout
-
-Thu Oct 23 10:22:24 2014 Eric Wong <e@80x24.org>
-
- * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking):
- ensure exit! during fork failure
-
-Thu Oct 23 10:21:21 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * NEWS: Added String#unicode_normalize(|!|d?) [ci skip]
-
-Thu Oct 23 03:41:51 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (unknown_keyword_error): delete expected keywords
- directly from raw table, so that the given block is not called.
- [ruby-core:65837] [Bug #10413]
-
-Thu Oct 23 02:33:01 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (update-unicode): invert dependency to run every times.
- [ruby-core:65842] [Bug #10415]
-
- * common.mk (after-update): update files under source tree.
- [ruby-core:65840] [Bug #10414]
-
-Wed Oct 22 22:38:59 2014 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * ext/openssl/lib/openssl/ssl.rb (DEFAULT_PARAMS): override
- options even if OpenSSL::SSL::OP_NO_SSLv3 is not defined.
- this is pointed out by Stephen Touset. [ruby-core:65711] [Bug #9424]
-
-Wed Oct 22 21:31:56 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * common.mk (prelude.c): add dependency to LIB_SRCS because
- enc/prelude.rb requires lib/unicode_normalize.rb, and it's also
- requires lib/unicode_normalize/tables.rb (=LIB_SRCS).
-
-Wed Oct 22 21:09:51 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
-
- * configure.in (nacl_cv_cpu_nick): fix typo in PNaCl.
- (XCFLAGS) Add -isystem flag to pnacl and nacl-newlib
- (CXX): added
-
- * nacl/GNUmakefile.in (CXX): Added
- (PPROGRAM): Use clang++ instead of clang because libnacl_io
- depends on c++ std lib.
-
-Wed Oct 22 21:07:32 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
-
- * common.mk (build-ext): avoid trying to build dynamic libraries
- if configured --with-static-linked-ext.
-
-Wed Oct 22 20:33:33 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * common.mk: Fixed grammar in comment [ci skip]
-
-Wed Oct 22 19:18:18 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/unicode_norm_gen.rb: Fixed escaping of backslash and
- double quote ('\\\&' -> "\\\\\\\&"; double quoted string
- is needed to make \& mean last match; double double
- backslashes are needed because of two layers of escaping).
-
-Wed Oct 22 18:13:29 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/test-unicode_normalize.rb: as often said, ruby is sometimes built
- at non-srcdir.
-
-Wed Oct 22 18:12:12 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/test-unicode_normalize.rb: Adjusted path for test
- data file (now ../enc/unicode/data/NormalizationTest.txt).
-
-Wed Oct 22 18:07:07 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/test-unicode_normalize.rb: Removed explicit require,
- changed method names, adjusted copyright.
-
-Wed Oct 22 18:00:00 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/test-unicode_normalize.rb: Importing from
- https://github.com/duerst/eprun/blob/master/test/test_normalize.rb.
- (removing trailing whitespace, fixing EOLs and adding EOL property)
-
-Wed Oct 22 08:21:09 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
-
- * nacl/pepper_main.c (Instance_DidCreate): mount devfs and rebind fd 0
- .. 2 so that stderr goes to the console of the browser.
-
-Wed Oct 22 03:47:43 2014 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * ext/etc/etc.c (etc_nprocessors_affin): maximum "n" should be 16384.
-
-Wed Oct 22 03:37:00 2014 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * ext/etc/etc.c (etc_nprocessors_affin): minor spell fix.
-
-Wed Oct 22 03:33:58 2014 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * ext/etc/etc.c (etc_nprocessors_affin): optimize memory usage a
- bit. Typical rubyist never use 8k cpus machine.
-
-Wed Oct 22 00:01:09 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
-
- * configure.in (XCFLAGS): Add include path for NaCl libraries.
- (XLDFLAGS): ditto.
- (NACL_LIB_PATH): new substitution
-
- * nacl/nacl-config.rb: support NACL_LIB_PATH
-
- * nacl/package.rb: ditto.
-
- * nacl/pepper_main.c: replace old implementations with nacl_io.
-
- * nacl/GNUmakefile.in: link nacl_io to pepper_ruby
-
- * ruby.c (rb_load_file): remove __attribute__((weak)) because the old
- override hack was replaced with nacl_io.
-
- * file.c (rb_file_load_ok): ditto.
-
-Tue Oct 21 17:32:32 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * common.mk: Adding explicit creation of directory
- enc/unicode/data because git doesn't handle empty
- directories. [patch by Masahiro Ide, filed with r48073]
-
-Tue Oct 21 17:12:12 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize/tables.rb: Committing to make version
- update easier and more predictable, and reducing compilation
- time.
-
-Tue Oct 21 15:56:56 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize/normalize.rb: Added comment to point to
- relevant portion of Unicode standard for Hangul (de)composition
- identifiers and algorithm.
-
-Tue Oct 21 11:49:16 2014 Andreas Schwab <schwab@suse.de>
-
- * gc.c (mark_current_machine_context) [__mc68000__]: Update stack
- marking.
- (rb_gc_mark_machine_stack) [__mc68000__]: Also handle it here.
-
-Mon Oct 20 23:59:38 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * enc/prelude.rb: we sometimes run ruby without library path (especially
- for test), so should permit to run ruby if unicode_normalize.rb is
- missing.
-
-Mon Oct 20 23:57:58 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * common.mk (lib/unicode_normalize/tables.rb): enable running (n)make
- in non-srcdir.
-
-Mon Oct 20 23:58:04 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/downloader.rb: add -a option to always download regardless
- existing files.
-
-Mon Oct 20 23:18:18 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * lib/mkmf.rb: no need to convert path separator for COPY because it's
- ruby -run cp and it can treat '/' on any platform.
-
-Mon Oct 20 19:54:54 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * config.mk: Added missing data files as targets for
- prerequisite update_unicode.
-
-Mon Oct 20 19:06:06 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize.rb: revert r48046. The s in sIndex
- is not hungarian notation. The variable name sIndex is
- directly taken from the relevant part of the Unicode
- Standard, where it is written SIndex and stands for
- 'syllable index'. See pp. 144/145 of
- http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf.
-
-Mon Oct 20 12:46:46 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize.rb: removing unnecessary 'self'.
-
-Mon Oct 20 12:37:37 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize.rb: change method names
- in commented-out code. Followup to r48027.
-
-Mon Oct 20 02:23:27 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * variable.c (rb_ivar_get), vm_insnhelper.c (vm_getivar): improve
- instance variable retrieval performance by checking ruby_verbose
- before call of rb_warning and evaluation of its argument.
- [ruby-core:65786] [Feature #10396]
-
-Sun Oct 19 23:31:29 2014 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * lib/unicode_normalize.rb: (unicode_normalize!): change method name.
- catch up the method name change at r48014. [Feature #10084]
-
-Sun Oct 19 20:05:58 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * ext/tk/lib/tkextlib/tile/treeview.rb: fix syntax error.
-
-Sun Oct 19 18:39:39 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/prelude.rb: Added automatic loading of
- lib/unicode_normalize.rb. This makes sure that all
- the methods that are available on String are
- available without explicit require.
-
-Sun Oct 19 18:35:35 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize/normalize.rb: Added a missing
- file extension in require statement.
-
-Sun Oct 19 18:13:13 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * common.mk: Added a rule to generate
- lib/unicode_normalize/tables.rb. This rule still
- needs to be integrated into the overall make process.
-
-Sun Oct 19 17:53:53 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize.rb: Changed to dynamic
- loading of actual normalization code and tables.
-
-Sun Oct 19 17:37:37 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize.rb: Small documentation fix.
-
-Sun Oct 19 17:26:26 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize.rb: Added documentation.
-
-Sun Oct 19 11:09:09 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/unicode_norm_gen.rb, lib/unicode_normalize.rb:
- File name change from lib/unicode_normalize/normalize_tables.rb
- to lib/unicode_normalize/tables.rb.
-
-Sun Oct 19 10:12:12 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize.rb: Changing method names, see
- https://bugs.ruby-lang.org/issues/10084#note-7
-
-Sun Oct 19 10:10:10 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize.rb: Changing module name.
-
-Sun Oct 19 10:08:08 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize.rb: Changing require statement,
- adjusting copyright.
-
-Sun Oct 19 10:04:04 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize.rb: Importing from
- https://github.com/duerst/eprun/blob/master/lib/string_normalize.rb.
- (removing trailing whitespace, fixing EOLs and adding EOL property)
-
-Sun Oct 19 09:56:56 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/unicode_norm_gen.rb: Changed module name.
-
-Sun Oct 19 09:48:48 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize/normalize.rb: Changed module name,
- adjusted copyright.
-
-Sun Oct 19 09:38:38 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize/normalize.rb: Importing from
- https://github.com/duerst/eprun/blob/master/lib/normalize.rb.
-
-Sat Oct 18 20:40:52 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * vm_core.h, proc.c, vm_backtrace.c, vm_trace.c:
- remove rb_binding_new_with_cfp, and use rb_vm_make_binding instead.
-
-Sat Oct 18 20:38:48 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * vm_core.h, vm.c, proc.c: fix GC mark miss on bindings.
- [ruby-dev:48616] [Bug #10368]
-
- * test/ruby/test_eval.rb: add a test code.
-
-Fri Oct 17 22:47:11 2014 Tanaka Akira <akr@fsij.org>
-
- * pack.c (pack_unpack): Add casts for char references for 'u'.
- Fix line ending recognition algorithm.
-
-Fri Oct 17 21:49:52 2014 Tanaka Akira <akr@fsij.org>
-
- * pack.c (pack_unpack): Add casts for char references for 'b' and 'h'.
-
-Fri Oct 17 17:50:10 2014 Tanaka Akira <akr@fsij.org>
-
- * Avoid undefined behaviors found by gcc -fsanitize=undefined.
- gcc (Debian 4.9.1-16) 4.9.1
-
- * string.c (rb_str_sum): Avoid undefined behavior.
-
-Fri Oct 17 17:43:50 2014 Tanaka Akira <akr@fsij.org>
-
- * Avoid undefined behaviors found by gcc -fsanitize=undefined.
- gcc (Debian 4.9.1-16) 4.9.1
-
- * include/ruby/ruby.h (INT2FIX): Avoid undefined behavior.
-
- * node.h (nd_set_line): Ditto.
-
- * pack.c (encodes): Ditto.
- (pack_unpack): Ditto.
-
- * regint.h (BIT_STATUS_AT): Ditto.
- (BS_BIT): Ditto.
-
- * time.c (time_mdump): Ditto.
- (time_mload): Ditto.
-
- * vm_core.h (VM_FRAME_MAGIC_MASK): Ditto.
-
- * vm_trace.c (recalc_add_ruby_vm_event_flags): Ditto.
-
-Fri Oct 17 15:06:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * re.c (unescape_nonascii): make dynamically compiled US-ASCII
- regexps ASCII-8BIT encoding if binary (hexadecimal, control,
- meta) escapes are contained, as well as literal regexps.
- [ruby-dev:48626] [Bug #10382]
-
-Fri Oct 17 03:05:08 2014 Eric Wong <e@80x24.org>
-
- * test/-ext-/bug_reporter/test_bug_reporter.rb
- (test_bug_reporter_add): revert r47972
- * test/ruby/test_rubyoptions.rb (test_segv_test): revert r47971
- [ruby-core:65764]
-
-Thu Oct 16 23:17:40 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * signal.c (rb_sigaltstack_size): double default size to get rid
- of heap corruption by alternate stack overflow in SEGV handler.
- typically happened at fprintf() in control_frame_dump().
-
-Thu Oct 16 22:43:12 2014 Tanaka Akira <akr@fsij.org>
-
- * vm_backtrace.c (id2str): Fix a variable name.
- [ruby-dev:48642] [Bug #10389]
-
-Thu Oct 16 20:01:26 2014 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/envutil.rb (assert_pattern_list): Show number of matched
- patterns and characters.
-
-Thu Oct 16 16:26:09 2014 Eric Wong <e@80x24.org>
-
- * cont.c (fiber_store): fix WIN32 fibers
- [ruby-core:65745] [ruby-core:65758]
-
-Thu Oct 16 15:05:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_here_document): do not append already appended
- and disposed code fragment. [ruby-dev:48647] [Bug #10392]
-
-Thu Oct 16 10:35:33 2014 Eric Wong <e@80x24.org>
-
- * test/-ext-/bug_reporter/test_bug_reporter.rb
- (test_bug_reporter_add): fix race
-
-Thu Oct 16 10:09:02 2014 Eric Wong <e@80x24.org>
-
- * test/ruby/test_rubyoptions.rb (test_segv_test): fix race
-
-Thu Oct 16 09:17:48 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * cont.c (rb_fiber_t): fix compile error caused by move to
- vm_core.h at r47964. [Feature #10341]
-
-Thu Oct 16 08:58:11 2014 Eric Wong <e@80x24.org>
-
- * test/ruby/test_process.rb (test_deadlock_by_signal_at_forking):
- avoid killing wrong parent
-
-Thu Oct 16 08:40:04 2014 Eric Wong <e@80x24.org>
-
- * cont.c (fiber_store): restore references to next_fib (fix typo)
-
-Thu Oct 16 08:26:08 2014 Eric Wong <e@80x24.org>
-
- * cont.c (fiber_store): remove references to nextfib
- fix build when FIBER_USE_NATIVE is 0
-
-Thu Oct 16 06:51:35 2014 Knut Franke <Knut.Franke@gmx.de>
-
- * vm_core.h: declare rb_fiber_t typedef
- (rb_thread_t): fiber and root_fiber become rb_fiber_t * (from VALUE)
- * vm.c (rb_thread_mark): use rb_fiber_mark_self
- * cont.c (rb_fiber_t): prev becomes rb_fiber_t * (from VALUE)
- (cont_mark, cont_free): simplify conditions
- (rb_fiber_mark_self): new function
- (fiber_mark): use rb_fiber_mark_self
- (cont_save_thread, cont_restore_thread): inline
- (cont_restore_thread): simplify
- (fiber_setcontext): simplify conditions
- (rb_cont_call): remove dereference
- (fiber_t_alloc): update for rb_fiber_t->prev type change
- (rb_fiber_start): ditto
- (fiber_current): extract from rb_fiber_current
- (return_fiber): move, simplify type checks
- (rb_fiber_current): use fiber_current
- (fiber_store): simplify type checks
- (fiber_switch): ditto, simplify call to fiber_setcontext,
- use fiber_current
- (rb_fiber_transfer): update for type changes
- (rb_fiber_terminate): move, use fiber_switch
- (rb_fiber_resume): update for type changes
- (rb_fiber_reset_root_local_storage): ditto
- (rb_fiber_yield): use rb_fiber_switch instead of rb_fiber_transfer
- (rb_fiber_m_transfer): ditto
- [ruby-core:65518] [Feature #10341]
-
-Thu Oct 16 06:25:29 2014 Knut Franke <Knut.Franke@gmx.de>
-
- * cont.c (rb_context_t): comment on saved_thread
- (cont_save_thread): sparse copy
- (cont_init): copy extra fields
- (fiber_init): use current thread VM stack size
- [ruby-core:65518] [Feature #10341]
-
-Thu Oct 16 06:13:09 2014 Knut Franke <Knut.Franke@gmx.de>
-
- * cont.c (cont_capture): remove unnecessary variable
- [ruby-core:65518] [Feature #10341]
-
-Thu Oct 16 05:02:31 2014 Knut Franke <Knut.Franke@gmx.de>
-
- * cont.c (fiber_store, fiber_switch): simplify
- [ruby-core:65518] [Feature #10341]
-
-Thu Oct 16 04:28:41 2014 Knut Franke <Knut.Franke@gmx.de>
-
- * cont.c (rb_fiber_t): remove prev_fiber/next_fiber
- (fiber_link_join, fiber_link_remove): remove functions
- (fiber_free, fiber_init, root_fiber_alloc):
- remove references to removed fields and functions
- [ruby-core:65518] [Feature #10341]
-
-Wed Oct 15 22:08:37 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/etc/etc.c (etc_nprocessors_affin): Test CPU_ALLOC availability.
- CentOS 5 don't have CPU_ALLOC().
-
-Wed Oct 15 18:26:19 2014 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * ext/etc/etc.c (etc_nprocessors_affinity): use sched_getaffinity
- for getting precious number of available cpus.
-
- * ext/etc/etc.c (etc_nprocessors): use etc_nprocessors_affinity if
- possible.
-
- [Feature #10267] etc-nprocessors-kosaki2.patch
-
-Wed Oct 15 17:53:28 2014 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/envutil.rb (assert_pattern_list) Renamed from
- assert_regexp_list.
- Show multiline string in multi lines.
-
- * test/-ext-/bug_reporter/test_bug_reporter.rb: Use
- assert_pattern_list.
-
-Wed Oct 15 12:26:58 2014 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/envutil.rb (assert_regexp_list): New assertion method.
-
- * test/ruby/test_rubyoptions.rb: Use assert_regexp_list.
-
-Wed Oct 15 07:21:09 2014 Tanaka Akira <akr@fsij.org>
-
- * enum.c: min(n) drops elements bigger than the n-th maximum element.
- (struct nmin_data): New field to record the n-th maximum element, limit
- (nmin_filter): Update limit field.
- (nmin_i): Drop too big elements.
- (nmin_run): Initialize limit field.
-
-Wed Oct 15 07:00:14 2014 Eric Wong <e@80x24.org>
-
- * test/ruby/test_optimization.rb (test_string_size): new test
-
-Wed Oct 15 06:51:13 2014 Eric Wong <e@80x24.org>
-
- * test/ruby/test_optimization.rb (test_string_eq_neq): new test
- (test_string_ltlt): ditto
-
-Wed Oct 15 06:50:29 2014 Eric Wong <e@80x24.org>
-
- * test/ruby/test_optimization.rb (test_hash_aset_with):
- assert assignment
-
-Wed Oct 15 04:56:27 2014 Zachary Scott <e@zzak.io>
-
- * gc.c (rb_obj_id): [DOC] Fix typo, clean up sentence, and wrap cols
-
-Wed Oct 15 04:53:30 2014 Zachary Scott <e@zzak.io>
-
- * error.c: [DOC] Fix case of type in exception message by @tricknotes
- [Fixes GH-740] https://github.com/ruby/ruby/pull/740
-
- * object.c: ditto
-
-Tue Oct 14 21:39:16 2014 Vit Ondruch <vondruch@redhat.com>
-
- * tool/rbinstall.rb (gem): Fix permissions of bundled gems
- specification files. [ruby-core:65700] [Bug #10383]
-
-Tue Oct 14 19:15:31 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_record.c: use typed data.
-
-Tue Oct 14 16:23:12 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * symbol.c (global_symbols): make ids two-dimensional array of
- strings and symbols, for write-barrier.
-
- * symbol.c (global_symbols): make IDs immortal always, instead
- of treating dynamic symbols as IDs.
-
- * iseq.c, marshal.c, string.c: use rb_str_intern instead of
- rb_str_dynamic_intern.
-
- * symbol.c (rb_str_intern): rename rb_str_dynamic_intern.
-
-Tue Oct 14 10:19:10 2014 Eric Wong <e@80x24.org>
-
- * test/ruby/test_optimization.rb (test_string_freeze): new test
- (test_hash_aref_with): ditto
- (test_hash_aset_with): ditto
-
-Tue Oct 14 01:27:54 2014 Tanaka Akira <akr@fsij.org>
-
- * enum.c (nmin_run): max(n) and max_by(n) returns an array in
- descending order.
- [ruby-core:65452] Suggested by David Grayson.
-
-Mon Oct 13 20:44:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (update-gems): chdir to the target directory and then
- add the tool directory to load paths, for older BASERUBY.
- [Bug #10372][ruby-core:65630]
-
-Mon Oct 13 17:53:01 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/xmlrpc/parser.rb: added new parser class using libxml-ruby gem.
- [Feature #9379][ruby-core:59633]
- * lib/xmlrpc/config.rb: ditto.
-
-Mon Oct 13 16:32:56 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/find.rb (Find.find): Call to_path for arguments to obtain
- strings.
- [ruby-core:63713] [Bug #10035] Reported by Herwin.
-
-Mon Oct 13 15:42:25 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * common.mk: use relative load path for bundled_gems directory.
- [Bug #10372][ruby-core:65630]
-
-Mon Oct 13 08:44:06 2014 Zachary Scott <e@zzak.io>
-
- * README.EXT: [DOC] fix example missing typedef with patch by
- @steveklabnik [Fixes GH-739] https://github.com/ruby/ruby/pull/739
-
- * README.EXT.ja: ditto.
-
-Mon Oct 13 06:52:09 2014 Eric Wong <e@80x24.org>
-
- * array.c (ary_recycle_hash): add RB_GC_GUARD
- (rb_ary_diff): remove volatile
- [Bug #10369]
-
-Mon Oct 13 03:20:23 2014 Zachary Scott <e@zzak.io>
-
- * ext/date/date_core.c: [DOC] Clean up whitespace, examples, and typos
- in date_core based on a patch by @vipulnsward [Fixes GH-724]
- https://github.com/ruby/ruby/pull/724
-
-Mon Oct 13 02:39:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (remove_duplicate_keys): should not simply eliminate all
- value nodes, which may have side effects.
- [ruby-core:65625] [Bug #10315]
-
-Sun Oct 12 10:39:16 2014 Zachary Scott <e@zzak.io>
-
- * vm.c: [DOC] fix typo by @yui-knk [Fixes GH-738]
- https://github.com/ruby/ruby/pull/738
-
-Sun Oct 12 09:24:15 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/test/unit.rb: Hide skips by default.
-
-Sun Oct 12 01:37:11 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
-
- * file.c: include sys/time.h only if HAVE_SYS_TIME_H
-
-Sat Oct 11 22:29:40 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
-
- * file.c (HAVE_UTIMENSAT): disabled for NativeClient.
- Fixes build error.
-
-Sat Oct 11 22:11:58 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
-
- * ext/extmk.rb: generates the rule for extinit.$(OBJEXT).
- extinit.$(OBJEXT) used to be generated by the builtin rule, thus
- didn't accept custom $(CC) and caused linkage error for cross
- compiling.
-
-Sat Oct 11 18:46:50 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
-
- * include/ruby/intern.h (rb_fd_select): declare struct timeval, or the
- struct gets local to the function in C99.
-
- * file.c (#include): add nacl/stat.h for PNaCl.
- (utimes): added a declaration for PNaCl.
- (stat_atimespec): stat::st_atimensec is long long but
- timespec::tv_nsec is long in PNaCl.
- (stat_mtimespec, stat_ctimespec): ditto.
- (rb_group_member): disable getgroups unless HAVE_GETGROUPS.
- (eaccess): unify the fallback to generic defined(USE_GETEUID).
-
- * io.c: include sys/time.h for struct timeval.
- (rb_close_before_exec): nothing we can do if F_GETFD is not
- available.
- (ioctl): pnacl newlib actually doesn't have ioctl.
-
- * process.c (maxgroups): it is used iff
- defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX) but not
- defined(HAVE_GETGROUPS) || defined(HAVE_SETGROUPS).
- (obj2gid): fail unless the object is a Fixnum if getgrnam is not
- available.
- (disable_child_handler_fork_child): sigaction is not available in
- PNaCl newlib.
-
- * configure.in (warnflags, strict_warnflags): avoid -ansi for strlcpy.
- (rb_cv_gcc_atomic_builtins): also check
- __atomic_or_etch because it is used in ruby_atomic.h.
- (rb_cv_gcc_sync_builtins): ditto.
- (HAVE_GETGRNAM): added.
-
-Sat Oct 11 15:32:08 2014 Eric Wong <e@80x24.org>
-
- * compile.c (iseq_build_from_ary_exception): move RB_GC_GUARD
- (iseq_build_from_ary_body): use PRIsVALUE instead of RB_GC_GUARD
-
-Sat Oct 11 14:57:08 2014 Eric Wong <e@80x24.org>
-
- * string.c (rb_str_intern): remove unnecessary RB_GC_GUARD
-
-Sat Oct 11 13:47:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (remove_duplicate_keys): remove duplicate literal keys,
- i.e., symbols and strings. [ruby-core:65368] [Bug #10315]
-
- * vm.c (kwmerge_i): override existing keys by new keys.
- [ruby-core:65368] [Bug #10315]
-
- * parse.y (assocs): concatenate splatted literal hashes. the
- former key has precedence even if duplicated literal keys
- follow. [ruby-core:65368] [Bug #10315]
-
-Sat Oct 11 12:27:03 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
-
- * configure.in (RUBY_NACL): automatically locate pnacl-clang.
- (RUBY_PLATFORM): pnacl instead of le32-nacl.
-
-Sat Oct 11 11:27:14 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
-
- * io.c: fix issues in the last two commits. don't disable cloexec for
- platforms other than NativeClient.
-
- * ChangeLog: ditto. add entries for the last two commits.
-
-Sat Oct 11 11:12:00 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
-
- * signal.c (install_signalhandler, init_sigchld): allow failure because it
- always fails with ENOSYS on NaCl.
-
-Sat Oct 11 11:11:53 2014 Yuki Yugui Sonoda <yugui@yugui.jp>
-
- * configure.in (RUBY_NACL and others): merge patch from naclports. Supports PNaCl.
-
- * dln.c: ditto. replace the old hacky dynamic loading over HTTP with nacl_io.
-
- * file.c: ditto. tentatively use access(2) instead of eaccess.
- (rb_file_load_ok): weaken with attribute but not by postprocess.
-
- * io.c: ditto.
- (socket.h): now NaCl has socket.h
- (flock): disable here instead of nacl/ioctl.h
-
- * nacl/GNUmakefile.in: ditto.
- (CC, LD, NM, AR, AS, RANLIB, OBJDUMP, OBJCOPY):
- respect path to them if they are absolute.
- This helps naclports to build ruby in their source tree.
- (PROGRAM_NMF, .SUFFIXES): support .pnexe for PNaCl.
- (ruby.o, file.o): move the hack to attributes in ruby.c and file.c
-
- * nacl/ioctl.h: ditto. removed. move the hack to io.c.
-
- * nacl/nacl-config.rb: ditto. support arm, pnacl and others.
-
- * nacl/pepper_main.c: ditto. support build in a naclports tree.
-
- * ruby.c (rb_load_file): ditto. weaken with attribute but not by postprocess.
-
-Sat Oct 11 09:32:00 2014 Zachary Scott <e@zzak.io>
-
- * ext/socket/unixsocket.c: [DOC] Fix example to render in HTML
- properly, with a patch by @eval [Fixes GH-733]
- https://github.com/ruby/ruby/pull/733
-
-Sat Oct 11 04:14:41 2014 Kir Shatrov <shatrov@me.com>
-
- * lib/open-uri.rb (OpenURI::Options): add :open_timeout default
- * (def OpenURI.open_http): check :open_timeout option
- * (module OpenURI): rdoc for :open_timeout
- * test/open-uri/test_open-uri.rb (test_open_timeout): new test
- [Feature #10361]
-
-Fri Oct 10 11:27:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/io.h (rb_io_mode_flags, rb_io_modenum_flags):
- deprecate old macros for compatibility for ruby 1.8 and older.
-
-Thu Oct 9 23:31:47 2014 Naohisa Goto <ngotogenome@gmail.com>
-
- * bignum.c (absint_numwords_generic): set an array element after
- definition of a variable to fix compile error with older version
- of fcc (Fujitsu C Compiler) 5.6 on Solaris 10 on Sparc.
- [Bug #10350] [ruby-dev:48608]
-
-Thu Oct 9 16:15:26 2014 Eric Wong <e@80x24.org>
-
- * ext/-test-/st/foreach/extconf.rb: new file
- * ext/-test-/st/foreach/foreach.c: ditto
- * test/-ext-/st/test_foreach.rb: ditto
- [Feature #10321]
-
-Thu Oct 9 12:40:28 2014 Eric Wong <e@80x24.org>
-
- * benchmark/bm_hash_aref_sym*.rb: force static symbols
-
-Thu Oct 9 12:38:28 2014 Eric Wong <e@80x24.org>
-
- * hash.c (rb_any_hash): remove unnecessary dsym check
-
-Thu Oct 9 07:20:30 2014 Rei Odaira <Rei.Odaira@gmail.com>
-
- * missing/setproctitle.c: Avoid invalidating argv[1], argv[2],
- etc. until the first call to Process.setproctitle, because
- the ps command of AIX refers to the argv array.
- [Bug #10090]
-
-Thu Oct 9 00:53:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (dir_s_aref): fix rdoc. `Dir.glob` allows an array but
- `Dir[]` not. the former accepts an optional parameter `flags`,
- while the latter accepts arbitrary number of arguments but no
- `flags`. [ruby-core:65265] [Bug #10294]
-
-Wed Oct 8 21:44:10 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_variable.c: use typed data.
-
-Wed Oct 8 16:36:47 2014 gogo tanaka <mail@tanakakazuki.com>
-
- * test/ruby/test_syntax.rb: added syntax tests of underscore
- arguments. [Feature #10340][ruby-core:65496]
-
-Wed Oct 8 07:42:39 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/generic.rb (URI#inspect): remove Object id.
- URI is considered that it doesn't require id.
-
-Wed Oct 8 05:22:42 2014 Eric Wong <e@80x24.org>
-
- * ext/etc/etc.c (etc_systmpdir): set default tmplen correctly
- Fixup r47826
-
-Wed Oct 8 05:16:32 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Add @- and @+ for Matrix and Vector.
- patch by gogo tanaka [#10068] [#10069]
-
-Wed Oct 8 04:58:48 2014 John Bachir <j@jjb.cc>
-
- * bootstraptest/test_io.rb (assert_finish):
- normalize rescue for Timeout::Error
- * lib/net/ftp.rb (Net#read_timeout): ditto for doc
- * lib/resolv.rb (Resolv::ResolvTimeout): ditto for subclass
- * lib/webrick/httprequest.rb (_read_data): ditto for rescue
- * sample/timeout.rb (p timeout): ditto for call
- * test/drb/drbtest.rb (test_06_timeout): ditto
- * test/ruby/test_readpartial.rb (test_open_pipe): ditto
- * test/thread/test_queue.rb (test_queue_thread_raise): ditto
- * thread.c (rb_thread_s_handle_interrupt): ditto for doc
- [ruby-core:65481] [misc #10339]
-
-Wed Oct 8 04:38:29 2014 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/ruby/test_process.rb (TestProcess#test_setsid): AIX
- does not allow Process::getsid(pid) when pid is in a
- different session.
-
-Wed Oct 8 04:33:04 2014 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/ruby/test_rubyoptions.rb (TestRubyOptions#test_encoding):
- On AIX, locale_charmap is ISO-8859-1 with LANG=C. This means
- the source encoding of stdin is ISO-8859-1, so "invalid
- multibyte char" error does not occur.
-
-Wed Oct 8 04:30:29 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Add Matrix#laplace_expansion.
- patch by gogo tanaka [#10073]
-
-Wed Oct 8 04:29:21 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Add Vector.basis.
- Based on patch by gogo tanaka [#10072]
-
-Tue Oct 7 23:40:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * signal.c (rb_f_kill): get rid of deadlock as unhandled and
- discarded signals do not make interrupt_cond signaled.
- based on the patch by Kazuki Tsujimoto at [ruby-dev:48606].
- [Bug #9820]
-
-Tue Oct 7 22:43:44 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_method.c: use typed data.
-
-Tue Oct 7 21:47:05 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_param.c: refactoring.
-
-Tue Oct 7 21:40:17 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_method.c: refactoring. add
- olemethod_data_get_struct to wrap Data_Get_Struct.
- * ext/win32ole/win32ole_method.h: ditto.
-
- * ext/win32ole/win32ole_param.c (oleparam_ole_param):
- call olemethod_data_get_struct instead of Data_Get_Struct.
-
-Tue Oct 7 11:17:08 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/etc/etc.c (etc_systmpdir): try user temporary directory by
- confstr() on Mac OS X.
- c.f. http://www.opensource.apple.com/source/ruby/ruby-104/patches/ext_etc_etc.c.diff
-
-Tue Oct 7 10:48:17 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (struct stat.st_size): prefer off_t over int, long,
- and so on. inspired by
- http://www.opensource.apple.com/source/ruby/ruby-104/patches/config.h.ed
-
-Tue Oct 7 10:37:39 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (RUBY_UNIVERSAL_ARCH): fix missing quoting
- brackets. incorporated from
- http://www.opensource.apple.com/source/ruby/ruby-104/patches/configure.diff
-
-Mon Oct 6 23:34:42 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_param.c: use typed data.
-
-Mon Oct 6 22:37:09 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * symbol.h (struct RSymbol): move from internal.h.
-
-Mon Oct 6 21:43:03 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * error.c: update exception tree. [DOC]
- reported by @hemge via twitter.
-
-Mon Oct 6 18:43:03 2014 Rei Odaira <Rei.Odaira@gmail.com>
-
- * configure.in: Fix typo. [Bug #9914]
-
-Mon Oct 6 16:23:30 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * signal.c (rb_f_kill): should not ignore signal unless the
- default handler is registered. [ruby-dev:48592] [Bug #9820]
-
-Mon Oct 6 16:07:11 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/ruby/test_string.rb (test_LSHIFT_neary_long_max): enable
- only on platforms where string size range is smaller than memory
- space. this test does not make sense but just wastes memory and
- time on other platforms, as it is hardly possible that a string
- size becomes neary LONG_MAX if long size equals pointer size.
- [ruby-core:65410] [Bug #10325]
-
-Mon Oct 6 11:21:21 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/unicode_norm_gen.rb: Adding/tweaking comments.
-
-Mon Oct 6 10:57:57 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/unicode_norm_gen.rb: Adjusted directory paths.
-
-Mon Oct 6 10:27:27 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/unicode_norm_gen.rb: Data generation script imported from
- https://github.com/duerst/eprun/blob/master/lib/generate.rb
-
-Mon Oct 6 10:15:15 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/downloader.rb: Adjust example in documentation for
- Downloader.download.
-
-Mon Oct 6 10:07:07 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize: New folder for Unicode normalization
- functionality
-
-Sun Oct 5 11:04:13 2014 Luiz Angelo Daros de Luca <luizluca@gmail.com>
-
- * ext/digest/{md5,rmd160,sha1,sha2}/extconf.rb: configure OpenSSL
- only if bundled libraries is not used, so that OpenSSL is not
- linked unnecessarily. [ruby-core:65404] [Bug #10324]
-
-Sun Oct 5 10:39:11 2014 Luiz Angelo Daros de Luca <luizluca@gmail.com>
-
- * ext/digest/rmd160/extconf.rb: fix transform function name to
- check. [ruby-core:65091] [Bug #10252]
-
-Sun Oct 5 05:46:00 2014 Eric Wong <e@80x24.org>
-
- * ext/zlib/zlib.c (zstream_mark, zstream_free): update signature
- (gzfile_mark, gzfile_free): ditto
- (zstream_memsize): new function for rb_data_type->dsize
- (gzfile_memsize): ditto
- (zstream_data_type, gzfile_data_type): new data types
- (zstream_new): Data_Make_Struct => TypedData_Make_Struct
- (gzfile_new): ditto
- (get_zstream, get_gzfile): Data_Get_Struct => TypedData_Get_Struct
- (rb_zstream_flush_next_in): ditto
- (rb_zstream_flush_next_out): ditto
- (rb_zstream_avail_out): ditto
- (rb_zstream_avail_in): ditto
- (rb_zstream_closed_p): ditto
- (rb_deflate_initialize): ditto
- (rb_deflate_init_copy): ditto
- (rb_inflate_initialize): ditto
- (gzfile_ensure_close): ditto
- (rb_gzfile_closed_p): ditto
- (rb_gzfile_path): ditto
- (rb_gzwriter_initialize): ditto
- (rb_gzreader_initialize): ditto
- (rb_gzreader_unused): ditto
- [ruby-core:65377] [Feature #10319]
-
-Sat Oct 4 16:24:41 2014 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/test_syslog.rb (TestSyslog#test_log): In AIX, each output
- line of LOG_PERROR to stderr has an additional empty line appended,
- so skip that line.
-
-Sat Oct 4 16:05:49 2014 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/socket/test_unix.rb (TestSocket_UNIXSocket#test_too_long_path):
- sockaddr_un.sun_path in AIX is defined as char[1024],
- so "a" * 300 is not too long. "a" * 3000 would be enough.
-
-Sat Oct 4 09:12:03 2014 Zachary Scott <e@zzak.io>
-
- * ext/win32ole/sample/example*.rb: Add wait input to quit for examples
- with patch provided by @windwiny [Fixes GH-705]
- https://github.com/ruby/ruby/pull/705
-
-Sat Oct 4 09:08:18 2014 Zachary Scott <e@zzak.io>
-
- * ext/win32ole/win32ole.c: [DOC] Fix typo in :nodoc: reported by
- @windwiny to [Fix GH-705] https://github.com/ruby/ruby/pull/705
-
- * ext/pty/pty.c: ditto
-
-Sat Oct 4 08:59:45 2014 Zachary Scott <e@zzak.io>
-
- * ext/openssl/ossl_rand.c: [DOC] Add call signature for pseudo_bytes
- and random_bytes, wrap lines at 80 chars, and remove useless
- comments.
-
-Sat Oct 4 08:49:34 2014 Zachary Scott <e@zzak.io>
-
- * ext/openssl/ossl_rand.c: [DOC] Add rdoc for method descriptions
- By @vipulnsward [Fixes GH-657] https://github.com/ruby/ruby/pull/657
-
-Sat Oct 4 08:23:48 2014 Zachary Scott <e@zzak.io>
-
- * ext/openssl/ossl_rand.c: Use rb_define_module_function instead of
- macro. [Fixes GH-686] https://github.com/ruby/ruby/pull/686
-
-Sat Oct 4 06:04:56 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_method.c(olemethod_set_member): remove
- redundant NULL check.
- * ext/win32ole/win32ole_type.c(oletype_set_member): ditto.
-
-Sat Oct 4 00:25:04 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * .travis.yml: removed needless preparation for gcc.
-
-Fri Oct 3 23:41:20 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * .travis.yml: enabled gcc build with osx on travis.
-
-Fri Oct 3 23:22:23 2014 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * template/fake.rb.in: fix make install failure due to MSYS path
- with mingw on MSYS environment.
- [ruby-core:64965] [Bug #10230]
-
-Fri Oct 3 21:02:32 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/ruby/test_io.rb (TestIO#test_advise): avoid to infinite loop.
-
-Fri Oct 3 19:26:01 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * .travis.yml: enabled test results of linux.
-
-Fri Oct 3 18:52:16 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/ruby/test_io.rb (TestIO#test_advise): added workaround of fadvise(2)
- with tmpfs and old linux kernel. [ruby-core:65355][Bug #10313]
-
-Fri Oct 3 18:22:45 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * .travis.yml: Disabled to generate document on travis.
- Reduce test running time.
-
-Fri Oct 3 12:42:15 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Add hstack & vstack methods.
- Based on a patch by creasywuqiong. [Fix GH-344]
-
-Fri Oct 3 12:37:48 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Fix Matrix.rows copy bug.
- Patch by Arron Mabrey. [Fix GH-707]
-
-Fri Oct 3 06:06:28 2014 Eric Wong <e@80x24.org>
-
- * st.c (next_pow2): new function (from old bignum.c)
- (new_size): use next_pow2 function
-
-Fri Oct 3 05:58:58 2014 Eric Wong <e@80x24.org>
-
- * vm_trace.c (rb_tp_t): pack 56 => 48 bytes on 64-bit
-
-Thu Oct 2 18:41:45 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/etc/etc.c (etc_nprocessors): Windows support.
- see [Feature #10267]
-
-Thu Oct 2 12:21:52 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/etc/etc.c (etc_nprocessors): New method.
- Accepted by matz at RubyKaigi 2014.
- [ruby-core:65142] [Feature #10267]
-
-Thu Oct 2 07:56:49 2014 Eric Wong <e@80x24.org>
-
- * iseq.c (rb_iseq_line_trace_each): explicit cast
- Fix https://travis-ci.org/ruby/ruby/jobs/36814282
-
-Thu Oct 2 05:40:05 2014 Eric Wong <e@80x24.org>
-
- * ruby.h: set rb_event_flag_t to uint32_t
- [ruby-core:65315] [misc #10249]
-
-Thu Oct 2 05:32:17 2014 Eric Wong <e@80x24.org>
-
- * io.c (fptr_finalize): free memory before GC sweep
- [ruby-core:65269] [Feature #10295]
-
-Thu Oct 2 05:27:24 2014 Eric Wong <e@80x24.org>
-
- * marshal.c (w_class): check dump_arg->compat_tbl before lookup
- (w_object): lazy init ->compat_tbl before insert
- (obj_alloc_by_class): ditto
- (clear_dump_arg): free only non-NULL ->compat_tbl
- (clear_load_arg): ditto for ->compat_tbl
- (marshal_dump): ->compat_tbl defaults to zero
- (marshal_load): ditto for ->compat_tbl
- (r_entry0): check l->compat_tbl before lookup
- (r_fixup_compat): ditto
- [ruby-core:65305] [Feature #10302]
-
-Wed Oct 1 21:14:34 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_type.c: use typed data.
-
-Wed Oct 1 18:15:42 2014 Nolan Evans <nolane@gmail.com>
-
- * compile.c: remove commented out code.
-
-Wed Oct 1 17:38:53 2014 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/fileutils/test_fileutils.rb: AIX does not allow
- a sticky bit on a regular file.
-
-Wed Oct 1 17:31:41 2014 Eric Hodel <drbrain@segment7.net>
-
- * NEWS: Add RubyGems update.
-
-Wed Oct 1 17:28:58 2014 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems 2.4.2.
- * test/rubygems: ditto.
-
-Tue Sep 30 22:25:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_data_type): separate ripper data type for from
- parser.
-
-Tue Sep 30 18:46:31 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_typelib.c: use typed data.
-
-Tue Sep 30 09:51:46 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * common.mk: fixed broken reference of update-config_files task
-
-Mon Sep 29 22:54:51 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/file.c (append_wstr): set expanded length, not length of
- appended string. fix "probable buffer overflow" bug.
- [ruby-core:65317] [Bug #10304]
-
- * string.c (str_make_independent_expand): drop NOFREE flag after
- reallocation, static buffer is not pointed anymore.
- [ruby-core:65317] [Bug #10304]
-
-Sun Sep 28 23:59:17 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * gc.c (rb_gcdebug_print_obj_condition): use RVALUE_REMEMBERED
- because GET_HEAP_REMEMBERSET_BITS is obsoleted.
-
-Sun Sep 28 11:14:14 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * common.mk: Created new target update-unicode to download
- some Unicode data files.
-
-Fri Sep 26 15:03:19 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * lib/uri/rfc3986_parser.rb: raise URI::InvalidURIError when
- uri doesn't respond to #to_str. [ruby-core:64453] [Bug #10150]
-
- * test/uri/test_parser.rb: test for above.
-
-Sat Sep 27 10:31:48 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * gems/bundled_gems: upgraded to power_assert 0.1.4.
-
-Fri Sep 26 12:52:36 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/stringio/stringio.c (strio_write): ASCII-8BIT StringIO
- should be writable any encoding strings, without conversion.
- [ruby-core:65240] [Bug #10285]
-
-Fri Sep 26 05:21:01 2014 Eric Wong <e@80x24.org>
-
- * object.c (rb_class_real): do not dereference 0 VALUE
-
- * test/ruby/test_module.rb (test_inspect_segfault):
- Test case and bug report by Thomas Stratmann.
- [ruby-core:65214] [Bug #10282]
-
-Fri Sep 26 05:12:10 2014 Eric Wong <e@80x24.org>
-
- * man/ruby.1: document stack size env variables
- [Feature #10197]
-
-Thu Sep 25 19:37:34 2014 Eric Wong <e@80x24.org>
-
- * io.c (free_io_buffer): new function for a common pattern
- (clear_readconv): use free_io_buffer
- (rb_io_fptr_finalize): ditto
-
-Thu Sep 25 07:51:07 2014 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * lib/matrix.rb: Fix docs. Patched by Ben Woodall. [GH-726]
-
-Wed Sep 24 19:04:04 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/data: New directory for downloaded Unicode
- data files.
-
-Wed Sep 24 18:59:59 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/downloader.rb: Adjusting example for
- Downloader.download to implementation changes in r47693.
-
-Wed Sep 24 18:06:06 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/downloader.rb: Removing unused method
- Downloader.download_if_modified_since.
- (if ever used, just replace with Downloader.download)
-
-Wed Sep 24 17:59:59 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/downloader.rb: Fixing raise after return.
-
-Wed Sep 24 17:55:55 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/downloader.rb: Made Unicode data file location available
- via :unicode Symbol.
-
-Wed Sep 24 10:45:45 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/downloader.rb: Small fix to documentation comment.
-
-Tue Sep 23 22:00:20 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parse_ident): just after a label, new expression should
- start, cannot be a modifier. [ruby-core:65211] [Bug #10279]
-
-Tue Sep 23 16:07:07 2014 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/downloader.rb: added Downloader.download_if_modified_since
- to reduce downloads of large files that change only rarely.
- [ruby-core:65164] [CommonRuby - Feature #10084]
-
-Tue Sep 23 11:55:09 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * .travis.yml: added rubyspec into travis tasks and eliminate to stdout.
-
-Mon Sep 22 20:00:29 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * test/win32ole/test_win32ole_variant.rb
- (test_conversion_time2date_with_msec): test by using only
- assert_in_delta to avoid to fail when converting Time object with
- 999999999 nanoseconds into VT_DATE Variant.
-
-Mon Sep 22 19:49:12 2014 Zachary Scott <e@zzak.io>
-
- * doc/syntax/methods.rdoc: [DOC] [] and []= methods by @process
- [Fixes GH-662] https://github.com/ruby/ruby/pull/662
-
-Mon Sep 22 18:21:35 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * .travis.yml: Only osx build is enabled. linux builds is random failure
- and test results of major linux is covered by rubyci.
-
-Mon Sep 22 12:10:29 2014 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_time_tz.rb: Fix test error with tzdata-2014g.
- [ruby-core:65058] [Bug #10245] Reported by Vit Ondruch.
-
-Mon Sep 22 09:28:43 2014 Eric Wong <e@80x24.org>
-
- * ext/socket/ancdata.c ({send,recv}msg_args_struct): 24 => 16 bytes
- * ext/socket/init.c (connect_arg): ditto
- * ext/socket/raddrinfo.c (getnameinfo_arg): 56 => 48 bytes
- (reductions only for 64-bit systems)
-
-Mon Sep 22 02:04:25 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/drb/drb.rb: Support graceful shutdown.
- (DRbTCPSocket#initialize): Create a pipe for shutdown notification.
- (DRbTCPSocket#close): Invoke close_shutdown_pipe.
- (DRbTCPSocket#close_shutdown_pipe): New private method.
- (DRbTCPSocket#accept): Use accept_or_shutdown.
- (DRbTCPSocket#accept_or_shutdown): New private method which returns
- nil on shutdown.
- (DRbServer#stop_service): Use shutdown instead of Thread#kill.
- (DRbServer#run): Break infinite loop when main_loop returns nil.
- (DRbServer#main_loop): @protocol.accept may return nil.
-
- * lib/drb/ssl.rb: Follow above change.
-
- * lib/drb/unix.rb: Ditto.
-
-Sun Sep 21 13:54:36 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * time.c: raise exception when minutes of utc_offset is out of 00-59.
- patch is from Kenichi Kamiya.
- [ruby-dev:47539] [Bug #8679]
-
- * test/ruby/test_time.rb: test for above.
- patch is from Kenichi Kamiya.
-
-Sun Sep 21 19:04:08 2014 Narihiro Nakamura <authornari@gmail.com>
-
- * st.c (do_hash_bin): unused macro.
-
-Sun Sep 21 18:45:01 2014 Narihiro Nakamura <authornari@gmail.com>
-
- * parse.y (parser_class_nest): unused variable after YARV
- merged (r11439).
-
-Sun Sep 21 18:14:03 2014 Narihiro Nakamura <authornari@gmail.com>
-
- * st.c (numberof): unused. internal.h has same macro.
-
- * node.c (F_CUSTOM2): unused.
-
-Sun Sep 21 14:11:23 2014 Tanaka Akira <akr@fsij.org>
-
- * thread_pthread.c (native_set_thread_name): New function to
- set thread name visible with ps command on GNU/Linux.
- Ex. ps -o %c -L
-
- * thread.c (thread_start_func_2): Call native_set_thread_name at
- beginning.
- (rb_thread_inspect_msg): Extract from rb_thread_inspect.
-
-Sun Sep 21 12:49:11 2014 Eric Wong <e@80x24.org>
-
- * iseq.c (rb_iseq_defined_string): trim redundant semi-colon
-
-Sun Sep 21 12:19:29 2014 Eric Wong <e@80x24.org>
-
- * file.c (rb_find_file_ext_safe): clear tmp buffer on failure
- (rb_find_file_safe): ditto
-
-Sat Sep 20 04:42:18 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * lib/csv.rb: avoid unnecessary object allocations.
- patch is from Andrew Vit. [ruby-core:63215] [Feature #9952]
-
-Sun Sep 21 12:10:18 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rexml/**/*.rb: removed commented-out code.
-
-Sat Sep 20 03:46:58 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c: use rb_equal_opt() for performance improvement.
- [ruby-core:64954] [Feature #10227]
-
-Sun Sep 21 11:16:56 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (rbtime2vtdate, vtdate2rbtime): fix
- the bug in conversion of milliseconds. [Bug #10258]
-
- * test/win32ole/test_win32ole_variant.rb
- (test_conversion_dbl2date_with_msec,
- test_conversion_time2date_with_msec): use assert_in_delta instead
- of assert_equal to treat an acceptable error range.
-
-Sun Sep 21 11:03:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * signal.c (ruby_signal): although "EINVAL from sigaction(2) is
- not a bug", but even it is a failure. pointed at toRuby/guRuby
- in RubyHiroba.
-
-Sat Sep 20 03:00:26 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * lib/tempfile.rb: define parameters appropriately and some
- refactoring.
-
- * lib/tmpdir.rb: ditto.
-
-Sat Sep 20 23:58:21 2014 Tanaka Akira <akr@fsij.org>
-
- * enum.c (enum_chunk): Deprecate the state management.
- (enum_slice_before): Ditto.
-
-Sat Sep 20 15:39:11 2014 Tanaka Akira <akr@fsij.org>
-
- * enum.c (enum_slice_when): New method: Enumerable#slice_when.
- (slicewhen_i): New function.
- (slicewhen_ii): New function.
-
- * enumerator.c (InitVM_Enumerator): New method:
- Enumerator::Lazy#slice_when.
-
- [ruby-core:62499] [Feature #9826]
-
-Sat Sep 20 11:55:19 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * .travis.yml: added new configurations for osx on travis ci.
- [fix GH-723]
- * test/ruby/test_object.rb: tweaked to memory leak limit for osx build.
-
-Sat Sep 20 10:48:41 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (assoc): allow quoted ID as a key of a hash literal.
- [ruby-core:34453] [Feature #4276]
-
-Sat Sep 20 10:23:00 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_set_arguments): store local variable IDs in
- temporary list as Symbols. previously these are stored as
- Fixnums to prevent from GC, but IDs of dynamic symbols can
- exceed Fixnum range and cause RangeError at inverting from
- Fixnum. [ruby-dev:48564] [Bug #10266]
-
-Sat Sep 20 10:02:51 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/openssl/lib/openssl/x509.rb (OpenSSL::X509::Name#pretty_print):
- New method.
- (OpenSSL::X509::Certificate#pretty_print): Ditto.
-
- * ext/openssl/lib/openssl/bn.rb (OpenSSL::BN#pretty_print): Ditto.
-
-Sat Sep 20 07:55:57 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (eval_string_with_cref): fix super from eval with
- scope. set klass in the current control frame to the class of
- the receiver in the context to be evaluated, this class/module
- must match the actual receiver to call super.
- [ruby-core:65122] [Bug #10263]
-
-Fri Sep 19 20:06:00 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * symbol.c (rb_str_dynamic_intern): check if the stem ID of
- attrset ID is already registered as a static ID.
- [ruby-dev:48559] [Bug #10259]
-
-Fri Sep 19 15:48:09 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/Makefile.sub (VCSUP): nothing to do if this worktree is not
- under any VCS (it means that the worktree may be from the release
- package).
-
-Fri Sep 19 10:47:03 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/ruby/test_math.rb (TestMath#assert_infinity): Float#finite?
- returns true also for NaN, so use Float#infinite? instead.
- [ruby-core:65117] [Feature #10261]
-
-Fri Sep 19 05:36:16 2014 Eric Wong <e@80x24.org>
-
- * NEWS: note --with-jemalloc option [ci skip]
-
-Thu Sep 18 16:26:27 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/rubygems/test_gem_commands_setup_command.rb: @ui uses StringIO
- as its streams, and Encoding.default_external does not effect to
- StringIOs already exist. so, we need to set external_encoding of
- @ui.outs directly. this problem (test failure) does not appear in
- the environments default_external is us-ascii or utf-8.
-
-Thu Sep 18 15:02:15 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/rubygems/test_gem_specification.rb: '/' is not always the root.
-
-Thu Sep 18 09:36:37 2014 Scott Francis <scott.francis@shopify.com>
-
- * vm_method.c (Init_Method): make global method cache size
- configurable by environment variable
- "RUBY_GLOBAL_METHOD_CACHE_SIZE" [Fix GH-719]
-
-Thu Sep 18 07:03:36 2014 Eric Wong <e@80x24.org>
-
- * test/-ext-/string/test_modify_expand.rb: increase limit
- for {je,tc}malloc [Bug #10236]
-
-Thu Sep 18 06:41:18 2014 Eric Wong <e@80x24.org>
-
- * ext/zlib/zlib.c (struct gzfile): pack (288 => 272 bytes) on 64-bit
-
-Thu Sep 18 05:44:05 2014 Eric Wong <e@80x24.org>
-
- * ext/socket/init.c (rsock_connect): refactor for blocking
- (wait_connectable): clear error before wait
- [Bug #9356]
-
-Wed Sep 17 23:12:36 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/rfc3986_parser.rb: specify a regexp for :OPAQUE; generic.rb
- assumes it is present, and will refuse all values otherwise.
- by Matthew Draper <matthew@trebex.net>
- https://github.com/ruby/ruby/pull/718 fix GH-718
-
-Wed Sep 17 16:22:58 2014 Eric Wong <e@80x24.org>
-
- * ext/zlib/zlib.c (zlib_mem_alloc): check overflow
-
-Wed Sep 17 11:33:35 2014 Laurent Arnoud <laurent@spkdev.net>
-
- * test/fiddle/test_import.rb (Fiddle::TestImport#test_sizeof):
- added test for long long [fix GH-716]
-
-Wed Sep 17 11:09:21 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * tool/rbinstall.rb: fixed invalid options with latest rubygems.
- https://github.com/rubygems/rubygems/issues/1013
-
-Tue Sep 16 19:19:00 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * benchmark/bm_app_aobench.rb: update outdated links to the
- original program. [ruby-dev:48550] [Feature #10247]
-
-Tue Sep 16 01:06:40 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * reg*.c: Merge Onigmo 5.15.0 38a870960aa7370051a3544
-
-Mon Sep 15 16:21:10 2014 Eric Wong <e@80x24.org>
-
- * io.c (struct io_advise_struct): 32 => 24 bytes on 64-bit
- * io.c (struct io_internal_writev_struct): 24 => 16 bytes on 64-bit
- * process.c (struct waitpid_arg): ditto
-
-Mon Sep 15 10:29:25 2014 Natalie Weizenbaum <nweiz@google.com>
-
- * ext/pathname/lib/pathname.rb (SAME_PATHS):
- Pathname#relative_path_from uses String#casecmp to compare strings
- on case-insensitive filesystem platforms (e.g., Windows). This can
- return nil for strings with different encodings, and the code
- previously assumed that it always returned a Fixnum. [Fix GH-713]
-
-Mon Sep 15 09:43:18 2014 Sho Hashimoto <sho.hsmt@gmail.com>
-
- * ext/fiddle/lib/fiddle/import.rb (Fiddle::Importer#sizeof): fix typo,
- SIZEOF_LONG_LON. [Fix GH-714]
-
-Mon Sep 15 08:13:40 2014 Matthew Draper <matthew@trebex.net>
-
- * sprintf.c (rb_str_format): rational 'f' format works for more
- values. [fix GH-717]
-
-Sun Sep 14 16:57:27 2014 Eric Wong <e@80x24.org>
-
- * template/vm.inc.tmpl: "insns.c" => "insns.def"
- * tool/instruction.rb: typo fix
-
-Sun Sep 14 12:29:52 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/test_tracer.rb: fixed testcase for rubygems update.
-
-Sun Sep 14 12:29:02 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rubygems: Update to RubyGems 2.4.1 master(713ab65)
- Complete history at:
- https://github.com/rubygems/rubygems/blob/master/History.txt#L3-L216
-
- * test/rubygems: ditto.
-
-Sun Sep 14 11:03:24 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych.rb: update version
- * ext/psych/psych.gemspec: ditto
-
-Sun Sep 14 08:43:37 2014 Eric Wong <e@80x24.org>
-
- * ccan/container_of/container_of.h (container_of_or_null): added
- [ccan 7ec5b8e06b2fd5fa98b1fcde1158c286d2d429d8] (David Gibson)
-
-Sun Sep 14 08:41:44 2014 Eric Wong <e@80x24.org>
-
- * ccan/list/list.h (list_del_init, list_node_init): new functions
- for multiple list_del() calls
- [ccan ec8654d94d3c5c47aa5f82698f7e8048c79765b1] (Rusty Russell)
-
-Sat Sep 13 22:19:26 2014 Bernard Potocki <bernard.potocki@imanel.org>
-
- * hash.c (rb_hash_aset): fix misleading example which may suggest
- that Hash.store will return self instead of value - Hash#store
- is returning value and update itself, as well as Hash#[]=.
- [Fix GH-715]
-
-Sat Sep 13 15:16:31 2014 Eric Wong <e@80x24.org>
-
- * class.c: use ALLOC(rb_subclass_entry_t)
-
-Sat Sep 13 14:14:00 2014 Eric Wong <e@80x24.org>
-
- * process.c (free_exec_arg): remove
- (memsize_exec_arg): ptr is never NULL
- (exec_arg_data_type): use RUBY_TYPED_DEFAULT_FREE
-
- * variable.c (autoload_i_free): remove
- (autoload_data_i_type): use RUBY_TYPED_DEFAULT_FREE
- (autoload_memsize): ptr is never NULL
-
- * vm_backtrace.c (location_free): remove
- (location_mark): ptr is never NULL
- (location_data_type): use RUBY_TYPED_DEFAULT_FREE
- (backtrace_mark): ditto
- (backtrace_free): ditto
-
-Sat Sep 13 13:43:07 2014 Eric Wong <e@80x24.org>
-
- * doc/NEWS-2.0.0: fix typo for default RUBY_FIBER_MACHINE_STACK_SIZE
- [ci skip]
-
-Sat Sep 13 11:16:58 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_event.c(ev_advise, ole_event_free,
- fev_s_allocate, fev_unadvise): avoid segmentation fault when COM
- server freed before calling Unadvise from WIN32OLE_EVENT object.
- * ext/win32ole/win32ole.c: ditto.
-
-Sat Sep 13 09:47:44 2014 Eric Wong <e@80x24.org>
-
- * man/ruby.1: use https for *.ruby-lang.org links
-
-Sat Sep 13 06:31:23 2014 Eric Wong <e@80x24.org>
-
- * vm.c (thread_alloc): remove needless volatile
-
-Sat Sep 13 06:13:55 2014 Eric Wong <e@80x24.org>
-
- * proc.c (proc_free): remove, use RUBY_TYPED_DEFAULT_FREE
- (proc_mark, proc_memsize): remove needless branching
-
- * vm.c (env_free): remove, use RUBY_TYPED_DEFAULT_FREE
- (env_mark, env_memsize): remove needless branching
-
-Sat Sep 13 05:52:15 2014 Eric Wong <e@80x24.org>
-
- * proc.c (rb_proc_alloc): inline and move to vm.c
- (rb_proc_wrap): new wrapper function used by rb_proc_alloc
- (proc_dup): simplify alloc + copy + wrap operation
- [ruby-core:64994]
-
- * vm.c (rb_proc_alloc): new inline function
- (rb_vm_make_proc): call rb_proc_alloc
-
- * vm_core.h: remove rb_proc_alloc, add rb_proc_wrap
-
- * benchmark/bm_vm2_newlambda.rb: short test to show difference
-
-Sat Sep 13 04:40:04 2014 Eric Wong <e@80x24.org>
-
- * process.c (Init_process): subclass Thread as Process::Waiter
- (rb_detach_process): use Process::Waiter instead of singleton class
- Thanks to headius and nobu. [Bug #10231]
-
- * test/ruby/test_process.rb (test_process_detach): new test
-
- * inits.c (rb_call_inits): call Init_Thread before Init_process to
- ensure Process::Waiter may be a subclass of Thread
-
-Fri Sep 12 18:14:28 2014 Eric Wong <e@80x24.org>
-
- * vm.c (env_alloc): inline to avoid extra zeroing
- tiny speedup [ruby-core:64980]
-
-Fri Sep 12 17:13:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_method.c (rb_method_entry_make, remove_method): ditto.
-
-Fri Sep 12 14:39:55 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * gems/bundled_gems: Upgraded to test-unit-3.0.1 and minitest-5.4.1
-
-Fri Sep 12 06:55:40 2014 Eric Wong <e@80x24.org>
-
- * string.c (Init_frozen_strings): use st_init_table_with_size
-
-Fri Sep 12 06:15:37 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (sym_find): remove Symbol.find because we have Symbol GC now.
- https://bugs.ruby-lang.org/projects/ruby/wiki/DevelopersMeeting20140904Japan
- If you still want this, request again on Redmine. [Feature #7854]
- https://bugs.ruby-lang.org/issues/7854
-
- * ext/-test-/symbol/init.c (sym_find): moved from string.c for tests.
-
-Fri Sep 12 04:24:03 2014 Eric Wong <e@80x24.org>
-
- * insns.def (once): define and use fake RUNNING_THREAD_ONCE_DONE
- pointer to indicate is->once.running_thread is done.
-
- * vm_core.h (iseq_inline_storage_entry): remove done field,
- allowing the union to be reduced from 24=>16 bytes on 64-bit
- [Feature #10187]
-
-Thu Sep 11 20:10:00 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm.c (rb_thread_mark): use rb_gc_mark_values() to mark VM stack.
-
-Thu Sep 11 19:50:57 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm.c (rb_vm_register_special_exception): make new function to
- make and register special exceptions.
-
- * vm.c (rb_vm_mark): do not need to mark special exceptions
- because they are registered by rb_gc_register_mark_object().
-
- * eval.c (Init_eval): use rb_vm_register_special_exception().
-
- * gc.c (Init_GC): ditto.
-
- * proc.c (Init_Proc): ditto.
-
- * thread.c (Init_Thread): ditto.
-
-Thu Sep 11 19:32:30 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_gc_mark_values): added.
- This function is similar to rb_gc_mark_locations(), but not
- conservative.
-
- * internal.h: ditto.
-
- * vm.c (env_mark): use rb_gc_mark_values() because env values should
- be Ruby VALUEs.
-
-Thu Sep 11 19:16:39 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_mark_ptr): rename to gc_mark_set.
-
- * gc.c (gc_mark): add gc_mark_ptr() to skip is_markable_object()
- check. gc_mark_maybe() can use gc_mark_ptr() directly because
- passed pointer is checked by is_pointer_to_heap().
-
-Thu Sep 11 18:40:16 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * .gitignore: ignored temporary files and coverage results.
-
-Thu Sep 11 18:15:30 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * .gitignore: ignored only simplecov.
- * coverage/README: Added coverage docs.
-
-Thu Sep 11 17:25:31 2014 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h, gc.c: add new internal events
- RUBY_INTERNAL_EVENT_GC_ENTER and
- RUBY_INTERNAL_EVENT_GC_EXIT.
-
- When invoking GC process, GC_ENTER event is called.
- When exiting from GC process, GC_EXIT event is called.
-
- Incremental GC (incremental marking and lazy sweep) can call
- these events many times.
-
- For example (minor marking):
- (1) GC_ENTER
- - (2) GC_START (minor GC)
- (minor marking)
- - (3) GC_END_MARK
- (start lazy sweep)
- (4) GC_EXIT
- (ruby process)
- (5) GC_ENTER
- (lazy sweep)
- (6) GC_EXIT
- (ruby process)
- (... repeat (5), (6))
- (7) GC_ENTER
- (finish lazy sweep)
- - (8) GC_END_SWEEP
- (9) GC_EXIT
-
- 2nd example (incremental major marking):
- (1) GC_ENTER
- - (2) GC_START (minor GC)
- (start incremental marking)
- (3) GC_EXIT
- (ruby process)
- (4) GC_ENTER
- (incremental marking)
- (5) GC_EXIT
- (ruby process)
- (... repeat (4), (5))
- (6) GC_ENTER
- (finish incremental marking)
- - (7) GC_END_MARK
- (start lazy sweep)
- (8) GC_EXIT
- (ruby process)
- (9) GC_ENTER
- (lazy sweep)
- (10) GC_EXIT
- (ruby process)
- (... repeat (9), (10))
- (11) GC_ENTER
- (finish lazy marking)
- - (12) GC_STOP_SWEEP
- (13) GC_EXIT
-
- These internal events enable to measure GC pause time completely.
-
-Thu Sep 11 17:04:54 2014 Eric Wong <e@80x24.org>
-
- * lib/benchmark.rb: remove CLOCK_MONOTONIC_RAW support
- Thanks to Vit Ondruch for reporting the issue on ARM.
- [Bug #10202]
-
-Thu Sep 11 14:31:57 2014 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h: freeze nil/true/false.
- [Feature #8923]
-
- * gc.c (should_be_finalizable): check frozen after checkin FL_ABLE.
-
- * object.c (rb_obj_taint): check
- OBJ_TAINTABLE(obj).
-
- * object.c (rb_obj_freeze): remove immediate_frozen_tbl
- because all of immediate values are frozen. YAY!
-
- * object.c (rb_obj_frozen_p): ditto.
-
- * test/ruby/test_eval.rb: skip instance_variable_set for
- frozen objects.
-
- * test/ruby/test_weakmap.rb: check ArgumentError instead of
- RuntimeError.
-
-Thu Sep 11 10:03:16 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rdoc.rb, lib/rdoc, test/rdoc: Update to RDoc 4.2.0.alpha(21b241a)
-
-Wed Sep 10 17:52:25 2014 Koichi Sasada <ko1@atdot.net>
-
- * compile.c (rb_vm_addr2insn): rename to rb_vm_insn_addr2insn
- to clear what address.
-
-Wed Sep 10 16:22:26 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_gc.rb: fix condition.
-
-Wed Sep 10 15:29:46 2014 Eric Wong <e@80x24.org>
-
- * vm_core.h (rb_call_info_t): ci->flag becomes 32-bit unsigned int
- ci->index becomes a 32-bit signed int (from signed long).
- Reorder for better packing on 64-bit, giving an 8 byte reduction
- from 104 to 96 bytes for each ci.
- [Feature #10187]
-
- * compile.c (new_callinfo, setup_args, iseq_compile_each,
- iseq_build_from_ary_body): adjust for type changes
-
- * vm_insnhelper.c (vm_getivar): ditto
-
-Wed Sep 10 15:07:35 2014 Eric Wong <e@80x24.org>
-
- * compile.c (rb_iseq_translate_threaded_code):
- modify in-place w/o copy
- (rb_vm_addr2insn): new function for debug
- (rb_iseq_original_iseq): ditto
- (iseq_set_sequence): assign iseq_encoded directly
- [Feature #10185]
-
- * vm_core (rb_iseq_t): move original ->iseq to bottom
-
- * iseq.c (iseq_free, iseq_free): adjust for new layout
- (rb_iseq_disasm): use original iseq for dump
- (iseq_data_to_ary): ditto
- (rb_iseq_line_trace_each): ditto
- (rb_iseq_build_for_ruby2cext): use iseq_encoded directly
-
- * vm_dump.c (rb_vmdebug_debug_print_pre): use original iseq
-
-Wed Sep 10 15:00:11 2014 Eric Wong <e@80x24.org>
-
- * time.c (time_mark): remove NULL check
- (time_memsize): ditto
- (time_free): remove, use RUBY_TYPED_DEFAULT_FREE instead
- [Feature #10219]
-
-Wed Sep 10 14:14:57 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * common.mk (encs enc trans libencs libenc libtrans): force to run
- enk.mk because common.mk does not know the dependency, but enk.mk
- knows. [ruby-dev:48530] [Bug #10220]
-
-Wed Sep 10 11:59:10 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat): update rdoc.
-
-Wed Sep 10 11:52:08 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat_internal): rename:
- * malloc_increase -> malloc_increase_bytes
- * malloc_limit -> malloc_increase_bytes_limit
- * oldmalloc_increase -> oldmalloc_increase_bytes
- * oldmalloc_limit -> oldmalloc_increase_bytes_limit
- ref: [Feature #9924]
-
-Wed Sep 10 11:45:40 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat_internal): rename `heap_used' to `heap_allocated_pages'.
- ref: [Feature #9924]
-
- * test/ruby/test_gc.rb: add constraints test for gc stat information.
-
-Wed Sep 10 11:31:16 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat_internal): rename:
- * remembered_shady_object -> remembered_wb_unprotected_objects
- * remembered_shady_object_limit -> remembered_wb_unprotected_objects_limit
- * old_object -> old_objects
- * old_object_limit -> old_objects_limit
- ref: [Feature #9924]
-
-Wed Sep 10 11:12:25 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat_internal): support:
- * total_allocated_pages
- * total_freed_pages
- ref: [Feature #9924]
-
-Wed Sep 10 10:48:04 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_gc.rb: catch up last fix.
-
-Wed Sep 10 10:36:08 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (objspace_total_slot): rename objspace_available_slots.
-
- * gc.c (objspace_live_slot, objspace_free_slot): rename
- ..._slot() to ..._slots().
-
- * gc.c (objspace_free_slot): should subtract heap_pages_final_slots.
-
- * gc.c (gc_stat_internal):
- * add `heap_available_slots' field
- * rename heap_live_slot to heap_live_slots
- * rename heap_free_slot to heap_free_slots
- ref: [Feature #9924]
-
-Wed Sep 10 07:22:53 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: refactoring for RGENGC_PROFILE > 0.
-
- * rename rb_objspace_t::profile::..._count
- to rb_objspace_t::profile::total_..._count
- * rename promote_infant_types to promote_types
-
- * gc.c (gc_remember_unprotected): count remembered shady objects here.
-
-Wed Sep 10 03:12:12 2014 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * gc.c (init_mark_stack): MEMZERO() receive type as 2nd argument instead
- of size.
- Coverity Scan found this bug.
-
-Tue Sep 9 21:55:39 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/sample/excel2.rb: remove some commented-out code.
- rotate graph more slowly to see graph clearly.
-
-Tue Sep 9 19:52:33 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename rb_objspace_t::marked_objects to marked_slots.
-
- * gc.c (gc_marks_start): should be clear first.
-
- * gc.c (gc_marks_start): remembered shady objects are also marked.
-
- * gc.c (gc_stat_internal): add heap_marked_slots.
-
-Tue Sep 9 18:58:48 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename
- * total_allocated_object_num -> total_allocated_objects
- * total_allocated_object_num_at_gc_start -> total_allocated_objects_at_gc_start
- * total_freed_object_num -> total_freed_objects
-
- * gc.c (gc_stat_internal):
- * rename total_allocated_object -> total_allocated_objects
- * rename total_freed_object -> total_freed_objects
-
-Tue Sep 9 18:51:36 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat_internal): fix symbol names
- * heap_final_slot -> heap_final_slots
- * heap_swept_slot -> heap_swept_slots
-
-Tue Sep 9 18:18:07 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_objspace_t::heap_pages): rename field names:
- * used -> allocated_pages
- * increment -> allocatable_pages
- * length -> sorted_length
- And remove unused `limit' field.
-
- * gc.c: rename macros:
- * heap_pages_used -> heap_allocated_pages
- * heap_pages_length -> heap_pages_sorted_length
- * heap_pages_increment -> heap_allocatable_pages
-
- * gc.c (gc_stat_internal): fix symbol names
- * heap_used -> heap_allocated_pages
- * heap_eden_page_length -> heap_eden_pages
- * heap_tomb_page_length -> heap_tomb_pages
- * heap_increment -> heap_allocatable_pages
- * heap_length -> heap_sorted_length
-
- ref: [Feature #9924]
- https://docs.google.com/spreadsheets/d/11Ua4uBr6o0k-nORrZLEIIUkHJ9JRzRR0NyZfrhEEnc8/edit?usp=sharing
- Yellow color fields in this table are changed.
-
- * test/ruby/test_gc.rb: catch up this change.
-
-Tue Sep 9 14:56:03 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: continue layout changing.
-
- newobj_of() also touch:
- (4) increment total_allocated_object_num
- (5) check hook_events
-
- And gather fields related to marking phase.
-
-Tue Sep 9 14:21:50 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: fix layout of rb_objspace_t to improve cache locality.
-
- newobj_of() accesses:
- (1) rb_objspace_t::flags
- (2) rb_objspace_t::eden_heap::freelist
- (3) and rb_objspace_t::eden_heap::free_pages if freelist is NULL.
-
-Tue Sep 9 14:09:36 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: move rb_objspace_t::flags::gc_stressful after during_gc
- to make accessing both parameters easy.
-
- * gc.c (heap_get_freeobj): add LIKELY() hint.
-
- * gc.c (heap_get_freeobj_from_next_freepage): ditto.
-
- * gc.c (newobj_of): check both parameters at once for exceptional
- case.
-
-Tue Sep 9 13:51:32 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: add rb_objspace_t::flags::gc_stressful and
- ruby_gc_stressful macro.
- Rename objspace->gc_stress to objspace->gc_stress_mode.
-
- If objspace->gc_stress_mode is true (!nil and !false) then
- ruby_gc_stressful becomes TRUE.
-
- ruby_gc_stressful will speedup newobj_of() slightly.
-
- * gc.c: initialize ruby_gc_stress(full|_mode) by gc_params.gc_stress
- even if ENABLE_VM_OBJSPACE is false.
-
-Tue Sep 9 13:05:50 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: remove ruby_disable_gc_stress and add ruby_disable_gc
- to speed-up newobj_of().
-
- * gc.c (ready_to_gc): check ruby_disable_gc.
-
- * signal.c: use ruby_disable_gc.
-
-Tue Sep 9 12:11:41 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename gc_stat entries and check stat transition.
-
-Tue Sep 9 12:06:03 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_sweep_rest): remove wrong modification of during_gc flag.
-
-Tue Sep 9 11:39:41 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: pack boolean values into rb_objspace_t::flags with bit fields
- to improve cache locality.
-
-Tue Sep 9 11:11:05 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_object.rb: extend timeout.
-
-Tue Sep 9 09:02:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (MakeMakefile#pkg_config): append --cflags to also
- $CXXFLAGS, as they are often used by C++ compiler.
- [ruby-core:54532] [Bug #8315]
-
-Tue Sep 9 07:03:22 2014 Eric Wong <e@80x24.org>
-
- * compile.c: remove needless SYM2ID <-> ID2SYM conversions
- [misc #10207]
-
-Tue Sep 9 05:48:42 2014 Eric Wong <e@80x24.org>
-
- * symbol.c (rb_intern_cstr_without_pindown): check dsymbol on return
- This is not a complete fix for bug 10206, but seems to reduce
- that crash and also looks correct.
-
-Tue Sep 9 04:36:24 2014 Eric Wong <e@80x24.org>
-
- * vm_core.h (rb_env_t): use flexible array
- This reduces allocations and speeds up the lambda calculus
- fizzbuzz (bm_app_lc_fizzbuzz.rb) benchmark [ruby-core:64858]
- * proc.c (get_local_variable_ptr): deconst to adjust for flex array
- * vm.c (env_mark, env_free, env_memsize): remove check for env->env
- * vm.c (env_alloc): single allocation for flex array
- * vm.c (vm_make_env_each): adjust env_alloc call
-
-Mon Sep 8 16:08:22 2014 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/bm_app_lc_fizzbuzz.rb: should skip output on benchmark.
-
-Mon Sep 8 16:04:02 2014 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/bm_app_lc_fizzbuzz.rb: `answer.to_a' does not return
- a string, but an array.
-
-Mon Sep 8 13:18:37 2014 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/bm_app_lc_fizzbuzz.rb: added.
-
- This program is described closely in "Understanding Computation"
- chapter 6 by Tom Stuart. <http://computationbook.com/>
-
- Japanese translation will be published soon.
- <http://www.oreilly.co.jp/books/9784873116976/>
-
-Mon Sep 8 12:01:39 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: add incremental GC algorithm. [Feature #10137]
-
- Please refer this ticket for details.
-
- This change also introduces the following changes.
-
- * Remove RGENGC_AGE2_PROMOTION and introduce object age (0 to 3).
- Age can be count with FL_PROMOTE0 and FL_PROMOTE1 flags in
- RBasic::flags (2 bit). Age == 3 objects become old objects.
- * WB_PROTECTED flag in RBasic to WB_UNPROTECTED bitmap.
- * LONG_LIVED bitmap to represent living objects while minor GCs
- It specifies (1) Old objects and (2) remembered shady objects.
- * Introduce rb_objspace_t::marked_objects which counts marked
- objects in current marking phase. marking count is needed to
- introduce incremental marking.
- * rename mark related function and sweep related function to
- gc_(marks|sweep)_(start|finish|step|rest|continue).
- * rename rgengc_report() to gc_report().
- * Add obj_info() function to get cstr of object details.
- * Add MEASURE_LINE() macro to measure execution time of specific line.
- * and many small fixes.
-
- * include/ruby/ruby.h: add flag USE_RINCGC.
- Now USE_RINCGC can be set only with USE_RGENGC.
-
- * include/ruby/ruby.h: introduce FL_PROMOTED0 and add FL_PROMOTED1
- to count object age.
-
- * include/ruby/ruby.h: rewrite write barriers for incremental marking.
-
- * debug.c: catch up flag name changes.
-
- * internal.h: add rb_gc_writebarrier_remember() instead of
- rb_gc_writebarrier_remember_promoted().
-
- * array.c (ary_memcpy0): use rb_gc_writebarrier_remember().
-
- * array.c (rb_ary_modify): ditto.
-
- * hash.c (rb_hash_keys): ditto.
-
- * hash.c (rb_hash_values): ditto.
-
- * object.c (init_copy): use rb_copy_wb_protected_attribute() because
- FL_WB_PROTECTED is moved from RBasic::flags.
-
- * test/objspace/test_objspace.rb: catch up ObjectSpace.dump() changes.
-
-Sun Sep 7 12:47:06 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c: PTHREAD_CANCEL_DISABLE is not defined on Android.
-
-Sat Sep 6 20:59:06 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (has_privilege): The gid zero is not a privilege.
-
-Sat Sep 6 20:19:16 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (struct child_handler_disabler_state): cancelstate field
- added.
- (disable_child_handler_before_fork): Record cancelstate.
- (disable_child_handler_fork_parent): Restore cancelstate.
-
-Sat Sep 6 19:27:10 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (struct child_handler_disabler_state): Defined.
-
-Sat Sep 6 18:31:32 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rake.rb, lib/rake/*, test/rake/*: Update latest rake master(e47d023)
-
-Sat Sep 6 16:38:08 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_variant.c (ole_val2variant_err,
- ole_val2variantdata, Init_win32ole_variant): support VT_ERROR
- variant with error code. add WIN32OLE_VARIANT::NoParam.
- * test/win32ole/test_win32ole_variant.rb(test_c_noparam,
- test_vt_error_noparam): ditto.
- * ext/win32ole/win32ole.c: ditto.
-
-Sat Sep 6 11:08:52 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (arg_ambiguous_gen): fix warning message, "even" does
- not mean the number of spaces here. state the place to put a
- space and the operator. [ruby-core:64790] [Bug #10204]
-
-Sat Sep 6 08:44:40 2014 Zachary Scott <e@zzak.io>
-
- * lib/rdoc/generator/template/darkfish/js/jquery.js: Backport
- rdoc/rdoc@74f60fcb04fee1778fe2694d1a0ea6513f8e67b7
-
-Sat Sep 6 08:10:44 2014 Eric Wong <e@80x24.org>
-
- * test/ruby/test_io.rb (test_readpartial_locktmp): use IO#nonblock=
- Old fcntl invocation may drop necessary flags on some platforms.
-
-Sat Sep 6 07:46:51 2014 Eric Wong <e@80x24.org>
-
- * test/ruby/test_io.rb (test_readpartial_locktmp): avoid EBADF
- [ruby-core:64773] [ruby-core:64775]
-
-Sat Sep 6 01:34:31 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_f_exec): Call before_exec_async_signal_safe and
- after_exec_async_signal_safe around rb_exec_async_signal_safe.
- (rb_exec_async_signal_safe): Don't call
- before_exec_async_signal_safe and after_exec_async_signal_safe.
- (rb_exec_without_timer_thread): Call before_exec and
- after_exec.
- (disable_child_handler_fork_child): Make SIGPIPE handler SIG_DFL.
-
-Sat Sep 6 00:49:41 2014 Tanaka Akira <akr@fsij.org>
-
- * signal.c (ruby_signal): Don't set SA_SIGINFO for SIG_IGN and
- SIG_DFL.
-
-Fri Sep 5 21:45:33 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (disable_child_handler_before_fork): New function.
- (disable_child_handler_fork_parent): Ditto.
- (disable_child_handler_fork_child): Ditto.
- (retry_fork_async_signal_safe): Call above functions to disable
- signal handlers in child process.
-
-Fri Sep 5 21:02:54 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (handle_fork_error): Make try_gc_p argument volatile to
- suppress "clobbered" warning.
-
-Fri Sep 5 20:48:06 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (handle_fork_error): Don't need state_p argument.
-
-Fri Sep 5 20:35:52 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (has_privilege): Fix a return value.
-
-Fri Sep 5 19:00:40 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/shellwords.rb: proofreading documentation.
- [Bug #10155][ruby-core:64471]
-
-Fri Sep 5 18:34:33 2014 Laurent Arnoud <laurent@spkdev.net>
-
- * test/csv/test_row.rb: Added some missing tests in CSV.
- [fix GH-710]
- * test/csv/test_table.rb: ditto.
-
-Fri Sep 5 12:57:52 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (has_privilege): Refine uid/gid check.
-
-Fri Sep 5 12:40:55 2014 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Check sys/id.h, getuidx and getgidx for AIX.
-
- * process.c (getresuid): Defined for AIX.
- (getresgid): Ditto
- AIX don't have getresuid/getresgid but getuidx/getgidx.
-
-Fri Sep 5 12:28:21 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (has_privilege): Fix assignments.
-
-Fri Sep 5 11:10:13 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rdoc/generator/pot/po.rb: fixed broken tests for trailing whitespace.
- * test/rdoc/test_rdoc_generator_pot.rb: ditto.
- * test/rdoc/test_rdoc_generator_pot_po.rb: ditto.
-
-Fri Sep 5 10:41:07 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/rdoc/test_rdoc_rdoc.rb (TestRDocRDoc#test_parse_file_encoding):
- typofix.
-
-Fri Sep 5 10:39:14 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rdoc.rb, lib/rdoc, test/rdoc: Update to RDoc 4.2.0.alpha(313287)
-
-Fri Sep 5 06:04:22 2014 Eric Wong <e@80x24.org>
-
- * vm.c: remove unused USE_THREAD_RECYCLE [misc #10198]
-
-Fri Sep 5 00:29:08 2014 Tanaka Akira <akr@fsij.org>
-
- * configure.in (dirfd): Check function.
-
- * dir.c (dir_fileno): New method.
- [ruby-dev:48265] [Feature #9880]
-
-Thu Sep 4 23:39:52 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (has_privilege): New function.
- (retry_fork_async_signal_safe): Don't use vfork() for privileged
- process.
-
- * configure.in (getresuid): Check function.
- (getresgid): Ditto.
-
-Thu Sep 4 20:22:14 2014 Laurent Arnoud <laurent@spkdev.net>
-
- * test/pathname/test_pathname.rb: added testcase for Pathname#mountpoint?.
- [fix GH-709]
-
-Thu Sep 4 20:09:21 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * symbian/*: removed Symbian support.
- [Feature #10199][ruby-core:64725]
- * dln.c: ditto.
- * include/ruby/defines.h: ditto.
- * thread_pthread.c: ditto.
- * vm.c: ditto.
-
-Thu Sep 4 17:44:40 2014 Koichi Sasada <ko1@atdot.net>
-
- * dir.c (glob_helper): use #ifdef instead of #if.
- gcc's -Wundef option shows warning for undefined macro.
-
- * numeric.c (flo_is_finite_p): ditto.
-
- * vm_dump.c (rb_vmdebug_thread_dump_state): ditto.
-
- * vm_core.h: define VM_DEBUG_VERIFY_METHOD_CACHE to 0.
-
-Thu Sep 4 03:57:46 2014 Eric Wong <e@80x24.org>
-
- * man/ruby.1: spelling fix ("bellow" => "below") [ci-skip]
-
-Thu Sep 4 03:52:16 2014 Eric Wong <e@80x24.org>
-
- * man/ruby.1: add trailing slash to URLs [ci-skip]
-
-Wed Sep 3 19:10:28 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (before_fork_ruby): Renamed from before_fork.
- (after_fork_ruby): Renamed from after_fork.
-
-Wed Sep 3 18:56:05 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (forked_child): Removed.
-
-Wed Sep 3 16:56:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (rb_obj_copy_ivar): allocate no memory for empty
- instance variables. [ruby-core:64700] [Bug #10191]
-
-Wed Sep 3 12:05:17 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (retry_fork_async_signal_safe): Use vfork() if available.
- vfork() is still faster than fork() especially when the parent
- process uses big memory.
-
- ruby -rbenchmark -e 'a = "a" * 1_000_000_000; puts Benchmark.measure { system("true") }'
- fork: 0.000000 0.010000 0.010000 ( 0.014968)
- vfork: 0.000000 0.000000 0.000000 ( 0.000912)
- on Debian sid.
-
-Wed Sep 3 11:33:08 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/openssl/test_pkey_rsa.rb (OpenSSL#test_sign_verify_memory_leak):
- added timeout into testcase for low performance environment.
- [Bug #9984][ruby-core:63367]
-
-Wed Sep 3 07:50:15 2014 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Use AC_FUNC_FORK.
-
- * io.c: Use HAVE_WORKING_FORK instead of HAVE_FORK.
-
- * process.c: Ditto.
-
-Wed Sep 3 00:12:44 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (retry_fork_async_signal_safe): Don't return on in child
- process.
-
-Tue Sep 2 23:47:35 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (retry_fork_async_signal_safe): Specialized version of
- retry_fork respect to rb_fork_async_signal_safe.
- (retry_fork_ruby): Specialized version of retry_fork respect to
- rb_fork_ruby.
- (rb_fork_ruby): Removed.
-
-Tue Sep 2 23:26:26 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (send_child_error): Simplified.
- (recv_child_error): Ditto.
-
-Tue Sep 2 22:56:25 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (rb_fork_async_signal_safe): Inline rb_fork_internal.
- (rb_fork_ruby): Ditto.
- (rb_fork_internal): Removed.
- (chfunc_protect): Removed.
-
-Tue Sep 2 22:43:52 2014 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_io.rb (test_new_with_block): Set autoclose to avoid
- EBADF.
-
-Tue Sep 2 22:01:51 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * Makefile.in (update-coverage): Remove a never executed line.
-
-Tue Sep 2 19:48:26 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (handle_fork_error): Extracted from retry_fork.
-
-Tue Sep 2 17:02:53 2014 Vit Ondruch <v.ondruch@tiscali.cz>
-
- * tool/rbinstall.rb: fixed error of local installation.
- [Bug #10192][ruby-core:64702]
-
-Tue Sep 2 16:58:03 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/runner.rb: reporting test coverage for test-all with COVERAGE env.
- [Feature #10189][ruby-core:64681][fix GH-708]
- * Makefile.in: added task for coverage report.
- * common.mk: added definition of forked simplecov url.
- * .gitignore: ignored coverage directory.
-
-Mon Sep 1 20:11:02 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (rbtime2vtdate): try to convert millisecond
- of Time object to millisecond of VT_DATE VARIANT.
- * test/win32ole/test_win32ole_variant.rb
- (test_conversion_time2date_with_msec): ditto.
-
-Sun Aug 31 16:58:49 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/benchmark.rb: Fix a syntax error.
-
-Sun Aug 31 08:46:44 2014 Eric Wong <e@80x24.org>
-
- * ext/zlib/zlib.c (gzfile_reset): preserve ZSTREAM_FLAG_GZFILE
- [Bug #10101]
-
- * test/zlib/test_zlib.rb (test_rewind): test each_byte
-
-Sat Aug 30 19:22:47 2014 Eric Wong <e@80x24.org>
-
- * symbol.c (rb_sym2id): do not return garbage object
-
-Sat Aug 30 06:39:48 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb: fix NameError dumping and
- loading. Fixes GH #85. Thanks @brentdax for the patch!
- * test/psych/test_exception.rb: test for fix
-
-Sat Aug 30 06:23:40 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/scalar_scanner.rb: fix loading strings that
- look like integers but have a newline. Fixes GH #189
- * test/psych/test_string.rb: test for fix
-
-Sat Aug 30 06:10:39 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/to_ruby.rb: merge keys with a hash
- should merge the hash in to the parent.
- * test/psych/test_merge_keys.rb: test for change. Fixes GH #202
-
-Sat Aug 30 06:00:26 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/to_ruby.rb: quoted "<<" strings
- should not be treated as merge keys.
- * ext/psych/lib/psych/visitors/yaml_tree.rb: hashes with keys
- containing "<<" should roundtrip.
- * test/psych/test_merge_keys.rb: test for change. Fixes GH #203
-
-Fri Aug 29 17:56:44 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/net/imap/test_imap_response_parser.rb: removed needless code.
-
-Fri Aug 29 17:36:58 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/rinda/test_rinda.rb: removed useless assignment variables.
- * test/rss/rss-assertions.rb: ditto.
- * test/rss/test_maker_itunes.rb: ditto.
-
-Fri Aug 29 16:18:26 2014 Eric Wong <e@80x24.org>
-
- * string.c: revert part of r47311, add rb_vm_fstring_table(),
- remove vm_core.h dependency. [ruby-core:64627]
-
-Fri Aug 29 15:17:13 2014 Eric Wong <e@80x24.org>
-
- * string.c: remove static frozen_strings
- * string.c (Init_frozen_strings): new function
- * string.c (rb_fstring): remove check for frozen strings,
- use per-VM table
- * string.c (rb_str_free): use per-VM table
- * string.c (Init_String): use per-VM table
- * vm_core.h (rb_vm_t): add frozen_strings table
- * internal.h (Init_frozen_strings): new function prototype
- * eval.c (ruby_setup): call Init_frozen_strings
- [Feature #10182]
-
-Wed Aug 27 23:10:24 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * lib/tempfile.rb: remove "require 'thread'". its features are no
- longer used.
-
-Wed Aug 27 21:19:40 2014 gogo tanaka <mail@tanakakazuki.com>
-
- * lib/drb/acl.rb: Removed meaningless #to_s methods in interpolation.
- [Feature #10174][ruby-core:64584]
- * lib/erb.rb: ditto.
- * lib/observer.rb: ditto.
- * lib/rake/invocation_chain.rb: ditto.
- * lib/rubygems/command_manager.rb: ditto.
- * lib/rubygems/config_file.rb: ditto.
- * lib/uri/common.rb: ditto.
-
-Wed Aug 27 21:08:20 2014 gogo tanaka <mail@tanakakazuki.com>
-
- * lib/drb/drb.rb: use attr_reader instead of Module#attr.
- [Feature #10172][ruby-core:64582]
- * lib/irb/ruby-token.rb: ditto.
- * lib/net/telnet.rb: ditto.
- * lib/rdoc/ruby_token.rb: ditto.
- * lib/thwait.rb: ditto.
-
-Wed Aug 27 19:52:33 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (vtdate2rbtime): try to convert millisecond
- of VT_DATE VARIANT to nsec of Time object.
- * test/win32ole/test_win32ole_variant.rb
- (test_conversion_dbl2date_with_msec): ditto.
-
-Wed Aug 27 09:57:29 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/ruby/test_complex.rb: removed unreachable code.
- * test/ruby/test_rational.rb: ditto.
-
-Wed Aug 27 07:59:17 2014 Eric Wong <e@80x24.org>
-
- * compile.c (iseq_set_sequence): check for multiplication overflow
-
-Tue Aug 26 22:07:42 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/ruby/test_complex.rb: cherry-picked working assertions from r47251.
- * test/ruby/test_rational.rb: cherry-picked working assertions from r47263.
-
-Tue Aug 26 21:07:56 2014 gogo tanaka <mail@tanakakazuki.com>
-
- * lib/mathn.rb (Fixnum#**, Bignum#**, Float#**, Rational#**):
- remove as these are now built-in. [ruby-core:63973] [Bug #10086]
-
-Tue Aug 26 20:46:55 2014 Tanaka Akira <akr@fsij.org>
-
- * time.c (rb_time_unmagnify_to_float): Avoid double rounding.
- Reported by Tsuyoshi Sawada.
- https://bugs.ruby-lang.org/issues/10135#note-1
-
-Tue Aug 26 17:12:47 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (io_close): ignore only "closed stream" IOError and
- NoMethodError, do not swallow other exceptions at the end of
- block. [ruby-core:64463] [Bug #10153]
-
-Tue Aug 26 13:46:33 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * template/fake.rb.in: fix failed to make install when @srcdir@ is
- absolute path.
-
-Tue Aug 26 13:43:50 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/ruby/test_range.rb: added workaround for VERBOSE message.
-
-Tue Aug 26 12:38:02 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/test_mathn.rb: added workaround for VERBOSE messages.
-
-Tue Aug 26 11:44:04 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/shell/process-controller.rb: removed commented-out code.
-
-Tue Aug 26 11:39:01 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/thwait.rb (ThreadsWait): removed needless constant.
-
-Tue Aug 26 09:27:10 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/mathn.rb: mathn library is deprecated on ruby 2.2.
- [Feature #10169][ruby-core:64553]
-
-Tue Aug 26 09:25:03 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/mathn.rb: removed commented-out code.
-
-Mon Aug 25 20:15:50 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c(fole_s_connect, fole_initialize): raise a
- security error with the tainted string object.
- * ext/win32ole/win32ole_event.c(ev_advise): ditto.
- * test/win32ole/test_win32ole.rb(test_s_new_exc_svr_tainted,
- test_s_new_exc_host_tainted): ditto.
- * test/win32ole/test_win32ole_event.rb(test_s_new_exc_tainted): ditto.
-
-Mon Aug 25 12:56:54 2014 Ivan Korunkov <ivankorunkov@ya.ru>
-
- * lib/logger.rb (format_datetime): use "%6N" to show microsecond.
- [Fix GH-704]
-
-Mon Aug 25 11:02:07 2014 Eric Wong <e@80x24.org>
-
- * vm_core.h (rb_iseq_location_t): change first_lineno type to VALUE
- * iseq.c (rb_iseq_build_for_ruby2cext): update based on argument
-
-Sun Aug 24 16:14:46 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/e2mmap.rb: remove needless instance variables.
- * lib/irb.rb: ditto.
- * lib/irb/**/*.rb: ditto.
- * lib/shell.rb: ditto.
-
-Sun Aug 24 12:44:26 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/ruby/test_complex.rb: removed needless conditions.
- * test/ruby/test_rational.rb: ditto.
-
-Sun Aug 24 11:47:39 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/ruby/test_rational.rb: fixed indent.
-
-Sun Aug 24 11:44:11 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/ruby/test_rational.rb: remove commented-out code.
-
-Sun Aug 24 11:09:29 2014 Eric Wong <e@80x24.org>
-
- * lib/benchmark.rb (measure): reduce allocations as in r47260
-
-Sun Aug 24 10:35:54 2014 Pete Higgins <pete@peterhiggins.org>
-
- * lib/benchmark.rb (module Benchmark): define BENCHMARK_CLOCK
- (realtime): use Process.clock_gettime(BENCHMARK_CLOCK)
- Reduces allocations to improve performance [Feature #10165]
-
- * test/benchmark/test_benchmark.rb (test_realtime_output): new test
-
-Fri Aug 22 20:23:54 2014 Koichi Sasada <ko1@atdot.net>
-
- * string.c (rb_fstring): fix condition (easy to cause infinite loop!).
-
-Fri Aug 22 20:07:43 2014 Koichi Sasada <ko1@atdot.net>
-
- * string.c (rb_fstring, fstr_update_callback): simply delete garbage
- key first.
-
- Garbage keys can be swept by lazy sweeping invoked by creating new
- fstring. So that simply do:
- (1) delete garbage key and return `fstr_update_callback' immediately
- (2) try again `fstr_update_callback()' to create a new fstr.
-
- This bug can be cause memory corruption, reported by
- http://u64.rubyci.org/~chkbuild/ruby-trunk/log/20140821T220302Z.fail.html.gz
-
-Fri Aug 22 19:30:39 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/ruby/test_complex.rb: removed commented-out code.
-
-Fri Aug 22 19:25:28 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/ruby/test_complex.rb: fixed broken tests. Math is not
- compatible CMath now.
-
-Fri Aug 22 15:36:09 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (Doxyfile): revert r43888, not to require preinstalled
- ruby. [ruby-core:64488] [Bug #10161]
-
-Fri Aug 22 12:32:15 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/shell.rb: removed commented-out code.
- * lib/shell/builtin-command.rb: ditto.
- * lib/shell/command-processor.rb: ditto.
-
-Fri Aug 22 12:21:46 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/complex.rb: removed deprecated library.
- * lib/rational.rb: ditto.
-
-Fri Aug 22 11:38:49 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/prettyprint.rb: removed PrettyPrint#first?
- because it is obsoleted method since Ruby 1.8.2
-
-Thu Aug 21 17:10:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (constat_attr): manage reverse video internally
- since Windows console window does not manage it. based on the
- patch by white leaf in [ruby-dev:48483]. [Bug #10158]
-
-Thu Aug 21 14:45:41 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/e2mmap.rb: removed commented-out code.
-
-Thu Aug 21 13:23:34 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rinda/ring.rb: split executable code into sample directory.
- * sample/rinda-ring.rb: ditto.
-
-Thu Aug 21 13:21:45 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/drb/acl.rb: split executable code into sample directory.
- * sample/drb/acl.rb: ditto.
-
-Thu Aug 21 12:55:35 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * .gitignore: ignored temporary file for Changelog.
- http://mkosaki.blog46.fc2.com/blog-entry-1284.html
-
-Thu Aug 21 12:40:22 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/net/imap.rb: split executable code into sample directory.
- * sample/net-imap.rb: ditto.
-
-Thu Aug 21 12:23:56 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/net/imap.rb: removed commented-out code.
-
-Wed Aug 20 17:27:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (RUBY_TRY_CFLAGS, RUBY_TRY_LDFLAGS),
- (RUBY_CHECK_BUILTIN_SETJMP, RUBY_SETJMP_TYPE),
- (RUBY_STACK_GROW_DIRECTION): quote defun names, for some
- versions of autoconf possibly. [ruby-core:64473] [Bug #10156]
-
-Tue Aug 19 22:28:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * sprintf.c (rb_str_format): fix condition to round.
- [ruby-core:64454] [Bug #10151]
-
-Tue Aug 19 22:22:45 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enc/trans/euckr-tbl.rb (EUCKR_TO_UCS_TBL): add missing euro and
- registered signs. [ruby-core:64452] [Bug #10149]
-
-Tue Aug 19 13:59:43 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compar.c (rb_cmperr): preserve encodings of arguments in the
- message.
-
-Tue Aug 19 10:13:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/thread/thread.c (get_array): check instance variables are
- initialized properly. [ruby-core:63826][Bug #10062]
-
-Mon Aug 18 17:06:27 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * sprintf.c (rb_str_format): support rational 'f' format.
- [ruby-core:64382] [Bug #10136]
-
-Mon Aug 18 08:03:46 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * spec/default.mspec: use 2.2 definition.
-
-Sun Aug 17 19:41:40 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * gc.c (obj_memsize_of): don't calculate memsize of T_NODE
- when called from check_gen_consistency. It fixes segmentation
- fault on RGENGC_CHECK_MODE >= 1 introduced by r47188.
-
-Sun Aug 17 17:08:12 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (ole_invoke): use RHASH_SIZE instead of
- calling Hash#length method.
-
-Sat Aug 16 19:32:06 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_event.c (evs_length): use RARRAY_LEN instead
- of calling Array#length method.
-
-Sat Aug 16 10:20:17 2014 Eric Wong <e@80x24.org>
-
- * time.c (time_timespec): fix tv_nsec overflow
- [Bug #10144]
-
-Fri Aug 15 20:34:17 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: separate WIN32OLE_EVENT src from
- win32ole.c.
- * ext/win32ole/win32ole.h: ditto.
- * ext/win32ole/win32ole_event.c: ditto.
- * ext/win32ole/win32ole_event.h: ditto.
- * ext/win32ole/depend: ditto.
-
-Fri Aug 15 19:38:00 2014 Koichi Sasada <ko1@atdot.net>
-
- * iseq.c (rb_iseq_clone): Should not insert write barrier from
- non-RVALUE data (to non-RVALUE data, of course).
-
- Ruby 2.1 also has a same problem.
-
-Fri Aug 15 19:34:33 2014 Koichi Sasada <ko1@atdot.net>
-
- * string.c (setup_fake_str): fake strings should not set class by
- RBASIC_SET_CLASS() because it insert write barriers to fake
- (non-RVALUE) structure.
-
- It can cause unexpected behaviour.
-
- Ruby 2.1 also have a same problem (setup_fake_str() in parse.y).
-
- * symbol.c (setup_fake_str): ditto.
-
-Fri Aug 15 19:27:25 2014 Koichi Sasada <ko1@atdot.net>
-
- * array.c (rb_ary_tmp_new_fill): added.
- This function creates internal use only array (which is completely
- hided by ObjectSpace.each_object) with filling nil.
-
- Otherwise, it can be includes strange VALUEs.
-
- * internal.h: added.
-
- * node.h: use rb_ary_tmp_new_fill() for MEMO.
-
-Fri Aug 15 10:13:37 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/gserver.rb: removed unmaintained code.
- [ruby-core:40313][Feature #5480]
- * lib/xmlrpc/httpserver.rb: ditto.
-
-Fri Aug 15 09:22:12 2014 Eric Wong <e@80x24.org>
-
- * vm_core.h (rb_thread_struct): reorder to pack
- * cont.c (rb_context_struct, rb_fiber_struct): ditto
- On x86-64, these changes reduces:
- rb_thread_struct to 1000 bytes (from 1016)
- rb_context_struct to 1288 bytes (from 1312)
- rb_fiber_struct to 2272 bytes (from 2304)
-
-Fri Aug 15 09:06:31 2014 Eric Wong <e@80x24.org>
-
- * thread_pthread.h: define RB_NATIVETHREAD_LOCK_INIT and
- RB_NATIVETHREAD_COND_INIT macros
-
- * thread_pthread.c (native_mutex_lock, native_mutex_unlock,
- native_mutex_trylock, native_mutex_initialize,
- native_mutex_destroy, native_cond_wait):
- use rb_nativethread_lock_t instead of pthread_mutex_t
- [Feature #10134]
-
- * thread_pthread.c (native_mutex_debug): make argument type-agnostic
- to avoid later cast.
-
- * thread_pthread.c (register_cached_thread_and_wait):
- replace PTHREAD_COND_INITIALIZER with RB_NATIVETHREAD_COND_INIT,
- use native_mutex_{lock,unlock}
-
- * thread_pthread.c (use_cached_thread):
- use native_mutex_{lock,unlock}
-
- * thread_pthread.c (native_sleep):
- use rb_nativethread_lock_t to match th->interrupt_lock,
- use native_mutex_{lock,unlock}
-
- * thread_pthread.c (timer_thread_lock): use rb_nativethread_lock_t type
-
-Fri Aug 15 08:10:29 2014 Eric Wong <e@80x24.org>
-
- * cont.c (cont_mark): fix typo in unused path [ci skip]
-
-Fri Aug 15 06:00:56 2014 Eric Wong <e@80x24.org>
-
- * vm.c (rb_thread_mark): update comment about marking `me'
- [ruby-core:64340] [ruby-core:64341]
-
-Fri Aug 15 05:53:59 2014 Eric Wong <e@80x24.org>
-
- * README.EXT: preliminary documentation for RB_GC_GUARD
- [Bug #10100] [ruby-core:60741]
-
-Thu Aug 14 00:26:19 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: separate WIN32OLE_RECORD src from
- win32ole.c
- * ext/win32ole/win32ole.h: ditto.
- * ext/win32ole/win32ole_record.c: ditto.
- * ext/win32ole/win32ole_record.h: ditto.
- * ext/win32ole/depend: ditto.
-
-Wed Aug 13 21:41:04 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: separate WIN32OLE_VARIANT src from
- win32ole.c.
- * ext/win32ole/win32ole.h: ditto.
- * ext/win32ole/win32ole_variant.c: ditto.
- * ext/win32ole/win32ole_variant.c: ditto.
- * ext/win32ole/depend: ditto.
-
-Wed Aug 13 20:09:37 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: remove unused variable.
-
-Wed Aug 13 19:31:27 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (ole_search_handler_method, rescue_callback,
- folerecord_inspect): use PRIsVALUE in rb_sprintf.
-
- * ext/win32ole/win32ole_param.c (foleparam_inspect): ditto.
-
- * ext/win32ole/win32ole_variable.c (folevariable_inspect): use
- PRIsVALUE in rb_sprintf, use rb_inspect.
-
-Wed Aug 13 11:54:41 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/irb/completion.rb: reverted r47163.
- because another case can't be show completion target.
-
-Wed Aug 13 11:17:00 2014 Shimpei Makimoto <github@makimoto.org>
-
- * lib/irb.rb: Prevent irb from crashing when exception with
- nil backtrace is raised.
- [fix GH-434][ruby-core:58078][Bug #9063]
- * test/irb/test_raise_no_backtrace_exception.rb: ditto.
-
-Wed Aug 13 11:08:55 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/irb/completion.rb: fixed broken completion list with
- String including spaces. Contributed from @dunric. [fix GH-465]
-
-Wed Aug 13 00:07:01 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: separate WIN32OLE_PARAM src from win32ole.c
- * ext/win32ole/win32ole.h: ditto.
- * ext/win32ole/win32ole_param.c: ditto.
- * ext/win32ole/win32ole_param.h: ditto.
- * ext/win32ole/depend: ditto.
-
-Tue Aug 12 23:17:47 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: refactoring. move some methods
- into win32ole_type.c / win32ole_method.c
- * ext/win32ole/win32ole.h: ditto.
- * ext/win32ole/win32ole_method.c: ditto.
- * ext/win32ole/win32ole_method.h: ditto.
- * ext/win32ole/win32ole_type.h: ditto.
- * ext/win32ole/win32ole_type.h: ditto.
-
-Tue Aug 12 22:59:48 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: refactoring. move
- ole_typelib_from_itypeinfo into win32ole_typelib.c.
- * ext/win32ole/win32ole.h: ditto.
- * ext/win32ole/win32ole_typelib.h: ditto.
- * ext/win32ole/win32ole_typelib.h: ditto.
-
-Tue Aug 12 21:49:40 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (ole_create_dcom): use the converted
- result if the argument can be converted to a string, to get rid
- of invalid access. Thanks to nobu. [ruby-dev:48467] [Bug #10127]
-
-Tue Aug 12 14:22:58 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * configure.in: ignored working directory same as prefix value.
- [ruby-core:54999] [Bug #8409]
-
-Tue Aug 12 13:34:25 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/fileutils.rb: enable to remove with non-owner directory.
- [ruby-dev:45976] [Bug #6756]
- * test/fileutils/test_fileutils.rb: add testcase for #6756.
-
-Tue Aug 12 12:57:28 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * vm_exec.c: improve performance in ppc64 arch.
- [ruby-core:63437] [Feature #9997]
-
-Tue Aug 12 12:14:52 2014 Akira Matsuda <ronnie@dio.jp>
-
- * lib/fileutils.rb: fix typo.
- [ruby-dev:47831] [Bug #9180]
-
-Tue Aug 12 10:10:42 2014 Eric Wong <e@80x24.org>
-
- * vm_method.c (release_method_definition): use rb_free_method_entry
-
-Tue Aug 12 06:16:09 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: separate WIN32OLE_METHOD src from
- win32ole.c.
- * ext/win32ole/win32ole.h: ditto.
- * ext/win32ole/win32ole_method.c: ditto.
- * ext/win32ole/win32ole_method.h: ditto.
- * ext/win32ole/depend: ditto.
-
-Mon Aug 11 22:19:15 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_variable.c (folevariable_inspect): refactoring.
-
-Mon Aug 11 20:47:27 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: separate WIN32OLE_VARIABLE src from
- win32ole.c
- * ext/win32ole/win32ole.h: ditto.
- * ext/win32ole/win32ole_variable.c: ditto.
- * ext/win32ole/win32ole_variable.h: ditto.
- * ext/win32ole/depend: ditto.
-
-Mon Aug 11 16:17:21 2014 Tony Miller <mcfiredrill@gmail.com>
-
- * dir.c (rb_dir_exists_p): [DOC] Document that Dir.exists? is
- deprecated. [ruby-core:64135] [Bug #10102]
-
-Mon Aug 11 11:26:33 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/tempfile.rb: start rdoc parsing inside singleton class
- definition to include the document there.
- [ruby-core:64157] [Bug #10105]
-
-Sun Aug 10 12:22:43 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_type.c: refactoring.
-
-Sun Aug 10 10:34:00 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/cgi/session/pstore.rb: separated sample code.
- * lib/open3.rb: ditto.
-
-Sun Aug 10 10:03:24 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/irb/ext/multi-irb.rb: removed commented-out code.
-
-Sat Aug 9 11:02:07 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/irb.rb: removed commented-out code.
- * lib/irb/**/*.rb: ditto.
-
-Sat Aug 9 10:35:30 2014 Laurent Arnoud <laurent@spkdev.net>
-
- * lib/cmath.rb: fixed indent. [fix GH-696]
- * lib/drb/ssl.rb: ditto.
- * lib/irb/**/*.rb: ditto.
-
-Sat Aug 9 10:28:03 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/minitest/test_minitest_unit.rb: removed obsoleted condition
- for Ruby 1.8.
- * test/ruby/test_time_tz.rb: ditto.
-
-Sat Aug 9 10:18:00 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/cgi/test_cgi_core.rb: removed obsoleted condition for Ruby 1.8.
- * test/cgi/test_cgi_header.rb: ditto.
- * test/cgi/test_cgi_multipart.rb: ditto.
- * test/cgi/test_cgi_tag_helper.rb: ditto.
-
-Sat Aug 9 00:34:37 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: separate WIN32OLE_TYPE src from win32ole.c.
- * ext/win32ole/win32ole.h: ditto.
- * ext/win32ole/win32ole_type.c: ditto.
- * ext/win32ole/win32ole_type.h: ditto.
- * ext/win32ole/depend: ditto.
-
-Fri Aug 8 01:53:37 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * lib/securerandom.rb: use OpenSSL::BN for performance improvement.
-
- * benchmark/bm_securerandom.rb: benchmark script.
-
-Fri Aug 8 17:19:57 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/open-uri.rb: remove needless condition for old ruby version.
- * test/open-uri/test_open-uri.rb: ditto.
-
-Fri Aug 8 16:40:59 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/irb/init.rb: removed unreachable code.
-
-Fri Aug 8 16:34:22 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/drb/drb.rb: removed unreachable code.
-
-Fri Aug 8 14:33:49 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/webrick/httpproxy.rb: remove needless condition
- for old ruby version.
-
-Fri Aug 8 01:07:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_yylex): fix invalid char in eval, should raise
- an syntax error too, as well as directly coded.
- [ruby-core:64243] [Bug #10117]
-
-Thu Aug 7 23:25:29 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * lib/open3.rb: avoid unnecessary write if stdin_data is empty.
-
-Thu Aug 7 21:42:49 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole_typelib.c (foletypelib_version): return
- version string.
-
- * test/win32ole/test_win32ole_typelib.rb (test_version): ditto.
-
-Thu Aug 7 15:13:13 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/cgi.rb: remove needless condition for old ruby version.
-
-Thu Aug 7 06:04:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_yyerror): preserve source code encoding in
- syntax error messages. [ruby-core:64228] [Bug #10114]
-
-Wed Aug 6 20:56:02 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: separate src of WIN32OLE_TYPELIB from
- win32ole.c
-
- * ext/win32ole/win32ole.h: ditto.
- * ext/win32ole/win32ole_typelib.c: ditto.
- * ext/win32ole/win32ole_typelib.h: ditto.
- * ext/win32ole/depend: ditto.
-
-Wed Aug 6 20:44:07 2014 Akinori MUSHA <knu@iDaemons.org>
-
- * enum.c (enum_one): [DOC] Move enum.one? documentation before the
- relevant method. Submitted by @vipulnsward. [Fixes GH-687]
- https://github.com/ruby/ruby/pull/687
-
-Wed Aug 6 20:25:47 2014 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/set.rb (Set#replace): Check if an object given is enumerable
- before clearing self. Reported by yui-knk. [GH-675]
- https://github.com/ruby/ruby/pull/675
-
-Wed Aug 6 20:07:26 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (olerecord_ivar_set): remove rb_str_subseq.
-
-Wed Aug 6 19:09:27 2014 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/set.rb (Set): Implement Set#clone by splitting
- initialize_copy into initialize_dup and initialize_clone.
- Submitted by yui-knk. [Fixes GH-661]
- https://github.com/ruby/ruby/pull/661
-
-Wed Aug 6 18:42:58 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: separate src of WIN32OLERuntimeError
- from win32ole.c.
-
- * ext/win32ole/win32ole.h: ditto
- * ext/win32ole/depend: ditto.
- * ext/win32ole/win32ole_error.c: ditto.
- * ext/win32ole/win32ole_error.h: ditto.
-
-Wed Aug 6 04:33:58 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/net/http.rb (Net::HTTP.proxy_uri): use initializer instead
- of parser to handle IPv6 address. [Bug #9129]
-
-Wed Aug 6 04:16:05 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/net/http/requests.rb (Net::HTTP::Options::RESPONSE_HAS_BODY):
- OPTIONS requests may have response bodies. [Feature #8429]
- https://www.rfc-editor.org/rfc/rfc7231#section-4.3.7
-
-Wed Aug 6 03:18:04 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/net/http/generic_request.rb (Net::HTTP::GenericRequest#exec):
- handle req['host'] in update_uri.
-
- * lib/net/http/generic_request.rb
- (Net::HTTP::GenericRequest#update_uri):
- use req['host'] if it is explicitly set. Even if URI is given,
- it is already used for the initial value of req['host'].
- Therefore overwritten value should be respected. [Bug #10054]
-
-Wed Aug 6 03:17:34 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/net/http/generic_request.rb
- (Net::HTTP::GenericRequest#update_uri):
- handle scheme, host, and port to reflect connection to @uri.
-
- * lib/net/http.rb (Net::HTTP#begin_transport): move trivial handling
- to Net::HTTP::GenericRequest#update_uri.
-
-
-Wed Aug 6 02:16:43 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/net/http/generic_request.rb
- (Net::HTTP::GenericRequest#initialize):
- optimize object allocation.
-
-Wed Aug 6 01:16:47 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/generic.rb (URI::Generic#path_query): remove a private method.
-
-Wed Aug 6 01:15:47 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/generic.rb (URI::Generic#normalize!): use String#empty?
-
- * lib/uri/generic.rb (URI::Generic#path_query): optimized.
-
- * lib/uri/generic.rb (URI::Generic#to_s): optimized.
-
-Wed Aug 6 00:15:10 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/http.rb (URI::HTTP#request_uri): optimized.
- decrease object allocation, and ensure always create at least one new
- object for return value.
-
-Wed Aug 6 03:41:21 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/to_ruby.rb: backwards compatibility for
- hashes emitted by Syck. Github #198
- * test/psych/test_hash.rb: test for change.
-
-Tue Aug 5 19:27:59 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (ole_invoke): skip VariantClear when
- argument is VT_RECORD variant.
-
-Tue Aug 5 15:52:51 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * gems/bundled_gems: Upgrade to test-unit-3.0.0 and minitest-5.4.0.
-
-Mon Aug 4 21:50:09 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * test/win32ole/test_win32ole_record.rb: add for WIN32OLE_RECORD
- test(need .NET Framework 3.5 to run test).
-
-Mon Aug 4 19:49:34 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (ole_invoke): call rb_hash_foreach instead
- of rb_block_call.
-
- * ext/win32ole/win32ole.c: add comment for rdoc of WIN32OLE_VARIANT
- class.
-
-Mon Aug 4 09:12:47 2014 Eric Wong <e@80x24.org>
-
- * variable.c: cleanup to use rb_const_lookup
- [Feature #10107]
-
- * vm_insnhelper.c: ditto
-
-Sun Aug 3 10:55:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/encoding.h (rb_check_symbol_cstr): ditto.
-
-Sun Aug 3 10:43:08 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_call_method): unusable super class should cause
- method missing when BasicObject is refined but not been using.
- [ruby-core:64166] [Bug #10106]
-
-Sat Aug 2 23:47:45 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: separate WIN32OLE::VARIANT src file
- from win32ole.c
- * ext/win32ole/win32ole.h: ditto.
- * ext/win32ole/win32ole_variant_m.c: ditto.
- * ext/win32ole/win32ole_variant_m.h: ditto.
- * ext/win32ole/depend: ditto.
- * ext/.document: ditto.
-
-Sat Aug 2 14:34:58 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: add comments for rdoc.
-
-Sat Aug 2 10:26:57 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (rb_obj_itself): new method Object#itself. based on the
- patch by Rafael Franca in [ruby-core:64156].
- [EXPERIMENTAL] this method may be renamed due to compatibilities.
- [ruby-core:44704] [Feature #6373]
-
-Fri Aug 1 22:30:40 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (folerecord_initialize): accept
- only 2 arguments. The 2nd argument should be WIN32OLE object or
- WIN32OLE_RECORD object.
-
-Fri Aug 1 20:17:33 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (ole_variant2val): call
- folerecord_s_allocate instead of WIN32OLE_RECORD.new.
-
-Fri Aug 1 18:39:57 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/date/test_date.rb: remove commented-out code.
- * test/date/test_date_arith.rb: ditto.
- * test/date/test_date_attr.rb: ditto.
- * test/date/test_date_parse.rb: ditto.
-
-Fri Aug 1 16:35:32 2014 Evan Miller <evan@squareup.com>
-
- * numeric.c (flodivmod): all results are NaN if divisor is NaN.
- [fix GH-692]
-
-Thu Aug 01 07:28:12 2014 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c: [DOC] Add description of
- `BigDecimal.new` exceptions. Patched by @joker1007 and
- @prathamesh-sonpatki [Fixes GH-690]
- https://github.com/ruby/ruby/pull/690
-
-Thu Jul 31 22:20:12 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: add WIN32OLE_RECORD#inspect.
-
-Thu Jul 31 20:35:32 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: add
- WIN32OLE_RECORD#ole_instance_variable_set and
- WIN32OLE_RECORD#ole_instance_variable_get
-
-Wed Jul 30 23:28:10 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * sprintf.c (rb_str_format): like r47006, get rid of
- function calls in RSTRING_PTR().
-
-Wed Jul 30 22:10:29 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * process.c (rlimit_resource_type, rlimit_resource_value):
- get rid of inadvertent dynamic symbol pin-down.
-
- * re.c (match_backref_number): ditto.
-
- * signal.c (esignal_init, rb_f_kill, trap_signm): ditto.
-
- * transcode.c (econv_opts): ditto.
-
- * vm_trace.c (symbol2event_flag): ditto.
-
-Wed Jul 30 21:29:39 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (ole_invoke): pass WIN32OLE_RECORD variant
- by reference when invoke OLE methods at first.
-
- * ext/win32ole/win32ole.c (olerecord_set_ivar): release
- IRecordInfo interface before setting another IRecordInfo interface.
-
-Wed Jul 30 13:17:35 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: remove unused macros.
-
-Tue Jul 29 22:21:37 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (hash2olerec): ignore WIN32OLE_RECORD
- instance variable if the variable is nil.
-
-Tue Jul 29 19:43:27 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (folerecord_method_missing): refactoring.
- divide functionality of folerecord_method_missing into
- olerecord_ivar_set and olerecord_ivar_get.
-
-Mon Jul 28 20:20:08 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win23ole.c (folerecord_method_missing): support
- setter of member of WIN32OLE_RECORD object.
-
-Mon Jul 28 06:37:19 2014 Zachary Scott <e@zzak.io>
-
- * vm_eval.c: [DOC] Fix rdoc formatting of patch from [Bug #9551]
-
-Mon Jul 28 06:34:43 2014 Zachary Scott <e@zzak.io>
-
- * vm_eval.c: [DOC] [Bug #9551] Improve clarity of Kernel::catch
- documentation, patch by Jesse Sielaff.
-
-Mon Jul 28 06:24:54 2014 Zachary Scott <e@zzak.io>
-
- * lib/uri/common.rb: [DOC] [Bug #9563] Recommend using URI.escape
- before parsing a uri to avoid invalid characters. Reported by
- Evgeniy Serykh.
-
-Mon Jul 28 05:55:56 2014 Zachary Scott <e@zzak.io>
-
- * time.c: [DOC] Clarify %Y in strftime, which can accept any digits
- and will output at least 4 digits as the year. Reported by Yury
- Trofimenko [Bug #10049]
-
- * lib/time.rb: ditto
-
-Mon Jul 28 05:32:06 2014 Zachary Scott <e@zzak.io>
-
- * lib/uri/common.rb: [DOC] [Bug #10075] Clarify how URI.join arguments
- are handled by RFC3986, originally reported by John Feminella.
-
-Mon Jul 28 05:21:41 2014 Zachary Scott <e@zzak.io>
-
- * file.c: [DOC] Clarify how File.file? handles symbolic links. Also
- cleaned up the rdoc style for this method, more to follow.
- Originally reported by Michael Renner [Bug #10067]
-
-Mon Jul 28 05:12:22 2014 Zachary Scott <e@zzak.io>
-
- * time.c: [DOC] Remove dead link and old bug report, which hasn't been
- reproduced in a few years. Reported by Federico Builes [Bug #10071]
-
-Mon Jul 28 04:39:58 2014 Zachary Scott <e@zzak.io>
-
- * ext/zlib/zlib.c: [DOC] Remove default value of Zlib constants, as
- they may change in the implementation without notice. Patched by
- @robin850 [Fixes GH-682] https://github.com/ruby/ruby/pull/682
-
-Mon Jul 28 04:35:35 2014 Zachary Scott <e@zzak.io>
-
- * ext/openssl/ossl_hmac.c: Fix NO_HMAC warning [Fixes GH-665]
- Patched by @vipulnsward https://github.com/ruby/ruby/pull/665
-
-Sun Jul 27 19:49:36 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/cgi/core.rb: remove unused variables.
- * lib/erb.rb: ditto.
- * lib/mkmf.rb: ditto.
- * lib/net/http/response.rb: ditto.
- * lib/optparse/version.rb: ditto.
- * lib/prime.rb: ditto.
- * lib/racc/parser.rb: ditto.
- * lib/rexml/document.rb: ditto.
- * lib/rexml/dtd/dtd.rb: ditto.
- * lib/rexml/element.rb: ditto.
- * lib/rexml/functions.rb: ditto.
- * lib/rexml/parsers/xpathparser.rb: ditto.
-
-Sun Jul 27 05:11:21 2014 Zachary Scott <e@zzak.io>
-
- * lib/irb.rb: [DOC] PROMPT_I cannot be nil, patch by @hgillane
- Fixes documenting-ruby/ruby#37
- https://github.com/documenting-ruby/ruby/pull/37
-
-Sun Jul 27 02:41:50 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/shell/command-processor.rb: remove unused variable.
- * lib/shell/system-command.rb: ditto.
- * lib/tmpdir.rb: ditto.
- * lib/uri/generic.rb: ditto.
-
-Sun Jul 27 02:08:31 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/weakref.rb: split executable code into sample directory.
- * sample/weakref.rb: ditto.
-
-Sun Jul 27 02:06:55 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/delegate.rb: split executable code into sample directory.
- * sample/delegate.rb: ditto.
-
-Sun Jul 27 01:46:34 2014 Zachary Scott <e@zzak.io>
-
- * proc.c (method_super_method): [DOC] Method#super_method
-
-Sun Jul 27 01:22:39 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (method_super_method): new method Method#super_method,
- which returns a method object of the method to be called by
- `super` in the receiver method object.
- [ruby-core:62202] [Feature #9781]
-
-Sat Jul 26 17:22:14 2014 URABE Shyouhei <shyouhei@ruby-lang.org>
-
- * ext/objspace/objspace_dump.c (dump_append): avoid fflush.
-
- because dump_append_string_value() iterates over each chars,
- fflush()-ing here effectively issues system calls on every single
- bytes exist in a ruby process.
-
-Sat Jul 26 16:55:18 2014 Eric Wong <e@80x24.org>
-
- * iseq.h (struct iseq_compile_data_storage): reduce overhead
- to 16 bytes (from 32) on 64-bit
-
-Sat Jul 26 16:28:06 2014 Eric Wong <e@80x24.org>
-
- * vm_core.h (struct rb_iseq_struct): reduce to 280 bytes
- (from 288 bytes) on 64-bit
-
-Sat Jul 26 06:44:43 2014 Eric Wong <e@80x24.org>
-
- * parse.y (struct parse_params): shrink to 320 to 304 bytes on 64-bit
-
-Sat Jul 26 05:58:35 2014 Eric Wong <e@80x24.org>
-
- * include/ruby/ruby.h (ZALLOC, ZALLOC_N): implement
- (Data_Make_Struct, TypedData_Make_Struct):
- ZALLOC replaces ALLOC+memset
- [ruby-core:63951][Feature #10082]
- * compile.c (iseq_seq_sequence): ZALLOC_N replaces ALLOC_N+MEMZERO
- * cont.c (fiber_t_alloc): ZALLOC replaces ALLOC+MEMZERO
- * io.c (rb_io_reopen): ditto
- * iseq.c (prepare_iseq_build): ditto
- * parse.y (new_args_tail_gen, parser_new, ripper_s_allocate): ditto
- * re.c (match_alloc): ditto
- * variable.c (rb_const_set): ditto
- * ext/socket/raddrinfo.c (get_addrinfo): ditto
- * ext/strscan/strscan.c (strscan_s_allocate): ditto
- * gc.c (rb_objspace_alloc): calloc replaces malloc+MEMZERO
-
-Sat Jul 26 05:54:54 2014 Eric Wong <e@80x24.org>
-
- * symbol.c (dsymbol_check): remove unneeded semi-colon
-
-Fri Jul 25 14:07:27 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: change objspace::rgengc::parent_object_is_old (boolean)
- to objspace::rgengc::parent_object (VALUE).
- Use Qfalse or RVALUE pointer instead of FALSE and TRUE.
-
- * gc.c (gc_marks_body): should clear parent_object just before
- gc_mark_roots() because there are no parents objects
- for root objects.
-
-Fri Jul 25 13:45:39 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_gc_writebarrier_remember_promoted): should remember only
- OLD objects on RGENGC_AGE2_PROMOTION.
-
-Fri Jul 25 13:42:02 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_mark_stacked_objects): fix error message.
-
-Fri Jul 25 13:18:00 2014 Will Farrington <wfarrington@digitalocean.com>
-
- * ext/socket/socket.c (sock_gethostname): Use NI_MAXHOST to support
- hostnames longer than 64 characters if the system supports it.
- [fixes GH-683]
-
-Fri Jul 25 12:21:11 2014 Santiago Pastorino <santiago@wyeworks.com>
-
- * compile.c (defined_expr): make the condition if the receiver
- is explicit or implicit cleaner. [fix GH-681]
-
-Fri Jul 25 03:53:52 2014 Eric Hodel <drbrain@segment7.net>
-
- * doc/keywords.rdoc: [DOC] Describe each keyword.
-
-Thu Jul 24 22:40:24 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (Init_win32ole): add WIN32OLE_RECORD#initialize
- method.
-
- * ext/win32ole/win32ole.c (ole_val2variant): convert WIN32OLE_RECORD
- object to VT_RECORD variant.
-
-Thu Jul 24 20:10:59 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: fix major GC flags.
- * add GPR_FLAG_MAJOR_BY_FORCE, which indicates
- major GC by METHOD, CAPI and so on (see GC_BY).
- * remove GPR_FLAG_MAJOR_BY_RESCAN because not used.
- * remove GPR_FLAG_MAJOR_BY_STRESS, use FORCE instead.
-
- * test/ruby/test_gc.rb: catch up.
-
-Thu Jul 24 15:55:02 2014 Naohisa Goto <ngotogenome@gmail.com>
-
- * include/ruby/io.h (struct rb_io_buffer_t): PACKED_STRUCT should not
- be used for platform-specific optimization. PACKED_STRUCT_UNALIGNED
- should be used. [ruby-core:63988] [Bug #10088]
-
-Thu Jul 24 04:42:13 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/benchmark.rb: split executable code into sample directory.
- * sample/benchmark.rb: ditto.
-
-Thu Jul 24 04:36:49 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/tempfile.rb: split executable code into sample directory.
- * sample/tempfile.rb: ditto.
-
-Thu Jul 24 04:29:36 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/pstore.rb: split executable code into sample directory.
- * sample/pstore.rb: ditto.
-
-Wed Jul 23 23:50:11 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/defines.h, siphash.c, st.c (UNALIGNED_WORD_ACCESS):
- add PowerPC64 too, which is capable to access unaligned words.
- patched by Gustavo Frederico Temple Pedrosa in [ruby-core:63937].
- [Feature #10081]
-
- * regint.h (PLATFORM_UNALIGNED_WORD_ACCESS): ditto.
-
-Wed Jul 23 04:04:38 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/drb/extserv.rb: remove duplicate code with sample directory.
- contributed from @vipulnsward. [fix GH-679]
-
-Tue Jul 22 12:56:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_count): fix wrong single-byte optimization.
- 7bit ascii can be a trailing byte in Shift_JIS.
- [ruby-dev:48442] [Bug #10078]
-
-Tue Jul 22 01:48:38 2014 Eric Wong <e@80x24.org>
-
- * include/ruby/io.h (rb_io_buffer_t): fix packing on gcc
- r46892 caused packing to be a no-op on gcc (4.7.2-5, Debian)
- [Bug #10079][ruby-core:63912]
-
-Mon Jul 21 15:55:42 2014 fuji70 <fujifuji70@gmail.com>
-
- * lib/optparse.rb (getopts): print default values and descriptions
- in the help message. [fix GH-676]
-
-Sun Jul 20 14:26:27 2014 Eric Wong <e@80x24.org>
-
- * vm_core.h (rb_proc_t): reduce to 64 bytes from 72 on 64-bit
-
-Sun Jul 20 13:50:34 2014 Eric Wong <e@80x24.org>
-
- * transcode.c (rb_econv_t): reduce to 184 bytes from 200 on 64-bit
-
-Sun Jul 20 12:44:23 2014 Eric Wong <e@80x24.org>
-
- * include/ruby/io.h (rb_io_buffer_t): pack structure
- Reduces rb_io_t from 200 to 192 bytes, allowing rb_io_t to
- occupy one less cache line.
- [Feature #10050]
-
-Sun Jul 20 12:41:53 2014 Eric Wong <e@80x24.org>
-
- * include/ruby/io.h (rb_io_t): shrink to 200 bytes from 216 on 64-bit
- This puts us within 8 bytes of being three cache lines instead of
- four lines on x86-64. This breaks the ABI.
- [Feature #10050]
-
-Sun Jul 20 12:36:46 2014 Eric Wong <e@80x24.org>
-
- * include/ruby/oniguruma.h (struct re_pattern_buffer): shrink to 448
- bytes from 464 bytes on 64-bit. This breaks the ABI.
- [Feature #10034]
-
-Sun Jul 20 01:06:06 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * ext/openssl/ossl.c: use encryptor instead of encrypter in doc.
- contributed from @vipulnsward. [fix GH-663]
-
-Sun Jul 20 00:32:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (rb_io_initialize): [DOC] fix rdoc of append mode. it does
- not move the pointer at open. [ruby-core:63747] [Bug #10039]
-
-Sat Jul 19 12:40:50 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_compile_each): allow to access private attribute
- reader in op_assign. [ruby-core:63817] [Bug #10060]
-
-Sat Jul 19 11:56:36 2014 Grey Baker <greysteil@gmail.com>
-
- * lib/time.rb (Time#apply_offset): Guards against a `nil` return
- value from `Time.month_days` when offsetting date. Out of range
- values are then caught when `Time.utc` is called (as usual).
-
- Previously a `nil` return value from `Time.month_days` would
- have the `<` operator called on it, and raise `NoMethodError`.
- [fix GH-667]
-
- * lib/rdoc/parser/changelog.rb (RDoc#parse_entries): fix dirty hack.
-
-Sat Jul 19 06:19:01 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: refactoring.
-
-Fri Jul 18 22:34:41 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (folevariant_initialize): WIN32OLE_VARIANT
- does not support VT_RECORD. VT_RECORD should be supported in
- WIN32OLE_RECORD.
-
- * test/win32ole/test_win32ole_variant.rb (test_s_new_vt_record_exc):
- ditto.
-
-Fri Jul 18 19:54:03 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (folevariant_initialize): remove unnecessary
- code.
-
-Fri Jul 18 19:11:03 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix/eigenvalue_decomposition: Style fix
- Patch by Gogo Tanaka [#10058]
-
-Fri Jul 18 19:03:53 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Avoid using `and`.
- Patch by gogo tanaka [#10058]
-
-Fri Jul 18 17:41:54 2014 GoGo tanaka <qlli.illb@gmail.com>
-
- * test/matrix/test_matrix.rb: Add tests for Matrix class.
- [Feature #10057][ruby-core:63809]
-
-Fri Jul 18 10:14:42 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/fileutils.rb: added missing options of FileUtils.touch by @Domon.
- [fix GH-669]
-
-Thu Jul 17 19:57:27 2014 Herwin <herwin@quarantainenet.nl>
-
- * ext/thread/thread.c (rb_szqueue_push): add optional parameter,
- non_block defaulted to false. [ruby-core:63794] [Feature #10052]
-
-Wed Jul 16 23:01:43 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (ole_variant2val): support array of
- VT_RECORD variant.
-
-Wed Jul 16 20:21:49 2014 Naohisa Goto <ngotogenome@gmail.com>
-
- * vm_core.h (struct rb_iseq_struct): stack_max is changed to int
- because all calculations related to stack_max in compile.c
- (iseq_set_sequence) and vm_insnhelper.c (vm_push_frame) are
- conducted by using int. This partly reverts r23945.
- * vm_insnhelper.c (vm_push_frame): ditto. This reverts r42401.
-
-Wed Jul 16 19:55:32 2014 Naohisa Goto <ngotogenome@gmail.com>
-
- * vm_core.h (struct rb_iseq_struct): temporal workaround of [Bug 10037].
- Add padding on big-endian 64-bit architecture (e.g. sparc64).
-
-Wed Jul 16 19:32:23 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (fole_record_method_missing): call
- rb_hash_fetch instead of rb_hash_aref.
-
-Wed Jul 16 18:08:47 2014 Koichi Sasada <ko1@atdot.net>
-
- * iseq.c (rb_iseq_defined_string): use rb_gc_mark_object() instead of
- marking from vm_mark().
-
- * vm.c (rb_vm_mark): ditto.
-
-Wed Jul 16 18:03:50 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_mark_roots): call rb_vm_mark directly.
-
- * vm.c: remove mark function for RubyVM object because
- RubyVM object marked manually.
-
-Wed Jul 16 12:25:39 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * regcomp.c: Merge Onigmo 5.14.1 25a8a69fc05ae3b56a09.
- this includes Support for Unicode 7.0 [Bug #9092].
-
-Tue Jul 15 23:59:27 2014 Jared Jennings <jared.jennings.ctr@us.af.mil>
-
- * ext/digest: make built-in digest function implementations
- indicate success or failure of init and final functions.
- [ruby-core:61614] [Bug #9659]
-
- * ext/digest/digest.c: expect digest init and finish functions to
- indicate success or failure; raise exception on failure.
- [ruby-core:61614] [Bug #9659]
-
-Tue Jul 15 20:31:40 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: modify document for WIN32OLE_RECORD.
-
-Tue Jul 15 12:42:23 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * defs/default_gems: change version definition file of rake.
-
-Tue Jul 15 12:00:03 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rake.rb, lib/rake/*.rb: Upgrade to rake-10.3.2
- [fix GH-668]
- * test/rake/*.rb: ditto.
-
-Mon Jul 14 19:14:51 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: modify WIN32OLE class document and
- add comment for constants of WIN32OLE.
-
-Mon Jul 14 16:38:45 2014 Eric Wong <e@80x24.org>
-
- * vm_core.h (struct rb_iseq_struct): reduce to 288 bytes
- on x86-64 (from 296 bytes)
-
-Mon Jul 14 16:07:25 2014 Eric Wong <e@80x24.org>
-
- * iseq.h (struct iseq_catch_table_entry): shrink to 32 bytes
- on x86-64 (from 48 bytes)
-
-Mon Jul 14 16:04:41 2014 Eric Wong <e@80x24.org>
-
- * iseq.h (struct iseq_catch_table): new flexible array struct
- (iseq_catch_table_bytes): allocated size function
- * vm_core.h (struct rb_iseq_struct): update catch_table member
- This reduces the struct from 304 to 296 bytes on x86-64.
- * compile.c (iseq_set_exception_table): update for struct changes
- * iseq.c (iseq_free): ditto
- * iseq.c (iseq_memsize): ditto
- * iseq.c (rb_iseq_disasm): ditto
- * iseq.c (iseq_data_to_ary): ditto
- * iseq.c (rb_iseq_build_for_ruby2cext): ditto (untested)
- * vm.c (vm_exec): ditto
- * vm_core.h (struct rb_iseq_struct): ditto
- * vm_insnhelper.c (vm_throw): ditto
-
-Sun Jul 13 17:49:52 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * ext/openssl/ossl_cipher.c: Fix call to ciphers class method and
- spell out `encryption` by @vipulnsward [fix GH-664]
-
-Sun Jul 13 17:31:51 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * ext/gdbm/gdbm.c: fix wrong arguments in GetDBM2 macro.
- * ext/sdbm/init.c: ditto.
-
-Sun Jul 13 17:25:50 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * ext/dbm/dbm.c: fix wrong arguments in GetDBM2 macro by @v2e4lisp.
- [fix GH-655]
-
-Sun Jul 13 16:44:56 2014 Eric Wong <e@80x24.org>
-
- * vm_core.h (struct rb_call_info_struct): improve packing
- This reduces the struct from 112 to 104 bytes on x86-64.
-
-Sun Jul 13 15:53:25 2014 Eric Wong <e@80x24.org>
-
- * vm_core.h (struct rb_iseq_struct): stack_max is uint32_t
- This reduces the struct from 312 to 304 bytes on x86-64.
-
-Sun Jul 13 10:56:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (rb_cv_broken_backtrace): exit with failure
- normally, no needs to abort. [ruby-core:63678] [Bug #10008]
-
-Sat Jul 12 15:10:22 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (fole_record_method_missing): correct
- fields Hash key.
-
-Sat Jul 12 04:17:40 2014 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * lib/net/smtp.rb (Net::SMTP#data): enable buffering while
- 'data' send for optimizing Net::SMTP#send_message.
- [ruby-dev:48329] [misc #9981]
- patch by Masahiro Tomita.
-
-Sat Jul 12 01:13:45 2014 Naohisa Goto <ngotogenome@gmail.com>
-
- * test/ruby/envutil.rb (assert_no_memory_leak): On Solaris 9 or later,
- if possible, execute child ruby with environment variables
- LD_PRELOAD=libumem.so UMEM_OPTIONS="backend=mmap". With these
- variables, freed memory is immediately returned to the OS.
- [Bug #10020] [ruby-dev:48391]
-
-Fri Jul 11 20:49:10 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c: add WIN32OLE_RECORD class to support
- VT_RECORD OLE variables.
-
-Fri Jul 11 17:15:08 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/abbrev.rb: remove executable.
-
-Fri Jul 11 16:45:39 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/fileutils.rb: handle ENOENT error with symlink targeted to
- non-exists file. [ruby-dev:45933] [Bug #6716]
-
-Fri Jul 11 15:59:42 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * array.c: Clarify documentation for Array#insert.
- [ruby-core:62934] [Bug #9901]
-
-Fri Jul 11 15:39:36 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * io.c: Improve Documentation by @dapplebeforedawn.
- [fix GH-658] [ruby-core:63579] [Bug #10012]
-
-Fri Jul 11 14:19:14 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Fix sign for cross_product [#9499]
-
-Fri Jul 11 11:11:50 2014 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/prepare_so_k_nucleotide.rb: use require_relative.
-
- * benchmark/prepare_so_reverse_complement.rb: ditto.
-
-Fri Jul 11 10:09:03 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * pack.c (encodes): fix buffer overrun by tail_lf. Thanks to
- Mamoru Tasaka and Tomas Hoger. [ruby-core:63604] [Bug #10019]
-
-Thu Jul 10 23:51:36 2014 Naohisa Goto <ngotogenome@gmail.com>
-
- * hash.c (ruby_setenv): Fix TestEnv#test_aset failure on Solaris 9.
- When name contains '=', ruby_setenv raises Errno::EINVAL.
- That is the same behavior as Solaris 10.
- NULL check for malloc return value is also added.
-
-Thu Jul 10 15:02:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_callee_setup_keyword_arg): adjust VM stack
- pointer to get rid of overwriting splat arguments by arguments
- for `to_hash` conversion. [ruby-core:63593] [Bug #10016]
-
-Thu Jul 10 01:09:57 2014 Koichi Sasada <ko1@atdot.net>
-
- * symbol.c: remove rb_gc_mark_symbols().
-
- fstrings referred by static symbols and pinned dynamic symbols
- are registered by rb_gc_register_mark_object().
-
- fstrings referred by dynamic symbols (not pinned symbols)
- are referred from global_symbols.dsymbol_fstr_hash (Hash object).
-
- Note that fstrings referred from dynamic symbols must live logger
- than symbol objects themselves because rb_gc_free_dsymbol() uses
- fstrings to remove from symbol tables.
- This is why we can not mark fstrings from dynamic symbols.
-
- This technique reduces root objects for GC marking.
-
- * gc.c (gc_mark_roots): ditto.
-
- * internal.h: ditto.
-
-Thu Jul 10 00:24:18 2014 Naohisa Goto <ngotogenome@gmail.com>
-
- * common.mk (DTRACE_DEPENDENT_OBJS): fix build failure on Solaris
- introduced in r46768. Object files containing dtrace probes should
- be listed in DTRACE_DEPENDENT_OBJS.
-
-Wed Jul 9 17:07:28 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * symbol.c, symbol.h: Symbol class implementation and internals,
- split from parse.y.
-
-Wed Jul 9 14:45:39 2014 Koichi Sasada <ko1@atdot.net>
-
- * parse.y: change Symbol <-> ID relationship to avoid
- exposing IDs from collectable symbols.
- [Bug #10014]
-
- Now, rb_check_id() returns 0 if corresponding symbol is
- pinned dynamic symbol.
-
- There is remaining intern_cstr_without_pindown(), it can return
- IDs from collectable symbols. We must be careful to use it
- (only used in parse.y). I think it should be removed if
- it does not have impact for performance.
-
- * parse.y:
- add:
- * STATIC_SYM2ID()
- * STATIC_ID2SYM()
- rename:
- * rb_pin_dynamic_symbol() -> dsymbol_pindown()
-
- * internal.h:
- remove:
- * rb_check_id_without_pindown()
- * rb_sym2id_without_pindown()
- add:
- * rb_check_symbol()
- * rb_check_symbol_cstr()
-
- * load.c: use rb_check_id() or rb_check_id_cstr().
-
- * object.c: ditto.
-
- * struct.c: ditto.
-
- * thread.c: ditto.
-
- * vm_method.c: ditto.
-
- * string.c (sym_find): use only rb_check_symbol().
-
- * sprintf.c (rb_str_format): use rb_check_symbol_cstr().
-
-Wed Jul 9 12:21:55 2014 Koichi Sasada <ko1@atdot.net>
-
- * parse.y (symbols_i): delete garbage symbols for Symbol.all_symbols.
-
-Wed Jul 9 05:49:08 2014 Eric Wong <e@80x24.org>
-
- * thread_pthread.h (struct rb_global_vm_lock_struct):
- do not expose pthread type for lock
-
-Wed Jul 9 05:41:40 2014 Eric Wong <e@80x24.org>
-
- * thread_pthread.h: remove unneeded semaphore.h include
-
-Wed Jul 9 00:12:28 2014 Keiju Ishitsuka <keiju@ishitsuka.com>
-
- * lib/irb/ruby-lex.rb: fix counting indent in identify_string_dvar.
-
-Tue Jul 8 16:58:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/ruby/memory_status.rb (Memory::PSCMD): use ps command which
- outputs expected result. [ruby-dev:48370] [Bug #10010]
-
-Tue Jul 8 14:45:17 2014 Koichi Sasada <ko1@atdot.net>
-
- * parse.y (dsymbol_alloc): set global_symbols.minor_marked to 0.
-
- * parse.y (dsymbol_check): set RSYMBOL(sym)->fstr to 0
- because we should not touch fstr after that.
-
- * parse.y (rb_gc_free_dsymbol): skip deleting str and sym
- from tables if fstr == 0.
-
-Mon Jul 7 14:31:52 2014 Koichi Sasada <ko1@atdot.net>
-
- * parse.y: remove global_symbols::pinned_dsym
- (and ::pinned_dsym_minor_marked).
-
- Mark pinned dsymbols by rb_gc_register_mark_object() because
- they are immortal.
-
- * parse.y (rb_gc_free_dsymbol): rename parameter name `ptr' to `sym'.
-
-Mon Jul 7 12:45:51 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: revert miss-commit.
-
-Mon Jul 7 12:40:59 2014 Koichi Sasada <ko1@atdot.net>
-
- * parse.y: need to use updated (re-created) symbols.
-
-Mon Jul 7 11:02:55 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/mkconfig.rb: remove not to require rbconfig/obsolete.rb.
-
- * lib/rbconfig/obsolete.rb: removed.
-
-Mon Jul 7 10:52:03 2014 Koichi Sasada <ko1@atdot.net>
-
- * parse.y: do not use rb_gc_resurrect(), but create a new dynamic
- symbol for garbage dynamic symbol.
-
- * common.mk: use gc.h by parse.y.
-
-Mon Jul 7 02:18:42 2014 Koichi Sasada <ko1@atdot.net>
-
- * string.c (fstr_update_callback): do not use rb_gc_resurrect()
- any more.
-
- Make new frozen string and replace with garbage frozen string.
-
- * common.mk: use gc.h from string.c.
-
-Mon Jul 7 00:36:13 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename is_dying_object() to is_garbage_object().
-
- * gc.h: rb_objspace_garbage_object_p() as an exported function.
-
-Sun Jul 6 21:30:35 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (is_dying_object): fix missed condition.
-
- * gc.c (is_live_object): move frequent path first.
-
-Sun Jul 6 21:00:11 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename is_dead_object() to is_dying_object().
- This function is not opposite against is_live_object()
- because is_dying_object() does *not* check object type.
-
- * gc.c (is_dying_object): change condition.
-
- * gc.c (is_live_object): use T_NONE instead of 0.
-
- * gc.c (rb_objspace_dying_object_p): added.
-
-Sun Jul 6 13:37:27 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_gc_register_mark_object): change data structure.
- From single array, to array of arrays. Each array only has 1024
- entries.
-
- * vm.c (Init_vm_objects): change default capa from 1 to 128.
-
-Sat Jul 5 05:05:53 2014 Vipul A M <vipulnsward@gmail.com>
-
- * lib/irb/locale.rb (IRB::Locale#modifier): fix wrong attr_reader
- `modifieer` => `modifier` from irb locale. [fix GH-656]
-
-Fri Jul 4 20:45:26 2014 Koichi Sasada <ko1@atdot.net>
-
- * parse.y: rename symbols::sym_id to symbols::str_id.
- This table is not {Symbol => ID} table, but
- {String => ID} table.
-
- * parse.y (lookup_sym_id): also rename lookup_sym_id() to
- lookup_str_id() because key is not Symbol, but String.
-
-Fri Jul 4 18:42:04 2014 Koichi Sasada <ko1@atdot.net>
-
- * parse.y (must_be_dynamic_symbol): fix missed-condition.
-
-Fri Jul 4 18:38:11 2014 Koichi Sasada <ko1@atdot.net>
-
- * parse.y (rb_pin_dynamic_symbol): should be `static' function.
-
-Fri Jul 4 18:03:35 2014 Koichi Sasada <ko1@atdot.net>
-
- * parse.y (must_be_dynamic_symbol): refactoring.
- * add `inline'.
- * use UNLIKELY().
- * check only DYNAMIC_SYM_P(), otherwise it is a bug.
- * lookup_id_str() is not needed in second condition.
-
-Fri Jul 4 11:53:56 2014 Koichi Sasada <ko1@atdot.net>
-
- * parse.y: remove unused code
- surrounded by `#if ENABLE_SELECTOR_NAMESPACE'
-
-Fri Jul 4 10:08:24 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/rubygems/test_gem_package.rb: avoid tempfile leaks using Tempfile#close!
- * test/rubygems/test_gem_request_set.rb: ditto.
- * test/rubygems/test_gem_request_set_gem_dependency_api.rb: ditto.
-
-Fri Jul 4 04:42:05 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/net/http/response.rb (Net::Inflater#inflate_adapter):
- prevent automatic encoding conversion.
-
-Fri Jul 4 04:39:52 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/net/http/response.rb (Net::HTTPResponse.each_response_header):
- raise first exception even if inflate_body_io.finish raises error.
- when begin block raises error, finish usually raises error too.
-
-Fri Jul 4 02:56:04 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/generic.rb (URI::Generic#query=): remove validation, just
- escape. [Feature #2542]
-
- * lib/uri/generic.rb (URI::Generic#fragment=): ditto.
-
- * lib/uri/generic.rb (URI::Generic#check_query): removed.
-
- * lib/uri/generic.rb (URI::Generic#set_query): ditto.
-
- * lib/uri/generic.rb (URI::Generic#check_fragment): ditto.
-
- * lib/uri/generic.rb (URI::Generic#set_fragment): ditto.
-
-Thu Jul 3 12:40:22 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (--with-static-linked-ext): fix for extensions to
- be linked statically.
-
- * Makefile.in, common.mk: use ENCSTATIC for enc directory.
-
- * ext/extmk.rb: supply dependencies of statically linked extension
- libraries.
-
-Wed Jul 2 15:45:49 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_heap_lazy_sweep): simplify logic.
-
- * gc.c (gc_page_sweep): return TRUE if empty slots are available.
-
-Wed Jul 2 09:48:42 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * logger.rb: removed unmaintained code.
- [Feature #9860][ruby-core:62724]
- * test/logger/test_application.rb: ditto.
-
-Wed Jul 2 03:20:00 2014 Charlie Somerville <charliesome@ruby-lang.org>
-
- * node.c (dump_node): handle nd_value == (NODE *)-1 to mean this
- keyword argument is required
-
-Wed Jul 2 02:57:27 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm.c (rb_vm_env_local_variables): returns array of local
- variable name symbols in the environment by envval.
-
- * proc.c (bind_local_variables): use rb_vm_env_local_variables.
-
-Wed Jul 2 02:23:52 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (bind_receiver): new method to return the bound receiver
- of the binding object. [ruby-dev:47613] [Feature #8779]
-
-Wed Jul 2 02:14:37 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (bind_local_variables): update env from envval for each
- iterations. [ruby-dev:48351] [Bug #10001]
-
-Tue Jul 1 23:46:34 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * NEWS: [DOC] mention about Binding#local_variables, introduced at
- r44392 (see [Feature #8773]).
-
-Tue Jul 1 23:30:51 2014 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * numeric.c (num_step_scan_args): table argument of rb_get_kwargs() is
- array of IDs, not Symbols. [ruby-dev:48353] [Bug #9811]
-
-Tue Jul 1 16:18:22 2014 Akinori MUSHA <knu@iDaemons.org>
-
- * ext/digest/lib/digest/hmac.rb, test/digest/test_digest_hmac.rb:
- Digest::HMAC is finally removed as previously noticed.
- [fix GH-648]
-
-Tue Jul 1 11:13:43 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * ext/date/lib/date/format.rb: removed empty file by @vipulnsward.
- * ext/date/lib/date.rb: removed needless require.
- [fix GH-647]
-
-Mon Jun 30 16:42:52 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_stat_internal): return size_t value instead of VALUE
- and remove `out' parameter.
-
- * gc.c: add braces for `if' statements.
-
- * gc.c (gc_stat_internal): fix comment.
-
-Mon Jun 30 15:07:34 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: support `USE_RGENGC == 0'.
-
- * test/ruby/test_gc.rb: ditto.
-
-Mon Jun 30 11:36:04 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * file.c: [DOC] document File.join returns a string.
- Contributed by @dapplebeforedawn. [fix GH-646]
-
-Sat Jun 28 22:57:01 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/pathname/pathname.c (path_birthtime): Windows support.
- see [Feature #9857] [ruby-dev:48339]
-
-Sat Jun 28 22:44:16 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/pathname/pathname.c (path_birthtime): New method,
- Pathname#birthtime.
- Proposed by Kazuhiro NISHIYAMA. [ruby-dev:48232] [Feature #9857]
-
-Sat Jun 28 20:29:03 2014 Simon Baird <simon.baird@gmail.com>
-
- * ext/bigdecimal/lib/bigdecimal/math.rb (BigMath#PI): change error
- message about zero or negative precision for clarity and
- consistency with other methods. [GH-644]
-
-Sat Jun 28 15:32:57 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/webrick/utils.rb (create_listeners): Close socket objects.
-
-Sat Jun 28 13:58:48 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (setup_exception): should not overwrite SystemStackError
- backtrace if set already. [ruby-core:63377] [Feature #6216]
-
- * eval.c (setup_exception): get rid of method calls before raising
- stack overflow, not to cause stack overflow again.
-
- * defs/id.def: add IDs for backtraces.
-
-Sat Jun 28 04:08:22 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/mailto.rb: update to latest specs, RFC 6068 and HTML5.
-
- * lib/uri/mailto.rb (HEADER_PATTERN): removed.
-
- * lib/uri/mailto.rb (HEADER_REGEXP): use RFC 6068 hfields.
-
- * lib/uri/mailto.rb (EMAIL_REGEXP): use HTML5 email regexp.
-
- * lib/uri/mailto.rb (URI::MailTo.build): support multiple to addresses.
-
- * lib/uri/mailto.rb (URI::MailTo#initialize): Support multiple to
- addresses. Don't check with regexp, only split.
-
- * lib/uri/mailto.rb (URI::MailTo#check_to): verify by matching
- URI path-rootless and HTML5 email regexp with unescaped one.
-
- * lib/uri/mailto.rb (URI::MailTo#check_headers): verify only by
- HEADER_REGEXP.
-
- * lib/uri/mailto.rb (URI::MailTo#set_headers): don't check by
- HEADER_REGEXP, only split it.
-
-Sat Jun 28 00:35:10 2014 Lauri Tirkkonen <lotheac@iki.fi>
-
- * tool/mkconfig.rb: fix empty RbConfig::CONFIG["prefix"] when
- configured --with-rubyarchprefix, remove prefix from rubyarchdir
- after expansion for the case it does not start with '$(prefix)'.
- [fix GH-643]
-
-Fri Jun 27 15:20:12 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rubygems/test_case.rb: rescue Gem::LoadError in Gem::TestCase.
- because it's effected by removing minitest from stdlib.
-
-Fri Jun 27 12:29:37 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/rubygems/specification.rb: fixed broken condition caused
- by removing YAML::ENGINE.
- * lib/rubygems/package/old.rb: ditto.
-
-Fri Jun 27 05:33:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (env_shift): fix memory leak on Windows, free environment
- strings block always. [ruby-dev:48332] [Bug #9983]
-
-Fri Jun 27 03:41:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * sprintf.c (GETASTER): should not use the numbered argument to be
- formatted, raise ArgumentError instead.
- [ruby-dev:48330] [Bug #9982]
-
-Thu Jun 26 18:18:28 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/with_different_ofs.rb: move into test library directory.
- * test/csv/base.rb: fix require path for with_different_ofs.rb.
- * test/digest/test_digest_extend.rb: ditto.
-
-Thu Jun 26 18:06:50 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/profile_test_all.rb: move into test library directory.
- * test/runner.rb: fix require path for profile_test_all.rb.
-
-Thu Jun 26 17:57:57 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/webrick/httpproxy.rb: remove useless assigned variables.
- * lib/webrick/httpservlet/cgihandler.rb: ditto.
- * lib/webrick/httpservlet/erbhandler.rb: ditto.
- * lib/webrick/server.rb: ditto.
-
-Thu Jun 26 08:28:01 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (env_select): fix memory leak and crash on Windows, make
- keys array first instead of iterating on environ directly.
- [ruby-dev:48325] [Bug #9978]
-
-Thu Jun 26 02:45:04 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval_error.c (error_print): put a newline after an anonymous
- exception class name.
-
-Wed Jun 25 22:31:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (ruby_setenv): fix memory leak on Windows, free
- environment strings block after check for the size.
- [ruby-dev:48323] [Bug #9977]
-
-Wed Jun 25 15:44:12 2014 Eric Wong <e@80x24.org>
-
- * ccan/container_of/container_of.h (container_off_var):
- avoid warning with -Wcast-qual
- [ccan ba5ad771af4aa9e085498de6c3c665c52694460f (Rusty Russell)]
-
-Wed Jun 25 10:19:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (env_aset, env_has_key, env_assoc, env_has_value),
- (env_rassoc, env_key): prohibit tainted strings if $SAFE is
- non-zero. [Bug #9976]
-
-Tue Jun 24 14:46:17 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/gserver.rb: remove redundant use of to_s in interpolation.
- * lib/logger.rb: ditto.
- * lib/optparse.rb: ditto.
- * lib/rbconfig/obsolete.rb: ditto.
- * lib/resolv.rb: ditto.
- * lib/webrick/httpresponse.rb: ditto.
-
-Tue Jun 24 10:50:06 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (env_path_str_new): make PATH environment variable
- string, to be frozen.
-
-Tue Jun 24 10:40:52 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * tool/make-snapshot: download bundle gems when package making.
- [Feature #9852][ruby-core:62676]
- * gems/bundled_gems: listed bundled gems for Ruby 2.2.
-
-Tue Jun 24 10:20:35 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * tool/downloader.rb: make Downloader class to general download utility.
- It can be used without config.guess and config.sub.
- * tool/get-config_files: ditto.
- * tool/make-snapshot: ditto.
-
-Tue Jun 24 06:17:52 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * eval.c (setup_exception): "mesg == sysstack_error" and
- sysstack_error_p(mesg) are duplicated.
- r46502 seems to want to use latter.
-
-Tue Jun 24 06:15:36 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/tk/tcltklib.c: fix format specifiers for VALUE and
- Tcl_Interp*. [ruby-core:63283] [Bug #9972]
-
-Tue Jun 24 05:40:41 2014 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
-
- * nacl/nacl-config.rb: Use File.exist? instead of executable?
- for irt_core. Recent nacl_sdk has non-executable irt_core.
- Patch by Shinichiro Hamaji.
- [Fixes GH-529] https://github.com/ruby/ruby/pull/529
-
-Mon Jun 23 18:44:45 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * tool/config_files.rb: rename class ConfigFiles to Downloader.
- * tool/get-config_files: ditto.
- * tool/make-snapshot: ditto.
-
-Mon Jun 23 18:03:13 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * tool/rbinstall.rb: support to install bundle gems.
-
-Mon Jun 23 17:33:11 2014 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/net/imap.rb (Net::IMAP#fetch): [DOC] Describe how a range in
- +set+ is interpreted, and mention -1 which can be used for '*'.
-
-Mon Jun 23 16:22:50 2014 URABE Shyouhei <shyouhei@ruby-lang.org>
-
- * include/ruby/ruby.h (struct RHash): no longer. [Feature #9889]
-
- * include/ruby/ruby.h (RHASH): ditto.
-
- * include/ruby/ruby.h (RHASH_ITER_LEV): deprecated. Will be deleted later.
-
- * include/ruby/ruby.h (RHASH_IFNONE): ditto.
-
- * internal.h (struct RHash): moved here.
-
- * internal.h (RHASH): ditto.
-
- * hash.c (rb_hash_iter_lev): do not use this.
-
- * hash.c (rb_hash_ifnone): ditto.
-
-Mon Jun 23 13:30:11 2014 URABE Shyouhei <shyouhei@ruby-lang.org>
-
- * include/ruby/ruby.h (struct RComplex): no longer. [Feature #9888]
-
- * include/ruby/ruby.h (RCOMPLEX): ditto.
-
- * include/ruby/ruby.h (RCOMPLEX_SET_REAL): deprecated. Will be deleted later.
-
- * include/ruby/ruby.h (RCOMPLEX_SET_IMAG): ditto.
-
- * internal.h (struct RFloat): moved here.
-
- * internal.h (RCOMPLEX): ditto.
-
- * complex.c (rb_complex_set_real): do not use this.
-
- * complex.c (rb_complex_set_imag): ditto.
-
-Mon Jun 23 13:10:15 2014 URABE Shyouhei <shyouhei@ruby-lang.org>
-
- * include/ruby/ruby.h (struct RFloat): no longer. [Feature #9863]
-
- * include/ruby/ruby.h (RFLOAT): ditto.
-
- * internal.h (struct RFloat): moved here.
-
- * internal.h (RFLOAT): ditto.
-
-Mon Jun 23 12:01:42 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/generic.rb (check_port): allow strings for port= as
- described in rdoc.
-
- * lib/uri/rfc3986_parser.rb (regexp): implementation detail of above.
-
-Mon Jun 23 11:35:01 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (setup_exception): set backtrace in system stack error
- other than the pre-allocated sysstack_error. [Feature #6216]
-
- * proc.c (Init_Proc): freeze the pre-allocated sysstack_error.
-
- * vm_insnhelper.c (vm_stackoverflow): raise new instance for each
- times without calling any methods to keep the backtrace with no
- further stack overflow.
-
- * object.c (rb_obj_copy_ivar): extract function to copy instance
- variables only for T_OBJECT from init_copy.
-
-Mon Jun 23 11:11:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * signal.c (check_stack_overflow): drop the last tag too close to
- the fault page, to get rid of stack overflow deadlock.
- [Bug #9971]
-
-Sun Jun 22 09:11:15 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/generic.rb: remove registry.
- 'registry' is not used and RFC3986 doesn't use it.
-
-Sun Jun 22 09:10:09 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/rfc3986_parser.rb: raise exception when given a URI string
- has non ASCII in order to keep the regexp compiled for US-ASCII.
-
-Sun Jun 22 09:05:42 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/common.rb (URI::REGEXP): move to lib/uri/rfc2396_parser.rb.
-
- * lib/uri/common.rb (URI::Parser): ditto.
-
- * lib/uri/common.rb (URI.split): use RFC3986_Parser. [Feature #2542]
-
- * lib/uri/common.rb (URI.parse): ditto.
-
- * lib/uri/common.rb (URI.join): ditto.
-
- * lib/uri/common.rb (URI.extract): deprecated.
-
- * lib/uri/common.rb (URI.regexp): ditto.
-
- * lib/uri/rfc2396_parser.rb: added.
-
- * lib/uri/rfc3986_parser.rb: added.
-
-Sun Jun 22 09:04:50 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/mailto.rb (initialize): as previous commit, fix arg_check
-
-Sun Jun 22 09:01:47 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/ftp.rb (initialize): argument checking flag is arg_check,
- but arg[-1] is fragment.
-
- * lib/uri/ftp.rb (initialize): explicitly specify arguments.
-
-Sat Jun 21 12:50:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/fiddle/extconf.rb: supply 0 to fill RUBY_LIBFFI_MODVERSION
- with 3-digit. libffi 3.1 returns just 2-digit.
- [ruby-core:62920] [Bug #9897]
-
-Sat Jun 21 07:06:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * encoding.c (enc_find): [DOC] never accepted a symbol.
- [ruby-dev:48308] [Bug #9966]
-
-Fri Jun 20 17:15:43 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/lib/tracepointchecker.rb: add to check TracePoint healthiness.
-
- * test/runner.rb: use it.
-
-Fri Jun 20 07:26:44 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_settracefunc.rb: rewrite tests with
- assert_consistent_call_return().
-
- assert_consistent_call_return() is also modified to check
- consistency.
-
-Fri Jun 20 07:07:28 2014 Koichi Sasada <ko1@atdot.net>
-
- * compile.c (rb_iseq_compile_node): put start label of block after
- trace (b_call).
- [Bug #9964]
-
- * test/ruby/test_settracefunc.rb: add a test.
-
- added assert_consistent_call_return() method check call/return
- consistency.
-
-Fri Jun 20 05:26:27 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm_eval.c (rb_catch_protect): fix same problem of [Bug #9961].
-
- * vm_eval.c (rb_iterate): ditto.
-
-Thu Jun 19 21:41:30 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm.c (rb_vm_rewind_cfp): add new function to rewind specified cfp
- with invoking RUBY_EVENT_C_RETURN.
- [Bug #9961]
-
- * vm_core.h: ditto.
-
- * eval.c (rb_protect): use it.
-
- * eval.c (rb_rescue2): ditto.
-
- * vm_eval.c (rb_iterate): ditto.
-
- * test/ruby/test_settracefunc.rb: add a test.
-
- * vm_core.h (rb_vm_rewind_cfp): add the prototype declaration.
-
-Thu Jun 19 19:47:21 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm.c (invoke_block_from_c): move call/return event timing for
- bmethod. It can invoke inconsistent call event if this call raises
- argument error.
- [Bug #9959]
-
- * vm_insnhelper.c (vm_call_bmethod_body): ditto.
-
- * test/ruby/test_settracefunc.rb: add a test.
-
-Thu Jun 19 18:14:47 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm_core.h: add VM_FRAME_MAGIC_RESCUE to recognize normal block or
- rescue clause.
-
- * vm.c (vm_exec): use VM_FRAME_MAGIC_RESCUE on at rescue/ensure.
-
- * test/ruby/test_settracefunc.rb: should not invoke b_return at rescue
- clause.
- [Bug #9957]
-
- * vm_dump.c (control_frame_dump): check VM_FRAME_MAGIC_RESCUE.
-
- * vm_dump.c (vm_stack_dump_each): ditto.
-
-Thu Jun 19 13:39:11 2014 Arne Brasseur <arne@arnebrasseur.net>
-
- * proc.c (rb_method_curry): Implement Method#curry, which delegates
- to to_proc.curry. [ruby-core:62212] [Feature #9783]
-
-Tue Jun 17 16:41:49 2014 Shugo Maeda <shugo@ruby-lang.org>
-
- * lib/net/ftp.rb (gets, readline): read lines without LF properly.
- [ruby-core:63205] [Bug #9949]
-
- * test/net/ftp/test_buffered_socket.rb: related test.
-
-Tue Jun 17 12:35:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (extract_raise_opts): pass unknown options to the
- exception, so that exception class can receive a hash argument.
- [ruby-core:63203] [Feature #8257]
-
-Tue Jun 17 12:24:57 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (obj_memsize_of): memsize_of(T_ZOMBIE) returns 0, not a rb_bug.
- ObjectSpace.count_objects_size() uses memsize_of(T_ZOMBIE).
-
- This bug introduced at r46348.
-
-Mon Jun 16 19:00:11 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/runner.rb: failure message should be passed as an argument.
-
-Mon Jun 16 18:42:57 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/runner.rb: capture TracePoint stat before setup and compare
- it after teardown.
-
-Mon Jun 16 14:33:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * process.c (open): use UTF-8 version function to support
- non-ascii path properly. [ruby-core:63185] [Bug #9946]
-
-Sat Jun 14 10:54:08 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rcombinate0): remove recursion, by looping with indexes
- stored in `p`.
-
- * array.c (rpermute0): remove recursion, by looping with indexes
- stored in `p`.
-
- * array.c (permute0): remove recursion, by looping with indexes
- stored in `p`. [ruby-core:63103] [Bug #9932]
-
-Sat Jun 14 10:52:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_resize): update capa only when buffer get
- reallocated.
- http://d.hatena.ne.jp/nagachika/20140613/ruby_trunk_changes_46413_46420#r46413
-
-Sat Jun 14 08:28:59 2014 Zachary Scott <e@zzak.io>
-
- * man/rake.1: [DOC] Update links for Rake, patch by @hsbt [Bug #9904]
- [Fixes GH-628] https://github.com/ruby/ruby/pull/628
-
-Fri Jun 13 17:58:58 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm_trace.c: add new method TracePoint.stat to debug
- TracePoint mechanism.
-
- Ruby users should not use this method. So I don't note this method
- in the NEWS file.
-
- * test/runner.rb: detect zombie active TracePoints with
- TracePoint.stat.
-
-Fri Jun 13 17:46:31 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm_trace.c: clear and restore recursive checking thread local data
- to avoid unexpected throw from TracePoint.
- [Bug #9940]
-
- * test/ruby/test_settracefunc.rb: add a test.
-
- * thread.c: added
- * rb_threadptr_reset_recursive_data(rb_thread_t *th);
- * rb_threadptr_restore_recursive_data(rb_thread_t *th, VALUE old);
-
- * vm_core.h: ditto.
-
-Fri Jun 13 17:33:14 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_combination): iterate on a shared copy, and use
- array of indexes instead of array of chosen objects.
- [ruby-core:63149] [Bug #9939]
-
- * array.c (yield_indexed_values): extract from permute0(),
- rpermute0(), and rcombinate0().
-
-Fri Jun 13 13:42:58 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_permutation): `p` is the array of size `r`, as
- commented at permute0(). since `n >= r` here, buffer overflow
- never happened, just reduce unnecessary allocation though.
-
-Thu Jun 12 20:32:28 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_resize): should consider the capacity instead
- of the old length, as pointed out by nagachika.
-
-Thu Jun 12 18:31:01 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/net/http/responses.rb: added Net::HTTPPermanentRedirect(308)
- Contributed by @yorkie [fix GH-638]
-
-Thu Jun 12 13:27:38 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_freeze): shrink the buffer before freezing, as
- pointed out by Eric Wong at [ruby-core:63119].
-
-Thu Jun 12 13:09:03 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (expand_path): shrink expanded path which no longer needs
- rooms to append. [ruby-core:63114] [Bug #9934]
-
-Wed Jun 11 17:37:48 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (rb_cv_scalar_pthread_t): pthread_t is not required
- to be a scalar type.
-
- * thread.c (fill_thread_id_string, thread_id_str): dump pthread_t
- in hexadecimal form if it is not a scalar type, assume it can be
- represented in a pointer form otherwise. based on the patch by
- Rei Odaira at [ruby-core:62867]. [ruby-core:62857] [Bug #9884]
-
- * thread_pthread.c (Init_native_thread, thread_start_func_1),
- (native_thread_create): set thread_id_str if needed.
-
- * vm_core.h (rb_thread_t): add thread_id_string if needed.
-
-Wed Jun 11 01:53:22 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: invoke GC before memory allocation (xmalloc/xrealloc)
- when GC.stress = true.
- [Bug #9859]
-
- * test/ruby/test_gc.rb: add a test.
-
-Tue Jun 10 13:20:14 2014 Takeyuki FUJIOKA <xibbar@ruby-lang.org>
-
- * lib/cgi/core.rb: Provide a mechanism to specify the
- max_multipart_length of multipart data.
- [Feature #8370] patch by Leif Eriksen <leif.eriksen.au@gmail.com>
-
-Tue Jun 10 10:57:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/csv.rb (CSV#<<): honor explicitly given encoding. based on
- the patch by DAISUKE TANIWAKI <daisuketaniwaki AT gmail.com> at
- [ruby-core:62113]. [Bug #9766]
-
-Mon Jun 9 20:40:48 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: change full GC timing to keep lower memory usage.
-
- Extend heap only at
- (1) after major GC
- or
- (2) after several (two times, at current) minor GC
-
- Details in https://bugs.ruby-lang.org/issues/9607#note-9
- [Bug #9607]
-
-Mon Jun 9 16:01:41 2014 Masahiro Ide <imasahiro9@gmail.com>
-
- * gc.c (gcdebug_sentinel): fix typo, "sentinel" not "sential".
- [fix GH-634]
-
-Mon Jun 9 00:04:25 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (posix_fadvise): disable use of posix_fadvise
- itself on 32-bit AIX. [ruby-core:62968] [Bug #9914]
-
-Sun Jun 8 23:28:00 2014 <kanemoto@ruby-lang.org>
-
- * io.c (rb_io_advise): AIX currently does not support a 32-bit call to
- posix_fadvise() if _LARGE_FILES is defined. Patch by Rei Odaira.
- [ruby-core:62968] [Bug #9914]
-
-Sun Jun 8 04:52:40 2014 Jun Hiroe <Jun.Hiroe@gmail.com>
-
- * string.c (rb_str_slice_bang): [DOC] update return value against
- a fixnum, which has changed because of M17N. [fix GH-631]
-
-Sat Jun 7 22:13:42 2014 Benoit Daloze <eregontp@gmail.com>
-
- * numeric.c (do_coerce): Add a warning when an exception is raised
- or an invalid value is returned in #coerce called by
- numeric comparison operators and the exception
- thrown by the caller has no information on the failure.
- In the next release such exception should not be rescued or
- should be the cause of the caller exception. nil is accepted
- as the "no possible coercion" return value. See #7688.
-
- * test/ruby/test_numeric.rb: Add corresponding test.
-
-Sat Jun 7 18:15:33 2014 Benoit Daloze <eregontp@gmail.com>
-
- * numeric.c (bit_coerce): remove constant parameter `err'
- (always TRUE) of bit_coerce().
-
-Sat Jun 7 16:01:57 2014 Yutaka Kanemoto <kanemoto@ruby-lang.org>
-
- * cont.c (rb_fiber_struct): keep context.uc_stack.ss_sp and context.uc_stack.ss_size
- for later use. Patch by Rei Odaira. [ruby-core:62945] [Bug #9905]
-
-Sat Jun 7 12:51:51 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (read_all): truncate the buffer before appending read data,
- instead of truncating before reading.
- [ruby-core:55951] [Bug #8625]
-
-Sat Jun 7 12:28:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/digest/digest.c (rb_digest_instance_equal): no need to call
- `to_s` twice. [Bug #9913]
-
-Sat Jun 7 11:35:01 2014 Tanaka Akira <akr@fsij.org>
-
- * object.c (rb_mod_initialize_clone): Override Kernel#initialize_clone
- to avoid an exception on Class.new.freeze.clone.to_s.
- Reported by Andrew Grimm. [ruby-core:41858] [Bug #5828]
-
-Sat Jun 7 06:03:11 2014 Benoit Daloze <eregontp@gmail.com>
-
- * ext/digest/digest.c (rb_digest_instance_equal):
- fix #== for non-string arguments. [ruby-core:62967] [Bug #9913]
-
- * test/digest/test_digest.rb: add test for above.
-
-Fri Jun 6 22:19:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (private_recv_p): check by node type, instead of a
- magic number.
-
- * node.h (NODE_PRIVATE_RECV), parse.y (attrset_gen): remove
-
-Fri Jun 6 17:07:08 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_compile_each), parse.y (new_attr_op_assign_gen):
- allow op assign to a private attribute.
- [ruby-core:62949] [Bug #9907]
-
-Fri Jun 6 13:39:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (io_setstrbuf, io_read): should not shorten the given buffer until
- read succeeds. [ruby-core:55951] [Bug #8625]
-
-Fri Jun 6 07:41:41 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb: dump empty symbols with a
- tag so that they can be parsed on input. [Bug #9873] [ruby-core:62825]
- * test/psych/test_symbol.rb: test for change
-
-Thu Jun 5 16:08:39 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_page_sweep): refactoring.
-
- * gc.c (gc_page_sweep): should not set, but add final_slots into
- sweep_page->final_slots.
-
-Thu Jun 5 14:36:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (jemalloc): check for the header regardless drop-in
- libjemalloc is found, for `malloc_conf` declaration.
-
- * version.c (ruby_show_version): show `malloc_conf` if set.
- [Feature #9113]
-
- * configure.in (with-jemalloc): also check for header, for ABIs
- which JEMALLOC_MANGLE is needed, i.e., Mach-O and PE-COFF
- platforms. [ruby-core:62939] [Feature #9113]
-
- * include/ruby/missing.h: include alternative malloc header to
- replace memory management functions.
-
- * dln.c, io.c, parse.y, st.c: undef malloc family before
- re-definition to suppress warnings.
-
-Thu Jun 5 12:52:18 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * man/ruby.1: remove rubyforge entry.
-
-Thu Jun 5 12:45:32 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * misc/README: use github link instead of rubyforge.
-
-Thu Jun 5 10:03:29 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (obj_free): check also FL_PROMOTED bit by RVALUE_OLD_P().
-
-Thu Jun 5 03:45:28 2014 Eric Wong <e@80x24.org>
-
- * configure.in: add --with-jemalloc option
- [ruby-core:62912]
-
-Wed Jun 4 22:28:14 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: introduce RZombie to manage zombie objects.
- Rewrite finalizing logics with this type.
-
- * gc.c (gc_verify_internal_consistency): verify zombie (finalizing)
- objects count.
-
-Wed Jun 4 22:09:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * re.c (match_aref, rb_reg_regsub): consider encoding of captured
- names, encoding-incompatible should not match.
- [ruby-dev:48278] [Bug #9903]
-
-Wed Jun 4 21:23:52 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * re.c (match_aref): should not ignore name after NUL byte.
- [ruby-dev:48275] [Bug #9902]
-
-Wed Jun 4 04:08:37 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm.c (core_hash_merge_kwd): should return the result hash, which
- may be converted from and differ from the given argument.
- [ruby-core:62921] [Bug #9898]
-
-Tue Jun 3 23:32:34 2014 Tanaka Akira <akr@fsij.org>
-
- * ruby.c (load_file_internal2): Extracted from load_file_internal.
- (load_file_internal): Invoke load_file_internal2 using rb_protect.
- Close an opened FD if load_file_internal2 raises an exception.
-
-Tue Jun 3 19:11:45 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_objspace_free): should not rest_sweep() here.
- Some data structures are already freed.
-
-Tue Jun 3 18:43:51 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_gc.rb: allocate more objects to invoke GC by newobj.
- GC allows extending pages depends on heap_increment.
-
-Tue Jun 3 18:01:27 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_gc_call_finalizer_at_exit): add
- gc_verify_internal_consistency() when RGENGC_CHECK_MODE >= 2.
-
-Tue Jun 3 17:54:21 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: change the counting method for young objects.
- clear counter at the beginning of every GC and
- count promoted (infant->young) objects.
-
- Some promotions (infant->young) are transition of promoting to old
- objects. We should not count such promotions.
-
- With this technique, we don't need to check young objects
- at obj_free().
-
-Tue Jun 3 16:38:19 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: add verifying counters code in gc_verify_internal_consistency().
- gc_verify_internal_consistency() counts all
- - live objects
- - young objects (if age2 promotion)
- - old objects
- in all pages and compares with objspace managing counters.
-
- * gc.c (gc_after_sweep): do gc_verify_internal_consistency()
- when RGENGC_CHECK_MODE >= 2.
-
-Tue Jun 3 13:14:04 2014 Shugo Maeda <shugo@ruby-lang.org>
-
- * lib/net/imap.rb (body_type_1part): Gmail IMAP reports a body
- type as "MIXED" followed immediately by params
- [ruby-core:62864] [Bug #9885]
- Patch by @rayners (David Raynes). [Fixes GH-622]
- https://github.com/ruby/ruby/pull/622
-
-Tue Jun 3 13:18:24 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (objspace_live_slot): live slot count should not include final
- slot (contains T_ZOMBIE) count.
-
-Tue Jun 3 13:03:21 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (obj_free): fix spacing.
-
-Tue Jun 3 12:59:32 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (check_gen_consistency): fix error message.
-
-Tue Jun 3 12:40:23 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: count old/young objects more correctly.
-
- * gc.c (RVALUE_DEMOTE_FROM_OLD): decrement old object count.
-
- * gc.c (RVALUE_DEMOTE_FROM_YOUNG): decrement young object count.
-
- * gc.c (rb_gc_resurrect): increment old object count.
-
- * gc.c (gc_marks_body): should not add old object count.
- This code is completely my misunderstanding.
-
- * gc.c (rb_gc_force_recycle): decrement young or old object count
- correctly.
-
-Tue Jun 3 12:26:47 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/memory_status.rb: add $LOAD_PATH to load test/unit
- correctly for fiddle/import unavailable environments.
-
-Tue Jun 3 09:45:13 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/openssl/test_ssl.rb (OpenSSL::TestSSL#test_verify_result):
- shouldn't use same server for respective tests, because the 1st
- test sometimes kills the server main loop silently.
- [Bug #9881] [ruby-dev:48266]
-
-Tue Jun 3 01:34:59 2014 Zachary Scott <e@zzak.io>
-
- * README.EXT: [DOC] Add rb_call_super when subclassing from @robin850
- [Fixes GH-623] https://github.com/ruby/ruby/pull/623
-
-Mon Jun 2 17:14:49 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm.c (ruby_vm_destruct): remove useless call of
- rb_gc_force_recycle().
-
- At this line, a VM object is already freed
- (is changed to T_NONE) by rb_gc_call_finalizer_at_exit().
-
-Mon Jun 2 15:50:24 2014 Koichi Sasada <ko1@atdot.net>
-
- * eval.c (rb_using_refinement): add write-barriers for
- cref->nd_refinements.
-
-Mon Jun 2 12:26:08 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * CONTRIBUTING.md: added contributing guide for github. [fix GH-625]
-
-Mon Jun 2 07:30:33 2014 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/envutil.rb (default_warning): New method.
-
- * test/ruby/test_autoload.rb: Use EnvUtil.default_warning.
-
-Mon Jun 2 07:05:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/encoding.h: constify `rb_encoding` arguments.
-
- * include/ruby/oniguruma.h: constify `OnigEncoding` arguments.
-
-Sun Jun 1 12:05:10 2014 Tanaka Akira <akr@fsij.org>
-
- * test/drb: Wrap tests definitions by DRbTests module. This makes
- several tests (ACLEntryTest, TestBug4409, etc.) easier to understand
- that they are tests for DRb.
-
-Sun Jun 1 11:36:25 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/rinda/ring.rb (RingFinger#make_socket): Close the socket on
- exception.
-
-Sun Jun 1 06:55:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (intern_str): dynamic attrset ID is registered by
- `rb_id_attrset()` already, so no further registration is needed.
- [ruby-core:62861]
-
-Sun Jun 1 04:52:47 2014 Zachary Scott <e@zzak.io>
-
- * lib/English.rb: [DOC] $LOADED_FEATURES moved to load.c [Fixes GH-620]
- Patch submitted by @leafac in https://github.com/ruby/ruby/pull/620
- * doc/globals.rdoc: Added $LOADED_FEATURES to list
-
-Sat May 31 22:30:14 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/leakchecker.rb: Leak checker extracted from
- test/lib/minitest/unit.rb.
-
-Sat May 31 21:15:43 2014 URABE Shyouhei <shyouhei@ruby-lang.org>
-
- * thread.c (rb_thread_atfork_internal): My compiler complains
- about this variable being used before initialized. I looked at
- the code and expanded the macro and turned out it was actually
- USED for pointer arithmetic, not dereferenced. So this was
- never a serious bug. But is annoying indeed to see warnings
- every time. I added `=0` and all went healthy.
-
- * configure.in: Also, I found that the problematic macro expansion
- only happens when we lack __typeof__ C extension, which shall
- not be the case of my compiler. I added AC_C_TYPEOF to kick ass.
-
-Sat May 31 16:32:50 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/ipaddr.rb: extracted inline tests into test dir.
- * test/test_ipaddr.rb: ditto.
-
-Sat May 31 16:29:21 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * ext/digest/lib/digest/hmac.rb: extracted inline tests into test dir.
- * test/digest/test_digest_hmac.rb: ditto.
-
-Sat May 31 16:02:03 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/test_syslog.rb: remove executable.
-
-Sat May 31 08:58:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enc/unicode.c (init_case_fold_table): no longer need to
- initialize tables at runtime.
-
- * enc/unicode/case-folding.rb (lookup_hash): make perfect hash to
- lookup case unfolding table 3.
-
- * enc/unicode/case-folding.rb (lookup_hash): make perfect hash to
- lookup case unfolding table 2.
-
- * enc/unicode/case-folding.rb (lookup_hash): make perfect hash to
- lookup case unfolding table 1.
-
- * enc/unicode/case-folding.rb (lookup_hash): make perfect hash to
- lookup case folding table.
-
- * enc/unicode/case-folding.rb (print_table): merge non-locale and
- locale tables, and reduce initializing loops.
-
- * enc/unicode/case-folding.rb (CaseFolding): modularize, and add
- --output-file option.
-
- * enc/unicode/case-folding.rb: script to convert CaseFolding.txt,
- translated from CaseFolding.py.
-
-Sat May 31 08:31:41 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb: Check Tempfile leaks for each test method
- again.
-
-Sat May 31 03:50:50 2014 Zachary Scott <e@zzak.io>
-
- * lib/delegate.rb: [DOC] Document raise in Delegator class
- Patch by @lucasmazza. [Fixes GH-621]
- https://github.com/ruby/ruby/pull/621
-
-Fri May 30 21:23:26 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/webrick/server.rb: Use a pipe to detect server shutdown.
- shutdown() or close() for listening socket is not a reliable.
- Actually, both doesn't work (doesn't wake up select()) on
- DragonFly BSD 3.6.2.
-
- * test/webrick/utils.rb: :ShutdownSocketWithoutClose is not required
- now to immediate server shutdown detection.
- This fixes fd leaks.
-
- * test/net/http/utils.rb: Ditto.
-
-Fri May 30 20:58:37 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb (check_fd_leak): Sort the inspected
- objects list for a FD.
-
-Fri May 30 18:06:55 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb (check_fd_leak): Try GC to delete leaked
- FDs.
-
-Fri May 30 12:05:59 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * test/lib/test/unit/parallel.rb (_run_suite): orig_stdout may be nil
- though I don't know the reason.
-
-Fri May 30 11:33:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_substr): need to reset code range for shared
- string too, not only copied string.
- [ruby-core:62842] [Bug #9882]
-
-Fri May 30 10:22:21 2014 Mark Lorenz <mlorenz@covermymeds.com>
-
- * lib/erb.rb (result): [DOC] no longer accepts a Proc, as
- Kernel.eval does not. [fix GH-619]
-
-Fri May 30 07:25:46 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/-test-/dir: Dir#fileno implemented.
-
- * test/lib/minitest/unit.rb (find_fds): Don't return the fd used to
- scan /proc/$$/fd.
-
-Fri May 30 04:48:00 2014 Eric Wong <e@80x24.org>
-
- * parse.y (rb_gc_mark_parser): remove, empty since r8758
- * internal.h: ditto, not usable from extensions since 2.0.0
- * gc.c (gc_mark_roots): remove checkpoint for parser
-
-Thu May 29 23:27:50 2014 Rei Odaira <Rei.Odaira@gmail.com>
-
- * signal.c (ruby_signal): should return either `old.sa_sigaction`
- or `old.sa_handler`, depending on whether `SA_SIGINFO` is set in
- `old.sa_flags`, because they may not be a union.
- [ruby-core:62836] [Bug #9878]
-
-Thu May 29 23:11:20 2014 Tanaka Akira <akr@fsij.org>
-
- * io.c (pipe_open): Close pipes when rb_execarg_fixup() raises
- an exception.
- (rb_execarg_fixup_v): New function.
-
-Thu May 29 22:18:57 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb (capture_subprocess_io): Close fds.
-
-Thu May 29 19:47:08 2014 Tanaka Akira <akr@fsij.org>
-
- * io.c (rb_io_s_pipe): Close pipes if io_encoding_set() raises an
- exception.
- (io_encoding_set_v): New function.
-
-Thu May 29 19:42:49 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/csv.rb (CSV.open): Close the opened file when an exception
- occur.
-
-Thu May 29 19:31:10 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/openssl/lib/openssl/ssl.rb (SSLServer#accept): Close a socket
- if any exception occur.
-
-Thu May 29 05:05:29 2014 Eric Wong <e@80x24.org>
-
- * include/ruby/ruby.h: Hide Symbol internals.
- (struct RSymbol): moved to internal.h
- (RSYMBOL): ditto
-
-Thu May 29 00:28:56 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/unixsocket.c (rsock_init_unixsock): Open a socket
- after path length check.
- This fixes a fd leak by TestSocket_UNIXSocket#test_too_long_path.
-
-Wed May 28 23:04:35 2014 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_io.rb (test_flush_in_finalizer1): Use
- ObjectSpace.each_object to close files.
- GC.start is not reliable.
-
-Wed May 28 19:00:31 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/net/imap.rb (Net::IMAP#initialize): Close the opened socket when
- any exception occur.
- This fixes a fd leak by IMAPTest#test_imaps_post_connection_check
- which start_tls_session() raises an exception.
-
-Wed May 28 18:06:13 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/openssl/ossl_ssl.c (ossl_ssl_close): Fix sync_close to work
- when SSL is not started.
- This fix the fd leak by test_https_proxy_authentication in
- test/net/http/test_https_proxy.rb.
-
-Wed May 28 10:29:28 2014 Eric Wong <e@80x24.org>
-
- * vm.c (rb_vm_living_threads_foreach): remove function
- [ruby-core:62745]
- * thread.c (terminate_i): remove
- * thread.c (terminate_all): implement (inlines old terminate_i)
- * thread.c (rb_thread_terminate_all): use terminate_all
- * thread.c (rb_thread_fd_close_i): remove
- * thread.c (rb_thread_fd_close): iterate inline
- * thread.c (thread_list_i): remove
- * thread.c (rb_thread_list): iterate inline
- * thread.c (rb_thread_atfork_internal): iterate inline
- * thread.c (terminate_atfork_i): update types to remove casts
- * thread.c (terminate_atfork_before_exec_i): ditto
- * thread.c (struct thgroup_list_params): remove definition
- * thread.c (thgroup_list_i): remove
- * thread.c (thgroup_list): iterate inline
- * thread.c (check_deadlock_i): remove
- * thread.c (debug_deadlock_check): implement (inlines check_deadlock_i)
- * thread.c (debug_i): remove
- * thread.c (rb_check_deadlock): iterate inline
- * vm.c (vm_mark_each_thread_func): remove
- * vm.c (rb_vm_mark): iterate inline
- * vm_core.h (rb_vm_living_threads_remove): remove
- * vm_trace.c (clear_trace_func_i): remove
- * vm_trace.c (rb_clear_trace_func): iterate inline
-
-Wed May 28 09:30:51 2014 Eric Wong <e@80x24.org>
-
- * signal.c (signal_exec): ignore immediate cmd for SIG_IGN
- * signal.c (trap_handler): set cmd to true for SIG_IGN
- * signal.c (trap): handle nil and true values for oldcmd
- [Bug #9835]
-
-Wed May 28 01:02:54 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/tempfile.rb (Tempfile#inspect): Show "(closed)" if the tempfile
- is closed.
-
-Wed May 28 00:38:09 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb: Use Tempfile#close! instead of
- Tempfile#unlink to close file descriptors.
-
- * test/openssl/test_config.rb: Ditto.
-
- * test/ruby/test_io.rb: Ditto.
-
-Wed May 28 00:06:18 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/net/ftp.rb (transfercmd): Close TCP server socket even if an
- exception occur.
-
-Tue May 27 23:50:07 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/cgi/core.rb: Use Tempfile#close! instead of Tempfile#unlink
- to close file descriptors.
-
-Tue May 27 23:06:46 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_number_literal_suffix): refine error message for
- extra dot and digits.
-
-Tue May 27 22:44:20 2014 Tanaka Akira <akr@fsij.org>
-
- * test/rexml: Avoid fd leaks.
-
-Tue May 27 22:24:25 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_document.rb: Indent.
-
-Tue May 27 22:15:29 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_document.rb: Wrap by REXMLTests module.
-
-Tue May 27 22:11:10 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_encoding_2.rb: Remove a needless file.
-
-Tue May 27 22:10:30 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_contrib.rb: Indent.
-
-Tue May 27 21:28:16 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/socket/ifaddr.c (ifaddr_inspect_flags): support IFF_SIMPLEX.
-
-Tue May 27 21:03:03 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/: Use REXMLTests as wrapping module for REXML tests.
- I avoid using the same module for library in test because
- it provides "include REXML" environment in test. Normally,
- users don't use REXML on "include REXML" environment. So I
- don't want to write tests on "include REXML" environment.
-
-Tue May 27 20:59:37 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_comment.rb: Remove needless REXML module wrapping.
-
-Tue May 27 20:56:49 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/openssl/test_pkcs7.rb: Fix inverted expected and actual values.
-
-Tue May 27 20:26:06 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/ruby/test_io.rb (test_flush_in_finalizer1): some opened fds are
- remain before GC, so unlink the tempfile is failed.
-
-Tue May 27 19:07:26 2014 Tanaka Akira <akr@fsij.org>
-
- * io.c (rb_io_autoclose_p): Don't raise on frozen IO.
-
- * test/lib/minitest/unit.rb: IO#autoclose? may raise IOError.
-
-Tue May 27 19:01:49 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/openssl/test_pair.rb: Modify TestSSL#test_read_and_write
- to handle partial sysreads. [Bug #7398][ruby-core:49563]
- * test/openssl/test_ssl.rb: ditto.
-
-Tue May 27 18:46:23 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/openssl/test_pkcs7.rb: Add tests for PKCS7#type= and add_data.
- [Feature #7399][ruby-core:49565]
-
-Tue May 27 17:45:09 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/openssl/test_hmac.rb (test_binary_update): Added Test for
- HMAC signing with UTF-8 String. [Bug #7512][ruby-core:50559]
-
-Tue May 27 17:10:14 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/runner.rb: fixed randomly test failure.
- [Bug #6573][ruby-core:45563]
-
-Tue May 27 16:58:12 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/test_timeout.rb (test_timeout): inverted test condition.
- [Bug #8523]
-
-Tue May 27 12:24:22 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb: Show leaked file descriptors.
-
-Tue May 27 11:12:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (rb_io_fileno, rb_io_inspect): non-modification does not
- error on frozen IO. [ruby-dev:48241] [Bug #9865]
-
-Tue May 27 00:00:21 2014 yui-knk <spiketeika@gmail.com>
-
- * insns.def (defineclass): fix typo in the instruction comment.
- [fix GH-618]
-
-Mon May 26 16:33:15 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/ruby/test_file.rb: skip the test of atime on Windows, because
- Windows delays updating atime about 1 hour.
- see more details:
- http://msdn.microsoft.com/en-us/library/windows/desktop/ms724290%28v=vs.85%29.aspx
-
-Mon May 26 12:25:36 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/optionparser.rb, lib/optparse.rb (OptParse): aliases.
- [ruby-core:62751] [Feature #9864]
-
-Mon May 26 07:59:34 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb: Show Finished threads line-by-line.
-
-Mon May 26 01:39:02 2014 Zachary Scott <e@zzak.io>
-
- * lib/csv.rb: Reject nil as data source for CSV.new, patch by @Peeja.
- [Fixes GH-580] https://github.com/ruby/ruby/pull/580
-
-Mon May 26 01:07:51 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb: Show leaked threads and tempfiles
- line-by-line.
-
-Sun May 25 23:02:06 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb (MiniTest::Assertions#diff): Remove
- tempfiles.
-
-Sun May 25 22:42:27 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb: Check tempfile leak for each test class.
-
-Sun May 25 20:31:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (ac_cv_func_{getcontext,setcontext}): do not
- disable ucontext.h entirely, but disable use of functions only.
- `ucontext_t` is necessary in the signal handler now.
-
-Sun May 25 20:00:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * signal.c (check_stack_overflow): revert part of r46100, the
- previous condition was correct, and fix compilation error on
- other architecture linux. [ruby-core:62746] [Bug #9862]
-
-Sun May 25 17:09:13 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb: Less ObjectSpace.each_object(Tempfile)
- invocation.
-
-Sun May 25 16:54:06 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb: Use Thread.list instead of
- ObjectSpace.each_object(Thread).
-
-Sun May 25 15:53:54 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/rinda/ring.rb (Rinda::RingServer#shutdown): Join the killed
- threads.
-
-Sun May 25 15:26:17 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/webrick/utils.rb: Override the inspect method of the thread
- used in WEBrick::Utils::TimeoutHandler.
-
-Sun May 25 14:22:30 2014 Tanaka Akira <akr@fsij.org>
-
- * test/openssl: Join threads.
-
-Sun May 25 12:46:47 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (rb_bug_context): new function to report bug with
- context.
-
- * vm_dump.c (rb_vm_bugreport): accepts `ucontext_t` argument to
- dump machine registers. based on [GH-584].
-
- * signal.c (sigbus, sigsegv): dump machine registers if available.
-
-Sun May 25 12:32:42 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb: Sort leaked threads and tempfiles.
-
-Sun May 25 12:15:30 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * signal.c (check_stack_overflow): fix condition to use ucontext
- register, mcontext_t dereference, and its member names, on Mac
- OS X.
-
-Sun May 25 11:58:26 2014 Zachary Scott <e@zzak.io>
-
- * enumerator.c: [DOC] Fix example to show Enumerator#peek behavior
- Patch by Erik Hollembeak [Bug #9814]
-
-Sun May 25 11:56:33 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vsnprintf.c (BSD_vfprintf): fix string width when precision is
- given. as the result of `memchr` is NULL or its offset from the
- start cannot exceed the size, the comparison was always false.
- [ruby-core:62737] [Bug #9861]
-
-Sun May 25 11:32:42 2014 Zachary Scott <e@zzak.io>
-
- * lib/yaml.rb: Remove Psych::EngineManager [Bug #8344]
- * test/psych/*: ditto.
-
-Sun May 25 10:34:15 2014 Zachary Scott <e@zzak.io>
-
- * doc/regexp.rdoc: [DOC] Clarify whitespace matching by @allolex
- [Fixes GH-606] https://github.com/ruby/ruby/pull/606
-
-Sun May 25 10:19:34 2014 Zachary Scott <e@zzak.io>
-
- * enum.c: [DOC] Use #find in example to clarify alias by @rachellogie
- Patch submitted via documenting-ruby/ruby#34
-
-Sun May 25 10:16:43 2014 Zachary Scott <e@zzak.io>
-
- * cont.c: [DOC] Fix rdoc in example for Fiber#transfer by @majjoha
- Patch submitted via documenting-ruby/ruby#33
-
-Sun May 25 10:01:11 2014 Zachary Scott <e@zzak.io>
-
- * lib/irb.rb: [DOC] Fixed syntax error in example by @jasdeepsingh.
- Patch submitted via documenting-ruby/ruby#32
-
-Sun May 25 09:58:02 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/fileutils/test_fileutils.rb (test_chown_R): Add tests for
- chown_R. [Feature #9383][ruby-core:59641]
-
-Sun May 25 09:57:09 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/fileutils/test_fileutils.rb: Added recursively chown tests.
- [Feature #9303][ruby-core:59325]
-
-Sun May 25 09:41:56 2014 Zachary Scott <e@zzak.io>
-
- * class.c: [DOC] Fixed grammar and examples of instance_methods.
- By @alex-frost via documenting-ruby/ruby#31
-
-Sun May 25 09:40:44 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb: Show leaked threads and tempfiles.
-
-Sun May 25 08:54:38 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/openssl/test_partial_record_read.rb: Testing read_nonblock on
- a partial TLS record results in IO::WaitReadable by @mohamedhafez.
- [fix GH-547]
-
-Sun May 25 08:43:16 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * lib/logger.rb: refactored to include Logger::Period.
-
-Sun May 25 06:50:19 2014 Zachary Scott <e@zzak.io>
-
- * vm_eval.c: [DOC] Improve instance_eval description when given a
- block or String arguments. By @nathanl via documenting-ruby/ruby#28
-
-Sun May 25 06:29:39 2014 Zachary Scott <e@zzak.io>
-
- * array.c: [DOC] Clarify default argument for Array.new.
- By @Elffers [Fixes GH-610]
-
-Sat May 24 22:37:20 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * array.c: [DOC] Add more documents to shuffle! and shuffle.
- Contributed by @JuanitoFatas [ci skip][fix GH-612]
-
-Sat May 24 22:28:55 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/lib/minitest/.document: removed unused configuration.
-
-Sat May 24 19:08:47 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/spec.rb: Unused file removed.
-
- * test/lib/minitest/autorun.rb: Don't require minitest/spec.
-
- * test/lib/minitest/benchmark.rb: Ditto.
-
-Sat May 24 18:45:30 2014 Tanaka Akira <akr@fsij.org>
-
- * test/benchmark/test_benchmark.rb: Use test/unit.
-
-Sat May 24 16:20:59 2014 Eric Wong <e@80x24.org>
-
- * process.c (proc_getgroups, proc_setgroups): use ALLOCV_N
- [Bug #9856]
-
-Sat May 24 15:49:39 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/unit.rb (parallelize_me!): Removed.
- This fixes the line-by-line structure of the test result in verbose
- mode. [ruby-core:54905]
-
- * test/lib/minitest/parallel_each.rb: Removed.
-
- * test/minitest/test_minitest_mock.rb: Don't call parallelize_me!.
-
- * test/minitest/test_minitest_spec.rb: Ditto.
-
- * test/minitest/test_minitest_unit.rb: Ditto.
- Tests for parallel feature removed.
-
-Sat May 24 15:29:10 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest/hell.rb: Unused file removed.
-
- * test/lib/minitest/pride.rb: Ditto.
-
-Sat May 24 15:05:32 2014 yui-knk <spiketeika@gmail.com>
-
- * enumerator.c (yielder_yield_push): Insert a break after the
- method return value. [fix GH-617]
-
-Sat May 24 14:59:12 2014 Tanaka Akira <akr@fsij.org>
-
- * test/lib/minitest: Remove comments not appropriate now.
-
- * test/minitest: Ditto.
-
-Sat May 24 14:02:04 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * NEWS: added minitest changes.
-
-Sat May 24 13:42:46 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/lib/test/unit/test-unit.gemspec: removed needless gemspec file.
-
-Sat May 24 09:39:06 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * defs/default_gems: removed minitest entry.
-
-Sat May 24 06:17:33 2014 Ryan Davis <ryand-ruby@zenspider.com>
-
- * lib/minitest: minitest 4.7.5 removed. Need to support proper
- gem packaging / installation before minitest 5 can be added.
-
-Sat May 24 05:54:06 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/mkconstants.rb: More constants
-
-Sat May 24 00:25:34 2014 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * NEWS: add information of incompatibility about Prime.prime?
- * lib/prime.rb: fix docs.
-
-Fri May 23 21:36:28 2014 Josh Goebel <dreamer3@gmail.com>
-
- * net/protocol.rb (using_each_crlf_line): fix SMTP dot-stuffing
- for messages not ending with a new-line.
- [ruby-core:61441] [Bug #9627] [fix GH-616]
-
-Fri May 23 03:48:08 2014 Eric Wong <e@80x24.org>
-
- * gc.c (rb_free_m_tbl): mark function as static
-
- * method.h (rb_free_m_tbl): remove prototype
-
-Thu May 22 22:58:27 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/mkconstants.rb: More TCP option constants.
- Describe Linux and glibc versions.
-
-Thu May 22 20:38:10 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * file.c (stat_birthtime): add birthtime support [Feature #9647]
-
- * file.c (rb_stat_birthtime): add File::Stat.birthtime
-
- * file.c (rb_file_s_birthtime): add File.birthtime
-
- * file.c (rb_file_birthtime): add File#birthtime
-
- * configure.in: check struct stat.st_birthtimespec.
-
-Thu May 22 19:38:14 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * file.c: remove IO::Statfs because of reject. [Feature #9772]
-
-Thu May 22 14:02:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enc/jis/props.kwd: constify character property tables of JIS
- based encodings by perfect hash.
-
- * enc/euc_jp.c, enc/shift_jis.c: use character property functions.
-
-Wed May 21 12:21:10 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/option.c: Fix compilation error on Android.
- Bionic doesn't define TCP state constants.
-
-Wed May 21 11:42:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: workaround for Info.plist to get rid of `dsymutil`
- crash by wrong files in parent directories.
- [ruby-core:62594] [Bug #9840]
-
-Tue May 20 20:57:34 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/ruby/test_dir.rb (test_glob): added testcase of double
- slash path.
-
-Tue May 20 04:58:54 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/extconf.rb: Don't check fields of struct tcp_info if the
- structure is not available.
-
-Mon May 19 23:13:33 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/option.c (inspect_tcp_info): Permit longer data. (glibc
- 2.7 adds tcpi_rcv_rtt, tcpi_rcv_space and tcpi_total_retrans to
- struct tcp_info.)
-
-Mon May 19 20:49:07 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/option.c (inspect_tcp_info): New function to inspect
- struct tcp_info.
- (sockopt_inspect): Use inspect_tcp_info.
-
- * ext/socket/extconf.rb: Check tcp_info related things.
-
- * ext/socket/rubysocket.h: Include netinet/tcp_fsm.h if available.
-
-Mon May 19 19:36:39 2014 Tanaka Akira <akr@fsij.org>
-
- * test/dbm/test_dbm.rb: Use Etc.uname.
-
- * test/gdbm/test_gdbm.rb: Ditto.
-
-Mon May 19 16:54:22 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/etc/etc.c (etc_uname): add support for Windows using
- GetVersionExW(), GetSystemInfo(), and GetComputerNameExW() with
- `ComputerNameDnsHostname`. [Feature #9842]
-
-Mon May 19 16:29:48 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_pat_search): advance by byte offset but not by char
- offset. [ruby-core:62669] [Bug #9849]
-
-Mon May 19 14:06:18 2014 Shota Fukumori <her@sorah.jp>
-
- * bin/testrb: Removed. Forgot to remove in r45971.
- [Feature #9711] [ruby-core:62620]
-
-Sun May 18 16:42:08 2014 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_m17n_comb.rb (test_str_crypt): Use Etc.confstr to
- detect the glibc version.
- libc.so is not an executable on Debian GNU/kFreeBSD 7.0 (wheezy).
-
-Sun May 18 12:15:54 2014 Jonathan Mukai-Heidt <johnnymukai@gmail.com>
-
- * io.c (argf_each_line, argf_inplace_mode_set): [DOC] Update ARGF
- documentation examples. `ARGF.lines` has been deprecated in
- favor of `ARGF.each_line`. [Fixes GH-615]
-
-Sun May 18 11:59:25 2014 Tanaka Akira <akr@fsij.org>
-
- * missing/nextafter.c: Include ruby/missing.h.
-
-Sun May 18 11:09:28 2014 Tanaka Akira <akr@fsij.org>
-
- * win32/Makefile.sub: Add nextafter.obj to MISSING.
-
-Sun May 18 10:46:04 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/etc/etc.c: Etc.sysconf, Etc.confstr and IO#pathconf implemented.
-
- * ext/etc/extconf.rb: Check sysconf(), confstr() and fpathconf().
-
- * ext/etc/mkconstants.rb: New file.
-
- [ruby-core:62600] [Feature #9842]
-
-Sun May 18 09:58:17 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/etc/etc.c: Etc.uname method implemented.
-
- * ext/etc/extconf.rb: Check uname() function.
-
- [ruby-core:62139] [Feature #9770]
-
-Sun May 18 09:16:33 2014 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Check nextafter() availability.
-
- * include/ruby/missing.h (nextafter): New optional declaration.
-
- * missing/nextafter.c: New file.
-
- * numeric.c: Float#next_float and Float#prev_float implemented.
-
- [ruby-core:62562] [Feature #9834]
-
-Sun May 18 09:02:17 2014 Tanaka Akira <akr@fsij.org>
-
- * enum.c: Enumerable#slice_after implemented.
-
- * enumerator.c: Enumerator::Lazy#slice_after implemented.
-
- Requested by Tsuyoshi Sawada. [ruby-core:58123] [Feature #9071]
-
-Sun May 18 08:22:25 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (io_setstrbuf): always check if the buffer is modifiable.
- [ruby-core:62643] [Bug #9847]
-
-Sun May 18 01:21:23 2014 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/ruby.h: Hide Rational internal.
- (RRational): Moved to internal.h
- (RRATIONAL): Ditto.
- (RRATIONAL_SET_NUM): Moved to rational.c.
- (RRATIONAL_SET_DEN): Ditto.
-
- * rational.c (rb_rational_num): New function.
- (rb_rational_den): Ditto.
-
- * include/ruby/intern.h (rb_rational_num): Declared.
- (rb_rational_den): Ditto.
-
- * ext/bigdecimal/bigdecimal.c: Follow the above change.
-
- * ext/date/date_core.c: Ditto.
-
- [ruby-core:60665] [Feature #9513]
-
-Sat May 17 17:04:32 2014 Shota Fukumori <her@sorah.jp>
-
- * NEWS: Add news about removal of lib/test/**/*.rb.
-
-Sat May 17 16:57:33 2014 Shota Fukumori <her@sorah.jp>
-
- * lib/test: Removed because ruby's test cases now independent to
- lib/test by r45970. [Feature #9711] [ruby-core:62620]
-
- I'm still considering about the future of lib/minitest, lib/test.
- (bundling gems?)
-
-Sat May 17 15:06:40 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/runner.rb: remove dependency test-unit and minitest
- from stdlib when running with test-all.
- [Feature #9711][ruby-core:61890]
- * test/testunit/*.rb: ditto.
- * test/lib: ditto.
-
-Sat May 17 11:02:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (glob_helper): try match PLAIN as well as ALPHA, which are
- separated by previous commits. [ruby-core:61552] [Bug #9648]
-
- * dir.c (glob_make_pattern): set PLAIN for non-magical path to
- skip parts which not need to glob.
- [ruby-core:61552] [Bug #9648]
-
- * dir.c (has_magic): return ALPHA at alphabetical name regardless
- FNM_CASEFOLD flag.
-
- * dir.c (glob_helper): fix conditions for ALPHA.
- [ruby-core:61552] [Bug #9648]
-
-Sat May 17 01:49:27 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (glob_helper): reduce matching at non-magical path on
- Windows.
-
-Sat May 17 01:49:23 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (glob_pattern_type): separate names with alphabet but no
- magical from plain.
-
- * dir.c (glob_helper): match plain names as-is to treat super-root
- same as the root. [ruby-core:61552] [Bug #9648]
-
-Fri May 16 17:38:22 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_marks, gc_marks_body): increase the counter of young objects
- at the major GC because AGE2Promotion changes all old objects into
- young objects at major GC.
-
-Fri May 16 17:26:24 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_before_sweep): heap_pages_swept_slots should contains
- heap_pages_increment.
-
- For example, GC by exceeding malloc_limit can remain
- heap_pages_increment.
-
-Thu May 15 21:18:43 2014 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * configure.in: enable SSE2 on mingw. target='i386-pc-mingw32'.
- [ruby-core:62095] [Bug #8358]
-
-Thu May 15 21:04:06 2014 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * lib/test/unit/parallel.rb: fix test-all parallel failure if a test
- is skipped after raise.
- DL::TestFunc#test_sinf is skipped after raise on mingw ruby.
- But it causes Marshal.load failure due to undefined class/module
- DL::DLError when doing test-all parallel and test-all doesn't
- complete. We create new MiniTest::Skip object to avoid Marshal.load
- failure.
- [ruby-core:62133] [Bug #9767]
-
- * test/testunit/test_parallel.rb (TestParallel): add a test.
-
- * test/testunit/tests_for_parallel/ptest_forth.rb: ditto.
-
-Thu May 15 18:57:23 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (garbage_collect_body): move gc_heap_prepare_minimum_pages()
- from gc_sweep().
-
-Thu May 15 18:51:25 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (heap_extend_pages): calculate next growing heap size.
-
- * gc.c (heap_set_increment): accept addition pages instead of
- minimum pages.
-
- * gc.c (gc_after_sweep): use heap_etend_pages().
-
- * gc.c (gc_heap_prepare_minimum_pages): add only 1 page.
-
- * gc.c (heap_ready_to_gc): add only 1 page.
-
-Thu May 15 18:42:49 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: introduce macros to remove magic number.
-
- GC_HEAP_FREE_SLOTS_MIN_RATIO = 0.3: guarantee minimum empty slots
- ratio after sweep.
- GC_HEAP_FREE_SLOTS_MAX_RATIO = 0.8: allow to free pages 0.2 (= 1-0.8)
- of current existing slots.
-
-Thu May 15 17:32:51 2014 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * thread_win32.c (rb_w32_stack_overflow_handler): use Structured
- Exception Handling by AddVectoredExceptionHandler() for machine
- stack overflow on mingw.
- This would be equivalent to the handling using __try and __except
- on mswin introduced by r43748.
-
-Wed May 14 19:31:03 2014 Koichi Sasada <ko1@atdot.net>
-
- * ext/openssl/depend: remove dependency from internal headers.
- [Feature #9612]
-
- * ext/openssl/ossl.c (ossl_fips_mode_set): ditto.
-
- * ext/coverage/depend: ditto.
-
- * include/ruby/thread_native.h: added.
-
- This header file only provides wrapper functions to control
- native threads. These wrapper functions are used by MRI
- implementation.
-
- * vm_core.h: use include/ruby/thread_native.h.
-
- * thread.c: ditto.
-
- * thread_pthread.h: ditto.
-
- * thread_win32.h: ditto.
-
- * thread_native.h: removed.
-
-Wed May 14 18:03:28 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: enable RGENGC_AGE2_PROMOTION.
-
-Wed May 14 18:02:30 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rgengc_rememberset_mark): promote remembered object earlier.
-
-Mon May 12 23:57:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (rb_cv_atan2_inf_c99): check whether runtime atan2
- handles Inf as C99. [ruby-core:62536] [Bug #9831]
-
-Mon May 12 20:33:01 2014 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Invoke AC_REPLACE_FUNCS for each function.
-
-Mon May 12 19:52:11 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: count young object correctly and show it in GC.stat
- on RGENGC_AGE2_PROMOTION.
-
- * gc.c (RVALUE_PROMOTE_YOUNG): decrement young object count on
- YOUNG->OLD.
-
- * gc.c (obj_free): decrement young object count when young object
- freed.
-
- * gc.c (gc_marks): should not clear young object count.
-
- * gc.c (gc_stat_internal): GC.stat :young_object information.
-
-Mon May 12 01:30:59 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/ifaddr.c (IS_IFADDRS): Unused macro removed.
-
- * ext/strscan/strscan.c (BUFSIZE): Ditto.
-
- * ext/zlib/zlib.c (OBJ_IS_FREED): Ditto.
-
-Sun May 11 22:27:18 2014 Tanaka Akira <akr@fsij.org>
-
- * compile.c (BUFSIZE): Unused macro removed.
-
- * vm.c (BUFSIZE): Ditto.
-
- * pack.c (INT64toNUM): Ditto.
- (UINT64toNUM): Ditto.
- (BYTEWIDTH): Ditto.
-
- * time.c (lshift): Ditto.
- (UINT64toNUM): Ditto.
- (id_lshift): Unused variable removed.
-
-Sun May 11 21:23:27 2014 Tanaka Akira <akr@fsij.org>
-
- * pack.c (swaps): Unused macro removed.
- (swapi): Ditto.
- (swapl): Ditto.
- (swapll): Ditto.
-
-Sun May 11 08:02:49 2014 Eric Wong <e@80x24.org>
-
- * vm_core.h (rb_vm_t): list_head and counter for living_threads
- (rb_thread_t): vmlt_node for living_threads linkage
- (rb_vm_living_threads_init): new function wrapper
- (rb_vm_living_threads_insert): ditto
- (rb_vm_living_threads_remove): ditto
- * vm.c (rb_vm_living_threads_foreach): new function wrapper
- * thread.c (terminate_i, thread_start_func_2, thread_create_core,
- thread_fd_close_i, thread_fd_close): update to use new APIs
- * vm.c (vm_mark_each_thread_func, rb_vm_mark, ruby_vm_destruct,
- vm_memsize, vm_init2, Init_VM): ditto
- * vm_trace.c (clear_trace_func_i, rb_clear_trace_func): ditto
- * benchmark/bm_vm_thread_close.rb: added to show improvement
- * ccan/build_assert/build_assert.h: added as a dependency of list.h
- * ccan/check_type/check_type.h: ditto
- * ccan/container_of/container_of.h: ditto
- * ccan/licenses/BSD-MIT: ditto
- * ccan/licenses/CC0: ditto
- * ccan/str/str.h: ditto (stripped of unused macros)
- * ccan/list/list.h: ditto
- * common.mk: add CCAN_LIST_INCLUDES
- [ruby-core:61871][Feature #9632 (part 1)]
-
-Sun May 11 01:10:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * signal.c (rb_f_kill): directly enqueue an ignored signal to self,
- except for SIGSEGV and SIGBUS. [ruby-dev:48203] [Bug #9820]
-
-Sat May 10 22:37:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (push_glob): match in UTF-8 on Mac OS X.
- [ruby-dev:48213] [Bug #9825]
-
-Sat May 10 13:32:18 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (thread_start_func_2): stop if forked in a sub-thread,
- the thread has become the main thread.
- [ruby-core:62070] [Bug #9751]
-
-Sat May 10 09:32:19 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * man/ruby.1: remove deadlink. [ruby-core:62145][Bug #9773]
-
-Sat May 10 08:47:36 2014 Tanaka Akira <akr@fsij.org>
-
- * signal.c (trap): Return "SYSTEM_DEFAULT" if SIG_DFL is set.
-
-Fri May 9 14:27:05 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (RUBY_SETJMP_TYPE): check for setjmp type after
- CCDLFLAGS is appended to CFLAGS, since __builtin_setjmp can be
- affected. [ruby-core:62469] [Bug #9818]
-
-Fri May 9 03:59:06 2014 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * lib/delegate.rb: Fix example of using delegator.
- patched from Andrey Koleshko. [Fixes GH-505]
-
-Fri May 9 03:42:43 2014 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * lib/shell.rb: add documentation in lib/shell.rb
- patched from reprah. [Fixes GH-516]
-
-Fri May 9 03:28:04 2014 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * lib/fileutils.rb: show fileutils require at top.
- patched from Richard Schneeman. [Fixes GH-604]
-
-Fri May 9 03:07:09 2014 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * lib/prime.rb (Prime#prime?): negative numbers can't be primes
- by definition. reported by Ivan Kataitsev. [Bug #7395]
- * test/test_prime.rb: add test.
-
-Thu May 8 14:34:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (rb_mod_init_copy): always clear instance variable,
- constant and method tables first, regardless the source tables.
- [ruby-dev:48182] [Bug #9813]
-
-Thu May 8 10:53:14 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: OpenBSD needs to include sys/param.h before include
- sys/mount.h. [ruby-dev:48167]
-
-Thu May 8 10:17:04 2014 Karsten Sperling <karsten@sperling.co.nz>
-
- * lib/webrick/httpserver.rb (WEBrick::HTTPServer#run): stop
- handling requests on shutdown, even if the socket is readable
- and IO.select() returns true. [Fixes GH-607]
-
- * lib/webrick/server.rb (WEBrick::GenericServer#start): IO.select()
- raises ENOTSOCK on shutdown on Windows.
-
-Wed May 7 21:45:00 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/openssl/lib/openssl/ssl.rb (OpenSSL::SSL::SSLServer#accept):
- Consider Socket#accept as well as TCPServer#accept.
- Reported by Sam Stelfox. [ruby-core:62064] [Bug #9750]
-
-Wed May 7 17:24:07 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (num_step_scan_args): check keyword arguments and fail
- if they conflict with positional arguments.
- [ruby-dev:48177] [Bug #9811]
-
-Wed May 7 12:06:14 2014 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/driver.rb: remove debug output and output results into
- specified file.
-
-Wed May 7 11:55:40 2014 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/driver.rb: add '--rawdata-output=[FILE] option to output
- raw results into FILE.
-
-Wed May 7 11:25:41 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (rb_f_local_variables): exclude variables hidden by
- shadowing. [ruby-core:60501] [Bug #9486]
-
- * vm.c (collect_local_variables_in_iseq): ditto.
-
-Tue May 6 23:29:05 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (new_bv_gen): no duplicated names, if already added in
- shadowing_lvar().
-
- * parse.y (local_tbl_gen): remove local variables duplicated with
- arguments.
- [ruby-core:60501] [Bug #9486]
-
-Tue May 6 18:48:50 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (Time.make_time): Adjust the time zone of "now".
-
-Tue May 6 18:33:12 2014 Tadayoshi Funaba <tadf@dotrb.org>
-
- * io.c (io_{read,write}_nonblock): use rb_get_kwargs instead of
- rb_hash_aref.
-
-Tue May 6 18:03:05 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (Time.make_time): Argument validation code moved from
- Time.parse and Time.strptime.
-
-Tue May 6 17:27:06 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (Time.parse): [DOC] Fix an example in the documentation
- to use EST.
- Reported by Marcus Stollsteimer.
- [ruby-core:60778] [Bug #9521] and [ruby-core:61718] [Bug #9682]
-
-Tue May 6 04:31:48 2014 Tadayoshi Funaba <tadf@dotrb.org>
-
- * file.c (rb_f_test): removed meaningless "case 'a'".
-
-Tue May 6 01:28:14 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/open-uri.rb (OpenURI.open_uri): Call StringIO#close only if
- the StringIO object is not closed yet.
- Reported by Jordi Massaguer Pla. [ruby-core:42538] [Bug #6010]
-
-Tue May 6 01:08:01 2014 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/driver.rb: define File::NULL if not defined and /dev/null
- is available to run benchmark driver on ruby 1.9.2.
-
-Mon May 5 23:53:24 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/mkconstants.rb: Add IP_TRANSPARENT.
- IP_TRANSPARENT is provieded since glibc-2.12.
- Reported by Eliezer Croitoru. [ruby-core:50372] [Bug #7476]
-
-Mon May 5 22:29:47 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (check_exec_redirect): Open the file in write mode for
- redirect from [:out, :err].
- Proposed and implemented by Yusuke Endoh.
- [ruby-dev:41430] [Feature #3348]
-
-Mon May 5 21:52:35 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/pathname/lib/pathname.rb (cleanpath_aggressive): make all
- separators File::SEPARATOR from File::ALT_SEPARATOR.
- Reported by Daniel Rikowski.
- Fixed by Nobuyoshi Nakada. [Bug #9618]
-
- * ext/pathname/lib/pathname.rb (cleanpath_conservative): ditto.
-
-Mon May 5 21:48:04 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/pathname/lib/pathname.rb (Pathname#/): Aliased to Pathname#+.
- Suggested by Alexey Muranov. [ruby-core:61432] [Feature #9625]
-
-Mon May 5 17:26:09 2014 Tadayoshi Funaba <tadf@dotrb.org>
-
- * math.c (rb_math_sqrt): omitted exporting an unused function,
- anyway.
- * internal.h: follows the above change.
-
-Mon May 5 11:44:03 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (Time.strptime): Raise ArgumentError if Date._strptime
- doesn't extract date information.
- Reported by tadayoshi funaba. [ruby-core:62349]
-
-Mon May 5 01:12:27 2014 Tadayoshi Funaba <tadf@dotrb.org>
-
- * ext/date/date_core.c (rt_rewrite_frags): a new feature (not a
- bug fix) of strptime. applies offset even if the given date is
- not local time (%s and %Q). This is an exceptional feature and
- I do NOT recommend to use this at all. Thank you git community.
-
-Sun May 4 20:51:32 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (Time.force_zone!): Use usual local time if it has
- expected offset from UTC.
-
-Sun May 4 17:58:12 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (Time.force_zone!): New private method.
- (Time.make_time): Use Time.force_zone!.
- (Time.strptime): Ditto.
- (Time.rfc2822): Ditto.
- (Time.xmlschema): Ditto.
-
- * lib/rss/rss.rb (Time.w3cdtf): Use Time.force_zone!.
-
-Sun May 4 10:22:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * math.c (math_atan2): return values like as expected by C99 if
- both two arguments are infinity. based on the patch by cremno
- phobia <cremno AT mail.ru> in [ruby-core:62310]. [Feature #9799]
-
-Sun May 4 03:46:42 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (Time.httpdate): Always return a UTC Time object.
-
-Sun May 4 03:26:39 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (Time.make_time): Refactored.
-
-Sun May 4 02:53:17 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (Time.rfc2822): Fix year completion.
- Produce fixed-offset time object if appropriate.
- (Time.xmlschema): Produce fixed-offset time object if appropriate.
-
-Sat May 3 23:52:20 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (make_time): Produce fixed-offset time object if
- appropriate.
- (Time.strptime): Use d[:zone] instead of d[:offset].
-
- * lib/rss/rss.rb (Time.w3cdtf): Produce fixed-offset time object if
- appropriate.
-
-Sat May 3 20:21:38 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (Time.strptime): Use d[:offset] if d[:seconds] is not
- given.
- Reported by tadayoshi funaba. [ruby-core:62322]
-
-Sat May 3 04:04:16 2014 Eric Wong <e@80x24.org>
-
- * complex.c (parse_comp): replace ALLOCA_N with ALLOCV_N/ALLOCV_END
- [Bug #9608]
- * rational.c (read_digits): ditto
-
-Sat May 3 00:06:30 2014 Naohisa Goto <ngotogenome@gmail.com>
-
- * file.c (HAVE_STRUCT_STATVFS_F_BASETYPE): File::Statfs#fstypename
- is supported on AIX, HP-UX, and Solaris, by using the value of
- struct statvfs.f_basetype.
-
- * configure.in (HAVE_STRUCT_STATVFS_F_BASETYPE): check struct
- statvfs.f_basetype which is available on AIX, HP-UX, and Solaris.
-
-Fri May 2 21:04:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (next_id): no reason to set ID_STATIC_SYM here, as ID
- returned by rb_intern3 can be a dynamic symbol and the static
- symbol flag is set otherwise. [Bug #9787]
-
-Fri May 2 11:32:51 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/ruby/test_io.rb (test_seek, test_seek_symwhence): defer
- File::Statfs#type call which may not be implemented, to mitigate
- errors on platforms where SEEK_DATA is available but f_type in
- struct statfs is not. [ruby-dev:48154] [Bug #9789]
-
-Fri May 2 10:37:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (rb_id_attrset): turn dynamically interned Symbol into
- an ID, since rb_str_dynamic_intern returns a Symbol but not an
- ID. [ruby-core:62226] [Bug #9787]
-
-Thu May 1 22:19:34 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * file.c: Change AND condition to nested condition.
-
-Thu May 1 00:36:26 2014 Naohisa Goto <ngotogenome@gmail.com>
-
- * file.c (FSTATFS): check availability of struct statfs and
- struct statvfs in addition to fstatfs(2) and fstatvfs(2).
- This fixes error in Solaris. [Bug #9788] [ruby-dev:48145]
-
-Wed Apr 30 19:46:23 2014 Narihiro Nakamura <authornari@gmail.com>
-
- * gc.c (gc_after_sweep): suppress unnecessary expanding heap.
- Tomb heap pages are freed pages here, so expanding heap is
- not required.
-
-Wed Apr 30 17:58:40 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm.c (invoke_block_from_c): add VM_FRAME_FLAG_BMETHOD to record
- it is bmethod frame.
-
- * vm.c (vm_exec): invoke RUBY_EVENT_RETURN event if rollbacked frame
- is VM_FRAME_FLAG_BMETHOD.
- [Bug #9759]
-
- * test/ruby/test_settracefunc.rb: add a test for TracePoint/set_trace_func.
-
- * vm_core.h: rename rb_thread_t::passed_me to
- rb_thread_t::passed_bmethod_me to clarify the usage.
-
- * vm_insnhelper.c (vm_call_bmethod_body): use renamed member.
-
-Wed Apr 30 17:06:49 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (rb_id_attrset): pin down dynamic symbol only. it is
- possible that attrset ID can be registered as a static symbol
- after the corresponding attrget ID has been registered as a
- dynamic, and then the latter may be collected.
- [ruby-core:62226] [Bug #9787]
-
-Tue Apr 29 14:17:57 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/tmpdir.rb: Rescue LoadError on etc.so for miniruby.
- Revert r45707, r45711, r45717.
-
-Tue Apr 29 12:50:02 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/fileutils.rb: Don't need to define fu_get_gid and fu_get_gid in
- rescue LoadError on 'etc'.
-
-Tue Apr 29 10:21:38 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * parse.y (symbols_i): like r45492, call rb_gc_resurrect().
-
-Tue Apr 29 04:29:05 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * file.c (HAVE_STRUCT_STATFS_T_F_FSTYPENAME): Add new macro for
- statfs_t.
- * file.c (HAVE_STRUCT_STATFS_T_F_TYPE): ditto.
-
- * file.c (rb_io_statfs): check FSTATFS macro only instead of
- HAVE_FSTATFS and HAVE_FSTATVFS.
-
- * file.c (statfs_type): use new macro.
- * file.c (statfs_fstypename): ditto.
- * file.c (statfs_inspect): ditto.
-
-Tue Apr 29 00:20:26 2014 Rajarshi Das <rajarshid@cybage.com>
-
- * bootstraptest/test_literal.rb: fix typo of "dynamic". [ci skip]
-
- * regexp.rdoc: fix typo of "organized". [ci skip]
-
- * lib/session.rb: fix typo of "recognized". [ci skip]
-
-Mon Apr 28 21:40:27 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in (HAVE_STRUCT_STATFS_F_TYPE): check struct statfs.f_type
- to support OpenBSD.
-
- * file.c (statfs_type): use above macro to switch.
-
- * file.c (statfs_inspect): ditto.
-
-Mon Apr 28 18:06:08 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: check struct statvfs and struct statvfs.f_fstypename.
-
- * configure.in: on NetBSD fstatfs is obsoleted.
-
- * file.c: support NetBSD for File::Statfs.
-
-Mon Apr 28 17:42:42 2014 Narihiro Nakamura <authornari@gmail.com>
-
- * gc.c: This argument must be a pointer.
-
-Mon Apr 28 17:40:15 2014 Narihiro Nakamura <authornari@gmail.com>
-
- * gc.c: Fix typos. These are undefined variables.
-
-Sun Apr 27 19:39:42 2014 Tadayoshi Funaba <tadf@dotrb.org>
-
- * ext/date/date_strptime.c (date__strptime_internal): do not
- overwrite century.
-
-Sat Apr 26 11:50:08 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/ruby/test_enum.rb (test_flat_map): Added test for flat_map.
- Contribute from @igaiga. [fix GH-598]
-
-Sat Apr 26 10:55:33 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (compile_array_): make copy a first hash not to modify
- the argument itself. keyword splat should be non-destructive.
- [ruby-core:62161] [Bug #9776]
-
-Sat Apr 26 08:05:36 2014 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_process.rb (test_rlimit_nofile): Don't limit
- RLIMIT_NOFILE too small.
- This fix sporadic "[ASYNC BUG] thread_timer: select" on GNU/Linux.
-
-Fri Apr 25 22:54:34 2014 Naohisa Goto <ngotogenome@gmail.com>
-
- * lib/fileutils.rb (rmdir): rescue Errno::EEXIST in addition to
- ENOTEMPTY (and ENOENT), because SUSv3 describes that "If the
- directory is not an empty directory, rmdir() shall fail and set
- errno to [EEXIST] or [ENOTEMPTY]" and Solaris uses EEXIST.
- [Bug #9571] [ruby-dev:48017]
-
-Fri Apr 25 19:16:30 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/webrick/utils.rb: Don't rescue LoadError for 'etc' extension.
-
-Fri Apr 25 14:55:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (rb_cv_func___builtin_unreachable): try with an
- external variable not only by a warning, which might not be
- shown due to the optimization. [ruby-core:61647] [Bug #9665]
-
-Fri Apr 25 13:11:49 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: NetBSD's ksh, used by configure, needs escapes.
-
-Fri Apr 25 12:51:08 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: correct pthread_setname_np's prototype on NetBSD.
- [Bug #9586]
-
-Thu Apr 24 23:17:25 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * lib/fileutils.rb (fu_get_uid, fu_get_gid): Etc.getpwnam/getgrnam may
- returns nil.
-
- * lib/webrick/utils.rb (su): ditto.
-
-Thu Apr 24 22:55:22 2014 Tanaka Akira <akr@fsij.org>
-
- * bootstraptest/test_io.rb: Add etc.so to $" before require 'tmpdir'.
-
-Thu Apr 24 21:09:55 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * man/ruby.1: fix broken link.
-
-Thu Apr 24 20:53:02 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/tmpdir.rb: Don't need to rescue LoadError for etc.so.
-
-Thu Apr 24 17:39:53 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * file.c (statfs_inspect): suppress warnings.
- assume those values won't be larger than LONG_LONG_MAX.
-
-Thu Apr 24 11:53:28 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/openssl/ossl_asn1.c (ossl_asn1_initialize): SYMID on a value
- other than Symbol is an undefined behavior. fix up r31699.
- [ruby-core:62142] [Bug #9771]
-
-Thu Apr 24 11:21:37 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (rb_sym2id, rb_sym2id_without_pindown): return 0 for
- non-symbol values, for the time being.
-
-Thu Apr 24 05:50:13 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * parse.y (dsym_node_gen): like r45492, call rb_gc_resurrect().
-
-Wed Apr 23 20:36:22 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/etc/extconf.rb: Build ext/etc unconditionally.
-
-Wed Apr 23 14:10:50 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * file.c (statfs_fsid): remove statfs.f_fsid because it doesn't return
- meaningful value portably. http://togetter.com/li/658517
-
-Wed Apr 23 11:03:41 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/stringio/stringio.c (strio_write): use rb_str_append to
- reuse coderange bits other than ASCII-8BIT, and keep
- taintedness. [ruby-dev:48118] [Bug #9769]
-
-Wed Apr 23 00:43:00 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c, include/ruby/win32.h (ustatfs): implementation of
- statfs(2) clone. [EXPERIMENTAL]
-
- * file.c (rb_io_statfs): use above function.
-
- * configure.in, win32/Makefile.sub (struct statfs): available.
-
-Tue Apr 22 23:56:24 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * file.c (rb_io_stafs): use statfs(2) if fstatfs(2) is unavailable.
-
- * configure.in (fstatfs): check it.
-
-Tue Apr 22 22:15:51 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * file.c (rb_io_statfs): need to define even if the system doesn't have
- fstatfs(2).
-
- * test/ruby/test_file.rb (TestFile#test_statfs): skip if IO#stafs is not
- implemented.
-
-Tue Apr 22 19:32:48 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * file.c: newly added a class File::Statfs. (experimental)
-
-Tue Apr 22 08:22:33 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (objspace_malloc_increase): don't cause GC by malloc_increase
- when memop type is MEMOP_TYPE_REALLOC.
-
- GC at realloc is not well maintained.
- We need a time to make it safe.
- [ruby-dev:48117]
-
-Tue Apr 22 06:54:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (objspace_malloc_increase): run full mark if 0x04 bit is
- set in ruby_gc_stress. [ruby-core:62103] [Feature #9761]
-
- * gc.c (objspace_malloc_increase): run GC after realloc not only
- malloc and calloc by GC.stress. [ruby-core:62103] [Feature #9761]
-
-Mon Apr 21 19:12:20 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (rb_str_coderange_scan_restartable): coderange is always
- ENC_CODERANGE_VALID if the string is ASCII-8BIT and already has a non
- ASCII character.
-
-Mon Apr 21 19:02:44 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (coderange_scan): remove useless condition `p < e` after
- search_nonascii.
-
- * string.c (rb_str_coderange_scan_restartable): ditto.
-
-Mon Apr 21 18:55:21 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/-test-/string/coderange.c: add Bug::String.new#coderange_scan
- to explicitly scan coderange.
-
-Mon Apr 21 18:19:35 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (coderange_scan): remove unused logic.
-
- * string.c (rb_str_coderange_scan_restartable): ditto.
-
-Mon Apr 21 14:11:48 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/stringio/stringio.c (strio_putc): fix for non-ascii
- encoding, like as IO#putc. [ruby-dev:48114] [Bug #9765]
-
-Sun Apr 20 12:57:15 2014 Masaya Tarui <tarui@ruby-lang.org>
-
- * st.c (st_foreach_check): change start point of search at check
- from top to current. [ruby-dev:48047] [Bug #9646]
-
-Sun Apr 20 08:41:33 2014 Andrew DeMaria <ademariad@gmail.com>
-
- * lib/mkmf.rb (link_command, libpathflag, create_makefile): prefer
- user specified `$LIBPATH` than `$DEFLIBPATH`. [ruby-core:62100]
- [ruby-trunk - Bug #9760]
-
-Sun Apr 20 06:01:18 2014 Eric Wong <e@80x24.org>
-
- * gc.c (rb_gc_writebarrier): drop special case for big hash/array
- [Bug #9518]
-
-Sat Apr 19 15:38:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (primary): flush cmdarg flags inside left-paren in a
- command argument, to allow parenthesed do-block as an argument
- without arguments parentheses. [ruby-core:61950] [Bug #9726]
-
-Sat Apr 19 10:07:24 2014 Tanaka Akira <akr@fsij.org>
-
- * internal.h (struct RBignum): Use size_t for len.
-
- * include/ruby/intern.h (rb_big_new): Use size_t instead of long to
- specify the size of bignum.
- (rb_big_resize): Ditto.
-
- * bignum.c: Follow above changes.
-
- * rational.c: Follow above changes.
-
- * marshal.c: Follow above changes.
-
-Sat Apr 19 00:32:07 2014 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_num2long): Returns a long.
- (rb_num2ulong): Returns a unsigned long.
-
- * bignum.c (rb_big2long): Returns a long.
- (rb_big2ulong): Returns a unsigned long.
-
- * include/ruby/intern.h: Follow above changes.
-
- * include/ruby/ruby.h: Follow above changes.
- (rb_num2long_inline): No need to cast.
- (rb_num2ulong_inline): Ditto.
-
-Sat Apr 19 00:17:20 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (SHARABLE_SUBSTRING_P): predicate if substring can be
- shared with the original string. true if just at the end of the
- original string, for the time being. all substring will be able to
- be shared in the future.
-
-Fri Apr 18 21:48:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_new_frozen): consider the shared string at
- middle.
-
- * string.c (rb_str_subseq, rb_str_substr, str_byte_substr): share
- middle of a string.
-
-Fri Apr 18 15:40:05 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c: use uintptr_t instead of VALUE because they are not ruby
- object.
-
-Fri Apr 18 14:51:42 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c: check str_strlen's argument, and add comment or
- use NULL if simply it uses str's enc.
-
-Fri Apr 18 14:32:40 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (str_strlen): use enc_strlen if the coderange is known.
-
-Fri Apr 18 14:21:21 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (enc_strlen): move UTF-8 optimization from str_strlen to
- enc_strlen.
-
-Fri Apr 18 08:50:18 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (rb_cv_getcwd_malloc): check if getcwd allocates
- buffer if NULL is given [ruby-core:62072] [Bug #9752]
-
-Thu Apr 17 16:28:10 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * prelude.rb: [DOC] Update Thread::exclusive docs by @stevenharman.
-
-Thu Apr 17 10:03:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/fileutils.rb (FileUtils#copy_entry): update rdoc about
- preserve option and permissions, following r31123.
- [ruby-core:62065] [Bug #9748]
-
-Wed Apr 16 23:47:36 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enum.c (dont_recycle_block_arg): fix condition to recycle block
- argument. lambda with rest can get internal array directly.
- [ruby-core:62060] [Bug #9749]
-
-Wed Apr 16 09:51:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/openssl/ossl_pkey.c (ossl_pkey_verify): as EVP_VerifyFinal()
- finalizes only a copy of the digest context, the context must be
- cleaned up after initialization by EVP_MD_CTX_cleanup() or a
- memory leak will occur. [ruby-core:62038] [Bug #9743]
-
-Tue Apr 15 19:36:42 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * include/ruby/win32.h (rb_w32_cmdvector): removed.
-
- * win32/win32.c (rb_w32_sysinit): use WCHAR version of GetCommandLine()
- internally.
-
- * win32/win32.c (w32_cmdvector): renamed from rb_w32_cmdvector. use
- WCHAR* instead of char* internally.
-
- these changes are expected to not changing the behavior yet.
-
-Tue Apr 15 19:26:05 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/extmk.rb: Re-generate extmk.mk and dummy makefiles only if
- really required.
- This fixes a problem to run multiple test-all concurrently as:
- make test-all & make test-all & make test-all & ...
-
-Tue Apr 15 12:49:53 2014 Sam Rawlins <sam.rawlins@gmail.com>
-
- * enum.c (enum_each_slice, enum_each_cons): make more efficient by
- allocating less and recycling block argument arrays if possible.
- [Fixes GH-596]
-
-Mon Apr 14 18:44:45 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (fill_lines): get base addrs in fill_lines to use it
- with dladdr_fbases introduced at r45563.
- it didn't get before if the executable is not pie.
-
-Mon Apr 14 18:05:48 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (main_exe_path): support FreeBSD.
- At least sh, csh, tcsh, bash, and zsh sets realpath of the main
- executable for dladdr, but gdb doesn't.
-
-Mon Apr 14 17:20:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (umethod_bind): use the ancestor iclass instead of new
- iclass to get rid of infinite recursion, if the defined module
- is already included. [ruby-core:62014] [Bug #9721]
-
-Sun Apr 13 12:46:58 2014 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (SIZEOF_BDIGIT): Renamed from SIZEOF_BDIGITS.
-
- * internal.h: Ditto.
-
- * marshal.c: Ditto.
-
- * rational.c: Ditto.
-
-Sun Apr 13 10:18:09 2014 Tanaka Akira <akr@fsij.org>
-
- * common.mk: Unused target, $(MKMAIN_CMD), removed.
-
- * Makefile.in (MKMAIN_CMD): Unused macro removed.
-
- * win32/Makefile.sub (MKMAIN_CMD): Ditto.
-
-Sat Apr 12 22:11:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (sym_to_proc), proc.c (rb_block_clear_env_self): clear
- caller's self which is useless, so that it can get collected.
- [Fixes GH-592]
-
-Sat Apr 12 09:26:48 2014 Eric Hodel <drbrain@segment7.net>
-
- * ext/openssl/ossl_ocsp.c: [DOC] Document OpenSSL::OCSP.
-
-Fri Apr 11 18:52:38 2014 Koichi Sasada <ko1@atdot.net>
-
- * array.c (ARY_SET): added.
-
- ARY_SET() is same functionality of RARRAY_ASET(), but
- it has an assertion (`ary' doesn't have shared array).
-
-Fri Apr 11 16:54:26 2014 Koichi Sasada <ko1@atdot.net>
-
- * array.c: make shared arrays WB-protected objects.
-
- Shared arrays were WB-unprotected object because
- sharing array can modify shared array's buffer
- if it occupied shared array.
-
- [sharing array (ary)] -> [shared array (shared)] -> <buff>
- | A
- +---------------------------------------+
- write `buff' with WB(ary, &buff[i], obj)
- -> if `ary' and `shared' are old, then only `ary'
- will be remembered.
- -> traverse from `ary'. But `shared' is old, so
- that written `obj' is not marked.
-
- It cause WB miss so that shared arrays were WB-unprotected.
- (WB-unprotected objects are marked everytime if it is living)
-
- This patch insert WB() for `shared' if it is needed.
-
-Fri Apr 11 15:05:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (rb_method_call_with_block, umethod_bind): call with
- IClass including the module for a module instance method.
- [ruby-core:61936] [Bug #9721]
-
- * vm_insnhelper.c (vm_search_super_method): allow bound
- UnboundMethod case.
-
-Fri Apr 11 12:02:30 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (rb_dump_backtrace_with_lines): set base address
- which is retrieved from dladdr to dladdr_fbases, to skip already
- parsed objects.
-
-Fri Apr 11 12:44:50 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (ary_reject): may be turned into a shared array during
- the given block. [ruby-dev:48101] [Bug #9727]
-
-Thu Apr 10 23:41:21 2014 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/net/ftp.rb (Net::FTP#login): [DOC] The default password for
- anonymous login was changed to "anonymous@" in r25313.
-
-Thu Apr 10 19:22:58 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_array.rb: remove useless `assert'.
-
-Thu Apr 10 19:11:11 2014 Koichi Sasada <ko1@atdot.net>
-
- * array.c (rb_ary_modify): remember shared array owner if a shared
- array owner is promoted and a shared array is not promoted.
-
- Now, shared array is WB-unprotected so that shared arrays are not
- promoted. All objects referred from shared array should be marked
- correctly.
-
- [ruby-core:61919] [ruby-trunk - Bug #9718]
-
- * test/ruby/test_array.rb: add a test for above.
-
-Thu Apr 10 18:57:12 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_verify_internal_consistency): move lines and enable
- allrefs_dump() on RGENGC_CHECK_MODE >= 4.
-
-Thu Apr 10 15:01:06 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (append_obj): clear allocated memory.
-
- * addr2line.c (rb_dump_backtrace_with_lines): free `base_addrs'.
-
-Thu Apr 10 14:40:18 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_gc_writebarrier_unprotect_promoted): disable to dump debug
- message when RGENGC_CHECK_MODE == 0.
-
-Thu Apr 10 08:13:47 2014 Tanaka Akira <akr@fsij.org>
-
- * signal.c (check_stack_overflow): Don't use ucontext_t if ucontext.h
- is not available.
- Fixes build on Android (x86).
-
-Wed Apr 9 23:22:44 2014 Tanaka Akira <akr@fsij.org>
-
- * gc.c (mark_current_machine_context): Call SET_STACK_END.
- This reverts a hunk of r40703 by ko1.
- This fixes [ruby-dev:48098] [Bug #9717].
-
-Wed Apr 9 21:02:04 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (OBJ2UID1): Defined even if getpwnam_r is not usable.
- (OBJ2GID1): Defined even if getgrnam_r is not usable.
- This fixes compilation error on Android.
-
-Wed Apr 9 15:16:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * encoding.c (rb_enc_default_internal): fix rdoc. `__FILE__` is
- in filesystem encoding but not `default_internal`.
- [ruby-core:61894] [Bug #9713]
-
-Wed Apr 9 14:43:00 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_gc.rb: more long timeout.
- This test failed under RGENGC_CHECK_MODE >= 2.
-
-Wed Apr 9 13:07:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: get rid of __builtin_setjmp/__builtin_longjmp on
- x64-mingw, which causes SEGV with callcc.
- [ruby-core:61887] [Bug #9710]
-
-Wed Apr 9 12:44:54 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (str_buf_cat): should round up the capacity by 4KiB,
- but not number of rooms. [ruby-core:61886] [Bug #9709]
-
-Tue Apr 8 22:55:32 2014 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/mkmf.rb (MakeMakefile#dir_config): [DOC] Improve
- documentation.
-
-Tue Apr 8 22:31:44 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename `RGENGC_THREEGEN' to `RGENGC_AGE2_PROMOTION'.
-
- * gc.c (rgengc_rememberset_mark): don't promote, but remain in
- remember set for infant objects.
-
- * gc.c (RVALUE_PROMOTE_INFANT, RVALUE_PROMOTE_YOUNG): count numbers
- in these functions.
-
-Mon Apr 7 21:11:49 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/socket.c (sock_s_getnameinfo): Save errno for EAI_SYSTEM.
- Reported by Saravana kumar. [ruby-core:61820] [Bug #9697]
- Fixed by Heesob Park. [ruby-core:61868]
-
-Mon Apr 7 07:20:23 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/xmlrpc/client.rb (do_rpc): don't check body length.
- If HTTP content-encoding is used, the length may be different.
- [Bug #8182] [ruby-core:53811]
-
-Mon Apr 7 02:39:48 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/matrix.rb: Add Matrix#cofactor [fix GH-568]
- Add first_minor [fix GH-568]
- Handle empty diagonal matrix case [fix GH-576]
- Patches by gogotanaka
-
-Sun Apr 6 08:52:50 2014 Bugra Barin <bugrabarin@hotmail.com>
-
- * dln.c (dln_load): use wchar version to load a library in
- non-ascii path on Windows. based on the patch by Bugra Barin
- <bugrabarin AT hotmail.com> in [ruby-core:61845]. [Bug #9699]
-
-Sat Apr 5 19:36:33 2014 Tadayoshi Funaba <tadf@dotrb.org>
-
- * ext/date/date_core.c (d_lite_cmp): should compare with #<.
-
-Sat Apr 5 00:31:21 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/readline/extconf.rb (rl_hook_func_t): check pointer type.
- [ruby-dev:48089] [Bug #9702]
-
-Fri Apr 4 07:13:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (ac_cv_func___builtin_setjmp): should not skip
- flags restoration in RUBY_WERROR_FLAG by `break`.
- [ruby-dev:48086] [Bug #9698]
-
-Wed Apr 2 21:50:06 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (ac_cv_func___builtin_setjmp): __builtin_longjmp()
- in Apple LLVM 5.1 (LLVM 3.4svn) uses `void**`, not `jmp_buf`.
- [Bug #9692]
-
-Wed Apr 2 20:57:15 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c, gc.h (rb_objspace_each_objects_without_setup):
- Add a new (hidden) C-API to iterate objspace snapshot.
-
- This API is not safe to call any C-APIs in a given callback
- function. Be careful to use this C-API.
-
-Wed Apr 2 17:43:17 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (ac_cv_func___builtin_setjmp): gcc 4.9 disallows a
- variable as the second argument of __builtin_longjmp().
- [ruby-core:61800] [Bug #9692]
-
-Wed Apr 2 15:12:18 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * common.mk: Use redmine-2.x url for DeveloperHowto wiki.
- [ruby-core:60657] [Bug #9511]
-
-Wed Apr 2 11:46:29 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * ext/pathname/lib/pathname.rb (Pathname#join): Fix error with
- empty args. Reported by ko1 via IRC.
-
- * test/pathname/test_pathname.rb (TestPathname#test_join): Add the
- test for above case.
-
-Tue Apr 1 11:39:57 2014 James Edward Gray II <james@graysoftinc.com>
-
- * lib/csv.rb: Symbol HeaderConverter: strip leading/trailing space.
- Reported by Skye Shaw
- [Fixes GH-575]
-
-Tue Apr 1 11:34:04 2014 James Edward Gray II <james@graysoftinc.com>
-
- * lib/csv.rb: Don't attempt to convert nil headers.
- Reported by Skye Shaw
-
-Tue Apr 1 17:29:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/config_files.rb (ConfigFiles.download): show failed URI.
- [ruby-core:61792] [Bug #9690]
-
-Tue Apr 1 12:06:49 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (rb_dump_backtrace_with_lines): don't depend hard coded
- symbol '_start'.
-
- * addr2line.c (fill_lines): instead of above, get a dynamic symbol
- in the main executable and use it to know the base address.
-
- * addr2line.c (follow_debuglink0): use obj_info_t instead of
- line_info_t to handle object related data.
-
- * addr2line.c (main_exe_path): defined for Linux.
-
-Tue Apr 1 08:58:39 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * parse.y (rb_str_dynamic_intern): set mark bit if dynamic symbol
- is before sweeping.
-
-Tue Apr 1 07:37:00 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (fill_lines): use dynsym, which is used for dynamic
- linking and always exists, if there's no symtab.
-
-Tue Apr 1 07:27:15 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_dump.c (rb_print_backtrace): current implementation
- uses dladdr to get the path of objects.
-
-Mon Mar 31 23:57:45 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/readline/extconf.rb: fix typo, `$defs` not `$DEFS`.
- [ruby-core:61756] [Bug #9578]
-
-Mon Mar 31 17:23:50 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/ruby/memory_status.rb: require envutil before accessing EnvUtil
- module. reported by ko1 via twitter.
-
-Mon Mar 31 10:28:01 2014 Eric Wong <e@80x24.org>
-
- * st.c (st_init_table_with_size): update comment
- [Feature #9425]
-
-Sun Mar 30 23:39:26 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (rb_w32_accept, open_ifs_socket, socketpair_internal):
- reset inherit flag of socket to avoid unintentional inheritance of
- socket. note that the return value of SetHandleInformation() is not
- verified intentionally because old Windows may return an error.
- [Bug #9688] [ruby-core:61754]
-
-Sat Mar 29 13:04:22 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_before_sweep): cap `malloc_limit' to
- gc_params.malloc_limit_max. It can grow and grow with such case:
- `loop{"a" * (1024 ** 2)}'
- [Bug #9687]
-
- This issue is pointed by Tim Robertson.
- http://www.omniref.com/blog/blog/2014/03/27/ruby-garbage-collection-still-not-ready-for-production/
-
-Fri Mar 28 19:32:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * struct.c (not_a_member): extract name error and use same error
- messages. based on the patch by Marcus Stollsteimer <sto.mar AT
- web.de> at [ruby-core:61721]. [Bug #9684]
-
-Fri Mar 28 09:21:54 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * ext/psych/psych.gemspec: update gemspec for psych-2.0.5
-
-Fri Mar 28 09:11:06 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * ext/psych/lib/psych.rb: Merge psych-2.0.5. bump version to
- libyaml-0.1.6 for CVE-2014-2525.
- * ext/psych/yaml/config.h: ditto.
- * ext/psych/yaml/scanner.c: ditto.
- * ext/psych/yaml/yaml_private.h: ditto.
-
-Thu Mar 27 18:58:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * re.c (match_regexp): set regexp for MatchData from string.
-
- * re.c (rb_backref_set_string): create MatchData from string and
- set backref.
-
- * string.c (rb_pat_search, rb_str_sub, rb_str_sub_bang, str_gsub),
- (scan_once, rb_str_scan, rb_str_partition): use rb_str_index
- instead of rb_reg_search() when pattern is a String. based on
- the patch by Sam Rawlins <sam.rawlins@gmail.com> [Fixes GH-579]
-
-Thu Mar 27 11:58:55 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (fill_lines): check shdr[i].sh_type because even if
- .symtab section exists, the section's type can be SHT_NOBITS and
- actual data doesn't exist in the file.
- revert r45441.
-
-Wed Mar 26 14:57:35 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * parse.y: inline must be static (for mswin).
- fixed build error introduced at r45426.
-
-Wed Mar 26 14:33:00 2014 Narihiro Nakamura <authornari@gmail.com>
-
- * internal.h (USE_SYMBOL_GC): enable Symbol GC by default (USE_SYMBOL_GC == 1).
-
-Tue Mar 25 22:57:11 2014 Narihiro Nakamura <authornari@gmail.com>
-
- * parse.y: support Symbol GC. [ruby-trunk Feature #9634]
- See this ticket about Symbol GC.
-
- * include/ruby/ruby.h:
- Declare few functions.
- * rb_sym2id: almost same as old SYM2ID but support dynamic symbols.
- * rb_id2sym: almost same as old ID2SYM but support dynamic symbols.
- * rb_sym2str: almost same as `rb_id2str(SYM2ID(sym))` but not
- pin down a dynamic symbol.
- Declare a new struct.
- * struct RSymbol: represents a dynamic symbol as object in
- Ruby's heaps.
- Add few macros.
- * STATIC_SYM_P: check a static symbol.
- * DYNAMIC_SYM_P: check a dynamic symbol.
- * RSYMBOL: cast to RSymbol
-
- * gc.c: declare RSymbol. support T_SYMBOL.
-
- * internal.h: Declare few functions.
- * rb_gc_free_dsymbol: free up a dynamic symbol. GC call this
- function at a sweep phase.
- * rb_str_dynamic_intern: convert a string to a dynamic symbol.
- * rb_check_id_without_pindown: not pinning function.
- * rb_sym2id_without_pindown: ditto.
- * rb_check_id_cstr_without_pindown: ditto.
-
- * string.c (Init_String): String#intern and String#to_sym use
- rb_str_dynamic_intern.
-
- * template/id.h.tmpl: use LSB of ID as a flag for determining a
- static symbol, so we shift left other ruby_id_types.
-
- * string.c: use rb_sym2str instead `rb_id2str(SYM2ID(sym))` to
- avoid pinning.
-
- * load.c: use xx_without_pindown function at creating temporary ID
- to avoid pinning.
-
- * object.c: ditto.
-
- * sprintf.c: ditto.
-
- * struct.c: ditto.
-
- * thread.c: ditto.
-
- * variable.c: ditto.
-
- * vm_method.c: ditto.
-
-Wed Mar 26 13:25:54 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (fill_lines): loop reverse order not to overwrite
- the basis of base addresses comparison.
-
- * addr2line.c: use uintptr_t instead of intptr_t for pointers.
-
- * addr2line.c (rb_dump_backtrace_with_lines): don't use syms.
-
- * vm_dump.c (rb_print_backtrace): ditto.
-
- * addr2line.h: ditto.
-
-Wed Mar 26 11:20:50 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * marshal.c (w_object): internal objects are not dumpable.
- [ruby-core:61677] [Bug #9674]
-
- * ext/thread/thread.c (undumpable): ConditionVariable and Queue
- are not dumpable. [ruby-core:61677] [Bug #9674]
-
-Wed Mar 26 10:36:39 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (follow_debuglink): show message if it closes opened
- (and maybe used) elf binary.
-
-Wed Mar 26 10:34:25 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (fill_line): pass and use offset instead of
- curobj_baseaddr.
-
-Wed Mar 26 09:07:48 2014 Yutaka Kanemoto <kanemoto@ruby-lang.org>
-
- * configure.in: add --disable-pie. [Feature #9673]
-
-Wed Mar 26 08:47:04 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (fill_lines): don't run fill_lines multiple times.
-
-Wed Mar 26 08:45:00 2014 Sam Rawlins <sam.rawlins@gmail.com>
-
- * internal.h: add prototype for rb_reg_search0
-
- * re.c: rename rb_reg_search to rb_reg_search0, add set_backref_str
- argument to allow callers to indicate that they don't require the
- backref string to be allocated.
-
- * string.c: don't allocate backref str if replacement string is provided
-
- [GH-578] [Bug #9676] [ruby-core:61682]
-
-Wed Mar 26 08:29:43 2014 mo khan <mo@mokhan.ca>
-
- * lib/rubygems.rb: fix spelling of Jim Weirich. [Fixes GH-577]
-
-Wed Mar 26 01:55:45 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (rb_dump_backtrace_with_lines): a function to get must
- be a function in the main executable, whose absolute path is not
- available by dladdr, and ruby get it by /proc/self/exe on Linux.
-
-Wed Mar 26 01:34:50 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (fill_lines): skip if path is NULL.
-
-Tue Mar 25 23:57:17 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_yylex): only a newline after label should be
- significant. [ruby-core:61658] [Bug #9669]
-
-Tue Mar 25 23:32:25 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * ext/pathname/lib/pathname.rb (Pathname#join): remove unnecessary
- unshift.
-
- * test/pathname/test_pathname.rb (TestPathname#test_join): add tests.
-
-Tue Mar 25 16:47:36 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (lex_state_e, parser_params, f_arglist, parser_yylex):
- separate EXPR_LABELARG from EXPR_BEG and let newline significant,
- so that required keyword argument can place at the end of
- argument list without parentheses. [ruby-core:61658] [Bug #9669]
-
-Mon Mar 24 22:19:56 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (ripper_initialize): filename can not be modified.
-
-Mon Mar 24 15:19:47 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (rb_dump_backtrace_with_lines): fetch path of the
- executable from /proc/self/exe on Linux.
-
-Mon Mar 24 14:14:37 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * gc.c: Fix up default GC params by @csfrancis [fix GH-556]
-
-Mon Mar 24 13:13:36 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (parse_debug_line_cu): explicitly specify signed char
- because DWARF's line_Base is signed char and char maybe unsigned.
- patched by Rei Odaira. [ruby-dev:48068] [Bug #9654]
-
-Sun Mar 23 11:03:50 2014 Kohei Suzuki <eagletmt@gmail.com>
-
- * vm_method.c (rb_method_entry_get_without_cache): me->klass is 0
- for a method aliased in a module. [ruby-core:61636] [Bug #9663]
-
-Sun Mar 23 08:12:27 2014 Eric Wong <e@80x24.org>
-
- * st.c (hash_pos): use bitwise AND to avoid slow modulo op
- (new_size): power-of-two sizes for hash_pos change
- (st_numhash): adjust for common keys due to lack of prime modulo
- [Feature #9425]
- * hash.c (rb_any_hash): right shift for symbols
- * benchmark/bm_hash_aref_miss.rb: added to show improvement
- * benchmark/bm_hash_aref_sym_long.rb: ditto
- * benchmark/bm_hash_aref_str.rb: ditto
- * benchmark/bm_hash_aref_sym.rb: ditto
- * benchmark/bm_hash_ident_num.rb: added to prevent regression
- * benchmark/bm_hash_ident_obj.rb: ditto
- * benchmark/bm_hash_ident_str.rb: ditto
- * benchmark/bm_hash_ident_sym.rb: ditto
-
-Sat Mar 22 22:56:45 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (fill_lines): compare the file names of object in which
- symbols exist. [Bug #9654] [ruby-dev:48058]
-
-Sat Mar 22 06:46:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/cgi/util.rb (escape_html, unescape_html): make synonyms
- aliases instead of wrapper methods.
-
- * lib/cgi/util.rb (escape_element, unescape_element): ditto.
- [Fixes GH-573]
-
-Fri Mar 21 21:57:34 2014 Akinori MUSHA <knu@iDaemons.org>
-
- * configure.in: Fix a build problem with clang and --with-opt-dir.
- If ruby is configured with --with-opt-dir=dir when using clang
- as compiler, a warning `clang: warning: argument unused during
- compilation: '-I dir'` is emitted almost every time clang
- compiles a file. Unfortunately, RUBY_CHECK_PRINTF_PREFIX takes
- any output from the compiler as fatal error, and the check thus
- fails due to the warning. This is an attempt to fix the problem
- by adding a flag -Qunused-arguments to CFLAGS locally in the
- function to suppress the warning. [ruby-dev:48062] [Bug #9658]
- [Fixes GH-571] https://github.com/ruby/ruby/pull/571
-
-Fri Mar 21 16:31:56 2014 Zachary Scott <e@zzak.io>
-
- * gc.c: [DOC] Fix call-seq for GC.start by @jasonrclark [Fixes GH-572]
- https://github.com/ruby/ruby/pull/572
-
-Thu Mar 20 11:37:28 2014 James Edward Gray II <james@graysoftinc.com>
-
- * lib/csv.rb: Fixed a broken regular expression that was causing
- CSV to miss escaping some special meaning characters when used
- in parsing.
- Reported by David Unric
- [ruby-core:54986] [Bug #8405]
-
-Thu Mar 20 16:53:07 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (objspace_malloc_increase): should not invoke
- garbage_collect_with_gvl() here on non-ruby threads.
-
- Should just ignore the malloc_increase.
-
- This issue is pointed by Eric Wong [ruby-core:61519].
-
-Thu Mar 20 13:05:16 2014 Koichi Sasada <ko1@atdot.net>
-
- * struct.c (rb_struct_alloc): use RARRAY_CONST_PTR() instead of
- RARRAY_PTR().
-
-Thu Mar 20 12:59:39 2014 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/intern.h (rb_obj_call_init, rb_class_new_instance):
- constify a parameter (VALUE *).
- I believe this incompatibility doesn't break any code.
- However, if you have trouble, please tell us.
-
- * eval.c, object.c: ditto.
-
-Thu Mar 20 12:31:26 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_method.c (rb_method_entry_get_without_cache): get rid of
- infinite recursion at aliases in a subclass and a superclass.
- return actually defined class for other than singleton class.
- [ruby-core:60431] [Bug #9475]
-
-Wed Mar 19 17:13:06 2014 Eric Wong <e@80x24.org>
-
- * time.c (time_mload): freeze and preserve marshal-loaded time zone
- * test/ruby/test_time.rb: add test for GC on loaded object
- [Bug #9652]
-
-Tue Mar 18 23:20:12 2014 Shota Fukumori <her@sorah.jp>
-
- * vm_eval.c (eval_string_with_cref): Unify to use NIL_P.
-
-Tue Mar 18 22:03:41 2014 Shota Fukumori <her@sorah.jp>
-
- * vm_eval.c (eval_string_with_cref): Use file path even if scope is
- given. Related to [ruby-core:56099] [Bug #8662] and r42103.
-
-Mon Mar 17 13:17:47 2014 Koichi Sasada <ko1@atdot.net>
-
- * enumerator.c (enumerator_block_call): use RARRAY_CONST_PTR()
- instead of RARRAY_PTR().
-
- * io.c (rb_io_s_popen): ditto.
-
- * numeric.c (num_step_size): ditto.
-
- * vm_eval.c (rb_apply): ditto.
-
- * vm_eval.c (rb_eval_cmd): ditto.
-
-Mon Mar 17 10:11:59 2014 Eric Wong <e@80x24.org>
-
- * variable.c (rb_const_set): delete existing entry on redefinition
- [Bug #9645]
- * test/ruby/test_const.rb (test_redefinition): test for leak
-
-Sun Mar 16 21:33:01 2014 Zachary Scott <e@zzak.io>
-
- * lib/time.rb: [DOC] Fix timezone in example of Time.parse [Bug #9521]
- Based on patch by @stomar
-
-Sun Mar 16 13:21:40 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (DLDFLAGS): insert a space between option and its
- argument for non-GCC compilers. [ruby-core:61429] [Bug #9624]
-
-Sun Mar 16 08:05:06 2014 Eric Wong <e@80x24.org>
-
- * gc.c (objspace_xcalloc): fix GC accounting
-
-Sun Mar 16 06:33:35 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (fill_lines): return address is just after calling
- address. Therefore noreturn function with tail call's return
- address may be in another function.
-
-Sun Mar 16 05:51:55 2014 Zachary Scott <e@zzak.io>
-
- * lib/gserver.rb: [DOC] Fixed typo in example by @stomar [Bug #9543]
-
-Sat Mar 15 18:54:03 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * ext/.document: remove refinement from documentable directories.
-
-Sat Mar 15 11:02:58 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (DLDFLAGS): check for each options to control
- symbol resolution. [ruby-core:61429] [Bug #9624]
-
-Sat Mar 15 07:02:35 2014 Eric Wong <e@80x24.org>
-
- * st.c (st_update): remove unnecessary assignment
-
-Fri Mar 14 14:58:38 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c (fill_lines): fetch symbol names from ELF binary's
- symbol table if it is built with cc -g and not stripped.
- Now ruby can show static symbols on Linux though glibc's
- backtrace_symbols(3) don't show them.
-
- * addr2line.c (rb_dump_backtrace_with_lines): use dladdr(3) to
- detect what object file declares the symbol because
- dl_iterate_phdr can't detect the main executable file
- and codes on the stack.
- NOTE: signal trampolines sometimes on the user stack. (FreeBSD)
-
- * addr2line.c (rb_dump_backtrace_with_lines): stop showing
- backtrace if the function's name is main.
- NOTE: FreeBSD's backtrace (libexecinfo) shows _start and
- an additional address. Why it doesn't remove them on dladdr phase
- is, dladdr may fail to detect the main function but detect
- as _start function. Therefore it must be after scanning
- the symbol table and getting correct name.
-
-
-Fri Mar 14 12:07:46 2014 Zachary Scott <e@zzak.io>
-
- * doc/syntax/literals.rdoc: [DOC] Single quote strings allows escape
- of backslash as well, patch by @idupree [Fixes GH-553]
- https://github.com/ruby/ruby/pull/553
-
-Fri Mar 14 01:18:24 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm.c (invoke_block_from_c): add splattable argument.
-
- * vm.c (vm_invoke_proc): disallow to splat when directly invoked.
-
- * vm_insnhelper.c (vm_callee_setup_arg_complex, vm_callee_setup_arg):
- relax arity check of yielded lambda. [ruby-core:61340] [Bug #9605]
-
- * test/ruby/test_yield.rb (TestRubyYieldGen#emu_bind_params): no
- longer raise ArgumentError when splatting to lambda.
-
-Thu Mar 13 23:51:02 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/-test-/win32/dln/libdlntest.c (dlntest_ordinal): no need to
- specify export in the source file because .def file do it.
- get rid of warning on linking.
-
-Wed Mar 12 11:19:03 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_callee_setup_arg): disable fastpath if splat
- argument, since argc may differ for each calls.
- [ruby-core:61422] [Bug #9622]
-
- * vm_insnhelper.c (vm_callee_setup_arg): turn a macro into an
- inline function.
-
-Wed Mar 12 07:26:05 2014 Eric Wong <e@80x24.org>
-
- * insns.def (opt_regexpmatch2): respect redefined match op
- Thanks to Sam Rawlins for the fix.
- * test/ruby/test_string.rb: test based on Tsuyoshi Sawada's report
- [Bug #9581]
-
-Tue Mar 11 22:31:25 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * ext/.document: add objspace/objspace_dump.c to document file.
-
-Tue Mar 11 22:22:38 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * test/objspace/test_objspace.rb (TestObjSpace#test_dump_uninitialized_file):
- remove dependency on json library.
-
-Tue Mar 11 10:55:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * README.EXT{,.ja} (Appendix B): update contents of `ruby_options`
- and replace `ruby_run` with `ruby_run_node`. based on the patch
- by Kaneko Yuichiro at [ruby-dev:48030] [Bug #9619].
-
-Tue Mar 11 06:54:00 2014 Scott Francis <scott.francis@shopify.com>
-
- * ext/objspace/objspace_dump.c: Check fptr before trying to dump RFILE
- object fd. [GH-562]
-
- * test/objspace/test_objspace.rb: add test
-
-Tue Mar 11 02:04:36 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_dump.c (rb_vm_bugreport): show vm maps on FreeBSD.
-
- * vm_dump.c (procstat_vm): copied from FreeBSD.
- http://svnweb.freebsd.org/base/head/usr.bin/procstat/procstat_vm.c?revision=261780
-
-Mon Mar 10 12:14:26 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: always check dladdr(1).
-
- * addr2line.c (fill_lines): show the line number in C backtrace if
- ruby is built without --enable-shared (PIE) on Linux.
- patch is originally by Shinichiro Hamaji
- https://twitter.com/shinh/status/441957774264504321
- NOTE: ld doesn't insert __executable_start for PIE.
- dladdr(3)'s argument must be a function pointer.
-
-Mon Mar 10 10:51:17 2014 ksss <co000ri@gmail.com>
-
- * test/ruby/test_enumerator.rb (test_iterators): fix test for hash
- iterators. [Fixes GH-558]
-
-Sun Mar 9 14:14:49 2014 Eric Wong <e@80x24.org>
-
- * class.c (rb_class_subclass_add): use xmalloc
- * class.c (rb_module_add_to_subclasses_list): ditto
- * class.c (rb_class_remove_from_super_subclasses): use xfree
- * class.c (rb_class_remove_from_module_subclasses): ditto
- [Bug #9616]
-
-Sun Mar 9 13:51:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/fiddle/function.c (function_call): fix memory leak when an
- exception occurs at argument conversion or the function call.
-
-Sun Mar 9 06:42:40 2014 Eric Wong <e@80x24.org>
-
- * variable.c (struct global_variable): shrink by 8 bytes on 64-bit
-
-Sat Mar 8 17:42:51 2014 Eric Wong <e@80x24.org>
-
- * vm.c (add_opt_method): cleanup to use rb_method_entry_at
-
-Sat Mar 8 13:46:40 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/dl/cptr.c (dlptr_free), ext/dl/handle.c (dlhandle_free),
- ext/fiddle/handle.c (fiddle_handle_free),
- ext/fiddle/pointer.c (fiddle_ptr_free): fix memory leak.
- based on the patch Heesob Park at [ruby-dev:48021] [Bug #9599].
-
-Sat Mar 8 13:30:39 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * process.c (obj2uid, obj2gid): now getpwnam_r() and getgrnam_r()
- may need larger buffers than sysconf values, so retry with
- expanding the buffer when ERANGE is returned.
- [ruby-core:61325] [Bug #9600]
-
-Fri Mar 7 19:29:13 2014 Eric Wong <e@80x24.org>
-
- * vm_eval.c (vm_call0_body): use RARRAY_CONST_PTR
- (check_funcall_exec): ditto
- [ruby-core:61360]
-
-Fri Mar 7 19:14:11 2014 Eric Wong <e@80x24.org>
-
- * vm_eval.c (vm_call0_body): fix RB_GC_GUARD location
- (check_funcall_exec): ditto
- [Bug #9609]
-
-Fri Mar 7 14:48:17 2014 Narihiro Nakamura <authornari@gmail.com>
-
- * parse.y (ENC_SINGLE): Unused macro removed.
-
-Fri Mar 7 12:06:19 2014 Martin Bosslet <Martin.Bosslet@gmail.com>
-
- * test/openssl/test_ssl.rb: Reuse TLS default options from
- OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.
-
-Thu Mar 6 15:15:24 2014 Zachary Scott <e@zzak.io>
-
- * doc/syntax/assignment.rdoc: [DOC] Fix assignment directions
- By @idupree [Fixes GH-555] https://github.com/ruby/ruby/pull/555
-
-Thu Mar 6 15:07:18 2014 Zachary Scott <e@zzak.io>
-
- * doc/syntax/methods.rdoc: [DOC] Fix example for block arguments
- By @idupree [Fixes GH-554] https://github.com/ruby/ruby/pull/554
-
-Thu Mar 6 10:33:31 2014 Martin Bosslet <Martin.Bosslet@gmail.com>
-
- * lib/openssl/ssl.rb: Explicitly whitelist the default
- SSL/TLS ciphers. Forbid SSLv2 and SSLv3, disable
- compression by default.
- Reported by Jeff Hodges.
- [ruby-core:59829] [Bug #9424]
-
-Wed Mar 5 15:56:18 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (f_arg_asgn): define optional arguments as argument
- variables in the rhs default expressions.
- [ruby-core:61299] [Bug #9593]
-
-Wed Mar 5 11:58:30 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/openssl/ossl.c (ossl_make_error): check NULL for unknown
- error reasons with old OpenSSL, and insert a colon iff formatted
- message is not empty.
-
-Wed Mar 5 00:42:00 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * ext/pathname/lib/pathname.rb (Pathname#find): add "ignore_error"
- keyword argument defaulted to true as well as Find#find.
-
-Tue Mar 4 23:00:18 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/ruby/test_eval.rb (TestEval#make_test_binding): renamed.
- it's not test method.
-
-Tue Mar 4 20:50:59 2014 Masaya Tarui <tarui@ruby-lang.org>
-
- * st.c (st_foreach): fix type of hash. not st_data_t but st_index_t.
-
-Tue Mar 4 19:41:40 2014 Tanaka Akira <akr@fsij.org>
-
- * Makefile.in: ".DEFAULT" target removed because it is not for
- specifying default target.
-
-Tue Mar 4 00:25:35 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * lib/find.rb (Find#find): should pass ignore_error option to enumerators.
-
-Mon Mar 3 13:27:35 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/test_find.rb (TestFind#test_unsearchable_dir): ruby cannot make
- directory unreachable by owner on Windows.
-
-Mon Mar 3 08:10:04 2014 Eric Wong <e@80x24.org>
-
- * vm_method.c (rb_method_entry_get_without_cache): disable GMC
- writing if GMC is disabled.
- [ruby-core:61218]
-
-Mon Mar 3 07:47:17 2014 Eric Wong <e@80x24.org>
-
- * README.EXT: wrap GetDBM with do/while(0)
- * README.EXT.ja: ditto
- * ext/dbm/dbm.c: ditto, likewise for GetDBM2
- * ext/gdbm/gdbm.c: ditto
- * ext/sdbm/init.c: ditto
- [ruby-core:61217]
-
-Mon Mar 3 07:17:31 2014 Zachary Scott <e@zzak.io>
-
- * NEWS: [DOC] Update doc regarding filesystem load when flushing IO
-
-Mon Mar 3 04:37:50 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * io.c (rb_io_fsync): need to fsync even if on Windows. fixed mistake
- of r45254 and r45256.
-
-Mon Mar 3 04:21:34 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/win32ole: get rid of warnings (unused variable).
-
-Mon Mar 3 02:53:53 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * io.c (rb_io_flush_raw): [EXPERIMENTAL] remove force syncing for Win32
- to speed up IO. this may break some tests, and they'll be fixed
- later.
- [ruby-core:58570] [Bug #9153]
-
-Mon Mar 3 00:17:43 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/ruby/test_backtrace.rb: get rid of warnings. unused variable,
- shadowing.
-
-Sun Mar 2 11:15:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/find.rb (Find#find): add "ignore_error" keyword argument
- defaulted to true. [ruby-core:51025] [Feature #7596]
-
-Sun Mar 2 11:13:30 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/readline/extconf.rb (rl_hook_func_t): define as Function for
- very old readline versions. [ruby-core:61209] [Bug #9578]
-
-Sun Mar 2 10:47:58 2014 Eric Wong <e@80x24.org>
-
- * load.c (ruby_init_ext): make idempotent to suppress warnings
-
-Sat Mar 1 19:51:42 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/open3.rb (Open3.capture3): Ignore Errno::EPIPE for writing
- stdin_data.
- (Open3.capture2): Ditto.
- (Open3.capture2e): Ditto.
-
-Sat Mar 1 19:06:47 2014 Eric Wong <e@80x24.org>
-
- * gc.c (ruby_gc_set_params): simplify condition
-
-Sat Mar 1 16:18:40 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/readline/readline.c (Init_readline): Use rl_hook_func_t instead
- of Function to support readline-6.3. (rl_hook_func_t is available
- since readline-4.2.)
- Reported by Dmitry Medvinsky. [ruby-core:61141] [Bug #9578]
-
-Sat Mar 1 16:05:58 2014 Eric Wong <e@80x24.org>
-
- * gc.c (ruby_gc_set_params): fix building without RGenGC
-
-Sat Mar 1 11:08:00 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb: support dumping Encoding
- objects.
-
- * ext/psych/lib/psych/visitors/to_ruby.rb: support loading Encoding
- objects.
-
- * test/psych/test_encoding.rb: add test
-
- * ext/psych/lib/psych.rb: add version
-
-Sat Mar 1 10:52:34 2014 Zachary Scott <e@zzak.io>
-
- * README.EXT.ja: [DOC] Fix typo "macro macro" @utenmiki [Fixes GH-551]
- https://github.com/ruby/ruby/pull/551
-
-Fri Feb 28 11:16:55 2014 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * numeric.c: Fix Numeric#step with 0 unit [Bug #9575]
-
-Thu Feb 27 17:59:01 2014 Zachary Scott <e@zzak.io>
-
- * lib/optparse.rb: [DOC] Add example of generating help with optparse.
- Patch by @joelmccracken documenting-ruby/ruby#19
- https://github.com/documenting-ruby/ruby/pull/19
-
-Thu Feb 27 12:10:09 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (ruby_num_interval_step_size): check signs and get rid
- of implementation dependent behavior of negative division.
- [ruby-core:61106] [Bug #9570]
-
-Thu Feb 27 03:55:45 2014 Zachary Scott <e@zzak.io>
-
- * thread.c: [DOC] Typo in comment for _FORTIFY_SOURCE [Fixes GH-548]
- Patch by @qnet-herwin https://github.com/ruby/ruby/pull/548
-
-Wed Feb 26 18:43:43 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (heap_pages_free_unused_pages): check tomb page availability
- at first.
- And return immediately if we don't touch sorted list any more.
-
-Wed Feb 26 14:10:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (setup_exception): preserve exception class name encoding
- in debug mode messages.
-
- * eval.c (setup_exception): preserve errinfo across calling #to_s
- method on the exception. [ruby-core:61091] [Bug #9568]
-
-Wed Feb 26 01:29:27 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (sym_find): Add Symbol.find(str), which returns whether given
- string is defined as symbol or not. [Feature #7854]
-
-Tue Feb 25 22:52:02 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * ext/dl/dl.c (rb_dl_realloc): use NUM2SIZET instead of NUM2INT.
-
- * ext/fiddle/fiddle.c (rb_fiddle_realloc): ditto.
-
-Tue Feb 25 22:49:30 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * ext/dl/dl.c (rb_dl_malloc): use NUM2SIZET instead of NUM2INT.
- Coverity Scan found this bug.
-
- * ext/fiddle/fiddle.c (rb_fiddle_malloc): ditto.
-
-Tue Feb 25 12:06:13 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * win32/Makefile.sub: define PACKED_STRUCT.
-
-Mon Feb 24 21:41:56 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * README.md, README.ja.md: removed (wrong) mode setting for emacs.
-
-Mon Feb 24 20:05:41 2014 Eric Wong <e@80x24.org>
-
- * configure.in: define PACKED_STRUCT_UNALIGNED for x86*
- * timev.h (struct vtm): use PACKED_STRUCT_UNALIGNED
- * time.c (struct time_object): ditto
- [Bug #9558] non-x86 cannot safely access unaligned addresses
-
-Mon Feb 24 18:10:02 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/fiddle/test_function.rb: remove unused variables.
- * test/fileutils/test_fileutils.rb: ditto.
- * test/io/console/test_io_console.rb: ditto.
-
-Mon Feb 24 12:37:51 2014 Eric Wong <e@80x24.org>
-
- * configure.in: use -Wno-packed-bitfield-compat for GCC 4.4+
- use __attribute__((packed)) if available
- * timev.h: shrink and pack struct vtm
- * time.c: pack struct time_object and adjust/introduce helpers
- [ruby-core:60794]
-
-Sun Feb 23 17:55:50 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/xmltokens.rb: Add missing non ASCII valid characters
- to element name characters. Now, REXML name tokens exactly
- match "[5] Name" in the XML spec and "[4] NCName" in the
- Namespaces in XML spec. See comment about the details.
- [Bug #9539] [ruby-core:60901]
- Reported by Mario Barcala. Thanks!!!
-
- * test/rexml/xpath/test_node.rb: Add tests for the above case.
-
-Sun Feb 23 12:18:54 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/socket/raddrinfo.c (inet_pton): use rb_w32_inet_pton, instead of
- inet_pton directly, which is unavailable on older version Windows.
-
- * include/ruby/win32.h, win32/win32.c (rb_w32_inet_pton): add a
- wrapper function for inet_pton minimum supported client is
- Vista, as well as inet_ntop.
-
-Sun Feb 23 11:33:25 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/net/imap/test_imap.rb: remove unused variables.
- * test/net/imap/test_imap_response_parser.rb: ditto.
- * test/net/pop/test_pop.rb: ditto.
-
-Sun Feb 23 02:19:51 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb (bind_random_port): Rescue EPERM for FreeBSD which
- security.mac.portacl.port_high is changed.
- See mac_portacl(4) for details.
- Reported by Jakub Szafranski. [ruby-core:60917] [Bug #9544]
-
-Sat Feb 22 23:17:01 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/xpath_parser.rb: Fix indent.
-
-Sat Feb 22 23:15:35 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/xpath/test_attribute.rb: Simplify.
-
-Sat Feb 22 20:28:47 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * tool/redmine-backporter.rb: more friendly.
-
-Sat Feb 22 20:24:43 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/test_xpath*.rb: Move to ...
- * test/rexml/xpath/*.rb: ... here.
-
-Sat Feb 22 20:04:41 2014 Kouhei Sutou <kou@cozmixng.org>
-
- * test/rexml/listener.rb: Untabify.
-
-Sat Feb 22 19:07:31 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/io/console/console.c (console_dev): need read access for conout$
- because some functions need it. [Bug#9554]
-
-Sat Feb 22 18:40:58 2014 Eric Wong <e@80x24.org>
-
- * .gitignore: ignore benchmark files
-
-Sat Feb 22 01:22:24 2014 Yusuke Endoh <mame@tsg.ne.jp>
-
- * bignum.c (bary_mul_precheck): fix a copy-paste error.
- Coverity Scan found this bug.
-
-Sat Feb 22 00:58:51 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * ext/socket/raddrinfo.c (rb_getaddrinfo): second argument of
- MEMZERO is type. Coverity Scan found this bug.
-
-Fri Feb 21 23:47:24 2014 Shugo Maeda <shugo@ruby-lang.org>
-
- * ext/socket/init.c (wait_connectable): break if the socket is
- writable to avoid infinite loops on FreeBSD and other platforms
- which conforms to SUSv3. This problem cannot be reproduced with
- loopback interfaces, so it's hard to write test code.
- rsock_connect() and wait_connectable() are overly complicated, so
- they should be refactored, but I commit this fix as a workaround
- for the release of Ruby 1.9.3 scheduled on Feb 24.
- [ruby-core:60940] [Bug #9547]
-
-Fri Feb 21 23:03:39 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/redmine-backporter.rb: added to handle redmine tickets.
-
-Fri Feb 21 20:42:01 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (rb_mod_init_copy): do nothing if copying self.
- [ruby-dev:47989] [Bug #9535]
-
- * hash.c (rb_hash_initialize_copy): ditto.
-
-Fri Feb 21 16:45:54 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/logger.rb (next_rotate_time, previous_period_end): consider
- DST change.
-
- * lib/logger.rb (Logger::LogDevice#check_shift_log): compare the
- current time with the time for the next rotation to fix rotation
- miss when date changed between the comparison and log writing.
- based on the patch by megayu <yuhg2310 AT gmail.com>.
- [Fixes GH-539]
-
-Fri Feb 21 10:39:33 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/monitor/test_monitor.rb: remove unused variables.
- * test/resolv/test_dns.rb: ditto.
- * test/rexml/test_functions.rb: ditto.
- * test/rss/test_setup_maker_itunes.rb: ditto.
-
-Fri Feb 21 09:48:56 2014 Eric Wong <e@80x24.org>
-
- * ext/socket/ancdata.c (bsock_sendmsg_internal): only retry on error
- (bsock_recvmsg_internal): ditto
- * test/socket/test_unix.rb: test above for infinite loop
-
-Fri Feb 21 08:27:19 2014 Eric Wong <e@80x24.org>
-
- * include/ruby/ruby.h (RB_GC_GUARD):
- use rb_gc_guarded_ptr_val on non-GCC/MSC
- * gc.c (rb_gc_guarded_ptr_val): rename and adjust argument.
- RB_GC_GUARD should be robust enough for any compiler.
- [ruby-core:60816] [Bug #7805]
-
-Thu Feb 20 22:21:26 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/raddrinfo.c (numeric_getaddrinfo): Use xcalloc.
- Suggested by Eric Wong.
- https://bugs.ruby-lang.org/issues/9525#note-14
-
-Thu Feb 20 11:21:13 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_flatten): fix behavior of flatten(-1).
- [ruby-dev:47988] [Bug #9533]
-
- * test/ruby/test_array.rb: test for above.
-
-Wed Feb 19 18:57:02 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket: Bypass getaddrinfo() if node and serv are numeric.
- Reporeted by Naotoshi Seo. [ruby-core:60801] [Bug #9525]
-
- * ext/socket/extconf.rb: Detect struct sockaddr_in6.sin6_len.
-
- * ext/socket/sockport.h (SET_SIN6_LEN): New macro.
- (INIT_SOCKADDR_IN6): Ditto.
-
- * ext/socket/rubysocket.h (struct rb_addrinfo): Add
- allocated_by_malloc field.
-
- * ext/socket/raddrinfo.c (numeric_getaddrinfo): New function.
- (rb_getaddrinfo): Call numeric_getaddrinfo at first.
- (rb_freeaddrinfo): Free struct addrinfo properly when it is
- allocated by numeric_getaddrinfo.
-
-Wed Feb 19 18:31:48 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket: Wrap struct addrinfo by struct rb_addrinfo.
-
-Wed Feb 19 17:47:01 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/ipsocket.c (ip_s_getaddress): Don't access freed memory.
-
-Wed Feb 19 11:39:41 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: it must see rb_cv_broken_memmem not rb_cv_func_memmem.
-
-Tue Feb 18 23:18:41 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/socket/test_socket.rb: unix socket is required by test case.
-
-Tue Feb 18 20:48:38 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/socket/test_addrinfo.rb: remove unused variables.
- * test/socket/test_nonblock.rb: ditto.
- * test/socket/test_socket.rb: ditto.
- * test/socket/test_unix.rb: ditto.
- * test/testunit/test_parallel.rb: ditto.
- * test/webrick/test_filehandler.rb: ditto.
- * test/xmlrpc/test_features.rb: ditto.
- * test/zlib/test_zlib.rb: ditto.
-
-Tue Feb 18 14:27:18 2014 Shota Fukumori <her@sorah.jp>
-
- * lib/test/unit.rb: Requires minitest < 5.0.0 if Gem is available.
-
-Tue Feb 18 14:24:07 2014 Shota Fukumori <her@sorah.jp>
-
- * lib/test/unit/test-unit.gemspec: Add minitest < 5.0.0 dependency
-
- * tool/rbinstall.rb: Add empty implementations for `add_dependency`,
- `add_runtime_dependency`, `add_development_dependency` for
- Gem::Specification.
-
-Tue Feb 18 12:06:39 2014 Tanaka Akira <akr@fsij.org>
-
- * configure.in (FILE_COUNT): Removed. (win32.c defines it in itself.)
- (FILE_READPTR): Ditto.
-
-Tue Feb 18 09:35:44 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/test/psych/test_string.rb: remove unused variables.
- * test/test/psych/test_yaml.rb: ditto.
-
-Mon Feb 17 21:31:31 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_gc.rb: ignore warning messages for running with -w
- option such as chkbuild.
-
-Mon Feb 17 20:00:27 2014 Tanaka Akira <akr@fsij.org>
-
- * internal.h: Move BDIGIT and related definitions from
- include/ruby/defines.h.
-
-Mon Feb 17 17:41:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * marshal.c (marshal_dump, marshal_load): do not recycle wrapper
- objects, to prevent from segfault with continuation.
- [ruby-dev:47970] [Bug #9523]
-
-Mon Feb 17 15:43:59 2014 Zachary Scott <e@zzak.io>
-
- * doc/keywords.rdoc: [DOC] Add keywords doc by documenting-ruby/ruby#29
- https://github.com/documenting-ruby/ruby/pull/29
-
-Mon Feb 17 12:31:31 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (get_envparam_double): fix a warning message.
-
-Mon Feb 17 12:09:52 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: introduce new environment variable
- "RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR" to control major/minor GC
- frequency.
-
- Do full GC when the number of old objects is more than R * N
- where R is this factor and
- N is the number of old objects just after last full GC.
-
- * test/ruby/test_gc.rb: add a test.
-
-Mon Feb 17 11:28:40 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/test_pty.rb: ignore warnings to unused variables.
-
-Mon Feb 17 11:27:36 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/test_find.rb: remove unused variables.
-
-Sun Feb 17 02:12:00 2014 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_initialize): Insert GC guard.
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_global_new): ditto.
-
-Sun Feb 16 15:53:36 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/test_securerandom.rb: File.exists? is deprecated. use File.exist?
-
-Sun Feb 16 15:05:00 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/pathname/test_pathname.rb: File.exists? is deprecated. use File.exist?
-
-Sun Feb 16 15:00:28 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
-
- * test/net/ftp/test_ftp.rb: remove unused variables.
- * test/logger/test_logger.rb: ditto.
-
-Sun Feb 16 14:52:46 2014 Eric Wong <e@80x24.org>
-
- * dir.c (dir_s_glob): RB_GC_GUARD instead of volatile
-
-Sun Feb 16 14:33:52 2014 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/ruby.h (RBIGNUM_SIGN): Defined for compatibility.
- (RBIGNUM_POSITIVE_P): Ditto.
- (RBIGNUM_NEGATIVE_P): Ditto.
-
-Sun Feb 16 12:46:47 2014 Eric Wong <e@80x24.org>
-
- * io.c (rb_f_backquote): trade volatile for manual recycle
- rb_gc_force_recycle ensures object is visible until recycle
-
-Sun Feb 16 11:55:14 2014 Eric Wong <e@80x24.org>
-
- * marshal.c (marshal_dump): use rb_gc_force_recycle for GC-safety
- (marshal_load): ditto
- [ruby-core:60730] [Bug #7805]
-
-Sun Feb 16 08:11:23 2014 Zachary Scott <e@zzak.io>
-
- * README.EXT.ja: [DOC] Fix typo by @utenmiki [Fixes GH-534]
- https://github.com/ruby/ruby/pull/534
-
-Sun Feb 16 07:48:20 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/bigdecimal/bigdecimal.c (BIGNUM_ZERO_P): Unused macro removed.
-
-Sun Feb 16 06:12:23 2014 Tanaka Akira <akr@fsij.org>
-
- * internal.h: Rename macro names: RBIGNUM_FOO to BIGNUM_FOO.
- (BIGNUM_EMBED_LEN_NUMBITS): Renamed from RBIGNUM_EMBED_LEN_NUMBITS.
- (BIGNUM_EMBED_LEN_MAX): Renamed from RBIGNUM_EMBED_LEN_MAX.
- (BIGNUM_SIGN_BIT): Renamed from RBIGNUM_SIGN_BIT.
- (BIGNUM_SIGN): Renamed from RBIGNUM_SIGN.
- (BIGNUM_SET_SIGN): Renamed from RBIGNUM_SET_SIGN.
- (BIGNUM_POSITIVE_P): Renamed from RBIGNUM_POSITIVE_P.
- (BIGNUM_NEGATIVE_P): Renamed from RBIGNUM_NEGATIVE_P.
- (BIGNUM_EMBED_FLAG): Renamed from RBIGNUM_EMBED_FLAG.
- (BIGNUM_EMBED_LEN_MASK): Renamed from RBIGNUM_EMBED_LEN_MASK.
- (BIGNUM_EMBED_LEN_SHIFT): Renamed from RBIGNUM_EMBED_LEN_SHIFT.
- (BIGNUM_LEN): Renamed from RBIGNUM_LEN.
- (RBIGNUM_DIGITS): Renamed from RBIGNUM_DIGITS.
- (BIGNUM_LENINT): Renamed from RBIGNUM_LENINT.
-
- * bignum.c: Follow the above change.
-
- * gc.c: Ditto.
-
- * marshal.c: Ditto.
-
- * math.c: Ditto.
-
- * numeric.c: Ditto.
-
- * random.c: Ditto.
-
- * rational.c: Ditto.
-
- * sprintf.c: Ditto.
-
- * ext/-test-/bignum/bigzero.c: Ditto.
-
- * ext/-test-/bignum/intpack.c: Ditto.
-
- * ext/bigdecimal/bigdecimal.c: Ditto.
-
-Sat Feb 15 20:48:49 2014 Tanaka Akira <akr@fsij.org>
-
- * configure.in (FILE_READEND): Don't detect it because it is not used.
-
-Sat Feb 15 13:22:28 2014 Eric Wong <e@80x24.org>
-
- * probes_helper.h (RUBY_DTRACE_HOOK): correct type for _id
-
-Sat Feb 15 11:47:47 2014 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_cmp): Avoid bignum allocation for comparison
- between bignum and fixnum.
-
-Sat Feb 15 10:55:12 2014 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * ext/-test-/win32/fd_setsize/depend: fix wrong dependencies.
- [ruby-dev:47253]
-
-Sat Feb 15 00:38:54 2014 Tanaka Akira <akr@fsij.org>
-
- * enum.c: Enumerable#{min,min_by,max,max_by} extended to take an
- optional argument.
- (nmin_cmp): New function.
- (nmin_block_cmp): Ditto
- (nmin_filter): Ditto.
- (nmin_i): Ditto.
- (nmin_run): Ditto.
- (enum_min): Call nmin_run if the optional argument is given.
- (nmin_max): Ditto.
- (nmin_min_by): Ditto.
- (nmin_max_by): Ditto.
-
- * range.c: Range#{min,max} extended to take an optional argument.
- (range_min): Call range_first if the optional argument is given.
- (range_max): Call rb_call_super if the optional argument is given.
-
- [ruby-core:57111] [Feature #8887]
-
-Sat Feb 15 00:27:46 2014 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/ruby.h,
- internal.h,
- ext/-test-/bignum/bigzero.c: Hide a Bignum definition.
- [ruby-core:42891] [Feature #6083]
-
-Sat Feb 15 00:13:14 2014 Tanaka Akira <akr@fsij.org>
-
- * include/ruby/intern.h,
- include/ruby/io.h,
- include/ruby/ruby.h,
- include/ruby/win32.h,
- include/ruby/backward/rubysig.h,
- bignum.c,
- gc.c,
- io.c,
- process.c,
- safe.c,
- struct.c,
- thread.c,
- ext/socket/rubysocket.h,
- ext/-test-/old_thread_select: Remove deprecated definitions
- [ruby-core:60581] [Feature #9502]
-
-Fri Feb 14 18:38:46 2014 Eric Wong <e@80x24.org>
-
- * string.c (rb_str_format_m): trade volatile for RB_GC_GUARD
- RB_GC_GUARD meaning is clear and has better code generation.
- [ruby-core:60688]
-
-Thu Feb 13 23:30:30 2014 Shugo Maeda <shugo@ruby-lang.org>
-
- * vm_insnhelper.c (vm_call_method): should check ci->me->flag of
- a refining method in case the method is private.
- [ruby-core:60111] [Bug #9452]
-
- * vm_method.c (make_method_entry_refined): set me->flag of a refined
- method entry to NOEX_PUBLIC in case the original method is private
- and it is refined as a public method. The original flag is stored
- in me->def->body.orig_me, so it's OK to make a refined method
- entry public. [ruby-core:60111] [Bug #9452]
-
- * test/ruby/test_refinement.rb: related tests.
-
-Thu Feb 13 18:38:15 2014 Eric Wong <e@80x24.org>
-
- * re.c (rb_reg_raise): remove volatile
- Unnecessary since r41597
-
-Thu Feb 13 18:28:51 2014 Eric Wong <e@80x24.org>
-
- * re.c (rb_reg_regcomp): remove volatile
- Unnecessary since r13261
-
-Thu Feb 13 16:54:32 2014 Zachary Scott <e@zzak.io>
-
- * test/ruby/test_array.rb: Ensure flatten! is used for test_flatten
- Patch by @ksss [Fixes GH-530] https://github.com/ruby/ruby/pull/530
-
-Thu Feb 13 15:43:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (IDSET_ATTRSET_FOR_INTERN): fix off-by-one bug.
-
- * parse.y (rb_enc_symname_type): junk ID succeeded by '=' is also
- attrset ID. [ruby-core:60668] [Bug #8756]
-
-Thu Feb 13 11:06:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: check if pthread_setname_np is available.
-
- * thread_pthread.c: pthread_setname_np is not available on old
- Darwins. [ruby-core:60524] [Bug #9492]
-
-Thu Feb 13 00:56:59 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * configure.in: revert r44922. I should have used AC_CHECK_FUNCS()
- to just define a symbol if the function is available.
-
-Thu Feb 13 00:20:58 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * configure.in: use AC_CHECK_FUNC instead of AC_CHECK_FUNCS
- if available.
-
-Thu Feb 13 00:15:10 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * configure.in: fix to undefine HAVE_MEMMEM correctly if it is broken.
-
-Tue Feb 11 23:54:40 2014 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_cmp): Specialize a comparison to zero.
-
- * ext/bigdecimal/bigdecimal.c (is_negative): Use rb_big_cmp instead of
- RBIGNUM_NEGATIVE_P.
- (BigMath_s_log): Ditto.
-
-Tue Feb 11 22:59:10 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/openssl/ossl_bn.c (ossl_bn_initialize): Use rb_integer_pack.
- Fix SEGV by OpenSSL::BN.new(1 << (2**34)).
-
-Tue Feb 11 17:00:38 2014 Zachary Scott <e@zzak.io>
-
- * ext/tk/README.tcltklib: [DOC] Fix typo by @xta [Fixes GH-532]
-
-Sun Feb 9 13:59:29 2014 Tanaka Akira <akr@fsij.org>
-
- * configure.in: Fix compilation error.
- https://bugs.ruby-lang.org/issues/8358#note-16
-
-Sun Feb 9 05:20:24 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in (rb_cv_gnu_qsort_r): use compile error "conflicting
- types for 'qsort_r'" instead of AC_RUN_IFELSE.
-
-Sun Feb 9 04:07:34 2014 Zachary Scott <e@zzak.io>
-
- * lib/yaml.rb: [DOC] Add links to syck and psych on github [Bug #9501]
- Based on a patch by Giorgos Tsiftsis
-
-Sun Feb 9 02:13:53 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (OBJ_TAINTABLE, OBJ_TAINT, OBJ_INFECT),
- marshal.c (r_entry0): all Numerics never be tainted now.
- [ruby-core:57346] [Bug #8945]
-
-Sat Feb 8 23:40:35 2014 Vit Ondruch <vondruch@redhat.com>
-
- * configure.in: add quoting brackets and append wildcard for the
- rest after target_cpu, to properly detect platform for SSE2
- instructions. [ruby-core:60576] [Bug #8358]
-
-Sat Feb 8 21:44:07 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * configure.in: check qsort_r(3) and whether it is GNU version.
- BSD version has different prototype.
-
- * util.h: use qsort_r() as ruby_qsort() if it is GNU version.
-
- * util.c: define ruby_qsort() if needed.
-
-Sat Feb 8 16:34:36 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb (Resolv::DNS::Message::MessageDecoder#get_labels):
- Make it iterative.
-
-Sat Feb 8 15:54:12 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c, gc.h (rb_objspace_marked_object_p): added.
- This function *ONLY* works just after marking phase,
- before any sweeping.
- This function is highly depending current GC implementation
- and can be removed future version.
-
-Sat Feb 8 15:41:37 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb: Don't set CLOEXEC flag explicitly. (Ruby set it by
- default.)
-
-Sat Feb 8 15:27:02 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb (Resolv::DNS::Message::MessageDecoder): Raise
- DecodeError if no data before the limit.
- Reported by Will Bryant. [ruby-core:60557] [Bug #9498]
-
-Sat Feb 8 15:11:21 2014 Tanaka Akira <akr@fsij.org>
-
- * io.c (SMALLBUF): Unused macro removed.
-
-Fri Feb 7 23:37:49 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb: Ignore name servers which cause EAFNOSUPPORT on
- socket creation.
- Reported by Bjoern Rennhak. [ruby-core:60442] [Bug #9477]
-
-Fri Feb 7 21:58:48 2014 Zachary Scott <e@zzak.io>
-
- * lib/open-uri.rb: [DOC] use lower case version of core classes, same
- as commit r44878, based on patch by Jonathan Jackson [Bug #9483]
-
-Fri Feb 7 21:54:53 2014 Zachary Scott <e@zzak.io>
-
- * ext/ripper/lib/ripper/lexer.rb: [DOC] use lower case version of core
- classes when referring to return value, since we aren't directly
- talking about the class. Patch by Jonathan Jackson [Bug #9483]
-
-Fri Feb 7 05:28:38 2014 Eric Wong <e@80x24.org>
-
- * constant.h: reduce rb_const_entry_t size on 64-bit
- Patch by Adam Avilla [ruby-core:60542] [Feature #9496]
-
-Thu Feb 6 15:27:46 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (get_envparam_int): correct warning messages.
-
- * gc.c (get_envparam_double): ditto.
-
-Thu Feb 6 15:17:30 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (get_envparam_int): don't accept a value equals to lowerbound
- (changed by last commit) because "" or "foo" (not a number) strings
- are parsed as 0. They should be rejected.
-
- * gc.c (get_envparam_double): ditto.
-
-Thu Feb 6 09:00:35 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (ruby_gc_set_params): if RUBY_GC_OLDMALLOC_LIMIT is provided,
- then set objspace->rgengc.oldmalloc_increase_limit.
- Without this fix, the env variable RUBY_GC_OLDMALLOC_LIMIT
- does not work.
-
- * gc.c (get_envparam_int): accept a value equals to lowerbound.
-
- * gc.c (get_envparam_double): ditto.
-
-Thu Feb 6 08:23:28 2014 Eric Wong <e@80x24.org>
-
- * ext/thread/thread.c (rb_szqueue_max_set): use correct queue and
- limit wakeups. [Bug #9343][ruby-core:60517]
- * test/thread/test_queue.rb (test_sized_queue_assign_max):
- test for bug
-
-Thu Feb 6 07:18:01 2014 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems 2.2.2. Complete history at:
-
- http://rubygems.rubyforge.org/rubygems-update/History_txt.html#label-2.2.2+%2F+2014-02-05
-
- * test/rubygems: ditto.
-
-Wed Feb 5 20:56:32 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * marshal.c (to_be_skipped_id): ignore anonymous attributes.
-
- * pack.c (Init_pack): use anonymous ID so that associated objects
- do not appear in the packed result.
-
- * parse.y (rb_make_internal_id): return an anonymous ID for
- internal use.
-
-Wed Feb 5 14:41:56 2014 Koichi Sasada <ko1@atdot.net>
-
- * vsnprintf.c: remove duplicated def of `UNINITIALIZED_VAR()'.
-
-Wed Feb 5 14:40:16 2014 Koichi Sasada <ko1@atdot.net>
-
- * ext/objspace/objspace_dump.c (dump_object): use STR_SHARED_P()
- instead of removed STR_NOCAPA_P() macro.
-
-Wed Feb 5 13:51:33 2014 Koichi Sasada <ko1@atdot.net>
-
- * internal.h, vm_core.h: move LIKELY/UNLIKELY/UNINITIALIZED_VAR()
- macros from vm_core.h to internal.h.
-
- * string.c: remove dependency to "vm_core.h".
-
- * common.mk: ditto.
-
-Wed Feb 5 13:29:01 2014 Koichi Sasada <ko1@atdot.net>
-
- * string.c (rb_str_free): use FL_TEST(str, STR_SHARED) directly
- because str is not embed.
-
- * string.c (str_replace): remove `FL_SET(str, STR_SHARED)' line
- because STR_SET_SHARED() set STR_SHARED.
-
-Wed Feb 5 13:18:08 2014 Koichi Sasada <ko1@atdot.net>
-
- * internal.h: remove macros STR_NOCAPA and STR_NOCAPA_P().
-
- * string.c (rb_str_resize): remove `STR_SET_NOEMBED(str)' because
- str_make_independent_expand() set NOEMBED flag.
-
- * string.c (rb_str_resize): remove `STR_NOCAPA_P(str)' check because
- `str' is independent (not shared).
-
-Wed Feb 5 12:54:25 2014 Koichi Sasada <ko1@atdot.net>
-
- * string.c: refactoring, especially about string flags.
-
- * string.c (STR_UNSET_NOCAPA): removed.
- Use FL_UNSET() with STR_SHARED.
-
- * string.c (rb_str_capacity): check STR_SHARED directly
- because it is not a embed string.
-
- * string.c (rb_str_modify_expand): ditto.
-
- * string.c (rb_str_shared_replace): use STR_SET_SHARED().
-
- * string.c (str_make_independent_expand): remove STR_UNSET_NOCAPA()
- because `str' is not shared string.
-
-Wed Feb 5 12:11:04 2014 Koichi Sasada <ko1@atdot.net>
-
- * string.c (RESIZE_CAPA): should not resize shared string.
-
-Wed Feb 5 11:46:42 2014 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_mark_children): STR_ASSOC is no longer available.
- Reported by @nagachika.
- http://d.hatena.ne.jp/nagachika/20140204
-
-Wed Feb 5 11:27:22 2014 Koichi Sasada <ko1@atdot.net>
-
- * string.c (rb_str_new_frozen): refactoring code.
- * Move code from str_new_frozen_with_klass() (and remove it)
- * `aux.shared' should not be 0 for STR_SHARED strings.
-
-Wed Feb 5 04:23:41 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych.rb: New release of psych.
- * ext/psych/psych.gemspec: ditto
-
-Wed Feb 5 04:16:41 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/yaml/emitter.c: merge libyaml 0.1.5
- * ext/psych/yaml/loader.c: ditto
- * ext/psych/yaml/parser.c: ditto
- * ext/psych/yaml/reader.c: ditto
- * ext/psych/yaml/scanner.c: ditto
- * ext/psych/yaml/writer.c: ditto
- * ext/psych/yaml/yaml_private.h: ditto
-
-Tue Feb 4 19:10:29 2014 Koichi Sasada <ko1@atdot.net>
-
- * string.c: use long allocator names instead of numbered
- allocator names.
- * rb_str_new2 -> rb_str_new_cstr
- * rb_str_new4 -> rb_str_new_frozen
- * rb_str_new5 -> rb_str_new_with_class
- * str_new3 -> str_new_shared
- * str_new4 -> str_new_frozen_with_klass
-
-Tue Feb 4 17:20:03 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (glob_helper): return the filename with actual cases on
- the filesystem if it is case-insensitive. [ruby-core:42469]
- [Feature #5994]
-
-Tue Feb 4 16:16:58 2014 Koichi Sasada <ko1@atdot.net>
-
- * string.c: use STR_SHARED instead of ELTS_SHARED.
- (same value, but more clear meaning)
-
-Tue Feb 4 16:09:14 2014 Koichi Sasada <ko1@atdot.net>
-
- * string.c: remove STR_ASSOC related code.
- By r44804, string objects can not have STR_ASSOC flag.
-
- * internal.h: ditto.
-
- * ext/objspace/objspace_dump.c (dump_object): ditto.
-
-Tue Feb 4 14:07:20 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * pack.c (str_associate, str_associated): keep associated objects
- in an instance variables, instead of in the internal structure.
-
- * string.c (rb_str_associate, rb_str_associated): deprecate.
-
-Tue Feb 4 12:55:31 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_modify_expand): enable capacity and disable
- association with packed objects when setting capa, so that
- pack("p") string fails to unpack properly after modified.
-
-Tue Feb 4 12:45:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (glob_make_pattern): all alphabets are magic characters on
- case-insensitive filesystems. [ruby-core:42469] [Feature #5994]
-
-Tue Feb 4 09:47:57 2014 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems 2.2.2 prerelease to check fixes to
- CI.
- * test/rubygems: ditto.
-
-Mon Feb 3 12:04:47 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * error.c: [DOC] Exception#cause may return nil. [ci skip]
-
-Sun Feb 2 05:48:42 2014 Eric Wong <e@80x24.org>
-
- * io.c (rb_io_syswrite): add RB_GC_GUARD
- [Bug #9472][ruby-core:60407]
-
-Sat Feb 1 15:09:16 2014 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (ole_typedesc2val): add VT_RECORD case.
-
-Sat Feb 1 06:38:51 2014 Zachary Scott <e@zzak.io>
-
- * lib/drb/drb.rb: [DOC] Add note about start_service for each process
- Based on a patch by @rosenfeld [Fixes GH-514] [ci skip]
- https://github.com/ruby/ruby/pull/514
-
-Sat Feb 1 06:30:20 2014 Zachary Scott <e@zzak.io>
-
- * error.c: [DOC] Document Exception#cause by @jasonrclark [ci skip]
- [Fixes GH-519] https://github.com/ruby/ruby/pull/519
-
-Sat Feb 1 06:10:49 2014 Zachary Scott <e@zzak.io>
-
- * lib/securerandom.rb: [DOC] Add note on require for examples
- Based on a patch by @schneems [Fixes GH-518] [ci skip]
- https://github.com/ruby/ruby/pull/518
-
-Sat Feb 1 06:04:56 2014 Zachary Scott <e@zzak.io>
-
- * numeric.c: [DOC] Fix typo in example for #step [ci skip]
- Patch by @ksss [Fixes GH-522] https://github.com/ruby/ruby/pull/522
-
-Fri Jan 31 17:01:47 2014 Eric Wong <e@80x24.org>
-
- * ext/socket/init.c (rsock_socket0): split out SOCK_CLOEXEC version
- * ext/socket/socket.c (rsock_socketpair0): ditto
- [ruby-core:60377]
-
-Fri Jan 31 03:48:40 2014 Eric Wong <e@80x24.org>
-
- * benchmark/driver: avoid large alloc in driver process
- [ruby-core:59869] [Bug #9430]
-
-Thu Jan 30 14:45:49 2014 Shugo Maeda <shugo@ruby-lang.org>
-
- * configure.in: use $@ instead of $(.TARGET) because .TARGET is not
- supported by GNU make.
-
-Thu Jan 30 08:26:21 2014 Yusuke Endoh <mame@tsg.ne.jp>
-
- * ext/fiddle/closure.c: use sizeof(*pcl) for correct sizeof value.
- [ruby-core:57599] [Bug #8978].
-
-Wed Jan 29 20:08:15 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (nogvl_copy_stream_sendfile): check socket on other than
- linux, as sendfile(2) on non-socket fd works only on linux.
- [Feature #9427]
-
-Wed Jan 29 18:09:48 2014 Eric Wong <e@80x24.org>
-
- * io.c (nogvl_copy_stream_sendfile): remove socket check
- [ruby-core:59856][Feature #9427]
-
-Wed Jan 29 04:29:54 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/openssl/ossl_ssl.c: pass read_nonblock options to underlying IO
- when SSL session has not been started.
-
- * test/openssl/test_ssl.rb: test for change.
-
-Wed Jan 29 03:49:36 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/fiddle/closure.c: use sizeof(*pcl) for correct sizeof value.
- [ruby-core:57599] [Bug #8978]. Thanks mame!
-
-Wed Jan 29 03:36:42 2014 Eric Wong <e@80x24.org>
-
- * doc/contributing.rdoc: allow/encourage other git hosts
- [ruby-core:59807][misc #9421]
-
-Tue Jan 28 23:36:01 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket: Avoid redundant fcntl/fstat syscalls for cloexec
- sockets.
- Patch by Eric Wong. [ruby-core:59429] [Feature #9330]
-
-Tue Jan 28 20:51:07 2014 Tanaka Akira <akr@fsij.org>
-
- * process.c (READ_FROM_CHILD): Apply the last hunk of
- 0001-process.c-avoid-EINTR-from-Process.spawn.patch written by
- Eric Wong in [Bug #8770].
-
-Tue Jan 28 16:31:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread_pthread.c (ruby_init_stack, ruby_stack_overflowed_p):
- place get_stack above others to get stack boundary information.
- [ruby-core:60113] [Bug #9454]
-
-Tue Jan 28 15:27:36 2014 NARUSE, Yui <naruse@ruby-lang.org>
-
- * thread_pthread.c: rlimit is only available on Linux.
- At least r44712 breaks FreeBSD.
- [ruby-core:60113] [Bug #9454]
-
-Tue Jan 28 15:17:59 2014 Zachary Scott <e@zzak.io>
-
- * lib/set.rb: [DOC] Add examples for Set#intersect? and Set#disjoint?
- Patch by xavier nayrac [Bug #9331] [ci skip]
-
-Tue Jan 28 15:12:22 2014 Zachary Scott <e@zzak.io>
-
- * ext/zlib/zlib.c (rb_zlib_adler32): [DOC] Add example for adler32
- Patch by Vajrasky Kok [Bug #9307] [ci skip]
-
-Tue Jan 28 08:56:00 2014 Charlie Somerville <charliesome@ruby-lang.org>
-
- * compile.c (iseq_build_from_ary_body): Use :blockptr instead of :block
- as hash key when loading serialized instruction sequences from arrays.
- [Bug #9455] [ruby-core:60146]
-
-Mon Jan 27 21:52:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread_pthread.c: get current main thread stack size, which may
- be expanded than allocated size at initialization, by rlimit().
- [ruby-core:60113] [Bug #9454]
-
-Sat Jan 25 22:17:02 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * README.ja.md, README.md: update the controller address of
- mailing lists.
-
-Sat Jan 25 14:50:42 2014 Eric Wong <normalperson@yhbt.net>
-
- * process.c (send_child_error): retry write on EINTR to fix
- occasional Errno::EINTR from Process.spawn.
-
- * process.c (recv_child_error): retry read on EINTR to fix
- occasional Errno::EINTR from Process.spawn.
-
-Sat Jan 25 14:21:06 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_compile_each): result of assignment should be
- its rhs instead of returned value from a method.
- [ruby-core:60071] [Bug #9448]
-
-Sat Jan 25 11:16:19 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (rb_extract_keywords): treat nil keyword_hash same as 0,
- for the case rb_scan_args returns nil if no keyword hash.
-
-Fri Jan 24 15:13:20 2014 Zachary Scott <e@zzak.io>
-
- * lib/racc/rdoc/grammar.en.rdoc: [DOC] Correct grammar and typos
- Patch by Giorgos Tsiftsis [Bug #9429] [ci skip]
-
-Thu Jan 23 20:20:17 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/envutil.rb: try to wait a bit (0.1sec) when ruby process
- exits by signals because some SEGV tests fail because of not enough
- error output.
-
-Thu Jan 23 20:06:27 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_settracefunc.rb: check the target thread.
-
-Thu Jan 23 19:59:16 2014 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_settracefunc.rb: check the target thread.
-
-Thu Jan 23 14:26:44 2014 Zachary Scott <e@zzak.io>
-
- * lib/fileutils.rb: [DOC] Fix typo in options_of() example [Bug #9392]
- Patch by Giorgos Tsiftsis
-
-Thu Jan 23 13:56:16 2014 Zachary Scott <e@zzak.io>
-
- * README -> README.md: [DOC] Format README with Markdown [Bug #9255]
- * README.ja -> README.ja.md: ditto
-
-Wed Jan 22 15:59:39 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/thread/thread.c (Init_thread): ConditionVariable and Queue
- are not able to copy. [ruby-core:59961] [Bug #9440]
-
-Tue Jan 21 20:14:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread_pthread.c (rb_thread_create_timer_thread): fix for platforms
- where PTHREAD_STACK_MIN is a dynamic value and not a compile-time
- constant. [ruby-dev:47911] [Bug #9436]
-
-Tue Jan 21 17:55:09 2014 Zachary Scott <e@zzak.io>
-
- * lib/uri/common.rb: [DOC] Use static w3.org uri [ci skip]
- Patch by @ykzts [Fix GH-484] https://github.com/ruby/ruby/pull/484
-
-Tue Jan 21 16:43:22 2014 Zachary Scott <e@zzak.io>
-
- * enum.c: [DOC] Add simple example of Enumerable#zip [ci skip]
- Patch by @nruth on documenting-ruby/ruby#22
- https://github.com/documenting-ruby/ruby/pull/22
-
-Tue Jan 21 16:26:44 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread_pthread.c (rb_thread_create_timer_thread): expand timer
- thread stack size to get rid of segfault on FreeBSD/powerpc64.
- based on the patch by Steve Wills at [ruby-core:59923].
- [ruby-core:56590] [Bug #8783]
-
-Tue Jan 21 04:31:23 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/option.c: Use "int" for IP_MULTICAST_LOOP and
- IP_MULTICAST_TTL on Mac OS X and Windows.
-
-Tue Jan 21 00:39:15 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/option.c: Use "byte" as default argument for
- IP_MULTICAST_LOOP and IP_MULTICAST_TTL socket option to follow
- the original multicast implementation.
-
-Mon Jan 20 20:20:27 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/option.c: Use preprocessor macros to avoid repeated
- conditionals.
-
-Mon Jan 20 13:55:03 2014 Zachary Scott <e@zzak.io>
-
- * lib/rubygems/version.rb: [DOC] Use gender-neutral pronouns [ci skip]
- * lib/rubygems/security.rb: ditto
-
-Sun Jan 19 06:38:48 2014 Benoit Daloze <eregontp@gmail.com>
-
- * compar.c (cmp_equal): warn for this release and still rescue
- standard exceptions for a nicer transition. See #7688.
- Partly reverts r44502.
-
- * test/ruby/test_comparable.rb: adapt assertion to match new behavior.
-
-Sun Jan 19 06:27:18 2014 Benoit Daloze <eregontp@gmail.com>
-
- * test/ruby/test_comparable.rb: specify behavior for the different
- kind of exceptions rescued (or not) by Comparable#==.
-
-Sat Jan 18 23:12:19 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket: Avoid unnecessary ppoll/select on Linux.
- Patch by Eric Wong. [ruby-core:57950] [Bug #9039]
-
-Sat Jan 18 22:57:44 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb (Resolv::DNS::Resource::TXT#data): Return concatenated
- string.
- Patch by Ryan Brunner. [ruby-core:58220] [Bug #9093]
-
-Sat Jan 18 22:35:15 2014 Tanaka Akira <akr@fsij.org>
-
- * io.c (rb_update_max_fd): Return immediately if the given fd is small
- enough.
-
-Sat Jan 18 22:25:53 2014 Tanaka Akira <akr@fsij.org>
-
- * io.c: Test O_CLOEXEC only once.
- Patch by Eric Wong. [ruby-core:59419] [Feature #9328]
-
-Sat Jan 18 21:24:49 2014 Tanaka Akira <akr@fsij.org>
-
- * ext/socket/option.c: IP_MULTICAST_LOOP and IP_MULTICAST_TTL socket
- option takes a byte on OpenBSD.
- Fixed by Jeremy Evans. [ruby-core:59496] [Bug #9350]
-
-Sat Jan 18 21:19:04 2014 Tanaka Akira <akr@fsij.org>
-
- * lib/open-uri.rb: Make proxy disabling working again.
- Fixed by Christophe Philemotte. [ruby-core:59650] [Bug #9385]
-
-Fri Jan 17 20:05:02 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/delegate.rb (Delegator): keep source information methods
- which start and end with '__'. [ruby-core:59718] [Bug #9403]
-
-Fri Jan 17 17:58:04 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (rb_mod_s_constants): return its own constants for other
- than Module itself. [ruby-core:59763] [Bug #9413]
-
-Tue Jan 16 00:17:00 2014 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.gemspec: bigdecimal version 1.2.5.
-
-Wed Jan 15 20:30:31 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * io.c (io_binwrite): use writev(2) to avoid double write if available.
-
- * configure.in: check writev(2)
-
-Wed Jan 15 14:04:33 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (get_encoding): respect BOM on pseudo encodings.
- [ruby-dev:47895] [Bug #9415]
-
-Wed Jan 15 14:03:47 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (get_actual_encoding): get actual encoding according to
- the BOM if exists.
-
- * string.c (rb_str_inspect): use according encoding, instead of
- pseudo encodings, UTF-{16,32}. [ruby-core:59757] [Bug #8940]
-
-Tue Jan 14 21:07:22 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * ext/thread/thread.c (rb_szqueue_clear): notify SZQUEUE_WAITERS
- on SizedQueue#clear. [ruby-core:59462] [Bug #9342]
-
- * test/thread/test_queue.rb: add test. the patch is from
- Justin Collins.
-
-Tue Jan 14 15:58:43 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/bigdecimal/bigdecimal.c (CLASS_NAME): macro to wrap
- depending on PRIsVALUE for 1.9. [Backport #9406]
-
- * ext/bigdecimal/bigdecimal.c (DECIMAL_SIZE_OF_BITS): fallback
- definition for 2.1 or older. [ruby-core:59750] [Backport #9406]
-
-Tue Jan 14 11:28:44 2014 Yuki Yugui Sonoda <yugui@google.com>
-
- * vm_exec.c (cfp): Fixes a SEGV issue in r44554.
- r11 can be broken by subroutine and sometimes causes SEGV at
- runtime. Use r13 instead.
-
-Tue Jan 14 02:20:00 2014 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_divide): Add an additional
- digit for the quotient to be compatible with bigdecimal 1.2.1 and
- the former. [ruby-core:59365] [#9316] [#9305]
-
- * test/bigdecimal/test_bigdecimal.rb: tests for the above change.
-
- * ext/bigdecimal/bigdecimal.gemspec: bigdecimal version 1.2.4.
-
-Mon Jan 13 14:55:31 2014 Zachary Scott <e@zzak.io>
-
- * lib/xmlrpc/client.rb: [DOC] Remove note about SSL package on RAA
- Since RAA has been deprecated, and the SSL package has been replaced
- with net/https this statement is entirely false and should be
- deleted. [Bug #9152]
-
-Mon Jan 13 14:47:07 2014 Zachary Scott <e@zzak.io>
-
- * lib/net/smtp.rb: [DOC] Remove dead link to RAA by Giorgos Tsiftsis
- Fixes the following bugs: [Bug #9152] [Bug #9268] [Bug #9394]
- * lib/open-uri.rb: ditto
-
-Mon Jan 13 14:25:55 2014 Zachary Scott <e@zzak.io>
-
- * ext/openssl/ossl_pkey_dh.c: Fixed typo by Sandor Szuecs [Bug #9243]
-
-Mon Jan 13 12:03:00 2014 Charlie Somerville <charliesome@ruby-lang.org>
-
- * ext/thread/thread.c (rb_szqueue_push): check GET_SZQUEUE_WAITERS
- instead of GET_QUEUE_WAITERS to prevent deadlock. Patch by Eric Wong.
- [Bug #9302] [ruby-core:59324]
-
- * test/thread/test_queue.rb: add test
-
-Sun Jan 12 16:41:10 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * iseq.c (iseq_load): keep type_map to get rid of memory leak.
- based on a patch by Eric Wong at [ruby-core:59699]. [Bug #9399]
-
-Sun Jan 12 09:21:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/util.h (DECIMAL_SIZE_OF_BITS): a preprocessor
- constant macro to approximate decimal representation size of n-bits
- integer.
-
- * iseq.c (register_label): use DECIMAL_SIZE_OF_BITS for better
- approximation.
-
- * ext/bigdecimal/bigdecimal.c (BigMath_s_log): ditto.
-
- * common.mk (iseq.o), ext/bigdecimal/depend (bigdecimal.o): add
- dependency to ruby/util.h for DECIMAL_SIZE_OF_BITS.
-
-Fri Jan 10 16:27:20 2014 Yuki Yugui Sonoda <yugui@google.com>
-
- * vm_exec.c (cfp): Avoid generating invalid binary for
- NativeClient.
- r15 on x86_64 is reserved by NativeClient. So r15 to cfp used to
- generate invalid binary under some combinations of compiler
- optimization flags.
-
-Fri Jan 10 18:01:41 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_search_super_method): allow bound method from a
- module, yet another method transplanting.
-
-Fri Jan 10 13:34:04 2014 Aman Gupta <ruby@tmm1.net>
-
- * insns.def (opt_aref_with): new instruction to optimize Hash#[],
- removing any allocation overhead when used with a string literal
- key. Patch by normalperson (Eric Wong). [ruby-core:59640] [Bug #9382]
- * insns.def (opt_aset_with): new instruction to optimize Hash#[]=
- * compile.c (iseq_compile_each): compiler shortcuts for new
- instructions
- * hash.c (static VALUE rb_hash_compare_by_id_p): fix documentation for
- Hash#compare_by_identity to reflect frozen string sharing
- * test/ruby/test_hash.rb (class TestHash): test for new behavior
-
-Fri Jan 10 06:23:21 2014 Benoit Daloze <eregontp@gmail.com>
-
- * range.c (Range#size): [DOC] improve description and add examples.
- Patch by @skade. [Fixes GH-501]
-
-Fri Jan 10 00:47:52 2014 Josef Stribny <strzibny@gmail.com>
-
- * ext/tk/extconf.rb: fix to pass arrays instead of strings to
- libpathflag. patch at [ruby-core:59665]. [Bug #9386]
-
-Thu Jan 9 20:49:22 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: -mstackrealign is necessary for -msse2 working.
- [ruby-core:54716] [Bug #8349]
-
- * configure.in: use SSE2 instructions to drop unexpected precisions on
- other than mingw. [ruby-core:59472] [Bug #8358]
-
-Thu Jan 9 20:31:10 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * hash.c (rb_objid_hash): should return `long'. brushup r44534.
-
- * object.c (rb_obj_hash): follow above change.
-
-Thu Jan 9 19:12:37 2014 Koichi Sasada <ko1@atdot.net>
-
- * vm.c (rb_vm_pop_cfunc_frame): added. It cares c_return event.
- The patch base by drkaes (Stefan Kaes).
- [Bug #9321]
-
- * variable.c (rb_mod_const_missing): use rb_vm_pop_cfunc_frame()
- instead of rb_frame_pop().
-
- * vm_eval.c (raise_method_missing): ditto.
-
- * vm_eval.c (rb_iterate): ditto.
-
- * internal.h (rb_vm_pop_cfunc_frame): add decl.
-
- * test/ruby/test_settracefunc.rb: add tests.
- provided by drkaes (Stefan Kaes).
-
- * vm.c, eval.c, include/ruby/intern.h (rb_frame_pop):
- move definition of rb_frame_pop() and deprecate it.
- It doesn't care about `return' events.
-
-Thu Jan 9 17:40:28 2014 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * hash.c (rb_any_hash): should treat the return value of rb_objid_hash()
- as `long', because ruby assumes the hash value of the object id of
- an object is `long'.
- this fixes test failures on mswin64 introduced at r44525.
-
-Thu Jan 9 09:55:20 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb: dumping strings with
- quotes should not have changed. [ruby-core:59316] [Bug #9300]
-
- * ext/psych/lib/psych.rb: fixed missing require.
-
- * test/psych/test_string.rb: test
-
-Thu Jan 9 09:51:00 2014 Aaron Patterson <aaron@tenderlovemaking.com>
-
- * ext/psych/lib/psych/visitors/to_ruby.rb: anonymous structs
- should be able to roundtrip. Thanks @splattael!
-
- * test/psych/test_object_references.rb: test for change
-
-Wed Jan 8 22:53:16 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_search_super_method): when super called in a
- bound UnboundMethod generated from a module, no superclass is
- found since the current defined class is the module, then call
- method_missing in that case. [ruby-core:59619] [Bug #9377]
-
-Wed Jan 8 15:55:21 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (rb_objid_hash): return hash value from object ID with a
- salt, extract from rb_any_hash().
-
- * object.c (rb_obj_hash): return same value as rb_any_hash().
- fix r44125. [ruby-core:59638] [Bug #9381]
-
-Wed Jan 8 13:12:41 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/timeout.rb (Timeout::ExitException.catch): pass arguments
- for new instance.
-
- * lib/timeout.rb (Timeout::ExitException#exception): fallback to
- Timeout::Error if couldn't throw. [ruby-dev:47872] [Bug #9380]
-
- * lib/timeout.rb (Timeout#timeout): initialize ExitException with
- message for the fallback case.
-
-Tue Jan 7 12:43:06 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/timeout.rb (Timeout#timeout): should not rescue ordinarily
- raised ExitException, which should not be thrown.
-
- * lib/timeout.rb (Timeout::ExitException.catch): set @thread only if
- it ought to be caught.
-
- * lib/timeout.rb (Timeout#timeout): when a custom exception is given,
- no instance is needed to be caught, so defer creating new instance
- until it is raised. [ruby-core:59511] [Bug #9354]
-
-Tue Jan 7 10:16:02 2014 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems: Update to RubyGems master 21e409d / RubyGems 2.2.1.
-
- See http://rubygems.rubyforge.org/rubygems-update/History_txt.html
- for a list of bug fixes.
-
- * test/rubygems: ditto.
-
-Tue Jan 7 10:10:46 2014 Eric Wong <e@80x24.org>
-
- * ext/json/generator/depend: add build dependencies for json extension
- [Bug #9374] [ruby-core:59609]
- * ext/json/parser/depend: ditto
-
-Tue Jan 7 04:35:46 2014 Aman Gupta <ruby@tmm1.net>
-
- * array.c (ary_add_hash): Fix consistency issue between Array#uniq and
- Array#uniq! [Bug #9340] [ruby-core:59457]
- * test/ruby/test_array.rb (class TestArray): regression test for above.
-
-Mon Jan 6 21:28:48 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * .gitignore: ignore *-fake.rb generated even when CROSS_COMPILING = no
- since r42862.
-
-Sun Jan 5 20:14:14 2014 Benoit Daloze <eregontp@gmail.com>
-
- * compar.c (cmp_equal): remove error hiding in Comparable#==.
- Comparable#== no longer rescues exceptions silently.
- This was the cause of quite a couple bugs. See #7688. [EXPERIMENTAL]
-
- * test/ruby/test_comparable.rb: adapt assertion to match new behavior.
-
- * lib/rdoc/method_attr.rb: fix bugs discovered by this change.
-
- * test/rdoc/test_rdoc_normal_class.rb: fix bugs in tests.
-
-Sat Jan 4 22:44:00 2014 Charlie Somerville <charliesome@ruby-lang.org>
-
- * struct.c (rb_struct_set): return assigned value from setter method
- rather than struct object. [Bug #9353] [ruby-core:59509]
-
- * test/ruby/test_struct.rb (test_setter_method_returns_value): add test
-
-Sat Jan 4 21:44:31 2014 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * test/ruby/test_gc.rb (TestGc#test_latest_gc_info): use
- GC.stat(:key) instead of GC.stat.
-
-Sat Jan 4 19:15:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/socket/socket.c (rsock_syserr_fail_host_port): use format flags,
- '+' to inspect, ' ' to quote unprintables.
-
- * ext/socket/socket.c (rsock_syserr_fail_path): ditto.
-
- * ext/socket/socket.c (rsock_syserr_fail_raddrinfo): ditto.
-
- * ext/socket/socket.c (rsock_syserr_fail_host_port): add errno
- argument version and use rb_syserr_fail_str() instead of
- rb_sys_fail_str() with restoring errno.
-
- * ext/socket/socket.c (rsock_syserr_fail_path): ditto, and
- rb_syserr_fail().
-
- * ext/socket/socket.c (rsock_sys_fail_sockaddr): ditto, use
- rsock_syserr_fail_raddrinfo().
-
- * ext/socket/socket.c (rsock_sys_fail_raddrinfo): ditto.
-
- * ext/socket/socket.c (setup_domain_and_type): ditto.
-
-Sat Jan 4 17:18:58 2014 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * vm.c (RubyVM::OPTS): get rid of a garbage character.
-
-Sat Jan 4 10:17:54 2014 Eric Hodel <drbrain@segment7.net>
-
- * lib/rinda/ring.rb (Rinda::RingFinger#make_socket): Use
- ipv4_multicast_ttl option for portability.
-
-Sat Jan 4 10:15:47 2014 Eric Hodel <drbrain@segment7.net>
-
- * lib/rinda/ring.rb (Rinda::RingFinger#make_socket): Use
- ipv4_multicast_loop option for portability. Patch by Jeremy Evans.
- [ruby-trunk - Bug #9351]
-
-Fri Jan 3 19:09:00 2014 Eric Wong <normalperson@yhbt.net>
-
- * ext/socket/socket.c (rsock_sys_fail_host_port): save and restore errno
- before calling rb_sys_fail_str to prevent [BUG] errno == 0.
- Patch by Eric Wong. [ruby-core:59498] [Bug #9352]
-
- * ext/socket/socket.c (rsock_sys_fail_path): ditto
- * ext/socket/socket.c (rsock_sys_fail_sockaddr): ditto
- * ext/socket/socket.c (rsock_sys_fail_raddrinfo): ditto
- * ext/socket/socket.c (rsock_sys_fail_raddrinfo_or_sockaddr): ditto
-
-Fri Jan 3 10:43:57 2014 Aman Gupta <ruby@tmm1.net>
-
- * test/net/imap/cacert.pem: generate new CA cert, since the last one
- expired. [Bug #9341] [ruby-core:59459]
- * test/net/imap/server.crt: new server cert signed with updated CA.
- * test/net/imap/Makefile: add `make regen_certs` to automate this
- process.
-
-Fri Jan 3 00:09:54 2014 Benoit Daloze <eregontp@gmail.com>
-
- * ext/bigdecimal: update class method call style from :: to .
- in documentation and usage.
-
- * ext/bigdecimal/lib/bigdecimal/math.rb: [DOC] fix examples values.
- Computations were made using ruby 2.0.0p247 to ensure
- no effect of the recent BigDecimal bug.
-
- * ext/bigdecimal/sample/nlsolve.rb: fix indent.
-
-Thu Jan 2 16:07:21 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * io.c (io_fwrite): freeze converted str.
-
-Thu Jan 2 04:15:13 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (rb_longjmp): remove an extra modifier from the forward
- declaration to match the actual definition. [ruby-core:59451]
- [Bug #9338]
-
-Thu Jan 2 01:23:30 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * vm_eval.c (method_missing): use ALLOCV_N() instead of
- ALLOCA_N() and rb_ary_tmp_new().
-
-Thu Jan 2 00:53:16 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * array.c (rb_ary_zip): use ALLOCV_N() instead of ALLOCA_N().
-
-Thu Jan 2 00:04:29 2014 Masaki Matsushita <glass.saga@gmail.com>
-
- * hash.c (rb_hash_keys): make rb_hash_keys() static.
- it is no longer used from array.c since r43969.
- the patch is from normalperson (Eric Wong).
- [ruby-core:59449] [Feature #9336]
-
- * internal.h: remove definition of rb_hash_keys().
-
-Wed Jan 1 18:19:35 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: reset LDFLAGS and DLDFLAGS for opt-dir again after
- LIBPATHFLAG and RPATHFLAG are set. [ruby-dev:47868] [Bug #9317]
-
-Wed Jan 1 11:12:29 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: use SSE2 instructions for drop unexpected
- precisions. [ruby-core:54738] [Bug #8358]
-
-Tue Dec 31 23:49:07 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (rb_f_raise): add cause: optional keyword argument.
- [ruby-core:58610] [Feature #8257] [EXPERIMENTAL]
-
-Tue Dec 31 21:44:17 2013 Akio Tajima <artonx@yahoo.co.jp>
-
- * win32/Makefile.sub: remove HAVE_FSEEKO because fseeko removed from win32/win32.c
- Fixed [Bug #9333].
-
-Tue Dec 31 21:02:27 2013 Masaki Matsushita <glass.saga@gmail.com>
-
- * io.c (io_fwrite): allocate frozen str only when str is not converted.
-
-Tue Dec 31 15:44:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (RbConfig): expand RUBY_SO_NAME for extensions
- backward compatibility. [ruby-core:59426] [Bug #9329]
-
-Mon Dec 30 23:33:07 2013 Ayumu AIZAWA <ayumu.aizawa@gmail.com>
-
- * variable.c: [DOC] adding extra example in docs.
- patched by Steve Klabnik. [Bug #9210]
-
-Mon Dec 30 18:34:18 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * encoding.c (must_encindex, rb_enc_from_index, rb_obj_encoding): mask
- encoding index and ignore dummy flags. [ruby-core:59354] [Bug #9314]
-
-Mon Dec 30 16:11:52 2013 WATANABE Hirofumi <eban@ruby-lang.org>
-
- * tool/make-snapshot: needs CXXFLAGS. [ruby-core:59393][Bug #9320]
-
-Sun Dec 29 18:36:54 2013 Shota Fukumori <her@sorah.jp>
-
- * lib/mkmf.rb (configuration): Make CXXFLAGS customizable.
- Patch by Kohei Suzuki (eagletmt). [Fixes GH-492]
-
-Sun Dec 29 12:11:11 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (mnew_from_me): keep iclass as-is, to make inheritance
- chain consistent. [ruby-core:59358] [Bug #9315]
-
- * proc.c (method_owner): return the original defined_class from
- prepended iclass, instead.
-
-Sun Dec 29 08:47:24 2013 Lucas Allan Amorim <lucas.allan@gmail.com>
-
- * test/ruby/test_sprintf.rb (test_hash): Added tests for sprintf
- with a hash as parameter. [Fixes GH-491]
-
-Sun Dec 29 07:27:51 2013 Benoit Daloze <eregontp@gmail.com>
-
- * compar.c (cmp_eq_recursive): Fix the return value, the value for
- failed #<=> should be nil. It was raising a NoMethodError for
- the test case TestComparable#test_no_cmp (undefined method `>'
- for false:FalseClass). Yet one more reason for #7688.
-
-Sat Dec 28 22:21:59 2013 Benoit Daloze <eregontp@gmail.com>
-
- * object.c (Kernel#<=>) surround Comparable operators with <code> tags.
- The #== method was hidden in ri/rdoc's output and was highlighting
- the line instead.
-
-Sat Dec 28 17:24:00 2013 DV Suresh <e@dvsuresh.me>
-
- * benchmark/bm_so_meteor_contest.rb: [DOC] Fix a few typos
- * ext/fiddle/lib/fiddle/import.rb: ditto
- * ext/psych/lib/psych.rb: ditto
- * ext/psych/lib/psych/nodes/sequence.rb: ditto
- * ext/tk/lib/multi-tk.rb: ditto
- * ext/tk/lib/tcltk.rb: ditto
-
-Sat Dec 28 00:42:37 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (local_push_gen, local_pop_gen): save cmdarg_stack to
- isolate command argument state from outer scope.
- [ruby-core:59342] [Bug #9308]
-
-Fri Dec 27 13:25:03 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/{setup.mak,Makefile.sub}: update fake.rb like
- template/fake.rb.in.
-
-Thu Dec 26 16:10:41 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/Makefile.sub (fake.rb): should depend on version.h because
- if RUBY_VERSION is updated, fake.rb need to say the new version
- to avoid install error in rbconfig.rb.
-
-Thu Dec 26 14:25:03 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (HASH_REJECT_COPY_EXTRA_STATES): turn off the old
- behavior, copying extra states by accident.
-
-Thu Dec 26 10:49:14 2013 Yukihiro Matsumoto <matz@ruby-lang.org>
-
- * version.h (RUBY_VERSION): 2.2.0 development has started.
-
-Thu Dec 26 10:27:53 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * tool/merger.rb (tag): support 2.1.1 semi-automatic tagging and 2.2.0
- explicit tagging.
-
-Thu Dec 26 06:35:25 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * proc.c: Having any mandatory keyword argument increases min arity
- [#9299]
-
-Thu Dec 26 06:27:08 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * proc.c: Having optional keyword arguments makes maximum arity +1,
- not unlimited [#8072]
-
-Thu Dec 26 01:09:57 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * tool/release.sh: make symbolic links.
-
-Thu Dec 26 00:45:33 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * tool/make-snapshot: support new version scheme.
-
-Wed Dec 25 22:44:14 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_set_arguments): set arg_keyword_check from
- nd_cflag, which is set by parser. internal ID is used for
- unnamed keyword rest argument, which should be separated from no
- keyword check.
-
- * iseq.c (rb_iseq_parameters): if no keyword check, keyword rest is
- present.
-
- * parse.y (new_args_tail_gen): set keywords check to nd_cflag, which
- equals to that keyword rest is not present.
-
-Wed Dec 25 22:32:19 2013 Zachary Scott <e@zzak.io>
-
- * lib/abbrev.rb: [DOC] rdoc format patch by Giorgos Tsiftsis [Bug #9146]
-
-Wed Dec 25 20:30:10 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * iseq.c (rb_iseq_parameters): push argument type symbol only for
- unnamed rest keywords argument.
-
-Wed Dec 25 20:28:48 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (rb_iseq_min_max_arity): maximum argument is unlimited if
- having rest keywords argument. [ruby-core:53298] [Bug #8072]
-
-Wed Dec 25 18:29:22 2013 Koichi Sasada <ko1@atdot.net>
-
- * vm_insnhelper.c (argument_error): insert dummy frame to make
- a backtrace object intead of modify backtrace string array.
- [Bug #9295]
-
- * test/ruby/test_backtrace.rb: add a test for this patch.
- fix test to compare a result of Exception#backtrace with
- a result of Exception#backtrace_locations.
-
-Wed Dec 25 13:00:54 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: let mingw do something black-magic, and check if
- _gmtime64_s() is available actually.
-
- * win32/win32.c (gmtime_s, localtime_s): use _gmtime64_s() and
- _localtime64_s() if available, not depending on very confusing
- mingw variants macros. based on the patch by phasis68 (Heesob
- Park) at [ruby-core:58764]. [ruby-core:58391] [Bug #9119]
-
-Wed Dec 25 12:33:41 2013 Yusuke Endoh <mame@tsg.ne.jp>
-
- * sample/trick2013/: added the award-winning entries of TRICK 2013.
- See https://github.com/tric/trick2013 for the contest outline.
- (Matz has approved the attachment.)
-
-Wed Dec 25 10:42:02 2013 Yamashita Yuu <yamashita@geishatokyo.com>
-
- * ext/openssl/ossl_ssl.c (Init_ossl_ssl): Declare a constant
- `OP_MSIE_SSLV2_RSA_PADDING` only if the macro is defined. The
- `SSL_OP_MSIE_SSLV2_RSA_PADDING` has been removed from latest
- snapshot of OpenSSL 1.0.1. [Fixes GH-488]
-
-Wed Dec 25 01:03:00 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (bind_local_variables): allowing binding to list its
- local variables. patch by Jack Danger Canty <jackdanger AT
- squareup.com> at [ruby-core:56543]. [Feature #8773]
-
-Tue Dec 24 23:20:38 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/fileutils/fileasserts.rb (assert_ownership_user): new
- assertion for user ownership.
-
- * test/fileutils/test_fileutils.rb (test_chown_error),
- (test_chown_without_permission, test_chown_with_root):
- based on the patch by vajrasky (Vajrasky Kok) at
- [ruby-core:59298]. [Feature #9292]
-
-Tue Dec 24 16:28:05 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (rb_mod_define_method): consider visibility only if self
- in the caller is same as the receiver, otherwise make public as
- well as old behavior. [ruby-core:57747] [Bug #9005]
- [ruby-core:58497] [Bug #9141]
-
- * vm.c (rb_vm_cref_in_context): return ruby level cref if self is
- same.
-
-Tue Dec 24 14:13:14 2013 Koichi Sasada <ko1@atdot.net>
-
- * README.EXT: add a refer to URL.
-
-Tue Dec 24 13:48:45 2013 Koichi Sasada <ko1@atdot.net>
-
- * README.EXT: add a document about RGenGC.
- Reviewed by havenwood.
- [misc #8962]
-
- * README.EXT.ja: ditto.
-
-Tue Dec 24 12:11:43 2013 Koichi Sasada <ko1@atdot.net>
-
- * include/ruby/ruby.h (RARRAY_ASET): try to avoid compiler warning.
- [Bug #9287]
-
-Tue Dec 24 05:04:56 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/fileutils/test_fileutils.rb (setup): should not call
- Process.groups for Windows. get rid of many errors introduced by
- r44364.
-
-Mon Dec 23 18:37:16 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/fileutils/fileasserts.rb (assert_ownership_group): new
- assertion for group ownership.
-
- * test/fileutils/test_fileutils.rb (test_chown{,_verbose,_noop}):
- based on the patch by vajrasky (Vajrasky Kok) at
- [ruby-core:59281]. [Feature #9286]
-
-Mon Dec 23 15:53:45 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (HAS_EXTRA_STATES): warn extra states only when something
- differ. [ruby-core:59254] [Bug #9275]
-
-Mon Dec 23 12:42:13 2013 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * array.c: Have to_h raise on elements that are not key-value pairs
- [#9239]
-
- * enum.c: ditto
-
-Mon Dec 23 05:01:55 2013 Zachary Scott <e@zzak.io>
-
- * doc/syntax/methods.rdoc: [DOC] Added example for underscore
- conventions in method names. Also added doc to clarify encoding
- character set support for Ruby programs and elaborated on defining
- predicate and bang methods. Based on a patch by @gaurish
- [Fixes GH-477] https://github.com/ruby/ruby/pull/477
-
-Mon Dec 23 03:18:09 2013 Zachary Scott <e@zzak.io>
-
- * doc/ChangeLog-1.9.3: [DOC] Fix typos by @dvsuresh
- [Fixes GH-485] https://github.com/ruby/ruby/pull/485
- * ext/openssl/ossl_config.c: ditto
- * lib/rss/utils.rb, lib/time.rb: ditto
- * test/ruby/envutil.rb: ditto
-
-Sun Dec 22 23:56:56 2013 Zachary Scott <e@zzak.io>
-
- * lib/{rake,rdoc,rss}/*, test/rexml/test_listener.rb: [DOC] Fix typos
- by @dvsuresh [Fixes GH-486] https://github.com/ruby/ruby/pull/486
-
-Sun Dec 22 11:08:47 2013 Eric Hodel <drbrain@segment7.net>
-
- * test/rubygems/test_gem_ext_builder.rb: Fix warning due to ambiguous
- expression.
-
-Sun Dec 22 11:05:53 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems/commands/install_command.rb: Restore gem install
- --ignore-dependencies for remote gems
- * test/rubygems/test_gem_commands_install_command.rb: Test for the
- above.
-
-Sun Dec 22 10:23:40 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rdoc.rb: Set RDoc to release version.
-
-Sun Dec 22 10:19:07 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems.rb: Set RubyGems to release version.
-
-Sun Dec 22 10:16:08 2013 Eric Hodel <drbrain@segment7.net>
-
- * lib/rubygems.rb (module Gem): Fix comment for
- Gem::load_path_insert_index.
-
-Sun Dec 22 04:07:55 2013 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (ruby_gc_set_params): don't show obsolete warnings for
- RUBY_FREE_MIN/RUBY_HEAP_MIN_SLOTS if
- RUBY_GC_HEAP_FREE_SLOTS/RUBY_GC_HEAP_INIT_SLOTS are given.
- [Bug #9276]
-
-Sat Dec 21 13:00:20 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c: remove unnecessary the source path from EEXIST error
- messages and show the destination path only. [ruby-core:59202]
- [Feature #9263]
-
-Sat Dec 21 12:37:19 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/resolv.rb (Resolv::Hosts#lazy_initialize): should not
- consider encodings in hosts file. [ruby-core:59239] [Bug #9273]
-
- * lib/resolv.rb (Resolv::Config.parse_resolv_conf): ditto.
-
-Sat Dec 21 05:43:27 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * tool/make-snapshot: replace RUBY_PATCHLEVEL_STR in version.h to
- show users that this ruby is a preview/rc version.
-
-Sat Dec 21 05:03:49 2013 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/Makefile.sub (fake.rb): fixed wrong RUBY_PLATFORM, to correctly
- install win32.h.
- [ruby-core:58801][Bug #9199] reported by arton.
-
-For the changes before 2.1.0, see doc/ChangeLog-2.1.0
-For the changes before 2.0.0, see doc/ChangeLog-2.0.0
-For the changes before 1.9.3, see doc/ChangeLog-1.9.3
-For the changes before 1.8.0, see doc/ChangeLog-1.8.0
-
-Local variables:
-coding: us-ascii
-add-log-time-format: (lambda ()
- (let* ((time (current-time))
- (system-time-locale "C")
- (diff (+ (cadr time) 32400))
- (lo (% diff 65536))
- (hi (+ (car time) (/ diff 65536))))
- (format-time-string "%a %b %e %H:%M:%S %Y" (list hi lo) t)))
-indent-tabs-mode: t
-tab-width: 8
-change-log-indent-text: 2
-end:
-vim: tabstop=8 shiftwidth=2
diff --git a/doc/ChangeLog/ChangeLog-2.4.0 b/doc/ChangeLog/ChangeLog-2.4.0
deleted file mode 100644
index 30e9ccab3d..0000000000
--- a/doc/ChangeLog/ChangeLog-2.4.0
+++ /dev/null
@@ -1,9492 +0,0 @@
-Mon Nov 7 00:32:45 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/ruby/test_optimization.rb (test_tailcall_interrupted_by_sigint):
- ignore on Windows because we cannot handle signaled status of child
- ruby process on this platform.
-
-Sun Nov 6 23:36:07 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * test/ruby/test_optimization.rb (test_tailcall_interrupted_by_sigint):
- send SIGKILL if the child process doesn't die within 1 second.
-
-Sun Nov 6 21:54:28 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/vcs.rb (export_changelog): generate ChangeLog file from
- vcs's log. [Feature #12283]
-
- * tool/make-snapshot (package): overwrite ChangeLog by generated
- ChangeLog.
-
-Sun Nov 6 21:36:33 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * NEWS: Added entry for RDoc 5.
-
-Sun Nov 6 21:35:37 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * NEWS: ordered entries and adjust styles.
-
-Sun Nov 6 18:23:31 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * NEWS: Added entry for [Feature #12160][ruby-core:74239]
-
-Sun Nov 6 18:18:25 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * NEWS: Added entry for r56624.
-
-Sun Nov 6 15:53:03 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * configure.in (-Wno-maybe-uninitialized): gcc 6 also shows the same
- warnings as described in r49410.
-
-Sun Nov 6 14:42:50 2016 takkanm <takkanm@gmail.com>
-
- * eval.c (rb_mod_include, rb_mod_prepend): check if arguments are
- given, as well as Kernel#extend. [ruby-dev:49854] [Bug #12887]
- [Fix GH-1470]
-
-Sun Nov 6 11:59:05 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * test/rinda/test_rinda.rb (test_make_socket_ipv6_multicast,
- test_make_socket_ipv6_multicast_hops): skip if IPv6 multicast
- address is not available.
-
-Sun Nov 6 11:53:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/irb.rb (Binding#irb): new method like Binding#pry.
-
-Sun Nov 6 11:48:55 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * test/net/smtp/test_smtp.rb (test_tls_connect, test_tls_connect):
- use Socket.tcp_server_sockets in case localhost is resolved to ::1.
-
-Sun Nov 6 11:49:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/irb.rb (IRB::Irb#run): split from IRB.start.
-
-Sun Nov 6 11:45:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/e2mmap.rb (E2MM.def_exception): remove old definition if
- exists so that works multiple times.
-
-Sun Nov 6 10:03:00 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * test/ruby/test_optimization.rb (test_tailcall_interrupted_by_sigint):
- don't use sleep to run faster.
-
-Sun Nov 6 09:58:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * process.c (rb_exec_fillarg): honor the given path environment
- variable. [ruby-core:53103] [Bug #8004]
-
-Sun Nov 6 01:52:31 2016 Akira Matsuda <ronnie@dio.jp>
-
- * lib/erb.rb: Alias regist_scanner to register_scanner
-
-Sun Nov 6 01:39:36 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * compile.c (tailcallable_p): disable tail call optimization for
- toplevel, eval, and load to avoid SEGV when interrupted by SIGINT.
- [ruby-core:76327] [Bug #12576]
-
-Sun Nov 6 01:28:41 2016 Koichi Sasada <ko1@atdot.net>
-
- * vm_insnhelper.h: rename REG_(CFP|PC|SP|EP) to VM_REG_....
- [Bug #12527]
-
- * vm_exec.c: ditto.
-
-Sun Nov 6 00:25:11 2016 Sho Hashimoto <sho.hsmt@gmail.com>
-
- * enumerator.c (InitVM_Enumerator): Enumerator::Lazy#chunk_while
- defined. [Fix GH-1186]
- https://github.com/ruby/ruby/pull/1186
-
-Sun Nov 6 00:22:51 2016 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * vm_eval.c (vm_call0_cfunc_with_frame): pass method id to
- dtrace hook. follow up r56592.
-
-Sun Nov 6 00:06:38 2016 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb (Resolv::LOC::Coord.create): fixed.
- [ruby-core:72567] [Bug #11912] fixed by Eric Wong and Kazuhiro
- NISHIYAMA.
-
-Sun Nov 6 00:03:09 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in (-Wimplicit-fallthrough): gcc7 introduces case
- fall through warnings but it is too noisy.
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=7652
-
-Sat Nov 5 23:58:32 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * numeric.c (rb_int_round): cast to SIGNED_VALUE to suppress
- warnings by -Wsign-compare.
-
-Sat Nov 5 23:48:27 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * file.c (rb_home_dir_of): convert given username into filesystem
- encoding. [ruby-core:76682] [Bug #12652]
- patched by Davis Mosans
-
-Sat Nov 5 23:46:03 2016 Tanaka Akira <akr@fsij.org>
-
- * time.c (vtm_add_offset): Fix yday on last day of year.
- [ruby-core:72878] [Bug #11994] Fixed by Andrew White.
-
-Sat Nov 5 23:30:41 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * lib/net/http.rb (Net::HTTP.post): new convenience method to send
- a POST request. [ruby-core:75484] [Feature #12375]
-
-Sat Nov 5 23:03:54 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/net/http.rb (transport_request): other than HTTPContinue
- in 1xx (HTTPInformation) also needs to continue. [Bug #12890]
-
-Sat Nov 5 22:51:06 2016 Tanaka Akira <akr@fsij.org>
-
- * lib/time.rb (make_time): "now" argument as nil works again.
- This is broken since Ruby 2.2.
- Mathieu Jobin pointed a problem.
- https://github.com/ruby/ruby/commit/e4b05d91eb0d48fd172abf015c493bb42d755d07#commitcomment-17421387
-
-Sat Nov 5 22:50:13 2016 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/ipaddr.rb (IPAddr#==): If coercion fails, return false
- instead of passing through the exception. [ruby-core:77451]
- [Bug #12799]
-
- * lib/ipaddr.rb (IPAddr#<=>): If coercion fails, return nil
- instead of passing through the exception. [ruby-core:77451]
- [Bug #12799]
-
-Sat Nov 5 22:11:33 2016 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * vm_trace.c (tracepoint_attr_callee_id, rb_tracearg_callee_id):
- add TracePoint#callee_id. [ruby-core:77241] [Feature #12747]
-
- * cont.c, eval.c, gc.c, include/ruby/intern.h, insns.def, thread.c,
- vm.c, vm_backtrace.c, vm_core.h, vm_eval.c, vm_insnhelper.c, vm_trace.c: ditto.
-
- * test/ruby/test_settracefunc.rb: tests for above.
-
-Sat Nov 5 22:09:48 2016 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * eval.c, method.h, proc.c, vm.c, vm_eval.c, vm_insnhelper.c, vm_method.c:
- TracePoint#method_id should return method_id, not callee_id.
- [ruby-core:77241] [Feature #12747]
-
- * test/ruby/test_settracefunc.rb: change accordingly.
-
-Sat Nov 5 18:49:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (flo_round, int_round): support round-to-nearest-even
- semantics of IEEE 754 to match sprintf behavior, and add `half:`
- optional keyword argument for the old behavior.
- [ruby-core:76273] [Bug #12548]
-
-Sat Nov 5 18:17:54 2016 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/set.rb (Set#compare_by_identity, Set#compare_by_identity?):
- New methods. [Feature #12210]
-
-Sat Nov 5 18:17:08 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rdoc/*, test/rdoc/*: Update rdoc-5.0.0
- Release note: https://github.com/rdoc/rdoc/blob/b825775647f62c5b525e9780a28ff2fbb1d5bf6f/History.rdoc#500--2016-11-05
-
-Sat Nov 5 17:29:06 2016 Tanaka Akira <akr@fsij.org>
-
- * lib/resolv.rb (Resolv::DNS#extract_resources): Use each_resource
- instead of each_answer.
- [ruby-core:75461] [Bug #12372] reported by Rafael Fernandez Lopez.
-
-Sat Nov 5 17:18:24 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/-test-/file/fs.c (get_atime_p): Updating of file access times
- is enabled or not.
-
-Sat Nov 5 16:28:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (extract_getline_opts): extract chomp option.
- [Feature #12553]
-
-Sat Nov 5 15:58:24 2016 Sho Hashimoto <sho-h@netlab.jp>
-
- * tool/mkconfig.rb: [DOC] add rbconfig documentation.
-
-Sat Nov 5 15:42:52 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * lib/net/smtp.rb (tlsconnect): support timeout for TLS handshake.
- [ruby-core:76893] [Bug #12678]
-
- * lib/net/protocol.rb (ssl_socket_connect): new method to implement
- timeout for TLS handshake.
-
- * lib/net/http.rb (connect): use Net::Protocol#ssl_socket_connect.
-
-Sat Nov 5 14:17:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (brace_body, do_body): since cmdarg_stack is saved in
- VALUE val, should restore from the same member. on big-endian
- platforms where VALUE is larger than int, it restored 0 in the
- upper word. [ruby-core:77920] [Bug #12900]
-
-Sat Nov 5 13:52:52 2016 Akinori MUSHA <knu@iDaemons.org>
-
- * lib/shellwords.rb (Shellwords#shellsplit): Fix the handling of
- the backslash in double quotes to conform to the standard.
- [ruby-core:63807] [Bug #10055]
-
-Sat Nov 5 12:14:31 2016 Tanaka Akira <akr@fsij.org>
-
- * ext/pathname/pathname.c (Pathname#empty?): New method.
- [ruby-core:76404] [Feature #12596] Proposed by John Backus.
-
-Sat Nov 5 11:53:02 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * test/ruby/test_refinement.rb (test_refine_alias_in_subclass):
- add a test to check that alias in subclasses can be refined.
- [ruby-core:69374] [Bug #11186]
-
-Sat Nov 5 11:20:57 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * cont.c (cont_new): disable optimization if clang's version is
- 3.8.0. [ruby-core:77894] [Bug #12893]
-
-Sat Nov 5 10:07:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/ruby/test_file.rb (TestFile#test_stat): fix noatime case.
- [ruby-core:77943] [Bug #12903]
-
-Fri Nov 4 17:52:44 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (heap_page_resurrect): do not return tomb_pages when
- page->freelist == NULL.
- [Bug #12670]
-
-Fri Nov 4 16:31:45 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * util.c (ruby_dtoa): round to even, instead of rounding to
- nearest. [ruby-core:77864] [Bug #12889]
-
-Fri Nov 4 15:31:00 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: Add compiler version message into rbconfig
- as RbConfig::CONFIG['CC_VERSION_MESSAGE']. [Feature #12896]
-
-Fri Nov 4 13:03:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * numeric.c (rb_int_digits): Fix exception message
- [ruby-core:77502] [Bug #12815]
-
-Fri Nov 4 10:51:16 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/pathname/pathname.c (path_hash): fix unnormalized Fixnum
- value bug on mingw/mswin.
-
-Fri Nov 4 10:35:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/fileutils.rb (FileUtils::Entry_#copy): ensure that the
- source entry exists first, to fix error for non-existent entry.
- [ruby-core:77885] [Bug #12892]
-
-Thu Nov 3 21:45:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * ext/bigdecimal/bigdecimal.c: Import changes from ruby/bigdecimal
- repository.
-
-Thu Nov 3 15:01:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c: include sys/sysmacros.h for ArchLinux which deprecated
- use of major() and minor() in sys/types.h.
-
-Wed Nov 2 08:45:49 2016 Dmitry Gritsay <unseductable@gmail.com>
-
- * doc/extension.rdoc: set ANYARGS as arguments for func1 and func2.
-
- * doc/extension.rdoc: mention the exception object which is passed
- to func2 as the second argument. [Fix GH-1471]
-
-Wed Nov 2 07:34:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (rb_num_coerce_bit): enable bit operations with
- coercing by non-integer object. [ruby-core:77783] [Bug #12875]
-
-Tue Nov 1 01:31:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (ac_cv_func_round): round(3) in x86_64-w64-mingw32
- is not accurate in an edge case. [ruby-core:77794] [Bug #12878]
-
-Mon Oct 31 17:36:04 2016 Code Ahss <aycabta@gmail.com>
-
- * test/test_forwardable.rb (TestForwardable#test_on_private_method):
- add test for [Bug #12782] [Bug #12840]
-
-Mon Oct 31 11:08:51 2016 Samuel Williams <samuel.williams@oriontransfer.co.nz>
-
- * lib/uri/generic.rb (URI::Generic#merge): merge merge0.
- [GH-1469]
-
-Sun Oct 30 15:32:43 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update
- rubygems to 2.6.8.
- Release note of 2.6.8: https://github.com/rubygems/rubygems/commit/9fb8880976f5ab998912898b091d88aa10eb1d4a
-
-Sun Oct 30 06:39:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/windows_1254.c: Fix typo. Reported by k-takata at
- https://github.com/k-takata/Onigmo/commit/ceb59cc. Thanks!
-
-Sat Oct 29 19:59:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (cond0): !-operator is a method call, no warning for
- literal in condition. [ruby-core:77801] [Bug #12881]
-
-Sat Oct 29 10:09:38 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_compile_each): turn flip-flop in a not-operator
- into a boolean value. fix up r56315
-
-Sat Oct 29 09:39:14 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (vm_call0_body): follow the original class, not to
- loop the prepended module. [ruby-core:77784] [Bug #12876]
-
-Sat Oct 29 00:14:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enc/trans/windows-1255-tbl.rb: update mapping from 0xCA to
- U+05BA. [Feature #12877]
-
-Fri Oct 28 23:22:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enc/depend: extract transcode_tblgen method calls for libraries
- loaded by dynamically generated names, in single_byte.trans.
-
-Fri Oct 28 16:05:03 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * insns.def (opt_case_dispatch): extract float value only if the
- Float method is not redefined.
-
-Fri Oct 28 15:58:16 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * internal.h (RB_OBJ_BUILTIN_TYPE): special-const safe
- BUILTIN_TYPE.
-
-Fri Oct 28 15:20:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * complex.c (id_finite_p, id_infinite_p, id_rationalize, id_PI):
- initialize static IDs.
-
- * complex.c (FINITE_TYPE_P): extract predicate.
-
- * complex.c (rb_complex_finite_p, rb_complex_infinite_p): use
- dedicated predicates instead of switch by TYPE.
-
-Thu Oct 27 23:28:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_integer_type_p): turn into macro to help
- clang based on old gcc to eliminate CSE.
-
-Thu Oct 27 16:33:47 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * tool/redmine-backporter.rb (rel): check the exception and show right
- message.
-
-Thu Oct 27 14:57:33 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/socket/lib/socket.rb (UDPSocket#recvfrom_nonblock): [DOC] Remove
- a false statement "If _maxlen_ is omitted, its default value is
- 65536." maxlen, the first parameter, cannot be omitted as the method
- signature indicates. This hasn't changed ever since it was first
- implemented.
-
-Thu Oct 27 09:42:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (rb_convert_to_integer): convert a fixable float to a
- fixnum directly without the conversion method, as well as bignum
- case.
-
- * object.c (rb_convert_to_integer): should not drop the converted
- string.
-
-Wed Oct 26 17:09:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_intern): use prefixed version macro
- RUBY_CONST_ID_CACHE.
-
-Wed Oct 26 11:28:25 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
-
- * NEWS: added several entries which (if I remember correctly) are
- added in a year.
-
-Tue Oct 25 12:54:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (mnew_internal): follow the original class, not to loop
- the prepended module. [ruby-core:77591] [Bug #12832]
-
-Mon Oct 24 10:52:17 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/lib/test/unit.rb (Test::Unit::Parallel#deal): update the
- job status after a task finished, to show idling workers.
-
-Mon Oct 24 10:51:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * complex.c (Init_Complex): undefine methods inherited from
- Comparable, because Complex does not have <=> method.
- [Bug #12866]
-
- * class.c (rb_undef_methods_from): undefine methods defined in
- super from klass.
-
-Mon Oct 24 10:19:44 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * complex.c (Init_Complex): undefine Complex#clamp, which does not
- work like other Comparable methods, because Complex does not
- have <=> method. patched by Tim Peters <zomg.tim AT gmail.com>
- in [ruby-core:77720]. [Bug #12866]
-
-Sun Oct 23 11:41:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/encoding.h: include "ruby/ruby.h" explicitly for
- enum ruby_fl_type and VALUE.
-
-Sat Oct 22 23:33:55 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (reg_compile_gen): always append error message to the
- error buffer.
-
-Sat Oct 22 22:33:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (num_funcall1): check recursion by inverse pair, to
- fix fake infinite recursion. [ruby-core:77713] [Bug #12864]
-
-Sat Oct 22 18:52:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (rb_hash_compact_bang): should return nil if no elements
- is deleted. [ruby-core:77709] [Bug #12863]
-
-Sat Oct 22 10:28:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (DLDFLAGS): fallback to LDFLAGS.
- [ruby-core:72444] [Bug #11863]
-
- * configure.in (LIBRUBY_DLDFLAGS): fallback to DLDFLAGS.
-
- * configure.in (RUBY_APPEND_OPTION, RUBY_PREPEND_OPTION): expand
- the option to be appended/prepended when matching, as well as
- RUBY_APPEND_OPTIONS and RUBY_PREPEND_OPTIONS.
-
-Sat Oct 22 09:52:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (setup_args): duplicate splatting array if more
- arguments present to obey left-to-right execution order.
- [ruby-core:77701] [Bug# 12860]
-
-Fri Oct 21 16:44:44 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (do_opendir): retry after GC when the limit for open file
- descriptors reached.
-
-Fri Oct 21 16:06:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (open_load_file): retry after GC when the limit for open
- file descriptors reached.
-
-Fri Oct 21 11:34:17 2016 Pascal Schmid <Lechindianer@users.noreply.github.com>
-
- * string.c (rb_str_sub, rb_str_gsub): [DOC] 'backlash' should read
- 'backslash'. [Fix GH-1461]
-
-Thu Oct 20 17:02:56 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/uri/common.rb: added documentation for deprecated method.
- [Misc #11960][ruby-core:72733][ci skip]
-
-Thu Oct 20 16:57:23 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * ext/digest/digest.c: Add documentation for Digest.
- [Feature #10452][ruby-core:66001][ci skip]
- * remove HMAC from list of digest algorithms,
- * add MD5 in list of digest algorithms,
- * add information about writing a C digest implementation using Digest::Base,
- * add documentation for Digest::Base public methods.
- * ext/digest/md5/md5init.c: add examples for MD5.
- * ext/digest/rmd160/rmd160init.c: add examples for Digest::RMD160.
- * ext/digest/sha1/sha1init.c: add examples for Digest::SHA1.
-
-Thu Oct 20 16:19:51 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/open-uri.rb: Improved documentation grammar for
- open-uri#open option. [Misc #11329][ruby-core:69868][ci skip]
-
-Wed Oct 19 21:48:40 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * NEWS: mention refinements with Kernel#send and
- BasicObject#__send__. [Feature #11476]
-
-Wed Oct 19 17:02:15 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_call_opt_send): enable refinements with
- Kernel#send and BasicObject#__send__. [Feature #11476]
-
-Wed Oct 19 14:22:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * basictest/runner.rb: do not clobber the option by --run-opt with
- RUBYOPT. reported by Allen Hewes <rallenh AT hotmail.com>.
-
-Wed Oct 19 00:09:06 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * addr2line.c (parse_debug_line_cu): boundary checks for
- compressed debug sections. [ruby-dev:49840] [Bug #12850]
-
-Tue Oct 18 16:36:40 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (DLDFLAGS): append --compress-debug-sections=zlib
- if available, which reduces the size of LIBRUBY_SO by half or
- more.
-
-Mon Oct 17 16:20:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/configure.bat: add option to enable/disable to install
- static ruby library. defaulted to "no". [Feature #12845]
-
- * configure.in (install-static-library): add option to enable/
- disable to install static ruby library. defaulted to "no" if
- enable-shared. [Feature #12845]
-
- * tool/rbinstall.rb (local-arch-lib): respect the option.
-
-Sun Oct 16 15:09:06 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/windows_1254.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for Windows-1254.
-
-Sat Oct 15 14:17:05 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_args.c (refine_sym_proc_call): search and call method with
- refinements.
-
- * vm_args.c (vm_caller_setup_arg_block): enable refinements when
- enabled in the caller. [Feature #9451]
-
-Sat Oct 15 00:54:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * process.c (proc_exec_cmd): use UTF-8 version aspawn.
- [ruby-dev:49838] [Bug #12841]
-
-Fri Oct 14 22:26:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/optparse/kwargs.rb (OptionParser#define_by_keywords):
- [EXPERIMENTAL] extract command line option definitions from the
- information of keyword arguments.
-
-Fri Oct 14 18:27:18 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * object.c: Improve documentation for Float conversion.
- [ruby-core:71661][Bug #11736][ci skip]
-
-Fri Oct 14 18:00:20 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/logger.rb: Improve Logger.new option documentation.
- [Feature #12803][ruby-core:77467]
-
-Fri Oct 14 17:20:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/optparse.rb (make_switch, parse_in_order): unify underscores
- to hyphens.
-
-Fri Oct 14 10:48:37 2016 Eric Wong <e@80x24.org>
-
- * lib/webrick/utils.rb (TimeoutHandler): use monotonic clock
- (watch): ditto
-
-Thu Oct 13 19:41:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (copy_stream_body): use IO to write to copy to duplex IO.
- http://twitter.com/knu/status/786505317974585344
-
-Thu Oct 13 17:05:57 2016 Dwain Faithfull <dwfaithfull@gmail.com>
-
- * hash.c (rb_hash_compact, rb_hash_compact_bang): Removes nil
- values from the original hash, to port Active Support behavior.
- [Feature #11818]
-
-Thu Oct 13 11:35:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_sort_bang, rb_ary_sort, rb_ary_sort_by_bang):
- [DOC] describe that sort may not be stable.
-
- * enum.c (enum_sort, enum_sort_by): ditto.
-
-Thu Oct 13 11:31:40 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/rexml/xpath/test_text.rb (test_ancestors): Array#sort may
- not be stable. [ruby-core:76088] [Bug #12509]
-
- * test/rss/test_maker_{0.9,1.0,2.0}.rb (test_items): ditto.
-
-Thu Oct 13 10:37:31 2016 Eric Wong <e@80x24.org>
-
- * doc/extension.rdoc: wording fix
-
-Thu Oct 13 00:39:08 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/ruby/test_array.rb (test_sort_bang_with_freeze): make a
- clone to copy a <=> singleton method, instead of dup. which
- element will be called is not predictable.
- [ruby-core:76088] [Bug #12509]
-
-Thu Oct 13 00:21:27 2016 Simon Soriano <simon0191@gmail.com>
-
- * doc/extension.rdoc: Replace "You can defined hooked variables"
- with "You can define hooked variables". [Fix GH-1460]
-
-Wed Oct 12 21:05:50 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ruby.c (open_load_file): revert r56385. it introduced incompatibility
- about `DATA.binmode?`.
-
-Wed Oct 12 15:24:53 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * tool/downloader.rb: Removed verification of gem certification.
- Because signed gem is not working on rubygems ecosystem.
- * tool/gem-unpack.rb: ditto.
-
-Tue Oct 11 22:08:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (prep_io): fix typo of struct member name.
- [ruby-core:77550] [Bug #12829]
-
-Tue Oct 11 16:45:24 2016 Tanaka Akira <akr@fsij.org>
-
- * lib/uri/generic.rb (URI.find_proxy): Add an optional argument, env.
-
-Tue Oct 11 16:38:32 2016 Tanaka Akira <akr@fsij.org>
-
- * lib/pp.rb (String#pretty_print): Defined to print a string as
- multiple lines.
- [ruby-core:76800] [Feature#12664] proposed by Petr Chalupa.
-
-Mon Oct 10 15:22:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (open_load_file): bind the open fd to an IO instance
- before waiting FIFO, not to leak the fd if interrupted.
-
-Mon Oct 10 12:40:54 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (open_load_file): compare with EXEEXT instead of hard
- coded name, and do not match with mere EXEEXT.
-
- * ruby.c (open_load_file): open in binary mode if available, as
- parser deals with EOLs.
-
- * io.c (prep_io): reduce isatty call (and its system call) on
- Cygwin.
-
-Sun Oct 9 23:05:53 2016 Prathamesh Sonpatki <csonpatki@gmail.com>
-
- * array.c, class.c: Fixed documentation where Fixnum was referred
- directly to use Integer, as Fixnum and Bignum are now unified
- into Integer and direct usage is deprecated. [Fix GH-1459]
-
-Sun Oct 9 11:37:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_core.h (VM_ASSERT): stringify expr here before expansion in
- RUBY_ASSERT_WHEN.
-
-Sat Oct 8 10:54:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/-test-/memory_status/memory_status.c (read_status): use
- Win32 GetProcessMemoryInfo API.
-
- * ext/-test-/memory_status/memory_status.c: get memory sizes by
- mach task_info system call.
-
-Sat Oct 8 09:06:55 2016 Aurelien Jacobs <aurel@gnuage.org>
-
- * lib/logger.rb (Logger::Period#next_rotate_time): fix monthly log
- rotate when DST is applied during a month of 31 days.
- [Fix GH-1458]
-
-Fri Oct 7 20:21:39 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (gc_prof_setup_new_record): fix the condition to get
- rusage.
-
- * gc.c (gc_profile_dump_major_reason): remove undefined flags.
-
-Fri Oct 7 19:18:33 2016 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/*.c, ext/win32ole/win32ole.h: use RB_INT2FIX instead of
- INT2FIX, and so on.
-
-Fri Oct 7 14:18:40 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * basictest/test.rb: Adjust spaces in class declarations
- with inheritance. [fix GH-1227] Patch by @adrfer
- * lib/irb/*: ditto.
- * lib/prime.rb: ditto.
- * lib/shell/builtin-command.rb: ditto.
- * object.c: ditto.
- * sample/*.rb: ditto.
- * test/-ext-/method/test_arity.rb: ditto.
-
-Thu Oct 6 17:29:44 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * load.c (rb_require_safe): SyntaxError created by the parser just
- has the message and needs to set up the backtrace.
- [ruby-core:77491] [Bug #12811]
-
- * load.c (rb_load_internal0): load/require is not the main
- script.
-
-Thu Oct 6 13:35:15 2016 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * enum.c: [DOC] Improve doc [ci-skip]
-
-Thu Oct 6 11:38:14 2016 Chris Jones <chris@christopherjones.us>
-
- * ext/readline/extconf.rb: Update error message with correct words.
- [fix GH-1453][ci skip] Patch by @magikid
-
-Thu Oct 6 11:01:49 2016 Tieg Zaharia <tieg.zaharia@gmail.com>
-
- * lib/uri/common.rb (WEB_ENCODINGS_): Update URI::WEB_ENCODINGS_
- hash, and fix documented command to grab it. [Fix GH-1430]
-
-Thu Oct 6 10:37:13 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * enum.c: Add reduce/inject alias note.
- [fix GH-1400][ci skip] Patch by @getaaron
-
-Thu Oct 6 10:30:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (update_coverage): check coverage values, and ignore
- non-fixnum values.
-
-Thu Oct 6 09:19:21 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (fptr_finalize): use dedicated macro RB_INTEGER_TYPE_P.
-
-Wed Oct 5 18:02:44 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/net/http/response.rb: Improve document readability.
- [fix GH-1411][ci skip] Patch by @stz-seongheon
-
-Wed Oct 5 15:43:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * node.c (dump_node): flatten statements in NODE_BLOCK.
-
-Wed Oct 5 14:27:36 2016 Byron Bowerman <me@bm5k.com>
-
- * range.c: Add docs for max/min behavior with exclusive range.
- [fix GH-1433][ci skip] Patch by @BM5k
-
-Wed Oct 5 12:57:21 2016 Richard Schneeman <richard.schneeman+foo@gmail.com>
-
- * ext/socket/*.c: Add proper require for example to work.
- [fix GH-1378][ci skip] Patch by @schneems
-
-Wed Oct 5 11:47:19 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * io.c: Fixed equivalent ruby code with core implementation.
- [fix GH-1429][ci skip] Patch by @sos4nt
-
-Wed Oct 5 11:36:21 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/delegate.rb: Added missing spaces and Removed needless spaces.
- [fix GH-1454][ci skip] Patch by @bogdanvlviv
-
-Wed Oct 5 03:24:55 2016 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * enum.c: Make Enumerable#chunk with no block return
- an Enumerator [#2172]
-
-Wed Oct 5 01:19:45 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * internal.h (ST2FIX): new macro to convert st_index_t to Fixnum.
- a hash value of Object might be Bignum, but it causes many troubles
- especially the Object is used as a key of a hash. so I've gave up
- to do so.
-
- * array.c (rb_ary_hash): use above macro.
-
- * bignum.c (rb_big_hash): ditto.
-
- * hash.c (rb_obj_hash, rb_hash_hash): ditto.
-
- * numeric.c (rb_dbl_hash): ditto.
-
- * proc.c (proc_hash): ditto.
-
- * re.c (rb_reg_hash, match_hash): ditto.
-
- * string.c (rb_str_hash_m): ditto.
-
-Tue Oct 4 12:59:44 2016 Koichi ITO <koic.ito@gmail.com>
-
- * array.c (rb_ary_dig): [DOC] update an example of error message
- by Array#dig, because of Integer Unification. [Fix GH-1455]
-
-Tue Oct 4 09:55:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/bigdecimal/bigdecimal.c (BigDecimal_div2): need more room
- for precision to round. [ruby-core:77475] [Bug #12805]
-
-Tue Oct 4 06:05:46 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * regcomp.c (onig_print_compiled_byte_code): make the shown address
- look relative.
-
-Tue Oct 4 05:53:11 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * regexec.c (OPCODE_EXEC_HOOK): op is p-1 because p is already
- incremented.
-
- * regexec.c (OPCODE_EXEC_HOOK): use the exact end address.
-
- * regexec.c (match_at): don't call OPCODE_EXEC_HOOK in CASE()
- when it comes from goto fail.
-
-Mon Oct 3 21:24:41 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * NEWS: mention Readline.quoting_detection_proc{,=}.
-
-Mon Oct 3 21:19:46 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * lib/logger.rb: [DOC] Fix default value of shift_age.
-
-Mon Oct 3 17:20:05 2016 George Brocklehurst <ruby@georgebrock.com>
-
- * ext/readline/readline.c (readline_s_set_quoting_detection_proc):
- support rl_char_is_quoted_p. [Feature #12659]
-
- * ext/readline/readline.c (readline_s_get_quoting_detection_proc):
- ditto.
-
-Sun Oct 2 08:22:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (RB_INT2FIX, RB_LONG2FIX): prefix RB to
- global symbols to get rid of name conflicts with other headers.
-
-Sun Oct 2 07:51:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_hash_m): hash values may be negative.
-
-Sun Oct 2 02:04:12 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * string.c (rb_str_hash_m): st_index_t is not guaranteed as the same
- size with int, and of course also not guaranteed the value can be
- Fixnum.
-
-Sun Oct 2 02:03:06 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * numeric.c (rb_fix2str): detect unnormalized Fixnum value.
-
-Sat Oct 1 23:08:47 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/date/date_parse.c (date_zone_to_diff): it's nonsense and really
- harm that to use unary minus operator with unsigned value.
- get rid of test failures introduced at r56312.
-
-Sat Oct 1 22:17:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_compile_each): move numeric literal range
- optimization from fixup_nodes() in parse.y.
-
-Sat Oct 1 19:19:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (compile_flip_flop): simplify generated code.
-
- * compile.c (compile_branch_condition): flip-flop can appear only
- in conditional expressions.
-
-Sat Oct 1 02:02:02 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (poll_child_status): rb_w32_wait_events_blocking() sets
- errno internally, then should not set it here.
-
-Fri Sep 30 19:06:21 2016 Anton Davydov <mail@davydovanton.com>
-
- * lib/uri/http.rb: Documentation and code style improvements.
- * test/uri/test_http.rb: Added test for coverage.
- [fix GH-1427][ruby-core:77255][Misc #12756]
-
-Fri Sep 30 18:43:20 2016 Jason Yeo <jason@jasonyeo.me>
-
- * doc/syntax/control_expressions.rdoc: Add missing 'as'
- [ci skip][fix GH-1448] Patch by @jsyeo
-
-Thu Sep 29 23:38:04 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * lib/yaml/store.rb (YAML::Store#dump): use table argument instead
- of @table directly.
-
-Thu Sep 29 22:22:22 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * lib/yaml/store.rb (YAML::Store#initialize): Fix arguments.
- [ruby-dev:49821] [Bug #12800]
-
- * test/yaml/test_store.rb: Add tests from test/test_pstore.rb.
-
- * test/yaml/test_store.rb (YAMLStoreTest#test_with_options): Add options test.
-
- * lib/yaml/store.rb (YAML::Store#dump): Revert to to_yaml.
-
- * lib/yaml/store.rb (YAML::Store#empty_marshal_data): Use to_yaml with options.
-
- * lib/yaml/store.rb (YAML::Store#empty_marshal_checksum): Use CHECKSUM_ALGO.
-
-Thu Sep 29 19:34:23 2016 Pete Higgins <pete@peterhiggins.org>
-
- * thread_sync.c (rb_queue_pop, rb_szqueue_push, rb_szqueue_pop):
- Document exception types, ThreadError, raised by Queue and
- SizedQueue. [Fix GH-1451]
-
-Thu Sep 29 19:21:02 2016 Pete Higgins <pete@peterhiggins.org>
-
- * thread_sync.c (Init_thread_sync): Remove confusing doc comments,
- which are picked up by rdoc unexpectedly, from Queue and
- SizedQueue. [Fix GH-1450]
-
-Wed Sep 28 23:14:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/pstore.rb (PStore::CHECKSUM_ALGO): find available hashing
- algorithm for checksum. MD5 is not available in FIPS mode.
- [Feature #6943]
-
-Wed Sep 28 13:00:25 2016 ksss <co000ri@gmail.com>
-
- * signal.c (sig_signame): [DOC] Add documentation in the case of
- return nil. [Fix GH-1449]
-
-Wed Sep 28 10:43:27 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
-
- * .travis.yml: delete comments. They were outdated.
-
-Wed Sep 28 09:57:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update
- rubygems to 2.6.7.
- Release note of 2.6.7: https://github.com/rubygems/rubygems/commit/60f35bd1d2359fc30301d2d4cd72bc6833e8d12a
-
-Wed Sep 28 00:21:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (rb_warning_s_warn): the argument must be an
- ASCII-compatible string. [ruby-core:77430] [Bug #12793]
-
-Tue Sep 27 23:22:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (symbol, dsym, parser_set_number_literal): set state to
- ENDARG, so that `do` after a literal should be `do_block` and
- bound to the outer method. [ruby-core:72482] [Bug #11873]
-
- * parse.y (parse_ident): revert r56198.
-
- * parse.y (warn_balanced): the state of symbol and numeric
- literals is now EXPR_ENDARG, do not exclude it.
-
-Tue Sep 27 22:59:42 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
-
- * NEWS: news about Warning.warn.
-
-Tue Sep 27 18:10:18 2016 Jeremy Evans <code@jeremyevans.net>
-
- * error.c: This makes all warnings raised call Warning.warn, which
- by default does the same thing it does currently
- (rb_write_error_str). You can override Warning.warn to change
- the behavior. [ruby-core:75016] [Feature #12299]
-
-Tue Sep 27 17:35:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * iseq.c (iseqw_s_compile_file): deal with syntax error as well as
- compile, and should not abort when rescued.
-
-Tue Sep 27 12:07:17 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/cgi/cookie.rb (parse): don't allow , as a separator. [Bug #12791]
-
- * lib/webrick/cookie.rb (parse): ditto.
-
-Mon Sep 26 21:37:21 2016 Akinori MUSHA <knu@iDaemons.org>
-
- * man/erb.1, man/irb.1, man/ri.1, man/ruby.1: Remove Ns before
- punctuation.
-
-Mon Sep 26 16:23:49 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/stringio/stringio.c (strio_seek): Avoid signed integer overflow.
- It's not harmful in practice here, but is still undefined behavior.
-
- * ext/stringio/stringio.c (strio_extend): Check that the new length does
- not exceed LONG_MAX. This fixes the invalid write on the overflow.
-
- * test/stringio/test_stringio.rb (test_write_integer_overflow): Add a
- test case for the above fix in strio_extend().
-
-Mon Sep 26 15:43:34 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * eval_intern.h (TH_PUSH_TAG): Initialize struct rb_vm_tag::tag with
- Qundef rather than 0 which is equal to Qfalse. Since Kernel#throw(obj)
- searches a tag with rb_vm_tag::tag == obj, throw(false) can
- accidentally find an unrelated tag which is not created by
- Kernel#catch. [ruby-core:77229] [Bug #12743]
-
- * test/ruby/test_exception.rb (test_throw_false): Add a test case for
- this.
-
-Mon Sep 26 14:36:12 2016 Naotoshi Seo <sonots@gmail.com>
-
- * lib/tempfile.rb: provide default basename parameter for
- Tempfile.create. [Feature #11965] Patch by Yuki Kurihara
- * test/test_tempfile.rb: ditto.
-
-Mon Sep 26 14:10:54 2016 Ary Borenszweig <ary@esperanto.org.ar>
-
- * string.c (lstrip_offset): add a fast path in the case of single
- byte optimizable strings, as well as rstrip_offset.
- [ruby-core:77392] [Feature #12788]
-
-Mon Sep 26 12:00:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gems/bundled_gems: update to minitest-5.9.1.
-
-Mon Sep 26 11:50:03 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * tool/rbinstall.rb (gem): Don't install gemspec if no files will be
- installed for the gem. This happens when the extension library is not
- compiled.
-
-Mon Sep 26 11:06:47 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * string.c (enc_strlen, rb_enc_strlen_cr): Avoid signed integer
- overflow. The result type of a pointer subtraction may have the same
- size as long. This fixes String#size returning an negative value on
- i686-linux environment:
-
- str = "\x00" * ((1<<31)-2))
- str.slice!(-3, 3)
- str.force_encoding("UTF-32BE")
- str << 1234
- p str.size
-
-Sun Sep 25 22:48:06 2016 namusyaka <namusyaka@gmail.com>
-
- * lib/erb.rb (ERB::Compiler::TrimScanner#stag): The :stag accessor
- has already been available because it is defined in parent
- Scanner class. [Fix GH-1445]
-
-Sun Sep 25 19:21:26 2016 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * node.c (dump_array): remove duplicate header of NODE_ARRAY/
- NODE_VALUES.
-
-Sat Sep 24 22:26:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb (extract_makefile, extmake, configuration): store
- extra libraries to be installed.
-
- * tool/rbinstall.rb (ext-arch): install extra libraries.
-
- * ext/zlib/extconf.rb: install zlib if built.
-
-Sat Sep 24 14:24:55 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * spec/README: update URL.
-
-Sat Sep 24 11:28:22 2016 Koichi ITO <koic.ito@gmail.com>
-
- * fix typos, "a" before "Integer" to "an". [Fix GH-1438]
-
-Sat Sep 24 10:19:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/misc/test_ruby_mode.rb (assert_indent): since write-region
- in Emacs 25.1 no longer displays the "Wrote file" message, shows
- the explicit message to check if successfully finished.
- [ruby-core:77355] [Bug #12785]
-
- * test/misc/test_ruby_mode.rb (EXPR_SAVE): use a numeric prefix
- argument of 0, not to make the previous version into a backup
- file, instead of backup-inhibited.
-
- * test/misc/test_ruby_mode.rb (run_emacs): always save the buffer
- if modified.
-
-Fri Sep 23 23:57:40 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * vm_method.c (make_method_entry_refined): fix wrong use of ||.
-
-Fri Sep 23 21:38:58 2016 Akinori MUSHA <knu@iDaemons.org>
-
- * tool/mdoc2man.rb (Mdoc2Man#parse_macro): Add support for the
- `Lk` macro.
-
- * tool/mdoc2man.rb (Mdoc2Man#shift_arg): A new function to extract
- a possibly quoted argument.
-
-Fri Sep 23 20:36:05 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * eval.c (rb_mod_refine): refine modules as well.
- [ruby-core:76199] [Feature #12534]
-
-Fri Sep 23 20:19:09 2016 Akinori MUSHA <knu@iDaemons.org>
-
- * man/ruby.1: Update the paragraphs in "Rich Libraries" which
- included a dead link.
-
-Fri Sep 23 20:05:27 2016 Akinori MUSHA <knu@iDaemons.org>
-
- * man/ruby.1, man/erb.1, man/irb.1, man/ri.1: Use the `Lk` macro
- for hyperlinks, which has been available since mdocml 1.5.1
- (released more than seven years ago).
-
-Fri Sep 23 15:47:04 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/forwardable.rb (_delegator_method): allow private methods to
- be delegated, with warnings. [ruby-core:77341] [Bug #12782]
-
-Fri Sep 23 12:15:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_peephole_optimize): enable tail call
- optimization inside a conditional block.
-
-Thu Sep 22 13:00:04 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * gc.c (gc_start_internal): [DOC] methods without arguments
- like r56194. [Bug #12777]
-
-Wed Sep 21 17:43:53 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * process.c (InitVM_process): Support CLOCK_MONOTONIC_RAW_APPROX,
- CLOCK_UPTIME_RAW, and CLOCK_UPTIME_RAW_APPROX which are introduced
- by macOS 10.12.
-
-Wed Sep 21 13:47:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (brace_body, do_body): preserve cmdarg_stack so that
- `do` after cmdarg in a block should be `do_block` and bound to
- the outer method. [ruby-core:72482] [Bug #11873]
-
- * parse.y: `do` after cmdarg in parentheses should be `do_block`
- and bound to the outer method. [ruby-core:72482] [Bug #11873]
-
- * parse.y (brace_body, do_body): extract block bodies.
-
-Tue Sep 20 23:02:50 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (gc_start_internal): [DOC] add ObjectSpace.garbage_collect
- and fix GC#garbage_collect. [Bug #12777]
-
-Tue Sep 20 21:24:01 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * doc/extension.ja.rdoc: translate r56189 (rb_gc_adjust_memory_usage).
-
-Tue Sep 20 17:52:28 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * gems/bundled_gems: Update rake-11.3.0
-
-Tue Sep 20 16:52:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (rb_gc_adjust_memory_usage): notify memory usage to the GC
- engine by extension libraries, to trigger GC. [Feature #12690]
-
-Mon Sep 19 17:05:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (Init_Numeric), bignum.c (Init_Bignum): deprecate
- Fixnum and Bignum. this may be reverted after previews.
- [Feature #12739]
-
-Mon Sep 19 10:36:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enumerator.c (lazy_init_yielder): directly call stored functions.
- [Feature #6183]
-
- * enumerator.c (lazy_add_method): create lazy enumerator which
- uses lazy_init_yielder().
-
-Sun Sep 18 22:48:54 2016 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rss/rss.rb (RSS::BaseModel): Remove needless codes.
- [Bug #12773][ruby-dev:49813]
- Reported by Kazuhiro NISHIYAMA. Thanks!!!
-
-Sun Sep 18 19:23:47 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * lib/sync.rb: Fix NameError when error.
-
-Sat Sep 17 22:46:02 2016 Koichi ITO <koic.ito@gmail.com>
-
- * vm_insnhelper.c (vm_throw_start): Remove too much ";"
- [fix GH-1432]
-
-Sat Sep 17 19:19:06 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * test/openssl/test_ssl.rb (test_ctx_options): Fix test failure on
- Ubuntu 16.04. The fix in r56147 was incomplete. This is a cherry-pick
- of the commit b039f3e268c2 at ruby/openssl.
-
-Sat Sep 17 10:49:35 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * doc/extension.ja.rdoc: translate r56130 (rb_check_arity).
-
-Sat Sep 17 02:40:52 2016 Aaron Patterson <tenderlove@ruby-lang.org>
-
- * ext/objspace/objspace_dump.c: Fix stream processing support for heap
- dumps. Full heap dumps should use JSON lines (http://jsonlines.org)
- so that we can process very large heaps without loading the entire
- heap dump in to memory at once.
-
-Fri Sep 16 22:10:31 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * ext/openssl/ossl_ssl.c (ssl_npn_select_cb_common): Fix compile error
- with old version of fcc (Fujitsu C Compiler) on Solaris 10.
- [Bug #12769] [ruby-dev:49809]
-
-Fri Sep 16 21:28:25 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * internal.h (MAYBE_UNUSED): The fallback definition is needed.
- Fix compile error with some non-GCC compilers such as
- Oracle Solaris Studio 12.3 on Solaris 10.
- [Bug #12767] [ruby-dev:49807]
-
- * internal.h (WARN_UNUSED_RESULT): ditto.
-
-Fri Sep 16 21:19:51 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * hash.c (each_pair_i_fast): Fix compile error with old version of
- fcc on Solaris 10. [Bug #12768] [ruby-dev:49808]
-
-Fri Sep 16 19:46:05 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/Makefile.sub (config.h): fixed compile error with VC introduced
- by previous commit.
-
-Fri Sep 16 14:54:34 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
-
- * internal.h (WARN_UNUSED_RESULT): moved to configure.in, to
- actually check its availability rather to check GCC's version.
-
- * configure.in (WARN_UNUSED_RESULT): moved to here.
-
- * configure.in (RUBY_FUNC_ATTRIBUTE): change function declaration
- to return int rather than void, because it makes no sense for a
- warn_unused_result attributed function to return void.
-
- Funny thing however is that it also makes no sense for noreturn
- attributed function to return int. So there is a fundamental
- conflict between them. While I tested this, I confirmed both
- GCC 6 and Clang 3.8 prefers int over void to correctly detect
- necessary attributes under this setup. Maybe subject to change
- in future.
-
- * internal.h (UNINITIALIZED_VAR): renamed to MAYBE_UNUSED, then
- moved to configure.in for the same reason we move
- WARN_UNUSED_RESULT.
-
- * configure.in (MAYBE_UNUSED): moved to here.
-
- * internal.h (__has_attribute): deleted, because it has no use now.
-
- * string.c (rb_str_enumerate_lines): refactor macro rename.
-
- * string.c (rb_str_enumerate_bytes): ditto.
-
- * string.c (rb_str_enumerate_chars): ditto.
-
- * string.c (rb_str_enumerate_codepoints): ditto.
-
- * thread.c (do_select): ditto.
-
- * vm_backtrace.c (rb_debug_inspector_open): ditto.
-
- * vsnprintf.c (BSD_vfprintf): ditto.
-
-Fri Sep 16 14:35:55 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
-
- * ChangeLog (add-log-time-format): Not exactly sure when but
- recently (25.x maybe), emacs changed its API to take optional
- two arguments. We have to follow that.
-
-Fri Sep 16 06:43:25 2016 Aaron Patterson <tenderlove@ruby-lang.org>
-
- * lib/uri/generic.rb (def check_password): don't include bad password
- in URI exception output
-
- * test/uri/test_generic.rb (def test_set_component): test for behavior
-
-Thu Sep 15 21:40:03 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * doc/extension.ja.rdoc: Fix file name.
-
-Thu Sep 15 00:59:30 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * benchmark/: add vnmakarov's benchmarks around hash [ruby-core:75265]
-
-Wed Sep 14 07:02:31 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * hash.c (each_pair_i_fast): use rb_yield_values2 to avoid var args.
-
-Tue Sep 13 21:32:54 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * string.c (STR_HEAP_SIZE, RESIZE_CAPA_TERM, str_new0, rb_str_buf_new,
- str_shared_replace, rb_str_init, str_make_independent_expand,
- rb_str_resize): Avoid overflow by casting the length to size_t. size_t
- should be able to represent LONG_MAX+termlen.
-
- * string.c (rb_str_modify_expand): Check that the new length is in the
- range of long before resizing. Also refactor to use RESIZE_CAPA_TERM
- macro.
-
- * string.c (str_buf_cat): Fix so that it does not create a negative
- length String. Also fix the condition for 'string sizes too big', the
- total length can be up to LONG_MAX.
-
- * string.c (rb_str_plus): Check the resulting String length does not
- exceed LONG_MAX.
-
- * string.c (rb_str_dump): Fix integer overflow. The dump result will be
- longer then the original String.
-
-Tue Sep 13 21:30:53 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * gc.c (heap_extend_pages, get_envparam_size, ruby_malloc_size_overflow,
- gc_profile_dump_on): Use PRIuSIZE instead of PRIdSIZE as the passed
- value is size_t, not ssize_t.
-
- * iseq.c (get_line_info, rb_iseq_disasm_insn): Ditto.
-
- * sprintf.c (rb_str_format): Ditto.
-
- * thread_win32.c (native_thread_create): Ditto.
-
- * vm.c (get_param): Ditto.
-
- * ext/objspace/objspace_dump.c (dump_append_string_content,
- dump_object): Ditto.
-
- * ext/socket/raddrinfo.c (host_str, port_str): Ditto.
-
-Tue Sep 13 21:27:35 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * string.c (STR_EMBEDDABLE_P): Renamed from STR_EMBEDABLE_P(). And use
- it in more places.
-
-Tue Sep 13 21:23:51 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * README.md: Drop support for BeOS now that Haiku is stable since
- 2.3.0.
-
- * README.ja.md: ditto.
-
-Tue Sep 13 21:11:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (STR_EMBEDABLE_P): extract the predicate macro to tell
- if the given length is capable in an embedded string, and fix
- possible integer overflow.
-
-Tue Sep 13 18:37:08 2016 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_exception.rb: fix thread issues.
- * use Queue instead of a local variable for synchronization.
- * join created thread to solve leaking threads warning.
-
-Tue Sep 13 16:07:26 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * string.c (rb_str_set_len): The buffer overflow check is wrong. The
- space for termlen is allocated outside the capacity returned by
- rb_str_capacity(). This fixes r41920 ("string.c: multi-byte
- terminator", 2013-07-11). [ruby-core:77257] [Bug #12757]
-
- * test/-ext-/string/test_set_len.rb (test_capacity_equals_to_new_size):
- Test for this change. Applying only the test will trigger [BUG].
-
-Tue Sep 13 06:03:34 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * common.mk (benchmark): fix lib path.
-
-Tue Sep 13 00:39:47 2016 Aaron Patterson <tenderlove@ruby-lang.org>
-
- * class.c (singleton_class_of): Copy superclass serial number to
- singleton class. This improves singleton class IMC hit rates.
- [Feature #12364] [ruby-core:75425]
-
-Mon Sep 12 13:46:23 2016 Anton Davydov <mail@davydovanton.com>
-
- * lib/uri/mailto.rb: Removed needless `return` and use `.` instead of `::`
- with class method.
- * test/uri/test_mailto.rb: Added tests for coverage.
- [fix GH-1426][Misc #12750][ruby-core:77242]
-
-Sun Sep 11 21:30:26 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * NEWS: News about Module.used_modules.
-
-Sun Sep 11 19:06:49 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (rb_w32_write_console): should set written length as the
- return value. [Bug #12748] [ruby-dev:49786]
-
-Fri Sep 9 22:43:29 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * gems/bundled_gems: sort lines.
-
-Fri Sep 9 17:59:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (rb_threadptr_raise): set cause from the called thread,
- but not from the thread to be interrupted.
- [ruby-core:77222] [Bug #12741]
-
-Fri Sep 9 13:50:05 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * doc/extension.rdoc, doc/extension.ja.rdoc: fix file name.
- pointed out by @takkanm in the RubyKaigi talk.
-
-Fri Sep 9 13:14:53 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * News: Announcing update to Unicode version 9.0.0 [ci skip]
-
-Fri Sep 9 10:10:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * variable.c (rb_const_search): warn with the actual class/module
- name which defines the deprecated constant.
-
- * variable.c (rb_const_search): raise with the actual class/module
- name which defines the private constant.
-
-Thu Sep 8 17:47:18 2016 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * array.c (flatten): use rb_obj_class instead of rb_class_of
- because rb_class_of may return a singleton class.
- [ruby-dev:49781] [Bug #12738]
-
-Thu Sep 8 17:40:15 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/rbinstall.rb (gem): use the bindir of each gemspec instead
- of hardcoded 'bin', since rdoc 5.0.0 overrides it.
-
-Thu Sep 8 16:47:03 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * eval.c (rb_mod_s_used_modules): rename Module.used_refinements to
- Module.used_modules. [Feature #7418] [ruby-core:49805]
-
-Thu Sep 8 14:21:48 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * ext/psych/psych.gemspec, lib/rdoc/rdoc.gemspec: Use file list instead of
- git output. It shows warning message when invoke `make install`
- [Bug #12736][ruby-dev:49778]
-
-Thu Sep 8 13:41:46 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * insns.def (setclassvariable, setconstant): warn when self is a
- refinement. [Bug #10103] [ruby-core:64143]
-
-Thu Sep 8 11:29:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * hash.c (rb_hash_transform_values, rb_hash_transform_values_bang):
- Rename map_v to transform_values.
- [Feature #12512] [ruby-core:76095]
-
- * test/ruby/test_hash.rb: ditto.
-
-Thu Sep 8 10:08:35 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * {ext,test}/openssl: Import Ruby/OpenSSL 2.0.0.beta.2. The full commit
- history since v2.0.0.beta.1 can be found at:
- https://github.com/ruby/openssl/compare/v2.0.0.beta.1...v2.0.0.beta.2
-
-Thu Sep 8 07:23:34 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rdoc/*, test/rdoc/*: Update rdoc-5.0.0.beta2
- Fixed ri parse defect with left-hand matched classes.
- https://github.com/rdoc/rdoc/pull/420
-
-Thu Sep 8 01:12:47 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * eval.c (rb_mod_s_used_refinements): new method
- Module.used_refinements. based on the patch by Charlie
- Somerville. [Feature #7418] [ruby-core:49805]
-
-Wed Sep 7 17:50:38 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/util.h (setenv): remove POSIX-noncompliant
- definition with 2 arguments.
-
-Wed Sep 7 17:35:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * unicode/8.0.0/casefold.h, name2ctype.h, unicode/data/8.0.0:
- removing directories/files related to Unicode version 8.0.0
-
-Wed Sep 7 17:21:55 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/timeout.rb (Timeout#timeout): add custom error message
- argument. [Feature #11650]
-
-Wed Sep 7 17:13:05 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * common.mk: Updated Unicode version to 9.0.0 [Feature #12513]
-
- * unicode/9.0.0/casefold.h, name2ctype.h, unicode/data/9.0.0:
- new directories/files for Unicode version 9.0.0
-
-Wed Sep 7 16:00:45 2016 Tanaka Akira <akr@fsij.org>
-
- * lib/open-uri.rb: Allow http to https redirection.
- Note that https to http is still forbidden.
- [ruby-core:20485] [Feature #859] by Roman Shterenzon.
-
-Wed Sep 7 14:56:59 2016 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * lib/csv.rb (CSV::{Row,Table}#{each,delete_if}): returns an enumerator
- if no block is given. [ruby-core:75346] [Feature #12347]
-
- * test/csv/test_row.rb: add test for above.
-
- * test/csv/test_table.rb: ditto.
-
-Wed Sep 7 14:50:01 2016 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * gems/bundled_gems: update to power_assert 0.3.1.
-
-Wed Sep 7 12:16:09 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * ext/psych/*, test/psych/*: Update psych-2.1.1
- This version fixed following pull requests.
- https://github.com/tenderlove/psych/pull/284
- https://github.com/tenderlove/psych/pull/276
-
-Wed Sep 7 11:51:06 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rdoc/*, test/rdoc/*: Update rdoc-5.0.0.beta1
- This version is mostly same as r56072. It contains to remove code
- for Ruby 1.8
-
-Tue Sep 6 09:23:06 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rdoc/rdoc.gemspec: partly reverted for default gem installer.
- upstream configuration is not working on ruby core repository.
-
-Mon Sep 5 19:35:22 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rdoc/*, test/rdoc/*: Update rdoc/rdoc master(f191513)
- https://github.com/rdoc/rdoc/blob/master/History.rdoc#423--2016--
- https://github.com/rdoc/rdoc/blob/master/History.rdoc#422--2016-02-09
-
-Sun Sep 4 00:17:55 2016 Sho Hashimoto <sho-h@ruby-lang.org>
-
- * proc.c: [DOC] fix Object#define_singleton_method and
- main.define_method return value. [ci skip]
-
-Sat Sep 3 11:28:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread_pthread.c (ruby_init_stack): check stack bounds even if
- get_main_stack succeeded, on the "co-routine" case.
- https://github.com/ruby/ruby/commit/53953ee#commitcomment-18887413
-
-Fri Sep 2 16:06:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * internal.h (MEMO_V1_SET, MEMO_V2_SET): fix typos. use the macro
- parameter, not the local variable.
-
-Fri Sep 2 00:55:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb (timestamp_file): move extmk.rb specific tricks
- from lib/mkmf.rb. keep RUBYCOMMONDIR prefix not to conflict
- with a timestamp file in the toplevel.
-
-Thu Sep 1 14:24:16 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb (gems): move dirty hacks for bundled gems from
- mkmf.rb.
-
- * lib/mkmf.rb (create_makefile): yield all configuration strings.
-
-Wed Aug 31 17:39:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb (create_makefile): make gem.build_complete file
- under TARGET_SO_DIR and install it only when the gem build
- succeeded. [ruby-core:77057] [Bug #12681]
-
-Wed Aug 31 15:36:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb: move TARGET_SO_DIR stuffs to mkmf.rb.
-
- * lib/mkmf.rb (create_makefile): create target shared object files
- under $(TARGET_SO_DIR) which is $sodir if it is defined with
- $extout. [ruby-core:77058] [Bug #12681]
-
-Wed Aug 31 01:56:55 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * doc/extension.ja.rdoc: [DOC] Fix a typo. [ci skip]
-
-Wed Aug 31 00:52:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb: make the gems target directory under the expanded
- name. [ruby-core:77102] [Bug #12714]
-
-Tue Aug 30 15:27:27 2016 Kouhei Yanagita <yanagi@shakenbu.org>
-
- * ext/json/lib/json/add/ostruct.rb (OpenStruct.json_create):
- Correct documentation, fix the name of values. [Fix GH-1421]
-
-Tue Aug 30 14:53:34 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * io.c (nogvl_fsync, nogvl_fdatasync): on Windows, just ignore if the
- fd is associated to non-disk device. if call fsync and/or fdatasync
- with such fds, it causes Errno::EBADF exception and the behavior is
- incompatible with ruby 2.1 and earlier unintentionally introduced.
-
-Tue Aug 30 03:38:35 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_dump.c (backtrace): use rip in the saved context for the case
- the SIGSEGV is received when the process is in userland.
- Note that ip in the stack should be used if the signal is received
- when it is in kernel (when it is calling syscall) [Bug #12711]
-
-Sat Aug 27 10:26:14 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * array.c (rb_ary_concat_multi): take multiple arguments. based
- on the patch by Satoru Horie. [Feature #12333]
-
- * string.c (rb_str_concat_multi, rb_str_prepend_multi): ditto.
-
-Thu Aug 25 00:42:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/file.c (append_wstr): remove a codepage argument, and use
- INVALID_CODE_PAGE for conversion by econv.
-
- * win32/file.c (append_wstr): exclude the terminator from the
- result length when input len == -1.
-
-Wed Aug 24 22:41:30 2016 Kouhei Sutou <kou@cozmixng.org>
-
- * gc.c (gc_reset_malloc_info): Remove too much ";".
-
-Wed Aug 24 20:07:57 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * include/ruby/defines.h (ALWAYS_INLINE): Add alternative definition.
- Fix compile error with compilers that do not have force inline
- attribute, including old version of fcc on Solaris 10.
- [ruby-dev:49773] [Bug #12701]
-
-Wed Aug 24 16:56:26 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * .gdbinit: follow r55766's VM change.
-
-Wed Aug 24 12:57:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (rb_mod_initialize, rb_class_initialize): [DOC] these
- methods do not invoke module_eval/class_eval, just eval the
- given block under the new module/class but sharing the context
- with the surrounding scope like those methods.
- [ruby-core:77023] [Bug #12696]
-
-Tue Aug 23 10:34:40 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/psych/test_psych.rb (test_load_file_with_fallback): fix
- Tempfile leak. https://github.com/tenderlove/psych/pull/288
-
-Tue Aug 23 10:15:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_fs_setter): check and convert $; value at
- assignment.
-
-Tue Aug 23 02:09:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_split_m): show $; name in error message when it
- is a wrong object.
-
-Mon Aug 22 16:29:52 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/csv.rb (CSV#shift): store partial quoted strings in an array
- and join at last, to improve performance with very long quoted
- lines. [ruby-core:76987] [Bug #12691]
-
-Mon Aug 22 14:35:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * man/irb.1: remove useless -width option.
- [ruby-dev:49767] [Bug #12692]
-
-Mon Aug 22 09:02:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * iseq.c (Init_ISeq): undefine allocator of InstructionSequence,
- to get rid of segfaults at method call on uninitialized object.
-
-Sat Aug 21 05:47:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * enum.c (enum_sort): prevent wasteful array duplication.
-
-Sat Aug 20 11:20:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * rubystub.c: generalize win32/stub.c.
-
-Fri Aug 19 11:39:06 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (primary): allow parenthesised statement as a method
- argument. [Feature #12686]
-
-Fri Aug 19 09:12:45 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm.c (vm_set_main_stack): TOPLEVEL_BINDING must be built.
- http://www.viva64.com/en/b/0414/#ID0EQ1CI [ruby-core:76973]
-
-Fri Aug 19 01:00:53 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * proc.c (mnew_missing): Remove an unused argument.
- After r51126 rid is not used.
-
-Thu Aug 18 09:26:52 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * gems/bundled_gems: bump to test-unit-3.2.1
-
-Thu Aug 18 02:36:26 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/rbinstall.rb: skip gems which failed to build extensions.
- [ruby-dev:49764] [Bug #12683]
-
-Wed Aug 17 23:35:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gems/bundled_gems (tk): bump up to 0.1.1.
-
-Wed Aug 17 23:14:42 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb: build gem extensions into separate directories
-
- * tool/rbinstall.rb: install pre-built gem extension files gem
- extension directories. [ruby-core:76931] [Bug #12681]
-
-Tue Aug 16 21:04:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (UNICODE_HDR_DIR): separate unicode header files from
- unicode data files. [ruby-core:76879] [Bug #12677]
-
-Tue Aug 16 11:17:51 2016 Koichi ITO <koic.ito@gmail.com>
-
- * lib/net/http/header.rb: Fix typo. [ci skip][fix GH-1407]
- * transcode.c: ditto.
-
-Tue Aug 16 11:02:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/make-snapshot (package): save generated header files from
- unicode data. [ruby-core:76879] [Bug #12677]
-
-Mon Aug 15 20:31:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * node.c (dump_array): show nd_alen field in NODE_ARRAY only in
- the first node. it is nd_end in the rest nodes.
-
-Mon Aug 15 16:41:32 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * appveyor.yml: Update libressl version to 2.3.7.
-
-Mon Aug 15 11:46:50 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb (extmake): extension libraries in gems cannot link
- statically.
-
-Sun Aug 14 22:35:40 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * id_table.c (hash_table_extend): should not shrink the table than
- the previous capacity. [ruby-core:76534] [Bug #12614]
-
-Sun Aug 14 18:51:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gems/bundled_gems: add gemified tk 0.1.0.
- this needs `extract-gems` to build.
-
-Sun Aug 14 14:54:14 2016 Kouhei Sutou <kou@cozmixng.org>
-
- * object.c (InitVM_Object): Update referenced document path.
-
-Sat Aug 13 23:08:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (num_funcall0, num_funcall1): get rid of infinite
- recursion in fallback methods of Numeric.
-
-Sat Aug 13 11:10:08 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (command_asgn, arg): fix syntax errors with chained
- assignment with op assign. [Bug #12669]
-
-Sat Aug 13 10:52:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (stmt, arg): rescue modifier in command op assignment
- should be limited to rhs only. [ruby-core:75621] [Bug #12402]
-
-Sat Aug 13 07:51:40 2016 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (ole_val2variant): fix integer conversion in
- cygwin64.
-
-Fri Aug 12 21:05:19 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/webrick/config.rb (WEBrick::Config::General):
- disable reverse lookup by default. [ruby-core:45514] [Feature #6559]
- Socket.do_not_reverse_lookup is true by default but WEBrick
- overwrote it.
- patch by Eric Hodel [ruby-core:45527]
-
-Fri Aug 12 12:50:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (rb_syntax_error_append): fix newline in syntax error
- message to the beginning, not after file name and line number.
- [Feature #11951]
-
-Thu Aug 11 16:24:23 2016 Ferdinand Niedermann <nerdinand@nerdinand.com>
-
- * compar.c (cmp_clamp): Introduce Comparable#clamp. [Feature #10594]
-
-Thu Aug 11 03:16:59 2016 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/prime.rb: Optimize prime?
- Adapted from patch by Jabari Zakiya [#12665]
-
- * test/test_prime.rb: Improve test
-
-Wed Aug 10 22:37:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (command_rhs, arg_rhs): introduce new rules to reduce
- repeated rules with rescue modifier.
-
-Wed Aug 10 17:26:43 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (command_asgn): rescue modifier in command assignment
- should be limited to rhs only. [ruby-core:75621] [Bug #12402]
-
-Wed Aug 10 15:35:03 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32/resolv/resolv.c: needs windows.h for iphlpapi.h on
- cygwin. [ruby-core:76791] [Bug #12663]
-
- * ext/win32/resolv/resolv.c (w32error_make_error): use
- Win32::Resolv::Error, an alias of Win32::Registry::Error.
-
-Tue Aug 9 17:50:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * hash.c (rb_hash_map_v, rb_hash_map_v_bang): implement Hash#map_v and
- Hash#map_v! [Feature #12512] [ruby-core:76095]
-
- * test/ruby/test_hash.rb: add tests for above change.
-
-Tue Aug 9 16:09:03 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_insnhelper.c (vm_getivar): use always_inline because
- gcc7 doesn't inline this without always_inline.
-
-Tue Aug 9 15:41:24 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/tk: Tk is removed from stdlib. [Feature #8539]
- https://github.com/ruby/tk is the new upstream.
-
-Tue Aug 9 00:12:31 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * doc/maintainers.rdoc: Remove moved file section.
-
-Mon Aug 8 20:56:46 2016 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/sample/excel1.rb, ext/win32ole/sample/excel2.rb,
- ext/win32ole/sample/excel3.rb, ext/win32ole/sample/ie.rb,
- ext/win32ole/sample/ienavi.rb, ext/win32ole/sample/ienavi2.rb: use
- true instead of deprecated TRUE. [ci skip]
-
-Mon Aug 8 12:51:12 2016 Zarko Todorovski <zarko@ca.ibm.com>
-
- * internal.h (RBASIC_CLEAR_CLASS): Reroute ANSI C's strict
- aliasing rule.
- [ruby-core:74427][Bug #12191][ruby-core:76747][Bug #12657]
-
-Sun Aug 7 18:08:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (InitVM_Object): deprecate toplevel constants TRUE,
- FALSE, and NIL. [Feature #12574]
-
-Sun Aug 7 06:48:21 2016 Eric Wong <e@80x24.org>
-
- * ext/openssl/ossl_ssl.c (ossl_ssl_write_internal):
- avoid undefined behavior
- * test/openssl/test_pair.rb (test_write_zero): new test
- [ruby-core:76751] [Bug #12660]
-
-Sat Aug 6 09:35:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * id_table.h (rb_id_table_iterator_result): add dummy sentinel
- member because C standard prohibits a trailing comma.
-
-Sat Aug 6 00:39:44 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (env_enc_str_new): make string for an environment
- variable name or value.
-
- * hash.c (env_name_new): make environment value string with the
- encoding for its name.
-
-Fri Aug 5 23:18:35 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * hash.c (env_str_new): taint the string. get rid of a test failure
- introduced at r55811.
-
-Fri Aug 5 17:04:02 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (w32_getenv): call rb_w32_getenv and rb_w32_ugetenv via
- this pointer without further comparisons.
-
-Thu Aug 4 11:54:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (env_assoc): the encoding of the value should be the
- locale, as well as other methods, [], fetch, values, etc.
-
-Wed Aug 3 21:31:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (reg_fragment_enc_error): compile_error is different
- between parser and ripper. [ruby-core:76397] [Bug #12651]
-
-Wed Aug 3 17:15:06 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (rb_obj_clone2): restrict freeze option to true other
- than false which only has the effect. [Feature #12300]
-
-Wed Aug 3 10:47:07 2016 Koichi Sasada <ko1@atdot.net>
-
- * vm_core.h: introduce VM_FRAME_RUBYFRAME_P()
- and VM_FRAME_CFRAME_P().
- Most of case, RUBY_VM_NORMAL_ISEQ_P() is no
- longer needed.
-
- * vm_core.h: introduce rb_obj_is_iseq().
-
- * cont.c, vm.c: VM_FRAME_MAGIC_DUMMY with
- VM_FRAME_FLAG_CFRAME.
-
-Wed Aug 3 09:25:16 2016 Koichi Sasada <ko1@atdot.net>
-
- * vm_core.h: rename macros and make them inline functions.
-
- * rename VM_FRAME_TYPE_FINISH_P() to VM_FRAME_FINISHED_P().
- * rename VM_FRAME_TYPE_BMETHOD_P() to VM_FRAME_BMETHOD_P().
-
-Wed Aug 03 09:15:02 2016 Koichi Sasada <ko1@atdot.net>
-
- * vm_core.h: introduce VM_FRAME_FLAG_CFRAME to represent cfp->iseq
- type.
-
-Tue Aug 2 21:42:40 2016 Chia-sheng Chen <qitar888@gmail.com>
-
- * math.c (tanh): make faster by the extract form if three
- hyperbolic functions are unavailable. [Feature #12647]
-
-Tue Aug 2 12:37:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/socket/option.c, ext/socket/rubysocket.h (inet_ntop): share
- the fallback definition. [ruby-core:76646] [Bug #12645]
-
-Tue Aug 2 04:07:29 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (set_pioinfo_extra): use more reliable way to search
- the position of pioinfo of VC14, and also support debug library of it.
- patched by davispuh AT gmail.com
- [ruby-core:76644] [Bug #12644]
- this fixes also [Bug #12631]
-
-Mon Aug 1 21:39:52 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb: [EXPERIMENTAL] build extension libraries in
- extracted gems.
-
-Mon Aug 1 16:07:18 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
-
- * include/ruby/ruby.h (struct RStruct): no longer.
-
- * internal.h (struct RStruct): moved here.
-
- * struct.c (rb_struct_ptr): a compensation function for the lack
- of RSTRUCT_PTR. But now that we have RSTRUCT_GET/SET, that must
- not be used anyway. I mark this deprecated. Dont use it.
-
-Mon Aug 1 14:50:06 2016 Jeremy Evans <code@jeremyevans.net>
-
- * object.c (rb_obj_clone2): Allow Object#clone to take freeze:
- false keyword argument to not freeze the clone.
- [ruby-core:75017][Feature #12300]
-
- * test/ruby/test_object.rb (TestObject): test for it.
-
-Mon Aug 1 12:16:19 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * ext/json/*, test/json/json_parser_test.rb: Update json-2.0.2.
-
-Sun Jul 31 16:17:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32/resolv/resolv.c (get_dns_server_list): [Win32] get DNS
- servers only for connected network devices by GetNetworkParams
- API. [Bug #12604]
-
-Sat Jul 30 12:13:26 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c (String#downcase), NEWS: Mentioned that case mapping for all
- of ISO-8859-1~16 is now supported. [ci skip]
-
-Sat Jul 30 12:00:01 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_2.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for ISO-8859-2, by Yushiro Ishii.
-
-Fri Jul 29 20:57:12 2016 chuanshuo <lilijreey@126.com>
-
- * *.c: rename rb_funcall2 to rb_funcallv, except for extensions
- which are/will be/may be gems. [Fix GH-1406]
-
-Fri Jul 29 10:51:34 2016 Koichi Sasada <ko1@atdot.net>
-
- * proc.c (env_write): remove unused function.
-
-Fri Jul 29 10:49:52 2016 Koichi Sasada <ko1@atdot.net>
-
- * vm_core.h (VM_LOCAL_P): should return an integer value.
- reported at
- http://d.hatena.ne.jp/nagachika/20160728/ruby_trunk_changes_55764_55770
-
-Fri Jul 29 04:23:08 2016 Koichi Sasada <ko1@atdot.net>
-
- * vm_core.h (VM_ENV_LOCAL_P): return truthy (0 or not) value.
-
- * vm.c (rb_vm_make_proc_lambda): use VM_ENV_ESCAPED_P() macro.
-
-Fri Jul 29 03:49:04 2016 Koichi Sasada <ko1@atdot.net>
-
- * vm.c, internal.h: remove RubyVM::Env class and all of env objects
- are imemo objects (imemo_env).
-
- * NEWS: describe this change. I believe nobody touch these objects
- because there are no method defined.
-
- * vm_core.h: remove the following definitions.
- * rb_cEnv decl.
- * GetEnvPtr() because Env is no longer T_DATA object.
-
- * vm_core.h (rb_env_t): fix layout for imemo values.
-
- * vm_core.h (vm_assert_env): added.
-
- * vm_core.h (vm_env_new): added.
-
-Thu Jul 28 19:53:21 2016 Koichi Sasada <ko1@atdot.net>
-
- * vm_core.h: revisit the structure of frame, block and env.
- [Bug #12628]
-
- This patch introduce many changes.
-
- * Introduce concept of "Block Handler (BH)" to represent
- passed blocks.
-
- * move rb_control_frame_t::flag to ep[0] (as a special local
- variable). This flags represents not only frame type, but also
- env flags such as escaped.
-
- * rename `rb_block_t` to `struct rb_block`.
-
- * Make Proc, Binding and RubyVM::Env objects wb-protected.
-
- Check [Bug #12628] for more details.
-
-Thu Jul 28 15:05:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (ruby_fl_type): use __extension__ to get rid
- of pedantic warning against RUBY_FL_USER19.
- https://github.com/skylightio/skylight-ruby/issues/64
-
- * include/ruby/ruby.h (rb_mul_size_overflow): ditto for use of
- int128.
-
-Wed Jul 27 10:32:59 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/windows_1253.c: Remove dead code found by Coverity Scan.
-
-Tue Jul 26 22:43:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (run_finalizer): make saved running finalizer state
- volatile to ensure not to be clobbered by longjmp.
-
-Tue Jul 26 19:26:00 2016 Koichi Sasada <ko1@atdot.net>
-
- * vm_insnhelper.c: introduce rb_vm_pop_frame() and use it
- instead of setting rb_thread_t::cfp directly.
-
- * vm_insnhelper.c (vm_pop_frame): return the result of
- finish frame or not.
-
-Tue Jul 26 19:06:39 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (rb_raw_obj_info): support to show Proc obj.
-
-Tue Jul 26 18:55:55 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_mark): add `inline' explicitly.
- I expected to inline this function implicitly at the loop
- (ex: marking T_ARRAY objects) but sometimes it remains as
- normal call.
-
-Tue Jul 26 16:33:16 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/windows_1257.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for Windows-1257, by Sho Koike.
-
-Tue Jul 26 16:19:41 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/windows_1250.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for Windows-1250, by Sho Koike.
-
- * ChangeLog: Fixed order of previous two entries.
-
-Tue Jul 26 15:54:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/windows_1253.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for Windows-1253, by Takumi Koyama.
-
-Tue Jul 26 15:30:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/windows_1251.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for Windows-1251, by Shunsuke Sato.
-
-Tue Jul 26 13:04:59 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive.rb: Add explicit skip test for
- availability of Unicode data files.
-
-Mon Jul 25 21:33:13 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * range.c (check_step_domain): check step argument domain by <=>
- method, instead of < and >.
-
-Mon Jul 25 21:11:32 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * doc/maintainers.rdoc: fix filenames.
-
-Mon Jul 25 16:59:00 2016 Koichi Sasada <ko1@atdot.net>
-
- * debug.c (ruby_debug_printf): use rb_raw_obj_info()
- instead of rb_inspect() because it is more robust way
- to see object internal.
-
-Sun Jul 24 16:33:13 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * regenc.h/c, include/ruby/oniguruma.h, enc/ascii.c, big5.c, cp949.c,
- emacs_mule.c, euc_jp.c, euc_kr.c, euc_tw.c, gb18030.c, gbk.c,
- iso_8859_1|2|3|4|5|6|7|8|9|10|11|13|14|15|16.c, koi8_r.c, koi8_u.c,
- shift_jis.c, unicode.c, us_ascii.c, utf_16|32be|le.c, utf_8.c,
- windows_1250|51|52|53|54|57.c, windows_31j.c, unicode.c:
- Remove conditional compilation macro ONIG_CASE_MAPPING. [Feature #12386].
-
-Sun Jul 24 12:53:42 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * doc/maintainers.rdoc: xmlrpc is bundled gem from Ruby 2.4.
-
-Sun Jul 24 12:07:39 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * doc/maintainers.rdoc: Update OpenSSL maintainer.
-
-Sat Jul 23 22:43:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * internal.h (Check_Type): inline check for the object type.
-
-Sat Jul 23 04:06:04 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (RTEST, NIL_P): use RUBY prefixed name in
- macros.
-
-Sat Jul 23 01:41:29 2016 Eric Wong <e@80x24.org>
-
- * lib/webrick/httpservlet/cgihandler.rb (do_GET): delete HTTP_PROXY
- * test/webrick/test_cgi.rb (test_cgi_env): new test
- * test/webrick/webrick.cgi (do_GET): new endpoint to dump env
- [ruby-core:76511] [Bug #12610]
-
-Fri Jul 22 19:55:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm.c (vm_set_main_stack): remove unnecessary check. toplevel
- binding must be initialized. [Bug #12611] (N1)
-
- * win32/win32.c (w32_symlink): fix return type. [Bug #12611] (N3)
-
- * string.c (rb_str_split_m): simplify the condition.
- [Bug #12611](N4)
-
-Fri Jul 22 17:13:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c (String#dump): Change escaping of non-ASCII characters in
- UTF-8 to use upper-case four-digit hexadecimal escapes without braces
- where possible [Feature #12419].
-
- * test/ruby/test_string.rb (test_dump): Add tests for above.
-
-Fri Jul 22 10:35:35 2016 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/rexml/attribute.rb (REXML::Attribute#to_string): Fix wrong
- entry reference name of double quote.
- [Bug #12609][ruby-core:76509]
- Patch by Joseph Marrero. Thanks!!!
-
-Fri Jul 22 10:32:13 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * template/unicode_norm_gen.tmpl: Remove
- UnicodeNormalize::UNICODE_VERSION at origin [Feature #12546].
-
-Fri Jul 22 09:23:51 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * LEGAL: Added entries for files under the USD license.
- [Bug #12598][ruby-core:76428][ci skip]
-
-Fri Jul 22 09:19:57 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * LEGAL: Added entry for `lib/rdoc/generator/template/darkfish/css/fonts.css`
- [Misc #12550][ruby-core:76255][ci skip]
-
-Fri Jul 22 06:28:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (run_finalizer): push and exec tag just once, instead of
- protecting for each finalizer.
-
- * gc.c (gc_start_internal, rb_gc_start): set finalizing flag
- whenever calling deferred finalizers not to recurse.
-
-Thu Jul 21 22:26:40 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * missing/strl{cat,cpy}.c: Update latest upstream files.
- [Misc #12205][ruby-core:74487]
- * LEGAL: Update license for missing/strl{cat,cpy}.c.
-
-Thu Jul 21 21:53:30 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * LEGAL: added file list with Public domain license.
- [ruby-core:76254][Bug #12549]
-
-Wed Jul 20 17:44:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enumerator.c (lazy_uniq): new method Enumerator::Lazy#uniq.
- [Feature #11090]
-
- * enum.c (enum_uniq): new method Enumerable#uniq.
- [Feature #11090]
-
-Wed Jul 20 17:35:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (rb_hash_add_new_element): add new element or do nothing
- if it is contained already.
-
- * array.c (ary_add_hash, ary_add_hash_by): use
- rb_hash_add_new_element.
-
-Tue Jul 19 18:21:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * lib/unicode_normalize/tables.rb: Remove
- UnicodeNormalize::UNICODE_VERSION (#12546).
-
-Tue Jul 19 15:38:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * variable.c (rb_local_constants_i): exclude private constants
- when excluding inherited constants too. [Bug #12345]
-
-Sun Jul 17 23:42:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * numeric.c (num_finite_p, num_infinite_p): Add Numeric#finite? and
- Numeric#infinite? [Feature #12039] [ruby-core:73618]
-
- * complex.c (rb_complex_finite_p): Add Complex#finite?
-
- * complex.c (rb_complex_infinite_p): Add Complex#infinite?
-
- * test/ruby/test_bignum.rb: Add test for Integer#finite? and
- Integer#infinite?
-
- * test/ruby/test_fixnum.rb: ditto.
-
- * test/ruby/test_rational.rb: Add test for Rational#finite? and
- Rational#infinite?
-
- * test/ruby/test_complex.rb: Add test for Complex#finite? and
- Complex#infinite?
-
-Sun Jul 17 20:59:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk, enc/depend (casefold.h, name2ctype.h): move to
- unicode data directory per version.
-
-Sat Jul 16 06:26:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk, enc/Makefile.in: moved timestamp files for
- directories under the specific directory, to get rid of match
- with files under the source directory.
-
-Fri Jul 15 22:05:13 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * string.c (str_buf_cat): Fix potential integer overflow of capa.
- In addition, termlen is used instead of +1.
-
-Fri Jul 15 21:30:38 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * string.c (str_buf_cat): Fix capa size for embed string.
- Fix bug in r55547. [Bug #12536]
-
-Fri Jul 15 18:13:15 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * gems/bundled_gems: update latest gems.
-
-Fri Jul 15 17:08:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * util.c (ruby_strtod): do not underflow only by preceding zeros,
- which may be canceled out by the exponent.
- http://twitter.com/kazuho/status/753829998767714305
-
-Fri Jul 15 09:53:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enc/unicode/case-folding.rb, tool/enc-unicode.rb: check if
- Unicode versions are consistent with each other.
-
-Fri Jul 15 08:25:15 2016 Jeremy Evans <code@jeremyevans.net>
-
- * string.c (STR_BUF_MIN_SIZE): reduce from 128 to 127
- [ruby-core:76371] [Feature #12025]
- * string.c (rb_str_buf_new): adjust for above reduction
-
-Thu Jul 14 17:26:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * Makefile.in (enc/unicode/name2ctype.h): remove stale recipe,
- which did not support Unicode age properties.
-
- * common.mk (enc/unicode/name2ctype.h): update by --header option
- of tool/enc-unicode.rb. enc/unicode/name2ctype.kwd file has not
- been used.
-
- * common.mk (enc/unicode/name2ctype.kwd): rule to create from
- Unicode data files, used only when the target does not exist.
-
-Thu Jul 14 13:10:54 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/json/lib/json/ext: remove stale directory. bundled
- extension libraries are placed under the directory for each
- architectures, but not mixed with plain text script libraries.
-
-Thu Jul 14 12:48:47 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * ext/json/**/*.rb: merge original files from upstream repository.
- It only fixes styles of frozen string literal.
-
-Wed Jul 13 22:23:03 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * test/json/json_common_interface_test.rb: use assert_raise instead of
- assert_raises.
-
-Wed Jul 13 22:14:23 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * test/lib/test/unit.rb: added test files with `_test` suffix for json
- upstream.
- * test/json: merge original test files from json upstream.
-
-Wed Jul 13 18:09:42 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_9.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for ISO-8859-9, by Kazuki Iijima.
-
- * enc/iso_8859_9.c: Exclude dotless i/I with dot from case-insensitive
- matching because they are not a case pair.
-
- * test/ruby/enc/test_iso_8859.rb: Make test coverage for ISO-8859-9
- a bit more complete.
-
-Wed Jul 13 17:21:24 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/windows_1252.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for Windows-1252, by Serina Tai.
-
- * test/ruby/enc/test_case_comprehensive.rb: Fix order of encodings.
-
-Wed Jul 13 16:19:14 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_7.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for ISO-8859-7, by Kosuke Kurihara.
-
- * test/ruby/enc/test_case_comprehensive.rb: Fix order of encodings.
-
-Wed Jul 13 16:08:08 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_mark_roots): should mark the VM object itself to mark
- singleton class of the VM object.
- Before this patch, we only set mark bit for the VM object and
- invoke mark function separately.
- [Bug #12583]
-
- * test/ruby/test_gc.rb: add a test.
-
-Wed Jul 13 15:59:59 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * math.c (_USE_MATH_DEFINES): it must be set before including internal.h
- because internal.h includes ruby.h, ruby.h includes win32.h, and
- win32.h includes system's math.h.
- this change is to get rid of a compiler warning (redefinition of
- a macro) introduced at r55641.
-
-Wed Jul 13 15:19:03 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_1.c, enc/iso_8859_4.c: Avoid setting modification flag if
- there is no modification.
-
-Wed Jul 13 14:40:04 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_5.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for ISO-8859-5, by Masaru Onodera.
-
- * test/ruby/enc/test_case_comprehensive.rb: Fix order of encodings.
-
-Wed Jul 13 14:28:33 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * math.c (rb_math_sqrt): r55646 must use f_signbit.
-
-Wed Jul 13 14:22:50 2016 Koichi Sasada <ko1@atdot.net>
-
- * iseq.c (Init_ISeq): undef ISeq.translate and ISeq.load_iseq
- to prevent calling super classes' methods.
-
- Without this patch, you can write workaround like:
-
- class << RubyVM::InstructionSequence
- def translate; end
- undef translate
- end
-
- * test/ruby/test_iseq.rb: add a test.
-
-Wed Jul 13 14:16:03 2016 Koichi Sasada <ko1@atdot.net>
-
- * vm_method.c (method_entry_get_without_cache): check
- undefined method even if ruby_running is FALSE.
-
- We haven't call "undef"ed methods before ruby_running.
- So that this issue does not make troubles.
-
-Wed Jul 13 14:15:22 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/windows_1254.c: Adjust variable/macro names.
-
-Wed Jul 13 13:19:12 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_9.c, enc/windows_1254.c: Split Windows-1254 from
- ISO-8859-9 to be able to implement different case conversions.
-
-Wed Jul 13 13:08:30 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_7.c, enc/windows_1253.c: Split Windows-1253 from
- ISO-8859-7 to be able to implement different case conversions.
-
-Wed Jul 13 10:50:12 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_13.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for ISO-8859-13, by Kanon Shindo.
-
-Wed Jul 13 10:31:39 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_13.c, enc/windows_1257.c: Split Windows-1257 from
- ISO-8859-13 to be able to implement different case conversions.
-
-Wed Jul 13 09:02:30 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_3.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for ISO-8859-3, by Takuya Miyamoto.
-
- * test/ruby/enc/test_case_comprehensive.rb: Extend special treatment
- for Turkic.
-
- * enc/iso_8859_3.c: Exclude dotless i/I with dot from case-insensitive
- matching because they are not a case pair.
-
-Wed Jul 13 08:40:21 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_iso_8859.rb: Exclude dotless i/I with dot from
- case-insensitive matching because they are not a case pair.
-
-Tue Jul 12 23:13:43 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * math.c (rb_math_sqrt): [EXPERIMENTAL] move Complex sqrt support
- from mathn.rb.
-
-Tue Jul 12 01:25:09 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * configure.in, lib/mkmf.rb, win32/Makefile.sub (CSRCFLAG): make the
- compiler option replacable in Makefile.
-
- * win32/Makefile.sub (OUTFLAG, COUTFLAG): ditto.
-
- * win32/Makeile.sub, win32/setup.mak (CC): should not append `-nologo`
- option forcely.
-
-Mon Jul 11 18:05:40 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_1.c: Moved test for lowercase characters without
- uppercase equivalent.
-
-Mon Jul 11 17:49:25 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_4.c, enc/iso_8859_10.c, enc/iso_8859_14.c,
- enc/iso_8859_15.c, enc/iso_8859_16.c: Replace case-by-case code with
- lookup in ENC_ISO_8859_xx_TO_LOWER_CASE table.
-
-Mon Jul 11 16:00:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/stringio/stringio.c (strio_each, strio_readlines): convert
- arguments just once before reading, instead of conversions for
- each lines, as r55603.
-
-Sun Jul 10 19:53:41 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_10.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for ISO-8859-10, by Toya Hosokawa.
-
-Sun Jul 10 19:33:47 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive.rb: Changed testing logic to
- catch unintended modifications of characters that do not have a case
- equivalent in the respective encoding.
- * enc/iso_8859_1.c, enc/iso_8859_15.c: Fixed unintended modifications of
- micro sign and y with diaeresis.
-
-Sun Jul 10 17:05:36 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_4.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for ISO-8859-4, by Kotaro Yoshida.
-
-Sun Jul 10 16:17:47 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive.rb: Fixed a comment
- (message belongs to last commit). [ci skip]
-
-Sun Jul 10 14:27:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * util.c (ruby_dtoa): [EXPERIMENTAL] adjust the case that the
- Float value is close to the exact but unrepresentable middle
- value of two values in the given precision, as r55604.
-
-Sun Jul 10 08:57:20 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * thread.c: Fixed implicit conversion error with Apple clang-800.0.31
-
-Sat Jul 9 12:43:09 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * lib/getoptlong.rb: use false instead of FALSE.
-
-Fri Jul 8 21:49:28 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * thread.c (rb_wait_for_single_fd): Clean up fds.revents every time
- before calling ppoll(2). [Bug #12575] [ruby-dev:49725]
-
-Fri Jul 8 14:16:48 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * vm_args.c (vm_caller_setup_arg_block): call rb_sym_to_proc()
- directly to reduce method dispatch overhead.
-
-Fri Jul 8 08:43:31 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * io.c (rb_io_s_read): add description of pipes to the documentation
- of IO.read.
-
-Fri Jul 8 03:54:22 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_args.c (setup_parameters_complex): don't raise ArgumentError
- if an array is given for instance_exec with optional argument.
- [ruby-core:76300] [Bug #12568]
- https://github.com/rails/rails/pull/25699
-
-Fri Jul 8 00:47:36 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_eval.c (yield_under): change prototype to get argc/argv.
-
- * vm_eval.c (specific_eval): change for above.
-
- * vm_eval.c (rb_obj_instance_exec): avoid object allocation.
-
- * vm_eval.c (rb_mod_module_exec): ditto.
-
-Thu Jul 7 20:08:37 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * vm_args.c (vm_caller_setup_arg_block): disable symbol block
- argument optimization when tail call optimization is enabled,
- in order to avoid SEGV. [ruby-core:76288] [Bug #12565]
-
-Thu Jul 7 16:37:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (flo_round): [EXPERIMENTAL] adjust the case that the
- receiver is close to the exact but unrepresentable middle value
- of two values in the given precision.
- http://d.hatena.ne.jp/hnw/20160702
-
-Thu Jul 7 16:31:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (rb_io_s_foreach, rb_io_s_readlines): convert arguments
- just once before reading, instead of conversions for each lines.
-
-Wed Jul 6 19:54:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_14.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for ISO-8859-14, by Yutaro Tada.
-
-Wed Jul 6 19:24:48 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_1.c, enc/iso_8859_15.c, enc/iso_8859_16.c:
- Align indenting to onigmo convention.
-
-Wed Jul 6 18:59:13 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_15.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for ISO-8859-15, by Maho Harada.
-
-Wed Jul 6 18:34:21 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_16.c, test/ruby/enc/test_case_comprehensive.rb:
- Implement non-ASCII case conversion for ISO-8859-16, by Satoshi Kayama.
-
-Wed Jul 6 14:44:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (create_makefile): store $headers in LOCAL_HDRS for
- depend files.
-
- * ext/digest/digest_conf.rb (digest_conf): add implementation
- specific headers to $header.
-
- * ext/digest/{md5,rmd160,sha1,sha2}/depend: add LOCAL_HDRS to the
- dependencies.
-
-Wed Jul 6 08:59:35 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * lib/net/http/generic_request.rb (write_header): A Request-Line must
- not contain CR or LF.
-
-Wed Jul 6 07:11:27 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * lib/net/ftp.rb (putline): raise an ArgumentError when
- CR or LF is included in a line.
-
-Tue Jul 5 20:49:30 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * ext/json/*, test/json/*: Update json-2.0.1.
- Changes of 2.0.0: https://github.com/flori/json/blob/f679ebd0c69a94e3e70a897ac9a229f5779c2ee1/CHANGES.md#2015-09-11-200
- Changes of 2.0.1: https://github.com/flori/json/blob/f679ebd0c69a94e3e70a897ac9a229f5779c2ee1/CHANGES.md#2016-07-01-201
- [Feature #12542][ruby-dev:49706][fix GH-1395]
-
-Tue Jul 5 19:39:49 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * string.c (rb_str_change_terminator_length): New function to change
- termlen and resize heap for the terminator. This is split from
- rb_str_fill_terminator (str_fill_term) because filling terminator
- and changing terminator length are different things. [Bug #12536]
-
- * internal.h: declaration for rb_str_change_terminator_length.
-
- * string.c (str_fill_term): Simplify only to zero-fill the terminator.
- For non-shared strings, it assumes that (capa + termlen) bytes of
- heap is allocated. This partially reverts r55557.
-
- * encoding.c (rb_enc_associate_index): rb_str_change_terminator_length
- is used, and it should be called whenever the termlen is changed.
-
- * string.c (str_capacity): New static function to return capacity
- of a string with the given termlen, because the termlen may
- sometimes be different from TERM_LEN(str) especially during
- changing termlen or filling terminator with specific termlen.
-
- * string.c (rb_str_capacity): Use str_capacity.
-
-Tue Jul 5 11:07:14 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * pack.c (pack_pack): use union instead of bare variable to ease
- optimizations and avoid assigning x87 floating point number.
- [ruby-core:74496] [Bug #12209]
-
- * pack.c (pack_unpack): ditto.
-
-Mon Jul 4 13:56:34 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * process.c: define sig_t if not exist.
- at least Solaris 10 and 11 doesn't have sig_t.
-
-Mon Jul 4 13:08:48 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * random.c (random_ulong_limited): avoid left shift count >= width of
- type on 32bit environment.
-
-Sun Jul 3 18:51:42 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive.rb, test_regex_casefold.rb,
- test/test_unicode_normalize.rb: Replace UNICODE_VERSION from
- UnicodeNormalize with RbConfig::CONFIG['UNICODE_VERSION'] from
- feature 12460.
-
-Sun Jul 3 06:04:09 2016 Eric Wong <e@80x24.org>
-
- * process.c (disable_child_handler_fork_child): simplify
- [ruby-core:75781] [Misc #12439]
-
-Sun Jul 3 05:25:46 2016 Eric Wong <e@80x24.org>
-
- * tool/asm_parse.rb: add description
- * tool/change_maker.rb: ditto
- * tool/downloader.rb: ditto
- * tool/eval.rb: ditto
- * tool/expand-config.rb: ditto
- * tool/extlibs.rb: ditto
- * tool/fake.rb: ditto
- * tool/file2lastrev.rb: ditto
- * tool/gem-unpack.rb: ditto
- * tool/gen_dummy_probes.rb: ditto
- * tool/gen_ruby_tapset.rb: ditto
- * tool/generic_erb.rb: ditto
- * tool/id2token.rb: ditto
- * tool/ifchange: ditto
- * tool/insns2vm.rb: ditto
- * tool/instruction.rb: ditto
- * tool/jisx0208.rb: ditto
- * tool/merger.rb: ditto
- * tool/mkrunnable.rb: ditto
- * tool/node_name.rb: ditto
- * tool/parse.rb: ditto
- * tool/rbinstall.rb: ditto
- * tool/rbuninstall.rb: ditto
- * tool/rmdirs: ditto
- * tool/runruby.rb: ditto
- * tool/strip-rdoc.rb: ditto
- * tool/vcs.rb: ditto
- * tool/vtlh.rb: ditto
- * tool/ytab.sed: ditto
- * tool/enc-unicode.rb: fix typo
- * tool/mk_call_iseq_optimized.rb: ditto
- * tool/update-deps: ditto
- [ruby-core:76215] [Bug #12539]
- by Noah Gibbs <the.codefolio.guy@gmail.com>
-
-Sat Jul 2 18:04:24 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/mailto.rb (initialize): RFC3986_Parser#split sets opaque
- only if the URI has path-rootless, not path-empty.
- [ruby-core:76055] [Bug #12498]
- patched by Chris Heisterkamp <cheister@squareup.com>
-
-Sat Jul 2 04:26:14 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * regcomp.c (noname_disable_map): don't optimize out group 0
- Ruby's Regexp doesn't allow normal numbered groups if the regexp
- has named groups. On such case it optimizes out related NT_ENCLOSE.
- But even on the case it can use \g<0>.
- This fix not to remove NT_ENCLOSE whose regnum is 0.
- [ruby-core:75828] [Bug #12454]
-
-Sat Jul 2 03:09:27 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * string.c: Partially reverts r55547 and r55555.
- ChangeLog about the reverted changes are also deleted in this file.
- [Bug #12536] [ruby-dev:49699] [ruby-dev:49702]
-
-Sat Jul 2 02:22:22 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * string.c (str_fill_term): When termlen increases, re-allocation
- of memory for termlen should always be needed.
- In this fix, if possible, decrease capa instead of realloc.
- [Bug #12536] [ruby-dev:49699]
-
-Fri Jul 1 20:20:20 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * string.c: Specify termlen as far as possible.
- Additional fix for [Bug #12536] [ruby-dev:49699].
-
- * string.c (str_new_static): Specify termlen from the given encoding
- when creating a new String object is needed.
-
- * string.c (rb_tainted_str_new_with_enc): New function to create a
- tainted String object with the given encoding. This means that
- the termlen is correctly specified. Currently static function.
- The function name might be renamed to rb_tainted_enc_str_new
- or rb_enc_tainted_str_new.
-
- * string.c (rb_external_str_new_with_enc): Use encoding by using the
- above rb_tainted_str_new_with_enc().
-
-Fri Jul 1 19:38:57 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * test/fiddle/test_pointer.rb (test_to_str, test_to_s, test_aref_aset):
- Attempt to use independent strings for destructive tests that
- directly modify values on memory by using Fiddle::Pointer.
- [Bug #12537] [ruby-dev:49700]
-
-Fri Jul 1 18:20:00 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * .gdbinit (rb_ps_thread): show the detail of cfunc in ruby level
- backtrace.
-
-Fri Jul 1 13:26:39 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * string.c (rb_str_subseq, str_substr): When RSTRING_EMBED_LEN_MAX
- is used, TERM_LEN(str) should be considered with it because
- embedded strings are also processed by TERM_FILL.
- Additional fix for [Bug #12536] [ruby-dev:49699].
-
-Fri Jul 1 12:11:01 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * .gdbinit (rb_count_objects): added gdb version of count_objects().
-
-Fri Jul 1 04:32:52 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * .gdbinit (rb_ps_thread): show ruby level backtrace.
- Usually you can call `rb_ps` to show ruby level backtraces
- for all living threads.
- Note that it can call with core file like `gcore <pid>`
- and `gdb ruby core.<pid>`.
-
-Thu Jun 30 19:15:13 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * string.c: Fix memory corruptions when using UTF-16/32 strings.
- [Bug #12536] [ruby-dev:49699]
-
- * string.c (rb_str_new_with_class): Use TERM_LEN of the "obj".
-
- * string.c (rb_str_plus, rb_str_justify): Use str_new0 which is aware
- of termlen.
-
- * string.c (str_shared_replace): Copy +termlen bytes instead of +1.
-
- * string.c (rb_str_times): termlen should not be included in capa.
-
- * string.c (RESIZE_CAPA_TERM): When using RSTRING_EMBED_LEN_MAX,
- termlen should be counted with it because embedded strings are
- also processed by TERM_FILL.
-
- * string.c (rb_str_capacity, str_shared_replace, str_buf_cat): ditto.
-
- * string.c (rb_str_drop_bytes, rb_str_setbyte, str_byte_substr): ditto.
-
-Wed Jun 29 22:24:37 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * ext/psych/lib/psych_jars.rb: removed needless file required to JRuby.
-
-Wed Jun 29 22:21:38 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_ocsp.c: The "reuse" behavior of d2i_ functions does
- not work well with OpenSSL 1.0.0t. So avoid it.
-
-Wed Jun 29 15:18:28 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * insns.def (opt_succ): optimize like r55515. (but this argument is
- constant)
-
-Wed Jun 29 12:41:58 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * test/ruby/test_refinement.rb: skip
- test_prepend_after_refine_wb_miss on ARM or MIPS.
- [ruby-core:76031] [Bug #12491]
-
-Wed Jun 29 08:45:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (passed_block): convert passed block symbol to proc.
- based on the patch by Daisuke Sato in [ruby-dev:49695].
- [Bug #12531]
-
-Wed Jun 29 03:34:41 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * bignum.c (rb_big2ulong): the old logic seems to try to avoid
- calculating `-(long)(num-1)-1` if `num` is not LONG_MIN. (Note that
- `-LONG_MIN` may be larger than LONG_MAX) But C compilers can
- optimize it into single NEG instruction.
- Therefore those two conditions can be single if-body.
-
- * bignum.c (rb_big2long): ditto.
-
- * bignum.c (rb_big2ull): ditto.
-
- * bignum.c (rb_big2ll): ditto.
-
-Tue Jun 28 22:55:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/pstore.rb (PStore::CHECKSUM_ALGO): extract the algorithm for
- checksum, instead of qualified names for each times.
-
-Tue Jun 28 22:29:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * bootstraptest/runner.rb: do not use safe navigation operator.
- this runner may run on older ruby. partially revert r53110
- (GH-1142 patched by @mlarraz).
-
-Tue Jun 28 22:09:09 2016 Akio Tajima <artonx@yahoo.co.jp>
-
- * lib/fileutils.rb: rescue Errno:EACCES for chown.
- [Bug #12520]
-
-Tue Jun 28 18:38:09 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * ext/digest/md5/md5ossl.h: Remove excess semicolons.
- Suppress warning on Solaris with Oracle Solaris Studio 12.
- [ruby-dev:49692] [Bug #12524]
-
- * ext/digest/md5/md5cc.h: ditto.
- * ext/digest/sha1/sha1cc.h: ditto.
- * ext/digest/sha1/sha1ossl.h: ditto.
- * ext/digest/sha2/sha2cc.h: ditto.
- * ext/digest/sha2/sha2ossl.h: ditto.
- * ext/openssl/ossl_pkey_rsa.c: ditto.
-
-Tue Jun 28 15:56:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/ruby/enc/test_case_comprehensive.rb: noting to test if
- Unicode data files are available.
- [ruby-core:76160] [Bug #12433]
-
- * test/test_unicode_normalize.rb: ditto.
-
-Tue Jun 28 15:20:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/net/http.rb (Net::HTTP#proxy_uri): cache the case no proxy
- is used.
-
-Tue Jun 28 09:56:29 2016 Stefan Schussler <mail@stefanschuessler.de>
-
- * object.c (rb_mod_eqq): [DOC] Fix typo in RDoc. [Fix GH-1393]
-
-Tue Jun 28 02:41:32 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * insns.def (opt_plus): use `- 1` instead of `& (~1)` to allow
- compilers to use x86 LEA instruction (3 operand).
- Even if 3 operand LEA's latency is 3 cycle after SandyBridge,
- it reduces code size and can be faster because of super scalar.
-
- * insns.def (opt_plus): calculate and use rb_int2big.
- On positive Fixnum overflow, `recv - 1 + obj` doesn't carry
- because recv's msb and obj's msb are 0, and resulted msb is 1.
- Therefore simply rshift and cast as signed long works fine.
- On negative Fixnum overflow, it will carry because both arguments'
- msb are 1, and resulted msb is also 1.
- In this case it needs to restore carried sign bit after rshift.
-
-Mon Jun 27 16:58:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/fileutils.rb (FileUtils#install): accecpt symbolic mode, as
- well as chmod.
-
- * lib/fileutils.rb (FileUtils#install): add owner and group
- options.
-
-Mon Jun 27 08:56:55 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (ADD_TRACE): ignore trace instruction on non-positive
- line.
-
- * parse.y (coverage): get rid of ArgumentError when the starting
- line number is not positive. [ruby-core:76141] [Bug #12517]
-
-Sun Jun 26 10:20:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32/lib/Win32API.rb (Win32API#initialize): Cygwin
- 2.5.2-1 (perhaps) seems to no longer append ".dll" suffix
- implicitly.
-
- * ext/win32/lib/win32/resolv.rb (Win32::Resolv): ditto. Fix the
- error reported by yamataka AT u08.itscom.net in
- [ruby-list:50339], and pointed out and patched by cerberus AT
- m3.kcn.ne.jp in [ruby-list:50341].
-
-Sat Jun 25 10:07:52 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * test/openssl/test_ocsp.rb: Ignore errors caused by bugs that exist in
- LibreSSL >= 2.3.1.
-
-Sat Jun 25 02:33:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_method.c (vm_respond_to): try method_missing if respond_to?
- is undefined, as if it is the default definition.
- [ruby-core:75377] [Bug #12353]
-
-Fri Jun 24 17:04:21 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * ext/psych/*, test/psych/*: Update psych 2.1.0
- This version fixed [Bug #11988][ruby-core:72850]
-
-Fri Jun 24 13:12:41 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*:
- Update rubygems 2.6.5 and 2.6.6.
- Release note of 2.6.5: https://github.com/rubygems/rubygems/commit/656f5d94dc888d78d0d00f3598a4fa37391aac80
- Release note of 2.6.6: https://github.com/rubygems/rubygems/commit/ccb9c3300c063f5b5656669972d24a10ef8afbf5
-
-Fri Jun 24 09:17:15 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (lib/unicode_normalize/tables.rb): should not depend
- on Unicode data files unless ALWAYS_UPDATE_UNICODE=yes, to get
- rid of downloading Unicode data unnecessary. [ruby-dev:49681]
-
- * common.mk (enc/unicode/casefold.h): update Unicode files in a
- sub-make, not to let the header depend on the files always.
-
- * enc/unicode/case-folding.rb: if gperf is not usable, assume the
- existing file is OK.
-
-Tue Jun 21 19:44:54 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_regex_casefold.rb: Add Windows-1251, KOI8-R, and
- KOI8-U to encodings; definitely removed EUC-JP.
-
-Tue Jun 21 19:32:23 2016 Mark St.Godard <markstgodard@gmail.com>
-
- * lib/webrick/httprequest.rb (setup_forwarded_info): Use the first
- value in X-Forwarded-Proto, if header contains multiple comma
- separated values. Some middlewares may add these values to the
- list, not replacing. [Fix GH-1386]
-
-Tue Jun 21 17:17:42 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/test_io.rb: Skip test_readpartial_with_not_empty_buffer,
- test_read_buffer_error, test_read_unlocktmp_ensure,
- test_readpartial_unlocktmp_ensure, and
- test_sysread_unlocktmp_ensure on cygwin,
- because these tests repeatedly hang. This makes test_io.rb
- complete in finite time on cygwin.
-
- * ChangeLog: Fix test_in.rb -> test_io.rb (two instances).
-
-Tue Jun 21 16:38:14 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_casemap): do not put code with side effects
- inside RSTRING_PTR() macro which evaluates the argument multiple
- times.
-
-Tue Jun 21 16:13:45 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (rb_str_casemap): fix memory leak.
-
-Tue Jun 21 16:12:21 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (rb_str_casemap): int is too small for string size.
-
-Tue Jun 21 15:42:22 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/test_io.rb: Skip test_read_buffer_error on cygwin,
- because this test repeatedly hangs.
-
-Tue Jun 21 15:35:14 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * LEGAL: Added filenames and copyrights for some files in
- enc/trans/JIS.
-
-Tue Jun 21 00:56:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (get_special_folder): fix calling convention of
- SHGetPathFromIDListEx, which should be WINAPI. pointed out by
- @arton at http://twitter.com/arton/status/744884064277016576
-
-Tue Jun 21 00:22:02 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in, include/ruby/defines.h (RUBY_USE_SETJMPEX):
- include setjmpex.h only when using setjmpex() for RUBY_SETJMP.
- the header of mingw32 overrides setjmp() by setjmpex().
-
-Mon Jun 20 18:39:16 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/test_io.rb: Skip test_open_fifo_does_not_block_other_threads
- on cygwin. Fifos seem to work okay in cygwin, but this test repeatedly
- hangs.
-
-Mon Jun 20 13:35:06 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * vm.c (invoke_bmethod, invoke_block_from_c_0): revert r52104
- partially to avoid "self has wrong type to call super in this
- context" errors.
- [ruby-core:72724] [Bug #11954]
-
-Mon Jun 20 12:53:38 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * test/rubygems/test_gem_remote_fetcher.rb: OpenSSL::PKey::DH#priv_key=
- is not defined when ext/openssl is built with OpenSSL 1.1.0.
- https://github.com/rubygems/rubygems/pull/1648
- [ruby-core:75225] [Feature #12324]
-
-Sun Jun 19 21:25:43 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_ocsp.c: Add OCSP::SingleResponse that represents an
- OCSP SingleResponse structure. Also add two new methods #responses
- and #find_response to OCSP::BasicResponse. A BasicResponse has one or
- more SingleResponse. We have OCSP::BasicResponse#status that returns
- them as an array of arrays, each containing the content of a
- SingleResponse, but this is not useful. When validating an OCSP
- response, we need to look into the each SingleResponse and check their
- validity but it is not simple. For example, when validating for a
- certificate 'cert', the code would be like:
-
- # certid_target is an OpenSSL::OCSP::CertificateId for cert
- basic = res.basic
- result = basic.status.any? do |ary|
- ary[0].cmp(certid_target) &&
- ary[4] <= Time.now && (!ary[5] || Time.now <= ary[5])
- end
-
- Adding OCSP::SingleResponse at the same time allows exposing
- OCSP_check_validity(). With this, the code above can be rewritten as:
-
- basic = res.basic
- single = basic.find_response(certid_target)
- result = single.check_validity
-
- * test/openssl/test_ocsp.rb: Test this.
-
-Sun Jun 19 18:40:19 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_ocsp.c (ossl_ocspbres_add_status): Allow specifying
- the times (thisUpdate, nextUpdate and revocationTime) with Time
- objects. Currently they accepts only relative seconds from the current
- time. This is inconvenience, especially for revocationTime. When
- Integer is passed, they are still treated as relative times. Since the
- type check is currently done with rb_Integer(), this is a slightly
- incompatible change. Hope no one passes a relative time as String or
- Time object...
- Also, allow passing nil as nextUpdate. It is optional.
-
- * ext/openssl/ruby_missing.h: Define RB_INTEGER_TYPE_P() if not defined.
- openssl gem will be released before Ruby 2.4.0.
-
-Sun Jun 19 18:39:38 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_ocsp.c: Implement OCSP::{CertificateId,Request,
- BasicResponse,Response}#initialize_copy.
- [ruby-core:75504] [Bug #12381]
-
- * test/openssl/test_ocsp.rb: Test them.
-
-Sun Jun 19 18:29:50 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_pkey_dh.c, ext/openssl/ossl_pkey_dsa.c,
- ext/openssl/ossl_pkey_ec.c, ext/openssl/ossl_pkey_rsa.c: Implement
- initialize_copy method for OpenSSL::PKey::*.
- [ruby-core:75504] [Bug #12381]
-
- * test/openssl/test_pkey_dh.rb, test/openssl/test_pkey_dsa.rb,
- test/openssl/test_pkey_ec.rb, test/openssl/test_pkey_rsa.rb: Test they
- actually copy the OpenSSL objects, and modifications to cloned object
- don't affect the original object.
-
-Sun Jun 19 16:55:16 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/test_dir_m17n.rb: Skip tests with non-UTF-8 encodings
- on cygwin. Cygwin can use the Unicode PUA (private use area) to store
- bytes from non-UTF-8 filenames (see
- https://cygwin.com/cygwin-ug-net/using-specialnames.html#pathnames-specialchars),
- but we are not supporting this. [Bug #12443]
-
-Sun Jun 19 15:01:18 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * localeinit.c: Fix filesystem encoding for cygwin to UTF-8 (see
- https://cygwin.com/cygwin-ug-net/using-specialnames.html#pathnames-unusual)
-
-Sun Jun 19 14:31:07 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_pkey.h, ext/openssl/ossl_pkey_dh.c,
- ext/openssl/ossl_pkey_dsa.c, ext/openssl/ossl_pkey_rsa.c: A few days
- ago, OpenSSL changed {DH,DSA,RSA}_get0_*() to take const BIGNUM **.
- https://git.openssl.org/gitweb/?p=openssl.git;a=commit;h=fd809cfdbd6e32b6b67b68c59f6d55fbed7a9327
- [ruby-core:75225] [Feature #12324]
-
-Sun Jun 19 11:19:43 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * variable.c (rb_path_to_class): consider the string length
- instead of a terminator.
-
- * variable.c (rb_path_to_class): search the constant at once
- instead of checking if defined and then getting it.
-
-Sat Jun 18 14:01:40 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * test/rubygems/test_gem_installer.rb: Fixed broken test with extension
- build. https://github.com/rubygems/rubygems/pull/1645
-
-Sat Jun 18 13:59:54 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems
- HEAD(2c6d256). It contains to update vendored Molinillo to 0.5.0.
- https://github.com/rubygems/rubygems/pull/1638
-
-Sat Jun 18 10:13:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (build-ext), ext/extmk.rb: use variable EXTENCS
- different than ENCOBJS, to get rid of circular dependency.
- build libencs when linking encodings statically.
- [ruby-core:75618] [Bug #12401]
-
-Sat Jun 18 08:52:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/stringio/stringio.c (strio_getline): fix pointer index
- overflow. reported by Guido Vranken <guido AT guidovranken.nl>.
-
-Thu Jun 16 16:35:35 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (Init_class_hierarchy): prevent rb_cObject which is the
- class tree root, from GC. [ruby-dev:49666] [Bug #12492]
-
-Thu Jun 16 12:17:52 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (tr_trans): adjust buffer size by processed and rest
- lengths, instead of doubling repeatedly.
-
-Thu Jun 16 11:15:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (tr_trans): consider terminator length and fix heap
- overflow. reported by Guido Vranken <guido AT guidovranken.nl>.
-
-Thu Jun 16 00:02:32 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_ocsp.c (ossl_ocspreq_verify, ossl_ocspbres_verify):
- Use ossl_clear_error() so that they don't print warnings to stderr and
- leak errors in the OpenSSL error queue. Also, check the return value
- of OCSP_*_verify() correctly. They can return -1 on verification
- failure.
-
-Wed Jun 15 19:52:23 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_ocsp.c (ossl_ocspreq_sign, ossl_ocspbres_sign): Allow
- specifying hash algorithm used in signing. They are hard coded to use
- SHA-1.
- Based on a patch provided by Tim Shirley <tidoublemy@gmail.com>.
- [ruby-core:70915] [Feature #11552] [GH ruby/openssl#28]
-
- * test/openssl/test_ocsp.rb: Test sign-verify works.
-
-Wed Jun 15 01:46:16 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c: [DOC] fix rdoc directive, and an example of negative
- value. [ruby-core:76025] [Bug #12487]
-
-Wed Jun 15 01:44:42 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/mkconfig.rb: provide Unicode Version information as
- RbConfig::CONFIG['UNICODE_VERSION'].
- [ruby-core:75845] [Feature #12460]
-
-Wed Jun 15 00:01:18 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * test/ruby/enc/test_case_comprehensive.rb
- (TestComprehensiveCaseFold::read_data): use \A and \z instead of
- ^ and $ in regexp.
-
-Tue Jun 14 23:43:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/backward.h (rb_cFixnum, rb_cBignum): remove the
- backward compatibility macros, to fail incompatible extension
- libraries early. [Bug #12427]
-
-Tue Jun 14 22:22:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * strftime.c (rb_strftime_with_timespec): limit the result string
- size by the format length, to get rid of unlimited memory use.
-
-Tue Jun 14 22:11:11 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_ocsp.c (ossl_ocspcid_get_issuer_name_hash,
- ossl_ocspcid_get_issuer_key_hash, ossl_ocspcid_get_hash_algorithm):
- Add accessor methods OCSP::CertificateId#issuer_name_hash,
- #issuer_key_hash, #hash_algorithm.
- Based on a patch provided by Paul Kehrer <paul.l.kehrer@gmail.com>.
- [ruby-core:48062] [Feature #7181]
-
- * test/openssl/test_ocsp.rb: Test these new methods.
-
-Tue Jun 14 22:07:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/date/date_strftime.c (date_strftime_with_tmx): reject too
- large precision to get rid of buffer overflow.
- reported by Guido Vranken <guido AT guidovranken.nl>.
-
-Tue Jun 14 21:40:42 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_ocsp.c (ossl_ocspbres_to_der, ossl_ocspcid_to_der):
- Implement #to_der methods for OCSP::BasicResponse and
- OCSP::CertificateId.
-
- (ossl_ocspreq_initialize, ossl_ocspres_initialize): Use GetOCSP*()
- instead of raw DATA_PTR().
-
- (ossl_ocspbres_initialize, ossl_ocspcid_initialize): Allow
- initializing from DER string.
-
- (Init_ossl_ocsp): Define new #to_der methods.
-
- * test/openssl/test_ocsp.rb: Test these changes. Also add missing tests
- for OCSP::{Response,Request}#to_der.
-
-Tue Jun 14 21:35:00 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/openssl_missing.h (DH_set0_pqg, RSA_set0_key):
- DH_set0_pqg() allows 'q' to be NULL. Fix a typo in RSA_set0_key().
- Fixes r55285. [ruby-core:75225] [Feature #12324]
-
-Mon Jun 14 10:19:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * NEWS: describe Integer#digits.
-
-Mon Jun 13 21:09:40 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * thread.c (debug_deadlock_check): show thread lock dependency and
- backtrace [Feature #8214] [ruby-dev:47217]
-
- * thread.c (thread_status_name): show "sleep_forever" instead of
- "sleep" if called from inspect.
-
-Mon Jun 13 20:50:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (reg_named_capture_assign_iter): remove named capture
- conflict warnings. it is just annoying rather than useful.
- [ruby-core:75416] [Bug #12359]
-
-Mon Jun 13 20:04:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * numeric.c (rb_int_digits, rb_fix_digits, rb_int_digits_bigbase):
- Add Integer#digits to extract columns in place-value notation
- [Feature #12447] [ruby-core:75799]
-
- * test/ruby/test_integer.rb: Add tests for the above change.
-
- * test/ruby/test_bignum.rb: ditto.
-
-Mon Jun 13 20:34:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (RUBY_INTEGER_UNIFICATION): macro to tell if
- Integer is integrated. [ruby-core:75718][Bug #12427]
-
- * include/ruby/backward.h, internal.h (rb_cFixnum, rb_cBignum):
- fallback to rb_cInteger.
-
- * bignum.c, numeric.c, ext/json/generator/generator.{c,h}: use the
- macro.
-
-Mon Jun 13 16:58:53 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive.rb: Add tests for full Unicode
- swapcase.
-
-Sun Jun 12 14:48:00 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive.rb: Add tests for ASCII-only
- swapcase; store calculated values in hashes.
-
-Sun Jun 12 14:05:45 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_cipher.c (ossl_cipher_get_auth_tag,
- ossl_cipher_set_auth_tag): Check if the cipher flags retrieved by
- EVP_CIPHER_CTX_flags() includes EVP_CIPH_FLAG_AEAD_CIPHER to see if
- the cipher supports AEAD. AES-GCM was the only supported in OpenSSL
- 1.0.1.
-
- (Init_ossl_cipher): Fix doc; OpenSSL::Cipher::AES.new(128, :GCM) can't
- work.
-
- * ext/openssl/openssl_missing.h: Define EVP_CTRL_AEAD_{GET,SET}_TAG if
- missing. They are added in OpenSSL 1.1.0, and have the same value as
- EVP_CTRL_GCM_{GET,SET}_TAG and EVP_CTRL_CCM_{GET,SET}_TAG.
-
-Sun Jun 12 13:47:42 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * test/openssl/test_engine.rb (test_openssl_engine_builtin,
- test_openssl_engine_by_id_string): Skip test if 'openssl' engine is
- already loaded. And test the number increased by Engine.load{_by_id,},
- not the total count of loaded engines. Previously, we called
- OpenSSL::Engine.cleanup every time running a test case, but we no
- longer can do it.
- [ruby-core:75225] [Feature #12324]
-
-Sun Jun 12 09:24:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (append_fspath): normalize directory name to be appended
- on OS X. [ruby-core:75957] [Ruby trunk Bug#12483]
- https://github.com/rails/rails/issues/25303#issuecomment-224834804
-
-Sat Jun 11 23:07:32 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * lib/forwardable.rb (_delegator_method): get rid of a warning which
- causes test failures introduced at r55376.
-
-Sat Jun 11 18:37:58 2016 Marcus Stollsteimer <sto.mar@web.de>
-
- * ext/json/lib/*.rb: Removed some comments. Because these are unnecessary
- class description. [ci skip][Bug #12255][ruby-core:74835]
-
-Sat Jun 11 15:19:38 2016 takiy33 <takiy33@users.noreply.github.com>
-
- * lib/net/smtp.rb: [DOC] Remove dead link on documentation for
- Japanese of SMTP. [Fix GH-1380]
-
-Sat Jun 11 15:02:45 2016 Grant Hutchins <github@nertzy.com>
-
- * string.c (rb_str_oct): [DOC] fix typo, hornored -> honored.
- [Fix GH-1379]
-
-Sat Jun 11 14:04:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/objspace/objspace_dump.c: generate valid JSON for dump_all.
-
-Sat Jun 11 13:52:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/forwardable.rb (_delegator_method): remove __send__ call if
- possible, so that more optimizations will be enabled.
-
-Sat Jun 11 11:24:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enc/iso_8859.h (SHARP_s): name frequently used codepoint.
-
-Sat Jun 11 09:58:45 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_1.c: Revert to older version of code.
-
-Sat Jun 11 09:46:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/iso_8859_1.c: Implement non-ASCII case mapping.
-
- * test/ruby/enc/test_case_comprehensive.rb: Tests for above.
-
- * string.c: Add iso-8859-1 to supported encodings.
-
-Sat Jun 11 09:31:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/forwardable.rb (_delegator_method): leave the backtrace
- untouched during accessor. forwardable.rb does not appear in
- the backtrace during delegated method because of tail-call
- optimization.
-
-Sat Jun 11 01:38:31 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * include/ruby/defines.h (GCC_VERSION_SINCE): Fix logic error by
- adding parentheses. Fix failures of TestMkmf::TestConvertible
- with GCC 3.4.3 on Solaris 10. [Bug #12479] [ruby-dev:49660]
-
-Fri Jun 10 21:54:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/forwardable.rb (Forwardable._delegator_method): extract
- method generator and deal with non-module objects.
- [ruby-dev:49656] [Bug #12478]
-
-Fri Jun 10 17:35:11 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: Special-case :ascii option in rb_str_capitalize_bang and
- rb_str_swapcase_bang.
-
-Fri Jun 10 17:12:24 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: Special-case :ascii option in rb_str_upcase_bang (retry).
-
-Fri Jun 10 14:48:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * hash.c (get_env_cstr): ensure NUL-terminated.
- [ruby-dev:49655] [Bug #12475]
-
- * string.c (rb_str_fill_terminator): return the pointer to the
- NUL-terminated content.
-
-Thu Jun 9 21:42:00 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_asn1.c (asn1integer_to_num): Use
- ASN1_ENUMERATED_to_BN() to convert an ASN1_ENUMERATED to a BN.
- Starting from OpenSSL 1.1.0, ASN1_INTEGER_to_BN() rejects
- non-ASN1_INTEGER objects. The format of INTEGER and ENUMERATED are
- almost identical so they behaved in the same way in OpenSSL <= 1.0.2.
- [ruby-core:75225] [Feature #12324]
-
- * test/openssl/test_asn1.rb (test_decode_enumerated): Test that it
- works.
-
-Thu Jun 9 21:10:04 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * tool/ifchange: fix timestamp error when target without
- directory.
-
-Thu Jun 9 19:46:22 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_ssl.c: Add define guards for OPENSSL_NO_EC.
- SSL_CTX_set_ecdh_auto() is defined even when ECDH is disabled in
- OpenSSL's configuration. This fixes r55214.
-
- * test/openssl/test_pair.rb (test_ecdh_curves): Skip if the OpenSSL does
- not support ECDH.
-
- * test/openssl/utils.rb (start_server): Ignore error in
- SSLContext#ecdh_curves=.
-
-Thu Jun 9 18:12:42 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * Makefile.in (un-runnable): fail with proper error message.
- [ruby-core:75905] [Bug #12472]
-
-Thu Jun 9 15:32:17 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (RBCONFIG): use ifchange tool to see if the content is
- changed and update the timestamp file.
-
- * tool/mkconfig.rb: remove ifchange features.
-
- * tool/ifchange: make target directory if it does not exist with
- its parent directories.
-
- * win32/ifchange.bat: drop support for command.com used on old
- systems.
-
-Thu Jun 9 15:03:35 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/extconf.rb: Check for CRYPTO_malloc() and SSL_new().
- OpenSSL_add_all_digests() and SSL_library_init() are deprecated and
- converted to macros in OpenSSL 1.1.0.
- [ruby-core:75225] [Feature #12324]
-
-Wed Jun 8 23:09:51 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * string.c (rb_str_ascii_casemap): fix compile error.
-
-Wed Jun 8 22:22:24 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: Revert previous commit (possibility of endless loop).
-
-Wed Jun 8 21:57:41 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: Special-case :ascii option in rb_str_upcase_bang.
-
-Wed Jun 8 21:28:36 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: New static function rb_str_ascii_casemap; special-casing
- :ascii option in rb_str_upcase_bang and rb_str_downcase_bang.
-
- * regenc.c: Fix a bug (wrong use of unnecessary slack at end of string).
-
- * regenc.h -> include/ruby/oniguruma.h: Move declaration of
- onigenc_ascii_only_case_map so that it is visible in string.c.
-
-Wed Jun 8 20:33:44 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * include/ruby/intern.h: Remove excess semicolons in PUREFUNC().
- Fix failure of TestMkmf::TestConvertible on Solaris with
- Oracle Solaris Studio 12. [ruby-dev:49651] [Bug #12470]
- * internal.h: ditto.
-
-Wed Jun 8 16:03:09 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * lib/net/smtp.rb (getok, get_response): raise an ArgumentError when
- CR or LF is included in a line, because they are not allowed in
- RFC5321. Thanks, Jeremy Daer.
-
-Tue Jun 7 21:27:25 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * test/rubygems/*_{cert,cert_32}.pem: Regenerate test certificates for
- OpenSSL 1.1.0. This is already in upstream.
- https://github.com/rubygems/rubygems/commit/9be5c53939440a61c4bba73cfffbeb5cfadf72be
- [ruby-core:75225] [Feature #12324]
-
-Tue Jun 7 21:27:17 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * test/open-uri/test_ssl.rb: Regenerate test certificates. The test CA
- certificate was incorrectly generated. A CA certificate must have the
- basic constraints extension with cA bit set to TRUE. OpenSSL <= 1.0.2
- allowed the error when the certificate is in the trusted store but
- OpenSSL 1.1.0 no longer does.
- [ruby-core:75225] [Feature #12324]
-
-Tue Jun 7 21:20:38 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * test/openssl/test_x509name.rb: Don't register OID for 'emailAddress'
- and 'serialNumber'. A recent change in OpenSSL made OBJ_create()
- reject an already existing OID. They were needed to run tests with
- OpenSSL 0.9.6 which is now unsupported.
- https://git.openssl.org/gitweb/?p=openssl.git;a=commit;h=52832e470f5fe8c222249ae5b539aeb3c74cdb25
- [ruby-core:75225] [Feature #12324]
-
- * test/openssl/test_ssl_session.rb (test_server_session): Duplicate
- SSL::Session before re-adding to the session store. OpenSSL 1.1.0
- starts rejecting SSL_SESSION once removed by SSL_CTX_remove_session().
- https://git.openssl.org/gitweb/?p=openssl.git;a=commit;h=7c2d4fee2547650102cd16d23f8125b76112ae75
-
- * test/openssl/test_pkey_ec.rb (setup): Remove X25519 from @keys. X25519
- is new in OpenSSL 1.1.0 but this is for key agreement and not for
- signing.
-
- * test/openssl/test_pair.rb, test/openssl/test_ssl.rb,
- test/openssl/utils.rb: Set security level to 0 when using aNULL cipher
- suites.
-
- * test/openssl/utils.rb: Use 1024 bits DSA key for client certificates.
-
- * test/openssl/test_engine.rb: Run each test in separate process.
- We can no longer cleanup engines explicitly as ENGINE_cleanup() was
- removed.
- https://git.openssl.org/gitweb/?p=openssl.git;a=commit;h=6d4fb1d59e61aacefa25edc4fe5acfe1ac93f743
-
- * ext/openssl/ossl_engine.c (ossl_engine_s_cleanup): Add a note to the
- RDoc for Engine.cleanup.
-
- * ext/openssl/lib/openssl/digest.rb: Don't define constants for DSS,
- DSS1 and SHA(-0) when using with OpenSSL 1.1.0. They are removed.
-
- * test/openssl/test_digest.rb, test/openssl/test_pkey_dsa.rb,
- test/openssl/test_pkey_dsa.rb, test/openssl/test_ssl.rb,
- test/openssl/test_x509cert.rb, test/openssl/test_x509req.rb: Don't
- test unsupported hash functions.
-
-Tue Jun 7 17:49:52 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive: Change test for encodings
- without any non-ASCII case conversions from ASCII-only test
- to full test.
-
-Tue Jun 7 17:18:39 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c (rb_str_upcase_bang, rb_str_capitalize_bang,
- rb_str_swapcase_bang): Switch to use primitive.
-
-Tue Jun 7 16:44:16 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c (rb_str_downcase_bang): Switch to use primitive except if
- conversion can be done ASCII-only.
-
-Tue Jun 7 16:13:36 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive: Add regression tests for
- current ASCII-only case conversion.
-
-Tue Jun 7 15:28:38 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive: Fix method name
- (generate_casefold_tests -> generate_case_mapping_tests).
-
-Tue Jun 7 15:05:13 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * regenc.h/c: Rename onigenc_not_support_case_map to
- onigenc_ascii_only_case_map.
-
- * regenc.h: Add definition of onigenc_single_byte_ascii_only_case_map.
-
- * enc/iso_8859_X.c, windows_125X.c, ascii.c, us-ascii.c, koi8_x.c:
- Replace onigenc_not_support_case_map by
- onigenc_single_byte_ascii_only_case_map.
-
- * enc/big5.c, cp949.c, emacs_mule.c, euc_X.c, gbX.c, shift_jis.c,
- windows_31j.c: Replace onigenc_not_support_case_map by
- onigenc_ascii_only_case_map.
-
-Tue Jun 7 14:57:09 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/extconf.rb: Check for SSL_CTX_set_min_proto_version()
- macro added in OpenSSL 1.1.0. Version-specific methods, such as
- TLSv1_method(), are deprecated in OpenSSL 1.1.0. We need to use
- version-flexible methods (TLS_*method() or SSLv23_*method()) and
- disable other protocol versions as necessary.
- [ruby-core:75225] [Feature #12324]
-
- * ext/openssl/ossl_ssl.c: Use SSL_CTX_set_{min,max}_proto_version() to
- fix the protocol version.
-
-Tue Jun 7 12:55:34 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * regenc.c (onigenc_not_support_case_map): Move to end of file;
- (onigenc_single_byte_ascii_only_case_map): Add new function.
-
-Tue Jun 7 09:26:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * regenc.c (onigenc_not_support_case_map): Rewrite to work correctly
- in ASCII range.
-
-Mon Jun 6 23:00:00 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * appveyor.yml: Update libressl version to 2.3.5.
-
-Mon Jun 6 18:37:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_throw_start): check if the iseq is symbol
- proc, class definition should not be a symbol proc.
- [ruby-core:75856] [Bug #12462]
-
-Mon Jun 6 18:36:34 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: Added UTF-16BE/LE and UTF-32BE/LE to supported encodings
- for Unicode case mapping.
-
- * test/ruby/enc/test_case_comprehensive.rb: Tests for above
- functionality; fixed an encoding issue in assertion error message.
-
-Mon Jun 6 17:29:35 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive.rb: Speed up testing for small
- encodings by preselecting codepoints.
-
-Mon Jun 6 17:10:50 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_cipher.c (ossl_cipher_free): Use EVP_CIPHER_CTX_free()
- to free EVP_CIPHER_CTX allocated by EVP_CIPHER_CTX_new().
- [ruby-core:75225] [Feature #12324]
-
-Mon Jun 6 13:37:08 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c Change rb_str_casemap to use encoding primitive
- case_map instead of directly calling onigenc_unicode_case_map.
-
-Mon Jun 6 13:16:46 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_mapping.rb:
- Remove :lithuanian guard for Unicode case mapping.
-
-Mon Jun 6 10:39:56 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/openssl_missing.h: Include ruby/config.h. r55285 added
- some inline functions but VC does not recognize 'inline' keyword.
-
-Mon Jun 6 09:25:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (thread_start_func_2): report raised exception if
- report_on_exception flag is set. [Feature #6647]
-
-Mon Jun 6 01:36:24 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/extconf.rb: Check existence of SSL_is_server(). This
- function was introduced in OpenSSL 1.0.2.
- [ruby-core:75225] [Feature #12324]
-
- * ext/openssl/openssl_missing.h: Implement SSL_is_server() if missing.
-
- * ext/openssl/ossl_ssl.c (ssl_info_cb): Use SSL_is_server() to see if
- the SSL is server. The state machine in OpenSSL was rewritten and
- SSL_get_state() no longer returns SSL_ST_ACCEPT.
-
- (ossl_ssl_cipher_to_ary, ossl_sslctx_session_get_cb): Add some
- `const`s to suppress warning.
-
-Mon Jun 6 01:18:10 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_asn1.c (decode_bool): Do the same thing as
- d2i_ASN1_BOOLEAN() does by ourselves. This function is removed in
- OpenSSL 1.1.0.
- [ruby-core:75225] [Feature #12324]
-
-Mon Jun 6 00:34:16 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/extconf.rb: Check existence of accessor functions that
- don't exist in OpenSSL 0.9.8. OpenSSL 1.1.0 made most of its
- structures opaque and requires use of these accessor functions.
- [ruby-core:75225] [Feature #12324]
-
- * ext/openssl/openssl_missing.[ch]: Implement them if missing.
-
- * ext/openssl/ossl*.c: Use these accessor functions.
-
- * test/openssl/test_hmac.rb: Add missing test for HMAC#reset.
-
-Mon Jun 6 00:00:13 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/openssl_missing.[ch]: Implement EVP_PKEY_get0_*() and
- {RSA,DSA,EC_KEY,DH}_get0_*() functions.
- OpenSSL 1.1.0 makes EVP_PKEY/RSA/DSA/DH opaque. We used to provide
- setter methods for each parameter of each PKey type, for example
- PKey::RSA#e=, but this is no longer possible because the new API
- RSA_set0_key() requires the 'n' at the same time. This commit adds
- deprecation warning to them and adds PKey::*#set_* methods as direct
- wrapper for those new APIs. For example, 'rsa.e = 3' now needs to be
- rewritten as 'rsa.set_key(rsa.n, 3, rsa.d)'.
- [ruby-core:75225] [Feature #12324]
-
- * ext/openssl/ossl_pkey*.[ch]: Use the new accessor functions. Implement
- RSA#set_{key,factors,crt_params}, DSA#set_{key,pqg}, DH#set_{key,pqg}.
- Emit a warning with rb_warning() when old setter methods are used.
-
- * test/drb/ut_array_drbssl.rb, test/drb/ut_drb_drbssl.rb,
- test/rubygems/test_gem_remote_fetcher.rb: Don't set a priv_key for DH
- object that are used in tmp_dh_callback. Generating a new key pair
- every time should be fine - actually the private exponent is ignored
- in OpenSSL >= 1.0.2f/1.0.1r even if we explicitly set.
- https://www.openssl.org/news/secadv/20160128.txt
-
-Sun Jun 5 22:06:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * configure.in: Fix the timing to detect the appropriate C++ compiler
- in OS X.
-
-Sun Jun 5 21:42:24 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/extconf.rb: Check absence of CRYPTO_lock() to see if the
- OpenSSL has the new threading API. In OpenSSL <= 1.0.2, an application
- had to set locking callbacks to use OpenSSL in a multi-threaded
- environment. OpenSSL 1.1.0 now finds pthreads or Windows threads so we
- don't need to do something special.
- [ruby-core:75225] [Feature #12324]
-
- Also check existence of *_up_ref(). Some structures in OpenSSL have
- a reference counter. We used to increment it with CRYPTO_add() which
- is a part of the old API.
-
- * ext/openssl/openssl_missing.h: Implement *_up_ref() if missing.
-
- * ext/openssl/ossl.c: Don't set locking callbacks if unneeded.
-
- * ext/openssl/ossl_pkey.c, ext/openssl/ossl_ssl.c,
- ext/openssl/ossl_x509cert.c, ext/openssl/ossl_x509crl.c,
- ext/openssl/ossl_x509store.c: Use *_up_ref() instead of CRYPTO_add().
-
-Sun Jun 5 21:38:13 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/extconf.rb: Check if RAND_pseudo_bytes() is usable. It is
- marked as deprecated in OpenSSL 1.1.0.
- [ruby-core:75225] [Feature #12324]
-
- * ext/openssl/ossl_rand.c: Disable Random.pseudo_bytes if
- RAND_pseudo_bytes() is unavailable.
-
- * test/openssl/test_random.rb: Don't test Random.pseudo_bytes if not
- defined.
-
-Sun Jun 5 19:06:40 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * NEWS: Add news about Unicode-wide case mapping for
- String/Symbol#upcase/downcase/swapcase/capitalize(!).
-
-Sun Jun 5 15:24:33 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive.rb:
- Remove :lithuanian guard for Unicode case mapping.
-
-Sun Jun 5 14:46:34 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: Remove :lithuanian guard for Unicode case mapping.
-
-Sat Jun 4 10:54:52 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * missing/crypt.h (struct crypt_data): remove unnecessary member
- "initialized".
-
- * missing/crypt.c (des_setkey_r): nothing to be initialized in
- crypt_data.
-
- * configure.in (struct crypt_data): check for "initialized" in
- struct crypt_data, which may be only in glibc, and isn't on AIX
- at least.
-
-Sat Jun 4 10:38:39 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c: unify MAX_PATH, _MAX_PATH, and MAXPATHLEN to
- PATH_MAX, except for MAX_PATH in get_special_folder for an API
- limit.
-
-Fri Jun 3 21:27:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (process_options): rb_str_conv_enc() never set encoding
- of the source string, but returns the string itself if the
- conversion failed. then the instance variable does not need to
- be set again.
-
-Fri Jun 3 18:04:37 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ruby.c (process_options): need to duplicate path before passing it to
- rb_str_conv_enc() because the function might call rb_enc_associate()
- internally. this fixes test failures on Windows introduced at r55260.
-
-Fri Jun 3 17:44:25 2016 Reiner Herrmann <reiner@reiner-h.de>
-
- * lib/mkmf.rb (create_makefile): sort lists of source and object
- files in generated Makefile, unless given by extconf.rb.
- [Fix GH-1367]
-
-Thu Jun 2 21:18:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/win32.c (get_special_folder): use SHGetPathFromIDListEx if
- available instead of old SHGetPathFromIDListW, to check the
- buffer size.
-
-Thu Jun 2 17:05:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (ruby_init_loadpath_safe): remove MAXPATHLEN restriction
- for Windows 10.
-
-Thu Jun 2 16:51:35 2016 Koichi ITO <koic.ito@gmail.com>
-
- * misc/ruby-mode.el (ruby-here-doc-beg-re),
- (ruby-here-doc-beg-match, ruby-parse-partial): Support for
- `squiggly heredoc' syntax in ruby-mode. [Fix GH-1372]
-
-Thu Jun 2 10:24:48 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: Raise ArgumentError when invalid string is detected in
- case mapping methods.
-
- * enc/unicode.c: Check for invalid string and signal with negative
- length value.
-
- * test/ruby/enc/test_case_mapping.rb: Add tests for above.
-
- * test/ruby/test_m17n_comb.rb: Add a message to clarify test failure.
-
-Wed Jun 1 21:41:05 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/extconf.rb: Check existence of ASN1_TIME_adj(). The old
- ASN1_TIME_set() is not Year 2038 ready on sizeof(time_t) == 4
- environment. This function was added in OpenSSL 1.0.0.
- [ruby-core:45552] [Bug #6571]
-
- * ext/openssl/ossl_asn1.c (ossl_time_split): Added. Split the argument
- (Time) into the number of days elapsed since the epoch and the
- remainder seconds to conform to ASN1_TIME_adj().
- (obj_to_asn1utime, obj_to_asn1gtime): Use ossl_time_split() and
- ASN1_*TIME_adj().
-
- * ext/openssl/ossl_asn1.h: Add the function prototype for
- ossl_time_split().
-
- * ext/openssl/ossl_x509.[ch]: Add ossl_x509_time_adjust(). Similarly to
- obj_to_asn1*time(), use X509_time_adj_ex() instead of X509_time_adj().
-
- * ext/openssl/ossl_x509cert.c, ext/openssl/ossl_x509crl.c,
- ext/openssl/ossl_x509revoked.c: Use ossl_x509_time_adjust().
-
-Wed Jun 1 15:58:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: revert r55237. replace crypt, not crypt_r, and
- check if crypt is broken more.
-
- * missing/crypt.c: move crypt_r.c
-
- * string.c (rb_str_crypt): use crypt_r if provided by the system.
-
-Wed Jun 1 14:07:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * missing/crypt_r.c (a64toi): initialize statically and fix out of
- bounds access when salt is not 7bit clean.
-
-Wed Jun 1 11:34:59 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/Makefile.sub (MISSING): fixed build error introduced at r55237.
-
-Wed Jun 1 09:48:06 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_crypt): use reentrant crypt_r.
-
-Wed Jun 1 09:37:26 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * missing/crypt.c (des_setkey): void function never returns any value.
-
-Wed Jun 1 09:16:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * crypt.h: separate header file from missing/crypt.c.
-
- * missing/crypt.c (crypt_r, setkey_r, encrypt_r): add reentrant
- versions.
-
-Wed Jun 1 02:25:38 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * missing/crypt.c: fix size macros to use configured values
- for platforms long is larger than 32bit.
- [ruby-core:75792] [Bug #12446]
-
-Tue May 31 17:28:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/optparse.rb (OptionParser::Completion.candidate): get rid of
- nil as key names. [ruby-core:75773] [Bug #12438]
-
- * lib/optparse.rb (OptionParser#make_switch): char class option
- cannot be NoArgument, default to RequiredArgument.
-
-Tue May 31 00:30:11 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/socket/raddrinfo.c (host_str, port_str): Use StringValueCStr
- instead of (Safe)StringValue, to detect NUL byte in the string.
-
-Mon May 30 22:02:01 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_asn1.c (time_to_time_t): Use NUM2TIMET() instead of
- NUM2LONG(). time_t may be larger than long.
- [ruby-core:45552] [Bug #6571]
-
-Mon May 30 21:15:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: Document current behavior for other case mapping methods
- on String. [ci skip]
-
-Mon May 30 20:00:25 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: Document current situation for String#downcase. [ci skip]
-
-Mon May 30 18:29:28 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_ssl.c (ossl_sslctx_s_alloc): Enable the automatic
- curve selection for ECDH by calling SSL_CTX_set_ecdh_auto(). With
- this a TLS server automatically selects a curve which both the client
- and the server support to use in ECDH. This changes the default
- behavior but users can still disable ECDH by excluding 'ECDH' cipher
- suites from the cipher list (with SSLContext#ciphers=). This commit
- also deprecate #tmp_ecdh_callback=. It was added in Ruby 2.3.0. It
- wraps SSL_CTX_set_tmp_ecdh_callback() which will be removed in OpenSSL
- 1.1.0. Its callback receives two values 'is_export' and 'keylength'
- but both are completely useless for determining a curve to use in
- ECDH. The automatic curve selection was introduced to replace this.
-
- (ossl_sslctx_setup): Deprecate SSLContext#tmp_ecdh_callback=. Emit a
- warning if this is in use.
-
- (ossl_sslctx_set_ecdh_curves): Add SSLContext#ecdh_curves=. Wrap
- SSL_CTX_set1_curves_list(). If it is not available, this falls back
- to SSL_CTX_set_tmp_ecdh().
-
- (Init_ossl_ssl): Define SSLContext#ecdh_curves=.
-
- * ext/openssl/extconf.rb: Check the existence of EC_curve_nist2nid(),
- SSL_CTX_set1_curves_list(), SSL_CTX_set_ecdh_auto() and
- SSL_CTX_set_tmp_ecdh_callback().
-
- * ext/openssl/openssl_missing.[ch]: Implement EC_curve_nist2nid() if
- missing.
-
- * test/openssl/test_pair.rb (test_ecdh_callback): Use
- EnvUtil.suppress_warning to suppress deprecated warning.
-
- (test_ecdh_curves): Test that SSLContext#ecdh_curves= works.
-
- * test/openssl/utils.rb (start_server): Use SSLContext#ecdh_curves=.
-
-Mon May 30 16:28:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/socket/raddrinfo.c (host_str, port_str): use RSTRING_LEN
- instead of strlen, since RSTRING_PTR StringValueCStr may not be
- NUL-terminated when SHARABLE_MIDDLE_SUBSTRING=1. reported by
- @tmtms, http://twitter.com/tmtms/status/736910516229005312
-
-Mon May 30 16:20:26 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (str_fill_term): return new pointer reallocated by
- filling terminator.
-
-Mon May 30 14:54:58 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/stringio/stringio.c (enc_subseq): share the return value and
- the buffer as possible.
-
-Mon May 30 14:50:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (str_substr, rb_str_aref): refactor not to create
- unnecessary empty string.
-
- * string.c (str_byte_substr, str_byte_aref): ditto.
-
-Mon May 30 00:09:37 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/-test-/auto_ext.rb: fixed a heedless bug introduced at r55198.
- this change will make RubyCI green.
-
-Sun May 29 22:58:19 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * regexec.c (ONIGENC_IS_MBC_ASCII_WORD): redefine optimized one.
- WORD of Ruby's ascii compatible encoding is always [a-zA-Z0-9_].
-
-Sun May 29 22:44:19 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * regexec.c (match_at): make compilers optimize harder.
-
-Sun May 29 12:08:42 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/-test-/auto_ext.rb (auto_ext): utility method to create
- extension libraries for tests.
-
-Sat May 28 20:40:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * misc/ruby-additional.el (ruby-insert-heredoc-code-block): insert
- here document code block for assert_separately mainly.
-
-Sat May 28 20:34:19 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/test_unicode_normalize.rb: Add test to check for availability of
- Unicode data file; refactoring; fix an error with tests for destructive
- method (unicode_normalize!).
-
-Sat May 28 19:08:36 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive.rb: Add error messages to tests
- for data file availability; refactoring.
-
-Sat May 28 14:00:10 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/lib/openssl/ssl.rb (SSLSocket): Move the implementation of
- SSLSocket#initialize to C. Initialize the SSL (OpenSSL object) in it.
- Currently this is delayed until ossl_ssl_setup(), which is called from
- SSLSocket#accept or #connect. Say we call SSLSocket#hostname= with an
- illegal value. We expect an exception to be raised in #hostname= but
- actually we get it in the later SSLSocket#connect. Because the SSL is
- not ready at #hostname=, the actual call of SSL_set_tlsext_host_name()
- is also delayed.
- This also fixes: [ruby-dev:49376] [Bug #11724]
-
- * ext/openssl/ossl_ssl.c (ossl_ssl_initialize): Added. Almost the same
- as the Ruby version but this instantiate the SSL object at the same
- time.
-
- (ossl_ssl_setup): Adjust to the changes. Just set the underlying IO to
- the SSL.
-
- (ssl_started): Added. Make use of SSL_get_fd(). This returns -1 if not
- yet set by SSL_set_fd().
-
- (ossl_ssl_data_get_struct): Removed. Now GetSSL() checks that the SSL
- exists.
-
- (ossl_ssl_set_session): Don't call ossl_ssl_setup() here as now the
- SSL is already instantiated in #initialize.
-
- (ossl_ssl_shutdown, ossl_start_ssl, ossl_ssl_read_internal,
- ossl_ssl_write_internal, ossl_ssl_stop, ossl_ssl_get_cert,
- ossl_ssl_get_peer_cert, ossl_ssl_get_peer_cert_chain,
- ossl_ssl_get_version, ossl_ssl_get_cipher, ossl_ssl_get_state,
- ossl_ssl_pending, ossl_ssl_session_reused,
- ossl_ssl_get_verify_result, ossl_ssl_get_client_ca_list,
- ossl_ssl_npn_protocol, ossl_ssl_alpn_protocol, ossl_ssl_tmp_key): Use
- GetSSL() instead of ossl_ssl_data_get_struct(). Use ssl_started().
-
- (Init_ossl_ssl): Add method declarations of SSLSocket#{initialize,
- hostname=}.
-
- * ext/openssl/ossl_ssl.h (GetSSL): Check that the SSL is not NULL. It
- should not be NULL because we now set it in #initialize.
-
- * ext/openssl/ossl_ssl_session.c (ossl_ssl_session_initialize): No need
- to check if the SSL is NULL.
-
-Sat May 28 10:47:40 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * gems/bundled_gems: Update latest releases, power_assert-0.3.0,
- test-unit 3.1.9, minitest 5.9.0, did_you_mean 1.0.1
-
-Sat May 28 10:45:40 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * addr2line.c: drop support for ATARI ST platform. It was
- discontinued more than two decades ago. [fix GH-1350] Patch by
- @cremno
- * include/ruby/ruby.h: ditto.
- * io.c: ditto.
-
-Sat May 28 10:39:47 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive.rb: Converted exception for
- unavailable Unicode data files to failed assertion.
-
-Sat May 28 10:26:18 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/cgi/util.rb: added missing quote.
- [fix GH-1363][ci skip] Patch by @dwaller
-
-Fri May 27 17:38:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * variable.c (rb_local_constants_i): exclude hidden constants.
- [ruby-core:75575] [Bug #12389]
-
-Fri May 27 17:09:44 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * transcode.c (str_transcode0): scrub in the given encoding when
- the source encoding is given, not in the encoding of the
- receiver. [ruby-core:75732] [Bug #12431]
-
-Fri May 27 15:07:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_scan_args): remove nul padding which
- caused syntax error if fmt is not a string literal.
-
- * include/ruby/ruby.h (rb_scan_args_verify): suppress array-bounds
- warnings by old clang.
-
- * include/ruby/ruby.h (rb_scan_args0): make extractor macros
- inline functions, which do not validate the format and are
- unnecessary to be expanded.
-
-Fri May 27 01:00:36 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * symbol.c (is_identchar): use ISDIGIT instead of rb_enc_isalnum.
- Though rb_enc_isalnum is encoding aware function, its argument here
- is *m, which is a single byte. Therefore ISDIGIT is faster.
-
- * symbol.c (is_special_global_name): ditto.
-
- * symbol.c (rb_enc_symname_type): ditto.
-
-Fri May 27 00:39:40 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_scan_args): add nul padding here to
- apply to all references.
-
- * include/ruby/ruby.h (rb_scan_args_verify): move length mismatch
- check outside conditional operators.
-
-Thu May 26 14:21:10 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_pkey_dh.c (ossl_dh_compute_key): Check that the DH
- has 'p' (the prime) before calling DH_size(). We can create a DH with
- no parameter but DH_size() does not check and dereferences NULL.
- [ruby-core:75720] [Bug #12428]
-
- * ext/openssl/ossl_pkey_dsa.c (ossl_dsa_sign): Ditto. DSA_size() does
- not check dsa->q.
-
- * ext/openssl/ossl_pkey_rsa.c (ossl_rsa_public_encrypt,
- ossl_rsa_public_decrypt, ossl_rsa_private_encrypt,
- ossl_rsa_private_decrypt): Ditto. RSA_size() does not check rsa->n.
-
-Thu May 26 14:13:52 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_scan_args_count): verify length with
- counting variables together.
-
-Thu May 26 09:45:41 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_comprehensive.rb: Add set of comprehensive
- (across most Unicode characters; later across most character encodings)
- tests for case mapping.
-
-Thu May 26 05:00:13 2016 Benoit Daloze <eregontp@gmail.com>
-
- * class.c (rb_define_class): Fix documentation.
-
-Wed May 25 20:50:12 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * re.c (unescape_nonascii): scan hex up to only 3 characters.
- [Bug #12420] [Bug #12423]
-
-Wed May 25 19:07:19 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Handle DOTLESS_i by hand because it isn't involved in folding.
-
-Wed May 25 18:30:53 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * regparse.c (fetch_token_in_cc): raise error if given octal escaped
- character is too big. [Bug #12420] [Bug #12423]
-
-Wed May 25 17:45:15 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl, test/openssl: Drop OpenSSL < 0.9.8 support.
-
-Wed May 25 17:43:30 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/openssl_missing.h, ext/openssl/ossl.h: Remove
- unnecessary 'extern "C"' blocks. We don't use C++ and these headers
- are local to ext/openssl, so there is no need to enclose with it.
-
-Wed May 25 17:42:58 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/extconf.rb: Remove check of OPENSSL_FIPS macro. This is
- unneeded because we can check the macro directly in source code,
- just as we already do for OPENSSL_NO_* macros.
-
- * ext/openssl/ossl.c: Replace occurrences of HAVE_OPENSSL_FIPS with
- OPENSSL_FIPS.
-
-Wed May 25 17:13:35 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (rb_scan_args): merge code for n_trail.
-
-Wed May 25 17:11:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_scan_args_validate): move failed
- condition to the terminal. [ruby-core:75714] [Bug #12426]
-
-Wed May 25 13:13:37 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * regcomp.c: remove condition for debug output because prelude
- doesn't use regexp now.
-
-Wed May 25 13:10:30 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * regcomp.c (compile_length_tree): return error code immediately
- if compile_length_tree raised error [Bug #12418]
-
-Wed May 25 08:01:39 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Fix flag error for switch from titlecase to lowercase.
-
- * test/ruby/enc/test_case_mapping.rb: Tests for above error.
-
-Wed May 25 01:13:55 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_pkey_ec.c (ec_key_new_from_group): Create a new
- EC_KEY on given EC group. Extracted from ossl_ec_key_initialize().
- (ossl_ec_key_s_generate): Added. Create a new EC instance and
- generate a random private and public key.
- (ossl_ec_key_initialize): Use ec_key_new_from_group().
- (Init_ossl_ec): Define the new method EC.generate. This change is
- for consistency with other PKey types. [ruby-core:45541] [Bug #6567]
-
- * test/openssl/test_pkey_ec.rb: Test that EC.generate works.
-
-Wed May 25 00:37:16 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_pkey_ec.c (ossl_ec_key_generate_key): Fix up RDoc.
- (Init_ossl_ec): Rename EC#generate_key to EC#generate_key!. Make the
- old name an alias of #generate_key!. This change is for consistency
- with other PKey types. [ruby-core:45541] [Bug #6567]
-
- * test/openssl/test_pkey_ec.rb: Use EC#generate_key! instead of
- EC#generate_key.
-
-Wed May 25 00:23:05 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_scan_args_set): check the arity after
- adjusting argc for an option hash, for optimization in simpler
- cases.
-
-Wed May 25 00:21:52 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (XCFLAGS): merge flags only for ruby itself from
- ruby_cflags.
-
-Tue May 24 22:04:15 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_cipher.c (ossl_cipher_set_key, ossl_cipher_set_iv):
- Reject too long values as well as too short ones. Currently they
- just truncate the input but this would hide bugs and lead to
- unexpected encryption/decryption results.
-
- * test/openssl/test_cipher.rb: Test that Cipher#key= and #iv= reject
- Strings with invalid length.
-
-Tue May 24 21:32:21 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_x509ext.c (ossl_x509ext_set_value): Use
- ASN1_OCTET_STRING_set() instead of M_ASN1_OCTET_STRING_set(). Macros
- prefixed by "M_" are discouraged to be used from outside OpenSSL
- library[1].
- (ossl_x509ext_get_value): Likewise, use ASN1_STRING_print() instead
- of M_ASN1_OCTET_STRING_print().
- [1] https://git.openssl.org/gitweb/?p=openssl.git;a=blob;f=CHANGES;h=bf61913d7b01212b4d8b2f3c13d71d645914f67c;hb=b6079a7835f61daa9fb2cbf9addfa86049523933#l878
-
- * ext/openssl/ossl.h: Include openssl/asn1.h instead of
- openssl/asn1_mac.h. It just includes openssl/asn1.h and defines some
- additional "M_" macros.
-
-Tue May 24 18:52:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_scan_args_verify): verify the format to
- scan if no invalid chars and variable argument length matching,
- at the compile time if possible.
-
-Tue May 24 17:18:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/defines.h (ERRORFUNC, WARNINGFUNC): add fallback
- definitions.
-
-Tue May 24 16:37:43 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in (ruby_cflags): separate from optflags [Bug #12409]
- -fexcess-precision=standard and -fp-model precise are set to this now.
-
- * configure.in (cflags): use ruby_cflags.
-
-Tue May 24 16:20:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (ERRORFUNC, WARNINGFUNC): __error__ and __warning__
- attributes take a parenthesized string literal.
-
-Tue May 24 12:35:56 2016 URABE Shyouhei <shyouhei@ruby-lang.org>
-
- * common.mk: sort lines, and add missing dependencies suggested
- by tool/update-deps
-
-Mon May 23 21:33:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/missing.h (isfinite): move from numeric.c.
-
-Mon May 23 21:09:06 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl.c (Init_openssl): Avoid reference to unset global
- variable. ossl_raise() may be called before dOSSL is set. Since
- global variables default to 0 and the default value of dOSSL set in
- Init_openssl() is also Qfalse, there is no real issue but confusing.
- Patch by Bertram Scharpf <software@bertram-scharpf.de>
- [ruby-core:58264] [Bug #9101]
-
-Mon May 23 20:32:16 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_asn1.c, ext/openssl/ossl_bn.c,
- ext/openssl/ossl_cipher.c, ext/openssl/ossl_digest.c
- ext/openssl/ossl_engine.c, ext/openssl/ossl_ns_spki.c
- ext/openssl/ossl_pkcs12.c, ext/openssl/ossl_pkcs7.c
- ext/openssl/ossl_pkey.c, ext/openssl/ossl_pkey_ec.c
- ext/openssl/ossl_rand.c, ext/openssl/ossl_ssl.c
- ext/openssl/ossl_x509attr.c, ext/openssl/ossl_x509cert.c
- ext/openssl/ossl_x509ext.c, ext/openssl/ossl_x509store.c: Use
- StringValueCStr() where NUL-terminated string is expected.
-
-Mon May 23 20:20:12 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/bigdecimal/bigdecimal.c (isfinite): get rid of a warning on
- cygwin. [Bug #12417][ruby-core:75691]
-
-Mon May 23 19:41:27 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_rand.c (ossl_rand_egd, ossl_rand_egd_bytes):
- RAND_egd{_bytes,}() return -1 on failure, not 0.
- Patch by cremno phobia <cremno@mail.ru>
- [ruby-core:63795] [Bug #10053]
- (ossl_pseudo_bytes): Similar, RAND_pseudo_bytes() may return 0 or
- -1 on failure.
-
-Mon May 23 15:52:07 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ext/bigdecimal/bigdecimal.c (isfinite): isfinite does not always
- exist. fixed build error on Windows introduced at r55123.
-
-Mon May 23 13:19:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_scan_args0): make compile error if the
- format is wrong or does not match with the variable argument
- length if possible.
-
-Mon May 23 12:47:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_scan_args0): raise fatal error if
- variable argument length does not match, it is a bug in the code
- which uses rb_scan_args, not a runtime error.
-
-Mon May 23 12:30:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/bigdecimal/bigdecimal.c (GetVpValueWithPrec): consider
- non-finite float values not to raise FloatDomainError.
- [ruby-core:75682] [Bug #12414]
-
-Mon May 23 12:21:18 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * array.c (rb_ary_fill): suppress warnings: 'item' may be used
- uninitialized in this function
-
-Mon May 23 07:41:49 2016 Eric Wong <e@80x24.org>
-
- * dir.c (dir_close): update RDoc for 2.3 #close change
- [ruby-core:75679] [Bug #12413]
-
-Sun May 22 20:01:21 2016 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
-
- * lib/drb/timeridconv.rb: use finalizer trick instead of thread.
-
- * test/drb/ut_timerholder.rb: ditto.
-
-Sun May 22 17:25:18 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_options.rb: adjust test class name
- to match file name
-
-Sun May 22 17:24:07 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * rename test/ruby/enc/test_casing_options.rb to test_case_options.rb
- for consistency
-
-Sun May 22 17:06:55 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * transcode.c (enc_arg, str_transcode_enc_args, econv_args):
- remove volatile, and add GC guards in callers.
- [ruby-core:75664] [Bug #12411]
-
-Sun May 22 16:27:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/-test-/integer/core_ext.c: move testutil/integer.c.
-
- * test/lib/-test-/integer.rb: extract implementation details from
- test/unit/assertions.rb. [Bug #12408]
-
-Sun May 22 14:57:43 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * include/ruby/oniguruma.h: Extend OnigEncodingTypeDefine to define a
- new encoding primitive 'case_map' for case mapping
-
- * enc/utf-8.c, utf_16be/le.c, utf_32be/le.c:
- add onigenc_unicode_case_map as case_map primitive
-
- * enc/ascii.c, big5.c, cp949.c, emacs_mule.c, euc_jp/kr/tw.c, gb18030.c,
- gbk.c, iso_8859_1/2/3/4/5/6/7/8/9/10/11/13/14/15/16.c, koi8_r/u.c,
- shift_jis.c, us_ascii.c, windows_1250/1251/1252.c:
- add onigenc_not_support_case_map as case_map primitive
-
-Sun May 22 14:45:45 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * regenc.h/c: Define new function onigenc_not_support_case_map
-
-Sun May 22 12:14:06 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_scan_args): use original rb_scan_args
- when fmt is dynamic.
-
-Sun May 22 11:41:12 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * class.c (rb_scan_args): moved to bottom of the file to make the
- effect of `#undef rb_scan_args` the minimum.
-
- * include/ruby/ruby.h (rb_scan_args): overwrite only if GCC and
- optimized. Visual C++ 14 or later can compile it but make it
- conservative.
-
-Sat May 21 22:45:50 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_scan_args): don't use ALWAYS_INLINE with
- `inline`. if gcc needs this duplication, do in ALWAYS_INLINE macro.
-
-Sat May 21 21:11:56 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_scan_args): use __VA_ARGS__ instead of
- va_arg to allow compilers optimize more aggressive.
- https://gustedt.wordpress.com/2011/07/10/avoid-writing-va_arg-functions/
- rb_scan_args is now expected to be statically resolved.
-
-Sun May 22 02:41:52 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/zlib/zlib.c: remove hacky macro introduced at r30437.
-
- * ext/zlib/zlib.c (gzfile_make_header): cast as long (instead of int).
-
- * ext/zlib/zlib.c (gzfile_make_footer): ditto.
-
-Sat May 21 21:07:18 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in (ALWAYS_INLINE): force compilers the function inlined.
-
-Sat May 21 16:16:03 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_ssl.c (ossl_ssl_stop): Don't free the SSL struct
- here. Since some methods such as SSLSocket#connect releases GVL,
- there is a chance of use after free if we free the SSL from another
- thread. SSLSocket#stop was documented as "prepares it for another
- connection" so this is a slightly incompatible change. However when
- this sentence was added (r30090, Add toplevel documentation for
- OpenSSL, 2010-12-06), it didn't actually. The current behavior is
- from r40304 (Correct shutdown behavior w.r.t GC., 2013-04-15).
- [ruby-core:74978] [Bug #12292]
-
- * ext/openssl/lib/openssl/ssl.rb (sysclose): Update doc.
-
- * test/openssl/test_ssl.rb: Test this.
-
-Sat May 21 14:41:14 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl.c: [DOC] Fix SSL client example. The variable name
- was wrong. Patch by Andreas Tiefenthaler <at@an-ti.eu> (@pxlpnk).
- [GH ruby/openssl#32]
-
-Sat May 21 14:25:38 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_pkey_ec.c: rename PKey::EC#private_key? and
- #public_key? to #private? and #public? for consistency with other
- PKey types. Old names remain as alias. [ruby-core:45541] [Bug #6567]
-
- * test/openssl/test_pkey_ec.rb (test_check_key): check private? and
- public? works correctly.
-
-Sat May 21 12:40:36 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/lib/openssl/buffering.rb (read_nonblock, readpartial):
- Remove impossible EOFError raise. Patch by Zach Anker
- <zanker@squareup.com>. [GH ruby/openssl#23]
-
-Sat May 21 11:18:42 2016 Evgeni Golov <evgeni@golov.de>
-
- * lib/ipaddr.rb: [DOC] fix documentation of IN6MASK to mention
- IPv6. [Fix GH-1349]
-
-Sat May 21 11:12:53 2016 Dan Martinez <dfm@razorwind.org>
-
- * io.c (Init_IO): [DOC] define dummy ARGF instead of ARGF.class to
- re-enable the generation of ARGF documentation. [Fix GH-1358]
-
-Sat May 21 11:07:29 2016 0x01f7 <souk.0x01f7@gmail.com>
-
- * doc/syntax/methods.rdoc (Method Names): add proper closing tag.
- [Fix GH-1356]
-
-Sat May 21 09:26:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (RUBY_CHECK_SETJMP): fix missing macro definition
- for the configured result. fix up r55021.
-
-Sat May 21 00:36:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * process.c (rb_execarg_commandline): build command line string
- from argument vector in rb_execarg.
- [ruby-core:75611] [Bug #12398]
-
-Fri May 20 23:25:42 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl.c (ossl_pem_passwd_value): Added. Convert the
- argument to String with StringValue() and validate the length is in
- 4..PEM_BUFSIZE. PEM_BUFSIZE is a macro defined in OpenSSL headers.
- (ossl_pem_passwd_cb): When reading/writing encrypted PEM format, we
- used to pass the password to PEM_def_callback() directly but it was
- problematic. It is not NUL character safe. And surprisingly, it
- silently truncates the password to 1024 bytes. [GH ruby/openssl#51]
-
- * ext/openssl/ossl.h: Add function prototype declaration of newly
- added ossl_pem_passwd_value().
-
- * ext/openssl/ossl_pkey.c (ossl_pkey_new_from_data): Use
- ossl_pem_passwd_value() to validate the password String.
-
- * ext/openssl/ossl_pkey_dsa.c (ossl_dsa_initialize, ossl_dsa_export):
- ditto.
-
- * ext/openssl/ossl_pkey_ec.c (ossl_ec_key_initialize,
- ossl_ec_key_to_string): ditto.
-
- * ext/openssl/ossl_pkey_rsa.c (ossl_rsa_initialize, ossl_rsa_export):
- ditto.
-
- * test/openssl/test_pkey_{dsa,ec,rsa}.rb: test this.
-
-Fri May 20 23:45:53 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * id_table.c (list_id_table_init): When unaligned word access is
- prohibited and sizeof(VALUE) is 8 (64-bit machines),
- capa should always be even number for 8-byte word alignment
- of the values of a table. This code assumes that sizeof(ID) is 4,
- sizeof(VALUE) is 8, and xmalloc() returns 8-byte aligned memory.
- This fixes bus error on 64-bit SPARC Solaris 10.
- [Bug #12406][ruby-dev:49631]
-
-Fri May 20 22:30:09 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * symbol.h (rb_id2sym): Use HAVE_BUILTIN___BUILTIN_CONSTANT_P
-
-Fri May 20 22:19:00 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * ext/date/date_core.c: [DOC] fix typos.
- [fix GH-1360] patched by @soundasleep
-
-Fri May 20 21:26:58 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * include/ruby/defines.h (RB_GNUC_EXTENSION, RB_GNUC_EXTENSION_BLOCK):
- macros for skipping __extension__ on non-GCC compilers.
- * eval_error.c (warn_print): use RB_GNUC_EXTENSION_BLOCK instead of
- __extension__ because __extension__ is a GNU extension.
- Fix compile error on Solaris 10 with Oracle Solaris Studio 12.x.
- [Bug #12397] [ruby-dev:49629].
- * internal.h (rb_fstring_cstr, rb_fstring_enc_cstr): ditto
- * include/ruby/encoding.h (rb_enc_str_new, rb_enc_str_new_cstr): ditto
- * include/ruby/intern.h (rb_str_new, rb_str_new_cstr,
- rb_usascii_str_new, rb_utf8_str_new, rb_tainted_str_new_cstr,
- rb_usascii_str_new_cstr, rb_utf8_str_new_cstr,
- rb_external_str_new_cstr, rb_locale_str_new_cstr,
- rb_str_buf_new_cstr, rb_str_cat_cstr, rb_exc_new_cstr): ditto
-
-Fri May 20 21:17:13 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32ole/win32ole.c (fole_missing): make substring or dup to
- share the content if possible.
-
-Fri May 20 19:48:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * internal.h (NEW_PARTIAL_MEMO_FOR): shrink buffer array not to
- mark non-VALUE fields. fix check_rvalue_consistency abort with
- RGENGC_CHECK_MODE=2.
-
- * internal.h (NEW_CMP_OPT_MEMO): exclude struct cmp_opt_data from
- the valid array range.
-
- * enum.c (slicewhen_i): exclude inverted too.
-
-Thu May 19 21:21:57 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * re.c (rb_reg_match_m_p): [DOC] fix return value in rdoc.
-
- * test/ruby/test_regexp.rb (TestRegexp#test_match_p): add some
- tests from document.
-
-Thu May 19 13:22:44 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl.c (Init_openssl): register an ex_data index for
- X509_STORE and X509_STORE_CTX respectively. Since they don't share
- the ex_data index registry, we can't use the same index.
- (ossl_verify_cb): use the correct index.
-
- * ext/openssl/ossl_ssl.c (ossl_ssl_verify_callback): ditto.
-
- * ext/openssl/ossl_x509store.c (ossl_x509store_set_vfy_cb): ditto.
- (ossl_x509stctx_verify): ditto.
-
- * ext/openssl/ossl.h (void ossl_clear_error): add extern declarations
- of ossl_store_{ctx_,}ex_verify_cb_idx.
-
- * ext/openssl/openssl_missing.c: remove X509_STORE_set_ex_data and
- X509_STORE_get_ex_data.
-
- * ext/openssl/openssl_missing.h: implement X509_STORE_get_ex_data,
- X509_STORE_set_ex_data and X509_STORE_get_ex_new_index as macros.
-
-Thu May 19 13:11:35 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_x509attr.c (ossl_x509attr_set_value): check that the
- argument is an OpenSSL::ASN1::Data before converting to ASN1_TYPE.
- This fixes SEGV on OpenSSL::X509::Attribute#value=(non-asn1-value).
-
- * test/openssl/test_x509attr.rb: add tests for OpenSSL::X509::Attribute.
-
-Thu May 19 12:10:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * re.c (rb_reg_match_m_p): fix match against empty string.
- rb_str_offset returns the end when the position exceeds the
- length. fix the range parameter of onig_search.
- [ruby-core:75604] [Bug #12394]
-
-Thu May 19 11:37:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * re.c (rb_reg_match_m_p): should return false if no match, as the
- document says. [Feature #8110]
-
-Thu May 19 00:17:01 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * re.c (reg_names_iter): specify capacify
-
-Wed May 18 21:29:59 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * thread.c (recursive_list_access): a object id may be a Bignum. so,
- the list must be a objhash, instead of a identhash.
- this fixes many test errors on mswin64 CI.
-
-Wed May 18 19:33:54 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * re.c (rb_reg_match_m_p): Introduce Regexp#match?, which returns
- bool and doesn't save backref.
-
-Wed May 18 16:52:03 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_pkcs12.c (ossl_pkcs12_initialize): pop errors
- leaked by PKCS12_parse(). This is a bug in OpenSSL, which exists
- in the versions before the version 1.0.0t, 1.0.1p, 1.0.2d.
-
-Wed May 18 16:04:54 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/downloader.rb (Downloader::RubyGems.download): verify gems
- only if RubyGems is 2.4 or later. old RubyGems fails to verify
- almost all of bundled gems.
-
-Wed May 18 14:52:38 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_modify_expand): check integer overflow.
- [ruby-core:75592] [Bug #12390]
-
-Wed May 18 13:11:44 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * re.c (match_ary_subseq): get subseq of match array without creating
- temporary array.
-
- * re.c (match_ary_aref): get element(s) of match array without creating
- temporary array.
-
- * re.c (match_aref): Use match_ary_subseq with handling irregulars.
-
- * re.c (match_values_at): Use match_ary_aref.
-
-Wed May 18 13:03:07 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_x509cert.c (ossl_x509_verify): X509_verify()
- family may put errors on 0 return (0 means verification failure).
- Clear OpenSSL error queue before return to Ruby. Since the queue is
- thread global, remaining errors in the queue can cause an unexpected
- error in the next OpenSSL operation. [ruby-core:48284] [Bug #7215]
-
- * ext/openssl/ossl_x509crl.c (ossl_x509crl_verify): ditto.
-
- * ext/openssl/ossl_x509req.c (ossl_x509req_verify): ditto.
-
- * ext/openssl/ossl_x509store.c (ossl_x509stctx_verify): ditto.
-
- * ext/openssl/ossl_pkey_dh.c (dh_generate): clear the OpenSSL error
- queue before re-raising exception.
-
- * ext/openssl/ossl_pkey_dsa.c (dsa_generate): ditto.
-
- * ext/openssl/ossl_pkey_rsa.c (rsa_generate): ditto.
-
- * ext/openssl/ossl_ssl.c (ossl_start_ssl): ditto.
-
- * test/openssl: check that OpenSSL.errors is empty every time after
- running a test case.
-
-Wed May 18 12:07:42 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl.c (ossl_clear_error): Extracted from
- ossl_make_error(). This prints errors in the OpenSSL error queue if
- OpenSSL.debug is true, and clears the queue.
- (ossl_make_error): use ossl_clear_error().
-
- * ext/openssl/ossl.h: add prototype declaration of ossl_make_error().
- (OSSL_BIO_reset) use ossl_clear_error() to clear the queue. Clearing
- silently makes debugging difficult.
-
- * ext/openssl/ossl_engine.c (ossl_engine_s_by_id): ditto.
-
- * ext/openssl/ossl_ns_spki.c (ossl_spki_initialize): ditto.
-
- * ext/openssl/ossl_pkcs7.c (ossl_pkcs7_verify): ditto.
-
- * ext/openssl/ossl_pkey_dsa.c (ossl_dsa_initialize): ditto.
-
- * ext/openssl/ossl_pkey_ec.c (ossl_ec_key_initialize): ditto.
- (ossl_ec_group_initialize): ditto.
-
- * ext/openssl/ossl_ssl.c (ossl_ssl_shutdown): ditto.
-
-Wed May 18 11:53:49 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_pkey_ec.c (ossl_ec_point_mul): Validate the
- arguments before passing to EC_POINT(s)_mul(). Add description of this
- method. [ruby-core:65152] [Bug #10268]
-
- * test/openssl/test_pkey_ec.rb (test_ec_point_mul): Test that
- OpenSSL::PKey::EC::Point#mul works.
-
-Wed May 18 11:19:59 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/ossl_bn.c (try_convert_to_bnptr): Extracted from
- GetBNPtr(). This doesn't raise exception but returns NULL on error.
- (GetBNPtr): Raise TypeError if conversion fails.
- (ossl_bn_eq): Implement BN#==.
- (ossl_bn_eql): #eql? should not raise TypeError even if the argument
- is not compatible with BN.
- (ossl_bn_hash): Implement BN#hash.
-
- * ext/openssl/ossl_bn.c (Init_ossl_bn): Define #== and #hash.
-
- * test/openssl/test_bn.rb: Test BN#eql?, #== and #hash
-
-Wed May 18 10:17:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (RB_INTEGER_TYPE_P): new macro and
- underlying inline function to check if the object is an
- Integer (Fixnum or Bignum).
-
-Wed May 18 09:52:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * enum.c (enum_sum, hash_sum, hash_sum_i, enum_sum_i, sum_iter):
- Optimize for hashes when each method isn't redefined.
-
-Wed May 18 09:14:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * enum.c (enum_sum, int_range_sum): Extract int_range_sum from
- enum_sum.
-
-Wed May 18 03:16:06 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * re.c (match_values_at): fix regression at r55036.
- MatchData#values_at accepts Range.
-
-Wed May 18 02:02:58 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * re.c (match_aref): remove useless condition and call rb_fix2int.
- rb_reg_nth_match handles negative index.
-
-Wed May 18 01:57:43 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * re.c (match_values_at): MatchData#values_at supports named captures
- [Feature #9179]
-
- * re.c (namev_to_backref_number): separated.
-
-Wed May 18 00:05:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * enum.c (enum_sum): Optimize for a range from int to int.
-
- * test/ruby/test_enum.rb (test_range_sum): Move from test_range.rb,
- and add assertions for some conditions.
-
- * test/ruby/test_enum.rb (test_hash_sum): Move from test_hash.rb.
-
- * test/ruby/test_hash.rb, test/ruby/test_range.rb: Remove test_sum.
-
-Tue May 17 23:08:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * enum.c (enum_sum): [DOC] Write documentation.
-
-Tue May 17 22:53:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * enum.c (enum_sum): Implement Enumerable#sum.
-
- * test/ruby/test_enum.rb (test_sum): Test sum for Enumerable.
-
- * test/ruby/test_hash.rb (test_sum): Test sum for Hash.
-
- * test/ruby/test_range.rb (test_sum): Test sum for Range.
-
-Tue May 17 22:11:41 2016 Tanaka Akira <akr@fsij.org>
-
- * object.c, numeric.c, enum.c, ext/-test-/bignum/mul.c,
- lib/rexml/quickpath.rb, lib/rexml/text.rb, lib/rexml/xpath_parser.rb,
- lib/rubygems/specification.rb, lib/uri/generic.rb,
- bootstraptest/test_eval.rb, basictest/test.rb,
- test/-ext-/bignum/test_big2str.rb, test/-ext-/bignum/test_div.rb,
- test/-ext-/bignum/test_mul.rb, test/-ext-/bignum/test_str2big.rb,
- test/csv/test_data_converters.rb, test/date/test_date.rb,
- test/json/test_json_generate.rb, test/minitest/test_minitest_mock.rb,
- test/openssl/test_cipher.rb, test/rexml/test_jaxen.rb,
- test/ruby/test_array.rb, test/ruby/test_basicinstructions.rb,
- test/ruby/test_bignum.rb, test/ruby/test_case.rb,
- test/ruby/test_class.rb, test/ruby/test_complex.rb,
- test/ruby/test_enum.rb, test/ruby/test_eval.rb,
- test/ruby/test_iseq.rb, test/ruby/test_literal.rb,
- test/ruby/test_math.rb, test/ruby/test_module.rb,
- test/ruby/test_numeric.rb, test/ruby/test_range.rb,
- test/ruby/test_rational.rb, test/ruby/test_refinement.rb,
- test/ruby/test_rubyvm.rb, test/ruby/test_struct.rb,
- test/ruby/test_variable.rb, test/rubygems/test_gem_specification.rb,
- test/thread/test_queue.rb: Use Integer instead of Fixnum and Bignum.
-
-Tue May 17 15:26:10 2016 Tanaka Akira <akr@fsij.org>
-
- * [Feature #12005] Unify Fixnum and Bignum into Integer
-
- * include/ruby/ruby.h (rb_class_of): Return rb_cInteger for fixnums.
-
- * insns.def (INTEGER_REDEFINED_OP_FLAG): Unified from
- FIXNUM_REDEFINED_OP_FLAG and BIGNUM_REDEFINED_OP_FLAG.
-
- * vm_core.h: Ditto.
-
- * vm_insnhelper.c (opt_eq_func): Use INTEGER_REDEFINED_OP_FLAG instead
- of FIXNUM_REDEFINED_OP_FLAG.
-
- * vm.c (vm_redefinition_check_flag): Use rb_cInteger instead of
- rb_cFixnum and rb_cBignum.
- (C): Use Integer instead of Fixnum and Bignum.
-
- * numeric.c (fix_succ): Removed.
- (Init_Numeric): Define Fixnum as Integer.
-
- * bignum.c (bignew): Use rb_cInteger instead of rb_cBignum.
- (rb_int_coerce): replaced from rb_big_coerce and return fixnums
- as-is.
- (Init_Bignum): Define Bignum as Integer.
- Don't define ===.
-
- * error.c (builtin_class_name): Return "Integer" for fixnums.
-
- * sprintf.c (ruby__sfvextra): Use rb_cInteger instead of rb_cFixnum.
-
- * ext/-test-/testutil: New directory to test.
- Currently it provides utilities for fixnum and bignum.
-
- * ext/json/generator/generator.c: Define mInteger_to_json.
-
- * lib/mathn.rb (Fixnum#/): Redefinition removed.
-
-Tue May 17 11:58:58 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (RUBY_CHECK_BUILTIN_SETJMP): declare t as NORETURN
- to suppress warnings by -Wsuggest-attribute=noreturn.
- [ruby-core:75510] [Bug #12383]
-
-Tue May 17 10:40:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (RUBY_CHECK_SETJMP): needs the header and proper
- arguments for builtin setjmp functions.
-
-Mon May 16 20:00:30 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.h: Additional uses of ONIG_CASE_MAPPING compilation switch
-
-Mon May 16 19:46:33 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * include/ruby/oniguruma.h: Introducing ONIG_CASE_MAPPING compilation
- switch
-
- * include/ruby/oniguruma.h, enc/unicode.h: Using ONIG_CASE_MAPPING
- compilation switch
-
-Mon May 16 19:29:31 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * gems/bundled_gems: Update xmlrpc-0.1.1. xmlrpc-0.1.0 didn't allow
- to install on 2.4.0dev.
-
-Mon May 16 13:28:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (FUNC_STDCALL, FUNC_CDECL, FUNC_FASTCALL): set
- macro names explicitly to the old names, which are accidentally
- changed at r54985, for backward compatibilities.
- fiddle also depends on these names to fallback to ANSI names.
- [ruby-core:75494] [Bug #12377]
-
-Mon May 16 11:39:02 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/xmlrpc.rb, lib/xmlrpc/*, test/xmlrpc: XMLRPC is bundled gem
- on Ruby 2.4. It is extracted to https://github.com/ruby/xmlrpc
- [Feature #12160][ruby-core:74239]
- * gems/bundled_gems: ditto.
-
-Mon May 16 06:06:21 2016 Eric Wong <e@80x24.org>
-
- * proc.c: fix RDoc of Proc#===/call/yield/[]
- [Bug #12332]
-
-Sun May 15 20:55:31 2016 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
-
- * lib/drb/timeridconv.rb: don't use keeper thread. [Bug #12342]
-
- * test/drb/ut_timerholder.rb: ditto.
-
-Sun May 15 16:15:25 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * array.c (rb_ary_entry): extract rb_ary_elt to organize if-conditions
- and check whether is embedded at once.
-
-Sun May 15 10:57:26 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_insnhelper.c (vm_get_ev_const): warn deprecated constant even
- in the class context. [ruby-core:75505] [Bug #12382]
-
-Sun May 15 03:13:01 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * iseq.h (struct iseq_compile_data): use struct rb_id_table
- instead of st_table.
-
- * iseq.c (prepare_iseq_build): don't allocate ivar_cache_table
- until it has at least one element.
-
- * iseq.c (compile_data_free): free ivar_cache_table only if it
- is allocated.
-
- * compile.c (get_ivar_ic_value): allocate if the table is not
- allocated yet.
-
-Sat May 14 09:04:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (pkg_config): use xsystem consistently to set up
- library path environment variable as well as latter pkg-config
- calls. [ruby-dev:49619] [Bug #12379]
-
-Sat May 14 00:16:54 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * random.c (make_seed_value): append leading-zero-guard and get
- rid of making a local copy of the seed.
-
-Fri May 13 08:46:42 2016 cremno <cremno@mail.ru>
-
- * NEWS: drop FreeBSD < 4 support. [Fix GH-1339]
- The most recent version affected by this is 3.5 and was released
- in 2000.
- https://www.freebsd.org/releases/3.5R/announce.html
- https://en.wikipedia.org/wiki/History_of_FreeBSD#Version_history
-
-Fri May 13 03:12:09 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * include/ruby/defines.h (GCC_VERSION_SINCE): moved from internal.h.
-
-Fri May 13 03:11:20 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in (__builtin_constant_p): check.
-
- * internal.h: Use HAVE_BUILTIN___BUILTIN_CONSTANT_P
-
-Fri May 13 03:10:39 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: use alternative keyword
- to avoid macros conflicts with them.
-
-Thu May 12 01:54:08 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/mkmf.rb (try_func): get rid of conflict of declarations of
- main(). checking local symbol reference does not make sense.
-
-Thu May 12 00:18:19 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/Makefile.sub (HAVE_QSORT_S): use qsort_s only for Visual Studio
- 2012 or later, because VS2010 seems to causes a SEGV in
- test/ruby/test_enum.rb.
-
-Wed May 11 23:59:47 2016 Masaya Tarui <tarui@ruby-lang.org>
-
- * vm_insnhelper.c (vm_getivar): describe fast-path explicit
- (compiler friendly). [Bug #12274].
-
-Wed May 11 21:30:07 2016 Masaya Tarui <tarui@ruby-lang.org>
-
- * compile.c (iseq_compile_each): share InlineCache during same
- instance variable accesses. Reducing memory consumption,
- rising cache hit rate and rising branch prediction hit rate
- are expected. A part of [Bug #12274].
-
- * iseq.h (struct iseq_compile_data): introduce instance
- variable IC table for sharing.
-
- * iseq.c (prepare_iseq_build, compile_data_free):
- construct/destruct above table.
-
-Wed May 11 17:18:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * util.c (ruby_qsort): use qsort_s if available, for Microsoft
- Visual Studio 2005 (msvcr80.dll) and mingw.
-
-Wed May 11 10:33:26 2016 Marcus Stollsteimer <sto.mar@web.de>
-
- * COPYING: Remove trailing-whitespaces.
- [ci skip][fix GH-1348]
-
-Tue May 10 21:05:45 2016 Benoit Daloze <eregontp@gmail.com>
-
- * insns.def (defineclass): Also raise an error when redeclaring the
- superclass of a class as Object and it has another superclass.
- [Bug #12367] [ruby-core:75446]
-
- * test/ruby/test_class.rb: test for above.
-
-Tue May 10 14:57:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * random.c (obj_random_bytes): base on bytes method instead of
- rand method, not to call toplevel rand method.
-
-Tue May 10 13:07:28 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in (-fexcess-precision=standard): before r54895 -std=c99
- is specified and it implied -fexcess-precision=standard.
- Now with -std=gnu99, it should be explicitly specified.
- https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
-
-Mon May 9 10:51:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (rb_thread_atfork_internal): move th to an argument.
-
- * thread.c (rb_thread_atfork): do not repeat GET_THREAD().
-
-Mon May 9 10:46:36 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (rb_thread_atfork, rb_thread_atfork_before_exec): do
- nothing unless working fork is available.
-
- * thread_sync.c (rb_mutex_abandon_all): define only if working
- fork is available.
-
- * thread_sync.c (rb_mutex_abandon_keeping_mutexes): ditto.
-
- * thread_sync.c (rb_mutex_abandon_locking_mutex): ditto.
-
- * thread_win32.c (gvl_init): never used.
-
-Mon May 9 07:18:06 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * include/ruby/{defines,ruby}.h: need to define function attributes
- alternatives in defines.h instead of ruby.h, because they are used
- in oniguruma.h and the header used without including ruby.h at
- encoding library sources.
-
-Mon May 9 06:30:12 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * include/ruby/ruby.h (CONSTFUNC, PUREFUNC): fixed build errors on
- non-gcc build environments introduced at r54952.
-
-Mon May 9 02:51:51 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * gc.c (rb_gc_unprotect_logging): throw rb_memerror when it cannot
- allocate memory. This is pointed out by Facebook's Infer.
-
- * gc.c (gc_prof_setup_new_record): ditto.
-
- * regparse.c (parse_regexp): ditto.
-
- * util.c (MALLOC): use xmalloc and xfree like above.
-
-Mon May 9 02:39:16 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: check function attribute const and pure,
- and define CONSTFUNC and PUREFUNC if available.
- Note that I don't add those options as default because
- it still shows many false-positive (it seems not to consider
- longjmp).
-
- * vm_eval.c (stack_check): get rb_thread_t* as an argument
- to avoid duplicate call of GET_THREAD().
-
-Sun May 8 21:01:14 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/openssl/extconf.rb: assume it doesn't have SSLv2 related
- functions when OPENSSL_NO_SSL2 is defined.
- Usually openssl's header and the library (libssl) have the same
- set of functions, but on some environment the library has functions
- whose headers doesn't declare. (openssl/opensslconf.h and libssl.so
- aren't be synchronized)
- To detect such case explicitly check feature macro and remove
- related functions.
-
-Sun May 8 18:51:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (rb_home_dir_of): return the default home path if the
- user name is the current user name, on platforms where struct
- pwd is not supported. a temporary measure against
- [Bug #12226].
-
-Sun May 8 08:51:38 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: add -Wsuggest-attribute=format and suppress warnings.
-
-Sun May 8 08:31:03 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: add -Wsuggest-attribute=noreturn and suppress warnings.
-
-Sun May 8 08:19:16 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: add -Werror=implicit-int to avoid missing type of
- function declaration.
-
-Sat May 7 22:22:37 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/webrick/ssl.rb: Accept string value for SSLCertName. It is used
- to invoke ssl server with command line.
- [fix GH-1329] Patch by @kerlin
- * test/webrick/test_ssl_server.rb: Added test for GH-1329
-
-Sat May 7 21:55:12 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * test/webrick/test_ssl_server.rb: Added basic test for `webrick/ssl`
-
-Sat May 7 16:22:13 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * random.c (int_pair_to_real_inclusive): optimize to multiply
- without Bignum.
-
-Sat May 7 07:58:02 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * process.c (rb_exec_getargs): honor the expected argument types
- over the conversion method. the basic language functionality
- should be robust. [ruby-core:75388] [Bug #12355]
-
-Fri May 6 08:16:26 2016 David Silva <david.silva@digital.cabinet-office.gov.uk>
-
- * enum.c (enum_find): [DOC] add more examples to the documentation
- of Enumerable#detect, to show that it equals to Enumerable#find.
- [Fix GH-1340]
-
-Thu May 5 18:08:31 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * test/ruby/test_complexrational.rb: Remove duplicated raise.
-
-Thu May 5 14:41:05 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * string.c (rb_str_sub): Fix a special match variable name.
- [ci skip]
-
-Thu May 5 12:22:17 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (rb_eval_cmd, rb_catch_obj): use TH_JUMP_TAG with the
- same rb_thread_t used for TH_PUSH_TAG, instead of JUMP_TAG with
- the current thread global variable.
-
-Thu May 5 10:49:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * random.c (fill_random_bytes_syscall): use arc4random_buf if
- available.
-
-Wed May 4 23:13:58 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * numeric.c (fix_plus): Remove rb_nucomp_add prototype
- declaration.
-
- * numeric.c (fix_mul): Remove rb_nucomp_mul prototype
- declaration.
-
- * internal.h (rb_nucomp_add, rb_nucomp_mul): add prototype
- declarations.
-
-Wed May 4 18:38:00 2016 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * lib/net/http/header.rb (Net::HTTPHeader#{each_header,each_name,
- each_capitalized_name,each_value,each_capitalized}): Return
- sized enumerators.
-
- * test/net/http/test_httpheader.rb: add test for above.
-
-Wed May 4 17:53:15 2016 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * lib/set.rb (Set#{delete_if,keep_if,collect!,reject!,select!,classify,divide},
- SortedSet#{delete_if,keep_if}): Return sized enumerators.
-
- * test/test_set.rb: add test for above.
-
-Tue May 3 23:25:48 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * numeric.c: [DOC] Update result of 123456789 ** -2.
- [ruby-dev:49606] [Bug #12339]
-
-Tue May 3 23:13:16 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * internal.h (RCOMPLEX_SET_IMAG): undef RCOMPLEX_SET_IMAG
- instead of duplicated undef RCOMPLEX_SET_REAL.
-
-Tue May 3 22:55:07 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * complex.c (rb_complex_set_imag): Fix to properly set imag
- of complex.
-
-Tue May 3 22:19:55 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in (warnflags): use -std=gnu99 instead of
- -std=iso9899:1999. [Feature #12336]
-
-Tue May 3 22:10:09 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (count_utf8_lead_bytes_with_word): Use __builtin_popcount
- only if it can use SSE 4.2 POPCNT whose latency is 3 cycle.
-
- * internal.h (rb_popcount64): use __builtin_popcountll because now
- it is in fast path.
-
-Tue May 3 14:19:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (new_if_gen): set newline flag to NODE_IF to trace all
- if/elsif statements. [ruby-core:67720] [Bug #10763]
-
-Tue May 3 05:35:54 2016 Eric Wong <e@80x24.org>
-
- * process.c (disable_child_handler_fork_child):
- initialize handler for SIGPIPE for !POSIX_SIGNAL
-
-Mon May 2 23:03:42 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c, include/ruby/win32.h (rb_w32_utruncate): implements new
- truncate alternative which accepts UTF-8 path.
-
- * file.c (truncate): use above function.
- [Bug #12340]
-
-Mon May 2 20:59:21 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * re.c (str_coderange): to avoid function call when the string already
- has coderange information.
-
- * re.c (rb_reg_prepare_enc): add shortcut path when the regexp has
- the same encoding of given string.
-
- * re.c (rb_reg_prepare_re): avoid duplicated allocation of
- onig_errmsg_buffer.
-
-
-Mon May 2 12:34:52 2016 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_refinement.rb (test_inspect): Use Integer instead of
- Fixnum.
-
-Mon May 2 06:58:38 2016 Tanaka Akira <akr@fsij.org>
-
- * complex.c: Don't refer rb_cFixnum and rb_cBignum.
- (k_fixnum_p): Use FIXNUM_P.
- (k_bignum_p): Use RB_TYPE_P.
-
-Mon May 2 01:27:59 2016 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_numeric.rb (test_step): Use Integer::FIXNUM_MAX.
-
-Mon May 2 01:15:01 2016 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_module.rb (test_name): Use Integer instead of Fixnum.
-
-Mon May 2 01:00:04 2016 Tanaka Akira <akr@fsij.org>
-
- * test/lib/test/unit/assertions.rb (assert_fixnum): Defined.
- (assert_bignum): Defined.
-
- * test/ruby/test_bignum.rb: Use assert_bignum.
-
- * test/ruby/test_integer_comb.rb: Use assert_fixnum and assert_bignum.
-
- * test/ruby/test_optimization.rb: Ditto.
-
-Mon May 2 00:41:53 2016 Tanaka Akira <akr@fsij.org>
-
- * vm_trace.c (recalc_remove_ruby_vm_event_flags): Add a cast to
- avoid signed integer overflow.
-
-Mon May 2 00:06:04 2016 Tanaka Akira <akr@fsij.org>
-
- * test/lib/envutil.rb: Define Integer::{FIXNUM_MIN,FIXNUM_MAX}.
-
- * test/ruby/test_bignum.rb: Use Integer::{FIXNUM_MIN,FIXNUM_MAX}.
-
- * test/ruby/test_bignum.rb: Ditto.
-
- * test/ruby/test_integer_comb.rb: Ditto.
-
- * test/ruby/test_marshal.rb: Ditto.
-
- * test/ruby/test_optimization.rb: Ditto.
-
-Sun May 1 23:59:59 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * array.c (rb_ary_sum): fix for mathn
-
- * test/ruby/test_array.rb (test_sum): ditto.
-
-Sun May 1 23:51:54 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * test/lib/test/unit.rb (Options#non_options): fixed wrong regexp.
- if both positives and negatives were specified, positives had to
- be specified from the beginning.
-
-Sun May 1 21:00:07 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c: drop Win2K support.
-
-Sun May 1 20:39:47 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * cont.c, hash.c, random.c, win32/win32.c: cleanup some Win9x/ME/NT4
- support leftovers.
- [fix GH-1328] patched by @cremno
-
-Sun May 1 07:30:44 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (search_nonascii): use nlz on big endian environments.
-
- * internal.h (nlz_intptr): defined.
-
-Sun May 1 00:03:30 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in (__builtin_ctz): check.
-
- * configure.in (__builtin_ctzll): check.
-
- * internal.h (rb_popcount32): defined for ntz_int32.
- it can use __builtin_popcount but this function is not used on
- GCC environment because it uses __builtin_ctz.
- When another function uses this, using __builtin_popcount
- should be re-considered.
-
- * internal.h (rb_popcount64): ditto.
-
- * internal.h (ntz_int32): defined for ntz_intptr.
-
- * internal.h (ntz_int64): defined for ntz_intptr.
-
- * internal.h (ntz_intptr): defined as ntz for uintptr_t.
-
- * string.c (search_nonascii): unroll and use ntz.
-
-Sat Apr 30 21:54:13 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (Init_Numeric): Gather Fixnum method definitions.
-
-Sat Apr 30 21:28:14 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_int_div): Define Integer#/.
-
- * bignum.c (rb_big_div): Don't define Bignum#/.
-
- * lib/mathn.rb (Integer#/): Replace Integer#/ instead of Bignum#/.
-
-Sat Apr 30 21:11:08 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_int_plus): Define Integer#+.
-
- * bignum.c (rb_big_plus): Don't define Bignum#+.
-
-Sat Apr 30 21:01:20 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_int_minus): Define Integer#-.
-
- * bignum.c (rb_big_minus): Don't define Bignum#-.
-
-Sat Apr 30 20:53:33 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_int_mul): Define Integer#*.
-
- * bignum.c (rb_big_mul): Don't define Bignum#*.
-
-Sat Apr 30 20:30:44 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_int_modulo): Define Integer#%.
-
- * bignum.c (rb_big_modulo): Don't define Bignum#%.
-
-Sat Apr 30 20:17:08 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_equal): Define Integer#==.
-
- * bignum.c (rb_big_eq): Don't define Bignum#==.
-
-Sat Apr 30 19:41:15 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_gt): Define Integer#>.
-
- * bignum.c (rb_big_gt): Don't define Bignum#>.
- Renamed from big_gt.
-
- * internal.h (rb_big_gt): Declared.
-
-Sat Apr 30 19:24:40 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_ge): Define Integer#>=.
-
- * bignum.c (rb_big_ge): Don't define Bignum#>=.
- Renamed from big_ge.
-
- * internal.h (rb_big_ge): Declared.
-
-Sat Apr 30 19:20:40 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * doc/standard_library.rdoc: Remove obsoleted classes and modules.
-
-Sat Apr 30 19:09:23 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_lt): Define Integer#<.
-
- * bignum.c (rb_big_lt): Don't define Bignum#<.
- Renamed from big_lt.
-
- * internal.h (rb_big_lt): Declared.
-
-Sat Apr 30 18:44:05 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_le): Define Integer#<=.
-
- * bignum.c (rb_big_le): Don't define Bignum#<=.
- Renamed from big_le.
-
- * internal.h (rb_big_le): Declared.
-
-Sat Apr 30 18:11:44 2016 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (Init_Bignum): Define Integer::GMP_VERSION.
-
-Sat Apr 30 16:58:18 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_remainder): Define Integer#remainder.
-
- * bignum.c (rb_big_remainder): Don't define Bignum#remainder.
-
- * internal.h (rb_big_remainder): Declared.
-
-Sat Apr 30 15:29:24 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_int_uminus): {Fixnum,Bignum}#-@ is unified into
- Integer.
-
- * bignum.c (rb_big_uminus): Don't define Bignum#-@.
-
-Sat Apr 30 14:42:20 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_int_idiv): {Fixnum,Bignum}#div is unified into
- Integer.
-
- * bignum.c (rb_big_idiv): Don't define Bignum#div.
-
-Sat Apr 30 14:25:55 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_int_modulo): {Fixnum,Bignum}#modulo is unified into
- Integer.
-
- * bignum.c (rb_big_modulo): Don't define Bignum#modulo.
-
-Sat Apr 30 14:04:30 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_divmod): {Fixnum,Bignum}#divmod is unified into
- Integer.
-
- * bignum.c (rb_big_divmod): Don't define Bignum#divmod.
-
-Sat Apr 30 13:20:00 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_fdiv): {Fixnum,Bignum}#fdiv is unified into
- Integer.
-
- * bignum.c (rb_big_fdiv): Don't define Bignum#fdiv.
-
-Sat Apr 30 12:25:43 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_int_pow): {Fixnum,Bignum}#** is unified into
- Integer.
-
- * bignum.c (rb_big_pow): Don't define Bignum#**.
-
-Sat Apr 30 12:28:59 2016 Tanaka Akira <akr@fsij.org>
-
- * bignum.c (rb_big_comp): Renamed from rb_big_neg.
-
- * numeric.c (fix_comp): Renamed from fix_rev.
-
-Sat Apr 30 12:25:43 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_comp): {Fixnum,Bignum}#~ is unified into
- Integer.
-
- * bignum.c (rb_big_neg): Don't define Bignum#~.
-
- * internal.h (rb_big_neg): Declared.
-
-Sat Apr 30 12:07:42 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_and): {Fixnum,Bignum}#& is unified into
- Integer.
-
- * bignum.c (rb_big_and): Don't define Bignum#&.
-
-Sat Apr 30 11:56:15 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/thread: removed dummy extension library. thread_sync.c
- provides "thread.rb" already.
-
-Sat Apr 30 11:53:48 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_or): {Fixnum,Bignum}#| is unified into
- Integer.
-
- * bignum.c (rb_big_or): Don't define Bignum#|.
-
-Sat Apr 30 11:18:47 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * vm_trace.c: Fix typos. [ci skip]
-
-Sat Apr 30 10:09:04 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/pty/pty.c (establishShell): honor USER environment variable
- and login name over uid, one uid can be shared by some login
- names.
-
-Fri Apr 29 22:40:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * doc/maintainers.rdoc (ext/io/nonblock): still maintained, as
- well as ext/io/wait, which is the origin.
-
-Fri Apr 29 21:18:12 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * doc/maintainers.rdoc (ext/win32): of course, it's still maintained.
-
-Fri Apr 29 21:03:10 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * gems/bundled_gems: Update latest gems, test-unit-3.1.8 and rake-11.1.2.
-
-Fri Apr 29 20:43:02 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * doc/maintainers.rdoc: Update latest maintainers list on Ruby 2.4
-
-Fri Apr 29 19:52:45 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * doc/maintainers.rdoc: Removed deprecated entries. These are already deleted.
-
-Fri Apr 29 19:48:45 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * doc/maintainers.rdoc: Removed Ruby 1.8 entries. It's not necessary to
- Ruby 2.4 or later.
-
-Thu Apr 28 17:03:17 2016 Nicholas Maccharoli <nmaccharoli@gmail.com>
-
- * hash.c (rb_hash_update_{block,func}_callback): dry up hash
- update callback code. [Fix GH-1338]
-
-Thu Apr 28 16:52:05 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * re.c (rb_reg_prepare_enc): use rb_enc_asciicompat(enc) instead of
- rb_enc_str_asciicompat_p(str) to avoid useless rb_enc_get(str) call.
-
-Thu Apr 28 16:33:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/optparse.rb: [DOC] fix example code. base on the code by
- Semyon Gaivoronskiy in [ruby-core:75224]. [Bug #12323]
-
-Thu Apr 28 09:33:03 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems-2.6.4.
- Please see entries of 2.6.4 on
- https://github.com/rubygems/rubygems/blob/master/History.txt
-
-Thu Apr 28 04:49:07 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * configure.in (rb_cv_lgamma_r_pm0): check if lgamma_r(+0.0)
- returns positive infinity, in addition to lgamma_r(-0.0).
- AIX returns an incorrect result of negative infinity.
-
- * math.c (ruby_lgamma_r): handle +0.0, in addition to -0.0.
-
-Thu Apr 28 01:11:14 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * time.c: define _DEFAULT_SOURCE because glibc 2.20 deprecates
- _BSD_SOURCE.
- https://sourceware.org/glibc/wiki/Release/2.20
-
-Thu Apr 28 00:27:55 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_xor): {Fixnum,Bignum}#^ is unified into
- Integer.
-
- * bignum.c (rb_big_xor): Don't define Bignum#^.
-
-Wed Apr 27 20:53:59 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_aref): {Fixnum,Bignum}#[] is unified into
- Integer.
-
- * bignum.c (rb_big_aref): Don't define Bignum#<<.
-
- * internal.h (rb_big_aref): Declared.
-
-Wed Apr 27 16:10:35 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/instruction.rb: fix to follow current implementation.
-
-Wed Apr 27 15:47:54 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/stringio/stringio.c (strio_s_new): warn if a block is given,
- as well as IO.new.
-
-Wed Apr 27 14:29:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (ruby_only_for_internal_use): raise fatal error when
- deprecated function only for internal use is called, not just a
- warning.
-
-Tue Apr 26 23:42:30 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * tool/redmine-backporter.rb (rel): should not raise exceptions even if
- the user input is wrong. only reports the error and continue process.
-
-Tue Apr 26 23:35:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (process_options): convert -e script to the encoding
- given by a command line option on Windows. assume it is the
- expected encoding. [ruby-dev:49461] [Bug #11900]
-
-Tue Apr 26 21:11:02 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_int_lshift): {Fixnum,Bignum}#<< is unified into
- Integer.
-
- * bignum.c (rb_big_lshift): Don't define Bignum#<<.
-
-Tue Apr 26 20:59:40 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_int_rshift): {Fixnum,Bignum}#>> is unified into
- Integer.
-
- * bignum.c (rb_big_rshift): Don't define Bignum#>>.
-
-Tue Apr 26 20:46:16 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_size): {Fixnum,Bignum}#size is unified into Integer.
-
- * bignum.c (rb_big_size_m): Don't define Bignum#size.
-
- * internal.h (rb_big_size_m): Declared.
-
-Tue Apr 26 20:09:08 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (rb_int_bit_length): {Fixnum,Bignum}#bit_length is
- unified into Integer.
-
- * bignum.c (rb_big_bit_length): Don't define Bignum#bit_length.
-
- * internal.h (rb_big_bit_length): Declared.
-
-Tue Apr 26 19:56:16 2016 Tanaka Akira <akr@fsij.org>
-
- * numeric.c (int_abs): Integer#{abs,magnitude} moved from
- Fixnum and Bignum.
-
- * bignum.c (rb_big_abs): Don't define Bignum#{abs,magnitude}.
-
- * internal.h (rb_big_abs): Declared.
-
-Mon Apr 25 14:39:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/rbconfig/sizeof/extconf.rb: just check the existence of each
- types, to reduce configuration time, especially cross-compiling.
-
- * template/sizes.c.tmpl: calculate sizes of checked types at
- compilation time.
-
-Mon Apr 25 11:27:27 2016 Marcus Stollsteimer <sto.mar@web.de>
-
- * doc/extension.rdoc: Improvements to english grammars.
- [Bug #12246][ruby-core:74792][ci skip]
-
-Mon Apr 25 11:17:50 2016 Marcus Stollsteimer <sto.mar@web.de>
-
- * encoding.c: Fix return value of `Encoding::ISO8859_1.name`
- [Bug #12313][ruby-core:75147][ci skip]
- * ext/bigdecimal/bigdecimal.c: Fix code sample of `BigDecimal.new`
-
-Sun Apr 24 23:29:16 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * configure.in: add missing -lm for AIX.
-
-Sun Apr 24 18:33:58 2016 Kazuki Tsujimoto <kazuki@callcc.net>
-
- * vm_insnhelper.c (INLINE): disable r54738 if __NO_INLINE__ is defined.
- It caused "undefined reference to `vm_getivar'".
-
-Sun Apr 24 09:32:12 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * test/ruby/test_array.rb: Add test cases for Array#sum with
- non-numeric objects.
-
-Sun Apr 24 04:21:27 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_insnhelper.c (INLINE): define as `inline` when it is optimized.
- define as `static inline` when it is not optimized to keep
- the symbol generated.
-
- * vm_insnhelper.c (vm_getivar): use `INLINE` to force inline
- so that a compiler inlines it into vm_getinstancevariable
- and optimizes out is_attr and related branches.
-
- * vm_insnhelper.c (vm_getivar): use `inline` to recommend inline.
- Without this vm1_ivar_set is degraded.
-
- benchmark results:
- minimum results in each 5 measurements.
- Execution time (sec)
- name ruby 2.4.0dev (2016-04-23 trunk 54727) [x86_64-linux] ruby 2.4.0dev (2016-04-23 trunk 54733) [x86_64-linux] built-ruby
- loop_whileloop 0.641 0.642 0.646
- vm1_ivar* 1.002 0.999 0.831
- vm1_ivar_set* 0.369 1.106 0.362
-
- Speedup ratio: compare with the result of `ruby 2.4.0dev (2016-04-23
- trunk 54727) [x86_64-linux]' (greater is better)
- name ruby 2.4.0dev (2016-04-23 trunk 54733) [x86_64-linux]
- built-ruby
- loop_whileloop
- 0.998 0.991
- vm1_ivar*
- 1.003 1.205
- vm1_ivar_set*
- 0.334 1.018
-
-Sat Apr 23 18:01:21 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * vm_insnhelper.c (vm_getivar): specify inline instead of static inline.
- vm_getivar is called by vm_call_ivar and vm_getinstancevariable.
- At least with GCC 4.8 and 5.3 on Linux, they are inlining it into
- vm_call_ivar but not vm_getinstancevariable.
- By `inline`, they correctly inline it and gains performance.
-
- Speedup ratio: compare with the result of `ruby 2.4.0dev (2016-04-23
- trunk 54727) [x86_64-linux]' (greater is better)
- name built-ruby
- loop_whileloop 1.001
- vm1_ivar* 1.189
- vm1_ivar_set* 1.024
-
- Note the `inline`'s meaning is different between old GCC
- and C99. Old GCC's inline means C99's extern inline.
- https://gcc.gnu.org/onlinedocs/gcc/Inline.html
- Since Ruby specify -std=iso9899:1999, it works like C99.
-
-Sat Apr 23 16:11:39 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_mul_size_overflow): use UNLIKELY
- by user side to improve generality.
-
-Sat Apr 23 16:10:02 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * include/ruby/ruby.h (RB_LIKELY): use prefix in ruby.h.
-
- * intern.h (LIKELY): define with RB_LIKELY.
-
-Sat Apr 23 13:27:25 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * NEWS: Add descriptions for Time#to_time updates.
- [Bug #12271]
-
-Sat Apr 23 13:21:24 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * NEWS: Add descriptions for DateTime#to_time updates.
- [Bug #12189]
-
-Sat Apr 23 11:21:27 2016 Marcus Stollsteimer <sto.mar@web.de>
-
- * ext/date/date_core.c (Init_date_core): [DOC] Convert DateTime
- documentation to RDoc from Markdown.
- [ruby-core:75136] [Bug #12311]
-
-Sat Apr 23 09:03:35 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c: cygwin does not use w32_cmdvector, command line can be
- other than UTF-8. [ruby-dev:49519] [Bug #12184]
-
-Sat Apr 23 01:00:03 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * configure.in: don't use the system-provided round(3) on AIX.
- In AIX, round(0.49999999999999994) returns 1.0.
- Use round() in numeric.c instead.
-
-Fri Apr 22 21:00:44 2016 Tanaka Akira <akr@fsij.org>
-
- * test/ruby/test_time_tz.rb: Tests depends on Europe/Moscow removed
- to avoid test failures due to the tzdata change.
- https://github.com/eggert/tz/commit/8ee11a301cf173afb0c76e0315b9f9ec8ebb9d95
- Found by naruse.
-
-Fri Apr 22 20:18:40 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_mul_size_overflow): added to handle
- mul overflow efficiently.
-
- * include/ruby/ruby.h (rb_alloc_tmp_buffer2): use rb_mul_size_overflow
- and avoid division where it can define DSIZE_T.
-
- * gc.c (xmalloc2_size): moved from ruby.h and use rb_mul_size_overflow.
-
-Fri Apr 22 20:34:04 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * time.c (time_asctime): [DOC] add ctime example, not only
- asctime. [ruby-core:75126] [Bug #12310]
-
-Fri Apr 22 18:44:32 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * variable.c: use uint32_t instead of long to avoid confusion about
- the type of ivtbl->numiv.
-
-Fri Apr 22 15:09:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval_jump.c (exec_end_procs_chain): restore previous error info
- for each end procs. [ruby-core:75038] [Bug #12302]
-
-Fri Apr 22 15:04:56 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * tool/redmine-backporter.rb: the fullpath of merger.rb is too long to
- copy&paste on Windows. show shorter name instead on the platform.
- I'm sure that the user of this command on Windows is only me.
-
-Fri Apr 22 14:52:04 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * tool/merger.rb: remove temporary file.
-
-Fri Apr 22 11:27:03 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/net/http.rb: Improve documentation for SSL requests via GET method.
- [fix GH-1325][ci skip] Patch by @jsyeo
-
-Fri Apr 22 10:51:13 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/webrick/ssl.rb: Support to add SSLCiphers option.
- [fix GH-1321] Patch by @rhadoo
-
-Fri Apr 22 10:43:19 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * file.c, win32/file.c: Removed obsoleted safe level checks.
- [fix GH-1327] Patch by @cremno
-
-Fri Apr 22 10:01:48 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * benchmark/bm_so_meteor_contest.rb: fix a typo.
- [fix GH-1330][ci skip] Patch by @sachin21
-
-Fri Apr 22 04:57:01 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * gc.c (rb_alloc_tmp_buffer_with_count): added like xmalloc2 to
- avoid duplicated check of size.
-
- * gc.c (ruby_xmalloc2): added to keep separate layers.
-
- * include/ruby/ruby.h (rb_alloc_tmp_buffer2): added to check
- the size more statically.
-
-Fri Apr 22 04:54:40 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * include/ruby/ruby.h (LIKELY): moved from internal.h.
-
- * include/ruby/ruby.h (UNLIKELY): ditto.
-
-Thu Apr 21 01:44:19 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * gc.c (objspace_malloc_prepare): remove size check because it is
- used by objspace_xmalloc and objspace_xcalloc.
- objspace_xmalloc introduces its own check in this commit.
- objspace_xcalloc checks with xmalloc2_size (ruby_xmalloc2_size).
-
- * gc.c (objspace_xmalloc0): common xmalloc function.
-
- * gc.c (objspace_xmalloc): introduce its own size check.
-
- * gc.c (objspace_xmalloc2): separated from ruby_xmalloc2 to clarify
- the layer who has the responsibility to check the size.
-
- * gc.c (objspace_xrealloc): remove duplicated size check.
-
- * gc.c (ruby_xmalloc2): use objspace_xmalloc2.
-
- * include/ruby/ruby.h (ruby_xmalloc2_size): follow the size limit
- as SSIZE_MAX. Note that ISO C says size_t is unsigned integer.
-
-Thu Apr 21 12:14:04 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: check if succeeded in creating config.h.
-
- * tool/ifchange: ignore failures when TEST_COLORS unmatched. just
- use the default value if expected name is not contained in it.
- [ruby-core:75046] [Bug #12303]
-
-Wed Apr 20 17:33:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/cgi/escape/escape.c (cgiesc_unescape): define unescape
- method instead of _unescape, and should pass the optional
- argument to the super method.
-
- * lib/cgi/util.rb (CGI::Util#_unescape): remove intermediate
- method.
-
-Wed Apr 20 15:52:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (syntax_error_initialize): move the default message,
- "compile error", from parse.y. the default parameter should
- belong to the class definition.
-
- * parse.y (yycompile0): use the default parameter.
-
-Wed Apr 20 10:25:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (append_compile_error): use rb_syntax_error_append.
-
- * error.c (rb_syntax_error_append): append messages into a
- SyntaxError exception instance.
-
- * parse.y (yycompile0): make new SyntaxError instance in main
- mode, otherwise error_buffer should be a SyntaxError if error
- has occurred.
-
-Tue Apr 19 17:42:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (err_vcatf): rename, and separate appending message from
- creating a string buffer.
-
- * error.c (rb_syntax_error_append): merge rb_error_vsprintf and
- rb_compile_err_append.
-
- * parse.y (parser_compile_error): use rb_syntax_error_append.
-
-Tue Apr 19 13:46:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (append_compile_error, compile_bug): pass iseq and get
- error info and file from it, not by the thread error info.
-
- * error.c (rb_report_bug_valist): take va_list instead of variadic
- arguments, and just report the bug but not abort.
-
-Tue Apr 19 13:18:12 2016 Naotoshi Seo <sonots@gmail.com>
-
- * lib/time.rb: revert r54167 because it would break
- backward compatibilities, and it is documented that
- Time.parse does not take into account time zone
- abbreations other than ones described in RFC 822
-
-Tue Apr 19 13:12:03 2016 Naotoshi Seo <sonots@gmail.com>
-
- * ChangeLog: Fix dates of previous commits
-
-Tue Apr 19 12:45:03 2016 Naotoshi Seo <sonots@gmail.com>
-
- * ChangeLog: Add descriptions for logger updates
- * NEWS: Add descriptions for logger updates
-
-Tue Apr 19 12:45:02 2016 Naotoshi Seo <sonots@gmail.com>
-
- * lib/logger.rb: Add shift_period_suffix option
-
-Tue Apr 19 12:45:01 2016 Naotoshi Seo <sonots@gmail.com>
-
- * lib/logger.rb: Allow specifying logger parameters in constructor
- such as level, progname, datetime_format, formatter.
-
-Mon Apr 18 16:07:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_peephole_optimize): should not replace the
- current target INSN, not to follow the replaced dangling link in
- the caller. [ruby-core:74993] [Bug #11816]
-
-Mon Apr 18 12:56:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (flo_truncate): add an optional parameter, digits, as
- well as Float#round. [Feature #12245]
-
- * numeric.c (int_truncate): add an optional parameter, digits, as
- well as Integer#round. [Feature #12245]
-
-Sun Apr 17 04:18:56 2016 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * tool/redmine-backporter.rb: revisions are strings.
-
-Sat Apr 16 14:26:49 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * ext/date/date_core.c : remove not used f_getlocal macro.
- After r54553 f_getlocal macro is not used.
-
-Sat Apr 16 14:15:24 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * ext/date/date_core.c : remove not used f_utc6 macro.
- After r54169 f_utc6 macro is not used.
-
-Sat Apr 16 10:00:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * struct.c (struct_make_members_list, rb_struct_s_def): member
- names should be unique. [ruby-core:74971] [Bug #12291]
-
- * struct.c (struct_make_members_list): extract making member name
- list from char* va_list, with creating symbols without
- intermediate IDs.
-
-Sat Apr 16 01:33:27 2016 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * tool/redmine-backporter.rb: sort revisions.
-
-Sat Apr 16 01:16:02 2016 Tanaka Akira <akr@fsij.org>
-
- * array.c (rb_ary_sum): Don't yield same element twice.
- Found by nagachika.
-
-Sat Apr 16 01:03:32 2016 Tanaka Akira <akr@fsij.org>
-
- * array.c (rb_ary_sum): Fix SEGV by [1/2r, 1].sum.
-
-Fri Apr 15 23:52:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * rational.c (rb_rational_plus): rename from rb_rational_add
- to be aligned with rb_fix_plus.
-
- * array.c (rb_ary_sum): ditto.
-
- * internal.h: ditto.
-
-Fri Apr 15 23:42:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * rational.c (rb_rational_add): rename from nurat_add.
-
- * array.c (rb_ary_sum): use rb_rational_add directly.
-
- * test/ruby/test_array.rb (test_sum): add assertions for an array of
- Rational values.
-
-Fri Apr 15 22:31:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * array.c (rb_ary_sum): apply the precision compensated algorithm
- for an array in which Rational and Float values are mixed.
-
- * test/ruby/test_array.rb (test_sum): add assertions for the above
- change.
-
-Fri Apr 15 22:30:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (rb_thread_setname): defer setting native thread name
- set in initialize until the native thread is created.
- [ruby-core:74963] [Bug #12290]
-
-Fri Apr 15 20:27:16 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/irb/ext/save-history.rb: Fix NoMethodError when method is not defined.
-
-Fri Apr 15 15:38:58 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * common.mk (benchmark): order options for built-ruby and compare-ruby.
-
-Fri Apr 15 14:14:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * test/ruby/test_array.rb (test_sum): add assertions for Rational and
- Complex numbers.
-
-Fri Apr 15 10:07:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/io/console/console.c (console_key_pressed_p): raise the same
- exception, "unknown virtual key code", for names with nul chars.
- though console_win32_vk() considers the length and can deal with
- nul chars, rb_sprintf() raised at PRIsVALUE previously, so quote
- it if it is unprintable.
-
-Fri Apr 15 09:02:58 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/io/console/console.c (rb_sym2str): fallback definition for
- older ruby. [ruby-core:74953] [Bug #12284]
-
-Thu Apr 14 21:46:36 2016 Tanaka Akira <akr@fsij.org>
-
- * array.c (rb_ary_sum): Support the optional argument, init, and
- block.
-
-Thu Apr 14 19:02:41 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/irb/ext/save-history.rb: suppress warning: method redefined;
- discarding old save_history=.
-
-Thu Apr 14 14:58:14 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/tk/tkutil/tkutil.c (tk_hash_kv): the third argument can be
- nil not only an Array. reported by @windwiny at
- https://github.com/ruby/ruby/commit/cdaa94e#commitcomment-17096618
-
-Thu Apr 14 14:28:55 2016 cremno phobia <cremno@mail.ru>
-
- * cont.c (fiber_initialize_machine_stack_context): fix wrong
- _MSC_VER check, should be decimal but not hexadecimal.
- [ruby-core:74936] [Bug #12279]
-
-Wed Apr 13 22:51:38 2016 Tanaka Akira <akr@fsij.org>
-
- * array.c (rb_ary_sum): Array#sum is implemented.
- Kahan's compensated summation algorithm for precise sum of float
- numbers is moved from ary_inject_op in enum.c.
-
- * enum.c (ary_inject_op): Don't specialize for float numbers.
-
- [ruby-core:74569] [Feature #12217] proposed by mrkn.
-
-Wed Apr 13 15:56:35 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (flo_ceil): add an optional parameter, digits, as
- well as Float#round. [Feature #12245]
-
- * numeric.c (flo_floor): add an optional parameter, digits, as
- well as Float#round. [Feature #12245]
-
- * numeric.c (int_ceil): add an optional parameter, digits, as
- well as Integer#round. [Feature #12245]
-
- * numeric.c (int_floor): add an optional parameter, digits, as
- well as Integer#round. [Feature #12245]
-
-Wed Apr 13 14:47:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (Init_File): add alias File.empty? to File.zero?.
- [Feature #9969]
-
-Wed Apr 13 14:36:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (assign_in_cond): allow multiple assignment in
- conditional expression. [Feature #10617]
-
-Wed Apr 13 14:11:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * bignum.c (rb_big_size): add wrapper function of BIGSIZE and
- rename the method function with _m suffix.
-
- * numeric.c (int_round_zero_p): extracted from rb_int_round.
- optimize for Bignum, and convert VALUE returned by Numeric#size
- to long.
-
-Wed Apr 13 12:00:08 2016 Koichi Sasada <ko1@atdot.net>
-
- * test/ruby/test_basicinstructions.rb: add a test to check access
- instance variables on special const objects.
-
- All of such objects are frozen, so that we can not set instance
- variables for them. But we can read instance variables and return
- default value (nil).
-
-Tue Apr 12 20:40:35 2016 Kaneko Yuichiro <spiketeika@gmail.com>
-
- * ext/date/date_core.c (time_to_time): should preserve timezone
- info. [ruby-core:74889] [Bug #12271]
-
-Tue Apr 12 11:51:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (new_label_body): initialize bit fields, since
- compile_data_alloc does not clear the memory. [Bug #12082]
-
-Mon Apr 11 20:18:43 2016 Koichi Sasada <ko1@atdot.net>
-
- * vm_backtrace.c (frame2klass): filter only for imemo_ment.
- T_IMEMO/imemo_iseq can be passed here.
-
-Mon Apr 11 17:43:04 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_optimize): disable tail call optimization in
- rescued, rescue, and ensure blocks.
- [ruby-core:73871] [Bug #12082]
-
-Mon Apr 11 06:54:39 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (apply2files): apply to a VALUE vector instead of a
- temporary array.
-
-Sun Apr 10 20:54:16 2016 Joe Swatosh <joe.swatosh@gmail.com>
-
- * ext/win32/lib/win32/registry.rb (DeleteValue, DeleteKey): fix
- API names. [ruby-core:74863] [Bug #12264]
-
-Sun Apr 10 17:47:42 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (rb_realpath_internal): no argument conversions since
- this internal function does not need to_path and encoding
- conversions, not to be affected by the default internal
- encoding.
-
-Sat Apr 9 10:03:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * load.c (rb_f_load): raise with the original path name before
- encoding conversion.
-
-Sat Apr 9 02:05:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * bignum.c (rb_cstr_parse_inum): [EXPERIMENTAL] new function to
- parse integer in C-string with length. the name and the
- arguments may be changed in the future.
-
- * bignum.c (rb_str_to_inum): preserve encoding of the argument in
- error messages, and no longer needs to copy non-terminated
- strings.
-
- * bignum.c (rb_str2big_{poweroftwo,normal,karatsuba,gmp}): ditto.
-
-Thu Apr 7 19:04:03 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * doc/regexp.rdoc (comments): [DOC] terminators cannot appear in
- comments. [ruby-core:74838] [Bug #12256]
-
-Thu Apr 7 11:24:14 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/tk/tkutil/tkutil.c (cbsubst_initialize): fix out-of-bound
- access when no arguments given. `p Tk::Event.new` crashed.
-
-Fri Apr 1 01:26:00 2016 Benoit Daloze <eregontp@gmail.com>
-
- * ext/coverage/coverage.c: Fully reset coverage to not persist global state.
- It was returning old file coverages as empty arrays to the user.
- [ruby-core:74596] [Bug #12220]
-
- * ext/coverage/coverage.c (rb_coverages): remove unused static state.
-
- * thread.c: Moved and renamed coverage_clear_result_i to reset_coverage_i.
-
- * test/coverage/test_coverage.rb: improve precision of tests.
-
-Wed Apr 6 22:41:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (rb_cv_lgamma_r_m0): fix the condition for
- lgamma_r(-0.0). [Bug #12249]
-
-Wed Apr 6 17:38:42 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * tool/downloader.rb (RubyGems.download): follow the change of the
- rubygems ssl_certs directory tree introduced by previous commit.
-
-Wed Apr 6 15:00:27 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems-2.6.3.
- Please see entries of 2.6.3 on
- https://github.com/rubygems/rubygems/blob/master/History.txt
-
-Wed Apr 6 14:13:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (rb_cv_lgamma_r_m0): check if lgamma_r(-0.0)
- returns negative infinity. [Bug #12249]
-
- * math.c (ruby_lgamma_r): define by the configured result.
-
-Wed Apr 6 10:56:15 2016 Anton Davydov <antondavydov.o@gmail.com>
-
- * lib/logger.rb (Logger#level=): remove unnecessary local
- variable.
-
- * lib/logger.rb (Logger#initialize, Logger#reopen): [DOC] mention
- the default values. cherrypicked from [GH-1319].
-
-Wed Apr 6 10:17:53 2016 cremno phobia <cremno@mail.ru>
-
- * math.c (ruby_lgamma_r): missing/lgamma_r.c is used on Windows,
- since msvcrt does not provide it.
-
- * missing/lgamma_r.c (lgamma_r): fix lgamma(-0.0).
- [ruby-core:74823] [Bug #12249]
-
-Wed Apr 6 01:22:55 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * math.c (ruby_lgamma_r): mswin's lgamma_r also seems to be wrong.
- cf. [Bug #12249]
-
-Wed Apr 6 00:53:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * math.c (ruby_lgamma_r): fix lgamma(-0.0) on mingw and OSX.
-
- * math.c (ruby_tgamma): fix tgamma(-0.0) on mingw.
- [ruby-core:74817] [Bug #12249]
-
-Tue Apr 5 14:50:28 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/nkf/nkf-utf8/nkf.c (mime_putc): fix typo.
- [Bug #12202] [ruby-core:74802]
-
-Tue Apr 5 00:06:44 2016 Aeris <aeris@imirhil.fr>
-
- * ext/openssl/ossl_ssl.c (ossl_ssl_tmp_key): Access to ephemeral
- TLS session key in case of forward secrecy cipher. Only
- available since OpenSSL 1.0.2. [Fix GH-1318]
-
- * ext/openssl/extconf.rb: Check for SSL_get_server_tmp_key.
-
-Mon Apr 4 23:37:05 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_core.h (rb_vm_struct): make at_exit a single linked list but
- not RArray, not to mark the registered functions by the write
- barrier. based on the patches by Evan Phoenix.
- [ruby-core:73908] [Bug #12095]
-
-Mon Apr 4 17:43:45 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: change default value of
- RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO 0.3 -> 0.2
- RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO 0.8 -> 0.65
-
- These values are same as Ruby 2.0.0.
-
- This change cause GC counts.
- However, generational GC reduced each (minor) GC time and
- increase memory locality. So that not so big impact on my
- benchmarking results.
- (surprisingly, this fix speed up programs on some cases)
-
- You can change these values by environment variables
- if you feel wrong.
-
-Mon Apr 4 17:36:52 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (get_envparam_double): take an upper_bound.
-
- And also take an accept_zero flag which allow to accept zero
- even if lower_bound is set.
-
- * gc.c (ruby_gc_set_params): fix parameters.
-
- RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO set 0.9 as *lower_bound*, so that
- it should be upper_bound.
- Set RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO as lower bound.
-
- Also set lower/upper bound of RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO to
- RUBY_GC_HEAP_FREE_SLOTS_MIN/MAX_RATIO.
-
-Mon Apr 4 16:41:32 2016 Koichi Sasada <ko1@atdot.net>
-
- * vm.c (Init_VM): should pass tokens.
-
-Sun Apr 3 09:34:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (flodivmod): round division if it is a finite number
- and module is required.
-
- * numeric.c (dbl2ival): do not round here.
-
- * numeric.c (flo_ceil): use dbl2ival.
-
- * numeric.c (flo_round): round explicitly.
-
-Sat Apr 2 15:24:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/intern.h (rb_check_arity): returns argc.
-
-Fri Apr 1 20:58:33 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb, casefold.h: Data generation to implement
- swapcase functionality for titlecase characters. Swapcase isn't defined
- by Unicode, because the purpose/usage of swapcase is unclear anyway.
- The implementation follows a proposal from Nobu, swapping the case of
- each component of a titlecase character individually.
- This means that the titlecase characters have to be decomposed.
-
- * enc/unicode.c: Code using the above data.
-
- * test/ruby/enc/test_case_mapping.rb: Tests for the above.
-
-Fri Apr 1 14:55:28 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * configure.in (AC_CONFIG_FILES): $srcdir/.git can be a file pointing
- the real git_dir, such as when the git working tree is a "linked
- working tree" (a working tree created by git-worktree). So use
- git-rev-parse --git-dir to check if $srcdir is the top-level of a git
- repository, not just checking if the $srcdir/.git directory does exist
- or not. [ruby-core:74759] [Bug #12239]
-
- * tool/change_maker.rb: use tool/vcs.rb to detect VCS. This used to have
- its own VCS detection code, while we have tool/vcs.rb.
-
- * tool/vcs.rb (detect): remove code duplication
-
-Fri Apr 1 04:50:44 2016 Eric Wong <e@80x24.org>
-
- * ext/openssl/ossl_ssl.c (ossl_sslctx_s_alloc):
- enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER by default
- [Bug #12126]
-
-Fri Apr 1 01:13:55 2016 Benoit Daloze <eregontp@gmail.com>
-
- * thread.c (update_coverage): Do not track coverage in loaded files
- after Coverage.result. Avoids out-of-bounds access. [Bug #12237]
-
- * ext/coverage/coverage.c (coverage_clear_result_i): document.
-
-Thu Mar 31 19:16:16 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: need to set initial value of GC_HEAP_FREE_SLOTS_GOAL_RATIO.
-
-Thu Mar 31 17:50:27 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: change additional allocation policy.
-
- Introduce new environment variable
- RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO (goal_ratio) to calculate the
- ratio of additional memory.
-
- Before this change, we add pages with the following formula
- (when free_slots < total_pages * RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO):
- next_pages = total_pages * RUBY_GC_HEAP_GROWTH_FACTOR
-
- This addition can allocate too much.
-
- With this change, we increase pages to satisfy the following formula:
- next_free_slots = next_total_slots * goal_ratio
- where
- next_free_slots = free_slots + adding_slots
- next_total_slots = total_slots + adding_slots.
-
- If you want to prepare many free slots, increase this ratio.
-
- If this variable is 0, then simply multiply
- RUBY_GC_HEAP_GROWTH_FACTOR.
-
- * gc.c (get_envparam_double): enable to accept 0.
-
-Thu Mar 31 17:48:25 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_marks_finish): fix syntax error.
-
-Thu Mar 31 16:49:36 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: simplify allocate/free detecting logic at the end of marking.
-
- Before this change, heap_pages_min_slots are calculated at the
- beginning sweeping phase. And this value is used at the end of
- *next* marking phase.
-
- To simplify it, we use this value at the end of this marking phase.
- It means that we don't need to store this value as global state.
-
- Also heap_pages_max_slots is calculated at the begging of sweeping
- phase and used at the end of sweeping phase.
- To simplify this logic, we introduced new global value
- heap_pages_freeable_pages it means extra pages count we can free.
- gc_sweep_step() checks this value and moves empty pages to tomb_heap
- not more than this value.
-
- Because of this fix, heap_pages_swept_slots is no longer needed.
-
- * gc.c (rb_objspace_t::heap_pages): restruct the objspace global
- status.
-
- remove the following fields
- * swept_slots (and heap_pages_swept_slots)
- * min_free_slots (and heap_pages_min_free_slots)
- * max_free_slots (and heap_pages_max_free_slots)
- And add the following filed.
- * freeable_pages (and heap_pages_freeable_pages)
-
- * gc.c (heap_pages_free_unused_pages): unlink tomb heap pages
- because tomb heap should have only freeable pages.
-
- * gc.c (heap_extend_pages): add parameters for future extension.
-
-Thu Mar 31 16:43:02 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: add GC parameters to configure the following values:
- * RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO:
- allocate additional pages when free slots is lower than
- the value (total_slots * (this ratio)).
- * RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO:
- allow to free pages when free slots is greater than
- the value (total_slots * (this ratio)).
-
- Before this change, these values are hard coded.
-
- * gc.c (ruby_gc_params_t): ditto.
-
- * gc.c (ruby_gc_set_params): ditto.
-
-Thu Mar 31 15:59:17 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_verify_heap_page): check the number of zombies.
-
- * gc.c (gc_verify_heap_pages): check also tomb heap.
-
-Thu Mar 31 15:48:18 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c (gc_page_sweep): return free slots count.
-
- * gc.c (gc_sweep_step): use returned free slots count.
-
- * gc.c (gc_sweep_step): change variable name `next'
- to `next_sweep_page'.
-
-Thu Mar 31 11:33:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/date/date_core.c (d_lite_strftime, dt_lite_strftime): [DOC]
- fix indent not to be a big sole verbatim.
-
-Thu Mar 31 11:18:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/date/date_core.c (Init_date_core): [DOC] fix misplaced doc
- of DateTime. [ruby-core:74729] [Bug #12233]
-
-Thu Mar 31 03:41:02 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/nkf/nkf-utf8/nkf.c: Merge upstream 69f7e74dde.
- fix indent.
-
-Wed Mar 30 16:33:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * extension.rdoc, extension.ja.rdoc: [DOC] Fix some errors.
- Renamed files, wrong method names or argument types; the example
- GetDBM macro is now updated to the current version of the actual
- code. patch by Marcus Stollsteimer in [ruby-core:74690].
- [Bug #12228]
-
-Wed Mar 30 09:46:01 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/open-uri.rb: Use `userinfo` for authenticated proxy.
- [fix GH-1148] Patch by @SokichiFujita
- * test/open-uri/test_open-uri.rb: ditto.
- [fix GH-1309] Patch by @jdamick
-
-Wed Mar 30 01:56:06 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * ext/nkf/nkf-utf8/nkf.c: Merge upstream 4f3edf80a0.
- patched by Anton Sivakov [Bug #12201] [Bug #12202]
-
-Wed Mar 30 01:54:30 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/redmine-backporter.rb: add given revision to current changesets
- on associating the revision to the related ticket.
-
-Wed Mar 30 01:53:17 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/merger.rb: update revision.h before merge.
-
-Tue Mar 29 19:33:54 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * addr2line.c: define toupper for its use. fix r54391.
-
-Tue Mar 29 19:23:46 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * include/ruby/ruby.h (rb_isupper, rb_islower, rb_isalpha, rb_isdigit,
- rb_isalnum, rb_isxdigit, rb_isblank, rb_isspace, rb_isblank,
- rb_iscntrl, rb_isprint, rb_ispunct, rb_isgraph,
- rb_tolower, rb_toupper): use inline function to avoid function call.
-
- * include/ruby/ruby.h (rb_isascii): use inline function to clarify
- the logic.
-
-Tue Mar 29 18:56:55 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/redmine-backporter.rb (backport): show merger.rb's path.
-
- * tool/redmine-backporter.rb (show): show current issue again if no
- ticket number is given.
-
- * tool/redmine-backporter.rb (rel): show error message if current
- bugs.ruby-lang.org doesn't support the API.
-
-Tue Mar 29 18:54:34 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * tool/merger.rb: support to backport header as backport identifier.
- Now you can specify by 'merge revision(s) 49254: [Backport #10738]'.
-
-Tue Mar 29 16:53:44 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb, casefold.h: Tweaked handling of 6
- special cases in CaseUnfold_11_Table.
-
- * enc/unicode.c: Adjustments for above.
-
- * test/ruby/enc/test_case_mapping.rb: Tests for the above: Some tests in
- test_titlecase activated; test_greek added. A test in test_cherokee fixed.
-
-Tue Mar 29 13:31:00 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Cleaned up some comments.
-
-Tue Mar 29 13:24:56 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb, casefold.h: Removing data for idempotent
- titlecasing.
-
- * enc/unicode.c: Adjust code to data removal.
-
-Tue Mar 29 12:45:18 2016 Laurent Arnoud <laurent@spkdev.net>
-
- * lib/webrick/httpresponse.rb: Move error_body to method. It allow to
- override the body more easily. [fix GH-1307]
- * test/webrick/test_httpresponse.rb: ditto.
-
-Tue Mar 29 06:40:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (rb_compile_err_append): rb_thread_t::base_block is no
- longer used.
-
- * iseq.c (rb_iseq_compile_with_option): ditto, no protection is
- needed.
-
-Tue Mar 29 06:39:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (struct parser_params): move parse_in_eval flag from
- rb_thread_t.
-
- * parse.y (rb_parser_set_context): set parsing context, not only
- mild error flag.
-
- * iseq.c (rb_iseq_compile_with_option): the parser now refers no
- thread local states to be restored.
-
- * vm_eval.c (eval_string_with_cref): ditto.
-
-Mon Mar 28 21:24:02 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * numeric.c (int_pos_p): fix typos.
-
-Mon Mar 28 14:54:49 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Refactoring in preparation for data reduction for
- titlecase.
-
-Mon Mar 28 14:36:36 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Minor refactoring for I WITH DOT ABOVE.
-
-Mon Mar 28 14:26:24 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Removed code now covered by data from table.
-
-Mon Mar 28 11:49:21 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Adding comments. [ci skip]
-
-Mon Mar 28 11:30:23 2016 Shinichi Maeshima <netwillnet@gmail.com>
-
- * lib/rubygems.rb: Fix `Gem.find_spec_for_exe` picks oldest gem.
- https://github.com/travis-ci/travis-ci/issues/5798
- https://github.com/rubygems/rubygems/pull/1566
- * test/rubygems/test_gem.rb: ditto.
-
-Mon Mar 28 11:26:31 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems-2.6.2.
- Please see entries of 2.6.2 on
- https://github.com/rubygems/rubygems/blob/master/History.txt
-
-Mon Mar 28 11:02:31 2016 Hiroshi Shirosaki <h.shirosaki@gmail.com>
-
- * lib/rubygems/test_case.rb: Fix test on Windows for inconsistent temp path.
- https://github.com/rubygems/rubygems/pull/1554
- [Bug #12193][ruby-core:74431]
-
-Mon Mar 28 08:19:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * sprintf.c (rb_str_format): refactor floating point format of
- Rational by using generic Integer functions.
-
- * sprintf.c (rb_str_format): fix buffer overflow, length must be
- greater than precision. reported by William Bowling <will AT
- wbowling.info>.
-
-Sun Mar 27 12:13:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * sprintf.c (rb_str_format): convert Rational to floating point
- format by using generic Integer functions, not by methods which
- can be overwritten.
-
-Sat Mar 26 10:55:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (rb_int2str): conversion function to String for
- generic Integer.
-
- * numeric.c (rb_int_round): rounding function for generic
- Integers.
-
- * numeric.c (rb_int_{uminus,plus,minus,mul,idiv,modulo}): basic
- arithmetic functions for generic Integers.
-
- * numeric.c (FIXNUM_{POSITIVE,NEGATIVE,ZERO}_P): predict macros
- only for Fixnum.
-
-Sat Mar 26 06:34:24 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * localeinit.c (rb_locale_charmap_index): fix prototype.
- patched by Andreas Schwab [Bug #12218]
-
-Fri Mar 25 16:40:48 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_mapping.rb: Additional tests title case;
- some not yet activated.
-
-Fri Mar 25 13:38:11 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * ext/openssl/extconf.rb: check SSL_CTX_set_next_proto_select_cb
- function rather than OPENSSL_NPN_NEGOTIATED macro. it exists
- even if it is disabled by OpenSSL configuration.
- [ruby-core:74384] [Bug #12182]
-
- * ext/openssl/ossl_ssl.c: update #ifdef(s) as above.
-
- * test/openssl/test_ssl.rb: skip NPN tests if NPN is disabled.
-
-Fri Mar 25 11:08:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/uri/http.rb (URI::HTTP#initialize): [DOC] fix example,
- missing mandatory arguments. [ruby-core:74540] [Bug #12215]
-
-Fri Mar 25 01:50:58 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * thread_pthread.c (reserve_stack): fix reserving position where
- the stack growing bottom to top. [Bug #12118]
-
-Fri Mar 25 01:10:42 2016 Sebastian Schuberth <sschuberth@gmail.com>
-
- * lib/mkmf.rb (find_executable0): On Windows, it is actually valid
- to surround individual PATH directory entries with double
- quotes. Remove these before joining the path as otherwise the
- literal quotes would become part of the path, resulting in the
- executable not to be found. [Fix GH-1305]
-
-Thu Mar 24 22:38:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * strftime.c (FMT, FMTV): remove recursive-assignments to get rid
- of undefined behavior. [ruby-core:74532] [Bug #12213]
-
-Thu Mar 24 17:44:02 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * strftime.c (FMT_PADDING): extract format for padding.
-
- * strftime.c (FMT_PRECISION): extract precision formula.
-
- * strftime.c (FMTV): append formatted string to expand the result.
-
-Thu Mar 24 14:20:21 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * strftime.c (STRFTIME): deal with case conversion flags for
- recursive formats.
-
-Thu Mar 24 12:43:26 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/date/date_core.c (dt_lite_iso8601): strftimev() always
- returns a String, so append them directly.
-
- * ext/date/date_core.c (d_lite_jisx0301, iso8601_timediv),
- (dt_lite_jisx0301): format by the format string in local buffer
- to prevent intermediate strings from GC.
-
- * ext/date/date_core.c (mk_inspect_raw, mk_inspect): inspect by
- "%+"PRIsVALUE, to prevent intermediate strings from GC.
-
-Thu Mar 24 11:43:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * strftime.c (rb_strftime_with_timespec): remove unnecessary
- check, as `s` equals to `endp` when recursed STRFTIME resized
- the capacity same as the size.
-
-Wed Mar 23 21:48:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * enum.c (ary_inject_op): put subtract operation out of if-clause.
-
-Wed Mar 23 21:38:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * enum.c (ary_inject_op): Use Kahan's compensated summation algorithm
- for summing up float values.
-
-Wed Mar 23 20:56:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * strftime.c (rb_strftime_with_timespec): append formatted results
- to the given string with expanding, and also deal with NUL chars.
-
- * strftime.c (rb_strftime, rb_strftime_timespec): return formatted
- string, not the length put in the given buffer.
-
- * time.c (rb_strftime_alloc): no longer needs to retry with
- reallocating buffers.
-
- * time.c (time_strftime): no longer needs to split by NUL chars.
-
-Wed Mar 23 14:23:54 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/rdoc/ri/driver.rb (interactive): rescue NotFoundError raised in
- expand_name. (display_name rescues NotFoundError by itself,
- the original logic looks buggy...)
-
-Wed Mar 23 11:44:53 2016 cremno <cremno@mail.ru>
-
- * marshal.c (r_long): cast to `signed char`, which is used
- already, instead of SIGN_EXTEND_CHAR.
-
- * parse.y: SIGN_EXTEND_CHAR is no longer used. [Fix GH-1302]
-
-Wed Mar 23 11:38:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * cygwin/GNUmakefile.in (MSYS2_ARG_CONV_EXCL_PARAM):
- * add missing parentheses and remove double quotes.
- * rename to get rid of recursive references.
- * as --excludes-dir option is for a path name, its argument
- should be converted.
- [ruby-dev:49526] [Bug #12199]
-
-Wed Mar 23 10:39:38 2016 Koichi ITO <koic.ito@gmail.com>
-
- * variable.c: Added documentation about order of `Module#constants`
- [ci skip][Bug #12121][ruby-dev:49505][fix GH-1301]
-
-Tue Mar 22 21:08:30 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * include/ruby/oniguruma.h: Additional flag for characters that are titlecase.
-
- * enc/unicode/case-folding.rb, casefold.h: Using above flag in data.
-
- * enc/unicode.c: Marking capitalized character as unmodified if it is
- already titlecase.
-
- * test/ruby/enc/test_case_mapping.rb: Tests for above functionality.
-
-Tue Mar 22 14:18:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (lambda_body, parser_yylex): warn mismatched indentation
- of lambda block.
-
-Tue Mar 22 11:36:49 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * time.c (wmul): wrong condition.
- fixed many test failures on 32bit and LLP64 platforms.
-
-Tue Mar 22 10:31:34 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * time.c (wdiv, wmod): wdivmod0() assumes the 3rd and the 4th arguments
- are valid pointers.
- maybe checking them in wdivmod0() is better manner, but I guess that
- passing real dummy pointers may be faster than checking and branching
- in wdivmod0().
- this commit fixes SEGV on 32bit and LLP64 platforms.
-
-Tue Mar 22 10:24:04 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * time.c (divmodv): void function never returns any value.
-
-Tue Mar 22 10:11:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/lib/test/unit.rb (Test::Unit::StatusLine#failed): print
- failed messages only if replacing mode, otherwise defer them
- until the end, to get rid of interleaving failures with progress
- messages. refix r54195.
-
-Tue Mar 22 03:45:03 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * time.c (MUL_OVERFLOW_FIXWV_P): defined for FIXWV.
-
- * time.c (wmul): use MUL_OVERFLOW_FIXWV_P and only switch.
-
- * time.c (wmul): use mul which has Fixnum optimization.
-
- * time.c (rb_time_magnify): If WIDEVALUE_IS_WIDER, wmul() has the same
- optimized logic, else mul() has also the similar logic for Fixnum.
-
- * time.c (rb_time_unmagnify): almost ditto.
-
-Tue Mar 22 03:10:09 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * time.c (divmodv): add the case both arguments are Fixnum.
-
- * time.c (wquo): use quo which has Fixnum optimization.
-
- * time.c (wdivmod0): added for WIDEVALUE_IS_WIDER.
-
- * time.c (wdivmod): use wdivmod0 and divmodv.
- divmodv has Fixnum optimization.
-
- * time.c (wdiv): use wdivmod0 and div to avoid the use of divmodv which
- calls id_quo whose return value is array.
-
- * time.c (wmod): use wdivmod0 and mod to avoid the use of divmodv which
- calls id_quo whose return value is array.
-
-Mon Mar 21 22:32:50 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * internal.h (rb_fix_divmod_fix): like r54213, use FIX2NUM only if
- x == FIXNUM_MIN && y == -1. This must be a rare case and it is
- expected compiler to handle well.
-
-Mon Mar 21 22:15:11 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * time.c (mod): Add Fixnum case.
-
- * time.c (quo): c can be Fixnum except a == FIXNUM_MIN && b == -1.
- Such case can be optimized out because quo()'s argument is constant.
-
-Mon Mar 21 22:09:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * internal.h (rb_fix_mul_fix): multiply converted values, not
- object VALUEs.
-
-Mon Mar 21 20:18:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk (TEST_EXCLUDES, EXCLUDE_TESTFRAMEWORK): use full spell
- long option.
-
- * cygwin/GNUmakefile.in (MSYS2_ARG_CONV_EXCL): suppress path name
- conversions by msys2. [ruby-dev:49525] [Bug #12199]
-
-Mon Mar 21 19:09:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (enc_succ_alnum_char): try to skip an invalid character
- gap between GREEK CAPITAL RHO and SIGMA.
- [ruby-core:74478] [Bug #12204]
-
-Mon Mar 21 18:55:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * node.c (rb_gc_mark_node): NODE_MATCH2 can have nd_args, u3,
- since r54100.
-
-Sun Mar 20 21:17:13 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * internal.h (rb_int128t2big): declare only when HAVE_INT128_T.
- fixed a compile error with VC++ introduced at r54203.
-
-Sun Mar 20 20:10:14 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * internal.h (DLONG): defined if long is 32bit (and LONG_LONG is 64bit;
- but LONG_LONG is always defined as 64bit), or there's int128_t.
-
- * internal.h (DL2NUM): defined if DLONG is defined.
-
- * internal.h (rb_fix_mul_fix): defined for `Fixnum * Fixnum`.
-
- * insns.def (opt_mul): use rb_fix_mul_fix().
-
- * numeric.c (fix_mul): ditto.
-
- * time.c (mul): ditto.
-
-Sun Mar 20 18:53:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (fix_gt, fix_ge, fix_lt, fix_le): optimize comparisons
- Fixnum against Bignum by rb_big_cmp in inversed order without
- new Bignum instance.
-
-Sun Mar 20 18:44:52 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * time.c (add): remove FIXABLE() which is in LONG2NUM().
-
- * time.c (sub): ditto.
-
- * time.c (mul): ditto.
-
-Sun Mar 20 04:46:02 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * bignum.c (rb_big_cmp): reduce the code.
-
- * bignum.c (rb_big_eq): If normalized bignum is still bignum,
- it must be larger than fixnum.
-
-Sat Mar 20 00:58:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * include/ruby/intern.h (rb_big_odd_p, rb_big_even_p): move to
- internal.h so that they are exported only for ruby itself.
-
- * internal.h (rb_big_odd_p, rb_big_even_p): ditto.
-
-Sat Mar 19 21:56:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/lib/test/unit.rb (Test::Unit::StatusLine#failed): defer
- failed messages until the end in verbose mode, to get rid of
- interleaving failures with progress messages.
-
-Sat Mar 19 21:53:35 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (fix_cmp): invert the result as the comparison is
- inverted.
-
-Sat Mar 19 18:32:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * numeric.c (int_to_f): raise NotImplementedError when a receiver
- class is unknown.
-
- * test/-ext-/integer/test_my_integer.rb (test_my_integer_to_f): modify
- a test for the above change.
-
-Sat Mar 19 18:21:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * bignum.c (Bignum#<=>): remove it because they are unified with
- Integer#<=>.
-
- * numeric.c (Integer#<=>, Fixnum#<=>): move <=> method from Fixnum to
- Integer.
-
- * numeric.c (int_cmp): add this method for Integer#<=>.
-
- * test/-ext-/integer/test_my_integer.rb (test_my_integer_cmp): add a
- test to examine Integer#<=> for unknown subclasses.
-
-Sat Mar 19 14:46:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * iseq.c (rb_iseq_compile_with_option): make the parser in mild
- error.
-
- * load.c (rb_load_internal0): ditto.
-
- * parse.y (yycompile0): return the error message within the error
- to be raised. [Feature #11951]
-
- * parse.y (parser_compile_error): accumulate error messages in the
- error_buffer.
-
-Sat Mar 19 03:57:13 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * time.c (LOCALTIME): organize #ifdefs.
-
- * time.c (GMTIME): define only ifndef HAVE_STRUCT_TM_TM_GMTOFF.
-
-Sat Mar 19 03:53:31 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in (rb_cv_member_struct_tm_tm_gmtoff): For Linux (glibc)
- define _BSD_SOURCE for time.h to define struct tm.tm_gmtoff.
-
- * time.c: define _BSD_SOURCE at the top.
-
-Sat Mar 19 03:00:50 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/-ext-/time/test_new.rb (test_timespec_new): change a gmtoff
- test to a better one that does not depend on whether the current
- time is in summer time or not.
-
-Fri Mar 19 00:00:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * bignum.c (rb_big_to_f, Bignum#to_f): removed them because they are
- unified with int_to_f and Integer#to_f.
-
- * numeric.c (int_to_f): treat Bignum values directly.
-
-Fri Mar 18 23:41:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * numeric.c (int_to_f, fix_to_f): rename fix_to_f to int_to_f, and add
- treatment for subclasses which don't have definitions of to_f method.
-
- * numeric.c (Integer#to_f, Fixnum#to_f): move to_f method from Fixnum
- to Integer.
-
- * ext/-test-/integer/my_integer.c: define helper class for testing
- to_f method for a subclass of Integer.
-
- * ext/-test-/integer/extconf.rb: ditto.
-
- * ext/-test-/integer/init.c: ditto.
-
- * test/-ext-/integer/test_my_integer.rb: examine to_f method for a
- subclass of Integer.
-
-Fri Mar 18 22:32:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * include/ruby/intern.h (rb_big_hash): Move to internal.h.
-
- * internal.h: ditto.
-
-Fri Mar 18 22:10:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * bignum.c (Bignum#eql?): remove its definition because it is unified
- with Numeric#eql?.
-
- * numeric.c (num_eql): treat Bignum values directly.
-
-Fri Mar 18 21:57:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * bignum.c (rb_big_to_s, Bignum#to_s): remove its definition because
- it is unified with Integer#to_s.
-
- * numeric.c (int_to_s): treat Bignum values directly.
-
-Fri Mar 18 21:30:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * numeric.c (int_to_s): Move from fix_to_s.
-
- * numeric.c (Integer#to_s): Move from Fixnum#to_s.
-
-Fri Mar 18 16:22:24 2016 Victor Nawothnig <Victor.Nawothnig@gmail.com>
-
- * parse.y (parse_numvar): NTH_REF must be less than a half of
- INT_MAX, as it is left-shifted to be ORed with back-ref flag.
- [ruby-core:74444] [Bug#12192] [Fix GH-1296]
-
-Fri Mar 18 12:25:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * gc.c (tick): fix missing close parenthesis. [Fix GH-1291]
-
-Fri Mar 18 10:24:12 2016 Naotoshi Seo <sonots@gmail.com>
-
- * ext/date/date_core.c (datetime_to_time): preserve timezone info
- [Bug #12189] [Fix GH-1295]
-
-Fri Mar 18 10:17:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * bignum.c (rb_big_hash): make it public function to be available in
- other source files, and remove documentation comment for Bignum#hash.
-
- * bignum.c (Bignum#hash): remove its definition because it is unified
- with Object#hash.
-
- * include/ruby/intern.h (rb_big_hash): add a prototype declaration.
-
- * hash.c (any_hash): treat Bignum values directly.
-
-Fri Mar 18 02:35:12 2016 Naotoshi Seo <sonots@gmail.com>
-
- * lib/time.rb (parse, strptime): Fix Time.parse/strptime does not
- have compatibility with DateTime.parse/strptime in terms of parsing
- timezone [Bug #12190] [Fix GH-1297]
-
-Fri Mar 18 02:17:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * numeric.c (fix_zero_p, fix_even_p, fix_odd_p): remove needless
- functions.
-
-Fri Mar 18 02:15:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * numeric.c (int_even_p): treat Fixnum and Bignum values directly.
-
-Fri Mar 18 02:07:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * bignum.c (Bignum#even?, Bignum#odd?): remove definitions
- because they are unified with Integer#even? and Integer#odd?.
-
- * numeric.c (Fixnum#zero?, Fixnum#even?, Fixnum#odd?): remove
- definitions because they are unified with Numeric#zero?,
- Integer#even?, and Integer#odd?.
-
- * numeric.c (num_zero_p, int_odd_p): treat Fixnum and
- Bignum values directly.
-
- * test/ruby/test_integer.rb (test_odd_p_even_p): remove meaningless
- test case.
-
-Fri Mar 18 01:51:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * bignum.c (rb_big_even_p, rb_big_odd_p): make them public functions
- to be available in other source files.
-
- * include/ruby/intern.h (rb_big_even_p, rb_big_odd_p): add prototype
- declarations.
-
-Fri Mar 18 00:25:56 2016 Tanaka Akira <akr@fsij.org>
-
- * enum.c (ary_inject_op): Implement the specialized code for sum of
- float numbers.
-
-Fri Mar 18 00:15:05 2016 Yusuke Endoh <mame@ruby-lang.org>
-
- * numeric.c (num_step): use rb_equal for zero check. rb_num_coerce_cmp
- created an object which caused extra overhead.
-
-Thu Mar 17 22:21:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/ruby.h (RB_GC_GUARD_PTR): remove intermediate
- macro, and expand for each RB_GC_GUARD. [Fix GH-1293]
-
-Thu Mar 17 22:08:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (iseq_specialized_instruction): move specialization
- for opt_newarray_max/min from translation phase.
-
-Thu Mar 17 21:52:09 2016 Yusuke Endoh <mame@ruby-lang.org>
-
- * array.c, enum.c: make rdoc format consistent.
-
-Thu Mar 17 21:47:57 2016 Yusuke Endoh <mame@ruby-lang.org>
-
- * NEWS: add Array#max, #min, and the optimization. [Feature #12172]
-
-Thu Mar 17 21:45:02 2016 Yusuke Endoh <mame@ruby-lang.org>
-
- * compile.c (NODE_CALL): add optimization shortcut for Array#max/min.
- Now `[x, y].max` is optimized so that a temporal array object is not
- created in some condition. [Feature #12172]
-
- * insns.def (opt_newarray_max, opt_newarray_min): added.
-
-Thu Mar 17 21:35:52 2016 Yusuke Endoh <mame@ruby-lang.org>
-
- * array.c (rb_ary_max, rb_ary_min): implement Array#max and min with
- arguments. replace super call with rb_nmin_run.
-
- * enum.c (nmin_run): exported (as rb_nmin_run).
-
- * internal.h: added a prototype for rb_nmin_run.
-
-Thu Mar 17 21:24:52 2016 Yusuke Endoh <mame@ruby-lang.org>
-
- * array.c (rb_ary_max, rb_ary_min): implement a block by itself instead
- of delegating Enumerable#max/min.
-
-Thu Mar 17 21:09:34 2016 Yusuke Endoh <mame@ruby-lang.org>
-
- * array.c (rb_ary_max, rb_ary_min): Array#max and Array#min added.
- [Feature #12172]
-
- * internal.h (OPTIMIZED_CMP): moved from enum.c so that array.c can
- use it.
-
- * test/ruby/test_array.rb (test_max, test_min): tests for Array#max
- and Array#min.
-
- * test/ruby/test_enum.rb (test_max, test_min): revised a bit to test
- Enumerable#max and #min explicitly.
-
-Thu Mar 17 21:02:42 2016 Yusuke Endoh <mame@ruby-lang.org>
-
- * internal.c: struct cmp_opt_data added for refactoring out a data
- structure for CMP_OPTIMIZABLE
-
- * array.c (struct ary_sort_data): use struct cmp_opt_data.
-
- * enum.c (struct min_t, max_t, min_max_t): use struct cmp_opt_data.
-
-Thu Mar 17 20:55:21 2016 Tanaka Akira <akr@fsij.org>
-
- * enum.c (ary_inject_op): Extracted from enum_inject.
-
-Thu Mar 17 18:39:04 2016 Tanaka Akira <akr@fsij.org>
-
- * enum.c (enum_inject): Implement the specialized code for sum of
- integers including Bignums.
-
- * internal.h (rb_fix_plus): Declared to be usable from enum_inject.
-
- * numeric.c (rb_fix_plus): Defined.
-
-Thu Mar 17 17:20:28 2016 Anton Davydov <antondavydov.o@gmail.com>
-
- * thread_sync.c: [DOC] Update documentation for Queue class
- description. [Fix GH-1292]
-
-Thu Mar 17 17:14:51 2016 Dinar Valeev <dvaleev@suse.com>
-
- * gc.c (tick): Use __builtin_ppc_get_timebase for POWER arch.
- [Fix GH-1291]
-
-Thu Mar 17 11:51:48 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/securerandom.rb (gen_random): to avoid blocking on Windows.
- On Windows OpenSSL RAND_bytes (underlying implementation is
- RAND_poll in crypto/rand/rand_win.c) may be blocked at
- NetStatisticsGet.
- https://wiki.openssl.org/index.php/Random_Numbers#Windows_Issues
- Instead of this, use Random.raw_seed directly (whose implementation
- CryptGenRandom is one of the source of
- entropy of RAND_poll on Windows).
- https://wiki.openssl.org/index.php/Random_Numbers
- Note: CryptGenRandom function is PRNG and doesn't check its entropy,
- so it won't block. [Bug #12139]
- https://msdn.microsoft.com/ja-jp/library/windows/desktop/aa379942.aspx
- https://www.rfc-editor.org/rfc/rfc4086#section-7.1.3
- https://eprint.iacr.org/2007/419.pdf
- http://www.cs.huji.ac.il/~dolev/pubs/thesis/msc-thesis-leo.pdf
-
-Thu Mar 17 12:09:00 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Fixed two macro definitions.
- * test/ruby/enc/test_case_mapping.rb: Test cases that detected
- the above bugs.
-
-Thu Mar 17 11:36:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/socket/option.c (inspect_tcpi_msec): more accurate condition
- for TCPI msec member inspection function.
- [ruby-core:74388] [Bug #12185]
-
-Thu Mar 17 08:13:43 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/-ext-/time/test_new.rb (test_timespec_new): Time#gmtoff values
- are the same only when both or neither of the Time objects are in
- summer time (daylight-saving time).
-
-Thu Mar 17 07:17:36 2016 Eric Hodel <drbrain@segment7.net>
-
- * marshal.c (r_object0): raise ArgumentError when linking to undefined
- object.
-
-Thu Mar 17 00:45:00 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * test/ruby/test_bignum.rb: Make sure to use Bignum values in the tests.
-
-Wed Mar 16 23:10:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * defs/keywords (alias, undef): symbol literals are allowed.
-
- * parse.y (parse_percent): should parse symbol literals for alias
- and undef. [ruby-dev:47681] [Bug #8851]
-
-Wed Mar 16 21:39:39 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * enc/trans/JIS: update Unicode's notice. [Bug #11844]
-
-Wed Mar 16 20:03:35 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * proc.c (proc_binding): proc from symbol can not make a binding.
- [ruby-core:74100] [Bug #12137]
-
-Wed Mar 16 18:42:45 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_mapping.rb: Fixed and activated a test for Cherokee.
-
-Wed Mar 16 17:58:56 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_mapping.rb: Fixed a logical error.
-
-Wed Mar 16 17:57:34 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_mapping.rb: Adding tests for Cherokee.
- One test not yet working.
- (with Kimihito Matsui)
-
-Wed Mar 16 15:44:05 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_mapping.rb: Adding tests for actual Unicode
- case mapping. Fixing some aliasing issues.
- (with Kimihito Matsui)
-
-Tue Mar 15 21:38:28 2016 Tanaka Akira <akr@fsij.org>
-
- * enum.c (enum_inject): Consider redefinition of Fixnum#+.
- [ruby-dev:49510] [Bug#12178] Reported by usa.
-
-Tue Mar 15 20:32:57 2016 Tanaka Akira <akr@fsij.org>
-
- * enum.c (enum_inject): Implement the specialized code for :+ operator
- for Fixnums.
-
-Tue Mar 15 20:21:01 2016 Tanaka Akira <akr@fsij.org>
-
- * enum.c (enum_inject): Implement the specialized code for self is an
- array and a symbol operator is given.
-
-Tue Mar 15 16:29:51 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Eliminating common code.
- (with Kimihito Matsui)
-
-Tue Mar 15 16:17:09 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Expansion of some code repetition in preparation for
- elimination of common code pieces.
- (with Kimihito Matsui)
-
-Tue Mar 15 13:49:23 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Additional macros and code to use mapping data in
- CaseMappingSpecials array.
- (with Kimihito Matsui)
-
-Tue Mar 15 13:41:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * internal.h (rb_gc_mark_global_tbl): should be private,
- but was accidentally exported.
-
-Tue Mar 15 12:51:06 2016 Marcus Stollsteimer <sto.mar@web.de>
-
- * doc/extension.ja.rdoc: Fix RDoc markup in doc/extension*.rdoc.
- [ci skip][Bug #12143][ruby-core:74143]
- * doc/extension.rdoc: ditto.
-
-Tue Mar 15 09:56:41 2016 Ian Lunderskov <ian.lunderskov@gmail.com>
-
- * time.c: Minor typo in Time#dst? documentation.
- [ci skip][fix GH-1290]
-
-Tue Mar 15 04:36:41 2016 Charles Oliver Nutter <headius@headius.com>
-
- * test/ruby/test_rubyoptions.rb (test_disable): add tests for
- --disable-gems and --disable-did_you_mean.
-
-Tue Mar 15 03:35:04 2016 Eric Hodel <drbrain@segment7.net>
-
- * marshal.c (r_object0): Fix Marshal crash for corrupt extended object.
-
-Tue Mar 15 01:22:27 2016 Charles Oliver Nutter <headius@headius.com>
-
- * test/ruby/test_rubyoptions.rb: make version matching support
- JRuby's version output.
-
-Mon Mar 14 19:05:39 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * bignum.c (big2str_2bdigits): reduce div instruction.
-
-Mon Mar 14 18:39:53 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * include/ruby/oniguruma.h, enc/unicode.c: Adjusting flag assignments
- and macros to work with unified CaseMappingSpecials array.
- (with Kimihito Matsui)
-
-Mon Mar 14 16:53:37 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (compile_named_capture_assign): optimize named capture
- assignments, by replacing repeating global variable accesses
- with `dup`, and by returning the matched result instead of
- re-getting it from the MatchData.
-
- * parse.y (reg_named_capture_assign_gen): build just assignment
- nodes for the optimization.
-
-Mon Mar 14 16:02:59 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * file.c (ruby_is_fd_loadable): now return -1 if loadable but
- may block.
-
- * ruby.c (open_load_file): wait to read by the result of
- ruby_is_fd_loadable, without fstat.
-
-Mon Mar 14 13:38:38 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * numeric.c (fix2str): improve r54092 like rb_int2big().
-
-Mon Mar 14 10:02:23 2016 Eric Wong <e@80x24.org>
-
- * ext/openssl/ossl_ssl.c (ossl_sslctx_setup): document as MT-unsafe
- [ruby-core:73803] [Bug #12069]
-
-Sun Mar 13 09:43:23 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/win32.h (O_SHARE_DELETE): change to fit Fixnum
- limit. [ruby-core:74285] [Bug #12171]
-
-Sun Mar 13 09:15:45 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (rb_fix2str): fix edge case, accidentally generated
- wrong Fixnum from LONG_MIN.
-
-Sat Mar 12 09:50:27 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (rb_f_catch): [DOC] fix malformed RDoc syntax, "+...+"
- cannot enclose non-identifier characters.
- a patch by Sebastian S in [ruby-core:74278]. [Bug#12170]
-
-Sat Mar 12 02:44:48 2016 Tanaka Akira <akr@fsij.org>
-
- * test/lib/test/unit.rb: describe !/REGEXP/ in the help message.
-
-Fri Mar 11 17:03:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/lib/test/unit.rb (Options#non_options): make regexp name
- options prefixed with "!" negative filters.
-
- * common.mk (TEST_EXCLUDES): use negative filter to exclude memory
- leak tests. -x option excludes test files, not test methods.
-
-Fri Mar 11 16:11:27 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb, casefold.h: Streamlining approach to
- case mapping data not available from case folding by unifying all
- three cases (special title, special upper, special lower).
- * enc/unicode.c: Adjust macro names for above (macros are currently inactive).
- (with Kimihito Matsui)
-
-Thu Mar 10 17:34:16 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * iseq.c (prepare_iseq_build): enable coverage by coverage_enabled
- option, not by parse_in_eval flag in the thread context.
-
- * iseq.h (rb_compile_option_struct): add coverage_enabled flag.
-
- * parse.y (yycompile0): set coverage_enabled flag if coverage
- array is made.
-
-Thu Mar 10 15:19:54 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * node.c (dump_option): nd_compile_option is a hidden hash object,
- cannot call inspect on it.
-
-Thu Mar 10 09:49:54 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/socket/test_socket.rb (test_udp_recvmsg_truncation):
- AIX does not set the MSG_TRUNC flag for a message partially read
- by recvmsg(2) with the MSG_PEEK flag set.
-
-Wed Mar 9 16:48:45 2016 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/driver.rb: fix my last commit (syntax error).
-
-Wed Mar 9 16:41:44 2016 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/driver.rb: fix output messages.
-
- * benchmark/memory_wrapper.rb: use respond_to? because
- member? does not work well.
-
-Wed Mar 9 16:20:25 2016 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/driver.rb: support memory usage benchmark.
- use `--measure-target=[target]'.
- Now, we can use the following targets:
- * real (default): real time which returns process time in sec.
- * peak: peak memory usage (physical memory) in bytes.
- * size: last memory usage (physical memory) in bytes.
-
- * benchmark/memory_wrapper.rb: ditto.
-
-Wed Mar 9 15:04:22 2016 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/bm_vm3_gc_old_full.rb: add GC.start benchmark.
-
- * benchmark/bm_vm3_gc_old_immediate.rb: ditto.
-
- * benchmark/bm_vm3_gc_old_lazy.rb: ditto.
-
-Wed Mar 9 14:59:11 2016 Koichi Sasada <ko1@atdot.net>
-
- * benchmark/driver.rb: exit benchmarking if a benchmark process
- receives signals.
-
-Wed Mar 9 13:22:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * test/lib/memory_status.rb: make Memory::Status independent of
- MiniTest::Skip.
-
- * test/lib/test/unit/assertions.rb (assert_no_memory_leak): skip
- if Memory::Status is not available.
-
-Wed Mar 9 09:19:55 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/io/wait/test_io_wait.rb (test_wait_readwrite_timeout):
- select(2) in AIX returns "readable" for the write-side fd
- of a pipe, so it is not possible to use a pipe to test
- the read-write timeout of IO#wait on AIX.
-
-Wed Mar 9 03:35:22 2016 Charles Oliver Nutter <headius@headius.com>
-
- * test/ruby/test_require.rb (test_require_with_loaded_features_pop):
- Only remove PATH so threads don't accidentally double-pop.
-
-Wed Mar 9 00:29:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_method.c (rb_alias): the original name should be properly
- available method_added method, set the name before calling the
- hook.
-
-Wed Mar 9 00:07:03 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/logger.rb (Logger::LogDevice#initialize): define using
- keyword arguments.
-
-Tue Mar 8 23:37:07 2016 Charles Oliver Nutter <headius@headius.com>
-
- * test/ruby/test_array.rb: split out the test for no stack error
- on large input for test_permutation, test_repeated_permutation,
- and test_repeated_combination, and make them all timeout:30.
-
-Tue Mar 8 17:20:21 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * intern.h (rb_divmod): assume compilers `/` and `%` comply C99
- and reduce branching. If a compiler doesn't comply, add #ifdefs.
-
- * intern.h (rb_div): added for Ruby's behavior.
-
- * intern.h (rb_mod): added for Ruby's behavior.
-
- * insns.def (opt_div): use rb_div.
-
- * insns.def (opt_mod): use rb_mod.
-
- * numeric.c (fixdivmod): removed.
-
- * numeric.c (fix_divide): use rb_div.
-
- * numeric.c (fix_mod): use rb_mod.
-
- * numeric.c (fix_divmod): use rb_divmod.
-
-Tue Mar 8 17:53:09 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * insns.def (opt_mod): show its method name on ZeroDivisionError.
- [Bug #12158]
-
-Tue Mar 8 17:33:38 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (rb_w32_write_console): now no need to check
- ERROR_CALL_NOT_IMPLEMENTED because it is for old Win9X.
-
-Tue Mar 8 16:54:29 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (rb_w32_write_console): stop the VT100 emulation if the
- console supports it natively.
-
-Tue Mar 8 08:13:01 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/net/imap/test_imap.rb (test_idle_timeout): Because of the
- timeout specified in "imap.idle(0.2)", there is no guarantee that
- the server thread has done all the work before the client thread
- performs the assertions. It depends on the thread scheduling.
- Add checks to avoid false positives (on AIX, particularly).
-
-Tue Mar 8 00:42:22 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * ruby.c (warn_cr_in_shebang): meaningless check on DOSISH platforms.
- fixed a test failure introduced at r53998.
-
-Tue Mar 8 00:27:53 2016 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * ext/tk/lib/tkextlib/tcllib/tablelist_tile.rb: fix method name typo.
- [ruby-core:72513] [Bug #11893] The patch provided by Akira Matsuda.
-
-
-Tue Mar 8 00:25:08 2016 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * ext/tk/lib/tkextlib/tcllib/toolbar.rb: fix method name typo.
- [ruby-core:72511] [Bug #11891] The patch provided by Akira Matsuda.
-
-
-Tue Mar 8 00:21:58 2016 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * ext/tk/lib/tkextlib/blt/tree.rb: fix method name typo.
- [ruby-core:72510] [Bug #11890] The patch provided by Akira Matsuda.
-
-
-Tue Mar 8 00:11:47 2016 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * ext/tk/lib/tk/menubar.rb: fix a typo in font name. [ruby-core:72505]
- [Bug #11886] The patch provided by Akira Matsuda.
-
- * ext/tk/sample/*.rb: ditto.
-
-Mon Mar 7 13:32:58 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * class.c (rb_define_class, rb_define_class_id_under): raise
- ArgumentError if super is 0, deprecated behavior which has been
- warned long time.
-
-Mon Mar 7 13:28:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * internal.h: move function declarations for class internals from
- include/ruby/intern.h.
-
-Mon Mar 7 10:58:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/win32ole/win32ole_event.c (rescue_callback): use
- rb_write_error_str instead of rb_write_error, to respect
- the encoding and prevent the message from GC.
-
- * internal.h (rb_write_error_str): export.
-
-Mon Mar 7 01:38:41 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/ruby/test_process.rb (test_execopts_gid): Skip a test
- that is known to fail on AIX. AIX allows setgid to
- a supplementary group, but Ruby does not allow the "-e"
- option when setgid'ed, so the test does not work as intended.
-
-Sun Mar 6 22:43:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * io.c (rb_obj_display): [DOC] fix output of Array, as Array#to_s
- is same as Array#inspect since 1.9.
-
-Sat Mar 5 09:50:58 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/socket/test_addrinfo.rb (test_ipv6_address_predicates):
- IN6_IS_ADDR_V4COMPAT and IN6_IS_ADDR_V4MAPPED are broken
- on AIX, so skip related tests.
-
-Sat Mar 5 09:17:54 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/rinda/test_rinda.rb (test_make_socket_ipv4_multicast):
- The fifth argument to getsockopt(2) should be modified to
- indicate the actual size of the value on return,
- but not in AIX. This is a know bug. Skip related tests.
- * test/rinda/test_rinda.rb (test_ring_server_ipv4_multicast):
- ditto.
- * test/rinda/test_rinda.rb (test_make_socket_unicast): ditto.
- * test/socket/test_basicsocket.rb (test_getsockopt): ditto.
- * test/socket/test_sockopt.rb (test_bool): ditto.
-
-Sat Mar 5 07:36:27 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/-ext-/float/test_nextafter.rb: In AIX,
- nextafter(+0.0,-0.0)=+0.0, and nextafter(-0.0,+0.0)=-0.0,
- but they should return -0.0 and +0.0, respectively. This is
- a known bug in nextafter(3) on AIX, so skip related tests.
-
-Sat Mar 5 07:14:10 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * test/zlib/test_zlib.rb (test_adler32_combine, test_crc32_combine):
- Skip two tests on AIX because zconf.h in zlib does not correctly
- recognize _LARGE_FILES in AIX. The problem was already reported
- to zlib, and skip these tests until it is fixed.
-
-Sat Mar 5 03:07:40 2016 Rei Odaira <Rei.Odaira@gmail.com>
-
- * thread_pthread.c (getstack): __pi_stacksize returned by
- pthread_getthrds_np() is wrong on AIX. Use
- __pi_stackend - __pi_stackaddr instead.
-
-Fri Mar 4 19:19:42 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: use 2 bits with unsigned int for rb_objspace::flags::mode
- because it always returns 0 to 2 (non-negative value).
-
-Fri Mar 4 18:42:08 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename "enum gc_stat" to "enum gc_mode"
- because there is a same name (no related) function gc_stat().
-
- Also gc_stat_* are renamed to gc_mode_*,
- gc_stat_transition() to gc_mode_transition(),
- rb_objspace::flags::stat is renamed to rb_objspace::flags::mode.
-
- Change rb_objspace::flags::mode from 2 bits to 3 bits because VC++
- returns negative enum value with 2 bits.
-
- * gc.c (gc_mode): add a macro to access rb_objspace::flags::mode
- with verification code (verification is enabled only on
- RGENGC_CHECK_MODE > 0).
-
- * gc.c (gc_mode_set): same macro for setter.
-
-Fri Mar 4 09:28:18 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems-2.6.1.
- Please see entries of 2.6.0 and 2.6.1 on
- https://github.com/rubygems/rubygems/blob/master/History.txt
- [fix GH-1270] Patch by @segiddins
-
-Thu Mar 3 14:09:00 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/ostruct.rb (modifiable?, new_ostruct_member!, table!):
- rename methods for internal use with suffixes and make private,
- [ruby-core:71069] [Bug #11587]
-
-Wed Mar 2 16:28:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (method_missing): call by found method entry and get
- rid of searching the same method entry twice.
-
- * vm_eval.c (vm_call0_body): calling method_missing method is
- method_missing().
-
-Wed Mar 2 15:13:33 2016 herwinw <herwin@quarantainenet.nl>
-
- * lib/xmlrpc.rb: Removed broken parser named XMLScanStreamParser.
- It's not works with current Ruby version.
- [fix GH-1271][ruby-core:59588][Bug #9369]
- * lib/xmlrpc/config.rb: ditto.
- * lib/xmlrpc/parser.rb: ditto.
-
-Wed Mar 2 15:08:33 2016 herwinw <herwin@quarantainenet.nl>
-
- * lib/xmlrpc.rb: Removed broken parser named XMLTreeParser.
- Required gem of its parser didn't compile on newer Ruby versions.
- [fix GH-1271][ruby-core:59590][Bug #9370]
- * lib/xmlrpc/config.rb: ditto.
- * lib/xmlrpc/parser.rb: ditto.
-
-Tue Mar 1 11:25:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/fileutils.rb: use keyword arguments instead of option
- hashes.
-
-Mon Feb 29 16:50:20 2016 hanachin <hanachin@gmail.com>
-
- * array.c (rb_ary_push_m): [DOC] Remove trailing comma from
- Array#push example, as other Array examples doesn't put trailing
- comma. [Fix GH-1279]
-
-Mon Feb 29 16:31:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * common.mk, tool/mkconfig.rb: set cross_compiling option from
- Makefile, but not from rbconfig.rb, which is just going to be
- created by this command.
-
-Sun Feb 28 23:13:49 2016 C.J. Collier <cjcollier@linuxfoundation.org>
-
- * configure.in: Add summary to end of configure output.
- [Fix GH-1275]
-
-Sun Feb 28 20:23:36 2016 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
-
- * lib/drb/drb.rb (error_print): Add verbose failure messages and
- avoid infamous DRb::DRbConnError. [Feature #12101]
-
-Sun Feb 28 13:40:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (nometh_err_initialize): add private_call? parameter.
-
- * error.c (nometh_err_private_call_p): add private_call? method,
- to tell if the exception raised in private form FCALL or VCALL.
- [Feature #12043]
-
- * vm_eval.c (make_no_method_exception): append private_call?
- argument.
-
- * vm_insnhelper.c (ci_missing_reason): copy FCALL flag.
-
-Sun Feb 28 10:19:47 2016 Ryan T. Hosford <tad.hosford@gmail.com>
-
- * array.c (rb_ary_and): clarify that set intersection returns the
- unique elements common to both arrays.
-
- * array.c (rb_ary_or): clarify that union preserves the order from
- the given arrays.
-
-Sat Feb 27 17:05:29 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb, casefold.h: Reducing size of TitleCase
- table by eliminating duplicates.
- (with Kimihito Matsui)
-
-Fri Feb 26 14:40:48 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (num_step_scan_args): comparison String with Numeric
- should raise TypeError. it is an invalid type, but not a
- mismatch the number of arguments. [ruby-core:62430] [Bug #9810]
-
-Fri Feb 26 14:39:39 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * doc/extension.rdoc, doc/extension.ja.rdoc: add editor local
- variables, with commenting out by :enddoc: directives which are
- just ignored unless code object mode. [Bug #12111]
-
-Fri Feb 26 12:25:56 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * doc/extension.ja.rdoc: removed rendering error caused by editor specific
- configuration on http://docs.ruby-lang.org/en/trunk/extension_rdoc.html .
- [Bug #12111][ruby-core:73990]
-
-Fri Feb 26 11:21:41 2016 herwinw <herwin@quarantainenet.nl>
-
- * lib/xmlrpc.rb: Removed references to NQXML. It's obsoleted parser.
- [fix GH-1245][ruby-core:59593][Feature #9371]
- * lib/xmlrpc/config.rb: ditto.
- * lib/xmlrpc/parser.rb: ditto.
-
-Fri Feb 26 11:10:19 2016 Rick Salevsky <rsalevsky@suse.com>
-
- * lib/tmpdir.rb: Unify to coding-style for method definition.
- [fix GH-1252]
-
-Fri Feb 26 11:02:04 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * README.md: update markdown syntax for anchor tag.
- [fix GH-1265] Patch by @lukBarros
-
-Fri Feb 26 10:52:29 2016 Alex Boyd <alex@opengroove.org>
-
- * lib/irb.rb: avoid to needless truncation when using back_trace_limit option.
- [fix GH-1205][ruby-core:72773][Bug #11969]
-
-Fri Feb 26 08:11:58 2016 Aaron Patterson <tenderlove@ruby-lang.org>
-
- * gem_prelude.rb: Reduce system calls by activating the `did_you_mean`
- gem before requiring the gem. Activating the gem puts the gem on
- the load path, where simply requiring the file will search every gem
- that's installed until it can find a gem that contains the
- `did_you_mean` file.
-
-Thu Feb 25 19:04:13 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb: Adding possibility for debugging output
- for TitleCase table in casefold.h.
- (with Kimihito Matsui)
-
-Wed Feb 24 22:31:13 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * include/ruby/oniguruma.h: Rearranging flag assignments and making
- space for titlecase indices; adding additional macros to add or
- extract titlecase index; adding comments for better documentation.
- * enc/unicode.c: Moving some macros to include/ruby/oniguruma.h;
- activating use of titlecase indices.
- (with Kimihito Matsui)
-
-Wed Feb 24 21:03:04 2016 Tanaka Akira <akr@fsij.org>
-
- * random.c (limited_rand): Add a specialized path for when the limit fits
- in 32 bit.
-
-Tue Feb 23 21:52:24 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb, casefold.h: Outputting actual titlecase
- data (new table, with indices from other tables).
- * enc/unicode.c: Ignoring titlecase data indices for the moment.
- (with Kimihito Matsui)
-
-Tue Feb 23 15:21:14 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb, casefold.h: Reading casing data from
- SpecialCasing.txt.
- (with Kimihito Matsui)
-
-Mon Feb 22 18:33:55 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb, casefold.h: Adding flag for title-case,
- not yet operational.
- (with Kimihito Matsui)
-
-Mon Feb 22 18:17:03 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb, casefold.h: Fixed bug that avoided inclusion
- of compatibility characters in upper-/lower-case mappings.
- (with Kimihito Matsui)
-
-Sun Feb 21 13:57:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * cgi/escape/escape.c: Optimize CGI.unescape performance by C ext
- for ASCII-compatible encodings. [Fix GH-1250]
-
-Sun Feb 21 13:56:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * cgi/escape/escape.c: Optimize CGI.unescapeHTML performance by C
- ext for ASCII-compatible encodings. [Fix GH-1242]
-
-Sat Feb 20 15:38:16 2016 Eric Wong <e@80x24.org>
-
- * doc/extension.rdoc: update paths for defs/ directory
-
-Sat Feb 20 14:44:15 2016 Lucas Buchala <lucasbuchala@gmail.com>
-
- * vm_eval.c (rb_mod_module_eval): [DOC] Fix documentation
- signature for Module#module_eval. [Fix GH-1258]
-
-Sat Feb 20 14:40:44 2016 Adam O'Connor <northband@gmail.com>
-
- * README.md: a few grammatical changes to the main Ruby README.md.
- [Fix GH-1259]
-
-Sat Feb 20 13:04:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (push_pattern, push_glob): deal with read paths as UTF-8
- to stat later, on Windows as well as OS X.
- [ruby-core:73868] [Bug #12081]
-
-Sat Feb 20 01:53:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (rb_mod_const_get): make error message at uninterned
- string consistent with symbols. [ruby-dev:49498] [Bug #12089]
-
-Fri Feb 19 23:37:52 2016 Masahiro Tomita <tommy@tmtm.org>
-
- * lib/find.rb (Find#find): raise with the given path name if it
- does not exist. [ruby-dev:49497] [Bug #12087]
-
-Fri Feb 19 12:44:57 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Activated use of case mapping data in CaseUnfold_11 array.
- (with Kimihito Matsui)
-
-Fri Feb 19 11:08:32 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/extmk.rb: add cygwin case, nothing excluded.
- [ruby-core:73806] [Bug#12071]
-
-Thu Feb 18 21:32:15 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * man/irb.1: fix output in EXAMPLES.
-
-Thu Feb 18 21:05:47 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (sym_match_m): delegate to String#match but not
- String#=~. [ruby-core:72864] [Bug #11991]
-
-Thu Feb 18 14:15:38 2016 Shota Fukumori <her@sorah.jp>
-
- * re.c: Add MatchData#named_captures
- [Feature #11999] [ruby-core:72897]
-
- * test/ruby/test_regexp.rb(test_match_data_named_captures): Test for above.
-
- * NEWS: News about MatchData#named_captures.
-
-Wed Feb 17 21:41:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * defs/id.def (predefined): add idLASTLINE and idBACKREF for $_
- and $~ respectively.
-
- * parse.y: use idLASTLINE and idBACKREF instead of rb_intern.
-
-Wed Feb 17 20:23:38 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_str_init): fix segfault and memory leak, consider
- wide char encoding terminator.
-
-Wed Feb 17 12:14:59 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (rb_str_init): introduce String.new(capacity: size)
- [Feature #12024]
-
-Tue Feb 16 19:10:08 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb, casefold.h: Used only first element
- (rather than all) of target in CaseUnfold_11 array.
- (with Kimihito Matsui)
-
-Tue Feb 16 18:24:38 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * numeric.c (compare_with_zero): fix variable name, rb_cmperr
- requires VALUEs but not an ID.
-
-Tue Feb 16 17:34:18 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * dir.c (rb_dir_s_empty_p): add Dir.empty? method, which tells the
- argument is the name of an empty directory. [Feature #10121]
-
-Tue Feb 16 09:51:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/rbinstall.rb (without_destdir): just strip a drive letter
- which is prepended by with_destdir.
- pointed out by @DavidEGrayson.
- https://github.com/ruby/ruby/commit/0e5f9ae#commitcomment-16101763
-
-Tue Feb 16 04:42:13 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * insns.def (opt_plus): simply use LONG2NUM() instead of wrongly
- complex overflow case.
-
- * insns.def (opt_sub): ditto.
-
-Tue Feb 16 02:49:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/rbinstall.rb (without_destdir): compare with the destdir
- after stripping a drive letter, on dosish platforms.
- pointed out by @DavidEGrayson.
- https://github.com/ruby/ruby/commit/d0cf23b#commitcomment-16100407
-
-Mon Feb 15 15:44:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parse_ident): allow keyword arguments just after a
- method where the same name local variable is defined.
- [ruby-core:73816] [Bug#12073]
-
-Mon Feb 15 14:43:28 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb: Added debugging option
- (with Kimihito Matsui)
-
-Sun Feb 14 17:31:50 2016 Lars Kanis <lars@greiz-reinsdorf.de>
-
- * lib/mkmf.rb (with_{cpp,c,ld}flags): copy caller strings not to
- be modified, in append_{cpp,c,ld}flags respectively.
- [Fix GH-1246]
-
-Sun Feb 14 16:18:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (setup_exception): set the cause only if it is explicitly
- given or not set yet. [Bug #12068]
-
-Sat Feb 13 21:44:58 2016 Tanaka Akira <akr@fsij.org>
-
- * hash.c (rb_hash_invert): [DOC] more examples.
-
-Sat Feb 13 17:30:49 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/uri/generic.rb (URI::Generic#find_proxy): support CIDR in
- no_proxy. [ruby-core:73769] [Feature#12062]
-
-Sat Feb 13 17:11:58 2016 Fabian Wiesel <fabian.wiesel@sap.com>
-
- * lib/uri/generic.rb (find_proxy): exclude white-spaces and allow
- for a leading dot in the domain name in no_proxy.
- [ruby-core:54542] [Feature #8317]
-
-Fri Feb 12 12:20:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * error.c (name_err_initialize, nometh_err_initialize): [DOC] fix
- argument positions. optional parameters except for the message
- are placed at the last.
-
-Fri Feb 12 11:49:49 2016 Anthony Dmitriyev <antstorm@gmail.com>
-
- * net/ftp.rb: add NullSocket#closed? to fix closing not opened
- connection. [Fix GH-1232]
-
-Fri Feb 12 11:17:38 2016 Bogdan <bogdanvlviv@gmail.com>
-
- * re.c (rb_reg_initialize_m): [DOC] fix missing right bracket.
- [Fix GH-1243]
-
-Thu Feb 11 14:57:58 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (RUBY_CHECK_SIZEOF, RUBY_DEFINT): fix for types
- which are conditionally available depending on architectures
- when universal binary, e.g., __int128.
-
-Thu Feb 11 06:26:18 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in (RUBY_DEFINT): use Parameter Expansion.
-
-Thu Feb 11 05:33:24 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in (int128_t): don't check HAVE_XXX (for example
- HAVE___INT128) because RUBY_CHECK_SIZEOF() don't define it for
- config.h and use of $ac_cv_sizeof___int128 alternates the check.
- (and don't need to define because users shouldn't know that)
-
-Wed Feb 10 12:03:41 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in (ARFLAGS): check if deterministic mode flag is
- effective, which is on by default on Ubuntu.
-
-Tue Feb 9 16:36:23 2016 Naotoshi Seo <sonots@gmail.com>
-
- * lib/logger.rb: Remove block from Logger.add as it's not needed
- patch provided by Daniel Lobato Garcia [fix GH-1240] [Bug #12054]
-
-Tue Feb 9 14:32:23 2016 Zachary Scott <zzak@ruby-lang.org>
-
- * ext/zlib/zlib.c: Document mtime header behavior with patch by @schneems
- Fixes [GH-1129]: https://github.com/ruby/ruby/pull/1129
-
-Tue Feb 9 13:52:49 2016 Zachary Scott <zzak@ruby-lang.org>
-
- * re.c: Remove deprecated kcode argument from Regexp.new and compile
- patch provided by Dylan Pulliam [Bug #11495]
-
-Mon Feb 8 21:26:19 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb, enc/unicode/casefold.h: Flags for
- upper/lower conversion added (titlecase and SpecialCasing still missing)
- (with Kimihito Matsui)
-
-Mon Feb 8 20:43:57 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c, enc/unicode.c: Disassociating ONIGENC_CASE_FOLD flag from
- ONIGENC_CASE_DOWNCASE.
- (with Kimihito Matsui)
-
-Mon Feb 8 13:00:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Shortened macros for enc/unicode/casefold.h to
- single-letter; use flags in casefold.h for logic.
-
- * enc/unicode/case-folding.rb: Added flag for case folding.
- Changed parameter passing.
-
- * enc/unicode/casefold.h: New flags added.
- (with Kimihito Matsui)
-
-Mon Feb 8 10:30:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (feature_option): raise a runtime error if ambiguous
- feature name is given, in the future. [Bug #12050]
-
-Mon Feb 8 09:43:57 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * common.mk: Removed enc/unicode/casefold.h from automatic build because
- some CI systems don't have gperf. Creation of enc/unicode/casefold.h
- is now possible with make unicode-up. This is intended as a temporary measure.
-
-Sun Feb 7 22:10:08 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * common.mk: Added two more precondition files for enc/unicode/casefold.h
-
- * enc/unicode.c: Added shortening macros for enc/unicode/casefold.h
-
- * enc/unicode/case-folding.rb: Fixed file encoding for CaseFolding.txt
- to ASCII-8BIT (should fix some ci errors). Clarified usage. Created
- class MapItem. Partially implemented class CaseMapping.
- (with Kimihito Matsui)
-
-Sun Feb 7 14:12:32 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb: Fixing parameter passing.
- (with Kimihito Matsui)
-
-Sun Feb 7 11:44:03 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode/case-folding.rb: New classes CaseMapping/CaseMappingDummy
- to pass as parameters; not yet implemented or used.
- (with Kimihito Matsui)
-
-Sun Feb 7 11:16:00 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * common.mk: using new option in recipe for enc/unicode/casefold.h
-
- * enc/unicode/case-folding.rb: Correctly specify argument to new option.
- (with Kimihito Matsui)
-
-Sun Feb 7 10:43:27 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- (this commit message applies to the previous commit)
- * common.mk: explicit recipe for enc/unicode/casefold.h
-
- * enc/unicode/case-folding.rb: Adding -m option to prepare for using
- multiple data files.
- (with Kimihito Matsui)
-
-Sat Feb 6 22:30:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/cgi/util.rb (escapeHTML, unescapeHTML): consider
- ASCII-incompatible encodings. [Fix GH-1239]
-
-Sat Feb 6 15:18:28 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_regex_casefold.rb: Added data-based testing for
- String#downcase :fold.
-
- * enc/unicode.c: Fixed a range error (lowest non-ASCII character affected
- by case operations is U+00B5, MICRO SIGN)
-
- * test/ruby/enc/test_case_mapping.rb: Explicit test for case folding of
- MICRO SIGN to Greek mu.
- (with Kimihito Matsui)
-
-Sat Feb 6 14:51:23 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_regex_casefold.rb: Tests for three case folding
- primitives (mbc_case_fold, get_case_fold_codes_by_str,
- apply_all_case_fold) in the various encodings. Currently only known
- good encodings are tested to avoid test failures. For bug hunting,
- start by adding more encodings with
- generate_test_casefold encoding
- (with Kimihito Matsui)
-
-Sat Feb 6 14:37:16 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c, test/ruby/enc/test_case_mapping.rb: Implemented :fold
- option for String#downcase by using case folding data from
- regular expression engine, and added a few simple tests.
- (with Kimihito Matsui)
-
-Fri Feb 5 20:08:59 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_case_mapping.rb: added tests for :ascii option.
- (with Kimihito Matsui)
-
-Fri Feb 5 12:22:20 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * insns.def (opt_mult): Use int128_t for overflow detection.
-
- * bignum.c (rb_uint128t2big): added for opt_mult.
-
- * bignum.c (rb_uint128t2big): added for rb_uint128t2big..
-
- * configure.in: define int128_t, uint128_t and related MACROs.
- Initially introduced by r41379 but reverted by r50749.
-
-Thu Feb 4 21:05:17 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Activated :ascii flag for ASCII-only case conversion
- (with Kimihito Matsui)
-
-Thu Feb 4 17:38:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * re.c (reg_set_source): make source string frozen without
- copying.
-
- * re.c (rb_reg_initialize_m): refactor initialization with
- encoding.
-
-Thu Feb 4 15:35:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * string.c (rb_fstring_enc_new, rb_fstring_enc_cstr): functions to
- make fstring with encoding.
-
-Thu Feb 4 14:42:29 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * common.mk: Added Unicode data file SpecialCasing.txt to be additionally
- downloaded (with Kimihito Matsui)
-
-Thu Feb 4 12:39:08 2016 joker1007 <kakyoin.hierophant@gmail.com>
-
- * cgi/escape/escape.c: Optimize CGI.escape performance by C ext
- for ASCII-compatible encodings. [Fix GH-1238]
-
-Thu Feb 4 11:53:56 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * common.mk: Introduce two variables (UNICODE_DATA_DIR and
- UNICODE_SRC_DATA_DIR) to eliminate repetitions.
-
-Wed Feb 3 12:13:20 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * string.c (str_new_frozen): if the given string is embeddedable
- but not embedded, embed a new copied string. [Bug #11946]
-
-Wed Feb 3 08:25:38 2016 boshan <boshan@subsplash.com>
-
- * ext/openssl/ossl_pkey.c (Init_ossl_pkey): [DOC] Fix typo
- "encrypted" to "decrypted". [Fix GH-1235]
-
-Wed Feb 3 08:21:32 2016 Seiei Miyagi <hanachin@gmail.com>
-
- * ext/ripper/lib/ripper/lexer.rb (on_heredoc_dedent): Fix
- Ripper.lex error in dedenting squiggly heredoc. heredoc tree is
- also an array of Elem in the outer tree. [Fix GH-1234]
-
-Wed Feb 3 02:33:39 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * re.c (rb_reg_prepare_enc): use already compiled US-ASCII regexp
- if given string is ASCII only.
- 121.2s to 113.9s on my x86_64-freebsd10.2 Intel Core i5 661
-
-Tue Feb 2 13:02:03 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * re.c: Introduce RREGEXP_PTR.
- patch by dbussink.
- partially merge https://github.com/ruby/ruby/pull/497
-
- * include/ruby/ruby.h: ditto.
-
- * gc.c: ditto.
-
- * ext/strscan/strscan.c: ditto.
-
- * parse.y: ditto.
-
- * string.c: ditto.
-
-Tue Feb 2 09:08:27 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rubygems/specification.rb: `coding` is effective only first
- line except shebang.
-
- * lib/rubygems/package.rb, lib/rubygems/package/*: ditto.
-
-Mon Feb 1 21:41:58 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/rubygems.rb, lib/rubygems/*, test/rubygems/*: Update rubygems-2.5.2.
- It supports to enable frozen string literal and add `--norc` option for
- disable to `.gemrc` configuration.
- See 2.5.2 release notes for other fixes and enhancements.
- https://github.com/rubygems/rubygems/blob/a8aa3bac723f045c52471c7b9328310a048561e0/History.txt#L3
-
-Sun Jan 31 12:33:13 2016 Dan Kreiger <dan@dankreiger.com>
-
- * test/drb/ut_large.rb (multiply, avg, median): add additional
- math operations to DRbLarge. [Fix GH-1086]
-
-Sun Jan 31 12:19:15 2016 Kuniaki IGARASHI <igaiga@gmail.com>
-
- * test/ruby/test_file_exhaustive.rb (test_lstat): Add lacking test
- for File#lstat. [Fix GH-1231]
-
-Sun Jan 31 12:15:33 2016 Prayag Verma <prayag.verma@gmail.com>
-
- * doc/standard_library.rdoc: fix typo [Fix GH-1230]
- Spelling mistakes -
- outputing > outputting
- publich > publish
-
-Sat Jan 30 15:18:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_eval.c (rb_check_funcall_with_hook): also should call the
- given hook before returning Qundef when overridden respond_to?
- method returned false. [ruby-core:73556] [Bug #12030]
-
-Fri Jan 29 17:40:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * win32/file.c (rb_readlink): drop garbage after the substitute
- name, as rb_w32_read_reparse_point returns the expected buffer
- size but "\??\" prefix is dropped from the result.
-
- * win32/win32.c (w32_readlink): ditto, including NUL-terminator.
-
-Fri Jan 29 17:07:27 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * win32/win32.c (fileattr_to_unixmode, rb_w32_reparse_symlink_p): volume
- mount point should be treated as directory, not symlink.
- [ruby-core:72483] [Bug #11874]
-
- * win32/win32.c (rb_w32_read_reparse_point): check the reparse point is
- a volume mount point or not.
-
- * win32/file.c (rb_readlink): follow above change (but this pass won't
- be used).
-
-Fri Jan 29 16:17:07 2016 Lucas Buchala <lucasbuchala@gmail.com>
-
- * enum.c (enum_take_while, enum_drop_while): rename block
- parameter to obj, since they are generic objects. [Fix GH-1226]
-
-Fri Jan 29 14:15:26 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/erb.rb (ERB::Compiler#detect_magic_comment): allow
- frozen-string-literal in comment as well as encoding.
-
- * lib/erb.rb (ERB#def_method): insert def line just before the
- first non-comment and non-empty line, not to leave duplicated
- and stale magic comments.
-
-Fri Jan 29 11:13:33 2016 Jeremy Evans <code@jeremyevans.net>
-
- * lib/erb.rb (ERB#set_eoutvar): explicitly make mutable string as
- a buffer to make ERB work with --enable-frozen-string-literal.
- [ruby-core:73561] [Bug #12031]
-
-Fri Jan 29 10:44:56 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/net/http/header.rb: Warn nil variable on HTTP Header.
- It caused to NoMethodError. [fix GH-952][fix GH-641] Patch by @teosz
- * test/net/http/test_httpheader.rb: Added test for nil HTTP Header.
-
-Thu Jan 28 17:31:43 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/socket/socket.c (sock_gethostname): support unlimited size
- hostname.
-
-Wed Jan 27 21:03:45 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * test/-ext-/string/test_capacity.rb: Added missing library.
-
-Wed Jan 27 18:53:40 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Fixed bit mask in macro OnigCodePointCount
-
-Wed Jan 27 17:54:42 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Protect code point count by macro, in order to
- be able to use the remaining bits for flags.
- (with Kimihito Matsui)
-
-Wed Jan 27 16:34:35 2016 boshan <boshan@subsplash.com>
-
- * lib/tempfile.rb (Tempfile#initialize): [DOC] the first parameter
- `basename` is optional and defaulted to an empty string since
- [GH-523]. [Fix GH-1225]
-
-Wed Jan 27 16:25:54 2016 Koichi ITO <koic.ito@gmail.com>
-
- * array.c (rb_ary_dig): [DOC] fix the exception class to be raised
- when intermediate object does not have dig method. TypeError
- will be raised now. [Fix GH-1224]
-
-Tue Jan 26 19:36:15 2016 Aggelos Avgerinos <evaggelos.avgerinos@gmail.com>
-
- * array.c (permute0, rpermute0): [DOC] Substitute indexes ->
- indices in documentation for consistency. [Fix GH-1222]
-
-Tue Jan 26 15:21:37 2016 Eric Wong <e@80x24.org>
-
- * compile.c (caller_location): use rb_fstring_cstr for "<compiled>"
- (it is converted to fstring anyways inside rb_iseq_new_with_opt)
- * iseq.c (iseqw_s_compile): ditto
- * iseq.c (rb_iseq_new_main): use rb_fstring_cstr for "<main>"
- * vm.c (Init_VM): ditto, share with with above
- * iseq.c (iseqw_s_compile_file): rb_fstring before rb_io_t->pathv
- share "<main>" with above
- * vm.c (rb_binding_add_dynavars): fstring "<temp>" immediately
-
-Tue Jan 26 15:14:01 2016 Kazuki Yamaguchi <k@rhe.jp>
-
- * compile.c (iseq_peephole_optimize): don't apply tailcall
- optimization to send/invokesuper instructions with blockiseq.
- This is a follow-up to the changes in r51903; blockiseq is now
- the third operand of send/invokesuper instructions.
- [ruby-core:73413] [Bug #12018]
-
-Tue Jan 26 14:26:46 2016 Eric Wong <e@80x24.org>
-
- * signal.c (sig_list): use fstring for hash key
- * test/ruby/test_signal.rb (test_signal_list_dedupe_keys): added
-
-Tue Jan 26 13:08:34 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * signal.c (rb_f_kill): should immediately deliver reserved
- signals SIGILL and SIGFPE, not only SIGSEGV and SIGBUS.
-
-Tue Jan 26 07:57:28 2016 Joseph Tibbertsma <josephtibbertsma@gmail.com>
-
- * gc.c (RVALUE_PAGE_WB_UNPROTECTED): fix a typo of argument name.
- [Fix GH-1221]
-
-Mon Jan 25 17:26:54 2016 Eric Wong <e@80x24.org>
-
- * ruby_assert.h (RUBY_ASSERT_WHEN): fix reference to macro name
- * vm_core.h: include ruby_assert.h before using
- [ruby-core:73371]
-
-Mon Jan 25 15:55:30 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * symbol.c (sym_check_asciionly): more informative error message
- with the encoding name and the inspected content.
- [ruby-core:73398] [Feature #12016]
-
-Mon Jan 25 09:38:26 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * test/ruby/test_string.rb: added testcase for next!, succ and succ!
- [fix GH-1213] Patch by @K0mAtoru
-
-Mon Jan 25 09:32:25 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/webrick/httpservlet/filehandler.rb: fix documentation for namespace.
- [fix GH-1219][ci skip] Patch by @leafac
-
-Sun Jan 24 19:34:23 2016 Eric Wong <e@80x24.org>
-
- * vm_insnhelper.c (vm_check_if_namespace): tiny size reduction
-
-Sun Jan 24 18:12:36 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * common.mk: Simplifying Unicode data file download logic to make
- it more reliable (including additional fix not in r53633) [Bug #12007]
-
-Sun Jan 24 16:54:11 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/io/wait/wait.c (io_wait_readwrite): [EXPERIMENTAL] allow to
- wait for multiple modes, readable and writable, at once. the
- arguments may change in the future. [Feature #12013]
-
-Sat Jan 23 22:30:59 2016 K0mA <mctj1218@gmail.com>
-
- * test/ruby/test_array.rb (test_keep_if): Add test for
- Array#keep_if separate from Array#select! [Fix GH-1218]
-
-Sat Jan 23 20:54:26 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * common.mk: revert r53633. It broke rubyci and travis.
- https://travis-ci.org/ruby/ruby/builds/104259623
-
-Sat Jan 23 20:10:29 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * range.c (range_eqq): revert r51585 because rb_call_super() is
- called in range_include() and thus r51585 doesn't work when the
- receiver Range object consists of non linear objects such as Date
- objects.
- [ruby-core:72908] [Bug #12003]
-
-Sat Jan 23 18:37:37 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * ChangeLog: Fixing wrong time on previous commit, and adding
- previous commit message to svn [ci skip]
-
-Sat Jan 23 18:30:30 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * common.mk: Simplifying Unicode data file download logic to make
- it more reliable [Bug #12007]
-
-Sat Jan 23 16:29:42 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * tool/downloader.rb: Fixed a logical error, improved documentation
-
-Sat Jan 23 11:42:43 2016 Peter Suschlik <ps@neopoly.de>
-
- * README.md: Use SVG Travis badge over PNG for better quality and
- device support. [Fix GH-1214] [Fix GH-1216]
-
-Sat Jan 23 11:29:16 2016 Pascal Betz <pascal.betz@simplificator.com>
-
- * lib/csv.rb: Update documentation of CSV header converter for
- r45498, [GH-575]. [Fix GH-1215]
-
-Fri Jan 22 17:36:46 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * vm_core.h (VM_ASSERT): use RUBY_ASSERT instead of rb_bug.
-
- * error.c (rb_assert_failure): assertion with stack dump.
-
- * ruby_assert.h (RUBY_ASSERT): new header for the assertion.
-
-Fri Jan 22 00:25:57 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * regparse.c (fetch_name_with_level): allow non word characters
- at the first character. [Feature #11949]
-
- * regparse.c (fetch_name): ditto.
-
-Thu Jan 21 17:34:01 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * marshal.c (r_object0): honor Marshal.load post proc
- value for TYPE_LINK. by Hiroshi Nakamura <nahi@ruby-lang.org>
- https://github.com/ruby/ruby/pull/1204 fix GH-1204
-
-Thu Jan 21 16:37:50 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * Makefile.in (update-rubyspec): fix r53208 like r53451.
-
-Wed Jan 20 20:58:25 2016 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * common.mk, Makefile.in: update-config_files is only for Unix
- platforms.
-
-Wed Jan 20 17:13:39 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/extlibs.rb: add --cache option to change cache directory.
-
-Tue Jan 19 17:03:40 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * common.mk: Added Unicode data file CaseFolding.txt to be additionally
- downloaded (with Kimihito Matsui)
-
-Tue Jan 19 10:09:58 2016 Sho Hashimoto <sho-h@ruby-lang.org>
-
- * lib/shell.rb (Shell.debug_output_exclusive_unlock): remove
- because Mutex#exclusive_unlock was already deleted. [fix GH-1185]
-
-Tue Jan 19 09:38:27 2016 Nick Cox <nick@nickcox.me>
-
- * vm_method.c: fix grammar in respond_to? warning.
- [fix GH-1047]
-
-Mon Jan 18 14:37:07 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_here_document): an escaped newline is not an
- actual newline, and the rest part should not be dedented.
- [ruby-core:72855] [Bug #11989]
-
-Mon Jan 18 12:04:34 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * test/ruby/test_string.rb: Added extra testcase for test_rstrip_bang
- and test_lstrip_bang. [fix GH-1178] Patch by @Matrixbirds
-
-Mon Jan 18 11:47:27 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * string.c: fix a typo. [fix GH-1202][ci skip] Patch by @sunboshan
-
-Sun Jan 17 21:15:30 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * configure.in: improve ICC (Intel C Compiler) support.
-
- * configure.in (CXX): The name of icc's c++ compiler is `icpc`.
-
- * configure.in (warnings): Add `-diag-disable=2259` to suppress
- noisy warnings: "non-pointer conversion from "..." to "..." may
- lose significant bits".
-
- * configure.in (optflags): Add `-fp-model precise` like -fno-fast-math.
-
- * lib/mkmf.rb: icc supports -Werror=division-by-zero
- and -Werror=deprecated-declarations, but doesn't support
- -Wdivision-by-zero and -Wdeprecated-declarations.
-
-Sun Jan 17 20:40:10 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: Any kind of option is now taking the new code path for
- upcase/downcase/capitalize/swapcase. :lithuanian can be used for
- testing if no specific option is desired.
- * test/ruby/enc/test_case_mapping.rb: Adjusted to above.
- (with Kimihito Matsui)
-
-Sun Jan 17 20:10:10 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Fixed a logical error and some comments.
- * test/ruby/enc/test_case_mapping.rb: Made tests more general.
- (with Kimihito Matsui)
-
-Sun Jan 17 17:41:41 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Removed artificial expansion for Turkic,
- added hand-coded support for Turkic, fixed logic for swapcase.
- * string.c: Made use of new case mapping code possible from upcase,
- capitalize, and swapcase (with :lithuanian as a guard).
- * test/ruby/enc/test_case_mapping.rb: Adjusted for above.
- (with Kimihito Matsui)
-
-Sun Jan 17 15:30:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/socket/option.c (sockopt_bool): relax boolean size to be one
- too not only sizeof(int). Winsock getsockopt() returns a single
- byte as a boolean socket option. [ruby-core:72730] [Bug #11958]
-
-Sun Jan 17 14:43:01 2016 Kuniaki IGARASHI <igaiga@gmail.com>
-
- * test/ruby/test_env.rb: [Fix GH-1201]
- * Extract test code for ENV#keep_if from ENV#select_bang
- * Add a test case for ENV#select_bang,keep_if
-
-Sun Jan 17 14:42:25 2016 Kuniaki IGARASHI <igaiga@gmail.com>
-
- * test/ruby/test_env.rb: [Fix GH-1201]
- * Extract test code for ENV#delete_if from ENV#reject_bang
- * Add a test case for ENV#reject_bang,delete_if
-
-Sun Jan 17 14:40:22 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ext/socket/option.c (check_size): extract a macro to check
- binary data size, with a consistent message.
-
- * ext/socket/option.c (sockopt_byte): fix error message,
- sizeof(int) differs from sizeof(unsigned char) in general.
-
-Sat Jan 16 21:16:21 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (xstring): reset heredoc indent after dedenting,
- so that following string literal would not be dedented.
- [ruby-core:72857] [Bug #11990]
-
-Sat Jan 16 17:24:24 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * enc/unicode.c: Artificial mapping to test buffer expansion code.
- * string.c: Fixed buffer expansion logic.
- * test/ruby/enc/test_case_mapping.rb: Tests for above.
- (with Kimihito Matsui)
-
-Sat Jan 16 16:47:14 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * ext/openssl/lib/openssl/pkey.rb: Added 2048 bit DH parameter.
- * test/openssl/test_pkey_dh.rb: ditto.
-
-Sat Jan 16 10:51:19 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * enc/unicode.c: fix implicit conversion error with clang. fixup r53548.
- * string.c: ditto.
-
-Sat Jan 16 10:31:00 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * common.mk: test-sample was changed to test-basic.
- [Feature #11982][ruby-core:72823]
- * basictest/runner.rb: ditto. rename from tool/rubytest.rb.
- * basictest/test.rb: ditto. rename from sample/test.rb.
- * defs/gmake.mk: picked from r53540
- * sample/test.rb: backward compatibility for chkbuild.
-
-Sat Jan 16 10:23:23 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c, enc/unicode.c: New code path as a preparation for Unicode-wide
- case mapping. The code path is currently guarded by the :lithuanian
- option to avoid accidental problems in daily use.
- * test/ruby/enc/test_case_mapping.rb: Test for above.
- * string.c: function 'check_case_options': fixed logical errors
- (with Kimihito Matsui)
-
-Fri Jan 15 20:20:20 2016 Naohisa Goto <ngotogenome@gmail.com>
-
- * regint.h (PLATFORM_UNALIGNED_WORD_ACCESS): The value of
- UNALIGNED_WORD_ACCESS should be used to determine whether
- unaligned word access is allowed or not. After this commit,
- ./configure CPPFLAGS="-DUNALIGNED_WORD_ACCESS=0" disables
- unaligned word access even on platforms that support the feature.
-
-Fri Jan 15 16:12:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (string1): reset heredoc indent for each string literal
- so that concatenated string would not be dedented.
- [ruby-core:72857] [Bug #11990]
-
-Thu Jan 14 20:01:00 2016 NARUSE, Yui <naruse@ruby-lang.org>
-
- * lib/uri/generic.rb (URI::Generic#to_s): change encoding to
- UTF-8 as Ruby 2.2/ by Koichi ITO <koic.ito@gmail.com>
- https://github.com/ruby/ruby/pull/1188 fix GH-1188
-
-Thu Jan 14 17:36:16 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * variable.c (rb_f_global_variables): add matched back references
- only, as well as defined? operator.
-
-Thu Jan 14 16:12:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * sprintf.c (rb_str_format): format exact number more exactly.
-
-Thu Jan 14 15:08:43 2016 Tony Arcieri <bascule@gmail.com>
-
- * Remove 512-bit DH group. It's affected by LogJam Attack.
- https://weakdh.org/
- [fix GH-1196][Bug #11968][ruby-core:72766]
-
-Thu Jan 14 11:44:29 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * variable.c (rb_f_global_variables): add $1..$9 only if $~ is
- set. fix the condition removed at r14014.
-
-Wed Jan 13 17:21:45 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * .travis.yml: removed commented-out code.
-
-Wed Jan 13 17:14:54 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * .travis.yml: removed osx code. follow up with r53517
-
-Wed Jan 13 16:56:19 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * iseq.c (rb_iseq_mark): mark parent iseq to prevent dynamically
- generated iseq by eval from GC. [ruby-core:72620] [Bug #11928]
-
-Wed Jan 13 03:42:58 2016 Eric Wong <e@80x24.org>
-
- * class.c (Init_class_hierarchy): resolve name for rb_cObject ASAP
- * object.c (rb_mod_const_set): move name resolution to rb_const_set
- * variable.c (rb_const_set): do class resolution here
- [ruby-core:72807] [Bug #11977]
-
-Wed Jan 13 00:37:12 2016 Satoshi Ohmori <sachin21dev@gmail.com>
-
- * man/ruby.1: fix double word typo. [Fix GH-1194]
-
-Tue Jan 12 21:01:09 2016 Benoit Daloze <eregontp@gmail.com>
-
- * common.mk: update URL and name for the Ruby spec suite.
-
-Tue Jan 12 19:52:19 2016 sorah (Shota Fukumori) <her@sorah.jp>
-
- * lib/forwardable.rb: Convert given accessors to String.
-
- r53381 changed to accept only Symbol or String for accessors, but
- there are several rubygems that pass classes (e.g. Array,
- Hash, ...) as accessors. Prior r53381, it was accepted because Class#to_s
- returns its class name. After r53381 given accessors are checked
- with define_method, but it accepts only Symbol or String, otherwise
- raises TypeError.
-
- def_delegator Foo, :some_method
-
- This change is to revert unexpected incompatibility. But this behavior
- may change in the future.
-
-Mon Jan 12 18:41:41 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: made a variable name more grammatically correct
-
-Mon Jan 12 18:34:34 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: minor grammar fix [ci skip]
-
-Mon Jan 12 16:09:09 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * test/ruby/enc/test_casing_options.rb: Tests for option
- parsing/checking for upcase/downcase/capitalize/swapcase
- (see r53503; with Kimihito Matsui)
-
-Mon Jan 12 16:03:03 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * string.c: Added option parsing/checking for upcase/downcase/
- capitalize/swapcase (with Kimihito Matsui)
-
-Mon Jan 11 21:28:28 2016 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * include/ruby/oniguruma.h: Added flags needed for upcase/downcase
- Unicode addition (with Kimihito Matsui)
-
-Mon Jan 11 09:50:24 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: check if the API version number is consistent with
- the program version number.
-
-Sun Jan 10 20:57:25 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (compile_massign_lhs): when index ends with splat,
- append rhs value to it like POSTARG, since VM_CALL_ARGS_SPLAT
- splats the last argument only. [ruby-core:72777] [Bug #11970]
-
-Sun Jan 10 15:45:10 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/missing.h (explicit_bzero_by_memset_s): remove
- inline implementation by memset_s, which needs a macro before
- including headers and can cause problems in extension libraries
- by the order of the macro and headers.
-
-Sun Jan 10 13:41:36 2016 Eric Wong <e@80x24.org>
-
- * io.c (rb_deferr): remove long obsolete global
-
-Sun Jan 10 09:14:42 2016 Eric Wong <e@80x24.org>
-
- * ext/psych/lib/psych/visitors/yaml_tree.rb (visit_String):
- eliminate chomp
- * lib/net/http.rb (connect): eliminate delete
- * lib/net/http/header.rb (basic_encode): ditto
- * lib/net/imap.rb (authenticate): eliminate gsub
- (self.encode_utf7): shorten delete arg
- * lib/net/smtp.rb (base64_encode): eliminate gsub
- * lib/open-uri.rb (OpenURI.open_http): eliminate delete
- * lib/rss/rss.rb: ditto
- * lib/securerandom.rb (base64): ditto
- (urlsafe_base64): eliminate delete!
- * lib/webrick/httpauth/digestauth.rb (split_param_value):
- eliminate chop
- * lib/webrick/httpproxy.rb (do_CONNECT): eliminate delete
- (setup_upstream_proxy_authentication): ditto
- [ruby-core:72666] [Feature #11938]
-
-Sat Jan 9 23:19:14 2016 Kuniaki IGARASHI <igaiga@gmail.com>
-
- * test/ruby/test_hash.rb (test_try_convert): Add test for
- Hash.try_convert. [Fix GH-1190]
-
-Sat Jan 9 23:15:25 2016 Jon Moss <maclover7@users.noreply.github.com>
-
- * ext/openssl/ossl.c: Add missing variables to documentation
- examples. [Fix GH-1189]
-
-Sat Jan 9 18:25:57 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * symbol.h (is_attrset_id): ASET is an attrset ID. fix
- unexpected safe call instead of an ordinary ASET.
-
-Sat Jan 9 10:44:33 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in, win32/setup.mak: extract RUBY_PROGRAM_VERSION from
- RUBY_VERSION in version.h instead of RUBY_API_VERSION numbers in
- include/ruby/version.h, and cut it into version numbers.
-
-Sat Jan 9 07:13:33 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename PAGE_* to HEAP_PAGE_* because PAGE_SIZE is used
- in Mac OS X.
-
- * test/ruby/test_gc.rb: catch up this fix.
-
-Sat Jan 9 05:45:40 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: PAGE_BITMAP_PLANES (the number of bitmap) is 4, not 3.
-
-Sat Jan 9 05:42:57 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename constant names HEAP_* to PAGE_*.
-
- Keys of GC::INTERNAL_CONSTANTS are also renamed.
-
- * test/ruby/test_gc.rb: catch up this fix.
-
-Fri Jan 8 22:30:06 2016 Akinori MUSHA <knu@iDaemons.org>
-
- * doc/regexp.rdoc: [DOC] Elaborate on the \G anchor. [ci skip]
-
-Fri Jan 8 19:49:27 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: remove heap_page::body. Instead of this field,
- heap_page::start field works well.
-
-Fri Jan 8 19:31:52 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: rename rb_heap_t::page_length to rb_heap_t::total_pages.
-
- `page_length' is not clear (we may understand with length of
- a page).
-
-Fri Jan 8 17:07:14 2016 Koichi Sasada <ko1@atdot.net>
-
- * gc.c: remove heap_page::heap. This field is only used to recognize
- whether a page is in a tomb or not. Instead of this field,
- heap_page::flags::in_tomb (1 bit field) is added.
-
- Also type of heap_page::(total|free|final)_slots are changed from
- int to short. 2B is enough for them.
-
-Fri Jan 8 09:33:59 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * iseq.c (rb_iseq_compile_with_option): move variable initialization
- code to avoid maybe-uninitialized warnings by gcc 4.8.
-
-Fri Jan 8 00:03:22 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * enum.c (enum_min, enum_max): do the same optimization as r53454.
-
-Thu Jan 7 22:32:21 2016 Kenta Murata <mrkn@mrkn.jp>
-
- * ruby.h: undef HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR_CONSTANT_P
- and HAVE_BUILTIN___BUILTIN_TYPES_COMPATIBLE_P on C++.
- [ruby-core:72736] [Bug #11962]
-
-Thu Jan 7 22:02:21 2016 Shugo Maeda <shugo@ruby-lang.org>
-
- * enum.c (enum_minmax): optimize object comparison in
- Enumerable#minmax.
-
-Thu Jan 7 14:49:12 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * thread.c (rb_thread_pending_interrupt_p): no pending interrupt
- before initialization.
-
- * thread.c (thread_raise_m, rb_thread_kill): uninitialized thread
- cannot interrupt. [ruby-core:72732] [Bug #11959]
-
-Thu Jan 7 11:34:14 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * include/ruby/backward.h (ruby_show_copyright_to_die): for source
- code backward compatibility.
-
- * ruby.c (process_options): return Qtrue to exit the process
- successfully.
-
- * version.c (ruby_show_copyright): no longer exit.
-
-Wed Jan 6 17:22:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/optparse.rb (OptionParser#order!): add `into` optional
- keyword argument to store the results. [Feature #11191]
-
-Tue Jan 5 21:44:37 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * ChangeLog: fix wrong class name.
-
-Tue Jan 5 21:43:50 2016 Kuniaki IGARASHI <igaiga@gmail.com>
-
- * test/ruby/test_string.rb(test_chr): added test for String#chr
- [fix GH-1179]
-
-Tue Jan 5 21:32:26 2016 Kuniaki IGARASHI <igaiga@gmail.com>
-
- * test/ruby/test_numeric.rb (test_nonzero_p): added test for Numeric#nonzero?
- [fix GH-1187]
-
-Tue Jan 5 11:47:23 2016 Damir Gaynetdinov <damir.gaynetdinov@gmail.com>
-
- * doc/marshal.rdoc: Clarify object references example, that the
- reference is same object. [Fix GH-1156]
-
-Tue Jan 5 05:06:51 2016 Eric Wong <e@80x24.org>
-
- * ext/stringio/stringio.c (strio_binmode): implement to set encoding
- * test/stringio/test_stringio.rb (test_binmode): new test
- [ruby-core:72699] [Bug #11945]
-
-Mon Jan 4 15:44:37 2016 Sho Hashimoto <sho-h@ruby-lang.org>
-
- * variable.c (rb_mod_deprecate_constant): [DOC] added
- documentation for Module#deprecate_constant. [ci skip]
-
-Mon Jan 4 15:36:38 2016 Sho Hashimoto <sho-h@ruby-lang.org>
-
- * thread_sync.c: [DOC] remove SizedQueue#close argument.
- [ci skip]
-
-Mon Jan 4 10:14:24 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * test/coverage/test_coverage.rb: ignored test when enabled to coverage.
- It lead to crash with `make test-all`.
-
-Mon Jan 4 08:10:44 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * insns.def (opt_case_dispatch): Move a comment to the
- appropriate position.
- [ci skip]
-
-Sun Jan 3 23:55:13 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/rubygems/security.rb (DIGEST_ALGORITHM, KEY_ALGORITHM):
- should check same name as the used constants.
- [ruby-core:72674] [Bug #11940]
-
-Sun Jan 3 19:22:01 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * aclocal.m4: add fallback file for non-aclocal environments.
- [ruby-core:72683] [Bug #11942]
-
-Sun Jan 3 13:56:49 2016 Yuichiro Kaneko <yui-knk@ruby-lang.org>
-
- * eval_error.c (rb_print_undef): Use `rb_method_visibility_t`
- instead of `int`.
- * eval_intern.h (rb_print_undef): ditto
- * proc.c (mnew_internal): ditto
- * vm_method.c (rb_export_method): ditto
- [Misc #11649] [ruby-core:71311] [fix GH-1078]
-
-Sun Jan 3 12:12:09 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * acinclude.m4: rename aclocal.m4, which should be generated by
- aclocal. [ruby-core:72675] [Bug #11941]
-
-Sat Jan 2 21:07:55 2016 Eric Wong <e@80x24.org>
-
- * thread_sync.c (queue_do_pop): avoid cast with Qfalse
- (rb_szqueue_push): ditto, use queue_sleep wrapper
-
-Sat Jan 2 16:16:14 2016 Masatoshi SEKI <m_seki@mva.biglobe.ne.jp>
-
- * lib/erb.rb: Allow ERB subclass to add token easily.
- [Feature #11936]
-
- * test/erb/test_erb.rb: ditto.
-
-Sat Jan 2 14:44:31 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (regexp): set_yylval_num sets u1, should use nd_tag
- instead of nd_state. [ruby-core:72638] [Bug #11932]
-
-Sat Jan 2 02:27:22 2016 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/ostruct.rb: Fix case of frozen object with initializer.
- Bug revealed by RubySpec [ruby-core:72639]
-
-Fri Jan 1 22:01:52 2016 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
-
- * NEWS: mention CSV's liberal_parsing option.
-
-Fri Jan 1 19:38:23 2016 okkez <okkez000@gmail.com>
-
- * doc/NEWS-2.3.0: fix double words typo.
- [ci skip][fix GH-1183]
-
-Fri Jan 1 15:28:56 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (remove_unreachable_chunk): decrease count of
- call_info in removed instructions. fix up r53402.
-
-Fri Jan 1 12:05:53 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * compile.c (remove_unreachable_chunk): remove unreferred label
- to optimize away unreachable chunk.
-
-Fri Jan 1 11:42:57 2016 James Edward Gray II <james@graysoftinc.com>
-
- * lib/csv.rb (CSV): Add a liberal_parsing option.
- Patch by Braden Anderson. [#11839]
- * test/csv/test_features.rb: test liberal_parsing
-
-Fri Jan 1 10:27:28 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * tool/mkconfig.rb (RbConfig): prefix SDKROOT to oldincludedir
- not includedir, the latter is outside the ruby installation.
- [ruby-core:72496] [Bug #11881]
-
-Fri Jan 1 08:53:02 2016 Yuki Kurihara <co000ri@gmail.com>
-
- * test/ruby/test_lazy_enumerator.rb (test_take_bad_arg): Add test
- code in case of Enumerator::Lazy#take called with negative number.
- [ruby-dev:49467] [Bug #11933]
-
-Fri Jan 1 05:06:20 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (parser_here_document): update indent for each line in
- indented here document with single-quotes.
- [ruby-core:72479] [Bug #11871]
-
-Fri Jan 1 03:26:44 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/ostruct.rb (freeze): define deferred accessors before
- freezing to get rid of an error when just reading frozen
- OpenStruct.
-
-Thu Dec 31 14:36:45 2015 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
-
- * lib/ostruct.rb: Fix new_ostruct_member to correctly avoid
- redefinition [#11901]
-
-Thu Dec 31 02:45:12 2015 NARUSE, Yui <naruse@ruby-lang.org>
-
- * test/ruby/test_module.rb (test_classpath): r53376 may change
- the order of m.constants.
- `make TESTS='-v ruby/test_class.rb ruby/test_module.rb' test-all`
- may fail after that.
- http://rubyci.s3.amazonaws.com/tk2-243-31075/ruby-trunk/log/20151230T164202Z.log.html.gz
-
-Thu Dec 31 02:20:00 2015 Benoit Daloze <eregontp@gmail.com>
-
- * common.mk (help): Fix typo.
-
-Wed Dec 30 20:53:09 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/net/http/responses.rb: Added new response class for 451 status code.
- * lib/net/http.rb: documentation for HTTPUnavailableForLegalReasons
-
-Wed Dec 30 20:45:45 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * lib/webrick/httpstatus.rb: Added HTTP 451 Status Code.
- [fix GH-1167] Patch by @MuhammetDilmac
- https://tools.ietf.org/html/draft-tbray-http-legally-restricted-status-00
-
-Wed Dec 30 20:25:52 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * doc/syntax/calling_methods.rdoc: fix old operator for safe navigation
- operator. [ci skip][fix GH-1182] Patch by @dougo
-
-Wed Dec 30 16:43:23 2015 Kuniaki IGARASHI <igaiga@gmail.com>
-
- * test/ruby/test_string.rb (test_ord): Add test for String#ord.
- [Fix GH-1181]
-
-Wed Dec 30 11:28:57 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/forwardable.rb (def_instance_delegator): adjust backtrace of
- method body by tail call optimization. adjusting the delegated
- target is still done by deleting backtrace.
-
- * lib/forwardable.rb (def_single_delegator): ditto.
-
-Wed Dec 30 11:18:42 2015 Elliot Winkler <elliot.winkler@gmail.com>
-
- * lib/forwardable.rb (def_instance_delegator) fix delegating to
- 'args' and 'block', clashing with local variables in generated
- methods. [ruby-core:72579] [Bug #11916]
-
- * lib/forwardable.rb (def_single_delegator): ditto.
-
-Wed Dec 30 09:58:56 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * object.c (rb_class_inherited_p): search the corresponding
- ancestor to prepended module from prepending class itself.
- [ruby-core:72493] [Bug #11878]
-
-Wed Dec 30 09:20:00 2015 Yuki Kurihara <co000ri@gmail.com>
-
- * test/stringio/test_io.rb (test_flag): add assertion for error when
- text and binary mode are mixed.
- [ruby-dev:49465] [Feature #11921]
-
-Wed Dec 30 08:43:59 2015 Yuki Kurihara <co000ri@gmail.com>
-
- * test/stringio/test_stringio.rb (test_initialize): add test for
- StringIO#initialize. [ruby-core:72585] [Feature #11920]
-
-Wed Dec 30 05:19:24 2015 Eric Wong <e@80x24.org>
-
- * class.c (struct clone_const_arg): adjust for id_table
- (clone_const): ditto
- (clone_const_i): ditto
- (rb_mod_init_copy): ditto
- (rb_singleton_class_clone_and_attach): ditto
- (rb_include_class_new): ditto
- (include_modules_at): ditto
- * constant.h (rb_free_const_table): ditto
- * gc.c (free_const_entry_i): ditto
- (rb_free_const_table): ditto
- (obj_memsize_of): ditto
- (mark_const_entry_i): ditto
- (mark_const_tbl): ditto
- * internal.h (struct rb_classext_struct): ditto
- * object.c (rb_mod_const_set): resolve class name on assignment
- * variable.c (const_update): replace with const_tbl_update
- (const_tbl_update): new function
- (fc_i): adjust for id_table
- (find_class_path): ditto
- (autoload_const_set): st_update => const_tbl_update
- (rb_const_remove): adjust for id_table
- (sv_i): ditto
- (rb_local_constants_i): ditto
- (rb_local_constants): ditto
- (rb_mod_const_at): ditto
- (rb_mod_const_set): ditto
- (rb_const_lookup): ditto
- [ruby-core:72112] [Feature #11614]
-
-Wed Dec 30 04:10:13 2015 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
-
- * thread_pthread.c (rb_thread_create_timer_thread): destroy attr even
- if pthread_create() failed.
-
-Wed Dec 30 02:55:09 2015 Eric Wong <e@80x24.org>
-
- * thread_pthread.c (setup_communication_pipe): delay setting owner
- (rb_thread_create_timer_thread): until thread creation succeeds
- [ruby-core:72590] [Bug #11922]
-
-Tue Dec 29 19:12:46 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * ruby.c (proc_options): -W command line option should be able to
- override -w in RUBYOPT environment variable.
-
-Tue Dec 29 17:54:16 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * eval.c (ignored_block): warn if a block is given to `using`,
- which is probably for `Module.new`.
-
-Tue Dec 29 12:48:34 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * lib/ostruct.rb (OpenStruct): make respond_to? working on
- just-allocated objects for workaround of Psych.
- [ruby-core:72501] [Bug #11884]
-
-Tue Dec 29 10:35:00 2015 Kenta Murata <mrkn@mrkn.jp>
-
- * test/mkmf/test_have_func.rb (test_have_func):
- Add assertion to examine the existence of HAVE_RUBY_INIT.
-
- * test/mkmf/test_have_func.rb (test_not_have_func):
- Add assertion to examine the absence of HAVE_RUBY_INIT.
-
-Tue Dec 29 06:50:42 2015 Eric Wong <e@80x24.org>
-
- * thread_sync.c: static classes
-
-Tue Dec 29 05:30:30 2015 Eric Wong <e@80x24.org>
-
- * lib/resolv.rb (Resolv::IPv6.create): avoid modifying frozen
- * test/resolv/test_dns.rb (test_ipv6_create): test for above
- [Bug #11910] [ruby-core:72559]
-
-Mon Dec 28 14:55:57 2015 Kuniaki IGARASHI <igaiga@gmail.com>
-
- * test/ruby/test_string.rb (TestString#test_rstrip_bang): Add test
- for String#rstrip!. [Fix GH-1176]
-
-Mon Dec 28 09:18:53 2015 Kuniaki IGARASHI <igaiga@gmail.com>
-
- * test/ruby/test_string.rb (TestString#test_lstrip_bang): Add test
- for String#lstrip!. [Fix GH-1176]
-
-Sun Dec 27 23:32:26 2015 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (ole_variant2val): refactoring.
-
-Sun Dec 27 21:14:42 2015 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * process.c (rb_execarg_parent_start1): need to convert the encoding to
- ospath's one.
-
-Sun Dec 27 20:54:22 2015 NAKAMURA Usaku <usa@ruby-lang.org>
-
- * process.c: use rb_w32_uchdir() instead of plain chdir() on Windows.
- reported by naruse via twitter.
-
- * process.c (rb_execarg_addopt): need to convert the encoding to
- ospath's one.
-
-Sun Dec 27 20:00:31 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * enc/x_emoji.h: fix dead-link.
-
-Sun Dec 27 19:55:55 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
-
- * doc/NEWS-2.3.0: fix a typo.
-
-Sun Dec 27 18:08:15 2015 Kuniaki IGARASHI <igaiga@gmail.com>
-
- * string.c (rb_str_lstrip_bang, rb_str_rstrip_bang): [DOC] Fix
- ruby-doc comments for String#rstrip! and lstrip!. It looks like
- dropped bang. [Fix GH-1175]
-
-Sun Dec 27 15:14:20 2015 Eric Wong <e@80x24.org>
-
- * io.c (io_getpartial): remove unused kwarg from template
- * test/ruby/test_io.rb (test_readpartial_bad_args): new
- [Bug #11885]
-
-Sun Dec 27 11:50:53 2015 Kuniaki IGARASHI <igaiga@gmail.com>
-
- * test/ruby/test_string.rb (test_rstrip, test_lstrip): Add tests
- for String#lstrip and rstrip. The test cases are used from
- string.c ruby-doc comments. [Fix GH-1174]
-
-Sun Dec 27 11:47:46 2015 Kuniaki IGARASHI <igaiga@gmail.com>
-
- * test/ruby/test_string.rb (test_insert): Add test for
- String#insert. The test cases are written in string.c
- comments as a reference. [Fix GH-1173]
-
-Sun Dec 27 11:03:33 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * parse.y (show_bitstack): trace stack_type value if yydebug.
-
-Sun Dec 27 10:03:14 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * enc/depend (enc, trans): fix version dependency, shared object
- files depend on the RUBY_SO_NAME value for runtime link.
-
-Sun Dec 27 09:47:20 2015 Masaki Suketa <masaki.suketa@nifty.ne.jp>
-
- * ext/win32ole/win32ole.c (ole_vstr2wc, ole_variant2val): fix blank
- string conversion.
- [Bug #11880]
- Thanks Akio Tajima for the patch!
-
-Sun Dec 27 09:34:53 2015 craft4coder <yooobuntu@163.com>
-
- * doc/extension.rdoc: [DOC] `nul` should be uppercase.
- change 'nul' => 'NUL'. [Fix GH-1172]
-
-Sat Dec 26 18:29:01 2015 Kouhei Sutou <kou@cozmixng.org>
-
- * lib/xmlrpc/client.rb: Support SSL options in async methods of
- XMLRPC::Client.
- [Bug #11489]
- Reported by Aleksandar Kostadinov. Thanks!!!
-
-Sat Dec 26 11:26:38 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * miniinit.c (Init_enc): add some common aliases of built-in
- encodings. [ruby-core:72481] [Bug #11872]
-
-Fri Dec 25 22:43:26 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
-
- * configure.in: extract RUBY_RELEASE_DAY at generating Makefile.
-
- * version.h (RUBY_RELEASE_DATE): construct from RUBY_RELEASE_YEAR,
- RUBY_RELEASE_MONTH, and RUBY_RELEASE_DAY.
-
-Fri Dec 25 21:33:06 2015 Yukihiro Matsumoto <matz@ruby-lang.org>
-
- * version.h (RUBY_VERSION): 2.4.0 development has started.
-
-Fri Dec 25 14:12:12 2015 Martin Duerst <duerst@it.aoyama.ac.jp>
-
- * doc/ChangeLog-2.3.0, ext/tk/lib/tkextlib/SUPPORT_STATUS,
- include/ruby/version.h: minor grammar fixes [ci skip]
-
-Fri Dec 25 08:23:22 2015 Tadashi Saito <tad.a.digger@gmail.com>
-
- * compile.c, cont.c, doc, man: fix common misspelling.
- [ruby-core:72466] [Bug #11870]
-
-
-For the changes before 2.3.0, see doc/ChangeLog-2.3.0
-For the changes before 2.2.0, see doc/ChangeLog-2.2.0
-For the changes before 2.1.0, see doc/ChangeLog-2.1.0
-For the changes before 2.0.0, see doc/ChangeLog-2.0.0
-For the changes before 1.9.3, see doc/ChangeLog-1.9.3
-For the changes before 1.8.0, see doc/ChangeLog-1.8.0
-
-Local variables:
-coding: us-ascii
-add-log-time-format: (lambda (&optional x y)
- (let* ((time (or x (current-time)))
- (system-time-locale "C")
- (diff (+ (cadr time) 32400))
- (lo (% diff 65536))
- (hi (+ (car time) (/ diff 65536))))
- (format-time-string "%a %b %e %H:%M:%S %Y" (list hi lo) t)))
-indent-tabs-mode: t
-tab-width: 8
-change-log-indent-text: 2
-end:
-vim: tabstop=8 shiftwidth=2
diff --git a/doc/NEWS/NEWS-3.2.0.md b/doc/NEWS/NEWS-3.2.0.md
deleted file mode 100644
index 33a7b85c47..0000000000
--- a/doc/NEWS/NEWS-3.2.0.md
+++ /dev/null
@@ -1,820 +0,0 @@
-# NEWS for Ruby 3.2.0
-
-This document is a list of user-visible feature changes
-since the **3.1.0** release, except for bug fixes.
-
-Note that each entry is kept to a minimum, see links for details.
-
-## Language changes
-
-* Anonymous rest and keyword rest arguments can now be passed as
- arguments, instead of just used in method parameters.
- [[Feature #18351]]
-
- ```ruby
- def foo(*)
- bar(*)
- end
- def baz(**)
- quux(**)
- end
- ```
-
-* A proc that accepts a single positional argument and keywords will
- no longer autosplat. [[Bug #18633]]
-
- ```ruby
- proc{|a, **k| a}.call([1, 2])
- # Ruby 3.1 and before
- # => 1
- # Ruby 3.2 and after
- # => [1, 2]
- ```
-
-* Constant assignment evaluation order for constants set on explicit
- objects has been made consistent with single attribute assignment
- evaluation order. With this code:
-
- ```ruby
- foo::BAR = baz
- ```
-
- `foo` is now called before `baz`. Similarly, for multiple assignments
- to constants, left-to-right evaluation order is used. With this
- code:
-
- ```ruby
- foo1::BAR1, foo2::BAR2 = baz1, baz2
- ```
-
- The following evaluation order is now used:
-
- 1. `foo1`
- 2. `foo2`
- 3. `baz1`
- 4. `baz2`
-
- [[Bug #15928]]
-
-* "Find pattern" is no longer experimental.
- [[Feature #18585]]
-
-* Methods taking a rest parameter (like `*args`) and wishing to delegate keyword
- arguments through `foo(*args)` must now be marked with `ruby2_keywords`
- (if not already the case). In other words, all methods wishing to delegate
- keyword arguments through `*args` must now be marked with `ruby2_keywords`,
- with no exception. This will make it easier to transition to other ways of
- delegation once a library can require Ruby 3+. Previously, the `ruby2_keywords`
- flag was kept if the receiving method took `*args`, but this was a bug and an
- inconsistency. A good technique to find the potentially-missing `ruby2_keywords`
- is to run the test suite, for where it fails find the last method which must
- receive keyword arguments, use `puts nil, caller, nil` there, and check each
- method/block on the call chain which must delegate keywords is correctly marked
- as `ruby2_keywords`. [[Bug #18625]] [[Bug #16466]]
-
- ```ruby
- def target(**kw)
- end
-
- # Accidentally worked without ruby2_keywords in Ruby 2.7-3.1, ruby2_keywords
- # needed in 3.2+. Just like (*args, **kwargs) or (...) would be needed on
- # both #foo and #bar when migrating away from ruby2_keywords.
- ruby2_keywords def bar(*args)
- target(*args)
- end
-
- ruby2_keywords def foo(*args)
- bar(*args)
- end
-
- foo(k: 1)
- ```
-
-## Core classes updates
-
-Note: We're only listing outstanding class updates.
-
-* Fiber
-
- * Introduce Fiber.[] and Fiber.[]= for inheritable fiber storage.
- Introduce Fiber#storage and Fiber#storage= (experimental) for
- getting and resetting the current storage. Introduce
- `Fiber.new(storage:)` for setting the storage when creating a
- fiber. [[Feature #19078]]
-
- Existing Thread and Fiber local variables can be tricky to use.
- Thread-local variables are shared between all fibers, making it
- hard to isolate, while Fiber-local variables can be hard to
- share. It is often desirable to define unit of execution
- ("execution context") such that some state is shared between all
- fibers and threads created in that context. This is what Fiber
- storage provides.
-
- ```ruby
- def log(message)
- puts "#{Fiber[:request_id]}: #{message}"
- end
-
- def handle_requests
- while request = read_request
- Fiber.schedule do
- Fiber[:request_id] = SecureRandom.uuid
-
- request.messages.each do |message|
- Fiber.schedule do
- log("Handling #{message}") # Log includes inherited request_id.
- end
- end
- end
- end
- end
- ```
-
- You should generally consider Fiber storage for any state which
- you want to be shared implicitly between all fibers and threads
- created in a given context, e.g. a connection pool, a request
- id, a logger level, environment variables, configuration, etc.
-
-* Fiber::Scheduler
-
- * Introduce `Fiber::Scheduler#io_select` for non-blocking IO.select.
- [[Feature #19060]]
-
-* IO
-
- * Introduce IO#timeout= and IO#timeout which can cause
- IO::TimeoutError to be raised if a blocking operation exceeds the
- specified timeout. [[Feature #18630]]
-
- ```ruby
- STDIN.timeout = 1
- STDIN.read # => Blocking operation timed out! (IO::TimeoutError)
- ```
-
- * Introduce `IO.new(..., path:)` and promote `File#path` to `IO#path`.
- [[Feature #19036]]
-
-* Class
-
- * Class#attached_object, which returns the object for which
- the receiver is the singleton class. Raises TypeError if the
- receiver is not a singleton class.
- [[Feature #12084]]
-
- ```ruby
- class Foo; end
-
- Foo.singleton_class.attached_object #=> Foo
- Foo.new.singleton_class.attached_object #=> #<Foo:0x000000010491a370>
- Foo.attached_object #=> TypeError: `Foo' is not a singleton class
- nil.singleton_class.attached_object #=> TypeError: `NilClass' is not a singleton class
- ```
-
-* Data
-
- * New core class to represent simple immutable value object. The class is
- similar to Struct and partially shares an implementation, but has more
- lean and strict API. [[Feature #16122]]
-
- ```ruby
- Measure = Data.define(:amount, :unit)
- distance = Measure.new(100, 'km') #=> #<data Measure amount=100, unit="km">
- weight = Measure.new(amount: 50, unit: 'kg') #=> #<data Measure amount=50, unit="kg">
- weight.with(amount: 40) #=> #<data Measure amount=40, unit="kg">
- weight.amount #=> 50
- weight.amount = 40 #=> NoMethodError: undefined method `amount='
- ```
-
-* Encoding
-
- * Encoding#replicate has been deprecated and will be removed in 3.3. [[Feature #18949]]
- * The dummy `Encoding::UTF_16` and `Encoding::UTF_32` encodings no longer
- try to dynamically guess the endian based on a byte order mark.
- Use `Encoding::UTF_16BE`/`UTF_16LE` and `Encoding::UTF_32BE`/`UTF_32LE` instead.
- This change speeds up getting the encoding of a String. [[Feature #18949]]
- * Limit maximum encoding set size by 256.
- If exceeding maximum size, `EncodingError` will be raised. [[Feature #18949]]
-
-* Enumerator
-
- * Enumerator.product has been added. Enumerator::Product is the implementation. [[Feature #18685]]
-
-* Exception
-
- * Exception#detailed_message has been added.
- The default error printer calls this method on the Exception object
- instead of #message. [[Feature #18564]]
-
-* Hash
-
- * Hash#shift now always returns nil if the hash is
- empty, instead of returning the default value or
- calling the default proc. [[Bug #16908]]
-
-* Integer
-
- * Integer#ceildiv has been added. [[Feature #18809]]
-
-* Kernel
-
- * Kernel#binding raises RuntimeError if called from a non-Ruby frame
- (such as a method defined in C). [[Bug #18487]]
-
-* MatchData
-
- * MatchData#byteoffset has been added. [[Feature #13110]]
- * MatchData#deconstruct has been added. [[Feature #18821]]
- * MatchData#deconstruct_keys has been added. [[Feature #18821]]
-
-* Module
-
- * Module.used_refinements has been added. [[Feature #14332]]
- * Module#refinements has been added. [[Feature #12737]]
- * Module#const_added has been added. [[Feature #17881]]
- * Module#undefined_instance_methods has been added. [[Feature #12655]]
-
-* Proc
-
- * Proc#dup returns an instance of subclass. [[Bug #17545]]
- * Proc#parameters now accepts lambda keyword. [[Feature #15357]]
-
-* Process
- * Added `RLIMIT_NPTS` constant to FreeBSD platform
-
-* Regexp
-
- * The cache-based optimization is introduced.
- Many (but not all) Regexp matching is now in linear time, which
- will prevent regular expression denial of service (ReDoS)
- vulnerability. [[Feature #19104]]
-
- * Regexp.linear_time? is introduced. [[Feature #19194]]
-
- * Regexp.new now supports passing the regexp flags not only as an Integer,
- but also as a String. Unknown flags raise ArgumentError.
- Otherwise, anything other than `true`, `false`, `nil` or Integer will be warned.
- [[Feature #18788]]
-
- * Regexp.timeout= has been added. Also, Regexp.new new supports timeout keyword.
- See [[Feature #17837]]
-
-* Refinement
-
- * Refinement#refined_class has been added. [[Feature #12737]]
-
-* RubyVM::AbstractSyntaxTree
-
- * Add `error_tolerant` option for `parse`, `parse_file` and `of`. [[Feature #19013]]
- With this option
-
- 1. SyntaxError is suppressed
- 2. AST is returned for invalid input
- 3. `end` is complemented when a parser reaches to the end of input but `end` is insufficient
- 4. `end` is treated as keyword based on indent
-
- ```ruby
- # Without error_tolerant option
- root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY)
- def m
- a = 10
- if
- end
- RUBY
- # => <internal:ast>:33:in `parse': syntax error, unexpected `end' (SyntaxError)
-
- # With error_tolerant option
- root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY, error_tolerant: true)
- def m
- a = 10
- if
- end
- RUBY
- p root # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-4:3>
-
- # `end` is treated as keyword based on indent
- root = RubyVM::AbstractSyntaxTree.parse(<<~RUBY, error_tolerant: true)
- module Z
- class Foo
- foo.
- end
-
- def bar
- end
- end
- RUBY
- p root.children[-1].children[-1].children[-1].children[-2..-1]
- # => [#<RubyVM::AbstractSyntaxTree::Node:CLASS@2:2-4:5>, #<RubyVM::AbstractSyntaxTree::Node:DEFN@6:2-7:5>]
- ```
-
- * Add `keep_tokens` option for `parse`, `parse_file` and `of`. Add `#tokens` and `#all_tokens`
- for RubyVM::AbstractSyntaxTree::Node [[Feature #19070]]
-
- ```ruby
- root = RubyVM::AbstractSyntaxTree.parse("x = 1 + 2", keep_tokens: true)
- root.tokens # => [[0, :tIDENTIFIER, "x", [1, 0, 1, 1]], [1, :tSP, " ", [1, 1, 1, 2]], ...]
- root.tokens.map{_1[2]}.join # => "x = 1 + 2"
- ```
-
-* Set
-
- * Set is now available as a built-in class without the need for `require "set"`. [[Feature #16989]]
- It is currently autoloaded via the Set constant or a call to Enumerable#to_set.
-
-* String
-
- * String#byteindex and String#byterindex have been added. [[Feature #13110]]
- * Update Unicode to Version 15.0.0 and Emoji Version 15.0. [[Feature #18639]]
- (also applies to Regexp)
- * String#bytesplice has been added. [[Feature #18598]]
- * String#dedup has been added as an alias to String#-@. [[Feature #18595]]
-
-* Struct
-
- * A Struct class can also be initialized with keyword arguments
- without `keyword_init: true` on Struct.new [[Feature #16806]]
-
- ```ruby
- Post = Struct.new(:id, :name)
- Post.new(1, "hello") #=> #<struct Post id=1, name="hello">
- # From Ruby 3.2, the following code also works without keyword_init: true.
- Post.new(id: 1, name: "hello") #=> #<struct Post id=1, name="hello">
- ```
-
-* Thread
-
- * Thread.each_caller_location is added. [[Feature #16663]]
-
-* Thread::Queue
-
- * Thread::Queue#pop(timeout: sec) is added. [[Feature #18774]]
-
-* Thread::SizedQueue
-
- * Thread::SizedQueue#pop(timeout: sec) is added. [[Feature #18774]]
- * Thread::SizedQueue#push(timeout: sec) is added. [[Feature #18944]]
-
-* Time
-
- * Time#deconstruct_keys is added, allowing to use Time instances
- in pattern-matching expressions [[Feature #19071]]
-
- * Time.new now can parse a string like generated by Time#inspect
- and return a Time instance based on the given argument.
- [[Feature #18033]]
-
-* SyntaxError
- * SyntaxError#path has been added. [[Feature #19138]]
-
-* TracePoint
-
- * TracePoint#binding now returns `nil` for `c_call`/`c_return` TracePoints.
- [[Bug #18487]]
- * TracePoint#enable `target_thread` keyword argument now defaults to the
- current thread if a block is given and `target` and `target_line` keyword
- arguments are not passed. [[Bug #16889]]
-
-* UnboundMethod
-
- * `UnboundMethod#==` returns `true` if the actual method is same. For example,
- `String.instance_method(:object_id) == Array.instance_method(:object_id)`
- returns `true`. [[Feature #18798]]
-
- * `UnboundMethod#inspect` does not show the receiver of `instance_method`.
- For example `String.instance_method(:object_id).inspect` returns
- `"#<UnboundMethod: Kernel#object_id()>"`
- (was `"#<UnboundMethod: String(Kernel)#object_id()>"`).
-
-* GC
-
- * Expose `need_major_gc` via `GC.latest_gc_info`. [GH-6791]
-
-* ObjectSpace
-
- * `ObjectSpace.dump_all` dump shapes as well. [GH-6868]
-
-## Stdlib updates
-
-* Bundler
-
- * Bundler now uses [PubGrub] resolver instead of [Molinillo] for performance improvement.
- * Add --ext=rust support to bundle gem for creating simple gems with Rust extensions.
- [[GH-rubygems-6149]]
- * Make cloning git repos faster [[GH-rubygems-4475]]
-
-* RubyGems
-
- * Add mswin support for cargo builder. [[GH-rubygems-6167]]
-
-* CGI
-
- * `CGI.escapeURIComponent` and `CGI.unescapeURIComponent` are added.
- [[Feature #18822]]
-
-* Coverage
-
- * `Coverage.setup` now accepts `eval: true`. By this, `eval` and related methods are
- able to generate code coverage. [[Feature #19008]]
-
- * `Coverage.supported?(mode)` enables detection of what coverage modes are
- supported. [[Feature #19026]]
-
-* Date
-
- * Added `Date#deconstruct_keys` and `DateTime#deconstruct_keys` same as [[Feature #19071]]
-
-* ERB
-
- * `ERB::Util.html_escape` is made faster than `CGI.escapeHTML`.
- * It no longer allocates a String object when no character needs to be escaped.
- * It skips calling `#to_s` method when an argument is already a String.
- * `ERB::Escape.html_escape` is added as an alias to `ERB::Util.html_escape`,
- which has not been monkey-patched by Rails.
- * `ERB::Util.url_encode` is made faster using `CGI.escapeURIComponent`.
- * `-S` option is removed from `erb` command.
-
-* FileUtils
-
- * Add FileUtils.ln_sr method and `relative:` option to FileUtils.ln_s.
- [[Feature #18925]]
-
-* IRB
-
- * debug.gem integration commands have been added: `debug`, `break`, `catch`,
- `next`, `delete`, `step`, `continue`, `finish`, `backtrace`, `info`
- * They work even if you don't have `gem "debug"` in your Gemfile.
- * See also: [What's new in Ruby 3.2's IRB?](https://st0012.dev/whats-new-in-ruby-3-2-irb)
- * More Pry-like commands and features have been added.
- * `edit` and `show_cmds` (like Pry's `help`) are added.
- * `ls` takes `-g` or `-G` option to filter out outputs.
- * `show_source` is aliased from `$` and accepts unquoted inputs.
- * `whereami` is aliased from `@`.
-
-* Net::Protocol
-
- * Improve `Net::BufferedIO` performance. [[GH-net-protocol-14]]
-
-* Pathname
-
- * Added `Pathname#lutime`. [[GH-pathname-20]]
-
-* Socket
-
- * Added the following constants for supported platforms.
- * `SO_INCOMING_CPU`
- * `SO_INCOMING_NAPI_ID`
- * `SO_RTABLE`
- * `SO_SETFIB`
- * `SO_USER_COOKIE`
- * `TCP_KEEPALIVE`
- * `TCP_CONNECTION_INFO`
-
-* SyntaxSuggest
-
- * The feature of `syntax_suggest` formerly `dead_end` is integrated in Ruby.
- [[Feature #18159]]
-
-* UNIXSocket
-
- * Add support for UNIXSocket on Windows. Emulate anonymous sockets. Add
- support for File.socket? and File::Stat#socket? where possible.
- [[Feature #19135]]
-
-* The following default gems are updated.
-
- * RubyGems 3.4.1
- * abbrev 0.1.1
- * benchmark 0.2.1
- * bigdecimal 3.1.3
- * bundler 2.4.1
- * cgi 0.3.6
- * csv 3.2.6
- * date 3.3.3
- * delegate 0.3.0
- * did_you_mean 1.6.3
- * digest 3.1.1
- * drb 2.1.1
- * english 0.7.2
- * erb 4.0.2
- * error_highlight 0.5.1
- * etc 1.4.2
- * fcntl 1.0.2
- * fiddle 1.1.1
- * fileutils 1.7.0
- * forwardable 1.3.3
- * getoptlong 0.2.0
- * io-console 0.6.0
- * io-nonblock 0.2.0
- * io-wait 0.3.0
- * ipaddr 1.2.5
- * irb 1.6.2
- * json 2.6.3
- * logger 1.5.3
- * mutex_m 0.1.2
- * net-http 0.3.2
- * net-protocol 0.2.1
- * nkf 0.1.2
- * open-uri 0.3.0
- * open3 0.1.2
- * openssl 3.1.0
- * optparse 0.3.1
- * ostruct 0.5.5
- * pathname 0.2.1
- * pp 0.4.0
- * pstore 0.1.2
- * psych 5.0.1
- * racc 1.6.2
- * rdoc 6.5.0
- * readline-ext 0.1.5
- * reline 0.3.2
- * resolv 0.2.2
- * resolv-replace 0.1.1
- * securerandom 0.2.2
- * set 1.0.3
- * stringio 3.0.4
- * strscan 3.0.5
- * syntax_suggest 1.0.2
- * syslog 0.1.1
- * tempfile 0.1.3
- * time 0.2.1
- * timeout 0.3.1
- * tmpdir 0.1.3
- * tsort 0.1.1
- * un 0.2.1
- * uri 0.12.0
- * weakref 0.1.2
- * win32ole 1.8.9
- * yaml 0.2.1
- * zlib 3.0.0
-
-* The following bundled gems are updated.
-
- * minitest 5.16.3
- * power_assert 2.0.3
- * test-unit 3.5.7
- * net-ftp 0.2.0
- * net-imap 0.3.4
- * net-pop 0.1.2
- * net-smtp 0.3.3
- * rbs 2.8.2
- * typeprof 0.21.3
- * debug 1.7.1
-
-See GitHub releases like [GitHub Releases of Logger](https://github.com/ruby/logger/releases) or changelog for details of the default gems or bundled gems.
-
-## Supported platforms
-
-* WebAssembly/WASI is added. See [wasm/README.md] and [ruby.wasm] for more details. [[Feature #18462]]
-
-## Compatibility issues
-
-* `String#to_c` currently treat a sequence of underscores as an end of Complex
- string. [[Bug #19087]]
-
-* Now `ENV.clone` raises `TypeError` as well as `ENV.dup` [[Bug #17767]]
-
-### Removed constants
-
-The following deprecated constants are removed.
-
-* `Fixnum` and `Bignum` [[Feature #12005]]
-* `Random::DEFAULT` [[Feature #17351]]
-* `Struct::Group`
-* `Struct::Passwd`
-
-### Removed methods
-
-The following deprecated methods are removed.
-
-* `Dir.exists?` [[Feature #17391]]
-* `File.exists?` [[Feature #17391]]
-* `Kernel#=~` [[Feature #15231]]
-* `Kernel#taint`, `Kernel#untaint`, `Kernel#tainted?`
- [[Feature #16131]]
-* `Kernel#trust`, `Kernel#untrust`, `Kernel#untrusted?`
- [[Feature #16131]]
-* `Method#public?`, `Method#private?`, `Method#protected?`,
- `UnboundMethod#public?`, `UnboundMethod#private?`, `UnboundMethod#protected?`
- [[Bug #18729]] [[Bug #18751]] [[Bug #18435]]
-
-### Source code incompatibility of extension libraries
-
-* Extension libraries provide PRNG, subclasses of Random, need updates.
- See [PRNG update] below for more information. [[Bug #19100]]
-
-### Error printer
-
-* Ruby no longer escapes control characters and backslashes in an
- error message. [[Feature #18367]]
-
-### Constant lookup when defining a class/module
-
-* When defining a class/module directly under the Object class by class/module
- statement, if there is already a class/module defined by `Module#include`
- with the same name, the statement was handled as "open class" in Ruby 3.1 or before.
- Since Ruby 3.2, a new class is defined instead. [[Feature #18832]]
-
-## Stdlib compatibility issues
-
-* Psych no longer bundles libyaml sources.
- And also Fiddle no longer bundles libffi sources.
- Users need to install the libyaml/libffi library themselves via the package
- manager like apt, yum, brew, etc.
-
- Psych and fiddle supported the static build with specific version of libyaml
- and libffi sources. You can build psych with libyaml-0.2.5 like this.
-
- ```bash
- $ ./configure --with-libyaml-source-dir=/path/to/libyaml-0.2.5
- ```
-
- And you can build fiddle with libffi-3.4.4 like this.
-
- ```bash
- $ ./configure --with-libffi-source-dir=/path/to/libffi-3.4.4
- ```
-
- [[Feature #18571]]
-
-* Check cookie name/path/domain characters in `CGI::Cookie`. [[CVE-2021-33621]]
-
-* `URI.parse` return empty string in host instead of nil. [[sec-156615]]
-
-## C API updates
-
-### Updated C APIs
-
-The following APIs are updated.
-
-* PRNG update
-
- `rb_random_interface_t` in ruby/random.h updated and versioned.
- Extension libraries which use this interface and built for older
- versions need to rebuild with adding `init_int32` function.
-
-### Added C APIs
-
-* `VALUE rb_hash_new_capa(long capa)` was added to created hashes with the desired capacity.
-* `rb_internal_thread_add_event_hook` and `rb_internal_thread_add_event_hook` were added to instrument threads scheduling.
- The following events are available:
- * `RUBY_INTERNAL_THREAD_EVENT_STARTED`
- * `RUBY_INTERNAL_THREAD_EVENT_READY`
- * `RUBY_INTERNAL_THREAD_EVENT_RESUMED`
- * `RUBY_INTERNAL_THREAD_EVENT_SUSPENDED`
- * `RUBY_INTERNAL_THREAD_EVENT_EXITED`
-* `rb_debug_inspector_current_depth` and `rb_debug_inspector_frame_depth` are added for debuggers.
-
-### Removed C APIs
-
-The following deprecated APIs are removed.
-
-* `rb_cData` variable.
-* "taintedness" and "trustedness" functions. [[Feature #16131]]
-
-## Implementation improvements
-
-* Fixed several race conditions in Kernel#autoload. [[Bug #18782]]
-* Cache invalidation for expressions referencing constants is now
- more fine-grained. `RubyVM.stat(:global_constant_state)` was
- removed because it was closely tied to the previous caching scheme
- where setting any constant invalidates all caches in the system.
- New keys, `:constant_cache_invalidations` and `:constant_cache_misses`,
- were introduced to help with use cases for `:global_constant_state`.
- [[Feature #18589]]
-* The cache-based optimization for Regexp matching is introduced.
- [[Feature #19104]]
-* [Variable Width Allocation](https://shopify.engineering/ruby-variable-width-allocation)
- is now enabled by default. [[Feature #18239]]
-* Added a new instance variable caching mechanism, called object shapes, which
- improves inline cache hits for most objects and allows us to generate very
- efficient JIT code. Objects whose instance variables are defined in a
- consistent order will see the most performance benefits.
- [[Feature #18776]]
-* Speed up marking instruction sequences by using a bitmap to find "markable"
- objects. This change results in faster major collections.
- [[Feature #18875]]
-
-## JIT
-
-### YJIT
-
-* YJIT is no longer experimental
- * Has been tested on production workloads for over a year and proven to be quite stable.
-* YJIT now supports both x86-64 and arm64/aarch64 CPUs on Linux, MacOS, BSD and other UNIX platforms.
- * This release brings support for Mac M1/M2, AWS Graviton and Raspberry Pi 4.
-* Building YJIT now requires Rust 1.58.0+. [[Feature #18481]]
- * In order to ensure that CRuby is built with YJIT, please install `rustc` >= 1.58.0
- before running `./configure`
- * Please reach out to the YJIT team should you run into any issues.
-* Physical memory for JIT code is lazily allocated. Unlike Ruby 3.1,
- the RSS of a Ruby process is minimized because virtual memory pages
- allocated by `--yjit-exec-mem-size` will not be mapped to physical
- memory pages until actually utilized by JIT code.
-* Introduce Code GC that frees all code pages when the memory consumption
- by JIT code reaches `--yjit-exec-mem-size`.
- * `RubyVM::YJIT.runtime_stats` returns Code GC metrics in addition to
- existing `inline_code_size` and `outlined_code_size` keys:
- `code_gc_count`, `live_page_count`, `freed_page_count`, and `freed_code_size`.
-* Most of the statistics produced by `RubyVM::YJIT.runtime_stats` are now available in release builds.
- * Simply run ruby with `--yjit-stats` to compute and dump stats (incurs some run-time overhead).
-* YJIT is now optimized to take advantage of object shapes. [[Feature #18776]]
-* Take advantage of finer-grained constant invalidation to invalidate less code when defining new constants. [[Feature #18589]]
-* The default `--yjit-exec-mem-size` is changed to 64 (MiB).
-* The default `--yjit-call-threshold` is changed to 30.
-
-### MJIT
-
-* The MJIT compiler is re-implemented in Ruby as `ruby_vm/mjit/compiler`.
-* MJIT compiler is executed under a forked Ruby process instead of
- doing it in a native thread called MJIT worker. [[Feature #18968]]
- * As a result, Microsoft Visual Studio (MSWIN) is no longer supported.
-* MinGW is no longer supported. [[Feature #18824]]
-* Rename `--mjit-min-calls` to `--mjit-call-threshold`.
-* Change default `--mjit-max-cache` back from 10000 to 100.
-
-[Feature #12005]: https://bugs.ruby-lang.org/issues/12005
-[Feature #12084]: https://bugs.ruby-lang.org/issues/12084
-[Feature #12655]: https://bugs.ruby-lang.org/issues/12655
-[Feature #12737]: https://bugs.ruby-lang.org/issues/12737
-[Feature #13110]: https://bugs.ruby-lang.org/issues/13110
-[Feature #14332]: https://bugs.ruby-lang.org/issues/14332
-[Feature #15231]: https://bugs.ruby-lang.org/issues/15231
-[Feature #15357]: https://bugs.ruby-lang.org/issues/15357
-[Bug #15928]: https://bugs.ruby-lang.org/issues/15928
-[Feature #16122]: https://bugs.ruby-lang.org/issues/16122
-[Feature #16131]: https://bugs.ruby-lang.org/issues/16131
-[Bug #16466]: https://bugs.ruby-lang.org/issues/16466
-[Feature #16663]: https://bugs.ruby-lang.org/issues/16663
-[Feature #16806]: https://bugs.ruby-lang.org/issues/16806
-[Bug #16889]: https://bugs.ruby-lang.org/issues/16889
-[Bug #16908]: https://bugs.ruby-lang.org/issues/16908
-[Feature #16989]: https://bugs.ruby-lang.org/issues/16989
-[Feature #17351]: https://bugs.ruby-lang.org/issues/17351
-[Feature #17391]: https://bugs.ruby-lang.org/issues/17391
-[Bug #17545]: https://bugs.ruby-lang.org/issues/17545
-[Bug #17767]: https://bugs.ruby-lang.org/issues/17767
-[Feature #17837]: https://bugs.ruby-lang.org/issues/17837
-[Feature #17881]: https://bugs.ruby-lang.org/issues/17881
-[Feature #18033]: https://bugs.ruby-lang.org/issues/18033
-[Feature #18159]: https://bugs.ruby-lang.org/issues/18159
-[Feature #18239]: https://bugs.ruby-lang.org/issues/18239#note-17
-[Feature #18351]: https://bugs.ruby-lang.org/issues/18351
-[Feature #18367]: https://bugs.ruby-lang.org/issues/18367
-[Bug #18435]: https://bugs.ruby-lang.org/issues/18435
-[Feature #18462]: https://bugs.ruby-lang.org/issues/18462
-[Feature #18481]: https://bugs.ruby-lang.org/issues/18481
-[Bug #18487]: https://bugs.ruby-lang.org/issues/18487
-[Feature #18564]: https://bugs.ruby-lang.org/issues/18564
-[Feature #18571]: https://bugs.ruby-lang.org/issues/18571
-[Feature #18585]: https://bugs.ruby-lang.org/issues/18585
-[Feature #18589]: https://bugs.ruby-lang.org/issues/18589
-[Feature #18595]: https://bugs.ruby-lang.org/issues/18595
-[Feature #18598]: https://bugs.ruby-lang.org/issues/18598
-[Bug #18625]: https://bugs.ruby-lang.org/issues/18625
-[Feature #18630]: https://bugs.ruby-lang.org/issues/18630
-[Bug #18633]: https://bugs.ruby-lang.org/issues/18633
-[Feature #18639]: https://bugs.ruby-lang.org/issues/18639
-[Feature #18685]: https://bugs.ruby-lang.org/issues/18685
-[Bug #18729]: https://bugs.ruby-lang.org/issues/18729
-[Bug #18751]: https://bugs.ruby-lang.org/issues/18751
-[Feature #18774]: https://bugs.ruby-lang.org/issues/18774
-[Feature #18776]: https://bugs.ruby-lang.org/issues/18776
-[Bug #18782]: https://bugs.ruby-lang.org/issues/18782
-[Feature #18788]: https://bugs.ruby-lang.org/issues/18788
-[Feature #18798]: https://bugs.ruby-lang.org/issues/18798
-[Feature #18809]: https://bugs.ruby-lang.org/issues/18809
-[Feature #18821]: https://bugs.ruby-lang.org/issues/18821
-[Feature #18822]: https://bugs.ruby-lang.org/issues/18822
-[Feature #18824]: https://bugs.ruby-lang.org/issues/18824
-[Feature #18832]: https://bugs.ruby-lang.org/issues/18832
-[Feature #18875]: https://bugs.ruby-lang.org/issues/18875
-[Feature #18925]: https://bugs.ruby-lang.org/issues/18925
-[Feature #18944]: https://bugs.ruby-lang.org/issues/18944
-[Feature #18949]: https://bugs.ruby-lang.org/issues/18949
-[Feature #18968]: https://bugs.ruby-lang.org/issues/18968
-[Feature #19008]: https://bugs.ruby-lang.org/issues/19008
-[Feature #19013]: https://bugs.ruby-lang.org/issues/19013
-[Feature #19026]: https://bugs.ruby-lang.org/issues/19026
-[Feature #19036]: https://bugs.ruby-lang.org/issues/19036
-[Feature #19060]: https://bugs.ruby-lang.org/issues/19060
-[Feature #19070]: https://bugs.ruby-lang.org/issues/19070
-[Feature #19071]: https://bugs.ruby-lang.org/issues/19071
-[Feature #19078]: https://bugs.ruby-lang.org/issues/19078
-[Bug #19087]: https://bugs.ruby-lang.org/issues/19087
-[Bug #19100]: https://bugs.ruby-lang.org/issues/19100
-[Feature #19104]: https://bugs.ruby-lang.org/issues/19104
-[Feature #19135]: https://bugs.ruby-lang.org/issues/19135
-[Feature #19138]: https://bugs.ruby-lang.org/issues/19138
-[Feature #19194]: https://bugs.ruby-lang.org/issues/19194
-[Molinillo]: https://github.com/CocoaPods/Molinillo
-[PubGrub]: https://github.com/jhawthorn/pub_grub
-[GH-net-protocol-14]: https://github.com/ruby/net-protocol/pull/14
-[GH-pathname-20]: https://github.com/ruby/pathname/pull/20
-[GH-6791]: https://github.com/ruby/ruby/pull/6791
-[GH-6868]: https://github.com/ruby/ruby/pull/6868
-[GH-rubygems-4475]: https://github.com/rubygems/rubygems/pull/4475
-[GH-rubygems-6149]: https://github.com/rubygems/rubygems/pull/6149
-[GH-rubygems-6167]: https://github.com/rubygems/rubygems/pull/6167
-[sec-156615]: https://hackerone.com/reports/156615
-[CVE-2021-33621]: https://www.ruby-lang.org/en/news/2022/11/22/http-response-splitting-in-cgi-cve-2021-33621/
-[wasm/README.md]: https://github.com/ruby/ruby/blob/master/wasm/README.md
-[ruby.wasm]: https://github.com/ruby/ruby.wasm
diff --git a/doc/NEWS/NEWS-3.3.0.md b/doc/NEWS/NEWS-3.3.0.md
deleted file mode 100644
index 364786d754..0000000000
--- a/doc/NEWS/NEWS-3.3.0.md
+++ /dev/null
@@ -1,529 +0,0 @@
-# NEWS for Ruby 3.3.0
-
-This document is a list of user-visible feature changes
-since the **3.2.0** release, except for bug fixes.
-
-Note that each entry is kept to a minimum, see links for details.
-
-## Command line options
-
-* A new `performance` warning category was introduced.
- They are not displayed by default even in verbose mode.
- Turn them on with `-W:performance` or `Warning[:performance] = true`. [[Feature #19538]]
-
-* A new `RUBY_CRASH_REPORT` environment variable was introduced to allow
- redirecting Ruby crash reports to a file or sub command. See the `BUG REPORT ENVIRONMENT`
- section of the ruby manpage for further details. [[Feature #19790]]
-
-## Core classes updates
-
-Note: We're only listing outstanding class updates.
-
-* Array
-
- * Array#pack now raises ArgumentError for unknown directives. [[Bug #19150]]
-
-* Dir
-
- * Dir.for_fd added for returning a Dir object for the directory specified
- by the provided directory file descriptor. [[Feature #19347]]
- * Dir.fchdir added for changing the directory to the directory specified
- by the provided directory file descriptor. [[Feature #19347]]
- * Dir#chdir added for changing the directory to the directory specified by
- the provided `Dir` object. [[Feature #19347]]
-
-* Encoding
-
- * `Encoding#replicate` has been removed, it was already deprecated. [[Feature #18949]]
-
-* Fiber
-
- * Introduce Fiber#kill. [[Bug #595]]
-
- ```ruby
- fiber = Fiber.new do
- while true
- puts "Yielding..."
- Fiber.yield
- end
- ensure
- puts "Exiting..."
- end
-
- fiber.resume
- # Yielding...
- fiber.kill
- # Exiting...
- ```
-
-* MatchData
-
- * MatchData#named_captures now accepts optional `symbolize_names`
- keyword. [[Feature #19591]]
-
-* Module
-
- * Module#set_temporary_name added for setting a temporary name for a
- module. [[Feature #19521]]
-
-* ObjectSpace::WeakKeyMap
-
- * New core class to build collections with weak references.
- The class use equality semantic to lookup keys like a regular hash,
- but it doesn't hold strong references on the keys. [[Feature #18498]]
-
-* ObjectSpace::WeakMap
-
- * ObjectSpace::WeakMap#delete was added to eagerly clear weak map
- entries. [[Feature #19561]]
-
-* Proc
- * Now Proc#dup and Proc#clone call `#initialize_dup` and `#initialize_clone`
- hooks respectively. [[Feature #19362]]
-
-* Process
-
- * New Process.warmup method that notify the Ruby virtual machine that the boot sequence is finished,
- and that now is a good time to optimize the application. This is useful
- for long-running applications. The actual optimizations performed are entirely
- implementation-specific and may change in the future without notice. [[Feature #18885]]
-
-* Process::Status
-
- * Process::Status#& and Process::Status#>> are deprecated. [[Bug #19868]]
-
-* Range
-
- * Range#reverse_each can now process beginless ranges with an Integer endpoint. [[Feature #18515]]
- * Range#reverse_each now raises TypeError for endless ranges. [[Feature #18551]]
- * Range#overlap? added for checking if two ranges overlap. [[Feature #19839]]
-
-* Refinement
-
- * Add Refinement#target as an alternative of Refinement#refined_class.
- Refinement#refined_class is deprecated and will be removed in Ruby
- 3.4. [[Feature #19714]]
-
-* Regexp
-
- * The cache-based optimization now supports lookarounds and atomic groupings. That is, match
- for Regexp containing these extensions can now also be performed in linear time to the length
- of the input string. However, these cannot contain captures and cannot be nested. [[Feature #19725]]
-
-* String
-
- * String#unpack now raises ArgumentError for unknown directives. [[Bug #19150]]
- * String#bytesplice now accepts new arguments index/length or range of the
- source string to be copied. [[Feature #19314]]
-
-* Thread::Queue
-
- * Thread::Queue#freeze now raises TypeError. [[Bug #17146]]
-
-* Thread::SizedQueue
-
- * Thread::SizedQueue#freeze now raises TypeError. [[Bug #17146]]
-
-* Time
-
- * Time.new with a string argument became stricter. [[Bug #19293]]
-
- ```ruby
- Time.new('2023-12-20')
- # no time information (ArgumentError)
- ```
-
-* TracePoint
-
- * TracePoint supports `rescue` event. When the raised exception was rescued,
- the TracePoint will fire the hook. `rescue` event only supports Ruby-level
- `rescue`. [[Feature #19572]]
-
-## Stdlib updates
-
-* RubyGems and Bundler warn if users do `require` the following gems without adding them to Gemfile or gemspec.
- This is because they will become the bundled gems in the future version of Ruby. This warning is suppressed
- if you use bootsnap gem. We recommend to run your application with `DISABLE_BOOTSNAP=1` environmental variable
- at least once. This is limitation of this version.
- [[Feature #19351]] [[Feature #19776]] [[Feature #19843]]
- * abbrev
- * base64
- * bigdecimal
- * csv
- * drb
- * getoptlong
- * mutex_m
- * nkf
- * observer
- * racc
- * resolv-replace
- * rinda
- * syslog
-
-* Socket#recv and Socket#recv_nonblock returns `nil` instead of an empty string on closed
- connections. Socket#recvmsg and Socket#recvmsg_nonblock returns `nil` instead of an empty packet on closed
- connections. [[Bug #19012]]
-
-* Name resolution such as Socket.getaddrinfo, Socket.getnameinfo, Addrinfo.getaddrinfo, etc.
- can now be interrupted. [[Feature #19965]]
-
-* Random::Formatter#alphanumeric is extended to accept optional `chars`
- keyword argument. [[Feature #18183]]
-
-The following default gem is added.
-
-* prism 0.19.0
-
-The following default gems are updated.
-
-* RubyGems 3.5.3
-* abbrev 0.1.2
-* base64 0.2.0
-* benchmark 0.3.0
-* bigdecimal 3.1.5
-* bundler 2.5.3
-* cgi 0.4.1
-* csv 3.2.8
-* date 3.3.4
-* delegate 0.3.1
-* drb 2.2.0
-* english 0.8.0
-* erb 4.0.3
-* error_highlight 0.6.0
-* etc 1.4.3
-* fcntl 1.1.0
-* fiddle 1.1.2
-* fileutils 1.7.2
-* find 0.2.0
-* getoptlong 0.2.1
-* io-console 0.7.1
-* io-nonblock 0.3.0
-* io-wait 0.3.1
-* ipaddr 1.2.6
-* irb 1.11.0
-* json 2.7.1
-* logger 1.6.0
-* mutex_m 0.2.0
-* net-http 0.4.0
-* net-protocol 0.2.2
-* nkf 0.1.3
-* observer 0.1.2
-* open-uri 0.4.1
-* open3 0.2.1
-* openssl 3.2.0
-* optparse 0.4.0
-* ostruct 0.6.0
-* pathname 0.3.0
-* pp 0.5.0
-* prettyprint 0.2.0
-* pstore 0.1.3
-* psych 5.1.2
-* rdoc 6.6.2
-* readline 0.0.4
-* reline 0.4.1
-* resolv 0.3.0
-* rinda 0.2.0
-* securerandom 0.3.1
-* set 1.1.0
-* shellwords 0.2.0
-* singleton 0.2.0
-* stringio 3.1.0
-* strscan 3.0.7
-* syntax_suggest 2.0.0
-* syslog 0.1.2
-* tempfile 0.2.1
-* time 0.3.0
-* timeout 0.4.1
-* tmpdir 0.2.0
-* tsort 0.2.0
-* un 0.3.0
-* uri 0.13.0
-* weakref 0.1.3
-* win32ole 1.8.10
-* yaml 0.3.0
-* zlib 3.1.0
-
-The following bundled gem is promoted from default gems.
-
-* racc 1.7.3
-
-The following bundled gems are updated.
-
-* minitest 5.20.0
-* rake 13.1.0
-* test-unit 3.6.1
-* rexml 3.2.6
-* rss 0.3.0
-* net-ftp 0.3.3
-* net-imap 0.4.9
-* net-smtp 0.4.0
-* rbs 3.4.0
-* typeprof 0.21.9
-* debug 1.9.1
-
-See GitHub releases like [Logger](https://github.com/ruby/logger/releases) or
-changelog for details of the default gems or bundled gems.
-
-### Prism
-
-* Introduced [the Prism parser](https://github.com/ruby/prism) as a default gem
- * Prism is a portable, error tolerant, and maintainable recursive descent parser for the Ruby language
-* Prism is production ready and actively maintained, you can use it in place of Ripper
- * There is [extensive documentation](https://ruby.github.io/prism/) on how to use Prism
- * Prism is both a C library that will be used internally by CRuby and a Ruby gem that can be used by any tooling which needs to parse Ruby code
- * Notable methods in the Prism API are:
- * `Prism.parse(source)` which returns the AST as part of a parse result object
- * `Prism.parse_comments(source)` which returns the comments
- * `Prism.parse_success?(source)` which returns true if there are no errors
-* You can make pull requests or issues directly on [the Prism repository](https://github.com/ruby/prism) if you are interested in contributing
-* You can now use `ruby --parser=prism` or `RUBYOPT="--parser=prism"` to experiment with the Prism compiler. Please note that this flag is for debugging only.
-
-## Compatibility issues
-
-* Subprocess creation/forking via the following file open methods is deprecated. [[Feature #19630]]
- * Kernel#open
- * URI.open
- * IO.binread
- * IO.foreach
- * IO.readlines
- * IO.read
- * IO.write
-
-* When given a non-lambda, non-literal block, Kernel#lambda with now raises
- ArgumentError instead of returning it unmodified. These usages have been
- issuing warnings under the `Warning[:deprecated]` category since Ruby 3.0.0.
- [[Feature #19777]]
-
-* The `RUBY_GC_HEAP_INIT_SLOTS` environment variable has been deprecated and
- removed. Environment variables `RUBY_GC_HEAP_%d_INIT_SLOTS` should be
- used instead. [[Feature #19785]]
-
-* `it` calls without arguments in a block with no ordinary parameters are
- deprecated. `it` will be a reference to the first block parameter in Ruby 3.4.
- [[Feature #18980]]
-
-* Error message for NoMethodError have changed to not use the target object's `#inspect`
- for efficiency, and says "instance of ClassName" instead. [[Feature #18285]]
-
- ```ruby
- ([1] * 100).nonexisting
- # undefined method `nonexisting' for an instance of Array (NoMethodError)
- ```
-
-* Now anonymous parameters forwarding is disallowed inside a block
- that uses anonymous parameters. [[Feature #19370]]
-
-## Stdlib compatibility issues
-
-* `racc` is promoted to bundled gems.
- * You need to add `racc` to your `Gemfile` if you use `racc` under bundler environment.
-* `ext/readline` is retired
- * We have `reline` that is pure Ruby implementation compatible with `ext/readline` API.
- We rely on `reline` in the future. If you need to use `ext/readline`, you can install
- `ext/readline` via rubygems.org with `gem install readline-ext`.
- * We no longer need to install libraries like `libreadline` or `libedit`.
-
-## C API updates
-
-* `rb_postponed_job` updates
- * New APIs and deprecated APIs (see comments for details)
- * added: `rb_postponed_job_preregister()`
- * added: `rb_postponed_job_trigger()`
- * deprecated: `rb_postponed_job_register()` (and semantic change. see below)
- * deprecated: `rb_postponed_job_register_one()`
- * The postponed job APIs have been changed to address some rare crashes.
- To solve the issue, we introduced new two APIs and deprecated current APIs.
- The semantics of these functions have also changed slightly; `rb_postponed_job_register`
- now behaves like the `once` variant in that multiple calls with the same
- `func` might be coalesced into a single execution of the `func`
- [[Feature #20057]]
-
-* Some updates for internal thread event hook APIs
- * `rb_internal_thread_event_data_t` with a target Ruby thread (VALUE)
- and callback functions (`rb_internal_thread_event_callback`) receive it.
- https://github.com/ruby/ruby/pull/8885
- * The following functions are introduced to manipulate Ruby thread local data
- from internal thread event hook APIs (they are introduced since Ruby 3.2).
- https://github.com/ruby/ruby/pull/8936
- * `rb_internal_thread_specific_key_create()`
- * `rb_internal_thread_specific_get()`
- * `rb_internal_thread_specific_set()`
-
-* `rb_profile_thread_frames()` is introduced to get a frames from
- a specific thread.
- [[Feature #10602]]
-
-* `rb_data_define()` is introduced to define `Data`. [[Feature #19757]]
-
-* `rb_ext_resolve_symbol()` is introduced to search a function from
- extension libraries. [[Feature #20005]]
-
-* IO related updates:
- * The details of `rb_io_t` will be hidden and deprecated attributes
- are added for each members. [[Feature #19057]]
- * `rb_io_path(VALUE io)` is introduced to get a path of `io`.
- * `rb_io_closed_p(VALUE io)` to get opening or closing of `io`.
- * `rb_io_mode(VALUE io)` to get the mode of `io`.
- * `rb_io_open_descriptor()` is introduced to make an IO object from a file
- descriptor.
-
-## Implementation improvements
-
-### Parser
-
-* Replace Bison with [Lrama LALR parser generator](https://github.com/ruby/lrama).
- No need to install Bison to build Ruby from source code anymore.
- We will no longer suffer bison compatibility issues and we can use new features by just implementing it to Lrama. [[Feature #19637]]
- * See [The future vision of Ruby Parser](https://rubykaigi.org/2023/presentations/spikeolaf.html) for detail.
- * Lrama internal parser is a LR parser generated by Racc for maintainability.
- * Parameterizing Rules `(?, *, +)` are supported, it will be used in Ruby parse.y.
-
-### GC / Memory management
-
-* Major performance improvements over Ruby 3.2
- * Young objects referenced by old objects are no longer immediately
- promoted to the old generation. This significantly reduces the frequency of
- major GC collections. [[Feature #19678]]
- * A new `REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO` tuning variable was
- introduced to control the number of unprotected objects cause a major GC
- collection to trigger. The default is set to `0.01` (1%). This significantly
- reduces the frequency of major GC collection. [[Feature #19571]]
- * Write Barriers were implemented for many core types that were missing them,
- notably `Time`, `Enumerator`, `MatchData`, `Method`, `File::Stat`, `BigDecimal`
- and several others. This significantly reduces minor GC collection time and major
- GC collection frequency.
- * Most core classes are now using Variable Width Allocation, notably `Hash`, `Time`,
- `Thread::Backtrace`, `Thread::Backtrace::Location`, `File::Stat`, `Method`.
- This makes these classes faster to allocate and free, use less memory and reduce
- heap fragmentation.
-* `defined?(@ivar)` is optimized with Object Shapes.
-
-### YJIT
-
-* Major performance improvements over Ruby 3.2
- * Support for splat and rest arguments has been improved.
- * Registers are allocated for stack operations of the virtual machine.
- * More calls with optional arguments are compiled. Exception handlers are also compiled.
- * Unsupported call types and megamorphic call sites no longer exit to the interpreter.
- * Basic methods like Rails `#blank?` and
- [specialized `#present?`](https://github.com/rails/rails/pull/49909) are inlined.
- * `Integer#*`, `Integer#!=`, `String#!=`, `String#getbyte`,
- `Kernel#block_given?`, `Kernel#is_a?`, `Kernel#instance_of?`, and `Module#===`
- are specially optimized.
- * Compilation speed is now slightly faster than Ruby 3.2.
- * Now more than 3x faster than the interpreter on Optcarrot!
-* Significantly improved memory usage over Ruby 3.2
- * Metadata for compiled code uses a lot less memory.
- * `--yjit-call-threshold` is automatically raised from 30 to 120
- when the application has more than 40,000 ISEQs.
- * `--yjit-cold-threshold` is added to skip compiling cold ISEQs.
- * More compact code is generated on Arm64.
-* Code GC is now disabled by default
- * `--yjit-exec-mem-size` is treated as a hard limit where compilation of new code stops.
- * No sudden drops in performance due to code GC.
- Better copy-on-write behavior on servers reforking with
- [Pitchfork](https://github.com/shopify/pitchfork).
- * You can still enable code GC if desired with `--yjit-code-gc`
-* Add `RubyVM::YJIT.enable` that can enable YJIT at run-time
- * You can start YJIT without modifying command-line arguments or environment variables.
- Rails 7.2 will [enable YJIT by default](https://github.com/rails/rails/pull/49947)
- using this method.
- * This can also be used to enable YJIT only once your application is
- done booting. `--yjit-disable` can be used if you want to use other
- YJIT options while disabling YJIT at boot.
-* More YJIT stats are available by default
- * `yjit_alloc_size` and several more metadata-related stats are now available by default.
- * `ratio_in_yjit` stat produced by `--yjit-stats` is now available in release builds,
- a special stats or dev build is no longer required to access most stats.
-* Add more profiling capabilities
- * `--yjit-perf` is added to facilitate profiling with Linux perf.
- * `--yjit-trace-exits` now supports sampling with `--yjit-trace-exits-sample-rate=N`
-* More thorough testing and multiple bug fixes
-* `--yjit-stats=quiet` is added to avoid printing stats on exit.
-
-### MJIT
-
-* MJIT is removed.
- * `--disable-jit-support` is removed. Consider using `--disable-yjit --disable-rjit` instead.
-
-### RJIT
-
-* Introduced a pure-Ruby JIT compiler RJIT.
- * RJIT supports only x86\_64 architecture on Unix platforms.
- * Unlike MJIT, it doesn't require a C compiler at runtime.
-* RJIT exists only for experimental purposes.
- * You should keep using YJIT in production.
-
-### M:N Thread scheduler
-
-* M:N Thread scheduler is introduced. [[Feature #19842]]
- * Background: Ruby 1.8 and before, M:1 thread scheduler (M Ruby threads
- with 1 native thread. Called as User level threads or Green threads)
- is used. Ruby 1.9 and later, 1:1 thread scheduler (1 Ruby thread with
- 1 native thread). M:1 threads takes lower resources compare with 1:1
- threads because it needs only 1 native threads. However it is difficult
- to support context switching for all of blocking operation so 1:1
- threads are employed from Ruby 1.9. M:N thread scheduler uses N native
- threads for M Ruby threads (N is small number in general). It doesn't
- need same number of native threads as Ruby threads (similar to the M:1
- thread scheduler). Also our M:N threads supports blocking operations
- well same as 1:1 threads. See the ticket for more details.
- Our M:N thread scheduler refers on the goroutine scheduler in the
- Go language.
- * In a ractor, only 1 thread can run in a same time because of
- implementation. Therefore, applications that use only one Ractor
- (most applications) M:N thread scheduler works as M:1 thread scheduler
- with further extension from Ruby 1.8.
- * M:N thread scheduler can introduce incompatibility for C-extensions,
- so it is disabled by default on the main Ractors.
- `RUBY_MN_THREADS=1` environment variable will enable it.
- On non-main Ractors, M:N thread scheduler is enabled (and can not
- disable it now).
- * `N` (the number of native threads) can be specified with `RUBY_MAX_CPU`
- environment variable. The default is 8.
- Note that more than `N` native threads are used to support many kind of
- blocking operations.
-
-[Bug #595]: https://bugs.ruby-lang.org/issues/595
-[Feature #10602]: https://bugs.ruby-lang.org/issues/10602
-[Bug #17146]: https://bugs.ruby-lang.org/issues/17146
-[Feature #18183]: https://bugs.ruby-lang.org/issues/18183
-[Feature #18285]: https://bugs.ruby-lang.org/issues/18285
-[Feature #18498]: https://bugs.ruby-lang.org/issues/18498
-[Feature #18515]: https://bugs.ruby-lang.org/issues/18515
-[Feature #18551]: https://bugs.ruby-lang.org/issues/18551
-[Feature #18885]: https://bugs.ruby-lang.org/issues/18885
-[Feature #18949]: https://bugs.ruby-lang.org/issues/18949
-[Feature #18980]: https://bugs.ruby-lang.org/issues/18980
-[Bug #19012]: https://bugs.ruby-lang.org/issues/19012
-[Feature #19057]: https://bugs.ruby-lang.org/issues/19057
-[Bug #19150]: https://bugs.ruby-lang.org/issues/19150
-[Bug #19293]: https://bugs.ruby-lang.org/issues/19293
-[Feature #19314]: https://bugs.ruby-lang.org/issues/19314
-[Feature #19347]: https://bugs.ruby-lang.org/issues/19347
-[Feature #19351]: https://bugs.ruby-lang.org/issues/19351
-[Feature #19362]: https://bugs.ruby-lang.org/issues/19362
-[Feature #19370]: https://bugs.ruby-lang.org/issues/19370
-[Feature #19521]: https://bugs.ruby-lang.org/issues/19521
-[Feature #19538]: https://bugs.ruby-lang.org/issues/19538
-[Feature #19561]: https://bugs.ruby-lang.org/issues/19561
-[Feature #19571]: https://bugs.ruby-lang.org/issues/19571
-[Feature #19572]: https://bugs.ruby-lang.org/issues/19572
-[Feature #19591]: https://bugs.ruby-lang.org/issues/19591
-[Feature #19630]: https://bugs.ruby-lang.org/issues/19630
-[Feature #19637]: https://bugs.ruby-lang.org/issues/19637
-[Feature #19678]: https://bugs.ruby-lang.org/issues/19678
-[Feature #19714]: https://bugs.ruby-lang.org/issues/19714
-[Feature #19725]: https://bugs.ruby-lang.org/issues/19725
-[Feature #19757]: https://bugs.ruby-lang.org/issues/19757
-[Feature #19776]: https://bugs.ruby-lang.org/issues/19776
-[Feature #19777]: https://bugs.ruby-lang.org/issues/19777
-[Feature #19785]: https://bugs.ruby-lang.org/issues/19785
-[Feature #19790]: https://bugs.ruby-lang.org/issues/19790
-[Feature #19839]: https://bugs.ruby-lang.org/issues/19839
-[Feature #19842]: https://bugs.ruby-lang.org/issues/19842
-[Feature #19843]: https://bugs.ruby-lang.org/issues/19843
-[Bug #19868]: https://bugs.ruby-lang.org/issues/19868
-[Feature #19965]: https://bugs.ruby-lang.org/issues/19965
-[Feature #20005]: https://bugs.ruby-lang.org/issues/20005
-[Feature #20057]: https://bugs.ruby-lang.org/issues/20057
diff --git a/doc/_regexp.rdoc b/doc/_regexp.rdoc
deleted file mode 100644
index da323e913f..0000000000
--- a/doc/_regexp.rdoc
+++ /dev/null
@@ -1,1276 +0,0 @@
-A {regular expression}[https://en.wikipedia.org/wiki/Regular_expression]
-(also called a _regexp_) is a <i>match pattern</i> (also simply called a _pattern_).
-
-A common notation for a regexp uses enclosing slash characters:
-
- /foo/
-
-A regexp may be applied to a <i>target string</i>;
-The part of the string (if any) that matches the pattern is called a _match_,
-and may be said <i>to match</i>:
-
- re = /red/
- re.match?('redirect') # => true # Match at beginning of target.
- re.match?('bored') # => true # Match at end of target.
- re.match?('credit') # => true # Match within target.
- re.match?('foo') # => false # No match.
-
-== \Regexp Uses
-
-A regexp may be used:
-
-- To extract substrings based on a given pattern:
-
- re = /foo/ # => /foo/
- re.match('food') # => #<MatchData "foo">
- re.match('good') # => nil
-
- See sections {Method match}[rdoc-ref:Regexp@Method+match]
- and {Operator =~}[rdoc-ref:Regexp@Operator+-3D~].
-
-- To determine whether a string matches a given pattern:
-
- re.match?('food') # => true
- re.match?('good') # => false
-
- See section {Method match?}[rdoc-ref:Regexp@Method+match-3F].
-
-- As an argument for calls to certain methods in other classes and modules;
- most such methods accept an argument that may be either a string
- or the (much more powerful) regexp.
-
- See {Regexp Methods}[rdoc-ref:regexp/methods.rdoc].
-
-== \Regexp Objects
-
-A regexp object has:
-
-- A source; see {Sources}[rdoc-ref:Regexp@Sources].
-
-- Several modes; see {Modes}[rdoc-ref:Regexp@Modes].
-
-- A timeout; see {Timeouts}[rdoc-ref:Regexp@Timeouts].
-
-- An encoding; see {Encodings}[rdoc-ref:Regexp@Encodings].
-
-== Creating a \Regexp
-
-A regular expression may be created with:
-
-- A regexp literal using slash characters
- (see {Regexp Literals}[rdoc-ref:syntax/literals.rdoc@Regexp+Literals]):
-
- # This is a very common usage.
- /foo/ # => /foo/
-
-- A <tt>%r</tt> regexp literal
- (see {%r: Regexp Literals}[rdoc-ref:syntax/literals.rdoc@25r-3A+Regexp+Literals]):
-
- # Same delimiter character at beginning and end;
- # useful for avoiding escaping characters
- %r/name\/value pair/ # => /name\/value pair/
- %r:name/value pair: # => /name\/value pair/
- %r|name/value pair| # => /name\/value pair/
-
- # Certain "paired" characters can be delimiters.
- %r[foo] # => /foo/
- %r{foo} # => /foo/
- %r(foo) # => /foo/
- %r<foo> # => /foo/
-
-- \Method Regexp.new.
-
-== \Method <tt>match</tt>
-
-Each of the methods Regexp#match, String#match, and Symbol#match
-returns a MatchData object if a match was found, +nil+ otherwise;
-each also sets {global variables}[rdoc-ref:Regexp@Global+Variables]:
-
- 'food'.match(/foo/) # => #<MatchData "foo">
- 'food'.match(/bar/) # => nil
-
-== Operator <tt>=~</tt>
-
-Each of the operators Regexp#=~, String#=~, and Symbol#=~
-returns an integer offset if a match was found, +nil+ otherwise;
-each also sets {global variables}[rdoc-ref:Regexp@Global+Variables]:
-
- /bar/ =~ 'foo bar' # => 4
- 'foo bar' =~ /bar/ # => 4
- /baz/ =~ 'foo bar' # => nil
-
-== \Method <tt>match?</tt>
-
-Each of the methods Regexp#match?, String#match?, and Symbol#match?
-returns +true+ if a match was found, +false+ otherwise;
-none sets {global variables}[rdoc-ref:Regexp@Global+Variables]:
-
- 'food'.match?(/foo/) # => true
- 'food'.match?(/bar/) # => false
-
-== Global Variables
-
-Certain regexp-oriented methods assign values to global variables:
-
-- <tt>#match</tt>: see {Method match}[rdoc-ref:Regexp@Method+match].
-- <tt>#=~</tt>: see {Operator =~}[rdoc-ref:Regexp@Operator+-3D~].
-
-The affected global variables are:
-
-- <tt>$~</tt>: Returns a MatchData object, or +nil+.
-- <tt>$&</tt>: Returns the matched part of the string, or +nil+.
-- <tt>$`</tt>: Returns the part of the string to the left of the match, or +nil+.
-- <tt>$'</tt>: Returns the part of the string to the right of the match, or +nil+.
-- <tt>$+</tt>: Returns the last group matched, or +nil+.
-- <tt>$1</tt>, <tt>$2</tt>, etc.: Returns the first, second, etc.,
- matched group, or +nil+.
- Note that <tt>$0</tt> is quite different;
- it returns the name of the currently executing program.
-
-Examples:
-
- # Matched string, but no matched groups.
- 'foo bar bar baz'.match('bar')
- $~ # => #<MatchData "bar">
- $& # => "bar"
- $` # => "foo "
- $' # => " bar baz"
- $+ # => nil
- $1 # => nil
-
- # Matched groups.
- /s(\w{2}).*(c)/.match('haystack')
- $~ # => #<MatchData "stac" 1:"ta" 2:"c">
- $& # => "stac"
- $` # => "hay"
- $' # => "k"
- $+ # => "c"
- $1 # => "ta"
- $2 # => "c"
- $3 # => nil
-
- # No match.
- 'foo'.match('bar')
- $~ # => nil
- $& # => nil
- $` # => nil
- $' # => nil
- $+ # => nil
- $1 # => nil
-
-Note that Regexp#match?, String#match?, and Symbol#match?
-do not set global variables.
-
-== Sources
-
-As seen above, the simplest regexp uses a literal expression as its source:
-
- re = /foo/ # => /foo/
- re.match('food') # => #<MatchData "foo">
- re.match('good') # => nil
-
-A rich collection of available _subexpressions_
-gives the regexp great power and flexibility:
-
-- {Special characters}[rdoc-ref:Regexp@Special+Characters]
-- {Source literals}[rdoc-ref:Regexp@Source+Literals]
-- {Character classes}[rdoc-ref:Regexp@Character+Classes]
-- {Shorthand character classes}[rdoc-ref:Regexp@Shorthand+Character+Classes]
-- {Anchors}[rdoc-ref:Regexp@Anchors]
-- {Alternation}[rdoc-ref:Regexp@Alternation]
-- {Quantifiers}[rdoc-ref:Regexp@Quantifiers]
-- {Groups and captures}[rdoc-ref:Regexp@Groups+and+Captures]
-- {Unicode}[rdoc-ref:Regexp@Unicode]
-- {POSIX Bracket Expressions}[rdoc-ref:Regexp@POSIX+Bracket+Expressions]
-- {Comments}[rdoc-ref:Regexp@Comments]
-
-=== Special Characters
-
-\Regexp special characters, called _metacharacters_,
-have special meanings in certain contexts;
-depending on the context, these are sometimes metacharacters:
-
- . ? - + * ^ \ | $ ( ) [ ] { }
-
-To match a metacharacter literally, backslash-escape it:
-
- # Matches one or more 'o' characters.
- /o+/.match('foo') # => #<MatchData "oo">
- # Would match 'o+'.
- /o\+/.match('foo') # => nil
-
-To match a backslash literally, backslash-escape it:
-
- /\./.match('\.') # => #<MatchData ".">
- /\\./.match('\.') # => #<MatchData "\\.">
-
-Method Regexp.escape returns an escaped string:
-
- Regexp.escape('.?-+*^\|$()[]{}')
- # => "\\.\\?\\-\\+\\*\\^\\\\\\|\\$\\(\\)\\[\\]\\{\\}"
-
-=== Source Literals
-
-The source literal largely behaves like a double-quoted string;
-see {Double-Quoted String Literals}[rdoc-ref:syntax/literals.rdoc@Double-Quoted+String+Literals].
-
-In particular, a source literal may contain interpolated expressions:
-
- s = 'foo' # => "foo"
- /#{s}/ # => /foo/
- /#{s.capitalize}/ # => /Foo/
- /#{2 + 2}/ # => /4/
-
-There are differences between an ordinary string literal and a source literal;
-see {Shorthand Character Classes}[rdoc-ref:Regexp@Shorthand+Character+Classes].
-
-- <tt>\s</tt> in an ordinary string literal is equivalent to a space character;
- in a source literal, it's shorthand for matching a whitespace character.
-- In an ordinary string literal, these are (needlessly) escaped characters;
- in a source literal, they are shorthands for various matching characters:
-
- \w \W \d \D \h \H \S \R
-
-=== Character Classes
-
-A <i>character class</i> is delimited by square brackets;
-it specifies that certain characters match at a given point in the target string:
-
- # This character class will match any vowel.
- re = /B[aeiou]rd/
- re.match('Bird') # => #<MatchData "Bird">
- re.match('Bard') # => #<MatchData "Bard">
- re.match('Byrd') # => nil
-
-A character class may contain hyphen characters to specify ranges of characters:
-
- # These regexps have the same effect.
- /[abcdef]/.match('foo') # => #<MatchData "f">
- /[a-f]/.match('foo') # => #<MatchData "f">
- /[a-cd-f]/.match('foo') # => #<MatchData "f">
-
-When the first character of a character class is a caret (<tt>^</tt>),
-the sense of the class is inverted: it matches any character _except_ those specified.
-
- /[^a-eg-z]/.match('f') # => #<MatchData "f">
-
-A character class may contain another character class.
-By itself this isn't useful because <tt>[a-z[0-9]]</tt>
-describes the same set as <tt>[a-z0-9]</tt>.
-
-However, character classes also support the <tt>&&</tt> operator,
-which performs set intersection on its arguments.
-The two can be combined as follows:
-
- /[a-w&&[^c-g]z]/ # ([a-w] AND ([^c-g] OR z))
-
-This is equivalent to:
-
- /[abh-w]/
-
-=== Shorthand Character Classes
-
-Each of the following metacharacters serves as a shorthand
-for a character class:
-
-- <tt>/./</tt>: Matches any character except a newline:
-
- /./.match('foo') # => #<MatchData "f">
- /./.match("\n") # => nil
-
-- <tt>/./m</tt>: Matches any character, including a newline;
- see {Multiline Mode}[rdoc-ref:Regexp@Multiline+Mode]:
-
- /./m.match("\n") # => #<MatchData "\n">
-
-- <tt>/\w/</tt>: Matches a word character: equivalent to <tt>[a-zA-Z0-9_]</tt>:
-
- /\w/.match(' foo') # => #<MatchData "f">
- /\w/.match(' _') # => #<MatchData "_">
- /\w/.match(' ') # => nil
-
-- <tt>/\W/</tt>: Matches a non-word character: equivalent to <tt>[^a-zA-Z0-9_]</tt>:
-
- /\W/.match(' ') # => #<MatchData " ">
- /\W/.match('_') # => nil
-
-- <tt>/\d/</tt>: Matches a digit character: equivalent to <tt>[0-9]</tt>:
-
- /\d/.match('THX1138') # => #<MatchData "1">
- /\d/.match('foo') # => nil
-
-- <tt>/\D/</tt>: Matches a non-digit character: equivalent to <tt>[^0-9]</tt>:
-
- /\D/.match('123Jump!') # => #<MatchData "J">
- /\D/.match('123') # => nil
-
-- <tt>/\h/</tt>: Matches a hexdigit character: equivalent to <tt>[0-9a-fA-F]</tt>:
-
- /\h/.match('xyz fedcba9876543210') # => #<MatchData "f">
- /\h/.match('xyz') # => nil
-
-- <tt>/\H/</tt>: Matches a non-hexdigit character: equivalent to <tt>[^0-9a-fA-F]</tt>:
-
- /\H/.match('fedcba9876543210xyz') # => #<MatchData "x">
- /\H/.match('fedcba9876543210') # => nil
-
-- <tt>/\s/</tt>: Matches a whitespace character: equivalent to <tt>/[ \t\r\n\f\v]/</tt>:
-
- /\s/.match('foo bar') # => #<MatchData " ">
- /\s/.match('foo') # => nil
-
-- <tt>/\S/</tt>: Matches a non-whitespace character: equivalent to <tt>/[^ \t\r\n\f\v]/</tt>:
-
- /\S/.match(" \t\r\n\f\v foo") # => #<MatchData "f">
- /\S/.match(" \t\r\n\f\v") # => nil
-
-- <tt>/\R/</tt>: Matches a linebreak, platform-independently:
-
- /\R/.match("\r") # => #<MatchData "\r"> # Carriage return (CR)
- /\R/.match("\n") # => #<MatchData "\n"> # Newline (LF)
- /\R/.match("\f") # => #<MatchData "\f"> # Formfeed (FF)
- /\R/.match("\v") # => #<MatchData "\v"> # Vertical tab (VT)
- /\R/.match("\r\n") # => #<MatchData "\r\n"> # CRLF
- /\R/.match("\u0085") # => #<MatchData "\u0085"> # Next line (NEL)
- /\R/.match("\u2028") # => #<MatchData "\u2028"> # Line separator (LSEP)
- /\R/.match("\u2029") # => #<MatchData "\u2029"> # Paragraph separator (PSEP)
-
-=== Anchors
-
-An anchor is a metasequence that matches a zero-width position between
-characters in the target string.
-
-For a subexpression with no anchor,
-matching may begin anywhere in the target string:
-
- /real/.match('surrealist') # => #<MatchData "real">
-
-For a subexpression with an anchor,
-matching must begin at the matched anchor.
-
-==== Boundary Anchors
-
-Each of these anchors matches a boundary:
-
-- <tt>^</tt>: Matches the beginning of a line:
-
- /^bar/.match("foo\nbar") # => #<MatchData "bar">
- /^ar/.match("foo\nbar") # => nil
-
-- <tt>$</tt>: Matches the end of a line:
-
- /bar$/.match("foo\nbar") # => #<MatchData "bar">
- /ba$/.match("foo\nbar") # => nil
-
-- <tt>\A</tt>: Matches the beginning of the string:
-
- /\Afoo/.match('foo bar') # => #<MatchData "foo">
- /\Afoo/.match(' foo bar') # => nil
-
-- <tt>\Z</tt>: Matches the end of the string;
- if string ends with a single newline,
- it matches just before the ending newline:
-
- /foo\Z/.match('bar foo') # => #<MatchData "foo">
- /foo\Z/.match('foo bar') # => nil
- /foo\Z/.match("bar foo\n") # => #<MatchData "foo">
- /foo\Z/.match("bar foo\n\n") # => nil
-
-- <tt>\z</tt>: Matches the end of the string:
-
- /foo\z/.match('bar foo') # => #<MatchData "foo">
- /foo\z/.match('foo bar') # => nil
- /foo\z/.match("bar foo\n") # => nil
-
-- <tt>\b</tt>: Matches word boundary when not inside brackets;
- matches backspace (<tt>"0x08"</tt>) when inside brackets:
-
- /foo\b/.match('foo bar') # => #<MatchData "foo">
- /foo\b/.match('foobar') # => nil
-
-- <tt>\B</tt>: Matches non-word boundary:
-
- /foo\B/.match('foobar') # => #<MatchData "foo">
- /foo\B/.match('foo bar') # => nil
-
-- <tt>\G</tt>: Matches first matching position:
-
- In methods like String#gsub and String#scan, it changes on each iteration.
- It initially matches the beginning of subject, and in each following iteration it matches where the last match finished.
-
- " a b c".gsub(/ /, '_') # => "____a_b_c"
- " a b c".gsub(/\G /, '_') # => "____a b c"
-
- In methods like Regexp#match and String#match
- that take an optional offset, it matches where the search begins.
-
- "hello, world".match(/,/, 3) # => #<MatchData ",">
- "hello, world".match(/\G,/, 3) # => nil
-
-==== Lookaround Anchors
-
-Lookahead anchors:
-
-- <tt>(?=_pat_)</tt>: Positive lookahead assertion:
- ensures that the following characters match _pat_,
- but doesn't include those characters in the matched substring.
-
-- <tt>(?!_pat_)</tt>: Negative lookahead assertion:
- ensures that the following characters <i>do not</i> match _pat_,
- but doesn't include those characters in the matched substring.
-
-Lookbehind anchors:
-
-- <tt>(?<=_pat_)</tt>: Positive lookbehind assertion:
- ensures that the preceding characters match _pat_, but
- doesn't include those characters in the matched substring.
-
-- <tt>(?<!_pat_)</tt>: Negative lookbehind assertion:
- ensures that the preceding characters do not match
- _pat_, but doesn't include those characters in the matched substring.
-
-The pattern below uses positive lookahead and positive lookbehind to match
-text appearing in <tt><b></tt>...<tt></b></tt> tags
-without including the tags in the match:
-
- /(?<=<b>)\w+(?=<\/b>)/.match("Fortune favors the <b>bold</b>.")
- # => #<MatchData "bold">
-
-==== Match-Reset Anchor
-
-- <tt>\K</tt>: Match reset:
- the matched content preceding <tt>\K</tt> in the regexp is excluded from the result.
- For example, the following two regexps are almost equivalent:
-
- /ab\Kc/.match('abc') # => #<MatchData "c">
- /(?<=ab)c/.match('abc') # => #<MatchData "c">
-
- These match same string and <tt>$&</tt> equals <tt>'c'</tt>,
- while the matched position is different.
-
- As are the following two regexps:
-
- /(a)\K(b)\Kc/
- /(?<=(?<=(a))(b))c/
-
-=== Alternation
-
-The vertical bar metacharacter (<tt>|</tt>) may be used within parentheses
-to express alternation:
-two or more subexpressions any of which may match the target string.
-
-Two alternatives:
-
- re = /(a|b)/
- re.match('foo') # => nil
- re.match('bar') # => #<MatchData "b" 1:"b">
-
-Four alternatives:
-
- re = /(a|b|c|d)/
- re.match('shazam') # => #<MatchData "a" 1:"a">
- re.match('cold') # => #<MatchData "c" 1:"c">
-
-Each alternative is a subexpression, and may be composed of other subexpressions:
-
- re = /([a-c]|[x-z])/
- re.match('bar') # => #<MatchData "b" 1:"b">
- re.match('ooz') # => #<MatchData "z" 1:"z">
-
-\Method Regexp.union provides a convenient way to construct
-a regexp with alternatives.
-
-=== Quantifiers
-
-A simple regexp matches one character:
-
- /\w/.match('Hello') # => #<MatchData "H">
-
-An added _quantifier_ specifies how many matches are required or allowed:
-
-- <tt>*</tt> - Matches zero or more times:
-
- /\w*/.match('')
- # => #<MatchData "">
- /\w*/.match('x')
- # => #<MatchData "x">
- /\w*/.match('xyz')
- # => #<MatchData "yz">
-
-- <tt>+</tt> - Matches one or more times:
-
- /\w+/.match('') # => nil
- /\w+/.match('x') # => #<MatchData "x">
- /\w+/.match('xyz') # => #<MatchData "xyz">
-
-- <tt>?</tt> - Matches zero or one times:
-
- /\w?/.match('') # => #<MatchData "">
- /\w?/.match('x') # => #<MatchData "x">
- /\w?/.match('xyz') # => #<MatchData "x">
-
-- <tt>{</tt>_n_<tt>}</tt> - Matches exactly _n_ times:
-
- /\w{2}/.match('') # => nil
- /\w{2}/.match('x') # => nil
- /\w{2}/.match('xyz') # => #<MatchData "xy">
-
-- <tt>{</tt>_min_<tt>,}</tt> - Matches _min_ or more times:
-
- /\w{2,}/.match('') # => nil
- /\w{2,}/.match('x') # => nil
- /\w{2,}/.match('xy') # => #<MatchData "xy">
- /\w{2,}/.match('xyz') # => #<MatchData "xyz">
-
-- <tt>{,</tt>_max_<tt>}</tt> - Matches _max_ or fewer times:
-
- /\w{,2}/.match('') # => #<MatchData "">
- /\w{,2}/.match('x') # => #<MatchData "x">
- /\w{,2}/.match('xyz') # => #<MatchData "xy">
-
-- <tt>{</tt>_min_<tt>,</tt>_max_<tt>}</tt> -
- Matches at least _min_ times and at most _max_ times:
-
- /\w{1,2}/.match('') # => nil
- /\w{1,2}/.match('x') # => #<MatchData "x">
- /\w{1,2}/.match('xyz') # => #<MatchData "xy">
-
-==== Greedy, Lazy, or Possessive Matching
-
-Quantifier matching may be greedy, lazy, or possessive:
-
-- In _greedy_ matching, as many occurrences as possible are matched
- while still allowing the overall match to succeed.
- Greedy quantifiers: <tt>*</tt>, <tt>+</tt>, <tt>?</tt>,
- <tt>{min, max}</tt> and its variants.
-- In _lazy_ matching, the minimum number of occurrences are matched.
- Lazy quantifiers: <tt>*?</tt>, <tt>+?</tt>, <tt>??</tt>,
- <tt>{min, max}?</tt> and its variants.
-- In _possessive_ matching, once a match is found, there is no backtracking;
- that match is retained, even if it jeopardises the overall match.
- Possessive quantifiers: <tt>*+</tt>, <tt>++</tt>, <tt>?+</tt>.
- Note that <tt>{min, max}</tt> and its variants do _not_ support possessive matching.
-
-More:
-
-- About greedy and lazy matching, see
- {Choosing Minimal or Maximal Repetition}[https://doc.lagout.org/programmation/Regular%20Expressions/Regular%20Expressions%20Cookbook_%20Detailed%20Solutions%20in%20Eight%20Programming%20Languages%20%282nd%20ed.%29%20%5BGoyvaerts%20%26%20Levithan%202012-09-06%5D.pdf#tutorial-backtrack].
-- About possessive matching, see
- {Eliminate Needless Backtracking}[https://doc.lagout.org/programmation/Regular%20Expressions/Regular%20Expressions%20Cookbook_%20Detailed%20Solutions%20in%20Eight%20Programming%20Languages%20%282nd%20ed.%29%20%5BGoyvaerts%20%26%20Levithan%202012-09-06%5D.pdf#tutorial-backtrack].
-
-=== Groups and Captures
-
-A simple regexp has (at most) one match:
-
- re = /\d\d\d\d-\d\d-\d\d/
- re.match('1943-02-04') # => #<MatchData "1943-02-04">
- re.match('1943-02-04').size # => 1
- re.match('foo') # => nil
-
-Adding one or more pairs of parentheses, <tt>(_subexpression_)</tt>,
-defines _groups_, which may result in multiple matched substrings,
-called _captures_:
-
- re = /(\d\d\d\d)-(\d\d)-(\d\d)/
- re.match('1943-02-04') # => #<MatchData "1943-02-04" 1:"1943" 2:"02" 3:"04">
- re.match('1943-02-04').size # => 4
-
-The first capture is the entire matched string;
-the other captures are the matched substrings from the groups.
-
-A group may have a {quantifier}[rdoc-ref:Regexp@Quantifiers]:
-
- re = /July 4(th)?/
- re.match('July 4') # => #<MatchData "July 4" 1:nil>
- re.match('July 4th') # => #<MatchData "July 4th" 1:"th">
-
- re = /(foo)*/
- re.match('') # => #<MatchData "" 1:nil>
- re.match('foo') # => #<MatchData "foo" 1:"foo">
- re.match('foofoo') # => #<MatchData "foofoo" 1:"foo">
-
- re = /(foo)+/
- re.match('') # => nil
- re.match('foo') # => #<MatchData "foo" 1:"foo">
- re.match('foofoo') # => #<MatchData "foofoo" 1:"foo">
-
-The returned \MatchData object gives access to the matched substrings:
-
- re = /(\d\d\d\d)-(\d\d)-(\d\d)/
- md = re.match('1943-02-04')
- # => #<MatchData "1943-02-04" 1:"1943" 2:"02" 3:"04">
- md[0] # => "1943-02-04"
- md[1] # => "1943"
- md[2] # => "02"
- md[3] # => "04"
-
-==== Non-Capturing Groups
-
-A group may be made non-capturing;
-it is still a group (and, for example, can have a quantifier),
-but its matching substring is not included among the captures.
-
-A non-capturing group begins with <tt>?:</tt> (inside the parentheses):
-
- # Don't capture the year.
- re = /(?:\d\d\d\d)-(\d\d)-(\d\d)/
- md = re.match('1943-02-04') # => #<MatchData "1943-02-04" 1:"02" 2:"04">
-
-==== Backreferences
-
-A group match may also be referenced within the regexp itself;
-such a reference is called a +backreference+:
-
- /[csh](..) [csh]\1 in/.match('The cat sat in the hat')
- # => #<MatchData "cat sat in" 1:"at">
-
-This table shows how each subexpression in the regexp above
-matches a substring in the target string:
-
- | Subexpression in Regexp | Matching Substring in Target String |
- |---------------------------|-------------------------------------|
- | First '[csh]' | Character 'c' |
- | '(..)' | First substring 'at' |
- | First space ' ' | First space character ' ' |
- | Second '[csh]' | Character 's' |
- | '\1' (backreference 'at') | Second substring 'at' |
- | ' in' | Substring ' in' |
-
-A regexp may contain any number of groups:
-
-- For a large number of groups:
-
- - The ordinary <tt>\\_n_</tt> notation applies only for _n_ in range (1..9).
- - The <tt>MatchData[_n_]</tt> notation applies for any non-negative _n_.
-
-- <tt>\0</tt> is a special backreference, referring to the entire matched string;
- it may not be used within the regexp itself,
- but may be used outside it (for example, in a substitution method call):
-
- 'The cat sat in the hat'.gsub(/[csh]at/, '\0s')
- # => "The cats sats in the hats"
-
-==== Named Captures
-
-As seen above, a capture can be referred to by its number.
-A capture can also have a name,
-prefixed as <tt>?<_name_></tt> or <tt>?'_name_'</tt>,
-and the name (symbolized) may be used as an index in <tt>MatchData[]</tt>:
-
- md = /\$(?<dollars>\d+)\.(?'cents'\d+)/.match("$3.67")
- # => #<MatchData "$3.67" dollars:"3" cents:"67">
- md[:dollars] # => "3"
- md[:cents] # => "67"
- # The capture numbers are still valid.
- md[2] # => "67"
-
-When a regexp contains a named capture, there are no unnamed captures:
-
- /\$(?<dollars>\d+)\.(\d+)/.match("$3.67")
- # => #<MatchData "$3.67" dollars:"3">
-
-A named group may be backreferenced as <tt>\k<_name_></tt>:
-
- /(?<vowel>[aeiou]).\k<vowel>.\k<vowel>/.match('ototomy')
- # => #<MatchData "ototo" vowel:"o">
-
-When (and only when) a regexp contains named capture groups
-and appears before the <tt>=~</tt> operator,
-the captured substrings are assigned to local variables with corresponding names:
-
- /\$(?<dollars>\d+)\.(?<cents>\d+)/ =~ '$3.67'
- dollars # => "3"
- cents # => "67"
-
-\Method Regexp#named_captures returns a hash of the capture names and substrings;
-method Regexp#names returns an array of the capture names.
-
-==== Atomic Grouping
-
-A group may be made _atomic_ with <tt>(?></tt>_subexpression_<tt>)</tt>.
-
-This causes the subexpression to be matched
-independently of the rest of the expression,
-so that the matched substring becomes fixed for the remainder of the match,
-unless the entire subexpression must be abandoned and subsequently revisited.
-
-In this way _subexpression_ is treated as a non-divisible whole.
-Atomic grouping is typically used to optimise patterns
-to prevent needless backtracking .
-
-Example (without atomic grouping):
-
- /".*"/.match('"Quote"') # => #<MatchData "\"Quote\"">
-
-Analysis:
-
-1. The leading subexpression <tt>"</tt> in the pattern matches the first character
- <tt>"</tt> in the target string.
-2. The next subexpression <tt>.*</tt> matches the next substring <tt>Quote“</tt>
- (including the trailing double-quote).
-3. Now there is nothing left in the target string to match
- the trailing subexpression <tt>"</tt> in the pattern;
- this would cause the overall match to fail.
-4. The matched substring is backtracked by one position: <tt>Quote</tt>.
-5. The final subexpression <tt>"</tt> now matches the final substring <tt>"</tt>,
- and the overall match succeeds.
-
-If subexpression <tt>.*</tt> is grouped atomically,
-the backtracking is disabled, and the overall match fails:
-
- /"(?>.*)"/.match('"Quote"') # => nil
-
-Atomic grouping can affect performance;
-see {Atomic Group}[https://www.regular-expressions.info/atomic.html].
-
-==== Subexpression Calls
-
-As seen above, a backreference number (<tt>\\_n_</tt>) or name (<tt>\k<_name_></tt>)
-gives access to a captured _substring_;
-the corresponding regexp _subexpression_ may also be accessed,
-via the number (<tt>\\g<i>n</i></tt>) or name (<tt>\g<_name_></tt>):
-
- /\A(?<paren>\(\g<paren>*\))*\z/.match('(())')
- # ^1
- # ^2
- # ^3
- # ^4
- # ^5
- # ^6
- # ^7
- # ^8
- # ^9
- # ^10
-
-The pattern:
-
-1. Matches at the beginning of the string, i.e. before the first character.
-2. Enters a named group +paren+.
-3. Matches the first character in the string, <tt>'('</tt>.
-4. Calls the +paren+ group again, i.e. recurses back to the second step.
-5. Re-enters the +paren+ group.
-6. Matches the second character in the string, <tt>'('</tt>.
-7. Attempts to call +paren+ a third time,
- but fails because doing so would prevent an overall successful match.
-8. Matches the third character in the string, <tt>')'</tt>;
- marks the end of the second recursive call
-9. Matches the fourth character in the string, <tt>')'</tt>.
-10. Matches the end of the string.
-
-See {Subexpression calls}[https://learnbyexample.github.io/Ruby_Regexp/groupings-and-backreferences.html?highlight=subexpression#subexpression-calls].
-
-==== Conditionals
-
-The conditional construct takes the form <tt>(?(_cond_)_yes_|_no_)</tt>, where:
-
-- _cond_ may be a capture number or name.
-- The match to be applied is _yes_ if _cond_ is captured;
- otherwise the match to be applied is _no_.
-- If not needed, <tt>|_no_</tt> may be omitted.
-
-Examples:
-
- re = /\A(foo)?(?(1)(T)|(F))\z/
- re.match('fooT') # => #<MatchData "fooT" 1:"foo" 2:"T" 3:nil>
- re.match('F') # => #<MatchData "F" 1:nil 2:nil 3:"F">
- re.match('fooF') # => nil
- re.match('T') # => nil
-
- re = /\A(?<xyzzy>foo)?(?(<xyzzy>)(T)|(F))\z/
- re.match('fooT') # => #<MatchData "fooT" xyzzy:"foo">
- re.match('F') # => #<MatchData "F" xyzzy:nil>
- re.match('fooF') # => nil
- re.match('T') # => nil
-
-
-==== Absence Operator
-
-The absence operator is a special group that matches anything which does _not_ match the contained subexpressions.
-
- /(?~real)/.match('surrealist') # => #<MatchData "surrea">
- /(?~real)ist/.match('surrealist') # => #<MatchData "ealist">
- /sur(?~real)ist/.match('surrealist') # => nil
-
-=== Unicode
-
-==== Unicode Properties
-
-The <tt>/\p{_property_name_}/</tt> construct (with lowercase +p+)
-matches characters using a Unicode property name,
-much like a character class;
-property +Alpha+ specifies alphabetic characters:
-
- /\p{Alpha}/.match('a') # => #<MatchData "a">
- /\p{Alpha}/.match('1') # => nil
-
-A property can be inverted
-by prefixing the name with a caret character (<tt>^</tt>):
-
- /\p{^Alpha}/.match('1') # => #<MatchData "1">
- /\p{^Alpha}/.match('a') # => nil
-
-Or by using <tt>\P</tt> (uppercase +P+):
-
- /\P{Alpha}/.match('1') # => #<MatchData "1">
- /\P{Alpha}/.match('a') # => nil
-
-See {Unicode Properties}[rdoc-ref:regexp/unicode_properties.rdoc]
-for regexps based on the numerous properties.
-
-Some commonly-used properties correspond to POSIX bracket expressions:
-
-- <tt>/\p{Alnum}/</tt>: Alphabetic and numeric character
-- <tt>/\p{Alpha}/</tt>: Alphabetic character
-- <tt>/\p{Blank}/</tt>: Space or tab
-- <tt>/\p{Cntrl}/</tt>: Control character
-- <tt>/\p{Digit}/</tt>: Digit
- characters, and similar)
-- <tt>/\p{Lower}/</tt>: Lowercase alphabetical character
-- <tt>/\p{Print}/</tt>: Like <tt>\p{Graph}</tt>, but includes the space character
-- <tt>/\p{Punct}/</tt>: Punctuation character
-- <tt>/\p{Space}/</tt>: Whitespace character (<tt>[:blank:]</tt>, newline,
- carriage return, etc.)
-- <tt>/\p{Upper}/</tt>: Uppercase alphabetical
-- <tt>/\p{XDigit}/</tt>: Digit allowed in a hexadecimal number (i.e., 0-9a-fA-F)
-
-These are also commonly used:
-
-- <tt>/\p{Emoji}/</tt>: Unicode emoji.
-- <tt>/\p{Graph}/</tt>: Non-blank character
- (excludes spaces, control characters, and similar).
-- <tt>/\p{Word}/</tt>: A member in one of these Unicode character
- categories (see below) or having one of these Unicode properties:
-
- - Unicode categories:
- - +Mark+ (+M+).
- - <tt>Decimal Number</tt> (+Nd+)
- - <tt>Connector Punctuation</tt> (+Pc+).
-
- - Unicode properties:
- - +Alpha+
- - <tt>Join_Control</tt>
-
-- <tt>/\p{ASCII}/</tt>: A character in the ASCII character set.
-- <tt>/\p{Any}/</tt>: Any Unicode character (including unassigned characters).
-- <tt>/\p{Assigned}/</tt>: An assigned character.
-
-==== Unicode Character Categories
-
-A Unicode character category name:
-
-- May be either its full name or its abbreviated name.
-- Is case-insensitive.
-- Treats a space, a hyphen, and an underscore as equivalent.
-
-Examples:
-
- /\p{lu}/ # => /\p{lu}/
- /\p{LU}/ # => /\p{LU}/
- /\p{Uppercase Letter}/ # => /\p{Uppercase Letter}/
- /\p{Uppercase_Letter}/ # => /\p{Uppercase_Letter}/
- /\p{UPPERCASE-LETTER}/ # => /\p{UPPERCASE-LETTER}/
-
-Below are the Unicode character category abbreviations and names.
-Enumerations of characters in each category are at the links.
-
-Letters:
-
-- +L+, +Letter+: +LC+, +Lm+, or +Lo+.
-- +LC+, +Cased_Letter+: +Ll+, +Lt+, or +Lu+.
-- {Lu, Lowercase_Letter}[https://www.compart.com/en/unicode/category/Ll].
-- {Lu, Modifier_Letter}[https://www.compart.com/en/unicode/category/Lm].
-- {Lu, Other_Letter}[https://www.compart.com/en/unicode/category/Lo].
-- {Lu, Titlecase_Letter}[https://www.compart.com/en/unicode/category/Lt].
-- {Lu, Uppercase_Letter}[https://www.compart.com/en/unicode/category/Lu].
-
-Marks:
-
-- +M+, +Mark+: +Mc+, +Me+, or +Mn+.
-- {Mc, Spacing_Mark}[https://www.compart.com/en/unicode/category/Mc].
-- {Me, Enclosing_Mark}[https://www.compart.com/en/unicode/category/Me].
-- {Mn, Nonapacing_Mark}[https://www.compart.com/en/unicode/category/Mn].
-
-Numbers:
-
-- +N+, +Number+: +Nd+, +Nl+, or +No+.
-- {Nd, Decimal_Number}[https://www.compart.com/en/unicode/category/Nd].
-- {Nl, Letter_Number}[https://www.compart.com/en/unicode/category/Nl].
-- {No, Other_Number}[https://www.compart.com/en/unicode/category/No].
-
-Punctation:
-
-- +P+, +Punctuation+: +Pc+, +Pd+, +Pe+, +Pf+, +Pi+, +Po+, or +Ps+.
-- {Pc, Connector_Punctuation}[https://www.compart.com/en/unicode/category/Pc].
-- {Pd, Dash_Punctuation}[https://www.compart.com/en/unicode/category/Pd].
-- {Pe, Close_Punctuation}[https://www.compart.com/en/unicode/category/Pe].
-- {Pf, Final_Punctuation}[https://www.compart.com/en/unicode/category/Pf].
-- {Pi, Initial_Punctuation}[https://www.compart.com/en/unicode/category/Pi].
-- {Po, Other_Punctuation}[https://www.compart.com/en/unicode/category/Po].
-- {Ps, Open_Punctuation}[https://www.compart.com/en/unicode/category/Ps].
-
-- +S+, +Symbol+: +Sc+, +Sk+, +Sm+, or +So+.
-- {Sc, Currency_Symbol}[https://www.compart.com/en/unicode/category/Sc].
-- {Sk, Modifier_Symbol}[https://www.compart.com/en/unicode/category/Sk].
-- {Sm, Math_Symbol}[https://www.compart.com/en/unicode/category/Sm].
-- {So, Other_Symbol}[https://www.compart.com/en/unicode/category/So].
-
-- +Z+, +Separator+: +Zl+, +Zp+, or +Zs+.
-- {Zl, Line_Separator}[https://www.compart.com/en/unicode/category/Zl].
-- {Zp, Paragraph_Separator}[https://www.compart.com/en/unicode/category/Zp].
-- {Zs, Space_Separator}[https://www.compart.com/en/unicode/category/Zs].
-
-- +C+, +Other+: +Cc+, +Cf+, +Cn+, +Co+, or +Cs+.
-- {Cc, Control}[https://www.compart.com/en/unicode/category/Cc].
-- {Cf, Format}[https://www.compart.com/en/unicode/category/Cf].
-- {Cn, Unassigned}[https://www.compart.com/en/unicode/category/Cn].
-- {Co, Private_Use}[https://www.compart.com/en/unicode/category/Co].
-- {Cs, Surrogate}[https://www.compart.com/en/unicode/category/Cs].
-
-==== Unicode Scripts and Blocks
-
-Among the Unicode properties are:
-
-- {Unicode scripts}[https://en.wikipedia.org/wiki/Script_(Unicode)];
- see {supported scripts}[https://www.unicode.org/standard/supported.html].
-- {Unicode blocks}[https://en.wikipedia.org/wiki/Unicode_block];
- see {supported blocks}[http://www.unicode.org/Public/UNIDATA/Blocks.txt].
-
-=== POSIX Bracket Expressions
-
-A POSIX <i>bracket expression</i> is also similar to a character class.
-These expressions provide a portable alternative to the above,
-with the added benefit of encompassing non-ASCII characters:
-
-- <tt>/\d/</tt> matches only ASCII decimal digits +0+ through +9+.
-- <tt>/[[:digit:]]/</tt> matches any character in the Unicode
- <tt>Decimal Number</tt> (+Nd+) category;
- see below.
-
-The POSIX bracket expressions:
-
-- <tt>/[[:digit:]]/</tt>: Matches a {Unicode digit}[https://www.compart.com/en/unicode/category/Nd]:
-
- /[[:digit:]]/.match('9') # => #<MatchData "9">
- /[[:digit:]]/.match("\u1fbf9") # => #<MatchData "9">
-
-- <tt>/[[:xdigit:]]/</tt>: Matches a digit allowed in a hexadecimal number;
- equivalent to <tt>[0-9a-fA-F]</tt>.
-
-- <tt>/[[:upper:]]/</tt>: Matches a {Unicode uppercase letter}[https://www.compart.com/en/unicode/category/Lu]:
-
- /[[:upper:]]/.match('A') # => #<MatchData "A">
- /[[:upper:]]/.match("\u00c6") # => #<MatchData "Æ">
-
-- <tt>/[[:lower:]]/</tt>: Matches a {Unicode lowercase letter}[https://www.compart.com/en/unicode/category/Ll]:
-
- /[[:lower:]]/.match('a') # => #<MatchData "a">
- /[[:lower:]]/.match("\u01fd") # => #<MatchData "ǽ">
-
-- <tt>/[[:alpha:]]/</tt>: Matches <tt>/[[:upper:]]/</tt> or <tt>/[[:lower:]]/</tt>.
-
-- <tt>/[[:alnum:]]/</tt>: Matches <tt>/[[:alpha:]]/</tt> or <tt>/[[:digit:]]/</tt>.
-
-- <tt>/[[:space:]]/</tt>: Matches {Unicode space character}[https://www.compart.com/en/unicode/category/Zs]:
-
- /[[:space:]]/.match(' ') # => #<MatchData " ">
- /[[:space:]]/.match("\u2005") # => #<MatchData " ">
-
-- <tt>/[[:blank:]]/</tt>: Matches <tt>/[[:space:]]/</tt> or tab character:
-
- /[[:blank:]]/.match(' ') # => #<MatchData " ">
- /[[:blank:]]/.match("\u2005") # => #<MatchData " ">
- /[[:blank:]]/.match("\t") # => #<MatchData "\t">
-
-- <tt>/[[:cntrl:]]/</tt>: Matches {Unicode control character}[https://www.compart.com/en/unicode/category/Cc]:
-
- /[[:cntrl:]]/.match("\u0000") # => #<MatchData "\u0000">
- /[[:cntrl:]]/.match("\u009f") # => #<MatchData "\u009F">
-
-- <tt>/[[:graph:]]/</tt>: Matches any character
- except <tt>/[[:space:]]/</tt> or <tt>/[[:cntrl:]]/</tt>.
-
-- <tt>/[[:print:]]/</tt>: Matches <tt>/[[:graph:]]/</tt> or space character.
-
-- <tt>/[[:punct:]]/</tt>: Matches any (Unicode punctuation character}[https://www.compart.com/en/unicode/category/Po]:
-
-Ruby also supports these (non-POSIX) bracket expressions:
-
-- <tt>/[[:ascii:]]/</tt>: Matches a character in the ASCII character set.
-- <tt>/[[:word:]]/</tt>: Matches a character in one of these Unicode character
- categories or having one of these Unicode properties:
-
- - Unicode categories:
- - +Mark+ (+M+).
- - <tt>Decimal Number</tt> (+Nd+)
- - <tt>Connector Punctuation</tt> (+Pc+).
-
- - Unicode properties:
- - +Alpha+
- - <tt>Join_Control</tt>
-
-=== Comments
-
-A comment may be included in a regexp pattern
-using the <tt>(?#</tt>_comment_<tt>)</tt> construct,
-where _comment_ is a substring that is to be ignored.
-arbitrary text ignored by the regexp engine:
-
- /foo(?#Ignore me)bar/.match('foobar') # => #<MatchData "foobar">
-
-The comment may not include an unescaped terminator character.
-
-See also {Extended Mode}[rdoc-ref:Regexp@Extended+Mode].
-
-== Modes
-
-Each of these modifiers sets a mode for the regexp:
-
-- +i+: <tt>/_pattern_/i</tt> sets
- {Case-Insensitive Mode}[rdoc-ref:Regexp@Case-Insensitive+Mode].
-- +m+: <tt>/_pattern_/m</tt> sets
- {Multiline Mode}[rdoc-ref:Regexp@Multiline+Mode].
-- +x+: <tt>/_pattern_/x</tt> sets
- {Extended Mode}[rdoc-ref:Regexp@Extended+Mode].
-- +o+: <tt>/_pattern_/o</tt> sets
- {Interpolation Mode}[rdoc-ref:Regexp@Interpolation+Mode].
-
-Any, all, or none of these may be applied.
-
-Modifiers +i+, +m+, and +x+ may be applied to subexpressions:
-
-- <tt>(?_modifier_)</tt> turns the mode "on" for ensuing subexpressions
-- <tt>(?-_modifier_)</tt> turns the mode "off" for ensuing subexpressions
-- <tt>(?_modifier_:_subexp_)</tt> turns the mode "on" for _subexp_ within the group
-- <tt>(?-_modifier_:_subexp_)</tt> turns the mode "off" for _subexp_ within the group
-
-Example:
-
- re = /(?i)te(?-i)st/
- re.match('test') # => #<MatchData "test">
- re.match('TEst') # => #<MatchData "TEst">
- re.match('TEST') # => nil
- re.match('teST') # => nil
-
- re = /t(?i:e)st/
- re.match('test') # => #<MatchData "test">
- re.match('tEst') # => #<MatchData "tEst">
- re.match('tEST') # => nil
-
-\Method Regexp#options returns an integer whose value showing
-the settings for case-insensitivity mode, multiline mode, and extended mode.
-
-=== Case-Insensitive Mode
-
-By default, a regexp is case-sensitive:
-
- /foo/.match('FOO') # => nil
-
-Modifier +i+ enables case-insensitive mode:
-
- /foo/i.match('FOO')
- # => #<MatchData "FOO">
-
-\Method Regexp#casefold? returns whether the mode is case-insensitive.
-
-=== Multiline Mode
-
-The multiline-mode in Ruby is what is commonly called a "dot-all mode":
-
-- Without the +m+ modifier, the subexpression <tt>.</tt> does not match newlines:
-
- /a.c/.match("a\nc") # => nil
-
-- With the modifier, it does match:
-
- /a.c/m.match("a\nc") # => #<MatchData "a\nc">
-
-Unlike other languages, the modifier +m+ does not affect the anchors <tt>^</tt> and <tt>$</tt>.
-These anchors always match at line-boundaries in Ruby.
-
-=== Extended Mode
-
-Modifier +x+ enables extended mode, which means that:
-
-- Literal white space in the pattern is to be ignored.
-- Character <tt>#</tt> marks the remainder of its containing line as a comment,
- which is also to be ignored for matching purposes.
-
-In extended mode, whitespace and comments may be used
-to form a self-documented regexp.
-
-Regexp not in extended mode (matches some Roman numerals):
-
- pattern = '^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$'
- re = /#{pattern}/
- re.match('MCMXLIII') # => #<MatchData "MCMXLIII" 1:"CM" 2:"XL" 3:"III">
-
-Regexp in extended mode:
-
- pattern = <<-EOT
- ^ # beginning of string
- M{0,3} # thousands - 0 to 3 Ms
- (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 Cs),
- # or 500-800 (D, followed by 0 to 3 Cs)
- (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 Xs),
- # or 50-80 (L, followed by 0 to 3 Xs)
- (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 Is),
- # or 5-8 (V, followed by 0 to 3 Is)
- $ # end of string
- EOT
- re = /#{pattern}/x
- re.match('MCMXLIII') # => #<MatchData "MCMXLIII" 1:"CM" 2:"XL" 3:"III">
-
-=== Interpolation Mode
-
-Modifier +o+ means that the first time a literal regexp with interpolations
-is encountered,
-the generated Regexp object is saved and used for all future evaluations
-of that literal regexp.
-Without modifier +o+, the generated Regexp is not saved,
-so each evaluation of the literal regexp generates a new Regexp object.
-
-Without modifier +o+:
-
- def letters; sleep 5; /[A-Z][a-z]/; end
- words = %w[abc def xyz]
- start = Time.now
- words.each {|word| word.match(/\A[#{letters}]+\z/) }
- Time.now - start # => 15.0174892
-
-With modifier +o+:
-
- start = Time.now
- words.each {|word| word.match(/\A[#{letters}]+\z/o) }
- Time.now - start # => 5.0010866
-
-Note that if the literal regexp does not have interpolations,
-the +o+ behavior is the default.
-
-== Encodings
-
-By default, a regexp with only US-ASCII characters has US-ASCII encoding:
-
- re = /foo/
- re.source.encoding # => #<Encoding:US-ASCII>
- re.encoding # => #<Encoding:US-ASCII>
-
-A regular expression containing non-US-ASCII characters
-is assumed to use the source encoding.
-This can be overridden with one of the following modifiers.
-
-- <tt>/_pat_/n</tt>: US-ASCII if only containing US-ASCII characters,
- otherwise ASCII-8BIT:
-
- /foo/n.encoding # => #<Encoding:US-ASCII>
- /foo\xff/n.encoding # => #<Encoding:ASCII-8BIT>
- /foo\x7f/n.encoding # => #<Encoding:US-ASCII>
-
-- <tt>/_pat_/u</tt>: UTF-8
-
- /foo/u.encoding # => #<Encoding:UTF-8>
-
-- <tt>/_pat_/e</tt>: EUC-JP
-
- /foo/e.encoding # => #<Encoding:EUC-JP>
-
-- <tt>/_pat_/s</tt>: Windows-31J
-
- /foo/s.encoding # => #<Encoding:Windows-31J>
-
-A regexp can be matched against a target string when either:
-
-- They have the same encoding.
-- The regexp's encoding is a fixed encoding and the string
- contains only ASCII characters.
- Method Regexp#fixed_encoding? returns whether the regexp
- has a <i>fixed</i> encoding.
-
-If a match between incompatible encodings is attempted an
-<tt>Encoding::CompatibilityError</tt> exception is raised.
-
-Example:
-
- re = eval("# encoding: ISO-8859-1\n/foo\\xff?/")
- re.encoding # => #<Encoding:ISO-8859-1>
- re =~ "foo".encode("UTF-8") # => 0
- re =~ "foo\u0100" # Raises Encoding::CompatibilityError
-
-The encoding may be explicitly fixed by including Regexp::FIXEDENCODING
-in the second argument for Regexp.new:
-
- # Regexp with encoding ISO-8859-1.
- re = Regexp.new("a".force_encoding('iso-8859-1'), Regexp::FIXEDENCODING)
- re.encoding # => #<Encoding:ISO-8859-1>
- # Target string with encoding UTF-8.
- s = "a\u3042"
- s.encoding # => #<Encoding:UTF-8>
- re.match(s) # Raises Encoding::CompatibilityError.
-
-== Timeouts
-
-When either a regexp source or a target string comes from untrusted input,
-malicious values could become a denial-of-service attack;
-to prevent such an attack, it is wise to set a timeout.
-
-\Regexp has two timeout values:
-
-- A class default timeout, used for a regexp whose instance timeout is +nil+;
- this default is initially +nil+, and may be set by method Regexp.timeout=:
-
- Regexp.timeout # => nil
- Regexp.timeout = 3.0
- Regexp.timeout # => 3.0
-
-- An instance timeout, which defaults to +nil+ and may be set in Regexp.new:
-
- re = Regexp.new('foo', timeout: 5.0)
- re.timeout # => 5.0
-
-When regexp.timeout is +nil+, the timeout "falls through" to Regexp.timeout;
-when regexp.timeout is non-+nil+, that value controls timing out:
-
- | regexp.timeout Value | Regexp.timeout Value | Result |
- |----------------------|----------------------|-----------------------------|
- | nil | nil | Never times out. |
- | nil | Float | Times out in Float seconds. |
- | Float | Any | Times out in Float seconds. |
-
-== Optimization
-
-For certain values of the pattern and target string,
-matching time can grow polynomially or exponentially in relation to the input size;
-the potential vulnerability arising from this is the {regular expression denial-of-service}[https://en.wikipedia.org/wiki/ReDoS] (ReDoS) attack.
-
-\Regexp matching can apply an optimization to prevent ReDoS attacks.
-When the optimization is applied, matching time increases linearly (not polynomially or exponentially)
-in relation to the input size, and a ReDoS attach is not possible.
-
-This optimization is applied if the pattern meets these criteria:
-
-- No backreferences.
-- No subexpression calls.
-- No nested lookaround anchors or atomic groups.
-- No nested quantifiers with counting (i.e. no nested <tt>{n}</tt>,
- <tt>{min,}</tt>, <tt>{,max}</tt>, or <tt>{min,max}</tt> style quantifiers)
-
-You can use method Regexp.linear_time? to determine whether a pattern meets these criteria:
-
- Regexp.linear_time?(/a*/) # => true
- Regexp.linear_time?('a*') # => true
- Regexp.linear_time?(/(a*)\1/) # => false
-
-However, an untrusted source may not be safe even if the method returns +true+,
-because the optimization uses memoization (which may invoke large memory consumption).
-
-== References
-
-Read (online PDF books):
-
-- {Mastering Regular Expressions}[https://ia902508.us.archive.org/10/items/allitebooks-02/Mastering%20Regular%20Expressions%2C%203rd%20Edition.pdf]
- by Jeffrey E.F. Friedl.
-- {Regular Expressions Cookbook}[https://doc.lagout.org/programmation/Regular%20Expressions/Regular%20Expressions%20Cookbook_%20Detailed%20Solutions%20in%20Eight%20Programming%20Languages%20%282nd%20ed.%29%20%5BGoyvaerts%20%26%20Levithan%202012-09-06%5D.pdf]
- by Jan Goyvaerts & Steven Levithan.
-
-Explore, test (interactive online editor):
-
-- {Rubular}[https://rubular.com/].
diff --git a/doc/_timezones.rdoc b/doc/_timezones.rdoc
deleted file mode 100644
index c5230ea67d..0000000000
--- a/doc/_timezones.rdoc
+++ /dev/null
@@ -1,156 +0,0 @@
-== Timezone Specifiers
-
-Certain +Time+ methods accept arguments that specify timezones:
-
-- Time.at: keyword argument +in:+.
-- Time.new: positional argument +zone+ or keyword argument +in:+.
-- Time.now: keyword argument +in:+.
-- Time#getlocal: positional argument +zone+.
-- Time#localtime: positional argument +zone+.
-
-The value given with any of these must be one of the following
-(each detailed below):
-
-- {Hours/minutes offset}[rdoc-ref:Time@Hours-2FMinutes+Offsets].
-- {Single-letter offset}[rdoc-ref:Time@Single-Letter+Offsets].
-- {Integer offset}[rdoc-ref:Time@Integer+Offsets].
-- {Timezone object}[rdoc-ref:Time@Timezone+Objects].
-- {Timezone name}[rdoc-ref:Time@Timezone+Names].
-
-=== Hours/Minutes Offsets
-
-The zone value may be a string offset from UTC
-in the form <tt>'+HH:MM'</tt> or <tt>'-HH:MM'</tt>,
-where:
-
-- +HH+ is the 2-digit hour in the range <tt>0..23</tt>.
-- +MM+ is the 2-digit minute in the range <tt>0..59</tt>.
-
-Examples:
-
- t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
- Time.at(t, in: '-23:59') # => 1999-12-31 20:16:01 -2359
- Time.at(t, in: '+23:59') # => 2000-01-02 20:14:01 +2359
-
-=== Single-Letter Offsets
-
-The zone value may be a letter in the range <tt>'A'..'I'</tt>
-or <tt>'K'..'Z'</tt>;
-see {List of military time zones}[https://en.wikipedia.org/wiki/List_of_military_time_zones]:
-
- t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
- Time.at(t, in: 'A') # => 2000-01-01 21:15:01 +0100
- Time.at(t, in: 'I') # => 2000-01-02 05:15:01 +0900
- Time.at(t, in: 'K') # => 2000-01-02 06:15:01 +1000
- Time.at(t, in: 'Y') # => 2000-01-01 08:15:01 -1200
- Time.at(t, in: 'Z') # => 2000-01-01 20:15:01 UTC
-
-=== \Integer Offsets
-
-The zone value may be an integer number of seconds
-in the range <tt>-86399..86399</tt>:
-
- t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
- Time.at(t, in: -86399) # => 1999-12-31 20:15:02 -235959
- Time.at(t, in: 86399) # => 2000-01-02 20:15:00 +235959
-
-=== Timezone Objects
-
-The zone value may be an object responding to certain timezone methods, an
-instance of {Timezone}[https://github.com/panthomakos/timezone] and
-{TZInfo}[https://tzinfo.github.io] for example.
-
-The timezone methods are:
-
-- +local_to_utc+:
-
- - Called when Time.new is invoked with +tz+
- as the value of positional argument +zone+ or keyword argument +in:+.
- - Argument: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects].
- - Returns: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects] in the UTC timezone.
-
-- +utc_to_local+:
-
- - Called when Time.at or Time.now is invoked with +tz+
- as the value for keyword argument +in:+,
- and when Time#getlocal or Time#localtime is called with +tz+
- as the value for positional argument +zone+.
- - Argument: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects].
- - Returns: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects] in the local timezone.
-
-A custom timezone class may have these instance methods,
-which will be called if defined:
-
-- +abbr+:
-
- - Called when Time#strftime is invoked with a format involving <tt>%Z</tt>.
- - Argument: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects].
- - Returns: a string abbreviation for the timezone name.
-
-- +dst?+:
-
- - Called when Time.at or Time.now is invoked with +tz+
- as the value for keyword argument +in:+,
- and when Time#getlocal or Time#localtime is called with +tz+
- as the value for positional argument +zone+.
- - Argument: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects].
- - Returns: whether the time is daylight saving time.
-
-- +name+:
-
- - Called when <tt>Marshal.dump(t)</tt> is invoked
- - Argument: none.
- - Returns: the string name of the timezone.
-
-==== +Time+-Like Objects
-
-A +Time+-like object is a container object capable of interfacing with
-timezone libraries for timezone conversion.
-
-The argument to the timezone conversion methods above will have attributes
-similar to Time, except that timezone related attributes are meaningless.
-
-The objects returned by +local_to_utc+ and +utc_to_local+ methods of the
-timezone object may be of the same class as their arguments, of arbitrary
-object classes, or of class Integer.
-
-For a returned class other than +Integer+, the class must have the
-following methods:
-
-- +year+
-- +mon+
-- +mday+
-- +hour+
-- +min+
-- +sec+
-- +isdst+
-- +to_i+
-
-For a returned +Integer+, its components, decomposed in UTC, are
-interpreted as times in the specified timezone.
-
-=== Timezone Names
-
-If the class (the receiver of class methods, or the class of the receiver
-of instance methods) has +find_timezone+ singleton method, this method is
-called to achieve the corresponding timezone object from a timezone name.
-
-For example, using {Timezone}[https://github.com/panthomakos/timezone]:
- class TimeWithTimezone < Time
- require 'timezone'
- def self.find_timezone(z) = Timezone[z]
- end
-
- TimeWithTimezone.now(in: "America/New_York") #=> 2023-12-25 00:00:00 -0500
- TimeWithTimezone.new("2023-12-25 America/New_York") #=> 2023-12-25 00:00:00 -0500
-
-Or, using {TZInfo}[https://tzinfo.github.io]:
- class TimeWithTZInfo < Time
- require 'tzinfo'
- def self.find_timezone(z) = TZInfo::Timezone.get(z)
- end
-
- TimeWithTZInfo.now(in: "America/New_York") #=> 2023-12-25 00:00:00 -0500
- TimeWithTZInfo.new("2023-12-25 America/New_York") #=> 2023-12-25 00:00:00 -0500
-
-You can define this method per subclasses, or on the toplevel Time class.
diff --git a/doc/bsearch.rdoc b/doc/bsearch.rdoc
index 90705853d7..ca8091fc0d 100644
--- a/doc/bsearch.rdoc
+++ b/doc/bsearch.rdoc
@@ -1,4 +1,4 @@
-= Binary Searching
+== Binary Searching
A few Ruby methods support binary searching in a collection:
diff --git a/doc/case_mapping.rdoc b/doc/case_mapping.rdoc
index 57c037b9d8..3c42154973 100644
--- a/doc/case_mapping.rdoc
+++ b/doc/case_mapping.rdoc
@@ -1,4 +1,4 @@
-= Case Mapping
+== Case Mapping
Some string-oriented methods use case mapping.
@@ -24,7 +24,7 @@ In Symbol:
- Symbol#swapcase
- Symbol#upcase
-== Default Case Mapping
+=== Default Case Mapping
By default, all of these methods use full Unicode case mapping,
which is suitable for most languages.
@@ -60,7 +60,7 @@ Case changes may not be reversible:
Case changing methods may not maintain Unicode normalization.
See String#unicode_normalize).
-== Options for Case Mapping
+=== Options for Case Mapping
Except for +casecmp+ and +casecmp?+,
each of the case-mapping methods listed above
diff --git a/doc/character_selectors.rdoc b/doc/character_selectors.rdoc
index 47cf242be7..e01b0e6a25 100644
--- a/doc/character_selectors.rdoc
+++ b/doc/character_selectors.rdoc
@@ -1,6 +1,6 @@
-= Character Selectors
+== Character Selectors
-== Character Selector
+=== Character Selector
A _character_ _selector_ is a string argument accepted by certain Ruby methods.
Each of these instance methods accepts one or more character selectors:
@@ -70,7 +70,7 @@ In a character selector, these three characters get special treatment:
"hello\r\nworld".delete("\\r") # => "hello\r\nwold"
"hello\r\nworld".delete("\\\r") # => "hello\nworld"
-== Multiple Character Selectors
+=== Multiple Character Selectors
These instance methods accept multiple character selectors:
diff --git a/doc/command_injection.rdoc b/doc/command_injection.rdoc
index ee33d4a04e..af09be23f0 100644
--- a/doc/command_injection.rdoc
+++ b/doc/command_injection.rdoc
@@ -1,4 +1,4 @@
-= Command Injection
+== Command Injection
Some Ruby core methods accept string data
that includes text to be executed as a system command.
@@ -7,27 +7,19 @@ They should not be called with unknown or unsanitized commands.
These methods include:
-- Kernel.exec
-- Kernel.spawn
- Kernel.system
- {\`command` (backtick method)}[rdoc-ref:Kernel#`]
(also called by the expression <tt>%x[command]</tt>).
-- IO.popen (when called with other than <tt>"-"</tt>).
-
-Some methods execute a system command only if the given path name starts
-with a <tt>|</tt>:
-
-- Kernel.open(command).
+- IO.popen(command).
- IO.read(command).
- IO.write(command).
- IO.binread(command).
- IO.binwrite(command).
- IO.readlines(command).
- IO.foreach(command).
-- URI.open(command).
Note that some of these methods do not execute commands when called
-from subclass +File+:
+from subclass \File:
- File.read(path).
- File.write(path).
diff --git a/doc/command_line/environment.md b/doc/command_line/environment.md
deleted file mode 100644
index abdfd5cfeb..0000000000
--- a/doc/command_line/environment.md
+++ /dev/null
@@ -1,173 +0,0 @@
-## Environment
-
-Certain command-line options affect the execution environment
-of the invoked Ruby program.
-
-### About the Examples
-
-The examples here use command-line option `-e`,
-which passes the Ruby code to be executed on the command line itself:
-
-```sh
-$ ruby -e 'puts "Hello, World."'
-```
-
-### Option `-C`
-
-The argument to option `-C` specifies a working directory
-for the invoked Ruby program;
-does not change the working directory for the current process:
-
-```sh
-$ basename `pwd`
-ruby
-$ ruby -C lib -e 'puts File.basename(Dir.pwd)'
-lib
-$ basename `pwd`
-ruby
-```
-
-Whitespace between the option and its argument may be omitted.
-
-### Option `-I`
-
-The argument to option `-I` specifies a directory
-to be added to the array in global variable `$LOAD_PATH`;
-the option may be given more than once:
-
-```sh
-$ pushd /tmp
-$ ruby -e 'p $LOAD_PATH.size'
-8
-$ ruby -I my_lib -I some_lib -e 'p $LOAD_PATH.size'
-10
-$ ruby -I my_lib -I some_lib -e 'p $LOAD_PATH.take(2)'
-["/tmp/my_lib", "/tmp/some_lib"]
-$ popd
-```
-
-Whitespace between the option and its argument may be omitted.
-
-### Option `-r`
-
-The argument to option `-r` specifies a library to be required
-before executing the Ruby program;
-the option may be given more than once:
-
-```sh
-$ ruby -e 'p defined?(JSON); p defined?(CSV)'
-nil
-nil
-$ ruby -r CSV -r JSON -e 'p defined?(JSON); p defined?(CSV)'
-"constant"
-"constant"
-```
-
-Whitespace between the option and its argument may be omitted.
-
-### Option `-0`
-
-Option `-0` defines the input record separator `$/`
-for the invoked Ruby program.
-
-The optional argument to the option must be octal digits,
-each in the range `0..7`;
-these digits are prefixed with digit `0` to form an octal value:
-
-- If no argument is given, the input record separator is `0x00`.
-- If the argument is `0`, the input record separator is `''`;
- see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values].
-- If the argument is in range `(1..0377)`,
- it becomes the character value of the input record separator `$/`.
-- Otherwise, the input record separator is `nil`.
-
-Examples:
-
-```sh
-$ ruby -0 -e 'p $/'
-"\x00"
-ruby -00 -e 'p $/'
-""
-$ ruby -012 -e 'p $/'
-"\n"
-$ ruby -015 -e 'p $/'
-"\r"
-$ ruby -0377 -e 'p $/'
-"\xFF"
-$ ruby -0400 -e 'p $/'
-nil
-```
-
-The option may not be separated from its argument by whitespace.
-
-### Option `-d`
-
-Some code in (or called by) the Ruby program may include statements or blocks
-conditioned by the global variable `$DEBUG` (e.g., `if $DEBUG`);
-these commonly write to `$stdout` or `$stderr`.
-
-The default value for `$DEBUG` is `false`;
-option `-d` (or `--debug`) sets it to `true`:
-
-```sh
-$ ruby -e 'p $DEBUG'
-false
-$ ruby -d -e 'p $DEBUG'
-true
-```
-
-### Option '-w'
-
-Option `-w` (lowercase letter) is equivalent to option `-W1` (uppercase letter).
-
-### Option `-W`
-
-Any Ruby code can create a <i>warning message</i> by calling method Kernel#warn;
-methods in the Ruby core and standard libraries can also create warning messages.
-Such a message may be printed on `$stderr`
-(or not, depending on certain settings).
-
-Option `-W` helps determine whether a particular warning message
-will be written,
-by setting the initial value of global variable `$-W`:
-
-- `-W0`: Sets `$-W` to `0` (silent; no warnings).
-- `-W1`: Sets `$-W` to `1` (moderate verbosity).
-- `-W2`: Sets `$-W` to `2` (high verbosity).
-- `-W`: Same as `-W2` (high verbosity).
-- Option not given: Same as `-W1` (moderate verbosity).
-
-The value of `$-W`, in turn, determines which warning messages (if any)
-are to be printed to `$stdout` (see Kernel#warn):
-
-```sh
-$ ruby -W1 -e 'p $foo'
-nil
-$ ruby -W2 -e 'p $foo'
--e:1: warning: global variable '$foo' not initialized
-nil
-```
-
-Ruby code may also define warnings for certain categories;
-these are the default settings for the defined categories:
-
-```
-Warning[:experimental] # => true
-Warning[:deprecated] # => false
-Warning[:performance] # => false
-```
-
-They may also be set:
-```
-Warning[:experimental] = false
-Warning[:deprecated] = true
-Warning[:performance] = true
-```
-
-You can suppress a category by prefixing `no-` to the category name:
-
-```
-$ ruby -W:no-experimental -e 'p IO::Buffer.new'
-#<IO::Buffer>
-```
-
diff --git a/doc/contributing/building_ruby.md b/doc/contributing/building_ruby.md
index 2b7a06baba..469c9d8361 100644
--- a/doc/contributing/building_ruby.md
+++ b/doc/contributing/building_ruby.md
@@ -1,142 +1,83 @@
# Building Ruby
-## Dependencies
+## Quick start guide
1. Install the prerequisite dependencies for building the CRuby interpreter:
* C compiler
-
- For RubyGems, you will also need:
-
- * [OpenSSL] 1.1.x or 3.0.x / [LibreSSL]
- * [libyaml] 0.1.7 or later
- * [zlib]
-
- If you want to build from the git repository, you will also need:
-
- * [autoconf] - 2.67 or later
- * [gperf] - 3.1 or later
- * Usually unneeded; only if you edit some source files using gperf
- * ruby - 3.0 or later
- * We can upgrade this version to system ruby version of the latest
- Ubuntu LTS.
+ * autoconf - 2.67 or later
+ * bison - 3.0 or later
+ * gperf - 3.0.3 or later
+ * ruby - 2.7 or later
2. Install optional, recommended dependencies:
- * [libffi] (to build fiddle)
- * [gmp] (if you wish to accelerate Bignum operations)
- * [rustc] - 1.58.0 or later, if you wish to build
- [YJIT](rdoc-ref:RubyVM::YJIT).
-
- If you installed the libraries needed for extensions (openssl, readline,
- libyaml, zlib) into other than the OS default place, typically using
- Homebrew on macOS, add `--with-EXTLIB-dir` options to `CONFIGURE_ARGS`
- environment variable.
-
- ``` shell
- export CONFIGURE_ARGS=""
- for ext in openssl readline libyaml zlib; do
- CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-$ext-dir=$(brew --prefix $ext)"
- done
- ```
+ * OpenSSL/LibreSSL
+ * readline/editline (libedit)
+ * zlib
+ * libffi
+ * libyaml
+ * libexecinfo (FreeBSD)
+ * rustc - 1.58.0 or later (if you wish to build [YJIT](/doc/yjit/yjit.md))
-[OpenSSL]: https://www.openssl.org
-[LibreSSL]: https://www.libressl.org
-[libyaml]: https://github.com/yaml/libyaml/
-[zlib]: https://www.zlib.net
-[autoconf]: https://www.gnu.org/software/autoconf/
-[gperf]: https://www.gnu.org/software/gperf/
-[libffi]: https://sourceware.org/libffi/
-[gmp]: https://gmplib.org
-[rustc]: https://www.rust-lang.org
+3. Checkout the CRuby source code:
-## Quick start guide
-
-1. Download ruby source code:
-
- Select one of the below.
-
- 1. Build from the tarball:
-
- Download the latest tarball from [Download Ruby] page and extract
- it. Example for Ruby 3.0.2:
-
- ``` shell
- tar -xzf ruby-3.0.2.tar.gz
- cd ruby-3.0.2
- ```
-
- 2. Build from the git repository:
-
- Checkout the CRuby source code:
-
- ``` shell
- git clone https://github.com/ruby/ruby.git
- cd ruby
- ```
+ ```
+ git clone https://github.com/ruby/ruby.git
+ ```
- Generate the configure file:
+4. Generate the configure file:
- ``` shell
- ./autogen.sh
- ```
+ ```
+ ./autogen.sh
+ ```
-2. Create a `build` directory separate from the source directory:
+5. Create a `build` directory outside of the source directory:
- ``` shell
+ ```
mkdir build && cd build
```
- While it's not necessary to build in a separate directory, it's good
- practice to do so.
+ While it's not necessary to build in a separate directory, it's good practice to do so.
-3. We'll install Ruby in `~/.rubies/ruby-master`, so create the directory:
+6. We'll install Ruby in `~/.rubies/ruby-master`, so create the directory:
- ``` shell
+ ```
mkdir ~/.rubies
```
-4. Run configure:
+7. Run configure:
- ``` shell
+ ```
../configure --prefix="${HOME}/.rubies/ruby-master"
```
- - Also `-C` (or `--config-cache`) would reduce time to configure from the
- next time.
+ - If you are frequently building Ruby, add the `--disable-install-doc` flag to not build documentation which will speed up the build process.
-5. Build Ruby:
+8. Build Ruby:
- ``` shell
- make
```
-
-6. [Run tests](testing_ruby.md) to confirm your build succeeded.
-
-7. Install Ruby:
-
- ``` shell
make install
```
- - If you need to run `make install` with `sudo` and want to avoid document
- generation with different permissions, you can use `make SUDO=sudo
- install`.
+ - If you're on macOS and installed \OpenSSL through Homebrew, you may encounter failure to build \OpenSSL that look like this:
-[Download Ruby]: https://www.ruby-lang.org/en/downloads/
+ ```
+ openssl:
+ Could not be configured. It will not be installed.
+ ruby/ext/openssl/extconf.rb: OpenSSL library could not be found. You might want to use --with-openssl-dir=<dir> option to specify the prefix where OpenSSL is installed.
+ Check ext/openssl/mkmf.log for more details.
+ ```
-### Unexplainable Build Errors
+ Adding `--with-openssl-dir=$(brew --prefix openssl)` to the list of options passed to configure may solve the issue.
-If you are having unexplainable build errors, after saving all your work, try
-running `git clean -xfd` in the source root to remove all git ignored local
-files. If you are working from a source directory that's been updated several
-times, you may have temporary build artifacts from previous releases which can
-cause build failures.
+ Remember to delete your `build` directory and start again from the configure step.
-## Building on Windows
+9. [Run tests](testing_ruby.md) to confirm your build succeeded.
-The documentation for building on Windows can be found in [the separated
-file](../windows.md).
+### Unexplainable Build Errors
+
+If you are having unexplainable build errors, after saving all your work, try running `git clean -xfd` in the source root to remove all git ignored local files. If you are working from a source directory that's been updated several times, you may have temporary build artifacts from previous releases which can cause build failures.
## More details
@@ -145,19 +86,16 @@ about Ruby's build to help out.
### Running make scripts in parallel
-In GNU make[^caution-gmake-3] and BSD make implementations, to run a specific make script in
-parallel, pass the flag `-j<number of processes>`. For instance, to run tests
-on 8 processes, use:
+In GNU make and BSD make implementations, to run a specific make script in parallel, pass the flag `-j<number of processes>`. For instance,
+to run tests on 8 processes, use:
-``` shell
+```
make test-all -j8
```
We can also set `MAKEFLAGS` to run _all_ `make` commands in parallel.
-Having the right `--jobs` flag will ensure all processors are utilized when
-building software projects. To do this effectively, you can set `MAKEFLAGS` in
-your shell configuration/profile:
+Having the right `--jobs` flag will ensure all processors are utilized when building software projects. To do this effectively, you can set `MAKEFLAGS` in your shell configuration/profile:
``` shell
# On macOS with Fish shell:
@@ -173,25 +111,20 @@ export MAKEFLAGS="--jobs "(nproc)
export MAKEFLAGS="--jobs $(nproc)"
```
-[^caution-gmake-3]: **CAUTION**: GNU make 3 is missing some features for parallel execution, we
-recommend to upgrade to GNU make 4 or later.
-
### Miniruby vs Ruby
-Miniruby is a version of Ruby which has no external dependencies and lacks
-certain features. It can be useful in Ruby development because it allows for
-faster build times. Miniruby is built before Ruby. A functional Miniruby is
-required to build Ruby. To build Miniruby:
+Miniruby is a version of Ruby which has no external dependencies and lacks certain features.
+It can be useful in Ruby development because it allows for faster build times. Miniruby is
+built before Ruby. A functional Miniruby is required to build Ruby. To build Miniruby:
-``` shell
+```
make miniruby
```
## Debugging
-You can use either lldb or gdb for debugging. Before debugging, you need to
-create a `test.rb` with the Ruby script you'd like to run. You can use the
-following make targets:
+You can use either lldb or gdb for debugging. Before debugging, you need to create a `test.rb`
+with the Ruby script you'd like to run. You can use the following make targets:
* `make run`: Runs `test.rb` using Miniruby
* `make lldb`: Runs `test.rb` using Miniruby in lldb
@@ -200,71 +133,25 @@ following make targets:
* `make lldb-ruby`: Runs `test.rb` using Ruby in lldb
* `make gdb-ruby`: Runs `test.rb` using Ruby in gdb
-### Compiling for Debugging
-
-You should configure Ruby without optimization and other flags that may
-interfere with debugging:
-
-``` shell
-./configure --enable-debug-env optflags="-O0 -fno-omit-frame-pointer"
-```
-
### Building with Address Sanitizer
-Using the address sanitizer (ASAN) is a great way to detect memory issues. It
-can detect memory safety issues in Ruby itself, and also in any C extensions
-compiled with and loaded into a Ruby compiled with ASAN.
+Using the address sanitizer is a great way to detect memory issues.
``` shell
./autogen.sh
mkdir build && cd build
-../configure CC=clang-18 cflags="-fsanitize=address -fno-omit-frame-pointer -DUSE_MN_THREADS=0" # and any other options you might like
+export ASAN_OPTIONS="halt_on_error=0:use_sigaltstack=0:detect_leaks=0"
+../configure cppflags="-fsanitize=address -fno-omit-frame-pointer" optflags=-O0 LDFLAGS="-fsanitize=address -fno-omit-frame-pointer"
make
```
-The compiled Ruby will now automatically crash with a report and a backtrace
-if ASAN detects a memory safety issue. To run Ruby's test suite under ASAN,
-issue the following command. Note that this will take quite a long time (over
-two hours on my laptop); the `RUBY_TEST_TIMEOUT_SCALE` and
-`SYNTAX_SUGEST_TIMEOUT` variables are required to make sure tests don't
-spuriously fail with timeouts when in fact they're just slow.
-
-``` shell
-RUBY_TEST_TIMEOUT_SCALE=5 SYNTAX_SUGGEST_TIMEOUT=600 make check
-```
-
-Please note, however, the following caveats!
-
-* ASAN will not work properly on any currently released version of Ruby; the
- necessary support is currently only present on Ruby's master branch (and the
- whole test suite passes only as of commit [Revision 9d0a5148]).
-* Due to [Bug #20243], Clang generates code for threadlocal variables which
- doesn't work with M:N threading. Thus, it's necessary to disable M:N
- threading support at build time for now (with the `-DUSE_MN_THREADS=0`
- configure argument).
-* ASAN will only work when using Clang version 18 or later - it requires
- [llvm/llvm-project#75290] related to multithreaded `fork`.
-* ASAN has only been tested so far with Clang on Linux. It may or may not work
- with other compilers or on other platforms - please file an issue on
- [Ruby Issue Tracking System] if you run into problems with such configurations
- (or, to report that they actually work properly!)
-* In particular, although I have not yet tried it, I have reason to believe
- ASAN will _not_ work properly on macOS yet - the fix for the multithreaded
- fork issue was actually reverted for macOS (see [llvm/llvm-project#75659]).
- Please open an issue on [Ruby Issue Tracking System] if this is a problem for
- you.
-
-[Revision 9d0a5148]: https://bugs.ruby-lang.org/projects/ruby-master/repository/git/revisions/9d0a5148ae062a0481a4a18fbeb9cfd01dc10428
-[Bug #20243]: https://bugs.ruby-lang.org/issues/20243
-[llvm/llvm-project#75290]: https://github.com/llvm/llvm-project/pull/75290
-[llvm/llvm-project#75659]: https://github.com/llvm/llvm-project/pull/75659#issuecomment-1861584777
-[Ruby Issue Tracking System]: https://bugs.ruby-lang.org
+On Linux it is important to specify `-O0` when debugging. This is especially true for ASAN which sometimes works incorrectly at higher optimisation levels.
## How to measure coverage of C and Ruby code
You need to be able to use gcc (gcov) and lcov visualizer.
-``` shell
+```
./autogen.sh
./configure --enable-gcov
make
@@ -275,12 +162,11 @@ make lcov
open lcov-out/index.html
```
-If you need only C code coverage, you can remove `COVERAGE=true` from the
-above process. You can also use `gcov` command directly to get per-file
-coverage.
+If you need only C code coverage, you can remove `COVERAGE=true` from the above process.
+You can also use `gcov` command directly to get per-file coverage.
-If you need only Ruby code coverage, you can remove `--enable-gcov`. Note
-that `test-coverage.dat` accumulates all runs of `make test-all`. Make sure
-that you remove the file if you want to measure one test run.
+If you need only Ruby code coverage, you can remove `--enable-gcov`.
+Note that `test-coverage.dat` accumulates all runs of `make test-all`.
+Make sure that you remove the file if you want to measure one test run.
You can see the coverage result of CI: https://rubyci.org/coverage
diff --git a/doc/contributing/documentation_guide.md b/doc/contributing/documentation_guide.md
index f93fc41165..9cfd59d629 100644
--- a/doc/contributing/documentation_guide.md
+++ b/doc/contributing/documentation_guide.md
@@ -20,16 +20,14 @@ build directory:
make html
```
-If you don't have a build directory, follow the [quick start
-guide](building_ruby.md#label-Quick+start+guide) up to step 4.
-
Then you can preview your changes by opening
`{build folder}/.ext/html/index.html` file in your browser.
+
## Goal
The goal of Ruby documentation is to impart the most important
-and relevant information in the shortest time.
+and relevant in the shortest time.
The reader should be able to quickly understand the usefulness
of the subject code and how to use it.
@@ -43,17 +41,16 @@ Use your judgment about what the user needs to know.
- Write short declarative or imperative sentences.
- Group sentences into (ideally short) paragraphs,
each covering a single topic.
-- Organize material with
- [headings](rdoc-ref:RDoc::MarkupReference@Headings).
+- Organize material with [headers](rdoc-ref:RDoc::Markup@Headers).
- Refer to authoritative and relevant sources using
- [links](rdoc-ref:RDoc::MarkupReference@Links).
+ [links](rdoc-ref:RDoc::Markup@Links).
- Use simple verb tenses: simple present, simple past, simple future.
- Use simple sentence structure, not compound or complex structure.
- Avoid:
- Excessive comma-separated phrases;
- consider a [list](rdoc-ref:RDoc::MarkupReference@Lists).
+ consider a [list](rdoc-ref:RDoc::Markup@Simple+Lists).
- Idioms and culture-specific references.
- - Overuse of headings.
+ - Overuse of headers.
- Using US-ASCII-incompatible characters in C source files;
see [Characters](#label-Characters) below.
@@ -127,23 +124,16 @@ a.shuffle! #=> [2, 3, 1]
a #=> [2, 3, 1]
```
-### Headings
-
-Organize a long discussion for a class or module with [headings](rdoc-ref:RDoc::MarkupReference@Headings).
+### Headers
-Do not use formal headings in the documentation for a method or constant.
-
-In the rare case where heading-like structures are needed
-within the documentation for a method or constant, use
-[bold text](rdoc-ref:RDoc::MarkupReference@Bold)
-as pseudo-headings.
+Organize a long discussion with [headers](rdoc-ref:RDoc::Markup@Headers).
### Blank Lines
A blank line begins a new paragraph.
-A [code block](rdoc-ref:RDoc::MarkupReference@Code+Blocks)
-or [list](rdoc-ref:RDoc::MarkupReference@Lists)
+A [code block](rdoc-ref:RDoc::Markup@Paragraphs+and+Verbatim)
+or [list](rdoc-ref:RDoc::Markup@Simple+Lists)
should be preceded by and followed by a blank line.
This is unnecessary for the HTML output, but helps in the `ri` output.
@@ -160,145 +150,19 @@ For a method name in text:
or a hash mark for an instance method:
<tt>Foo.bar</tt>, <tt>Foo#baz</tt>.
-### Embedded Code and Commands
-
-Code or commands embedded in running text (i.e., not in a code block)
-should marked up as
-[monofont](rdoc-ref:RDoc::MarkupReference@Monofont).
-
-Code that is a simple string should include the quote marks.
-
### Auto-Linking
-Most often, the name of a class, module, or method
-is auto-linked:
-
-```
-- Float.
-- Enumerable.
-- File.new
-- File#read.
-```
-renders as:
-
-> - Float.
-> - Enumerable.
-> - File.new
-> - File#read.
-
In general, \RDoc's auto-linking should not be suppressed.
-For example, we should write just plain _Float_ (which is auto-linked):
-
-```
-Returns a Float.
-```
-
-which renders as:
-
-> Returns a Float.
-
-However, _do_ suppress auto-linking when the word in question
-does not refer to a Ruby entity (e.g., some uses of _Class_ or _English_):
-
-```
-\Class variables can be tricky.
-```
-
-renders as:
-
-> \\Class variables can be tricky.
-
-Also, _do_ suppress auto-linking when the word in question
-refers to the current document
-(e.g., _Float_ in the documentation for class Float).
-
-In this case you may consider forcing the name to
-[monofont](rdoc-ref:RDoc::MarkupReference@Monofont),
-which suppresses auto-linking, and also emphasizes that the word is a class name:
-
-```
-A +Float+ object represents ....
-```
-
-renders as:
-
-> A `Float` object represents ....
-
-For a _very_ few, _very_ often-discussed classes,
-you might consider avoiding the capitalized class name altogether.
-For example, for some mentions of arrays,
-you might write simply the lowercase _array_.
-
-Instead of:
-
-```
-For an empty Array, ....
-```
-
-which renders as:
-
-> For an empty Array, ....
-
-you might write:
-
-```
-For an empty array, ....
-```
-
-which renders as:
-
-> For an empty array, ....
+For example, we should write `Array`, not `\Array`.
-This more casual usage avoids both auto-linking and distracting font changes,
-and is unlikely to cause confusion.
+We might consider whether to suppress when:
-This principle may be usefully applied, in particular, for:
-
-- An array.
-- An integer.
-- A hash.
-- A string.
-
-However, it should be applied _only_ when referring to an _instance_ of the class,
-and _never_ when referring to the class itself.
-
-### Explicit Links
-
-When writing an explicit link, follow these guidelines.
-
-#### +rdoc-ref+ Scheme
-
-Use the +rdoc-ref+ scheme for:
-
-- A link in core documentation to other core documentation.
-- A link in core documentation to documentation in a standard library package.
-- A link in a standard library package to other documentation in that same
- standard library package.
-
-See section "+rdoc-ref+ Scheme" in {Links}[rdoc-ref:RDoc::MarkupReference@Links].
-
-#### URL-Based Link
-
-Use a full URL-based link for:
-
-- A link in standard library documentation to documentation in the core.
-- A link in standard library documentation to documentation in a different
- standard library package.
-
-Doing so ensures that the link will valid even when the package documentation
-is built independently (separately from the core documentation).
-
-The link should lead to a target in https://docs.ruby-lang.org/en/master/.
-
-Also use a full URL-based link for a link to an off-site document.
-
-### Variable Names
-
-The name of a variable (as specified in its call-seq) should be marked up as
-[monofont](rdoc-ref:RDoc::MarkupReference@Monofont).
-
-Also, use monofont text for the name of a transient variable
-(i.e., one defined and used only in the discussion, such as +n+).
+- The word in question does not refer to a Ruby entity
+ (e.g., some uses of _Class_ or _English_).
+- The reference is to the current class document
+ (e.g., _Array_ in the documentation for class `Array`).
+- The same reference is repeated many times
+ (e.g., _RDoc_ on this page).
### HTML Tags
@@ -311,21 +175,16 @@ may not render them properly.
In particular, avoid building tables with HTML tags
(<tt><table></tt>, etc.).
-Alternatives:
-
-- A {verbatim text block}[rdoc-ref:RDoc::MarkupReference@Verbatim+Text+Blocks],
- using spaces and punctuation to format the text;
- note that {text markup}[rdoc-ref:RDoc::MarkupReference@Text+Markup]
- will not be honored:
+Alternatives are:
- - Example {source}[https://github.com/ruby/ruby/blob/34d802f32f00df1ac0220b62f72605827c16bad8/file.c#L6570-L6596].
- - Corresponding {output}[rdoc-ref:File@Read-2FWrite+Mode].
+- The GFM (GitHub Flavored Markdown) table extension,
+ which is enabled by default. See
+ {GFM tables extension}[https://github.github.com/gfm/#tables-extension-].
-- (Markdown format only): A {Github Flavored Markdown (GFM) table}[https://github.github.com/gfm/#tables-extension-],
- using special formatting for the text:
-
- - Example {source}[https://github.com/ruby/ruby/blob/34d802f32f00df1ac0220b62f72605827c16bad8/doc/contributing/glossary.md?plain=1].
- - Corresponding {output}[https://docs.ruby-lang.org/en/master/contributing/glossary_md.html].
+- A {verbatim text block}[rdoc-ref:RDoc::MarkupReference@Verbatim+Text+Blocks],
+ using spaces and punctuation to format the text.
+ Note that {text markup}[rdoc-ref:RDoc::MarkupReference@Text+Markup]
+ will not be honored.
## Documenting Classes and Modules
@@ -355,12 +214,9 @@ Guidelines:
- The section title is `What's Here`.
- Consider listing the parent class and any included modules; consider
- [links](rdoc-ref:RDoc::MarkupReference@Links)
+ [links](rdoc-ref:RDoc::Markup@Links)
to their "What's Here" sections if those exist.
-- All methods mentioned in the left-pane table of contents
- should be listed (including any methods extended from another class).
-- Attributes (which are not included in the TOC) may also be listed.
-- Display methods as items in one or more bullet lists:
+- List methods as a bullet list:
- Begin each item with the method name, followed by a colon
and a short description.
@@ -368,9 +224,9 @@ Guidelines:
(and do not list the aliases separately).
- Check the rendered documentation to determine whether \RDoc has recognized
the method and linked to it; if not, manually insert a
- [link](rdoc-ref:RDoc::MarkupReference@Links).
+ [link](rdoc-ref:RDoc::Markup@Links).
-- If there are numerous entries, consider grouping them into subsections with headings.
+- If there are numerous entries, consider grouping them into subsections with headers.
- If there are more than a few such subsections,
consider adding a table of contents just below the main section title.
@@ -382,10 +238,10 @@ The general structure of the method documentation should be:
- Calling sequence (for methods written in C).
- Synopsis (short description).
-- In-brief examples (optional)
- Details and examples.
- Argument description (if necessary).
- Corner cases and exceptions.
+- Aliases.
- Related methods (optional).
### Calling Sequence (for methods written in C)
@@ -394,7 +250,7 @@ For methods written in Ruby, \RDoc documents the calling sequence automatically.
For methods written in C, \RDoc cannot determine what arguments
the method accepts, so those need to be documented using \RDoc directive
-[`call-seq:`](rdoc-ref:RDoc::MarkupReference@Directives+for+Method+Documentation).
+[`call-seq:`](rdoc-ref:RDoc::Markup@Method+arguments).
For a singleton method, use the form:
@@ -426,18 +282,10 @@ For example, in Array, use:
```
```
-* call-seq:
+* call-seq:
* <=> other -> -1, 0, 1, or nil
```
-For a binary-operator style method (e.g., Array#&),
-cite `self` in the call-seq (not, e.g., `array` or `receiver`):
-
-```
-* call-seq:
-* self & other_array -> new_array
-```
-
Arguments:
- If the method does not accept arguments, omit the parentheses.
@@ -450,8 +298,7 @@ Arguments:
For example, use:
```
- * call-seq:
- * respond_to?(symbol, include_all = false) -> true or false
+ respond_to?(symbol, include_all = false) -> true or false
```
- If the behavior is different with an omitted or an explicit argument,
@@ -459,7 +306,6 @@ Arguments:
For example, in Enumerable, use:
```
- * call-seq:
* max -> element
* max(n) -> array
```
@@ -469,14 +315,6 @@ Block:
- If the method does not accept a block, omit the block.
- If the method accepts a block, the `call-seq` should have `{|args| ... }`,
not `{|args| block }` or `{|args| code }`.
-- If the method accepts a block, but returns an Enumerator when the block is omitted,
- the `call-seq` should show both forms:
-
- ```
- * call-seq:
- * array.select {|element| ... } -> new_array
- * array.select -> new_enumerator
- ```
Return types:
@@ -490,11 +328,7 @@ Return types:
Aliases:
-- Omit aliases from the `call-seq`, unless the alias is an
- operator method. If listing both a regular method and an
- operator method in the `call-seq`, explain in the details and
- examples section when it is recommended to use the regular method
- and when it is recommended to use the operator method.
+- Omit aliases from the `call-seq`, but mention them near the end (see below).
### Synopsis
@@ -513,16 +347,6 @@ This is great as it is short and descriptive. Avoid documenting
too much in the synopsis, stick to the most important information
for the benefit of the reader.
-### In-Brief Examples
-
-For a method whose documentation is lengthy,
-consider adding an "in-brief" passage,
-showing examples that summarize the method's uses.
-
-The passage may answer some users' questions
-(without their having to read long documentation);
-see Array#[] and Array#[]=.
-
### Details and Examples
Most non-trivial methods benefit from examples, as well as details
@@ -545,15 +369,6 @@ do not add an example if it provides the same information given
in the synopsis or details. The purpose of examples is not to prove
what the details are stating.
-Many methods that can take an optional block call the block if it is given,
-but return a new Enumerator if the block is not given;
-in that case, do not provide an example,
-but do state the fact (with the auto-linking uppercase Enumerator):
-
-```
-* With no block given, returns a new Enumerator.
-```
-
### Argument Description (if necessary)
For methods that require arguments, if not obvious and not explicitly
@@ -570,7 +385,7 @@ argument passed if it is not obvious, not explicitly mentioned in the
details, and not implicitly shown in the examples.
If there is more than one argument or block argument, use a
-[labeled list](rdoc-ref:RDoc::MarkupReference@Labeled+Lists).
+[labeled list](rdoc-ref:RDoc::Markup@Labeled+Lists).
### Corner Cases and Exceptions
@@ -583,6 +398,14 @@ you do not need to document that a `TypeError` is raised if a non-integer
is passed. Do not provide examples of exceptions being raised unless
that is a common case, such as `Hash#fetch` raising a `KeyError`.
+### Aliases
+
+Mention aliases in the form
+
+```
+// Array#find_index is an alias for Array#index.
+```
+
### Related Methods (optional)
In some cases, it is useful to document which methods are related to
diff --git a/doc/contributing/glossary.md b/doc/contributing/glossary.md
deleted file mode 100644
index 86c6671fbd..0000000000
--- a/doc/contributing/glossary.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# Ruby Internals Glossary
-
-Just a list of acronyms I've run across in the Ruby source code and their meanings.
-
-| Term | Definition |
-| --- | -----------|
-| `BIN` | Basic Instruction Name. Used as a macro to reference the YARV instruction. Converts pop into YARVINSN_pop. |
-| `bop` | Basic Operator. Relates to methods like `Integer` plus and minus which can be optimized as long as they haven't been redefined. |
-| `cc` | Call Cache. An inline cache structure for the call site. Stored in the `cd` |
-| `cd` | Call Data. A data structure that points at the `ci` and the `cc`. `iseq` objects points at the `cd`, and access call information and call caches via this structure |
-| `cfp`| Control Frame Pointer. Represents a Ruby stack frame. Calling a method pushes a new frame (cfp), returning pops a frame. Points at the `pc`, `sp`, `ep`, and the corresponding `iseq`|
-| `ci` | Call Information. Refers to an `rb_callinfo` struct. Contains call information about the call site, including number of parameters to be passed, whether it they are keyword arguments or not, etc. Used in conjunction with the `cc` and `cd`. |
-| `cref` | Class reference. A structure pointing to the class reference where `klass_or_self`, visibility scope, and refinements are stored. It also stores a pointer to the next class in the hierarchy referenced by `rb_cref_struct * next`. The Class reference is lexically scoped. |
-| CRuby | Implementation of Ruby written in C |
-| `cvar` | Class Variable. Refers to a Ruby class variable like `@@foo` |
-| `dvar` | Dynamic Variable. Used by the parser to refer to local variables that are defined outside of the current lexical scope. For example `def foo; bar = 1; -> { p bar }; end` the "bar" inside the block is a `dvar` |
-| `ec` | Execution Context. The top level VM context, points at the current `cfp` |
-| `ep` | Environment Pointer. Local variables, including method parameters are stored in the `ep` array. The `ep` is pointed to by the `cfp` |
-| GC | Garbage Collector |
-| `gvar` | Global Variable. Refers to a Ruby global variable like `$$`, etc |
-| `ICLASS` | Internal Class. When a module is included, the target class gets a new superclass which is an instance of an `ICLASS`. The `ICLASS` represents the module in the inheritance chain. |
-| `ifunc` | Internal FUNCtion. A block implemented in C. |
-| `iseq` | Instruction Sequence. Usually "iseq" in the C code will refer to an `rb_iseq_t` object that holds a reference to the actual instruction sequences which are executed by the VM. The object also holds information about the code, like the method name associated with the code. |
-| `insn` | Instruction. Refers to a YARV instruction. |
-| `insns` | Instructions. Usually an array of YARV instructions. |
-| `ivar` | Instance Variable. Refers to a Ruby instance variable like `@foo` |
-| `imemo` | Internal Memo. A tagged struct whose memory is managed by Ruby's GC, but contains internal information and isn't meant to be exposed to Ruby programs. Contains various information depending on the type. See the `imemo_type` enum for different types. |
-| JIT | Just In Time compiler |
-| `lep` | Local Environment Pointer. An `ep` which is tagged `VM_ENV_FLAG_LOCAL`. Usually this is the `ep` of a method (rather than a block, whose `ep` isn't "local") |
-| `local` | Local. Refers to a local variable. |
-| `me` | Method Entry. Refers to an `rb_method_entry_t` struct, the internal representation of a Ruby method.
-| MRI | Matz's Ruby Implementation |
-| `pc` | Program Counter. Usually the instruction that will be executed _next_ by the VM. Pointed to by the `cfp` and incremented by the VM |
-| `sp` | Stack Pointer. The top of the stack. The VM executes instructions in the `iseq` and instructions will push and pop values on the stack. The VM updates the `sp` on the `cfp` to point at the top of the stack|
-| `svar` | Special Variable. Refers to special local variables like `$~` and `$_`. See the `getspecial` instruction in `insns.def` |
-| `VALUE` | VALUE is a pointer to a ruby object from the Ruby C code. |
-| VM | Virtual Machine. In MRI's case YARV (Yet Another Ruby VM)
-| WB | Write Barrier. To do with GC write barriers |
-| WC | Wild Card. As seen in instructions like `getlocal_WC_0`. It means this instruction takes a "wild card" for the parameter (in this case an index for a local) |
-| YARV | Yet Another Ruby VM. The virtual machine that CRuby uses |
-| ZOMBIE | A zombie object. An object that has a finalizer which hasn't been executed yet. The object has been collected, so is "dead", but the finalizer hasn't run yet so it's still somewhat alive. |
diff --git a/doc/contributing/making_changes_to_stdlibs.md b/doc/contributing/making_changes_to_stdlibs.md
index 3b33092fea..ef3811ea12 100644
--- a/doc/contributing/making_changes_to_stdlibs.md
+++ b/doc/contributing/making_changes_to_stdlibs.md
@@ -8,7 +8,7 @@ For example, CSV lives in [a separate repository](https://github.com/ruby/csv) a
## Maintainers
-You can find the list of maintainers [here](https://docs.ruby-lang.org/en/master/maintainers_md.html#label-Maintainers).
+You can find the list of maintainers [here](https://docs.ruby-lang.org/en/master/maintainers_rdoc.html#label-Maintainers).
## Build
diff --git a/doc/contributing/testing_ruby.md b/doc/contributing/testing_ruby.md
index dfb7fb3a65..6247686efc 100644
--- a/doc/contributing/testing_ruby.md
+++ b/doc/contributing/testing_ruby.md
@@ -70,7 +70,7 @@ We can run any of the make scripts [in parallel](building_ruby.md#label-Running+
first the file name, and then the test name, prefixed with `--name`. For example:
```
- make test-all TESTS="../test/ruby/test_alias.rb --name=TestAlias#test_alias_with_zsuper_method"
+ make test-all TESTS="../test/ruby/test_alias.rb --name=/test_alias_with_zsuper_method/"
```
To run these specs with logs, we can use:
@@ -79,13 +79,7 @@ We can run any of the make scripts [in parallel](building_ruby.md#label-Running+
make test-all TESTS=-v
```
- We can display the help of the `TESTS` option:
-
- ```
- make test-all TESTS=--help
- ```
-
- If we would like to run the `test/`, `bootstraptest/` and `spec/` test suites (the `spec/` is explained in a later section), we can run
+ If we would like to run both the `test/` and `bootstraptest/` test suites, we can run
```
make check
@@ -99,28 +93,28 @@ We can run any of the make scripts [in parallel](building_ruby.md#label-Running+
make test-spec
```
- To run a specific directory, we can use `SPECOPTS` to specify the directory:
+ To run a specific directory, we can use `MSPECOPT` to specify the directory:
```
- make test-spec SPECOPTS=spec/ruby/core/array
+ make test-spec MSPECOPT=spec/ruby/core/array
```
- To run a specific file, we can also use `SPECOPTS` to specify the file:
+ To run a specific file, we can also use `MSPECOPT` to specify the file:
```
- make test-spec SPECOPTS=spec/ruby/core/array/any_spec.rb
+ make test-spec MSPECOPT=spec/ruby/core/array/any_spec.rb
```
To run a specific test, we can use the `--example` flag to match against the test name:
```
- make test-spec SPECOPTS="../spec/ruby/core/array/any_spec.rb --example='is false if the array is empty'"
+ make test-spec MSPECOPT="../spec/ruby/core/array/any_spec.rb --example='is false if the array is empty'"
```
To run these specs with logs, we can use:
```
- make test-spec SPECOPTS=-Vfs
+ make test-spec MSPECOPT=-Vfs
```
To run a ruby-spec file or directory with GNU make, we can use
@@ -140,17 +134,5 @@ We can run any of the make scripts [in parallel](building_ruby.md#label-Running+
To run a specific bundler spec file, we can use `BUNDLER_SPECS` as follows:
```
- make test-bundler BUNDLER_SPECS=commands/exec_spec.rb
+ $ make test-bundler BUNDLER_SPECS=commands/exec_spec.rb
```
-
-## Troubleshooting
-
-### Running test suites on s390x CPU Architecture
-
-If we see failing tests related to the zlib library on s390x CPU architecture, we can run the test suites with `DFLTCC=0` to pass:
-
-```
-DFLTCC=0 make check
-```
-
-The failures can happen with the zlib library applying the patch [madler/zlib#410](https://github.com/madler/zlib/pull/410) to enable the deflate algorithm producing a different compressed byte stream. We manage this issue at [[ruby-core:114942][Bug #19909]](https://bugs.ruby-lang.org/issues/19909).
diff --git a/doc/csv/options/common/col_sep.rdoc b/doc/csv/options/common/col_sep.rdoc
index 3f23c6d2d3..05769b5773 100644
--- a/doc/csv/options/common/col_sep.rdoc
+++ b/doc/csv/options/common/col_sep.rdoc
@@ -55,3 +55,9 @@ Raises an exception if parsing with the empty \String:
# Raises ArgumentError (:col_sep must be 1 or more characters: "")
CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep)
+Raises an exception if the given value is not String-convertible:
+ col_sep = BasicObject.new
+ # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
+ CSV.generate(line, col_sep: col_sep)
+ # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
+ CSV.parse(str, col_sep: col_sep)
diff --git a/doc/csv/options/common/row_sep.rdoc b/doc/csv/options/common/row_sep.rdoc
index eae15b4a84..872d9d1f3f 100644
--- a/doc/csv/options/common/row_sep.rdoc
+++ b/doc/csv/options/common/row_sep.rdoc
@@ -89,3 +89,12 @@ if any of the following is true:
* The stream is only available for output.
Obviously, discovery takes a little time. Set manually if speed is important. Also note that IO objects should be opened in binary mode on Windows if this feature will be used as the line-ending translation can cause problems with resetting the document position to where it was before the read ahead.
+
+---
+
+Raises an exception if the given value is not String-convertible:
+ row_sep = BasicObject.new
+ # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
+ CSV.generate(ary, row_sep: row_sep)
+ # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
+ CSV.parse(str, row_sep: row_sep)
diff --git a/doc/csv/options/generating/write_converters.rdoc b/doc/csv/options/generating/write_converters.rdoc
index d1a9cc748f..6e5fae5fda 100644
--- a/doc/csv/options/generating/write_converters.rdoc
+++ b/doc/csv/options/generating/write_converters.rdoc
@@ -23,3 +23,11 @@ With two write converters (called in order):
str # => "a,b,c\n"
See also {Write Converters}[#class-CSV-label-Write+Converters]
+
+---
+
+Raises an exception if the converter returns a value that is neither +nil+
+nor \String-convertible:
+ bad_converter = proc {|field| BasicObject.new }
+ # Raises NoMethodError (undefined method `is_a?' for #<BasicObject:>)
+ CSV.generate_line(['a', 'b', 'c'], write_converters: bad_converter) \ No newline at end of file
diff --git a/doc/csv/options/generating/write_headers.rdoc b/doc/csv/options/generating/write_headers.rdoc
index c56aa48adb..f9faa9d438 100644
--- a/doc/csv/options/generating/write_headers.rdoc
+++ b/doc/csv/options/generating/write_headers.rdoc
@@ -19,7 +19,7 @@ Without +write_headers+:
With +write_headers+":
CSV.open(file_path,'w',
- :write_headers => true,
+ :write_headers=> true,
:headers => ['Name','Value']
) do |csv|
csv << ['foo', '0']
diff --git a/doc/csv/options/parsing/liberal_parsing.rdoc b/doc/csv/options/parsing/liberal_parsing.rdoc
index 603de28613..b8b9b00c98 100644
--- a/doc/csv/options/parsing/liberal_parsing.rdoc
+++ b/doc/csv/options/parsing/liberal_parsing.rdoc
@@ -1,13 +1,13 @@
====== Option +liberal_parsing+
-Specifies the boolean or hash value that determines whether
+Specifies the boolean value that determines whether
CSV will attempt to parse input not conformant with RFC 4180,
such as double quotes in unquoted fields.
Default value:
CSV::DEFAULT_OPTIONS.fetch(:liberal_parsing) # => false
-For the next two examples:
+For examples in this section:
str = 'is,this "three, or four",fields'
Without +liberal_parsing+:
@@ -17,22 +17,3 @@ Without +liberal_parsing+:
With +liberal_parsing+:
ary = CSV.parse_line(str, liberal_parsing: true)
ary # => ["is", "this \"three", " or four\"", "fields"]
-
-Use the +backslash_quote+ sub-option to parse values that use
-a backslash to escape a double-quote character. This
-causes the parser to treat <code>\"</code> as if it were
-<code>""</code>.
-
-For the next two examples:
- str = 'Show,"Harry \"Handcuff\" Houdini, the one and only","Tampa Theater"'
-
-With +liberal_parsing+, but without the +backslash_quote+ sub-option:
- # Incorrect interpretation of backslash; incorrectly interprets the quoted comma as a field separator.
- ary = CSV.parse_line(str, liberal_parsing: true)
- ary # => ["Show", "\"Harry \\\"Handcuff\\\" Houdini", " the one and only\"", "Tampa Theater"]
- puts ary[1] # => "Harry \"Handcuff\" Houdini
-
-With +liberal_parsing+ and its +backslash_quote+ sub-option:
- ary = CSV.parse_line(str, liberal_parsing: { backslash_quote: true })
- ary # => ["Show", "Harry \"Handcuff\" Houdini, the one and only", "Tampa Theater"]
- puts ary[1] # => Harry "Handcuff" Houdini, the one and only
diff --git a/doc/csv/recipes/filtering.rdoc b/doc/csv/recipes/filtering.rdoc
index 1552bf0fb8..470649d09a 100644
--- a/doc/csv/recipes/filtering.rdoc
+++ b/doc/csv/recipes/filtering.rdoc
@@ -1,7 +1,5 @@
== Recipes for Filtering \CSV
-These recipes are specific code examples for specific \CSV filtering tasks.
-
For other recipes, see {Recipes for CSV}[./recipes_rdoc.html].
All code snippets on this page assume that the following has been executed:
diff --git a/doc/csv/recipes/generating.rdoc b/doc/csv/recipes/generating.rdoc
index e61838d31a..3ef6df99b4 100644
--- a/doc/csv/recipes/generating.rdoc
+++ b/doc/csv/recipes/generating.rdoc
@@ -1,7 +1,5 @@
== Recipes for Generating \CSV
-These recipes are specific code examples for specific \CSV generating tasks.
-
For other recipes, see {Recipes for CSV}[./recipes_rdoc.html].
All code snippets on this page assume that the following has been executed:
@@ -146,7 +144,7 @@ This example defines and uses a custom write converter to strip whitespace from
==== Recipe: Specify Multiple Write Converters
-Use option <tt>:write_converters</tt> and multiple custom converters
+Use option <tt>:write_converters</tt> and multiple custom coverters
to convert field values when generating \CSV.
This example defines and uses two custom write converters to strip and upcase generated fields:
@@ -163,7 +161,7 @@ This example defines and uses two custom write converters to strip and upcase ge
=== RFC 4180 Compliance
By default, \CSV generates data that is compliant with
-{RFC 4180}[https://www.rfc-editor.org/rfc/rfc4180]
+{RFC 4180}[https://tools.ietf.org/html/rfc4180]
with respect to:
- Column separator.
- Quote character.
diff --git a/doc/csv/recipes/parsing.rdoc b/doc/csv/recipes/parsing.rdoc
index 1b7071e33f..7ac96a934b 100644
--- a/doc/csv/recipes/parsing.rdoc
+++ b/doc/csv/recipes/parsing.rdoc
@@ -1,7 +1,5 @@
== Recipes for Parsing \CSV
-These recipes are specific code examples for specific \CSV parsing tasks.
-
For other recipes, see {Recipes for CSV}[./recipes_rdoc.html].
All code snippets on this page assume that the following has been executed:
@@ -191,7 +189,7 @@ Output:
=== RFC 4180 Compliance
By default, \CSV parses data that is compliant with
-{RFC 4180}[https://www.rfc-editor.org/rfc/rfc4180]
+{RFC 4180}[https://tools.ietf.org/html/rfc4180]
with respect to:
- Row separator.
- Column separator.
@@ -520,7 +518,7 @@ Apply multiple header converters by defining and registering a custom header con
To capture unconverted field values, use option +:unconverted_fields+:
source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
parsed = CSV.parse(source, converters: :integer, unconverted_fields: true)
- parsed # => [["Name", "Value"], ["foo", 0], ["bar", 1], ["baz", 2]]
+ parsed # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
parsed.each {|row| p row.unconverted_fields }
Output:
["Name", "Value"]
diff --git a/doc/csv/recipes/recipes.rdoc b/doc/csv/recipes/recipes.rdoc
index 9bf7885b1e..9e4eaa1da4 100644
--- a/doc/csv/recipes/recipes.rdoc
+++ b/doc/csv/recipes/recipes.rdoc
@@ -1,6 +1,6 @@
== Recipes for \CSV
-The recipes are specific code examples for specific tasks. See:
+See:
- {Recipes for Parsing CSV}[./parsing_rdoc.html]
- {Recipes for Generating CSV}[./generating_rdoc.html]
- {Recipes for Filtering CSV}[./filtering_rdoc.html]
diff --git a/doc/distribution.md b/doc/distribution.md
deleted file mode 100644
index bc89a7500a..0000000000
--- a/doc/distribution.md
+++ /dev/null
@@ -1,47 +0,0 @@
-# Distribution
-
-This document outlines the expected way to distribute Ruby, with a specific focus on building Ruby packages.
-
-## Getting the Ruby Tarball
-
-### Official Releases
-
-The tarball for official releases is created by the release manager. The release manager uploads the tarball to the [Ruby website](https://www.ruby-lang.org/en/downloads/).
-
-Downstream distributors should use the official release tarballs as part of their build process. This ensures that the tarball is created in a consistent way, and that the tarball is crytographically verified.
-
-### Using the nightly tarball for testing
-
-See the Snapshots section of the [Ruby website](https://www.ruby-lang.org/en/downloads/).
-
-### Building a manual snapshot tarball for testing
-
-This can be useful if the nightly tarball does not have all changes yet.
-
-At Ruby source tree cloned using git:
-```sh-session
-$ ./autogen.sh
-$ ./configure -C
-$ make
-$ make dist
-```
-
-This will create several tarball in the `tmp` directory. The tarball will be named e.g. `ruby-<version>.tar.gz` (several different compression formats will be generated).
-
-## Building the Tarball
-
-See [Building Ruby](contributing/building_ruby.md).
-
-## Updating the Ruby Standard Library
-
-The Ruby standard library is a collection of Ruby files that are included with Ruby. These files are used to provide the basic functionality of Ruby. The standard library is located in the `lib` directory and is distributed as part of the Ruby tarball.
-
-Occasionally, the standard library needs to be updated, for example a security issue might be found in a default gem or standard gem. There are two main ways that Ruby would update this code.
-
-### Releasing an Updated Ruby Gem
-
-Normally, the Ruby gem maintainer will release an updated gem. This gem can be installed alongside the default gem. This allows the user to update the gem without having to update Ruby.
-
-### Releasing a New Ruby Version
-
-If the update is critical, then the Ruby maintainers may decide to release a new version of Ruby. This new version will include the updated standard library.
diff --git a/doc/encodings.rdoc b/doc/encodings.rdoc
index d85099cdbc..1f3c54d740 100644
--- a/doc/encodings.rdoc
+++ b/doc/encodings.rdoc
@@ -1,6 +1,6 @@
-= Encodings
+== Encodings
-== The Basics
+=== The Basics
A {character encoding}[https://en.wikipedia.org/wiki/Character_encoding],
often shortened to _encoding_, is a mapping between:
@@ -30,9 +30,9 @@ Other characters, such as the Euro symbol, are multi-byte:
s = "\u20ac" # => "€"
s.bytes # => [226, 130, 172]
-== The \Encoding \Class
+=== The \Encoding \Class
-=== \Encoding Objects
+==== \Encoding Objects
Ruby encodings are defined by constants in class \Encoding.
There can be only one instance of \Encoding for each of these constants.
@@ -43,7 +43,7 @@ There can be only one instance of \Encoding for each of these constants.
Encoding.list.take(3)
# => [#<Encoding:ASCII-8BIT>, #<Encoding:UTF-8>, #<Encoding:US-ASCII>]
-=== Names and Aliases
+==== Names and Aliases
\Method Encoding#name returns the name of an \Encoding:
@@ -78,7 +78,7 @@ because it includes both the names and their aliases.
Encoding.find("US-ASCII") # => #<Encoding:US-ASCII>
Encoding.find("US-ASCII").class # => Encoding
-=== Default Encodings
+==== Default Encodings
\Method Encoding.find, above, also returns a default \Encoding
for each of these special names:
@@ -118,7 +118,7 @@ for each of these special names:
Encoding.default_internal = 'US-ASCII' # => "US-ASCII"
Encoding.default_internal # => #<Encoding:US-ASCII>
-=== Compatible Encodings
+==== Compatible Encodings
\Method Encoding.compatible? returns whether two given objects are encoding-compatible
(that is, whether they can be concatenated);
@@ -132,21 +132,20 @@ returns the \Encoding of the concatenated string, or +nil+ if incompatible:
s1 = "\xa1\xa1".force_encoding('euc-jp') # => "\x{A1A1}"
Encoding.compatible?(s0, s1) # => nil
-== \String \Encoding
+=== \String \Encoding
A Ruby String object has an encoding that is an instance of class \Encoding.
The encoding may be retrieved by method String#encoding.
-The default encoding for a string literal is the script encoding;
-see {Script Encoding}[rdoc-ref:encodings.rdoc@Script+Encoding].
+The default encoding for a string literal is the script encoding
+(see Encoding@Script+encoding):
's'.encoding # => #<Encoding:UTF-8>
The default encoding for a string created with method String.new is:
- For a \String object argument, the encoding of that string.
-- For a string literal, the script encoding;
- see {Script Encoding}[rdoc-ref:encodings.rdoc@Script+Encoding].
+- For a string literal, the script encoding (see Encoding@Script+encoding).
In either case, any encoding may be specified:
@@ -183,7 +182,7 @@ Here are a couple of useful query methods:
s = "\xc2".force_encoding("UTF-8") # => "\xC2"
s.valid_encoding? # => false
-== \Symbol and \Regexp Encodings
+=== \Symbol and \Regexp Encodings
The string stored in a Symbol or Regexp object also has an encoding;
the encoding may be retrieved by method Symbol#encoding or Regexp#encoding.
@@ -191,23 +190,22 @@ the encoding may be retrieved by method Symbol#encoding or Regexp#encoding.
The default encoding for these, however, is:
- US-ASCII, if all characters are US-ASCII.
-- The script encoding, otherwise;
- see (Script Encoding)[rdoc-ref:encodings.rdoc@Script+Encoding].
+- The script encoding, otherwise (see Encoding@Script+encoding).
-== Filesystem \Encoding
+=== Filesystem \Encoding
The filesystem encoding is the default \Encoding for a string from the filesystem:
Encoding.find("filesystem") # => #<Encoding:UTF-8>
-== Locale \Encoding
+=== Locale \Encoding
The locale encoding is the default encoding for a string from the environment,
other than from the filesystem:
Encoding.find('locale') # => #<Encoding:IBM437>
-== Stream Encodings
+=== Stream Encodings
Certain stream objects can have two encodings; these objects include instances of:
@@ -222,7 +220,7 @@ The two encodings are:
- An _internal_ _encoding_, which (if not +nil+) specifies the encoding
to be used for the string constructed from the stream.
-=== External \Encoding
+==== External \Encoding
The external encoding, which is an \Encoding object, specifies how bytes read
from the stream are to be interpreted as characters.
@@ -250,7 +248,7 @@ For an \IO, \File, \ARGF, or \StringIO object, the external encoding may be set
- \Methods +set_encoding+ or (except for \ARGF) +set_encoding_by_bom+.
-=== Internal \Encoding
+==== Internal \Encoding
The internal encoding, which is an \Encoding object or +nil+,
specifies how characters read from the stream
@@ -276,7 +274,7 @@ For an \IO, \File, \ARGF, or \StringIO object, the internal encoding may be set
- \Method +set_encoding+.
-== Script \Encoding
+=== Script \Encoding
A Ruby script has a script encoding, which may be retrieved by:
@@ -291,7 +289,7 @@ followed by a colon, space and the Encoding name or alias:
# encoding: ISO-8859-1
__ENCODING__ #=> #<Encoding:ISO-8859-1>
-== Transcoding
+=== Transcoding
_Transcoding_ is the process of changing a sequence of characters
from one encoding to another.
@@ -302,7 +300,7 @@ but the bytes that represent them may change.
The handling for characters that cannot be represented in the destination encoding
may be specified by @Encoding+Options.
-=== Transcoding a \String
+==== Transcoding a \String
Each of these methods transcodes a string:
@@ -317,7 +315,7 @@ Each of these methods transcodes a string:
- String#unicode_normalize!: Like String#unicode_normalize,
but transcodes +self+ in place.
-== Transcoding a Stream
+=== Transcoding a Stream
Each of these methods may transcode a stream;
whether it does so depends on the external and internal encodings:
@@ -352,7 +350,7 @@ Output:
"R\xE9sum\xE9"
"Résumé"
-== \Encoding Options
+=== \Encoding Options
A number of methods in the Ruby core accept keyword arguments as encoding options.
@@ -419,7 +417,7 @@ These keyword-value pairs specify encoding options:
hash = {"\u3042" => 'xyzzy'}
hash.default = 'XYZZY'
- s.encode('ASCII', fallback: hash) # => "xyzzyfooXYZZY"
+ s.encode('ASCII', fallback: h) # => "xyzzyfooXYZZY"
def (fallback = "U+%.4X").escape(x)
self % x.unpack("U")
diff --git a/doc/exceptions.md b/doc/exceptions.md
deleted file mode 100644
index 47176141ad..0000000000
--- a/doc/exceptions.md
+++ /dev/null
@@ -1,528 +0,0 @@
-# Exceptions
-
-Ruby code can raise exceptions.
-
-Most often, a raised exception is meant to alert the running program
-that an unusual (i.e., _exceptional_) situation has arisen,
-and may need to be handled.
-
-Code throughout the Ruby core, Ruby standard library, and Ruby gems generates exceptions
-in certain circumstances:
-
-```
-File.open('nope.txt') # Raises Errno::ENOENT: "No such file or directory"
-```
-
-## Raised Exceptions
-
-A raised exception transfers program execution, one way or another.
-
-### Unrescued Exceptions
-
-If an exception not _rescued_
-(see [Rescued Exceptions](#label-Rescued+Exceptions) below),
-execution transfers to code in the Ruby interpreter
-that prints a message and exits the program (or thread):
-
-```
-$ ruby -e "raise"
--e:1:in `<main>': unhandled exception
-```
-
-### Rescued Exceptions
-
-An <i>exception handler</i> may determine what is to happen
-when an exception is raised;
-the handler may _rescue_ an exception,
-and may prevent the program from exiting.
-
-A simple example:
-
-```
-begin
- raise 'Boom!' # Raises an exception, transfers control.
- puts 'Will not get here.'
-rescue
- puts 'Rescued an exception.' # Control transferred to here; program does not exit.
-end
-puts 'Got here.'
-```
-
-Output:
-
-```
-Rescued an exception.
-Got here.
-```
-
-An exception handler has several elements:
-
-| Element | Use |
-|-----------------------------|------------------------------------------------------------------------------------------|
-| Begin clause. | Begins the handler and contains the code whose raised exception, if any, may be rescued. |
-| One or more rescue clauses. | Each contains "rescuing" code, which is to be executed for certain exceptions. |
-| Else clause (optional). | Contains code to be executed if no exception is raised. |
-| Ensure clause (optional). | Contains code to be executed whether or not an exception is raised, or is rescued. |
-| <tt>end</tt> statement. | Ends the handler. ` |
-
-#### Begin Clause
-
-The begin clause begins the exception handler:
-
-- May start with a `begin` statement;
- see also [Begin-Less Exception Handlers](#label-Begin-Less+Exception+Handlers).
-- Contains code whose raised exception (if any) is covered
- by the handler.
-- Ends with the first following `rescue` statement.
-
-#### Rescue Clauses
-
-A rescue clause:
-
-- Starts with a `rescue` statement.
-- Contains code that is to be executed for certain raised exceptions.
-- Ends with the first following `rescue`,
- `else`, `ensure`, or `end` statement.
-
-##### Rescued Exceptions
-
-A `rescue` statement may include one or more classes
-that are to be rescued;
-if none is given, StandardError is assumed.
-
-The rescue clause rescues both the specified class
-(or StandardError if none given) or any of its subclasses;
-see [Built-In Exception Class Hierarchy](rdoc-ref:Exception@Built-In+Exception+Class+Hierarchy).
-
-```
-begin
- 1 / 0 # Raises ZeroDivisionError, a subclass of StandardError.
-rescue
- puts "Rescued #{$!.class}"
-end
-```
-
-Output:
-
-```
-Rescued ZeroDivisionError
-```
-
-If the `rescue` statement specifies an exception class,
-only that class (or one of its subclasses) is rescued;
-this example exits with a ZeroDivisionError,
-which was not rescued because it is not ArgumentError or one of its subclasses:
-
-```
-begin
- 1 / 0
-rescue ArgumentError
- puts "Rescued #{$!.class}"
-end
-```
-
-A `rescue` statement may specify multiple classes,
-which means that its code rescues an exception
-of any of the given classes (or their subclasses):
-
-```
-begin
- 1 / 0
-rescue FloatDomainError, ZeroDivisionError
- puts "Rescued #{$!.class}"
-end
-```
-
-##### Multiple Rescue Clauses
-
-An exception handler may contain multiple rescue clauses;
-in that case, the first clause that rescues the exception does so,
-and those before and after are ignored:
-
-```
-begin
- Dir.open('nosuch')
-rescue Errno::ENOTDIR
- puts "Rescued #{$!.class}"
-rescue Errno::ENOENT
- puts "Rescued #{$!.class}"
-end
-```
-
-Output:
-
-```
-Rescued Errno::ENOENT
-```
-
-##### Capturing the Rescued \Exception
-
-A `rescue` statement may specify a variable
-whose value becomes the rescued exception
-(an instance of Exception or one of its subclasses:
-
-```
-begin
- 1 / 0
-rescue => x
- puts x.class
- puts x.message
-end
-```
-
-Output:
-
-```
-ZeroDivisionError
-divided by 0
-```
-
-##### Global Variables
-
-Two read-only global variables always have `nil` value
-except in a rescue clause;
-there:
-
-- `$!`: contains the rescued exception.
-- `$@`: contains its backtrace.
-
-Example:
-
-```
-begin
- 1 / 0
-rescue
- p $!
- p $@
-end
-```
-
-Output:
-
-```
-#<ZeroDivisionError: divided by 0>
-["t.rb:2:in `/'", "t.rb:2:in `<main>'"]
-```
-
-##### Cause
-
-In a rescue clause, the method Exception#cause returns the previous value of `$!`,
-which may be `nil`;
-elsewhere, the method returns `nil`.
-
-Example:
-
-```
-begin
- raise('Boom 0')
-rescue => x0
- puts "Exception: #{x0.inspect}; $!: #{$!.inspect}; cause: #{x0.cause.inspect}."
- begin
- raise('Boom 1')
- rescue => x1
- puts "Exception: #{x1.inspect}; $!: #{$!.inspect}; cause: #{x1.cause.inspect}."
- begin
- raise('Boom 2')
- rescue => x2
- puts "Exception: #{x2.inspect}; $!: #{$!.inspect}; cause: #{x2.cause.inspect}."
- end
- end
-end
-```
-
-Output:
-
-```
-Exception: #<RuntimeError: Boom 0>; $!: #<RuntimeError: Boom 0>; cause: nil.
-Exception: #<RuntimeError: Boom 1>; $!: #<RuntimeError: Boom 1>; cause: #<RuntimeError: Boom 0>.
-Exception: #<RuntimeError: Boom 2>; $!: #<RuntimeError: Boom 2>; cause: #<RuntimeError: Boom 1>.
-```
-
-#### Else Clause
-
-The `else` clause:
-
-- Starts with an `else` statement.
-- Contains code that is to be executed if no exception is raised in the begin clause.
-- Ends with the first following `ensure` or `end` statement.
-
-```
-begin
- puts 'Begin.'
-rescue
- puts 'Rescued an exception!'
-else
- puts 'No exception raised.'
-end
-```
-
-Output:
-
-```
-Begin.
-No exception raised.
-```
-
-#### Ensure Clause
-
-The ensure clause:
-
-- Starts with an `ensure` statement.
-- Contains code that is to be executed
- regardless of whether an exception is raised,
- and regardless of whether a raised exception is handled.
-- Ends with the first following `end` statement.
-
-```
-def foo(boom: false)
- puts 'Begin.'
- raise 'Boom!' if boom
-rescue
- puts 'Rescued an exception!'
-else
- puts 'No exception raised.'
-ensure
- puts 'Always do this.'
-end
-
-foo(boom: true)
-foo(boom: false)
-```
-
-Output:
-
-```
-Begin.
-Rescued an exception!
-Always do this.
-Begin.
-No exception raised.
-Always do this.
-```
-
-#### End Statement
-
-The `end` statement ends the handler.
-
-Code following it is reached only if any raised exception is rescued.
-
-#### Begin-Less \Exception Handlers
-
-As seen above, an exception handler may be implemented with `begin` and `end`.
-
-An exception handler may also be implemented as:
-
-- A method body:
-
- ```
- def foo(boom: false) # Serves as beginning of exception handler.
- puts 'Begin.'
- raise 'Boom!' if boom
- rescue
- puts 'Rescued an exception!'
- else
- puts 'No exception raised.'
- end # Serves as end of exception handler.
- ```
-
-- A block:
-
- ```
- Dir.chdir('.') do |dir| # Serves as beginning of exception handler.
- raise 'Boom!'
- rescue
- puts 'Rescued an exception!'
- end # Serves as end of exception handler.
- ```
-
-#### Re-Raising an \Exception
-
-It can be useful to rescue an exception, but allow its eventual effect;
-for example, a program can rescue an exception, log data about it,
-and then "reinstate" the exception.
-
-This may be done via the `raise` method, but in a special way;
-a rescuing clause:
-
- - Captures an exception.
- - Does whatever is needed concerning the exception (such as logging it).
- - Calls method `raise` with no argument,
- which raises the rescued exception:
-
-```
-begin
- 1 / 0
-rescue ZeroDivisionError
- # Do needful things (like logging).
- raise # Raised exception will be ZeroDivisionError, not RuntimeError.
-end
-```
-
-Output:
-
-```
-ruby t.rb
-t.rb:2:in `/': divided by 0 (ZeroDivisionError)
- from t.rb:2:in `<main>'
-```
-
-#### Retrying
-
-It can be useful to retry a begin clause;
-for example, if it must access a possibly-volatile resource
-(such as a web page),
-it can be useful to try the access more than once
-(in the hope that it may become available):
-
-```
-retries = 0
-begin
- puts "Try ##{retries}."
- raise 'Boom'
-rescue
- puts "Rescued retry ##{retries}."
- if (retries += 1) < 3
- puts 'Retrying'
- retry
- else
- puts 'Giving up.'
- raise
- end
-end
-```
-
-```
-Try #0.
-Rescued retry #0.
-Retrying
-Try #1.
-Rescued retry #1.
-Retrying
-Try #2.
-Rescued retry #2.
-Giving up.
-# RuntimeError ('Boom') raised.
-```
-
-Note that the retry re-executes the entire begin clause,
-not just the part after the point of failure.
-
-## Raising an \Exception
-
-\Method Kernel#raise raises an exception.
-
-## Custom Exceptions
-
-To provide additional or alternate information,
-you may create custom exception classes.
-Each should be a subclass of one of the built-in exception classes
-(commonly StandardError or RuntimeError);
-see [Built-In Exception Class Hierarchy](rdoc-ref:Exception@Built-In+Exception+Class+Hierarchy).
-
-```
-class MyException < StandardError; end
-```
-
-## Messages
-
-Every `Exception` object has a message,
-which is a string that is set at the time the object is created;
-see Exception.new.
-
-The message cannot be changed, but you can create a similar object with a different message;
-see Exception#exception.
-
-This method returns the message as defined:
-
-- Exception#message.
-
-Two other methods return enhanced versions of the message:
-
-- Exception#detailed_message: adds exception class name, with optional highlighting.
-- Exception#full_message: adds exception class name and backtrace, with optional highlighting.
-
-Each of the two methods above accepts keyword argument `highlight`;
-if the value of keyword `highlight` is `true`,
-the returned string includes bolding and underlining ANSI codes (see below)
-to enhance the appearance of the message.
-
-Any exception class (Ruby or custom) may choose to override either of these methods,
-and may choose to interpret keyword argument <tt>highlight: true</tt>
-to mean that the returned message should contain
-[ANSI codes](https://en.wikipedia.org/wiki/ANSI_escape_code)
-that specify color, bolding, and underlining.
-
-Because the enhanced message may be written to a non-terminal device
-(e.g., into an HTML page),
-it is best to limit the ANSI codes to these widely-supported codes:
-
-- Begin font color:
-
- | Color | ANSI Code |
- |---------|------------------|
- | Red | <tt>\\e[31m</tt> |
- | Green | <tt>\\e[32m</tt> |
- | Yellow | <tt>\\e[33m</tt> |
- | Blue | <tt>\\e[34m</tt> |
- | Magenta | <tt>\\e[35m</tt> |
- | Cyan | <tt>\\e[36m</tt> |
-
-<br>
-
-- Begin font attribute:
-
- | Attribute | ANSI Code |
- |-----------|-----------------|
- | Bold | <tt>\\e[1m</tt> |
- | Underline | <tt>\\e[4m</tt> |
-
-<br>
-
-- End all of the above:
-
- | Color | ANSI Code |
- |-------|-----------------|
- | Reset | <tt>\\e[0m</tt> |
-
-It's also best to craft a message that is conveniently human-readable,
-even if the ANSI codes are included "as-is"
-(rather than interpreted as font directives).
-
-## Backtraces
-
-A _backtrace_ is a record of the methods currently
-in the [call stack](https://en.wikipedia.org/wiki/Call_stack);
-each such method has been called, but has not yet returned.
-
-These methods return backtrace information:
-
-- Exception#backtrace: returns the backtrace as an array of strings or `nil`.
-- Exception#backtrace_locations: returns the backtrace as an array
- of Thread::Backtrace::Location objects or `nil`.
- Each Thread::Backtrace::Location object gives detailed information about a called method.
-
-An `Exception` object stores its backtrace value as one of:
-
-- An array of Thread::Backtrace::Location objects;
- this is the common case: the exception was raised by the Ruby core or the Ruby standard library.
- In this case:
-
- - Exception#backtrace_locations returns the array of Thread::Backtrace::Location objects.
- - Exception#backtrace returns the array of their string values
- (`Exception#backtrace_locations.map {|loc| loc.to_s }`).
-
-- An array of strings;
- this is an uncommon case: the user manually set the backtrace to an array of strings;
- In this case:
-
- - Exception#backtrace returns the array of strings.
- - Exception#backtrace_locations returns `nil`.
-
-- `nil`, in which case both methods return `nil`.
-
-These methods set the backtrace value:
-
-- Exception#set_backtrace: sets the backtrace value to an array of strings, or to `nil`.
-- Kernel#raise: sets the backtrace value to an array of Thread::Backtrace::Location objects,
- or to an array of strings.
-
diff --git a/doc/extension.ja.rdoc b/doc/extension.ja.rdoc
index 2f7856f3d4..93f5753cd1 100644
--- a/doc/extension.ja.rdoc
+++ b/doc/extension.ja.rdoc
@@ -780,14 +780,9 @@ RUBY_TYPED_WB_PROTECTED ::
メソッドã®å®Ÿè£…ã«é©åˆ‡ã«ãƒ©ã‚¤ãƒˆãƒãƒªã‚¢ã‚’挿入ã™ã‚‹è²¬ä»»ãŒã‚りã¾ã™ï¼Ž
ã•ã‚‚ãªãã°Rubyã¯å®Ÿè¡Œæ™‚ã«ã‚¯ãƒ©ãƒƒã‚·ãƒ¥ã™ã‚‹å¯èƒ½æ€§ãŒã‚りã¾ã™ï¼Ž
- ライトãƒãƒªã‚¢ã«ã¤ã„ã¦ã¯{世代別
- GC}[rdoc-ref:@Appendix+D.+-E4-B8-96-E4-BB-A3-E5-88-A5GC]
- ã‚‚å‚ç…§ã—ã¦ãã ã•ã„.
+ ライトãƒãƒªã‚¢ã«ã¤ã„ã¦ã¯doc/extension.ja.rdocã®Appendix D
+ "世代別GC"ã‚‚å‚ç…§ã—ã¦ãã ã•ã„.
-ã“ã®ãƒžã‚¯ãƒ­ã¯ä¾‹å¤–を発生ã•ã›ã‚‹å¯èƒ½æ€§ãŒã‚ã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•
-ã„. ラップã•れる sval ãŒï¼Œè§£æ”¾ã™ã‚‹å¿…è¦ãŒã‚るリソース (割り
-当ã¦ã‚‰ã‚ŒãŸãƒ¡ãƒ¢ãƒªï¼Œå¤–部ライブラリã‹ã‚‰ã®ãƒãƒ³ãƒ‰ãƒ«ãªã©) ã‚’ä¿æŒã—
-ã¦ã„ã‚‹å ´åˆã¯ï¼Œrb_protect を使用ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ï¼Ž
Cã®æ§‹é€ ä½“ã®å‰²å½“ã¨å¯¾å¿œã™ã‚‹ã‚ªãƒ–ジェクトã®ç”Ÿæˆã‚’åŒæ™‚ã«è¡Œã†ãƒžã‚¯
ロã¨ã—ã¦ä»¥ä¸‹ã®ã‚‚ã®ãŒæä¾›ã•れã¦ã„ã¾ã™ï¼Ž
@@ -893,12 +888,12 @@ dbm.cã§ã¯TypedData_Make_Structを以下ã®ã‚ˆã†ã«ä½¿ã£ã¦ã„ã¾ã™ï¼Ž
obj = TypedData_Make_Struct(klass, struct dbmdata, &dbm_type, dbmp);
-ã“ã“ã§ã¯dbmdata構造体ã¸ã®ãƒã‚¤ãƒ³ã‚¿ã‚’Rubyオブジェクトã«ã‚«ãƒ—ã‚»
-ル化ã—ã¦ã„ã¾ã™ï¼ŽDBM*を直接カプセル化ã—ãªã„ã®ã¯close()ã—ãŸæ™‚
-ã®å‡¦ç†ã‚’考ãˆã¦ã®ã“ã¨ã§ã™ï¼Ž
+ã“ã“ã§ã¯dbmdata構造体ã¸ã®ãƒã‚¤ãƒ³ã‚¿ã‚’Dataã«ã‚«ãƒ—セル化ã—ã¦ã„
+ã¾ã™ï¼ŽDBM*を直接カプセル化ã—ãªã„ã®ã¯close()ã—ãŸæ™‚ã®å‡¦ç†ã‚’考
+ãˆã¦ã®ã“ã¨ã§ã™ï¼Ž
-Rubyオブジェクトã‹ã‚‰dbmdata構造体ã®ãƒã‚¤ãƒ³ã‚¿ã‚’å–り出ã™ãŸã‚ã«
-以下ã®ãƒžã‚¯ãƒ­ã‚’使ã£ã¦ã„ã¾ã™ï¼Ž
+Dataオブジェクトã‹ã‚‰dbmstruct構造体ã®ãƒã‚¤ãƒ³ã‚¿ã‚’å–り出ã™ãŸã‚
+ã«ä»¥ä¸‹ã®ãƒžã‚¯ãƒ­ã‚’使ã£ã¦ã„ã¾ã™ï¼Ž
#define GetDBM(obj, dbmp) do {\
TypedData_Get_Struct((obj), struct dbmdata, &dbm_type, (dbmp));\
@@ -1736,7 +1731,7 @@ have_func(func, header) ::
ックã™ã‚‹ï¼ŽfuncãŒæ¨™æº–ã§ã¯ãƒªãƒ³ã‚¯ã•れãªã„ライブラリ内ã®ã‚‚ã®ã§
ã‚る時ã«ã¯å…ˆã«have_libraryã§ãã®ãƒ©ã‚¤ãƒ–ラリをãƒã‚§ãƒƒã‚¯ã—ã¦ãŠ
ã事.ãƒã‚§ãƒƒã‚¯ã«æˆåŠŸã™ã‚‹ã¨ï¼Œãƒ—リプロセッサマクロ
- <tt>HAVE_{FUNC}</tt> を定義ã—,trueã‚’è¿”ã™ï¼Ž
+ `HAVE_{FUNC}` を定義ã—,trueã‚’è¿”ã™ï¼Ž
have_var(var, header) ::
@@ -1744,44 +1739,44 @@ have_var(var, header) ::
クã™ã‚‹ï¼ŽvarãŒæ¨™æº–ã§ã¯ãƒªãƒ³ã‚¯ã•れãªã„ライブラリ内ã®ã‚‚ã®ã§ã‚
る時ã«ã¯å…ˆã«have_libraryã§ãã®ãƒ©ã‚¤ãƒ–ラリをãƒã‚§ãƒƒã‚¯ã—ã¦ãŠã
事.ãƒã‚§ãƒƒã‚¯ã«æˆåŠŸã™ã‚‹ã¨ï¼Œãƒ—リプロセッサマクロ
- <tt>HAVE_{VAR}</tt> を定義ã—,trueã‚’è¿”ã™ï¼Ž
+ `HAVE_{VAR}` を定義ã—,trueã‚’è¿”ã™ï¼Ž
have_header(header) ::
ヘッダファイルã®å­˜åœ¨ã‚’ãƒã‚§ãƒƒã‚¯ã™ã‚‹ï¼Žãƒã‚§ãƒƒã‚¯ã«æˆåŠŸã™ã‚‹ã¨ï¼Œ
- プリプロセッサマクロ <tt>HAVE_{HEADER_H}</tt> を定義ã—,trueã‚’è¿”ã™ï¼Ž
+ プリプロセッサマクロ `HAVE_{HEADER_H}` を定義ã—,trueã‚’è¿”ã™ï¼Ž
(スラッシュやドットã¯ã‚¢ãƒ³ãƒ€ãƒ¼ã‚¹ã‚³ã‚¢ã«ç½®æ›ã•れる)
find_header(header, path...) ::
ヘッダファイルheaderã®å­˜åœ¨ã‚’ -Ipath を追加ã—ãªãŒã‚‰ãƒã‚§ãƒƒã‚¯
ã™ã‚‹ï¼Žãƒã‚§ãƒƒã‚¯ã«æˆåŠŸã™ã‚‹ã¨ï¼Œãƒ—リプロセッサマクロ
- <tt>HAVE_{HEADER_H}</tt> を定義ã—,trueã‚’è¿”ã™ï¼Ž
+ `HAVE_{HEADER_H}` を定義ã—,trueã‚’è¿”ã™ï¼Ž
(スラッシュやドットã¯ã‚¢ãƒ³ãƒ€ãƒ¼ã‚¹ã‚³ã‚¢ã«ç½®æ›ã•れる)
have_struct_member(type, member[, header[, opt]]) ::
ヘッダファイルheaderをインクルードã—ã¦åž‹typeãŒå®šç¾©ã•れ,
ãªãŠã‹ã¤ãƒ¡ãƒ³ãƒmemberãŒå­˜åœ¨ã™ã‚‹ã‹ã‚’ãƒã‚§ãƒƒã‚¯ã™ã‚‹ï¼Žãƒã‚§ãƒƒã‚¯ã«
- æˆåŠŸã™ã‚‹ã¨ï¼Œãƒ—リプロセッサマクロ <tt>HAVE_{TYPE}_{MEMBER}</tt> ã‚’
+ æˆåŠŸã™ã‚‹ã¨ï¼Œãƒ—リプロセッサマクロ `HAVE_{TYPE}_{MEMBER}` ã‚’
定義ã—,trueã‚’è¿”ã™ï¼Ž
have_type(type, header, opt) ::
ヘッダファイルheaderをインクルードã—ã¦åž‹typeãŒå­˜åœ¨ã™ã‚‹ã‹ã‚’
ãƒã‚§ãƒƒã‚¯ã™ã‚‹ï¼Žãƒã‚§ãƒƒã‚¯ã«æˆåŠŸã™ã‚‹ã¨ï¼Œãƒ—リプロセッサマクロ
- <tt>HAVE_TYPE_{TYPE}</tt> を定義ã—,trueã‚’è¿”ã™ï¼Ž
+ `HAVE_TYPE_{TYPE}` を定義ã—,trueã‚’è¿”ã™ï¼Ž
check_sizeof(type, header) ::
ヘッダファイルheaderをインクルードã—ã¦åž‹typeã®charå˜ä½ã‚µã‚¤
ズを調ã¹ã‚‹ï¼Žãƒã‚§ãƒƒã‚¯ã«æˆåŠŸã™ã‚‹ã¨ï¼Œãƒ—リプロセッサマクロ
- <tt>SIZEOF_{TYPE}</tt> を定義ã—,ãã®ã‚µã‚¤ã‚ºã‚’è¿”ã™ï¼Žå®šç¾©ã•れã¦ã„ãª
+ `SIZEOF_{TYPE}` を定義ã—,ãã®ã‚µã‚¤ã‚ºã‚’è¿”ã™ï¼Žå®šç¾©ã•れã¦ã„ãª
ã„ã¨ãã¯nilã‚’è¿”ã™ï¼Ž
-append_cppflags(array-of-flags[, opt]) ::
-append_cflags(array-of-flags[, opt]) ::
-append_ldflags(array-of-flags[, opt]) ::
+append_cppflags(array-of-flags[, opt])
+append_cflags(array-of-flags[, opt])
+append_ldflags(array-of-flags[, opt])
å„flagãŒä½¿ç”¨å¯èƒ½ã§ã‚れã°ï¼Œãれãžã‚Œ$CPPFLAGS, $CFLAGS,
$LDFLAGSã«è¿½åŠ ã™ã‚‹ï¼Žã‚³ãƒ³ãƒ‘イラã®ãƒ•ラグã«ã¯ç§»æ¤æ€§ãŒãªã„ã®ã§ï¼Œ
@@ -1855,9 +1850,8 @@ RGenGCã¯ï¼ŒéŽåŽ»ã®æ‹¡å¼µãƒ©ã‚¤ãƒ–ラリã«ï¼ˆã»ã¼ï¼‰äº’æ›æ€§ã‚’ä¿ã¤ã‚ˆã
スã™ã‚‹ã‚ˆã†ãªã‚³ãƒ¼ãƒ‰ã¯æ›¸ã‹ãªã„よã†ã«ã—ã¦ä¸‹ã•ã„.代ã‚りã«ï¼Œrb_ary_aref(),
rb_ary_store() ãªã©ã®ï¼Œé©åˆ‡ãª API 関数を利用ã™ã‚‹ã‚ˆã†ã«ã—ã¦ä¸‹ã•ã„.
-ãã®ã»ã‹ï¼Œå¯¾å¿œã«ã¤ã„ã¦ã®è©³ç´°ã¯ {Appendix D. Generational
-GC}[rdoc-ref:extension.rdoc@Appendix+D.+Generational+GC]ã‚’å‚
-ç…§ã—ã¦ä¸‹ã•ã„.
+ãã®ã»ã‹ï¼Œå¯¾å¿œã«ã¤ã„ã¦ã®è©³ç´°ã¯ extension.rdoc ã®ã€ŒAppendix D. Generational
+GCã€ã‚’å‚ç…§ã—ã¦ä¸‹ã•ã„.
== Appendix E. Ractor サãƒãƒ¼ãƒˆ
@@ -1866,12 +1860,10 @@ Ruby 3.0 ã‹ã‚‰ã€Ruby プログラムを並列ã«å®Ÿè¡Œã™ã‚‹ãŸã‚ã®ä»•組ã¿
ãªã‚Šã¾ã™ã€‚サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„ライブラリã¯ã€ãƒ¡ã‚¤ãƒ³ Ractor 以外ã§å®Ÿè¡Œã™ã‚‹ã¨
エラーã«ãªã‚Šã¾ã™ï¼ˆRactor::UnsafeError)。
-Ractor をサãƒãƒ¼ãƒˆã™ã‚‹ãŸã‚ã®è©³ç´°ã¯ã€{Appendix F. Ractor
-support}[rdoc-ref:extension.rdoc@Appendix+F.+Ractor+support]
-ã‚’å‚ç…§ã—ã¦ãã ã•ã„。
+Ractor をサãƒãƒ¼ãƒˆã™ã‚‹ãŸã‚ã®è©³ç´°ã¯ã€extension.rdoc ã®ã€ŒAppendix F. Ractor
+supportã€ã‚’å‚ç…§ã—ã¦ãã ã•ã„。
---
-Local variables:
-fill-column: 60
-end:
-++
+
+:enddoc: Local variables:
+:enddoc: fill-column: 60
+:enddoc: end:
diff --git a/doc/extension.rdoc b/doc/extension.rdoc
index ba59d107ab..ad9ae641d2 100644
--- a/doc/extension.rdoc
+++ b/doc/extension.rdoc
@@ -1,6 +1,6 @@
# extension.rdoc - -*- RDoc -*- created at: Mon Aug 7 16:45:54 JST 1995
-= Creating extension libraries for Ruby
+= Creating Extension Libraries for Ruby
This document explains how to make extension libraries for Ruby.
@@ -10,8 +10,8 @@ In C, variables have types and data do not have types. In contrast,
Ruby variables do not have a static type, and data themselves have
types, so data will need to be converted between the languages.
-Objects in Ruby are represented by the C type `VALUE'. Each VALUE
-data has its data type.
+Data in Ruby are represented by the C type `VALUE'. Each VALUE data
+has its data type.
To retrieve C data from a VALUE, you need to:
@@ -20,7 +20,7 @@ To retrieve C data from a VALUE, you need to:
Converting to the wrong data type may cause serious problems.
-=== Ruby data types
+=== Data Types
The Ruby interpreter has the following data types:
@@ -54,7 +54,7 @@ T_ZOMBIE :: object awaiting finalization
Most of the types are represented by C structures.
-=== Check type of the VALUE data
+=== Check Data Type of the VALUE
The macro TYPE() defined in ruby.h shows the data type of the VALUE.
TYPE() returns the constant number T_XXXX described above. To handle
@@ -88,7 +88,7 @@ There are also faster check macros for fixnums and nil.
FIXNUM_P(obj)
NIL_P(obj)
-=== Convert VALUE into C data
+=== Convert VALUE into C Data
The data for type T_NIL, T_FALSE, T_TRUE are nil, false, true
respectively. They are singletons for the data type.
@@ -143,7 +143,7 @@ Notice: Do not change the value of the structure directly, unless you
are responsible for the result. This ends up being the cause of
interesting bugs.
-=== Convert C data into VALUE
+=== Convert C Data into VALUE
To convert C data to Ruby values:
@@ -169,14 +169,14 @@ INT2NUM() :: for arbitrary sized integers.
INT2NUM() converts an integer into a Bignum if it is out of the FIXNUM
range, but is a bit slower.
-=== Manipulating Ruby object
+=== Manipulating Ruby Data
As I already mentioned, it is not recommended to modify an object's
internal structure. To manipulate objects, use the functions supplied
by the Ruby interpreter. Some (not all) of the useful functions are
listed below:
-==== String functions
+==== String Functions
rb_str_new(const char *ptr, long len) ::
@@ -279,7 +279,7 @@ rb_str_modify(VALUE str) ::
you MUST call this function before modifying the contents using
RSTRING_PTR and/or rb_str_set_len.
-==== Array functions
+==== Array Functions
rb_ary_new() ::
@@ -338,13 +338,13 @@ rb_ary_cat(VALUE ary, const VALUE *ptr, long len) ::
== Extending Ruby with C
-=== Adding new features to Ruby
+=== Adding New Features to Ruby
You can add new features (classes, methods, etc.) to the Ruby
interpreter. Ruby provides APIs for defining the following things:
- Classes, Modules
-- Methods, singleton methods
+- Methods, Singleton Methods
- Constants
==== Class and Module Definition
@@ -362,7 +362,7 @@ To define nested classes or modules, use the functions below:
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
VALUE rb_define_module_under(VALUE outer, const char *name)
-==== Method and singleton method definition
+==== Method and Singleton Method Definition
To define methods or singleton methods, use these functions:
@@ -467,7 +467,7 @@ available), you can use:
VALUE rb_current_receiver(void)
-==== Constant definition
+==== Constant Definition
We have 2 functions to define constants:
@@ -477,11 +477,11 @@ We have 2 functions to define constants:
The former is to define a constant under specified class/module. The
latter is to define a global constant.
-=== Use Ruby features from C
+=== Use Ruby Features from C
There are several ways to invoke Ruby's features from C code.
-==== Evaluate Ruby programs in a string
+==== Evaluate Ruby Programs in a String
The easiest way to use Ruby's functionality from a C program is to
evaluate the string as Ruby program. This function will do the job:
@@ -550,7 +550,7 @@ and to convert Ruby Symbol object to ID, use
ID SYM2ID(VALUE symbol)
-==== Invoke Ruby method from C
+==== Invoke Ruby Method from C
To invoke methods directly, you can use the function below
@@ -559,7 +559,7 @@ To invoke methods directly, you can use the function below
This function invokes a method on the recv, with the method name
specified by the symbol mid.
-==== Accessing the variables and constants
+==== Accessing the Variables and Constants
You can access class variables and instance variables using access
functions. Also, global variables can be shared between both
@@ -578,9 +578,9 @@ To access the constants of the class/module:
See also Constant Definition above.
-== Information sharing between Ruby and C
+== Information Sharing Between Ruby and C
-=== Ruby constants that can be accessed from C
+=== Ruby Constants That Can Be Accessed From C
As stated in section 1.3,
the following Ruby constants can be referred from C.
@@ -594,7 +594,7 @@ Qnil ::
Ruby nil in C scope.
-=== Global variables shared between C and Ruby
+=== Global Variables Shared Between C and Ruby
Information can be shared between the two environments using shared global
variables. To define them, you can use functions listed below:
@@ -636,7 +636,7 @@ The prototypes of the getter and setter functions are as follows:
VALUE (*getter)(ID id);
void (*setter)(VALUE val, ID id);
-=== Encapsulate C data into a Ruby object
+=== Encapsulate C Data into a Ruby Object
Sometimes you need to expose your struct in the C world as a Ruby
object.
@@ -747,100 +747,33 @@ RUBY_TYPED_WB_PROTECTED ::
barriers in all implementations of methods of that object as
appropriate. Otherwise Ruby might crash while running.
- More about write barriers can be found in {Generational
- GC}[rdoc-ref:@Appendix+D.+Generational+GC].
+ More about write barriers can be found in "Generational GC" in
+ Appendix D.
RUBY_TYPED_FROZEN_SHAREABLE ::
- This flag indicates that the object is shareable object if the object
- is frozen. See {Ractor support}[rdoc-ref:@Appendix+F.+Ractor+support]
- more details.
+ This flag indicates that the object is shareable object
+ if the object is frozen. See Appendix F more details.
If this flag is not set, the object can not become a shareable
object by Ractor.make_shareable() method.
-Note that this macro can raise an exception. If sval to be wrapped
-holds a resource needs to be released (e.g., allocated memory, handle
-from an external library, and etc), you will have to use rb_protect.
-
-You can allocate and wrap the structure in one step, in more
-preferable manner.
+You can allocate and wrap the structure in one step.
TypedData_Make_Struct(klass, type, data_type, sval)
-This macro returns an allocated T_DATA object, wrapping the pointer to
+This macro returns an allocated Data object, wrapping the pointer to
the structure, which is also allocated. This macro works like:
(sval = ZALLOC(type), TypedData_Wrap_Struct(klass, data_type, sval))
-However, you should use this macro instead of "allocation then wrap"
-like the above code if it is simply allocated, because the latter can
-raise a NoMemoryError and sval will be memory leaked in that case.
-
Arguments klass and data_type work like their counterparts in
TypedData_Wrap_Struct(). A pointer to the allocated structure will
be assigned to sval, which should be a pointer of the type specified.
-==== Declaratively marking/compacting struct references
-
-In the case where your struct refers to Ruby objects that are simple values,
-not wrapped in conditional logic or complex data structures an alternative
-approach to marking and reference updating is provided, by declaring offset
-references to the VALUES in your struct.
-
-Doing this allows the Ruby GC to support marking these references and GC
-compaction without the need to define the +dmark+ and +dcompact+ callbacks.
-
-You must define a static list of VALUE pointers to the offsets within your
-struct where the references are located, and set the "data" member to point to
-this reference list. The reference list must end with +RUBY_END_REFS+.
-
-Some Macros have been provided to make edge referencing easier:
-
-* <code>RUBY_TYPED_DECL_MARKING</code> =A flag that can be set on the +ruby_data_type_t+ to indicate that references are being declared as edges.
-
-* <code>RUBY_REFERENCES(ref_list_name)</code> - Define _ref_list_name_ as a list of references
-
-* <code>RUBY_REF_END</code> - The end mark of the references list.
-
-* <code>RUBY_REF_EDGE(struct, member)</code> - Declare _member_ as a VALUE edge from _struct_. Use this after +RUBY_REFERENCES_START+
-
-* +RUBY_REFS_LIST_PTR+ - Coerce the reference list into a format that can be
- accepted by the existing +dmark+ interface.
-
-The example below is from Dir (defined in +dir.c+)
-
- // The struct being wrapped. Notice this contains 3 members of which the second
- // is a VALUE reference to another ruby object.
- struct dir_data {
- DIR *dir;
- const VALUE path;
- rb_encoding *enc;
- }
-
- // Define a reference list `dir_refs` containing a single entry to `path`.
- // Needs terminating with RUBY_REF_END
- RUBY_REFERENCES(dir_refs) = {
- RUBY_REF_EDGE(dir_data, path),
- RUBY_REF_END
- };
-
- // Override the "dmark" field with the defined reference list now that we
- // no longer need a marking callback and add RUBY_TYPED_DECL_MARKING to the
- // flags field
- static const rb_data_type_t dir_data_type = {
- "dir",
- {RUBY_REFS_LIST_PTR(dir_refs), dir_free, dir_memsize,},
- 0, NULL, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_DECL_MARKING
- };
-
-Declaring simple references declaratively in this manner allows the GC to both
-mark, and move the underlying object, and automatically update the reference to
-it during compaction.
-
==== Ruby object to C struct
-To retrieve the C pointer from the T_DATA object, use the macro
+To retrieve the C pointer from the Data object, use the macro
TypedData_Get_Struct().
TypedData_Get_Struct(obj, type, &data_type, sval)
@@ -855,7 +788,7 @@ OK, here's the example of making an extension library. This is the
extension to access DBMs. The full source is included in the ext/
directory in the Ruby's source tree.
-=== Make the directory
+=== Make the Directory
% mkdir ext/dbm
@@ -1066,7 +999,7 @@ If a compilation condition is not fulfilled, you should not call
``create_makefile''. The Makefile will not be generated, compilation will
not be done.
-=== Prepare depend (Optional)
+=== Prepare Depend (Optional)
If the file named depend exists, Makefile will include that file to
check dependencies. You can make this file by invoking
@@ -1105,15 +1038,15 @@ You may need to rb_debug the extension. Extensions can be linked
statically by adding the directory name in the ext/Setup file so that
you can inspect the extension with the debugger.
-=== Done! Now you have the extension library
+=== Done! Now You Have the Extension Library
You can do anything you want with your library. The author of Ruby
will not claim any restrictions on your code depending on the Ruby API.
Feel free to use, modify, distribute or sell your program.
-== Appendix A. Ruby header and source files overview
+== Appendix A. Ruby Header and Source Files Overview
-=== Ruby header files
+=== Ruby Header Files
Everything under <tt>$repo_root/include/ruby</tt> is installed with
<tt>make install</tt>.
@@ -1130,7 +1063,7 @@ Header files under <tt>$repo_root/internal/</tt> or directly under the
root <tt>$repo_root/*.h</tt> are not make-installed.
They are internal headers with only internal APIs.
-=== Ruby language core
+=== Ruby Language Core
class.c :: classes and modules
error.c :: exception classes and exception mechanism
@@ -1139,14 +1072,14 @@ load.c :: library loading
object.c :: objects
variable.c :: variables and constants
-=== Ruby syntax parser
+=== Ruby Syntax Parser
parse.y :: grammar definition
parse.c :: automatically generated from parse.y
defs/keywords :: reserved keywords
lex.c :: automatically generated from keywords
-=== Ruby evaluator (a.k.a. YARV)
+=== Ruby Evaluator (a.k.a. YARV)
compile.c
eval.c
@@ -1172,7 +1105,7 @@ lex.c :: automatically generated from keywords
-> opt*.inc : automatically generated
-> vm.inc : automatically generated
-=== Regular expression engine (Onigumo)
+=== Regular Expression Engine (Onigumo)
regcomp.c
regenc.c
@@ -1181,7 +1114,7 @@ lex.c :: automatically generated from keywords
regparse.c
regsyntax.c
-=== Utility functions
+=== Utility Functions
debug.c :: debug symbols for C debugger
dln.c :: dynamic loading
@@ -1189,7 +1122,7 @@ st.c :: general purpose hash table
strftime.c :: formatting times
util.c :: misc utilities
-=== Ruby interpreter implementation
+=== Ruby Interpreter Implementation
dmyext.c
dmydln.c
@@ -1203,7 +1136,7 @@ util.c :: misc utilities
gem_prelude.rb
prelude.rb
-=== Class library
+=== Class Library
array.c :: Array
bignum.c :: Bignum
@@ -1242,13 +1175,13 @@ transcode.c :: Encoding::Converter
enc/*.c :: encoding classes
enc/trans/* :: codepoint mapping tables
-=== goruby interpreter implementation
+=== goruby Interpreter Implementation
goruby.c
golf_prelude.rb : goruby specific libraries.
-> golf_prelude.c : automatically generated
-== Appendix B. Ruby extension API reference
+== Appendix B. Ruby Extension API Reference
=== Types
@@ -1258,7 +1191,7 @@ VALUE ::
such as struct RString, etc. To refer the values in structures, use
casting macros like RSTRING(obj).
-=== Variables and constants
+=== Variables and Constants
Qnil ::
@@ -1272,7 +1205,7 @@ Qfalse ::
false object
-=== C pointer wrapping
+=== C Pointer Wrapping
Data_Wrap_Struct(VALUE klass, void (*mark)(), void (*free)(), void *sval) ::
@@ -1292,7 +1225,7 @@ Data_Get_Struct(data, type, sval) ::
This macro retrieves the pointer value from DATA, and assigns it to
the variable sval.
-=== Checking VALUE types
+=== Checking Data Types
RB_TYPE_P(value, type) ::
@@ -1322,7 +1255,7 @@ void Check_Type(VALUE value, int type) ::
Ensures +value+ is of the given internal +type+ or raises a TypeError
-=== VALUE type conversion
+=== Data Type Conversion
FIX2INT(value), INT2FIX(i) ::
@@ -1406,7 +1339,7 @@ rb_str_new2(s) ::
char * -> String
-=== Defining classes and modules
+=== Defining Classes and Modules
VALUE rb_define_class(const char *name, VALUE super) ::
@@ -1433,7 +1366,7 @@ void rb_extend_object(VALUE object, VALUE module) ::
Extend the object with the module's attributes.
-=== Defining global variables
+=== Defining Global Variables
void rb_define_variable(const char *name, VALUE *var) ::
@@ -1477,7 +1410,7 @@ void rb_gc_register_mark_object(VALUE object) ::
Tells GC to protect the +object+, which may not be referenced anywhere.
-=== Constant definition
+=== Constant Definition
void rb_define_const(VALUE klass, const char *name, VALUE val) ::
@@ -1489,7 +1422,7 @@ void rb_define_global_const(const char *name, VALUE val) ::
rb_define_const(rb_cObject, name, val)
-=== Method definition
+=== Method Definition
rb_define_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc) ::
@@ -1665,7 +1598,7 @@ int rb_respond_to(VALUE obj, ID id) ::
Returns true if the object responds to the message specified by id.
-=== Instance variables
+=== Instance Variables
VALUE rb_iv_get(VALUE obj, const char *name) ::
@@ -1676,7 +1609,7 @@ VALUE rb_iv_set(VALUE obj, const char *name, VALUE val) ::
Sets the value of the instance variable.
-=== Control structure
+=== Control Structure
VALUE rb_block_call(VALUE recv, ID mid, int argc, VALUE * argv, VALUE (*func) (ANYARGS), VALUE data2) ::
@@ -1772,7 +1705,7 @@ void rb_iter_break_value(VALUE value) ::
return the given argument value. This function never return to the
caller.
-=== Exceptions and errors
+=== Exceptions and Errors
void rb_warn(const char *fmt, ...) ::
@@ -1845,7 +1778,7 @@ int rb_wait_for_single_fd(int fd, int events, struct timeval *timeout) ::
Use a NULL +timeout+ to wait indefinitely.
-=== I/O multiplexing
+=== I/O Multiplexing
Ruby supports I/O multiplexing based on the select(2) system call.
The Linux select_tut(2) manpage
@@ -1897,7 +1830,7 @@ int rb_thread_fd_select(int nfds, rb_fdset_t *readfds, rb_fdset_t *writefds, rb_
rb_io_wait_writable, or rb_wait_for_single_fd functions since
they can be optimized for specific platforms (currently, only Linux).
-=== Initialize and start the interpreter
+=== Initialize and Start the Interpreter
The embedding API functions are below (not needed for extension libraries):
@@ -1922,7 +1855,7 @@ void ruby_script(char *name) ::
Specifies the name of the script ($0).
-=== Hooks for the interpreter events
+=== Hooks for the Interpreter Events
void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data) ::
@@ -1964,7 +1897,7 @@ void rb_gc_adjust_memory_usage(ssize_t diff) ::
is decreased; a memory block is freed or a block is reallocated as
smaller size. This function may trigger the GC.
-=== Macros for compatibility
+=== Macros for Compatibility
Some macros to check API compatibilities are available by default.
@@ -2219,72 +2152,70 @@ Ractor safety around C extensions has the following properties:
To make a "Ractor-safe" C extension, we need to check the following points:
-1. Do not share unshareable objects between ractors
+(1) Do not share unshareable objects between ractors
- For example, C's global variable can lead sharing an unshareable objects
- between ractors.
+For example, C's global variable can lead sharing an unshareable objects
+between ractors.
- VALUE g_var;
- VALUE set(VALUE self, VALUE v){ return g_var = v; }
- VALUE get(VALUE self){ return g_var; }
+ VALUE g_var;
+ VALUE set(VALUE self, VALUE v){ return g_var = v; }
+ VALUE get(VALUE self){ return g_var; }
- set() and get() pair can share an unshareable objects using g_var, and
- it is Ractor-unsafe.
+set() and get() pair can share an unshareable objects using g_var, and
+it is Ractor-unsafe.
- Not only using global variables directly, some indirect data structure
- such as global st_table can share the objects, so please take care.
+Not only using global variables directly, some indirect data structure
+such as global st_table can share the objects, so please take care.
- Note that class and module objects are shareable objects, so you can
- keep the code "cFoo = rb_define_class(...)" with C's global variables.
+Note that class and module objects are shareable objects, so you can
+keep the code "cFoo = rb_define_class(...)" with C's global variables.
-2. Check the thread-safety of the extension
+(2) Check the thread-safety of the extension
- An extension should be thread-safe. For example, the following code is
- not thread-safe:
+An extension should be thread-safe. For example, the following code is
+not thread-safe:
- bool g_called = false;
- VALUE call(VALUE self) {
- if (g_called) rb_raise("recursive call is not allowed.");
- g_called = true;
- VALUE ret = do_something();
- g_called = false;
- return ret;
- }
+ bool g_called = false;
+ VALUE call(VALUE self) {
+ if (g_called) rb_raise("recursive call is not allowed.");
+ g_called = true;
+ VALUE ret = do_something();
+ g_called = false;
+ return ret;
+ }
- because g_called global variable should be synchronized by other
- ractor's threads. To avoid such data-race, some synchronization should
- be used. Check include/ruby/thread_native.h and include/ruby/atomic.h.
+because g_called global variable should be synchronized by other
+ractor's threads. To avoid such data-race, some synchronization should
+be used. Check include/ruby/thread_native.h and include/ruby/atomic.h.
- With Ractors, all objects given as method parameters and the receiver (self)
- are guaranteed to be from the current Ractor or to be shareable. As a
- consequence, it is easier to make code ractor-safe than to make code generally
- thread-safe. For example, we don't need to lock an array object to access the
- element of it.
+With Ractors, all objects given as method parameters and the receiver (self)
+are guaranteed to be from the current Ractor or to be shareable. As a
+consequence, it is easier to make code ractor-safe than to make code generally
+thread-safe. For example, we don't need to lock an array object to access the
+element of it.
-3. Check the thread-safety of any used library
+(3) Check the thread-safety of any used library
- If the extension relies on an external library, such as a function foo() from
- a library libfoo, the function libfoo foo() should be thread safe.
+If the extension relies on an external library, such as a function foo() from
+a library libfoo, the function libfoo foo() should be thread safe.
-4. Make an object shareable
+(4) Make an object shareable
- This is not required to make an extension Ractor-safe.
+This is not required to make an extension Ractor-safe.
- If an extension provides special objects defined by rb_data_type_t,
- consider these objects can become shareable or not.
+If an extension provides special objects defined by rb_data_type_t,
+consider these objects can become shareable or not.
- RUBY_TYPED_FROZEN_SHAREABLE flag indicates that these objects can be
- shareable objects if the object is frozen. This means that if the object
- is frozen, the mutation of wrapped data is not allowed.
+RUBY_TYPED_FROZEN_SHAREABLE flag indicates that these objects can be
+shareable objects if the object is frozen. This means that if the object
+is frozen, the mutation of wrapped data is not allowed.
-5. Others
+(5) Others
- There are possibly other points or requirements which must be considered in the
- making of a Ractor-safe extension. This document will be extended as they are
- discovered.
+There are possibly other points or requirements which must be considered in the
+making of a Ractor-safe extension. This document will be extended as they are
+discovered.
---
-Local variables:
-fill-column: 70
-end:
-++
+:enddoc: Local variables:
+:enddoc: fill-column: 70
+:enddoc: end:
diff --git a/doc/format_specifications.rdoc b/doc/format_specifications.rdoc
index bdfdc24953..e589524f27 100644
--- a/doc/format_specifications.rdoc
+++ b/doc/format_specifications.rdoc
@@ -1,4 +1,4 @@
-= Format Specifications
+== Format Specifications
Several Ruby core classes have instance method +printf+ or +sprintf+:
@@ -37,12 +37,12 @@ It consists of:
Except for the leading percent character,
the only required part is the type specifier, so we begin with that.
-== Type Specifiers
+=== Type Specifiers
This section provides a brief explanation of each type specifier.
The links lead to the details and examples.
-=== \Integer Type Specifiers
+==== \Integer Type Specifiers
- +b+ or +B+: Format +argument+ as a binary integer.
See {Specifiers b and B}[rdoc-ref:format_specifications.rdoc@Specifiers+b+and+B].
@@ -54,7 +54,7 @@ The links lead to the details and examples.
- +x+ or +X+: Format +argument+ as a hexadecimal integer.
See {Specifiers x and X}[rdoc-ref:format_specifications.rdoc@Specifiers+x+and+X].
-=== Floating-Point Type Specifiers
+==== Floating-Point Type Specifiers
- +a+ or +A+: Format +argument+ as hexadecimal floating-point number.
See {Specifiers a and A}[rdoc-ref:format_specifications.rdoc@Specifiers+a+and+A].
@@ -65,7 +65,7 @@ The links lead to the details and examples.
- +g+ or +G+: Format +argument+ in a "general" format.
See {Specifiers g and G}[rdoc-ref:format_specifications.rdoc@Specifiers+g+and+G].
-=== Other Type Specifiers
+==== Other Type Specifiers
- +c+: Format +argument+ as a character.
See {Specifier c}[rdoc-ref:format_specifications.rdoc@Specifier+c].
@@ -76,7 +76,7 @@ The links lead to the details and examples.
- <tt>%</tt>: Format +argument+ (<tt>'%'</tt>) as a single percent character.
See {Specifier %}[rdoc-ref:format_specifications.rdoc@Specifier+-25].
-== Flags
+=== Flags
The effect of a flag may vary greatly among type specifiers.
These remarks are general in nature.
@@ -85,7 +85,7 @@ See {type-specific details}[rdoc-ref:format_specifications.rdoc@Type+Specifier+D
Multiple flags may be given with single type specifier;
order does not matter.
-=== <tt>' '</tt> Flag
+==== <tt>' '</tt> Flag
Insert a space before a non-negative number:
@@ -97,49 +97,49 @@ Insert a minus sign for negative value:
sprintf('%d', -10) # => "-10"
sprintf('% d', -10) # => "-10"
-=== <tt>'#'</tt> Flag
+==== <tt>'#'</tt> Flag
Use an alternate format; varies among types:
sprintf('%x', 100) # => "64"
sprintf('%#x', 100) # => "0x64"
-=== <tt>'+'</tt> Flag
+==== <tt>'+'</tt> Flag
Add a leading plus sign for a non-negative number:
sprintf('%x', 100) # => "64"
sprintf('%+x', 100) # => "+64"
-=== <tt>'-'</tt> Flag
+==== <tt>'-'</tt> Flag
Left justify the value in its field:
sprintf('%6d', 100) # => " 100"
sprintf('%-6d', 100) # => "100 "
-=== <tt>'0'</tt> Flag
+==== <tt>'0'</tt> Flag
Left-pad with zeros instead of spaces:
sprintf('%6d', 100) # => " 100"
sprintf('%06d', 100) # => "000100"
-=== <tt>'*'</tt> Flag
+==== <tt>'*'</tt> Flag
Use the next argument as the field width:
sprintf('%d', 20, 14) # => "20"
sprintf('%*d', 20, 14) # => " 14"
-=== <tt>'n$'</tt> Flag
+==== <tt>'n$'</tt> Flag
Format the (1-based) <tt>n</tt>th argument into this field:
sprintf("%s %s", 'world', 'hello') # => "world hello"
sprintf("%2$s %1$s", 'world', 'hello') # => "hello world"
-== Width Specifier
+=== Width Specifier
In general, a width specifier determines the minimum width (in characters)
of the formatted field:
@@ -152,7 +152,7 @@ of the formatted field:
# Ignore if too small.
sprintf('%1d', 100) # => "100"
-== Precision Specifier
+=== Precision Specifier
A precision specifier is a decimal point followed by zero or more
decimal digits.
@@ -194,9 +194,9 @@ the number of characters to write:
sprintf('%s', Time.now) # => "2022-05-04 11:59:16 -0400"
sprintf('%.10s', Time.now) # => "2022-05-04"
-== Type Specifier Details and Examples
+=== Type Specifier Details and Examples
-=== Specifiers +a+ and +A+
+==== Specifiers +a+ and +A+
Format +argument+ as hexadecimal floating-point number:
@@ -209,7 +209,7 @@ Format +argument+ as hexadecimal floating-point number:
sprintf('%A', 4096) # => "0X1P+12"
sprintf('%A', -4096) # => "-0X1P+12"
-=== Specifiers +b+ and +B+
+==== Specifiers +b+ and +B+
The two specifiers +b+ and +B+ behave identically
except when flag <tt>'#'</tt>+ is used.
@@ -226,16 +226,14 @@ Format +argument+ as a binary integer:
sprintf('%#b', 4) # => "0b100"
sprintf('%#B', 4) # => "0B100"
-=== Specifier +c+
+==== Specifier +c+
Format +argument+ as a single character:
sprintf('%c', 'A') # => "A"
sprintf('%c', 65) # => "A"
-This behaves like String#<<, except for raising ArgumentError instead of RangeError.
-
-=== Specifier +d+
+==== Specifier +d+
Format +argument+ as a decimal integer:
@@ -244,7 +242,7 @@ Format +argument+ as a decimal integer:
Flag <tt>'#'</tt> does not apply.
-=== Specifiers +e+ and +E+
+==== Specifiers +e+ and +E+
Format +argument+ in
{scientific notation}[https://en.wikipedia.org/wiki/Scientific_notation]:
@@ -252,7 +250,7 @@ Format +argument+ in
sprintf('%e', 3.14159) # => "3.141590e+00"
sprintf('%E', -3.14159) # => "-3.141590E+00"
-=== Specifier +f+
+==== Specifier +f+
Format +argument+ as a floating-point number:
@@ -261,7 +259,7 @@ Format +argument+ as a floating-point number:
Flag <tt>'#'</tt> does not apply.
-=== Specifiers +g+ and +G+
+==== Specifiers +g+ and +G+
Format +argument+ using exponential form (+e+/+E+ specifier)
if the exponent is less than -4 or greater than or equal to the precision.
@@ -283,7 +281,7 @@ Otherwise format +argument+ using floating-point form (+f+ specifier):
sprintf('%#G', 100000000000) # => "1.00000E+11"
sprintf('%#G', 0.000000000001) # => "1.00000E-12"
-=== Specifier +o+
+==== Specifier +o+
Format +argument+ as an octal integer.
If +argument+ is negative, it will be formatted as a two's complement
@@ -298,14 +296,14 @@ prefixed with +..7+:
sprintf('%#o', 16) # => "020"
sprintf('%#o', -16) # => "..760"
-=== Specifier +p+
+==== Specifier +p+
Format +argument+ as a string via <tt>argument.inspect</tt>:
t = Time.now
sprintf('%p', t) # => "2022-05-01 13:42:07.1645683 -0500"
-=== Specifier +s+
+==== Specifier +s+
Format +argument+ as a string via <tt>argument.to_s</tt>:
@@ -314,7 +312,7 @@ Format +argument+ as a string via <tt>argument.to_s</tt>:
Flag <tt>'#'</tt> does not apply.
-=== Specifiers +x+ and +X+
+==== Specifiers +x+ and +X+
Format +argument+ as a hexadecimal integer.
If +argument+ is negative, it will be formatted as a two's complement
@@ -331,7 +329,7 @@ prefixed with +..f+:
# Alternate format for negative value.
sprintf('%#x', -100) # => "0x..f9c"
-=== Specifier <tt>%</tt>
+==== Specifier <tt>%</tt>
Format +argument+ (<tt>'%'</tt>) as a single percent character:
@@ -339,7 +337,7 @@ Format +argument+ (<tt>'%'</tt>) as a single percent character:
Flags do not apply.
-== Reference by Name
+=== Reference by Name
For more complex formatting, Ruby supports a reference by name.
%<name>s style uses format style, but %{name} style doesn't.
diff --git a/doc/forwardable.rd.ja b/doc/forwardable.rd.ja
index 53e8202513..171724b2e5 100644
--- a/doc/forwardable.rd.ja
+++ b/doc/forwardable.rd.ja
@@ -1,4 +1,4 @@
- -- forwardable.rb
+ -- forwatable.rb
$Release Version: 1.1 $
$Revision$
diff --git a/doc/globals.rdoc b/doc/globals.rdoc
index 9d9fc57e6e..1d7cda69f9 100644
--- a/doc/globals.rdoc
+++ b/doc/globals.rdoc
@@ -1,416 +1,69 @@
-= Pre-Defined Global Variables
-
-Some of the pre-defined global variables have synonyms
-that are available via module English.
-For each of those, the \English synonym is given.
-
-To use the module:
-
- require 'English'
-
-== Exceptions
-
-=== <tt>$!</tt> (\Exception)
-
-Contains the Exception object set by Kernel#raise:
-
- begin
- raise RuntimeError.new('Boo!')
- rescue RuntimeError
- p $!
- end
-
-Output:
-
- #<RuntimeError: Boo!>
-
-English - <tt>$ERROR_INFO</tt>
-
-=== <tt>$@</tt> (Backtrace)
-
-Same as <tt>$!.backtrace</tt>;
-returns an array of backtrace positions:
-
- begin
- raise RuntimeError.new('Boo!')
- rescue RuntimeError
- pp $@.take(4)
- end
-
-Output:
-
- ["(irb):338:in `<top (required)>'",
- "/snap/ruby/317/lib/ruby/3.2.0/irb/workspace.rb:119:in `eval'",
- "/snap/ruby/317/lib/ruby/3.2.0/irb/workspace.rb:119:in `evaluate'",
- "/snap/ruby/317/lib/ruby/3.2.0/irb/context.rb:502:in `evaluate'"]
-
-English - <tt>$ERROR_POSITION</tt>.
-
-== Pattern Matching
-
-These global variables store information about the most recent
-successful match in the current scope.
-
-For details and examples,
-see {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
-
-=== <tt>$~</tt> (\MatchData)
-
-MatchData object created from the match;
-thread-local and frame-local.
-
-English - <tt>$LAST_MATCH_INFO</tt>.
-
-=== <tt>$&</tt> (Matched Substring)
-
-The matched string.
-
-English - <tt>$MATCH</tt>.
-
-=== <tt>$`</tt> (Pre-Match Substring)
-
-The string to the left of the match.
-
-English - <tt>$PREMATCH</tt>.
-
-=== <tt>$'</tt> (Post-Match Substring)
-
-The string to the right of the match.
-
-English - <tt>$POSTMATCH</tt>.
-
-=== <tt>$+</tt> (Last Matched Group)
-
-The last group matched.
-
-English - <tt>$LAST_PAREN_MATCH</tt>.
-
-=== <tt>$1</tt>, <tt>$2</tt>, \Etc. (Matched Group)
-
-For <tt>$_n_</tt> the _nth_ group of the match.
-
-No \English.
-
-== Separators
-
-=== <tt>$/</tt> (Input Record Separator)
-
-An input record separator, initially newline.
-
-English - <tt>$INPUT_RECORD_SEPARATOR</tt>, <tt>$RS</tt>.
-
-Aliased as <tt>$-0</tt>.
-
-=== <tt>$\\</tt> (Output Record Separator)
-
-An output record separator, initially +nil+.
-
-English - <tt>$OUTPUT_RECORD_SEPARATOR</tt>, <tt>$ORS</tt>.
-
-== Streams
-
-=== <tt>$stdin</tt> (Standard Input)
-
-The current standard input stream; initially:
-
- $stdin # => #<IO:<STDIN>>
-
-=== <tt>$stdout</tt> (Standard Output)
-
-The current standard output stream; initially:
-
- $stdout # => #<IO:<STDOUT>>
-
-=== <tt>$stderr</tt> (Standard Error)
-
-The current standard error stream; initially:
-
- $stderr # => #<IO:<STDERR>>
-
-=== <tt>$<</tt> (\ARGF or $stdin)
-
-Points to stream ARGF if not empty, else to stream $stdin; read-only.
-
-English - <tt>$DEFAULT_INPUT</tt>.
-
-=== <tt>$></tt> (Default Standard Output)
-
-An output stream, initially <tt>$stdout</tt>.
-
-English - <tt>$DEFAULT_OUTPUT
-
-=== <tt>$.</tt> (Input Position)
-
-The input position (line number) in the most recently read stream.
-
-English - <tt>$INPUT_LINE_NUMBER</tt>, <tt>$NR</tt>
-
-=== <tt>$_</tt> (Last Read Line)
-
-The line (string) from the most recently read stream.
-
-English - <tt>$LAST_READ_LINE</tt>.
-
-== Processes
-
-=== <tt>$0</tt>
-
-Initially, contains the name of the script being executed;
-may be reassigned.
-
-=== <tt>$*</tt> (\ARGV)
-
-Points to ARGV.
-
-English - <tt>$ARGV</tt>.
-
-=== <tt>$$</tt> (Process ID)
-
-The process ID of the current process. Same as Process.pid.
-
-English - <tt>$PROCESS_ID</tt>, <tt>$PID</tt>.
-
-=== <tt>$?</tt> (Child Status)
-
-Initially +nil+, otherwise the Process::Status object
-created for the most-recently exited child process;
-thread-local.
-
-English - <tt>$CHILD_STATUS</tt>.
-
-=== <tt>$LOAD_PATH</tt> (Load Path)
-
-Contains the array of paths to be searched
-by Kernel#load and Kernel#require.
-
-Singleton method <tt>$LOAD_PATH.resolve_feature_path(feature)</tt>
-returns:
-
-- <tt>[:rb, _path_]</tt>, where +path+ is the path to the Ruby file
- to be loaded for the given +feature+.
-- <tt>[:so+ _path_]</tt>, where +path+ is the path to the shared object file
- to be loaded for the given +feature+.
-- +nil+ if there is no such +feature+ and +path+.
-
-Examples:
-
- $LOAD_PATH.resolve_feature_path('timeout')
- # => [:rb, "/snap/ruby/317/lib/ruby/3.2.0/timeout.rb"]
- $LOAD_PATH.resolve_feature_path('date_core')
- # => [:so, "/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/date_core.so"]
- $LOAD_PATH.resolve_feature_path('foo')
- # => nil
-
-Aliased as <tt>$:</tt> and <tt>$-I</tt>.
-
-=== <tt>$LOADED_FEATURES</tt>
-
-Contains an array of the paths to the loaded files:
-
- $LOADED_FEATURES.take(10)
- # =>
- ["enumerator.so",
- "thread.rb",
- "fiber.so",
- "rational.so",
- "complex.so",
- "ruby2_keywords.rb",
- "/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/enc/encdb.so",
- "/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/enc/trans/transdb.so",
- "/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/rbconfig.rb",
- "/snap/ruby/317/lib/ruby/3.2.0/rubygems/compatibility.rb"]
-
-Aliased as <tt>$"</tt>.
-
-== Debugging
-
-=== <tt>$FILENAME</tt>
-
-The value returned by method ARGF.filename.
-
-=== <tt>$DEBUG</tt>
-
-Initially +true+ if command-line option <tt>-d</tt> or <tt>--debug</tt> is given,
-otherwise initially +false+;
-may be set to either value in the running program.
-
-When +true+, prints each raised exception to <tt>$stderr</tt>.
-
-Aliased as <tt>$-d</tt>.
-
-=== <tt>$VERBOSE</tt>
-
-Initially +true+ if command-line option <tt>-v</tt> or <tt>-w</tt> is given,
-otherwise initially +false+;
-may be set to either value, or to +nil+, in the running program.
-
-When +true+, enables Ruby warnings.
-
-When +nil+, disables warnings, including those from Kernel#warn.
-
-Aliased as <tt>$-v</tt> and <tt>$-w</tt>.
-
-== Other Variables
-
-=== <tt>$-a</tt>
-
-Whether command-line option <tt>-a</tt> was given; read-only.
-
-=== <tt>$-i</tt>
-
-Contains the extension given with command-line option <tt>-i</tt>,
-or +nil+ if none.
-
-An alias of ARGF.inplace_mode.
-
-=== <tt>$-l</tt>
-
-Whether command-line option <tt>-l</tt> was set; read-only.
-
-=== <tt>$-p</tt>
-
-Whether command-line option <tt>-p</tt> was given; read-only.
-
-== Deprecated
-
-=== <tt>$=</tt>
-
-=== <tt>$,</tt>
-
-=== <tt>$;</tt>
-
-= Pre-Defined Global Constants
-
-= Streams
-
-=== <tt>STDIN</tt>
-
-The standard input stream (the default value for <tt>$stdin</tt>):
-
- STDIN # => #<IO:<STDIN>>
-
-=== <tt>STDOUT</tt>
-
-The standard output stream (the default value for <tt>$stdout</tt>):
-
- STDOUT # => #<IO:<STDOUT>>
-
-=== <tt>STDERR</tt>
-
-The standard error stream (the default value for <tt>$stderr</tt>):
-
- STDERR # => #<IO:<STDERR>>
-
-== Environment
-
-=== ENV
-
-A hash of the contains current environment variables names and values:
-
- ENV.take(5)
- # =>
- [["COLORTERM", "truecolor"],
- ["DBUS_SESSION_BUS_ADDRESS", "unix:path=/run/user/1000/bus"],
- ["DESKTOP_SESSION", "ubuntu"],
- ["DISPLAY", ":0"],
- ["GDMSESSION", "ubuntu"]]
-
-=== ARGF
-
-The virtual concatenation of the files given on the command line, or from
-<tt>$stdin</tt> if no files were given, <tt>"-"</tt> is given, or after
-all files have been read.
-
-=== <tt>ARGV</tt>
-
-An array of the given command-line arguments.
-
-=== <tt>TOPLEVEL_BINDING</tt>
-
-The Binding of the top level scope:
-
- TOPLEVEL_BINDING # => #<Binding:0x00007f58da0da7c0>
-
-=== <tt>RUBY_VERSION</tt>
-
-The Ruby version:
-
- RUBY_VERSION # => "3.2.2"
-
-=== <tt>RUBY_RELEASE_DATE</tt>
-
-The release date string:
-
- RUBY_RELEASE_DATE # => "2023-03-30"
-
-=== <tt>RUBY_PLATFORM</tt>
-
-The platform identifier:
-
- RUBY_PLATFORM # => "x86_64-linux"
-
-=== <tt>RUBY_PATCHLEVEL</tt>
-
-The integer patch level for this Ruby:
-
- RUBY_PATCHLEVEL # => 53
-
-For a development build the patch level will be -1.
-
-=== <tt>RUBY_REVISION</tt>
-
-The git commit hash for this Ruby:
-
- RUBY_REVISION # => "e51014f9c05aa65cbf203442d37fef7c12390015"
-
-=== <tt>RUBY_COPYRIGHT</tt>
-
-The copyright string:
-
- RUBY_COPYRIGHT
- # => "ruby - Copyright (C) 1993-2023 Yukihiro Matsumoto"
-
-=== <tt>RUBY_ENGINE</tt>
-
-The name of the Ruby implementation:
-
- RUBY_ENGINE # => "ruby"
-
-=== <tt>RUBY_ENGINE_VERSION</tt>
-
-The version of the Ruby implementation:
-
- RUBY_ENGINE_VERSION # => "3.2.2"
-
-=== <tt>RUBY_DESCRIPTION</tt>
-
-The description of the Ruby implementation:
-
- RUBY_DESCRIPTION
- # => "ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]"
-
-== Embedded \Data
-
-=== <tt>DATA</tt>
-
-Defined if and only if the program has this line:
-
- __END__
-
-When defined, <tt>DATA</tt> is a File object
-containing the lines following the <tt>__END__</tt>,
-positioned at the first of those lines:
-
- p DATA
- DATA.each_line { |line| p line }
- __END__
- Foo
- Bar
- Baz
-
-Output:
-
- #<File:t.rb>
- "Foo\n"
- "Bar\n"
- "Baz\n"
+# -*- mode: rdoc; coding: utf-8; fill-column: 74; -*-
+
+== Pre-defined global variables
+
+$!:: The Exception object set by Kernel#raise.
+$@:: The same as <code>$!.backtrace</code>.
+$~:: The information about the last match in the current scope (thread-local and frame-local).
+$&:: The string matched by the last successful match.
+$`:: The string to the left of the last successful match.
+$':: The string to the right of the last successful match.
+$+:: The highest group matched by the last successful match.
+$1:: The Nth group of the last successful match. May be > 1.
+$=:: This variable is no longer effective. Deprecated.
+$/:: The input record separator, newline by default. Aliased to $-0.
+$\:: The output record separator for Kernel#print and IO#write. Default is +nil+.
+$,:: The output field separator for Kernel#print and Array#join. Non-nil $, will be deprecated.
+$;:: The default separator for String#split. Non-nil $; will be deprecated. Aliased to $-F.
+$.:: The current input line number of the last file that was read.
+$<:: The same as ARGF.
+$>:: The default output stream for Kernel#print and Kernel#printf. $stdout by default.
+$_:: The last input line of string by gets or readline.
+$0:: Contains the name of the script being executed. May be assignable.
+$*:: The same as ARGV.
+$$:: The process number of the Ruby running this script. Same as Process.pid.
+$?:: The status of the last executed child process (thread-local).
+$LOAD_PATH:: Load path for searching Ruby scripts and extension libraries used
+ by Kernel#load and Kernel#require. Aliased to $: and $-I.
+ Has a singleton method <code>$LOAD_PATH.resolve_feature_path(feature)</code>
+ that returns [+:rb+ or +:so+, path], which resolves the feature to
+ the path the original Kernel#require method would load.
+$LOADED_FEATURES:: The array contains the module names loaded by require.
+ Aliased to $".
+$DEBUG:: The debug flag, which is set by the <tt>-d</tt> switch. Enabling debug
+ output prints each exception raised to $stderr (but not its
+ backtrace). Setting this to a true value enables debug output as
+ if <tt>-d</tt> were given on the command line. Setting this to a false
+ value disables debug output. Aliased to $-d.
+$FILENAME:: Current input filename from ARGF. Same as ARGF.filename.
+$stderr:: The current standard error output.
+$stdin:: The current standard input.
+$stdout:: The current standard output.
+$VERBOSE:: The verbose flag, which is set by the <tt>-w</tt> or <tt>-v</tt> switch.
+ Setting this to a true value enables warnings as if <tt>-w</tt> or <tt>-v</tt> were given
+ on the command line. Setting this to +nil+ disables warnings,
+ including from Kernel#warn. Aliased to $-v and $-w.
+$-a:: True if option <tt>-a</tt> is set. Read-only variable.
+$-i:: In in-place-edit mode, this variable holds the extension, otherwise +nil+.
+$-l:: True if option <tt>-l</tt> is set. Read-only variable.
+$-p:: True if option <tt>-p</tt> is set. Read-only variable.
+
+== Pre-defined global constants
+
+STDIN:: The standard input. The default value for $stdin.
+STDOUT:: The standard output. The default value for $stdout.
+STDERR:: The standard error output. The default value for $stderr.
+ENV:: The hash contains current environment variables.
+ARGF:: The virtual concatenation of the files given on command line (or from $stdin if no files were given).
+ARGV:: An Array of command line arguments given for the script.
+DATA:: The file object of the script, pointing just after <code>__END__</code>.
+TOPLEVEL_BINDING:: The Binding of the top level scope.
+RUBY_VERSION:: The Ruby language version.
+RUBY_RELEASE_DATE:: The release date string.
+RUBY_PLATFORM:: The platform identifier.
+RUBY_PATCHLEVEL:: The patchlevel for this Ruby. If this is a development build of Ruby the patchlevel will be -1.
+RUBY_REVISION:: The GIT commit hash for this Ruby.
+RUBY_COPYRIGHT:: The copyright string for Ruby.
+RUBY_ENGINE:: The name of the Ruby implementation.
+RUBY_ENGINE_VERSION:: The version of the Ruby implementation.
+RUBY_DESCRIPTION:: The same as <tt>ruby --version</tt>, a String describing various aspects of the Ruby implementation.
diff --git a/doc/implicit_conversion.rdoc b/doc/implicit_conversion.rdoc
index e244096125..ba15fa4bf4 100644
--- a/doc/implicit_conversion.rdoc
+++ b/doc/implicit_conversion.rdoc
@@ -1,4 +1,4 @@
-= Implicit Conversions
+== Implicit Conversions
Some Ruby methods accept one or more objects
that can be either:
@@ -15,7 +15,7 @@ a specific conversion method:
* Integer: +to_int+
* String: +to_str+
-== Array-Convertible Objects
+=== Array-Convertible Objects
An <i>Array-convertible object</i> is an object that:
@@ -69,7 +69,7 @@ This class is not Array-convertible (method +to_ary+ returns non-Array):
# Raises TypeError (can't convert NotArrayConvertible to Array (NotArrayConvertible#to_ary gives Symbol))
a.replace(NotArrayConvertible.new)
-== Hash-Convertible Objects
+=== Hash-Convertible Objects
A <i>Hash-convertible object</i> is an object that:
@@ -123,7 +123,7 @@ This class is not Hash-convertible (method +to_hash+ returns non-Hash):
# Raises TypeError (can't convert NotHashConvertible to Hash (ToHashReturnsNonHash#to_hash gives Symbol))
h.merge(NotHashConvertible.new)
-== Integer-Convertible Objects
+=== Integer-Convertible Objects
An <i>Integer-convertible object</i> is an object that:
@@ -171,7 +171,7 @@ This class is not Integer-convertible (method +to_int+ returns non-Integer):
# Raises TypeError (can't convert NotIntegerConvertible to Integer (NotIntegerConvertible#to_int gives Symbol))
Array.new(NotIntegerConvertible.new)
-== String-Convertible Objects
+=== String-Convertible Objects
A <i>String-convertible object</i> is an object that:
* Has instance method +to_str+.
diff --git a/doc/irb/indexes.md b/doc/irb/indexes.md
deleted file mode 100644
index d6dc5c160e..0000000000
--- a/doc/irb/indexes.md
+++ /dev/null
@@ -1,189 +0,0 @@
-## Indexes
-
-### Index of Command-Line Options
-
-These are the \IRB command-line options, with links to explanatory text:
-
-- `-d`: Set `$DEBUG` and {$VERBOSE}[rdoc-ref:IRB@Verbosity]
- to `true`.
-- `-E _ex_[:_in_]`: Set initial external (ex) and internal (in)
- {encodings}[rdoc-ref:IRB@Encodings] (same as `ruby -E`).
-- `-f`: Don't initialize from {configuration file}[rdoc-ref:IRB@Configuration+File].
-- `-I _dirpath_`: Specify {$LOAD_PATH directory}[rdoc-ref:IRB@Load+Modules]
- (same as `ruby -I`).
-- `-r _load-module_`: Require {load-module}[rdoc-ref:IRB@Load+Modules]
- (same as `ruby -r`).
-- `-U`: Set external and internal {encodings}[rdoc-ref:IRB@Encodings] to UTF-8.
-- `-w`: Suppress {warnings}[rdoc-ref:IRB@Warnings] (same as `ruby -w`).
-- `-W[_level_]`: Set {warning level}[rdoc-ref:IRB@Warnings];
- 0=silence, 1=medium, 2=verbose (same as `ruby -W`).
-- `--autocomplete`: Use {auto-completion}[rdoc-ref:IRB@Automatic+Completion].
-- `--back-trace-limit _n_`: Set a {backtrace limit}[rdoc-ref:IRB@Tracer];
- display at most the top `n` and bottom `n` entries.
-- `--colorize`: Use {color-highlighting}[rdoc-ref:IRB@Color+Highlighting]
- for input and output.
-- `--context-mode _n_`: Select method to create Binding object
- for new {workspace}[rdoc-ref:IRB@Commands]; `n` in range `0..4`.
-- `--echo`: Print ({echo}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- return values.
-- `--extra-doc-dir _dirpath_`:
- Add a {documentation directory}[rdoc-ref:IRB@RI+Documentation+Directories]
- for the documentation dialog.
-- `--inf-ruby-mode`: Set prompt mode to {:INF_RUBY}[rdoc-ref:IRB@Pre-Defined+Prompts]
- (appropriate for `inf-ruby-mode` on Emacs);
- suppresses --multiline and --singleline.
-- `--inspect`: Use method `inspect` for printing ({echoing}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- return values.
-- `--multiline`: Use the multiline editor as the {input method}[rdoc-ref:IRB@Input+Method].
-- `--noautocomplete`: Don't use {auto-completion}[rdoc-ref:IRB@Automatic+Completion].
-- `--nocolorize`: Don't use {color-highlighting}[rdoc-ref:IRB@Color+Highlighting]
- for input and output.
-- `--noecho`: Don't print ({echo}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- return values.
-- `--noecho-on-assignment`: Don't print ({echo}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- result on assignment.
-- `--noinspect`: Don't se method `inspect` for printing ({echoing}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- return values.
-- `--nomultiline`: Don't use the multiline editor as the {input method}[rdoc-ref:IRB@Input+Method].
-- `--noprompt`: Don't print {prompts}[rdoc-ref:IRB@Prompt+and+Return+Formats].
-- `--noscript`: Treat the first command-line argument as a normal
- {command-line argument}[rdoc-ref:IRB@Initialization+Script],
- and include it in `ARGV`.
-- `--nosingleline`: Don't use the singleline editor as the {input method}[rdoc-ref:IRB@Input+Method].
-- `--noverbose`: Don't print {verbose}[rdoc-ref:IRB@Verbosity] details.
-- `--prompt _mode_`, `--prompt-mode _mode_`:
- Set {prompt and return formats}[rdoc-ref:IRB@Prompt+and+Return+Formats];
- `mode` may be a {pre-defined prompt}[rdoc-ref:IRB@Pre-Defined+Prompts]
- or the name of a {custom prompt}[rdoc-ref:IRB@Custom+Prompts].
-- `--script`: Treat the first command-line argument as the path to an
- {initialization script}[rdoc-ref:IRB@Initialization+Script],
- and omit it from `ARGV`.
-- `--simple-prompt`, `--sample-book-mode`:
- Set prompt mode to {:SIMPLE}[rdoc-ref:IRB@Pre-Defined+Prompts].
-- `--singleline`: Use the singleline editor as the {input method}[rdoc-ref:IRB@Input+Method].
-- `--tracer`: Use {Tracer}[rdoc-ref:IRB@Tracer] to print a stack trace for each input command.
-- `--truncate-echo-on-assignment`: Print ({echo}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- truncated result on assignment.
-- `--verbose`Print {verbose}[rdoc-ref:IRB@Verbosity] details.
-- `-v`, `--version`: Print the {IRB version}[rdoc-ref:IRB@Version].
-- `-h`, `--help`: Print the {IRB help text}[rdoc-ref:IRB@Help].
-- `--`: Separate options from {arguments}[rdoc-ref:IRB@Command-Line+Arguments]
- on the command-line.
-
-### Index of \IRB.conf Entries
-
-These are the keys for hash \IRB.conf entries, with links to explanatory text;
-for each entry that is pre-defined, the initial value is given:
-
-- `:AP_NAME`: \IRB {application name}[rdoc-ref:IRB@Application+Name];
- initial value: `'irb'`.
-- `:AT_EXIT`: Array of hooks to call
- {at exit}[rdoc-ref:IRB@IRB];
- initial value: `[]`.
-- `:AUTO_INDENT`: Whether {automatic indentation}[rdoc-ref:IRB@Automatic+Indentation]
- is enabled; initial value: `true`.
-- `:BACK_TRACE_LIMIT`: Sets the {back trace limit}[rdoc-ref:IRB@Tracer];
- initial value: `16`.
-- `:COMMAND_ALIASES`: Defines input {command aliases}[rdoc-ref:IRB@Command+Aliases];
- initial value:
-
- {
- "$": :show_source,
- "@": :whereami,
- }
-
-- `:CONTEXT_MODE`: Sets the {context mode}[rdoc-ref:IRB@Context+Mode],
- the type of binding to be used when evaluating statements;
- initial value: `4`.
-- `:ECHO`: Whether to print ({echo}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- return values;
- initial value: `nil`, which would set `conf.echo` to `true`.
-- `:ECHO_ON_ASSIGNMENT`: Whether to print ({echo}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29])
- return values on assignment;
- initial value: `nil`, which would set `conf.echo_on_assignment` to `:truncate`.
-- `:EVAL_HISTORY`: How much {evaluation history}[rdoc-ref:IRB@Evaluation+History]
- is to be stored; initial value: `nil`.
-- `:EXTRA_DOC_DIRS`: \Array of
- {RI documentation directories}[rdoc-ref:IRB@RI+Documentation+Directories]
- to be parsed for the documentation dialog;
- initial value: `[]`.
-- `:IGNORE_EOF`: Whether to ignore {end-of-file}[rdoc-ref:IRB@End-of-File];
- initial value: `false`.
-- `:IGNORE_SIGINT`: Whether to ignore {SIGINT}[rdoc-ref:IRB@SIGINT];
- initial value: `true`.
-- `:INSPECT_MODE`: Whether to use method `inspect` for printing
- ({echoing}[rdoc-ref:IRB@Return-Value+Printing+-28Echoing-29]) return values;
- initial value: `true`.
-- `:IRB_LIB_PATH`: The path to the {IRB library directory}[rdoc-ref:IRB@IRB+Library+Directory]; initial value:
-
- - `"<i>RUBY_DIR</i>/lib/ruby/gems/<i>RUBY_VER_NUM</i>/gems/irb-<i>IRB_VER_NUM</i>/lib/irb"`,
-
- where:
-
- - <i>RUBY_DIR</i> is the Ruby installation dirpath.
- - <i>RUBY_VER_NUM</i> is the Ruby version number.
- - <i>IRB_VER_NUM</i> is the \IRB version number.
-
-- `:IRB_NAME`: {IRB name}[rdoc-ref:IRB@IRB+Name];
- initial value: `'irb'`.
-- `:IRB_RC`: {Configuration monitor}[rdoc-ref:IRB@Configuration+Monitor];
- initial value: `nil`.
-- `:LC_MESSAGES`: {Locale}[rdoc-ref:IRB@Locale];
- initial value: IRB::Locale object.
-- `:LOAD_MODULES`: deprecated.
-- `:MAIN_CONTEXT`: The {context}[rdoc-ref:IRB@Session+Context] for the main \IRB session;
- initial value: IRB::Context object.
-- `:MEASURE`: Whether to
- {measure performance}[rdoc-ref:IRB@Performance+Measurement];
- initial value: `false`.
-- `:MEASURE_CALLBACKS`: Callback methods for
- {performance measurement}[rdoc-ref:IRB@Performance+Measurement];
- initial value: `[]`.
-- `:MEASURE_PROC`: Procs for
- {performance measurement}[rdoc-ref:IRB@Performance+Measurement];
- initial value:
-
- {
- :TIME=>#<Proc:0x0000556e271c6598 /var/lib/gems/3.0.0/gems/irb-1.8.3/lib/irb/init.rb:106>,
- :STACKPROF=>#<Proc:0x0000556e271c6548 /var/lib/gems/3.0.0/gems/irb-1.8.3/lib/irb/init.rb:116>
- }
-
-- `:PROMPT`: \Hash of {defined prompts}[rdoc-ref:IRB@Prompt+and+Return+Formats];
- initial value:
-
- {
- :NULL=>{:PROMPT_I=>nil, :PROMPT_S=>nil, :PROMPT_C=>nil, :RETURN=>"%s\n"},
- :DEFAULT=>{:PROMPT_I=>"%N(%m):%03n> ", :PROMPT_S=>"%N(%m):%03n%l ", :PROMPT_C=>"%N(%m):%03n* ", :RETURN=>"=> %s\n"},
- :CLASSIC=>{:PROMPT_I=>"%N(%m):%03n:%i> ", :PROMPT_S=>"%N(%m):%03n:%i%l ", :PROMPT_C=>"%N(%m):%03n:%i* ", :RETURN=>"%s\n"},
- :SIMPLE=>{:PROMPT_I=>">> ", :PROMPT_S=>"%l> ", :PROMPT_C=>"?> ", :RETURN=>"=> %s\n"},
- :INF_RUBY=>{:PROMPT_I=>"%N(%m):%03n> ", :PROMPT_S=>nil, :PROMPT_C=>nil, :RETURN=>"%s\n", :AUTO_INDENT=>true},
- :XMP=>{:PROMPT_I=>nil, :PROMPT_S=>nil, :PROMPT_C=>nil, :RETURN=>" ==>%s\n"}
- }
-
-- `:PROMPT_MODE`: Name of {current prompt}[rdoc-ref:IRB@Prompt+and+Return+Formats];
- initial value: `:DEFAULT`.
-- `:RC`: Whether a {configuration file}[rdoc-ref:IRB@Configuration+File]
- was found and interpreted;
- initial value: `true` if a configuration file was found, `false` otherwise.
-- `:SAVE_HISTORY`: Number of commands to save in
- {input command history}[rdoc-ref:IRB@Input+Command+History];
- initial value: `1000`.
-- `:SINGLE_IRB`: Whether command-line option `--single-irb` was given;
- initial value: `true` if the option was given, `false` otherwise.
- See {Single-IRB Mode}[rdoc-ref:IRB@Single-IRB+Mode].
-- `:USE_AUTOCOMPLETE`: Whether to use
- {automatic completion}[rdoc-ref:IRB@Automatic+Completion];
- initial value: `true`.
-- `:USE_COLORIZE`: Whether to use
- {color highlighting}[rdoc-ref:IRB@Color+Highlighting];
- initial value: `true`.
-- `:USE_LOADER`: Whether to use the
- {IRB loader}[rdoc-ref:IRB@IRB+Loader] for `require` and `load`;
- initial value: `false`.
-- `:USE_TRACER`: Whether to use the
- {IRB tracer}[rdoc-ref:IRB@Tracer];
- initial value: `false`.
-- `:VERBOSE`: Whether to print {verbose output}[rdoc-ref:IRB@Verbosity];
- initial value: `nil`.
-- `:__MAIN__`: The main \IRB object;
- initial value: `main`.
diff --git a/doc/irb/irb.rd.ja b/doc/irb/irb.rd.ja
index c51e0bd60d..633c08cbd4 100644
--- a/doc/irb/irb.rd.ja
+++ b/doc/irb/irb.rd.ja
@@ -125,6 +125,7 @@ irb起動時ã«``~/.irbrc''を読ã¿è¾¼ã¿ã¾ã™. ã‚‚ã—存在ã—ãªã„å ´åˆã¯
IRB.conf[:PROMPT][:MY_PROMPT] = { # プロンプトモードã®åå‰
:PROMPT_I => nil, # 通常ã®ãƒ—ロンプト
+ :PROMPT_N => nil, # 継続行ã®ãƒ—ロンプト
:PROMPT_S => nil, # 文字列ãªã©ã®ç¶™ç¶šè¡Œã®ãƒ—ロンプト
:PROMPT_C => nil, # å¼ãŒç¶™ç¶šã—ã¦ã„る時ã®ãƒ—ロンプト
:RETURN => " ==>%s\n" # リターン時ã®ãƒ—ロンプト
@@ -139,7 +140,7 @@ OKã§ã™.
IRB.conf[:PROMPT_MODE] = :MY_PROMPT
-PROMPT_I, PROMPT_S, PROMPT_Cã¯, フォーマットを指定ã—ã¾ã™.
+PROMPT_I, PROMPT_N, PROMPT_S, PROMPT_Cã¯, フォーマットを指定ã—ã¾ã™.
%N èµ·å‹•ã—ã¦ã„るコマンドåãŒå‡ºåŠ›ã•れる.
%m mainオブジェクト(self)ãŒto_sã§å‡ºåŠ›ã•れる.
@@ -154,6 +155,7 @@ PROMPT_I, PROMPT_S, PROMPT_Cã¯, フォーマットを指定ã—ã¾ã™.
IRB.conf[:PROMPT][:DEFAULT] = {
:PROMPT_I => "%N(%m):%03n:%i> ",
+ :PROMPT_N => "%N(%m):%03n:%i> ",
:PROMPT_S => "%N(%m):%03n:%i%l ",
:PROMPT_C => "%N(%m):%03n:%i* ",
:RETURN => "=> %s\n"
diff --git a/doc/keywords.rdoc b/doc/keywords.rdoc
new file mode 100644
index 0000000000..cb1cff33f0
--- /dev/null
+++ b/doc/keywords.rdoc
@@ -0,0 +1,162 @@
+== Keywords
+
+The following keywords are used by Ruby.
+
+__ENCODING__::
+ The script encoding of the current file. See Encoding.
+
+__LINE__::
+ The line number of this keyword in the current file.
+
+__FILE__::
+ The path to the current file.
+
+BEGIN::
+ Runs before any other code in the current file. See {miscellaneous
+ syntax}[rdoc-ref:syntax/miscellaneous.rdoc]
+
+END::
+ Runs after any other code in the current file. See {miscellaneous
+ syntax}[rdoc-ref:syntax/miscellaneous.rdoc]
+
+alias::
+ Creates an alias between two methods (and other things). See {modules and
+ classes syntax}[rdoc-ref:syntax/modules_and_classes.rdoc]
+
+and::
+ Short-circuit Boolean and with lower precedence than <code>&&</code>
+
+begin::
+ Starts an exception handling block. See {exceptions
+ syntax}[rdoc-ref:syntax/exceptions.rdoc]
+
+break::
+ Leaves a block early. See {control expressions
+ syntax}[rdoc-ref:syntax/control_expressions.rdoc]
+
+case::
+ Starts a +case+ expression. See {control expressions
+ syntax}[rdoc-ref:syntax/control_expressions.rdoc]
+
+class::
+ Creates or opens a class. See {modules and classes
+ syntax}[rdoc-ref:syntax/modules_and_classes.rdoc]
+
+def::
+ Defines a method. See {methods syntax}[rdoc-ref:syntax/methods.rdoc]
+
+defined?::
+ Returns a string describing its argument. See {miscellaneous
+ syntax}[rdoc-ref:syntax/miscellaneous.rdoc]
+
+do::
+ Starts a block.
+
+else::
+ The unhandled condition in +case+, +if+ and +unless+ expressions. See
+ {control expressions}[rdoc-ref:syntax/control_expressions.rdoc]
+
+elsif::
+ An alternate condition for an +if+ expression. See {control
+ expressions}[rdoc-ref:syntax/control_expressions.rdoc]
+
+end::
+ The end of a syntax block. Used by classes, modules, methods, exception
+ handling and control expressions.
+
+ensure::
+ Starts a section of code that is always run when an exception is raised.
+ See {exception handling}[rdoc-ref:syntax/exceptions.rdoc]
+
+false::
+ Boolean false. See {literals}[rdoc-ref:syntax/literals.rdoc]
+
+for::
+ A loop that is similar to using the +each+ method. See {control
+ expressions}[rdoc-ref:syntax/control_expressions.rdoc]
+
+if::
+ Used for +if+ and modifier +if+ statements. See {control
+ expressions}[rdoc-ref:syntax/control_expressions.rdoc]
+
+in::
+ Used to separate the iterable object and iterator variable in a +for+ loop.
+ See {control expressions}[rdoc-ref:syntax/control_expressions.rdoc]
+ It also serves as a pattern in a +case+ expression.
+ See {pattern matching}[rdoc-ref:syntax/pattern_matching.rdoc]
+
+module::
+ Creates or opens a module. See {modules and classes
+ syntax}[rdoc-ref:syntax/modules_and_classes.rdoc]
+
+next::
+ Skips the rest of the block. See {control
+ expressions}[rdoc-ref:syntax/control_expressions.rdoc]
+
+nil::
+ A false value usually indicating "no value" or "unknown". See
+ {literals}[rdoc-ref:syntax/literals.rdoc]
+
+not::
+ Inverts the following boolean expression. Has a lower precedence than
+ <code>!</code>
+
+or::
+ Boolean or with lower precedence than <code>||</code>
+
+redo::
+ Restarts execution in the current block. See {control
+ expressions}[rdoc-ref:syntax/control_expressions.rdoc]
+
+rescue::
+ Starts an exception section of code in a +begin+ block. See {exception
+ handling}[rdoc-ref:syntax/exceptions.rdoc]
+
+retry::
+ Retries an exception block. See {exception
+ handling}[rdoc-ref:syntax/exceptions.rdoc]
+
+return::
+ Exits a method. See {methods}[rdoc-ref:syntax/methods.rdoc].
+ If met in top-level scope, immediately stops interpretation of
+ the current file.
+
+self::
+ The object the current method is attached to. See
+ {methods}[rdoc-ref:syntax/methods.rdoc]
+
+super::
+ Calls the current method in a superclass. See
+ {methods}[rdoc-ref:syntax/methods.rdoc]
+
+then::
+ Indicates the end of conditional blocks in control structures. See
+ {control expressions}[rdoc-ref:syntax/control_expressions.rdoc]
+
+true::
+ Boolean true. See {literals}[rdoc-ref:syntax/literals.rdoc]
+
+undef::
+ Prevents a class or module from responding to a method call.
+ See {modules and classes}[rdoc-ref:syntax/modules_and_classes.rdoc]
+
+unless::
+ Used for +unless+ and modifier +unless+ statements. See {control
+ expressions}[rdoc-ref:syntax/control_expressions.rdoc]
+
+until::
+ Creates a loop that executes until the condition is true. See
+ {control expressions}[rdoc-ref:syntax/control_expressions.rdoc]
+
+when::
+ A condition in a +case+ expression. See
+ {control expressions}[rdoc-ref:syntax/control_expressions.rdoc]
+
+while::
+ Creates a loop that executes while the condition is true. See
+ {control expressions}[rdoc-ref:syntax/control_expressions.rdoc]
+
+yield::
+ Starts execution of the block sent to the current method. See
+ {methods}[rdoc-ref:syntax/methods.rdoc]
+
diff --git a/doc/maintainers.md b/doc/maintainers.md
deleted file mode 100644
index dabbdc0cb6..0000000000
--- a/doc/maintainers.md
+++ /dev/null
@@ -1,504 +0,0 @@
-# Maintainers
-This page describes the current branch, module, library, and extension maintainers of Ruby.
-
-## Branch Maintainers
-
-A branch maintainer is responsible for backporting commits into stable branches
-and publishing Ruby patch releases.
-
-[The list of current branch maintainers is available in the wiki](https://github.com/ruby/ruby/wiki/Release-Engineering).
-
-## Module Maintainers
-A module maintainer is responsible for a certain part of Ruby.
-
-* The maintainer fixes bugs of the part. Particularly, they should fix
- security vulnerabilities as soon as possible.
-* They handle issues related the module on the Redmine or ML.
-* They may be discharged by the 3 months rule [[ruby-core:25764]](https://blade.ruby-lang.org/ruby-core/25764).
-* They have commit right to Ruby's repository to modify their part in the
- repository.
-* They have "developer" role on the Redmine to modify issues.
-* They have authority to decide the feature of their part. But they should
- always respect discussions on ruby-core/ruby-dev.
-
-A submaintainer of a module is like a maintainer. But the submaintainer does
-not have authority to change/add a feature on his/her part. They need
-consensus on ruby-core/ruby-dev before changing/adding. Some of submaintainers
-have commit right, others don't.
-
-### Language core features including security
-* Yukihiro Matsumoto (matz)
-
-### Evaluator
-* Koichi Sasada (ko1)
-
-### Core classes
-* Yukihiro Matsumoto (matz)
-
-## Standard Library Maintainers
-### Libraries
-#### lib/mkmf.rb
-* *unmaintained*
-
-#### lib/rubygems.rb, lib/rubygems/*
-* Eric Hodel (drbrain)
-* Hiroshi SHIBATA (hsbt)
-* https://github.com/rubygems/rubygems
-
-#### lib/unicode_normalize.rb, lib/unicode_normalize/*
-* Martin J. Dürst
-
-### Extensions
-#### ext/continuation
-* Koichi Sasada (ko1)
-
-#### ext/coverage
-* Yusuke Endoh (mame)
-
-#### ext/fiber
-* Koichi Sasada (ko1)
-
-#### ext/monitor
-* Koichi Sasada (ko1)
-
-#### ext/objspace
-* *unmaintained*
-
-#### ext/pty
-* *unmaintained*
-
-#### ext/ripper
-* *unmaintained*
-
-#### ext/socket
-* Tanaka Akira (akr)
-* API change needs matz's approval
-
-#### ext/win32
-* NAKAMURA Usaku (usa)
-
-## Default gems Maintainers
-### Libraries
-
-#### lib/benchmark.rb
-* *unmaintained*
-* https://github.com/ruby/benchmark
-* https://rubygems.org/gems/benchmark
-
-#### lib/bundler.rb, lib/bundler/*
-* Hiroshi SHIBATA (hsbt)
-* https://github.com/rubygems/rubygems
-* https://rubygems.org/gems/bundler
-
-#### lib/cgi.rb, lib/cgi/*
-* *unmaintained*
-* https://github.com/ruby/cgi
-* https://rubygems.org/gems/cgi
-
-#### lib/English.rb
-* *unmaintained*
-* https://github.com/ruby/English
-* https://rubygems.org/gems/English
-
-#### lib/delegate.rb
-* *unmaintained*
-* https://github.com/ruby/delegate
-* https://rubygems.org/gems/delegate
-
-#### lib/did_you_mean.rb
-* Yuki Nishijima (yuki24)
-* https://github.com/ruby/did_you_mean
-* https://rubygems.org/gems/did_you_mean
-
-#### ext/digest, ext/digest/*
-* Akinori MUSHA (knu)
-* https://github.com/ruby/digest
-* https://rubygems.org/gems/digest
-
-#### lib/erb.rb
-* Masatoshi SEKI (seki)
-* Takashi Kokubun (k0kubun)
-* https://github.com/ruby/erb
-* https://rubygems.org/gems/erb
-
-#### lib/error_highlight.rb, lib/error_highlight/*
-* Yusuke Endoh (mame)
-* https://github.com/ruby/error_highlight
-* https://rubygems.org/gems/error_highlight
-
-#### lib/fileutils.rb
-* *unmaintained*
-* https://github.com/ruby/fileutils
-* https://rubygems.org/gems/fileutils
-
-#### lib/find.rb
-* Kazuki Tsujimoto (ktsj)
-* https://github.com/ruby/find
-* https://rubygems.org/gems/find
-
-#### lib/forwardable.rb
-* Keiju ISHITSUKA (keiju)
-* https://github.com/ruby/forwardable
-* https://rubygems.org/gems/forwardable
-
-#### lib/ipaddr.rb
-* Akinori MUSHA (knu)
-* https://github.com/ruby/ipaddr
-* https://rubygems.org/gems/ipaddr
-
-#### lib/irb.rb, lib/irb/*
-* Stan Lo (st0012)
-* Tomoya Ishida (tompng)
-* Mari Imaizumi (ima1zumi)
-* Hitoshi Hasumi (hasumikin)
-* https://github.com/ruby/irb
-* https://rubygems.org/gems/irb
-
-#### lib/optparse.rb, lib/optparse/*
-* Nobuyuki Nakada (nobu)
-* https://github.com/ruby/optparse
-
-#### lib/logger.rb
-* Naotoshi Seo (sonots)
-* https://github.com/ruby/logger
-* https://rubygems.org/gems/logger
-
-#### lib/net/http.rb, lib/net/https.rb
-* NARUSE, Yui (naruse)
-* https://github.com/ruby/net-http
-* https://rubygems.org/gems/net-http
-
-#### lib/net/protocol.rb
-* *unmaintained*
-* https://github.com/ruby/net-protocol
-* https://rubygems.org/gems/net-protocol
-
-#### lib/open3.rb
-* *unmaintained*
-* https://github.com/ruby/open3
-* https://rubygems.org/gems/open3
-
-#### lib/open-uri.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/open-uri
-
-#### lib/ostruct.rb
-* Marc-André Lafortune (marcandre)
-* https://github.com/ruby/ostruct
-* https://rubygems.org/gems/ostruct
-
-#### lib/pp.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/pp
-* https://rubygems.org/gems/pp
-
-#### lib/prettyprint.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/prettyprint
-* https://rubygems.org/gems/prettyprint
-
-#### lib/prism.rb
-* Kevin Newton (kddnewton)
-* Jemma Issroff (jemmaissroff)
-* https://github.com/ruby/prism
-* https://rubygems.org/gems/prism
-
-#### lib/pstore.rb
-* *unmaintained*
-* https://github.com/ruby/pstore
-* https://rubygems.org/gems/pstore
-
-#### lib/readline.rb
-* aycabta
-* https://github.com/ruby/readline
-* https://rubygems.org/gems/readline
-
-#### lib/resolv.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/resolv
-* https://rubygems.org/gems/resolv
-
-#### lib/rdoc.rb, lib/rdoc/*
-* Eric Hodel (drbrain)
-* Hiroshi SHIBATA (hsbt)
-* https://github.com/ruby/rdoc
-* https://rubygems.org/gems/rdoc
-
-#### lib/reline.rb, lib/reline/*
-* Tomoya Ishida (tompng)
-* Mari Imaizumi (ima1zumi)
-* Stan Lo (st0012)
-* Hitoshi Hasumi (hasumikin)
-* https://github.com/ruby/reline
-* https://rubygems.org/gems/reline
-
-#### lib/securerandom.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/securerandom
-* https://rubygems.org/gems/securerandom
-
-#### lib/set.rb
-* Akinori MUSHA (knu)
-* https://github.com/ruby/set
-* https://rubygems.org/gems/set
-
-#### lib/shellwords.rb
-* Akinori MUSHA (knu)
-* https://github.com/ruby/shellwords
-* https://rubygems.org/gems/shellwords
-
-#### lib/singleton.rb
-* Yukihiro Matsumoto (matz)
-* https://github.com/ruby/singleton
-* https://rubygems.org/gems/singleton
-
-#### lib/tempfile.rb
-* *unmaintained*
-* https://github.com/ruby/tempfile
-* https://rubygems.org/gems/tempfile
-
-#### lib/time.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/time
-* https://rubygems.org/gems/time
-
-#### lib/timeout.rb
-* Yukihiro Matsumoto (matz)
-* https://github.com/ruby/timeout
-* https://rubygems.org/gems/timeout
-
-#### lib/thwait.rb
-* Keiju ISHITSUKA (keiju)
-* https://github.com/ruby/thwait
-* https://rubygems.org/gems/thwait
-
-#### lib/tmpdir.rb
-* *unmaintained*
-* https://github.com/ruby/tmpdir
-* https://rubygems.org/gems/tmpdir
-
-#### lib/tsort.rb
-* Tanaka Akira (akr)
-* https://github.com/ruby/tsort
-* https://rubygems.org/gems/tsort
-
-#### lib/un.rb
-* WATANABE Hirofumi (eban)
-* https://github.com/ruby/un
-* https://rubygems.org/gems/un
-
-#### lib/uri.rb, lib/uri/*
-* NARUSE, Yui (naruse)
-* https://github.com/ruby/uri
-* https://rubygems.org/gems/uri
-
-#### lib/yaml.rb, lib/yaml/*
-* Aaron Patterson (tenderlove)
-* Hiroshi SHIBATA (hsbt)
-* https://github.com/ruby/yaml
-* https://rubygems.org/gems/yaml
-
-#### lib/weakref.rb
-* *unmaintained*
-* https://github.com/ruby/weakref
-* https://rubygems.org/gems/weakref
-
-### Extensions
-
-#### ext/cgi
-* Nobuyoshi Nakada (nobu)
-* https://github.com/ruby/cgi
-* https://rubygems.org/gems/cgi
-
-#### ext/date
-* *unmaintained*
-* https://github.com/ruby/date
-* https://rubygems.org/gems/date
-
-#### ext/etc
-* *unmaintained*
-* https://github.com/ruby/etc
-* https://rubygems.org/gems/etc
-
-#### ext/fcntl
-* *unmaintained*
-* https://github.com/ruby/fcntl
-* https://rubygems.org/gems/fcntl
-
-#### ext/fiddle
-* Aaron Patterson (tenderlove)
-* https://github.com/ruby/fiddle
-* https://rubygems.org/gems/fiddle
-
-#### ext/io/console
-* Nobuyuki Nakada (nobu)
-* https://github.com/ruby/io-console
-* https://rubygems.org/gems/io-console
-
-#### ext/io/nonblock
-* Nobuyuki Nakada (nobu)
-* https://github.com/ruby/io-nonblock
-* https://rubygems.org/gems/io-nonblock
-
-#### ext/io/wait
-* Nobuyuki Nakada (nobu)
-* https://github.com/ruby/io-wait
-* https://rubygems.org/gems/io-wait
-
-#### ext/json
-* NARUSE, Yui (naruse)
-* Hiroshi SHIBATA (hsbt)
-* https://github.com/flori/json
-* https://rubygems.org/gems/json
-
-#### ext/openssl
-* Kazuki Yamaguchi (rhe)
-* https://github.com/ruby/openssl
-* https://rubygems.org/gems/openssl
-
-#### ext/pathname
-* Tanaka Akira (akr)
-* https://github.com/ruby/pathname
-* https://rubygems.org/gems/pathname
-
-#### ext/psych
-* Aaron Patterson (tenderlove)
-* Hiroshi SHIBATA (hsbt)
-* https://github.com/ruby/psych
-* https://rubygems.org/gems/psych
-
-#### ext/stringio
-* Nobuyuki Nakada (nobu)
-* https://github.com/ruby/stringio
-* https://rubygems.org/gems/stringio
-
-#### ext/strscan
-* Kouhei Sutou (kou)
-* https://github.com/ruby/strscan
-* https://rubygems.org/gems/strscan
-
-#### ext/win32ole
-* Masaki Suketa (suke)
-* https://github.com/ruby/win32ole
-* https://rubygems.org/gems/win32ole
-
-#### ext/zlib
-* NARUSE, Yui (naruse)
-* https://github.com/ruby/zlib
-* https://rubygems.org/gems/zlib
-
-## Bundled gems upstream repositories
-### minitest
-* https://github.com/minitest/minitest
-
-### power_assert
-* https://github.com/ruby/power_assert
-
-### rake
-* https://github.com/ruby/rake
-
-### test-unit
-* https://github.com/test-unit/test-unit
-
-### rexml
-* https://github.com/ruby/rexml
-
-### rss
-* https://github.com/ruby/rss
-
-### net-ftp
-* https://github.com/ruby/net-ftp
-
-### net-imap
-* https://github.com/ruby/net-imap
-
-### net-pop
-* https://github.com/ruby/net-pop
-
-### net-smtp
-* https://github.com/ruby/net-smtp
-
-### matrix
-* https://github.com/ruby/matrix
-
-### prime
-* https://github.com/ruby/prime
-
-### rbs
-* https://github.com/ruby/rbs
-
-### typeprof
-* https://github.com/ruby/typeprof
-
-### debug
-* https://github.com/ruby/debug
-
-### racc
-* https://github.com/ruby/racc
-
-#### mutex_m
-* https://github.com/ruby/mutex_m
-
-#### getoptlong
-* https://github.com/ruby/getoptlong
-
-#### base64
-* https://github.com/ruby/base64
-
-#### bigdecimal
-* https://github.com/ruby/bigdecimal
-
-#### observer
-* https://github.com/ruby/observer
-
-#### abbrev
-* https://github.com/ruby/abbrev
-
-#### resolv-replace
-* https://github.com/ruby/resolv-replace
-
-#### rinda
-* https://github.com/ruby/rinda
-
-#### drb
-* https://github.com/ruby/drb
-
-#### nkf
-* https://github.com/ruby/nkf
-
-#### syslog
-* https://github.com/ruby/syslog
-
-#### csv
-* https://github.com/ruby/csv
-
-## Platform Maintainers
-### mswin64 (Microsoft Windows)
-* NAKAMURA Usaku (usa)
-
-### mingw32 (Minimalist GNU for Windows)
-* Nobuyoshi Nakada (nobu)
-
-### AIX
-* Yutaka Kanemoto (kanemoto)
-
-### FreeBSD
-* Akinori MUSHA (knu)
-
-### Solaris
-* Naohisa Goto (ngoto)
-
-### RHEL, CentOS
-* KOSAKI Motohiro (kosaki)
-
-### macOS
-* Kenta Murata (mrkn)
-
-### OpenBSD
-* Jeremy Evans (jeremyevans0)
-
-### cygwin, ...
-* none. (Maintainer WANTED)
-
-### WebAssembly/WASI
-* Yuta Saito (katei)
diff --git a/doc/maintainers.rdoc b/doc/maintainers.rdoc
new file mode 100644
index 0000000000..7e0c35194f
--- /dev/null
+++ b/doc/maintainers.rdoc
@@ -0,0 +1,424 @@
+= Maintainers
+
+This page describes the current module, library, and extension maintainers of Ruby.
+
+== Module Maintainers
+
+A module maintainer is responsible for a certain part of Ruby.
+
+* The maintainer fixes bugs of the part. Particularly, they should fix security vulnerabilities as soon as possible.
+* They handle issues related the module on the Redmine or ML.
+* They may be discharged by the 3 months rule [ruby-core:25764].
+* They have commit right to Ruby's repository to modify their part in the repository.
+* They have "developer" role on the Redmine to modify issues.
+* They have authority to decide the feature of their part. But they should always respect discussions on ruby-core/ruby-dev.
+
+A submaintainer of a module is like a maintainer. But the submaintainer does
+not have authority to change/add a feature on his/her part. They need consensus
+on ruby-core/ruby-dev before changing/adding. Some of submaintainers have
+commit right, others don't.
+
+=== Language core features including security
+
+Yukihiro Matsumoto (matz)
+
+=== Evaluator
+
+Koichi Sasada (ko1)
+
+=== Core classes
+
+Yukihiro Matsumoto (matz)
+
+== Standard Library Maintainers
+
+=== Libraries
+
+[lib/mkmf.rb]
+ _unmaintained_
+[lib/rubygems.rb, lib/rubygems/*]
+ Eric Hodel (drbrain), Hiroshi SHIBATA (hsbt)
+ https://github.com/rubygems/rubygems
+[lib/unicode_normalize.rb, lib/unicode_normalize/*]
+ Martin J. Dürst
+
+=== Extensions
+
+[ext/continuation]
+ Koichi Sasada (ko1)
+[ext/coverage]
+ Yusuke Endoh (mame)
+[ext/fiber]
+ Koichi Sasada (ko1)
+[ext/monitor]
+ Koichi Sasada (ko1)
+[ext/objspace]
+ _unmaintained_
+[ext/pty]
+ _unmaintained_
+[ext/ripper]
+ _unmaintained_
+[ext/socket]
+ * Tanaka Akira (akr)
+ * API change needs matz's approval
+[ext/win32]
+ NAKAMURA Usaku (usa)
+
+== Default gems Maintainers
+
+=== Libraries
+
+[lib/abbrev.rb]
+ Akinori MUSHA (knu)
+ https://github.com/ruby/abbrev
+ https://rubygems.org/gems/abbrev
+[lib/base64.rb]
+ Yusuke Endoh (mame)
+ https://github.com/ruby/base64
+ https://rubygems.org/gems/base64
+[lib/benchmark.rb]
+ _unmaintained_
+ https://github.com/ruby/benchmark
+ https://rubygems.org/gems/benchmark
+[lib/bundler.rb, lib/bundler/*]
+ Hiroshi SHIBATA (hsbt)
+ https://github.com/rubygems/rubygems
+ https://rubygems.org/gems/bundler
+[lib/cgi.rb, lib/cgi/*]
+ _unmaintained_
+ https://github.com/ruby/cgi
+ https://rubygems.org/gems/cgi
+[lib/csv.rb]
+ Kenta Murata (mrkn), Kouhei Sutou (kou)
+ https://github.com/ruby/csv
+ https://rubygems.org/gems/csv
+[lib/English.rb]
+ _unmaintained_
+ https://github.com/ruby/English
+ https://rubygems.org/gems/English
+[lib/debug.rb]
+ _unmaintained_
+ https://github.com/ruby/debug
+[lib/delegate.rb]
+ _unmaintained_
+ https://github.com/ruby/delegate
+ https://rubygems.org/gems/delegate
+[lib/did_you_mean.rb]
+ Yuki Nishijima (yuki24)
+ https://github.com/ruby/did_you_mean
+ https://rubygems.org/gems/did_you_mean
+[ext/digest, ext/digest/*]
+ Akinori MUSHA (knu)
+ https://github.com/ruby/digest
+ https://rubygems.org/gems/digest
+[lib/drb.rb, lib/drb/*]
+ Masatoshi SEKI (seki)
+ https://github.com/ruby/drb
+ https://rubygems.org/gems/drb
+[lib/erb.rb]
+ Masatoshi SEKI (seki), Takashi Kokubun (k0kubun)
+ https://github.com/ruby/erb
+ https://rubygems.org/gems/erb
+[lib/error_highlight.rb, lib/error_highlight/*]
+ Yusuke Endoh (mame)
+ https://github.com/ruby/error_highlight
+ https://rubygems.org/gems/error_highlight
+[lib/fileutils.rb]
+ _unmaintained_
+ https://github.com/ruby/fileutils
+ https://rubygems.org/gems/fileutils
+[lib/find.rb]
+ Kazuki Tsujimoto (ktsj)
+ https://github.com/ruby/find
+ https://rubygems.org/gems/find
+[lib/forwardable.rb]
+ Keiju ISHITSUKA (keiju)
+ https://github.com/ruby/forwardable
+ https://rubygems.org/gems/forwardable
+[lib/getoptlong.rb]
+ _unmaintained_
+ https://github.com/ruby/getoptlong
+ https://rubygems.org/gems/getoptlong
+[lib/ipaddr.rb]
+ Akinori MUSHA (knu)
+ https://github.com/ruby/ipaddr
+ https://rubygems.org/gems/ipaddr
+[lib/irb.rb, lib/irb/*]
+ aycabta
+ https://github.com/ruby/irb
+ https://rubygems.org/gems/irb
+[lib/optparse.rb, lib/optparse/*]
+ Nobuyuki Nakada (nobu)
+ https://github.com/ruby/optparse
+[lib/logger.rb]
+ Naotoshi Seo (sonots)
+ https://github.com/ruby/logger
+ https://rubygems.org/gems/logger
+[lib/mutex_m.rb]
+ Keiju ISHITSUKA (keiju)
+ https://github.com/ruby/mutex_m
+ https://rubygems.org/gems/mutex_m
+[lib/net/http.rb, lib/net/https.rb]
+ NARUSE, Yui (naruse)
+ https://github.com/ruby/net-http
+ https://rubygems.org/gems/net-http
+[lib/net/protocol.rb]
+ _unmaintained_
+ https://github.com/ruby/net-protocol
+ https://rubygems.org/gems/net-protocol
+[lib/observer.rb]
+ _unmaintained_
+ https://github.com/ruby/observer
+ https://rubygems.org/gems/observer
+[lib/open3.rb]
+ _unmaintained_
+ https://github.com/ruby/open3
+ https://rubygems.org/gems/open3
+[lib/open-uri.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/open-uri
+[lib/ostruct.rb]
+ Marc-André Lafortune (marcandre)
+ https://github.com/ruby/ostruct
+ https://rubygems.org/gems/ostruct
+[lib/pp.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/pp
+ https://rubygems.org/gems/pp
+[lib/prettyprint.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/prettyprint
+ https://rubygems.org/gems/prettyprint
+[lib/pstore.rb]
+ _unmaintained_
+ https://github.com/ruby/pstore
+ https://rubygems.org/gems/pstore
+[lib/racc.rb, lib/racc/*]
+ Aaron Patterson (tenderlove), Hiroshi SHIBATA (hsbt)
+ https://github.com/ruby/racc
+ https://rubygems.org/gems/racc
+[lib/readline.rb]
+ aycabta
+ https://github.com/ruby/readline
+ https://rubygems.org/gems/readline
+[lib/resolv.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/resolv
+ https://rubygems.org/gems/resolv
+[lib/resolv-replace.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/resolv-replace
+ https://rubygems.org/gems/resolv-replace
+[lib/rdoc.rb, lib/rdoc/*]
+ Eric Hodel (drbrain), Hiroshi SHIBATA (hsbt)
+ https://github.com/ruby/rdoc
+ https://rubygems.org/gems/rdoc
+[lib/readline.rb]
+ aycabta
+ https://github.com/ruby/readline
+ https://rubygems.org/gems/readline
+[lib/reline.rb, lib/reline/*]
+ aycabta
+ https://github.com/ruby/reline
+ https://rubygems.org/gems/reline
+[lib/rinda/*]
+ Masatoshi SEKI (seki)
+ https://github.com/ruby/rinda
+ https://rubygems.org/gems/rinda
+[lib/securerandom.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/securerandom
+ https://rubygems.org/gems/securerandom
+[lib/set.rb]
+ Akinori MUSHA (knu)
+ https://github.com/ruby/set
+ https://rubygems.org/gems/set
+[lib/shellwords.rb]
+ Akinori MUSHA (knu)
+ https://github.com/ruby/shellwords
+ https://rubygems.org/gems/shellwords
+[lib/singleton.rb]
+ Yukihiro Matsumoto (matz)
+ https://github.com/ruby/singleton
+ https://rubygems.org/gems/singleton
+[lib/tempfile.rb]
+ _unmaintained_
+ https://github.com/ruby/tempfile
+ https://rubygems.org/gems/tempfile
+[lib/time.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/time
+ https://rubygems.org/gems/time
+[lib/timeout.rb]
+ Yukihiro Matsumoto (matz)
+ https://github.com/ruby/timeout
+ https://rubygems.org/gems/timeout
+[lib/thwait.rb]
+ Keiju ISHITSUKA (keiju)
+ https://github.com/ruby/thwait
+ https://rubygems.org/gems/thwait
+[lib/tmpdir.rb]
+ _unmaintained_
+ https://github.com/ruby/tmpdir
+ https://rubygems.org/gems/tmpdir
+[lib/tsort.rb]
+ Tanaka Akira (akr)
+ https://github.com/ruby/tsort
+ https://rubygems.org/gems/tsort
+[lib/un.rb]
+ WATANABE Hirofumi (eban)
+ https://github.com/ruby/un
+ https://rubygems.org/gems/un
+[lib/uri.rb, lib/uri/*]
+ YAMADA, Akira (akira)
+ https://github.com/ruby/uri
+ https://rubygems.org/gems/uri
+[lib/yaml.rb, lib/yaml/*]
+ Aaron Patterson (tenderlove), Hiroshi SHIBATA (hsbt)
+ https://github.com/ruby/yaml
+ https://rubygems.org/gems/yaml
+[lib/weakref.rb]
+ _unmaintained_
+ https://github.com/ruby/weakref
+ https://rubygems.org/gems/weakref
+
+=== Extensions
+
+[ext/bigdecimal]
+ Kenta Murata (mrkn)
+ https://github.com/ruby/bigdecimal
+ https://rubygems.org/gems/bigdecimal
+[ext/cgi]
+ Nobuyoshi Nakada (nobu)
+ https://github.com/ruby/cgi
+ https://rubygems.org/gems/cgi
+[ext/date]
+ _unmaintained_
+ https://github.com/ruby/date
+ https://rubygems.org/gems/date
+[ext/etc]
+ Ruby core team
+ https://github.com/ruby/etc
+ https://rubygems.org/gems/etc
+[ext/fcntl]
+ Ruby core team
+ https://github.com/ruby/fcntl
+ https://rubygems.org/gems/fcntl
+[ext/fiddle]
+ Aaron Patterson (tenderlove)
+ https://github.com/ruby/fiddle
+ https://rubygems.org/gems/fiddle
+[ext/io/console]
+ Nobuyuki Nakada (nobu)
+ https://github.com/ruby/io-console
+ https://rubygems.org/gems/io-console
+[ext/io/nonblock]
+ Nobuyuki Nakada (nobu)
+ https://github.com/ruby/io-nonblock
+ https://rubygems.org/gems/io-nonblock
+[ext/io/wait]
+ Nobuyuki Nakada (nobu)
+ https://github.com/ruby/io-wait
+ https://rubygems.org/gems/io-wait
+[ext/json]
+ NARUSE, Yui (naruse), Hiroshi SHIBATA (hsbt)
+ https://github.com/flori/json
+ https://rubygems.org/gems/json
+[ext/nkf]
+ NARUSE, Yui (naruse)
+ https://github.com/ruby/nkf
+ https://rubygems.org/gems/nkf
+[ext/openssl]
+ Kazuki Yamaguchi (rhe)
+ https://github.com/ruby/openssl
+ https://rubygems.org/gems/openssl
+[ext/pathname]
+ Tanaka Akira (akr)
+ https://github.com/ruby/pathname
+ https://rubygems.org/gems/pathname
+[ext/psych]
+ Aaron Patterson (tenderlove), Hiroshi SHIBATA (hsbt)
+ https://github.com/ruby/psych
+ https://rubygems.org/gems/psych
+[ext/racc]
+ Aaron Patterson (tenderlove), Hiroshi SHIBATA (hsbt)
+ https://github.com/ruby/racc
+ https://rubygems.org/gems/racc
+[ext/readline]
+ TAKAO Kouji (kouji)
+ https://github.com/ruby/readline-ext
+ https://rubygems.org/gems/readline-ext
+[ext/stringio]
+ Nobuyuki Nakada (nobu)
+ https://github.com/ruby/stringio
+ https://rubygems.org/gems/stringio
+[ext/strscan]
+ Kouhei Sutou (kou)
+ https://github.com/ruby/strscan
+ https://rubygems.org/gems/strscan
+[ext/syslog]
+ Akinori MUSHA (knu)
+ https://github.com/ruby/syslog
+ https://rubygems.org/gems/syslog
+[ext/win32ole]
+ Masaki Suketa (suke)
+ https://github.com/ruby/win32ole
+ https://rubygems.org/gems/win32ole
+[ext/zlib]
+ NARUSE, Yui (naruse)
+ https://github.com/ruby/zlib
+ https://rubygems.org/gems/zlib
+
+== Bundled gems upstream repositories
+
+[minitest]
+ https://github.com/seattlerb/minitest
+[power_assert]
+ https://github.com/ruby/power_assert
+[rake]
+ https://github.com/ruby/rake
+[test-unit]
+ https://github.com/test-unit/test-unit
+[rexml]
+ https://github.com/ruby/rexml
+[rss]
+ https://github.com/ruby/rss
+[net-ftp]
+ https://github.com/ruby/net-ftp
+[net-imap]
+ https://github.com/ruby/net-imap
+[net-pop]
+ https://github.com/ruby/net-pop
+[net-smtp]
+ https://github.com/ruby/net-smtp
+[matrix]
+ https://github.com/ruby/matrix
+[prime]
+ https://github.com/ruby/prime
+[rbs]
+ https://github.com/ruby/rbs
+[typeprof]
+ https://github.com/ruby/typeprof
+
+=== Platform Maintainers
+
+[mswin64 (Microsoft Windows)]
+ NAKAMURA Usaku (usa)
+[mingw32 (Minimalist GNU for Windows)]
+ Nobuyoshi Nakada (nobu)
+[AIX]
+ Yutaka Kanemoto (kanemoto)
+[FreeBSD]
+ Akinori MUSHA (knu)
+[Solaris]
+ Naohisa Goto (ngoto)
+[RHEL, CentOS]
+ KOSAKI Motohiro (kosaki)
+[macOS]
+ Kenta Murata (mrkn)
+[OpenBSD]
+ Jeremy Evans (jeremyevans0)
+[cygwin, ...]
+ none. (Maintainer WANTED)
+[WebAssembly/WASI]
+ Yuta Saito (katei)
diff --git a/doc/matchdata/bytebegin.rdoc b/doc/matchdata/bytebegin.rdoc
deleted file mode 100644
index 5b40a7ef73..0000000000
--- a/doc/matchdata/bytebegin.rdoc
+++ /dev/null
@@ -1,30 +0,0 @@
-Returns the offset (in bytes) of the beginning of the specified match.
-
-When non-negative integer argument +n+ is given,
-returns the offset of the beginning of the <tt>n</tt>th match:
-
- m = /(.)(.)(\d+)(\d)/.match("THX1138.")
- # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
- m[0] # => "HX1138"
- m.bytebegin(0) # => 1
- m[3] # => "113"
- m.bytebegin(3) # => 3
-
- m = /(Ñ‚)(е)(Ñ)/.match('теÑÑ‚')
- # => #<MatchData "теÑ" 1:"Ñ‚" 2:"е" 3:"Ñ">
- m[0] # => "теÑ"
- m.bytebegin(0) # => 0
- m[3] # => "Ñ"
- m.bytebegin(3) # => 4
-
-When string or symbol argument +name+ is given,
-returns the offset of the beginning for the named match:
-
- m = /(?<foo>.)(.)(?<bar>.)/.match("hoge")
- # => #<MatchData "hog" foo:"h" bar:"g">
- m[:foo] # => "h"
- m.bytebegin('foo') # => 0
- m[:bar] # => "g"
- m.bytebegin(:bar) # => 2
-
-Related: MatchData#byteend, MatchData#byteoffset.
diff --git a/doc/matchdata/byteend.rdoc b/doc/matchdata/byteend.rdoc
deleted file mode 100644
index eb57664022..0000000000
--- a/doc/matchdata/byteend.rdoc
+++ /dev/null
@@ -1,30 +0,0 @@
-Returns the offset (in bytes) of the end of the specified match.
-
-When non-negative integer argument +n+ is given,
-returns the offset of the end of the <tt>n</tt>th match:
-
- m = /(.)(.)(\d+)(\d)/.match("THX1138.")
- # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
- m[0] # => "HX1138"
- m.byteend(0) # => 7
- m[3] # => "113"
- m.byteend(3) # => 6
-
- m = /(Ñ‚)(е)(Ñ)/.match('теÑÑ‚')
- # => #<MatchData "теÑ" 1:"Ñ‚" 2:"е" 3:"Ñ">
- m[0] # => "теÑ"
- m.byteend(0) # => 6
- m[3] # => "Ñ"
- m.byteend(3) # => 6
-
-When string or symbol argument +name+ is given,
-returns the offset of the end for the named match:
-
- m = /(?<foo>.)(.)(?<bar>.)/.match("hoge")
- # => #<MatchData "hog" foo:"h" bar:"g">
- m[:foo] # => "h"
- m.byteend('foo') # => 1
- m[:bar] # => "g"
- m.byteend(:bar) # => 3
-
-Related: MatchData#bytebegin, MatchData#byteoffset.
diff --git a/doc/mjit/mjit.md b/doc/mjit/mjit.md
new file mode 100644
index 0000000000..6f19ab3ea7
--- /dev/null
+++ b/doc/mjit/mjit.md
@@ -0,0 +1,39 @@
+# MJIT
+
+This document has some tips that might be useful when you work on MJIT.
+
+## Supported platforms
+
+The following platforms are either tested on CI or assumed to work.
+
+* OS: Linux, macOS
+* Arch: x86\_64, aarch64, arm64, i686, i386
+
+### Not supported
+
+The MJIT support for the following platforms is no longer maintained.
+
+* OS: Windows (mswin, MinGW), Solaris
+* Arch: SPARC, s390x
+
+## Developing MJIT
+
+### Bindgen
+
+If you see an "MJIT bindgen" GitHub Actions failure, please commit the `git diff` shown on the failed job.
+
+For doing the same thing locally, run `make mjit-bindgen` after installing libclang.
+macOS seems to have libclang by default. On Ubuntu, you can install it with `apt install libclang1`.
+
+### Always run make install
+
+Always run `make install` before running MJIT. It could easily cause a SEGV if you don't.
+MJIT looks for the installed header for security reasons.
+
+### --mjit-debug vs --mjit-debug=-ggdb3
+
+`--mjit-debug=[flags]` allows you to specify arbitrary flags while keeping other compiler flags like `-O3`,
+which is useful for profiling benchmarks.
+
+`--mjit-debug` alone, on the other hand, disables `-O3` and adds debug flags.
+If you're debugging MJIT, what you need to use is not `--mjit-debug=-ggdb3` but `--mjit-debug`.
diff --git a/doc/optparse/argument_converters.rdoc b/doc/optparse/argument_converters.rdoc
index 4b4b30e8de..ac659da8c5 100644
--- a/doc/optparse/argument_converters.rdoc
+++ b/doc/optparse/argument_converters.rdoc
@@ -1,7 +1,7 @@
== Argument Converters
An option can specify that its argument is to be converted
-from the default +String+ to an instance of another class.
+from the default \String to an instance of another class.
=== Contents
@@ -27,13 +27,13 @@ from the default +String+ to an instance of another class.
=== Built-In Argument Converters
-+OptionParser+ has a number of built-in argument converters,
+\OptionParser has a number of built-in argument converters,
which are demonstrated below.
-==== +Date+
+==== \Date
File +date.rb+
-defines an option whose argument is to be converted to a +Date+ object.
+defines an option whose argument is to be converted to a \Date object.
The argument is converted by method Date#parse.
:include: ruby/date.rb
@@ -47,10 +47,10 @@ Executions:
$ ruby date.rb --date "3rd Feb 2001"
[#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>, Date]
-==== +DateTime+
+==== \DateTime
File +datetime.rb+
-defines an option whose argument is to be converted to a +DateTime+ object.
+defines an option whose argument is to be converted to a \DateTime object.
The argument is converted by method DateTime#parse.
:include: ruby/datetime.rb
@@ -64,10 +64,10 @@ Executions:
$ ruby datetime.rb --datetime "3rd Feb 2001 04:05:06 PM"
[#<DateTime: 2001-02-03T16:05:06+00:00 ((2451944j,57906s,0n),+0s,2299161j)>, DateTime]
-==== +Time+
+==== \Time
File +time.rb+
-defines an option whose argument is to be converted to a +Time+ object.
+defines an option whose argument is to be converted to a \Time object.
The argument is converted by method Time#httpdate or Time#parse.
:include: ruby/time.rb
@@ -79,10 +79,10 @@ Executions:
$ ruby time.rb --time 2010-10-31
[2010-10-31 00:00:00 -0500, Time]
-==== +URI+
+==== \URI
File +uri.rb+
-defines an option whose argument is to be converted to a +URI+ object.
+defines an option whose argument is to be converted to a \URI object.
The argument is converted by method URI#parse.
:include: ruby/uri.rb
@@ -96,10 +96,10 @@ Executions:
$ ruby uri.rb --uri file://~/var
[#<URI::File file://~/var>, URI::File]
-==== +Shellwords+
+==== \Shellwords
File +shellwords.rb+
-defines an option whose argument is to be converted to an +Array+ object by method
+defines an option whose argument is to be converted to an \Array object by method
Shellwords#shellwords.
:include: ruby/shellwords.rb
@@ -111,10 +111,10 @@ Executions:
$ ruby shellwords.rb --shellwords "here are 'two words'"
[["here", "are", "two words"], Array]
-==== +Integer+
+==== \Integer
File +integer.rb+
-defines an option whose argument is to be converted to an +Integer+ object.
+defines an option whose argument is to be converted to an \Integer object.
The argument is converted by method Kernel#Integer.
:include: ruby/integer.rb
@@ -132,10 +132,10 @@ Executions:
$ ruby integer.rb --integer 0b100
[4, Integer]
-==== +Float+
+==== \Float
File +float.rb+
-defines an option whose argument is to be converted to a +Float+ object.
+defines an option whose argument is to be converted to a \Float object.
The argument is converted by method Kernel#Float.
:include: ruby/float.rb
@@ -151,11 +151,11 @@ Executions:
$ ruby float.rb --float 1.234E-2
[0.01234, Float]
-==== +Numeric+
+==== \Numeric
File +numeric.rb+
defines an option whose argument is to be converted to an instance
-of +Rational+, +Float+, or +Integer+.
+of \Rational, \Float, or \Integer.
The argument is converted by method Kernel#Rational,
Kernel#Float, or Kernel#Integer.
@@ -170,10 +170,10 @@ Executions:
$ ruby numeric.rb --numeric 3
[3, Integer]
-==== +DecimalInteger+
+==== \DecimalInteger
File +decimal_integer.rb+
-defines an option whose argument is to be converted to an +Integer+ object.
+defines an option whose argument is to be converted to an \Integer object.
The argument is converted by method Kernel#Integer.
:include: ruby/decimal_integer.rb
@@ -192,10 +192,10 @@ Executions:
$ ruby decimal_integer.rb --decimal_integer -0100
[-100, Integer]
-==== +OctalInteger+
+==== \OctalInteger
File +octal_integer.rb+
-defines an option whose argument is to be converted to an +Integer+ object.
+defines an option whose argument is to be converted to an \Integer object.
The argument is converted by method Kernel#Integer.
:include: ruby/octal_integer.rb
@@ -212,10 +212,10 @@ Executions:
$ ruby octal_integer.rb --octal_integer 0100
[64, Integer]
-==== +DecimalNumeric+
+==== \DecimalNumeric
File +decimal_numeric.rb+
-defines an option whose argument is to be converted to an +Integer+ object.
+defines an option whose argument is to be converted to an \Integer object.
The argument is converted by method Kernel#Integer
:include: ruby/decimal_numeric.rb
@@ -232,7 +232,7 @@ Executions:
$ ruby decimal_numeric.rb --decimal_numeric 0100
[64, Integer]
-==== +TrueClass+
+==== \TrueClass
File +true_class.rb+
defines an option whose argument is to be converted to +true+ or +false+.
@@ -259,7 +259,7 @@ Executions:
$ ruby true_class.rb --true_class nil
[false, FalseClass]
-==== +FalseClass+
+==== \FalseClass
File +false_class.rb+
defines an option whose argument is to be converted to +true+ or +false+.
@@ -286,10 +286,10 @@ Executions:
$ ruby false_class.rb --false_class +
[true, TrueClass]
-==== +Object+
+==== \Object
File +object.rb+
-defines an option whose argument is not to be converted from +String+.
+defines an option whose argument is not to be converted from \String.
:include: ruby/object.rb
@@ -300,10 +300,10 @@ Executions:
$ ruby object.rb --object nil
["nil", String]
-==== +String+
+==== \String
File +string.rb+
-defines an option whose argument is not to be converted from +String+.
+defines an option whose argument is not to be converted from \String.
:include: ruby/string.rb
@@ -314,10 +314,10 @@ Executions:
$ ruby string.rb --string nil
["nil", String]
-==== +Array+
+==== \Array
File +array.rb+
-defines an option whose argument is to be converted from +String+
+defines an option whose argument is to be converted from \String
to an array of strings, based on comma-separated substrings.
:include: ruby/array.rb
@@ -331,10 +331,10 @@ Executions:
$ ruby array.rb --array "foo, bar, baz"
[["foo", " bar", " baz"], Array]
-==== +Regexp+
+==== \Regexp
File +regexp.rb+
-defines an option whose argument is to be converted to a +Regexp+ object.
+defines an option whose argument is to be converted to a \Regexp object.
:include: ruby/regexp.rb
@@ -352,7 +352,7 @@ To create a custom converter, call OptionParser#accept with:
- A block that accepts the argument and returns the converted value.
This custom converter accepts any argument and converts it,
-if possible, to a +Complex+ object.
+if possible, to a \Complex object.
:include: ruby/custom_converter.rb
diff --git a/doc/optparse/option_params.rdoc b/doc/optparse/option_params.rdoc
index 35db8b5a55..ace2c4283f 100644
--- a/doc/optparse/option_params.rdoc
+++ b/doc/optparse/option_params.rdoc
@@ -1,6 +1,6 @@
== Parameters for New Options
-Option-creating methods in +OptionParser+
+Option-creating methods in \OptionParser
accept arguments that determine the behavior of a new option:
- OptionParser#on
@@ -31,7 +31,7 @@ Contents:
- {Long Names with Optional Arguments}[#label-Long+Names+with+Optional+Arguments]
- {Long Names with Negation}[#label-Long+Names+with+Negation]
- {Mixed Names}[#label-Mixed+Names]
-- {Argument Strings}[#label-Argument+Strings]
+- {Argument Styles}[#label-Argument+Styles]
- {Argument Values}[#label-Argument+Values]
- {Explicit Argument Values}[#label-Explicit+Argument+Values]
- {Explicit Values in Array}[#label-Explicit+Values+in+Array]
@@ -405,7 +405,7 @@ Executions:
=== Argument Converters
An option can specify that its argument is to be converted
-from the default +String+ to an instance of another class.
+from the default \String to an instance of another class.
There are a number of built-in converters.
You can also define custom converters.
diff --git a/doc/optparse/ruby/argument_abbreviation.rb b/doc/optparse/ruby/argument_abbreviation.rb
deleted file mode 100644
index 49007ebe69..0000000000
--- a/doc/optparse/ruby/argument_abbreviation.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require 'optparse'
-parser = OptionParser.new
-parser.on('-x', '--xxx=VALUE', %w[ABC def], 'Argument abbreviations') do |value|
- p ['--xxx', value]
-end
-parser.on('-y', '--yyy=VALUE', {"abc"=>"XYZ", def: "FOO"}, 'Argument abbreviations') do |value|
- p ['--yyy', value]
-end
-parser.parse!
diff --git a/doc/optparse/tutorial.rdoc b/doc/optparse/tutorial.rdoc
index 6f56bbf92d..b95089826d 100644
--- a/doc/optparse/tutorial.rdoc
+++ b/doc/optparse/tutorial.rdoc
@@ -1,10 +1,10 @@
== Tutorial
-=== Why +OptionParser+?
+=== Why \OptionParser?
When a Ruby program executes, it captures its command-line arguments
and options into variable ARGV.
-This simple program just prints its +ARGV+:
+This simple program just prints its \ARGV:
:include: ruby/argv.rb
@@ -18,7 +18,7 @@ the command-line options.
OptionParser offers methods for parsing and handling those options.
-With +OptionParser+, you can define options so that for each option:
+With \OptionParser, you can define options so that for each option:
- The code that defines the option and code that handles that option
are in the same place.
@@ -55,7 +55,7 @@ The class also has method #help, which displays automatically-generated help tex
- {Argument Converters}[#label-Argument+Converters]
- {Help}[#label-Help]
- {Top List and Base List}[#label-Top+List+and+Base+List]
-- {Methods for Defining Options}[#label-Methods+for+Defining+Options]
+- {Defining Options}[#label-Defining+Options]
- {Parsing}[#label-Parsing]
- {Method parse!}[#label-Method+parse-21]
- {Method parse}[#label-Method+parse]
@@ -66,10 +66,10 @@ The class also has method #help, which displays automatically-generated help tex
=== To Begin With
-To use +OptionParser+:
+To use \OptionParser:
-1. Require the +OptionParser+ code.
-2. Create an +OptionParser+ object.
+1. Require the \OptionParser code.
+2. Create an \OptionParser object.
3. Define one or more options.
4. Parse the command line.
@@ -92,9 +92,9 @@ the block defined for the option is called with the argument value.
An invalid option raises an exception.
Method #parse!, which is used most often in this tutorial,
-removes from +ARGV+ the options and arguments it finds,
+removes from \ARGV the options and arguments it finds,
leaving other non-option arguments for the program to handle on its own.
-The method returns the possibly-reduced +ARGV+ array.
+The method returns the possibly-reduced \ARGV array.
Executions:
@@ -115,7 +115,7 @@ Executions:
=== Defining Options
-A common way to define an option in +OptionParser+
+A common way to define an option in \OptionParser
is with instance method OptionParser#on.
The method may be called with any number of arguments
@@ -351,29 +351,6 @@ Executions:
Omitting an optional argument does not raise an error.
-==== Argument Abbreviations
-
-Specify an argument list as an Array or a Hash.
-
- :include: ruby/argument_abbreviation.rb
-
-When an argument is abbreviated, the expanded argument yielded.
-
-Executions:
-
- $ ruby argument_abbreviation.rb --help
- Usage: argument_abbreviation [options]
- Usage: argument_abbreviation [options]
- -x, --xxx=VALUE Argument abbreviations
- -y, --yyy=VALUE Argument abbreviations
- $ ruby argument_abbreviation.rb --xxx A
- ["--xxx", "ABC"]
- $ ruby argument_abbreviation.rb --xxx c
- argument_abbreviation.rb:9:in `<main>': invalid argument: --xxx c (OptionParser::InvalidArgument)
- $ ruby argument_abbreviation.rb --yyy a --yyy d
- ["--yyy", "XYZ"]
- ["--yyy", "FOO"]
-
=== Argument Values
Permissible argument values may be restricted
@@ -545,11 +522,11 @@ Executions:
=== Argument Converters
An option can specify that its argument is to be converted
-from the default +String+ to an instance of another class.
+from the default \String to an instance of another class.
There are a number of built-in converters.
Example: File +date.rb+
-defines an option whose argument is to be converted to a +Date+ object.
+defines an option whose argument is to be converted to a \Date object.
The argument is converted by method Date#parse.
:include: ruby/date.rb
@@ -569,7 +546,7 @@ for both built-in and custom converters.
=== Help
-+OptionParser+ makes automatically generated help text available.
+\OptionParser makes automatically generated help text available.
The help text consists of:
@@ -637,49 +614,49 @@ Execution:
=== Top List and Base List
-An +OptionParser+ object maintains a stack of OptionParser::List objects,
+An \OptionParser object maintains a stack of \OptionParser::List objects,
each of which has a collection of zero or more options.
It is unlikely that you'll need to add or take away from that stack.
The stack includes:
-- The <em>top list</em>, given by OptionParser#top.
-- The <em>base list</em>, given by OptionParser#base.
+- The <em>top list</em>, given by \OptionParser#top.
+- The <em>base list</em>, given by \OptionParser#base.
-When +OptionParser+ builds its help text, the options in the top list
+When \OptionParser builds its help text, the options in the top list
precede those in the base list.
-=== Methods for Defining Options
+=== Defining Options
Option-defining methods allow you to create an option, and also append/prepend it
to the top list or append it to the base list.
Each of these next three methods accepts a sequence of parameter arguments and a block,
-creates an option object using method OptionParser#make_switch (see below),
+creates an option object using method \Option#make_switch (see below),
and returns the created option:
-- \Method OptionParser#define appends the created option to the top list.
+- \Method \OptionParser#define appends the created option to the top list.
-- \Method OptionParser#define_head prepends the created option to the top list.
+- \Method \OptionParser#define_head prepends the created option to the top list.
-- \Method OptionParser#define_tail appends the created option to the base list.
+- \Method \OptionParser#define_tail appends the created option to the base list.
These next three methods are identical to the three above,
except for their return values:
-- \Method OptionParser#on is identical to method OptionParser#define,
+- \Method \OptionParser#on is identical to method \OptionParser#define,
except that it returns the parser object +self+.
-- \Method OptionParser#on_head is identical to method OptionParser#define_head,
+- \Method \OptionParser#on_head is identical to method \OptionParser#define_head,
except that it returns the parser object +self+.
-- \Method OptionParser#on_tail is identical to method OptionParser#define_tail,
+- \Method \OptionParser#on_tail is identical to method \OptionParser#define_tail,
except that it returns the parser object +self+.
Though you may never need to call it directly,
here's the core method for defining an option:
-- \Method OptionParser#make_switch accepts an array of parameters and a block.
+- \Method \OptionParser#make_switch accepts an array of parameters and a block.
See {Parameters for New Options}[optparse/option_params.rdoc].
This method is unlike others here in that it:
- Accepts an <em>array of parameters</em>;
@@ -691,7 +668,7 @@ here's the core method for defining an option:
=== Parsing
-+OptionParser+ has six instance methods for parsing.
+\OptionParser has six instance methods for parsing.
Three have names ending with a "bang" (<tt>!</tt>):
@@ -722,9 +699,9 @@ Each of these methods:
(see {Keyword Argument into}[#label-Keyword+Argument+into]).
- Returns +argv+, possibly with some elements removed.
-==== \Method +parse!+
+==== \Method parse!
-\Method +parse!+:
+\Method parse!:
- Accepts an optional array of string arguments +argv+;
if not given, +argv+ defaults to the value of OptionParser#default_argv,
@@ -779,9 +756,9 @@ Processing ended by non-option found when +POSIXLY_CORRECT+ is defined:
["--xxx", true]
Returned: ["input_file.txt", "output_file.txt", "-yyy", "FOO"] (Array)
-==== \Method +parse+
+==== \Method parse
-\Method +parse+:
+\Method parse:
- Accepts an array of string arguments
_or_ zero or more string arguments.
@@ -833,25 +810,25 @@ Processing ended by non-option found when +POSIXLY_CORRECT+ is defined:
["--xxx", true]
Returned: ["input_file.txt", "output_file.txt", "-yyy", "FOO"] (Array)
-==== \Method +order!+
+==== \Method order!
Calling method OptionParser#order! gives exactly the same result as
calling method OptionParser#parse! with environment variable
+POSIXLY_CORRECT+ defined.
-==== \Method +order+
+==== \Method order
Calling method OptionParser#order gives exactly the same result as
calling method OptionParser#parse with environment variable
+POSIXLY_CORRECT+ defined.
-==== \Method +permute!+
+==== \Method permute!
Calling method OptionParser#permute! gives exactly the same result as
calling method OptionParser#parse! with environment variable
+POSIXLY_CORRECT+ _not_ defined.
-==== \Method +permute+
+==== \Method permute
Calling method OptionParser#permute gives exactly the same result as
calling method OptionParser#parse with environment variable
diff --git a/doc/packed_data.rdoc b/doc/packed_data.rdoc
index fa95db9106..ec13b24c69 100644
--- a/doc/packed_data.rdoc
+++ b/doc/packed_data.rdoc
@@ -1,4 +1,4 @@
-= Packed \Data
+== Packed \Data
Certain Ruby core methods deal with packing and unpacking data:
@@ -64,7 +64,7 @@ If elements don't fit the provided directive, only least significant bits are en
[257].pack("C").unpack("C") # => [1]
-== Packing \Method
+=== Packing \Method
\Method Array#pack accepts optional keyword argument
+buffer+ that specifies the target string (instead of a new string):
@@ -76,7 +76,7 @@ The method can accept a block:
# Packed string is passed to the block.
[65, 66].pack('C*') {|s| p s } # => "AB"
-== Unpacking Methods
+=== Unpacking Methods
Methods String#unpack and String#unpack1 each accept
an optional keyword argument +offset+ that specifies an offset
@@ -95,12 +95,12 @@ Both methods can accept a block:
# The single unpacked object is passed to the block.
'AB'.unpack1('C*') {|ele| p ele } # => 65
-== \Integer Directives
+=== \Integer Directives
Each integer directive specifies the packing or unpacking
for one element in the input or output array.
-=== 8-Bit \Integer Directives
+==== 8-Bit \Integer Directives
- <tt>'c'</tt> - 8-bit signed integer
(like C <tt>signed char</tt>):
@@ -109,14 +109,14 @@ for one element in the input or output array.
s = [0, 1, -1].pack('c*') # => "\x00\x01\xFF"
s.unpack('c*') # => [0, 1, -1]
-- <tt>'C'</tt> - 8-bit unsigned integer
+- <tt>'C'</tt> - 8-bit signed integer
(like C <tt>unsigned char</tt>):
[0, 1, 255].pack('C*') # => "\x00\x01\xFF"
s = [0, 1, -1].pack('C*') # => "\x00\x01\xFF"
s.unpack('C*') # => [0, 1, 255]
-=== 16-Bit \Integer Directives
+==== 16-Bit \Integer Directives
- <tt>'s'</tt> - 16-bit signed integer, native-endian
(like C <tt>int16_t</tt>):
@@ -146,7 +146,7 @@ for one element in the input or output array.
s.unpack('v*')
# => [0, 1, 65535, 32767, 32768, 65535]
-=== 32-Bit \Integer Directives
+==== 32-Bit \Integer Directives
- <tt>'l'</tt> - 32-bit signed integer, native-endian
(like C <tt>int32_t</tt>):
@@ -178,7 +178,7 @@ for one element in the input or output array.
s.unpack('v*')
# => [0, 0, 1, 0, 65535, 65535]
-=== 64-Bit \Integer Directives
+==== 64-Bit \Integer Directives
- <tt>'q'</tt> - 64-bit signed integer, native-endian
(like C <tt>int64_t</tt>):
@@ -196,7 +196,7 @@ for one element in the input or output array.
s.unpack('Q*')
# => [578437695752307201, 17940646550795321087]
-=== Platform-Dependent \Integer Directives
+==== Platform-Dependent \Integer Directives
- <tt>'i'</tt> - Platform-dependent width signed integer,
native-endian (like C <tt>int</tt>):
@@ -214,24 +214,26 @@ for one element in the input or output array.
s.unpack('I*')
# => [67305985, 4244504319]
-- <tt>'j'</tt> - Pointer-width signed integer, native-endian
- (like C <tt>intptr_t</tt>):
+==== Pointer Directives
+
+- <tt>'j'</tt> - 64-bit pointer-width signed integer,
+ native-endian (like C <tt>intptr_t</tt>):
s = [67305985, -50462977].pack('j*')
# => "\x01\x02\x03\x04\x00\x00\x00\x00\xFF\xFE\xFD\xFC\xFF\xFF\xFF\xFF"
s.unpack('j*')
# => [67305985, -50462977]
-- <tt>'J'</tt> - Pointer-width unsigned integer, native-endian
- (like C <tt>uintptr_t</tt>):
+- <tt>'j'</tt> - 64-bit pointer-width unsigned integer,
+ native-endian (like C <tt>uintptr_t</tt>):
s = [67305985, 4244504319].pack('J*')
# => "\x01\x02\x03\x04\x00\x00\x00\x00\xFF\xFE\xFD\xFC\x00\x00\x00\x00"
s.unpack('J*')
# => [67305985, 4244504319]
-=== Other \Integer Directives
-
+==== Other \Integer Directives
+:
- <tt>'U'</tt> - UTF-8 character:
s = [4194304].pack('U*')
@@ -240,37 +242,38 @@ for one element in the input or output array.
# => [4194304]
- <tt>'w'</tt> - BER-encoded integer
- (see {BER encoding}[https://en.wikipedia.org/wiki/X.690#BER_encoding]):
+ (see {BER enocding}[https://en.wikipedia.org/wiki/X.690#BER_encoding]):
s = [1073741823].pack('w*')
# => "\x83\xFF\xFF\xFF\x7F"
s.unpack('w*')
# => [1073741823]
-=== Modifiers for \Integer Directives
-
-For the following directives, <tt>'!'</tt> or <tt>'_'</tt> modifiers may be
-suffixed as underlying platform’s native size.
-
-- <tt>'i'</tt>, <tt>'I'</tt> - C <tt>int</tt>, always native size.
-- <tt>'s'</tt>, <tt>'S'</tt> - C <tt>short</tt>.
-- <tt>'l'</tt>, <tt>'L'</tt> - C <tt>long</tt>.
-- <tt>'q'</tt>, <tt>'Q'</tt> - C <tt>long long</tt>, if available.
-- <tt>'j'</tt>, <tt>'J'</tt> - C <tt>intptr_t</tt>, always native size.
-
-Native size modifiers are silently ignored for always native size directives.
-
-The endian modifiers also may be suffixed in the directives above:
-
+==== Modifiers for \Integer Directives
+
+For directives in
+<tt>'i'</tt>,
+<tt>'I'</tt>,
+<tt>'s'</tt>,
+<tt>'S'</tt>,
+<tt>'l'</tt>,
+<tt>'L'</tt>,
+<tt>'q'</tt>,
+<tt>'Q'</tt>,
+<tt>'j'</tt>, and
+<tt>'J'</tt>,
+these modifiers may be suffixed:
+
+- <tt>'!'</tt> or <tt>'_'</tt> - Underlying platform’s native size.
- <tt>'>'</tt> - Big-endian.
- <tt>'<'</tt> - Little-endian.
-== \Float Directives
+=== \Float Directives
Each float directive specifies the packing or unpacking
for one element in the input or output array.
-=== Single-Precision \Float Directives
+==== Single-Precision \Float Directives
- <tt>'F'</tt> or <tt>'f'</tt> - Native format:
@@ -287,7 +290,7 @@ for one element in the input or output array.
s = [3.0].pack('g') # => "@@\x00\x00"
s.unpack('g') # => [3.0]
-=== Double-Precision \Float Directives
+==== Double-Precision \Float Directives
- <tt>'D'</tt> or <tt>'d'</tt> - Native format:
@@ -314,12 +317,12 @@ A float directive may be infinity or not-a-number:
[nan].pack('f') # => "\x00\x00\xC0\x7F"
"\x00\x00\xC0\x7F".unpack('f') # => [NaN]
-== \String Directives
+=== \String Directives
Each string directive specifies the packing or unpacking
for one byte in the input or output string.
-=== Binary \String Directives
+==== Binary \String Directives
- <tt>'A'</tt> - Arbitrary binary string (space padded; count is width);
+nil+ is treated as the empty string:
@@ -377,7 +380,7 @@ for one byte in the input or output string.
"foo".unpack('Z*') # => ["foo"]
"foo\0bar".unpack('Z*') # => ["foo"] # Does not read past "\0".
-=== Bit \String Directives
+==== Bit \String Directives
- <tt>'B'</tt> - Bit string (high byte first):
@@ -421,7 +424,7 @@ for one byte in the input or output string.
"\x01".unpack("b2") # => ["10"]
"\x01".unpack("b3") # => ["100"]
-=== Hex \String Directives
+==== Hex \String Directives
- <tt>'H'</tt> - Hex string (high nibble first):
@@ -467,7 +470,7 @@ for one byte in the input or output string.
"\x01\xfe".unpack('h4') # => ["10ef"]
"\x01\xfe".unpack('h5') # => ["10ef"]
-=== Pointer \String Directives
+==== Pointer \String Directives
- <tt>'P'</tt> - Pointer to a structure (fixed-length string):
@@ -485,7 +488,7 @@ for one byte in the input or output string.
("\0" * 8).unpack("p") # => [nil]
[nil].pack("p") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
-=== Other \String Directives
+==== Other \String Directives
- <tt>'M'</tt> - Quoted printable, MIME encoding;
text mode, but input must use LF and output LF;
@@ -554,52 +557,34 @@ for one byte in the input or output string.
- <tt>'u'</tt> - UU-encoded string:
- [""].pack("u") # => ""
- ["a"].pack("u") # => "!80``\n"
- ["aaa"].pack("u") # => "#86%A\n"
-
- "".unpack("u") # => [""]
- "#86)C\n".unpack("u") # => ["abc"]
+ [0].pack("U") # => "\u0000"
+ [0x3fffffff].pack("U") # => "\xFC\xBF\xBF\xBF\xBF\xBF"
+ [0x40000000].pack("U") # => "\xFD\x80\x80\x80\x80\x80"
+ [0x7fffffff].pack("U") # => "\xFD\xBF\xBF\xBF\xBF\xBF"
-== Offset Directives
+=== Offset Directives
- <tt>'@'</tt> - Begin packing at the given byte offset;
- for packing, null fill or shrink if necessary:
-
- [1, 2].pack("C@0C") # => "\x02"
- [1, 2].pack("C@1C") # => "\x01\x02"
- [1, 2].pack("C@5C") # => "\x01\x00\x00\x00\x00\x02"
- [*1..5].pack("CCCC@2C") # => "\x01\x02\x05"
+ for packing, null fill if necessary:
- For unpacking, cannot to move to outside the string:
+ [1, 2].pack("C@0C") # => "\x02"
+ [1, 2].pack("C@1C") # => "\x01\x02"
+ [1, 2].pack("C@5C") # => "\x01\x00\x00\x00\x00\x02"
"\x01\x00\x00\x02".unpack("C@3C") # => [1, 2]
"\x00".unpack("@1C") # => [nil]
- "\x00".unpack("@2C") # Raises ArgumentError.
-- <tt>'X'</tt> - For packing, shrink for the given byte offset:
+- <tt>'X'</tt> - Back up a byte:
[0, 1, 2].pack("CCXC") # => "\x00\x02"
[0, 1, 2].pack("CCX2C") # => "\x02"
-
- For unpacking; rewind unpacking position for the given byte offset:
-
"\x00\x02".unpack("CCXC") # => [0, 2, 2]
- Cannot to move to outside the string:
+=== Null Byte Direcive
- [0, 1, 2].pack("CCX3C") # Raises ArgumentError.
- "\x00\x02".unpack("CX3C") # Raises ArgumentError.
-
-- <tt>'x'</tt> - Begin packing at after the given byte offset;
- for packing, null fill if necessary:
+- <tt>'x'</tt> - Null byte:
[].pack("x0") # => ""
[].pack("x") # => "\x00"
[].pack("x8") # => "\x00\x00\x00\x00\x00\x00\x00\x00"
-
- For unpacking, cannot to move to outside the string:
-
"\x00\x00\x02".unpack("CxC") # => [0, 2]
- "\x00\x00\x02".unpack("x3C") # => [nil]
- "\x00\x00\x02".unpack("x4C") # Raises ArgumentError
diff --git a/doc/pty/README.expect.ja b/doc/pty/README.expect.ja
index a4eb6b01df..7c0456f24f 100644
--- a/doc/pty/README.expect.ja
+++ b/doc/pty/README.expect.ja
@@ -1,23 +1,21 @@
-= README for expect
+ README for expect
by A. Ito, 28 October, 1998
-Expectライブラリã¯ï¼Œtcl ã® expect パッケージã¨ä¼¼ãŸã‚ˆã†ãªæ©Ÿèƒ½ã‚’
+ Expectライブラリã¯ï¼Œtcl ã® expect パッケージã¨ä¼¼ãŸã‚ˆã†ãªæ©Ÿèƒ½ã‚’
IOクラスã«è¿½åŠ ã—ã¾ã™ï¼Ž
-追加ã•れるメソッドã®ä½¿ã„æ–¹ã¯æ¬¡ã®é€šã‚Šã§ã™ï¼Ž
+ 追加ã•れるメソッドã®ä½¿ã„æ–¹ã¯æ¬¡ã®é€šã‚Šã§ã™ï¼Ž
-[IO#expect(pattern,timeout=9999999)]
+ IO#expect(pattern,timeout=9999999)
- _pattern_ 㯠String ã‹ Regexp ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ï¼Œ_timeout_ 㯠Fixnum
- ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã§ã™ï¼Ž_timeout_ ã¯çœç•¥ã§ãã¾ã™ï¼Ž
-
- ã“ã®ãƒ¡ã‚½ãƒƒãƒ‰ãŒãƒ–ロックãªã—ã§å‘¼ã°ã‚ŒãŸå ´åˆï¼Œã¾ãšãƒ¬ã‚·ãƒ¼ãƒã§ã‚ã‚‹
- IOオブジェクトã‹ã‚‰ _pattern_ ã«ãƒžãƒƒãƒã™ã‚‹ãƒ‘ターンãŒèª­ã¿ã“ã¾ã‚Œã‚‹
- ã¾ã§å¾…ã¡ã¾ã™ï¼Žãƒ‘ターンãŒå¾—られãŸã‚‰ï¼Œãã®ãƒ‘ターンã«é–¢ã™ã‚‹é…列を
- è¿”ã—ã¾ã™ï¼Žé…åˆ—ã®æœ€åˆã®è¦ç´ ã¯ï¼Œ_pattern_ ã«ãƒžãƒƒãƒã™ã‚‹ã¾ã§ã«èª­ã¿ã“
- ã¾ã‚ŒãŸå†…å®¹ã®æ–‡å­—列ã§ã™ï¼Ž2番目以é™ã®è¦ç´ ã¯ï¼Œ_pattern_ ã®æ­£è¦è¡¨ç¾
- ã®ä¸­ã«ã‚¢ãƒ³ã‚«ãƒ¼ãŒã‚ã£ãŸå ´åˆã«ï¼Œãã®ã‚¢ãƒ³ã‚«ãƒ¼ã«ãƒžãƒƒãƒã™ã‚‹éƒ¨åˆ†ã§ã™ï¼Ž
- ã‚‚ã—タイムアウトãŒèµ·ããŸå ´åˆã¯ï¼Œã“ã®ãƒ¡ã‚½ãƒƒãƒ‰ã¯ +nil+ ã‚’è¿”ã—ã¾ã™ï¼Ž
-
- ã“ã®ãƒ¡ã‚½ãƒƒãƒ‰ãŒãƒ–ロック付ãã§å‘¼ã°ã‚ŒãŸå ´åˆã«ã¯ï¼Œãƒžãƒƒãƒã—ãŸè¦ç´ ã®
- é…列ãŒãƒ–ロック引数ã¨ã—ã¦æ¸¡ã•れ,ブロックãŒè©•価ã•れã¾ã™ï¼Ž
+pattern 㯠String ã‹ Regexp ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ï¼Œtimeout 㯠Fixnum
+ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã§ã™ï¼Žtimeout ã¯çœç•¥ã§ãã¾ã™ï¼Ž
+ ã“ã®ãƒ¡ã‚½ãƒƒãƒ‰ãŒãƒ–ロックãªã—ã§å‘¼ã°ã‚ŒãŸå ´åˆï¼Œã¾ãšãƒ¬ã‚·ãƒ¼ãƒã§ã‚ã‚‹
+IOオブジェクトã‹ã‚‰ pattern ã«ãƒžãƒƒãƒã™ã‚‹ãƒ‘ターンãŒèª­ã¿ã“ã¾ã‚Œã‚‹
+ã¾ã§å¾…ã¡ã¾ã™ï¼Žãƒ‘ターンãŒå¾—られãŸã‚‰ï¼Œãã®ãƒ‘ターンã«é–¢ã™ã‚‹é…列を
+è¿”ã—ã¾ã™ï¼Žé…åˆ—ã®æœ€åˆã®è¦ç´ ã¯ï¼Œpattern ã«ãƒžãƒƒãƒã™ã‚‹ã¾ã§ã«èª­ã¿ã“
+ã¾ã‚ŒãŸå†…å®¹ã®æ–‡å­—列ã§ã™ï¼Ž2番目以é™ã®è¦ç´ ã¯ï¼Œpattern ã®æ­£è¦è¡¨ç¾
+ã®ä¸­ã«ã‚¢ãƒ³ã‚«ãƒ¼ãŒã‚ã£ãŸå ´åˆã«ï¼Œãã®ã‚¢ãƒ³ã‚«ãƒ¼ã«ãƒžãƒƒãƒã™ã‚‹éƒ¨åˆ†ã§ã™ï¼Ž
+ã‚‚ã—タイムアウトãŒèµ·ããŸå ´åˆã¯ï¼Œã“ã®ãƒ¡ã‚½ãƒƒãƒ‰ã¯nilã‚’è¿”ã—ã¾ã™ï¼Ž
+ ã“ã®ãƒ¡ã‚½ãƒƒãƒ‰ãŒãƒ–ロック付ãã§å‘¼ã°ã‚ŒãŸå ´åˆã«ã¯ï¼Œãƒžãƒƒãƒã—ãŸè¦ç´ ã®
+é…列ãŒãƒ–ロック引数ã¨ã—ã¦æ¸¡ã•れ,ブロックãŒè©•価ã•れã¾ã™ï¼Ž
diff --git a/doc/pty/README.ja b/doc/pty/README.ja
index a26b4932ff..2d83ffa033 100644
--- a/doc/pty/README.ja
+++ b/doc/pty/README.ja
@@ -1,26 +1,27 @@
-= pty 拡張モジュール version 0.3 by A.ito
+pty 拡張モジュール version 0.3 by A.ito
1. ã¯ã˜ã‚ã«
- ã“ã®æ‹¡å¼µãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã¯ï¼Œä»®æƒ³tty (pty) を通ã—ã¦é©å½“ãªã‚³ãƒžãƒ³ãƒ‰ã‚’
- 実行ã™ã‚‹æ©Ÿèƒ½ã‚’ ruby ã«æä¾›ã—ã¾ã™ï¼Ž
+ã“ã®æ‹¡å¼µãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã¯ï¼Œä»®æƒ³tty (pty) を通ã—ã¦é©å½“ãªã‚³ãƒžãƒ³ãƒ‰ã‚’
+実行ã™ã‚‹æ©Ÿèƒ½ã‚’ ruby ã«æä¾›ã—ã¾ã™ï¼Ž
2. インストール
- 次ã®ã‚ˆã†ã«ã—ã¦ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ã¦ãã ã•ã„.
+次ã®ã‚ˆã†ã«ã—ã¦ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ã¦ãã ã•ã„.
- 1. <tt>ruby extconf.rb</tt>
- を実行ã™ã‚‹ã¨ Makefile ãŒç”Ÿæˆã•れã¾ã™ï¼Ž
+(1) ruby extconf.rb
- 2. <tt>make; make install</tt> を実行ã—ã¦ãã ã•ã„.
+ を実行ã™ã‚‹ã¨ Makefile ãŒç”Ÿæˆã•れã¾ã™ï¼Ž
+
+(2) make; make install を実行ã—ã¦ãã ã•ã„.
3. 何ãŒã§ãã‚‹ã‹
- ã“ã®æ‹¡å¼µãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã¯ï¼ŒPTY ã¨ã„ã†ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’定義ã—ã¾ã™ï¼Žãã®ä¸­
- ã«ã¯ï¼Œæ¬¡ã®ã‚ˆã†ãªãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«é–¢æ•°ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ï¼Ž
+ã“ã®æ‹¡å¼µãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã¯ï¼ŒPTY ã¨ã„ã†ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’定義ã—ã¾ã™ï¼Žãã®ä¸­
+ã«ã¯ï¼Œæ¬¡ã®ã‚ˆã†ãªãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«é–¢æ•°ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ï¼Ž
- [PTY.getpty(command)]
- [PTY.spawn(command)]
+ getpty(command)
+ spawn(command)
ã“ã®é–¢æ•°ã¯ï¼Œä»®æƒ³ttyを確ä¿ã—,指定ã•れãŸã‚³ãƒžãƒ³ãƒ‰ã‚’ãã®ä»®æƒ³tty
ã®å‘ã“ã†ã§å®Ÿè¡Œã—,é…列を返ã—ã¾ã™ï¼Žæˆ»ã‚Šå€¤ã¯3ã¤ã®è¦ç´ ã‹ã‚‰ãªã‚‹
@@ -34,7 +35,12 @@
ã®ã¿ä¾‹å¤–ãŒç™ºç”Ÿã—ã¾ã™ï¼Žå­ãƒ—ロセスをモニターã—ã¦ã„るスレッドã¯ãƒ–ロッ
クを抜ã‘ã‚‹ã¨ãã«çµ‚了ã—ã¾ã™ï¼Ž
- [PTY.open]
+ protect_signal
+ reset_signal
+
+ 廃止予定ã§ã™ï¼Ž
+
+ PTY.open
仮想ttyを確ä¿ã—,マスターå´ã«å¯¾å¿œã™ã‚‹IOオブジェクトã¨ã‚¹ãƒ¬ãƒ¼ãƒ–å´ã«
対応ã™ã‚‹Fileオブジェクトã®é…列を返ã—ã¾ã™ï¼Žãƒ–ロック付ãã§å‘¼ã³å‡ºã•
@@ -42,7 +48,7 @@
クã‹ã‚‰è¿”ã•れãŸçµæžœã‚’è¿”ã—ã¾ã™ï¼Žã¾ãŸã€ã“ã®ãƒžã‚¹ã‚¿ãƒ¼IOã¨ã‚¹ãƒ¬ãƒ¼ãƒ–File
ã¯ã€ãƒ–ロックを抜ã‘ã‚‹ã¨ãã«ã‚¯ãƒ­ãƒ¼ã‚ºæ¸ˆã¿ã§ãªã‘れã°ã‚¯ãƒ­ãƒ¼ã‚ºã•れã¾ã™ï¼Ž
- [PTY.check(pid[, raise=false])]
+ PTY.check(pid[, raise=false])
pidã§æŒ‡å®šã•れãŸå­ãƒ—ロセスã®çŠ¶æ…‹ã‚’ãƒã‚§ãƒƒã‚¯ã—,実行中ã§ã‚れã°nilã‚’
è¿”ã—ã¾ã™ï¼Žçµ‚了ã—ã¦ã„ã‚‹ã‹åœæ­¢ã—ã¦ã„ã‚‹å ´åˆã€ç¬¬äºŒå¼•æ•°ãŒå½ã§ã‚れã°ã€
@@ -51,20 +57,20 @@
4. 利用ã«ã¤ã„ã¦
- 伊藤彰則ãŒè‘—ä½œæ¨©ã‚’ä¿æœ‰ã—ã¾ã™ï¼Ž
+伊藤彰則ãŒè‘—ä½œæ¨©ã‚’ä¿æœ‰ã—ã¾ã™ï¼Ž
- ソースプログラムã¾ãŸã¯ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã«å…ƒã®è‘—ä½œæ¨©è¡¨ç¤ºãŒæ”¹å¤‰ã•れãšã«
- 表示ã•れã¦ã„ã‚‹å ´åˆã«é™ã‚Šï¼Œèª°ã§ã‚‚,ã“ã®ã‚½ãƒ•トウェアを無償ã‹ã¤è‘—作
- 権者ã«ç„¡æ–­ã§åˆ©ç”¨ãƒ»é…布・改変ã§ãã¾ã™ï¼Žåˆ©ç”¨ç›®çš„ã¯é™å®šã•れã¦ã„ã¾ã›
- ん.
+ソースプログラムã¾ãŸã¯ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã«å…ƒã®è‘—ä½œæ¨©è¡¨ç¤ºãŒæ”¹å¤‰ã•れãšã«
+表示ã•れã¦ã„ã‚‹å ´åˆã«é™ã‚Šï¼Œèª°ã§ã‚‚,ã“ã®ã‚½ãƒ•トウェアを無償ã‹ã¤è‘—作
+権者ã«ç„¡æ–­ã§åˆ©ç”¨ãƒ»é…布・改変ã§ãã¾ã™ï¼Žåˆ©ç”¨ç›®çš„ã¯é™å®šã•れã¦ã„ã¾ã›
+ん.
- ã“ã®ãƒ—ログラムã®åˆ©ç”¨ãƒ»é…布ãã®ä»–ã“ã®ãƒ—ログラムã«é–¢ä¿‚ã™ã‚‹è¡Œç‚ºã«ã‚ˆ
- ã£ã¦ç”Ÿã˜ãŸã„ã‹ãªã‚‹æå®³ã«å¯¾ã—ã¦ã‚‚,作者ã¯ä¸€åˆ‡è²¬ä»»ã‚’è² ã„ã¾ã›ã‚“.
+ã“ã®ãƒ—ログラムã®åˆ©ç”¨ãƒ»é…布ãã®ä»–ã“ã®ãƒ—ログラムã«é–¢ä¿‚ã™ã‚‹è¡Œç‚ºã«ã‚ˆ
+ã£ã¦ç”Ÿã˜ãŸã„ã‹ãªã‚‹æå®³ã«å¯¾ã—ã¦ã‚‚,作者ã¯ä¸€åˆ‡è²¬ä»»ã‚’è² ã„ã¾ã›ã‚“.
5. ãƒã‚°å ±å‘Šç­‰
- ãƒã‚°ãƒ¬ãƒãƒ¼ãƒˆã¯æ­“迎ã—ã¾ã™ï¼Ž
+ãƒã‚°ãƒ¬ãƒãƒ¼ãƒˆã¯æ­“迎ã—ã¾ã™ï¼Ž
aito@ei5sun.yz.yamagata-u.ac.jp
- ã¾ã§é›»å­ãƒ¡ãƒ¼ãƒ«ã§ãƒã‚°ãƒ¬ãƒãƒ¼ãƒˆã‚’ãŠé€ã‚Šãã ã•ã„.
+ã¾ã§é›»å­ãƒ¡ãƒ¼ãƒ«ã§ãƒã‚°ãƒ¬ãƒãƒ¼ãƒˆã‚’ãŠé€ã‚Šãã ã•ã„.
diff --git a/doc/ractor.md b/doc/ractor.md
index 7a69e839de..843754c263 100644
--- a/doc/ractor.md
+++ b/doc/ractor.md
@@ -204,8 +204,8 @@ For message sending and receiving, there are two types of APIs: push type and pu
* When a Ractor is terminated, the Ractor's ports are closed.
* There are 3 ways to send an object as a message
* (1) Send a reference: Sending a shareable object, send only a reference to the object (fast)
- * (2) Copy an object: Sending an unshareable object by copying an object deeply (slow). Note that you can not send an object which does not support deep copy. Some `T_DATA` objects (objects whose class is defined in a C extension, such as `StringIO`) are not supported.
- * (3) Move an object: Sending an unshareable object reference with a membership. Sender Ractor can not access moved objects anymore (raise an exception) after moving it. Current implementation makes new object as a moved object for receiver Ractor and copies references of sending object to moved object. `T_DATA` objects are not supported.
+ * (2) Copy an object: Sending an unshareable object by copying an object deeply (slow). Note that you can not send an object which does not support deep copy. Some `T_DATA` objects are not supported.
+ * (3) Move an object: Sending an unshareable object reference with a membership. Sender Ractor can not access moved objects anymore (raise an exception) after moving it. Current implementation makes new object as a moved object for receiver Ractor and copies references of sending object to moved object.
* You can choose "Copy" and "Move" by the `move:` keyword, `Ractor#send(obj, move: true/false)` and `Ractor.yield(obj, move: true/false)` (default is `false` (COPY)).
### Sending/Receiving ports
@@ -393,7 +393,7 @@ TODO: `select` syntax of go-language uses round-robin technique to make fair sch
* `Ractor#close_incoming/outgoing` close incoming/outgoing ports (similar to `Queue#close`).
* `Ractor#close_incoming`
- * `r.send(obj)` where `r`'s incoming port is closed, will raise an exception.
+ * `r.send(obj) ` where `r`'s incoming port is closed, will raise an exception.
* When the incoming queue is empty and incoming port is closed, `Ractor.receive` raises an exception. If the incoming queue is not empty, it dequeues an object without exceptions.
* `Ractor#close_outgoing`
* `Ractor.yield` on a Ractor which closed the outgoing port, it will raise an exception.
@@ -536,7 +536,7 @@ The following objects are shareable.
Implementation: Now shareable objects (`RVALUE`) have `FL_SHAREABLE` flag. This flag can be added lazily.
-To make shareable objects, `Ractor.make_shareable(obj)` method is provided. In this case, try to make sharaeble by freezing `obj` and recursively traversable objects. This method accepts `copy:` keyword (default value is false).`Ractor.make_shareable(obj, copy: true)` tries to make a deep copy of `obj` and make the copied object shareable.
+To make shareable objects, `Ractor.make_shareable(obj)` method is provided. In this case, try to make sharaeble by freezing `obj` and recursively travasible objects. This method accepts `copy:` keyword (default value is false).`Ractor.make_shareable(obj, copy: true)` tries to make a deep copy of `obj` and make the copied object shareable.
## Language changes to isolate unshareable objects between Ractors
@@ -705,8 +705,8 @@ TABLE = {a: 'ko1', b: 'ko2', c: 'ko3'}
* none: Do nothing. Same as: `CONST = expr`
* literal:
- * if `expr` consists of literals, replaced to `CONST = Ractor.make_shareable(expr)`.
- * otherwise: replaced to `CONST = expr.tap{|o| raise unless Ractor.shareable?(o)}`.
+ * if `expr` is consites of literals, replaced to `CONST = Ractor.make_shareable(expr)`.
+ * otherwise: replaced to `CONST = expr.tap{|o| raise unless Ractor.shareable?}`.
* experimental_everything: replaced to `CONST = Ractor.make_shareable(expr)`.
* experimental_copy: replaced to `CONST = Ractor.make_shareable(expr, copy: true)`.
diff --git a/doc/rdoc/markup_reference.rb b/doc/rdoc/markup_reference.rb
index bb2dc67eca..66ec6786c0 100644
--- a/doc/rdoc/markup_reference.rb
+++ b/doc/rdoc/markup_reference.rb
@@ -7,61 +7,72 @@ require 'rdoc'
# attributes, and constants -- are solely for illustrating \RDoc markup,
# and have no other legitimate use.
#
-# == About the Examples
+# = \RDoc Markup Reference
+#
+# Notes:
#
# - Examples in this reference are Ruby code and comments;
# certain differences from other sources
# (such as C code and comments) are noted.
-# - Almost all examples on this page are all RDoc-like;
-# that is, they have no explicit comment markers like Ruby <tt>#</tt>
-# or C <tt>/* ... */</tt>.
# - An example that shows rendered HTML output
# displays that output in a blockquote:
#
+# Rendered HTML:
# >>>
# Some stuff
#
-# == \RDoc Sources
+# \RDoc-generated documentation is derived from and controlled by:
#
-# The sources of \RDoc documentation vary according to the type of file:
+# - Single-line or multi-line comments that precede certain definitions;
+# see {Markup in Comments}[rdoc-ref:RDoc::MarkupReference@Markup+in+Comments].
+# - \RDoc directives in trailing comments (on the same line as code);
+# see <tt>:nodoc:</tt>, <tt>:doc:</tt>, and <tt>:notnew</tt>.
+# - \RDoc directives in single-line comments;
+# see other {Directives}[rdoc-ref:RDoc::MarkupReference@Directives].
+# - The Ruby code itself (but not from C code);
+# see {Documentation Derived from Ruby Code}[rdoc-ref:RDoc::MarkupReference@Documentation+Derived+from+Ruby+Code].
#
-# - <tt>.rb</tt> (Ruby code file):
+# == Markup in Comments
#
-# - Markup may be found in Ruby comments:
-# A comment that immediately precedes the definition
-# of a Ruby class, module, method, alias, constant, or attribute
-# becomes the documentation for that defined object.
-# - An \RDoc directive may be found in:
+# The treatment of markup in comments varies according to the type of file:
#
-# - A trailing comment (on the same line as code);
-# see <tt>:nodoc:</tt>, <tt>:doc:</tt>, and <tt>:notnew:</tt>.
-# - A single-line comment;
-# see other {Directives}[rdoc-ref:RDoc::MarkupReference@Directives].
+# - <tt>.rb</tt> (Ruby code file): markup is parsed from Ruby comments.
+# - <tt>.c</tt> (C code file): markup is parsed from C comments.
+# - <tt>.rdoc</tt> (RDoc text file): markup is parsed from the entire file.
#
-# - Documentation may be derived from the Ruby code itself;
-# see {Documentation Derived from Ruby Code}[rdoc-ref:RDoc::MarkupReference@Documentation+Derived+from+Ruby+Code].
+# The comment associated with
+# a Ruby class, module, method, alias, constant, or attribute
+# becomes the documentation for that defined object:
#
-# - <tt>.c</tt> (C code file): markup is parsed from C comments.
-# A comment that immediately precedes
-# a function that implements a Ruby method,
-# or otherwise immediately precedes the definition of a Ruby object,
-# becomes the documentation for that object.
-# - <tt>.rdoc</tt> (\RDoc markup text file) or <tt>.md</tt> (\RDoc markdown text file):
-# markup is parsed from the entire file.
-# The text is not associated with any code object,
-# but may (depending on how the documentation is built)
-# become a separate page.
-#
-# An <i>RDoc document</i>:
-#
-# - A (possibly multi-line) comment in a Ruby or C file
-# that generates \RDoc documentation (as above).
-# - The entire markup (<tt>.rdoc</tt>) file or markdown (<tt>.md</tt>) file
-# (which is usually multi-line).
+# - In a Ruby file, that comment immediately precedes
+# the definition of the object.
+# - In a C file, that comment immediately precedes
+# the function that implements a method,
+# or otherwise immediately precedes the definition of the object.
+#
+# In either a Ruby or a C file,
+# \RDoc ignores comments that do not precede object definitions.
+#
+# In an \RDoc file, the text is not associated with any code object,
+# but may (depending on how the documentation is built),
+# become a separate page.
+#
+# Almost all examples on this page are all RDoc-like;
+# that is, they have no comment markers like Ruby <tt>#</tt>
+# or C <tt>/* ... */</tt>.
+#
+# === Margins
+#
+# In a multi-line comment,
+# \RDoc looks for the comment's natural left margin,
+# which becomes the <em>base margin</em> for the comment
+# and is the initial <em>current margin</em> for for the comment.
+#
+# The current margin can change, and does so, for example in a list.
#
# === Blocks
#
-# It's convenient to think of an \RDoc document as a sequence of _blocks_
+# It's convenient to think of \RDoc markup input as a sequence of _blocks_
# of various types (details at the links):
#
# - {Paragraph}[rdoc-ref:RDoc::MarkupReference@Paragraphs]:
@@ -77,7 +88,7 @@ require 'rdoc'
# - {List}[rdoc-ref:RDoc::MarkupReference@Lists]: items for
# a bullet list, numbered list, lettered list, or labeled list.
# - {Heading}[rdoc-ref:RDoc::MarkupReference@Headings]:
-# a heading.
+# a section heading.
# - {Horizontal rule}[rdoc-ref:RDoc::MarkupReference@Horizontal+Rules]:
# a line across the rendered page.
# - {Directive}[rdoc-ref:RDoc::MarkupReference@Directives]:
@@ -92,10 +103,6 @@ require 'rdoc'
# - Any block may appear independently
# (that is, not nested in another block);
# some blocks may be nested, as detailed below.
-# - In a multi-line block,
-# \RDoc looks for the block's natural left margin,
-# which becomes the <em>base margin</em> for the block
-# and is the initial <em>current margin</em> for the block.
#
# ==== Paragraphs
#
@@ -339,7 +346,7 @@ require 'rdoc'
#
# ===== Lettered Lists
#
-# A lettered list item begins with letters and a period.
+# A numbered list item begins with a letters and a period.
#
# The items are automatically "re-lettered."
#
@@ -460,32 +467,8 @@ require 'rdoc'
#
# - Appended to a line of code
# that defines a class, module, method, alias, constant, or attribute.
-#
# - Specifies that the defined object should not be documented.
#
-# - For a method definition in C code, it the directive must be in the comment line
-# immediately preceding the definition:
-#
-# /* :nodoc: */
-# static VALUE
-# some_method(VALUE self)
-# {
-# return self;
-# }
-#
-# Note that this directive has <em>no effect at all</em>
-# when placed at the method declaration:
-#
-# /* :nodoc: */
-# rb_define_method(cMyClass, "do_something", something_func, 0);
-#
-# The above comment is just a comment and has nothing to do with \RDoc.
-# Therefore, +do_something+ method will be reported as "undocumented"
-# unless that method or function is documented elsewhere.
-#
-# - For a constant definition in C code, this directive <em>can not work</em>
-# because there is no "implementation" place for a constant.
-#
# - <tt># :nodoc: all</tt>:
#
# - Appended to a line of code
@@ -497,7 +480,7 @@ require 'rdoc'
#
# - Appended to a line of code
# that defines a class, module, method, alias, constant, or attribute.
-# - Specifies the defined object should be documented, even if it otherwise
+# - Specifies the defined object should be documented, even if otherwise
# would not be documented.
#
# - <tt># :notnew:</tt> (aliased as <tt>:not_new:</tt> and <tt>:not-new:</tt>):
@@ -519,8 +502,8 @@ require 'rdoc'
# #++
# # Documented.
#
-# For C code, any of directives <tt>:startdoc:</tt>, <tt>:stopdoc:</tt>,
-# and <tt>:enddoc:</tt> may appear in a stand-alone comment:
+# For C code, any of directives <tt>:startdoc:</tt>, <tt>:enddoc:</tt>,
+# and <tt>:nodoc:</tt> may appear in a stand-alone comment:
#
# /* :startdoc: */
# /* :stopdoc: */
@@ -532,8 +515,7 @@ require 'rdoc'
#
# - Appears on a line by itself.
# - Specifies the format for the \RDoc input;
-# parameter +type+ is one of: +rdoc+ (the default), +markdown+, +rd+, +tomdoc+.
-# See {Markup Formats}[rdoc-ref:RDoc::Markup@Markup+Formats].
+# parameter +type+ is one of +markdown+, +rd+, +rdoc+, +tomdoc+.
#
# ===== Directives for HTML Output
#
@@ -642,9 +624,9 @@ require 'rdoc'
# The file content is shifted to have the same indentation as the colon
# at the start of the directive.
#
-# The file is searched for in the directory containing the current file,
-# and then in each of the directories given with the <tt>--include</tt>
-# command-line option.
+# The file is searched for in the directories
+# given with the <tt>--include</tt> command-line option,
+# or by default in the current directory.
#
# For C code, the directive may appear in a stand-alone comment
#
@@ -918,6 +900,10 @@ require 'rdoc'
#
# - Linked: <tt>https://github.com</tt> links to https://github.com.
#
+# [Protocol +www+]
+#
+# - Linked: <tt>www.yahoo.com</tt> links to www.yahoo.com.
+#
# [Protocol +ftp+]
#
# - Linked: <tt>ftp://nosuch.site</tt> links to ftp://nosuch.site.
@@ -1206,26 +1192,13 @@ require 'rdoc'
#
class RDoc::MarkupReference
- # Example class.
class DummyClass; end
-
- # Example module.
module DummyModule; end
-
- # Example singleton method.
def self.dummy_singleton_method(foo, bar); end
-
- # Example instance method.
def dummy_instance_method(foo, bar); end;
-
alias dummy_instance_alias dummy_instance_method
-
- # Example attribute.
attr_accessor :dummy_attribute
-
alias dummy_attribute_alias dummy_attribute
-
- # Example constant.
DUMMY_CONSTANT = ''
# :call-seq:
diff --git a/doc/regexp.rdoc b/doc/regexp.rdoc
new file mode 100644
index 0000000000..92c7ecf66e
--- /dev/null
+++ b/doc/regexp.rdoc
@@ -0,0 +1,801 @@
+# -*- mode: rdoc; coding: utf-8; fill-column: 74; -*-
+
+Regular expressions (<i>regexp</i>s) are patterns which describe the
+contents of a string. They're used for testing whether a string contains a
+given pattern, or extracting the portions that match. They are created
+with the <tt>/</tt><i>pat</i><tt>/</tt> and
+<tt>%r{</tt><i>pat</i><tt>}</tt> literals or the <tt>Regexp.new</tt>
+constructor.
+
+A regexp is usually delimited with forward slashes (<tt>/</tt>). For
+example:
+
+ /hay/ =~ 'haystack' #=> 0
+ /y/.match('haystack') #=> #<MatchData "y">
+
+If a string contains the pattern it is said to <i>match</i>. A literal
+string matches itself.
+
+Here 'haystack' does not contain the pattern 'needle', so it doesn't match:
+
+ /needle/.match('haystack') #=> nil
+
+Here 'haystack' contains the pattern 'hay', so it matches:
+
+ /hay/.match('haystack') #=> #<MatchData "hay">
+
+Specifically, <tt>/st/</tt> requires that the string contains the letter
+_s_ followed by the letter _t_, so it matches _haystack_, also.
+
+Note that any Regexp matching will raise a RuntimeError if timeout is set and
+exceeded. See {"Timeout"}[#label-Timeout] section in detail.
+
+== \Regexp Interpolation
+
+A regexp may contain interpolated strings; trivially:
+
+ foo = 'bar'
+ /#{foo}/ # => /bar/
+
+== <tt>=~</tt> and Regexp#match
+
+Pattern matching may be achieved by using <tt>=~</tt> operator or Regexp#match
+method.
+
+=== <tt>=~</tt> Operator
+
+<tt>=~</tt> is Ruby's basic pattern-matching operator. When one operand is a
+regular expression and the other is a string then the regular expression is
+used as a pattern to match against the string. (This operator is equivalently
+defined by Regexp and String so the order of String and Regexp do not matter.
+Other classes may have different implementations of <tt>=~</tt>.) If a match
+is found, the operator returns index of first match in string, otherwise it
+returns +nil+.
+
+ /hay/ =~ 'haystack' #=> 0
+ 'haystack' =~ /hay/ #=> 0
+ /a/ =~ 'haystack' #=> 1
+ /u/ =~ 'haystack' #=> nil
+
+Using <tt>=~</tt> operator with a String and Regexp the <tt>$~</tt> global
+variable is set after a successful match. <tt>$~</tt> holds a MatchData
+object. Regexp.last_match is equivalent to <tt>$~</tt>.
+
+=== Regexp#match Method
+
+The #match method returns a MatchData object:
+
+ /st/.match('haystack') #=> #<MatchData "st">
+
+== Metacharacters and Escapes
+
+The following are <i>metacharacters</i> <tt>(</tt>, <tt>)</tt>,
+<tt>[</tt>, <tt>]</tt>, <tt>{</tt>, <tt>}</tt>, <tt>.</tt>, <tt>?</tt>,
+<tt>+</tt>, <tt>*</tt>. They have a specific meaning when appearing in a
+pattern. To match them literally they must be backslash-escaped. To match
+a backslash literally, backslash-escape it: <tt>\\\\</tt>.
+
+ /1 \+ 2 = 3\?/.match('Does 1 + 2 = 3?') #=> #<MatchData "1 + 2 = 3?">
+ /a\\\\b/.match('a\\\\b') #=> #<MatchData "a\\b">
+
+Patterns behave like double-quoted strings and can contain the same
+backslash escapes (the meaning of <tt>\s</tt> is different, however,
+see below[#label-Character+Classes]).
+
+ /\s\u{6771 4eac 90fd}/.match("Go to æ±äº¬éƒ½")
+ #=> #<MatchData " æ±äº¬éƒ½">
+
+Arbitrary Ruby expressions can be embedded into patterns with the
+<tt>#{...}</tt> construct.
+
+ place = "æ±äº¬éƒ½"
+ /#{place}/.match("Go to æ±äº¬éƒ½")
+ #=> #<MatchData "æ±äº¬éƒ½">
+
+== Character Classes
+
+A <i>character class</i> is delimited with square brackets (<tt>[</tt>,
+<tt>]</tt>) and lists characters that may appear at that point in the
+match. <tt>/[ab]/</tt> means _a_ or _b_, as opposed to <tt>/ab/</tt> which
+means _a_ followed by _b_.
+
+ /W[aeiou]rd/.match("Word") #=> #<MatchData "Word">
+
+Within a character class the hyphen (<tt>-</tt>) is a metacharacter
+denoting an inclusive range of characters. <tt>[abcd]</tt> is equivalent
+to <tt>[a-d]</tt>. A range can be followed by another range, so
+<tt>[abcdwxyz]</tt> is equivalent to <tt>[a-dw-z]</tt>. The order in which
+ranges or individual characters appear inside a character class is
+irrelevant.
+
+ /[0-9a-f]/.match('9f') #=> #<MatchData "9">
+ /[9f]/.match('9f') #=> #<MatchData "9">
+
+If the first character of a character class is a caret (<tt>^</tt>) the
+class is inverted: it matches any character _except_ those named.
+
+ /[^a-eg-z]/.match('f') #=> #<MatchData "f">
+
+A character class may contain another character class. By itself this
+isn't useful because <tt>[a-z[0-9]]</tt> describes the same set as
+<tt>[a-z0-9]</tt>. However, character classes also support the <tt>&&</tt>
+operator which performs set intersection on its arguments. The two can be
+combined as follows:
+
+ /[a-w&&[^c-g]z]/ # ([a-w] AND ([^c-g] OR z))
+
+This is equivalent to:
+
+ /[abh-w]/
+
+The following metacharacters also behave like character classes:
+
+* <tt>/./</tt> - Any character except a newline.
+* <tt>/./m</tt> - Any character (the +m+ modifier enables multiline mode)
+* <tt>/\w/</tt> - A word character (<tt>[a-zA-Z0-9_]</tt>)
+* <tt>/\W/</tt> - A non-word character (<tt>[^a-zA-Z0-9_]</tt>).
+ Please take a look at {Bug #4044}[https://bugs.ruby-lang.org/issues/4044] if
+ using <tt>/\W/</tt> with the <tt>/i</tt> modifier.
+* <tt>/\d/</tt> - A digit character (<tt>[0-9]</tt>)
+* <tt>/\D/</tt> - A non-digit character (<tt>[^0-9]</tt>)
+* <tt>/\h/</tt> - A hexdigit character (<tt>[0-9a-fA-F]</tt>)
+* <tt>/\H/</tt> - A non-hexdigit character (<tt>[^0-9a-fA-F]</tt>)
+* <tt>/\s/</tt> - A whitespace character: <tt>/[ \t\r\n\f\v]/</tt>
+* <tt>/\S/</tt> - A non-whitespace character: <tt>/[^ \t\r\n\f\v]/</tt>
+* <tt>/\R/</tt> - A linebreak: <tt>\n</tt>, <tt>\v</tt>, <tt>\f</tt>, <tt>\r</tt>
+ <tt>\u0085</tt> (NEXT LINE), <tt>\u2028</tt> (LINE SEPARATOR), <tt>\u2029</tt> (PARAGRAPH SEPARATOR)
+ or <tt>\r\n</tt>.
+
+POSIX <i>bracket expressions</i> are also similar to character classes.
+They provide a portable alternative to the above, with the added benefit
+that they encompass non-ASCII characters. For instance, <tt>/\d/</tt>
+matches only the ASCII decimal digits (0-9); whereas <tt>/[[:digit:]]/</tt>
+matches any character in the Unicode _Nd_ category.
+
+* <tt>/[[:alnum:]]/</tt> - Alphabetic and numeric character
+* <tt>/[[:alpha:]]/</tt> - Alphabetic character
+* <tt>/[[:blank:]]/</tt> - Space or tab
+* <tt>/[[:cntrl:]]/</tt> - Control character
+* <tt>/[[:digit:]]/</tt> - Digit
+* <tt>/[[:graph:]]/</tt> - Non-blank character (excludes spaces, control
+ characters, and similar)
+* <tt>/[[:lower:]]/</tt> - Lowercase alphabetical character
+* <tt>/[[:print:]]/</tt> - Like [:graph:], but includes the space character
+* <tt>/[[:punct:]]/</tt> - Punctuation character
+* <tt>/[[:space:]]/</tt> - Whitespace character (<tt>[:blank:]</tt>, newline,
+ carriage return, etc.)
+* <tt>/[[:upper:]]/</tt> - Uppercase alphabetical
+* <tt>/[[:xdigit:]]/</tt> - Digit allowed in a hexadecimal number (i.e.,
+ 0-9a-fA-F)
+
+Ruby also supports the following non-POSIX character classes:
+
+* <tt>/[[:word:]]/</tt> - A character in one of the following Unicode
+ general categories _Letter_, _Mark_, _Number_,
+ <i>Connector_Punctuation</i>
+* <tt>/[[:ascii:]]/</tt> - A character in the ASCII character set
+
+ # U+06F2 is "EXTENDED ARABIC-INDIC DIGIT TWO"
+ /[[:digit:]]/.match("\u06F2") #=> #<MatchData "\u{06F2}">
+ /[[:upper:]][[:lower:]]/.match("Hello") #=> #<MatchData "He">
+ /[[:xdigit:]][[:xdigit:]]/.match("A6") #=> #<MatchData "A6">
+
+== Repetition
+
+The constructs described so far match a single character. They can be
+followed by a repetition metacharacter to specify how many times they need
+to occur. Such metacharacters are called <i>quantifiers</i>.
+
+* <tt>*</tt> - Zero or more times
+* <tt>+</tt> - One or more times
+* <tt>?</tt> - Zero or one times (optional)
+* <tt>{</tt><i>n</i><tt>}</tt> - Exactly <i>n</i> times
+* <tt>{</tt><i>n</i><tt>,}</tt> - <i>n</i> or more times
+* <tt>{,</tt><i>m</i><tt>}</tt> - <i>m</i> or less times
+* <tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}</tt> - At least <i>n</i> and
+ at most <i>m</i> times
+
+At least one uppercase character ('H'), at least one lowercase character
+('e'), two 'l' characters, then one 'o':
+
+ "Hello".match(/[[:upper:]]+[[:lower:]]+l{2}o/) #=> #<MatchData "Hello">
+
+=== Greedy Match
+
+Repetition is <i>greedy</i> by default: as many occurrences as possible
+are matched while still allowing the overall match to succeed. By
+contrast, <i>lazy</i> matching makes the minimal amount of matches
+necessary for overall success. Most greedy metacharacters can be made lazy
+by following them with <tt>?</tt>. For the <tt>{n}</tt> pattern, because
+it specifies an exact number of characters to match and not a variable
+number of characters, the <tt>?</tt> metacharacter instead makes the
+repeated pattern optional.
+
+Both patterns below match the string. The first uses a greedy quantifier so
+'.+' matches '<a><b>'; the second uses a lazy quantifier so '.+?' matches
+'<a>':
+
+ /<.+>/.match("<a><b>") #=> #<MatchData "<a><b>">
+ /<.+?>/.match("<a><b>") #=> #<MatchData "<a>">
+
+=== Possessive Match
+
+A quantifier followed by <tt>+</tt> matches <i>possessively</i>: once it
+has matched it does not backtrack. They behave like greedy quantifiers,
+but having matched they refuse to "give up" their match even if this
+jeopardises the overall match.
+
+ /<.*><.+>/.match("<a><b>") #=> #<MatchData "<a><b>">
+ /<.*+><.+>/.match("<a><b>") #=> nil
+ /<.*><.++>/.match("<a><b>") #=> nil
+
+== Capturing
+
+Parentheses can be used for <i>capturing</i>. The text enclosed by the
+<i>n</i>th group of parentheses can be subsequently referred to
+with <i>n</i>. Within a pattern use the <i>backreference</i>
+<tt>\n</tt> (e.g. <tt>\1</tt>); outside of the pattern use
+<tt>MatchData[n]</tt> (e.g. <tt>MatchData[1]</tt>).
+
+In this example, <tt>'at'</tt> is captured by the first group of
+parentheses, then referred to later with <tt>\1</tt>:
+
+ /[csh](..) [csh]\1 in/.match("The cat sat in the hat")
+ #=> #<MatchData "cat sat in" 1:"at">
+
+Regexp#match returns a MatchData object which makes the captured text
+available with its #[] method:
+
+ /[csh](..) [csh]\1 in/.match("The cat sat in the hat")[1] #=> 'at'
+
+While Ruby supports an arbitrary number of numbered captured groups,
+only groups 1-9 are supported using the <tt>\n</tt> backreference
+syntax.
+
+Ruby also supports <tt>\0</tt> as a special backreference, which
+references the entire matched string. This is also available at
+<tt>MatchData[0]</tt>. Note that the <tt>\0</tt> backreference cannot
+be used inside the regexp, as backreferences can only be used after the
+end of the capture group, and the <tt>\0</tt> backreference uses the
+implicit capture group of the entire match. However, you can use
+this backreference when doing substitution:
+
+ "The cat sat in the hat".gsub(/[csh]at/, '\0s')
+ # => "The cats sats in the hats"
+
+=== Named Captures
+
+Capture groups can be referred to by name when defined with the
+<tt>(?<</tt><i>name</i><tt>>)</tt> or <tt>(?'</tt><i>name</i><tt>')</tt>
+constructs.
+
+ /\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$3.67")
+ #=> #<MatchData "$3.67" dollars:"3" cents:"67">
+ /\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$3.67")[:dollars] #=> "3"
+
+Named groups can be backreferenced with <tt>\k<</tt><i>name</i><tt>></tt>,
+where _name_ is the group name.
+
+ /(?<vowel>[aeiou]).\k<vowel>.\k<vowel>/.match('ototomy')
+ #=> #<MatchData "ototo" vowel:"o">
+
+*Note*: A regexp can't use named backreferences and numbered
+backreferences simultaneously. Also, if a named capture is used in a
+regexp, then parentheses used for grouping which would otherwise result
+in a unnamed capture are treated as non-capturing.
+
+ /(\w)(\w)/.match("ab").captures # => ["a", "b"]
+ /(\w)(\w)/.match("ab").named_captures # => {}
+
+ /(?<c>\w)(\w)/.match("ab").captures # => ["a"]
+ /(?<c>\w)(\w)/.match("ab").named_captures # => {"c"=>"a"}
+
+When named capture groups are used with a literal regexp on the left-hand
+side of an expression and the <tt>=~</tt> operator, the captured text is
+also assigned to local variables with corresponding names.
+
+ /\$(?<dollars>\d+)\.(?<cents>\d+)/ =~ "$3.67" #=> 0
+ dollars #=> "3"
+
+== Grouping
+
+Parentheses also <i>group</i> the terms they enclose, allowing them to be
+quantified as one <i>atomic</i> whole.
+
+The pattern below matches a vowel followed by 2 word characters:
+
+ /[aeiou]\w{2}/.match("Caenorhabditis elegans") #=> #<MatchData "aen">
+
+Whereas the following pattern matches a vowel followed by a word character,
+twice, i.e. <tt>[aeiou]\w[aeiou]\w</tt>: 'enor'.
+
+ /([aeiou]\w){2}/.match("Caenorhabditis elegans")
+ #=> #<MatchData "enor" 1:"or">
+
+The <tt>(?:</tt>...<tt>)</tt> construct provides grouping without
+capturing. That is, it combines the terms it contains into an atomic whole
+without creating a backreference. This benefits performance at the slight
+expense of readability.
+
+The first group of parentheses captures 'n' and the second 'ti'. The second
+group is referred to later with the backreference <tt>\2</tt>:
+
+ /I(n)ves(ti)ga\2ons/.match("Investigations")
+ #=> #<MatchData "Investigations" 1:"n" 2:"ti">
+
+The first group of parentheses is now made non-capturing with '?:', so it
+still matches 'n', but doesn't create the backreference. Thus, the
+backreference <tt>\1</tt> now refers to 'ti'.
+
+ /I(?:n)ves(ti)ga\1ons/.match("Investigations")
+ #=> #<MatchData "Investigations" 1:"ti">
+
+=== Atomic Grouping
+
+Grouping can be made <i>atomic</i> with
+<tt>(?></tt><i>pat</i><tt>)</tt>. This causes the subexpression <i>pat</i>
+to be matched independently of the rest of the expression such that what
+it matches becomes fixed for the remainder of the match, unless the entire
+subexpression must be abandoned and subsequently revisited. In this
+way <i>pat</i> is treated as a non-divisible whole. Atomic grouping is
+typically used to optimise patterns so as to prevent the regular
+expression engine from backtracking needlessly.
+
+The <tt>"</tt> in the pattern below matches the first character of the string,
+then <tt>.*</tt> matches <i>Quote"</i>. This causes the overall match to fail,
+so the text matched by <tt>.*</tt> is backtracked by one position, which
+leaves the final character of the string available to match <tt>"</tt>
+
+ /".*"/.match('"Quote"') #=> #<MatchData "\"Quote\"">
+
+If <tt>.*</tt> is grouped atomically, it refuses to backtrack <i>Quote"</i>,
+even though this means that the overall match fails
+
+ /"(?>.*)"/.match('"Quote"') #=> nil
+
+== Subexpression Calls
+
+The <tt>\g<</tt><i>name</i><tt>></tt> syntax matches the previous
+subexpression named _name_, which can be a group name or number, again.
+This differs from backreferences in that it re-executes the group rather
+than simply trying to re-match the same text.
+
+This pattern matches a <i>(</i> character and assigns it to the <tt>paren</tt>
+group, tries to call that the <tt>paren</tt> sub-expression again but fails,
+then matches a literal <i>)</i>:
+
+ /\A(?<paren>\(\g<paren>*\))*\z/ =~ '()'
+
+
+ /\A(?<paren>\(\g<paren>*\))*\z/ =~ '(())' #=> 0
+ # ^1
+ # ^2
+ # ^3
+ # ^4
+ # ^5
+ # ^6
+ # ^7
+ # ^8
+ # ^9
+ # ^10
+
+1. Matches at the beginning of the string, i.e. before the first
+ character.
+2. Enters a named capture group called <tt>paren</tt>
+3. Matches a literal <i>(</i>, the first character in the string
+4. Calls the <tt>paren</tt> group again, i.e. recurses back to the
+ second step
+5. Re-enters the <tt>paren</tt> group
+6. Matches a literal <i>(</i>, the second character in the
+ string
+7. Try to call <tt>paren</tt> a third time, but fail because
+ doing so would prevent an overall successful match
+8. Match a literal <i>)</i>, the third character in the string.
+ Marks the end of the second recursive call
+9. Match a literal <i>)</i>, the fourth character in the string
+10. Match the end of the string
+
+== Alternation
+
+The vertical bar metacharacter (<tt>|</tt>) combines several expressions into
+a single one that matches any of the expressions. Each expression is an
+<i>alternative</i>.
+
+ /\w(and|or)\w/.match("Feliformia") #=> #<MatchData "form" 1:"or">
+ /\w(and|or)\w/.match("furandi") #=> #<MatchData "randi" 1:"and">
+ /\w(and|or)\w/.match("dissemblance") #=> nil
+
+== Character Properties
+
+The <tt>\p{}</tt> construct matches characters with the named property,
+much like POSIX bracket classes.
+
+* <tt>/\p{Alnum}/</tt> - Alphabetic and numeric character
+* <tt>/\p{Alpha}/</tt> - Alphabetic character
+* <tt>/\p{Blank}/</tt> - Space or tab
+* <tt>/\p{Cntrl}/</tt> - Control character
+* <tt>/\p{Digit}/</tt> - Digit
+* <tt>/\p{Emoji}/</tt> - Unicode emoji
+* <tt>/\p{Graph}/</tt> - Non-blank character (excludes spaces, control
+ characters, and similar)
+* <tt>/\p{Lower}/</tt> - Lowercase alphabetical character
+* <tt>/\p{Print}/</tt> - Like <tt>\p{Graph}</tt>, but includes the space character
+* <tt>/\p{Punct}/</tt> - Punctuation character
+* <tt>/\p{Space}/</tt> - Whitespace character (<tt>[:blank:]</tt>, newline,
+ carriage return, etc.)
+* <tt>/\p{Upper}/</tt> - Uppercase alphabetical
+* <tt>/\p{XDigit}/</tt> - Digit allowed in a hexadecimal number (i.e., 0-9a-fA-F)
+* <tt>/\p{Word}/</tt> - A member of one of the following Unicode general
+ category <i>Letter</i>, <i>Mark</i>, <i>Number</i>,
+ <i>Connector\_Punctuation</i>
+* <tt>/\p{ASCII}/</tt> - A character in the ASCII character set
+* <tt>/\p{Any}/</tt> - Any Unicode character (including unassigned
+ characters)
+* <tt>/\p{Assigned}/</tt> - An assigned character
+
+A Unicode character's <i>General Category</i> value can also be matched
+with <tt>\p{</tt><i>Ab</i><tt>}</tt> where <i>Ab</i> is the category's
+abbreviation as described below:
+
+* <tt>/\p{L}/</tt> - 'Letter'
+* <tt>/\p{Ll}/</tt> - 'Letter: Lowercase'
+* <tt>/\p{Lm}/</tt> - 'Letter: Mark'
+* <tt>/\p{Lo}/</tt> - 'Letter: Other'
+* <tt>/\p{Lt}/</tt> - 'Letter: Titlecase'
+* <tt>/\p{Lu}/</tt> - 'Letter: Uppercase
+* <tt>/\p{Lo}/</tt> - 'Letter: Other'
+* <tt>/\p{M}/</tt> - 'Mark'
+* <tt>/\p{Mn}/</tt> - 'Mark: Nonspacing'
+* <tt>/\p{Mc}/</tt> - 'Mark: Spacing Combining'
+* <tt>/\p{Me}/</tt> - 'Mark: Enclosing'
+* <tt>/\p{N}/</tt> - 'Number'
+* <tt>/\p{Nd}/</tt> - 'Number: Decimal Digit'
+* <tt>/\p{Nl}/</tt> - 'Number: Letter'
+* <tt>/\p{No}/</tt> - 'Number: Other'
+* <tt>/\p{P}/</tt> - 'Punctuation'
+* <tt>/\p{Pc}/</tt> - 'Punctuation: Connector'
+* <tt>/\p{Pd}/</tt> - 'Punctuation: Dash'
+* <tt>/\p{Ps}/</tt> - 'Punctuation: Open'
+* <tt>/\p{Pe}/</tt> - 'Punctuation: Close'
+* <tt>/\p{Pi}/</tt> - 'Punctuation: Initial Quote'
+* <tt>/\p{Pf}/</tt> - 'Punctuation: Final Quote'
+* <tt>/\p{Po}/</tt> - 'Punctuation: Other'
+* <tt>/\p{S}/</tt> - 'Symbol'
+* <tt>/\p{Sm}/</tt> - 'Symbol: Math'
+* <tt>/\p{Sc}/</tt> - 'Symbol: Currency'
+* <tt>/\p{Sc}/</tt> - 'Symbol: Currency'
+* <tt>/\p{Sk}/</tt> - 'Symbol: Modifier'
+* <tt>/\p{So}/</tt> - 'Symbol: Other'
+* <tt>/\p{Z}/</tt> - 'Separator'
+* <tt>/\p{Zs}/</tt> - 'Separator: Space'
+* <tt>/\p{Zl}/</tt> - 'Separator: Line'
+* <tt>/\p{Zp}/</tt> - 'Separator: Paragraph'
+* <tt>/\p{C}/</tt> - 'Other'
+* <tt>/\p{Cc}/</tt> - 'Other: Control'
+* <tt>/\p{Cf}/</tt> - 'Other: Format'
+* <tt>/\p{Cn}/</tt> - 'Other: Not Assigned'
+* <tt>/\p{Co}/</tt> - 'Other: Private Use'
+* <tt>/\p{Cs}/</tt> - 'Other: Surrogate'
+
+Lastly, <tt>\p{}</tt> matches a character's Unicode <i>script</i>. The
+following scripts are supported: <i>Arabic</i>, <i>Armenian</i>,
+<i>Balinese</i>, <i>Bengali</i>, <i>Bopomofo</i>, <i>Braille</i>,
+<i>Buginese</i>, <i>Buhid</i>, <i>Canadian_Aboriginal</i>, <i>Carian</i>,
+<i>Cham</i>, <i>Cherokee</i>, <i>Common</i>, <i>Coptic</i>,
+<i>Cuneiform</i>, <i>Cypriot</i>, <i>Cyrillic</i>, <i>Deseret</i>,
+<i>Devanagari</i>, <i>Ethiopic</i>, <i>Georgian</i>, <i>Glagolitic</i>,
+<i>Gothic</i>, <i>Greek</i>, <i>Gujarati</i>, <i>Gurmukhi</i>, <i>Han</i>,
+<i>Hangul</i>, <i>Hanunoo</i>, <i>Hebrew</i>, <i>Hiragana</i>,
+<i>Inherited</i>, <i>Kannada</i>, <i>Katakana</i>, <i>Kayah_Li</i>,
+<i>Kharoshthi</i>, <i>Khmer</i>, <i>Lao</i>, <i>Latin</i>, <i>Lepcha</i>,
+<i>Limbu</i>, <i>Linear_B</i>, <i>Lycian</i>, <i>Lydian</i>,
+<i>Malayalam</i>, <i>Mongolian</i>, <i>Myanmar</i>, <i>New_Tai_Lue</i>,
+<i>Nko</i>, <i>Ogham</i>, <i>Ol_Chiki</i>, <i>Old_Italic</i>,
+<i>Old_Persian</i>, <i>Oriya</i>, <i>Osmanya</i>, <i>Phags_Pa</i>,
+<i>Phoenician</i>, <i>Rejang</i>, <i>Runic</i>, <i>Saurashtra</i>,
+<i>Shavian</i>, <i>Sinhala</i>, <i>Sundanese</i>, <i>Syloti_Nagri</i>,
+<i>Syriac</i>, <i>Tagalog</i>, <i>Tagbanwa</i>, <i>Tai_Le</i>,
+<i>Tamil</i>, <i>Telugu</i>, <i>Thaana</i>, <i>Thai</i>, <i>Tibetan</i>,
+<i>Tifinagh</i>, <i>Ugaritic</i>, <i>Vai</i>, and <i>Yi</i>.
+
+Unicode codepoint U+06E9 is named "ARABIC PLACE OF SAJDAH" and belongs to the
+Arabic script:
+
+ /\p{Arabic}/.match("\u06E9") #=> #<MatchData "\u06E9">
+
+All character properties can be inverted by prefixing their name with a
+caret (<tt>^</tt>).
+
+Letter 'A' is not in the Unicode Ll (Letter; Lowercase) category, so this
+match succeeds:
+
+ /\p{^Ll}/.match("A") #=> #<MatchData "A">
+
+== Anchors
+
+Anchors are metacharacter that match the zero-width positions between
+characters, <i>anchoring</i> the match to a specific position.
+
+* <tt>^</tt> - Matches beginning of line
+* <tt>$</tt> - Matches end of line
+* <tt>\A</tt> - Matches beginning of string.
+* <tt>\Z</tt> - Matches end of string. If string ends with a newline,
+ it matches just before newline
+* <tt>\z</tt> - Matches end of string
+* <tt>\G</tt> - Matches first matching position:
+
+ In methods like <tt>String#gsub</tt> and <tt>String#scan</tt>, it changes on each iteration.
+ It initially matches the beginning of subject, and in each following iteration it matches where the last match finished.
+
+ " a b c".gsub(/ /, '_') #=> "____a_b_c"
+ " a b c".gsub(/\G /, '_') #=> "____a b c"
+
+ In methods like <tt>Regexp#match</tt> and <tt>String#match</tt> that take an (optional) offset, it matches where the search begins.
+
+ "hello, world".match(/,/, 3) #=> #<MatchData ",">
+ "hello, world".match(/\G,/, 3) #=> nil
+
+* <tt>\b</tt> - Matches word boundaries when outside brackets;
+ backspace (0x08) when inside brackets
+* <tt>\B</tt> - Matches non-word boundaries
+* <tt>(?=</tt><i>pat</i><tt>)</tt> - <i>Positive lookahead</i> assertion:
+ ensures that the following characters match <i>pat</i>, but doesn't
+ include those characters in the matched text
+* <tt>(?!</tt><i>pat</i><tt>)</tt> - <i>Negative lookahead</i> assertion:
+ ensures that the following characters do not match <i>pat</i>, but
+ doesn't include those characters in the matched text
+* <tt>(?<=</tt><i>pat</i><tt>)</tt> - <i>Positive lookbehind</i>
+ assertion: ensures that the preceding characters match <i>pat</i>, but
+ doesn't include those characters in the matched text
+* <tt>(?<!</tt><i>pat</i><tt>)</tt> - <i>Negative lookbehind</i>
+ assertion: ensures that the preceding characters do not match
+ <i>pat</i>, but doesn't include those characters in the matched text
+
+* <tt>\K</tt> - <i>Match reset</i>: the matched content preceding
+ <tt>\K</tt> in the regexp is excluded from the result. For example,
+ the following two regexps are almost equivalent:
+
+ /ab\Kc/ =~ "abc" #=> 0
+ /(?<=ab)c/ =~ "abc" #=> 2
+
+ These match same string and <i>$&</i> equals <tt>"c"</tt>, while the
+ matched position is different.
+
+ As are the following two regexps:
+
+ /(a)\K(b)\Kc/
+ /(?<=(?<=(a))(b))c/
+
+If a pattern isn't anchored it can begin at any point in the string:
+
+ /real/.match("surrealist") #=> #<MatchData "real">
+
+Anchoring the pattern to the beginning of the string forces the match to start
+there. 'real' doesn't occur at the beginning of the string, so now the match
+fails:
+
+ /\Areal/.match("surrealist") #=> nil
+
+The match below fails because although 'Demand' contains 'and', the pattern
+does not occur at a word boundary.
+
+ /\band/.match("Demand")
+
+Whereas in the following example 'and' has been anchored to a non-word
+boundary so instead of matching the first 'and' it matches from the fourth
+letter of 'demand' instead:
+
+ /\Band.+/.match("Supply and demand curve") #=> #<MatchData "and curve">
+
+The pattern below uses positive lookahead and positive lookbehind to match
+text appearing in <b></b> tags without including the tags in the match:
+
+ /(?<=<b>)\w+(?=<\/b>)/.match("Fortune favours the <b>bold</b>")
+ #=> #<MatchData "bold">
+
+== Options
+
+The end delimiter for a regexp can be followed by one or more single-letter
+options which control how the pattern can match.
+
+* <tt>/pat/i</tt> - Ignore case
+* <tt>/pat/m</tt> - Treat a newline as a character matched by <tt>.</tt>
+* <tt>/pat/x</tt> - Ignore whitespace and comments in the pattern
+* <tt>/pat/o</tt> - Perform <tt>#{}</tt> interpolation only once
+
+<tt>i</tt>, <tt>m</tt>, and <tt>x</tt> can also be applied on the
+subexpression level with the
+<tt>(?</tt><i>on</i><tt>-</tt><i>off</i><tt>)</tt> construct, which
+enables options <i>on</i>, and disables options <i>off</i> for the
+expression enclosed by the parentheses:
+
+ /a(?i:b)c/.match('aBc') #=> #<MatchData "aBc">
+ /a(?-i:b)c/i.match('ABC') #=> nil
+
+Additionally, these options can also be toggled for the remainder of the
+pattern:
+
+ /a(?i)bc/.match('abC') #=> #<MatchData "abC">
+
+Options may also be used with <tt>Regexp.new</tt>:
+
+ Regexp.new("abc", Regexp::IGNORECASE) #=> /abc/i
+ Regexp.new("abc", Regexp::MULTILINE) #=> /abc/m
+ Regexp.new("abc # Comment", Regexp::EXTENDED) #=> /abc # Comment/x
+ Regexp.new("abc", Regexp::IGNORECASE | Regexp::MULTILINE) #=> /abc/mi
+
+ Regexp.new("abc", "i") #=> /abc/i
+ Regexp.new("abc", "m") #=> /abc/m
+ Regexp.new("abc # Comment", "x") #=> /abc # Comment/x
+ Regexp.new("abc", "im") #=> /abc/mi
+
+== Free-Spacing Mode and Comments
+
+As mentioned above, the <tt>x</tt> option enables <i>free-spacing</i>
+mode. Literal white space inside the pattern is ignored, and the
+octothorpe (<tt>#</tt>) character introduces a comment until the end of
+the line. This allows the components of the pattern to be organized in a
+potentially more readable fashion.
+
+A contrived pattern to match a number with optional decimal places:
+
+ float_pat = /\A
+ [[:digit:]]+ # 1 or more digits before the decimal point
+ (\. # Decimal point
+ [[:digit:]]+ # 1 or more digits after the decimal point
+ )? # The decimal point and following digits are optional
+ \Z/x
+ float_pat.match('3.14') #=> #<MatchData "3.14" 1:".14">
+
+There are a number of strategies for matching whitespace:
+
+* Use a pattern such as <tt>\s</tt> or <tt>\p{Space}</tt>.
+* Use escaped whitespace such as <tt>\ </tt>, i.e. a space preceded by a backslash.
+* Use a character class such as <tt>[ ]</tt>.
+
+Comments can be included in a non-<tt>x</tt> pattern with the
+<tt>(?#</tt><i>comment</i><tt>)</tt> construct, where <i>comment</i> is
+arbitrary text ignored by the regexp engine.
+
+Comments in regexp literals cannot include unescaped terminator
+characters.
+
+== Encoding
+
+Regular expressions are assumed to use the source encoding. This can be
+overridden with one of the following modifiers.
+
+* <tt>/</tt><i>pat</i><tt>/u</tt> - UTF-8
+* <tt>/</tt><i>pat</i><tt>/e</tt> - EUC-JP
+* <tt>/</tt><i>pat</i><tt>/s</tt> - Windows-31J
+* <tt>/</tt><i>pat</i><tt>/n</tt> - ASCII-8BIT
+
+A regexp can be matched against a string when they either share an
+encoding, or the regexp's encoding is _US-ASCII_ and the string's encoding
+is ASCII-compatible.
+
+If a match between incompatible encodings is attempted an
+<tt>Encoding::CompatibilityError</tt> exception is raised.
+
+The <tt>Regexp#fixed_encoding?</tt> predicate indicates whether the regexp
+has a <i>fixed</i> encoding, that is one incompatible with ASCII. A
+regexp's encoding can be explicitly fixed by supplying
+<tt>Regexp::FIXEDENCODING</tt> as the second argument of
+<tt>Regexp.new</tt>:
+
+ r = Regexp.new("a".force_encoding("iso-8859-1"),Regexp::FIXEDENCODING)
+ r =~ "a\u3042"
+ # raises Encoding::CompatibilityError: incompatible encoding regexp match
+ # (ISO-8859-1 regexp with UTF-8 string)
+
+== \Regexp Global Variables
+
+Pattern matching sets some global variables :
+
+* <tt>$~</tt> is equivalent to Regexp.last_match;
+* <tt>$&</tt> contains the complete matched text;
+* <tt>$`</tt> contains string before match;
+* <tt>$'</tt> contains string after match;
+* <tt>$1</tt>, <tt>$2</tt> and so on contain text matching first, second, etc
+ capture group;
+* <tt>$+</tt> contains last capture group.
+
+Example:
+
+ m = /s(\w{2}).*(c)/.match('haystack') #=> #<MatchData "stac" 1:"ta" 2:"c">
+ $~ #=> #<MatchData "stac" 1:"ta" 2:"c">
+ Regexp.last_match #=> #<MatchData "stac" 1:"ta" 2:"c">
+
+ $& #=> "stac"
+ # same as m[0]
+ $` #=> "hay"
+ # same as m.pre_match
+ $' #=> "k"
+ # same as m.post_match
+ $1 #=> "ta"
+ # same as m[1]
+ $2 #=> "c"
+ # same as m[2]
+ $3 #=> nil
+ # no third group in pattern
+ $+ #=> "c"
+ # same as m[-1]
+
+These global variables are thread-local and method-local variables.
+
+== Performance
+
+Certain pathological combinations of constructs can lead to abysmally bad
+performance.
+
+Consider a string of 25 <i>a</i>s, a <i>d</i>, 4 <i>a</i>s, and a
+<i>c</i>.
+
+ s = 'a' * 25 + 'd' + 'a' * 4 + 'c'
+ #=> "aaaaaaaaaaaaaaaaaaaaaaaaadaaaac"
+
+The following patterns match instantly as you would expect:
+
+ /(b|a)/ =~ s #=> 0
+ /(b|a+)/ =~ s #=> 0
+ /(b|a+)*/ =~ s #=> 0
+
+However, the following pattern takes appreciably longer:
+
+ /(b|a+)*c/ =~ s #=> 26
+
+This happens because an atom in the regexp is quantified by both an
+immediate <tt>+</tt> and an enclosing <tt>*</tt> with nothing to
+differentiate which is in control of any particular character. The
+nondeterminism that results produces super-linear performance. (Consult
+<i>Mastering Regular Expressions</i> (3rd ed.), pp 222, by
+<i>Jeffery Friedl</i>, for an in-depth analysis). This particular case
+can be fixed by use of atomic grouping, which prevents the unnecessary
+backtracking:
+
+ (start = Time.now) && /(b|a+)*c/ =~ s && (Time.now - start)
+ #=> 24.702736882
+ (start = Time.now) && /(?>b|a+)*c/ =~ s && (Time.now - start)
+ #=> 0.000166571
+
+A similar case is typified by the following example, which takes
+approximately 60 seconds to execute for me:
+
+Match a string of 29 <i>a</i>s against a pattern of 29 optional <i>a</i>s
+followed by 29 mandatory <i>a</i>s:
+
+ Regexp.new('a?' * 29 + 'a' * 29) =~ 'a' * 29
+
+The 29 optional <i>a</i>s match the string, but this prevents the 29
+mandatory <i>a</i>s that follow from matching. Ruby must then backtrack
+repeatedly so as to satisfy as many of the optional matches as it can
+while still matching the mandatory 29. It is plain to us that none of the
+optional matches can succeed, but this fact unfortunately eludes Ruby.
+
+The best way to improve performance is to significantly reduce the amount of
+backtracking needed. For this case, instead of individually matching 29
+optional <i>a</i>s, a range of optional <i>a</i>s can be matched all at once
+with <i>a{0,29}</i>:
+
+ Regexp.new('a{0,29}' + 'a' * 29) =~ 'a' * 29
+
+== Timeout
+
+There are two APIs to set timeout. One is Regexp.timeout=, which is
+process-global configuration of timeout for Regexp matching.
+
+ Regexp.timeout = 3
+ s = 'a' * 25 + 'd' + 'a' * 4 + 'c'
+ /(b|a+)*c/ =~ s #=> This raises an exception in three seconds
+
+The other is timeout keyword of Regexp.new.
+
+ re = Regexp.new("(b|a+)*c", timeout: 3)
+ s = 'a' * 25 + 'd' + 'a' * 4 + 'c'
+ /(b|a+)*c/ =~ s #=> This raises an exception in three seconds
+
+When using Regexps to process untrusted input, you should use the timeout
+feature to avoid excessive backtracking. Otherwise, a malicious user can
+provide input to Regexp causing Denial-of-Service attack.
+Note that the timeout is not set by default because an appropriate limit
+highly depends on an application requirement and context.
diff --git a/doc/regexp/methods.rdoc b/doc/regexp/methods.rdoc
deleted file mode 100644
index 356156ac9a..0000000000
--- a/doc/regexp/methods.rdoc
+++ /dev/null
@@ -1,41 +0,0 @@
-== \Regexp Methods
-
-Each of these Ruby core methods can accept a regexp as an argument:
-
-- Enumerable#all?
-- Enumerable#any?
-- Enumerable#grep
-- Enumerable#grep_v
-- Enumerable#none?
-- Enumerable#one?
-- Enumerable#slice_after
-- Enumerable#slice_before
-- Regexp#=~
-- Regexp#match
-- Regexp#match?
-- Regexp.new
-- Regexp.union
-- String#=~
-- String#[]=
-- String#byteindex
-- String#byterindex
-- String#gsub
-- String#gsub!
-- String#index
-- String#match
-- String#match?
-- String#partition
-- String#rindex
-- String#rpartition
-- String#scan
-- String#slice
-- String#slice!
-- String#split
-- String#start_with?
-- String#sub
-- String#sub!
-- Symbol#=~
-- Symbol#match
-- Symbol#match?
-- Symbol#slice
-- Symbol#start_with?
diff --git a/doc/regexp/unicode_properties.rdoc b/doc/regexp/unicode_properties.rdoc
deleted file mode 100644
index a1d7ecc380..0000000000
--- a/doc/regexp/unicode_properties.rdoc
+++ /dev/null
@@ -1,678 +0,0 @@
-== \Regexps Based on Unicode Properties
-
-The properties shown here are those currently supported in Ruby.
-Older versions may not support all of these.
-
-=== POSIX brackets
-
-- <tt>\p{ASCII}</tt>
-- <tt>\p{Alnum}</tt>
-- <tt>\p{Alphabetic}</tt>, <tt>\p{Alpha}</tt>
-- <tt>\p{Blank}</tt>
-- <tt>\p{Cntrl}</tt>
-- <tt>\p{Digit}</tt>
-- <tt>\p{Graph}</tt>
-- <tt>\p{Lowercase}</tt>, <tt>\p{Lower}</tt>
-- <tt>\p{Print}</tt>
-- <tt>\p{Punct}</tt>
-- <tt>\p{Space}</tt>
-- <tt>\p{Uppercase}</tt>, <tt>\p{Upper}</tt>
-- <tt>\p{Word}</tt>
-- <tt>\p{XDigit}</tt>
-- <tt>\p{XPosixPunct}</tt>
-
-=== Special
-
-- <tt>\p{Any}</tt>
-- <tt>\p{Assigned}</tt>
-
-=== Major and General Categories
-
-- <tt>\p{Cased_Letter}</tt>, <tt>\p{LC}</tt>
-- <tt>\p{Close_Punctuation}</tt>, <tt>\p{Pe}</tt>
-- <tt>\p{Connector_Punctuation}</tt>, <tt>\p{Pc}</tt>
-- <tt>\p{Control}</tt>, <tt>\p{Cc}</tt>
-- <tt>\p{Currency_Symbol}</tt>, <tt>\p{Sc}</tt>
-- <tt>\p{Dash_Punctuation}</tt>, <tt>\p{Pd}</tt>
-- <tt>\p{Decimal_Number}</tt>, <tt>\p{Nd}</tt>
-- <tt>\p{Enclosing_Mark}</tt>, <tt>\p{Me}</tt>
-- <tt>\p{Final_Punctuation}</tt>, <tt>\p{Pf}</tt>
-- <tt>\p{Format}</tt>, <tt>\p{Cf}</tt>
-- <tt>\p{Initial_Punctuation}</tt>, <tt>\p{Pi}</tt>
-- <tt>\p{Letter}</tt>, <tt>\p{L}</tt>
-- <tt>\p{Letter_Number}</tt>, <tt>\p{Nl}</tt>
-- <tt>\p{Line_Separator}</tt>, <tt>\p{Zl}</tt>
-- <tt>\p{Lowercase_Letter}</tt>, <tt>\p{Ll}</tt>
-- <tt>\p{Mark}</tt>, <tt>\p{M}</tt>
-- <tt>\p{Math_Symbol}</tt>, <tt>\p{Sm}</tt>
-- <tt>\p{Modifier_Letter}</tt>, <tt>\p{Lm}</tt>
-- <tt>\p{Modifier_Symbol}</tt>, <tt>\p{Sk}</tt>
-- <tt>\p{Nonspacing_Mark}</tt>, <tt>\p{Mn}</tt>
-- <tt>\p{Number}</tt>, <tt>\p{N}</tt>
-- <tt>\p{Open_Punctuation}</tt>, <tt>\p{Ps}</tt>
-- <tt>\p{Other}</tt>, <tt>\p{C}</tt>
-- <tt>\p{Other_Letter}</tt>, <tt>\p{Lo}</tt>
-- <tt>\p{Other_Number}</tt>, <tt>\p{No}</tt>
-- <tt>\p{Other_Punctuation}</tt>, <tt>\p{Po}</tt>
-- <tt>\p{Other_Symbol}</tt>, <tt>\p{So}</tt>
-- <tt>\p{Paragraph_Separator}</tt>, <tt>\p{Zp}</tt>
-- <tt>\p{Private_Use}</tt>, <tt>\p{Co}</tt>
-- <tt>\p{Punctuation}</tt>, <tt>\p{P}</tt>
-- <tt>\p{Separator}</tt>, <tt>\p{Z}</tt>
-- <tt>\p{Space_Separator}</tt>, <tt>\p{Zs}</tt>
-- <tt>\p{Spacing_Mark}</tt>, <tt>\p{Mc}</tt>
-- <tt>\p{Surrogate}</tt>, <tt>\p{Cs}</tt>
-- <tt>\p{Symbol}</tt>, <tt>\p{S}</tt>
-- <tt>\p{Titlecase_Letter}</tt>, <tt>\p{Lt}</tt>
-- <tt>\p{Unassigned}</tt>, <tt>\p{Cn}</tt>
-- <tt>\p{Uppercase_Letter}</tt>, <tt>\p{Lu}</tt>
-
-=== Prop List
-
-- <tt>\p{ASCII_Hex_Digit}</tt>, <tt>\p{AHex}</tt>
-- <tt>\p{Bidi_Control}</tt>, <tt>\p{Bidi_C}</tt>
-- <tt>\p{Dash}</tt>
-- <tt>\p{Deprecated}</tt>, <tt>\p{Dep}</tt>
-- <tt>\p{Diacritic}</tt>, <tt>\p{Dia}</tt>
-- <tt>\p{Extender}</tt>, <tt>\p{Ext}</tt>
-- <tt>\p{Hex_Digit}</tt>, <tt>\p{Hex}</tt>
-- <tt>\p{Hyphen}</tt>
-- <tt>\p{IDS_Binary_Operator}</tt>, <tt>\p{IDSB}</tt>
-- <tt>\p{IDS_Trinary_Operator}</tt>, <tt>\p{IDST}</tt>
-- <tt>\p{Ideographic}</tt>, <tt>\p{Ideo}</tt>
-- <tt>\p{Join_Control}</tt>, <tt>\p{Join_C}</tt>
-- <tt>\p{Logical_Order_Exception}</tt>, <tt>\p{LOE}</tt>
-- <tt>\p{Noncharacter_Code_Point}</tt>, <tt>\p{NChar}</tt>
-- <tt>\p{Other_Alphabetic}</tt>, <tt>\p{OAlpha}</tt>
-- <tt>\p{Other_Default_Ignorable_Code_Point}</tt>, <tt>\p{ODI}</tt>
-- <tt>\p{Other_Grapheme_Extend}</tt>, <tt>\p{OGr_Ext}</tt>
-- <tt>\p{Other_ID_Continue}</tt>, <tt>\p{OIDC}</tt>
-- <tt>\p{Other_ID_Start}</tt>, <tt>\p{OIDS}</tt>
-- <tt>\p{Other_Lowercase}</tt>, <tt>\p{OLower}</tt>
-- <tt>\p{Other_Math}</tt>, <tt>\p{OMath}</tt>
-- <tt>\p{Other_Uppercase}</tt>, <tt>\p{OUpper}</tt>
-- <tt>\p{Pattern_Syntax}</tt>, <tt>\p{Pat_Syn}</tt>
-- <tt>\p{Pattern_White_Space}</tt>, <tt>\p{Pat_WS}</tt>
-- <tt>\p{Prepended_Concatenation_Mark}</tt>, <tt>\p{PCM}</tt>
-- <tt>\p{Quotation_Mark}</tt>, <tt>\p{QMark}</tt>
-- <tt>\p{Radical}</tt>
-- <tt>\p{Regional_Indicator}</tt>, <tt>\p{RI}</tt>
-- <tt>\p{Sentence_Terminal}</tt>, <tt>\p{STerm}</tt>
-- <tt>\p{Soft_Dotted}</tt>, <tt>\p{SD}</tt>
-- <tt>\p{Terminal_Punctuation}</tt>, <tt>\p{Term}</tt>
-- <tt>\p{Unified_Ideograph}</tt>, <tt>\p{UIdeo}</tt>
-- <tt>\p{Variation_Selector}</tt>, <tt>\p{VS}</tt>
-- <tt>\p{White_Space}</tt>, <tt>\p{WSpace}</tt>
-
-=== Derived Core Properties
-
-- <tt>\p{Alphabetic}</tt>, <tt>\p{Alpha}</tt>
-- <tt>\p{Case_Ignorable}</tt>, <tt>\p{CI}</tt>
-- <tt>\p{Cased}</tt>
-- <tt>\p{Changes_When_Casefolded}</tt>, <tt>\p{CWCF}</tt>
-- <tt>\p{Changes_When_Casemapped}</tt>, <tt>\p{CWCM}</tt>
-- <tt>\p{Changes_When_Lowercased}</tt>, <tt>\p{CWL}</tt>
-- <tt>\p{Changes_When_Titlecased}</tt>, <tt>\p{CWT}</tt>
-- <tt>\p{Changes_When_Uppercased}</tt>, <tt>\p{CWU}</tt>
-- <tt>\p{Default_Ignorable_Code_Point}</tt>, <tt>\p{DI}</tt>
-- <tt>\p{Grapheme_Base}</tt>, <tt>\p{Gr_Base}</tt>
-- <tt>\p{Grapheme_Extend}</tt>, <tt>\p{Gr_Ext}</tt>
-- <tt>\p{Grapheme_Link}</tt>, <tt>\p{Gr_Link}</tt>
-- <tt>\p{ID_Continue}</tt>, <tt>\p{IDC}</tt>
-- <tt>\p{ID_Start}</tt>, <tt>\p{IDS}</tt>
-- <tt>\p{Lowercase}</tt>, <tt>\p{Lower}</tt>
-- <tt>\p{Math}</tt>
-- <tt>\p{Uppercase}</tt>, <tt>\p{Upper}</tt>
-- <tt>\p{XID_Continue}</tt>, <tt>\p{XIDC}</tt>
-- <tt>\p{XID_Start}</tt>, <tt>\p{XIDS}</tt>
-
-=== Scripts
-
-- <tt>\p{Adlam}</tt>, <tt>\p{Adlm}</tt>
-- <tt>\p{Ahom}</tt>
-- <tt>\p{Anatolian_Hieroglyphs}</tt>, <tt>\p{Hluw}</tt>
-- <tt>\p{Arabic}</tt>, <tt>\p{Arab}</tt>
-- <tt>\p{Armenian}</tt>, <tt>\p{Armn}</tt>
-- <tt>\p{Avestan}</tt>, <tt>\p{Avst}</tt>
-- <tt>\p{Balinese}</tt>, <tt>\p{Bali}</tt>
-- <tt>\p{Bamum}</tt>, <tt>\p{Bamu}</tt>
-- <tt>\p{Bassa_Vah}</tt>, <tt>\p{Bass}</tt>
-- <tt>\p{Batak}</tt>, <tt>\p{Batk}</tt>
-- <tt>\p{Bengali}</tt>, <tt>\p{Beng}</tt>
-- <tt>\p{Bhaiksuki}</tt>, <tt>\p{Bhks}</tt>
-- <tt>\p{Bopomofo}</tt>, <tt>\p{Bopo}</tt>
-- <tt>\p{Brahmi}</tt>, <tt>\p{Brah}</tt>
-- <tt>\p{Braille}</tt>, <tt>\p{Brai}</tt>
-- <tt>\p{Buginese}</tt>, <tt>\p{Bugi}</tt>
-- <tt>\p{Buhid}</tt>, <tt>\p{Buhd}</tt>
-- <tt>\p{Canadian_Aboriginal}</tt>, <tt>\p{Cans}</tt>
-- <tt>\p{Carian}</tt>, <tt>\p{Cari}</tt>
-- <tt>\p{Caucasian_Albanian}</tt>, <tt>\p{Aghb}</tt>
-- <tt>\p{Chakma}</tt>, <tt>\p{Cakm}</tt>
-- <tt>\p{Cham}</tt>
-- <tt>\p{Cherokee}</tt>, <tt>\p{Cher}</tt>
-- <tt>\p{Chorasmian}</tt>, <tt>\p{Chrs}</tt>
-- <tt>\p{Common}</tt>, <tt>\p{Zyyy}</tt>
-- <tt>\p{Coptic}</tt>, <tt>\p{Copt}</tt>
-- <tt>\p{Cuneiform}</tt>, <tt>\p{Xsux}</tt>
-- <tt>\p{Cypriot}</tt>, <tt>\p{Cprt}</tt>
-- <tt>\p{Cypro_Minoan}</tt>, <tt>\p{Cpmn}</tt>
-- <tt>\p{Cyrillic}</tt>, <tt>\p{Cyrl}</tt>
-- <tt>\p{Deseret}</tt>, <tt>\p{Dsrt}</tt>
-- <tt>\p{Devanagari}</tt>, <tt>\p{Deva}</tt>
-- <tt>\p{Dives_Akuru}</tt>, <tt>\p{Diak}</tt>
-- <tt>\p{Dogra}</tt>, <tt>\p{Dogr}</tt>
-- <tt>\p{Duployan}</tt>, <tt>\p{Dupl}</tt>
-- <tt>\p{Egyptian_Hieroglyphs}</tt>, <tt>\p{Egyp}</tt>
-- <tt>\p{Elbasan}</tt>, <tt>\p{Elba}</tt>
-- <tt>\p{Elymaic}</tt>, <tt>\p{Elym}</tt>
-- <tt>\p{Ethiopic}</tt>, <tt>\p{Ethi}</tt>
-- <tt>\p{Georgian}</tt>, <tt>\p{Geor}</tt>
-- <tt>\p{Glagolitic}</tt>, <tt>\p{Glag}</tt>
-- <tt>\p{Gothic}</tt>, <tt>\p{Goth}</tt>
-- <tt>\p{Grantha}</tt>, <tt>\p{Gran}</tt>
-- <tt>\p{Greek}</tt>, <tt>\p{Grek}</tt>
-- <tt>\p{Gujarati}</tt>, <tt>\p{Gujr}</tt>
-- <tt>\p{Gunjala_Gondi}</tt>, <tt>\p{Gong}</tt>
-- <tt>\p{Gurmukhi}</tt>, <tt>\p{Guru}</tt>
-- <tt>\p{Han}</tt>, <tt>\p{Hani}</tt>
-- <tt>\p{Hangul}</tt>, <tt>\p{Hang}</tt>
-- <tt>\p{Hanifi_Rohingya}</tt>, <tt>\p{Rohg}</tt>
-- <tt>\p{Hanunoo}</tt>, <tt>\p{Hano}</tt>
-- <tt>\p{Hatran}</tt>, <tt>\p{Hatr}</tt>
-- <tt>\p{Hebrew}</tt>, <tt>\p{Hebr}</tt>
-- <tt>\p{Hiragana}</tt>, <tt>\p{Hira}</tt>
-- <tt>\p{Imperial_Aramaic}</tt>, <tt>\p{Armi}</tt>
-- <tt>\p{Inherited}</tt>, <tt>\p{Zinh}</tt>
-- <tt>\p{Inscriptional_Pahlavi}</tt>, <tt>\p{Phli}</tt>
-- <tt>\p{Inscriptional_Parthian}</tt>, <tt>\p{Prti}</tt>
-- <tt>\p{Javanese}</tt>, <tt>\p{Java}</tt>
-- <tt>\p{Kaithi}</tt>, <tt>\p{Kthi}</tt>
-- <tt>\p{Kannada}</tt>, <tt>\p{Knda}</tt>
-- <tt>\p{Katakana}</tt>, <tt>\p{Kana}</tt>
-- <tt>\p{Kawi}</tt>
-- <tt>\p{Kayah_Li}</tt>, <tt>\p{Kali}</tt>
-- <tt>\p{Kharoshthi}</tt>, <tt>\p{Khar}</tt>
-- <tt>\p{Khitan_Small_Script}</tt>, <tt>\p{Kits}</tt>
-- <tt>\p{Khmer}</tt>, <tt>\p{Khmr}</tt>
-- <tt>\p{Khojki}</tt>, <tt>\p{Khoj}</tt>
-- <tt>\p{Khudawadi}</tt>, <tt>\p{Sind}</tt>
-- <tt>\p{Lao}</tt>, <tt>\p{Laoo}</tt>
-- <tt>\p{Latin}</tt>, <tt>\p{Latn}</tt>
-- <tt>\p{Lepcha}</tt>, <tt>\p{Lepc}</tt>
-- <tt>\p{Limbu}</tt>, <tt>\p{Limb}</tt>
-- <tt>\p{Linear_A}</tt>, <tt>\p{Lina}</tt>
-- <tt>\p{Linear_B}</tt>, <tt>\p{Linb}</tt>
-- <tt>\p{Lisu}</tt>
-- <tt>\p{Lycian}</tt>, <tt>\p{Lyci}</tt>
-- <tt>\p{Lydian}</tt>, <tt>\p{Lydi}</tt>
-- <tt>\p{Mahajani}</tt>, <tt>\p{Mahj}</tt>
-- <tt>\p{Makasar}</tt>, <tt>\p{Maka}</tt>
-- <tt>\p{Malayalam}</tt>, <tt>\p{Mlym}</tt>
-- <tt>\p{Mandaic}</tt>, <tt>\p{Mand}</tt>
-- <tt>\p{Manichaean}</tt>, <tt>\p{Mani}</tt>
-- <tt>\p{Marchen}</tt>, <tt>\p{Marc}</tt>
-- <tt>\p{Masaram_Gondi}</tt>, <tt>\p{Gonm}</tt>
-- <tt>\p{Medefaidrin}</tt>, <tt>\p{Medf}</tt>
-- <tt>\p{Meetei_Mayek}</tt>, <tt>\p{Mtei}</tt>
-- <tt>\p{Mende_Kikakui}</tt>, <tt>\p{Mend}</tt>
-- <tt>\p{Meroitic_Cursive}</tt>, <tt>\p{Merc}</tt>
-- <tt>\p{Meroitic_Hieroglyphs}</tt>, <tt>\p{Mero}</tt>
-- <tt>\p{Miao}</tt>, <tt>\p{Plrd}</tt>
-- <tt>\p{Modi}</tt>
-- <tt>\p{Mongolian}</tt>, <tt>\p{Mong}</tt>
-- <tt>\p{Mro}</tt>, <tt>\p{Mroo}</tt>
-- <tt>\p{Multani}</tt>, <tt>\p{Mult}</tt>
-- <tt>\p{Myanmar}</tt>, <tt>\p{Mymr}</tt>
-- <tt>\p{Nabataean}</tt>, <tt>\p{Nbat}</tt>
-- <tt>\p{Nag_Mundari}</tt>, <tt>\p{Nagm}</tt>
-- <tt>\p{Nandinagari}</tt>, <tt>\p{Nand}</tt>
-- <tt>\p{New_Tai_Lue}</tt>, <tt>\p{Talu}</tt>
-- <tt>\p{Newa}</tt>
-- <tt>\p{Nko}</tt>, <tt>\p{Nkoo}</tt>
-- <tt>\p{Nushu}</tt>, <tt>\p{Nshu}</tt>
-- <tt>\p{Nyiakeng_Puachue_Hmong}</tt>, <tt>\p{Hmnp}</tt>
-- <tt>\p{Ogham}</tt>, <tt>\p{Ogam}</tt>
-- <tt>\p{Ol_Chiki}</tt>, <tt>\p{Olck}</tt>
-- <tt>\p{Old_Hungarian}</tt>, <tt>\p{Hung}</tt>
-- <tt>\p{Old_Italic}</tt>, <tt>\p{Ital}</tt>
-- <tt>\p{Old_North_Arabian}</tt>, <tt>\p{Narb}</tt>
-- <tt>\p{Old_Permic}</tt>, <tt>\p{Perm}</tt>
-- <tt>\p{Old_Persian}</tt>, <tt>\p{Xpeo}</tt>
-- <tt>\p{Old_Sogdian}</tt>, <tt>\p{Sogo}</tt>
-- <tt>\p{Old_South_Arabian}</tt>, <tt>\p{Sarb}</tt>
-- <tt>\p{Old_Turkic}</tt>, <tt>\p{Orkh}</tt>
-- <tt>\p{Old_Uyghur}</tt>, <tt>\p{Ougr}</tt>
-- <tt>\p{Oriya}</tt>, <tt>\p{Orya}</tt>
-- <tt>\p{Osage}</tt>, <tt>\p{Osge}</tt>
-- <tt>\p{Osmanya}</tt>, <tt>\p{Osma}</tt>
-- <tt>\p{Pahawh_Hmong}</tt>, <tt>\p{Hmng}</tt>
-- <tt>\p{Palmyrene}</tt>, <tt>\p{Palm}</tt>
-- <tt>\p{Pau_Cin_Hau}</tt>, <tt>\p{Pauc}</tt>
-- <tt>\p{Phags_Pa}</tt>, <tt>\p{Phag}</tt>
-- <tt>\p{Phoenician}</tt>, <tt>\p{Phnx}</tt>
-- <tt>\p{Psalter_Pahlavi}</tt>, <tt>\p{Phlp}</tt>
-- <tt>\p{Rejang}</tt>, <tt>\p{Rjng}</tt>
-- <tt>\p{Runic}</tt>, <tt>\p{Runr}</tt>
-- <tt>\p{Samaritan}</tt>, <tt>\p{Samr}</tt>
-- <tt>\p{Saurashtra}</tt>, <tt>\p{Saur}</tt>
-- <tt>\p{Sharada}</tt>, <tt>\p{Shrd}</tt>
-- <tt>\p{Shavian}</tt>, <tt>\p{Shaw}</tt>
-- <tt>\p{Siddham}</tt>, <tt>\p{Sidd}</tt>
-- <tt>\p{SignWriting}</tt>, <tt>\p{Sgnw}</tt>
-- <tt>\p{Sinhala}</tt>, <tt>\p{Sinh}</tt>
-- <tt>\p{Sogdian}</tt>, <tt>\p{Sogd}</tt>
-- <tt>\p{Sora_Sompeng}</tt>, <tt>\p{Sora}</tt>
-- <tt>\p{Soyombo}</tt>, <tt>\p{Soyo}</tt>
-- <tt>\p{Sundanese}</tt>, <tt>\p{Sund}</tt>
-- <tt>\p{Syloti_Nagri}</tt>, <tt>\p{Sylo}</tt>
-- <tt>\p{Syriac}</tt>, <tt>\p{Syrc}</tt>
-- <tt>\p{Tagalog}</tt>, <tt>\p{Tglg}</tt>
-- <tt>\p{Tagbanwa}</tt>, <tt>\p{Tagb}</tt>
-- <tt>\p{Tai_Le}</tt>, <tt>\p{Tale}</tt>
-- <tt>\p{Tai_Tham}</tt>, <tt>\p{Lana}</tt>
-- <tt>\p{Tai_Viet}</tt>, <tt>\p{Tavt}</tt>
-- <tt>\p{Takri}</tt>, <tt>\p{Takr}</tt>
-- <tt>\p{Tamil}</tt>, <tt>\p{Taml}</tt>
-- <tt>\p{Tangsa}</tt>, <tt>\p{Tnsa}</tt>
-- <tt>\p{Tangut}</tt>, <tt>\p{Tang}</tt>
-- <tt>\p{Telugu}</tt>, <tt>\p{Telu}</tt>
-- <tt>\p{Thaana}</tt>, <tt>\p{Thaa}</tt>
-- <tt>\p{Thai}</tt>
-- <tt>\p{Tibetan}</tt>, <tt>\p{Tibt}</tt>
-- <tt>\p{Tifinagh}</tt>, <tt>\p{Tfng}</tt>
-- <tt>\p{Tirhuta}</tt>, <tt>\p{Tirh}</tt>
-- <tt>\p{Toto}</tt>
-- <tt>\p{Ugaritic}</tt>, <tt>\p{Ugar}</tt>
-- <tt>\p{Unknown}</tt>, <tt>\p{Zzzz}</tt>
-- <tt>\p{Vai}</tt>, <tt>\p{Vaii}</tt>
-- <tt>\p{Vithkuqi}</tt>, <tt>\p{Vith}</tt>
-- <tt>\p{Wancho}</tt>, <tt>\p{Wcho}</tt>
-- <tt>\p{Warang_Citi}</tt>, <tt>\p{Wara}</tt>
-- <tt>\p{Yezidi}</tt>, <tt>\p{Yezi}</tt>
-- <tt>\p{Yi}</tt>, <tt>\p{Yiii}</tt>
-- <tt>\p{Zanabazar_Square}</tt>, <tt>\p{Zanb}</tt>
-
-=== Blocks
-
-- <tt>\p{In_Adlam}</tt>
-- <tt>\p{In_Aegean_Numbers}</tt>
-- <tt>\p{In_Ahom}</tt>
-- <tt>\p{In_Alchemical_Symbols}</tt>
-- <tt>\p{In_Alphabetic_Presentation_Forms}</tt>
-- <tt>\p{In_Anatolian_Hieroglyphs}</tt>
-- <tt>\p{In_Ancient_Greek_Musical_Notation}</tt>
-- <tt>\p{In_Ancient_Greek_Numbers}</tt>
-- <tt>\p{In_Ancient_Symbols}</tt>
-- <tt>\p{In_Arabic}</tt>
-- <tt>\p{In_Arabic_Extended_A}</tt>
-- <tt>\p{In_Arabic_Extended_B}</tt>
-- <tt>\p{In_Arabic_Extended_C}</tt>
-- <tt>\p{In_Arabic_Mathematical_Alphabetic_Symbols}</tt>
-- <tt>\p{In_Arabic_Presentation_Forms_A}</tt>
-- <tt>\p{In_Arabic_Presentation_Forms_B}</tt>
-- <tt>\p{In_Arabic_Supplement}</tt>
-- <tt>\p{In_Armenian}</tt>
-- <tt>\p{In_Arrows}</tt>
-- <tt>\p{In_Avestan}</tt>
-- <tt>\p{In_Balinese}</tt>
-- <tt>\p{In_Bamum}</tt>
-- <tt>\p{In_Bamum_Supplement}</tt>
-- <tt>\p{In_Basic_Latin}</tt>
-- <tt>\p{In_Bassa_Vah}</tt>
-- <tt>\p{In_Batak}</tt>
-- <tt>\p{In_Bengali}</tt>
-- <tt>\p{In_Bhaiksuki}</tt>
-- <tt>\p{In_Block_Elements}</tt>
-- <tt>\p{In_Bopomofo}</tt>
-- <tt>\p{In_Bopomofo_Extended}</tt>
-- <tt>\p{In_Box_Drawing}</tt>
-- <tt>\p{In_Brahmi}</tt>
-- <tt>\p{In_Braille_Patterns}</tt>
-- <tt>\p{In_Buginese}</tt>
-- <tt>\p{In_Buhid}</tt>
-- <tt>\p{In_Byzantine_Musical_Symbols}</tt>
-- <tt>\p{In_CJK_Compatibility}</tt>
-- <tt>\p{In_CJK_Compatibility_Forms}</tt>
-- <tt>\p{In_CJK_Compatibility_Ideographs}</tt>
-- <tt>\p{In_CJK_Compatibility_Ideographs_Supplement}</tt>
-- <tt>\p{In_CJK_Radicals_Supplement}</tt>
-- <tt>\p{In_CJK_Strokes}</tt>
-- <tt>\p{In_CJK_Symbols_and_Punctuation}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_A}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_B}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_C}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_D}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_E}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_F}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_G}</tt>
-- <tt>\p{In_CJK_Unified_Ideographs_Extension_H}</tt>
-- <tt>\p{In_Carian}</tt>
-- <tt>\p{In_Caucasian_Albanian}</tt>
-- <tt>\p{In_Chakma}</tt>
-- <tt>\p{In_Cham}</tt>
-- <tt>\p{In_Cherokee}</tt>
-- <tt>\p{In_Cherokee_Supplement}</tt>
-- <tt>\p{In_Chess_Symbols}</tt>
-- <tt>\p{In_Chorasmian}</tt>
-- <tt>\p{In_Combining_Diacritical_Marks}</tt>
-- <tt>\p{In_Combining_Diacritical_Marks_Extended}</tt>
-- <tt>\p{In_Combining_Diacritical_Marks_Supplement}</tt>
-- <tt>\p{In_Combining_Diacritical_Marks_for_Symbols}</tt>
-- <tt>\p{In_Combining_Half_Marks}</tt>
-- <tt>\p{In_Common_Indic_Number_Forms}</tt>
-- <tt>\p{In_Control_Pictures}</tt>
-- <tt>\p{In_Coptic}</tt>
-- <tt>\p{In_Coptic_Epact_Numbers}</tt>
-- <tt>\p{In_Counting_Rod_Numerals}</tt>
-- <tt>\p{In_Cuneiform}</tt>
-- <tt>\p{In_Cuneiform_Numbers_and_Punctuation}</tt>
-- <tt>\p{In_Currency_Symbols}</tt>
-- <tt>\p{In_Cypriot_Syllabary}</tt>
-- <tt>\p{In_Cypro_Minoan}</tt>
-- <tt>\p{In_Cyrillic}</tt>
-- <tt>\p{In_Cyrillic_Extended_A}</tt>
-- <tt>\p{In_Cyrillic_Extended_B}</tt>
-- <tt>\p{In_Cyrillic_Extended_C}</tt>
-- <tt>\p{In_Cyrillic_Extended_D}</tt>
-- <tt>\p{In_Cyrillic_Supplement}</tt>
-- <tt>\p{In_Deseret}</tt>
-- <tt>\p{In_Devanagari}</tt>
-- <tt>\p{In_Devanagari_Extended}</tt>
-- <tt>\p{In_Devanagari_Extended_A}</tt>
-- <tt>\p{In_Dingbats}</tt>
-- <tt>\p{In_Dives_Akuru}</tt>
-- <tt>\p{In_Dogra}</tt>
-- <tt>\p{In_Domino_Tiles}</tt>
-- <tt>\p{In_Duployan}</tt>
-- <tt>\p{In_Early_Dynastic_Cuneiform}</tt>
-- <tt>\p{In_Egyptian_Hieroglyph_Format_Controls}</tt>
-- <tt>\p{In_Egyptian_Hieroglyphs}</tt>
-- <tt>\p{In_Elbasan}</tt>
-- <tt>\p{In_Elymaic}</tt>
-- <tt>\p{In_Emoticons}</tt>
-- <tt>\p{In_Enclosed_Alphanumeric_Supplement}</tt>
-- <tt>\p{In_Enclosed_Alphanumerics}</tt>
-- <tt>\p{In_Enclosed_CJK_Letters_and_Months}</tt>
-- <tt>\p{In_Enclosed_Ideographic_Supplement}</tt>
-- <tt>\p{In_Ethiopic}</tt>
-- <tt>\p{In_Ethiopic_Extended}</tt>
-- <tt>\p{In_Ethiopic_Extended_A}</tt>
-- <tt>\p{In_Ethiopic_Extended_B}</tt>
-- <tt>\p{In_Ethiopic_Supplement}</tt>
-- <tt>\p{In_General_Punctuation}</tt>
-- <tt>\p{In_Geometric_Shapes}</tt>
-- <tt>\p{In_Geometric_Shapes_Extended}</tt>
-- <tt>\p{In_Georgian}</tt>
-- <tt>\p{In_Georgian_Extended}</tt>
-- <tt>\p{In_Georgian_Supplement}</tt>
-- <tt>\p{In_Glagolitic}</tt>
-- <tt>\p{In_Glagolitic_Supplement}</tt>
-- <tt>\p{In_Gothic}</tt>
-- <tt>\p{In_Grantha}</tt>
-- <tt>\p{In_Greek_Extended}</tt>
-- <tt>\p{In_Greek_and_Coptic}</tt>
-- <tt>\p{In_Gujarati}</tt>
-- <tt>\p{In_Gunjala_Gondi}</tt>
-- <tt>\p{In_Gurmukhi}</tt>
-- <tt>\p{In_Halfwidth_and_Fullwidth_Forms}</tt>
-- <tt>\p{In_Hangul_Compatibility_Jamo}</tt>
-- <tt>\p{In_Hangul_Jamo}</tt>
-- <tt>\p{In_Hangul_Jamo_Extended_A}</tt>
-- <tt>\p{In_Hangul_Jamo_Extended_B}</tt>
-- <tt>\p{In_Hangul_Syllables}</tt>
-- <tt>\p{In_Hanifi_Rohingya}</tt>
-- <tt>\p{In_Hanunoo}</tt>
-- <tt>\p{In_Hatran}</tt>
-- <tt>\p{In_Hebrew}</tt>
-- <tt>\p{In_High_Private_Use_Surrogates}</tt>
-- <tt>\p{In_High_Surrogates}</tt>
-- <tt>\p{In_Hiragana}</tt>
-- <tt>\p{In_IPA_Extensions}</tt>
-- <tt>\p{In_Ideographic_Description_Characters}</tt>
-- <tt>\p{In_Ideographic_Symbols_and_Punctuation}</tt>
-- <tt>\p{In_Imperial_Aramaic}</tt>
-- <tt>\p{In_Indic_Siyaq_Numbers}</tt>
-- <tt>\p{In_Inscriptional_Pahlavi}</tt>
-- <tt>\p{In_Inscriptional_Parthian}</tt>
-- <tt>\p{In_Javanese}</tt>
-- <tt>\p{In_Kaithi}</tt>
-- <tt>\p{In_Kaktovik_Numerals}</tt>
-- <tt>\p{In_Kana_Extended_A}</tt>
-- <tt>\p{In_Kana_Extended_B}</tt>
-- <tt>\p{In_Kana_Supplement}</tt>
-- <tt>\p{In_Kanbun}</tt>
-- <tt>\p{In_Kangxi_Radicals}</tt>
-- <tt>\p{In_Kannada}</tt>
-- <tt>\p{In_Katakana}</tt>
-- <tt>\p{In_Katakana_Phonetic_Extensions}</tt>
-- <tt>\p{In_Kawi}</tt>
-- <tt>\p{In_Kayah_Li}</tt>
-- <tt>\p{In_Kharoshthi}</tt>
-- <tt>\p{In_Khitan_Small_Script}</tt>
-- <tt>\p{In_Khmer}</tt>
-- <tt>\p{In_Khmer_Symbols}</tt>
-- <tt>\p{In_Khojki}</tt>
-- <tt>\p{In_Khudawadi}</tt>
-- <tt>\p{In_Lao}</tt>
-- <tt>\p{In_Latin_1_Supplement}</tt>
-- <tt>\p{In_Latin_Extended_A}</tt>
-- <tt>\p{In_Latin_Extended_Additional}</tt>
-- <tt>\p{In_Latin_Extended_B}</tt>
-- <tt>\p{In_Latin_Extended_C}</tt>
-- <tt>\p{In_Latin_Extended_D}</tt>
-- <tt>\p{In_Latin_Extended_E}</tt>
-- <tt>\p{In_Latin_Extended_F}</tt>
-- <tt>\p{In_Latin_Extended_G}</tt>
-- <tt>\p{In_Lepcha}</tt>
-- <tt>\p{In_Letterlike_Symbols}</tt>
-- <tt>\p{In_Limbu}</tt>
-- <tt>\p{In_Linear_A}</tt>
-- <tt>\p{In_Linear_B_Ideograms}</tt>
-- <tt>\p{In_Linear_B_Syllabary}</tt>
-- <tt>\p{In_Lisu}</tt>
-- <tt>\p{In_Lisu_Supplement}</tt>
-- <tt>\p{In_Low_Surrogates}</tt>
-- <tt>\p{In_Lycian}</tt>
-- <tt>\p{In_Lydian}</tt>
-- <tt>\p{In_Mahajani}</tt>
-- <tt>\p{In_Mahjong_Tiles}</tt>
-- <tt>\p{In_Makasar}</tt>
-- <tt>\p{In_Malayalam}</tt>
-- <tt>\p{In_Mandaic}</tt>
-- <tt>\p{In_Manichaean}</tt>
-- <tt>\p{In_Marchen}</tt>
-- <tt>\p{In_Masaram_Gondi}</tt>
-- <tt>\p{In_Mathematical_Alphanumeric_Symbols}</tt>
-- <tt>\p{In_Mathematical_Operators}</tt>
-- <tt>\p{In_Mayan_Numerals}</tt>
-- <tt>\p{In_Medefaidrin}</tt>
-- <tt>\p{In_Meetei_Mayek}</tt>
-- <tt>\p{In_Meetei_Mayek_Extensions}</tt>
-- <tt>\p{In_Mende_Kikakui}</tt>
-- <tt>\p{In_Meroitic_Cursive}</tt>
-- <tt>\p{In_Meroitic_Hieroglyphs}</tt>
-- <tt>\p{In_Miao}</tt>
-- <tt>\p{In_Miscellaneous_Mathematical_Symbols_A}</tt>
-- <tt>\p{In_Miscellaneous_Mathematical_Symbols_B}</tt>
-- <tt>\p{In_Miscellaneous_Symbols}</tt>
-- <tt>\p{In_Miscellaneous_Symbols_and_Arrows}</tt>
-- <tt>\p{In_Miscellaneous_Symbols_and_Pictographs}</tt>
-- <tt>\p{In_Miscellaneous_Technical}</tt>
-- <tt>\p{In_Modi}</tt>
-- <tt>\p{In_Modifier_Tone_Letters}</tt>
-- <tt>\p{In_Mongolian}</tt>
-- <tt>\p{In_Mongolian_Supplement}</tt>
-- <tt>\p{In_Mro}</tt>
-- <tt>\p{In_Multani}</tt>
-- <tt>\p{In_Musical_Symbols}</tt>
-- <tt>\p{In_Myanmar}</tt>
-- <tt>\p{In_Myanmar_Extended_A}</tt>
-- <tt>\p{In_Myanmar_Extended_B}</tt>
-- <tt>\p{In_NKo}</tt>
-- <tt>\p{In_Nabataean}</tt>
-- <tt>\p{In_Nag_Mundari}</tt>
-- <tt>\p{In_Nandinagari}</tt>
-- <tt>\p{In_New_Tai_Lue}</tt>
-- <tt>\p{In_Newa}</tt>
-- <tt>\p{In_No_Block}</tt>
-- <tt>\p{In_Number_Forms}</tt>
-- <tt>\p{In_Nushu}</tt>
-- <tt>\p{In_Nyiakeng_Puachue_Hmong}</tt>
-- <tt>\p{In_Ogham}</tt>
-- <tt>\p{In_Ol_Chiki}</tt>
-- <tt>\p{In_Old_Hungarian}</tt>
-- <tt>\p{In_Old_Italic}</tt>
-- <tt>\p{In_Old_North_Arabian}</tt>
-- <tt>\p{In_Old_Permic}</tt>
-- <tt>\p{In_Old_Persian}</tt>
-- <tt>\p{In_Old_Sogdian}</tt>
-- <tt>\p{In_Old_South_Arabian}</tt>
-- <tt>\p{In_Old_Turkic}</tt>
-- <tt>\p{In_Old_Uyghur}</tt>
-- <tt>\p{In_Optical_Character_Recognition}</tt>
-- <tt>\p{In_Oriya}</tt>
-- <tt>\p{In_Ornamental_Dingbats}</tt>
-- <tt>\p{In_Osage}</tt>
-- <tt>\p{In_Osmanya}</tt>
-- <tt>\p{In_Ottoman_Siyaq_Numbers}</tt>
-- <tt>\p{In_Pahawh_Hmong}</tt>
-- <tt>\p{In_Palmyrene}</tt>
-- <tt>\p{In_Pau_Cin_Hau}</tt>
-- <tt>\p{In_Phags_pa}</tt>
-- <tt>\p{In_Phaistos_Disc}</tt>
-- <tt>\p{In_Phoenician}</tt>
-- <tt>\p{In_Phonetic_Extensions}</tt>
-- <tt>\p{In_Phonetic_Extensions_Supplement}</tt>
-- <tt>\p{In_Playing_Cards}</tt>
-- <tt>\p{In_Private_Use_Area}</tt>
-- <tt>\p{In_Psalter_Pahlavi}</tt>
-- <tt>\p{In_Rejang}</tt>
-- <tt>\p{In_Rumi_Numeral_Symbols}</tt>
-- <tt>\p{In_Runic}</tt>
-- <tt>\p{In_Samaritan}</tt>
-- <tt>\p{In_Saurashtra}</tt>
-- <tt>\p{In_Sharada}</tt>
-- <tt>\p{In_Shavian}</tt>
-- <tt>\p{In_Shorthand_Format_Controls}</tt>
-- <tt>\p{In_Siddham}</tt>
-- <tt>\p{In_Sinhala}</tt>
-- <tt>\p{In_Sinhala_Archaic_Numbers}</tt>
-- <tt>\p{In_Small_Form_Variants}</tt>
-- <tt>\p{In_Small_Kana_Extension}</tt>
-- <tt>\p{In_Sogdian}</tt>
-- <tt>\p{In_Sora_Sompeng}</tt>
-- <tt>\p{In_Soyombo}</tt>
-- <tt>\p{In_Spacing_Modifier_Letters}</tt>
-- <tt>\p{In_Specials}</tt>
-- <tt>\p{In_Sundanese}</tt>
-- <tt>\p{In_Sundanese_Supplement}</tt>
-- <tt>\p{In_Superscripts_and_Subscripts}</tt>
-- <tt>\p{In_Supplemental_Arrows_A}</tt>
-- <tt>\p{In_Supplemental_Arrows_B}</tt>
-- <tt>\p{In_Supplemental_Arrows_C}</tt>
-- <tt>\p{In_Supplemental_Mathematical_Operators}</tt>
-- <tt>\p{In_Supplemental_Punctuation}</tt>
-- <tt>\p{In_Supplemental_Symbols_and_Pictographs}</tt>
-- <tt>\p{In_Supplementary_Private_Use_Area_A}</tt>
-- <tt>\p{In_Supplementary_Private_Use_Area_B}</tt>
-- <tt>\p{In_Sutton_SignWriting}</tt>
-- <tt>\p{In_Syloti_Nagri}</tt>
-- <tt>\p{In_Symbols_and_Pictographs_Extended_A}</tt>
-- <tt>\p{In_Symbols_for_Legacy_Computing}</tt>
-- <tt>\p{In_Syriac}</tt>
-- <tt>\p{In_Syriac_Supplement}</tt>
-- <tt>\p{In_Tagalog}</tt>
-- <tt>\p{In_Tagbanwa}</tt>
-- <tt>\p{In_Tags}</tt>
-- <tt>\p{In_Tai_Le}</tt>
-- <tt>\p{In_Tai_Tham}</tt>
-- <tt>\p{In_Tai_Viet}</tt>
-- <tt>\p{In_Tai_Xuan_Jing_Symbols}</tt>
-- <tt>\p{In_Takri}</tt>
-- <tt>\p{In_Tamil}</tt>
-- <tt>\p{In_Tamil_Supplement}</tt>
-- <tt>\p{In_Tangsa}</tt>
-- <tt>\p{In_Tangut}</tt>
-- <tt>\p{In_Tangut_Components}</tt>
-- <tt>\p{In_Tangut_Supplement}</tt>
-- <tt>\p{In_Telugu}</tt>
-- <tt>\p{In_Thaana}</tt>
-- <tt>\p{In_Thai}</tt>
-- <tt>\p{In_Tibetan}</tt>
-- <tt>\p{In_Tifinagh}</tt>
-- <tt>\p{In_Tirhuta}</tt>
-- <tt>\p{In_Toto}</tt>
-- <tt>\p{In_Transport_and_Map_Symbols}</tt>
-- <tt>\p{In_Ugaritic}</tt>
-- <tt>\p{In_Unified_Canadian_Aboriginal_Syllabics}</tt>
-- <tt>\p{In_Unified_Canadian_Aboriginal_Syllabics_Extended}</tt>
-- <tt>\p{In_Unified_Canadian_Aboriginal_Syllabics_Extended_A}</tt>
-- <tt>\p{In_Vai}</tt>
-- <tt>\p{In_Variation_Selectors}</tt>
-- <tt>\p{In_Variation_Selectors_Supplement}</tt>
-- <tt>\p{In_Vedic_Extensions}</tt>
-- <tt>\p{In_Vertical_Forms}</tt>
-- <tt>\p{In_Vithkuqi}</tt>
-- <tt>\p{In_Wancho}</tt>
-- <tt>\p{In_Warang_Citi}</tt>
-- <tt>\p{In_Yezidi}</tt>
-- <tt>\p{In_Yi_Radicals}</tt>
-- <tt>\p{In_Yi_Syllables}</tt>
-- <tt>\p{In_Yijing_Hexagram_Symbols}</tt>
-- <tt>\p{In_Zanabazar_Square}</tt>
-- <tt>\p{In_Znamenny_Musical_Notation}</tt>
-
-=== Emoji
-
-- <tt>\p{Emoji}</tt>
-- <tt>\p{Emoji_Component}</tt>, <tt>\p{EComp}</tt>
-- <tt>\p{Emoji_Modifier}</tt>, <tt>\p{EMod}</tt>
-- <tt>\p{Emoji_Modifier_Base}</tt>, <tt>\p{EBase}</tt>
-- <tt>\p{Emoji_Presentation}</tt>, <tt>\p{EPres}</tt>
-- <tt>\p{Extended_Pictographic}</tt>, <tt>\p{ExtPict}</tt>
-
-=== Graphemes
-
-- <tt>\p{Grapheme_Cluster_Break_CR}</tt>
-- <tt>\p{Grapheme_Cluster_Break_Control}</tt>
-- <tt>\p{Grapheme_Cluster_Break_Extend}</tt>
-- <tt>\p{Grapheme_Cluster_Break_L}</tt>
-- <tt>\p{Grapheme_Cluster_Break_LF}</tt>
-- <tt>\p{Grapheme_Cluster_Break_LV}</tt>
-- <tt>\p{Grapheme_Cluster_Break_LVT}</tt>
-- <tt>\p{Grapheme_Cluster_Break_Prepend}</tt>
-- <tt>\p{Grapheme_Cluster_Break_Regional_Indicator}</tt>
-- <tt>\p{Grapheme_Cluster_Break_SpacingMark}</tt>
-- <tt>\p{Grapheme_Cluster_Break_T}</tt>
-- <tt>\p{Grapheme_Cluster_Break_V}</tt>
-- <tt>\p{Grapheme_Cluster_Break_ZWJ}</tt>
-
-=== Derived Ages
-
-- <tt>\p{Age_10_0}</tt>
-- <tt>\p{Age_11_0}</tt>
-- <tt>\p{Age_12_0}</tt>
-- <tt>\p{Age_12_1}</tt>
-- <tt>\p{Age_13_0}</tt>
-- <tt>\p{Age_14_0}</tt>
-- <tt>\p{Age_15_0}</tt>
-- <tt>\p{Age_1_1}</tt>
-- <tt>\p{Age_2_0}</tt>
-- <tt>\p{Age_2_1}</tt>
-- <tt>\p{Age_3_0}</tt>
-- <tt>\p{Age_3_1}</tt>
-- <tt>\p{Age_3_2}</tt>
-- <tt>\p{Age_4_0}</tt>
-- <tt>\p{Age_4_1}</tt>
-- <tt>\p{Age_5_0}</tt>
-- <tt>\p{Age_5_1}</tt>
-- <tt>\p{Age_5_2}</tt>
-- <tt>\p{Age_6_0}</tt>
-- <tt>\p{Age_6_1}</tt>
-- <tt>\p{Age_6_2}</tt>
-- <tt>\p{Age_6_3}</tt>
-- <tt>\p{Age_7_0}</tt>
-- <tt>\p{Age_8_0}</tt>
-- <tt>\p{Age_9_0}</tt>
diff --git a/doc/reline/face.md b/doc/reline/face.md
deleted file mode 100644
index 1fa916123b..0000000000
--- a/doc/reline/face.md
+++ /dev/null
@@ -1,111 +0,0 @@
-# Face
-
-With the `Reline::Face` class, you can modify the text color and text decorations in your terminal emulator.
-This is primarily used to customize the appearance of the method completion dialog in IRB.
-
-## Usage
-
-### ex: Change the background color of the completion dialog cyan to blue
-
-```ruby
-Reline::Face.config(:completion_dialog) do |conf|
- conf.define :default, foreground: :white, background: :blue
- # ^^^^^ `:cyan` by default
- conf.define :enhanced, foreground: :white, background: :magenta
- conf.define :scrollbar, foreground: :white, background: :blue
-end
-```
-
-If you provide the above code to an IRB session in some way, you can apply the configuration.
-It's generally done by writing it in `.irbrc`.
-
-Regarding `.irbrc`, please refer to the following link: [https://docs.ruby-lang.org/en/master/IRB.html](https://docs.ruby-lang.org/en/master/IRB.html)
-
-## Available parameters
-
-`Reline::Face` internally creates SGR (Select Graphic Rendition) code according to the block parameter of `Reline::Face.config` method.
-
-| Key | Value | SGR Code (numeric part following "\e[")|
-|:------------|:------------------|-----:|
-| :foreground | :black | 30 |
-| | :red | 31 |
-| | :green | 32 |
-| | :yellow | 33 |
-| | :blue | 34 |
-| | :magenta | 35 |
-| | :cyan | 36 |
-| | :white | 37 |
-| | :bright_black | 90 |
-| | :gray | 90 |
-| | :bright_red | 91 |
-| | :bright_green | 92 |
-| | :bright_yellow | 93 |
-| | :bright_blue | 94 |
-| | :bright_magenta | 95 |
-| | :bright_cyan | 96 |
-| | :bright_white | 97 |
-| :background | :black | 40 |
-| | :red | 41 |
-| | :green | 42 |
-| | :yellow | 43 |
-| | :blue | 44 |
-| | :magenta | 45 |
-| | :cyan | 46 |
-| | :white | 47 |
-| | :bright_black | 100 |
-| | :gray | 100 |
-| | :bright_red | 101 |
-| | :bright_green | 102 |
-| | :bright_yellow | 103 |
-| | :bright_blue | 104 |
-| | :bright_magenta | 105 |
-| | :bright_cyan | 106 |
-| | :bright_white | 107 |
-| :style | :reset | 0 |
-| | :bold | 1 |
-| | :faint | 2 |
-| | :italicized | 3 |
-| | :underlined | 4 |
-| | :slowly_blinking | 5 |
-| | :blinking | 5 |
-| | :rapidly_blinking | 6 |
-| | :negative | 7 |
-| | :concealed | 8 |
-| | :crossed_out | 9 |
-
-- The value for `:style` can be both a Symbol and an Array
- ```ruby
- # Single symbol
- conf.define :default, style: :bold
- # Array
- conf.define :default, style: [:bold, :negative]
- ```
-- The availability of specific SGR codes depends on your terminal emulator
-- You can specify a hex color code to `:foreground` and `:background` color like `foreground: "#FF1020"`. Its availability also depends on your terminal emulator
-
-## Debugging
-
-You can see the current Face configuration by `Reline::Face.configs` method
-
-Example:
-
-```ruby
-irb(main):001:0> Reline::Face.configs
-=>
-{:default=>
- {:default=>{:style=>:reset, :escape_sequence=>"\e[0m"},
- :enhanced=>{:style=>:reset, :escape_sequence=>"\e[0m"},
- :scrollbar=>{:style=>:reset, :escape_sequence=>"\e[0m"}},
- :completion_dialog=>
- {:default=>{:foreground=>:white, :background=>:cyan, :escape_sequence=>"\e[0m\e[37;46m"},
- :enhanced=>{:foreground=>:white, :background=>:magenta, :escape_sequence=>"\e[0m\e[37;45m"},
- :scrollbar=>{:foreground=>:white, :background=>:cyan, :escape_sequence=>"\e[0m\e[37;46m"}}}
-```
-
-## 256-Color and TrueColor
-
-Reline will automatically detect if your terminal emulator supports truecolor with `ENV['COLORTERM] in 'truecolor' | '24bit'`. When this env is not set, Reline will fallback to 256-color.
-If your terminal emulator supports truecolor but does not set COLORTERM env, add this line to `.irbrc`.
-```ruby
-Reline::Face.force_truecolor
-```
diff --git a/doc/rjit/rjit.md b/doc/rjit/rjit.md
deleted file mode 100644
index 9e60e43ce3..0000000000
--- a/doc/rjit/rjit.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# RJIT: Ruby JIT
-
-This document has some tips that might be useful when you work on RJIT.
-
-## Project purpose
-
-This project is for experimental purposes.
-For production deployment, consider using YJIT instead.
-
-## Supported platforms
-
-The following platforms are assumed to work. `linux-x86_64` is tested on CI.
-
-* OS: Linux, macOS, BSD
-* Arch: x86\_64
-
-## configure
-### --enable-rjit
-
-On supported platforms, `--enable-rjit` is set by default. You usually don't need to specify this.
-You may still manually pass `--enable-rjit` to try RJIT on unsupported platforms.
-
-### --enable-rjit=dev
-
-It enables `--rjit-dump-disasm` if libcapstone is available.
-
-## make
-### rjit-bindgen
-
-If you see an "RJIT bindgen" GitHub Actions failure, please commit the `git diff` shown on the failed job.
-
-For doing the same thing locally, run `make rjit-bindgen` after installing libclang.
-macOS seems to have libclang by default. On Ubuntu, you can install it with `apt install libclang1`.
-
-## ruby
-### --rjit-stats
-
-This prints RJIT stats at exit.
-
-### --rjit-dump-disasm
-
-This dumps all JIT code. You need to install libcapstone before configure and use `--enable-rjit=dev` on configure.
-
-* Ubuntu: `sudo apt-get install -y libcapstone-dev`
-* macOS: `brew install capstone`
diff --git a/doc/ruby/option_dump.md b/doc/ruby/option_dump.md
deleted file mode 100644
index 00d0ec77d5..0000000000
--- a/doc/ruby/option_dump.md
+++ /dev/null
@@ -1,297 +0,0 @@
-# Option `--dump`
-
-For other argument values,
-see {Option --dump}[options_md.html#label--dump-3A+Dump+Items].
-
-For the examples here, we use this program:
-
-```sh
-$ cat t.rb
-puts 'Foo'
-```
-
-The supported dump items:
-
-- `insns`: Instruction sequences:
-
- ```sh
- $ ruby --dump=insns t.rb
- == disasm: #<ISeq:<main>@t.rb:1 (1,0)-(1,10)> (catch: FALSE)
- 0000 putself ( 1)[Li]
- 0001 putstring "Foo"
- 0003 opt_send_without_block <calldata!mid:puts, argc:1, FCALL|ARGS_SIMPLE>
- 0005 leave
- ```
-
-- `parsetree`: {Abstract syntax tree}[https://en.wikipedia.org/wiki/Abstract_syntax_tree]
- (AST):
-
- ```sh
- $ ruby --dump=parsetree t.rb
- ###########################################################
- ## Do NOT use this node dump for any purpose other than ##
- ## debug and research. Compatibility is not guaranteed. ##
- ###########################################################
-
- # @ NODE_SCOPE (line: 1, location: (1,0)-(1,10))
- # +- nd_tbl: (empty)
- # +- nd_args:
- # | (null node)
- # +- nd_body:
- # @ NODE_FCALL (line: 1, location: (1,0)-(1,10))*
- # +- nd_mid: :puts
- # +- nd_args:
- # @ NODE_LIST (line: 1, location: (1,5)-(1,10))
- # +- nd_alen: 1
- # +- nd_head:
- # | @ NODE_STR (line: 1, location: (1,5)-(1,10))
- # | +- nd_lit: "Foo"
- # +- nd_next:
- # (null node)
- ```
-
-- `parsetree_with_comment`: AST with comments:
-
- ```sh
- $ ruby --dump=parsetree_with_comment t.rb
- ###########################################################
- ## Do NOT use this node dump for any purpose other than ##
- ## debug and research. Compatibility is not guaranteed. ##
- ###########################################################
-
- # @ NODE_SCOPE (line: 1, location: (1,0)-(1,10))
- # | # new scope
- # | # format: [nd_tbl]: local table, [nd_args]: arguments, [nd_body]: body
- # +- nd_tbl (local table): (empty)
- # +- nd_args (arguments):
- # | (null node)
- # +- nd_body (body):
- # @ NODE_FCALL (line: 1, location: (1,0)-(1,10))*
- # | # function call
- # | # format: [nd_mid]([nd_args])
- # | # example: foo(1)
- # +- nd_mid (method id): :puts
- # +- nd_args (arguments):
- # @ NODE_LIST (line: 1, location: (1,5)-(1,10))
- # | # list constructor
- # | # format: [ [nd_head], [nd_next].. ] (length: [nd_alen])
- # | # example: [1, 2, 3]
- # +- nd_alen (length): 1
- # +- nd_head (element):
- # | @ NODE_STR (line: 1, location: (1,5)-(1,10))
- # | | # string literal
- # | | # format: [nd_lit]
- # | | # example: 'foo'
- # | +- nd_lit (literal): "Foo"
- # +- nd_next (next element):
- # (null node)
- ```
-
-- `yydebug`: Debugging information from yacc parser generator:
-
- ```sh
- $ ruby --dump=yydebug t.rb
- Starting parse
- Entering state 0
- Reducing stack by rule 1 (line 1295):
- lex_state: NONE -> BEG at line 1296
- vtable_alloc:12392: 0x0000558453df1a00
- vtable_alloc:12393: 0x0000558453df1a60
- cmdarg_stack(push): 0 at line 12406
- cond_stack(push): 0 at line 12407
- -> $$ = nterm $@1 (1.0-1.0: )
- Stack now 0
- Entering state 2
- Reading a token:
- lex_state: BEG -> CMDARG at line 9049
- Next token is token "local variable or method" (1.0-1.4: puts)
- Shifting token "local variable or method" (1.0-1.4: puts)
- Entering state 35
- Reading a token: Next token is token "string literal" (1.5-1.6: )
- Reducing stack by rule 742 (line 5567):
- $1 = token "local variable or method" (1.0-1.4: puts)
- -> $$ = nterm operation (1.0-1.4: )
- Stack now 0 2
- Entering state 126
- Reducing stack by rule 78 (line 1794):
- $1 = nterm operation (1.0-1.4: )
- -> $$ = nterm fcall (1.0-1.4: )
- Stack now 0 2
- Entering state 80
- Next token is token "string literal" (1.5-1.6: )
- Reducing stack by rule 292 (line 2723):
- cmdarg_stack(push): 1 at line 2737
- -> $$ = nterm $@16 (1.4-1.4: )
- Stack now 0 2 80
- Entering state 235
- Next token is token "string literal" (1.5-1.6: )
- Shifting token "string literal" (1.5-1.6: )
- Entering state 216
- Reducing stack by rule 607 (line 4706):
- -> $$ = nterm string_contents (1.6-1.6: )
- Stack now 0 2 80 235 216
- Entering state 437
- Reading a token: Next token is token "literal content" (1.6-1.9: "Foo")
- Shifting token "literal content" (1.6-1.9: "Foo")
- Entering state 503
- Reducing stack by rule 613 (line 4802):
- $1 = token "literal content" (1.6-1.9: "Foo")
- -> $$ = nterm string_content (1.6-1.9: )
- Stack now 0 2 80 235 216 437
- Entering state 507
- Reducing stack by rule 608 (line 4716):
- $1 = nterm string_contents (1.6-1.6: )
- $2 = nterm string_content (1.6-1.9: )
- -> $$ = nterm string_contents (1.6-1.9: )
- Stack now 0 2 80 235 216
- Entering state 437
- Reading a token:
- lex_state: CMDARG -> END at line 7276
- Next token is token "terminator" (1.9-1.10: )
- Shifting token "terminator" (1.9-1.10: )
- Entering state 508
- Reducing stack by rule 590 (line 4569):
- $1 = token "string literal" (1.5-1.6: )
- $2 = nterm string_contents (1.6-1.9: )
- $3 = token "terminator" (1.9-1.10: )
- -> $$ = nterm string1 (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 109
- Reducing stack by rule 588 (line 4559):
- $1 = nterm string1 (1.5-1.10: )
- -> $$ = nterm string (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 108
- Reading a token:
- lex_state: END -> BEG at line 9200
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 586 (line 4541):
- $1 = nterm string (1.5-1.10: )
- -> $$ = nterm strings (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 107
- Reducing stack by rule 307 (line 2837):
- $1 = nterm strings (1.5-1.10: )
- -> $$ = nterm primary (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 90
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 261 (line 2553):
- $1 = nterm primary (1.5-1.10: )
- -> $$ = nterm arg (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 220
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 270 (line 2586):
- $1 = nterm arg (1.5-1.10: )
- -> $$ = nterm arg_value (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 221
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 297 (line 2779):
- $1 = nterm arg_value (1.5-1.10: )
- -> $$ = nterm args (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 224
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 772 (line 5626):
- -> $$ = nterm none (1.10-1.10: )
- Stack now 0 2 80 235 224
- Entering state 442
- Reducing stack by rule 296 (line 2773):
- $1 = nterm none (1.10-1.10: )
-
- -> $$ = nterm opt_block_arg (1.10-1.10: )
- Stack now 0 2 80 235 224
- Entering state 441
- Reducing stack by rule 288 (line 2696):
- $1 = nterm args (1.5-1.10: )
- $2 = nterm opt_block_arg (1.10-1.10: )
- -> $$ = nterm call_args (1.5-1.10: )
- Stack now 0 2 80 235
- Entering state 453
- Reducing stack by rule 293 (line 2723):
- $1 = nterm $@16 (1.4-1.4: )
- $2 = nterm call_args (1.5-1.10: )
- cmdarg_stack(pop): 0 at line 2754
- -> $$ = nterm command_args (1.4-1.10: )
- Stack now 0 2 80
- Entering state 333
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 79 (line 1804):
- $1 = nterm fcall (1.0-1.4: )
- $2 = nterm command_args (1.4-1.10: )
- -> $$ = nterm command (1.0-1.10: )
- Stack now 0 2
- Entering state 81
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 73 (line 1770):
- $1 = nterm command (1.0-1.10: )
- -> $$ = nterm command_call (1.0-1.10: )
- Stack now 0 2
- Entering state 78
- Reducing stack by rule 51 (line 1659):
- $1 = nterm command_call (1.0-1.10: )
- -> $$ = nterm expr (1.0-1.10: )
- Stack now 0 2
- Entering state 75
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 39 (line 1578):
- $1 = nterm expr (1.0-1.10: )
- -> $$ = nterm stmt (1.0-1.10: )
- Stack now 0 2
- Entering state 73
- Next token is token '\n' (1.10-1.10: )
- Reducing stack by rule 8 (line 1354):
- $1 = nterm stmt (1.0-1.10: )
- -> $$ = nterm top_stmt (1.0-1.10: )
- Stack now 0 2
- Entering state 72
- Reducing stack by rule 5 (line 1334):
- $1 = nterm top_stmt (1.0-1.10: )
- -> $$ = nterm top_stmts (1.0-1.10: )
- Stack now 0 2
- Entering state 71
- Next token is token '\n' (1.10-1.10: )
- Shifting token '\n' (1.10-1.10: )
- Entering state 311
- Reducing stack by rule 769 (line 5618):
- $1 = token '\n' (1.10-1.10: )
- -> $$ = nterm term (1.10-1.10: )
- Stack now 0 2 71
- Entering state 313
- Reducing stack by rule 770 (line 5621):
- $1 = nterm term (1.10-1.10: )
- -> $$ = nterm terms (1.10-1.10: )
- Stack now 0 2 71
- Entering state 314
- Reading a token: Now at end of input.
- Reducing stack by rule 759 (line 5596):
- $1 = nterm terms (1.10-1.10: )
- -> $$ = nterm opt_terms (1.10-1.10: )
- Stack now 0 2 71
- Entering state 312
- Reducing stack by rule 3 (line 1321):
- $1 = nterm top_stmts (1.0-1.10: )
- $2 = nterm opt_terms (1.10-1.10: )
- -> $$ = nterm top_compstmt (1.0-1.10: )
- Stack now 0 2
- Entering state 70
- Reducing stack by rule 2 (line 1295):
- $1 = nterm $@1 (1.0-1.0: )
- $2 = nterm top_compstmt (1.0-1.10: )
- vtable_free:12426: p->lvtbl->args(0x0000558453df1a00)
- vtable_free:12427: p->lvtbl->vars(0x0000558453df1a60)
- cmdarg_stack(pop): 0 at line 12428
- cond_stack(pop): 0 at line 12429
- -> $$ = nterm program (1.0-1.10: )
- Stack now 0
- Entering state 1
- Now at end of input.
- Shifting token "end-of-input" (1.10-1.10: )
- Entering state 3
- Stack now 0 1 3
- Cleanup: popping token "end-of-input" (1.10-1.10: )
- Cleanup: popping nterm program (1.0-1.10: )
- ```
-
diff --git a/doc/ruby/options.md b/doc/ruby/options.md
deleted file mode 100644
index 143c8925f1..0000000000
--- a/doc/ruby/options.md
+++ /dev/null
@@ -1,723 +0,0 @@
-# Ruby Command-Line Options
-
-## About the Examples
-
-Some examples here use command-line option `-e`,
-which passes the Ruby code to be executed on the command line itself:
-
-```sh
-$ ruby -e 'puts "Hello, World."'
-```
-
-Some examples here assume that file `desiderata.txt` exists:
-
-```
-$ cat desiderata.txt
-Go placidly amid the noise and the haste,
-and remember what peace there may be in silence.
-As far as possible, without surrender,
-be on good terms with all persons.
-```
-
-## Options
-
-### `-0`: \Set `$/` (Input Record Separator)
-
-Option `-0` defines the input record separator `$/`
-for the invoked Ruby program.
-
-The optional argument to the option must be octal digits,
-each in the range `0..7`;
-these digits are prefixed with digit `0` to form an octal value.
-
-If no argument is given, the input record separator is `0x00`.
-
-If an argument is given, it must immediately follow the option
-(no intervening whitespace or equal-sign character `'='`);
-argument values:
-
-- `0`: the input record separator is `''`;
- see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values].
-- In range `(1..0377)`:
- the input record separator `$/` is set to the character value of the argument.
-- Any other octal value: the input record separator is `nil`.
-
-Examples:
-
-```sh
-$ ruby -0 -e 'p $/'
-"\x00"
-ruby -00 -e 'p $/'
-""
-$ ruby -012 -e 'p $/'
-"\n"
-$ ruby -015 -e 'p $/'
-"\r"
-$ ruby -0377 -e 'p $/'
-"\xFF"
-$ ruby -0400 -e 'p $/'
-nil
-```
-
-See also:
-
-- {Option -a}[rdoc-ref:ruby/options.md@a-3A+Split+Input+Lines+into+Fields]:
- Split input lines into fields.
-- {Option -F}[rdoc-ref:ruby/options.md@F-3A+Set+Input+Field+Separator]:
- \Set input field separator.
-- {Option -l}[rdoc-ref:ruby/options.md@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]:
- \Set output record separator; chop lines.
-- {Option -n}[rdoc-ref:ruby/options.md@n-3A+Run+Program+in+gets+Loop]:
- Run program in `gets` loop.
-- {Option -p}[rdoc-ref:ruby/options.md@p-3A+-n-2C+with+Printing]:
- `-n`, with printing.
-
-### `-a`: Split Input Lines into Fields
-
-Option `-a`, when given with either of options `-n` or `-p`,
-splits the string at `$_` into an array of strings at `$F`:
-
-```sh
-$ ruby -an -e 'p $F' desiderata.txt
-["Go", "placidly", "amid", "the", "noise", "and", "the", "haste,"]
-["and", "remember", "what", "peace", "there", "may", "be", "in", "silence."]
-["As", "far", "as", "possible,", "without", "surrender,"]
-["be", "on", "good", "terms", "with", "all", "persons."]
-```
-
-For the splitting,
-the default record separator is `$/`,
-and the default field separator is `$;`.
-
-See also:
-
-- {Option -0}[rdoc-ref:ruby/options.md@0-3A+Set+-24-2F+-28Input+Record+Separator-29]:
- \Set `$/` (input record separator).
-- {Option -F}[rdoc-ref:ruby/options.md@F-3A+Set+Input+Field+Separator]:
- \Set input field separator.
-- {Option -l}[rdoc-ref:ruby/options.md@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]:
- \Set output record separator; chop lines.
-- {Option -n}[rdoc-ref:ruby/options.md@n-3A+Run+Program+in+gets+Loop]:
- Run program in `gets` loop.
-- {Option -p}[rdoc-ref:ruby/options.md@p-3A+-n-2C+with+Printing]:
- `-n`, with printing.
-
-### `-c`: Check Syntax
-
-Option `-c` specifies that the specified Ruby program
-should be checked for syntax, but not actually executed:
-
-```
-$ ruby -e 'puts "Foo"'
-Foo
-$ ruby -c -e 'puts "Foo"'
-Syntax OK
-```
-
-### `-C`: \Set Working Directory
-
-The argument to option `-C` specifies a working directory
-for the invoked Ruby program;
-does not change the working directory for the current process:
-
-```sh
-$ basename `pwd`
-ruby
-$ ruby -C lib -e 'puts File.basename(Dir.pwd)'
-lib
-$ basename `pwd`
-ruby
-```
-
-Whitespace between the option and its argument may be omitted.
-
-### `-d`: \Set `$DEBUG` to `true`
-
-Some code in (or called by) the Ruby program may include statements or blocks
-conditioned by the global variable `$DEBUG` (e.g., `if $DEBUG`);
-these commonly write to `$stdout` or `$stderr`.
-
-The default value for `$DEBUG` is `false`;
-option `-d` sets it to `true`:
-
-```sh
-$ ruby -e 'p $DEBUG'
-false
-$ ruby -d -e 'p $DEBUG'
-true
-```
-
-Option `--debug` is an alias for option `-d`.
-
-### `-e`: Execute Given Ruby Code
-
-Option `-e` requires an argument, which is Ruby code to be executed;
-the option may be given more than once:
-
-```
-$ ruby -e 'puts "Foo"' -e 'puts "Bar"'
-Foo
-Bar
-```
-
-Whitespace between the option and its argument may be omitted.
-
-The command may include other options,
-but should not include arguments (which, if given, are ignored).
-
-### `-E`: \Set Default Encodings
-
-Option `-E` requires an argument, which specifies either the default external encoding,
-or both the default external and internal encodings for the invoked Ruby program:
-
-```
-# No option -E.
-$ ruby -e 'p [Encoding::default_external, Encoding::default_internal]'
-[#<Encoding:UTF-8>, nil]
-# Option -E with default external encoding.
-$ ruby -E cesu-8 -e 'p [Encoding::default_external, Encoding::default_internal]'
-[#<Encoding:CESU-8>, nil]
-# Option -E with default external and internal encodings.
-$ ruby -E utf-8:cesu-8 -e 'p [Encoding::default_external, Encoding::default_internal]'
-[#<Encoding:UTF-8>, #<Encoding:CESU-8>]
-```
-
-Whitespace between the option and its argument may be omitted.
-
-See also:
-
-- {Option --external-encoding}[options_md.html#label--external-encoding-3A+Set+Default+External+Encoding]:
- \Set default external encoding.
-- {Option --internal-encoding}[options_md.html#label--internal-encoding-3A+Set+Default+Internal+Encoding]:
- \Set default internal encoding.
-
-Option `--encoding` is an alias for option `-E`.
-
-### `-F`: \Set Input Field Separator
-
-Option `-F`, when given with option `-a`,
-specifies that its argument is to be the input field separator to be used for splitting:
-
-```sh
-$ ruby -an -Fs -e 'p $F' desiderata.txt
-["Go placidly amid the noi", "e and the ha", "te,\n"]
-["and remember what peace there may be in ", "ilence.\n"]
-["A", " far a", " po", "", "ible, without ", "urrender,\n"]
-["be on good term", " with all per", "on", ".\n"]
-```
-
-The argument may be a regular expression:
-
-```
-$ ruby -an -F'[.,]\s*' -e 'p $F' desiderata.txt
-["Go placidly amid the noise and the haste"]
-["and remember what peace there may be in silence"]
-["As far as possible", "without surrender"]
-["be on good terms with all persons"]
-```
-
-The argument must immediately follow the option
-(no intervening whitespace or equal-sign character `'='`).
-
-See also:
-
-- {Option -0}[rdoc-ref:ruby/options.md@0-3A+Set+-24-2F+-28Input+Record+Separator-29]:
- \Set `$/` (input record separator).
-- {Option -a}[rdoc-ref:ruby/options.md@a-3A+Split+Input+Lines+into+Fields]:
- Split input lines into fields.
-- {Option -l}[rdoc-ref:ruby/options.md@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]:
- \Set output record separator; chop lines.
-- {Option -n}[rdoc-ref:ruby/options.md@n-3A+Run+Program+in+gets+Loop]:
- Run program in `gets` loop.
-- {Option -p}[rdoc-ref:ruby/options.md@p-3A+-n-2C+with+Printing]:
- `-n`, with printing.
-
-### `-h`: Print Short Help Message
-
-Option `-h` prints a short help message
-that includes single-hyphen options (e.g. `-I`),
-and largely omits double-hyphen options (e.g., `--version`).
-
-Arguments and additional options are ignored.
-
-For a longer help message, use option `--help`.
-
-### `-i`: \Set \ARGF In-Place Mode
-
-Option `-i` sets the \ARGF in-place mode for the invoked Ruby program;
-see ARGF#inplace_mode=:
-
-```
-$ ruby -e 'p ARGF.inplace_mode'
-nil
-$ ruby -i -e 'p ARGF.inplace_mode'
-""
-$ ruby -i.bak -e 'p ARGF.inplace_mode'
-".bak"
-```
-
-### `-I`: Add to `$LOAD_PATH`
-
-The argument to option `-I` specifies a directory
-to be added to the array in global variable `$LOAD_PATH`;
-the option may be given more than once:
-
-```sh
-$ pushd /tmp
-$ ruby -e 'p $LOAD_PATH.size'
-8
-$ ruby -I my_lib -I some_lib -e 'p $LOAD_PATH.size'
-10
-$ ruby -I my_lib -I some_lib -e 'p $LOAD_PATH.take(2)'
-["/tmp/my_lib", "/tmp/some_lib"]
-$ popd
-```
-
-Whitespace between the option and its argument may be omitted.
-
-### `-l`: \Set Output Record Separator; Chop Lines
-
-Option `-l`, when given with option `-n` or `-p`,
-modifies line-ending processing by:
-
-- Setting global variable output record separator `$\`
- to the current value of input record separator `$/`;
- this affects line-oriented output (such a the output from Kernel#puts).
-- Calling String#chop! on each line read.
-
-Without option `-l` (unchopped):
-
-```sh
-$ ruby -n -e 'p $_' desiderata.txt
-"Go placidly amid the noise and the haste,\n"
-"and remember what peace there may be in silence.\n"
-"As far as possible, without surrender,\n"
-"be on good terms with all persons.\n"
-```
-
-With option `-l' (chopped):
-
-```sh
-$ ruby -ln -e 'p $_' desiderata.txt
-"Go placidly amid the noise and the haste,"
-"and remember what peace there may be in silence."
-"As far as possible, without surrender,"
-"be on good terms with all persons."
-```
-
-See also:
-
-- {Option -0}[rdoc-ref:ruby/options.md@0-3A+Set+-24-2F+-28Input+Record+Separator-29]:
- \Set `$/` (input record separator).
-- {Option -a}[rdoc-ref:ruby/options.md@a-3A+Split+Input+Lines+into+Fields]:
- Split input lines into fields.
-- {Option -F}[rdoc-ref:ruby/options.md@F-3A+Set+Input+Field+Separator]:
- \Set input field separator.
-- {Option -n}[rdoc-ref:ruby/options.md@n-3A+Run+Program+in+gets+Loop]:
- Run program in `gets` loop.
-- {Option -p}[rdoc-ref:ruby/options.md@p-3A+-n-2C+with+Printing]:
- `-n`, with printing.
-
-### `-n`: Run Program in `gets` Loop
-
-Option `-n` runs your program in a Kernel#gets loop:
-
-```
-while gets
- # Your Ruby code.
-end
-```
-
-Note that `gets` reads the next line and sets global variable `$_`
-to the last read line:
-
-```sh
-$ ruby -n -e 'puts $_' desiderata.txt
-Go placidly amid the noise and the haste,
-and remember what peace there may be in silence.
-As far as possible, without surrender,
-be on good terms with all persons.
-```
-
-See also:
-
-- {Option -0}[rdoc-ref:ruby/options.md@0-3A+Set+-24-2F+-28Input+Record+Separator-29]:
- \Set `$/` (input record separator).
-- {Option -a}[rdoc-ref:ruby/options.md@a-3A+Split+Input+Lines+into+Fields]:
- Split input lines into fields.
-- {Option -F}[rdoc-ref:ruby/options.md@F-3A+Set+Input+Field+Separator]:
- \Set input field separator.
-- {Option -l}[rdoc-ref:ruby/options.md@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]:
- \Set output record separator; chop lines.
-- {Option -p}[rdoc-ref:ruby/options.md@p-3A+-n-2C+with+Printing]:
- `-n`, with printing.
-
-### `-p`: `-n`, with Printing
-
-Option `-p` is like option `-n`, but also prints each line:
-
-```sh
-$ ruby -p -e 'puts $_.size' desiderata.txt
-42
-Go placidly amid the noise and the haste,
-49
-and remember what peace there may be in silence.
-39
-As far as possible, without surrender,
-35
-be on good terms with all persons.
-```
-
-See also:
-
-- {Option -0}[rdoc-ref:ruby/options.md@0-3A+Set+-24-2F+-28Input+Record+Separator-29]:
- \Set `$/` (input record separator).
-- {Option -a}[rdoc-ref:ruby/options.md@a-3A+Split+Input+Lines+into+Fields]:
- Split input lines into fields.
-- {Option -F}[rdoc-ref:ruby/options.md@F-3A+Set+Input+Field+Separator]:
- \Set input field separator.
-- {Option -l}[rdoc-ref:ruby/options.md@l-3A+Set+Output+Record+Separator-3B+Chop+Lines]:
- \Set output record separator; chop lines.
-- {Option -n}[rdoc-ref:ruby/options.md@n-3A+Run+Program+in+gets+Loop]:
- Run program in `gets` loop.
-
-### `-r`: Require Library
-
-The argument to option `-r` specifies a library to be required
-before executing the Ruby program;
-the option may be given more than once:
-
-```sh
-$ ruby -e 'p defined?(JSON); p defined?(CSV)'
-nil
-nil
-$ ruby -r CSV -r JSON -e 'p defined?(JSON); p defined?(CSV)'
-"constant"
-"constant"
-```
-
-Whitespace between the option and its argument may be omitted.
-
-### `-s`: Define Global Variable
-
-Option `-s` specifies that a "custom option" is to define a global variable
-in the invoked Ruby program:
-
-- The custom option must appear _after_ the program name.
-- The custom option must begin with single hyphen (e.g., `-foo`),
- not two hyphens (e.g., `--foo`).
-- The name of the global variable is based on the option name:
- global variable `$foo` for custom option`-foo`.
-- The value of the global variable is the string option argument if given,
- `true` otherwise.
-
-More than one custom option may be given:
-
-```
-$ cat t.rb
-p [$foo, $bar]
-$ ruby t.rb
-[nil, nil]
-$ ruby -s t.rb -foo=baz
-["baz", nil]
-$ ruby -s t.rb -foo
-[true, nil]
-$ ruby -s t.rb -foo=baz -bar=bat
-["baz", "bat"]
-```
-
-The option may not be used with
-{option -e}[rdoc-ref:ruby/options.md@e-3A+Execute+Given+Ruby+Code]
-
-### `-S`: Search Directories in `ENV['PATH']`
-
-Option `-S` specifies that the Ruby interpreter
-is to search (if necessary) the directories whose paths are in the program's
-`PATH` environment variable;
-the program is executed in the shell's current working directory
-(not necessarily in the directory where the program is found).
-
-This example uses adds path `'tmp/'` to the `PATH` environment variable:
-
-```sh
-$ export PATH=/tmp:$PATH
-$ echo "puts File.basename(Dir.pwd)" > /tmp/t.rb
-$ ruby -S t.rb
-ruby
-```
-
-### `-v`: Print Version; \Set `$VERBOSE`
-
-Options `-v` prints the Ruby version and sets global variable `$VERBOSE`:
-
-```
-$ ruby -e 'p $VERBOSE'
-false
-$ ruby -v -e 'p $VERBOSE'
-ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x64-mingw-ucrt]
-true
-```
-
-### `-w`: Synonym for `-W1`
-
-Option `-w` (lowercase letter) is equivalent to option `-W1` (uppercase letter).
-
-### `-W`: \Set \Warning Policy
-
-Any Ruby code can create a <i>warning message</i> by calling method Kernel#warn;
-methods in the Ruby core and standard libraries can also create warning messages.
-Such a message may be printed on `$stderr`
-(or not, depending on certain settings).
-
-Option `-W` helps determine whether a particular warning message
-will be written,
-by setting the initial value of global variable `$-W`:
-
-- `-W0`: Sets `$-W` to `0` (silent; no warnings).
-- `-W1`: Sets `$-W` to `1` (moderate verbosity).
-- `-W2`: Sets `$-W` to `2` (high verbosity).
-- `-W`: Same as `-W2` (high verbosity).
-- Option not given: Same as `-W1` (moderate verbosity).
-
-The value of `$-W`, in turn, determines which warning messages (if any)
-are to be printed to `$stdout` (see Kernel#warn):
-
-```sh
-$ ruby -W1 -e 'p $foo'
-nil
-$ ruby -W2 -e 'p $foo'
--e:1: warning: global variable '$foo' not initialized
-nil
-```
-
-Ruby code may also define warnings for certain categories;
-these are the default settings for the defined categories:
-
-```
-Warning[:experimental] # => true
-Warning[:deprecated] # => false
-Warning[:performance] # => false
-```
-
-They may also be set:
-```
-Warning[:experimental] = false
-Warning[:deprecated] = true
-Warning[:performance] = true
-```
-
-You can suppress a category by prefixing `no-` to the category name:
-
-```
-$ ruby -W:no-experimental -e 'p IO::Buffer.new'
-#<IO::Buffer>
-```
-
-### `-x`: Execute Ruby Code Found in Text
-
-Option `-x` executes a Ruby program whose code is embedded
-in other, non-code, text:
-
-The ruby code:
-
-- Begins after the first line beginning with `'#!` and containing string `'ruby'`.
-- Ends before any one of:
-
- - End-of-file.
- - A line consisting of `'__END__'`,
- - Character `Ctrl-D` or `Ctrl-Z`.
-
-Example:
-
-```sh
-$ cat t.txt
-Leading garbage.
-#!ruby
-puts File.basename(Dir.pwd)
-__END__
-Trailing garbage.
-
-$ ruby -x t.txt
-ruby
-```
-
-The optional argument specifies the directory where the text file
-is to be found;
-the Ruby code is executed in that directory:
-
-```sh
-$ cp t.txt /tmp/
-$ ruby -x/tmp t.txt
-tmp
-$
-
-```
-
-If an argument is given, it must immediately follow the option
-(no intervening whitespace or equal-sign character `'='`).
-
-### `--backtrace-limit`: \Set Backtrace Limit
-
-Option `--backtrace-limit` sets a limit on the number of entries
-to be displayed in a backtrace.
-
-See Thread::Backtrace.limit.
-
-### `--copyright`: Print Ruby Copyright
-
-Option `--copyright` prints a copyright message:
-
-```sh
-$ ruby --copyright
-ruby - Copyright (C) 1993-2024 Yukihiro Matsumoto
-```
-
-### `--debug`: Alias for `-d`
-
-Option `--debug` is an alias for
-{option -d}[rdoc-ref:ruby/options.md@d-3A+Set+-24DEBUG+to+true].
-
-### `--disable`: Disable Features
-
-Option `--disable` specifies features to be disabled;
-the argument is a comma-separated list of the features to be disabled:
-
-```sh
-ruby --disable=gems,rubyopt t.rb
-```
-
-The supported features:
-
-- `gems`: Rubygems (default: enabled).
-- `did_you_mean`: [`did_you_mean`](https://github.com/ruby/did_you_mean) (default: enabled).
-- `rubyopt`: `RUBYOPT` environment variable (default: enabled).
-- `frozen-string-literal`: Freeze all string literals (default: disabled).
-- `jit`: JIT compiler (default: disabled).
-
-See also {option --enable}[options_md.html#label--enable-3A+Enable+Features].
-
-### `--dump`: Dump Items
-
-Option `--dump` specifies items to be dumped;
-the argument is a comma-separated list of the items.
-
-Some of the argument values cause the command to behave as if a different
-option was given:
-
-- `--dump=copyright`:
- Same as {option \-\-copyright}[options_md.html#label--copyright-3A+Print+Ruby+Copyright].
-- `--dump=help`:
- Same as {option \-\-help}[options_md.html#label--help-3A+Print+Help+Message].
-- `--dump=syntax`:
- Same as {option -c}[rdoc-ref:ruby/options.md@c-3A+Check+Syntax].
-- `--dump=usage`:
- Same as {option -h}[rdoc-ref:ruby/options.md@h-3A+Print+Short+Help+Message].
-- `--dump=version`:
- Same as {option \-\-version}[options_md.html#label--version-3A+Print+Ruby+Version].
-
-For other argument values and examples,
-see {Option --dump}[option_dump_md.html].
-
-### `--enable`: Enable Features
-
-Option `--enable` specifies features to be enabled;
-the argument is a comma-separated list of the features to be enabled.
-
-```sh
-ruby --enable=gems,rubyopt t.rb
-```
-
-For the features,
-see {option --disable}[options_md.html#label--disable-3A+Disable+Features].
-
-### `--encoding`: Alias for `-E`.
-
-Option `--encoding` is an alias for
-{option -E}[rdoc-ref:ruby/options.md@E-3A+Set+Default+Encodings].
-
-### `--external-encoding`: \Set Default External \Encoding
-
-Option `--external-encoding`
-sets the default external encoding for the invoked Ruby program;
-for values of +encoding+,
-see {Encoding: Names and Aliases}[rdoc-ref:encodings.rdoc@Names+and+Aliases].
-
-```sh
-$ ruby -e 'puts Encoding::default_external'
-UTF-8
-$ ruby --external-encoding=cesu-8 -e 'puts Encoding::default_external'
-CESU-8
-```
-
-### `--help`: Print Help Message
-
-Option `--help` prints a long help message.
-
-Arguments and additional options are ignored.
-
-For a shorter help message, use option `-h`.
-
-### `--internal-encoding`: \Set Default Internal \Encoding
-
-Option `--internal-encoding`
-sets the default internal encoding for the invoked Ruby program;
-for values of +encoding+,
-see {Encoding: Names and Aliases}[rdoc-ref:encodings.rdoc@Names+and+Aliases].
-
-```sh
-$ ruby -e 'puts Encoding::default_internal.nil?'
-true
-$ ruby --internal-encoding=cesu-8 -e 'puts Encoding::default_internal'
-CESU-8
-```
-
-### `--verbose`: \Set `$VERBOSE`
-
-Option `--verbose` sets global variable `$VERBOSE` to `true`
-and disables input from `$stdin`.
-
-### `--version`: Print Ruby Version
-
-Option `--version` prints the version of the Ruby interpreter, then exits.
-
-## Experimental Options
-
-These options are experimental in the current Ruby release,
-and may be modified or withdrawn in later releases.
-
-### `--jit`
-
-Option `-jit` enables JIT compilation with the default option.
-
-#### `--jit-debug`
-
-Option `--jit-debug` enables JIT debugging (very slow);
-adds compiler flags if given.
-
-#### `--jit-max-cache=num`
-
-Option `--jit-max-cache=num` sets the maximum number of methods
-to be JIT-ed in a cache; default: 100).
-
-#### `--jit-min-calls=num`
-
-Option `jit-min-calls=num` sets the minimum number of calls to trigger JIT
-(for testing); default: 10000).
-
-#### `--jit-save-temps`
-
-Option `--jit-save-temps` saves JIT temporary files in $TMP or /tmp (for testing).
-
-#### `--jit-verbose`
-
-Option `--jit-verbose` prints JIT logs of level `num` or less
-to `$stderr`; default: 0.
-
-#### `--jit-wait`
-
-Option `--jit-wait` waits until JIT compilation finishes every time (for testing).
-
-#### `--jit-warnings`
-
-Option `--jit-warnings` enables printing of JIT warnings.
-
diff --git a/doc/security.rdoc b/doc/security.rdoc
index e428036cf5..ae20ed30fa 100644
--- a/doc/security.rdoc
+++ b/doc/security.rdoc
@@ -37,7 +37,7 @@ programs for configuration and database persistence of Ruby object trees.
Similar to +Marshal+, it is able to deserialize into arbitrary Ruby classes.
For example, the following YAML data will create an +ERB+ object when
-deserialized, using the `unsafe_load` method:
+deserialized:
!ruby/object:ERB
src: puts `uname`
diff --git a/doc/standard_library.rdoc b/doc/standard_library.rdoc
index a9fca632f8..7c9938c5b0 100644
--- a/doc/standard_library.rdoc
+++ b/doc/standard_library.rdoc
@@ -23,43 +23,43 @@ Socket:: Access underlying OS socket implementations
= Default gems
-* default gems are shipped with Ruby releases and also available as rubygems.
-* default gems are not uninstallable from Ruby installation.
-* default gems can be updated used by rubygems.
- * e.g. `gem update json`
-* default gems can be used with bundler environment like `unbundled_env`.
-* default gems can be used any version on Gemfile.
- * e.g. `gem "json", ">= 2.6"`
-
== Libraries
+Abbrev:: Calculates a set of unique abbreviations for a given set of strings
+Base64:: Support for encoding and decoding binary data using a Base64 representation
Benchmark:: Provides methods to measure and report the time used to execute code
Bundler:: Manage your Ruby application's gem dependencies
CGI:: Support for the Common Gateway Interface protocol
+CSV:: Provides an interface to read and write CSV files and data
Delegator:: Provides three abilities to delegate method calls to an object
DidYouMean:: "Did you mean?" experience in Ruby
+DRb:: Distributed object system for Ruby
English:: Provides references to special global variables with less cryptic names
ERB:: An easy to use but powerful templating system for Ruby
ErrorHighlight:: Highlight error location in your code
FileUtils:: Several file utility methods for copying, moving, removing, etc
Find:: This module supports top-down traversal of a set of file paths
Forwardable:: Provides delegation of specified methods to a designated object
+GetoptLong:: Parse command line options similar to the GNU C getopt_long()
IPAddr:: Provides methods to manipulate IPv4 and IPv6 IP addresses
IRB:: Interactive Ruby command-line tool for REPL (Read Eval Print Loop)
OptionParser:: Ruby-oriented class for command-line option analysis
Logger:: Provides a simple logging utility for outputting messages
+Mutex_m:: Mixin to extend objects to be handled like a Mutex
Net::HTTP:: HTTP client api for Ruby
+Observable:: Provides a mechanism for publish/subscribe pattern in Ruby
Open3:: Provides access to stdin, stdout and stderr when running other programs
OpenStruct:: Class to build custom data structures, similar to a Hash
OpenURI:: An easy-to-use wrapper for Net::HTTP, Net::HTTPS and Net::FTP
PP:: Provides a PrettyPrinter for Ruby objects
PrettyPrinter:: Implements a pretty printing algorithm for readable structure
-Prism:: A portable, error-tolerant Ruby parser
PStore:: Implements a file based persistence mechanism based on a Hash
Readline:: Wrapper for Readline extencion and Reline
Reline:: GNU Readline and Editline by pure Ruby implementation.
Resolv:: Thread-aware DNS resolver library in Ruby
+resolv-replace.rb:: Replace Socket DNS with Resolv
RDoc:: Produces HTML and command-line documentation for Ruby
+Rinda:: The Linda distributed computing paradigm in Ruby
SecureRandom:: Interface for secure random number generator
Set:: Provides a class to deal with collections of unordered, unique values
Shellwords:: Manipulates strings with word parsing rules of UNIX Bourne shell
@@ -76,6 +76,7 @@ WeakRef:: Allows a referenced object to be garbage-collected
== Extensions
+BigDecimal:: Provides arbitrary-precision floating point decimal arithmetic
Date:: A subclass of Object includes Comparable module for handling dates
DateTime:: Subclass of Date to handling dates, hours, minutes, seconds, offsets
Digest:: Provides a framework for message digest libraries
@@ -84,22 +85,20 @@ Fcntl:: Loads constants defined in the OS fcntl.h C header file
Fiddle:: A libffi wrapper for Ruby
IO:: Extensions for Ruby IO class, including #wait, #nonblock and ::console
JSON:: Implements Javascript Object Notation for Ruby
+NKF:: Ruby extension for Network Kanji Filter
OpenSSL:: Provides SSL, TLS and general purpose cryptography for Ruby
Pathname:: Representation of the name of a file or directory on the filesystem
Psych:: A YAML parser and emitter for Ruby
+Racc:: A LALR(1) parser generator written in Ruby.
+Readline:: Provides an interface for GNU Readline and Edit Line (libedit)
StringIO:: Pseudo I/O on String objects
StringScanner:: Provides lexical scanning operations on a String
+Syslog:: Ruby interface for the POSIX system logging facility
WIN32OLE:: Provides an interface for OLE Automation in Ruby
Zlib:: Ruby interface for the zlib compression/decompression library
= Bundled gems
-* bundled gems are shipped with Ruby releases and also available as rubygems.
-* bundled gems are same as normal gems like `rails`, `rack`.
- * They are only bundled with Ruby releases.
- * They can be uninstallable from Ruby installation.
- * They are needed to declare in Gemfile when use with bundler.
-
== Libraries
MiniTest:: A test suite with TDD, BDD, mocking and benchmarking
@@ -117,16 +116,3 @@ Prime:: Prime numbers and factorization library
RBS:: RBS is a language to describe the structure of Ruby programs
TypeProf:: A type analysis tool for Ruby code based on abstract interpretation
DEBUGGER__:: Debugging functionality for Ruby
-Racc:: A LALR(1) parser generator written in Ruby.
-Mutex_m:: Mixin to extend objects to be handled like a Mutex
-GetoptLong:: Parse command line options similar to the GNU C getopt_long()
-Base64:: Support for encoding and decoding binary data using a Base64 representation
-BigDecimal:: Provides arbitrary-precision floating point decimal arithmetic
-Observable:: Provides a mechanism for publish/subscribe pattern in Ruby
-Abbrev:: Calculates a set of unique abbreviations for a given set of strings
-resolv-replace.rb:: Replace Socket DNS with Resolv
-Rinda:: The Linda distributed computing paradigm in Ruby
-DRb:: Distributed object system for Ruby
-NKF:: Ruby extension for Network Kanji Filter
-Syslog:: Ruby interface for the POSIX system logging facility
-CSV:: Provides an interface to read and write CSV files and data
diff --git a/doc/strftime_formatting.rdoc b/doc/strftime_formatting.rdoc
index 5c7b33155d..30a629bf68 100644
--- a/doc/strftime_formatting.rdoc
+++ b/doc/strftime_formatting.rdoc
@@ -1,4 +1,4 @@
-= Formats for Dates and Times
+== Formats for Dates and Times
Several Ruby time-related classes have instance method +strftime+,
which returns a formatted string representing all or part of a date or time:
@@ -32,9 +32,9 @@ It consists of:
Except for the leading percent character,
the only required part is the conversion specifier, so we begin with that.
-== Conversion Specifiers
+=== Conversion Specifiers
-=== \Date (Year, Month, Day)
+==== \Date (Year, Month, Day)
- <tt>%Y</tt> - Year including century, zero-padded:
@@ -87,7 +87,7 @@ the only required part is the conversion specifier, so we begin with that.
Time.new(2002, 1, 1).strftime('%j') # => "001"
Time.new(2002, 12, 31).strftime('%j') # => "365"
-=== \Time (Hour, Minute, Second, Subsecond)
+==== \Time (Hour, Minute, Second, Subsecond)
- <tt>%H</tt> - Hour of the day, in range (0..23), zero-padded:
@@ -152,7 +152,7 @@ the only required part is the conversion specifier, so we begin with that.
Time.now.strftime('%s') # => "1656505136"
-=== Timezone
+==== Timezone
- <tt>%z</tt> - Timezone as hour and minute offset from UTC:
@@ -162,7 +162,7 @@ the only required part is the conversion specifier, so we begin with that.
Time.now.strftime('%Z') # => "Central Daylight Time"
-=== Weekday
+==== Weekday
- <tt>%A</tt> - Full weekday name:
@@ -184,7 +184,7 @@ the only required part is the conversion specifier, so we begin with that.
t.strftime('%a') # => "Sun"
t.strftime('%w') # => "0"
-=== Week Number
+==== Week Number
- <tt>%U</tt> - Week number of the year, in range (0..53), zero-padded,
where each week begins on a Sunday:
@@ -200,7 +200,7 @@ the only required part is the conversion specifier, so we begin with that.
t.strftime('%a') # => "Sun"
t.strftime('%W') # => "25"
-=== Week Dates
+==== Week Dates
See {ISO 8601 week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates].
@@ -223,7 +223,7 @@ See {ISO 8601 week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates].
t0.strftime('%V') # => "52"
t1.strftime('%V') # => "01"
-=== Literals
+==== Literals
- <tt>%n</tt> - Newline character "\n":
@@ -237,7 +237,7 @@ See {ISO 8601 week dates}[https://en.wikipedia.org/wiki/ISO_8601#Week_dates].
Time.now.strftime('%%') # => "%"
-=== Shorthand Conversion Specifiers
+==== Shorthand Conversion Specifiers
Each shorthand specifier here is shown with its corresponding
longhand specifier.
@@ -294,14 +294,14 @@ longhand specifier.
DateTime.now.strftime('%a %b %e %H:%M:%S %Z %Y')
# => "Wed Jun 29 08:32:18 -05:00 2022"
-== Flags
+=== Flags
Flags may affect certain formatting specifications.
Multiple flags may be given with a single conversion specified;
order does not matter.
-=== Padding Flags
+==== Padding Flags
- <tt>0</tt> - Pad with zeroes:
@@ -315,7 +315,7 @@ order does not matter.
Time.new(10).strftime('%-Y') # => "10"
-=== Casing Flags
+==== Casing Flags
- <tt>^</tt> - Upcase result:
@@ -328,7 +328,7 @@ order does not matter.
Time.now.strftime('%^p') # => "AM"
Time.now.strftime('%#p') # => "am"
-=== Timezone Flags
+==== Timezone Flags
- <tt>:</tt> - Put timezone as colon-separated hours and minutes:
@@ -338,7 +338,7 @@ order does not matter.
Time.now.strftime('%::z') # => "-05:00:00"
-== Width Specifiers
+=== Width Specifiers
The integer width specifier gives a minimum width for the returned string:
@@ -348,15 +348,15 @@ The integer width specifier gives a minimum width for the returned string:
Time.new(2002, 12).strftime('%10B') # => " December"
Time.new(2002, 12).strftime('%3B') # => "December" # Ignored if too small.
-= Specialized Format Strings
+== Specialized Format Strings
Here are a few specialized format strings,
each based on an external standard.
-== HTTP Format
+=== HTTP Format
The HTTP date format is based on
-{RFC 2616}[https://www.rfc-editor.org/rfc/rfc2616],
+{RFC 2616}[https://datatracker.ietf.org/doc/html/rfc2616],
and treats dates in the format <tt>'%a, %d %b %Y %T GMT'</tt>:
d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
@@ -368,10 +368,10 @@ and treats dates in the format <tt>'%a, %d %b %Y %T GMT'</tt>:
Date._httpdate(httpdate)
# => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"GMT", :offset=>0}
-== RFC 3339 Format
+=== RFC 3339 Format
The RFC 3339 date format is based on
-{RFC 3339}[https://www.rfc-editor.org/rfc/rfc3339]:
+{RFC 3339}[https://datatracker.ietf.org/doc/html/rfc3339]:
d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
# Return 3339-formatted string.
@@ -382,10 +382,10 @@ The RFC 3339 date format is based on
Date._rfc3339(rfc3339)
# => {:year=>2001, :mon=>2, :mday=>3, :hour=>0, :min=>0, :sec=>0, :zone=>"+00:00", :offset=>0}
-== RFC 2822 Format
+=== RFC 2822 Format
The RFC 2822 date format is based on
-{RFC 2822}[https://www.rfc-editor.org/rfc/rfc2822],
+{RFC 2822}[https://datatracker.ietf.org/doc/html/rfc2822],
and treats dates in the format <tt>'%a, %-d %b %Y %T %z'</tt>]:
d = Date.new(2001, 2, 3) # => #<Date: 2001-02-03>
@@ -397,7 +397,7 @@ and treats dates in the format <tt>'%a, %-d %b %Y %T %z'</tt>]:
Date._rfc2822(rfc2822)
# => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"+0000", :offset=>0}
-== JIS X 0301 Format
+=== JIS X 0301 Format
The JIS X 0301 format includes the
{Japanese era name}[https://en.wikipedia.org/wiki/Japanese_era_name],
@@ -412,7 +412,7 @@ with the first letter of the romanized era name prefixed:
# Return hash parsed from 0301-formatted string.
Date._jisx0301(jisx0301) # => {:year=>2001, :mon=>2, :mday=>3}
-== ISO 8601 Format Specifications
+=== ISO 8601 Format Specifications
This section shows format specifications that are compatible with
{ISO 8601}[https://en.wikipedia.org/wiki/ISO_8601].
@@ -422,7 +422,7 @@ Examples in this section assume:
t = Time.now # => 2022-06-29 16:49:25.465246 -0500
-=== Dates
+==== Dates
See {ISO 8601 dates}[https://en.wikipedia.org/wiki/ISO_8601#Dates].
@@ -473,7 +473,7 @@ See {ISO 8601 dates}[https://en.wikipedia.org/wiki/ISO_8601#Dates].
t.strftime('%Y-%j') # => "2022-180"
-=== Times
+==== Times
See {ISO 8601 times}[https://en.wikipedia.org/wiki/ISO_8601#Times].
@@ -514,7 +514,7 @@ See {ISO 8601 times}[https://en.wikipedia.org/wiki/ISO_8601#Times].
- {Coordinated Universal Time (UTC)}[https://en.wikipedia.org/wiki/ISO_8601#Coordinated_Universal_Time_(UTC)].
- {Time offsets from UTC}[https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC].
-=== Combined \Date and \Time
+==== Combined \Date and \Time
See {ISO 8601 Combined date and time representations}[https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations].
diff --git a/doc/string/encode.rdoc b/doc/string/encode.rdoc
deleted file mode 100644
index 65872fdfd4..0000000000
--- a/doc/string/encode.rdoc
+++ /dev/null
@@ -1,47 +0,0 @@
-Returns a copy of +self+ transcoded as determined by +dst_encoding+.
-By default, raises an exception if +self+
-contains an invalid byte or a character not defined in +dst_encoding+;
-that behavior may be modified by encoding options; see below.
-
-With no arguments:
-
-- Uses the same encoding if <tt>Encoding.default_internal</tt> is +nil+
- (the default):
-
- Encoding.default_internal # => nil
- s = "Ruby\x99".force_encoding('Windows-1252')
- s.encoding # => #<Encoding:Windows-1252>
- s.bytes # => [82, 117, 98, 121, 153]
- t = s.encode # => "Ruby\x99"
- t.encoding # => #<Encoding:Windows-1252>
- t.bytes # => [82, 117, 98, 121, 226, 132, 162]
-
-- Otherwise, uses the encoding <tt>Encoding.default_internal</tt>:
-
- Encoding.default_internal = 'UTF-8'
- t = s.encode # => "Rubyâ„¢"
- t.encoding # => #<Encoding:UTF-8>
-
-With only argument +dst_encoding+ given, uses that encoding:
-
- s = "Ruby\x99".force_encoding('Windows-1252')
- s.encoding # => #<Encoding:Windows-1252>
- t = s.encode('UTF-8') # => "Rubyâ„¢"
- t.encoding # => #<Encoding:UTF-8>
-
-With arguments +dst_encoding+ and +src_encoding+ given,
-interprets +self+ using +src_encoding+, encodes the new string using +dst_encoding+:
-
- s = "Ruby\x99"
- t = s.encode('UTF-8', 'Windows-1252') # => "Rubyâ„¢"
- t.encoding # => #<Encoding:UTF-8>
-
-Optional keyword arguments +enc_opts+ specify encoding options;
-see {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
-
-Please note that, unless <code>invalid: :replace</code> option is
-given, conversion from an encoding +enc+ to the same encoding +enc+
-(independent of whether +enc+ is given explicitly or implicitly) is a
-no-op, i.e. the string is simply copied without any changes, and no
-exceptions are raised, even if there are invalid bytes.
-
diff --git a/doc/string/length.rdoc b/doc/string/length.rdoc
index 544bca269f..0a7e17f7dc 100644
--- a/doc/string/length.rdoc
+++ b/doc/string/length.rdoc
@@ -10,3 +10,4 @@ Contrast with String#bytesize:
'теÑÑ‚'.bytesize # => 8
'ã“ã‚“ã«ã¡ã¯'.bytesize # => 15
+String#size is an alias for String#length.
diff --git a/doc/string/new.rdoc b/doc/string/new.rdoc
index 1d44291f76..d955e61c87 100644
--- a/doc/string/new.rdoc
+++ b/doc/string/new.rdoc
@@ -46,10 +46,6 @@ which may in turn affect performance:
String.new(capacity: 1)
String.new('foo', capacity: 4096)
-Note that Ruby strings are null-terminated internally, so the internal
-buffer size will be one or more bytes larger than the requested capacity
-depending on the encoding.
-
The +string+, +encoding+, and +capacity+ arguments may all be used together:
String.new('hello', encoding: 'UTF-8', capacity: 25)
diff --git a/doc/string/split.rdoc b/doc/string/split.rdoc
index 5ab065093b..2b5e14ddb6 100644
--- a/doc/string/split.rdoc
+++ b/doc/string/split.rdoc
@@ -9,7 +9,7 @@ When +field_sep+ is <tt>$;</tt>:
(see below).
- If <tt>$;</tt> is a string,
- the split occurs just as if +field_sep+ were given as that string
+ the split ocurs just as if +field_sep+ were given as that string
(see below).
When +field_sep+ is <tt>' '</tt> and +limit+ is +nil+,
diff --git a/doc/strscan/helper_methods.md b/doc/strscan/helper_methods.md
deleted file mode 100644
index 6555a2ce66..0000000000
--- a/doc/strscan/helper_methods.md
+++ /dev/null
@@ -1,128 +0,0 @@
-## Helper Methods
-
-These helper methods display values returned by scanner's methods.
-
-### `put_situation(scanner)`
-
-Display scanner's situation:
-
-- Byte position (`#pos`).
-- Character position (`#charpos`)
-- Target string (`#rest`) and size (`#rest_size`).
-
-```
-scanner = StringScanner.new('foobarbaz')
-scanner.scan(/foo/)
-put_situation(scanner)
-# Situation:
-# pos: 3
-# charpos: 3
-# rest: "barbaz"
-# rest_size: 6
-```
-
-### `put_match_values(scanner)`
-
-Display the scanner's match values:
-
-```
-scanner = StringScanner.new('Fri Dec 12 1975 14:39')
-pattern = /(?<wday>\w+) (?<month>\w+) (?<day>\d+) /
-scanner.match?(pattern)
-put_match_values(scanner)
-# Basic match values:
-# matched?: true
-# matched_size: 11
-# pre_match: ""
-# matched : "Fri Dec 12 "
-# post_match: "1975 14:39"
-# Captured match values:
-# size: 4
-# captures: ["Fri", "Dec", "12"]
-# named_captures: {"wday"=>"Fri", "month"=>"Dec", "day"=>"12"}
-# values_at: ["Fri Dec 12 ", "Fri", "Dec", "12", nil]
-# []:
-# [0]: "Fri Dec 12 "
-# [1]: "Fri"
-# [2]: "Dec"
-# [3]: "12"
-# [4]: nil
-```
-
-### `match_values_cleared?(scanner)`
-
-Returns whether the scanner's match values are all properly cleared:
-
-```
-scanner = StringScanner.new('foobarbaz')
-match_values_cleared?(scanner) # => true
-put_match_values(scanner)
-# Basic match values:
-# matched?: false
-# matched_size: nil
-# pre_match: nil
-# matched : nil
-# post_match: nil
-# Captured match values:
-# size: nil
-# captures: nil
-# named_captures: {}
-# values_at: nil
-# [0]: nil
-scanner.scan(/foo/)
-match_values_cleared?(scanner) # => false
-```
-
-## The Code
-
-```
-def put_situation(scanner)
- puts '# Situation:'
- puts "# pos: #{scanner.pos}"
- puts "# charpos: #{scanner.charpos}"
- puts "# rest: #{scanner.rest.inspect}"
- puts "# rest_size: #{scanner.rest_size}"
-end
-```
-
-```
-def put_match_values(scanner)
- puts '# Basic match values:'
- puts "# matched?: #{scanner.matched?}"
- value = scanner.matched_size || 'nil'
- puts "# matched_size: #{value}"
- puts "# pre_match: #{scanner.pre_match.inspect}"
- puts "# matched : #{scanner.matched.inspect}"
- puts "# post_match: #{scanner.post_match.inspect}"
- puts '# Captured match values:'
- puts "# size: #{scanner.size}"
- puts "# captures: #{scanner.captures}"
- puts "# named_captures: #{scanner.named_captures}"
- if scanner.size.nil?
- puts "# values_at: #{scanner.values_at(0)}"
- puts "# [0]: #{scanner[0]}"
- else
- puts "# values_at: #{scanner.values_at(*(0..scanner.size))}"
- puts "# []:"
- scanner.size.times do |i|
- puts "# [#{i}]: #{scanner[i].inspect}"
- end
- end
-end
-```
-
-```
-def match_values_cleared?(scanner)
- scanner.matched? == false &&
- scanner.matched_size.nil? &&
- scanner.matched.nil? &&
- scanner.pre_match.nil? &&
- scanner.post_match.nil? &&
- scanner.size.nil? &&
- scanner[0].nil? &&
- scanner.captures.nil? &&
- scanner.values_at(0..1).nil? &&
- scanner.named_captures == {}
-end
-```
-
diff --git a/doc/strscan/link_refs.txt b/doc/strscan/link_refs.txt
deleted file mode 100644
index 19f6f7ce5c..0000000000
--- a/doc/strscan/link_refs.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-[1]: rdoc-ref:StringScanner@Stored+String
-[2]: rdoc-ref:StringScanner@Byte+Position+-28Position-29
-[3]: rdoc-ref:StringScanner@Target+Substring
-[4]: rdoc-ref:StringScanner@Setting+the+Target+Substring
-[5]: rdoc-ref:StringScanner@Traversing+the+Target+Substring
-[6]: https://docs.ruby-lang.org/en/master/Regexp.html
-[7]: rdoc-ref:StringScanner@Character+Position
-[8]: https://docs.ruby-lang.org/en/master/String.html#method-i-5B-5D
-[9]: rdoc-ref:StringScanner@Match+Values
-[10]: rdoc-ref:StringScanner@Fixed-Anchor+Property
-[11]: rdoc-ref:StringScanner@Positions
-[13]: rdoc-ref:StringScanner@Captured+Match+Values
-[14]: rdoc-ref:StringScanner@Querying+the+Target+Substring
-[15]: rdoc-ref:StringScanner@Searching+the+Target+Substring
-[16]: https://docs.ruby-lang.org/en/master/Regexp.html#class-Regexp-label-Groups+and+Captures
-[17]: rdoc-ref:StringScanner@Matching
-[18]: rdoc-ref:StringScanner@Basic+Match+Values
diff --git a/doc/strscan/methods/get_byte.md b/doc/strscan/methods/get_byte.md
deleted file mode 100644
index 2f23be1899..0000000000
--- a/doc/strscan/methods/get_byte.md
+++ /dev/null
@@ -1,30 +0,0 @@
-call-seq:
- get_byte -> byte_as_character or nil
-
-Returns the next byte, if available:
-
-- If the [position][2]
- is not at the end of the [stored string][1]:
-
- - Returns the next byte.
- - Increments the [byte position][2].
- - Adjusts the [character position][7].
-
- ```
- scanner = StringScanner.new(HIRAGANA_TEXT)
- # => #<StringScanner 0/15 @ "\xE3\x81\x93\xE3\x82...">
- scanner.string # => "ã“ã‚“ã«ã¡ã¯"
- [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\xE3", 1, 1]
- [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\x81", 2, 2]
- [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\x93", 3, 1]
- [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\xE3", 4, 2]
- [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\x82", 5, 3]
- [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\x93", 6, 2]
- ```
-
-- Otherwise, returns `nil`, and does not change the positions.
-
- ```
- scanner.terminate
- [scanner.get_byte, scanner.pos, scanner.charpos] # => [nil, 15, 5]
- ```
diff --git a/doc/strscan/methods/get_charpos.md b/doc/strscan/methods/get_charpos.md
deleted file mode 100644
index f77563c860..0000000000
--- a/doc/strscan/methods/get_charpos.md
+++ /dev/null
@@ -1,19 +0,0 @@
-call-seq:
- charpos -> character_position
-
-Returns the [character position][7] (initially zero),
-which may be different from the [byte position][2]
-given by method #pos:
-
-```
-scanner = StringScanner.new(HIRAGANA_TEXT)
-scanner.string # => "ã“ã‚“ã«ã¡ã¯"
-scanner.getch # => "ã“" # 3-byte character.
-scanner.getch # => "ã‚“" # 3-byte character.
-put_situation(scanner)
-# Situation:
-# pos: 6
-# charpos: 2
-# rest: "ã«ã¡ã¯"
-# rest_size: 9
-```
diff --git a/doc/strscan/methods/get_pos.md b/doc/strscan/methods/get_pos.md
deleted file mode 100644
index 56bcef3274..0000000000
--- a/doc/strscan/methods/get_pos.md
+++ /dev/null
@@ -1,14 +0,0 @@
-call-seq:
- pos -> byte_position
-
-Returns the integer [byte position][2],
-which may be different from the [character position][7]:
-
-```
-scanner = StringScanner.new(HIRAGANA_TEXT)
-scanner.string # => "ã“ã‚“ã«ã¡ã¯"
-scanner.pos # => 0
-scanner.getch # => "ã“" # 3-byte character.
-scanner.charpos # => 1
-scanner.pos # => 3
-```
diff --git a/doc/strscan/methods/getch.md b/doc/strscan/methods/getch.md
deleted file mode 100644
index b57732ad7c..0000000000
--- a/doc/strscan/methods/getch.md
+++ /dev/null
@@ -1,43 +0,0 @@
-call-seq:
- getch -> character or nil
-
-Returns the next (possibly multibyte) character,
-if available:
-
-- If the [position][2]
- is at the beginning of a character:
-
- - Returns the character.
- - Increments the [character position][7] by 1.
- - Increments the [byte position][2]
- by the size (in bytes) of the character.
-
- ```
- scanner = StringScanner.new(HIRAGANA_TEXT)
- scanner.string # => "ã“ã‚“ã«ã¡ã¯"
- [scanner.getch, scanner.pos, scanner.charpos] # => ["ã“", 3, 1]
- [scanner.getch, scanner.pos, scanner.charpos] # => ["ã‚“", 6, 2]
- [scanner.getch, scanner.pos, scanner.charpos] # => ["ã«", 9, 3]
- [scanner.getch, scanner.pos, scanner.charpos] # => ["ã¡", 12, 4]
- [scanner.getch, scanner.pos, scanner.charpos] # => ["ã¯", 15, 5]
- [scanner.getch, scanner.pos, scanner.charpos] # => [nil, 15, 5]
- ```
-
-- If the [position][2] is within a multi-byte character
- (that is, not at its beginning),
- behaves like #get_byte (returns a 1-byte character):
-
- ```
- scanner.pos = 1
- [scanner.getch, scanner.pos, scanner.charpos] # => ["\x81", 2, 2]
- [scanner.getch, scanner.pos, scanner.charpos] # => ["\x93", 3, 1]
- [scanner.getch, scanner.pos, scanner.charpos] # => ["ã‚“", 6, 2]
- ```
-
-- If the [position][2] is at the end of the [stored string][1],
- returns `nil` and does not modify the positions:
-
- ```
- scanner.terminate
- [scanner.getch, scanner.pos, scanner.charpos] # => [nil, 15, 5]
- ```
diff --git a/doc/strscan/methods/scan.md b/doc/strscan/methods/scan.md
deleted file mode 100644
index 714fa9910a..0000000000
--- a/doc/strscan/methods/scan.md
+++ /dev/null
@@ -1,51 +0,0 @@
-call-seq:
- scan(pattern) -> substring or nil
-
-Attempts to [match][17] the given `pattern`
-at the beginning of the [target substring][3].
-
-If the match succeeds:
-
-- Returns the matched substring.
-- Increments the [byte position][2] by <tt>substring.bytesize</tt>,
- and may increment the [character position][7].
-- Sets [match values][9].
-
-```
-scanner = StringScanner.new(HIRAGANA_TEXT)
-scanner.string # => "ã“ã‚“ã«ã¡ã¯"
-scanner.pos = 6
-scanner.scan(/ã«/) # => "ã«"
-put_match_values(scanner)
-# Basic match values:
-# matched?: true
-# matched_size: 3
-# pre_match: "ã“ã‚“"
-# matched : "ã«"
-# post_match: "ã¡ã¯"
-# Captured match values:
-# size: 1
-# captures: []
-# named_captures: {}
-# values_at: ["ã«", nil]
-# []:
-# [0]: "ã«"
-# [1]: nil
-put_situation(scanner)
-# Situation:
-# pos: 9
-# charpos: 3
-# rest: "ã¡ã¯"
-# rest_size: 6
-```
-
-If the match fails:
-
-- Returns `nil`.
-- Does not increment byte and character positions.
-- Clears match values.
-
-```
-scanner.scan(/nope/) # => nil
-match_values_cleared?(scanner) # => true
-```
diff --git a/doc/strscan/methods/scan_until.md b/doc/strscan/methods/scan_until.md
deleted file mode 100644
index 3b7ff2c3a9..0000000000
--- a/doc/strscan/methods/scan_until.md
+++ /dev/null
@@ -1,52 +0,0 @@
-call-seq:
- scan_until(pattern) -> substring or nil
-
-Attempts to [match][17] the given `pattern`
-anywhere (at any [position][2]) in the [target substring][3].
-
-If the match attempt succeeds:
-
-- Sets [match values][9].
-- Sets the [byte position][2] to the end of the matched substring;
- may adjust the [character position][7].
-- Returns the matched substring.
-
-
-```
-scanner = StringScanner.new(HIRAGANA_TEXT)
-scanner.string # => "ã“ã‚“ã«ã¡ã¯"
-scanner.pos = 6
-scanner.scan_until(/ã¡/) # => "ã«ã¡"
-put_match_values(scanner)
-# Basic match values:
-# matched?: true
-# matched_size: 3
-# pre_match: "ã“ã‚“ã«"
-# matched : "ã¡"
-# post_match: "ã¯"
-# Captured match values:
-# size: 1
-# captures: []
-# named_captures: {}
-# values_at: ["ã¡", nil]
-# []:
-# [0]: "ã¡"
-# [1]: nil
-put_situation(scanner)
-# Situation:
-# pos: 12
-# charpos: 4
-# rest: "ã¯"
-# rest_size: 3
-```
-
-If the match attempt fails:
-
-- Clears match data.
-- Returns `nil`.
-- Does not update positions.
-
-```
-scanner.scan_until(/nope/) # => nil
-match_values_cleared?(scanner) # => true
-```
diff --git a/doc/strscan/methods/set_pos.md b/doc/strscan/methods/set_pos.md
deleted file mode 100644
index 230177109c..0000000000
--- a/doc/strscan/methods/set_pos.md
+++ /dev/null
@@ -1,27 +0,0 @@
-call-seq:
- pos = n -> n
- pointer = n -> n
-
-Sets the [byte position][2] and the [character position][11];
-returns `n`.
-
-Does not affect [match values][9].
-
-For non-negative `n`, sets the position to `n`:
-
-```
-scanner = StringScanner.new(HIRAGANA_TEXT)
-scanner.string # => "ã“ã‚“ã«ã¡ã¯"
-scanner.pos = 3 # => 3
-scanner.rest # => "ã‚“ã«ã¡ã¯"
-scanner.charpos # => 1
-```
-
-For negative `n`, counts from the end of the [stored string][1]:
-
-```
-scanner.pos = -9 # => -9
-scanner.pos # => 6
-scanner.rest # => "ã«ã¡ã¯"
-scanner.charpos # => 2
-```
diff --git a/doc/strscan/methods/skip.md b/doc/strscan/methods/skip.md
deleted file mode 100644
index 656f134c5a..0000000000
--- a/doc/strscan/methods/skip.md
+++ /dev/null
@@ -1,43 +0,0 @@
-call-seq:
- skip(pattern) match_size or nil
-
-Attempts to [match][17] the given `pattern`
-at the beginning of the [target substring][3];
-
-If the match succeeds:
-
-- Increments the [byte position][2] by substring.bytesize,
- and may increment the [character position][7].
-- Sets [match values][9].
-- Returns the size (bytes) of the matched substring.
-
-```
-scanner = StringScanner.new(HIRAGANA_TEXT)
-scanner.string # => "ã“ã‚“ã«ã¡ã¯"
-scanner.pos = 6
-scanner.skip(/ã«/) # => 3
-put_match_values(scanner)
-# Basic match values:
-# matched?: true
-# matched_size: 3
-# pre_match: "ã“ã‚“"
-# matched : "ã«"
-# post_match: "ã¡ã¯"
-# Captured match values:
-# size: 1
-# captures: []
-# named_captures: {}
-# values_at: ["ã«", nil]
-# []:
-# [0]: "ã«"
-# [1]: nil
-put_situation(scanner)
-# Situation:
-# pos: 9
-# charpos: 3
-# rest: "ã¡ã¯"
-# rest_size: 6
-
-scanner.skip(/nope/) # => nil
-match_values_cleared?(scanner) # => true
-```
diff --git a/doc/strscan/methods/skip_until.md b/doc/strscan/methods/skip_until.md
deleted file mode 100644
index 5187a4826f..0000000000
--- a/doc/strscan/methods/skip_until.md
+++ /dev/null
@@ -1,49 +0,0 @@
-call-seq:
- skip_until(pattern) -> matched_substring_size or nil
-
-Attempts to [match][17] the given `pattern`
-anywhere (at any [position][2]) in the [target substring][3];
-does not modify the positions.
-
-If the match attempt succeeds:
-
-- Sets [match values][9].
-- Returns the size of the matched substring.
-
-```
-scanner = StringScanner.new(HIRAGANA_TEXT)
-scanner.string # => "ã“ã‚“ã«ã¡ã¯"
-scanner.pos = 6
-scanner.skip_until(/ã¡/) # => 6
-put_match_values(scanner)
-# Basic match values:
-# matched?: true
-# matched_size: 3
-# pre_match: "ã“ã‚“ã«"
-# matched : "ã¡"
-# post_match: "ã¯"
-# Captured match values:
-# size: 1
-# captures: []
-# named_captures: {}
-# values_at: ["ã¡", nil]
-# []:
-# [0]: "ã¡"
-# [1]: nil
-put_situation(scanner)
-# Situation:
-# pos: 12
-# charpos: 4
-# rest: "ã¯"
-# rest_size: 3
-```
-
-If the match attempt fails:
-
-- Clears match values.
-- Returns `nil`.
-
-```
-scanner.skip_until(/nope/) # => nil
-match_values_cleared?(scanner) # => true
-```
diff --git a/doc/strscan/methods/terminate.md b/doc/strscan/methods/terminate.md
deleted file mode 100644
index fd55727099..0000000000
--- a/doc/strscan/methods/terminate.md
+++ /dev/null
@@ -1,30 +0,0 @@
-call-seq:
- terminate -> self
-
-Sets the scanner to end-of-string;
-returns +self+:
-
-- Sets both [positions][11] to end-of-stream.
-- Clears [match values][9].
-
-```
-scanner = StringScanner.new(HIRAGANA_TEXT)
-scanner.string # => "ã“ã‚“ã«ã¡ã¯"
-scanner.scan_until(/ã«/)
-put_situation(scanner)
-# Situation:
-# pos: 9
-# charpos: 3
-# rest: "ã¡ã¯"
-# rest_size: 6
-match_values_cleared?(scanner) # => false
-
-scanner.terminate # => #<StringScanner fin>
-put_situation(scanner)
-# Situation:
-# pos: 15
-# charpos: 5
-# rest: ""
-# rest_size: 0
-match_values_cleared?(scanner) # => true
-```
diff --git a/doc/strscan/strscan.md b/doc/strscan/strscan.md
deleted file mode 100644
index 465cebd4cb..0000000000
--- a/doc/strscan/strscan.md
+++ /dev/null
@@ -1,543 +0,0 @@
-\Class `StringScanner` supports processing a stored string as a stream;
-this code creates a new `StringScanner` object with string `'foobarbaz'`:
-
-```
-require 'strscan'
-scanner = StringScanner.new('foobarbaz')
-```
-
-## About the Examples
-
-All examples here assume that `StringScanner` has been required:
-
-```
-require 'strscan'
-```
-
-Some examples here assume that these constants are defined:
-
-```
-MULTILINE_TEXT = <<~EOT
-Go placidly amid the noise and haste,
-and remember what peace there may be in silence.
-EOT
-
-HIRAGANA_TEXT = 'ã“ã‚“ã«ã¡ã¯'
-
-ENGLISH_TEXT = 'Hello'
-```
-
-Some examples here assume that certain helper methods are defined:
-
-- `put_situation(scanner)`:
- Displays the values of the scanner's
- methods #pos, #charpos, #rest, and #rest_size.
-- `put_match_values(scanner)`:
- Displays the scanner's [match values][9].
-- `match_values_cleared?(scanner)`:
- Returns whether the scanner's [match values][9] are cleared.
-
-See examples [here][ext/strscan/helper_methods_md.html].
-
-## The `StringScanner` \Object
-
-This code creates a `StringScanner` object
-(we'll call it simply a _scanner_),
-and shows some of its basic properties:
-
-```
-scanner = StringScanner.new('foobarbaz')
-scanner.string # => "foobarbaz"
-put_situation(scanner)
-# Situation:
-# pos: 0
-# charpos: 0
-# rest: "foobarbaz"
-# rest_size: 9
-```
-
-The scanner has:
-
-* A <i>stored string</i>, which is:
-
- * Initially set by StringScanner.new(string) to the given `string`
- (`'foobarbaz'` in the example above).
- * Modifiable by methods #string=(new_string) and #concat(more_string).
- * Returned by method #string.
-
- More at [Stored String][1] below.
-
-* A _position_;
- a zero-based index into the bytes of the stored string (_not_ into its characters):
-
- * Initially set by StringScanner.new to `0`.
- * Returned by method #pos.
- * Modifiable explicitly by methods #reset, #terminate, and #pos=(new_pos).
- * Modifiable implicitly (various traversing methods, among others).
-
- More at [Byte Position][2] below.
-
-* A <i>target substring</i>,
- which is a trailing substring of the stored string;
- it extends from the current position to the end of the stored string:
-
- * Initially set by StringScanner.new(string) to the given `string`
- (`'foobarbaz'` in the example above).
- * Returned by method #rest.
- * Modified by any modification to either the stored string or the position.
-
- <b>Most importantly</b>:
- the searching and traversing methods operate on the target substring,
- which may be (and often is) less than the entire stored string.
-
- More at [Target Substring][3] below.
-
-## Stored \String
-
-The <i>stored string</i> is the string stored in the `StringScanner` object.
-
-Each of these methods sets, modifies, or returns the stored string:
-
-| Method | Effect |
-|----------------------|-------------------------------------------------|
-| ::new(string) | Creates a new scanner for the given string. |
-| #string=(new_string) | Replaces the existing stored string. |
-| #concat(more_string) | Appends a string to the existing stored string. |
-| #string | Returns the stored string. |
-
-## Positions
-
-A `StringScanner` object maintains a zero-based <i>byte position</i>
-and a zero-based <i>character position</i>.
-
-Each of these methods explicitly sets positions:
-
-| Method | Effect |
-|--------------------------|----------------------------------------------------------|
-| #reset | Sets both positions to zero (begining of stored string). |
-| #terminate | Sets both positions to the end of the stored string. |
-| #pos=(new_byte_position) | Sets byte position; adjusts character position. |
-
-### Byte Position (Position)
-
-The byte position (or simply _position_)
-is a zero-based index into the bytes in the scanner's stored string;
-for a new `StringScanner` object, the byte position is zero.
-
-When the byte position is:
-
-* Zero (at the beginning), the target substring is the entire stored string.
-* Equal to the size of the stored string (at the end),
- the target substring is the empty string `''`.
-
-To get or set the byte position:
-
-* \#pos: returns the byte position.
-* \#pos=(new_pos): sets the byte position.
-
-Many methods use the byte position as the basis for finding matches;
-many others set, increment, or decrement the byte position:
-
-```
-scanner = StringScanner.new('foobar')
-scanner.pos # => 0
-scanner.scan(/foo/) # => "foo" # Match found.
-scanner.pos # => 3 # Byte position incremented.
-scanner.scan(/foo/) # => nil # Match not found.
-scanner.pos # => 3 # Byte position not changed.
-```
-
-Some methods implicitly modify the byte position;
-see:
-
-* [Setting the Target Substring][4].
-* [Traversing the Target Substring][5].
-
-The values of these methods are derived directly from the values of #pos and #string:
-
-- \#charpos: the [character position][7].
-- \#rest: the [target substring][3].
-- \#rest_size: `rest.size`.
-
-### Character Position
-
-The character position is a zero-based index into the _characters_
-in the stored string;
-for a new `StringScanner` object, the character position is zero.
-
-\Method #charpos returns the character position;
-its value may not be reset explicitly.
-
-Some methods change (increment or reset) the character position;
-see:
-
-* [Setting the Target Substring][4].
-* [Traversing the Target Substring][5].
-
-Example (string includes multi-byte characters):
-
-```
-scanner = StringScanner.new(ENGLISH_TEXT) # Five 1-byte characters.
-scanner.concat(HIRAGANA_TEXT) # Five 3-byte characters
-scanner.string # => "Helloã“ã‚“ã«ã¡ã¯" # Twenty bytes in all.
-put_situation(scanner)
-# Situation:
-# pos: 0
-# charpos: 0
-# rest: "Helloã“ã‚“ã«ã¡ã¯"
-# rest_size: 20
-scanner.scan(/Hello/) # => "Hello" # Five 1-byte characters.
-put_situation(scanner)
-# Situation:
-# pos: 5
-# charpos: 5
-# rest: "ã“ã‚“ã«ã¡ã¯"
-# rest_size: 15
-scanner.getch # => "ã“" # One 3-byte character.
-put_situation(scanner)
-# Situation:
-# pos: 8
-# charpos: 6
-# rest: "ã‚“ã«ã¡ã¯"
-# rest_size: 12```
-
-## Target Substring
-
-The target substring is the the part of the [stored string][1]
-that extends from the current [byte position][2] to the end of the stored string;
-it is always either:
-
-- The entire stored string (byte position is zero).
-- A trailing substring of the stored string (byte position positive).
-
-The target substring is returned by method #rest,
-and its size is returned by method #rest_size.
-
-Examples:
-
-```
-scanner = StringScanner.new('foobarbaz')
-put_situation(scanner)
-# Situation:
-# pos: 0
-# charpos: 0
-# rest: "foobarbaz"
-# rest_size: 9
-scanner.pos = 3
-put_situation(scanner)
-# Situation:
-# pos: 3
-# charpos: 3
-# rest: "barbaz"
-# rest_size: 6
-scanner.pos = 9
-put_situation(scanner)
-# Situation:
-# pos: 9
-# charpos: 9
-# rest: ""
-# rest_size: 0
-```
-
-### Setting the Target Substring
-
-The target substring is set whenever:
-
-* The [stored string][1] is set (position reset to zero; target substring set to stored string).
-* The [byte position][2] is set (target substring adjusted accordingly).
-
-### Querying the Target Substring
-
-This table summarizes (details and examples at the links):
-
-| Method | Returns |
-|------------|-----------------------------------|
-| #rest | Target substring. |
-| #rest_size | Size (bytes) of target substring. |
-
-### Searching the Target Substring
-
-A _search_ method examines the target substring,
-but does not advance the [positions][11]
-or (by implication) shorten the target substring.
-
-This table summarizes (details and examples at the links):
-
-| Method | Returns | Sets Match Values? |
-|-----------------------|-----------------------------------------------|--------------------|
-| #check(pattern) | Matched leading substring or +nil+. | Yes. |
-| #check_until(pattern) | Matched substring (anywhere) or +nil+. | Yes. |
-| #exist?(pattern) | Matched substring (anywhere) end index. | Yes. |
-| #match?(pattern) | Size of matched leading substring or +nil+. | Yes. |
-| #peek(size) | Leading substring of given length (bytes). | No. |
-| #peek_byte | Integer leading byte or +nil+. | No. |
-| #rest | Target substring (from byte position to end). | No. |
-
-### Traversing the Target Substring
-
-A _traversal_ method examines the target substring,
-and, if successful:
-
-- Advances the [positions][11].
-- Shortens the target substring.
-
-
-This table summarizes (details and examples at links):
-
-| Method | Returns | Sets Match Values? |
-|----------------------|------------------------------------------------------|--------------------|
-| #get_byte | Leading byte or +nil+. | No. |
-| #getch | Leading character or +nil+. | No. |
-| #scan(pattern) | Matched leading substring or +nil+. | Yes. |
-| #scan_byte | Integer leading byte or +nil+. | No. |
-| #scan_until(pattern) | Matched substring (anywhere) or +nil+. | Yes. |
-| #skip(pattern) | Matched leading substring size or +nil+. | Yes. |
-| #skip_until(pattern) | Position delta to end-of-matched-substring or +nil+. | Yes. |
-| #unscan | +self+. | No. |
-
-## Querying the Scanner
-
-Each of these methods queries the scanner object
-without modifying it (details and examples at links)
-
-| Method | Returns |
-|---------------------|----------------------------------|
-| #beginning_of_line? | +true+ or +false+. |
-| #charpos | Character position. |
-| #eos? | +true+ or +false+. |
-| #fixed_anchor? | +true+ or +false+. |
-| #inspect | String representation of +self+. |
-| #pos | Byte position. |
-| #rest | Target substring. |
-| #rest_size | Size of target substring. |
-| #string | Stored string. |
-
-## Matching
-
-`StringScanner` implements pattern matching via Ruby class [Regexp][6],
-and its matching behaviors are the same as Ruby's
-except for the [fixed-anchor property][10].
-
-### Matcher Methods
-
-Each <i>matcher method</i> takes a single argument `pattern`,
-and attempts to find a matching substring in the [target substring][3].
-
-| Method | Pattern Type | Matches Target Substring | Success Return | May Update Positions? |
-|--------------|-------------------|--------------------------|--------------------|-----------------------|
-| #check | Regexp or String. | At beginning. | Matched substring. | No. |
-| #check_until | Regexp. | Anywhere. | Substring. | No. |
-| #match? | Regexp or String. | At beginning. | Updated position. | No. |
-| #exist? | Regexp. | Anywhere. | Updated position. | No. |
-| #scan | Regexp or String. | At beginning. | Matched substring. | Yes. |
-| #scan_until | Regexp. | Anywhere. | Substring. | Yes. |
-| #skip | Regexp or String. | At beginning. | Match size. | Yes. |
-| #skip_until | Regexp. | Anywhere. | Position delta. | Yes. |
-
-<br>
-
-Which matcher you choose will depend on:
-
-- Where you want to find a match:
-
- - Only at the beginning of the target substring:
- #check, #match?, #scan, #skip.
- - Anywhere in the target substring:
- #check_until, #exist?, #scan_until, #skip_until.
-
-- Whether you want to:
-
- - Traverse, by advancing the positions:
- #scan, #scan_until, #skip, #skip_until.
- - Keep the positions unchanged:
- #check, #check_until, #exist?, #match?.
-
-- What you want for the return value:
-
- - The matched substring: #check, #check_until, #scan, #scan_until.
- - The updated position: #exist?, #match?.
- - The position delta: #skip_until.
- - The match size: #skip.
-
-### Match Values
-
-The <i>match values</i> in a `StringScanner` object
-generally contain the results of the most recent attempted match.
-
-Each match value may be thought of as:
-
-* _Clear_: Initially, or after an unsuccessful match attempt:
- usually, `false`, `nil`, or `{}`.
-* _Set_: After a successful match attempt:
- `true`, string, array, or hash.
-
-Each of these methods clears match values:
-
-- ::new(string).
-- \#reset.
-- \#terminate.
-
-Each of these methods attempts a match based on a pattern,
-and either sets match values (if successful) or clears them (if not);
-
-- \#check(pattern)
-- \#check_until(pattern)
-- \#exist?(pattern)
-- \#match?(pattern)
-- \#scan(pattern)
-- \#scan_until(pattern)
-- \#skip(pattern)
-- \#skip_until(pattern)
-
-#### Basic Match Values
-
-Basic match values are those not related to captures.
-
-Each of these methods returns a basic match value:
-
-| Method | Return After Match | Return After No Match |
-|-----------------|----------------------------------------|-----------------------|
-| #matched? | +true+. | +false+. |
-| #matched_size | Size of matched substring. | +nil+. |
-| #matched | Matched substring. | +nil+. |
-| #pre_match | Substring preceding matched substring. | +nil+. |
-| #post_match | Substring following matched substring. | +nil+. |
-
-<br>
-
-See examples below.
-
-#### Captured Match Values
-
-Captured match values are those related to [captures][16].
-
-Each of these methods returns a captured match value:
-
-| Method | Return After Match | Return After No Match |
-|-----------------|-----------------------------------------|-----------------------|
-| #size | Count of captured substrings. | +nil+. |
-| #[](n) | <tt>n</tt>th captured substring. | +nil+. |
-| #captures | Array of all captured substrings. | +nil+. |
-| #values_at(*n) | Array of specified captured substrings. | +nil+. |
-| #named_captures | Hash of named captures. | <tt>{}</tt>. |
-
-<br>
-
-See examples below.
-
-#### Match Values Examples
-
-Successful basic match attempt (no captures):
-
-```
-scanner = StringScanner.new('foobarbaz')
-scanner.exist?(/bar/)
-put_match_values(scanner)
-# Basic match values:
-# matched?: true
-# matched_size: 3
-# pre_match: "foo"
-# matched : "bar"
-# post_match: "baz"
-# Captured match values:
-# size: 1
-# captures: []
-# named_captures: {}
-# values_at: ["bar", nil]
-# []:
-# [0]: "bar"
-# [1]: nil
-```
-
-Failed basic match attempt (no captures);
-
-```
-scanner = StringScanner.new('foobarbaz')
-scanner.exist?(/nope/)
-match_values_cleared?(scanner) # => true
-```
-
-Successful unnamed capture match attempt:
-
-```
-scanner = StringScanner.new('foobarbazbatbam')
-scanner.exist?(/(foo)bar(baz)bat(bam)/)
-put_match_values(scanner)
-# Basic match values:
-# matched?: true
-# matched_size: 15
-# pre_match: ""
-# matched : "foobarbazbatbam"
-# post_match: ""
-# Captured match values:
-# size: 4
-# captures: ["foo", "baz", "bam"]
-# named_captures: {}
-# values_at: ["foobarbazbatbam", "foo", "baz", "bam", nil]
-# []:
-# [0]: "foobarbazbatbam"
-# [1]: "foo"
-# [2]: "baz"
-# [3]: "bam"
-# [4]: nil
-```
-
-Successful named capture match attempt;
-same as unnamed above, except for #named_captures:
-
-```
-scanner = StringScanner.new('foobarbazbatbam')
-scanner.exist?(/(?<x>foo)bar(?<y>baz)bat(?<z>bam)/)
-scanner.named_captures # => {"x"=>"foo", "y"=>"baz", "z"=>"bam"}
-```
-
-Failed unnamed capture match attempt:
-
-```
-scanner = StringScanner.new('somestring')
-scanner.exist?(/(foo)bar(baz)bat(bam)/)
-match_values_cleared?(scanner) # => true
-```
-
-Failed named capture match attempt;
-same as unnamed above, except for #named_captures:
-
-```
-scanner = StringScanner.new('somestring')
-scanner.exist?(/(?<x>foo)bar(?<y>baz)bat(?<z>bam)/)
-match_values_cleared?(scanner) # => false
-scanner.named_captures # => {"x"=>nil, "y"=>nil, "z"=>nil}
-```
-
-## Fixed-Anchor Property
-
-Pattern matching in `StringScanner` is the same as in Ruby's,
-except for its fixed-anchor property,
-which determines the meaning of `'\A'`:
-
-* `false` (the default): matches the current byte position.
-
- ```
- scanner = StringScanner.new('foobar')
- scanner.scan(/\A./) # => "f"
- scanner.scan(/\A./) # => "o"
- scanner.scan(/\A./) # => "o"
- scanner.scan(/\A./) # => "b"
- ```
-
-* `true`: matches the beginning of the target substring;
- never matches unless the byte position is zero:
-
- ```
- scanner = StringScanner.new('foobar', fixed_anchor: true)
- scanner.scan(/\A./) # => "f"
- scanner.scan(/\A./) # => nil
- scanner.reset
- scanner.scan(/\A./) # => "f"
- ```
-
-The fixed-anchor property is set when the `StringScanner` object is created,
-and may not be modified
-(see StringScanner.new);
-method #fixed_anchor? returns the setting.
-
diff --git a/doc/syntax.rdoc b/doc/syntax.rdoc
index cb427b6f0f..5895673f36 100644
--- a/doc/syntax.rdoc
+++ b/doc/syntax.rdoc
@@ -12,7 +12,7 @@ Assignment[rdoc-ref:syntax/assignment.rdoc] ::
+if+, +unless+, +while+, +until+, +for+, +break+, +next+, +redo+
{Pattern matching}[rdoc-ref:syntax/pattern_matching.rdoc] ::
- Structural pattern matching and variable binding syntax
+ Experimental structural pattern matching and variable binding syntax
Methods[rdoc-ref:syntax/methods.rdoc] ::
Method and method argument syntax
@@ -37,6 +37,3 @@ Miscellaneous[rdoc-ref:syntax/miscellaneous.rdoc] ::
Comments[rdoc-ref:syntax/comments.rdoc] ::
Line and block code comments
-
-Operators[rdoc-ref:syntax/operators.rdoc] ::
- Operator method behaviors
diff --git a/doc/syntax/assignment.rdoc b/doc/syntax/assignment.rdoc
index f45f5bc0ea..1321bbf3ac 100644
--- a/doc/syntax/assignment.rdoc
+++ b/doc/syntax/assignment.rdoc
@@ -107,7 +107,7 @@ Rather than printing "true" you receive a NameError, "undefined local variable
or method `a'". Since ruby parses the bare +a+ left of the +if+ first and has
not yet seen an assignment to +a+ it assumes you wish to call a method. Ruby
then sees the assignment to +a+ and will assume you are referencing a local
-variable.
+method.
The confusion comes from the out-of-order execution of the expression. First
the local variable is assigned-to then you attempt to call a nonexistent
@@ -162,7 +162,9 @@ Here is an example of instance variable usage:
p object1.value # prints "some value"
p object2.value # prints "other value"
-An uninitialized instance variable has a value of +nil+.
+An uninitialized instance variable has a value of +nil+. If you run Ruby with
+warnings enabled, you will get a warning when accessing an uninitialized
+instance variable.
The +value+ method has access to the value set by the +initialize+ method, but
only for the same object.
@@ -401,10 +403,6 @@ assigning. This is similar to multiple assignment:
p a # prints [1, 2, 3]
- b = *1
-
- p b # prints [1]
-
You can splat anywhere in the right-hand side of the assignment:
a = 1, *[2, 3]
diff --git a/doc/syntax/calling_methods.rdoc b/doc/syntax/calling_methods.rdoc
index c2c6c61a10..da061dbfdb 100644
--- a/doc/syntax/calling_methods.rdoc
+++ b/doc/syntax/calling_methods.rdoc
@@ -210,7 +210,7 @@ definition. If a keyword argument is given that the method did not list,
and the method definition does not accept arbitrary keyword arguments, an
ArgumentError will be raised.
-Keyword argument value can be omitted, meaning the value will be fetched
+Keyword argument value can be omitted, meaning the value will be be fetched
from the context by the name of the key
keyword1 = 'some value'
@@ -322,6 +322,18 @@ Both are equivalent to:
my_method(1, 2, 3)
+If the method accepts keyword arguments, the splat operator will convert a
+hash at the end of the array into keyword arguments:
+
+ def my_method(a, b, c: 3)
+ end
+
+ arguments = [1, 2, { c: 4 }]
+ my_method(*arguments)
+
+Note that this behavior is currently deprecated and will emit a warning.
+This behavior will be removed in Ruby 3.0.
+
You may also use the <code>**</code> (described next) to convert a Hash into
keyword arguments.
diff --git a/doc/syntax/comments.rdoc b/doc/syntax/comments.rdoc
index 00d19d588a..dbc7816984 100644
--- a/doc/syntax/comments.rdoc
+++ b/doc/syntax/comments.rdoc
@@ -196,7 +196,7 @@ The method Module#const_set is not affected.
In this mode, all values assigned to constants are deeply copied and
made shareable. It is safer mode than +experimental_everything+.
- # shareable_constant_value: experimental_copy
+ # shareable_constant_value: experimental_everything
var = [{foo: []}]
var.frozen? # => false (assignment was made to local variable)
X = var # => calls `Ractor.make_shareable(var, copy: true)`
diff --git a/doc/syntax/control_expressions.rdoc b/doc/syntax/control_expressions.rdoc
index 3de6cd293f..df3b5ced38 100644
--- a/doc/syntax/control_expressions.rdoc
+++ b/doc/syntax/control_expressions.rdoc
@@ -189,7 +189,7 @@ The same is true for +unless+.
The +case+ expression can be used in two ways.
The most common way is to compare an object against multiple patterns. The
-patterns are matched using the <tt>===</tt> method which is aliased to <tt>==</tt> on
+patterns are matched using the +===+ method which is aliased to +==+ on
Object. Other classes must override it to give meaningful behavior. See
Module#=== and Regexp#=== for examples.
@@ -255,7 +255,7 @@ Again, the +then+ and +else+ are optional.
The result value of a +case+ expression is the last value executed in the
expression.
-Since Ruby 2.7, +case+ expressions also provide a more powerful
+Since Ruby 2.7, +case+ expressions also provide a more powerful experimental
pattern matching feature via the +in+ keyword:
case {a: 1, b: 2, c: 3}
@@ -569,71 +569,3 @@ evaluated on the following iteration:
Here, the flip-flop turns on when +value+ equals 2, but doesn't turn off on the
same iteration. The `off' condition isn't evaluated until the following
iteration and +value+ will never be two again.
-
-== throw/catch
-
-+throw+ and +catch+ are used to implement non-local control flow in Ruby. They
-operate similarly to exceptions, allowing control to pass directly from the
-place where +throw+ is called to the place where the matching +catch+ is
-called. The main difference between +throw+/+catch+ and the use of exceptions
-is that +throw+/+catch+ are designed for expected non-local control flow,
-while exceptions are designed for exceptional control flow situations, such
-as handling unexpected errors.
-
-When using +throw+, you provide 1-2 arguments. The first argument is the
-value for the matching +catch+. The second argument is optional (defaults to
-+nil+), and will be the value that +catch+ returns if there is a matching
-+throw+ inside the +catch+ block. If no matching +throw+ method is called
-inside a +catch+ block, the +catch+ method returns the return value of the
-block passed to it.
-
- def a(n)
- throw :d, :a if n == 0
- b(n)
- end
-
- def b(n)
- throw :d, :b if n == 1
- c(n)
- end
-
- def c(n)
- throw :d if n == 2
- end
-
- 4.times.map do |i|
- catch(:d) do
- a(i)
- :default
- end
- end
- # => [:a, :b, nil, :default]
-
-If the first argument you pass to +throw+ is not handled by a matching
-+catch+, an UncaughtThrowError exception will be raised. This is because
-+throw+/+catch+ should only be used for expected control flow changes, so
-using a value that is not already expected is an error.
-
-+throw+/+catch+ are implemented as Kernel methods (Kernel#throw and
-Kernel#catch), not as keywords. So they are not usable directly if you are
-in a BasicObject context. You can use Kernel.throw and Kernel.catch in
-this case:
-
- BasicObject.new.instance_exec do
- def a
- b
- end
-
- def b
- c
- end
-
- def c
- ::Kernel.throw :d, :e
- end
-
- result = ::Kernel.catch(:d) do
- a
- end
- result # => :e
- end
diff --git a/doc/syntax/exceptions.rdoc b/doc/syntax/exceptions.rdoc
index ac5ff78a95..31e2f0175c 100644
--- a/doc/syntax/exceptions.rdoc
+++ b/doc/syntax/exceptions.rdoc
@@ -86,7 +86,7 @@ To always run some code whether an exception was raised or not, use +ensure+:
rescue
# ...
ensure
- # this always runs BUT does not implicitly return the last evaluated statement.
+ # this always runs
end
You may also run some code when an exception is not raised:
@@ -96,11 +96,7 @@ You may also run some code when an exception is not raised:
rescue
# ...
else
- # this runs only when no exception was raised AND return the last evaluated statement
+ # this runs only when no exception was raised
ensure
- # this always runs.
- # It is evaluated after the evaluation of either the `rescue` or the `else` block.
- # It will not return implicitly.
+ # ...
end
-
-NB : Without explicit +return+ in the +ensure+ block, +begin+/+end+ block will return the last evaluated statement before entering in the `ensure` block.
diff --git a/doc/syntax/keywords.rdoc b/doc/syntax/keywords.rdoc
deleted file mode 100644
index 7c368205ef..0000000000
--- a/doc/syntax/keywords.rdoc
+++ /dev/null
@@ -1,162 +0,0 @@
-= Keywords
-
-The following keywords are used by Ruby.
-
-__ENCODING__::
- The script encoding of the current file. See Encoding.
-
-__LINE__::
- The line number of this keyword in the current file.
-
-__FILE__::
- The path to the current file.
-
-BEGIN::
- Runs before any other code in the current file. See {miscellaneous
- syntax}[rdoc-ref:syntax/miscellaneous.rdoc]
-
-END::
- Runs after any other code in the current file. See {miscellaneous
- syntax}[rdoc-ref:syntax/miscellaneous.rdoc]
-
-alias::
- Creates an alias between two methods (and other things). See {modules and
- classes syntax}[rdoc-ref:syntax/modules_and_classes.rdoc]
-
-and::
- Short-circuit Boolean and with lower precedence than <code>&&</code>
-
-begin::
- Starts an exception handling block. See {exceptions
- syntax}[rdoc-ref:syntax/exceptions.rdoc]
-
-break::
- Leaves a block early. See {control expressions
- syntax}[rdoc-ref:syntax/control_expressions.rdoc]
-
-case::
- Starts a +case+ expression. See {control expressions
- syntax}[rdoc-ref:syntax/control_expressions.rdoc]
-
-class::
- Creates or opens a class. See {modules and classes
- syntax}[rdoc-ref:syntax/modules_and_classes.rdoc]
-
-def::
- Defines a method. See {methods syntax}[rdoc-ref:syntax/methods.rdoc]
-
-defined?::
- Returns a string describing its argument. See {miscellaneous
- syntax}[rdoc-ref:syntax/miscellaneous.rdoc]
-
-do::
- Starts a block.
-
-else::
- The unhandled condition in +case+, +if+ and +unless+ expressions. See
- {control expressions}[rdoc-ref:syntax/control_expressions.rdoc]
-
-elsif::
- An alternate condition for an +if+ expression. See {control
- expressions}[rdoc-ref:syntax/control_expressions.rdoc]
-
-end::
- The end of a syntax block. Used by classes, modules, methods, exception
- handling and control expressions.
-
-ensure::
- Starts a section of code that is always run when an exception is raised.
- See {exception handling}[rdoc-ref:syntax/exceptions.rdoc]
-
-false::
- Boolean false. See {literals}[rdoc-ref:syntax/literals.rdoc]
-
-for::
- A loop that is similar to using the +each+ method. See {control
- expressions}[rdoc-ref:syntax/control_expressions.rdoc]
-
-if::
- Used for +if+ and modifier +if+ statements. See {control
- expressions}[rdoc-ref:syntax/control_expressions.rdoc]
-
-in::
- Used to separate the iterable object and iterator variable in a +for+ loop.
- See {control expressions}[rdoc-ref:syntax/control_expressions.rdoc]
- It also serves as a pattern in a +case+ expression.
- See {pattern matching}[rdoc-ref:syntax/pattern_matching.rdoc]
-
-module::
- Creates or opens a module. See {modules and classes
- syntax}[rdoc-ref:syntax/modules_and_classes.rdoc]
-
-next::
- Skips the rest of the block. See {control
- expressions}[rdoc-ref:syntax/control_expressions.rdoc]
-
-nil::
- A false value usually indicating "no value" or "unknown". See
- {literals}[rdoc-ref:syntax/literals.rdoc]
-
-not::
- Inverts the following boolean expression. Has a lower precedence than
- <code>!</code>
-
-or::
- Boolean or with lower precedence than <code>||</code>
-
-redo::
- Restarts execution in the current block. See {control
- expressions}[rdoc-ref:syntax/control_expressions.rdoc]
-
-rescue::
- Starts an exception section of code in a +begin+ block. See {exception
- handling}[rdoc-ref:syntax/exceptions.rdoc]
-
-retry::
- Retries an exception block. See {exception
- handling}[rdoc-ref:syntax/exceptions.rdoc]
-
-return::
- Exits a method. See {methods}[rdoc-ref:syntax/methods.rdoc].
- If met in top-level scope, immediately stops interpretation of
- the current file.
-
-self::
- The object the current method is attached to. See
- {methods}[rdoc-ref:syntax/methods.rdoc]
-
-super::
- Calls the current method in a superclass. See
- {methods}[rdoc-ref:syntax/methods.rdoc]
-
-then::
- Indicates the end of conditional blocks in control structures. See
- {control expressions}[rdoc-ref:syntax/control_expressions.rdoc]
-
-true::
- Boolean true. See {literals}[rdoc-ref:syntax/literals.rdoc]
-
-undef::
- Prevents a class or module from responding to a method call.
- See {modules and classes}[rdoc-ref:syntax/modules_and_classes.rdoc]
-
-unless::
- Used for +unless+ and modifier +unless+ statements. See {control
- expressions}[rdoc-ref:syntax/control_expressions.rdoc]
-
-until::
- Creates a loop that executes until the condition is true. See
- {control expressions}[rdoc-ref:syntax/control_expressions.rdoc]
-
-when::
- A condition in a +case+ expression. See
- {control expressions}[rdoc-ref:syntax/control_expressions.rdoc]
-
-while::
- Creates a loop that executes while the condition is true. See
- {control expressions}[rdoc-ref:syntax/control_expressions.rdoc]
-
-yield::
- Starts execution of the block sent to the current method. See
- {methods}[rdoc-ref:syntax/methods.rdoc]
-
diff --git a/doc/syntax/literals.rdoc b/doc/syntax/literals.rdoc
index ce398dd75d..b641433249 100644
--- a/doc/syntax/literals.rdoc
+++ b/doc/syntax/literals.rdoc
@@ -138,18 +138,19 @@ Also \Rational numbers may be imaginary numbers.
== Strings
-=== Escape Sequences
-
-Some characters can be represented as escape sequences in
-double-quoted strings,
-character literals,
-here document literals (non-quoted, double-quoted, and with backticks),
-double-quoted symbols,
-double-quoted symbol keys in Hash literals,
-Regexp literals, and
-several percent literals (<tt>%</tt>, <tt>%Q,</tt> <tt>%W</tt>, <tt>%I</tt>, <tt>%r</tt>, <tt>%x</tt>).
-
-They allow escape sequences such as <tt>\n</tt> for
+=== \String Literals
+
+The most common way of writing strings is using <tt>"</tt>:
+
+ "This is a string."
+
+The string may be many lines long.
+
+Any internal <tt>"</tt> must be escaped:
+
+ "This string has a quote: \". As you can see, it is escaped"
+
+Double-quote strings allow escaped characters such as <tt>\n</tt> for
newline, <tt>\t</tt> for tab, etc. The full list of supported escape
sequences are as follows:
@@ -173,31 +174,11 @@ sequences are as follows:
\M-\cx same as above
\c\M-x same as above
\c? or \C-? delete, ASCII 7Fh (DEL)
- \<newline> continuation line (empty string)
-
-The last one, <tt>\<newline></tt>, represents an empty string instead of a character.
-It is used to fold a line in a string.
-
-=== Double-Quoted \String Literals
-The most common way of writing strings is using <tt>"</tt>:
-
- "This is a string."
-
-The string may be many lines long.
-
-Any internal <tt>"</tt> must be escaped:
-
- "This string has a quote: \". As you can see, it is escaped"
-
-Double-quoted strings allow escape sequences described in
-{Escape Sequences}[#label-Escape+Sequences].
-
-In a double-quoted string,
-any other character following a backslash is interpreted as the
+Any other character following a backslash is interpreted as the
character itself.
-Double-quoted strings allow interpolation of other values using
+Double-quote strings allow interpolation of other values using
<tt>#{...}</tt>:
"One plus one is two: #{1 + 1}"
@@ -209,14 +190,8 @@ You can also use <tt>#@foo</tt>, <tt>#@@foo</tt> and <tt>#$foo</tt> as a
shorthand for, respectively, <tt>#{ @foo }</tt>, <tt>#{ @@foo }</tt> and
<tt>#{ $foo }</tt>.
-See also:
-
-* {% and %Q: Interpolable String Literals}[#label-25+and+-25Q-3A+Interpolable+String+Literals]
-
-=== Single-Quoted \String Literals
-
Interpolation may be disabled by escaping the "#" character or using
-single-quoted strings:
+single-quote strings:
'#{1 + 1}' #=> "\#{1 + 1}"
@@ -224,16 +199,6 @@ In addition to disabling interpolation, single-quoted strings also disable all
escape sequences except for the single-quote (<tt>\'</tt>) and backslash
(<tt>\\\\</tt>).
-In a single-quoted string,
-any other character following a backslash is interpreted as is:
-a backslash and the character itself.
-
-See also:
-
-* {%q: Non-Interpolable String Literals}[#label-25q-3A+Non-Interpolable+String+Literals]
-
-=== Literal String Concatenation
-
Adjacent string literals are automatically concatenated by the interpreter:
"con" "cat" "en" "at" "ion" #=> "concatenation"
@@ -246,12 +211,10 @@ be concatenated as long as a percent-string is not last.
%q{a} 'b' "c" #=> "abc"
"a" 'b' %q{c} #=> NameError: uninitialized constant q
-=== Character Literal
-
There is also a character literal notation to represent single
character strings, which syntax is a question mark (<tt>?</tt>)
-followed by a single character or escape sequence (except continuation line)
-that corresponds to a single codepoint in the script encoding:
+followed by a single character or escape sequence that corresponds to
+a single codepoint in the script encoding:
?a #=> "a"
?abc #=> SyntaxError
@@ -265,6 +228,11 @@ that corresponds to a single codepoint in the script encoding:
?\C-\M-a #=> "\x81", same as above
?ã‚ #=> "ã‚"
+See also:
+
+* {%q: Non-Interpolable String Literals}[#label-25q-3A+Non-Interpolable+String+Literals]
+* {% and %Q: Interpolable String Literals}[#label-25+and+-25Q-3A+Interpolable+String+Literals]
+
=== Here Document Literals
If you are writing a large block of text you may use a "here document" or
@@ -315,10 +283,9 @@ its end is a multiple of eight. The amount to be removed is counted in terms
of the number of spaces. If the boundary appears in the middle of a tab, that
tab is not removed.
-A heredoc allows interpolation and the escape sequences described in
-{Escape Sequences}[#label-Escape+Sequences].
-You may disable interpolation and the escaping by surrounding the opening
-identifier with single quotes:
+A heredoc allows interpolation and escaped characters. You may disable
+interpolation and escaping by surrounding the opening identifier with single
+quotes:
expected_result = <<-'EXPECTED'
One plus one is #{1 + 1}
@@ -359,15 +326,12 @@ details on what symbols are and when ruby creates them internally.
You may reference a symbol using a colon: <tt>:my_symbol</tt>.
-You may also create symbols by interpolation and escape sequences described in
-{Escape Sequences}[#label-Escape+Sequences] with double-quotes:
+You may also create symbols by interpolation:
:"my_symbol1"
:"my_symbol#{1 + 1}"
- :"foo\sbar"
-Like strings, a single-quote may be used to disable interpolation and
-escape sequences:
+Like strings, a single-quote may be used to disable interpolation:
:'my_symbol#{1 + 1}' #=> :"my_symbol\#{1 + 1}"
@@ -450,9 +414,9 @@ slash (<tt>'/'</tt>) characters:
re = /foo/ # => /foo/
re.class # => Regexp
-The trailing slash may be followed by one or more modifiers characters
-that set modes for the regexp.
-See {Regexp modes}[rdoc-ref:Regexp@Modes] for details.
+The trailing slash may be followed by one or more _flag_ characters
+that modify the behavior.
+See {Regexp options}[rdoc-ref:Regexp@Options] for details.
Interpolation may be used inside regular expressions along with escaped
characters. Note that a regular expression may require additional escaped
@@ -487,12 +451,7 @@ may use these paired delimiters:
* <tt>(</tt> and <tt>)</tt>.
* <tt>{</tt> and <tt>}</tt>.
* <tt><</tt> and <tt>></tt>.
-* Non-alphanumeric ASCII character except above, as both beginning and ending delimiters.
-
-The delimiters can be escaped with a backslash.
-However, the first four pairs (brackets, parenthesis, braces, and
-angle brackets) are allowed without backslash as far as they are correctly
-paired.
+* Any other character, as both beginning and ending delimiters.
These are demonstrated in the next section.
@@ -501,20 +460,13 @@ These are demonstrated in the next section.
You can write a non-interpolable string with <tt>%q</tt>.
The created string is the same as if you created it with single quotes:
- %q[foo bar baz] # => "foo bar baz" # Using [].
- %q(foo bar baz) # => "foo bar baz" # Using ().
- %q{foo bar baz} # => "foo bar baz" # Using {}.
- %q<foo bar baz> # => "foo bar baz" # Using <>.
- %q|foo bar baz| # => "foo bar baz" # Using two |.
- %q:foo bar baz: # => "foo bar baz" # Using two :.
+ %[foo bar baz] # => "foo bar baz" # Using [].
+ %(foo bar baz) # => "foo bar baz" # Using ().
+ %{foo bar baz} # => "foo bar baz" # Using {}.
+ %<foo bar baz> # => "foo bar baz" # Using <>.
+ %|foo bar baz| # => "foo bar baz" # Using two |.
+ %:foo bar baz: # => "foo bar baz" # Using two :.
%q(1 + 1 is #{1 + 1}) # => "1 + 1 is \#{1 + 1}" # No interpolation.
- %q[foo[bar]baz] # => "foo[bar]baz" # brackets can be nested.
- %q(foo(bar)baz) # => "foo(bar)baz" # parenthesis can be nested.
- %q{foo{bar}baz} # => "foo{bar}baz" # braces can be nested.
- %q<foo<bar>baz> # => "foo<bar>baz" # angle brackets can be nested.
-
-This is similar to single-quoted string but only backslashs and
-the specified delimiters can be escaped with a backslash.
=== <tt>% and %Q</tt>: Interpolable String Literals
@@ -524,63 +476,30 @@ or with its alias <tt>%</tt>:
%[foo bar baz] # => "foo bar baz"
%(1 + 1 is #{1 + 1}) # => "1 + 1 is 2" # Interpolation.
-This is similar to double-quoted string.
-It allow escape sequences described in
-{Escape Sequences}[#label-Escape+Sequences].
-Other escaped characters (a backslash followed by a character) are
-interpreted as the character.
-
=== <tt>%w and %W</tt>: String-Array Literals
-You can write an array of strings as whitespace-separated words
-with <tt>%w</tt> (non-interpolable) or <tt>%W</tt> (interpolable):
+You can write an array of strings with <tt>%w</tt> (non-interpolable)
+or <tt>%W</tt> (interpolable):
%w[foo bar baz] # => ["foo", "bar", "baz"]
%w[1 % *] # => ["1", "%", "*"]
# Use backslash to embed spaces in the strings.
%w[foo\ bar baz\ bat] # => ["foo bar", "baz bat"]
- %W[foo\ bar baz\ bat] # => ["foo bar", "baz bat"]
%w(#{1 + 1}) # => ["\#{1", "+", "1}"]
%W(#{1 + 1}) # => ["2"]
- # The nested delimiters evaluated to a flat array of strings
- # (not nested array).
- %w[foo[bar baz]qux] # => ["foo[bar", "baz]qux"]
-
-The following characters are considered as white spaces to separate words:
-
-* space, ASCII 20h (SPC)
-* form feed, ASCII 0Ch (FF)
-* newline (line feed), ASCII 0Ah (LF)
-* carriage return, ASCII 0Dh (CR)
-* horizontal tab, ASCII 09h (TAB)
-* vertical tab, ASCII 0Bh (VT)
-
-The white space characters can be escaped with a backslash to make them
-part of a word.
-
-<tt>%W</tt> allow escape sequences described in
-{Escape Sequences}[#label-Escape+Sequences].
-However the continuation line <tt>\<newline></tt> is not usable because
-it is interpreted as the escaped newline described above.
-
=== <tt>%i and %I</tt>: Symbol-Array Literals
-You can write an array of symbols as whitespace-separated words
-with <tt>%i</tt> (non-interpolable) or <tt>%I</tt> (interpolable):
+You can write an array of symbols with <tt>%i</tt> (non-interpolable)
+or <tt>%I</tt> (interpolable):
%i[foo bar baz] # => [:foo, :bar, :baz]
%i[1 % *] # => [:"1", :%, :*]
# Use backslash to embed spaces in the symbols.
%i[foo\ bar baz\ bat] # => [:"foo bar", :"baz bat"]
- %I[foo\ bar baz\ bat] # => [:"foo bar", :"baz bat"]
%i(#{1 + 1}) # => [:"\#{1", :+, :"1}"]
%I(#{1 + 1}) # => [:"2"]
-The white space characters and its escapes are interpreted as the same as
-string-array literals described in
-{%w and %W: String-Array Literals}[#label-25w+and+-25W-3A+String-Array+Literals].
-
=== <tt>%s</tt>: Symbol Literals
You can write a symbol with <tt>%s</tt>:
@@ -588,10 +507,6 @@ You can write a symbol with <tt>%s</tt>:
%s[foo] # => :foo
%s[foo bar] # => :"foo bar"
-This is non-interpolable.
-No interpolation allowed.
-Only backslashs and the specified delimiters can be escaped with a backslash.
-
=== <tt>%r</tt>: Regexp Literals
You can write a regular expression with <tt>%r</tt>;
@@ -608,18 +523,12 @@ A few "symmetrical" character pairs may be used as delimiters:
%r(foo) # => /foo/
%r<foo> # => /foo/
-The trailing delimiter may be followed by one or more modifier characters
-that set modes for the regexp.
-See {Regexp modes}[rdoc-ref:Regexp@Modes] for details.
+The trailing delimiter may be followed by one or more _flag_ characters
+that modify the behavior.
+See {Regexp options}[rdoc-ref:Regexp@Options] for details.
=== <tt>%x</tt>: Backtick Literals
You can write and execute a shell command with <tt>%x</tt>:
- %x(echo 1) # => "1\n"
- %x[echo #{1 + 2}] # => "3\n"
- %x[echo \u0030] # => "0\n"
-
-This is interpolable.
-<tt>%x</tt> allow escape sequences described in
-{Escape Sequences}[#label-Escape+Sequences].
+ %x(echo 1) # => "1\n"
diff --git a/doc/syntax/modules_and_classes.rdoc b/doc/syntax/modules_and_classes.rdoc
index 9e05c5c774..024815a5a6 100644
--- a/doc/syntax/modules_and_classes.rdoc
+++ b/doc/syntax/modules_and_classes.rdoc
@@ -40,9 +40,9 @@ functionality:
remove_method :my_method
end
-Reopening modules (or classes) is a very powerful feature of Ruby, but it is
-best to only reopen modules you own. Reopening modules you do not own may lead
-to naming conflicts or difficult to diagnose bugs.
+Reopening classes is a very powerful feature of Ruby, but it is best to only
+reopen classes you own. Reopening classes you do not own may lead to naming
+conflicts or difficult to diagnose bugs.
== Nesting
@@ -259,28 +259,6 @@ includes a minimum of built-in methods. You can use BasicObject to create an
independent inheritance structure. See the BasicObject documentation for
further details.
-Just like modules, classes can also be reopened. You can omit its superclass
-when you reopen a class. Specifying a different superclass than the previous
-definition will raise an error.
-
- class C
- end
-
- class D < C
- end
-
- # OK
- class D < C
- end
-
- # OK
- class D
- end
-
- # TypeError: superclass mismatch for class D
- class D < String
- end
-
== Inheritance
Any method defined on a class is callable from its subclass:
diff --git a/doc/syntax/operators.rdoc b/doc/syntax/operators.rdoc
deleted file mode 100644
index d3045ac99e..0000000000
--- a/doc/syntax/operators.rdoc
+++ /dev/null
@@ -1,75 +0,0 @@
-= Operators
-
-In Ruby, operators such as <code>+</code>, are defined as methods on the class.
-Literals[rdoc-ref:syntax/literals.rdoc] define their methods within the lower
-level, C language. String class, for example.
-
-Ruby objects can define or overload their own implementation for most operators.
-
-Here is an example:
-
- class Foo < String
- def +(str)
- self.concat(str).concat("another string")
- end
- end
-
- foobar = Foo.new("test ")
- puts foobar + "baz "
-
-This prints:
-
- test baz another string
-
-What operators are available is dependent on the implementing class.
-
-== Operator Behavior
-
-How a class behaves to a given operator is specific to that class, since
-operators are method implementations.
-
-When using an operator, it's the expression on the left-hand side of the
-operation that specifies the behavior.
-
- 'a' * 3 #=> "aaa"
- 3 * 'a' # TypeError: String can't be coerced into Integer
-
-== Logical Operators
-
-Logical operators are not methods, and therefore cannot be
-redefined/overloaded. They are tokenized at a lower level.
-
-Short-circuit logical operators (<code>&&</code>, <code>||</code>,
-<code>and</code>, and <code>or</code>) do not always result in a boolean value.
-Similar to blocks, it's the last evaluated expression that defines the result
-of the operation.
-
-=== <code>&&</code>, <code>and</code>
-
-Both <code>&&</code>/<code>and</code> operators provide short-circuiting by executing each
-side of the operator, left to right, and stopping at the first occurrence of a
-falsey expression. The expression that defines the result is the last one
-executed, whether it be the final expression, or the first occurrence of a falsey
-expression.
-
-Some examples:
-
- true && 9 && "string" #=> "string"
- (1 + 2) && nil && "string" #=> nil
- (a = 1) && (b = false) && (c = "string") #=> false
-
- puts a #=> 1
- puts b #=> false
- puts c #=> nil
-
-In this last example, <code>c</code> was initialized, but not defined.
-
-=== <code>||</code>, <code>or</code>
-
-The means by which <code>||</code>/<code>or</code> short-circuits, is to return the result of
-the first expression that is truthy.
-
-Some examples:
-
- (1 + 2) || true || "string" #=> 3
- false || nil || "string" #=> "string"
diff --git a/doc/syntax/pattern_matching.rdoc b/doc/syntax/pattern_matching.rdoc
index 6a30380f46..b7d614770c 100644
--- a/doc/syntax/pattern_matching.rdoc
+++ b/doc/syntax/pattern_matching.rdoc
@@ -415,15 +415,9 @@ Additionally, when matching custom classes, the expected class can be specified
end
#=> "matched: 1"
-These core and library classes implement deconstruction:
-
-* MatchData#deconstruct and MatchData#deconstruct_keys;
-* Time#deconstruct_keys, Date#deconstruct_keys, DateTime#deconstruct_keys.
-
== Guard clauses
-+if+ can be used to attach an additional condition (guard clause) when the pattern matches in +case+/+in+ expressions.
-This condition may use bound variables:
++if+ can be used to attach an additional condition (guard clause) when the pattern matches. This condition may use bound variables:
case [1, 2]
in a, b if b == a*2
@@ -451,10 +445,28 @@ This condition may use bound variables:
end
#=> "matched"
-Note that <code>=></code> and +in+ operator can not have a guard clause.
-The following examples is parsed as a standalone expression with modifier +if+.
+== Current feature status
+
+As of Ruby 3.1, find patterns are considered _experimental_: its syntax can change in the future. Every time you use these features in code, a warning will be printed:
+
+ [0] => [*, 0, *]
+ # warning: Find pattern is experimental, and the behavior may change in future versions of Ruby!
+ # warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!
+
+To suppress this warning, one may use the Warning::[]= method:
+
+ Warning[:experimental] = false
+ eval('[0] => [*, 0, *]')
+ # ...no warning printed...
+
+Note that pattern-matching warnings are raised at compile time, so this will not suppress the warning:
+
+ Warning[:experimental] = false # At the time this line is evaluated, the parsing happened and warning emitted
+ [0] => [*, 0, *]
+
+So, only subsequently loaded files or `eval`-ed code is affected by switching the flag.
- [1, 2] in a, b if b == a*2
+Alternatively, the command line option <code>-W:no-experimental</code> can be used to turn off "experimental" feature warnings.
== Appendix A. Pattern syntax
diff --git a/doc/syntax/refinements.rdoc b/doc/syntax/refinements.rdoc
index 17d5e67c21..c900ab1bdc 100644
--- a/doc/syntax/refinements.rdoc
+++ b/doc/syntax/refinements.rdoc
@@ -279,6 +279,6 @@ Refinements in descendants have higher precedence than those of ancestors.
== Further Reading
-See https://github.com/ruby/ruby/wiki/Refinements-Spec for the
+See https://bugs.ruby-lang.org/projects/ruby-master/wiki/RefinementsSpec for the
current specification for implementing refinements. The specification also
contains more details.
diff --git a/doc/timezones.rdoc b/doc/timezones.rdoc
new file mode 100644
index 0000000000..c3aae88fde
--- /dev/null
+++ b/doc/timezones.rdoc
@@ -0,0 +1,108 @@
+== Timezones
+
+=== Timezone Specifiers
+
+Certain \Time methods accept arguments that specify timezones:
+
+- Time.at: keyword argument +in:+.
+- Time.new: positional argument +zone+ or keyword argument +in:+.
+- Time.now: keyword argument +in:+.
+- Time#getlocal: positional argument +zone+.
+- Time#localtime: positional argument +zone+.
+
+The value given with any of these must be one of the following
+(each detailed below):
+
+- {Hours/minutes offset}[rdoc-ref:timezones.rdoc@Hours-2FMinutes+Offsets].
+- {Single-letter offset}[rdoc-ref:timezones.rdoc@Single-Letter+Offsets].
+- {Integer offset}[rdoc-ref:timezones.rdoc@Integer+Offsets].
+- {Timezone object}[rdoc-ref:timezones.rdoc@Timezone+Objects].
+
+==== Hours/Minutes Offsets
+
+The zone value may be a string offset from UTC
+in the form <tt>'+HH:MM'</tt> or <tt>'-HH:MM'</tt>,
+where:
+
+- +HH+ is the 2-digit hour in the range <tt>0..23</tt>.
+- +MM+ is the 2-digit minute in the range <tt>0..59</tt>.
+
+Examples:
+
+ t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
+ Time.at(t, in: '-23:59') # => 1999-12-31 20:16:01 -2359
+ Time.at(t, in: '+23:59') # => 2000-01-02 20:14:01 +2359
+
+==== Single-Letter Offsets
+
+The zone value may be a letter in the range <tt>'A'..'I'</tt>
+or <tt>'K'..'Z'</tt>;
+see {List of military time zones}[https://en.wikipedia.org/wiki/List_of_military_time_zones]:
+
+ t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
+ Time.at(t, in: 'A') # => 2000-01-01 21:15:01 +0100
+ Time.at(t, in: 'I') # => 2000-01-02 05:15:01 +0900
+ Time.at(t, in: 'K') # => 2000-01-02 06:15:01 +1000
+ Time.at(t, in: 'Y') # => 2000-01-01 08:15:01 -1200
+ Time.at(t, in: 'Z') # => 2000-01-01 20:15:01 UTC
+
+==== \Integer Offsets
+
+The zone value may be an integer number of seconds
+in the range <tt>-86399..86399</tt>:
+
+ t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
+ Time.at(t, in: -86399) # => 1999-12-31 20:15:02 -235959
+ Time.at(t, in: 86399) # => 2000-01-02 20:15:00 +235959
+
+==== Timezone Objects
+
+In most cases, the zone value may be an object
+responding to certain timezone methods.
+
+\Exceptions (timezone object not allowed):
+
+- Time.new with positional argument +zone+.
+- Time.now with keyword argument +in:+.
+
+The timezone methods are:
+
+- +local_to_utc+:
+
+ - Called when Time.new is invoked with +tz+
+ as the value of positional argument +zone+ or keyword argument +in:+.
+ - Argument: a <tt>Time::tm</tt> object.
+ - Returns: a \Time-like object in the UTC timezone.
+
+- +utc_to_local+:
+
+ - Called when Time.at or Time.now is invoked with +tz+
+ as the value for keyword argument +in:+,
+ and when Time#getlocal or Time#localtime is called with +tz+
+ as the value for positional argument +zone+.
+ - Argument: a <tt>Time::tm</tt> object.
+ - Returns: a \Time-like object in the local timezone.
+
+A custom timezone class may have these instance methods,
+which will be called if defined:
+
+- +abbr+:
+
+ - Called when Time#strftime is invoked with a format involving <tt>%Z</tt>.
+ - Argument: a <tt>Time::tm</tt> object.
+ - Returns: a string abbreviation for the timezone name.
+
+- +dst?+:
+
+ - Called when Time.at or Time.now is invoked with +tz+
+ as the value for keyword argument +in:+,
+ and when Time#getlocal or Time#localtime is called with +tz+
+ as the value for positional argument +zone+.
+ - Argument: a <tt>Time::tm</tt> object.
+ - Returns: whether the time is daylight saving time.
+
+- +name+:
+
+ - Called when <tt>Marshal.dump(t) is invoked
+ - Argument: none.
+ - Returns: the string name of the timezone.
diff --git a/doc/transcode.rdoc b/doc/transcode.rdoc
new file mode 100644
index 0000000000..4f15dff94a
--- /dev/null
+++ b/doc/transcode.rdoc
@@ -0,0 +1,52 @@
+# :markup: ruby
+
+class String
+ # call-seq:
+ # encode(dst_encoding = Encoding.default_internal, **enc_opts) -> string
+ # encode(dst_encoding, src_encoding, **enc_opts) -> string
+ #
+ # Returns a copy of +self+ transcoded as determined by +dst_encoding+.
+ # By default, raises an exception if +self+
+ # contains an invalid byte or a character not defined in +dst_encoding+;
+ # that behavior may be modified by encoding options; see below.
+ #
+ # With no arguments:
+ #
+ # - Uses the same encoding if <tt>Encoding.default_internal</tt> is +nil+
+ # (the default):
+ #
+ # Encoding.default_internal # => nil
+ # s = "Ruby\x99".force_encoding('Windows-1252')
+ # s.encoding # => #<Encoding:Windows-1252>
+ # s.bytes # => [82, 117, 98, 121, 153]
+ # t = s.encode # => "Ruby\x99"
+ # t.encoding # => #<Encoding:Windows-1252>
+ # t.bytes # => [82, 117, 98, 121, 226, 132, 162]
+ #
+ # - Otherwise, uses the encoding <tt>Encoding.default_internal</tt>:
+ #
+ # Encoding.default_internal = 'UTF-8'
+ # t = s.encode # => "Rubyâ„¢"
+ # t.encoding # => #<Encoding:UTF-8>
+ #
+ # With only argument +dst_encoding+ given, uses that encoding:
+ #
+ # s = "Ruby\x99".force_encoding('Windows-1252')
+ # s.encoding # => #<Encoding:Windows-1252>
+ # t = s.encode('UTF-8') # => "Rubyâ„¢"
+ # t.encoding # => #<Encoding:UTF-8>
+ #
+ # With arguments +dst_encoding+ and +src_encoding+ given,
+ # interprets +self+ using +src_encoding+, encodes the new string using +dst_encoding+:
+ #
+ # s = "Ruby\x99"
+ # t = s.encode('UTF-8', 'Windows-1252') # => "Rubyâ„¢"
+ # t.encoding # => #<Encoding:UTF-8>
+ #
+ # Optional keyword arguments +enc_opts+ specify encoding options;
+ # see {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
+ def encode(dst_encoding = Encoding.default_internal, **enc_opts)
+ # Pseudo code
+ Primitive.str_encode(...)
+ end
+end
diff --git a/doc/windows.md b/doc/windows.md
deleted file mode 100644
index f638e57529..0000000000
--- a/doc/windows.md
+++ /dev/null
@@ -1,250 +0,0 @@
-# Windows
-
-Ruby supports a few native build platforms for Windows.
-
-* mswin: Build using Microsoft Visual C++ compiler with vcruntimeXXX.dll
-* mingw-msvcrt: Build using compiler for Mingw with msvcrtXX.dll
-* mingw-ucrt: Build using compiler for Mingw with Windows Universal CRT
-
-## Building Ruby using Mingw with UCRT
-
-The easiest build environment is just a standard [RubyInstaller-Devkit]
-installation and [git-for-windows]. You might like to use [VSCode] as an
-editor.
-
-### Build examples
-
-Ruby core development can be done either in Windows `cmd` like:
-
-```
-ridk enable ucrt64
-
-pacman -S --needed %MINGW_PACKAGE_PREFIX%-openssl %MINGW_PACKAGE_PREFIX%-libyaml %MINGW_PACKAGE_PREFIX%-libffi
-
-cd c:\
-mkdir work
-cd work
-git clone https://github.com/ruby/ruby
-
-cd c:\work\ruby
-sh autogen.sh
-sh configure -C --disable-install-doc
-make
-```
-
-or in MSYS2 `bash` like:
-
-```
-ridk enable ucrt64
-bash
-
-pacman -S --needed $MINGW_PACKAGE_PREFIX-openssl $MINGW_PACKAGE_PREFIX-libyaml $MINGW_PACKAGE_PREFIX-libffi
-
-cd /c/
-mkdir work
-cd work
-git clone https://github.com/ruby/ruby
-cd ruby
-
-./autogen.sh
-./configure -C --disable-install-doc
-make
-```
-
-[RubyInstaller-Devkit]: https://rubyinstaller.org/
-[git-for-windows]: https://gitforwindows.org/
-[VSCode]: https://code.visualstudio.com/
-
-## Building Ruby using Visual C++
-
-### Requirement
-
-1. Windows 10/Windows Server 2016 or later.
-
-2. Visual C++ 14.0 (2015) or later.
-
- **Note** if you want to build x64 version, use native compiler for
- x64.
-
-3. Please set environment variable `INCLUDE`, `LIB`, `PATH`
- to run required commands properly from the command line.
-
- **Note** building ruby requires following commands.
-
- * nmake
- * cl
- * ml
- * lib
- * dumpbin
-
-4. If you want to build from GIT source, following commands are required.
- * git
- * patch
- * sed
- * ruby 3.0 or later
-
- You can use [scoop](https://scoop.sh/) to install them like:
-
- ```
- scoop install git patch sed ruby
- ```
-
-5. You need to install required libraries using [vcpkg](https://vcpkg.io/) on
- directory of ruby repository like:
-
- ```
- vcpkg --triplet x64-windows install
- ```
-
-6. Enable Command Extension of your command line. It's the default behavior
- of `cmd.exe`. If you want to enable it explicitly, run `cmd.exe` with
- `/E:ON` option.
-
-### How to compile and install
-
-1. Execute `win32\configure.bat` on your build directory.
- You can specify the target platform as an argument.
- For example, run `configure --target=i686-mswin32`
- You can also specify the install directory.
- For example, run `configure --prefix=<install_directory>`
- Default of the install directory is `/usr` .
- The default _PLATFORM_ is `i386-mswin32_`_MSRTVERSION_ on 32-bit
- platforms, or `x64-mswin64_`_MSRTVERSION_ on x64 platforms.
- _MSRTVERSION_ is the 2- or 3-digits version of the Microsoft
- Runtime Library.
-
-2. Change _RUBY_INSTALL_NAME_ and _RUBY_SO_NAME_ in `Makefile`
- if you want to change the name of the executable files.
- And add _RUBYW_INSTALL_NAME_ to change the name of the
- executable without console window if also you want.
-
-3. You need specify vcpkg directory to use `--with-opt-dir`
- option like `win32\configure.bat --with-opt-dir=vcpkg_installed\x64-windows`
-
-4. Run `nmake up` if you are building from GIT source.
-
-5. Run `nmake`
-
-6. Run `nmake prepare-vcpkg` if you need to copy
- vcpkg installed libraries like `libssl-3-x64.dll` to the build directory.
-
-7. Run `nmake check`
-
-8. Run `nmake install`
-
-### Build examples
-
-* Build on the ruby source directory.
-
- ```
- ruby source directory: C:\ruby
- build directory: C:\ruby
- install directory: C:\usr\local
- ```
-
- ```
- C:
- cd \ruby
- win32\configure --prefix=/usr/local
- nmake
- nmake check
- nmake install
- ```
-
-* Build on the relative directory from the ruby source directory.
-
- ```
- ruby source directory: C:\ruby
- build directory: C:\ruby\mswin32
- install directory: C:\usr\local
- ```
-
- ```
- C:
- cd \ruby
- mkdir mswin32
- cd mswin32
- ..\win32\configure --prefix=/usr/local
- nmake
- nmake check
- nmake install
- ```
-
-* Build on the different drive.
-
- ```
- ruby source directory: C:\src\ruby
- build directory: D:\build\ruby
- install directory: C:\usr\local
- ```
-
- ```
- D:
- cd D:\build\ruby
- C:\src\ruby\win32\configure --prefix=/usr/local
- nmake
- nmake check
- nmake install DESTDIR=C:
- ```
-
-* Build x64 version (requires native x64 VC++ compiler)
-
- ```
- ruby source directory: C:\ruby
- build directory: C:\ruby
- install directory: C:\usr\local
- ```
-
- ```
- C:
- cd \ruby
- win32\configure --prefix=/usr/local --target=x64-mswin64
- nmake
- nmake check
- nmake install
- ```
-
-### Bugs
-
-You can **NOT** use a path name that contains any white space characters
-as the ruby source directory, this restriction comes from the behavior
-of `!INCLUDE` directives of `NMAKE`.
-
-You can build ruby in any directory including the source directory,
-except `win32` directory in the source directory.
-This is restriction originating in the path search method of `NMAKE`.
-
-### Dependency management
-
-Ruby uses [vcpkg](https://vcpkg.io/) to manage dependencies on mswin platform.
-
-You can update and install it under the build directory like:
-
-```
-nmake update-vcpkg # Update baseline version of vcpkg
-nmake install-vcpkg # Install vcpkg from build directory
-```
-
-
-## Icons
-
-Any icon files(`*.ico`) in the build directory, directories specified with
-_icondirs_ make variable and `win32` directory under the ruby
-source directory will be included in DLL or executable files, according
-to their base names.
- $(RUBY_INSTALL_NAME).ico or ruby.ico --> $(RUBY_INSTALL_NAME).exe
- $(RUBYW_INSTALL_NAME).ico or rubyw.ico --> $(RUBYW_INSTALL_NAME).exe
- the others --> $(RUBY_SO_NAME).dll
-
-Although no icons are distributed with the ruby source, you can use
-anything you like. You will be able to find many images by search engines.
-For example, followings are made from [Ruby logo kit]:
-
-* Small [favicon] in the official site
-
-* [vit-ruby.ico] or [icon itself]
-
-[Ruby logo kit]: https://cache.ruby-lang.org/pub/misc/logo/ruby-logo-kit.zip
-[favicon]: https://www.ruby-lang.org/favicon.ico
-[vit-ruby.ico]: http://ruby.morphball.net/vit-ruby-ico_en.html
-[icon itself]: http://ruby.morphball.net/icon/vit-ruby.ico
diff --git a/doc/yjit/yjit.md b/doc/yjit/yjit.md
index c63d31b64f..67b2ffa5f0 100644
--- a/doc/yjit/yjit.md
+++ b/doc/yjit/yjit.md
@@ -4,28 +4,26 @@
</a>
</p>
+
YJIT - Yet Another Ruby JIT
===========================
YJIT is a lightweight, minimalistic Ruby JIT built inside CRuby.
It lazily compiles code using a Basic Block Versioning (BBV) architecture.
+The target use case is that of servers running Ruby on Rails.
YJIT is currently supported for macOS, Linux and BSD on x86-64 and arm64/aarch64 CPUs.
This project is open source and falls under the same license as CRuby.
<p align="center"><b>
If you're using YJIT in production, please
<a href="mailto:maxime.chevalierboisvert@shopify.com">share your success stories with us!</a>
-</b></p>
+ </b></p>
If you wish to learn more about the approach taken, here are some conference talks and publications:
-
-- RubyKaigi 2023 keynote: [Optimizing YJIT’s Performance, from Inception to Production](https://www.youtube.com/watch?v=X0JRhh8w_4I)
-- RubyKaigi 2023 keynote: [Fitting Rust YJIT into CRuby](https://www.youtube.com/watch?v=GI7vvAgP_Qs)
- RubyKaigi 2022 keynote: [Stories from developing YJIT](https://www.youtube.com/watch?v=EMchdR9C8XM)
- RubyKaigi 2022 talk: [Building a Lightweight IR and Backend for YJIT](https://www.youtube.com/watch?v=BbLGqTxTRp0)
- RubyKaigi 2021 talk: [YJIT: Building a New JIT Compiler Inside CRuby](https://www.youtube.com/watch?v=PBVLf3yfMs8)
- Blog post: [YJIT: Building a New JIT Compiler Inside CRuby](https://pointersgonewild.com/2021/06/02/yjit-building-a-new-jit-compiler-inside-cruby/)
-- MPLR 2023 paper: [Evaluating YJIT’s Performance in a Production Context: A Pragmatic Approach](https://dl.acm.org/doi/10.1145/3617651.3622982)
- VMIL 2021 paper: [YJIT: A Basic Block Versioning JIT Compiler for CRuby](https://dl.acm.org/doi/10.1145/3486606.3486781)
- MoreVMs 2021 talk: [YJIT: Building a New JIT Compiler Inside CRuby](https://www.youtube.com/watch?v=vucLAqv7qpc)
- ECOOP 2016 talk: [Interprocedural Type Specialization of JavaScript Programs Without Type Analysis](https://www.youtube.com/watch?v=sRNBY7Ss97A)
@@ -33,31 +31,31 @@ If you wish to learn more about the approach taken, here are some conference tal
- ECOOP 2015 talk: [Simple and Effective Type Check Removal through Lazy Basic Block Versioning](https://www.youtube.com/watch?v=S-aHBuoiYE0)
- ECOOP 2015 paper: [Simple and Effective Type Check Removal through Lazy Basic Block Versioning](https://arxiv.org/pdf/1411.0352.pdf)
-To cite YJIT in your publications, please cite the MPLR 2023 paper:
+To cite YJIT in your publications, please cite the VMIL 2021 paper:
```
-@inproceedings{yjit_mplr_2023,
-author = {Chevalier-Boisvert, Maxime and Kokubun, Takashi and Gibbs, Noah and Wu, Si Xing (Alan) and Patterson, Aaron and Issroff, Jemma},
-title = {Evaluating YJIT’s Performance in a Production Context: A Pragmatic Approach},
-year = {2023},
-isbn = {9798400703805},
+@inproceedings{yjit_vmil2021,
+author = {Chevalier-Boisvert, Maxime and Gibbs, Noah and Boussier, Jean and Wu, Si Xing (Alan) and Patterson, Aaron and Newton, Kevin and Hawthorn, John},
+title = {YJIT: A Basic Block Versioning JIT Compiler for CRuby},
+year = {2021},
+isbn = {9781450391092},
publisher = {Association for Computing Machinery},
address = {New York, NY, USA},
-url = {https://doi.org/10.1145/3617651.3622982},
-doi = {10.1145/3617651.3622982},
-booktitle = {Proceedings of the 20th ACM SIGPLAN International Conference on Managed Programming Languages and Runtimes},
-pages = {20–33},
-numpages = {14},
-keywords = {dynamically typed, optimization, just-in-time, virtual machine, ruby, compiler, bytecode},
-location = {Cascais, Portugal},
-series = {MPLR 2023}
+url = {https://doi.org/10.1145/3486606.3486781},
+doi = {10.1145/3486606.3486781},
+booktitle = {Proceedings of the 13th ACM SIGPLAN International Workshop on Virtual Machines and Intermediate Languages},
+pages = {25–32},
+numpages = {8},
+keywords = {ruby, dynamically typed, compiler, optimization, just-in-time, bytecode},
+location = {Chicago, IL, USA},
+series = {VMIL 2021}
}
```
## Current Limitations
-YJIT may not be suitable for certain applications. It currently only supports macOS, Linux and BSD on x86-64 and arm64/aarch64 CPUs. YJIT will use more memory than the Ruby interpreter because the JIT compiler needs to generate machine code in memory and maintain additional state information.
-You can change how much executable memory is allocated using [YJIT's command-line options](#command-line-options).
+YJIT may not be suitable for certain applications. It currently only supports macOS and Linux on x86-64 and arm64/aarch64 CPUs. YJIT will use more memory than the Ruby interpreter because the JIT compiler needs to generate machine code in memory and maintain additional state information.
+You can change how much executable memory is allocated using [YJIT's command-line options](#command-line-options). There is a slight performance tradeoff because allocating less executable memory could result in the generated machine code being collected more often.
## Installation
@@ -114,7 +112,7 @@ On macOS, you may need to specify where to find some libraries:
```sh
# Install dependencies
-brew install openssl libyaml
+brew install openssl readline libyaml
# Configure in dev (debug) mode for development, build and install
./autogen.sh
@@ -161,67 +159,37 @@ You can dump statistics about compilation and execution by running YJIT with the
The machine code generated for a given method can be printed by adding `puts RubyVM::YJIT.disasm(method(:method_name))` to a Ruby script. Note that no code will be generated if the method is not compiled.
-<h3 id="command-line-options">Command-Line Options</h3>
+### Command-Line Options
YJIT supports all command-line options supported by upstream CRuby, but also adds a few YJIT-specific options:
- `--yjit`: enable YJIT (disabled by default)
-- `--yjit-exec-mem-size=N`: size of the executable memory block to allocate, in MiB (default 48 MiB)
-- `--yjit-call-threshold=N`: number of calls after which YJIT begins to compile a function.
- It defaults to 30, and it's then increased to 120 when the number of ISEQs in the process reaches 40,000.
-- `--yjit-cold-threshold=N`: number of global calls after which an ISEQ is considered cold and not
- compiled, lower values mean less code is compiled (default 200K)
+- `--yjit-call-threshold=N`: number of calls after which YJIT begins to compile a function (default 30)
+- `--yjit-exec-mem-size=N`: size of the executable memory block to allocate, in MiB (default 64 MiB)
- `--yjit-stats`: print statistics after the execution of a program (incurs a run-time cost)
-- `--yjit-stats=quiet`: gather statistics while running a program but don't print them. Stats are accessible through `RubyVM::YJIT.runtime_stats`. (incurs a run-time cost)
-- `--yjit-disable`: disable YJIT despite other `--yjit*` flags for lazily enabling it with `RubyVM::YJIT.enable`
-- `--yjit-code-gc`: enable code GC (disabled by default as of Ruby 3.3).
- It will cause all machine code to be discarded when the executable memory size limit is hit, meaning JIT compilation will then start over.
- This can allow you to use a lower executable memory size limit, but may cause a slight drop in performance when the limit is hit.
-- `--yjit-perf`: enable frame pointers and profiling with the `perf` tool
-- `--yjit-trace-exits`: produce a Marshal dump of backtraces from all exits. Automatically enables `--yjit-stats`
-- `--yjit-trace-exits=COUNTER`: produce a Marshal dump of backtraces from a counted exit or a fallback. Automatically enables `--yjit-stats`
-- `--yjit-trace-exits-sample-rate=N`: trace exit locations only every Nth occurrence. Automatically enables `--yjit-trace-exits`
+- `--yjit-trace-exits`: produce a Marshal dump of backtraces from specific exits. Automatically enables `--yjit-stats`
Note that there is also an environment variable `RUBY_YJIT_ENABLE` which can be used to enable YJIT.
This can be useful for some deployment scripts where specifying an extra command-line option to Ruby is not practical.
-You can also enable YJIT at run-time using `RubyVM::YJIT.enable`. This can allow you to enable YJIT after your application is done
-booting, which makes it possible to avoid compiling any initialization code.
-
-You can verify that YJIT is enabled using `RubyVM::YJIT.enabled?` or by checking that `ruby --yjit -v` includes the string `+YJIT`:
-
-```sh
-ruby --yjit -v
-ruby 3.3.0dev (2023-01-31T15:11:10Z master 2a0bf269c9) +YJIT dev [x86_64-darwin22]
-
-ruby --yjit -e "p RubyVM::YJIT.enabled?"
-true
-
-ruby -e "RubyVM::YJIT.enable; p RubyVM::YJIT.enabled?"
-true
-```
-
### Benchmarking
-We have collected a set of benchmarks and implemented a simple benchmarking harness in the [yjit-bench](https://github.com/Shopify/yjit-bench) repository. This benchmarking harness is designed to disable CPU frequency scaling, set process affinity and disable address space randomization so that the variance between benchmarking runs will be as small as possible.
+We have collected a set of benchmarks and implemented a simple benchmarking harness in the [yjit-bench](https://github.com/Shopify/yjit-bench) repository. This benchmarking harness is designed to disable CPU frequency scaling, set process affinity and disable address space randomization so that the variance between benchmarking runs will be as small as possible. Please kindly note that we are at an early stage in this project.
## Performance Tips for Production Deployments
While YJIT options default to what we think would work well for most workloads,
they might not necessarily be the best configuration for your application.
+
This section covers tips on improving YJIT performance in case YJIT does not
speed up your application in production.
### Increasing --yjit-exec-mem-size
When JIT code size (`RubyVM::YJIT.runtime_stats[:code_region_size]`) reaches this value,
-YJIT stops compiling new code. Increasing the executable memory size means more code
-can be optimized by YJIT, at the cost of more memory usage.
-
-If you start Ruby with `--yjit-stats`, e.g. using an environment variable `RUBYOPT=--yjit-stats`,
-`RubyVM::YJIT.runtime_stats[:ratio_in_yjit]` shows the ratio of YJIT-executed instructions in %.
-Ideally, `ratio_in_yjit` should be as large as 99%, and increasing `--yjit-exec-mem-size` often
-helps improving `ratio_in_yjit`.
+YJIT triggers "code GC" that frees all JIT code and starts recompiling everything.
+Compiling code takes some time, so scheduling code GC too frequently slows down your application.
+Increasing `--yjit-exec-mem-size` may speed up your application if `RubyVM::YJIT.runtime_stats[:code_gc_count]` is not 0 or 1.
### Running workers as long as possible
@@ -233,29 +201,30 @@ You should monitor the number of requests each process has served.
If you're periodically killing worker processes, e.g. with `unicorn-worker-killer` or `puma_worker_killer`,
you may want to reduce the killing frequency or increase the limit.
-## Reducing YJIT Memory Usage
+## Saving YJIT Memory Usage
YJIT allocates memory for JIT code and metadata. Enabling YJIT generally results in more memory usage.
+
This section goes over tips on minimizing YJIT memory usage in case it uses more than your capacity.
+### Increasing --yjit-call-threshold
+
+As of Ruby 3.2, `--yjit-call-threshold` defaults to 30. With this default, some applications end up
+compiling methods that are used only during the application boot. Increasing this option may help
+you reduce the size of JIT code and metadata. It's worth trying different values like `--yjit-call-threshold=100`.
+
+Note that increasing the value too much may result in compiling code too late.
+You should monitor how many requests each worker processes before it's restarted. For example,
+if each process only handles 1000 requests, `--yjit-call-threshold=1000` might be too large for your application.
+
### Decreasing --yjit-exec-mem-size
-The `--yjit-exec-mem-size` option specifies the JIT code size, but YJIT also uses memory for its metadata,
+`--yjit-exec-mem-size` specifies the JIT code size, but YJIT also uses memory for its metadata,
which often consumes more memory than JIT code. Generally, YJIT adds memory overhead by roughly
-3-4x of `--yjit-exec-mem-size` in production as of Ruby 3.3. You should multiply that by the number
+3-4x of `--yjit-exec-mem-size` in production as of Ruby 3.2. You should multiply that by the number
of worker processes to estimate the worst case memory overhead.
-`--yjit-exec-mem-size=48` is the default since Ruby 3.3.1,
-but smaller values like 32 MiB might make sense for your application.
-While doing so, you may want to monitor `RubyVM::YJIT.runtime_stats[:ratio_in_yjit]` as explained above.
-
-### Enabling YJIT lazily
-
-If you enable YJIT by `--yjit` options or `RUBY_YJIT_ENABLE=1`, YJIT may compile code that is
-used only during the application boot. `RubyVM::YJIT.enable` allows you to enable YJIT from Ruby code,
-and you can call this after your application is initialized, e.g. on Unicorn's `after_fork` hook.
-If you use any YJIT options (`--yjit-*`), YJIT will start at boot by default, but `--yjit-disable`
-allows you to start Ruby with the YJIT-disabled mode while passing YJIT tuning options.
+Running code GC adds overhead, but it could be still faster than recovering from a whole process killed by OOM.
## Code Optimization Tips
@@ -266,27 +235,27 @@ This section contains tips on writing Ruby code that will run as fast as possibl
- Avoid redefining the meaning of `nil`, equality, etc.
- Avoid allocating objects in the hot parts of your code
- Minimize layers of indirection
- - Avoid writing wrapper classes if you can (e.g. a class that only wraps a Ruby hash)
- - Avoid methods that just call another method
-- Ruby method calls are costly. Avoid things such as methods that only return a value from a hash
-- Try to write code so that the same variables and method arguments always have the same type
-- Avoid using `TracePoint` as it can cause YJIT to deoptimize code
-- Avoid using `Binding` as it can cause YJIT to deoptimize code
+ - Avoid classes that wrap objects if you can
+ - Avoid methods that just call another method, trivial one liner methods
+- Try to write code so that the same variables always have the same type
+- Use `while` loops if you can, instead of C methods like `Array#each`
+ - This is not idiomatic Ruby, but could help in hot methods
+- CRuby method calls are costly. Avoid things such as methods that only return a value from a hash or return a constant.
You can also use the `--yjit-stats` command-line option to see which bytecodes cause YJIT to exit, and refactor your code to avoid using these instructions in the hottest methods of your code.
### Other Statistics
-If you run `ruby` with `--yjit-stats`, YJIT will track and return performance statistics in `RubyVM::YJIT.runtime_stats`.
+If you run `ruby` with `--yjit --yjit-stats`, YJIT will track and return performance statistics in `RubyVM::YJIT.runtime_stats`.
```rb
-$ RUBYOPT="--yjit-stats" irb
+$ RUBYOPT="--yjit --yjit-stats" irb
irb(main):001:0> RubyVM::YJIT.runtime_stats
=>
{:inline_code_size=>340745,
:outlined_code_size=>297664,
:all_stats=>true,
- :yjit_insns_count=>1547816,
+ :exec_instruction=>1547816,
:send_callsite_not_simple=>7267,
:send_kw_splat=>7,
:send_ivar_set_method=>72,
@@ -295,43 +264,41 @@ irb(main):001:0> RubyVM::YJIT.runtime_stats
Some of the counters include:
-* `:yjit_insns_count` - how many Ruby bytecode instructions have been executed
-* `:binding_allocations` - number of bindings allocated
-* `:binding_set` - number of variables set via a binding
-* `:code_gc_count` - number of garbage collections of compiled code since process start
-* `:vm_insns_count` - number of instructions executed by the Ruby interpreter
-* `:compiled_iseq_count` - number of bytecode sequences compiled
-* `:inline_code_size` - size in bytes of compiled YJIT blocks
-* `:outline_code_size` - size in bytes of YJIT error-handling compiled code
-* `:side_exit_count` - number of side exits taken at runtime
-* `:total_exit_count` - number of exits, including side exits, taken at runtime
-* `:avg_len_in_yjit` - avg. number of instructions in compiled blocks before exiting to interpreter
+* :exec_instruction - how many Ruby bytecode instructions have been executed
+* :binding_allocations - number of bindings allocated
+* :binding_set - number of variables set via a binding
+* :code_gc_count - number of garbage collections of compiled code since process start
+* :vm_insns_count - number of instructions executed by the Ruby interpreter
+* :compiled_iseq_count - number of bytecode sequences compiled
+* :inline_code_size - size in bytes of compiled YJIT blocks
+* :outline_code_size - size in bytes of YJIT error-handling compiled code
+* :side_exit_count - number of side exits taken at runtime
+* :total_exit_count - number of exits, including side exits, taken at runtime
+* :avg_len_in_yjit - avg. number of instructions in compiled blocks before exiting to interpreter
-Counters starting with "exit_" show reasons for YJIT code taking a side exit (return to the interpreter.)
+Counters starting with "exit_" show reasons for YJIT code taking a side exit (return to the interpreter.) See yjit_hacking.md for more details.
-Performance counter names are not guaranteed to remain the same between Ruby versions. If you're curious what each counter means,
-it's usually best to search the source code for it &mdash; but it may change in a later Ruby version.
+Performance counter names are not guaranteed to remain the same between Ruby versions. If you're curious what one does, it's usually best to search the source code for it &mdash; but it may change in a later Ruby version.
-The printed text after a `--yjit-stats` run includes other information that may be named differently than the information in `RubyVM::YJIT.runtime_stats`.
+The printed text after a --yjit-stats run includes other information that may be named differently than the information in runtime_stats.
## Contributing
-We welcome open source contributions. You should feel free to open new issues to report bugs or just to ask questions.
+We welcome open source contributors. You should feel free to open new issues to report bugs or just to ask questions.
Suggestions on how to make this readme file more helpful for new contributors are most welcome.
Bug fixes and bug reports are very valuable to us. If you find a bug in YJIT, it's very possible be that nobody has reported it before,
or that we don't have a good reproduction for it, so please open an issue and provide as much information as you can about your configuration and a description of how you encountered the problem. List the commands you used to run YJIT so that we can easily reproduce the issue on our end and investigate it. If you are able to produce a small program reproducing the error to help us track it down, that is very much appreciated as well.
-If you would like to contribute a large patch to YJIT, we suggest opening an issue or a discussion on the [Shopify/ruby repository](https://github.com/Shopify/ruby/issues) so that
+If you would like to contribute a large patch to YJIT, we suggest opening an issue or a discussion on this repository so that
we can have an active discussion. A common problem is that sometimes people submit large pull requests to open source projects
without prior communication, and we have to reject them because the work they implemented does not fit within the design of the
-project. We want to save you time and frustration, so please reach out so we can have a productive discussion as to how
-you can contribute patches we will want to merge into YJIT.
+project. We want to save you time and frustration, so please reach out and we can have a productive discussion as to how
+you can contribute things we will want to merge into YJIT.
### Source Code Organization
The YJIT source code is divided between:
-
- `yjit.c`: code YJIT uses to interface with the rest of CRuby
- `yjit.h`: C definitions YJIT exposes to the rest of the CRuby
- `yjit.rb`: `YJIT` Ruby module that is exposed to Ruby
@@ -340,11 +307,10 @@ The YJIT source code is divided between:
- `yjit/src/core.rb`: basic block versioning logic, core structure of YJIT
- `yjit/src/stats.rs`: gathering of run-time statistics
- `yjit/src/options.rs`: handling of command-line options
-- `yjit/src/cruby.rs`: C bindings manually exposed to the Rust codebase
- `yjit/bindgen/src/main.rs`: C bindings exposed to the Rust codebase through bindgen
+- `yjit/src/cruby.rs`: C bindings manually exposed to the Rust codebase
The core of CRuby's interpreter logic is found in:
-
- `insns.def`: defines Ruby's bytecode instructions (gets compiled into `vm.inc`)
- `vm_insnshelper.c`: logic used by Ruby's bytecode instructions
- `vm_exec.c`: Ruby interpreter loop
@@ -365,13 +331,11 @@ add them to `yjit/cruby.rs` instead.
### Coding & Debugging Protips
-There are multiple test suites:
-
+There are 3 test suites:
- `make btest` (see `/bootstraptest`)
- `make test-all`
- `make test-spec`
- `make check` runs all of the above
-- `make yjit-smoke-test` runs quick checks to see that YJIT is working correctly
The tests can be run in parallel like this:
@@ -385,18 +349,12 @@ Or single-threaded like this, to more easily identify which specific test is fai
make test-all TESTOPTS=--verbose RUN_OPTS="--yjit-call-threshold=1"
```
-To run a single test file with `test-all`:
+To debug a single test in `test-all`:
```sh
make test-all TESTS='test/-ext-/marshal/test_usrmarshal.rb' RUNRUBYOPT=--debugger=lldb RUN_OPTS="--yjit-call-threshold=1"
```
-It's also possible to filter tests by name to run a single test:
-
-```sh
-make test-all TESTS='-n /test_float_plus/' RUN_OPTS="--yjit-call-threshold=1"
-```
-
You can also run one specific test in `btest`:
```sh
@@ -457,71 +415,3 @@ While in your i386 shell, install Cargo and Homebrew, then hack away!
2. Cargo will install in $HOME/.cargo by default, and I don't know a good way to change architectures after install
If you use Fish shell you can [read this link](https://tenderlovemaking.com/2022/01/07/homebrew-rosetta-and-ruby.html) for information on making the dev environment easier.
-
-## Profiling with Linux perf
-
-`--yjit-perf` allows you to profile JIT-ed methods along with other native functions using Linux perf.
-When you run Ruby with `perf record`, perf looks up `/tmp/perf-{pid}.map` to resolve symbols in JIT code,
-and this option lets YJIT write method symbols into that file as well as enabling frame pointers.
-
-### Call graph
-
-Here's an example way to use this option with [Firefox Profiler](https://profiler.firefox.com)
-(See also: [Profiling with Linux perf](https://profiler.firefox.com/docs/#/./guide-perf-profiling)):
-
-```bash
-# Compile the interpreter with frame pointers enabled
-./configure --enable-yjit --prefix=$HOME/.rubies/ruby-yjit --disable-install-doc cflags=-fno-omit-frame-pointer
-make -j && make install
-
-# [Optional] Allow running perf without sudo
-echo 0 | sudo tee /proc/sys/kernel/kptr_restrict
-echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
-
-# Profile Ruby with --yjit-perf
-cd ../yjit-bench
-PERF="record --call-graph fp" ruby --yjit-perf -Iharness-perf benchmarks/liquid-render/benchmark.rb
-
-# View results on Firefox Profiler https://profiler.firefox.com.
-# Create /tmp/test.perf as below and upload it using "Load a profile from file".
-perf script --fields +pid > /tmp/test.perf
-```
-
-### YJIT codegen
-
-You can also profile the number of cycles consumed by code generated by each YJIT function.
-
-```bash
-# Install perf
-apt-get install linux-tools-common linux-tools-generic linux-tools-`uname -r`
-
-# [Optional] Allow running perf without sudo
-echo 0 | sudo tee /proc/sys/kernel/kptr_restrict
-echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
-
-# Profile Ruby with --yjit-perf=codegen
-cd ../yjit-bench
-PERF=record ruby --yjit-perf=codegen -Iharness-perf benchmarks/lobsters/benchmark.rb
-
-# Aggregate results
-perf script > /tmp/perf.txt
-../ruby/misc/yjit_perf.py /tmp/perf.txt
-```
-
-#### Building perf with Python support
-
-The above instructions work fine for most people, but you could also use
-a handy `perf script -s` interface if you build perf from source.
-
-```bash
-# Build perf from source for Python support
-sudo apt-get install libpython3-dev python3-pip flex libtraceevent-dev \
- libelf-dev libunwind-dev libaudit-dev libslang2-dev libdw-dev
-git clone --depth=1 https://github.com/torvalds/linux
-cd linux/tools/perf
-make
-make install
-
-# Aggregate results
-perf script -s ../ruby/misc/yjit_perf.py
-```
diff --git a/doc/yjit/yjit_hacking.md b/doc/yjit/yjit_hacking.md
new file mode 100644
index 0000000000..4c4d742b73
--- /dev/null
+++ b/doc/yjit/yjit_hacking.md
@@ -0,0 +1,75 @@
+# YJIT Hacking
+
+## Code Generation and Assembly Language
+
+YJIT’s basic purpose is to take ISEQs and generate machine code.
+
+Documentation on each Ruby bytecode can be found in insns.def.
+
+YJIT uses those bytecodes as the “Basic Blocks†in Lazy Basic Block Versioning (LBBV.) For more deep details of LBBV, see yjit.md in this directory.
+
+Current YJIT has a simple assembler as a backend. Each method that generates code does it by emitting machine code:
+
+```
+# Excerpt of yjit_gen_exit() from yjit_codegen.c, Sept 2021
+// Generate an exit to return to the interpreter
+static uint32_t
+yjit_gen_exit(VALUE *exit_pc, ctx_t *ctx, codeblock_t *cb)
+{
+ const uint32_t code_pos = cb->write_pos;
+
+ ADD_COMMENT(cb, "exit to interpreter");
+
+ // Generate the code to exit to the interpreters
+ // Write the adjusted SP back into the CFP
+ if (ctx->sp_offset != 0) {
+ x86opnd_t stack_pointer = ctx_sp_opnd(ctx, 0);
+ lea(cb, REG_SP, stack_pointer);
+ mov(cb, member_opnd(REG_CFP, rb_control_frame_t, sp), REG_SP);
+ }
+
+ // Update CFP->PC
+ mov(cb, RAX, const_ptr_opnd(exit_pc));
+ mov(cb, member_opnd(REG_CFP, rb_control_frame_t, pc), RAX);
+```
+
+Later there will be a more complex backend.
+
+## Code Generation vs Code Execution
+
+When you see lea() call above (“load effective address,â€) it’s not running the LEA x86 instruction. It’s generating an LEA instruction to the codeblock pointer in the first argument. It will execute that instruction later, when the codeblock gets executed.
+
+This is subtle because YJIT will often wait to compile the method until you’re about to run it -- that’s when it knows the most about what types of arguments the method will receive. So it’s a compile-time instruction, but often it will defer compile-time until just barely before runtime.
+
+The ctx structure tracks what is known at compile time about the arguments being passed into the Ruby bytecode. Often YJIT will “peek†at an expected type before it generates machine code.
+
+## Inlined and Outlined Code
+
+When YJIT is generating code, it needs a code pointer. In many cases it needs two, usually called “cb†(codeblock) and “ocb†(out-of-line codeblock.)
+
+cb is for “inlined†normal code and ocb is for “outline†code such as exits. Inlined code is normal generated code for Ruby operations, while outlined code is for unusual and error conditions, such as encountering an unexpected parameter type and exiting to the interpreter.
+
+The purpose of the outlined code block is to keep things we believe are going to be infrequent somewhere else. That way we can keep the code in the inline block more linear and compact. Linear code, with as few branches as possible, is more easily predicted by the CPU. An exception or unsupported operation will cause YJIT to generate outlined code to handle it.
+
+If you search for ocb in yjit_codegen.c, you can see some places where out-of-line code is generated.
+
+YJIT statistics are only gathered when RUBY_DEBUG or YJIT_STATS is true. In some cases the code to increment YJIT statistics will be generated out-of-line, especially if those statistics are gathered when a side exit happens.
+
+## Statistics and Comments
+
+When RUBY_DEBUG is defined to a true value, YJIT will emit comments into the generated machine code. This can make disassemblies a lot more readable. When RUBY_DEBUG or YJIT_STATS is defined and stats are active (--yjit-stats or export YJIT_STATS=1), code will be generated to collect statistics during the run, and a report will be printed when the process exits.
+
+## Entering and Exiting the Interpreter
+
+YJIT won’t generate machine code for an ISEQ until it’s been run a certain number of times (10 by default.) Then, the next time the interpreter would call that ISEQ, it will call the generated machine code version instead. If YJIT hits an unexpected or unsupported operation, it will return to the normal interpreter.
+
+If YJIT returns to the interpreter, the behaviour will be correct but slower. YJIT only optimises part of some operations - for instance, YJIT will not optimise a BMETHOD call yet.
+
+When the interpreter calls to a YJIT-optimised method again, control will return to YJIT’s generated machine code. The more time that’s spent in YJIT-generated code (“ratio in YJIT,â€) the more CPU time YJIT can save with its optimisations.
+
+## Side Exits
+
+When YJIT has compiled an ISEQ and is running it later, sometimes it will hit an unexpected condition. It might see a parameter of a different type than before, or square-brackets might be used on a hash when they were first used on an array. In those cases, the generated code will contain a call to return to the interpreter at runtime, called a “side exit.â€
+
+Side exits are generated as out-of-line code.
+
diff --git a/enc/Makefile.in b/enc/Makefile.in
index ce93fdd22d..9d0c367134 100644
--- a/enc/Makefile.in
+++ b/enc/Makefile.in
@@ -40,7 +40,6 @@ BUILTRUBY = $(topdir)/miniruby$(EXEEXT)
empty =
AR = @AR@
-LD = @LD@
CC = @CC@
ARFLAGS = @ARFLAGS@$(empty)
RANLIB = @RANLIB@
@@ -57,7 +56,6 @@ DEFS = @DEFS@
CPPFLAGS = @CPPFLAGS@ -DONIG_ENC_REGISTER=rb_enc_register
LDFLAGS = @LDFLAGS@
LDSHARED = @LDSHARED@
-POSTLINK = @POSTLINK@
ldflags = $(LDFLAGS)
dldflags = @DLDFLAGS@
extdldflags = @EXTDLDFLAGS@
@@ -72,7 +70,6 @@ WORKDIRS = @WORKDIRS@
NULLCMD = @NULLCMD@
RM = @RM@
-RMALL = @RMALL@
RMDIR = @RMDIR@
RMDIRS = @RMDIRS@
MAKEDIRS = @MAKEDIRS@
@@ -84,9 +81,6 @@ all:
make-workdir:
$(Q)$(MAKEDIRS) $(WORKDIRS)
-.PHONY: encs all modencs libencs enc libenc trans libtrans srcs
-.PHONY: clean distclean realclean clean-srcs
-
clean:
distclean: clean
diff --git a/enc/depend b/enc/depend
index 2918a90a05..973ad93010 100644
--- a/enc/depend
+++ b/enc/depend
@@ -35,7 +35,6 @@ ENCSOS =<%ENCS.map {|e|%> $(ENCSODIR)/<%=e%>.$(DLEXT) \
<%}%> #
ENCCLEANLIBS = <%=cleanlibs.map {|clean|
clean.gsub(/\$\*(\.\w+)?/) {"$(ENCOBJS#{$1 ? ":.#{CONFIG["OBJEXT"]}=#{$1}" : ""})"}
- .gsub(/\$\(\KTARGET_SO(?=[:\)])/) {"ENCSOS"}
}.join(" ")%>
ENCCLEANOBJS = <%=cleanobjs.map {|clean|
clean.gsub(/\$\*(\.\w+)?/) {"$(ENCOBJS#{$1 ? ":.#{CONFIG["OBJEXT"]}=#{$1}" : ""})"}
@@ -52,7 +51,6 @@ TRANSSOS =<%TRANS.map {|e|%> $(ENCSODIR)/<%=e%>.$(DLEXT) \
<%}%> #
TRANSCLEANLIBS = <%=cleanlibs.map {|clean|
clean.gsub(/\$\*(\.\w+)?/) {"$(TRANSOBJS#{$1 ? ":.#{CONFIG["OBJEXT"]}=#{$1}" : ""})"}
- .gsub(/\$\(\KTARGET_SO(?=[:\)])/) {"TRANSSOS"}
}.join(" ")%>
TRANSCLEANOBJS = <%=cleanobjs.map {|clean|
clean.gsub(/\$\*(\.\w+)?/) {"$(TRANSOBJS#{$1 ? ":.#{CONFIG["OBJEXT"]}=#{$1}" : ""})"}
@@ -60,8 +58,12 @@ TRANSCLEANOBJS = <%=cleanobjs.map {|clean|
LIBTRANS=enc/libtrans.$(LIBEXT)
UNICODE_HDR_DIR = --missing-unicode-header-dir--
-encs all: <%= MODULE_TYPE == :static ? "lib" : "mod" %>encs
-modencs: enc trans
+encs: all
+% if MODULE_TYPE == :static
+all: libenc libtrans
+% else
+all: enc trans
+%end
libencs: libenc libtrans
enc: $(ENCSOS)
libenc: $(LIBENC)
@@ -153,7 +155,7 @@ enc/trans/transdb.$(OBJEXT): transdb.h
clean:
% %w[$(ENCSOS) $(LIBENC) $(ENCOBJS) $(ENCCLEANOBJS) $(ENCCLEANLIBS) $(TRANSSOS) $(LIBTRANS) $(TRANSOBJS) $(TRANSCLEANOBJS) $(TRANSCLEANLIBS) $(ENC_TRANS_D) $(ENC_TRANS_SO_D)].each do |clean|
- $(Q)$(RMALL) <%=pathrep[clean]%>
+ $(Q)$(RM) <%=pathrep[clean]%>
% end
% unless inplace
$(Q)$(RM) enc/unicode/*/casefold.h enc/unicode/*/name2ctype.h
@@ -232,7 +234,6 @@ enc/ascii.$(OBJEXT): internal/attr/noexcept.h
enc/ascii.$(OBJEXT): internal/attr/noinline.h
enc/ascii.$(OBJEXT): internal/attr/nonnull.h
enc/ascii.$(OBJEXT): internal/attr/noreturn.h
-enc/ascii.$(OBJEXT): internal/attr/packed_struct.h
enc/ascii.$(OBJEXT): internal/attr/pure.h
enc/ascii.$(OBJEXT): internal/attr/restrict.h
enc/ascii.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -301,6 +302,7 @@ enc/ascii.$(OBJEXT): internal/intern/enumerator.h
enc/ascii.$(OBJEXT): internal/intern/error.h
enc/ascii.$(OBJEXT): internal/intern/eval.h
enc/ascii.$(OBJEXT): internal/intern/file.h
+enc/ascii.$(OBJEXT): internal/intern/gc.h
enc/ascii.$(OBJEXT): internal/intern/hash.h
enc/ascii.$(OBJEXT): internal/intern/io.h
enc/ascii.$(OBJEXT): internal/intern/load.h
@@ -331,12 +333,12 @@ enc/ascii.$(OBJEXT): internal/memory.h
enc/ascii.$(OBJEXT): internal/method.h
enc/ascii.$(OBJEXT): internal/module.h
enc/ascii.$(OBJEXT): internal/newobj.h
+enc/ascii.$(OBJEXT): internal/rgengc.h
enc/ascii.$(OBJEXT): internal/scan_args.h
enc/ascii.$(OBJEXT): internal/special_consts.h
enc/ascii.$(OBJEXT): internal/static_assert.h
enc/ascii.$(OBJEXT): internal/stdalign.h
enc/ascii.$(OBJEXT): internal/stdbool.h
-enc/ascii.$(OBJEXT): internal/stdckdint.h
enc/ascii.$(OBJEXT): internal/symbol.h
enc/ascii.$(OBJEXT): internal/value.h
enc/ascii.$(OBJEXT): internal/value_type.h
@@ -403,7 +405,6 @@ enc/big5.$(OBJEXT): internal/attr/noexcept.h
enc/big5.$(OBJEXT): internal/attr/noinline.h
enc/big5.$(OBJEXT): internal/attr/nonnull.h
enc/big5.$(OBJEXT): internal/attr/noreturn.h
-enc/big5.$(OBJEXT): internal/attr/packed_struct.h
enc/big5.$(OBJEXT): internal/attr/pure.h
enc/big5.$(OBJEXT): internal/attr/restrict.h
enc/big5.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -463,6 +464,7 @@ enc/big5.$(OBJEXT): internal/intern/enumerator.h
enc/big5.$(OBJEXT): internal/intern/error.h
enc/big5.$(OBJEXT): internal/intern/eval.h
enc/big5.$(OBJEXT): internal/intern/file.h
+enc/big5.$(OBJEXT): internal/intern/gc.h
enc/big5.$(OBJEXT): internal/intern/hash.h
enc/big5.$(OBJEXT): internal/intern/io.h
enc/big5.$(OBJEXT): internal/intern/load.h
@@ -493,12 +495,12 @@ enc/big5.$(OBJEXT): internal/memory.h
enc/big5.$(OBJEXT): internal/method.h
enc/big5.$(OBJEXT): internal/module.h
enc/big5.$(OBJEXT): internal/newobj.h
+enc/big5.$(OBJEXT): internal/rgengc.h
enc/big5.$(OBJEXT): internal/scan_args.h
enc/big5.$(OBJEXT): internal/special_consts.h
enc/big5.$(OBJEXT): internal/static_assert.h
enc/big5.$(OBJEXT): internal/stdalign.h
enc/big5.$(OBJEXT): internal/stdbool.h
-enc/big5.$(OBJEXT): internal/stdckdint.h
enc/big5.$(OBJEXT): internal/symbol.h
enc/big5.$(OBJEXT): internal/value.h
enc/big5.$(OBJEXT): internal/value_type.h
@@ -566,7 +568,6 @@ enc/cesu_8.$(OBJEXT): internal/attr/noexcept.h
enc/cesu_8.$(OBJEXT): internal/attr/noinline.h
enc/cesu_8.$(OBJEXT): internal/attr/nonnull.h
enc/cesu_8.$(OBJEXT): internal/attr/noreturn.h
-enc/cesu_8.$(OBJEXT): internal/attr/packed_struct.h
enc/cesu_8.$(OBJEXT): internal/attr/pure.h
enc/cesu_8.$(OBJEXT): internal/attr/restrict.h
enc/cesu_8.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -635,6 +636,7 @@ enc/cesu_8.$(OBJEXT): internal/intern/enumerator.h
enc/cesu_8.$(OBJEXT): internal/intern/error.h
enc/cesu_8.$(OBJEXT): internal/intern/eval.h
enc/cesu_8.$(OBJEXT): internal/intern/file.h
+enc/cesu_8.$(OBJEXT): internal/intern/gc.h
enc/cesu_8.$(OBJEXT): internal/intern/hash.h
enc/cesu_8.$(OBJEXT): internal/intern/io.h
enc/cesu_8.$(OBJEXT): internal/intern/load.h
@@ -665,12 +667,12 @@ enc/cesu_8.$(OBJEXT): internal/memory.h
enc/cesu_8.$(OBJEXT): internal/method.h
enc/cesu_8.$(OBJEXT): internal/module.h
enc/cesu_8.$(OBJEXT): internal/newobj.h
+enc/cesu_8.$(OBJEXT): internal/rgengc.h
enc/cesu_8.$(OBJEXT): internal/scan_args.h
enc/cesu_8.$(OBJEXT): internal/special_consts.h
enc/cesu_8.$(OBJEXT): internal/static_assert.h
enc/cesu_8.$(OBJEXT): internal/stdalign.h
enc/cesu_8.$(OBJEXT): internal/stdbool.h
-enc/cesu_8.$(OBJEXT): internal/stdckdint.h
enc/cesu_8.$(OBJEXT): internal/symbol.h
enc/cesu_8.$(OBJEXT): internal/value.h
enc/cesu_8.$(OBJEXT): internal/value_type.h
@@ -737,7 +739,6 @@ enc/cp949.$(OBJEXT): internal/attr/noexcept.h
enc/cp949.$(OBJEXT): internal/attr/noinline.h
enc/cp949.$(OBJEXT): internal/attr/nonnull.h
enc/cp949.$(OBJEXT): internal/attr/noreturn.h
-enc/cp949.$(OBJEXT): internal/attr/packed_struct.h
enc/cp949.$(OBJEXT): internal/attr/pure.h
enc/cp949.$(OBJEXT): internal/attr/restrict.h
enc/cp949.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -797,6 +798,7 @@ enc/cp949.$(OBJEXT): internal/intern/enumerator.h
enc/cp949.$(OBJEXT): internal/intern/error.h
enc/cp949.$(OBJEXT): internal/intern/eval.h
enc/cp949.$(OBJEXT): internal/intern/file.h
+enc/cp949.$(OBJEXT): internal/intern/gc.h
enc/cp949.$(OBJEXT): internal/intern/hash.h
enc/cp949.$(OBJEXT): internal/intern/io.h
enc/cp949.$(OBJEXT): internal/intern/load.h
@@ -827,12 +829,12 @@ enc/cp949.$(OBJEXT): internal/memory.h
enc/cp949.$(OBJEXT): internal/method.h
enc/cp949.$(OBJEXT): internal/module.h
enc/cp949.$(OBJEXT): internal/newobj.h
+enc/cp949.$(OBJEXT): internal/rgengc.h
enc/cp949.$(OBJEXT): internal/scan_args.h
enc/cp949.$(OBJEXT): internal/special_consts.h
enc/cp949.$(OBJEXT): internal/static_assert.h
enc/cp949.$(OBJEXT): internal/stdalign.h
enc/cp949.$(OBJEXT): internal/stdbool.h
-enc/cp949.$(OBJEXT): internal/stdckdint.h
enc/cp949.$(OBJEXT): internal/symbol.h
enc/cp949.$(OBJEXT): internal/value.h
enc/cp949.$(OBJEXT): internal/value_type.h
@@ -898,7 +900,6 @@ enc/emacs_mule.$(OBJEXT): internal/attr/noexcept.h
enc/emacs_mule.$(OBJEXT): internal/attr/noinline.h
enc/emacs_mule.$(OBJEXT): internal/attr/nonnull.h
enc/emacs_mule.$(OBJEXT): internal/attr/noreturn.h
-enc/emacs_mule.$(OBJEXT): internal/attr/packed_struct.h
enc/emacs_mule.$(OBJEXT): internal/attr/pure.h
enc/emacs_mule.$(OBJEXT): internal/attr/restrict.h
enc/emacs_mule.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -958,6 +959,7 @@ enc/emacs_mule.$(OBJEXT): internal/intern/enumerator.h
enc/emacs_mule.$(OBJEXT): internal/intern/error.h
enc/emacs_mule.$(OBJEXT): internal/intern/eval.h
enc/emacs_mule.$(OBJEXT): internal/intern/file.h
+enc/emacs_mule.$(OBJEXT): internal/intern/gc.h
enc/emacs_mule.$(OBJEXT): internal/intern/hash.h
enc/emacs_mule.$(OBJEXT): internal/intern/io.h
enc/emacs_mule.$(OBJEXT): internal/intern/load.h
@@ -988,12 +990,12 @@ enc/emacs_mule.$(OBJEXT): internal/memory.h
enc/emacs_mule.$(OBJEXT): internal/method.h
enc/emacs_mule.$(OBJEXT): internal/module.h
enc/emacs_mule.$(OBJEXT): internal/newobj.h
+enc/emacs_mule.$(OBJEXT): internal/rgengc.h
enc/emacs_mule.$(OBJEXT): internal/scan_args.h
enc/emacs_mule.$(OBJEXT): internal/special_consts.h
enc/emacs_mule.$(OBJEXT): internal/static_assert.h
enc/emacs_mule.$(OBJEXT): internal/stdalign.h
enc/emacs_mule.$(OBJEXT): internal/stdbool.h
-enc/emacs_mule.$(OBJEXT): internal/stdckdint.h
enc/emacs_mule.$(OBJEXT): internal/symbol.h
enc/emacs_mule.$(OBJEXT): internal/value.h
enc/emacs_mule.$(OBJEXT): internal/value_type.h
@@ -1060,7 +1062,6 @@ enc/encdb.$(OBJEXT): internal/attr/noexcept.h
enc/encdb.$(OBJEXT): internal/attr/noinline.h
enc/encdb.$(OBJEXT): internal/attr/nonnull.h
enc/encdb.$(OBJEXT): internal/attr/noreturn.h
-enc/encdb.$(OBJEXT): internal/attr/packed_struct.h
enc/encdb.$(OBJEXT): internal/attr/pure.h
enc/encdb.$(OBJEXT): internal/attr/restrict.h
enc/encdb.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -1129,6 +1130,7 @@ enc/encdb.$(OBJEXT): internal/intern/enumerator.h
enc/encdb.$(OBJEXT): internal/intern/error.h
enc/encdb.$(OBJEXT): internal/intern/eval.h
enc/encdb.$(OBJEXT): internal/intern/file.h
+enc/encdb.$(OBJEXT): internal/intern/gc.h
enc/encdb.$(OBJEXT): internal/intern/hash.h
enc/encdb.$(OBJEXT): internal/intern/io.h
enc/encdb.$(OBJEXT): internal/intern/load.h
@@ -1159,12 +1161,12 @@ enc/encdb.$(OBJEXT): internal/memory.h
enc/encdb.$(OBJEXT): internal/method.h
enc/encdb.$(OBJEXT): internal/module.h
enc/encdb.$(OBJEXT): internal/newobj.h
+enc/encdb.$(OBJEXT): internal/rgengc.h
enc/encdb.$(OBJEXT): internal/scan_args.h
enc/encdb.$(OBJEXT): internal/special_consts.h
enc/encdb.$(OBJEXT): internal/static_assert.h
enc/encdb.$(OBJEXT): internal/stdalign.h
enc/encdb.$(OBJEXT): internal/stdbool.h
-enc/encdb.$(OBJEXT): internal/stdckdint.h
enc/encdb.$(OBJEXT): internal/symbol.h
enc/encdb.$(OBJEXT): internal/value.h
enc/encdb.$(OBJEXT): internal/value_type.h
@@ -1233,7 +1235,6 @@ enc/euc_jp.$(OBJEXT): internal/attr/noexcept.h
enc/euc_jp.$(OBJEXT): internal/attr/noinline.h
enc/euc_jp.$(OBJEXT): internal/attr/nonnull.h
enc/euc_jp.$(OBJEXT): internal/attr/noreturn.h
-enc/euc_jp.$(OBJEXT): internal/attr/packed_struct.h
enc/euc_jp.$(OBJEXT): internal/attr/pure.h
enc/euc_jp.$(OBJEXT): internal/attr/restrict.h
enc/euc_jp.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -1293,6 +1294,7 @@ enc/euc_jp.$(OBJEXT): internal/intern/enumerator.h
enc/euc_jp.$(OBJEXT): internal/intern/error.h
enc/euc_jp.$(OBJEXT): internal/intern/eval.h
enc/euc_jp.$(OBJEXT): internal/intern/file.h
+enc/euc_jp.$(OBJEXT): internal/intern/gc.h
enc/euc_jp.$(OBJEXT): internal/intern/hash.h
enc/euc_jp.$(OBJEXT): internal/intern/io.h
enc/euc_jp.$(OBJEXT): internal/intern/load.h
@@ -1323,12 +1325,12 @@ enc/euc_jp.$(OBJEXT): internal/memory.h
enc/euc_jp.$(OBJEXT): internal/method.h
enc/euc_jp.$(OBJEXT): internal/module.h
enc/euc_jp.$(OBJEXT): internal/newobj.h
+enc/euc_jp.$(OBJEXT): internal/rgengc.h
enc/euc_jp.$(OBJEXT): internal/scan_args.h
enc/euc_jp.$(OBJEXT): internal/special_consts.h
enc/euc_jp.$(OBJEXT): internal/static_assert.h
enc/euc_jp.$(OBJEXT): internal/stdalign.h
enc/euc_jp.$(OBJEXT): internal/stdbool.h
-enc/euc_jp.$(OBJEXT): internal/stdckdint.h
enc/euc_jp.$(OBJEXT): internal/symbol.h
enc/euc_jp.$(OBJEXT): internal/value.h
enc/euc_jp.$(OBJEXT): internal/value_type.h
@@ -1394,7 +1396,6 @@ enc/euc_kr.$(OBJEXT): internal/attr/noexcept.h
enc/euc_kr.$(OBJEXT): internal/attr/noinline.h
enc/euc_kr.$(OBJEXT): internal/attr/nonnull.h
enc/euc_kr.$(OBJEXT): internal/attr/noreturn.h
-enc/euc_kr.$(OBJEXT): internal/attr/packed_struct.h
enc/euc_kr.$(OBJEXT): internal/attr/pure.h
enc/euc_kr.$(OBJEXT): internal/attr/restrict.h
enc/euc_kr.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -1454,6 +1455,7 @@ enc/euc_kr.$(OBJEXT): internal/intern/enumerator.h
enc/euc_kr.$(OBJEXT): internal/intern/error.h
enc/euc_kr.$(OBJEXT): internal/intern/eval.h
enc/euc_kr.$(OBJEXT): internal/intern/file.h
+enc/euc_kr.$(OBJEXT): internal/intern/gc.h
enc/euc_kr.$(OBJEXT): internal/intern/hash.h
enc/euc_kr.$(OBJEXT): internal/intern/io.h
enc/euc_kr.$(OBJEXT): internal/intern/load.h
@@ -1484,12 +1486,12 @@ enc/euc_kr.$(OBJEXT): internal/memory.h
enc/euc_kr.$(OBJEXT): internal/method.h
enc/euc_kr.$(OBJEXT): internal/module.h
enc/euc_kr.$(OBJEXT): internal/newobj.h
+enc/euc_kr.$(OBJEXT): internal/rgengc.h
enc/euc_kr.$(OBJEXT): internal/scan_args.h
enc/euc_kr.$(OBJEXT): internal/special_consts.h
enc/euc_kr.$(OBJEXT): internal/static_assert.h
enc/euc_kr.$(OBJEXT): internal/stdalign.h
enc/euc_kr.$(OBJEXT): internal/stdbool.h
-enc/euc_kr.$(OBJEXT): internal/stdckdint.h
enc/euc_kr.$(OBJEXT): internal/symbol.h
enc/euc_kr.$(OBJEXT): internal/value.h
enc/euc_kr.$(OBJEXT): internal/value_type.h
@@ -1555,7 +1557,6 @@ enc/euc_tw.$(OBJEXT): internal/attr/noexcept.h
enc/euc_tw.$(OBJEXT): internal/attr/noinline.h
enc/euc_tw.$(OBJEXT): internal/attr/nonnull.h
enc/euc_tw.$(OBJEXT): internal/attr/noreturn.h
-enc/euc_tw.$(OBJEXT): internal/attr/packed_struct.h
enc/euc_tw.$(OBJEXT): internal/attr/pure.h
enc/euc_tw.$(OBJEXT): internal/attr/restrict.h
enc/euc_tw.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -1615,6 +1616,7 @@ enc/euc_tw.$(OBJEXT): internal/intern/enumerator.h
enc/euc_tw.$(OBJEXT): internal/intern/error.h
enc/euc_tw.$(OBJEXT): internal/intern/eval.h
enc/euc_tw.$(OBJEXT): internal/intern/file.h
+enc/euc_tw.$(OBJEXT): internal/intern/gc.h
enc/euc_tw.$(OBJEXT): internal/intern/hash.h
enc/euc_tw.$(OBJEXT): internal/intern/io.h
enc/euc_tw.$(OBJEXT): internal/intern/load.h
@@ -1645,12 +1647,12 @@ enc/euc_tw.$(OBJEXT): internal/memory.h
enc/euc_tw.$(OBJEXT): internal/method.h
enc/euc_tw.$(OBJEXT): internal/module.h
enc/euc_tw.$(OBJEXT): internal/newobj.h
+enc/euc_tw.$(OBJEXT): internal/rgengc.h
enc/euc_tw.$(OBJEXT): internal/scan_args.h
enc/euc_tw.$(OBJEXT): internal/special_consts.h
enc/euc_tw.$(OBJEXT): internal/static_assert.h
enc/euc_tw.$(OBJEXT): internal/stdalign.h
enc/euc_tw.$(OBJEXT): internal/stdbool.h
-enc/euc_tw.$(OBJEXT): internal/stdckdint.h
enc/euc_tw.$(OBJEXT): internal/symbol.h
enc/euc_tw.$(OBJEXT): internal/value.h
enc/euc_tw.$(OBJEXT): internal/value_type.h
@@ -1716,7 +1718,6 @@ enc/gb18030.$(OBJEXT): internal/attr/noexcept.h
enc/gb18030.$(OBJEXT): internal/attr/noinline.h
enc/gb18030.$(OBJEXT): internal/attr/nonnull.h
enc/gb18030.$(OBJEXT): internal/attr/noreturn.h
-enc/gb18030.$(OBJEXT): internal/attr/packed_struct.h
enc/gb18030.$(OBJEXT): internal/attr/pure.h
enc/gb18030.$(OBJEXT): internal/attr/restrict.h
enc/gb18030.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -1776,6 +1777,7 @@ enc/gb18030.$(OBJEXT): internal/intern/enumerator.h
enc/gb18030.$(OBJEXT): internal/intern/error.h
enc/gb18030.$(OBJEXT): internal/intern/eval.h
enc/gb18030.$(OBJEXT): internal/intern/file.h
+enc/gb18030.$(OBJEXT): internal/intern/gc.h
enc/gb18030.$(OBJEXT): internal/intern/hash.h
enc/gb18030.$(OBJEXT): internal/intern/io.h
enc/gb18030.$(OBJEXT): internal/intern/load.h
@@ -1806,12 +1808,12 @@ enc/gb18030.$(OBJEXT): internal/memory.h
enc/gb18030.$(OBJEXT): internal/method.h
enc/gb18030.$(OBJEXT): internal/module.h
enc/gb18030.$(OBJEXT): internal/newobj.h
+enc/gb18030.$(OBJEXT): internal/rgengc.h
enc/gb18030.$(OBJEXT): internal/scan_args.h
enc/gb18030.$(OBJEXT): internal/special_consts.h
enc/gb18030.$(OBJEXT): internal/static_assert.h
enc/gb18030.$(OBJEXT): internal/stdalign.h
enc/gb18030.$(OBJEXT): internal/stdbool.h
-enc/gb18030.$(OBJEXT): internal/stdckdint.h
enc/gb18030.$(OBJEXT): internal/symbol.h
enc/gb18030.$(OBJEXT): internal/value.h
enc/gb18030.$(OBJEXT): internal/value_type.h
@@ -1877,7 +1879,6 @@ enc/gb2312.$(OBJEXT): internal/attr/noexcept.h
enc/gb2312.$(OBJEXT): internal/attr/noinline.h
enc/gb2312.$(OBJEXT): internal/attr/nonnull.h
enc/gb2312.$(OBJEXT): internal/attr/noreturn.h
-enc/gb2312.$(OBJEXT): internal/attr/packed_struct.h
enc/gb2312.$(OBJEXT): internal/attr/pure.h
enc/gb2312.$(OBJEXT): internal/attr/restrict.h
enc/gb2312.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -1937,6 +1938,7 @@ enc/gb2312.$(OBJEXT): internal/intern/enumerator.h
enc/gb2312.$(OBJEXT): internal/intern/error.h
enc/gb2312.$(OBJEXT): internal/intern/eval.h
enc/gb2312.$(OBJEXT): internal/intern/file.h
+enc/gb2312.$(OBJEXT): internal/intern/gc.h
enc/gb2312.$(OBJEXT): internal/intern/hash.h
enc/gb2312.$(OBJEXT): internal/intern/io.h
enc/gb2312.$(OBJEXT): internal/intern/load.h
@@ -1967,12 +1969,12 @@ enc/gb2312.$(OBJEXT): internal/memory.h
enc/gb2312.$(OBJEXT): internal/method.h
enc/gb2312.$(OBJEXT): internal/module.h
enc/gb2312.$(OBJEXT): internal/newobj.h
+enc/gb2312.$(OBJEXT): internal/rgengc.h
enc/gb2312.$(OBJEXT): internal/scan_args.h
enc/gb2312.$(OBJEXT): internal/special_consts.h
enc/gb2312.$(OBJEXT): internal/static_assert.h
enc/gb2312.$(OBJEXT): internal/stdalign.h
enc/gb2312.$(OBJEXT): internal/stdbool.h
-enc/gb2312.$(OBJEXT): internal/stdckdint.h
enc/gb2312.$(OBJEXT): internal/symbol.h
enc/gb2312.$(OBJEXT): internal/value.h
enc/gb2312.$(OBJEXT): internal/value_type.h
@@ -2038,7 +2040,6 @@ enc/gbk.$(OBJEXT): internal/attr/noexcept.h
enc/gbk.$(OBJEXT): internal/attr/noinline.h
enc/gbk.$(OBJEXT): internal/attr/nonnull.h
enc/gbk.$(OBJEXT): internal/attr/noreturn.h
-enc/gbk.$(OBJEXT): internal/attr/packed_struct.h
enc/gbk.$(OBJEXT): internal/attr/pure.h
enc/gbk.$(OBJEXT): internal/attr/restrict.h
enc/gbk.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -2098,6 +2099,7 @@ enc/gbk.$(OBJEXT): internal/intern/enumerator.h
enc/gbk.$(OBJEXT): internal/intern/error.h
enc/gbk.$(OBJEXT): internal/intern/eval.h
enc/gbk.$(OBJEXT): internal/intern/file.h
+enc/gbk.$(OBJEXT): internal/intern/gc.h
enc/gbk.$(OBJEXT): internal/intern/hash.h
enc/gbk.$(OBJEXT): internal/intern/io.h
enc/gbk.$(OBJEXT): internal/intern/load.h
@@ -2128,12 +2130,12 @@ enc/gbk.$(OBJEXT): internal/memory.h
enc/gbk.$(OBJEXT): internal/method.h
enc/gbk.$(OBJEXT): internal/module.h
enc/gbk.$(OBJEXT): internal/newobj.h
+enc/gbk.$(OBJEXT): internal/rgengc.h
enc/gbk.$(OBJEXT): internal/scan_args.h
enc/gbk.$(OBJEXT): internal/special_consts.h
enc/gbk.$(OBJEXT): internal/static_assert.h
enc/gbk.$(OBJEXT): internal/stdalign.h
enc/gbk.$(OBJEXT): internal/stdbool.h
-enc/gbk.$(OBJEXT): internal/stdckdint.h
enc/gbk.$(OBJEXT): internal/symbol.h
enc/gbk.$(OBJEXT): internal/value.h
enc/gbk.$(OBJEXT): internal/value_type.h
@@ -2200,7 +2202,6 @@ enc/iso_8859_1.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_1.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_1.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_1.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_1.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_1.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_1.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_1.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -2260,6 +2261,7 @@ enc/iso_8859_1.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_1.$(OBJEXT): internal/intern/error.h
enc/iso_8859_1.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_1.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_1.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_1.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_1.$(OBJEXT): internal/intern/io.h
enc/iso_8859_1.$(OBJEXT): internal/intern/load.h
@@ -2290,12 +2292,12 @@ enc/iso_8859_1.$(OBJEXT): internal/memory.h
enc/iso_8859_1.$(OBJEXT): internal/method.h
enc/iso_8859_1.$(OBJEXT): internal/module.h
enc/iso_8859_1.$(OBJEXT): internal/newobj.h
+enc/iso_8859_1.$(OBJEXT): internal/rgengc.h
enc/iso_8859_1.$(OBJEXT): internal/scan_args.h
enc/iso_8859_1.$(OBJEXT): internal/special_consts.h
enc/iso_8859_1.$(OBJEXT): internal/static_assert.h
enc/iso_8859_1.$(OBJEXT): internal/stdalign.h
enc/iso_8859_1.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_1.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_1.$(OBJEXT): internal/symbol.h
enc/iso_8859_1.$(OBJEXT): internal/value.h
enc/iso_8859_1.$(OBJEXT): internal/value_type.h
@@ -2362,7 +2364,6 @@ enc/iso_8859_10.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_10.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_10.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_10.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_10.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_10.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_10.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_10.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -2422,6 +2423,7 @@ enc/iso_8859_10.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_10.$(OBJEXT): internal/intern/error.h
enc/iso_8859_10.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_10.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_10.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_10.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_10.$(OBJEXT): internal/intern/io.h
enc/iso_8859_10.$(OBJEXT): internal/intern/load.h
@@ -2452,12 +2454,12 @@ enc/iso_8859_10.$(OBJEXT): internal/memory.h
enc/iso_8859_10.$(OBJEXT): internal/method.h
enc/iso_8859_10.$(OBJEXT): internal/module.h
enc/iso_8859_10.$(OBJEXT): internal/newobj.h
+enc/iso_8859_10.$(OBJEXT): internal/rgengc.h
enc/iso_8859_10.$(OBJEXT): internal/scan_args.h
enc/iso_8859_10.$(OBJEXT): internal/special_consts.h
enc/iso_8859_10.$(OBJEXT): internal/static_assert.h
enc/iso_8859_10.$(OBJEXT): internal/stdalign.h
enc/iso_8859_10.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_10.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_10.$(OBJEXT): internal/symbol.h
enc/iso_8859_10.$(OBJEXT): internal/value.h
enc/iso_8859_10.$(OBJEXT): internal/value_type.h
@@ -2523,7 +2525,6 @@ enc/iso_8859_11.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_11.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_11.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_11.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_11.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_11.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_11.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_11.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -2583,6 +2584,7 @@ enc/iso_8859_11.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_11.$(OBJEXT): internal/intern/error.h
enc/iso_8859_11.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_11.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_11.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_11.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_11.$(OBJEXT): internal/intern/io.h
enc/iso_8859_11.$(OBJEXT): internal/intern/load.h
@@ -2613,12 +2615,12 @@ enc/iso_8859_11.$(OBJEXT): internal/memory.h
enc/iso_8859_11.$(OBJEXT): internal/method.h
enc/iso_8859_11.$(OBJEXT): internal/module.h
enc/iso_8859_11.$(OBJEXT): internal/newobj.h
+enc/iso_8859_11.$(OBJEXT): internal/rgengc.h
enc/iso_8859_11.$(OBJEXT): internal/scan_args.h
enc/iso_8859_11.$(OBJEXT): internal/special_consts.h
enc/iso_8859_11.$(OBJEXT): internal/static_assert.h
enc/iso_8859_11.$(OBJEXT): internal/stdalign.h
enc/iso_8859_11.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_11.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_11.$(OBJEXT): internal/symbol.h
enc/iso_8859_11.$(OBJEXT): internal/value.h
enc/iso_8859_11.$(OBJEXT): internal/value_type.h
@@ -2685,7 +2687,6 @@ enc/iso_8859_13.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_13.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_13.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_13.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_13.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_13.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_13.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_13.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -2745,6 +2746,7 @@ enc/iso_8859_13.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_13.$(OBJEXT): internal/intern/error.h
enc/iso_8859_13.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_13.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_13.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_13.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_13.$(OBJEXT): internal/intern/io.h
enc/iso_8859_13.$(OBJEXT): internal/intern/load.h
@@ -2775,12 +2777,12 @@ enc/iso_8859_13.$(OBJEXT): internal/memory.h
enc/iso_8859_13.$(OBJEXT): internal/method.h
enc/iso_8859_13.$(OBJEXT): internal/module.h
enc/iso_8859_13.$(OBJEXT): internal/newobj.h
+enc/iso_8859_13.$(OBJEXT): internal/rgengc.h
enc/iso_8859_13.$(OBJEXT): internal/scan_args.h
enc/iso_8859_13.$(OBJEXT): internal/special_consts.h
enc/iso_8859_13.$(OBJEXT): internal/static_assert.h
enc/iso_8859_13.$(OBJEXT): internal/stdalign.h
enc/iso_8859_13.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_13.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_13.$(OBJEXT): internal/symbol.h
enc/iso_8859_13.$(OBJEXT): internal/value.h
enc/iso_8859_13.$(OBJEXT): internal/value_type.h
@@ -2847,7 +2849,6 @@ enc/iso_8859_14.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_14.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_14.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_14.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_14.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_14.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_14.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_14.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -2907,6 +2908,7 @@ enc/iso_8859_14.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_14.$(OBJEXT): internal/intern/error.h
enc/iso_8859_14.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_14.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_14.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_14.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_14.$(OBJEXT): internal/intern/io.h
enc/iso_8859_14.$(OBJEXT): internal/intern/load.h
@@ -2937,12 +2939,12 @@ enc/iso_8859_14.$(OBJEXT): internal/memory.h
enc/iso_8859_14.$(OBJEXT): internal/method.h
enc/iso_8859_14.$(OBJEXT): internal/module.h
enc/iso_8859_14.$(OBJEXT): internal/newobj.h
+enc/iso_8859_14.$(OBJEXT): internal/rgengc.h
enc/iso_8859_14.$(OBJEXT): internal/scan_args.h
enc/iso_8859_14.$(OBJEXT): internal/special_consts.h
enc/iso_8859_14.$(OBJEXT): internal/static_assert.h
enc/iso_8859_14.$(OBJEXT): internal/stdalign.h
enc/iso_8859_14.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_14.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_14.$(OBJEXT): internal/symbol.h
enc/iso_8859_14.$(OBJEXT): internal/value.h
enc/iso_8859_14.$(OBJEXT): internal/value_type.h
@@ -3009,7 +3011,6 @@ enc/iso_8859_15.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_15.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_15.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_15.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_15.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_15.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_15.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_15.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -3069,6 +3070,7 @@ enc/iso_8859_15.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_15.$(OBJEXT): internal/intern/error.h
enc/iso_8859_15.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_15.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_15.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_15.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_15.$(OBJEXT): internal/intern/io.h
enc/iso_8859_15.$(OBJEXT): internal/intern/load.h
@@ -3099,12 +3101,12 @@ enc/iso_8859_15.$(OBJEXT): internal/memory.h
enc/iso_8859_15.$(OBJEXT): internal/method.h
enc/iso_8859_15.$(OBJEXT): internal/module.h
enc/iso_8859_15.$(OBJEXT): internal/newobj.h
+enc/iso_8859_15.$(OBJEXT): internal/rgengc.h
enc/iso_8859_15.$(OBJEXT): internal/scan_args.h
enc/iso_8859_15.$(OBJEXT): internal/special_consts.h
enc/iso_8859_15.$(OBJEXT): internal/static_assert.h
enc/iso_8859_15.$(OBJEXT): internal/stdalign.h
enc/iso_8859_15.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_15.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_15.$(OBJEXT): internal/symbol.h
enc/iso_8859_15.$(OBJEXT): internal/value.h
enc/iso_8859_15.$(OBJEXT): internal/value_type.h
@@ -3171,7 +3173,6 @@ enc/iso_8859_16.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_16.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_16.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_16.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_16.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_16.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_16.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_16.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -3231,6 +3232,7 @@ enc/iso_8859_16.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_16.$(OBJEXT): internal/intern/error.h
enc/iso_8859_16.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_16.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_16.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_16.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_16.$(OBJEXT): internal/intern/io.h
enc/iso_8859_16.$(OBJEXT): internal/intern/load.h
@@ -3261,12 +3263,12 @@ enc/iso_8859_16.$(OBJEXT): internal/memory.h
enc/iso_8859_16.$(OBJEXT): internal/method.h
enc/iso_8859_16.$(OBJEXT): internal/module.h
enc/iso_8859_16.$(OBJEXT): internal/newobj.h
+enc/iso_8859_16.$(OBJEXT): internal/rgengc.h
enc/iso_8859_16.$(OBJEXT): internal/scan_args.h
enc/iso_8859_16.$(OBJEXT): internal/special_consts.h
enc/iso_8859_16.$(OBJEXT): internal/static_assert.h
enc/iso_8859_16.$(OBJEXT): internal/stdalign.h
enc/iso_8859_16.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_16.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_16.$(OBJEXT): internal/symbol.h
enc/iso_8859_16.$(OBJEXT): internal/value.h
enc/iso_8859_16.$(OBJEXT): internal/value_type.h
@@ -3333,7 +3335,6 @@ enc/iso_8859_2.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_2.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_2.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_2.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_2.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_2.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_2.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_2.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -3393,6 +3394,7 @@ enc/iso_8859_2.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_2.$(OBJEXT): internal/intern/error.h
enc/iso_8859_2.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_2.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_2.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_2.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_2.$(OBJEXT): internal/intern/io.h
enc/iso_8859_2.$(OBJEXT): internal/intern/load.h
@@ -3423,12 +3425,12 @@ enc/iso_8859_2.$(OBJEXT): internal/memory.h
enc/iso_8859_2.$(OBJEXT): internal/method.h
enc/iso_8859_2.$(OBJEXT): internal/module.h
enc/iso_8859_2.$(OBJEXT): internal/newobj.h
+enc/iso_8859_2.$(OBJEXT): internal/rgengc.h
enc/iso_8859_2.$(OBJEXT): internal/scan_args.h
enc/iso_8859_2.$(OBJEXT): internal/special_consts.h
enc/iso_8859_2.$(OBJEXT): internal/static_assert.h
enc/iso_8859_2.$(OBJEXT): internal/stdalign.h
enc/iso_8859_2.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_2.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_2.$(OBJEXT): internal/symbol.h
enc/iso_8859_2.$(OBJEXT): internal/value.h
enc/iso_8859_2.$(OBJEXT): internal/value_type.h
@@ -3495,7 +3497,6 @@ enc/iso_8859_3.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_3.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_3.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_3.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_3.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_3.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_3.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_3.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -3555,6 +3556,7 @@ enc/iso_8859_3.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_3.$(OBJEXT): internal/intern/error.h
enc/iso_8859_3.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_3.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_3.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_3.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_3.$(OBJEXT): internal/intern/io.h
enc/iso_8859_3.$(OBJEXT): internal/intern/load.h
@@ -3585,12 +3587,12 @@ enc/iso_8859_3.$(OBJEXT): internal/memory.h
enc/iso_8859_3.$(OBJEXT): internal/method.h
enc/iso_8859_3.$(OBJEXT): internal/module.h
enc/iso_8859_3.$(OBJEXT): internal/newobj.h
+enc/iso_8859_3.$(OBJEXT): internal/rgengc.h
enc/iso_8859_3.$(OBJEXT): internal/scan_args.h
enc/iso_8859_3.$(OBJEXT): internal/special_consts.h
enc/iso_8859_3.$(OBJEXT): internal/static_assert.h
enc/iso_8859_3.$(OBJEXT): internal/stdalign.h
enc/iso_8859_3.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_3.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_3.$(OBJEXT): internal/symbol.h
enc/iso_8859_3.$(OBJEXT): internal/value.h
enc/iso_8859_3.$(OBJEXT): internal/value_type.h
@@ -3657,7 +3659,6 @@ enc/iso_8859_4.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_4.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_4.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_4.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_4.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_4.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_4.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_4.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -3717,6 +3718,7 @@ enc/iso_8859_4.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_4.$(OBJEXT): internal/intern/error.h
enc/iso_8859_4.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_4.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_4.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_4.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_4.$(OBJEXT): internal/intern/io.h
enc/iso_8859_4.$(OBJEXT): internal/intern/load.h
@@ -3747,12 +3749,12 @@ enc/iso_8859_4.$(OBJEXT): internal/memory.h
enc/iso_8859_4.$(OBJEXT): internal/method.h
enc/iso_8859_4.$(OBJEXT): internal/module.h
enc/iso_8859_4.$(OBJEXT): internal/newobj.h
+enc/iso_8859_4.$(OBJEXT): internal/rgengc.h
enc/iso_8859_4.$(OBJEXT): internal/scan_args.h
enc/iso_8859_4.$(OBJEXT): internal/special_consts.h
enc/iso_8859_4.$(OBJEXT): internal/static_assert.h
enc/iso_8859_4.$(OBJEXT): internal/stdalign.h
enc/iso_8859_4.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_4.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_4.$(OBJEXT): internal/symbol.h
enc/iso_8859_4.$(OBJEXT): internal/value.h
enc/iso_8859_4.$(OBJEXT): internal/value_type.h
@@ -3818,7 +3820,6 @@ enc/iso_8859_5.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_5.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_5.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_5.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_5.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_5.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_5.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_5.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -3878,6 +3879,7 @@ enc/iso_8859_5.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_5.$(OBJEXT): internal/intern/error.h
enc/iso_8859_5.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_5.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_5.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_5.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_5.$(OBJEXT): internal/intern/io.h
enc/iso_8859_5.$(OBJEXT): internal/intern/load.h
@@ -3908,12 +3910,12 @@ enc/iso_8859_5.$(OBJEXT): internal/memory.h
enc/iso_8859_5.$(OBJEXT): internal/method.h
enc/iso_8859_5.$(OBJEXT): internal/module.h
enc/iso_8859_5.$(OBJEXT): internal/newobj.h
+enc/iso_8859_5.$(OBJEXT): internal/rgengc.h
enc/iso_8859_5.$(OBJEXT): internal/scan_args.h
enc/iso_8859_5.$(OBJEXT): internal/special_consts.h
enc/iso_8859_5.$(OBJEXT): internal/static_assert.h
enc/iso_8859_5.$(OBJEXT): internal/stdalign.h
enc/iso_8859_5.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_5.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_5.$(OBJEXT): internal/symbol.h
enc/iso_8859_5.$(OBJEXT): internal/value.h
enc/iso_8859_5.$(OBJEXT): internal/value_type.h
@@ -3979,7 +3981,6 @@ enc/iso_8859_6.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_6.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_6.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_6.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_6.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_6.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_6.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_6.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -4039,6 +4040,7 @@ enc/iso_8859_6.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_6.$(OBJEXT): internal/intern/error.h
enc/iso_8859_6.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_6.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_6.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_6.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_6.$(OBJEXT): internal/intern/io.h
enc/iso_8859_6.$(OBJEXT): internal/intern/load.h
@@ -4069,12 +4071,12 @@ enc/iso_8859_6.$(OBJEXT): internal/memory.h
enc/iso_8859_6.$(OBJEXT): internal/method.h
enc/iso_8859_6.$(OBJEXT): internal/module.h
enc/iso_8859_6.$(OBJEXT): internal/newobj.h
+enc/iso_8859_6.$(OBJEXT): internal/rgengc.h
enc/iso_8859_6.$(OBJEXT): internal/scan_args.h
enc/iso_8859_6.$(OBJEXT): internal/special_consts.h
enc/iso_8859_6.$(OBJEXT): internal/static_assert.h
enc/iso_8859_6.$(OBJEXT): internal/stdalign.h
enc/iso_8859_6.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_6.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_6.$(OBJEXT): internal/symbol.h
enc/iso_8859_6.$(OBJEXT): internal/value.h
enc/iso_8859_6.$(OBJEXT): internal/value_type.h
@@ -4140,7 +4142,6 @@ enc/iso_8859_7.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_7.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_7.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_7.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_7.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_7.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_7.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_7.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -4200,6 +4201,7 @@ enc/iso_8859_7.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_7.$(OBJEXT): internal/intern/error.h
enc/iso_8859_7.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_7.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_7.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_7.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_7.$(OBJEXT): internal/intern/io.h
enc/iso_8859_7.$(OBJEXT): internal/intern/load.h
@@ -4230,12 +4232,12 @@ enc/iso_8859_7.$(OBJEXT): internal/memory.h
enc/iso_8859_7.$(OBJEXT): internal/method.h
enc/iso_8859_7.$(OBJEXT): internal/module.h
enc/iso_8859_7.$(OBJEXT): internal/newobj.h
+enc/iso_8859_7.$(OBJEXT): internal/rgengc.h
enc/iso_8859_7.$(OBJEXT): internal/scan_args.h
enc/iso_8859_7.$(OBJEXT): internal/special_consts.h
enc/iso_8859_7.$(OBJEXT): internal/static_assert.h
enc/iso_8859_7.$(OBJEXT): internal/stdalign.h
enc/iso_8859_7.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_7.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_7.$(OBJEXT): internal/symbol.h
enc/iso_8859_7.$(OBJEXT): internal/value.h
enc/iso_8859_7.$(OBJEXT): internal/value_type.h
@@ -4301,7 +4303,6 @@ enc/iso_8859_8.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_8.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_8.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_8.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_8.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_8.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_8.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_8.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -4361,6 +4362,7 @@ enc/iso_8859_8.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_8.$(OBJEXT): internal/intern/error.h
enc/iso_8859_8.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_8.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_8.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_8.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_8.$(OBJEXT): internal/intern/io.h
enc/iso_8859_8.$(OBJEXT): internal/intern/load.h
@@ -4391,12 +4393,12 @@ enc/iso_8859_8.$(OBJEXT): internal/memory.h
enc/iso_8859_8.$(OBJEXT): internal/method.h
enc/iso_8859_8.$(OBJEXT): internal/module.h
enc/iso_8859_8.$(OBJEXT): internal/newobj.h
+enc/iso_8859_8.$(OBJEXT): internal/rgengc.h
enc/iso_8859_8.$(OBJEXT): internal/scan_args.h
enc/iso_8859_8.$(OBJEXT): internal/special_consts.h
enc/iso_8859_8.$(OBJEXT): internal/static_assert.h
enc/iso_8859_8.$(OBJEXT): internal/stdalign.h
enc/iso_8859_8.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_8.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_8.$(OBJEXT): internal/symbol.h
enc/iso_8859_8.$(OBJEXT): internal/value.h
enc/iso_8859_8.$(OBJEXT): internal/value_type.h
@@ -4463,7 +4465,6 @@ enc/iso_8859_9.$(OBJEXT): internal/attr/noexcept.h
enc/iso_8859_9.$(OBJEXT): internal/attr/noinline.h
enc/iso_8859_9.$(OBJEXT): internal/attr/nonnull.h
enc/iso_8859_9.$(OBJEXT): internal/attr/noreturn.h
-enc/iso_8859_9.$(OBJEXT): internal/attr/packed_struct.h
enc/iso_8859_9.$(OBJEXT): internal/attr/pure.h
enc/iso_8859_9.$(OBJEXT): internal/attr/restrict.h
enc/iso_8859_9.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -4523,6 +4524,7 @@ enc/iso_8859_9.$(OBJEXT): internal/intern/enumerator.h
enc/iso_8859_9.$(OBJEXT): internal/intern/error.h
enc/iso_8859_9.$(OBJEXT): internal/intern/eval.h
enc/iso_8859_9.$(OBJEXT): internal/intern/file.h
+enc/iso_8859_9.$(OBJEXT): internal/intern/gc.h
enc/iso_8859_9.$(OBJEXT): internal/intern/hash.h
enc/iso_8859_9.$(OBJEXT): internal/intern/io.h
enc/iso_8859_9.$(OBJEXT): internal/intern/load.h
@@ -4553,12 +4555,12 @@ enc/iso_8859_9.$(OBJEXT): internal/memory.h
enc/iso_8859_9.$(OBJEXT): internal/method.h
enc/iso_8859_9.$(OBJEXT): internal/module.h
enc/iso_8859_9.$(OBJEXT): internal/newobj.h
+enc/iso_8859_9.$(OBJEXT): internal/rgengc.h
enc/iso_8859_9.$(OBJEXT): internal/scan_args.h
enc/iso_8859_9.$(OBJEXT): internal/special_consts.h
enc/iso_8859_9.$(OBJEXT): internal/static_assert.h
enc/iso_8859_9.$(OBJEXT): internal/stdalign.h
enc/iso_8859_9.$(OBJEXT): internal/stdbool.h
-enc/iso_8859_9.$(OBJEXT): internal/stdckdint.h
enc/iso_8859_9.$(OBJEXT): internal/symbol.h
enc/iso_8859_9.$(OBJEXT): internal/value.h
enc/iso_8859_9.$(OBJEXT): internal/value_type.h
@@ -4624,7 +4626,6 @@ enc/koi8_r.$(OBJEXT): internal/attr/noexcept.h
enc/koi8_r.$(OBJEXT): internal/attr/noinline.h
enc/koi8_r.$(OBJEXT): internal/attr/nonnull.h
enc/koi8_r.$(OBJEXT): internal/attr/noreturn.h
-enc/koi8_r.$(OBJEXT): internal/attr/packed_struct.h
enc/koi8_r.$(OBJEXT): internal/attr/pure.h
enc/koi8_r.$(OBJEXT): internal/attr/restrict.h
enc/koi8_r.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -4684,6 +4685,7 @@ enc/koi8_r.$(OBJEXT): internal/intern/enumerator.h
enc/koi8_r.$(OBJEXT): internal/intern/error.h
enc/koi8_r.$(OBJEXT): internal/intern/eval.h
enc/koi8_r.$(OBJEXT): internal/intern/file.h
+enc/koi8_r.$(OBJEXT): internal/intern/gc.h
enc/koi8_r.$(OBJEXT): internal/intern/hash.h
enc/koi8_r.$(OBJEXT): internal/intern/io.h
enc/koi8_r.$(OBJEXT): internal/intern/load.h
@@ -4714,12 +4716,12 @@ enc/koi8_r.$(OBJEXT): internal/memory.h
enc/koi8_r.$(OBJEXT): internal/method.h
enc/koi8_r.$(OBJEXT): internal/module.h
enc/koi8_r.$(OBJEXT): internal/newobj.h
+enc/koi8_r.$(OBJEXT): internal/rgengc.h
enc/koi8_r.$(OBJEXT): internal/scan_args.h
enc/koi8_r.$(OBJEXT): internal/special_consts.h
enc/koi8_r.$(OBJEXT): internal/static_assert.h
enc/koi8_r.$(OBJEXT): internal/stdalign.h
enc/koi8_r.$(OBJEXT): internal/stdbool.h
-enc/koi8_r.$(OBJEXT): internal/stdckdint.h
enc/koi8_r.$(OBJEXT): internal/symbol.h
enc/koi8_r.$(OBJEXT): internal/value.h
enc/koi8_r.$(OBJEXT): internal/value_type.h
@@ -4785,7 +4787,6 @@ enc/koi8_u.$(OBJEXT): internal/attr/noexcept.h
enc/koi8_u.$(OBJEXT): internal/attr/noinline.h
enc/koi8_u.$(OBJEXT): internal/attr/nonnull.h
enc/koi8_u.$(OBJEXT): internal/attr/noreturn.h
-enc/koi8_u.$(OBJEXT): internal/attr/packed_struct.h
enc/koi8_u.$(OBJEXT): internal/attr/pure.h
enc/koi8_u.$(OBJEXT): internal/attr/restrict.h
enc/koi8_u.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -4845,6 +4846,7 @@ enc/koi8_u.$(OBJEXT): internal/intern/enumerator.h
enc/koi8_u.$(OBJEXT): internal/intern/error.h
enc/koi8_u.$(OBJEXT): internal/intern/eval.h
enc/koi8_u.$(OBJEXT): internal/intern/file.h
+enc/koi8_u.$(OBJEXT): internal/intern/gc.h
enc/koi8_u.$(OBJEXT): internal/intern/hash.h
enc/koi8_u.$(OBJEXT): internal/intern/io.h
enc/koi8_u.$(OBJEXT): internal/intern/load.h
@@ -4875,12 +4877,12 @@ enc/koi8_u.$(OBJEXT): internal/memory.h
enc/koi8_u.$(OBJEXT): internal/method.h
enc/koi8_u.$(OBJEXT): internal/module.h
enc/koi8_u.$(OBJEXT): internal/newobj.h
+enc/koi8_u.$(OBJEXT): internal/rgengc.h
enc/koi8_u.$(OBJEXT): internal/scan_args.h
enc/koi8_u.$(OBJEXT): internal/special_consts.h
enc/koi8_u.$(OBJEXT): internal/static_assert.h
enc/koi8_u.$(OBJEXT): internal/stdalign.h
enc/koi8_u.$(OBJEXT): internal/stdbool.h
-enc/koi8_u.$(OBJEXT): internal/stdckdint.h
enc/koi8_u.$(OBJEXT): internal/symbol.h
enc/koi8_u.$(OBJEXT): internal/value.h
enc/koi8_u.$(OBJEXT): internal/value_type.h
@@ -4949,7 +4951,6 @@ enc/shift_jis.$(OBJEXT): internal/attr/noexcept.h
enc/shift_jis.$(OBJEXT): internal/attr/noinline.h
enc/shift_jis.$(OBJEXT): internal/attr/nonnull.h
enc/shift_jis.$(OBJEXT): internal/attr/noreturn.h
-enc/shift_jis.$(OBJEXT): internal/attr/packed_struct.h
enc/shift_jis.$(OBJEXT): internal/attr/pure.h
enc/shift_jis.$(OBJEXT): internal/attr/restrict.h
enc/shift_jis.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -5009,6 +5010,7 @@ enc/shift_jis.$(OBJEXT): internal/intern/enumerator.h
enc/shift_jis.$(OBJEXT): internal/intern/error.h
enc/shift_jis.$(OBJEXT): internal/intern/eval.h
enc/shift_jis.$(OBJEXT): internal/intern/file.h
+enc/shift_jis.$(OBJEXT): internal/intern/gc.h
enc/shift_jis.$(OBJEXT): internal/intern/hash.h
enc/shift_jis.$(OBJEXT): internal/intern/io.h
enc/shift_jis.$(OBJEXT): internal/intern/load.h
@@ -5039,12 +5041,12 @@ enc/shift_jis.$(OBJEXT): internal/memory.h
enc/shift_jis.$(OBJEXT): internal/method.h
enc/shift_jis.$(OBJEXT): internal/module.h
enc/shift_jis.$(OBJEXT): internal/newobj.h
+enc/shift_jis.$(OBJEXT): internal/rgengc.h
enc/shift_jis.$(OBJEXT): internal/scan_args.h
enc/shift_jis.$(OBJEXT): internal/special_consts.h
enc/shift_jis.$(OBJEXT): internal/static_assert.h
enc/shift_jis.$(OBJEXT): internal/stdalign.h
enc/shift_jis.$(OBJEXT): internal/stdbool.h
-enc/shift_jis.$(OBJEXT): internal/stdckdint.h
enc/shift_jis.$(OBJEXT): internal/symbol.h
enc/shift_jis.$(OBJEXT): internal/value.h
enc/shift_jis.$(OBJEXT): internal/value_type.h
@@ -5109,7 +5111,6 @@ enc/trans/big5.$(OBJEXT): internal/attr/noexcept.h
enc/trans/big5.$(OBJEXT): internal/attr/noinline.h
enc/trans/big5.$(OBJEXT): internal/attr/nonnull.h
enc/trans/big5.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/big5.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/big5.$(OBJEXT): internal/attr/pure.h
enc/trans/big5.$(OBJEXT): internal/attr/restrict.h
enc/trans/big5.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -5169,6 +5170,7 @@ enc/trans/big5.$(OBJEXT): internal/intern/enumerator.h
enc/trans/big5.$(OBJEXT): internal/intern/error.h
enc/trans/big5.$(OBJEXT): internal/intern/eval.h
enc/trans/big5.$(OBJEXT): internal/intern/file.h
+enc/trans/big5.$(OBJEXT): internal/intern/gc.h
enc/trans/big5.$(OBJEXT): internal/intern/hash.h
enc/trans/big5.$(OBJEXT): internal/intern/io.h
enc/trans/big5.$(OBJEXT): internal/intern/load.h
@@ -5199,12 +5201,12 @@ enc/trans/big5.$(OBJEXT): internal/memory.h
enc/trans/big5.$(OBJEXT): internal/method.h
enc/trans/big5.$(OBJEXT): internal/module.h
enc/trans/big5.$(OBJEXT): internal/newobj.h
+enc/trans/big5.$(OBJEXT): internal/rgengc.h
enc/trans/big5.$(OBJEXT): internal/scan_args.h
enc/trans/big5.$(OBJEXT): internal/special_consts.h
enc/trans/big5.$(OBJEXT): internal/static_assert.h
enc/trans/big5.$(OBJEXT): internal/stdalign.h
enc/trans/big5.$(OBJEXT): internal/stdbool.h
-enc/trans/big5.$(OBJEXT): internal/stdckdint.h
enc/trans/big5.$(OBJEXT): internal/symbol.h
enc/trans/big5.$(OBJEXT): internal/value.h
enc/trans/big5.$(OBJEXT): internal/value_type.h
@@ -5268,7 +5270,6 @@ enc/trans/cesu_8.$(OBJEXT): internal/attr/noexcept.h
enc/trans/cesu_8.$(OBJEXT): internal/attr/noinline.h
enc/trans/cesu_8.$(OBJEXT): internal/attr/nonnull.h
enc/trans/cesu_8.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/cesu_8.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/cesu_8.$(OBJEXT): internal/attr/pure.h
enc/trans/cesu_8.$(OBJEXT): internal/attr/restrict.h
enc/trans/cesu_8.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -5328,6 +5329,7 @@ enc/trans/cesu_8.$(OBJEXT): internal/intern/enumerator.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/error.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/eval.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/file.h
+enc/trans/cesu_8.$(OBJEXT): internal/intern/gc.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/hash.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/io.h
enc/trans/cesu_8.$(OBJEXT): internal/intern/load.h
@@ -5358,12 +5360,12 @@ enc/trans/cesu_8.$(OBJEXT): internal/memory.h
enc/trans/cesu_8.$(OBJEXT): internal/method.h
enc/trans/cesu_8.$(OBJEXT): internal/module.h
enc/trans/cesu_8.$(OBJEXT): internal/newobj.h
+enc/trans/cesu_8.$(OBJEXT): internal/rgengc.h
enc/trans/cesu_8.$(OBJEXT): internal/scan_args.h
enc/trans/cesu_8.$(OBJEXT): internal/special_consts.h
enc/trans/cesu_8.$(OBJEXT): internal/static_assert.h
enc/trans/cesu_8.$(OBJEXT): internal/stdalign.h
enc/trans/cesu_8.$(OBJEXT): internal/stdbool.h
-enc/trans/cesu_8.$(OBJEXT): internal/stdckdint.h
enc/trans/cesu_8.$(OBJEXT): internal/symbol.h
enc/trans/cesu_8.$(OBJEXT): internal/value.h
enc/trans/cesu_8.$(OBJEXT): internal/value_type.h
@@ -5427,7 +5429,6 @@ enc/trans/chinese.$(OBJEXT): internal/attr/noexcept.h
enc/trans/chinese.$(OBJEXT): internal/attr/noinline.h
enc/trans/chinese.$(OBJEXT): internal/attr/nonnull.h
enc/trans/chinese.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/chinese.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/chinese.$(OBJEXT): internal/attr/pure.h
enc/trans/chinese.$(OBJEXT): internal/attr/restrict.h
enc/trans/chinese.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -5487,6 +5488,7 @@ enc/trans/chinese.$(OBJEXT): internal/intern/enumerator.h
enc/trans/chinese.$(OBJEXT): internal/intern/error.h
enc/trans/chinese.$(OBJEXT): internal/intern/eval.h
enc/trans/chinese.$(OBJEXT): internal/intern/file.h
+enc/trans/chinese.$(OBJEXT): internal/intern/gc.h
enc/trans/chinese.$(OBJEXT): internal/intern/hash.h
enc/trans/chinese.$(OBJEXT): internal/intern/io.h
enc/trans/chinese.$(OBJEXT): internal/intern/load.h
@@ -5517,12 +5519,12 @@ enc/trans/chinese.$(OBJEXT): internal/memory.h
enc/trans/chinese.$(OBJEXT): internal/method.h
enc/trans/chinese.$(OBJEXT): internal/module.h
enc/trans/chinese.$(OBJEXT): internal/newobj.h
+enc/trans/chinese.$(OBJEXT): internal/rgengc.h
enc/trans/chinese.$(OBJEXT): internal/scan_args.h
enc/trans/chinese.$(OBJEXT): internal/special_consts.h
enc/trans/chinese.$(OBJEXT): internal/static_assert.h
enc/trans/chinese.$(OBJEXT): internal/stdalign.h
enc/trans/chinese.$(OBJEXT): internal/stdbool.h
-enc/trans/chinese.$(OBJEXT): internal/stdckdint.h
enc/trans/chinese.$(OBJEXT): internal/symbol.h
enc/trans/chinese.$(OBJEXT): internal/value.h
enc/trans/chinese.$(OBJEXT): internal/value_type.h
@@ -5586,7 +5588,6 @@ enc/trans/ebcdic.$(OBJEXT): internal/attr/noexcept.h
enc/trans/ebcdic.$(OBJEXT): internal/attr/noinline.h
enc/trans/ebcdic.$(OBJEXT): internal/attr/nonnull.h
enc/trans/ebcdic.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/ebcdic.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/ebcdic.$(OBJEXT): internal/attr/pure.h
enc/trans/ebcdic.$(OBJEXT): internal/attr/restrict.h
enc/trans/ebcdic.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -5646,6 +5647,7 @@ enc/trans/ebcdic.$(OBJEXT): internal/intern/enumerator.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/error.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/eval.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/file.h
+enc/trans/ebcdic.$(OBJEXT): internal/intern/gc.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/hash.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/io.h
enc/trans/ebcdic.$(OBJEXT): internal/intern/load.h
@@ -5676,12 +5678,12 @@ enc/trans/ebcdic.$(OBJEXT): internal/memory.h
enc/trans/ebcdic.$(OBJEXT): internal/method.h
enc/trans/ebcdic.$(OBJEXT): internal/module.h
enc/trans/ebcdic.$(OBJEXT): internal/newobj.h
+enc/trans/ebcdic.$(OBJEXT): internal/rgengc.h
enc/trans/ebcdic.$(OBJEXT): internal/scan_args.h
enc/trans/ebcdic.$(OBJEXT): internal/special_consts.h
enc/trans/ebcdic.$(OBJEXT): internal/static_assert.h
enc/trans/ebcdic.$(OBJEXT): internal/stdalign.h
enc/trans/ebcdic.$(OBJEXT): internal/stdbool.h
-enc/trans/ebcdic.$(OBJEXT): internal/stdckdint.h
enc/trans/ebcdic.$(OBJEXT): internal/symbol.h
enc/trans/ebcdic.$(OBJEXT): internal/value.h
enc/trans/ebcdic.$(OBJEXT): internal/value_type.h
@@ -5745,7 +5747,6 @@ enc/trans/emoji.$(OBJEXT): internal/attr/noexcept.h
enc/trans/emoji.$(OBJEXT): internal/attr/noinline.h
enc/trans/emoji.$(OBJEXT): internal/attr/nonnull.h
enc/trans/emoji.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/emoji.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/emoji.$(OBJEXT): internal/attr/pure.h
enc/trans/emoji.$(OBJEXT): internal/attr/restrict.h
enc/trans/emoji.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -5805,6 +5806,7 @@ enc/trans/emoji.$(OBJEXT): internal/intern/enumerator.h
enc/trans/emoji.$(OBJEXT): internal/intern/error.h
enc/trans/emoji.$(OBJEXT): internal/intern/eval.h
enc/trans/emoji.$(OBJEXT): internal/intern/file.h
+enc/trans/emoji.$(OBJEXT): internal/intern/gc.h
enc/trans/emoji.$(OBJEXT): internal/intern/hash.h
enc/trans/emoji.$(OBJEXT): internal/intern/io.h
enc/trans/emoji.$(OBJEXT): internal/intern/load.h
@@ -5835,12 +5837,12 @@ enc/trans/emoji.$(OBJEXT): internal/memory.h
enc/trans/emoji.$(OBJEXT): internal/method.h
enc/trans/emoji.$(OBJEXT): internal/module.h
enc/trans/emoji.$(OBJEXT): internal/newobj.h
+enc/trans/emoji.$(OBJEXT): internal/rgengc.h
enc/trans/emoji.$(OBJEXT): internal/scan_args.h
enc/trans/emoji.$(OBJEXT): internal/special_consts.h
enc/trans/emoji.$(OBJEXT): internal/static_assert.h
enc/trans/emoji.$(OBJEXT): internal/stdalign.h
enc/trans/emoji.$(OBJEXT): internal/stdbool.h
-enc/trans/emoji.$(OBJEXT): internal/stdckdint.h
enc/trans/emoji.$(OBJEXT): internal/symbol.h
enc/trans/emoji.$(OBJEXT): internal/value.h
enc/trans/emoji.$(OBJEXT): internal/value_type.h
@@ -5904,7 +5906,6 @@ enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/noexcept.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/noinline.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/nonnull.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/pure.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/restrict.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -5964,6 +5965,7 @@ enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/enumerator.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/error.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/eval.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/file.h
+enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/gc.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/hash.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/io.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/load.h
@@ -5994,12 +5996,12 @@ enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/memory.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/method.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/module.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/newobj.h
+enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/rgengc.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/scan_args.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/special_consts.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/static_assert.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/stdalign.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/stdbool.h
-enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/stdckdint.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/symbol.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/value.h
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/value_type.h
@@ -6063,7 +6065,6 @@ enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/noexcept.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/noinline.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/nonnull.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/pure.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/restrict.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -6123,6 +6124,7 @@ enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/enumerator.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/error.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/eval.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/file.h
+enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/gc.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/hash.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/io.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/load.h
@@ -6153,12 +6155,12 @@ enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/memory.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/method.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/module.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/newobj.h
+enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/rgengc.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/scan_args.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/special_consts.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/static_assert.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/stdalign.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/stdbool.h
-enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/stdckdint.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/symbol.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/value.h
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/value_type.h
@@ -6222,7 +6224,6 @@ enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/noexcept.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/noinline.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/nonnull.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/pure.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/restrict.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -6282,6 +6283,7 @@ enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/enumerator.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/error.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/eval.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/file.h
+enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/gc.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/hash.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/io.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/load.h
@@ -6312,12 +6314,12 @@ enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/memory.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/method.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/module.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/newobj.h
+enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/rgengc.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/scan_args.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/special_consts.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/static_assert.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/stdalign.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/stdbool.h
-enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/stdckdint.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/symbol.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/value.h
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/value_type.h
@@ -6381,7 +6383,6 @@ enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/noexcept.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/noinline.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/nonnull.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/pure.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/restrict.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -6441,6 +6442,7 @@ enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/enumerator.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/error.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/eval.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/file.h
+enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/gc.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/hash.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/io.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/load.h
@@ -6471,12 +6473,12 @@ enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/memory.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/method.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/module.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/newobj.h
+enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/rgengc.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/scan_args.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/special_consts.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/static_assert.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/stdalign.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/stdbool.h
-enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/stdckdint.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/symbol.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/value.h
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/value_type.h
@@ -6540,7 +6542,6 @@ enc/trans/escape.$(OBJEXT): internal/attr/noexcept.h
enc/trans/escape.$(OBJEXT): internal/attr/noinline.h
enc/trans/escape.$(OBJEXT): internal/attr/nonnull.h
enc/trans/escape.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/escape.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/escape.$(OBJEXT): internal/attr/pure.h
enc/trans/escape.$(OBJEXT): internal/attr/restrict.h
enc/trans/escape.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -6600,6 +6601,7 @@ enc/trans/escape.$(OBJEXT): internal/intern/enumerator.h
enc/trans/escape.$(OBJEXT): internal/intern/error.h
enc/trans/escape.$(OBJEXT): internal/intern/eval.h
enc/trans/escape.$(OBJEXT): internal/intern/file.h
+enc/trans/escape.$(OBJEXT): internal/intern/gc.h
enc/trans/escape.$(OBJEXT): internal/intern/hash.h
enc/trans/escape.$(OBJEXT): internal/intern/io.h
enc/trans/escape.$(OBJEXT): internal/intern/load.h
@@ -6630,12 +6632,12 @@ enc/trans/escape.$(OBJEXT): internal/memory.h
enc/trans/escape.$(OBJEXT): internal/method.h
enc/trans/escape.$(OBJEXT): internal/module.h
enc/trans/escape.$(OBJEXT): internal/newobj.h
+enc/trans/escape.$(OBJEXT): internal/rgengc.h
enc/trans/escape.$(OBJEXT): internal/scan_args.h
enc/trans/escape.$(OBJEXT): internal/special_consts.h
enc/trans/escape.$(OBJEXT): internal/static_assert.h
enc/trans/escape.$(OBJEXT): internal/stdalign.h
enc/trans/escape.$(OBJEXT): internal/stdbool.h
-enc/trans/escape.$(OBJEXT): internal/stdckdint.h
enc/trans/escape.$(OBJEXT): internal/symbol.h
enc/trans/escape.$(OBJEXT): internal/value.h
enc/trans/escape.$(OBJEXT): internal/value_type.h
@@ -6699,7 +6701,6 @@ enc/trans/gb18030.$(OBJEXT): internal/attr/noexcept.h
enc/trans/gb18030.$(OBJEXT): internal/attr/noinline.h
enc/trans/gb18030.$(OBJEXT): internal/attr/nonnull.h
enc/trans/gb18030.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/gb18030.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/gb18030.$(OBJEXT): internal/attr/pure.h
enc/trans/gb18030.$(OBJEXT): internal/attr/restrict.h
enc/trans/gb18030.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -6759,6 +6760,7 @@ enc/trans/gb18030.$(OBJEXT): internal/intern/enumerator.h
enc/trans/gb18030.$(OBJEXT): internal/intern/error.h
enc/trans/gb18030.$(OBJEXT): internal/intern/eval.h
enc/trans/gb18030.$(OBJEXT): internal/intern/file.h
+enc/trans/gb18030.$(OBJEXT): internal/intern/gc.h
enc/trans/gb18030.$(OBJEXT): internal/intern/hash.h
enc/trans/gb18030.$(OBJEXT): internal/intern/io.h
enc/trans/gb18030.$(OBJEXT): internal/intern/load.h
@@ -6789,12 +6791,12 @@ enc/trans/gb18030.$(OBJEXT): internal/memory.h
enc/trans/gb18030.$(OBJEXT): internal/method.h
enc/trans/gb18030.$(OBJEXT): internal/module.h
enc/trans/gb18030.$(OBJEXT): internal/newobj.h
+enc/trans/gb18030.$(OBJEXT): internal/rgengc.h
enc/trans/gb18030.$(OBJEXT): internal/scan_args.h
enc/trans/gb18030.$(OBJEXT): internal/special_consts.h
enc/trans/gb18030.$(OBJEXT): internal/static_assert.h
enc/trans/gb18030.$(OBJEXT): internal/stdalign.h
enc/trans/gb18030.$(OBJEXT): internal/stdbool.h
-enc/trans/gb18030.$(OBJEXT): internal/stdckdint.h
enc/trans/gb18030.$(OBJEXT): internal/symbol.h
enc/trans/gb18030.$(OBJEXT): internal/value.h
enc/trans/gb18030.$(OBJEXT): internal/value_type.h
@@ -6858,7 +6860,6 @@ enc/trans/gbk.$(OBJEXT): internal/attr/noexcept.h
enc/trans/gbk.$(OBJEXT): internal/attr/noinline.h
enc/trans/gbk.$(OBJEXT): internal/attr/nonnull.h
enc/trans/gbk.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/gbk.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/gbk.$(OBJEXT): internal/attr/pure.h
enc/trans/gbk.$(OBJEXT): internal/attr/restrict.h
enc/trans/gbk.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -6918,6 +6919,7 @@ enc/trans/gbk.$(OBJEXT): internal/intern/enumerator.h
enc/trans/gbk.$(OBJEXT): internal/intern/error.h
enc/trans/gbk.$(OBJEXT): internal/intern/eval.h
enc/trans/gbk.$(OBJEXT): internal/intern/file.h
+enc/trans/gbk.$(OBJEXT): internal/intern/gc.h
enc/trans/gbk.$(OBJEXT): internal/intern/hash.h
enc/trans/gbk.$(OBJEXT): internal/intern/io.h
enc/trans/gbk.$(OBJEXT): internal/intern/load.h
@@ -6948,12 +6950,12 @@ enc/trans/gbk.$(OBJEXT): internal/memory.h
enc/trans/gbk.$(OBJEXT): internal/method.h
enc/trans/gbk.$(OBJEXT): internal/module.h
enc/trans/gbk.$(OBJEXT): internal/newobj.h
+enc/trans/gbk.$(OBJEXT): internal/rgengc.h
enc/trans/gbk.$(OBJEXT): internal/scan_args.h
enc/trans/gbk.$(OBJEXT): internal/special_consts.h
enc/trans/gbk.$(OBJEXT): internal/static_assert.h
enc/trans/gbk.$(OBJEXT): internal/stdalign.h
enc/trans/gbk.$(OBJEXT): internal/stdbool.h
-enc/trans/gbk.$(OBJEXT): internal/stdckdint.h
enc/trans/gbk.$(OBJEXT): internal/symbol.h
enc/trans/gbk.$(OBJEXT): internal/value.h
enc/trans/gbk.$(OBJEXT): internal/value_type.h
@@ -7016,8 +7018,8 @@ enc/trans/iso2022.$(OBJEXT): internal/attr/nodiscard.h
enc/trans/iso2022.$(OBJEXT): internal/attr/noexcept.h
enc/trans/iso2022.$(OBJEXT): internal/attr/noinline.h
enc/trans/iso2022.$(OBJEXT): internal/attr/nonnull.h
+enc/trans/iso2022.$(OBJEXT): internal/attr/nonstring.h
enc/trans/iso2022.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/iso2022.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/iso2022.$(OBJEXT): internal/attr/pure.h
enc/trans/iso2022.$(OBJEXT): internal/attr/restrict.h
enc/trans/iso2022.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -7077,6 +7079,7 @@ enc/trans/iso2022.$(OBJEXT): internal/intern/enumerator.h
enc/trans/iso2022.$(OBJEXT): internal/intern/error.h
enc/trans/iso2022.$(OBJEXT): internal/intern/eval.h
enc/trans/iso2022.$(OBJEXT): internal/intern/file.h
+enc/trans/iso2022.$(OBJEXT): internal/intern/gc.h
enc/trans/iso2022.$(OBJEXT): internal/intern/hash.h
enc/trans/iso2022.$(OBJEXT): internal/intern/io.h
enc/trans/iso2022.$(OBJEXT): internal/intern/load.h
@@ -7107,12 +7110,12 @@ enc/trans/iso2022.$(OBJEXT): internal/memory.h
enc/trans/iso2022.$(OBJEXT): internal/method.h
enc/trans/iso2022.$(OBJEXT): internal/module.h
enc/trans/iso2022.$(OBJEXT): internal/newobj.h
+enc/trans/iso2022.$(OBJEXT): internal/rgengc.h
enc/trans/iso2022.$(OBJEXT): internal/scan_args.h
enc/trans/iso2022.$(OBJEXT): internal/special_consts.h
enc/trans/iso2022.$(OBJEXT): internal/static_assert.h
enc/trans/iso2022.$(OBJEXT): internal/stdalign.h
enc/trans/iso2022.$(OBJEXT): internal/stdbool.h
-enc/trans/iso2022.$(OBJEXT): internal/stdckdint.h
enc/trans/iso2022.$(OBJEXT): internal/symbol.h
enc/trans/iso2022.$(OBJEXT): internal/value.h
enc/trans/iso2022.$(OBJEXT): internal/value_type.h
@@ -7176,7 +7179,6 @@ enc/trans/japanese.$(OBJEXT): internal/attr/noexcept.h
enc/trans/japanese.$(OBJEXT): internal/attr/noinline.h
enc/trans/japanese.$(OBJEXT): internal/attr/nonnull.h
enc/trans/japanese.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/japanese.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/japanese.$(OBJEXT): internal/attr/pure.h
enc/trans/japanese.$(OBJEXT): internal/attr/restrict.h
enc/trans/japanese.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -7236,6 +7238,7 @@ enc/trans/japanese.$(OBJEXT): internal/intern/enumerator.h
enc/trans/japanese.$(OBJEXT): internal/intern/error.h
enc/trans/japanese.$(OBJEXT): internal/intern/eval.h
enc/trans/japanese.$(OBJEXT): internal/intern/file.h
+enc/trans/japanese.$(OBJEXT): internal/intern/gc.h
enc/trans/japanese.$(OBJEXT): internal/intern/hash.h
enc/trans/japanese.$(OBJEXT): internal/intern/io.h
enc/trans/japanese.$(OBJEXT): internal/intern/load.h
@@ -7266,12 +7269,12 @@ enc/trans/japanese.$(OBJEXT): internal/memory.h
enc/trans/japanese.$(OBJEXT): internal/method.h
enc/trans/japanese.$(OBJEXT): internal/module.h
enc/trans/japanese.$(OBJEXT): internal/newobj.h
+enc/trans/japanese.$(OBJEXT): internal/rgengc.h
enc/trans/japanese.$(OBJEXT): internal/scan_args.h
enc/trans/japanese.$(OBJEXT): internal/special_consts.h
enc/trans/japanese.$(OBJEXT): internal/static_assert.h
enc/trans/japanese.$(OBJEXT): internal/stdalign.h
enc/trans/japanese.$(OBJEXT): internal/stdbool.h
-enc/trans/japanese.$(OBJEXT): internal/stdckdint.h
enc/trans/japanese.$(OBJEXT): internal/symbol.h
enc/trans/japanese.$(OBJEXT): internal/value.h
enc/trans/japanese.$(OBJEXT): internal/value_type.h
@@ -7335,7 +7338,6 @@ enc/trans/japanese_euc.$(OBJEXT): internal/attr/noexcept.h
enc/trans/japanese_euc.$(OBJEXT): internal/attr/noinline.h
enc/trans/japanese_euc.$(OBJEXT): internal/attr/nonnull.h
enc/trans/japanese_euc.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/japanese_euc.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/japanese_euc.$(OBJEXT): internal/attr/pure.h
enc/trans/japanese_euc.$(OBJEXT): internal/attr/restrict.h
enc/trans/japanese_euc.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -7395,6 +7397,7 @@ enc/trans/japanese_euc.$(OBJEXT): internal/intern/enumerator.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/error.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/eval.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/file.h
+enc/trans/japanese_euc.$(OBJEXT): internal/intern/gc.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/hash.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/io.h
enc/trans/japanese_euc.$(OBJEXT): internal/intern/load.h
@@ -7425,12 +7428,12 @@ enc/trans/japanese_euc.$(OBJEXT): internal/memory.h
enc/trans/japanese_euc.$(OBJEXT): internal/method.h
enc/trans/japanese_euc.$(OBJEXT): internal/module.h
enc/trans/japanese_euc.$(OBJEXT): internal/newobj.h
+enc/trans/japanese_euc.$(OBJEXT): internal/rgengc.h
enc/trans/japanese_euc.$(OBJEXT): internal/scan_args.h
enc/trans/japanese_euc.$(OBJEXT): internal/special_consts.h
enc/trans/japanese_euc.$(OBJEXT): internal/static_assert.h
enc/trans/japanese_euc.$(OBJEXT): internal/stdalign.h
enc/trans/japanese_euc.$(OBJEXT): internal/stdbool.h
-enc/trans/japanese_euc.$(OBJEXT): internal/stdckdint.h
enc/trans/japanese_euc.$(OBJEXT): internal/symbol.h
enc/trans/japanese_euc.$(OBJEXT): internal/value.h
enc/trans/japanese_euc.$(OBJEXT): internal/value_type.h
@@ -7494,7 +7497,6 @@ enc/trans/japanese_sjis.$(OBJEXT): internal/attr/noexcept.h
enc/trans/japanese_sjis.$(OBJEXT): internal/attr/noinline.h
enc/trans/japanese_sjis.$(OBJEXT): internal/attr/nonnull.h
enc/trans/japanese_sjis.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/japanese_sjis.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/japanese_sjis.$(OBJEXT): internal/attr/pure.h
enc/trans/japanese_sjis.$(OBJEXT): internal/attr/restrict.h
enc/trans/japanese_sjis.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -7554,6 +7556,7 @@ enc/trans/japanese_sjis.$(OBJEXT): internal/intern/enumerator.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/error.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/eval.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/file.h
+enc/trans/japanese_sjis.$(OBJEXT): internal/intern/gc.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/hash.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/io.h
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/load.h
@@ -7584,12 +7587,12 @@ enc/trans/japanese_sjis.$(OBJEXT): internal/memory.h
enc/trans/japanese_sjis.$(OBJEXT): internal/method.h
enc/trans/japanese_sjis.$(OBJEXT): internal/module.h
enc/trans/japanese_sjis.$(OBJEXT): internal/newobj.h
+enc/trans/japanese_sjis.$(OBJEXT): internal/rgengc.h
enc/trans/japanese_sjis.$(OBJEXT): internal/scan_args.h
enc/trans/japanese_sjis.$(OBJEXT): internal/special_consts.h
enc/trans/japanese_sjis.$(OBJEXT): internal/static_assert.h
enc/trans/japanese_sjis.$(OBJEXT): internal/stdalign.h
enc/trans/japanese_sjis.$(OBJEXT): internal/stdbool.h
-enc/trans/japanese_sjis.$(OBJEXT): internal/stdckdint.h
enc/trans/japanese_sjis.$(OBJEXT): internal/symbol.h
enc/trans/japanese_sjis.$(OBJEXT): internal/value.h
enc/trans/japanese_sjis.$(OBJEXT): internal/value_type.h
@@ -7653,7 +7656,6 @@ enc/trans/korean.$(OBJEXT): internal/attr/noexcept.h
enc/trans/korean.$(OBJEXT): internal/attr/noinline.h
enc/trans/korean.$(OBJEXT): internal/attr/nonnull.h
enc/trans/korean.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/korean.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/korean.$(OBJEXT): internal/attr/pure.h
enc/trans/korean.$(OBJEXT): internal/attr/restrict.h
enc/trans/korean.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -7713,6 +7715,7 @@ enc/trans/korean.$(OBJEXT): internal/intern/enumerator.h
enc/trans/korean.$(OBJEXT): internal/intern/error.h
enc/trans/korean.$(OBJEXT): internal/intern/eval.h
enc/trans/korean.$(OBJEXT): internal/intern/file.h
+enc/trans/korean.$(OBJEXT): internal/intern/gc.h
enc/trans/korean.$(OBJEXT): internal/intern/hash.h
enc/trans/korean.$(OBJEXT): internal/intern/io.h
enc/trans/korean.$(OBJEXT): internal/intern/load.h
@@ -7743,12 +7746,12 @@ enc/trans/korean.$(OBJEXT): internal/memory.h
enc/trans/korean.$(OBJEXT): internal/method.h
enc/trans/korean.$(OBJEXT): internal/module.h
enc/trans/korean.$(OBJEXT): internal/newobj.h
+enc/trans/korean.$(OBJEXT): internal/rgengc.h
enc/trans/korean.$(OBJEXT): internal/scan_args.h
enc/trans/korean.$(OBJEXT): internal/special_consts.h
enc/trans/korean.$(OBJEXT): internal/static_assert.h
enc/trans/korean.$(OBJEXT): internal/stdalign.h
enc/trans/korean.$(OBJEXT): internal/stdbool.h
-enc/trans/korean.$(OBJEXT): internal/stdckdint.h
enc/trans/korean.$(OBJEXT): internal/symbol.h
enc/trans/korean.$(OBJEXT): internal/value.h
enc/trans/korean.$(OBJEXT): internal/value_type.h
@@ -7811,7 +7814,6 @@ enc/trans/newline.$(OBJEXT): internal/attr/noexcept.h
enc/trans/newline.$(OBJEXT): internal/attr/noinline.h
enc/trans/newline.$(OBJEXT): internal/attr/nonnull.h
enc/trans/newline.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/newline.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/newline.$(OBJEXT): internal/attr/pure.h
enc/trans/newline.$(OBJEXT): internal/attr/restrict.h
enc/trans/newline.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -7871,6 +7873,7 @@ enc/trans/newline.$(OBJEXT): internal/intern/enumerator.h
enc/trans/newline.$(OBJEXT): internal/intern/error.h
enc/trans/newline.$(OBJEXT): internal/intern/eval.h
enc/trans/newline.$(OBJEXT): internal/intern/file.h
+enc/trans/newline.$(OBJEXT): internal/intern/gc.h
enc/trans/newline.$(OBJEXT): internal/intern/hash.h
enc/trans/newline.$(OBJEXT): internal/intern/io.h
enc/trans/newline.$(OBJEXT): internal/intern/load.h
@@ -7901,12 +7904,12 @@ enc/trans/newline.$(OBJEXT): internal/memory.h
enc/trans/newline.$(OBJEXT): internal/method.h
enc/trans/newline.$(OBJEXT): internal/module.h
enc/trans/newline.$(OBJEXT): internal/newobj.h
+enc/trans/newline.$(OBJEXT): internal/rgengc.h
enc/trans/newline.$(OBJEXT): internal/scan_args.h
enc/trans/newline.$(OBJEXT): internal/special_consts.h
enc/trans/newline.$(OBJEXT): internal/static_assert.h
enc/trans/newline.$(OBJEXT): internal/stdalign.h
enc/trans/newline.$(OBJEXT): internal/stdbool.h
-enc/trans/newline.$(OBJEXT): internal/stdckdint.h
enc/trans/newline.$(OBJEXT): internal/symbol.h
enc/trans/newline.$(OBJEXT): internal/value.h
enc/trans/newline.$(OBJEXT): internal/value_type.h
@@ -7970,7 +7973,6 @@ enc/trans/single_byte.$(OBJEXT): internal/attr/noexcept.h
enc/trans/single_byte.$(OBJEXT): internal/attr/noinline.h
enc/trans/single_byte.$(OBJEXT): internal/attr/nonnull.h
enc/trans/single_byte.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/single_byte.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/single_byte.$(OBJEXT): internal/attr/pure.h
enc/trans/single_byte.$(OBJEXT): internal/attr/restrict.h
enc/trans/single_byte.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -8030,6 +8032,7 @@ enc/trans/single_byte.$(OBJEXT): internal/intern/enumerator.h
enc/trans/single_byte.$(OBJEXT): internal/intern/error.h
enc/trans/single_byte.$(OBJEXT): internal/intern/eval.h
enc/trans/single_byte.$(OBJEXT): internal/intern/file.h
+enc/trans/single_byte.$(OBJEXT): internal/intern/gc.h
enc/trans/single_byte.$(OBJEXT): internal/intern/hash.h
enc/trans/single_byte.$(OBJEXT): internal/intern/io.h
enc/trans/single_byte.$(OBJEXT): internal/intern/load.h
@@ -8060,12 +8063,12 @@ enc/trans/single_byte.$(OBJEXT): internal/memory.h
enc/trans/single_byte.$(OBJEXT): internal/method.h
enc/trans/single_byte.$(OBJEXT): internal/module.h
enc/trans/single_byte.$(OBJEXT): internal/newobj.h
+enc/trans/single_byte.$(OBJEXT): internal/rgengc.h
enc/trans/single_byte.$(OBJEXT): internal/scan_args.h
enc/trans/single_byte.$(OBJEXT): internal/special_consts.h
enc/trans/single_byte.$(OBJEXT): internal/static_assert.h
enc/trans/single_byte.$(OBJEXT): internal/stdalign.h
enc/trans/single_byte.$(OBJEXT): internal/stdbool.h
-enc/trans/single_byte.$(OBJEXT): internal/stdckdint.h
enc/trans/single_byte.$(OBJEXT): internal/symbol.h
enc/trans/single_byte.$(OBJEXT): internal/value.h
enc/trans/single_byte.$(OBJEXT): internal/value_type.h
@@ -8129,7 +8132,6 @@ enc/trans/transdb.$(OBJEXT): internal/attr/noexcept.h
enc/trans/transdb.$(OBJEXT): internal/attr/noinline.h
enc/trans/transdb.$(OBJEXT): internal/attr/nonnull.h
enc/trans/transdb.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/transdb.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/transdb.$(OBJEXT): internal/attr/pure.h
enc/trans/transdb.$(OBJEXT): internal/attr/restrict.h
enc/trans/transdb.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -8189,6 +8191,7 @@ enc/trans/transdb.$(OBJEXT): internal/intern/enumerator.h
enc/trans/transdb.$(OBJEXT): internal/intern/error.h
enc/trans/transdb.$(OBJEXT): internal/intern/eval.h
enc/trans/transdb.$(OBJEXT): internal/intern/file.h
+enc/trans/transdb.$(OBJEXT): internal/intern/gc.h
enc/trans/transdb.$(OBJEXT): internal/intern/hash.h
enc/trans/transdb.$(OBJEXT): internal/intern/io.h
enc/trans/transdb.$(OBJEXT): internal/intern/load.h
@@ -8219,12 +8222,12 @@ enc/trans/transdb.$(OBJEXT): internal/memory.h
enc/trans/transdb.$(OBJEXT): internal/method.h
enc/trans/transdb.$(OBJEXT): internal/module.h
enc/trans/transdb.$(OBJEXT): internal/newobj.h
+enc/trans/transdb.$(OBJEXT): internal/rgengc.h
enc/trans/transdb.$(OBJEXT): internal/scan_args.h
enc/trans/transdb.$(OBJEXT): internal/special_consts.h
enc/trans/transdb.$(OBJEXT): internal/static_assert.h
enc/trans/transdb.$(OBJEXT): internal/stdalign.h
enc/trans/transdb.$(OBJEXT): internal/stdbool.h
-enc/trans/transdb.$(OBJEXT): internal/stdckdint.h
enc/trans/transdb.$(OBJEXT): internal/symbol.h
enc/trans/transdb.$(OBJEXT): internal/value.h
enc/trans/transdb.$(OBJEXT): internal/value_type.h
@@ -8289,7 +8292,6 @@ enc/trans/utf8_mac.$(OBJEXT): internal/attr/noexcept.h
enc/trans/utf8_mac.$(OBJEXT): internal/attr/noinline.h
enc/trans/utf8_mac.$(OBJEXT): internal/attr/nonnull.h
enc/trans/utf8_mac.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/utf8_mac.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/utf8_mac.$(OBJEXT): internal/attr/pure.h
enc/trans/utf8_mac.$(OBJEXT): internal/attr/restrict.h
enc/trans/utf8_mac.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -8349,6 +8351,7 @@ enc/trans/utf8_mac.$(OBJEXT): internal/intern/enumerator.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/error.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/eval.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/file.h
+enc/trans/utf8_mac.$(OBJEXT): internal/intern/gc.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/hash.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/io.h
enc/trans/utf8_mac.$(OBJEXT): internal/intern/load.h
@@ -8379,12 +8382,12 @@ enc/trans/utf8_mac.$(OBJEXT): internal/memory.h
enc/trans/utf8_mac.$(OBJEXT): internal/method.h
enc/trans/utf8_mac.$(OBJEXT): internal/module.h
enc/trans/utf8_mac.$(OBJEXT): internal/newobj.h
+enc/trans/utf8_mac.$(OBJEXT): internal/rgengc.h
enc/trans/utf8_mac.$(OBJEXT): internal/scan_args.h
enc/trans/utf8_mac.$(OBJEXT): internal/special_consts.h
enc/trans/utf8_mac.$(OBJEXT): internal/static_assert.h
enc/trans/utf8_mac.$(OBJEXT): internal/stdalign.h
enc/trans/utf8_mac.$(OBJEXT): internal/stdbool.h
-enc/trans/utf8_mac.$(OBJEXT): internal/stdckdint.h
enc/trans/utf8_mac.$(OBJEXT): internal/symbol.h
enc/trans/utf8_mac.$(OBJEXT): internal/value.h
enc/trans/utf8_mac.$(OBJEXT): internal/value_type.h
@@ -8448,7 +8451,6 @@ enc/trans/utf_16_32.$(OBJEXT): internal/attr/noexcept.h
enc/trans/utf_16_32.$(OBJEXT): internal/attr/noinline.h
enc/trans/utf_16_32.$(OBJEXT): internal/attr/nonnull.h
enc/trans/utf_16_32.$(OBJEXT): internal/attr/noreturn.h
-enc/trans/utf_16_32.$(OBJEXT): internal/attr/packed_struct.h
enc/trans/utf_16_32.$(OBJEXT): internal/attr/pure.h
enc/trans/utf_16_32.$(OBJEXT): internal/attr/restrict.h
enc/trans/utf_16_32.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -8508,6 +8510,7 @@ enc/trans/utf_16_32.$(OBJEXT): internal/intern/enumerator.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/error.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/eval.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/file.h
+enc/trans/utf_16_32.$(OBJEXT): internal/intern/gc.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/hash.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/io.h
enc/trans/utf_16_32.$(OBJEXT): internal/intern/load.h
@@ -8538,12 +8541,12 @@ enc/trans/utf_16_32.$(OBJEXT): internal/memory.h
enc/trans/utf_16_32.$(OBJEXT): internal/method.h
enc/trans/utf_16_32.$(OBJEXT): internal/module.h
enc/trans/utf_16_32.$(OBJEXT): internal/newobj.h
+enc/trans/utf_16_32.$(OBJEXT): internal/rgengc.h
enc/trans/utf_16_32.$(OBJEXT): internal/scan_args.h
enc/trans/utf_16_32.$(OBJEXT): internal/special_consts.h
enc/trans/utf_16_32.$(OBJEXT): internal/static_assert.h
enc/trans/utf_16_32.$(OBJEXT): internal/stdalign.h
enc/trans/utf_16_32.$(OBJEXT): internal/stdbool.h
-enc/trans/utf_16_32.$(OBJEXT): internal/stdckdint.h
enc/trans/utf_16_32.$(OBJEXT): internal/symbol.h
enc/trans/utf_16_32.$(OBJEXT): internal/value.h
enc/trans/utf_16_32.$(OBJEXT): internal/value_type.h
@@ -8610,7 +8613,6 @@ enc/unicode.$(OBJEXT): internal/attr/noexcept.h
enc/unicode.$(OBJEXT): internal/attr/noinline.h
enc/unicode.$(OBJEXT): internal/attr/nonnull.h
enc/unicode.$(OBJEXT): internal/attr/noreturn.h
-enc/unicode.$(OBJEXT): internal/attr/packed_struct.h
enc/unicode.$(OBJEXT): internal/attr/pure.h
enc/unicode.$(OBJEXT): internal/attr/restrict.h
enc/unicode.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -8670,6 +8672,7 @@ enc/unicode.$(OBJEXT): internal/intern/enumerator.h
enc/unicode.$(OBJEXT): internal/intern/error.h
enc/unicode.$(OBJEXT): internal/intern/eval.h
enc/unicode.$(OBJEXT): internal/intern/file.h
+enc/unicode.$(OBJEXT): internal/intern/gc.h
enc/unicode.$(OBJEXT): internal/intern/hash.h
enc/unicode.$(OBJEXT): internal/intern/io.h
enc/unicode.$(OBJEXT): internal/intern/load.h
@@ -8700,12 +8703,12 @@ enc/unicode.$(OBJEXT): internal/memory.h
enc/unicode.$(OBJEXT): internal/method.h
enc/unicode.$(OBJEXT): internal/module.h
enc/unicode.$(OBJEXT): internal/newobj.h
+enc/unicode.$(OBJEXT): internal/rgengc.h
enc/unicode.$(OBJEXT): internal/scan_args.h
enc/unicode.$(OBJEXT): internal/special_consts.h
enc/unicode.$(OBJEXT): internal/static_assert.h
enc/unicode.$(OBJEXT): internal/stdalign.h
enc/unicode.$(OBJEXT): internal/stdbool.h
-enc/unicode.$(OBJEXT): internal/stdckdint.h
enc/unicode.$(OBJEXT): internal/symbol.h
enc/unicode.$(OBJEXT): internal/value.h
enc/unicode.$(OBJEXT): internal/value_type.h
@@ -8772,7 +8775,6 @@ enc/us_ascii.$(OBJEXT): internal/attr/noexcept.h
enc/us_ascii.$(OBJEXT): internal/attr/noinline.h
enc/us_ascii.$(OBJEXT): internal/attr/nonnull.h
enc/us_ascii.$(OBJEXT): internal/attr/noreturn.h
-enc/us_ascii.$(OBJEXT): internal/attr/packed_struct.h
enc/us_ascii.$(OBJEXT): internal/attr/pure.h
enc/us_ascii.$(OBJEXT): internal/attr/restrict.h
enc/us_ascii.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -8841,6 +8843,7 @@ enc/us_ascii.$(OBJEXT): internal/intern/enumerator.h
enc/us_ascii.$(OBJEXT): internal/intern/error.h
enc/us_ascii.$(OBJEXT): internal/intern/eval.h
enc/us_ascii.$(OBJEXT): internal/intern/file.h
+enc/us_ascii.$(OBJEXT): internal/intern/gc.h
enc/us_ascii.$(OBJEXT): internal/intern/hash.h
enc/us_ascii.$(OBJEXT): internal/intern/io.h
enc/us_ascii.$(OBJEXT): internal/intern/load.h
@@ -8871,12 +8874,12 @@ enc/us_ascii.$(OBJEXT): internal/memory.h
enc/us_ascii.$(OBJEXT): internal/method.h
enc/us_ascii.$(OBJEXT): internal/module.h
enc/us_ascii.$(OBJEXT): internal/newobj.h
+enc/us_ascii.$(OBJEXT): internal/rgengc.h
enc/us_ascii.$(OBJEXT): internal/scan_args.h
enc/us_ascii.$(OBJEXT): internal/special_consts.h
enc/us_ascii.$(OBJEXT): internal/static_assert.h
enc/us_ascii.$(OBJEXT): internal/stdalign.h
enc/us_ascii.$(OBJEXT): internal/stdbool.h
-enc/us_ascii.$(OBJEXT): internal/stdckdint.h
enc/us_ascii.$(OBJEXT): internal/symbol.h
enc/us_ascii.$(OBJEXT): internal/value.h
enc/us_ascii.$(OBJEXT): internal/value_type.h
@@ -8944,7 +8947,6 @@ enc/utf_16be.$(OBJEXT): internal/attr/noexcept.h
enc/utf_16be.$(OBJEXT): internal/attr/noinline.h
enc/utf_16be.$(OBJEXT): internal/attr/nonnull.h
enc/utf_16be.$(OBJEXT): internal/attr/noreturn.h
-enc/utf_16be.$(OBJEXT): internal/attr/packed_struct.h
enc/utf_16be.$(OBJEXT): internal/attr/pure.h
enc/utf_16be.$(OBJEXT): internal/attr/restrict.h
enc/utf_16be.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -9004,6 +9006,7 @@ enc/utf_16be.$(OBJEXT): internal/intern/enumerator.h
enc/utf_16be.$(OBJEXT): internal/intern/error.h
enc/utf_16be.$(OBJEXT): internal/intern/eval.h
enc/utf_16be.$(OBJEXT): internal/intern/file.h
+enc/utf_16be.$(OBJEXT): internal/intern/gc.h
enc/utf_16be.$(OBJEXT): internal/intern/hash.h
enc/utf_16be.$(OBJEXT): internal/intern/io.h
enc/utf_16be.$(OBJEXT): internal/intern/load.h
@@ -9034,12 +9037,12 @@ enc/utf_16be.$(OBJEXT): internal/memory.h
enc/utf_16be.$(OBJEXT): internal/method.h
enc/utf_16be.$(OBJEXT): internal/module.h
enc/utf_16be.$(OBJEXT): internal/newobj.h
+enc/utf_16be.$(OBJEXT): internal/rgengc.h
enc/utf_16be.$(OBJEXT): internal/scan_args.h
enc/utf_16be.$(OBJEXT): internal/special_consts.h
enc/utf_16be.$(OBJEXT): internal/static_assert.h
enc/utf_16be.$(OBJEXT): internal/stdalign.h
enc/utf_16be.$(OBJEXT): internal/stdbool.h
-enc/utf_16be.$(OBJEXT): internal/stdckdint.h
enc/utf_16be.$(OBJEXT): internal/symbol.h
enc/utf_16be.$(OBJEXT): internal/value.h
enc/utf_16be.$(OBJEXT): internal/value_type.h
@@ -9106,7 +9109,6 @@ enc/utf_16le.$(OBJEXT): internal/attr/noexcept.h
enc/utf_16le.$(OBJEXT): internal/attr/noinline.h
enc/utf_16le.$(OBJEXT): internal/attr/nonnull.h
enc/utf_16le.$(OBJEXT): internal/attr/noreturn.h
-enc/utf_16le.$(OBJEXT): internal/attr/packed_struct.h
enc/utf_16le.$(OBJEXT): internal/attr/pure.h
enc/utf_16le.$(OBJEXT): internal/attr/restrict.h
enc/utf_16le.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -9166,6 +9168,7 @@ enc/utf_16le.$(OBJEXT): internal/intern/enumerator.h
enc/utf_16le.$(OBJEXT): internal/intern/error.h
enc/utf_16le.$(OBJEXT): internal/intern/eval.h
enc/utf_16le.$(OBJEXT): internal/intern/file.h
+enc/utf_16le.$(OBJEXT): internal/intern/gc.h
enc/utf_16le.$(OBJEXT): internal/intern/hash.h
enc/utf_16le.$(OBJEXT): internal/intern/io.h
enc/utf_16le.$(OBJEXT): internal/intern/load.h
@@ -9196,12 +9199,12 @@ enc/utf_16le.$(OBJEXT): internal/memory.h
enc/utf_16le.$(OBJEXT): internal/method.h
enc/utf_16le.$(OBJEXT): internal/module.h
enc/utf_16le.$(OBJEXT): internal/newobj.h
+enc/utf_16le.$(OBJEXT): internal/rgengc.h
enc/utf_16le.$(OBJEXT): internal/scan_args.h
enc/utf_16le.$(OBJEXT): internal/special_consts.h
enc/utf_16le.$(OBJEXT): internal/static_assert.h
enc/utf_16le.$(OBJEXT): internal/stdalign.h
enc/utf_16le.$(OBJEXT): internal/stdbool.h
-enc/utf_16le.$(OBJEXT): internal/stdckdint.h
enc/utf_16le.$(OBJEXT): internal/symbol.h
enc/utf_16le.$(OBJEXT): internal/value.h
enc/utf_16le.$(OBJEXT): internal/value_type.h
@@ -9268,7 +9271,6 @@ enc/utf_32be.$(OBJEXT): internal/attr/noexcept.h
enc/utf_32be.$(OBJEXT): internal/attr/noinline.h
enc/utf_32be.$(OBJEXT): internal/attr/nonnull.h
enc/utf_32be.$(OBJEXT): internal/attr/noreturn.h
-enc/utf_32be.$(OBJEXT): internal/attr/packed_struct.h
enc/utf_32be.$(OBJEXT): internal/attr/pure.h
enc/utf_32be.$(OBJEXT): internal/attr/restrict.h
enc/utf_32be.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -9328,6 +9330,7 @@ enc/utf_32be.$(OBJEXT): internal/intern/enumerator.h
enc/utf_32be.$(OBJEXT): internal/intern/error.h
enc/utf_32be.$(OBJEXT): internal/intern/eval.h
enc/utf_32be.$(OBJEXT): internal/intern/file.h
+enc/utf_32be.$(OBJEXT): internal/intern/gc.h
enc/utf_32be.$(OBJEXT): internal/intern/hash.h
enc/utf_32be.$(OBJEXT): internal/intern/io.h
enc/utf_32be.$(OBJEXT): internal/intern/load.h
@@ -9358,12 +9361,12 @@ enc/utf_32be.$(OBJEXT): internal/memory.h
enc/utf_32be.$(OBJEXT): internal/method.h
enc/utf_32be.$(OBJEXT): internal/module.h
enc/utf_32be.$(OBJEXT): internal/newobj.h
+enc/utf_32be.$(OBJEXT): internal/rgengc.h
enc/utf_32be.$(OBJEXT): internal/scan_args.h
enc/utf_32be.$(OBJEXT): internal/special_consts.h
enc/utf_32be.$(OBJEXT): internal/static_assert.h
enc/utf_32be.$(OBJEXT): internal/stdalign.h
enc/utf_32be.$(OBJEXT): internal/stdbool.h
-enc/utf_32be.$(OBJEXT): internal/stdckdint.h
enc/utf_32be.$(OBJEXT): internal/symbol.h
enc/utf_32be.$(OBJEXT): internal/value.h
enc/utf_32be.$(OBJEXT): internal/value_type.h
@@ -9430,7 +9433,6 @@ enc/utf_32le.$(OBJEXT): internal/attr/noexcept.h
enc/utf_32le.$(OBJEXT): internal/attr/noinline.h
enc/utf_32le.$(OBJEXT): internal/attr/nonnull.h
enc/utf_32le.$(OBJEXT): internal/attr/noreturn.h
-enc/utf_32le.$(OBJEXT): internal/attr/packed_struct.h
enc/utf_32le.$(OBJEXT): internal/attr/pure.h
enc/utf_32le.$(OBJEXT): internal/attr/restrict.h
enc/utf_32le.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -9490,6 +9492,7 @@ enc/utf_32le.$(OBJEXT): internal/intern/enumerator.h
enc/utf_32le.$(OBJEXT): internal/intern/error.h
enc/utf_32le.$(OBJEXT): internal/intern/eval.h
enc/utf_32le.$(OBJEXT): internal/intern/file.h
+enc/utf_32le.$(OBJEXT): internal/intern/gc.h
enc/utf_32le.$(OBJEXT): internal/intern/hash.h
enc/utf_32le.$(OBJEXT): internal/intern/io.h
enc/utf_32le.$(OBJEXT): internal/intern/load.h
@@ -9520,12 +9523,12 @@ enc/utf_32le.$(OBJEXT): internal/memory.h
enc/utf_32le.$(OBJEXT): internal/method.h
enc/utf_32le.$(OBJEXT): internal/module.h
enc/utf_32le.$(OBJEXT): internal/newobj.h
+enc/utf_32le.$(OBJEXT): internal/rgengc.h
enc/utf_32le.$(OBJEXT): internal/scan_args.h
enc/utf_32le.$(OBJEXT): internal/special_consts.h
enc/utf_32le.$(OBJEXT): internal/static_assert.h
enc/utf_32le.$(OBJEXT): internal/stdalign.h
enc/utf_32le.$(OBJEXT): internal/stdbool.h
-enc/utf_32le.$(OBJEXT): internal/stdckdint.h
enc/utf_32le.$(OBJEXT): internal/symbol.h
enc/utf_32le.$(OBJEXT): internal/value.h
enc/utf_32le.$(OBJEXT): internal/value_type.h
@@ -9592,7 +9595,6 @@ enc/utf_8.$(OBJEXT): internal/attr/noexcept.h
enc/utf_8.$(OBJEXT): internal/attr/noinline.h
enc/utf_8.$(OBJEXT): internal/attr/nonnull.h
enc/utf_8.$(OBJEXT): internal/attr/noreturn.h
-enc/utf_8.$(OBJEXT): internal/attr/packed_struct.h
enc/utf_8.$(OBJEXT): internal/attr/pure.h
enc/utf_8.$(OBJEXT): internal/attr/restrict.h
enc/utf_8.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -9661,6 +9663,7 @@ enc/utf_8.$(OBJEXT): internal/intern/enumerator.h
enc/utf_8.$(OBJEXT): internal/intern/error.h
enc/utf_8.$(OBJEXT): internal/intern/eval.h
enc/utf_8.$(OBJEXT): internal/intern/file.h
+enc/utf_8.$(OBJEXT): internal/intern/gc.h
enc/utf_8.$(OBJEXT): internal/intern/hash.h
enc/utf_8.$(OBJEXT): internal/intern/io.h
enc/utf_8.$(OBJEXT): internal/intern/load.h
@@ -9691,12 +9694,12 @@ enc/utf_8.$(OBJEXT): internal/memory.h
enc/utf_8.$(OBJEXT): internal/method.h
enc/utf_8.$(OBJEXT): internal/module.h
enc/utf_8.$(OBJEXT): internal/newobj.h
+enc/utf_8.$(OBJEXT): internal/rgengc.h
enc/utf_8.$(OBJEXT): internal/scan_args.h
enc/utf_8.$(OBJEXT): internal/special_consts.h
enc/utf_8.$(OBJEXT): internal/static_assert.h
enc/utf_8.$(OBJEXT): internal/stdalign.h
enc/utf_8.$(OBJEXT): internal/stdbool.h
-enc/utf_8.$(OBJEXT): internal/stdckdint.h
enc/utf_8.$(OBJEXT): internal/symbol.h
enc/utf_8.$(OBJEXT): internal/value.h
enc/utf_8.$(OBJEXT): internal/value_type.h
@@ -9764,7 +9767,6 @@ enc/windows_1250.$(OBJEXT): internal/attr/noexcept.h
enc/windows_1250.$(OBJEXT): internal/attr/noinline.h
enc/windows_1250.$(OBJEXT): internal/attr/nonnull.h
enc/windows_1250.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_1250.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_1250.$(OBJEXT): internal/attr/pure.h
enc/windows_1250.$(OBJEXT): internal/attr/restrict.h
enc/windows_1250.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -9824,6 +9826,7 @@ enc/windows_1250.$(OBJEXT): internal/intern/enumerator.h
enc/windows_1250.$(OBJEXT): internal/intern/error.h
enc/windows_1250.$(OBJEXT): internal/intern/eval.h
enc/windows_1250.$(OBJEXT): internal/intern/file.h
+enc/windows_1250.$(OBJEXT): internal/intern/gc.h
enc/windows_1250.$(OBJEXT): internal/intern/hash.h
enc/windows_1250.$(OBJEXT): internal/intern/io.h
enc/windows_1250.$(OBJEXT): internal/intern/load.h
@@ -9854,12 +9857,12 @@ enc/windows_1250.$(OBJEXT): internal/memory.h
enc/windows_1250.$(OBJEXT): internal/method.h
enc/windows_1250.$(OBJEXT): internal/module.h
enc/windows_1250.$(OBJEXT): internal/newobj.h
+enc/windows_1250.$(OBJEXT): internal/rgengc.h
enc/windows_1250.$(OBJEXT): internal/scan_args.h
enc/windows_1250.$(OBJEXT): internal/special_consts.h
enc/windows_1250.$(OBJEXT): internal/static_assert.h
enc/windows_1250.$(OBJEXT): internal/stdalign.h
enc/windows_1250.$(OBJEXT): internal/stdbool.h
-enc/windows_1250.$(OBJEXT): internal/stdckdint.h
enc/windows_1250.$(OBJEXT): internal/symbol.h
enc/windows_1250.$(OBJEXT): internal/value.h
enc/windows_1250.$(OBJEXT): internal/value_type.h
@@ -9925,7 +9928,6 @@ enc/windows_1251.$(OBJEXT): internal/attr/noexcept.h
enc/windows_1251.$(OBJEXT): internal/attr/noinline.h
enc/windows_1251.$(OBJEXT): internal/attr/nonnull.h
enc/windows_1251.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_1251.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_1251.$(OBJEXT): internal/attr/pure.h
enc/windows_1251.$(OBJEXT): internal/attr/restrict.h
enc/windows_1251.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -9985,6 +9987,7 @@ enc/windows_1251.$(OBJEXT): internal/intern/enumerator.h
enc/windows_1251.$(OBJEXT): internal/intern/error.h
enc/windows_1251.$(OBJEXT): internal/intern/eval.h
enc/windows_1251.$(OBJEXT): internal/intern/file.h
+enc/windows_1251.$(OBJEXT): internal/intern/gc.h
enc/windows_1251.$(OBJEXT): internal/intern/hash.h
enc/windows_1251.$(OBJEXT): internal/intern/io.h
enc/windows_1251.$(OBJEXT): internal/intern/load.h
@@ -10015,12 +10018,12 @@ enc/windows_1251.$(OBJEXT): internal/memory.h
enc/windows_1251.$(OBJEXT): internal/method.h
enc/windows_1251.$(OBJEXT): internal/module.h
enc/windows_1251.$(OBJEXT): internal/newobj.h
+enc/windows_1251.$(OBJEXT): internal/rgengc.h
enc/windows_1251.$(OBJEXT): internal/scan_args.h
enc/windows_1251.$(OBJEXT): internal/special_consts.h
enc/windows_1251.$(OBJEXT): internal/static_assert.h
enc/windows_1251.$(OBJEXT): internal/stdalign.h
enc/windows_1251.$(OBJEXT): internal/stdbool.h
-enc/windows_1251.$(OBJEXT): internal/stdckdint.h
enc/windows_1251.$(OBJEXT): internal/symbol.h
enc/windows_1251.$(OBJEXT): internal/value.h
enc/windows_1251.$(OBJEXT): internal/value_type.h
@@ -10087,7 +10090,6 @@ enc/windows_1252.$(OBJEXT): internal/attr/noexcept.h
enc/windows_1252.$(OBJEXT): internal/attr/noinline.h
enc/windows_1252.$(OBJEXT): internal/attr/nonnull.h
enc/windows_1252.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_1252.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_1252.$(OBJEXT): internal/attr/pure.h
enc/windows_1252.$(OBJEXT): internal/attr/restrict.h
enc/windows_1252.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -10147,6 +10149,7 @@ enc/windows_1252.$(OBJEXT): internal/intern/enumerator.h
enc/windows_1252.$(OBJEXT): internal/intern/error.h
enc/windows_1252.$(OBJEXT): internal/intern/eval.h
enc/windows_1252.$(OBJEXT): internal/intern/file.h
+enc/windows_1252.$(OBJEXT): internal/intern/gc.h
enc/windows_1252.$(OBJEXT): internal/intern/hash.h
enc/windows_1252.$(OBJEXT): internal/intern/io.h
enc/windows_1252.$(OBJEXT): internal/intern/load.h
@@ -10177,12 +10180,12 @@ enc/windows_1252.$(OBJEXT): internal/memory.h
enc/windows_1252.$(OBJEXT): internal/method.h
enc/windows_1252.$(OBJEXT): internal/module.h
enc/windows_1252.$(OBJEXT): internal/newobj.h
+enc/windows_1252.$(OBJEXT): internal/rgengc.h
enc/windows_1252.$(OBJEXT): internal/scan_args.h
enc/windows_1252.$(OBJEXT): internal/special_consts.h
enc/windows_1252.$(OBJEXT): internal/static_assert.h
enc/windows_1252.$(OBJEXT): internal/stdalign.h
enc/windows_1252.$(OBJEXT): internal/stdbool.h
-enc/windows_1252.$(OBJEXT): internal/stdckdint.h
enc/windows_1252.$(OBJEXT): internal/symbol.h
enc/windows_1252.$(OBJEXT): internal/value.h
enc/windows_1252.$(OBJEXT): internal/value_type.h
@@ -10248,7 +10251,6 @@ enc/windows_1253.$(OBJEXT): internal/attr/noexcept.h
enc/windows_1253.$(OBJEXT): internal/attr/noinline.h
enc/windows_1253.$(OBJEXT): internal/attr/nonnull.h
enc/windows_1253.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_1253.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_1253.$(OBJEXT): internal/attr/pure.h
enc/windows_1253.$(OBJEXT): internal/attr/restrict.h
enc/windows_1253.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -10308,6 +10310,7 @@ enc/windows_1253.$(OBJEXT): internal/intern/enumerator.h
enc/windows_1253.$(OBJEXT): internal/intern/error.h
enc/windows_1253.$(OBJEXT): internal/intern/eval.h
enc/windows_1253.$(OBJEXT): internal/intern/file.h
+enc/windows_1253.$(OBJEXT): internal/intern/gc.h
enc/windows_1253.$(OBJEXT): internal/intern/hash.h
enc/windows_1253.$(OBJEXT): internal/intern/io.h
enc/windows_1253.$(OBJEXT): internal/intern/load.h
@@ -10338,12 +10341,12 @@ enc/windows_1253.$(OBJEXT): internal/memory.h
enc/windows_1253.$(OBJEXT): internal/method.h
enc/windows_1253.$(OBJEXT): internal/module.h
enc/windows_1253.$(OBJEXT): internal/newobj.h
+enc/windows_1253.$(OBJEXT): internal/rgengc.h
enc/windows_1253.$(OBJEXT): internal/scan_args.h
enc/windows_1253.$(OBJEXT): internal/special_consts.h
enc/windows_1253.$(OBJEXT): internal/static_assert.h
enc/windows_1253.$(OBJEXT): internal/stdalign.h
enc/windows_1253.$(OBJEXT): internal/stdbool.h
-enc/windows_1253.$(OBJEXT): internal/stdckdint.h
enc/windows_1253.$(OBJEXT): internal/symbol.h
enc/windows_1253.$(OBJEXT): internal/value.h
enc/windows_1253.$(OBJEXT): internal/value_type.h
@@ -10410,7 +10413,6 @@ enc/windows_1254.$(OBJEXT): internal/attr/noexcept.h
enc/windows_1254.$(OBJEXT): internal/attr/noinline.h
enc/windows_1254.$(OBJEXT): internal/attr/nonnull.h
enc/windows_1254.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_1254.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_1254.$(OBJEXT): internal/attr/pure.h
enc/windows_1254.$(OBJEXT): internal/attr/restrict.h
enc/windows_1254.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -10470,6 +10472,7 @@ enc/windows_1254.$(OBJEXT): internal/intern/enumerator.h
enc/windows_1254.$(OBJEXT): internal/intern/error.h
enc/windows_1254.$(OBJEXT): internal/intern/eval.h
enc/windows_1254.$(OBJEXT): internal/intern/file.h
+enc/windows_1254.$(OBJEXT): internal/intern/gc.h
enc/windows_1254.$(OBJEXT): internal/intern/hash.h
enc/windows_1254.$(OBJEXT): internal/intern/io.h
enc/windows_1254.$(OBJEXT): internal/intern/load.h
@@ -10500,12 +10503,12 @@ enc/windows_1254.$(OBJEXT): internal/memory.h
enc/windows_1254.$(OBJEXT): internal/method.h
enc/windows_1254.$(OBJEXT): internal/module.h
enc/windows_1254.$(OBJEXT): internal/newobj.h
+enc/windows_1254.$(OBJEXT): internal/rgengc.h
enc/windows_1254.$(OBJEXT): internal/scan_args.h
enc/windows_1254.$(OBJEXT): internal/special_consts.h
enc/windows_1254.$(OBJEXT): internal/static_assert.h
enc/windows_1254.$(OBJEXT): internal/stdalign.h
enc/windows_1254.$(OBJEXT): internal/stdbool.h
-enc/windows_1254.$(OBJEXT): internal/stdckdint.h
enc/windows_1254.$(OBJEXT): internal/symbol.h
enc/windows_1254.$(OBJEXT): internal/value.h
enc/windows_1254.$(OBJEXT): internal/value_type.h
@@ -10572,7 +10575,6 @@ enc/windows_1257.$(OBJEXT): internal/attr/noexcept.h
enc/windows_1257.$(OBJEXT): internal/attr/noinline.h
enc/windows_1257.$(OBJEXT): internal/attr/nonnull.h
enc/windows_1257.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_1257.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_1257.$(OBJEXT): internal/attr/pure.h
enc/windows_1257.$(OBJEXT): internal/attr/restrict.h
enc/windows_1257.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -10632,6 +10634,7 @@ enc/windows_1257.$(OBJEXT): internal/intern/enumerator.h
enc/windows_1257.$(OBJEXT): internal/intern/error.h
enc/windows_1257.$(OBJEXT): internal/intern/eval.h
enc/windows_1257.$(OBJEXT): internal/intern/file.h
+enc/windows_1257.$(OBJEXT): internal/intern/gc.h
enc/windows_1257.$(OBJEXT): internal/intern/hash.h
enc/windows_1257.$(OBJEXT): internal/intern/io.h
enc/windows_1257.$(OBJEXT): internal/intern/load.h
@@ -10662,12 +10665,12 @@ enc/windows_1257.$(OBJEXT): internal/memory.h
enc/windows_1257.$(OBJEXT): internal/method.h
enc/windows_1257.$(OBJEXT): internal/module.h
enc/windows_1257.$(OBJEXT): internal/newobj.h
+enc/windows_1257.$(OBJEXT): internal/rgengc.h
enc/windows_1257.$(OBJEXT): internal/scan_args.h
enc/windows_1257.$(OBJEXT): internal/special_consts.h
enc/windows_1257.$(OBJEXT): internal/static_assert.h
enc/windows_1257.$(OBJEXT): internal/stdalign.h
enc/windows_1257.$(OBJEXT): internal/stdbool.h
-enc/windows_1257.$(OBJEXT): internal/stdckdint.h
enc/windows_1257.$(OBJEXT): internal/symbol.h
enc/windows_1257.$(OBJEXT): internal/value.h
enc/windows_1257.$(OBJEXT): internal/value_type.h
@@ -10736,7 +10739,6 @@ enc/windows_31j.$(OBJEXT): internal/attr/noexcept.h
enc/windows_31j.$(OBJEXT): internal/attr/noinline.h
enc/windows_31j.$(OBJEXT): internal/attr/nonnull.h
enc/windows_31j.$(OBJEXT): internal/attr/noreturn.h
-enc/windows_31j.$(OBJEXT): internal/attr/packed_struct.h
enc/windows_31j.$(OBJEXT): internal/attr/pure.h
enc/windows_31j.$(OBJEXT): internal/attr/restrict.h
enc/windows_31j.$(OBJEXT): internal/attr/returns_nonnull.h
@@ -10796,6 +10798,7 @@ enc/windows_31j.$(OBJEXT): internal/intern/enumerator.h
enc/windows_31j.$(OBJEXT): internal/intern/error.h
enc/windows_31j.$(OBJEXT): internal/intern/eval.h
enc/windows_31j.$(OBJEXT): internal/intern/file.h
+enc/windows_31j.$(OBJEXT): internal/intern/gc.h
enc/windows_31j.$(OBJEXT): internal/intern/hash.h
enc/windows_31j.$(OBJEXT): internal/intern/io.h
enc/windows_31j.$(OBJEXT): internal/intern/load.h
@@ -10826,12 +10829,12 @@ enc/windows_31j.$(OBJEXT): internal/memory.h
enc/windows_31j.$(OBJEXT): internal/method.h
enc/windows_31j.$(OBJEXT): internal/module.h
enc/windows_31j.$(OBJEXT): internal/newobj.h
+enc/windows_31j.$(OBJEXT): internal/rgengc.h
enc/windows_31j.$(OBJEXT): internal/scan_args.h
enc/windows_31j.$(OBJEXT): internal/special_consts.h
enc/windows_31j.$(OBJEXT): internal/static_assert.h
enc/windows_31j.$(OBJEXT): internal/stdalign.h
enc/windows_31j.$(OBJEXT): internal/stdbool.h
-enc/windows_31j.$(OBJEXT): internal/stdckdint.h
enc/windows_31j.$(OBJEXT): internal/symbol.h
enc/windows_31j.$(OBJEXT): internal/value.h
enc/windows_31j.$(OBJEXT): internal/value_type.h
diff --git a/enc/ebcdic.h b/enc/ebcdic.h
index 5109bf7065..a3b380a327 100644
--- a/enc/ebcdic.h
+++ b/enc/ebcdic.h
@@ -7,5 +7,5 @@ ENC_ALIAS("ebcdic-cp-us", "IBM037");
* hopefully the most widely used one.
*
* See http://www.iana.org/assignments/character-sets/character-sets.xhtml
- * https://www.rfc-editor.org/rfc/rfc1345
+ * http://tools.ietf.org/html/rfc1345
*/
diff --git a/enc/encinit.c.erb b/enc/encinit.c.erb
index 3662ba200d..120408f8e3 100644
--- a/enc/encinit.c.erb
+++ b/enc/encinit.c.erb
@@ -1,6 +1,3 @@
-/* Automatically generated from <%= erb.filename %>
- * Do not edit<%# directly%>.
- */
/* Copyright 2012 Google Inc. Some Rights Reserved.
* Author: yugui@google.com (Yugui Sonoda)
*/
diff --git a/enc/jis/props.h.blt b/enc/jis/props.h.blt
index 865ae6b651..508a084449 100644
--- a/enc/jis/props.h.blt
+++ b/enc/jis/props.h.blt
@@ -1,5 +1,5 @@
/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf -L ANSI-C -k1,3 -7 -c -j1 -i1 -t -C -P -t --ignore-case -H onig_jis_property_hash -Q onig_jis_property_pool -N onig_jis_property enc/jis/props.kwd */
+/* Command-line: gperf -k1,3 -7 -c -j1 -i1 -t -C -P -t --ignore-case -H onig_jis_property_hash -Q onig_jis_property_pool -N onig_jis_property enc/jis/props.kwd */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@@ -28,6 +28,7 @@
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
#endif
+#define gperf_offsetof(s, n) (short)offsetof(struct s##_t, s##_str##n)
#line 1 "enc/jis/props.kwd"
/* -*- c -*- */
#define GPERF_DOWNCASE 1
@@ -81,7 +82,7 @@ struct enc_property;
#ifndef GPERF_DOWNCASE
#define GPERF_DOWNCASE 1
-static unsigned char gperf_downcase[256] =
+static const unsigned char gperf_downcase[256] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
@@ -179,19 +180,19 @@ onig_jis_property (register const char *str, register size_t len)
{
{-1}, {-1}, {-1}, {-1}, {-1},
#line 48 "enc/jis/props.kwd"
- {(int)(size_t)&((struct onig_jis_property_pool_t *)0)->onig_jis_property_pool_str5, onigenc_jis_han},
+ {gperf_offsetof(onig_jis_property_pool, 5), onigenc_jis_han},
{-1},
#line 49 "enc/jis/props.kwd"
- {(int)(size_t)&((struct onig_jis_property_pool_t *)0)->onig_jis_property_pool_str7, onigenc_jis_latin},
+ {gperf_offsetof(onig_jis_property_pool, 7), onigenc_jis_latin},
#line 50 "enc/jis/props.kwd"
- {(int)(size_t)&((struct onig_jis_property_pool_t *)0)->onig_jis_property_pool_str8, onigenc_jis_greek},
+ {gperf_offsetof(onig_jis_property_pool, 8), onigenc_jis_greek},
{-1},
#line 46 "enc/jis/props.kwd"
- {(int)(size_t)&((struct onig_jis_property_pool_t *)0)->onig_jis_property_pool_str10, onigenc_jis_hiragana},
+ {gperf_offsetof(onig_jis_property_pool, 10), onigenc_jis_hiragana},
#line 47 "enc/jis/props.kwd"
- {(int)(size_t)&((struct onig_jis_property_pool_t *)0)->onig_jis_property_pool_str11, onigenc_jis_katakana},
+ {gperf_offsetof(onig_jis_property_pool, 11), onigenc_jis_katakana},
#line 51 "enc/jis/props.kwd"
- {(int)(size_t)&((struct onig_jis_property_pool_t *)0)->onig_jis_property_pool_str12, onigenc_jis_cyrillic}
+ {gperf_offsetof(onig_jis_property_pool, 12), onigenc_jis_cyrillic}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/enc/make_encmake.rb b/enc/make_encmake.rb
index 96d1944bcb..fcfc2c9267 100755
--- a/enc/make_encmake.rb
+++ b/enc/make_encmake.rb
@@ -121,32 +121,39 @@ ENCS, ENC_DEPS = target_encodings
ATRANS, TRANS = target_transcoders
if File.exist?(depend = File.join($srcdir, "depend"))
- erb = ERB.new(File.read(depend), trim_mode: '%')
+ if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
+ erb = ERB.new(File.read(depend), trim_mode: '%')
+ else
+ erb = ERB.new(File.read(depend), nil, '%')
+ end
erb.filename = depend
tmp = erb.result(binding)
- dep = "\n#### depend ####\n\n" + depend_rules(tmp).join
+ dep = "\n#### depend ####\n\n" << depend_rules(tmp).join
else
dep = ""
end
mkin = File.read(File.join($srcdir, "Makefile.in"))
-# Variables that should not be expanded in Makefile.in to allow
-# overriding inherited variables at make-time.
-not_expand_vars = %w(CFLAGS)
-mkin.gsub!(/@(#{RbConfig::CONFIG.keys.join('|')})@/) do
- not_expand_vars.include?($1) ? CONFIG[$1] : RbConfig::CONFIG[$1]
-end
+mkin.gsub!(/@(#{CONFIG.keys.join('|')})@/) {CONFIG[$1]}
File.open(ARGV[0], 'wb') {|f|
f.puts mkin, dep
}
if MODULE_TYPE == :static
filename = "encinit.c.erb"
- erb = ERB.new(File.read(File.join($srcdir, filename)), trim_mode: '%-')
+ if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
+ erb = ERB.new(File.read(File.join($srcdir, filename)), trim_mode: '%-')
+ else
+ erb = ERB.new(File.read(File.join($srcdir, filename)), nil, '%-')
+ end
erb.filename = "enc/#{filename}"
tmp = erb.result(binding)
begin
Dir.mkdir 'enc'
rescue Errno::EEXIST
end
- require 'tool/lib/output'
- Output.new(path: "enc/encinit.c", ifchange: true).write(tmp)
+ File.open("enc/encinit.c", "w") {|f|
+ f.puts "/* Automatically generated from enc/encinit.c.erb"
+ f.puts " * Do not edit."
+ f.puts " */"
+ f.puts tmp
+ }
end
diff --git a/enc/trans/big5-uao-tbl.rb b/enc/trans/big5-uao-tbl.rb
index a6f37cc7bd..295fbfdda5 100644
--- a/enc/trans/big5-uao-tbl.rb
+++ b/enc/trans/big5-uao-tbl.rb
@@ -19781,4 +19781,4 @@ BIG5_UAO_TO_UCS_TBL = [
["FEFC",0x8262],
["FEFD",0x826A],
["FEFE",0x8288],
-]
+] \ No newline at end of file
diff --git a/enc/trans/cp850-tbl.rb b/enc/trans/cp850-tbl.rb
index e0d120c803..615d3b2599 100644
--- a/enc/trans/cp850-tbl.rb
+++ b/enc/trans/cp850-tbl.rb
@@ -127,4 +127,4 @@ CP850_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/cp852-tbl.rb b/enc/trans/cp852-tbl.rb
index ad32cdc59d..6763bfa6e9 100644
--- a/enc/trans/cp852-tbl.rb
+++ b/enc/trans/cp852-tbl.rb
@@ -127,4 +127,4 @@ CP852_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/cp855-tbl.rb b/enc/trans/cp855-tbl.rb
index a2ca9daf97..72e548b9cb 100644
--- a/enc/trans/cp855-tbl.rb
+++ b/enc/trans/cp855-tbl.rb
@@ -127,4 +127,4 @@ CP855_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/gbk-tbl.rb b/enc/trans/gbk-tbl.rb
index 40929f992e..26f5078c45 100644
--- a/enc/trans/gbk-tbl.rb
+++ b/enc/trans/gbk-tbl.rb
@@ -21791,4 +21791,4 @@ GBK_TO_UCS_TBL= [
["A3FE",0xFFE3],
["A957",0xFFE4],
["A3A4",0xFFE5],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm437-tbl.rb b/enc/trans/ibm437-tbl.rb
index 6a823c293d..5ae64d621e 100644
--- a/enc/trans/ibm437-tbl.rb
+++ b/enc/trans/ibm437-tbl.rb
@@ -127,4 +127,4 @@ IBM437_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm775-tbl.rb b/enc/trans/ibm775-tbl.rb
index 2b79780813..f55679f409 100644
--- a/enc/trans/ibm775-tbl.rb
+++ b/enc/trans/ibm775-tbl.rb
@@ -127,4 +127,4 @@ IBM775_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm852-tbl.rb b/enc/trans/ibm852-tbl.rb
index 3e70daef2e..6cec51cf80 100644
--- a/enc/trans/ibm852-tbl.rb
+++ b/enc/trans/ibm852-tbl.rb
@@ -127,4 +127,4 @@ IBM852_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm855-tbl.rb b/enc/trans/ibm855-tbl.rb
index b4c0244728..7e0cc5014f 100644
--- a/enc/trans/ibm855-tbl.rb
+++ b/enc/trans/ibm855-tbl.rb
@@ -127,4 +127,4 @@ IBM855_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm857-tbl.rb b/enc/trans/ibm857-tbl.rb
index c1c76545ed..5b20d389d3 100644
--- a/enc/trans/ibm857-tbl.rb
+++ b/enc/trans/ibm857-tbl.rb
@@ -124,4 +124,4 @@ IBM857_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm860-tbl.rb b/enc/trans/ibm860-tbl.rb
index 77734cd194..ae218a129f 100644
--- a/enc/trans/ibm860-tbl.rb
+++ b/enc/trans/ibm860-tbl.rb
@@ -127,4 +127,4 @@ IBM860_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm861-tbl.rb b/enc/trans/ibm861-tbl.rb
index 69e0a45019..c24042a76c 100644
--- a/enc/trans/ibm861-tbl.rb
+++ b/enc/trans/ibm861-tbl.rb
@@ -127,4 +127,4 @@ IBM861_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm862-tbl.rb b/enc/trans/ibm862-tbl.rb
index f564051fd6..31d6fb0243 100644
--- a/enc/trans/ibm862-tbl.rb
+++ b/enc/trans/ibm862-tbl.rb
@@ -127,4 +127,4 @@ IBM862_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm863-tbl.rb b/enc/trans/ibm863-tbl.rb
index af1eb97566..db110cf38c 100644
--- a/enc/trans/ibm863-tbl.rb
+++ b/enc/trans/ibm863-tbl.rb
@@ -127,4 +127,4 @@ IBM863_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm864-tbl.rb b/enc/trans/ibm864-tbl.rb
deleted file mode 100644
index 13f8a27f1d..0000000000
--- a/enc/trans/ibm864-tbl.rb
+++ /dev/null
@@ -1,126 +0,0 @@
-IBM864_TO_UCS_TBL = [
- ["80",0x00B0],
- ["81",0x00B7],
- ["82",0x2219],
- ["83",0x221A],
- ["84",0x2592],
- ["85",0x2500],
- ["86",0x2502],
- ["87",0x253C],
- ["88",0x2524],
- ["89",0x252C],
- ["8A",0x251C],
- ["8B",0x2534],
- ["8C",0x2510],
- ["8D",0x250C],
- ["8E",0x2514],
- ["8F",0x2518],
- ["90",0x03B2],
- ["91",0x221E],
- ["92",0x03C6],
- ["93",0x00B1],
- ["94",0x00BD],
- ["95",0x00BC],
- ["96",0x2248],
- ["97",0x00AB],
- ["98",0x00BB],
- ["99",0xFEF7],
- ["9A",0xFEF8],
- ["9D",0xFEFB],
- ["9E",0xFEFC],
- ["9F",0xFE73],
- ["A0",0x00A0],
- ["A1",0x00AD],
- ["A2",0xFE82],
- ["A3",0x00A3],
- ["A4",0x00A4],
- ["A5",0xFE84],
- ["A7",0x20AC], # Euro sign from CCSID 864
- ["A8",0xFE8E],
- ["A9",0xFE8F],
- ["AA",0xFE95],
- ["AB",0xFE99],
- ["AC",0x060C],
- ["AD",0xFE9D],
- ["AE",0xFEA1],
- ["AF",0xFEA5],
- ["B0",0x0660],
- ["B1",0x0661],
- ["B2",0x0662],
- ["B3",0x0663],
- ["B4",0x0664],
- ["B5",0x0665],
- ["B6",0x0666],
- ["B7",0x0667],
- ["B8",0x0668],
- ["B9",0x0669],
- ["BA",0xFED1],
- ["BB",0x061B],
- ["BC",0xFEB1],
- ["BD",0xFEB5],
- ["BE",0xFEB9],
- ["BF",0x061F],
- ["C0",0x00A2],
- ["C1",0xFE80],
- ["C2",0xFE81],
- ["C3",0xFE83],
- ["C4",0xFE85],
- ["C5",0xFECA],
- ["C6",0xFE8B],
- ["C7",0xFE8D],
- ["C8",0xFE91],
- ["C9",0xFE93],
- ["CA",0xFE97],
- ["CB",0xFE9B],
- ["CC",0xFE9F],
- ["CD",0xFEA3],
- ["CE",0xFEA7],
- ["CF",0xFEA9],
- ["D0",0xFEAB],
- ["D1",0xFEAD],
- ["D2",0xFEAF],
- ["D3",0xFEB3],
- ["D4",0xFEB7],
- ["D5",0xFEBB],
- ["D6",0xFEBF],
- ["D7",0xFEC1],
- ["D8",0xFEC5],
- ["D9",0xFECB],
- ["DA",0xFECF],
- ["DB",0x00A6],
- ["DC",0x00AC],
- ["DD",0x00F7],
- ["DE",0x00D7],
- ["DF",0xFEC9],
- ["E0",0x0640],
- ["E1",0xFED3],
- ["E2",0xFED7],
- ["E3",0xFEDB],
- ["E4",0xFEDF],
- ["E5",0xFEE3],
- ["E6",0xFEE7],
- ["E7",0xFEEB],
- ["E8",0xFEED],
- ["E9",0xFEEF],
- ["EA",0xFEF3],
- ["EB",0xFEBD],
- ["EC",0xFECC],
- ["ED",0xFECE],
- ["EE",0xFECD],
- ["EF",0xFEE1],
- ["F0",0xFE7D],
- ["F1",0x0651],
- ["F2",0xFEE5],
- ["F3",0xFEE9],
- ["F4",0xFEEC],
- ["F5",0xFEF0],
- ["F6",0xFEF2],
- ["F7",0xFED0],
- ["F8",0xFED5],
- ["F9",0xFEF5],
- ["FA",0xFEF6],
- ["FB",0xFEDD],
- ["FC",0xFED9],
- ["FD",0xFEF1],
- ["FE",0x25A0]
-]
diff --git a/enc/trans/ibm865-tbl.rb b/enc/trans/ibm865-tbl.rb
index 4747509d66..22e322fb31 100644
--- a/enc/trans/ibm865-tbl.rb
+++ b/enc/trans/ibm865-tbl.rb
@@ -127,4 +127,4 @@ IBM865_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm866-tbl.rb b/enc/trans/ibm866-tbl.rb
index ed4b0d683e..95b9ee7534 100644
--- a/enc/trans/ibm866-tbl.rb
+++ b/enc/trans/ibm866-tbl.rb
@@ -127,4 +127,4 @@ IBM866_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/ibm869-tbl.rb b/enc/trans/ibm869-tbl.rb
index bee85b84ea..437e41ad98 100644
--- a/enc/trans/ibm869-tbl.rb
+++ b/enc/trans/ibm869-tbl.rb
@@ -118,4 +118,4 @@ IBM869_TO_UCS_TBL = [
["B1",0x2592],
["B2",0x2593],
["FE",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/iso2022.trans b/enc/trans/iso2022.trans
index a25a4a12a1..a441f1596d 100644
--- a/enc/trans/iso2022.trans
+++ b/enc/trans/iso2022.trans
@@ -79,34 +79,6 @@ iso2022jp_init(void *statep)
return 0;
}
-static unsigned char *
-iso2022jp_put_state(unsigned char *sp, unsigned char *o, int oldstate, int newstate)
-{
- if (oldstate != newstate) {
- *o++ = 0x1b;
- switch (newstate) {
- case G0_ASCII:
- *o++ = '(';
- *o++ = 'B';
- break;
- case G0_JISX0201_KATAKANA:
- *o++ = '(';
- *o++ = 'I';
- break;
- case G0_JISX0208_1978:
- *o++ = '$';
- *o++ = '@';
- break;
- default:
- *o++ = '$';
- *o++ = 'B';
- break;
- }
- *sp = newstate;
- }
- return o;
-}
-
static VALUE
fun_si_iso2022jp_decoder(void *statep, const unsigned char *s, size_t l)
{
@@ -182,7 +154,24 @@ fun_so_iso2022jp_encoder(void *statep, const unsigned char *s, size_t l, unsigne
else
newstate = G0_JISX0208_1983;
- o = iso2022jp_put_state(sp, o, *sp, newstate);
+ if (*sp != newstate) {
+ if (newstate == G0_ASCII) {
+ *o++ = 0x1b;
+ *o++ = '(';
+ *o++ = 'B';
+ }
+ else if (newstate == G0_JISX0208_1978) {
+ *o++ = 0x1b;
+ *o++ = '$';
+ *o++ = '@';
+ }
+ else {
+ *o++ = 0x1b;
+ *o++ = '$';
+ *o++ = 'B';
+ }
+ *sp = newstate;
+ }
if (l == 1) {
*o++ = s[0] & 0x7f;
@@ -213,7 +202,10 @@ finish_iso2022jp_encoder(void *statep, unsigned char *o, size_t osize)
if (*sp == G0_ASCII)
return 0;
- o = iso2022jp_put_state(sp, o, *sp, G0_ASCII);
+ *o++ = 0x1b;
+ *o++ = '(';
+ *o++ = 'B';
+ *sp = G0_ASCII;
return o - output0;
}
@@ -407,7 +399,24 @@ fun_so_cp5022x_encoder(void *statep, const unsigned char *s, size_t l,
else
newstate = G0_JISX0208_1983;
- o = iso2022jp_put_state(sp, o, sp[0], newstate);
+ if (*sp != newstate) {
+ if (newstate == G0_ASCII) {
+ *o++ = 0x1b;
+ *o++ = '(';
+ *o++ = 'B';
+ }
+ else if (newstate == G0_JISX0201_KATAKANA) {
+ *o++ = 0x1b;
+ *o++ = '(';
+ *o++ = 'I';
+ }
+ else {
+ *o++ = 0x1b;
+ *o++ = '$';
+ *o++ = 'B';
+ }
+ *sp = newstate;
+ }
if (l == 1) {
*o++ = s[0] & 0x7f;
@@ -434,26 +443,15 @@ rb_cp50221_encoder = {
iso2022jp_encoder_reset_sequence_size, finish_iso2022jp_encoder
};
-/* JIS0201 to JIS0208 conversion table */
-enum {tbl0208_num = 0xDF - 0xA1 + 1};
-static const char tbl0208[tbl0208_num][2] = {
- "\x21\x23", "\x21\x56", "\x21\x57", "\x21\x22",
- "\x21\x26", "\x25\x72", "\x25\x21", "\x25\x23",
- "\x25\x25", "\x25\x27", "\x25\x29", "\x25\x63",
- "\x25\x65", "\x25\x67", "\x25\x43", "\x21\x3C",
- "\x25\x22", "\x25\x24", "\x25\x26", "\x25\x28",
- "\x25\x2A", "\x25\x2B", "\x25\x2D", "\x25\x2F",
- "\x25\x31", "\x25\x33", "\x25\x35", "\x25\x37",
- "\x25\x39", "\x25\x3B", "\x25\x3D", "\x25\x3F",
- "\x25\x41", "\x25\x44", "\x25\x46", "\x25\x48",
- "\x25\x4A", "\x25\x4B", "\x25\x4C", "\x25\x4D",
- "\x25\x4E", "\x25\x4F", "\x25\x52", "\x25\x55",
- "\x25\x58", "\x25\x5B", "\x25\x5E", "\x25\x5F",
- "\x25\x60", "\x25\x61", "\x25\x62", "\x25\x64",
- "\x25\x66", "\x25\x68", "\x25\x69", "\x25\x6A",
- "\x25\x6B", "\x25\x6C", "\x25\x6D", "\x25\x6F",
- "\x25\x73", "\x21\x2B", "\x21\x2C"
-};
+static const char *tbl0208 =
+ "\x21\x23\x21\x56\x21\x57\x21\x22\x21\x26\x25\x72\x25\x21\x25\x23" \
+ "\x25\x25\x25\x27\x25\x29\x25\x63\x25\x65\x25\x67\x25\x43\x21\x3C" \
+ "\x25\x22\x25\x24\x25\x26\x25\x28\x25\x2A\x25\x2B\x25\x2D\x25\x2F" \
+ "\x25\x31\x25\x33\x25\x35\x25\x37\x25\x39\x25\x3B\x25\x3D\x25\x3F" \
+ "\x25\x41\x25\x44\x25\x46\x25\x48\x25\x4A\x25\x4B\x25\x4C\x25\x4D" \
+ "\x25\x4E\x25\x4F\x25\x52\x25\x55\x25\x58\x25\x5B\x25\x5E\x25\x5F" \
+ "\x25\x60\x25\x61\x25\x62\x25\x64\x25\x66\x25\x68\x25\x69\x25\x6A" \
+ "\x25\x6B\x25\x6C\x25\x6D\x25\x6F\x25\x73\x21\x2B\x21\x2C";
static ssize_t
fun_so_cp50220_encoder(void *statep, const unsigned char *s, size_t l,
@@ -462,21 +460,22 @@ fun_so_cp50220_encoder(void *statep, const unsigned char *s, size_t l,
unsigned char *output0 = o;
unsigned char *sp = statep;
- if (sp[0] == G0_JISX0201_KATAKANA && sp[2]) {
+ if (sp[0] == G0_JISX0201_KATAKANA) {
int c = sp[2] & 0x7F;
- const char *p = tbl0208[c - 0x21];
- sp[2] = 0;
- o = iso2022jp_put_state(sp, o, sp[1], G0_JISX0208_1983);
+ const char *p = tbl0208 + (c - 0x21) * 2;
+ if (sp[1] != G0_JISX0208_1983) {
+ *o++ = 0x1b;
+ *o++ = '$';
+ *o++ = 'B';
+ }
sp[0] = G0_JISX0208_1983;
*o++ = *p++;
if (l == 2 && s[0] == 0x8E) {
if (s[1] == 0xDE) {
- /* VOICED SOUND MARK */
*o++ = *p + 1;
return o - output0;
}
else if (s[1] == 0xDF && (0x4A <= c && c <= 0x4E)) {
- /* SEMI-VOICED SOUND MARK */
*o++ = *p + 2;
return o - output0;
}
@@ -485,25 +484,21 @@ fun_so_cp50220_encoder(void *statep, const unsigned char *s, size_t l,
}
if (l == 2 && s[0] == 0x8E) {
+ const char *p = tbl0208 + (s[1] - 0xA1) * 2;
if ((0xA1 <= s[1] && s[1] <= 0xB5) ||
(0xC5 <= s[1] && s[1] <= 0xC9) ||
(0xCF <= s[1] && s[1] <= 0xDF)) {
- /* May not be followed by a sound mark */
- const char *p = tbl0208[s[1] - 0xA1];
- o = iso2022jp_put_state(sp, o, *sp, G0_JISX0208_1983);
+ if (*sp != G0_JISX0208_1983) {
+ *o++ = 0x1b;
+ *o++ = '$';
+ *o++ = 'B';
+ *sp = G0_JISX0208_1983;
+ }
*o++ = *p++;
*o++ = *p;
return o - output0;
}
- if (s[1] > 0xDF) { /* undef */
- o = iso2022jp_put_state(sp, o, *sp, G0_JISX0201_KATAKANA);
- *o++ = s[1] & 0x7F;
- sp[2] = 0;
- return o - output0;
- }
-
- /* Katakana that may be followed by a sound mark */
sp[2] = s[1];
sp[1] = sp[0];
sp[0] = G0_JISX0201_KATAKANA;
@@ -523,16 +518,23 @@ finish_cp50220_encoder(void *statep, unsigned char *o, size_t osize)
if (*sp == G0_ASCII)
return 0;
- if (sp[0] == G0_JISX0201_KATAKANA && sp[2]) {
+ if (sp[0] == G0_JISX0201_KATAKANA) {
int c = sp[2] & 0x7F;
- const char *p = tbl0208[c - 0x21];
- o = iso2022jp_put_state(sp, o, sp[1], G0_JISX0208_1983);
+ const char *p = tbl0208 + (c - 0x21) * 2;
+ if (sp[1] != G0_JISX0208_1983) {
+ *o++ = 0x1b;
+ *o++ = '$';
+ *o++ = 'B';
+ }
sp[0] = G0_JISX0208_1983;
*o++ = *p++;
*o++ = *p;
}
- o = iso2022jp_put_state(sp, o, sp[0], G0_ASCII);
+ *o++ = 0x1b;
+ *o++ = '(';
+ *o++ = 'B';
+ *sp = G0_ASCII;
return o - output0;
}
@@ -562,3 +564,4 @@ TRANS_INIT(iso2022)
rb_register_transcoder(&rb_cp50220_encoder);
rb_register_transcoder(&rb_cp50221_encoder);
}
+
diff --git a/enc/trans/koi8-r-tbl.rb b/enc/trans/koi8-r-tbl.rb
index 4cfe523334..a1f55ff2e3 100644
--- a/enc/trans/koi8-r-tbl.rb
+++ b/enc/trans/koi8-r-tbl.rb
@@ -127,4 +127,4 @@ KOI8_R_TO_UCS_TBL = [
["91",0x2592],
["92",0x2593],
["94",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/koi8-u-tbl.rb b/enc/trans/koi8-u-tbl.rb
index 225931ba5e..e87aa1aa3f 100644
--- a/enc/trans/koi8-u-tbl.rb
+++ b/enc/trans/koi8-u-tbl.rb
@@ -127,4 +127,4 @@ KOI8_U_TO_UCS_TBL = [
["91",0x2592],
["92",0x2593],
["94",0x25A0],
-]
+] \ No newline at end of file
diff --git a/enc/trans/maccroatian-tbl.rb b/enc/trans/maccroatian-tbl.rb
index e78f2f373f..359878ec1f 100644
--- a/enc/trans/maccroatian-tbl.rb
+++ b/enc/trans/maccroatian-tbl.rb
@@ -126,4 +126,4 @@ MACCROATIAN_TO_UCS_TBL = [
["B2",0x2264],
["B3",0x2265],
["D7",0x25CA],
-]
+] \ No newline at end of file
diff --git a/enc/trans/maccyrillic-tbl.rb b/enc/trans/maccyrillic-tbl.rb
index 2d5af7b466..378aa8c3bc 100644
--- a/enc/trans/maccyrillic-tbl.rb
+++ b/enc/trans/maccyrillic-tbl.rb
@@ -127,4 +127,4 @@ MACCYRILLIC_TO_UCS_TBL = [
["AD",0x2260],
["B2",0x2264],
["B3",0x2265],
-]
+] \ No newline at end of file
diff --git a/enc/trans/macgreek-tbl.rb b/enc/trans/macgreek-tbl.rb
index 645aefe5ff..7f75fde6d2 100644
--- a/enc/trans/macgreek-tbl.rb
+++ b/enc/trans/macgreek-tbl.rb
@@ -126,4 +126,4 @@ MACGREEK_TO_UCS_TBL = [
["AD",0x2260],
["B2",0x2264],
["B3",0x2265],
-]
+] \ No newline at end of file
diff --git a/enc/trans/maciceland-tbl.rb b/enc/trans/maciceland-tbl.rb
index ee9b5000d9..818d992274 100644
--- a/enc/trans/maciceland-tbl.rb
+++ b/enc/trans/maciceland-tbl.rb
@@ -126,4 +126,4 @@ MACICELAND_TO_UCS_TBL = [
["B2",0x2264],
["B3",0x2265],
["D7",0x25CA],
-]
+] \ No newline at end of file
diff --git a/enc/trans/macroman-tbl.rb b/enc/trans/macroman-tbl.rb
index 9a8172554a..8f74eea27f 100644
--- a/enc/trans/macroman-tbl.rb
+++ b/enc/trans/macroman-tbl.rb
@@ -126,4 +126,4 @@ MACROMAN_TO_UCS_TBL = [
["D7",0x25CA],
["DE",0xFB01],
["DF",0xFB02],
-]
+] \ No newline at end of file
diff --git a/enc/trans/macromania-tbl.rb b/enc/trans/macromania-tbl.rb
index 29a7942d9b..ff95c5e957 100644
--- a/enc/trans/macromania-tbl.rb
+++ b/enc/trans/macromania-tbl.rb
@@ -126,4 +126,4 @@ MACROMANIA_TO_UCS_TBL = [
["B2",0x2264],
["B3",0x2265],
["D7",0x25CA],
-]
+] \ No newline at end of file
diff --git a/enc/trans/macturkish-tbl.rb b/enc/trans/macturkish-tbl.rb
index 883f693e23..2358672ed6 100644
--- a/enc/trans/macturkish-tbl.rb
+++ b/enc/trans/macturkish-tbl.rb
@@ -125,4 +125,4 @@ MACTURKISH_TO_UCS_TBL = [
["B2",0x2264],
["B3",0x2265],
["D7",0x25CA],
-]
+] \ No newline at end of file
diff --git a/enc/trans/macukraine-tbl.rb b/enc/trans/macukraine-tbl.rb
index 09acf7c45a..6941af654d 100644
--- a/enc/trans/macukraine-tbl.rb
+++ b/enc/trans/macukraine-tbl.rb
@@ -127,4 +127,4 @@ MACUKRAINE_TO_UCS_TBL = [
["AD",0x2260],
["B2",0x2264],
["B3",0x2265],
-]
+] \ No newline at end of file
diff --git a/enc/trans/single_byte.trans b/enc/trans/single_byte.trans
index c326cbebea..0d5407b918 100644
--- a/enc/trans/single_byte.trans
+++ b/enc/trans/single_byte.trans
@@ -61,7 +61,6 @@
transcode_tblgen_singlebyte "IBM861"
transcode_tblgen_singlebyte "IBM862"
transcode_tblgen_singlebyte "IBM863"
- transcode_tblgen_singlebyte "IBM864"
transcode_tblgen_singlebyte "IBM865"
transcode_tblgen_singlebyte "IBM866"
transcode_tblgen_singlebyte "IBM869"
diff --git a/enc/trans/windows-1250-tbl.rb b/enc/trans/windows-1250-tbl.rb
index 9cdb432a03..52063e17b1 100644
--- a/enc/trans/windows-1250-tbl.rb
+++ b/enc/trans/windows-1250-tbl.rb
@@ -122,4 +122,4 @@ WINDOWS_1250_TO_UCS_TBL = [
["9B",0x203A],
["80",0x20AC],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-1251-tbl.rb b/enc/trans/windows-1251-tbl.rb
index 3c6c4ca0bb..870c718b72 100644
--- a/enc/trans/windows-1251-tbl.rb
+++ b/enc/trans/windows-1251-tbl.rb
@@ -126,4 +126,4 @@ WINDOWS_1251_TO_UCS_TBL = [
["88",0x20AC],
["B9",0x2116],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-1252-tbl.rb b/enc/trans/windows-1252-tbl.rb
index 86a7be41e7..cefc72dff2 100644
--- a/enc/trans/windows-1252-tbl.rb
+++ b/enc/trans/windows-1252-tbl.rb
@@ -122,4 +122,4 @@ WINDOWS_1252_TO_UCS_TBL = [
["9B",0x203A],
["80",0x20AC],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-1253-tbl.rb b/enc/trans/windows-1253-tbl.rb
index b9d47be2e0..132edb60ba 100644
--- a/enc/trans/windows-1253-tbl.rb
+++ b/enc/trans/windows-1253-tbl.rb
@@ -110,4 +110,4 @@ WINDOWS_1253_TO_UCS_TBL = [
["9B",0x203A],
["80",0x20AC],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-1254-tbl.rb b/enc/trans/windows-1254-tbl.rb
index 84063abf05..81a747afaa 100644
--- a/enc/trans/windows-1254-tbl.rb
+++ b/enc/trans/windows-1254-tbl.rb
@@ -120,4 +120,4 @@ WINDOWS_1254_TO_UCS_TBL = [
["9B",0x203A],
["80",0x20AC],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-1256-tbl.rb b/enc/trans/windows-1256-tbl.rb
index 0b76c824d1..25c5874fb0 100644
--- a/enc/trans/windows-1256-tbl.rb
+++ b/enc/trans/windows-1256-tbl.rb
@@ -127,4 +127,4 @@ WINDOWS_1256_TO_UCS_TBL = [
["9B",0x203A],
["80",0x20AC],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-1257-tbl.rb b/enc/trans/windows-1257-tbl.rb
index 7f15cbbd50..9e89b2b0b5 100644
--- a/enc/trans/windows-1257-tbl.rb
+++ b/enc/trans/windows-1257-tbl.rb
@@ -115,4 +115,4 @@ WINDOWS_1257_TO_UCS_TBL = [
["9B",0x203A],
["80",0x20AC],
["99",0x2122],
-]
+] \ No newline at end of file
diff --git a/enc/trans/windows-874-tbl.rb b/enc/trans/windows-874-tbl.rb
index a569765bf0..0552df3d28 100644
--- a/enc/trans/windows-874-tbl.rb
+++ b/enc/trans/windows-874-tbl.rb
@@ -96,4 +96,4 @@ WINDOWS_874_TO_UCS_TBL = [
["95",0x2022],
["85",0x2026],
["80",0x20AC],
-]
+] \ No newline at end of file
diff --git a/enc/unicode/15.0.0/name2ctype.h b/enc/unicode/15.0.0/name2ctype.h
index 6bbbb3512f..a2c996423d 100644
--- a/enc/unicode/15.0.0/name2ctype.h
+++ b/enc/unicode/15.0.0/name2ctype.h
@@ -5402,7 +5402,7 @@ static const OnigCodePoint CR_ASCII[] = {
0x0000, 0x007f,
}; /* CR_ASCII */
-/* 'Punct': [[:Punct:]] */
+/* 'Punct' */
static const OnigCodePoint CR_Punct[] = {
191,
0x0021, 0x0023,
diff --git a/encoding.c b/encoding.c
index d4fe6ea124..2f4b47bdfa 100644
--- a/encoding.c
+++ b/encoding.c
@@ -71,24 +71,6 @@ static struct enc_table {
st_table *names;
} global_enc_table;
-static int
-enc_names_free_i(st_data_t name, st_data_t idx, st_data_t args)
-{
- ruby_xfree((void *)name);
- return ST_DELETE;
-}
-
-void
-rb_free_global_enc_table(void)
-{
- for (size_t i = 0; i < ENCODING_LIST_CAPA; i++) {
- xfree((void *)global_enc_table.list[i].enc);
- }
-
- st_foreach(global_enc_table.names, enc_names_free_i, (st_data_t)0);
- st_free_table(global_enc_table.names);
-}
-
static rb_encoding *global_enc_ascii,
*global_enc_utf_8,
*global_enc_us_ascii;
@@ -120,7 +102,7 @@ static rb_encoding *global_enc_ascii,
static const rb_data_type_t encoding_data_type = {
"encoding",
{0, 0, 0,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
#define is_data_encoding(obj) (RTYPEDDATA_P(obj) && RTYPEDDATA_TYPE(obj) == &encoding_data_type)
@@ -523,6 +505,37 @@ enc_replicate(struct enc_table *enc_table, const char *name, rb_encoding *encodi
return idx;
}
+int
+rb_enc_replicate(const char *name, rb_encoding *encoding)
+{
+ int r;
+
+ GLOBAL_ENC_TABLE_EVAL(enc_table,
+ r = enc_replicate(enc_table, name, encoding));
+
+ return r;
+}
+
+/*
+ * call-seq:
+ * enc.replicate(name) -> encoding
+ *
+ * Returns a replicated encoding of _enc_ whose name is _name_.
+ * The new encoding should have the same byte structure of _enc_.
+ * If _name_ is used by another encoding, raise ArgumentError.
+ *
+ */
+static VALUE
+enc_replicate_m(VALUE encoding, VALUE name)
+{
+ int idx;
+ rb_warn_deprecated_to_remove("3.3", "Encoding#replicate", "the original encoding");
+
+ idx = rb_enc_replicate(name_for_encoding(&name), rb_to_encoding(encoding));
+ RB_GC_GUARD(name);
+ return rb_enc_from_encoding_index(idx);
+}
+
static int
enc_replicate_with_index(struct enc_table *enc_table, const char *name, rb_encoding *origenc, int idx)
{
@@ -1015,22 +1028,13 @@ rb_enc_get(VALUE obj)
return rb_enc_from_index(rb_enc_get_index(obj));
}
-const char *
-rb_enc_inspect_name(rb_encoding *enc)
-{
- if (enc == global_enc_ascii) {
- return "BINARY (ASCII-8BIT)";
- }
- return enc->name;
-}
-
static rb_encoding*
rb_encoding_check(rb_encoding* enc, VALUE str1, VALUE str2)
{
if (!enc)
rb_raise(rb_eEncCompatError, "incompatible character encodings: %s and %s",
- rb_enc_inspect_name(rb_enc_get(str1)),
- rb_enc_inspect_name(rb_enc_get(str2)));
+ rb_enc_name(rb_enc_get(str1)),
+ rb_enc_name(rb_enc_get(str2)));
return enc;
}
@@ -1053,13 +1057,6 @@ rb_enc_check(VALUE str1, VALUE str2)
static rb_encoding*
enc_compatible_latter(VALUE str1, VALUE str2, int idx1, int idx2)
{
- if (idx1 < 0 || idx2 < 0)
- return 0;
-
- if (idx1 == idx2) {
- return rb_enc_from_index(idx1);
- }
-
int isstr1, isstr2;
rb_encoding *enc1 = rb_enc_from_index(idx1);
rb_encoding *enc2 = rb_enc_from_index(idx2);
@@ -1118,7 +1115,15 @@ enc_compatible_str(VALUE str1, VALUE str2)
int idx1 = enc_get_index_str(str1);
int idx2 = enc_get_index_str(str2);
- return enc_compatible_latter(str1, str2, idx1, idx2);
+ if (idx1 < 0 || idx2 < 0)
+ return 0;
+
+ if (idx1 == idx2) {
+ return rb_enc_from_index(idx1);
+ }
+ else {
+ return enc_compatible_latter(str1, str2, idx1, idx2);
+ }
}
rb_encoding*
@@ -1127,6 +1132,13 @@ rb_enc_compatible(VALUE str1, VALUE str2)
int idx1 = rb_enc_get_index(str1);
int idx2 = rb_enc_get_index(str2);
+ if (idx1 < 0 || idx2 < 0)
+ return 0;
+
+ if (idx1 == idx2) {
+ return rb_enc_from_index(idx1);
+ }
+
return enc_compatible_latter(str1, str2, idx1, idx2);
}
@@ -1264,10 +1276,9 @@ enc_inspect(VALUE self)
if (!(enc = DATA_PTR(self)) || rb_enc_from_index(rb_enc_to_index(enc)) != enc) {
rb_raise(rb_eTypeError, "broken Encoding");
}
-
return rb_enc_sprintf(rb_usascii_encoding(),
"#<%"PRIsVALUE":%s%s%s>", rb_obj_class(self),
- rb_enc_inspect_name(enc),
+ rb_enc_name(enc),
(ENC_DUMMY_P(enc) ? " (dummy)" : ""),
rb_enc_autoload_p(enc) ? " (autoload)" : "");
}
@@ -1293,7 +1304,7 @@ enc_names_i(st_data_t name, st_data_t idx, st_data_t args)
VALUE *arg = (VALUE *)args;
if ((int)idx == (int)arg[0]) {
- VALUE str = rb_interned_str_cstr((char *)name);
+ VALUE str = rb_fstring_cstr((char *)name);
rb_ary_push(arg[1], str);
}
return ST_CONTINUE;
@@ -1790,7 +1801,7 @@ static int
rb_enc_name_list_i(st_data_t name, st_data_t idx, st_data_t arg)
{
VALUE ary = (VALUE)arg;
- VALUE str = rb_interned_str_cstr((char *)name);
+ VALUE str = rb_fstring_cstr((char *)name);
rb_ary_push(ary, str);
return ST_CONTINUE;
}
@@ -1835,7 +1846,7 @@ rb_enc_aliases_enc_i(st_data_t name, st_data_t orig, st_data_t arg)
str = rb_fstring_cstr(rb_enc_name(enc));
rb_ary_store(ary, idx, str);
}
- key = rb_interned_str_cstr((char *)name);
+ key = rb_fstring_cstr((char *)name);
rb_hash_aset(aliases, key, str);
return ST_CONTINUE;
}
@@ -1910,6 +1921,7 @@ Init_Encoding(void)
rb_define_method(rb_cEncoding, "names", enc_names, 0);
rb_define_method(rb_cEncoding, "dummy?", enc_dummy_p, 0);
rb_define_method(rb_cEncoding, "ascii_compatible?", enc_ascii_compatible_p, 0);
+ rb_define_method(rb_cEncoding, "replicate", enc_replicate_m, 1);
rb_define_singleton_method(rb_cEncoding, "list", enc_list, 0);
rb_define_singleton_method(rb_cEncoding, "name_list", rb_enc_name_list, 0);
rb_define_singleton_method(rb_cEncoding, "aliases", rb_enc_aliases, 0);
@@ -1929,7 +1941,7 @@ Init_Encoding(void)
list = rb_encoding_list = rb_ary_new2(ENCODING_LIST_CAPA);
RBASIC_CLEAR_CLASS(list);
- rb_vm_register_global_object(list);
+ rb_gc_register_mark_object(list);
for (i = 0; i < enc_table->count; ++i) {
rb_ary_push(list, enc_new(enc_table->list[i].enc));
diff --git a/enum.c b/enum.c
index 495b01dfa0..b3c715e0a1 100644
--- a/enum.c
+++ b/enum.c
@@ -322,32 +322,16 @@ enum_count(int argc, VALUE *argv, VALUE obj)
return imemo_count_value(memo);
}
-NORETURN(static void found(VALUE i, VALUE memop));
-static void
-found(VALUE i, VALUE memop) {
- struct MEMO *memo = MEMO_CAST(memop);
- MEMO_V1_SET(memo, i);
- memo->u3.cnt = 1;
- rb_iter_break();
-}
-
-static VALUE
-find_i_fast(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
-{
- if (RTEST(rb_yield_values2(argc, argv))) {
- ENUM_WANT_SVALUE();
- found(i, memop);
- }
- return Qnil;
-}
-
static VALUE
find_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
{
ENUM_WANT_SVALUE();
if (RTEST(enum_yield(argc, i))) {
- found(i, memop);
+ struct MEMO *memo = MEMO_CAST(memop);
+ MEMO_V1_SET(memo, i);
+ memo->u3.cnt = 1;
+ rb_iter_break();
}
return Qnil;
}
@@ -370,7 +354,7 @@ find_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
* {foo: 0, bar: 1, baz: 2}.find {|key, value| key.start_with?('b') } # => [:bar, 1]
* {foo: 0, bar: 1, baz: 2}.find(proc {[]}) {|key, value| key.start_with?('c') } # => []
*
- * With no block given, returns an Enumerator.
+ * With no block given, returns an \Enumerator.
*
*/
static VALUE
@@ -382,10 +366,7 @@ enum_find(int argc, VALUE *argv, VALUE obj)
if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
RETURN_ENUMERATOR(obj, argc, argv);
memo = MEMO_NEW(Qundef, 0, 0);
- if (rb_block_pair_yield_optimizable())
- rb_block_call2(obj, id_each, 0, 0, find_i_fast, (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
- else
- rb_block_call2(obj, id_each, 0, 0, find_i, (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
+ rb_block_call(obj, id_each, 0, 0, find_i, (VALUE)memo);
if (memo->u3.cnt) {
return memo->v1;
}
@@ -443,7 +424,7 @@ find_index_iter_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, memop))
* ['a', 'b', 'c', 'b'].find_index {|element| element.start_with?('b') } # => 1
* {foo: 0, bar: 1, baz: 2}.find_index {|key, value| value > 1 } # => 2
*
- * With no argument and no block given, returns an Enumerator.
+ * With no argument and no block given, returns an \Enumerator.
*
*/
@@ -520,7 +501,7 @@ enum_size_over_p(VALUE obj, long n)
* a = {foo: 0, bar: 1, baz: 2}.select {|key, value| key.start_with?('b') }
* a # => {:bar=>1, :baz=>2}
*
- * With no block given, returns an Enumerator.
+ * With no block given, returns an \Enumerator.
*
* Related: #reject.
*/
@@ -562,7 +543,7 @@ filter_map_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
* (0..9).filter_map {|i| i * 2 if i.even? } # => [0, 4, 8, 12, 16]
* {foo: 0, bar: 1, baz: 2}.filter_map {|key, value| key if value.even? } # => [:foo, :baz]
*
- * When no block given, returns an Enumerator.
+ * When no block given, returns an \Enumerator.
*
*/
static VALUE
@@ -603,7 +584,7 @@ reject_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
* (0..9).reject {|i| i * 2 if i.even? } # => [1, 3, 5, 7, 9]
* {foo: 0, bar: 1, baz: 2}.reject {|key, value| key if value.odd? } # => {:foo=>0, :baz=>2}
*
- * When no block given, returns an Enumerator.
+ * When no block given, returns an \Enumerator.
*
* Related: #select.
*/
@@ -650,7 +631,7 @@ collect_all(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
* (0..4).map {|i| i*i } # => [0, 1, 4, 9, 16]
* {foo: 0, bar: 1, baz: 2}.map {|key, value| value*2} # => [0, 2, 4]
*
- * With no block given, returns an Enumerator.
+ * With no block given, returns an \Enumerator.
*
*/
static VALUE
@@ -700,7 +681,7 @@ flat_map_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
* [[0, 1], [2, 3]].flat_map {|e| e + [100] } # => [0, 1, 100, 2, 3, 100]
* {foo: 0, bar: 1, baz: 2}.flat_map {|key, value| [key, value] } # => [:foo, 0, :bar, 1, :baz, 2]
*
- * With no block given, returns an Enumerator.
+ * With no block given, returns an \Enumerator.
*
* Alias: #collect_concat.
*/
@@ -719,12 +700,13 @@ enum_flat_map(VALUE obj)
/*
* call-seq:
- * to_a(*args) -> array
+ * to_a -> array
*
* Returns an array containing the items in +self+:
*
* (0..4).to_a # => [0, 1, 2, 3, 4]
*
+ * Enumerable#entries is an alias for Enumerable#to_a.
*/
static VALUE
enum_to_a(int argc, VALUE *argv, VALUE obj)
@@ -764,8 +746,8 @@ enum_to_h_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
/*
* call-seq:
- * to_h(*args) -> hash
- * to_h(*args) {|element| ... } -> hash
+ * to_h -> hash
+ * to_h {|element| ... } -> hash
*
* When +self+ consists of 2-element arrays,
* returns a hash each of whose entries is the key-value pair
@@ -889,152 +871,136 @@ ary_inject_op(VALUE ary, VALUE init, VALUE op)
/*
* call-seq:
- * inject(symbol) -> object
- * inject(initial_value, symbol) -> object
- * inject {|memo, value| ... } -> object
- * inject(initial_value) {|memo, value| ... } -> object
+ * inject(symbol) -> object
+ * inject(initial_operand, symbol) -> object
+ * inject {|memo, operand| ... } -> object
+ * inject(initial_operand) {|memo, operand| ... } -> object
+ *
+ * Returns an object formed from operands via either:
*
- * Returns the result of applying a reducer to an initial value and
- * the first element of the Enumerable. It then takes the result and applies the
- * function to it and the second element of the collection, and so on. The
- * return value is the result returned by the final call to the function.
+ * - A method named by +symbol+.
+ * - A block to which each operand is passed.
+ *
+ * With method-name argument +symbol+,
+ * combines operands using the method:
+ *
+ * # Sum, without initial_operand.
+ * (1..4).inject(:+) # => 10
+ * # Sum, with initial_operand.
+ * (1..4).inject(10, :+) # => 20
*
- * You can think of
+ * With a block, passes each operand to the block:
+ *
+ * # Sum of squares, without initial_operand.
+ * (1..4).inject {|sum, n| sum + n*n } # => 30
+ * # Sum of squares, with initial_operand.
+ * (1..4).inject(2) {|sum, n| sum + n*n } # => 32
*
- * [ a, b, c, d ].inject(i) { |r, v| fn(r, v) }
+ * <b>Operands</b>
*
- * as being
- *
- * fn(fn(fn(fn(i, a), b), c), d)
- *
- * In a way the +inject+ function _injects_ the function
- * between the elements of the enumerable.
- *
- * +inject+ is aliased as +reduce+. You use it when you want to
- * _reduce_ a collection to a single value.
- *
- * <b>The Calling Sequences</b>
- *
- * Let's start with the most verbose:
- *
- * enum.inject(initial_value) do |result, next_value|
- * # do something with +result+ and +next_value+
- * # the value returned by the block becomes the
- * # value passed in to the next iteration
- * # as +result+
- * end
- *
- * For example:
- *
- * product = [ 2, 3, 4 ].inject(1) do |result, next_value|
- * result * next_value
- * end
- * product #=> 24
- *
- * When this runs, the block is first called with +1+ (the initial value) and
- * +2+ (the first element of the array). The block returns <tt>1*2</tt>, so on
- * the next iteration the block is called with +2+ (the previous result) and
- * +3+. The block returns +6+, and is called one last time with +6+ and +4+.
- * The result of the block, +24+ becomes the value returned by +inject+. This
- * code returns the product of the elements in the enumerable.
- *
- * <b>First Shortcut: Default Initial value</b>
- *
- * In the case of the previous example, the initial value, +1+, wasn't really
- * necessary: the calculation of the product of a list of numbers is self-contained.
- *
- * In these circumstances, you can omit the +initial_value+ parameter. +inject+
- * will then initially call the block with the first element of the collection
- * as the +result+ parameter and the second element as the +next_value+.
- *
- * [ 2, 3, 4 ].inject do |result, next_value|
- * result * next_value
- * end
+ * If argument +initial_operand+ is not given,
+ * the operands for +inject+ are simply the elements of +self+.
+ * Example calls and their operands:
*
- * This shortcut is convenient, but can only be used when the block produces a result
- * which can be passed back to it as a first parameter.
+ * - <tt>(1..4).inject(:+)</tt>:: <tt>[1, 2, 3, 4]</tt>.
+ * - <tt>(1...4).inject(:+)</tt>:: <tt>[1, 2, 3]</tt>.
+ * - <tt>('a'..'d').inject(:+)</tt>:: <tt>['a', 'b', 'c', 'd']</tt>.
+ * - <tt>('a'...'d').inject(:+)</tt>:: <tt>['a', 'b', 'c']</tt>.
*
- * Here's an example where that's not the case: it returns a hash where the keys are words
- * and the values are the number of occurrences of that word in the enumerable.
+ * Examples with first operand (which is <tt>self.first</tt>) of various types:
*
- * freqs = File.read("README.md")
- * .scan(/\w{2,}/)
- * .reduce(Hash.new(0)) do |counts, word|
- * counts[word] += 1
- * counts
- * end
- * freqs #=> {"Actions"=>4,
- * "Status"=>5,
- * "MinGW"=>3,
- * "https"=>27,
- * "github"=>10,
- * "com"=>15, ...
+ * # Integer.
+ * (1..4).inject(:+) # => 10
+ * # Float.
+ * [1.0, 2, 3, 4].inject(:+) # => 10.0
+ * # Character.
+ * ('a'..'d').inject(:+) # => "abcd"
+ * # Complex.
+ * [Complex(1, 2), 3, 4].inject(:+) # => (8+2i)
*
- * Note that the last line of the block is just the word +counts+. This ensures the
- * return value of the block is the result that's being calculated.
+ * If argument +initial_operand+ is given,
+ * the operands for +inject+ are that value plus the elements of +self+.
+ * Example calls their operands:
*
- * <b>Second Shortcut: a Reducer function</b>
+ * - <tt>(1..4).inject(10, :+)</tt>:: <tt>[10, 1, 2, 3, 4]</tt>.
+ * - <tt>(1...4).inject(10, :+)</tt>:: <tt>[10, 1, 2, 3]</tt>.
+ * - <tt>('a'..'d').inject('e', :+)</tt>:: <tt>['e', 'a', 'b', 'c', 'd']</tt>.
+ * - <tt>('a'...'d').inject('e', :+)</tt>:: <tt>['e', 'a', 'b', 'c']</tt>.
*
- * A <i>reducer function</i> is a function that takes a partial result and the next value,
- * returning the next partial result. The block that is given to +inject+ is a reducer.
+ * Examples with +initial_operand+ of various types:
*
- * You can also write a reducer as a function and pass the name of that function
- * (as a symbol) to +inject+. However, for this to work, the function
+ * # Integer.
+ * (1..4).inject(2, :+) # => 12
+ * # Float.
+ * (1..4).inject(2.0, :+) # => 12.0
+ * # String.
+ * ('a'..'d').inject('foo', :+) # => "fooabcd"
+ * # Array.
+ * %w[a b c].inject(['x'], :push) # => ["x", "a", "b", "c"]
+ * # Complex.
+ * (1..4).inject(Complex(2, 2), :+) # => (12+2i)
*
- * 1. Must be defined on the type of the result value
- * 2. Must accept a single parameter, the next value in the collection, and
- * 3. Must return an updated result which will also implement the function.
+ * <b>Combination by Given \Method</b>
*
- * Here's an example that adds elements to a string. The two calls invoke the functions
- * String#concat and String#+ on the result so far, passing it the next value.
+ * If the method-name argument +symbol+ is given,
+ * the operands are combined by that method:
*
- * s = [ "cat", " ", "dog" ].inject("", :concat)
- * s #=> "cat dog"
- * s = [ "cat", " ", "dog" ].inject("The result is:", :+)
- * s #=> "The result is: cat dog"
+ * - The first and second operands are combined.
+ * - That result is combined with the third operand.
+ * - That result is combined with the fourth operand.
+ * - And so on.
*
- * Here's a more complex example when the result object maintains
- * state of a different type to the enumerable elements.
+ * The return value from +inject+ is the result of the last combination.
*
- * class Turtle
+ * This call to +inject+ computes the sum of the operands:
*
- * def initialize
- * @x = @y = 0
- * end
+ * (1..4).inject(:+) # => 10
*
- * def move(dir)
- * case dir
- * when "n" then @y += 1
- * when "s" then @y -= 1
- * when "e" then @x += 1
- * when "w" then @x -= 1
- * end
- * self
- * end
- * end
+ * Examples with various methods:
*
- * position = "nnneesw".chars.reduce(Turtle.new, :move)
- * position #=>> #<Turtle:0x00000001052f4698 @y=2, @x=1>
+ * # Integer addition.
+ * (1..4).inject(:+) # => 10
+ * # Integer multiplication.
+ * (1..4).inject(:*) # => 24
+ * # Character range concatenation.
+ * ('a'..'d').inject('', :+) # => "abcd"
+ * # String array concatenation.
+ * %w[foo bar baz].inject('', :+) # => "foobarbaz"
+ * # Hash update.
+ * h = [{foo: 0, bar: 1}, {baz: 2}, {bat: 3}].inject(:update)
+ * h # => {:foo=>0, :bar=>1, :baz=>2, :bat=>3}
+ * # Hash conversion to nested arrays.
+ * h = {foo: 0, bar: 1}.inject([], :push)
+ * h # => [[:foo, 0], [:bar, 1]]
*
- * <b>Third Shortcut: Reducer With no Initial Value</b>
+ * <b>Combination by Given Block</b>
*
- * If your reducer returns a value that it can accept as a parameter, then you
- * don't have to pass in an initial value. Here <tt>:*</tt> is the name of the
- * _times_ function:
+ * If a block is given, the operands are passed to the block:
*
- * product = [ 2, 3, 4 ].inject(:*)
- * product # => 24
+ * - The first call passes the first and second operands.
+ * - The second call passes the result of the first call,
+ * along with the third operand.
+ * - The third call passes the result of the second call,
+ * along with the fourth operand.
+ * - And so on.
*
- * String concatenation again:
+ * The return value from +inject+ is the return value from the last block call.
+ *
+ * This call to +inject+ gives a block
+ * that writes the memo and element, and also sums the elements:
*
- * s = [ "cat", " ", "dog" ].inject(:+)
- * s #=> "cat dog"
+ * (1..4).inject do |memo, element|
+ * p "Memo: #{memo}; element: #{element}"
+ * memo + element
+ * end # => 10
*
- * And an example that converts a hash to an array of two-element subarrays.
+ * Output:
*
- * nested = {foo: 0, bar: 1}.inject([], :push)
- * nested # => [[:foo, 0], [:bar, 1]]
+ * "Memo: 1; element: 2"
+ * "Memo: 3; element: 3"
+ * "Memo: 6; element: 4"
*
+ * Enumerable#reduce is an alias for Enumerable#inject.
*
*/
static VALUE
@@ -1235,47 +1201,29 @@ tally_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
/*
* call-seq:
- * tally(hash = {}) -> hash
- *
- * When argument +hash+ is not given,
- * returns a new hash whose keys are the distinct elements in +self+;
- * each integer value is the count of occurrences of each element:
- *
- * %w[a b c b c a c b].tally # => {"a"=>2, "b"=>3, "c"=>3}
- *
- * When argument +hash+ is given,
- * returns +hash+, possibly augmented; for each element +ele+ in +self+:
+ * tally -> new_hash
+ * tally(hash) -> hash
*
- * - Adds it as a key with a zero value if that key does not already exist:
+ * Returns a hash containing the counts of equal elements:
*
- * hash[ele] = 0 unless hash.include?(ele)
+ * - Each key is an element of +self+.
+ * - Each value is the number elements equal to that key.
*
- * - Increments the value of key +ele+:
+ * With no argument:
*
- * hash[ele] += 1
- *
- * This is useful for accumulating tallies across multiple enumerables:
- *
- * h = {} # => {}
- * %w[a c d b c a].tally(h) # => {"a"=>2, "c"=>2, "d"=>1, "b"=>1}
- * %w[b a z].tally(h) # => {"a"=>3, "c"=>2, "d"=>1, "b"=>2, "z"=>1}
- * %w[b a m].tally(h) # => {"a"=>4, "c"=>2, "d"=>1, "b"=>3, "z"=>1, "m"=>1}
- *
- * The key to be added or found for an element depends on the class of +self+;
- * see {Enumerable in Ruby Classes}[rdoc-ref:Enumerable@Enumerable+in+Ruby+Classes].
- *
- * Examples:
+ * %w[a b c b c a c b].tally # => {"a"=>2, "b"=>3, "c"=>3}
*
- * - Array (and certain array-like classes):
- * the key is the element (as above).
- * - Hash (and certain hash-like classes):
- * the key is the 2-element array formed from the key-value pair:
+ * With a hash argument, that hash is used for the tally (instead of a new hash),
+ * and is returned;
+ * this may be useful for accumulating tallies across multiple enumerables:
*
- * h = {} # => {}
- * {foo: 'a', bar: 'b'}.tally(h) # => {[:foo, "a"]=>1, [:bar, "b"]=>1}
- * {foo: 'c', bar: 'd'}.tally(h) # => {[:foo, "a"]=>1, [:bar, "b"]=>1, [:foo, "c"]=>1, [:bar, "d"]=>1}
- * {foo: 'a', bar: 'b'}.tally(h) # => {[:foo, "a"]=>2, [:bar, "b"]=>2, [:foo, "c"]=>1, [:bar, "d"]=>1}
- * {foo: 'c', bar: 'd'}.tally(h) # => {[:foo, "a"]=>2, [:bar, "b"]=>2, [:foo, "c"]=>2, [:bar, "d"]=>2}
+ * hash = {}
+ * hash = %w[a c d b c a].tally(hash)
+ * hash # => {"a"=>2, "c"=>2, "d"=>1, "b"=>1}
+ * hash = %w[b a z].tally(hash)
+ * hash # => {"a"=>3, "c"=>2, "d"=>1, "b"=>2, "z"=>1}
+ * hash = %w[b a m].tally(hash)
+ * hash # => {"a"=>4, "c"=>2, "d"=>1, "b"=>3, "z"=>1, "m"=> 1}
*
*/
@@ -1358,7 +1306,7 @@ enum_first(int argc, VALUE *argv, VALUE obj)
* The ordering of equal elements is indeterminate and may be unstable.
*
* With no block given, the sort compares
- * using the elements' own method <tt>#<=></tt>:
+ * using the elements' own method <tt><=></tt>:
*
* %w[b c a d].sort # => ["a", "b", "c", "d"]
* {foo: 0, bar: 1, baz: 2}.sort # => [[:bar, 1], [:baz, 2], [:foo, 0]]
@@ -1388,12 +1336,10 @@ enum_sort(VALUE obj)
}
#define SORT_BY_BUFSIZE 16
-#define SORT_BY_UNIFORMED(num, flo, fix) (((num&1)<<2)|((flo&1)<<1)|fix)
struct sort_by_data {
const VALUE ary;
const VALUE buf;
- uint8_t n;
- uint8_t primitive_uniformed;
+ long n;
};
static VALUE
@@ -1414,11 +1360,6 @@ sort_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, _data))
rb_raise(rb_eRuntimeError, "sort_by reentered");
}
- if (data->primitive_uniformed) {
- data->primitive_uniformed &= SORT_BY_UNIFORMED((FIXNUM_P(v)) || (RB_FLOAT_TYPE_P(v)),
- RB_FLOAT_TYPE_P(v),
- FIXNUM_P(v));
- }
RARRAY_ASET(data->buf, data->n*2, v);
RARRAY_ASET(data->buf, data->n*2+1, i);
data->n++;
@@ -1446,179 +1387,6 @@ sort_by_cmp(const void *ap, const void *bp, void *data)
return OPTIMIZED_CMP(a, b);
}
-
-/*
- This is parts of uniform sort
-*/
-
-#define uless rb_uniform_is_less
-#define UNIFORM_SWAP(a,b)\
- do{struct rb_uniform_sort_data tmp = a; a = b; b = tmp;} while(0)
-
-struct rb_uniform_sort_data {
- VALUE v;
- VALUE i;
-};
-
-static inline bool
-rb_uniform_is_less(VALUE a, VALUE b)
-{
-
- if (FIXNUM_P(a) && FIXNUM_P(b)) {
- return (SIGNED_VALUE)a < (SIGNED_VALUE)b;
- }
- else if (FIXNUM_P(a)) {
- RUBY_ASSERT(RB_FLOAT_TYPE_P(b));
- return rb_float_cmp(b, a) > 0;
- }
- else {
- RUBY_ASSERT(RB_FLOAT_TYPE_P(a));
- return rb_float_cmp(a, b) < 0;
- }
-}
-
-static inline bool
-rb_uniform_is_larger(VALUE a, VALUE b)
-{
-
- if (FIXNUM_P(a) && FIXNUM_P(b)) {
- return (SIGNED_VALUE)a > (SIGNED_VALUE)b;
- }
- else if (FIXNUM_P(a)) {
- RUBY_ASSERT(RB_FLOAT_TYPE_P(b));
- return rb_float_cmp(b, a) < 0;
- }
- else {
- RUBY_ASSERT(RB_FLOAT_TYPE_P(a));
- return rb_float_cmp(a, b) > 0;
- }
-}
-
-#define med3_val(a,b,c) (uless(a,b)?(uless(b,c)?b:uless(c,a)?a:c):(uless(c,b)?b:uless(a,c)?a:c))
-
-static void
-rb_uniform_insertionsort_2(struct rb_uniform_sort_data* ptr_begin,
- struct rb_uniform_sort_data* ptr_end)
-{
- if ((ptr_end - ptr_begin) < 2) return;
- struct rb_uniform_sort_data tmp, *j, *k,
- *index = ptr_begin+1;
- for (; index < ptr_end; index++) {
- tmp = *index;
- j = k = index;
- if (uless(tmp.v, ptr_begin->v)) {
- while (ptr_begin < j) {
- *j = *(--k);
- j = k;
- }
- }
- else {
- while (uless(tmp.v, (--k)->v)) {
- *j = *k;
- j = k;
- }
- }
- *j = tmp;
- }
-}
-
-static inline void
-rb_uniform_heap_down_2(struct rb_uniform_sort_data* ptr_begin,
- size_t offset, size_t len)
-{
- size_t c;
- struct rb_uniform_sort_data tmp = ptr_begin[offset];
- while ((c = (offset<<1)+1) <= len) {
- if (c < len && uless(ptr_begin[c].v, ptr_begin[c+1].v)) {
- c++;
- }
- if (!uless(tmp.v, ptr_begin[c].v)) break;
- ptr_begin[offset] = ptr_begin[c];
- offset = c;
- }
- ptr_begin[offset] = tmp;
-}
-
-static void
-rb_uniform_heapsort_2(struct rb_uniform_sort_data* ptr_begin,
- struct rb_uniform_sort_data* ptr_end)
-{
- size_t n = ptr_end - ptr_begin;
- if (n < 2) return;
-
- for (size_t offset = n>>1; offset > 0;) {
- rb_uniform_heap_down_2(ptr_begin, --offset, n-1);
- }
- for (size_t offset = n-1; offset > 0;) {
- UNIFORM_SWAP(*ptr_begin, ptr_begin[offset]);
- rb_uniform_heap_down_2(ptr_begin, 0, --offset);
- }
-}
-
-
-static void
-rb_uniform_quicksort_intro_2(struct rb_uniform_sort_data* ptr_begin,
- struct rb_uniform_sort_data* ptr_end, size_t d)
-{
-
- if (ptr_end - ptr_begin <= 16) {
- rb_uniform_insertionsort_2(ptr_begin, ptr_end);
- return;
- }
- if (d == 0) {
- rb_uniform_heapsort_2(ptr_begin, ptr_end);
- return;
- }
-
- VALUE x = med3_val(ptr_begin->v,
- ptr_begin[(ptr_end - ptr_begin)>>1].v,
- ptr_end[-1].v);
- struct rb_uniform_sort_data *i = ptr_begin;
- struct rb_uniform_sort_data *j = ptr_end-1;
-
- do {
- while (uless(i->v, x)) i++;
- while (uless(x, j->v)) j--;
- if (i <= j) {
- UNIFORM_SWAP(*i, *j);
- i++;
- j--;
- }
- } while (i <= j);
- j++;
- if (ptr_end - j > 1) rb_uniform_quicksort_intro_2(j, ptr_end, d-1);
- if (i - ptr_begin > 1) rb_uniform_quicksort_intro_2(ptr_begin, i, d-1);
-}
-
-/**
- * Direct primitive data compare sort. Implement with intro sort.
- * @param[in] ptr_begin The begin address of target rb_ary's raw pointer.
- * @param[in] ptr_end The end address of target rb_ary's raw pointer.
-**/
-static void
-rb_uniform_intro_sort_2(struct rb_uniform_sort_data* ptr_begin,
- struct rb_uniform_sort_data* ptr_end)
-{
- size_t n = ptr_end - ptr_begin;
- size_t d = CHAR_BIT * sizeof(n) - nlz_intptr(n) - 1;
- bool sorted_flag = true;
-
- for (struct rb_uniform_sort_data* ptr = ptr_begin+1; ptr < ptr_end; ptr++) {
- if (rb_uniform_is_larger((ptr-1)->v, (ptr)->v)) {
- sorted_flag = false;
- break;
- }
- }
-
- if (sorted_flag) {
- return;
- }
- rb_uniform_quicksort_intro_2(ptr_begin, ptr_end, d<<1);
-}
-
-#undef uless
-
-
/*
* call-seq:
* sort_by {|element| ... } -> array
@@ -1725,9 +1493,6 @@ enum_sort_by(VALUE obj)
RB_OBJ_WRITE(memo, &data->ary, ary);
RB_OBJ_WRITE(memo, &data->buf, buf);
data->n = 0;
- data->primitive_uniformed = SORT_BY_UNIFORMED((CMP_OPTIMIZABLE(FLOAT) && CMP_OPTIMIZABLE(INTEGER)),
- CMP_OPTIMIZABLE(FLOAT),
- CMP_OPTIMIZABLE(INTEGER));
rb_block_call(obj, id_each, 0, 0, sort_by_i, (VALUE)memo);
ary = data->ary;
buf = data->buf;
@@ -1736,16 +1501,9 @@ enum_sort_by(VALUE obj)
rb_ary_concat(ary, buf);
}
if (RARRAY_LEN(ary) > 2) {
- if (data->primitive_uniformed) {
- RARRAY_PTR_USE(ary, ptr,
- rb_uniform_intro_sort_2((struct rb_uniform_sort_data*)ptr,
- (struct rb_uniform_sort_data*)(ptr + RARRAY_LEN(ary))));
- }
- else {
- RARRAY_PTR_USE(ary, ptr,
- ruby_qsort(ptr, RARRAY_LEN(ary)/2, 2*sizeof(VALUE),
- sort_by_cmp, (void *)ary));
- }
+ RARRAY_PTR_USE(ary, ptr,
+ ruby_qsort(ptr, RARRAY_LEN(ary)/2, 2*sizeof(VALUE),
+ sort_by_cmp, (void *)ary));
}
if (RBASIC(ary)->klass) {
rb_raise(rb_eRuntimeError, "sort_by reentered");
@@ -1761,9 +1519,6 @@ enum_sort_by(VALUE obj)
#define ENUMFUNC(name) argc ? name##_eqq : rb_block_given_p() ? name##_iter_i : name##_i
-#define ENUM_BLOCK_CALL(name) \
- rb_block_call2(obj, id_each, 0, 0, ENUMFUNC(name), (VALUE)memo, rb_block_given_p() && rb_block_pair_yield_optimizable() ? RB_BLOCK_NO_USE_PACKED_ARGS : 0);
-
#define MEMO_ENUM_NEW(v1) (rb_check_arity(argc, 0, 1), MEMO_NEW((v1), (argc ? *argv : 0), 0))
#define DEFINE_ENUMFUNCS(name) \
@@ -1814,9 +1569,6 @@ DEFINE_ENUMFUNCS(all)
*
* Returns whether every element meets a given criterion.
*
- * If +self+ has no element, returns +true+ and argument or block
- * are not used.
- *
* With no argument and no block,
* returns whether every element is truthy:
*
@@ -1857,7 +1609,7 @@ enum_all(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
WARN_UNUSED_BLOCK(argc);
- ENUM_BLOCK_CALL(all);
+ rb_block_call(obj, id_each, 0, 0, ENUMFUNC(all), (VALUE)memo);
return memo->v1;
}
@@ -1878,9 +1630,6 @@ DEFINE_ENUMFUNCS(any)
*
* Returns whether any element meets a given criterion.
*
- * If +self+ has no element, returns +false+ and argument or block
- * are not used.
- *
* With no argument and no block,
* returns whether any element is truthy:
*
@@ -1911,6 +1660,7 @@ DEFINE_ENUMFUNCS(any)
* {foo: 0, bar: 1, baz: 2}.any? {|key, value| value < 1 } # => true
* {foo: 0, bar: 1, baz: 2}.any? {|key, value| value < 0 } # => false
*
+ *
* Related: #all?, #none?, #one?.
*/
@@ -1919,7 +1669,7 @@ enum_any(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo = MEMO_ENUM_NEW(Qfalse);
WARN_UNUSED_BLOCK(argc);
- ENUM_BLOCK_CALL(any);
+ rb_block_call(obj, id_each, 0, 0, ENUMFUNC(any), (VALUE)memo);
return memo->v1;
}
@@ -2208,7 +1958,7 @@ enum_one(int argc, VALUE *argv, VALUE obj)
VALUE result;
WARN_UNUSED_BLOCK(argc);
- ENUM_BLOCK_CALL(one);
+ rb_block_call(obj, id_each, 0, 0, ENUMFUNC(one), (VALUE)memo);
result = memo->v1;
if (UNDEF_P(result)) return Qfalse;
return result;
@@ -2269,7 +2019,7 @@ enum_none(int argc, VALUE *argv, VALUE obj)
struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
WARN_UNUSED_BLOCK(argc);
- ENUM_BLOCK_CALL(none);
+ rb_block_call(obj, id_each, 0, 0, ENUMFUNC(none), (VALUE)memo);
return memo->v1;
}
@@ -2327,7 +2077,7 @@ min_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
* The ordering of equal elements is indeterminate and may be unstable.
*
* With no argument and no block, returns the minimum element,
- * using the elements' own method <tt>#<=></tt> for comparison:
+ * using the elements' own method <tt><=></tt> for comparison:
*
* (1..4).min # => 1
* (-4..-1).min # => -4
@@ -2449,7 +2199,7 @@ max_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, args))
* The ordering of equal elements is indeterminate and may be unstable.
*
* With no argument and no block, returns the maximum element,
- * using the elements' own method <tt>#<=></tt> for comparison:
+ * using the elements' own method <tt><=></tt> for comparison:
*
* (1..4).max # => 4
* (-4..-1).max # => -1
@@ -2638,7 +2388,7 @@ minmax_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, _memo))
* The ordering of equal elements is indeterminate and may be unstable.
*
* With no argument and no block, returns the minimum and maximum elements,
- * using the elements' own method <tt>#<=></tt> for comparison:
+ * using the elements' own method <tt><=></tt> for comparison:
*
* (1..4).minmax # => [1, 4]
* (-4..-1).minmax # => [-4, -1]
@@ -2972,6 +2722,8 @@ member_i(RB_BLOCK_CALL_FUNC_ARGLIST(iter, args))
* {foo: 0, bar: 1, baz: 2}.include?('foo') # => false
* {foo: 0, bar: 1, baz: 2}.include?(0) # => false
*
+ * Enumerable#member? is an alias for Enumerable#include?.
+ *
*/
static VALUE
@@ -4595,7 +4347,7 @@ struct enum_sum_memo {
static void
sum_iter_normalize_memo(struct enum_sum_memo *memo)
{
- RUBY_ASSERT(FIXABLE(memo->n));
+ assert(FIXABLE(memo->n));
memo->v = rb_fix_plus(LONG2FIX(memo->n), memo->v);
memo->n = 0;
@@ -4697,7 +4449,7 @@ sum_iter_Kahan_Babuska(VALUE i, struct enum_sum_memo *memo)
static void
sum_iter(VALUE i, struct enum_sum_memo *memo)
{
- RUBY_ASSERT(memo != NULL);
+ assert(memo != NULL);
if (memo->block_given) {
i = rb_yield(i);
}
@@ -4707,7 +4459,7 @@ sum_iter(VALUE i, struct enum_sum_memo *memo)
}
else switch (TYPE(memo->v)) {
default: sum_iter_some_value(i, memo); return;
- case T_FLOAT: sum_iter_Kahan_Babuska(i, memo); return;
+ case T_FLOAT:
case T_FIXNUM:
case T_BIGNUM:
case T_RATIONAL:
@@ -4748,8 +4500,8 @@ hash_sum_i(VALUE key, VALUE value, VALUE arg)
static void
hash_sum(VALUE hash, struct enum_sum_memo *memo)
{
- RUBY_ASSERT(RB_TYPE_P(hash, T_HASH));
- RUBY_ASSERT(memo != NULL);
+ assert(RB_TYPE_P(hash, T_HASH));
+ assert(memo != NULL);
rb_hash_foreach(hash, hash_sum_i, (VALUE)memo);
}
@@ -4881,13 +4633,13 @@ uniq_iter(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
* %w[a b c c b a a b c].uniq # => ["a", "b", "c"]
* [0, 1, 2, 2, 1, 0, 0, 1, 2].uniq # => [0, 1, 2]
*
- * With a block, returns a new array containing elements only for which the block
+ * With a block, returns a new array containing only for which the block
* returns a unique value:
*
* a = [0, 1, 2, 3, 4, 5, 5, 4, 3, 2, 1]
* a.uniq {|i| i.even? ? i : 0 } # => [0, 2, 4]
* a = %w[a b c d e e d c b a a b c d e]
- * a.uniq {|c| c < 'c' } # => ["a", "c"]
+ a.uniq {|c| c < 'c' } # => ["a", "c"]
*
*/
@@ -4946,7 +4698,7 @@ enum_compact(VALUE obj)
*
* - {Querying}[rdoc-ref:Enumerable@Methods+for+Querying]
* - {Fetching}[rdoc-ref:Enumerable@Methods+for+Fetching]
- * - {Searching and Filtering}[rdoc-ref:Enumerable@Methods+for+Searching+and+Filtering]
+ * - {Searching}[rdoc-ref:Enumerable@Methods+for+Searching]
* - {Sorting}[rdoc-ref:Enumerable@Methods+for+Sorting]
* - {Iterating}[rdoc-ref:Enumerable@Methods+for+Iterating]
* - {And more....}[rdoc-ref:Enumerable@Other+Methods]
@@ -4955,14 +4707,14 @@ enum_compact(VALUE obj)
*
* These methods return information about the \Enumerable other than the elements themselves:
*
- * - #member? (aliased as #include?): Returns +true+ if <tt>self == object</tt>, +false+ otherwise.
+ * - #include?, #member?: Returns +true+ if <tt>self == object</tt>, +false+ otherwise.
* - #all?: Returns +true+ if all elements meet a specified criterion; +false+ otherwise.
* - #any?: Returns +true+ if any element meets a specified criterion; +false+ otherwise.
* - #none?: Returns +true+ if no element meets a specified criterion; +false+ otherwise.
* - #one?: Returns +true+ if exactly one element meets a specified criterion; +false+ otherwise.
* - #count: Returns the count of elements,
* based on an argument or block criterion, if given.
- * - #tally: Returns a new Hash containing the counts of occurrences of each element.
+ * - #tally: Returns a new \Hash containing the counts of occurrences of each element.
*
* === Methods for Fetching
*
@@ -4970,7 +4722,7 @@ enum_compact(VALUE obj)
*
* <i>Leading, trailing, or all elements</i>:
*
- * - #to_a (aliased as #entries): Returns all elements.
+ * - #entries, #to_a: Returns all elements.
* - #first: Returns the first element or leading elements.
* - #take: Returns a specified number of leading elements.
* - #drop: Returns a specified number of trailing elements.
@@ -4980,24 +4732,24 @@ enum_compact(VALUE obj)
* <i>Minimum and maximum value elements</i>:
*
* - #min: Returns the elements whose values are smallest among the elements,
- * as determined by <tt>#<=></tt> or a given block.
+ * as determined by <tt><=></tt> or a given block.
* - #max: Returns the elements whose values are largest among the elements,
- * as determined by <tt>#<=></tt> or a given block.
- * - #minmax: Returns a 2-element Array containing the smallest and largest elements.
+ * as determined by <tt><=></tt> or a given block.
+ * - #minmax: Returns a 2-element \Array containing the smallest and largest elements.
* - #min_by: Returns the smallest element, as determined by the given block.
* - #max_by: Returns the largest element, as determined by the given block.
* - #minmax_by: Returns the smallest and largest elements, as determined by the given block.
*
* <i>Groups, slices, and partitions</i>:
*
- * - #group_by: Returns a Hash that partitions the elements into groups.
+ * - #group_by: Returns a \Hash that partitions the elements into groups.
* - #partition: Returns elements partitioned into two new Arrays, as determined by the given block.
- * - #slice_after: Returns a new Enumerator whose entries are a partition of +self+,
- * based either on a given +object+ or a given block.
- * - #slice_before: Returns a new Enumerator whose entries are a partition of +self+,
- * based either on a given +object+ or a given block.
- * - #slice_when: Returns a new Enumerator whose entries are a partition of +self+
- * based on the given block.
+ * - #slice_after: Returns a new \Enumerator whose entries are a partition of +self+,
+ based either on a given +object+ or a given block.
+ * - #slice_before: Returns a new \Enumerator whose entries are a partition of +self+,
+ based either on a given +object+ or a given block.
+ * - #slice_when: Returns a new \Enumerator whose entries are a partition of +self+
+ based on the given block.
* - #chunk: Returns elements organized into chunks as specified by the given block.
* - #chunk_while: Returns elements organized into chunks as specified by the given block.
*
@@ -5005,8 +4757,8 @@ enum_compact(VALUE obj)
*
* These methods return elements that meet a specified criterion:
*
- * - #find (aliased as #detect): Returns an element selected by the block.
- * - #find_all (aliased as #filter, #select): Returns elements selected by the block.
+ * - #find, #detect: Returns an element selected by the block.
+ * - #find_all, #filter, #select: Returns elements selected by the block.
* - #find_index: Returns the index of an element selected by a given object or block.
* - #reject: Returns elements not rejected by the block.
* - #uniq: Returns elements that are not duplicates.
@@ -5015,7 +4767,7 @@ enum_compact(VALUE obj)
*
* These methods return elements in sorted order:
*
- * - #sort: Returns the elements, sorted by <tt>#<=></tt> or the given block.
+ * - #sort: Returns the elements, sorted by <tt><=></tt> or the given block.
* - #sort_by: Returns the elements, sorted by the given block.
*
* === Methods for Iterating
@@ -5031,14 +4783,14 @@ enum_compact(VALUE obj)
*
* === Other Methods
*
- * - #collect (aliased as #map): Returns objects returned by the block.
+ * - #map, #collect: Returns objects returned by the block.
* - #filter_map: Returns truthy objects returned by the block.
- * - #flat_map (aliased as #collect_concat): Returns flattened objects returned by the block.
+ * - #flat_map, #collect_concat: Returns flattened objects returned by the block.
* - #grep: Returns elements selected by a given object
* or objects returned by a given block.
* - #grep_v: Returns elements selected by a given object
* or objects returned by a given block.
- * - #inject (aliased as #reduce): Returns the object formed by combining all elements.
+ * - #reduce, #inject: Returns the object formed by combining all elements.
* - #sum: Returns the sum of the elements, using method <tt>+</tt>.
* - #zip: Combines each element with elements from other enumerables;
* returns the n-tuples or calls the block with each.
@@ -5097,18 +4849,18 @@ enum_compact(VALUE obj)
*
* Virtually all methods in \Enumerable call method +#each+ in the including class:
*
- * - <tt>Hash#each</tt> yields the next key-value pair as a 2-element Array.
- * - <tt>Struct#each</tt> yields the next name-value pair as a 2-element Array.
+ * - <tt>Hash#each</tt> yields the next key-value pair as a 2-element \Array.
+ * - <tt>Struct#each</tt> yields the next name-value pair as a 2-element \Array.
* - For the other classes above, +#each+ yields the next object from the collection.
*
* == About the Examples
*
* The example code snippets for the \Enumerable methods:
*
- * - Always show the use of one or more Array-like classes (often Array itself).
- * - Sometimes show the use of a Hash-like class.
+ * - Always show the use of one or more \Array-like classes (often \Array itself).
+ * - Sometimes show the use of a \Hash-like class.
* For some methods, though, the usage would not make sense,
- * and so it is not shown. Example: #tally would find exactly one of each Hash entry.
+ * and so it is not shown. Example: #tally would find exactly one of each \Hash entry.
*
*/
diff --git a/enumerator.c b/enumerator.c
index faaa77cb49..d587b63d32 100644
--- a/enumerator.c
+++ b/enumerator.c
@@ -73,7 +73,7 @@
* puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
* # => ["0:foo", "1:bar", "2:baz"]
*
- * == External Iteration
+ * == External Iteration
*
* An Enumerator can also be used as an external iterator.
* For example, Enumerator#next returns the next value of the iterator
@@ -85,31 +85,26 @@
* puts e.next # => 3
* puts e.next # raises StopIteration
*
- * +next+, +next_values+, +peek+, and +peek_values+ are the only methods
- * which use external iteration (and Array#zip(Enumerable-not-Array) which uses +next+ internally).
+ * +next+, +next_values+, +peek+ and +peek_values+ are the only methods
+ * which use external iteration (and Array#zip(Enumerable-not-Array) which uses +next+).
*
* These methods do not affect other internal enumeration methods,
* unless the underlying iteration method itself has side-effect, e.g. IO#each_line.
*
- * FrozenError will be raised if these methods are called against a frozen enumerator.
- * Since +rewind+ and +feed+ also change state for external iteration,
- * these methods may raise FrozenError too.
- *
* External iteration differs *significantly* from internal iteration
* due to using a Fiber:
- * - The Fiber adds some overhead compared to internal enumeration.
- * - The stacktrace will only include the stack from the Enumerator, not above.
- * - Fiber-local variables are *not* inherited inside the Enumerator Fiber,
- * which instead starts with no Fiber-local variables.
- * - Fiber storage variables *are* inherited and are designed
- * to handle Enumerator Fibers. Assigning to a Fiber storage variable
- * only affects the current Fiber, so if you want to change state
- * in the caller Fiber of the Enumerator Fiber, you need to use an
- * extra indirection (e.g., use some object in the Fiber storage
- * variable and mutate some ivar of it).
+ * - The Fiber adds some overhead compared to internal enumeration.
+ * - The stacktrace will only include the stack from the Enumerator, not above.
+ * - Fiber-local variables are *not* inherited inside the Enumerator Fiber,
+ * which instead starts with no Fiber-local variables.
+ * - Fiber storage variables *are* inherited and are designed
+ * to handle Enumerator Fibers. Assigning to a Fiber storage variable
+ * only affects the current Fiber, so if you want to change state
+ * in the caller Fiber of the Enumerator Fiber, you need to use an
+ * extra indirection (e.g., use some object in the Fiber storage
+ * variable and mutate some ivar of it).
*
* Concretely:
- *
* Thread.current[:fiber_local] = 1
* Fiber[:storage_var] = 1
* e = Enumerator.new do |y|
@@ -125,7 +120,7 @@
* e.each { p _1 }
* p Fiber[:storage_var] # => 2 (it ran in the same Fiber/"stack" as the current Fiber)
*
- * == Convert External Iteration to Internal Iteration
+ * == Convert External Iteration to Internal Iteration
*
* You can use an external iterator to implement an internal iterator as follows:
*
@@ -195,19 +190,6 @@ struct enumerator {
int kw_splat;
};
-RUBY_REFERENCES(enumerator_refs) = {
- RUBY_REF_EDGE(struct enumerator, obj),
- RUBY_REF_EDGE(struct enumerator, args),
- RUBY_REF_EDGE(struct enumerator, fib),
- RUBY_REF_EDGE(struct enumerator, dst),
- RUBY_REF_EDGE(struct enumerator, lookahead),
- RUBY_REF_EDGE(struct enumerator, feedvalue),
- RUBY_REF_EDGE(struct enumerator, stop_exc),
- RUBY_REF_EDGE(struct enumerator, size),
- RUBY_REF_EDGE(struct enumerator, procs),
- RUBY_REF_END
-};
-
static VALUE rb_cGenerator, rb_cYielder, rb_cEnumProducer;
struct generator {
@@ -257,15 +239,56 @@ struct enum_product {
VALUE rb_cArithSeq;
+/*
+ * Enumerator
+ */
+static void
+enumerator_mark(void *p)
+{
+ struct enumerator *ptr = p;
+ rb_gc_mark_movable(ptr->obj);
+ rb_gc_mark_movable(ptr->args);
+ rb_gc_mark_movable(ptr->fib);
+ rb_gc_mark_movable(ptr->dst);
+ rb_gc_mark_movable(ptr->lookahead);
+ rb_gc_mark_movable(ptr->feedvalue);
+ rb_gc_mark_movable(ptr->stop_exc);
+ rb_gc_mark_movable(ptr->size);
+ rb_gc_mark_movable(ptr->procs);
+}
+
+static void
+enumerator_compact(void *p)
+{
+ struct enumerator *ptr = p;
+ ptr->obj = rb_gc_location(ptr->obj);
+ ptr->args = rb_gc_location(ptr->args);
+ ptr->fib = rb_gc_location(ptr->fib);
+ ptr->dst = rb_gc_location(ptr->dst);
+ ptr->lookahead = rb_gc_location(ptr->lookahead);
+ ptr->feedvalue = rb_gc_location(ptr->feedvalue);
+ ptr->stop_exc = rb_gc_location(ptr->stop_exc);
+ ptr->size = rb_gc_location(ptr->size);
+ ptr->procs = rb_gc_location(ptr->procs);
+}
+
+#define enumerator_free RUBY_TYPED_DEFAULT_FREE
+
+static size_t
+enumerator_memsize(const void *p)
+{
+ return sizeof(struct enumerator);
+}
+
static const rb_data_type_t enumerator_data_type = {
"enumerator",
{
- RUBY_REFS_LIST_PTR(enumerator_refs),
- RUBY_TYPED_DEFAULT_FREE,
- NULL, // Nothing allocated externally, so don't need a memsize function
- NULL,
+ enumerator_mark,
+ enumerator_free,
+ enumerator_memsize,
+ enumerator_compact,
},
- 0, NULL, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static struct enumerator *
@@ -296,15 +319,22 @@ proc_entry_compact(void *p)
ptr->memo = rb_gc_location(ptr->memo);
}
+#define proc_entry_free RUBY_TYPED_DEFAULT_FREE
+
+static size_t
+proc_entry_memsize(const void *p)
+{
+ return p ? sizeof(struct proc_entry) : 0;
+}
+
static const rb_data_type_t proc_entry_data_type = {
"proc_entry",
{
proc_entry_mark,
- RUBY_TYPED_DEFAULT_FREE,
- NULL, // Nothing allocated externally, so don't need a memsize function
+ proc_entry_free,
+ proc_entry_memsize,
proc_entry_compact,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
};
static struct proc_entry *
@@ -389,7 +419,7 @@ obj_to_enum(int argc, VALUE *argv, VALUE obj)
}
enumerator = rb_enumeratorize_with_size(obj, meth, argc, argv, 0);
if (rb_block_given_p()) {
- RB_OBJ_WRITE(enumerator, &enumerator_ptr(enumerator)->size, rb_block_proc());
+ enumerator_ptr(enumerator)->size = rb_block_proc();
}
return enumerator;
}
@@ -418,15 +448,15 @@ enumerator_init(VALUE enum_obj, VALUE obj, VALUE meth, int argc, const VALUE *ar
rb_raise(rb_eArgError, "unallocated enumerator");
}
- RB_OBJ_WRITE(enum_obj, &ptr->obj, obj);
+ ptr->obj = obj;
ptr->meth = rb_to_id(meth);
- if (argc) RB_OBJ_WRITE(enum_obj, &ptr->args, rb_ary_new4(argc, argv));
+ if (argc) ptr->args = rb_ary_new4(argc, argv);
ptr->fib = 0;
ptr->dst = Qnil;
ptr->lookahead = Qundef;
ptr->feedvalue = Qundef;
ptr->stop_exc = Qfalse;
- RB_OBJ_WRITE(enum_obj, &ptr->size, size);
+ ptr->size = size;
ptr->size_fn = size_fn;
ptr->kw_splat = kw_splat;
@@ -505,13 +535,13 @@ enumerator_init_copy(VALUE obj, VALUE orig)
rb_raise(rb_eArgError, "unallocated enumerator");
}
- RB_OBJ_WRITE(obj, &ptr1->obj, ptr0->obj);
+ ptr1->obj = ptr0->obj;
ptr1->meth = ptr0->meth;
- RB_OBJ_WRITE(obj, &ptr1->args, ptr0->args);
+ ptr1->args = ptr0->args;
ptr1->fib = 0;
ptr1->lookahead = Qundef;
ptr1->feedvalue = Qundef;
- RB_OBJ_WRITE(obj, &ptr1->size, ptr0->size);
+ ptr1->size = ptr0->size;
ptr1->size_fn = ptr0->size_fn;
return obj;
@@ -559,17 +589,11 @@ enumerator_block_call(VALUE obj, rb_block_call_func *func, VALUE arg)
const struct enumerator *e = enumerator_ptr(obj);
ID meth = e->meth;
- VALUE args = e->args;
- if (args) {
- argc = RARRAY_LENINT(args);
- argv = RARRAY_CONST_PTR(args);
+ if (e->args) {
+ argc = RARRAY_LENINT(e->args);
+ argv = RARRAY_CONST_PTR(e->args);
}
-
- VALUE ret = rb_block_call_kw(e->obj, meth, argc, argv, func, arg, e->kw_splat);
-
- RB_GC_GUARD(args);
-
- return ret;
+ return rb_block_call_kw(e->obj, meth, argc, argv, func, arg, e->kw_splat);
}
/*
@@ -626,7 +650,7 @@ enumerator_each(int argc, VALUE *argv, VALUE obj)
else {
args = rb_ary_new4(argc, argv);
}
- RB_OBJ_WRITE(obj, &e->args, args);
+ e->args = args;
e->size = Qnil;
e->size_fn = 0;
}
@@ -767,7 +791,7 @@ next_i(RB_BLOCK_CALL_FUNC_ARGLIST(_, obj))
VALUE result;
result = rb_block_call(obj, id_each, 0, 0, next_ii, obj);
- RB_OBJ_WRITE(obj, &e->stop_exc, rb_exc_new2(rb_eStopIteration, "iteration reached an end"));
+ e->stop_exc = rb_exc_new2(rb_eStopIteration, "iteration reached an end");
rb_ivar_set(e->stop_exc, id_result, result);
return rb_fiber_yield(1, &nil);
}
@@ -776,8 +800,8 @@ static void
next_init(VALUE obj, struct enumerator *e)
{
VALUE curr = rb_fiber_current();
- RB_OBJ_WRITE(obj, &e->dst, curr);
- RB_OBJ_WRITE(obj, &e->fib, rb_fiber_new(next_i, obj));
+ e->dst = curr;
+ e->fib = rb_fiber_new(next_i, obj);
e->lookahead = Qundef;
}
@@ -865,8 +889,6 @@ enumerator_next_values(VALUE obj)
struct enumerator *e = enumerator_ptr(obj);
VALUE vs;
- rb_check_frozen(obj);
-
if (!UNDEF_P(e->lookahead)) {
vs = e->lookahead;
e->lookahead = Qundef;
@@ -928,12 +950,9 @@ enumerator_peek_values(VALUE obj)
{
struct enumerator *e = enumerator_ptr(obj);
- rb_check_frozen(obj);
-
if (UNDEF_P(e->lookahead)) {
- RB_OBJ_WRITE(obj, &e->lookahead, get_next_values(obj, e));
+ e->lookahead = get_next_values(obj, e);
}
-
return e->lookahead;
}
@@ -1055,12 +1074,10 @@ enumerator_feed(VALUE obj, VALUE v)
{
struct enumerator *e = enumerator_ptr(obj);
- rb_check_frozen(obj);
-
if (!UNDEF_P(e->feedvalue)) {
rb_raise(rb_eTypeError, "feed value already set");
}
- RB_OBJ_WRITE(obj, &e->feedvalue, v);
+ e->feedvalue = v;
return Qnil;
}
@@ -1079,8 +1096,6 @@ enumerator_rewind(VALUE obj)
{
struct enumerator *e = enumerator_ptr(obj);
- rb_check_frozen(obj);
-
rb_check_funcall(e->obj, id_rewind, 0, 0);
e->fib = 0;
@@ -1294,15 +1309,23 @@ yielder_compact(void *p)
ptr->proc = rb_gc_location(ptr->proc);
}
+#define yielder_free RUBY_TYPED_DEFAULT_FREE
+
+static size_t
+yielder_memsize(const void *p)
+{
+ return sizeof(struct yielder);
+}
+
static const rb_data_type_t yielder_data_type = {
"yielder",
{
yielder_mark,
- RUBY_TYPED_DEFAULT_FREE,
- NULL,
+ yielder_free,
+ yielder_memsize,
yielder_compact,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static struct yielder *
@@ -1341,7 +1364,7 @@ yielder_init(VALUE obj, VALUE proc)
rb_raise(rb_eArgError, "unallocated yielder");
}
- RB_OBJ_WRITE(obj, &ptr->proc, proc);
+ ptr->proc = proc;
return obj;
}
@@ -1426,15 +1449,23 @@ generator_compact(void *p)
ptr->obj = rb_gc_location(ptr->obj);
}
+#define generator_free RUBY_TYPED_DEFAULT_FREE
+
+static size_t
+generator_memsize(const void *p)
+{
+ return sizeof(struct generator);
+}
+
static const rb_data_type_t generator_data_type = {
"generator",
{
generator_mark,
- RUBY_TYPED_DEFAULT_FREE,
- NULL,
+ generator_free,
+ generator_memsize,
generator_compact,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static struct generator *
@@ -1474,7 +1505,7 @@ generator_init(VALUE obj, VALUE proc)
rb_raise(rb_eArgError, "unallocated generator");
}
- RB_OBJ_WRITE(obj, &ptr->proc, proc);
+ ptr->proc = proc;
return obj;
}
@@ -1522,7 +1553,7 @@ generator_init_copy(VALUE obj, VALUE orig)
rb_raise(rb_eArgError, "unallocated generator");
}
- RB_OBJ_WRITE(obj, &ptr1->proc, ptr0->proc);
+ ptr1->proc = ptr0->proc;
return obj;
}
@@ -1689,7 +1720,7 @@ lazy_generator_init(VALUE enumerator, VALUE procs)
lazy_init_block, rb_ary_new3(2, obj, procs));
gen_ptr = generator_ptr(generator);
- RB_OBJ_WRITE(generator, &gen_ptr->obj, obj);
+ gen_ptr->obj = obj;
return generator;
}
@@ -1874,10 +1905,10 @@ lazy_add_method(VALUE obj, int argc, VALUE *argv, VALUE args, VALUE memo,
VALUE entry_obj = TypedData_Make_Struct(rb_cObject, struct proc_entry,
&proc_entry_data_type, entry);
if (rb_block_given_p()) {
- RB_OBJ_WRITE(entry_obj, &entry->proc, rb_block_proc());
+ entry->proc = rb_block_proc();
}
entry->fn = fn;
- RB_OBJ_WRITE(entry_obj, &entry->memo, args);
+ entry->memo = args;
lazy_set_args(entry_obj, memo);
@@ -1886,9 +1917,9 @@ lazy_add_method(VALUE obj, int argc, VALUE *argv, VALUE args, VALUE memo,
rb_ary_push(new_procs, entry_obj);
new_obj = enumerator_init_copy(enumerator_allocate(rb_cLazy), obj);
- new_e = RTYPEDDATA_GET_DATA(new_obj);
- RB_OBJ_WRITE(new_obj, &new_e->obj, new_generator);
- RB_OBJ_WRITE(new_obj, &new_e->procs, new_procs);
+ new_e = DATA_PTR(new_obj);
+ new_e->obj = new_generator;
+ new_e->procs = new_procs;
if (argc > 0) {
new_e->meth = rb_to_id(*argv++);
@@ -1897,9 +1928,7 @@ lazy_add_method(VALUE obj, int argc, VALUE *argv, VALUE args, VALUE memo,
else {
new_e->meth = id_each;
}
-
- RB_OBJ_WRITE(new_obj, &new_e->args, rb_ary_new4(argc, argv));
-
+ new_e->args = rb_ary_new4(argc, argv);
return new_obj;
}
@@ -1985,7 +2014,7 @@ lazy_to_enum(int argc, VALUE *argv, VALUE self)
}
lazy = lazy_to_enum_i(self, meth, argc, argv, 0, rb_keyword_given_p());
if (rb_block_given_p()) {
- RB_OBJ_WRITE(lazy, &enumerator_ptr(lazy)->size, rb_block_proc());
+ enumerator_ptr(lazy)->size = rb_block_proc();
}
return lazy;
}
@@ -2371,6 +2400,7 @@ lazy_zip_arrays_func(VALUE proc_entry, struct MEMO *result, VALUE memos, long me
rb_ary_push(ary, rb_ary_entry(RARRAY_AREF(arrays, i), count));
}
LAZY_MEMO_SET_VALUE(result, ary);
+ LAZY_MEMO_SET_PACKED(result);
rb_ary_store(memos, memo_index, LONG2NUM(++count));
return result;
}
@@ -2400,6 +2430,7 @@ lazy_zip_func(VALUE proc_entry, struct MEMO *result, VALUE memos, long memo_inde
rb_ary_push(ary, v);
}
LAZY_MEMO_SET_VALUE(result, ary);
+ LAZY_MEMO_SET_PACKED(result);
return result;
}
@@ -2944,7 +2975,7 @@ static const rb_data_type_t producer_data_type = {
producer_memsize,
producer_compact,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static struct producer *
@@ -2984,8 +3015,8 @@ producer_init(VALUE obj, VALUE init, VALUE proc)
rb_raise(rb_eArgError, "unallocated producer");
}
- RB_OBJ_WRITE(obj, &ptr->init, init);
- RB_OBJ_WRITE(obj, &ptr->proc, proc);
+ ptr->init = init;
+ ptr->proc = proc;
return obj;
}
@@ -3180,7 +3211,7 @@ enum_chain_initialize(VALUE obj, VALUE enums)
if (!ptr) rb_raise(rb_eArgError, "unallocated chain");
- ptr->enums = rb_ary_freeze(enums);
+ ptr->enums = rb_obj_freeze(enums);
ptr->pos = -1;
return obj;
@@ -3508,7 +3539,7 @@ enum_product_initialize(int argc, VALUE *argv, VALUE obj)
if (!ptr) rb_raise(rb_eArgError, "unallocated product");
- ptr->enums = rb_ary_freeze(enums);
+ ptr->enums = rb_obj_freeze(enums);
return obj;
}
@@ -3535,19 +3566,10 @@ static VALUE
enum_product_total_size(VALUE enums)
{
VALUE total = INT2FIX(1);
- VALUE sizes = rb_ary_hidden_new(RARRAY_LEN(enums));
long i;
for (i = 0; i < RARRAY_LEN(enums); i++) {
VALUE size = enum_size(RARRAY_AREF(enums, i));
- if (size == INT2FIX(0)) {
- rb_ary_resize(sizes, 0);
- return size;
- }
- rb_ary_push(sizes, size);
- }
- for (i = 0; i < RARRAY_LEN(sizes); i++) {
- VALUE size = RARRAY_AREF(sizes, i);
if (NIL_P(size) || (RB_TYPE_P(size, T_FLOAT) && isinf(NUM2DBL(size)))) {
return size;
@@ -4570,7 +4592,7 @@ InitVM_Enumerator(void)
rb_hash_aset(lazy_use_super_method, sym("uniq"), sym("_enumerable_uniq"));
rb_hash_aset(lazy_use_super_method, sym("with_index"), sym("_enumerable_with_index"));
rb_obj_freeze(lazy_use_super_method);
- rb_vm_register_global_object(lazy_use_super_method);
+ rb_gc_register_mark_object(lazy_use_super_method);
#if 0 /* for RDoc */
rb_define_method(rb_cLazy, "to_a", lazy_to_a, 0);
diff --git a/error.c b/error.c
index 5256521acd..726f57a4c0 100644
--- a/error.c
+++ b/error.c
@@ -23,33 +23,25 @@
# include <unistd.h>
#endif
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-
#if defined __APPLE__
# include <AvailabilityMacros.h>
#endif
#include "internal.h"
-#include "internal/class.h"
#include "internal/error.h"
#include "internal/eval.h"
#include "internal/hash.h"
#include "internal/io.h"
#include "internal/load.h"
#include "internal/object.h"
-#include "internal/process.h"
#include "internal/string.h"
#include "internal/symbol.h"
#include "internal/thread.h"
#include "internal/variable.h"
#include "ruby/encoding.h"
#include "ruby/st.h"
-#include "ruby/util.h"
#include "ruby_assert.h"
#include "vm_core.h"
-#include "yjit.h"
#include "builtin.h"
@@ -85,7 +77,6 @@ static ID id_warn;
static ID id_category;
static ID id_deprecated;
static ID id_experimental;
-static ID id_performance;
static VALUE sym_category;
static VALUE sym_highlight;
static struct {
@@ -157,8 +148,8 @@ rb_syntax_error_append(VALUE exc, VALUE file, int line, int column,
}
static unsigned int warning_disabled_categories = (
- (1U << RB_WARN_CATEGORY_DEPRECATED) |
- ~RB_WARN_CATEGORY_DEFAULT_BITS);
+ 1U << RB_WARN_CATEGORY_DEPRECATED |
+ 0);
static unsigned int
rb_warning_category_mask(VALUE category)
@@ -196,7 +187,7 @@ rb_warning_category_update(unsigned int mask, unsigned int bits)
warning_disabled_categories |= mask & ~bits;
}
-bool
+MJIT_FUNC_EXPORTED bool
rb_warning_category_enabled_p(rb_warning_category_t category)
{
return !(warning_disabled_categories & (1U << category));
@@ -209,18 +200,14 @@ rb_warning_category_enabled_p(rb_warning_category_t category)
* Returns the flag to show the warning messages for +category+.
* Supported categories are:
*
- * +:deprecated+ ::
- * deprecation warnings
- * * assignment of non-nil value to <code>$,</code> and <code>$;</code>
- * * keyword arguments
- * etc.
+ * +:deprecated+ :: deprecation warnings
+ * * assignment of non-nil value to <code>$,</code> and <code>$;</code>
+ * * keyword arguments
+ * * proc/lambda without block
+ * etc.
*
- * +:experimental+ ::
- * experimental features
- *
- * +:performance+ ::
- * performance hints
- * * Shape variation limit
+ * +:experimental+ :: experimental features
+ * * Pattern matching
*/
static VALUE
@@ -253,26 +240,6 @@ rb_warning_s_aset(VALUE mod, VALUE category, VALUE flag)
/*
* call-seq:
- * categories -> array
- *
- * Returns a list of the supported category symbols.
- */
-
-static VALUE
-rb_warning_s_categories(VALUE mod)
-{
- st_index_t num = warning_categories.id2enum->num_entries;
- ID *ids = ALLOCA_N(ID, num);
- num = st_keys(warning_categories.id2enum, ids, num);
- VALUE ary = rb_ary_new_capa(num);
- for (st_index_t i = 0; i < num; ++i) {
- rb_ary_push(ary, ID2SYM(ids[i]));
- }
- return rb_ary_freeze(ary);
-}
-
-/*
- * call-seq:
* warn(msg, category: nil) -> nil
*
* Writes warning message +msg+ to $stderr. This method is called by
@@ -312,11 +279,11 @@ rb_warning_s_warn(int argc, VALUE *argv, VALUE mod)
*
* Changing the behavior of Warning.warn is useful to customize how warnings are
* handled by Ruby, for instance by filtering some warnings, and/or outputting
- * warnings somewhere other than <tt>$stderr</tt>.
+ * warnings somewhere other than $stderr.
*
* If you want to change the behavior of Warning.warn you should use
- * <tt>Warning.extend(MyNewModuleWithWarnMethod)</tt> and you can use +super+
- * to get the default behavior of printing the warning to <tt>$stderr</tt>.
+ * +Warning.extend(MyNewModuleWithWarnMethod)+ and you can use `super`
+ * to get the default behavior of printing the warning to $stderr.
*
* Example:
* module MyWarningFilter
@@ -333,7 +300,7 @@ rb_warning_s_warn(int argc, VALUE *argv, VALUE mod)
* You should never redefine Warning#warn (the instance method), as that will
* then no longer provide a way to use the default behavior.
*
- * The warning[https://rubygems.org/gems/warning] gem provides convenient ways to customize Warning.warn.
+ * The +warning+ gem provides convenient ways to customize Warning.warn.
*/
static VALUE
@@ -385,28 +352,18 @@ warn_vsprintf(rb_encoding *enc, const char *file, int line, const char *fmt, va_
return rb_str_cat2(str, "\n");
}
-#define with_warn_vsprintf(enc, file, line, fmt) \
+#define with_warn_vsprintf(file, line, fmt) \
VALUE str; \
va_list args; \
va_start(args, fmt); \
- str = warn_vsprintf(enc, file, line, fmt, args); \
+ str = warn_vsprintf(NULL, file, line, fmt, args); \
va_end(args);
void
rb_compile_warn(const char *file, int line, const char *fmt, ...)
{
if (!NIL_P(ruby_verbose)) {
- with_warn_vsprintf(NULL, file, line, fmt) {
- rb_write_warning_str(str);
- }
- }
-}
-
-void
-rb_enc_compile_warn(rb_encoding *enc, const char *file, int line, const char *fmt, ...)
-{
- if (!NIL_P(ruby_verbose)) {
- with_warn_vsprintf(enc, file, line, fmt) {
+ with_warn_vsprintf(file, line, fmt) {
rb_write_warning_str(str);
}
}
@@ -417,18 +374,7 @@ void
rb_compile_warning(const char *file, int line, const char *fmt, ...)
{
if (RTEST(ruby_verbose)) {
- with_warn_vsprintf(NULL, file, line, fmt) {
- rb_write_warning_str(str);
- }
- }
-}
-
-/* rb_enc_compile_warning() reports only in verbose mode */
-void
-rb_enc_compile_warning(rb_encoding *enc, const char *file, int line, const char *fmt, ...)
-{
- if (RTEST(ruby_verbose)) {
- with_warn_vsprintf(enc, file, line, fmt) {
+ with_warn_vsprintf(file, line, fmt) {
rb_write_warning_str(str);
}
}
@@ -438,7 +384,7 @@ void
rb_category_compile_warn(rb_warning_category_t category, const char *file, int line, const char *fmt, ...)
{
if (!NIL_P(ruby_verbose)) {
- with_warn_vsprintf(NULL, file, line, fmt) {
+ with_warn_vsprintf(file, line, fmt) {
rb_warn_category(str, rb_warning_category_to_name(category));
}
}
@@ -670,239 +616,18 @@ rb_bug_reporter_add(void (*func)(FILE *, void *), void *data)
return 1;
}
-/* returns true if x can not be used as file name */
-static bool
-path_sep_p(char x)
-{
-#if defined __CYGWIN__ || defined DOSISH
-# define PATH_SEP_ENCODING 1
- // Assume that "/" is only the first byte in any encoding.
- if (x == ':') return true; // drive letter or ADS
- if (x == '\\') return true;
-#endif
- return x == '/';
-}
-
-struct path_string {
- const char *ptr;
- size_t len;
-};
-
-static const char PATHSEP_REPLACE = '!';
-
-static char *
-append_pathname(char *p, const char *pe, VALUE str)
-{
-#ifdef PATH_SEP_ENCODING
- rb_encoding *enc = rb_enc_get(str);
-#endif
- const char *s = RSTRING_PTR(str);
- const char *const se = s + RSTRING_LEN(str);
- char c;
-
- --pe; // for terminator
-
- while (p < pe && s < se && (c = *s) != '\0') {
- if (c == '.') {
- if (s == se || !*s) break; // chomp "." basename
- if (path_sep_p(s[1])) goto skipsep; // skip "./"
- }
- else if (path_sep_p(c)) {
- // squeeze successive separators
- *p++ = PATHSEP_REPLACE;
- skipsep:
- while (++s < se && path_sep_p(*s));
- continue;
- }
- const char *const ss = s;
- while (p < pe && s < se && *s && !path_sep_p(*s)) {
-#ifdef PATH_SEP_ENCODING
- int n = rb_enc_mbclen(s, se, enc);
-#else
- const int n = 1;
-#endif
- p += n;
- s += n;
- }
- if (s > ss) memcpy(p - (s - ss), ss, s - ss);
- }
-
- return p;
-}
-
-static char *
-append_basename(char *p, const char *pe, struct path_string *path, VALUE str)
-{
- if (!path->ptr) {
-#ifdef PATH_SEP_ENCODING
- rb_encoding *enc = rb_enc_get(str);
-#endif
- const char *const b = RSTRING_PTR(str), *const e = RSTRING_END(str), *p = e;
-
- while (p > b) {
- if (path_sep_p(p[-1])) {
-#ifdef PATH_SEP_ENCODING
- const char *t = rb_enc_prev_char(b, p, e, enc);
- if (t == p-1) break;
- p = t;
-#else
- break;
-#endif
- }
- else {
- --p;
- }
- }
-
- path->ptr = p;
- path->len = e - p;
- }
- size_t n = path->len;
- if (p + n > pe) n = pe - p;
- memcpy(p, path->ptr, n);
- return p + n;
-}
-
-static void
-finish_report(FILE *out, rb_pid_t pid)
-{
- if (out != stdout && out != stderr) fclose(out);
-#ifdef HAVE_WORKING_FORK
- if (pid > 0) waitpid(pid, NULL, 0);
-#endif
-}
-
-struct report_expansion {
- struct path_string exe, script;
- rb_pid_t pid;
- time_t time;
-};
-
-/*
- * Open a bug report file to write. The `RUBY_CRASH_REPORT`
- * environment variable can be set to define a template that is used
- * to name bug report files. The template can contain % specifiers
- * which are substituted by the following values when a bug report
- * file is created:
- *
- * %% A single % character.
- * %e The base name of the executable filename.
- * %E Pathname of executable, with slashes ('/') replaced by
- * exclamation marks ('!').
- * %f Similar to %e with the main script filename.
- * %F Similar to %E with the main script filename.
- * %p PID of dumped process in decimal.
- * %t Time of dump, expressed as seconds since the Epoch,
- * 1970-01-01 00:00:00 +0000 (UTC).
- * %NNN Octal char code, upto 3 digits.
- */
-static char *
-expand_report_argument(const char **input_template, struct report_expansion *values,
- char *buf, size_t size, bool word)
-{
- char *p = buf;
- char *end = buf + size;
- const char *template = *input_template;
- bool store = true;
-
- if (p >= end-1 || !*template) return NULL;
- do {
- char c = *template++;
- if (word && ISSPACE(c)) break;
- if (!store) continue;
- if (c == '%') {
- size_t n;
- switch (c = *template++) {
- case 'e':
- p = append_basename(p, end, &values->exe, rb_argv0);
- continue;
- case 'E':
- p = append_pathname(p, end, rb_argv0);
- continue;
- case 'f':
- p = append_basename(p, end, &values->script, GET_VM()->orig_progname);
- continue;
- case 'F':
- p = append_pathname(p, end, GET_VM()->orig_progname);
- continue;
- case 'p':
- if (!values->pid) values->pid = getpid();
- snprintf(p, end-p, "%" PRI_PIDT_PREFIX "d", values->pid);
- p += strlen(p);
- continue;
- case 't':
- if (!values->time) values->time = time(NULL);
- snprintf(p, end-p, "%" PRI_TIMET_PREFIX "d", values->time);
- p += strlen(p);
- continue;
- default:
- if (c >= '0' && c <= '7') {
- c = (unsigned char)ruby_scan_oct(template-1, 3, &n);
- template += n - 1;
- if (!c) store = false;
- }
- break;
- }
- }
- if (p < end-1) *p++ = c;
- } while (*template);
- *input_template = template;
- *p = '\0';
- return ++p;
-}
-
-FILE *ruby_popen_writer(char *const *argv, rb_pid_t *pid);
-
-static FILE *
-open_report_path(const char *template, char *buf, size_t size, rb_pid_t *pid)
-{
- struct report_expansion values = {{0}};
-
- if (!template) return NULL;
- if (0) fprintf(stderr, "RUBY_CRASH_REPORT=%s\n", buf);
- if (*template == '|') {
- char *argv[16], *bufend = buf + size, *p;
- int argc;
- template++;
- for (argc = 0; argc < numberof(argv) - 1; ++argc) {
- while (*template && ISSPACE(*template)) template++;
- p = expand_report_argument(&template, &values, buf, bufend-buf, true);
- if (!p) break;
- argv[argc] = buf;
- buf = p;
- }
- argv[argc] = NULL;
- if (!p) return ruby_popen_writer(argv, pid);
- }
- else if (*template) {
- expand_report_argument(&template, &values, buf, size, false);
- return fopen(buf, "w");
- }
- return NULL;
-}
-
-static const char *crash_report;
-
/* SIGSEGV handler might have a very small stack. Thus we need to use it carefully. */
#define REPORT_BUG_BUFSIZ 256
static FILE *
-bug_report_file(const char *file, int line, rb_pid_t *pid)
+bug_report_file(const char *file, int line)
{
char buf[REPORT_BUG_BUFSIZ];
- const char *report = crash_report;
- if (!report) report = getenv("RUBY_CRASH_REPORT");
- FILE *out = open_report_path(report, buf, sizeof(buf), pid);
+ FILE *out = stderr;
int len = err_position_0(buf, sizeof(buf), file, line);
- if (out) {
- if ((ssize_t)fwrite(buf, 1, len, out) == (ssize_t)len) return out;
- fclose(out);
- }
- if ((ssize_t)fwrite(buf, 1, len, stderr) == (ssize_t)len) {
- return stderr;
- }
- if ((ssize_t)fwrite(buf, 1, len, stdout) == (ssize_t)len) {
- return stdout;
+ if ((ssize_t)fwrite(buf, 1, len, out) == (ssize_t)len ||
+ (ssize_t)fwrite(buf, 1, len, (out = stdout)) == (ssize_t)len) {
+ return out;
}
return NULL;
@@ -1009,7 +734,7 @@ bug_report_begin_valist(FILE *out, const char *fmt, va_list args)
} while (0)
static void
-bug_report_end(FILE *out, rb_pid_t pid)
+bug_report_end(FILE *out)
{
/* call additional bug reporters */
{
@@ -1020,45 +745,26 @@ bug_report_end(FILE *out, rb_pid_t pid)
}
}
postscript_dump(out);
- finish_report(out, pid);
}
#define report_bug(file, line, fmt, ctx) do { \
- rb_pid_t pid = -1; \
- FILE *out = bug_report_file(file, line, &pid); \
+ FILE *out = bug_report_file(file, line); \
if (out) { \
bug_report_begin(out, fmt); \
- rb_vm_bugreport(ctx, out); \
- bug_report_end(out, pid); \
+ rb_vm_bugreport(ctx); \
+ bug_report_end(out); \
} \
} while (0) \
#define report_bug_valist(file, line, fmt, ctx, args) do { \
- rb_pid_t pid = -1; \
- FILE *out = bug_report_file(file, line, &pid); \
+ FILE *out = bug_report_file(file, line); \
if (out) { \
bug_report_begin_valist(out, fmt, args); \
- rb_vm_bugreport(ctx, out); \
- bug_report_end(out, pid); \
+ rb_vm_bugreport(ctx); \
+ bug_report_end(out); \
} \
} while (0) \
-void
-ruby_set_crash_report(const char *template)
-{
- crash_report = template;
-#if RUBY_DEBUG
- rb_pid_t pid = -1;
- char buf[REPORT_BUG_BUFSIZ];
- FILE *out = open_report_path(template, buf, sizeof(buf), &pid);
- if (out) {
- time_t t = time(NULL);
- fprintf(out, "ruby_test_bug_report: %s", ctime(&t));
- finish_report(out, pid);
- }
-#endif
-}
-
NORETURN(static void die(void));
static void
die(void)
@@ -1108,7 +814,6 @@ rb_bug_for_fatal_signal(ruby_sighandler_t default_sighandler, int sig, const voi
if (default_sighandler) default_sighandler(sig);
- ruby_default_signal(sig);
die();
}
@@ -1162,33 +867,16 @@ rb_report_bug_valist(VALUE file, int line, const char *fmt, va_list args)
report_bug_valist(RSTRING_PTR(file), line, fmt, NULL, args);
}
-void
+MJIT_FUNC_EXPORTED void
rb_assert_failure(const char *file, int line, const char *name, const char *expr)
{
- rb_assert_failure_detail(file, line, name, expr, NULL);
-}
-
-void
-rb_assert_failure_detail(const char *file, int line, const char *name, const char *expr,
- const char *fmt, ...)
-{
FILE *out = stderr;
fprintf(out, "Assertion Failed: %s:%d:", file, line);
if (name) fprintf(out, "%s:", name);
- fputs(expr, out);
-
- if (fmt && *fmt) {
- va_list args;
- va_start(args, fmt);
- fputs(": ", out);
- vfprintf(out, fmt, args);
- va_end(args);
- }
- fprintf(out, "\n%s\n\n", rb_dynamic_description);
-
+ fprintf(out, "%s\n%s\n\n", expr, rb_dynamic_description);
preface_dump(out);
- rb_vm_bugreport(NULL, out);
- bug_report_end(out, -1);
+ rb_vm_bugreport(NULL);
+ bug_report_end(out);
die();
}
@@ -1382,7 +1070,7 @@ rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type)
actual = rb_str_new_cstr(name); /* or rb_fstring_cstr? not sure... */
}
else {
- return RTYPEDDATA_GET_DATA(obj);
+ return DATA_PTR(obj);
}
const char *expected = data_type->wrap_struct_name;
@@ -1453,7 +1141,6 @@ rb_exc_new_cstr(VALUE etype, const char *s)
VALUE
rb_exc_new_str(VALUE etype, VALUE str)
{
- rb_yjit_lazy_push_frame(GET_EC()->cfp->pc);
StringValue(str);
return rb_class_new_instance(1, &str, etype);
}
@@ -1468,23 +1155,12 @@ exc_init(VALUE exc, VALUE mesg)
}
/*
- * call-seq:
- * Exception.new(message = nil) -> exception
- *
- * Returns a new exception object.
- *
- * The given +message+ should be
- * a {string-convertible object}[rdoc-ref:implicit_conversion.rdoc@String-Convertible+Objects];
- * see method #message;
- * if not given, the message is the class name of the new instance
- * (which may be the name of a subclass):
- *
- * Examples:
- *
- * Exception.new # => #<Exception: Exception>
- * LoadError.new # => #<LoadError: LoadError> # Subclass of Exception.
- * Exception.new('Boom') # => #<Exception: Boom>
+ * call-seq:
+ * Exception.new(msg = nil) -> exception
+ * Exception.exception(msg = nil) -> exception
*
+ * Construct a new Exception object, optionally passing in
+ * a message.
*/
static VALUE
@@ -1500,24 +1176,12 @@ exc_initialize(int argc, VALUE *argv, VALUE exc)
* Document-method: exception
*
* call-seq:
- * exception(message = nil) -> self or new_exception
- *
- * Returns an exception object of the same class as +self+;
- * useful for creating a similar exception, but with a different message.
- *
- * With +message+ +nil+, returns +self+:
+ * exc.exception([string]) -> an_exception or exc
*
- * x0 = StandardError.new('Boom') # => #<StandardError: Boom>
- * x1 = x0.exception # => #<StandardError: Boom>
- * x0.__id__ == x1.__id__ # => true
- *
- * With {string-convertible object}[rdoc-ref:implicit_conversion.rdoc@String-Convertible+Objects]
- * +message+ (even the same as the original message),
- * returns a new exception object whose class is the same as +self+,
- * and whose message is the given +message+:
- *
- * x1 = x0.exception('Boom') # => #<StandardError: Boom>
- * x0..equal?(x1) # => false
+ * With no argument, or if the argument is the same as the receiver,
+ * return the receiver. Otherwise, create a new
+ * exception object of the same class as the receiver, but with a
+ * message equal to <code>string.to_str</code>.
*
*/
@@ -1536,15 +1200,10 @@ exc_exception(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * to_s -> string
- *
- * Returns a string representation of +self+:
- *
- * x = RuntimeError.new('Boom')
- * x.to_s # => "Boom"
- * x = RuntimeError.new
- * x.to_s # => "RuntimeError"
+ * exception.to_s -> string
*
+ * Returns exception's message (or the name of the exception if
+ * no message is set).
*/
static VALUE
@@ -1584,10 +1243,10 @@ rb_get_detailed_message(VALUE exc, VALUE opt)
}
/*
- * call-seq:
- * Exception.to_tty? -> true or false
+ * call-seq:
+ * Exception.to_tty? -> true or false
*
- * Returns +true+ if exception messages will be sent to a terminal device.
+ * Returns +true+ if exception messages will be sent to a tty.
*/
static VALUE
exc_s_to_tty_p(VALUE self)
@@ -1647,51 +1306,20 @@ check_order_keyword(VALUE opt)
/*
* call-seq:
- * full_message(highlight: true, order: :top) -> string
- *
- * Returns an enhanced message string:
- *
- * - Includes the exception class name.
- * - If the value of keyword +highlight+ is true (not +nil+ or +false+),
- * includes bolding ANSI codes (see below) to enhance the appearance of the message.
- * - Includes the {backtrace}[rdoc-ref:exceptions.md@Backtraces]:
- *
- * - If the value of keyword +order+ is +:top+ (the default),
- * lists the error message and the innermost backtrace entry first.
- * - If the value of keyword +order+ is +:bottom+,
- * lists the error message the the innermost entry last.
- *
- * Example:
+ * exception.full_message(highlight: bool, order: [:top or :bottom]) -> string
*
- * def baz
- * begin
- * 1 / 0
- * rescue => x
- * pp x.message
- * pp x.full_message(highlight: false).split("\n")
- * pp x.full_message.split("\n")
- * end
- * end
- * def bar; baz; end
- * def foo; bar; end
- * foo
+ * Returns formatted string of _exception_.
+ * The returned string is formatted using the same format that Ruby uses
+ * when printing an uncaught exceptions to stderr.
*
- * Output:
+ * If _highlight_ is +true+ the default error handler will send the
+ * messages to a tty.
*
- * "divided by 0"
- * ["t.rb:3:in `/': divided by 0 (ZeroDivisionError)",
- * "\tfrom t.rb:3:in `baz'",
- * "\tfrom t.rb:10:in `bar'",
- * "\tfrom t.rb:11:in `foo'",
- * "\tfrom t.rb:12:in `<main>'"]
- * ["t.rb:3:in `/': \e[1mdivided by 0 (\e[1;4mZeroDivisionError\e[m\e[1m)\e[m",
- * "\tfrom t.rb:3:in `baz'",
- * "\tfrom t.rb:10:in `bar'",
- * "\tfrom t.rb:11:in `foo'",
- * "\tfrom t.rb:12:in `<main>'"]
+ * _order_ must be either of +:top+ or +:bottom+, and places the error
+ * message and the innermost backtrace come at the top or the bottom.
*
- * An overrriding method should be careful with ANSI code enhancements;
- * see {Messages}[rdoc-ref:exceptions.md@Messages].
+ * The default values of these options depend on <code>$stderr</code>
+ * and its +tty?+ at the timing of a call.
*/
static VALUE
@@ -1720,11 +1348,10 @@ exc_full_message(int argc, VALUE *argv, VALUE exc)
/*
* call-seq:
- * message -> string
+ * exception.message -> string
*
- * Returns #to_s.
- *
- * See {Messages}[rdoc-ref:exceptions.md@Messages].
+ * Returns the result of invoking <code>exception.to_s</code>.
+ * Normally this returns the exception's message or name.
*/
static VALUE
@@ -1735,47 +1362,42 @@ exc_message(VALUE exc)
/*
* call-seq:
- * detailed_message(highlight: false, **kwargs) -> string
- *
- * Returns the message string with enhancements:
+ * exception.detailed_message(highlight: bool, **opt) -> string
*
- * - Includes the exception class name in the first line.
- * - If the value of keyword +highlight+ is +true+,
- * includes bolding and underlining ANSI codes (see below)
- * to enhance the appearance of the message.
+ * Processes a string returned by #message.
*
- * Examples:
+ * It may add the class name of the exception to the end of the first line.
+ * Also, when +highlight+ keyword is true, it adds ANSI escape sequences to
+ * make the message bold.
*
- * begin
- * 1 / 0
- * rescue => x
- * p x.message
- * p x.detailed_message # Class name added.
- * p x.detailed_message(highlight: true) # Class name, bolding, and underlining added.
- * end
+ * If you override this method, it must be tolerant for unknown keyword
+ * arguments. All keyword arguments passed to #full_message are delegated
+ * to this method.
*
- * Output:
+ * This method is overridden by did_you_mean and error_highlight to add
+ * their information.
*
- * "divided by 0"
- * "divided by 0 (ZeroDivisionError)"
- * "\e[1mdivided by 0 (\e[1;4mZeroDivisionError\e[m\e[1m)\e[m"
+ * A user-defined exception class can also define their own
+ * +detailed_message+ method to add supplemental information.
+ * When +highlight+ is true, it can return a string containing escape
+ * sequences, but use widely-supported ones. It is recommended to limit
+ * the following codes:
*
- * This method is overridden by some gems in the Ruby standard library to add information:
+ * - Reset (+\e[0m+)
+ * - Bold (+\e[1m+)
+ * - Underline (+\e[4m+)
+ * - Foreground color except white and black
+ * - Red (+\e[31m+)
+ * - Green (+\e[32m+)
+ * - Yellow (+\e[33m+)
+ * - Blue (+\e[34m+)
+ * - Magenta (+\e[35m+)
+ * - Cyan (+\e[36m+)
*
- * - DidYouMean::Correctable#detailed_message.
- * - ErrorHighlight::CoreExt#detailed_message.
- * - SyntaxSuggest#detailed_message.
- *
- * An overriding method must be tolerant of passed keyword arguments,
- * which may include (but may not be limited to):
- *
- * - +:highlight+.
- * - +:did_you_mean+.
- * - +:error_highlight+.
- * - +:syntax_suggest+.
- *
- * An overrriding method should also be careful with ANSI code enhancements;
- * see {Messages}[rdoc-ref:exceptions.md@Messages].
+ * Use escape sequences carefully even if +highlight+ is true.
+ * Do not use escape sequences to express essential information;
+ * the message should be readable even if all escape sequences are
+ * ignored.
*/
static VALUE
@@ -1787,22 +1409,16 @@ exc_detailed_message(int argc, VALUE *argv, VALUE exc)
VALUE highlight = check_highlight_keyword(opt, 0);
- extern VALUE rb_decorate_message(const VALUE eclass, VALUE emesg, int highlight);
+ extern VALUE rb_decorate_message(const VALUE eclass, const VALUE emesg, int highlight);
return rb_decorate_message(CLASS_OF(exc), rb_get_message(exc), RTEST(highlight));
}
/*
* call-seq:
- * inspect -> string
- *
- * Returns a string representation of +self+:
- *
- * x = RuntimeError.new('Boom')
- * x.inspect # => "#<RuntimeError: Boom>"
- * x = RuntimeError.new
- * x.inspect # => "#<RuntimeError: RuntimeError>"
+ * exception.inspect -> string
*
+ * Return this exception's class name and message.
*/
static VALUE
@@ -1835,31 +1451,38 @@ exc_inspect(VALUE exc)
/*
* call-seq:
- * backtrace -> array or nil
+ * exception.backtrace -> array or nil
*
- * Returns a backtrace value for +self+;
- * the returned value depends on the form of the stored backtrace value:
+ * Returns any backtrace associated with the exception. The backtrace
+ * is an array of strings, each containing either ``filename:lineNo: in
+ * `method''' or ``filename:lineNo.''
*
- * - \Array of Thread::Backtrace::Location objects:
- * returns the array of strings given by
- * <tt>Exception#backtrace_locations.map {|loc| loc.to_s }</tt>.
- * This is the normal case, where the backtrace value was stored by Kernel#raise.
- * - \Array of strings: returns that array.
- * This is the unusual case, where the backtrace value was explicitly
- * stored as an array of strings.
- * - +nil+: returns +nil+.
+ * def a
+ * raise "boom"
+ * end
*
- * Example:
+ * def b
+ * a()
+ * end
*
- * begin
- * 1 / 0
- * rescue => x
- * x.backtrace.take(2)
- * end
- * # => ["(irb):132:in `/'", "(irb):132:in `<top (required)>'"]
+ * begin
+ * b()
+ * rescue => detail
+ * print detail.backtrace.join("\n")
+ * end
*
- * see {Backtraces}[rdoc-ref:exceptions.md@Backtraces].
- */
+ * <em>produces:</em>
+ *
+ * prog.rb:2:in `a'
+ * prog.rb:6:in `b'
+ * prog.rb:10
+ *
+ * In the case no backtrace has been set, +nil+ is returned
+ *
+ * ex = StandardError.new
+ * ex.backtrace
+ * #=> nil
+*/
static VALUE
exc_backtrace(VALUE exc)
@@ -1901,24 +1524,13 @@ rb_get_backtrace(VALUE exc)
/*
* call-seq:
- * backtrace_locations -> array or nil
- *
- * Returns a backtrace value for +self+;
- * the returned value depends on the form of the stored backtrace value:
+ * exception.backtrace_locations -> array or nil
*
- * - \Array of Thread::Backtrace::Location objects: returns that array.
- * - \Array of strings or +nil+: returns +nil+.
- *
- * Example:
+ * Returns any backtrace associated with the exception. This method is
+ * similar to Exception#backtrace, but the backtrace is an array of
+ * Thread::Backtrace::Location.
*
- * begin
- * 1 / 0
- * rescue => x
- * x.backtrace_locations.take(2)
- * end
- * # => ["(irb):150:in `/'", "(irb):150:in `<top (required)>'"]
- *
- * See {Backtraces}[rdoc-ref:exceptions.md@Backtraces].
+ * This method is not affected by Exception#set_backtrace().
*/
static VALUE
exc_backtrace_locations(VALUE exc)
@@ -1936,7 +1548,7 @@ static VALUE
rb_check_backtrace(VALUE bt)
{
long i;
- static const char err[] = "backtrace must be an Array of String or an Array of Thread::Backtrace::Location";
+ static const char err[] = "backtrace must be Array of String";
if (!NIL_P(bt)) {
if (RB_TYPE_P(bt, T_STRING)) return rb_ary_new3(1, bt);
@@ -1956,71 +1568,33 @@ rb_check_backtrace(VALUE bt)
/*
* call-seq:
- * set_backtrace(value) -> value
- *
- * Sets the backtrace value for +self+; returns the given +value:
- *
- * x = RuntimeError.new('Boom')
- * x.set_backtrace(%w[foo bar baz]) # => ["foo", "bar", "baz"]
- * x.backtrace # => ["foo", "bar", "baz"]
+ * exc.set_backtrace(backtrace) -> array
*
- * The given +value+ must be an array of strings, a single string, or +nil+.
+ * Sets the backtrace information associated with +exc+. The +backtrace+ must
+ * be an array of String objects or a single String in the format described
+ * in Exception#backtrace.
*
- * Does not affect the value returned by #backtrace_locations.
- *
- * See {Backtraces}[rdoc-ref:exceptions.md@Backtraces].
*/
static VALUE
exc_set_backtrace(VALUE exc, VALUE bt)
{
- VALUE btobj = rb_location_ary_to_backtrace(bt);
- if (RTEST(btobj)) {
- rb_ivar_set(exc, id_bt, btobj);
- rb_ivar_set(exc, id_bt_locations, btobj);
- return bt;
- }
- else {
- return rb_ivar_set(exc, id_bt, rb_check_backtrace(bt));
- }
+ return rb_ivar_set(exc, id_bt, rb_check_backtrace(bt));
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_exc_set_backtrace(VALUE exc, VALUE bt)
{
return exc_set_backtrace(exc, bt);
}
/*
- * call-seq:
- * cause -> exception or nil
- *
- * Returns the previous value of global variable <tt>$!</tt>,
- * which may be +nil+
- * (see {Global Variables}[rdoc-ref:exceptions.md@Global+Variables]):
- *
- * begin
- * raise('Boom 0')
- * rescue => x0
- * puts "Exception: #{x0}; $!: #{$!}; cause: #{x0.cause.inspect}."
- * begin
- * raise('Boom 1')
- * rescue => x1
- * puts "Exception: #{x1}; $!: #{$!}; cause: #{x1.cause}."
- * begin
- * raise('Boom 2')
- * rescue => x2
- * puts "Exception: #{x2}; $!: #{$!}; cause: #{x2.cause}."
- * end
- * end
- * end
- *
- * Output:
- *
- * Exception: Boom 0; $!: Boom 0; cause: nil.
- * Exception: Boom 1; $!: Boom 1; cause: Boom 0.
- * Exception: Boom 2; $!: Boom 2; cause: Boom 1.
+ * call-seq:
+ * exception.cause -> an_exception or nil
*
+ * Returns the previous exception ($!) at the time this exception was raised.
+ * This is useful for wrapping exceptions and retaining the original exception
+ * information.
*/
static VALUE
@@ -2037,11 +1611,11 @@ try_convert_to_exception(VALUE obj)
/*
* call-seq:
- * self == object -> true or false
- *
- * Returns whether +object+ is the same class as +self+
- * and its #message and #backtrace are equal to those of +self+.
+ * exc == obj -> true or false
*
+ * Equality---If <i>obj</i> is not an Exception, returns
+ * <code>false</code>. Otherwise, returns <code>true</code> if <i>exc</i> and
+ * <i>obj</i> share same class, messages, and backtrace.
*/
static VALUE
@@ -2376,50 +1950,50 @@ rb_nomethod_err_new(VALUE mesg, VALUE recv, VALUE method, VALUE args, int priv)
return nometh_err_init_attr(exc, args, priv);
}
-typedef struct name_error_message_struct {
- VALUE mesg;
- VALUE recv;
- VALUE name;
-} name_error_message_t;
+/* :nodoc: */
+enum {
+ NAME_ERR_MESG__MESG,
+ NAME_ERR_MESG__RECV,
+ NAME_ERR_MESG__NAME,
+ NAME_ERR_MESG_COUNT
+};
static void
name_err_mesg_mark(void *p)
{
- name_error_message_t *ptr = (name_error_message_t *)p;
- rb_gc_mark_movable(ptr->mesg);
- rb_gc_mark_movable(ptr->recv);
- rb_gc_mark_movable(ptr->name);
+ VALUE *ptr = p;
+ rb_gc_mark_locations(ptr, ptr+NAME_ERR_MESG_COUNT);
}
-static void
-name_err_mesg_update(void *p)
+#define name_err_mesg_free RUBY_TYPED_DEFAULT_FREE
+
+static size_t
+name_err_mesg_memsize(const void *p)
{
- name_error_message_t *ptr = (name_error_message_t *)p;
- ptr->mesg = rb_gc_location(ptr->mesg);
- ptr->recv = rb_gc_location(ptr->recv);
- ptr->name = rb_gc_location(ptr->name);
+ return NAME_ERR_MESG_COUNT * sizeof(VALUE);
}
static const rb_data_type_t name_err_mesg_data_type = {
"name_err_mesg",
{
name_err_mesg_mark,
- RUBY_TYPED_DEFAULT_FREE,
- NULL, // No external memory to report,
- name_err_mesg_update,
+ name_err_mesg_free,
+ name_err_mesg_memsize,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
/* :nodoc: */
static VALUE
-rb_name_err_mesg_init(VALUE klass, VALUE mesg, VALUE recv, VALUE name)
+rb_name_err_mesg_init(VALUE klass, VALUE mesg, VALUE recv, VALUE method)
{
- name_error_message_t *message;
- VALUE result = TypedData_Make_Struct(klass, name_error_message_t, &name_err_mesg_data_type, message);
- RB_OBJ_WRITE(result, &message->mesg, mesg);
- RB_OBJ_WRITE(result, &message->recv, recv);
- RB_OBJ_WRITE(result, &message->name, name);
+ VALUE result = TypedData_Wrap_Struct(klass, &name_err_mesg_data_type, 0);
+ VALUE *ptr = ALLOC_N(VALUE, NAME_ERR_MESG_COUNT);
+
+ ptr[NAME_ERR_MESG__MESG] = mesg;
+ ptr[NAME_ERR_MESG__RECV] = recv;
+ ptr[NAME_ERR_MESG__NAME] = method;
+ RTYPEDDATA_DATA(result) = ptr;
return result;
}
@@ -2441,16 +2015,14 @@ name_err_mesg_alloc(VALUE klass)
static VALUE
name_err_mesg_init_copy(VALUE obj1, VALUE obj2)
{
+ VALUE *ptr1, *ptr2;
+
if (obj1 == obj2) return obj1;
rb_obj_init_copy(obj1, obj2);
- name_error_message_t *ptr1, *ptr2;
- TypedData_Get_Struct(obj1, name_error_message_t, &name_err_mesg_data_type, ptr1);
- TypedData_Get_Struct(obj2, name_error_message_t, &name_err_mesg_data_type, ptr2);
-
- RB_OBJ_WRITE(obj1, &ptr1->mesg, ptr2->mesg);
- RB_OBJ_WRITE(obj1, &ptr1->recv, ptr2->recv);
- RB_OBJ_WRITE(obj1, &ptr1->name, ptr2->name);
+ TypedData_Get_Struct(obj1, VALUE, &name_err_mesg_data_type, ptr1);
+ TypedData_Get_Struct(obj2, VALUE, &name_err_mesg_data_type, ptr2);
+ MEMCPY(ptr1, ptr2, VALUE, NAME_ERR_MESG_COUNT);
return obj1;
}
@@ -2458,18 +2030,19 @@ name_err_mesg_init_copy(VALUE obj1, VALUE obj2)
static VALUE
name_err_mesg_equal(VALUE obj1, VALUE obj2)
{
- if (obj1 == obj2) return Qtrue;
+ VALUE *ptr1, *ptr2;
+ int i;
+ if (obj1 == obj2) return Qtrue;
if (rb_obj_class(obj2) != rb_cNameErrorMesg)
return Qfalse;
- name_error_message_t *ptr1, *ptr2;
- TypedData_Get_Struct(obj1, name_error_message_t, &name_err_mesg_data_type, ptr1);
- TypedData_Get_Struct(obj2, name_error_message_t, &name_err_mesg_data_type, ptr2);
-
- if (!rb_equal(ptr1->mesg, ptr2->mesg)) return Qfalse;
- if (!rb_equal(ptr1->recv, ptr2->recv)) return Qfalse;
- if (!rb_equal(ptr1->name, ptr2->name)) return Qfalse;
+ TypedData_Get_Struct(obj1, VALUE, &name_err_mesg_data_type, ptr1);
+ TypedData_Get_Struct(obj2, VALUE, &name_err_mesg_data_type, ptr2);
+ for (i=0; i<NAME_ERR_MESG_COUNT; i++) {
+ if (!rb_equal(ptr1[i], ptr2[i]))
+ return Qfalse;
+ }
return Qtrue;
}
@@ -2488,91 +2061,51 @@ name_err_mesg_receiver_name(VALUE obj)
static VALUE
name_err_mesg_to_str(VALUE obj)
{
- name_error_message_t *ptr;
- TypedData_Get_Struct(obj, name_error_message_t, &name_err_mesg_data_type, ptr);
+ VALUE *ptr, mesg;
+ TypedData_Get_Struct(obj, VALUE, &name_err_mesg_data_type, ptr);
- VALUE mesg = ptr->mesg;
+ mesg = ptr[NAME_ERR_MESG__MESG];
if (NIL_P(mesg)) return Qnil;
else {
- struct RString s_str, c_str, d_str;
- VALUE c, s, d = 0, args[4], c2;
- int state = 0;
+ struct RString s_str, d_str;
+ VALUE c, s, d = 0, args[4];
+ int state = 0, singleton = 0;
rb_encoding *usascii = rb_usascii_encoding();
#define FAKE_CSTR(v, str) rb_setup_fake_str((v), (str), rb_strlen_lit(str), usascii)
- c = s = FAKE_CSTR(&s_str, "");
- obj = ptr->recv;
+ obj = ptr[NAME_ERR_MESG__RECV];
switch (obj) {
case Qnil:
- c = d = FAKE_CSTR(&d_str, "nil");
+ d = FAKE_CSTR(&d_str, "nil");
break;
case Qtrue:
- c = d = FAKE_CSTR(&d_str, "true");
+ d = FAKE_CSTR(&d_str, "true");
break;
case Qfalse:
- c = d = FAKE_CSTR(&d_str, "false");
+ d = FAKE_CSTR(&d_str, "false");
break;
default:
- if (strstr(RSTRING_PTR(mesg), "%2$s")) {
- d = rb_protect(name_err_mesg_receiver_name, obj, &state);
- if (state || NIL_OR_UNDEF_P(d))
- d = rb_protect(rb_inspect, obj, &state);
- if (state) {
- rb_set_errinfo(Qnil);
- }
- d = rb_check_string_type(d);
- if (NIL_P(d)) {
- d = rb_any_to_s(obj);
- }
- }
-
- if (!RB_SPECIAL_CONST_P(obj)) {
- switch (RB_BUILTIN_TYPE(obj)) {
- case T_MODULE:
- s = FAKE_CSTR(&s_str, "module ");
- c = obj;
- break;
- case T_CLASS:
- s = FAKE_CSTR(&s_str, "class ");
- c = obj;
- break;
- default:
- goto object;
- }
- }
- else {
- VALUE klass;
- object:
- klass = CLASS_OF(obj);
- if (RB_TYPE_P(klass, T_CLASS) && RCLASS_SINGLETON_P(klass)) {
- s = FAKE_CSTR(&s_str, "");
- if (obj == rb_vm_top_self()) {
- c = FAKE_CSTR(&c_str, "main");
- }
- else {
- c = rb_any_to_s(obj);
- }
- break;
- }
- else {
- s = FAKE_CSTR(&s_str, "an instance of ");
- c = rb_class_real(klass);
- }
- }
- c2 = rb_protect(name_err_mesg_receiver_name, c, &state);
- if (state || NIL_OR_UNDEF_P(c2))
- c2 = rb_protect(rb_inspect, c, &state);
+ d = rb_protect(name_err_mesg_receiver_name, obj, &state);
+ if (state || NIL_OR_UNDEF_P(d))
+ d = rb_protect(rb_inspect, obj, &state);
if (state) {
rb_set_errinfo(Qnil);
}
- c2 = rb_check_string_type(c2);
- if (NIL_P(c2)) {
- c2 = rb_any_to_s(c);
+ d = rb_check_string_type(d);
+ if (NIL_P(d)) {
+ d = rb_any_to_s(obj);
}
- c = c2;
+ singleton = (RSTRING_LEN(d) > 0 && RSTRING_PTR(d)[0] == '#');
break;
}
- args[0] = rb_obj_as_string(ptr->name);
+ if (!singleton) {
+ s = FAKE_CSTR(&s_str, ":");
+ c = rb_class_name(CLASS_OF(obj));
+ }
+ else {
+ c = s = FAKE_CSTR(&s_str, "");
+ }
+ args[0] = rb_obj_as_string(ptr[NAME_ERR_MESG__NAME]);
args[1] = d;
args[2] = s;
args[3] = c;
@@ -2605,17 +2138,17 @@ name_err_mesg_load(VALUE klass, VALUE str)
static VALUE
name_err_receiver(VALUE self)
{
- VALUE recv = rb_ivar_lookup(self, id_recv, Qundef);
+ VALUE *ptr, recv, mesg;
+
+ recv = rb_ivar_lookup(self, id_recv, Qundef);
if (!UNDEF_P(recv)) return recv;
- VALUE mesg = rb_attr_get(self, id_mesg);
+ mesg = rb_attr_get(self, id_mesg);
if (!rb_typeddata_is_kind_of(mesg, &name_err_mesg_data_type)) {
rb_raise(rb_eArgError, "no receiver is available");
}
-
- name_error_message_t *ptr;
- TypedData_Get_Struct(mesg, name_error_message_t, &name_err_mesg_data_type, ptr);
- return ptr->recv;
+ ptr = DATA_PTR(mesg);
+ return ptr[NAME_ERR_MESG__RECV];
}
/*
@@ -2825,18 +2358,8 @@ syntax_error_with_path(VALUE exc, VALUE path, VALUE *mesg, rb_encoding *enc)
rb_ivar_set(exc, id_i_path, path);
}
else {
- VALUE old_path = rb_attr_get(exc, id_i_path);
- if (old_path != path) {
- if (rb_str_equal(path, old_path)) {
- rb_raise(rb_eArgError, "SyntaxError#path changed: %+"PRIsVALUE" (%p->%p)",
- old_path, (void *)old_path, (void *)path);
- }
- else {
- rb_raise(rb_eArgError, "SyntaxError#path changed: %+"PRIsVALUE"(%s%s)->%+"PRIsVALUE"(%s)",
- old_path, rb_enc_name(rb_enc_get(old_path)),
- (FL_TEST(old_path, RSTRING_FSTR) ? ":FSTR" : ""),
- path, rb_enc_name(rb_enc_get(path)));
- }
+ if (rb_attr_get(exc, id_i_path) != path) {
+ rb_raise(rb_eArgError, "SyntaxError#path changed");
}
VALUE s = *mesg = rb_attr_get(exc, idMesg);
if (RSTRING_LEN(s) > 0 && *(RSTRING_END(s)-1) != '\n')
@@ -2847,99 +2370,68 @@ syntax_error_with_path(VALUE exc, VALUE path, VALUE *mesg, rb_encoding *enc)
/*
* Document-module: Errno
-
- * When an operating system encounters an error,
- * it typically reports the error as an integer error code:
*
- * $ ls nosuch.txt
- * ls: cannot access 'nosuch.txt': No such file or directory
- * $ echo $? # Code for last error.
- * 2
+ * Ruby exception objects are subclasses of Exception. However,
+ * operating systems typically report errors using plain
+ * integers. Module Errno is created dynamically to map these
+ * operating system errors to Ruby classes, with each error number
+ * generating its own subclass of SystemCallError. As the subclass
+ * is created in module Errno, its name will start
+ * <code>Errno::</code>.
*
- * When the Ruby interpreter interacts with the operating system
- * and receives such an error code (e.g., +2+),
- * it maps the code to a particular Ruby exception class (e.g., +Errno::ENOENT+):
+ * The names of the <code>Errno::</code> classes depend on the
+ * environment in which Ruby runs. On a typical Unix or Windows
+ * platform, there are Errno classes such as Errno::EACCES,
+ * Errno::EAGAIN, Errno::EINTR, and so on.
*
- * File.open('nosuch.txt')
- * # => No such file or directory @ rb_sysopen - nosuch.txt (Errno::ENOENT)
+ * The integer operating system error number corresponding to a
+ * particular error is available as the class constant
+ * <code>Errno::</code><em>error</em><code>::Errno</code>.
*
- * Each such class is:
+ * Errno::EACCES::Errno #=> 13
+ * Errno::EAGAIN::Errno #=> 11
+ * Errno::EINTR::Errno #=> 4
*
- * - A nested class in this module, +Errno+.
- * - A subclass of class SystemCallError.
- * - Associated with an error code.
- *
- * Thus:
- *
- * Errno::ENOENT.superclass # => SystemCallError
- * Errno::ENOENT::Errno # => 2
- *
- * The names of nested classes are returned by method +Errno.constants+:
- *
- * Errno.constants.size # => 158
- * Errno.constants.sort.take(5) # => [:E2BIG, :EACCES, :EADDRINUSE, :EADDRNOTAVAIL, :EADV]
- *
- * As seen above, the error code associated with each class
- * is available as the value of a constant;
- * the value for a particular class may vary among operating systems.
- * If the class is not needed for the particular operating system,
- * the value is zero:
- *
- * Errno::ENOENT::Errno # => 2
- * Errno::ENOTCAPABLE::Errno # => 0
+ * The full list of operating system errors on your particular platform
+ * are available as the constants of Errno.
*
+ * Errno.constants #=> :E2BIG, :EACCES, :EADDRINUSE, :EADDRNOTAVAIL, ...
*/
static st_table *syserr_tbl;
-void
-rb_free_warning(void)
-{
- st_free_table(warning_categories.id2enum);
- st_free_table(warning_categories.enum2id);
- st_free_table(syserr_tbl);
-}
-
static VALUE
-setup_syserr(int n, const char *name)
+set_syserr(int n, const char *name)
{
- VALUE error = rb_define_class_under(rb_mErrno, name, rb_eSystemCallError);
+ st_data_t error;
+
+ if (!st_lookup(syserr_tbl, n, &error)) {
+ error = rb_define_class_under(rb_mErrno, name, rb_eSystemCallError);
- /* capture nonblock errnos for WaitReadable/WaitWritable subclasses */
- switch (n) {
- case EAGAIN:
- rb_eEAGAIN = error;
+ /* capture nonblock errnos for WaitReadable/WaitWritable subclasses */
+ switch (n) {
+ case EAGAIN:
+ rb_eEAGAIN = error;
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
- break;
- case EWOULDBLOCK:
+ break;
+ case EWOULDBLOCK:
#endif
- rb_eEWOULDBLOCK = error;
- break;
- case EINPROGRESS:
- rb_eEINPROGRESS = error;
- break;
- }
-
- rb_define_const(error, "Errno", INT2NUM(n));
- st_add_direct(syserr_tbl, n, (st_data_t)error);
- return error;
-}
-
-static VALUE
-set_syserr(int n, const char *name)
-{
- st_data_t error;
+ rb_eEWOULDBLOCK = error;
+ break;
+ case EINPROGRESS:
+ rb_eEINPROGRESS = error;
+ break;
+ }
- if (!st_lookup(syserr_tbl, n, &error)) {
- return setup_syserr(n, name);
+ rb_define_const(error, "Errno", INT2NUM(n));
+ st_add_direct(syserr_tbl, n, error);
}
else {
- VALUE errclass = (VALUE)error;
- rb_define_const(rb_mErrno, name, errclass);
- return errclass;
+ rb_define_const(rb_mErrno, name, error);
}
+ return error;
}
static VALUE
@@ -2948,12 +2440,12 @@ get_syserr(int n)
st_data_t error;
if (!st_lookup(syserr_tbl, n, &error)) {
- char name[DECIMAL_SIZE_OF(n) + sizeof("E-")];
+ char name[8]; /* some Windows' errno have 5 digits. */
snprintf(name, sizeof(name), "E%03d", n);
- return setup_syserr(n, name);
+ error = set_syserr(n, name);
}
- return (VALUE)error;
+ return error;
}
/*
@@ -3267,7 +2759,7 @@ syserr_eqq(VALUE self, VALUE exc)
*
* <em>raises the exception:</em>
*
- * NoMethodError: undefined method `to_ary' for an instance of String
+ * NoMethodError: undefined method `to_ary' for "hello":String
*/
/*
@@ -3340,7 +2832,7 @@ syserr_eqq(VALUE self, VALUE exc)
/*
* Document-class: fatal
*
- * +fatal+ is an Exception that is raised when Ruby has encountered a fatal
+ * fatal is an Exception that is raised when Ruby has encountered a fatal
* error and must exit.
*/
@@ -3352,30 +2844,66 @@ syserr_eqq(VALUE self, VALUE exc)
/*
* Document-class: Exception
*
- * \Class +Exception+ and its subclasses are used to indicate that an error
- * or other problem has occurred,
- * and may need to be handled.
- * See {Exceptions}[rdoc-ref:exceptions.md].
+ * \Class Exception and its subclasses are used to communicate between
+ * Kernel#raise and +rescue+ statements in <code>begin ... end</code> blocks.
*
- * An +Exception+ object carries certain information:
+ * An Exception object carries information about an exception:
+ * - Its type (the exception's class).
+ * - An optional descriptive message.
+ * - Optional backtrace information.
*
- * - The type (the exception's class),
- * commonly StandardError, RuntimeError, or a subclass of one or the other;
- * see {Built-In Exception Class Hierarchy}[rdoc-ref:Exception@Built-In+Exception+Class+Hierarchy].
- * - An optional descriptive message;
- * see methods ::new, #message.
- * - Optional backtrace information;
- * see methods #backtrace, #backtrace_locations, #set_backtrace.
- * - An optional cause;
- * see method #cause.
+ * Some built-in subclasses of Exception have additional methods: e.g., NameError#name.
*
- * == Built-In \Exception \Class Hierarchy
+ * == Defaults
*
- * The hierarchy of built-in subclasses of class +Exception+:
+ * Two Ruby statements have default exception classes:
+ * - +raise+: defaults to RuntimeError.
+ * - +rescue+: defaults to StandardError.
+ *
+ * == Global Variables
+ *
+ * When an exception has been raised but not yet handled (in +rescue+,
+ * +ensure+, +at_exit+ and +END+ blocks), two global variables are set:
+ * - <code>$!</code> contains the current exception.
+ * - <code>$@</code> contains its backtrace.
+ *
+ * == Custom Exceptions
+ *
+ * To provide additional or alternate information,
+ * a program may create custom exception classes
+ * that derive from the built-in exception classes.
+ *
+ * A good practice is for a library to create a single "generic" exception class
+ * (typically a subclass of StandardError or RuntimeError)
+ * and have its other exception classes derive from that class.
+ * This allows the user to rescue the generic exception, thus catching all exceptions
+ * the library may raise even if future versions of the library add new
+ * exception subclasses.
+ *
+ * For example:
+ *
+ * class MyLibrary
+ * class Error < ::StandardError
+ * end
+ *
+ * class WidgetError < Error
+ * end
+ *
+ * class FrobError < Error
+ * end
+ *
+ * end
+ *
+ * To handle both MyLibrary::WidgetError and MyLibrary::FrobError the library
+ * user can rescue MyLibrary::Error.
+ *
+ * == Built-In Exception Classes
+ *
+ * The built-in subclasses of Exception are:
*
* * NoMemoryError
* * ScriptError
- * * {LoadError}[https://docs.ruby-lang.org/en/master/LoadError.html]
+ * * LoadError
* * NotImplementedError
* * SyntaxError
* * SecurityError
@@ -3401,14 +2929,13 @@ syserr_eqq(VALUE self, VALUE exc)
* * RuntimeError
* * FrozenError
* * SystemCallError
- * * Errno (and its subclasses, representing system errors)
+ * * Errno::*
* * ThreadError
* * TypeError
* * ZeroDivisionError
* * SystemExit
* * SystemStackError
- * * {fatal}[https://docs.ruby-lang.org/en/master/fatal.html]
- *
+ * * fatal
*/
static VALUE
@@ -3428,9 +2955,9 @@ exception_dumper(VALUE exc)
}
static int
-ivar_copy_i(ID key, VALUE val, st_data_t exc)
+ivar_copy_i(st_data_t key, st_data_t val, st_data_t exc)
{
- rb_ivar_set((VALUE)exc, key, val);
+ rb_ivar_set((VALUE) exc, (ID) key, (VALUE) val);
return ST_CONTINUE;
}
@@ -3507,11 +3034,11 @@ Init_Exception(void)
* and will render `idPath` as an attribute name without this trick */
ID path = idPath;
- /* the path that failed to parse */
+ /* the path failed to parse */
rb_attr(rb_eSyntaxError, path, TRUE, FALSE, FALSE);
rb_eLoadError = rb_define_class("LoadError", rb_eScriptError);
- /* the path that failed to load */
+ /* the path failed to load */
rb_attr(rb_eLoadError, path, TRUE, FALSE, FALSE);
rb_eNotImpError = rb_define_class("NotImplementedError", rb_eScriptError);
@@ -3558,7 +3085,6 @@ Init_Exception(void)
rb_mWarning = rb_define_module("Warning");
rb_define_singleton_method(rb_mWarning, "[]", rb_warning_s_aref, 1);
rb_define_singleton_method(rb_mWarning, "[]=", rb_warning_s_aset, 2);
- rb_define_singleton_method(rb_mWarning, "categories", rb_warning_s_categories, 0);
rb_define_method(rb_mWarning, "warn", rb_warning_s_warn, -1);
rb_extend_object(rb_mWarning, rb_mWarning);
@@ -3583,7 +3109,6 @@ Init_Exception(void)
id_category = rb_intern_const("category");
id_deprecated = rb_intern_const("deprecated");
id_experimental = rb_intern_const("experimental");
- id_performance = rb_intern_const("performance");
id_top = rb_intern_const("top");
id_bottom = rb_intern_const("bottom");
id_iseq = rb_make_internal_id();
@@ -3595,13 +3120,11 @@ Init_Exception(void)
warning_categories.id2enum = rb_init_identtable();
st_add_direct(warning_categories.id2enum, id_deprecated, RB_WARN_CATEGORY_DEPRECATED);
st_add_direct(warning_categories.id2enum, id_experimental, RB_WARN_CATEGORY_EXPERIMENTAL);
- st_add_direct(warning_categories.id2enum, id_performance, RB_WARN_CATEGORY_PERFORMANCE);
warning_categories.enum2id = rb_init_identtable();
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_NONE, 0);
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_DEPRECATED, id_deprecated);
st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_EXPERIMENTAL, id_experimental);
- st_add_direct(warning_categories.enum2id, RB_WARN_CATEGORY_PERFORMANCE, id_performance);
}
void
@@ -3684,7 +3207,7 @@ rb_fatal(const char *fmt, ...)
/* The thread has no GVL. Object allocation impossible (cant run GC),
* thus no message can be printed out. */
fprintf(stderr, "[FATAL] rb_fatal() outside of GVL\n");
- rb_print_backtrace(stderr);
+ rb_print_backtrace();
die();
}
@@ -3747,14 +3270,12 @@ rb_syserr_fail_str(int e, VALUE mesg)
rb_exc_raise(rb_syserr_new_str(e, mesg));
}
-#undef rb_sys_fail
void
rb_sys_fail(const char *mesg)
{
rb_exc_raise(make_errno_exc(mesg));
}
-#undef rb_sys_fail_str
void
rb_sys_fail_str(VALUE mesg)
{
@@ -3976,8 +3497,6 @@ inspect_frozen_obj(VALUE obj, VALUE mesg, int recur)
void
rb_error_frozen_object(VALUE frozen_obj)
{
- rb_yjit_lazy_push_frame(GET_EC()->cfp->pc);
-
VALUE debug_info;
const ID created_info = id_debug_created_info;
VALUE mesg = rb_sprintf("can't modify frozen %"PRIsVALUE": ",
@@ -4000,27 +3519,23 @@ rb_error_frozen_object(VALUE frozen_obj)
void
rb_check_frozen(VALUE obj)
{
- rb_check_frozen_inline(obj);
+ rb_check_frozen_internal(obj);
}
void
rb_check_copyable(VALUE obj, VALUE orig)
{
if (!FL_ABLE(obj)) return;
- rb_check_frozen(obj);
+ rb_check_frozen_internal(obj);
if (!FL_ABLE(orig)) return;
}
void
Init_syserr(void)
{
- rb_eNOERROR = setup_syserr(0, "NOERROR");
-#if 0
- /* No error */
- rb_define_const(rb_mErrno, "NOERROR", rb_eNOERROR);
-#endif
+ rb_eNOERROR = set_syserr(0, "NOERROR");
#define defined_error(name, num) set_syserr((num), (name));
-#define undefined_error(name) rb_define_const(rb_mErrno, (name), rb_eNOERROR);
+#define undefined_error(name) set_syserr(0, (name));
#include "known_errors.inc"
#undef defined_error
#undef undefined_error
diff --git a/eval.c b/eval.c
index 7fb9d35903..a61dfb1289 100644
--- a/eval.c
+++ b/eval.c
@@ -18,12 +18,12 @@
#endif
#include "eval_intern.h"
+#include "gc.h"
#include "internal.h"
#include "internal/class.h"
#include "internal/cont.h"
#include "internal/error.h"
#include "internal/eval.h"
-#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/inits.h"
#include "internal/io.h"
@@ -32,7 +32,7 @@
#include "internal/variable.h"
#include "ruby/fiber/scheduler.h"
#include "iseq.h"
-#include "rjit.h"
+#include "mjit.h"
#include "probes.h"
#include "probes_helper.h"
#include "ruby/vm.h"
@@ -70,6 +70,8 @@ ruby_setup(void)
if (GET_VM())
return 0;
+ ruby_init_stack((void *)&state);
+
/*
* Disable THP early before mallocs happen because we want this to
* affect as many future pages as possible for CoW-friendliness
@@ -78,6 +80,7 @@ ruby_setup(void)
prctl(PR_SET_THP_DISABLE, 1, 0, 0, 0);
#endif
Init_BareVM();
+ Init_heap();
rb_vm_encoded_insn_data_table_init();
Init_vm_objects();
@@ -112,9 +115,10 @@ ruby_options(int argc, char **argv)
enum ruby_tag_type state;
void *volatile iseq = 0;
+ ruby_init_stack((void *)&iseq);
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- iseq = ruby_process_options(argc, argv);
+ SAVE_ROOT_JMPBUF(GET_THREAD(), iseq = ruby_process_options(argc, argv));
}
else {
rb_ec_clear_current_thread_trace_func(ec);
@@ -161,7 +165,7 @@ rb_ec_finalize(rb_execution_context_t *ec)
{
ruby_sig_finalize();
ec->errinfo = Qnil;
- rb_objspace_call_finalizer();
+ rb_objspace_call_finalizer(rb_ec_vm_ptr(ec)->objspace);
}
void
@@ -196,15 +200,16 @@ rb_ec_cleanup(rb_execution_context_t *ec, enum ruby_tag_type ex)
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- RUBY_VM_CHECK_INTS(ec);
+ SAVE_ROOT_JMPBUF(th, { RUBY_VM_CHECK_INTS(ec); });
step_0: step++;
save_error = ec->errinfo;
if (THROW_DATA_P(ec->errinfo)) ec->errinfo = Qnil;
+ ruby_init_stack(&message);
/* exits with failure but silently when an exception raised
* here */
- rb_ec_teardown(ec);
+ SAVE_ROOT_JMPBUF(th, rb_ec_teardown(ec));
step_1: step++;
VALUE err = ec->errinfo;
@@ -222,7 +227,7 @@ rb_ec_cleanup(rb_execution_context_t *ec, enum ruby_tag_type ex)
mode1 = exiting_split(err, (mode0 & EXITING_WITH_STATUS) ? NULL : &sysex, &signaled);
if (mode1 & EXITING_WITH_MESSAGE) {
buf = rb_str_new(NULL, 0);
- rb_ec_error_print_detailed(ec, err, buf, Qundef);
+ SAVE_ROOT_JMPBUF(th, rb_ec_error_print_detailed(ec, err, buf, Qundef));
message = buf;
}
}
@@ -231,7 +236,7 @@ rb_ec_cleanup(rb_execution_context_t *ec, enum ruby_tag_type ex)
/* protect from Thread#raise */
th->status = THREAD_KILLED;
- rb_ractor_terminate_all();
+ SAVE_ROOT_JMPBUF(th, rb_ractor_terminate_all());
step_3: step++;
if (!NIL_P(buf = message)) {
@@ -252,6 +257,8 @@ rb_ec_cleanup(rb_execution_context_t *ec, enum ruby_tag_type ex)
}
}
+ mjit_finish(true); // We still need ISeqs here, so it's before rb_ec_finalize().
+
rb_ec_finalize(ec);
/* unlock again if finalizer took mutexes. */
@@ -278,7 +285,10 @@ rb_ec_exec_node(rb_execution_context_t *ec, void *n)
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- rb_iseq_eval_main(iseq);
+ rb_thread_t *const th = rb_ec_thread_ptr(ec);
+ SAVE_ROOT_JMPBUF(th, {
+ rb_iseq_eval_main(iseq);
+ });
}
EC_POP_TAG();
return state;
@@ -316,12 +326,14 @@ ruby_run_node(void *n)
rb_ec_cleanup(ec, (NIL_P(ec->errinfo) ? TAG_NONE : TAG_RAISE));
return status;
}
+ ruby_init_stack((void *)&status);
return rb_ec_cleanup(ec, rb_ec_exec_node(ec, n));
}
int
ruby_exec_node(void *n)
{
+ ruby_init_stack((void *)&n);
return rb_ec_exec_node(GET_EC(), n);
}
@@ -409,11 +421,11 @@ rb_mod_s_constants(int argc, VALUE *argv, VALUE mod)
return rb_const_list(data);
}
-/**
- * Asserts that `klass` is not a frozen class.
- * @param[in] klass a `Module` object
- * @exception RuntimeError if `klass` is not a class or frozen.
- * @ingroup class
+/*!
+ * Asserts that \a klass is not a frozen class.
+ * \param[in] klass a \c Module object
+ * \exception RuntimeError if \a klass is not a class or frozen.
+ * \ingroup class
*/
void
rb_class_modify_check(VALUE klass)
@@ -427,9 +439,9 @@ rb_class_modify_check(VALUE klass)
if (OBJ_FROZEN(klass)) {
const char *desc;
- if (RCLASS_SINGLETON_P(klass)) {
+ if (FL_TEST(klass, FL_SINGLETON)) {
desc = "object";
- klass = RCLASS_ATTACHED_OBJECT(klass);
+ klass = rb_ivar_get(klass, id__attached__);
if (!SPECIAL_CONST_P(klass)) {
switch (BUILTIN_TYPE(klass)) {
case T_MODULE:
@@ -462,7 +474,7 @@ rb_class_modify_check(VALUE klass)
}
}
-NORETURN(static void rb_longjmp(rb_execution_context_t *, enum ruby_tag_type, volatile VALUE, VALUE));
+NORETURN(static void rb_longjmp(rb_execution_context_t *, int, volatile VALUE, VALUE));
static VALUE get_errinfo(void);
#define get_ec_errinfo(ec) rb_ec_get_errinfo(ec)
@@ -540,7 +552,7 @@ exc_setup_message(const rb_execution_context_t *ec, VALUE mesg, VALUE *cause)
}
static void
-setup_exception(rb_execution_context_t *ec, enum ruby_tag_type tag, volatile VALUE mesg, VALUE cause)
+setup_exception(rb_execution_context_t *ec, int tag, volatile VALUE mesg, VALUE cause)
{
VALUE e;
int line;
@@ -588,15 +600,15 @@ setup_exception(rb_execution_context_t *ec, enum ruby_tag_type tag, volatile VAL
e = rb_obj_as_string(mesg);
ec->errinfo = mesg;
if (file && line) {
- e = rb_sprintf("Exception '%"PRIsVALUE"' at %s:%d - %"PRIsVALUE"\n",
+ e = rb_sprintf("Exception `%"PRIsVALUE"' at %s:%d - %"PRIsVALUE"\n",
rb_obj_class(mesg), file, line, e);
}
else if (file) {
- e = rb_sprintf("Exception '%"PRIsVALUE"' at %s - %"PRIsVALUE"\n",
+ e = rb_sprintf("Exception `%"PRIsVALUE"' at %s - %"PRIsVALUE"\n",
rb_obj_class(mesg), file, e);
}
else {
- e = rb_sprintf("Exception '%"PRIsVALUE"' - %"PRIsVALUE"\n",
+ e = rb_sprintf("Exception `%"PRIsVALUE"' - %"PRIsVALUE"\n",
rb_obj_class(mesg), e);
}
warn_print_str(e);
@@ -644,7 +656,7 @@ rb_ec_setup_exception(const rb_execution_context_t *ec, VALUE mesg, VALUE cause)
}
static void
-rb_longjmp(rb_execution_context_t *ec, enum ruby_tag_type tag, volatile VALUE mesg, VALUE cause)
+rb_longjmp(rb_execution_context_t *ec, int tag, volatile VALUE mesg, VALUE cause)
{
mesg = exc_setup_message(ec, mesg, &cause);
setup_exception(ec, tag, mesg, cause);
@@ -654,10 +666,10 @@ rb_longjmp(rb_execution_context_t *ec, enum ruby_tag_type tag, volatile VALUE me
static VALUE make_exception(int argc, const VALUE *argv, int isstr);
-NORETURN(static void rb_exc_exception(VALUE mesg, enum ruby_tag_type tag, VALUE cause));
+NORETURN(static void rb_exc_exception(VALUE mesg, int tag, VALUE cause));
static void
-rb_exc_exception(VALUE mesg, enum ruby_tag_type tag, VALUE cause)
+rb_exc_exception(VALUE mesg, int tag, VALUE cause)
{
if (!NIL_P(mesg)) {
mesg = make_exception(1, &mesg, FALSE);
@@ -665,12 +677,12 @@ rb_exc_exception(VALUE mesg, enum ruby_tag_type tag, VALUE cause)
rb_longjmp(GET_EC(), tag, mesg, cause);
}
-/**
+/*!
* Raises an exception in the current thread.
- * @param[in] mesg an Exception class or an `Exception` object.
- * @exception always raises an instance of the given exception class or
- * the given `Exception` object.
- * @ingroup exception
+ * \param[in] mesg an Exception class or an \c Exception object.
+ * \exception always raises an instance of the given exception class or
+ * the given \c Exception object.
+ * \ingroup exception
*/
void
rb_exc_raise(VALUE mesg)
@@ -746,91 +758,31 @@ rb_f_raise(int argc, VALUE *argv)
/*
* call-seq:
- * raise(exception, message = exception.to_s, backtrace = nil, cause: $!)
- * raise(message = nil, cause: $!)
- *
- * Raises an exception;
- * see {Exceptions}[rdoc-ref:exceptions.md].
- *
- * Argument +exception+ sets the class of the new exception;
- * it should be class Exception or one of its subclasses
- * (most commonly, RuntimeError or StandardError),
- * or an instance of one of those classes:
- *
- * begin
- * raise(StandardError)
- * rescue => x
- * p x.class
- * end
- * # => StandardError
- *
- * Argument +message+ sets the stored message in the new exception,
- * which may be retrieved by method Exception#message;
- * the message must be
- * a {string-convertible object}[rdoc-ref:implicit_conversion.rdoc@String-Convertible+Objects]
- * or +nil+:
- *
- * begin
- * raise(StandardError, 'Boom')
- * rescue => x
- * p x.message
- * end
- * # => "Boom"
- *
- * If argument +message+ is not given,
- * the message is the exception class name.
- *
- * See {Messages}[rdoc-ref:exceptions.md@Messages].
- *
- * Argument +backtrace+ sets the stored backtrace in the new exception,
- * which may be retrieved by method Exception#backtrace;
- * the backtrace must be an array of strings or +nil+:
- *
- * begin
- * raise(StandardError, 'Boom', %w[foo bar baz])
- * rescue => x
- * p x.backtrace
- * end
- * # => ["foo", "bar", "baz"]
- *
- * If argument +backtrace+ is not given,
- * the backtrace is set according to an array of Thread::Backtrace::Location objects,
- * as derived from the call stack.
- *
- * See {Backtraces}[rdoc-ref:exceptions.md@Backtraces].
- *
- * Keyword argument +cause+ sets the stored cause in the new exception,
- * which may be retrieved by method Exception#cause;
- * the cause must be an exception object (Exception or one of its subclasses),
- * or +nil+:
- *
- * begin
- * raise(StandardError, cause: RuntimeError.new)
- * rescue => x
- * p x.cause
- * end
- * # => #<RuntimeError: RuntimeError>
- *
- * If keyword argument +cause+ is not given,
- * the cause is the value of <tt>$!</tt>.
- *
- * See {Cause}[rdoc-ref:exceptions.md@Cause].
- *
- * In the alternate calling sequence,
- * where argument +exception+ _not_ given,
- * raises a new exception of the class given by <tt>$!</tt>,
- * or of class RuntimeError if <tt>$!</tt> is +nil+:
- *
- * begin
- * raise
- * rescue => x
- * p x
- * end
- * # => RuntimeError
- *
- * With argument +exception+ not given,
- * argument +message+ and keyword argument +cause+ may be given,
- * but argument +backtrace+ may not be given.
+ * raise
+ * raise(string, cause: $!)
+ * raise(exception [, string [, array]], cause: $!)
+ * fail
+ * fail(string, cause: $!)
+ * fail(exception [, string [, array]], cause: $!)
+ *
+ * With no arguments, raises the exception in <code>$!</code> or raises
+ * a RuntimeError if <code>$!</code> is +nil+. With a single +String+
+ * argument, raises a +RuntimeError+ with the string as a message. Otherwise,
+ * the first parameter should be an +Exception+ class (or another
+ * object that returns an +Exception+ object when sent an +exception+
+ * message). The optional second parameter sets the message associated with
+ * the exception (accessible via Exception#message), and the third parameter
+ * is an array of callback information (accessible via Exception#backtrace).
+ * The +cause+ of the generated exception (accessible via Exception#cause)
+ * is automatically set to the "current" exception (<code>$!</code>), if any.
+ * An alternative value, either an +Exception+ object or +nil+, can be
+ * specified via the +:cause+ argument.
+ *
+ * Exceptions are caught by the +rescue+ clause of
+ * <code>begin...end</code> blocks.
+ *
+ * raise "Failed to create socket"
+ * raise ArgumentError, "No parameters", caller
*/
static VALUE
@@ -1030,7 +982,7 @@ rb_protect(VALUE (* proc) (VALUE), VALUE data, int *pstate)
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- result = (*proc)(data);
+ SAVE_ROOT_JMPBUF(rb_ec_thread_ptr(ec), result = (*proc) (data));
}
else {
rb_vm_rewind_cfp(ec, cfp);
@@ -1044,10 +996,16 @@ rb_protect(VALUE (* proc) (VALUE), VALUE data, int *pstate)
VALUE
rb_ensure(VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE data2)
{
- enum ruby_tag_type state;
+ int state;
volatile VALUE result = Qnil;
VALUE errinfo;
rb_execution_context_t * volatile ec = GET_EC();
+ rb_ensure_list_t ensure_list;
+ ensure_list.entry.marker = 0;
+ ensure_list.entry.e_proc = e_proc;
+ ensure_list.entry.data2 = data2;
+ ensure_list.next = ec->ensure_list;
+ ec->ensure_list = &ensure_list;
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
result = (*b_proc) (data1);
@@ -1057,7 +1015,8 @@ rb_ensure(VALUE (*b_proc)(VALUE), VALUE data1, VALUE (*e_proc)(VALUE), VALUE dat
if (!NIL_P(errinfo) && !RB_TYPE_P(errinfo, T_OBJECT)) {
ec->errinfo = Qnil;
}
- (*e_proc)(data2);
+ ec->ensure_list=ensure_list.next;
+ (*ensure_list.entry.e_proc)(ensure_list.entry.data2);
ec->errinfo = errinfo;
if (state)
EC_JUMP_TAG(ec, state);
@@ -1328,6 +1287,12 @@ rb_using_refinement(rb_cref_t *cref, VALUE klass, VALUE module)
RCLASS_M_TBL(c) = RCLASS_M_TBL(module);
+ module = RCLASS_SUPER(module);
+ while (module && module != klass) {
+ c = RCLASS_SET_SUPER(c, rb_include_class_new(module, RCLASS_SUPER(c)));
+ RB_OBJ_WRITE(c, &RCLASS_REFINED_CLASS(c), klass);
+ module = RCLASS_SUPER(module);
+ }
rb_hash_aset(CREF_REFINEMENTS(cref), klass, iclass);
}
@@ -1378,21 +1343,14 @@ rb_using_module(const rb_cref_t *cref, VALUE module)
{
Check_Type(module, T_MODULE);
using_module_recursive(cref, module);
- rb_clear_all_refinement_method_cache();
+ rb_clear_method_cache_all();
}
/*
* call-seq:
- * target -> class_or_module
- *
- * Return the class or module refined by the receiver.
- *
- * module M
- * refine String do
- * end
- * end
+ * refined_class -> class
*
- * M.refinements[0].target # => String
+ * Return the class refined by the receiver.
*/
VALUE
rb_refinement_module_get_refined_class(VALUE module)
@@ -1403,21 +1361,6 @@ rb_refinement_module_get_refined_class(VALUE module)
return rb_attr_get(module, id_refined_class);
}
-/*
- * call-seq:
- * refined_class -> class
- *
- * Deprecated; prefer #target.
- *
- * Return the class refined by the receiver.
- */
-static VALUE
-rb_refinement_refined_class(VALUE module)
-{
- rb_warn_deprecated_to_remove("3.4", "Refinement#refined_class", "Refinement#target");
- return rb_refinement_module_get_refined_class(module);
-}
-
static void
add_activated_refinement(VALUE activated_refinements,
VALUE klass, VALUE refinement)
@@ -1547,7 +1490,7 @@ mod_using(VALUE self, VALUE module)
* call-seq:
* refinements -> array
*
- * Returns an array of +Refinement+ defined within the receiver.
+ * Returns an array of modules defined within the receiver.
*
* module A
* refine Integer do
@@ -1870,7 +1813,7 @@ top_include(int argc, VALUE *argv, VALUE self)
static VALUE
top_using(VALUE self, VALUE module)
{
- const rb_cref_t *cref = CREF_NEXT(rb_vm_cref());
+ const rb_cref_t *cref = CREF_NEXT(rb_vm_cref());;
rb_control_frame_t *prev_cfp = previous_frame(GET_EC());
rb_thread_t *th = GET_THREAD();
@@ -2063,7 +2006,7 @@ f_global_variables(VALUE _)
* +Proc+ object) or block is executed whenever the variable
* is assigned. The block or +Proc+ object receives the
* variable's new value as a parameter. Also see
- * #untrace_var.
+ * Kernel::untrace_var.
*
* trace_var :$_, proc {|v| puts "$_ is now '#{v}'" }
* $_ = "hello"
@@ -2130,8 +2073,7 @@ Init_eval(void)
rb_mod_s_used_refinements, 0);
rb_undef_method(rb_cClass, "refine");
rb_define_private_method(rb_cRefinement, "import_methods", refinement_import_methods, -1);
- rb_define_method(rb_cRefinement, "target", rb_refinement_module_get_refined_class, 0);
- rb_define_method(rb_cRefinement, "refined_class", rb_refinement_refined_class, 0);
+ rb_define_method(rb_cRefinement, "refined_class", rb_refinement_module_get_refined_class, 0);
rb_undef_method(rb_cRefinement, "append_features");
rb_undef_method(rb_cRefinement, "prepend_features");
rb_undef_method(rb_cRefinement, "extend_object");
@@ -2160,21 +2102,3 @@ Init_eval(void)
id_signo = rb_intern_const("signo");
id_status = rb_intern_const("status");
}
-
-int
-rb_errno(void)
-{
- return *rb_orig_errno_ptr();
-}
-
-void
-rb_errno_set(int e)
-{
- *rb_orig_errno_ptr() = e;
-}
-
-int *
-rb_errno_ptr(void)
-{
- return rb_orig_errno_ptr();
-}
diff --git a/eval_error.c b/eval_error.c
index f3d05a1043..9806683000 100644
--- a/eval_error.c
+++ b/eval_error.c
@@ -7,8 +7,6 @@
(NIL_P(str) ? warn_print(x) : (void)rb_str_cat_cstr(str, x))
#define write_warn2(str, x, l) \
(NIL_P(str) ? warn_print2(x, l) : (void)rb_str_cat(str, x, l))
-#define write_warn_enc(str, x, l, enc) \
- (NIL_P(str) ? warn_print2(x, l) : (void)rb_enc_str_buf_cat(str, x, l, enc))
#ifdef HAVE_BUILTIN___BUILTIN_CONSTANT_P
#define warn_print(x) RB_GNUC_EXTENSION_BLOCK( \
(__builtin_constant_p(x)) ? \
@@ -47,7 +45,7 @@ error_pos_str(void)
return rb_sprintf("%"PRIsVALUE": ", sourcefile);
}
else if ((caller_name = rb_frame_callee()) != 0) {
- return rb_sprintf("%"PRIsVALUE":%d:in '%"PRIsVALUE"': ",
+ return rb_sprintf("%"PRIsVALUE":%d:in `%"PRIsVALUE"': ",
sourcefile, sourceline,
rb_id2str(caller_name));
}
@@ -105,7 +103,7 @@ print_errinfo(const VALUE eclass, const VALUE errat, const VALUE emesg, const VA
if (highlight) write_warn(str, underline);
write_warn(str, "unhandled exception");
if (highlight) write_warn(str, reset);
- write_warn(str, "\n");
+ write_warn2(str, "\n", 1);
}
else {
VALUE epath;
@@ -125,21 +123,17 @@ print_errinfo(const VALUE eclass, const VALUE errat, const VALUE emesg, const VA
}
VALUE
-rb_decorate_message(const VALUE eclass, VALUE emesg, int highlight)
+rb_decorate_message(const VALUE eclass, const VALUE emesg, int highlight)
{
const char *einfo = "";
long elen = 0;
- rb_encoding *eenc;
- VALUE str = rb_usascii_str_new_cstr("");
+ VALUE str = rb_str_new2("");
- if (!NIL_P(emesg) && rb_enc_asciicompat(eenc = rb_enc_get(emesg))) {
+ if (!NIL_P(emesg)) {
einfo = RSTRING_PTR(emesg);
elen = RSTRING_LEN(emesg);
}
- else {
- eenc = NULL;
- }
if (eclass == rb_eRuntimeError && elen == 0) {
if (highlight) write_warn(str, underline);
write_warn(str, "unhandled exception");
@@ -162,7 +156,7 @@ rb_decorate_message(const VALUE eclass, VALUE emesg, int highlight)
if (RSTRING_PTR(epath)[0] == '#')
epath = 0;
if ((tail = memchr(einfo, '\n', elen)) != 0) {
- write_warn_enc(str, einfo, tail - einfo, eenc);
+ write_warn2(str, einfo, tail - einfo);
tail++; /* skip newline */
}
else {
@@ -176,23 +170,23 @@ rb_decorate_message(const VALUE eclass, VALUE emesg, int highlight)
write_warn(str, reset);
write_warn(str, bold);
}
- write_warn(str, ")");
+ write_warn2(str, ")", 1);
if (highlight) write_warn(str, reset);
}
if (tail && einfo+elen > tail) {
if (!highlight) {
- write_warn(str, "\n");
- write_warn_enc(str, tail, einfo+elen-tail, eenc);
+ write_warn2(str, "\n", 1);
+ write_warn2(str, tail, einfo+elen-tail);
}
else {
elen -= tail - einfo;
einfo = tail;
- write_warn(str, "\n");
+ write_warn2(str, "\n", 1);
while (elen > 0) {
tail = memchr(einfo, '\n', elen);
if (!tail || tail > einfo) {
write_warn(str, bold);
- write_warn_enc(str, einfo, tail ? tail-einfo : elen, eenc);
+ write_warn2(str, einfo, tail ? tail-einfo : elen);
write_warn(str, reset);
if (!tail) {
break;
@@ -201,7 +195,7 @@ rb_decorate_message(const VALUE eclass, VALUE emesg, int highlight)
elen -= tail - einfo;
einfo = tail;
do ++tail; while (tail < einfo+elen && *tail == '\n');
- write_warn_enc(str, einfo, tail-einfo, eenc);
+ write_warn2(str, einfo, tail-einfo);
elen -= tail - einfo;
einfo = tail;
}
@@ -210,8 +204,6 @@ rb_decorate_message(const VALUE eclass, VALUE emesg, int highlight)
}
}
- RB_GC_GUARD(emesg);
-
return str;
}
@@ -392,7 +384,7 @@ rb_ec_error_print(rb_execution_context_t *volatile ec, volatile VALUE errinfo)
rb_ec_error_print_detailed(ec, errinfo, Qnil, Qundef);
}
-#define undef_mesg_for(v, k) rb_fstring_lit("undefined"v" method '%1$s' for "k" '%2$s'")
+#define undef_mesg_for(v, k) rb_fstring_lit("undefined"v" method `%1$s' for "k" `%2$s'")
#define undef_mesg(v) ( \
is_mod ? \
undef_mesg_for(v, "module") : \
@@ -420,7 +412,7 @@ rb_print_undef_str(VALUE klass, VALUE name)
rb_name_err_raise_str(undef_mesg(""), klass, name);
}
-#define inaccessible_mesg_for(v, k) rb_fstring_lit("method '%1$s' for "k" '%2$s' is "v)
+#define inaccessible_mesg_for(v, k) rb_fstring_lit("method `%1$s' for "k" `%2$s' is "v)
#define inaccessible_mesg(v) ( \
is_mod ? \
inaccessible_mesg_for(v, "module") : \
diff --git a/eval_intern.h b/eval_intern.h
index 9a551120ff..6cbaa51361 100644
--- a/eval_intern.h
+++ b/eval_intern.h
@@ -95,6 +95,14 @@ extern int select_large_fdset(int, fd_set *, fd_set *, fd_set *, struct timeval
#include <sys/stat.h>
+
+#define SAVE_ROOT_JMPBUF(th, stmt) do \
+ if (true) { \
+ stmt; \
+ } \
+ else if (th) { /* suppress unused-variable warning */ \
+ } while (0)
+
#define EC_PUSH_TAG(ec) do { \
rb_execution_context_t * const _ec = (ec); \
struct rb_vm_tag _tag; \
@@ -102,11 +110,9 @@ extern int select_large_fdset(int, fd_set *, fd_set *, fd_set *, struct timeval
_tag.tag = Qundef; \
_tag.prev = _ec->tag; \
_tag.lock_rec = rb_ec_vm_lock_rec(_ec); \
- rb_vm_tag_jmpbuf_init(&_tag.buf); \
#define EC_POP_TAG() \
_ec->tag = _tag.prev; \
- rb_vm_tag_jmpbuf_deinit(&_tag.buf); \
} while (0)
#define EC_TMPPOP_TAG() \
@@ -145,8 +151,6 @@ rb_ec_tag_state(const rb_execution_context_t *ec)
enum ruby_tag_type state = tag->state;
tag->state = TAG_NONE;
rb_ec_vm_lock_rec_check(ec, tag->lock_rec);
- RBIMPL_ASSUME(state > TAG_NONE);
- RBIMPL_ASSUME(state <= TAG_FATAL);
return state;
}
@@ -154,9 +158,8 @@ NORETURN(static inline void rb_ec_tag_jump(const rb_execution_context_t *ec, enu
static inline void
rb_ec_tag_jump(const rb_execution_context_t *ec, enum ruby_tag_type st)
{
- RUBY_ASSERT(st > TAG_NONE && st <= TAG_FATAL, ": Invalid tag jump: %d", (int)st);
ec->tag->state = st;
- ruby_longjmp(RB_VM_TAG_JMPBUF_GET(ec->tag->buf), 1);
+ ruby_longjmp(ec->tag->buf, 1);
}
/*
@@ -164,7 +167,7 @@ rb_ec_tag_jump(const rb_execution_context_t *ec, enum ruby_tag_type st)
[ISO/IEC 9899:1999] 7.13.1.1
*/
#define EC_EXEC_TAG() \
- (UNLIKELY(ruby_setjmp(RB_VM_TAG_JMPBUF_GET(_tag.buf))) ? rb_ec_tag_state(VAR_FROM_MEMORY(_ec)) : (EC_REPUSH_TAG(), 0))
+ (ruby_setjmp(_tag.buf) ? rb_ec_tag_state(VAR_FROM_MEMORY(_ec)) : (EC_REPUSH_TAG(), 0))
#define EC_JUMP_TAG(ec, st) rb_ec_tag_jump(ec, st)
@@ -290,9 +293,9 @@ NORETURN(void rb_print_undef(VALUE, ID, rb_method_visibility_t));
NORETURN(void rb_print_undef_str(VALUE, VALUE));
NORETURN(void rb_print_inaccessible(VALUE, ID, rb_method_visibility_t));
NORETURN(void rb_vm_localjump_error(const char *,VALUE, int));
-NORETURN(void rb_vm_jump_tag_but_local_jump(enum ruby_tag_type));
+NORETURN(void rb_vm_jump_tag_but_local_jump(int));
-VALUE rb_vm_make_jump_tag_but_local_jump(enum ruby_tag_type state, VALUE val);
+VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val);
rb_cref_t *rb_vm_cref(void);
rb_cref_t *rb_vm_cref_replace_with_duplicated_cref(void);
VALUE rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg, VALUE block_handler, VALUE filename);
@@ -321,4 +324,16 @@ rb_char_next(const char *p)
# endif
#endif
+#if defined DOSISH || defined __CYGWIN__
+static inline void
+translit_char(char *p, int from, int to)
+{
+ while (*p) {
+ if ((unsigned char)*p == from)
+ *p = to;
+ p = CharNext(p);
+ }
+}
+#endif
+
#endif /* RUBY_EVAL_INTERN_H */
diff --git a/eval_jump.c b/eval_jump.c
index 7593a35e36..e8e74f4e70 100644
--- a/eval_jump.c
+++ b/eval_jump.c
@@ -112,21 +112,21 @@ rb_ec_exec_end_proc(rb_execution_context_t * ec)
{
enum ruby_tag_type state;
volatile VALUE errinfo = ec->errinfo;
- volatile bool finished = false;
-
- while (!finished) {
- EC_PUSH_TAG(ec);
- if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- exec_end_procs_chain(&ephemeral_end_procs, &ec->errinfo);
- exec_end_procs_chain(&end_procs, &ec->errinfo);
- finished = true;
- }
- EC_POP_TAG();
- if (state != TAG_NONE) {
- error_handle(ec, ec->errinfo, state);
- if (!NIL_P(ec->errinfo)) errinfo = ec->errinfo;
- }
+
+ EC_PUSH_TAG(ec);
+ if ((state = EC_EXEC_TAG()) == TAG_NONE) {
+ again:
+ exec_end_procs_chain(&ephemeral_end_procs, &ec->errinfo);
+ exec_end_procs_chain(&end_procs, &ec->errinfo);
+ }
+ else {
+ EC_TMPPOP_TAG();
+ error_handle(ec, ec->errinfo, state);
+ if (!NIL_P(ec->errinfo)) errinfo = ec->errinfo;
+ EC_REPUSH_TAG();
+ goto again;
}
+ EC_POP_TAG();
ec->errinfo = errinfo;
}
diff --git a/ext/-test-/RUBY_ALIGNOF/depend b/ext/-test-/RUBY_ALIGNOF/depend
index 25364e55fb..21ef8c6dd0 100644
--- a/ext/-test-/RUBY_ALIGNOF/depend
+++ b/ext/-test-/RUBY_ALIGNOF/depend
@@ -52,7 +52,6 @@ c.o: $(hdrdir)/ruby/internal/attr/noexcept.h
c.o: $(hdrdir)/ruby/internal/attr/noinline.h
c.o: $(hdrdir)/ruby/internal/attr/nonnull.h
c.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-c.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
c.o: $(hdrdir)/ruby/internal/attr/pure.h
c.o: $(hdrdir)/ruby/internal/attr/restrict.h
c.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ c.o: $(hdrdir)/ruby/internal/intern/enumerator.h
c.o: $(hdrdir)/ruby/internal/intern/error.h
c.o: $(hdrdir)/ruby/internal/intern/eval.h
c.o: $(hdrdir)/ruby/internal/intern/file.h
+c.o: $(hdrdir)/ruby/internal/intern/gc.h
c.o: $(hdrdir)/ruby/internal/intern/hash.h
c.o: $(hdrdir)/ruby/internal/intern/io.h
c.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ c.o: $(hdrdir)/ruby/internal/memory.h
c.o: $(hdrdir)/ruby/internal/method.h
c.o: $(hdrdir)/ruby/internal/module.h
c.o: $(hdrdir)/ruby/internal/newobj.h
+c.o: $(hdrdir)/ruby/internal/rgengc.h
c.o: $(hdrdir)/ruby/internal/scan_args.h
c.o: $(hdrdir)/ruby/internal/special_consts.h
c.o: $(hdrdir)/ruby/internal/static_assert.h
c.o: $(hdrdir)/ruby/internal/stdalign.h
c.o: $(hdrdir)/ruby/internal/stdbool.h
-c.o: $(hdrdir)/ruby/internal/stdckdint.h
c.o: $(hdrdir)/ruby/internal/symbol.h
c.o: $(hdrdir)/ruby/internal/value.h
c.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/arith_seq/beg_len_step/depend b/ext/-test-/arith_seq/beg_len_step/depend
index 702a0037a8..36a2c4c71b 100644
--- a/ext/-test-/arith_seq/beg_len_step/depend
+++ b/ext/-test-/arith_seq/beg_len_step/depend
@@ -51,7 +51,6 @@ beg_len_step.o: $(hdrdir)/ruby/internal/attr/noexcept.h
beg_len_step.o: $(hdrdir)/ruby/internal/attr/noinline.h
beg_len_step.o: $(hdrdir)/ruby/internal/attr/nonnull.h
beg_len_step.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-beg_len_step.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
beg_len_step.o: $(hdrdir)/ruby/internal/attr/pure.h
beg_len_step.o: $(hdrdir)/ruby/internal/attr/restrict.h
beg_len_step.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ beg_len_step.o: $(hdrdir)/ruby/internal/intern/enumerator.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/error.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/eval.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/file.h
+beg_len_step.o: $(hdrdir)/ruby/internal/intern/gc.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/hash.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/io.h
beg_len_step.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,12 +141,12 @@ beg_len_step.o: $(hdrdir)/ruby/internal/memory.h
beg_len_step.o: $(hdrdir)/ruby/internal/method.h
beg_len_step.o: $(hdrdir)/ruby/internal/module.h
beg_len_step.o: $(hdrdir)/ruby/internal/newobj.h
+beg_len_step.o: $(hdrdir)/ruby/internal/rgengc.h
beg_len_step.o: $(hdrdir)/ruby/internal/scan_args.h
beg_len_step.o: $(hdrdir)/ruby/internal/special_consts.h
beg_len_step.o: $(hdrdir)/ruby/internal/static_assert.h
beg_len_step.o: $(hdrdir)/ruby/internal/stdalign.h
beg_len_step.o: $(hdrdir)/ruby/internal/stdbool.h
-beg_len_step.o: $(hdrdir)/ruby/internal/stdckdint.h
beg_len_step.o: $(hdrdir)/ruby/internal/symbol.h
beg_len_step.o: $(hdrdir)/ruby/internal/value.h
beg_len_step.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/arith_seq/extract/depend b/ext/-test-/arith_seq/extract/depend
index fdbd71dfbc..57cbaa9a0c 100644
--- a/ext/-test-/arith_seq/extract/depend
+++ b/ext/-test-/arith_seq/extract/depend
@@ -51,7 +51,6 @@ extract.o: $(hdrdir)/ruby/internal/attr/noexcept.h
extract.o: $(hdrdir)/ruby/internal/attr/noinline.h
extract.o: $(hdrdir)/ruby/internal/attr/nonnull.h
extract.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-extract.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
extract.o: $(hdrdir)/ruby/internal/attr/pure.h
extract.o: $(hdrdir)/ruby/internal/attr/restrict.h
extract.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ extract.o: $(hdrdir)/ruby/internal/intern/enumerator.h
extract.o: $(hdrdir)/ruby/internal/intern/error.h
extract.o: $(hdrdir)/ruby/internal/intern/eval.h
extract.o: $(hdrdir)/ruby/internal/intern/file.h
+extract.o: $(hdrdir)/ruby/internal/intern/gc.h
extract.o: $(hdrdir)/ruby/internal/intern/hash.h
extract.o: $(hdrdir)/ruby/internal/intern/io.h
extract.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,12 +141,12 @@ extract.o: $(hdrdir)/ruby/internal/memory.h
extract.o: $(hdrdir)/ruby/internal/method.h
extract.o: $(hdrdir)/ruby/internal/module.h
extract.o: $(hdrdir)/ruby/internal/newobj.h
+extract.o: $(hdrdir)/ruby/internal/rgengc.h
extract.o: $(hdrdir)/ruby/internal/scan_args.h
extract.o: $(hdrdir)/ruby/internal/special_consts.h
extract.o: $(hdrdir)/ruby/internal/static_assert.h
extract.o: $(hdrdir)/ruby/internal/stdalign.h
extract.o: $(hdrdir)/ruby/internal/stdbool.h
-extract.o: $(hdrdir)/ruby/internal/stdckdint.h
extract.o: $(hdrdir)/ruby/internal/symbol.h
extract.o: $(hdrdir)/ruby/internal/value.h
extract.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/array/concat/depend b/ext/-test-/array/concat/depend
index f2213a42ea..79c833738e 100644
--- a/ext/-test-/array/concat/depend
+++ b/ext/-test-/array/concat/depend
@@ -52,7 +52,6 @@ to_ary_concat.o: $(hdrdir)/ruby/internal/attr/noexcept.h
to_ary_concat.o: $(hdrdir)/ruby/internal/attr/noinline.h
to_ary_concat.o: $(hdrdir)/ruby/internal/attr/nonnull.h
to_ary_concat.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-to_ary_concat.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
to_ary_concat.o: $(hdrdir)/ruby/internal/attr/pure.h
to_ary_concat.o: $(hdrdir)/ruby/internal/attr/restrict.h
to_ary_concat.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ to_ary_concat.o: $(hdrdir)/ruby/internal/intern/enumerator.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/error.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/eval.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/file.h
+to_ary_concat.o: $(hdrdir)/ruby/internal/intern/gc.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/hash.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/io.h
to_ary_concat.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ to_ary_concat.o: $(hdrdir)/ruby/internal/memory.h
to_ary_concat.o: $(hdrdir)/ruby/internal/method.h
to_ary_concat.o: $(hdrdir)/ruby/internal/module.h
to_ary_concat.o: $(hdrdir)/ruby/internal/newobj.h
+to_ary_concat.o: $(hdrdir)/ruby/internal/rgengc.h
to_ary_concat.o: $(hdrdir)/ruby/internal/scan_args.h
to_ary_concat.o: $(hdrdir)/ruby/internal/special_consts.h
to_ary_concat.o: $(hdrdir)/ruby/internal/static_assert.h
to_ary_concat.o: $(hdrdir)/ruby/internal/stdalign.h
to_ary_concat.o: $(hdrdir)/ruby/internal/stdbool.h
-to_ary_concat.o: $(hdrdir)/ruby/internal/stdckdint.h
to_ary_concat.o: $(hdrdir)/ruby/internal/symbol.h
to_ary_concat.o: $(hdrdir)/ruby/internal/value.h
to_ary_concat.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/array/resize/depend b/ext/-test-/array/resize/depend
index f88a9d03c1..49e0f346d3 100644
--- a/ext/-test-/array/resize/depend
+++ b/ext/-test-/array/resize/depend
@@ -51,7 +51,6 @@ resize.o: $(hdrdir)/ruby/internal/attr/noexcept.h
resize.o: $(hdrdir)/ruby/internal/attr/noinline.h
resize.o: $(hdrdir)/ruby/internal/attr/nonnull.h
resize.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-resize.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
resize.o: $(hdrdir)/ruby/internal/attr/pure.h
resize.o: $(hdrdir)/ruby/internal/attr/restrict.h
resize.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ resize.o: $(hdrdir)/ruby/internal/intern/enumerator.h
resize.o: $(hdrdir)/ruby/internal/intern/error.h
resize.o: $(hdrdir)/ruby/internal/intern/eval.h
resize.o: $(hdrdir)/ruby/internal/intern/file.h
+resize.o: $(hdrdir)/ruby/internal/intern/gc.h
resize.o: $(hdrdir)/ruby/internal/intern/hash.h
resize.o: $(hdrdir)/ruby/internal/intern/io.h
resize.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,12 +141,12 @@ resize.o: $(hdrdir)/ruby/internal/memory.h
resize.o: $(hdrdir)/ruby/internal/method.h
resize.o: $(hdrdir)/ruby/internal/module.h
resize.o: $(hdrdir)/ruby/internal/newobj.h
+resize.o: $(hdrdir)/ruby/internal/rgengc.h
resize.o: $(hdrdir)/ruby/internal/scan_args.h
resize.o: $(hdrdir)/ruby/internal/special_consts.h
resize.o: $(hdrdir)/ruby/internal/static_assert.h
resize.o: $(hdrdir)/ruby/internal/stdalign.h
resize.o: $(hdrdir)/ruby/internal/stdbool.h
-resize.o: $(hdrdir)/ruby/internal/stdckdint.h
resize.o: $(hdrdir)/ruby/internal/symbol.h
resize.o: $(hdrdir)/ruby/internal/value.h
resize.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/asan/asan.c b/ext/-test-/asan/asan.c
deleted file mode 100644
index 45b6253fda..0000000000
--- a/ext/-test-/asan/asan.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "ruby/ruby.h"
-
-static VALUE
-asan_enabled_p(VALUE self)
-{
-#if defined(__has_feature)
- /* clang uses __has_feature for determining asan */
- return __has_feature(address_sanitizer) ? Qtrue : Qfalse;
-#elif defined(__SANITIZE_ADDRESS__)
- /* GCC sets __SANITIZE_ADDRESS__ for determining asan */
- return Qtrue;
-#else
- return Qfalse;
-#endif
-}
-
-void
-Init_asan(void)
-{
- VALUE m = rb_define_module("Test");
- VALUE c = rb_define_class_under(m, "ASAN", rb_cObject);
- rb_define_singleton_method(c, "enabled?", asan_enabled_p, 0);
-}
-
diff --git a/ext/-test-/asan/extconf.rb b/ext/-test-/asan/extconf.rb
deleted file mode 100644
index ec02742b81..0000000000
--- a/ext/-test-/asan/extconf.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-require 'mkmf'
-create_makefile('-test-/asan')
diff --git a/ext/-test-/bignum/depend b/ext/-test-/bignum/depend
index 078915ab72..d4072fb35c 100644
--- a/ext/-test-/bignum/depend
+++ b/ext/-test-/bignum/depend
@@ -51,7 +51,6 @@ big2str.o: $(hdrdir)/ruby/internal/attr/noexcept.h
big2str.o: $(hdrdir)/ruby/internal/attr/noinline.h
big2str.o: $(hdrdir)/ruby/internal/attr/nonnull.h
big2str.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-big2str.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
big2str.o: $(hdrdir)/ruby/internal/attr/pure.h
big2str.o: $(hdrdir)/ruby/internal/attr/restrict.h
big2str.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ big2str.o: $(hdrdir)/ruby/internal/intern/enumerator.h
big2str.o: $(hdrdir)/ruby/internal/intern/error.h
big2str.o: $(hdrdir)/ruby/internal/intern/eval.h
big2str.o: $(hdrdir)/ruby/internal/intern/file.h
+big2str.o: $(hdrdir)/ruby/internal/intern/gc.h
big2str.o: $(hdrdir)/ruby/internal/intern/hash.h
big2str.o: $(hdrdir)/ruby/internal/intern/io.h
big2str.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,12 +141,12 @@ big2str.o: $(hdrdir)/ruby/internal/memory.h
big2str.o: $(hdrdir)/ruby/internal/method.h
big2str.o: $(hdrdir)/ruby/internal/module.h
big2str.o: $(hdrdir)/ruby/internal/newobj.h
+big2str.o: $(hdrdir)/ruby/internal/rgengc.h
big2str.o: $(hdrdir)/ruby/internal/scan_args.h
big2str.o: $(hdrdir)/ruby/internal/special_consts.h
big2str.o: $(hdrdir)/ruby/internal/static_assert.h
big2str.o: $(hdrdir)/ruby/internal/stdalign.h
big2str.o: $(hdrdir)/ruby/internal/stdbool.h
-big2str.o: $(hdrdir)/ruby/internal/stdckdint.h
big2str.o: $(hdrdir)/ruby/internal/symbol.h
big2str.o: $(hdrdir)/ruby/internal/value.h
big2str.o: $(hdrdir)/ruby/internal/value_type.h
@@ -211,7 +211,6 @@ bigzero.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bigzero.o: $(hdrdir)/ruby/internal/attr/noinline.h
bigzero.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bigzero.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bigzero.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bigzero.o: $(hdrdir)/ruby/internal/attr/pure.h
bigzero.o: $(hdrdir)/ruby/internal/attr/restrict.h
bigzero.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -271,6 +270,7 @@ bigzero.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bigzero.o: $(hdrdir)/ruby/internal/intern/error.h
bigzero.o: $(hdrdir)/ruby/internal/intern/eval.h
bigzero.o: $(hdrdir)/ruby/internal/intern/file.h
+bigzero.o: $(hdrdir)/ruby/internal/intern/gc.h
bigzero.o: $(hdrdir)/ruby/internal/intern/hash.h
bigzero.o: $(hdrdir)/ruby/internal/intern/io.h
bigzero.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -301,12 +301,12 @@ bigzero.o: $(hdrdir)/ruby/internal/memory.h
bigzero.o: $(hdrdir)/ruby/internal/method.h
bigzero.o: $(hdrdir)/ruby/internal/module.h
bigzero.o: $(hdrdir)/ruby/internal/newobj.h
+bigzero.o: $(hdrdir)/ruby/internal/rgengc.h
bigzero.o: $(hdrdir)/ruby/internal/scan_args.h
bigzero.o: $(hdrdir)/ruby/internal/special_consts.h
bigzero.o: $(hdrdir)/ruby/internal/static_assert.h
bigzero.o: $(hdrdir)/ruby/internal/stdalign.h
bigzero.o: $(hdrdir)/ruby/internal/stdbool.h
-bigzero.o: $(hdrdir)/ruby/internal/stdckdint.h
bigzero.o: $(hdrdir)/ruby/internal/symbol.h
bigzero.o: $(hdrdir)/ruby/internal/value.h
bigzero.o: $(hdrdir)/ruby/internal/value_type.h
@@ -371,7 +371,6 @@ div.o: $(hdrdir)/ruby/internal/attr/noexcept.h
div.o: $(hdrdir)/ruby/internal/attr/noinline.h
div.o: $(hdrdir)/ruby/internal/attr/nonnull.h
div.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-div.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
div.o: $(hdrdir)/ruby/internal/attr/pure.h
div.o: $(hdrdir)/ruby/internal/attr/restrict.h
div.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -431,6 +430,7 @@ div.o: $(hdrdir)/ruby/internal/intern/enumerator.h
div.o: $(hdrdir)/ruby/internal/intern/error.h
div.o: $(hdrdir)/ruby/internal/intern/eval.h
div.o: $(hdrdir)/ruby/internal/intern/file.h
+div.o: $(hdrdir)/ruby/internal/intern/gc.h
div.o: $(hdrdir)/ruby/internal/intern/hash.h
div.o: $(hdrdir)/ruby/internal/intern/io.h
div.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -461,12 +461,12 @@ div.o: $(hdrdir)/ruby/internal/memory.h
div.o: $(hdrdir)/ruby/internal/method.h
div.o: $(hdrdir)/ruby/internal/module.h
div.o: $(hdrdir)/ruby/internal/newobj.h
+div.o: $(hdrdir)/ruby/internal/rgengc.h
div.o: $(hdrdir)/ruby/internal/scan_args.h
div.o: $(hdrdir)/ruby/internal/special_consts.h
div.o: $(hdrdir)/ruby/internal/static_assert.h
div.o: $(hdrdir)/ruby/internal/stdalign.h
div.o: $(hdrdir)/ruby/internal/stdbool.h
-div.o: $(hdrdir)/ruby/internal/stdckdint.h
div.o: $(hdrdir)/ruby/internal/symbol.h
div.o: $(hdrdir)/ruby/internal/value.h
div.o: $(hdrdir)/ruby/internal/value_type.h
@@ -532,7 +532,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -592,6 +591,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -622,12 +622,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -691,7 +691,6 @@ intpack.o: $(hdrdir)/ruby/internal/attr/noexcept.h
intpack.o: $(hdrdir)/ruby/internal/attr/noinline.h
intpack.o: $(hdrdir)/ruby/internal/attr/nonnull.h
intpack.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-intpack.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
intpack.o: $(hdrdir)/ruby/internal/attr/pure.h
intpack.o: $(hdrdir)/ruby/internal/attr/restrict.h
intpack.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -751,6 +750,7 @@ intpack.o: $(hdrdir)/ruby/internal/intern/enumerator.h
intpack.o: $(hdrdir)/ruby/internal/intern/error.h
intpack.o: $(hdrdir)/ruby/internal/intern/eval.h
intpack.o: $(hdrdir)/ruby/internal/intern/file.h
+intpack.o: $(hdrdir)/ruby/internal/intern/gc.h
intpack.o: $(hdrdir)/ruby/internal/intern/hash.h
intpack.o: $(hdrdir)/ruby/internal/intern/io.h
intpack.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -781,12 +781,12 @@ intpack.o: $(hdrdir)/ruby/internal/memory.h
intpack.o: $(hdrdir)/ruby/internal/method.h
intpack.o: $(hdrdir)/ruby/internal/module.h
intpack.o: $(hdrdir)/ruby/internal/newobj.h
+intpack.o: $(hdrdir)/ruby/internal/rgengc.h
intpack.o: $(hdrdir)/ruby/internal/scan_args.h
intpack.o: $(hdrdir)/ruby/internal/special_consts.h
intpack.o: $(hdrdir)/ruby/internal/static_assert.h
intpack.o: $(hdrdir)/ruby/internal/stdalign.h
intpack.o: $(hdrdir)/ruby/internal/stdbool.h
-intpack.o: $(hdrdir)/ruby/internal/stdckdint.h
intpack.o: $(hdrdir)/ruby/internal/symbol.h
intpack.o: $(hdrdir)/ruby/internal/value.h
intpack.o: $(hdrdir)/ruby/internal/value_type.h
@@ -851,7 +851,6 @@ mul.o: $(hdrdir)/ruby/internal/attr/noexcept.h
mul.o: $(hdrdir)/ruby/internal/attr/noinline.h
mul.o: $(hdrdir)/ruby/internal/attr/nonnull.h
mul.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-mul.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
mul.o: $(hdrdir)/ruby/internal/attr/pure.h
mul.o: $(hdrdir)/ruby/internal/attr/restrict.h
mul.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -911,6 +910,7 @@ mul.o: $(hdrdir)/ruby/internal/intern/enumerator.h
mul.o: $(hdrdir)/ruby/internal/intern/error.h
mul.o: $(hdrdir)/ruby/internal/intern/eval.h
mul.o: $(hdrdir)/ruby/internal/intern/file.h
+mul.o: $(hdrdir)/ruby/internal/intern/gc.h
mul.o: $(hdrdir)/ruby/internal/intern/hash.h
mul.o: $(hdrdir)/ruby/internal/intern/io.h
mul.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -941,12 +941,12 @@ mul.o: $(hdrdir)/ruby/internal/memory.h
mul.o: $(hdrdir)/ruby/internal/method.h
mul.o: $(hdrdir)/ruby/internal/module.h
mul.o: $(hdrdir)/ruby/internal/newobj.h
+mul.o: $(hdrdir)/ruby/internal/rgengc.h
mul.o: $(hdrdir)/ruby/internal/scan_args.h
mul.o: $(hdrdir)/ruby/internal/special_consts.h
mul.o: $(hdrdir)/ruby/internal/static_assert.h
mul.o: $(hdrdir)/ruby/internal/stdalign.h
mul.o: $(hdrdir)/ruby/internal/stdbool.h
-mul.o: $(hdrdir)/ruby/internal/stdckdint.h
mul.o: $(hdrdir)/ruby/internal/symbol.h
mul.o: $(hdrdir)/ruby/internal/value.h
mul.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1011,7 +1011,6 @@ str2big.o: $(hdrdir)/ruby/internal/attr/noexcept.h
str2big.o: $(hdrdir)/ruby/internal/attr/noinline.h
str2big.o: $(hdrdir)/ruby/internal/attr/nonnull.h
str2big.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-str2big.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
str2big.o: $(hdrdir)/ruby/internal/attr/pure.h
str2big.o: $(hdrdir)/ruby/internal/attr/restrict.h
str2big.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1071,6 +1070,7 @@ str2big.o: $(hdrdir)/ruby/internal/intern/enumerator.h
str2big.o: $(hdrdir)/ruby/internal/intern/error.h
str2big.o: $(hdrdir)/ruby/internal/intern/eval.h
str2big.o: $(hdrdir)/ruby/internal/intern/file.h
+str2big.o: $(hdrdir)/ruby/internal/intern/gc.h
str2big.o: $(hdrdir)/ruby/internal/intern/hash.h
str2big.o: $(hdrdir)/ruby/internal/intern/io.h
str2big.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1101,12 +1101,12 @@ str2big.o: $(hdrdir)/ruby/internal/memory.h
str2big.o: $(hdrdir)/ruby/internal/method.h
str2big.o: $(hdrdir)/ruby/internal/module.h
str2big.o: $(hdrdir)/ruby/internal/newobj.h
+str2big.o: $(hdrdir)/ruby/internal/rgengc.h
str2big.o: $(hdrdir)/ruby/internal/scan_args.h
str2big.o: $(hdrdir)/ruby/internal/special_consts.h
str2big.o: $(hdrdir)/ruby/internal/static_assert.h
str2big.o: $(hdrdir)/ruby/internal/stdalign.h
str2big.o: $(hdrdir)/ruby/internal/stdbool.h
-str2big.o: $(hdrdir)/ruby/internal/stdckdint.h
str2big.o: $(hdrdir)/ruby/internal/symbol.h
str2big.o: $(hdrdir)/ruby/internal/value.h
str2big.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/bug-14834/bug-14384.c b/ext/-test-/bug-14834/bug-14384.c
new file mode 100644
index 0000000000..3a16a2d222
--- /dev/null
+++ b/ext/-test-/bug-14834/bug-14384.c
@@ -0,0 +1,39 @@
+#include <ruby/ruby.h>
+#include <ruby/debug.h>
+
+#ifndef MAYBE_UNUSED
+# define MAYBE_UNUSED(x) x
+#endif
+
+static NOINLINE(VALUE f(VALUE));
+static NOINLINE(void g(VALUE, void*));
+extern NOINLINE(void Init_bug_14384(void));
+
+void
+Init_bug_14834(void)
+{
+ VALUE q = rb_define_module("Bug");
+ rb_define_module_function(q, "bug_14834", f, 0);
+}
+
+VALUE
+f(VALUE q)
+{
+ int w[] = { 0, 1024 };
+ VALUE e = rb_tracepoint_new(Qnil, RUBY_INTERNAL_EVENT_NEWOBJ, g, w);
+
+ rb_tracepoint_enable(e);
+ return rb_ensure(rb_yield, q, rb_tracepoint_disable, e);
+}
+
+void
+g(MAYBE_UNUSED(VALUE q), void* w)
+{
+ const int *e = (const int *)w;
+ const int r = *e++;
+ const int t = *e++;
+ VALUE *y = ALLOCA_N(VALUE, t);
+ int *u = ALLOCA_N(int, t);
+
+ rb_profile_frames(r, t, y, u);
+}
diff --git a/ext/-test-/bug-14834/bug-14834.c b/ext/-test-/bug-14834/bug-14834.c
deleted file mode 100644
index af2070d303..0000000000
--- a/ext/-test-/bug-14834/bug-14834.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include <ruby/ruby.h>
-#include <ruby/debug.h>
-
-#ifndef MAYBE_UNUSED
-# define MAYBE_UNUSED(x) x
-#endif
-
-static NOINLINE(VALUE f(VALUE));
-static NOINLINE(void g(VALUE, void*));
-extern NOINLINE(void Init_bug_14834(void));
-
-void
-Init_bug_14834(void)
-{
- VALUE q = rb_define_module("Bug");
- rb_define_module_function(q, "bug_14834", f, 0);
-}
-
-VALUE
-f(VALUE q)
-{
- int w[] = { 0, 1024 };
- VALUE e = rb_tracepoint_new(Qnil, RUBY_INTERNAL_EVENT_NEWOBJ, g, w);
-
- rb_tracepoint_enable(e);
- return rb_ensure(rb_yield, q, rb_tracepoint_disable, e);
-}
-
-void
-g(MAYBE_UNUSED(VALUE q), void* w)
-{
- const int *e = (const int *)w;
- const int r = *e++;
- const int t = *e++;
- VALUE *y = ALLOCA_N(VALUE, t);
- int *u = ALLOCA_N(int, t);
-
- rb_profile_frames(r, t, y, u);
-}
diff --git a/ext/-test-/bug-14834/depend b/ext/-test-/bug-14834/depend
index 38429918b1..7bac8409e8 100644
--- a/ext/-test-/bug-14834/depend
+++ b/ext/-test-/bug-14834/depend
@@ -1,162 +1,162 @@
# AUTOGENERATED DEPENDENCIES START
-bug-14834.o: $(RUBY_EXTCONF_H)
-bug-14834.o: $(arch_hdrdir)/ruby/config.h
-bug-14834.o: $(hdrdir)/ruby/assert.h
-bug-14834.o: $(hdrdir)/ruby/backward.h
-bug-14834.o: $(hdrdir)/ruby/backward/2/assume.h
-bug-14834.o: $(hdrdir)/ruby/backward/2/attributes.h
-bug-14834.o: $(hdrdir)/ruby/backward/2/bool.h
-bug-14834.o: $(hdrdir)/ruby/backward/2/inttypes.h
-bug-14834.o: $(hdrdir)/ruby/backward/2/limits.h
-bug-14834.o: $(hdrdir)/ruby/backward/2/long_long.h
-bug-14834.o: $(hdrdir)/ruby/backward/2/stdalign.h
-bug-14834.o: $(hdrdir)/ruby/backward/2/stdarg.h
-bug-14834.o: $(hdrdir)/ruby/debug.h
-bug-14834.o: $(hdrdir)/ruby/defines.h
-bug-14834.o: $(hdrdir)/ruby/intern.h
-bug-14834.o: $(hdrdir)/ruby/internal/abi.h
-bug-14834.o: $(hdrdir)/ruby/internal/anyargs.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-bug-14834.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-bug-14834.o: $(hdrdir)/ruby/internal/assume.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/artificial.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/cold.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/const.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/error.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/format.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/noalias.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/noinline.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/pure.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/restrict.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/warning.h
-bug-14834.o: $(hdrdir)/ruby/internal/attr/weakref.h
-bug-14834.o: $(hdrdir)/ruby/internal/cast.h
-bug-14834.o: $(hdrdir)/ruby/internal/compiler_is.h
-bug-14834.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-bug-14834.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-bug-14834.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-bug-14834.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-bug-14834.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-bug-14834.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-bug-14834.o: $(hdrdir)/ruby/internal/compiler_since.h
-bug-14834.o: $(hdrdir)/ruby/internal/config.h
-bug-14834.o: $(hdrdir)/ruby/internal/constant_p.h
-bug-14834.o: $(hdrdir)/ruby/internal/core.h
-bug-14834.o: $(hdrdir)/ruby/internal/core/rarray.h
-bug-14834.o: $(hdrdir)/ruby/internal/core/rbasic.h
-bug-14834.o: $(hdrdir)/ruby/internal/core/rbignum.h
-bug-14834.o: $(hdrdir)/ruby/internal/core/rclass.h
-bug-14834.o: $(hdrdir)/ruby/internal/core/rdata.h
-bug-14834.o: $(hdrdir)/ruby/internal/core/rfile.h
-bug-14834.o: $(hdrdir)/ruby/internal/core/rhash.h
-bug-14834.o: $(hdrdir)/ruby/internal/core/robject.h
-bug-14834.o: $(hdrdir)/ruby/internal/core/rregexp.h
-bug-14834.o: $(hdrdir)/ruby/internal/core/rstring.h
-bug-14834.o: $(hdrdir)/ruby/internal/core/rstruct.h
-bug-14834.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-bug-14834.o: $(hdrdir)/ruby/internal/ctype.h
-bug-14834.o: $(hdrdir)/ruby/internal/dllexport.h
-bug-14834.o: $(hdrdir)/ruby/internal/dosish.h
-bug-14834.o: $(hdrdir)/ruby/internal/error.h
-bug-14834.o: $(hdrdir)/ruby/internal/eval.h
-bug-14834.o: $(hdrdir)/ruby/internal/event.h
-bug-14834.o: $(hdrdir)/ruby/internal/fl_type.h
-bug-14834.o: $(hdrdir)/ruby/internal/gc.h
-bug-14834.o: $(hdrdir)/ruby/internal/glob.h
-bug-14834.o: $(hdrdir)/ruby/internal/globals.h
-bug-14834.o: $(hdrdir)/ruby/internal/has/attribute.h
-bug-14834.o: $(hdrdir)/ruby/internal/has/builtin.h
-bug-14834.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-bug-14834.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-bug-14834.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-bug-14834.o: $(hdrdir)/ruby/internal/has/extension.h
-bug-14834.o: $(hdrdir)/ruby/internal/has/feature.h
-bug-14834.o: $(hdrdir)/ruby/internal/has/warning.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/array.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/bignum.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/class.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/compar.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/complex.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/cont.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/dir.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/enum.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/error.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/eval.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/file.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/hash.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/io.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/load.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/marshal.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/numeric.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/object.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/parse.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/proc.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/process.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/random.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/range.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/rational.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/re.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/ruby.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/select.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/signal.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/string.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/struct.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/thread.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/time.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/variable.h
-bug-14834.o: $(hdrdir)/ruby/internal/intern/vm.h
-bug-14834.o: $(hdrdir)/ruby/internal/interpreter.h
-bug-14834.o: $(hdrdir)/ruby/internal/iterator.h
-bug-14834.o: $(hdrdir)/ruby/internal/memory.h
-bug-14834.o: $(hdrdir)/ruby/internal/method.h
-bug-14834.o: $(hdrdir)/ruby/internal/module.h
-bug-14834.o: $(hdrdir)/ruby/internal/newobj.h
-bug-14834.o: $(hdrdir)/ruby/internal/scan_args.h
-bug-14834.o: $(hdrdir)/ruby/internal/special_consts.h
-bug-14834.o: $(hdrdir)/ruby/internal/static_assert.h
-bug-14834.o: $(hdrdir)/ruby/internal/stdalign.h
-bug-14834.o: $(hdrdir)/ruby/internal/stdbool.h
-bug-14834.o: $(hdrdir)/ruby/internal/stdckdint.h
-bug-14834.o: $(hdrdir)/ruby/internal/symbol.h
-bug-14834.o: $(hdrdir)/ruby/internal/value.h
-bug-14834.o: $(hdrdir)/ruby/internal/value_type.h
-bug-14834.o: $(hdrdir)/ruby/internal/variable.h
-bug-14834.o: $(hdrdir)/ruby/internal/warning_push.h
-bug-14834.o: $(hdrdir)/ruby/internal/xmalloc.h
-bug-14834.o: $(hdrdir)/ruby/missing.h
-bug-14834.o: $(hdrdir)/ruby/ruby.h
-bug-14834.o: $(hdrdir)/ruby/st.h
-bug-14834.o: $(hdrdir)/ruby/subst.h
-bug-14834.o: bug-14834.c
+bug-14384.o: $(RUBY_EXTCONF_H)
+bug-14384.o: $(arch_hdrdir)/ruby/config.h
+bug-14384.o: $(hdrdir)/ruby/assert.h
+bug-14384.o: $(hdrdir)/ruby/backward.h
+bug-14384.o: $(hdrdir)/ruby/backward/2/assume.h
+bug-14384.o: $(hdrdir)/ruby/backward/2/attributes.h
+bug-14384.o: $(hdrdir)/ruby/backward/2/bool.h
+bug-14384.o: $(hdrdir)/ruby/backward/2/inttypes.h
+bug-14384.o: $(hdrdir)/ruby/backward/2/limits.h
+bug-14384.o: $(hdrdir)/ruby/backward/2/long_long.h
+bug-14384.o: $(hdrdir)/ruby/backward/2/stdalign.h
+bug-14384.o: $(hdrdir)/ruby/backward/2/stdarg.h
+bug-14384.o: $(hdrdir)/ruby/debug.h
+bug-14384.o: $(hdrdir)/ruby/defines.h
+bug-14384.o: $(hdrdir)/ruby/intern.h
+bug-14384.o: $(hdrdir)/ruby/internal/abi.h
+bug-14384.o: $(hdrdir)/ruby/internal/anyargs.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+bug-14384.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+bug-14384.o: $(hdrdir)/ruby/internal/assume.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/artificial.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/cold.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/const.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/error.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/format.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/noalias.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/noinline.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/pure.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/restrict.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/warning.h
+bug-14384.o: $(hdrdir)/ruby/internal/attr/weakref.h
+bug-14384.o: $(hdrdir)/ruby/internal/cast.h
+bug-14384.o: $(hdrdir)/ruby/internal/compiler_is.h
+bug-14384.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+bug-14384.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+bug-14384.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+bug-14384.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+bug-14384.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+bug-14384.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+bug-14384.o: $(hdrdir)/ruby/internal/compiler_since.h
+bug-14384.o: $(hdrdir)/ruby/internal/config.h
+bug-14384.o: $(hdrdir)/ruby/internal/constant_p.h
+bug-14384.o: $(hdrdir)/ruby/internal/core.h
+bug-14384.o: $(hdrdir)/ruby/internal/core/rarray.h
+bug-14384.o: $(hdrdir)/ruby/internal/core/rbasic.h
+bug-14384.o: $(hdrdir)/ruby/internal/core/rbignum.h
+bug-14384.o: $(hdrdir)/ruby/internal/core/rclass.h
+bug-14384.o: $(hdrdir)/ruby/internal/core/rdata.h
+bug-14384.o: $(hdrdir)/ruby/internal/core/rfile.h
+bug-14384.o: $(hdrdir)/ruby/internal/core/rhash.h
+bug-14384.o: $(hdrdir)/ruby/internal/core/robject.h
+bug-14384.o: $(hdrdir)/ruby/internal/core/rregexp.h
+bug-14384.o: $(hdrdir)/ruby/internal/core/rstring.h
+bug-14384.o: $(hdrdir)/ruby/internal/core/rstruct.h
+bug-14384.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+bug-14384.o: $(hdrdir)/ruby/internal/ctype.h
+bug-14384.o: $(hdrdir)/ruby/internal/dllexport.h
+bug-14384.o: $(hdrdir)/ruby/internal/dosish.h
+bug-14384.o: $(hdrdir)/ruby/internal/error.h
+bug-14384.o: $(hdrdir)/ruby/internal/eval.h
+bug-14384.o: $(hdrdir)/ruby/internal/event.h
+bug-14384.o: $(hdrdir)/ruby/internal/fl_type.h
+bug-14384.o: $(hdrdir)/ruby/internal/gc.h
+bug-14384.o: $(hdrdir)/ruby/internal/glob.h
+bug-14384.o: $(hdrdir)/ruby/internal/globals.h
+bug-14384.o: $(hdrdir)/ruby/internal/has/attribute.h
+bug-14384.o: $(hdrdir)/ruby/internal/has/builtin.h
+bug-14384.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+bug-14384.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+bug-14384.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+bug-14384.o: $(hdrdir)/ruby/internal/has/extension.h
+bug-14384.o: $(hdrdir)/ruby/internal/has/feature.h
+bug-14384.o: $(hdrdir)/ruby/internal/has/warning.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/array.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/bignum.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/class.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/compar.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/complex.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/cont.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/dir.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/enum.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/error.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/eval.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/file.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/gc.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/hash.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/io.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/load.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/marshal.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/numeric.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/object.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/parse.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/proc.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/process.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/random.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/range.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/rational.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/re.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/ruby.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/select.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/signal.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/string.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/struct.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/thread.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/time.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/variable.h
+bug-14384.o: $(hdrdir)/ruby/internal/intern/vm.h
+bug-14384.o: $(hdrdir)/ruby/internal/interpreter.h
+bug-14384.o: $(hdrdir)/ruby/internal/iterator.h
+bug-14384.o: $(hdrdir)/ruby/internal/memory.h
+bug-14384.o: $(hdrdir)/ruby/internal/method.h
+bug-14384.o: $(hdrdir)/ruby/internal/module.h
+bug-14384.o: $(hdrdir)/ruby/internal/newobj.h
+bug-14384.o: $(hdrdir)/ruby/internal/rgengc.h
+bug-14384.o: $(hdrdir)/ruby/internal/scan_args.h
+bug-14384.o: $(hdrdir)/ruby/internal/special_consts.h
+bug-14384.o: $(hdrdir)/ruby/internal/static_assert.h
+bug-14384.o: $(hdrdir)/ruby/internal/stdalign.h
+bug-14384.o: $(hdrdir)/ruby/internal/stdbool.h
+bug-14384.o: $(hdrdir)/ruby/internal/symbol.h
+bug-14384.o: $(hdrdir)/ruby/internal/value.h
+bug-14384.o: $(hdrdir)/ruby/internal/value_type.h
+bug-14384.o: $(hdrdir)/ruby/internal/variable.h
+bug-14384.o: $(hdrdir)/ruby/internal/warning_push.h
+bug-14384.o: $(hdrdir)/ruby/internal/xmalloc.h
+bug-14384.o: $(hdrdir)/ruby/missing.h
+bug-14384.o: $(hdrdir)/ruby/ruby.h
+bug-14384.o: $(hdrdir)/ruby/st.h
+bug-14384.o: $(hdrdir)/ruby/subst.h
+bug-14384.o: bug-14384.c
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/-test-/bug-3571/depend b/ext/-test-/bug-3571/depend
index 84517a9c15..2303f47594 100644
--- a/ext/-test-/bug-3571/depend
+++ b/ext/-test-/bug-3571/depend
@@ -52,7 +52,6 @@ bug.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bug.o: $(hdrdir)/ruby/internal/attr/noinline.h
bug.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bug.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bug.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bug.o: $(hdrdir)/ruby/internal/attr/pure.h
bug.o: $(hdrdir)/ruby/internal/attr/restrict.h
bug.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ bug.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bug.o: $(hdrdir)/ruby/internal/intern/error.h
bug.o: $(hdrdir)/ruby/internal/intern/eval.h
bug.o: $(hdrdir)/ruby/internal/intern/file.h
+bug.o: $(hdrdir)/ruby/internal/intern/gc.h
bug.o: $(hdrdir)/ruby/internal/intern/hash.h
bug.o: $(hdrdir)/ruby/internal/intern/io.h
bug.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ bug.o: $(hdrdir)/ruby/internal/memory.h
bug.o: $(hdrdir)/ruby/internal/method.h
bug.o: $(hdrdir)/ruby/internal/module.h
bug.o: $(hdrdir)/ruby/internal/newobj.h
+bug.o: $(hdrdir)/ruby/internal/rgengc.h
bug.o: $(hdrdir)/ruby/internal/scan_args.h
bug.o: $(hdrdir)/ruby/internal/special_consts.h
bug.o: $(hdrdir)/ruby/internal/static_assert.h
bug.o: $(hdrdir)/ruby/internal/stdalign.h
bug.o: $(hdrdir)/ruby/internal/stdbool.h
-bug.o: $(hdrdir)/ruby/internal/stdckdint.h
bug.o: $(hdrdir)/ruby/internal/symbol.h
bug.o: $(hdrdir)/ruby/internal/value.h
bug.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/bug-5832/depend b/ext/-test-/bug-5832/depend
index 84517a9c15..2303f47594 100644
--- a/ext/-test-/bug-5832/depend
+++ b/ext/-test-/bug-5832/depend
@@ -52,7 +52,6 @@ bug.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bug.o: $(hdrdir)/ruby/internal/attr/noinline.h
bug.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bug.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bug.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bug.o: $(hdrdir)/ruby/internal/attr/pure.h
bug.o: $(hdrdir)/ruby/internal/attr/restrict.h
bug.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ bug.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bug.o: $(hdrdir)/ruby/internal/intern/error.h
bug.o: $(hdrdir)/ruby/internal/intern/eval.h
bug.o: $(hdrdir)/ruby/internal/intern/file.h
+bug.o: $(hdrdir)/ruby/internal/intern/gc.h
bug.o: $(hdrdir)/ruby/internal/intern/hash.h
bug.o: $(hdrdir)/ruby/internal/intern/io.h
bug.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ bug.o: $(hdrdir)/ruby/internal/memory.h
bug.o: $(hdrdir)/ruby/internal/method.h
bug.o: $(hdrdir)/ruby/internal/module.h
bug.o: $(hdrdir)/ruby/internal/newobj.h
+bug.o: $(hdrdir)/ruby/internal/rgengc.h
bug.o: $(hdrdir)/ruby/internal/scan_args.h
bug.o: $(hdrdir)/ruby/internal/special_consts.h
bug.o: $(hdrdir)/ruby/internal/static_assert.h
bug.o: $(hdrdir)/ruby/internal/stdalign.h
bug.o: $(hdrdir)/ruby/internal/stdbool.h
-bug.o: $(hdrdir)/ruby/internal/stdckdint.h
bug.o: $(hdrdir)/ruby/internal/symbol.h
bug.o: $(hdrdir)/ruby/internal/value.h
bug.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/bug_reporter/depend b/ext/-test-/bug_reporter/depend
index 1c73234247..603dd53ebf 100644
--- a/ext/-test-/bug_reporter/depend
+++ b/ext/-test-/bug_reporter/depend
@@ -52,7 +52,6 @@ bug_reporter.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bug_reporter.o: $(hdrdir)/ruby/internal/attr/noinline.h
bug_reporter.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bug_reporter.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bug_reporter.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bug_reporter.o: $(hdrdir)/ruby/internal/attr/pure.h
bug_reporter.o: $(hdrdir)/ruby/internal/attr/restrict.h
bug_reporter.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ bug_reporter.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/error.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/eval.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/file.h
+bug_reporter.o: $(hdrdir)/ruby/internal/intern/gc.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/hash.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/io.h
bug_reporter.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ bug_reporter.o: $(hdrdir)/ruby/internal/memory.h
bug_reporter.o: $(hdrdir)/ruby/internal/method.h
bug_reporter.o: $(hdrdir)/ruby/internal/module.h
bug_reporter.o: $(hdrdir)/ruby/internal/newobj.h
+bug_reporter.o: $(hdrdir)/ruby/internal/rgengc.h
bug_reporter.o: $(hdrdir)/ruby/internal/scan_args.h
bug_reporter.o: $(hdrdir)/ruby/internal/special_consts.h
bug_reporter.o: $(hdrdir)/ruby/internal/static_assert.h
bug_reporter.o: $(hdrdir)/ruby/internal/stdalign.h
bug_reporter.o: $(hdrdir)/ruby/internal/stdbool.h
-bug_reporter.o: $(hdrdir)/ruby/internal/stdckdint.h
bug_reporter.o: $(hdrdir)/ruby/internal/symbol.h
bug_reporter.o: $(hdrdir)/ruby/internal/value.h
bug_reporter.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/class/depend b/ext/-test-/class/depend
index b0595fdc46..a615eacd74 100644
--- a/ext/-test-/class/depend
+++ b/ext/-test-/class/depend
@@ -51,7 +51,6 @@ class2name.o: $(hdrdir)/ruby/internal/attr/noexcept.h
class2name.o: $(hdrdir)/ruby/internal/attr/noinline.h
class2name.o: $(hdrdir)/ruby/internal/attr/nonnull.h
class2name.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-class2name.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
class2name.o: $(hdrdir)/ruby/internal/attr/pure.h
class2name.o: $(hdrdir)/ruby/internal/attr/restrict.h
class2name.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ class2name.o: $(hdrdir)/ruby/internal/intern/enumerator.h
class2name.o: $(hdrdir)/ruby/internal/intern/error.h
class2name.o: $(hdrdir)/ruby/internal/intern/eval.h
class2name.o: $(hdrdir)/ruby/internal/intern/file.h
+class2name.o: $(hdrdir)/ruby/internal/intern/gc.h
class2name.o: $(hdrdir)/ruby/internal/intern/hash.h
class2name.o: $(hdrdir)/ruby/internal/intern/io.h
class2name.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,12 +141,12 @@ class2name.o: $(hdrdir)/ruby/internal/memory.h
class2name.o: $(hdrdir)/ruby/internal/method.h
class2name.o: $(hdrdir)/ruby/internal/module.h
class2name.o: $(hdrdir)/ruby/internal/newobj.h
+class2name.o: $(hdrdir)/ruby/internal/rgengc.h
class2name.o: $(hdrdir)/ruby/internal/scan_args.h
class2name.o: $(hdrdir)/ruby/internal/special_consts.h
class2name.o: $(hdrdir)/ruby/internal/static_assert.h
class2name.o: $(hdrdir)/ruby/internal/stdalign.h
class2name.o: $(hdrdir)/ruby/internal/stdbool.h
-class2name.o: $(hdrdir)/ruby/internal/stdckdint.h
class2name.o: $(hdrdir)/ruby/internal/symbol.h
class2name.o: $(hdrdir)/ruby/internal/value.h
class2name.o: $(hdrdir)/ruby/internal/value_type.h
@@ -211,7 +211,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -271,6 +270,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -301,12 +301,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/class/init.c b/ext/-test-/class/init.c
index 108ff7525c..ed715c1942 100644
--- a/ext/-test-/class/init.c
+++ b/ext/-test-/class/init.c
@@ -7,6 +7,5 @@ Init_class(void)
{
VALUE mBug = rb_define_module("Bug");
VALUE mod = rb_define_module_under(mBug, "Class");
- rb_define_class_under(mod, "TestClassDefinedInC", rb_cObject);
TEST_INIT_FUNCS(init);
}
diff --git a/ext/-test-/debug/depend b/ext/-test-/debug/depend
index 67e32c6aa6..c3a0c278aa 100644
--- a/ext/-test-/debug/depend
+++ b/ext/-test-/debug/depend
@@ -52,7 +52,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -212,7 +212,6 @@ inspector.o: $(hdrdir)/ruby/internal/attr/noexcept.h
inspector.o: $(hdrdir)/ruby/internal/attr/noinline.h
inspector.o: $(hdrdir)/ruby/internal/attr/nonnull.h
inspector.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-inspector.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
inspector.o: $(hdrdir)/ruby/internal/attr/pure.h
inspector.o: $(hdrdir)/ruby/internal/attr/restrict.h
inspector.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -272,6 +271,7 @@ inspector.o: $(hdrdir)/ruby/internal/intern/enumerator.h
inspector.o: $(hdrdir)/ruby/internal/intern/error.h
inspector.o: $(hdrdir)/ruby/internal/intern/eval.h
inspector.o: $(hdrdir)/ruby/internal/intern/file.h
+inspector.o: $(hdrdir)/ruby/internal/intern/gc.h
inspector.o: $(hdrdir)/ruby/internal/intern/hash.h
inspector.o: $(hdrdir)/ruby/internal/intern/io.h
inspector.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -302,12 +302,12 @@ inspector.o: $(hdrdir)/ruby/internal/memory.h
inspector.o: $(hdrdir)/ruby/internal/method.h
inspector.o: $(hdrdir)/ruby/internal/module.h
inspector.o: $(hdrdir)/ruby/internal/newobj.h
+inspector.o: $(hdrdir)/ruby/internal/rgengc.h
inspector.o: $(hdrdir)/ruby/internal/scan_args.h
inspector.o: $(hdrdir)/ruby/internal/special_consts.h
inspector.o: $(hdrdir)/ruby/internal/static_assert.h
inspector.o: $(hdrdir)/ruby/internal/stdalign.h
inspector.o: $(hdrdir)/ruby/internal/stdbool.h
-inspector.o: $(hdrdir)/ruby/internal/stdckdint.h
inspector.o: $(hdrdir)/ruby/internal/symbol.h
inspector.o: $(hdrdir)/ruby/internal/value.h
inspector.o: $(hdrdir)/ruby/internal/value_type.h
@@ -372,7 +372,6 @@ profile_frames.o: $(hdrdir)/ruby/internal/attr/noexcept.h
profile_frames.o: $(hdrdir)/ruby/internal/attr/noinline.h
profile_frames.o: $(hdrdir)/ruby/internal/attr/nonnull.h
profile_frames.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-profile_frames.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
profile_frames.o: $(hdrdir)/ruby/internal/attr/pure.h
profile_frames.o: $(hdrdir)/ruby/internal/attr/restrict.h
profile_frames.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -432,6 +431,7 @@ profile_frames.o: $(hdrdir)/ruby/internal/intern/enumerator.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/error.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/eval.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/file.h
+profile_frames.o: $(hdrdir)/ruby/internal/intern/gc.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/hash.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/io.h
profile_frames.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -462,12 +462,12 @@ profile_frames.o: $(hdrdir)/ruby/internal/memory.h
profile_frames.o: $(hdrdir)/ruby/internal/method.h
profile_frames.o: $(hdrdir)/ruby/internal/module.h
profile_frames.o: $(hdrdir)/ruby/internal/newobj.h
+profile_frames.o: $(hdrdir)/ruby/internal/rgengc.h
profile_frames.o: $(hdrdir)/ruby/internal/scan_args.h
profile_frames.o: $(hdrdir)/ruby/internal/special_consts.h
profile_frames.o: $(hdrdir)/ruby/internal/static_assert.h
profile_frames.o: $(hdrdir)/ruby/internal/stdalign.h
profile_frames.o: $(hdrdir)/ruby/internal/stdbool.h
-profile_frames.o: $(hdrdir)/ruby/internal/stdckdint.h
profile_frames.o: $(hdrdir)/ruby/internal/symbol.h
profile_frames.o: $(hdrdir)/ruby/internal/value.h
profile_frames.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/debug/profile_frames.c b/ext/-test-/debug/profile_frames.c
index f9a77a5a78..d2bba7d183 100644
--- a/ext/-test-/debug/profile_frames.c
+++ b/ext/-test-/debug/profile_frames.c
@@ -37,29 +37,8 @@ profile_frames(VALUE self, VALUE start_v, VALUE num_v)
return result;
}
-static VALUE
-profile_thread_frames(VALUE self, VALUE thread, VALUE start_v, VALUE num_v)
-{
- int i, collected_size;
- int start = NUM2INT(start_v);
- int buff_size = NUM2INT(num_v);
- VALUE buff[MAX_BUF_SIZE];
- int lines[MAX_BUF_SIZE];
- VALUE result = rb_ary_new();
-
- if (buff_size > MAX_BUF_SIZE) rb_raise(rb_eRuntimeError, "too long buff_size");
-
- collected_size = rb_profile_thread_frames(thread, start, buff_size, buff, lines);
- for (i=0; i<collected_size; i++) {
- rb_ary_push(result, rb_profile_frame_full_label(buff[i]));
- }
-
- return result;
-}
-
void
Init_profile_frames(VALUE klass)
{
rb_define_module_function(klass, "profile_frames", profile_frames, 2);
- rb_define_module_function(klass, "profile_thread_frames", profile_thread_frames, 3);
}
diff --git a/ext/-test-/dln/empty/depend b/ext/-test-/dln/empty/depend
index d3e606df57..e16082a7dc 100644
--- a/ext/-test-/dln/empty/depend
+++ b/ext/-test-/dln/empty/depend
@@ -52,7 +52,6 @@ empty.o: $(hdrdir)/ruby/internal/attr/noexcept.h
empty.o: $(hdrdir)/ruby/internal/attr/noinline.h
empty.o: $(hdrdir)/ruby/internal/attr/nonnull.h
empty.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-empty.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
empty.o: $(hdrdir)/ruby/internal/attr/pure.h
empty.o: $(hdrdir)/ruby/internal/attr/restrict.h
empty.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ empty.o: $(hdrdir)/ruby/internal/intern/enumerator.h
empty.o: $(hdrdir)/ruby/internal/intern/error.h
empty.o: $(hdrdir)/ruby/internal/intern/eval.h
empty.o: $(hdrdir)/ruby/internal/intern/file.h
+empty.o: $(hdrdir)/ruby/internal/intern/gc.h
empty.o: $(hdrdir)/ruby/internal/intern/hash.h
empty.o: $(hdrdir)/ruby/internal/intern/io.h
empty.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ empty.o: $(hdrdir)/ruby/internal/memory.h
empty.o: $(hdrdir)/ruby/internal/method.h
empty.o: $(hdrdir)/ruby/internal/module.h
empty.o: $(hdrdir)/ruby/internal/newobj.h
+empty.o: $(hdrdir)/ruby/internal/rgengc.h
empty.o: $(hdrdir)/ruby/internal/scan_args.h
empty.o: $(hdrdir)/ruby/internal/special_consts.h
empty.o: $(hdrdir)/ruby/internal/static_assert.h
empty.o: $(hdrdir)/ruby/internal/stdalign.h
empty.o: $(hdrdir)/ruby/internal/stdbool.h
-empty.o: $(hdrdir)/ruby/internal/stdckdint.h
empty.o: $(hdrdir)/ruby/internal/symbol.h
empty.o: $(hdrdir)/ruby/internal/value.h
empty.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/ensure_and_callcc/ensure_and_callcc.c b/ext/-test-/ensure_and_callcc/ensure_and_callcc.c
deleted file mode 100644
index 1a92de69c3..0000000000
--- a/ext/-test-/ensure_and_callcc/ensure_and_callcc.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include "ruby.h"
-
-static VALUE rb_mEnsureAndCallcc;
-
-struct require_data {
- VALUE obj;
- VALUE fname;
-};
-
-static VALUE
-call_require(VALUE arg)
-{
- struct require_data *data = (struct require_data *)arg;
- rb_f_require(data->obj, data->fname);
- return Qnil;
-}
-
-static VALUE
-call_ensure(VALUE _)
-{
- VALUE v = rb_iv_get(rb_mEnsureAndCallcc, "@ensure_called");
- int called = FIX2INT(v) + 1;
- rb_iv_set(rb_mEnsureAndCallcc, "@ensure_called", INT2FIX(called));
- return Qnil;
-}
-
-static VALUE
-require_with_ensure(VALUE self, VALUE fname)
-{
- struct require_data data = {
- .obj = self,
- .fname = fname
- };
- return rb_ensure(call_require, (VALUE)&data, call_ensure, Qnil);
-}
-
-static VALUE
-ensure_called(VALUE self)
-{
- return rb_iv_get(rb_mEnsureAndCallcc, "@ensure_called");
-}
-
-static VALUE
-reset(VALUE self)
-{
- rb_iv_set(rb_mEnsureAndCallcc, "@ensure_called", INT2FIX(0));
- return Qnil;
-}
-
-void
-Init_ensure_and_callcc(void)
-{
- rb_mEnsureAndCallcc = rb_define_module("EnsureAndCallcc");
- rb_iv_set(rb_mEnsureAndCallcc, "@ensure_called", INT2FIX(0));
- rb_define_singleton_method(rb_mEnsureAndCallcc, "reset", reset, 0);
- rb_define_singleton_method(rb_mEnsureAndCallcc, "ensure_called", ensure_called, 0);
- rb_define_singleton_method(rb_mEnsureAndCallcc, "require_with_ensure", require_with_ensure, 1);
-}
diff --git a/ext/-test-/ensure_and_callcc/extconf.rb b/ext/-test-/ensure_and_callcc/extconf.rb
deleted file mode 100644
index 123b80b8d0..0000000000
--- a/ext/-test-/ensure_and_callcc/extconf.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-# frozen_string_literal: false
-require "mkmf"
-
-require_relative "../auto_ext.rb"
-auto_ext(inc: true)
diff --git a/ext/-test-/enumerator_kw/depend b/ext/-test-/enumerator_kw/depend
index 85daa55b53..14a9557e41 100644
--- a/ext/-test-/enumerator_kw/depend
+++ b/ext/-test-/enumerator_kw/depend
@@ -52,7 +52,6 @@ enumerator_kw.o: $(hdrdir)/ruby/internal/attr/noexcept.h
enumerator_kw.o: $(hdrdir)/ruby/internal/attr/noinline.h
enumerator_kw.o: $(hdrdir)/ruby/internal/attr/nonnull.h
enumerator_kw.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-enumerator_kw.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
enumerator_kw.o: $(hdrdir)/ruby/internal/attr/pure.h
enumerator_kw.o: $(hdrdir)/ruby/internal/attr/restrict.h
enumerator_kw.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ enumerator_kw.o: $(hdrdir)/ruby/internal/intern/enumerator.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/error.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/eval.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/file.h
+enumerator_kw.o: $(hdrdir)/ruby/internal/intern/gc.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/hash.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/io.h
enumerator_kw.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ enumerator_kw.o: $(hdrdir)/ruby/internal/memory.h
enumerator_kw.o: $(hdrdir)/ruby/internal/method.h
enumerator_kw.o: $(hdrdir)/ruby/internal/module.h
enumerator_kw.o: $(hdrdir)/ruby/internal/newobj.h
+enumerator_kw.o: $(hdrdir)/ruby/internal/rgengc.h
enumerator_kw.o: $(hdrdir)/ruby/internal/scan_args.h
enumerator_kw.o: $(hdrdir)/ruby/internal/special_consts.h
enumerator_kw.o: $(hdrdir)/ruby/internal/static_assert.h
enumerator_kw.o: $(hdrdir)/ruby/internal/stdalign.h
enumerator_kw.o: $(hdrdir)/ruby/internal/stdbool.h
-enumerator_kw.o: $(hdrdir)/ruby/internal/stdckdint.h
enumerator_kw.o: $(hdrdir)/ruby/internal/symbol.h
enumerator_kw.o: $(hdrdir)/ruby/internal/value.h
enumerator_kw.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/exception/depend b/ext/-test-/exception/depend
index 7a0544b1e1..e00f0b279d 100644
--- a/ext/-test-/exception/depend
+++ b/ext/-test-/exception/depend
@@ -51,7 +51,6 @@ dataerror.o: $(hdrdir)/ruby/internal/attr/noexcept.h
dataerror.o: $(hdrdir)/ruby/internal/attr/noinline.h
dataerror.o: $(hdrdir)/ruby/internal/attr/nonnull.h
dataerror.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-dataerror.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
dataerror.o: $(hdrdir)/ruby/internal/attr/pure.h
dataerror.o: $(hdrdir)/ruby/internal/attr/restrict.h
dataerror.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ dataerror.o: $(hdrdir)/ruby/internal/intern/enumerator.h
dataerror.o: $(hdrdir)/ruby/internal/intern/error.h
dataerror.o: $(hdrdir)/ruby/internal/intern/eval.h
dataerror.o: $(hdrdir)/ruby/internal/intern/file.h
+dataerror.o: $(hdrdir)/ruby/internal/intern/gc.h
dataerror.o: $(hdrdir)/ruby/internal/intern/hash.h
dataerror.o: $(hdrdir)/ruby/internal/intern/io.h
dataerror.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,12 +141,12 @@ dataerror.o: $(hdrdir)/ruby/internal/memory.h
dataerror.o: $(hdrdir)/ruby/internal/method.h
dataerror.o: $(hdrdir)/ruby/internal/module.h
dataerror.o: $(hdrdir)/ruby/internal/newobj.h
+dataerror.o: $(hdrdir)/ruby/internal/rgengc.h
dataerror.o: $(hdrdir)/ruby/internal/scan_args.h
dataerror.o: $(hdrdir)/ruby/internal/special_consts.h
dataerror.o: $(hdrdir)/ruby/internal/static_assert.h
dataerror.o: $(hdrdir)/ruby/internal/stdalign.h
dataerror.o: $(hdrdir)/ruby/internal/stdbool.h
-dataerror.o: $(hdrdir)/ruby/internal/stdckdint.h
dataerror.o: $(hdrdir)/ruby/internal/symbol.h
dataerror.o: $(hdrdir)/ruby/internal/value.h
dataerror.o: $(hdrdir)/ruby/internal/value_type.h
@@ -212,7 +212,6 @@ enc_raise.o: $(hdrdir)/ruby/internal/attr/noexcept.h
enc_raise.o: $(hdrdir)/ruby/internal/attr/noinline.h
enc_raise.o: $(hdrdir)/ruby/internal/attr/nonnull.h
enc_raise.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-enc_raise.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
enc_raise.o: $(hdrdir)/ruby/internal/attr/pure.h
enc_raise.o: $(hdrdir)/ruby/internal/attr/restrict.h
enc_raise.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -281,6 +280,7 @@ enc_raise.o: $(hdrdir)/ruby/internal/intern/enumerator.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/error.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/eval.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/file.h
+enc_raise.o: $(hdrdir)/ruby/internal/intern/gc.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/hash.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/io.h
enc_raise.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -311,12 +311,12 @@ enc_raise.o: $(hdrdir)/ruby/internal/memory.h
enc_raise.o: $(hdrdir)/ruby/internal/method.h
enc_raise.o: $(hdrdir)/ruby/internal/module.h
enc_raise.o: $(hdrdir)/ruby/internal/newobj.h
+enc_raise.o: $(hdrdir)/ruby/internal/rgengc.h
enc_raise.o: $(hdrdir)/ruby/internal/scan_args.h
enc_raise.o: $(hdrdir)/ruby/internal/special_consts.h
enc_raise.o: $(hdrdir)/ruby/internal/static_assert.h
enc_raise.o: $(hdrdir)/ruby/internal/stdalign.h
enc_raise.o: $(hdrdir)/ruby/internal/stdbool.h
-enc_raise.o: $(hdrdir)/ruby/internal/stdckdint.h
enc_raise.o: $(hdrdir)/ruby/internal/symbol.h
enc_raise.o: $(hdrdir)/ruby/internal/value.h
enc_raise.o: $(hdrdir)/ruby/internal/value_type.h
@@ -383,7 +383,6 @@ ensured.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ensured.o: $(hdrdir)/ruby/internal/attr/noinline.h
ensured.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ensured.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ensured.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ensured.o: $(hdrdir)/ruby/internal/attr/pure.h
ensured.o: $(hdrdir)/ruby/internal/attr/restrict.h
ensured.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -443,6 +442,7 @@ ensured.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ensured.o: $(hdrdir)/ruby/internal/intern/error.h
ensured.o: $(hdrdir)/ruby/internal/intern/eval.h
ensured.o: $(hdrdir)/ruby/internal/intern/file.h
+ensured.o: $(hdrdir)/ruby/internal/intern/gc.h
ensured.o: $(hdrdir)/ruby/internal/intern/hash.h
ensured.o: $(hdrdir)/ruby/internal/intern/io.h
ensured.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -473,12 +473,12 @@ ensured.o: $(hdrdir)/ruby/internal/memory.h
ensured.o: $(hdrdir)/ruby/internal/method.h
ensured.o: $(hdrdir)/ruby/internal/module.h
ensured.o: $(hdrdir)/ruby/internal/newobj.h
+ensured.o: $(hdrdir)/ruby/internal/rgengc.h
ensured.o: $(hdrdir)/ruby/internal/scan_args.h
ensured.o: $(hdrdir)/ruby/internal/special_consts.h
ensured.o: $(hdrdir)/ruby/internal/static_assert.h
ensured.o: $(hdrdir)/ruby/internal/stdalign.h
ensured.o: $(hdrdir)/ruby/internal/stdbool.h
-ensured.o: $(hdrdir)/ruby/internal/stdckdint.h
ensured.o: $(hdrdir)/ruby/internal/symbol.h
ensured.o: $(hdrdir)/ruby/internal/value.h
ensured.o: $(hdrdir)/ruby/internal/value_type.h
@@ -543,7 +543,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -603,6 +602,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -633,12 +633,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/fatal/depend b/ext/-test-/fatal/depend
index 36b0ad4205..5b1adb6607 100644
--- a/ext/-test-/fatal/depend
+++ b/ext/-test-/fatal/depend
@@ -1,325 +1,4 @@
# AUTOGENERATED DEPENDENCIES START
-
-init.o: $(RUBY_EXTCONF_H)
-init.o: $(arch_hdrdir)/ruby/config.h
-init.o: $(hdrdir)/ruby.h
-init.o: $(hdrdir)/ruby/assert.h
-init.o: $(hdrdir)/ruby/backward.h
-init.o: $(hdrdir)/ruby/backward/2/assume.h
-init.o: $(hdrdir)/ruby/backward/2/attributes.h
-init.o: $(hdrdir)/ruby/backward/2/bool.h
-init.o: $(hdrdir)/ruby/backward/2/inttypes.h
-init.o: $(hdrdir)/ruby/backward/2/limits.h
-init.o: $(hdrdir)/ruby/backward/2/long_long.h
-init.o: $(hdrdir)/ruby/backward/2/stdalign.h
-init.o: $(hdrdir)/ruby/backward/2/stdarg.h
-init.o: $(hdrdir)/ruby/defines.h
-init.o: $(hdrdir)/ruby/intern.h
-init.o: $(hdrdir)/ruby/internal/abi.h
-init.o: $(hdrdir)/ruby/internal/anyargs.h
-init.o: $(hdrdir)/ruby/internal/arithmetic.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-init.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-init.o: $(hdrdir)/ruby/internal/assume.h
-init.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-init.o: $(hdrdir)/ruby/internal/attr/artificial.h
-init.o: $(hdrdir)/ruby/internal/attr/cold.h
-init.o: $(hdrdir)/ruby/internal/attr/const.h
-init.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-init.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-init.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-init.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-init.o: $(hdrdir)/ruby/internal/attr/error.h
-init.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-init.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-init.o: $(hdrdir)/ruby/internal/attr/format.h
-init.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-init.o: $(hdrdir)/ruby/internal/attr/noalias.h
-init.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-init.o: $(hdrdir)/ruby/internal/attr/noinline.h
-init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-init.o: $(hdrdir)/ruby/internal/attr/pure.h
-init.o: $(hdrdir)/ruby/internal/attr/restrict.h
-init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-init.o: $(hdrdir)/ruby/internal/attr/warning.h
-init.o: $(hdrdir)/ruby/internal/attr/weakref.h
-init.o: $(hdrdir)/ruby/internal/cast.h
-init.o: $(hdrdir)/ruby/internal/compiler_is.h
-init.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-init.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-init.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-init.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-init.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-init.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-init.o: $(hdrdir)/ruby/internal/compiler_since.h
-init.o: $(hdrdir)/ruby/internal/config.h
-init.o: $(hdrdir)/ruby/internal/constant_p.h
-init.o: $(hdrdir)/ruby/internal/core.h
-init.o: $(hdrdir)/ruby/internal/core/rarray.h
-init.o: $(hdrdir)/ruby/internal/core/rbasic.h
-init.o: $(hdrdir)/ruby/internal/core/rbignum.h
-init.o: $(hdrdir)/ruby/internal/core/rclass.h
-init.o: $(hdrdir)/ruby/internal/core/rdata.h
-init.o: $(hdrdir)/ruby/internal/core/rfile.h
-init.o: $(hdrdir)/ruby/internal/core/rhash.h
-init.o: $(hdrdir)/ruby/internal/core/robject.h
-init.o: $(hdrdir)/ruby/internal/core/rregexp.h
-init.o: $(hdrdir)/ruby/internal/core/rstring.h
-init.o: $(hdrdir)/ruby/internal/core/rstruct.h
-init.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-init.o: $(hdrdir)/ruby/internal/ctype.h
-init.o: $(hdrdir)/ruby/internal/dllexport.h
-init.o: $(hdrdir)/ruby/internal/dosish.h
-init.o: $(hdrdir)/ruby/internal/error.h
-init.o: $(hdrdir)/ruby/internal/eval.h
-init.o: $(hdrdir)/ruby/internal/event.h
-init.o: $(hdrdir)/ruby/internal/fl_type.h
-init.o: $(hdrdir)/ruby/internal/gc.h
-init.o: $(hdrdir)/ruby/internal/glob.h
-init.o: $(hdrdir)/ruby/internal/globals.h
-init.o: $(hdrdir)/ruby/internal/has/attribute.h
-init.o: $(hdrdir)/ruby/internal/has/builtin.h
-init.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-init.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-init.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-init.o: $(hdrdir)/ruby/internal/has/extension.h
-init.o: $(hdrdir)/ruby/internal/has/feature.h
-init.o: $(hdrdir)/ruby/internal/has/warning.h
-init.o: $(hdrdir)/ruby/internal/intern/array.h
-init.o: $(hdrdir)/ruby/internal/intern/bignum.h
-init.o: $(hdrdir)/ruby/internal/intern/class.h
-init.o: $(hdrdir)/ruby/internal/intern/compar.h
-init.o: $(hdrdir)/ruby/internal/intern/complex.h
-init.o: $(hdrdir)/ruby/internal/intern/cont.h
-init.o: $(hdrdir)/ruby/internal/intern/dir.h
-init.o: $(hdrdir)/ruby/internal/intern/enum.h
-init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-init.o: $(hdrdir)/ruby/internal/intern/error.h
-init.o: $(hdrdir)/ruby/internal/intern/eval.h
-init.o: $(hdrdir)/ruby/internal/intern/file.h
-init.o: $(hdrdir)/ruby/internal/intern/hash.h
-init.o: $(hdrdir)/ruby/internal/intern/io.h
-init.o: $(hdrdir)/ruby/internal/intern/load.h
-init.o: $(hdrdir)/ruby/internal/intern/marshal.h
-init.o: $(hdrdir)/ruby/internal/intern/numeric.h
-init.o: $(hdrdir)/ruby/internal/intern/object.h
-init.o: $(hdrdir)/ruby/internal/intern/parse.h
-init.o: $(hdrdir)/ruby/internal/intern/proc.h
-init.o: $(hdrdir)/ruby/internal/intern/process.h
-init.o: $(hdrdir)/ruby/internal/intern/random.h
-init.o: $(hdrdir)/ruby/internal/intern/range.h
-init.o: $(hdrdir)/ruby/internal/intern/rational.h
-init.o: $(hdrdir)/ruby/internal/intern/re.h
-init.o: $(hdrdir)/ruby/internal/intern/ruby.h
-init.o: $(hdrdir)/ruby/internal/intern/select.h
-init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-init.o: $(hdrdir)/ruby/internal/intern/signal.h
-init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-init.o: $(hdrdir)/ruby/internal/intern/string.h
-init.o: $(hdrdir)/ruby/internal/intern/struct.h
-init.o: $(hdrdir)/ruby/internal/intern/thread.h
-init.o: $(hdrdir)/ruby/internal/intern/time.h
-init.o: $(hdrdir)/ruby/internal/intern/variable.h
-init.o: $(hdrdir)/ruby/internal/intern/vm.h
-init.o: $(hdrdir)/ruby/internal/interpreter.h
-init.o: $(hdrdir)/ruby/internal/iterator.h
-init.o: $(hdrdir)/ruby/internal/memory.h
-init.o: $(hdrdir)/ruby/internal/method.h
-init.o: $(hdrdir)/ruby/internal/module.h
-init.o: $(hdrdir)/ruby/internal/newobj.h
-init.o: $(hdrdir)/ruby/internal/scan_args.h
-init.o: $(hdrdir)/ruby/internal/special_consts.h
-init.o: $(hdrdir)/ruby/internal/static_assert.h
-init.o: $(hdrdir)/ruby/internal/stdalign.h
-init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
-init.o: $(hdrdir)/ruby/internal/symbol.h
-init.o: $(hdrdir)/ruby/internal/value.h
-init.o: $(hdrdir)/ruby/internal/value_type.h
-init.o: $(hdrdir)/ruby/internal/variable.h
-init.o: $(hdrdir)/ruby/internal/warning_push.h
-init.o: $(hdrdir)/ruby/internal/xmalloc.h
-init.o: $(hdrdir)/ruby/missing.h
-init.o: $(hdrdir)/ruby/ruby.h
-init.o: $(hdrdir)/ruby/st.h
-init.o: $(hdrdir)/ruby/subst.h
-init.o: init.c
-invalid.o: $(RUBY_EXTCONF_H)
-invalid.o: $(arch_hdrdir)/ruby/config.h
-invalid.o: $(hdrdir)/ruby.h
-invalid.o: $(hdrdir)/ruby/assert.h
-invalid.o: $(hdrdir)/ruby/backward.h
-invalid.o: $(hdrdir)/ruby/backward/2/assume.h
-invalid.o: $(hdrdir)/ruby/backward/2/attributes.h
-invalid.o: $(hdrdir)/ruby/backward/2/bool.h
-invalid.o: $(hdrdir)/ruby/backward/2/inttypes.h
-invalid.o: $(hdrdir)/ruby/backward/2/limits.h
-invalid.o: $(hdrdir)/ruby/backward/2/long_long.h
-invalid.o: $(hdrdir)/ruby/backward/2/stdalign.h
-invalid.o: $(hdrdir)/ruby/backward/2/stdarg.h
-invalid.o: $(hdrdir)/ruby/defines.h
-invalid.o: $(hdrdir)/ruby/intern.h
-invalid.o: $(hdrdir)/ruby/internal/abi.h
-invalid.o: $(hdrdir)/ruby/internal/anyargs.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-invalid.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-invalid.o: $(hdrdir)/ruby/internal/assume.h
-invalid.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-invalid.o: $(hdrdir)/ruby/internal/attr/artificial.h
-invalid.o: $(hdrdir)/ruby/internal/attr/cold.h
-invalid.o: $(hdrdir)/ruby/internal/attr/const.h
-invalid.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-invalid.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-invalid.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-invalid.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-invalid.o: $(hdrdir)/ruby/internal/attr/error.h
-invalid.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-invalid.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-invalid.o: $(hdrdir)/ruby/internal/attr/format.h
-invalid.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-invalid.o: $(hdrdir)/ruby/internal/attr/noalias.h
-invalid.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-invalid.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-invalid.o: $(hdrdir)/ruby/internal/attr/noinline.h
-invalid.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-invalid.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-invalid.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-invalid.o: $(hdrdir)/ruby/internal/attr/pure.h
-invalid.o: $(hdrdir)/ruby/internal/attr/restrict.h
-invalid.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-invalid.o: $(hdrdir)/ruby/internal/attr/warning.h
-invalid.o: $(hdrdir)/ruby/internal/attr/weakref.h
-invalid.o: $(hdrdir)/ruby/internal/cast.h
-invalid.o: $(hdrdir)/ruby/internal/compiler_is.h
-invalid.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-invalid.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-invalid.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-invalid.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-invalid.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-invalid.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-invalid.o: $(hdrdir)/ruby/internal/compiler_since.h
-invalid.o: $(hdrdir)/ruby/internal/config.h
-invalid.o: $(hdrdir)/ruby/internal/constant_p.h
-invalid.o: $(hdrdir)/ruby/internal/core.h
-invalid.o: $(hdrdir)/ruby/internal/core/rarray.h
-invalid.o: $(hdrdir)/ruby/internal/core/rbasic.h
-invalid.o: $(hdrdir)/ruby/internal/core/rbignum.h
-invalid.o: $(hdrdir)/ruby/internal/core/rclass.h
-invalid.o: $(hdrdir)/ruby/internal/core/rdata.h
-invalid.o: $(hdrdir)/ruby/internal/core/rfile.h
-invalid.o: $(hdrdir)/ruby/internal/core/rhash.h
-invalid.o: $(hdrdir)/ruby/internal/core/robject.h
-invalid.o: $(hdrdir)/ruby/internal/core/rregexp.h
-invalid.o: $(hdrdir)/ruby/internal/core/rstring.h
-invalid.o: $(hdrdir)/ruby/internal/core/rstruct.h
-invalid.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-invalid.o: $(hdrdir)/ruby/internal/ctype.h
-invalid.o: $(hdrdir)/ruby/internal/dllexport.h
-invalid.o: $(hdrdir)/ruby/internal/dosish.h
-invalid.o: $(hdrdir)/ruby/internal/error.h
-invalid.o: $(hdrdir)/ruby/internal/eval.h
-invalid.o: $(hdrdir)/ruby/internal/event.h
-invalid.o: $(hdrdir)/ruby/internal/fl_type.h
-invalid.o: $(hdrdir)/ruby/internal/gc.h
-invalid.o: $(hdrdir)/ruby/internal/glob.h
-invalid.o: $(hdrdir)/ruby/internal/globals.h
-invalid.o: $(hdrdir)/ruby/internal/has/attribute.h
-invalid.o: $(hdrdir)/ruby/internal/has/builtin.h
-invalid.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-invalid.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-invalid.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-invalid.o: $(hdrdir)/ruby/internal/has/extension.h
-invalid.o: $(hdrdir)/ruby/internal/has/feature.h
-invalid.o: $(hdrdir)/ruby/internal/has/warning.h
-invalid.o: $(hdrdir)/ruby/internal/intern/array.h
-invalid.o: $(hdrdir)/ruby/internal/intern/bignum.h
-invalid.o: $(hdrdir)/ruby/internal/intern/class.h
-invalid.o: $(hdrdir)/ruby/internal/intern/compar.h
-invalid.o: $(hdrdir)/ruby/internal/intern/complex.h
-invalid.o: $(hdrdir)/ruby/internal/intern/cont.h
-invalid.o: $(hdrdir)/ruby/internal/intern/dir.h
-invalid.o: $(hdrdir)/ruby/internal/intern/enum.h
-invalid.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-invalid.o: $(hdrdir)/ruby/internal/intern/error.h
-invalid.o: $(hdrdir)/ruby/internal/intern/eval.h
-invalid.o: $(hdrdir)/ruby/internal/intern/file.h
-invalid.o: $(hdrdir)/ruby/internal/intern/hash.h
-invalid.o: $(hdrdir)/ruby/internal/intern/io.h
-invalid.o: $(hdrdir)/ruby/internal/intern/load.h
-invalid.o: $(hdrdir)/ruby/internal/intern/marshal.h
-invalid.o: $(hdrdir)/ruby/internal/intern/numeric.h
-invalid.o: $(hdrdir)/ruby/internal/intern/object.h
-invalid.o: $(hdrdir)/ruby/internal/intern/parse.h
-invalid.o: $(hdrdir)/ruby/internal/intern/proc.h
-invalid.o: $(hdrdir)/ruby/internal/intern/process.h
-invalid.o: $(hdrdir)/ruby/internal/intern/random.h
-invalid.o: $(hdrdir)/ruby/internal/intern/range.h
-invalid.o: $(hdrdir)/ruby/internal/intern/rational.h
-invalid.o: $(hdrdir)/ruby/internal/intern/re.h
-invalid.o: $(hdrdir)/ruby/internal/intern/ruby.h
-invalid.o: $(hdrdir)/ruby/internal/intern/select.h
-invalid.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-invalid.o: $(hdrdir)/ruby/internal/intern/signal.h
-invalid.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-invalid.o: $(hdrdir)/ruby/internal/intern/string.h
-invalid.o: $(hdrdir)/ruby/internal/intern/struct.h
-invalid.o: $(hdrdir)/ruby/internal/intern/thread.h
-invalid.o: $(hdrdir)/ruby/internal/intern/time.h
-invalid.o: $(hdrdir)/ruby/internal/intern/variable.h
-invalid.o: $(hdrdir)/ruby/internal/intern/vm.h
-invalid.o: $(hdrdir)/ruby/internal/interpreter.h
-invalid.o: $(hdrdir)/ruby/internal/iterator.h
-invalid.o: $(hdrdir)/ruby/internal/memory.h
-invalid.o: $(hdrdir)/ruby/internal/method.h
-invalid.o: $(hdrdir)/ruby/internal/module.h
-invalid.o: $(hdrdir)/ruby/internal/newobj.h
-invalid.o: $(hdrdir)/ruby/internal/scan_args.h
-invalid.o: $(hdrdir)/ruby/internal/special_consts.h
-invalid.o: $(hdrdir)/ruby/internal/static_assert.h
-invalid.o: $(hdrdir)/ruby/internal/stdalign.h
-invalid.o: $(hdrdir)/ruby/internal/stdbool.h
-invalid.o: $(hdrdir)/ruby/internal/stdckdint.h
-invalid.o: $(hdrdir)/ruby/internal/symbol.h
-invalid.o: $(hdrdir)/ruby/internal/value.h
-invalid.o: $(hdrdir)/ruby/internal/value_type.h
-invalid.o: $(hdrdir)/ruby/internal/variable.h
-invalid.o: $(hdrdir)/ruby/internal/warning_push.h
-invalid.o: $(hdrdir)/ruby/internal/xmalloc.h
-invalid.o: $(hdrdir)/ruby/missing.h
-invalid.o: $(hdrdir)/ruby/ruby.h
-invalid.o: $(hdrdir)/ruby/st.h
-invalid.o: $(hdrdir)/ruby/subst.h
-invalid.o: invalid.c
rb_fatal.o: $(RUBY_EXTCONF_H)
rb_fatal.o: $(arch_hdrdir)/ruby/config.h
rb_fatal.o: $(hdrdir)/ruby.h
@@ -373,7 +52,6 @@ rb_fatal.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rb_fatal.o: $(hdrdir)/ruby/internal/attr/noinline.h
rb_fatal.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rb_fatal.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rb_fatal.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rb_fatal.o: $(hdrdir)/ruby/internal/attr/pure.h
rb_fatal.o: $(hdrdir)/ruby/internal/attr/restrict.h
rb_fatal.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -433,6 +111,7 @@ rb_fatal.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/error.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/eval.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/file.h
+rb_fatal.o: $(hdrdir)/ruby/internal/intern/gc.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/hash.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/io.h
rb_fatal.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -463,12 +142,12 @@ rb_fatal.o: $(hdrdir)/ruby/internal/memory.h
rb_fatal.o: $(hdrdir)/ruby/internal/method.h
rb_fatal.o: $(hdrdir)/ruby/internal/module.h
rb_fatal.o: $(hdrdir)/ruby/internal/newobj.h
+rb_fatal.o: $(hdrdir)/ruby/internal/rgengc.h
rb_fatal.o: $(hdrdir)/ruby/internal/scan_args.h
rb_fatal.o: $(hdrdir)/ruby/internal/special_consts.h
rb_fatal.o: $(hdrdir)/ruby/internal/static_assert.h
rb_fatal.o: $(hdrdir)/ruby/internal/stdalign.h
rb_fatal.o: $(hdrdir)/ruby/internal/stdbool.h
-rb_fatal.o: $(hdrdir)/ruby/internal/stdckdint.h
rb_fatal.o: $(hdrdir)/ruby/internal/symbol.h
rb_fatal.o: $(hdrdir)/ruby/internal/value.h
rb_fatal.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/fatal/extconf.rb b/ext/-test-/fatal/extconf.rb
index ca51178a18..d5849c0733 100644
--- a/ext/-test-/fatal/extconf.rb
+++ b/ext/-test-/fatal/extconf.rb
@@ -1,3 +1,2 @@
# frozen_string_literal: false
-require_relative "../auto_ext.rb"
-auto_ext
+create_makefile("-test-/fatal/rb_fatal")
diff --git a/ext/-test-/fatal/init.c b/ext/-test-/fatal/init.c
deleted file mode 100644
index 3b71708789..0000000000
--- a/ext/-test-/fatal/init.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "ruby.h"
-
-#define init(n) {void Init_##n(VALUE klass); Init_##n(klass);}
-
-void
-Init_fatal(void)
-{
- VALUE klass = rb_define_module("Bug");
- TEST_INIT_FUNCS(init);
-}
diff --git a/ext/-test-/fatal/invalid.c b/ext/-test-/fatal/invalid.c
deleted file mode 100644
index f0726edb52..0000000000
--- a/ext/-test-/fatal/invalid.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <ruby.h>
-
-#if SIZEOF_LONG == SIZEOF_VOIDP
-# define NUM2PTR(x) (void *)NUM2ULONG(x)
-#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
-# define NUM2PTR(x) (void *)NUM2ULL(x)
-#endif
-
-static VALUE
-invalid_call(VALUE obj, VALUE address)
-{
- typedef VALUE (*func_type)(VALUE);
-
- return (*(func_type)NUM2PTR(address))(obj);
-}
-
-static VALUE
-invalid_access(VALUE obj, VALUE address)
-{
- return *(VALUE *)NUM2PTR(address) == obj ? Qtrue : Qfalse;
-}
-
-void
-Init_invalid(VALUE mBug)
-{
- rb_define_singleton_method(mBug, "invalid_call", invalid_call, 1);
- rb_define_singleton_method(mBug, "invalid_access", invalid_access, 1);
-}
diff --git a/ext/-test-/fatal/rb_fatal.c b/ext/-test-/fatal/rb_fatal.c
index 6c7bb89628..eedbc51f8b 100644
--- a/ext/-test-/fatal/rb_fatal.c
+++ b/ext/-test-/fatal/rb_fatal.c
@@ -13,7 +13,8 @@ ruby_fatal(VALUE obj, VALUE msg)
}
void
-Init_rb_fatal(VALUE mBug)
+Init_rb_fatal(void)
{
+ VALUE mBug = rb_define_module("Bug");
rb_define_singleton_method(mBug, "rb_fatal", ruby_fatal, 1);
}
diff --git a/ext/-test-/file/depend b/ext/-test-/file/depend
index e985f914b2..f0fffc2485 100644
--- a/ext/-test-/file/depend
+++ b/ext/-test-/file/depend
@@ -52,7 +52,6 @@ fs.o: $(hdrdir)/ruby/internal/attr/noexcept.h
fs.o: $(hdrdir)/ruby/internal/attr/noinline.h
fs.o: $(hdrdir)/ruby/internal/attr/nonnull.h
fs.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-fs.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
fs.o: $(hdrdir)/ruby/internal/attr/pure.h
fs.o: $(hdrdir)/ruby/internal/attr/restrict.h
fs.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -121,6 +120,7 @@ fs.o: $(hdrdir)/ruby/internal/intern/enumerator.h
fs.o: $(hdrdir)/ruby/internal/intern/error.h
fs.o: $(hdrdir)/ruby/internal/intern/eval.h
fs.o: $(hdrdir)/ruby/internal/intern/file.h
+fs.o: $(hdrdir)/ruby/internal/intern/gc.h
fs.o: $(hdrdir)/ruby/internal/intern/hash.h
fs.o: $(hdrdir)/ruby/internal/intern/io.h
fs.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -151,12 +151,12 @@ fs.o: $(hdrdir)/ruby/internal/memory.h
fs.o: $(hdrdir)/ruby/internal/method.h
fs.o: $(hdrdir)/ruby/internal/module.h
fs.o: $(hdrdir)/ruby/internal/newobj.h
+fs.o: $(hdrdir)/ruby/internal/rgengc.h
fs.o: $(hdrdir)/ruby/internal/scan_args.h
fs.o: $(hdrdir)/ruby/internal/special_consts.h
fs.o: $(hdrdir)/ruby/internal/static_assert.h
fs.o: $(hdrdir)/ruby/internal/stdalign.h
fs.o: $(hdrdir)/ruby/internal/stdbool.h
-fs.o: $(hdrdir)/ruby/internal/stdckdint.h
fs.o: $(hdrdir)/ruby/internal/symbol.h
fs.o: $(hdrdir)/ruby/internal/value.h
fs.o: $(hdrdir)/ruby/internal/value_type.h
@@ -224,7 +224,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -284,6 +283,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -314,12 +314,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -331,178 +331,6 @@ init.o: $(hdrdir)/ruby/ruby.h
init.o: $(hdrdir)/ruby/st.h
init.o: $(hdrdir)/ruby/subst.h
init.o: init.c
-newline_conv.o: $(RUBY_EXTCONF_H)
-newline_conv.o: $(arch_hdrdir)/ruby/config.h
-newline_conv.o: $(hdrdir)/ruby/assert.h
-newline_conv.o: $(hdrdir)/ruby/backward.h
-newline_conv.o: $(hdrdir)/ruby/backward/2/assume.h
-newline_conv.o: $(hdrdir)/ruby/backward/2/attributes.h
-newline_conv.o: $(hdrdir)/ruby/backward/2/bool.h
-newline_conv.o: $(hdrdir)/ruby/backward/2/inttypes.h
-newline_conv.o: $(hdrdir)/ruby/backward/2/limits.h
-newline_conv.o: $(hdrdir)/ruby/backward/2/long_long.h
-newline_conv.o: $(hdrdir)/ruby/backward/2/stdalign.h
-newline_conv.o: $(hdrdir)/ruby/backward/2/stdarg.h
-newline_conv.o: $(hdrdir)/ruby/defines.h
-newline_conv.o: $(hdrdir)/ruby/encoding.h
-newline_conv.o: $(hdrdir)/ruby/intern.h
-newline_conv.o: $(hdrdir)/ruby/internal/abi.h
-newline_conv.o: $(hdrdir)/ruby/internal/anyargs.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-newline_conv.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-newline_conv.o: $(hdrdir)/ruby/internal/assume.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/artificial.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/cold.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/const.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/error.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/format.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/noalias.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/noinline.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/pure.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/restrict.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/warning.h
-newline_conv.o: $(hdrdir)/ruby/internal/attr/weakref.h
-newline_conv.o: $(hdrdir)/ruby/internal/cast.h
-newline_conv.o: $(hdrdir)/ruby/internal/compiler_is.h
-newline_conv.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-newline_conv.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-newline_conv.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-newline_conv.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-newline_conv.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-newline_conv.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-newline_conv.o: $(hdrdir)/ruby/internal/compiler_since.h
-newline_conv.o: $(hdrdir)/ruby/internal/config.h
-newline_conv.o: $(hdrdir)/ruby/internal/constant_p.h
-newline_conv.o: $(hdrdir)/ruby/internal/core.h
-newline_conv.o: $(hdrdir)/ruby/internal/core/rarray.h
-newline_conv.o: $(hdrdir)/ruby/internal/core/rbasic.h
-newline_conv.o: $(hdrdir)/ruby/internal/core/rbignum.h
-newline_conv.o: $(hdrdir)/ruby/internal/core/rclass.h
-newline_conv.o: $(hdrdir)/ruby/internal/core/rdata.h
-newline_conv.o: $(hdrdir)/ruby/internal/core/rfile.h
-newline_conv.o: $(hdrdir)/ruby/internal/core/rhash.h
-newline_conv.o: $(hdrdir)/ruby/internal/core/robject.h
-newline_conv.o: $(hdrdir)/ruby/internal/core/rregexp.h
-newline_conv.o: $(hdrdir)/ruby/internal/core/rstring.h
-newline_conv.o: $(hdrdir)/ruby/internal/core/rstruct.h
-newline_conv.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-newline_conv.o: $(hdrdir)/ruby/internal/ctype.h
-newline_conv.o: $(hdrdir)/ruby/internal/dllexport.h
-newline_conv.o: $(hdrdir)/ruby/internal/dosish.h
-newline_conv.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-newline_conv.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-newline_conv.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-newline_conv.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-newline_conv.o: $(hdrdir)/ruby/internal/encoding/re.h
-newline_conv.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-newline_conv.o: $(hdrdir)/ruby/internal/encoding/string.h
-newline_conv.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-newline_conv.o: $(hdrdir)/ruby/internal/encoding/transcode.h
-newline_conv.o: $(hdrdir)/ruby/internal/error.h
-newline_conv.o: $(hdrdir)/ruby/internal/eval.h
-newline_conv.o: $(hdrdir)/ruby/internal/event.h
-newline_conv.o: $(hdrdir)/ruby/internal/fl_type.h
-newline_conv.o: $(hdrdir)/ruby/internal/gc.h
-newline_conv.o: $(hdrdir)/ruby/internal/glob.h
-newline_conv.o: $(hdrdir)/ruby/internal/globals.h
-newline_conv.o: $(hdrdir)/ruby/internal/has/attribute.h
-newline_conv.o: $(hdrdir)/ruby/internal/has/builtin.h
-newline_conv.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-newline_conv.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-newline_conv.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-newline_conv.o: $(hdrdir)/ruby/internal/has/extension.h
-newline_conv.o: $(hdrdir)/ruby/internal/has/feature.h
-newline_conv.o: $(hdrdir)/ruby/internal/has/warning.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/array.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/bignum.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/class.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/compar.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/complex.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/cont.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/dir.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/enum.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/error.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/eval.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/file.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/hash.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/io.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/load.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/marshal.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/numeric.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/object.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/parse.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/proc.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/process.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/random.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/range.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/rational.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/re.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/ruby.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/select.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/signal.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/string.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/struct.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/thread.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/time.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/variable.h
-newline_conv.o: $(hdrdir)/ruby/internal/intern/vm.h
-newline_conv.o: $(hdrdir)/ruby/internal/interpreter.h
-newline_conv.o: $(hdrdir)/ruby/internal/iterator.h
-newline_conv.o: $(hdrdir)/ruby/internal/memory.h
-newline_conv.o: $(hdrdir)/ruby/internal/method.h
-newline_conv.o: $(hdrdir)/ruby/internal/module.h
-newline_conv.o: $(hdrdir)/ruby/internal/newobj.h
-newline_conv.o: $(hdrdir)/ruby/internal/scan_args.h
-newline_conv.o: $(hdrdir)/ruby/internal/special_consts.h
-newline_conv.o: $(hdrdir)/ruby/internal/static_assert.h
-newline_conv.o: $(hdrdir)/ruby/internal/stdalign.h
-newline_conv.o: $(hdrdir)/ruby/internal/stdbool.h
-newline_conv.o: $(hdrdir)/ruby/internal/stdckdint.h
-newline_conv.o: $(hdrdir)/ruby/internal/symbol.h
-newline_conv.o: $(hdrdir)/ruby/internal/value.h
-newline_conv.o: $(hdrdir)/ruby/internal/value_type.h
-newline_conv.o: $(hdrdir)/ruby/internal/variable.h
-newline_conv.o: $(hdrdir)/ruby/internal/warning_push.h
-newline_conv.o: $(hdrdir)/ruby/internal/xmalloc.h
-newline_conv.o: $(hdrdir)/ruby/io.h
-newline_conv.o: $(hdrdir)/ruby/missing.h
-newline_conv.o: $(hdrdir)/ruby/onigmo.h
-newline_conv.o: $(hdrdir)/ruby/oniguruma.h
-newline_conv.o: $(hdrdir)/ruby/ruby.h
-newline_conv.o: $(hdrdir)/ruby/st.h
-newline_conv.o: $(hdrdir)/ruby/subst.h
-newline_conv.o: newline_conv.c
stat.o: $(RUBY_EXTCONF_H)
stat.o: $(arch_hdrdir)/ruby/config.h
stat.o: $(hdrdir)/ruby/assert.h
@@ -556,7 +384,6 @@ stat.o: $(hdrdir)/ruby/internal/attr/noexcept.h
stat.o: $(hdrdir)/ruby/internal/attr/noinline.h
stat.o: $(hdrdir)/ruby/internal/attr/nonnull.h
stat.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-stat.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
stat.o: $(hdrdir)/ruby/internal/attr/pure.h
stat.o: $(hdrdir)/ruby/internal/attr/restrict.h
stat.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -625,6 +452,7 @@ stat.o: $(hdrdir)/ruby/internal/intern/enumerator.h
stat.o: $(hdrdir)/ruby/internal/intern/error.h
stat.o: $(hdrdir)/ruby/internal/intern/eval.h
stat.o: $(hdrdir)/ruby/internal/intern/file.h
+stat.o: $(hdrdir)/ruby/internal/intern/gc.h
stat.o: $(hdrdir)/ruby/internal/intern/hash.h
stat.o: $(hdrdir)/ruby/internal/intern/io.h
stat.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -655,12 +483,12 @@ stat.o: $(hdrdir)/ruby/internal/memory.h
stat.o: $(hdrdir)/ruby/internal/method.h
stat.o: $(hdrdir)/ruby/internal/module.h
stat.o: $(hdrdir)/ruby/internal/newobj.h
+stat.o: $(hdrdir)/ruby/internal/rgengc.h
stat.o: $(hdrdir)/ruby/internal/scan_args.h
stat.o: $(hdrdir)/ruby/internal/special_consts.h
stat.o: $(hdrdir)/ruby/internal/static_assert.h
stat.o: $(hdrdir)/ruby/internal/stdalign.h
stat.o: $(hdrdir)/ruby/internal/stdbool.h
-stat.o: $(hdrdir)/ruby/internal/stdckdint.h
stat.o: $(hdrdir)/ruby/internal/symbol.h
stat.o: $(hdrdir)/ruby/internal/value.h
stat.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/file/newline_conv.c b/ext/-test-/file/newline_conv.c
deleted file mode 100644
index 2ac5aef801..0000000000
--- a/ext/-test-/file/newline_conv.c
+++ /dev/null
@@ -1,73 +0,0 @@
-#include "ruby/ruby.h"
-#include "ruby/io.h"
-#include <fcntl.h>
-
-static VALUE
-open_with_rb_file_open(VALUE self, VALUE filename, VALUE read_or_write, VALUE binary_or_text)
-{
- char fmode[3] = { 0 };
- if (rb_sym2id(read_or_write) == rb_intern("read")) {
- fmode[0] = 'r';
- }
- else if (rb_sym2id(read_or_write) == rb_intern("write")) {
- fmode[0] = 'w';
- }
- else {
- rb_raise(rb_eArgError, "read_or_write param must be :read or :write");
- }
-
- if (rb_sym2id(binary_or_text) == rb_intern("binary")) {
- fmode[1] = 'b';
- }
- else if (rb_sym2id(binary_or_text) == rb_intern("text")) {
-
- }
- else {
- rb_raise(rb_eArgError, "binary_or_text param must be :binary or :text");
- }
-
- return rb_file_open(StringValueCStr(filename), fmode);
-}
-
-static VALUE
-open_with_rb_io_fdopen(VALUE self, VALUE filename, VALUE read_or_write, VALUE binary_or_text)
-{
- int omode = 0;
- if (rb_sym2id(read_or_write) == rb_intern("read")) {
- omode |= O_RDONLY;
- }
- else if (rb_sym2id(read_or_write) == rb_intern("write")) {
- omode |= O_WRONLY;
- }
- else {
- rb_raise(rb_eArgError, "read_or_write param must be :read or :write");
- }
-
- if (rb_sym2id(binary_or_text) == rb_intern("binary")) {
-#ifdef O_BINARY
- omode |= O_BINARY;
-#endif
- }
- else if (rb_sym2id(binary_or_text) == rb_intern("text")) {
-
- }
- else {
- rb_raise(rb_eArgError, "binary_or_text param must be :binary or :text");
- }
-
- int fd = rb_cloexec_open(StringValueCStr(filename), omode, 0);
- if (fd < 0) {
- rb_raise(rb_eIOError, "failed to open the file");
- }
-
- rb_update_max_fd(fd);
- return rb_io_fdopen(fd, omode, StringValueCStr(filename));
-}
-
-void
-Init_newline_conv(VALUE module)
-{
- VALUE newline_conv = rb_define_module_under(module, "NewlineConv");
- rb_define_module_function(newline_conv, "rb_file_open", open_with_rb_file_open, 3);
- rb_define_module_function(newline_conv, "rb_io_fdopen", open_with_rb_io_fdopen, 3);
-}
diff --git a/ext/-test-/float/depend b/ext/-test-/float/depend
index 3e34818d5f..9391a445a3 100644
--- a/ext/-test-/float/depend
+++ b/ext/-test-/float/depend
@@ -55,7 +55,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -115,6 +114,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -145,12 +145,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -215,7 +215,6 @@ nextafter.o: $(hdrdir)/ruby/internal/attr/noexcept.h
nextafter.o: $(hdrdir)/ruby/internal/attr/noinline.h
nextafter.o: $(hdrdir)/ruby/internal/attr/nonnull.h
nextafter.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-nextafter.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
nextafter.o: $(hdrdir)/ruby/internal/attr/pure.h
nextafter.o: $(hdrdir)/ruby/internal/attr/restrict.h
nextafter.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -275,6 +274,7 @@ nextafter.o: $(hdrdir)/ruby/internal/intern/enumerator.h
nextafter.o: $(hdrdir)/ruby/internal/intern/error.h
nextafter.o: $(hdrdir)/ruby/internal/intern/eval.h
nextafter.o: $(hdrdir)/ruby/internal/intern/file.h
+nextafter.o: $(hdrdir)/ruby/internal/intern/gc.h
nextafter.o: $(hdrdir)/ruby/internal/intern/hash.h
nextafter.o: $(hdrdir)/ruby/internal/intern/io.h
nextafter.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -305,12 +305,12 @@ nextafter.o: $(hdrdir)/ruby/internal/memory.h
nextafter.o: $(hdrdir)/ruby/internal/method.h
nextafter.o: $(hdrdir)/ruby/internal/module.h
nextafter.o: $(hdrdir)/ruby/internal/newobj.h
+nextafter.o: $(hdrdir)/ruby/internal/rgengc.h
nextafter.o: $(hdrdir)/ruby/internal/scan_args.h
nextafter.o: $(hdrdir)/ruby/internal/special_consts.h
nextafter.o: $(hdrdir)/ruby/internal/static_assert.h
nextafter.o: $(hdrdir)/ruby/internal/stdalign.h
nextafter.o: $(hdrdir)/ruby/internal/stdbool.h
-nextafter.o: $(hdrdir)/ruby/internal/stdckdint.h
nextafter.o: $(hdrdir)/ruby/internal/symbol.h
nextafter.o: $(hdrdir)/ruby/internal/value.h
nextafter.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/funcall/depend b/ext/-test-/funcall/depend
index a5a30873ac..24e8c54bd9 100644
--- a/ext/-test-/funcall/depend
+++ b/ext/-test-/funcall/depend
@@ -52,7 +52,6 @@ funcall.o: $(hdrdir)/ruby/internal/attr/noexcept.h
funcall.o: $(hdrdir)/ruby/internal/attr/noinline.h
funcall.o: $(hdrdir)/ruby/internal/attr/nonnull.h
funcall.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-funcall.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
funcall.o: $(hdrdir)/ruby/internal/attr/pure.h
funcall.o: $(hdrdir)/ruby/internal/attr/restrict.h
funcall.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ funcall.o: $(hdrdir)/ruby/internal/intern/enumerator.h
funcall.o: $(hdrdir)/ruby/internal/intern/error.h
funcall.o: $(hdrdir)/ruby/internal/intern/eval.h
funcall.o: $(hdrdir)/ruby/internal/intern/file.h
+funcall.o: $(hdrdir)/ruby/internal/intern/gc.h
funcall.o: $(hdrdir)/ruby/internal/intern/hash.h
funcall.o: $(hdrdir)/ruby/internal/intern/io.h
funcall.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ funcall.o: $(hdrdir)/ruby/internal/memory.h
funcall.o: $(hdrdir)/ruby/internal/method.h
funcall.o: $(hdrdir)/ruby/internal/module.h
funcall.o: $(hdrdir)/ruby/internal/newobj.h
+funcall.o: $(hdrdir)/ruby/internal/rgengc.h
funcall.o: $(hdrdir)/ruby/internal/scan_args.h
funcall.o: $(hdrdir)/ruby/internal/special_consts.h
funcall.o: $(hdrdir)/ruby/internal/static_assert.h
funcall.o: $(hdrdir)/ruby/internal/stdalign.h
funcall.o: $(hdrdir)/ruby/internal/stdbool.h
-funcall.o: $(hdrdir)/ruby/internal/stdckdint.h
funcall.o: $(hdrdir)/ruby/internal/symbol.h
funcall.o: $(hdrdir)/ruby/internal/value.h
funcall.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/gvl/call_without_gvl/depend b/ext/-test-/gvl/call_without_gvl/depend
index 6463d4527d..cd184aa01c 100644
--- a/ext/-test-/gvl/call_without_gvl/depend
+++ b/ext/-test-/gvl/call_without_gvl/depend
@@ -51,7 +51,6 @@ call_without_gvl.o: $(hdrdir)/ruby/internal/attr/noexcept.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/noinline.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/nonnull.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-call_without_gvl.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/pure.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/restrict.h
call_without_gvl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ call_without_gvl.o: $(hdrdir)/ruby/internal/intern/enumerator.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/error.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/eval.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/file.h
+call_without_gvl.o: $(hdrdir)/ruby/internal/intern/gc.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/hash.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/io.h
call_without_gvl.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,12 +141,12 @@ call_without_gvl.o: $(hdrdir)/ruby/internal/memory.h
call_without_gvl.o: $(hdrdir)/ruby/internal/method.h
call_without_gvl.o: $(hdrdir)/ruby/internal/module.h
call_without_gvl.o: $(hdrdir)/ruby/internal/newobj.h
+call_without_gvl.o: $(hdrdir)/ruby/internal/rgengc.h
call_without_gvl.o: $(hdrdir)/ruby/internal/scan_args.h
call_without_gvl.o: $(hdrdir)/ruby/internal/special_consts.h
call_without_gvl.o: $(hdrdir)/ruby/internal/static_assert.h
call_without_gvl.o: $(hdrdir)/ruby/internal/stdalign.h
call_without_gvl.o: $(hdrdir)/ruby/internal/stdbool.h
-call_without_gvl.o: $(hdrdir)/ruby/internal/stdckdint.h
call_without_gvl.o: $(hdrdir)/ruby/internal/symbol.h
call_without_gvl.o: $(hdrdir)/ruby/internal/value.h
call_without_gvl.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/hash/depend b/ext/-test-/hash/depend
index 4bc4bfcdd6..a8bc47e640 100644
--- a/ext/-test-/hash/depend
+++ b/ext/-test-/hash/depend
@@ -52,7 +52,6 @@ delete.o: $(hdrdir)/ruby/internal/attr/noexcept.h
delete.o: $(hdrdir)/ruby/internal/attr/noinline.h
delete.o: $(hdrdir)/ruby/internal/attr/nonnull.h
delete.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-delete.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
delete.o: $(hdrdir)/ruby/internal/attr/pure.h
delete.o: $(hdrdir)/ruby/internal/attr/restrict.h
delete.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ delete.o: $(hdrdir)/ruby/internal/intern/enumerator.h
delete.o: $(hdrdir)/ruby/internal/intern/error.h
delete.o: $(hdrdir)/ruby/internal/intern/eval.h
delete.o: $(hdrdir)/ruby/internal/intern/file.h
+delete.o: $(hdrdir)/ruby/internal/intern/gc.h
delete.o: $(hdrdir)/ruby/internal/intern/hash.h
delete.o: $(hdrdir)/ruby/internal/intern/io.h
delete.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ delete.o: $(hdrdir)/ruby/internal/memory.h
delete.o: $(hdrdir)/ruby/internal/method.h
delete.o: $(hdrdir)/ruby/internal/module.h
delete.o: $(hdrdir)/ruby/internal/newobj.h
+delete.o: $(hdrdir)/ruby/internal/rgengc.h
delete.o: $(hdrdir)/ruby/internal/scan_args.h
delete.o: $(hdrdir)/ruby/internal/special_consts.h
delete.o: $(hdrdir)/ruby/internal/static_assert.h
delete.o: $(hdrdir)/ruby/internal/stdalign.h
delete.o: $(hdrdir)/ruby/internal/stdbool.h
-delete.o: $(hdrdir)/ruby/internal/stdckdint.h
delete.o: $(hdrdir)/ruby/internal/symbol.h
delete.o: $(hdrdir)/ruby/internal/value.h
delete.o: $(hdrdir)/ruby/internal/value_type.h
@@ -212,7 +212,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -272,6 +271,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -302,12 +302,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/integer/depend b/ext/-test-/integer/depend
index d89965e3d9..b12159f308 100644
--- a/ext/-test-/integer/depend
+++ b/ext/-test-/integer/depend
@@ -52,7 +52,6 @@ core_ext.o: $(hdrdir)/ruby/internal/attr/noexcept.h
core_ext.o: $(hdrdir)/ruby/internal/attr/noinline.h
core_ext.o: $(hdrdir)/ruby/internal/attr/nonnull.h
core_ext.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-core_ext.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
core_ext.o: $(hdrdir)/ruby/internal/attr/pure.h
core_ext.o: $(hdrdir)/ruby/internal/attr/restrict.h
core_ext.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ core_ext.o: $(hdrdir)/ruby/internal/intern/enumerator.h
core_ext.o: $(hdrdir)/ruby/internal/intern/error.h
core_ext.o: $(hdrdir)/ruby/internal/intern/eval.h
core_ext.o: $(hdrdir)/ruby/internal/intern/file.h
+core_ext.o: $(hdrdir)/ruby/internal/intern/gc.h
core_ext.o: $(hdrdir)/ruby/internal/intern/hash.h
core_ext.o: $(hdrdir)/ruby/internal/intern/io.h
core_ext.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ core_ext.o: $(hdrdir)/ruby/internal/memory.h
core_ext.o: $(hdrdir)/ruby/internal/method.h
core_ext.o: $(hdrdir)/ruby/internal/module.h
core_ext.o: $(hdrdir)/ruby/internal/newobj.h
+core_ext.o: $(hdrdir)/ruby/internal/rgengc.h
core_ext.o: $(hdrdir)/ruby/internal/scan_args.h
core_ext.o: $(hdrdir)/ruby/internal/special_consts.h
core_ext.o: $(hdrdir)/ruby/internal/static_assert.h
core_ext.o: $(hdrdir)/ruby/internal/stdalign.h
core_ext.o: $(hdrdir)/ruby/internal/stdbool.h
-core_ext.o: $(hdrdir)/ruby/internal/stdckdint.h
core_ext.o: $(hdrdir)/ruby/internal/symbol.h
core_ext.o: $(hdrdir)/ruby/internal/value.h
core_ext.o: $(hdrdir)/ruby/internal/value_type.h
@@ -220,7 +220,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -280,6 +279,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -310,12 +310,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -380,7 +380,6 @@ my_integer.o: $(hdrdir)/ruby/internal/attr/noexcept.h
my_integer.o: $(hdrdir)/ruby/internal/attr/noinline.h
my_integer.o: $(hdrdir)/ruby/internal/attr/nonnull.h
my_integer.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-my_integer.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
my_integer.o: $(hdrdir)/ruby/internal/attr/pure.h
my_integer.o: $(hdrdir)/ruby/internal/attr/restrict.h
my_integer.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -440,6 +439,7 @@ my_integer.o: $(hdrdir)/ruby/internal/intern/enumerator.h
my_integer.o: $(hdrdir)/ruby/internal/intern/error.h
my_integer.o: $(hdrdir)/ruby/internal/intern/eval.h
my_integer.o: $(hdrdir)/ruby/internal/intern/file.h
+my_integer.o: $(hdrdir)/ruby/internal/intern/gc.h
my_integer.o: $(hdrdir)/ruby/internal/intern/hash.h
my_integer.o: $(hdrdir)/ruby/internal/intern/io.h
my_integer.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -470,12 +470,12 @@ my_integer.o: $(hdrdir)/ruby/internal/memory.h
my_integer.o: $(hdrdir)/ruby/internal/method.h
my_integer.o: $(hdrdir)/ruby/internal/module.h
my_integer.o: $(hdrdir)/ruby/internal/newobj.h
+my_integer.o: $(hdrdir)/ruby/internal/rgengc.h
my_integer.o: $(hdrdir)/ruby/internal/scan_args.h
my_integer.o: $(hdrdir)/ruby/internal/special_consts.h
my_integer.o: $(hdrdir)/ruby/internal/static_assert.h
my_integer.o: $(hdrdir)/ruby/internal/stdalign.h
my_integer.o: $(hdrdir)/ruby/internal/stdbool.h
-my_integer.o: $(hdrdir)/ruby/internal/stdckdint.h
my_integer.o: $(hdrdir)/ruby/internal/symbol.h
my_integer.o: $(hdrdir)/ruby/internal/value.h
my_integer.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/integer/my_integer.c b/ext/-test-/integer/my_integer.c
index 94f14d2765..d86474bd7d 100644
--- a/ext/-test-/integer/my_integer.c
+++ b/ext/-test-/integer/my_integer.c
@@ -1,13 +1,9 @@
#include "ruby.h"
-static const rb_data_type_t my_integer_type = {
- "MyInteger", {0}, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
-};
-
static VALUE
my_integer_s_new(VALUE klass)
{
- return TypedData_Wrap_Struct(klass, &my_integer_type, 0);
+ return Data_Wrap_Struct(klass, 0, 0, 0);
}
void
diff --git a/ext/-test-/iseq_load/depend b/ext/-test-/iseq_load/depend
index fd07b3199c..308956550c 100644
--- a/ext/-test-/iseq_load/depend
+++ b/ext/-test-/iseq_load/depend
@@ -52,7 +52,6 @@ iseq_load.o: $(hdrdir)/ruby/internal/attr/noexcept.h
iseq_load.o: $(hdrdir)/ruby/internal/attr/noinline.h
iseq_load.o: $(hdrdir)/ruby/internal/attr/nonnull.h
iseq_load.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-iseq_load.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
iseq_load.o: $(hdrdir)/ruby/internal/attr/pure.h
iseq_load.o: $(hdrdir)/ruby/internal/attr/restrict.h
iseq_load.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ iseq_load.o: $(hdrdir)/ruby/internal/intern/enumerator.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/error.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/eval.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/file.h
+iseq_load.o: $(hdrdir)/ruby/internal/intern/gc.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/hash.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/io.h
iseq_load.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ iseq_load.o: $(hdrdir)/ruby/internal/memory.h
iseq_load.o: $(hdrdir)/ruby/internal/method.h
iseq_load.o: $(hdrdir)/ruby/internal/module.h
iseq_load.o: $(hdrdir)/ruby/internal/newobj.h
+iseq_load.o: $(hdrdir)/ruby/internal/rgengc.h
iseq_load.o: $(hdrdir)/ruby/internal/scan_args.h
iseq_load.o: $(hdrdir)/ruby/internal/special_consts.h
iseq_load.o: $(hdrdir)/ruby/internal/static_assert.h
iseq_load.o: $(hdrdir)/ruby/internal/stdalign.h
iseq_load.o: $(hdrdir)/ruby/internal/stdbool.h
-iseq_load.o: $(hdrdir)/ruby/internal/stdckdint.h
iseq_load.o: $(hdrdir)/ruby/internal/symbol.h
iseq_load.o: $(hdrdir)/ruby/internal/value.h
iseq_load.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/iter/depend b/ext/-test-/iter/depend
index cff4b1bb43..d14c164cd4 100644
--- a/ext/-test-/iter/depend
+++ b/ext/-test-/iter/depend
@@ -52,7 +52,6 @@ break.o: $(hdrdir)/ruby/internal/attr/noexcept.h
break.o: $(hdrdir)/ruby/internal/attr/noinline.h
break.o: $(hdrdir)/ruby/internal/attr/nonnull.h
break.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-break.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
break.o: $(hdrdir)/ruby/internal/attr/pure.h
break.o: $(hdrdir)/ruby/internal/attr/restrict.h
break.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ break.o: $(hdrdir)/ruby/internal/intern/enumerator.h
break.o: $(hdrdir)/ruby/internal/intern/error.h
break.o: $(hdrdir)/ruby/internal/intern/eval.h
break.o: $(hdrdir)/ruby/internal/intern/file.h
+break.o: $(hdrdir)/ruby/internal/intern/gc.h
break.o: $(hdrdir)/ruby/internal/intern/hash.h
break.o: $(hdrdir)/ruby/internal/intern/io.h
break.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ break.o: $(hdrdir)/ruby/internal/memory.h
break.o: $(hdrdir)/ruby/internal/method.h
break.o: $(hdrdir)/ruby/internal/module.h
break.o: $(hdrdir)/ruby/internal/newobj.h
+break.o: $(hdrdir)/ruby/internal/rgengc.h
break.o: $(hdrdir)/ruby/internal/scan_args.h
break.o: $(hdrdir)/ruby/internal/special_consts.h
break.o: $(hdrdir)/ruby/internal/static_assert.h
break.o: $(hdrdir)/ruby/internal/stdalign.h
break.o: $(hdrdir)/ruby/internal/stdbool.h
-break.o: $(hdrdir)/ruby/internal/stdckdint.h
break.o: $(hdrdir)/ruby/internal/symbol.h
break.o: $(hdrdir)/ruby/internal/value.h
break.o: $(hdrdir)/ruby/internal/value_type.h
@@ -212,7 +212,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -272,6 +271,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -302,12 +302,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -372,7 +372,6 @@ yield.o: $(hdrdir)/ruby/internal/attr/noexcept.h
yield.o: $(hdrdir)/ruby/internal/attr/noinline.h
yield.o: $(hdrdir)/ruby/internal/attr/nonnull.h
yield.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-yield.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
yield.o: $(hdrdir)/ruby/internal/attr/pure.h
yield.o: $(hdrdir)/ruby/internal/attr/restrict.h
yield.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -432,6 +431,7 @@ yield.o: $(hdrdir)/ruby/internal/intern/enumerator.h
yield.o: $(hdrdir)/ruby/internal/intern/error.h
yield.o: $(hdrdir)/ruby/internal/intern/eval.h
yield.o: $(hdrdir)/ruby/internal/intern/file.h
+yield.o: $(hdrdir)/ruby/internal/intern/gc.h
yield.o: $(hdrdir)/ruby/internal/intern/hash.h
yield.o: $(hdrdir)/ruby/internal/intern/io.h
yield.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -462,12 +462,12 @@ yield.o: $(hdrdir)/ruby/internal/memory.h
yield.o: $(hdrdir)/ruby/internal/method.h
yield.o: $(hdrdir)/ruby/internal/module.h
yield.o: $(hdrdir)/ruby/internal/newobj.h
+yield.o: $(hdrdir)/ruby/internal/rgengc.h
yield.o: $(hdrdir)/ruby/internal/scan_args.h
yield.o: $(hdrdir)/ruby/internal/special_consts.h
yield.o: $(hdrdir)/ruby/internal/static_assert.h
yield.o: $(hdrdir)/ruby/internal/stdalign.h
yield.o: $(hdrdir)/ruby/internal/stdbool.h
-yield.o: $(hdrdir)/ruby/internal/stdckdint.h
yield.o: $(hdrdir)/ruby/internal/symbol.h
yield.o: $(hdrdir)/ruby/internal/value.h
yield.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/load/dot.dot/depend b/ext/-test-/load/dot.dot/depend
index f9be79e957..d8b8937c3c 100644
--- a/ext/-test-/load/dot.dot/depend
+++ b/ext/-test-/load/dot.dot/depend
@@ -52,7 +52,6 @@ dot.dot.o: $(hdrdir)/ruby/internal/attr/noexcept.h
dot.dot.o: $(hdrdir)/ruby/internal/attr/noinline.h
dot.dot.o: $(hdrdir)/ruby/internal/attr/nonnull.h
dot.dot.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-dot.dot.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
dot.dot.o: $(hdrdir)/ruby/internal/attr/pure.h
dot.dot.o: $(hdrdir)/ruby/internal/attr/restrict.h
dot.dot.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ dot.dot.o: $(hdrdir)/ruby/internal/intern/enumerator.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/error.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/eval.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/file.h
+dot.dot.o: $(hdrdir)/ruby/internal/intern/gc.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/hash.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/io.h
dot.dot.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ dot.dot.o: $(hdrdir)/ruby/internal/memory.h
dot.dot.o: $(hdrdir)/ruby/internal/method.h
dot.dot.o: $(hdrdir)/ruby/internal/module.h
dot.dot.o: $(hdrdir)/ruby/internal/newobj.h
+dot.dot.o: $(hdrdir)/ruby/internal/rgengc.h
dot.dot.o: $(hdrdir)/ruby/internal/scan_args.h
dot.dot.o: $(hdrdir)/ruby/internal/special_consts.h
dot.dot.o: $(hdrdir)/ruby/internal/static_assert.h
dot.dot.o: $(hdrdir)/ruby/internal/stdalign.h
dot.dot.o: $(hdrdir)/ruby/internal/stdbool.h
-dot.dot.o: $(hdrdir)/ruby/internal/stdckdint.h
dot.dot.o: $(hdrdir)/ruby/internal/symbol.h
dot.dot.o: $(hdrdir)/ruby/internal/value.h
dot.dot.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/load/protect/depend b/ext/-test-/load/protect/depend
index 324c17237a..dd4ee71b62 100644
--- a/ext/-test-/load/protect/depend
+++ b/ext/-test-/load/protect/depend
@@ -52,7 +52,6 @@ protect.o: $(hdrdir)/ruby/internal/attr/noexcept.h
protect.o: $(hdrdir)/ruby/internal/attr/noinline.h
protect.o: $(hdrdir)/ruby/internal/attr/nonnull.h
protect.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-protect.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
protect.o: $(hdrdir)/ruby/internal/attr/pure.h
protect.o: $(hdrdir)/ruby/internal/attr/restrict.h
protect.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ protect.o: $(hdrdir)/ruby/internal/intern/enumerator.h
protect.o: $(hdrdir)/ruby/internal/intern/error.h
protect.o: $(hdrdir)/ruby/internal/intern/eval.h
protect.o: $(hdrdir)/ruby/internal/intern/file.h
+protect.o: $(hdrdir)/ruby/internal/intern/gc.h
protect.o: $(hdrdir)/ruby/internal/intern/hash.h
protect.o: $(hdrdir)/ruby/internal/intern/io.h
protect.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ protect.o: $(hdrdir)/ruby/internal/memory.h
protect.o: $(hdrdir)/ruby/internal/method.h
protect.o: $(hdrdir)/ruby/internal/module.h
protect.o: $(hdrdir)/ruby/internal/newobj.h
+protect.o: $(hdrdir)/ruby/internal/rgengc.h
protect.o: $(hdrdir)/ruby/internal/scan_args.h
protect.o: $(hdrdir)/ruby/internal/special_consts.h
protect.o: $(hdrdir)/ruby/internal/static_assert.h
protect.o: $(hdrdir)/ruby/internal/stdalign.h
protect.o: $(hdrdir)/ruby/internal/stdbool.h
-protect.o: $(hdrdir)/ruby/internal/stdckdint.h
protect.o: $(hdrdir)/ruby/internal/symbol.h
protect.o: $(hdrdir)/ruby/internal/value.h
protect.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/load/resolve_symbol_resolver/extconf.rb b/ext/-test-/load/resolve_symbol_resolver/extconf.rb
deleted file mode 100644
index 2299efcfd3..0000000000
--- a/ext/-test-/load/resolve_symbol_resolver/extconf.rb
+++ /dev/null
@@ -1 +0,0 @@
-create_makefile('-test-/load/resolve_symbol_resolver')
diff --git a/ext/-test-/load/resolve_symbol_resolver/resolve_symbol_resolver.c b/ext/-test-/load/resolve_symbol_resolver/resolve_symbol_resolver.c
deleted file mode 100644
index a856319cfb..0000000000
--- a/ext/-test-/load/resolve_symbol_resolver/resolve_symbol_resolver.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <ruby.h>
-#include "ruby/internal/intern/load.h"
-
-typedef VALUE(*target_func)(VALUE);
-
-static target_func rst_any_method;
-
-VALUE
-rsr_any_method(VALUE klass)
-{
- return rst_any_method((VALUE)NULL);
-}
-
-VALUE
-rsr_try_resolve_fname(VALUE klass)
-{
- target_func rst_something_missing =
- (target_func) rb_ext_resolve_symbol("-test-/load/resolve_symbol_missing", "rst_any_method");
- if (rst_something_missing == NULL) {
- // This should be done in Init_*, so the error is LoadError
- rb_raise(rb_eLoadError, "symbol not found: missing fname");
- }
- return Qtrue;
-}
-
-VALUE
-rsr_try_resolve_sname(VALUE klass)
-{
- target_func rst_something_missing =
- (target_func)rb_ext_resolve_symbol("-test-/load/resolve_symbol_target", "rst_something_missing");
- if (rst_something_missing == NULL) {
- // This should be done in Init_*, so the error is LoadError
- rb_raise(rb_eLoadError, "symbol not found: missing sname");
- }
- return Qtrue;
-}
-
-void
-Init_resolve_symbol_resolver(void)
-{
- /*
- * Resolving symbols at the head of Init_ because it raises LoadError (in cases).
- * If the module and methods are defined before raising LoadError, retrying `require "this.so"` will
- * cause re-defining those methods (and will be warned).
- */
- rst_any_method = (target_func)rb_ext_resolve_symbol("-test-/load/resolve_symbol_target", "rst_any_method");
- if (rst_any_method == NULL) {
- rb_raise(rb_eLoadError, "resolve_symbol_target is not loaded");
- }
-
- VALUE mod = rb_define_module("ResolveSymbolResolver");
- rb_define_singleton_method(mod, "any_method", rsr_any_method, 0);
- rb_define_singleton_method(mod, "try_resolve_fname", rsr_try_resolve_fname, 0);
- rb_define_singleton_method(mod, "try_resolve_sname", rsr_try_resolve_sname, 0);
-}
diff --git a/ext/-test-/load/resolve_symbol_target/extconf.rb b/ext/-test-/load/resolve_symbol_target/extconf.rb
deleted file mode 100644
index b5a99ca7f1..0000000000
--- a/ext/-test-/load/resolve_symbol_target/extconf.rb
+++ /dev/null
@@ -1 +0,0 @@
-create_makefile('-test-/load/resolve_symbol_target')
diff --git a/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.c b/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.c
deleted file mode 100644
index b5bc9e8ee0..0000000000
--- a/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <ruby.h>
-#include "resolve_symbol_target.h"
-
-VALUE
-rst_any_method(VALUE klass)
-{
- return rb_str_new_cstr("from target");
-}
-
-void
-Init_resolve_symbol_target(void)
-{
- VALUE mod = rb_define_module("ResolveSymbolTarget");
- rb_define_singleton_method(mod, "any_method", rst_any_method, 0);
-}
diff --git a/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.h b/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.h
deleted file mode 100644
index 847dcb7dd3..0000000000
--- a/ext/-test-/load/resolve_symbol_target/resolve_symbol_target.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#include <ruby.h>
-#include "ruby/internal/dllexport.h"
-
-RUBY_FUNC_EXPORTED VALUE rst_any_method(VALUE);
diff --git a/ext/-test-/load/stringify_symbols/extconf.rb b/ext/-test-/load/stringify_symbols/extconf.rb
deleted file mode 100644
index ac39c15f09..0000000000
--- a/ext/-test-/load/stringify_symbols/extconf.rb
+++ /dev/null
@@ -1 +0,0 @@
-create_makefile('-test-/load/stringify_symbols')
diff --git a/ext/-test-/load/stringify_symbols/stringify_symbols.c b/ext/-test-/load/stringify_symbols/stringify_symbols.c
deleted file mode 100644
index 11a5ee3bc5..0000000000
--- a/ext/-test-/load/stringify_symbols/stringify_symbols.c
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <ruby.h>
-#include "ruby/internal/intern/load.h"
-#include "ruby/util.h"
-
-#if SIZEOF_INTPTR_T == SIZEOF_LONG_LONG
-# define UINTPTR2NUM ULL2NUM
-#elif SIZEOF_INTPTR_T == SIZEOF_LONG
-# define UINTPTR2NUM ULONG2NUM
-#else
-# define UINTPTR2NUM UINT2NUM
-#endif
-
-static VALUE
-stringify_symbol(VALUE klass, VALUE fname, VALUE sname)
-{
- void *ptr = rb_ext_resolve_symbol(StringValueCStr(fname), StringValueCStr(sname));
- if (ptr == NULL) {
- return Qnil;
- }
- uintptr_t uintptr = (uintptr_t)ptr;
- return UINTPTR2NUM(uintptr);
-}
-
-void
-Init_stringify_symbols(void)
-{
- VALUE mod = rb_define_module("StringifySymbols");
- rb_define_singleton_method(mod, "stringify_symbol", stringify_symbol, 2);
-}
diff --git a/ext/-test-/load/stringify_target/extconf.rb b/ext/-test-/load/stringify_target/extconf.rb
deleted file mode 100644
index 4aa201cb09..0000000000
--- a/ext/-test-/load/stringify_target/extconf.rb
+++ /dev/null
@@ -1 +0,0 @@
-create_makefile('-test-/load/stringify_target')
diff --git a/ext/-test-/load/stringify_target/stringify_target.c b/ext/-test-/load/stringify_target/stringify_target.c
deleted file mode 100644
index ce09b8fd77..0000000000
--- a/ext/-test-/load/stringify_target/stringify_target.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <ruby.h>
-#include "stringify_target.h"
-
-VALUE
-stt_any_method(VALUE klass)
-{
- return rb_str_new_cstr("from target");
-}
-
-void
-Init_stringify_target(void)
-{
- VALUE mod = rb_define_module("StringifyTarget");
- rb_define_singleton_method(mod, "any_method", stt_any_method, 0);
-}
diff --git a/ext/-test-/load/stringify_target/stringify_target.h b/ext/-test-/load/stringify_target/stringify_target.h
deleted file mode 100644
index d95fb65d7c..0000000000
--- a/ext/-test-/load/stringify_target/stringify_target.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#include <ruby.h>
-#include "ruby/internal/dllexport.h"
-
-RUBY_FUNC_EXPORTED VALUE stt_any_method(VALUE);
diff --git a/ext/-test-/marshal/compat/depend b/ext/-test-/marshal/compat/depend
index 8bcd9f8b5e..2c3ecf1ab9 100644
--- a/ext/-test-/marshal/compat/depend
+++ b/ext/-test-/marshal/compat/depend
@@ -52,7 +52,6 @@ usrcompat.o: $(hdrdir)/ruby/internal/attr/noexcept.h
usrcompat.o: $(hdrdir)/ruby/internal/attr/noinline.h
usrcompat.o: $(hdrdir)/ruby/internal/attr/nonnull.h
usrcompat.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-usrcompat.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
usrcompat.o: $(hdrdir)/ruby/internal/attr/pure.h
usrcompat.o: $(hdrdir)/ruby/internal/attr/restrict.h
usrcompat.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ usrcompat.o: $(hdrdir)/ruby/internal/intern/enumerator.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/error.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/eval.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/file.h
+usrcompat.o: $(hdrdir)/ruby/internal/intern/gc.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/hash.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/io.h
usrcompat.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ usrcompat.o: $(hdrdir)/ruby/internal/memory.h
usrcompat.o: $(hdrdir)/ruby/internal/method.h
usrcompat.o: $(hdrdir)/ruby/internal/module.h
usrcompat.o: $(hdrdir)/ruby/internal/newobj.h
+usrcompat.o: $(hdrdir)/ruby/internal/rgengc.h
usrcompat.o: $(hdrdir)/ruby/internal/scan_args.h
usrcompat.o: $(hdrdir)/ruby/internal/special_consts.h
usrcompat.o: $(hdrdir)/ruby/internal/static_assert.h
usrcompat.o: $(hdrdir)/ruby/internal/stdalign.h
usrcompat.o: $(hdrdir)/ruby/internal/stdbool.h
-usrcompat.o: $(hdrdir)/ruby/internal/stdckdint.h
usrcompat.o: $(hdrdir)/ruby/internal/symbol.h
usrcompat.o: $(hdrdir)/ruby/internal/value.h
usrcompat.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/marshal/internal_ivar/depend b/ext/-test-/marshal/internal_ivar/depend
index f8be031efc..cacb54a1a7 100644
--- a/ext/-test-/marshal/internal_ivar/depend
+++ b/ext/-test-/marshal/internal_ivar/depend
@@ -52,7 +52,6 @@ internal_ivar.o: $(hdrdir)/ruby/internal/attr/noexcept.h
internal_ivar.o: $(hdrdir)/ruby/internal/attr/noinline.h
internal_ivar.o: $(hdrdir)/ruby/internal/attr/nonnull.h
internal_ivar.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-internal_ivar.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
internal_ivar.o: $(hdrdir)/ruby/internal/attr/pure.h
internal_ivar.o: $(hdrdir)/ruby/internal/attr/restrict.h
internal_ivar.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ internal_ivar.o: $(hdrdir)/ruby/internal/intern/enumerator.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/error.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/eval.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/file.h
+internal_ivar.o: $(hdrdir)/ruby/internal/intern/gc.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/hash.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/io.h
internal_ivar.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ internal_ivar.o: $(hdrdir)/ruby/internal/memory.h
internal_ivar.o: $(hdrdir)/ruby/internal/method.h
internal_ivar.o: $(hdrdir)/ruby/internal/module.h
internal_ivar.o: $(hdrdir)/ruby/internal/newobj.h
+internal_ivar.o: $(hdrdir)/ruby/internal/rgengc.h
internal_ivar.o: $(hdrdir)/ruby/internal/scan_args.h
internal_ivar.o: $(hdrdir)/ruby/internal/special_consts.h
internal_ivar.o: $(hdrdir)/ruby/internal/static_assert.h
internal_ivar.o: $(hdrdir)/ruby/internal/stdalign.h
internal_ivar.o: $(hdrdir)/ruby/internal/stdbool.h
-internal_ivar.o: $(hdrdir)/ruby/internal/stdckdint.h
internal_ivar.o: $(hdrdir)/ruby/internal/symbol.h
internal_ivar.o: $(hdrdir)/ruby/internal/value.h
internal_ivar.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/marshal/usr/depend b/ext/-test-/marshal/usr/depend
index 09e8207d3a..717101cbcf 100644
--- a/ext/-test-/marshal/usr/depend
+++ b/ext/-test-/marshal/usr/depend
@@ -52,7 +52,6 @@ usrmarshal.o: $(hdrdir)/ruby/internal/attr/noexcept.h
usrmarshal.o: $(hdrdir)/ruby/internal/attr/noinline.h
usrmarshal.o: $(hdrdir)/ruby/internal/attr/nonnull.h
usrmarshal.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-usrmarshal.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
usrmarshal.o: $(hdrdir)/ruby/internal/attr/pure.h
usrmarshal.o: $(hdrdir)/ruby/internal/attr/restrict.h
usrmarshal.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ usrmarshal.o: $(hdrdir)/ruby/internal/intern/enumerator.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/error.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/eval.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/file.h
+usrmarshal.o: $(hdrdir)/ruby/internal/intern/gc.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/hash.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/io.h
usrmarshal.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ usrmarshal.o: $(hdrdir)/ruby/internal/memory.h
usrmarshal.o: $(hdrdir)/ruby/internal/method.h
usrmarshal.o: $(hdrdir)/ruby/internal/module.h
usrmarshal.o: $(hdrdir)/ruby/internal/newobj.h
+usrmarshal.o: $(hdrdir)/ruby/internal/rgengc.h
usrmarshal.o: $(hdrdir)/ruby/internal/scan_args.h
usrmarshal.o: $(hdrdir)/ruby/internal/special_consts.h
usrmarshal.o: $(hdrdir)/ruby/internal/static_assert.h
usrmarshal.o: $(hdrdir)/ruby/internal/stdalign.h
usrmarshal.o: $(hdrdir)/ruby/internal/stdbool.h
-usrmarshal.o: $(hdrdir)/ruby/internal/stdckdint.h
usrmarshal.o: $(hdrdir)/ruby/internal/symbol.h
usrmarshal.o: $(hdrdir)/ruby/internal/value.h
usrmarshal.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/memory_status/depend b/ext/-test-/memory_status/depend
index 52e2fe8e1f..a65fe66ae3 100644
--- a/ext/-test-/memory_status/depend
+++ b/ext/-test-/memory_status/depend
@@ -52,7 +52,6 @@ memory_status.o: $(hdrdir)/ruby/internal/attr/noexcept.h
memory_status.o: $(hdrdir)/ruby/internal/attr/noinline.h
memory_status.o: $(hdrdir)/ruby/internal/attr/nonnull.h
memory_status.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-memory_status.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
memory_status.o: $(hdrdir)/ruby/internal/attr/pure.h
memory_status.o: $(hdrdir)/ruby/internal/attr/restrict.h
memory_status.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ memory_status.o: $(hdrdir)/ruby/internal/intern/enumerator.h
memory_status.o: $(hdrdir)/ruby/internal/intern/error.h
memory_status.o: $(hdrdir)/ruby/internal/intern/eval.h
memory_status.o: $(hdrdir)/ruby/internal/intern/file.h
+memory_status.o: $(hdrdir)/ruby/internal/intern/gc.h
memory_status.o: $(hdrdir)/ruby/internal/intern/hash.h
memory_status.o: $(hdrdir)/ruby/internal/intern/io.h
memory_status.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,6 +142,7 @@ memory_status.o: $(hdrdir)/ruby/internal/memory.h
memory_status.o: $(hdrdir)/ruby/internal/method.h
memory_status.o: $(hdrdir)/ruby/internal/module.h
memory_status.o: $(hdrdir)/ruby/internal/newobj.h
+memory_status.o: $(hdrdir)/ruby/internal/rgengc.h
memory_status.o: $(hdrdir)/ruby/internal/scan_args.h
memory_status.o: $(hdrdir)/ruby/internal/special_consts.h
memory_status.o: $(hdrdir)/ruby/internal/static_assert.h
diff --git a/ext/-test-/memory_view/depend b/ext/-test-/memory_view/depend
index 0c92fc1236..7ce2d0374c 100644
--- a/ext/-test-/memory_view/depend
+++ b/ext/-test-/memory_view/depend
@@ -52,7 +52,6 @@ memory_view.o: $(hdrdir)/ruby/internal/attr/noexcept.h
memory_view.o: $(hdrdir)/ruby/internal/attr/noinline.h
memory_view.o: $(hdrdir)/ruby/internal/attr/nonnull.h
memory_view.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-memory_view.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
memory_view.o: $(hdrdir)/ruby/internal/attr/pure.h
memory_view.o: $(hdrdir)/ruby/internal/attr/restrict.h
memory_view.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ memory_view.o: $(hdrdir)/ruby/internal/intern/enumerator.h
memory_view.o: $(hdrdir)/ruby/internal/intern/error.h
memory_view.o: $(hdrdir)/ruby/internal/intern/eval.h
memory_view.o: $(hdrdir)/ruby/internal/intern/file.h
+memory_view.o: $(hdrdir)/ruby/internal/intern/gc.h
memory_view.o: $(hdrdir)/ruby/internal/intern/hash.h
memory_view.o: $(hdrdir)/ruby/internal/intern/io.h
memory_view.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ memory_view.o: $(hdrdir)/ruby/internal/memory.h
memory_view.o: $(hdrdir)/ruby/internal/method.h
memory_view.o: $(hdrdir)/ruby/internal/module.h
memory_view.o: $(hdrdir)/ruby/internal/newobj.h
+memory_view.o: $(hdrdir)/ruby/internal/rgengc.h
memory_view.o: $(hdrdir)/ruby/internal/scan_args.h
memory_view.o: $(hdrdir)/ruby/internal/special_consts.h
memory_view.o: $(hdrdir)/ruby/internal/static_assert.h
memory_view.o: $(hdrdir)/ruby/internal/stdalign.h
memory_view.o: $(hdrdir)/ruby/internal/stdbool.h
-memory_view.o: $(hdrdir)/ruby/internal/stdckdint.h
memory_view.o: $(hdrdir)/ruby/internal/symbol.h
memory_view.o: $(hdrdir)/ruby/internal/value.h
memory_view.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/memory_view/memory_view.c b/ext/-test-/memory_view/memory_view.c
index 63f0beb81e..c1df0353cf 100644
--- a/ext/-test-/memory_view/memory_view.c
+++ b/ext/-test-/memory_view/memory_view.c
@@ -313,8 +313,8 @@ mdview_get_memory_view(VALUE obj, rb_memory_view_t *view, int flags)
static bool
mdview_release_memory_view(VALUE obj, rb_memory_view_t *view)
{
- xfree((void *)view->shape);
- xfree((void *)view->strides);
+ if (view->shape) xfree((void *)view->shape);
+ if (view->strides) xfree((void *)view->strides);
return true;
}
diff --git a/ext/-test-/method/depend b/ext/-test-/method/depend
index dce2a815a4..85cf4d174a 100644
--- a/ext/-test-/method/depend
+++ b/ext/-test-/method/depend
@@ -52,7 +52,6 @@ arity.o: $(hdrdir)/ruby/internal/attr/noexcept.h
arity.o: $(hdrdir)/ruby/internal/attr/noinline.h
arity.o: $(hdrdir)/ruby/internal/attr/nonnull.h
arity.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-arity.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
arity.o: $(hdrdir)/ruby/internal/attr/pure.h
arity.o: $(hdrdir)/ruby/internal/attr/restrict.h
arity.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ arity.o: $(hdrdir)/ruby/internal/intern/enumerator.h
arity.o: $(hdrdir)/ruby/internal/intern/error.h
arity.o: $(hdrdir)/ruby/internal/intern/eval.h
arity.o: $(hdrdir)/ruby/internal/intern/file.h
+arity.o: $(hdrdir)/ruby/internal/intern/gc.h
arity.o: $(hdrdir)/ruby/internal/intern/hash.h
arity.o: $(hdrdir)/ruby/internal/intern/io.h
arity.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ arity.o: $(hdrdir)/ruby/internal/memory.h
arity.o: $(hdrdir)/ruby/internal/method.h
arity.o: $(hdrdir)/ruby/internal/module.h
arity.o: $(hdrdir)/ruby/internal/newobj.h
+arity.o: $(hdrdir)/ruby/internal/rgengc.h
arity.o: $(hdrdir)/ruby/internal/scan_args.h
arity.o: $(hdrdir)/ruby/internal/special_consts.h
arity.o: $(hdrdir)/ruby/internal/static_assert.h
arity.o: $(hdrdir)/ruby/internal/stdalign.h
arity.o: $(hdrdir)/ruby/internal/stdbool.h
-arity.o: $(hdrdir)/ruby/internal/stdckdint.h
arity.o: $(hdrdir)/ruby/internal/symbol.h
arity.o: $(hdrdir)/ruby/internal/value.h
arity.o: $(hdrdir)/ruby/internal/value_type.h
@@ -212,7 +212,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -272,6 +271,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -302,12 +302,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/notimplement/depend b/ext/-test-/notimplement/depend
index 84517a9c15..2303f47594 100644
--- a/ext/-test-/notimplement/depend
+++ b/ext/-test-/notimplement/depend
@@ -52,7 +52,6 @@ bug.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bug.o: $(hdrdir)/ruby/internal/attr/noinline.h
bug.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bug.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bug.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bug.o: $(hdrdir)/ruby/internal/attr/pure.h
bug.o: $(hdrdir)/ruby/internal/attr/restrict.h
bug.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ bug.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bug.o: $(hdrdir)/ruby/internal/intern/error.h
bug.o: $(hdrdir)/ruby/internal/intern/eval.h
bug.o: $(hdrdir)/ruby/internal/intern/file.h
+bug.o: $(hdrdir)/ruby/internal/intern/gc.h
bug.o: $(hdrdir)/ruby/internal/intern/hash.h
bug.o: $(hdrdir)/ruby/internal/intern/io.h
bug.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ bug.o: $(hdrdir)/ruby/internal/memory.h
bug.o: $(hdrdir)/ruby/internal/method.h
bug.o: $(hdrdir)/ruby/internal/module.h
bug.o: $(hdrdir)/ruby/internal/newobj.h
+bug.o: $(hdrdir)/ruby/internal/rgengc.h
bug.o: $(hdrdir)/ruby/internal/scan_args.h
bug.o: $(hdrdir)/ruby/internal/special_consts.h
bug.o: $(hdrdir)/ruby/internal/static_assert.h
bug.o: $(hdrdir)/ruby/internal/stdalign.h
bug.o: $(hdrdir)/ruby/internal/stdbool.h
-bug.o: $(hdrdir)/ruby/internal/stdckdint.h
bug.o: $(hdrdir)/ruby/internal/symbol.h
bug.o: $(hdrdir)/ruby/internal/value.h
bug.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/num2int/depend b/ext/-test-/num2int/depend
index 5550033be7..a3283838dd 100644
--- a/ext/-test-/num2int/depend
+++ b/ext/-test-/num2int/depend
@@ -52,7 +52,6 @@ num2int.o: $(hdrdir)/ruby/internal/attr/noexcept.h
num2int.o: $(hdrdir)/ruby/internal/attr/noinline.h
num2int.o: $(hdrdir)/ruby/internal/attr/nonnull.h
num2int.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-num2int.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
num2int.o: $(hdrdir)/ruby/internal/attr/pure.h
num2int.o: $(hdrdir)/ruby/internal/attr/restrict.h
num2int.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ num2int.o: $(hdrdir)/ruby/internal/intern/enumerator.h
num2int.o: $(hdrdir)/ruby/internal/intern/error.h
num2int.o: $(hdrdir)/ruby/internal/intern/eval.h
num2int.o: $(hdrdir)/ruby/internal/intern/file.h
+num2int.o: $(hdrdir)/ruby/internal/intern/gc.h
num2int.o: $(hdrdir)/ruby/internal/intern/hash.h
num2int.o: $(hdrdir)/ruby/internal/intern/io.h
num2int.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ num2int.o: $(hdrdir)/ruby/internal/memory.h
num2int.o: $(hdrdir)/ruby/internal/method.h
num2int.o: $(hdrdir)/ruby/internal/module.h
num2int.o: $(hdrdir)/ruby/internal/newobj.h
+num2int.o: $(hdrdir)/ruby/internal/rgengc.h
num2int.o: $(hdrdir)/ruby/internal/scan_args.h
num2int.o: $(hdrdir)/ruby/internal/special_consts.h
num2int.o: $(hdrdir)/ruby/internal/static_assert.h
num2int.o: $(hdrdir)/ruby/internal/stdalign.h
num2int.o: $(hdrdir)/ruby/internal/stdbool.h
-num2int.o: $(hdrdir)/ruby/internal/stdckdint.h
num2int.o: $(hdrdir)/ruby/internal/symbol.h
num2int.o: $(hdrdir)/ruby/internal/value.h
num2int.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/path_to_class/depend b/ext/-test-/path_to_class/depend
index a1657c9574..17f8e957c3 100644
--- a/ext/-test-/path_to_class/depend
+++ b/ext/-test-/path_to_class/depend
@@ -52,7 +52,6 @@ path_to_class.o: $(hdrdir)/ruby/internal/attr/noexcept.h
path_to_class.o: $(hdrdir)/ruby/internal/attr/noinline.h
path_to_class.o: $(hdrdir)/ruby/internal/attr/nonnull.h
path_to_class.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-path_to_class.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
path_to_class.o: $(hdrdir)/ruby/internal/attr/pure.h
path_to_class.o: $(hdrdir)/ruby/internal/attr/restrict.h
path_to_class.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ path_to_class.o: $(hdrdir)/ruby/internal/intern/enumerator.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/error.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/eval.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/file.h
+path_to_class.o: $(hdrdir)/ruby/internal/intern/gc.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/hash.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/io.h
path_to_class.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ path_to_class.o: $(hdrdir)/ruby/internal/memory.h
path_to_class.o: $(hdrdir)/ruby/internal/method.h
path_to_class.o: $(hdrdir)/ruby/internal/module.h
path_to_class.o: $(hdrdir)/ruby/internal/newobj.h
+path_to_class.o: $(hdrdir)/ruby/internal/rgengc.h
path_to_class.o: $(hdrdir)/ruby/internal/scan_args.h
path_to_class.o: $(hdrdir)/ruby/internal/special_consts.h
path_to_class.o: $(hdrdir)/ruby/internal/static_assert.h
path_to_class.o: $(hdrdir)/ruby/internal/stdalign.h
path_to_class.o: $(hdrdir)/ruby/internal/stdbool.h
-path_to_class.o: $(hdrdir)/ruby/internal/stdckdint.h
path_to_class.o: $(hdrdir)/ruby/internal/symbol.h
path_to_class.o: $(hdrdir)/ruby/internal/value.h
path_to_class.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/popen_deadlock/depend b/ext/-test-/popen_deadlock/depend
index 1904e64e59..22da87f2fe 100644
--- a/ext/-test-/popen_deadlock/depend
+++ b/ext/-test-/popen_deadlock/depend
@@ -52,7 +52,6 @@ infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/noexcept.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/noinline.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/nonnull.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/pure.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/restrict.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/enumerator.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/error.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/eval.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/file.h
+infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/gc.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/hash.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/io.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/memory.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/method.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/module.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/newobj.h
+infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/rgengc.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/scan_args.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/special_consts.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/static_assert.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/stdalign.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/stdbool.h
-infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/stdckdint.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/symbol.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/value.h
infinite_loop_dlsym.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/postponed_job/depend b/ext/-test-/postponed_job/depend
index 72250896b0..35aca7f2b0 100644
--- a/ext/-test-/postponed_job/depend
+++ b/ext/-test-/postponed_job/depend
@@ -53,7 +53,6 @@ postponed_job.o: $(hdrdir)/ruby/internal/attr/noexcept.h
postponed_job.o: $(hdrdir)/ruby/internal/attr/noinline.h
postponed_job.o: $(hdrdir)/ruby/internal/attr/nonnull.h
postponed_job.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-postponed_job.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
postponed_job.o: $(hdrdir)/ruby/internal/attr/pure.h
postponed_job.o: $(hdrdir)/ruby/internal/attr/restrict.h
postponed_job.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -113,6 +112,7 @@ postponed_job.o: $(hdrdir)/ruby/internal/intern/enumerator.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/error.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/eval.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/file.h
+postponed_job.o: $(hdrdir)/ruby/internal/intern/gc.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/hash.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/io.h
postponed_job.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -143,12 +143,12 @@ postponed_job.o: $(hdrdir)/ruby/internal/memory.h
postponed_job.o: $(hdrdir)/ruby/internal/method.h
postponed_job.o: $(hdrdir)/ruby/internal/module.h
postponed_job.o: $(hdrdir)/ruby/internal/newobj.h
+postponed_job.o: $(hdrdir)/ruby/internal/rgengc.h
postponed_job.o: $(hdrdir)/ruby/internal/scan_args.h
postponed_job.o: $(hdrdir)/ruby/internal/special_consts.h
postponed_job.o: $(hdrdir)/ruby/internal/static_assert.h
postponed_job.o: $(hdrdir)/ruby/internal/stdalign.h
postponed_job.o: $(hdrdir)/ruby/internal/stdbool.h
-postponed_job.o: $(hdrdir)/ruby/internal/stdckdint.h
postponed_job.o: $(hdrdir)/ruby/internal/symbol.h
postponed_job.o: $(hdrdir)/ruby/internal/value.h
postponed_job.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/postponed_job/postponed_job.c b/ext/-test-/postponed_job/postponed_job.c
index 9ac866ae77..fa57bef6f5 100644
--- a/ext/-test-/postponed_job/postponed_job.c
+++ b/ext/-test-/postponed_job/postponed_job.c
@@ -1,29 +1,6 @@
#include "ruby.h"
#include "ruby/debug.h"
-// We're testing deprecated things, don't print the compiler warnings
-#if 0
-
-#elif defined(_MSC_VER)
-#pragma warning(disable : 4996)
-
-#elif defined(__INTEL_COMPILER)
-#pragma warning(disable : 1786)
-
-#elif defined(__clang__)
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-
-#elif defined(__SUNPRO_CC)
-#pragma error_messages (off,symdeprecated)
-
-#else
-// :FIXME: improve here for your compiler.
-
-#endif
-
static int counter;
static void
@@ -81,22 +58,6 @@ pjob_call_direct(VALUE self, VALUE obj)
return self;
}
-static void pjob_noop_callback(void *data) { }
-
-static VALUE
-pjob_register_one_same(VALUE self)
-{
- rb_gc_start();
- int r1 = rb_postponed_job_register_one(0, pjob_noop_callback, NULL);
- int r2 = rb_postponed_job_register_one(0, pjob_noop_callback, NULL);
- int r3 = rb_postponed_job_register_one(0, pjob_noop_callback, NULL);
- VALUE ary = rb_ary_new();
- rb_ary_push(ary, INT2FIX(r1));
- rb_ary_push(ary, INT2FIX(r2));
- rb_ary_push(ary, INT2FIX(r3));
- return ary;
-}
-
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
@@ -125,93 +86,6 @@ pjob_register_in_c_thread(VALUE self, VALUE obj)
}
#endif
-static void
-pjob_preregistered_callback(void *data)
-{
- VALUE ary = (VALUE)data;
- Check_Type(ary, T_ARRAY);
- rb_ary_push(ary, INT2FIX(counter));
-}
-
-static VALUE
-pjob_preregister_and_call_with_sleep(VALUE self, VALUE obj)
-{
- counter = 0;
- rb_postponed_job_handle_t h = rb_postponed_job_preregister(0, pjob_preregistered_callback, (void *)obj);
- counter++;
- rb_postponed_job_trigger(h);
- rb_thread_sleep(0);
- counter++;
- rb_postponed_job_trigger(h);
- rb_thread_sleep(0);
- counter++;
- rb_postponed_job_trigger(h);
- rb_thread_sleep(0);
- return self;
-}
-
-static VALUE
-pjob_preregister_and_call_without_sleep(VALUE self, VALUE obj)
-{
- counter = 0;
- rb_postponed_job_handle_t h = rb_postponed_job_preregister(0, pjob_preregistered_callback, (void *)obj);
- counter = 3;
- rb_postponed_job_trigger(h);
- rb_postponed_job_trigger(h);
- rb_postponed_job_trigger(h);
- return self;
-}
-
-static VALUE
-pjob_preregister_multiple_times(VALUE self)
-{
- int r1 = rb_postponed_job_preregister(0, pjob_noop_callback, NULL);
- int r2 = rb_postponed_job_preregister(0, pjob_noop_callback, NULL);
- int r3 = rb_postponed_job_preregister(0, pjob_noop_callback, NULL);
- VALUE ary = rb_ary_new();
- rb_ary_push(ary, INT2FIX(r1));
- rb_ary_push(ary, INT2FIX(r2));
- rb_ary_push(ary, INT2FIX(r3));
- return ary;
-
-}
-
-struct pjob_append_data_args {
- VALUE ary;
- VALUE data;
-};
-
-static void
-pjob_append_data_callback(void *vctx) {
- struct pjob_append_data_args *ctx = (struct pjob_append_data_args *)vctx;
- Check_Type(ctx->ary, T_ARRAY);
- rb_ary_push(ctx->ary, ctx->data);
-}
-
-static VALUE
-pjob_preregister_calls_with_last_argument(VALUE self)
-{
- VALUE ary = rb_ary_new();
-
- struct pjob_append_data_args arg1 = { .ary = ary, .data = INT2FIX(1) };
- struct pjob_append_data_args arg2 = { .ary = ary, .data = INT2FIX(2) };
- struct pjob_append_data_args arg3 = { .ary = ary, .data = INT2FIX(3) };
- struct pjob_append_data_args arg4 = { .ary = ary, .data = INT2FIX(4) };
-
- rb_postponed_job_handle_t h;
- h = rb_postponed_job_preregister(0, pjob_append_data_callback, &arg1);
- rb_postponed_job_preregister(0, pjob_append_data_callback, &arg2);
- rb_postponed_job_trigger(h);
- rb_postponed_job_preregister(0, pjob_append_data_callback, &arg3);
- rb_thread_sleep(0); // should execute with arg3
-
- rb_postponed_job_preregister(0, pjob_append_data_callback, &arg4);
- rb_postponed_job_trigger(h);
- rb_thread_sleep(0); // should execute with arg4
-
- return ary;
-}
-
void
Init_postponed_job(VALUE self)
{
@@ -219,13 +93,8 @@ Init_postponed_job(VALUE self)
rb_define_module_function(mBug, "postponed_job_register", pjob_register, 1);
rb_define_module_function(mBug, "postponed_job_register_one", pjob_register_one, 1);
rb_define_module_function(mBug, "postponed_job_call_direct", pjob_call_direct, 1);
- rb_define_module_function(mBug, "postponed_job_register_one_same", pjob_register_one_same, 0);
#ifdef HAVE_PTHREAD_H
rb_define_module_function(mBug, "postponed_job_register_in_c_thread", pjob_register_in_c_thread, 1);
#endif
- rb_define_module_function(mBug, "postponed_job_preregister_and_call_with_sleep", pjob_preregister_and_call_with_sleep, 1);
- rb_define_module_function(mBug, "postponed_job_preregister_and_call_without_sleep", pjob_preregister_and_call_without_sleep, 1);
- rb_define_module_function(mBug, "postponed_job_preregister_multiple_times", pjob_preregister_multiple_times, 0);
- rb_define_module_function(mBug, "postponed_job_preregister_calls_with_last_argument", pjob_preregister_calls_with_last_argument, 0);
}
diff --git a/ext/-test-/printf/depend b/ext/-test-/printf/depend
index 0530df78bf..6dfe1fe03d 100644
--- a/ext/-test-/printf/depend
+++ b/ext/-test-/printf/depend
@@ -53,7 +53,6 @@ printf.o: $(hdrdir)/ruby/internal/attr/noexcept.h
printf.o: $(hdrdir)/ruby/internal/attr/noinline.h
printf.o: $(hdrdir)/ruby/internal/attr/nonnull.h
printf.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-printf.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
printf.o: $(hdrdir)/ruby/internal/attr/pure.h
printf.o: $(hdrdir)/ruby/internal/attr/restrict.h
printf.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ printf.o: $(hdrdir)/ruby/internal/intern/enumerator.h
printf.o: $(hdrdir)/ruby/internal/intern/error.h
printf.o: $(hdrdir)/ruby/internal/intern/eval.h
printf.o: $(hdrdir)/ruby/internal/intern/file.h
+printf.o: $(hdrdir)/ruby/internal/intern/gc.h
printf.o: $(hdrdir)/ruby/internal/intern/hash.h
printf.o: $(hdrdir)/ruby/internal/intern/io.h
printf.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,12 +152,12 @@ printf.o: $(hdrdir)/ruby/internal/memory.h
printf.o: $(hdrdir)/ruby/internal/method.h
printf.o: $(hdrdir)/ruby/internal/module.h
printf.o: $(hdrdir)/ruby/internal/newobj.h
+printf.o: $(hdrdir)/ruby/internal/rgengc.h
printf.o: $(hdrdir)/ruby/internal/scan_args.h
printf.o: $(hdrdir)/ruby/internal/special_consts.h
printf.o: $(hdrdir)/ruby/internal/static_assert.h
printf.o: $(hdrdir)/ruby/internal/stdalign.h
printf.o: $(hdrdir)/ruby/internal/stdbool.h
-printf.o: $(hdrdir)/ruby/internal/stdckdint.h
printf.o: $(hdrdir)/ruby/internal/symbol.h
printf.o: $(hdrdir)/ruby/internal/value.h
printf.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/proc/depend b/ext/-test-/proc/depend
index 45e12bcd09..e3f1cf6ce9 100644
--- a/ext/-test-/proc/depend
+++ b/ext/-test-/proc/depend
@@ -52,7 +52,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -212,7 +212,6 @@ receiver.o: $(hdrdir)/ruby/internal/attr/noexcept.h
receiver.o: $(hdrdir)/ruby/internal/attr/noinline.h
receiver.o: $(hdrdir)/ruby/internal/attr/nonnull.h
receiver.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-receiver.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
receiver.o: $(hdrdir)/ruby/internal/attr/pure.h
receiver.o: $(hdrdir)/ruby/internal/attr/restrict.h
receiver.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -272,6 +271,7 @@ receiver.o: $(hdrdir)/ruby/internal/intern/enumerator.h
receiver.o: $(hdrdir)/ruby/internal/intern/error.h
receiver.o: $(hdrdir)/ruby/internal/intern/eval.h
receiver.o: $(hdrdir)/ruby/internal/intern/file.h
+receiver.o: $(hdrdir)/ruby/internal/intern/gc.h
receiver.o: $(hdrdir)/ruby/internal/intern/hash.h
receiver.o: $(hdrdir)/ruby/internal/intern/io.h
receiver.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -302,12 +302,12 @@ receiver.o: $(hdrdir)/ruby/internal/memory.h
receiver.o: $(hdrdir)/ruby/internal/method.h
receiver.o: $(hdrdir)/ruby/internal/module.h
receiver.o: $(hdrdir)/ruby/internal/newobj.h
+receiver.o: $(hdrdir)/ruby/internal/rgengc.h
receiver.o: $(hdrdir)/ruby/internal/scan_args.h
receiver.o: $(hdrdir)/ruby/internal/special_consts.h
receiver.o: $(hdrdir)/ruby/internal/static_assert.h
receiver.o: $(hdrdir)/ruby/internal/stdalign.h
receiver.o: $(hdrdir)/ruby/internal/stdbool.h
-receiver.o: $(hdrdir)/ruby/internal/stdckdint.h
receiver.o: $(hdrdir)/ruby/internal/symbol.h
receiver.o: $(hdrdir)/ruby/internal/value.h
receiver.o: $(hdrdir)/ruby/internal/value_type.h
@@ -372,7 +372,6 @@ super.o: $(hdrdir)/ruby/internal/attr/noexcept.h
super.o: $(hdrdir)/ruby/internal/attr/noinline.h
super.o: $(hdrdir)/ruby/internal/attr/nonnull.h
super.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-super.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
super.o: $(hdrdir)/ruby/internal/attr/pure.h
super.o: $(hdrdir)/ruby/internal/attr/restrict.h
super.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -432,6 +431,7 @@ super.o: $(hdrdir)/ruby/internal/intern/enumerator.h
super.o: $(hdrdir)/ruby/internal/intern/error.h
super.o: $(hdrdir)/ruby/internal/intern/eval.h
super.o: $(hdrdir)/ruby/internal/intern/file.h
+super.o: $(hdrdir)/ruby/internal/intern/gc.h
super.o: $(hdrdir)/ruby/internal/intern/hash.h
super.o: $(hdrdir)/ruby/internal/intern/io.h
super.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -462,12 +462,12 @@ super.o: $(hdrdir)/ruby/internal/memory.h
super.o: $(hdrdir)/ruby/internal/method.h
super.o: $(hdrdir)/ruby/internal/module.h
super.o: $(hdrdir)/ruby/internal/newobj.h
+super.o: $(hdrdir)/ruby/internal/rgengc.h
super.o: $(hdrdir)/ruby/internal/scan_args.h
super.o: $(hdrdir)/ruby/internal/special_consts.h
super.o: $(hdrdir)/ruby/internal/static_assert.h
super.o: $(hdrdir)/ruby/internal/stdalign.h
super.o: $(hdrdir)/ruby/internal/stdbool.h
-super.o: $(hdrdir)/ruby/internal/stdckdint.h
super.o: $(hdrdir)/ruby/internal/symbol.h
super.o: $(hdrdir)/ruby/internal/value.h
super.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/public_header_warnings/extconf.rb b/ext/-test-/public_header_warnings/extconf.rb
deleted file mode 100644
index 4431e09da4..0000000000
--- a/ext/-test-/public_header_warnings/extconf.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Under compilers with WERRORFLAG, MakeMakefile.try_compile treats warnings as errors, so we can
-# use append_cflags to test whether the public header files emit warnings with certain flags turned
-# on.
-#
-def check_append_cflags(flag, msg = nil)
- msg ||= "flag #{flag} is not acceptable"
- if $CFLAGS.include?(flag)
- raise("flag #{flag} already present in $CFLAGS")
- end
- append_cflags(flag)
- unless $CFLAGS.include?(flag)
- system("cat mkmf.log")
- raise(msg)
- end
-end
-
-if %w[gcc clang].include?(RbConfig::CONFIG['CC'])
- config_string("WERRORFLAG") or raise("expected WERRORFLAG to be defined")
-
- # should be acceptable on all modern C compilers
- check_append_cflags("-D_TEST_OK", "baseline compiler warning test failed")
-
- # Feature #20507: Allow compilation of C extensions with -Wconversion
- check_append_cflags("-Wconversion", "-Wconversion raising warnings in public headers")
-end
-
-create_makefile("-test-/public_header_warnings")
diff --git a/ext/-test-/random/depend b/ext/-test-/random/depend
index 71f5f6e1e6..f2cbf7fc14 100644
--- a/ext/-test-/random/depend
+++ b/ext/-test-/random/depend
@@ -51,7 +51,6 @@ bad_version.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bad_version.o: $(hdrdir)/ruby/internal/attr/noinline.h
bad_version.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bad_version.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bad_version.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bad_version.o: $(hdrdir)/ruby/internal/attr/pure.h
bad_version.o: $(hdrdir)/ruby/internal/attr/restrict.h
bad_version.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ bad_version.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bad_version.o: $(hdrdir)/ruby/internal/intern/error.h
bad_version.o: $(hdrdir)/ruby/internal/intern/eval.h
bad_version.o: $(hdrdir)/ruby/internal/intern/file.h
+bad_version.o: $(hdrdir)/ruby/internal/intern/gc.h
bad_version.o: $(hdrdir)/ruby/internal/intern/hash.h
bad_version.o: $(hdrdir)/ruby/internal/intern/io.h
bad_version.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,12 +141,12 @@ bad_version.o: $(hdrdir)/ruby/internal/memory.h
bad_version.o: $(hdrdir)/ruby/internal/method.h
bad_version.o: $(hdrdir)/ruby/internal/module.h
bad_version.o: $(hdrdir)/ruby/internal/newobj.h
+bad_version.o: $(hdrdir)/ruby/internal/rgengc.h
bad_version.o: $(hdrdir)/ruby/internal/scan_args.h
bad_version.o: $(hdrdir)/ruby/internal/special_consts.h
bad_version.o: $(hdrdir)/ruby/internal/static_assert.h
bad_version.o: $(hdrdir)/ruby/internal/stdalign.h
bad_version.o: $(hdrdir)/ruby/internal/stdbool.h
-bad_version.o: $(hdrdir)/ruby/internal/stdckdint.h
bad_version.o: $(hdrdir)/ruby/internal/symbol.h
bad_version.o: $(hdrdir)/ruby/internal/value.h
bad_version.o: $(hdrdir)/ruby/internal/value_type.h
@@ -212,7 +212,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -272,6 +271,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -302,12 +302,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -371,7 +371,6 @@ loop.o: $(hdrdir)/ruby/internal/attr/noexcept.h
loop.o: $(hdrdir)/ruby/internal/attr/noinline.h
loop.o: $(hdrdir)/ruby/internal/attr/nonnull.h
loop.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-loop.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
loop.o: $(hdrdir)/ruby/internal/attr/pure.h
loop.o: $(hdrdir)/ruby/internal/attr/restrict.h
loop.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -431,6 +430,7 @@ loop.o: $(hdrdir)/ruby/internal/intern/enumerator.h
loop.o: $(hdrdir)/ruby/internal/intern/error.h
loop.o: $(hdrdir)/ruby/internal/intern/eval.h
loop.o: $(hdrdir)/ruby/internal/intern/file.h
+loop.o: $(hdrdir)/ruby/internal/intern/gc.h
loop.o: $(hdrdir)/ruby/internal/intern/hash.h
loop.o: $(hdrdir)/ruby/internal/intern/io.h
loop.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -461,12 +461,12 @@ loop.o: $(hdrdir)/ruby/internal/memory.h
loop.o: $(hdrdir)/ruby/internal/method.h
loop.o: $(hdrdir)/ruby/internal/module.h
loop.o: $(hdrdir)/ruby/internal/newobj.h
+loop.o: $(hdrdir)/ruby/internal/rgengc.h
loop.o: $(hdrdir)/ruby/internal/scan_args.h
loop.o: $(hdrdir)/ruby/internal/special_consts.h
loop.o: $(hdrdir)/ruby/internal/static_assert.h
loop.o: $(hdrdir)/ruby/internal/stdalign.h
loop.o: $(hdrdir)/ruby/internal/stdbool.h
-loop.o: $(hdrdir)/ruby/internal/stdckdint.h
loop.o: $(hdrdir)/ruby/internal/symbol.h
loop.o: $(hdrdir)/ruby/internal/value.h
loop.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/random/loop.c b/ext/-test-/random/loop.c
index f79e5cfd83..b789ab1d01 100644
--- a/ext/-test-/random/loop.c
+++ b/ext/-test-/random/loop.c
@@ -13,15 +13,6 @@ static const rb_random_interface_t random_loop_if = {
RB_RANDOM_INTERFACE_DEFINE_WITH_REAL(loop)
};
-static void
-loop_free(void *ptr)
-{
- rand_loop_t *r = ptr;
-
- xfree(r->buf);
- xfree(r);
-}
-
RB_RANDOM_DEFINE_INIT_INT32_FUNC(loop)
static size_t
random_loop_memsize(const void *ptr)
@@ -34,7 +25,7 @@ static rb_random_data_type_t random_loop_type = {
"random/loop",
{
rb_random_mark,
- loop_free,
+ RUBY_TYPED_DEFAULT_FREE,
random_loop_memsize,
},
RB_RANDOM_PARENT,
diff --git a/ext/-test-/rational/depend b/ext/-test-/rational/depend
index 363d779302..ce977821b8 100644
--- a/ext/-test-/rational/depend
+++ b/ext/-test-/rational/depend
@@ -56,7 +56,6 @@ rat.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rat.o: $(hdrdir)/ruby/internal/attr/noinline.h
rat.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rat.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rat.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rat.o: $(hdrdir)/ruby/internal/attr/pure.h
rat.o: $(hdrdir)/ruby/internal/attr/restrict.h
rat.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -116,6 +115,7 @@ rat.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rat.o: $(hdrdir)/ruby/internal/intern/error.h
rat.o: $(hdrdir)/ruby/internal/intern/eval.h
rat.o: $(hdrdir)/ruby/internal/intern/file.h
+rat.o: $(hdrdir)/ruby/internal/intern/gc.h
rat.o: $(hdrdir)/ruby/internal/intern/hash.h
rat.o: $(hdrdir)/ruby/internal/intern/io.h
rat.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -146,12 +146,12 @@ rat.o: $(hdrdir)/ruby/internal/memory.h
rat.o: $(hdrdir)/ruby/internal/method.h
rat.o: $(hdrdir)/ruby/internal/module.h
rat.o: $(hdrdir)/ruby/internal/newobj.h
+rat.o: $(hdrdir)/ruby/internal/rgengc.h
rat.o: $(hdrdir)/ruby/internal/scan_args.h
rat.o: $(hdrdir)/ruby/internal/special_consts.h
rat.o: $(hdrdir)/ruby/internal/static_assert.h
rat.o: $(hdrdir)/ruby/internal/stdalign.h
rat.o: $(hdrdir)/ruby/internal/stdbool.h
-rat.o: $(hdrdir)/ruby/internal/stdckdint.h
rat.o: $(hdrdir)/ruby/internal/symbol.h
rat.o: $(hdrdir)/ruby/internal/value.h
rat.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/rb_call_super_kw/depend b/ext/-test-/rb_call_super_kw/depend
index 04a0fac12c..3512a081c9 100644
--- a/ext/-test-/rb_call_super_kw/depend
+++ b/ext/-test-/rb_call_super_kw/depend
@@ -52,7 +52,6 @@ rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/noinline.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/pure.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/restrict.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/error.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/eval.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/file.h
+rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/gc.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/hash.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/io.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ rb_call_super_kw.o: $(hdrdir)/ruby/internal/memory.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/method.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/module.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/newobj.h
+rb_call_super_kw.o: $(hdrdir)/ruby/internal/rgengc.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/scan_args.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/special_consts.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/static_assert.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/stdalign.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/stdbool.h
-rb_call_super_kw.o: $(hdrdir)/ruby/internal/stdckdint.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/symbol.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/value.h
rb_call_super_kw.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/recursion/depend b/ext/-test-/recursion/depend
index 2a65c98b09..e499f95e73 100644
--- a/ext/-test-/recursion/depend
+++ b/ext/-test-/recursion/depend
@@ -52,7 +52,6 @@ recursion.o: $(hdrdir)/ruby/internal/attr/noexcept.h
recursion.o: $(hdrdir)/ruby/internal/attr/noinline.h
recursion.o: $(hdrdir)/ruby/internal/attr/nonnull.h
recursion.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-recursion.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
recursion.o: $(hdrdir)/ruby/internal/attr/pure.h
recursion.o: $(hdrdir)/ruby/internal/attr/restrict.h
recursion.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ recursion.o: $(hdrdir)/ruby/internal/intern/enumerator.h
recursion.o: $(hdrdir)/ruby/internal/intern/error.h
recursion.o: $(hdrdir)/ruby/internal/intern/eval.h
recursion.o: $(hdrdir)/ruby/internal/intern/file.h
+recursion.o: $(hdrdir)/ruby/internal/intern/gc.h
recursion.o: $(hdrdir)/ruby/internal/intern/hash.h
recursion.o: $(hdrdir)/ruby/internal/intern/io.h
recursion.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ recursion.o: $(hdrdir)/ruby/internal/memory.h
recursion.o: $(hdrdir)/ruby/internal/method.h
recursion.o: $(hdrdir)/ruby/internal/module.h
recursion.o: $(hdrdir)/ruby/internal/newobj.h
+recursion.o: $(hdrdir)/ruby/internal/rgengc.h
recursion.o: $(hdrdir)/ruby/internal/scan_args.h
recursion.o: $(hdrdir)/ruby/internal/special_consts.h
recursion.o: $(hdrdir)/ruby/internal/static_assert.h
recursion.o: $(hdrdir)/ruby/internal/stdalign.h
recursion.o: $(hdrdir)/ruby/internal/stdbool.h
-recursion.o: $(hdrdir)/ruby/internal/stdckdint.h
recursion.o: $(hdrdir)/ruby/internal/symbol.h
recursion.o: $(hdrdir)/ruby/internal/value.h
recursion.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/regexp/depend b/ext/-test-/regexp/depend
index 0127a66a2e..fa431e013a 100644
--- a/ext/-test-/regexp/depend
+++ b/ext/-test-/regexp/depend
@@ -52,7 +52,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -212,7 +212,6 @@ parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/noexcept.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/noinline.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/nonnull.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/pure.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/restrict.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -272,6 +271,7 @@ parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/enumerator.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/error.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/eval.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/file.h
+parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/gc.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/hash.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/io.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -302,12 +302,12 @@ parse_depth_limit.o: $(hdrdir)/ruby/internal/memory.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/method.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/module.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/newobj.h
+parse_depth_limit.o: $(hdrdir)/ruby/internal/rgengc.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/scan_args.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/special_consts.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/static_assert.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/stdalign.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/stdbool.h
-parse_depth_limit.o: $(hdrdir)/ruby/internal/stdckdint.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/symbol.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/value.h
parse_depth_limit.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/scan_args/depend b/ext/-test-/scan_args/depend
index 922e5bbd5c..2194936b04 100644
--- a/ext/-test-/scan_args/depend
+++ b/ext/-test-/scan_args/depend
@@ -52,7 +52,6 @@ scan_args.o: $(hdrdir)/ruby/internal/attr/noexcept.h
scan_args.o: $(hdrdir)/ruby/internal/attr/noinline.h
scan_args.o: $(hdrdir)/ruby/internal/attr/nonnull.h
scan_args.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-scan_args.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
scan_args.o: $(hdrdir)/ruby/internal/attr/pure.h
scan_args.o: $(hdrdir)/ruby/internal/attr/restrict.h
scan_args.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ scan_args.o: $(hdrdir)/ruby/internal/intern/enumerator.h
scan_args.o: $(hdrdir)/ruby/internal/intern/error.h
scan_args.o: $(hdrdir)/ruby/internal/intern/eval.h
scan_args.o: $(hdrdir)/ruby/internal/intern/file.h
+scan_args.o: $(hdrdir)/ruby/internal/intern/gc.h
scan_args.o: $(hdrdir)/ruby/internal/intern/hash.h
scan_args.o: $(hdrdir)/ruby/internal/intern/io.h
scan_args.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ scan_args.o: $(hdrdir)/ruby/internal/memory.h
scan_args.o: $(hdrdir)/ruby/internal/method.h
scan_args.o: $(hdrdir)/ruby/internal/module.h
scan_args.o: $(hdrdir)/ruby/internal/newobj.h
+scan_args.o: $(hdrdir)/ruby/internal/rgengc.h
scan_args.o: $(hdrdir)/ruby/internal/scan_args.h
scan_args.o: $(hdrdir)/ruby/internal/special_consts.h
scan_args.o: $(hdrdir)/ruby/internal/static_assert.h
scan_args.o: $(hdrdir)/ruby/internal/stdalign.h
scan_args.o: $(hdrdir)/ruby/internal/stdbool.h
-scan_args.o: $(hdrdir)/ruby/internal/stdckdint.h
scan_args.o: $(hdrdir)/ruby/internal/symbol.h
scan_args.o: $(hdrdir)/ruby/internal/value.h
scan_args.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/st/foreach/depend b/ext/-test-/st/foreach/depend
index 36273f8df8..0464ee3c53 100644
--- a/ext/-test-/st/foreach/depend
+++ b/ext/-test-/st/foreach/depend
@@ -52,7 +52,6 @@ foreach.o: $(hdrdir)/ruby/internal/attr/noexcept.h
foreach.o: $(hdrdir)/ruby/internal/attr/noinline.h
foreach.o: $(hdrdir)/ruby/internal/attr/nonnull.h
foreach.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-foreach.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
foreach.o: $(hdrdir)/ruby/internal/attr/pure.h
foreach.o: $(hdrdir)/ruby/internal/attr/restrict.h
foreach.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ foreach.o: $(hdrdir)/ruby/internal/intern/enumerator.h
foreach.o: $(hdrdir)/ruby/internal/intern/error.h
foreach.o: $(hdrdir)/ruby/internal/intern/eval.h
foreach.o: $(hdrdir)/ruby/internal/intern/file.h
+foreach.o: $(hdrdir)/ruby/internal/intern/gc.h
foreach.o: $(hdrdir)/ruby/internal/intern/hash.h
foreach.o: $(hdrdir)/ruby/internal/intern/io.h
foreach.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ foreach.o: $(hdrdir)/ruby/internal/memory.h
foreach.o: $(hdrdir)/ruby/internal/method.h
foreach.o: $(hdrdir)/ruby/internal/module.h
foreach.o: $(hdrdir)/ruby/internal/newobj.h
+foreach.o: $(hdrdir)/ruby/internal/rgengc.h
foreach.o: $(hdrdir)/ruby/internal/scan_args.h
foreach.o: $(hdrdir)/ruby/internal/special_consts.h
foreach.o: $(hdrdir)/ruby/internal/static_assert.h
foreach.o: $(hdrdir)/ruby/internal/stdalign.h
foreach.o: $(hdrdir)/ruby/internal/stdbool.h
-foreach.o: $(hdrdir)/ruby/internal/stdckdint.h
foreach.o: $(hdrdir)/ruby/internal/symbol.h
foreach.o: $(hdrdir)/ruby/internal/value.h
foreach.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/st/foreach/foreach.c b/ext/-test-/st/foreach/foreach.c
index 7fbf064694..cde49fb26d 100644
--- a/ext/-test-/st/foreach/foreach.c
+++ b/ext/-test-/st/foreach/foreach.c
@@ -14,20 +14,20 @@ force_unpack_check(struct checker *c, st_data_t key, st_data_t val)
if (c->nr == 0) {
st_data_t i;
- if (c->tbl->bins != NULL) rb_bug("should be packed");
+ if (c->tbl->bins != NULL) rb_bug("should be packed\n");
/* force unpacking during iteration: */
for (i = 1; i < expect_size; i++)
st_add_direct(c->tbl, i, i);
- if (c->tbl->bins == NULL) rb_bug("should be unpacked");
+ if (c->tbl->bins == NULL) rb_bug("should be unpacked\n");
}
if (key != c->nr) {
- rb_bug("unexpected key: %"PRIuVALUE" (expected %"PRIuVALUE")", (VALUE)key, (VALUE)c->nr);
+ rb_bug("unexpected key: %"PRIuVALUE" (expected %"PRIuVALUE")\n", (VALUE)key, (VALUE)c->nr);
}
if (val != c->nr) {
- rb_bug("unexpected val: %"PRIuVALUE" (expected %"PRIuVALUE")", (VALUE)val, (VALUE)c->nr);
+ rb_bug("unexpected val: %"PRIuVALUE" (expected %"PRIuVALUE")\n", (VALUE)val, (VALUE)c->nr);
}
c->nr++;
@@ -60,7 +60,7 @@ unp_fec_i(st_data_t key, st_data_t val, st_data_t args, int error)
st_data_t v;
if (!st_delete(c->tbl, &k, &v)) {
- rb_bug("failed to delete");
+ rb_bug("failed to delete\n");
}
if (v != 0) {
rb_bug("unexpected value deleted: %"PRIuVALUE" (expected 0)", (VALUE)v);
@@ -84,21 +84,21 @@ unp_fec(VALUE self, VALUE test)
st_add_direct(tbl, 0, 0);
- if (tbl->bins != NULL) rb_bug("should still be packed");
+ if (tbl->bins != NULL) rb_bug("should still be packed\n");
st_foreach_check(tbl, unp_fec_i, (st_data_t)&c, -1);
if (c.test == ID2SYM(rb_intern("delete2"))) {
if (c.nr != 1) {
- rb_bug("mismatched iteration: %"PRIuVALUE" (expected 1)", (VALUE)c.nr);
+ rb_bug("mismatched iteration: %"PRIuVALUE" (expected 1)\n", (VALUE)c.nr);
}
}
else if (c.nr != expect_size) {
- rb_bug("mismatched iteration: %"PRIuVALUE" (expected %"PRIuVALUE")",
+ rb_bug("mismatched iteration: %"PRIuVALUE" (expected %"PRIuVALUE")\n",
(VALUE)c.nr, (VALUE)expect_size);
}
- if (tbl->bins == NULL) rb_bug("should be unpacked");
+ if (tbl->bins == NULL) rb_bug("should be unpacked\n");
st_free_table(tbl);
@@ -120,14 +120,14 @@ unp_fe_i(st_data_t key, st_data_t val, st_data_t args)
st_data_t v;
if (!st_delete(c->tbl, &k, &v)) {
- rb_bug("failed to delete");
+ rb_bug("failed to delete\n");
}
if (v != 0) {
rb_bug("unexpected value deleted: %"PRIuVALUE" (expected 0)", (VALUE)v);
}
return ST_CONTINUE;
}
- rb_bug("should never get here");
+ rb_bug("should never get here\n");
}
rb_raise(rb_eArgError, "unexpected arg: %+"PRIsVALUE, c->test);
@@ -145,21 +145,21 @@ unp_fe(VALUE self, VALUE test)
st_add_direct(tbl, 0, 0);
- if (tbl->bins != NULL) rb_bug("should still be packed");
+ if (tbl->bins != NULL) rb_bug("should still be packed\n");
st_foreach(tbl, unp_fe_i, (st_data_t)&c);
if (c.test == ID2SYM(rb_intern("unpack_delete"))) {
if (c.nr != 1) {
- rb_bug("mismatched iteration: %"PRIuVALUE" (expected 1)", (VALUE)c.nr);
+ rb_bug("mismatched iteration: %"PRIuVALUE" (expected 1)\n", (VALUE)c.nr);
}
}
else if (c.nr != expect_size) {
- rb_bug("mismatched iteration: %"PRIuVALUE" (expected %"PRIuVALUE"o)",
+ rb_bug("mismatched iteration: %"PRIuVALUE" (expected %"PRIuVALUE"o)\n",
(VALUE)c.nr, (VALUE)expect_size);
}
- if (tbl->bins == NULL) rb_bug("should be unpacked");
+ if (tbl->bins == NULL) rb_bug("should be unpacked\n");
st_free_table(tbl);
diff --git a/ext/-test-/st/numhash/depend b/ext/-test-/st/numhash/depend
index a0916183b6..9665ed6e39 100644
--- a/ext/-test-/st/numhash/depend
+++ b/ext/-test-/st/numhash/depend
@@ -52,7 +52,6 @@ numhash.o: $(hdrdir)/ruby/internal/attr/noexcept.h
numhash.o: $(hdrdir)/ruby/internal/attr/noinline.h
numhash.o: $(hdrdir)/ruby/internal/attr/nonnull.h
numhash.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-numhash.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
numhash.o: $(hdrdir)/ruby/internal/attr/pure.h
numhash.o: $(hdrdir)/ruby/internal/attr/restrict.h
numhash.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ numhash.o: $(hdrdir)/ruby/internal/intern/enumerator.h
numhash.o: $(hdrdir)/ruby/internal/intern/error.h
numhash.o: $(hdrdir)/ruby/internal/intern/eval.h
numhash.o: $(hdrdir)/ruby/internal/intern/file.h
+numhash.o: $(hdrdir)/ruby/internal/intern/gc.h
numhash.o: $(hdrdir)/ruby/internal/intern/hash.h
numhash.o: $(hdrdir)/ruby/internal/intern/io.h
numhash.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ numhash.o: $(hdrdir)/ruby/internal/memory.h
numhash.o: $(hdrdir)/ruby/internal/method.h
numhash.o: $(hdrdir)/ruby/internal/module.h
numhash.o: $(hdrdir)/ruby/internal/newobj.h
+numhash.o: $(hdrdir)/ruby/internal/rgengc.h
numhash.o: $(hdrdir)/ruby/internal/scan_args.h
numhash.o: $(hdrdir)/ruby/internal/special_consts.h
numhash.o: $(hdrdir)/ruby/internal/static_assert.h
numhash.o: $(hdrdir)/ruby/internal/stdalign.h
numhash.o: $(hdrdir)/ruby/internal/stdbool.h
-numhash.o: $(hdrdir)/ruby/internal/stdckdint.h
numhash.o: $(hdrdir)/ruby/internal/symbol.h
numhash.o: $(hdrdir)/ruby/internal/value.h
numhash.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/st/update/depend b/ext/-test-/st/update/depend
index 96ba194df0..01960df965 100644
--- a/ext/-test-/st/update/depend
+++ b/ext/-test-/st/update/depend
@@ -52,7 +52,6 @@ update.o: $(hdrdir)/ruby/internal/attr/noexcept.h
update.o: $(hdrdir)/ruby/internal/attr/noinline.h
update.o: $(hdrdir)/ruby/internal/attr/nonnull.h
update.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-update.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
update.o: $(hdrdir)/ruby/internal/attr/pure.h
update.o: $(hdrdir)/ruby/internal/attr/restrict.h
update.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ update.o: $(hdrdir)/ruby/internal/intern/enumerator.h
update.o: $(hdrdir)/ruby/internal/intern/error.h
update.o: $(hdrdir)/ruby/internal/intern/eval.h
update.o: $(hdrdir)/ruby/internal/intern/file.h
+update.o: $(hdrdir)/ruby/internal/intern/gc.h
update.o: $(hdrdir)/ruby/internal/intern/hash.h
update.o: $(hdrdir)/ruby/internal/intern/io.h
update.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ update.o: $(hdrdir)/ruby/internal/memory.h
update.o: $(hdrdir)/ruby/internal/method.h
update.o: $(hdrdir)/ruby/internal/module.h
update.o: $(hdrdir)/ruby/internal/newobj.h
+update.o: $(hdrdir)/ruby/internal/rgengc.h
update.o: $(hdrdir)/ruby/internal/scan_args.h
update.o: $(hdrdir)/ruby/internal/special_consts.h
update.o: $(hdrdir)/ruby/internal/static_assert.h
update.o: $(hdrdir)/ruby/internal/stdalign.h
update.o: $(hdrdir)/ruby/internal/stdbool.h
-update.o: $(hdrdir)/ruby/internal/stdckdint.h
update.o: $(hdrdir)/ruby/internal/symbol.h
update.o: $(hdrdir)/ruby/internal/value.h
update.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/string/cstr.c b/ext/-test-/string/cstr.c
index b0b1ef5374..468ee7a3b1 100644
--- a/ext/-test-/string/cstr.c
+++ b/ext/-test-/string/cstr.c
@@ -61,12 +61,18 @@ bug_str_unterminated_substring(VALUE str, VALUE vbeg, VALUE vlen)
if (RSTRING_LEN(str) < beg) rb_raise(rb_eIndexError, "beg: %ld", beg);
if (RSTRING_LEN(str) < beg + len) rb_raise(rb_eIndexError, "end: %ld", beg + len);
str = rb_str_new_shared(str);
- RSTRING(str)->len = len;
if (STR_EMBED_P(str)) {
+#if USE_RVARGC
+ RSTRING(str)->as.embed.len = (short)len;
+#else
+ RSTRING(str)->basic.flags &= ~RSTRING_EMBED_LEN_MASK;
+ RSTRING(str)->basic.flags |= len << RSTRING_EMBED_LEN_SHIFT;
+#endif
memmove(RSTRING(str)->as.embed.ary, RSTRING(str)->as.embed.ary + beg, len);
}
else {
RSTRING(str)->as.heap.ptr += beg;
+ RSTRING(str)->as.heap.len = len;
}
return str;
}
@@ -110,10 +116,14 @@ bug_str_s_cstr_noembed(VALUE self, VALUE str)
Check_Type(str, T_STRING);
FL_SET((str2), STR_NOEMBED);
memcpy(buf, RSTRING_PTR(str), capacity);
+#if USE_RVARGC
RBASIC(str2)->flags &= ~(STR_SHARED | FL_USER5 | FL_USER6);
+#else
+ RBASIC(str2)->flags &= ~RSTRING_EMBED_LEN_MASK;
+#endif
RSTRING(str2)->as.heap.aux.capa = capacity;
RSTRING(str2)->as.heap.ptr = buf;
- RSTRING(str2)->len = RSTRING_LEN(str);
+ RSTRING(str2)->as.heap.len = RSTRING_LEN(str);
TERM_FILL(RSTRING_END(str2), TERM_LEN(str));
return str2;
}
diff --git a/ext/-test-/string/depend b/ext/-test-/string/depend
index 044b6109ff..773231047e 100644
--- a/ext/-test-/string/depend
+++ b/ext/-test-/string/depend
@@ -54,7 +54,6 @@ capacity.o: $(hdrdir)/ruby/internal/attr/noexcept.h
capacity.o: $(hdrdir)/ruby/internal/attr/noinline.h
capacity.o: $(hdrdir)/ruby/internal/attr/nonnull.h
capacity.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-capacity.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
capacity.o: $(hdrdir)/ruby/internal/attr/pure.h
capacity.o: $(hdrdir)/ruby/internal/attr/restrict.h
capacity.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -123,6 +122,7 @@ capacity.o: $(hdrdir)/ruby/internal/intern/enumerator.h
capacity.o: $(hdrdir)/ruby/internal/intern/error.h
capacity.o: $(hdrdir)/ruby/internal/intern/eval.h
capacity.o: $(hdrdir)/ruby/internal/intern/file.h
+capacity.o: $(hdrdir)/ruby/internal/intern/gc.h
capacity.o: $(hdrdir)/ruby/internal/intern/hash.h
capacity.o: $(hdrdir)/ruby/internal/intern/io.h
capacity.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -153,12 +153,12 @@ capacity.o: $(hdrdir)/ruby/internal/memory.h
capacity.o: $(hdrdir)/ruby/internal/method.h
capacity.o: $(hdrdir)/ruby/internal/module.h
capacity.o: $(hdrdir)/ruby/internal/newobj.h
+capacity.o: $(hdrdir)/ruby/internal/rgengc.h
capacity.o: $(hdrdir)/ruby/internal/scan_args.h
capacity.o: $(hdrdir)/ruby/internal/special_consts.h
capacity.o: $(hdrdir)/ruby/internal/static_assert.h
capacity.o: $(hdrdir)/ruby/internal/stdalign.h
capacity.o: $(hdrdir)/ruby/internal/stdbool.h
-capacity.o: $(hdrdir)/ruby/internal/stdckdint.h
capacity.o: $(hdrdir)/ruby/internal/symbol.h
capacity.o: $(hdrdir)/ruby/internal/value.h
capacity.o: $(hdrdir)/ruby/internal/value_type.h
@@ -174,166 +174,6 @@ capacity.o: $(hdrdir)/ruby/subst.h
capacity.o: $(top_srcdir)/internal/compilers.h
capacity.o: $(top_srcdir)/internal/string.h
capacity.o: capacity.c
-chilled.o: $(RUBY_EXTCONF_H)
-chilled.o: $(arch_hdrdir)/ruby/config.h
-chilled.o: $(hdrdir)/ruby.h
-chilled.o: $(hdrdir)/ruby/assert.h
-chilled.o: $(hdrdir)/ruby/backward.h
-chilled.o: $(hdrdir)/ruby/backward/2/assume.h
-chilled.o: $(hdrdir)/ruby/backward/2/attributes.h
-chilled.o: $(hdrdir)/ruby/backward/2/bool.h
-chilled.o: $(hdrdir)/ruby/backward/2/inttypes.h
-chilled.o: $(hdrdir)/ruby/backward/2/limits.h
-chilled.o: $(hdrdir)/ruby/backward/2/long_long.h
-chilled.o: $(hdrdir)/ruby/backward/2/stdalign.h
-chilled.o: $(hdrdir)/ruby/backward/2/stdarg.h
-chilled.o: $(hdrdir)/ruby/defines.h
-chilled.o: $(hdrdir)/ruby/intern.h
-chilled.o: $(hdrdir)/ruby/internal/abi.h
-chilled.o: $(hdrdir)/ruby/internal/anyargs.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-chilled.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-chilled.o: $(hdrdir)/ruby/internal/assume.h
-chilled.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-chilled.o: $(hdrdir)/ruby/internal/attr/artificial.h
-chilled.o: $(hdrdir)/ruby/internal/attr/cold.h
-chilled.o: $(hdrdir)/ruby/internal/attr/const.h
-chilled.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-chilled.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-chilled.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-chilled.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-chilled.o: $(hdrdir)/ruby/internal/attr/error.h
-chilled.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-chilled.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-chilled.o: $(hdrdir)/ruby/internal/attr/format.h
-chilled.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-chilled.o: $(hdrdir)/ruby/internal/attr/noalias.h
-chilled.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-chilled.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-chilled.o: $(hdrdir)/ruby/internal/attr/noinline.h
-chilled.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-chilled.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-chilled.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-chilled.o: $(hdrdir)/ruby/internal/attr/pure.h
-chilled.o: $(hdrdir)/ruby/internal/attr/restrict.h
-chilled.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-chilled.o: $(hdrdir)/ruby/internal/attr/warning.h
-chilled.o: $(hdrdir)/ruby/internal/attr/weakref.h
-chilled.o: $(hdrdir)/ruby/internal/cast.h
-chilled.o: $(hdrdir)/ruby/internal/compiler_is.h
-chilled.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-chilled.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-chilled.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-chilled.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-chilled.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-chilled.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-chilled.o: $(hdrdir)/ruby/internal/compiler_since.h
-chilled.o: $(hdrdir)/ruby/internal/config.h
-chilled.o: $(hdrdir)/ruby/internal/constant_p.h
-chilled.o: $(hdrdir)/ruby/internal/core.h
-chilled.o: $(hdrdir)/ruby/internal/core/rarray.h
-chilled.o: $(hdrdir)/ruby/internal/core/rbasic.h
-chilled.o: $(hdrdir)/ruby/internal/core/rbignum.h
-chilled.o: $(hdrdir)/ruby/internal/core/rclass.h
-chilled.o: $(hdrdir)/ruby/internal/core/rdata.h
-chilled.o: $(hdrdir)/ruby/internal/core/rfile.h
-chilled.o: $(hdrdir)/ruby/internal/core/rhash.h
-chilled.o: $(hdrdir)/ruby/internal/core/robject.h
-chilled.o: $(hdrdir)/ruby/internal/core/rregexp.h
-chilled.o: $(hdrdir)/ruby/internal/core/rstring.h
-chilled.o: $(hdrdir)/ruby/internal/core/rstruct.h
-chilled.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-chilled.o: $(hdrdir)/ruby/internal/ctype.h
-chilled.o: $(hdrdir)/ruby/internal/dllexport.h
-chilled.o: $(hdrdir)/ruby/internal/dosish.h
-chilled.o: $(hdrdir)/ruby/internal/error.h
-chilled.o: $(hdrdir)/ruby/internal/eval.h
-chilled.o: $(hdrdir)/ruby/internal/event.h
-chilled.o: $(hdrdir)/ruby/internal/fl_type.h
-chilled.o: $(hdrdir)/ruby/internal/gc.h
-chilled.o: $(hdrdir)/ruby/internal/glob.h
-chilled.o: $(hdrdir)/ruby/internal/globals.h
-chilled.o: $(hdrdir)/ruby/internal/has/attribute.h
-chilled.o: $(hdrdir)/ruby/internal/has/builtin.h
-chilled.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-chilled.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-chilled.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-chilled.o: $(hdrdir)/ruby/internal/has/extension.h
-chilled.o: $(hdrdir)/ruby/internal/has/feature.h
-chilled.o: $(hdrdir)/ruby/internal/has/warning.h
-chilled.o: $(hdrdir)/ruby/internal/intern/array.h
-chilled.o: $(hdrdir)/ruby/internal/intern/bignum.h
-chilled.o: $(hdrdir)/ruby/internal/intern/class.h
-chilled.o: $(hdrdir)/ruby/internal/intern/compar.h
-chilled.o: $(hdrdir)/ruby/internal/intern/complex.h
-chilled.o: $(hdrdir)/ruby/internal/intern/cont.h
-chilled.o: $(hdrdir)/ruby/internal/intern/dir.h
-chilled.o: $(hdrdir)/ruby/internal/intern/enum.h
-chilled.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-chilled.o: $(hdrdir)/ruby/internal/intern/error.h
-chilled.o: $(hdrdir)/ruby/internal/intern/eval.h
-chilled.o: $(hdrdir)/ruby/internal/intern/file.h
-chilled.o: $(hdrdir)/ruby/internal/intern/hash.h
-chilled.o: $(hdrdir)/ruby/internal/intern/io.h
-chilled.o: $(hdrdir)/ruby/internal/intern/load.h
-chilled.o: $(hdrdir)/ruby/internal/intern/marshal.h
-chilled.o: $(hdrdir)/ruby/internal/intern/numeric.h
-chilled.o: $(hdrdir)/ruby/internal/intern/object.h
-chilled.o: $(hdrdir)/ruby/internal/intern/parse.h
-chilled.o: $(hdrdir)/ruby/internal/intern/proc.h
-chilled.o: $(hdrdir)/ruby/internal/intern/process.h
-chilled.o: $(hdrdir)/ruby/internal/intern/random.h
-chilled.o: $(hdrdir)/ruby/internal/intern/range.h
-chilled.o: $(hdrdir)/ruby/internal/intern/rational.h
-chilled.o: $(hdrdir)/ruby/internal/intern/re.h
-chilled.o: $(hdrdir)/ruby/internal/intern/ruby.h
-chilled.o: $(hdrdir)/ruby/internal/intern/select.h
-chilled.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-chilled.o: $(hdrdir)/ruby/internal/intern/signal.h
-chilled.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-chilled.o: $(hdrdir)/ruby/internal/intern/string.h
-chilled.o: $(hdrdir)/ruby/internal/intern/struct.h
-chilled.o: $(hdrdir)/ruby/internal/intern/thread.h
-chilled.o: $(hdrdir)/ruby/internal/intern/time.h
-chilled.o: $(hdrdir)/ruby/internal/intern/variable.h
-chilled.o: $(hdrdir)/ruby/internal/intern/vm.h
-chilled.o: $(hdrdir)/ruby/internal/interpreter.h
-chilled.o: $(hdrdir)/ruby/internal/iterator.h
-chilled.o: $(hdrdir)/ruby/internal/memory.h
-chilled.o: $(hdrdir)/ruby/internal/method.h
-chilled.o: $(hdrdir)/ruby/internal/module.h
-chilled.o: $(hdrdir)/ruby/internal/newobj.h
-chilled.o: $(hdrdir)/ruby/internal/scan_args.h
-chilled.o: $(hdrdir)/ruby/internal/special_consts.h
-chilled.o: $(hdrdir)/ruby/internal/static_assert.h
-chilled.o: $(hdrdir)/ruby/internal/stdalign.h
-chilled.o: $(hdrdir)/ruby/internal/stdbool.h
-chilled.o: $(hdrdir)/ruby/internal/stdckdint.h
-chilled.o: $(hdrdir)/ruby/internal/symbol.h
-chilled.o: $(hdrdir)/ruby/internal/value.h
-chilled.o: $(hdrdir)/ruby/internal/value_type.h
-chilled.o: $(hdrdir)/ruby/internal/variable.h
-chilled.o: $(hdrdir)/ruby/internal/warning_push.h
-chilled.o: $(hdrdir)/ruby/internal/xmalloc.h
-chilled.o: $(hdrdir)/ruby/missing.h
-chilled.o: $(hdrdir)/ruby/ruby.h
-chilled.o: $(hdrdir)/ruby/st.h
-chilled.o: $(hdrdir)/ruby/subst.h
-chilled.o: chilled.c
coderange.o: $(RUBY_EXTCONF_H)
coderange.o: $(arch_hdrdir)/ruby/config.h
coderange.o: $(hdrdir)/ruby/assert.h
@@ -387,7 +227,6 @@ coderange.o: $(hdrdir)/ruby/internal/attr/noexcept.h
coderange.o: $(hdrdir)/ruby/internal/attr/noinline.h
coderange.o: $(hdrdir)/ruby/internal/attr/nonnull.h
coderange.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-coderange.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
coderange.o: $(hdrdir)/ruby/internal/attr/pure.h
coderange.o: $(hdrdir)/ruby/internal/attr/restrict.h
coderange.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -456,6 +295,7 @@ coderange.o: $(hdrdir)/ruby/internal/intern/enumerator.h
coderange.o: $(hdrdir)/ruby/internal/intern/error.h
coderange.o: $(hdrdir)/ruby/internal/intern/eval.h
coderange.o: $(hdrdir)/ruby/internal/intern/file.h
+coderange.o: $(hdrdir)/ruby/internal/intern/gc.h
coderange.o: $(hdrdir)/ruby/internal/intern/hash.h
coderange.o: $(hdrdir)/ruby/internal/intern/io.h
coderange.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -486,12 +326,12 @@ coderange.o: $(hdrdir)/ruby/internal/memory.h
coderange.o: $(hdrdir)/ruby/internal/method.h
coderange.o: $(hdrdir)/ruby/internal/module.h
coderange.o: $(hdrdir)/ruby/internal/newobj.h
+coderange.o: $(hdrdir)/ruby/internal/rgengc.h
coderange.o: $(hdrdir)/ruby/internal/scan_args.h
coderange.o: $(hdrdir)/ruby/internal/special_consts.h
coderange.o: $(hdrdir)/ruby/internal/static_assert.h
coderange.o: $(hdrdir)/ruby/internal/stdalign.h
coderange.o: $(hdrdir)/ruby/internal/stdbool.h
-coderange.o: $(hdrdir)/ruby/internal/stdckdint.h
coderange.o: $(hdrdir)/ruby/internal/symbol.h
coderange.o: $(hdrdir)/ruby/internal/value.h
coderange.o: $(hdrdir)/ruby/internal/value_type.h
@@ -559,7 +399,6 @@ cstr.o: $(hdrdir)/ruby/internal/attr/noexcept.h
cstr.o: $(hdrdir)/ruby/internal/attr/noinline.h
cstr.o: $(hdrdir)/ruby/internal/attr/nonnull.h
cstr.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-cstr.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
cstr.o: $(hdrdir)/ruby/internal/attr/pure.h
cstr.o: $(hdrdir)/ruby/internal/attr/restrict.h
cstr.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -628,6 +467,7 @@ cstr.o: $(hdrdir)/ruby/internal/intern/enumerator.h
cstr.o: $(hdrdir)/ruby/internal/intern/error.h
cstr.o: $(hdrdir)/ruby/internal/intern/eval.h
cstr.o: $(hdrdir)/ruby/internal/intern/file.h
+cstr.o: $(hdrdir)/ruby/internal/intern/gc.h
cstr.o: $(hdrdir)/ruby/internal/intern/hash.h
cstr.o: $(hdrdir)/ruby/internal/intern/io.h
cstr.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -658,12 +498,12 @@ cstr.o: $(hdrdir)/ruby/internal/memory.h
cstr.o: $(hdrdir)/ruby/internal/method.h
cstr.o: $(hdrdir)/ruby/internal/module.h
cstr.o: $(hdrdir)/ruby/internal/newobj.h
+cstr.o: $(hdrdir)/ruby/internal/rgengc.h
cstr.o: $(hdrdir)/ruby/internal/scan_args.h
cstr.o: $(hdrdir)/ruby/internal/special_consts.h
cstr.o: $(hdrdir)/ruby/internal/static_assert.h
cstr.o: $(hdrdir)/ruby/internal/stdalign.h
cstr.o: $(hdrdir)/ruby/internal/stdbool.h
-cstr.o: $(hdrdir)/ruby/internal/stdckdint.h
cstr.o: $(hdrdir)/ruby/internal/symbol.h
cstr.o: $(hdrdir)/ruby/internal/value.h
cstr.o: $(hdrdir)/ruby/internal/value_type.h
@@ -733,7 +573,6 @@ ellipsize.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ellipsize.o: $(hdrdir)/ruby/internal/attr/noinline.h
ellipsize.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ellipsize.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ellipsize.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ellipsize.o: $(hdrdir)/ruby/internal/attr/pure.h
ellipsize.o: $(hdrdir)/ruby/internal/attr/restrict.h
ellipsize.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -793,6 +632,7 @@ ellipsize.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/error.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/eval.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/file.h
+ellipsize.o: $(hdrdir)/ruby/internal/intern/gc.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/hash.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/io.h
ellipsize.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -823,12 +663,12 @@ ellipsize.o: $(hdrdir)/ruby/internal/memory.h
ellipsize.o: $(hdrdir)/ruby/internal/method.h
ellipsize.o: $(hdrdir)/ruby/internal/module.h
ellipsize.o: $(hdrdir)/ruby/internal/newobj.h
+ellipsize.o: $(hdrdir)/ruby/internal/rgengc.h
ellipsize.o: $(hdrdir)/ruby/internal/scan_args.h
ellipsize.o: $(hdrdir)/ruby/internal/special_consts.h
ellipsize.o: $(hdrdir)/ruby/internal/static_assert.h
ellipsize.o: $(hdrdir)/ruby/internal/stdalign.h
ellipsize.o: $(hdrdir)/ruby/internal/stdbool.h
-ellipsize.o: $(hdrdir)/ruby/internal/stdckdint.h
ellipsize.o: $(hdrdir)/ruby/internal/symbol.h
ellipsize.o: $(hdrdir)/ruby/internal/value.h
ellipsize.o: $(hdrdir)/ruby/internal/value_type.h
@@ -894,7 +734,6 @@ enc_associate.o: $(hdrdir)/ruby/internal/attr/noexcept.h
enc_associate.o: $(hdrdir)/ruby/internal/attr/noinline.h
enc_associate.o: $(hdrdir)/ruby/internal/attr/nonnull.h
enc_associate.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-enc_associate.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
enc_associate.o: $(hdrdir)/ruby/internal/attr/pure.h
enc_associate.o: $(hdrdir)/ruby/internal/attr/restrict.h
enc_associate.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -963,6 +802,7 @@ enc_associate.o: $(hdrdir)/ruby/internal/intern/enumerator.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/error.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/eval.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/file.h
+enc_associate.o: $(hdrdir)/ruby/internal/intern/gc.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/hash.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/io.h
enc_associate.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -993,12 +833,12 @@ enc_associate.o: $(hdrdir)/ruby/internal/memory.h
enc_associate.o: $(hdrdir)/ruby/internal/method.h
enc_associate.o: $(hdrdir)/ruby/internal/module.h
enc_associate.o: $(hdrdir)/ruby/internal/newobj.h
+enc_associate.o: $(hdrdir)/ruby/internal/rgengc.h
enc_associate.o: $(hdrdir)/ruby/internal/scan_args.h
enc_associate.o: $(hdrdir)/ruby/internal/special_consts.h
enc_associate.o: $(hdrdir)/ruby/internal/static_assert.h
enc_associate.o: $(hdrdir)/ruby/internal/stdalign.h
enc_associate.o: $(hdrdir)/ruby/internal/stdbool.h
-enc_associate.o: $(hdrdir)/ruby/internal/stdckdint.h
enc_associate.o: $(hdrdir)/ruby/internal/symbol.h
enc_associate.o: $(hdrdir)/ruby/internal/value.h
enc_associate.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1012,178 +852,6 @@ enc_associate.o: $(hdrdir)/ruby/ruby.h
enc_associate.o: $(hdrdir)/ruby/st.h
enc_associate.o: $(hdrdir)/ruby/subst.h
enc_associate.o: enc_associate.c
-enc_dummy.o: $(RUBY_EXTCONF_H)
-enc_dummy.o: $(arch_hdrdir)/ruby/config.h
-enc_dummy.o: $(hdrdir)/ruby.h
-enc_dummy.o: $(hdrdir)/ruby/assert.h
-enc_dummy.o: $(hdrdir)/ruby/backward.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/assume.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/attributes.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/bool.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/inttypes.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/limits.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/long_long.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/stdalign.h
-enc_dummy.o: $(hdrdir)/ruby/backward/2/stdarg.h
-enc_dummy.o: $(hdrdir)/ruby/defines.h
-enc_dummy.o: $(hdrdir)/ruby/encoding.h
-enc_dummy.o: $(hdrdir)/ruby/intern.h
-enc_dummy.o: $(hdrdir)/ruby/internal/abi.h
-enc_dummy.o: $(hdrdir)/ruby/internal/anyargs.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-enc_dummy.o: $(hdrdir)/ruby/internal/assume.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/artificial.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/cold.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/const.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/error.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/format.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/noalias.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/noinline.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/pure.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/restrict.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/warning.h
-enc_dummy.o: $(hdrdir)/ruby/internal/attr/weakref.h
-enc_dummy.o: $(hdrdir)/ruby/internal/cast.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-enc_dummy.o: $(hdrdir)/ruby/internal/compiler_since.h
-enc_dummy.o: $(hdrdir)/ruby/internal/config.h
-enc_dummy.o: $(hdrdir)/ruby/internal/constant_p.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rarray.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rbasic.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rbignum.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rclass.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rdata.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rfile.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rhash.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/robject.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rregexp.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rstring.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rstruct.h
-enc_dummy.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-enc_dummy.o: $(hdrdir)/ruby/internal/ctype.h
-enc_dummy.o: $(hdrdir)/ruby/internal/dllexport.h
-enc_dummy.o: $(hdrdir)/ruby/internal/dosish.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/re.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/string.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-enc_dummy.o: $(hdrdir)/ruby/internal/encoding/transcode.h
-enc_dummy.o: $(hdrdir)/ruby/internal/error.h
-enc_dummy.o: $(hdrdir)/ruby/internal/eval.h
-enc_dummy.o: $(hdrdir)/ruby/internal/event.h
-enc_dummy.o: $(hdrdir)/ruby/internal/fl_type.h
-enc_dummy.o: $(hdrdir)/ruby/internal/gc.h
-enc_dummy.o: $(hdrdir)/ruby/internal/glob.h
-enc_dummy.o: $(hdrdir)/ruby/internal/globals.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/attribute.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/builtin.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/extension.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/feature.h
-enc_dummy.o: $(hdrdir)/ruby/internal/has/warning.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/array.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/bignum.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/class.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/compar.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/complex.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/cont.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/dir.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/enum.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/error.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/eval.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/file.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/hash.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/io.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/load.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/marshal.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/numeric.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/object.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/parse.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/proc.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/process.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/random.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/range.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/rational.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/re.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/ruby.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/select.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/signal.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/string.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/struct.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/thread.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/time.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/variable.h
-enc_dummy.o: $(hdrdir)/ruby/internal/intern/vm.h
-enc_dummy.o: $(hdrdir)/ruby/internal/interpreter.h
-enc_dummy.o: $(hdrdir)/ruby/internal/iterator.h
-enc_dummy.o: $(hdrdir)/ruby/internal/memory.h
-enc_dummy.o: $(hdrdir)/ruby/internal/method.h
-enc_dummy.o: $(hdrdir)/ruby/internal/module.h
-enc_dummy.o: $(hdrdir)/ruby/internal/newobj.h
-enc_dummy.o: $(hdrdir)/ruby/internal/scan_args.h
-enc_dummy.o: $(hdrdir)/ruby/internal/special_consts.h
-enc_dummy.o: $(hdrdir)/ruby/internal/static_assert.h
-enc_dummy.o: $(hdrdir)/ruby/internal/stdalign.h
-enc_dummy.o: $(hdrdir)/ruby/internal/stdbool.h
-enc_dummy.o: $(hdrdir)/ruby/internal/stdckdint.h
-enc_dummy.o: $(hdrdir)/ruby/internal/symbol.h
-enc_dummy.o: $(hdrdir)/ruby/internal/value.h
-enc_dummy.o: $(hdrdir)/ruby/internal/value_type.h
-enc_dummy.o: $(hdrdir)/ruby/internal/variable.h
-enc_dummy.o: $(hdrdir)/ruby/internal/warning_push.h
-enc_dummy.o: $(hdrdir)/ruby/internal/xmalloc.h
-enc_dummy.o: $(hdrdir)/ruby/missing.h
-enc_dummy.o: $(hdrdir)/ruby/onigmo.h
-enc_dummy.o: $(hdrdir)/ruby/oniguruma.h
-enc_dummy.o: $(hdrdir)/ruby/ruby.h
-enc_dummy.o: $(hdrdir)/ruby/st.h
-enc_dummy.o: $(hdrdir)/ruby/subst.h
-enc_dummy.o: enc_dummy.c
enc_str_buf_cat.o: $(RUBY_EXTCONF_H)
enc_str_buf_cat.o: $(arch_hdrdir)/ruby/config.h
enc_str_buf_cat.o: $(hdrdir)/ruby/assert.h
@@ -1237,7 +905,6 @@ enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/noexcept.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/noinline.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/nonnull.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/pure.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/restrict.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1306,6 +973,7 @@ enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/enumerator.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/error.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/eval.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/file.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/gc.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/hash.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/io.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1336,12 +1004,12 @@ enc_str_buf_cat.o: $(hdrdir)/ruby/internal/memory.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/method.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/module.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/newobj.h
+enc_str_buf_cat.o: $(hdrdir)/ruby/internal/rgengc.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/scan_args.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/special_consts.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/static_assert.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/stdalign.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/stdbool.h
-enc_str_buf_cat.o: $(hdrdir)/ruby/internal/stdckdint.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/symbol.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/value.h
enc_str_buf_cat.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1363,7 +1031,6 @@ fstring.o: $(hdrdir)/ruby/backward.h
fstring.o: $(hdrdir)/ruby/backward/2/assume.h
fstring.o: $(hdrdir)/ruby/backward/2/attributes.h
fstring.o: $(hdrdir)/ruby/backward/2/bool.h
-fstring.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
fstring.o: $(hdrdir)/ruby/backward/2/inttypes.h
fstring.o: $(hdrdir)/ruby/backward/2/limits.h
fstring.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -1410,7 +1077,6 @@ fstring.o: $(hdrdir)/ruby/internal/attr/noexcept.h
fstring.o: $(hdrdir)/ruby/internal/attr/noinline.h
fstring.o: $(hdrdir)/ruby/internal/attr/nonnull.h
fstring.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-fstring.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
fstring.o: $(hdrdir)/ruby/internal/attr/pure.h
fstring.o: $(hdrdir)/ruby/internal/attr/restrict.h
fstring.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1479,6 +1145,7 @@ fstring.o: $(hdrdir)/ruby/internal/intern/enumerator.h
fstring.o: $(hdrdir)/ruby/internal/intern/error.h
fstring.o: $(hdrdir)/ruby/internal/intern/eval.h
fstring.o: $(hdrdir)/ruby/internal/intern/file.h
+fstring.o: $(hdrdir)/ruby/internal/intern/gc.h
fstring.o: $(hdrdir)/ruby/internal/intern/hash.h
fstring.o: $(hdrdir)/ruby/internal/intern/io.h
fstring.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1509,12 +1176,12 @@ fstring.o: $(hdrdir)/ruby/internal/memory.h
fstring.o: $(hdrdir)/ruby/internal/method.h
fstring.o: $(hdrdir)/ruby/internal/module.h
fstring.o: $(hdrdir)/ruby/internal/newobj.h
+fstring.o: $(hdrdir)/ruby/internal/rgengc.h
fstring.o: $(hdrdir)/ruby/internal/scan_args.h
fstring.o: $(hdrdir)/ruby/internal/special_consts.h
fstring.o: $(hdrdir)/ruby/internal/static_assert.h
fstring.o: $(hdrdir)/ruby/internal/stdalign.h
fstring.o: $(hdrdir)/ruby/internal/stdbool.h
-fstring.o: $(hdrdir)/ruby/internal/stdckdint.h
fstring.o: $(hdrdir)/ruby/internal/symbol.h
fstring.o: $(hdrdir)/ruby/internal/value.h
fstring.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1527,8 +1194,6 @@ fstring.o: $(hdrdir)/ruby/oniguruma.h
fstring.o: $(hdrdir)/ruby/ruby.h
fstring.o: $(hdrdir)/ruby/st.h
fstring.o: $(hdrdir)/ruby/subst.h
-fstring.o: $(top_srcdir)/internal/compilers.h
-fstring.o: $(top_srcdir)/internal/string.h
fstring.o: fstring.c
init.o: $(RUBY_EXTCONF_H)
init.o: $(arch_hdrdir)/ruby/config.h
@@ -1583,7 +1248,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1643,6 +1307,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1673,12 +1338,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1743,7 +1408,6 @@ modify.o: $(hdrdir)/ruby/internal/attr/noexcept.h
modify.o: $(hdrdir)/ruby/internal/attr/noinline.h
modify.o: $(hdrdir)/ruby/internal/attr/nonnull.h
modify.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-modify.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
modify.o: $(hdrdir)/ruby/internal/attr/pure.h
modify.o: $(hdrdir)/ruby/internal/attr/restrict.h
modify.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1803,6 +1467,7 @@ modify.o: $(hdrdir)/ruby/internal/intern/enumerator.h
modify.o: $(hdrdir)/ruby/internal/intern/error.h
modify.o: $(hdrdir)/ruby/internal/intern/eval.h
modify.o: $(hdrdir)/ruby/internal/intern/file.h
+modify.o: $(hdrdir)/ruby/internal/intern/gc.h
modify.o: $(hdrdir)/ruby/internal/intern/hash.h
modify.o: $(hdrdir)/ruby/internal/intern/io.h
modify.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1833,12 +1498,12 @@ modify.o: $(hdrdir)/ruby/internal/memory.h
modify.o: $(hdrdir)/ruby/internal/method.h
modify.o: $(hdrdir)/ruby/internal/module.h
modify.o: $(hdrdir)/ruby/internal/newobj.h
+modify.o: $(hdrdir)/ruby/internal/rgengc.h
modify.o: $(hdrdir)/ruby/internal/scan_args.h
modify.o: $(hdrdir)/ruby/internal/special_consts.h
modify.o: $(hdrdir)/ruby/internal/static_assert.h
modify.o: $(hdrdir)/ruby/internal/stdalign.h
modify.o: $(hdrdir)/ruby/internal/stdbool.h
-modify.o: $(hdrdir)/ruby/internal/stdckdint.h
modify.o: $(hdrdir)/ruby/internal/symbol.h
modify.o: $(hdrdir)/ruby/internal/value.h
modify.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1904,7 +1569,6 @@ new.o: $(hdrdir)/ruby/internal/attr/noexcept.h
new.o: $(hdrdir)/ruby/internal/attr/noinline.h
new.o: $(hdrdir)/ruby/internal/attr/nonnull.h
new.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-new.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
new.o: $(hdrdir)/ruby/internal/attr/pure.h
new.o: $(hdrdir)/ruby/internal/attr/restrict.h
new.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1973,6 +1637,7 @@ new.o: $(hdrdir)/ruby/internal/intern/enumerator.h
new.o: $(hdrdir)/ruby/internal/intern/error.h
new.o: $(hdrdir)/ruby/internal/intern/eval.h
new.o: $(hdrdir)/ruby/internal/intern/file.h
+new.o: $(hdrdir)/ruby/internal/intern/gc.h
new.o: $(hdrdir)/ruby/internal/intern/hash.h
new.o: $(hdrdir)/ruby/internal/intern/io.h
new.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2003,12 +1668,12 @@ new.o: $(hdrdir)/ruby/internal/memory.h
new.o: $(hdrdir)/ruby/internal/method.h
new.o: $(hdrdir)/ruby/internal/module.h
new.o: $(hdrdir)/ruby/internal/newobj.h
+new.o: $(hdrdir)/ruby/internal/rgengc.h
new.o: $(hdrdir)/ruby/internal/scan_args.h
new.o: $(hdrdir)/ruby/internal/special_consts.h
new.o: $(hdrdir)/ruby/internal/static_assert.h
new.o: $(hdrdir)/ruby/internal/stdalign.h
new.o: $(hdrdir)/ruby/internal/stdbool.h
-new.o: $(hdrdir)/ruby/internal/stdckdint.h
new.o: $(hdrdir)/ruby/internal/symbol.h
new.o: $(hdrdir)/ruby/internal/value.h
new.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2075,7 +1740,6 @@ nofree.o: $(hdrdir)/ruby/internal/attr/noexcept.h
nofree.o: $(hdrdir)/ruby/internal/attr/noinline.h
nofree.o: $(hdrdir)/ruby/internal/attr/nonnull.h
nofree.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-nofree.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
nofree.o: $(hdrdir)/ruby/internal/attr/pure.h
nofree.o: $(hdrdir)/ruby/internal/attr/restrict.h
nofree.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2135,6 +1799,7 @@ nofree.o: $(hdrdir)/ruby/internal/intern/enumerator.h
nofree.o: $(hdrdir)/ruby/internal/intern/error.h
nofree.o: $(hdrdir)/ruby/internal/intern/eval.h
nofree.o: $(hdrdir)/ruby/internal/intern/file.h
+nofree.o: $(hdrdir)/ruby/internal/intern/gc.h
nofree.o: $(hdrdir)/ruby/internal/intern/hash.h
nofree.o: $(hdrdir)/ruby/internal/intern/io.h
nofree.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2165,12 +1830,12 @@ nofree.o: $(hdrdir)/ruby/internal/memory.h
nofree.o: $(hdrdir)/ruby/internal/method.h
nofree.o: $(hdrdir)/ruby/internal/module.h
nofree.o: $(hdrdir)/ruby/internal/newobj.h
+nofree.o: $(hdrdir)/ruby/internal/rgengc.h
nofree.o: $(hdrdir)/ruby/internal/scan_args.h
nofree.o: $(hdrdir)/ruby/internal/special_consts.h
nofree.o: $(hdrdir)/ruby/internal/static_assert.h
nofree.o: $(hdrdir)/ruby/internal/stdalign.h
nofree.o: $(hdrdir)/ruby/internal/stdbool.h
-nofree.o: $(hdrdir)/ruby/internal/stdckdint.h
nofree.o: $(hdrdir)/ruby/internal/symbol.h
nofree.o: $(hdrdir)/ruby/internal/value.h
nofree.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2235,7 +1900,6 @@ normalize.o: $(hdrdir)/ruby/internal/attr/noexcept.h
normalize.o: $(hdrdir)/ruby/internal/attr/noinline.h
normalize.o: $(hdrdir)/ruby/internal/attr/nonnull.h
normalize.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-normalize.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
normalize.o: $(hdrdir)/ruby/internal/attr/pure.h
normalize.o: $(hdrdir)/ruby/internal/attr/restrict.h
normalize.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2304,6 +1968,7 @@ normalize.o: $(hdrdir)/ruby/internal/intern/enumerator.h
normalize.o: $(hdrdir)/ruby/internal/intern/error.h
normalize.o: $(hdrdir)/ruby/internal/intern/eval.h
normalize.o: $(hdrdir)/ruby/internal/intern/file.h
+normalize.o: $(hdrdir)/ruby/internal/intern/gc.h
normalize.o: $(hdrdir)/ruby/internal/intern/hash.h
normalize.o: $(hdrdir)/ruby/internal/intern/io.h
normalize.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2334,12 +1999,12 @@ normalize.o: $(hdrdir)/ruby/internal/memory.h
normalize.o: $(hdrdir)/ruby/internal/method.h
normalize.o: $(hdrdir)/ruby/internal/module.h
normalize.o: $(hdrdir)/ruby/internal/newobj.h
+normalize.o: $(hdrdir)/ruby/internal/rgengc.h
normalize.o: $(hdrdir)/ruby/internal/scan_args.h
normalize.o: $(hdrdir)/ruby/internal/special_consts.h
normalize.o: $(hdrdir)/ruby/internal/static_assert.h
normalize.o: $(hdrdir)/ruby/internal/stdalign.h
normalize.o: $(hdrdir)/ruby/internal/stdbool.h
-normalize.o: $(hdrdir)/ruby/internal/stdckdint.h
normalize.o: $(hdrdir)/ruby/internal/symbol.h
normalize.o: $(hdrdir)/ruby/internal/value.h
normalize.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2408,7 +2073,6 @@ qsort.o: $(hdrdir)/ruby/internal/attr/noexcept.h
qsort.o: $(hdrdir)/ruby/internal/attr/noinline.h
qsort.o: $(hdrdir)/ruby/internal/attr/nonnull.h
qsort.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-qsort.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
qsort.o: $(hdrdir)/ruby/internal/attr/pure.h
qsort.o: $(hdrdir)/ruby/internal/attr/restrict.h
qsort.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2477,6 +2141,7 @@ qsort.o: $(hdrdir)/ruby/internal/intern/enumerator.h
qsort.o: $(hdrdir)/ruby/internal/intern/error.h
qsort.o: $(hdrdir)/ruby/internal/intern/eval.h
qsort.o: $(hdrdir)/ruby/internal/intern/file.h
+qsort.o: $(hdrdir)/ruby/internal/intern/gc.h
qsort.o: $(hdrdir)/ruby/internal/intern/hash.h
qsort.o: $(hdrdir)/ruby/internal/intern/io.h
qsort.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2507,12 +2172,12 @@ qsort.o: $(hdrdir)/ruby/internal/memory.h
qsort.o: $(hdrdir)/ruby/internal/method.h
qsort.o: $(hdrdir)/ruby/internal/module.h
qsort.o: $(hdrdir)/ruby/internal/newobj.h
+qsort.o: $(hdrdir)/ruby/internal/rgengc.h
qsort.o: $(hdrdir)/ruby/internal/scan_args.h
qsort.o: $(hdrdir)/ruby/internal/special_consts.h
qsort.o: $(hdrdir)/ruby/internal/static_assert.h
qsort.o: $(hdrdir)/ruby/internal/stdalign.h
qsort.o: $(hdrdir)/ruby/internal/stdbool.h
-qsort.o: $(hdrdir)/ruby/internal/stdckdint.h
qsort.o: $(hdrdir)/ruby/internal/symbol.h
qsort.o: $(hdrdir)/ruby/internal/value.h
qsort.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2580,7 +2245,6 @@ rb_interned_str.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rb_interned_str.o: $(hdrdir)/ruby/internal/attr/noinline.h
rb_interned_str.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rb_interned_str.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rb_interned_str.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rb_interned_str.o: $(hdrdir)/ruby/internal/attr/pure.h
rb_interned_str.o: $(hdrdir)/ruby/internal/attr/restrict.h
rb_interned_str.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2640,6 +2304,7 @@ rb_interned_str.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/error.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/eval.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/file.h
+rb_interned_str.o: $(hdrdir)/ruby/internal/intern/gc.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/hash.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/io.h
rb_interned_str.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2670,12 +2335,12 @@ rb_interned_str.o: $(hdrdir)/ruby/internal/memory.h
rb_interned_str.o: $(hdrdir)/ruby/internal/method.h
rb_interned_str.o: $(hdrdir)/ruby/internal/module.h
rb_interned_str.o: $(hdrdir)/ruby/internal/newobj.h
+rb_interned_str.o: $(hdrdir)/ruby/internal/rgengc.h
rb_interned_str.o: $(hdrdir)/ruby/internal/scan_args.h
rb_interned_str.o: $(hdrdir)/ruby/internal/special_consts.h
rb_interned_str.o: $(hdrdir)/ruby/internal/static_assert.h
rb_interned_str.o: $(hdrdir)/ruby/internal/stdalign.h
rb_interned_str.o: $(hdrdir)/ruby/internal/stdbool.h
-rb_interned_str.o: $(hdrdir)/ruby/internal/stdckdint.h
rb_interned_str.o: $(hdrdir)/ruby/internal/symbol.h
rb_interned_str.o: $(hdrdir)/ruby/internal/value.h
rb_interned_str.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2740,7 +2405,6 @@ rb_str_dup.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rb_str_dup.o: $(hdrdir)/ruby/internal/attr/noinline.h
rb_str_dup.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rb_str_dup.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rb_str_dup.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rb_str_dup.o: $(hdrdir)/ruby/internal/attr/pure.h
rb_str_dup.o: $(hdrdir)/ruby/internal/attr/restrict.h
rb_str_dup.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2800,6 +2464,7 @@ rb_str_dup.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/error.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/eval.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/file.h
+rb_str_dup.o: $(hdrdir)/ruby/internal/intern/gc.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/hash.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/io.h
rb_str_dup.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2830,12 +2495,12 @@ rb_str_dup.o: $(hdrdir)/ruby/internal/memory.h
rb_str_dup.o: $(hdrdir)/ruby/internal/method.h
rb_str_dup.o: $(hdrdir)/ruby/internal/module.h
rb_str_dup.o: $(hdrdir)/ruby/internal/newobj.h
+rb_str_dup.o: $(hdrdir)/ruby/internal/rgengc.h
rb_str_dup.o: $(hdrdir)/ruby/internal/scan_args.h
rb_str_dup.o: $(hdrdir)/ruby/internal/special_consts.h
rb_str_dup.o: $(hdrdir)/ruby/internal/static_assert.h
rb_str_dup.o: $(hdrdir)/ruby/internal/stdalign.h
rb_str_dup.o: $(hdrdir)/ruby/internal/stdbool.h
-rb_str_dup.o: $(hdrdir)/ruby/internal/stdckdint.h
rb_str_dup.o: $(hdrdir)/ruby/internal/symbol.h
rb_str_dup.o: $(hdrdir)/ruby/internal/value.h
rb_str_dup.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2900,7 +2565,6 @@ set_len.o: $(hdrdir)/ruby/internal/attr/noexcept.h
set_len.o: $(hdrdir)/ruby/internal/attr/noinline.h
set_len.o: $(hdrdir)/ruby/internal/attr/nonnull.h
set_len.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-set_len.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
set_len.o: $(hdrdir)/ruby/internal/attr/pure.h
set_len.o: $(hdrdir)/ruby/internal/attr/restrict.h
set_len.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2960,6 +2624,7 @@ set_len.o: $(hdrdir)/ruby/internal/intern/enumerator.h
set_len.o: $(hdrdir)/ruby/internal/intern/error.h
set_len.o: $(hdrdir)/ruby/internal/intern/eval.h
set_len.o: $(hdrdir)/ruby/internal/intern/file.h
+set_len.o: $(hdrdir)/ruby/internal/intern/gc.h
set_len.o: $(hdrdir)/ruby/internal/intern/hash.h
set_len.o: $(hdrdir)/ruby/internal/intern/io.h
set_len.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2990,12 +2655,12 @@ set_len.o: $(hdrdir)/ruby/internal/memory.h
set_len.o: $(hdrdir)/ruby/internal/method.h
set_len.o: $(hdrdir)/ruby/internal/module.h
set_len.o: $(hdrdir)/ruby/internal/newobj.h
+set_len.o: $(hdrdir)/ruby/internal/rgengc.h
set_len.o: $(hdrdir)/ruby/internal/scan_args.h
set_len.o: $(hdrdir)/ruby/internal/special_consts.h
set_len.o: $(hdrdir)/ruby/internal/static_assert.h
set_len.o: $(hdrdir)/ruby/internal/stdalign.h
set_len.o: $(hdrdir)/ruby/internal/stdbool.h
-set_len.o: $(hdrdir)/ruby/internal/stdckdint.h
set_len.o: $(hdrdir)/ruby/internal/symbol.h
set_len.o: $(hdrdir)/ruby/internal/value.h
set_len.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/string/enc_dummy.c b/ext/-test-/string/enc_dummy.c
deleted file mode 100644
index 4169552655..0000000000
--- a/ext/-test-/string/enc_dummy.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "ruby.h"
-#include "ruby/encoding.h"
-
-VALUE
-bug_rb_define_dummy_encoding(VALUE self, VALUE name)
-{
- int idx = rb_define_dummy_encoding(RSTRING_PTR(name));
- return rb_enc_from_encoding(rb_enc_from_index(idx));
-}
-
-void
-Init_string_enc_dummy(VALUE klass)
-{
- rb_define_singleton_method(klass, "rb_define_dummy_encoding", bug_rb_define_dummy_encoding, 1);
-}
diff --git a/ext/-test-/string/fstring.c b/ext/-test-/string/fstring.c
index 71c4b7f97e..64f079251d 100644
--- a/ext/-test-/string/fstring.c
+++ b/ext/-test-/string/fstring.c
@@ -1,19 +1,12 @@
#include "ruby.h"
#include "ruby/encoding.h"
-#include "internal/string.h"
-VALUE
-bug_s_fstring(VALUE self, VALUE str)
-{
- return rb_str_to_interned_str(str);
-}
+VALUE rb_fstring(VALUE str);
VALUE
-bug_s_fstring_fake_str(VALUE self)
+bug_s_fstring(VALUE self, VALUE str)
{
- static const char literal[] = "abcdefghijklmnopqrstuvwxyz";
- struct RString fake_str;
- return rb_str_to_interned_str(rb_setup_fake_str(&fake_str, literal, sizeof(literal) - 1, 0));
+ return rb_fstring(str);
}
VALUE
@@ -32,7 +25,6 @@ void
Init_string_fstring(VALUE klass)
{
rb_define_singleton_method(klass, "fstring", bug_s_fstring, 1);
- rb_define_singleton_method(klass, "fstring_fake_str", bug_s_fstring_fake_str, 0);
rb_define_singleton_method(klass, "rb_enc_interned_str", bug_s_rb_enc_interned_str, 1);
rb_define_singleton_method(klass, "rb_enc_str_new", bug_s_rb_enc_str_new, 1);
}
diff --git a/ext/-test-/string/set_len.c b/ext/-test-/string/set_len.c
index b55ef6f469..049da2cdb5 100644
--- a/ext/-test-/string/set_len.c
+++ b/ext/-test-/string/set_len.c
@@ -16,17 +16,9 @@ bug_str_append(VALUE str, VALUE addendum)
return str;
}
-static VALUE
-bug_str_resize(VALUE str, VALUE len)
-{
- rb_str_resize(str, NUM2LONG(len));
- return str;
-}
-
void
Init_string_set_len(VALUE klass)
{
rb_define_method(klass, "set_len", bug_str_set_len, 1);
rb_define_method(klass, "append", bug_str_append, 1);
- rb_define_method(klass, "resize", bug_str_resize, 1);
}
diff --git a/ext/-test-/struct/data.c b/ext/-test-/struct/data.c
deleted file mode 100644
index 5841c342e7..0000000000
--- a/ext/-test-/struct/data.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "ruby.h"
-
-static VALUE
-bug_data_new(VALUE self, VALUE super)
-{
- return rb_data_define(super, "mem1", "mem2", NULL);
-}
-
-void
-Init_data(VALUE klass)
-{
- rb_define_singleton_method(klass, "data_new", bug_data_new, 1);
-}
diff --git a/ext/-test-/struct/depend b/ext/-test-/struct/depend
index 951dddd5dd..920a065216 100644
--- a/ext/-test-/struct/depend
+++ b/ext/-test-/struct/depend
@@ -1,164 +1,4 @@
# AUTOGENERATED DEPENDENCIES START
-data.o: $(RUBY_EXTCONF_H)
-data.o: $(arch_hdrdir)/ruby/config.h
-data.o: $(hdrdir)/ruby.h
-data.o: $(hdrdir)/ruby/assert.h
-data.o: $(hdrdir)/ruby/backward.h
-data.o: $(hdrdir)/ruby/backward/2/assume.h
-data.o: $(hdrdir)/ruby/backward/2/attributes.h
-data.o: $(hdrdir)/ruby/backward/2/bool.h
-data.o: $(hdrdir)/ruby/backward/2/inttypes.h
-data.o: $(hdrdir)/ruby/backward/2/limits.h
-data.o: $(hdrdir)/ruby/backward/2/long_long.h
-data.o: $(hdrdir)/ruby/backward/2/stdalign.h
-data.o: $(hdrdir)/ruby/backward/2/stdarg.h
-data.o: $(hdrdir)/ruby/defines.h
-data.o: $(hdrdir)/ruby/intern.h
-data.o: $(hdrdir)/ruby/internal/abi.h
-data.o: $(hdrdir)/ruby/internal/anyargs.h
-data.o: $(hdrdir)/ruby/internal/arithmetic.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-data.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-data.o: $(hdrdir)/ruby/internal/assume.h
-data.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-data.o: $(hdrdir)/ruby/internal/attr/artificial.h
-data.o: $(hdrdir)/ruby/internal/attr/cold.h
-data.o: $(hdrdir)/ruby/internal/attr/const.h
-data.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-data.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-data.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-data.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-data.o: $(hdrdir)/ruby/internal/attr/error.h
-data.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-data.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-data.o: $(hdrdir)/ruby/internal/attr/format.h
-data.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-data.o: $(hdrdir)/ruby/internal/attr/noalias.h
-data.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-data.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-data.o: $(hdrdir)/ruby/internal/attr/noinline.h
-data.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-data.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-data.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-data.o: $(hdrdir)/ruby/internal/attr/pure.h
-data.o: $(hdrdir)/ruby/internal/attr/restrict.h
-data.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-data.o: $(hdrdir)/ruby/internal/attr/warning.h
-data.o: $(hdrdir)/ruby/internal/attr/weakref.h
-data.o: $(hdrdir)/ruby/internal/cast.h
-data.o: $(hdrdir)/ruby/internal/compiler_is.h
-data.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-data.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-data.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-data.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-data.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-data.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-data.o: $(hdrdir)/ruby/internal/compiler_since.h
-data.o: $(hdrdir)/ruby/internal/config.h
-data.o: $(hdrdir)/ruby/internal/constant_p.h
-data.o: $(hdrdir)/ruby/internal/core.h
-data.o: $(hdrdir)/ruby/internal/core/rarray.h
-data.o: $(hdrdir)/ruby/internal/core/rbasic.h
-data.o: $(hdrdir)/ruby/internal/core/rbignum.h
-data.o: $(hdrdir)/ruby/internal/core/rclass.h
-data.o: $(hdrdir)/ruby/internal/core/rdata.h
-data.o: $(hdrdir)/ruby/internal/core/rfile.h
-data.o: $(hdrdir)/ruby/internal/core/rhash.h
-data.o: $(hdrdir)/ruby/internal/core/robject.h
-data.o: $(hdrdir)/ruby/internal/core/rregexp.h
-data.o: $(hdrdir)/ruby/internal/core/rstring.h
-data.o: $(hdrdir)/ruby/internal/core/rstruct.h
-data.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-data.o: $(hdrdir)/ruby/internal/ctype.h
-data.o: $(hdrdir)/ruby/internal/dllexport.h
-data.o: $(hdrdir)/ruby/internal/dosish.h
-data.o: $(hdrdir)/ruby/internal/error.h
-data.o: $(hdrdir)/ruby/internal/eval.h
-data.o: $(hdrdir)/ruby/internal/event.h
-data.o: $(hdrdir)/ruby/internal/fl_type.h
-data.o: $(hdrdir)/ruby/internal/gc.h
-data.o: $(hdrdir)/ruby/internal/glob.h
-data.o: $(hdrdir)/ruby/internal/globals.h
-data.o: $(hdrdir)/ruby/internal/has/attribute.h
-data.o: $(hdrdir)/ruby/internal/has/builtin.h
-data.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-data.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-data.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-data.o: $(hdrdir)/ruby/internal/has/extension.h
-data.o: $(hdrdir)/ruby/internal/has/feature.h
-data.o: $(hdrdir)/ruby/internal/has/warning.h
-data.o: $(hdrdir)/ruby/internal/intern/array.h
-data.o: $(hdrdir)/ruby/internal/intern/bignum.h
-data.o: $(hdrdir)/ruby/internal/intern/class.h
-data.o: $(hdrdir)/ruby/internal/intern/compar.h
-data.o: $(hdrdir)/ruby/internal/intern/complex.h
-data.o: $(hdrdir)/ruby/internal/intern/cont.h
-data.o: $(hdrdir)/ruby/internal/intern/dir.h
-data.o: $(hdrdir)/ruby/internal/intern/enum.h
-data.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-data.o: $(hdrdir)/ruby/internal/intern/error.h
-data.o: $(hdrdir)/ruby/internal/intern/eval.h
-data.o: $(hdrdir)/ruby/internal/intern/file.h
-data.o: $(hdrdir)/ruby/internal/intern/hash.h
-data.o: $(hdrdir)/ruby/internal/intern/io.h
-data.o: $(hdrdir)/ruby/internal/intern/load.h
-data.o: $(hdrdir)/ruby/internal/intern/marshal.h
-data.o: $(hdrdir)/ruby/internal/intern/numeric.h
-data.o: $(hdrdir)/ruby/internal/intern/object.h
-data.o: $(hdrdir)/ruby/internal/intern/parse.h
-data.o: $(hdrdir)/ruby/internal/intern/proc.h
-data.o: $(hdrdir)/ruby/internal/intern/process.h
-data.o: $(hdrdir)/ruby/internal/intern/random.h
-data.o: $(hdrdir)/ruby/internal/intern/range.h
-data.o: $(hdrdir)/ruby/internal/intern/rational.h
-data.o: $(hdrdir)/ruby/internal/intern/re.h
-data.o: $(hdrdir)/ruby/internal/intern/ruby.h
-data.o: $(hdrdir)/ruby/internal/intern/select.h
-data.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-data.o: $(hdrdir)/ruby/internal/intern/signal.h
-data.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-data.o: $(hdrdir)/ruby/internal/intern/string.h
-data.o: $(hdrdir)/ruby/internal/intern/struct.h
-data.o: $(hdrdir)/ruby/internal/intern/thread.h
-data.o: $(hdrdir)/ruby/internal/intern/time.h
-data.o: $(hdrdir)/ruby/internal/intern/variable.h
-data.o: $(hdrdir)/ruby/internal/intern/vm.h
-data.o: $(hdrdir)/ruby/internal/interpreter.h
-data.o: $(hdrdir)/ruby/internal/iterator.h
-data.o: $(hdrdir)/ruby/internal/memory.h
-data.o: $(hdrdir)/ruby/internal/method.h
-data.o: $(hdrdir)/ruby/internal/module.h
-data.o: $(hdrdir)/ruby/internal/newobj.h
-data.o: $(hdrdir)/ruby/internal/scan_args.h
-data.o: $(hdrdir)/ruby/internal/special_consts.h
-data.o: $(hdrdir)/ruby/internal/static_assert.h
-data.o: $(hdrdir)/ruby/internal/stdalign.h
-data.o: $(hdrdir)/ruby/internal/stdbool.h
-data.o: $(hdrdir)/ruby/internal/stdckdint.h
-data.o: $(hdrdir)/ruby/internal/symbol.h
-data.o: $(hdrdir)/ruby/internal/value.h
-data.o: $(hdrdir)/ruby/internal/value_type.h
-data.o: $(hdrdir)/ruby/internal/variable.h
-data.o: $(hdrdir)/ruby/internal/warning_push.h
-data.o: $(hdrdir)/ruby/internal/xmalloc.h
-data.o: $(hdrdir)/ruby/missing.h
-data.o: $(hdrdir)/ruby/ruby.h
-data.o: $(hdrdir)/ruby/st.h
-data.o: $(hdrdir)/ruby/subst.h
-data.o: data.c
duplicate.o: $(RUBY_EXTCONF_H)
duplicate.o: $(arch_hdrdir)/ruby/config.h
duplicate.o: $(hdrdir)/ruby.h
@@ -212,7 +52,6 @@ duplicate.o: $(hdrdir)/ruby/internal/attr/noexcept.h
duplicate.o: $(hdrdir)/ruby/internal/attr/noinline.h
duplicate.o: $(hdrdir)/ruby/internal/attr/nonnull.h
duplicate.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-duplicate.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
duplicate.o: $(hdrdir)/ruby/internal/attr/pure.h
duplicate.o: $(hdrdir)/ruby/internal/attr/restrict.h
duplicate.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -272,6 +111,7 @@ duplicate.o: $(hdrdir)/ruby/internal/intern/enumerator.h
duplicate.o: $(hdrdir)/ruby/internal/intern/error.h
duplicate.o: $(hdrdir)/ruby/internal/intern/eval.h
duplicate.o: $(hdrdir)/ruby/internal/intern/file.h
+duplicate.o: $(hdrdir)/ruby/internal/intern/gc.h
duplicate.o: $(hdrdir)/ruby/internal/intern/hash.h
duplicate.o: $(hdrdir)/ruby/internal/intern/io.h
duplicate.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -302,12 +142,12 @@ duplicate.o: $(hdrdir)/ruby/internal/memory.h
duplicate.o: $(hdrdir)/ruby/internal/method.h
duplicate.o: $(hdrdir)/ruby/internal/module.h
duplicate.o: $(hdrdir)/ruby/internal/newobj.h
+duplicate.o: $(hdrdir)/ruby/internal/rgengc.h
duplicate.o: $(hdrdir)/ruby/internal/scan_args.h
duplicate.o: $(hdrdir)/ruby/internal/special_consts.h
duplicate.o: $(hdrdir)/ruby/internal/static_assert.h
duplicate.o: $(hdrdir)/ruby/internal/stdalign.h
duplicate.o: $(hdrdir)/ruby/internal/stdbool.h
-duplicate.o: $(hdrdir)/ruby/internal/stdckdint.h
duplicate.o: $(hdrdir)/ruby/internal/symbol.h
duplicate.o: $(hdrdir)/ruby/internal/value.h
duplicate.o: $(hdrdir)/ruby/internal/value_type.h
@@ -372,7 +212,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -432,6 +271,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -462,12 +302,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -532,7 +372,6 @@ len.o: $(hdrdir)/ruby/internal/attr/noexcept.h
len.o: $(hdrdir)/ruby/internal/attr/noinline.h
len.o: $(hdrdir)/ruby/internal/attr/nonnull.h
len.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-len.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
len.o: $(hdrdir)/ruby/internal/attr/pure.h
len.o: $(hdrdir)/ruby/internal/attr/restrict.h
len.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -592,6 +431,7 @@ len.o: $(hdrdir)/ruby/internal/intern/enumerator.h
len.o: $(hdrdir)/ruby/internal/intern/error.h
len.o: $(hdrdir)/ruby/internal/intern/eval.h
len.o: $(hdrdir)/ruby/internal/intern/file.h
+len.o: $(hdrdir)/ruby/internal/intern/gc.h
len.o: $(hdrdir)/ruby/internal/intern/hash.h
len.o: $(hdrdir)/ruby/internal/intern/io.h
len.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -622,12 +462,12 @@ len.o: $(hdrdir)/ruby/internal/memory.h
len.o: $(hdrdir)/ruby/internal/method.h
len.o: $(hdrdir)/ruby/internal/module.h
len.o: $(hdrdir)/ruby/internal/newobj.h
+len.o: $(hdrdir)/ruby/internal/rgengc.h
len.o: $(hdrdir)/ruby/internal/scan_args.h
len.o: $(hdrdir)/ruby/internal/special_consts.h
len.o: $(hdrdir)/ruby/internal/static_assert.h
len.o: $(hdrdir)/ruby/internal/stdalign.h
len.o: $(hdrdir)/ruby/internal/stdbool.h
-len.o: $(hdrdir)/ruby/internal/stdckdint.h
len.o: $(hdrdir)/ruby/internal/symbol.h
len.o: $(hdrdir)/ruby/internal/value.h
len.o: $(hdrdir)/ruby/internal/value_type.h
@@ -692,7 +532,6 @@ member.o: $(hdrdir)/ruby/internal/attr/noexcept.h
member.o: $(hdrdir)/ruby/internal/attr/noinline.h
member.o: $(hdrdir)/ruby/internal/attr/nonnull.h
member.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-member.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
member.o: $(hdrdir)/ruby/internal/attr/pure.h
member.o: $(hdrdir)/ruby/internal/attr/restrict.h
member.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -752,6 +591,7 @@ member.o: $(hdrdir)/ruby/internal/intern/enumerator.h
member.o: $(hdrdir)/ruby/internal/intern/error.h
member.o: $(hdrdir)/ruby/internal/intern/eval.h
member.o: $(hdrdir)/ruby/internal/intern/file.h
+member.o: $(hdrdir)/ruby/internal/intern/gc.h
member.o: $(hdrdir)/ruby/internal/intern/hash.h
member.o: $(hdrdir)/ruby/internal/intern/io.h
member.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -782,12 +622,12 @@ member.o: $(hdrdir)/ruby/internal/memory.h
member.o: $(hdrdir)/ruby/internal/method.h
member.o: $(hdrdir)/ruby/internal/module.h
member.o: $(hdrdir)/ruby/internal/newobj.h
+member.o: $(hdrdir)/ruby/internal/rgengc.h
member.o: $(hdrdir)/ruby/internal/scan_args.h
member.o: $(hdrdir)/ruby/internal/special_consts.h
member.o: $(hdrdir)/ruby/internal/static_assert.h
member.o: $(hdrdir)/ruby/internal/stdalign.h
member.o: $(hdrdir)/ruby/internal/stdbool.h
-member.o: $(hdrdir)/ruby/internal/stdckdint.h
member.o: $(hdrdir)/ruby/internal/symbol.h
member.o: $(hdrdir)/ruby/internal/value.h
member.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/struct/member.c b/ext/-test-/struct/member.c
index 29ddff93e8..f5400fe477 100644
--- a/ext/-test-/struct/member.c
+++ b/ext/-test-/struct/member.c
@@ -6,7 +6,7 @@ bug_struct_get(VALUE obj, VALUE name)
ID id = rb_check_id(&name);
if (!id) {
- rb_name_error_str(name, "'%"PRIsVALUE"' is not a struct member", name);
+ rb_name_error_str(name, "`%"PRIsVALUE"' is not a struct member", name);
}
return rb_struct_getmember(obj, id);
}
diff --git a/ext/-test-/symbol/depend b/ext/-test-/symbol/depend
index 7c76596fdf..b94e4ce821 100644
--- a/ext/-test-/symbol/depend
+++ b/ext/-test-/symbol/depend
@@ -52,7 +52,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -212,7 +212,6 @@ type.o: $(hdrdir)/ruby/internal/attr/noexcept.h
type.o: $(hdrdir)/ruby/internal/attr/noinline.h
type.o: $(hdrdir)/ruby/internal/attr/nonnull.h
type.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-type.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
type.o: $(hdrdir)/ruby/internal/attr/pure.h
type.o: $(hdrdir)/ruby/internal/attr/restrict.h
type.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -272,6 +271,7 @@ type.o: $(hdrdir)/ruby/internal/intern/enumerator.h
type.o: $(hdrdir)/ruby/internal/intern/error.h
type.o: $(hdrdir)/ruby/internal/intern/eval.h
type.o: $(hdrdir)/ruby/internal/intern/file.h
+type.o: $(hdrdir)/ruby/internal/intern/gc.h
type.o: $(hdrdir)/ruby/internal/intern/hash.h
type.o: $(hdrdir)/ruby/internal/intern/io.h
type.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -302,12 +302,12 @@ type.o: $(hdrdir)/ruby/internal/memory.h
type.o: $(hdrdir)/ruby/internal/method.h
type.o: $(hdrdir)/ruby/internal/module.h
type.o: $(hdrdir)/ruby/internal/newobj.h
+type.o: $(hdrdir)/ruby/internal/rgengc.h
type.o: $(hdrdir)/ruby/internal/scan_args.h
type.o: $(hdrdir)/ruby/internal/special_consts.h
type.o: $(hdrdir)/ruby/internal/static_assert.h
type.o: $(hdrdir)/ruby/internal/stdalign.h
type.o: $(hdrdir)/ruby/internal/stdbool.h
-type.o: $(hdrdir)/ruby/internal/stdckdint.h
type.o: $(hdrdir)/ruby/internal/symbol.h
type.o: $(hdrdir)/ruby/internal/value.h
type.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/thread/id/extconf.rb b/ext/-test-/thread/id/extconf.rb
deleted file mode 100644
index a0ae0eff15..0000000000
--- a/ext/-test-/thread/id/extconf.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-if have_func("gettid")
- create_makefile("-test-/thread/id")
-end
diff --git a/ext/-test-/thread/id/id.c b/ext/-test-/thread/id/id.c
deleted file mode 100644
index b46a5955e2..0000000000
--- a/ext/-test-/thread/id/id.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <ruby.h>
-
-static VALUE
-bug_gettid(VALUE self)
-{
- pid_t tid = gettid();
- return PIDT2NUM(tid);
-}
-
-void
-Init_id(void)
-{
- VALUE klass = rb_define_module_under(rb_define_module("Bug"), "ThreadID");
- rb_define_module_function(klass, "gettid", bug_gettid, 0);
-}
diff --git a/ext/-test-/thread/instrumentation/depend b/ext/-test-/thread/instrumentation/depend
index a37e4d5675..e2fcd060d8 100644
--- a/ext/-test-/thread/instrumentation/depend
+++ b/ext/-test-/thread/instrumentation/depend
@@ -52,7 +52,6 @@ instrumentation.o: $(hdrdir)/ruby/internal/attr/noexcept.h
instrumentation.o: $(hdrdir)/ruby/internal/attr/noinline.h
instrumentation.o: $(hdrdir)/ruby/internal/attr/nonnull.h
instrumentation.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-instrumentation.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
instrumentation.o: $(hdrdir)/ruby/internal/attr/pure.h
instrumentation.o: $(hdrdir)/ruby/internal/attr/restrict.h
instrumentation.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ instrumentation.o: $(hdrdir)/ruby/internal/intern/enumerator.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/error.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/eval.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/file.h
+instrumentation.o: $(hdrdir)/ruby/internal/intern/gc.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/hash.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/io.h
instrumentation.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ instrumentation.o: $(hdrdir)/ruby/internal/memory.h
instrumentation.o: $(hdrdir)/ruby/internal/method.h
instrumentation.o: $(hdrdir)/ruby/internal/module.h
instrumentation.o: $(hdrdir)/ruby/internal/newobj.h
+instrumentation.o: $(hdrdir)/ruby/internal/rgengc.h
instrumentation.o: $(hdrdir)/ruby/internal/scan_args.h
instrumentation.o: $(hdrdir)/ruby/internal/special_consts.h
instrumentation.o: $(hdrdir)/ruby/internal/static_assert.h
instrumentation.o: $(hdrdir)/ruby/internal/stdalign.h
instrumentation.o: $(hdrdir)/ruby/internal/stdbool.h
-instrumentation.o: $(hdrdir)/ruby/internal/stdckdint.h
instrumentation.o: $(hdrdir)/ruby/internal/symbol.h
instrumentation.o: $(hdrdir)/ruby/internal/value.h
instrumentation.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/thread/instrumentation/instrumentation.c b/ext/-test-/thread/instrumentation/instrumentation.c
index d81bc0f2a7..d2a2c2740b 100644
--- a/ext/-test-/thread/instrumentation/instrumentation.c
+++ b/ext/-test-/thread/instrumentation/instrumentation.c
@@ -2,137 +2,90 @@
#include "ruby/atomic.h"
#include "ruby/thread.h"
-#ifndef RB_THREAD_LOCAL_SPECIFIER
-# define RB_THREAD_LOCAL_SPECIFIER
+static rb_atomic_t started_count = 0;
+static rb_atomic_t ready_count = 0;
+static rb_atomic_t resumed_count = 0;
+static rb_atomic_t suspended_count = 0;
+static rb_atomic_t exited_count = 0;
+
+#if __STDC_VERSION__ >= 201112
+ #define RB_THREAD_LOCAL_SPECIFIER _Thread_local
+#elif defined(__GNUC__) && !defined(RB_THREAD_LOCAL_SPECIFIER_IS_UNSUPPORTED)
+ /* note that ICC (linux) and Clang are covered by __GNUC__ */
+ #define RB_THREAD_LOCAL_SPECIFIER __thread
+#else
+ #define RB_THREAD_LOCAL_SPECIFIER
#endif
-static VALUE last_thread = Qnil;
-static VALUE timeline_value = Qnil;
-
-struct thread_event {
- VALUE thread;
- rb_event_flag_t event;
-};
-
-#define MAX_EVENTS 1024
-static struct thread_event event_timeline[MAX_EVENTS];
-static rb_atomic_t timeline_cursor;
-
-static void
-event_timeline_gc_mark(void *ptr) {
- rb_atomic_t cursor;
- for (cursor = 0; cursor < timeline_cursor; cursor++) {
- rb_gc_mark(event_timeline[cursor].thread);
- }
-}
-
-static const rb_data_type_t event_timeline_type = {
- "TestThreadInstrumentation/event_timeline",
- {event_timeline_gc_mark, NULL, NULL,},
- 0, 0,
- RUBY_TYPED_FREE_IMMEDIATELY,
-};
+static RB_THREAD_LOCAL_SPECIFIER unsigned int local_ready_count = 0;
+static RB_THREAD_LOCAL_SPECIFIER unsigned int local_resumed_count = 0;
+static RB_THREAD_LOCAL_SPECIFIER unsigned int local_suspended_count = 0;
static void
-reset_timeline(void)
-{
- timeline_cursor = 0;
- memset(event_timeline, 0, sizeof(struct thread_event) * MAX_EVENTS);
-}
-
-static rb_event_flag_t
-find_last_event(VALUE thread)
-{
- rb_atomic_t cursor = timeline_cursor;
- if (cursor) {
- do {
- if (event_timeline[cursor].thread == thread){
- return event_timeline[cursor].event;
- }
- cursor--;
- } while (cursor > 0);
- }
- return 0;
-}
-
-static const char *
-event_name(rb_event_flag_t event)
+ex_callback(rb_event_flag_t event, const rb_internal_thread_event_data_t *event_data, void *user_data)
{
switch (event) {
case RUBY_INTERNAL_THREAD_EVENT_STARTED:
- return "started";
+ RUBY_ATOMIC_INC(started_count);
+ break;
case RUBY_INTERNAL_THREAD_EVENT_READY:
- return "ready";
+ RUBY_ATOMIC_INC(ready_count);
+ local_ready_count++;
+ break;
case RUBY_INTERNAL_THREAD_EVENT_RESUMED:
- return "resumed";
+ RUBY_ATOMIC_INC(resumed_count);
+ local_resumed_count++;
+ break;
case RUBY_INTERNAL_THREAD_EVENT_SUSPENDED:
- return "suspended";
+ RUBY_ATOMIC_INC(suspended_count);
+ local_suspended_count++;
+ break;
case RUBY_INTERNAL_THREAD_EVENT_EXITED:
- return "exited";
+ RUBY_ATOMIC_INC(exited_count);
+ break;
}
- return "no-event";
}
-static void
-unexpected(bool strict, const char *format, VALUE thread, rb_event_flag_t last_event)
+static rb_internal_thread_event_hook_t * single_hook = NULL;
+
+static VALUE
+thread_counters(VALUE thread)
{
- const char *last_event_name = event_name(last_event);
- if (strict) {
- rb_bug(format, thread, last_event_name);
- }
- else {
- fprintf(stderr, format, thread, last_event_name);
- fprintf(stderr, "\n");
- }
+ VALUE array = rb_ary_new2(5);
+ rb_ary_push(array, UINT2NUM(started_count));
+ rb_ary_push(array, UINT2NUM(ready_count));
+ rb_ary_push(array, UINT2NUM(resumed_count));
+ rb_ary_push(array, UINT2NUM(suspended_count));
+ rb_ary_push(array, UINT2NUM(exited_count));
+ return array;
}
-static void
-ex_callback(rb_event_flag_t event, const rb_internal_thread_event_data_t *event_data, void *user_data)
+static VALUE
+thread_local_counters(VALUE thread)
{
- rb_event_flag_t last_event = find_last_event(event_data->thread);
- bool strict = (bool)user_data;
-
- if (last_event != 0) {
- switch (event) {
- case RUBY_INTERNAL_THREAD_EVENT_STARTED:
- unexpected(strict, "[thread=%"PRIxVALUE"] `started` event can't be preceded by `%s`", event_data->thread, last_event);
- break;
- case RUBY_INTERNAL_THREAD_EVENT_READY:
- if (last_event != RUBY_INTERNAL_THREAD_EVENT_STARTED && last_event != RUBY_INTERNAL_THREAD_EVENT_SUSPENDED) {
- unexpected(strict, "[thread=%"PRIxVALUE"] `ready` must be preceded by `started` or `suspended`, got: `%s`", event_data->thread, last_event);
- }
- break;
- case RUBY_INTERNAL_THREAD_EVENT_RESUMED:
- if (last_event != RUBY_INTERNAL_THREAD_EVENT_READY) {
- unexpected(strict, "[thread=%"PRIxVALUE"] `resumed` must be preceded by `ready`, got: `%s`", event_data->thread, last_event);
- }
- break;
- case RUBY_INTERNAL_THREAD_EVENT_SUSPENDED:
- if (last_event != RUBY_INTERNAL_THREAD_EVENT_RESUMED) {
- unexpected(strict, "[thread=%"PRIxVALUE"] `suspended` must be preceded by `resumed`, got: `%s`", event_data->thread, last_event);
- }
- break;
- case RUBY_INTERNAL_THREAD_EVENT_EXITED:
- if (last_event != RUBY_INTERNAL_THREAD_EVENT_RESUMED && last_event != RUBY_INTERNAL_THREAD_EVENT_SUSPENDED) {
- unexpected(strict, "[thread=%"PRIxVALUE"] `exited` must be preceded by `resumed` or `suspended`, got: `%s`", event_data->thread, last_event);
- }
- break;
- }
- }
-
- rb_atomic_t cursor = RUBY_ATOMIC_FETCH_ADD(timeline_cursor, 1);
- if (cursor >= MAX_EVENTS) {
- rb_bug("TestThreadInstrumentation: ran out of event_timeline space");
- }
-
- event_timeline[cursor].thread = event_data->thread;
- event_timeline[cursor].event = event;
+ VALUE array = rb_ary_new2(3);
+ rb_ary_push(array, UINT2NUM(local_ready_count));
+ rb_ary_push(array, UINT2NUM(local_resumed_count));
+ rb_ary_push(array, UINT2NUM(local_suspended_count));
+ return array;
}
-static rb_internal_thread_event_hook_t * single_hook = NULL;
+static VALUE
+thread_reset_counters(VALUE thread)
+{
+ RUBY_ATOMIC_SET(started_count, 0);
+ RUBY_ATOMIC_SET(ready_count, 0);
+ RUBY_ATOMIC_SET(resumed_count, 0);
+ RUBY_ATOMIC_SET(suspended_count, 0);
+ RUBY_ATOMIC_SET(exited_count, 0);
+ local_ready_count = 0;
+ local_resumed_count = 0;
+ local_suspended_count = 0;
+ return Qtrue;
+}
static VALUE
-thread_register_callback(VALUE thread, VALUE strict)
+thread_register_callback(VALUE thread)
{
single_hook = rb_internal_thread_add_event_hook(
ex_callback,
@@ -141,33 +94,13 @@ thread_register_callback(VALUE thread, VALUE strict)
RUBY_INTERNAL_THREAD_EVENT_RESUMED |
RUBY_INTERNAL_THREAD_EVENT_SUSPENDED |
RUBY_INTERNAL_THREAD_EVENT_EXITED,
- (void *)RTEST(strict)
+ NULL
);
return Qnil;
}
static VALUE
-event_symbol(rb_event_flag_t event)
-{
- switch (event) {
- case RUBY_INTERNAL_THREAD_EVENT_STARTED:
- return rb_id2sym(rb_intern("started"));
- case RUBY_INTERNAL_THREAD_EVENT_READY:
- return rb_id2sym(rb_intern("ready"));
- case RUBY_INTERNAL_THREAD_EVENT_RESUMED:
- return rb_id2sym(rb_intern("resumed"));
- case RUBY_INTERNAL_THREAD_EVENT_SUSPENDED:
- return rb_id2sym(rb_intern("suspended"));
- case RUBY_INTERNAL_THREAD_EVENT_EXITED:
- return rb_id2sym(rb_intern("exited"));
- default:
- rb_bug("TestThreadInstrumentation: Unexpected event");
- break;
- }
-}
-
-static VALUE
thread_unregister_callback(VALUE thread)
{
if (single_hook) {
@@ -175,18 +108,7 @@ thread_unregister_callback(VALUE thread)
single_hook = NULL;
}
- VALUE events = rb_ary_new_capa(timeline_cursor);
- rb_atomic_t cursor;
- for (cursor = 0; cursor < timeline_cursor; cursor++) {
- VALUE pair = rb_ary_new_capa(2);
- rb_ary_push(pair, event_timeline[cursor].thread);
- rb_ary_push(pair, event_symbol(event_timeline[cursor].event));
- rb_ary_push(events, pair);
- }
-
- reset_timeline();
-
- return events;
+ return Qnil;
}
static VALUE
@@ -210,11 +132,10 @@ Init_instrumentation(void)
{
VALUE mBug = rb_define_module("Bug");
VALUE klass = rb_define_module_under(mBug, "ThreadInstrumentation");
- rb_global_variable(&timeline_value);
- timeline_value = TypedData_Wrap_Struct(0, &event_timeline_type, 0);
-
- rb_global_variable(&last_thread);
- rb_define_singleton_method(klass, "register_callback", thread_register_callback, 1);
+ rb_define_singleton_method(klass, "counters", thread_counters, 0);
+ rb_define_singleton_method(klass, "local_counters", thread_local_counters, 0);
+ rb_define_singleton_method(klass, "reset_counters", thread_reset_counters, 0);
+ rb_define_singleton_method(klass, "register_callback", thread_register_callback, 0);
rb_define_singleton_method(klass, "unregister_callback", thread_unregister_callback, 0);
rb_define_singleton_method(klass, "register_and_unregister_callbacks", thread_register_and_unregister_callback, 0);
}
diff --git a/ext/-test-/thread/lock_native_thread/extconf.rb b/ext/-test-/thread/lock_native_thread/extconf.rb
deleted file mode 100644
index 832bfde01a..0000000000
--- a/ext/-test-/thread/lock_native_thread/extconf.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-# frozen_string_literal: false
-create_makefile("-test-/thread/lock_native_thread")
diff --git a/ext/-test-/thread/lock_native_thread/lock_native_thread.c b/ext/-test-/thread/lock_native_thread/lock_native_thread.c
deleted file mode 100644
index 2eb75809a9..0000000000
--- a/ext/-test-/thread/lock_native_thread/lock_native_thread.c
+++ /dev/null
@@ -1,50 +0,0 @@
-
-#include "ruby/ruby.h"
-#include "ruby/thread.h"
-
-#ifdef HAVE_PTHREAD_H
-#include <pthread.h>
-
-static pthread_key_t tls_key;
-
-static VALUE
-get_tls(VALUE self)
-{
- return (VALUE)pthread_getspecific(tls_key);
-}
-
-static VALUE
-set_tls(VALUE self, VALUE vn)
-{
- pthread_setspecific(tls_key, (void *)vn);
- return Qnil;
-}
-
-static VALUE
-lock_native_thread(VALUE self)
-{
- return rb_thread_lock_native_thread() ? Qtrue : Qfalse;
-}
-
-void
-Init_lock_native_thread(void)
-{
- int r;
-
- if ((r = pthread_key_create(&tls_key, NULL)) != 0) {
- rb_bug("pthread_key_create() returns %d", r);
- }
- pthread_setspecific(tls_key, NULL);
-
- rb_define_method(rb_cThread, "lock_native_thread", lock_native_thread, 0);
- rb_define_method(rb_cThread, "get_tls", get_tls, 0);
- rb_define_method(rb_cThread, "set_tls", set_tls, 1);
-}
-
-#else // HAVE_PTHREAD_H
-void
-Init_lock_native_thread(void)
-{
- // do nothing
-}
-#endif // HAVE_PTHREAD_H
diff --git a/ext/-test-/thread_fd/depend b/ext/-test-/thread_fd/depend
index 0fda9f6dbf..ecf738108a 100644
--- a/ext/-test-/thread_fd/depend
+++ b/ext/-test-/thread_fd/depend
@@ -51,7 +51,6 @@ thread_fd.o: $(hdrdir)/ruby/internal/attr/noexcept.h
thread_fd.o: $(hdrdir)/ruby/internal/attr/noinline.h
thread_fd.o: $(hdrdir)/ruby/internal/attr/nonnull.h
thread_fd.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-thread_fd.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
thread_fd.o: $(hdrdir)/ruby/internal/attr/pure.h
thread_fd.o: $(hdrdir)/ruby/internal/attr/restrict.h
thread_fd.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ thread_fd.o: $(hdrdir)/ruby/internal/intern/enumerator.h
thread_fd.o: $(hdrdir)/ruby/internal/intern/error.h
thread_fd.o: $(hdrdir)/ruby/internal/intern/eval.h
thread_fd.o: $(hdrdir)/ruby/internal/intern/file.h
+thread_fd.o: $(hdrdir)/ruby/internal/intern/gc.h
thread_fd.o: $(hdrdir)/ruby/internal/intern/hash.h
thread_fd.o: $(hdrdir)/ruby/internal/intern/io.h
thread_fd.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,12 +141,12 @@ thread_fd.o: $(hdrdir)/ruby/internal/memory.h
thread_fd.o: $(hdrdir)/ruby/internal/method.h
thread_fd.o: $(hdrdir)/ruby/internal/module.h
thread_fd.o: $(hdrdir)/ruby/internal/newobj.h
+thread_fd.o: $(hdrdir)/ruby/internal/rgengc.h
thread_fd.o: $(hdrdir)/ruby/internal/scan_args.h
thread_fd.o: $(hdrdir)/ruby/internal/special_consts.h
thread_fd.o: $(hdrdir)/ruby/internal/static_assert.h
thread_fd.o: $(hdrdir)/ruby/internal/stdalign.h
thread_fd.o: $(hdrdir)/ruby/internal/stdbool.h
-thread_fd.o: $(hdrdir)/ruby/internal/stdckdint.h
thread_fd.o: $(hdrdir)/ruby/internal/symbol.h
thread_fd.o: $(hdrdir)/ruby/internal/value.h
thread_fd.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/time/depend b/ext/-test-/time/depend
index 5ed791bcc5..b7d1a2b114 100644
--- a/ext/-test-/time/depend
+++ b/ext/-test-/time/depend
@@ -52,7 +52,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -213,7 +213,6 @@ leap_second.o: $(hdrdir)/ruby/internal/attr/noexcept.h
leap_second.o: $(hdrdir)/ruby/internal/attr/noinline.h
leap_second.o: $(hdrdir)/ruby/internal/attr/nonnull.h
leap_second.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-leap_second.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
leap_second.o: $(hdrdir)/ruby/internal/attr/pure.h
leap_second.o: $(hdrdir)/ruby/internal/attr/restrict.h
leap_second.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -273,6 +272,7 @@ leap_second.o: $(hdrdir)/ruby/internal/intern/enumerator.h
leap_second.o: $(hdrdir)/ruby/internal/intern/error.h
leap_second.o: $(hdrdir)/ruby/internal/intern/eval.h
leap_second.o: $(hdrdir)/ruby/internal/intern/file.h
+leap_second.o: $(hdrdir)/ruby/internal/intern/gc.h
leap_second.o: $(hdrdir)/ruby/internal/intern/hash.h
leap_second.o: $(hdrdir)/ruby/internal/intern/io.h
leap_second.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -303,12 +303,12 @@ leap_second.o: $(hdrdir)/ruby/internal/memory.h
leap_second.o: $(hdrdir)/ruby/internal/method.h
leap_second.o: $(hdrdir)/ruby/internal/module.h
leap_second.o: $(hdrdir)/ruby/internal/newobj.h
+leap_second.o: $(hdrdir)/ruby/internal/rgengc.h
leap_second.o: $(hdrdir)/ruby/internal/scan_args.h
leap_second.o: $(hdrdir)/ruby/internal/special_consts.h
leap_second.o: $(hdrdir)/ruby/internal/static_assert.h
leap_second.o: $(hdrdir)/ruby/internal/stdalign.h
leap_second.o: $(hdrdir)/ruby/internal/stdbool.h
-leap_second.o: $(hdrdir)/ruby/internal/stdckdint.h
leap_second.o: $(hdrdir)/ruby/internal/symbol.h
leap_second.o: $(hdrdir)/ruby/internal/value.h
leap_second.o: $(hdrdir)/ruby/internal/value_type.h
@@ -377,7 +377,6 @@ new.o: $(hdrdir)/ruby/internal/attr/noexcept.h
new.o: $(hdrdir)/ruby/internal/attr/noinline.h
new.o: $(hdrdir)/ruby/internal/attr/nonnull.h
new.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-new.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
new.o: $(hdrdir)/ruby/internal/attr/pure.h
new.o: $(hdrdir)/ruby/internal/attr/restrict.h
new.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -437,6 +436,7 @@ new.o: $(hdrdir)/ruby/internal/intern/enumerator.h
new.o: $(hdrdir)/ruby/internal/intern/error.h
new.o: $(hdrdir)/ruby/internal/intern/eval.h
new.o: $(hdrdir)/ruby/internal/intern/file.h
+new.o: $(hdrdir)/ruby/internal/intern/gc.h
new.o: $(hdrdir)/ruby/internal/intern/hash.h
new.o: $(hdrdir)/ruby/internal/intern/io.h
new.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -467,12 +467,12 @@ new.o: $(hdrdir)/ruby/internal/memory.h
new.o: $(hdrdir)/ruby/internal/method.h
new.o: $(hdrdir)/ruby/internal/module.h
new.o: $(hdrdir)/ruby/internal/newobj.h
+new.o: $(hdrdir)/ruby/internal/rgengc.h
new.o: $(hdrdir)/ruby/internal/scan_args.h
new.o: $(hdrdir)/ruby/internal/special_consts.h
new.o: $(hdrdir)/ruby/internal/static_assert.h
new.o: $(hdrdir)/ruby/internal/stdalign.h
new.o: $(hdrdir)/ruby/internal/stdbool.h
-new.o: $(hdrdir)/ruby/internal/stdckdint.h
new.o: $(hdrdir)/ruby/internal/symbol.h
new.o: $(hdrdir)/ruby/internal/value.h
new.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/tracepoint/depend b/ext/-test-/tracepoint/depend
index 133663b3bd..8e2aa7eab6 100644
--- a/ext/-test-/tracepoint/depend
+++ b/ext/-test-/tracepoint/depend
@@ -52,7 +52,6 @@ gc_hook.o: $(hdrdir)/ruby/internal/attr/noexcept.h
gc_hook.o: $(hdrdir)/ruby/internal/attr/noinline.h
gc_hook.o: $(hdrdir)/ruby/internal/attr/nonnull.h
gc_hook.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-gc_hook.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
gc_hook.o: $(hdrdir)/ruby/internal/attr/pure.h
gc_hook.o: $(hdrdir)/ruby/internal/attr/restrict.h
gc_hook.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ gc_hook.o: $(hdrdir)/ruby/internal/intern/enumerator.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/error.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/eval.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/file.h
+gc_hook.o: $(hdrdir)/ruby/internal/intern/gc.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/hash.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/io.h
gc_hook.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ gc_hook.o: $(hdrdir)/ruby/internal/memory.h
gc_hook.o: $(hdrdir)/ruby/internal/method.h
gc_hook.o: $(hdrdir)/ruby/internal/module.h
gc_hook.o: $(hdrdir)/ruby/internal/newobj.h
+gc_hook.o: $(hdrdir)/ruby/internal/rgengc.h
gc_hook.o: $(hdrdir)/ruby/internal/scan_args.h
gc_hook.o: $(hdrdir)/ruby/internal/special_consts.h
gc_hook.o: $(hdrdir)/ruby/internal/static_assert.h
gc_hook.o: $(hdrdir)/ruby/internal/stdalign.h
gc_hook.o: $(hdrdir)/ruby/internal/stdbool.h
-gc_hook.o: $(hdrdir)/ruby/internal/stdckdint.h
gc_hook.o: $(hdrdir)/ruby/internal/symbol.h
gc_hook.o: $(hdrdir)/ruby/internal/value.h
gc_hook.o: $(hdrdir)/ruby/internal/value_type.h
@@ -212,7 +212,6 @@ tracepoint.o: $(hdrdir)/ruby/internal/attr/noexcept.h
tracepoint.o: $(hdrdir)/ruby/internal/attr/noinline.h
tracepoint.o: $(hdrdir)/ruby/internal/attr/nonnull.h
tracepoint.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-tracepoint.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
tracepoint.o: $(hdrdir)/ruby/internal/attr/pure.h
tracepoint.o: $(hdrdir)/ruby/internal/attr/restrict.h
tracepoint.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -272,6 +271,7 @@ tracepoint.o: $(hdrdir)/ruby/internal/intern/enumerator.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/error.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/eval.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/file.h
+tracepoint.o: $(hdrdir)/ruby/internal/intern/gc.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/hash.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/io.h
tracepoint.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -302,12 +302,12 @@ tracepoint.o: $(hdrdir)/ruby/internal/memory.h
tracepoint.o: $(hdrdir)/ruby/internal/method.h
tracepoint.o: $(hdrdir)/ruby/internal/module.h
tracepoint.o: $(hdrdir)/ruby/internal/newobj.h
+tracepoint.o: $(hdrdir)/ruby/internal/rgengc.h
tracepoint.o: $(hdrdir)/ruby/internal/scan_args.h
tracepoint.o: $(hdrdir)/ruby/internal/special_consts.h
tracepoint.o: $(hdrdir)/ruby/internal/static_assert.h
tracepoint.o: $(hdrdir)/ruby/internal/stdalign.h
tracepoint.o: $(hdrdir)/ruby/internal/stdbool.h
-tracepoint.o: $(hdrdir)/ruby/internal/stdckdint.h
tracepoint.o: $(hdrdir)/ruby/internal/symbol.h
tracepoint.o: $(hdrdir)/ruby/internal/value.h
tracepoint.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/tracepoint/gc_hook.c b/ext/-test-/tracepoint/gc_hook.c
index 54c06c54a5..a3f4e7f68a 100644
--- a/ext/-test-/tracepoint/gc_hook.c
+++ b/ext/-test-/tracepoint/gc_hook.c
@@ -33,9 +33,7 @@ gc_start_end_i(VALUE tpval, void *data)
}
if (invoking == 0) {
- /* will overwrite the existing handle with new data on the second and subsequent call */
- rb_postponed_job_handle_t h = rb_postponed_job_preregister(0, invoke_proc, data);
- rb_postponed_job_trigger(h);
+ rb_postponed_job_register(0, invoke_proc, data);
}
}
diff --git a/ext/-test-/typeddata/depend b/ext/-test-/typeddata/depend
index 6c0847c82d..02f6de6e20 100644
--- a/ext/-test-/typeddata/depend
+++ b/ext/-test-/typeddata/depend
@@ -52,7 +52,6 @@ typeddata.o: $(hdrdir)/ruby/internal/attr/noexcept.h
typeddata.o: $(hdrdir)/ruby/internal/attr/noinline.h
typeddata.o: $(hdrdir)/ruby/internal/attr/nonnull.h
typeddata.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-typeddata.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
typeddata.o: $(hdrdir)/ruby/internal/attr/pure.h
typeddata.o: $(hdrdir)/ruby/internal/attr/restrict.h
typeddata.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ typeddata.o: $(hdrdir)/ruby/internal/intern/enumerator.h
typeddata.o: $(hdrdir)/ruby/internal/intern/error.h
typeddata.o: $(hdrdir)/ruby/internal/intern/eval.h
typeddata.o: $(hdrdir)/ruby/internal/intern/file.h
+typeddata.o: $(hdrdir)/ruby/internal/intern/gc.h
typeddata.o: $(hdrdir)/ruby/internal/intern/hash.h
typeddata.o: $(hdrdir)/ruby/internal/intern/io.h
typeddata.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ typeddata.o: $(hdrdir)/ruby/internal/memory.h
typeddata.o: $(hdrdir)/ruby/internal/method.h
typeddata.o: $(hdrdir)/ruby/internal/module.h
typeddata.o: $(hdrdir)/ruby/internal/newobj.h
+typeddata.o: $(hdrdir)/ruby/internal/rgengc.h
typeddata.o: $(hdrdir)/ruby/internal/scan_args.h
typeddata.o: $(hdrdir)/ruby/internal/special_consts.h
typeddata.o: $(hdrdir)/ruby/internal/static_assert.h
typeddata.o: $(hdrdir)/ruby/internal/stdalign.h
typeddata.o: $(hdrdir)/ruby/internal/stdbool.h
-typeddata.o: $(hdrdir)/ruby/internal/stdckdint.h
typeddata.o: $(hdrdir)/ruby/internal/symbol.h
typeddata.o: $(hdrdir)/ruby/internal/value.h
typeddata.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/vm/depend b/ext/-test-/vm/depend
index 422b40a32d..7f110d48eb 100644
--- a/ext/-test-/vm/depend
+++ b/ext/-test-/vm/depend
@@ -51,7 +51,6 @@ at_exit.o: $(hdrdir)/ruby/internal/attr/noexcept.h
at_exit.o: $(hdrdir)/ruby/internal/attr/noinline.h
at_exit.o: $(hdrdir)/ruby/internal/attr/nonnull.h
at_exit.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-at_exit.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
at_exit.o: $(hdrdir)/ruby/internal/attr/pure.h
at_exit.o: $(hdrdir)/ruby/internal/attr/restrict.h
at_exit.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ at_exit.o: $(hdrdir)/ruby/internal/intern/enumerator.h
at_exit.o: $(hdrdir)/ruby/internal/intern/error.h
at_exit.o: $(hdrdir)/ruby/internal/intern/eval.h
at_exit.o: $(hdrdir)/ruby/internal/intern/file.h
+at_exit.o: $(hdrdir)/ruby/internal/intern/gc.h
at_exit.o: $(hdrdir)/ruby/internal/intern/hash.h
at_exit.o: $(hdrdir)/ruby/internal/intern/io.h
at_exit.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,12 +141,12 @@ at_exit.o: $(hdrdir)/ruby/internal/memory.h
at_exit.o: $(hdrdir)/ruby/internal/method.h
at_exit.o: $(hdrdir)/ruby/internal/module.h
at_exit.o: $(hdrdir)/ruby/internal/newobj.h
+at_exit.o: $(hdrdir)/ruby/internal/rgengc.h
at_exit.o: $(hdrdir)/ruby/internal/scan_args.h
at_exit.o: $(hdrdir)/ruby/internal/special_consts.h
at_exit.o: $(hdrdir)/ruby/internal/static_assert.h
at_exit.o: $(hdrdir)/ruby/internal/stdalign.h
at_exit.o: $(hdrdir)/ruby/internal/stdbool.h
-at_exit.o: $(hdrdir)/ruby/internal/stdckdint.h
at_exit.o: $(hdrdir)/ruby/internal/symbol.h
at_exit.o: $(hdrdir)/ruby/internal/value.h
at_exit.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/-test-/wait/depend b/ext/-test-/wait/depend
index 7997a16709..e71bda9968 100644
--- a/ext/-test-/wait/depend
+++ b/ext/-test-/wait/depend
@@ -52,7 +52,6 @@ wait.o: $(hdrdir)/ruby/internal/attr/noexcept.h
wait.o: $(hdrdir)/ruby/internal/attr/noinline.h
wait.o: $(hdrdir)/ruby/internal/attr/nonnull.h
wait.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-wait.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
wait.o: $(hdrdir)/ruby/internal/attr/pure.h
wait.o: $(hdrdir)/ruby/internal/attr/restrict.h
wait.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -121,6 +120,7 @@ wait.o: $(hdrdir)/ruby/internal/intern/enumerator.h
wait.o: $(hdrdir)/ruby/internal/intern/error.h
wait.o: $(hdrdir)/ruby/internal/intern/eval.h
wait.o: $(hdrdir)/ruby/internal/intern/file.h
+wait.o: $(hdrdir)/ruby/internal/intern/gc.h
wait.o: $(hdrdir)/ruby/internal/intern/hash.h
wait.o: $(hdrdir)/ruby/internal/intern/io.h
wait.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -151,12 +151,12 @@ wait.o: $(hdrdir)/ruby/internal/memory.h
wait.o: $(hdrdir)/ruby/internal/method.h
wait.o: $(hdrdir)/ruby/internal/module.h
wait.o: $(hdrdir)/ruby/internal/newobj.h
+wait.o: $(hdrdir)/ruby/internal/rgengc.h
wait.o: $(hdrdir)/ruby/internal/scan_args.h
wait.o: $(hdrdir)/ruby/internal/special_consts.h
wait.o: $(hdrdir)/ruby/internal/static_assert.h
wait.o: $(hdrdir)/ruby/internal/stdalign.h
wait.o: $(hdrdir)/ruby/internal/stdbool.h
-wait.o: $(hdrdir)/ruby/internal/stdckdint.h
wait.o: $(hdrdir)/ruby/internal/symbol.h
wait.o: $(hdrdir)/ruby/internal/value.h
wait.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/.document b/ext/.document
index 0efd511a61..aeb40c60fb 100644
--- a/ext/.document
+++ b/ext/.document
@@ -11,6 +11,7 @@ date/date_parse.c
date/date_strftime.c
date/date_strptime.c
date/lib
+dbm/dbm.c
digest/bubblebabble/bubblebabble.c
digest/digest.c
digest/lib
@@ -21,6 +22,7 @@ digest/sha2/sha2init.c
digest/sha2/lib
etc/etc.c
fcntl/fcntl.c
+fiber/fiber.c
fiddle/closure.c
fiddle/conversions.c
fiddle/fiddle.c
@@ -29,7 +31,9 @@ fiddle/pinned.c
fiddle/pointer.c
fiddle/handle.c
fiddle/lib
-io/console/
+gdbm/gdbm.c
+io/console/console.c
+io/console/lib
io/nonblock/nonblock.c
io/wait/wait.c
json/generator/generator.c
diff --git a/ext/Setup b/ext/Setup
index 9c3e2f48fe..0376e2fc6c 100644
--- a/ext/Setup
+++ b/ext/Setup
@@ -5,6 +5,7 @@
#continuation
#coverage
#date
+#dbm
#digest/bubblebabble
#digest
#digest/md5
@@ -13,7 +14,9 @@
#digest/sha2
#etc
#fcntl
+#fiber
#fiddle
+#gdbm
#io/console
#io/nonblock
#io/wait
diff --git a/ext/Setup.atheos b/ext/Setup.atheos
index 91f73f32f9..3f6263b1e2 100644
--- a/ext/Setup.atheos
+++ b/ext/Setup.atheos
@@ -1,19 +1,23 @@
option nodynamic
+#Win32API
bigdecimal
cgi/escape
+dbm
digest
digest/md5
digest/rmd160
digest/sha1
digest/sha2
+enumerator
etc
fcntl
+gdbm
io/wait
nkf
#openssl
pty
-#racc/cparse
+racc/parse
readline
ripper
socket
diff --git a/ext/Setup.nt b/ext/Setup.nt
index 1278f183e4..dc36aa8688 100644
--- a/ext/Setup.nt
+++ b/ext/Setup.nt
@@ -1,20 +1,24 @@
#option platform cygwin|mingw|mswin
#option nodynamic
+Win32API
bigdecimal
cgi/escape
+#dbm
digest
digest/md5
digest/rmd160
digest/sha1
digest/sha2
+enumerator
etc
fcntl
+#gdbm
#io/wait
nkf
#openssl
#pty
-#racc/cparse
+racc/cparse
#readline
#ripper
socket
diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c
new file mode 100644
index 0000000000..d6ea35c615
--- /dev/null
+++ b/ext/bigdecimal/bigdecimal.c
@@ -0,0 +1,7724 @@
+/*
+ *
+ * Ruby BigDecimal(Variable decimal precision) extension library.
+ *
+ * Copyright(C) 2002 by Shigeo Kobayashi(shigeo@tinyforest.gr.jp)
+ *
+ */
+
+/* #define BIGDECIMAL_DEBUG 1 */
+
+#include "bigdecimal.h"
+#include "ruby/util.h"
+
+#ifndef BIGDECIMAL_DEBUG
+# undef NDEBUG
+# define NDEBUG
+#endif
+#include <assert.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+
+#include "bits.h"
+#include "static_assert.h"
+
+/* #define ENABLE_NUMERIC_STRING */
+
+#define SIGNED_VALUE_MAX INTPTR_MAX
+#define SIGNED_VALUE_MIN INTPTR_MIN
+#define MUL_OVERFLOW_SIGNED_VALUE_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, SIGNED_VALUE_MIN, SIGNED_VALUE_MAX)
+
+VALUE rb_cBigDecimal;
+VALUE rb_mBigMath;
+
+static ID id_BigDecimal_exception_mode;
+static ID id_BigDecimal_rounding_mode;
+static ID id_BigDecimal_precision_limit;
+
+static ID id_up;
+static ID id_down;
+static ID id_truncate;
+static ID id_half_up;
+static ID id_default;
+static ID id_half_down;
+static ID id_half_even;
+static ID id_banker;
+static ID id_ceiling;
+static ID id_ceil;
+static ID id_floor;
+static ID id_to_r;
+static ID id_eq;
+static ID id_half;
+
+#define RBD_NUM_ROUNDING_MODES 11
+
+static struct {
+ ID id;
+ uint8_t mode;
+} rbd_rounding_modes[RBD_NUM_ROUNDING_MODES];
+
+/* MACRO's to guard objects from GC by keeping them in stack */
+#ifdef RBIMPL_ATTR_MAYBE_UNUSED
+#define ENTER(n) RBIMPL_ATTR_MAYBE_UNUSED() volatile VALUE vStack[n];int iStack=0
+#else
+#define ENTER(n) volatile VALUE RB_UNUSED_VAR(vStack[n]);int iStack=0
+#endif
+#define PUSH(x) (vStack[iStack++] = (VALUE)(x))
+#define SAVE(p) PUSH((p)->obj)
+#define GUARD_OBJ(p,y) ((p)=(y), SAVE(p))
+
+#define BASE_FIG BIGDECIMAL_COMPONENT_FIGURES
+#define BASE BIGDECIMAL_BASE
+
+#define HALF_BASE (BASE/2)
+#define BASE1 (BASE/10)
+
+#define LOG10_2 0.3010299956639812
+
+#ifndef RRATIONAL_ZERO_P
+# define RRATIONAL_ZERO_P(x) (FIXNUM_P(rb_rational_num(x)) && \
+ FIX2LONG(rb_rational_num(x)) == 0)
+#endif
+
+#ifndef RRATIONAL_NEGATIVE_P
+# define RRATIONAL_NEGATIVE_P(x) RTEST(rb_funcall((x), '<', 1, INT2FIX(0)))
+#endif
+
+#ifndef DECIMAL_SIZE_OF_BITS
+#define DECIMAL_SIZE_OF_BITS(n) (((n) * 3010 + 9998) / 9999)
+/* an approximation of ceil(n * log10(2)), upto 65536 at least */
+#endif
+
+#ifdef PRIsVALUE
+# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
+# define RB_OBJ_STRING(obj) (obj)
+#else
+# define PRIsVALUE "s"
+# define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
+# define RB_OBJ_STRING(obj) StringValueCStr(obj)
+#endif
+
+#ifndef MAYBE_UNUSED
+# define MAYBE_UNUSED(x) x
+#endif
+
+#define BIGDECIMAL_POSITIVE_P(bd) ((bd)->sign > 0)
+#define BIGDECIMAL_NEGATIVE_P(bd) ((bd)->sign < 0)
+
+/*
+ * ================== Memory allocation ============================
+ */
+
+#ifdef BIGDECIMAL_DEBUG
+static size_t rbd_allocation_count = 0; /* Memory allocation counter */
+static inline void
+atomic_allocation_count_inc(void)
+{
+ RUBY_ATOMIC_SIZE_INC(rbd_allocation_count);
+}
+static inline void
+atomic_allocation_count_dec_nounderflow(void)
+{
+ if (rbd_allocation_count == 0) return;
+ RUBY_ATOMIC_SIZE_DEC(rbd_allocation_count);
+}
+static void
+check_allocation_count_nonzero(void)
+{
+ if (rbd_allocation_count != 0) return;
+ rb_bug("[bigdecimal][rbd_free_struct] Too many memory free calls");
+}
+#else
+# define atomic_allocation_count_inc() /* nothing */
+# define atomic_allocation_count_dec_nounderflow() /* nothing */
+# define check_allocation_count_nonzero() /* nothing */
+#endif /* BIGDECIMAL_DEBUG */
+
+PUREFUNC(static inline size_t rbd_struct_size(size_t const));
+
+static inline size_t
+rbd_struct_size(size_t const internal_digits)
+{
+ size_t const frac_len = (internal_digits == 0) ? 1 : internal_digits;
+ return offsetof(Real, frac) + frac_len * sizeof(DECDIG);
+}
+
+static inline Real *
+rbd_allocate_struct(size_t const internal_digits)
+{
+ size_t const size = rbd_struct_size(internal_digits);
+ Real *real = ruby_xcalloc(1, size);
+ atomic_allocation_count_inc();
+ real->MaxPrec = internal_digits;
+ return real;
+}
+
+static size_t
+rbd_calculate_internal_digits(size_t const digits, bool limit_precision)
+{
+ size_t const len = roomof(digits, BASE_FIG);
+ if (limit_precision) {
+ size_t const prec_limit = VpGetPrecLimit();
+ if (prec_limit > 0) {
+ /* NOTE: 2 more digits for rounding and division */
+ size_t const max_len = roomof(prec_limit, BASE_FIG) + 2;
+ if (len > max_len)
+ return max_len;
+ }
+ }
+
+ return len;
+}
+
+static inline Real *
+rbd_allocate_struct_decimal_digits(size_t const decimal_digits, bool limit_precision)
+{
+ size_t const internal_digits = rbd_calculate_internal_digits(decimal_digits, limit_precision);
+ return rbd_allocate_struct(internal_digits);
+}
+
+static VALUE BigDecimal_wrap_struct(VALUE obj, Real *vp);
+
+static Real *
+rbd_reallocate_struct(Real *real, size_t const internal_digits)
+{
+ size_t const size = rbd_struct_size(internal_digits);
+ VALUE obj = real ? real->obj : 0;
+ Real *new_real = (Real *)ruby_xrealloc(real, size);
+ new_real->MaxPrec = internal_digits;
+ if (obj) {
+ new_real->obj = 0;
+ BigDecimal_wrap_struct(obj, new_real);
+ }
+ return new_real;
+}
+
+static void
+rbd_free_struct(Real *real)
+{
+ if (real != NULL) {
+ check_allocation_count_nonzero();
+ ruby_xfree(real);
+ atomic_allocation_count_dec_nounderflow();
+ }
+}
+
+#define NewZero rbd_allocate_struct_zero
+static Real *
+rbd_allocate_struct_zero(int sign, size_t const digits, bool limit_precision)
+{
+ Real *real = rbd_allocate_struct_decimal_digits(digits, limit_precision);
+ VpSetZero(real, sign);
+ return real;
+}
+
+MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited(int sign, size_t const digits));
+#define NewZeroLimited rbd_allocate_struct_zero_limited
+static inline Real *
+rbd_allocate_struct_zero_limited(int sign, size_t const digits)
+{
+ return rbd_allocate_struct_zero(sign, digits, true);
+}
+
+MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit(int sign, size_t const digits));
+#define NewZeroNolimit rbd_allocate_struct_zero_nolimit
+static inline Real *
+rbd_allocate_struct_zero_nolimit(int sign, size_t const digits)
+{
+ return rbd_allocate_struct_zero(sign, digits, false);
+}
+
+#define NewOne rbd_allocate_struct_one
+static Real *
+rbd_allocate_struct_one(int sign, size_t const digits, bool limit_precision)
+{
+ Real *real = rbd_allocate_struct_decimal_digits(digits, limit_precision);
+ VpSetOne(real);
+ if (sign < 0)
+ VpSetSign(real, VP_SIGN_NEGATIVE_FINITE);
+ return real;
+}
+
+MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_limited(int sign, size_t const digits));
+#define NewOneLimited rbd_allocate_struct_one_limited
+static inline Real *
+rbd_allocate_struct_one_limited(int sign, size_t const digits)
+{
+ return rbd_allocate_struct_one(sign, digits, true);
+}
+
+MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_nolimit(int sign, size_t const digits));
+#define NewOneNolimit rbd_allocate_struct_one_nolimit
+static inline Real *
+rbd_allocate_struct_one_nolimit(int sign, size_t const digits)
+{
+ return rbd_allocate_struct_one(sign, digits, false);
+}
+
+/*
+ * ================== Ruby Interface part ==========================
+ */
+#define DoSomeOne(x,y,f) rb_num_coerce_bin(x,y,f)
+
+/*
+ * VP routines used in BigDecimal part
+ */
+static unsigned short VpGetException(void);
+static void VpSetException(unsigned short f);
+static void VpCheckException(Real *p, bool always);
+static VALUE VpCheckGetValue(Real *p);
+static void VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v);
+static int VpLimitRound(Real *c, size_t ixDigit);
+static Real *VpCopy(Real *pv, Real const* const x);
+static int VPrint(FILE *fp,const char *cntl_chr,Real *a);
+
+/*
+ * **** BigDecimal part ****
+ */
+
+static VALUE BigDecimal_nan(void);
+static VALUE BigDecimal_positive_infinity(void);
+static VALUE BigDecimal_negative_infinity(void);
+static VALUE BigDecimal_positive_zero(void);
+static VALUE BigDecimal_negative_zero(void);
+
+static void
+BigDecimal_delete(void *pv)
+{
+ rbd_free_struct(pv);
+}
+
+static size_t
+BigDecimal_memsize(const void *ptr)
+{
+ const Real *pv = ptr;
+ return (sizeof(*pv) + pv->MaxPrec * sizeof(DECDIG));
+}
+
+#ifndef HAVE_RB_EXT_RACTOR_SAFE
+# undef RUBY_TYPED_FROZEN_SHAREABLE
+# define RUBY_TYPED_FROZEN_SHAREABLE 0
+#endif
+
+static const rb_data_type_t BigDecimal_data_type = {
+ "BigDecimal",
+ { 0, BigDecimal_delete, BigDecimal_memsize, },
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE
+#endif
+};
+
+static Real *
+rbd_allocate_struct_zero_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision)
+{
+ Real *real = rbd_allocate_struct_zero(sign, digits, limit_precision);
+ if (real != NULL) {
+ VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
+ BigDecimal_wrap_struct(obj, real);
+ }
+ return real;
+}
+
+MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits));
+#define NewZeroWrapLimited rbd_allocate_struct_zero_limited_wrap
+static inline Real *
+rbd_allocate_struct_zero_limited_wrap(int sign, size_t const digits)
+{
+ return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, true);
+}
+
+MAYBE_UNUSED(static inline Real * rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits));
+#define NewZeroWrapNolimit rbd_allocate_struct_zero_nolimit_wrap
+static inline Real *
+rbd_allocate_struct_zero_nolimit_wrap(int sign, size_t const digits)
+{
+ return rbd_allocate_struct_zero_wrap_klass(rb_cBigDecimal, sign, digits, false);
+}
+
+static Real *
+rbd_allocate_struct_one_wrap_klass(VALUE klass, int sign, size_t const digits, bool limit_precision)
+{
+ Real *real = rbd_allocate_struct_one(sign, digits, limit_precision);
+ if (real != NULL) {
+ VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
+ BigDecimal_wrap_struct(obj, real);
+ }
+ return real;
+}
+
+MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits));
+#define NewOneWrapLimited rbd_allocate_struct_one_limited_wrap
+static inline Real *
+rbd_allocate_struct_one_limited_wrap(int sign, size_t const digits)
+{
+ return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, true);
+}
+
+MAYBE_UNUSED(static inline Real * rbd_allocate_struct_one_nolimit_wrap(int sign, size_t const digits));
+#define NewOneWrapNolimit rbd_allocate_struct_one_nolimit_wrap
+static inline Real *
+rbd_allocate_struct_one_nolimit_wrap(int sign, size_t const digits)
+{
+ return rbd_allocate_struct_one_wrap_klass(rb_cBigDecimal, sign, digits, false);
+}
+
+static inline int
+is_kind_of_BigDecimal(VALUE const v)
+{
+ return rb_typeddata_is_kind_of(v, &BigDecimal_data_type);
+}
+
+NORETURN(static void cannot_be_coerced_into_BigDecimal(VALUE, VALUE));
+
+static void
+cannot_be_coerced_into_BigDecimal(VALUE exc_class, VALUE v)
+{
+ VALUE str;
+
+ if (rb_special_const_p(v)) {
+ str = rb_inspect(v);
+ }
+ else {
+ str = rb_class_name(rb_obj_class(v));
+ }
+
+ str = rb_str_cat2(rb_str_dup(str), " can't be coerced into BigDecimal");
+ rb_exc_raise(rb_exc_new3(exc_class, str));
+}
+
+static inline VALUE BigDecimal_div2(VALUE, VALUE, VALUE);
+static VALUE rb_inum_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
+static VALUE rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
+static VALUE rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
+static VALUE rb_cstr_convert_to_BigDecimal(const char *c_str, size_t digs, int raise_exception);
+static VALUE rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception);
+
+static Real*
+GetVpValueWithPrec(VALUE v, long prec, int must)
+{
+ const size_t digs = prec < 0 ? SIZE_MAX : (size_t)prec;
+
+ switch(TYPE(v)) {
+ case T_FLOAT:
+ v = rb_float_convert_to_BigDecimal(v, digs, must);
+ break;
+
+ case T_RATIONAL:
+ v = rb_rational_convert_to_BigDecimal(v, digs, must);
+ break;
+
+ case T_DATA:
+ if (!is_kind_of_BigDecimal(v)) {
+ goto SomeOneMayDoIt;
+ }
+ break;
+
+ case T_FIXNUM: {
+ char szD[128];
+ snprintf(szD, 128, "%ld", FIX2LONG(v));
+ v = rb_cstr_convert_to_BigDecimal(szD, VpBaseFig() * 2 + 1, must);
+ break;
+ }
+
+#ifdef ENABLE_NUMERIC_STRING
+ case T_STRING: {
+ const char *c_str = StringValueCStr(v);
+ v = rb_cstr_convert_to_BigDecimal(c_str, RSTRING_LEN(v) + VpBaseFig() + 1, must);
+ break;
+ }
+#endif /* ENABLE_NUMERIC_STRING */
+
+ case T_BIGNUM: {
+ VALUE bg = rb_big2str(v, 10);
+ v = rb_cstr_convert_to_BigDecimal(RSTRING_PTR(bg), RSTRING_LEN(bg) + VpBaseFig() + 1, must);
+ RB_GC_GUARD(bg);
+ break;
+ }
+
+ default:
+ goto SomeOneMayDoIt;
+ }
+
+ Real *vp;
+ TypedData_Get_Struct(v, Real, &BigDecimal_data_type, vp);
+ return vp;
+
+SomeOneMayDoIt:
+ if (must) {
+ cannot_be_coerced_into_BigDecimal(rb_eTypeError, v);
+ }
+ return NULL; /* NULL means to coerce */
+}
+
+static inline Real*
+GetVpValue(VALUE v, int must)
+{
+ return GetVpValueWithPrec(v, -1, must);
+}
+
+/* call-seq:
+ * BigDecimal.double_fig -> integer
+ *
+ * Returns the number of digits a Float object is allowed to have;
+ * the result is system-dependent:
+ *
+ * BigDecimal.double_fig # => 16
+ *
+ */
+static inline VALUE
+BigDecimal_double_fig(VALUE self)
+{
+ return INT2FIX(VpDblFig());
+}
+
+/* call-seq:
+ * precs -> array
+ *
+ * Returns an Array of two Integer values that represent platform-dependent
+ * internal storage properties.
+ *
+ * This method is deprecated and will be removed in the future.
+ * Instead, use BigDecimal#n_significant_digits for obtaining the number of
+ * significant digits in scientific notation, and BigDecimal#precision for
+ * obtaining the number of digits in decimal notation.
+ *
+ */
+
+static VALUE
+BigDecimal_prec(VALUE self)
+{
+ ENTER(1);
+ Real *p;
+ VALUE obj;
+
+ rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
+ "BigDecimal#precs is deprecated and will be removed in the future; "
+ "use BigDecimal#precision instead.");
+
+ GUARD_OBJ(p, GetVpValue(self, 1));
+ obj = rb_assoc_new(SIZET2NUM(p->Prec*VpBaseFig()),
+ SIZET2NUM(p->MaxPrec*VpBaseFig()));
+ return obj;
+}
+
+static void
+BigDecimal_count_precision_and_scale(VALUE self, ssize_t *out_precision, ssize_t *out_scale)
+{
+ ENTER(1);
+
+ if (out_precision == NULL && out_scale == NULL)
+ return;
+
+ Real *p;
+ GUARD_OBJ(p, GetVpValue(self, 1));
+ if (VpIsZero(p) || !VpIsDef(p)) {
+ zero:
+ if (out_precision) *out_precision = 0;
+ if (out_scale) *out_scale = 0;
+ return;
+ }
+
+ DECDIG x;
+
+ ssize_t n = p->Prec; /* The length of frac without zeros. */
+ while (n > 0 && p->frac[n-1] == 0) --n;
+ if (n == 0) goto zero;
+
+ int nlz = BASE_FIG;
+ for (x = p->frac[0]; x > 0; x /= 10) --nlz;
+
+ int ntz = 0;
+ for (x = p->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
+
+ /*
+ * Calculate the precision and the scale
+ * -------------------------------------
+ *
+ * The most significant digit is frac[0], and the least significant digit
+ * is frac[Prec-1]. When the exponent is zero, the decimal point is
+ * located just before frac[0].
+ *
+ * When the exponent is negative, the decimal point moves to leftward.
+ * In this case, the precision can be calculated by
+ *
+ * precision = BASE_FIG * (-exponent + n) - ntz,
+ *
+ * and the scale is the same as precision.
+ *
+ * 0 . 0000 0000 | frac[0] ... frac[n-1] |
+ * |<----------| exponent == -2 |
+ * |---------------------------------->| precision
+ * |---------------------------------->| scale
+ *
+ *
+ * Conversely, when the exponent is positive, the decimal point moves to
+ * rightward. In this case, the scale equals to
+ *
+ * BASE_FIG * (n - exponent) - ntz.
+ *
+ * the precision equals to
+ *
+ * scale + BASE_FIG * exponent - nlz.
+ *
+ * | frac[0] frac[1] . frac[2] ... frac[n-1] |
+ * |---------------->| exponent == 2 |
+ * | |---------------------->| scale
+ * |---------------------------------------->| precision
+ */
+
+ ssize_t ex = p->exponent;
+
+ /* Count the number of decimal digits before frac[1]. */
+ ssize_t n_digits_head = BASE_FIG;
+ if (ex < 0) {
+ n_digits_head += (-ex) * BASE_FIG; /* The number of leading zeros before frac[0]. */
+ ex = 0;
+ }
+ else if (ex > 0) {
+ /* Count the number of decimal digits without the leading zeros in
+ * the most significant digit in the integral part.
+ */
+ n_digits_head -= nlz; /* Make the number of digits */
+ }
+
+ if (out_precision) {
+ ssize_t precision = n_digits_head;
+
+ /* Count the number of decimal digits after frac[0]. */
+ if (ex > (ssize_t)n) {
+ /* In this case the number is an integer with some trailing zeros. */
+ precision += (ex - 1) * BASE_FIG;
+ }
+ else if (n > 0) {
+ precision += (n - 1) * BASE_FIG;
+
+ if (ex < (ssize_t)n) {
+ precision -= ntz;
+ }
+ }
+
+ *out_precision = precision;
+ }
+
+ if (out_scale) {
+ ssize_t scale = 0;
+
+ if (p->exponent < 0) {
+ scale = n_digits_head + (n - 1) * BASE_FIG - ntz;
+ }
+ else if (n > p->exponent) {
+ scale = (n - p->exponent) * BASE_FIG - ntz;
+ }
+
+ *out_scale = scale;
+ }
+}
+
+/*
+ * call-seq:
+ * precision -> integer
+ *
+ * Returns the number of decimal digits in +self+:
+ *
+ * BigDecimal("0").precision # => 0
+ * BigDecimal("1").precision # => 1
+ * BigDecimal("1.1").precision # => 2
+ * BigDecimal("3.1415").precision # => 5
+ * BigDecimal("-1e20").precision # => 21
+ * BigDecimal("1e-20").precision # => 20
+ * BigDecimal("Infinity").precision # => 0
+ * BigDecimal("-Infinity").precision # => 0
+ * BigDecimal("NaN").precision # => 0
+ *
+ */
+static VALUE
+BigDecimal_precision(VALUE self)
+{
+ ssize_t precision;
+ BigDecimal_count_precision_and_scale(self, &precision, NULL);
+ return SSIZET2NUM(precision);
+}
+
+/*
+ * call-seq:
+ * scale -> integer
+ *
+ * Returns the number of decimal digits following the decimal digits in +self+.
+ *
+ * BigDecimal("0").scale # => 0
+ * BigDecimal("1").scale # => 1
+ * BigDecimal("1.1").scale # => 1
+ * BigDecimal("3.1415").scale # => 4
+ * BigDecimal("-1e20").precision # => 0
+ * BigDecimal("1e-20").precision # => 20
+ * BigDecimal("Infinity").scale # => 0
+ * BigDecimal("-Infinity").scale # => 0
+ * BigDecimal("NaN").scale # => 0
+ */
+static VALUE
+BigDecimal_scale(VALUE self)
+{
+ ssize_t scale;
+ BigDecimal_count_precision_and_scale(self, NULL, &scale);
+ return SSIZET2NUM(scale);
+}
+
+/*
+ * call-seq:
+ * precision_scale -> [integer, integer]
+ *
+ * Returns a 2-length array; the first item is the result of
+ * BigDecimal#precision and the second one is of BigDecimal#scale.
+ *
+ * See BigDecimal#precision.
+ * See BigDecimal#scale.
+ */
+static VALUE
+BigDecimal_precision_scale(VALUE self)
+{
+ ssize_t precision, scale;
+ BigDecimal_count_precision_and_scale(self, &precision, &scale);
+ return rb_assoc_new(SSIZET2NUM(precision), SSIZET2NUM(scale));
+}
+
+/*
+ * call-seq:
+ * n_significant_digits -> integer
+ *
+ * Returns the number of decimal significant digits in +self+.
+ *
+ * BigDecimal("0").n_significant_digits # => 0
+ * BigDecimal("1").n_significant_digits # => 1
+ * BigDecimal("1.1").n_significant_digits # => 2
+ * BigDecimal("3.1415").n_significant_digits # => 5
+ * BigDecimal("-1e20").n_significant_digits # => 1
+ * BigDecimal("1e-20").n_significant_digits # => 1
+ * BigDecimal("Infinity").n_significant_digits # => 0
+ * BigDecimal("-Infinity").n_significant_digits # => 0
+ * BigDecimal("NaN").n_significant_digits # => 0
+ */
+static VALUE
+BigDecimal_n_significant_digits(VALUE self)
+{
+ ENTER(1);
+
+ Real *p;
+ GUARD_OBJ(p, GetVpValue(self, 1));
+ if (VpIsZero(p) || !VpIsDef(p)) {
+ return INT2FIX(0);
+ }
+
+ ssize_t n = p->Prec; /* The length of frac without trailing zeros. */
+ for (n = p->Prec; n > 0 && p->frac[n-1] == 0; --n);
+ if (n == 0) return INT2FIX(0);
+
+ DECDIG x;
+ int nlz = BASE_FIG;
+ for (x = p->frac[0]; x > 0; x /= 10) --nlz;
+
+ int ntz = 0;
+ for (x = p->frac[n-1]; x > 0 && x % 10 == 0; x /= 10) ++ntz;
+
+ ssize_t n_significant_digits = BASE_FIG*n - nlz - ntz;
+ return SSIZET2NUM(n_significant_digits);
+}
+
+/*
+ * call-seq:
+ * hash -> integer
+ *
+ * Returns the integer hash value for +self+.
+ *
+ * Two instances of \BigDecimal have the same hash value if and only if
+ * they have equal:
+ *
+ * - Sign.
+ * - Fractional part.
+ * - Exponent.
+ *
+ */
+static VALUE
+BigDecimal_hash(VALUE self)
+{
+ ENTER(1);
+ Real *p;
+ st_index_t hash;
+
+ GUARD_OBJ(p, GetVpValue(self, 1));
+ hash = (st_index_t)p->sign;
+ /* hash!=2: the case for 0(1),NaN(0) or +-Infinity(3) is sign itself */
+ if(hash == 2 || hash == (st_index_t)-2) {
+ hash ^= rb_memhash(p->frac, sizeof(DECDIG)*p->Prec);
+ hash += p->exponent;
+ }
+ return ST2FIX(hash);
+}
+
+/*
+ * call-seq:
+ * _dump -> string
+ *
+ * Returns a string representing the marshalling of +self+.
+ * See module Marshal.
+ *
+ * inf = BigDecimal('Infinity') # => Infinity
+ * dumped = inf._dump # => "9:Infinity"
+ * BigDecimal._load(dumped) # => Infinity
+ *
+ */
+static VALUE
+BigDecimal_dump(int argc, VALUE *argv, VALUE self)
+{
+ ENTER(5);
+ Real *vp;
+ char *psz;
+ VALUE dummy;
+ volatile VALUE dump;
+ size_t len;
+
+ rb_scan_args(argc, argv, "01", &dummy);
+ GUARD_OBJ(vp,GetVpValue(self, 1));
+ dump = rb_str_new(0, VpNumOfChars(vp, "E")+50);
+ psz = RSTRING_PTR(dump);
+ snprintf(psz, RSTRING_LEN(dump), "%"PRIuSIZE":", VpMaxPrec(vp)*VpBaseFig());
+ len = strlen(psz);
+ VpToString(vp, psz+len, RSTRING_LEN(dump)-len, 0, 0);
+ rb_str_resize(dump, strlen(psz));
+ return dump;
+}
+
+/*
+ * Internal method used to provide marshalling support. See the Marshal module.
+ */
+static VALUE
+BigDecimal_load(VALUE self, VALUE str)
+{
+ ENTER(2);
+ Real *pv;
+ unsigned char *pch;
+ unsigned char ch;
+ unsigned long m=0;
+
+ pch = (unsigned char *)StringValueCStr(str);
+ /* First get max prec */
+ while((*pch) != (unsigned char)'\0' && (ch = *pch++) != (unsigned char)':') {
+ if(!ISDIGIT(ch)) {
+ rb_raise(rb_eTypeError, "load failed: invalid character in the marshaled string");
+ }
+ m = m*10 + (unsigned long)(ch-'0');
+ }
+ if (m > VpBaseFig()) m -= VpBaseFig();
+ GUARD_OBJ(pv, VpNewRbClass(m, (char *)pch, self, true, true));
+ m /= VpBaseFig();
+ if (m && pv->MaxPrec > m) {
+ pv->MaxPrec = m+1;
+ }
+ return VpCheckGetValue(pv);
+}
+
+static unsigned short
+check_rounding_mode_option(VALUE const opts)
+{
+ VALUE mode;
+ char const *s;
+ long l;
+
+ assert(RB_TYPE_P(opts, T_HASH));
+
+ if (NIL_P(opts))
+ goto no_opt;
+
+ mode = rb_hash_lookup2(opts, ID2SYM(id_half), Qundef);
+ if (mode == Qundef || NIL_P(mode))
+ goto no_opt;
+
+ if (SYMBOL_P(mode))
+ mode = rb_sym2str(mode);
+ else if (!RB_TYPE_P(mode, T_STRING)) {
+ VALUE str_mode = rb_check_string_type(mode);
+ if (NIL_P(str_mode))
+ goto invalid;
+ mode = str_mode;
+ }
+ s = RSTRING_PTR(mode);
+ l = RSTRING_LEN(mode);
+ switch (l) {
+ case 2:
+ if (strncasecmp(s, "up", 2) == 0)
+ return VP_ROUND_HALF_UP;
+ break;
+ case 4:
+ if (strncasecmp(s, "even", 4) == 0)
+ return VP_ROUND_HALF_EVEN;
+ else if (strncasecmp(s, "down", 4) == 0)
+ return VP_ROUND_HALF_DOWN;
+ break;
+ default:
+ break;
+ }
+
+ invalid:
+ rb_raise(rb_eArgError, "invalid rounding mode (%"PRIsVALUE")", mode);
+
+ no_opt:
+ return VpGetRoundMode();
+}
+
+static unsigned short
+check_rounding_mode(VALUE const v)
+{
+ unsigned short sw;
+ ID id;
+ if (RB_TYPE_P(v, T_SYMBOL)) {
+ int i;
+ id = SYM2ID(v);
+ for (i = 0; i < RBD_NUM_ROUNDING_MODES; ++i) {
+ if (rbd_rounding_modes[i].id == id) {
+ return rbd_rounding_modes[i].mode;
+ }
+ }
+ rb_raise(rb_eArgError, "invalid rounding mode (%"PRIsVALUE")", v);
+ }
+ else {
+ sw = NUM2USHORT(v);
+ if (!VpIsRoundMode(sw)) {
+ rb_raise(rb_eArgError, "invalid rounding mode (%"PRIsVALUE")", v);
+ }
+ return sw;
+ }
+}
+
+/* call-seq:
+ * BigDecimal.mode(mode, setting = nil) -> integer
+ *
+ * Returns an integer representing the mode settings
+ * for exception handling and rounding.
+ *
+ * These modes control exception handling:
+ *
+ * - \BigDecimal::EXCEPTION_NaN.
+ * - \BigDecimal::EXCEPTION_INFINITY.
+ * - \BigDecimal::EXCEPTION_UNDERFLOW.
+ * - \BigDecimal::EXCEPTION_OVERFLOW.
+ * - \BigDecimal::EXCEPTION_ZERODIVIDE.
+ * - \BigDecimal::EXCEPTION_ALL.
+ *
+ * Values for +setting+ for exception handling:
+ *
+ * - +true+: sets the given +mode+ to +true+.
+ * - +false+: sets the given +mode+ to +false+.
+ * - +nil+: does not modify the mode settings.
+ *
+ * You can use method BigDecimal.save_exception_mode
+ * to temporarily change, and then automatically restore, exception modes.
+ *
+ * For clarity, some examples below begin by setting all
+ * exception modes to +false+.
+ *
+ * This mode controls the way rounding is to be performed:
+ *
+ * - \BigDecimal::ROUND_MODE
+ *
+ * You can use method BigDecimal.save_rounding_mode
+ * to temporarily change, and then automatically restore, the rounding mode.
+ *
+ * <b>NaNs</b>
+ *
+ * Mode \BigDecimal::EXCEPTION_NaN controls behavior
+ * when a \BigDecimal NaN is created.
+ *
+ * Settings:
+ *
+ * - +false+ (default): Returns <tt>BigDecimal('NaN')</tt>.
+ * - +true+: Raises FloatDomainError.
+ *
+ * Examples:
+ *
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
+ * BigDecimal('NaN') # => NaN
+ * BigDecimal.mode(BigDecimal::EXCEPTION_NaN, true) # => 2
+ * BigDecimal('NaN') # Raises FloatDomainError
+ *
+ * <b>Infinities</b>
+ *
+ * Mode \BigDecimal::EXCEPTION_INFINITY controls behavior
+ * when a \BigDecimal Infinity or -Infinity is created.
+ * Settings:
+ *
+ * - +false+ (default): Returns <tt>BigDecimal('Infinity')</tt>
+ * or <tt>BigDecimal('-Infinity')</tt>.
+ * - +true+: Raises FloatDomainError.
+ *
+ * Examples:
+ *
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
+ * BigDecimal('Infinity') # => Infinity
+ * BigDecimal('-Infinity') # => -Infinity
+ * BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, true) # => 1
+ * BigDecimal('Infinity') # Raises FloatDomainError
+ * BigDecimal('-Infinity') # Raises FloatDomainError
+ *
+ * <b>Underflow</b>
+ *
+ * Mode \BigDecimal::EXCEPTION_UNDERFLOW controls behavior
+ * when a \BigDecimal underflow occurs.
+ * Settings:
+ *
+ * - +false+ (default): Returns <tt>BigDecimal('0')</tt>
+ * or <tt>BigDecimal('-Infinity')</tt>.
+ * - +true+: Raises FloatDomainError.
+ *
+ * Examples:
+ *
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
+ * def flow_under
+ * x = BigDecimal('0.1')
+ * 100.times { x *= x }
+ * end
+ * flow_under # => 100
+ * BigDecimal.mode(BigDecimal::EXCEPTION_UNDERFLOW, true) # => 4
+ * flow_under # Raises FloatDomainError
+ *
+ * <b>Overflow</b>
+ *
+ * Mode \BigDecimal::EXCEPTION_OVERFLOW controls behavior
+ * when a \BigDecimal overflow occurs.
+ * Settings:
+ *
+ * - +false+ (default): Returns <tt>BigDecimal('Infinity')</tt>
+ * or <tt>BigDecimal('-Infinity')</tt>.
+ * - +true+: Raises FloatDomainError.
+ *
+ * Examples:
+ *
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
+ * def flow_over
+ * x = BigDecimal('10')
+ * 100.times { x *= x }
+ * end
+ * flow_over # => 100
+ * BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, true) # => 1
+ * flow_over # Raises FloatDomainError
+ *
+ * <b>Zero Division</b>
+ *
+ * Mode \BigDecimal::EXCEPTION_ZERODIVIDE controls behavior
+ * when a zero-division occurs.
+ * Settings:
+ *
+ * - +false+ (default): Returns <tt>BigDecimal('Infinity')</tt>
+ * or <tt>BigDecimal('-Infinity')</tt>.
+ * - +true+: Raises FloatDomainError.
+ *
+ * Examples:
+ *
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
+ * one = BigDecimal('1')
+ * zero = BigDecimal('0')
+ * one / zero # => Infinity
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ZERODIVIDE, true) # => 16
+ * one / zero # Raises FloatDomainError
+ *
+ * <b>All Exceptions</b>
+ *
+ * Mode \BigDecimal::EXCEPTION_ALL controls all of the above:
+ *
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, false) # => 0
+ * BigDecimal.mode(BigDecimal::EXCEPTION_ALL, true) # => 23
+ *
+ * <b>Rounding</b>
+ *
+ * Mode \BigDecimal::ROUND_MODE controls the way rounding is to be performed;
+ * its +setting+ values are:
+ *
+ * - +ROUND_UP+: Round away from zero.
+ * Aliased as +:up+.
+ * - +ROUND_DOWN+: Round toward zero.
+ * Aliased as +:down+ and +:truncate+.
+ * - +ROUND_HALF_UP+: Round toward the nearest neighbor;
+ * if the neighbors are equidistant, round away from zero.
+ * Aliased as +:half_up+ and +:default+.
+ * - +ROUND_HALF_DOWN+: Round toward the nearest neighbor;
+ * if the neighbors are equidistant, round toward zero.
+ * Aliased as +:half_down+.
+ * - +ROUND_HALF_EVEN+ (Banker's rounding): Round toward the nearest neighbor;
+ * if the neighbors are equidistant, round toward the even neighbor.
+ * Aliased as +:half_even+ and +:banker+.
+ * - +ROUND_CEILING+: Round toward positive infinity.
+ * Aliased as +:ceiling+ and +:ceil+.
+ * - +ROUND_FLOOR+: Round toward negative infinity.
+ * Aliased as +:floor:+.
+ *
+ */
+static VALUE
+BigDecimal_mode(int argc, VALUE *argv, VALUE self)
+{
+ VALUE which;
+ VALUE val;
+ unsigned long f,fo;
+
+ rb_scan_args(argc, argv, "11", &which, &val);
+ f = (unsigned long)NUM2INT(which);
+
+ if (f & VP_EXCEPTION_ALL) {
+ /* Exception mode setting */
+ fo = VpGetException();
+ if (val == Qnil) return INT2FIX(fo);
+ if (val != Qfalse && val!=Qtrue) {
+ rb_raise(rb_eArgError, "second argument must be true or false");
+ return Qnil; /* Not reached */
+ }
+ if (f & VP_EXCEPTION_INFINITY) {
+ VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_INFINITY) :
+ (fo & (~VP_EXCEPTION_INFINITY))));
+ }
+ fo = VpGetException();
+ if (f & VP_EXCEPTION_NaN) {
+ VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_NaN) :
+ (fo & (~VP_EXCEPTION_NaN))));
+ }
+ fo = VpGetException();
+ if (f & VP_EXCEPTION_UNDERFLOW) {
+ VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_UNDERFLOW) :
+ (fo & (~VP_EXCEPTION_UNDERFLOW))));
+ }
+ fo = VpGetException();
+ if(f & VP_EXCEPTION_ZERODIVIDE) {
+ VpSetException((unsigned short)((val == Qtrue) ? (fo | VP_EXCEPTION_ZERODIVIDE) :
+ (fo & (~VP_EXCEPTION_ZERODIVIDE))));
+ }
+ fo = VpGetException();
+ return INT2FIX(fo);
+ }
+ if (VP_ROUND_MODE == f) {
+ /* Rounding mode setting */
+ unsigned short sw;
+ fo = VpGetRoundMode();
+ if (NIL_P(val)) return INT2FIX(fo);
+ sw = check_rounding_mode(val);
+ fo = VpSetRoundMode(sw);
+ return INT2FIX(fo);
+ }
+ rb_raise(rb_eTypeError, "first argument for BigDecimal.mode invalid");
+ return Qnil;
+}
+
+static size_t
+GetAddSubPrec(Real *a, Real *b)
+{
+ size_t mxs;
+ size_t mx = a->Prec;
+ SIGNED_VALUE d;
+
+ if (!VpIsDef(a) || !VpIsDef(b)) return (size_t)-1L;
+ if (mx < b->Prec) mx = b->Prec;
+ if (a->exponent != b->exponent) {
+ mxs = mx;
+ d = a->exponent - b->exponent;
+ if (d < 0) d = -d;
+ mx = mx + (size_t)d;
+ if (mx < mxs) {
+ return VpException(VP_EXCEPTION_INFINITY, "Exponent overflow", 0);
+ }
+ }
+ return mx;
+}
+
+static inline SIGNED_VALUE
+check_int_precision(VALUE v)
+{
+ SIGNED_VALUE n;
+#if SIZEOF_VALUE <= SIZEOF_LONG
+ n = (SIGNED_VALUE)NUM2LONG(v);
+#elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
+ n = (SIGNED_VALUE)NUM2LL(v);
+#else
+# error SIZEOF_VALUE is too large
+#endif
+ if (n < 0) {
+ rb_raise(rb_eArgError, "negative precision");
+ }
+ return n;
+}
+
+static VALUE
+BigDecimal_wrap_struct(VALUE obj, Real *vp)
+{
+ assert(is_kind_of_BigDecimal(obj));
+ assert(vp != NULL);
+
+ if (vp->obj == obj && RTYPEDDATA_DATA(obj) == vp)
+ return obj;
+
+ assert(RTYPEDDATA_DATA(obj) == NULL);
+ assert(vp->obj == 0);
+
+ RTYPEDDATA_DATA(obj) = vp;
+ vp->obj = obj;
+ RB_OBJ_FREEZE(obj);
+ return obj;
+}
+
+VP_EXPORT Real *
+VpNewRbClass(size_t mx, const char *str, VALUE klass, bool strict_p, bool raise_exception)
+{
+ VALUE obj = TypedData_Wrap_Struct(klass, &BigDecimal_data_type, 0);
+ Real *pv = VpAlloc(mx, str, strict_p, raise_exception);
+ if (!pv)
+ return NULL;
+ BigDecimal_wrap_struct(obj, pv);
+ return pv;
+}
+
+VP_EXPORT Real *
+VpCreateRbObject(size_t mx, const char *str, bool raise_exception)
+{
+ return VpNewRbClass(mx, str, rb_cBigDecimal, true, raise_exception);
+}
+
+static Real *
+VpCopy(Real *pv, Real const* const x)
+{
+ assert(x != NULL);
+
+ pv = rbd_reallocate_struct(pv, x->MaxPrec);
+ pv->MaxPrec = x->MaxPrec;
+ pv->Prec = x->Prec;
+ pv->exponent = x->exponent;
+ pv->sign = x->sign;
+ pv->flag = x->flag;
+ MEMCPY(pv->frac, x->frac, DECDIG, pv->MaxPrec);
+
+ return pv;
+}
+
+/* Returns True if the value is Not a Number. */
+static VALUE
+BigDecimal_IsNaN(VALUE self)
+{
+ Real *p = GetVpValue(self, 1);
+ if (VpIsNaN(p)) return Qtrue;
+ return Qfalse;
+}
+
+/* Returns nil, -1, or +1 depending on whether the value is finite,
+ * -Infinity, or +Infinity.
+ */
+static VALUE
+BigDecimal_IsInfinite(VALUE self)
+{
+ Real *p = GetVpValue(self, 1);
+ if (VpIsPosInf(p)) return INT2FIX(1);
+ if (VpIsNegInf(p)) return INT2FIX(-1);
+ return Qnil;
+}
+
+/* Returns True if the value is finite (not NaN or infinite). */
+static VALUE
+BigDecimal_IsFinite(VALUE self)
+{
+ Real *p = GetVpValue(self, 1);
+ if (VpIsNaN(p)) return Qfalse;
+ if (VpIsInf(p)) return Qfalse;
+ return Qtrue;
+}
+
+static void
+BigDecimal_check_num(Real *p)
+{
+ VpCheckException(p, true);
+}
+
+static VALUE BigDecimal_split(VALUE self);
+
+/* Returns the value as an Integer.
+ *
+ * If the BigDecimal is infinity or NaN, raises FloatDomainError.
+ */
+static VALUE
+BigDecimal_to_i(VALUE self)
+{
+ ENTER(5);
+ ssize_t e, nf;
+ Real *p;
+
+ GUARD_OBJ(p, GetVpValue(self, 1));
+ BigDecimal_check_num(p);
+
+ e = VpExponent10(p);
+ if (e <= 0) return INT2FIX(0);
+ nf = VpBaseFig();
+ if (e <= nf) {
+ return LONG2NUM((long)(VpGetSign(p) * (DECDIG_DBL_SIGNED)p->frac[0]));
+ }
+ else {
+ VALUE a = BigDecimal_split(self);
+ VALUE digits = RARRAY_AREF(a, 1);
+ VALUE numerator = rb_funcall(digits, rb_intern("to_i"), 0);
+ VALUE ret;
+ ssize_t dpower = e - (ssize_t)RSTRING_LEN(digits);
+
+ if (BIGDECIMAL_NEGATIVE_P(p)) {
+ numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
+ }
+ if (dpower < 0) {
+ ret = rb_funcall(numerator, rb_intern("div"), 1,
+ rb_funcall(INT2FIX(10), rb_intern("**"), 1,
+ INT2FIX(-dpower)));
+ }
+ else {
+ ret = rb_funcall(numerator, '*', 1,
+ rb_funcall(INT2FIX(10), rb_intern("**"), 1,
+ INT2FIX(dpower)));
+ }
+ if (RB_TYPE_P(ret, T_FLOAT)) {
+ rb_raise(rb_eFloatDomainError, "Infinity");
+ }
+ return ret;
+ }
+}
+
+/* Returns a new Float object having approximately the same value as the
+ * BigDecimal number. Normal accuracy limits and built-in errors of binary
+ * Float arithmetic apply.
+ */
+static VALUE
+BigDecimal_to_f(VALUE self)
+{
+ ENTER(1);
+ Real *p;
+ double d;
+ SIGNED_VALUE e;
+ char *buf;
+ volatile VALUE str;
+
+ GUARD_OBJ(p, GetVpValue(self, 1));
+ if (VpVtoD(&d, &e, p) != 1)
+ return rb_float_new(d);
+ if (e > (SIGNED_VALUE)(DBL_MAX_10_EXP+BASE_FIG))
+ goto overflow;
+ if (e < (SIGNED_VALUE)(DBL_MIN_10_EXP-BASE_FIG))
+ goto underflow;
+
+ str = rb_str_new(0, VpNumOfChars(p, "E"));
+ buf = RSTRING_PTR(str);
+ VpToString(p, buf, RSTRING_LEN(str), 0, 0);
+ errno = 0;
+ d = strtod(buf, 0);
+ if (errno == ERANGE) {
+ if (d == 0.0) goto underflow;
+ if (fabs(d) >= HUGE_VAL) goto overflow;
+ }
+ return rb_float_new(d);
+
+overflow:
+ VpException(VP_EXCEPTION_OVERFLOW, "BigDecimal to Float conversion", 0);
+ if (BIGDECIMAL_NEGATIVE_P(p))
+ return rb_float_new(VpGetDoubleNegInf());
+ else
+ return rb_float_new(VpGetDoublePosInf());
+
+underflow:
+ VpException(VP_EXCEPTION_UNDERFLOW, "BigDecimal to Float conversion", 0);
+ if (BIGDECIMAL_NEGATIVE_P(p))
+ return rb_float_new(-0.0);
+ else
+ return rb_float_new(0.0);
+}
+
+
+/* Converts a BigDecimal to a Rational.
+ */
+static VALUE
+BigDecimal_to_r(VALUE self)
+{
+ Real *p;
+ ssize_t sign, power, denomi_power;
+ VALUE a, digits, numerator;
+
+ p = GetVpValue(self, 1);
+ BigDecimal_check_num(p);
+
+ sign = VpGetSign(p);
+ power = VpExponent10(p);
+ a = BigDecimal_split(self);
+ digits = RARRAY_AREF(a, 1);
+ denomi_power = power - RSTRING_LEN(digits);
+ numerator = rb_funcall(digits, rb_intern("to_i"), 0);
+
+ if (sign < 0) {
+ numerator = rb_funcall(numerator, '*', 1, INT2FIX(-1));
+ }
+ if (denomi_power < 0) {
+ return rb_Rational(numerator,
+ rb_funcall(INT2FIX(10), rb_intern("**"), 1,
+ INT2FIX(-denomi_power)));
+ }
+ else {
+ return rb_Rational1(rb_funcall(numerator, '*', 1,
+ rb_funcall(INT2FIX(10), rb_intern("**"), 1,
+ INT2FIX(denomi_power))));
+ }
+}
+
+/* The coerce method provides support for Ruby type coercion. It is not
+ * enabled by default.
+ *
+ * This means that binary operations like + * / or - can often be performed
+ * on a BigDecimal and an object of another type, if the other object can
+ * be coerced into a BigDecimal value.
+ *
+ * e.g.
+ * a = BigDecimal("1.0")
+ * b = a / 2.0 #=> 0.5
+ *
+ * Note that coercing a String to a BigDecimal is not supported by default;
+ * it requires a special compile-time option when building Ruby.
+ */
+static VALUE
+BigDecimal_coerce(VALUE self, VALUE other)
+{
+ ENTER(2);
+ VALUE obj;
+ Real *b;
+
+ if (RB_TYPE_P(other, T_FLOAT)) {
+ GUARD_OBJ(b, GetVpValueWithPrec(other, 0, 1));
+ obj = rb_assoc_new(VpCheckGetValue(b), self);
+ }
+ else {
+ if (RB_TYPE_P(other, T_RATIONAL)) {
+ Real* pv = DATA_PTR(self);
+ GUARD_OBJ(b, GetVpValueWithPrec(other, pv->Prec*VpBaseFig(), 1));
+ }
+ else {
+ GUARD_OBJ(b, GetVpValue(other, 1));
+ }
+ obj = rb_assoc_new(b->obj, self);
+ }
+
+ return obj;
+}
+
+/*
+ * call-seq:
+ * +big_decimal -> self
+ *
+ * Returns +self+:
+ *
+ * +BigDecimal(5) # => 0.5e1
+ * +BigDecimal(-5) # => -0.5e1
+ *
+ */
+
+static VALUE
+BigDecimal_uplus(VALUE self)
+{
+ return self;
+}
+
+ /*
+ * call-seq:
+ * self + value -> bigdecimal
+ *
+ * Returns the \BigDecimal sum of +self+ and +value+:
+ *
+ * b = BigDecimal('111111.111') # => 0.111111111e6
+ * b + 2 # => 0.111113111e6
+ * b + 2.0 # => 0.111113111e6
+ * b + Rational(2, 1) # => 0.111113111e6
+ * b + Complex(2, 0) # => (0.111113111e6+0i)
+ *
+ * See the {Note About Precision}[BigDecimal.html#class-BigDecimal-label-A+Note+About+Precision].
+ *
+ */
+
+static VALUE
+BigDecimal_add(VALUE self, VALUE r)
+{
+ ENTER(5);
+ Real *c, *a, *b;
+ size_t mx;
+
+ GUARD_OBJ(a, GetVpValue(self, 1));
+ if (RB_TYPE_P(r, T_FLOAT)) {
+ b = GetVpValueWithPrec(r, 0, 1);
+ }
+ else if (RB_TYPE_P(r, T_RATIONAL)) {
+ b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
+ }
+ else {
+ b = GetVpValue(r, 0);
+ }
+
+ if (!b) return DoSomeOne(self,r,'+');
+ SAVE(b);
+
+ if (VpIsNaN(b)) return b->obj;
+ if (VpIsNaN(a)) return a->obj;
+
+ mx = GetAddSubPrec(a, b);
+ if (mx == (size_t)-1L) {
+ GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
+ VpAddSub(c, a, b, 1);
+ }
+ else {
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
+ if (!mx) {
+ VpSetInf(c, VpGetSign(a));
+ }
+ else {
+ VpAddSub(c, a, b, 1);
+ }
+ }
+ return VpCheckGetValue(c);
+}
+
+ /* call-seq:
+ * self - value -> bigdecimal
+ *
+ * Returns the \BigDecimal difference of +self+ and +value+:
+ *
+ * b = BigDecimal('333333.333') # => 0.333333333e6
+ * b - 2 # => 0.333331333e6
+ * b - 2.0 # => 0.333331333e6
+ * b - Rational(2, 1) # => 0.333331333e6
+ * b - Complex(2, 0) # => (0.333331333e6+0i)
+ *
+ * See the {Note About Precision}[BigDecimal.html#class-BigDecimal-label-A+Note+About+Precision].
+ *
+ */
+static VALUE
+BigDecimal_sub(VALUE self, VALUE r)
+{
+ ENTER(5);
+ Real *c, *a, *b;
+ size_t mx;
+
+ GUARD_OBJ(a, GetVpValue(self,1));
+ if (RB_TYPE_P(r, T_FLOAT)) {
+ b = GetVpValueWithPrec(r, 0, 1);
+ }
+ else if (RB_TYPE_P(r, T_RATIONAL)) {
+ b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
+ }
+ else {
+ b = GetVpValue(r,0);
+ }
+
+ if (!b) return DoSomeOne(self,r,'-');
+ SAVE(b);
+
+ if (VpIsNaN(b)) return b->obj;
+ if (VpIsNaN(a)) return a->obj;
+
+ mx = GetAddSubPrec(a,b);
+ if (mx == (size_t)-1L) {
+ GUARD_OBJ(c, NewZeroWrapLimited(1, VpBaseFig() + 1));
+ VpAddSub(c, a, b, -1);
+ }
+ else {
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx *(VpBaseFig() + 1)));
+ if (!mx) {
+ VpSetInf(c,VpGetSign(a));
+ }
+ else {
+ VpAddSub(c, a, b, -1);
+ }
+ }
+ return VpCheckGetValue(c);
+}
+
+static VALUE
+BigDecimalCmp(VALUE self, VALUE r,char op)
+{
+ ENTER(5);
+ SIGNED_VALUE e;
+ Real *a, *b=0;
+ GUARD_OBJ(a, GetVpValue(self, 1));
+ switch (TYPE(r)) {
+ case T_DATA:
+ if (!is_kind_of_BigDecimal(r)) break;
+ /* fall through */
+ case T_FIXNUM:
+ /* fall through */
+ case T_BIGNUM:
+ GUARD_OBJ(b, GetVpValue(r, 0));
+ break;
+
+ case T_FLOAT:
+ GUARD_OBJ(b, GetVpValueWithPrec(r, 0, 0));
+ break;
+
+ case T_RATIONAL:
+ GUARD_OBJ(b, GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 0));
+ break;
+
+ default:
+ break;
+ }
+ if (b == NULL) {
+ ID f = 0;
+
+ switch (op) {
+ case '*':
+ return rb_num_coerce_cmp(self, r, rb_intern("<=>"));
+
+ case '=':
+ return RTEST(rb_num_coerce_cmp(self, r, rb_intern("=="))) ? Qtrue : Qfalse;
+
+ case 'G':
+ f = rb_intern(">=");
+ break;
+
+ case 'L':
+ f = rb_intern("<=");
+ break;
+
+ case '>':
+ /* fall through */
+ case '<':
+ f = (ID)op;
+ break;
+
+ default:
+ break;
+ }
+ return rb_num_coerce_relop(self, r, f);
+ }
+ SAVE(b);
+ e = VpComp(a, b);
+ if (e == 999)
+ return (op == '*') ? Qnil : Qfalse;
+ switch (op) {
+ case '*':
+ return INT2FIX(e); /* any op */
+
+ case '=':
+ if (e == 0) return Qtrue;
+ return Qfalse;
+
+ case 'G':
+ if (e >= 0) return Qtrue;
+ return Qfalse;
+
+ case '>':
+ if (e > 0) return Qtrue;
+ return Qfalse;
+
+ case 'L':
+ if (e <= 0) return Qtrue;
+ return Qfalse;
+
+ case '<':
+ if (e < 0) return Qtrue;
+ return Qfalse;
+
+ default:
+ break;
+ }
+
+ rb_bug("Undefined operation in BigDecimalCmp()");
+
+ UNREACHABLE;
+}
+
+/* Returns True if the value is zero. */
+static VALUE
+BigDecimal_zero(VALUE self)
+{
+ Real *a = GetVpValue(self, 1);
+ return VpIsZero(a) ? Qtrue : Qfalse;
+}
+
+/* Returns self if the value is non-zero, nil otherwise. */
+static VALUE
+BigDecimal_nonzero(VALUE self)
+{
+ Real *a = GetVpValue(self, 1);
+ return VpIsZero(a) ? Qnil : self;
+}
+
+/* The comparison operator.
+ * a <=> b is 0 if a == b, 1 if a > b, -1 if a < b.
+ */
+static VALUE
+BigDecimal_comp(VALUE self, VALUE r)
+{
+ return BigDecimalCmp(self, r, '*');
+}
+
+/*
+ * Tests for value equality; returns true if the values are equal.
+ *
+ * The == and === operators and the eql? method have the same implementation
+ * for BigDecimal.
+ *
+ * Values may be coerced to perform the comparison:
+ *
+ * BigDecimal('1.0') == 1.0 #=> true
+ */
+static VALUE
+BigDecimal_eq(VALUE self, VALUE r)
+{
+ return BigDecimalCmp(self, r, '=');
+}
+
+/* call-seq:
+ * self < other -> true or false
+ *
+ * Returns +true+ if +self+ is less than +other+, +false+ otherwise:
+ *
+ * b = BigDecimal('1.5') # => 0.15e1
+ * b < 2 # => true
+ * b < 2.0 # => true
+ * b < Rational(2, 1) # => true
+ * b < 1.5 # => false
+ *
+ * Raises an exception if the comparison cannot be made.
+ *
+ */
+static VALUE
+BigDecimal_lt(VALUE self, VALUE r)
+{
+ return BigDecimalCmp(self, r, '<');
+}
+
+/* call-seq:
+ * self <= other -> true or false
+ *
+ * Returns +true+ if +self+ is less or equal to than +other+, +false+ otherwise:
+ *
+ * b = BigDecimal('1.5') # => 0.15e1
+ * b <= 2 # => true
+ * b <= 2.0 # => true
+ * b <= Rational(2, 1) # => true
+ * b <= 1.5 # => true
+ * b < 1 # => false
+ *
+ * Raises an exception if the comparison cannot be made.
+ *
+ */
+static VALUE
+BigDecimal_le(VALUE self, VALUE r)
+{
+ return BigDecimalCmp(self, r, 'L');
+}
+
+/* call-seq:
+ * self > other -> true or false
+ *
+ * Returns +true+ if +self+ is greater than +other+, +false+ otherwise:
+ *
+ * b = BigDecimal('1.5')
+ * b > 1 # => true
+ * b > 1.0 # => true
+ * b > Rational(1, 1) # => true
+ * b > 2 # => false
+ *
+ * Raises an exception if the comparison cannot be made.
+ *
+ */
+static VALUE
+BigDecimal_gt(VALUE self, VALUE r)
+{
+ return BigDecimalCmp(self, r, '>');
+}
+
+/* call-seq:
+ * self >= other -> true or false
+ *
+ * Returns +true+ if +self+ is greater than or equal to +other+, +false+ otherwise:
+ *
+ * b = BigDecimal('1.5')
+ * b >= 1 # => true
+ * b >= 1.0 # => true
+ * b >= Rational(1, 1) # => true
+ * b >= 1.5 # => true
+ * b > 2 # => false
+ *
+ * Raises an exception if the comparison cannot be made.
+ *
+ */
+static VALUE
+BigDecimal_ge(VALUE self, VALUE r)
+{
+ return BigDecimalCmp(self, r, 'G');
+}
+
+/*
+ * call-seq:
+ * -self -> bigdecimal
+ *
+ * Returns the \BigDecimal negation of self:
+ *
+ * b0 = BigDecimal('1.5')
+ * b1 = -b0 # => -0.15e1
+ * b2 = -b1 # => 0.15e1
+ *
+ */
+
+static VALUE
+BigDecimal_neg(VALUE self)
+{
+ ENTER(5);
+ Real *c, *a;
+ GUARD_OBJ(a, GetVpValue(self, 1));
+ GUARD_OBJ(c, NewZeroWrapLimited(1, a->Prec *(VpBaseFig() + 1)));
+ VpAsgn(c, a, -1);
+ return VpCheckGetValue(c);
+}
+
+static VALUE
+BigDecimal_mult(VALUE self, VALUE r)
+{
+ ENTER(5);
+ Real *c, *a, *b;
+ size_t mx;
+
+ GUARD_OBJ(a, GetVpValue(self, 1));
+ if (RB_TYPE_P(r, T_FLOAT)) {
+ b = GetVpValueWithPrec(r, 0, 1);
+ }
+ else if (RB_TYPE_P(r, T_RATIONAL)) {
+ b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
+ }
+ else {
+ b = GetVpValue(r,0);
+ }
+
+ if (!b) return DoSomeOne(self, r, '*');
+ SAVE(b);
+
+ mx = a->Prec + b->Prec;
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx * (VpBaseFig() + 1)));
+ VpMult(c, a, b);
+ return VpCheckGetValue(c);
+}
+
+static VALUE
+BigDecimal_divide(VALUE self, VALUE r, Real **c, Real **res, Real **div)
+/* For c = self.div(r): with round operation */
+{
+ ENTER(5);
+ Real *a, *b;
+ ssize_t a_prec, b_prec;
+ size_t mx;
+
+ TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
+ SAVE(a);
+
+ VALUE rr = r;
+ if (is_kind_of_BigDecimal(rr)) {
+ /* do nothing */
+ }
+ else if (RB_INTEGER_TYPE_P(r)) {
+ rr = rb_inum_convert_to_BigDecimal(r, 0, true);
+ }
+ else if (RB_TYPE_P(r, T_FLOAT)) {
+ rr = rb_float_convert_to_BigDecimal(r, 0, true);
+ }
+ else if (RB_TYPE_P(r, T_RATIONAL)) {
+ rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
+ }
+
+ if (!is_kind_of_BigDecimal(rr)) {
+ return DoSomeOne(self, r, '/');
+ }
+
+ TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
+ SAVE(b);
+ *div = b;
+
+ BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
+ BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
+ mx = (a_prec > b_prec) ? a_prec : b_prec;
+ mx *= 2;
+
+ if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
+ mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
+
+ GUARD_OBJ((*c), NewZeroWrapNolimit(1, mx + 2*BASE_FIG));
+ GUARD_OBJ((*res), NewZeroWrapNolimit(1, (mx + 1)*2 + 2*BASE_FIG));
+ VpDivd(*c, *res, a, b);
+
+ return Qnil;
+}
+
+static VALUE BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod);
+
+/* call-seq:
+ * a / b -> bigdecimal
+ *
+ * Divide by the specified value.
+ *
+ * The result precision will be the precision of the larger operand,
+ * but its minimum is 2*Float::DIG.
+ *
+ * See BigDecimal#div.
+ * See BigDecimal#quo.
+ */
+static VALUE
+BigDecimal_div(VALUE self, VALUE r)
+/* For c = self/r: with round operation */
+{
+ ENTER(5);
+ Real *c=NULL, *res=NULL, *div = NULL;
+ r = BigDecimal_divide(self, r, &c, &res, &div);
+ if (!NIL_P(r)) return r; /* coerced by other */
+ SAVE(c); SAVE(res); SAVE(div);
+ /* a/b = c + r/b */
+ /* c xxxxx
+ r 00000yyyyy ==> (y/b)*BASE >= HALF_BASE
+ */
+ /* Round */
+ if (VpHasVal(div)) { /* frac[0] must be zero for NaN,INF,Zero */
+ VpInternalRound(c, 0, c->frac[c->Prec-1], (DECDIG)(VpBaseVal() * (DECDIG_DBL)res->frac[0] / div->frac[0]));
+ }
+ return VpCheckGetValue(c);
+}
+
+static VALUE BigDecimal_round(int argc, VALUE *argv, VALUE self);
+
+/* call-seq:
+ * quo(value) -> bigdecimal
+ * quo(value, digits) -> bigdecimal
+ *
+ * Divide by the specified value.
+ *
+ * digits:: If specified and less than the number of significant digits of
+ * the result, the result is rounded to the given number of digits,
+ * according to the rounding mode indicated by BigDecimal.mode.
+ *
+ * If digits is 0 or omitted, the result is the same as for the
+ * / operator.
+ *
+ * See BigDecimal#/.
+ * See BigDecimal#div.
+ */
+static VALUE
+BigDecimal_quo(int argc, VALUE *argv, VALUE self)
+{
+ VALUE value, digits, result;
+ SIGNED_VALUE n = -1;
+
+ argc = rb_scan_args(argc, argv, "11", &value, &digits);
+ if (argc > 1) {
+ n = check_int_precision(digits);
+ }
+
+ if (n > 0) {
+ result = BigDecimal_div2(self, value, digits);
+ }
+ else {
+ result = BigDecimal_div(self, value);
+ }
+
+ return result;
+}
+
+/*
+ * %: mod = a%b = a - (a.to_f/b).floor * b
+ * div = (a.to_f/b).floor
+ */
+static VALUE
+BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod)
+{
+ ENTER(8);
+ Real *c=NULL, *d=NULL, *res=NULL;
+ Real *a, *b;
+ ssize_t a_prec, b_prec;
+ size_t mx;
+
+ TypedData_Get_Struct(self, Real, &BigDecimal_data_type, a);
+ SAVE(a);
+
+ VALUE rr = r;
+ if (is_kind_of_BigDecimal(rr)) {
+ /* do nothing */
+ }
+ else if (RB_INTEGER_TYPE_P(r)) {
+ rr = rb_inum_convert_to_BigDecimal(r, 0, true);
+ }
+ else if (RB_TYPE_P(r, T_FLOAT)) {
+ rr = rb_float_convert_to_BigDecimal(r, 0, true);
+ }
+ else if (RB_TYPE_P(r, T_RATIONAL)) {
+ rr = rb_rational_convert_to_BigDecimal(r, a->Prec*BASE_FIG, true);
+ }
+
+ if (!is_kind_of_BigDecimal(rr)) {
+ return Qfalse;
+ }
+
+ TypedData_Get_Struct(rr, Real, &BigDecimal_data_type, b);
+ SAVE(b);
+
+ if (VpIsNaN(a) || VpIsNaN(b)) goto NaN;
+ if (VpIsInf(a) && VpIsInf(b)) goto NaN;
+ if (VpIsZero(b)) {
+ rb_raise(rb_eZeroDivError, "divided by 0");
+ }
+ if (VpIsInf(a)) {
+ if (VpGetSign(a) == VpGetSign(b)) {
+ VALUE inf = BigDecimal_positive_infinity();
+ TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
+ }
+ else {
+ VALUE inf = BigDecimal_negative_infinity();
+ TypedData_Get_Struct(inf, Real, &BigDecimal_data_type, *div);
+ }
+ VALUE nan = BigDecimal_nan();
+ TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod);
+ return Qtrue;
+ }
+ if (VpIsInf(b)) {
+ VALUE zero = BigDecimal_positive_zero();
+ TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
+ *mod = a;
+ return Qtrue;
+ }
+ if (VpIsZero(a)) {
+ VALUE zero = BigDecimal_positive_zero();
+ TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *div);
+ TypedData_Get_Struct(zero, Real, &BigDecimal_data_type, *mod);
+ return Qtrue;
+ }
+
+ BigDecimal_count_precision_and_scale(self, &a_prec, NULL);
+ BigDecimal_count_precision_and_scale(rr, &b_prec, NULL);
+
+ mx = (a_prec > b_prec) ? a_prec : b_prec;
+ mx *= 2;
+
+ if (2*BIGDECIMAL_DOUBLE_FIGURES > mx)
+ mx = 2*BIGDECIMAL_DOUBLE_FIGURES;
+
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx + 2*BASE_FIG));
+ GUARD_OBJ(res, NewZeroWrapNolimit(1, mx*2 + 2*BASE_FIG));
+ VpDivd(c, res, a, b);
+
+ mx = c->Prec * BASE_FIG;
+ GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
+ VpActiveRound(d, c, VP_ROUND_DOWN, 0);
+
+ VpMult(res, d, b);
+ VpAddSub(c, a, res, -1);
+
+ if (!VpIsZero(c) && (VpGetSign(a) * VpGetSign(b) < 0)) {
+ /* result adjustment for negative case */
+ res = rbd_reallocate_struct(res, d->MaxPrec);
+ res->MaxPrec = d->MaxPrec;
+ VpAddSub(res, d, VpOne(), -1);
+ GUARD_OBJ(d, NewZeroWrapLimited(1, GetAddSubPrec(c, b) * 2*BASE_FIG));
+ VpAddSub(d, c, b, 1);
+ *div = res;
+ *mod = d;
+ }
+ else {
+ *div = d;
+ *mod = c;
+ }
+ return Qtrue;
+
+ NaN:
+ {
+ VALUE nan = BigDecimal_nan();
+ TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *div);
+ TypedData_Get_Struct(nan, Real, &BigDecimal_data_type, *mod);
+ }
+ return Qtrue;
+}
+
+/* call-seq:
+ * a % b
+ * a.modulo(b)
+ *
+ * Returns the modulus from dividing by b.
+ *
+ * See BigDecimal#divmod.
+ */
+static VALUE
+BigDecimal_mod(VALUE self, VALUE r) /* %: a%b = a - (a.to_f/b).floor * b */
+{
+ ENTER(3);
+ Real *div = NULL, *mod = NULL;
+
+ if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
+ SAVE(div); SAVE(mod);
+ return VpCheckGetValue(mod);
+ }
+ return DoSomeOne(self, r, '%');
+}
+
+static VALUE
+BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
+{
+ ENTER(10);
+ size_t mx;
+ Real *a = NULL, *b = NULL, *c = NULL, *res = NULL, *d = NULL, *rr = NULL, *ff = NULL;
+ Real *f = NULL;
+
+ GUARD_OBJ(a, GetVpValue(self, 1));
+ if (RB_TYPE_P(r, T_FLOAT)) {
+ b = GetVpValueWithPrec(r, 0, 1);
+ }
+ else if (RB_TYPE_P(r, T_RATIONAL)) {
+ b = GetVpValueWithPrec(r, a->Prec*VpBaseFig(), 1);
+ }
+ else {
+ b = GetVpValue(r, 0);
+ }
+
+ if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
+ SAVE(b);
+
+ mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
+ GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
+ GUARD_OBJ(rr, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
+ GUARD_OBJ(ff, NewZeroWrapNolimit(1, (mx+1) * 2 + (VpBaseFig() + 1)));
+
+ VpDivd(c, res, a, b);
+
+ mx = c->Prec *(VpBaseFig() + 1);
+
+ GUARD_OBJ(d, NewZeroWrapLimited(1, mx));
+ GUARD_OBJ(f, NewZeroWrapLimited(1, mx));
+
+ VpActiveRound(d, c, VP_ROUND_DOWN, 0); /* 0: round off */
+
+ VpFrac(f, c);
+ VpMult(rr, f, b);
+ VpAddSub(ff, res, rr, 1);
+
+ *dv = d;
+ *rv = ff;
+ return Qnil;
+}
+
+/* call-seq:
+ * remainder(value)
+ *
+ * Returns the remainder from dividing by the value.
+ *
+ * x.remainder(y) means x-y*(x/y).truncate
+ */
+static VALUE
+BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
+{
+ VALUE f;
+ Real *d, *rv = 0;
+ f = BigDecimal_divremain(self, r, &d, &rv);
+ if (!NIL_P(f)) return f;
+ return VpCheckGetValue(rv);
+}
+
+/* call-seq:
+ * divmod(value)
+ *
+ * Divides by the specified value, and returns the quotient and modulus
+ * as BigDecimal numbers. The quotient is rounded towards negative infinity.
+ *
+ * For example:
+ *
+ * require 'bigdecimal'
+ *
+ * a = BigDecimal("42")
+ * b = BigDecimal("9")
+ *
+ * q, m = a.divmod(b)
+ *
+ * c = q * b + m
+ *
+ * a == c #=> true
+ *
+ * The quotient q is (a/b).floor, and the modulus is the amount that must be
+ * added to q * b to get a.
+ */
+static VALUE
+BigDecimal_divmod(VALUE self, VALUE r)
+{
+ ENTER(5);
+ Real *div = NULL, *mod = NULL;
+
+ if (BigDecimal_DoDivmod(self, r, &div, &mod)) {
+ SAVE(div); SAVE(mod);
+ return rb_assoc_new(VpCheckGetValue(div), VpCheckGetValue(mod));
+ }
+ return DoSomeOne(self,r,rb_intern("divmod"));
+}
+
+/*
+ * Do the same manner as Float#div when n is nil.
+ * Do the same manner as BigDecimal#quo when n is 0.
+ */
+static inline VALUE
+BigDecimal_div2(VALUE self, VALUE b, VALUE n)
+{
+ ENTER(5);
+ SIGNED_VALUE ix;
+
+ if (NIL_P(n)) { /* div in Float sense */
+ Real *div = NULL;
+ Real *mod;
+ if (BigDecimal_DoDivmod(self, b, &div, &mod)) {
+ return BigDecimal_to_i(VpCheckGetValue(div));
+ }
+ return DoSomeOne(self, b, rb_intern("div"));
+ }
+
+ /* div in BigDecimal sense */
+ ix = check_int_precision(n);
+ if (ix == 0) {
+ return BigDecimal_div(self, b);
+ }
+ else {
+ Real *res = NULL;
+ Real *av = NULL, *bv = NULL, *cv = NULL;
+ size_t mx = ix + VpBaseFig()*2;
+ size_t b_prec = ix;
+ size_t pl = VpSetPrecLimit(0);
+
+ GUARD_OBJ(cv, NewZeroWrapLimited(1, mx + VpBaseFig()));
+ GUARD_OBJ(av, GetVpValue(self, 1));
+ /* TODO: I want to refactor this precision control for a float value later
+ * by introducing an implicit conversion function instead of
+ * GetVpValueWithPrec. */
+ if (RB_FLOAT_TYPE_P(b) && b_prec > BIGDECIMAL_DOUBLE_FIGURES) {
+ b_prec = BIGDECIMAL_DOUBLE_FIGURES;
+ }
+ GUARD_OBJ(bv, GetVpValueWithPrec(b, b_prec, 1));
+ mx = av->Prec + bv->Prec + 2;
+ if (mx <= cv->MaxPrec) mx = cv->MaxPrec + 1;
+ GUARD_OBJ(res, NewZeroWrapNolimit(1, (mx * 2 + 2)*VpBaseFig()));
+ VpDivd(cv, res, av, bv);
+ VpSetPrecLimit(pl);
+ VpLeftRound(cv, VpGetRoundMode(), ix);
+ return VpCheckGetValue(cv);
+ }
+}
+
+ /*
+ * Document-method: BigDecimal#div
+ *
+ * call-seq:
+ * div(value) -> integer
+ * div(value, digits) -> bigdecimal or integer
+ *
+ * Divide by the specified value.
+ *
+ * digits:: If specified and less than the number of significant digits of the
+ * result, the result is rounded to that number of digits, according
+ * to BigDecimal.mode.
+ *
+ * If digits is 0, the result is the same as for the / operator
+ * or #quo.
+ *
+ * If digits is not specified, the result is an integer,
+ * by analogy with Float#div; see also BigDecimal#divmod.
+ *
+ * See BigDecimal#/.
+ * See BigDecimal#quo.
+ *
+ * Examples:
+ *
+ * a = BigDecimal("4")
+ * b = BigDecimal("3")
+ *
+ * a.div(b, 3) # => 0.133e1
+ *
+ * a.div(b, 0) # => 0.1333333333333333333e1
+ * a / b # => 0.1333333333333333333e1
+ * a.quo(b) # => 0.1333333333333333333e1
+ *
+ * a.div(b) # => 1
+ */
+static VALUE
+BigDecimal_div3(int argc, VALUE *argv, VALUE self)
+{
+ VALUE b,n;
+
+ rb_scan_args(argc, argv, "11", &b, &n);
+
+ return BigDecimal_div2(self, b, n);
+}
+
+ /*
+ * call-seq:
+ * add(value, ndigits) -> new_bigdecimal
+ *
+ * Returns the \BigDecimal sum of +self+ and +value+
+ * with a precision of +ndigits+ decimal digits.
+ *
+ * When +ndigits+ is less than the number of significant digits
+ * in the sum, the sum is rounded to that number of digits,
+ * according to the current rounding mode; see BigDecimal.mode.
+ *
+ * Examples:
+ *
+ * # Set the rounding mode.
+ * BigDecimal.mode(BigDecimal::ROUND_MODE, :half_up)
+ * b = BigDecimal('111111.111')
+ * b.add(1, 0) # => 0.111112111e6
+ * b.add(1, 3) # => 0.111e6
+ * b.add(1, 6) # => 0.111112e6
+ * b.add(1, 15) # => 0.111112111e6
+ * b.add(1.0, 15) # => 0.111112111e6
+ * b.add(Rational(1, 1), 15) # => 0.111112111e6
+ *
+ */
+
+static VALUE
+BigDecimal_add2(VALUE self, VALUE b, VALUE n)
+{
+ ENTER(2);
+ Real *cv;
+ SIGNED_VALUE mx = check_int_precision(n);
+ if (mx == 0) return BigDecimal_add(self, b);
+ else {
+ size_t pl = VpSetPrecLimit(0);
+ VALUE c = BigDecimal_add(self, b);
+ VpSetPrecLimit(pl);
+ GUARD_OBJ(cv, GetVpValue(c, 1));
+ VpLeftRound(cv, VpGetRoundMode(), mx);
+ return VpCheckGetValue(cv);
+ }
+}
+
+/* call-seq:
+ * sub(value, digits) -> bigdecimal
+ *
+ * Subtract the specified value.
+ *
+ * e.g.
+ * c = a.sub(b,n)
+ *
+ * digits:: If specified and less than the number of significant digits of the
+ * result, the result is rounded to that number of digits, according
+ * to BigDecimal.mode.
+ *
+ */
+static VALUE
+BigDecimal_sub2(VALUE self, VALUE b, VALUE n)
+{
+ ENTER(2);
+ Real *cv;
+ SIGNED_VALUE mx = check_int_precision(n);
+ if (mx == 0) return BigDecimal_sub(self, b);
+ else {
+ size_t pl = VpSetPrecLimit(0);
+ VALUE c = BigDecimal_sub(self, b);
+ VpSetPrecLimit(pl);
+ GUARD_OBJ(cv, GetVpValue(c, 1));
+ VpLeftRound(cv, VpGetRoundMode(), mx);
+ return VpCheckGetValue(cv);
+ }
+}
+
+ /*
+ * call-seq:
+ * mult(other, ndigits) -> bigdecimal
+ *
+ * Returns the \BigDecimal product of +self+ and +value+
+ * with a precision of +ndigits+ decimal digits.
+ *
+ * When +ndigits+ is less than the number of significant digits
+ * in the sum, the sum is rounded to that number of digits,
+ * according to the current rounding mode; see BigDecimal.mode.
+ *
+ * Examples:
+ *
+ * # Set the rounding mode.
+ * BigDecimal.mode(BigDecimal::ROUND_MODE, :half_up)
+ * b = BigDecimal('555555.555')
+ * b.mult(3, 0) # => 0.1666666665e7
+ * b.mult(3, 3) # => 0.167e7
+ * b.mult(3, 6) # => 0.166667e7
+ * b.mult(3, 15) # => 0.1666666665e7
+ * b.mult(3.0, 0) # => 0.1666666665e7
+ * b.mult(Rational(3, 1), 0) # => 0.1666666665e7
+ * b.mult(Complex(3, 0), 0) # => (0.1666666665e7+0.0i)
+ *
+ */
+
+static VALUE
+BigDecimal_mult2(VALUE self, VALUE b, VALUE n)
+{
+ ENTER(2);
+ Real *cv;
+ SIGNED_VALUE mx = check_int_precision(n);
+ if (mx == 0) return BigDecimal_mult(self, b);
+ else {
+ size_t pl = VpSetPrecLimit(0);
+ VALUE c = BigDecimal_mult(self, b);
+ VpSetPrecLimit(pl);
+ GUARD_OBJ(cv, GetVpValue(c, 1));
+ VpLeftRound(cv, VpGetRoundMode(), mx);
+ return VpCheckGetValue(cv);
+ }
+}
+
+/*
+ * call-seq:
+ * abs -> bigdecimal
+ *
+ * Returns the \BigDecimal absolute value of +self+:
+ *
+ * BigDecimal('5').abs # => 0.5e1
+ * BigDecimal('-3').abs # => 0.3e1
+ *
+ */
+
+static VALUE
+BigDecimal_abs(VALUE self)
+{
+ ENTER(5);
+ Real *c, *a;
+ size_t mx;
+
+ GUARD_OBJ(a, GetVpValue(self, 1));
+ mx = a->Prec *(VpBaseFig() + 1);
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
+ VpAsgn(c, a, 1);
+ VpChangeSign(c, 1);
+ return VpCheckGetValue(c);
+}
+
+/* call-seq:
+ * sqrt(n)
+ *
+ * Returns the square root of the value.
+ *
+ * Result has at least n significant digits.
+ */
+static VALUE
+BigDecimal_sqrt(VALUE self, VALUE nFig)
+{
+ ENTER(5);
+ Real *c, *a;
+ size_t mx, n;
+
+ GUARD_OBJ(a, GetVpValue(self, 1));
+ mx = a->Prec * (VpBaseFig() + 1);
+
+ n = check_int_precision(nFig);
+ n += VpDblFig() + VpBaseFig();
+ if (mx <= n) mx = n;
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
+ VpSqrt(c, a);
+ return VpCheckGetValue(c);
+}
+
+/* Return the integer part of the number, as a BigDecimal.
+ */
+static VALUE
+BigDecimal_fix(VALUE self)
+{
+ ENTER(5);
+ Real *c, *a;
+ size_t mx;
+
+ GUARD_OBJ(a, GetVpValue(self, 1));
+ mx = a->Prec *(VpBaseFig() + 1);
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
+ VpActiveRound(c, a, VP_ROUND_DOWN, 0); /* 0: round off */
+ return VpCheckGetValue(c);
+}
+
+/* call-seq:
+ * round(n, mode)
+ *
+ * Round to the nearest integer (by default), returning the result as a
+ * BigDecimal if n is specified, or as an Integer if it isn't.
+ *
+ * BigDecimal('3.14159').round #=> 3
+ * BigDecimal('8.7').round #=> 9
+ * BigDecimal('-9.9').round #=> -10
+ *
+ * BigDecimal('3.14159').round(2).class.name #=> "BigDecimal"
+ * BigDecimal('3.14159').round.class.name #=> "Integer"
+ *
+ * If n is specified and positive, the fractional part of the result has no
+ * more than that many digits.
+ *
+ * If n is specified and negative, at least that many digits to the left of the
+ * decimal point will be 0 in the result, and return value will be an Integer.
+ *
+ * BigDecimal('3.14159').round(3) #=> 3.142
+ * BigDecimal('13345.234').round(-2) #=> 13300
+ *
+ * The value of the optional mode argument can be used to determine how
+ * rounding is performed; see BigDecimal.mode.
+ */
+static VALUE
+BigDecimal_round(int argc, VALUE *argv, VALUE self)
+{
+ ENTER(5);
+ Real *c, *a;
+ int iLoc = 0;
+ VALUE vLoc;
+ VALUE vRound;
+ int round_to_int = 0;
+ size_t mx, pl;
+
+ unsigned short sw = VpGetRoundMode();
+
+ switch (rb_scan_args(argc, argv, "02", &vLoc, &vRound)) {
+ case 0:
+ iLoc = 0;
+ round_to_int = 1;
+ break;
+ case 1:
+ if (RB_TYPE_P(vLoc, T_HASH)) {
+ sw = check_rounding_mode_option(vLoc);
+ }
+ else {
+ iLoc = NUM2INT(vLoc);
+ if (iLoc < 1) round_to_int = 1;
+ }
+ break;
+ case 2:
+ iLoc = NUM2INT(vLoc);
+ if (RB_TYPE_P(vRound, T_HASH)) {
+ sw = check_rounding_mode_option(vRound);
+ }
+ else {
+ sw = check_rounding_mode(vRound);
+ }
+ break;
+ default:
+ break;
+ }
+
+ pl = VpSetPrecLimit(0);
+ GUARD_OBJ(a, GetVpValue(self, 1));
+ mx = a->Prec * (VpBaseFig() + 1);
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
+ VpSetPrecLimit(pl);
+ VpActiveRound(c, a, sw, iLoc);
+ if (round_to_int) {
+ return BigDecimal_to_i(VpCheckGetValue(c));
+ }
+ return VpCheckGetValue(c);
+}
+
+/* call-seq:
+ * truncate(n)
+ *
+ * Truncate to the nearest integer (by default), returning the result as a
+ * BigDecimal.
+ *
+ * BigDecimal('3.14159').truncate #=> 3
+ * BigDecimal('8.7').truncate #=> 8
+ * BigDecimal('-9.9').truncate #=> -9
+ *
+ * If n is specified and positive, the fractional part of the result has no
+ * more than that many digits.
+ *
+ * If n is specified and negative, at least that many digits to the left of the
+ * decimal point will be 0 in the result.
+ *
+ * BigDecimal('3.14159').truncate(3) #=> 3.141
+ * BigDecimal('13345.234').truncate(-2) #=> 13300.0
+ */
+static VALUE
+BigDecimal_truncate(int argc, VALUE *argv, VALUE self)
+{
+ ENTER(5);
+ Real *c, *a;
+ int iLoc;
+ VALUE vLoc;
+ size_t mx, pl = VpSetPrecLimit(0);
+
+ if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
+ iLoc = 0;
+ }
+ else {
+ iLoc = NUM2INT(vLoc);
+ }
+
+ GUARD_OBJ(a, GetVpValue(self, 1));
+ mx = a->Prec * (VpBaseFig() + 1);
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
+ VpSetPrecLimit(pl);
+ VpActiveRound(c, a, VP_ROUND_DOWN, iLoc); /* 0: truncate */
+ if (argc == 0) {
+ return BigDecimal_to_i(VpCheckGetValue(c));
+ }
+ return VpCheckGetValue(c);
+}
+
+/* Return the fractional part of the number, as a BigDecimal.
+ */
+static VALUE
+BigDecimal_frac(VALUE self)
+{
+ ENTER(5);
+ Real *c, *a;
+ size_t mx;
+
+ GUARD_OBJ(a, GetVpValue(self, 1));
+ mx = a->Prec * (VpBaseFig() + 1);
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
+ VpFrac(c, a);
+ return VpCheckGetValue(c);
+}
+
+/* call-seq:
+ * floor(n)
+ *
+ * Return the largest integer less than or equal to the value, as a BigDecimal.
+ *
+ * BigDecimal('3.14159').floor #=> 3
+ * BigDecimal('-9.1').floor #=> -10
+ *
+ * If n is specified and positive, the fractional part of the result has no
+ * more than that many digits.
+ *
+ * If n is specified and negative, at least that
+ * many digits to the left of the decimal point will be 0 in the result.
+ *
+ * BigDecimal('3.14159').floor(3) #=> 3.141
+ * BigDecimal('13345.234').floor(-2) #=> 13300.0
+ */
+static VALUE
+BigDecimal_floor(int argc, VALUE *argv, VALUE self)
+{
+ ENTER(5);
+ Real *c, *a;
+ int iLoc;
+ VALUE vLoc;
+ size_t mx, pl = VpSetPrecLimit(0);
+
+ if (rb_scan_args(argc, argv, "01", &vLoc)==0) {
+ iLoc = 0;
+ }
+ else {
+ iLoc = NUM2INT(vLoc);
+ }
+
+ GUARD_OBJ(a, GetVpValue(self, 1));
+ mx = a->Prec * (VpBaseFig() + 1);
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
+ VpSetPrecLimit(pl);
+ VpActiveRound(c, a, VP_ROUND_FLOOR, iLoc);
+#ifdef BIGDECIMAL_DEBUG
+ VPrint(stderr, "floor: c=%\n", c);
+#endif
+ if (argc == 0) {
+ return BigDecimal_to_i(VpCheckGetValue(c));
+ }
+ return VpCheckGetValue(c);
+}
+
+/* call-seq:
+ * ceil(n)
+ *
+ * Return the smallest integer greater than or equal to the value, as a BigDecimal.
+ *
+ * BigDecimal('3.14159').ceil #=> 4
+ * BigDecimal('-9.1').ceil #=> -9
+ *
+ * If n is specified and positive, the fractional part of the result has no
+ * more than that many digits.
+ *
+ * If n is specified and negative, at least that
+ * many digits to the left of the decimal point will be 0 in the result.
+ *
+ * BigDecimal('3.14159').ceil(3) #=> 3.142
+ * BigDecimal('13345.234').ceil(-2) #=> 13400.0
+ */
+static VALUE
+BigDecimal_ceil(int argc, VALUE *argv, VALUE self)
+{
+ ENTER(5);
+ Real *c, *a;
+ int iLoc;
+ VALUE vLoc;
+ size_t mx, pl = VpSetPrecLimit(0);
+
+ if (rb_scan_args(argc, argv, "01", &vLoc) == 0) {
+ iLoc = 0;
+ } else {
+ iLoc = NUM2INT(vLoc);
+ }
+
+ GUARD_OBJ(a, GetVpValue(self, 1));
+ mx = a->Prec * (VpBaseFig() + 1);
+ GUARD_OBJ(c, NewZeroWrapLimited(1, mx));
+ VpSetPrecLimit(pl);
+ VpActiveRound(c, a, VP_ROUND_CEIL, iLoc);
+ if (argc == 0) {
+ return BigDecimal_to_i(VpCheckGetValue(c));
+ }
+ return VpCheckGetValue(c);
+}
+
+/* call-seq:
+ * to_s(s)
+ *
+ * Converts the value to a string.
+ *
+ * The default format looks like 0.xxxxEnn.
+ *
+ * The optional parameter s consists of either an integer; or an optional '+'
+ * or ' ', followed by an optional number, followed by an optional 'E' or 'F'.
+ *
+ * If there is a '+' at the start of s, positive values are returned with
+ * a leading '+'.
+ *
+ * A space at the start of s returns positive values with a leading space.
+ *
+ * If s contains a number, a space is inserted after each group of that many
+ * fractional digits.
+ *
+ * If s ends with an 'E', engineering notation (0.xxxxEnn) is used.
+ *
+ * If s ends with an 'F', conventional floating point notation is used.
+ *
+ * Examples:
+ *
+ * BigDecimal('-123.45678901234567890').to_s('5F')
+ * #=> '-123.45678 90123 45678 9'
+ *
+ * BigDecimal('123.45678901234567890').to_s('+8F')
+ * #=> '+123.45678901 23456789'
+ *
+ * BigDecimal('123.45678901234567890').to_s(' F')
+ * #=> ' 123.4567890123456789'
+ */
+static VALUE
+BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
+{
+ ENTER(5);
+ int fmt = 0; /* 0: E format, 1: F format */
+ int fPlus = 0; /* 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
+ Real *vp;
+ volatile VALUE str;
+ char *psz;
+ char ch;
+ size_t nc, mc = 0;
+ SIGNED_VALUE m;
+ VALUE f;
+
+ GUARD_OBJ(vp, GetVpValue(self, 1));
+
+ if (rb_scan_args(argc, argv, "01", &f) == 1) {
+ if (RB_TYPE_P(f, T_STRING)) {
+ psz = StringValueCStr(f);
+ if (*psz == ' ') {
+ fPlus = 1;
+ psz++;
+ }
+ else if (*psz == '+') {
+ fPlus = 2;
+ psz++;
+ }
+ while ((ch = *psz++) != 0) {
+ if (ISSPACE(ch)) {
+ continue;
+ }
+ if (!ISDIGIT(ch)) {
+ if (ch == 'F' || ch == 'f') {
+ fmt = 1; /* F format */
+ }
+ break;
+ }
+ mc = mc*10 + ch - '0';
+ }
+ }
+ else {
+ m = NUM2INT(f);
+ if (m <= 0) {
+ rb_raise(rb_eArgError, "argument must be positive");
+ }
+ mc = (size_t)m;
+ }
+ }
+ if (fmt) {
+ nc = VpNumOfChars(vp, "F");
+ }
+ else {
+ nc = VpNumOfChars(vp, "E");
+ }
+ if (mc > 0) {
+ nc += (nc + mc - 1) / mc + 1;
+ }
+
+ str = rb_usascii_str_new(0, nc);
+ psz = RSTRING_PTR(str);
+
+ if (fmt) {
+ VpToFString(vp, psz, RSTRING_LEN(str), mc, fPlus);
+ }
+ else {
+ VpToString (vp, psz, RSTRING_LEN(str), mc, fPlus);
+ }
+ rb_str_resize(str, strlen(psz));
+ return str;
+}
+
+/* Splits a BigDecimal number into four parts, returned as an array of values.
+ *
+ * The first value represents the sign of the BigDecimal, and is -1 or 1, or 0
+ * if the BigDecimal is Not a Number.
+ *
+ * The second value is a string representing the significant digits of the
+ * BigDecimal, with no leading zeros.
+ *
+ * The third value is the base used for arithmetic (currently always 10) as an
+ * Integer.
+ *
+ * The fourth value is an Integer exponent.
+ *
+ * If the BigDecimal can be represented as 0.xxxxxx*10**n, then xxxxxx is the
+ * string of significant digits with no leading zeros, and n is the exponent.
+ *
+ * From these values, you can translate a BigDecimal to a float as follows:
+ *
+ * sign, significant_digits, base, exponent = a.split
+ * f = sign * "0.#{significant_digits}".to_f * (base ** exponent)
+ *
+ * (Note that the to_f method is provided as a more convenient way to translate
+ * a BigDecimal to a Float.)
+ */
+static VALUE
+BigDecimal_split(VALUE self)
+{
+ ENTER(5);
+ Real *vp;
+ VALUE obj,str;
+ ssize_t e, s;
+ char *psz1;
+
+ GUARD_OBJ(vp, GetVpValue(self, 1));
+ str = rb_str_new(0, VpNumOfChars(vp, "E"));
+ psz1 = RSTRING_PTR(str);
+ VpSzMantissa(vp, psz1, RSTRING_LEN(str));
+ s = 1;
+ if(psz1[0] == '-') {
+ size_t len = strlen(psz1 + 1);
+
+ memmove(psz1, psz1 + 1, len);
+ psz1[len] = '\0';
+ s = -1;
+ }
+ if (psz1[0] == 'N') s = 0; /* NaN */
+ e = VpExponent10(vp);
+ obj = rb_ary_new2(4);
+ rb_ary_push(obj, INT2FIX(s));
+ rb_ary_push(obj, str);
+ rb_str_resize(str, strlen(psz1));
+ rb_ary_push(obj, INT2FIX(10));
+ rb_ary_push(obj, SSIZET2NUM(e));
+ return obj;
+}
+
+/* Returns the exponent of the BigDecimal number, as an Integer.
+ *
+ * If the number can be represented as 0.xxxxxx*10**n where xxxxxx is a string
+ * of digits with no leading zeros, then n is the exponent.
+ */
+static VALUE
+BigDecimal_exponent(VALUE self)
+{
+ ssize_t e = VpExponent10(GetVpValue(self, 1));
+ return SSIZET2NUM(e);
+}
+
+/* Returns a string representation of self.
+ *
+ * BigDecimal("1234.5678").inspect
+ * #=> "0.12345678e4"
+ */
+static VALUE
+BigDecimal_inspect(VALUE self)
+{
+ ENTER(5);
+ Real *vp;
+ volatile VALUE str;
+ size_t nc;
+
+ GUARD_OBJ(vp, GetVpValue(self, 1));
+ nc = VpNumOfChars(vp, "E");
+
+ str = rb_str_new(0, nc);
+ VpToString(vp, RSTRING_PTR(str), RSTRING_LEN(str), 0, 0);
+ rb_str_resize(str, strlen(RSTRING_PTR(str)));
+ return str;
+}
+
+static VALUE BigMath_s_exp(VALUE, VALUE, VALUE);
+static VALUE BigMath_s_log(VALUE, VALUE, VALUE);
+
+#define BigMath_exp(x, n) BigMath_s_exp(rb_mBigMath, (x), (n))
+#define BigMath_log(x, n) BigMath_s_log(rb_mBigMath, (x), (n))
+
+inline static int
+is_integer(VALUE x)
+{
+ return (RB_TYPE_P(x, T_FIXNUM) || RB_TYPE_P(x, T_BIGNUM));
+}
+
+inline static int
+is_negative(VALUE x)
+{
+ if (FIXNUM_P(x)) {
+ return FIX2LONG(x) < 0;
+ }
+ else if (RB_TYPE_P(x, T_BIGNUM)) {
+ return FIX2INT(rb_big_cmp(x, INT2FIX(0))) < 0;
+ }
+ else if (RB_TYPE_P(x, T_FLOAT)) {
+ return RFLOAT_VALUE(x) < 0.0;
+ }
+ return RTEST(rb_funcall(x, '<', 1, INT2FIX(0)));
+}
+
+#define is_positive(x) (!is_negative(x))
+
+inline static int
+is_zero(VALUE x)
+{
+ VALUE num;
+
+ switch (TYPE(x)) {
+ case T_FIXNUM:
+ return FIX2LONG(x) == 0;
+
+ case T_BIGNUM:
+ return Qfalse;
+
+ case T_RATIONAL:
+ num = rb_rational_num(x);
+ return FIXNUM_P(num) && FIX2LONG(num) == 0;
+
+ default:
+ break;
+ }
+
+ return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(0)));
+}
+
+inline static int
+is_one(VALUE x)
+{
+ VALUE num, den;
+
+ switch (TYPE(x)) {
+ case T_FIXNUM:
+ return FIX2LONG(x) == 1;
+
+ case T_BIGNUM:
+ return Qfalse;
+
+ case T_RATIONAL:
+ num = rb_rational_num(x);
+ den = rb_rational_den(x);
+ return FIXNUM_P(den) && FIX2LONG(den) == 1 &&
+ FIXNUM_P(num) && FIX2LONG(num) == 1;
+
+ default:
+ break;
+ }
+
+ return RTEST(rb_funcall(x, id_eq, 1, INT2FIX(1)));
+}
+
+inline static int
+is_even(VALUE x)
+{
+ switch (TYPE(x)) {
+ case T_FIXNUM:
+ return (FIX2LONG(x) % 2) == 0;
+
+ case T_BIGNUM:
+ {
+ unsigned long l;
+ rb_big_pack(x, &l, 1);
+ return l % 2 == 0;
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static VALUE
+bigdecimal_power_by_bigdecimal(Real const* x, Real const* exp, ssize_t const n)
+{
+ VALUE log_x, multiplied, y;
+ volatile VALUE obj = exp->obj;
+
+ if (VpIsZero(exp)) {
+ return VpCheckGetValue(NewOneWrapLimited(1, n));
+ }
+
+ log_x = BigMath_log(x->obj, SSIZET2NUM(n+1));
+ multiplied = BigDecimal_mult2(exp->obj, log_x, SSIZET2NUM(n+1));
+ y = BigMath_exp(multiplied, SSIZET2NUM(n));
+ RB_GC_GUARD(obj);
+
+ return y;
+}
+
+/* call-seq:
+ * power(n)
+ * power(n, prec)
+ *
+ * Returns the value raised to the power of n.
+ *
+ * Note that n must be an Integer.
+ *
+ * Also available as the operator **.
+ */
+static VALUE
+BigDecimal_power(int argc, VALUE*argv, VALUE self)
+{
+ ENTER(5);
+ VALUE vexp, prec;
+ Real* exp = NULL;
+ Real *x, *y;
+ ssize_t mp, ma, n;
+ SIGNED_VALUE int_exp;
+ double d;
+
+ rb_scan_args(argc, argv, "11", &vexp, &prec);
+
+ GUARD_OBJ(x, GetVpValue(self, 1));
+ n = NIL_P(prec) ? (ssize_t)(x->Prec*VpBaseFig()) : NUM2SSIZET(prec);
+
+ if (VpIsNaN(x)) {
+ y = NewZeroWrapLimited(1, n);
+ VpSetNaN(y);
+ RB_GC_GUARD(y->obj);
+ return VpCheckGetValue(y);
+ }
+
+ retry:
+ switch (TYPE(vexp)) {
+ case T_FIXNUM:
+ break;
+
+ case T_BIGNUM:
+ break;
+
+ case T_FLOAT:
+ d = RFLOAT_VALUE(vexp);
+ if (d == round(d)) {
+ if (FIXABLE(d)) {
+ vexp = LONG2FIX((long)d);
+ }
+ else {
+ vexp = rb_dbl2big(d);
+ }
+ goto retry;
+ }
+ if (NIL_P(prec)) {
+ n += BIGDECIMAL_DOUBLE_FIGURES;
+ }
+ exp = GetVpValueWithPrec(vexp, 0, 1);
+ break;
+
+ case T_RATIONAL:
+ if (is_zero(rb_rational_num(vexp))) {
+ if (is_positive(vexp)) {
+ vexp = INT2FIX(0);
+ goto retry;
+ }
+ }
+ else if (is_one(rb_rational_den(vexp))) {
+ vexp = rb_rational_num(vexp);
+ goto retry;
+ }
+ exp = GetVpValueWithPrec(vexp, n, 1);
+ if (NIL_P(prec)) {
+ n += n;
+ }
+ break;
+
+ case T_DATA:
+ if (is_kind_of_BigDecimal(vexp)) {
+ VALUE zero = INT2FIX(0);
+ VALUE rounded = BigDecimal_round(1, &zero, vexp);
+ if (RTEST(BigDecimal_eq(vexp, rounded))) {
+ vexp = BigDecimal_to_i(vexp);
+ goto retry;
+ }
+ if (NIL_P(prec)) {
+ GUARD_OBJ(y, GetVpValue(vexp, 1));
+ n += y->Prec*VpBaseFig();
+ }
+ exp = DATA_PTR(vexp);
+ break;
+ }
+ /* fall through */
+ default:
+ rb_raise(rb_eTypeError,
+ "wrong argument type %"PRIsVALUE" (expected scalar Numeric)",
+ RB_OBJ_CLASSNAME(vexp));
+ }
+
+ if (VpIsZero(x)) {
+ if (is_negative(vexp)) {
+ y = NewZeroWrapNolimit(1, n);
+ if (BIGDECIMAL_NEGATIVE_P(x)) {
+ if (is_integer(vexp)) {
+ if (is_even(vexp)) {
+ /* (-0) ** (-even_integer) -> Infinity */
+ VpSetPosInf(y);
+ }
+ else {
+ /* (-0) ** (-odd_integer) -> -Infinity */
+ VpSetNegInf(y);
+ }
+ }
+ else {
+ /* (-0) ** (-non_integer) -> Infinity */
+ VpSetPosInf(y);
+ }
+ }
+ else {
+ /* (+0) ** (-num) -> Infinity */
+ VpSetPosInf(y);
+ }
+ RB_GC_GUARD(y->obj);
+ return VpCheckGetValue(y);
+ }
+ else if (is_zero(vexp)) {
+ return VpCheckGetValue(NewOneWrapLimited(1, n));
+ }
+ else {
+ return VpCheckGetValue(NewZeroWrapLimited(1, n));
+ }
+ }
+
+ if (is_zero(vexp)) {
+ return VpCheckGetValue(NewOneWrapLimited(1, n));
+ }
+ else if (is_one(vexp)) {
+ return self;
+ }
+
+ if (VpIsInf(x)) {
+ if (is_negative(vexp)) {
+ if (BIGDECIMAL_NEGATIVE_P(x)) {
+ if (is_integer(vexp)) {
+ if (is_even(vexp)) {
+ /* (-Infinity) ** (-even_integer) -> +0 */
+ return VpCheckGetValue(NewZeroWrapLimited(1, n));
+ }
+ else {
+ /* (-Infinity) ** (-odd_integer) -> -0 */
+ return VpCheckGetValue(NewZeroWrapLimited(-1, n));
+ }
+ }
+ else {
+ /* (-Infinity) ** (-non_integer) -> -0 */
+ return VpCheckGetValue(NewZeroWrapLimited(-1, n));
+ }
+ }
+ else {
+ return VpCheckGetValue(NewZeroWrapLimited(1, n));
+ }
+ }
+ else {
+ y = NewZeroWrapLimited(1, n);
+ if (BIGDECIMAL_NEGATIVE_P(x)) {
+ if (is_integer(vexp)) {
+ if (is_even(vexp)) {
+ VpSetPosInf(y);
+ }
+ else {
+ VpSetNegInf(y);
+ }
+ }
+ else {
+ /* TODO: support complex */
+ rb_raise(rb_eMathDomainError,
+ "a non-integral exponent for a negative base");
+ }
+ }
+ else {
+ VpSetPosInf(y);
+ }
+ return VpCheckGetValue(y);
+ }
+ }
+
+ if (exp != NULL) {
+ return bigdecimal_power_by_bigdecimal(x, exp, n);
+ }
+ else if (RB_TYPE_P(vexp, T_BIGNUM)) {
+ VALUE abs_value = BigDecimal_abs(self);
+ if (is_one(abs_value)) {
+ return VpCheckGetValue(NewOneWrapLimited(1, n));
+ }
+ else if (RTEST(rb_funcall(abs_value, '<', 1, INT2FIX(1)))) {
+ if (is_negative(vexp)) {
+ y = NewZeroWrapLimited(1, n);
+ VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
+ return VpCheckGetValue(y);
+ }
+ else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
+ return VpCheckGetValue(NewZeroWrapLimited(-1, n));
+ }
+ else {
+ return VpCheckGetValue(NewZeroWrapLimited(1, n));
+ }
+ }
+ else {
+ if (is_positive(vexp)) {
+ y = NewZeroWrapLimited(1, n);
+ VpSetInf(y, (is_even(vexp) ? 1 : -1) * VpGetSign(x));
+ return VpCheckGetValue(y);
+ }
+ else if (BIGDECIMAL_NEGATIVE_P(x) && is_even(vexp)) {
+ return VpCheckGetValue(NewZeroWrapLimited(-1, n));
+ }
+ else {
+ return VpCheckGetValue(NewZeroWrapLimited(1, n));
+ }
+ }
+ }
+
+ int_exp = FIX2LONG(vexp);
+ ma = int_exp;
+ if (ma < 0) ma = -ma;
+ if (ma == 0) ma = 1;
+
+ if (VpIsDef(x)) {
+ mp = x->Prec * (VpBaseFig() + 1);
+ GUARD_OBJ(y, NewZeroWrapLimited(1, mp * (ma + 1)));
+ }
+ else {
+ GUARD_OBJ(y, NewZeroWrapLimited(1, 1));
+ }
+ VpPowerByInt(y, x, int_exp);
+ if (!NIL_P(prec) && VpIsDef(y)) {
+ VpMidRound(y, VpGetRoundMode(), n);
+ }
+ return VpCheckGetValue(y);
+}
+
+/* call-seq:
+ * self ** other -> bigdecimal
+ *
+ * Returns the \BigDecimal value of +self+ raised to power +other+:
+ *
+ * b = BigDecimal('3.14')
+ * b ** 2 # => 0.98596e1
+ * b ** 2.0 # => 0.98596e1
+ * b ** Rational(2, 1) # => 0.98596e1
+ *
+ * Related: BigDecimal#power.
+ *
+ */
+static VALUE
+BigDecimal_power_op(VALUE self, VALUE exp)
+{
+ return BigDecimal_power(1, &exp, self);
+}
+
+/* :nodoc:
+ *
+ * private method for dup and clone the provided BigDecimal +other+
+ */
+static VALUE
+BigDecimal_initialize_copy(VALUE self, VALUE other)
+{
+ Real *pv = rb_check_typeddata(self, &BigDecimal_data_type);
+ Real *x = rb_check_typeddata(other, &BigDecimal_data_type);
+
+ if (self != other) {
+ DATA_PTR(self) = VpCopy(pv, x);
+ }
+ return self;
+}
+
+static VALUE
+BigDecimal_clone(VALUE self)
+{
+ return self;
+}
+
+#ifdef HAVE_RB_OPTS_EXCEPTION_P
+int rb_opts_exception_p(VALUE opts, int default_value);
+#define opts_exception_p(opts) rb_opts_exception_p((opts), 1)
+#else
+static int
+opts_exception_p(VALUE opts)
+{
+ static ID kwds[1];
+ VALUE exception;
+ if (!kwds[0]) {
+ kwds[0] = rb_intern_const("exception");
+ }
+ if (!rb_get_kwargs(opts, kwds, 0, 1, &exception)) return 1;
+ switch (exception) {
+ case Qtrue: case Qfalse:
+ break;
+ default:
+ rb_raise(rb_eArgError, "true or false is expected as exception: %+"PRIsVALUE,
+ exception);
+ }
+ return exception != Qfalse;
+}
+#endif
+
+static VALUE
+check_exception(VALUE bd)
+{
+ assert(is_kind_of_BigDecimal(bd));
+
+ Real *vp;
+ TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
+ VpCheckGetValue(vp); /* VpCheckGetValue performs exception check */
+
+ return bd;
+}
+
+static VALUE
+rb_uint64_convert_to_BigDecimal(uint64_t uval, RB_UNUSED_VAR(size_t digs), int raise_exception)
+{
+ VALUE obj = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
+
+ Real *vp;
+ if (uval == 0) {
+ vp = rbd_allocate_struct(1);
+ vp->MaxPrec = 1;
+ vp->Prec = 1;
+ vp->exponent = 1;
+ VpSetZero(vp, 1);
+ vp->frac[0] = 0;
+ }
+ else if (uval < BASE) {
+ vp = rbd_allocate_struct(1);
+ vp->MaxPrec = 1;
+ vp->Prec = 1;
+ vp->exponent = 1;
+ VpSetSign(vp, 1);
+ vp->frac[0] = (DECDIG)uval;
+ }
+ else {
+ DECDIG buf[BIGDECIMAL_INT64_MAX_LENGTH] = {0,};
+ DECDIG r = uval % BASE;
+ size_t len = 0, ntz = 0;
+ if (r == 0) {
+ // Count and skip trailing zeros
+ for (; r == 0 && uval > 0; ++ntz) {
+ uval /= BASE;
+ r = uval % BASE;
+ }
+ }
+ for (; uval > 0; ++len) {
+ // Store digits
+ buf[BIGDECIMAL_INT64_MAX_LENGTH - len - 1] = r;
+ uval /= BASE;
+ r = uval % BASE;
+ }
+
+ const size_t exp = len + ntz;
+ vp = rbd_allocate_struct(len);
+ vp->MaxPrec = len;
+ vp->Prec = len;
+ vp->exponent = exp;
+ VpSetSign(vp, 1);
+ MEMCPY(vp->frac, buf + BIGDECIMAL_INT64_MAX_LENGTH - len, DECDIG, len);
+ }
+
+ return BigDecimal_wrap_struct(obj, vp);
+}
+
+static VALUE
+rb_int64_convert_to_BigDecimal(int64_t ival, size_t digs, int raise_exception)
+{
+ const uint64_t uval = (ival < 0) ? (((uint64_t)-(ival+1))+1) : (uint64_t)ival;
+ VALUE bd = rb_uint64_convert_to_BigDecimal(uval, digs, raise_exception);
+ if (ival < 0) {
+ Real *vp;
+ TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
+ VpSetSign(vp, -1);
+ }
+ return bd;
+}
+
+static VALUE
+rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
+{
+ assert(RB_TYPE_P(val, T_BIGNUM));
+
+ int leading_zeros;
+ size_t size = rb_absint_size(val, &leading_zeros);
+ int sign = FIX2INT(rb_big_cmp(val, INT2FIX(0)));
+ if (sign < 0 && leading_zeros == 0) {
+ size += 1;
+ }
+ if (size <= sizeof(long)) {
+ if (sign < 0) {
+ return rb_int64_convert_to_BigDecimal(NUM2LONG(val), digs, raise_exception);
+ }
+ else {
+ return rb_uint64_convert_to_BigDecimal(NUM2ULONG(val), digs, raise_exception);
+ }
+ }
+#if defined(SIZEOF_LONG_LONG) && SIZEOF_LONG < SIZEOF_LONG_LONG
+ else if (size <= sizeof(LONG_LONG)) {
+ if (sign < 0) {
+ return rb_int64_convert_to_BigDecimal(NUM2LL(val), digs, raise_exception);
+ }
+ else {
+ return rb_uint64_convert_to_BigDecimal(NUM2ULL(val), digs, raise_exception);
+ }
+ }
+#endif
+ else {
+ VALUE str = rb_big2str(val, 10);
+ Real *vp = VpCreateRbObject(RSTRING_LEN(str) + BASE_FIG + 1,
+ RSTRING_PTR(str), true);
+ RB_GC_GUARD(str);
+ return check_exception(vp->obj);
+ }
+}
+
+static VALUE
+rb_inum_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_exception)
+{
+ assert(RB_INTEGER_TYPE_P(val));
+ if (FIXNUM_P(val)) {
+ return rb_int64_convert_to_BigDecimal(FIX2LONG(val), digs, raise_exception);
+ }
+ else {
+ return rb_big_convert_to_BigDecimal(val, digs, raise_exception);
+ }
+}
+
+static VALUE
+rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
+{
+ assert(RB_FLOAT_TYPE_P(val));
+
+ double d = RFLOAT_VALUE(val);
+
+ if (isnan(d)) {
+ VALUE obj = BigDecimal_nan();
+ return check_exception(obj);
+ }
+ else if (isinf(d)) {
+ VALUE obj;
+ if (d > 0) {
+ obj = BigDecimal_positive_infinity();
+ }
+ else {
+ obj = BigDecimal_negative_infinity();
+ }
+ return check_exception(obj);
+ }
+ else if (d == 0.0) {
+ if (1/d < 0.0) {
+ return BigDecimal_negative_zero();
+ }
+ else {
+ return BigDecimal_positive_zero();
+ }
+ }
+
+ if (digs == SIZE_MAX) {
+ if (!raise_exception)
+ return Qnil;
+ rb_raise(rb_eArgError,
+ "can't omit precision for a %"PRIsVALUE".",
+ CLASS_OF(val));
+ }
+ else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
+ if (!raise_exception)
+ return Qnil;
+ rb_raise(rb_eArgError, "precision too large.");
+ }
+
+ /* Use the same logic in flo_to_s to convert a float to a decimal string */
+ char buf[BIGDECIMAL_DOUBLE_FIGURES + BASE_FIG + 2 + 1]; /* sizeof(buf) == 28 in the typical case */
+ int decpt, negative_p;
+ char *e;
+ const int mode = digs == 0 ? 0 : 2;
+ char *p = BigDecimal_dtoa(d, mode, (int)digs, &decpt, &negative_p, &e);
+ int len10 = (int)(e - p);
+ if (len10 > BIGDECIMAL_DOUBLE_FIGURES) {
+ /* TODO: Presumably, rounding should be done here. */
+ len10 = BIGDECIMAL_DOUBLE_FIGURES;
+ }
+ memcpy(buf, p, len10);
+ xfree(p);
+
+ VALUE inum;
+ size_t RB_UNUSED_VAR(prec) = 0;
+ SIGNED_VALUE exp = 0;
+ if (decpt > 0) {
+ if (decpt < len10) {
+ /*
+ * len10 |---------------|
+ * : |-------| frac_len10 = len10 - decpt
+ * decpt |-------| |--| ntz10 = BASE_FIG - frac_len10 % BASE_FIG
+ * : : :
+ * 00 dd dddd.dddd dd 00
+ * prec |-----.----.----.-----| prec = exp + roomof(frac_len, BASE_FIG)
+ * exp |-----.----| exp = roomof(decpt, BASE_FIG)
+ */
+ const size_t frac_len10 = len10 - decpt;
+ const size_t ntz10 = BASE_FIG - frac_len10 % BASE_FIG;
+ memset(buf + len10, '0', ntz10);
+ buf[len10 + ntz10] = '\0';
+ inum = rb_cstr_to_inum(buf, 10, false);
+
+ exp = roomof(decpt, BASE_FIG);
+ prec = exp + roomof(frac_len10, BASE_FIG);
+ }
+ else {
+ /*
+ * decpt |-----------------------|
+ * len10 |----------| :
+ * : |------------| exp10
+ * : : :
+ * 00 dd dddd dd 00 0000 0000.0
+ * : : : :
+ * : |--| ntz10 = exp10 % BASE_FIG
+ * prec |-----.----.-----| :
+ * : |----.----| exp10 / BASE_FIG
+ * exp |-----.----.-----.----.----|
+ */
+ const size_t exp10 = decpt - len10;
+ const size_t ntz10 = exp10 % BASE_FIG;
+
+ memset(buf + len10, '0', ntz10);
+ buf[len10 + ntz10] = '\0';
+ inum = rb_cstr_to_inum(buf, 10, false);
+
+ prec = roomof(len10 + ntz10, BASE_FIG);
+ exp = prec + exp10 / BASE_FIG;
+ }
+ }
+ else if (decpt == 0) {
+ /*
+ * len10 |------------|
+ * : :
+ * 0.dddd dddd dd 00
+ * : : :
+ * : |--| ntz10 = prec * BASE_FIG - len10
+ * prec |----.----.-----| roomof(len10, BASE_FIG)
+ */
+ prec = roomof(len10, BASE_FIG);
+ const size_t ntz10 = prec * BASE_FIG - len10;
+
+ memset(buf + len10, '0', ntz10);
+ buf[len10 + ntz10] = '\0';
+ inum = rb_cstr_to_inum(buf, 10, false);
+ }
+ else {
+ /*
+ * len10 |---------------|
+ * : :
+ * decpt |-------| |--| ntz10 = prec * BASE_FIG - nlz10 - len10
+ * : : :
+ * 0.0000 00 dd dddd dddd dd 00
+ * : : :
+ * nlz10 |--| : decpt % BASE_FIG
+ * prec |-----.----.----.-----| roomof(decpt + len10, BASE_FIG) - exp
+ * exp |----| decpt / BASE_FIG
+ */
+ decpt = -decpt;
+
+ const size_t nlz10 = decpt % BASE_FIG;
+ exp = decpt / BASE_FIG;
+ prec = roomof(decpt + len10, BASE_FIG) - exp;
+ const size_t ntz10 = prec * BASE_FIG - nlz10 - len10;
+
+ if (nlz10 > 0) {
+ memmove(buf + nlz10, buf, len10);
+ memset(buf, '0', nlz10);
+ }
+ memset(buf + nlz10 + len10, '0', ntz10);
+ buf[nlz10 + len10 + ntz10] = '\0';
+ inum = rb_cstr_to_inum(buf, 10, false);
+
+ exp = -exp;
+ }
+
+ VALUE bd = rb_inum_convert_to_BigDecimal(inum, SIZE_MAX, raise_exception);
+ Real *vp;
+ TypedData_Get_Struct(bd, Real, &BigDecimal_data_type, vp);
+ assert(vp->Prec == prec);
+ vp->exponent = exp;
+
+ if (negative_p) VpSetSign(vp, -1);
+ return bd;
+}
+
+static VALUE
+rb_rational_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
+{
+ assert(RB_TYPE_P(val, T_RATIONAL));
+
+ if (digs == SIZE_MAX) {
+ if (!raise_exception)
+ return Qnil;
+ rb_raise(rb_eArgError,
+ "can't omit precision for a %"PRIsVALUE".",
+ CLASS_OF(val));
+ }
+
+ VALUE num = rb_inum_convert_to_BigDecimal(rb_rational_num(val), 0, raise_exception);
+ VALUE d = BigDecimal_div2(num, rb_rational_den(val), SIZET2NUM(digs));
+ return d;
+}
+
+static VALUE
+rb_cstr_convert_to_BigDecimal(const char *c_str, size_t digs, int raise_exception)
+{
+ if (digs == SIZE_MAX)
+ digs = 0;
+
+ Real *vp = VpCreateRbObject(digs, c_str, raise_exception);
+ if (!vp)
+ return Qnil;
+ return VpCheckGetValue(vp);
+}
+
+static inline VALUE
+rb_str_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
+{
+ const char *c_str = StringValueCStr(val);
+ return rb_cstr_convert_to_BigDecimal(c_str, digs, raise_exception);
+}
+
+static VALUE
+rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
+{
+ switch (val) {
+ case Qnil:
+ case Qtrue:
+ case Qfalse:
+ if (raise_exception) {
+ const char *cname = NIL_P(val) ? "nil" :
+ val == Qtrue ? "true" :
+ val == Qfalse ? "false" :
+ NULL;
+ rb_raise(rb_eTypeError,
+ "can't convert %s into BigDecimal", cname);
+ }
+ return Qnil;
+
+ default:
+ break;
+ }
+
+ if (is_kind_of_BigDecimal(val)) {
+ if (digs == SIZE_MAX)
+ return check_exception(val);
+
+ Real *vp;
+ TypedData_Get_Struct(val, Real, &BigDecimal_data_type, vp);
+
+ VALUE copy = TypedData_Wrap_Struct(rb_cBigDecimal, &BigDecimal_data_type, 0);
+ vp = VpCopy(NULL, vp);
+ /* TODO: rounding */
+ BigDecimal_wrap_struct(copy, vp);
+ return VpCheckGetValue(vp);
+ }
+ else if (RB_INTEGER_TYPE_P(val)) {
+ return rb_inum_convert_to_BigDecimal(val, digs, raise_exception);
+ }
+ else if (RB_FLOAT_TYPE_P(val)) {
+ return rb_float_convert_to_BigDecimal(val, digs, raise_exception);
+ }
+ else if (RB_TYPE_P(val, T_RATIONAL)) {
+ return rb_rational_convert_to_BigDecimal(val, digs, raise_exception);
+ }
+ else if (RB_TYPE_P(val, T_COMPLEX)) {
+ VALUE im = rb_complex_imag(val);
+ if (!is_zero(im)) {
+ /* TODO: handle raise_exception */
+ rb_raise(rb_eArgError,
+ "Unable to make a BigDecimal from non-zero imaginary number");
+ }
+ return rb_convert_to_BigDecimal(rb_complex_real(val), digs, raise_exception);
+ }
+ else if (RB_TYPE_P(val, T_STRING)) {
+ return rb_str_convert_to_BigDecimal(val, digs, raise_exception);
+ }
+
+ /* TODO: chheck to_d */
+ /* TODO: chheck to_int */
+
+ VALUE str = rb_check_convert_type(val, T_STRING, "String", "to_str");
+ if (!RB_TYPE_P(str, T_STRING)) {
+ if (raise_exception) {
+ rb_raise(rb_eTypeError,
+ "can't convert %"PRIsVALUE" into BigDecimal", rb_obj_class(val));
+ }
+ return Qnil;
+ }
+ return rb_str_convert_to_BigDecimal(str, digs, raise_exception);
+}
+
+/* call-seq:
+ * BigDecimal(value, exception: true) -> bigdecimal
+ * BigDecimal(value, ndigits, exception: true) -> bigdecimal
+ *
+ * Returns the \BigDecimal converted from +value+
+ * with a precision of +ndigits+ decimal digits.
+ *
+ * When +ndigits+ is less than the number of significant digits
+ * in the value, the result is rounded to that number of digits,
+ * according to the current rounding mode; see BigDecimal.mode.
+ *
+ * When +ndigits+ is 0, the number of digits to correctly represent a float number
+ * is determined automatically.
+ *
+ * Returns +value+ converted to a \BigDecimal, depending on the type of +value+:
+ *
+ * - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
+ *
+ * # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given.
+ * BigDecimal(2) # => 0.2e1
+ * BigDecimal(Complex(2, 0)) # => 0.2e1
+ * BigDecimal(BigDecimal(2)) # => 0.2e1
+ * # Float or Rational value requires ndigits.
+ * BigDecimal(2.0, 0) # => 0.2e1
+ * BigDecimal(Rational(2, 1), 0) # => 0.2e1
+ *
+ * - String: converted by parsing if it contains an integer or floating-point literal;
+ * leading and trailing whitespace is ignored:
+ *
+ * # String does not require ndigits; ignored if given.
+ * BigDecimal('2') # => 0.2e1
+ * BigDecimal('2.0') # => 0.2e1
+ * BigDecimal('0.2e1') # => 0.2e1
+ * BigDecimal(' 2.0 ') # => 0.2e1
+ *
+ * - Other type that responds to method <tt>:to_str</tt>:
+ * first converted to a string, then converted to a \BigDecimal, as above.
+ *
+ * - Other type:
+ *
+ * - Raises an exception if keyword argument +exception+ is +true+.
+ * - Returns +nil+ if keyword argument +exception+ is +true+.
+ *
+ * Raises an exception if +value+ evaluates to a Float
+ * and +digits+ is larger than Float::DIG + 1.
+ *
+ */
+static VALUE
+f_BigDecimal(int argc, VALUE *argv, VALUE self)
+{
+ VALUE val, digs_v, opts = Qnil;
+ argc = rb_scan_args(argc, argv, "11:", &val, &digs_v, &opts);
+ int exception = opts_exception_p(opts);
+
+ size_t digs = SIZE_MAX; /* this means digs is omitted */
+ if (argc > 1) {
+ digs_v = rb_to_int(digs_v);
+ if (FIXNUM_P(digs_v)) {
+ long n = FIX2LONG(digs_v);
+ if (n < 0)
+ goto negative_digs;
+ digs = (size_t)n;
+ }
+ else {
+ if (RBIGNUM_NEGATIVE_P(digs_v)) {
+ negative_digs:
+ if (!exception)
+ return Qnil;
+ rb_raise(rb_eArgError, "negative precision");
+ }
+ digs = NUM2SIZET(digs_v);
+ }
+ }
+
+ return rb_convert_to_BigDecimal(val, digs, exception);
+}
+
+static VALUE
+BigDecimal_s_interpret_loosely(VALUE klass, VALUE str)
+{
+ char const *c_str = StringValueCStr(str);
+ Real *vp = VpNewRbClass(0, c_str, klass, false, true);
+ if (!vp)
+ return Qnil;
+ else
+ return VpCheckGetValue(vp);
+}
+
+ /* call-seq:
+ * BigDecimal.limit(digits)
+ *
+ * Limit the number of significant digits in newly created BigDecimal
+ * numbers to the specified value. Rounding is performed as necessary,
+ * as specified by BigDecimal.mode.
+ *
+ * A limit of 0, the default, means no upper limit.
+ *
+ * The limit specified by this method takes less priority over any limit
+ * specified to instance methods such as ceil, floor, truncate, or round.
+ */
+static VALUE
+BigDecimal_limit(int argc, VALUE *argv, VALUE self)
+{
+ VALUE nFig;
+ VALUE nCur = SIZET2NUM(VpGetPrecLimit());
+
+ if (rb_scan_args(argc, argv, "01", &nFig) == 1) {
+ int nf;
+ if (NIL_P(nFig)) return nCur;
+ nf = NUM2INT(nFig);
+ if (nf < 0) {
+ rb_raise(rb_eArgError, "argument must be positive");
+ }
+ VpSetPrecLimit(nf);
+ }
+ return nCur;
+}
+
+/* Returns the sign of the value.
+ *
+ * Returns a positive value if > 0, a negative value if < 0.
+ * It behaves the same with zeros -
+ * it returns a positive value for a positive zero (BigDecimal('0')) and
+ * a negative value for a negative zero (BigDecimal('-0')).
+ *
+ * The specific value returned indicates the type and sign of the BigDecimal,
+ * as follows:
+ *
+ * BigDecimal::SIGN_NaN:: value is Not a Number
+ * BigDecimal::SIGN_POSITIVE_ZERO:: value is +0
+ * BigDecimal::SIGN_NEGATIVE_ZERO:: value is -0
+ * BigDecimal::SIGN_POSITIVE_INFINITE:: value is +Infinity
+ * BigDecimal::SIGN_NEGATIVE_INFINITE:: value is -Infinity
+ * BigDecimal::SIGN_POSITIVE_FINITE:: value is positive
+ * BigDecimal::SIGN_NEGATIVE_FINITE:: value is negative
+ */
+static VALUE
+BigDecimal_sign(VALUE self)
+{ /* sign */
+ int s = GetVpValue(self, 1)->sign;
+ return INT2FIX(s);
+}
+
+/*
+ * call-seq: BigDecimal.save_exception_mode { ... }
+ *
+ * Execute the provided block, but preserve the exception mode
+ *
+ * BigDecimal.save_exception_mode do
+ * BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false)
+ * BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false)
+ *
+ * BigDecimal(BigDecimal('Infinity'))
+ * BigDecimal(BigDecimal('-Infinity'))
+ * BigDecimal(BigDecimal('NaN'))
+ * end
+ *
+ * For use with the BigDecimal::EXCEPTION_*
+ *
+ * See BigDecimal.mode
+ */
+static VALUE
+BigDecimal_save_exception_mode(VALUE self)
+{
+ unsigned short const exception_mode = VpGetException();
+ int state;
+ VALUE ret = rb_protect(rb_yield, Qnil, &state);
+ VpSetException(exception_mode);
+ if (state) rb_jump_tag(state);
+ return ret;
+}
+
+/*
+ * call-seq: BigDecimal.save_rounding_mode { ... }
+ *
+ * Execute the provided block, but preserve the rounding mode
+ *
+ * BigDecimal.save_rounding_mode do
+ * BigDecimal.mode(BigDecimal::ROUND_MODE, :up)
+ * puts BigDecimal.mode(BigDecimal::ROUND_MODE)
+ * end
+ *
+ * For use with the BigDecimal::ROUND_*
+ *
+ * See BigDecimal.mode
+ */
+static VALUE
+BigDecimal_save_rounding_mode(VALUE self)
+{
+ unsigned short const round_mode = VpGetRoundMode();
+ int state;
+ VALUE ret = rb_protect(rb_yield, Qnil, &state);
+ VpSetRoundMode(round_mode);
+ if (state) rb_jump_tag(state);
+ return ret;
+}
+
+/*
+ * call-seq: BigDecimal.save_limit { ... }
+ *
+ * Execute the provided block, but preserve the precision limit
+ *
+ * BigDecimal.limit(100)
+ * puts BigDecimal.limit
+ * BigDecimal.save_limit do
+ * BigDecimal.limit(200)
+ * puts BigDecimal.limit
+ * end
+ * puts BigDecimal.limit
+ *
+ */
+static VALUE
+BigDecimal_save_limit(VALUE self)
+{
+ size_t const limit = VpGetPrecLimit();
+ int state;
+ VALUE ret = rb_protect(rb_yield, Qnil, &state);
+ VpSetPrecLimit(limit);
+ if (state) rb_jump_tag(state);
+ return ret;
+}
+
+/* call-seq:
+ * BigMath.exp(decimal, numeric) -> BigDecimal
+ *
+ * Computes the value of e (the base of natural logarithms) raised to the
+ * power of +decimal+, to the specified number of digits of precision.
+ *
+ * If +decimal+ is infinity, returns Infinity.
+ *
+ * If +decimal+ is NaN, returns NaN.
+ */
+static VALUE
+BigMath_s_exp(VALUE klass, VALUE x, VALUE vprec)
+{
+ ssize_t prec, n, i;
+ Real* vx = NULL;
+ VALUE one, d, y;
+ int negative = 0;
+ int infinite = 0;
+ int nan = 0;
+ double flo;
+
+ prec = NUM2SSIZET(vprec);
+ if (prec <= 0) {
+ rb_raise(rb_eArgError, "Zero or negative precision for exp");
+ }
+
+ /* TODO: the following switch statement is almost same as one in the
+ * BigDecimalCmp function. */
+ switch (TYPE(x)) {
+ case T_DATA:
+ if (!is_kind_of_BigDecimal(x)) break;
+ vx = DATA_PTR(x);
+ negative = BIGDECIMAL_NEGATIVE_P(vx);
+ infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
+ nan = VpIsNaN(vx);
+ break;
+
+ case T_FIXNUM:
+ /* fall through */
+ case T_BIGNUM:
+ vx = GetVpValue(x, 0);
+ break;
+
+ case T_FLOAT:
+ flo = RFLOAT_VALUE(x);
+ negative = flo < 0;
+ infinite = isinf(flo);
+ nan = isnan(flo);
+ if (!infinite && !nan) {
+ vx = GetVpValueWithPrec(x, 0, 0);
+ }
+ break;
+
+ case T_RATIONAL:
+ vx = GetVpValueWithPrec(x, prec, 0);
+ break;
+
+ default:
+ break;
+ }
+ if (infinite) {
+ if (negative) {
+ return VpCheckGetValue(GetVpValueWithPrec(INT2FIX(0), prec, 1));
+ }
+ else {
+ Real* vy = NewZeroWrapNolimit(1, prec);
+ VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
+ RB_GC_GUARD(vy->obj);
+ return VpCheckGetValue(vy);
+ }
+ }
+ else if (nan) {
+ Real* vy = NewZeroWrapNolimit(1, prec);
+ VpSetNaN(vy);
+ RB_GC_GUARD(vy->obj);
+ return VpCheckGetValue(vy);
+ }
+ else if (vx == NULL) {
+ cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
+ }
+ x = vx->obj;
+
+ n = prec + BIGDECIMAL_DOUBLE_FIGURES;
+ negative = BIGDECIMAL_NEGATIVE_P(vx);
+ if (negative) {
+ VALUE x_zero = INT2NUM(1);
+ VALUE x_copy = f_BigDecimal(1, &x_zero, klass);
+ x = BigDecimal_initialize_copy(x_copy, x);
+ vx = DATA_PTR(x);
+ VpSetSign(vx, 1);
+ }
+
+ one = VpCheckGetValue(NewOneWrapLimited(1, 1));
+ y = one;
+ d = y;
+ i = 1;
+
+ while (!VpIsZero((Real*)DATA_PTR(d))) {
+ SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
+ SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
+ ssize_t m = n - vabs(ey - ed);
+
+ rb_thread_check_ints();
+
+ if (m <= 0) {
+ break;
+ }
+ else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
+ m = BIGDECIMAL_DOUBLE_FIGURES;
+ }
+
+ d = BigDecimal_mult(d, x); /* d <- d * x */
+ d = BigDecimal_div2(d, SSIZET2NUM(i), SSIZET2NUM(m)); /* d <- d / i */
+ y = BigDecimal_add(y, d); /* y <- y + d */
+ ++i; /* i <- i + 1 */
+ }
+
+ if (negative) {
+ return BigDecimal_div2(one, y, vprec);
+ }
+ else {
+ vprec = SSIZET2NUM(prec - VpExponent10(DATA_PTR(y)));
+ return BigDecimal_round(1, &vprec, y);
+ }
+
+ RB_GC_GUARD(one);
+ RB_GC_GUARD(x);
+ RB_GC_GUARD(y);
+ RB_GC_GUARD(d);
+}
+
+/* call-seq:
+ * BigMath.log(decimal, numeric) -> BigDecimal
+ *
+ * Computes the natural logarithm of +decimal+ to the specified number of
+ * digits of precision, +numeric+.
+ *
+ * If +decimal+ is zero or negative, raises Math::DomainError.
+ *
+ * If +decimal+ is positive infinity, returns Infinity.
+ *
+ * If +decimal+ is NaN, returns NaN.
+ */
+static VALUE
+BigMath_s_log(VALUE klass, VALUE x, VALUE vprec)
+{
+ ssize_t prec, n, i;
+ SIGNED_VALUE expo;
+ Real* vx = NULL;
+ VALUE vn, one, two, w, x2, y, d;
+ int zero = 0;
+ int negative = 0;
+ int infinite = 0;
+ int nan = 0;
+ double flo;
+ long fix;
+
+ if (!is_integer(vprec)) {
+ rb_raise(rb_eArgError, "precision must be an Integer");
+ }
+
+ prec = NUM2SSIZET(vprec);
+ if (prec <= 0) {
+ rb_raise(rb_eArgError, "Zero or negative precision for exp");
+ }
+
+ /* TODO: the following switch statement is almost same as one in the
+ * BigDecimalCmp function. */
+ switch (TYPE(x)) {
+ case T_DATA:
+ if (!is_kind_of_BigDecimal(x)) break;
+ vx = DATA_PTR(x);
+ zero = VpIsZero(vx);
+ negative = BIGDECIMAL_NEGATIVE_P(vx);
+ infinite = VpIsPosInf(vx) || VpIsNegInf(vx);
+ nan = VpIsNaN(vx);
+ break;
+
+ case T_FIXNUM:
+ fix = FIX2LONG(x);
+ zero = fix == 0;
+ negative = fix < 0;
+ goto get_vp_value;
+
+ case T_BIGNUM:
+ i = FIX2INT(rb_big_cmp(x, INT2FIX(0)));
+ zero = i == 0;
+ negative = i < 0;
+get_vp_value:
+ if (zero || negative) break;
+ vx = GetVpValue(x, 0);
+ break;
+
+ case T_FLOAT:
+ flo = RFLOAT_VALUE(x);
+ zero = flo == 0;
+ negative = flo < 0;
+ infinite = isinf(flo);
+ nan = isnan(flo);
+ if (!zero && !negative && !infinite && !nan) {
+ vx = GetVpValueWithPrec(x, 0, 1);
+ }
+ break;
+
+ case T_RATIONAL:
+ zero = RRATIONAL_ZERO_P(x);
+ negative = RRATIONAL_NEGATIVE_P(x);
+ if (zero || negative) break;
+ vx = GetVpValueWithPrec(x, prec, 1);
+ break;
+
+ case T_COMPLEX:
+ rb_raise(rb_eMathDomainError,
+ "Complex argument for BigMath.log");
+
+ default:
+ break;
+ }
+ if (infinite && !negative) {
+ Real *vy = NewZeroWrapNolimit(1, prec);
+ RB_GC_GUARD(vy->obj);
+ VpSetInf(vy, VP_SIGN_POSITIVE_INFINITE);
+ return VpCheckGetValue(vy);
+ }
+ else if (nan) {
+ Real* vy = NewZeroWrapNolimit(1, prec);
+ RB_GC_GUARD(vy->obj);
+ VpSetNaN(vy);
+ return VpCheckGetValue(vy);
+ }
+ else if (zero || negative) {
+ rb_raise(rb_eMathDomainError,
+ "Zero or negative argument for log");
+ }
+ else if (vx == NULL) {
+ cannot_be_coerced_into_BigDecimal(rb_eArgError, x);
+ }
+ x = VpCheckGetValue(vx);
+
+ RB_GC_GUARD(one) = VpCheckGetValue(NewOneWrapLimited(1, 1));
+ RB_GC_GUARD(two) = VpCheckGetValue(VpCreateRbObject(1, "2", true));
+
+ n = prec + BIGDECIMAL_DOUBLE_FIGURES;
+ RB_GC_GUARD(vn) = SSIZET2NUM(n);
+ expo = VpExponent10(vx);
+ if (expo < 0 || expo >= 3) {
+ char buf[DECIMAL_SIZE_OF_BITS(SIZEOF_VALUE * CHAR_BIT) + 4];
+ snprintf(buf, sizeof(buf), "1E%"PRIdVALUE, -expo);
+ x = BigDecimal_mult2(x, VpCheckGetValue(VpCreateRbObject(1, buf, true)), vn);
+ }
+ else {
+ expo = 0;
+ }
+ w = BigDecimal_sub(x, one);
+ x = BigDecimal_div2(w, BigDecimal_add(x, one), vn);
+ RB_GC_GUARD(x2) = BigDecimal_mult2(x, x, vn);
+ RB_GC_GUARD(y) = x;
+ RB_GC_GUARD(d) = y;
+ i = 1;
+ while (!VpIsZero((Real*)DATA_PTR(d))) {
+ SIGNED_VALUE const ey = VpExponent10(DATA_PTR(y));
+ SIGNED_VALUE const ed = VpExponent10(DATA_PTR(d));
+ ssize_t m = n - vabs(ey - ed);
+ if (m <= 0) {
+ break;
+ }
+ else if ((size_t)m < BIGDECIMAL_DOUBLE_FIGURES) {
+ m = BIGDECIMAL_DOUBLE_FIGURES;
+ }
+
+ x = BigDecimal_mult2(x2, x, vn);
+ i += 2;
+ d = BigDecimal_div2(x, SSIZET2NUM(i), SSIZET2NUM(m));
+ y = BigDecimal_add(y, d);
+ }
+
+ y = BigDecimal_mult(y, two);
+ if (expo != 0) {
+ VALUE log10, vexpo, dy;
+ log10 = BigMath_s_log(klass, INT2FIX(10), vprec);
+ vexpo = VpCheckGetValue(GetVpValue(SSIZET2NUM(expo), 1));
+ dy = BigDecimal_mult(log10, vexpo);
+ y = BigDecimal_add(y, dy);
+ }
+
+ return y;
+}
+
+static VALUE BIGDECIMAL_NAN = Qnil;
+
+static VALUE
+BigDecimal_nan(void)
+{
+ return BIGDECIMAL_NAN;
+}
+
+static VALUE BIGDECIMAL_POSITIVE_INFINITY = Qnil;
+
+static VALUE
+BigDecimal_positive_infinity(void)
+{
+ return BIGDECIMAL_POSITIVE_INFINITY;
+}
+
+static VALUE BIGDECIMAL_NEGATIVE_INFINITY = Qnil;
+
+static VALUE
+BigDecimal_negative_infinity(void)
+{
+ return BIGDECIMAL_NEGATIVE_INFINITY;
+}
+
+static VALUE BIGDECIMAL_POSITIVE_ZERO = Qnil;
+
+static VALUE
+BigDecimal_positive_zero(void)
+{
+ return BIGDECIMAL_POSITIVE_ZERO;
+}
+
+static VALUE BIGDECIMAL_NEGATIVE_ZERO = Qnil;
+
+static VALUE
+BigDecimal_negative_zero(void)
+{
+ return BIGDECIMAL_NEGATIVE_ZERO;
+}
+
+/* Document-class: BigDecimal
+ * BigDecimal provides arbitrary-precision floating point decimal arithmetic.
+ *
+ * == Introduction
+ *
+ * Ruby provides built-in support for arbitrary precision integer arithmetic.
+ *
+ * For example:
+ *
+ * 42**13 #=> 1265437718438866624512
+ *
+ * BigDecimal provides similar support for very large or very accurate floating
+ * point numbers.
+ *
+ * Decimal arithmetic is also useful for general calculation, because it
+ * provides the correct answers people expect--whereas normal binary floating
+ * point arithmetic often introduces subtle errors because of the conversion
+ * between base 10 and base 2.
+ *
+ * For example, try:
+ *
+ * sum = 0
+ * 10_000.times do
+ * sum = sum + 0.0001
+ * end
+ * print sum #=> 0.9999999999999062
+ *
+ * and contrast with the output from:
+ *
+ * require 'bigdecimal'
+ *
+ * sum = BigDecimal("0")
+ * 10_000.times do
+ * sum = sum + BigDecimal("0.0001")
+ * end
+ * print sum #=> 0.1E1
+ *
+ * Similarly:
+ *
+ * (BigDecimal("1.2") - BigDecimal("1.0")) == BigDecimal("0.2") #=> true
+ *
+ * (1.2 - 1.0) == 0.2 #=> false
+ *
+ * == A Note About Precision
+ *
+ * For a calculation using a \BigDecimal and another +value+,
+ * the precision of the result depends on the type of +value+:
+ *
+ * - If +value+ is a \Float,
+ * the precision is Float::DIG + 1.
+ * - If +value+ is a \Rational, the precision is larger than Float::DIG + 1.
+ * - If +value+ is a \BigDecimal, the precision is +value+'s precision in the
+ * internal representation, which is platform-dependent.
+ * - If +value+ is other object, the precision is determined by the result of +BigDecimal(value)+.
+ *
+ * == Special features of accurate decimal arithmetic
+ *
+ * Because BigDecimal is more accurate than normal binary floating point
+ * arithmetic, it requires some special values.
+ *
+ * === Infinity
+ *
+ * BigDecimal sometimes needs to return infinity, for example if you divide
+ * a value by zero.
+ *
+ * BigDecimal("1.0") / BigDecimal("0.0") #=> Infinity
+ * BigDecimal("-1.0") / BigDecimal("0.0") #=> -Infinity
+ *
+ * You can represent infinite numbers to BigDecimal using the strings
+ * <code>'Infinity'</code>, <code>'+Infinity'</code> and
+ * <code>'-Infinity'</code> (case-sensitive)
+ *
+ * === Not a Number
+ *
+ * When a computation results in an undefined value, the special value +NaN+
+ * (for 'not a number') is returned.
+ *
+ * Example:
+ *
+ * BigDecimal("0.0") / BigDecimal("0.0") #=> NaN
+ *
+ * You can also create undefined values.
+ *
+ * NaN is never considered to be the same as any other value, even NaN itself:
+ *
+ * n = BigDecimal('NaN')
+ * n == 0.0 #=> false
+ * n == n #=> false
+ *
+ * === Positive and negative zero
+ *
+ * If a computation results in a value which is too small to be represented as
+ * a BigDecimal within the currently specified limits of precision, zero must
+ * be returned.
+ *
+ * If the value which is too small to be represented is negative, a BigDecimal
+ * value of negative zero is returned.
+ *
+ * BigDecimal("1.0") / BigDecimal("-Infinity") #=> -0.0
+ *
+ * If the value is positive, a value of positive zero is returned.
+ *
+ * BigDecimal("1.0") / BigDecimal("Infinity") #=> 0.0
+ *
+ * (See BigDecimal.mode for how to specify limits of precision.)
+ *
+ * Note that +-0.0+ and +0.0+ are considered to be the same for the purposes of
+ * comparison.
+ *
+ * Note also that in mathematics, there is no particular concept of negative
+ * or positive zero; true mathematical zero has no sign.
+ *
+ * == bigdecimal/util
+ *
+ * When you require +bigdecimal/util+, the #to_d method will be
+ * available on BigDecimal and the native Integer, Float, Rational,
+ * and String classes:
+ *
+ * require 'bigdecimal/util'
+ *
+ * 42.to_d # => 0.42e2
+ * 0.5.to_d # => 0.5e0
+ * (2/3r).to_d(3) # => 0.667e0
+ * "0.5".to_d # => 0.5e0
+ *
+ * == License
+ *
+ * Copyright (C) 2002 by Shigeo Kobayashi <shigeo@tinyforest.gr.jp>.
+ *
+ * BigDecimal is released under the Ruby and 2-clause BSD licenses.
+ * See LICENSE.txt for details.
+ *
+ * Maintained by mrkn <mrkn@mrkn.jp> and ruby-core members.
+ *
+ * Documented by zzak <zachary@zacharyscott.net>, mathew <meta@pobox.com>, and
+ * many other contributors.
+ */
+void
+Init_bigdecimal(void)
+{
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+ rb_ext_ractor_safe(true);
+#endif
+ VALUE arg;
+
+ id_BigDecimal_exception_mode = rb_intern_const("BigDecimal.exception_mode");
+ id_BigDecimal_rounding_mode = rb_intern_const("BigDecimal.rounding_mode");
+ id_BigDecimal_precision_limit = rb_intern_const("BigDecimal.precision_limit");
+
+ /* Initialize VP routines */
+ VpInit(0UL);
+
+ /* Class and method registration */
+ rb_cBigDecimal = rb_define_class("BigDecimal", rb_cNumeric);
+
+ /* Global function */
+ rb_define_global_function("BigDecimal", f_BigDecimal, -1);
+
+ /* Class methods */
+ rb_undef_alloc_func(rb_cBigDecimal);
+ rb_undef_method(CLASS_OF(rb_cBigDecimal), "new");
+ rb_define_singleton_method(rb_cBigDecimal, "interpret_loosely", BigDecimal_s_interpret_loosely, 1);
+ rb_define_singleton_method(rb_cBigDecimal, "mode", BigDecimal_mode, -1);
+ rb_define_singleton_method(rb_cBigDecimal, "limit", BigDecimal_limit, -1);
+ rb_define_singleton_method(rb_cBigDecimal, "double_fig", BigDecimal_double_fig, 0);
+ rb_define_singleton_method(rb_cBigDecimal, "_load", BigDecimal_load, 1);
+
+ rb_define_singleton_method(rb_cBigDecimal, "save_exception_mode", BigDecimal_save_exception_mode, 0);
+ rb_define_singleton_method(rb_cBigDecimal, "save_rounding_mode", BigDecimal_save_rounding_mode, 0);
+ rb_define_singleton_method(rb_cBigDecimal, "save_limit", BigDecimal_save_limit, 0);
+
+ /* Constants definition */
+
+#ifndef RUBY_BIGDECIMAL_VERSION
+# error RUBY_BIGDECIMAL_VERSION is not defined
+#endif
+ /*
+ * The version of bigdecimal library
+ */
+ rb_define_const(rb_cBigDecimal, "VERSION", rb_str_new2(RUBY_BIGDECIMAL_VERSION));
+
+ /*
+ * Base value used in internal calculations. On a 32 bit system, BASE
+ * is 10000, indicating that calculation is done in groups of 4 digits.
+ * (If it were larger, BASE**2 wouldn't fit in 32 bits, so you couldn't
+ * guarantee that two groups could always be multiplied together without
+ * overflow.)
+ */
+ rb_define_const(rb_cBigDecimal, "BASE", INT2FIX((SIGNED_VALUE)VpBaseVal()));
+
+ /* Exceptions */
+
+ /*
+ * 0xff: Determines whether overflow, underflow or zero divide result in
+ * an exception being thrown. See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "EXCEPTION_ALL", INT2FIX(VP_EXCEPTION_ALL));
+
+ /*
+ * 0x02: Determines what happens when the result of a computation is not a
+ * number (NaN). See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "EXCEPTION_NaN", INT2FIX(VP_EXCEPTION_NaN));
+
+ /*
+ * 0x01: Determines what happens when the result of a computation is
+ * infinity. See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "EXCEPTION_INFINITY", INT2FIX(VP_EXCEPTION_INFINITY));
+
+ /*
+ * 0x04: Determines what happens when the result of a computation is an
+ * underflow (a result too small to be represented). See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "EXCEPTION_UNDERFLOW", INT2FIX(VP_EXCEPTION_UNDERFLOW));
+
+ /*
+ * 0x01: Determines what happens when the result of a computation is an
+ * overflow (a result too large to be represented). See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "EXCEPTION_OVERFLOW", INT2FIX(VP_EXCEPTION_OVERFLOW));
+
+ /*
+ * 0x10: Determines what happens when a division by zero is performed.
+ * See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "EXCEPTION_ZERODIVIDE", INT2FIX(VP_EXCEPTION_ZERODIVIDE));
+
+ /*
+ * 0x100: Determines what happens when a result must be rounded in order to
+ * fit in the appropriate number of significant digits. See
+ * BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "ROUND_MODE", INT2FIX(VP_ROUND_MODE));
+
+ /* 1: Indicates that values should be rounded away from zero. See
+ * BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "ROUND_UP", INT2FIX(VP_ROUND_UP));
+
+ /* 2: Indicates that values should be rounded towards zero. See
+ * BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "ROUND_DOWN", INT2FIX(VP_ROUND_DOWN));
+
+ /* 3: Indicates that digits >= 5 should be rounded up, others rounded down.
+ * See BigDecimal.mode. */
+ rb_define_const(rb_cBigDecimal, "ROUND_HALF_UP", INT2FIX(VP_ROUND_HALF_UP));
+
+ /* 4: Indicates that digits >= 6 should be rounded up, others rounded down.
+ * See BigDecimal.mode.
+ */
+ rb_define_const(rb_cBigDecimal, "ROUND_HALF_DOWN", INT2FIX(VP_ROUND_HALF_DOWN));
+ /* 5: Round towards +Infinity. See BigDecimal.mode. */
+ rb_define_const(rb_cBigDecimal, "ROUND_CEILING", INT2FIX(VP_ROUND_CEIL));
+
+ /* 6: Round towards -Infinity. See BigDecimal.mode. */
+ rb_define_const(rb_cBigDecimal, "ROUND_FLOOR", INT2FIX(VP_ROUND_FLOOR));
+
+ /* 7: Round towards the even neighbor. See BigDecimal.mode. */
+ rb_define_const(rb_cBigDecimal, "ROUND_HALF_EVEN", INT2FIX(VP_ROUND_HALF_EVEN));
+
+ /* 0: Indicates that a value is not a number. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_NaN", INT2FIX(VP_SIGN_NaN));
+
+ /* 1: Indicates that a value is +0. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_ZERO", INT2FIX(VP_SIGN_POSITIVE_ZERO));
+
+ /* -1: Indicates that a value is -0. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_ZERO", INT2FIX(VP_SIGN_NEGATIVE_ZERO));
+
+ /* 2: Indicates that a value is positive and finite. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_FINITE", INT2FIX(VP_SIGN_POSITIVE_FINITE));
+
+ /* -2: Indicates that a value is negative and finite. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_FINITE", INT2FIX(VP_SIGN_NEGATIVE_FINITE));
+
+ /* 3: Indicates that a value is positive and infinite. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_POSITIVE_INFINITE", INT2FIX(VP_SIGN_POSITIVE_INFINITE));
+
+ /* -3: Indicates that a value is negative and infinite. See BigDecimal.sign. */
+ rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_INFINITE", INT2FIX(VP_SIGN_NEGATIVE_INFINITE));
+
+ /* Positive zero value. */
+ arg = rb_str_new2("+0");
+ BIGDECIMAL_POSITIVE_ZERO = f_BigDecimal(1, &arg, rb_cBigDecimal);
+ rb_gc_register_mark_object(BIGDECIMAL_POSITIVE_ZERO);
+
+ /* Negative zero value. */
+ arg = rb_str_new2("-0");
+ BIGDECIMAL_NEGATIVE_ZERO = f_BigDecimal(1, &arg, rb_cBigDecimal);
+ rb_gc_register_mark_object(BIGDECIMAL_NEGATIVE_ZERO);
+
+ /* Positive infinity value. */
+ arg = rb_str_new2("+Infinity");
+ BIGDECIMAL_POSITIVE_INFINITY = f_BigDecimal(1, &arg, rb_cBigDecimal);
+ rb_gc_register_mark_object(BIGDECIMAL_POSITIVE_INFINITY);
+
+ /* Negative infinity value. */
+ arg = rb_str_new2("-Infinity");
+ BIGDECIMAL_NEGATIVE_INFINITY = f_BigDecimal(1, &arg, rb_cBigDecimal);
+ rb_gc_register_mark_object(BIGDECIMAL_NEGATIVE_INFINITY);
+
+ /* 'Not a Number' value. */
+ arg = rb_str_new2("NaN");
+ BIGDECIMAL_NAN = f_BigDecimal(1, &arg, rb_cBigDecimal);
+ rb_gc_register_mark_object(BIGDECIMAL_NAN);
+
+ /* Special value constants */
+ rb_define_const(rb_cBigDecimal, "INFINITY", BIGDECIMAL_POSITIVE_INFINITY);
+ rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_NAN);
+
+ /* instance methods */
+ rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
+ rb_define_method(rb_cBigDecimal, "precision", BigDecimal_precision, 0);
+ rb_define_method(rb_cBigDecimal, "scale", BigDecimal_scale, 0);
+ rb_define_method(rb_cBigDecimal, "precision_scale", BigDecimal_precision_scale, 0);
+ rb_define_method(rb_cBigDecimal, "n_significant_digits", BigDecimal_n_significant_digits, 0);
+
+ rb_define_method(rb_cBigDecimal, "add", BigDecimal_add2, 2);
+ rb_define_method(rb_cBigDecimal, "sub", BigDecimal_sub2, 2);
+ rb_define_method(rb_cBigDecimal, "mult", BigDecimal_mult2, 2);
+ rb_define_method(rb_cBigDecimal, "div", BigDecimal_div3, -1);
+ rb_define_method(rb_cBigDecimal, "hash", BigDecimal_hash, 0);
+ rb_define_method(rb_cBigDecimal, "to_s", BigDecimal_to_s, -1);
+ rb_define_method(rb_cBigDecimal, "to_i", BigDecimal_to_i, 0);
+ rb_define_method(rb_cBigDecimal, "to_int", BigDecimal_to_i, 0);
+ rb_define_method(rb_cBigDecimal, "to_r", BigDecimal_to_r, 0);
+ rb_define_method(rb_cBigDecimal, "split", BigDecimal_split, 0);
+ rb_define_method(rb_cBigDecimal, "+", BigDecimal_add, 1);
+ rb_define_method(rb_cBigDecimal, "-", BigDecimal_sub, 1);
+ rb_define_method(rb_cBigDecimal, "+@", BigDecimal_uplus, 0);
+ rb_define_method(rb_cBigDecimal, "-@", BigDecimal_neg, 0);
+ rb_define_method(rb_cBigDecimal, "*", BigDecimal_mult, 1);
+ rb_define_method(rb_cBigDecimal, "/", BigDecimal_div, 1);
+ rb_define_method(rb_cBigDecimal, "quo", BigDecimal_quo, -1);
+ rb_define_method(rb_cBigDecimal, "%", BigDecimal_mod, 1);
+ rb_define_method(rb_cBigDecimal, "modulo", BigDecimal_mod, 1);
+ rb_define_method(rb_cBigDecimal, "remainder", BigDecimal_remainder, 1);
+ rb_define_method(rb_cBigDecimal, "divmod", BigDecimal_divmod, 1);
+ rb_define_method(rb_cBigDecimal, "clone", BigDecimal_clone, 0);
+ rb_define_method(rb_cBigDecimal, "dup", BigDecimal_clone, 0);
+ rb_define_method(rb_cBigDecimal, "to_f", BigDecimal_to_f, 0);
+ rb_define_method(rb_cBigDecimal, "abs", BigDecimal_abs, 0);
+ rb_define_method(rb_cBigDecimal, "sqrt", BigDecimal_sqrt, 1);
+ rb_define_method(rb_cBigDecimal, "fix", BigDecimal_fix, 0);
+ rb_define_method(rb_cBigDecimal, "round", BigDecimal_round, -1);
+ rb_define_method(rb_cBigDecimal, "frac", BigDecimal_frac, 0);
+ rb_define_method(rb_cBigDecimal, "floor", BigDecimal_floor, -1);
+ rb_define_method(rb_cBigDecimal, "ceil", BigDecimal_ceil, -1);
+ rb_define_method(rb_cBigDecimal, "power", BigDecimal_power, -1);
+ rb_define_method(rb_cBigDecimal, "**", BigDecimal_power_op, 1);
+ rb_define_method(rb_cBigDecimal, "<=>", BigDecimal_comp, 1);
+ rb_define_method(rb_cBigDecimal, "==", BigDecimal_eq, 1);
+ rb_define_method(rb_cBigDecimal, "===", BigDecimal_eq, 1);
+ rb_define_method(rb_cBigDecimal, "eql?", BigDecimal_eq, 1);
+ rb_define_method(rb_cBigDecimal, "<", BigDecimal_lt, 1);
+ rb_define_method(rb_cBigDecimal, "<=", BigDecimal_le, 1);
+ rb_define_method(rb_cBigDecimal, ">", BigDecimal_gt, 1);
+ rb_define_method(rb_cBigDecimal, ">=", BigDecimal_ge, 1);
+ rb_define_method(rb_cBigDecimal, "zero?", BigDecimal_zero, 0);
+ rb_define_method(rb_cBigDecimal, "nonzero?", BigDecimal_nonzero, 0);
+ rb_define_method(rb_cBigDecimal, "coerce", BigDecimal_coerce, 1);
+ rb_define_method(rb_cBigDecimal, "inspect", BigDecimal_inspect, 0);
+ rb_define_method(rb_cBigDecimal, "exponent", BigDecimal_exponent, 0);
+ rb_define_method(rb_cBigDecimal, "sign", BigDecimal_sign, 0);
+ rb_define_method(rb_cBigDecimal, "nan?", BigDecimal_IsNaN, 0);
+ rb_define_method(rb_cBigDecimal, "infinite?", BigDecimal_IsInfinite, 0);
+ rb_define_method(rb_cBigDecimal, "finite?", BigDecimal_IsFinite, 0);
+ rb_define_method(rb_cBigDecimal, "truncate", BigDecimal_truncate, -1);
+ rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
+
+ rb_mBigMath = rb_define_module("BigMath");
+ rb_define_singleton_method(rb_mBigMath, "exp", BigMath_s_exp, 2);
+ rb_define_singleton_method(rb_mBigMath, "log", BigMath_s_log, 2);
+
+#define ROUNDING_MODE(i, name, value) \
+ id_##name = rb_intern_const(#name); \
+ rbd_rounding_modes[i].id = id_##name; \
+ rbd_rounding_modes[i].mode = value;
+
+ ROUNDING_MODE(0, up, RBD_ROUND_UP);
+ ROUNDING_MODE(1, down, RBD_ROUND_DOWN);
+ ROUNDING_MODE(2, half_up, RBD_ROUND_HALF_UP);
+ ROUNDING_MODE(3, half_down, RBD_ROUND_HALF_DOWN);
+ ROUNDING_MODE(4, ceil, RBD_ROUND_CEIL);
+ ROUNDING_MODE(5, floor, RBD_ROUND_FLOOR);
+ ROUNDING_MODE(6, half_even, RBD_ROUND_HALF_EVEN);
+
+ ROUNDING_MODE(7, default, RBD_ROUND_DEFAULT);
+ ROUNDING_MODE(8, truncate, RBD_ROUND_TRUNCATE);
+ ROUNDING_MODE(9, banker, RBD_ROUND_BANKER);
+ ROUNDING_MODE(10, ceiling, RBD_ROUND_CEILING);
+
+#undef ROUNDING_MODE
+
+ id_to_r = rb_intern_const("to_r");
+ id_eq = rb_intern_const("==");
+ id_half = rb_intern_const("half");
+
+ (void)VPrint; /* suppress unused warning */
+}
+
+/*
+ *
+ * ============================================================================
+ *
+ * vp_ routines begin from here.
+ *
+ * ============================================================================
+ *
+ */
+#ifdef BIGDECIMAL_DEBUG
+static int gfDebug = 1; /* Debug switch */
+#if 0
+static int gfCheckVal = 1; /* Value checking flag in VpNmlz() */
+#endif
+#endif /* BIGDECIMAL_DEBUG */
+
+static Real *VpConstOne; /* constant 1.0 */
+static Real *VpConstPt5; /* constant 0.5 */
+#define maxnr 100UL /* Maximum iterations for calculating sqrt. */
+ /* used in VpSqrt() */
+
+/* ETC */
+#define MemCmp(x,y,z) memcmp(x,y,z)
+#define StrCmp(x,y) strcmp(x,y)
+
+enum op_sw {
+ OP_SW_ADD = 1, /* + */
+ OP_SW_SUB, /* - */
+ OP_SW_MULT, /* * */
+ OP_SW_DIV /* / */
+};
+
+static int VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw);
+static int AddExponent(Real *a, SIGNED_VALUE n);
+static DECDIG VpAddAbs(Real *a,Real *b,Real *c);
+static DECDIG VpSubAbs(Real *a,Real *b,Real *c);
+static size_t VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, DECDIG *av, DECDIG *bv);
+static int VpNmlz(Real *a);
+static void VpFormatSt(char *psz, size_t fFmt);
+static int VpRdup(Real *m, size_t ind_m);
+
+#ifdef BIGDECIMAL_DEBUG
+# ifdef HAVE_RB_EXT_RACTOR_SAFE
+# error Need to make rewiting gnAlloc atomic
+# endif
+static int gnAlloc = 0; /* Memory allocation counter */
+#endif /* BIGDECIMAL_DEBUG */
+
+/*
+ * EXCEPTION Handling.
+ */
+
+#define bigdecimal_set_thread_local_exception_mode(mode) \
+ rb_thread_local_aset( \
+ rb_thread_current(), \
+ id_BigDecimal_exception_mode, \
+ INT2FIX((int)(mode)) \
+ )
+
+static unsigned short
+VpGetException (void)
+{
+ VALUE const vmode = rb_thread_local_aref(
+ rb_thread_current(),
+ id_BigDecimal_exception_mode
+ );
+
+ if (NIL_P(vmode)) {
+ bigdecimal_set_thread_local_exception_mode(BIGDECIMAL_EXCEPTION_MODE_DEFAULT);
+ return BIGDECIMAL_EXCEPTION_MODE_DEFAULT;
+ }
+
+ return NUM2USHORT(vmode);
+}
+
+static void
+VpSetException(unsigned short f)
+{
+ bigdecimal_set_thread_local_exception_mode(f);
+}
+
+static void
+VpCheckException(Real *p, bool always)
+{
+ if (VpIsNaN(p)) {
+ VpException(VP_EXCEPTION_NaN, "Computation results in 'NaN' (Not a Number)", always);
+ }
+ else if (VpIsPosInf(p)) {
+ VpException(VP_EXCEPTION_INFINITY, "Computation results in 'Infinity'", always);
+ }
+ else if (VpIsNegInf(p)) {
+ VpException(VP_EXCEPTION_INFINITY, "Computation results in '-Infinity'", always);
+ }
+}
+
+static VALUE
+VpCheckGetValue(Real *p)
+{
+ VpCheckException(p, false);
+ return p->obj;
+}
+
+/*
+ * Precision limit.
+ */
+
+#define bigdecimal_set_thread_local_precision_limit(limit) \
+ rb_thread_local_aset( \
+ rb_thread_current(), \
+ id_BigDecimal_precision_limit, \
+ SIZET2NUM(limit) \
+ )
+#define BIGDECIMAL_PRECISION_LIMIT_DEFAULT ((size_t)0)
+
+/* These 2 functions added at v1.1.7 */
+VP_EXPORT size_t
+VpGetPrecLimit(void)
+{
+ VALUE const vlimit = rb_thread_local_aref(
+ rb_thread_current(),
+ id_BigDecimal_precision_limit
+ );
+
+ if (NIL_P(vlimit)) {
+ bigdecimal_set_thread_local_precision_limit(BIGDECIMAL_PRECISION_LIMIT_DEFAULT);
+ return BIGDECIMAL_PRECISION_LIMIT_DEFAULT;
+ }
+
+ return NUM2SIZET(vlimit);
+}
+
+VP_EXPORT size_t
+VpSetPrecLimit(size_t n)
+{
+ size_t const s = VpGetPrecLimit();
+ bigdecimal_set_thread_local_precision_limit(n);
+ return s;
+}
+
+/*
+ * Rounding mode.
+ */
+
+#define bigdecimal_set_thread_local_rounding_mode(mode) \
+ rb_thread_local_aset( \
+ rb_thread_current(), \
+ id_BigDecimal_rounding_mode, \
+ INT2FIX((int)(mode)) \
+ )
+
+VP_EXPORT unsigned short
+VpGetRoundMode(void)
+{
+ VALUE const vmode = rb_thread_local_aref(
+ rb_thread_current(),
+ id_BigDecimal_rounding_mode
+ );
+
+ if (NIL_P(vmode)) {
+ bigdecimal_set_thread_local_rounding_mode(BIGDECIMAL_ROUNDING_MODE_DEFAULT);
+ return BIGDECIMAL_ROUNDING_MODE_DEFAULT;
+ }
+
+ return NUM2USHORT(vmode);
+}
+
+VP_EXPORT int
+VpIsRoundMode(unsigned short n)
+{
+ switch (n) {
+ case VP_ROUND_UP:
+ case VP_ROUND_DOWN:
+ case VP_ROUND_HALF_UP:
+ case VP_ROUND_HALF_DOWN:
+ case VP_ROUND_CEIL:
+ case VP_ROUND_FLOOR:
+ case VP_ROUND_HALF_EVEN:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+VP_EXPORT unsigned short
+VpSetRoundMode(unsigned short n)
+{
+ if (VpIsRoundMode(n)) {
+ bigdecimal_set_thread_local_rounding_mode(n);
+ return n;
+ }
+
+ return VpGetRoundMode();
+}
+
+/*
+ * 0.0 & 1.0 generator
+ * These gZero_..... and gOne_..... can be any name
+ * referenced from nowhere except Zero() and One().
+ * gZero_..... and gOne_..... must have global scope
+ * (to let the compiler know they may be changed in outside
+ * (... but not actually..)).
+ */
+volatile const double gOne_ABCED9B4_CE73__00400511F31D = 1.0;
+
+static double
+One(void)
+{
+ return gOne_ABCED9B4_CE73__00400511F31D;
+}
+
+/*
+ ----------------------------------------------------------------
+ Value of sign in Real structure is reserved for future use.
+ short sign;
+ ==0 : NaN
+ 1 : Positive zero
+ -1 : Negative zero
+ 2 : Positive number
+ -2 : Negative number
+ 3 : Positive infinite number
+ -3 : Negative infinite number
+ ----------------------------------------------------------------
+*/
+
+VP_EXPORT double
+VpGetDoubleNaN(void) /* Returns the value of NaN */
+{
+ return nan("");
+}
+
+VP_EXPORT double
+VpGetDoublePosInf(void) /* Returns the value of +Infinity */
+{
+ return HUGE_VAL;
+}
+
+VP_EXPORT double
+VpGetDoubleNegInf(void) /* Returns the value of -Infinity */
+{
+ return -HUGE_VAL;
+}
+
+VP_EXPORT double
+VpGetDoubleNegZero(void) /* Returns the value of -0 */
+{
+ static double nzero = 1000.0;
+ if (nzero != 0.0) nzero = (One()/VpGetDoubleNegInf());
+ return nzero;
+}
+
+#if 0 /* unused */
+VP_EXPORT int
+VpIsNegDoubleZero(double v)
+{
+ double z = VpGetDoubleNegZero();
+ return MemCmp(&v,&z,sizeof(v))==0;
+}
+#endif
+
+VP_EXPORT int
+VpException(unsigned short f, const char *str,int always)
+{
+ unsigned short const exception_mode = VpGetException();
+
+ if (f == VP_EXCEPTION_OP) always = 1;
+
+ if (always || (exception_mode & f)) {
+ switch(f) {
+ /* case VP_EXCEPTION_OVERFLOW: */
+ case VP_EXCEPTION_ZERODIVIDE:
+ case VP_EXCEPTION_INFINITY:
+ case VP_EXCEPTION_NaN:
+ case VP_EXCEPTION_UNDERFLOW:
+ case VP_EXCEPTION_OP:
+ rb_raise(rb_eFloatDomainError, "%s", str);
+ break;
+ default:
+ rb_fatal("%s", str);
+ }
+ }
+ return 0; /* 0 Means VpException() raised no exception */
+}
+
+/* Throw exception or returns 0,when resulting c is Inf or NaN */
+/* sw=1:+ 2:- 3:* 4:/ */
+static int
+VpIsDefOP(Real *c, Real *a, Real *b, enum op_sw sw)
+{
+ if (VpIsNaN(a) || VpIsNaN(b)) {
+ /* at least a or b is NaN */
+ VpSetNaN(c);
+ goto NaN;
+ }
+
+ if (VpIsInf(a)) {
+ if (VpIsInf(b)) {
+ switch(sw) {
+ case OP_SW_ADD: /* + */
+ if (VpGetSign(a) == VpGetSign(b)) {
+ VpSetInf(c, VpGetSign(a));
+ goto Inf;
+ }
+ else {
+ VpSetNaN(c);
+ goto NaN;
+ }
+ case OP_SW_SUB: /* - */
+ if (VpGetSign(a) != VpGetSign(b)) {
+ VpSetInf(c, VpGetSign(a));
+ goto Inf;
+ }
+ else {
+ VpSetNaN(c);
+ goto NaN;
+ }
+ case OP_SW_MULT: /* * */
+ VpSetInf(c, VpGetSign(a)*VpGetSign(b));
+ goto Inf;
+ case OP_SW_DIV: /* / */
+ VpSetNaN(c);
+ goto NaN;
+ }
+ VpSetNaN(c);
+ goto NaN;
+ }
+ /* Inf op Finite */
+ switch(sw) {
+ case OP_SW_ADD: /* + */
+ case OP_SW_SUB: /* - */
+ VpSetInf(c, VpGetSign(a));
+ break;
+ case OP_SW_MULT: /* * */
+ if (VpIsZero(b)) {
+ VpSetNaN(c);
+ goto NaN;
+ }
+ VpSetInf(c, VpGetSign(a)*VpGetSign(b));
+ break;
+ case OP_SW_DIV: /* / */
+ VpSetInf(c, VpGetSign(a)*VpGetSign(b));
+ }
+ goto Inf;
+ }
+
+ if (VpIsInf(b)) {
+ switch(sw) {
+ case OP_SW_ADD: /* + */
+ VpSetInf(c, VpGetSign(b));
+ break;
+ case OP_SW_SUB: /* - */
+ VpSetInf(c, -VpGetSign(b));
+ break;
+ case OP_SW_MULT: /* * */
+ if (VpIsZero(a)) {
+ VpSetNaN(c);
+ goto NaN;
+ }
+ VpSetInf(c, VpGetSign(a)*VpGetSign(b));
+ break;
+ case OP_SW_DIV: /* / */
+ VpSetZero(c, VpGetSign(a)*VpGetSign(b));
+ }
+ goto Inf;
+ }
+ return 1; /* Results OK */
+
+Inf:
+ if (VpIsPosInf(c)) {
+ return VpException(VP_EXCEPTION_INFINITY, "Computation results to 'Infinity'", 0);
+ }
+ else {
+ return VpException(VP_EXCEPTION_INFINITY, "Computation results to '-Infinity'", 0);
+ }
+
+NaN:
+ return VpException(VP_EXCEPTION_NaN, "Computation results to 'NaN'", 0);
+}
+
+/*
+ ----------------------------------------------------------------
+*/
+
+/*
+ * returns number of chars needed to represent vp in specified format.
+ */
+VP_EXPORT size_t
+VpNumOfChars(Real *vp,const char *pszFmt)
+{
+ SIGNED_VALUE ex;
+ size_t nc;
+
+ if (vp == NULL) return BASE_FIG*2+6;
+ if (!VpIsDef(vp)) return 32; /* not sure,may be OK */
+
+ switch(*pszFmt) {
+ case 'F':
+ nc = BASE_FIG*(vp->Prec + 1)+2;
+ ex = vp->exponent;
+ if (ex < 0) {
+ nc += BASE_FIG*(size_t)(-ex);
+ }
+ else {
+ if ((size_t)ex > vp->Prec) {
+ nc += BASE_FIG*((size_t)ex - vp->Prec);
+ }
+ }
+ break;
+ case 'E':
+ /* fall through */
+ default:
+ nc = BASE_FIG*(vp->Prec + 2)+6; /* 3: sign + exponent chars */
+ }
+ return nc;
+}
+
+/*
+ * Initializer for Vp routines and constants used.
+ * [Input]
+ * BaseVal: Base value(assigned to BASE) for Vp calculation.
+ * It must be the form BaseVal=10**n.(n=1,2,3,...)
+ * If Base <= 0L,then the BASE will be calculated so
+ * that BASE is as large as possible satisfying the
+ * relation MaxVal <= BASE*(BASE+1). Where the value
+ * MaxVal is the largest value which can be represented
+ * by one DECDIG word in the computer used.
+ *
+ * [Returns]
+ * BIGDECIMAL_DOUBLE_FIGURES ... OK
+ */
+VP_EXPORT size_t
+VpInit(DECDIG BaseVal)
+{
+ /* Setup +/- Inf NaN -0 */
+ VpGetDoubleNegZero();
+
+ /* Const 1.0 */
+ VpConstOne = NewOneNolimit(1, 1);
+
+ /* Const 0.5 */
+ VpConstPt5 = NewOneNolimit(1, 1);
+ VpConstPt5->exponent = 0;
+ VpConstPt5->frac[0] = 5*BASE1;
+
+#ifdef BIGDECIMAL_DEBUG
+ gnAlloc = 0;
+#endif /* BIGDECIMAL_DEBUG */
+
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ printf("VpInit: BaseVal = %"PRIuDECDIG"\n", BaseVal);
+ printf("\tBASE = %"PRIuDECDIG"\n", BASE);
+ printf("\tHALF_BASE = %"PRIuDECDIG"\n", HALF_BASE);
+ printf("\tBASE1 = %"PRIuDECDIG"\n", BASE1);
+ printf("\tBASE_FIG = %u\n", BASE_FIG);
+ printf("\tBIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+
+ return BIGDECIMAL_DOUBLE_FIGURES;
+}
+
+VP_EXPORT Real *
+VpOne(void)
+{
+ return VpConstOne;
+}
+
+/* If exponent overflows,then raise exception or returns 0 */
+static int
+AddExponent(Real *a, SIGNED_VALUE n)
+{
+ SIGNED_VALUE e = a->exponent;
+ SIGNED_VALUE m = e+n;
+ SIGNED_VALUE eb, mb;
+ if (e > 0) {
+ if (n > 0) {
+ if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
+ MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
+ goto overflow;
+ mb = m*(SIGNED_VALUE)BASE_FIG;
+ eb = e*(SIGNED_VALUE)BASE_FIG;
+ if (eb - mb > 0) goto overflow;
+ }
+ }
+ else if (n < 0) {
+ if (MUL_OVERFLOW_SIGNED_VALUE_P(m, (SIGNED_VALUE)BASE_FIG) ||
+ MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
+ goto underflow;
+ mb = m*(SIGNED_VALUE)BASE_FIG;
+ eb = e*(SIGNED_VALUE)BASE_FIG;
+ if (mb - eb > 0) goto underflow;
+ }
+ a->exponent = m;
+ return 1;
+
+/* Overflow/Underflow ==> Raise exception or returns 0 */
+underflow:
+ VpSetZero(a, VpGetSign(a));
+ return VpException(VP_EXCEPTION_UNDERFLOW, "Exponent underflow", 0);
+
+overflow:
+ VpSetInf(a, VpGetSign(a));
+ return VpException(VP_EXCEPTION_OVERFLOW, "Exponent overflow", 0);
+}
+
+Real *
+bigdecimal_parse_special_string(const char *str)
+{
+ static const struct {
+ const char *str;
+ size_t len;
+ int sign;
+ } table[] = {
+ { SZ_INF, sizeof(SZ_INF) - 1, VP_SIGN_POSITIVE_INFINITE },
+ { SZ_PINF, sizeof(SZ_PINF) - 1, VP_SIGN_POSITIVE_INFINITE },
+ { SZ_NINF, sizeof(SZ_NINF) - 1, VP_SIGN_NEGATIVE_INFINITE },
+ { SZ_NaN, sizeof(SZ_NaN) - 1, VP_SIGN_NaN }
+ };
+ static const size_t table_length = sizeof(table) / sizeof(table[0]);
+ size_t i;
+
+ for (i = 0; i < table_length; ++i) {
+ const char *p;
+ if (strncmp(str, table[i].str, table[i].len) != 0) {
+ continue;
+ }
+
+ p = str + table[i].len;
+ while (*p && ISSPACE(*p)) ++p;
+ if (*p == '\0') {
+ Real *vp = rbd_allocate_struct(1);
+ vp->MaxPrec = 1;
+ switch (table[i].sign) {
+ default:
+ UNREACHABLE; break;
+ case VP_SIGN_POSITIVE_INFINITE:
+ VpSetPosInf(vp);
+ return vp;
+ case VP_SIGN_NEGATIVE_INFINITE:
+ VpSetNegInf(vp);
+ return vp;
+ case VP_SIGN_NaN:
+ VpSetNaN(vp);
+ return vp;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Allocates variable.
+ * [Input]
+ * mx ... The number of decimal digits to be allocated, if zero then mx is determined by szVal.
+ * The mx will be the number of significant digits can to be stored.
+ * szVal ... The value assigned(char). If szVal==NULL, then zero is assumed.
+ * If szVal[0]=='#' then MaxPrec is not affected by the precision limit
+ * so that the full precision specified by szVal is allocated.
+ *
+ * [Returns]
+ * Pointer to the newly allocated variable, or
+ * NULL be returned if memory allocation is failed,or any error.
+ */
+VP_EXPORT Real *
+VpAlloc(size_t mx, const char *szVal, int strict_p, int exc)
+{
+ const char *orig_szVal = szVal;
+ size_t i, j, ni, ipf, nf, ipe, ne, dot_seen, exp_seen, nalloc;
+ size_t len;
+ char v, *psz;
+ int sign=1;
+ Real *vp = NULL;
+ VALUE buf;
+
+ if (szVal == NULL) {
+ return_zero:
+ /* necessary to be able to store */
+ /* at least mx digits. */
+ /* szVal==NULL ==> allocate zero value. */
+ vp = rbd_allocate_struct(mx);
+ vp->MaxPrec = rbd_calculate_internal_digits(mx, false); /* Must false */
+ VpSetZero(vp, 1); /* initialize vp to zero. */
+ return vp;
+ }
+
+ /* Skipping leading spaces */
+ while (ISSPACE(*szVal)) szVal++;
+
+ /* Check on Inf & NaN */
+ if ((vp = bigdecimal_parse_special_string(szVal)) != NULL) {
+ return vp;
+ }
+
+ /* Processing the leading one `#` */
+ if (*szVal != '#') {
+ len = rbd_calculate_internal_digits(mx, true);
+ }
+ else {
+ len = rbd_calculate_internal_digits(mx, false);
+ ++szVal;
+ }
+
+ /* Scanning digits */
+
+ /* A buffer for keeping scanned digits */
+ buf = rb_str_tmp_new(strlen(szVal) + 1);
+ psz = RSTRING_PTR(buf);
+
+ /* cursor: i for psz, and j for szVal */
+ i = j = 0;
+
+ /* Scanning: sign part */
+ v = psz[i] = szVal[j];
+ if ((v == '-') || (v == '+')) {
+ sign = -(v == '-');
+ ++i;
+ ++j;
+ }
+
+ /* Scanning: integer part */
+ ni = 0; /* number of digits in the integer part */
+ while ((v = psz[i] = szVal[j]) != '\0') {
+ if (!strict_p && ISSPACE(v)) {
+ v = psz[i] = '\0';
+ break;
+ }
+ if (v == '_') {
+ if (ni > 0) {
+ v = szVal[j+1];
+ if (v == '\0' || ISSPACE(v) || ISDIGIT(v)) {
+ ++j;
+ continue;
+ }
+ if (!strict_p) {
+ v = psz[i] = '\0';
+ break;
+ }
+ }
+ goto invalid_value;
+ }
+ if (!ISDIGIT(v)) {
+ break;
+ }
+ ++ni;
+ ++i;
+ ++j;
+ }
+
+ /* Scanning: fractional part */
+ nf = 0; /* number of digits in the fractional part */
+ ne = 0; /* number of digits in the exponential part */
+ ipf = 0; /* index of the beginning of the fractional part */
+ ipe = 0; /* index of the beginning of the exponential part */
+ dot_seen = 0;
+ exp_seen = 0;
+
+ if (v != '\0') {
+ /* Scanning fractional part */
+ if ((psz[i] = szVal[j]) == '.') {
+ dot_seen = 1;
+ ++i;
+ ++j;
+ ipf = i;
+ while ((v = psz[i] = szVal[j]) != '\0') {
+ if (!strict_p && ISSPACE(v)) {
+ v = psz[i] = '\0';
+ break;
+ }
+ if (v == '_') {
+ if (nf > 0 && ISDIGIT(szVal[j+1])) {
+ ++j;
+ continue;
+ }
+ if (!strict_p) {
+ v = psz[i] = '\0';
+ if (nf == 0) {
+ dot_seen = 0;
+ }
+ break;
+ }
+ goto invalid_value;
+ }
+ if (!ISDIGIT(v)) break;
+ ++i;
+ ++j;
+ ++nf;
+ }
+ }
+
+ /* Scanning exponential part */
+ if (v != '\0') {
+ switch ((psz[i] = szVal[j])) {
+ case '\0':
+ break;
+ case 'e': case 'E':
+ case 'd': case 'D':
+ exp_seen = 1;
+ ++i;
+ ++j;
+ ipe = i;
+ v = psz[i] = szVal[j];
+ if ((v == '-') || (v == '+')) {
+ ++i;
+ ++j;
+ }
+ while ((v = psz[i] = szVal[j]) != '\0') {
+ if (!strict_p && ISSPACE(v)) {
+ v = psz[i] = '\0';
+ break;
+ }
+ if (v == '_') {
+ if (ne > 0 && ISDIGIT(szVal[j+1])) {
+ ++j;
+ continue;
+ }
+ if (!strict_p) {
+ v = psz[i] = '\0';
+ if (ne == 0) {
+ exp_seen = 0;
+ }
+ break;
+ }
+ goto invalid_value;
+ }
+ if (!ISDIGIT(v)) break;
+ ++i;
+ ++j;
+ ++ne;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (v != '\0') {
+ /* Scanning trailing spaces */
+ while (ISSPACE(szVal[j])) ++j;
+
+ /* Invalid character */
+ if (szVal[j] && strict_p) {
+ goto invalid_value;
+ }
+ }
+ }
+
+ psz[i] = '\0';
+
+ if (strict_p && (((ni == 0 || dot_seen) && nf == 0) || (exp_seen && ne == 0))) {
+ VALUE str;
+ invalid_value:
+ if (!strict_p) {
+ goto return_zero;
+ }
+ if (!exc) {
+ return NULL;
+ }
+ str = rb_str_new2(orig_szVal);
+ rb_raise(rb_eArgError, "invalid value for BigDecimal(): \"%"PRIsVALUE"\"", str);
+ }
+
+ nalloc = (ni + nf + BASE_FIG - 1) / BASE_FIG + 1; /* set effective allocation */
+ /* units for szVal[] */
+ if (len == 0) len = 1;
+ nalloc = Max(nalloc, len);
+ len = nalloc;
+ vp = rbd_allocate_struct(len);
+ vp->MaxPrec = len; /* set max precision */
+ VpSetZero(vp, sign);
+ VpCtoV(vp, psz, ni, psz + ipf, nf, psz + ipe, ne);
+ rb_str_resize(buf, 0);
+ return vp;
+}
+
+/*
+ * Assignment(c=a).
+ * [Input]
+ * a ... RHSV
+ * isw ... switch for assignment.
+ * c = a when isw > 0
+ * c = -a when isw < 0
+ * if c->MaxPrec < a->Prec,then round operation
+ * will be performed.
+ * [Output]
+ * c ... LHSV
+ */
+VP_EXPORT size_t
+VpAsgn(Real *c, Real *a, int isw)
+{
+ size_t n;
+ if (VpIsNaN(a)) {
+ VpSetNaN(c);
+ return 0;
+ }
+ if (VpIsInf(a)) {
+ VpSetInf(c, isw * VpGetSign(a));
+ return 0;
+ }
+
+ /* check if the RHS is zero */
+ if (!VpIsZero(a)) {
+ c->exponent = a->exponent; /* store exponent */
+ VpSetSign(c, isw * VpGetSign(a)); /* set sign */
+ n = (a->Prec < c->MaxPrec) ? (a->Prec) : (c->MaxPrec);
+ c->Prec = n;
+ memcpy(c->frac, a->frac, n * sizeof(DECDIG));
+ /* Needs round ? */
+ if (isw != 10) {
+ /* Not in ActiveRound */
+ if(c->Prec < a->Prec) {
+ VpInternalRound(c, n, (n>0) ? a->frac[n-1] : 0, a->frac[n]);
+ }
+ else {
+ VpLimitRound(c,0);
+ }
+ }
+ }
+ else {
+ /* The value of 'a' is zero. */
+ VpSetZero(c, isw * VpGetSign(a));
+ return 1;
+ }
+ return c->Prec * BASE_FIG;
+}
+
+/*
+ * c = a + b when operation = 1 or 2
+ * c = a - b when operation = -1 or -2.
+ * Returns number of significant digits of c
+ */
+VP_EXPORT size_t
+VpAddSub(Real *c, Real *a, Real *b, int operation)
+{
+ short sw, isw;
+ Real *a_ptr, *b_ptr;
+ size_t n, na, nb, i;
+ DECDIG mrv;
+
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, "VpAddSub(enter) a=% \n", a);
+ VPrint(stdout, " b=% \n", b);
+ printf(" operation=%d\n", operation);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+
+ if (!VpIsDefOP(c, a, b, (operation > 0) ? OP_SW_ADD : OP_SW_SUB)) return 0; /* No significant digits */
+
+ /* check if a or b is zero */
+ if (VpIsZero(a)) {
+ /* a is zero,then assign b to c */
+ if (!VpIsZero(b)) {
+ VpAsgn(c, b, operation);
+ }
+ else {
+ /* Both a and b are zero. */
+ if (VpGetSign(a) < 0 && operation * VpGetSign(b) < 0) {
+ /* -0 -0 */
+ VpSetZero(c, -1);
+ }
+ else {
+ VpSetZero(c, 1);
+ }
+ return 1; /* 0: 1 significant digits */
+ }
+ return c->Prec * BASE_FIG;
+ }
+ if (VpIsZero(b)) {
+ /* b is zero,then assign a to c. */
+ VpAsgn(c, a, 1);
+ return c->Prec*BASE_FIG;
+ }
+
+ if (operation < 0) sw = -1;
+ else sw = 1;
+
+ /* compare absolute value. As a result,|a_ptr|>=|b_ptr| */
+ if (a->exponent > b->exponent) {
+ a_ptr = a;
+ b_ptr = b;
+ } /* |a|>|b| */
+ else if (a->exponent < b->exponent) {
+ a_ptr = b;
+ b_ptr = a;
+ } /* |a|<|b| */
+ else {
+ /* Exponent part of a and b is the same,then compare fraction */
+ /* part */
+ na = a->Prec;
+ nb = b->Prec;
+ n = Min(na, nb);
+ for (i=0; i < n; ++i) {
+ if (a->frac[i] > b->frac[i]) {
+ a_ptr = a;
+ b_ptr = b;
+ goto end_if;
+ }
+ else if (a->frac[i] < b->frac[i]) {
+ a_ptr = b;
+ b_ptr = a;
+ goto end_if;
+ }
+ }
+ if (na > nb) {
+ a_ptr = a;
+ b_ptr = b;
+ goto end_if;
+ }
+ else if (na < nb) {
+ a_ptr = b;
+ b_ptr = a;
+ goto end_if;
+ }
+ /* |a| == |b| */
+ if (VpGetSign(a) + sw *VpGetSign(b) == 0) {
+ VpSetZero(c, 1); /* abs(a)=abs(b) and operation = '-' */
+ return c->Prec * BASE_FIG;
+ }
+ a_ptr = a;
+ b_ptr = b;
+ }
+
+end_if:
+ isw = VpGetSign(a) + sw *VpGetSign(b);
+ /*
+ * isw = 0 ...( 1)+(-1),( 1)-( 1),(-1)+(1),(-1)-(-1)
+ * = 2 ...( 1)+( 1),( 1)-(-1)
+ * =-2 ...(-1)+(-1),(-1)-( 1)
+ * If isw==0, then c =(Sign a_ptr)(|a_ptr|-|b_ptr|)
+ * else c =(Sign ofisw)(|a_ptr|+|b_ptr|)
+ */
+ if (isw) { /* addition */
+ VpSetSign(c, 1);
+ mrv = VpAddAbs(a_ptr, b_ptr, c);
+ VpSetSign(c, isw / 2);
+ }
+ else { /* subtraction */
+ VpSetSign(c, 1);
+ mrv = VpSubAbs(a_ptr, b_ptr, c);
+ if (a_ptr == a) {
+ VpSetSign(c,VpGetSign(a));
+ }
+ else {
+ VpSetSign(c, VpGetSign(a_ptr) * sw);
+ }
+ }
+ VpInternalRound(c, 0, (c->Prec > 0) ? c->frac[c->Prec-1] : 0, mrv);
+
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, "VpAddSub(result) c=% \n", c);
+ VPrint(stdout, " a=% \n", a);
+ VPrint(stdout, " b=% \n", b);
+ printf(" operation=%d\n", operation);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+ return c->Prec * BASE_FIG;
+}
+
+/*
+ * Addition of two values with variable precision
+ * a and b assuming abs(a)>abs(b).
+ * c = abs(a) + abs(b) ; where |a|>=|b|
+ */
+static DECDIG
+VpAddAbs(Real *a, Real *b, Real *c)
+{
+ size_t word_shift;
+ size_t ap;
+ size_t bp;
+ size_t cp;
+ size_t a_pos;
+ size_t b_pos, b_pos_with_word_shift;
+ size_t c_pos;
+ DECDIG av, bv, carry, mrv;
+
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, "VpAddAbs called: a = %\n", a);
+ VPrint(stdout, " b = %\n", b);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+
+ word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
+ a_pos = ap;
+ b_pos = bp;
+ c_pos = cp;
+
+ if (word_shift == (size_t)-1L) return 0; /* Overflow */
+ if (b_pos == (size_t)-1L) goto Assign_a;
+
+ mrv = av + bv; /* Most right val. Used for round. */
+
+ /* Just assign the last few digits of b to c because a has no */
+ /* corresponding digits to be added. */
+ if (b_pos > 0) {
+ while (b_pos > 0 && b_pos + word_shift > a_pos) {
+ c->frac[--c_pos] = b->frac[--b_pos];
+ }
+ }
+ if (b_pos == 0 && word_shift > a_pos) {
+ while (word_shift-- > a_pos) {
+ c->frac[--c_pos] = 0;
+ }
+ }
+
+ /* Just assign the last few digits of a to c because b has no */
+ /* corresponding digits to be added. */
+ b_pos_with_word_shift = b_pos + word_shift;
+ while (a_pos > b_pos_with_word_shift) {
+ c->frac[--c_pos] = a->frac[--a_pos];
+ }
+ carry = 0; /* set first carry be zero */
+
+ /* Now perform addition until every digits of b will be */
+ /* exhausted. */
+ while (b_pos > 0) {
+ c->frac[--c_pos] = a->frac[--a_pos] + b->frac[--b_pos] + carry;
+ if (c->frac[c_pos] >= BASE) {
+ c->frac[c_pos] -= BASE;
+ carry = 1;
+ }
+ else {
+ carry = 0;
+ }
+ }
+
+ /* Just assign the first few digits of a with considering */
+ /* the carry obtained so far because b has been exhausted. */
+ while (a_pos > 0) {
+ c->frac[--c_pos] = a->frac[--a_pos] + carry;
+ if (c->frac[c_pos] >= BASE) {
+ c->frac[c_pos] -= BASE;
+ carry = 1;
+ }
+ else {
+ carry = 0;
+ }
+ }
+ if (c_pos) c->frac[c_pos - 1] += carry;
+ goto Exit;
+
+Assign_a:
+ VpAsgn(c, a, 1);
+ mrv = 0;
+
+Exit:
+
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, "VpAddAbs exit: c=% \n", c);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+ return mrv;
+}
+
+/*
+ * c = abs(a) - abs(b)
+ */
+static DECDIG
+VpSubAbs(Real *a, Real *b, Real *c)
+{
+ size_t word_shift;
+ size_t ap;
+ size_t bp;
+ size_t cp;
+ size_t a_pos;
+ size_t b_pos, b_pos_with_word_shift;
+ size_t c_pos;
+ DECDIG av, bv, borrow, mrv;
+
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, "VpSubAbs called: a = %\n", a);
+ VPrint(stdout, " b = %\n", b);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+
+ word_shift = VpSetPTR(a, b, c, &ap, &bp, &cp, &av, &bv);
+ a_pos = ap;
+ b_pos = bp;
+ c_pos = cp;
+ if (word_shift == (size_t)-1L) return 0; /* Overflow */
+ if (b_pos == (size_t)-1L) goto Assign_a;
+
+ if (av >= bv) {
+ mrv = av - bv;
+ borrow = 0;
+ }
+ else {
+ mrv = 0;
+ borrow = 1;
+ }
+
+ /* Just assign the values which are the BASE subtracted by */
+ /* each of the last few digits of the b because the a has no */
+ /* corresponding digits to be subtracted. */
+ if (b_pos + word_shift > a_pos) {
+ while (b_pos > 0 && b_pos + word_shift > a_pos) {
+ c->frac[--c_pos] = BASE - b->frac[--b_pos] - borrow;
+ borrow = 1;
+ }
+ if (b_pos == 0) {
+ while (word_shift > a_pos) {
+ --word_shift;
+ c->frac[--c_pos] = BASE - borrow;
+ borrow = 1;
+ }
+ }
+ }
+ /* Just assign the last few digits of a to c because b has no */
+ /* corresponding digits to subtract. */
+
+ b_pos_with_word_shift = b_pos + word_shift;
+ while (a_pos > b_pos_with_word_shift) {
+ c->frac[--c_pos] = a->frac[--a_pos];
+ }
+
+ /* Now perform subtraction until every digits of b will be */
+ /* exhausted. */
+ while (b_pos > 0) {
+ --c_pos;
+ if (a->frac[--a_pos] < b->frac[--b_pos] + borrow) {
+ c->frac[c_pos] = BASE + a->frac[a_pos] - b->frac[b_pos] - borrow;
+ borrow = 1;
+ }
+ else {
+ c->frac[c_pos] = a->frac[a_pos] - b->frac[b_pos] - borrow;
+ borrow = 0;
+ }
+ }
+
+ /* Just assign the first few digits of a with considering */
+ /* the borrow obtained so far because b has been exhausted. */
+ while (a_pos > 0) {
+ --c_pos;
+ if (a->frac[--a_pos] < borrow) {
+ c->frac[c_pos] = BASE + a->frac[a_pos] - borrow;
+ borrow = 1;
+ }
+ else {
+ c->frac[c_pos] = a->frac[a_pos] - borrow;
+ borrow = 0;
+ }
+ }
+ if (c_pos) c->frac[c_pos - 1] -= borrow;
+ goto Exit;
+
+Assign_a:
+ VpAsgn(c, a, 1);
+ mrv = 0;
+
+Exit:
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, "VpSubAbs exit: c=% \n", c);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+ return mrv;
+}
+
+/*
+ * Note: If(av+bv)>= HALF_BASE,then 1 will be added to the least significant
+ * digit of c(In case of addition).
+ * ------------------------- figure of output -----------------------------------
+ * a = xxxxxxxxxxx
+ * b = xxxxxxxxxx
+ * c =xxxxxxxxxxxxxxx
+ * word_shift = | |
+ * right_word = | | (Total digits in RHSV)
+ * left_word = | | (Total digits in LHSV)
+ * a_pos = |
+ * b_pos = |
+ * c_pos = |
+ */
+static size_t
+VpSetPTR(Real *a, Real *b, Real *c, size_t *a_pos, size_t *b_pos, size_t *c_pos, DECDIG *av, DECDIG *bv)
+{
+ size_t left_word, right_word, word_shift;
+
+ size_t const round_limit = (VpGetPrecLimit() + BASE_FIG - 1) / BASE_FIG;
+
+ assert(a->exponent >= b->exponent);
+
+ c->frac[0] = 0;
+ *av = *bv = 0;
+
+ word_shift = (a->exponent - b->exponent);
+ left_word = b->Prec + word_shift;
+ right_word = Max(a->Prec, left_word);
+ left_word = c->MaxPrec - 1; /* -1 ... prepare for round up */
+
+ /*
+ * check if 'round' is needed.
+ */
+ if (right_word > left_word) { /* round ? */
+ /*---------------------------------
+ * Actual size of a = xxxxxxAxx
+ * Actual size of b = xxxBxxxxx
+ * Max. size of c = xxxxxx
+ * Round off = |-----|
+ * c_pos = |
+ * right_word = |
+ * a_pos = |
+ */
+ *c_pos = right_word = left_word + 1; /* Set resulting precision */
+ /* be equal to that of c */
+ if (a->Prec >= c->MaxPrec) {
+ /*
+ * a = xxxxxxAxxx
+ * c = xxxxxx
+ * a_pos = |
+ */
+ *a_pos = left_word;
+ if (*a_pos <= round_limit) {
+ *av = a->frac[*a_pos]; /* av is 'A' shown in above. */
+ }
+ }
+ else {
+ /*
+ * a = xxxxxxx
+ * c = xxxxxxxxxx
+ * a_pos = |
+ */
+ *a_pos = a->Prec;
+ }
+ if (b->Prec + word_shift >= c->MaxPrec) {
+ /*
+ * a = xxxxxxxxx
+ * b = xxxxxxxBxxx
+ * c = xxxxxxxxxxx
+ * b_pos = |
+ */
+ if (c->MaxPrec >= word_shift + 1) {
+ *b_pos = c->MaxPrec - word_shift - 1;
+ if (*b_pos + word_shift <= round_limit) {
+ *bv = b->frac[*b_pos];
+ }
+ }
+ else {
+ *b_pos = -1L;
+ }
+ }
+ else {
+ /*
+ * a = xxxxxxxxxxxxxxxx
+ * b = xxxxxx
+ * c = xxxxxxxxxxxxx
+ * b_pos = |
+ */
+ *b_pos = b->Prec;
+ }
+ }
+ else { /* The MaxPrec of c - 1 > The Prec of a + b */
+ /*
+ * a = xxxxxxx
+ * b = xxxxxx
+ * c = xxxxxxxxxxx
+ * c_pos = |
+ */
+ *b_pos = b->Prec;
+ *a_pos = a->Prec;
+ *c_pos = right_word + 1;
+ }
+ c->Prec = *c_pos;
+ c->exponent = a->exponent;
+ if (!AddExponent(c, 1)) return (size_t)-1L;
+ return word_shift;
+}
+
+/*
+ * Return number of significant digits
+ * c = a * b , Where a = a0a1a2 ... an
+ * b = b0b1b2 ... bm
+ * c = c0c1c2 ... cl
+ * a0 a1 ... an * bm
+ * a0 a1 ... an * bm-1
+ * . . .
+ * . . .
+ * a0 a1 .... an * b0
+ * +_____________________________
+ * c0 c1 c2 ...... cl
+ * nc <---|
+ * MaxAB |--------------------|
+ */
+VP_EXPORT size_t
+VpMult(Real *c, Real *a, Real *b)
+{
+ size_t MxIndA, MxIndB, MxIndAB, MxIndC;
+ size_t ind_c, i, ii, nc;
+ size_t ind_as, ind_ae, ind_bs;
+ DECDIG carry;
+ DECDIG_DBL s;
+ Real *w;
+
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, "VpMult(Enter): a=% \n", a);
+ VPrint(stdout, " b=% \n", b);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+
+ if (!VpIsDefOP(c, a, b, OP_SW_MULT)) return 0; /* No significant digit */
+
+ if (VpIsZero(a) || VpIsZero(b)) {
+ /* at least a or b is zero */
+ VpSetZero(c, VpGetSign(a) * VpGetSign(b));
+ return 1; /* 0: 1 significant digit */
+ }
+
+ if (VpIsOne(a)) {
+ VpAsgn(c, b, VpGetSign(a));
+ goto Exit;
+ }
+ if (VpIsOne(b)) {
+ VpAsgn(c, a, VpGetSign(b));
+ goto Exit;
+ }
+ if (b->Prec > a->Prec) {
+ /* Adjust so that digits(a)>digits(b) */
+ w = a;
+ a = b;
+ b = w;
+ }
+ w = NULL;
+ MxIndA = a->Prec - 1;
+ MxIndB = b->Prec - 1;
+ MxIndC = c->MaxPrec - 1;
+ MxIndAB = a->Prec + b->Prec - 1;
+
+ if (MxIndC < MxIndAB) { /* The Max. prec. of c < Prec(a)+Prec(b) */
+ w = c;
+ c = NewZeroNolimit(1, (size_t)((MxIndAB + 1) * BASE_FIG));
+ MxIndC = MxIndAB;
+ }
+
+ /* set LHSV c info */
+
+ c->exponent = a->exponent; /* set exponent */
+ if (!AddExponent(c, b->exponent)) {
+ if (w) rbd_free_struct(c);
+ return 0;
+ }
+ VpSetSign(c, VpGetSign(a) * VpGetSign(b)); /* set sign */
+ carry = 0;
+ nc = ind_c = MxIndAB;
+ memset(c->frac, 0, (nc + 1) * sizeof(DECDIG)); /* Initialize c */
+ c->Prec = nc + 1; /* set precision */
+ for (nc = 0; nc < MxIndAB; ++nc, --ind_c) {
+ if (nc < MxIndB) { /* The left triangle of the Fig. */
+ ind_as = MxIndA - nc;
+ ind_ae = MxIndA;
+ ind_bs = MxIndB;
+ }
+ else if (nc <= MxIndA) { /* The middle rectangular of the Fig. */
+ ind_as = MxIndA - nc;
+ ind_ae = MxIndA - (nc - MxIndB);
+ ind_bs = MxIndB;
+ }
+ else /* if (nc > MxIndA) */ { /* The right triangle of the Fig. */
+ ind_as = 0;
+ ind_ae = MxIndAB - nc - 1;
+ ind_bs = MxIndB - (nc - MxIndA);
+ }
+
+ for (i = ind_as; i <= ind_ae; ++i) {
+ s = (DECDIG_DBL)a->frac[i] * b->frac[ind_bs--];
+ carry = (DECDIG)(s / BASE);
+ s -= (DECDIG_DBL)carry * BASE;
+ c->frac[ind_c] += (DECDIG)s;
+ if (c->frac[ind_c] >= BASE) {
+ s = c->frac[ind_c] / BASE;
+ carry += (DECDIG)s;
+ c->frac[ind_c] -= (DECDIG)(s * BASE);
+ }
+ if (carry) {
+ ii = ind_c;
+ while (ii-- > 0) {
+ c->frac[ii] += carry;
+ if (c->frac[ii] >= BASE) {
+ carry = c->frac[ii] / BASE;
+ c->frac[ii] -= (carry * BASE);
+ }
+ else {
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (w != NULL) { /* free work variable */
+ VpNmlz(c);
+ VpAsgn(w, c, 1);
+ rbd_free_struct(c);
+ c = w;
+ }
+ else {
+ VpLimitRound(c,0);
+ }
+
+Exit:
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, "VpMult(c=a*b): c=% \n", c);
+ VPrint(stdout, " a=% \n", a);
+ VPrint(stdout, " b=% \n", b);
+ }
+#endif /*BIGDECIMAL_DEBUG */
+ return c->Prec*BASE_FIG;
+}
+
+/*
+ * c = a / b, remainder = r
+ */
+VP_EXPORT size_t
+VpDivd(Real *c, Real *r, Real *a, Real *b)
+{
+ size_t word_a, word_b, word_c, word_r;
+ size_t i, n, ind_a, ind_b, ind_c, ind_r;
+ size_t nLoop;
+ DECDIG_DBL q, b1, b1p1, b1b2, b1b2p1, r1r2;
+ DECDIG borrow, borrow1, borrow2;
+ DECDIG_DBL qb;
+
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, " VpDivd(c=a/b) a=% \n", a);
+ VPrint(stdout, " b=% \n", b);
+ }
+#endif /*BIGDECIMAL_DEBUG */
+
+ VpSetNaN(r);
+ if (!VpIsDefOP(c, a, b, OP_SW_DIV)) goto Exit;
+ if (VpIsZero(a) && VpIsZero(b)) {
+ VpSetNaN(c);
+ return VpException(VP_EXCEPTION_NaN, "Computation results to 'NaN'", 0);
+ }
+ if (VpIsZero(b)) {
+ VpSetInf(c, VpGetSign(a) * VpGetSign(b));
+ return VpException(VP_EXCEPTION_ZERODIVIDE, "Divide by zero", 0);
+ }
+ if (VpIsZero(a)) {
+ /* numerator a is zero */
+ VpSetZero(c, VpGetSign(a) * VpGetSign(b));
+ VpSetZero(r, VpGetSign(a) * VpGetSign(b));
+ goto Exit;
+ }
+ if (VpIsOne(b)) {
+ /* divide by one */
+ VpAsgn(c, a, VpGetSign(b));
+ VpSetZero(r, VpGetSign(a));
+ goto Exit;
+ }
+
+ word_a = a->Prec;
+ word_b = b->Prec;
+ word_c = c->MaxPrec;
+ word_r = r->MaxPrec;
+
+ if (word_a >= word_r) goto space_error;
+
+ ind_r = 1;
+ r->frac[0] = 0;
+ while (ind_r <= word_a) {
+ r->frac[ind_r] = a->frac[ind_r - 1];
+ ++ind_r;
+ }
+ while (ind_r < word_r) r->frac[ind_r++] = 0;
+
+ ind_c = 0;
+ while (ind_c < word_c) c->frac[ind_c++] = 0;
+
+ /* initial procedure */
+ b1 = b1p1 = b->frac[0];
+ if (b->Prec <= 1) {
+ b1b2p1 = b1b2 = b1p1 * BASE;
+ }
+ else {
+ b1p1 = b1 + 1;
+ b1b2p1 = b1b2 = b1 * BASE + b->frac[1];
+ if (b->Prec > 2) ++b1b2p1;
+ }
+
+ /* */
+ /* loop start */
+ ind_c = word_r - 1;
+ nLoop = Min(word_c,ind_c);
+ ind_c = 1;
+ while (ind_c < nLoop) {
+ if (r->frac[ind_c] == 0) {
+ ++ind_c;
+ continue;
+ }
+ r1r2 = (DECDIG_DBL)r->frac[ind_c] * BASE + r->frac[ind_c + 1];
+ if (r1r2 == b1b2) {
+ /* The first two word digits is the same */
+ ind_b = 2;
+ ind_a = ind_c + 2;
+ while (ind_b < word_b) {
+ if (r->frac[ind_a] < b->frac[ind_b]) goto div_b1p1;
+ if (r->frac[ind_a] > b->frac[ind_b]) break;
+ ++ind_a;
+ ++ind_b;
+ }
+ /* The first few word digits of r and b is the same and */
+ /* the first different word digit of w is greater than that */
+ /* of b, so quotient is 1 and just subtract b from r. */
+ borrow = 0; /* quotient=1, then just r-b */
+ ind_b = b->Prec - 1;
+ ind_r = ind_c + ind_b;
+ if (ind_r >= word_r) goto space_error;
+ n = ind_b;
+ for (i = 0; i <= n; ++i) {
+ if (r->frac[ind_r] < b->frac[ind_b] + borrow) {
+ r->frac[ind_r] += (BASE - (b->frac[ind_b] + borrow));
+ borrow = 1;
+ }
+ else {
+ r->frac[ind_r] = r->frac[ind_r] - b->frac[ind_b] - borrow;
+ borrow = 0;
+ }
+ --ind_r;
+ --ind_b;
+ }
+ ++c->frac[ind_c];
+ goto carry;
+ }
+ /* The first two word digits is not the same, */
+ /* then compare magnitude, and divide actually. */
+ if (r1r2 >= b1b2p1) {
+ q = r1r2 / b1b2p1; /* q == (DECDIG)q */
+ c->frac[ind_c] += (DECDIG)q;
+ ind_r = b->Prec + ind_c - 1;
+ goto sub_mult;
+ }
+
+div_b1p1:
+ if (ind_c + 1 >= word_c) goto out_side;
+ q = r1r2 / b1p1; /* q == (DECDIG)q */
+ c->frac[ind_c + 1] += (DECDIG)q;
+ ind_r = b->Prec + ind_c;
+
+sub_mult:
+ borrow1 = borrow2 = 0;
+ ind_b = word_b - 1;
+ if (ind_r >= word_r) goto space_error;
+ n = ind_b;
+ for (i = 0; i <= n; ++i) {
+ /* now, perform r = r - q * b */
+ qb = q * b->frac[ind_b];
+ if (qb < BASE) borrow1 = 0;
+ else {
+ borrow1 = (DECDIG)(qb / BASE);
+ qb -= (DECDIG_DBL)borrow1 * BASE; /* get qb < BASE */
+ }
+ if(r->frac[ind_r] < qb) {
+ r->frac[ind_r] += (DECDIG)(BASE - qb);
+ borrow2 = borrow2 + borrow1 + 1;
+ }
+ else {
+ r->frac[ind_r] -= (DECDIG)qb;
+ borrow2 += borrow1;
+ }
+ if (borrow2) {
+ if(r->frac[ind_r - 1] < borrow2) {
+ r->frac[ind_r - 1] += (BASE - borrow2);
+ borrow2 = 1;
+ }
+ else {
+ r->frac[ind_r - 1] -= borrow2;
+ borrow2 = 0;
+ }
+ }
+ --ind_r;
+ --ind_b;
+ }
+
+ r->frac[ind_r] -= borrow2;
+carry:
+ ind_r = ind_c;
+ while (c->frac[ind_r] >= BASE) {
+ c->frac[ind_r] -= BASE;
+ --ind_r;
+ ++c->frac[ind_r];
+ }
+ }
+ /* End of operation, now final arrangement */
+out_side:
+ c->Prec = word_c;
+ c->exponent = a->exponent;
+ if (!AddExponent(c, 2)) return 0;
+ if (!AddExponent(c, -(b->exponent))) return 0;
+
+ VpSetSign(c, VpGetSign(a) * VpGetSign(b));
+ VpNmlz(c); /* normalize c */
+ r->Prec = word_r;
+ r->exponent = a->exponent;
+ if (!AddExponent(r, 1)) return 0;
+ VpSetSign(r, VpGetSign(a));
+ VpNmlz(r); /* normalize r(remainder) */
+ goto Exit;
+
+space_error:
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ printf(" word_a=%"PRIuSIZE"\n", word_a);
+ printf(" word_b=%"PRIuSIZE"\n", word_b);
+ printf(" word_c=%"PRIuSIZE"\n", word_c);
+ printf(" word_r=%"PRIuSIZE"\n", word_r);
+ printf(" ind_r =%"PRIuSIZE"\n", ind_r);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+ rb_bug("ERROR(VpDivd): space for remainder too small.");
+
+Exit:
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, " VpDivd(c=a/b), c=% \n", c);
+ VPrint(stdout, " r=% \n", r);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+ return c->Prec * BASE_FIG;
+}
+
+/*
+ * Input a = 00000xxxxxxxx En(5 preceding zeros)
+ * Output a = xxxxxxxx En-5
+ */
+static int
+VpNmlz(Real *a)
+{
+ size_t ind_a, i;
+
+ if (!VpIsDef(a)) goto NoVal;
+ if (VpIsZero(a)) goto NoVal;
+
+ ind_a = a->Prec;
+ while (ind_a--) {
+ if (a->frac[ind_a]) {
+ a->Prec = ind_a + 1;
+ i = 0;
+ while (a->frac[i] == 0) ++i; /* skip the first few zeros */
+ if (i) {
+ a->Prec -= i;
+ if (!AddExponent(a, -(SIGNED_VALUE)i)) return 0;
+ memmove(&a->frac[0], &a->frac[i], a->Prec*sizeof(DECDIG));
+ }
+ return 1;
+ }
+ }
+ /* a is zero(no non-zero digit) */
+ VpSetZero(a, VpGetSign(a));
+ return 0;
+
+NoVal:
+ a->frac[0] = 0;
+ a->Prec = 1;
+ return 0;
+}
+
+/*
+ * VpComp = 0 ... if a=b,
+ * Pos ... a>b,
+ * Neg ... a<b.
+ * 999 ... result undefined(NaN)
+ */
+VP_EXPORT int
+VpComp(Real *a, Real *b)
+{
+ int val;
+ size_t mx, ind;
+ int e;
+ val = 0;
+ if (VpIsNaN(a) || VpIsNaN(b)) return 999;
+ if (!VpIsDef(a)) {
+ if (!VpIsDef(b)) e = a->sign - b->sign;
+ else e = a->sign;
+
+ if (e > 0) return 1;
+ else if (e < 0) return -1;
+ else return 0;
+ }
+ if (!VpIsDef(b)) {
+ e = -b->sign;
+ if (e > 0) return 1;
+ else return -1;
+ }
+ /* Zero check */
+ if (VpIsZero(a)) {
+ if (VpIsZero(b)) return 0; /* both zero */
+ val = -VpGetSign(b);
+ goto Exit;
+ }
+ if (VpIsZero(b)) {
+ val = VpGetSign(a);
+ goto Exit;
+ }
+
+ /* compare sign */
+ if (VpGetSign(a) > VpGetSign(b)) {
+ val = 1; /* a>b */
+ goto Exit;
+ }
+ if (VpGetSign(a) < VpGetSign(b)) {
+ val = -1; /* a<b */
+ goto Exit;
+ }
+
+ /* a and b have same sign, && sign!=0,then compare exponent */
+ if (a->exponent > b->exponent) {
+ val = VpGetSign(a);
+ goto Exit;
+ }
+ if (a->exponent < b->exponent) {
+ val = -VpGetSign(b);
+ goto Exit;
+ }
+
+ /* a and b have same exponent, then compare their significand. */
+ mx = (a->Prec < b->Prec) ? a->Prec : b->Prec;
+ ind = 0;
+ while (ind < mx) {
+ if (a->frac[ind] > b->frac[ind]) {
+ val = VpGetSign(a);
+ goto Exit;
+ }
+ if (a->frac[ind] < b->frac[ind]) {
+ val = -VpGetSign(b);
+ goto Exit;
+ }
+ ++ind;
+ }
+ if (a->Prec > b->Prec) {
+ val = VpGetSign(a);
+ }
+ else if (a->Prec < b->Prec) {
+ val = -VpGetSign(b);
+ }
+
+Exit:
+ if (val > 1) val = 1;
+ else if (val < -1) val = -1;
+
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, " VpComp a=%\n", a);
+ VPrint(stdout, " b=%\n", b);
+ printf(" ans=%d\n", val);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+ return (int)val;
+}
+
+/*
+ * cntl_chr ... ASCIIZ Character, print control characters
+ * Available control codes:
+ * % ... VP variable. To print '%', use '%%'.
+ * \n ... new line
+ * \b ... backspace
+ * \t ... tab
+ * Note: % must not appear more than once
+ * a ... VP variable to be printed
+ */
+static int
+VPrint(FILE *fp, const char *cntl_chr, Real *a)
+{
+ size_t i, j, nc, nd, ZeroSup, sep = 10;
+ DECDIG m, e, nn;
+
+ j = 0;
+ nd = nc = 0; /* nd : number of digits in fraction part(every 10 digits, */
+ /* nd<=10). */
+ /* nc : number of characters printed */
+ ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
+ while (*(cntl_chr + j)) {
+ if (*(cntl_chr + j) == '%' && *(cntl_chr + j + 1) != '%') {
+ nc = 0;
+ if (VpIsNaN(a)) {
+ fprintf(fp, SZ_NaN);
+ nc += 8;
+ }
+ else if (VpIsPosInf(a)) {
+ fprintf(fp, SZ_INF);
+ nc += 8;
+ }
+ else if (VpIsNegInf(a)) {
+ fprintf(fp, SZ_NINF);
+ nc += 9;
+ }
+ else if (!VpIsZero(a)) {
+ if (BIGDECIMAL_NEGATIVE_P(a)) {
+ fprintf(fp, "-");
+ ++nc;
+ }
+ nc += fprintf(fp, "0.");
+ switch (*(cntl_chr + j + 1)) {
+ default:
+ break;
+
+ case '0': case 'z':
+ ZeroSup = 0;
+ ++j;
+ sep = cntl_chr[j] == 'z' ? BIGDECIMAL_COMPONENT_FIGURES : 10;
+ break;
+ }
+ for (i = 0; i < a->Prec; ++i) {
+ m = BASE1;
+ e = a->frac[i];
+ while (m) {
+ nn = e / m;
+ if (!ZeroSup || nn) {
+ nc += fprintf(fp, "%lu", (unsigned long)nn); /* The leading zero(s) */
+ /* as 0.00xx will not */
+ /* be printed. */
+ ++nd;
+ ZeroSup = 0; /* Set to print succeeding zeros */
+ }
+ if (nd >= sep) { /* print ' ' after every 10 digits */
+ nd = 0;
+ nc += fprintf(fp, " ");
+ }
+ e = e - nn * m;
+ m /= 10;
+ }
+ }
+ nc += fprintf(fp, "E%"PRIdSIZE, VpExponent10(a));
+ nc += fprintf(fp, " (%"PRIdVALUE", %lu, %lu)", a->exponent, a->Prec, a->MaxPrec);
+ }
+ else {
+ nc += fprintf(fp, "0.0");
+ }
+ }
+ else {
+ ++nc;
+ if (*(cntl_chr + j) == '\\') {
+ switch (*(cntl_chr + j + 1)) {
+ case 'n':
+ fprintf(fp, "\n");
+ ++j;
+ break;
+ case 't':
+ fprintf(fp, "\t");
+ ++j;
+ break;
+ case 'b':
+ fprintf(fp, "\n");
+ ++j;
+ break;
+ default:
+ fprintf(fp, "%c", *(cntl_chr + j));
+ break;
+ }
+ }
+ else {
+ fprintf(fp, "%c", *(cntl_chr + j));
+ if (*(cntl_chr + j) == '%') ++j;
+ }
+ }
+ j++;
+ }
+
+ return (int)nc;
+}
+
+static void
+VpFormatSt(char *psz, size_t fFmt)
+{
+ size_t ie, i, nf = 0;
+ char ch;
+
+ if (fFmt == 0) return;
+
+ ie = strlen(psz);
+ for (i = 0; i < ie; ++i) {
+ ch = psz[i];
+ if (!ch) break;
+ if (ISSPACE(ch) || ch=='-' || ch=='+') continue;
+ if (ch == '.') { nf = 0; continue; }
+ if (ch == 'E' || ch == 'e') break;
+
+ if (++nf > fFmt) {
+ memmove(psz + i + 1, psz + i, ie - i + 1);
+ ++ie;
+ nf = 0;
+ psz[i] = ' ';
+ }
+ }
+}
+
+VP_EXPORT ssize_t
+VpExponent10(Real *a)
+{
+ ssize_t ex;
+ size_t n;
+
+ if (!VpHasVal(a)) return 0;
+
+ ex = a->exponent * (ssize_t)BASE_FIG;
+ n = BASE1;
+ while ((a->frac[0] / n) == 0) {
+ --ex;
+ n /= 10;
+ }
+ return ex;
+}
+
+VP_EXPORT void
+VpSzMantissa(Real *a, char *buf, size_t buflen)
+{
+ size_t i, n, ZeroSup;
+ DECDIG_DBL m, e, nn;
+
+ if (VpIsNaN(a)) {
+ snprintf(buf, buflen, SZ_NaN);
+ return;
+ }
+ if (VpIsPosInf(a)) {
+ snprintf(buf, buflen, SZ_INF);
+ return;
+ }
+ if (VpIsNegInf(a)) {
+ snprintf(buf, buflen, SZ_NINF);
+ return;
+ }
+
+ ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
+ if (!VpIsZero(a)) {
+ if (BIGDECIMAL_NEGATIVE_P(a)) *buf++ = '-';
+ n = a->Prec;
+ for (i = 0; i < n; ++i) {
+ m = BASE1;
+ e = a->frac[i];
+ while (m) {
+ nn = e / m;
+ if (!ZeroSup || nn) {
+ snprintf(buf, buflen, "%lu", (unsigned long)nn); /* The leading zero(s) */
+ buf += strlen(buf);
+ /* as 0.00xx will be ignored. */
+ ZeroSup = 0; /* Set to print succeeding zeros */
+ }
+ e = e - nn * m;
+ m /= 10;
+ }
+ }
+ *buf = 0;
+ while (buf[-1] == '0') *(--buf) = 0;
+ }
+ else {
+ if (VpIsPosZero(a)) snprintf(buf, buflen, "0");
+ else snprintf(buf, buflen, "-0");
+ }
+}
+
+VP_EXPORT int
+VpToSpecialString(Real *a, char *buf, size_t buflen, int fPlus)
+/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
+{
+ if (VpIsNaN(a)) {
+ snprintf(buf, buflen, SZ_NaN);
+ return 1;
+ }
+
+ if (VpIsPosInf(a)) {
+ if (fPlus == 1) {
+ *buf++ = ' ';
+ }
+ else if (fPlus == 2) {
+ *buf++ = '+';
+ }
+ snprintf(buf, buflen, SZ_INF);
+ return 1;
+ }
+ if (VpIsNegInf(a)) {
+ snprintf(buf, buflen, SZ_NINF);
+ return 1;
+ }
+ if (VpIsZero(a)) {
+ if (VpIsPosZero(a)) {
+ if (fPlus == 1) snprintf(buf, buflen, " 0.0");
+ else if (fPlus == 2) snprintf(buf, buflen, "+0.0");
+ else snprintf(buf, buflen, "0.0");
+ }
+ else snprintf(buf, buflen, "-0.0");
+ return 1;
+ }
+ return 0;
+}
+
+VP_EXPORT void
+VpToString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
+/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
+{
+ size_t i, n, ZeroSup;
+ DECDIG shift, m, e, nn;
+ char *p = buf;
+ size_t plen = buflen;
+ ssize_t ex;
+
+ if (VpToSpecialString(a, buf, buflen, fPlus)) return;
+
+ ZeroSup = 1; /* Flag not to print the leading zeros as 0.00xxxxEnn */
+
+#define ADVANCE(n) do { \
+ if (plen < n) goto overflow; \
+ p += n; \
+ plen -= n; \
+} while (0)
+
+ if (BIGDECIMAL_NEGATIVE_P(a)) {
+ *p = '-';
+ ADVANCE(1);
+ }
+ else if (fPlus == 1) {
+ *p = ' ';
+ ADVANCE(1);
+ }
+ else if (fPlus == 2) {
+ *p = '+';
+ ADVANCE(1);
+ }
+
+ *p = '0'; ADVANCE(1);
+ *p = '.'; ADVANCE(1);
+
+ n = a->Prec;
+ for (i = 0; i < n; ++i) {
+ m = BASE1;
+ e = a->frac[i];
+ while (m) {
+ nn = e / m;
+ if (!ZeroSup || nn) {
+ /* The reading zero(s) */
+ size_t n = (size_t)snprintf(p, plen, "%lu", (unsigned long)nn);
+ if (n > plen) goto overflow;
+ ADVANCE(n);
+ /* as 0.00xx will be ignored. */
+ ZeroSup = 0; /* Set to print succeeding zeros */
+ }
+ e = e - nn * m;
+ m /= 10;
+ }
+ }
+
+ ex = a->exponent * (ssize_t)BASE_FIG;
+ shift = BASE1;
+ while (a->frac[0] / shift == 0) {
+ --ex;
+ shift /= 10;
+ }
+ while (p - 1 > buf && p[-1] == '0') {
+ *(--p) = '\0';
+ ++plen;
+ }
+ snprintf(p, plen, "e%"PRIdSIZE, ex);
+ if (fFmt) VpFormatSt(buf, fFmt);
+
+ overflow:
+ return;
+#undef ADVANCE
+}
+
+VP_EXPORT void
+VpToFString(Real *a, char *buf, size_t buflen, size_t fFmt, int fPlus)
+/* fPlus = 0: default, 1: set ' ' before digits, 2: set '+' before digits. */
+{
+ size_t i, n;
+ DECDIG m, e, nn;
+ char *p = buf;
+ size_t plen = buflen;
+ ssize_t ex;
+
+ if (VpToSpecialString(a, buf, buflen, fPlus)) return;
+
+#define ADVANCE(n) do { \
+ if (plen < n) goto overflow; \
+ p += n; \
+ plen -= n; \
+} while (0)
+
+
+ if (BIGDECIMAL_NEGATIVE_P(a)) {
+ *p = '-';
+ ADVANCE(1);
+ }
+ else if (fPlus == 1) {
+ *p = ' ';
+ ADVANCE(1);
+ }
+ else if (fPlus == 2) {
+ *p = '+';
+ ADVANCE(1);
+ }
+
+ n = a->Prec;
+ ex = a->exponent;
+ if (ex <= 0) {
+ *p = '0'; ADVANCE(1);
+ *p = '.'; ADVANCE(1);
+ while (ex < 0) {
+ for (i=0; i < BASE_FIG; ++i) {
+ *p = '0'; ADVANCE(1);
+ }
+ ++ex;
+ }
+ ex = -1;
+ }
+
+ for (i = 0; i < n; ++i) {
+ --ex;
+ if (i == 0 && ex >= 0) {
+ size_t n = snprintf(p, plen, "%lu", (unsigned long)a->frac[i]);
+ if (n > plen) goto overflow;
+ ADVANCE(n);
+ }
+ else {
+ m = BASE1;
+ e = a->frac[i];
+ while (m) {
+ nn = e / m;
+ *p = (char)(nn + '0');
+ ADVANCE(1);
+ e = e - nn * m;
+ m /= 10;
+ }
+ }
+ if (ex == 0) {
+ *p = '.';
+ ADVANCE(1);
+ }
+ }
+ while (--ex>=0) {
+ m = BASE;
+ while (m /= 10) {
+ *p = '0';
+ ADVANCE(1);
+ }
+ if (ex == 0) {
+ *p = '.';
+ ADVANCE(1);
+ }
+ }
+
+ *p = '\0';
+ while (p - 1 > buf && p[-1] == '0') {
+ *(--p) = '\0';
+ ++plen;
+ }
+ if (p - 1 > buf && p[-1] == '.') {
+ snprintf(p, plen, "0");
+ }
+ if (fFmt) VpFormatSt(buf, fFmt);
+
+ overflow:
+ return;
+#undef ADVANCE
+}
+
+/*
+ * [Output]
+ * a[] ... variable to be assigned the value.
+ * [Input]
+ * int_chr[] ... integer part(may include '+/-').
+ * ni ... number of characters in int_chr[],not including '+/-'.
+ * frac[] ... fraction part.
+ * nf ... number of characters in frac[].
+ * exp_chr[] ... exponent part(including '+/-').
+ * ne ... number of characters in exp_chr[],not including '+/-'.
+ */
+VP_EXPORT int
+VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne)
+{
+ size_t i, j, ind_a, ma, mi, me;
+ SIGNED_VALUE e, es, eb, ef;
+ int sign, signe, exponent_overflow;
+
+ /* get exponent part */
+ e = 0;
+ ma = a->MaxPrec;
+ mi = ni;
+ me = ne;
+ signe = 1;
+ exponent_overflow = 0;
+ memset(a->frac, 0, ma * sizeof(DECDIG));
+ if (ne > 0) {
+ i = 0;
+ if (exp_chr[0] == '-') {
+ signe = -1;
+ ++i;
+ ++me;
+ }
+ else if (exp_chr[0] == '+') {
+ ++i;
+ ++me;
+ }
+ while (i < me) {
+ if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG)) {
+ es = e;
+ goto exp_overflow;
+ }
+ es = e * (SIGNED_VALUE)BASE_FIG;
+ if (MUL_OVERFLOW_SIGNED_VALUE_P(e, 10) ||
+ SIGNED_VALUE_MAX - (exp_chr[i] - '0') < e * 10)
+ goto exp_overflow;
+ e = e * 10 + exp_chr[i] - '0';
+ if (MUL_OVERFLOW_SIGNED_VALUE_P(e, (SIGNED_VALUE)BASE_FIG))
+ goto exp_overflow;
+ if (es > (SIGNED_VALUE)(e * BASE_FIG)) {
+ exp_overflow:
+ exponent_overflow = 1;
+ e = es; /* keep sign */
+ break;
+ }
+ ++i;
+ }
+ }
+
+ /* get integer part */
+ i = 0;
+ sign = 1;
+ if (1 /*ni >= 0*/) {
+ if (int_chr[0] == '-') {
+ sign = -1;
+ ++i;
+ ++mi;
+ }
+ else if (int_chr[0] == '+') {
+ ++i;
+ ++mi;
+ }
+ }
+
+ e = signe * e; /* e: The value of exponent part. */
+ e = e + ni; /* set actual exponent size. */
+
+ if (e > 0) signe = 1;
+ else signe = -1;
+
+ /* Adjust the exponent so that it is the multiple of BASE_FIG. */
+ j = 0;
+ ef = 1;
+ while (ef) {
+ if (e >= 0) eb = e;
+ else eb = -e;
+ ef = eb / (SIGNED_VALUE)BASE_FIG;
+ ef = eb - ef * (SIGNED_VALUE)BASE_FIG;
+ if (ef) {
+ ++j; /* Means to add one more preceding zero */
+ ++e;
+ }
+ }
+
+ eb = e / (SIGNED_VALUE)BASE_FIG;
+
+ if (exponent_overflow) {
+ int zero = 1;
+ for ( ; i < mi && zero; i++) zero = int_chr[i] == '0';
+ for (i = 0; i < nf && zero; i++) zero = frac[i] == '0';
+ if (!zero && signe > 0) {
+ VpSetInf(a, sign);
+ VpException(VP_EXCEPTION_INFINITY, "exponent overflow",0);
+ }
+ else VpSetZero(a, sign);
+ return 1;
+ }
+
+ ind_a = 0;
+ while (i < mi) {
+ a->frac[ind_a] = 0;
+ while (j < BASE_FIG && i < mi) {
+ a->frac[ind_a] = a->frac[ind_a] * 10 + int_chr[i] - '0';
+ ++j;
+ ++i;
+ }
+ if (i < mi) {
+ ++ind_a;
+ if (ind_a >= ma) goto over_flow;
+ j = 0;
+ }
+ }
+
+ /* get fraction part */
+
+ i = 0;
+ while (i < nf) {
+ while (j < BASE_FIG && i < nf) {
+ a->frac[ind_a] = a->frac[ind_a] * 10 + frac[i] - '0';
+ ++j;
+ ++i;
+ }
+ if (i < nf) {
+ ++ind_a;
+ if (ind_a >= ma) goto over_flow;
+ j = 0;
+ }
+ }
+ goto Final;
+
+over_flow:
+ rb_warn("Conversion from String to BigDecimal overflow (last few digits discarded).");
+
+Final:
+ if (ind_a >= ma) ind_a = ma - 1;
+ while (j < BASE_FIG) {
+ a->frac[ind_a] = a->frac[ind_a] * 10;
+ ++j;
+ }
+ a->Prec = ind_a + 1;
+ a->exponent = eb;
+ VpSetSign(a, sign);
+ VpNmlz(a);
+ return 1;
+}
+
+/*
+ * [Input]
+ * *m ... Real
+ * [Output]
+ * *d ... fraction part of m(d = 0.xxxxxxx). where # of 'x's is fig.
+ * *e ... exponent of m.
+ * BIGDECIMAL_DOUBLE_FIGURES ... Number of digits in a double variable.
+ *
+ * m -> d*10**e, 0<d<BASE
+ * [Returns]
+ * 0 ... Zero
+ * 1 ... Normal
+ * 2 ... Infinity
+ * -1 ... NaN
+ */
+VP_EXPORT int
+VpVtoD(double *d, SIGNED_VALUE *e, Real *m)
+{
+ size_t ind_m, mm, fig;
+ double div;
+ int f = 1;
+
+ if (VpIsNaN(m)) {
+ *d = VpGetDoubleNaN();
+ *e = 0;
+ f = -1; /* NaN */
+ goto Exit;
+ }
+ else if (VpIsPosZero(m)) {
+ *d = 0.0;
+ *e = 0;
+ f = 0;
+ goto Exit;
+ }
+ else if (VpIsNegZero(m)) {
+ *d = VpGetDoubleNegZero();
+ *e = 0;
+ f = 0;
+ goto Exit;
+ }
+ else if (VpIsPosInf(m)) {
+ *d = VpGetDoublePosInf();
+ *e = 0;
+ f = 2;
+ goto Exit;
+ }
+ else if (VpIsNegInf(m)) {
+ *d = VpGetDoubleNegInf();
+ *e = 0;
+ f = 2;
+ goto Exit;
+ }
+ /* Normal number */
+ fig = roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG);
+ ind_m = 0;
+ mm = Min(fig, m->Prec);
+ *d = 0.0;
+ div = 1.;
+ while (ind_m < mm) {
+ div /= (double)BASE;
+ *d = *d + (double)m->frac[ind_m++] * div;
+ }
+ *e = m->exponent * (SIGNED_VALUE)BASE_FIG;
+ *d *= VpGetSign(m);
+
+Exit:
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, " VpVtoD: m=%\n", m);
+ printf(" d=%e * 10 **%ld\n", *d, *e);
+ printf(" BIGDECIMAL_DOUBLE_FIGURES = %d\n", BIGDECIMAL_DOUBLE_FIGURES);
+ }
+#endif /*BIGDECIMAL_DEBUG */
+ return f;
+}
+
+/*
+ * m <- d
+ */
+VP_EXPORT void
+VpDtoV(Real *m, double d)
+{
+ size_t ind_m, mm;
+ SIGNED_VALUE ne;
+ DECDIG i;
+ double val, val2;
+
+ if (isnan(d)) {
+ VpSetNaN(m);
+ goto Exit;
+ }
+ if (isinf(d)) {
+ if (d > 0.0) VpSetPosInf(m);
+ else VpSetNegInf(m);
+ goto Exit;
+ }
+
+ if (d == 0.0) {
+ VpSetZero(m, 1);
+ goto Exit;
+ }
+ val = (d > 0.) ? d : -d;
+ ne = 0;
+ if (val >= 1.0) {
+ while (val >= 1.0) {
+ val /= (double)BASE;
+ ++ne;
+ }
+ }
+ else {
+ val2 = 1.0 / (double)BASE;
+ while (val < val2) {
+ val *= (double)BASE;
+ --ne;
+ }
+ }
+ /* Now val = 0.xxxxx*BASE**ne */
+
+ mm = m->MaxPrec;
+ memset(m->frac, 0, mm * sizeof(DECDIG));
+ for (ind_m = 0; val > 0.0 && ind_m < mm; ind_m++) {
+ val *= (double)BASE;
+ i = (DECDIG)val;
+ val -= (double)i;
+ m->frac[ind_m] = i;
+ }
+ if (ind_m >= mm) ind_m = mm - 1;
+ VpSetSign(m, (d > 0.0) ? 1 : -1);
+ m->Prec = ind_m + 1;
+ m->exponent = ne;
+
+ VpInternalRound(m, 0, (m->Prec > 0) ? m->frac[m->Prec-1] : 0,
+ (DECDIG)(val*(double)BASE));
+
+Exit:
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ printf("VpDtoV d=%30.30e\n", d);
+ VPrint(stdout, " m=%\n", m);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+ return;
+}
+
+/*
+ * m <- ival
+ */
+#if 0 /* unused */
+VP_EXPORT void
+VpItoV(Real *m, SIGNED_VALUE ival)
+{
+ size_t mm, ind_m;
+ size_t val, v1, v2, v;
+ int isign;
+ SIGNED_VALUE ne;
+
+ if (ival == 0) {
+ VpSetZero(m, 1);
+ goto Exit;
+ }
+ isign = 1;
+ val = ival;
+ if (ival < 0) {
+ isign = -1;
+ val =(size_t)(-ival);
+ }
+ ne = 0;
+ ind_m = 0;
+ mm = m->MaxPrec;
+ while (ind_m < mm) {
+ m->frac[ind_m] = 0;
+ ++ind_m;
+ }
+ ind_m = 0;
+ while (val > 0) {
+ if (val) {
+ v1 = val;
+ v2 = 1;
+ while (v1 >= BASE) {
+ v1 /= BASE;
+ v2 *= BASE;
+ }
+ val = val - v2 * v1;
+ v = v1;
+ }
+ else {
+ v = 0;
+ }
+ m->frac[ind_m] = v;
+ ++ind_m;
+ ++ne;
+ }
+ m->Prec = ind_m - 1;
+ m->exponent = ne;
+ VpSetSign(m, isign);
+ VpNmlz(m);
+
+Exit:
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ printf(" VpItoV i=%d\n", ival);
+ VPrint(stdout, " m=%\n", m);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+ return;
+}
+#endif
+
+/*
+ * y = SQRT(x), y*y - x =>0
+ */
+VP_EXPORT int
+VpSqrt(Real *y, Real *x)
+{
+ Real *f = NULL;
+ Real *r = NULL;
+ size_t y_prec;
+ SIGNED_VALUE n, e;
+ SIGNED_VALUE prec;
+ ssize_t nr;
+ double val;
+
+ /* Zero or +Infinity ? */
+ if (VpIsZero(x) || VpIsPosInf(x)) {
+ VpAsgn(y,x,1);
+ goto Exit;
+ }
+
+ /* Negative ? */
+ if (BIGDECIMAL_NEGATIVE_P(x)) {
+ VpSetNaN(y);
+ return VpException(VP_EXCEPTION_OP, "sqrt of negative value", 0);
+ }
+
+ /* NaN ? */
+ if (VpIsNaN(x)) {
+ VpSetNaN(y);
+ return VpException(VP_EXCEPTION_OP, "sqrt of 'NaN'(Not a Number)", 0);
+ }
+
+ /* One ? */
+ if (VpIsOne(x)) {
+ VpSetOne(y);
+ goto Exit;
+ }
+
+ n = (SIGNED_VALUE)y->MaxPrec;
+ if (x->MaxPrec > (size_t)n) n = (ssize_t)x->MaxPrec;
+
+ /* allocate temporally variables */
+ /* TODO: reconsider MaxPrec of f and r */
+ f = NewOneNolimit(1, y->MaxPrec * (BASE_FIG + 2));
+ r = NewOneNolimit(1, (n + n) * (BASE_FIG + 2));
+
+ nr = 0;
+ y_prec = y->MaxPrec;
+
+ prec = x->exponent - (ssize_t)y_prec;
+ if (x->exponent > 0)
+ ++prec;
+ else
+ --prec;
+
+ VpVtoD(&val, &e, x); /* val <- x */
+ e /= (SIGNED_VALUE)BASE_FIG;
+ n = e / 2;
+ if (e - n * 2 != 0) {
+ val /= BASE;
+ n = (e + 1) / 2;
+ }
+ VpDtoV(y, sqrt(val)); /* y <- sqrt(val) */
+ y->exponent += n;
+ n = (SIGNED_VALUE)roomof(BIGDECIMAL_DOUBLE_FIGURES, BASE_FIG);
+ y->MaxPrec = Min((size_t)n , y_prec);
+ f->MaxPrec = y->MaxPrec + 1;
+ n = (SIGNED_VALUE)(y_prec * BASE_FIG);
+ if (n < (SIGNED_VALUE)maxnr) n = (SIGNED_VALUE)maxnr;
+
+ /*
+ * Perform: y_{n+1} = (y_n - x/y_n) / 2
+ */
+ do {
+ y->MaxPrec *= 2;
+ if (y->MaxPrec > y_prec) y->MaxPrec = y_prec;
+ f->MaxPrec = y->MaxPrec;
+ VpDivd(f, r, x, y); /* f = x/y */
+ VpAddSub(r, f, y, -1); /* r = f - y */
+ VpMult(f, VpConstPt5, r); /* f = 0.5*r */
+ if (VpIsZero(f))
+ goto converge;
+ VpAddSub(r, f, y, 1); /* r = y + f */
+ VpAsgn(y, r, 1); /* y = r */
+ } while (++nr < n);
+
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ printf("ERROR(VpSqrt): did not converge within %ld iterations.\n", nr);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+ y->MaxPrec = y_prec;
+
+converge:
+ VpChangeSign(y, 1);
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VpMult(r, y, y);
+ VpAddSub(f, x, r, -1);
+ printf("VpSqrt: iterations = %"PRIdSIZE"\n", nr);
+ VPrint(stdout, " y =% \n", y);
+ VPrint(stdout, " x =% \n", x);
+ VPrint(stdout, " x-y*y = % \n", f);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+ y->MaxPrec = y_prec;
+
+Exit:
+ rbd_free_struct(f);
+ rbd_free_struct(r);
+ return 1;
+}
+
+/*
+ * Round relatively from the decimal point.
+ * f: rounding mode
+ * nf: digit location to round from the decimal point.
+ */
+VP_EXPORT int
+VpMidRound(Real *y, unsigned short f, ssize_t nf)
+{
+ /* fracf: any positive digit under rounding position? */
+ /* fracf_1further: any positive digits under one further than the rounding position? */
+ /* exptoadd: number of digits needed to compensate negative nf */
+ int fracf, fracf_1further;
+ ssize_t n,i,ix,ioffset, exptoadd;
+ DECDIG v, shifter;
+ DECDIG div;
+
+ nf += y->exponent * (ssize_t)BASE_FIG;
+ exptoadd=0;
+ if (nf < 0) {
+ /* rounding position too left(large). */
+ if (f != VP_ROUND_CEIL && f != VP_ROUND_FLOOR) {
+ VpSetZero(y, VpGetSign(y)); /* truncate everything */
+ return 0;
+ }
+ exptoadd = -nf;
+ nf = 0;
+ }
+
+ ix = nf / (ssize_t)BASE_FIG;
+ if ((size_t)ix >= y->Prec) return 0; /* rounding position too right(small). */
+ v = y->frac[ix];
+
+ ioffset = nf - ix*(ssize_t)BASE_FIG;
+ n = (ssize_t)BASE_FIG - ioffset - 1;
+ for (shifter = 1, i = 0; i < n; ++i) shifter *= 10;
+
+ /* so the representation used (in y->frac) is an array of DECDIG, where
+ each DECDIG contains a value between 0 and BASE-1, consisting of BASE_FIG
+ decimal places.
+
+ (that numbers of decimal places are typed as ssize_t is somewhat confusing)
+
+ nf is now position (in decimal places) of the digit from the start of
+ the array.
+
+ ix is the position (in DECDIGs) of the DECDIG containing the decimal digit,
+ from the start of the array.
+
+ v is the value of this DECDIG
+
+ ioffset is the number of extra decimal places along of this decimal digit
+ within v.
+
+ n is the number of decimal digits remaining within v after this decimal digit
+ shifter is 10**n,
+
+ v % shifter are the remaining digits within v
+ v % (shifter * 10) are the digit together with the remaining digits within v
+ v / shifter are the digit's predecessors together with the digit
+ div = v / shifter / 10 is just the digit's precessors
+ (v / shifter) - div*10 is just the digit, which is what v ends up being reassigned to.
+ */
+
+ fracf = (v % (shifter * 10) > 0);
+ fracf_1further = ((v % shifter) > 0);
+
+ v /= shifter;
+ div = v / 10;
+ v = v - div*10;
+ /* now v is just the digit required.
+ now fracf is whether the digit or any of the remaining digits within v are non-zero
+ now fracf_1further is whether any of the remaining digits within v are non-zero
+ */
+
+ /* now check all the remaining DECDIGs for zero-ness a whole DECDIG at a time.
+ if we spot any non-zeroness, that means that we found a positive digit under
+ rounding position, and we also found a positive digit under one further than
+ the rounding position, so both searches (to see if any such non-zero digit exists)
+ can stop */
+
+ for (i = ix + 1; (size_t)i < y->Prec; i++) {
+ if (y->frac[i] % BASE) {
+ fracf = fracf_1further = 1;
+ break;
+ }
+ }
+
+ /* now fracf = does any positive digit exist under the rounding position?
+ now fracf_1further = does any positive digit exist under one further than the
+ rounding position?
+ now v = the first digit under the rounding position */
+
+ /* drop digits after pointed digit */
+ memset(y->frac + ix + 1, 0, (y->Prec - (ix + 1)) * sizeof(DECDIG));
+
+ switch (f) {
+ case VP_ROUND_DOWN: /* Truncate */
+ break;
+ case VP_ROUND_UP: /* Roundup */
+ if (fracf) ++div;
+ break;
+ case VP_ROUND_HALF_UP:
+ if (v>=5) ++div;
+ break;
+ case VP_ROUND_HALF_DOWN:
+ if (v > 5 || (v == 5 && fracf_1further)) ++div;
+ break;
+ case VP_ROUND_CEIL:
+ if (fracf && BIGDECIMAL_POSITIVE_P(y)) ++div;
+ break;
+ case VP_ROUND_FLOOR:
+ if (fracf && BIGDECIMAL_NEGATIVE_P(y)) ++div;
+ break;
+ case VP_ROUND_HALF_EVEN: /* Banker's rounding */
+ if (v > 5) ++div;
+ else if (v == 5) {
+ if (fracf_1further) {
+ ++div;
+ }
+ else {
+ if (ioffset == 0) {
+ /* v is the first decimal digit of its DECDIG;
+ need to grab the previous DECDIG if present
+ to check for evenness of the previous decimal
+ digit (which is same as that of the DECDIG since
+ base 10 has a factor of 2) */
+ if (ix && (y->frac[ix-1] % 2)) ++div;
+ }
+ else {
+ if (div % 2) ++div;
+ }
+ }
+ }
+ break;
+ }
+ for (i = 0; i <= n; ++i) div *= 10;
+ if (div >= BASE) {
+ if (ix) {
+ y->frac[ix] = 0;
+ VpRdup(y, ix);
+ }
+ else {
+ short s = VpGetSign(y);
+ SIGNED_VALUE e = y->exponent;
+ VpSetOne(y);
+ VpSetSign(y, s);
+ y->exponent = e + 1;
+ }
+ }
+ else {
+ y->frac[ix] = div;
+ VpNmlz(y);
+ }
+ if (exptoadd > 0) {
+ y->exponent += (SIGNED_VALUE)(exptoadd / BASE_FIG);
+ exptoadd %= (ssize_t)BASE_FIG;
+ for (i = 0; i < exptoadd; i++) {
+ y->frac[0] *= 10;
+ if (y->frac[0] >= BASE) {
+ y->frac[0] /= BASE;
+ y->exponent++;
+ }
+ }
+ }
+ return 1;
+}
+
+VP_EXPORT int
+VpLeftRound(Real *y, unsigned short f, ssize_t nf)
+/*
+ * Round from the left hand side of the digits.
+ */
+{
+ DECDIG v;
+ if (!VpHasVal(y)) return 0; /* Unable to round */
+ v = y->frac[0];
+ nf -= VpExponent(y) * (ssize_t)BASE_FIG;
+ while ((v /= 10) != 0) nf--;
+ nf += (ssize_t)BASE_FIG-1;
+ return VpMidRound(y, f, nf);
+}
+
+VP_EXPORT int
+VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t nf)
+{
+ /* First,assign whole value in truncation mode */
+ if (VpAsgn(y, x, 10) <= 1) return 0; /* Zero,NaN,or Infinity */
+ return VpMidRound(y, f, nf);
+}
+
+static int
+VpLimitRound(Real *c, size_t ixDigit)
+{
+ size_t ix = VpGetPrecLimit();
+ if (!VpNmlz(c)) return -1;
+ if (!ix) return 0;
+ if (!ixDigit) ixDigit = c->Prec-1;
+ if ((ix + BASE_FIG - 1) / BASE_FIG > ixDigit + 1) return 0;
+ return VpLeftRound(c, VpGetRoundMode(), (ssize_t)ix);
+}
+
+/* If I understand correctly, this is only ever used to round off the final decimal
+ digit of precision */
+static void
+VpInternalRound(Real *c, size_t ixDigit, DECDIG vPrev, DECDIG v)
+{
+ int f = 0;
+
+ unsigned short const rounding_mode = VpGetRoundMode();
+
+ if (VpLimitRound(c, ixDigit)) return;
+ if (!v) return;
+
+ v /= BASE1;
+ switch (rounding_mode) {
+ case VP_ROUND_DOWN:
+ break;
+ case VP_ROUND_UP:
+ if (v) f = 1;
+ break;
+ case VP_ROUND_HALF_UP:
+ if (v >= 5) f = 1;
+ break;
+ case VP_ROUND_HALF_DOWN:
+ /* this is ok - because this is the last digit of precision,
+ the case where v == 5 and some further digits are nonzero
+ will never occur */
+ if (v >= 6) f = 1;
+ break;
+ case VP_ROUND_CEIL:
+ if (v && BIGDECIMAL_POSITIVE_P(c)) f = 1;
+ break;
+ case VP_ROUND_FLOOR:
+ if (v && BIGDECIMAL_NEGATIVE_P(c)) f = 1;
+ break;
+ case VP_ROUND_HALF_EVEN: /* Banker's rounding */
+ /* as per VP_ROUND_HALF_DOWN, because this is the last digit of precision,
+ there is no case to worry about where v == 5 and some further digits are nonzero */
+ if (v > 5) f = 1;
+ else if (v == 5 && vPrev % 2) f = 1;
+ break;
+ }
+ if (f) {
+ VpRdup(c, ixDigit);
+ VpNmlz(c);
+ }
+}
+
+/*
+ * Rounds up m(plus one to final digit of m).
+ */
+static int
+VpRdup(Real *m, size_t ind_m)
+{
+ DECDIG carry;
+
+ if (!ind_m) ind_m = m->Prec;
+
+ carry = 1;
+ while (carry > 0 && ind_m--) {
+ m->frac[ind_m] += carry;
+ if (m->frac[ind_m] >= BASE) m->frac[ind_m] -= BASE;
+ else carry = 0;
+ }
+ if (carry > 0) { /* Overflow,count exponent and set fraction part be 1 */
+ if (!AddExponent(m, 1)) return 0;
+ m->Prec = m->frac[0] = 1;
+ }
+ else {
+ VpNmlz(m);
+ }
+ return 1;
+}
+
+/*
+ * y = x - fix(x)
+ */
+VP_EXPORT void
+VpFrac(Real *y, Real *x)
+{
+ size_t my, ind_y, ind_x;
+
+ if (!VpHasVal(x)) {
+ VpAsgn(y, x, 1);
+ goto Exit;
+ }
+
+ if (x->exponent > 0 && (size_t)x->exponent >= x->Prec) {
+ VpSetZero(y, VpGetSign(x));
+ goto Exit;
+ }
+ else if (x->exponent <= 0) {
+ VpAsgn(y, x, 1);
+ goto Exit;
+ }
+
+ /* satisfy: x->exponent > 0 */
+
+ y->Prec = x->Prec - (size_t)x->exponent;
+ y->Prec = Min(y->Prec, y->MaxPrec);
+ y->exponent = 0;
+ VpSetSign(y, VpGetSign(x));
+ ind_y = 0;
+ my = y->Prec;
+ ind_x = x->exponent;
+ while (ind_y < my) {
+ y->frac[ind_y] = x->frac[ind_x];
+ ++ind_y;
+ ++ind_x;
+ }
+ VpNmlz(y);
+
+Exit:
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, "VpFrac y=%\n", y);
+ VPrint(stdout, " x=%\n", x);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+ return;
+}
+
+/*
+ * y = x ** n
+ */
+VP_EXPORT int
+VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n)
+{
+ size_t s, ss;
+ ssize_t sign;
+ Real *w1 = NULL;
+ Real *w2 = NULL;
+
+ if (VpIsZero(x)) {
+ if (n == 0) {
+ VpSetOne(y);
+ goto Exit;
+ }
+ sign = VpGetSign(x);
+ if (n < 0) {
+ n = -n;
+ if (sign < 0) sign = (n % 2) ? -1 : 1;
+ VpSetInf(y, sign);
+ }
+ else {
+ if (sign < 0) sign = (n % 2) ? -1 : 1;
+ VpSetZero(y,sign);
+ }
+ goto Exit;
+ }
+ if (VpIsNaN(x)) {
+ VpSetNaN(y);
+ goto Exit;
+ }
+ if (VpIsInf(x)) {
+ if (n == 0) {
+ VpSetOne(y);
+ goto Exit;
+ }
+ if (n > 0) {
+ VpSetInf(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
+ goto Exit;
+ }
+ VpSetZero(y, (n % 2 == 0 || VpIsPosInf(x)) ? 1 : -1);
+ goto Exit;
+ }
+
+ if (x->exponent == 1 && x->Prec == 1 && x->frac[0] == 1) {
+ /* abs(x) = 1 */
+ VpSetOne(y);
+ if (BIGDECIMAL_POSITIVE_P(x)) goto Exit;
+ if ((n % 2) == 0) goto Exit;
+ VpSetSign(y, -1);
+ goto Exit;
+ }
+
+ if (n > 0) sign = 1;
+ else if (n < 0) {
+ sign = -1;
+ n = -n;
+ }
+ else {
+ VpSetOne(y);
+ goto Exit;
+ }
+
+ /* Allocate working variables */
+ /* TODO: reconsider MaxPrec of w1 and w2 */
+ w1 = NewZeroNolimit(1, (y->MaxPrec + 2) * BASE_FIG);
+ w2 = NewZeroNolimit(1, (w1->MaxPrec * 2 + 1) * BASE_FIG);
+
+ /* calculation start */
+
+ VpAsgn(y, x, 1);
+ --n;
+ while (n > 0) {
+ VpAsgn(w1, x, 1);
+ s = 1;
+ while (ss = s, (s += s) <= (size_t)n) {
+ VpMult(w2, w1, w1);
+ VpAsgn(w1, w2, 1);
+ }
+ n -= (SIGNED_VALUE)ss;
+ VpMult(w2, y, w1);
+ VpAsgn(y, w2, 1);
+ }
+ if (sign < 0) {
+ VpDivd(w1, w2, VpConstOne, y);
+ VpAsgn(y, w1, 1);
+ }
+
+Exit:
+#ifdef BIGDECIMAL_DEBUG
+ if (gfDebug) {
+ VPrint(stdout, "VpPowerByInt y=%\n", y);
+ VPrint(stdout, "VpPowerByInt x=%\n", x);
+ printf(" n=%"PRIdVALUE"\n", n);
+ }
+#endif /* BIGDECIMAL_DEBUG */
+ rbd_free_struct(w2);
+ rbd_free_struct(w1);
+ return 1;
+}
+
+#ifdef BIGDECIMAL_DEBUG
+int
+VpVarCheck(Real * v)
+/*
+ * Checks the validity of the Real variable v.
+ * [Input]
+ * v ... Real *, variable to be checked.
+ * [Returns]
+ * 0 ... correct v.
+ * other ... error
+ */
+{
+ size_t i;
+
+ if (v->MaxPrec == 0) {
+ printf("ERROR(VpVarCheck): Illegal Max. Precision(=%"PRIuSIZE")\n",
+ v->MaxPrec);
+ return 1;
+ }
+ if (v->Prec == 0 || v->Prec > v->MaxPrec) {
+ printf("ERROR(VpVarCheck): Illegal Precision(=%"PRIuSIZE")\n", v->Prec);
+ printf(" Max. Prec.=%"PRIuSIZE"\n", v->MaxPrec);
+ return 2;
+ }
+ for (i = 0; i < v->Prec; ++i) {
+ if (v->frac[i] >= BASE) {
+ printf("ERROR(VpVarCheck): Illegal fraction\n");
+ printf(" Frac[%"PRIuSIZE"]=%"PRIuDECDIG"\n", i, v->frac[i]);
+ printf(" Prec. =%"PRIuSIZE"\n", v->Prec);
+ printf(" Exp. =%"PRIdVALUE"\n", v->exponent);
+ printf(" BASE =%"PRIuDECDIG"\n", BASE);
+ return 3;
+ }
+ }
+ return 0;
+}
+#endif /* BIGDECIMAL_DEBUG */
diff --git a/ext/bigdecimal/bigdecimal.gemspec b/ext/bigdecimal/bigdecimal.gemspec
new file mode 100644
index 0000000000..d215757188
--- /dev/null
+++ b/ext/bigdecimal/bigdecimal.gemspec
@@ -0,0 +1,38 @@
+# coding: utf-8
+
+Gem::Specification.new do |s|
+ s.name = "bigdecimal"
+ s.version = "3.1.3"
+ s.authors = ["Kenta Murata", "Zachary Scott", "Shigeo Kobayashi"]
+ s.email = ["mrkn@mrkn.jp"]
+
+ s.summary = "Arbitrary-precision decimal floating-point number library."
+ s.description = "This library provides arbitrary-precision decimal floating-point number class."
+ s.homepage = "https://github.com/ruby/bigdecimal"
+ s.licenses = ["Ruby", "bsd-2-clause"]
+
+ s.require_paths = %w[lib]
+ s.extensions = %w[ext/bigdecimal/extconf.rb]
+ s.files = %w[
+ bigdecimal.gemspec
+ ext/bigdecimal/bigdecimal.c
+ ext/bigdecimal/bigdecimal.h
+ ext/bigdecimal/bits.h
+ ext/bigdecimal/feature.h
+ ext/bigdecimal/missing.c
+ ext/bigdecimal/missing.h
+ ext/bigdecimal/missing/dtoa.c
+ ext/bigdecimal/static_assert.h
+ lib/bigdecimal.rb
+ lib/bigdecimal/jacobian.rb
+ lib/bigdecimal/ludcmp.rb
+ lib/bigdecimal/math.rb
+ lib/bigdecimal/newton.rb
+ lib/bigdecimal/util.rb
+ sample/linear.rb
+ sample/nlsolve.rb
+ sample/pi.rb
+ ]
+
+ s.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
+end
diff --git a/ext/bigdecimal/bigdecimal.h b/ext/bigdecimal/bigdecimal.h
new file mode 100644
index 0000000000..54fed811fb
--- /dev/null
+++ b/ext/bigdecimal/bigdecimal.h
@@ -0,0 +1,313 @@
+/*
+ *
+ * Ruby BigDecimal(Variable decimal precision) extension library.
+ *
+ * Copyright(C) 2002 by Shigeo Kobayashi(shigeo@tinyforest.gr.jp)
+ *
+ */
+
+#ifndef RUBY_BIG_DECIMAL_H
+#define RUBY_BIG_DECIMAL_H 1
+
+#define RUBY_NO_OLD_COMPATIBILITY
+#include "ruby/ruby.h"
+#include "missing.h"
+
+#ifdef HAVE_FLOAT_H
+# include <float.h>
+#endif
+
+#ifdef HAVE_INT64_T
+# define DECDIG uint32_t
+# define DECDIG_DBL uint64_t
+# define DECDIG_DBL_SIGNED int64_t
+# define SIZEOF_DECDIG 4
+# define PRI_DECDIG_PREFIX ""
+# ifdef PRI_LL_PREFIX
+# define PRI_DECDIG_DBL_PREFIX PRI_LL_PREFIX
+# else
+# define PRI_DECDIG_DBL_PREFIX "l"
+# endif
+#else
+# define DECDIG uint16_t
+# define DECDIG_DBL uint32_t
+# define DECDIG_DBL_SIGNED int32_t
+# define SIZEOF_DECDIG 2
+# define PRI_DECDIG_PREFIX "h"
+# define PRI_DECDIG_DBL_PREFIX ""
+#endif
+
+#define PRIdDECDIG PRI_DECDIG_PREFIX"d"
+#define PRIiDECDIG PRI_DECDIG_PREFIX"i"
+#define PRIoDECDIG PRI_DECDIG_PREFIX"o"
+#define PRIuDECDIG PRI_DECDIG_PREFIX"u"
+#define PRIxDECDIG PRI_DECDIG_PREFIX"x"
+#define PRIXDECDIG PRI_DECDIG_PREFIX"X"
+
+#define PRIdDECDIG_DBL PRI_DECDIG_DBL_PREFIX"d"
+#define PRIiDECDIG_DBL PRI_DECDIG_DBL_PREFIX"i"
+#define PRIoDECDIG_DBL PRI_DECDIG_DBL_PREFIX"o"
+#define PRIuDECDIG_DBL PRI_DECDIG_DBL_PREFIX"u"
+#define PRIxDECDIG_DBL PRI_DECDIG_DBL_PREFIX"x"
+#define PRIXDECDIG_DBL PRI_DECDIG_DBL_PREFIX"X"
+
+#if SIZEOF_DECDIG == 4
+# define BIGDECIMAL_BASE ((DECDIG)1000000000U)
+# define BIGDECIMAL_COMPONENT_FIGURES 9
+/*
+ * The number of components required for a 64-bit integer.
+ *
+ * INT64_MAX: 9_223372036_854775807
+ * UINT64_MAX: 18_446744073_709551615
+ */
+# define BIGDECIMAL_INT64_MAX_LENGTH 3
+
+#elif SIZEOF_DECDIG == 2
+# define BIGDECIMAL_BASE ((DECDIG)10000U)
+# define BIGDECIMAL_COMPONENT_FIGURES 4
+/*
+ * The number of components required for a 64-bit integer.
+ *
+ * INT64_MAX: 922_3372_0368_5477_5807
+ * UINT64_MAX: 1844_6744_0737_0955_1615
+ */
+# define BIGDECIMAL_INT64_MAX_LENGTH 5
+
+#else
+# error Unknown size of DECDIG
+#endif
+
+#define BIGDECIMAL_DOUBLE_FIGURES (1+DBL_DIG)
+
+#if defined(__cplusplus)
+extern "C" {
+#if 0
+} /* satisfy cc-mode */
+#endif
+#endif
+
+extern VALUE rb_cBigDecimal;
+
+/*
+ * NaN & Infinity
+ */
+#define SZ_NaN "NaN"
+#define SZ_INF "Infinity"
+#define SZ_PINF "+Infinity"
+#define SZ_NINF "-Infinity"
+
+/*
+ * #define VP_EXPORT other than static to let VP_ routines
+ * be called from outside of this module.
+ */
+#define VP_EXPORT static
+
+/* Exception mode */
+#define VP_EXCEPTION_ALL ((unsigned short)0x00FF)
+#define VP_EXCEPTION_INFINITY ((unsigned short)0x0001)
+#define VP_EXCEPTION_NaN ((unsigned short)0x0002)
+#define VP_EXCEPTION_UNDERFLOW ((unsigned short)0x0004)
+#define VP_EXCEPTION_OVERFLOW ((unsigned short)0x0001) /* 0x0008) */
+#define VP_EXCEPTION_ZERODIVIDE ((unsigned short)0x0010)
+
+/* Following 2 exceptions can't controlled by user */
+#define VP_EXCEPTION_OP ((unsigned short)0x0020)
+
+#define BIGDECIMAL_EXCEPTION_MODE_DEFAULT 0U
+
+/* This is used in BigDecimal#mode */
+#define VP_ROUND_MODE ((unsigned short)0x0100)
+
+/* Rounding mode */
+#define VP_ROUND_UP RBD_ROUND_UP
+#define VP_ROUND_DOWN RBD_ROUND_DOWN
+#define VP_ROUND_HALF_UP RBD_ROUND_HALF_UP
+#define VP_ROUND_HALF_DOWN RBD_ROUND_HALF_DOWN
+#define VP_ROUND_CEIL RBD_ROUND_CEIL
+#define VP_ROUND_FLOOR RBD_ROUND_FLOOR
+#define VP_ROUND_HALF_EVEN RBD_ROUND_HALF_EVEN
+
+enum rbd_rounding_mode {
+ RBD_ROUND_UP = 1,
+ RBD_ROUND_DOWN = 2,
+ RBD_ROUND_HALF_UP = 3,
+ RBD_ROUND_HALF_DOWN = 4,
+ RBD_ROUND_CEIL = 5,
+ RBD_ROUND_FLOOR = 6,
+ RBD_ROUND_HALF_EVEN = 7,
+
+ RBD_ROUND_DEFAULT = RBD_ROUND_HALF_UP,
+ RBD_ROUND_TRUNCATE = RBD_ROUND_DOWN,
+ RBD_ROUND_BANKER = RBD_ROUND_HALF_EVEN,
+ RBD_ROUND_CEILING = RBD_ROUND_CEIL
+};
+
+#define BIGDECIMAL_ROUNDING_MODE_DEFAULT VP_ROUND_HALF_UP
+
+/* Sign flag */
+#define VP_SIGN_NaN 0 /* NaN */
+#define VP_SIGN_POSITIVE_ZERO 1 /* Positive zero */
+#define VP_SIGN_NEGATIVE_ZERO -1 /* Negative zero */
+#define VP_SIGN_POSITIVE_FINITE 2 /* Positive finite number */
+#define VP_SIGN_NEGATIVE_FINITE -2 /* Negative finite number */
+#define VP_SIGN_POSITIVE_INFINITE 3 /* Positive infinite number */
+#define VP_SIGN_NEGATIVE_INFINITE -3 /* Negative infinite number */
+
+/* The size of fraction part array */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+#define FLEXIBLE_ARRAY_SIZE /* */
+#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
+#define FLEXIBLE_ARRAY_SIZE 0
+#else
+#define FLEXIBLE_ARRAY_SIZE 1
+#endif
+
+/*
+ * VP representation
+ * r = 0.xxxxxxxxx *BASE**exponent
+ */
+typedef struct {
+ VALUE obj; /* Back pointer(VALUE) for Ruby object. */
+ size_t MaxPrec; /* Maximum precision size */
+ /* This is the actual size of frac[] */
+ /*(frac[0] to frac[MaxPrec] are available). */
+ size_t Prec; /* Current precision size. */
+ /* This indicates how much the */
+ /* array frac[] is actually used. */
+ SIGNED_VALUE exponent; /* Exponent part. */
+ short sign; /* Attributes of the value. */
+ /*
+ * ==0 : NaN
+ * 1 : Positive zero
+ * -1 : Negative zero
+ * 2 : Positive number
+ * -2 : Negative number
+ * 3 : Positive infinite number
+ * -3 : Negative infinite number
+ */
+ short flag; /* Not used in vp_routines,space for user. */
+ DECDIG frac[FLEXIBLE_ARRAY_SIZE]; /* Array of fraction part. */
+} Real;
+
+/*
+ * ------------------
+ * EXPORTables.
+ * ------------------
+ */
+
+VP_EXPORT Real *VpNewRbClass(size_t mx, char const *str, VALUE klass, bool strict_p, bool raise_exception);
+
+VP_EXPORT Real *VpCreateRbObject(size_t mx, const char *str, bool raise_exception);
+
+#define VpBaseFig() BIGDECIMAL_COMPONENT_FIGURES
+#define VpDblFig() BIGDECIMAL_DOUBLE_FIGURES
+#define VpBaseVal() BIGDECIMAL_BASE
+
+/* Zero,Inf,NaN (isinf(),isnan() used to check) */
+VP_EXPORT double VpGetDoubleNaN(void);
+VP_EXPORT double VpGetDoublePosInf(void);
+VP_EXPORT double VpGetDoubleNegInf(void);
+VP_EXPORT double VpGetDoubleNegZero(void);
+
+/* These 2 functions added at v1.1.7 */
+VP_EXPORT size_t VpGetPrecLimit(void);
+VP_EXPORT size_t VpSetPrecLimit(size_t n);
+
+/* Round mode */
+VP_EXPORT int VpIsRoundMode(unsigned short n);
+VP_EXPORT unsigned short VpGetRoundMode(void);
+VP_EXPORT unsigned short VpSetRoundMode(unsigned short n);
+
+VP_EXPORT int VpException(unsigned short f,const char *str,int always);
+#if 0 /* unused */
+VP_EXPORT int VpIsNegDoubleZero(double v);
+#endif
+VP_EXPORT size_t VpNumOfChars(Real *vp,const char *pszFmt);
+VP_EXPORT size_t VpInit(DECDIG BaseVal);
+VP_EXPORT Real *VpAlloc(size_t mx, const char *szVal, int strict_p, int exc);
+VP_EXPORT size_t VpAsgn(Real *c, Real *a, int isw);
+VP_EXPORT size_t VpAddSub(Real *c,Real *a,Real *b,int operation);
+VP_EXPORT size_t VpMult(Real *c,Real *a,Real *b);
+VP_EXPORT size_t VpDivd(Real *c,Real *r,Real *a,Real *b);
+VP_EXPORT int VpComp(Real *a,Real *b);
+VP_EXPORT ssize_t VpExponent10(Real *a);
+VP_EXPORT void VpSzMantissa(Real *a, char *buf, size_t bufsize);
+VP_EXPORT int VpToSpecialString(Real *a, char *buf, size_t bufsize, int fPlus);
+VP_EXPORT void VpToString(Real *a, char *buf, size_t bufsize, size_t fFmt, int fPlus);
+VP_EXPORT void VpToFString(Real *a, char *buf, size_t bufsize, size_t fFmt, int fPlus);
+VP_EXPORT int VpCtoV(Real *a, const char *int_chr, size_t ni, const char *frac, size_t nf, const char *exp_chr, size_t ne);
+VP_EXPORT int VpVtoD(double *d, SIGNED_VALUE *e, Real *m);
+VP_EXPORT void VpDtoV(Real *m,double d);
+#if 0 /* unused */
+VP_EXPORT void VpItoV(Real *m,S_INT ival);
+#endif
+VP_EXPORT int VpSqrt(Real *y,Real *x);
+VP_EXPORT int VpActiveRound(Real *y, Real *x, unsigned short f, ssize_t il);
+VP_EXPORT int VpMidRound(Real *y, unsigned short f, ssize_t nf);
+VP_EXPORT int VpLeftRound(Real *y, unsigned short f, ssize_t nf);
+VP_EXPORT void VpFrac(Real *y, Real *x);
+VP_EXPORT int VpPowerByInt(Real *y, Real *x, SIGNED_VALUE n);
+#define VpPower VpPowerByInt
+
+/* VP constants */
+VP_EXPORT Real *VpOne(void);
+
+/*
+ * ------------------
+ * MACRO definitions.
+ * ------------------
+ */
+#define Abs(a) (((a)>= 0)?(a):(-(a)))
+#define Max(a, b) (((a)>(b))?(a):(b))
+#define Min(a, b) (((a)>(b))?(b):(a))
+
+#define VpMaxPrec(a) ((a)->MaxPrec)
+#define VpPrec(a) ((a)->Prec)
+#define VpGetFlag(a) ((a)->flag)
+
+/* Sign */
+
+/* VpGetSign(a) returns 1,-1 if a>0,a<0 respectively */
+#define VpGetSign(a) (((a)->sign>0)?1:(-1))
+/* Change sign of a to a>0,a<0 if s = 1,-1 respectively */
+#define VpChangeSign(a,s) {if((s)>0) (a)->sign=(short)Abs((ssize_t)(a)->sign);else (a)->sign=-(short)Abs((ssize_t)(a)->sign);}
+/* Sets sign of a to a>0,a<0 if s = 1,-1 respectively */
+#define VpSetSign(a,s) {if((s)>0) (a)->sign=(short)VP_SIGN_POSITIVE_FINITE;else (a)->sign=(short)VP_SIGN_NEGATIVE_FINITE;}
+
+/* 1 */
+#define VpSetOne(a) {(a)->Prec=(a)->exponent=(a)->frac[0]=1;(a)->sign=VP_SIGN_POSITIVE_FINITE;}
+
+/* ZEROs */
+#define VpIsPosZero(a) ((a)->sign==VP_SIGN_POSITIVE_ZERO)
+#define VpIsNegZero(a) ((a)->sign==VP_SIGN_NEGATIVE_ZERO)
+#define VpIsZero(a) (VpIsPosZero(a) || VpIsNegZero(a))
+#define VpSetPosZero(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_POSITIVE_ZERO)
+#define VpSetNegZero(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NEGATIVE_ZERO)
+#define VpSetZero(a,s) (void)(((s)>0)?VpSetPosZero(a):VpSetNegZero(a))
+
+/* NaN */
+#define VpIsNaN(a) ((a)->sign==VP_SIGN_NaN)
+#define VpSetNaN(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NaN)
+
+/* Infinity */
+#define VpIsPosInf(a) ((a)->sign==VP_SIGN_POSITIVE_INFINITE)
+#define VpIsNegInf(a) ((a)->sign==VP_SIGN_NEGATIVE_INFINITE)
+#define VpIsInf(a) (VpIsPosInf(a) || VpIsNegInf(a))
+#define VpIsDef(a) ( !(VpIsNaN(a)||VpIsInf(a)) )
+#define VpSetPosInf(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_POSITIVE_INFINITE)
+#define VpSetNegInf(a) ((a)->frac[0]=0,(a)->Prec=1,(a)->sign=VP_SIGN_NEGATIVE_INFINITE)
+#define VpSetInf(a,s) (void)(((s)>0)?VpSetPosInf(a):VpSetNegInf(a))
+#define VpHasVal(a) (a->frac[0])
+#define VpIsOne(a) ((a->Prec==1)&&(a->frac[0]==1)&&(a->exponent==1))
+#define VpExponent(a) (a->exponent)
+#ifdef BIGDECIMAL_DEBUG
+int VpVarCheck(Real * v);
+#endif /* BIGDECIMAL_DEBUG */
+
+#if defined(__cplusplus)
+#if 0
+{ /* satisfy cc-mode */
+#endif
+} /* extern "C" { */
+#endif
+#endif /* RUBY_BIG_DECIMAL_H */
diff --git a/ext/bigdecimal/bits.h b/ext/bigdecimal/bits.h
new file mode 100644
index 0000000000..6e1e4776e3
--- /dev/null
+++ b/ext/bigdecimal/bits.h
@@ -0,0 +1,141 @@
+#ifndef BIGDECIMAL_BITS_H
+#define BIGDECIMAL_BITS_H
+
+#include "feature.h"
+#include "static_assert.h"
+
+#if defined(__x86_64__) && defined(HAVE_X86INTRIN_H)
+# include <x86intrin.h> /* for _lzcnt_u64, etc. */
+#elif defined(_MSC_VER) && defined(HAVE_INTRIN_H)
+# include <intrin.h> /* for the following intrinsics */
+#endif
+
+#if defined(_MSC_VER) && defined(__AVX2__)
+# pragma intrinsic(__lzcnt)
+# pragma intrinsic(__lzcnt64)
+#endif
+
+#define numberof(array) ((int)(sizeof(array) / sizeof((array)[0])))
+#define roomof(x, y) (((x) + (y) - 1) / (y))
+#define type_roomof(x, y) roomof(sizeof(x), sizeof(y))
+
+#define MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
+ (a) == 0 ? 0 : \
+ (a) == -1 ? (b) < -(max) : \
+ (a) > 0 ? \
+ ((b) > 0 ? (max) / (a) < (b) : (min) / (a) > (b)) : \
+ ((b) > 0 ? (min) / (a) < (b) : (max) / (a) > (b)))
+
+#ifdef HAVE_UINT128_T
+# define bit_length(x) \
+ (unsigned int) \
+ (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \
+ sizeof(x) <= sizeof(int64_t) ? 64 - nlz_int64((uint64_t)(x)) : \
+ 128 - nlz_int128((uint128_t)(x)))
+#else
+# define bit_length(x) \
+ (unsigned int) \
+ (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \
+ 64 - nlz_int64((uint64_t)(x)))
+#endif
+
+static inline unsigned nlz_int32(uint32_t x);
+static inline unsigned nlz_int64(uint64_t x);
+#ifdef HAVE_UINT128_T
+static inline unsigned nlz_int128(uint128_t x);
+#endif
+
+static inline unsigned int
+nlz_int32(uint32_t x)
+{
+#if defined(_MSC_VER) && defined(__AVX2__) && defined(HAVE___LZCNT)
+ /* Note: It seems there is no such thing like __LZCNT__ predefined in MSVC.
+ * AMD CPUs have had this instruction for decades (since K10) but for
+ * Intel, Haswell is the oldest one. We need to use __AVX2__ for maximum
+ * safety. */
+ return (unsigned int)__lzcnt(x);
+
+#elif defined(__x86_64__) && defined(__LZCNT__) && defined(HAVE__LZCNT_U32)
+ return (unsigned int)_lzcnt_u32(x);
+
+#elif defined(_MSC_VER) && defined(HAVE__BITSCANREVERSE)
+ unsigned long r;
+ return _BitScanReverse(&r, x) ? (31 - (int)r) : 32;
+
+#elif __has_builtin(__builtin_clz)
+ STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT == 32);
+ return x ? (unsigned int)__builtin_clz(x) : 32;
+
+#else
+ uint32_t y;
+ unsigned n = 32;
+ y = x >> 16; if (y) {n -= 16; x = y;}
+ y = x >> 8; if (y) {n -= 8; x = y;}
+ y = x >> 4; if (y) {n -= 4; x = y;}
+ y = x >> 2; if (y) {n -= 2; x = y;}
+ y = x >> 1; if (y) {return n - 2;}
+ return (unsigned int)(n - x);
+#endif
+}
+
+static inline unsigned int
+nlz_int64(uint64_t x)
+{
+#if defined(_MSC_VER) && defined(__AVX2__) && defined(HAVE___LZCNT64)
+ return (unsigned int)__lzcnt64(x);
+
+#elif defined(__x86_64__) && defined(__LZCNT__) && defined(HAVE__LZCNT_U64)
+ return (unsigned int)_lzcnt_u64(x);
+
+#elif defined(_WIN64) && defined(_MSC_VER) && defined(HAVE__BITSCANREVERSE64)
+ unsigned long r;
+ return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64;
+
+#elif __has_builtin(__builtin_clzl) && __has_builtin(__builtin_clzll) && !(defined(__sun) && defined(__sparc))
+ if (x == 0) {
+ return 64;
+ }
+ else if (sizeof(long) * CHAR_BIT == 64) {
+ return (unsigned int)__builtin_clzl((unsigned long)x);
+ }
+ else if (sizeof(long long) * CHAR_BIT == 64) {
+ return (unsigned int)__builtin_clzll((unsigned long long)x);
+ }
+ else {
+ /* :FIXME: Is there a way to make this branch a compile-time error? */
+ __builtin_unreachable();
+ }
+
+#else
+ uint64_t y;
+ unsigned int n = 64;
+ y = x >> 32; if (y) {n -= 32; x = y;}
+ y = x >> 16; if (y) {n -= 16; x = y;}
+ y = x >> 8; if (y) {n -= 8; x = y;}
+ y = x >> 4; if (y) {n -= 4; x = y;}
+ y = x >> 2; if (y) {n -= 2; x = y;}
+ y = x >> 1; if (y) {return n - 2;}
+ return (unsigned int)(n - x);
+
+#endif
+}
+
+#ifdef HAVE_UINT128_T
+static inline unsigned int
+nlz_int128(uint128_t x)
+{
+ uint64_t y = (uint64_t)(x >> 64);
+
+ if (x == 0) {
+ return 128;
+ }
+ else if (y == 0) {
+ return (unsigned int)nlz_int64(x) + 64;
+ }
+ else {
+ return (unsigned int)nlz_int64(y);
+ }
+}
+#endif
+
+#endif /* BIGDECIMAL_BITS_H */
diff --git a/ext/bigdecimal/depend b/ext/bigdecimal/depend
new file mode 100644
index 0000000000..ee892162f2
--- /dev/null
+++ b/ext/bigdecimal/depend
@@ -0,0 +1,330 @@
+extconf.h: $(srcdir)/$(GEMSPEC)
+Makefile: $(BIGDECIMAL_RB)
+
+# AUTOGENERATED DEPENDENCIES START
+bigdecimal.o: $(RUBY_EXTCONF_H)
+bigdecimal.o: $(arch_hdrdir)/ruby/config.h
+bigdecimal.o: $(hdrdir)/ruby/assert.h
+bigdecimal.o: $(hdrdir)/ruby/backward/2/assume.h
+bigdecimal.o: $(hdrdir)/ruby/backward/2/attributes.h
+bigdecimal.o: $(hdrdir)/ruby/backward/2/bool.h
+bigdecimal.o: $(hdrdir)/ruby/backward/2/inttypes.h
+bigdecimal.o: $(hdrdir)/ruby/backward/2/limits.h
+bigdecimal.o: $(hdrdir)/ruby/backward/2/long_long.h
+bigdecimal.o: $(hdrdir)/ruby/backward/2/stdalign.h
+bigdecimal.o: $(hdrdir)/ruby/backward/2/stdarg.h
+bigdecimal.o: $(hdrdir)/ruby/defines.h
+bigdecimal.o: $(hdrdir)/ruby/intern.h
+bigdecimal.o: $(hdrdir)/ruby/internal/abi.h
+bigdecimal.o: $(hdrdir)/ruby/internal/anyargs.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+bigdecimal.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+bigdecimal.o: $(hdrdir)/ruby/internal/assume.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/artificial.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/cold.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/const.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/error.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/format.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/noalias.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/noinline.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/pure.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/restrict.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/warning.h
+bigdecimal.o: $(hdrdir)/ruby/internal/attr/weakref.h
+bigdecimal.o: $(hdrdir)/ruby/internal/cast.h
+bigdecimal.o: $(hdrdir)/ruby/internal/compiler_is.h
+bigdecimal.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+bigdecimal.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+bigdecimal.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+bigdecimal.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+bigdecimal.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+bigdecimal.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+bigdecimal.o: $(hdrdir)/ruby/internal/compiler_since.h
+bigdecimal.o: $(hdrdir)/ruby/internal/config.h
+bigdecimal.o: $(hdrdir)/ruby/internal/constant_p.h
+bigdecimal.o: $(hdrdir)/ruby/internal/core.h
+bigdecimal.o: $(hdrdir)/ruby/internal/core/rarray.h
+bigdecimal.o: $(hdrdir)/ruby/internal/core/rbasic.h
+bigdecimal.o: $(hdrdir)/ruby/internal/core/rbignum.h
+bigdecimal.o: $(hdrdir)/ruby/internal/core/rclass.h
+bigdecimal.o: $(hdrdir)/ruby/internal/core/rdata.h
+bigdecimal.o: $(hdrdir)/ruby/internal/core/rfile.h
+bigdecimal.o: $(hdrdir)/ruby/internal/core/rhash.h
+bigdecimal.o: $(hdrdir)/ruby/internal/core/robject.h
+bigdecimal.o: $(hdrdir)/ruby/internal/core/rregexp.h
+bigdecimal.o: $(hdrdir)/ruby/internal/core/rstring.h
+bigdecimal.o: $(hdrdir)/ruby/internal/core/rstruct.h
+bigdecimal.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+bigdecimal.o: $(hdrdir)/ruby/internal/ctype.h
+bigdecimal.o: $(hdrdir)/ruby/internal/dllexport.h
+bigdecimal.o: $(hdrdir)/ruby/internal/dosish.h
+bigdecimal.o: $(hdrdir)/ruby/internal/error.h
+bigdecimal.o: $(hdrdir)/ruby/internal/eval.h
+bigdecimal.o: $(hdrdir)/ruby/internal/event.h
+bigdecimal.o: $(hdrdir)/ruby/internal/fl_type.h
+bigdecimal.o: $(hdrdir)/ruby/internal/gc.h
+bigdecimal.o: $(hdrdir)/ruby/internal/glob.h
+bigdecimal.o: $(hdrdir)/ruby/internal/globals.h
+bigdecimal.o: $(hdrdir)/ruby/internal/has/attribute.h
+bigdecimal.o: $(hdrdir)/ruby/internal/has/builtin.h
+bigdecimal.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+bigdecimal.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+bigdecimal.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+bigdecimal.o: $(hdrdir)/ruby/internal/has/extension.h
+bigdecimal.o: $(hdrdir)/ruby/internal/has/feature.h
+bigdecimal.o: $(hdrdir)/ruby/internal/has/warning.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/array.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/bignum.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/class.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/compar.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/complex.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/cont.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/dir.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/enum.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/error.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/eval.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/file.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/gc.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/hash.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/io.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/load.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/marshal.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/numeric.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/object.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/parse.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/proc.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/process.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/random.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/range.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/rational.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/re.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/ruby.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/select.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/signal.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/string.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/struct.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/thread.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/time.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/variable.h
+bigdecimal.o: $(hdrdir)/ruby/internal/intern/vm.h
+bigdecimal.o: $(hdrdir)/ruby/internal/interpreter.h
+bigdecimal.o: $(hdrdir)/ruby/internal/iterator.h
+bigdecimal.o: $(hdrdir)/ruby/internal/memory.h
+bigdecimal.o: $(hdrdir)/ruby/internal/method.h
+bigdecimal.o: $(hdrdir)/ruby/internal/module.h
+bigdecimal.o: $(hdrdir)/ruby/internal/newobj.h
+bigdecimal.o: $(hdrdir)/ruby/internal/rgengc.h
+bigdecimal.o: $(hdrdir)/ruby/internal/scan_args.h
+bigdecimal.o: $(hdrdir)/ruby/internal/special_consts.h
+bigdecimal.o: $(hdrdir)/ruby/internal/static_assert.h
+bigdecimal.o: $(hdrdir)/ruby/internal/stdalign.h
+bigdecimal.o: $(hdrdir)/ruby/internal/stdbool.h
+bigdecimal.o: $(hdrdir)/ruby/internal/symbol.h
+bigdecimal.o: $(hdrdir)/ruby/internal/value.h
+bigdecimal.o: $(hdrdir)/ruby/internal/value_type.h
+bigdecimal.o: $(hdrdir)/ruby/internal/variable.h
+bigdecimal.o: $(hdrdir)/ruby/internal/warning_push.h
+bigdecimal.o: $(hdrdir)/ruby/internal/xmalloc.h
+bigdecimal.o: $(hdrdir)/ruby/missing.h
+bigdecimal.o: $(hdrdir)/ruby/ruby.h
+bigdecimal.o: $(hdrdir)/ruby/st.h
+bigdecimal.o: $(hdrdir)/ruby/subst.h
+bigdecimal.o: $(hdrdir)/ruby/util.h
+bigdecimal.o: bigdecimal.c
+bigdecimal.o: bigdecimal.h
+bigdecimal.o: bits.h
+bigdecimal.o: feature.h
+bigdecimal.o: missing.h
+bigdecimal.o: static_assert.h
+missing.o: $(RUBY_EXTCONF_H)
+missing.o: $(arch_hdrdir)/ruby/config.h
+missing.o: $(hdrdir)/ruby/assert.h
+missing.o: $(hdrdir)/ruby/atomic.h
+missing.o: $(hdrdir)/ruby/backward.h
+missing.o: $(hdrdir)/ruby/backward/2/assume.h
+missing.o: $(hdrdir)/ruby/backward/2/attributes.h
+missing.o: $(hdrdir)/ruby/backward/2/bool.h
+missing.o: $(hdrdir)/ruby/backward/2/inttypes.h
+missing.o: $(hdrdir)/ruby/backward/2/limits.h
+missing.o: $(hdrdir)/ruby/backward/2/long_long.h
+missing.o: $(hdrdir)/ruby/backward/2/stdalign.h
+missing.o: $(hdrdir)/ruby/backward/2/stdarg.h
+missing.o: $(hdrdir)/ruby/defines.h
+missing.o: $(hdrdir)/ruby/intern.h
+missing.o: $(hdrdir)/ruby/internal/abi.h
+missing.o: $(hdrdir)/ruby/internal/anyargs.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+missing.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+missing.o: $(hdrdir)/ruby/internal/assume.h
+missing.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+missing.o: $(hdrdir)/ruby/internal/attr/artificial.h
+missing.o: $(hdrdir)/ruby/internal/attr/cold.h
+missing.o: $(hdrdir)/ruby/internal/attr/const.h
+missing.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+missing.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+missing.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+missing.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+missing.o: $(hdrdir)/ruby/internal/attr/error.h
+missing.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+missing.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+missing.o: $(hdrdir)/ruby/internal/attr/format.h
+missing.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+missing.o: $(hdrdir)/ruby/internal/attr/noalias.h
+missing.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+missing.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+missing.o: $(hdrdir)/ruby/internal/attr/noinline.h
+missing.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+missing.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+missing.o: $(hdrdir)/ruby/internal/attr/pure.h
+missing.o: $(hdrdir)/ruby/internal/attr/restrict.h
+missing.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+missing.o: $(hdrdir)/ruby/internal/attr/warning.h
+missing.o: $(hdrdir)/ruby/internal/attr/weakref.h
+missing.o: $(hdrdir)/ruby/internal/cast.h
+missing.o: $(hdrdir)/ruby/internal/compiler_is.h
+missing.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+missing.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+missing.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+missing.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+missing.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+missing.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+missing.o: $(hdrdir)/ruby/internal/compiler_since.h
+missing.o: $(hdrdir)/ruby/internal/config.h
+missing.o: $(hdrdir)/ruby/internal/constant_p.h
+missing.o: $(hdrdir)/ruby/internal/core.h
+missing.o: $(hdrdir)/ruby/internal/core/rarray.h
+missing.o: $(hdrdir)/ruby/internal/core/rbasic.h
+missing.o: $(hdrdir)/ruby/internal/core/rbignum.h
+missing.o: $(hdrdir)/ruby/internal/core/rclass.h
+missing.o: $(hdrdir)/ruby/internal/core/rdata.h
+missing.o: $(hdrdir)/ruby/internal/core/rfile.h
+missing.o: $(hdrdir)/ruby/internal/core/rhash.h
+missing.o: $(hdrdir)/ruby/internal/core/robject.h
+missing.o: $(hdrdir)/ruby/internal/core/rregexp.h
+missing.o: $(hdrdir)/ruby/internal/core/rstring.h
+missing.o: $(hdrdir)/ruby/internal/core/rstruct.h
+missing.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+missing.o: $(hdrdir)/ruby/internal/ctype.h
+missing.o: $(hdrdir)/ruby/internal/dllexport.h
+missing.o: $(hdrdir)/ruby/internal/dosish.h
+missing.o: $(hdrdir)/ruby/internal/error.h
+missing.o: $(hdrdir)/ruby/internal/eval.h
+missing.o: $(hdrdir)/ruby/internal/event.h
+missing.o: $(hdrdir)/ruby/internal/fl_type.h
+missing.o: $(hdrdir)/ruby/internal/gc.h
+missing.o: $(hdrdir)/ruby/internal/glob.h
+missing.o: $(hdrdir)/ruby/internal/globals.h
+missing.o: $(hdrdir)/ruby/internal/has/attribute.h
+missing.o: $(hdrdir)/ruby/internal/has/builtin.h
+missing.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+missing.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+missing.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+missing.o: $(hdrdir)/ruby/internal/has/extension.h
+missing.o: $(hdrdir)/ruby/internal/has/feature.h
+missing.o: $(hdrdir)/ruby/internal/has/warning.h
+missing.o: $(hdrdir)/ruby/internal/intern/array.h
+missing.o: $(hdrdir)/ruby/internal/intern/bignum.h
+missing.o: $(hdrdir)/ruby/internal/intern/class.h
+missing.o: $(hdrdir)/ruby/internal/intern/compar.h
+missing.o: $(hdrdir)/ruby/internal/intern/complex.h
+missing.o: $(hdrdir)/ruby/internal/intern/cont.h
+missing.o: $(hdrdir)/ruby/internal/intern/dir.h
+missing.o: $(hdrdir)/ruby/internal/intern/enum.h
+missing.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+missing.o: $(hdrdir)/ruby/internal/intern/error.h
+missing.o: $(hdrdir)/ruby/internal/intern/eval.h
+missing.o: $(hdrdir)/ruby/internal/intern/file.h
+missing.o: $(hdrdir)/ruby/internal/intern/gc.h
+missing.o: $(hdrdir)/ruby/internal/intern/hash.h
+missing.o: $(hdrdir)/ruby/internal/intern/io.h
+missing.o: $(hdrdir)/ruby/internal/intern/load.h
+missing.o: $(hdrdir)/ruby/internal/intern/marshal.h
+missing.o: $(hdrdir)/ruby/internal/intern/numeric.h
+missing.o: $(hdrdir)/ruby/internal/intern/object.h
+missing.o: $(hdrdir)/ruby/internal/intern/parse.h
+missing.o: $(hdrdir)/ruby/internal/intern/proc.h
+missing.o: $(hdrdir)/ruby/internal/intern/process.h
+missing.o: $(hdrdir)/ruby/internal/intern/random.h
+missing.o: $(hdrdir)/ruby/internal/intern/range.h
+missing.o: $(hdrdir)/ruby/internal/intern/rational.h
+missing.o: $(hdrdir)/ruby/internal/intern/re.h
+missing.o: $(hdrdir)/ruby/internal/intern/ruby.h
+missing.o: $(hdrdir)/ruby/internal/intern/select.h
+missing.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+missing.o: $(hdrdir)/ruby/internal/intern/signal.h
+missing.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+missing.o: $(hdrdir)/ruby/internal/intern/string.h
+missing.o: $(hdrdir)/ruby/internal/intern/struct.h
+missing.o: $(hdrdir)/ruby/internal/intern/thread.h
+missing.o: $(hdrdir)/ruby/internal/intern/time.h
+missing.o: $(hdrdir)/ruby/internal/intern/variable.h
+missing.o: $(hdrdir)/ruby/internal/intern/vm.h
+missing.o: $(hdrdir)/ruby/internal/interpreter.h
+missing.o: $(hdrdir)/ruby/internal/iterator.h
+missing.o: $(hdrdir)/ruby/internal/memory.h
+missing.o: $(hdrdir)/ruby/internal/method.h
+missing.o: $(hdrdir)/ruby/internal/module.h
+missing.o: $(hdrdir)/ruby/internal/newobj.h
+missing.o: $(hdrdir)/ruby/internal/rgengc.h
+missing.o: $(hdrdir)/ruby/internal/scan_args.h
+missing.o: $(hdrdir)/ruby/internal/special_consts.h
+missing.o: $(hdrdir)/ruby/internal/static_assert.h
+missing.o: $(hdrdir)/ruby/internal/stdalign.h
+missing.o: $(hdrdir)/ruby/internal/stdbool.h
+missing.o: $(hdrdir)/ruby/internal/symbol.h
+missing.o: $(hdrdir)/ruby/internal/value.h
+missing.o: $(hdrdir)/ruby/internal/value_type.h
+missing.o: $(hdrdir)/ruby/internal/variable.h
+missing.o: $(hdrdir)/ruby/internal/warning_push.h
+missing.o: $(hdrdir)/ruby/internal/xmalloc.h
+missing.o: $(hdrdir)/ruby/missing.h
+missing.o: $(hdrdir)/ruby/ruby.h
+missing.o: $(hdrdir)/ruby/st.h
+missing.o: $(hdrdir)/ruby/subst.h
+missing.o: missing.c
+missing.o: missing/dtoa.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/bigdecimal/extconf.rb b/ext/bigdecimal/extconf.rb
new file mode 100644
index 0000000000..17e7905dd6
--- /dev/null
+++ b/ext/bigdecimal/extconf.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: false
+require 'mkmf'
+
+def check_bigdecimal_version(gemspec_path)
+ message "checking RUBY_BIGDECIMAL_VERSION... "
+ bigdecimal_version = File.read(gemspec_path).match(/^\s*s\.version\s+=\s+['"]([^'"]+)['"]\s*$/)[1]
+
+ version_components = bigdecimal_version.split('.')
+ bigdecimal_version = version_components[0, 3].join('.')
+ bigdecimal_version << "-#{version_components[3]}" if version_components[3]
+ $defs << %Q[-DRUBY_BIGDECIMAL_VERSION=\\"#{bigdecimal_version}\\"]
+
+ message "#{bigdecimal_version}\n"
+end
+
+def have_builtin_func(name, check_expr, opt = "", &b)
+ checking_for checking_message(name.funcall_style, nil, opt) do
+ if try_compile(<<SRC, opt, &b)
+int foo;
+int main() { #{check_expr}; return 0; }
+SRC
+ $defs.push(format("-DHAVE_BUILTIN_%s", name.tr_cpp))
+ true
+ else
+ false
+ end
+ end
+end
+
+gemspec_name = gemspec_path = nil
+unless ['', '../../'].any? {|dir|
+ gemspec_name = "#{dir}bigdecimal.gemspec"
+ gemspec_path = File.expand_path("../#{gemspec_name}", __FILE__)
+ File.file?(gemspec_path)
+ }
+ $stderr.puts "Unable to find bigdecimal.gemspec"
+ abort
+end
+
+check_bigdecimal_version(gemspec_path)
+
+have_builtin_func("__builtin_clz", "__builtin_clz(0)")
+have_builtin_func("__builtin_clzl", "__builtin_clzl(0)")
+have_builtin_func("__builtin_clzll", "__builtin_clzll(0)")
+
+have_header("float.h")
+have_header("math.h")
+have_header("stdbool.h")
+have_header("stdlib.h")
+
+have_header("x86intrin.h")
+have_func("_lzcnt_u32", "x86intrin.h")
+have_func("_lzcnt_u64", "x86intrin.h")
+
+have_header("intrin.h")
+have_func("__lzcnt", "intrin.h")
+have_func("__lzcnt64", "intrin.h")
+have_func("_BitScanReverse", "intrin.h")
+have_func("_BitScanReverse64", "intrin.h")
+
+have_func("labs", "stdlib.h")
+have_func("llabs", "stdlib.h")
+have_func("finite", "math.h")
+have_func("isfinite", "math.h")
+
+have_header("ruby/atomic.h")
+have_header("ruby/internal/has/builtin.h")
+have_header("ruby/internal/static_assert.h")
+
+have_func("rb_rational_num", "ruby.h")
+have_func("rb_rational_den", "ruby.h")
+have_func("rb_complex_real", "ruby.h")
+have_func("rb_complex_imag", "ruby.h")
+have_func("rb_opts_exception_p", "ruby.h")
+have_func("rb_category_warn", "ruby.h")
+have_const("RB_WARN_CATEGORY_DEPRECATED", "ruby.h")
+
+if File.file?(File.expand_path('../lib/bigdecimal.rb', __FILE__))
+ bigdecimal_rb = "$(srcdir)/lib/bigdecimal.rb"
+else
+ bigdecimal_rb = "$(srcdir)/../../lib/bigdecimal.rb"
+end
+
+create_makefile('bigdecimal') {|mf|
+ mf << "GEMSPEC = #{gemspec_name}\n"
+ mf << "BIGDECIMAL_RB = #{bigdecimal_rb}\n"
+}
diff --git a/ext/bigdecimal/feature.h b/ext/bigdecimal/feature.h
new file mode 100644
index 0000000000..f628514500
--- /dev/null
+++ b/ext/bigdecimal/feature.h
@@ -0,0 +1,68 @@
+#ifndef BIGDECIMAL_HAS_FEATURE_H
+#define BIGDECIMAL_HAS_FEATURE_H
+
+/* ======== __has_feature ======== */
+
+#ifndef __has_feature
+# define __has_feature(_) 0
+#endif
+
+/* ======== __has_extension ======== */
+
+#ifndef __has_extension
+# define __has_extension __has_feature
+#endif
+
+/* ======== __has_builtin ======== */
+
+#ifdef HAVE_RUBY_INTERNAL_HAS_BUILTIN_H
+# include <ruby/internal/has/builtin.h>
+#endif
+
+#ifdef RBIMPL_HAS_BUILTIN
+# define BIGDECIMAL_HAS_BUILTIN(...) RBIMPL_HAS_BUILTIN(__VA_ARGS__)
+
+#else
+# /* The following section is copied from CRuby's builtin.h */
+#
+# ifdef __has_builtin
+# if defined(__INTEL_COMPILER)
+# /* :TODO: Intel C Compiler has __has_builtin (since 19.1 maybe?), and is
+# * reportedly broken. We have to skip them. However the situation can
+# * change. They might improve someday. We need to revisit here later. */
+# elif defined(__GNUC__) && ! __has_builtin(__builtin_alloca)
+# /* FreeBSD's <sys/cdefs.h> defines its own *broken* version of
+# * __has_builtin. Cygwin copied that content to be a victim of the
+# * broken-ness. We don't take them into account. */
+# else
+# define HAVE___HAS_BUILTIN 1
+# endif
+# endif
+#
+# if defined(HAVE___HAS_BUILTIN)
+# define BIGDECIMAL_HAS_BUILTIN(_) __has_builtin(_)
+#
+# elif defined(__GNUC__)
+# define BIGDECIMAL_HAS_BUILTIN(_) BIGDECIMAL_HAS_BUILTIN_ ## _
+# if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 6))
+# define BIGDECIMAL_HAS_BUILTIN___builtin_clz 1
+# define BIGDECIMAL_HAS_BUILTIN___builtin_clzl 1
+# else
+# define BIGDECIMAL_HAS_BUILTIN___builtin_clz 0
+# define BIGDECIMAL_HAS_BUILTIN___builtin_clzl 0
+# endif
+# elif defined(_MSC_VER)
+# define BIGDECIMAL_HAS_BUILTIN(_) 0
+#
+# else
+# define BIGDECIMAL_HAS_BUILTIN(_) BIGDECIMAL_HAS_BUILTIN_ ## _
+# define BIGDECIMAL_HAS_BUILTIN___builtin_clz HAVE_BUILTIN___BUILTIN_CLZ
+# define BIGDECIMAL_HAS_BUILTIN___builtin_clzl HAVE_BUILTIN___BUILTIN_CLZL
+# endif
+#endif /* RBIMPL_HAS_BUILTIN */
+
+#ifndef __has_builtin
+# define __has_builtin(...) BIGDECIMAL_HAS_BUILTIN(__VA_ARGS__)
+#endif
+
+#endif /* BIGDECIMAL_HAS_FEATURE_H */
diff --git a/ext/bigdecimal/lib/bigdecimal.rb b/ext/bigdecimal/lib/bigdecimal.rb
new file mode 100644
index 0000000000..8fd2587c84
--- /dev/null
+++ b/ext/bigdecimal/lib/bigdecimal.rb
@@ -0,0 +1 @@
+require 'bigdecimal.so'
diff --git a/ext/bigdecimal/lib/bigdecimal/jacobian.rb b/ext/bigdecimal/lib/bigdecimal/jacobian.rb
new file mode 100644
index 0000000000..4448024c74
--- /dev/null
+++ b/ext/bigdecimal/lib/bigdecimal/jacobian.rb
@@ -0,0 +1,90 @@
+# frozen_string_literal: false
+
+require 'bigdecimal'
+
+# require 'bigdecimal/jacobian'
+#
+# Provides methods to compute the Jacobian matrix of a set of equations at a
+# point x. In the methods below:
+#
+# f is an Object which is used to compute the Jacobian matrix of the equations.
+# It must provide the following methods:
+#
+# f.values(x):: returns the values of all functions at x
+#
+# f.zero:: returns 0.0
+# f.one:: returns 1.0
+# f.two:: returns 2.0
+# f.ten:: returns 10.0
+#
+# f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal.
+#
+# x is the point at which to compute the Jacobian.
+#
+# fx is f.values(x).
+#
+module Jacobian
+ module_function
+
+ # Determines the equality of two numbers by comparing to zero, or using the epsilon value
+ def isEqual(a,b,zero=0.0,e=1.0e-8)
+ aa = a.abs
+ bb = b.abs
+ if aa == zero && bb == zero then
+ true
+ else
+ if ((a-b)/(aa+bb)).abs < e then
+ true
+ else
+ false
+ end
+ end
+ end
+
+
+ # Computes the derivative of +f[i]+ at +x[i]+.
+ # +fx+ is the value of +f+ at +x+.
+ def dfdxi(f,fx,x,i)
+ nRetry = 0
+ n = x.size
+ xSave = x[i]
+ ok = 0
+ ratio = f.ten*f.ten*f.ten
+ dx = x[i].abs/ratio
+ dx = fx[i].abs/ratio if isEqual(dx,f.zero,f.zero,f.eps)
+ dx = f.one/f.ten if isEqual(dx,f.zero,f.zero,f.eps)
+ until ok>0 do
+ deriv = []
+ nRetry += 1
+ if nRetry > 100
+ raise "Singular Jacobian matrix. No change at x[" + i.to_s + "]"
+ end
+ dx = dx*f.two
+ x[i] += dx
+ fxNew = f.values(x)
+ for j in 0...n do
+ if !isEqual(fxNew[j],fx[j],f.zero,f.eps) then
+ ok += 1
+ deriv <<= (fxNew[j]-fx[j])/dx
+ else
+ deriv <<= f.zero
+ end
+ end
+ x[i] = xSave
+ end
+ deriv
+ end
+
+ # Computes the Jacobian of +f+ at +x+. +fx+ is the value of +f+ at +x+.
+ def jacobian(f,fx,x)
+ n = x.size
+ dfdx = Array.new(n*n)
+ for i in 0...n do
+ df = dfdxi(f,fx,x,i)
+ for j in 0...n do
+ dfdx[j*n+i] = df[j]
+ end
+ end
+ dfdx
+ end
+end
diff --git a/ext/bigdecimal/lib/bigdecimal/ludcmp.rb b/ext/bigdecimal/lib/bigdecimal/ludcmp.rb
new file mode 100644
index 0000000000..dd265e482a
--- /dev/null
+++ b/ext/bigdecimal/lib/bigdecimal/ludcmp.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: false
+require 'bigdecimal'
+
+#
+# Solves a*x = b for x, using LU decomposition.
+#
+module LUSolve
+ module_function
+
+ # Performs LU decomposition of the n by n matrix a.
+ def ludecomp(a,n,zero=0,one=1)
+ prec = BigDecimal.limit(nil)
+ ps = []
+ scales = []
+ for i in 0...n do # pick up largest(abs. val.) element in each row.
+ ps <<= i
+ nrmrow = zero
+ ixn = i*n
+ for j in 0...n do
+ biggst = a[ixn+j].abs
+ nrmrow = biggst if biggst>nrmrow
+ end
+ if nrmrow>zero then
+ scales <<= one.div(nrmrow,prec)
+ else
+ raise "Singular matrix"
+ end
+ end
+ n1 = n - 1
+ for k in 0...n1 do # Gaussian elimination with partial pivoting.
+ biggst = zero;
+ for i in k...n do
+ size = a[ps[i]*n+k].abs*scales[ps[i]]
+ if size>biggst then
+ biggst = size
+ pividx = i
+ end
+ end
+ raise "Singular matrix" if biggst<=zero
+ if pividx!=k then
+ j = ps[k]
+ ps[k] = ps[pividx]
+ ps[pividx] = j
+ end
+ pivot = a[ps[k]*n+k]
+ for i in (k+1)...n do
+ psin = ps[i]*n
+ a[psin+k] = mult = a[psin+k].div(pivot,prec)
+ if mult!=zero then
+ pskn = ps[k]*n
+ for j in (k+1)...n do
+ a[psin+j] -= mult.mult(a[pskn+j],prec)
+ end
+ end
+ end
+ end
+ raise "Singular matrix" if a[ps[n1]*n+n1] == zero
+ ps
+ end
+
+ # Solves a*x = b for x, using LU decomposition.
+ #
+ # a is a matrix, b is a constant vector, x is the solution vector.
+ #
+ # ps is the pivot, a vector which indicates the permutation of rows performed
+ # during LU decomposition.
+ def lusolve(a,b,ps,zero=0.0)
+ prec = BigDecimal.limit(nil)
+ n = ps.size
+ x = []
+ for i in 0...n do
+ dot = zero
+ psin = ps[i]*n
+ for j in 0...i do
+ dot = a[psin+j].mult(x[j],prec) + dot
+ end
+ x <<= b[ps[i]] - dot
+ end
+ (n-1).downto(0) do |i|
+ dot = zero
+ psin = ps[i]*n
+ for j in (i+1)...n do
+ dot = a[psin+j].mult(x[j],prec) + dot
+ end
+ x[i] = (x[i]-dot).div(a[psin+i],prec)
+ end
+ x
+ end
+end
diff --git a/ext/bigdecimal/lib/bigdecimal/math.rb b/ext/bigdecimal/lib/bigdecimal/math.rb
new file mode 100644
index 0000000000..0b9d0648bb
--- /dev/null
+++ b/ext/bigdecimal/lib/bigdecimal/math.rb
@@ -0,0 +1,232 @@
+# frozen_string_literal: false
+require 'bigdecimal'
+
+#
+#--
+# Contents:
+# sqrt(x, prec)
+# sin (x, prec)
+# cos (x, prec)
+# atan(x, prec) Note: |x|<1, x=0.9999 may not converge.
+# PI (prec)
+# E (prec) == exp(1.0,prec)
+#
+# where:
+# x ... BigDecimal number to be computed.
+# |x| must be small enough to get convergence.
+# prec ... Number of digits to be obtained.
+#++
+#
+# Provides mathematical functions.
+#
+# Example:
+#
+# require "bigdecimal/math"
+#
+# include BigMath
+#
+# a = BigDecimal((PI(100)/2).to_s)
+# puts sin(a,100) # => 0.99999999999999999999......e0
+#
+module BigMath
+ module_function
+
+ # call-seq:
+ # sqrt(decimal, numeric) -> BigDecimal
+ #
+ # Computes the square root of +decimal+ to the specified number of digits of
+ # precision, +numeric+.
+ #
+ # BigMath.sqrt(BigDecimal('2'), 16).to_s
+ # #=> "0.1414213562373095048801688724e1"
+ #
+ def sqrt(x, prec)
+ x.sqrt(prec)
+ end
+
+ # call-seq:
+ # sin(decimal, numeric) -> BigDecimal
+ #
+ # Computes the sine of +decimal+ to the specified number of digits of
+ # precision, +numeric+.
+ #
+ # If +decimal+ is Infinity or NaN, returns NaN.
+ #
+ # BigMath.sin(BigMath.PI(5)/4, 5).to_s
+ # #=> "0.70710678118654752440082036563292800375e0"
+ #
+ def sin(x, prec)
+ raise ArgumentError, "Zero or negative precision for sin" if prec <= 0
+ return BigDecimal("NaN") if x.infinite? || x.nan?
+ n = prec + BigDecimal.double_fig
+ one = BigDecimal("1")
+ two = BigDecimal("2")
+ x = -x if neg = x < 0
+ if x > (twopi = two * BigMath.PI(prec))
+ if x > 30
+ x %= twopi
+ else
+ x -= twopi while x > twopi
+ end
+ end
+ x1 = x
+ x2 = x.mult(x,n)
+ sign = 1
+ y = x
+ d = y
+ i = one
+ z = one
+ while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
+ m = BigDecimal.double_fig if m < BigDecimal.double_fig
+ sign = -sign
+ x1 = x2.mult(x1,n)
+ i += two
+ z *= (i-one) * i
+ d = sign * x1.div(z,m)
+ y += d
+ end
+ neg ? -y : y
+ end
+
+ # call-seq:
+ # cos(decimal, numeric) -> BigDecimal
+ #
+ # Computes the cosine of +decimal+ to the specified number of digits of
+ # precision, +numeric+.
+ #
+ # If +decimal+ is Infinity or NaN, returns NaN.
+ #
+ # BigMath.cos(BigMath.PI(4), 16).to_s
+ # #=> "-0.999999999999999999999999999999856613163740061349e0"
+ #
+ def cos(x, prec)
+ raise ArgumentError, "Zero or negative precision for cos" if prec <= 0
+ return BigDecimal("NaN") if x.infinite? || x.nan?
+ n = prec + BigDecimal.double_fig
+ one = BigDecimal("1")
+ two = BigDecimal("2")
+ x = -x if x < 0
+ if x > (twopi = two * BigMath.PI(prec))
+ if x > 30
+ x %= twopi
+ else
+ x -= twopi while x > twopi
+ end
+ end
+ x1 = one
+ x2 = x.mult(x,n)
+ sign = 1
+ y = one
+ d = y
+ i = BigDecimal("0")
+ z = one
+ while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
+ m = BigDecimal.double_fig if m < BigDecimal.double_fig
+ sign = -sign
+ x1 = x2.mult(x1,n)
+ i += two
+ z *= (i-one) * i
+ d = sign * x1.div(z,m)
+ y += d
+ end
+ y
+ end
+
+ # call-seq:
+ # atan(decimal, numeric) -> BigDecimal
+ #
+ # Computes the arctangent of +decimal+ to the specified number of digits of
+ # precision, +numeric+.
+ #
+ # If +decimal+ is NaN, returns NaN.
+ #
+ # BigMath.atan(BigDecimal('-1'), 16).to_s
+ # #=> "-0.785398163397448309615660845819878471907514682065e0"
+ #
+ def atan(x, prec)
+ raise ArgumentError, "Zero or negative precision for atan" if prec <= 0
+ return BigDecimal("NaN") if x.nan?
+ pi = PI(prec)
+ x = -x if neg = x < 0
+ return pi.div(neg ? -2 : 2, prec) if x.infinite?
+ return pi / (neg ? -4 : 4) if x.round(prec) == 1
+ x = BigDecimal("1").div(x, prec) if inv = x > 1
+ x = (-1 + sqrt(1 + x**2, prec))/x if dbl = x > 0.5
+ n = prec + BigDecimal.double_fig
+ y = x
+ d = y
+ t = x
+ r = BigDecimal("3")
+ x2 = x.mult(x,n)
+ while d.nonzero? && ((m = n - (y.exponent - d.exponent).abs) > 0)
+ m = BigDecimal.double_fig if m < BigDecimal.double_fig
+ t = -t.mult(x2,n)
+ d = t.div(r,m)
+ y += d
+ r += 2
+ end
+ y *= 2 if dbl
+ y = pi / 2 - y if inv
+ y = -y if neg
+ y
+ end
+
+ # call-seq:
+ # PI(numeric) -> BigDecimal
+ #
+ # Computes the value of pi to the specified number of digits of precision,
+ # +numeric+.
+ #
+ # BigMath.PI(10).to_s
+ # #=> "0.3141592653589793238462643388813853786957412e1"
+ #
+ def PI(prec)
+ raise ArgumentError, "Zero or negative precision for PI" if prec <= 0
+ n = prec + BigDecimal.double_fig
+ zero = BigDecimal("0")
+ one = BigDecimal("1")
+ two = BigDecimal("2")
+
+ m25 = BigDecimal("-0.04")
+ m57121 = BigDecimal("-57121")
+
+ pi = zero
+
+ d = one
+ k = one
+ t = BigDecimal("-80")
+ while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
+ m = BigDecimal.double_fig if m < BigDecimal.double_fig
+ t = t*m25
+ d = t.div(k,m)
+ k = k+two
+ pi = pi + d
+ end
+
+ d = one
+ k = one
+ t = BigDecimal("956")
+ while d.nonzero? && ((m = n - (pi.exponent - d.exponent).abs) > 0)
+ m = BigDecimal.double_fig if m < BigDecimal.double_fig
+ t = t.div(m57121,n)
+ d = t.div(k,m)
+ pi = pi + d
+ k = k+two
+ end
+ pi
+ end
+
+ # call-seq:
+ # E(numeric) -> BigDecimal
+ #
+ # Computes e (the base of natural logarithms) to the specified number of
+ # digits of precision, +numeric+.
+ #
+ # BigMath.E(10).to_s
+ # #=> "0.271828182845904523536028752390026306410273e1"
+ #
+ def E(prec)
+ raise ArgumentError, "Zero or negative precision for E" if prec <= 0
+ BigMath.exp(1, prec)
+ end
+end
diff --git a/ext/bigdecimal/lib/bigdecimal/newton.rb b/ext/bigdecimal/lib/bigdecimal/newton.rb
new file mode 100644
index 0000000000..85bacb7f2e
--- /dev/null
+++ b/ext/bigdecimal/lib/bigdecimal/newton.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: false
+require "bigdecimal/ludcmp"
+require "bigdecimal/jacobian"
+
+#
+# newton.rb
+#
+# Solves the nonlinear algebraic equation system f = 0 by Newton's method.
+# This program is not dependent on BigDecimal.
+#
+# To call:
+# n = nlsolve(f,x)
+# where n is the number of iterations required,
+# x is the initial value vector
+# f is an Object which is used to compute the values of the equations to be solved.
+# It must provide the following methods:
+#
+# f.values(x):: returns the values of all functions at x
+#
+# f.zero:: returns 0.0
+# f.one:: returns 1.0
+# f.two:: returns 2.0
+# f.ten:: returns 10.0
+#
+# f.eps:: returns the convergence criterion (epsilon value) used to determine whether two values are considered equal. If |a-b| < epsilon, the two values are considered equal.
+#
+# On exit, x is the solution vector.
+#
+module Newton
+ include LUSolve
+ include Jacobian
+ module_function
+
+ def norm(fv,zero=0.0) # :nodoc:
+ s = zero
+ n = fv.size
+ for i in 0...n do
+ s += fv[i]*fv[i]
+ end
+ s
+ end
+
+ # See also Newton
+ def nlsolve(f,x)
+ nRetry = 0
+ n = x.size
+
+ f0 = f.values(x)
+ zero = f.zero
+ one = f.one
+ two = f.two
+ p5 = one/two
+ d = norm(f0,zero)
+ minfact = f.ten*f.ten*f.ten
+ minfact = one/minfact
+ e = f.eps
+ while d >= e do
+ nRetry += 1
+ # Not yet converged. => Compute Jacobian matrix
+ dfdx = jacobian(f,f0,x)
+ # Solve dfdx*dx = -f0 to estimate dx
+ dx = lusolve(dfdx,f0,ludecomp(dfdx,n,zero,one),zero)
+ fact = two
+ xs = x.dup
+ begin
+ fact *= p5
+ if fact < minfact then
+ raise "Failed to reduce function values."
+ end
+ for i in 0...n do
+ x[i] = xs[i] - dx[i]*fact
+ end
+ f0 = f.values(x)
+ dn = norm(f0,zero)
+ end while(dn>=d)
+ d = dn
+ end
+ nRetry
+ end
+end
diff --git a/ext/bigdecimal/lib/bigdecimal/util.rb b/ext/bigdecimal/lib/bigdecimal/util.rb
new file mode 100644
index 0000000000..ad92f7cfe6
--- /dev/null
+++ b/ext/bigdecimal/lib/bigdecimal/util.rb
@@ -0,0 +1,185 @@
+# frozen_string_literal: false
+#
+#--
+# bigdecimal/util extends various native classes to provide the #to_d method,
+# and provides BigDecimal#to_d and BigDecimal#to_digits.
+#++
+
+require 'bigdecimal'
+
+class Integer < Numeric
+ # call-seq:
+ # int.to_d -> bigdecimal
+ #
+ # Returns the value of +int+ as a BigDecimal.
+ #
+ # require 'bigdecimal'
+ # require 'bigdecimal/util'
+ #
+ # 42.to_d # => 0.42e2
+ #
+ # See also BigDecimal::new.
+ #
+ def to_d
+ BigDecimal(self)
+ end
+end
+
+
+class Float < Numeric
+ # call-seq:
+ # float.to_d -> bigdecimal
+ # float.to_d(precision) -> bigdecimal
+ #
+ # Returns the value of +float+ as a BigDecimal.
+ # The +precision+ parameter is used to determine the number of
+ # significant digits for the result. When +precision+ is set to +0+,
+ # the number of digits to represent the float being converted is determined
+ # automatically.
+ # The default +precision+ is +0+.
+ #
+ # require 'bigdecimal'
+ # require 'bigdecimal/util'
+ #
+ # 0.5.to_d # => 0.5e0
+ # 1.234.to_d # => 0.1234e1
+ # 1.234.to_d(2) # => 0.12e1
+ #
+ # See also BigDecimal::new.
+ #
+ def to_d(precision=0)
+ BigDecimal(self, precision)
+ end
+end
+
+
+class String
+ # call-seq:
+ # str.to_d -> bigdecimal
+ #
+ # Returns the result of interpreting leading characters in +str+
+ # as a BigDecimal.
+ #
+ # require 'bigdecimal'
+ # require 'bigdecimal/util'
+ #
+ # "0.5".to_d # => 0.5e0
+ # "123.45e1".to_d # => 0.12345e4
+ # "45.67 degrees".to_d # => 0.4567e2
+ #
+ # See also BigDecimal::new.
+ #
+ def to_d
+ BigDecimal.interpret_loosely(self)
+ end
+end
+
+
+class BigDecimal < Numeric
+ # call-seq:
+ # a.to_digits -> string
+ #
+ # Converts a BigDecimal to a String of the form "nnnnnn.mmm".
+ # This method is deprecated; use BigDecimal#to_s("F") instead.
+ #
+ # require 'bigdecimal/util'
+ #
+ # d = BigDecimal("3.14")
+ # d.to_digits # => "3.14"
+ #
+ def to_digits
+ if self.nan? || self.infinite? || self.zero?
+ self.to_s
+ else
+ i = self.to_i.to_s
+ _,f,_,z = self.frac.split
+ i + "." + ("0"*(-z)) + f
+ end
+ end
+
+ # call-seq:
+ # a.to_d -> bigdecimal
+ #
+ # Returns self.
+ #
+ # require 'bigdecimal/util'
+ #
+ # d = BigDecimal("3.14")
+ # d.to_d # => 0.314e1
+ #
+ def to_d
+ self
+ end
+end
+
+
+class Rational < Numeric
+ # call-seq:
+ # rat.to_d(precision) -> bigdecimal
+ #
+ # Returns the value as a BigDecimal.
+ #
+ # The required +precision+ parameter is used to determine the number of
+ # significant digits for the result.
+ #
+ # require 'bigdecimal'
+ # require 'bigdecimal/util'
+ #
+ # Rational(22, 7).to_d(3) # => 0.314e1
+ #
+ # See also BigDecimal::new.
+ #
+ def to_d(precision)
+ BigDecimal(self, precision)
+ end
+end
+
+
+class Complex < Numeric
+ # call-seq:
+ # cmp.to_d -> bigdecimal
+ # cmp.to_d(precision) -> bigdecimal
+ #
+ # Returns the value as a BigDecimal.
+ #
+ # The +precision+ parameter is required for a rational complex number.
+ # This parameter is used to determine the number of significant digits
+ # for the result.
+ #
+ # require 'bigdecimal'
+ # require 'bigdecimal/util'
+ #
+ # Complex(0.1234567, 0).to_d(4) # => 0.1235e0
+ # Complex(Rational(22, 7), 0).to_d(3) # => 0.314e1
+ #
+ # See also BigDecimal::new.
+ #
+ def to_d(*args)
+ BigDecimal(self) unless self.imag.zero? # to raise eerror
+
+ if args.length == 0
+ case self.real
+ when Rational
+ BigDecimal(self.real) # to raise error
+ end
+ end
+ self.real.to_d(*args)
+ end
+end
+
+
+class NilClass
+ # call-seq:
+ # nil.to_d -> bigdecimal
+ #
+ # Returns nil represented as a BigDecimal.
+ #
+ # require 'bigdecimal'
+ # require 'bigdecimal/util'
+ #
+ # nil.to_d # => 0.0
+ #
+ def to_d
+ BigDecimal(0)
+ end
+end
diff --git a/ext/bigdecimal/missing.c b/ext/bigdecimal/missing.c
new file mode 100644
index 0000000000..703232d92f
--- /dev/null
+++ b/ext/bigdecimal/missing.c
@@ -0,0 +1,27 @@
+#include <ruby/ruby.h>
+
+#ifdef HAVE_RUBY_ATOMIC_H
+# include <ruby/atomic.h>
+#endif
+
+#ifdef RUBY_ATOMIC_PTR_CAS
+# define ATOMIC_PTR_CAS(var, old, new) RUBY_ATOMIC_PTR_CAS(var, old, new)
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+/* GCC warns about unknown sanitizer, which is annoying. */
+# undef NO_SANITIZE
+# define NO_SANITIZE(x, y) \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wattributes\"") \
+ __attribute__((__no_sanitize__(x))) y; \
+ _Pragma("GCC diagnostic pop")
+#endif
+
+#undef strtod
+#define strtod BigDecimal_strtod
+#undef dtoa
+#define dtoa BigDecimal_dtoa
+#undef hdtoa
+#define hdtoa BigDecimal_hdtoa
+#include "missing/dtoa.c"
diff --git a/ext/bigdecimal/missing.h b/ext/bigdecimal/missing.h
new file mode 100644
index 0000000000..325554b5f5
--- /dev/null
+++ b/ext/bigdecimal/missing.h
@@ -0,0 +1,196 @@
+#ifndef MISSING_H
+#define MISSING_H 1
+
+#if defined(__cplusplus)
+extern "C" {
+#if 0
+} /* satisfy cc-mode */
+#endif
+#endif
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_MATH_H
+# include <math.h>
+#endif
+
+#ifndef RB_UNUSED_VAR
+# if defined(_MSC_VER) && _MSC_VER >= 1911
+# define RB_UNUSED_VAR(x) x [[maybe_unused]]
+
+# elif defined(__has_cpp_attribute) && __has_cpp_attribute(maybe_unused)
+# define RB_UNUSED_VAR(x) x [[maybe_unused]]
+
+# elif defined(__has_c_attribute) && __has_c_attribute(maybe_unused)
+# define RB_UNUSED_VAR(x) x [[maybe_unused]]
+
+# elif defined(__GNUC__)
+# define RB_UNUSED_VAR(x) x __attribute__ ((unused))
+
+# else
+# define RB_UNUSED_VAR(x) x
+# endif
+#endif /* RB_UNUSED_VAR */
+
+#if defined(_MSC_VER) && _MSC_VER >= 1310
+# define HAVE___ASSUME 1
+
+#elif defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1300
+# define HAVE___ASSUME 1
+#endif
+
+#ifndef UNREACHABLE
+# if __has_builtin(__builtin_unreachable)
+# define UNREACHABLE __builtin_unreachable()
+
+# elif defined(HAVE___ASSUME)
+# define UNREACHABLE __assume(0)
+
+# else
+# define UNREACHABLE /* unreachable */
+# endif
+#endif /* UNREACHABLE */
+
+/* bool */
+
+#if defined(__bool_true_false_are_defined)
+# /* Take that. */
+
+#elif defined(HAVE_STDBOOL_H)
+# include <stdbool.h>
+
+#else
+typedef unsigned char _Bool;
+# define bool _Bool
+# define true ((_Bool)+1)
+# define false ((_Bool)-1)
+# define __bool_true_false_are_defined
+#endif
+
+/* abs */
+
+#ifndef HAVE_LABS
+static inline long
+labs(long const x)
+{
+ if (x < 0) return -x;
+ return x;
+}
+#endif
+
+#ifndef HAVE_LLABS
+static inline LONG_LONG
+llabs(LONG_LONG const x)
+{
+ if (x < 0) return -x;
+ return x;
+}
+#endif
+
+#ifdef vabs
+# undef vabs
+#endif
+#if SIZEOF_VALUE <= SIZEOF_INT
+# define vabs abs
+#elif SIZEOF_VALUE <= SIZEOF_LONG
+# define vabs labs
+#elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
+# define vabs llabs
+#endif
+
+/* finite */
+
+#ifndef HAVE_FINITE
+static int
+finite(double)
+{
+ return !isnan(n) && !isinf(n);
+}
+#endif
+
+#ifndef isfinite
+# ifndef HAVE_ISFINITE
+# define HAVE_ISFINITE 1
+# define isfinite(x) finite(x)
+# endif
+#endif
+
+/* dtoa */
+char *BigDecimal_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve);
+
+/* rational */
+
+#ifndef HAVE_RB_RATIONAL_NUM
+static inline VALUE
+rb_rational_num(VALUE rat)
+{
+#ifdef RRATIONAL
+ return RRATIONAL(rat)->num;
+#else
+ return rb_funcall(rat, rb_intern("numerator"), 0);
+#endif
+}
+#endif
+
+#ifndef HAVE_RB_RATIONAL_DEN
+static inline VALUE
+rb_rational_den(VALUE rat)
+{
+#ifdef RRATIONAL
+ return RRATIONAL(rat)->den;
+#else
+ return rb_funcall(rat, rb_intern("denominator"), 0);
+#endif
+}
+#endif
+
+/* complex */
+
+#ifndef HAVE_RB_COMPLEX_REAL
+static inline VALUE
+rb_complex_real(VALUE cmp)
+{
+#ifdef RCOMPLEX
+ return RCOMPLEX(cmp)->real;
+#else
+ return rb_funcall(cmp, rb_intern("real"), 0);
+#endif
+}
+#endif
+
+#ifndef HAVE_RB_COMPLEX_IMAG
+static inline VALUE
+rb_complex_imag(VALUE cmp)
+{
+# ifdef RCOMPLEX
+ return RCOMPLEX(cmp)->imag;
+# else
+ return rb_funcall(cmp, rb_intern("imag"), 0);
+# endif
+}
+#endif
+
+/* st */
+
+#ifndef ST2FIX
+# undef RB_ST2FIX
+# define RB_ST2FIX(h) LONG2FIX((long)(h))
+# define ST2FIX(h) RB_ST2FIX(h)
+#endif
+
+/* warning */
+
+#if !defined(HAVE_RB_CATEGORY_WARN) || !defined(HAVE_CONST_RB_WARN_CATEGORY_DEPRECATED)
+# define rb_category_warn(category, ...) rb_warn(__VA_ARGS__)
+#endif
+
+#if defined(__cplusplus)
+#if 0
+{ /* satisfy cc-mode */
+#endif
+} /* extern "C" { */
+#endif
+
+#endif /* MISSING_H */
diff --git a/ext/bigdecimal/missing/dtoa.c b/ext/bigdecimal/missing/dtoa.c
new file mode 100644
index 0000000000..41b0a221d1
--- /dev/null
+++ b/ext/bigdecimal/missing/dtoa.c
@@ -0,0 +1,3462 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa. If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ * _control87(PC_53, MCW_PC);
+ * does this with many compilers. Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE). With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule. Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *
+ * 1. We only require IEEE, IBM, or VAX double-precision
+ * arithmetic (not IEEE double-extended).
+ * 2. We get by with floating-point arithmetic in a case that
+ * Clinger missed -- when we're computing d * 10^n
+ * for a small integer d and the integer n is not too
+ * much larger than 22 (the maximum integer k for which
+ * we can represent 10^k exactly), we may be able to
+ * compute (d*10^k) * 10^(e-k) with just one roundoff.
+ * 3. Rather than a bit-at-a-time adjustment of the binary
+ * result in the hard case, we use floating-point
+ * arithmetic to determine the adjustment to within
+ * one bit; only in really hard cases do we need to
+ * compute a second residual.
+ * 4. Because of 3., we don't need a large table of powers of 10
+ * for ten-to-e (just some small tables, e.g. of 10^k
+ * for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_LITTLE_ENDIAN for IEEE-arithmetic machines where the least
+ * significant byte has the lowest address.
+ * #define IEEE_BIG_ENDIAN for IEEE-arithmetic machines where the most
+ * significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ * computation of dtoa.
+ * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ * and strtod and dtoa should round accordingly.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ * and Honor_FLT_ROUNDS is not #defined.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ * that use extended-precision instructions to compute rounded
+ * products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ * products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ * integer type (of >= 64 bits). On such machines, you can
+ * #define Just_16 to store 16 bits per 32-bit Long when doing
+ * high-precision integer arithmetic. Whether this speeds things
+ * up or slows things down depends on the machine and the number
+ * being converted. If long long is available and the name is
+ * something other than "long long", #define Llong to be the name,
+ * and if "unsigned Llong" does not work as an unsigned version of
+ * Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ * FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ * if memory is available and otherwise does something you deem
+ * appropriate. If MALLOC is undefined, malloc will be invoked
+ * directly -- and assumed always to succeed.
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ * memory allocations from a private pool of memory when possible.
+ * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes,
+ * unless #defined to be a different length. This default length
+ * suffices to get rid of MALLOC calls except for unusual cases,
+ * such as decimal-to-binary conversion of a very long string of
+ * digits. The longest string dtoa can return is about 751 bytes
+ * long. For conversions by strtod of strings of 800 digits and
+ * all dtoa conversions in single-threaded executions with 8-byte
+ * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte
+ * pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define INFNAN_CHECK on IEEE systems to cause strtod to check for
+ * Infinity and NaN (case insensitively). On some systems (e.g.,
+ * some HP systems), it may be necessary to #define NAN_WORD0
+ * appropriately -- to the most significant word of a quiet NaN.
+ * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ * strtod also accepts (case insensitively) strings of the form
+ * NaN(x), where x is a string of hexadecimal digits and spaces;
+ * if there is only one string of hexadecimal digits, it is taken
+ * for the 52 fraction bits of the resulting NaN; if there are two
+ * or more strings of hex digits, the first is for the high 20 bits,
+ * the second and subsequent for the low 32 bits, with intervening
+ * white space ignored; but if this results in none of the 52
+ * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0
+ * and NAN_WORD1 are used instead.
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ * multiple threads. In this case, you must provide (or suitably
+ * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed
+ * in pow5mult, ensures lazy evaluation of only one copy of high
+ * powers of 5; omitting this lock would introduce a small
+ * probability of wasting memory, but would otherwise be harmless.)
+ * You must also invoke freedtoa(s) to free the value s returned by
+ * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that
+ * avoids underflows on inputs whose result does not underflow.
+ * If you #define NO_IEEE_Scale on a machine that uses IEEE-format
+ * floating-point numbers and flushes underflows to zero rather
+ * than implementing gradual underflow, then you must also #define
+ * Sudden_Underflow.
+ * #define YES_ALIAS to permit aliasing certain double values with
+ * arrays of ULongs. This leads to slightly better code with
+ * some compilers and was always used prior to 19990916, but it
+ * is not strictly legal and can cause trouble with aggressively
+ * optimizing compilers (e.g., gcc 2.95.1 under -O2).
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ * #define SET_INEXACT if IEEE arithmetic is being used and extra
+ * computation should be done to set the inexact flag when the
+ * result is inexact and avoid setting inexact when the result
+ * is exact. In this case, dtoa.c must be compiled in
+ * an environment, perhaps provided by #include "dtoa.c" in a
+ * suitable wrapper, that defines two functions,
+ * int get_inexact(void);
+ * void clear_inexact(void);
+ * such that get_inexact() returns a nonzero value if the
+ * inexact bit is already set, and clear_inexact() sets the
+ * inexact bit to 0. When SET_INEXACT is #defined, strtod
+ * also does extra computations to set the underflow and overflow
+ * flags when appropriate (i.e., when the result is tiny and
+ * inexact or when it is a numeric value rounded to +-infinity).
+ * #define NO_ERRNO if strtod should not assign errno = ERANGE when
+ * the result overflows to +-Infinity or underflows to 0.
+ */
+
+#ifdef WORDS_BIGENDIAN
+#define IEEE_BIG_ENDIAN
+#else
+#define IEEE_LITTLE_ENDIAN
+#endif
+
+#ifdef __vax__
+#define VAX
+#undef IEEE_BIG_ENDIAN
+#undef IEEE_LITTLE_ENDIAN
+#endif
+
+#if defined(__arm__) && !defined(__VFP_FP__)
+#define IEEE_BIG_ENDIAN
+#undef IEEE_LITTLE_ENDIAN
+#endif
+
+#undef Long
+#undef ULong
+
+#include <limits.h>
+
+#if (INT_MAX >> 30) && !(INT_MAX >> 31)
+#define Long int
+#define ULong unsigned int
+#elif (LONG_MAX >> 30) && !(LONG_MAX >> 31)
+#define Long long int
+#define ULong unsigned long int
+#else
+#error No 32bit integer
+#endif
+
+#if HAVE_LONG_LONG
+#define Llong LONG_LONG
+#else
+#define NO_LONG_LONG
+#endif
+
+#ifdef DEBUG
+#include <stdio.h>
+#define Bug(x) {fprintf(stderr, "%s\n", (x)); exit(EXIT_FAILURE);}
+#endif
+
+#ifndef ISDIGIT
+#include <ctype.h>
+#define ISDIGIT(c) isdigit(c)
+#endif
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef USE_LOCALE
+#include <locale.h>
+#endif
+
+#ifdef MALLOC
+extern void *MALLOC(size_t);
+#else
+#define MALLOC xmalloc
+#endif
+#ifdef FREE
+extern void FREE(void*);
+#else
+#define FREE xfree
+#endif
+#ifndef NO_SANITIZE
+#define NO_SANITIZE(x, y) y
+#endif
+
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_BIG_ENDIAN
+#define IEEE_Arith
+#endif
+#ifdef IEEE_LITTLE_ENDIAN
+#define IEEE_Arith
+#endif
+
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#endif /*IEEE_Arith*/
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include <float.h>
+#endif /* Bad_float_h */
+
+#include <math.h>
+
+#ifdef __cplusplus
+extern "C" {
+#if 0
+} /* satisfy cc-mode */
+#endif
+#endif
+
+#ifndef hexdigit
+static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
+#endif
+
+#if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_LITTLE_ENDIAN, IEEE_BIG_ENDIAN, VAX, or IBM should be defined.
+#endif
+
+typedef union { double d; ULong L[2]; } U;
+
+#ifdef YES_ALIAS
+typedef double double_u;
+# define dval(x) (x)
+# ifdef IEEE_LITTLE_ENDIAN
+# define word0(x) (((ULong *)&(x))[1])
+# define word1(x) (((ULong *)&(x))[0])
+# else
+# define word0(x) (((ULong *)&(x))[0])
+# define word1(x) (((ULong *)&(x))[1])
+# endif
+#else
+typedef U double_u;
+# ifdef IEEE_LITTLE_ENDIAN
+# define word0(x) ((x).L[1])
+# define word1(x) ((x).L[0])
+# else
+# define word0(x) ((x).L[0])
+# define word1(x) ((x).L[1])
+# endif
+# define dval(x) ((x).d)
+#endif
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_LITTLE_ENDIAN) + defined(VAX) + defined(__arm__)
+#define Storeinc(a,b,c) (((unsigned short *)(a))[1] = (unsigned short)(b), \
+((unsigned short *)(a))[0] = (unsigned short)(c), (a)++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)(a))[0] = (unsigned short)(b), \
+((unsigned short *)(a))[1] = (unsigned short)(c), (a)++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift 20
+#define Exp_shift1 20
+#define Exp_msk1 0x100000
+#define Exp_msk11 0x100000
+#define Exp_mask 0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1 0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask 0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask 0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+#ifndef NO_IEEE_Scale
+#define Avoid_Underflow
+#ifdef Flush_Denorm /* debugging option */
+#undef Sudden_Underflow
+#endif
+#endif
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#ifdef Honor_FLT_ROUNDS
+#define Rounding rounding
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+#else /* ifndef IEEE_Arith */
+#undef Check_FLT_ROUNDS
+#undef Honor_FLT_ROUNDS
+#undef SET_INEXACT
+#undef Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift 24
+#define Exp_shift1 24
+#define Exp_msk1 0x1000000
+#define Exp_msk11 0x1000000
+#define Exp_mask 0x7f000000
+#define P 14
+#define Bias 65
+#define Exp_1 0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask 0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask 0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift 23
+#define Exp_shift1 7
+#define Exp_msk1 0x80
+#define Exp_msk11 0x800000
+#define Exp_mask 0x7f80
+#define P 56
+#define Bias 129
+#define Exp_1 0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask 0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask 0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) ((a) = rnd_prod((a), (b)))
+#define rounded_quotient(a,b) ((a) = rnd_quot((a), (b)))
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#else
+#define rounded_product(a,b) ((a) *= (b))
+#define rounded_quotient(a,b) ((a) /= (b))
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+#define FFFFFFFF 0xffffffffUL
+
+#ifdef NO_LONG_LONG
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower. Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else /* long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#endif /* NO_LONG_LONG */
+
+#define MULTIPLE_THREADS 1
+
+#ifndef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n) /*nothing*/
+#define FREE_DTOA_LOCK(n) /*nothing*/
+#else
+#define ACQUIRE_DTOA_LOCK(n) /*unused right now*/
+#define FREE_DTOA_LOCK(n) /*unused right now*/
+#endif
+
+#ifndef ATOMIC_PTR_CAS
+#define ATOMIC_PTR_CAS(var, old, new) ((var) = (new), (old))
+#endif
+#ifndef LIKELY
+#define LIKELY(x) (x)
+#endif
+#ifndef UNLIKELY
+#define UNLIKELY(x) (x)
+#endif
+#ifndef ASSUME
+#define ASSUME(x) (void)(x)
+#endif
+
+#define Kmax 15
+
+struct Bigint {
+ struct Bigint *next;
+ int k, maxwds, sign, wds;
+ ULong x[1];
+};
+
+typedef struct Bigint Bigint;
+
+static Bigint *freelist[Kmax+1];
+
+static Bigint *
+Balloc(int k)
+{
+ int x;
+ Bigint *rv;
+#ifndef Omit_Private_Memory
+ size_t len;
+#endif
+
+ rv = 0;
+ ACQUIRE_DTOA_LOCK(0);
+ if (k <= Kmax) {
+ rv = freelist[k];
+ while (rv) {
+ Bigint *rvn = rv;
+ rv = ATOMIC_PTR_CAS(freelist[k], rv, rv->next);
+ if (LIKELY(rvn == rv)) {
+ ASSUME(rv);
+ break;
+ }
+ }
+ }
+ if (!rv) {
+ x = 1 << k;
+#ifdef Omit_Private_Memory
+ rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+#else
+ len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+ /sizeof(double);
+ if (k <= Kmax) {
+ double *pnext = pmem_next;
+ while (pnext - private_mem + len <= PRIVATE_mem) {
+ double *p = pnext;
+ pnext = ATOMIC_PTR_CAS(pmem_next, pnext, pnext + len);
+ if (LIKELY(p == pnext)) {
+ rv = (Bigint*)pnext;
+ ASSUME(rv);
+ break;
+ }
+ }
+ }
+ if (!rv)
+ rv = (Bigint*)MALLOC(len*sizeof(double));
+#endif
+ rv->k = k;
+ rv->maxwds = x;
+ }
+ FREE_DTOA_LOCK(0);
+ rv->sign = rv->wds = 0;
+ return rv;
+}
+
+static void
+Bfree(Bigint *v)
+{
+ Bigint *vn;
+ if (v) {
+ if (v->k > Kmax) {
+ FREE(v);
+ return;
+ }
+ ACQUIRE_DTOA_LOCK(0);
+ do {
+ vn = v->next = freelist[v->k];
+ } while (UNLIKELY(ATOMIC_PTR_CAS(freelist[v->k], vn, v) != vn));
+ FREE_DTOA_LOCK(0);
+ }
+}
+
+#define Bcopy(x,y) memcpy((char *)&(x)->sign, (char *)&(y)->sign, \
+(y)->wds*sizeof(Long) + 2*sizeof(int))
+
+static Bigint *
+multadd(Bigint *b, int m, int a) /* multiply by m and add a */
+{
+ int i, wds;
+ ULong *x;
+#ifdef ULLong
+ ULLong carry, y;
+#else
+ ULong carry, y;
+#ifdef Pack_32
+ ULong xi, z;
+#endif
+#endif
+ Bigint *b1;
+
+ wds = b->wds;
+ x = b->x;
+ i = 0;
+ carry = a;
+ do {
+#ifdef ULLong
+ y = *x * (ULLong)m + carry;
+ carry = y >> 32;
+ *x++ = (ULong)(y & FFFFFFFF);
+#else
+#ifdef Pack_32
+ xi = *x;
+ y = (xi & 0xffff) * m + carry;
+ z = (xi >> 16) * m + (y >> 16);
+ carry = z >> 16;
+ *x++ = (z << 16) + (y & 0xffff);
+#else
+ y = *x * m + carry;
+ carry = y >> 16;
+ *x++ = y & 0xffff;
+#endif
+#endif
+ } while (++i < wds);
+ if (carry) {
+ if (wds >= b->maxwds) {
+ b1 = Balloc(b->k+1);
+ Bcopy(b1, b);
+ Bfree(b);
+ b = b1;
+ }
+ b->x[wds++] = (ULong)carry;
+ b->wds = wds;
+ }
+ return b;
+}
+
+static Bigint *
+s2b(const char *s, int nd0, int nd, ULong y9)
+{
+ Bigint *b;
+ int i, k;
+ Long x, y;
+
+ x = (nd + 8) / 9;
+ for (k = 0, y = 1; x > y; y <<= 1, k++) ;
+#ifdef Pack_32
+ b = Balloc(k);
+ b->x[0] = y9;
+ b->wds = 1;
+#else
+ b = Balloc(k+1);
+ b->x[0] = y9 & 0xffff;
+ b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
+#endif
+
+ i = 9;
+ if (9 < nd0) {
+ s += 9;
+ do {
+ b = multadd(b, 10, *s++ - '0');
+ } while (++i < nd0);
+ s++;
+ }
+ else
+ s += 10;
+ for (; i < nd; i++)
+ b = multadd(b, 10, *s++ - '0');
+ return b;
+}
+
+static int
+hi0bits(register ULong x)
+{
+ register int k = 0;
+
+ if (!(x & 0xffff0000)) {
+ k = 16;
+ x <<= 16;
+ }
+ if (!(x & 0xff000000)) {
+ k += 8;
+ x <<= 8;
+ }
+ if (!(x & 0xf0000000)) {
+ k += 4;
+ x <<= 4;
+ }
+ if (!(x & 0xc0000000)) {
+ k += 2;
+ x <<= 2;
+ }
+ if (!(x & 0x80000000)) {
+ k++;
+ if (!(x & 0x40000000))
+ return 32;
+ }
+ return k;
+}
+
+static int
+lo0bits(ULong *y)
+{
+ register int k;
+ register ULong x = *y;
+
+ if (x & 7) {
+ if (x & 1)
+ return 0;
+ if (x & 2) {
+ *y = x >> 1;
+ return 1;
+ }
+ *y = x >> 2;
+ return 2;
+ }
+ k = 0;
+ if (!(x & 0xffff)) {
+ k = 16;
+ x >>= 16;
+ }
+ if (!(x & 0xff)) {
+ k += 8;
+ x >>= 8;
+ }
+ if (!(x & 0xf)) {
+ k += 4;
+ x >>= 4;
+ }
+ if (!(x & 0x3)) {
+ k += 2;
+ x >>= 2;
+ }
+ if (!(x & 1)) {
+ k++;
+ x >>= 1;
+ if (!x)
+ return 32;
+ }
+ *y = x;
+ return k;
+}
+
+static Bigint *
+i2b(int i)
+{
+ Bigint *b;
+
+ b = Balloc(1);
+ b->x[0] = i;
+ b->wds = 1;
+ return b;
+}
+
+static Bigint *
+mult(Bigint *a, Bigint *b)
+{
+ Bigint *c;
+ int k, wa, wb, wc;
+ ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+ ULong y;
+#ifdef ULLong
+ ULLong carry, z;
+#else
+ ULong carry, z;
+#ifdef Pack_32
+ ULong z2;
+#endif
+#endif
+
+ if (a->wds < b->wds) {
+ c = a;
+ a = b;
+ b = c;
+ }
+ k = a->k;
+ wa = a->wds;
+ wb = b->wds;
+ wc = wa + wb;
+ if (wc > a->maxwds)
+ k++;
+ c = Balloc(k);
+ for (x = c->x, xa = x + wc; x < xa; x++)
+ *x = 0;
+ xa = a->x;
+ xae = xa + wa;
+ xb = b->x;
+ xbe = xb + wb;
+ xc0 = c->x;
+#ifdef ULLong
+ for (; xb < xbe; xc0++) {
+ if ((y = *xb++) != 0) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * (ULLong)y + *xc + carry;
+ carry = z >> 32;
+ *xc++ = (ULong)(z & FFFFFFFF);
+ } while (x < xae);
+ *xc = (ULong)carry;
+ }
+ }
+#else
+#ifdef Pack_32
+ for (; xb < xbe; xb++, xc0++) {
+ if ((y = *xb & 0xffff) != 0) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+ carry = z >> 16;
+ z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+ carry = z2 >> 16;
+ Storeinc(xc, z2, z);
+ } while (x < xae);
+ *xc = (ULong)carry;
+ }
+ if ((y = *xb >> 16) != 0) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ z2 = *xc;
+ do {
+ z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+ carry = z >> 16;
+ Storeinc(xc, z, z2);
+ z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+ carry = z2 >> 16;
+ } while (x < xae);
+ *xc = z2;
+ }
+ }
+#else
+ for (; xb < xbe; xc0++) {
+ if (y = *xb++) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * y + *xc + carry;
+ carry = z >> 16;
+ *xc++ = z & 0xffff;
+ } while (x < xae);
+ *xc = (ULong)carry;
+ }
+ }
+#endif
+#endif
+ for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+ c->wds = wc;
+ return c;
+}
+
+static Bigint *p5s;
+
+static Bigint *
+pow5mult(Bigint *b, int k)
+{
+ Bigint *b1, *p5, *p51;
+ Bigint *p5tmp;
+ int i;
+ static const int p05[3] = { 5, 25, 125 };
+
+ if ((i = k & 3) != 0)
+ b = multadd(b, p05[i-1], 0);
+
+ if (!(k >>= 2))
+ return b;
+ if (!(p5 = p5s)) {
+ /* first time */
+ ACQUIRE_DTOA_LOCK(1);
+ if (!(p5 = p5s)) {
+ p5 = i2b(625);
+ p5->next = 0;
+ p5tmp = ATOMIC_PTR_CAS(p5s, NULL, p5);
+ if (UNLIKELY(p5tmp)) {
+ Bfree(p5);
+ p5 = p5tmp;
+ }
+ }
+ FREE_DTOA_LOCK(1);
+ }
+ for (;;) {
+ if (k & 1) {
+ b1 = mult(b, p5);
+ Bfree(b);
+ b = b1;
+ }
+ if (!(k >>= 1))
+ break;
+ if (!(p51 = p5->next)) {
+ ACQUIRE_DTOA_LOCK(1);
+ if (!(p51 = p5->next)) {
+ p51 = mult(p5,p5);
+ p51->next = 0;
+ p5tmp = ATOMIC_PTR_CAS(p5->next, NULL, p51);
+ if (UNLIKELY(p5tmp)) {
+ Bfree(p51);
+ p51 = p5tmp;
+ }
+ }
+ FREE_DTOA_LOCK(1);
+ }
+ p5 = p51;
+ }
+ return b;
+}
+
+static Bigint *
+lshift(Bigint *b, int k)
+{
+ int i, k1, n, n1;
+ Bigint *b1;
+ ULong *x, *x1, *xe, z;
+
+#ifdef Pack_32
+ n = k >> 5;
+#else
+ n = k >> 4;
+#endif
+ k1 = b->k;
+ n1 = n + b->wds + 1;
+ for (i = b->maxwds; n1 > i; i <<= 1)
+ k1++;
+ b1 = Balloc(k1);
+ x1 = b1->x;
+ for (i = 0; i < n; i++)
+ *x1++ = 0;
+ x = b->x;
+ xe = x + b->wds;
+#ifdef Pack_32
+ if (k &= 0x1f) {
+ k1 = 32 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k | z;
+ z = *x++ >> k1;
+ } while (x < xe);
+ if ((*x1 = z) != 0)
+ ++n1;
+ }
+#else
+ if (k &= 0xf) {
+ k1 = 16 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k & 0xffff | z;
+ z = *x++ >> k1;
+ } while (x < xe);
+ if (*x1 = z)
+ ++n1;
+ }
+#endif
+ else
+ do {
+ *x1++ = *x++;
+ } while (x < xe);
+ b1->wds = n1 - 1;
+ Bfree(b);
+ return b1;
+}
+
+static int
+cmp(Bigint *a, Bigint *b)
+{
+ ULong *xa, *xa0, *xb, *xb0;
+ int i, j;
+
+ i = a->wds;
+ j = b->wds;
+#ifdef DEBUG
+ if (i > 1 && !a->x[i-1])
+ Bug("cmp called with a->x[a->wds-1] == 0");
+ if (j > 1 && !b->x[j-1])
+ Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+ if (i -= j)
+ return i;
+ xa0 = a->x;
+ xa = xa0 + j;
+ xb0 = b->x;
+ xb = xb0 + j;
+ for (;;) {
+ if (*--xa != *--xb)
+ return *xa < *xb ? -1 : 1;
+ if (xa <= xa0)
+ break;
+ }
+ return 0;
+}
+
+NO_SANITIZE("unsigned-integer-overflow", static Bigint * diff(Bigint *a, Bigint *b));
+static Bigint *
+diff(Bigint *a, Bigint *b)
+{
+ Bigint *c;
+ int i, wa, wb;
+ ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+ ULLong borrow, y;
+#else
+ ULong borrow, y;
+#ifdef Pack_32
+ ULong z;
+#endif
+#endif
+
+ i = cmp(a,b);
+ if (!i) {
+ c = Balloc(0);
+ c->wds = 1;
+ c->x[0] = 0;
+ return c;
+ }
+ if (i < 0) {
+ c = a;
+ a = b;
+ b = c;
+ i = 1;
+ }
+ else
+ i = 0;
+ c = Balloc(a->k);
+ c->sign = i;
+ wa = a->wds;
+ xa = a->x;
+ xae = xa + wa;
+ wb = b->wds;
+ xb = b->x;
+ xbe = xb + wb;
+ xc = c->x;
+ borrow = 0;
+#ifdef ULLong
+ do {
+ y = (ULLong)*xa++ - *xb++ - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *xc++ = (ULong)(y & FFFFFFFF);
+ } while (xb < xbe);
+ while (xa < xae) {
+ y = *xa++ - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *xc++ = (ULong)(y & FFFFFFFF);
+ }
+#else
+#ifdef Pack_32
+ do {
+ y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ } while (xb < xbe);
+ while (xa < xae) {
+ y = (*xa & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ }
+#else
+ do {
+ y = *xa++ - *xb++ - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ } while (xb < xbe);
+ while (xa < xae) {
+ y = *xa++ - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ }
+#endif
+#endif
+ while (!*--xc)
+ wa--;
+ c->wds = wa;
+ return c;
+}
+
+static double
+ulp(double x_)
+{
+ register Long L;
+ double_u x, a;
+ dval(x) = x_;
+
+ L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+ if (L > 0) {
+#endif
+#endif
+#ifdef IBM
+ L |= Exp_msk1 >> 4;
+#endif
+ word0(a) = L;
+ word1(a) = 0;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+ }
+ else {
+ L = -L >> Exp_shift;
+ if (L < Exp_shift) {
+ word0(a) = 0x80000 >> L;
+ word1(a) = 0;
+ }
+ else {
+ word0(a) = 0;
+ L -= Exp_shift;
+ word1(a) = L >= 31 ? 1 : 1 << 31 - L;
+ }
+ }
+#endif
+#endif
+ return dval(a);
+}
+
+static double
+b2d(Bigint *a, int *e)
+{
+ ULong *xa, *xa0, w, y, z;
+ int k;
+ double_u d;
+#ifdef VAX
+ ULong d0, d1;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+ xa0 = a->x;
+ xa = xa0 + a->wds;
+ y = *--xa;
+#ifdef DEBUG
+ if (!y) Bug("zero y in b2d");
+#endif
+ k = hi0bits(y);
+ *e = 32 - k;
+#ifdef Pack_32
+ if (k < Ebits) {
+ d0 = Exp_1 | y >> (Ebits - k);
+ w = xa > xa0 ? *--xa : 0;
+ d1 = y << ((32-Ebits) + k) | w >> (Ebits - k);
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ if (k -= Ebits) {
+ d0 = Exp_1 | y << k | z >> (32 - k);
+ y = xa > xa0 ? *--xa : 0;
+ d1 = z << k | y >> (32 - k);
+ }
+ else {
+ d0 = Exp_1 | y;
+ d1 = z;
+ }
+#else
+ if (k < Ebits + 16) {
+ z = xa > xa0 ? *--xa : 0;
+ d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+ w = xa > xa0 ? *--xa : 0;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ w = xa > xa0 ? *--xa : 0;
+ k -= Ebits + 16;
+ d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = w << k + 16 | y << k;
+#endif
+ret_d:
+#ifdef VAX
+ word0(d) = d0 >> 16 | d0 << 16;
+ word1(d) = d1 >> 16 | d1 << 16;
+#else
+#undef d0
+#undef d1
+#endif
+ return dval(d);
+}
+
+static Bigint *
+d2b(double d_, int *e, int *bits)
+{
+ double_u d;
+ Bigint *b;
+ int de, k;
+ ULong *x, y, z;
+#ifndef Sudden_Underflow
+ int i;
+#endif
+#ifdef VAX
+ ULong d0, d1;
+#endif
+ dval(d) = d_;
+#ifdef VAX
+ d0 = word0(d) >> 16 | word0(d) << 16;
+ d1 = word1(d) >> 16 | word1(d) << 16;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+#ifdef Pack_32
+ b = Balloc(1);
+#else
+ b = Balloc(2);
+#endif
+ x = b->x;
+
+ z = d0 & Frac_mask;
+ d0 &= 0x7fffffff; /* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+ de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+ z |= Exp_msk11;
+#endif
+#else
+ if ((de = (int)(d0 >> Exp_shift)) != 0)
+ z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+ if ((y = d1) != 0) {
+ if ((k = lo0bits(&y)) != 0) {
+ x[0] = y | z << (32 - k);
+ z >>= k;
+ }
+ else
+ x[0] = y;
+#ifndef Sudden_Underflow
+ i =
+#endif
+ b->wds = (x[1] = z) ? 2 : 1;
+ }
+ else {
+#ifdef DEBUG
+ if (!z)
+ Bug("Zero passed to d2b");
+#endif
+ k = lo0bits(&z);
+ x[0] = z;
+#ifndef Sudden_Underflow
+ i =
+#endif
+ b->wds = 1;
+ k += 32;
+ }
+#else
+ if (y = d1) {
+ if (k = lo0bits(&y))
+ if (k >= 16) {
+ x[0] = y | z << 32 - k & 0xffff;
+ x[1] = z >> k - 16 & 0xffff;
+ x[2] = z >> k;
+ i = 2;
+ }
+ else {
+ x[0] = y & 0xffff;
+ x[1] = y >> 16 | z << 16 - k & 0xffff;
+ x[2] = z >> k & 0xffff;
+ x[3] = z >> k+16;
+ i = 3;
+ }
+ else {
+ x[0] = y & 0xffff;
+ x[1] = y >> 16;
+ x[2] = z & 0xffff;
+ x[3] = z >> 16;
+ i = 3;
+ }
+ }
+ else {
+#ifdef DEBUG
+ if (!z)
+ Bug("Zero passed to d2b");
+#endif
+ k = lo0bits(&z);
+ if (k >= 16) {
+ x[0] = z;
+ i = 0;
+ }
+ else {
+ x[0] = z & 0xffff;
+ x[1] = z >> 16;
+ i = 1;
+ }
+ k += 32;
+ }
+ while (!x[i])
+ --i;
+ b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+ if (de) {
+#endif
+#ifdef IBM
+ *e = (de - Bias - (P-1) << 2) + k;
+ *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask);
+#else
+ *e = de - Bias - (P-1) + k;
+ *bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+ }
+ else {
+ *e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+ *bits = 32*i - hi0bits(x[i-1]);
+#else
+ *bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+ }
+#endif
+ return b;
+}
+#undef d0
+#undef d1
+
+static double
+ratio(Bigint *a, Bigint *b)
+{
+ double_u da, db;
+ int k, ka, kb;
+
+ dval(da) = b2d(a, &ka);
+ dval(db) = b2d(b, &kb);
+#ifdef Pack_32
+ k = ka - kb + 32*(a->wds - b->wds);
+#else
+ k = ka - kb + 16*(a->wds - b->wds);
+#endif
+#ifdef IBM
+ if (k > 0) {
+ word0(da) += (k >> 2)*Exp_msk1;
+ if (k &= 3)
+ dval(da) *= 1 << k;
+ }
+ else {
+ k = -k;
+ word0(db) += (k >> 2)*Exp_msk1;
+ if (k &= 3)
+ dval(db) *= 1 << k;
+ }
+#else
+ if (k > 0)
+ word0(da) += k*Exp_msk1;
+ else {
+ k = -k;
+ word0(db) += k*Exp_msk1;
+ }
+#endif
+ return dval(da) / dval(db);
+}
+
+static const double
+tens[] = {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22
+#ifdef VAX
+ , 1e23, 1e24
+#endif
+};
+
+static const double
+#ifdef IEEE_Arith
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
+#ifdef Avoid_Underflow
+ 9007199254740992.*9007199254740992.e-256
+ /* = 2^106 * 1e-53 */
+#else
+ 1e-256
+#endif
+};
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily. It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#else
+#ifdef IBM
+bigtens[] = { 1e16, 1e32, 1e64 };
+static const double tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#define n_bigtens 3
+#else
+bigtens[] = { 1e16, 1e32 };
+static const double tinytens[] = { 1e-16, 1e-32 };
+#define n_bigtens 2
+#endif
+#endif
+
+#ifndef IEEE_Arith
+#undef INFNAN_CHECK
+#endif
+
+#ifdef INFNAN_CHECK
+
+#ifndef NAN_WORD0
+#define NAN_WORD0 0x7ff80000
+#endif
+
+#ifndef NAN_WORD1
+#define NAN_WORD1 0
+#endif
+
+static int
+match(const char **sp, char *t)
+{
+ int c, d;
+ const char *s = *sp;
+
+ while (d = *t++) {
+ if ((c = *++s) >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ if (c != d)
+ return 0;
+ }
+ *sp = s + 1;
+ return 1;
+}
+
+#ifndef No_Hex_NaN
+static void
+hexnan(double *rvp, const char **sp)
+{
+ ULong c, x[2];
+ const char *s;
+ int havedig, udx0, xshift;
+
+ x[0] = x[1] = 0;
+ havedig = xshift = 0;
+ udx0 = 1;
+ s = *sp;
+ while (c = *(const unsigned char*)++s) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'a' && c <= 'f')
+ c += 10 - 'a';
+ else if (c >= 'A' && c <= 'F')
+ c += 10 - 'A';
+ else if (c <= ' ') {
+ if (udx0 && havedig) {
+ udx0 = 0;
+ xshift = 1;
+ }
+ continue;
+ }
+ else if (/*(*/ c == ')' && havedig) {
+ *sp = s + 1;
+ break;
+ }
+ else
+ return; /* invalid form: don't change *sp */
+ havedig = 1;
+ if (xshift) {
+ xshift = 0;
+ x[0] = x[1];
+ x[1] = 0;
+ }
+ if (udx0)
+ x[0] = (x[0] << 4) | (x[1] >> 28);
+ x[1] = (x[1] << 4) | c;
+ }
+ if ((x[0] &= 0xfffff) || x[1]) {
+ word0(*rvp) = Exp_mask | x[0];
+ word1(*rvp) = x[1];
+ }
+}
+#endif /*No_Hex_NaN*/
+#endif /* INFNAN_CHECK */
+
+NO_SANITIZE("unsigned-integer-overflow", double strtod(const char *s00, char **se));
+double
+strtod(const char *s00, char **se)
+{
+#ifdef Avoid_Underflow
+ int scale;
+#endif
+ int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
+ e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+ const char *s, *s0, *s1;
+ double aadj, adj;
+ double_u aadj1, rv, rv0;
+ Long L;
+ ULong y, z;
+ Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
+#ifdef SET_INEXACT
+ int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS
+ int rounding;
+#endif
+#ifdef USE_LOCALE
+ const char *s2;
+#endif
+
+ errno = 0;
+ sign = nz0 = nz = 0;
+ dval(rv) = 0.;
+ for (s = s00;;s++)
+ switch (*s) {
+ case '-':
+ sign = 1;
+ /* no break */
+ case '+':
+ if (*++s)
+ goto break2;
+ /* no break */
+ case 0:
+ goto ret0;
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case ' ':
+ continue;
+ default:
+ goto break2;
+ }
+break2:
+ if (*s == '0') {
+ if (s[1] == 'x' || s[1] == 'X') {
+ s0 = ++s;
+ adj = 0;
+ aadj = 1.0;
+ nd0 = -4;
+
+ if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0;
+ if (*s == '0') {
+ while (*++s == '0');
+ s1 = strchr(hexdigit, *s);
+ }
+ if (s1 != NULL) {
+ do {
+ adj += aadj * ((s1 - hexdigit) & 15);
+ nd0 += 4;
+ aadj /= 16;
+ } while (*++s && (s1 = strchr(hexdigit, *s)));
+ }
+
+ if (*s == '.') {
+ dsign = 1;
+ if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0;
+ if (nd0 < 0) {
+ while (*s == '0') {
+ s++;
+ nd0 -= 4;
+ }
+ }
+ for (; *s && (s1 = strchr(hexdigit, *s)); ++s) {
+ adj += aadj * ((s1 - hexdigit) & 15);
+ if ((aadj /= 16) == 0.0) {
+ while (strchr(hexdigit, *++s));
+ break;
+ }
+ }
+ }
+ else {
+ dsign = 0;
+ }
+
+ if (*s == 'P' || *s == 'p') {
+ dsign = 0x2C - *++s; /* +: 2B, -: 2D */
+ if (abs(dsign) == 1) s++;
+ else dsign = 1;
+
+ nd = 0;
+ c = *s;
+ if (c < '0' || '9' < c) goto ret0;
+ do {
+ nd *= 10;
+ nd += c;
+ nd -= '0';
+ c = *++s;
+ /* Float("0x0."+("0"*267)+"1fp2095") */
+ if (nd + dsign * nd0 > 2095) {
+ while ('0' <= c && c <= '9') c = *++s;
+ break;
+ }
+ } while ('0' <= c && c <= '9');
+ nd0 += nd * dsign;
+ }
+ else {
+ if (dsign) goto ret0;
+ }
+ dval(rv) = ldexp(adj, nd0);
+ goto ret;
+ }
+ nz0 = 1;
+ while (*++s == '0') ;
+ if (!*s)
+ goto ret;
+ }
+ s0 = s;
+ y = z = 0;
+ for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+ if (nd < 9)
+ y = 10*y + c - '0';
+ else if (nd < DBL_DIG + 2)
+ z = 10*z + c - '0';
+ nd0 = nd;
+#ifdef USE_LOCALE
+ s1 = localeconv()->decimal_point;
+ if (c == *s1) {
+ c = '.';
+ if (*++s1) {
+ s2 = s;
+ for (;;) {
+ if (*++s2 != *s1) {
+ c = 0;
+ break;
+ }
+ if (!*++s1) {
+ s = s2;
+ break;
+ }
+ }
+ }
+ }
+#endif
+ if (c == '.') {
+ if (!ISDIGIT(s[1]))
+ goto dig_done;
+ c = *++s;
+ if (!nd) {
+ for (; c == '0'; c = *++s)
+ nz++;
+ if (c > '0' && c <= '9') {
+ s0 = s;
+ nf += nz;
+ nz = 0;
+ goto have_dig;
+ }
+ goto dig_done;
+ }
+ for (; c >= '0' && c <= '9'; c = *++s) {
+have_dig:
+ nz++;
+ if (nd > DBL_DIG * 4) {
+ continue;
+ }
+ if (c -= '0') {
+ nf += nz;
+ for (i = 1; i < nz; i++)
+ if (nd++ < 9)
+ y *= 10;
+ else if (nd <= DBL_DIG + 2)
+ z *= 10;
+ if (nd++ < 9)
+ y = 10*y + c;
+ else if (nd <= DBL_DIG + 2)
+ z = 10*z + c;
+ nz = 0;
+ }
+ }
+ }
+dig_done:
+ e = 0;
+ if (c == 'e' || c == 'E') {
+ if (!nd && !nz && !nz0) {
+ goto ret0;
+ }
+ s00 = s;
+ esign = 0;
+ switch (c = *++s) {
+ case '-':
+ esign = 1;
+ case '+':
+ c = *++s;
+ }
+ if (c >= '0' && c <= '9') {
+ while (c == '0')
+ c = *++s;
+ if (c > '0' && c <= '9') {
+ L = c - '0';
+ s1 = s;
+ while ((c = *++s) >= '0' && c <= '9')
+ L = 10*L + c - '0';
+ if (s - s1 > 8 || L > 19999)
+ /* Avoid confusion from exponents
+ * so large that e might overflow.
+ */
+ e = 19999; /* safe for 16 bit ints */
+ else
+ e = (int)L;
+ if (esign)
+ e = -e;
+ }
+ else
+ e = 0;
+ }
+ else
+ s = s00;
+ }
+ if (!nd) {
+ if (!nz && !nz0) {
+#ifdef INFNAN_CHECK
+ /* Check for Nan and Infinity */
+ switch (c) {
+ case 'i':
+ case 'I':
+ if (match(&s,"nf")) {
+ --s;
+ if (!match(&s,"inity"))
+ ++s;
+ word0(rv) = 0x7ff00000;
+ word1(rv) = 0;
+ goto ret;
+ }
+ break;
+ case 'n':
+ case 'N':
+ if (match(&s, "an")) {
+ word0(rv) = NAN_WORD0;
+ word1(rv) = NAN_WORD1;
+#ifndef No_Hex_NaN
+ if (*s == '(') /*)*/
+ hexnan(&rv, &s);
+#endif
+ goto ret;
+ }
+ }
+#endif /* INFNAN_CHECK */
+ret0:
+ s = s00;
+ sign = 0;
+ }
+ goto ret;
+ }
+ e1 = e -= nf;
+
+ /* Now we have nd0 digits, starting at s0, followed by a
+ * decimal point, followed by nd-nd0 digits. The number we're
+ * after is the integer represented by those digits times
+ * 10**e */
+
+ if (!nd0)
+ nd0 = nd;
+ k = nd < DBL_DIG + 2 ? nd : DBL_DIG + 2;
+ dval(rv) = y;
+ if (k > 9) {
+#ifdef SET_INEXACT
+ if (k > DBL_DIG)
+ oldinexact = get_inexact();
+#endif
+ dval(rv) = tens[k - 9] * dval(rv) + z;
+ }
+ bd0 = bb = bd = bs = delta = 0;
+ if (nd <= DBL_DIG
+#ifndef RND_PRODQUOT
+#ifndef Honor_FLT_ROUNDS
+ && Flt_Rounds == 1
+#endif
+#endif
+ ) {
+ if (!e)
+ goto ret;
+ if (e > 0) {
+ if (e <= Ten_pmax) {
+#ifdef VAX
+ goto vax_ovfl_check;
+#else
+#ifdef Honor_FLT_ROUNDS
+ /* round correctly FLT_ROUNDS = 2 or 3 */
+ if (sign) {
+ dval(rv) = -dval(rv);
+ sign = 0;
+ }
+#endif
+ /* rv = */ rounded_product(dval(rv), tens[e]);
+ goto ret;
+#endif
+ }
+ i = DBL_DIG - nd;
+ if (e <= Ten_pmax + i) {
+ /* A fancier test would sometimes let us do
+ * this for larger i values.
+ */
+#ifdef Honor_FLT_ROUNDS
+ /* round correctly FLT_ROUNDS = 2 or 3 */
+ if (sign) {
+ dval(rv) = -dval(rv);
+ sign = 0;
+ }
+#endif
+ e -= i;
+ dval(rv) *= tens[i];
+#ifdef VAX
+ /* VAX exponent range is so narrow we must
+ * worry about overflow here...
+ */
+vax_ovfl_check:
+ word0(rv) -= P*Exp_msk1;
+ /* rv = */ rounded_product(dval(rv), tens[e]);
+ if ((word0(rv) & Exp_mask)
+ > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
+ goto ovfl;
+ word0(rv) += P*Exp_msk1;
+#else
+ /* rv = */ rounded_product(dval(rv), tens[e]);
+#endif
+ goto ret;
+ }
+ }
+#ifndef Inaccurate_Divide
+ else if (e >= -Ten_pmax) {
+#ifdef Honor_FLT_ROUNDS
+ /* round correctly FLT_ROUNDS = 2 or 3 */
+ if (sign) {
+ dval(rv) = -dval(rv);
+ sign = 0;
+ }
+#endif
+ /* rv = */ rounded_quotient(dval(rv), tens[-e]);
+ goto ret;
+ }
+#endif
+ }
+ e1 += nd - k;
+
+#ifdef IEEE_Arith
+#ifdef SET_INEXACT
+ inexact = 1;
+ if (k <= DBL_DIG)
+ oldinexact = get_inexact();
+#endif
+#ifdef Avoid_Underflow
+ scale = 0;
+#endif
+#ifdef Honor_FLT_ROUNDS
+ if ((rounding = Flt_Rounds) >= 2) {
+ if (sign)
+ rounding = rounding == 2 ? 0 : 2;
+ else
+ if (rounding != 2)
+ rounding = 0;
+ }
+#endif
+#endif /*IEEE_Arith*/
+
+ /* Get starting approximation = rv * 10**e1 */
+
+ if (e1 > 0) {
+ if ((i = e1 & 15) != 0)
+ dval(rv) *= tens[i];
+ if (e1 &= ~15) {
+ if (e1 > DBL_MAX_10_EXP) {
+ovfl:
+#ifndef NO_ERRNO
+ errno = ERANGE;
+#endif
+ /* Can't trust HUGE_VAL */
+#ifdef IEEE_Arith
+#ifdef Honor_FLT_ROUNDS
+ switch (rounding) {
+ case 0: /* toward 0 */
+ case 3: /* toward -infinity */
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+ break;
+ default:
+ word0(rv) = Exp_mask;
+ word1(rv) = 0;
+ }
+#else /*Honor_FLT_ROUNDS*/
+ word0(rv) = Exp_mask;
+ word1(rv) = 0;
+#endif /*Honor_FLT_ROUNDS*/
+#ifdef SET_INEXACT
+ /* set overflow bit */
+ dval(rv0) = 1e300;
+ dval(rv0) *= dval(rv0);
+#endif
+#else /*IEEE_Arith*/
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+#endif /*IEEE_Arith*/
+ if (bd0)
+ goto retfree;
+ goto ret;
+ }
+ e1 >>= 4;
+ for (j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(rv) *= bigtens[j];
+ /* The last multiplication could overflow. */
+ word0(rv) -= P*Exp_msk1;
+ dval(rv) *= bigtens[j];
+ if ((z = word0(rv) & Exp_mask)
+ > Exp_msk1*(DBL_MAX_EXP+Bias-P))
+ goto ovfl;
+ if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
+ /* set to largest number */
+ /* (Can't trust DBL_MAX) */
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+ }
+ else
+ word0(rv) += P*Exp_msk1;
+ }
+ }
+ else if (e1 < 0) {
+ e1 = -e1;
+ if ((i = e1 & 15) != 0)
+ dval(rv) /= tens[i];
+ if (e1 >>= 4) {
+ if (e1 >= 1 << n_bigtens)
+ goto undfl;
+#ifdef Avoid_Underflow
+ if (e1 & Scale_Bit)
+ scale = 2*P;
+ for (j = 0; e1 > 0; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(rv) *= tinytens[j];
+ if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask)
+ >> Exp_shift)) > 0) {
+ /* scaled rv is denormal; zap j low bits */
+ if (j >= 32) {
+ word1(rv) = 0;
+ if (j >= 53)
+ word0(rv) = (P+2)*Exp_msk1;
+ else
+ word0(rv) &= 0xffffffff << (j-32);
+ }
+ else
+ word1(rv) &= 0xffffffff << j;
+ }
+#else
+ for (j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(rv) *= tinytens[j];
+ /* The last multiplication could underflow. */
+ dval(rv0) = dval(rv);
+ dval(rv) *= tinytens[j];
+ if (!dval(rv)) {
+ dval(rv) = 2.*dval(rv0);
+ dval(rv) *= tinytens[j];
+#endif
+ if (!dval(rv)) {
+undfl:
+ dval(rv) = 0.;
+#ifndef NO_ERRNO
+ errno = ERANGE;
+#endif
+ if (bd0)
+ goto retfree;
+ goto ret;
+ }
+#ifndef Avoid_Underflow
+ word0(rv) = Tiny0;
+ word1(rv) = Tiny1;
+ /* The refinement below will clean
+ * this approximation up.
+ */
+ }
+#endif
+ }
+ }
+
+ /* Now the hard part -- adjusting rv to the correct value.*/
+
+ /* Put digits into bd: true value = bd * 10^e */
+
+ bd0 = s2b(s0, nd0, nd, y);
+
+ for (;;) {
+ bd = Balloc(bd0->k);
+ Bcopy(bd, bd0);
+ bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */
+ bs = i2b(1);
+
+ if (e >= 0) {
+ bb2 = bb5 = 0;
+ bd2 = bd5 = e;
+ }
+ else {
+ bb2 = bb5 = -e;
+ bd2 = bd5 = 0;
+ }
+ if (bbe >= 0)
+ bb2 += bbe;
+ else
+ bd2 -= bbe;
+ bs2 = bb2;
+#ifdef Honor_FLT_ROUNDS
+ if (rounding != 1)
+ bs2++;
+#endif
+#ifdef Avoid_Underflow
+ j = bbe - scale;
+ i = j + bbbits - 1; /* logb(rv) */
+ if (i < Emin) /* denormal */
+ j += P - Emin;
+ else
+ j = P + 1 - bbbits;
+#else /*Avoid_Underflow*/
+#ifdef Sudden_Underflow
+#ifdef IBM
+ j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3);
+#else
+ j = P + 1 - bbbits;
+#endif
+#else /*Sudden_Underflow*/
+ j = bbe;
+ i = j + bbbits - 1; /* logb(rv) */
+ if (i < Emin) /* denormal */
+ j += P - Emin;
+ else
+ j = P + 1 - bbbits;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ bb2 += j;
+ bd2 += j;
+#ifdef Avoid_Underflow
+ bd2 += scale;
+#endif
+ i = bb2 < bd2 ? bb2 : bd2;
+ if (i > bs2)
+ i = bs2;
+ if (i > 0) {
+ bb2 -= i;
+ bd2 -= i;
+ bs2 -= i;
+ }
+ if (bb5 > 0) {
+ bs = pow5mult(bs, bb5);
+ bb1 = mult(bs, bb);
+ Bfree(bb);
+ bb = bb1;
+ }
+ if (bb2 > 0)
+ bb = lshift(bb, bb2);
+ if (bd5 > 0)
+ bd = pow5mult(bd, bd5);
+ if (bd2 > 0)
+ bd = lshift(bd, bd2);
+ if (bs2 > 0)
+ bs = lshift(bs, bs2);
+ delta = diff(bb, bd);
+ dsign = delta->sign;
+ delta->sign = 0;
+ i = cmp(delta, bs);
+#ifdef Honor_FLT_ROUNDS
+ if (rounding != 1) {
+ if (i < 0) {
+ /* Error is less than an ulp */
+ if (!delta->x[0] && delta->wds <= 1) {
+ /* exact */
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ break;
+ }
+ if (rounding) {
+ if (dsign) {
+ adj = 1.;
+ goto apply_adj;
+ }
+ }
+ else if (!dsign) {
+ adj = -1.;
+ if (!word1(rv)
+ && !(word0(rv) & Frac_mask)) {
+ y = word0(rv) & Exp_mask;
+#ifdef Avoid_Underflow
+ if (!scale || y > 2*P*Exp_msk1)
+#else
+ if (y)
+#endif
+ {
+ delta = lshift(delta,Log2P);
+ if (cmp(delta, bs) <= 0)
+ adj = -0.5;
+ }
+ }
+apply_adj:
+#ifdef Avoid_Underflow
+ if (scale && (y = word0(rv) & Exp_mask)
+ <= 2*P*Exp_msk1)
+ word0(adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+ if ((word0(rv) & Exp_mask) <=
+ P*Exp_msk1) {
+ word0(rv) += P*Exp_msk1;
+ dval(rv) += adj*ulp(dval(rv));
+ word0(rv) -= P*Exp_msk1;
+ }
+ else
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ dval(rv) += adj*ulp(dval(rv));
+ }
+ break;
+ }
+ adj = ratio(delta, bs);
+ if (adj < 1.)
+ adj = 1.;
+ if (adj <= 0x7ffffffe) {
+ /* adj = rounding ? ceil(adj) : floor(adj); */
+ y = adj;
+ if (y != adj) {
+ if (!((rounding>>1) ^ dsign))
+ y++;
+ adj = y;
+ }
+ }
+#ifdef Avoid_Underflow
+ if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
+ word0(adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
+ word0(rv) += P*Exp_msk1;
+ adj *= ulp(dval(rv));
+ if (dsign)
+ dval(rv) += adj;
+ else
+ dval(rv) -= adj;
+ word0(rv) -= P*Exp_msk1;
+ goto cont;
+ }
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ adj *= ulp(dval(rv));
+ if (dsign)
+ dval(rv) += adj;
+ else
+ dval(rv) -= adj;
+ goto cont;
+ }
+#endif /*Honor_FLT_ROUNDS*/
+
+ if (i < 0) {
+ /* Error is less than half an ulp -- check for
+ * special case of mantissa a power of two.
+ */
+ if (dsign || word1(rv) || word0(rv) & Bndry_mask
+#ifdef IEEE_Arith
+#ifdef Avoid_Underflow
+ || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1
+#else
+ || (word0(rv) & Exp_mask) <= Exp_msk1
+#endif
+#endif
+ ) {
+#ifdef SET_INEXACT
+ if (!delta->x[0] && delta->wds <= 1)
+ inexact = 0;
+#endif
+ break;
+ }
+ if (!delta->x[0] && delta->wds <= 1) {
+ /* exact result */
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ break;
+ }
+ delta = lshift(delta,Log2P);
+ if (cmp(delta, bs) > 0)
+ goto drop_down;
+ break;
+ }
+ if (i == 0) {
+ /* exactly half-way between */
+ if (dsign) {
+ if ((word0(rv) & Bndry_mask1) == Bndry_mask1
+ && word1(rv) == (
+#ifdef Avoid_Underflow
+ (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
+ ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) :
+#endif
+ 0xffffffff)) {
+ /*boundary case -- increment exponent*/
+ word0(rv) = (word0(rv) & Exp_mask)
+ + Exp_msk1
+#ifdef IBM
+ | Exp_msk1 >> 4
+#endif
+ ;
+ word1(rv) = 0;
+#ifdef Avoid_Underflow
+ dsign = 0;
+#endif
+ break;
+ }
+ }
+ else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
+drop_down:
+ /* boundary case -- decrement exponent */
+#ifdef Sudden_Underflow /*{{*/
+ L = word0(rv) & Exp_mask;
+#ifdef IBM
+ if (L < Exp_msk1)
+#else
+#ifdef Avoid_Underflow
+ if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1))
+#else
+ if (L <= Exp_msk1)
+#endif /*Avoid_Underflow*/
+#endif /*IBM*/
+ goto undfl;
+ L -= Exp_msk1;
+#else /*Sudden_Underflow}{*/
+#ifdef Avoid_Underflow
+ if (scale) {
+ L = word0(rv) & Exp_mask;
+ if (L <= (2*P+1)*Exp_msk1) {
+ if (L > (P+2)*Exp_msk1)
+ /* round even ==> */
+ /* accept rv */
+ break;
+ /* rv = smallest denormal */
+ goto undfl;
+ }
+ }
+#endif /*Avoid_Underflow*/
+ L = (word0(rv) & Exp_mask) - Exp_msk1;
+#endif /*Sudden_Underflow}}*/
+ word0(rv) = L | Bndry_mask1;
+ word1(rv) = 0xffffffff;
+#ifdef IBM
+ goto cont;
+#else
+ break;
+#endif
+ }
+#ifndef ROUND_BIASED
+ if (!(word1(rv) & LSB))
+ break;
+#endif
+ if (dsign)
+ dval(rv) += ulp(dval(rv));
+#ifndef ROUND_BIASED
+ else {
+ dval(rv) -= ulp(dval(rv));
+#ifndef Sudden_Underflow
+ if (!dval(rv))
+ goto undfl;
+#endif
+ }
+#ifdef Avoid_Underflow
+ dsign = 1 - dsign;
+#endif
+#endif
+ break;
+ }
+ if ((aadj = ratio(delta, bs)) <= 2.) {
+ if (dsign)
+ aadj = dval(aadj1) = 1.;
+ else if (word1(rv) || word0(rv) & Bndry_mask) {
+#ifndef Sudden_Underflow
+ if (word1(rv) == Tiny1 && !word0(rv))
+ goto undfl;
+#endif
+ aadj = 1.;
+ dval(aadj1) = -1.;
+ }
+ else {
+ /* special case -- power of FLT_RADIX to be */
+ /* rounded down... */
+
+ if (aadj < 2./FLT_RADIX)
+ aadj = 1./FLT_RADIX;
+ else
+ aadj *= 0.5;
+ dval(aadj1) = -aadj;
+ }
+ }
+ else {
+ aadj *= 0.5;
+ dval(aadj1) = dsign ? aadj : -aadj;
+#ifdef Check_FLT_ROUNDS
+ switch (Rounding) {
+ case 2: /* towards +infinity */
+ dval(aadj1) -= 0.5;
+ break;
+ case 0: /* towards 0 */
+ case 3: /* towards -infinity */
+ dval(aadj1) += 0.5;
+ }
+#else
+ if (Flt_Rounds == 0)
+ dval(aadj1) += 0.5;
+#endif /*Check_FLT_ROUNDS*/
+ }
+ y = word0(rv) & Exp_mask;
+
+ /* Check for overflow */
+
+ if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
+ dval(rv0) = dval(rv);
+ word0(rv) -= P*Exp_msk1;
+ adj = dval(aadj1) * ulp(dval(rv));
+ dval(rv) += adj;
+ if ((word0(rv) & Exp_mask) >=
+ Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
+ if (word0(rv0) == Big0 && word1(rv0) == Big1)
+ goto ovfl;
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+ goto cont;
+ }
+ else
+ word0(rv) += P*Exp_msk1;
+ }
+ else {
+#ifdef Avoid_Underflow
+ if (scale && y <= 2*P*Exp_msk1) {
+ if (aadj <= 0x7fffffff) {
+ if ((z = (int)aadj) <= 0)
+ z = 1;
+ aadj = z;
+ dval(aadj1) = dsign ? aadj : -aadj;
+ }
+ word0(aadj1) += (2*P+1)*Exp_msk1 - y;
+ }
+ adj = dval(aadj1) * ulp(dval(rv));
+ dval(rv) += adj;
+#else
+#ifdef Sudden_Underflow
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
+ dval(rv0) = dval(rv);
+ word0(rv) += P*Exp_msk1;
+ adj = dval(aadj1) * ulp(dval(rv));
+ dval(rv) += adj;
+#ifdef IBM
+ if ((word0(rv) & Exp_mask) < P*Exp_msk1)
+#else
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1)
+#endif
+ {
+ if (word0(rv0) == Tiny0 && word1(rv0) == Tiny1)
+ goto undfl;
+ word0(rv) = Tiny0;
+ word1(rv) = Tiny1;
+ goto cont;
+ }
+ else
+ word0(rv) -= P*Exp_msk1;
+ }
+ else {
+ adj = dval(aadj1) * ulp(dval(rv));
+ dval(rv) += adj;
+ }
+#else /*Sudden_Underflow*/
+ /* Compute adj so that the IEEE rounding rules will
+ * correctly round rv + adj in some half-way cases.
+ * If rv * ulp(rv) is denormalized (i.e.,
+ * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
+ * trouble from bits lost to denormalization;
+ * example: 1.2e-307 .
+ */
+ if (y <= (P-1)*Exp_msk1 && aadj > 1.) {
+ dval(aadj1) = (double)(int)(aadj + 0.5);
+ if (!dsign)
+ dval(aadj1) = -dval(aadj1);
+ }
+ adj = dval(aadj1) * ulp(dval(rv));
+ dval(rv) += adj;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ }
+ z = word0(rv) & Exp_mask;
+#ifndef SET_INEXACT
+#ifdef Avoid_Underflow
+ if (!scale)
+#endif
+ if (y == z) {
+ /* Can we stop now? */
+ L = (Long)aadj;
+ aadj -= L;
+ /* The tolerances below are conservative. */
+ if (dsign || word1(rv) || word0(rv) & Bndry_mask) {
+ if (aadj < .4999999 || aadj > .5000001)
+ break;
+ }
+ else if (aadj < .4999999/FLT_RADIX)
+ break;
+ }
+#endif
+cont:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(delta);
+ }
+#ifdef SET_INEXACT
+ if (inexact) {
+ if (!oldinexact) {
+ word0(rv0) = Exp_1 + (70 << Exp_shift);
+ word1(rv0) = 0;
+ dval(rv0) += 1.;
+ }
+ }
+ else if (!oldinexact)
+ clear_inexact();
+#endif
+#ifdef Avoid_Underflow
+ if (scale) {
+ word0(rv0) = Exp_1 - 2*P*Exp_msk1;
+ word1(rv0) = 0;
+ dval(rv) *= dval(rv0);
+#ifndef NO_ERRNO
+ /* try to avoid the bug of testing an 8087 register value */
+ if (word0(rv) == 0 && word1(rv) == 0)
+ errno = ERANGE;
+#endif
+ }
+#endif /* Avoid_Underflow */
+#ifdef SET_INEXACT
+ if (inexact && !(word0(rv) & Exp_mask)) {
+ /* set underflow bit */
+ dval(rv0) = 1e-300;
+ dval(rv0) *= dval(rv0);
+ }
+#endif
+retfree:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(bd0);
+ Bfree(delta);
+ret:
+ if (se)
+ *se = (char *)s;
+ return sign ? -dval(rv) : dval(rv);
+}
+
+NO_SANITIZE("unsigned-integer-overflow", static int quorem(Bigint *b, Bigint *S));
+static int
+quorem(Bigint *b, Bigint *S)
+{
+ int n;
+ ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+ ULLong borrow, carry, y, ys;
+#else
+ ULong borrow, carry, y, ys;
+#ifdef Pack_32
+ ULong si, z, zs;
+#endif
+#endif
+
+ n = S->wds;
+#ifdef DEBUG
+ /*debug*/ if (b->wds > n)
+ /*debug*/ Bug("oversize b in quorem");
+#endif
+ if (b->wds < n)
+ return 0;
+ sx = S->x;
+ sxe = sx + --n;
+ bx = b->x;
+ bxe = bx + n;
+ q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
+#ifdef DEBUG
+ /*debug*/ if (q > 9)
+ /*debug*/ Bug("oversized quotient in quorem");
+#endif
+ if (q) {
+ borrow = 0;
+ carry = 0;
+ do {
+#ifdef ULLong
+ ys = *sx++ * (ULLong)q + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & FFFFFFFF) - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *bx++ = (ULong)(y & FFFFFFFF);
+#else
+#ifdef Pack_32
+ si = *sx++;
+ ys = (si & 0xffff) * q + carry;
+ zs = (si >> 16) * q + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ * q + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *bx++ = y & 0xffff;
+#endif
+#endif
+ } while (sx <= sxe);
+ if (!*bxe) {
+ bx = b->x;
+ while (--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ if (cmp(b, S) >= 0) {
+ q++;
+ borrow = 0;
+ carry = 0;
+ bx = b->x;
+ sx = S->x;
+ do {
+#ifdef ULLong
+ ys = *sx++ + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & FFFFFFFF) - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *bx++ = (ULong)(y & FFFFFFFF);
+#else
+#ifdef Pack_32
+ si = *sx++;
+ ys = (si & 0xffff) + carry;
+ zs = (si >> 16) + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *bx++ = y & 0xffff;
+#endif
+#endif
+ } while (sx <= sxe);
+ bx = b->x;
+ bxe = bx + n;
+ if (!*bxe) {
+ while (--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ return q;
+}
+
+#ifndef MULTIPLE_THREADS
+static char *dtoa_result;
+#endif
+
+#ifndef MULTIPLE_THREADS
+static char *
+rv_alloc(int i)
+{
+ return dtoa_result = MALLOC(i);
+}
+#else
+#define rv_alloc(i) MALLOC(i)
+#endif
+
+static char *
+nrv_alloc(const char *s, char **rve, size_t n)
+{
+ char *rv, *t;
+
+ t = rv = rv_alloc(n);
+ while ((*t = *s++) != 0) t++;
+ if (rve)
+ *rve = t;
+ return rv;
+}
+
+#define rv_strdup(s, rve) nrv_alloc((s), (rve), strlen(s)+1)
+
+#ifndef MULTIPLE_THREADS
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined. It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+static void
+freedtoa(char *s)
+{
+ FREE(s);
+}
+#endif
+
+static const char INFSTR[] = "Infinity";
+static const char NANSTR[] = "NaN";
+static const char ZEROSTR[] = "0";
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ * 1. Rather than iterating, we use a simple numeric overestimate
+ * to determine k = floor(log10(d)). We scale relevant
+ * quantities using O(log2(k)) rather than O(k) multiplications.
+ * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ * try to generate digits strictly left to right. Instead, we
+ * compute with fewer bits and propagate the carry if necessary
+ * when rounding the final digit up. This is often faster.
+ * 3. Under the assumption that input will be rounded nearest,
+ * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ * That is, we allow equality in stopping tests when the
+ * round-nearest rule will give the same floating-point value
+ * as would satisfaction of the stopping test with strict
+ * inequality.
+ * 4. We remove common factors of powers of 2 from relevant
+ * quantities.
+ * 5. When converting floating-point integers less than 1e16,
+ * we use floating-point arithmetic rather than resorting
+ * to multiple-precision integers.
+ * 6. When asked to produce fewer than 15 digits, we first try
+ * to get by with floating-point arithmetic; we resort to
+ * multiple-precision integer arithmetic only if we cannot
+ * guarantee that the floating-point calculation has given
+ * the correctly rounded result. For k requested digits and
+ * "uniformly" distributed input, the probability is
+ * something like 10^(k-15) that we must resort to the Long
+ * calculation.
+ */
+
+char *
+dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve)
+{
+ /* Arguments ndigits, decpt, sign are similar to those
+ of ecvt and fcvt; trailing zeros are suppressed from
+ the returned string. If not null, *rve is set to point
+ to the end of the return value. If d is +-Infinity or NaN,
+ then *decpt is set to 9999.
+
+ mode:
+ 0 ==> shortest string that yields d when read in
+ and rounded to nearest.
+ 1 ==> like 0, but with Steele & White stopping rule;
+ e.g. with IEEE P754 arithmetic , mode 0 gives
+ 1e23 whereas mode 1 gives 9.999999999999999e22.
+ 2 ==> max(1,ndigits) significant digits. This gives a
+ return value similar to that of ecvt, except
+ that trailing zeros are suppressed.
+ 3 ==> through ndigits past the decimal point. This
+ gives a return value similar to that from fcvt,
+ except that trailing zeros are suppressed, and
+ ndigits can be negative.
+ 4,5 ==> similar to 2 and 3, respectively, but (in
+ round-nearest mode) with the tests of mode 0 to
+ possibly return a shorter string that rounds to d.
+ With IEEE arithmetic and compilation with
+ -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+ as modes 2 and 3 when FLT_ROUNDS != 1.
+ 6-9 ==> Debugging modes similar to mode - 4: don't try
+ fast floating-point estimate (if applicable).
+
+ Values of mode other than 0-9 are treated as mode 0.
+
+ Sufficient space is allocated to the return value
+ to hold the suppressed trailing zeros.
+ */
+
+ int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+ j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+ spec_case, try_quick, half = 0;
+ Long L;
+#ifndef Sudden_Underflow
+ int denorm;
+ ULong x;
+#endif
+ Bigint *b, *b1, *delta, *mlo = 0, *mhi = 0, *S;
+ double ds;
+ double_u d, d2, eps;
+ char *s, *s0;
+#ifdef Honor_FLT_ROUNDS
+ int rounding;
+#endif
+#ifdef SET_INEXACT
+ int inexact, oldinexact;
+#endif
+
+ dval(d) = d_;
+
+#ifndef MULTIPLE_THREADS
+ if (dtoa_result) {
+ freedtoa(dtoa_result);
+ dtoa_result = 0;
+ }
+#endif
+
+ if (word0(d) & Sign_bit) {
+ /* set sign for everything, including 0's and NaNs */
+ *sign = 1;
+ word0(d) &= ~Sign_bit; /* clear sign bit */
+ }
+ else
+ *sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+ if ((word0(d) & Exp_mask) == Exp_mask)
+#else
+ if (word0(d) == 0x8000)
+#endif
+ {
+ /* Infinity or NaN */
+ *decpt = 9999;
+#ifdef IEEE_Arith
+ if (!word1(d) && !(word0(d) & 0xfffff))
+ return rv_strdup(INFSTR, rve);
+#endif
+ return rv_strdup(NANSTR, rve);
+ }
+#endif
+#ifdef IBM
+ dval(d) += 0; /* normalize */
+#endif
+ if (!dval(d)) {
+ *decpt = 1;
+ return rv_strdup(ZEROSTR, rve);
+ }
+
+#ifdef SET_INEXACT
+ try_quick = oldinexact = get_inexact();
+ inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+ if ((rounding = Flt_Rounds) >= 2) {
+ if (*sign)
+ rounding = rounding == 2 ? 0 : 2;
+ else
+ if (rounding != 2)
+ rounding = 0;
+ }
+#endif
+
+ b = d2b(dval(d), &be, &bbits);
+#ifdef Sudden_Underflow
+ i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+ if ((i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) {
+#endif
+ dval(d2) = dval(d);
+ word0(d2) &= Frac_mask1;
+ word0(d2) |= Exp_11;
+#ifdef IBM
+ if (j = 11 - hi0bits(word0(d2) & Frac_mask))
+ dval(d2) /= 1 << j;
+#endif
+
+ /* log(x) ~=~ log(1.5) + (x-1.5)/1.5
+ * log10(x) = log(x) / log(10)
+ * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+ * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+ *
+ * This suggests computing an approximation k to log10(d) by
+ *
+ * k = (i - Bias)*0.301029995663981
+ * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+ *
+ * We want k to be too large rather than too small.
+ * The error in the first-order Taylor series approximation
+ * is in our favor, so we just round up the constant enough
+ * to compensate for any error in the multiplication of
+ * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+ * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+ * adding 1e-13 to the constant term more than suffices.
+ * Hence we adjust the constant term to 0.1760912590558.
+ * (We could get a more accurate k by invoking log10,
+ * but this is probably not worthwhile.)
+ */
+
+ i -= Bias;
+#ifdef IBM
+ i <<= 2;
+ i += j;
+#endif
+#ifndef Sudden_Underflow
+ denorm = 0;
+ }
+ else {
+ /* d is denormalized */
+
+ i = bbits + be + (Bias + (P-1) - 1);
+ x = i > 32 ? word0(d) << (64 - i) | word1(d) >> (i - 32)
+ : word1(d) << (32 - i);
+ dval(d2) = x;
+ word0(d2) -= 31*Exp_msk1; /* adjust exponent */
+ i -= (Bias + (P-1) - 1) + 1;
+ denorm = 1;
+ }
+#endif
+ ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+ k = (int)ds;
+ if (ds < 0. && ds != k)
+ k--; /* want k = floor(ds) */
+ k_check = 1;
+ if (k >= 0 && k <= Ten_pmax) {
+ if (dval(d) < tens[k])
+ k--;
+ k_check = 0;
+ }
+ j = bbits - i - 1;
+ if (j >= 0) {
+ b2 = 0;
+ s2 = j;
+ }
+ else {
+ b2 = -j;
+ s2 = 0;
+ }
+ if (k >= 0) {
+ b5 = 0;
+ s5 = k;
+ s2 += k;
+ }
+ else {
+ b2 -= k;
+ b5 = -k;
+ s5 = 0;
+ }
+ if (mode < 0 || mode > 9)
+ mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+ try_quick = Rounding == 1;
+#else
+ try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+ if (mode > 5) {
+ mode -= 4;
+ try_quick = 0;
+ }
+ leftright = 1;
+ ilim = ilim1 = -1;
+ switch (mode) {
+ case 0:
+ case 1:
+ i = 18;
+ ndigits = 0;
+ break;
+ case 2:
+ leftright = 0;
+ /* no break */
+ case 4:
+ if (ndigits <= 0)
+ ndigits = 1;
+ ilim = ilim1 = i = ndigits;
+ break;
+ case 3:
+ leftright = 0;
+ /* no break */
+ case 5:
+ i = ndigits + k + 1;
+ ilim = i;
+ ilim1 = i - 1;
+ if (i <= 0)
+ i = 1;
+ }
+ s = s0 = rv_alloc(i+1);
+
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1 && rounding != 1)
+ leftright = 0;
+#endif
+
+ if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+ /* Try to get by with floating-point arithmetic. */
+
+ i = 0;
+ dval(d2) = dval(d);
+ k0 = k;
+ ilim0 = ilim;
+ ieps = 2; /* conservative */
+ if (k > 0) {
+ ds = tens[k&0xf];
+ j = k >> 4;
+ if (j & Bletch) {
+ /* prevent overflows */
+ j &= Bletch - 1;
+ dval(d) /= bigtens[n_bigtens-1];
+ ieps++;
+ }
+ for (; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ ds *= bigtens[i];
+ }
+ dval(d) /= ds;
+ }
+ else if ((j1 = -k) != 0) {
+ dval(d) *= tens[j1 & 0xf];
+ for (j = j1 >> 4; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ dval(d) *= bigtens[i];
+ }
+ }
+ if (k_check && dval(d) < 1. && ilim > 0) {
+ if (ilim1 <= 0)
+ goto fast_failed;
+ ilim = ilim1;
+ k--;
+ dval(d) *= 10.;
+ ieps++;
+ }
+ dval(eps) = ieps*dval(d) + 7.;
+ word0(eps) -= (P-1)*Exp_msk1;
+ if (ilim == 0) {
+ S = mhi = 0;
+ dval(d) -= 5.;
+ if (dval(d) > dval(eps))
+ goto one_digit;
+ if (dval(d) < -dval(eps))
+ goto no_digits;
+ goto fast_failed;
+ }
+#ifndef No_leftright
+ if (leftright) {
+ /* Use Steele & White method of only
+ * generating digits needed.
+ */
+ dval(eps) = 0.5/tens[ilim-1] - dval(eps);
+ for (i = 0;;) {
+ L = (int)dval(d);
+ dval(d) -= L;
+ *s++ = '0' + (int)L;
+ if (dval(d) < dval(eps))
+ goto ret1;
+ if (1. - dval(d) < dval(eps))
+ goto bump_up;
+ if (++i >= ilim)
+ break;
+ dval(eps) *= 10.;
+ dval(d) *= 10.;
+ }
+ }
+ else {
+#endif
+ /* Generate ilim digits, then fix them up. */
+ dval(eps) *= tens[ilim-1];
+ for (i = 1;; i++, dval(d) *= 10.) {
+ L = (Long)(dval(d));
+ if (!(dval(d) -= L))
+ ilim = i;
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ if (dval(d) > 0.5 + dval(eps))
+ goto bump_up;
+ else if (dval(d) < 0.5 - dval(eps)) {
+ while (*--s == '0') ;
+ s++;
+ goto ret1;
+ }
+ half = 1;
+ if ((*(s-1) - '0') & 1) {
+ goto bump_up;
+ }
+ break;
+ }
+ }
+#ifndef No_leftright
+ }
+#endif
+fast_failed:
+ s = s0;
+ dval(d) = dval(d2);
+ k = k0;
+ ilim = ilim0;
+ }
+
+ /* Do we have a "small" integer? */
+
+ if (be >= 0 && k <= Int_max) {
+ /* Yes. */
+ ds = tens[k];
+ if (ndigits < 0 && ilim <= 0) {
+ S = mhi = 0;
+ if (ilim < 0 || dval(d) <= 5*ds)
+ goto no_digits;
+ goto one_digit;
+ }
+ for (i = 1;; i++, dval(d) *= 10.) {
+ L = (Long)(dval(d) / ds);
+ dval(d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+ /* If FLT_ROUNDS == 2, L will usually be high by 1 */
+ if (dval(d) < 0) {
+ L--;
+ dval(d) += ds;
+ }
+#endif
+ *s++ = '0' + (int)L;
+ if (!dval(d)) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ break;
+ }
+ if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1)
+ switch (rounding) {
+ case 0: goto ret1;
+ case 2: goto bump_up;
+ }
+#endif
+ dval(d) += dval(d);
+ if (dval(d) > ds || (dval(d) == ds && (L & 1))) {
+bump_up:
+ while (*--s == '9')
+ if (s == s0) {
+ k++;
+ *s = '0';
+ break;
+ }
+ ++*s++;
+ }
+ break;
+ }
+ }
+ goto ret1;
+ }
+
+ m2 = b2;
+ m5 = b5;
+ if (leftright) {
+ i =
+#ifndef Sudden_Underflow
+ denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+ 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+ 1 + P - bbits;
+#endif
+ b2 += i;
+ s2 += i;
+ mhi = i2b(1);
+ }
+ if (m2 > 0 && s2 > 0) {
+ i = m2 < s2 ? m2 : s2;
+ b2 -= i;
+ m2 -= i;
+ s2 -= i;
+ }
+ if (b5 > 0) {
+ if (leftright) {
+ if (m5 > 0) {
+ mhi = pow5mult(mhi, m5);
+ b1 = mult(mhi, b);
+ Bfree(b);
+ b = b1;
+ }
+ if ((j = b5 - m5) != 0)
+ b = pow5mult(b, j);
+ }
+ else
+ b = pow5mult(b, b5);
+ }
+ S = i2b(1);
+ if (s5 > 0)
+ S = pow5mult(S, s5);
+
+ /* Check for special case that d is a normalized power of 2. */
+
+ spec_case = 0;
+ if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+ && rounding == 1
+#endif
+ ) {
+ if (!word1(d) && !(word0(d) & Bndry_mask)
+#ifndef Sudden_Underflow
+ && word0(d) & (Exp_mask & ~Exp_msk1)
+#endif
+ ) {
+ /* The special case */
+ b2 += Log2P;
+ s2 += Log2P;
+ spec_case = 1;
+ }
+ }
+
+ /* Arrange for convenient computation of quotients:
+ * shift left if necessary so divisor has 4 leading 0 bits.
+ *
+ * Perhaps we should just compute leading 28 bits of S once
+ * and for all and pass them and a shift to quorem, so it
+ * can do shifts and ors to compute the numerator for q.
+ */
+#ifdef Pack_32
+ if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0)
+ i = 32 - i;
+#else
+ if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) != 0)
+ i = 16 - i;
+#endif
+ if (i > 4) {
+ i -= 4;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ else if (i < 4) {
+ i += 28;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ if (b2 > 0)
+ b = lshift(b, b2);
+ if (s2 > 0)
+ S = lshift(S, s2);
+ if (k_check) {
+ if (cmp(b,S) < 0) {
+ k--;
+ b = multadd(b, 10, 0); /* we botched the k estimate */
+ if (leftright)
+ mhi = multadd(mhi, 10, 0);
+ ilim = ilim1;
+ }
+ }
+ if (ilim <= 0 && (mode == 3 || mode == 5)) {
+ if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) {
+ /* no digits, fcvt style */
+no_digits:
+ k = -1 - ndigits;
+ goto ret;
+ }
+one_digit:
+ *s++ = '1';
+ k++;
+ goto ret;
+ }
+ if (leftright) {
+ if (m2 > 0)
+ mhi = lshift(mhi, m2);
+
+ /* Compute mlo -- check for special case
+ * that d is a normalized power of 2.
+ */
+
+ mlo = mhi;
+ if (spec_case) {
+ mhi = Balloc(mhi->k);
+ Bcopy(mhi, mlo);
+ mhi = lshift(mhi, Log2P);
+ }
+
+ for (i = 1;;i++) {
+ dig = quorem(b,S) + '0';
+ /* Do we yet have the shortest decimal string
+ * that will round to d?
+ */
+ j = cmp(b, mlo);
+ delta = diff(S, mhi);
+ j1 = delta->sign ? 1 : cmp(b, delta);
+ Bfree(delta);
+#ifndef ROUND_BIASED
+ if (j1 == 0 && mode != 1 && !(word1(d) & 1)
+#ifdef Honor_FLT_ROUNDS
+ && rounding >= 1
+#endif
+ ) {
+ if (dig == '9')
+ goto round_9_up;
+ if (j > 0)
+ dig++;
+#ifdef SET_INEXACT
+ else if (!b->x[0] && b->wds <= 1)
+ inexact = 0;
+#endif
+ *s++ = dig;
+ goto ret;
+ }
+#endif
+ if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+ && !(word1(d) & 1)
+#endif
+ )) {
+ if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ goto accept_dig;
+ }
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1)
+ switch (rounding) {
+ case 0: goto accept_dig;
+ case 2: goto keep_dig;
+ }
+#endif /*Honor_FLT_ROUNDS*/
+ if (j1 > 0) {
+ b = lshift(b, 1);
+ j1 = cmp(b, S);
+ if ((j1 > 0 || (j1 == 0 && (dig & 1))) && dig++ == '9')
+ goto round_9_up;
+ }
+accept_dig:
+ *s++ = dig;
+ goto ret;
+ }
+ if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+ if (!rounding)
+ goto accept_dig;
+#endif
+ if (dig == '9') { /* possible if i == 1 */
+round_9_up:
+ *s++ = '9';
+ goto roundoff;
+ }
+ *s++ = dig + 1;
+ goto ret;
+ }
+#ifdef Honor_FLT_ROUNDS
+keep_dig:
+#endif
+ *s++ = dig;
+ if (i == ilim)
+ break;
+ b = multadd(b, 10, 0);
+ if (mlo == mhi)
+ mlo = mhi = multadd(mhi, 10, 0);
+ else {
+ mlo = multadd(mlo, 10, 0);
+ mhi = multadd(mhi, 10, 0);
+ }
+ }
+ }
+ else
+ for (i = 1;; i++) {
+ *s++ = dig = quorem(b,S) + '0';
+ if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ goto ret;
+ }
+ if (i >= ilim)
+ break;
+ b = multadd(b, 10, 0);
+ }
+
+ /* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+ switch (rounding) {
+ case 0: goto trimzeros;
+ case 2: goto roundoff;
+ }
+#endif
+ b = lshift(b, 1);
+ j = cmp(b, S);
+ if (j > 0 || (j == 0 && (dig & 1))) {
+ roundoff:
+ while (*--s == '9')
+ if (s == s0) {
+ k++;
+ *s++ = '1';
+ goto ret;
+ }
+ if (!half || (*s - '0') & 1)
+ ++*s;
+ }
+ else {
+ while (*--s == '0') ;
+ }
+ s++;
+ret:
+ Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ret1:
+#ifdef SET_INEXACT
+ if (inexact) {
+ if (!oldinexact) {
+ word0(d) = Exp_1 + (70 << Exp_shift);
+ word1(d) = 0;
+ dval(d) += 1.;
+ }
+ }
+ else if (!oldinexact)
+ clear_inexact();
+#endif
+ Bfree(b);
+ *s = 0;
+ *decpt = k + 1;
+ if (rve)
+ *rve = s;
+ return s0;
+}
+
+/*-
+ * Copyright (c) 2004-2008 David Schultz <das@FreeBSD.ORG>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define DBL_MANH_SIZE 20
+#define DBL_MANL_SIZE 32
+#define DBL_ADJ (DBL_MAX_EXP - 2)
+#define SIGFIGS ((DBL_MANT_DIG + 3) / 4 + 1)
+#define dexp_get(u) ((int)(word0(u) >> Exp_shift) & ~Exp_msk1)
+#define dexp_set(u,v) (word0(u) = (((int)(word0(u)) & ~Exp_mask) | ((v) << Exp_shift)))
+#define dmanh_get(u) ((uint32_t)(word0(u) & Frac_mask))
+#define dmanl_get(u) ((uint32_t)word1(u))
+
+
+/*
+ * This procedure converts a double-precision number in IEEE format
+ * into a string of hexadecimal digits and an exponent of 2. Its
+ * behavior is bug-for-bug compatible with dtoa() in mode 2, with the
+ * following exceptions:
+ *
+ * - An ndigits < 0 causes it to use as many digits as necessary to
+ * represent the number exactly.
+ * - The additional xdigs argument should point to either the string
+ * "0123456789ABCDEF" or the string "0123456789abcdef", depending on
+ * which case is desired.
+ * - This routine does not repeat dtoa's mistake of setting decpt
+ * to 9999 in the case of an infinity or NaN. INT_MAX is used
+ * for this purpose instead.
+ *
+ * Note that the C99 standard does not specify what the leading digit
+ * should be for non-zero numbers. For instance, 0x1.3p3 is the same
+ * as 0x2.6p2 is the same as 0x4.cp3. This implementation always makes
+ * the leading digit a 1. This ensures that the exponent printed is the
+ * actual base-2 exponent, i.e., ilogb(d).
+ *
+ * Inputs: d, xdigs, ndigits
+ * Outputs: decpt, sign, rve
+ */
+char *
+hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign, char **rve)
+{
+ U u;
+ char *s, *s0;
+ int bufsize;
+ uint32_t manh, manl;
+
+ u.d = d;
+ if (word0(u) & Sign_bit) {
+ /* set sign for everything, including 0's and NaNs */
+ *sign = 1;
+ word0(u) &= ~Sign_bit; /* clear sign bit */
+ }
+ else
+ *sign = 0;
+
+ if (isinf(d)) { /* FP_INFINITE */
+ *decpt = INT_MAX;
+ return rv_strdup(INFSTR, rve);
+ }
+ else if (isnan(d)) { /* FP_NAN */
+ *decpt = INT_MAX;
+ return rv_strdup(NANSTR, rve);
+ }
+ else if (d == 0.0) { /* FP_ZERO */
+ *decpt = 1;
+ return rv_strdup(ZEROSTR, rve);
+ }
+ else if (dexp_get(u)) { /* FP_NORMAL */
+ *decpt = dexp_get(u) - DBL_ADJ;
+ }
+ else { /* FP_SUBNORMAL */
+ u.d *= 5.363123171977039e+154 /* 0x1p514 */;
+ *decpt = dexp_get(u) - (514 + DBL_ADJ);
+ }
+
+ if (ndigits == 0) /* dtoa() compatibility */
+ ndigits = 1;
+
+ /*
+ * If ndigits < 0, we are expected to auto-size, so we allocate
+ * enough space for all the digits.
+ */
+ bufsize = (ndigits > 0) ? ndigits : SIGFIGS;
+ s0 = rv_alloc(bufsize+1);
+
+ /* Round to the desired number of digits. */
+ if (SIGFIGS > ndigits && ndigits > 0) {
+ float redux = 1.0f;
+ int offset = 4 * ndigits + DBL_MAX_EXP - 4 - DBL_MANT_DIG;
+ dexp_set(u, offset);
+ u.d += redux;
+ u.d -= redux;
+ *decpt += dexp_get(u) - offset;
+ }
+
+ manh = dmanh_get(u);
+ manl = dmanl_get(u);
+ *s0 = '1';
+ for (s = s0 + 1; s < s0 + bufsize; s++) {
+ *s = xdigs[(manh >> (DBL_MANH_SIZE - 4)) & 0xf];
+ manh = (manh << 4) | (manl >> (DBL_MANL_SIZE - 4));
+ manl <<= 4;
+ }
+
+ /* If ndigits < 0, we are expected to auto-size the precision. */
+ if (ndigits < 0) {
+ for (ndigits = SIGFIGS; s0[ndigits - 1] == '0'; ndigits--)
+ ;
+ }
+
+ s = s0 + ndigits;
+ *s = '\0';
+ if (rve != NULL)
+ *rve = s;
+ return (s0);
+}
+
+#ifdef __cplusplus
+#if 0
+{ /* satisfy cc-mode */
+#endif
+}
+#endif
diff --git a/ext/bigdecimal/sample/linear.rb b/ext/bigdecimal/sample/linear.rb
new file mode 100644
index 0000000000..516c2473be
--- /dev/null
+++ b/ext/bigdecimal/sample/linear.rb
@@ -0,0 +1,74 @@
+#!/usr/local/bin/ruby
+# frozen_string_literal: false
+
+#
+# linear.rb
+#
+# Solves linear equation system(A*x = b) by LU decomposition method.
+# where A is a coefficient matrix,x is an answer vector,b is a constant vector.
+#
+# USAGE:
+# ruby linear.rb [input file solved]
+#
+
+# :stopdoc:
+require "bigdecimal"
+require "bigdecimal/ludcmp"
+
+#
+# NOTE:
+# Change following BigDecimal.limit() if needed.
+BigDecimal.limit(100)
+#
+
+include LUSolve
+def rd_order(na)
+ printf("Number of equations ?") if(na <= 0)
+ n = ARGF.gets().to_i
+end
+
+na = ARGV.size
+zero = BigDecimal("0.0")
+one = BigDecimal("1.0")
+
+while (n=rd_order(na))>0
+ a = []
+ as= []
+ b = []
+ if na <= 0
+ # Read data from console.
+ printf("\nEnter coefficient matrix element A[i,j]\n")
+ for i in 0...n do
+ for j in 0...n do
+ printf("A[%d,%d]? ",i,j); s = ARGF.gets
+ a << BigDecimal(s)
+ as << BigDecimal(s)
+ end
+ printf("Contatant vector element b[%d] ? ",i)
+ b << BigDecimal(ARGF.gets)
+ end
+ else
+ # Read data from specified file.
+ printf("Coefficient matrix and constant vector.\n")
+ for i in 0...n do
+ s = ARGF.gets
+ printf("%d) %s",i,s)
+ s = s.split
+ for j in 0...n do
+ a << BigDecimal(s[j])
+ as << BigDecimal(s[j])
+ end
+ b << BigDecimal(s[n])
+ end
+ end
+ x = lusolve(a,b,ludecomp(a,n,zero,one),zero)
+ printf("Answer(x[i] & (A*x-b)[i]) follows\n")
+ for i in 0...n do
+ printf("x[%d]=%s ",i,x[i].to_s)
+ s = zero
+ for j in 0...n do
+ s = s + as[i*n+j]*x[j]
+ end
+ printf(" & %s\n",(s-b[i]).to_s)
+ end
+end
diff --git a/ext/bigdecimal/sample/nlsolve.rb b/ext/bigdecimal/sample/nlsolve.rb
new file mode 100644
index 0000000000..c2227dac73
--- /dev/null
+++ b/ext/bigdecimal/sample/nlsolve.rb
@@ -0,0 +1,40 @@
+#!/usr/local/bin/ruby
+# frozen_string_literal: false
+
+#
+# nlsolve.rb
+# An example for solving nonlinear algebraic equation system.
+#
+
+require "bigdecimal"
+require "bigdecimal/newton"
+include Newton
+
+class Function # :nodoc: all
+ def initialize()
+ @zero = BigDecimal("0.0")
+ @one = BigDecimal("1.0")
+ @two = BigDecimal("2.0")
+ @ten = BigDecimal("10.0")
+ @eps = BigDecimal("1.0e-16")
+ end
+ def zero;@zero;end
+ def one ;@one ;end
+ def two ;@two ;end
+ def ten ;@ten ;end
+ def eps ;@eps ;end
+ def values(x) # <= defines functions solved
+ f = []
+ f1 = x[0]*x[0] + x[1]*x[1] - @two # f1 = x**2 + y**2 - 2 => 0
+ f2 = x[0] - x[1] # f2 = x - y => 0
+ f <<= f1
+ f <<= f2
+ f
+ end
+end
+
+f = BigDecimal.limit(100)
+f = Function.new
+x = [f.zero,f.zero] # Initial values
+n = nlsolve(f,x)
+p x
diff --git a/ext/bigdecimal/sample/pi.rb b/ext/bigdecimal/sample/pi.rb
new file mode 100644
index 0000000000..ea9663896c
--- /dev/null
+++ b/ext/bigdecimal/sample/pi.rb
@@ -0,0 +1,21 @@
+#!/usr/local/bin/ruby
+# frozen_string_literal: false
+
+#
+# pi.rb
+#
+# Calculates 3.1415.... (the number of times that a circle's diameter
+# will fit around the circle) using J. Machin's formula.
+#
+
+require "bigdecimal"
+require "bigdecimal/math.rb"
+
+include BigMath
+
+if ARGV.size == 1
+ print "PI("+ARGV[0]+"):\n"
+ p PI(ARGV[0].to_i)
+else
+ print "TRY: ruby pi.rb 1000 \n"
+end
diff --git a/ext/bigdecimal/static_assert.h b/ext/bigdecimal/static_assert.h
new file mode 100644
index 0000000000..9295729bf6
--- /dev/null
+++ b/ext/bigdecimal/static_assert.h
@@ -0,0 +1,54 @@
+#ifndef BIGDECIMAL_STATIC_ASSERT_H
+#define BIGDECIMAL_STATIC_ASSERT_H
+
+#include "feature.h"
+
+#ifdef HAVE_RUBY_INTERNAL_STATIC_ASSERT_H
+# include <ruby/internal/static_assert.h>
+#endif
+
+#ifdef RBIMPL_STATIC_ASSERT
+# define STATIC_ASSERT RBIMPL_STATIC_ASSERT
+#endif
+
+#ifndef STATIC_ASSERT
+# /* The following section is copied from CRuby's static_assert.h */
+
+# if defined(__cplusplus) && defined(__cpp_static_assert)
+# /* https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations */
+# define BIGDECIMAL_STATIC_ASSERT0 static_assert
+
+# elif defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER >= 1600
+# define BIGDECIMAL_STATIC_ASSERT0 static_assert
+
+# elif defined(__INTEL_CXX11_MODE__)
+# define BIGDECIMAL_STATIC_ASSERT0 static_assert
+
+# elif defined(__cplusplus) && __cplusplus >= 201103L
+# define BIGDECIMAL_STATIC_ASSERT0 static_assert
+
+# elif defined(__cplusplus) && __has_extension(cxx_static_assert)
+# define BIGDECIMAL_STATIC_ASSERT0 __extension__ static_assert
+
+# elif defined(__STDC_VERSION__) && __has_extension(c_static_assert)
+# define BIGDECIMAL_STATIC_ASSERT0 __extension__ _Static_assert
+
+# elif defined(__STDC_VERSION__) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+# define BIGDECIMAL_STATIC_ASSERT0 __extension__ _Static_assert
+#endif
+
+# if defined(__DOXYGEN__)
+# define STATIC_ASSERT static_assert
+
+# elif defined(BIGDECIMAL_STATIC_ASSERT0)
+# define STATIC_ASSERT(name, expr) \
+ BIGDECIMAL_STATIC_ASSERT0(expr, #name ": " #expr)
+
+# else
+# define STATIC_ASSERT(name, expr) \
+ typedef int static_assert_ ## name ## _check[1 - 2 * !(expr)]
+# endif
+#endif /* STATIC_ASSERT */
+
+
+#endif /* BIGDECIMAL_STATIC_ASSERT_H */
diff --git a/ext/cgi/escape/depend b/ext/cgi/escape/depend
index 746b47246a..e3904d0695 100644
--- a/ext/cgi/escape/depend
+++ b/ext/cgi/escape/depend
@@ -53,7 +53,6 @@ escape.o: $(hdrdir)/ruby/internal/attr/noexcept.h
escape.o: $(hdrdir)/ruby/internal/attr/noinline.h
escape.o: $(hdrdir)/ruby/internal/attr/nonnull.h
escape.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-escape.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
escape.o: $(hdrdir)/ruby/internal/attr/pure.h
escape.o: $(hdrdir)/ruby/internal/attr/restrict.h
escape.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ escape.o: $(hdrdir)/ruby/internal/intern/enumerator.h
escape.o: $(hdrdir)/ruby/internal/intern/error.h
escape.o: $(hdrdir)/ruby/internal/intern/eval.h
escape.o: $(hdrdir)/ruby/internal/intern/file.h
+escape.o: $(hdrdir)/ruby/internal/intern/gc.h
escape.o: $(hdrdir)/ruby/internal/intern/hash.h
escape.o: $(hdrdir)/ruby/internal/intern/io.h
escape.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,12 +152,12 @@ escape.o: $(hdrdir)/ruby/internal/memory.h
escape.o: $(hdrdir)/ruby/internal/method.h
escape.o: $(hdrdir)/ruby/internal/module.h
escape.o: $(hdrdir)/ruby/internal/newobj.h
+escape.o: $(hdrdir)/ruby/internal/rgengc.h
escape.o: $(hdrdir)/ruby/internal/scan_args.h
escape.o: $(hdrdir)/ruby/internal/special_consts.h
escape.o: $(hdrdir)/ruby/internal/static_assert.h
escape.o: $(hdrdir)/ruby/internal/stdalign.h
escape.o: $(hdrdir)/ruby/internal/stdbool.h
-escape.o: $(hdrdir)/ruby/internal/stdckdint.h
escape.o: $(hdrdir)/ruby/internal/symbol.h
escape.o: $(hdrdir)/ruby/internal/value.h
escape.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/cgi/escape/escape.c b/ext/cgi/escape/escape.c
index 495ad83aa3..c5b76de596 100644
--- a/ext/cgi/escape/escape.c
+++ b/ext/cgi/escape/escape.c
@@ -83,7 +83,7 @@ optimized_unescape_html(VALUE str)
unsigned long charlimit = (strcasecmp(rb_enc_name(enc), "UTF-8") == 0 ? UNICODE_MAX :
strcasecmp(rb_enc_name(enc), "ISO-8859-1") == 0 ? 256 :
128);
- long i, j, len, beg = 0;
+ long i, len, beg = 0;
size_t clen, plen;
int overflow;
const char *cstr;
@@ -100,7 +100,6 @@ optimized_unescape_html(VALUE str)
plen = i - beg;
if (++i >= len) break;
c = (unsigned char)cstr[i];
- j = i;
#define MATCH(s) (len - i >= (int)rb_strlen_lit(s) && \
memcmp(&cstr[i], s, rb_strlen_lit(s)) == 0 && \
(i += rb_strlen_lit(s) - 1, 1))
@@ -113,40 +112,28 @@ optimized_unescape_html(VALUE str)
else if (MATCH("mp;")) {
c = '&';
}
- else {
- i = j;
- continue;
- }
+ else continue;
break;
case 'q':
++i;
if (MATCH("uot;")) {
c = '"';
}
- else {
- i = j;
- continue;
- }
+ else continue;
break;
case 'g':
++i;
if (MATCH("t;")) {
c = '>';
}
- else {
- i = j;
- continue;
- }
+ else continue;
break;
case 'l':
++i;
if (MATCH("t;")) {
c = '<';
}
- else {
- i = j;
- continue;
- }
+ else continue;
break;
case '#':
if (len - ++i >= 2 && ISDIGIT(cstr[i])) {
@@ -155,15 +142,9 @@ optimized_unescape_html(VALUE str)
else if ((cstr[i] == 'x' || cstr[i] == 'X') && len - ++i >= 2 && ISXDIGIT(cstr[i])) {
cc = ruby_scan_digits(&cstr[i], len-i, 16, &clen, &overflow);
}
- else {
- i = j;
- continue;
- }
+ else continue;
i += clen;
- if (overflow || cc >= charlimit || cstr[i] != ';') {
- i = j;
- continue;
- }
+ if (overflow || cc >= charlimit || cstr[i] != ';') continue;
if (!dest) {
dest = rb_str_buf_new(len);
}
@@ -477,9 +458,7 @@ InitVM_escape(void)
rb_define_method(rb_mEscape, "escapeHTML", cgiesc_escape_html, 1);
rb_define_method(rb_mEscape, "unescapeHTML", cgiesc_unescape_html, 1);
rb_define_method(rb_mEscape, "escapeURIComponent", cgiesc_escape_uri_component, 1);
- rb_define_alias(rb_mEscape, "escape_uri_component", "escapeURIComponent");
rb_define_method(rb_mEscape, "unescapeURIComponent", cgiesc_unescape_uri_component, -1);
- rb_define_alias(rb_mEscape, "unescape_uri_component", "unescapeURIComponent");
rb_define_method(rb_mEscape, "escape", cgiesc_escape, 1);
rb_define_method(rb_mEscape, "unescape", cgiesc_unescape, -1);
rb_prepend_module(rb_mUtil, rb_mEscape);
diff --git a/ext/cgi/escape/extconf.rb b/ext/cgi/escape/extconf.rb
index 73acd89ca8..16e8ff224d 100644
--- a/ext/cgi/escape/extconf.rb
+++ b/ext/cgi/escape/extconf.rb
@@ -1,7 +1,3 @@
require 'mkmf'
-if RUBY_ENGINE == 'truffleruby'
- File.write("Makefile", dummy_makefile($srcdir).join(""))
-else
- create_makefile 'cgi/escape'
-end
+create_makefile 'cgi/escape'
diff --git a/ext/continuation/depend b/ext/continuation/depend
index b40e52e29b..81218f9965 100644
--- a/ext/continuation/depend
+++ b/ext/continuation/depend
@@ -51,7 +51,6 @@ continuation.o: $(hdrdir)/ruby/internal/attr/noexcept.h
continuation.o: $(hdrdir)/ruby/internal/attr/noinline.h
continuation.o: $(hdrdir)/ruby/internal/attr/nonnull.h
continuation.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-continuation.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
continuation.o: $(hdrdir)/ruby/internal/attr/pure.h
continuation.o: $(hdrdir)/ruby/internal/attr/restrict.h
continuation.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ continuation.o: $(hdrdir)/ruby/internal/intern/enumerator.h
continuation.o: $(hdrdir)/ruby/internal/intern/error.h
continuation.o: $(hdrdir)/ruby/internal/intern/eval.h
continuation.o: $(hdrdir)/ruby/internal/intern/file.h
+continuation.o: $(hdrdir)/ruby/internal/intern/gc.h
continuation.o: $(hdrdir)/ruby/internal/intern/hash.h
continuation.o: $(hdrdir)/ruby/internal/intern/io.h
continuation.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,12 +141,12 @@ continuation.o: $(hdrdir)/ruby/internal/memory.h
continuation.o: $(hdrdir)/ruby/internal/method.h
continuation.o: $(hdrdir)/ruby/internal/module.h
continuation.o: $(hdrdir)/ruby/internal/newobj.h
+continuation.o: $(hdrdir)/ruby/internal/rgengc.h
continuation.o: $(hdrdir)/ruby/internal/scan_args.h
continuation.o: $(hdrdir)/ruby/internal/special_consts.h
continuation.o: $(hdrdir)/ruby/internal/static_assert.h
continuation.o: $(hdrdir)/ruby/internal/stdalign.h
continuation.o: $(hdrdir)/ruby/internal/stdbool.h
-continuation.o: $(hdrdir)/ruby/internal/stdckdint.h
continuation.o: $(hdrdir)/ruby/internal/symbol.h
continuation.o: $(hdrdir)/ruby/internal/value.h
continuation.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/coverage/coverage.c b/ext/coverage/coverage.c
index 9fc93bb58d..4578de54e4 100644
--- a/ext/coverage/coverage.c
+++ b/ext/coverage/coverage.c
@@ -8,7 +8,7 @@
************************************************/
-#include "internal/gc.h"
+#include "gc.h"
#include "internal/hash.h"
#include "internal/thread.h"
#include "internal/sanitizers.h"
@@ -29,7 +29,7 @@ static VALUE me2counter = Qnil;
* Returns true if coverage measurement is supported for the given mode.
*
* The mode should be one of the following symbols:
- * +:lines+, +:oneshot_lines+, +:branches+, +:methods+, +:eval+.
+ * +:lines+, +:branches+, +:methods+, +:eval+.
*
* Example:
*
@@ -43,7 +43,6 @@ rb_coverage_supported(VALUE self, VALUE _mode)
return RBOOL(
mode == rb_intern("lines") ||
- mode == rb_intern("oneshot_lines") ||
mode == rb_intern("branches") ||
mode == rb_intern("methods") ||
mode == rb_intern("eval")
@@ -353,8 +352,7 @@ rb_coverage_peek_result(VALUE klass)
rb_raise(rb_eRuntimeError, "coverage measurement is not enabled");
}
OBJ_WB_UNPROTECT(coverages);
-
- rb_hash_foreach(coverages, coverage_peek_result_i, ncoverages);
+ st_foreach(RHASH_TBL_RAW(coverages), coverage_peek_result_i, ncoverages);
if (current_mode & COVERAGE_TARGET_METHODS) {
rb_objspace_each_objects(method_coverage_i, &ncoverages);
diff --git a/ext/coverage/depend b/ext/coverage/depend
index 1be81c5e9a..e7fab16484 100644
--- a/ext/coverage/depend
+++ b/ext/coverage/depend
@@ -15,7 +15,6 @@ coverage.o: $(hdrdir)/ruby/backward/2/long_long.h
coverage.o: $(hdrdir)/ruby/backward/2/stdalign.h
coverage.o: $(hdrdir)/ruby/backward/2/stdarg.h
coverage.o: $(hdrdir)/ruby/defines.h
-coverage.o: $(hdrdir)/ruby/encoding.h
coverage.o: $(hdrdir)/ruby/intern.h
coverage.o: $(hdrdir)/ruby/internal/abi.h
coverage.o: $(hdrdir)/ruby/internal/anyargs.h
@@ -55,7 +54,6 @@ coverage.o: $(hdrdir)/ruby/internal/attr/noexcept.h
coverage.o: $(hdrdir)/ruby/internal/attr/noinline.h
coverage.o: $(hdrdir)/ruby/internal/attr/nonnull.h
coverage.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-coverage.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
coverage.o: $(hdrdir)/ruby/internal/attr/pure.h
coverage.o: $(hdrdir)/ruby/internal/attr/restrict.h
coverage.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -88,15 +86,6 @@ coverage.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
coverage.o: $(hdrdir)/ruby/internal/ctype.h
coverage.o: $(hdrdir)/ruby/internal/dllexport.h
coverage.o: $(hdrdir)/ruby/internal/dosish.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/re.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/string.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-coverage.o: $(hdrdir)/ruby/internal/encoding/transcode.h
coverage.o: $(hdrdir)/ruby/internal/error.h
coverage.o: $(hdrdir)/ruby/internal/eval.h
coverage.o: $(hdrdir)/ruby/internal/event.h
@@ -124,6 +113,7 @@ coverage.o: $(hdrdir)/ruby/internal/intern/enumerator.h
coverage.o: $(hdrdir)/ruby/internal/intern/error.h
coverage.o: $(hdrdir)/ruby/internal/intern/eval.h
coverage.o: $(hdrdir)/ruby/internal/intern/file.h
+coverage.o: $(hdrdir)/ruby/internal/intern/gc.h
coverage.o: $(hdrdir)/ruby/internal/intern/hash.h
coverage.o: $(hdrdir)/ruby/internal/intern/io.h
coverage.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -154,12 +144,12 @@ coverage.o: $(hdrdir)/ruby/internal/memory.h
coverage.o: $(hdrdir)/ruby/internal/method.h
coverage.o: $(hdrdir)/ruby/internal/module.h
coverage.o: $(hdrdir)/ruby/internal/newobj.h
+coverage.o: $(hdrdir)/ruby/internal/rgengc.h
coverage.o: $(hdrdir)/ruby/internal/scan_args.h
coverage.o: $(hdrdir)/ruby/internal/special_consts.h
coverage.o: $(hdrdir)/ruby/internal/static_assert.h
coverage.o: $(hdrdir)/ruby/internal/stdalign.h
coverage.o: $(hdrdir)/ruby/internal/stdbool.h
-coverage.o: $(hdrdir)/ruby/internal/stdckdint.h
coverage.o: $(hdrdir)/ruby/internal/symbol.h
coverage.o: $(hdrdir)/ruby/internal/value.h
coverage.o: $(hdrdir)/ruby/internal/value_type.h
@@ -167,8 +157,6 @@ coverage.o: $(hdrdir)/ruby/internal/variable.h
coverage.o: $(hdrdir)/ruby/internal/warning_push.h
coverage.o: $(hdrdir)/ruby/internal/xmalloc.h
coverage.o: $(hdrdir)/ruby/missing.h
-coverage.o: $(hdrdir)/ruby/onigmo.h
-coverage.o: $(hdrdir)/ruby/oniguruma.h
coverage.o: $(hdrdir)/ruby/ruby.h
coverage.o: $(hdrdir)/ruby/st.h
coverage.o: $(hdrdir)/ruby/subst.h
@@ -178,6 +166,7 @@ coverage.o: $(top_srcdir)/ccan/container_of/container_of.h
coverage.o: $(top_srcdir)/ccan/list/list.h
coverage.o: $(top_srcdir)/ccan/str/str.h
coverage.o: $(top_srcdir)/constant.h
+coverage.o: $(top_srcdir)/gc.h
coverage.o: $(top_srcdir)/id_table.h
coverage.o: $(top_srcdir)/internal.h
coverage.o: $(top_srcdir)/internal/array.h
@@ -197,7 +186,6 @@ coverage.o: $(top_srcdir)/method.h
coverage.o: $(top_srcdir)/node.h
coverage.o: $(top_srcdir)/ruby_assert.h
coverage.o: $(top_srcdir)/ruby_atomic.h
-coverage.o: $(top_srcdir)/rubyparser.h
coverage.o: $(top_srcdir)/shape.h
coverage.o: $(top_srcdir)/thread_pthread.h
coverage.o: $(top_srcdir)/vm_core.h
diff --git a/ext/date/date.gemspec b/ext/date/date.gemspec
index bd42b1518a..660353ebc5 100644
--- a/ext/date/date.gemspec
+++ b/ext/date/date.gemspec
@@ -31,6 +31,4 @@ Gem::Specification.new do |s|
s.email = [nil]
s.homepage = "https://github.com/ruby/date"
s.licenses = ["Ruby", "BSD-2-Clause"]
-
- s.metadata["changelog_uri"] = s.homepage + "/releases"
end
diff --git a/ext/date/date_core.c b/ext/date/date_core.c
index 823c0bc2a5..21367c0ddf 100644
--- a/ext/date/date_core.c
+++ b/ext/date/date_core.c
@@ -57,7 +57,7 @@ static VALUE sym_hour, sym_min, sym_sec, sym_sec_fraction, sym_zone;
#define f_add3(x,y,z) f_add(f_add(x, y), z)
#define f_sub3(x,y,z) f_sub(f_sub(x, y), z)
-#define f_frozen_ary(...) rb_ary_freeze(rb_ary_new3(__VA_ARGS__))
+#define f_frozen_ary(...) rb_obj_freeze(rb_ary_new3(__VA_ARGS__))
static VALUE date_initialize(int argc, VALUE *argv, VALUE self);
static VALUE datetime_initialize(int argc, VALUE *argv, VALUE self);
@@ -2589,6 +2589,8 @@ date_s__valid_civil_p(int argc, VALUE *argv, VALUE klass)
*
* See argument {start}[rdoc-ref:calendars.rdoc@Argument+start].
*
+ * Date.valid_date? is an alias for Date.valid_civil?.
+ *
* Related: Date.jd, Date.new.
*/
static VALUE
@@ -2984,6 +2986,8 @@ date_s_julian_leap_p(VALUE klass, VALUE y)
* Date.gregorian_leap?(2000) # => true
* Date.gregorian_leap?(2001) # => false
*
+ * Date.leap? is an alias for Date.gregorian_leap?.
+ *
* Related: Date.julian_leap?.
*/
static VALUE
@@ -3489,6 +3493,8 @@ date_s_civil(int argc, VALUE *argv, VALUE klass)
*
* See argument {start}[rdoc-ref:calendars.rdoc@Argument+start].
*
+ * Date.civil is an alias for Date.new.
+ *
* Related: Date.jd.
*/
static VALUE
@@ -4464,6 +4470,12 @@ check_limit(VALUE str, VALUE opt)
{
size_t slen, limit;
if (NIL_P(str)) return;
+ if (SYMBOL_P(str)) {
+ rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
+ "The ability to parse Symbol is an unintentional bug and is deprecated");
+ str = rb_sym2str(str);
+ }
+
StringValue(str);
slen = RSTRING_LEN(str);
limit = get_limit(opt);
@@ -4820,6 +4832,8 @@ date_s_xmlschema(int argc, VALUE *argv, VALUE klass)
*
* See argument {limit}[rdoc-ref:Date@Argument+limit].
*
+ * Date._rfc822 is an alias for Date._rfc2822.
+ *
* Related: Date.rfc2822 (returns a \Date object).
*/
static VALUE
@@ -4850,6 +4864,8 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass)
* - Argument {start}[rdoc-ref:calendars.rdoc@Argument+start].
* - Argument {limit}[rdoc-ref:Date@Argument+limit].
*
+ * Date.rfc822 is an alias for Date.rfc2822.
+ *
* Related: Date._rfc2822 (returns a hash).
*/
static VALUE
@@ -5330,6 +5346,7 @@ d_lite_yday(VALUE self)
*
* Date.new(2001, 2, 3).mon # => 2
*
+ * Date#month is an alias for Date#mon.
*/
static VALUE
d_lite_mon(VALUE self)
@@ -5346,6 +5363,7 @@ d_lite_mon(VALUE self)
*
* Date.new(2001, 2, 3).mday # => 3
*
+ * Date#day is an alias for Date#mday.
*/
static VALUE
d_lite_mday(VALUE self)
@@ -5595,6 +5613,7 @@ d_lite_hour(VALUE self)
*
* DateTime.new(2001, 2, 3, 4, 5, 6).min # => 5
*
+ * Date#minute is an alias for Date#min.
*/
static VALUE
d_lite_min(VALUE self)
@@ -5611,6 +5630,7 @@ d_lite_min(VALUE self)
*
* DateTime.new(2001, 2, 3, 4, 5, 6).sec # => 6
*
+ * Date#second is an alias for Date#sec.
*/
static VALUE
d_lite_sec(VALUE self)
@@ -5628,6 +5648,7 @@ d_lite_sec(VALUE self)
*
* DateTime.new(2001, 2, 3, 4, 5, 6.5).sec_fraction # => (1/2)
*
+ * Date#second_fraction is an alias for Date#sec_fraction.
*/
static VALUE
d_lite_sec_fraction(VALUE self)
@@ -6326,11 +6347,9 @@ minus_dd(VALUE self, VALUE other)
* call-seq:
* d - other -> date or rational
*
- * If the other is a date object, returns a Rational
- * whose value is the difference between the two dates in days.
- * If the other is a numeric value, returns a date object
- * pointing +other+ days before self.
- * If the other is a fractional number,
+ * Returns the difference between the two dates if the other is a date
+ * object. If the other is a numeric value, returns a date object
+ * pointing +other+ days before self. If the other is a fractional number,
* assumes its precision is at most nanosecond.
*
* Date.new(2001,2,3) - 1 #=> #<Date: 2001-02-02 ...>
@@ -6405,6 +6424,7 @@ d_lite_prev_day(int argc, VALUE *argv, VALUE self)
* d.to_s # => "2001-02-03"
* d.next.to_s # => "2001-02-04"
*
+ * Date#succ is an alias for Date#next.
*/
static VALUE
d_lite_next(VALUE self)
@@ -7278,6 +7298,7 @@ strftimev(const char *fmt, VALUE self,
*
* See {asctime}[https://linux.die.net/man/3/asctime].
*
+ * Date#ctime is an alias for Date#asctime.
*/
static VALUE
d_lite_asctime(VALUE self)
@@ -7295,6 +7316,7 @@ d_lite_asctime(VALUE self)
*
* Date.new(2001, 2, 3).iso8601 # => "2001-02-03"
*
+ * Date#xmlschema is an alias for Date#iso8601.
*/
static VALUE
d_lite_iso8601(VALUE self)
@@ -7327,6 +7349,7 @@ d_lite_rfc3339(VALUE self)
*
* Date.new(2001, 2, 3).rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
*
+ * Date#rfc822 is an alias for Date#rfc2822.
*/
static VALUE
d_lite_rfc2822(VALUE self)
@@ -8722,8 +8745,8 @@ dt_lite_to_s(VALUE self)
*
* DateTime.now.strftime # => "2022-07-01T11:03:19-05:00"
*
- * For other formats,
- * see {Formats for Dates and Times}[rdoc-ref:strftime_formatting.rdoc]:
+ * For other formats, see
+ * {Formats for Dates and Times}[doc/strftime_formatting.rdoc].
*
*/
static VALUE
@@ -8957,22 +8980,18 @@ time_to_datetime(VALUE self)
static VALUE
date_to_time(VALUE self)
{
- VALUE t;
-
get_d1a(self);
if (m_julian_p(adat)) {
- self = d_lite_gregorian(self);
- get_d1b(self);
+ VALUE tmp = d_lite_gregorian(self);
+ get_d1b(tmp);
adat = bdat;
}
- t = f_local3(rb_cTime,
+ return f_local3(rb_cTime,
m_real_year(adat),
INT2FIX(m_mon(adat)),
INT2FIX(m_mday(adat)));
- RB_GC_GUARD(self); /* may be the converted gregorian */
- return t;
}
/*
@@ -9061,7 +9080,6 @@ datetime_to_time(VALUE self)
f_add(INT2FIX(m_sec(dat)),
m_sf_in_sec(dat)),
INT2FIX(m_of(dat)));
- RB_GC_GUARD(self); /* may be the converted gregorian */
return t;
}
}
@@ -9466,7 +9484,7 @@ mk_ary_of_str(long len, const char *a[])
}
rb_ary_push(o, e);
}
- rb_ary_freeze(o);
+ rb_obj_freeze(o);
return o;
}
diff --git a/ext/date/date_parse.c b/ext/date/date_parse.c
index a1600e4708..c6f26ecb91 100644
--- a/ext/date/date_parse.c
+++ b/ext/date/date_parse.c
@@ -7,9 +7,6 @@
#include "ruby/re.h"
#include <ctype.h>
-#undef strncasecmp
-#define strncasecmp STRNCASECMP
-
RUBY_EXTERN VALUE rb_int_positive_pow(long x, unsigned long y);
RUBY_EXTERN unsigned long ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow);
diff --git a/ext/date/date_strptime.c b/ext/date/date_strptime.c
index da58c21a76..f731629df1 100644
--- a/ext/date/date_strptime.c
+++ b/ext/date/date_strptime.c
@@ -7,9 +7,6 @@
#include "ruby/re.h"
#include <ctype.h>
-#undef strncasecmp
-#define strncasecmp STRNCASECMP
-
static const char *day_names[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday",
diff --git a/ext/date/depend b/ext/date/depend
index d07f10a593..3f550cd0a7 100644
--- a/ext/date/depend
+++ b/ext/date/depend
@@ -53,7 +53,6 @@ date_core.o: $(hdrdir)/ruby/internal/attr/noexcept.h
date_core.o: $(hdrdir)/ruby/internal/attr/noinline.h
date_core.o: $(hdrdir)/ruby/internal/attr/nonnull.h
date_core.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-date_core.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
date_core.o: $(hdrdir)/ruby/internal/attr/pure.h
date_core.o: $(hdrdir)/ruby/internal/attr/restrict.h
date_core.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ date_core.o: $(hdrdir)/ruby/internal/intern/enumerator.h
date_core.o: $(hdrdir)/ruby/internal/intern/error.h
date_core.o: $(hdrdir)/ruby/internal/intern/eval.h
date_core.o: $(hdrdir)/ruby/internal/intern/file.h
+date_core.o: $(hdrdir)/ruby/internal/intern/gc.h
date_core.o: $(hdrdir)/ruby/internal/intern/hash.h
date_core.o: $(hdrdir)/ruby/internal/intern/io.h
date_core.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,12 +152,12 @@ date_core.o: $(hdrdir)/ruby/internal/memory.h
date_core.o: $(hdrdir)/ruby/internal/method.h
date_core.o: $(hdrdir)/ruby/internal/module.h
date_core.o: $(hdrdir)/ruby/internal/newobj.h
+date_core.o: $(hdrdir)/ruby/internal/rgengc.h
date_core.o: $(hdrdir)/ruby/internal/scan_args.h
date_core.o: $(hdrdir)/ruby/internal/special_consts.h
date_core.o: $(hdrdir)/ruby/internal/static_assert.h
date_core.o: $(hdrdir)/ruby/internal/stdalign.h
date_core.o: $(hdrdir)/ruby/internal/stdbool.h
-date_core.o: $(hdrdir)/ruby/internal/stdckdint.h
date_core.o: $(hdrdir)/ruby/internal/symbol.h
date_core.o: $(hdrdir)/ruby/internal/value.h
date_core.o: $(hdrdir)/ruby/internal/value_type.h
@@ -227,7 +227,6 @@ date_parse.o: $(hdrdir)/ruby/internal/attr/noexcept.h
date_parse.o: $(hdrdir)/ruby/internal/attr/noinline.h
date_parse.o: $(hdrdir)/ruby/internal/attr/nonnull.h
date_parse.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-date_parse.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
date_parse.o: $(hdrdir)/ruby/internal/attr/pure.h
date_parse.o: $(hdrdir)/ruby/internal/attr/restrict.h
date_parse.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -297,6 +296,7 @@ date_parse.o: $(hdrdir)/ruby/internal/intern/enumerator.h
date_parse.o: $(hdrdir)/ruby/internal/intern/error.h
date_parse.o: $(hdrdir)/ruby/internal/intern/eval.h
date_parse.o: $(hdrdir)/ruby/internal/intern/file.h
+date_parse.o: $(hdrdir)/ruby/internal/intern/gc.h
date_parse.o: $(hdrdir)/ruby/internal/intern/hash.h
date_parse.o: $(hdrdir)/ruby/internal/intern/io.h
date_parse.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -327,12 +327,12 @@ date_parse.o: $(hdrdir)/ruby/internal/memory.h
date_parse.o: $(hdrdir)/ruby/internal/method.h
date_parse.o: $(hdrdir)/ruby/internal/module.h
date_parse.o: $(hdrdir)/ruby/internal/newobj.h
+date_parse.o: $(hdrdir)/ruby/internal/rgengc.h
date_parse.o: $(hdrdir)/ruby/internal/scan_args.h
date_parse.o: $(hdrdir)/ruby/internal/special_consts.h
date_parse.o: $(hdrdir)/ruby/internal/static_assert.h
date_parse.o: $(hdrdir)/ruby/internal/stdalign.h
date_parse.o: $(hdrdir)/ruby/internal/stdbool.h
-date_parse.o: $(hdrdir)/ruby/internal/stdckdint.h
date_parse.o: $(hdrdir)/ruby/internal/symbol.h
date_parse.o: $(hdrdir)/ruby/internal/value.h
date_parse.o: $(hdrdir)/ruby/internal/value_type.h
@@ -402,7 +402,6 @@ date_strftime.o: $(hdrdir)/ruby/internal/attr/noexcept.h
date_strftime.o: $(hdrdir)/ruby/internal/attr/noinline.h
date_strftime.o: $(hdrdir)/ruby/internal/attr/nonnull.h
date_strftime.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-date_strftime.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
date_strftime.o: $(hdrdir)/ruby/internal/attr/pure.h
date_strftime.o: $(hdrdir)/ruby/internal/attr/restrict.h
date_strftime.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -462,6 +461,7 @@ date_strftime.o: $(hdrdir)/ruby/internal/intern/enumerator.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/error.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/eval.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/file.h
+date_strftime.o: $(hdrdir)/ruby/internal/intern/gc.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/hash.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/io.h
date_strftime.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -492,12 +492,12 @@ date_strftime.o: $(hdrdir)/ruby/internal/memory.h
date_strftime.o: $(hdrdir)/ruby/internal/method.h
date_strftime.o: $(hdrdir)/ruby/internal/module.h
date_strftime.o: $(hdrdir)/ruby/internal/newobj.h
+date_strftime.o: $(hdrdir)/ruby/internal/rgengc.h
date_strftime.o: $(hdrdir)/ruby/internal/scan_args.h
date_strftime.o: $(hdrdir)/ruby/internal/special_consts.h
date_strftime.o: $(hdrdir)/ruby/internal/static_assert.h
date_strftime.o: $(hdrdir)/ruby/internal/stdalign.h
date_strftime.o: $(hdrdir)/ruby/internal/stdbool.h
-date_strftime.o: $(hdrdir)/ruby/internal/stdckdint.h
date_strftime.o: $(hdrdir)/ruby/internal/symbol.h
date_strftime.o: $(hdrdir)/ruby/internal/value.h
date_strftime.o: $(hdrdir)/ruby/internal/value_type.h
@@ -564,7 +564,6 @@ date_strptime.o: $(hdrdir)/ruby/internal/attr/noexcept.h
date_strptime.o: $(hdrdir)/ruby/internal/attr/noinline.h
date_strptime.o: $(hdrdir)/ruby/internal/attr/nonnull.h
date_strptime.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-date_strptime.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
date_strptime.o: $(hdrdir)/ruby/internal/attr/pure.h
date_strptime.o: $(hdrdir)/ruby/internal/attr/restrict.h
date_strptime.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -634,6 +633,7 @@ date_strptime.o: $(hdrdir)/ruby/internal/intern/enumerator.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/error.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/eval.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/file.h
+date_strptime.o: $(hdrdir)/ruby/internal/intern/gc.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/hash.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/io.h
date_strptime.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -664,12 +664,12 @@ date_strptime.o: $(hdrdir)/ruby/internal/memory.h
date_strptime.o: $(hdrdir)/ruby/internal/method.h
date_strptime.o: $(hdrdir)/ruby/internal/module.h
date_strptime.o: $(hdrdir)/ruby/internal/newobj.h
+date_strptime.o: $(hdrdir)/ruby/internal/rgengc.h
date_strptime.o: $(hdrdir)/ruby/internal/scan_args.h
date_strptime.o: $(hdrdir)/ruby/internal/special_consts.h
date_strptime.o: $(hdrdir)/ruby/internal/static_assert.h
date_strptime.o: $(hdrdir)/ruby/internal/stdalign.h
date_strptime.o: $(hdrdir)/ruby/internal/stdbool.h
-date_strptime.o: $(hdrdir)/ruby/internal/stdckdint.h
date_strptime.o: $(hdrdir)/ruby/internal/symbol.h
date_strptime.o: $(hdrdir)/ruby/internal/value.h
date_strptime.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/date/lib/date.rb b/ext/date/lib/date.rb
index 6888bd2d4e..a9fe3ce4b0 100644
--- a/ext/date/lib/date.rb
+++ b/ext/date/lib/date.rb
@@ -4,7 +4,7 @@
require 'date_core'
class Date
- VERSION = "3.3.4" # :nodoc:
+ VERSION = "3.3.3" # :nodoc:
# call-seq:
# infinite? -> false
diff --git a/ext/date/prereq.mk b/ext/date/prereq.mk
index b5d271a32c..cee7685975 100644
--- a/ext/date/prereq.mk
+++ b/ext/date/prereq.mk
@@ -1,7 +1,7 @@
.SUFFIXES: .list
.list.h:
- gperf --ignore-case -L ANSI-C -C -c -P -p -j1 -i 1 -g -o -t -N $(*F) $< \
+ gperf --ignore-case -C -c -P -p -j1 -i 1 -g -o -t -N $(*F) $< \
| sed -f $(top_srcdir)/tool/gperf.sed \
> $(@F)
diff --git a/ext/date/zonetab.h b/ext/date/zonetab.h
index 2a2e8910c9..7ced9e0308 100644
--- a/ext/date/zonetab.h
+++ b/ext/date/zonetab.h
@@ -1,5 +1,5 @@
/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf --ignore-case -L ANSI-C -C -c -P -p -j1 -i 1 -g -o -t -N zonetab zonetab.list */
+/* Command-line: gperf --ignore-case -C -c -P -p -j1 -i 1 -g -o -t -N zonetab zonetab.list */
/* Computed positions: -k'1-4,9' */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
@@ -29,17 +29,15 @@
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
#endif
+#define gperf_offsetof(s, n) (short)offsetof(struct s##_t, s##_str##n)
#line 1 "zonetab.list"
-#define GPERF_DOWNCASE 1
-#define GPERF_CASE_STRNCMP 1
-#define gperf_case_strncmp strncasecmp
struct zone {
int name;
int offset;
};
static const struct zone *zonetab(register const char *str, register size_t len);
-#line 12 "zonetab.list"
+#line 9 "zonetab.list"
struct zone;
#define TOTAL_KEYWORDS 316
@@ -51,7 +49,7 @@ struct zone;
#ifndef GPERF_DOWNCASE
#define GPERF_DOWNCASE 1
-static unsigned char gperf_downcase[256] =
+static const unsigned char gperf_downcase[256] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
@@ -810,736 +808,736 @@ zonetab (register const char *str, register size_t len)
static const struct zone wordlist[] =
{
{-1}, {-1},
-#line 37 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str2, -2*3600},
-#line 46 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str3, -11*3600},
-#line 48 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str4, 0*3600},
-#line 39 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str5, -4*3600},
+#line 34 "zonetab.list"
+ {gperf_offsetof(stringpool, 2), -2*3600},
+#line 43 "zonetab.list"
+ {gperf_offsetof(stringpool, 3), -11*3600},
+#line 45 "zonetab.list"
+ {gperf_offsetof(stringpool, 4), 0*3600},
+#line 36 "zonetab.list"
+ {gperf_offsetof(stringpool, 5), -4*3600},
{-1}, {-1},
-#line 272 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str8,21600},
-#line 271 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str9,25200},
-#line 38 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str10, -3*3600},
+#line 269 "zonetab.list"
+ {gperf_offsetof(stringpool, 8),21600},
+#line 268 "zonetab.list"
+ {gperf_offsetof(stringpool, 9),25200},
+#line 35 "zonetab.list"
+ {gperf_offsetof(stringpool, 10), -3*3600},
{-1}, {-1},
+#line 21 "zonetab.list"
+ {gperf_offsetof(stringpool, 13), 1*3600},
+#line 25 "zonetab.list"
+ {gperf_offsetof(stringpool, 14), 5*3600},
+#line 271 "zonetab.list"
+ {gperf_offsetof(stringpool, 15),-18000},
+#line 279 "zonetab.list"
+ {gperf_offsetof(stringpool, 16),-10800},
+#line 273 "zonetab.list"
+ {gperf_offsetof(stringpool, 17),43200},
+#line 272 "zonetab.list"
+ {gperf_offsetof(stringpool, 18),43200},
+#line 80 "zonetab.list"
+ {gperf_offsetof(stringpool, 19), 2*3600},
+#line 186 "zonetab.list"
+ {gperf_offsetof(stringpool, 20),36000},
+#line 88 "zonetab.list"
+ {gperf_offsetof(stringpool, 21), 3*3600},
+#line 87 "zonetab.list"
+ {gperf_offsetof(stringpool, 22), 3*3600},
+ {-1},
+#line 101 "zonetab.list"
+ {gperf_offsetof(stringpool, 24),-6*3600},
+#line 217 "zonetab.list"
+ {gperf_offsetof(stringpool, 25),-18000},
+#line 19 "zonetab.list"
+ {gperf_offsetof(stringpool, 26), -8*3600},
+#line 133 "zonetab.list"
+ {gperf_offsetof(stringpool, 27), -18000},
+#line 32 "zonetab.list"
+ {gperf_offsetof(stringpool, 28), 12*3600},
+#line 56 "zonetab.list"
+ {gperf_offsetof(stringpool, 29), -4*3600},
+#line 13 "zonetab.list"
+ {gperf_offsetof(stringpool, 30), -5*3600},
+#line 23 "zonetab.list"
+ {gperf_offsetof(stringpool, 31), 3*3600},
+#line 256 "zonetab.list"
+ {gperf_offsetof(stringpool, 32),23400},
+#line 73 "zonetab.list"
+ {gperf_offsetof(stringpool, 33), 1*3600},
+ {-1},
+#line 82 "zonetab.list"
+ {gperf_offsetof(stringpool, 35), 2*3600},
+#line 71 "zonetab.list"
+ {gperf_offsetof(stringpool, 36), 1*3600},
#line 24 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str13, 1*3600},
-#line 28 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str14, 5*3600},
-#line 274 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str15,-18000},
-#line 282 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str16,-10800},
-#line 276 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str17,43200},
-#line 275 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str18,43200},
-#line 83 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str19, 2*3600},
-#line 189 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str20,36000},
-#line 91 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str21, 3*3600},
-#line 90 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str22, 3*3600},
+ {gperf_offsetof(stringpool, 37), 4*3600},
+#line 79 "zonetab.list"
+ {gperf_offsetof(stringpool, 38), 2*3600},
+#line 65 "zonetab.list"
+ {gperf_offsetof(stringpool, 39),2*3600},
{-1},
-#line 104 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str24,-6*3600},
-#line 220 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str25,-18000},
-#line 22 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str26, -8*3600},
-#line 136 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str27, -18000},
-#line 35 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str28, 12*3600},
-#line 59 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str29, -4*3600},
-#line 16 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str30, -5*3600},
+#line 202 "zonetab.list"
+ {gperf_offsetof(stringpool, 41),28800},
+#line 252 "zonetab.list"
+ {gperf_offsetof(stringpool, 42),39600},
+#line 251 "zonetab.list"
+ {gperf_offsetof(stringpool, 43),43200},
+#line 17 "zonetab.list"
+ {gperf_offsetof(stringpool, 44), -7*3600},
+#line 89 "zonetab.list"
+ {gperf_offsetof(stringpool, 45), 3*3600},
+#line 212 "zonetab.list"
+ {gperf_offsetof(stringpool, 46),-18000},
+#line 15 "zonetab.list"
+ {gperf_offsetof(stringpool, 47), -6*3600},
+#line 192 "zonetab.list"
+ {gperf_offsetof(stringpool, 48),18000},
#line 26 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str31, 3*3600},
-#line 259 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str32,23400},
-#line 76 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str33, 1*3600},
+ {gperf_offsetof(stringpool, 49), 6*3600},
+ {-1}, {-1},
+#line 51 "zonetab.list"
+ {gperf_offsetof(stringpool, 52), -3*3600},
+#line 226 "zonetab.list"
+ {gperf_offsetof(stringpool, 53),-7200},
+#line 221 "zonetab.list"
+ {gperf_offsetof(stringpool, 54),10800},
+#line 22 "zonetab.list"
+ {gperf_offsetof(stringpool, 55), 2*3600},
{-1},
-#line 85 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str35, 2*3600},
+#line 190 "zonetab.list"
+ {gperf_offsetof(stringpool, 57),43200},
+#line 189 "zonetab.list"
+ {gperf_offsetof(stringpool, 58),43200},
+#line 199 "zonetab.list"
+ {gperf_offsetof(stringpool, 59),28800},
+#line 29 "zonetab.list"
+ {gperf_offsetof(stringpool, 60), 9*3600},
+#line 276 "zonetab.list"
+ {gperf_offsetof(stringpool, 61),28800},
+#line 48 "zonetab.list"
+ {gperf_offsetof(stringpool, 62), -2*3600},
+#line 94 "zonetab.list"
+ {gperf_offsetof(stringpool, 63), 6*3600},
#line 74 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str36, 1*3600},
-#line 27 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str37, 4*3600},
-#line 82 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str38, 2*3600},
-#line 68 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str39,2*3600},
- {-1},
-#line 205 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str41,28800},
-#line 255 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str42,39600},
+ {gperf_offsetof(stringpool, 64), 1*3600},
+#line 81 "zonetab.list"
+ {gperf_offsetof(stringpool, 65), 2*3600},
+#line 64 "zonetab.list"
+ {gperf_offsetof(stringpool, 66),-10*3600},
#line 254 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str43,43200},
-#line 20 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str44, -7*3600},
+ {gperf_offsetof(stringpool, 67),18000},
#line 92 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str45, 3*3600},
-#line 215 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str46,-18000},
-#line 18 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str47, -6*3600},
-#line 195 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str48,18000},
-#line 29 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str49, 6*3600},
- {-1}, {-1},
-#line 54 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str52, -3*3600},
-#line 229 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str53,-7200},
-#line 224 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str54,10800},
-#line 25 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str55, 2*3600},
+ {gperf_offsetof(stringpool, 68), 5*3600},
{-1},
-#line 193 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str57,43200},
-#line 192 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str58,43200},
-#line 202 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str59,28800},
-#line 32 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str60, 9*3600},
-#line 279 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str61,28800},
-#line 51 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str62, -2*3600},
-#line 97 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str63, 6*3600},
-#line 77 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str64, 1*3600},
-#line 84 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str65, 2*3600},
-#line 67 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str66,-10*3600},
-#line 257 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str67,18000},
-#line 95 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str68, 5*3600},
- {-1},
-#line 203 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str70,-14400},
-#line 73 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str71, 1*3600},
-#line 284 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str72,32400},
+#line 200 "zonetab.list"
+ {gperf_offsetof(stringpool, 70),-14400},
+#line 70 "zonetab.list"
+ {gperf_offsetof(stringpool, 71), 1*3600},
+#line 281 "zonetab.list"
+ {gperf_offsetof(stringpool, 72),32400},
{-1},
-#line 283 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str74,39600},
-#line 241 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str75,21600},
-#line 96 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str76, (5*3600+1800)},
-#line 197 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str77,28800},
+#line 280 "zonetab.list"
+ {gperf_offsetof(stringpool, 74),39600},
+#line 238 "zonetab.list"
+ {gperf_offsetof(stringpool, 75),21600},
+#line 93 "zonetab.list"
+ {gperf_offsetof(stringpool, 76), (5*3600+1800)},
+#line 194 "zonetab.list"
+ {gperf_offsetof(stringpool, 77),28800},
{-1},
-#line 258 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str79,43200},
-#line 78 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str80, 1*3600},
-#line 273 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str81,18000},
-#line 86 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str82, 2*3600},
+#line 255 "zonetab.list"
+ {gperf_offsetof(stringpool, 79),43200},
+#line 75 "zonetab.list"
+ {gperf_offsetof(stringpool, 80), 1*3600},
+#line 270 "zonetab.list"
+ {gperf_offsetof(stringpool, 81),18000},
+#line 83 "zonetab.list"
+ {gperf_offsetof(stringpool, 82), 2*3600},
{-1},
-#line 210 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str84,36000},
-#line 281 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str85,-7200},
+#line 207 "zonetab.list"
+ {gperf_offsetof(stringpool, 84),36000},
+#line 278 "zonetab.list"
+ {gperf_offsetof(stringpool, 85),-7200},
{-1}, {-1},
-#line 129 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str88, -21600},
-#line 188 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str89,39600},
-#line 186 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str90,-18000},
-#line 221 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str91,-18000},
+#line 126 "zonetab.list"
+ {gperf_offsetof(stringpool, 88), -21600},
#line 185 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str92,34200},
-#line 106 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str93,11*3600},
-#line 56 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str94, -3*3600},
-#line 211 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str95,36000},
-#line 52 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str96,-2*3600},
-#line 123 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str97, 34200},
- {-1}, {-1},
+ {gperf_offsetof(stringpool, 89),39600},
+#line 183 "zonetab.list"
+ {gperf_offsetof(stringpool, 90),-18000},
#line 218 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str100,25200},
-#line 245 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str101,12600},
-#line 244 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str102,28800},
-#line 243 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str103,32400},
-#line 89 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str104, 3*3600},
-#line 36 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str105, -1*3600},
-#line 204 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str106,21600},
-#line 151 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str107, -25200},
-#line 99 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str108, (6*3600+1800)},
-#line 45 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str109, -10*3600},
-#line 34 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str110, 11*3600},
-#line 75 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str111, 1*3600},
+ {gperf_offsetof(stringpool, 91),-18000},
+#line 182 "zonetab.list"
+ {gperf_offsetof(stringpool, 92),34200},
+#line 103 "zonetab.list"
+ {gperf_offsetof(stringpool, 93),11*3600},
+#line 53 "zonetab.list"
+ {gperf_offsetof(stringpool, 94), -3*3600},
+#line 208 "zonetab.list"
+ {gperf_offsetof(stringpool, 95),36000},
+#line 49 "zonetab.list"
+ {gperf_offsetof(stringpool, 96),-2*3600},
+#line 120 "zonetab.list"
+ {gperf_offsetof(stringpool, 97), 34200},
+ {-1}, {-1},
+#line 215 "zonetab.list"
+ {gperf_offsetof(stringpool, 100),25200},
+#line 242 "zonetab.list"
+ {gperf_offsetof(stringpool, 101),12600},
+#line 241 "zonetab.list"
+ {gperf_offsetof(stringpool, 102),28800},
+#line 240 "zonetab.list"
+ {gperf_offsetof(stringpool, 103),32400},
+#line 86 "zonetab.list"
+ {gperf_offsetof(stringpool, 104), 3*3600},
+#line 33 "zonetab.list"
+ {gperf_offsetof(stringpool, 105), -1*3600},
+#line 201 "zonetab.list"
+ {gperf_offsetof(stringpool, 106),21600},
+#line 148 "zonetab.list"
+ {gperf_offsetof(stringpool, 107), -25200},
+#line 96 "zonetab.list"
+ {gperf_offsetof(stringpool, 108), (6*3600+1800)},
+#line 42 "zonetab.list"
+ {gperf_offsetof(stringpool, 109), -10*3600},
+#line 31 "zonetab.list"
+ {gperf_offsetof(stringpool, 110), 11*3600},
+#line 72 "zonetab.list"
+ {gperf_offsetof(stringpool, 111), 1*3600},
{-1},
-#line 93 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str113, 4*3600},
-#line 50 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str114, 0*3600},
+#line 90 "zonetab.list"
+ {gperf_offsetof(stringpool, 113), 4*3600},
+#line 47 "zonetab.list"
+ {gperf_offsetof(stringpool, 114), 0*3600},
{-1},
-#line 81 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str116, 1*3600},
-#line 80 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str117, 1*3600},
+#line 78 "zonetab.list"
+ {gperf_offsetof(stringpool, 116), 1*3600},
+#line 77 "zonetab.list"
+ {gperf_offsetof(stringpool, 117), 1*3600},
{-1},
-#line 98 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str119, 2*3600},
-#line 316 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str120,43200},
-#line 58 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str121, -(2*3600+1800)},
-#line 187 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str122,31500},
-#line 207 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str123,45900},
-#line 213 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str124,-18000},
-#line 201 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str125,14400},
-#line 60 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str126, -4*3600},
-#line 200 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str127,18000},
+#line 95 "zonetab.list"
+ {gperf_offsetof(stringpool, 119), 2*3600},
+#line 313 "zonetab.list"
+ {gperf_offsetof(stringpool, 120),43200},
+#line 55 "zonetab.list"
+ {gperf_offsetof(stringpool, 121), -(2*3600+1800)},
+#line 184 "zonetab.list"
+ {gperf_offsetof(stringpool, 122),31500},
+#line 204 "zonetab.list"
+ {gperf_offsetof(stringpool, 123),45900},
+#line 210 "zonetab.list"
+ {gperf_offsetof(stringpool, 124),-18000},
+#line 198 "zonetab.list"
+ {gperf_offsetof(stringpool, 125),14400},
#line 57 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str128,-3*3600},
-#line 256 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str129,-30600},
-#line 94 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str130, 4*3600},
-#line 102 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str131, 9*3600},
-#line 125 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str132, 21600},
-#line 190 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str133,16200},
-#line 135 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str134, -10800},
-#line 124 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str135, -21600},
+ {gperf_offsetof(stringpool, 126), -4*3600},
+#line 197 "zonetab.list"
+ {gperf_offsetof(stringpool, 127),18000},
+#line 54 "zonetab.list"
+ {gperf_offsetof(stringpool, 128),-3*3600},
+#line 253 "zonetab.list"
+ {gperf_offsetof(stringpool, 129),-30600},
+#line 91 "zonetab.list"
+ {gperf_offsetof(stringpool, 130), 4*3600},
+#line 99 "zonetab.list"
+ {gperf_offsetof(stringpool, 131), 9*3600},
+#line 122 "zonetab.list"
+ {gperf_offsetof(stringpool, 132), 21600},
+#line 187 "zonetab.list"
+ {gperf_offsetof(stringpool, 133),16200},
+#line 132 "zonetab.list"
+ {gperf_offsetof(stringpool, 134), -10800},
+#line 121 "zonetab.list"
+ {gperf_offsetof(stringpool, 135), -21600},
{-1},
-#line 239 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str137,25200},
+#line 236 "zonetab.list"
+ {gperf_offsetof(stringpool, 137),25200},
{-1}, {-1}, {-1}, {-1}, {-1},
-#line 277 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str143,36000},
-#line 269 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str144,43200},
-#line 149 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str145, -21600},
-#line 196 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str146,32400},
-#line 223 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str147,-3600},
-#line 217 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str148,25200},
-#line 222 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str149,0},
-#line 278 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str150,46800},
-#line 112 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str151, -32400},
+#line 274 "zonetab.list"
+ {gperf_offsetof(stringpool, 143),36000},
+#line 266 "zonetab.list"
+ {gperf_offsetof(stringpool, 144),43200},
+#line 146 "zonetab.list"
+ {gperf_offsetof(stringpool, 145), -21600},
+#line 193 "zonetab.list"
+ {gperf_offsetof(stringpool, 146),32400},
+#line 220 "zonetab.list"
+ {gperf_offsetof(stringpool, 147),-3600},
+#line 214 "zonetab.list"
+ {gperf_offsetof(stringpool, 148),25200},
+#line 219 "zonetab.list"
+ {gperf_offsetof(stringpool, 149),0},
+#line 275 "zonetab.list"
+ {gperf_offsetof(stringpool, 150),46800},
+#line 109 "zonetab.list"
+ {gperf_offsetof(stringpool, 151), -32400},
{-1}, {-1},
-#line 71 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str154, -11*3600},
+#line 68 "zonetab.list"
+ {gperf_offsetof(stringpool, 154), -11*3600},
{-1}, {-1}, {-1},
-#line 324 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str158,0},
+#line 321 "zonetab.list"
+ {gperf_offsetof(stringpool, 158),0},
{-1},
+#line 178 "zonetab.list"
+ {gperf_offsetof(stringpool, 160), 18000},
#line 181 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str160, 18000},
-#line 184 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str161,37800},
-#line 268 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str162,20700},
-#line 252 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str163,37800},
-#line 111 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str164, 16200},
+ {gperf_offsetof(stringpool, 161),37800},
+#line 265 "zonetab.list"
+ {gperf_offsetof(stringpool, 162),20700},
+#line 249 "zonetab.list"
+ {gperf_offsetof(stringpool, 163),37800},
+#line 108 "zonetab.list"
+ {gperf_offsetof(stringpool, 164), 16200},
{-1}, {-1},
-#line 33 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str167, 10*3600},
- {-1},
#line 30 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str169, 7*3600},
-#line 242 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str170,16200},
-#line 209 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str171,28800},
-#line 208 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str172,32400},
-#line 15 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str173, 0*3600},
-#line 232 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str174,14400},
-#line 267 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str175,25200},
-#line 266 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str176,25200},
-#line 226 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str177,43200},
-#line 43 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str178, -8*3600},
-#line 225 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str179,46800},
+ {gperf_offsetof(stringpool, 167), 10*3600},
{-1},
-#line 285 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str181,-10800},
-#line 263 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str182,39600},
-#line 103 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str183, 9*3600},
-#line 247 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str184,39600},
-#line 105 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str185, 10*3600},
-#line 146 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str186, 12600},
-#line 132 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str187, 10800},
-#line 101 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str188, 8*3600},
-#line 42 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str189, -7*3600},
-#line 133 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str190, 36000},
-#line 41 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str191, -6*3600},
+#line 27 "zonetab.list"
+ {gperf_offsetof(stringpool, 169), 7*3600},
+#line 239 "zonetab.list"
+ {gperf_offsetof(stringpool, 170),16200},
#line 206 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str192,49500},
-#line 301 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str193,18000},
-#line 212 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str194,-14400},
-#line 194 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str195,-43200},
+ {gperf_offsetof(stringpool, 171),28800},
+#line 205 "zonetab.list"
+ {gperf_offsetof(stringpool, 172),32400},
+#line 12 "zonetab.list"
+ {gperf_offsetof(stringpool, 173), 0*3600},
+#line 229 "zonetab.list"
+ {gperf_offsetof(stringpool, 174),14400},
+#line 264 "zonetab.list"
+ {gperf_offsetof(stringpool, 175),25200},
+#line 263 "zonetab.list"
+ {gperf_offsetof(stringpool, 176),25200},
+#line 223 "zonetab.list"
+ {gperf_offsetof(stringpool, 177),43200},
+#line 40 "zonetab.list"
+ {gperf_offsetof(stringpool, 178), -8*3600},
+#line 222 "zonetab.list"
+ {gperf_offsetof(stringpool, 179),46800},
{-1},
-#line 262 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str197,28800},
-#line 182 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str198, 36000},
+#line 282 "zonetab.list"
+ {gperf_offsetof(stringpool, 181),-10800},
#line 260 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str199,14400},
-#line 322 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str200,32400},
-#line 87 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str201, 2*3600},
-#line 289 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str202,39600},
-#line 155 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str203, 43200},
-#line 303 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str204,46800},
+ {gperf_offsetof(stringpool, 182),39600},
+#line 100 "zonetab.list"
+ {gperf_offsetof(stringpool, 183), 9*3600},
+#line 244 "zonetab.list"
+ {gperf_offsetof(stringpool, 184),39600},
+#line 102 "zonetab.list"
+ {gperf_offsetof(stringpool, 185), 10*3600},
+#line 143 "zonetab.list"
+ {gperf_offsetof(stringpool, 186), 12600},
+#line 129 "zonetab.list"
+ {gperf_offsetof(stringpool, 187), 10800},
+#line 98 "zonetab.list"
+ {gperf_offsetof(stringpool, 188), 8*3600},
+#line 39 "zonetab.list"
+ {gperf_offsetof(stringpool, 189), -7*3600},
#line 130 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str205, 28800},
-#line 302 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str206,50400},
-#line 88 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str207, -11*3600},
+ {gperf_offsetof(stringpool, 190), 36000},
+#line 38 "zonetab.list"
+ {gperf_offsetof(stringpool, 191), -6*3600},
+#line 203 "zonetab.list"
+ {gperf_offsetof(stringpool, 192),49500},
+#line 298 "zonetab.list"
+ {gperf_offsetof(stringpool, 193),18000},
+#line 209 "zonetab.list"
+ {gperf_offsetof(stringpool, 194),-14400},
+#line 191 "zonetab.list"
+ {gperf_offsetof(stringpool, 195),-43200},
{-1},
-#line 145 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str209, 19800},
+#line 259 "zonetab.list"
+ {gperf_offsetof(stringpool, 197),28800},
+#line 179 "zonetab.list"
+ {gperf_offsetof(stringpool, 198), 36000},
+#line 257 "zonetab.list"
+ {gperf_offsetof(stringpool, 199),14400},
+#line 319 "zonetab.list"
+ {gperf_offsetof(stringpool, 200),32400},
+#line 84 "zonetab.list"
+ {gperf_offsetof(stringpool, 201), 2*3600},
+#line 286 "zonetab.list"
+ {gperf_offsetof(stringpool, 202),39600},
+#line 152 "zonetab.list"
+ {gperf_offsetof(stringpool, 203), 43200},
+#line 300 "zonetab.list"
+ {gperf_offsetof(stringpool, 204),46800},
+#line 127 "zonetab.list"
+ {gperf_offsetof(stringpool, 205), 28800},
+#line 299 "zonetab.list"
+ {gperf_offsetof(stringpool, 206),50400},
+#line 85 "zonetab.list"
+ {gperf_offsetof(stringpool, 207), -11*3600},
{-1},
-#line 317 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str211,-10800},
-#line 291 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str212,39600},
+#line 142 "zonetab.list"
+ {gperf_offsetof(stringpool, 209), 19800},
{-1},
-#line 199 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str214,-3600},
-#line 198 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str215,0},
-#line 296 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str216,-36000},
-#line 109 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str217, 12*3600},
-#line 131 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str218, -43200},
-#line 108 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str219,12*3600},
-#line 173 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str220, 32400},
+#line 314 "zonetab.list"
+ {gperf_offsetof(stringpool, 211),-10800},
+#line 288 "zonetab.list"
+ {gperf_offsetof(stringpool, 212),39600},
+ {-1},
+#line 196 "zonetab.list"
+ {gperf_offsetof(stringpool, 214),-3600},
+#line 195 "zonetab.list"
+ {gperf_offsetof(stringpool, 215),0},
+#line 293 "zonetab.list"
+ {gperf_offsetof(stringpool, 216),-36000},
+#line 106 "zonetab.list"
+ {gperf_offsetof(stringpool, 217), 12*3600},
#line 128 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str221, 39600},
+ {gperf_offsetof(stringpool, 218), -43200},
+#line 105 "zonetab.list"
+ {gperf_offsetof(stringpool, 219),12*3600},
+#line 170 "zonetab.list"
+ {gperf_offsetof(stringpool, 220), 32400},
+#line 125 "zonetab.list"
+ {gperf_offsetof(stringpool, 221), 39600},
{-1},
-#line 286 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str223,21600},
-#line 116 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str224, -14400},
-#line 265 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str225,39600},
+#line 283 "zonetab.list"
+ {gperf_offsetof(stringpool, 223),21600},
+#line 113 "zonetab.list"
+ {gperf_offsetof(stringpool, 224), -14400},
+#line 262 "zonetab.list"
+ {gperf_offsetof(stringpool, 225),39600},
{-1},
-#line 14 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str227, 0*3600},
-#line 304 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str228,10800},
-#line 318 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str229,43200},
-#line 294 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str230,-10800},
-#line 23 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str231, -7*3600},
-#line 251 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str232,39600},
+#line 11 "zonetab.list"
+ {gperf_offsetof(stringpool, 227), 0*3600},
+#line 301 "zonetab.list"
+ {gperf_offsetof(stringpool, 228),10800},
+#line 315 "zonetab.list"
+ {gperf_offsetof(stringpool, 229),43200},
+#line 291 "zonetab.list"
+ {gperf_offsetof(stringpool, 230),-10800},
+#line 20 "zonetab.list"
+ {gperf_offsetof(stringpool, 231), -7*3600},
+#line 248 "zonetab.list"
+ {gperf_offsetof(stringpool, 232),39600},
{-1},
-#line 55 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str234, -3*3600},
-#line 17 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str235, -4*3600},
+#line 52 "zonetab.list"
+ {gperf_offsetof(stringpool, 234), -3*3600},
+#line 14 "zonetab.list"
+ {gperf_offsetof(stringpool, 235), -4*3600},
{-1}, {-1},
-#line 280 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str238,18000},
-#line 191 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str239,21600},
-#line 323 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str240,28800},
- {-1},
+#line 277 "zonetab.list"
+ {gperf_offsetof(stringpool, 238),18000},
+#line 188 "zonetab.list"
+ {gperf_offsetof(stringpool, 239),21600},
#line 320 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str242,-7200},
-#line 63 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str243,-9*3600},
-#line 319 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str244,-3600},
+ {gperf_offsetof(stringpool, 240),28800},
{-1},
-#line 249 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str246,25200},
-#line 248 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str247,28800},
-#line 150 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str248, -7200},
-#line 21 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str249, -6*3600},
-#line 253 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str250,50400},
-#line 168 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str251, 28800},
-#line 19 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str252, -5*3600},
-#line 79 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str253, 1*3600},
+#line 317 "zonetab.list"
+ {gperf_offsetof(stringpool, 242),-10800},
+#line 60 "zonetab.list"
+ {gperf_offsetof(stringpool, 243),-9*3600},
+#line 316 "zonetab.list"
+ {gperf_offsetof(stringpool, 244),-7200},
{-1},
-#line 167 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str255, 25200},
-#line 44 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str256, -9*3600},
+#line 246 "zonetab.list"
+ {gperf_offsetof(stringpool, 246),25200},
+#line 245 "zonetab.list"
+ {gperf_offsetof(stringpool, 247),28800},
+#line 147 "zonetab.list"
+ {gperf_offsetof(stringpool, 248), -7200},
+#line 18 "zonetab.list"
+ {gperf_offsetof(stringpool, 249), -6*3600},
+#line 250 "zonetab.list"
+ {gperf_offsetof(stringpool, 250),50400},
+#line 165 "zonetab.list"
+ {gperf_offsetof(stringpool, 251), 28800},
+#line 16 "zonetab.list"
+ {gperf_offsetof(stringpool, 252), -5*3600},
+#line 76 "zonetab.list"
+ {gperf_offsetof(stringpool, 253), 1*3600},
{-1},
-#line 174 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str258, 46800},
-#line 214 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str259,-36000},
+#line 164 "zonetab.list"
+ {gperf_offsetof(stringpool, 255), 25200},
+#line 41 "zonetab.list"
+ {gperf_offsetof(stringpool, 256), -9*3600},
{-1},
-#line 311 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str261,-14400},
-#line 122 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str262, 14400},
-#line 126 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str263, 3600},
-#line 31 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str264, 8*3600},
-#line 127 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str265, 3600},
-#line 156 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str266, -12600},
-#line 113 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str267, 10800},
-#line 292 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str268,14400},
-#line 115 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str269, 10800},
-#line 114 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str270, 14400},
-#line 219 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str271,36000},
+#line 171 "zonetab.list"
+ {gperf_offsetof(stringpool, 258), 46800},
+#line 211 "zonetab.list"
+ {gperf_offsetof(stringpool, 259),-36000},
{-1},
-#line 314 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str273,21600},
-#line 69 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str274,-10*3600},
-#line 154 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str275, 20700},
-#line 270 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str276,-39600},
-#line 228 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str277,-14400},
+#line 308 "zonetab.list"
+ {gperf_offsetof(stringpool, 261),-14400},
+#line 119 "zonetab.list"
+ {gperf_offsetof(stringpool, 262), 14400},
+#line 123 "zonetab.list"
+ {gperf_offsetof(stringpool, 263), 3600},
+#line 28 "zonetab.list"
+ {gperf_offsetof(stringpool, 264), 8*3600},
+#line 124 "zonetab.list"
+ {gperf_offsetof(stringpool, 265), 3600},
+#line 153 "zonetab.list"
+ {gperf_offsetof(stringpool, 266), -12600},
+#line 110 "zonetab.list"
+ {gperf_offsetof(stringpool, 267), 10800},
+#line 289 "zonetab.list"
+ {gperf_offsetof(stringpool, 268),14400},
+#line 112 "zonetab.list"
+ {gperf_offsetof(stringpool, 269), 10800},
+#line 111 "zonetab.list"
+ {gperf_offsetof(stringpool, 270), 14400},
+#line 216 "zonetab.list"
+ {gperf_offsetof(stringpool, 271),36000},
{-1},
-#line 227 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str279,-10800},
-#line 70 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str280,-10*3600},
-#line 240 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str281,10800},
+#line 311 "zonetab.list"
+ {gperf_offsetof(stringpool, 273),21600},
+#line 66 "zonetab.list"
+ {gperf_offsetof(stringpool, 274),-10*3600},
+#line 151 "zonetab.list"
+ {gperf_offsetof(stringpool, 275), 20700},
+#line 267 "zonetab.list"
+ {gperf_offsetof(stringpool, 276),-39600},
+#line 225 "zonetab.list"
+ {gperf_offsetof(stringpool, 277),-14400},
+ {-1},
+#line 224 "zonetab.list"
+ {gperf_offsetof(stringpool, 279),-10800},
+#line 67 "zonetab.list"
+ {gperf_offsetof(stringpool, 280),-10*3600},
+#line 237 "zonetab.list"
+ {gperf_offsetof(stringpool, 281),10800},
{-1}, {-1},
-#line 300 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str284,32400},
-#line 178 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str285, 28800},
-#line 137 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str286, 7200},
-#line 152 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str287, 23400},
-#line 110 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str288,13*3600},
-#line 233 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str289,-10800},
-#line 310 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str290,18000},
+#line 297 "zonetab.list"
+ {gperf_offsetof(stringpool, 284),32400},
+#line 175 "zonetab.list"
+ {gperf_offsetof(stringpool, 285), 28800},
+#line 134 "zonetab.list"
+ {gperf_offsetof(stringpool, 286), 7200},
+#line 149 "zonetab.list"
+ {gperf_offsetof(stringpool, 287), 23400},
+#line 107 "zonetab.list"
+ {gperf_offsetof(stringpool, 288),13*3600},
+#line 230 "zonetab.list"
+ {gperf_offsetof(stringpool, 289),-10800},
+#line 307 "zonetab.list"
+ {gperf_offsetof(stringpool, 290),18000},
{-1}, {-1},
-#line 158 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str293, 25200},
+#line 155 "zonetab.list"
+ {gperf_offsetof(stringpool, 293), 25200},
+#line 258 "zonetab.list"
+ {gperf_offsetof(stringpool, 294),18000},
+#line 227 "zonetab.list"
+ {gperf_offsetof(stringpool, 295),-21600},
#line 261 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str294,18000},
-#line 230 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str295,-21600},
-#line 264 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str296,43200},
-#line 216 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str297,-3600},
+ {gperf_offsetof(stringpool, 296),43200},
+#line 213 "zonetab.list"
+ {gperf_offsetof(stringpool, 297),-3600},
+#line 154 "zonetab.list"
+ {gperf_offsetof(stringpool, 298), 28800},
+ {-1},
+#line 243 "zonetab.list"
+ {gperf_offsetof(stringpool, 300),21600},
+#line 114 "zonetab.list"
+ {gperf_offsetof(stringpool, 301), 34200},
#line 157 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str298, 28800},
+ {gperf_offsetof(stringpool, 302), -28800},
{-1},
-#line 246 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str300,21600},
#line 117 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str301, 34200},
-#line 160 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str302, -28800},
+ {gperf_offsetof(stringpool, 304), -21600},
{-1},
-#line 120 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str304, -21600},
- {-1},
-#line 159 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str306, -14400},
-#line 119 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str307, -3600},
-#line 231 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str308,-32400},
-#line 297 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str309,18000},
-#line 40 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str310, -5*3600},
-#line 140 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str311, 7200},
-#line 61 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str312,-8*3600},
-#line 307 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str313,28800},
-#line 306 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str314,32400},
-#line 287 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str315,14400},
+#line 156 "zonetab.list"
+ {gperf_offsetof(stringpool, 306), -14400},
+#line 116 "zonetab.list"
+ {gperf_offsetof(stringpool, 307), -3600},
+#line 228 "zonetab.list"
+ {gperf_offsetof(stringpool, 308),-32400},
+#line 294 "zonetab.list"
+ {gperf_offsetof(stringpool, 309),18000},
+#line 37 "zonetab.list"
+ {gperf_offsetof(stringpool, 310), -5*3600},
+#line 137 "zonetab.list"
+ {gperf_offsetof(stringpool, 311), 7200},
+#line 58 "zonetab.list"
+ {gperf_offsetof(stringpool, 312),-8*3600},
+#line 304 "zonetab.list"
+ {gperf_offsetof(stringpool, 313),28800},
+#line 303 "zonetab.list"
+ {gperf_offsetof(stringpool, 314),32400},
+#line 284 "zonetab.list"
+ {gperf_offsetof(stringpool, 315),14400},
{-1},
-#line 298 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str317,18000},
+#line 295 "zonetab.list"
+ {gperf_offsetof(stringpool, 317),18000},
{-1},
-#line 169 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str319, 7200},
+#line 166 "zonetab.list"
+ {gperf_offsetof(stringpool, 319), 7200},
{-1}, {-1}, {-1}, {-1},
-#line 100 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str324, 8*3600},
+#line 97 "zonetab.list"
+ {gperf_offsetof(stringpool, 324), 8*3600},
{-1},
-#line 53 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str326, -(1*3600+1800)},
-#line 288 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str327,-10800},
+#line 50 "zonetab.list"
+ {gperf_offsetof(stringpool, 326), -(1*3600+1800)},
+#line 285 "zonetab.list"
+ {gperf_offsetof(stringpool, 327),-10800},
{-1}, {-1},
-#line 290 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str330,14400},
+#line 287 "zonetab.list"
+ {gperf_offsetof(stringpool, 330),14400},
{-1},
-#line 172 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str332, 36000},
+#line 169 "zonetab.list"
+ {gperf_offsetof(stringpool, 332), 36000},
{-1},
-#line 238 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str334,25200},
-#line 237 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str335,28800},
- {-1}, {-1},
#line 235 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str338,-14400},
+ {gperf_offsetof(stringpool, 334),25200},
+#line 234 "zonetab.list"
+ {gperf_offsetof(stringpool, 335),28800},
+ {-1}, {-1},
+#line 232 "zonetab.list"
+ {gperf_offsetof(stringpool, 338),-14400},
{-1}, {-1}, {-1},
-#line 47 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str342, -12*3600},
-#line 64 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str343,-9*3600},
-#line 165 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str344, -14400},
-#line 144 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str345, -36000},
+#line 44 "zonetab.list"
+ {gperf_offsetof(stringpool, 342), -12*3600},
+#line 61 "zonetab.list"
+ {gperf_offsetof(stringpool, 343),-9*3600},
+#line 162 "zonetab.list"
+ {gperf_offsetof(stringpool, 344), -14400},
+#line 141 "zonetab.list"
+ {gperf_offsetof(stringpool, 345), -36000},
{-1},
-#line 309 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str347,-10800},
+#line 306 "zonetab.list"
+ {gperf_offsetof(stringpool, 347),-10800},
{-1},
-#line 308 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str349,-7200},
-#line 329 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str350,18000},
-#line 328 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str351,21600},
-#line 250 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str352,14400},
+#line 305 "zonetab.list"
+ {gperf_offsetof(stringpool, 349),-7200},
#line 326 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str353,32400},
+ {gperf_offsetof(stringpool, 350),18000},
#line 325 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str354,36000},
+ {gperf_offsetof(stringpool, 351),21600},
+#line 247 "zonetab.list"
+ {gperf_offsetof(stringpool, 352),14400},
+#line 323 "zonetab.list"
+ {gperf_offsetof(stringpool, 353),32400},
+#line 322 "zonetab.list"
+ {gperf_offsetof(stringpool, 354),36000},
{-1}, {-1}, {-1},
-#line 66 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str358, -9*3600},
-#line 147 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str359, 7200},
+#line 63 "zonetab.list"
+ {gperf_offsetof(stringpool, 358), -9*3600},
+#line 144 "zonetab.list"
+ {gperf_offsetof(stringpool, 359), 7200},
{-1}, {-1}, {-1}, {-1}, {-1},
-#line 170 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str365, 21600},
+#line 167 "zonetab.list"
+ {gperf_offsetof(stringpool, 365), 21600},
{-1},
-#line 183 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str367, 32400},
+#line 180 "zonetab.list"
+ {gperf_offsetof(stringpool, 367), 32400},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#line 321 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str375,25200},
+#line 318 "zonetab.list"
+ {gperf_offsetof(stringpool, 375),25200},
{-1},
-#line 118 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str377, 36000},
-#line 234 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str378,43200},
+#line 115 "zonetab.list"
+ {gperf_offsetof(stringpool, 377), 36000},
+#line 231 "zonetab.list"
+ {gperf_offsetof(stringpool, 378),43200},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#line 176 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str387, -25200},
+#line 173 "zonetab.list"
+ {gperf_offsetof(stringpool, 387), -25200},
{-1}, {-1}, {-1},
-#line 313 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str391,36000},
-#line 312 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str392,39600},
+#line 310 "zonetab.list"
+ {gperf_offsetof(stringpool, 391),36000},
+#line 309 "zonetab.list"
+ {gperf_offsetof(stringpool, 392),39600},
{-1}, {-1},
-#line 143 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str395, 7200},
+#line 140 "zonetab.list"
+ {gperf_offsetof(stringpool, 395), 7200},
{-1}, {-1},
-#line 171 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str398, 28800},
-#line 293 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str399,39600},
+#line 168 "zonetab.list"
+ {gperf_offsetof(stringpool, 398), 28800},
+#line 290 "zonetab.list"
+ {gperf_offsetof(stringpool, 399),39600},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#line 121 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str408, -3600},
+#line 118 "zonetab.list"
+ {gperf_offsetof(stringpool, 408), -3600},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#line 299 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str417,46800},
-#line 166 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str418, -39600},
+#line 296 "zonetab.list"
+ {gperf_offsetof(stringpool, 417),46800},
+#line 163 "zonetab.list"
+ {gperf_offsetof(stringpool, 418), -39600},
{-1}, {-1},
-#line 164 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str421, -18000},
+#line 161 "zonetab.list"
+ {gperf_offsetof(stringpool, 421), -18000},
{-1}, {-1}, {-1}, {-1}, {-1},
-#line 315 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str427,39600},
-#line 72 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str428,-12*3600},
+#line 312 "zonetab.list"
+ {gperf_offsetof(stringpool, 427),39600},
+#line 69 "zonetab.list"
+ {gperf_offsetof(stringpool, 428),-12*3600},
{-1}, {-1}, {-1},
-#line 139 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str432, 43200},
+#line 136 "zonetab.list"
+ {gperf_offsetof(stringpool, 432), 43200},
{-1}, {-1},
-#line 49 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str435, 0*3600},
+#line 46 "zonetab.list"
+ {gperf_offsetof(stringpool, 435), 0*3600},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#line 148 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str443, 32400},
+#line 145 "zonetab.list"
+ {gperf_offsetof(stringpool, 443), 32400},
{-1},
-#line 134 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str445, 7200},
+#line 131 "zonetab.list"
+ {gperf_offsetof(stringpool, 445), 7200},
{-1}, {-1}, {-1},
-#line 295 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str449,10800},
+#line 292 "zonetab.list"
+ {gperf_offsetof(stringpool, 449),10800},
{-1}, {-1},
-#line 153 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str452, 21600},
+#line 150 "zonetab.list"
+ {gperf_offsetof(stringpool, 452), 21600},
{-1}, {-1},
-#line 305 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str455,43200},
+#line 302 "zonetab.list"
+ {gperf_offsetof(stringpool, 455),43200},
{-1}, {-1},
-#line 179 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str458, 3600},
+#line 176 "zonetab.list"
+ {gperf_offsetof(stringpool, 458), 3600},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#line 138 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str466, 18000},
+#line 135 "zonetab.list"
+ {gperf_offsetof(stringpool, 466), 18000},
{-1},
-#line 177 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str468, 36000},
+#line 174 "zonetab.list"
+ {gperf_offsetof(stringpool, 468), 36000},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#line 327 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str476,36000},
-#line 175 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str477, -18000},
+#line 324 "zonetab.list"
+ {gperf_offsetof(stringpool, 476),36000},
+#line 172 "zonetab.list"
+ {gperf_offsetof(stringpool, 477), -18000},
{-1}, {-1}, {-1}, {-1},
-#line 163 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str482, -10800},
+#line 160 "zonetab.list"
+ {gperf_offsetof(stringpool, 482), -10800},
{-1}, {-1},
-#line 65 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str485, -9*3600},
-#line 162 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str486, 10800},
+#line 62 "zonetab.list"
+ {gperf_offsetof(stringpool, 485), -9*3600},
+#line 159 "zonetab.list"
+ {gperf_offsetof(stringpool, 486), 10800},
{-1}, {-1}, {-1}, {-1}, {-1},
-#line 236 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str492,28800},
+#line 233 "zonetab.list"
+ {gperf_offsetof(stringpool, 492),28800},
{-1}, {-1}, {-1}, {-1},
-#line 161 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str497, 3600},
+#line 158 "zonetab.list"
+ {gperf_offsetof(stringpool, 497), 3600},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#line 180 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str540, 3600},
+#line 177 "zonetab.list"
+ {gperf_offsetof(stringpool, 540), 3600},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1}, {-1},
-#line 62 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str563, -8*3600},
+#line 59 "zonetab.list"
+ {gperf_offsetof(stringpool, 563), -8*3600},
{-1}, {-1},
-#line 107 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str566,12*3600},
-#line 142 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str567, 0},
+#line 104 "zonetab.list"
+ {gperf_offsetof(stringpool, 566),12*3600},
+#line 139 "zonetab.list"
+ {gperf_offsetof(stringpool, 567), 0},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
{-1}, {-1}, {-1}, {-1}, {-1}, {-1},
-#line 141 "zonetab.list"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str619, -10800}
+#line 138 "zonetab.list"
+ {gperf_offsetof(stringpool, 619), -10800}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
@@ -1560,5 +1558,5 @@ zonetab (register const char *str, register size_t len)
}
return 0;
}
-#line 330 "zonetab.list"
+#line 327 "zonetab.list"
diff --git a/ext/date/zonetab.list b/ext/date/zonetab.list
index 63b6873447..748aec1d8a 100644
--- a/ext/date/zonetab.list
+++ b/ext/date/zonetab.list
@@ -1,7 +1,4 @@
%{
-#define GPERF_DOWNCASE 1
-#define GPERF_CASE_STRNCMP 1
-#define gperf_case_strncmp strncasecmp
struct zone {
int name;
int offset;
@@ -316,8 +313,8 @@ vut,39600
wakt,43200
warst,-10800
wft,43200
-wgst,-3600
-wgt,-7200
+wgst,-7200
+wgt,-10800
wib,25200
wit,32400
wita,28800
diff --git a/ext/digest/.document b/ext/digest/.document
deleted file mode 100644
index beab275b5a..0000000000
--- a/ext/digest/.document
+++ /dev/null
@@ -1,3 +0,0 @@
-digest.c
-bubblebabble/bubblebabble.c
-*/*init.c
diff --git a/ext/digest/bubblebabble/bubblebabble.c b/ext/digest/bubblebabble/bubblebabble.c
index dac603c0d7..358ab416b9 100644
--- a/ext/digest/bubblebabble/bubblebabble.c
+++ b/ext/digest/bubblebabble/bubblebabble.c
@@ -129,14 +129,15 @@ Init_bubblebabble(void)
rb_require("digest");
+ rb_mDigest = rb_path2class("Digest");
+ rb_mDigest_Instance = rb_path2class("Digest::Instance");
+ rb_cDigest_Class = rb_path2class("Digest::Class");
+
#if 0
rb_mDigest = rb_define_module("Digest");
rb_mDigest_Instance = rb_define_module_under(rb_mDigest, "Instance");
rb_cDigest_Class = rb_define_class_under(rb_mDigest, "Class", rb_cObject);
#endif
- rb_mDigest = rb_digest_namespace();
- rb_mDigest_Instance = rb_const_get(rb_mDigest, rb_intern_const("Instance"));
- rb_cDigest_Class = rb_const_get(rb_mDigest, rb_intern_const("Class"));
rb_define_module_function(rb_mDigest, "bubblebabble", rb_digest_s_bubblebabble, 1);
rb_define_singleton_method(rb_cDigest_Class, "bubblebabble", rb_digest_class_s_bubblebabble, -1);
diff --git a/ext/digest/bubblebabble/depend b/ext/digest/bubblebabble/depend
index 0da9c223ee..38f5ddb1e2 100644
--- a/ext/digest/bubblebabble/depend
+++ b/ext/digest/bubblebabble/depend
@@ -52,7 +52,6 @@ bubblebabble.o: $(hdrdir)/ruby/internal/attr/noexcept.h
bubblebabble.o: $(hdrdir)/ruby/internal/attr/noinline.h
bubblebabble.o: $(hdrdir)/ruby/internal/attr/nonnull.h
bubblebabble.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-bubblebabble.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
bubblebabble.o: $(hdrdir)/ruby/internal/attr/pure.h
bubblebabble.o: $(hdrdir)/ruby/internal/attr/restrict.h
bubblebabble.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ bubblebabble.o: $(hdrdir)/ruby/internal/intern/enumerator.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/error.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/eval.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/file.h
+bubblebabble.o: $(hdrdir)/ruby/internal/intern/gc.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/hash.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/io.h
bubblebabble.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ bubblebabble.o: $(hdrdir)/ruby/internal/memory.h
bubblebabble.o: $(hdrdir)/ruby/internal/method.h
bubblebabble.o: $(hdrdir)/ruby/internal/module.h
bubblebabble.o: $(hdrdir)/ruby/internal/newobj.h
+bubblebabble.o: $(hdrdir)/ruby/internal/rgengc.h
bubblebabble.o: $(hdrdir)/ruby/internal/scan_args.h
bubblebabble.o: $(hdrdir)/ruby/internal/special_consts.h
bubblebabble.o: $(hdrdir)/ruby/internal/static_assert.h
bubblebabble.o: $(hdrdir)/ruby/internal/stdalign.h
bubblebabble.o: $(hdrdir)/ruby/internal/stdbool.h
-bubblebabble.o: $(hdrdir)/ruby/internal/stdckdint.h
bubblebabble.o: $(hdrdir)/ruby/internal/symbol.h
bubblebabble.o: $(hdrdir)/ruby/internal/value.h
bubblebabble.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/digest/depend b/ext/digest/depend
index cb9e8d4813..5a84fd53ec 100644
--- a/ext/digest/depend
+++ b/ext/digest/depend
@@ -52,7 +52,6 @@ digest.o: $(hdrdir)/ruby/internal/attr/noexcept.h
digest.o: $(hdrdir)/ruby/internal/attr/noinline.h
digest.o: $(hdrdir)/ruby/internal/attr/nonnull.h
digest.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-digest.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
digest.o: $(hdrdir)/ruby/internal/attr/pure.h
digest.o: $(hdrdir)/ruby/internal/attr/restrict.h
digest.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ digest.o: $(hdrdir)/ruby/internal/intern/enumerator.h
digest.o: $(hdrdir)/ruby/internal/intern/error.h
digest.o: $(hdrdir)/ruby/internal/intern/eval.h
digest.o: $(hdrdir)/ruby/internal/intern/file.h
+digest.o: $(hdrdir)/ruby/internal/intern/gc.h
digest.o: $(hdrdir)/ruby/internal/intern/hash.h
digest.o: $(hdrdir)/ruby/internal/intern/io.h
digest.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ digest.o: $(hdrdir)/ruby/internal/memory.h
digest.o: $(hdrdir)/ruby/internal/method.h
digest.o: $(hdrdir)/ruby/internal/module.h
digest.o: $(hdrdir)/ruby/internal/newobj.h
+digest.o: $(hdrdir)/ruby/internal/rgengc.h
digest.o: $(hdrdir)/ruby/internal/scan_args.h
digest.o: $(hdrdir)/ruby/internal/special_consts.h
digest.o: $(hdrdir)/ruby/internal/static_assert.h
digest.o: $(hdrdir)/ruby/internal/stdalign.h
digest.o: $(hdrdir)/ruby/internal/stdbool.h
-digest.o: $(hdrdir)/ruby/internal/stdckdint.h
digest.o: $(hdrdir)/ruby/internal/symbol.h
digest.o: $(hdrdir)/ruby/internal/value.h
digest.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/digest/digest.c b/ext/digest/digest.c
index bd8d3e815f..68837a674c 100644
--- a/ext/digest/digest.c
+++ b/ext/digest/digest.c
@@ -534,39 +534,9 @@ rb_digest_class_init(VALUE self)
*
*
* rb_ivar_set(cDigest_SHA1, rb_intern("metadata"),
- * rb_digest_make_metadata(&sha1));
+ * Data_Wrap_Struct(0, 0, 0, (void *)&sha1));
*/
-#ifdef DIGEST_USE_RB_EXT_RESOLVE_SYMBOL
-static const rb_data_type_t metadata_type = {
- "digest/metadata",
- {0},
-};
-
-RUBY_FUNC_EXPORTED VALUE
-rb_digest_wrap_metadata(const rb_digest_metadata_t *meta)
-{
- return rb_obj_freeze(TypedData_Wrap_Struct(0, &metadata_type, (void *)meta));
-}
-#endif
-
-static rb_digest_metadata_t *
-get_metadata_ptr(VALUE obj)
-{
- rb_digest_metadata_t *algo;
-
-#ifdef DIGEST_USE_RB_EXT_RESOLVE_SYMBOL
- if (!rb_typeddata_is_kind_of(obj, &metadata_type)) return 0;
- algo = RTYPEDDATA_DATA(obj);
-#else
-# undef RUBY_UNTYPED_DATA_WARNING
-# define RUBY_UNTYPED_DATA_WARNING 0
- Data_Get_Struct(obj, rb_digest_metadata_t, algo);
-#endif
-
- return algo;
-}
-
static rb_digest_metadata_t *
get_digest_base_metadata(VALUE klass)
{
@@ -584,8 +554,8 @@ get_digest_base_metadata(VALUE klass)
if (NIL_P(p))
rb_raise(rb_eRuntimeError, "Digest::Base cannot be directly inherited in Ruby");
- algo = get_metadata_ptr(obj);
- if (!algo) {
+ if (!RB_TYPE_P(obj, T_DATA) || RTYPEDDATA_P(obj)) {
+ wrong:
if (p == klass)
rb_raise(rb_eTypeError, "%"PRIsVALUE"::metadata is not initialized properly",
klass);
@@ -594,6 +564,12 @@ get_digest_base_metadata(VALUE klass)
klass, p);
}
+#undef RUBY_UNTYPED_DATA_WARNING
+#define RUBY_UNTYPED_DATA_WARNING 0
+ Data_Get_Struct(obj, rb_digest_metadata_t, algo);
+
+ if (!algo) goto wrong;
+
switch (algo->api_version) {
case 3:
break;
diff --git a/ext/digest/digest.h b/ext/digest/digest.h
index 4503929bab..8a4c5b7e4e 100644
--- a/ext/digest/digest.h
+++ b/ext/digest/digest.h
@@ -40,8 +40,7 @@ rb_digest_##name##_update(void *ctx, unsigned char *ptr, size_t size) \
for (; size > stride; size -= stride, ptr += stride) { \
name##_Update(ctx, ptr, stride); \
} \
- /* Since size <= stride, size should fit into an unsigned int */ \
- if (size > 0) name##_Update(ctx, ptr, (unsigned int)size); \
+ if (size > 0) name##_Update(ctx, ptr, size); \
}
#define DEFINE_FINISH_FUNC_FROM_FINAL(name) \
@@ -64,29 +63,10 @@ rb_id_metadata(void)
return rb_intern_const("metadata");
}
-#if !defined(HAVE_RB_EXT_RESOLVE_SYMBOL)
-#elif !defined(RUBY_UNTYPED_DATA_WARNING)
-# error RUBY_UNTYPED_DATA_WARNING is not defined
-#elif RUBY_UNTYPED_DATA_WARNING
-/* rb_ext_resolve_symbol() has been defined since Ruby 3.3, but digest
- * bundled with 3.3 didn't use it. */
-# define DIGEST_USE_RB_EXT_RESOLVE_SYMBOL 1
-#endif
-
static inline VALUE
rb_digest_make_metadata(const rb_digest_metadata_t *meta)
{
-#ifdef DIGEST_USE_RB_EXT_RESOLVE_SYMBOL
- typedef VALUE (*wrapper_func_type)(const rb_digest_metadata_t *meta);
- static wrapper_func_type wrapper;
- if (!wrapper) {
- wrapper = (wrapper_func_type)rb_ext_resolve_symbol("digest.so", "rb_digest_wrap_metadata");
- if (!wrapper) rb_raise(rb_eLoadError, "rb_digest_wrap_metadata not found");
- }
- return wrapper(meta);
-#else
#undef RUBY_UNTYPED_DATA_WARNING
#define RUBY_UNTYPED_DATA_WARNING 0
return rb_obj_freeze(Data_Wrap_Struct(0, 0, 0, (void *)meta));
-#endif
}
diff --git a/ext/digest/md5/depend b/ext/digest/md5/depend
index e71915e5b4..ea1ceec7fd 100644
--- a/ext/digest/md5/depend
+++ b/ext/digest/md5/depend
@@ -55,7 +55,6 @@ md5.o: $(hdrdir)/ruby/internal/attr/noexcept.h
md5.o: $(hdrdir)/ruby/internal/attr/noinline.h
md5.o: $(hdrdir)/ruby/internal/attr/nonnull.h
md5.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-md5.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
md5.o: $(hdrdir)/ruby/internal/attr/pure.h
md5.o: $(hdrdir)/ruby/internal/attr/restrict.h
md5.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -115,6 +114,7 @@ md5.o: $(hdrdir)/ruby/internal/intern/enumerator.h
md5.o: $(hdrdir)/ruby/internal/intern/error.h
md5.o: $(hdrdir)/ruby/internal/intern/eval.h
md5.o: $(hdrdir)/ruby/internal/intern/file.h
+md5.o: $(hdrdir)/ruby/internal/intern/gc.h
md5.o: $(hdrdir)/ruby/internal/intern/hash.h
md5.o: $(hdrdir)/ruby/internal/intern/io.h
md5.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -145,12 +145,12 @@ md5.o: $(hdrdir)/ruby/internal/memory.h
md5.o: $(hdrdir)/ruby/internal/method.h
md5.o: $(hdrdir)/ruby/internal/module.h
md5.o: $(hdrdir)/ruby/internal/newobj.h
+md5.o: $(hdrdir)/ruby/internal/rgengc.h
md5.o: $(hdrdir)/ruby/internal/scan_args.h
md5.o: $(hdrdir)/ruby/internal/special_consts.h
md5.o: $(hdrdir)/ruby/internal/static_assert.h
md5.o: $(hdrdir)/ruby/internal/stdalign.h
md5.o: $(hdrdir)/ruby/internal/stdbool.h
-md5.o: $(hdrdir)/ruby/internal/stdckdint.h
md5.o: $(hdrdir)/ruby/internal/symbol.h
md5.o: $(hdrdir)/ruby/internal/value.h
md5.o: $(hdrdir)/ruby/internal/value_type.h
@@ -217,7 +217,6 @@ md5init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
md5init.o: $(hdrdir)/ruby/internal/attr/noinline.h
md5init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
md5init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-md5init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
md5init.o: $(hdrdir)/ruby/internal/attr/pure.h
md5init.o: $(hdrdir)/ruby/internal/attr/restrict.h
md5init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -277,6 +276,7 @@ md5init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
md5init.o: $(hdrdir)/ruby/internal/intern/error.h
md5init.o: $(hdrdir)/ruby/internal/intern/eval.h
md5init.o: $(hdrdir)/ruby/internal/intern/file.h
+md5init.o: $(hdrdir)/ruby/internal/intern/gc.h
md5init.o: $(hdrdir)/ruby/internal/intern/hash.h
md5init.o: $(hdrdir)/ruby/internal/intern/io.h
md5init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -307,12 +307,12 @@ md5init.o: $(hdrdir)/ruby/internal/memory.h
md5init.o: $(hdrdir)/ruby/internal/method.h
md5init.o: $(hdrdir)/ruby/internal/module.h
md5init.o: $(hdrdir)/ruby/internal/newobj.h
+md5init.o: $(hdrdir)/ruby/internal/rgengc.h
md5init.o: $(hdrdir)/ruby/internal/scan_args.h
md5init.o: $(hdrdir)/ruby/internal/special_consts.h
md5init.o: $(hdrdir)/ruby/internal/static_assert.h
md5init.o: $(hdrdir)/ruby/internal/stdalign.h
md5init.o: $(hdrdir)/ruby/internal/stdbool.h
-md5init.o: $(hdrdir)/ruby/internal/stdckdint.h
md5init.o: $(hdrdir)/ruby/internal/symbol.h
md5init.o: $(hdrdir)/ruby/internal/value.h
md5init.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/digest/md5/md5cc.h b/ext/digest/md5/md5cc.h
index 657f573f85..e34d7d5c11 100644
--- a/ext/digest/md5/md5cc.h
+++ b/ext/digest/md5/md5cc.h
@@ -1,16 +1,8 @@
#define COMMON_DIGEST_FOR_OPENSSL 1
#include <CommonCrypto/CommonDigest.h>
-#ifdef __GNUC__
-# define RB_DIGEST_DIAGNOSTIC(compiler, op, flag) _Pragma(STRINGIZE(compiler diagnostic op flag))
-# ifdef RBIMPL_WARNING_IGNORED
-# define RB_DIGEST_WARNING_IGNORED(flag) RBIMPL_WARNING_IGNORED(flag)
-# elif defined(__clang__)
-# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(clang, ignored, #flag)
-# else /* __GNUC__ */
-# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(GCC, ignored, #flag)
-# endif
-RB_DIGEST_WARNING_IGNORED(-Wdeprecated-declarations)
+#ifdef __clang__
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
/* Suppress deprecation warnings of MD5 from Xcode 11.1 */
/* Although we know MD5 is deprecated too, provide just for backward
* compatibility, as well as Apple does. */
@@ -25,11 +17,3 @@ static DEFINE_FINISH_FUNC_FROM_FINAL(MD5)
#undef MD5_Finish
#define MD5_Update rb_digest_MD5_update
#define MD5_Finish rb_digest_MD5_finish
-
-/*
- * Pre-10.6 defines are with args, which don't match the argless use in
- * the function pointer inits. Thus, we redefine MD5_Init as well.
- * This is a NOP on 10.6+.
- */
-#undef MD5_Init
-#define MD5_Init CC_MD5_Init
diff --git a/ext/digest/md5/md5init.c b/ext/digest/md5/md5init.c
index b81fd94864..52cba78bf1 100644
--- a/ext/digest/md5/md5init.c
+++ b/ext/digest/md5/md5init.c
@@ -53,8 +53,9 @@ Init_md5(void)
mDigest = rb_define_module("Digest"); /* let rdoc know */
#endif
mDigest = rb_digest_namespace();
- cDigest_Base = rb_const_get(mDigest, rb_intern_const("Base"));
+ cDigest_Base = rb_path2class("Digest::Base");
cDigest_MD5 = rb_define_class_under(mDigest, "MD5", cDigest_Base);
+
rb_iv_set(cDigest_MD5, "metadata", rb_digest_make_metadata(&md5));
}
diff --git a/ext/digest/rmd160/depend b/ext/digest/rmd160/depend
index 09558ad92b..3a0ed72732 100644
--- a/ext/digest/rmd160/depend
+++ b/ext/digest/rmd160/depend
@@ -55,7 +55,6 @@ rmd160.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rmd160.o: $(hdrdir)/ruby/internal/attr/noinline.h
rmd160.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rmd160.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rmd160.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rmd160.o: $(hdrdir)/ruby/internal/attr/pure.h
rmd160.o: $(hdrdir)/ruby/internal/attr/restrict.h
rmd160.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -115,6 +114,7 @@ rmd160.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rmd160.o: $(hdrdir)/ruby/internal/intern/error.h
rmd160.o: $(hdrdir)/ruby/internal/intern/eval.h
rmd160.o: $(hdrdir)/ruby/internal/intern/file.h
+rmd160.o: $(hdrdir)/ruby/internal/intern/gc.h
rmd160.o: $(hdrdir)/ruby/internal/intern/hash.h
rmd160.o: $(hdrdir)/ruby/internal/intern/io.h
rmd160.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -145,12 +145,12 @@ rmd160.o: $(hdrdir)/ruby/internal/memory.h
rmd160.o: $(hdrdir)/ruby/internal/method.h
rmd160.o: $(hdrdir)/ruby/internal/module.h
rmd160.o: $(hdrdir)/ruby/internal/newobj.h
+rmd160.o: $(hdrdir)/ruby/internal/rgengc.h
rmd160.o: $(hdrdir)/ruby/internal/scan_args.h
rmd160.o: $(hdrdir)/ruby/internal/special_consts.h
rmd160.o: $(hdrdir)/ruby/internal/static_assert.h
rmd160.o: $(hdrdir)/ruby/internal/stdalign.h
rmd160.o: $(hdrdir)/ruby/internal/stdbool.h
-rmd160.o: $(hdrdir)/ruby/internal/stdckdint.h
rmd160.o: $(hdrdir)/ruby/internal/symbol.h
rmd160.o: $(hdrdir)/ruby/internal/value.h
rmd160.o: $(hdrdir)/ruby/internal/value_type.h
@@ -217,7 +217,6 @@ rmd160init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
rmd160init.o: $(hdrdir)/ruby/internal/attr/noinline.h
rmd160init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
rmd160init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-rmd160init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
rmd160init.o: $(hdrdir)/ruby/internal/attr/pure.h
rmd160init.o: $(hdrdir)/ruby/internal/attr/restrict.h
rmd160init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -277,6 +276,7 @@ rmd160init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/error.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/eval.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/file.h
+rmd160init.o: $(hdrdir)/ruby/internal/intern/gc.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/hash.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/io.h
rmd160init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -307,12 +307,12 @@ rmd160init.o: $(hdrdir)/ruby/internal/memory.h
rmd160init.o: $(hdrdir)/ruby/internal/method.h
rmd160init.o: $(hdrdir)/ruby/internal/module.h
rmd160init.o: $(hdrdir)/ruby/internal/newobj.h
+rmd160init.o: $(hdrdir)/ruby/internal/rgengc.h
rmd160init.o: $(hdrdir)/ruby/internal/scan_args.h
rmd160init.o: $(hdrdir)/ruby/internal/special_consts.h
rmd160init.o: $(hdrdir)/ruby/internal/static_assert.h
rmd160init.o: $(hdrdir)/ruby/internal/stdalign.h
rmd160init.o: $(hdrdir)/ruby/internal/stdbool.h
-rmd160init.o: $(hdrdir)/ruby/internal/stdckdint.h
rmd160init.o: $(hdrdir)/ruby/internal/symbol.h
rmd160init.o: $(hdrdir)/ruby/internal/value.h
rmd160init.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/digest/rmd160/rmd160init.c b/ext/digest/rmd160/rmd160init.c
index e4b707ed9e..2ae81ec4d6 100644
--- a/ext/digest/rmd160/rmd160init.c
+++ b/ext/digest/rmd160/rmd160init.c
@@ -49,8 +49,9 @@ Init_rmd160(void)
mDigest = rb_define_module("Digest"); /* let rdoc know */
#endif
mDigest = rb_digest_namespace();
- cDigest_Base = rb_const_get(mDigest, rb_intern_const("Base"));
+ cDigest_Base = rb_path2class("Digest::Base");
cDigest_RMD160 = rb_define_class_under(mDigest, "RMD160", cDigest_Base);
+
rb_iv_set(cDigest_RMD160, "metadata", rb_digest_make_metadata(&rmd160));
}
diff --git a/ext/digest/sha1/depend b/ext/digest/sha1/depend
index 827b8a0852..48aaef158b 100644
--- a/ext/digest/sha1/depend
+++ b/ext/digest/sha1/depend
@@ -55,7 +55,6 @@ sha1.o: $(hdrdir)/ruby/internal/attr/noexcept.h
sha1.o: $(hdrdir)/ruby/internal/attr/noinline.h
sha1.o: $(hdrdir)/ruby/internal/attr/nonnull.h
sha1.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-sha1.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
sha1.o: $(hdrdir)/ruby/internal/attr/pure.h
sha1.o: $(hdrdir)/ruby/internal/attr/restrict.h
sha1.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -115,6 +114,7 @@ sha1.o: $(hdrdir)/ruby/internal/intern/enumerator.h
sha1.o: $(hdrdir)/ruby/internal/intern/error.h
sha1.o: $(hdrdir)/ruby/internal/intern/eval.h
sha1.o: $(hdrdir)/ruby/internal/intern/file.h
+sha1.o: $(hdrdir)/ruby/internal/intern/gc.h
sha1.o: $(hdrdir)/ruby/internal/intern/hash.h
sha1.o: $(hdrdir)/ruby/internal/intern/io.h
sha1.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -145,12 +145,12 @@ sha1.o: $(hdrdir)/ruby/internal/memory.h
sha1.o: $(hdrdir)/ruby/internal/method.h
sha1.o: $(hdrdir)/ruby/internal/module.h
sha1.o: $(hdrdir)/ruby/internal/newobj.h
+sha1.o: $(hdrdir)/ruby/internal/rgengc.h
sha1.o: $(hdrdir)/ruby/internal/scan_args.h
sha1.o: $(hdrdir)/ruby/internal/special_consts.h
sha1.o: $(hdrdir)/ruby/internal/static_assert.h
sha1.o: $(hdrdir)/ruby/internal/stdalign.h
sha1.o: $(hdrdir)/ruby/internal/stdbool.h
-sha1.o: $(hdrdir)/ruby/internal/stdckdint.h
sha1.o: $(hdrdir)/ruby/internal/symbol.h
sha1.o: $(hdrdir)/ruby/internal/value.h
sha1.o: $(hdrdir)/ruby/internal/value_type.h
@@ -217,7 +217,6 @@ sha1init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
sha1init.o: $(hdrdir)/ruby/internal/attr/noinline.h
sha1init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
sha1init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-sha1init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
sha1init.o: $(hdrdir)/ruby/internal/attr/pure.h
sha1init.o: $(hdrdir)/ruby/internal/attr/restrict.h
sha1init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -277,6 +276,7 @@ sha1init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
sha1init.o: $(hdrdir)/ruby/internal/intern/error.h
sha1init.o: $(hdrdir)/ruby/internal/intern/eval.h
sha1init.o: $(hdrdir)/ruby/internal/intern/file.h
+sha1init.o: $(hdrdir)/ruby/internal/intern/gc.h
sha1init.o: $(hdrdir)/ruby/internal/intern/hash.h
sha1init.o: $(hdrdir)/ruby/internal/intern/io.h
sha1init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -307,12 +307,12 @@ sha1init.o: $(hdrdir)/ruby/internal/memory.h
sha1init.o: $(hdrdir)/ruby/internal/method.h
sha1init.o: $(hdrdir)/ruby/internal/module.h
sha1init.o: $(hdrdir)/ruby/internal/newobj.h
+sha1init.o: $(hdrdir)/ruby/internal/rgengc.h
sha1init.o: $(hdrdir)/ruby/internal/scan_args.h
sha1init.o: $(hdrdir)/ruby/internal/special_consts.h
sha1init.o: $(hdrdir)/ruby/internal/static_assert.h
sha1init.o: $(hdrdir)/ruby/internal/stdalign.h
sha1init.o: $(hdrdir)/ruby/internal/stdbool.h
-sha1init.o: $(hdrdir)/ruby/internal/stdckdint.h
sha1init.o: $(hdrdir)/ruby/internal/symbol.h
sha1init.o: $(hdrdir)/ruby/internal/value.h
sha1init.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/digest/sha1/sha1cc.h b/ext/digest/sha1/sha1cc.h
index f39ecc6234..2ed8d646ab 100644
--- a/ext/digest/sha1/sha1cc.h
+++ b/ext/digest/sha1/sha1cc.h
@@ -12,11 +12,3 @@ static DEFINE_FINISH_FUNC_FROM_FINAL(SHA1)
#undef SHA1_Finish
#define SHA1_Update rb_digest_SHA1_update
#define SHA1_Finish rb_digest_SHA1_finish
-
-/*
- * Pre-10.6 defines are with args, which don't match the argless use in
- * the function pointer inits. Thus, we redefine SHA1_Init as well.
- * This is a NOP on 10.6+.
- */
-#undef SHA1_Init
-#define SHA1_Init CC_SHA1_Init
diff --git a/ext/digest/sha1/sha1init.c b/ext/digest/sha1/sha1init.c
index c39959f428..f7047bc6d3 100644
--- a/ext/digest/sha1/sha1init.c
+++ b/ext/digest/sha1/sha1init.c
@@ -55,8 +55,9 @@ Init_sha1(void)
mDigest = rb_define_module("Digest"); /* let rdoc know */
#endif
mDigest = rb_digest_namespace();
- cDigest_Base = rb_const_get(mDigest, rb_intern_const("Base"));
+ cDigest_Base = rb_path2class("Digest::Base");
cDigest_SHA1 = rb_define_class_under(mDigest, "SHA1", cDigest_Base);
+
rb_iv_set(cDigest_SHA1, "metadata", rb_digest_make_metadata(&sha1));
}
diff --git a/ext/digest/sha2/depend b/ext/digest/sha2/depend
index af1600d346..47a859068c 100644
--- a/ext/digest/sha2/depend
+++ b/ext/digest/sha2/depend
@@ -55,7 +55,6 @@ sha2.o: $(hdrdir)/ruby/internal/attr/noexcept.h
sha2.o: $(hdrdir)/ruby/internal/attr/noinline.h
sha2.o: $(hdrdir)/ruby/internal/attr/nonnull.h
sha2.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-sha2.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
sha2.o: $(hdrdir)/ruby/internal/attr/pure.h
sha2.o: $(hdrdir)/ruby/internal/attr/restrict.h
sha2.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -115,6 +114,7 @@ sha2.o: $(hdrdir)/ruby/internal/intern/enumerator.h
sha2.o: $(hdrdir)/ruby/internal/intern/error.h
sha2.o: $(hdrdir)/ruby/internal/intern/eval.h
sha2.o: $(hdrdir)/ruby/internal/intern/file.h
+sha2.o: $(hdrdir)/ruby/internal/intern/gc.h
sha2.o: $(hdrdir)/ruby/internal/intern/hash.h
sha2.o: $(hdrdir)/ruby/internal/intern/io.h
sha2.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -145,12 +145,12 @@ sha2.o: $(hdrdir)/ruby/internal/memory.h
sha2.o: $(hdrdir)/ruby/internal/method.h
sha2.o: $(hdrdir)/ruby/internal/module.h
sha2.o: $(hdrdir)/ruby/internal/newobj.h
+sha2.o: $(hdrdir)/ruby/internal/rgengc.h
sha2.o: $(hdrdir)/ruby/internal/scan_args.h
sha2.o: $(hdrdir)/ruby/internal/special_consts.h
sha2.o: $(hdrdir)/ruby/internal/static_assert.h
sha2.o: $(hdrdir)/ruby/internal/stdalign.h
sha2.o: $(hdrdir)/ruby/internal/stdbool.h
-sha2.o: $(hdrdir)/ruby/internal/stdckdint.h
sha2.o: $(hdrdir)/ruby/internal/symbol.h
sha2.o: $(hdrdir)/ruby/internal/value.h
sha2.o: $(hdrdir)/ruby/internal/value_type.h
@@ -217,7 +217,6 @@ sha2init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
sha2init.o: $(hdrdir)/ruby/internal/attr/noinline.h
sha2init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
sha2init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-sha2init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
sha2init.o: $(hdrdir)/ruby/internal/attr/pure.h
sha2init.o: $(hdrdir)/ruby/internal/attr/restrict.h
sha2init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -277,6 +276,7 @@ sha2init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
sha2init.o: $(hdrdir)/ruby/internal/intern/error.h
sha2init.o: $(hdrdir)/ruby/internal/intern/eval.h
sha2init.o: $(hdrdir)/ruby/internal/intern/file.h
+sha2init.o: $(hdrdir)/ruby/internal/intern/gc.h
sha2init.o: $(hdrdir)/ruby/internal/intern/hash.h
sha2init.o: $(hdrdir)/ruby/internal/intern/io.h
sha2init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -307,12 +307,12 @@ sha2init.o: $(hdrdir)/ruby/internal/memory.h
sha2init.o: $(hdrdir)/ruby/internal/method.h
sha2init.o: $(hdrdir)/ruby/internal/module.h
sha2init.o: $(hdrdir)/ruby/internal/newobj.h
+sha2init.o: $(hdrdir)/ruby/internal/rgengc.h
sha2init.o: $(hdrdir)/ruby/internal/scan_args.h
sha2init.o: $(hdrdir)/ruby/internal/special_consts.h
sha2init.o: $(hdrdir)/ruby/internal/static_assert.h
sha2init.o: $(hdrdir)/ruby/internal/stdalign.h
sha2init.o: $(hdrdir)/ruby/internal/stdbool.h
-sha2init.o: $(hdrdir)/ruby/internal/stdckdint.h
sha2init.o: $(hdrdir)/ruby/internal/symbol.h
sha2init.o: $(hdrdir)/ruby/internal/value.h
sha2init.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/digest/sha2/sha2cc.h b/ext/digest/sha2/sha2cc.h
index 1245a2e2c7..3f99604465 100644
--- a/ext/digest/sha2/sha2cc.h
+++ b/ext/digest/sha2/sha2cc.h
@@ -1,33 +1,6 @@
#define COMMON_DIGEST_FOR_OPENSSL 1
#include <CommonCrypto/CommonDigest.h>
-/*
- * Prior to 10.5, OpenSSL-compatible definitions are missing for
- * SHA2 macros, though the CC_ versions are present.
- * Add the missing definitions we actually use here if needed.
- * Note that the definitions are the argless 10.6+-style.
- * The weird CTX mismatch is copied from the 10.6 header.
- */
-#ifndef SHA256_DIGEST_LENGTH
-#define SHA256_DIGEST_LENGTH CC_SHA256_DIGEST_LENGTH
-#define SHA256_CTX CC_SHA256_CTX
-#define SHA256_Update CC_SHA256_Update
-#define SHA256_Final CC_SHA256_Final
-#endif /* !defined SHA256_DIGEST_LENGTH */
-
-#ifndef SHA384_DIGEST_LENGTH
-#define SHA384_DIGEST_LENGTH CC_SHA384_DIGEST_LENGTH
-#define SHA512_CTX CC_SHA512_CTX
-#define SHA384_Update CC_SHA384_Update
-#define SHA384_Final CC_SHA384_Final
-#endif /* !defined SHA384_DIGEST_LENGTH */
-
-#ifndef SHA512_DIGEST_LENGTH
-#define SHA512_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH
-#define SHA512_Update CC_SHA512_Update
-#define SHA512_Final CC_SHA512_Final
-#endif /* !defined SHA512_DIGEST_LENGTH */
-
#define SHA256_BLOCK_LENGTH CC_SHA256_BLOCK_BYTES
#define SHA384_BLOCK_LENGTH CC_SHA384_BLOCK_BYTES
#define SHA512_BLOCK_LENGTH CC_SHA512_BLOCK_BYTES
@@ -56,15 +29,3 @@ static DEFINE_FINISH_FUNC_FROM_FINAL(SHA512)
#undef SHA512_Finish
#define SHA512_Update rb_digest_SHA512_update
#define SHA512_Finish rb_digest_SHA512_finish
-
-/*
- * Pre-10.6 defines are with args, which don't match the argless use in
- * the function pointer inits. Thus, we redefine SHA*_Init as well.
- * This is a NOP on 10.6+.
- */
-#undef SHA256_Init
-#define SHA256_Init CC_SHA256_Init
-#undef SHA384_Init
-#define SHA384_Init CC_SHA384_Init
-#undef SHA512_Init
-#define SHA512_Init CC_SHA512_Init
diff --git a/ext/digest/sha2/sha2init.c b/ext/digest/sha2/sha2init.c
index 3923e3724c..94cccf3feb 100644
--- a/ext/digest/sha2/sha2init.c
+++ b/ext/digest/sha2/sha2init.c
@@ -25,50 +25,29 @@ static const rb_digest_metadata_t sha##bitlen = { \
FOREACH_BITLEN(DEFINE_ALGO_METADATA)
/*
- * Document-class: Digest::SHA256 < Digest::Base
- *
* Classes for calculating message digests using the SHA-256/384/512
* Secure Hash Algorithm(s) by NIST (the US' National Institute of
* Standards and Technology), described in FIPS PUB 180-2.
- *
- * See SHA2.
- */
-/*
- * Document-class: Digest::SHA384 < Digest::Base
- *
- * Classes for calculating message digests using the SHA-256/384/512
- * Secure Hash Algorithm(s) by NIST (the US' National Institute of
- * Standards and Technology), described in FIPS PUB 180-2.
- *
- * See SHA2.
- */
-/*
- * Document-class: Digest::SHA512 < Digest::Base
- *
- * Classes for calculating message digests using the SHA-256/384/512
- * Secure Hash Algorithm(s) by NIST (the US' National Institute of
- * Standards and Technology), described in FIPS PUB 180-2.
- *
- * See SHA2.
*/
void
Init_sha2(void)
{
- VALUE mDigest, cDigest_Base, cDigest_SHA2;
+ VALUE mDigest, cDigest_Base;
ID id_metadata = rb_id_metadata();
-#if 0
- mDigest = rb_define_module("Digest"); /* let rdoc know */
-#endif
- mDigest = rb_digest_namespace();
- cDigest_Base = rb_const_get(mDigest, rb_intern_const("Base"));
+#define DECLARE_ALGO_CLASS(bitlen) \
+ VALUE cDigest_SHA##bitlen;
+
+ FOREACH_BITLEN(DECLARE_ALGO_CLASS)
- cDigest_SHA2 = rb_define_class_under(mDigest, "SHA256", cDigest_Base);
- rb_ivar_set(cDigest_SHA2, id_metadata, rb_digest_make_metadata(&sha256));
+ mDigest = rb_digest_namespace();
+ cDigest_Base = rb_path2class("Digest::Base");
- cDigest_SHA2 = rb_define_class_under(mDigest, "SHA384", cDigest_Base);
- rb_ivar_set(cDigest_SHA2, id_metadata, rb_digest_make_metadata(&sha384));
+#define DEFINE_ALGO_CLASS(bitlen) \
+ cDigest_SHA##bitlen = rb_define_class_under(mDigest, "SHA" #bitlen, cDigest_Base); \
+\
+ rb_ivar_set(cDigest_SHA##bitlen, id_metadata, \
+ rb_digest_make_metadata(&sha##bitlen));
- cDigest_SHA2 = rb_define_class_under(mDigest, "SHA512", cDigest_Base);
- rb_ivar_set(cDigest_SHA2, id_metadata, rb_digest_make_metadata(&sha512));
+ FOREACH_BITLEN(DEFINE_ALGO_CLASS)
}
diff --git a/ext/erb/escape/extconf.rb b/ext/erb/escape/extconf.rb
index 783e8c1f55..c1002548ad 100644
--- a/ext/erb/escape/extconf.rb
+++ b/ext/erb/escape/extconf.rb
@@ -1,7 +1,6 @@
require 'mkmf'
-case RUBY_ENGINE
-when 'jruby', 'truffleruby'
+if RUBY_ENGINE == 'truffleruby'
File.write('Makefile', dummy_makefile($srcdir).join)
else
create_makefile 'erb/escape'
diff --git a/ext/etc/.document b/ext/etc/.document
deleted file mode 100644
index 9bbea23b92..0000000000
--- a/ext/etc/.document
+++ /dev/null
@@ -1,2 +0,0 @@
-etc.c
-constdefs.h
diff --git a/ext/etc/depend b/ext/etc/depend
index 675699b129..a541db6db6 100644
--- a/ext/etc/depend
+++ b/ext/etc/depend
@@ -58,7 +58,6 @@ etc.o: $(hdrdir)/ruby/internal/attr/noexcept.h
etc.o: $(hdrdir)/ruby/internal/attr/noinline.h
etc.o: $(hdrdir)/ruby/internal/attr/nonnull.h
etc.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-etc.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
etc.o: $(hdrdir)/ruby/internal/attr/pure.h
etc.o: $(hdrdir)/ruby/internal/attr/restrict.h
etc.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -127,6 +126,7 @@ etc.o: $(hdrdir)/ruby/internal/intern/enumerator.h
etc.o: $(hdrdir)/ruby/internal/intern/error.h
etc.o: $(hdrdir)/ruby/internal/intern/eval.h
etc.o: $(hdrdir)/ruby/internal/intern/file.h
+etc.o: $(hdrdir)/ruby/internal/intern/gc.h
etc.o: $(hdrdir)/ruby/internal/intern/hash.h
etc.o: $(hdrdir)/ruby/internal/intern/io.h
etc.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -157,12 +157,12 @@ etc.o: $(hdrdir)/ruby/internal/memory.h
etc.o: $(hdrdir)/ruby/internal/method.h
etc.o: $(hdrdir)/ruby/internal/module.h
etc.o: $(hdrdir)/ruby/internal/newobj.h
+etc.o: $(hdrdir)/ruby/internal/rgengc.h
etc.o: $(hdrdir)/ruby/internal/scan_args.h
etc.o: $(hdrdir)/ruby/internal/special_consts.h
etc.o: $(hdrdir)/ruby/internal/static_assert.h
etc.o: $(hdrdir)/ruby/internal/stdalign.h
etc.o: $(hdrdir)/ruby/internal/stdbool.h
-etc.o: $(hdrdir)/ruby/internal/stdckdint.h
etc.o: $(hdrdir)/ruby/internal/symbol.h
etc.o: $(hdrdir)/ruby/internal/value.h
etc.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/etc/etc.c b/ext/etc/etc.c
index fcbd1af1b5..6c7145b40b 100644
--- a/ext/etc/etc.c
+++ b/ext/etc/etc.c
@@ -54,9 +54,9 @@ static VALUE sGroup;
# include <stdlib.h>
# endif
#endif
-RUBY_EXTERN char *getlogin(void);
+char *getlogin();
-#define RUBY_ETC_VERSION "1.4.3"
+#define RUBY_ETC_VERSION "1.4.2"
#ifdef HAVE_RB_DEPRECATE_CONSTANT
void rb_deprecate_constant(VALUE mod, const char *name);
@@ -66,17 +66,6 @@ void rb_deprecate_constant(VALUE mod, const char *name);
#include "constdefs.h"
-#ifndef HAVE_RB_IO_DESCRIPTOR
-static int
-io_descriptor_fallback(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- return fptr->fd;
-}
-#define rb_io_descriptor io_descriptor_fallback
-#endif
-
#ifdef HAVE_RUBY_ATOMIC_H
# include "ruby/atomic.h"
#else
@@ -203,7 +192,7 @@ setup_passwd(struct passwd *pwd)
#endif
/* call-seq:
- * getpwuid(uid) -> Etc::Passwd
+ * getpwuid(uid) -> Passwd
*
* Returns the <tt>/etc/passwd</tt> information for the user with the given
* integer +uid+.
@@ -215,7 +204,7 @@ setup_passwd(struct passwd *pwd)
*
* See the unix manpage for <code>getpwuid(3)</code> for more detail.
*
- * *Example:*
+ * === Example:
*
* Etc.getpwuid(0)
* #=> #<struct Etc::Passwd name="root", passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
@@ -243,7 +232,7 @@ etc_getpwuid(int argc, VALUE *argv, VALUE obj)
}
/* call-seq:
- * getpwnam(name) -> Etc::Passwd
+ * getpwnam(name) -> Passwd
*
* Returns the <tt>/etc/passwd</tt> information for the user with specified
* login +name+.
@@ -252,7 +241,7 @@ etc_getpwuid(int argc, VALUE *argv, VALUE obj)
*
* See the unix manpage for <code>getpwnam(3)</code> for more detail.
*
- * *Example:*
+ * === Example:
*
* Etc.getpwnam('root')
* #=> #<struct Etc::Passwd name="root", passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash">
@@ -307,8 +296,8 @@ each_passwd(void)
#endif
/* call-seq:
- * passwd { |struct| block }
- * passwd -> Etc::Passwd
+ * Etc.passwd { |struct| block } -> Passwd
+ * Etc.passwd -> Passwd
*
* Provides a convenient Ruby iterator which executes a block for each entry
* in the <tt>/etc/passwd</tt> file.
@@ -317,7 +306,7 @@ each_passwd(void)
*
* See ::getpwent above for details.
*
- * *Example:*
+ * Example:
*
* require 'etc'
*
@@ -343,7 +332,7 @@ etc_passwd(VALUE obj)
}
/* call-seq:
- * Etc::Passwd.each { |struct| block } -> Etc::Passwd
+ * Etc::Passwd.each { |struct| block } -> Passwd
* Etc::Passwd.each -> Enumerator
*
* Iterates for each entry in the <tt>/etc/passwd</tt> file if a block is
@@ -355,7 +344,7 @@ etc_passwd(VALUE obj)
*
* See Etc.getpwent above for details.
*
- * *Example:*
+ * Example:
*
* require 'etc'
*
@@ -377,10 +366,7 @@ etc_each_passwd(VALUE obj)
return obj;
}
-/* call-seq:
- * setpwent
- *
- * Resets the process of reading the <tt>/etc/passwd</tt> file, so that the
+/* Resets the process of reading the <tt>/etc/passwd</tt> file, so that the
* next call to ::getpwent will return the first entry again.
*/
static VALUE
@@ -392,10 +378,7 @@ etc_setpwent(VALUE obj)
return Qnil;
}
-/* call-seq:
- * endpwent
- *
- * Ends the process of scanning through the <tt>/etc/passwd</tt> file begun
+/* Ends the process of scanning through the <tt>/etc/passwd</tt> file begun
* with ::getpwent, and closes the file.
*/
static VALUE
@@ -407,10 +390,7 @@ etc_endpwent(VALUE obj)
return Qnil;
}
-/* call-seq:
- * getpwent -> Etc::Passwd
- *
- * Returns an entry from the <tt>/etc/passwd</tt> file.
+/* Returns an entry from the <tt>/etc/passwd</tt> file.
*
* The first time it is called it opens the file and returns the first entry;
* each successive call returns the next entry, or +nil+ if the end of the file
@@ -458,7 +438,7 @@ setup_group(struct group *grp)
#endif
/* call-seq:
- * getgrgid(group_id) -> Etc::Group
+ * getgrgid(group_id) -> Group
*
* Returns information about the group with specified integer +group_id+,
* as found in <tt>/etc/group</tt>.
@@ -467,7 +447,7 @@ setup_group(struct group *grp)
*
* See the unix manpage for <code>getgrgid(3)</code> for more detail.
*
- * *Example:*
+ * === Example:
*
* Etc.getgrgid(100)
* #=> #<struct Etc::Group name="users", passwd="x", gid=100, mem=["meta", "root"]>
@@ -496,7 +476,7 @@ etc_getgrgid(int argc, VALUE *argv, VALUE obj)
}
/* call-seq:
- * getgrnam(name) -> Etc::Group
+ * getgrnam(name) -> Group
*
* Returns information about the group with specified +name+, as found in
* <tt>/etc/group</tt>.
@@ -505,7 +485,7 @@ etc_getgrgid(int argc, VALUE *argv, VALUE obj)
*
* See the unix manpage for <code>getgrnam(3)</code> for more detail.
*
- * *Example:*
+ * === Example:
*
* Etc.getgrnam('users')
* #=> #<struct Etc::Group name="users", passwd="x", gid=100, mem=["meta", "root"]>
@@ -538,6 +518,7 @@ group_ensure(VALUE _)
return Qnil;
}
+
static VALUE
group_iterate(VALUE _)
{
@@ -560,18 +541,14 @@ each_group(void)
}
#endif
-/* call-seq:
- * group { |struct| block }
- * group -> Etc::Group
- *
- * Provides a convenient Ruby iterator which executes a block for each entry
+/* Provides a convenient Ruby iterator which executes a block for each entry
* in the <tt>/etc/group</tt> file.
*
* The code block is passed an Group struct.
*
* See ::getgrent above for details.
*
- * *Example:*
+ * Example:
*
* require 'etc'
*
@@ -598,7 +575,7 @@ etc_group(VALUE obj)
#ifdef HAVE_GETGRENT
/* call-seq:
- * Etc::Group.each { |group| block } -> Etc::Group
+ * Etc::Group.each { |group| block } -> obj
* Etc::Group.each -> Enumerator
*
* Iterates for each entry in the <tt>/etc/group</tt> file if a block is
@@ -608,7 +585,7 @@ etc_group(VALUE obj)
*
* The code block is passed a Group struct.
*
- * *Example:*
+ * Example:
*
* require 'etc'
*
@@ -629,10 +606,7 @@ etc_each_group(VALUE obj)
}
#endif
-/* call-seq:
- * setgrent
- *
- * Resets the process of reading the <tt>/etc/group</tt> file, so that the
+/* Resets the process of reading the <tt>/etc/group</tt> file, so that the
* next call to ::getgrent will return the first entry again.
*/
static VALUE
@@ -644,10 +618,7 @@ etc_setgrent(VALUE obj)
return Qnil;
}
-/* call-seq:
- * endgrent
- *
- * Ends the process of scanning through the <tt>/etc/group</tt> file begun
+/* Ends the process of scanning through the <tt>/etc/group</tt> file begun
* by ::getgrent, and closes the file.
*/
static VALUE
@@ -659,10 +630,7 @@ etc_endgrent(VALUE obj)
return Qnil;
}
-/* call-seq:
- * getgrent -> Etc::Group
- *
- * Returns an entry from the <tt>/etc/group</tt> file.
+/* Returns an entry from the <tt>/etc/group</tt> file.
*
* The first time it is called it opens the file and returns the first entry;
* each successive call returns the next entry, or +nil+ if the end of the file
@@ -693,9 +661,7 @@ UINT rb_w32_system_tmpdir(WCHAR *path, UINT len);
VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
#endif
-/* call-seq:
- * sysconfdir -> String
- *
+/*
* Returns system configuration directory.
*
* This is typically <code>"/etc"</code>, but is modified by the prefix used
@@ -715,9 +681,7 @@ etc_sysconfdir(VALUE obj)
#endif
}
-/* call-seq:
- * systmpdir -> String
- *
+/*
* Returns system temporary directory; typically "/tmp".
*/
static VALUE
@@ -761,15 +725,13 @@ etc_systmpdir(VALUE _)
}
#ifdef HAVE_UNAME
-/* call-seq:
- * uname -> hash
- *
+/*
* Returns the system information obtained by uname system call.
*
* The return value is a hash which has 5 keys at least:
* :sysname, :nodename, :release, :version, :machine
*
- * *Example:*
+ * Example:
*
* require 'etc'
* require 'pp'
@@ -879,9 +841,7 @@ etc_uname(VALUE obj)
#endif
#ifdef HAVE_SYSCONF
-/* call-seq:
- * sysconf(name) -> Integer
- *
+/*
* Returns system configuration variable using sysconf().
*
* _name_ should be a constant under <code>Etc</code> which begins with <code>SC_</code>.
@@ -915,9 +875,7 @@ etc_sysconf(VALUE obj, VALUE arg)
#endif
#ifdef HAVE_CONFSTR
-/* call-seq:
- * confstr(name) -> String
- *
+/*
* Returns system configuration variable using confstr().
*
* _name_ should be a constant under <code>Etc</code> which begins with <code>CS_</code>.
@@ -964,9 +922,7 @@ etc_confstr(VALUE obj, VALUE arg)
#endif
#ifdef HAVE_FPATHCONF
-/* call-seq:
- * pathconf(name) -> Integer
- *
+/*
* Returns pathname configuration variable using fpathconf().
*
* _name_ should be a constant under <code>Etc</code> which begins with <code>PC_</code>.
@@ -985,11 +941,14 @@ io_pathconf(VALUE io, VALUE arg)
{
int name;
long ret;
+ rb_io_t *fptr;
name = NUM2INT(arg);
+ GetOpenFile(io, fptr);
+
errno = 0;
- ret = fpathconf(rb_io_descriptor(io), name);
+ ret = fpathconf(fptr->fd, name);
if (ret == -1) {
if (errno == 0) /* no limit */
return Qnil;
@@ -1058,9 +1017,7 @@ etc_nprocessors_affin(void)
}
#endif
-/* call-seq:
- * nprocessors -> Integer
- *
+/*
* Returns the number of online processors.
*
* The result is intended as the number of processes to
@@ -1070,7 +1027,7 @@ etc_nprocessors_affin(void)
* - sched_getaffinity(): Linux
* - sysconf(_SC_NPROCESSORS_ONLN): GNU/Linux, NetBSD, FreeBSD, OpenBSD, DragonFly BSD, OpenIndiana, Mac OS X, AIX
*
- * *Example:*
+ * Example:
*
* require 'etc'
* p Etc.nprocessors #=> 4
@@ -1079,7 +1036,7 @@ etc_nprocessors_affin(void)
* process is bound to specific cpus. This is intended for getting better
* parallel processing.
*
- * *Example:* (Linux)
+ * Example: (Linux)
*
* linux$ taskset 0x3 ./ruby -retc -e "p Etc.nprocessors" #=> 2
*
@@ -1129,7 +1086,7 @@ etc_nprocessors(VALUE obj)
* The Etc module provides a more reliable way to access information about
* the logged in user than environment variables such as +$USER+.
*
- * *Example:*
+ * == Example:
*
* require 'etc'
*
@@ -1153,7 +1110,6 @@ Init_etc(void)
RB_EXT_RACTOR_SAFE(true);
#endif
mEtc = rb_define_module("Etc");
- /* The version */
rb_define_const(mEtc, "VERSION", rb_str_new_cstr(RUBY_ETC_VERSION));
init_constants(mEtc);
diff --git a/ext/etc/extconf.rb b/ext/etc/extconf.rb
index 2e28d58037..159b1614b7 100644
--- a/ext/etc/extconf.rb
+++ b/ext/etc/extconf.rb
@@ -43,23 +43,13 @@ have_struct_member('struct group', 'gr_passwd', 'grp.h')
# for https://github.com/ruby/etc
srcdir = File.expand_path("..", __FILE__)
-constdefs = "#{srcdir}/constdefs.h"
-if !File.exist?(constdefs)
- ruby = RbConfig.ruby
- if File.file?(ruby)
- ruby = [ruby]
- else
- require "shellwords"
- ruby = Shellwords.split(ruby)
- end
- system(*ruby, "#{srcdir}/mkconstants.rb", "-o", constdefs)
+if !File.exist?("#{srcdir}/depend")
+ %x[#{RbConfig.ruby} #{srcdir}/mkconstants.rb -o #{srcdir}/constdefs.h]
end
# TODO: remove when dropping 2.7 support, as exported since 3.0
have_func('rb_deprecate_constant(Qnil, "None")')
-have_func("rb_io_descriptor")
-
$distcleanfiles << "constdefs.h"
create_makefile("etc")
diff --git a/ext/etc/mkconstants.rb b/ext/etc/mkconstants.rb
index a766560a8a..a752d64519 100644
--- a/ext/etc/mkconstants.rb
+++ b/ext/etc/mkconstants.rb
@@ -35,12 +35,6 @@ opt.def_option('-H FILE', 'specify output header file') {|filename|
opt.parse!
-CONST_PREFIXES = {
- 'SC' => 'for Etc.sysconf; See <tt>man sysconf</tt>',
- 'CS' => 'for Etc.confstr; See <tt>man constr</tt>',
- 'PC' => 'for IO#pathconf; See <tt>man fpathconf</tt>',
-}
-
h = {}
COMMENTS = {}
@@ -55,13 +49,6 @@ DATA.each_line {|s|
next
end
h[name] = default_value
- if additional = CONST_PREFIXES[name[/\A_([A-Z]+)_/, 1]]
- if comment&.match(/\w\z/)
- comment << " " << additional
- else
- (comment ||= String.new) << " " << additional.sub(/\A\w/) {$&.upcase}
- end
- end
COMMENTS[name] = comment if comment
}
DEFS = h.to_a
@@ -79,11 +66,15 @@ def each_name(pat)
}
end
-erb_new = lambda do |src, trim|
- ERB.new(src, trim_mode: trim)
+erb_new = lambda do |src, safe, trim|
+ if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
+ ERB.new(src, trim_mode: trim)
+ else
+ ERB.new(src, safe, trim)
+ end
end
-erb_new.call(<<'EOS', '%').def_method(Object, "gen_const_decls")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_const_decls")
% each_const {|name, default_value|
#if !defined(<%=name%>)
# if defined(HAVE_CONST_<%=name.upcase%>)
@@ -97,7 +88,7 @@ erb_new.call(<<'EOS', '%').def_method(Object, "gen_const_decls")
% }
EOS
-erb_new.call(<<'EOS', '%').def_method(Object, "gen_const_defs")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_const_defs")
% each_const {|name, default_value|
#if defined(<%=name%>)
% if comment = COMMENTS[name]
@@ -108,13 +99,13 @@ erb_new.call(<<'EOS', '%').def_method(Object, "gen_const_defs")
% }
EOS
-header_result = erb_new.call(<<'EOS', '%').result(binding)
+header_result = erb_new.call(<<'EOS', nil, '%').result(binding)
/* autogenerated file */
<%= gen_const_decls %>
EOS
-result = erb_new.call(<<'EOS', '%').result(binding)
+result = erb_new.call(<<'EOS', nil, '%').result(binding)
/* autogenerated file */
#ifdef HAVE_LONG_LONG
@@ -132,9 +123,6 @@ result = erb_new.call(<<'EOS', '%').result(binding)
static void
init_constants(VALUE mod)
{
-#if 0
- mod = rb_define_module("Etc");
-#endif
<%= gen_const_defs %>
}
EOS
diff --git a/ext/extmk.rb b/ext/extmk.rb
index 8b6b365a99..4e77a7167b 100755
--- a/ext/extmk.rb
+++ b/ext/extmk.rb
@@ -2,13 +2,7 @@
# -*- mode: ruby; coding: us-ascii -*-
# frozen_string_literal: false
-module Gem
- # Used by Gem::Platform.local
- def self.target_rbconfig
- RbConfig::CONFIG
- end
-end
-# only needs Gem::Platform
+module Gem; end # only needs Gem::Platform
require 'rubygems/platform'
# :stopdoc:
@@ -49,7 +43,11 @@ $" << "mkmf.rb"
load File.expand_path("lib/mkmf.rb", srcdir)
require 'optparse/shellwords'
-@null = File::NULL
+if defined?(File::NULL)
+ @null = File::NULL
+elsif !File.chardev?(@null = "/dev/null")
+ @null = "nul"
+end
def verbose?
$mflags.defined?("V") == "1"
@@ -110,7 +108,7 @@ def extract_makefile(makefile, keep = true)
end
return false
end
- srcs = Dir[*SRC_EXT.map {|e| "*.#{e}"}, base: $srcdir].map {|fn| File.basename(fn)}.sort
+ srcs = Dir[File.join($srcdir, "*.{#{SRC_EXT.join(%q{,})}}")].map {|fn| File.basename(fn)}.sort
if !srcs.empty?
old_srcs = m[/^ORIG_SRCS[ \t]*=[ \t](.*)/, 1] or return false
(old_srcs.split - srcs).empty? or return false
@@ -173,8 +171,6 @@ def extmake(target, basedir = 'ext', maybestatic = true)
$mdir = target
$srcdir = File.join($top_srcdir, basedir, $mdir)
$preload = nil
- $objs = []
- $srcs = []
$extso = []
makefile = "./Makefile"
static = $static
@@ -208,7 +204,7 @@ def extmake(target, basedir = 'ext', maybestatic = true)
begin
$extconf_h = nil
ok &&= extract_makefile(makefile)
- old_objs = $objs
+ old_objs = $objs || []
old_cleanfiles = $distcleanfiles | $cleanfiles
conf = ["#{$srcdir}/makefile.rb", "#{$srcdir}/extconf.rb"].find {|f| File.exist?(f)}
if (!ok || ($extconf_h && !File.exist?($extconf_h)) ||
@@ -271,6 +267,8 @@ def extmake(target, basedir = 'ext', maybestatic = true)
unless $destdir.to_s.empty? or $mflags.defined?("DESTDIR")
args += ["DESTDIR=" + relative_from($destdir, "../"+prefix)]
end
+ $objs ||= []
+ $srcs ||= []
if $static and ok and !$objs.empty? and !noinstall
args += ["static"]
$extlist.push [(maybestatic ? $static : false), target, $target, $preload]
@@ -486,13 +484,12 @@ if exts = ARGV.shift
$extension = [exts] if exts
if ext_prefix.start_with?('.')
@gemname = exts
- exts = []
- else
- exts &&= $static_ext.select {|t, *| File.fnmatch(t, exts)}
+ elsif exts
+ $static_ext.delete_if {|t, *| !File.fnmatch(t, exts)}
end
end
-ext_prefix ||= 'ext'
-exts = (exts || $static_ext).sort_by {|t, i| i}.collect {|t, i| t}
+ext_prefix = "#{$top_srcdir}/#{ext_prefix || 'ext'}"
+exts = $static_ext.sort_by {|t, i| i}.collect {|t, i| t}
default_exclude_exts =
case
when $cygwin
@@ -505,30 +502,28 @@ default_exclude_exts =
mandatory_exts = {}
withes, withouts = [["--with", nil], ["--without", default_exclude_exts]].collect {|w, d|
if !(w = %w[-extensions -ext].collect {|o|arg_config(w+o)}).any?
- d ? proc {|&c1| d.any?(&c1)} : proc {true}
+ d ? proc {|c1| d.any?(&c1)} : proc {true}
elsif (w = w.grep(String)).empty?
proc {true}
else
w = w.collect {|o| o.split(/,/)}.flatten
w.collect! {|o| o == '+' ? d : o}.flatten!
- proc {|&c1| w.any?(&c1)}
+ proc {|c1| w.any?(&c1)}
end
}
cond = proc {|ext, *|
- withes.call {|n| !n or (mandatory_exts[ext] = true if File.fnmatch(n, ext))} and
- !withouts.call {|n| File.fnmatch(n, ext)}
+ withes.call(proc {|n|
+ !n or (mandatory_exts[ext] = true if File.fnmatch(n, ext))
+ }) and
+ !withouts.call(proc {|n| File.fnmatch(n, ext)})
}
($extension || %w[*]).each do |e|
e = e.sub(/\A(?:\.\/)+/, '')
- incl, excl = Dir.glob("#{e}/**/extconf.rb", base: "#$top_srcdir/#{ext_prefix}").collect {|d|
- File.dirname(d)
+ incl, excl = Dir.glob("#{ext_prefix}/#{e}/**/extconf.rb").collect {|d|
+ d = File.dirname(d)
+ d.slice!(0, ext_prefix.length + 1)
+ d
}.partition {|ext|
- if @gemname
- ext = ext[%r[\A[^/]+]] # extract gem name
- Dir.glob("*.gemspec", base: "#$top_srcdir/#{ext_prefix}/#{ext}") do |g|
- break ext = g if ext.start_with?("#{g.chomp!(".gemspec")}-")
- end
- end
with_config(ext, &cond)
}
incl.sort!
@@ -539,7 +534,7 @@ cond = proc {|ext, *|
exts.delete_if {|d| File.fnmatch?("-*", d)}
end
end
-ext_prefix.chomp!("/")
+ext_prefix = ext_prefix[$top_srcdir.size+1..-2]
@ext_prefix = ext_prefix
@inplace = inplace
@@ -651,9 +646,7 @@ $hdrdir = ($top_srcdir = relative_from(srcdir, $topdir = "..")) + "/include"
extso = []
fails = []
exts.each do |d|
- $static = $force_static ? true : $static_ext.fetch(d) do
- $static_ext.any? {|t, | File.fnmatch?(t, d)}
- end
+ $static = $force_static ? true : $static_ext[d]
if !$nodynamic or $static
result = extmake(d, ext_prefix, !@gemname) or abort
@@ -779,18 +772,12 @@ begin
end
submakeopts << 'EXTLDFLAGS="$(EXTLDFLAGS)"'
submakeopts << 'EXTINITS="$(EXTINITS)"'
+ submakeopts << 'UPDATE_LIBRARIES="$(UPDATE_LIBRARIES)"'
submakeopts << 'SHOWFLAGS='
mf.macro "SUBMAKEOPTS", submakeopts
mf.macro "NOTE_MESG", %w[$(RUBY) $(top_srcdir)/tool/lib/colorize.rb skip]
mf.macro "NOTE_NAME", %w[$(RUBY) $(top_srcdir)/tool/lib/colorize.rb fail]
%w[RM RMDIRS RMDIR RMALL].each {|w| mf.macro w, [RbConfig::CONFIG[w]]}
- if $nmake
- message = ['@(for %I in (', ') do @echo.%~I)']
- else
- message = ['@for line in', '; do echo "$$line"; done']
- end
- mf.macro "MESSAGE_BEGIN", [message.first]
- mf.macro "MESSAGE_END", [message.last]
mf.puts
targets = %w[all install static install-so install-rb clean distclean realclean]
targets.each do |tgt|
@@ -834,7 +821,7 @@ begin
end
mf.puts "#{t}:#{pd}\n\t$(Q)#{submake} $(MFLAGS) V=$(V) $(@F)"
if clean and clean.begin(1)
- mf.puts "\t$(Q)$(RM) $(ext_build_dir)/exts.mk\n\t$(Q)$(RMDIRS) $(@D)"
+ mf.puts "\t$(Q)$(RM) $(ext_build_dir)/exts.mk\n\t$(Q)$(RMDIRS) -p $(@D)"
end
end
end
@@ -853,17 +840,15 @@ begin
fails.each do |ext, (parent, err)|
abandon ||= mandatory_exts[ext]
mf.puts %Q<\t@$(NOTE_NAME) "#{ext}:">
- mf.puts "\t$(MESSAGE_BEGIN) \\"
if parent
- mf.puts %Q<\t"\tCould not be configured. It will not be installed." \\>
+ mf.puts %Q<\t@echo "\tCould not be configured. It will not be installed.">
err and err.scan(/.+/) do |ee|
- mf.puts %Q<\t"\t#{ee.gsub(/["`$^]/, '\\\\\\&')}" \\>
+ mf.puts %Q<\t@echo "\t#{ee.gsub(/["`$^]/, '\\\\\\&')}">
end
- mf.puts %Q<\t"\tCheck #{ext_prefix}/#{ext}/mkmf.log for more details." \\>
+ mf.puts %Q<\t@echo "\tCheck #{ext_prefix}/#{ext}/mkmf.log for more details.">
else
- mf.puts %Q<\t"\tSkipped because its parent was not configured." \\>
+ mf.puts %Q<\t@echo "\tSkipped because its parent was not configured.">
end
- mf.puts "\t$(MESSAGE_END)"
end
mf.puts "note:\n"
mf.puts %Q<\t@$(NOTE_MESG) "*** Fix the problems, then remove these directories and try again if you want.">
diff --git a/ext/fcntl/depend b/ext/fcntl/depend
index 5ed652563b..718de62e26 100644
--- a/ext/fcntl/depend
+++ b/ext/fcntl/depend
@@ -52,7 +52,6 @@ fcntl.o: $(hdrdir)/ruby/internal/attr/noexcept.h
fcntl.o: $(hdrdir)/ruby/internal/attr/noinline.h
fcntl.o: $(hdrdir)/ruby/internal/attr/nonnull.h
fcntl.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-fcntl.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
fcntl.o: $(hdrdir)/ruby/internal/attr/pure.h
fcntl.o: $(hdrdir)/ruby/internal/attr/restrict.h
fcntl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -112,6 +111,7 @@ fcntl.o: $(hdrdir)/ruby/internal/intern/enumerator.h
fcntl.o: $(hdrdir)/ruby/internal/intern/error.h
fcntl.o: $(hdrdir)/ruby/internal/intern/eval.h
fcntl.o: $(hdrdir)/ruby/internal/intern/file.h
+fcntl.o: $(hdrdir)/ruby/internal/intern/gc.h
fcntl.o: $(hdrdir)/ruby/internal/intern/hash.h
fcntl.o: $(hdrdir)/ruby/internal/intern/io.h
fcntl.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -142,12 +142,12 @@ fcntl.o: $(hdrdir)/ruby/internal/memory.h
fcntl.o: $(hdrdir)/ruby/internal/method.h
fcntl.o: $(hdrdir)/ruby/internal/module.h
fcntl.o: $(hdrdir)/ruby/internal/newobj.h
+fcntl.o: $(hdrdir)/ruby/internal/rgengc.h
fcntl.o: $(hdrdir)/ruby/internal/scan_args.h
fcntl.o: $(hdrdir)/ruby/internal/special_consts.h
fcntl.o: $(hdrdir)/ruby/internal/static_assert.h
fcntl.o: $(hdrdir)/ruby/internal/stdalign.h
fcntl.o: $(hdrdir)/ruby/internal/stdbool.h
-fcntl.o: $(hdrdir)/ruby/internal/stdckdint.h
fcntl.o: $(hdrdir)/ruby/internal/symbol.h
fcntl.o: $(hdrdir)/ruby/internal/value.h
fcntl.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/fcntl/fcntl.c b/ext/fcntl/fcntl.c
index e34a3aeae3..3bccc41e4c 100644
--- a/ext/fcntl/fcntl.c
+++ b/ext/fcntl/fcntl.c
@@ -28,10 +28,7 @@ pack up your own arguments to pass as args for locking functions, etc.
#include "ruby.h"
#include <fcntl.h>
-/*
- * Document-module: Fcntl
- *
- * Fcntl loads the constants defined in the system's <fcntl.h> C header
+/* Fcntl loads the constants defined in the system's <fcntl.h> C header
* file, and used with both the fcntl(2) and open(2) POSIX system calls.
*
* To perform a fcntl(2) operation, use IO::fcntl.
@@ -64,19 +61,13 @@ pack up your own arguments to pass as args for locking functions, etc.
* f.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK|m)
*
*/
-
-#define FCNTL_VERSION "1.1.0"
-
void
Init_fcntl(void)
{
VALUE mFcntl = rb_define_module("Fcntl");
-
- /* The version string. */
- rb_define_const(mFcntl, "VERSION", rb_str_new_cstr(FCNTL_VERSION));
-
#ifdef F_DUPFD
- /*
+ /* Document-const: F_DUPFD
+ *
* Duplicate a file descriptor to the minimum unused file descriptor
* greater than or equal to the argument.
*
@@ -87,164 +78,195 @@ Init_fcntl(void)
rb_define_const(mFcntl, "F_DUPFD", INT2NUM(F_DUPFD));
#endif
#ifdef F_GETFD
- /*
+ /* Document-const: F_GETFD
+ *
* Read the close-on-exec flag of a file descriptor.
*/
rb_define_const(mFcntl, "F_GETFD", INT2NUM(F_GETFD));
#endif
#ifdef F_GETLK
- /*
+ /* Document-const: F_GETLK
+ *
* Determine whether a given region of a file is locked. This uses one of
* the F_*LK flags.
*/
rb_define_const(mFcntl, "F_GETLK", INT2NUM(F_GETLK));
#endif
#ifdef F_SETFD
- /*
+ /* Document-const: F_SETFD
+ *
* Set the close-on-exec flag of a file descriptor.
*/
rb_define_const(mFcntl, "F_SETFD", INT2NUM(F_SETFD));
#endif
#ifdef F_GETFL
- /*
+ /* Document-const: F_GETFL
+ *
* Get the file descriptor flags. This will be one or more of the O_*
* flags.
*/
rb_define_const(mFcntl, "F_GETFL", INT2NUM(F_GETFL));
#endif
#ifdef F_SETFL
- /*
+ /* Document-const: F_SETFL
+ *
* Set the file descriptor flags. This will be one or more of the O_*
* flags.
*/
rb_define_const(mFcntl, "F_SETFL", INT2NUM(F_SETFL));
#endif
#ifdef F_SETLK
- /*
+ /* Document-const: F_SETLK
+ *
* Acquire a lock on a region of a file. This uses one of the F_*LCK
* flags.
*/
rb_define_const(mFcntl, "F_SETLK", INT2NUM(F_SETLK));
#endif
#ifdef F_SETLKW
- /*
+ /* Document-const: F_SETLKW
+ *
* Acquire a lock on a region of a file, waiting if necessary. This uses
* one of the F_*LCK flags
*/
rb_define_const(mFcntl, "F_SETLKW", INT2NUM(F_SETLKW));
#endif
#ifdef FD_CLOEXEC
- /*
+ /* Document-const: FD_CLOEXEC
+ *
* the value of the close-on-exec flag.
*/
rb_define_const(mFcntl, "FD_CLOEXEC", INT2NUM(FD_CLOEXEC));
#endif
#ifdef F_RDLCK
- /*
+ /* Document-const: F_RDLCK
+ *
* Read lock for a region of a file
*/
rb_define_const(mFcntl, "F_RDLCK", INT2NUM(F_RDLCK));
#endif
#ifdef F_UNLCK
- /*
+ /* Document-const: F_UNLCK
+ *
* Remove lock for a region of a file
*/
rb_define_const(mFcntl, "F_UNLCK", INT2NUM(F_UNLCK));
#endif
#ifdef F_WRLCK
- /*
+ /* Document-const: F_WRLCK
+ *
* Write lock for a region of a file
*/
rb_define_const(mFcntl, "F_WRLCK", INT2NUM(F_WRLCK));
#endif
#ifdef F_SETPIPE_SZ
- /*
+ /* Document-const: F_SETPIPE_SZ
+ *
* Change the capacity of the pipe referred to by fd to be at least arg bytes.
*/
rb_define_const(mFcntl, "F_SETPIPE_SZ", INT2NUM(F_SETPIPE_SZ));
#endif
#ifdef F_GETPIPE_SZ
- /*
+ /* Document-const: F_GETPIPE_SZ
+ *
* Return (as the function result) the capacity of the pipe referred to by fd.
*/
rb_define_const(mFcntl, "F_GETPIPE_SZ", INT2NUM(F_GETPIPE_SZ));
#endif
#ifdef O_CREAT
- /*
+ /* Document-const: O_CREAT
+ *
* Create the file if it doesn't exist
*/
rb_define_const(mFcntl, "O_CREAT", INT2NUM(O_CREAT));
#endif
#ifdef O_EXCL
- /*
+ /* Document-const: O_EXCL
+ *
* Used with O_CREAT, fail if the file exists
*/
rb_define_const(mFcntl, "O_EXCL", INT2NUM(O_EXCL));
#endif
#ifdef O_NOCTTY
- /*
+ /* Document-const: O_NOCTTY
+ *
* Open TTY without it becoming the controlling TTY
*/
rb_define_const(mFcntl, "O_NOCTTY", INT2NUM(O_NOCTTY));
#endif
#ifdef O_TRUNC
- /*
+ /* Document-const: O_TRUNC
+ *
* Truncate the file on open
*/
rb_define_const(mFcntl, "O_TRUNC", INT2NUM(O_TRUNC));
#endif
#ifdef O_APPEND
- /*
+ /* Document-const: O_APPEND
+ *
* Open the file in append mode
*/
rb_define_const(mFcntl, "O_APPEND", INT2NUM(O_APPEND));
#endif
#ifdef O_NONBLOCK
- /*
+ /* Document-const: O_NONBLOCK
+ *
* Open the file in non-blocking mode
*/
rb_define_const(mFcntl, "O_NONBLOCK", INT2NUM(O_NONBLOCK));
#endif
#ifdef O_NDELAY
- /*
+ /* Document-const: O_NDELAY
+ *
* Open the file in non-blocking mode
*/
rb_define_const(mFcntl, "O_NDELAY", INT2NUM(O_NDELAY));
#endif
#ifdef O_RDONLY
- /*
+ /* Document-const: O_RDONLY
+ *
* Open the file in read-only mode
*/
rb_define_const(mFcntl, "O_RDONLY", INT2NUM(O_RDONLY));
#endif
#ifdef O_RDWR
- /*
+ /* Document-const: O_RDWR
+ *
* Open the file in read-write mode
*/
rb_define_const(mFcntl, "O_RDWR", INT2NUM(O_RDWR));
#endif
#ifdef O_WRONLY
- /*
+ /* Document-const: O_WRONLY
+ *
* Open the file in write-only mode.
*/
rb_define_const(mFcntl, "O_WRONLY", INT2NUM(O_WRONLY));
#endif
-#ifndef O_ACCMODE
- int O_ACCMODE = (O_RDONLY | O_WRONLY | O_RDWR);
-#endif
- /*
+#ifdef O_ACCMODE
+ /* Document-const: O_ACCMODE
+ *
* Mask to extract the read/write flags
*/
rb_define_const(mFcntl, "O_ACCMODE", INT2FIX(O_ACCMODE));
+#else
+ /* Document-const: O_ACCMODE
+ *
+ * Mask to extract the read/write flags
+ */
+ rb_define_const(mFcntl, "O_ACCMODE", INT2FIX(O_RDONLY | O_WRONLY | O_RDWR));
+#endif
#ifdef F_DUP2FD
- /*
+ /* Document-const: F_DUP2FD
+ *
* It is a FreeBSD specific constant and equivalent
* to dup2 call.
*/
rb_define_const(mFcntl, "F_DUP2FD", INT2NUM(F_DUP2FD));
#endif
#ifdef F_DUP2FD_CLOEXEC
- /*
+ /* Document-const: F_DUP2FD_CLOEXEC
+ *
* It is a FreeBSD specific constant and acts
* similarly as F_DUP2FD but set the FD_CLOEXEC
* flag in addition.
diff --git a/ext/fcntl/fcntl.gemspec b/ext/fcntl/fcntl.gemspec
index d621bc0491..09d3fc2568 100644
--- a/ext/fcntl/fcntl.gemspec
+++ b/ext/fcntl/fcntl.gemspec
@@ -1,19 +1,9 @@
# coding: utf-8
# frozen_string_literal: true
-source_version = ["", "ext/fcntl/"].find do |dir|
- begin
- break File.open(File.join(__dir__, "#{dir}fcntl.c")) {|f|
- f.gets("\n#define FCNTL_VERSION ")
- f.gets[/\s*"(.+)"/, 1]
- }
- rescue Errno::ENOENT
- end
-end
-
Gem::Specification.new do |spec|
spec.name = "fcntl"
- spec.version = source_version
+ spec.version = "1.0.2"
spec.authors = ["Yukihiro Matsumoto"]
spec.email = ["matz@ruby-lang.org"]
@@ -23,10 +13,9 @@ Gem::Specification.new do |spec|
spec.licenses = ["Ruby", "BSD-2-Clause"]
spec.files = ["ext/fcntl/extconf.rb", "ext/fcntl/fcntl.c"]
- spec.extra_rdoc_files = [".document", ".rdoc_options", "LICENSE.txt", "README.md"]
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
spec.extensions = "ext/fcntl/extconf.rb"
- spec.required_ruby_version = ">= 2.5.0"
+ spec.required_ruby_version = ">= 2.3.0"
end
diff --git a/ext/fiddle/closure.c b/ext/fiddle/closure.c
index 7aa9407619..892f522a62 100644
--- a/ext/fiddle/closure.c
+++ b/ext/fiddle/closure.c
@@ -1,5 +1,4 @@
#include <fiddle.h>
-#include <stdbool.h>
#include <ruby/thread.h>
int ruby_thread_has_gvl_p(void); /* from internal.h */
@@ -55,13 +54,10 @@ closure_memsize(const void * ptr)
}
const rb_data_type_t closure_data_type = {
- .wrap_struct_name = "fiddle/closure",
- .function = {
- .dmark = 0,
- .dfree = dealloc,
- .dsize = closure_memsize
- },
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ "fiddle/closure",
+ {0, dealloc, closure_memsize,},
+ 0, 0,
+ RUBY_TYPED_FREE_IMMEDIATELY,
};
struct callback_args {
@@ -140,20 +136,6 @@ with_gvl_callback(void *ptr)
rb_ary_push(params,
rb_str_new_cstr(*((const char **)(x->args[i]))));
break;
- case TYPE_BOOL:
- if (sizeof(bool) == sizeof(char)) {
- rb_ary_push(params, CBOOL2RBBOOL(*(unsigned char *)x->args[i]));
- } else if (sizeof(bool) == sizeof(short)) {
- rb_ary_push(params, CBOOL2RBBOOL(*(unsigned short *)x->args[i]));
- } else if (sizeof(bool) == sizeof(int)) {
- rb_ary_push(params, CBOOL2RBBOOL(*(unsigned int *)x->args[i]));
- } else if (sizeof(bool) == sizeof(long)) {
- rb_ary_push(params, CBOOL2RBBOOL(*(unsigned long *)x->args[i]));
- } else {
- rb_raise(rb_eNotImpError, "bool isn't supported: %u",
- (unsigned int)sizeof(bool));
- }
- break;
default:
rb_raise(rb_eRuntimeError, "closure args: %d", type);
}
@@ -203,13 +185,6 @@ with_gvl_callback(void *ptr)
/* Dangerous. Callback must keep reference of the String. */
*((const char **)(x->resp)) = StringValueCStr(ret);
break;
- case TYPE_BOOL:
- if (sizeof(bool) == sizeof(long)) {
- *(unsigned long *)x->resp = RB_TEST(ret);
- } else {
- *(ffi_arg *)x->resp = RB_TEST(ret);
- }
- break;
default:
rb_raise(rb_eRuntimeError, "closure retval: %d", type);
}
@@ -455,3 +430,4 @@ Init_fiddle_closure(void)
*/
rb_define_method(cFiddleClosure, "freed?", closure_freed_p, 0);
}
+/* vim: set noet sw=4 sts=4 */
diff --git a/ext/fiddle/conversions.c b/ext/fiddle/conversions.c
index 298ed9775a..3b70f7de4c 100644
--- a/ext/fiddle/conversions.c
+++ b/ext/fiddle/conversions.c
@@ -1,5 +1,3 @@
-#include <stdbool.h>
-
#include <fiddle.h>
VALUE
@@ -46,7 +44,6 @@ rb_fiddle_type_ensure(VALUE type)
ID ptrdiff_t_id;
ID intptr_t_id;
ID uintptr_t_id;
- ID bool_id;
RUBY_CONST_ID(void_id, "void");
RUBY_CONST_ID(voidp_id, "voidp");
RUBY_CONST_ID(char_id, "char");
@@ -77,7 +74,6 @@ rb_fiddle_type_ensure(VALUE type)
RUBY_CONST_ID(ptrdiff_t_id, "ptrdiff_t");
RUBY_CONST_ID(intptr_t_id, "intptr_t");
RUBY_CONST_ID(uintptr_t_id, "uintptr_t");
- RUBY_CONST_ID(bool_id, "bool");
if (type_id == void_id) {
return INT2NUM(TYPE_VOID);
}
@@ -148,9 +144,6 @@ rb_fiddle_type_ensure(VALUE type)
else if (type_id == uintptr_t_id) {
return INT2NUM(TYPE_UINTPTR_T);
}
- else if (type_id == bool_id) {
- return INT2NUM(TYPE_BOOL);
- }
else {
type = original_type;
}
@@ -194,20 +187,6 @@ rb_fiddle_int_to_ffi_type(int type)
return &ffi_type_double;
case TYPE_CONST_STRING:
return &ffi_type_pointer;
- case TYPE_BOOL:
- signed_p = 0;
- if (sizeof(bool) == sizeof(char)) {
- return rb_ffi_type_of(char);
- } else if (sizeof(bool) == sizeof(short)) {
- return rb_ffi_type_of(short);
- } else if (sizeof(bool) == sizeof(int)) {
- return rb_ffi_type_of(int);
- } else if (sizeof(bool) == sizeof(long)) {
- return rb_ffi_type_of(long);
- } else {
- rb_raise(rb_eNotImpError, "bool isn't supported: %u",
- (unsigned int)sizeof(bool));
- }
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
}
@@ -230,11 +209,7 @@ rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst)
dst->pointer = NUM2PTR(rb_Integer(*src));
break;
case TYPE_CHAR:
- if (RB_TYPE_P(*src, RUBY_T_STRING) && RSTRING_LEN(*src) == 1) {
- dst->schar = RSTRING_PTR(*src)[0];
- } else {
- dst->schar = (signed char)NUM2INT(*src);
- }
+ dst->schar = (signed char)NUM2INT(*src);
break;
case TYPE_UCHAR:
dst->uchar = (unsigned char)NUM2UINT(*src);
@@ -279,23 +254,8 @@ rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst)
dst->pointer = rb_string_value_cstr(src);
}
break;
- case TYPE_BOOL:
- if (sizeof(bool) == sizeof(char)) {
- dst->uchar = RB_TEST(*src);
- } else if (sizeof(bool) == sizeof(short)) {
- dst->ushort = RB_TEST(*src);
- } else if (sizeof(bool) == sizeof(int)) {
- dst->uint = RB_TEST(*src);
- } else if (sizeof(bool) == sizeof(long)) {
- dst->ulong = RB_TEST(*src);
- } else {
- rb_raise(rb_eNotImpError, "bool isn't supported: %u",
- (unsigned int)sizeof(bool));
- }
- break;
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
- break;
}
}
@@ -354,19 +314,6 @@ rb_fiddle_generic_to_value(VALUE rettype, fiddle_generic retval)
else {
return Qnil;
}
- case TYPE_BOOL:
- if (sizeof(bool) == sizeof(char)) {
- return CBOOL2RBBOOL((unsigned char)retval.fffi_arg);
- } else if (sizeof(bool) == sizeof(short)) {
- return CBOOL2RBBOOL((unsigned short)retval.fffi_arg);
- } else if (sizeof(bool) == sizeof(int)) {
- return CBOOL2RBBOOL((unsigned int)retval.fffi_arg);
- } else if (sizeof(bool) == sizeof(long)) {
- return CBOOL2RBBOOL(retval.ulong);
- } else {
- rb_raise(rb_eNotImpError, "bool isn't supported: %u",
- (unsigned int)sizeof(bool));
- }
default:
rb_raise(rb_eRuntimeError, "unknown type %d", type);
}
@@ -379,3 +326,5 @@ generic_to_value(VALUE rettype, fiddle_generic retval)
{
return rb_fiddle_generic_to_value(rettype, retval);
}
+
+/* vim: set noet sw=4 sts=4 */
diff --git a/ext/fiddle/conversions.h b/ext/fiddle/conversions.h
index 7a1e928d56..c7c12a9234 100644
--- a/ext/fiddle/conversions.h
+++ b/ext/fiddle/conversions.h
@@ -50,6 +50,4 @@ VALUE generic_to_value(VALUE rettype, fiddle_generic retval);
# define NUM2PTR(x) ((void*)(NUM2ULL(x)))
#endif
-#define CBOOL2RBBOOL(cbool) ((cbool) ? RUBY_Qtrue : RUBY_Qfalse)
-
#endif
diff --git a/ext/fiddle/depend b/ext/fiddle/depend
index 43b11ca780..d6a053f05b 100644
--- a/ext/fiddle/depend
+++ b/ext/fiddle/depend
@@ -105,7 +105,6 @@ closure.o: $(hdrdir)/ruby/internal/attr/noexcept.h
closure.o: $(hdrdir)/ruby/internal/attr/noinline.h
closure.o: $(hdrdir)/ruby/internal/attr/nonnull.h
closure.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-closure.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
closure.o: $(hdrdir)/ruby/internal/attr/pure.h
closure.o: $(hdrdir)/ruby/internal/attr/restrict.h
closure.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -165,6 +164,7 @@ closure.o: $(hdrdir)/ruby/internal/intern/enumerator.h
closure.o: $(hdrdir)/ruby/internal/intern/error.h
closure.o: $(hdrdir)/ruby/internal/intern/eval.h
closure.o: $(hdrdir)/ruby/internal/intern/file.h
+closure.o: $(hdrdir)/ruby/internal/intern/gc.h
closure.o: $(hdrdir)/ruby/internal/intern/hash.h
closure.o: $(hdrdir)/ruby/internal/intern/io.h
closure.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -195,12 +195,12 @@ closure.o: $(hdrdir)/ruby/internal/memory.h
closure.o: $(hdrdir)/ruby/internal/method.h
closure.o: $(hdrdir)/ruby/internal/module.h
closure.o: $(hdrdir)/ruby/internal/newobj.h
+closure.o: $(hdrdir)/ruby/internal/rgengc.h
closure.o: $(hdrdir)/ruby/internal/scan_args.h
closure.o: $(hdrdir)/ruby/internal/special_consts.h
closure.o: $(hdrdir)/ruby/internal/static_assert.h
closure.o: $(hdrdir)/ruby/internal/stdalign.h
closure.o: $(hdrdir)/ruby/internal/stdbool.h
-closure.o: $(hdrdir)/ruby/internal/stdckdint.h
closure.o: $(hdrdir)/ruby/internal/symbol.h
closure.o: $(hdrdir)/ruby/internal/value.h
closure.o: $(hdrdir)/ruby/internal/value_type.h
@@ -270,7 +270,6 @@ conversions.o: $(hdrdir)/ruby/internal/attr/noexcept.h
conversions.o: $(hdrdir)/ruby/internal/attr/noinline.h
conversions.o: $(hdrdir)/ruby/internal/attr/nonnull.h
conversions.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-conversions.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
conversions.o: $(hdrdir)/ruby/internal/attr/pure.h
conversions.o: $(hdrdir)/ruby/internal/attr/restrict.h
conversions.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -330,6 +329,7 @@ conversions.o: $(hdrdir)/ruby/internal/intern/enumerator.h
conversions.o: $(hdrdir)/ruby/internal/intern/error.h
conversions.o: $(hdrdir)/ruby/internal/intern/eval.h
conversions.o: $(hdrdir)/ruby/internal/intern/file.h
+conversions.o: $(hdrdir)/ruby/internal/intern/gc.h
conversions.o: $(hdrdir)/ruby/internal/intern/hash.h
conversions.o: $(hdrdir)/ruby/internal/intern/io.h
conversions.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -360,12 +360,12 @@ conversions.o: $(hdrdir)/ruby/internal/memory.h
conversions.o: $(hdrdir)/ruby/internal/method.h
conversions.o: $(hdrdir)/ruby/internal/module.h
conversions.o: $(hdrdir)/ruby/internal/newobj.h
+conversions.o: $(hdrdir)/ruby/internal/rgengc.h
conversions.o: $(hdrdir)/ruby/internal/scan_args.h
conversions.o: $(hdrdir)/ruby/internal/special_consts.h
conversions.o: $(hdrdir)/ruby/internal/static_assert.h
conversions.o: $(hdrdir)/ruby/internal/stdalign.h
conversions.o: $(hdrdir)/ruby/internal/stdbool.h
-conversions.o: $(hdrdir)/ruby/internal/stdckdint.h
conversions.o: $(hdrdir)/ruby/internal/symbol.h
conversions.o: $(hdrdir)/ruby/internal/value.h
conversions.o: $(hdrdir)/ruby/internal/value_type.h
@@ -434,7 +434,6 @@ fiddle.o: $(hdrdir)/ruby/internal/attr/noexcept.h
fiddle.o: $(hdrdir)/ruby/internal/attr/noinline.h
fiddle.o: $(hdrdir)/ruby/internal/attr/nonnull.h
fiddle.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-fiddle.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
fiddle.o: $(hdrdir)/ruby/internal/attr/pure.h
fiddle.o: $(hdrdir)/ruby/internal/attr/restrict.h
fiddle.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -494,6 +493,7 @@ fiddle.o: $(hdrdir)/ruby/internal/intern/enumerator.h
fiddle.o: $(hdrdir)/ruby/internal/intern/error.h
fiddle.o: $(hdrdir)/ruby/internal/intern/eval.h
fiddle.o: $(hdrdir)/ruby/internal/intern/file.h
+fiddle.o: $(hdrdir)/ruby/internal/intern/gc.h
fiddle.o: $(hdrdir)/ruby/internal/intern/hash.h
fiddle.o: $(hdrdir)/ruby/internal/intern/io.h
fiddle.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -524,12 +524,12 @@ fiddle.o: $(hdrdir)/ruby/internal/memory.h
fiddle.o: $(hdrdir)/ruby/internal/method.h
fiddle.o: $(hdrdir)/ruby/internal/module.h
fiddle.o: $(hdrdir)/ruby/internal/newobj.h
+fiddle.o: $(hdrdir)/ruby/internal/rgengc.h
fiddle.o: $(hdrdir)/ruby/internal/scan_args.h
fiddle.o: $(hdrdir)/ruby/internal/special_consts.h
fiddle.o: $(hdrdir)/ruby/internal/static_assert.h
fiddle.o: $(hdrdir)/ruby/internal/stdalign.h
fiddle.o: $(hdrdir)/ruby/internal/stdbool.h
-fiddle.o: $(hdrdir)/ruby/internal/stdckdint.h
fiddle.o: $(hdrdir)/ruby/internal/symbol.h
fiddle.o: $(hdrdir)/ruby/internal/value.h
fiddle.o: $(hdrdir)/ruby/internal/value_type.h
@@ -598,7 +598,6 @@ function.o: $(hdrdir)/ruby/internal/attr/noexcept.h
function.o: $(hdrdir)/ruby/internal/attr/noinline.h
function.o: $(hdrdir)/ruby/internal/attr/nonnull.h
function.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-function.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
function.o: $(hdrdir)/ruby/internal/attr/pure.h
function.o: $(hdrdir)/ruby/internal/attr/restrict.h
function.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -658,6 +657,7 @@ function.o: $(hdrdir)/ruby/internal/intern/enumerator.h
function.o: $(hdrdir)/ruby/internal/intern/error.h
function.o: $(hdrdir)/ruby/internal/intern/eval.h
function.o: $(hdrdir)/ruby/internal/intern/file.h
+function.o: $(hdrdir)/ruby/internal/intern/gc.h
function.o: $(hdrdir)/ruby/internal/intern/hash.h
function.o: $(hdrdir)/ruby/internal/intern/io.h
function.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -688,12 +688,12 @@ function.o: $(hdrdir)/ruby/internal/memory.h
function.o: $(hdrdir)/ruby/internal/method.h
function.o: $(hdrdir)/ruby/internal/module.h
function.o: $(hdrdir)/ruby/internal/newobj.h
+function.o: $(hdrdir)/ruby/internal/rgengc.h
function.o: $(hdrdir)/ruby/internal/scan_args.h
function.o: $(hdrdir)/ruby/internal/special_consts.h
function.o: $(hdrdir)/ruby/internal/static_assert.h
function.o: $(hdrdir)/ruby/internal/stdalign.h
function.o: $(hdrdir)/ruby/internal/stdbool.h
-function.o: $(hdrdir)/ruby/internal/stdckdint.h
function.o: $(hdrdir)/ruby/internal/symbol.h
function.o: $(hdrdir)/ruby/internal/value.h
function.o: $(hdrdir)/ruby/internal/value_type.h
@@ -763,7 +763,6 @@ handle.o: $(hdrdir)/ruby/internal/attr/noexcept.h
handle.o: $(hdrdir)/ruby/internal/attr/noinline.h
handle.o: $(hdrdir)/ruby/internal/attr/nonnull.h
handle.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-handle.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
handle.o: $(hdrdir)/ruby/internal/attr/pure.h
handle.o: $(hdrdir)/ruby/internal/attr/restrict.h
handle.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -823,6 +822,7 @@ handle.o: $(hdrdir)/ruby/internal/intern/enumerator.h
handle.o: $(hdrdir)/ruby/internal/intern/error.h
handle.o: $(hdrdir)/ruby/internal/intern/eval.h
handle.o: $(hdrdir)/ruby/internal/intern/file.h
+handle.o: $(hdrdir)/ruby/internal/intern/gc.h
handle.o: $(hdrdir)/ruby/internal/intern/hash.h
handle.o: $(hdrdir)/ruby/internal/intern/io.h
handle.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -853,12 +853,12 @@ handle.o: $(hdrdir)/ruby/internal/memory.h
handle.o: $(hdrdir)/ruby/internal/method.h
handle.o: $(hdrdir)/ruby/internal/module.h
handle.o: $(hdrdir)/ruby/internal/newobj.h
+handle.o: $(hdrdir)/ruby/internal/rgengc.h
handle.o: $(hdrdir)/ruby/internal/scan_args.h
handle.o: $(hdrdir)/ruby/internal/special_consts.h
handle.o: $(hdrdir)/ruby/internal/static_assert.h
handle.o: $(hdrdir)/ruby/internal/stdalign.h
handle.o: $(hdrdir)/ruby/internal/stdbool.h
-handle.o: $(hdrdir)/ruby/internal/stdckdint.h
handle.o: $(hdrdir)/ruby/internal/symbol.h
handle.o: $(hdrdir)/ruby/internal/value.h
handle.o: $(hdrdir)/ruby/internal/value_type.h
@@ -928,7 +928,6 @@ memory_view.o: $(hdrdir)/ruby/internal/attr/noexcept.h
memory_view.o: $(hdrdir)/ruby/internal/attr/noinline.h
memory_view.o: $(hdrdir)/ruby/internal/attr/nonnull.h
memory_view.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-memory_view.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
memory_view.o: $(hdrdir)/ruby/internal/attr/pure.h
memory_view.o: $(hdrdir)/ruby/internal/attr/restrict.h
memory_view.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -997,6 +996,7 @@ memory_view.o: $(hdrdir)/ruby/internal/intern/enumerator.h
memory_view.o: $(hdrdir)/ruby/internal/intern/error.h
memory_view.o: $(hdrdir)/ruby/internal/intern/eval.h
memory_view.o: $(hdrdir)/ruby/internal/intern/file.h
+memory_view.o: $(hdrdir)/ruby/internal/intern/gc.h
memory_view.o: $(hdrdir)/ruby/internal/intern/hash.h
memory_view.o: $(hdrdir)/ruby/internal/intern/io.h
memory_view.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1027,12 +1027,12 @@ memory_view.o: $(hdrdir)/ruby/internal/memory.h
memory_view.o: $(hdrdir)/ruby/internal/method.h
memory_view.o: $(hdrdir)/ruby/internal/module.h
memory_view.o: $(hdrdir)/ruby/internal/newobj.h
+memory_view.o: $(hdrdir)/ruby/internal/rgengc.h
memory_view.o: $(hdrdir)/ruby/internal/scan_args.h
memory_view.o: $(hdrdir)/ruby/internal/special_consts.h
memory_view.o: $(hdrdir)/ruby/internal/static_assert.h
memory_view.o: $(hdrdir)/ruby/internal/stdalign.h
memory_view.o: $(hdrdir)/ruby/internal/stdbool.h
-memory_view.o: $(hdrdir)/ruby/internal/stdckdint.h
memory_view.o: $(hdrdir)/ruby/internal/symbol.h
memory_view.o: $(hdrdir)/ruby/internal/value.h
memory_view.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1104,7 +1104,6 @@ pinned.o: $(hdrdir)/ruby/internal/attr/noexcept.h
pinned.o: $(hdrdir)/ruby/internal/attr/noinline.h
pinned.o: $(hdrdir)/ruby/internal/attr/nonnull.h
pinned.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-pinned.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
pinned.o: $(hdrdir)/ruby/internal/attr/pure.h
pinned.o: $(hdrdir)/ruby/internal/attr/restrict.h
pinned.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1164,6 +1163,7 @@ pinned.o: $(hdrdir)/ruby/internal/intern/enumerator.h
pinned.o: $(hdrdir)/ruby/internal/intern/error.h
pinned.o: $(hdrdir)/ruby/internal/intern/eval.h
pinned.o: $(hdrdir)/ruby/internal/intern/file.h
+pinned.o: $(hdrdir)/ruby/internal/intern/gc.h
pinned.o: $(hdrdir)/ruby/internal/intern/hash.h
pinned.o: $(hdrdir)/ruby/internal/intern/io.h
pinned.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1194,12 +1194,12 @@ pinned.o: $(hdrdir)/ruby/internal/memory.h
pinned.o: $(hdrdir)/ruby/internal/method.h
pinned.o: $(hdrdir)/ruby/internal/module.h
pinned.o: $(hdrdir)/ruby/internal/newobj.h
+pinned.o: $(hdrdir)/ruby/internal/rgengc.h
pinned.o: $(hdrdir)/ruby/internal/scan_args.h
pinned.o: $(hdrdir)/ruby/internal/special_consts.h
pinned.o: $(hdrdir)/ruby/internal/static_assert.h
pinned.o: $(hdrdir)/ruby/internal/stdalign.h
pinned.o: $(hdrdir)/ruby/internal/stdbool.h
-pinned.o: $(hdrdir)/ruby/internal/stdckdint.h
pinned.o: $(hdrdir)/ruby/internal/symbol.h
pinned.o: $(hdrdir)/ruby/internal/value.h
pinned.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1269,7 +1269,6 @@ pointer.o: $(hdrdir)/ruby/internal/attr/noexcept.h
pointer.o: $(hdrdir)/ruby/internal/attr/noinline.h
pointer.o: $(hdrdir)/ruby/internal/attr/nonnull.h
pointer.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-pointer.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
pointer.o: $(hdrdir)/ruby/internal/attr/pure.h
pointer.o: $(hdrdir)/ruby/internal/attr/restrict.h
pointer.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1338,6 +1337,7 @@ pointer.o: $(hdrdir)/ruby/internal/intern/enumerator.h
pointer.o: $(hdrdir)/ruby/internal/intern/error.h
pointer.o: $(hdrdir)/ruby/internal/intern/eval.h
pointer.o: $(hdrdir)/ruby/internal/intern/file.h
+pointer.o: $(hdrdir)/ruby/internal/intern/gc.h
pointer.o: $(hdrdir)/ruby/internal/intern/hash.h
pointer.o: $(hdrdir)/ruby/internal/intern/io.h
pointer.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1368,12 +1368,12 @@ pointer.o: $(hdrdir)/ruby/internal/memory.h
pointer.o: $(hdrdir)/ruby/internal/method.h
pointer.o: $(hdrdir)/ruby/internal/module.h
pointer.o: $(hdrdir)/ruby/internal/newobj.h
+pointer.o: $(hdrdir)/ruby/internal/rgengc.h
pointer.o: $(hdrdir)/ruby/internal/scan_args.h
pointer.o: $(hdrdir)/ruby/internal/special_consts.h
pointer.o: $(hdrdir)/ruby/internal/static_assert.h
pointer.o: $(hdrdir)/ruby/internal/stdalign.h
pointer.o: $(hdrdir)/ruby/internal/stdbool.h
-pointer.o: $(hdrdir)/ruby/internal/stdckdint.h
pointer.o: $(hdrdir)/ruby/internal/symbol.h
pointer.o: $(hdrdir)/ruby/internal/value.h
pointer.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/fiddle/extconf.rb b/ext/fiddle/extconf.rb
index 2d85b3eea5..cf8b5223bb 100644
--- a/ext/fiddle/extconf.rb
+++ b/ext/fiddle/extconf.rb
@@ -63,11 +63,6 @@ unless bundle
end
if have_ffi_header && (have_library('ffi') || have_library('libffi'))
have_libffi = true
- checking_for("undefined FFI_GO_CLOSURES is used") do
- if egrep_cpp(/warning: 'FFI_GO_CLOSURES' is not defined/, cpp_include(ffi_header), "2>&1")
- $defs.push('-DFFI_GO_CLOSURES=0')
- end
- end
end
end
diff --git a/ext/fiddle/fiddle.c b/ext/fiddle/fiddle.c
index 91a998813a..c06cd5634a 100644
--- a/ext/fiddle/fiddle.c
+++ b/ext/fiddle/fiddle.c
@@ -1,5 +1,3 @@
-#include <stdbool.h>
-
#include <fiddle.h>
VALUE mFiddle;
@@ -60,16 +58,18 @@ rb_fiddle_free(VALUE self, VALUE addr)
/*
* call-seq: Fiddle.dlunwrap(addr)
*
- * Returns the Ruby object stored at the memory address +addr+
+ * Returns the hexadecimal representation of a memory pointer address +addr+
*
* Example:
*
- * x = Object.new
- * # => #<Object:0x0000000107c7d870>
- * Fiddle.dlwrap(x)
- * # => 4425504880
- * Fiddle.dlunwrap(_)
- * # => #<Object:0x0000000107c7d870>
+ * lib = Fiddle.dlopen('/lib64/libc-2.15.so')
+ * => #<Fiddle::Handle:0x00000001342460>
+ *
+ * lib['strcpy'].to_s(16)
+ * => "7f59de6dd240"
+ *
+ * Fiddle.dlunwrap(Fiddle.dlwrap(lib['strcpy'].to_s(16)))
+ * => "7f59de6dd240"
*/
VALUE
rb_fiddle_ptr2value(VALUE self, VALUE addr)
@@ -80,22 +80,15 @@ rb_fiddle_ptr2value(VALUE self, VALUE addr)
/*
* call-seq: Fiddle.dlwrap(val)
*
- * Returns the memory address of the Ruby object stored at +val+
+ * Returns a memory pointer of a function's hexadecimal address location +val+
*
* Example:
*
- * x = Object.new
- * # => #<Object:0x0000000107c7d870>
- * Fiddle.dlwrap(x)
- * # => 4425504880
- *
- * In the case +val+ is not a heap allocated object, this method will return
- * the tagged pointer value.
+ * lib = Fiddle.dlopen('/lib64/libc-2.15.so')
+ * => #<Fiddle::Handle:0x00000001342460>
*
- * Example:
- *
- * Fiddle.dlwrap(123)
- * # => 247
+ * Fiddle.dlwrap(lib['strcpy'].to_s(16))
+ * => 25522520
*/
static VALUE
rb_fiddle_value2ptr(VALUE self, VALUE val)
@@ -359,12 +352,6 @@ Init_fiddle(void)
*/
rb_define_const(mFiddleTypes, "UINTPTR_T", INT2NUM(TYPE_UINTPTR_T));
- /* Document-const: Fiddle::Types::BOOL
- *
- * C type - bool
- */
- rb_define_const(mFiddleTypes, "BOOL" , INT2NUM(TYPE_BOOL));
-
/* Document-const: ALIGN_VOIDP
*
* The alignment size of a void*
@@ -469,12 +456,6 @@ Init_fiddle(void)
*/
rb_define_const(mFiddle, "ALIGN_UINTPTR_T", INT2NUM(ALIGN_OF(uintptr_t)));
- /* Document-const: ALIGN_BOOL
- *
- * The alignment size of a bool
- */
- rb_define_const(mFiddle, "ALIGN_BOOL", INT2NUM(ALIGN_OF(bool)));
-
/* Document-const: WINDOWS
*
* Returns a boolean regarding whether the host is WIN32
@@ -649,12 +630,6 @@ Init_fiddle(void)
*/
rb_define_const(mFiddle, "SIZEOF_CONST_STRING", INT2NUM(sizeof(const char*)));
- /* Document-const: SIZEOF_BOOL
- *
- * size of a bool
- */
- rb_define_const(mFiddle, "SIZEOF_BOOL", INT2NUM(sizeof(bool)));
-
/* Document-const: RUBY_FREE
*
* Address of the ruby_xfree() function
@@ -709,3 +684,4 @@ Init_fiddle(void)
Init_fiddle_memory_view();
#endif
}
+/* vim: set noet sws=4 sw=4: */
diff --git a/ext/fiddle/fiddle.gemspec b/ext/fiddle/fiddle.gemspec
index fc3cbfabc7..878109395b 100644
--- a/ext/fiddle/fiddle.gemspec
+++ b/ext/fiddle/fiddle.gemspec
@@ -34,6 +34,10 @@ Gem::Specification.new do |spec|
"ext/fiddle/memory_view.c",
"ext/fiddle/pinned.c",
"ext/fiddle/pointer.c",
+ "ext/fiddle/win32/fficonfig.h",
+ "ext/fiddle/win32/libffi-3.2.1-mswin.patch",
+ "ext/fiddle/win32/libffi-config.rb",
+ "ext/fiddle/win32/libffi.mk.tmpl",
"fiddle.gemspec",
"lib/fiddle.rb",
"lib/fiddle/closure.rb",
@@ -52,5 +56,4 @@ Gem::Specification.new do |spec|
spec.required_ruby_version = ">= 2.5.0"
spec.metadata["msys2_mingw_dependencies"] = "libffi"
- spec.metadata["changelog_uri"] = "https://github.com/ruby/fiddle/releases"
end
diff --git a/ext/fiddle/fiddle.h b/ext/fiddle/fiddle.h
index 54391b95f5..10eb9ceedb 100644
--- a/ext/fiddle/fiddle.h
+++ b/ext/fiddle/fiddle.h
@@ -118,7 +118,7 @@
#define TYPE_UINT -TYPE_INT
#define TYPE_LONG 5
#define TYPE_ULONG -TYPE_LONG
-#ifdef HAVE_LONG_LONG
+#if HAVE_LONG_LONG
#define TYPE_LONG_LONG 6
#define TYPE_ULONG_LONG -TYPE_LONG_LONG
#endif
@@ -126,7 +126,6 @@
#define TYPE_DOUBLE 8
#define TYPE_VARIADIC 9
#define TYPE_CONST_STRING 10
-#define TYPE_BOOL 11
#define TYPE_INT8_T TYPE_CHAR
#define TYPE_UINT8_T -TYPE_INT8_T
@@ -197,20 +196,7 @@
#endif
#define TYPE_UINTPTR_T (-TYPE_INTPTR_T)
-/* GCC releases before GCC 4.9 had a bug in _Alignof. See GCC bug 52023
- <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023>.
- clang versions < 8.0.0 have the same bug. */
-#if defined(HAVE__ALIGNOF)
-# /* Autoconf detected availability of a sane `_Alignof()`. */
-# define ALIGN_OF(type) RB_GNUC_EXTENSION(_Alignof(type))
-#elif (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112 \
- || (defined(__GNUC__) && __GNUC__ < 4 + (__GNUC_MINOR__ < 9) \
- && !defined(__clang__)) \
- || (defined(__clang__) && __clang_major__ < 8))
-# define ALIGN_OF(type) offsetof(struct {char align_c; type align_x;}, align_x)
-#else
-# define ALIGN_OF(type) _Alignof(type)
-#endif
+#define ALIGN_OF(type) offsetof(struct {char align_c; type align_x;}, align_x)
#define ALIGN_VOIDP ALIGN_OF(void*)
#define ALIGN_CHAR ALIGN_OF(char)
@@ -237,3 +223,4 @@ typedef void (*rb_fiddle_freefunc_t)(void*);
VALUE rb_fiddle_ptr_new_wrap(void *ptr, long size, rb_fiddle_freefunc_t func, VALUE wrap0, VALUE wrap1);
#endif
+/* vim: set noet sws=4 sw=4: */
diff --git a/ext/fiddle/function.c b/ext/fiddle/function.c
index b6a105abe1..274d181d17 100644
--- a/ext/fiddle/function.c
+++ b/ext/fiddle/function.c
@@ -53,13 +53,8 @@ function_memsize(const void *p)
}
const rb_data_type_t function_data_type = {
- .wrap_struct_name = "fiddle/function",
- .function = {
- .dmark = 0,
- .dfree = deallocate,
- .dsize = function_memsize
- },
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ "fiddle/function",
+ {0, deallocate, function_memsize,},
};
static VALUE
@@ -493,3 +488,4 @@ Init_fiddle_function(void)
*/
rb_define_method(cFiddleFunction, "initialize", initialize, -1);
}
+/* vim: set noet sws=4 sw=4: */
diff --git a/ext/fiddle/handle.c b/ext/fiddle/handle.c
index 558d6d4551..ae8cc3a581 100644
--- a/ext/fiddle/handle.c
+++ b/ext/fiddle/handle.c
@@ -50,13 +50,8 @@ fiddle_handle_memsize(const void *ptr)
}
static const rb_data_type_t fiddle_handle_data_type = {
- .wrap_struct_name = "fiddle/handle",
- .function = {
- .dmark = 0,
- .dfree = fiddle_handle_free,
- .dsize = fiddle_handle_memsize
- },
- .flags = RUBY_TYPED_WB_PROTECTED,
+ "fiddle/handle",
+ {0, fiddle_handle_free, fiddle_handle_memsize,},
};
/*
@@ -587,3 +582,5 @@ Init_fiddle_handle(void)
rb_define_method(rb_cHandle, "enable_close", rb_fiddle_handle_enable_close, 0);
rb_define_method(rb_cHandle, "close_enabled?", rb_fiddle_handle_close_enabled_p, 0);
}
+
+/* vim: set noet sws=4 sw=4: */
diff --git a/ext/fiddle/lib/fiddle/cparser.rb b/ext/fiddle/lib/fiddle/cparser.rb
index 264ca166dd..9a70402953 100644
--- a/ext/fiddle/lib/fiddle/cparser.rb
+++ b/ext/fiddle/lib/fiddle/cparser.rb
@@ -165,30 +165,18 @@ module Fiddle
raise(RuntimeError, "unsupported type: #{ty}")
end
return TYPE_ULONG_LONG
- when /\Aunsigned\s+long(?:\s+int\s+)?(?:\s+\w+)?\z/,
- /\Aunsigned\s+int\s+long(?:\s+\w+)?\z/,
- /\Along(?:\s+int)?\s+unsigned(?:\s+\w+)?\z/,
- /\Aint\s+unsigned\s+long(?:\s+\w+)?\z/,
- /\A(?:int\s+)?long\s+unsigned(?:\s+\w+)?\z/
- return TYPE_ULONG
- when /\A(?:signed\s+)?long(?:\s+int\s+)?(?:\s+\w+)?\z/,
- /\A(?:signed\s+)?int\s+long(?:\s+\w+)?\z/,
- /\Along(?:\s+int)?\s+signed(?:\s+\w+)?\z/
+ when /\A(?:signed\s+)?long(?:\s+int\s+)?(?:\s+\w+)?\z/
return TYPE_LONG
- when /\Aunsigned\s+short(?:\s+int\s+)?(?:\s+\w+)?\z/,
- /\Aunsigned\s+int\s+short(?:\s+\w+)?\z/,
- /\Ashort(?:\s+int)?\s+unsigned(?:\s+\w+)?\z/,
- /\Aint\s+unsigned\s+short(?:\s+\w+)?\z/,
- /\A(?:int\s+)?short\s+unsigned(?:\s+\w+)?\z/
- return TYPE_USHORT
- when /\A(?:signed\s+)?short(?:\s+int\s+)?(?:\s+\w+)?\z/,
- /\A(?:signed\s+)?int\s+short(?:\s+\w+)?\z/,
- /\Aint\s+(?:signed\s+)?short(?:\s+\w+)?\z/
- return TYPE_SHORT
+ when /\Aunsigned\s+long(?:\s+int\s+)?(?:\s+\w+)?\z/
+ return TYPE_ULONG
when /\A(?:signed\s+)?int(?:\s+\w+)?\z/
return TYPE_INT
when /\A(?:unsigned\s+int|uint)(?:\s+\w+)?\z/
return TYPE_UINT
+ when /\A(?:signed\s+)?short(?:\s+int\s+)?(?:\s+\w+)?\z/
+ return TYPE_SHORT
+ when /\Aunsigned\s+short(?:\s+int\s+)?(?:\s+\w+)?\z/
+ return TYPE_USHORT
when /\A(?:signed\s+)?char(?:\s+\w+)?\z/
return TYPE_CHAR
when /\Aunsigned\s+char(?:\s+\w+)?\z/
@@ -247,8 +235,6 @@ module Fiddle
return TYPE_INTPTR_T
when /\Auintptr_t(?:\s+\w+)?\z/
return TYPE_UINTPTR_T
- when "bool"
- return TYPE_BOOL
when /\*/, /\[[\s\d]*\]/
return TYPE_VOIDP
when "..."
diff --git a/ext/fiddle/lib/fiddle/import.rb b/ext/fiddle/lib/fiddle/import.rb
index 050708fb96..09ffcef544 100644
--- a/ext/fiddle/lib/fiddle/import.rb
+++ b/ext/fiddle/lib/fiddle/import.rb
@@ -119,8 +119,6 @@ module Fiddle
return SIZEOF_VOIDP
when TYPE_CONST_STRING
return SIZEOF_CONST_STRING
- when TYPE_BOOL
- return SIZEOF_BOOL
else
if defined?(TYPE_LONG_LONG) and
ty == TYPE_LONG_LONG
diff --git a/ext/fiddle/lib/fiddle/pack.rb b/ext/fiddle/lib/fiddle/pack.rb
index 81088f402b..545b985d50 100644
--- a/ext/fiddle/lib/fiddle/pack.rb
+++ b/ext/fiddle/lib/fiddle/pack.rb
@@ -15,7 +15,6 @@ module Fiddle
TYPE_USHORT => ALIGN_SHORT,
TYPE_UINT => ALIGN_INT,
TYPE_ULONG => ALIGN_LONG,
- TYPE_BOOL => ALIGN_BOOL,
}
PACK_MAP = {
@@ -31,16 +30,6 @@ module Fiddle
TYPE_UINT => "I!",
TYPE_ULONG => "L!",
}
- case SIZEOF_BOOL
- when SIZEOF_CHAR
- PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_UCHAR]
- when SIZEOF_SHORT
- PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_USHORT]
- when SIZEOF_INT
- PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_UINT]
- when SIZEOF_LONG
- PACK_MAP[TYPE_BOOL] = PACK_MAP[TYPE_ULONG]
- end
SIZE_MAP = {
TYPE_VOIDP => SIZEOF_VOIDP,
@@ -54,7 +43,6 @@ module Fiddle
TYPE_USHORT => SIZEOF_SHORT,
TYPE_UINT => SIZEOF_INT,
TYPE_ULONG => SIZEOF_LONG,
- TYPE_BOOL => SIZEOF_BOOL,
}
if defined?(TYPE_LONG_LONG)
ALIGN_MAP[TYPE_LONG_LONG] = ALIGN_MAP[TYPE_ULONG_LONG] = ALIGN_LONG_LONG
diff --git a/ext/fiddle/lib/fiddle/value.rb b/ext/fiddle/lib/fiddle/value.rb
index 5f0b2e951e..01fec1c206 100644
--- a/ext/fiddle/lib/fiddle/value.rb
+++ b/ext/fiddle/lib/fiddle/value.rb
@@ -6,17 +6,17 @@ module Fiddle
def unsigned_value(val, ty)
case ty.abs
when TYPE_CHAR
- [val].pack("c").unpack1("C")
+ [val].pack("c").unpack("C")[0]
when TYPE_SHORT
- [val].pack("s!").unpack1("S!")
+ [val].pack("s!").unpack("S!")[0]
when TYPE_INT
- [val].pack("i!").unpack1("I!")
+ [val].pack("i!").unpack("I!")[0]
when TYPE_LONG
- [val].pack("l!").unpack1("L!")
+ [val].pack("l!").unpack("L!")[0]
else
if defined?(TYPE_LONG_LONG) and
ty.abs == TYPE_LONG_LONG
- [val].pack("q").unpack1("Q")
+ [val].pack("q").unpack("Q")[0]
else
val
end
@@ -26,17 +26,17 @@ module Fiddle
def signed_value(val, ty)
case ty.abs
when TYPE_CHAR
- [val].pack("C").unpack1("c")
+ [val].pack("C").unpack("c")[0]
when TYPE_SHORT
- [val].pack("S!").unpack1("s!")
+ [val].pack("S!").unpack("s!")[0]
when TYPE_INT
- [val].pack("I!").unpack1("i!")
+ [val].pack("I!").unpack("i!")[0]
when TYPE_LONG
- [val].pack("L!").unpack1("l!")
+ [val].pack("L!").unpack("l!")[0]
else
if defined?(TYPE_LONG_LONG) and
ty.abs == TYPE_LONG_LONG
- [val].pack("Q").unpack1("q")
+ [val].pack("Q").unpack("q")[0]
else
val
end
@@ -80,11 +80,11 @@ module Fiddle
else
case SIZEOF_VOIDP
when SIZEOF_LONG
- return [arg].pack("p").unpack1("l!")
+ return [arg].pack("p").unpack("l!")[0]
else
if defined?(SIZEOF_LONG_LONG) and
SIZEOF_VOIDP == SIZEOF_LONG_LONG
- return [arg].pack("p").unpack1("q")
+ return [arg].pack("p").unpack("q")[0]
else
raise(RuntimeError, "sizeof(void*)?")
end
@@ -102,8 +102,10 @@ module Fiddle
return val.unpack('C*')
end
end
+ return arg
+ else
+ return arg
end
- return arg
else
if( arg.respond_to?(:to_ptr) )
return arg.to_ptr.to_i
diff --git a/ext/fiddle/lib/fiddle/version.rb b/ext/fiddle/lib/fiddle/version.rb
index 3444e24f92..719dc62e37 100644
--- a/ext/fiddle/lib/fiddle/version.rb
+++ b/ext/fiddle/lib/fiddle/version.rb
@@ -1,3 +1,3 @@
module Fiddle
- VERSION = "1.1.3.dev"
+ VERSION = "1.1.1"
end
diff --git a/ext/fiddle/pointer.c b/ext/fiddle/pointer.c
index 1b7d7a69f6..15107e3862 100644
--- a/ext/fiddle/pointer.c
+++ b/ext/fiddle/pointer.c
@@ -88,13 +88,8 @@ fiddle_ptr_memsize(const void *ptr)
}
static const rb_data_type_t fiddle_ptr_data_type = {
- .wrap_struct_name = "fiddle/pointer",
- .function = {
- .dmark = fiddle_ptr_mark,
- .dfree = fiddle_ptr_free,
- .dsize = fiddle_ptr_memsize,
- },
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
+ "fiddle/pointer",
+ {fiddle_ptr_mark, fiddle_ptr_free, fiddle_ptr_memsize,},
};
#ifdef HAVE_RUBY_MEMORY_VIEW_H
@@ -140,8 +135,8 @@ rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func, VALUE wra
data->free = func;
data->freed = false;
data->size = size;
- RB_OBJ_WRITE(val, &data->wrap[0], wrap0);
- RB_OBJ_WRITE(val, &data->wrap[1], wrap1);
+ data->wrap[0] = wrap0;
+ data->wrap[1] = wrap1;
return val;
}
@@ -240,8 +235,8 @@ rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
/* Free previous memory. Use of inappropriate initialize may cause SEGV. */
(*(data->free))(data->ptr);
}
- RB_OBJ_WRITE(self, &data->wrap[0], wrap);
- RB_OBJ_WRITE(self, &data->wrap[1], funcwrap);
+ data->wrap[0] = wrap;
+ data->wrap[1] = funcwrap;
data->ptr = p;
data->size = s;
data->free = f;
@@ -319,7 +314,7 @@ rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
}
obj = rb_fiddle_ptr_malloc(klass, s,f);
- if (wrap) RB_OBJ_WRITE(obj, &RPTR_DATA(obj)->wrap[1], wrap);
+ if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;
if (rb_block_given_p()) {
if (!f) {
@@ -800,37 +795,10 @@ rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
if (num == val) wrap = 0;
ptr = rb_fiddle_ptr_new(NUM2PTR(num), 0, NULL);
}
- if (wrap) RB_OBJ_WRITE(ptr, &RPTR_DATA(ptr)->wrap[0], wrap);
+ if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
return ptr;
}
-/*
- * call-seq:
- * Fiddle::Pointer.read(address, len) => string
- *
- * Or read the memory at address +address+ with length +len+ and return a
- * string with that memory
- */
-
-static VALUE
-rb_fiddle_ptr_read_mem(VALUE klass, VALUE address, VALUE len)
-{
- return rb_str_new((char *)NUM2PTR(address), NUM2ULONG(len));
-}
-
-/*
- * call-seq:
- * Fiddle::Pointer.write(address, str)
- *
- * Write bytes in +str+ to the location pointed to by +address+.
- */
-static VALUE
-rb_fiddle_ptr_write_mem(VALUE klass, VALUE addr, VALUE str)
-{
- memcpy(NUM2PTR(addr), StringValuePtr(str), RSTRING_LEN(str));
- return str;
-}
-
void
Init_fiddle_pointer(void)
{
@@ -847,8 +815,6 @@ Init_fiddle_pointer(void)
rb_define_singleton_method(rb_cPointer, "malloc", rb_fiddle_ptr_s_malloc, -1);
rb_define_singleton_method(rb_cPointer, "to_ptr", rb_fiddle_ptr_s_to_ptr, 1);
rb_define_singleton_method(rb_cPointer, "[]", rb_fiddle_ptr_s_to_ptr, 1);
- rb_define_singleton_method(rb_cPointer, "read", rb_fiddle_ptr_read_mem, 2);
- rb_define_singleton_method(rb_cPointer, "write", rb_fiddle_ptr_write_mem, 2);
rb_define_method(rb_cPointer, "initialize", rb_fiddle_ptr_initialize, -1);
rb_define_method(rb_cPointer, "free=", rb_fiddle_ptr_free_set, 1);
rb_define_method(rb_cPointer, "free", rb_fiddle_ptr_free_get, 0);
diff --git a/ext/fiddle/win32/fficonfig.h b/ext/fiddle/win32/fficonfig.h
new file mode 100644
index 0000000000..776808159c
--- /dev/null
+++ b/ext/fiddle/win32/fficonfig.h
@@ -0,0 +1,29 @@
+#define HAVE_ALLOCA 1
+#define HAVE_MEMCPY 1
+#define HAVE_MEMORY_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRING_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TYPES_H 1
+#if _MSC_VER >= 1600
+#define HAVE_INTTYPES_H 1
+#define HAVE_STDINT_H 1
+#endif
+
+#define SIZEOF_DOUBLE 8
+#if defined(X86_WIN64)
+#define SIZEOF_SIZE_T 8
+#else
+#define SIZEOF_SIZE_T 4
+#endif
+
+#define STACK_DIRECTION -1
+
+#define STDC_HEADERS 1
+
+#ifdef LIBFFI_ASM
+#define FFI_HIDDEN(name)
+#else
+#define FFI_HIDDEN
+#endif
+
diff --git a/ext/fiddle/win32/libffi-3.2.1-mswin.patch b/ext/fiddle/win32/libffi-3.2.1-mswin.patch
new file mode 100644
index 0000000000..f9100e703d
--- /dev/null
+++ b/ext/fiddle/win32/libffi-3.2.1-mswin.patch
@@ -0,0 +1,191 @@
+diff -ru libffi-3.2.1/src/x86/ffi.c libffi-3.2.1/src/x86/ffi.c
+--- libffi-3.2.1/src/x86/ffi.c 2014-11-08 21:47:24.000000000 +0900
++++ libffi-3.2.1/src/x86/ffi.c 2014-12-25 18:46:14.806761900 +0900
+@@ -99,11 +99,13 @@
+ i != 0;
+ i--, p_arg += dir, p_argv += dir)
+ {
++ size_t z;
++
+ /* Align if necessary */
+ if ((sizeof(void*) - 1) & (size_t) argp)
+ argp = (char *) ALIGN(argp, sizeof(void*));
+
+- size_t z = (*p_arg)->size;
++ z = (*p_arg)->size;
+
+ #ifdef X86_WIN64
+ if (z > FFI_SIZEOF_ARG
+@@ -202,6 +204,7 @@
+ on top of stack, so that those can be moved to registers by call-handler. */
+ if (stack_args_count > 0)
+ {
++ int i;
+ if (dir < 0 && stack_args_count > 1)
+ {
+ /* Reverse order if iterating arguments backwards */
+@@ -210,7 +213,6 @@
+ *(ffi_arg*) p_stack_data[stack_args_count - 1] = tmp;
+ }
+
+- int i;
+ for (i = 0; i < stack_args_count; i++)
+ {
+ if (p_stack_data[i] != argp2)
+@@ -569,11 +571,12 @@
+ i < cif->nargs && passed_regs < max_stack_count;
+ i++, p_arg++)
+ {
++ size_t sz;
+ if ((*p_arg)->type == FFI_TYPE_FLOAT
+ || (*p_arg)->type == FFI_TYPE_STRUCT)
+ continue;
+
+- size_t sz = (*p_arg)->size;
++ sz = (*p_arg)->size;
+ if(sz == 0 || sz > FFI_SIZEOF_ARG)
+ continue;
+
+@@ -599,11 +602,13 @@
+ i != 0;
+ i--, p_arg += dir, p_argv += dir)
+ {
++ size_t z;
++
+ /* Align if necessary */
+ if ((sizeof(void*) - 1) & (size_t) argp)
+ argp = (char *) ALIGN(argp, sizeof(void*));
+
+- size_t z = (*p_arg)->size;
++ z = (*p_arg)->size;
+
+ #ifdef X86_WIN64
+ if (z > FFI_SIZEOF_ARG
+@@ -642,7 +647,7 @@
+ #endif
+ }
+
+- return (size_t)argp - (size_t)stack;
++ return (int)((size_t)argp - (size_t)stack);
+ }
+
+ #define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \
+@@ -855,11 +860,12 @@
+
+ for (i = 0; i < cif->nargs && passed_regs <= max_regs; i++)
+ {
++ size_t sz;
+ if (cif->arg_types[i]->type == FFI_TYPE_FLOAT
+ || cif->arg_types[i]->type == FFI_TYPE_STRUCT)
+ continue;
+
+- size_t sz = cif->arg_types[i]->size;
++ sz = cif->arg_types[i]->size;
+ if (sz == 0 || sz > FFI_SIZEOF_ARG)
+ continue;
+
+diff -ru libffi-3.2.1/src/x86/ffitarget.h libffi-3.2.1/src/x86/ffitarget.h
+--- libffi-3.2.1/src/x86/ffitarget.h 2014-11-08 21:47:24.000000000 +0900
++++ libffi-3.2.1/src/x86/ffitarget.h 2014-12-22 15:45:54.000000000 +0900
+@@ -50,7 +50,9 @@
+ #endif
+
+ #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
++#ifndef _MSC_VER
+ #define FFI_TARGET_HAS_COMPLEX_TYPE
++#endif
+
+ /* ---- Generic type definitions ----------------------------------------- */
+
+diff -ru libffi-3.2.1/src/x86/win64.S libffi-3.2.1/src/x86/win64.S
+--- libffi-3.2.1/src/x86/win64.S 2014-11-08 21:47:24.000000000 +0900
++++ libffi-3.2.1/src/x86/win64.S 2014-12-22 16:14:40.000000000 +0900
+@@ -127,7 +127,7 @@
+
+ mov rcx, QWORD PTR RVALUE[rbp]
+ mov DWORD PTR [rcx], eax
+- jmp ret_void$
++ jmp SHORT ret_void$
+
+ ret_struct2b$:
+ cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_2B
+@@ -135,7 +135,7 @@
+
+ mov rcx, QWORD PTR RVALUE[rbp]
+ mov WORD PTR [rcx], ax
+- jmp ret_void$
++ jmp SHORT ret_void$
+
+ ret_struct1b$:
+ cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_1B
+@@ -143,7 +143,7 @@
+
+ mov rcx, QWORD PTR RVALUE[rbp]
+ mov BYTE PTR [rcx], al
+- jmp ret_void$
++ jmp SHORT ret_void$
+
+ ret_uint8$:
+ cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT8
+@@ -152,7 +152,7 @@
+ mov rcx, QWORD PTR RVALUE[rbp]
+ movzx rax, al
+ mov QWORD PTR [rcx], rax
+- jmp ret_void$
++ jmp SHORT ret_void$
+
+ ret_sint8$:
+ cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT8
+@@ -161,7 +161,7 @@
+ mov rcx, QWORD PTR RVALUE[rbp]
+ movsx rax, al
+ mov QWORD PTR [rcx], rax
+- jmp ret_void$
++ jmp SHORT ret_void$
+
+ ret_uint16$:
+ cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT16
+@@ -188,7 +188,13 @@
+ mov rcx, QWORD PTR RVALUE[rbp]
+ mov eax, eax
+ mov QWORD PTR [rcx], rax
+- jmp SHORT ret_void$
++
++ret_void$:
++ xor rax, rax
++
++ lea rsp, QWORD PTR [rbp+16]
++ pop rbp
++ ret 0
+
+ ret_sint32$:
+ cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT32
+@@ -247,13 +253,6 @@
+ cdqe
+ mov QWORD PTR [rcx], rax
+ jmp SHORT ret_void$
+-
+-ret_void$:
+- xor rax, rax
+-
+- lea rsp, QWORD PTR [rbp+16]
+- pop rbp
+- ret 0
+ ffi_call_win64 ENDP
+ _TEXT ENDS
+ END
+diff -ru libffi-3.2.1/include/ffi.h.in libffi-3.2.1/include/ffi.h.in
+--- libffi-3.2.1/include/ffi.h.in 2014-11-08 21:47:24.000000000 +0900
++++ libffi-3.2.1/include/ffi.h.in 2015-01-11 12:35:30.000000000 +0900
+@@ -103,6 +103,11 @@
+ # undef FFI_64_BIT_MAX
+ # define FFI_64_BIT_MAX 9223372036854775807LL
+ # endif
++# ifdef _MSC_VER
++# define FFI_LONG_LONG_MAX _I64_MAX
++# undef FFI_64_BIT_MAX
++# define FFI_64_BIT_MAX 9223372036854775807I64
++# endif
+ # endif
+ #endif
+
diff --git a/ext/fiddle/win32/libffi-config.rb b/ext/fiddle/win32/libffi-config.rb
new file mode 100755
index 0000000000..985fc29d36
--- /dev/null
+++ b/ext/fiddle/win32/libffi-config.rb
@@ -0,0 +1,48 @@
+#!/usr/bin/ruby
+# frozen_string_literal: true
+require 'fileutils'
+
+basedir = File.dirname(__FILE__)
+conf = {}
+enable = {}
+until ARGV.empty?
+ arg = ARGV.shift
+ case arg
+ when '-C'
+ # ignore
+ when /\A--srcdir=(.*)/
+ conf['SRCDIR'] = srcdir = $1
+ when /\A(CC|CFLAGS|CXX|CXXFLAGS|LD|LDFLAGS)=(.*)/
+ conf[$1] = $2
+ when /\A--host=(.*)/
+ host = $1
+ when /\A--enable-([^=]+)(?:=(.*))?/
+ enable[$1] = $2 || true
+ when /\A--disable-([^=]+)/
+ enable[$1] = false
+ end
+end
+
+IO.foreach("#{srcdir}/configure.ac") do |line|
+ if /^AC_INIT\((.*)\)/ =~ line
+ version = $1.split(/,\s*/)[1]
+ version.gsub!(/\A\[|\]\z/, '')
+ conf['VERSION'] = version
+ break
+ end
+end
+
+builddir = srcdir == "." ? (enable['builddir'] || ".") : "."
+conf['TARGET'] = /^x64/ =~ host ? "X86_WIN64" : "X86_WIN32"
+
+FileUtils.mkdir_p([builddir, "#{builddir}/include", "#{builddir}/src/x86"])
+FileUtils.cp("#{basedir}/fficonfig.h", ".", preserve: true)
+
+hdr = IO.binread("#{srcdir}/include/ffi.h.in")
+hdr.gsub!(/@(\w+)@/) {conf[$1] || $&}
+hdr.gsub!(/^(#if\s+)@\w+@/, '\10')
+IO.binwrite("#{builddir}/include/ffi.h", hdr)
+
+mk = IO.binread("#{basedir}/libffi.mk.tmpl")
+mk.gsub!(/@(\w+)@/) {conf[$1] || $&}
+IO.binwrite("Makefile", mk)
diff --git a/ext/fiddle/win32/libffi.mk.tmpl b/ext/fiddle/win32/libffi.mk.tmpl
new file mode 100644
index 0000000000..2a16e8efec
--- /dev/null
+++ b/ext/fiddle/win32/libffi.mk.tmpl
@@ -0,0 +1,96 @@
+# -*- makefile -*-
+# ====================================================================
+#
+# libffi Windows Makefile
+#
+#
+# ====================================================================
+#
+NAME = ffi
+TARGET = @TARGET@
+CC = cl
+!if "$(TARGET)" == "X86_WIN64"
+AS = ml64
+!else
+AS = ml
+!endif
+AR = link
+DLEXT = dll
+OBJEXT = obj
+LIBEXT = lib
+TOPDIR = @SRCDIR@
+CPP = $(CC) -EP
+CFLAGS = @CFLAGS@
+ARFLAGS = -lib
+ASFLAGS = -coff -W3 -Cx
+INCLUDES= -I. -I./include -I./src/x86 \
+ -I$(TOPDIR)/include -I$(TOPDIR)/include/src/x86
+
+SRCDIR = $(TOPDIR)/src
+WORKDIR = ./.libs
+BUILDDIR= ./src
+LIBNAME = lib$(NAME)
+STATICLIB= $(WORKDIR)/$(LIBNAME)_convenience.$(LIBEXT)
+
+HEADERS = \
+ ./fficonfig.h
+FFI_HEADERS = \
+ ./include/ffi.h \
+ ./include/ffitarget.h
+
+!if "$(TARGET)" == "X86_WIN32"
+OSSRC = win32
+!else if "$(TARGET)" == "X86_WIN64"
+OSSRC = win64
+!else
+! error unknown target: $(TARGET)
+!endif
+
+OBJECTS = \
+ $(BUILDDIR)/closures.$(OBJEXT) \
+ $(BUILDDIR)/debug.$(OBJEXT) \
+ $(BUILDDIR)/java_raw_api.$(OBJEXT) \
+ $(BUILDDIR)/prep_cif.$(OBJEXT) \
+ $(BUILDDIR)/raw_api.$(OBJEXT) \
+ $(BUILDDIR)/types.$(OBJEXT) \
+ $(BUILDDIR)/x86/ffi.$(OBJEXT) \
+ $(BUILDDIR)/x86/$(OSSRC).$(OBJEXT)
+ASMSRCS = \
+ $(BUILDDIR)/x86/$(OSSRC).asm
+
+.SUFFIXES : .S .asm
+
+all: $(WORKDIR) $(STATICLIB)
+
+{$(SRCDIR)}.c{$(BUILDDIR)}.$(OBJEXT):
+ $(CC) -c $(CFLAGS) $(INCLUDES) -Fo$(@:\=/) -Fd$(WORKDIR)/$(NAME)-src $(<:\=/)
+
+{$(SRCDIR)/x86}.c{$(BUILDDIR)/x86}.$(OBJEXT):
+ $(CC) -c $(CFLAGS) $(INCLUDES) -Fo$(@:\=/) -Fd$(WORKDIR)/$(NAME)-src $(<:\=/)
+
+{$(SRCDIR)/x86}.S{$(BUILDDIR)/x86}.asm:
+ $(CPP) $(CFLAGS) $(INCLUDES) $(<:\=/) >$(@:\=/)
+
+{$(BUILDDIR)/x86}.asm{$(BUILDDIR)/x86}.$(OBJEXT):
+ cd $(@D) && $(AS) -c $(ASFLAGS) -Fo $(@F) $(<F)
+
+$(BUILDDIR)/x86/$(OSSRC).asm: $(SRCDIR)/x86/$(OSSRC).S
+
+$(OBJECTS): $(FFI_HEADERS) $(HEADERS)
+
+$(WORKDIR):
+ -@if not exist "$(WORKDIR:/=\)\$(NULL)" mkdir $(WORKDIR:/=\)
+
+$(STATICLIB): $(WORKDIR) $(OBJECTS)
+ $(AR) $(ARFLAGS) -out:$(STATICLIB) @<<
+ $(OBJECTS)
+<<
+
+clean:
+ -@del /Q $(OBJECTS:/=\) 2>NUL
+ -@del /Q $(ASMSRCS:/=\) 2>NUL
+ -@del /Q /S $(WORKDIR:/=\) 2>NUL
+
+distclean: clean
+ -@del /Q $(HEADERS:/=\) $(FFI_HEADERS:/=\) 2>NUL
+ -@del /Q Makefile 2>NUL
diff --git a/ext/io/console/.document b/ext/io/console/.document
deleted file mode 100644
index 945a377256..0000000000
--- a/ext/io/console/.document
+++ /dev/null
@@ -1,2 +0,0 @@
-console.c
-lib/size.rb
diff --git a/ext/io/console/console.c b/ext/io/console/console.c
index 85e6a0613e..21454a73fa 100644
--- a/ext/io/console/console.c
+++ b/ext/io/console/console.c
@@ -2,10 +2,6 @@
/*
* console IO module
*/
-
-static const char *const
-IO_CONSOLE_VERSION = "0.7.2";
-
#include "ruby.h"
#include "ruby/io.h"
#include "ruby/thread.h"
@@ -79,10 +75,10 @@ getattr(int fd, conmode *t)
#define SET_LAST_ERROR (0)
#endif
-#define CSI "\x1b\x5b"
-
-static ID id_getc, id_close;
-static ID id_gets, id_flush, id_chomp_bang;
+static ID id_getc, id_console, id_close;
+#if ENABLE_IO_GETPASS
+static ID id_gets, id_chomp_bang;
+#endif
#if defined HAVE_RUBY_FIBER_SCHEDULER_H
# include "ruby/fiber/scheduler.h"
@@ -91,41 +87,7 @@ extern VALUE rb_scheduler_timeout(struct timeval *timeout);
# define rb_fiber_scheduler_make_timeout rb_scheduler_timeout
#endif
-#ifndef HAVE_RB_IO_DESCRIPTOR
-static int
-io_descriptor_fallback(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- return fptr->fd;
-}
-#define rb_io_descriptor io_descriptor_fallback
-#endif
-
-#ifndef HAVE_RB_IO_PATH
-static VALUE
-io_path_fallback(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- return fptr->pathv;
-}
-#define rb_io_path io_path_fallback
-#endif
-
-#ifndef HAVE_RB_IO_GET_WRITE_IO
-static VALUE
-io_get_write_io_fallback(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- VALUE wio = fptr->tied_io_for_writing;
- return wio ? wio : io;
-}
-#define rb_io_get_write_io io_get_write_io_fallback
-#endif
-
-#define sys_fail(io) rb_sys_fail_str(rb_io_path(io))
+#define sys_fail_fptr(fptr) rb_sys_fail_str((fptr)->pathv)
#ifndef HAVE_RB_F_SEND
#ifndef RB_PASS_CALLED_KEYWORDS
@@ -331,21 +293,33 @@ set_ttymode(int fd, conmode *t, void (*setter)(conmode *, void *), void *arg)
return setattr(fd, &r);
}
-#define GetReadFD(io) rb_io_descriptor(io)
-#define GetWriteFD(io) rb_io_descriptor(rb_io_get_write_io(io))
+#define GetReadFD(fptr) ((fptr)->fd)
+
+static inline int
+get_write_fd(const rb_io_t *fptr)
+{
+ VALUE wio = fptr->tied_io_for_writing;
+ rb_io_t *ofptr;
+ if (!wio) return fptr->fd;
+ GetOpenFile(wio, ofptr);
+ return ofptr->fd;
+}
+#define GetWriteFD(fptr) get_write_fd(fptr)
#define FD_PER_IO 2
static VALUE
ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, void *), void *arg)
{
+ rb_io_t *fptr;
int status = -1;
int error = 0;
int fd[FD_PER_IO];
conmode t[FD_PER_IO];
VALUE result = Qnil;
- fd[0] = GetReadFD(io);
+ GetOpenFile(io, fptr);
+ fd[0] = GetReadFD(fptr);
if (fd[0] != -1) {
if (set_ttymode(fd[0], t+0, setter, arg)) {
status = 0;
@@ -355,7 +329,7 @@ ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, vo
fd[0] = -1;
}
}
- fd[1] = GetWriteFD(io);
+ fd[1] = GetWriteFD(fptr);
if (fd[1] != -1 && fd[1] != fd[0]) {
if (set_ttymode(fd[1], t+1, setter, arg)) {
status = 0;
@@ -368,13 +342,14 @@ ttymode(VALUE io, VALUE (*func)(VALUE), VALUE farg, void (*setter)(conmode *, vo
if (status == 0) {
result = rb_protect(func, farg, &status);
}
- if (fd[0] != -1 && fd[0] == GetReadFD(io)) {
+ GetOpenFile(io, fptr);
+ if (fd[0] != -1 && fd[0] == GetReadFD(fptr)) {
if (!setattr(fd[0], t+0)) {
error = errno;
status = -1;
}
}
- if (fd[1] != -1 && fd[1] != fd[0] && fd[1] == GetWriteFD(io)) {
+ if (fd[1] != -1 && fd[1] != fd[0] && fd[1] == GetWriteFD(fptr)) {
if (!setattr(fd[1], t+1)) {
error = errno;
status = -1;
@@ -460,11 +435,15 @@ static VALUE
console_set_raw(int argc, VALUE *argv, VALUE io)
{
conmode t;
+ rb_io_t *fptr;
+ int fd;
rawmode_arg_t opts, *optp = rawmode_opt(&argc, argv, 0, 0, &opts);
- int fd = GetReadFD(io);
- if (!getattr(fd, &t)) sys_fail(io);
+
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
+ if (!getattr(fd, &t)) sys_fail_fptr(fptr);
set_rawmode(&t, optp);
- if (!setattr(fd, &t)) sys_fail(io);
+ if (!setattr(fd, &t)) sys_fail_fptr(fptr);
return io;
}
@@ -500,10 +479,14 @@ static VALUE
console_set_cooked(VALUE io)
{
conmode t;
- int fd = GetReadFD(io);
- if (!getattr(fd, &t)) sys_fail(io);
+ rb_io_t *fptr;
+ int fd;
+
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
+ if (!getattr(fd, &t)) sys_fail_fptr(fptr);
set_cookedmode(&t, NULL);
- if (!setattr(fd, &t)) sys_fail(io);
+ if (!setattr(fd, &t)) sys_fail_fptr(fptr);
return io;
}
@@ -655,17 +638,17 @@ static VALUE
console_set_echo(VALUE io, VALUE f)
{
conmode t;
- int fd = GetReadFD(io);
-
- if (!getattr(fd, &t)) sys_fail(io);
+ rb_io_t *fptr;
+ int fd;
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
+ if (!getattr(fd, &t)) sys_fail_fptr(fptr);
if (RTEST(f))
- set_echo(&t, NULL);
+ set_echo(&t, NULL);
else
- set_noecho(&t, NULL);
-
- if (!setattr(fd, &t)) sys_fail(io);
-
+ set_noecho(&t, NULL);
+ if (!setattr(fd, &t)) sys_fail_fptr(fptr);
return io;
}
@@ -681,9 +664,12 @@ static VALUE
console_echo_p(VALUE io)
{
conmode t;
- int fd = GetReadFD(io);
+ rb_io_t *fptr;
+ int fd;
- if (!getattr(fd, &t)) sys_fail(io);
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
+ if (!getattr(fd, &t)) sys_fail_fptr(fptr);
return echo_p(&t) ? Qtrue : Qfalse;
}
@@ -762,9 +748,12 @@ static VALUE
console_conmode_get(VALUE io)
{
conmode t;
- int fd = GetReadFD(io);
+ rb_io_t *fptr;
+ int fd;
- if (!getattr(fd, &t)) sys_fail(io);
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
+ if (!getattr(fd, &t)) sys_fail_fptr(fptr);
return conmode_new(cConmode, &t);
}
@@ -781,12 +770,14 @@ static VALUE
console_conmode_set(VALUE io, VALUE mode)
{
conmode *t, r;
- int fd = GetReadFD(io);
+ rb_io_t *fptr;
+ int fd;
TypedData_Get_Struct(mode, conmode, &conmode_type, t);
r = *t;
-
- if (!setattr(fd, &r)) sys_fail(io);
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
+ if (!setattr(fd, &r)) sys_fail_fptr(fptr);
return mode;
}
@@ -822,9 +813,13 @@ typedef CONSOLE_SCREEN_BUFFER_INFO rb_console_size_t;
static VALUE
console_winsize(VALUE io)
{
+ rb_io_t *fptr;
+ int fd;
rb_console_size_t ws;
- int fd = GetWriteFD(io);
- if (!getwinsize(fd, &ws)) sys_fail(io);
+
+ GetOpenFile(io, fptr);
+ fd = GetWriteFD(fptr);
+ if (!getwinsize(fd, &ws)) sys_fail_fptr(fptr);
return rb_assoc_new(INT2NUM(winsize_row(&ws)), INT2NUM(winsize_col(&ws)));
}
@@ -840,6 +835,7 @@ console_winsize(VALUE io)
static VALUE
console_set_winsize(VALUE io, VALUE size)
{
+ rb_io_t *fptr;
rb_console_size_t ws;
#if defined _WIN32
HANDLE wh;
@@ -848,17 +844,20 @@ console_set_winsize(VALUE io, VALUE size)
#endif
VALUE row, col, xpixel, ypixel;
const VALUE *sz;
- long sizelen;
int fd;
+ long sizelen;
+ GetOpenFile(io, fptr);
size = rb_Array(size);
if ((sizelen = RARRAY_LEN(size)) != 2 && sizelen != 4) {
- rb_raise(rb_eArgError, "wrong number of arguments (given %ld, expected 2 or 4)", sizelen);
+ rb_raise(rb_eArgError,
+ "wrong number of arguments (given %ld, expected 2 or 4)",
+ sizelen);
}
sz = RARRAY_CONST_PTR(size);
row = sz[0], col = sz[1], xpixel = ypixel = Qnil;
if (sizelen == 4) xpixel = sz[2], ypixel = sz[3];
- fd = GetWriteFD(io);
+ fd = GetWriteFD(fptr);
#if defined TIOCSWINSZ
ws.ws_row = ws.ws_col = ws.ws_xpixel = ws.ws_ypixel = 0;
#define SET(m) ws.ws_##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
@@ -867,7 +866,7 @@ console_set_winsize(VALUE io, VALUE size)
SET(xpixel);
SET(ypixel);
#undef SET
- if (!setwinsize(fd, &ws)) sys_fail(io);
+ if (!setwinsize(fd, &ws)) sys_fail_fptr(fptr);
#elif defined _WIN32
wh = (HANDLE)rb_w32_get_osfhandle(fd);
#define SET(m) new##m = NIL_P(m) ? 0 : (unsigned short)NUM2UINT(m)
@@ -902,23 +901,15 @@ console_set_winsize(VALUE io, VALUE size)
#endif
#ifdef _WIN32
-/*
- * call-seq:
- * io.check_winsize_changed { ... } -> io
- *
- * Yields while console input events are queued.
- *
- * This method is Windows only.
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_check_winsize_changed(VALUE io)
{
+ rb_io_t *fptr;
HANDLE h;
DWORD num;
- h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(io));
+ GetOpenFile(io, fptr);
+ h = (HANDLE)rb_w32_get_osfhandle(GetReadFD(fptr));
while (GetNumberOfConsoleInputEvents(h, &num) && num > 0) {
INPUT_RECORD rec;
if (ReadConsoleInput(h, &rec, 1, &num)) {
@@ -944,11 +935,15 @@ console_check_winsize_changed(VALUE io)
static VALUE
console_iflush(VALUE io)
{
+ rb_io_t *fptr;
+ int fd;
+
+ GetOpenFile(io, fptr);
+ fd = GetReadFD(fptr);
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
- int fd = GetReadFD(io);
- if (tcflush(fd, TCIFLUSH)) sys_fail(io);
+ if (tcflush(fd, TCIFLUSH)) sys_fail_fptr(fptr);
#endif
-
+ (void)fd;
return io;
}
@@ -963,9 +958,13 @@ console_iflush(VALUE io)
static VALUE
console_oflush(VALUE io)
{
- int fd = GetWriteFD(io);
+ rb_io_t *fptr;
+ int fd;
+
+ GetOpenFile(io, fptr);
+ fd = GetWriteFD(fptr);
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
- if (tcflush(fd, TCOFLUSH)) sys_fail(io);
+ if (tcflush(fd, TCOFLUSH)) sys_fail_fptr(fptr);
#endif
(void)fd;
return io;
@@ -982,38 +981,40 @@ console_oflush(VALUE io)
static VALUE
console_ioflush(VALUE io)
{
+ rb_io_t *fptr;
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
- int fd1 = GetReadFD(io);
- int fd2 = GetWriteFD(io);
+ int fd1, fd2;
+#endif
+ GetOpenFile(io, fptr);
+#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H
+ fd1 = GetReadFD(fptr);
+ fd2 = GetWriteFD(fptr);
if (fd2 != -1 && fd1 != fd2) {
- if (tcflush(fd1, TCIFLUSH)) sys_fail(io);
- if (tcflush(fd2, TCOFLUSH)) sys_fail(io);
+ if (tcflush(fd1, TCIFLUSH)) sys_fail_fptr(fptr);
+ if (tcflush(fd2, TCOFLUSH)) sys_fail_fptr(fptr);
}
else {
- if (tcflush(fd1, TCIOFLUSH)) sys_fail(io);
+ if (tcflush(fd1, TCIOFLUSH)) sys_fail_fptr(fptr);
}
#endif
-
return io;
}
-/*
- * call-seq:
- * io.beep
- *
- * Beeps on the output console.
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_beep(VALUE io)
{
+ rb_io_t *fptr;
+ int fd;
+
+ GetOpenFile(io, fptr);
+ fd = GetWriteFD(fptr);
#ifdef _WIN32
+ (void)fd;
MessageBeep(0);
#else
- int fd = GetWriteFD(io);
- if (write(fd, "\a", 1) < 0) sys_fail(io);
+ if (write(fd, "\a", 1) < 0)
+ sys_fail_fptr(fptr);
#endif
return io;
}
@@ -1034,6 +1035,79 @@ mode_in_range(VALUE val, int high, const char *modename)
}
#if defined _WIN32
+static VALUE
+console_goto(VALUE io, VALUE y, VALUE x)
+{
+ rb_io_t *fptr;
+ int fd;
+ COORD pos;
+
+ GetOpenFile(io, fptr);
+ fd = GetWriteFD(fptr);
+ pos.X = NUM2UINT(x);
+ pos.Y = NUM2UINT(y);
+ if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ return io;
+}
+
+static VALUE
+console_cursor_pos(VALUE io)
+{
+ rb_io_t *fptr;
+ int fd;
+ rb_console_size_t ws;
+
+ GetOpenFile(io, fptr);
+ fd = GetWriteFD(fptr);
+ if (!GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), &ws)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y), UINT2NUM(ws.dwCursorPosition.X));
+}
+
+static VALUE
+console_move(VALUE io, int y, int x)
+{
+ rb_io_t *fptr;
+ HANDLE h;
+ rb_console_size_t ws;
+ COORD *pos = &ws.dwCursorPosition;
+
+ GetOpenFile(io, fptr);
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
+ if (!GetConsoleScreenBufferInfo(h, &ws)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ pos->X += x;
+ pos->Y += y;
+ if (!SetConsoleCursorPosition(h, *pos)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ return io;
+}
+
+static VALUE
+console_goto_column(VALUE io, VALUE val)
+{
+ rb_io_t *fptr;
+ HANDLE h;
+ rb_console_size_t ws;
+ COORD *pos = &ws.dwCursorPosition;
+
+ GetOpenFile(io, fptr);
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
+ if (!GetConsoleScreenBufferInfo(h, &ws)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ pos->X = NUM2INT(val);
+ if (!SetConsoleCursorPosition(h, *pos)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ return io;
+}
+
static void
constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos)
{
@@ -1044,12 +1118,86 @@ constat_clear(HANDLE handle, WORD attr, DWORD len, COORD pos)
}
static VALUE
+console_erase_line(VALUE io, VALUE val)
+{
+ rb_io_t *fptr;
+ HANDLE h;
+ rb_console_size_t ws;
+ COORD *pos = &ws.dwCursorPosition;
+ DWORD w;
+ int mode = mode_in_range(val, 2, "line erase");
+
+ GetOpenFile(io, fptr);
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
+ if (!GetConsoleScreenBufferInfo(h, &ws)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ w = winsize_col(&ws);
+ switch (mode) {
+ case 0: /* after cursor */
+ w -= pos->X;
+ break;
+ case 1: /* before *and* cursor */
+ w = pos->X + 1;
+ pos->X = 0;
+ break;
+ case 2: /* entire line */
+ pos->X = 0;
+ break;
+ }
+ constat_clear(h, ws.wAttributes, w, *pos);
+ return io;
+}
+
+static VALUE
+console_erase_screen(VALUE io, VALUE val)
+{
+ rb_io_t *fptr;
+ HANDLE h;
+ rb_console_size_t ws;
+ COORD *pos = &ws.dwCursorPosition;
+ DWORD w;
+ int mode = mode_in_range(val, 3, "screen erase");
+
+ GetOpenFile(io, fptr);
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
+ if (!GetConsoleScreenBufferInfo(h, &ws)) {
+ rb_syserr_fail(LAST_ERROR, 0);
+ }
+ w = winsize_col(&ws);
+ switch (mode) {
+ case 0: /* erase after cursor */
+ w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
+ break;
+ case 1: /* erase before *and* cursor */
+ w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
+ pos->X = 0;
+ pos->Y = ws.srWindow.Top;
+ break;
+ case 2: /* erase entire screen */
+ w = (w * winsize_row(&ws));
+ pos->X = 0;
+ pos->Y = ws.srWindow.Top;
+ break;
+ case 3: /* erase entire screen */
+ w = (w * ws.dwSize.Y);
+ pos->X = 0;
+ pos->Y = 0;
+ break;
+ }
+ constat_clear(h, ws.wAttributes, w, *pos);
+ return io;
+}
+
+static VALUE
console_scroll(VALUE io, int line)
{
+ rb_io_t *fptr;
HANDLE h;
rb_console_size_t ws;
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
+ GetOpenFile(io, fptr);
+ h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(fptr));
if (!GetConsoleScreenBufferInfo(h, &ws)) {
rb_syserr_fail(LAST_ERROR, 0);
}
@@ -1071,22 +1219,8 @@ console_scroll(VALUE io, int line)
return io;
}
-#define GPERF_DOWNCASE 1
-#define GPERF_CASE_STRCMP 1
-#define gperf_case_strcmp STRCASECMP
#include "win32_vk.inc"
-/*
- * call-seq:
- * io.pressed?(key) -> bool
- *
- * Returns +true+ if +key+ is pressed. +key+ may be a virtual key
- * code or its name (String or Symbol) with out "VK_" prefix.
- *
- * This method is Windows only.
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_key_pressed_p(VALUE io, VALUE k)
{
@@ -1122,11 +1256,23 @@ static int
direct_query(VALUE io, const struct query_args *query)
{
if (RB_TYPE_P(io, T_FILE)) {
- VALUE wio = rb_io_get_write_io(io);
- VALUE s = rb_str_new_cstr(query->qstr);
- rb_io_write(wio, s);
- rb_io_flush(wio);
- return 1;
+ rb_io_t *fptr;
+ VALUE wio;
+ GetOpenFile(io, fptr);
+ wio = fptr->tied_io_for_writing;
+ if (wio) {
+ VALUE s = rb_str_new_cstr(query->qstr);
+ rb_io_write(wio, s);
+ rb_io_flush(wio);
+ return 1;
+ }
+ if (write(fptr->fd, query->qstr, strlen(query->qstr)) != -1) {
+ return 1;
+ }
+ if (fptr->fd == 0 &&
+ write(1, query->qstr, strlen(query->qstr)) != -1) {
+ return 1;
+ }
}
return 0;
}
@@ -1177,40 +1323,8 @@ console_vt_response(int argc, VALUE *argv, VALUE io, const struct query_args *qa
}
static VALUE
-console_scroll(VALUE io, int line)
-{
- if (line) {
- VALUE s = rb_sprintf(CSI "%d%c", line < 0 ? -line : line,
- line < 0 ? 'T' : 'S');
- rb_io_write(io, s);
- }
- return io;
-}
-
-# define console_key_pressed_p rb_f_notimplement
-#endif
-
-/*
- * call-seq:
- * io.cursor -> [row, column]
- *
- * Returns the current cursor position as a two-element array of integers (row, column)
- *
- * io.cursor # => [3, 5]
- *
- * You must require 'io/console' to use this method.
- */
-static VALUE
console_cursor_pos(VALUE io)
{
-#ifdef _WIN32
- rb_console_size_t ws;
- int fd = GetWriteFD(io);
- if (!GetConsoleScreenBufferInfo((HANDLE)rb_w32_get_osfhandle(fd), &ws)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
- return rb_assoc_new(UINT2NUM(ws.dwCursorPosition.Y), UINT2NUM(ws.dwCursorPosition.X));
-#else
static const struct query_args query = {"\033[6n", 0};
VALUE resp = console_vt_response(0, 0, io, &query);
VALUE row, column, term;
@@ -1227,205 +1341,64 @@ console_cursor_pos(VALUE io)
RARRAY_ASET(resp, 0, INT2NUM(r));
RARRAY_ASET(resp, 1, INT2NUM(c));
return resp;
-#endif
}
-/*
- * call-seq:
- * io.goto(line, column) -> io
- *
- * Set the cursor position at +line+ and +column+.
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_goto(VALUE io, VALUE y, VALUE x)
{
-#ifdef _WIN32
- COORD pos;
- int fd = GetWriteFD(io);
- pos.X = NUM2UINT(x);
- pos.Y = NUM2UINT(y);
- if (!SetConsoleCursorPosition((HANDLE)rb_w32_get_osfhandle(fd), pos)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
-#else
- rb_io_write(io, rb_sprintf(CSI "%d;%dH", NUM2UINT(y)+1, NUM2UINT(x)+1));
-#endif
+ rb_io_write(io, rb_sprintf("\x1b[%d;%dH", NUM2UINT(y)+1, NUM2UINT(x)+1));
return io;
}
static VALUE
console_move(VALUE io, int y, int x)
{
-#ifdef _WIN32
- HANDLE h;
- rb_console_size_t ws;
- COORD *pos = &ws.dwCursorPosition;
-
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
- if (!GetConsoleScreenBufferInfo(h, &ws)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
- pos->X += x;
- pos->Y += y;
- if (!SetConsoleCursorPosition(h, *pos)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
-#else
if (x || y) {
VALUE s = rb_str_new_cstr("");
- if (y) rb_str_catf(s, CSI "%d%c", y < 0 ? -y : y, y < 0 ? 'A' : 'B');
- if (x) rb_str_catf(s, CSI "%d%c", x < 0 ? -x : x, x < 0 ? 'D' : 'C');
+ if (y) rb_str_catf(s, "\x1b[%d%c", y < 0 ? -y : y, y < 0 ? 'A' : 'B');
+ if (x) rb_str_catf(s, "\x1b[%d%c", x < 0 ? -x : x, x < 0 ? 'D' : 'C');
rb_io_write(io, s);
rb_io_flush(io);
}
-#endif
return io;
}
-/*
- * call-seq:
- * io.goto_column(column) -> io
- *
- * Set the cursor position at +column+ in the same line of the current
- * position.
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_goto_column(VALUE io, VALUE val)
{
-#ifdef _WIN32
- HANDLE h;
- rb_console_size_t ws;
- COORD *pos = &ws.dwCursorPosition;
-
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
- if (!GetConsoleScreenBufferInfo(h, &ws)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
- pos->X = NUM2INT(val);
- if (!SetConsoleCursorPosition(h, *pos)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
-#else
- rb_io_write(io, rb_sprintf(CSI "%dG", NUM2UINT(val)+1));
-#endif
+ rb_io_write(io, rb_sprintf("\x1b[%dG", NUM2UINT(val)+1));
return io;
}
-/*
- * call-seq:
- * io.erase_line(mode) -> io
- *
- * Erases the line at the cursor corresponding to +mode+.
- * +mode+ may be either:
- * 0: after cursor
- * 1: before and cursor
- * 2: entire line
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_erase_line(VALUE io, VALUE val)
{
int mode = mode_in_range(val, 2, "line erase");
-#ifdef _WIN32
- HANDLE h;
- rb_console_size_t ws;
- COORD *pos = &ws.dwCursorPosition;
- DWORD w;
-
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
- if (!GetConsoleScreenBufferInfo(h, &ws)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
- w = winsize_col(&ws);
- switch (mode) {
- case 0: /* after cursor */
- w -= pos->X;
- break;
- case 1: /* before *and* cursor */
- w = pos->X + 1;
- pos->X = 0;
- break;
- case 2: /* entire line */
- pos->X = 0;
- break;
- }
- constat_clear(h, ws.wAttributes, w, *pos);
- return io;
-#else
- rb_io_write(io, rb_sprintf(CSI "%dK", mode));
-#endif
+ rb_io_write(io, rb_sprintf("\x1b[%dK", mode));
return io;
}
-/*
- * call-seq:
- * io.erase_screen(mode) -> io
- *
- * Erases the screen at the cursor corresponding to +mode+.
- * +mode+ may be either:
- * 0: after cursor
- * 1: before and cursor
- * 2: entire screen
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_erase_screen(VALUE io, VALUE val)
{
int mode = mode_in_range(val, 3, "screen erase");
-#ifdef _WIN32
- HANDLE h;
- rb_console_size_t ws;
- COORD *pos = &ws.dwCursorPosition;
- DWORD w;
+ rb_io_write(io, rb_sprintf("\x1b[%dJ", mode));
+ return io;
+}
- h = (HANDLE)rb_w32_get_osfhandle(GetWriteFD(io));
- if (!GetConsoleScreenBufferInfo(h, &ws)) {
- rb_syserr_fail(LAST_ERROR, 0);
- }
- w = winsize_col(&ws);
- switch (mode) {
- case 0: /* erase after cursor */
- w = (w * (ws.srWindow.Bottom - pos->Y + 1) - pos->X);
- break;
- case 1: /* erase before *and* cursor */
- w = (w * (pos->Y - ws.srWindow.Top) + pos->X + 1);
- pos->X = 0;
- pos->Y = ws.srWindow.Top;
- break;
- case 2: /* erase entire screen */
- w = (w * winsize_row(&ws));
- pos->X = 0;
- pos->Y = ws.srWindow.Top;
- break;
- case 3: /* erase entire screen */
- w = (w * ws.dwSize.Y);
- pos->X = 0;
- pos->Y = 0;
- break;
+static VALUE
+console_scroll(VALUE io, int line)
+{
+ if (line) {
+ VALUE s = rb_sprintf("\x1b[%d%c", line < 0 ? -line : line,
+ line < 0 ? 'T' : 'S');
+ rb_io_write(io, s);
}
- constat_clear(h, ws.wAttributes, w, *pos);
-#else
- rb_io_write(io, rb_sprintf(CSI "%dJ", mode));
-#endif
return io;
}
+# define console_key_pressed_p rb_f_notimplement
+#endif
-/*
- * call-seq:
- * io.cursor = [line, column] -> io
- *
- * Same as <tt>io.goto(line, column)</tt>
- *
- * See IO#goto.
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_cursor_set(VALUE io, VALUE cpos)
{
@@ -1434,98 +1407,42 @@ console_cursor_set(VALUE io, VALUE cpos)
return console_goto(io, RARRAY_AREF(cpos, 0), RARRAY_AREF(cpos, 1));
}
-/*
- * call-seq:
- * io.cursor_up(n) -> io
- *
- * Moves the cursor up +n+ lines.
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_cursor_up(VALUE io, VALUE val)
{
return console_move(io, -NUM2INT(val), 0);
}
-/*
- * call-seq:
- * io.cursor_down(n) -> io
- *
- * Moves the cursor down +n+ lines.
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_cursor_down(VALUE io, VALUE val)
{
return console_move(io, +NUM2INT(val), 0);
}
-/*
- * call-seq:
- * io.cursor_left(n) -> io
- *
- * Moves the cursor left +n+ columns.
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_cursor_left(VALUE io, VALUE val)
{
return console_move(io, 0, -NUM2INT(val));
}
-/*
- * call-seq:
- * io.cursor_right(n) -> io
- *
- * Moves the cursor right +n+ columns.
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_cursor_right(VALUE io, VALUE val)
{
return console_move(io, 0, +NUM2INT(val));
}
-/*
- * call-seq:
- * io.scroll_forward(n) -> io
- *
- * Scrolls the entire scrolls forward +n+ lines.
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_scroll_forward(VALUE io, VALUE val)
{
return console_scroll(io, +NUM2INT(val));
}
-/*
- * call-seq:
- * io.scroll_backward(n) -> io
- *
- * Scrolls the entire scrolls backward +n+ lines.
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_scroll_backward(VALUE io, VALUE val)
{
return console_scroll(io, -NUM2INT(val));
}
-/*
- * call-seq:
- * io.clear_screen -> io
- *
- * Clears the entire screen and moves the cursor top-left corner.
- *
- * You must require 'io/console' to use this method.
- */
static VALUE
console_clear_screen(VALUE io)
{
@@ -1534,92 +1451,6 @@ console_clear_screen(VALUE io)
return io;
}
-#ifndef HAVE_RB_IO_OPEN_DESCRIPTOR
-static VALUE
-io_open_descriptor_fallback(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, void *encoding)
-{
- VALUE arguments[2] = {
- (rb_update_max_fd(descriptor), INT2NUM(descriptor)),
- INT2FIX(mode),
- };
-
- VALUE self = rb_class_new_instance(2, arguments, klass);
-
- rb_io_t *fptr;
- GetOpenFile(self, fptr);
- fptr->pathv = path;
- fptr->mode |= mode;
-
- return self;
-}
-#define rb_io_open_descriptor io_open_descriptor_fallback
-#endif
-
-#ifndef HAVE_RB_IO_CLOSED_P
-static VALUE
-rb_io_closed_p(VALUE io)
-{
- rb_io_t *fptr = RFILE(io)->fptr;
- return fptr->fd == -1 ? Qtrue : Qfalse;
-}
-#endif
-
-#if defined(RB_EXT_RACTOR_SAFE) && defined(HAVE_RB_RACTOR_LOCAL_STORAGE_VALUE_NEWKEY)
-# define USE_RACTOR_STORAGE 1
-#else
-# define USE_RACTOR_STORAGE 0
-#endif
-
-#if USE_RACTOR_STORAGE
-#include "ruby/ractor.h"
-static rb_ractor_local_key_t key_console_dev;
-
-static bool
-console_dev_get(VALUE klass, VALUE *dev)
-{
- return rb_ractor_local_storage_value_lookup(key_console_dev, dev);
-}
-
-static void
-console_dev_set(VALUE klass, VALUE value)
-{
- rb_ractor_local_storage_value_set(key_console_dev, value);
-}
-
-static void
-console_dev_remove(VALUE klass)
-{
- console_dev_set(klass, Qnil);
-}
-
-#else
-
-static ID id_console;
-
-static int
-console_dev_get(VALUE klass, VALUE *dev)
-{
- if (rb_const_defined(klass, id_console)) {
- *dev = rb_const_get(klass, id_console);
- return 1;
- }
- return 0;
-}
-
-static void
-console_dev_set(VALUE klass, VALUE value)
-{
- rb_const_set(klass, id_console, value);
-}
-
-static void
-console_dev_remove(VALUE klass)
-{
- rb_const_remove(klass, id_console);
-}
-
-#endif
-
/*
* call-seq:
* IO.console -> #<File:/dev/tty>
@@ -1637,36 +1468,34 @@ static VALUE
console_dev(int argc, VALUE *argv, VALUE klass)
{
VALUE con = 0;
+ rb_io_t *fptr;
VALUE sym = 0;
rb_check_arity(argc, 0, UNLIMITED_ARGUMENTS);
-
if (argc) {
- Check_Type(sym = argv[0], T_SYMBOL);
+ Check_Type(sym = argv[0], T_SYMBOL);
}
-
- // Force the class to be File.
if (klass == rb_cIO) klass = rb_cFile;
-
- if (console_dev_get(klass, &con)) {
- if (!RB_TYPE_P(con, T_FILE) || RTEST(rb_io_closed_p(con))) {
- console_dev_remove(klass);
- con = 0;
- }
+ if (rb_const_defined(klass, id_console)) {
+ con = rb_const_get(klass, id_console);
+ if (!RB_TYPE_P(con, T_FILE) ||
+ (!(fptr = RFILE(con)->fptr) || GetReadFD(fptr) == -1)) {
+ rb_const_remove(klass, id_console);
+ con = 0;
+ }
}
-
if (sym) {
- if (sym == ID2SYM(id_close) && argc == 1) {
- if (con) {
- rb_io_close(con);
- console_dev_remove(klass);
- con = 0;
- }
- return Qnil;
- }
+ if (sym == ID2SYM(id_close) && argc == 1) {
+ if (con) {
+ rb_io_close(con);
+ rb_const_remove(klass, id_console);
+ con = 0;
+ }
+ return Qnil;
+ }
}
-
if (!con) {
+ VALUE args[2];
#if defined HAVE_TERMIOS_H || defined HAVE_TERMIO_H || defined HAVE_SGTTY_H
# define CONSOLE_DEVICE "/dev/tty"
#elif defined _WIN32
@@ -1678,35 +1507,44 @@ console_dev(int argc, VALUE *argv, VALUE klass)
# define CONSOLE_DEVICE_FOR_READING CONSOLE_DEVICE
#endif
#ifdef CONSOLE_DEVICE_FOR_WRITING
- VALUE out;
+ VALUE out;
+ rb_io_t *ofptr;
#endif
- int fd;
- VALUE path = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
+ int fd;
#ifdef CONSOLE_DEVICE_FOR_WRITING
- fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_RDWR, 0);
- if (fd < 0) return Qnil;
- out = rb_io_open_descriptor(klass, fd, FMODE_WRITABLE | FMODE_SYNC, path, Qnil, NULL);
+ fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_WRITING, O_RDWR, 0);
+ if (fd < 0) return Qnil;
+ rb_update_max_fd(fd);
+ args[1] = INT2FIX(O_WRONLY);
+ args[0] = INT2NUM(fd);
+ out = rb_class_new_instance(2, args, klass);
#endif
- fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_READING, O_RDWR, 0);
- if (fd < 0) {
+ fd = rb_cloexec_open(CONSOLE_DEVICE_FOR_READING, O_RDWR, 0);
+ if (fd < 0) {
#ifdef CONSOLE_DEVICE_FOR_WRITING
- rb_io_close(out);
+ rb_io_close(out);
#endif
- return Qnil;
- }
-
- con = rb_io_open_descriptor(klass, fd, FMODE_READWRITE | FMODE_SYNC, path, Qnil, NULL);
+ return Qnil;
+ }
+ rb_update_max_fd(fd);
+ args[1] = INT2FIX(O_RDWR);
+ args[0] = INT2NUM(fd);
+ con = rb_class_new_instance(2, args, klass);
+ GetOpenFile(con, fptr);
+ fptr->pathv = rb_obj_freeze(rb_str_new2(CONSOLE_DEVICE));
#ifdef CONSOLE_DEVICE_FOR_WRITING
- rb_io_set_write_io(con, out);
+ GetOpenFile(out, ofptr);
+ ofptr->pathv = fptr->pathv;
+ fptr->tied_io_for_writing = out;
+ ofptr->mode |= FMODE_SYNC;
#endif
- console_dev_set(klass, con);
+ fptr->mode |= FMODE_SYNC;
+ rb_const_set(klass, id_console, con);
}
-
if (sym) {
- return rb_f_send(argc, argv, con);
+ return rb_f_send(argc, argv, con);
}
-
return con;
}
@@ -1722,6 +1560,7 @@ io_getch(int argc, VALUE *argv, VALUE io)
return rb_funcallv(io, id_getc, argc, argv);
}
+#if ENABLE_IO_GETPASS
static VALUE
puts_call(VALUE io)
{
@@ -1729,12 +1568,6 @@ puts_call(VALUE io)
}
static VALUE
-gets_call(VALUE io)
-{
- return rb_funcallv(io, id_gets, 0, 0);
-}
-
-static VALUE
getpass_call(VALUE io)
{
return ttymode(io, rb_io_gets, io, set_noecho, NULL);
@@ -1754,8 +1587,7 @@ static VALUE
str_chomp(VALUE str)
{
if (!NIL_P(str)) {
- const VALUE rs = rb_default_rs; /* rvalue in TruffleRuby */
- rb_funcallv(str, id_chomp_bang, 1, &rs);
+ rb_funcallv(str, id_chomp_bang, 0, 0);
}
return str;
}
@@ -1772,12 +1604,6 @@ str_chomp(VALUE str)
* see String#chomp!.
*
* You must require 'io/console' to use this method.
- *
- * require 'io/console'
- * IO::console.getpass("Enter password:")
- * Enter password:
- * # => "mypassword"
- *
*/
static VALUE
console_getpass(int argc, VALUE *argv, VALUE io)
@@ -1788,7 +1614,6 @@ console_getpass(int argc, VALUE *argv, VALUE io)
wio = rb_io_get_write_io(io);
if (wio == io && io == rb_stdin) wio = rb_stderr;
prompt(argc, argv, wio);
- rb_io_flush(wio);
str = rb_ensure(getpass_call, io, puts_call, wio);
return str_chomp(str);
}
@@ -1806,10 +1631,11 @@ io_getpass(int argc, VALUE *argv, VALUE io)
rb_check_arity(argc, 0, 1);
prompt(argc, argv, io);
- rb_check_funcall(io, id_flush, 0, 0);
- str = rb_ensure(gets_call, io, puts_call, io);
- return str_chomp(str);
+ str = str_chomp(rb_funcallv(io, id_gets, 0, 0));
+ puts_call(io);
+ return str;
}
+#endif
/*
* IO console methods
@@ -1817,20 +1643,13 @@ io_getpass(int argc, VALUE *argv, VALUE io)
void
Init_console(void)
{
-#if USE_RACTOR_STORAGE
- RB_EXT_RACTOR_SAFE(true);
-#endif
-
#undef rb_intern
-#if USE_RACTOR_STORAGE
- key_console_dev = rb_ractor_local_storage_value_newkey();
-#else
- id_console = rb_intern("console");
-#endif
id_getc = rb_intern("getc");
+#if ENABLE_IO_GETPASS
id_gets = rb_intern("gets");
- id_flush = rb_intern("flush");
id_chomp_bang = rb_intern("chomp!");
+#endif
+ id_console = rb_intern("console");
id_close = rb_intern("close");
#define init_rawmode_opt_id(name) \
rawmode_opt_ids[kwd_##name] = rb_intern(#name)
@@ -1877,19 +1696,20 @@ InitVM_console(void)
rb_define_method(rb_cIO, "clear_screen", console_clear_screen, 0);
rb_define_method(rb_cIO, "pressed?", console_key_pressed_p, 1);
rb_define_method(rb_cIO, "check_winsize_changed", console_check_winsize_changed, 0);
+#if ENABLE_IO_GETPASS
rb_define_method(rb_cIO, "getpass", console_getpass, -1);
+#endif
rb_define_singleton_method(rb_cIO, "console", console_dev, -1);
{
- /* :stopdoc: */
VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
- /* :startdoc: */
rb_define_method(mReadable, "getch", io_getch, -1);
+#if ENABLE_IO_GETPASS
rb_define_method(mReadable, "getpass", io_getpass, -1);
+#endif
}
{
/* :stopdoc: */
cConmode = rb_define_class_under(rb_cIO, "ConsoleMode", rb_cObject);
- rb_define_const(cConmode, "VERSION", rb_str_new_cstr(IO_CONSOLE_VERSION));
rb_define_alloc_func(cConmode, conmode_alloc);
rb_undef_method(cConmode, "initialize");
rb_define_method(cConmode, "initialize_copy", conmode_init_copy, 1);
diff --git a/ext/io/console/depend b/ext/io/console/depend
index e66b6f4f5d..36747ef583 100644
--- a/ext/io/console/depend
+++ b/ext/io/console/depend
@@ -54,7 +54,6 @@ console.o: $(hdrdir)/ruby/internal/attr/noexcept.h
console.o: $(hdrdir)/ruby/internal/attr/noinline.h
console.o: $(hdrdir)/ruby/internal/attr/nonnull.h
console.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-console.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
console.o: $(hdrdir)/ruby/internal/attr/pure.h
console.o: $(hdrdir)/ruby/internal/attr/restrict.h
console.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -123,6 +122,7 @@ console.o: $(hdrdir)/ruby/internal/intern/enumerator.h
console.o: $(hdrdir)/ruby/internal/intern/error.h
console.o: $(hdrdir)/ruby/internal/intern/eval.h
console.o: $(hdrdir)/ruby/internal/intern/file.h
+console.o: $(hdrdir)/ruby/internal/intern/gc.h
console.o: $(hdrdir)/ruby/internal/intern/hash.h
console.o: $(hdrdir)/ruby/internal/intern/io.h
console.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -153,12 +153,12 @@ console.o: $(hdrdir)/ruby/internal/memory.h
console.o: $(hdrdir)/ruby/internal/method.h
console.o: $(hdrdir)/ruby/internal/module.h
console.o: $(hdrdir)/ruby/internal/newobj.h
+console.o: $(hdrdir)/ruby/internal/rgengc.h
console.o: $(hdrdir)/ruby/internal/scan_args.h
console.o: $(hdrdir)/ruby/internal/special_consts.h
console.o: $(hdrdir)/ruby/internal/static_assert.h
console.o: $(hdrdir)/ruby/internal/stdalign.h
console.o: $(hdrdir)/ruby/internal/stdbool.h
-console.o: $(hdrdir)/ruby/internal/stdckdint.h
console.o: $(hdrdir)/ruby/internal/symbol.h
console.o: $(hdrdir)/ruby/internal/value.h
console.o: $(hdrdir)/ruby/internal/value_type.h
@@ -169,7 +169,6 @@ console.o: $(hdrdir)/ruby/io.h
console.o: $(hdrdir)/ruby/missing.h
console.o: $(hdrdir)/ruby/onigmo.h
console.o: $(hdrdir)/ruby/oniguruma.h
-console.o: $(hdrdir)/ruby/ractor.h
console.o: $(hdrdir)/ruby/ruby.h
console.o: $(hdrdir)/ruby/st.h
console.o: $(hdrdir)/ruby/subst.h
diff --git a/ext/io/console/extconf.rb b/ext/io/console/extconf.rb
index 6161b747b5..e8c5923b18 100644
--- a/ext/io/console/extconf.rb
+++ b/ext/io/console/extconf.rb
@@ -1,25 +1,7 @@
# frozen_string_literal: false
require 'mkmf'
-# `--target-rbconfig` compatibility for Ruby 3.3 or earlier
-# See https://bugs.ruby-lang.org/issues/20345
-MakeMakefile::RbConfig ||= ::RbConfig
-
-have_func("rb_io_path")
-have_func("rb_io_descriptor")
-have_func("rb_io_get_write_io")
-have_func("rb_io_closed_p")
-have_func("rb_io_open_descriptor")
-have_func("rb_ractor_local_storage_value_newkey")
-
-is_wasi = /wasi/ =~ MakeMakefile::RbConfig::CONFIG["platform"]
-# `ok` can be `true`, `false`, or `nil`:
-# * `true` : Required headers and functions available, proceed regular build.
-# * `false`: Required headers or functions not available, abort build.
-# * `nil` : Unsupported compilation target, generate dummy Makefile.
-#
-# Skip building io/console on WASI, as it does not support termios.h.
-ok = true if (RUBY_ENGINE == "ruby" && !is_wasi) || RUBY_ENGINE == "truffleruby"
+ok = true if RUBY_ENGINE == "ruby" || RUBY_ENGINE == "truffleruby"
hdr = nil
case
when macro_defined?("_WIN32", "")
@@ -47,6 +29,7 @@ when true
elsif have_func("rb_scheduler_timeout") # 3.0
have_func("rb_io_wait")
end
+ $defs << "-D""ENABLE_IO_GETPASS=1"
create_makefile("io/console") {|conf|
conf << "\n""VK_HEADER = #{vk_header}\n"
}
diff --git a/ext/io/console/io-console.gemspec b/ext/io/console/io-console.gemspec
index f9c1729cb7..d26a757b01 100644
--- a/ext/io/console/io-console.gemspec
+++ b/ext/io/console/io-console.gemspec
@@ -1,13 +1,5 @@
# -*- ruby -*-
-_VERSION = ["", "ext/io/console/"].find do |dir|
- begin
- break File.open(File.join(__dir__, "#{dir}console.c")) {|f|
- f.gets("\nIO_CONSOLE_VERSION ")
- f.gets[/"(.+)"/, 1]
- }
- rescue Errno::ENOENT
- end
-end
+_VERSION = "0.6.0"
Gem::Specification.new do |s|
s.name = "io-console"
@@ -18,11 +10,9 @@ Gem::Specification.new do |s|
s.required_ruby_version = ">= 2.6.0"
s.homepage = "https://github.com/ruby/io-console"
s.metadata["source_code_url"] = s.homepage
- s.metadata["changelog_uri"] = s.homepage + "/releases"
s.authors = ["Nobu Nakada"]
s.require_path = %[lib]
s.files = %w[
- .document
LICENSE.txt
README.md
ext/io/console/console.c
@@ -35,16 +25,15 @@ Gem::Specification.new do |s|
if Gem::Platform === s.platform and s.platform =~ 'java'
s.files.delete_if {|f| f.start_with?("ext/")}
s.extensions.clear
- s.require_paths.unshift('lib/ffi')
s.files.concat(%w[
- lib/ffi/io/console.rb
- lib/ffi/io/console/bsd_console.rb
- lib/ffi/io/console/common.rb
- lib/ffi/io/console/linux_console.rb
- lib/ffi/io/console/native_console.rb
- lib/ffi/io/console/stty_console.rb
- lib/ffi/io/console/stub_console.rb
- lib/ffi/io/console/version.rb
+ lib/io/console.rb
+ lib/io/console/ffi/bsd_console.rb
+ lib/io/console/ffi/common.rb
+ lib/io/console/ffi/console.rb
+ lib/io/console/ffi/linux_console.rb
+ lib/io/console/ffi/native_console.rb
+ lib/io/console/ffi/stty_console.rb
+ lib/io/console/ffi/stub_console.rb
])
end
diff --git a/ext/io/console/win32_vk.inc b/ext/io/console/win32_vk.inc
index 348e6be5ed..d15b1219fb 100644
--- a/ext/io/console/win32_vk.inc
+++ b/ext/io/console/win32_vk.inc
@@ -519,7 +519,7 @@ struct vktable;
#ifndef GPERF_DOWNCASE
#define GPERF_DOWNCASE 1
-static unsigned char gperf_downcase[256] =
+static const unsigned char gperf_downcase[256] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
diff --git a/ext/io/nonblock/depend b/ext/io/nonblock/depend
index 20a96f1252..7f2db65732 100644
--- a/ext/io/nonblock/depend
+++ b/ext/io/nonblock/depend
@@ -53,7 +53,6 @@ nonblock.o: $(hdrdir)/ruby/internal/attr/noexcept.h
nonblock.o: $(hdrdir)/ruby/internal/attr/noinline.h
nonblock.o: $(hdrdir)/ruby/internal/attr/nonnull.h
nonblock.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-nonblock.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
nonblock.o: $(hdrdir)/ruby/internal/attr/pure.h
nonblock.o: $(hdrdir)/ruby/internal/attr/restrict.h
nonblock.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ nonblock.o: $(hdrdir)/ruby/internal/intern/enumerator.h
nonblock.o: $(hdrdir)/ruby/internal/intern/error.h
nonblock.o: $(hdrdir)/ruby/internal/intern/eval.h
nonblock.o: $(hdrdir)/ruby/internal/intern/file.h
+nonblock.o: $(hdrdir)/ruby/internal/intern/gc.h
nonblock.o: $(hdrdir)/ruby/internal/intern/hash.h
nonblock.o: $(hdrdir)/ruby/internal/intern/io.h
nonblock.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,12 +152,12 @@ nonblock.o: $(hdrdir)/ruby/internal/memory.h
nonblock.o: $(hdrdir)/ruby/internal/method.h
nonblock.o: $(hdrdir)/ruby/internal/module.h
nonblock.o: $(hdrdir)/ruby/internal/newobj.h
+nonblock.o: $(hdrdir)/ruby/internal/rgengc.h
nonblock.o: $(hdrdir)/ruby/internal/scan_args.h
nonblock.o: $(hdrdir)/ruby/internal/special_consts.h
nonblock.o: $(hdrdir)/ruby/internal/static_assert.h
nonblock.o: $(hdrdir)/ruby/internal/stdalign.h
nonblock.o: $(hdrdir)/ruby/internal/stdbool.h
-nonblock.o: $(hdrdir)/ruby/internal/stdckdint.h
nonblock.o: $(hdrdir)/ruby/internal/symbol.h
nonblock.o: $(hdrdir)/ruby/internal/value.h
nonblock.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/io/nonblock/extconf.rb b/ext/io/nonblock/extconf.rb
index a1e6075c9b..d813a01e7c 100644
--- a/ext/io/nonblock/extconf.rb
+++ b/ext/io/nonblock/extconf.rb
@@ -2,13 +2,6 @@
require 'mkmf'
target = "io/nonblock"
-unless RUBY_ENGINE == 'ruby'
- File.write("Makefile", dummy_makefile($srcdir).join(""))
- return
-end
-
-have_func("rb_io_descriptor")
-
hdr = %w"fcntl.h"
if have_macro("O_NONBLOCK", hdr) and
(have_macro("F_GETFL", hdr) or have_macro("F_SETFL", hdr))
diff --git a/ext/io/nonblock/io-nonblock.gemspec b/ext/io/nonblock/io-nonblock.gemspec
index 6a16c8b03b..d6df21a84d 100644
--- a/ext/io/nonblock/io-nonblock.gemspec
+++ b/ext/io/nonblock/io-nonblock.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = "io-nonblock"
- spec.version = "0.3.0"
+ spec.version = "0.2.0"
spec.authors = ["Nobu Nakada"]
spec.email = ["nobu@ruby-lang.org"]
diff --git a/ext/io/nonblock/nonblock.c b/ext/io/nonblock/nonblock.c
index d90538f735..b8a40ff38e 100644
--- a/ext/io/nonblock/nonblock.c
+++ b/ext/io/nonblock/nonblock.c
@@ -17,17 +17,6 @@
#endif
#include <fcntl.h>
-#ifndef HAVE_RB_IO_DESCRIPTOR
-static int
-io_descriptor_fallback(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- return fptr->fd;
-}
-#define rb_io_descriptor io_descriptor_fallback
-#endif
-
#ifdef F_GETFL
static int
get_fcntl_flags(int fd)
@@ -50,8 +39,10 @@ get_fcntl_flags(int fd)
static VALUE
rb_io_nonblock_p(VALUE io)
{
- if (get_fcntl_flags(rb_io_descriptor(io)) & O_NONBLOCK)
- return Qtrue;
+ rb_io_t *fptr;
+ GetOpenFile(io, fptr);
+ if (get_fcntl_flags(fptr->fd) & O_NONBLOCK)
+ return Qtrue;
return Qfalse;
}
#else
@@ -66,8 +57,6 @@ set_fcntl_flags(int fd, int f)
rb_sys_fail(0);
}
-#ifndef RUBY_IO_NONBLOCK_METHODS
-
static int
io_nonblock_set(int fd, int f, int nb)
{
@@ -133,23 +122,17 @@ io_nonblock_set(int fd, int f, int nb)
*
*/
static VALUE
-rb_io_nonblock_set(VALUE self, VALUE value)
+rb_io_nonblock_set(VALUE io, VALUE nb)
{
- if (RTEST(value)) {
- rb_io_t *fptr;
- GetOpenFile(self, fptr);
- rb_io_set_nonblock(fptr);
- }
- else {
- int descriptor = rb_io_descriptor(self);
- io_nonblock_set(descriptor, get_fcntl_flags(descriptor), RTEST(value));
- }
-
- return self;
+ rb_io_t *fptr;
+ GetOpenFile(io, fptr);
+ if (RTEST(nb))
+ rb_io_set_nonblock(fptr);
+ else
+ io_nonblock_set(fptr->fd, get_fcntl_flags(fptr->fd), RTEST(nb));
+ return io;
}
-#endif /* RUBY_IO_NONBLOCK_METHODS */
-
static VALUE
io_nonblock_restore(VALUE arg)
{
@@ -169,25 +152,24 @@ io_nonblock_restore(VALUE arg)
* The original mode is restored after the block is executed.
*/
static VALUE
-rb_io_nonblock_block(int argc, VALUE *argv, VALUE self)
+rb_io_nonblock_block(int argc, VALUE *argv, VALUE io)
{
int nb = 1;
+ rb_io_t *fptr;
+ int f, restore[2];
- int descriptor = rb_io_descriptor(self);
-
+ GetOpenFile(io, fptr);
if (argc > 0) {
- VALUE v;
- rb_scan_args(argc, argv, "01", &v);
- nb = RTEST(v);
+ VALUE v;
+ rb_scan_args(argc, argv, "01", &v);
+ nb = RTEST(v);
}
-
- int current_flags = get_fcntl_flags(descriptor);
- int restore[2] = {descriptor, current_flags};
-
- if (!io_nonblock_set(descriptor, current_flags, nb))
- return rb_yield(self);
-
- return rb_ensure(rb_yield, self, io_nonblock_restore, (VALUE)restore);
+ f = get_fcntl_flags(fptr->fd);
+ restore[0] = fptr->fd;
+ restore[1] = f;
+ if (!io_nonblock_set(fptr->fd, f, nb))
+ return rb_yield(io);
+ return rb_ensure(rb_yield, io, io_nonblock_restore, (VALUE)restore);
}
#else
#define rb_io_nonblock_set rb_f_notimplement
@@ -197,10 +179,7 @@ rb_io_nonblock_block(int argc, VALUE *argv, VALUE self)
void
Init_nonblock(void)
{
-#ifndef RUBY_IO_NONBLOCK_METHODS
rb_define_method(rb_cIO, "nonblock?", rb_io_nonblock_p, 0);
rb_define_method(rb_cIO, "nonblock=", rb_io_nonblock_set, 1);
-#endif
-
rb_define_method(rb_cIO, "nonblock", rb_io_nonblock_block, -1);
}
diff --git a/ext/io/wait/depend b/ext/io/wait/depend
index 70317b1497..51e1af8280 100644
--- a/ext/io/wait/depend
+++ b/ext/io/wait/depend
@@ -54,7 +54,6 @@ wait.o: $(hdrdir)/ruby/internal/attr/noexcept.h
wait.o: $(hdrdir)/ruby/internal/attr/noinline.h
wait.o: $(hdrdir)/ruby/internal/attr/nonnull.h
wait.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-wait.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
wait.o: $(hdrdir)/ruby/internal/attr/pure.h
wait.o: $(hdrdir)/ruby/internal/attr/restrict.h
wait.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -123,6 +122,7 @@ wait.o: $(hdrdir)/ruby/internal/intern/enumerator.h
wait.o: $(hdrdir)/ruby/internal/intern/error.h
wait.o: $(hdrdir)/ruby/internal/intern/eval.h
wait.o: $(hdrdir)/ruby/internal/intern/file.h
+wait.o: $(hdrdir)/ruby/internal/intern/gc.h
wait.o: $(hdrdir)/ruby/internal/intern/hash.h
wait.o: $(hdrdir)/ruby/internal/intern/io.h
wait.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -153,12 +153,12 @@ wait.o: $(hdrdir)/ruby/internal/memory.h
wait.o: $(hdrdir)/ruby/internal/method.h
wait.o: $(hdrdir)/ruby/internal/module.h
wait.o: $(hdrdir)/ruby/internal/newobj.h
+wait.o: $(hdrdir)/ruby/internal/rgengc.h
wait.o: $(hdrdir)/ruby/internal/scan_args.h
wait.o: $(hdrdir)/ruby/internal/special_consts.h
wait.o: $(hdrdir)/ruby/internal/static_assert.h
wait.o: $(hdrdir)/ruby/internal/stdalign.h
wait.o: $(hdrdir)/ruby/internal/stdbool.h
-wait.o: $(hdrdir)/ruby/internal/stdckdint.h
wait.o: $(hdrdir)/ruby/internal/symbol.h
wait.o: $(hdrdir)/ruby/internal/value.h
wait.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/io/wait/extconf.rb b/ext/io/wait/extconf.rb
index e63c046187..c6230b7783 100644
--- a/ext/io/wait/extconf.rb
+++ b/ext/io/wait/extconf.rb
@@ -5,8 +5,7 @@ if RUBY_VERSION < "2.6"
File.write("Makefile", dummy_makefile($srcdir).join(""))
else
target = "io/wait"
- have_func("rb_io_wait")
- have_func("rb_io_descriptor")
+ have_func("rb_io_wait", "ruby/io.h")
unless macro_defined?("DOSISH", "#include <ruby.h>")
have_header(ioctl_h = "sys/ioctl.h") or ioctl_h = nil
fionread = %w[sys/ioctl.h sys/filio.h sys/socket.h].find do |h|
diff --git a/ext/io/wait/io-wait.gemspec b/ext/io/wait/io-wait.gemspec
index e850e10bf9..ebc1f6f5c7 100644
--- a/ext/io/wait/io-wait.gemspec
+++ b/ext/io/wait/io-wait.gemspec
@@ -1,4 +1,4 @@
-_VERSION = "0.3.1"
+_VERSION = "0.3.0"
Gem::Specification.new do |spec|
spec.name = "io-wait"
diff --git a/ext/io/wait/wait.c b/ext/io/wait/wait.c
index 8835670e59..d74afb580b 100644
--- a/ext/io/wait/wait.c
+++ b/ext/io/wait/wait.c
@@ -87,15 +87,8 @@ io_nread(VALUE io)
rb_io_check_readable(fptr);
len = rb_io_read_pending(fptr);
if (len > 0) return INT2FIX(len);
-
-#ifdef HAVE_RB_IO_DESCRIPTOR
- int fd = rb_io_descriptor(io);
-#else
- int fd = fptr->fd;
-#endif
-
- if (!FIONREAD_POSSIBLE_P(fd)) return INT2FIX(0);
- if (ioctl(fd, FIONREAD, &n)) return INT2FIX(0);
+ if (!FIONREAD_POSSIBLE_P(fptr->fd)) return INT2FIX(0);
+ if (ioctl(fptr->fd, FIONREAD, &n)) return INT2FIX(0);
if (n > 0) return ioctl_arg2num(n);
return INT2FIX(0);
}
diff --git a/ext/json/VERSION b/ext/json/VERSION
new file mode 100644
index 0000000000..ec1cf33c3f
--- /dev/null
+++ b/ext/json/VERSION
@@ -0,0 +1 @@
+2.6.3
diff --git a/ext/json/fbuffer/fbuffer.h b/ext/json/fbuffer/fbuffer.h
index 1fb9d66700..dc8f406b5b 100644
--- a/ext/json/fbuffer/fbuffer.h
+++ b/ext/json/fbuffer/fbuffer.h
@@ -31,8 +31,12 @@
# define RB_OBJ_STRING(obj) StringValueCStr(obj)
#endif
+#ifdef HAVE_RUBY_ENCODING_H
#include "ruby/encoding.h"
#define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding())
+#else
+#define FORCE_UTF8(obj)
+#endif
/* We don't need to guard objects for rbx, so let's do nothing at all. */
#ifndef RB_GC_GUARD
@@ -66,10 +70,6 @@ static FBuffer *fbuffer_dup(FBuffer *fb);
static VALUE fbuffer_to_s(FBuffer *fb);
#endif
-#ifndef RB_UNLIKELY
-#define RB_UNLIKELY(expr) expr
-#endif
-
static FBuffer *fbuffer_alloc(unsigned long initial_length)
{
FBuffer *fb;
@@ -91,22 +91,20 @@ static void fbuffer_clear(FBuffer *fb)
fb->len = 0;
}
-static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
+static void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
{
- if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
- unsigned long required;
+ unsigned long required;
- if (RB_UNLIKELY(!fb->ptr)) {
- fb->ptr = ALLOC_N(char, fb->initial_length);
- fb->capa = fb->initial_length;
- }
+ if (!fb->ptr) {
+ fb->ptr = ALLOC_N(char, fb->initial_length);
+ fb->capa = fb->initial_length;
+ }
- for (required = fb->capa; requested > required - fb->len; required <<= 1);
+ for (required = fb->capa; requested > required - fb->len; required <<= 1);
- if (required > fb->capa) {
- REALLOC_N(fb->ptr, char, required);
- fb->capa = required;
- }
+ if (required > fb->capa) {
+ REALLOC_N(fb->ptr, char, required);
+ fb->capa = required;
}
}
diff --git a/ext/json/generator/depend b/ext/json/generator/depend
index f47e5f3a70..28ef06b36d 100644
--- a/ext/json/generator/depend
+++ b/ext/json/generator/depend
@@ -56,7 +56,6 @@ generator.o: $(hdrdir)/ruby/internal/attr/noexcept.h
generator.o: $(hdrdir)/ruby/internal/attr/noinline.h
generator.o: $(hdrdir)/ruby/internal/attr/nonnull.h
generator.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-generator.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
generator.o: $(hdrdir)/ruby/internal/attr/pure.h
generator.o: $(hdrdir)/ruby/internal/attr/restrict.h
generator.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -126,6 +125,7 @@ generator.o: $(hdrdir)/ruby/internal/intern/enumerator.h
generator.o: $(hdrdir)/ruby/internal/intern/error.h
generator.o: $(hdrdir)/ruby/internal/intern/eval.h
generator.o: $(hdrdir)/ruby/internal/intern/file.h
+generator.o: $(hdrdir)/ruby/internal/intern/gc.h
generator.o: $(hdrdir)/ruby/internal/intern/hash.h
generator.o: $(hdrdir)/ruby/internal/intern/io.h
generator.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -156,12 +156,12 @@ generator.o: $(hdrdir)/ruby/internal/memory.h
generator.o: $(hdrdir)/ruby/internal/method.h
generator.o: $(hdrdir)/ruby/internal/module.h
generator.o: $(hdrdir)/ruby/internal/newobj.h
+generator.o: $(hdrdir)/ruby/internal/rgengc.h
generator.o: $(hdrdir)/ruby/internal/scan_args.h
generator.o: $(hdrdir)/ruby/internal/special_consts.h
generator.o: $(hdrdir)/ruby/internal/static_assert.h
generator.o: $(hdrdir)/ruby/internal/stdalign.h
generator.o: $(hdrdir)/ruby/internal/stdbool.h
-generator.o: $(hdrdir)/ruby/internal/stdckdint.h
generator.o: $(hdrdir)/ruby/internal/symbol.h
generator.o: $(hdrdir)/ruby/internal/value.h
generator.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/json/generator/extconf.rb b/ext/json/generator/extconf.rb
index cf8d5f2bda..8627c5f4bd 100644
--- a/ext/json/generator/extconf.rb
+++ b/ext/json/generator/extconf.rb
@@ -1,9 +1,4 @@
require 'mkmf'
-if RUBY_ENGINE == 'truffleruby'
- # The pure-Ruby generator is faster on TruffleRuby, so skip compiling the generator extension
- File.write('Makefile', dummy_makefile("").join)
-else
- $defs << "-DJSON_GENERATOR"
- create_makefile 'json/ext/generator'
-end
+$defs << "-DJSON_GENERATOR"
+create_makefile 'json/ext/generator'
diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c
index b8734764c7..98d0ea46c3 100644
--- a/ext/json/generator/generator.c
+++ b/ext/json/generator/generator.c
@@ -16,7 +16,7 @@ static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
i_pack, i_unpack, i_create_id, i_extend, i_key_p,
i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
- i_buffer_initial_length, i_dup, i_script_safe, i_escape_slash, i_strict;
+ i_buffer_initial_length, i_dup, i_escape_slash;
/*
* Copyright 2001-2004 Unicode, Inc.
@@ -66,6 +66,42 @@ static const char trailingBytesForUTF8[256] = {
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
+/*
+ * Utility routine to tell whether a sequence of bytes is legal UTF-8.
+ * This must be called with the length pre-determined by the first byte.
+ * If not calling this from ConvertUTF8to*, then the length can be set by:
+ * length = trailingBytesForUTF8[*source]+1;
+ * and the sequence is illegal right away if there aren't that many bytes
+ * available.
+ * If presented with a length > 4, this returns 0. The Unicode
+ * definition of UTF-8 goes up to 4-byte sequences.
+ */
+static unsigned char isLegalUTF8(const UTF8 *source, unsigned long length)
+{
+ UTF8 a;
+ const UTF8 *srcptr = source+length;
+ switch (length) {
+ default: return 0;
+ /* Everything else falls through when "1"... */
+ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
+ case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
+ case 2: if ((a = (*--srcptr)) > 0xBF) return 0;
+
+ switch (*source) {
+ /* no fall-through in this inner switch */
+ case 0xE0: if (a < 0xA0) return 0; break;
+ case 0xED: if (a > 0x9F) return 0; break;
+ case 0xF0: if (a < 0x90) return 0; break;
+ case 0xF4: if (a > 0x8F) return 0; break;
+ default: if (a < 0x80) return 0;
+ }
+
+ case 1: if (*source >= 0x80 && *source < 0xC2) return 0;
+ }
+ if (*source > 0xF4) return 0;
+ return 1;
+}
+
/* Escapes the UTF16 character and stores the result in the buffer buf. */
static void unicode_escape(char *buf, UTF16 character)
{
@@ -88,24 +124,23 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
/* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
* and control characters are JSON escaped. */
-static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char script_safe)
+static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash)
{
const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
const UTF8 *sourceEnd = source + RSTRING_LEN(string);
char buf[6] = { '\\', 'u' };
- int ascii_only = rb_enc_str_asciionly_p(string);
-
- if (!ascii_only) {
- if (RB_ENCODING_GET_INLINED(string) != rb_utf8_encindex() || RB_ENC_CODERANGE(string) != RUBY_ENC_CODERANGE_VALID) {
- rb_raise(rb_path2class("JSON::GeneratorError"),
- "source sequence is illegal/malformed utf-8");
- }
- }
-
while (source < sourceEnd) {
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd) {
+ rb_raise(rb_path2class("JSON::GeneratorError"),
+ "partial character in source, but hit end");
+ }
+ if (!isLegalUTF8(source, extraBytesToRead+1)) {
+ rb_raise(rb_path2class("JSON::GeneratorError"),
+ "source sequence is illegal/malformed utf-8");
+ }
/*
* The cases all fall through. See "Note A" below.
*/
@@ -140,7 +175,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char scrip
fbuffer_append(buffer, "\\\"", 2);
break;
case '/':
- if(script_safe) {
+ if(escape_slash) {
fbuffer_append(buffer, "\\/", 2);
break;
}
@@ -193,7 +228,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char scrip
* characters required by the JSON standard are JSON escaped. The remaining
* characters (should be UTF8) are just passed through and appended to the
* result. */
-static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char script_safe)
+static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash)
{
const char *ptr = RSTRING_PTR(string), *p;
unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
@@ -203,13 +238,6 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char script_safe
char buf[6] = { '\\', 'u' };
int ascii_only = rb_enc_str_asciionly_p(string);
- if (!ascii_only) {
- if (RB_ENCODING_GET_INLINED(string) != rb_utf8_encindex() || RB_ENC_CODERANGE(string) != RUBY_ENC_CODERANGE_VALID) {
- rb_raise(rb_path2class("JSON::GeneratorError"),
- "source sequence is illegal/malformed utf-8");
- }
- }
-
for (start = 0, end = 0; end < len;) {
p = ptr + end;
c = (unsigned char) *p;
@@ -252,7 +280,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char script_safe
escape_len = 2;
break;
case '/':
- if(script_safe) {
+ if(escape_slash) {
escape = "\\/";
escape_len = 2;
break;
@@ -266,20 +294,9 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char script_safe
rb_raise(rb_path2class("JSON::GeneratorError"),
"partial character in source, but hit end");
}
-
- if (script_safe && c == 0xE2) {
- unsigned char c2 = (unsigned char) *(p+1);
- unsigned char c3 = (unsigned char) *(p+2);
- if (c2 == 0x80 && (c3 == 0xA8 || c3 == 0xA9)) {
- fbuffer_append(buffer, ptr + start, end - start);
- start = end = (end + clen);
- if (c3 == 0xA8) {
- fbuffer_append(buffer, "\\u2028", 6);
- } else {
- fbuffer_append(buffer, "\\u2029", 6);
- }
- continue;
- }
+ if (!isLegalUTF8((UTF8 *) p, clen)) {
+ rb_raise(rb_path2class("JSON::GeneratorError"),
+ "source sequence is illegal/malformed utf-8");
}
}
end += clen;
@@ -461,7 +478,6 @@ static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
*/
static VALUE mString_included_s(VALUE self, VALUE modul) {
VALUE result = rb_funcall(modul, i_extend, 1, mString_Extend);
- rb_call_super(1, &modul);
return result;
}
@@ -603,12 +619,16 @@ static size_t State_memsize(const void *ptr)
# define RUBY_TYPED_FROZEN_SHAREABLE 0
#endif
+#ifdef NEW_TYPEDDATA_WRAPPER
static const rb_data_type_t JSON_Generator_State_type = {
"JSON/Generator/State",
{NULL, State_free, State_memsize,},
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
0, 0,
- RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
+#endif
};
+#endif
static VALUE cState_s_allocate(VALUE klass)
{
@@ -706,14 +726,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
state->allow_nan = RTEST(tmp);
tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
state->ascii_only = RTEST(tmp);
- tmp = rb_hash_aref(opts, ID2SYM(i_script_safe));
- state->script_safe = RTEST(tmp);
- if (!state->script_safe) {
- tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
- state->script_safe = RTEST(tmp);
- }
- tmp = rb_hash_aref(opts, ID2SYM(i_strict));
- state->strict = RTEST(tmp);
+ tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
+ state->escape_slash = RTEST(tmp);
return self;
}
@@ -748,8 +762,7 @@ static VALUE cState_to_h(VALUE self)
rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
- rb_hash_aset(result, ID2SYM(i_script_safe), state->script_safe ? Qtrue : Qfalse);
- rb_hash_aset(result, ID2SYM(i_strict), state->strict ? Qtrue : Qfalse);
+ rb_hash_aset(result, ID2SYM(i_escape_slash), state->escape_slash ? Qtrue : Qfalse);
rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
return result;
@@ -814,6 +827,7 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
long delim2_len = FBUFFER_LEN(state->object_delim2);
long depth = state->depth;
int j;
+ VALUE klass, key_to_s;
if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
if (object_nl) {
@@ -825,19 +839,15 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
}
}
- VALUE key_to_s;
- switch(rb_type(key)) {
- case T_STRING:
- key_to_s = key;
- break;
- case T_SYMBOL:
- key_to_s = rb_sym2str(key);
- break;
- default:
- key_to_s = rb_convert_type(key, T_STRING, "String", "to_s");
- break;
+ klass = CLASS_OF(key);
+ if (klass == rb_cString) {
+ key_to_s = key;
+ } else if (klass == rb_cSymbol) {
+ key_to_s = rb_id2str(SYM2ID(key));
+ } else {
+ key_to_s = rb_funcall(key, i_to_s, 0);
}
-
+ Check_Type(key_to_s, T_STRING);
generate_json(buffer, Vstate, state, key_to_s);
fbuffer_append(buffer, delim2, delim2_len);
generate_json(buffer, Vstate, state, val);
@@ -858,6 +868,7 @@ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
struct hash_foreach_arg arg;
if (max_nesting != 0 && depth > max_nesting) {
+ fbuffer_free(buffer);
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
}
fbuffer_append_char(buffer, '{');
@@ -892,6 +903,7 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
long depth = ++state->depth;
int i, j;
if (max_nesting != 0 && depth > max_nesting) {
+ fbuffer_free(buffer);
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
}
fbuffer_append_char(buffer, '[');
@@ -917,24 +929,27 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
fbuffer_append_char(buffer, ']');
}
+#ifdef HAVE_RUBY_ENCODING_H
static int enc_utf8_compatible_p(rb_encoding *enc)
{
if (enc == rb_usascii_encoding()) return 1;
if (enc == rb_utf8_encoding()) return 1;
return 0;
}
+#endif
static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
{
fbuffer_append_char(buffer, '"');
+#ifdef HAVE_RUBY_ENCODING_H
if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
obj = rb_str_export_to_enc(obj, rb_utf8_encoding());
}
-
+#endif
if (state->ascii_only) {
- convert_UTF8_to_JSON_ASCII(buffer, obj, state->script_safe);
+ convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash);
} else {
- convert_UTF8_to_JSON(buffer, obj, state->script_safe);
+ convert_UTF8_to_JSON(buffer, obj, state->escape_slash);
}
fbuffer_append_char(buffer, '"');
}
@@ -981,8 +996,10 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
VALUE tmp = rb_funcall(obj, i_to_s, 0);
if (!allow_nan) {
if (isinf(value)) {
+ fbuffer_free(buffer);
rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp));
} else if (isnan(value)) {
+ fbuffer_free(buffer);
rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp));
}
}
@@ -1011,8 +1028,6 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
generate_json_bignum(buffer, Vstate, state, obj);
} else if (klass == rb_cFloat) {
generate_json_float(buffer, Vstate, state, obj);
- } else if (state->strict) {
- rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(CLASS_OF(obj)));
} else if (rb_respond_to(obj, i_to_json)) {
tmp = rb_funcall(obj, i_to_json, 1, Vstate);
Check_Type(tmp, T_STRING);
@@ -1055,45 +1070,11 @@ static FBuffer *cState_prepare_buffer(VALUE self)
return buffer;
}
-struct generate_json_data {
- FBuffer *buffer;
- VALUE vstate;
- JSON_Generator_State *state;
- VALUE obj;
-};
-
-static VALUE generate_json_try(VALUE d)
-{
- struct generate_json_data *data = (struct generate_json_data *)d;
-
- generate_json(data->buffer, data->vstate, data->state, data->obj);
-
- return Qnil;
-}
-
-static VALUE generate_json_rescue(VALUE d, VALUE exc)
-{
- struct generate_json_data *data = (struct generate_json_data *)d;
- fbuffer_free(data->buffer);
-
- rb_exc_raise(exc);
-
- return Qundef;
-}
-
static VALUE cState_partial_generate(VALUE self, VALUE obj)
{
FBuffer *buffer = cState_prepare_buffer(self);
GET_STATE(self);
-
- struct generate_json_data data = {
- .buffer = buffer,
- .vstate = self,
- .state = state,
- .obj = obj
- };
- rb_rescue(generate_json_try, (VALUE)&data, generate_json_rescue, (VALUE)&data);
-
+ generate_json(buffer, self, state, obj);
return fbuffer_to_s(buffer);
}
@@ -1409,58 +1390,27 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
}
/*
- * call-seq: script_safe
+ * call-seq: escape_slash
*
* If this boolean is true, the forward slashes will be escaped in
* the json output.
*/
-static VALUE cState_script_safe(VALUE self)
+static VALUE cState_escape_slash(VALUE self)
{
GET_STATE(self);
- return state->script_safe ? Qtrue : Qfalse;
+ return state->escape_slash ? Qtrue : Qfalse;
}
/*
- * call-seq: script_safe=(enable)
+ * call-seq: escape_slash=(depth)
*
* This sets whether or not the forward slashes will be escaped in
* the json output.
*/
-static VALUE cState_script_safe_set(VALUE self, VALUE enable)
-{
- GET_STATE(self);
- state->script_safe = RTEST(enable);
- return Qnil;
-}
-
-/*
- * call-seq: strict
- *
- * If this boolean is false, types unsupported by the JSON format will
- * be serialized as strings.
- * If this boolean is true, types unsupported by the JSON format will
- * raise a JSON::GeneratorError.
- */
-static VALUE cState_strict(VALUE self)
-{
- GET_STATE(self);
- return state->strict ? Qtrue : Qfalse;
-}
-
-/*
- * call-seq: strict=(enable)
- *
- * This sets whether or not to serialize types unsupported by the
- * JSON format as strings.
- * If this boolean is false, types unsupported by the JSON format will
- * be serialized as strings.
- * If this boolean is true, types unsupported by the JSON format will
- * raise a JSON::GeneratorError.
- */
-static VALUE cState_strict_set(VALUE self, VALUE enable)
+static VALUE cState_escape_slash_set(VALUE self, VALUE enable)
{
GET_STATE(self);
- state->strict = RTEST(enable);
+ state->escape_slash = RTEST(enable);
return Qnil;
}
@@ -1580,15 +1530,9 @@ void Init_generator(void)
rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
- rb_define_method(cState, "script_safe", cState_script_safe, 0);
- rb_define_method(cState, "script_safe?", cState_script_safe, 0);
- rb_define_method(cState, "script_safe=", cState_script_safe_set, 1);
- rb_define_alias(cState, "escape_slash", "script_safe");
- rb_define_alias(cState, "escape_slash?", "script_safe?");
- rb_define_alias(cState, "escape_slash=", "script_safe=");
- rb_define_method(cState, "strict", cState_strict, 0);
- rb_define_method(cState, "strict?", cState_strict, 0);
- rb_define_method(cState, "strict=", cState_strict_set, 1);
+ rb_define_method(cState, "escape_slash", cState_escape_slash, 0);
+ rb_define_method(cState, "escape_slash?", cState_escape_slash, 0);
+ rb_define_method(cState, "escape_slash=", cState_escape_slash_set, 1);
rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
@@ -1645,9 +1589,7 @@ void Init_generator(void)
i_object_nl = rb_intern("object_nl");
i_array_nl = rb_intern("array_nl");
i_max_nesting = rb_intern("max_nesting");
- i_script_safe = rb_intern("script_safe");
i_escape_slash = rb_intern("escape_slash");
- i_strict = rb_intern("strict");
i_allow_nan = rb_intern("allow_nan");
i_ascii_only = rb_intern("ascii_only");
i_depth = rb_intern("depth");
diff --git a/ext/json/generator/generator.h b/ext/json/generator/generator.h
index 8dde7be827..3ebd622554 100644
--- a/ext/json/generator/generator.h
+++ b/ext/json/generator/generator.h
@@ -46,10 +46,11 @@ static const int halfShift = 10; /* used for shifting by 10 bits */
static const UTF32 halfBase = 0x0010000UL;
static const UTF32 halfMask = 0x3FFUL;
+static unsigned char isLegalUTF8(const UTF8 *source, unsigned long length);
static void unicode_escape(char *buf, UTF16 character);
static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16 character);
-static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char script_safe);
-static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char script_safe);
+static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash);
+static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash);
static char *fstrndup(const char *ptr, unsigned long len);
/* ruby api and some helpers */
@@ -71,8 +72,7 @@ typedef struct JSON_Generator_StateStruct {
long max_nesting;
char allow_nan;
char ascii_only;
- char script_safe;
- char strict;
+ char escape_slash;
long depth;
long buffer_initial_length;
} JSON_Generator_State;
@@ -151,10 +151,8 @@ static VALUE cState_allow_nan_p(VALUE self);
static VALUE cState_ascii_only_p(VALUE self);
static VALUE cState_depth(VALUE self);
static VALUE cState_depth_set(VALUE self, VALUE depth);
-static VALUE cState_script_safe(VALUE self);
-static VALUE cState_script_safe_set(VALUE self, VALUE depth);
-static VALUE cState_strict(VALUE self);
-static VALUE cState_strict_set(VALUE self, VALUE strict);
+static VALUE cState_escape_slash(VALUE self);
+static VALUE cState_escape_slash_set(VALUE self, VALUE depth);
static FBuffer *cState_prepare_buffer(VALUE self);
#ifndef ZALLOC
#define ZALLOC(type) ((type *)ruby_zalloc(sizeof(type)))
@@ -165,7 +163,12 @@ static inline void *ruby_zalloc(size_t n)
return p;
}
#endif
-
+#ifdef TypedData_Make_Struct
static const rb_data_type_t JSON_Generator_State_type;
+#define NEW_TYPEDDATA_WRAPPER 1
+#else
+#define TypedData_Make_Struct(klass, type, ignore, json) Data_Make_Struct(klass, type, NULL, State_free, json)
+#define TypedData_Get_Struct(self, JSON_Generator_State, ignore, json) Data_Get_Struct(self, JSON_Generator_State, json)
+#endif
#endif
diff --git a/ext/json/json.gemspec b/ext/json/json.gemspec
index 64d0c81391..948e92c501 100644
--- a/ext/json/json.gemspec
+++ b/ext/json/json.gemspec
@@ -1,10 +1,8 @@
-version = File.foreach(File.join(__dir__, "lib/json/version.rb")) do |line|
- /^\s*VERSION\s*=\s*'(.*)'/ =~ line and break $1
-end rescue nil
+# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = "json"
- s.version = version
+ s.version = File.read(File.expand_path('../VERSION', __FILE__)).chomp
s.summary = "JSON Implementation for Ruby"
s.description = "This is a JSON implementation as a Ruby extension in C."
@@ -19,6 +17,7 @@ Gem::Specification.new do |s|
"CHANGES.md",
"LICENSE",
"README.md",
+ "VERSION",
"ext/json/ext/fbuffer/fbuffer.h",
"ext/json/ext/generator/depend",
"ext/json/ext/generator/extconf.rb",
@@ -54,12 +53,12 @@ Gem::Specification.new do |s|
"lib/json/pure/parser.rb",
"lib/json/version.rb",
]
- s.homepage = "https://flori.github.io/json"
+ s.homepage = "http://flori.github.com/json"
s.metadata = {
'bug_tracker_uri' => 'https://github.com/flori/json/issues',
'changelog_uri' => 'https://github.com/flori/json/blob/master/CHANGES.md',
- 'documentation_uri' => 'https://flori.github.io/json/doc/index.html',
- 'homepage_uri' => s.homepage,
+ 'documentation_uri' => 'http://flori.github.io/json/doc/index.html',
+ 'homepage_uri' => 'http://flori.github.io/json/',
'source_code_uri' => 'https://github.com/flori/json',
'wiki_uri' => 'https://github.com/flori/json/wiki'
}
diff --git a/ext/json/lib/json.rb b/ext/json/lib/json.rb
index 807488ffef..1e64bfcb1a 100644
--- a/ext/json/lib/json.rb
+++ b/ext/json/lib/json.rb
@@ -285,15 +285,6 @@ require 'json/common'
# # Raises JSON::NestingError (nesting of 2 is too deep):
# JSON.generate(obj, max_nesting: 2)
#
-# ====== Escaping Options
-#
-# Options +script_safe+ (boolean) specifies wether <tt>'\u2028'</tt>, <tt>'\u2029'</tt>
-# and <tt>'/'</tt> should be escaped as to make the JSON object safe to interpolate in script
-# tags.
-#
-# Options +ascii_only+ (boolean) specifies wether all characters outside the ASCII range
-# should be escaped.
-#
# ====== Output Options
#
# The default formatting options generate the most compact
diff --git a/ext/json/lib/json/add/bigdecimal.rb b/ext/json/lib/json/add/bigdecimal.rb
index b1d0cfa043..c8b4f567cb 100644
--- a/ext/json/lib/json/add/bigdecimal.rb
+++ b/ext/json/lib/json/add/bigdecimal.rb
@@ -2,36 +2,19 @@
unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
require 'json'
end
-begin
- require 'bigdecimal'
-rescue LoadError
-end
+defined?(::BigDecimal) or require 'bigdecimal'
class BigDecimal
-
- # See #as_json.
+ # Import a JSON Marshalled object.
+ #
+ # method used for JSON marshalling support.
def self.json_create(object)
BigDecimal._load object['b']
end
- # Methods <tt>BigDecimal#as_json</tt> and +BigDecimal.json_create+ may be used
- # to serialize and deserialize a \BigDecimal object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>BigDecimal#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/bigdecimal'
- # x = BigDecimal(2).as_json # => {"json_class"=>"BigDecimal", "b"=>"27:0.2e1"}
- # y = BigDecimal(2.0, 4).as_json # => {"json_class"=>"BigDecimal", "b"=>"36:0.2e1"}
- # z = BigDecimal(Complex(2, 0)).as_json # => {"json_class"=>"BigDecimal", "b"=>"27:0.2e1"}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \BigDecimal object:
- #
- # BigDecimal.json_create(x) # => 0.2e1
- # BigDecimal.json_create(y) # => 0.2e1
- # BigDecimal.json_create(z) # => 0.2e1
+ # Marshal the object to JSON.
#
+ # method used for JSON marshalling support.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -39,20 +22,8 @@ class BigDecimal
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/bigdecimal'
- # puts BigDecimal(2).to_json
- # puts BigDecimal(2.0, 4).to_json
- # puts BigDecimal(Complex(2, 0)).to_json
- #
- # Output:
- #
- # {"json_class":"BigDecimal","b":"27:0.2e1"}
- # {"json_class":"BigDecimal","b":"36:0.2e1"}
- # {"json_class":"BigDecimal","b":"27:0.2e1"}
- #
+ # return the JSON value
def to_json(*args)
as_json.to_json(*args)
end
-end if defined?(::BigDecimal)
+end
diff --git a/ext/json/lib/json/add/complex.rb b/ext/json/lib/json/add/complex.rb
index ef48c554c6..e63e29fd22 100644
--- a/ext/json/lib/json/add/complex.rb
+++ b/ext/json/lib/json/add/complex.rb
@@ -5,27 +5,14 @@ end
class Complex
- # See #as_json.
+ # Deserializes JSON string by converting Real value <tt>r</tt>, imaginary
+ # value <tt>i</tt>, to a Complex object.
def self.json_create(object)
Complex(object['r'], object['i'])
end
- # Methods <tt>Complex#as_json</tt> and +Complex.json_create+ may be used
- # to serialize and deserialize a \Complex object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Complex#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/complex'
- # x = Complex(2).as_json # => {"json_class"=>"Complex", "r"=>2, "i"=>0}
- # y = Complex(2.0, 4).as_json # => {"json_class"=>"Complex", "r"=>2.0, "i"=>4}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Complex object:
- #
- # Complex.json_create(x) # => (2+0i)
- # Complex.json_create(y) # => (2.0+4i)
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -34,17 +21,7 @@ class Complex
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/complex'
- # puts Complex(2).to_json
- # puts Complex(2.0, 4).to_json
- #
- # Output:
- #
- # {"json_class":"Complex","r":2,"i":0}
- # {"json_class":"Complex","r":2.0,"i":4}
- #
+ # Stores class name (Complex) along with real value <tt>r</tt> and imaginary value <tt>i</tt> as JSON string
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/date.rb b/ext/json/lib/json/add/date.rb
index 19688f751b..25523561a5 100644
--- a/ext/json/lib/json/add/date.rb
+++ b/ext/json/lib/json/add/date.rb
@@ -6,29 +6,16 @@ require 'date'
class Date
- # See #as_json.
+ # Deserializes JSON string by converting Julian year <tt>y</tt>, month
+ # <tt>m</tt>, day <tt>d</tt> and Day of Calendar Reform <tt>sg</tt> to Date.
def self.json_create(object)
civil(*object.values_at('y', 'm', 'd', 'sg'))
end
alias start sg unless method_defined?(:start)
- # Methods <tt>Date#as_json</tt> and +Date.json_create+ may be used
- # to serialize and deserialize a \Date object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Date#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/date'
- # x = Date.today.as_json
- # # => {"json_class"=>"Date", "y"=>2023, "m"=>11, "d"=>21, "sg"=>2299161.0}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Date object:
- #
- # Date.json_create(x)
- # # => #<Date: 2023-11-21 ((2460270j,0s,0n),+0s,2299161j)>
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -39,15 +26,8 @@ class Date
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/date'
- # puts Date.today.to_json
- #
- # Output:
- #
- # {"json_class":"Date","y":2023,"m":11,"d":21,"sg":2299161.0}
- #
+ # Stores class name (Date) with Julian year <tt>y</tt>, month <tt>m</tt>, day
+ # <tt>d</tt> and Day of Calendar Reform <tt>sg</tt> as JSON string
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/date_time.rb b/ext/json/lib/json/add/date_time.rb
index d7d42591cf..38b0e86ab8 100644
--- a/ext/json/lib/json/add/date_time.rb
+++ b/ext/json/lib/json/add/date_time.rb
@@ -6,7 +6,9 @@ require 'date'
class DateTime
- # See #as_json.
+ # Deserializes JSON string by converting year <tt>y</tt>, month <tt>m</tt>,
+ # day <tt>d</tt>, hour <tt>H</tt>, minute <tt>M</tt>, second <tt>S</tt>,
+ # offset <tt>of</tt> and Day of Calendar Reform <tt>sg</tt> to DateTime.
def self.json_create(object)
args = object.values_at('y', 'm', 'd', 'H', 'M', 'S')
of_a, of_b = object['of'].split('/')
@@ -21,21 +23,8 @@ class DateTime
alias start sg unless method_defined?(:start)
- # Methods <tt>DateTime#as_json</tt> and +DateTime.json_create+ may be used
- # to serialize and deserialize a \DateTime object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>DateTime#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/datetime'
- # x = DateTime.now.as_json
- # # => {"json_class"=>"DateTime", "y"=>2023, "m"=>11, "d"=>21, "sg"=>2299161.0}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \DateTime object:
- #
- # DateTime.json_create(x) # BUG? Raises Date::Error "invalid date"
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -50,15 +39,9 @@ class DateTime
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/datetime'
- # puts DateTime.now.to_json
- #
- # Output:
- #
- # {"json_class":"DateTime","y":2023,"m":11,"d":21,"sg":2299161.0}
- #
+ # Stores class name (DateTime) with Julian year <tt>y</tt>, month <tt>m</tt>,
+ # day <tt>d</tt>, hour <tt>H</tt>, minute <tt>M</tt>, second <tt>S</tt>,
+ # offset <tt>of</tt> and Day of Calendar Reform <tt>sg</tt> as JSON string
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/exception.rb b/ext/json/lib/json/add/exception.rb
index 71d8deb0ea..a107e5b3c4 100644
--- a/ext/json/lib/json/add/exception.rb
+++ b/ext/json/lib/json/add/exception.rb
@@ -5,27 +5,16 @@ end
class Exception
- # See #as_json.
+ # Deserializes JSON string by constructing new Exception object with message
+ # <tt>m</tt> and backtrace <tt>b</tt> serialized with <tt>to_json</tt>
def self.json_create(object)
result = new(object['m'])
result.set_backtrace object['b']
result
end
- # Methods <tt>Exception#as_json</tt> and +Exception.json_create+ may be used
- # to serialize and deserialize a \Exception object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Exception#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/exception'
- # x = Exception.new('Foo').as_json # => {"json_class"=>"Exception", "m"=>"Foo", "b"=>nil}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Exception object:
- #
- # Exception.json_create(x) # => #<Exception: Foo>
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -34,15 +23,8 @@ class Exception
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/exception'
- # puts Exception.new('Foo').to_json
- #
- # Output:
- #
- # {"json_class":"Exception","m":"Foo","b":null}
- #
+ # Stores class name (Exception) with message <tt>m</tt> and backtrace array
+ # <tt>b</tt> as JSON string
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/ostruct.rb b/ext/json/lib/json/add/ostruct.rb
index 1e6f408248..686cf0025d 100644
--- a/ext/json/lib/json/add/ostruct.rb
+++ b/ext/json/lib/json/add/ostruct.rb
@@ -2,34 +2,18 @@
unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
require 'json'
end
-begin
- require 'ostruct'
-rescue LoadError
-end
+require 'ostruct'
class OpenStruct
- # See #as_json.
+ # Deserializes JSON string by constructing new Struct object with values
+ # <tt>t</tt> serialized by <tt>to_json</tt>.
def self.json_create(object)
new(object['t'] || object[:t])
end
- # Methods <tt>OpenStruct#as_json</tt> and +OpenStruct.json_create+ may be used
- # to serialize and deserialize a \OpenStruct object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>OpenStruct#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/ostruct'
- # x = OpenStruct.new('name' => 'Rowdy', :age => nil).as_json
- # # => {"json_class"=>"OpenStruct", "t"=>{:name=>'Rowdy', :age=>nil}}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \OpenStruct object:
- #
- # OpenStruct.json_create(x)
- # # => #<OpenStruct name='Rowdy', age=nil>
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
klass = self.class.name
klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!"
@@ -39,16 +23,9 @@ class OpenStruct
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/ostruct'
- # puts OpenStruct.new('name' => 'Rowdy', :age => nil).to_json
- #
- # Output:
- #
- # {"json_class":"OpenStruct","t":{'name':'Rowdy',"age":null}}
- #
+ # Stores class name (OpenStruct) with this struct's values <tt>t</tt> as a
+ # JSON string.
def to_json(*args)
as_json.to_json(*args)
end
-end if defined?(::OpenStruct)
+end
diff --git a/ext/json/lib/json/add/range.rb b/ext/json/lib/json/add/range.rb
index 53f54ac372..93529fb1c4 100644
--- a/ext/json/lib/json/add/range.rb
+++ b/ext/json/lib/json/add/range.rb
@@ -5,29 +5,14 @@ end
class Range
- # See #as_json.
+ # Deserializes JSON string by constructing new Range object with arguments
+ # <tt>a</tt> serialized by <tt>to_json</tt>.
def self.json_create(object)
new(*object['a'])
end
- # Methods <tt>Range#as_json</tt> and +Range.json_create+ may be used
- # to serialize and deserialize a \Range object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Range#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/range'
- # x = (1..4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, false]}
- # y = (1...4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, true]}
- # z = ('a'..'d').as_json # => {"json_class"=>"Range", "a"=>["a", "d", false]}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Range object:
- #
- # Range.json_create(x) # => 1..4
- # Range.json_create(y) # => 1...4
- # Range.json_create(z) # => "a".."d"
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -35,19 +20,9 @@ class Range
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/range'
- # puts (1..4).to_json
- # puts (1...4).to_json
- # puts ('a'..'d').to_json
- #
- # Output:
- #
- # {"json_class":"Range","a":[1,4,false]}
- # {"json_class":"Range","a":[1,4,true]}
- # {"json_class":"Range","a":["a","d",false]}
- #
+ # Stores class name (Range) with JSON array of arguments <tt>a</tt> which
+ # include <tt>first</tt> (integer), <tt>last</tt> (integer), and
+ # <tt>exclude_end?</tt> (boolean) as JSON string.
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/rational.rb b/ext/json/lib/json/add/rational.rb
index 8c39a7db55..f776226046 100644
--- a/ext/json/lib/json/add/rational.rb
+++ b/ext/json/lib/json/add/rational.rb
@@ -4,28 +4,14 @@ unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
end
class Rational
-
- # See #as_json.
+ # Deserializes JSON string by converting numerator value <tt>n</tt>,
+ # denominator value <tt>d</tt>, to a Rational object.
def self.json_create(object)
Rational(object['n'], object['d'])
end
- # Methods <tt>Rational#as_json</tt> and +Rational.json_create+ may be used
- # to serialize and deserialize a \Rational object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Rational#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/rational'
- # x = Rational(2, 3).as_json
- # # => {"json_class"=>"Rational", "n"=>2, "d"=>3}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Rational object:
- #
- # Rational.json_create(x)
- # # => (2/3)
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -34,15 +20,7 @@ class Rational
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/rational'
- # puts Rational(2, 3).to_json
- #
- # Output:
- #
- # {"json_class":"Rational","n":2,"d":3}
- #
+ # Stores class name (Rational) along with numerator value <tt>n</tt> and denominator value <tt>d</tt> as JSON string
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/regexp.rb b/ext/json/lib/json/add/regexp.rb
index b63f49608f..39d69fede7 100644
--- a/ext/json/lib/json/add/regexp.rb
+++ b/ext/json/lib/json/add/regexp.rb
@@ -5,26 +5,15 @@ end
class Regexp
- # See #as_json.
+ # Deserializes JSON string by constructing new Regexp object with source
+ # <tt>s</tt> (Regexp or String) and options <tt>o</tt> serialized by
+ # <tt>to_json</tt>
def self.json_create(object)
new(object['s'], object['o'])
end
- # Methods <tt>Regexp#as_json</tt> and +Regexp.json_create+ may be used
- # to serialize and deserialize a \Regexp object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Regexp#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/regexp'
- # x = /foo/.as_json
- # # => {"json_class"=>"Regexp", "o"=>0, "s"=>"foo"}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Regexp object:
- #
- # Regexp.json_create(x) # => /foo/
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -33,15 +22,8 @@ class Regexp
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/regexp'
- # puts /foo/.to_json
- #
- # Output:
- #
- # {"json_class":"Regexp","o":0,"s":"foo"}
- #
+ # Stores class name (Regexp) with options <tt>o</tt> and source <tt>s</tt>
+ # (Regexp or String) as JSON string
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/set.rb b/ext/json/lib/json/add/set.rb
index 1918353187..71e2a0ac8b 100644
--- a/ext/json/lib/json/add/set.rb
+++ b/ext/json/lib/json/add/set.rb
@@ -4,27 +4,16 @@ end
defined?(::Set) or require 'set'
class Set
-
- # See #as_json.
+ # Import a JSON Marshalled object.
+ #
+ # method used for JSON marshalling support.
def self.json_create(object)
new object['a']
end
- # Methods <tt>Set#as_json</tt> and +Set.json_create+ may be used
- # to serialize and deserialize a \Set object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Set#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/set'
- # x = Set.new(%w/foo bar baz/).as_json
- # # => {"json_class"=>"Set", "a"=>["foo", "bar", "baz"]}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Set object:
- #
- # Set.json_create(x) # => #<Set: {"foo", "bar", "baz"}>
+ # Marshal the object to JSON.
#
+ # method used for JSON marshalling support.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -32,15 +21,7 @@ class Set
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/set'
- # puts Set.new(%w/foo bar baz/).to_json
- #
- # Output:
- #
- # {"json_class":"Set","a":["foo","bar","baz"]}
- #
+ # return the JSON value
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/struct.rb b/ext/json/lib/json/add/struct.rb
index 86847762ac..e8395ed42f 100644
--- a/ext/json/lib/json/add/struct.rb
+++ b/ext/json/lib/json/add/struct.rb
@@ -5,28 +5,14 @@ end
class Struct
- # See #as_json.
+ # Deserializes JSON string by constructing new Struct object with values
+ # <tt>v</tt> serialized by <tt>to_json</tt>.
def self.json_create(object)
new(*object['v'])
end
- # Methods <tt>Struct#as_json</tt> and +Struct.json_create+ may be used
- # to serialize and deserialize a \Struct object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Struct#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/struct'
- # Customer = Struct.new('Customer', :name, :address, :zip)
- # x = Struct::Customer.new.as_json
- # # => {"json_class"=>"Struct::Customer", "v"=>[nil, nil, nil]}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Struct object:
- #
- # Struct::Customer.json_create(x)
- # # => #<struct Struct::Customer name=nil, address=nil, zip=nil>
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
klass = self.class.name
klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!"
@@ -36,16 +22,8 @@ class Struct
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/struct'
- # Customer = Struct.new('Customer', :name, :address, :zip)
- # puts Struct::Customer.new.to_json
- #
- # Output:
- #
- # {"json_class":"Struct","t":{'name':'Rowdy',"age":null}}
- #
+ # Stores class name (Struct) with Struct values <tt>v</tt> as a JSON string.
+ # Only named structs are supported.
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/add/symbol.rb b/ext/json/lib/json/add/symbol.rb
index b5f3623158..74b13a423f 100644
--- a/ext/json/lib/json/add/symbol.rb
+++ b/ext/json/lib/json/add/symbol.rb
@@ -1,26 +1,11 @@
-
#frozen_string_literal: false
unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
require 'json'
end
class Symbol
-
- # Methods <tt>Symbol#as_json</tt> and +Symbol.json_create+ may be used
- # to serialize and deserialize a \Symbol object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Symbol#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/symbol'
- # x = :foo.as_json
- # # => {"json_class"=>"Symbol", "s"=>"foo"}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Symbol object:
- #
- # Symbol.json_create(x) # => :foo
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
{
JSON.create_id => self.class.name,
@@ -28,20 +13,12 @@ class Symbol
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/symbol'
- # puts :foo.to_json
- #
- # Output:
- #
- # # {"json_class":"Symbol","s":"foo"}
- #
+ # Stores class name (Symbol) with String representation of Symbol as a JSON string.
def to_json(*a)
as_json.to_json(*a)
end
- # See #as_json.
+ # Deserializes JSON string by converting the <tt>string</tt> value stored in the object to a Symbol
def self.json_create(o)
o['s'].to_sym
end
diff --git a/ext/json/lib/json/add/time.rb b/ext/json/lib/json/add/time.rb
index 599ed9e24b..b73acc4086 100644
--- a/ext/json/lib/json/add/time.rb
+++ b/ext/json/lib/json/add/time.rb
@@ -5,7 +5,7 @@ end
class Time
- # See #as_json.
+ # Deserializes JSON string by converting time since epoch to Time
def self.json_create(object)
if usec = object.delete('u') # used to be tv_usec -> tv_nsec
object['n'] = usec * 1000
@@ -17,22 +17,8 @@ class Time
end
end
- # Methods <tt>Time#as_json</tt> and +Time.json_create+ may be used
- # to serialize and deserialize a \Time object;
- # see Marshal[rdoc-ref:Marshal].
- #
- # \Method <tt>Time#as_json</tt> serializes +self+,
- # returning a 2-element hash representing +self+:
- #
- # require 'json/add/time'
- # x = Time.now.as_json
- # # => {"json_class"=>"Time", "s"=>1700931656, "n"=>472846644}
- #
- # \Method +JSON.create+ deserializes such a hash, returning a \Time object:
- #
- # Time.json_create(x)
- # # => 2023-11-25 11:00:56.472846644 -0600
- #
+ # Returns a hash, that will be turned into a JSON object and represent this
+ # object.
def as_json(*)
nanoseconds = [ tv_usec * 1000 ]
respond_to?(:tv_nsec) and nanoseconds << tv_nsec
@@ -44,15 +30,8 @@ class Time
}
end
- # Returns a JSON string representing +self+:
- #
- # require 'json/add/time'
- # puts Time.now.to_json
- #
- # Output:
- #
- # {"json_class":"Time","s":1700931678,"n":980650786}
- #
+ # Stores class name (Time) with number of seconds since epoch and number of
+ # microseconds for Time as JSON string
def to_json(*args)
as_json.to_json(*args)
end
diff --git a/ext/json/lib/json/common.rb b/ext/json/lib/json/common.rb
index 95098d3bb4..ea46896fcc 100644
--- a/ext/json/lib/json/common.rb
+++ b/ext/json/lib/json/common.rb
@@ -1,12 +1,8 @@
#frozen_string_literal: false
require 'json/version'
+require 'json/generic_object'
module JSON
- autoload :GenericObject, 'json/generic_object'
-
- NOT_SET = Object.new.freeze
- private_constant :NOT_SET
-
class << self
# :call-seq:
# JSON[object] -> new_array or new_string
@@ -299,9 +295,19 @@ module JSON
#
def generate(obj, opts = nil)
if State === opts
- state = opts
+ state, opts = opts, nil
else
- state = State.new(opts)
+ state = State.new
+ end
+ if opts
+ if opts.respond_to? :to_hash
+ opts = opts.to_hash
+ elsif opts.respond_to? :to_h
+ opts = opts.to_h
+ else
+ raise TypeError, "can't convert #{opts.class} into Hash"
+ end
+ state = state.configure(opts)
end
state.generate(obj)
end
@@ -328,9 +334,19 @@ module JSON
# JSON.fast_generate(a)
def fast_generate(obj, opts = nil)
if State === opts
- state = opts
+ state, opts = opts, nil
else
- state = JSON.create_fast_state.configure(opts)
+ state = JSON.create_fast_state
+ end
+ if opts
+ if opts.respond_to? :to_hash
+ opts = opts.to_hash
+ elsif opts.respond_to? :to_h
+ opts = opts.to_h
+ else
+ raise TypeError, "can't convert #{opts.class} into Hash"
+ end
+ state.configure(opts)
end
state.generate(obj)
end
@@ -576,13 +592,13 @@ module JSON
# Sets or returns the default options for the JSON.dump method.
# Initially:
# opts = JSON.dump_default_options
- # opts # => {:max_nesting=>false, :allow_nan=>true, :script_safe=>false}
+ # opts # => {:max_nesting=>false, :allow_nan=>true, :escape_slash=>false}
attr_accessor :dump_default_options
end
self.dump_default_options = {
:max_nesting => false,
:allow_nan => true,
- :script_safe => false,
+ :escape_slash => false,
}
# :call-seq:
@@ -612,18 +628,16 @@ module JSON
# puts File.read(path)
# Output:
# {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
- def dump(obj, anIO = nil, limit = nil, kwargs = nil)
- io_limit_opt = [anIO, limit, kwargs].compact
- kwargs = io_limit_opt.pop if io_limit_opt.last.is_a?(Hash)
- anIO, limit = io_limit_opt
- if anIO.respond_to?(:to_io)
- anIO = anIO.to_io
- elsif limit.nil? && !anIO.respond_to?(:write)
- anIO, limit = nil, anIO
+ def dump(obj, anIO = nil, limit = nil)
+ if anIO and limit.nil?
+ anIO = anIO.to_io if anIO.respond_to?(:to_io)
+ unless anIO.respond_to?(:write)
+ limit = anIO
+ anIO = nil
+ end
end
opts = JSON.dump_default_options
opts = opts.merge(:max_nesting => limit) if limit
- opts = merge_dump_options(opts, **kwargs) if kwargs
result = generate(obj, opts)
if anIO
anIO.write result
@@ -639,15 +653,6 @@ module JSON
def self.iconv(to, from, string)
string.encode(to, from)
end
-
- def merge_dump_options(opts, strict: NOT_SET)
- opts = opts.merge(strict: strict) if NOT_SET != strict
- opts
- end
-
- class << self
- private :merge_dump_options
- end
end
module ::Kernel
diff --git a/ext/json/lib/json/ext.rb b/ext/json/lib/json/ext.rb
index b62e231712..7264a857fa 100644
--- a/ext/json/lib/json/ext.rb
+++ b/ext/json/lib/json/ext.rb
@@ -4,19 +4,11 @@ module JSON
# This module holds all the modules/classes that implement JSON's
# functionality as C extensions.
module Ext
- if RUBY_ENGINE == 'truffleruby'
- require 'json/ext/parser'
- require 'json/pure'
- $DEBUG and warn "Using Ext extension for JSON parser and Pure library for JSON generator."
- JSON.parser = Parser
- JSON.generator = JSON::Pure::Generator
- else
- require 'json/ext/parser'
- require 'json/ext/generator'
- $DEBUG and warn "Using Ext extension for JSON."
- JSON.parser = Parser
- JSON.generator = Generator
- end
+ require 'json/ext/parser'
+ require 'json/ext/generator'
+ $DEBUG and warn "Using Ext extension for JSON."
+ JSON.parser = Parser
+ JSON.generator = Generator
end
JSON_LOADED = true unless defined?(::JSON::JSON_LOADED)
diff --git a/ext/json/lib/json/generic_object.rb b/ext/json/lib/json/generic_object.rb
index 56efda6495..108309db26 100644
--- a/ext/json/lib/json/generic_object.rb
+++ b/ext/json/lib/json/generic_object.rb
@@ -1,9 +1,5 @@
#frozen_string_literal: false
-begin
- require 'ostruct'
-rescue LoadError
- warn "JSON::GenericObject requires 'ostruct'. Please install it with `gem install ostruct`."
-end
+require 'ostruct'
module JSON
class GenericObject < OpenStruct
@@ -71,5 +67,5 @@ module JSON
def to_json(*a)
as_json.to_json(*a)
end
- end if defined?(::OpenStruct)
+ end
end
diff --git a/ext/json/lib/json/version.rb b/ext/json/lib/json/version.rb
index 836f47edf4..3d4326d836 100644
--- a/ext/json/lib/json/version.rb
+++ b/ext/json/lib/json/version.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: false
module JSON
# JSON version
- VERSION = '2.7.2'
+ VERSION = '2.6.3'
VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
diff --git a/ext/json/parser/depend b/ext/json/parser/depend
index f3422b4f84..a8e066ce15 100644
--- a/ext/json/parser/depend
+++ b/ext/json/parser/depend
@@ -56,7 +56,6 @@ parser.o: $(hdrdir)/ruby/internal/attr/noexcept.h
parser.o: $(hdrdir)/ruby/internal/attr/noinline.h
parser.o: $(hdrdir)/ruby/internal/attr/nonnull.h
parser.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-parser.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
parser.o: $(hdrdir)/ruby/internal/attr/pure.h
parser.o: $(hdrdir)/ruby/internal/attr/restrict.h
parser.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -125,6 +124,7 @@ parser.o: $(hdrdir)/ruby/internal/intern/enumerator.h
parser.o: $(hdrdir)/ruby/internal/intern/error.h
parser.o: $(hdrdir)/ruby/internal/intern/eval.h
parser.o: $(hdrdir)/ruby/internal/intern/file.h
+parser.o: $(hdrdir)/ruby/internal/intern/gc.h
parser.o: $(hdrdir)/ruby/internal/intern/hash.h
parser.o: $(hdrdir)/ruby/internal/intern/io.h
parser.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -155,12 +155,12 @@ parser.o: $(hdrdir)/ruby/internal/memory.h
parser.o: $(hdrdir)/ruby/internal/method.h
parser.o: $(hdrdir)/ruby/internal/module.h
parser.o: $(hdrdir)/ruby/internal/newobj.h
+parser.o: $(hdrdir)/ruby/internal/rgengc.h
parser.o: $(hdrdir)/ruby/internal/scan_args.h
parser.o: $(hdrdir)/ruby/internal/special_consts.h
parser.o: $(hdrdir)/ruby/internal/static_assert.h
parser.o: $(hdrdir)/ruby/internal/stdalign.h
parser.o: $(hdrdir)/ruby/internal/stdbool.h
-parser.o: $(hdrdir)/ruby/internal/stdckdint.h
parser.o: $(hdrdir)/ruby/internal/symbol.h
parser.o: $(hdrdir)/ruby/internal/value.h
parser.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/json/parser/extconf.rb b/ext/json/parser/extconf.rb
index feb586e1b4..4723a02aee 100644
--- a/ext/json/parser/extconf.rb
+++ b/ext/json/parser/extconf.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: false
require 'mkmf'
-have_func("rb_enc_raise", "ruby.h")
-have_func("rb_enc_interned_str", "ruby.h")
+have_func("rb_enc_raise", "ruby/encoding.h")
+have_func("rb_enc_interned_str", "ruby/encoding.h")
# checking if String#-@ (str_uminus) dedupes... '
begin
diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c
index 128f683e0f..9bd7f1971e 100644
--- a/ext/json/parser/parser.c
+++ b/ext/json/parser/parser.c
@@ -3,2181 +3,3345 @@
#include "../fbuffer/fbuffer.h"
#include "parser.h"
+#if defined HAVE_RUBY_ENCODING_H
+# define EXC_ENCODING rb_utf8_encoding(),
+# ifndef HAVE_RB_ENC_RAISE
+static void
+enc_raise(rb_encoding *enc, VALUE exc, const char *fmt, ...)
+{
+ va_list args;
+ VALUE mesg;
+
+ va_start(args, fmt);
+ mesg = rb_enc_vsprintf(enc, fmt, args);
+ va_end(args);
+
+ rb_exc_raise(rb_exc_new3(exc, mesg));
+}
+# define rb_enc_raise enc_raise
+# endif
+#else
+# define EXC_ENCODING /* nothing */
+# define rb_enc_raise rb_raise
+#endif
+
/* unicode */
static const signed char digit_values[256] = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
- -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
+ -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1
};
static UTF32 unescape_unicode(const unsigned char *p)
{
- signed char b;
- UTF32 result = 0;
- b = digit_values[p[0]];
- if (b < 0) return UNI_REPLACEMENT_CHAR;
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[1]];
- if (b < 0) return UNI_REPLACEMENT_CHAR;
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[2]];
- if (b < 0) return UNI_REPLACEMENT_CHAR;
- result = (result << 4) | (unsigned char)b;
- b = digit_values[p[3]];
- if (b < 0) return UNI_REPLACEMENT_CHAR;
- result = (result << 4) | (unsigned char)b;
- return result;
+ signed char b;
+ UTF32 result = 0;
+ b = digit_values[p[0]];
+ if (b < 0) return UNI_REPLACEMENT_CHAR;
+ result = (result << 4) | (unsigned char)b;
+ b = digit_values[p[1]];
+ if (b < 0) return UNI_REPLACEMENT_CHAR;
+ result = (result << 4) | (unsigned char)b;
+ b = digit_values[p[2]];
+ if (b < 0) return UNI_REPLACEMENT_CHAR;
+ result = (result << 4) | (unsigned char)b;
+ b = digit_values[p[3]];
+ if (b < 0) return UNI_REPLACEMENT_CHAR;
+ result = (result << 4) | (unsigned char)b;
+ return result;
}
static int convert_UTF32_to_UTF8(char *buf, UTF32 ch)
{
- int len = 1;
- if (ch <= 0x7F) {
- buf[0] = (char) ch;
- } else if (ch <= 0x07FF) {
- buf[0] = (char) ((ch >> 6) | 0xC0);
- buf[1] = (char) ((ch & 0x3F) | 0x80);
- len++;
- } else if (ch <= 0xFFFF) {
- buf[0] = (char) ((ch >> 12) | 0xE0);
- buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
- buf[2] = (char) ((ch & 0x3F) | 0x80);
- len += 2;
- } else if (ch <= 0x1fffff) {
- buf[0] =(char) ((ch >> 18) | 0xF0);
- buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
- buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
- buf[3] =(char) ((ch & 0x3F) | 0x80);
- len += 3;
- } else {
- buf[0] = '?';
- }
- return len;
+ int len = 1;
+ if (ch <= 0x7F) {
+ buf[0] = (char) ch;
+ } else if (ch <= 0x07FF) {
+ buf[0] = (char) ((ch >> 6) | 0xC0);
+ buf[1] = (char) ((ch & 0x3F) | 0x80);
+ len++;
+ } else if (ch <= 0xFFFF) {
+ buf[0] = (char) ((ch >> 12) | 0xE0);
+ buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
+ buf[2] = (char) ((ch & 0x3F) | 0x80);
+ len += 2;
+ } else if (ch <= 0x1fffff) {
+ buf[0] =(char) ((ch >> 18) | 0xF0);
+ buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
+ buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
+ buf[3] =(char) ((ch & 0x3F) | 0x80);
+ len += 3;
+ } else {
+ buf[0] = '?';
+ }
+ return len;
}
static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
static VALUE CNaN, CInfinity, CMinusInfinity;
static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
- i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
- i_object_class, i_array_class, i_decimal_class, i_key_p,
- i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
- i_leftshift, i_new, i_try_convert, i_freeze, i_uminus;
+i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
+i_object_class, i_array_class, i_decimal_class, i_key_p,
+i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
+i_leftshift, i_new, i_try_convert, i_freeze, i_uminus;
#line 125 "parser.rl"
-#line 107 "parser.c"
enum {JSON_object_start = 1};
enum {JSON_object_first_final = 27};
enum {JSON_object_error = 0};
enum {JSON_object_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_object_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_object_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_object_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_object_nfa_pop_trans)[] = {
+ 0, 0
+};
+
#line 167 "parser.rl"
static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
{
- int cs = EVIL;
- VALUE last_name = Qnil;
- VALUE object_class = json->object_class;
+ int cs = EVIL;
+ VALUE last_name = Qnil;
+ VALUE object_class = json->object_class;
- if (json->max_nesting && current_nesting > json->max_nesting) {
- rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
- }
+ if (json->max_nesting && current_nesting > json->max_nesting) {
+ rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
+ }
- *result = NIL_P(object_class) ? rb_hash_new() : rb_class_new_instance(0, 0, object_class);
+ *result = NIL_P(object_class) ? rb_hash_new() : rb_class_new_instance(0, 0, object_class);
-#line 131 "parser.c"
{
- cs = JSON_object_start;
+ cs = (int)JSON_object_start;
}
-#line 182 "parser.rl"
+ #line 182 "parser.rl"
+
-#line 138 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-case 1:
- if ( (*p) == 123 )
- goto st2;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-st2:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 2:
+ goto st_case_2;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 5:
+ goto st_case_5;
+ case 6:
+ goto st_case_6;
+ case 7:
+ goto st_case_7;
+ case 8:
+ goto st_case_8;
+ case 9:
+ goto st_case_9;
+ case 10:
+ goto st_case_10;
+ case 11:
+ goto st_case_11;
+ case 12:
+ goto st_case_12;
+ case 13:
+ goto st_case_13;
+ case 14:
+ goto st_case_14;
+ case 15:
+ goto st_case_15;
+ case 16:
+ goto st_case_16;
+ case 17:
+ goto st_case_17;
+ case 18:
+ goto st_case_18;
+ case 27:
+ goto st_case_27;
+ case 19:
+ goto st_case_19;
+ case 20:
+ goto st_case_20;
+ case 21:
+ goto st_case_21;
+ case 22:
+ goto st_case_22;
+ case 23:
+ goto st_case_23;
+ case 24:
+ goto st_case_24;
+ case 25:
+ goto st_case_25;
+ case 26:
+ goto st_case_26;
+ }
+ goto st_out;
+ st_case_1:
+ if ( ( (*( p))) == 123 ) {
+ goto st2;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- switch( (*p) ) {
- case 13: goto st2;
- case 32: goto st2;
- case 34: goto tr2;
- case 47: goto st23;
- case 125: goto tr4;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
- goto st2;
- goto st0;
-tr2:
-#line 149 "parser.rl"
- {
- char *np;
- json->parsing_name = 1;
- np = JSON_parse_string(json, p, pe, &last_name);
- json->parsing_name = 0;
- if (np == NULL) { p--; {p++; cs = 3; goto _out;} } else {p = (( np))-1;}
- }
- goto st3;
-st3:
- if ( ++p == pe )
- goto _test_eof3;
-case 3:
-#line 179 "parser.c"
- switch( (*p) ) {
- case 13: goto st3;
- case 32: goto st3;
- case 47: goto st4;
- case 58: goto st8;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
+ st_case_2:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st2;
+ }
+ case 32: {
+ goto st2;
+ }
+ case 34: {
+ goto ctr2;
+ }
+ case 47: {
+ goto st23;
+ }
+ case 125: {
+ goto ctr4;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st2;
+ }
+ {
+ goto st0;
+ }
+ ctr2:
+ {
+ #line 149 "parser.rl"
+
+ char *np;
+ json->parsing_name = 1;
+ np = JSON_parse_string(json, p, pe, &last_name);
+ json->parsing_name = 0;
+ if (np == NULL) { {p = p - 1; } {p+= 1; cs = 3; goto _out;} } else {p = (( np))-1;}
+
+ }
+
goto st3;
- goto st0;
-st4:
- if ( ++p == pe )
+ st3:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof3;
+ st_case_3:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st3;
+ }
+ case 32: {
+ goto st3;
+ }
+ case 47: {
+ goto st4;
+ }
+ case 58: {
+ goto st8;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st3;
+ }
+ {
+ goto st0;
+ }
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
- switch( (*p) ) {
- case 42: goto st5;
- case 47: goto st7;
- }
- goto st0;
-st5:
- if ( ++p == pe )
+ st_case_4:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st5;
+ }
+ case 47: {
+ goto st7;
+ }
+ }
+ {
+ goto st0;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- if ( (*p) == 42 )
- goto st6;
- goto st5;
-st6:
- if ( ++p == pe )
+ st_case_5:
+ if ( ( (*( p))) == 42 ) {
+ goto st6;
+ }
+ {
+ goto st5;
+ }
+ st6:
+ p+= 1;
+ if ( p == pe )
goto _test_eof6;
-case 6:
- switch( (*p) ) {
- case 42: goto st6;
- case 47: goto st3;
- }
- goto st5;
-st7:
- if ( ++p == pe )
+ st_case_6:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st6;
+ }
+ case 47: {
+ goto st3;
+ }
+ }
+ {
+ goto st5;
+ }
+ st7:
+ p+= 1;
+ if ( p == pe )
goto _test_eof7;
-case 7:
- if ( (*p) == 10 )
- goto st3;
- goto st7;
-st8:
- if ( ++p == pe )
+ st_case_7:
+ if ( ( (*( p))) == 10 ) {
+ goto st3;
+ }
+ {
+ goto st7;
+ }
+ st8:
+ p+= 1;
+ if ( p == pe )
goto _test_eof8;
-case 8:
- switch( (*p) ) {
- case 13: goto st8;
- case 32: goto st8;
- case 34: goto tr11;
- case 45: goto tr11;
- case 47: goto st19;
- case 73: goto tr11;
- case 78: goto tr11;
- case 91: goto tr11;
- case 102: goto tr11;
- case 110: goto tr11;
- case 116: goto tr11;
- case 123: goto tr11;
- }
- if ( (*p) > 10 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto tr11;
- } else if ( (*p) >= 9 )
- goto st8;
- goto st0;
-tr11:
-#line 133 "parser.rl"
- {
- VALUE v = Qnil;
- char *np = JSON_parse_value(json, p, pe, &v, current_nesting);
- if (np == NULL) {
- p--; {p++; cs = 9; goto _out;}
- } else {
- if (NIL_P(json->object_class)) {
- OBJ_FREEZE(last_name);
- rb_hash_aset(*result, last_name, v);
- } else {
- rb_funcall(*result, i_aset, 2, last_name, v);
- }
- {p = (( np))-1;}
- }
- }
- goto st9;
-st9:
- if ( ++p == pe )
- goto _test_eof9;
-case 9:
-#line 267 "parser.c"
- switch( (*p) ) {
- case 13: goto st9;
- case 32: goto st9;
- case 44: goto st10;
- case 47: goto st15;
- case 125: goto tr4;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
+ st_case_8:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st8;
+ }
+ case 32: {
+ goto st8;
+ }
+ case 34: {
+ goto ctr11;
+ }
+ case 45: {
+ goto ctr11;
+ }
+ case 47: {
+ goto st19;
+ }
+ case 73: {
+ goto ctr11;
+ }
+ case 78: {
+ goto ctr11;
+ }
+ case 91: {
+ goto ctr11;
+ }
+ case 102: {
+ goto ctr11;
+ }
+ case 110: {
+ goto ctr11;
+ }
+ case 116: {
+ goto ctr11;
+ }
+ case 123: {
+ goto ctr11;
+ }
+ }
+ if ( ( (*( p))) > 10 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto ctr11;
+ }
+ } else if ( ( (*( p))) >= 9 ) {
+ goto st8;
+ }
+ {
+ goto st0;
+ }
+ ctr11:
+ {
+ #line 133 "parser.rl"
+
+ VALUE v = Qnil;
+ char *np = JSON_parse_value(json, p, pe, &v, current_nesting);
+ if (np == NULL) {
+ {p = p - 1; } {p+= 1; cs = 9; goto _out;}
+ } else {
+ if (NIL_P(json->object_class)) {
+ OBJ_FREEZE(last_name);
+ rb_hash_aset(*result, last_name, v);
+ } else {
+ rb_funcall(*result, i_aset, 2, last_name, v);
+ }
+ {p = (( np))-1;}
+
+ }
+ }
+
goto st9;
- goto st0;
-st10:
- if ( ++p == pe )
+ st9:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof9;
+ st_case_9:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st9;
+ }
+ case 32: {
+ goto st9;
+ }
+ case 44: {
+ goto st10;
+ }
+ case 47: {
+ goto st15;
+ }
+ case 125: {
+ goto ctr4;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st9;
+ }
+ {
+ goto st0;
+ }
+ st10:
+ p+= 1;
+ if ( p == pe )
goto _test_eof10;
-case 10:
- switch( (*p) ) {
- case 13: goto st10;
- case 32: goto st10;
- case 34: goto tr2;
- case 47: goto st11;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
- goto st10;
- goto st0;
-st11:
- if ( ++p == pe )
+ st_case_10:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st10;
+ }
+ case 32: {
+ goto st10;
+ }
+ case 34: {
+ goto ctr2;
+ }
+ case 47: {
+ goto st11;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st10;
+ }
+ {
+ goto st0;
+ }
+ st11:
+ p+= 1;
+ if ( p == pe )
goto _test_eof11;
-case 11:
- switch( (*p) ) {
- case 42: goto st12;
- case 47: goto st14;
- }
- goto st0;
-st12:
- if ( ++p == pe )
+ st_case_11:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st12;
+ }
+ case 47: {
+ goto st14;
+ }
+ }
+ {
+ goto st0;
+ }
+ st12:
+ p+= 1;
+ if ( p == pe )
goto _test_eof12;
-case 12:
- if ( (*p) == 42 )
- goto st13;
- goto st12;
-st13:
- if ( ++p == pe )
+ st_case_12:
+ if ( ( (*( p))) == 42 ) {
+ goto st13;
+ }
+ {
+ goto st12;
+ }
+ st13:
+ p+= 1;
+ if ( p == pe )
goto _test_eof13;
-case 13:
- switch( (*p) ) {
- case 42: goto st13;
- case 47: goto st10;
- }
- goto st12;
-st14:
- if ( ++p == pe )
+ st_case_13:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st13;
+ }
+ case 47: {
+ goto st10;
+ }
+ }
+ {
+ goto st12;
+ }
+ st14:
+ p+= 1;
+ if ( p == pe )
goto _test_eof14;
-case 14:
- if ( (*p) == 10 )
- goto st10;
- goto st14;
-st15:
- if ( ++p == pe )
+ st_case_14:
+ if ( ( (*( p))) == 10 ) {
+ goto st10;
+ }
+ {
+ goto st14;
+ }
+ st15:
+ p+= 1;
+ if ( p == pe )
goto _test_eof15;
-case 15:
- switch( (*p) ) {
- case 42: goto st16;
- case 47: goto st18;
- }
- goto st0;
-st16:
- if ( ++p == pe )
+ st_case_15:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st16;
+ }
+ case 47: {
+ goto st18;
+ }
+ }
+ {
+ goto st0;
+ }
+ st16:
+ p+= 1;
+ if ( p == pe )
goto _test_eof16;
-case 16:
- if ( (*p) == 42 )
- goto st17;
- goto st16;
-st17:
- if ( ++p == pe )
+ st_case_16:
+ if ( ( (*( p))) == 42 ) {
+ goto st17;
+ }
+ {
+ goto st16;
+ }
+ st17:
+ p+= 1;
+ if ( p == pe )
goto _test_eof17;
-case 17:
- switch( (*p) ) {
- case 42: goto st17;
- case 47: goto st9;
- }
- goto st16;
-st18:
- if ( ++p == pe )
+ st_case_17:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st17;
+ }
+ case 47: {
+ goto st9;
+ }
+ }
+ {
+ goto st16;
+ }
+ st18:
+ p+= 1;
+ if ( p == pe )
goto _test_eof18;
-case 18:
- if ( (*p) == 10 )
- goto st9;
- goto st18;
-tr4:
-#line 157 "parser.rl"
- { p--; {p++; cs = 27; goto _out;} }
- goto st27;
-st27:
- if ( ++p == pe )
+ st_case_18:
+ if ( ( (*( p))) == 10 ) {
+ goto st9;
+ }
+ {
+ goto st18;
+ }
+ ctr4:
+ {
+ #line 157 "parser.rl"
+ {p = p - 1; } {p+= 1; cs = 27; goto _out;} }
+
+ goto st27;
+ st27:
+ p+= 1;
+ if ( p == pe )
goto _test_eof27;
-case 27:
-#line 363 "parser.c"
- goto st0;
-st19:
- if ( ++p == pe )
+ st_case_27:
+ {
+ goto st0;
+ }
+ st19:
+ p+= 1;
+ if ( p == pe )
goto _test_eof19;
-case 19:
- switch( (*p) ) {
- case 42: goto st20;
- case 47: goto st22;
- }
- goto st0;
-st20:
- if ( ++p == pe )
+ st_case_19:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st20;
+ }
+ case 47: {
+ goto st22;
+ }
+ }
+ {
+ goto st0;
+ }
+ st20:
+ p+= 1;
+ if ( p == pe )
goto _test_eof20;
-case 20:
- if ( (*p) == 42 )
- goto st21;
- goto st20;
-st21:
- if ( ++p == pe )
+ st_case_20:
+ if ( ( (*( p))) == 42 ) {
+ goto st21;
+ }
+ {
+ goto st20;
+ }
+ st21:
+ p+= 1;
+ if ( p == pe )
goto _test_eof21;
-case 21:
- switch( (*p) ) {
- case 42: goto st21;
- case 47: goto st8;
- }
- goto st20;
-st22:
- if ( ++p == pe )
+ st_case_21:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st21;
+ }
+ case 47: {
+ goto st8;
+ }
+ }
+ {
+ goto st20;
+ }
+ st22:
+ p+= 1;
+ if ( p == pe )
goto _test_eof22;
-case 22:
- if ( (*p) == 10 )
- goto st8;
- goto st22;
-st23:
- if ( ++p == pe )
+ st_case_22:
+ if ( ( (*( p))) == 10 ) {
+ goto st8;
+ }
+ {
+ goto st22;
+ }
+ st23:
+ p+= 1;
+ if ( p == pe )
goto _test_eof23;
-case 23:
- switch( (*p) ) {
- case 42: goto st24;
- case 47: goto st26;
- }
- goto st0;
-st24:
- if ( ++p == pe )
+ st_case_23:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st24;
+ }
+ case 47: {
+ goto st26;
+ }
+ }
+ {
+ goto st0;
+ }
+ st24:
+ p+= 1;
+ if ( p == pe )
goto _test_eof24;
-case 24:
- if ( (*p) == 42 )
- goto st25;
- goto st24;
-st25:
- if ( ++p == pe )
+ st_case_24:
+ if ( ( (*( p))) == 42 ) {
+ goto st25;
+ }
+ {
+ goto st24;
+ }
+ st25:
+ p+= 1;
+ if ( p == pe )
goto _test_eof25;
-case 25:
- switch( (*p) ) {
- case 42: goto st25;
- case 47: goto st2;
- }
- goto st24;
-st26:
- if ( ++p == pe )
+ st_case_25:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st25;
+ }
+ case 47: {
+ goto st2;
+ }
+ }
+ {
+ goto st24;
+ }
+ st26:
+ p+= 1;
+ if ( p == pe )
goto _test_eof26;
-case 26:
- if ( (*p) == 10 )
- goto st2;
- goto st26;
- }
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
- _test_eof6: cs = 6; goto _test_eof;
- _test_eof7: cs = 7; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof9: cs = 9; goto _test_eof;
- _test_eof10: cs = 10; goto _test_eof;
- _test_eof11: cs = 11; goto _test_eof;
- _test_eof12: cs = 12; goto _test_eof;
- _test_eof13: cs = 13; goto _test_eof;
- _test_eof14: cs = 14; goto _test_eof;
- _test_eof15: cs = 15; goto _test_eof;
- _test_eof16: cs = 16; goto _test_eof;
- _test_eof17: cs = 17; goto _test_eof;
- _test_eof18: cs = 18; goto _test_eof;
- _test_eof27: cs = 27; goto _test_eof;
- _test_eof19: cs = 19; goto _test_eof;
- _test_eof20: cs = 20; goto _test_eof;
- _test_eof21: cs = 21; goto _test_eof;
- _test_eof22: cs = 22; goto _test_eof;
- _test_eof23: cs = 23; goto _test_eof;
- _test_eof24: cs = 24; goto _test_eof;
- _test_eof25: cs = 25; goto _test_eof;
- _test_eof26: cs = 26; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ st_case_26:
+ if ( ( (*( p))) == 10 ) {
+ goto st2;
+ }
+ {
+ goto st26;
+ }
+ st_out:
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+ _test_eof18: cs = 18; goto _test_eof;
+ _test_eof27: cs = 27; goto _test_eof;
+ _test_eof19: cs = 19; goto _test_eof;
+ _test_eof20: cs = 20; goto _test_eof;
+ _test_eof21: cs = 21; goto _test_eof;
+ _test_eof22: cs = 22; goto _test_eof;
+ _test_eof23: cs = 23; goto _test_eof;
+ _test_eof24: cs = 24; goto _test_eof;
+ _test_eof25: cs = 25; goto _test_eof;
+ _test_eof26: cs = 26; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 183 "parser.rl"
+
+
+ if (cs >= JSON_object_first_final) {
+ if (json->create_additions) {
+ VALUE klassname;
+ if (NIL_P(json->object_class)) {
+ klassname = rb_hash_aref(*result, json->create_id);
+ } else {
+ klassname = rb_funcall(*result, i_aref, 1, json->create_id);
+ }
+ if (!NIL_P(klassname)) {
+ VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname);
+ if (RTEST(rb_funcall(klass, i_json_creatable_p, 0))) {
+ *result = rb_funcall(klass, i_json_create, 1, *result);
+ }
+ }
+ }
+ return p + 1;
+ } else {
+ return NULL;
}
-
-#line 183 "parser.rl"
-
- if (cs >= JSON_object_first_final) {
- if (json->create_additions) {
- VALUE klassname;
- if (NIL_P(json->object_class)) {
- klassname = rb_hash_aref(*result, json->create_id);
- } else {
- klassname = rb_funcall(*result, i_aref, 1, json->create_id);
- }
- if (!NIL_P(klassname)) {
- VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname);
- if (RTEST(rb_funcall(klass, i_json_creatable_p, 0))) {
- *result = rb_funcall(klass, i_json_create, 1, *result);
- }
- }
- }
- return p + 1;
- } else {
- return NULL;
- }
}
-#line 486 "parser.c"
enum {JSON_value_start = 1};
enum {JSON_value_first_final = 29};
enum {JSON_value_error = 0};
enum {JSON_value_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_value_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_value_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_value_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_value_nfa_pop_trans)[] = {
+ 0, 0
+};
+
#line 283 "parser.rl"
static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
{
- int cs = EVIL;
+ int cs = EVIL;
-#line 502 "parser.c"
{
- cs = JSON_value_start;
+ cs = (int)JSON_value_start;
}
-#line 290 "parser.rl"
+ #line 290 "parser.rl"
+
-#line 509 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-st1:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 29:
+ goto st_case_29;
+ case 2:
+ goto st_case_2;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 5:
+ goto st_case_5;
+ case 6:
+ goto st_case_6;
+ case 7:
+ goto st_case_7;
+ case 8:
+ goto st_case_8;
+ case 9:
+ goto st_case_9;
+ case 10:
+ goto st_case_10;
+ case 11:
+ goto st_case_11;
+ case 12:
+ goto st_case_12;
+ case 13:
+ goto st_case_13;
+ case 14:
+ goto st_case_14;
+ case 15:
+ goto st_case_15;
+ case 16:
+ goto st_case_16;
+ case 17:
+ goto st_case_17;
+ case 18:
+ goto st_case_18;
+ case 19:
+ goto st_case_19;
+ case 20:
+ goto st_case_20;
+ case 21:
+ goto st_case_21;
+ case 22:
+ goto st_case_22;
+ case 23:
+ goto st_case_23;
+ case 24:
+ goto st_case_24;
+ case 25:
+ goto st_case_25;
+ case 26:
+ goto st_case_26;
+ case 27:
+ goto st_case_27;
+ case 28:
+ goto st_case_28;
+ }
+ goto st_out;
+ st1:
+ p+= 1;
+ if ( p == pe )
goto _test_eof1;
-case 1:
- switch( (*p) ) {
- case 13: goto st1;
- case 32: goto st1;
- case 34: goto tr2;
- case 45: goto tr3;
- case 47: goto st6;
- case 73: goto st10;
- case 78: goto st17;
- case 91: goto tr7;
- case 102: goto st19;
- case 110: goto st23;
- case 116: goto st26;
- case 123: goto tr11;
- }
- if ( (*p) > 10 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto tr3;
- } else if ( (*p) >= 9 )
- goto st1;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-tr2:
-#line 235 "parser.rl"
- {
- char *np = JSON_parse_string(json, p, pe, result);
- if (np == NULL) { p--; {p++; cs = 29; goto _out;} } else {p = (( np))-1;}
- }
- goto st29;
-tr3:
-#line 240 "parser.rl"
- {
- char *np;
- if(pe > p + 8 && !strncmp(MinusInfinity, p, 9)) {
- if (json->allow_nan) {
- *result = CMinusInfinity;
- {p = (( p + 10))-1;}
- p--; {p++; cs = 29; goto _out;}
- } else {
- rb_enc_raise(rb_utf8_encoding(), eParserError, "unexpected token at '%s'", p);
- }
- }
- np = JSON_parse_float(json, p, pe, result);
- if (np != NULL) {p = (( np))-1;}
- np = JSON_parse_integer(json, p, pe, result);
- if (np != NULL) {p = (( np))-1;}
- p--; {p++; cs = 29; goto _out;}
- }
- goto st29;
-tr7:
-#line 258 "parser.rl"
- {
- char *np;
- np = JSON_parse_array(json, p, pe, result, current_nesting + 1);
- if (np == NULL) { p--; {p++; cs = 29; goto _out;} } else {p = (( np))-1;}
- }
- goto st29;
-tr11:
-#line 264 "parser.rl"
- {
- char *np;
- np = JSON_parse_object(json, p, pe, result, current_nesting + 1);
- if (np == NULL) { p--; {p++; cs = 29; goto _out;} } else {p = (( np))-1;}
- }
- goto st29;
-tr25:
-#line 228 "parser.rl"
- {
- if (json->allow_nan) {
- *result = CInfinity;
- } else {
- rb_enc_raise(rb_utf8_encoding(), eParserError, "unexpected token at '%s'", p - 7);
- }
- }
- goto st29;
-tr27:
-#line 221 "parser.rl"
- {
- if (json->allow_nan) {
- *result = CNaN;
- } else {
- rb_enc_raise(rb_utf8_encoding(), eParserError, "unexpected token at '%s'", p - 2);
- }
- }
- goto st29;
-tr31:
-#line 215 "parser.rl"
- {
- *result = Qfalse;
- }
- goto st29;
-tr34:
-#line 212 "parser.rl"
- {
- *result = Qnil;
- }
- goto st29;
-tr37:
-#line 218 "parser.rl"
- {
- *result = Qtrue;
- }
- goto st29;
-st29:
- if ( ++p == pe )
- goto _test_eof29;
-case 29:
-#line 270 "parser.rl"
- { p--; {p++; cs = 29; goto _out;} }
-#line 629 "parser.c"
- switch( (*p) ) {
- case 13: goto st29;
- case 32: goto st29;
- case 47: goto st2;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
+ st_case_1:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st1;
+ }
+ case 32: {
+ goto st1;
+ }
+ case 34: {
+ goto ctr2;
+ }
+ case 45: {
+ goto ctr3;
+ }
+ case 47: {
+ goto st6;
+ }
+ case 73: {
+ goto st10;
+ }
+ case 78: {
+ goto st17;
+ }
+ case 91: {
+ goto ctr7;
+ }
+ case 102: {
+ goto st19;
+ }
+ case 110: {
+ goto st23;
+ }
+ case 116: {
+ goto st26;
+ }
+ case 123: {
+ goto ctr11;
+ }
+ }
+ if ( ( (*( p))) > 10 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto ctr3;
+ }
+ } else if ( ( (*( p))) >= 9 ) {
+ goto st1;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ ctr2:
+ {
+ #line 235 "parser.rl"
+
+ char *np = JSON_parse_string(json, p, pe, result);
+ if (np == NULL) { {p = p - 1; } {p+= 1; cs = 29; goto _out;} } else {p = (( np))-1;}
+
+ }
+
+ goto st29;
+ ctr3:
+ {
+ #line 240 "parser.rl"
+
+ char *np;
+ if(pe > p + 8 && !strncmp(MinusInfinity, p, 9)) {
+ if (json->allow_nan) {
+ *result = CMinusInfinity;
+ {p = (( p + 10))-1;}
+
+ {p = p - 1; } {p+= 1; cs = 29; goto _out;}
+ } else {
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
+ }
+ }
+ np = JSON_parse_float(json, p, pe, result);
+ if (np != NULL) {p = (( np))-1;}
+
+ np = JSON_parse_integer(json, p, pe, result);
+ if (np != NULL) {p = (( np))-1;}
+
+ {p = p - 1; } {p+= 1; cs = 29; goto _out;}
+ }
+
goto st29;
- goto st0;
-st2:
- if ( ++p == pe )
+ ctr7:
+ {
+ #line 258 "parser.rl"
+
+ char *np;
+ np = JSON_parse_array(json, p, pe, result, current_nesting + 1);
+ if (np == NULL) { {p = p - 1; } {p+= 1; cs = 29; goto _out;} } else {p = (( np))-1;}
+
+ }
+
+ goto st29;
+ ctr11:
+ {
+ #line 264 "parser.rl"
+
+ char *np;
+ np = JSON_parse_object(json, p, pe, result, current_nesting + 1);
+ if (np == NULL) { {p = p - 1; } {p+= 1; cs = 29; goto _out;} } else {p = (( np))-1;}
+
+ }
+
+ goto st29;
+ ctr25:
+ {
+ #line 228 "parser.rl"
+
+ if (json->allow_nan) {
+ *result = CInfinity;
+ } else {
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 8);
+ }
+ }
+
+ goto st29;
+ ctr27:
+ {
+ #line 221 "parser.rl"
+
+ if (json->allow_nan) {
+ *result = CNaN;
+ } else {
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 2);
+ }
+ }
+
+ goto st29;
+ ctr31:
+ {
+ #line 215 "parser.rl"
+
+ *result = Qfalse;
+ }
+
+ goto st29;
+ ctr34:
+ {
+ #line 212 "parser.rl"
+
+ *result = Qnil;
+ }
+
+ goto st29;
+ ctr37:
+ {
+ #line 218 "parser.rl"
+
+ *result = Qtrue;
+ }
+
+ goto st29;
+ st29:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof29;
+ st_case_29:
+ {
+ #line 270 "parser.rl"
+ {p = p - 1; } {p+= 1; cs = 29; goto _out;} }
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st29;
+ }
+ case 32: {
+ goto st29;
+ }
+ case 47: {
+ goto st2;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st29;
+ }
+ {
+ goto st0;
+ }
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- switch( (*p) ) {
- case 42: goto st3;
- case 47: goto st5;
- }
- goto st0;
-st3:
- if ( ++p == pe )
+ st_case_2:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st3;
+ }
+ case 47: {
+ goto st5;
+ }
+ }
+ {
+ goto st0;
+ }
+ st3:
+ p+= 1;
+ if ( p == pe )
goto _test_eof3;
-case 3:
- if ( (*p) == 42 )
- goto st4;
- goto st3;
-st4:
- if ( ++p == pe )
+ st_case_3:
+ if ( ( (*( p))) == 42 ) {
+ goto st4;
+ }
+ {
+ goto st3;
+ }
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
- switch( (*p) ) {
- case 42: goto st4;
- case 47: goto st29;
- }
- goto st3;
-st5:
- if ( ++p == pe )
+ st_case_4:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st4;
+ }
+ case 47: {
+ goto st29;
+ }
+ }
+ {
+ goto st3;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- if ( (*p) == 10 )
- goto st29;
- goto st5;
-st6:
- if ( ++p == pe )
+ st_case_5:
+ if ( ( (*( p))) == 10 ) {
+ goto st29;
+ }
+ {
+ goto st5;
+ }
+ st6:
+ p+= 1;
+ if ( p == pe )
goto _test_eof6;
-case 6:
- switch( (*p) ) {
- case 42: goto st7;
- case 47: goto st9;
- }
- goto st0;
-st7:
- if ( ++p == pe )
+ st_case_6:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st7;
+ }
+ case 47: {
+ goto st9;
+ }
+ }
+ {
+ goto st0;
+ }
+ st7:
+ p+= 1;
+ if ( p == pe )
goto _test_eof7;
-case 7:
- if ( (*p) == 42 )
- goto st8;
- goto st7;
-st8:
- if ( ++p == pe )
+ st_case_7:
+ if ( ( (*( p))) == 42 ) {
+ goto st8;
+ }
+ {
+ goto st7;
+ }
+ st8:
+ p+= 1;
+ if ( p == pe )
goto _test_eof8;
-case 8:
- switch( (*p) ) {
- case 42: goto st8;
- case 47: goto st1;
- }
- goto st7;
-st9:
- if ( ++p == pe )
+ st_case_8:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st8;
+ }
+ case 47: {
+ goto st1;
+ }
+ }
+ {
+ goto st7;
+ }
+ st9:
+ p+= 1;
+ if ( p == pe )
goto _test_eof9;
-case 9:
- if ( (*p) == 10 )
- goto st1;
- goto st9;
-st10:
- if ( ++p == pe )
+ st_case_9:
+ if ( ( (*( p))) == 10 ) {
+ goto st1;
+ }
+ {
+ goto st9;
+ }
+ st10:
+ p+= 1;
+ if ( p == pe )
goto _test_eof10;
-case 10:
- if ( (*p) == 110 )
- goto st11;
- goto st0;
-st11:
- if ( ++p == pe )
+ st_case_10:
+ if ( ( (*( p))) == 110 ) {
+ goto st11;
+ }
+ {
+ goto st0;
+ }
+ st11:
+ p+= 1;
+ if ( p == pe )
goto _test_eof11;
-case 11:
- if ( (*p) == 102 )
- goto st12;
- goto st0;
-st12:
- if ( ++p == pe )
+ st_case_11:
+ if ( ( (*( p))) == 102 ) {
+ goto st12;
+ }
+ {
+ goto st0;
+ }
+ st12:
+ p+= 1;
+ if ( p == pe )
goto _test_eof12;
-case 12:
- if ( (*p) == 105 )
- goto st13;
- goto st0;
-st13:
- if ( ++p == pe )
+ st_case_12:
+ if ( ( (*( p))) == 105 ) {
+ goto st13;
+ }
+ {
+ goto st0;
+ }
+ st13:
+ p+= 1;
+ if ( p == pe )
goto _test_eof13;
-case 13:
- if ( (*p) == 110 )
- goto st14;
- goto st0;
-st14:
- if ( ++p == pe )
+ st_case_13:
+ if ( ( (*( p))) == 110 ) {
+ goto st14;
+ }
+ {
+ goto st0;
+ }
+ st14:
+ p+= 1;
+ if ( p == pe )
goto _test_eof14;
-case 14:
- if ( (*p) == 105 )
- goto st15;
- goto st0;
-st15:
- if ( ++p == pe )
+ st_case_14:
+ if ( ( (*( p))) == 105 ) {
+ goto st15;
+ }
+ {
+ goto st0;
+ }
+ st15:
+ p+= 1;
+ if ( p == pe )
goto _test_eof15;
-case 15:
- if ( (*p) == 116 )
- goto st16;
- goto st0;
-st16:
- if ( ++p == pe )
+ st_case_15:
+ if ( ( (*( p))) == 116 ) {
+ goto st16;
+ }
+ {
+ goto st0;
+ }
+ st16:
+ p+= 1;
+ if ( p == pe )
goto _test_eof16;
-case 16:
- if ( (*p) == 121 )
- goto tr25;
- goto st0;
-st17:
- if ( ++p == pe )
+ st_case_16:
+ if ( ( (*( p))) == 121 ) {
+ goto ctr25;
+ }
+ {
+ goto st0;
+ }
+ st17:
+ p+= 1;
+ if ( p == pe )
goto _test_eof17;
-case 17:
- if ( (*p) == 97 )
- goto st18;
- goto st0;
-st18:
- if ( ++p == pe )
+ st_case_17:
+ if ( ( (*( p))) == 97 ) {
+ goto st18;
+ }
+ {
+ goto st0;
+ }
+ st18:
+ p+= 1;
+ if ( p == pe )
goto _test_eof18;
-case 18:
- if ( (*p) == 78 )
- goto tr27;
- goto st0;
-st19:
- if ( ++p == pe )
+ st_case_18:
+ if ( ( (*( p))) == 78 ) {
+ goto ctr27;
+ }
+ {
+ goto st0;
+ }
+ st19:
+ p+= 1;
+ if ( p == pe )
goto _test_eof19;
-case 19:
- if ( (*p) == 97 )
- goto st20;
- goto st0;
-st20:
- if ( ++p == pe )
+ st_case_19:
+ if ( ( (*( p))) == 97 ) {
+ goto st20;
+ }
+ {
+ goto st0;
+ }
+ st20:
+ p+= 1;
+ if ( p == pe )
goto _test_eof20;
-case 20:
- if ( (*p) == 108 )
- goto st21;
- goto st0;
-st21:
- if ( ++p == pe )
+ st_case_20:
+ if ( ( (*( p))) == 108 ) {
+ goto st21;
+ }
+ {
+ goto st0;
+ }
+ st21:
+ p+= 1;
+ if ( p == pe )
goto _test_eof21;
-case 21:
- if ( (*p) == 115 )
- goto st22;
- goto st0;
-st22:
- if ( ++p == pe )
+ st_case_21:
+ if ( ( (*( p))) == 115 ) {
+ goto st22;
+ }
+ {
+ goto st0;
+ }
+ st22:
+ p+= 1;
+ if ( p == pe )
goto _test_eof22;
-case 22:
- if ( (*p) == 101 )
- goto tr31;
- goto st0;
-st23:
- if ( ++p == pe )
+ st_case_22:
+ if ( ( (*( p))) == 101 ) {
+ goto ctr31;
+ }
+ {
+ goto st0;
+ }
+ st23:
+ p+= 1;
+ if ( p == pe )
goto _test_eof23;
-case 23:
- if ( (*p) == 117 )
- goto st24;
- goto st0;
-st24:
- if ( ++p == pe )
+ st_case_23:
+ if ( ( (*( p))) == 117 ) {
+ goto st24;
+ }
+ {
+ goto st0;
+ }
+ st24:
+ p+= 1;
+ if ( p == pe )
goto _test_eof24;
-case 24:
- if ( (*p) == 108 )
- goto st25;
- goto st0;
-st25:
- if ( ++p == pe )
+ st_case_24:
+ if ( ( (*( p))) == 108 ) {
+ goto st25;
+ }
+ {
+ goto st0;
+ }
+ st25:
+ p+= 1;
+ if ( p == pe )
goto _test_eof25;
-case 25:
- if ( (*p) == 108 )
- goto tr34;
- goto st0;
-st26:
- if ( ++p == pe )
+ st_case_25:
+ if ( ( (*( p))) == 108 ) {
+ goto ctr34;
+ }
+ {
+ goto st0;
+ }
+ st26:
+ p+= 1;
+ if ( p == pe )
goto _test_eof26;
-case 26:
- if ( (*p) == 114 )
- goto st27;
- goto st0;
-st27:
- if ( ++p == pe )
+ st_case_26:
+ if ( ( (*( p))) == 114 ) {
+ goto st27;
+ }
+ {
+ goto st0;
+ }
+ st27:
+ p+= 1;
+ if ( p == pe )
goto _test_eof27;
-case 27:
- if ( (*p) == 117 )
- goto st28;
- goto st0;
-st28:
- if ( ++p == pe )
+ st_case_27:
+ if ( ( (*( p))) == 117 ) {
+ goto st28;
+ }
+ {
+ goto st0;
+ }
+ st28:
+ p+= 1;
+ if ( p == pe )
goto _test_eof28;
-case 28:
- if ( (*p) == 101 )
- goto tr37;
- goto st0;
- }
- _test_eof1: cs = 1; goto _test_eof;
- _test_eof29: cs = 29; goto _test_eof;
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
- _test_eof6: cs = 6; goto _test_eof;
- _test_eof7: cs = 7; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof9: cs = 9; goto _test_eof;
- _test_eof10: cs = 10; goto _test_eof;
- _test_eof11: cs = 11; goto _test_eof;
- _test_eof12: cs = 12; goto _test_eof;
- _test_eof13: cs = 13; goto _test_eof;
- _test_eof14: cs = 14; goto _test_eof;
- _test_eof15: cs = 15; goto _test_eof;
- _test_eof16: cs = 16; goto _test_eof;
- _test_eof17: cs = 17; goto _test_eof;
- _test_eof18: cs = 18; goto _test_eof;
- _test_eof19: cs = 19; goto _test_eof;
- _test_eof20: cs = 20; goto _test_eof;
- _test_eof21: cs = 21; goto _test_eof;
- _test_eof22: cs = 22; goto _test_eof;
- _test_eof23: cs = 23; goto _test_eof;
- _test_eof24: cs = 24; goto _test_eof;
- _test_eof25: cs = 25; goto _test_eof;
- _test_eof26: cs = 26; goto _test_eof;
- _test_eof27: cs = 27; goto _test_eof;
- _test_eof28: cs = 28; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ st_case_28:
+ if ( ( (*( p))) == 101 ) {
+ goto ctr37;
+ }
+ {
+ goto st0;
+ }
+ st_out:
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof29: cs = 29; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+ _test_eof18: cs = 18; goto _test_eof;
+ _test_eof19: cs = 19; goto _test_eof;
+ _test_eof20: cs = 20; goto _test_eof;
+ _test_eof21: cs = 21; goto _test_eof;
+ _test_eof22: cs = 22; goto _test_eof;
+ _test_eof23: cs = 23; goto _test_eof;
+ _test_eof24: cs = 24; goto _test_eof;
+ _test_eof25: cs = 25; goto _test_eof;
+ _test_eof26: cs = 26; goto _test_eof;
+ _test_eof27: cs = 27; goto _test_eof;
+ _test_eof28: cs = 28; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 291 "parser.rl"
+
+
+ if (json->freeze) {
+ OBJ_FREEZE(*result);
+ }
+
+ if (cs >= JSON_value_first_final) {
+ return p;
+ } else {
+ return NULL;
}
-
-#line 291 "parser.rl"
-
- if (json->freeze) {
- OBJ_FREEZE(*result);
- }
-
- if (cs >= JSON_value_first_final) {
- return p;
- } else {
- return NULL;
- }
}
-#line 884 "parser.c"
enum {JSON_integer_start = 1};
enum {JSON_integer_first_final = 3};
enum {JSON_integer_error = 0};
enum {JSON_integer_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_integer_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_integer_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_integer_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_integer_nfa_pop_trans)[] = {
+ 0, 0
+};
+
#line 311 "parser.rl"
static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result)
{
- int cs = EVIL;
+ int cs = EVIL;
-#line 900 "parser.c"
{
- cs = JSON_integer_start;
+ cs = (int)JSON_integer_start;
}
-#line 318 "parser.rl"
- json->memo = p;
+ #line 318 "parser.rl"
+
+ json->memo = p;
-#line 908 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-case 1:
- switch( (*p) ) {
- case 45: goto st2;
- case 48: goto st3;
- }
- if ( 49 <= (*p) && (*p) <= 57 )
- goto st5;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-st2:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 2:
+ goto st_case_2;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 5:
+ goto st_case_5;
+ }
+ goto st_out;
+ st_case_1:
+ switch( ( (*( p))) ) {
+ case 45: {
+ goto st2;
+ }
+ case 48: {
+ goto st3;
+ }
+ }
+ if ( 49 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st5;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- if ( (*p) == 48 )
- goto st3;
- if ( 49 <= (*p) && (*p) <= 57 )
- goto st5;
- goto st0;
-st3:
- if ( ++p == pe )
+ st_case_2:
+ if ( ( (*( p))) == 48 ) {
+ goto st3;
+ }
+ if ( 49 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st5;
+ }
+ {
+ goto st0;
+ }
+ st3:
+ p+= 1;
+ if ( p == pe )
goto _test_eof3;
-case 3:
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st0;
- goto tr4;
-tr4:
-#line 308 "parser.rl"
- { p--; {p++; cs = 4; goto _out;} }
- goto st4;
-st4:
- if ( ++p == pe )
+ st_case_3:
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st0;
+ }
+ {
+ goto ctr4;
+ }
+ ctr4:
+ {
+ #line 308 "parser.rl"
+ {p = p - 1; } {p+= 1; cs = 4; goto _out;} }
+
+ goto st4;
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
-#line 949 "parser.c"
- goto st0;
-st5:
- if ( ++p == pe )
+ st_case_4:
+ {
+ goto st0;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st5;
- goto tr4;
- }
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ st_case_5:
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st5;
+ }
+ {
+ goto ctr4;
+ }
+ st_out:
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 320 "parser.rl"
+
+
+ if (cs >= JSON_integer_first_final) {
+ long len = p - json->memo;
+ fbuffer_clear(json->fbuffer);
+ fbuffer_append(json->fbuffer, json->memo, len);
+ fbuffer_append_char(json->fbuffer, '\0');
+ *result = rb_cstr2inum(FBUFFER_PTR(json->fbuffer), 10);
+ return p + 1;
+ } else {
+ return NULL;
}
-
-#line 320 "parser.rl"
-
- if (cs >= JSON_integer_first_final) {
- long len = p - json->memo;
- fbuffer_clear(json->fbuffer);
- fbuffer_append(json->fbuffer, json->memo, len);
- fbuffer_append_char(json->fbuffer, '\0');
- *result = rb_cstr2inum(FBUFFER_PTR(json->fbuffer), 10);
- return p + 1;
- } else {
- return NULL;
- }
}
-#line 983 "parser.c"
enum {JSON_float_start = 1};
enum {JSON_float_first_final = 8};
enum {JSON_float_error = 0};
enum {JSON_float_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_float_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_float_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_float_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_float_nfa_pop_trans)[] = {
+ 0, 0
+};
+
#line 345 "parser.rl"
static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)
{
- int cs = EVIL;
+ int cs = EVIL;
-#line 999 "parser.c"
{
- cs = JSON_float_start;
+ cs = (int)JSON_float_start;
}
-#line 352 "parser.rl"
- json->memo = p;
+ #line 352 "parser.rl"
+
+ json->memo = p;
-#line 1007 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-case 1:
- switch( (*p) ) {
- case 45: goto st2;
- case 48: goto st3;
- }
- if ( 49 <= (*p) && (*p) <= 57 )
- goto st7;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-st2:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 2:
+ goto st_case_2;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 8:
+ goto st_case_8;
+ case 9:
+ goto st_case_9;
+ case 5:
+ goto st_case_5;
+ case 6:
+ goto st_case_6;
+ case 10:
+ goto st_case_10;
+ case 7:
+ goto st_case_7;
+ }
+ goto st_out;
+ st_case_1:
+ switch( ( (*( p))) ) {
+ case 45: {
+ goto st2;
+ }
+ case 48: {
+ goto st3;
+ }
+ }
+ if ( 49 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st7;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- if ( (*p) == 48 )
- goto st3;
- if ( 49 <= (*p) && (*p) <= 57 )
- goto st7;
- goto st0;
-st3:
- if ( ++p == pe )
+ st_case_2:
+ if ( ( (*( p))) == 48 ) {
+ goto st3;
+ }
+ if ( 49 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st7;
+ }
+ {
+ goto st0;
+ }
+ st3:
+ p+= 1;
+ if ( p == pe )
goto _test_eof3;
-case 3:
- switch( (*p) ) {
- case 46: goto st4;
- case 69: goto st5;
- case 101: goto st5;
- }
- goto st0;
-st4:
- if ( ++p == pe )
+ st_case_3:
+ switch( ( (*( p))) ) {
+ case 46: {
+ goto st4;
+ }
+ case 69: {
+ goto st5;
+ }
+ case 101: {
+ goto st5;
+ }
+ }
+ {
+ goto st0;
+ }
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st8;
- goto st0;
-st8:
- if ( ++p == pe )
- goto _test_eof8;
-case 8:
- switch( (*p) ) {
- case 69: goto st5;
- case 101: goto st5;
- }
- if ( (*p) > 46 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
+ st_case_4:
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
goto st8;
- } else if ( (*p) >= 45 )
- goto st0;
- goto tr9;
-tr9:
-#line 339 "parser.rl"
- { p--; {p++; cs = 9; goto _out;} }
- goto st9;
-st9:
- if ( ++p == pe )
+ }
+ {
+ goto st0;
+ }
+ st8:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof8;
+ st_case_8:
+ switch( ( (*( p))) ) {
+ case 69: {
+ goto st5;
+ }
+ case 101: {
+ goto st5;
+ }
+ }
+ if ( ( (*( p))) > 46 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st8;
+ }
+ } else if ( ( (*( p))) >= 45 ) {
+ goto st0;
+ }
+ {
+ goto ctr9;
+ }
+ ctr9:
+ {
+ #line 339 "parser.rl"
+ {p = p - 1; } {p+= 1; cs = 9; goto _out;} }
+
+ goto st9;
+ st9:
+ p+= 1;
+ if ( p == pe )
goto _test_eof9;
-case 9:
-#line 1072 "parser.c"
- goto st0;
-st5:
- if ( ++p == pe )
+ st_case_9:
+ {
+ goto st0;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- switch( (*p) ) {
- case 43: goto st6;
- case 45: goto st6;
- }
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st10;
- goto st0;
-st6:
- if ( ++p == pe )
+ st_case_5:
+ switch( ( (*( p))) ) {
+ case 43: {
+ goto st6;
+ }
+ case 45: {
+ goto st6;
+ }
+ }
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st10;
+ }
+ {
+ goto st0;
+ }
+ st6:
+ p+= 1;
+ if ( p == pe )
goto _test_eof6;
-case 6:
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st10;
- goto st0;
-st10:
- if ( ++p == pe )
- goto _test_eof10;
-case 10:
- switch( (*p) ) {
- case 69: goto st0;
- case 101: goto st0;
- }
- if ( (*p) > 46 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
+ st_case_6:
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
goto st10;
- } else if ( (*p) >= 45 )
- goto st0;
- goto tr9;
-st7:
- if ( ++p == pe )
+ }
+ {
+ goto st0;
+ }
+ st10:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof10;
+ st_case_10:
+ switch( ( (*( p))) ) {
+ case 69: {
+ goto st0;
+ }
+ case 101: {
+ goto st0;
+ }
+ }
+ if ( ( (*( p))) > 46 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st10;
+ }
+ } else if ( ( (*( p))) >= 45 ) {
+ goto st0;
+ }
+ {
+ goto ctr9;
+ }
+ st7:
+ p+= 1;
+ if ( p == pe )
goto _test_eof7;
-case 7:
- switch( (*p) ) {
- case 46: goto st4;
- case 69: goto st5;
- case 101: goto st5;
- }
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st7;
- goto st0;
- }
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof9: cs = 9; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
- _test_eof6: cs = 6; goto _test_eof;
- _test_eof10: cs = 10; goto _test_eof;
- _test_eof7: cs = 7; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ st_case_7:
+ switch( ( (*( p))) ) {
+ case 46: {
+ goto st4;
+ }
+ case 69: {
+ goto st5;
+ }
+ case 101: {
+ goto st5;
+ }
+ }
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st7;
+ }
+ {
+ goto st0;
+ }
+ st_out:
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 354 "parser.rl"
+
+
+ if (cs >= JSON_float_first_final) {
+ VALUE mod = Qnil;
+ ID method_id = 0;
+ if (rb_respond_to(json->decimal_class, i_try_convert)) {
+ mod = json->decimal_class;
+ method_id = i_try_convert;
+ } else if (rb_respond_to(json->decimal_class, i_new)) {
+ mod = json->decimal_class;
+ method_id = i_new;
+ } else if (RB_TYPE_P(json->decimal_class, T_CLASS)) {
+ VALUE name = rb_class_name(json->decimal_class);
+ const char *name_cstr = RSTRING_PTR(name);
+ const char *last_colon = strrchr(name_cstr, ':');
+ if (last_colon) {
+ const char *mod_path_end = last_colon - 1;
+ VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
+ mod = rb_path_to_class(mod_path);
+
+ const char *method_name_beg = last_colon + 1;
+ long before_len = method_name_beg - name_cstr;
+ long len = RSTRING_LEN(name) - before_len;
+ VALUE method_name = rb_str_substr(name, before_len, len);
+ method_id = SYM2ID(rb_str_intern(method_name));
+ } else {
+ mod = rb_mKernel;
+ method_id = SYM2ID(rb_str_intern(name));
+ }
+ }
+
+ long len = p - json->memo;
+ fbuffer_clear(json->fbuffer);
+ fbuffer_append(json->fbuffer, json->memo, len);
+ fbuffer_append_char(json->fbuffer, '\0');
+
+ if (method_id) {
+ VALUE text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
+ *result = rb_funcallv(mod, method_id, 1, &text);
+ } else {
+ *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
+ }
+
+ return p + 1;
+ } else {
+ return NULL;
}
-
-#line 354 "parser.rl"
-
- if (cs >= JSON_float_first_final) {
- VALUE mod = Qnil;
- ID method_id = 0;
- if (rb_respond_to(json->decimal_class, i_try_convert)) {
- mod = json->decimal_class;
- method_id = i_try_convert;
- } else if (rb_respond_to(json->decimal_class, i_new)) {
- mod = json->decimal_class;
- method_id = i_new;
- } else if (RB_TYPE_P(json->decimal_class, T_CLASS)) {
- VALUE name = rb_class_name(json->decimal_class);
- const char *name_cstr = RSTRING_PTR(name);
- const char *last_colon = strrchr(name_cstr, ':');
- if (last_colon) {
- const char *mod_path_end = last_colon - 1;
- VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
- mod = rb_path_to_class(mod_path);
-
- const char *method_name_beg = last_colon + 1;
- long before_len = method_name_beg - name_cstr;
- long len = RSTRING_LEN(name) - before_len;
- VALUE method_name = rb_str_substr(name, before_len, len);
- method_id = SYM2ID(rb_str_intern(method_name));
- } else {
- mod = rb_mKernel;
- method_id = SYM2ID(rb_str_intern(name));
- }
- }
-
- long len = p - json->memo;
- fbuffer_clear(json->fbuffer);
- fbuffer_append(json->fbuffer, json->memo, len);
- fbuffer_append_char(json->fbuffer, '\0');
-
- if (method_id) {
- VALUE text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
- *result = rb_funcallv(mod, method_id, 1, &text);
- } else {
- *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
- }
-
- return p + 1;
- } else {
- return NULL;
- }
}
-#line 1184 "parser.c"
enum {JSON_array_start = 1};
enum {JSON_array_first_final = 17};
enum {JSON_array_error = 0};
enum {JSON_array_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_array_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_array_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_array_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_array_nfa_pop_trans)[] = {
+ 0, 0
+};
+
#line 432 "parser.rl"
static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
{
- int cs = EVIL;
- VALUE array_class = json->array_class;
+ int cs = EVIL;
+ VALUE array_class = json->array_class;
- if (json->max_nesting && current_nesting > json->max_nesting) {
- rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
- }
- *result = NIL_P(array_class) ? rb_ary_new() : rb_class_new_instance(0, 0, array_class);
+ if (json->max_nesting && current_nesting > json->max_nesting) {
+ rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
+ }
+ *result = NIL_P(array_class) ? rb_ary_new() : rb_class_new_instance(0, 0, array_class);
-#line 1206 "parser.c"
{
- cs = JSON_array_start;
+ cs = (int)JSON_array_start;
}
-#line 445 "parser.rl"
+ #line 445 "parser.rl"
+
-#line 1213 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-case 1:
- if ( (*p) == 91 )
- goto st2;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-st2:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 2:
+ goto st_case_2;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 5:
+ goto st_case_5;
+ case 6:
+ goto st_case_6;
+ case 7:
+ goto st_case_7;
+ case 8:
+ goto st_case_8;
+ case 9:
+ goto st_case_9;
+ case 10:
+ goto st_case_10;
+ case 11:
+ goto st_case_11;
+ case 12:
+ goto st_case_12;
+ case 17:
+ goto st_case_17;
+ case 13:
+ goto st_case_13;
+ case 14:
+ goto st_case_14;
+ case 15:
+ goto st_case_15;
+ case 16:
+ goto st_case_16;
+ }
+ goto st_out;
+ st_case_1:
+ if ( ( (*( p))) == 91 ) {
+ goto st2;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- switch( (*p) ) {
- case 13: goto st2;
- case 32: goto st2;
- case 34: goto tr2;
- case 45: goto tr2;
- case 47: goto st13;
- case 73: goto tr2;
- case 78: goto tr2;
- case 91: goto tr2;
- case 93: goto tr4;
- case 102: goto tr2;
- case 110: goto tr2;
- case 116: goto tr2;
- case 123: goto tr2;
- }
- if ( (*p) > 10 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto tr2;
- } else if ( (*p) >= 9 )
- goto st2;
- goto st0;
-tr2:
-#line 409 "parser.rl"
- {
- VALUE v = Qnil;
- char *np = JSON_parse_value(json, p, pe, &v, current_nesting);
- if (np == NULL) {
- p--; {p++; cs = 3; goto _out;}
- } else {
- if (NIL_P(json->array_class)) {
- rb_ary_push(*result, v);
- } else {
- rb_funcall(*result, i_leftshift, 1, v);
- }
- {p = (( np))-1;}
- }
- }
- goto st3;
-st3:
- if ( ++p == pe )
- goto _test_eof3;
-case 3:
-#line 1272 "parser.c"
- switch( (*p) ) {
- case 13: goto st3;
- case 32: goto st3;
- case 44: goto st4;
- case 47: goto st9;
- case 93: goto tr4;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
+ st_case_2:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st2;
+ }
+ case 32: {
+ goto st2;
+ }
+ case 34: {
+ goto ctr2;
+ }
+ case 45: {
+ goto ctr2;
+ }
+ case 47: {
+ goto st13;
+ }
+ case 73: {
+ goto ctr2;
+ }
+ case 78: {
+ goto ctr2;
+ }
+ case 91: {
+ goto ctr2;
+ }
+ case 93: {
+ goto ctr4;
+ }
+ case 102: {
+ goto ctr2;
+ }
+ case 110: {
+ goto ctr2;
+ }
+ case 116: {
+ goto ctr2;
+ }
+ case 123: {
+ goto ctr2;
+ }
+ }
+ if ( ( (*( p))) > 10 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto ctr2;
+ }
+ } else if ( ( (*( p))) >= 9 ) {
+ goto st2;
+ }
+ {
+ goto st0;
+ }
+ ctr2:
+ {
+ #line 409 "parser.rl"
+
+ VALUE v = Qnil;
+ char *np = JSON_parse_value(json, p, pe, &v, current_nesting);
+ if (np == NULL) {
+ {p = p - 1; } {p+= 1; cs = 3; goto _out;}
+ } else {
+ if (NIL_P(json->array_class)) {
+ rb_ary_push(*result, v);
+ } else {
+ rb_funcall(*result, i_leftshift, 1, v);
+ }
+ {p = (( np))-1;}
+
+ }
+ }
+
goto st3;
- goto st0;
-st4:
- if ( ++p == pe )
+ st3:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof3;
+ st_case_3:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st3;
+ }
+ case 32: {
+ goto st3;
+ }
+ case 44: {
+ goto st4;
+ }
+ case 47: {
+ goto st9;
+ }
+ case 93: {
+ goto ctr4;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st3;
+ }
+ {
+ goto st0;
+ }
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
- switch( (*p) ) {
- case 13: goto st4;
- case 32: goto st4;
- case 34: goto tr2;
- case 45: goto tr2;
- case 47: goto st5;
- case 73: goto tr2;
- case 78: goto tr2;
- case 91: goto tr2;
- case 102: goto tr2;
- case 110: goto tr2;
- case 116: goto tr2;
- case 123: goto tr2;
- }
- if ( (*p) > 10 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto tr2;
- } else if ( (*p) >= 9 )
- goto st4;
- goto st0;
-st5:
- if ( ++p == pe )
+ st_case_4:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st4;
+ }
+ case 32: {
+ goto st4;
+ }
+ case 34: {
+ goto ctr2;
+ }
+ case 45: {
+ goto ctr2;
+ }
+ case 47: {
+ goto st5;
+ }
+ case 73: {
+ goto ctr2;
+ }
+ case 78: {
+ goto ctr2;
+ }
+ case 91: {
+ goto ctr2;
+ }
+ case 102: {
+ goto ctr2;
+ }
+ case 110: {
+ goto ctr2;
+ }
+ case 116: {
+ goto ctr2;
+ }
+ case 123: {
+ goto ctr2;
+ }
+ }
+ if ( ( (*( p))) > 10 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto ctr2;
+ }
+ } else if ( ( (*( p))) >= 9 ) {
+ goto st4;
+ }
+ {
+ goto st0;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- switch( (*p) ) {
- case 42: goto st6;
- case 47: goto st8;
- }
- goto st0;
-st6:
- if ( ++p == pe )
+ st_case_5:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st6;
+ }
+ case 47: {
+ goto st8;
+ }
+ }
+ {
+ goto st0;
+ }
+ st6:
+ p+= 1;
+ if ( p == pe )
goto _test_eof6;
-case 6:
- if ( (*p) == 42 )
- goto st7;
- goto st6;
-st7:
- if ( ++p == pe )
+ st_case_6:
+ if ( ( (*( p))) == 42 ) {
+ goto st7;
+ }
+ {
+ goto st6;
+ }
+ st7:
+ p+= 1;
+ if ( p == pe )
goto _test_eof7;
-case 7:
- switch( (*p) ) {
- case 42: goto st7;
- case 47: goto st4;
- }
- goto st6;
-st8:
- if ( ++p == pe )
+ st_case_7:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st7;
+ }
+ case 47: {
+ goto st4;
+ }
+ }
+ {
+ goto st6;
+ }
+ st8:
+ p+= 1;
+ if ( p == pe )
goto _test_eof8;
-case 8:
- if ( (*p) == 10 )
- goto st4;
- goto st8;
-st9:
- if ( ++p == pe )
+ st_case_8:
+ if ( ( (*( p))) == 10 ) {
+ goto st4;
+ }
+ {
+ goto st8;
+ }
+ st9:
+ p+= 1;
+ if ( p == pe )
goto _test_eof9;
-case 9:
- switch( (*p) ) {
- case 42: goto st10;
- case 47: goto st12;
- }
- goto st0;
-st10:
- if ( ++p == pe )
+ st_case_9:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st10;
+ }
+ case 47: {
+ goto st12;
+ }
+ }
+ {
+ goto st0;
+ }
+ st10:
+ p+= 1;
+ if ( p == pe )
goto _test_eof10;
-case 10:
- if ( (*p) == 42 )
- goto st11;
- goto st10;
-st11:
- if ( ++p == pe )
+ st_case_10:
+ if ( ( (*( p))) == 42 ) {
+ goto st11;
+ }
+ {
+ goto st10;
+ }
+ st11:
+ p+= 1;
+ if ( p == pe )
goto _test_eof11;
-case 11:
- switch( (*p) ) {
- case 42: goto st11;
- case 47: goto st3;
- }
- goto st10;
-st12:
- if ( ++p == pe )
+ st_case_11:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st11;
+ }
+ case 47: {
+ goto st3;
+ }
+ }
+ {
+ goto st10;
+ }
+ st12:
+ p+= 1;
+ if ( p == pe )
goto _test_eof12;
-case 12:
- if ( (*p) == 10 )
- goto st3;
- goto st12;
-tr4:
-#line 424 "parser.rl"
- { p--; {p++; cs = 17; goto _out;} }
- goto st17;
-st17:
- if ( ++p == pe )
+ st_case_12:
+ if ( ( (*( p))) == 10 ) {
+ goto st3;
+ }
+ {
+ goto st12;
+ }
+ ctr4:
+ {
+ #line 424 "parser.rl"
+ {p = p - 1; } {p+= 1; cs = 17; goto _out;} }
+
+ goto st17;
+ st17:
+ p+= 1;
+ if ( p == pe )
goto _test_eof17;
-case 17:
-#line 1379 "parser.c"
- goto st0;
-st13:
- if ( ++p == pe )
+ st_case_17:
+ {
+ goto st0;
+ }
+ st13:
+ p+= 1;
+ if ( p == pe )
goto _test_eof13;
-case 13:
- switch( (*p) ) {
- case 42: goto st14;
- case 47: goto st16;
- }
- goto st0;
-st14:
- if ( ++p == pe )
+ st_case_13:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st14;
+ }
+ case 47: {
+ goto st16;
+ }
+ }
+ {
+ goto st0;
+ }
+ st14:
+ p+= 1;
+ if ( p == pe )
goto _test_eof14;
-case 14:
- if ( (*p) == 42 )
- goto st15;
- goto st14;
-st15:
- if ( ++p == pe )
+ st_case_14:
+ if ( ( (*( p))) == 42 ) {
+ goto st15;
+ }
+ {
+ goto st14;
+ }
+ st15:
+ p+= 1;
+ if ( p == pe )
goto _test_eof15;
-case 15:
- switch( (*p) ) {
- case 42: goto st15;
- case 47: goto st2;
- }
- goto st14;
-st16:
- if ( ++p == pe )
+ st_case_15:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st15;
+ }
+ case 47: {
+ goto st2;
+ }
+ }
+ {
+ goto st14;
+ }
+ st16:
+ p+= 1;
+ if ( p == pe )
goto _test_eof16;
-case 16:
- if ( (*p) == 10 )
- goto st2;
- goto st16;
- }
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
- _test_eof6: cs = 6; goto _test_eof;
- _test_eof7: cs = 7; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof9: cs = 9; goto _test_eof;
- _test_eof10: cs = 10; goto _test_eof;
- _test_eof11: cs = 11; goto _test_eof;
- _test_eof12: cs = 12; goto _test_eof;
- _test_eof17: cs = 17; goto _test_eof;
- _test_eof13: cs = 13; goto _test_eof;
- _test_eof14: cs = 14; goto _test_eof;
- _test_eof15: cs = 15; goto _test_eof;
- _test_eof16: cs = 16; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ st_case_16:
+ if ( ( (*( p))) == 10 ) {
+ goto st2;
+ }
+ {
+ goto st16;
+ }
+ st_out:
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof11: cs = 11; goto _test_eof;
+ _test_eof12: cs = 12; goto _test_eof;
+ _test_eof17: cs = 17; goto _test_eof;
+ _test_eof13: cs = 13; goto _test_eof;
+ _test_eof14: cs = 14; goto _test_eof;
+ _test_eof15: cs = 15; goto _test_eof;
+ _test_eof16: cs = 16; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 446 "parser.rl"
+
+
+ if(cs >= JSON_array_first_final) {
+ return p + 1;
+ } else {
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
+ return NULL;
}
-
-#line 446 "parser.rl"
-
- if(cs >= JSON_array_first_final) {
- return p + 1;
- } else {
- rb_enc_raise(rb_utf8_encoding(), eParserError, "unexpected token at '%s'", p);
- return NULL;
- }
}
static const size_t MAX_STACK_BUFFER_SIZE = 128;
static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int symbolize)
{
- VALUE result = Qnil;
- size_t bufferSize = stringEnd - string;
- char *p = string, *pe = string, *unescape, *bufferStart, *buffer;
- int unescape_len;
- char buf[4];
+ VALUE result = Qnil;
+ size_t bufferSize = stringEnd - string;
+ char *p = string, *pe = string, *unescape, *bufferStart, *buffer;
+ int unescape_len;
+ char buf[4];
- if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
# ifdef HAVE_RB_ENC_INTERNED_STR
- bufferStart = buffer = ALLOC_N(char, bufferSize ? bufferSize : 1);
+ bufferStart = buffer = ALLOC_N(char, bufferSize ? bufferSize : 1);
# else
- bufferStart = buffer = ALLOC_N(char, bufferSize);
+ bufferStart = buffer = ALLOC_N(char, bufferSize);
# endif
- } else {
+ } else {
# ifdef HAVE_RB_ENC_INTERNED_STR
- bufferStart = buffer = ALLOCA_N(char, bufferSize ? bufferSize : 1);
+ bufferStart = buffer = ALLOCA_N(char, bufferSize ? bufferSize : 1);
# else
- bufferStart = buffer = ALLOCA_N(char, bufferSize);
+ bufferStart = buffer = ALLOCA_N(char, bufferSize);
# endif
- }
-
- while (pe < stringEnd) {
- if (*pe == '\\') {
- unescape = (char *) "?";
- unescape_len = 1;
- if (pe > p) {
- MEMCPY(buffer, p, char, pe - p);
- buffer += pe - p;
- }
- switch (*++pe) {
- case 'n':
- unescape = (char *) "\n";
- break;
- case 'r':
- unescape = (char *) "\r";
- break;
- case 't':
- unescape = (char *) "\t";
- break;
- case '"':
- unescape = (char *) "\"";
- break;
- case '\\':
- unescape = (char *) "\\";
- break;
- case 'b':
- unescape = (char *) "\b";
- break;
- case 'f':
- unescape = (char *) "\f";
- break;
- case 'u':
- if (pe > stringEnd - 4) {
- if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- ruby_xfree(bufferStart);
- }
- rb_enc_raise(
- rb_utf8_encoding(), eParserError,
- "incomplete unicode character escape sequence at '%s'", p
- );
- } else {
- UTF32 ch = unescape_unicode((unsigned char *) ++pe);
- pe += 3;
- if (UNI_SUR_HIGH_START == (ch & 0xFC00)) {
- pe++;
- if (pe > stringEnd - 6) {
- if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- ruby_xfree(bufferStart);
- }
- rb_enc_raise(
- rb_utf8_encoding(), eParserError,
- "incomplete surrogate pair at '%s'", p
- );
- }
- if (pe[0] == '\\' && pe[1] == 'u') {
- UTF32 sur = unescape_unicode((unsigned char *) pe + 2);
- ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
- | (sur & 0x3FF));
- pe += 5;
- } else {
- unescape = (char *) "?";
- break;
- }
- }
- unescape_len = convert_UTF32_to_UTF8(buf, ch);
- unescape = buf;
- }
- break;
- default:
- p = pe;
- continue;
- }
- MEMCPY(buffer, unescape, char, unescape_len);
- buffer += unescape_len;
- p = ++pe;
- } else {
- pe++;
- }
- }
-
- if (pe > p) {
- MEMCPY(buffer, p, char, pe - p);
- buffer += pe - p;
- }
+ }
-# ifdef HAVE_RB_ENC_INTERNED_STR
- if (intern) {
- result = rb_enc_interned_str(bufferStart, (long)(buffer - bufferStart), rb_utf8_encoding());
- } else {
- result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
- }
- if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- ruby_xfree(bufferStart);
- }
-# else
- result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
-
- if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- ruby_xfree(bufferStart);
- }
-
- if (intern) {
- # if STR_UMINUS_DEDUPE_FROZEN
- // Starting from MRI 2.8 it is preferable to freeze the string
- // before deduplication so that it can be interned directly
- // otherwise it would be duplicated first which is wasteful.
- result = rb_funcall(rb_str_freeze(result), i_uminus, 0);
- # elif STR_UMINUS_DEDUPE
- // MRI 2.5 and older do not deduplicate strings that are already
- // frozen.
- result = rb_funcall(result, i_uminus, 0);
- # else
- result = rb_str_freeze(result);
- # endif
- }
-# endif
+ while (pe < stringEnd) {
+ if (*pe == '\\') {
+ unescape = (char *) "?";
+ unescape_len = 1;
+ if (pe > p) {
+ MEMCPY(buffer, p, char, pe - p);
+ buffer += pe - p;
+ }
+ switch (*++pe) {
+ case 'n':
+ unescape = (char *) "\n";
+ break;
+ case 'r':
+ unescape = (char *) "\r";
+ break;
+ case 't':
+ unescape = (char *) "\t";
+ break;
+ case '"':
+ unescape = (char *) "\"";
+ break;
+ case '\\':
+ unescape = (char *) "\\";
+ break;
+ case 'b':
+ unescape = (char *) "\b";
+ break;
+ case 'f':
+ unescape = (char *) "\f";
+ break;
+ case 'u':
+ if (pe > stringEnd - 4) {
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ free(bufferStart);
+ }
+ rb_enc_raise(
+ EXC_ENCODING eParserError,
+ "incomplete unicode character escape sequence at '%s'", p
+ );
+ } else {
+ UTF32 ch = unescape_unicode((unsigned char *) ++pe);
+ pe += 3;
+ if (UNI_SUR_HIGH_START == (ch & 0xFC00)) {
+ pe++;
+ if (pe > stringEnd - 6) {
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ free(bufferStart);
+ }
+ rb_enc_raise(
+ EXC_ENCODING eParserError,
+ "incomplete surrogate pair at '%s'", p
+ );
+ }
+ if (pe[0] == '\\' && pe[1] == 'u') {
+ UTF32 sur = unescape_unicode((unsigned char *) pe + 2);
+ ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
+ | (sur & 0x3FF));
+ pe += 5;
+ } else {
+ unescape = (char *) "?";
+ break;
+ }
+ }
+ unescape_len = convert_UTF32_to_UTF8(buf, ch);
+ unescape = buf;
+ }
+ break;
+ default:
+ p = pe;
+ continue;
+ }
+ MEMCPY(buffer, unescape, char, unescape_len);
+ buffer += unescape_len;
+ p = ++pe;
+ } else {
+ pe++;
+ }
+ }
+
+ if (pe > p) {
+ MEMCPY(buffer, p, char, pe - p);
+ buffer += pe - p;
+ }
+
+ # ifdef HAVE_RB_ENC_INTERNED_STR
+ if (intern) {
+ result = rb_enc_interned_str(bufferStart, (long)(buffer - bufferStart), rb_utf8_encoding());
+ } else {
+ result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
+ }
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ free(bufferStart);
+ }
+ # else
+ result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
+
+ if (bufferSize > MAX_STACK_BUFFER_SIZE) {
+ free(bufferStart);
+ }
+
+ if (intern) {
+ # if STR_UMINUS_DEDUPE_FROZEN
+ // Starting from MRI 2.8 it is preferable to freeze the string
+ // before deduplication so that it can be interned directly
+ // otherwise it would be duplicated first which is wasteful.
+ result = rb_funcall(rb_str_freeze(result), i_uminus, 0);
+ # elif STR_UMINUS_DEDUPE
+ // MRI 2.5 and older do not deduplicate strings that are already
+ // frozen.
+ result = rb_funcall(result, i_uminus, 0);
+ # else
+ result = rb_str_freeze(result);
+ # endif
+ }
+ # endif
- if (symbolize) {
- result = rb_str_intern(result);
- }
+ if (symbolize) {
+ result = rb_str_intern(result);
+ }
- return result;
+ return result;
}
-#line 1592 "parser.c"
enum {JSON_string_start = 1};
enum {JSON_string_first_final = 8};
enum {JSON_string_error = 0};
enum {JSON_string_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_string_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_string_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_string_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_string_nfa_pop_trans)[] = {
+ 0, 0
+};
+
-#line 620 "parser.rl"
+#line 612 "parser.rl"
static int
match_i(VALUE regexp, VALUE klass, VALUE memo)
{
- if (regexp == Qundef) return ST_STOP;
- if (RTEST(rb_funcall(klass, i_json_creatable_p, 0)) &&
- RTEST(rb_funcall(regexp, i_match, 1, rb_ary_entry(memo, 0)))) {
- rb_ary_push(memo, klass);
- return ST_STOP;
- }
- return ST_CONTINUE;
+ if (regexp == Qundef) return ST_STOP;
+ if (RTEST(rb_funcall(klass, i_json_creatable_p, 0)) &&
+ RTEST(rb_funcall(regexp, i_match, 1, rb_ary_entry(memo, 0)))) {
+ rb_ary_push(memo, klass);
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
}
static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result)
{
- int cs = EVIL;
- VALUE match_string;
+ int cs = EVIL;
+ VALUE match_string;
-#line 1621 "parser.c"
{
- cs = JSON_string_start;
+ cs = (int)JSON_string_start;
}
-#line 640 "parser.rl"
- json->memo = p;
+ #line 632 "parser.rl"
+
+ json->memo = p;
-#line 1629 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-case 1:
- if ( (*p) == 34 )
- goto st2;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-st2:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 2:
+ goto st_case_2;
+ case 8:
+ goto st_case_8;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 5:
+ goto st_case_5;
+ case 6:
+ goto st_case_6;
+ case 7:
+ goto st_case_7;
+ }
+ goto st_out;
+ st_case_1:
+ if ( ( (*( p))) == 34 ) {
+ goto st2;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- switch( (*p) ) {
- case 34: goto tr2;
- case 92: goto st3;
- }
- if ( 0 <= (signed char)(*(p)) && (*(p)) <= 31 )
- goto st0;
- goto st2;
-tr2:
-#line 607 "parser.rl"
- {
- *result = json_string_unescape(json->memo + 1, p, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
- if (NIL_P(*result)) {
- p--;
- {p++; cs = 8; goto _out;}
- } else {
- {p = (( p + 1))-1;}
- }
- }
-#line 617 "parser.rl"
- { p--; {p++; cs = 8; goto _out;} }
- goto st8;
-st8:
- if ( ++p == pe )
+ st_case_2:
+ switch( ( (*( p))) ) {
+ case 34: {
+ goto ctr2;
+ }
+ case 92: {
+ goto st3;
+ }
+ }
+ if ( 0 <= (signed char)(*(p)) && (*(p)) <= 31 ) {
+ goto st0;
+ }
+ {
+ goto st2;
+ }
+ ctr2:
+ {
+ #line 599 "parser.rl"
+
+ *result = json_string_unescape(json->memo + 1, p, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
+ if (NIL_P(*result)) {
+ {p = p - 1; }
+ {p+= 1; cs = 8; goto _out;}
+ } else {
+ {p = (( p + 1))-1;}
+
+ }
+ }
+ {
+ #line 609 "parser.rl"
+ {p = p - 1; } {p+= 1; cs = 8; goto _out;} }
+
+ goto st8;
+ st8:
+ p+= 1;
+ if ( p == pe )
goto _test_eof8;
-case 8:
-#line 1671 "parser.c"
- goto st0;
-st3:
- if ( ++p == pe )
+ st_case_8:
+ {
+ goto st0;
+ }
+ st3:
+ p+= 1;
+ if ( p == pe )
goto _test_eof3;
-case 3:
- if ( (*p) == 117 )
- goto st4;
- if ( 0 <= (signed char)(*(p)) && (*(p)) <= 31 )
- goto st0;
- goto st2;
-st4:
- if ( ++p == pe )
+ st_case_3:
+ if ( ( (*( p))) == 117 ) {
+ goto st4;
+ }
+ if ( 0 <= (signed char)(*(p)) && (*(p)) <= 31 ) {
+ goto st0;
+ }
+ {
+ goto st2;
+ }
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
- if ( (*p) < 65 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
+ st_case_4:
+ if ( ( (*( p))) < 65 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st5;
+ }
+ } else if ( ( (*( p))) > 70 ) {
+ if ( 97 <= ( (*( p))) && ( (*( p))) <= 102 ) {
+ goto st5;
+ }
+ } else {
goto st5;
- } else if ( (*p) > 70 ) {
- if ( 97 <= (*p) && (*p) <= 102 )
- goto st5;
- } else
- goto st5;
- goto st0;
-st5:
- if ( ++p == pe )
+ }
+ {
+ goto st0;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- if ( (*p) < 65 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st6;
- } else if ( (*p) > 70 ) {
- if ( 97 <= (*p) && (*p) <= 102 )
+ st_case_5:
+ if ( ( (*( p))) < 65 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st6;
+ }
+ } else if ( ( (*( p))) > 70 ) {
+ if ( 97 <= ( (*( p))) && ( (*( p))) <= 102 ) {
+ goto st6;
+ }
+ } else {
goto st6;
- } else
- goto st6;
- goto st0;
-st6:
- if ( ++p == pe )
+ }
+ {
+ goto st0;
+ }
+ st6:
+ p+= 1;
+ if ( p == pe )
goto _test_eof6;
-case 6:
- if ( (*p) < 65 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto st7;
- } else if ( (*p) > 70 ) {
- if ( 97 <= (*p) && (*p) <= 102 )
+ st_case_6:
+ if ( ( (*( p))) < 65 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st7;
+ }
+ } else if ( ( (*( p))) > 70 ) {
+ if ( 97 <= ( (*( p))) && ( (*( p))) <= 102 ) {
+ goto st7;
+ }
+ } else {
goto st7;
- } else
- goto st7;
- goto st0;
-st7:
- if ( ++p == pe )
+ }
+ {
+ goto st0;
+ }
+ st7:
+ p+= 1;
+ if ( p == pe )
goto _test_eof7;
-case 7:
- if ( (*p) < 65 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
+ st_case_7:
+ if ( ( (*( p))) < 65 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto st2;
+ }
+ } else if ( ( (*( p))) > 70 ) {
+ if ( 97 <= ( (*( p))) && ( (*( p))) <= 102 ) {
+ goto st2;
+ }
+ } else {
goto st2;
- } else if ( (*p) > 70 ) {
- if ( 97 <= (*p) && (*p) <= 102 )
- goto st2;
- } else
- goto st2;
- goto st0;
- }
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
- _test_eof6: cs = 6; goto _test_eof;
- _test_eof7: cs = 7; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ }
+ {
+ goto st0;
+ }
+ st_out:
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 634 "parser.rl"
+
+
+ if (json->create_additions && RTEST(match_string = json->match_string)) {
+ VALUE klass;
+ VALUE memo = rb_ary_new2(2);
+ rb_ary_push(memo, *result);
+ rb_hash_foreach(match_string, match_i, memo);
+ klass = rb_ary_entry(memo, 1);
+ if (RTEST(klass)) {
+ *result = rb_funcall(klass, i_json_create, 1, *result);
+ }
+ }
+
+ if (cs >= JSON_string_first_final) {
+ return p + 1;
+ } else {
+ return NULL;
}
-
-#line 642 "parser.rl"
-
- if (json->create_additions && RTEST(match_string = json->match_string)) {
- VALUE klass;
- VALUE memo = rb_ary_new2(2);
- rb_ary_push(memo, *result);
- rb_hash_foreach(match_string, match_i, memo);
- klass = rb_ary_entry(memo, 1);
- if (RTEST(klass)) {
- *result = rb_funcall(klass, i_json_create, 1, *result);
- }
- }
-
- if (cs >= JSON_string_first_final) {
- return p + 1;
- } else {
- return NULL;
- }
}
/*
- * Document-class: JSON::Ext::Parser
- *
- * This is the JSON parser implemented as a C extension. It can be configured
- * to be used by setting
- *
- * JSON.parser = JSON::Ext::Parser
- *
- * with the method parser= in JSON.
- *
- */
+* Document-class: JSON::Ext::Parser
+*
+* This is the JSON parser implemented as a C extension. It can be configured
+* to be used by setting
+*
+* JSON.parser = JSON::Ext::Parser
+*
+* with the method parser= in JSON.
+*
+*/
static VALUE convert_encoding(VALUE source)
{
- rb_encoding *enc = rb_enc_get(source);
- if (enc == rb_ascii8bit_encoding()) {
- if (OBJ_FROZEN(source)) {
- source = rb_str_dup(source);
- }
- FORCE_UTF8(source);
- } else {
- source = rb_str_conv_enc(source, rb_enc_get(source), rb_utf8_encoding());
- }
- return source;
+ #ifdef HAVE_RUBY_ENCODING_H
+ rb_encoding *enc = rb_enc_get(source);
+ if (enc == rb_ascii8bit_encoding()) {
+ if (OBJ_FROZEN(source)) {
+ source = rb_str_dup(source);
+ }
+ FORCE_UTF8(source);
+ } else {
+ source = rb_str_conv_enc(source, rb_enc_get(source), rb_utf8_encoding());
+ }
+ #endif
+ return source;
}
/*
- * call-seq: new(source, opts => {})
- *
- * Creates a new JSON::Ext::Parser instance for the string _source_.
- *
- * It will be configured by the _opts_ hash. _opts_ can have the following
- * keys:
- *
- * _opts_ can have the following keys:
- * * *max_nesting*: The maximum depth of nesting allowed in the parsed data
- * structures. Disable depth checking with :max_nesting => false|nil|0, it
- * defaults to 100.
- * * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
- * defiance of RFC 4627 to be parsed by the Parser. This option defaults to
- * false.
- * * *symbolize_names*: If set to true, returns symbols for the names
- * (keys) in a JSON object. Otherwise strings are returned, which is
- * also the default. It's not possible to use this option in
- * conjunction with the *create_additions* option.
- * * *create_additions*: If set to false, the Parser doesn't create
- * additions even if a matching class and create_id was found. This option
- * defaults to false.
- * * *object_class*: Defaults to Hash
- * * *array_class*: Defaults to Array
- */
+* call-seq: new(source, opts => {})
+*
+* Creates a new JSON::Ext::Parser instance for the string _source_.
+*
+* Creates a new JSON::Ext::Parser instance for the string _source_.
+*
+* It will be configured by the _opts_ hash. _opts_ can have the following
+* keys:
+*
+* _opts_ can have the following keys:
+* * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+* structures. Disable depth checking with :max_nesting => false|nil|0, it
+* defaults to 100.
+* * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
+* defiance of RFC 4627 to be parsed by the Parser. This option defaults to
+* false.
+* * *symbolize_names*: If set to true, returns symbols for the names
+* (keys) in a JSON object. Otherwise strings are returned, which is
+* also the default. It's not possible to use this option in
+* conjunction with the *create_additions* option.
+* * *create_additions*: If set to false, the Parser doesn't create
+* additions even if a matching class and create_id was found. This option
+* defaults to false.
+* * *object_class*: Defaults to Hash
+* * *array_class*: Defaults to Array
+*/
static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
{
- VALUE source, opts;
- GET_PARSER_INIT;
-
- if (json->Vsource) {
- rb_raise(rb_eTypeError, "already initialized instance");
- }
- rb_scan_args(argc, argv, "1:", &source, &opts);
- if (!NIL_P(opts)) {
- VALUE tmp = ID2SYM(i_max_nesting);
- if (option_given_p(opts, tmp)) {
- VALUE max_nesting = rb_hash_aref(opts, tmp);
- if (RTEST(max_nesting)) {
- Check_Type(max_nesting, T_FIXNUM);
- json->max_nesting = FIX2INT(max_nesting);
- } else {
- json->max_nesting = 0;
- }
- } else {
- json->max_nesting = 100;
- }
- tmp = ID2SYM(i_allow_nan);
- if (option_given_p(opts, tmp)) {
- json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
- } else {
- json->allow_nan = 0;
- }
- tmp = ID2SYM(i_symbolize_names);
- if (option_given_p(opts, tmp)) {
- json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
- } else {
- json->symbolize_names = 0;
- }
- tmp = ID2SYM(i_freeze);
- if (option_given_p(opts, tmp)) {
- json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ VALUE source, opts;
+ GET_PARSER_INIT;
+
+ if (json->Vsource) {
+ rb_raise(rb_eTypeError, "already initialized instance");
+ }
+ #ifdef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
+ rb_scan_args(argc, argv, "1:", &source, &opts);
+ #else
+ rb_scan_args(argc, argv, "11", &source, &opts);
+ #endif
+ if (!NIL_P(opts)) {
+ #ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
+ opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
+ if (NIL_P(opts)) {
+ rb_raise(rb_eArgError, "opts needs to be like a hash");
+ } else {
+ #endif
+ VALUE tmp = ID2SYM(i_max_nesting);
+ if (option_given_p(opts, tmp)) {
+ VALUE max_nesting = rb_hash_aref(opts, tmp);
+ if (RTEST(max_nesting)) {
+ Check_Type(max_nesting, T_FIXNUM);
+ json->max_nesting = FIX2INT(max_nesting);
+ } else {
+ json->max_nesting = 0;
+ }
+ } else {
+ json->max_nesting = 100;
+ }
+ tmp = ID2SYM(i_allow_nan);
+ if (option_given_p(opts, tmp)) {
+ json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ } else {
+ json->allow_nan = 0;
+ }
+ tmp = ID2SYM(i_symbolize_names);
+ if (option_given_p(opts, tmp)) {
+ json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ } else {
+ json->symbolize_names = 0;
+ }
+ tmp = ID2SYM(i_freeze);
+ if (option_given_p(opts, tmp)) {
+ json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ } else {
+ json->freeze = 0;
+ }
+ tmp = ID2SYM(i_create_additions);
+ if (option_given_p(opts, tmp)) {
+ json->create_additions = RTEST(rb_hash_aref(opts, tmp));
+ } else {
+ json->create_additions = 0;
+ }
+ if (json->symbolize_names && json->create_additions) {
+ rb_raise(rb_eArgError,
+ "options :symbolize_names and :create_additions cannot be "
+ " used in conjunction");
+ }
+ tmp = ID2SYM(i_create_id);
+ if (option_given_p(opts, tmp)) {
+ json->create_id = rb_hash_aref(opts, tmp);
+ } else {
+ json->create_id = rb_funcall(mJSON, i_create_id, 0);
+ }
+ tmp = ID2SYM(i_object_class);
+ if (option_given_p(opts, tmp)) {
+ json->object_class = rb_hash_aref(opts, tmp);
+ } else {
+ json->object_class = Qnil;
+ }
+ tmp = ID2SYM(i_array_class);
+ if (option_given_p(opts, tmp)) {
+ json->array_class = rb_hash_aref(opts, tmp);
+ } else {
+ json->array_class = Qnil;
+ }
+ tmp = ID2SYM(i_decimal_class);
+ if (option_given_p(opts, tmp)) {
+ json->decimal_class = rb_hash_aref(opts, tmp);
+ } else {
+ json->decimal_class = Qnil;
+ }
+ tmp = ID2SYM(i_match_string);
+ if (option_given_p(opts, tmp)) {
+ VALUE match_string = rb_hash_aref(opts, tmp);
+ json->match_string = RTEST(match_string) ? match_string : Qnil;
+ } else {
+ json->match_string = Qnil;
+ }
+ #ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
+ }
+ #endif
} else {
- json->freeze = 0;
- }
- tmp = ID2SYM(i_create_additions);
- if (option_given_p(opts, tmp)) {
- json->create_additions = RTEST(rb_hash_aref(opts, tmp));
- } else {
- json->create_additions = 0;
- }
- if (json->symbolize_names && json->create_additions) {
- rb_raise(rb_eArgError,
- "options :symbolize_names and :create_additions cannot be "
- " used in conjunction");
- }
- tmp = ID2SYM(i_create_id);
- if (option_given_p(opts, tmp)) {
- json->create_id = rb_hash_aref(opts, tmp);
- } else {
- json->create_id = rb_funcall(mJSON, i_create_id, 0);
- }
- tmp = ID2SYM(i_object_class);
- if (option_given_p(opts, tmp)) {
- json->object_class = rb_hash_aref(opts, tmp);
- } else {
- json->object_class = Qnil;
- }
- tmp = ID2SYM(i_array_class);
- if (option_given_p(opts, tmp)) {
- json->array_class = rb_hash_aref(opts, tmp);
- } else {
- json->array_class = Qnil;
- }
- tmp = ID2SYM(i_decimal_class);
- if (option_given_p(opts, tmp)) {
- json->decimal_class = rb_hash_aref(opts, tmp);
- } else {
- json->decimal_class = Qnil;
- }
- tmp = ID2SYM(i_match_string);
- if (option_given_p(opts, tmp)) {
- VALUE match_string = rb_hash_aref(opts, tmp);
- json->match_string = RTEST(match_string) ? match_string : Qnil;
- } else {
- json->match_string = Qnil;
- }
- } else {
- json->max_nesting = 100;
- json->allow_nan = 0;
- json->create_additions = 0;
- json->create_id = Qnil;
- json->object_class = Qnil;
- json->array_class = Qnil;
- json->decimal_class = Qnil;
- }
- source = convert_encoding(StringValue(source));
- StringValue(source);
- json->len = RSTRING_LEN(source);
- json->source = RSTRING_PTR(source);;
- json->Vsource = source;
- return self;
+ json->max_nesting = 100;
+ json->allow_nan = 0;
+ json->create_additions = 0;
+ json->create_id = rb_funcall(mJSON, i_create_id, 0);
+ json->object_class = Qnil;
+ json->array_class = Qnil;
+ json->decimal_class = Qnil;
+ }
+ source = convert_encoding(StringValue(source));
+ StringValue(source);
+ json->len = RSTRING_LEN(source);
+ json->source = RSTRING_PTR(source);;
+ json->Vsource = source;
+ return self;
}
-#line 1920 "parser.c"
enum {JSON_start = 1};
enum {JSON_first_final = 10};
enum {JSON_error = 0};
enum {JSON_en_main = 1};
+static const char MAYBE_UNUSED(_JSON_nfa_targs)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_nfa_offsets)[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_nfa_push_actions)[] = {
+ 0, 0
+};
+
+static const char MAYBE_UNUSED(_JSON_nfa_pop_trans)[] = {
+ 0, 0
+};
+
-#line 828 "parser.rl"
+#line 835 "parser.rl"
/*
- * call-seq: parse()
- *
- * Parses the current JSON text _source_ and returns the complete data
- * structure as a result.
- * It raises JSON::ParserError if fail to parse.
- */
+* call-seq: parse()
+*
+* Parses the current JSON text _source_ and returns the complete data
+* structure as a result.
+* It raises JSON::ParseError if fail to parse.
+*/
static VALUE cParser_parse(VALUE self)
{
- char *p, *pe;
- int cs = EVIL;
- VALUE result = Qnil;
- GET_PARSER;
+ char *p, *pe;
+ int cs = EVIL;
+ VALUE result = Qnil;
+ GET_PARSER;
-#line 1946 "parser.c"
{
- cs = JSON_start;
+ cs = (int)JSON_start;
}
-#line 845 "parser.rl"
- p = json->source;
- pe = p + json->len;
+ #line 851 "parser.rl"
+
+ p = json->source;
+ pe = p + json->len;
-#line 1955 "parser.c"
{
- if ( p == pe )
+ if ( p == pe )
goto _test_eof;
- switch ( cs )
- {
-st1:
- if ( ++p == pe )
+ switch ( cs )
+ {
+ case 1:
+ goto st_case_1;
+ case 0:
+ goto st_case_0;
+ case 10:
+ goto st_case_10;
+ case 2:
+ goto st_case_2;
+ case 3:
+ goto st_case_3;
+ case 4:
+ goto st_case_4;
+ case 5:
+ goto st_case_5;
+ case 6:
+ goto st_case_6;
+ case 7:
+ goto st_case_7;
+ case 8:
+ goto st_case_8;
+ case 9:
+ goto st_case_9;
+ }
+ goto st_out;
+ st1:
+ p+= 1;
+ if ( p == pe )
goto _test_eof1;
-case 1:
- switch( (*p) ) {
- case 13: goto st1;
- case 32: goto st1;
- case 34: goto tr2;
- case 45: goto tr2;
- case 47: goto st6;
- case 73: goto tr2;
- case 78: goto tr2;
- case 91: goto tr2;
- case 102: goto tr2;
- case 110: goto tr2;
- case 116: goto tr2;
- case 123: goto tr2;
- }
- if ( (*p) > 10 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto tr2;
- } else if ( (*p) >= 9 )
- goto st1;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-tr2:
-#line 820 "parser.rl"
- {
- char *np = JSON_parse_value(json, p, pe, &result, 0);
- if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;}
- }
- goto st10;
-st10:
- if ( ++p == pe )
- goto _test_eof10;
-case 10:
-#line 1999 "parser.c"
- switch( (*p) ) {
- case 13: goto st10;
- case 32: goto st10;
- case 47: goto st2;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
+ st_case_1:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st1;
+ }
+ case 32: {
+ goto st1;
+ }
+ case 34: {
+ goto ctr2;
+ }
+ case 45: {
+ goto ctr2;
+ }
+ case 47: {
+ goto st6;
+ }
+ case 73: {
+ goto ctr2;
+ }
+ case 78: {
+ goto ctr2;
+ }
+ case 91: {
+ goto ctr2;
+ }
+ case 102: {
+ goto ctr2;
+ }
+ case 110: {
+ goto ctr2;
+ }
+ case 116: {
+ goto ctr2;
+ }
+ case 123: {
+ goto ctr2;
+ }
+ }
+ if ( ( (*( p))) > 10 ) {
+ if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) {
+ goto ctr2;
+ }
+ } else if ( ( (*( p))) >= 9 ) {
+ goto st1;
+ }
+ {
+ goto st0;
+ }
+ st_case_0:
+ st0:
+ cs = 0;
+ goto _out;
+ ctr2:
+ {
+ #line 827 "parser.rl"
+
+ char *np = JSON_parse_value(json, p, pe, &result, 0);
+ if (np == NULL) { {p = p - 1; } {p+= 1; cs = 10; goto _out;} } else {p = (( np))-1;}
+
+ }
+
goto st10;
- goto st0;
-st2:
- if ( ++p == pe )
+ st10:
+ p+= 1;
+ if ( p == pe )
+ goto _test_eof10;
+ st_case_10:
+ switch( ( (*( p))) ) {
+ case 13: {
+ goto st10;
+ }
+ case 32: {
+ goto st10;
+ }
+ case 47: {
+ goto st2;
+ }
+ }
+ if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) {
+ goto st10;
+ }
+ {
+ goto st0;
+ }
+ st2:
+ p+= 1;
+ if ( p == pe )
goto _test_eof2;
-case 2:
- switch( (*p) ) {
- case 42: goto st3;
- case 47: goto st5;
- }
- goto st0;
-st3:
- if ( ++p == pe )
+ st_case_2:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st3;
+ }
+ case 47: {
+ goto st5;
+ }
+ }
+ {
+ goto st0;
+ }
+ st3:
+ p+= 1;
+ if ( p == pe )
goto _test_eof3;
-case 3:
- if ( (*p) == 42 )
- goto st4;
- goto st3;
-st4:
- if ( ++p == pe )
+ st_case_3:
+ if ( ( (*( p))) == 42 ) {
+ goto st4;
+ }
+ {
+ goto st3;
+ }
+ st4:
+ p+= 1;
+ if ( p == pe )
goto _test_eof4;
-case 4:
- switch( (*p) ) {
- case 42: goto st4;
- case 47: goto st10;
- }
- goto st3;
-st5:
- if ( ++p == pe )
+ st_case_4:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st4;
+ }
+ case 47: {
+ goto st10;
+ }
+ }
+ {
+ goto st3;
+ }
+ st5:
+ p+= 1;
+ if ( p == pe )
goto _test_eof5;
-case 5:
- if ( (*p) == 10 )
- goto st10;
- goto st5;
-st6:
- if ( ++p == pe )
+ st_case_5:
+ if ( ( (*( p))) == 10 ) {
+ goto st10;
+ }
+ {
+ goto st5;
+ }
+ st6:
+ p+= 1;
+ if ( p == pe )
goto _test_eof6;
-case 6:
- switch( (*p) ) {
- case 42: goto st7;
- case 47: goto st9;
- }
- goto st0;
-st7:
- if ( ++p == pe )
+ st_case_6:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st7;
+ }
+ case 47: {
+ goto st9;
+ }
+ }
+ {
+ goto st0;
+ }
+ st7:
+ p+= 1;
+ if ( p == pe )
goto _test_eof7;
-case 7:
- if ( (*p) == 42 )
- goto st8;
- goto st7;
-st8:
- if ( ++p == pe )
+ st_case_7:
+ if ( ( (*( p))) == 42 ) {
+ goto st8;
+ }
+ {
+ goto st7;
+ }
+ st8:
+ p+= 1;
+ if ( p == pe )
goto _test_eof8;
-case 8:
- switch( (*p) ) {
- case 42: goto st8;
- case 47: goto st1;
- }
- goto st7;
-st9:
- if ( ++p == pe )
+ st_case_8:
+ switch( ( (*( p))) ) {
+ case 42: {
+ goto st8;
+ }
+ case 47: {
+ goto st1;
+ }
+ }
+ {
+ goto st7;
+ }
+ st9:
+ p+= 1;
+ if ( p == pe )
goto _test_eof9;
-case 9:
- if ( (*p) == 10 )
- goto st1;
- goto st9;
- }
- _test_eof1: cs = 1; goto _test_eof;
- _test_eof10: cs = 10; goto _test_eof;
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
- _test_eof6: cs = 6; goto _test_eof;
- _test_eof7: cs = 7; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof9: cs = 9; goto _test_eof;
-
- _test_eof: {}
- _out: {}
+ st_case_9:
+ if ( ( (*( p))) == 10 ) {
+ goto st1;
+ }
+ {
+ goto st9;
+ }
+ st_out:
+ _test_eof1: cs = 1; goto _test_eof;
+ _test_eof10: cs = 10; goto _test_eof;
+ _test_eof2: cs = 2; goto _test_eof;
+ _test_eof3: cs = 3; goto _test_eof;
+ _test_eof4: cs = 4; goto _test_eof;
+ _test_eof5: cs = 5; goto _test_eof;
+ _test_eof6: cs = 6; goto _test_eof;
+ _test_eof7: cs = 7; goto _test_eof;
+ _test_eof8: cs = 8; goto _test_eof;
+ _test_eof9: cs = 9; goto _test_eof;
+
+ _test_eof: {}
+ _out: {}
+ }
+
+ #line 854 "parser.rl"
+
+
+ if (cs >= JSON_first_final && p == pe) {
+ return result;
+ } else {
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
+ return Qnil;
}
-
-#line 848 "parser.rl"
-
- if (cs >= JSON_first_final && p == pe) {
- return result;
- } else {
- rb_enc_raise(rb_utf8_encoding(), eParserError, "unexpected token at '%s'", p);
- return Qnil;
- }
}
static void JSON_mark(void *ptr)
{
- JSON_Parser *json = ptr;
- rb_gc_mark(json->Vsource);
- rb_gc_mark(json->create_id);
- rb_gc_mark(json->object_class);
- rb_gc_mark(json->array_class);
- rb_gc_mark(json->decimal_class);
- rb_gc_mark(json->match_string);
+ JSON_Parser *json = ptr;
+ rb_gc_mark_maybe(json->Vsource);
+ rb_gc_mark_maybe(json->create_id);
+ rb_gc_mark_maybe(json->object_class);
+ rb_gc_mark_maybe(json->array_class);
+ rb_gc_mark_maybe(json->decimal_class);
+ rb_gc_mark_maybe(json->match_string);
}
static void JSON_free(void *ptr)
{
- JSON_Parser *json = ptr;
- fbuffer_free(json->fbuffer);
- ruby_xfree(json);
+ JSON_Parser *json = ptr;
+ fbuffer_free(json->fbuffer);
+ ruby_xfree(json);
}
static size_t JSON_memsize(const void *ptr)
{
- const JSON_Parser *json = ptr;
- return sizeof(*json) + FBUFFER_CAPA(json->fbuffer);
+ const JSON_Parser *json = ptr;
+ return sizeof(*json) + FBUFFER_CAPA(json->fbuffer);
}
+#ifdef NEW_TYPEDDATA_WRAPPER
static const rb_data_type_t JSON_Parser_type = {
- "JSON/Parser",
- {JSON_mark, JSON_free, JSON_memsize,},
- 0, 0,
- RUBY_TYPED_FREE_IMMEDIATELY,
+ "JSON/Parser",
+ {JSON_mark, JSON_free, JSON_memsize,},
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
+ 0, 0,
+ RUBY_TYPED_FREE_IMMEDIATELY,
+ #endif
};
+#endif
static VALUE cJSON_parser_s_allocate(VALUE klass)
{
- JSON_Parser *json;
- VALUE obj = TypedData_Make_Struct(klass, JSON_Parser, &JSON_Parser_type, json);
- json->fbuffer = fbuffer_alloc(0);
- return obj;
+ JSON_Parser *json;
+ VALUE obj = TypedData_Make_Struct(klass, JSON_Parser, &JSON_Parser_type, json);
+ json->fbuffer = fbuffer_alloc(0);
+ return obj;
}
/*
- * call-seq: source()
- *
- * Returns a copy of the current _source_ string, that was used to construct
- * this Parser.
- */
+* call-seq: source()
+*
+* Returns a copy of the current _source_ string, that was used to construct
+* this Parser.
+*/
static VALUE cParser_source(VALUE self)
{
- GET_PARSER;
- return rb_str_dup(json->Vsource);
+ GET_PARSER;
+ return rb_str_dup(json->Vsource);
}
void Init_parser(void)
{
-#ifdef HAVE_RB_EXT_RACTOR_SAFE
- rb_ext_ractor_safe(true);
-#endif
-
-#undef rb_intern
- rb_require("json/common");
- mJSON = rb_define_module("JSON");
- mExt = rb_define_module_under(mJSON, "Ext");
- cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
- eParserError = rb_path2class("JSON::ParserError");
- eNestingError = rb_path2class("JSON::NestingError");
- rb_gc_register_mark_object(eParserError);
- rb_gc_register_mark_object(eNestingError);
- rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
- rb_define_method(cParser, "initialize", cParser_initialize, -1);
- rb_define_method(cParser, "parse", cParser_parse, 0);
- rb_define_method(cParser, "source", cParser_source, 0);
-
- CNaN = rb_const_get(mJSON, rb_intern("NaN"));
- rb_gc_register_mark_object(CNaN);
-
- CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
- rb_gc_register_mark_object(CInfinity);
-
- CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
- rb_gc_register_mark_object(CMinusInfinity);
-
- i_json_creatable_p = rb_intern("json_creatable?");
- i_json_create = rb_intern("json_create");
- i_create_id = rb_intern("create_id");
- i_create_additions = rb_intern("create_additions");
- i_chr = rb_intern("chr");
- i_max_nesting = rb_intern("max_nesting");
- i_allow_nan = rb_intern("allow_nan");
- i_symbolize_names = rb_intern("symbolize_names");
- i_object_class = rb_intern("object_class");
- i_array_class = rb_intern("array_class");
- i_decimal_class = rb_intern("decimal_class");
- i_match = rb_intern("match");
- i_match_string = rb_intern("match_string");
- i_key_p = rb_intern("key?");
- i_deep_const_get = rb_intern("deep_const_get");
- i_aset = rb_intern("[]=");
- i_aref = rb_intern("[]");
- i_leftshift = rb_intern("<<");
- i_new = rb_intern("new");
- i_try_convert = rb_intern("try_convert");
- i_freeze = rb_intern("freeze");
- i_uminus = rb_intern("-@");
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
+ rb_ext_ractor_safe(true);
+ #endif
+
+ #undef rb_intern
+ rb_require("json/common");
+ mJSON = rb_define_module("JSON");
+ mExt = rb_define_module_under(mJSON, "Ext");
+ cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
+ eParserError = rb_path2class("JSON::ParserError");
+ eNestingError = rb_path2class("JSON::NestingError");
+ rb_gc_register_mark_object(eParserError);
+ rb_gc_register_mark_object(eNestingError);
+ rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
+ rb_define_method(cParser, "initialize", cParser_initialize, -1);
+ rb_define_method(cParser, "parse", cParser_parse, 0);
+ rb_define_method(cParser, "source", cParser_source, 0);
+
+ CNaN = rb_const_get(mJSON, rb_intern("NaN"));
+ rb_gc_register_mark_object(CNaN);
+
+ CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
+ rb_gc_register_mark_object(CInfinity);
+
+ CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
+ rb_gc_register_mark_object(CMinusInfinity);
+
+ i_json_creatable_p = rb_intern("json_creatable?");
+ i_json_create = rb_intern("json_create");
+ i_create_id = rb_intern("create_id");
+ i_create_additions = rb_intern("create_additions");
+ i_chr = rb_intern("chr");
+ i_max_nesting = rb_intern("max_nesting");
+ i_allow_nan = rb_intern("allow_nan");
+ i_symbolize_names = rb_intern("symbolize_names");
+ i_object_class = rb_intern("object_class");
+ i_array_class = rb_intern("array_class");
+ i_decimal_class = rb_intern("decimal_class");
+ i_match = rb_intern("match");
+ i_match_string = rb_intern("match_string");
+ i_key_p = rb_intern("key?");
+ i_deep_const_get = rb_intern("deep_const_get");
+ i_aset = rb_intern("[]=");
+ i_aref = rb_intern("[]");
+ i_leftshift = rb_intern("<<");
+ i_new = rb_intern("new");
+ i_try_convert = rb_intern("try_convert");
+ i_freeze = rb_intern("freeze");
+ i_uminus = rb_intern("-@");
}
/*
- * Local variables:
- * mode: c
- * c-file-style: ruby
- * indent-tabs-mode: nil
- * End:
- */
+* Local variables:
+* mode: c
+* c-file-style: ruby
+* indent-tabs-mode: nil
+* End:
+*/
diff --git a/ext/json/parser/parser.h b/ext/json/parser/parser.h
index 651d40c074..92ed3fdc5d 100644
--- a/ext/json/parser/parser.h
+++ b/ext/json/parser/parser.h
@@ -85,7 +85,12 @@ static inline void *ruby_zalloc(size_t n)
return p;
}
#endif
-
+#ifdef TypedData_Make_Struct
static const rb_data_type_t JSON_Parser_type;
+#define NEW_TYPEDDATA_WRAPPER 1
+#else
+#define TypedData_Make_Struct(klass, type, ignore, json) Data_Make_Struct(klass, type, NULL, JSON_free, json)
+#define TypedData_Get_Struct(self, JSON_Parser, ignore, json) Data_Get_Struct(self, JSON_Parser, json)
+#endif
#endif
diff --git a/ext/json/parser/parser.rl b/ext/json/parser/parser.rl
index 873c1b3007..2dbdc7ef24 100644
--- a/ext/json/parser/parser.rl
+++ b/ext/json/parser/parser.rl
@@ -1,6 +1,28 @@
#include "../fbuffer/fbuffer.h"
#include "parser.h"
+#if defined HAVE_RUBY_ENCODING_H
+# define EXC_ENCODING rb_utf8_encoding(),
+# ifndef HAVE_RB_ENC_RAISE
+static void
+enc_raise(rb_encoding *enc, VALUE exc, const char *fmt, ...)
+{
+ va_list args;
+ VALUE mesg;
+
+ va_start(args, fmt);
+ mesg = rb_enc_vsprintf(enc, fmt, args);
+ va_end(args);
+
+ rb_exc_raise(rb_exc_new3(exc, mesg));
+}
+# define rb_enc_raise enc_raise
+# endif
+#else
+# define EXC_ENCODING /* nothing */
+# define rb_enc_raise rb_raise
+#endif
+
/* unicode */
static const signed char digit_values[256] = {
@@ -200,14 +222,14 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
if (json->allow_nan) {
*result = CNaN;
} else {
- rb_enc_raise(rb_utf8_encoding(), eParserError, "unexpected token at '%s'", p - 2);
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 2);
}
}
action parse_infinity {
if (json->allow_nan) {
*result = CInfinity;
} else {
- rb_enc_raise(rb_utf8_encoding(), eParserError, "unexpected token at '%s'", p - 7);
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 8);
}
}
action parse_string {
@@ -223,7 +245,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
fexec p + 10;
fhold; fbreak;
} else {
- rb_enc_raise(rb_utf8_encoding(), eParserError, "unexpected token at '%s'", p);
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
}
}
np = JSON_parse_float(json, fpc, pe, result);
@@ -425,7 +447,7 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul
if(cs >= JSON_array_first_final) {
return p + 1;
} else {
- rb_enc_raise(rb_utf8_encoding(), eParserError, "unexpected token at '%s'", p);
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
return NULL;
}
}
@@ -486,10 +508,10 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
case 'u':
if (pe > stringEnd - 4) {
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- ruby_xfree(bufferStart);
+ free(bufferStart);
}
rb_enc_raise(
- rb_utf8_encoding(), eParserError,
+ EXC_ENCODING eParserError,
"incomplete unicode character escape sequence at '%s'", p
);
} else {
@@ -499,10 +521,10 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
pe++;
if (pe > stringEnd - 6) {
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- ruby_xfree(bufferStart);
+ free(bufferStart);
}
rb_enc_raise(
- rb_utf8_encoding(), eParserError,
+ EXC_ENCODING eParserError,
"incomplete surrogate pair at '%s'", p
);
}
@@ -544,13 +566,13 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
}
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- ruby_xfree(bufferStart);
+ free(bufferStart);
}
# else
result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
- ruby_xfree(bufferStart);
+ free(bufferStart);
}
if (intern) {
@@ -669,6 +691,8 @@ static VALUE convert_encoding(VALUE source)
*
* Creates a new JSON::Ext::Parser instance for the string _source_.
*
+ * Creates a new JSON::Ext::Parser instance for the string _source_.
+ *
* It will be configured by the _opts_ hash. _opts_ can have the following
* keys:
*
@@ -697,85 +721,98 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
if (json->Vsource) {
rb_raise(rb_eTypeError, "already initialized instance");
}
+#ifdef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
rb_scan_args(argc, argv, "1:", &source, &opts);
+#else
+ rb_scan_args(argc, argv, "11", &source, &opts);
+#endif
if (!NIL_P(opts)) {
- VALUE tmp = ID2SYM(i_max_nesting);
- if (option_given_p(opts, tmp)) {
- VALUE max_nesting = rb_hash_aref(opts, tmp);
- if (RTEST(max_nesting)) {
- Check_Type(max_nesting, T_FIXNUM);
- json->max_nesting = FIX2INT(max_nesting);
- } else {
- json->max_nesting = 0;
- }
- } else {
- json->max_nesting = 100;
- }
- tmp = ID2SYM(i_allow_nan);
- if (option_given_p(opts, tmp)) {
- json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
- } else {
- json->allow_nan = 0;
- }
- tmp = ID2SYM(i_symbolize_names);
- if (option_given_p(opts, tmp)) {
- json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
- } else {
- json->symbolize_names = 0;
- }
- tmp = ID2SYM(i_freeze);
- if (option_given_p(opts, tmp)) {
- json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
- } else {
- json->freeze = 0;
- }
- tmp = ID2SYM(i_create_additions);
- if (option_given_p(opts, tmp)) {
- json->create_additions = RTEST(rb_hash_aref(opts, tmp));
- } else {
- json->create_additions = 0;
- }
- if (json->symbolize_names && json->create_additions) {
- rb_raise(rb_eArgError,
- "options :symbolize_names and :create_additions cannot be "
- " used in conjunction");
- }
- tmp = ID2SYM(i_create_id);
- if (option_given_p(opts, tmp)) {
- json->create_id = rb_hash_aref(opts, tmp);
- } else {
- json->create_id = rb_funcall(mJSON, i_create_id, 0);
- }
- tmp = ID2SYM(i_object_class);
- if (option_given_p(opts, tmp)) {
- json->object_class = rb_hash_aref(opts, tmp);
- } else {
- json->object_class = Qnil;
- }
- tmp = ID2SYM(i_array_class);
- if (option_given_p(opts, tmp)) {
- json->array_class = rb_hash_aref(opts, tmp);
- } else {
- json->array_class = Qnil;
- }
- tmp = ID2SYM(i_decimal_class);
- if (option_given_p(opts, tmp)) {
- json->decimal_class = rb_hash_aref(opts, tmp);
- } else {
- json->decimal_class = Qnil;
- }
- tmp = ID2SYM(i_match_string);
- if (option_given_p(opts, tmp)) {
- VALUE match_string = rb_hash_aref(opts, tmp);
- json->match_string = RTEST(match_string) ? match_string : Qnil;
- } else {
- json->match_string = Qnil;
- }
+#ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
+ opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
+ if (NIL_P(opts)) {
+ rb_raise(rb_eArgError, "opts needs to be like a hash");
+ } else {
+#endif
+ VALUE tmp = ID2SYM(i_max_nesting);
+ if (option_given_p(opts, tmp)) {
+ VALUE max_nesting = rb_hash_aref(opts, tmp);
+ if (RTEST(max_nesting)) {
+ Check_Type(max_nesting, T_FIXNUM);
+ json->max_nesting = FIX2INT(max_nesting);
+ } else {
+ json->max_nesting = 0;
+ }
+ } else {
+ json->max_nesting = 100;
+ }
+ tmp = ID2SYM(i_allow_nan);
+ if (option_given_p(opts, tmp)) {
+ json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ } else {
+ json->allow_nan = 0;
+ }
+ tmp = ID2SYM(i_symbolize_names);
+ if (option_given_p(opts, tmp)) {
+ json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ } else {
+ json->symbolize_names = 0;
+ }
+ tmp = ID2SYM(i_freeze);
+ if (option_given_p(opts, tmp)) {
+ json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
+ } else {
+ json->freeze = 0;
+ }
+ tmp = ID2SYM(i_create_additions);
+ if (option_given_p(opts, tmp)) {
+ json->create_additions = RTEST(rb_hash_aref(opts, tmp));
+ } else {
+ json->create_additions = 0;
+ }
+ if (json->symbolize_names && json->create_additions) {
+ rb_raise(rb_eArgError,
+ "options :symbolize_names and :create_additions cannot be "
+ " used in conjunction");
+ }
+ tmp = ID2SYM(i_create_id);
+ if (option_given_p(opts, tmp)) {
+ json->create_id = rb_hash_aref(opts, tmp);
+ } else {
+ json->create_id = rb_funcall(mJSON, i_create_id, 0);
+ }
+ tmp = ID2SYM(i_object_class);
+ if (option_given_p(opts, tmp)) {
+ json->object_class = rb_hash_aref(opts, tmp);
+ } else {
+ json->object_class = Qnil;
+ }
+ tmp = ID2SYM(i_array_class);
+ if (option_given_p(opts, tmp)) {
+ json->array_class = rb_hash_aref(opts, tmp);
+ } else {
+ json->array_class = Qnil;
+ }
+ tmp = ID2SYM(i_decimal_class);
+ if (option_given_p(opts, tmp)) {
+ json->decimal_class = rb_hash_aref(opts, tmp);
+ } else {
+ json->decimal_class = Qnil;
+ }
+ tmp = ID2SYM(i_match_string);
+ if (option_given_p(opts, tmp)) {
+ VALUE match_string = rb_hash_aref(opts, tmp);
+ json->match_string = RTEST(match_string) ? match_string : Qnil;
+ } else {
+ json->match_string = Qnil;
+ }
+#ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
+ }
+#endif
} else {
json->max_nesting = 100;
json->allow_nan = 0;
json->create_additions = 0;
- json->create_id = Qnil;
+ json->create_id = rb_funcall(mJSON, i_create_id, 0);
json->object_class = Qnil;
json->array_class = Qnil;
json->decimal_class = Qnil;
@@ -810,7 +847,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
*
* Parses the current JSON text _source_ and returns the complete data
* structure as a result.
- * It raises JSON::ParserError if fail to parse.
+ * It raises JSON::ParseError if fail to parse.
*/
static VALUE cParser_parse(VALUE self)
{
@@ -827,7 +864,7 @@ static VALUE cParser_parse(VALUE self)
if (cs >= JSON_first_final && p == pe) {
return result;
} else {
- rb_enc_raise(rb_utf8_encoding(), eParserError, "unexpected token at '%s'", p);
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
return Qnil;
}
}
@@ -835,12 +872,12 @@ static VALUE cParser_parse(VALUE self)
static void JSON_mark(void *ptr)
{
JSON_Parser *json = ptr;
- rb_gc_mark(json->Vsource);
- rb_gc_mark(json->create_id);
- rb_gc_mark(json->object_class);
- rb_gc_mark(json->array_class);
- rb_gc_mark(json->decimal_class);
- rb_gc_mark(json->match_string);
+ rb_gc_mark_maybe(json->Vsource);
+ rb_gc_mark_maybe(json->create_id);
+ rb_gc_mark_maybe(json->object_class);
+ rb_gc_mark_maybe(json->array_class);
+ rb_gc_mark_maybe(json->decimal_class);
+ rb_gc_mark_maybe(json->match_string);
}
static void JSON_free(void *ptr)
@@ -856,12 +893,16 @@ static size_t JSON_memsize(const void *ptr)
return sizeof(*json) + FBUFFER_CAPA(json->fbuffer);
}
+#ifdef NEW_TYPEDDATA_WRAPPER
static const rb_data_type_t JSON_Parser_type = {
"JSON/Parser",
{JSON_mark, JSON_free, JSON_memsize,},
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
0, 0,
RUBY_TYPED_FREE_IMMEDIATELY,
+#endif
};
+#endif
static VALUE cJSON_parser_s_allocate(VALUE klass)
{
diff --git a/ext/monitor/depend b/ext/monitor/depend
index bc7ead0d32..3030da71d0 100644
--- a/ext/monitor/depend
+++ b/ext/monitor/depend
@@ -51,7 +51,6 @@ monitor.o: $(hdrdir)/ruby/internal/attr/noexcept.h
monitor.o: $(hdrdir)/ruby/internal/attr/noinline.h
monitor.o: $(hdrdir)/ruby/internal/attr/nonnull.h
monitor.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-monitor.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
monitor.o: $(hdrdir)/ruby/internal/attr/pure.h
monitor.o: $(hdrdir)/ruby/internal/attr/restrict.h
monitor.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -111,6 +110,7 @@ monitor.o: $(hdrdir)/ruby/internal/intern/enumerator.h
monitor.o: $(hdrdir)/ruby/internal/intern/error.h
monitor.o: $(hdrdir)/ruby/internal/intern/eval.h
monitor.o: $(hdrdir)/ruby/internal/intern/file.h
+monitor.o: $(hdrdir)/ruby/internal/intern/gc.h
monitor.o: $(hdrdir)/ruby/internal/intern/hash.h
monitor.o: $(hdrdir)/ruby/internal/intern/io.h
monitor.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -141,12 +141,12 @@ monitor.o: $(hdrdir)/ruby/internal/memory.h
monitor.o: $(hdrdir)/ruby/internal/method.h
monitor.o: $(hdrdir)/ruby/internal/module.h
monitor.o: $(hdrdir)/ruby/internal/newobj.h
+monitor.o: $(hdrdir)/ruby/internal/rgengc.h
monitor.o: $(hdrdir)/ruby/internal/scan_args.h
monitor.o: $(hdrdir)/ruby/internal/special_consts.h
monitor.o: $(hdrdir)/ruby/internal/static_assert.h
monitor.o: $(hdrdir)/ruby/internal/stdalign.h
monitor.o: $(hdrdir)/ruby/internal/stdbool.h
-monitor.o: $(hdrdir)/ruby/internal/stdckdint.h
monitor.o: $(hdrdir)/ruby/internal/symbol.h
monitor.o: $(hdrdir)/ruby/internal/value.h
monitor.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/monitor/lib/monitor.rb b/ext/monitor/lib/monitor.rb
index 31d6d2b3c4..11c5ac17d9 100644
--- a/ext/monitor/lib/monitor.rb
+++ b/ext/monitor/lib/monitor.rb
@@ -7,19 +7,17 @@
# You can freely distribute/modify this library.
#
-require 'monitor.so'
-
#
# In concurrent programming, a monitor is an object or module intended to be
-# used safely by more than one thread. The defining characteristic of a
-# monitor is that its methods are executed with mutual exclusion. That is, at
+# used safely by more than one thread. The defining characteristic of a
+# monitor is that its methods are executed with mutual exclusion. That is, at
# each point in time, at most one thread may be executing any of its methods.
# This mutual exclusion greatly simplifies reasoning about the implementation
# of monitors compared to reasoning about parallel code that updates a data
# structure.
#
# You can read more about the general principles on the Wikipedia page for
-# Monitors[https://en.wikipedia.org/wiki/Monitor_%28synchronization%29].
+# Monitors[https://en.wikipedia.org/wiki/Monitor_%28synchronization%29]
#
# == Examples
#
@@ -50,7 +48,7 @@ require 'monitor.so'
# end
#
# The consumer thread waits for the producer thread to push a line to buf
-# while <tt>buf.empty?</tt>. The producer thread (main thread) reads a
+# while <tt>buf.empty?</tt>. The producer thread (main thread) reads a
# line from ARGF and pushes it into buf then calls <tt>empty_cond.signal</tt>
# to notify the consumer thread of new data.
#
@@ -88,6 +86,9 @@ require 'monitor.so'
# This Class is implemented as subclass of Array which includes the
# MonitorMixin module.
#
+
+require 'monitor.so'
+
module MonitorMixin
#
# FIXME: This isn't documented in Nutshell.
diff --git a/ext/monitor/monitor.c b/ext/monitor/monitor.c
index 86613f6ade..10209cf2aa 100644
--- a/ext/monitor/monitor.c
+++ b/ext/monitor/monitor.c
@@ -102,7 +102,7 @@ monitor_exit(VALUE monitor)
struct rb_monitor *mc = monitor_ptr(monitor);
- if (mc->count <= 0) rb_bug("monitor_exit: count:%d", (int)mc->count);
+ if (mc->count <= 0) rb_bug("monitor_exit: count:%d\n", (int)mc->count);
mc->count--;
if (mc->count == 0) {
diff --git a/ext/nkf/depend b/ext/nkf/depend
new file mode 100644
index 0000000000..9e2f468ba1
--- /dev/null
+++ b/ext/nkf/depend
@@ -0,0 +1,182 @@
+# BSD make needs "nkf.o: nkf.c" dependency BEFORE "nkf.o: nkf-utf8/nkf.c".
+# It seems BSD make searches the target for implicit rule in dependencies at first.
+nkf.o: nkf.c
+
+# AUTOGENERATED DEPENDENCIES START
+nkf.o: $(RUBY_EXTCONF_H)
+nkf.o: $(arch_hdrdir)/ruby/config.h
+nkf.o: $(hdrdir)/ruby/assert.h
+nkf.o: $(hdrdir)/ruby/backward.h
+nkf.o: $(hdrdir)/ruby/backward/2/assume.h
+nkf.o: $(hdrdir)/ruby/backward/2/attributes.h
+nkf.o: $(hdrdir)/ruby/backward/2/bool.h
+nkf.o: $(hdrdir)/ruby/backward/2/inttypes.h
+nkf.o: $(hdrdir)/ruby/backward/2/limits.h
+nkf.o: $(hdrdir)/ruby/backward/2/long_long.h
+nkf.o: $(hdrdir)/ruby/backward/2/stdalign.h
+nkf.o: $(hdrdir)/ruby/backward/2/stdarg.h
+nkf.o: $(hdrdir)/ruby/defines.h
+nkf.o: $(hdrdir)/ruby/encoding.h
+nkf.o: $(hdrdir)/ruby/intern.h
+nkf.o: $(hdrdir)/ruby/internal/abi.h
+nkf.o: $(hdrdir)/ruby/internal/anyargs.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+nkf.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+nkf.o: $(hdrdir)/ruby/internal/assume.h
+nkf.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+nkf.o: $(hdrdir)/ruby/internal/attr/artificial.h
+nkf.o: $(hdrdir)/ruby/internal/attr/cold.h
+nkf.o: $(hdrdir)/ruby/internal/attr/const.h
+nkf.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+nkf.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+nkf.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+nkf.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+nkf.o: $(hdrdir)/ruby/internal/attr/error.h
+nkf.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+nkf.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+nkf.o: $(hdrdir)/ruby/internal/attr/format.h
+nkf.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+nkf.o: $(hdrdir)/ruby/internal/attr/noalias.h
+nkf.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+nkf.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+nkf.o: $(hdrdir)/ruby/internal/attr/noinline.h
+nkf.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+nkf.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+nkf.o: $(hdrdir)/ruby/internal/attr/pure.h
+nkf.o: $(hdrdir)/ruby/internal/attr/restrict.h
+nkf.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+nkf.o: $(hdrdir)/ruby/internal/attr/warning.h
+nkf.o: $(hdrdir)/ruby/internal/attr/weakref.h
+nkf.o: $(hdrdir)/ruby/internal/cast.h
+nkf.o: $(hdrdir)/ruby/internal/compiler_is.h
+nkf.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+nkf.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+nkf.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+nkf.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+nkf.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+nkf.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+nkf.o: $(hdrdir)/ruby/internal/compiler_since.h
+nkf.o: $(hdrdir)/ruby/internal/config.h
+nkf.o: $(hdrdir)/ruby/internal/constant_p.h
+nkf.o: $(hdrdir)/ruby/internal/core.h
+nkf.o: $(hdrdir)/ruby/internal/core/rarray.h
+nkf.o: $(hdrdir)/ruby/internal/core/rbasic.h
+nkf.o: $(hdrdir)/ruby/internal/core/rbignum.h
+nkf.o: $(hdrdir)/ruby/internal/core/rclass.h
+nkf.o: $(hdrdir)/ruby/internal/core/rdata.h
+nkf.o: $(hdrdir)/ruby/internal/core/rfile.h
+nkf.o: $(hdrdir)/ruby/internal/core/rhash.h
+nkf.o: $(hdrdir)/ruby/internal/core/robject.h
+nkf.o: $(hdrdir)/ruby/internal/core/rregexp.h
+nkf.o: $(hdrdir)/ruby/internal/core/rstring.h
+nkf.o: $(hdrdir)/ruby/internal/core/rstruct.h
+nkf.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+nkf.o: $(hdrdir)/ruby/internal/ctype.h
+nkf.o: $(hdrdir)/ruby/internal/dllexport.h
+nkf.o: $(hdrdir)/ruby/internal/dosish.h
+nkf.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+nkf.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+nkf.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+nkf.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+nkf.o: $(hdrdir)/ruby/internal/encoding/re.h
+nkf.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+nkf.o: $(hdrdir)/ruby/internal/encoding/string.h
+nkf.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+nkf.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+nkf.o: $(hdrdir)/ruby/internal/error.h
+nkf.o: $(hdrdir)/ruby/internal/eval.h
+nkf.o: $(hdrdir)/ruby/internal/event.h
+nkf.o: $(hdrdir)/ruby/internal/fl_type.h
+nkf.o: $(hdrdir)/ruby/internal/gc.h
+nkf.o: $(hdrdir)/ruby/internal/glob.h
+nkf.o: $(hdrdir)/ruby/internal/globals.h
+nkf.o: $(hdrdir)/ruby/internal/has/attribute.h
+nkf.o: $(hdrdir)/ruby/internal/has/builtin.h
+nkf.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+nkf.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+nkf.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+nkf.o: $(hdrdir)/ruby/internal/has/extension.h
+nkf.o: $(hdrdir)/ruby/internal/has/feature.h
+nkf.o: $(hdrdir)/ruby/internal/has/warning.h
+nkf.o: $(hdrdir)/ruby/internal/intern/array.h
+nkf.o: $(hdrdir)/ruby/internal/intern/bignum.h
+nkf.o: $(hdrdir)/ruby/internal/intern/class.h
+nkf.o: $(hdrdir)/ruby/internal/intern/compar.h
+nkf.o: $(hdrdir)/ruby/internal/intern/complex.h
+nkf.o: $(hdrdir)/ruby/internal/intern/cont.h
+nkf.o: $(hdrdir)/ruby/internal/intern/dir.h
+nkf.o: $(hdrdir)/ruby/internal/intern/enum.h
+nkf.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+nkf.o: $(hdrdir)/ruby/internal/intern/error.h
+nkf.o: $(hdrdir)/ruby/internal/intern/eval.h
+nkf.o: $(hdrdir)/ruby/internal/intern/file.h
+nkf.o: $(hdrdir)/ruby/internal/intern/gc.h
+nkf.o: $(hdrdir)/ruby/internal/intern/hash.h
+nkf.o: $(hdrdir)/ruby/internal/intern/io.h
+nkf.o: $(hdrdir)/ruby/internal/intern/load.h
+nkf.o: $(hdrdir)/ruby/internal/intern/marshal.h
+nkf.o: $(hdrdir)/ruby/internal/intern/numeric.h
+nkf.o: $(hdrdir)/ruby/internal/intern/object.h
+nkf.o: $(hdrdir)/ruby/internal/intern/parse.h
+nkf.o: $(hdrdir)/ruby/internal/intern/proc.h
+nkf.o: $(hdrdir)/ruby/internal/intern/process.h
+nkf.o: $(hdrdir)/ruby/internal/intern/random.h
+nkf.o: $(hdrdir)/ruby/internal/intern/range.h
+nkf.o: $(hdrdir)/ruby/internal/intern/rational.h
+nkf.o: $(hdrdir)/ruby/internal/intern/re.h
+nkf.o: $(hdrdir)/ruby/internal/intern/ruby.h
+nkf.o: $(hdrdir)/ruby/internal/intern/select.h
+nkf.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+nkf.o: $(hdrdir)/ruby/internal/intern/signal.h
+nkf.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+nkf.o: $(hdrdir)/ruby/internal/intern/string.h
+nkf.o: $(hdrdir)/ruby/internal/intern/struct.h
+nkf.o: $(hdrdir)/ruby/internal/intern/thread.h
+nkf.o: $(hdrdir)/ruby/internal/intern/time.h
+nkf.o: $(hdrdir)/ruby/internal/intern/variable.h
+nkf.o: $(hdrdir)/ruby/internal/intern/vm.h
+nkf.o: $(hdrdir)/ruby/internal/interpreter.h
+nkf.o: $(hdrdir)/ruby/internal/iterator.h
+nkf.o: $(hdrdir)/ruby/internal/memory.h
+nkf.o: $(hdrdir)/ruby/internal/method.h
+nkf.o: $(hdrdir)/ruby/internal/module.h
+nkf.o: $(hdrdir)/ruby/internal/newobj.h
+nkf.o: $(hdrdir)/ruby/internal/rgengc.h
+nkf.o: $(hdrdir)/ruby/internal/scan_args.h
+nkf.o: $(hdrdir)/ruby/internal/special_consts.h
+nkf.o: $(hdrdir)/ruby/internal/static_assert.h
+nkf.o: $(hdrdir)/ruby/internal/stdalign.h
+nkf.o: $(hdrdir)/ruby/internal/stdbool.h
+nkf.o: $(hdrdir)/ruby/internal/symbol.h
+nkf.o: $(hdrdir)/ruby/internal/value.h
+nkf.o: $(hdrdir)/ruby/internal/value_type.h
+nkf.o: $(hdrdir)/ruby/internal/variable.h
+nkf.o: $(hdrdir)/ruby/internal/warning_push.h
+nkf.o: $(hdrdir)/ruby/internal/xmalloc.h
+nkf.o: $(hdrdir)/ruby/missing.h
+nkf.o: $(hdrdir)/ruby/onigmo.h
+nkf.o: $(hdrdir)/ruby/oniguruma.h
+nkf.o: $(hdrdir)/ruby/ruby.h
+nkf.o: $(hdrdir)/ruby/st.h
+nkf.o: $(hdrdir)/ruby/subst.h
+nkf.o: nkf-utf8/config.h
+nkf.o: nkf-utf8/nkf.c
+nkf.o: nkf-utf8/nkf.h
+nkf.o: nkf-utf8/utf8tbl.c
+nkf.o: nkf-utf8/utf8tbl.h
+nkf.o: nkf.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/nkf/extconf.rb b/ext/nkf/extconf.rb
new file mode 100644
index 0000000000..f41f6b11dc
--- /dev/null
+++ b/ext/nkf/extconf.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: false
+require 'mkmf'
+create_makefile('nkf')
diff --git a/ext/nkf/lib/kconv.rb b/ext/nkf/lib/kconv.rb
new file mode 100644
index 0000000000..f52b755288
--- /dev/null
+++ b/ext/nkf/lib/kconv.rb
@@ -0,0 +1,283 @@
+# frozen_string_literal: false
+#
+# kconv.rb - Kanji Converter.
+#
+# $Id$
+#
+# ----
+#
+# kconv.rb implements the Kconv class for Kanji Converter. Additionally,
+# some methods in String classes are added to allow easy conversion.
+#
+
+require 'nkf'
+
+#
+# Kanji Converter for Ruby.
+#
+module Kconv
+ #
+ # Public Constants
+ #
+
+ #Constant of Encoding
+
+ # Auto-Detect
+ AUTO = NKF::AUTO
+ # ISO-2022-JP
+ JIS = NKF::JIS
+ # EUC-JP
+ EUC = NKF::EUC
+ # Shift_JIS
+ SJIS = NKF::SJIS
+ # BINARY
+ BINARY = NKF::BINARY
+ # NOCONV
+ NOCONV = NKF::NOCONV
+ # ASCII
+ ASCII = NKF::ASCII
+ # UTF-8
+ UTF8 = NKF::UTF8
+ # UTF-16
+ UTF16 = NKF::UTF16
+ # UTF-32
+ UTF32 = NKF::UTF32
+ # UNKNOWN
+ UNKNOWN = NKF::UNKNOWN
+
+ #
+ # Public Methods
+ #
+
+ # call-seq:
+ # Kconv.kconv(str, to_enc, from_enc=nil)
+ #
+ # Convert <code>str</code> to <code>to_enc</code>.
+ # <code>to_enc</code> and <code>from_enc</code> are given as constants of Kconv or Encoding objects.
+ def kconv(str, to_enc, from_enc=nil)
+ opt = ''
+ opt += ' --ic=' + from_enc.to_s if from_enc
+ opt += ' --oc=' + to_enc.to_s if to_enc
+
+ ::NKF::nkf(opt, str)
+ end
+ module_function :kconv
+
+ #
+ # Encode to
+ #
+
+ # call-seq:
+ # Kconv.tojis(str) => string
+ #
+ # Convert <code>str</code> to ISO-2022-JP
+ def tojis(str)
+ kconv(str, JIS)
+ end
+ module_function :tojis
+
+ # call-seq:
+ # Kconv.toeuc(str) => string
+ #
+ # Convert <code>str</code> to EUC-JP
+ def toeuc(str)
+ kconv(str, EUC)
+ end
+ module_function :toeuc
+
+ # call-seq:
+ # Kconv.tosjis(str) => string
+ #
+ # Convert <code>str</code> to Shift_JIS
+ def tosjis(str)
+ kconv(str, SJIS)
+ end
+ module_function :tosjis
+
+ # call-seq:
+ # Kconv.toutf8(str) => string
+ #
+ # Convert <code>str</code> to UTF-8
+ def toutf8(str)
+ kconv(str, UTF8)
+ end
+ module_function :toutf8
+
+ # call-seq:
+ # Kconv.toutf16(str) => string
+ #
+ # Convert <code>str</code> to UTF-16
+ def toutf16(str)
+ kconv(str, UTF16)
+ end
+ module_function :toutf16
+
+ # call-seq:
+ # Kconv.toutf32(str) => string
+ #
+ # Convert <code>str</code> to UTF-32
+ def toutf32(str)
+ kconv(str, UTF32)
+ end
+ module_function :toutf32
+
+ # call-seq:
+ # Kconv.tolocale => string
+ #
+ # Convert <code>self</code> to locale encoding
+ def tolocale(str)
+ kconv(str, Encoding.locale_charmap)
+ end
+ module_function :tolocale
+
+ #
+ # guess
+ #
+
+ # call-seq:
+ # Kconv.guess(str) => encoding
+ #
+ # Guess input encoding by NKF.guess
+ def guess(str)
+ ::NKF::guess(str)
+ end
+ module_function :guess
+
+ #
+ # isEncoding
+ #
+
+ # call-seq:
+ # Kconv.iseuc(str) => true or false
+ #
+ # Returns whether input encoding is EUC-JP or not.
+ #
+ # *Note* don't expect this return value is MatchData.
+ def iseuc(str)
+ str.dup.force_encoding(EUC).valid_encoding?
+ end
+ module_function :iseuc
+
+ # call-seq:
+ # Kconv.issjis(str) => true or false
+ #
+ # Returns whether input encoding is Shift_JIS or not.
+ def issjis(str)
+ str.dup.force_encoding(SJIS).valid_encoding?
+ end
+ module_function :issjis
+
+ # call-seq:
+ # Kconv.isjis(str) => true or false
+ #
+ # Returns whether input encoding is ISO-2022-JP or not.
+ def isjis(str)
+ /\A [\t\n\r\x20-\x7E]*
+ (?:
+ (?:\x1b \x28 I [\x21-\x7E]*
+ |\x1b \x28 J [\x21-\x7E]*
+ |\x1b \x24 @ (?:[\x21-\x7E]{2})*
+ |\x1b \x24 B (?:[\x21-\x7E]{2})*
+ |\x1b \x24 \x28 D (?:[\x21-\x7E]{2})*
+ )*
+ \x1b \x28 B [\t\n\r\x20-\x7E]*
+ )*
+ \z/nox =~ str.dup.force_encoding('BINARY') ? true : false
+ end
+ module_function :isjis
+
+ # call-seq:
+ # Kconv.isutf8(str) => true or false
+ #
+ # Returns whether input encoding is UTF-8 or not.
+ def isutf8(str)
+ str.dup.force_encoding(UTF8).valid_encoding?
+ end
+ module_function :isutf8
+end
+
+class String
+ # call-seq:
+ # String#kconv(to_enc, from_enc)
+ #
+ # Convert <code>self</code> to <code>to_enc</code>.
+ # <code>to_enc</code> and <code>from_enc</code> are given as constants of Kconv or Encoding objects.
+ def kconv(to_enc, from_enc=nil)
+ from_enc = self.encoding if !from_enc && self.encoding != Encoding.list[0]
+ Kconv::kconv(self, to_enc, from_enc)
+ end
+
+ #
+ # to Encoding
+ #
+
+ # call-seq:
+ # String#tojis => string
+ #
+ # Convert <code>self</code> to ISO-2022-JP
+ def tojis; Kconv.tojis(self) end
+
+ # call-seq:
+ # String#toeuc => string
+ #
+ # Convert <code>self</code> to EUC-JP
+ def toeuc; Kconv.toeuc(self) end
+
+ # call-seq:
+ # String#tosjis => string
+ #
+ # Convert <code>self</code> to Shift_JIS
+ def tosjis; Kconv.tosjis(self) end
+
+ # call-seq:
+ # String#toutf8 => string
+ #
+ # Convert <code>self</code> to UTF-8
+ def toutf8; Kconv.toutf8(self) end
+
+ # call-seq:
+ # String#toutf16 => string
+ #
+ # Convert <code>self</code> to UTF-16
+ def toutf16; Kconv.toutf16(self) end
+
+ # call-seq:
+ # String#toutf32 => string
+ #
+ # Convert <code>self</code> to UTF-32
+ def toutf32; Kconv.toutf32(self) end
+
+ # call-seq:
+ # String#tolocale => string
+ #
+ # Convert <code>self</code> to locale encoding
+ def tolocale; Kconv.tolocale(self) end
+
+ #
+ # is Encoding
+ #
+
+ # call-seq:
+ # String#iseuc => true or false
+ #
+ # Returns whether <code>self</code>'s encoding is EUC-JP or not.
+ def iseuc; Kconv.iseuc(self) end
+
+ # call-seq:
+ # String#issjis => true or false
+ #
+ # Returns whether <code>self</code>'s encoding is Shift_JIS or not.
+ def issjis; Kconv.issjis(self) end
+
+ # call-seq:
+ # String#isjis => true or false
+ #
+ # Returns whether <code>self</code>'s encoding is ISO-2022-JP or not.
+ def isjis; Kconv.isjis(self) end
+
+ # call-seq:
+ # String#isutf8 => true or false
+ #
+ # Returns whether <code>self</code>'s encoding is UTF-8 or not.
+ def isutf8; Kconv.isutf8(self) end
+end
diff --git a/ext/nkf/nkf-utf8/config.h b/ext/nkf/nkf-utf8/config.h
new file mode 100644
index 0000000000..36898c0b4b
--- /dev/null
+++ b/ext/nkf/nkf-utf8/config.h
@@ -0,0 +1,51 @@
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+/* UTF8 input and output */
+#define UTF8_INPUT_ENABLE
+#define UTF8_OUTPUT_ENABLE
+
+/* invert characters invalid in Shift_JIS to CP932 */
+#define SHIFTJIS_CP932
+
+/* fix input encoding when given by option */
+#define INPUT_CODE_FIX
+
+/* --overwrite option */
+/* by Satoru Takabayashi <ccsatoru@vega.aichi-u.ac.jp> */
+#define OVERWRITE
+
+/* --cap-input, --url-input option */
+#define INPUT_OPTION
+
+/* --numchar-input option */
+#define NUMCHAR_OPTION
+
+/* --debug, --no-output option */
+#define CHECK_OPTION
+
+/* JIS X0212 */
+#define X0212_ENABLE
+
+/* --exec-in, --exec-out option
+ * require pipe, fork, execvp and so on.
+ * please undef this on MS-DOS, MinGW
+ * this is still buggy around child process
+ */
+/* #define EXEC_IO */
+
+/* Unicode Normalization */
+#define UNICODE_NORMALIZATION
+
+/*
+ * Select Default Output Encoding
+ *
+ */
+
+/* #define DEFAULT_CODE_JIS */
+/* #define DEFAULT_CODE_SJIS */
+/* #define DEFAULT_CODE_WINDOWS_31J */
+/* #define DEFAULT_CODE_EUC */
+/* #define DEFAULT_CODE_UTF8 */
+
+#endif /* _CONFIG_H_ */
diff --git a/ext/nkf/nkf-utf8/nkf.c b/ext/nkf/nkf-utf8/nkf.c
new file mode 100644
index 0000000000..6888a43918
--- /dev/null
+++ b/ext/nkf/nkf-utf8/nkf.c
@@ -0,0 +1,7205 @@
+/*
+ * Copyright (c) 1987, Fujitsu LTD. (Itaru ICHIKAWA).
+ * Copyright (c) 1996-2018, The nkf Project.
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+#define NKF_VERSION "2.1.5"
+#define NKF_RELEASE_DATE "2018-12-15"
+#define COPY_RIGHT \
+ "Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa).\n" \
+ "Copyright (C) 1996-2018, The nkf Project."
+
+#include "config.h"
+#include "nkf.h"
+#include "utf8tbl.h"
+#ifdef __WIN32__
+#include <windows.h>
+#include <locale.h>
+#endif
+#if defined(__OS2__)
+# define INCL_DOS
+# define INCL_DOSERRORS
+# include <os2.h>
+#endif
+#include <assert.h>
+
+
+/* state of output_mode and input_mode
+
+ c2 0 means ASCII
+ JIS_X_0201_1976_K
+ ISO_8859_1
+ JIS_X_0208
+ EOF all termination
+ c1 32bit data
+
+ */
+
+/* MIME ENCODE */
+
+#define FIXED_MIME 7
+#define STRICT_MIME 8
+
+/* byte order */
+enum byte_order {
+ ENDIAN_BIG = 1,
+ ENDIAN_LITTLE = 2,
+ ENDIAN_2143 = 3,
+ ENDIAN_3412 = 4
+};
+
+/* ASCII CODE */
+
+#define BS 0x08
+#define TAB 0x09
+#define LF 0x0a
+#define CR 0x0d
+#define ESC 0x1b
+#define SP 0x20
+#define DEL 0x7f
+#define SI 0x0f
+#define SO 0x0e
+#define SS2 0x8e
+#define SS3 0x8f
+#define CRLF 0x0D0A
+
+
+/* encodings */
+
+enum nkf_encodings {
+ ASCII,
+ ISO_8859_1,
+ ISO_2022_JP,
+ CP50220,
+ CP50221,
+ CP50222,
+ ISO_2022_JP_1,
+ ISO_2022_JP_3,
+ ISO_2022_JP_2004,
+ SHIFT_JIS,
+ WINDOWS_31J,
+ CP10001,
+ EUC_JP,
+ EUCJP_NKF,
+ CP51932,
+ EUCJP_MS,
+ EUCJP_ASCII,
+ SHIFT_JISX0213,
+ SHIFT_JIS_2004,
+ EUC_JISX0213,
+ EUC_JIS_2004,
+ UTF_8,
+ UTF_8N,
+ UTF_8_BOM,
+ UTF8_MAC,
+ UTF_16,
+ UTF_16BE,
+ UTF_16BE_BOM,
+ UTF_16LE,
+ UTF_16LE_BOM,
+ UTF_32,
+ UTF_32BE,
+ UTF_32BE_BOM,
+ UTF_32LE,
+ UTF_32LE_BOM,
+ BINARY,
+ NKF_ENCODING_TABLE_SIZE,
+ JIS_X_0201_1976_K = 0x1013, /* I */ /* JIS C 6220-1969 */
+ /* JIS_X_0201_1976_R = 0x1014, */ /* J */ /* JIS C 6220-1969 */
+ /* JIS_X_0208_1978 = 0x1040, */ /* @ */ /* JIS C 6226-1978 */
+ /* JIS_X_0208_1983 = 0x1087, */ /* B */ /* JIS C 6226-1983 */
+ JIS_X_0208 = 0x1168, /* @B */
+ JIS_X_0212 = 0x1159, /* D */
+ /* JIS_X_0213_2000_1 = 0x1228, */ /* O */
+ JIS_X_0213_2 = 0x1229, /* P */
+ JIS_X_0213_1 = 0x1233 /* Q */
+};
+
+static nkf_char s_iconv(nkf_char c2, nkf_char c1, nkf_char c0);
+static nkf_char e_iconv(nkf_char c2, nkf_char c1, nkf_char c0);
+static nkf_char w_iconv(nkf_char c2, nkf_char c1, nkf_char c0);
+static nkf_char w_iconv16(nkf_char c2, nkf_char c1, nkf_char c0);
+static nkf_char w_iconv32(nkf_char c2, nkf_char c1, nkf_char c0);
+static void j_oconv(nkf_char c2, nkf_char c1);
+static void s_oconv(nkf_char c2, nkf_char c1);
+static void e_oconv(nkf_char c2, nkf_char c1);
+static void w_oconv(nkf_char c2, nkf_char c1);
+static void w_oconv16(nkf_char c2, nkf_char c1);
+static void w_oconv32(nkf_char c2, nkf_char c1);
+
+typedef const struct {
+ const char *name;
+ nkf_char (*iconv)(nkf_char c2, nkf_char c1, nkf_char c0);
+ void (*oconv)(nkf_char c2, nkf_char c1);
+} nkf_native_encoding;
+
+nkf_native_encoding NkfEncodingASCII = { "ASCII", e_iconv, e_oconv };
+nkf_native_encoding NkfEncodingISO_2022_JP = { "ISO-2022-JP", e_iconv, j_oconv };
+nkf_native_encoding NkfEncodingShift_JIS = { "Shift_JIS", s_iconv, s_oconv };
+nkf_native_encoding NkfEncodingEUC_JP = { "EUC-JP", e_iconv, e_oconv };
+nkf_native_encoding NkfEncodingUTF_8 = { "UTF-8", w_iconv, w_oconv };
+nkf_native_encoding NkfEncodingUTF_16 = { "UTF-16", w_iconv16, w_oconv16 };
+nkf_native_encoding NkfEncodingUTF_32 = { "UTF-32", w_iconv32, w_oconv32 };
+
+typedef const struct {
+ int id;
+ const char *name;
+ nkf_native_encoding *base_encoding;
+} nkf_encoding;
+
+nkf_encoding nkf_encoding_table[] = {
+ {ASCII, "US-ASCII", &NkfEncodingASCII},
+ {ISO_8859_1, "ISO-8859-1", &NkfEncodingASCII},
+ {ISO_2022_JP, "ISO-2022-JP", &NkfEncodingISO_2022_JP},
+ {CP50220, "CP50220", &NkfEncodingISO_2022_JP},
+ {CP50221, "CP50221", &NkfEncodingISO_2022_JP},
+ {CP50222, "CP50222", &NkfEncodingISO_2022_JP},
+ {ISO_2022_JP_1, "ISO-2022-JP-1", &NkfEncodingISO_2022_JP},
+ {ISO_2022_JP_3, "ISO-2022-JP-3", &NkfEncodingISO_2022_JP},
+ {ISO_2022_JP_2004, "ISO-2022-JP-2004", &NkfEncodingISO_2022_JP},
+ {SHIFT_JIS, "Shift_JIS", &NkfEncodingShift_JIS},
+ {WINDOWS_31J, "Windows-31J", &NkfEncodingShift_JIS},
+ {CP10001, "CP10001", &NkfEncodingShift_JIS},
+ {EUC_JP, "EUC-JP", &NkfEncodingEUC_JP},
+ {EUCJP_NKF, "eucJP-nkf", &NkfEncodingEUC_JP},
+ {CP51932, "CP51932", &NkfEncodingEUC_JP},
+ {EUCJP_MS, "eucJP-MS", &NkfEncodingEUC_JP},
+ {EUCJP_ASCII, "eucJP-ASCII", &NkfEncodingEUC_JP},
+ {SHIFT_JISX0213, "Shift_JISX0213", &NkfEncodingShift_JIS},
+ {SHIFT_JIS_2004, "Shift_JIS-2004", &NkfEncodingShift_JIS},
+ {EUC_JISX0213, "EUC-JISX0213", &NkfEncodingEUC_JP},
+ {EUC_JIS_2004, "EUC-JIS-2004", &NkfEncodingEUC_JP},
+ {UTF_8, "UTF-8", &NkfEncodingUTF_8},
+ {UTF_8N, "UTF-8N", &NkfEncodingUTF_8},
+ {UTF_8_BOM, "UTF-8-BOM", &NkfEncodingUTF_8},
+ {UTF8_MAC, "UTF8-MAC", &NkfEncodingUTF_8},
+ {UTF_16, "UTF-16", &NkfEncodingUTF_16},
+ {UTF_16BE, "UTF-16BE", &NkfEncodingUTF_16},
+ {UTF_16BE_BOM, "UTF-16BE-BOM", &NkfEncodingUTF_16},
+ {UTF_16LE, "UTF-16LE", &NkfEncodingUTF_16},
+ {UTF_16LE_BOM, "UTF-16LE-BOM", &NkfEncodingUTF_16},
+ {UTF_32, "UTF-32", &NkfEncodingUTF_32},
+ {UTF_32BE, "UTF-32BE", &NkfEncodingUTF_32},
+ {UTF_32BE_BOM, "UTF-32BE-BOM", &NkfEncodingUTF_32},
+ {UTF_32LE, "UTF-32LE", &NkfEncodingUTF_32},
+ {UTF_32LE_BOM, "UTF-32LE-BOM", &NkfEncodingUTF_32},
+ {BINARY, "BINARY", &NkfEncodingASCII},
+ {-1, NULL, NULL}
+};
+
+static const struct {
+ const char *name;
+ int id;
+} encoding_name_to_id_table[] = {
+ {"US-ASCII", ASCII},
+ {"ASCII", ASCII},
+ {"646", ASCII},
+ {"ROMAN8", ASCII},
+ {"ISO-2022-JP", ISO_2022_JP},
+ {"ISO2022JP-CP932", CP50220},
+ {"CP50220", CP50220},
+ {"CP50221", CP50221},
+ {"CSISO2022JP", CP50221},
+ {"CP50222", CP50222},
+ {"ISO-2022-JP-1", ISO_2022_JP_1},
+ {"ISO-2022-JP-3", ISO_2022_JP_3},
+ {"ISO-2022-JP-2004", ISO_2022_JP_2004},
+ {"SHIFT_JIS", SHIFT_JIS},
+ {"SJIS", SHIFT_JIS},
+ {"MS_Kanji", SHIFT_JIS},
+ {"PCK", SHIFT_JIS},
+ {"WINDOWS-31J", WINDOWS_31J},
+ {"CSWINDOWS31J", WINDOWS_31J},
+ {"CP932", WINDOWS_31J},
+ {"MS932", WINDOWS_31J},
+ {"CP10001", CP10001},
+ {"EUCJP", EUC_JP},
+ {"EUC-JP", EUC_JP},
+ {"EUCJP-NKF", EUCJP_NKF},
+ {"CP51932", CP51932},
+ {"EUC-JP-MS", EUCJP_MS},
+ {"EUCJP-MS", EUCJP_MS},
+ {"EUCJPMS", EUCJP_MS},
+ {"EUC-JP-ASCII", EUCJP_ASCII},
+ {"EUCJP-ASCII", EUCJP_ASCII},
+ {"SHIFT_JISX0213", SHIFT_JISX0213},
+ {"SHIFT_JIS-2004", SHIFT_JIS_2004},
+ {"EUC-JISX0213", EUC_JISX0213},
+ {"EUC-JIS-2004", EUC_JIS_2004},
+ {"UTF-8", UTF_8},
+ {"UTF-8N", UTF_8N},
+ {"UTF-8-BOM", UTF_8_BOM},
+ {"UTF8-MAC", UTF8_MAC},
+ {"UTF-8-MAC", UTF8_MAC},
+ {"UTF-16", UTF_16},
+ {"UTF-16BE", UTF_16BE},
+ {"UTF-16BE-BOM", UTF_16BE_BOM},
+ {"UTF-16LE", UTF_16LE},
+ {"UTF-16LE-BOM", UTF_16LE_BOM},
+ {"UTF-32", UTF_32},
+ {"UTF-32BE", UTF_32BE},
+ {"UTF-32BE-BOM", UTF_32BE_BOM},
+ {"UTF-32LE", UTF_32LE},
+ {"UTF-32LE-BOM", UTF_32LE_BOM},
+ {"BINARY", BINARY},
+ {NULL, -1}
+};
+
+#if defined(DEFAULT_CODE_JIS)
+#define DEFAULT_ENCIDX ISO_2022_JP
+#elif defined(DEFAULT_CODE_SJIS)
+#define DEFAULT_ENCIDX SHIFT_JIS
+#elif defined(DEFAULT_CODE_WINDOWS_31J)
+#define DEFAULT_ENCIDX WINDOWS_31J
+#elif defined(DEFAULT_CODE_EUC)
+#define DEFAULT_ENCIDX EUC_JP
+#elif defined(DEFAULT_CODE_UTF8)
+#define DEFAULT_ENCIDX UTF_8
+#endif
+
+
+#define is_alnum(c) \
+ (('a'<=c && c<='z')||('A'<= c && c<='Z')||('0'<=c && c<='9'))
+
+/* I don't trust portablity of toupper */
+#define nkf_toupper(c) (('a'<=c && c<='z')?(c-('a'-'A')):c)
+#define nkf_isoctal(c) ('0'<=c && c<='7')
+#define nkf_isdigit(c) ('0'<=c && c<='9')
+#define nkf_isxdigit(c) (nkf_isdigit(c) || ('a'<=c && c<='f') || ('A'<=c && c <= 'F'))
+#define nkf_isblank(c) (c == SP || c == TAB)
+#define nkf_isspace(c) (nkf_isblank(c) || c == CR || c == LF)
+#define nkf_isalpha(c) (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
+#define nkf_isalnum(c) (nkf_isdigit(c) || nkf_isalpha(c))
+#define nkf_isprint(c) (SP<=c && c<='~')
+#define nkf_isgraph(c) ('!'<=c && c<='~')
+#define hex2bin(c) (('0'<=c&&c<='9') ? (c-'0') : \
+ ('A'<=c&&c<='F') ? (c-'A'+10) : \
+ ('a'<=c&&c<='f') ? (c-'a'+10) : 0)
+#define bin2hex(c) ("0123456789ABCDEF"[c&15])
+#define is_eucg3(c2) (((unsigned short)c2 >> 8) == SS3)
+#define nkf_noescape_mime(c) ((c == CR) || (c == LF) || \
+ ((c > SP) && (c < DEL) && (c != '?') && (c != '=') && (c != '_') \
+ && (c != '(') && (c != ')') && (c != '.') && (c != 0x22)))
+
+#define is_ibmext_in_sjis(c2) (CP932_TABLE_BEGIN <= c2 && c2 <= CP932_TABLE_END)
+#define nkf_byte_jisx0201_katakana_p(c) (SP <= c && c <= 0x5F)
+
+#define HOLD_SIZE 1024
+#if defined(INT_IS_SHORT)
+#define IOBUF_SIZE 2048
+#else
+#define IOBUF_SIZE 16384
+#endif
+
+#define DEFAULT_J 'B'
+#define DEFAULT_R 'B'
+
+
+#define GETA1 0x22
+#define GETA2 0x2e
+
+
+/* MIME preprocessor */
+
+#ifdef EASYWIN /*Easy Win */
+extern POINT _BufferSize;
+#endif
+
+struct input_code{
+ const char *name;
+ nkf_char stat;
+ nkf_char score;
+ nkf_char index;
+ nkf_char buf[3];
+ void (*status_func)(struct input_code *, nkf_char);
+ nkf_char (*iconv_func)(nkf_char c2, nkf_char c1, nkf_char c0);
+ int _file_stat;
+};
+
+static const char *input_codename = NULL; /* NULL: unestablished, "": BINARY */
+static nkf_encoding *input_encoding = NULL;
+static nkf_encoding *output_encoding = NULL;
+
+#if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
+/* UCS Mapping
+ * 0: Shift_JIS, eucJP-ascii
+ * 1: eucJP-ms
+ * 2: CP932, CP51932
+ * 3: CP10001
+ */
+#define UCS_MAP_ASCII 0
+#define UCS_MAP_MS 1
+#define UCS_MAP_CP932 2
+#define UCS_MAP_CP10001 3
+static int ms_ucs_map_f = UCS_MAP_ASCII;
+#endif
+#ifdef UTF8_INPUT_ENABLE
+/* no NEC special, NEC-selected IBM extended and IBM extended characters */
+static int no_cp932ext_f = FALSE;
+/* ignore ZERO WIDTH NO-BREAK SPACE */
+static int no_best_fit_chars_f = FALSE;
+static int input_endian = ENDIAN_BIG;
+static int input_bom_f = FALSE;
+static nkf_char unicode_subchar = '?'; /* the regular substitution character */
+static void (*encode_fallback)(nkf_char c) = NULL;
+static void w_status(struct input_code *, nkf_char);
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+static int output_bom_f = FALSE;
+static int output_endian = ENDIAN_BIG;
+#endif
+
+static void std_putc(nkf_char c);
+static nkf_char std_getc(FILE *f);
+static nkf_char std_ungetc(nkf_char c,FILE *f);
+
+static nkf_char broken_getc(FILE *f);
+static nkf_char broken_ungetc(nkf_char c,FILE *f);
+
+static nkf_char mime_getc(FILE *f);
+
+static void mime_putc(nkf_char c);
+
+/* buffers */
+
+#if !defined(PERL_XS) && !defined(WIN32DLL)
+static unsigned char stdibuf[IOBUF_SIZE];
+static unsigned char stdobuf[IOBUF_SIZE];
+#endif
+
+#define NKF_UNSPECIFIED (-TRUE)
+
+/* flags */
+static int unbuf_f = FALSE;
+static int estab_f = FALSE;
+static int nop_f = FALSE;
+static int binmode_f = TRUE; /* binary mode */
+static int rot_f = FALSE; /* rot14/43 mode */
+static int hira_f = FALSE; /* hira/kata henkan */
+static int alpha_f = FALSE; /* convert JIx0208 alphbet to ASCII */
+static int mime_f = MIME_DECODE_DEFAULT; /* convert MIME B base64 or Q */
+static int mime_decode_f = FALSE; /* mime decode is explicitly on */
+static int mimebuf_f = FALSE; /* MIME buffered input */
+static int broken_f = FALSE; /* convert ESC-less broken JIS */
+static int iso8859_f = FALSE; /* ISO8859 through */
+static int mimeout_f = FALSE; /* base64 mode */
+static int x0201_f = NKF_UNSPECIFIED; /* convert JIS X 0201 */
+static int iso2022jp_f = FALSE; /* replace non ISO-2022-JP with GETA */
+
+#ifdef UNICODE_NORMALIZATION
+static int nfc_f = FALSE;
+static nkf_char (*i_nfc_getc)(FILE *) = std_getc; /* input of ugetc */
+static nkf_char (*i_nfc_ungetc)(nkf_char c ,FILE *f) = std_ungetc;
+#endif
+
+#ifdef INPUT_OPTION
+static int cap_f = FALSE;
+static nkf_char (*i_cgetc)(FILE *) = std_getc; /* input of cgetc */
+static nkf_char (*i_cungetc)(nkf_char c ,FILE *f) = std_ungetc;
+
+static int url_f = FALSE;
+static nkf_char (*i_ugetc)(FILE *) = std_getc; /* input of ugetc */
+static nkf_char (*i_uungetc)(nkf_char c ,FILE *f) = std_ungetc;
+#endif
+
+#define PREFIX_EUCG3 NKF_INT32_C(0x8F00)
+#define CLASS_MASK NKF_INT32_C(0xFF000000)
+#define CLASS_UNICODE NKF_INT32_C(0x01000000)
+#define VALUE_MASK NKF_INT32_C(0x00FFFFFF)
+#define UNICODE_BMP_MAX NKF_INT32_C(0x0000FFFF)
+#define UNICODE_MAX NKF_INT32_C(0x0010FFFF)
+#define nkf_char_euc3_new(c) ((c) | PREFIX_EUCG3)
+#define nkf_char_unicode_new(c) ((c) | CLASS_UNICODE)
+#define nkf_char_unicode_p(c) ((c & CLASS_MASK) == CLASS_UNICODE)
+#define nkf_char_unicode_bmp_p(c) ((c & VALUE_MASK) <= UNICODE_BMP_MAX)
+#define nkf_char_unicode_value_p(c) ((c & VALUE_MASK) <= UNICODE_MAX)
+
+#define UTF16_TO_UTF32(lead, trail) (((lead) << 10) + (trail) - NKF_INT32_C(0x35FDC00))
+
+#ifdef NUMCHAR_OPTION
+static int numchar_f = FALSE;
+static nkf_char (*i_ngetc)(FILE *) = std_getc; /* input of ugetc */
+static nkf_char (*i_nungetc)(nkf_char c ,FILE *f) = std_ungetc;
+#endif
+
+#ifdef CHECK_OPTION
+static int noout_f = FALSE;
+static void no_putc(nkf_char c);
+static int debug_f = FALSE;
+static void debug(const char *str);
+static nkf_char (*iconv_for_check)(nkf_char c2,nkf_char c1,nkf_char c0) = 0;
+#endif
+
+static int guess_f = 0; /* 0: OFF, 1: ON, 2: VERBOSE */
+static void set_input_codename(const char *codename);
+
+#ifdef EXEC_IO
+static int exec_f = 0;
+#endif
+
+#ifdef SHIFTJIS_CP932
+/* invert IBM extended characters to others */
+static int cp51932_f = FALSE;
+
+/* invert NEC-selected IBM extended characters to IBM extended characters */
+static int cp932inv_f = TRUE;
+
+/* static nkf_char cp932_conv(nkf_char c2, nkf_char c1); */
+#endif /* SHIFTJIS_CP932 */
+
+static int x0212_f = FALSE;
+static int x0213_f = FALSE;
+
+static unsigned char prefix_table[256];
+
+static void e_status(struct input_code *, nkf_char);
+static void s_status(struct input_code *, nkf_char);
+
+struct input_code input_code_list[] = {
+ {"EUC-JP", 0, 0, 0, {0, 0, 0}, e_status, e_iconv, 0},
+ {"Shift_JIS", 0, 0, 0, {0, 0, 0}, s_status, s_iconv, 0},
+#ifdef UTF8_INPUT_ENABLE
+ {"UTF-8", 0, 0, 0, {0, 0, 0}, w_status, w_iconv, 0},
+ {"UTF-16", 0, 0, 0, {0, 0, 0}, NULL, w_iconv16, 0},
+ {"UTF-32", 0, 0, 0, {0, 0, 0}, NULL, w_iconv32, 0},
+#endif
+ {NULL, 0, 0, 0, {0, 0, 0}, NULL, NULL, 0}
+};
+
+static int mimeout_mode = 0; /* 0, -1, 'Q', 'B', 1, 2 */
+static int base64_count = 0;
+
+/* X0208 -> ASCII converter */
+
+/* fold parameter */
+static int f_line = 0; /* chars in line */
+static int f_prev = 0;
+static int fold_preserve_f = FALSE; /* preserve new lines */
+static int fold_f = FALSE;
+static int fold_len = 0;
+
+/* options */
+static unsigned char kanji_intro = DEFAULT_J;
+static unsigned char ascii_intro = DEFAULT_R;
+
+/* Folding */
+
+#define FOLD_MARGIN 10
+#define DEFAULT_FOLD 60
+
+static int fold_margin = FOLD_MARGIN;
+
+/* process default */
+
+static nkf_char
+no_connection2(ARG_UNUSED nkf_char c2, ARG_UNUSED nkf_char c1, ARG_UNUSED nkf_char c0)
+{
+ fprintf(stderr,"nkf internal module connection failure.\n");
+ exit(EXIT_FAILURE);
+ return 0; /* LINT */
+}
+
+static void
+no_connection(nkf_char c2, nkf_char c1)
+{
+ no_connection2(c2,c1,0);
+}
+
+static nkf_char (*iconv)(nkf_char c2,nkf_char c1,nkf_char c0) = no_connection2;
+static void (*oconv)(nkf_char c2,nkf_char c1) = no_connection;
+
+static void (*o_zconv)(nkf_char c2,nkf_char c1) = no_connection;
+static void (*o_fconv)(nkf_char c2,nkf_char c1) = no_connection;
+static void (*o_eol_conv)(nkf_char c2,nkf_char c1) = no_connection;
+static void (*o_rot_conv)(nkf_char c2,nkf_char c1) = no_connection;
+static void (*o_hira_conv)(nkf_char c2,nkf_char c1) = no_connection;
+static void (*o_base64conv)(nkf_char c2,nkf_char c1) = no_connection;
+static void (*o_iso2022jp_check_conv)(nkf_char c2,nkf_char c1) = no_connection;
+
+/* static redirections */
+
+static void (*o_putc)(nkf_char c) = std_putc;
+
+static nkf_char (*i_getc)(FILE *f) = std_getc; /* general input */
+static nkf_char (*i_ungetc)(nkf_char c,FILE *f) =std_ungetc;
+
+static nkf_char (*i_bgetc)(FILE *) = std_getc; /* input of mgetc */
+static nkf_char (*i_bungetc)(nkf_char c ,FILE *f) = std_ungetc;
+
+static void (*o_mputc)(nkf_char c) = std_putc ; /* output of mputc */
+
+static nkf_char (*i_mgetc)(FILE *) = std_getc; /* input of mgetc */
+static nkf_char (*i_mungetc)(nkf_char c ,FILE *f) = std_ungetc;
+
+/* for strict mime */
+static nkf_char (*i_mgetc_buf)(FILE *) = std_getc; /* input of mgetc_buf */
+static nkf_char (*i_mungetc_buf)(nkf_char c,FILE *f) = std_ungetc;
+
+/* Global states */
+static int output_mode = ASCII; /* output kanji mode */
+static int input_mode = ASCII; /* input kanji mode */
+static int mime_decode_mode = FALSE; /* MIME mode B base64, Q hex */
+
+/* X0201 / X0208 conversion tables */
+
+/* X0201 kana conversion table */
+/* 90-9F A0-DF */
+static const unsigned char cv[]= {
+ 0x21,0x21,0x21,0x23,0x21,0x56,0x21,0x57,
+ 0x21,0x22,0x21,0x26,0x25,0x72,0x25,0x21,
+ 0x25,0x23,0x25,0x25,0x25,0x27,0x25,0x29,
+ 0x25,0x63,0x25,0x65,0x25,0x67,0x25,0x43,
+ 0x21,0x3c,0x25,0x22,0x25,0x24,0x25,0x26,
+ 0x25,0x28,0x25,0x2a,0x25,0x2b,0x25,0x2d,
+ 0x25,0x2f,0x25,0x31,0x25,0x33,0x25,0x35,
+ 0x25,0x37,0x25,0x39,0x25,0x3b,0x25,0x3d,
+ 0x25,0x3f,0x25,0x41,0x25,0x44,0x25,0x46,
+ 0x25,0x48,0x25,0x4a,0x25,0x4b,0x25,0x4c,
+ 0x25,0x4d,0x25,0x4e,0x25,0x4f,0x25,0x52,
+ 0x25,0x55,0x25,0x58,0x25,0x5b,0x25,0x5e,
+ 0x25,0x5f,0x25,0x60,0x25,0x61,0x25,0x62,
+ 0x25,0x64,0x25,0x66,0x25,0x68,0x25,0x69,
+ 0x25,0x6a,0x25,0x6b,0x25,0x6c,0x25,0x6d,
+ 0x25,0x6f,0x25,0x73,0x21,0x2b,0x21,0x2c,
+ 0x00,0x00};
+
+
+/* X0201 kana conversion table for dakuten */
+/* 90-9F A0-DF */
+static const unsigned char dv[]= {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x25,0x74,
+ 0x00,0x00,0x00,0x00,0x25,0x2c,0x25,0x2e,
+ 0x25,0x30,0x25,0x32,0x25,0x34,0x25,0x36,
+ 0x25,0x38,0x25,0x3a,0x25,0x3c,0x25,0x3e,
+ 0x25,0x40,0x25,0x42,0x25,0x45,0x25,0x47,
+ 0x25,0x49,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x25,0x50,0x25,0x53,
+ 0x25,0x56,0x25,0x59,0x25,0x5c,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00};
+
+/* X0201 kana conversion table for han-dakuten */
+/* 90-9F A0-DF */
+static const unsigned char ev[]= {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x25,0x51,0x25,0x54,
+ 0x25,0x57,0x25,0x5a,0x25,0x5d,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00};
+
+/* X0201 kana to X0213 conversion table for han-dakuten */
+/* 90-9F A0-DF */
+static const unsigned char ev_x0213[]= {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x25,0x77,0x25,0x78,
+ 0x25,0x79,0x25,0x7a,0x25,0x7b,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x25,0x7c,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x25,0x7d,0x00,0x00,
+ 0x25,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00};
+
+
+/* X0208 kigou conversion table */
+/* 0x8140 - 0x819e */
+static const unsigned char fv[] = {
+
+ 0x00,0x00,0x00,0x00,0x2c,0x2e,0x00,0x3a,
+ 0x3b,0x3f,0x21,0x00,0x00,0x27,0x60,0x00,
+ 0x5e,0x00,0x5f,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x2d,0x00,0x2f,
+ 0x5c,0x00,0x00,0x7c,0x00,0x00,0x60,0x27,
+ 0x22,0x22,0x28,0x29,0x00,0x00,0x5b,0x5d,
+ 0x7b,0x7d,0x3c,0x3e,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x2b,0x2d,0x00,0x00,
+ 0x00,0x3d,0x00,0x3c,0x3e,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x24,0x00,0x00,0x25,0x23,0x26,0x2a,0x40,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+} ;
+
+
+
+static int option_mode = 0;
+static int file_out_f = FALSE;
+#ifdef OVERWRITE
+static int overwrite_f = FALSE;
+static int preserve_time_f = FALSE;
+static int backup_f = FALSE;
+static char *backup_suffix = "";
+#endif
+
+static int eolmode_f = 0; /* CR, LF, CRLF */
+static int input_eol = 0; /* 0: unestablished, EOF: MIXED */
+static nkf_char prev_cr = 0; /* CR or 0 */
+#ifdef EASYWIN /*Easy Win */
+static int end_check;
+#endif /*Easy Win */
+
+static void *
+nkf_xmalloc(size_t size)
+{
+ void *ptr;
+
+ if (size == 0) size = 1;
+
+ ptr = malloc(size);
+ if (ptr == NULL) {
+ perror("can't malloc");
+ exit(EXIT_FAILURE);
+ }
+
+ return ptr;
+}
+
+static void *
+nkf_xrealloc(void *ptr, size_t size)
+{
+ if (size == 0) size = 1;
+
+ ptr = realloc(ptr, size);
+ if (ptr == NULL) {
+ perror("can't realloc");
+ exit(EXIT_FAILURE);
+ }
+
+ return ptr;
+}
+
+#define nkf_xfree(ptr) free(ptr)
+
+static int
+nkf_str_caseeql(const char *src, const char *target)
+{
+ int i;
+ for (i = 0; src[i] && target[i]; i++) {
+ if (nkf_toupper(src[i]) != nkf_toupper(target[i])) return FALSE;
+ }
+ if (src[i] || target[i]) return FALSE;
+ else return TRUE;
+}
+
+static nkf_encoding*
+nkf_enc_from_index(int idx)
+{
+ if (idx < 0 || NKF_ENCODING_TABLE_SIZE <= idx) {
+ return 0;
+ }
+ return &nkf_encoding_table[idx];
+}
+
+static int
+nkf_enc_find_index(const char *name)
+{
+ int i;
+ if (name[0] == 'X' && *(name+1) == '-') name += 2;
+ for (i = 0; encoding_name_to_id_table[i].id >= 0; i++) {
+ if (nkf_str_caseeql(encoding_name_to_id_table[i].name, name)) {
+ return encoding_name_to_id_table[i].id;
+ }
+ }
+ return -1;
+}
+
+static nkf_encoding*
+nkf_enc_find(const char *name)
+{
+ int idx = -1;
+ idx = nkf_enc_find_index(name);
+ if (idx < 0) return 0;
+ return nkf_enc_from_index(idx);
+}
+
+#define nkf_enc_name(enc) (enc)->name
+#define nkf_enc_to_index(enc) (enc)->id
+#define nkf_enc_to_base_encoding(enc) (enc)->base_encoding
+#define nkf_enc_to_iconv(enc) nkf_enc_to_base_encoding(enc)->iconv
+#define nkf_enc_to_oconv(enc) nkf_enc_to_base_encoding(enc)->oconv
+#define nkf_enc_asciicompat(enc) (\
+ nkf_enc_to_base_encoding(enc) == &NkfEncodingASCII ||\
+ nkf_enc_to_base_encoding(enc) == &NkfEncodingISO_2022_JP)
+#define nkf_enc_unicode_p(enc) (\
+ nkf_enc_to_base_encoding(enc) == &NkfEncodingUTF_8 ||\
+ nkf_enc_to_base_encoding(enc) == &NkfEncodingUTF_16 ||\
+ nkf_enc_to_base_encoding(enc) == &NkfEncodingUTF_32)
+#define nkf_enc_cp5022x_p(enc) (\
+ nkf_enc_to_index(enc) == CP50220 ||\
+ nkf_enc_to_index(enc) == CP50221 ||\
+ nkf_enc_to_index(enc) == CP50222)
+
+#ifdef DEFAULT_CODE_LOCALE
+static const char*
+nkf_locale_charmap(void)
+{
+#ifdef HAVE_LANGINFO_H
+ return nl_langinfo(CODESET);
+#elif defined(__WIN32__)
+ static char buf[16];
+ sprintf(buf, "CP%d", GetACP());
+ return buf;
+#elif defined(__OS2__)
+# if defined(INT_IS_SHORT)
+ /* OS/2 1.x */
+ return NULL;
+# else
+ /* OS/2 32bit */
+ static char buf[16];
+ ULONG ulCP[1], ulncp;
+ DosQueryCp(sizeof(ulCP), ulCP, &ulncp);
+ if (ulCP[0] == 932 || ulCP[0] == 943)
+ strcpy(buf, "Shift_JIS");
+ else
+ sprintf(buf, "CP%lu", ulCP[0]);
+ return buf;
+# endif
+#endif
+ return NULL;
+}
+
+static nkf_encoding*
+nkf_locale_encoding(void)
+{
+ nkf_encoding *enc = 0;
+ const char *encname = nkf_locale_charmap();
+ if (encname)
+ enc = nkf_enc_find(encname);
+ return enc;
+}
+#endif /* DEFAULT_CODE_LOCALE */
+
+static nkf_encoding*
+nkf_utf8_encoding(void)
+{
+ return &nkf_encoding_table[UTF_8];
+}
+
+static nkf_encoding*
+nkf_default_encoding(void)
+{
+ nkf_encoding *enc = 0;
+#ifdef DEFAULT_CODE_LOCALE
+ enc = nkf_locale_encoding();
+#elif defined(DEFAULT_ENCIDX)
+ enc = nkf_enc_from_index(DEFAULT_ENCIDX);
+#endif
+ if (!enc) enc = nkf_utf8_encoding();
+ return enc;
+}
+
+typedef struct {
+ long capa;
+ long len;
+ nkf_char *ptr;
+} nkf_buf_t;
+
+static nkf_buf_t *
+nkf_buf_new(int length)
+{
+ nkf_buf_t *buf = nkf_xmalloc(sizeof(nkf_buf_t));
+ buf->ptr = nkf_xmalloc(sizeof(nkf_char) * length);
+ buf->capa = length;
+ buf->len = 0;
+ return buf;
+}
+
+#if 0
+static void
+nkf_buf_dispose(nkf_buf_t *buf)
+{
+ nkf_xfree(buf->ptr);
+ nkf_xfree(buf);
+}
+#endif
+
+#define nkf_buf_length(buf) ((buf)->len)
+#define nkf_buf_empty_p(buf) ((buf)->len == 0)
+
+static nkf_char
+nkf_buf_at(nkf_buf_t *buf, int index)
+{
+ assert(index <= buf->len);
+ return buf->ptr[index];
+}
+
+static void
+nkf_buf_clear(nkf_buf_t *buf)
+{
+ buf->len = 0;
+}
+
+static void
+nkf_buf_push(nkf_buf_t *buf, nkf_char c)
+{
+ if (buf->capa <= buf->len) {
+ exit(EXIT_FAILURE);
+ }
+ buf->ptr[buf->len++] = c;
+}
+
+static nkf_char
+nkf_buf_pop(nkf_buf_t *buf)
+{
+ assert(!nkf_buf_empty_p(buf));
+ return buf->ptr[--buf->len];
+}
+
+/* Normalization Form C */
+#ifndef PERL_XS
+#ifdef WIN32DLL
+#define fprintf dllprintf
+#endif
+
+static void
+version(void)
+{
+ fprintf(HELP_OUTPUT,"Network Kanji Filter Version " NKF_VERSION " (" NKF_RELEASE_DATE ") \n" COPY_RIGHT "\n");
+}
+
+static void
+usage(void)
+{
+ fprintf(HELP_OUTPUT,
+ "Usage: nkf -[flags] [--] [in file] .. [out file for -O flag]\n"
+#ifdef UTF8_OUTPUT_ENABLE
+ " j/s/e/w Specify output encoding ISO-2022-JP, Shift_JIS, EUC-JP\n"
+ " UTF options is -w[8[0],{16,32}[{B,L}[0]]]\n"
+#else
+#endif
+#ifdef UTF8_INPUT_ENABLE
+ " J/S/E/W Specify input encoding ISO-2022-JP, Shift_JIS, EUC-JP\n"
+ " UTF option is -W[8,[16,32][B,L]]\n"
+#else
+ " J/S/E Specify output encoding ISO-2022-JP, Shift_JIS, EUC-JP\n"
+#endif
+ );
+ fprintf(HELP_OUTPUT,
+ " m[BQSN0] MIME decode [B:base64,Q:quoted,S:strict,N:nonstrict,0:no decode]\n"
+ " M[BQ] MIME encode [B:base64 Q:quoted]\n"
+ " f/F Folding: -f60 or -f or -f60-10 (fold margin 10) F preserve nl\n"
+ );
+ fprintf(HELP_OUTPUT,
+ " Z[0-4] Default/0: Convert JISX0208 Alphabet to ASCII\n"
+ " 1: Kankaku to one space 2: to two spaces 3: HTML Entity\n"
+ " 4: JISX0208 Katakana to JISX0201 Katakana\n"
+ " X,x Convert Halfwidth Katakana to Fullwidth or preserve it\n"
+ );
+ fprintf(HELP_OUTPUT,
+ " O Output to File (DEFAULT 'nkf.out')\n"
+ " L[uwm] Line mode u:LF w:CRLF m:CR (DEFAULT noconversion)\n"
+ );
+ fprintf(HELP_OUTPUT,
+ " --ic=<encoding> Specify the input encoding\n"
+ " --oc=<encoding> Specify the output encoding\n"
+ " --hiragana --katakana Hiragana/Katakana Conversion\n"
+ " --katakana-hiragana Converts each other\n"
+ );
+ fprintf(HELP_OUTPUT,
+#ifdef INPUT_OPTION
+ " --{cap, url}-input Convert hex after ':' or '%%'\n"
+#endif
+#ifdef NUMCHAR_OPTION
+ " --numchar-input Convert Unicode Character Reference\n"
+#endif
+#ifdef UTF8_INPUT_ENABLE
+ " --fb-{skip, html, xml, perl, java, subchar}\n"
+ " Specify unassigned character's replacement\n"
+#endif
+ );
+ fprintf(HELP_OUTPUT,
+#ifdef OVERWRITE
+ " --in-place[=SUF] Overwrite original files\n"
+ " --overwrite[=SUF] Preserve timestamp of original files\n"
+#endif
+ " -g --guess Guess the input code\n"
+ " -v --version Print the version\n"
+ " --help/-V Print this help / configuration\n"
+ );
+ version();
+}
+
+static void
+show_configuration(void)
+{
+ fprintf(HELP_OUTPUT,
+ "Summary of my nkf " NKF_VERSION " (" NKF_RELEASE_DATE ") configuration:\n"
+ " Compile-time options:\n"
+ " Compiled at: " __DATE__ " " __TIME__ "\n"
+ );
+ fprintf(HELP_OUTPUT,
+ " Default output encoding: "
+#ifdef DEFAULT_CODE_LOCALE
+ "LOCALE (%s)\n", nkf_enc_name(nkf_default_encoding())
+#elif defined(DEFAULT_ENCIDX)
+ "CONFIG (%s)\n", nkf_enc_name(nkf_default_encoding())
+#else
+ "NONE\n"
+#endif
+ );
+ fprintf(HELP_OUTPUT,
+ " Default output end of line: "
+#if DEFAULT_NEWLINE == CR
+ "CR"
+#elif DEFAULT_NEWLINE == CRLF
+ "CRLF"
+#else
+ "LF"
+#endif
+ "\n"
+ " Decode MIME encoded string: "
+#if MIME_DECODE_DEFAULT
+ "ON"
+#else
+ "OFF"
+#endif
+ "\n"
+ " Convert JIS X 0201 Katakana: "
+#if X0201_DEFAULT
+ "ON"
+#else
+ "OFF"
+#endif
+ "\n"
+ " --help, --version output: "
+#if HELP_OUTPUT_HELP_OUTPUT
+ "HELP_OUTPUT"
+#else
+ "STDOUT"
+#endif
+ "\n");
+}
+#endif /*PERL_XS*/
+
+#ifdef OVERWRITE
+static char*
+get_backup_filename(const char *suffix, const char *filename)
+{
+ char *backup_filename;
+ int asterisk_count = 0;
+ int i, j;
+ int filename_length = strlen(filename);
+
+ for(i = 0; suffix[i]; i++){
+ if(suffix[i] == '*') asterisk_count++;
+ }
+
+ if(asterisk_count){
+ backup_filename = nkf_xmalloc(strlen(suffix) + (asterisk_count * (filename_length - 1)) + 1);
+ for(i = 0, j = 0; suffix[i];){
+ if(suffix[i] == '*'){
+ backup_filename[j] = '\0';
+ strncat(backup_filename, filename, filename_length);
+ i++;
+ j += filename_length;
+ }else{
+ backup_filename[j++] = suffix[i++];
+ }
+ }
+ backup_filename[j] = '\0';
+ }else{
+ j = filename_length + strlen(suffix);
+ backup_filename = nkf_xmalloc(j + 1);
+ strcpy(backup_filename, filename);
+ strcat(backup_filename, suffix);
+ backup_filename[j] = '\0';
+ }
+ return backup_filename;
+}
+#endif
+
+#ifdef UTF8_INPUT_ENABLE
+static void
+nkf_each_char_to_hex(void (*f)(nkf_char c2,nkf_char c1), nkf_char c)
+{
+ int shift = 20;
+ c &= VALUE_MASK;
+ while(shift >= 0){
+ if(c >= NKF_INT32_C(1)<<shift){
+ while(shift >= 0){
+ (*f)(0, bin2hex(c>>shift));
+ shift -= 4;
+ }
+ }else{
+ shift -= 4;
+ }
+ }
+ return;
+}
+
+static void
+encode_fallback_html(nkf_char c)
+{
+ (*oconv)(0, '&');
+ (*oconv)(0, '#');
+ c &= VALUE_MASK;
+ if(c >= NKF_INT32_C(1000000))
+ (*oconv)(0, 0x30+(c/NKF_INT32_C(1000000))%10);
+ if(c >= NKF_INT32_C(100000))
+ (*oconv)(0, 0x30+(c/NKF_INT32_C(100000) )%10);
+ if(c >= 10000)
+ (*oconv)(0, 0x30+(c/10000 )%10);
+ if(c >= 1000)
+ (*oconv)(0, 0x30+(c/1000 )%10);
+ if(c >= 100)
+ (*oconv)(0, 0x30+(c/100 )%10);
+ if(c >= 10)
+ (*oconv)(0, 0x30+(c/10 )%10);
+ if(c >= 0)
+ (*oconv)(0, 0x30+ c %10);
+ (*oconv)(0, ';');
+ return;
+}
+
+static void
+encode_fallback_xml(nkf_char c)
+{
+ (*oconv)(0, '&');
+ (*oconv)(0, '#');
+ (*oconv)(0, 'x');
+ nkf_each_char_to_hex(oconv, c);
+ (*oconv)(0, ';');
+ return;
+}
+
+static void
+encode_fallback_java(nkf_char c)
+{
+ (*oconv)(0, '\\');
+ c &= VALUE_MASK;
+ if(!nkf_char_unicode_bmp_p(c)){
+ int high = (c >> 10) + NKF_INT32_C(0xD7C0); /* high surrogate */
+ int low = (c & 0x3FF) + NKF_INT32_C(0xDC00); /* low surrogate */
+ (*oconv)(0, 'u');
+ (*oconv)(0, bin2hex(high>>12));
+ (*oconv)(0, bin2hex(high>> 8));
+ (*oconv)(0, bin2hex(high>> 4));
+ (*oconv)(0, bin2hex(high ));
+ (*oconv)(0, '\\');
+ (*oconv)(0, 'u');
+ (*oconv)(0, bin2hex(low>>12));
+ (*oconv)(0, bin2hex(low>> 8));
+ (*oconv)(0, bin2hex(low>> 4));
+ (*oconv)(0, bin2hex(low ));
+ }else{
+ (*oconv)(0, 'u');
+ (*oconv)(0, bin2hex(c>>12));
+ (*oconv)(0, bin2hex(c>> 8));
+ (*oconv)(0, bin2hex(c>> 4));
+ (*oconv)(0, bin2hex(c ));
+ }
+ return;
+}
+
+static void
+encode_fallback_perl(nkf_char c)
+{
+ (*oconv)(0, '\\');
+ (*oconv)(0, 'x');
+ (*oconv)(0, '{');
+ nkf_each_char_to_hex(oconv, c);
+ (*oconv)(0, '}');
+ return;
+}
+
+static void
+encode_fallback_subchar(nkf_char c)
+{
+ c = unicode_subchar;
+ (*oconv)((c>>8)&0xFF, c&0xFF);
+ return;
+}
+#endif
+
+static const struct {
+ const char *name;
+ const char *alias;
+} long_option[] = {
+ {"ic=", ""},
+ {"oc=", ""},
+ {"base64","jMB"},
+ {"euc","e"},
+ {"euc-input","E"},
+ {"fj","jm"},
+ {"help",""},
+ {"jis","j"},
+ {"jis-input","J"},
+ {"mac","sLm"},
+ {"mime","jM"},
+ {"mime-input","m"},
+ {"msdos","sLw"},
+ {"sjis","s"},
+ {"sjis-input","S"},
+ {"unix","eLu"},
+ {"version","v"},
+ {"windows","sLw"},
+ {"hiragana","h1"},
+ {"katakana","h2"},
+ {"katakana-hiragana","h3"},
+ {"guess=", ""},
+ {"guess", "g2"},
+ {"cp932", ""},
+ {"no-cp932", ""},
+#ifdef X0212_ENABLE
+ {"x0212", ""},
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ {"utf8", "w"},
+ {"utf16", "w16"},
+ {"ms-ucs-map", ""},
+ {"fb-skip", ""},
+ {"fb-html", ""},
+ {"fb-xml", ""},
+ {"fb-perl", ""},
+ {"fb-java", ""},
+ {"fb-subchar", ""},
+ {"fb-subchar=", ""},
+#endif
+#ifdef UTF8_INPUT_ENABLE
+ {"utf8-input", "W"},
+ {"utf16-input", "W16"},
+ {"no-cp932ext", ""},
+ {"no-best-fit-chars",""},
+#endif
+#ifdef UNICODE_NORMALIZATION
+ {"utf8mac-input", ""},
+#endif
+#ifdef OVERWRITE
+ {"overwrite", ""},
+ {"overwrite=", ""},
+ {"in-place", ""},
+ {"in-place=", ""},
+#endif
+#ifdef INPUT_OPTION
+ {"cap-input", ""},
+ {"url-input", ""},
+#endif
+#ifdef NUMCHAR_OPTION
+ {"numchar-input", ""},
+#endif
+#ifdef CHECK_OPTION
+ {"no-output", ""},
+ {"debug", ""},
+#endif
+#ifdef SHIFTJIS_CP932
+ {"cp932inv", ""},
+#endif
+#ifdef EXEC_IO
+ {"exec-in", ""},
+ {"exec-out", ""},
+#endif
+ {"prefix=", ""},
+};
+
+static void
+set_input_encoding(nkf_encoding *enc)
+{
+ switch (nkf_enc_to_index(enc)) {
+ case ISO_8859_1:
+ iso8859_f = TRUE;
+ break;
+ case CP50221:
+ case CP50222:
+ if (x0201_f == NKF_UNSPECIFIED) x0201_f = FALSE; /* -x specified implicitly */
+ case CP50220:
+#ifdef SHIFTJIS_CP932
+ cp51932_f = TRUE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP932;
+#endif
+ break;
+ case ISO_2022_JP_1:
+ x0212_f = TRUE;
+ break;
+ case ISO_2022_JP_3:
+ x0212_f = TRUE;
+ x0213_f = TRUE;
+ break;
+ case ISO_2022_JP_2004:
+ x0212_f = TRUE;
+ x0213_f = TRUE;
+ break;
+ case SHIFT_JIS:
+ break;
+ case WINDOWS_31J:
+ if (x0201_f == NKF_UNSPECIFIED) x0201_f = FALSE; /* -x specified implicitly */
+#ifdef SHIFTJIS_CP932
+ cp51932_f = TRUE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP932;
+#endif
+ break;
+ break;
+ case CP10001:
+#ifdef SHIFTJIS_CP932
+ cp51932_f = TRUE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP10001;
+#endif
+ break;
+ case EUC_JP:
+ break;
+ case EUCJP_NKF:
+ break;
+ case CP51932:
+ if (x0201_f == NKF_UNSPECIFIED) x0201_f = FALSE; /* -x specified implicitly */
+#ifdef SHIFTJIS_CP932
+ cp51932_f = TRUE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP932;
+#endif
+ break;
+ case EUCJP_MS:
+ if (x0201_f == NKF_UNSPECIFIED) x0201_f = FALSE; /* -x specified implicitly */
+#ifdef SHIFTJIS_CP932
+ cp51932_f = FALSE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_MS;
+#endif
+ break;
+ case EUCJP_ASCII:
+ if (x0201_f == NKF_UNSPECIFIED) x0201_f = FALSE; /* -x specified implicitly */
+#ifdef SHIFTJIS_CP932
+ cp51932_f = FALSE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_ASCII;
+#endif
+ break;
+ case SHIFT_JISX0213:
+ case SHIFT_JIS_2004:
+ x0213_f = TRUE;
+#ifdef SHIFTJIS_CP932
+ cp51932_f = FALSE;
+ if (cp932inv_f == TRUE) cp932inv_f = FALSE;
+#endif
+ break;
+ case EUC_JISX0213:
+ case EUC_JIS_2004:
+ x0213_f = TRUE;
+#ifdef SHIFTJIS_CP932
+ cp51932_f = FALSE;
+#endif
+ break;
+#ifdef UTF8_INPUT_ENABLE
+#ifdef UNICODE_NORMALIZATION
+ case UTF8_MAC:
+ nfc_f = TRUE;
+ break;
+#endif
+ case UTF_16:
+ case UTF_16BE:
+ case UTF_16BE_BOM:
+ input_endian = ENDIAN_BIG;
+ break;
+ case UTF_16LE:
+ case UTF_16LE_BOM:
+ input_endian = ENDIAN_LITTLE;
+ break;
+ case UTF_32:
+ case UTF_32BE:
+ case UTF_32BE_BOM:
+ input_endian = ENDIAN_BIG;
+ break;
+ case UTF_32LE:
+ case UTF_32LE_BOM:
+ input_endian = ENDIAN_LITTLE;
+ break;
+#endif
+ }
+}
+
+static void
+set_output_encoding(nkf_encoding *enc)
+{
+ switch (nkf_enc_to_index(enc)) {
+ case CP50220:
+#ifdef SHIFTJIS_CP932
+ if (cp932inv_f == TRUE) cp932inv_f = FALSE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP932;
+#endif
+ break;
+ case CP50221:
+ if (x0201_f == NKF_UNSPECIFIED) x0201_f = FALSE; /* -x specified implicitly */
+#ifdef SHIFTJIS_CP932
+ if (cp932inv_f == TRUE) cp932inv_f = FALSE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP932;
+#endif
+ break;
+ case ISO_2022_JP:
+#ifdef SHIFTJIS_CP932
+ if (cp932inv_f == TRUE) cp932inv_f = FALSE;
+#endif
+ break;
+ case ISO_2022_JP_1:
+ x0212_f = TRUE;
+#ifdef SHIFTJIS_CP932
+ if (cp932inv_f == TRUE) cp932inv_f = FALSE;
+#endif
+ break;
+ case ISO_2022_JP_3:
+ case ISO_2022_JP_2004:
+ x0212_f = TRUE;
+ x0213_f = TRUE;
+#ifdef SHIFTJIS_CP932
+ if (cp932inv_f == TRUE) cp932inv_f = FALSE;
+#endif
+ break;
+ case SHIFT_JIS:
+ break;
+ case WINDOWS_31J:
+ if (x0201_f == NKF_UNSPECIFIED) x0201_f = FALSE; /* -x specified implicitly */
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP932;
+#endif
+ break;
+ case CP10001:
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP10001;
+#endif
+ break;
+ case EUC_JP:
+ x0212_f = TRUE;
+#ifdef SHIFTJIS_CP932
+ if (cp932inv_f == TRUE) cp932inv_f = FALSE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_ASCII;
+#endif
+ break;
+ case EUCJP_NKF:
+ x0212_f = FALSE;
+#ifdef SHIFTJIS_CP932
+ if (cp932inv_f == TRUE) cp932inv_f = FALSE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_ASCII;
+#endif
+ break;
+ case CP51932:
+ if (x0201_f == NKF_UNSPECIFIED) x0201_f = FALSE; /* -x specified implicitly */
+#ifdef SHIFTJIS_CP932
+ if (cp932inv_f == TRUE) cp932inv_f = FALSE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP932;
+#endif
+ break;
+ case EUCJP_MS:
+ if (x0201_f == NKF_UNSPECIFIED) x0201_f = FALSE; /* -x specified implicitly */
+ x0212_f = TRUE;
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_MS;
+#endif
+ break;
+ case EUCJP_ASCII:
+ if (x0201_f == NKF_UNSPECIFIED) x0201_f = FALSE; /* -x specified implicitly */
+ x0212_f = TRUE;
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_ASCII;
+#endif
+ break;
+ case SHIFT_JISX0213:
+ case SHIFT_JIS_2004:
+ x0213_f = TRUE;
+#ifdef SHIFTJIS_CP932
+ if (cp932inv_f == TRUE) cp932inv_f = FALSE;
+#endif
+ break;
+ case EUC_JISX0213:
+ case EUC_JIS_2004:
+ x0212_f = TRUE;
+ x0213_f = TRUE;
+#ifdef SHIFTJIS_CP932
+ if (cp932inv_f == TRUE) cp932inv_f = FALSE;
+#endif
+ break;
+#ifdef UTF8_OUTPUT_ENABLE
+ case UTF_8_BOM:
+ output_bom_f = TRUE;
+ break;
+ case UTF_16:
+ case UTF_16BE_BOM:
+ output_bom_f = TRUE;
+ break;
+ case UTF_16LE:
+ output_endian = ENDIAN_LITTLE;
+ output_bom_f = FALSE;
+ break;
+ case UTF_16LE_BOM:
+ output_endian = ENDIAN_LITTLE;
+ output_bom_f = TRUE;
+ break;
+ case UTF_32:
+ case UTF_32BE_BOM:
+ output_bom_f = TRUE;
+ break;
+ case UTF_32LE:
+ output_endian = ENDIAN_LITTLE;
+ output_bom_f = FALSE;
+ break;
+ case UTF_32LE_BOM:
+ output_endian = ENDIAN_LITTLE;
+ output_bom_f = TRUE;
+ break;
+#endif
+ }
+}
+
+static struct input_code*
+find_inputcode_byfunc(nkf_char (*iconv_func)(nkf_char c2,nkf_char c1,nkf_char c0))
+{
+ if (iconv_func){
+ struct input_code *p = input_code_list;
+ while (p->name){
+ if (iconv_func == p->iconv_func){
+ return p;
+ }
+ p++;
+ }
+ }
+ return 0;
+}
+
+static void
+set_iconv(nkf_char f, nkf_char (*iconv_func)(nkf_char c2,nkf_char c1,nkf_char c0))
+{
+#ifdef INPUT_CODE_FIX
+ if (f || !input_encoding)
+#endif
+ if (estab_f != f){
+ estab_f = f;
+ }
+
+ if (iconv_func
+#ifdef INPUT_CODE_FIX
+ && (f == -TRUE || !input_encoding) /* -TRUE means "FORCE" */
+#endif
+ ){
+ iconv = iconv_func;
+ }
+#ifdef CHECK_OPTION
+ if (estab_f && iconv_for_check != iconv){
+ struct input_code *p = find_inputcode_byfunc(iconv);
+ if (p){
+ set_input_codename(p->name);
+ debug(p->name);
+ }
+ iconv_for_check = iconv;
+ }
+#endif
+}
+
+#ifdef X0212_ENABLE
+static nkf_char
+x0212_shift(nkf_char c)
+{
+ nkf_char ret = c;
+ c &= 0x7f;
+ if (is_eucg3(ret)){
+ if (0x75 <= c && c <= 0x7f){
+ ret = c + (0x109 - 0x75);
+ }
+ }else{
+ if (0x75 <= c && c <= 0x7f){
+ ret = c + (0x113 - 0x75);
+ }
+ }
+ return ret;
+}
+
+
+static nkf_char
+x0212_unshift(nkf_char c)
+{
+ nkf_char ret = c;
+ if (0x7f <= c && c <= 0x88){
+ ret = c + (0x75 - 0x7f);
+ }else if (0x89 <= c && c <= 0x92){
+ ret = PREFIX_EUCG3 | 0x80 | (c + (0x75 - 0x89));
+ }
+ return ret;
+}
+#endif /* X0212_ENABLE */
+
+static int
+is_x0213_2_in_x0212(nkf_char c1)
+{
+ static const char x0213_2_table[] =
+ {0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1};
+ int ku = c1 - 0x20;
+ if (ku <= 15)
+ return x0213_2_table[ku]; /* 1, 3-5, 8, 12-15 */
+ if (78 <= ku && ku <= 94)
+ return 1;
+ return 0;
+}
+
+static nkf_char
+e2s_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1)
+{
+ nkf_char ndx;
+ if (is_eucg3(c2)){
+ ndx = c2 & 0x7f;
+ if (x0213_f && is_x0213_2_in_x0212(ndx)){
+ if((0x21 <= ndx && ndx <= 0x2F)){
+ if (p2) *p2 = ((ndx - 1) >> 1) + 0xec - ndx / 8 * 3;
+ if (p1) *p1 = c1 + ((ndx & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e);
+ return 0;
+ }else if(0x6E <= ndx && ndx <= 0x7E){
+ if (p2) *p2 = ((ndx - 1) >> 1) + 0xbe;
+ if (p1) *p1 = c1 + ((ndx & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e);
+ return 0;
+ }
+ return 1;
+ }
+#ifdef X0212_ENABLE
+ else if(nkf_isgraph(ndx)){
+ nkf_char val = 0;
+ const unsigned short *ptr;
+ ptr = x0212_shiftjis[ndx - 0x21];
+ if (ptr){
+ val = ptr[(c1 & 0x7f) - 0x21];
+ }
+ if (val){
+ c2 = val >> 8;
+ c1 = val & 0xff;
+ if (p2) *p2 = c2;
+ if (p1) *p1 = c1;
+ return 0;
+ }
+ c2 = x0212_shift(c2);
+ }
+#endif /* X0212_ENABLE */
+ }
+ if(0x7F < c2) return 1;
+ if (p2) *p2 = ((c2 - 1) >> 1) + ((c2 <= 0x5e) ? 0x71 : 0xb1);
+ if (p1) *p1 = c1 + ((c2 & 1) ? ((c1 < 0x60) ? 0x1f : 0x20) : 0x7e);
+ return 0;
+}
+
+static nkf_char
+s2e_conv(nkf_char c2, nkf_char c1, nkf_char *p2, nkf_char *p1)
+{
+#if defined(SHIFTJIS_CP932) || defined(X0212_ENABLE)
+ nkf_char val;
+#endif
+ static const char shift_jisx0213_s1a3_table[5][2] ={ { 1, 8}, { 3, 4}, { 5,12}, {13,14}, {15, 0} };
+ if (0xFC < c1) return 1;
+#ifdef SHIFTJIS_CP932
+ if (!cp932inv_f && !x0213_f && is_ibmext_in_sjis(c2)){
+ val = shiftjis_cp932[c2 - CP932_TABLE_BEGIN][c1 - 0x40];
+ if (val){
+ c2 = val >> 8;
+ c1 = val & 0xff;
+ }
+ }
+ if (cp932inv_f
+ && CP932INV_TABLE_BEGIN <= c2 && c2 <= CP932INV_TABLE_END){
+ val = cp932inv[c2 - CP932INV_TABLE_BEGIN][c1 - 0x40];
+ if (val){
+ c2 = val >> 8;
+ c1 = val & 0xff;
+ }
+ }
+#endif /* SHIFTJIS_CP932 */
+#ifdef X0212_ENABLE
+ if (!x0213_f && is_ibmext_in_sjis(c2)){
+ val = shiftjis_x0212[c2 - 0xfa][c1 - 0x40];
+ if (val){
+ if (val > 0x7FFF){
+ c2 = PREFIX_EUCG3 | ((val >> 8) & 0x7f);
+ c1 = val & 0xff;
+ }else{
+ c2 = val >> 8;
+ c1 = val & 0xff;
+ }
+ if (p2) *p2 = c2;
+ if (p1) *p1 = c1;
+ return 0;
+ }
+ }
+#endif
+ if(c2 >= 0x80){
+ if(x0213_f && c2 >= 0xF0){
+ if(c2 <= 0xF3 || (c2 == 0xF4 && c1 < 0x9F)){ /* k=1, 3<=k<=5, k=8, 12<=k<=15 */
+ c2 = PREFIX_EUCG3 | 0x20 | shift_jisx0213_s1a3_table[c2 - 0xF0][0x9E < c1];
+ }else{ /* 78<=k<=94 */
+ c2 = PREFIX_EUCG3 | (c2 * 2 - 0x17B);
+ if (0x9E < c1) c2++;
+ }
+ }else{
+#define SJ0162 0x00e1 /* 01 - 62 ku offset */
+#define SJ6394 0x0161 /* 63 - 94 ku offset */
+ c2 = c2 + c2 - ((c2 <= 0x9F) ? SJ0162 : SJ6394);
+ if (0x9E < c1) c2++;
+ }
+ if (c1 < 0x9F)
+ c1 = c1 - ((c1 > DEL) ? SP : 0x1F);
+ else {
+ c1 = c1 - 0x7E;
+ }
+ }
+
+#ifdef X0212_ENABLE
+ c2 = x0212_unshift(c2);
+#endif
+ if (p2) *p2 = c2;
+ if (p1) *p1 = c1;
+ return 0;
+}
+
+#if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
+static void
+nkf_unicode_to_utf8(nkf_char val, nkf_char *p1, nkf_char *p2, nkf_char *p3, nkf_char *p4)
+{
+ val &= VALUE_MASK;
+ if (val < 0x80){
+ *p1 = val;
+ *p2 = 0;
+ *p3 = 0;
+ *p4 = 0;
+ }else if (val < 0x800){
+ *p1 = 0xc0 | (val >> 6);
+ *p2 = 0x80 | (val & 0x3f);
+ *p3 = 0;
+ *p4 = 0;
+ } else if (nkf_char_unicode_bmp_p(val)) {
+ *p1 = 0xe0 | (val >> 12);
+ *p2 = 0x80 | ((val >> 6) & 0x3f);
+ *p3 = 0x80 | ( val & 0x3f);
+ *p4 = 0;
+ } else if (nkf_char_unicode_value_p(val)) {
+ *p1 = 0xf0 | (val >> 18);
+ *p2 = 0x80 | ((val >> 12) & 0x3f);
+ *p3 = 0x80 | ((val >> 6) & 0x3f);
+ *p4 = 0x80 | ( val & 0x3f);
+ } else {
+ *p1 = 0;
+ *p2 = 0;
+ *p3 = 0;
+ *p4 = 0;
+ }
+}
+
+static nkf_char
+nkf_utf8_to_unicode(nkf_char c1, nkf_char c2, nkf_char c3, nkf_char c4)
+{
+ nkf_char wc;
+ if (c1 <= 0x7F) {
+ /* single byte */
+ wc = c1;
+ }
+ else if (c1 <= 0xC1) {
+ /* trail byte or invalid */
+ return -1;
+ }
+ else if (c1 <= 0xDF) {
+ /* 2 bytes */
+ wc = (c1 & 0x1F) << 6;
+ wc |= (c2 & 0x3F);
+ }
+ else if (c1 <= 0xEF) {
+ /* 3 bytes */
+ wc = (c1 & 0x0F) << 12;
+ wc |= (c2 & 0x3F) << 6;
+ wc |= (c3 & 0x3F);
+ }
+ else if (c2 <= 0xF4) {
+ /* 4 bytes */
+ wc = (c1 & 0x0F) << 18;
+ wc |= (c2 & 0x3F) << 12;
+ wc |= (c3 & 0x3F) << 6;
+ wc |= (c4 & 0x3F);
+ }
+ else {
+ return -1;
+ }
+ return wc;
+}
+#endif
+
+#ifdef UTF8_INPUT_ENABLE
+static int
+unicode_to_jis_common2(nkf_char c1, nkf_char c0,
+ const unsigned short *const *pp, nkf_char psize,
+ nkf_char *p2, nkf_char *p1)
+{
+ nkf_char c2;
+ const unsigned short *p;
+ unsigned short val;
+
+ if (pp == 0) return 1;
+
+ c1 -= 0x80;
+ if (c1 < 0 || psize <= c1) return 1;
+ p = pp[c1];
+ if (p == 0) return 1;
+
+ c0 -= 0x80;
+ if (c0 < 0 || sizeof_utf8_to_euc_C2 <= c0) return 1;
+ val = p[c0];
+ if (val == 0) return 1;
+ if (no_cp932ext_f && (
+ (val>>8) == 0x2D || /* NEC special characters */
+ val > NKF_INT32_C(0xF300) /* IBM extended characters */
+ )) return 1;
+
+ c2 = val >> 8;
+ if (val > 0x7FFF){
+ c2 &= 0x7f;
+ c2 |= PREFIX_EUCG3;
+ }
+ if (c2 == SO) c2 = JIS_X_0201_1976_K;
+ c1 = val & 0xFF;
+ if (p2) *p2 = c2;
+ if (p1) *p1 = c1;
+ return 0;
+}
+
+static int
+unicode_to_jis_common(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *p2, nkf_char *p1)
+{
+ const unsigned short *const *pp;
+ const unsigned short *const *const *ppp;
+ static const char no_best_fit_chars_table_C2[] =
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 2, 1, 1, 2,
+ 0, 0, 1, 1, 0, 1, 0, 1, 2, 1, 1, 1, 1, 1, 1, 1};
+ static const char no_best_fit_chars_table_C2_ms[] =
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0,
+ 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0};
+ static const char no_best_fit_chars_table_932_C2[] =
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0};
+ static const char no_best_fit_chars_table_932_C3[] =
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1};
+ nkf_char ret = 0;
+
+ if(c2 < 0x80){
+ *p2 = 0;
+ *p1 = c2;
+ }else if(c2 < 0xe0){
+ if(no_best_fit_chars_f){
+ if(ms_ucs_map_f == UCS_MAP_CP932){
+ switch(c2){
+ case 0xC2:
+ if(no_best_fit_chars_table_932_C2[c1&0x3F]) return 1;
+ break;
+ case 0xC3:
+ if(no_best_fit_chars_table_932_C3[c1&0x3F]) return 1;
+ break;
+ }
+ }else if(!cp932inv_f){
+ switch(c2){
+ case 0xC2:
+ if(no_best_fit_chars_table_C2[c1&0x3F]) return 1;
+ break;
+ case 0xC3:
+ if(no_best_fit_chars_table_932_C3[c1&0x3F]) return 1;
+ break;
+ }
+ }else if(ms_ucs_map_f == UCS_MAP_MS){
+ if(c2 == 0xC2 && no_best_fit_chars_table_C2_ms[c1&0x3F]) return 1;
+ }else if(ms_ucs_map_f == UCS_MAP_CP10001){
+ switch(c2){
+ case 0xC2:
+ switch(c1){
+ case 0xA2:
+ case 0xA3:
+ case 0xA5:
+ case 0xA6:
+ case 0xAC:
+ case 0xAF:
+ case 0xB8:
+ return 1;
+ }
+ break;
+ }
+ }
+ }
+ pp =
+ ms_ucs_map_f == UCS_MAP_CP932 ? utf8_to_euc_2bytes_932 :
+ ms_ucs_map_f == UCS_MAP_MS ? utf8_to_euc_2bytes_ms :
+ ms_ucs_map_f == UCS_MAP_CP10001 ? utf8_to_euc_2bytes_mac :
+ x0213_f ? utf8_to_euc_2bytes_x0213 :
+ utf8_to_euc_2bytes;
+ ret = unicode_to_jis_common2(c2, c1, pp, sizeof_utf8_to_euc_2bytes, p2, p1);
+ }else if(c0 < 0xF0){
+ if(no_best_fit_chars_f){
+ if(ms_ucs_map_f == UCS_MAP_CP932){
+ if(c2 == 0xE3 && c1 == 0x82 && c0 == 0x94) return 1;
+ }else if(ms_ucs_map_f == UCS_MAP_MS){
+ switch(c2){
+ case 0xE2:
+ switch(c1){
+ case 0x80:
+ if(c0 == 0x94 || c0 == 0x96 || c0 == 0xBE) return 1;
+ break;
+ case 0x88:
+ if(c0 == 0x92) return 1;
+ break;
+ }
+ break;
+ case 0xE3:
+ if(c1 == 0x80 || c0 == 0x9C) return 1;
+ break;
+ }
+ }else if(ms_ucs_map_f == UCS_MAP_CP10001){
+ switch(c2){
+ case 0xE3:
+ switch(c1){
+ case 0x82:
+ if(c0 == 0x94) return 1;
+ break;
+ case 0x83:
+ if(c0 == 0xBB) return 1;
+ break;
+ }
+ break;
+ }
+ }else{
+ switch(c2){
+ case 0xE2:
+ switch(c1){
+ case 0x80:
+ if(c0 == 0x95) return 1;
+ break;
+ case 0x88:
+ if(c0 == 0xA5) return 1;
+ break;
+ }
+ break;
+ case 0xEF:
+ switch(c1){
+ case 0xBC:
+ if(c0 == 0x8D) return 1;
+ break;
+ case 0xBD:
+ if(c0 == 0x9E && !cp932inv_f) return 1;
+ break;
+ case 0xBF:
+ if(0xA0 <= c0 && c0 <= 0xA5) return 1;
+ break;
+ }
+ break;
+ }
+ }
+ }
+ ppp =
+ ms_ucs_map_f == UCS_MAP_CP932 ? utf8_to_euc_3bytes_932 :
+ ms_ucs_map_f == UCS_MAP_MS ? utf8_to_euc_3bytes_ms :
+ ms_ucs_map_f == UCS_MAP_CP10001 ? utf8_to_euc_3bytes_mac :
+ x0213_f ? utf8_to_euc_3bytes_x0213 :
+ utf8_to_euc_3bytes;
+ ret = unicode_to_jis_common2(c1, c0, ppp[c2 - 0xE0], sizeof_utf8_to_euc_C2, p2, p1);
+ }else return -1;
+#ifdef SHIFTJIS_CP932
+ if (!ret&& is_eucg3(*p2)) {
+ if (cp932inv_f) {
+ if (encode_fallback) ret = 1;
+ }
+ else {
+ nkf_char s2, s1;
+ if (e2s_conv(*p2, *p1, &s2, &s1) == 0) {
+ s2e_conv(s2, s1, p2, p1);
+ }else{
+ ret = 1;
+ }
+ }
+ }
+#endif
+ return ret;
+}
+
+#ifdef UTF8_OUTPUT_ENABLE
+#define X0213_SURROGATE_FIND(tbl, size, euc) do { \
+ int i; \
+ for (i = 0; i < size; i++) \
+ if (tbl[i][0] == euc) { \
+ low = tbl[i][2]; \
+ break; \
+ } \
+ } while (0)
+
+static nkf_char
+e2w_conv(nkf_char c2, nkf_char c1)
+{
+ const unsigned short *p;
+
+ if (c2 == JIS_X_0201_1976_K) {
+ if (ms_ucs_map_f == UCS_MAP_CP10001) {
+ switch (c1) {
+ case 0x20:
+ return 0xA0;
+ case 0x7D:
+ return 0xA9;
+ }
+ }
+ p = euc_to_utf8_1byte;
+#ifdef X0212_ENABLE
+ } else if (is_eucg3(c2)){
+ if(ms_ucs_map_f == UCS_MAP_ASCII&& c2 == NKF_INT32_C(0x8F22) && c1 == 0x43){
+ return 0xA6;
+ }
+ c2 = (c2&0x7f) - 0x21;
+ if (0<=c2 && c2<sizeof_euc_to_utf8_2bytes)
+ p =
+ x0213_f ? x0212_to_utf8_2bytes_x0213[c2] :
+ x0212_to_utf8_2bytes[c2];
+ else
+ return 0;
+#endif
+ } else {
+ c2 &= 0x7f;
+ c2 = (c2&0x7f) - 0x21;
+ if (0<=c2 && c2<sizeof_euc_to_utf8_2bytes)
+ p =
+ x0213_f ? euc_to_utf8_2bytes_x0213[c2] :
+ ms_ucs_map_f == UCS_MAP_ASCII ? euc_to_utf8_2bytes[c2] :
+ ms_ucs_map_f == UCS_MAP_CP10001 ? euc_to_utf8_2bytes_mac[c2] :
+ euc_to_utf8_2bytes_ms[c2];
+ else
+ return 0;
+ }
+ if (!p) return 0;
+ c1 = (c1 & 0x7f) - 0x21;
+ if (0<=c1 && c1<sizeof_euc_to_utf8_1byte) {
+ nkf_char val = p[c1];
+ if (x0213_f && 0xD800<=val && val<=0xDBFF) {
+ nkf_char euc = (c2+0x21)<<8 | (c1+0x21);
+ nkf_char low = 0;
+ if (p==x0212_to_utf8_2bytes_x0213[c2]) {
+ X0213_SURROGATE_FIND(x0213_2_surrogate_table, sizeof_x0213_2_surrogate_table, euc);
+ } else {
+ X0213_SURROGATE_FIND(x0213_1_surrogate_table, sizeof_x0213_1_surrogate_table, euc);
+ }
+ if (!low) return 0;
+ return UTF16_TO_UTF32(val, low);
+ } else {
+ return val;
+ }
+ }
+ return 0;
+}
+
+static nkf_char
+e2w_combining(nkf_char comb, nkf_char c2, nkf_char c1)
+{
+ nkf_char euc;
+ int i;
+ for (i = 0; i < sizeof_x0213_combining_chars; i++)
+ if (x0213_combining_chars[i] == comb)
+ break;
+ if (i >= sizeof_x0213_combining_chars)
+ return 0;
+ euc = (c2&0x7f)<<8 | (c1&0x7f);
+ for (i = 0; i < sizeof_x0213_combining_table; i++)
+ if (x0213_combining_table[i][0] == euc)
+ return x0213_combining_table[i][1];
+ return 0;
+}
+#endif
+
+static nkf_char
+w2e_conv(nkf_char c2, nkf_char c1, nkf_char c0, nkf_char *p2, nkf_char *p1)
+{
+ nkf_char ret = 0;
+
+ if (!c1){
+ *p2 = 0;
+ *p1 = c2;
+ }else if (0xc0 <= c2 && c2 <= 0xef) {
+ ret = unicode_to_jis_common(c2, c1, c0, p2, p1);
+#ifdef NUMCHAR_OPTION
+ if (ret > 0){
+ if (p2) *p2 = 0;
+ if (p1) *p1 = nkf_char_unicode_new(nkf_utf8_to_unicode(c2, c1, c0, 0));
+ ret = 0;
+ }
+#endif
+ }
+ return ret;
+}
+
+#ifdef UTF8_INPUT_ENABLE
+static nkf_char
+w16e_conv(nkf_char val, nkf_char *p2, nkf_char *p1)
+{
+ nkf_char c1, c2, c3, c4;
+ nkf_char ret = 0;
+ val &= VALUE_MASK;
+ if (val < 0x80) {
+ *p2 = 0;
+ *p1 = val;
+ }
+ else if (nkf_char_unicode_bmp_p(val)){
+ nkf_unicode_to_utf8(val, &c1, &c2, &c3, &c4);
+ ret = unicode_to_jis_common(c1, c2, c3, p2, p1);
+ if (ret > 0){
+ *p2 = 0;
+ *p1 = nkf_char_unicode_new(val);
+ ret = 0;
+ }
+ }
+ else {
+ int i;
+ if (x0213_f) {
+ c1 = (val >> 10) + NKF_INT32_C(0xD7C0); /* high surrogate */
+ c2 = (val & 0x3FF) + NKF_INT32_C(0xDC00); /* low surrogate */
+ for (i = 0; i < sizeof_x0213_1_surrogate_table; i++)
+ if (x0213_1_surrogate_table[i][1] == c1 && x0213_1_surrogate_table[i][2] == c2) {
+ val = x0213_1_surrogate_table[i][0];
+ *p2 = val >> 8;
+ *p1 = val & 0xFF;
+ return 0;
+ }
+ for (i = 0; i < sizeof_x0213_2_surrogate_table; i++)
+ if (x0213_2_surrogate_table[i][1] == c1 && x0213_2_surrogate_table[i][2] == c2) {
+ val = x0213_2_surrogate_table[i][0];
+ *p2 = PREFIX_EUCG3 | (val >> 8);
+ *p1 = val & 0xFF;
+ return 0;
+ }
+ }
+ *p2 = 0;
+ *p1 = nkf_char_unicode_new(val);
+ }
+ return ret;
+}
+#endif
+
+static nkf_char
+e_iconv(nkf_char c2, nkf_char c1, nkf_char c0)
+{
+ if (c2 == JIS_X_0201_1976_K || c2 == SS2){
+ if (iso2022jp_f && !x0201_f) {
+ c2 = GETA1; c1 = GETA2;
+ } else {
+ c2 = JIS_X_0201_1976_K;
+ c1 &= 0x7f;
+ }
+#ifdef X0212_ENABLE
+ }else if (c2 == 0x8f){
+ if (c0 == 0){
+ return -1;
+ }
+ if (!cp51932_f && !x0213_f && 0xF5 <= c1 && c1 <= 0xFE && 0xA1 <= c0 && c0 <= 0xFE) {
+ /* encoding is eucJP-ms, so invert to Unicode Private User Area */
+ c1 = nkf_char_unicode_new((c1 - 0xF5) * 94 + c0 - 0xA1 + 0xE3AC);
+ c2 = 0;
+ } else {
+ c2 = (c2 << 8) | (c1 & 0x7f);
+ c1 = c0 & 0x7f;
+#ifdef SHIFTJIS_CP932
+ if (cp51932_f){
+ nkf_char s2, s1;
+ if (e2s_conv(c2, c1, &s2, &s1) == 0){
+ s2e_conv(s2, s1, &c2, &c1);
+ if (c2 < 0x100){
+ c1 &= 0x7f;
+ c2 &= 0x7f;
+ }
+ }
+ }
+#endif /* SHIFTJIS_CP932 */
+ }
+#endif /* X0212_ENABLE */
+ } else if ((c2 == EOF) || (c2 == 0) || c2 < SP || c2 == ISO_8859_1) {
+ /* NOP */
+ } else {
+ if (!cp51932_f && ms_ucs_map_f && 0xF5 <= c2 && c2 <= 0xFE && 0xA1 <= c1 && c1 <= 0xFE) {
+ /* encoding is eucJP-ms, so invert to Unicode Private User Area */
+ c1 = nkf_char_unicode_new((c2 - 0xF5) * 94 + c1 - 0xA1 + 0xE000);
+ c2 = 0;
+ } else {
+ c1 &= 0x7f;
+ c2 &= 0x7f;
+#ifdef SHIFTJIS_CP932
+ if (cp51932_f && 0x79 <= c2 && c2 <= 0x7c){
+ nkf_char s2, s1;
+ if (e2s_conv(c2, c1, &s2, &s1) == 0){
+ s2e_conv(s2, s1, &c2, &c1);
+ if (c2 < 0x100){
+ c1 &= 0x7f;
+ c2 &= 0x7f;
+ }
+ }
+ }
+#endif /* SHIFTJIS_CP932 */
+ }
+ }
+ (*oconv)(c2, c1);
+ return 0;
+}
+
+static nkf_char
+s_iconv(ARG_UNUSED nkf_char c2, nkf_char c1, ARG_UNUSED nkf_char c0)
+{
+ if (c2 == JIS_X_0201_1976_K || (0xA1 <= c2 && c2 <= 0xDF)) {
+ if (iso2022jp_f && !x0201_f) {
+ c2 = GETA1; c1 = GETA2;
+ } else {
+ c1 &= 0x7f;
+ }
+ } else if ((c2 == EOF) || (c2 == 0) || c2 < SP) {
+ /* NOP */
+ } else if (!x0213_f && 0xF0 <= c2 && c2 <= 0xF9 && 0x40 <= c1 && c1 <= 0xFC) {
+ /* CP932 UDC */
+ if(c1 == 0x7F) return 0;
+ c1 = nkf_char_unicode_new((c2 - 0xF0) * 188 + (c1 - 0x40 - (0x7E < c1)) + 0xE000);
+ c2 = 0;
+ } else {
+ nkf_char ret = s2e_conv(c2, c1, &c2, &c1);
+ if (ret) return ret;
+ }
+ (*oconv)(c2, c1);
+ return 0;
+}
+
+static int
+x0213_wait_combining_p(nkf_char wc)
+{
+ int i;
+ for (i = 0; i < sizeof_x0213_combining_table; i++) {
+ if (x0213_combining_table[i][1] == wc) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static int
+x0213_combining_p(nkf_char wc)
+{
+ int i;
+ for (i = 0; i < sizeof_x0213_combining_chars; i++) {
+ if (x0213_combining_chars[i] == wc) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static nkf_char
+w_iconv(nkf_char c1, nkf_char c2, nkf_char c3)
+{
+ nkf_char ret = 0, c4 = 0;
+ static const char w_iconv_utf8_1st_byte[] =
+ { /* 0xC0 - 0xFF */
+ 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 33,
+ 40, 41, 41, 41, 42, 43, 43, 43, 50, 50, 50, 50, 60, 60, 70, 70};
+
+ if (c3 > 0xFF) {
+ c4 = c3 & 0xFF;
+ c3 >>= 8;
+ }
+
+ if (c1 < 0 || 0xff < c1) {
+ }else if (c1 == 0) { /* 0 : 1 byte*/
+ c3 = 0;
+ } else if ((c1 & 0xC0) == 0x80) { /* 0x80-0xbf : trail byte */
+ return 0;
+ } else{
+ switch (w_iconv_utf8_1st_byte[c1 - 0xC0]) {
+ case 21:
+ if (c2 < 0x80 || 0xBF < c2) return 0;
+ break;
+ case 30:
+ if (c3 == 0) return -1;
+ if (c2 < 0xA0 || 0xBF < c2 || (c3 & 0xC0) != 0x80)
+ return 0;
+ break;
+ case 31:
+ case 33:
+ if (c3 == 0) return -1;
+ if ((c2 & 0xC0) != 0x80 || (c3 & 0xC0) != 0x80)
+ return 0;
+ break;
+ case 32:
+ if (c3 == 0) return -1;
+ if (c2 < 0x80 || 0x9F < c2 || (c3 & 0xC0) != 0x80)
+ return 0;
+ break;
+ case 40:
+ if (c3 == 0) return -2;
+ if (c2 < 0x90 || 0xBF < c2 || (c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
+ return 0;
+ break;
+ case 41:
+ if (c3 == 0) return -2;
+ if (c2 < 0x80 || 0xBF < c2 || (c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
+ return 0;
+ break;
+ case 42:
+ if (c3 == 0) return -2;
+ if (c2 < 0x80 || 0x8F < c2 || (c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
+ return 0;
+ break;
+ default:
+ return 0;
+ break;
+ }
+ }
+ if (c1 == 0 || c1 == EOF){
+ } else if ((c1 & 0xf8) == 0xf0) { /* 4 bytes */
+ c2 = nkf_char_unicode_new(nkf_utf8_to_unicode(c1, c2, c3, c4));
+ c1 = 0;
+ } else {
+ if (x0213_f && x0213_wait_combining_p(nkf_utf8_to_unicode(c1, c2, c3, c4)))
+ return -3;
+ ret = w2e_conv(c1, c2, c3, &c1, &c2);
+ }
+ if (ret == 0){
+ (*oconv)(c1, c2);
+ }
+ return ret;
+}
+
+static nkf_char
+w_iconv_nocombine(nkf_char c1, nkf_char c2, nkf_char c3)
+{
+ /* continue from the line below 'return -3;' in w_iconv() */
+ nkf_char ret = w2e_conv(c1, c2, c3, &c1, &c2);
+ if (ret == 0){
+ (*oconv)(c1, c2);
+ }
+ return ret;
+}
+
+#define NKF_ICONV_INVALID_CODE_RANGE -13
+#define NKF_ICONV_WAIT_COMBINING_CHAR -14
+#define NKF_ICONV_NOT_COMBINED -15
+static size_t
+unicode_iconv(nkf_char wc, int nocombine)
+{
+ nkf_char c1, c2;
+ int ret = 0;
+
+ if (wc < 0x80) {
+ c2 = 0;
+ c1 = wc;
+ }else if ((wc>>11) == 27) {
+ /* unpaired surrogate */
+ return NKF_ICONV_INVALID_CODE_RANGE;
+ }else if (wc < 0xFFFF) {
+ if (!nocombine && x0213_f && x0213_wait_combining_p(wc))
+ return NKF_ICONV_WAIT_COMBINING_CHAR;
+ ret = w16e_conv(wc, &c2, &c1);
+ if (ret) return ret;
+ }else if (wc < 0x10FFFF) {
+ c2 = 0;
+ c1 = nkf_char_unicode_new(wc);
+ } else {
+ return NKF_ICONV_INVALID_CODE_RANGE;
+ }
+ (*oconv)(c2, c1);
+ return 0;
+}
+
+static nkf_char
+unicode_iconv_combine(nkf_char wc, nkf_char wc2)
+{
+ nkf_char c1, c2;
+ int i;
+
+ if (wc2 < 0x80) {
+ return NKF_ICONV_NOT_COMBINED;
+ }else if ((wc2>>11) == 27) {
+ /* unpaired surrogate */
+ return NKF_ICONV_INVALID_CODE_RANGE;
+ }else if (wc2 < 0xFFFF) {
+ if (!x0213_combining_p(wc2))
+ return NKF_ICONV_NOT_COMBINED;
+ for (i = 0; i < sizeof_x0213_combining_table; i++) {
+ if (x0213_combining_table[i][1] == wc &&
+ x0213_combining_table[i][2] == wc2) {
+ c2 = x0213_combining_table[i][0] >> 8;
+ c1 = x0213_combining_table[i][0] & 0x7f;
+ (*oconv)(c2, c1);
+ return 0;
+ }
+ }
+ }else if (wc2 < 0x10FFFF) {
+ return NKF_ICONV_NOT_COMBINED;
+ } else {
+ return NKF_ICONV_INVALID_CODE_RANGE;
+ }
+ return NKF_ICONV_NOT_COMBINED;
+}
+
+static nkf_char
+w_iconv_combine(nkf_char c1, nkf_char c2, nkf_char c3, nkf_char c4, nkf_char c5, nkf_char c6)
+{
+ nkf_char wc, wc2;
+ wc = nkf_utf8_to_unicode(c1, c2, c3, 0);
+ wc2 = nkf_utf8_to_unicode(c4, c5, c6, 0);
+ if (wc2 < 0)
+ return wc2;
+ return unicode_iconv_combine(wc, wc2);
+}
+
+#define NKF_ICONV_NEED_ONE_MORE_BYTE (size_t)-1
+#define NKF_ICONV_NEED_TWO_MORE_BYTES (size_t)-2
+static size_t
+nkf_iconv_utf_16(nkf_char c1, nkf_char c2, nkf_char c3, nkf_char c4)
+{
+ nkf_char wc;
+
+ if (c1 == EOF) {
+ (*oconv)(EOF, 0);
+ return 0;
+ }
+
+ if (input_endian == ENDIAN_BIG) {
+ if (0xD8 <= c1 && c1 <= 0xDB) {
+ if (0xDC <= c3 && c3 <= 0xDF) {
+ wc = UTF16_TO_UTF32(c1 << 8 | c2, c3 << 8 | c4);
+ } else return NKF_ICONV_NEED_TWO_MORE_BYTES;
+ } else {
+ wc = c1 << 8 | c2;
+ }
+ } else {
+ if (0xD8 <= c2 && c2 <= 0xDB) {
+ if (0xDC <= c4 && c4 <= 0xDF) {
+ wc = UTF16_TO_UTF32(c2 << 8 | c1, c4 << 8 | c3);
+ } else return NKF_ICONV_NEED_TWO_MORE_BYTES;
+ } else {
+ wc = c2 << 8 | c1;
+ }
+ }
+
+ return (*unicode_iconv)(wc, FALSE);
+}
+
+static size_t
+nkf_iconv_utf_16_combine(nkf_char c1, nkf_char c2, nkf_char c3, nkf_char c4)
+{
+ nkf_char wc, wc2;
+
+ if (input_endian == ENDIAN_BIG) {
+ if (0xD8 <= c3 && c3 <= 0xDB) {
+ return NKF_ICONV_NOT_COMBINED;
+ } else {
+ wc = c1 << 8 | c2;
+ wc2 = c3 << 8 | c4;
+ }
+ } else {
+ if (0xD8 <= c2 && c2 <= 0xDB) {
+ return NKF_ICONV_NOT_COMBINED;
+ } else {
+ wc = c2 << 8 | c1;
+ wc2 = c4 << 8 | c3;
+ }
+ }
+
+ return unicode_iconv_combine(wc, wc2);
+}
+
+static size_t
+nkf_iconv_utf_16_nocombine(nkf_char c1, nkf_char c2)
+{
+ nkf_char wc;
+ if (input_endian == ENDIAN_BIG)
+ wc = c1 << 8 | c2;
+ else
+ wc = c2 << 8 | c1;
+ return (*unicode_iconv)(wc, TRUE);
+}
+
+static nkf_char
+w_iconv16(nkf_char c2, nkf_char c1, ARG_UNUSED nkf_char c0)
+{
+ (*oconv)(c2, c1);
+ return 16; /* different from w_iconv32 */
+}
+
+static nkf_char
+w_iconv32(nkf_char c2, nkf_char c1, ARG_UNUSED nkf_char c0)
+{
+ (*oconv)(c2, c1);
+ return 32; /* different from w_iconv16 */
+}
+
+static nkf_char
+utf32_to_nkf_char(nkf_char c1, nkf_char c2, nkf_char c3, nkf_char c4)
+{
+ nkf_char wc;
+
+ switch(input_endian){
+ case ENDIAN_BIG:
+ wc = c2 << 16 | c3 << 8 | c4;
+ break;
+ case ENDIAN_LITTLE:
+ wc = c3 << 16 | c2 << 8 | c1;
+ break;
+ case ENDIAN_2143:
+ wc = c1 << 16 | c4 << 8 | c3;
+ break;
+ case ENDIAN_3412:
+ wc = c4 << 16 | c1 << 8 | c2;
+ break;
+ default:
+ return NKF_ICONV_INVALID_CODE_RANGE;
+ }
+ return wc;
+}
+
+static size_t
+nkf_iconv_utf_32(nkf_char c1, nkf_char c2, nkf_char c3, nkf_char c4)
+{
+ nkf_char wc;
+
+ if (c1 == EOF) {
+ (*oconv)(EOF, 0);
+ return 0;
+ }
+
+ wc = utf32_to_nkf_char(c1, c2, c3, c4);
+ if (wc < 0)
+ return wc;
+
+ return (*unicode_iconv)(wc, FALSE);
+}
+
+static nkf_char
+nkf_iconv_utf_32_combine(nkf_char c1, nkf_char c2, nkf_char c3, nkf_char c4, nkf_char c5, nkf_char c6, nkf_char c7, nkf_char c8)
+{
+ nkf_char wc, wc2;
+
+ wc = utf32_to_nkf_char(c1, c2, c3, c4);
+ if (wc < 0)
+ return wc;
+ wc2 = utf32_to_nkf_char(c5, c6, c7, c8);
+ if (wc2 < 0)
+ return wc2;
+
+ return unicode_iconv_combine(wc, wc2);
+}
+
+static size_t
+nkf_iconv_utf_32_nocombine(nkf_char c1, nkf_char c2, nkf_char c3, nkf_char c4)
+{
+ nkf_char wc;
+
+ wc = utf32_to_nkf_char(c1, c2, c3, c4);
+ return (*unicode_iconv)(wc, TRUE);
+}
+#endif
+
+#define output_ascii_escape_sequence(mode) do { \
+ if (output_mode != ASCII && output_mode != ISO_8859_1) { \
+ (*o_putc)(ESC); \
+ (*o_putc)('('); \
+ (*o_putc)(ascii_intro); \
+ output_mode = mode; \
+ } \
+ } while (0)
+
+static void
+output_escape_sequence(int mode)
+{
+ if (output_mode == mode)
+ return;
+ switch(mode) {
+ case ISO_8859_1:
+ (*o_putc)(ESC);
+ (*o_putc)('.');
+ (*o_putc)('A');
+ break;
+ case JIS_X_0201_1976_K:
+ (*o_putc)(ESC);
+ (*o_putc)('(');
+ (*o_putc)('I');
+ break;
+ case JIS_X_0208:
+ (*o_putc)(ESC);
+ (*o_putc)('$');
+ (*o_putc)(kanji_intro);
+ break;
+ case JIS_X_0212:
+ (*o_putc)(ESC);
+ (*o_putc)('$');
+ (*o_putc)('(');
+ (*o_putc)('D');
+ break;
+ case JIS_X_0213_1:
+ (*o_putc)(ESC);
+ (*o_putc)('$');
+ (*o_putc)('(');
+ (*o_putc)('Q');
+ break;
+ case JIS_X_0213_2:
+ (*o_putc)(ESC);
+ (*o_putc)('$');
+ (*o_putc)('(');
+ (*o_putc)('P');
+ break;
+ }
+ output_mode = mode;
+}
+
+static void
+j_oconv(nkf_char c2, nkf_char c1)
+{
+#ifdef NUMCHAR_OPTION
+ if (c2 == 0 && nkf_char_unicode_p(c1)){
+ w16e_conv(c1, &c2, &c1);
+ if (c2 == 0 && nkf_char_unicode_p(c1)){
+ c2 = c1 & VALUE_MASK;
+ if (ms_ucs_map_f && 0xE000 <= c2 && c2 <= 0xE757) {
+ /* CP5022x UDC */
+ c1 &= 0xFFF;
+ c2 = 0x7F + c1 / 94;
+ c1 = 0x21 + c1 % 94;
+ } else {
+ if (encode_fallback) (*encode_fallback)(c1);
+ return;
+ }
+ }
+ }
+#endif
+ if (c2 == 0) {
+ output_ascii_escape_sequence(ASCII);
+ (*o_putc)(c1);
+ }
+ else if (c2 == EOF) {
+ output_ascii_escape_sequence(ASCII);
+ (*o_putc)(EOF);
+ }
+ else if (c2 == ISO_8859_1) {
+ output_ascii_escape_sequence(ISO_8859_1);
+ (*o_putc)(c1|0x80);
+ }
+ else if (c2 == JIS_X_0201_1976_K) {
+ output_escape_sequence(JIS_X_0201_1976_K);
+ (*o_putc)(c1);
+#ifdef X0212_ENABLE
+ } else if (is_eucg3(c2)){
+ output_escape_sequence(x0213_f ? JIS_X_0213_2 : JIS_X_0212);
+ (*o_putc)(c2 & 0x7f);
+ (*o_putc)(c1);
+#endif
+ } else {
+ if(ms_ucs_map_f
+ ? c2<0x20 || 0x92<c2 || c1<0x20 || 0x7e<c1
+ : c2<0x20 || 0x7e<c2 || c1<0x20 || 0x7e<c1) return;
+ output_escape_sequence(x0213_f ? JIS_X_0213_1 : JIS_X_0208);
+ (*o_putc)(c2);
+ (*o_putc)(c1);
+ }
+}
+
+static void
+e_oconv(nkf_char c2, nkf_char c1)
+{
+ if (c2 == 0 && nkf_char_unicode_p(c1)){
+ w16e_conv(c1, &c2, &c1);
+ if (c2 == 0 && nkf_char_unicode_p(c1)){
+ c2 = c1 & VALUE_MASK;
+ if (x0212_f && 0xE000 <= c2 && c2 <= 0xE757) {
+ /* eucJP-ms UDC */
+ c1 &= 0xFFF;
+ c2 = c1 / 94;
+ c2 += c2 < 10 ? 0x75 : 0x8FEB;
+ c1 = 0x21 + c1 % 94;
+ if (is_eucg3(c2)){
+ (*o_putc)(0x8f);
+ (*o_putc)((c2 & 0x7f) | 0x080);
+ (*o_putc)(c1 | 0x080);
+ }else{
+ (*o_putc)((c2 & 0x7f) | 0x080);
+ (*o_putc)(c1 | 0x080);
+ }
+ return;
+ } else {
+ if (encode_fallback) (*encode_fallback)(c1);
+ return;
+ }
+ }
+ }
+
+ if (c2 == EOF) {
+ (*o_putc)(EOF);
+ } else if (c2 == 0) {
+ output_mode = ASCII;
+ (*o_putc)(c1);
+ } else if (c2 == JIS_X_0201_1976_K) {
+ output_mode = EUC_JP;
+ (*o_putc)(SS2); (*o_putc)(c1|0x80);
+ } else if (c2 == ISO_8859_1) {
+ output_mode = ISO_8859_1;
+ (*o_putc)(c1 | 0x080);
+#ifdef X0212_ENABLE
+ } else if (is_eucg3(c2)){
+ output_mode = EUC_JP;
+#ifdef SHIFTJIS_CP932
+ if (!cp932inv_f){
+ nkf_char s2, s1;
+ if (e2s_conv(c2, c1, &s2, &s1) == 0){
+ s2e_conv(s2, s1, &c2, &c1);
+ }
+ }
+#endif
+ if (c2 == 0) {
+ output_mode = ASCII;
+ (*o_putc)(c1);
+ }else if (is_eucg3(c2)){
+ if (x0212_f){
+ (*o_putc)(0x8f);
+ (*o_putc)((c2 & 0x7f) | 0x080);
+ (*o_putc)(c1 | 0x080);
+ }
+ }else{
+ (*o_putc)((c2 & 0x7f) | 0x080);
+ (*o_putc)(c1 | 0x080);
+ }
+#endif
+ } else {
+ if (!nkf_isgraph(c1) || !nkf_isgraph(c2)) {
+ set_iconv(FALSE, 0);
+ return; /* too late to rescue this char */
+ }
+ output_mode = EUC_JP;
+ (*o_putc)(c2 | 0x080);
+ (*o_putc)(c1 | 0x080);
+ }
+}
+
+static void
+s_oconv(nkf_char c2, nkf_char c1)
+{
+#ifdef NUMCHAR_OPTION
+ if (c2 == 0 && nkf_char_unicode_p(c1)){
+ w16e_conv(c1, &c2, &c1);
+ if (c2 == 0 && nkf_char_unicode_p(c1)){
+ c2 = c1 & VALUE_MASK;
+ if (!x0213_f && 0xE000 <= c2 && c2 <= 0xE757) {
+ /* CP932 UDC */
+ c1 &= 0xFFF;
+ c2 = c1 / 188 + (cp932inv_f ? 0xF0 : 0xEB);
+ c1 = c1 % 188;
+ c1 += 0x40 + (c1 > 0x3e);
+ (*o_putc)(c2);
+ (*o_putc)(c1);
+ return;
+ } else {
+ if(encode_fallback)(*encode_fallback)(c1);
+ return;
+ }
+ }
+ }
+#endif
+ if (c2 == EOF) {
+ (*o_putc)(EOF);
+ return;
+ } else if (c2 == 0) {
+ output_mode = ASCII;
+ (*o_putc)(c1);
+ } else if (c2 == JIS_X_0201_1976_K) {
+ output_mode = SHIFT_JIS;
+ (*o_putc)(c1|0x80);
+ } else if (c2 == ISO_8859_1) {
+ output_mode = ISO_8859_1;
+ (*o_putc)(c1 | 0x080);
+#ifdef X0212_ENABLE
+ } else if (is_eucg3(c2)){
+ output_mode = SHIFT_JIS;
+ if (e2s_conv(c2, c1, &c2, &c1) == 0){
+ (*o_putc)(c2);
+ (*o_putc)(c1);
+ }
+#endif
+ } else {
+ if (!nkf_isprint(c1) || !nkf_isprint(c2)) {
+ set_iconv(FALSE, 0);
+ return; /* too late to rescue this char */
+ }
+ output_mode = SHIFT_JIS;
+ e2s_conv(c2, c1, &c2, &c1);
+
+#ifdef SHIFTJIS_CP932
+ if (cp932inv_f
+ && CP932INV_TABLE_BEGIN <= c2 && c2 <= CP932INV_TABLE_END){
+ nkf_char c = cp932inv[c2 - CP932INV_TABLE_BEGIN][c1 - 0x40];
+ if (c){
+ c2 = c >> 8;
+ c1 = c & 0xff;
+ }
+ }
+#endif /* SHIFTJIS_CP932 */
+
+ (*o_putc)(c2);
+ if (prefix_table[(unsigned char)c1]){
+ (*o_putc)(prefix_table[(unsigned char)c1]);
+ }
+ (*o_putc)(c1);
+ }
+}
+
+#ifdef UTF8_OUTPUT_ENABLE
+#define OUTPUT_UTF8(val) do { \
+ nkf_unicode_to_utf8(val, &c1, &c2, &c3, &c4); \
+ (*o_putc)(c1); \
+ if (c2) (*o_putc)(c2); \
+ if (c3) (*o_putc)(c3); \
+ if (c4) (*o_putc)(c4); \
+ } while (0)
+
+static void
+w_oconv(nkf_char c2, nkf_char c1)
+{
+ nkf_char c3, c4;
+ nkf_char val, val2;
+
+ if (output_bom_f) {
+ output_bom_f = FALSE;
+ (*o_putc)('\357');
+ (*o_putc)('\273');
+ (*o_putc)('\277');
+ }
+
+ if (c2 == EOF) {
+ (*o_putc)(EOF);
+ return;
+ }
+
+ if (c2 == 0 && nkf_char_unicode_p(c1)){
+ val = c1 & VALUE_MASK;
+ OUTPUT_UTF8(val);
+ return;
+ }
+
+ if (c2 == 0) {
+ (*o_putc)(c1);
+ } else {
+ val = e2w_conv(c2, c1);
+ if (val){
+ val2 = e2w_combining(val, c2, c1);
+ if (val2)
+ OUTPUT_UTF8(val2);
+ OUTPUT_UTF8(val);
+ }
+ }
+}
+
+#define OUTPUT_UTF16_BYTES(c1, c2) do { \
+ if (output_endian == ENDIAN_LITTLE){ \
+ (*o_putc)(c1); \
+ (*o_putc)(c2); \
+ }else{ \
+ (*o_putc)(c2); \
+ (*o_putc)(c1); \
+ } \
+ } while (0)
+
+#define OUTPUT_UTF16(val) do { \
+ if (nkf_char_unicode_bmp_p(val)) { \
+ c2 = (val >> 8) & 0xff; \
+ c1 = val & 0xff; \
+ OUTPUT_UTF16_BYTES(c1, c2); \
+ } else { \
+ val &= VALUE_MASK; \
+ if (val <= UNICODE_MAX) { \
+ c2 = (val >> 10) + NKF_INT32_C(0xD7C0); /* high surrogate */ \
+ c1 = (val & 0x3FF) + NKF_INT32_C(0xDC00); /* low surrogate */ \
+ OUTPUT_UTF16_BYTES(c2 & 0xff, (c2 >> 8) & 0xff); \
+ OUTPUT_UTF16_BYTES(c1 & 0xff, (c1 >> 8) & 0xff); \
+ } \
+ } \
+ } while (0)
+
+static void
+w_oconv16(nkf_char c2, nkf_char c1)
+{
+ if (output_bom_f) {
+ output_bom_f = FALSE;
+ OUTPUT_UTF16_BYTES(0xFF, 0xFE);
+ }
+
+ if (c2 == EOF) {
+ (*o_putc)(EOF);
+ return;
+ }
+
+ if (c2 == 0 && nkf_char_unicode_p(c1)) {
+ OUTPUT_UTF16(c1);
+ } else if (c2) {
+ nkf_char val, val2;
+ val = e2w_conv(c2, c1);
+ if (!val) return;
+ val2 = e2w_combining(val, c2, c1);
+ if (val2)
+ OUTPUT_UTF16(val2);
+ OUTPUT_UTF16(val);
+ } else {
+ OUTPUT_UTF16_BYTES(c1, c2);
+ }
+}
+
+#define OUTPUT_UTF32(c) do { \
+ if (output_endian == ENDIAN_LITTLE){ \
+ (*o_putc)( (c) & 0xFF); \
+ (*o_putc)(((c) >> 8) & 0xFF); \
+ (*o_putc)(((c) >> 16) & 0xFF); \
+ (*o_putc)(0); \
+ }else{ \
+ (*o_putc)(0); \
+ (*o_putc)(((c) >> 16) & 0xFF); \
+ (*o_putc)(((c) >> 8) & 0xFF); \
+ (*o_putc)( (c) & 0xFF); \
+ } \
+ } while (0)
+
+static void
+w_oconv32(nkf_char c2, nkf_char c1)
+{
+ if (output_bom_f) {
+ output_bom_f = FALSE;
+ if (output_endian == ENDIAN_LITTLE){
+ (*o_putc)(0xFF);
+ (*o_putc)(0xFE);
+ (*o_putc)(0);
+ (*o_putc)(0);
+ }else{
+ (*o_putc)(0);
+ (*o_putc)(0);
+ (*o_putc)(0xFE);
+ (*o_putc)(0xFF);
+ }
+ }
+
+ if (c2 == EOF) {
+ (*o_putc)(EOF);
+ return;
+ }
+
+ if (c2 == ISO_8859_1) {
+ c1 |= 0x80;
+ } else if (c2 == 0 && nkf_char_unicode_p(c1)) {
+ c1 &= VALUE_MASK;
+ } else if (c2) {
+ nkf_char val, val2;
+ val = e2w_conv(c2, c1);
+ if (!val) return;
+ val2 = e2w_combining(val, c2, c1);
+ if (val2)
+ OUTPUT_UTF32(val2);
+ c1 = val;
+ }
+ OUTPUT_UTF32(c1);
+}
+#endif
+
+#define SCORE_L2 (1) /* Kanji Level 2 */
+#define SCORE_KANA (SCORE_L2 << 1) /* Halfwidth Katakana */
+#define SCORE_DEPEND (SCORE_KANA << 1) /* MD Characters */
+#define SCORE_CP932 (SCORE_DEPEND << 1) /* IBM extended characters */
+#define SCORE_X0212 (SCORE_CP932 << 1) /* JIS X 0212 */
+#define SCORE_X0213 (SCORE_X0212 << 1) /* JIS X 0213 */
+#define SCORE_NO_EXIST (SCORE_X0213 << 1) /* Undefined Characters */
+#define SCORE_iMIME (SCORE_NO_EXIST << 1) /* MIME selected */
+#define SCORE_ERROR (SCORE_iMIME << 1) /* Error */
+
+#define SCORE_INIT (SCORE_iMIME)
+
+static const nkf_char score_table_A0[] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND,
+ SCORE_DEPEND, SCORE_DEPEND, SCORE_DEPEND, SCORE_X0213,
+};
+
+static const nkf_char score_table_F0[] = {
+ SCORE_L2, SCORE_L2, SCORE_L2, SCORE_L2,
+ SCORE_L2, SCORE_DEPEND, SCORE_X0213, SCORE_X0213,
+ SCORE_DEPEND, SCORE_DEPEND, SCORE_CP932, SCORE_CP932,
+ SCORE_CP932, SCORE_X0213, SCORE_X0213, SCORE_ERROR,
+};
+
+static const nkf_char score_table_8FA0[] = {
+ 0, SCORE_X0213, SCORE_X0212, SCORE_X0213,
+ SCORE_X0213, SCORE_X0213, SCORE_X0212, SCORE_X0212,
+ SCORE_X0213, SCORE_X0212, SCORE_X0212, SCORE_X0212,
+ SCORE_X0213, SCORE_X0213, SCORE_X0213, SCORE_X0213,
+};
+
+static const nkf_char score_table_8FE0[] = {
+ SCORE_X0212, SCORE_X0212, SCORE_X0212, SCORE_X0212,
+ SCORE_X0212, SCORE_X0212, SCORE_X0212, SCORE_X0212,
+ SCORE_X0212, SCORE_X0212, SCORE_X0212, SCORE_X0212,
+ SCORE_X0212, SCORE_X0212, SCORE_X0213, SCORE_X0213,
+};
+
+static const nkf_char score_table_8FF0[] = {
+ SCORE_X0213, SCORE_X0213, SCORE_X0213, SCORE_X0212,
+ SCORE_X0212, SCORE_X0213, SCORE_X0213, SCORE_X0213,
+ SCORE_X0213, SCORE_X0213, SCORE_X0213, SCORE_X0213,
+ SCORE_X0213, SCORE_X0213, SCORE_X0213, SCORE_X0213,
+};
+
+static void
+set_code_score(struct input_code *ptr, nkf_char score)
+{
+ if (ptr){
+ ptr->score |= score;
+ }
+}
+
+static void
+clr_code_score(struct input_code *ptr, nkf_char score)
+{
+ if (ptr){
+ ptr->score &= ~score;
+ }
+}
+
+static void
+code_score(struct input_code *ptr)
+{
+ nkf_char c2 = ptr->buf[0];
+ nkf_char c1 = ptr->buf[1];
+ if (c2 < 0){
+ set_code_score(ptr, SCORE_ERROR);
+ }else if (c2 == SS2){
+ set_code_score(ptr, SCORE_KANA);
+ }else if (c2 == 0x8f){
+ if ((c1 & 0x70) == 0x20){
+ set_code_score(ptr, score_table_8FA0[c1 & 0x0f]);
+ }else if ((c1 & 0x70) == 0x60){
+ set_code_score(ptr, score_table_8FE0[c1 & 0x0f]);
+ }else if ((c1 & 0x70) == 0x70){
+ set_code_score(ptr, score_table_8FF0[c1 & 0x0f]);
+ }else{
+ set_code_score(ptr, SCORE_X0212);
+ }
+#ifdef UTF8_OUTPUT_ENABLE
+ }else if (!e2w_conv(c2, c1)){
+ set_code_score(ptr, SCORE_NO_EXIST);
+#endif
+ }else if ((c2 & 0x70) == 0x20){
+ set_code_score(ptr, score_table_A0[c2 & 0x0f]);
+ }else if ((c2 & 0x70) == 0x70){
+ set_code_score(ptr, score_table_F0[c2 & 0x0f]);
+ }else if ((c2 & 0x70) >= 0x50){
+ set_code_score(ptr, SCORE_L2);
+ }
+}
+
+static void
+status_disable(struct input_code *ptr)
+{
+ ptr->stat = -1;
+ ptr->buf[0] = -1;
+ code_score(ptr);
+ if (iconv == ptr->iconv_func) set_iconv(FALSE, 0);
+}
+
+static void
+status_push_ch(struct input_code *ptr, nkf_char c)
+{
+ ptr->buf[ptr->index++] = c;
+}
+
+static void
+status_clear(struct input_code *ptr)
+{
+ ptr->stat = 0;
+ ptr->index = 0;
+}
+
+static void
+status_reset(struct input_code *ptr)
+{
+ status_clear(ptr);
+ ptr->score = SCORE_INIT;
+}
+
+static void
+status_reinit(struct input_code *ptr)
+{
+ status_reset(ptr);
+ ptr->_file_stat = 0;
+}
+
+static void
+status_check(struct input_code *ptr, nkf_char c)
+{
+ if (c <= DEL && estab_f){
+ status_reset(ptr);
+ }
+}
+
+static void
+s_status(struct input_code *ptr, nkf_char c)
+{
+ switch(ptr->stat){
+ case -1:
+ status_check(ptr, c);
+ break;
+ case 0:
+ if (c <= DEL){
+ break;
+ }else if (nkf_char_unicode_p(c)){
+ break;
+ }else if (0xa1 <= c && c <= 0xdf){
+ status_push_ch(ptr, SS2);
+ status_push_ch(ptr, c);
+ code_score(ptr);
+ status_clear(ptr);
+ }else if ((0x81 <= c && c < 0xa0) || (0xe0 <= c && c <= 0xea)){
+ ptr->stat = 1;
+ status_push_ch(ptr, c);
+ }else if (0xed <= c && c <= 0xee){
+ ptr->stat = 3;
+ status_push_ch(ptr, c);
+#ifdef SHIFTJIS_CP932
+ }else if (is_ibmext_in_sjis(c)){
+ ptr->stat = 2;
+ status_push_ch(ptr, c);
+#endif /* SHIFTJIS_CP932 */
+#ifdef X0212_ENABLE
+ }else if (0xf0 <= c && c <= 0xfc){
+ ptr->stat = 1;
+ status_push_ch(ptr, c);
+#endif /* X0212_ENABLE */
+ }else{
+ status_disable(ptr);
+ }
+ break;
+ case 1:
+ if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){
+ status_push_ch(ptr, c);
+ s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]);
+ code_score(ptr);
+ status_clear(ptr);
+ }else{
+ status_disable(ptr);
+ }
+ break;
+ case 2:
+#ifdef SHIFTJIS_CP932
+ if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)) {
+ status_push_ch(ptr, c);
+ if (s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]) == 0) {
+ set_code_score(ptr, SCORE_CP932);
+ status_clear(ptr);
+ break;
+ }
+ }
+#endif /* SHIFTJIS_CP932 */
+ status_disable(ptr);
+ break;
+ case 3:
+ if ((0x40 <= c && c <= 0x7e) || (0x80 <= c && c <= 0xfc)){
+ status_push_ch(ptr, c);
+ s2e_conv(ptr->buf[0], ptr->buf[1], &ptr->buf[0], &ptr->buf[1]);
+ set_code_score(ptr, SCORE_CP932);
+ status_clear(ptr);
+ }else{
+ status_disable(ptr);
+ }
+ break;
+ }
+}
+
+static void
+e_status(struct input_code *ptr, nkf_char c)
+{
+ switch (ptr->stat){
+ case -1:
+ status_check(ptr, c);
+ break;
+ case 0:
+ if (c <= DEL){
+ break;
+ }else if (nkf_char_unicode_p(c)){
+ break;
+ }else if (SS2 == c || (0xa1 <= c && c <= 0xfe)){
+ ptr->stat = 1;
+ status_push_ch(ptr, c);
+#ifdef X0212_ENABLE
+ }else if (0x8f == c){
+ ptr->stat = 2;
+ status_push_ch(ptr, c);
+#endif /* X0212_ENABLE */
+ }else{
+ status_disable(ptr);
+ }
+ break;
+ case 1:
+ if (0xa1 <= c && c <= 0xfe){
+ status_push_ch(ptr, c);
+ code_score(ptr);
+ status_clear(ptr);
+ }else{
+ status_disable(ptr);
+ }
+ break;
+#ifdef X0212_ENABLE
+ case 2:
+ if (0xa1 <= c && c <= 0xfe){
+ ptr->stat = 1;
+ status_push_ch(ptr, c);
+ }else{
+ status_disable(ptr);
+ }
+#endif /* X0212_ENABLE */
+ }
+}
+
+#ifdef UTF8_INPUT_ENABLE
+static void
+w_status(struct input_code *ptr, nkf_char c)
+{
+ switch (ptr->stat){
+ case -1:
+ status_check(ptr, c);
+ break;
+ case 0:
+ if (c <= DEL){
+ break;
+ }else if (nkf_char_unicode_p(c)){
+ break;
+ }else if (0xc0 <= c && c <= 0xdf){
+ ptr->stat = 1;
+ status_push_ch(ptr, c);
+ }else if (0xe0 <= c && c <= 0xef){
+ ptr->stat = 2;
+ status_push_ch(ptr, c);
+ }else if (0xf0 <= c && c <= 0xf4){
+ ptr->stat = 3;
+ status_push_ch(ptr, c);
+ }else{
+ status_disable(ptr);
+ }
+ break;
+ case 1:
+ case 2:
+ if (0x80 <= c && c <= 0xbf){
+ status_push_ch(ptr, c);
+ if (ptr->index > ptr->stat){
+ int bom = (ptr->buf[0] == 0xef && ptr->buf[1] == 0xbb
+ && ptr->buf[2] == 0xbf);
+ w2e_conv(ptr->buf[0], ptr->buf[1], ptr->buf[2],
+ &ptr->buf[0], &ptr->buf[1]);
+ if (!bom){
+ code_score(ptr);
+ }
+ status_clear(ptr);
+ }
+ }else{
+ status_disable(ptr);
+ }
+ break;
+ case 3:
+ if (0x80 <= c && c <= 0xbf){
+ if (ptr->index < ptr->stat){
+ status_push_ch(ptr, c);
+ } else {
+ status_clear(ptr);
+ }
+ }else{
+ status_disable(ptr);
+ }
+ break;
+ }
+}
+#endif
+
+static void
+code_status(nkf_char c)
+{
+ int action_flag = 1;
+ struct input_code *result = 0;
+ struct input_code *p = input_code_list;
+ while (p->name){
+ if (!p->status_func) {
+ ++p;
+ continue;
+ }
+ if (!p->status_func)
+ continue;
+ (p->status_func)(p, c);
+ if (p->stat > 0){
+ action_flag = 0;
+ }else if(p->stat == 0){
+ if (result){
+ action_flag = 0;
+ }else{
+ result = p;
+ }
+ }
+ ++p;
+ }
+
+ if (action_flag){
+ if (result && !estab_f){
+ set_iconv(TRUE, result->iconv_func);
+ }else if (c <= DEL){
+ struct input_code *ptr = input_code_list;
+ while (ptr->name){
+ status_reset(ptr);
+ ++ptr;
+ }
+ }
+ }
+}
+
+typedef struct {
+ nkf_buf_t *std_gc_buf;
+ nkf_char broken_state;
+ nkf_buf_t *broken_buf;
+ nkf_char mimeout_state;
+ nkf_buf_t *nfc_buf;
+} nkf_state_t;
+
+static nkf_state_t *nkf_state = NULL;
+
+#define STD_GC_BUFSIZE (256)
+
+static void
+nkf_state_init(void)
+{
+ if (nkf_state) {
+ nkf_buf_clear(nkf_state->std_gc_buf);
+ nkf_buf_clear(nkf_state->broken_buf);
+ nkf_buf_clear(nkf_state->nfc_buf);
+ }
+ else {
+ nkf_state = nkf_xmalloc(sizeof(nkf_state_t));
+ nkf_state->std_gc_buf = nkf_buf_new(STD_GC_BUFSIZE);
+ nkf_state->broken_buf = nkf_buf_new(3);
+ nkf_state->nfc_buf = nkf_buf_new(9);
+ }
+ nkf_state->broken_state = 0;
+ nkf_state->mimeout_state = 0;
+}
+
+#ifndef WIN32DLL
+static nkf_char
+std_getc(FILE *f)
+{
+ if (!nkf_buf_empty_p(nkf_state->std_gc_buf)){
+ return nkf_buf_pop(nkf_state->std_gc_buf);
+ }
+ return getc(f);
+}
+#endif /*WIN32DLL*/
+
+static nkf_char
+std_ungetc(nkf_char c, ARG_UNUSED FILE *f)
+{
+ nkf_buf_push(nkf_state->std_gc_buf, c);
+ return c;
+}
+
+#ifndef WIN32DLL
+static void
+std_putc(nkf_char c)
+{
+ if(c!=EOF)
+ putchar(c);
+}
+#endif /*WIN32DLL*/
+
+static nkf_char hold_buf[HOLD_SIZE*2];
+static int hold_count = 0;
+static nkf_char
+push_hold_buf(nkf_char c2)
+{
+ if (hold_count >= HOLD_SIZE*2)
+ return (EOF);
+ hold_buf[hold_count++] = c2;
+ return ((hold_count >= HOLD_SIZE*2) ? EOF : hold_count);
+}
+
+static int
+h_conv(FILE *f, nkf_char c1, nkf_char c2)
+{
+ int ret;
+ int hold_index;
+ int fromhold_count;
+ nkf_char c3, c4;
+
+ /** it must NOT be in the kanji shifte sequence */
+ /** it must NOT be written in JIS7 */
+ /** and it must be after 2 byte 8bit code */
+
+ hold_count = 0;
+ push_hold_buf(c1);
+ push_hold_buf(c2);
+
+ while ((c2 = (*i_getc)(f)) != EOF) {
+ if (c2 == ESC){
+ (*i_ungetc)(c2,f);
+ break;
+ }
+ code_status(c2);
+ if (push_hold_buf(c2) == EOF || estab_f) {
+ break;
+ }
+ }
+
+ if (!estab_f) {
+ struct input_code *p = input_code_list;
+ struct input_code *result = p;
+ if (c2 == EOF) {
+ code_status(c2);
+ }
+ while (p->name) {
+ if (p->status_func && p->score < result->score) {
+ result = p;
+ }
+ p++;
+ }
+ set_iconv(TRUE, result->iconv_func);
+ }
+
+
+ /** now,
+ ** 1) EOF is detected, or
+ ** 2) Code is established, or
+ ** 3) Buffer is FULL (but last word is pushed)
+ **
+ ** in 1) and 3) cases, we continue to use
+ ** Kanji codes by oconv and leave estab_f unchanged.
+ **/
+
+ ret = c2;
+ hold_index = 0;
+ while (hold_index < hold_count){
+ c1 = hold_buf[hold_index++];
+ if (nkf_char_unicode_p(c1)) {
+ (*oconv)(0, c1);
+ continue;
+ }
+ else if (c1 <= DEL){
+ (*iconv)(0, c1, 0);
+ continue;
+ }else if (iconv == s_iconv && 0xa1 <= c1 && c1 <= 0xdf){
+ (*iconv)(JIS_X_0201_1976_K, c1, 0);
+ continue;
+ }
+ fromhold_count = 1;
+ if (hold_index < hold_count){
+ c2 = hold_buf[hold_index++];
+ fromhold_count++;
+ }else{
+ c2 = (*i_getc)(f);
+ if (c2 == EOF){
+ c4 = EOF;
+ break;
+ }
+ code_status(c2);
+ }
+ c3 = 0;
+ switch ((*iconv)(c1, c2, 0)) { /* can be EUC/SJIS/UTF-8 */
+ case -2:
+ /* 4 bytes UTF-8 */
+ if (hold_index < hold_count){
+ c3 = hold_buf[hold_index++];
+ } else if ((c3 = (*i_getc)(f)) == EOF) {
+ ret = EOF;
+ break;
+ }
+ code_status(c3);
+ if (hold_index < hold_count){
+ c4 = hold_buf[hold_index++];
+ } else if ((c4 = (*i_getc)(f)) == EOF) {
+ c3 = ret = EOF;
+ break;
+ }
+ code_status(c4);
+ (*iconv)(c1, c2, (c3<<8)|c4);
+ break;
+ case -3:
+ /* 4 bytes UTF-8 (check combining character) */
+ if (hold_index < hold_count){
+ c3 = hold_buf[hold_index++];
+ fromhold_count++;
+ } else if ((c3 = (*i_getc)(f)) == EOF) {
+ w_iconv_nocombine(c1, c2, 0);
+ break;
+ }
+ if (hold_index < hold_count){
+ c4 = hold_buf[hold_index++];
+ fromhold_count++;
+ } else if ((c4 = (*i_getc)(f)) == EOF) {
+ w_iconv_nocombine(c1, c2, 0);
+ if (fromhold_count <= 2)
+ (*i_ungetc)(c3,f);
+ else
+ hold_index--;
+ continue;
+ }
+ if (w_iconv_combine(c1, c2, 0, c3, c4, 0)) {
+ w_iconv_nocombine(c1, c2, 0);
+ if (fromhold_count <= 2) {
+ (*i_ungetc)(c4,f);
+ (*i_ungetc)(c3,f);
+ } else if (fromhold_count == 3) {
+ (*i_ungetc)(c4,f);
+ hold_index--;
+ } else {
+ hold_index -= 2;
+ }
+ }
+ break;
+ case -1:
+ /* 3 bytes EUC or UTF-8 */
+ if (hold_index < hold_count){
+ c3 = hold_buf[hold_index++];
+ fromhold_count++;
+ } else if ((c3 = (*i_getc)(f)) == EOF) {
+ ret = EOF;
+ break;
+ } else {
+ code_status(c3);
+ }
+ if ((*iconv)(c1, c2, c3) == -3) {
+ /* 6 bytes UTF-8 (check combining character) */
+ nkf_char c5, c6;
+ if (hold_index < hold_count){
+ c4 = hold_buf[hold_index++];
+ fromhold_count++;
+ } else if ((c4 = (*i_getc)(f)) == EOF) {
+ w_iconv_nocombine(c1, c2, c3);
+ continue;
+ }
+ if (hold_index < hold_count){
+ c5 = hold_buf[hold_index++];
+ fromhold_count++;
+ } else if ((c5 = (*i_getc)(f)) == EOF) {
+ w_iconv_nocombine(c1, c2, c3);
+ if (fromhold_count == 4)
+ hold_index--;
+ else
+ (*i_ungetc)(c4,f);
+ continue;
+ }
+ if (hold_index < hold_count){
+ c6 = hold_buf[hold_index++];
+ fromhold_count++;
+ } else if ((c6 = (*i_getc)(f)) == EOF) {
+ w_iconv_nocombine(c1, c2, c3);
+ if (fromhold_count == 5) {
+ hold_index -= 2;
+ } else if (fromhold_count == 4) {
+ hold_index--;
+ (*i_ungetc)(c5,f);
+ } else {
+ (*i_ungetc)(c5,f);
+ (*i_ungetc)(c4,f);
+ }
+ continue;
+ }
+ if (w_iconv_combine(c1, c2, c3, c4, c5, c6)) {
+ w_iconv_nocombine(c1, c2, c3);
+ if (fromhold_count == 6) {
+ hold_index -= 3;
+ } else if (fromhold_count == 5) {
+ hold_index -= 2;
+ (*i_ungetc)(c6,f);
+ } else if (fromhold_count == 4) {
+ hold_index--;
+ (*i_ungetc)(c6,f);
+ (*i_ungetc)(c5,f);
+ } else {
+ (*i_ungetc)(c6,f);
+ (*i_ungetc)(c5,f);
+ (*i_ungetc)(c4,f);
+ }
+ }
+ }
+ break;
+ }
+ if (c3 == EOF) break;
+ }
+ return ret;
+}
+
+/*
+ * Check and Ignore BOM
+ */
+static void
+check_bom(FILE *f)
+{
+ int c2;
+ input_bom_f = FALSE;
+ switch(c2 = (*i_getc)(f)){
+ case 0x00:
+ if((c2 = (*i_getc)(f)) == 0x00){
+ if((c2 = (*i_getc)(f)) == 0xFE){
+ if((c2 = (*i_getc)(f)) == 0xFF){
+ if(!input_encoding){
+ set_iconv(TRUE, w_iconv32);
+ }
+ if (iconv == w_iconv32) {
+ input_bom_f = TRUE;
+ input_endian = ENDIAN_BIG;
+ return;
+ }
+ (*i_ungetc)(0xFF,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0xFE,f);
+ }else if(c2 == 0xFF){
+ if((c2 = (*i_getc)(f)) == 0xFE){
+ if(!input_encoding){
+ set_iconv(TRUE, w_iconv32);
+ }
+ if (iconv == w_iconv32) {
+ input_endian = ENDIAN_2143;
+ return;
+ }
+ (*i_ungetc)(0xFF,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0xFF,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0x00,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0x00,f);
+ break;
+ case 0xEF:
+ if((c2 = (*i_getc)(f)) == 0xBB){
+ if((c2 = (*i_getc)(f)) == 0xBF){
+ if(!input_encoding){
+ set_iconv(TRUE, w_iconv);
+ }
+ if (iconv == w_iconv) {
+ input_bom_f = TRUE;
+ return;
+ }
+ (*i_ungetc)(0xBF,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0xBB,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0xEF,f);
+ break;
+ case 0xFE:
+ if((c2 = (*i_getc)(f)) == 0xFF){
+ if((c2 = (*i_getc)(f)) == 0x00){
+ if((c2 = (*i_getc)(f)) == 0x00){
+ if(!input_encoding){
+ set_iconv(TRUE, w_iconv32);
+ }
+ if (iconv == w_iconv32) {
+ input_endian = ENDIAN_3412;
+ return;
+ }
+ (*i_ungetc)(0x00,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0x00,f);
+ }else (*i_ungetc)(c2,f);
+ if(!input_encoding){
+ set_iconv(TRUE, w_iconv16);
+ }
+ if (iconv == w_iconv16) {
+ input_endian = ENDIAN_BIG;
+ input_bom_f = TRUE;
+ return;
+ }
+ (*i_ungetc)(0xFF,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0xFE,f);
+ break;
+ case 0xFF:
+ if((c2 = (*i_getc)(f)) == 0xFE){
+ if((c2 = (*i_getc)(f)) == 0x00){
+ if((c2 = (*i_getc)(f)) == 0x00){
+ if(!input_encoding){
+ set_iconv(TRUE, w_iconv32);
+ }
+ if (iconv == w_iconv32) {
+ input_endian = ENDIAN_LITTLE;
+ input_bom_f = TRUE;
+ return;
+ }
+ (*i_ungetc)(0x00,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0x00,f);
+ }else (*i_ungetc)(c2,f);
+ if(!input_encoding){
+ set_iconv(TRUE, w_iconv16);
+ }
+ if (iconv == w_iconv16) {
+ input_endian = ENDIAN_LITTLE;
+ input_bom_f = TRUE;
+ return;
+ }
+ (*i_ungetc)(0xFE,f);
+ }else (*i_ungetc)(c2,f);
+ (*i_ungetc)(0xFF,f);
+ break;
+ default:
+ (*i_ungetc)(c2,f);
+ break;
+ }
+}
+
+static nkf_char
+broken_getc(FILE *f)
+{
+ nkf_char c, c1;
+
+ if (!nkf_buf_empty_p(nkf_state->broken_buf)) {
+ return nkf_buf_pop(nkf_state->broken_buf);
+ }
+ c = (*i_bgetc)(f);
+ if (c=='$' && nkf_state->broken_state != ESC
+ && (input_mode == ASCII || input_mode == JIS_X_0201_1976_K)) {
+ c1= (*i_bgetc)(f);
+ nkf_state->broken_state = 0;
+ if (c1=='@'|| c1=='B') {
+ nkf_buf_push(nkf_state->broken_buf, c1);
+ nkf_buf_push(nkf_state->broken_buf, c);
+ return ESC;
+ } else {
+ (*i_bungetc)(c1,f);
+ return c;
+ }
+ } else if (c=='(' && nkf_state->broken_state != ESC
+ && (input_mode == JIS_X_0208 || input_mode == JIS_X_0201_1976_K)) {
+ c1= (*i_bgetc)(f);
+ nkf_state->broken_state = 0;
+ if (c1=='J'|| c1=='B') {
+ nkf_buf_push(nkf_state->broken_buf, c1);
+ nkf_buf_push(nkf_state->broken_buf, c);
+ return ESC;
+ } else {
+ (*i_bungetc)(c1,f);
+ return c;
+ }
+ } else {
+ nkf_state->broken_state = c;
+ return c;
+ }
+}
+
+static nkf_char
+broken_ungetc(nkf_char c, ARG_UNUSED FILE *f)
+{
+ if (nkf_buf_length(nkf_state->broken_buf) < 2)
+ nkf_buf_push(nkf_state->broken_buf, c);
+ return c;
+}
+
+static void
+eol_conv(nkf_char c2, nkf_char c1)
+{
+ if (guess_f && input_eol != EOF) {
+ if (c2 == 0 && c1 == LF) {
+ if (!input_eol) input_eol = prev_cr ? CRLF : LF;
+ else if (input_eol != (prev_cr ? CRLF : LF)) input_eol = EOF;
+ } else if (c2 == 0 && c1 == CR && input_eol == LF) input_eol = EOF;
+ else if (!prev_cr);
+ else if (!input_eol) input_eol = CR;
+ else if (input_eol != CR) input_eol = EOF;
+ }
+ if (prev_cr || (c2 == 0 && c1 == LF)) {
+ prev_cr = 0;
+ if (eolmode_f != LF) (*o_eol_conv)(0, CR);
+ if (eolmode_f != CR) (*o_eol_conv)(0, LF);
+ }
+ if (c2 == 0 && c1 == CR) prev_cr = CR;
+ else if (c2 != 0 || c1 != LF) (*o_eol_conv)(c2, c1);
+}
+
+static void
+put_newline(void (*func)(nkf_char))
+{
+ switch (eolmode_f ? eolmode_f : DEFAULT_NEWLINE) {
+ case CRLF:
+ (*func)(0x0D);
+ (*func)(0x0A);
+ break;
+ case CR:
+ (*func)(0x0D);
+ break;
+ case LF:
+ (*func)(0x0A);
+ break;
+ }
+}
+
+static void
+oconv_newline(void (*func)(nkf_char, nkf_char))
+{
+ switch (eolmode_f ? eolmode_f : DEFAULT_NEWLINE) {
+ case CRLF:
+ (*func)(0, 0x0D);
+ (*func)(0, 0x0A);
+ break;
+ case CR:
+ (*func)(0, 0x0D);
+ break;
+ case LF:
+ (*func)(0, 0x0A);
+ break;
+ }
+}
+
+/*
+ Return value of fold_conv()
+
+ LF add newline and output char
+ CR add newline and output nothing
+ SP space
+ 0 skip
+ 1 (or else) normal output
+
+ fold state in prev (previous character)
+
+ >0x80 Japanese (X0208/X0201)
+ <0x80 ASCII
+ LF new line
+ SP space
+
+ This fold algorithm does not preserve heading space in a line.
+ This is the main difference from fmt.
+ */
+
+#define char_size(c2,c1) (c2?2:1)
+
+static void
+fold_conv(nkf_char c2, nkf_char c1)
+{
+ nkf_char prev0;
+ nkf_char fold_state;
+
+ if (c1== CR && !fold_preserve_f) {
+ fold_state=0; /* ignore cr */
+ }else if (c1== LF&&f_prev==CR && fold_preserve_f) {
+ f_prev = LF;
+ fold_state=0; /* ignore cr */
+ } else if (c1== BS) {
+ if (f_line>0) f_line--;
+ fold_state = 1;
+ } else if (c2==EOF && f_line != 0) { /* close open last line */
+ fold_state = LF;
+ } else if ((c1==LF && !fold_preserve_f)
+ || ((c1==CR||(c1==LF&&f_prev!=CR))
+ && fold_preserve_f)) {
+ /* new line */
+ if (fold_preserve_f) {
+ f_prev = c1;
+ f_line = 0;
+ fold_state = CR;
+ } else if ((f_prev == c1)
+ || (f_prev == LF)
+ ) { /* duplicate newline */
+ if (f_line) {
+ f_line = 0;
+ fold_state = LF; /* output two newline */
+ } else {
+ f_line = 0;
+ fold_state = 1;
+ }
+ } else {
+ if (f_prev&0x80) { /* Japanese? */
+ f_prev = c1;
+ fold_state = 0; /* ignore given single newline */
+ } else if (f_prev==SP) {
+ fold_state = 0;
+ } else {
+ f_prev = c1;
+ if (++f_line<=fold_len)
+ fold_state = SP;
+ else {
+ f_line = 0;
+ fold_state = CR; /* fold and output nothing */
+ }
+ }
+ }
+ } else if (c1=='\f') {
+ f_prev = LF;
+ f_line = 0;
+ fold_state = LF; /* output newline and clear */
+ } else if ((c2==0 && nkf_isblank(c1)) || (c2 == '!' && c1 == '!')) {
+ /* X0208 kankaku or ascii space */
+ if (f_prev == SP) {
+ fold_state = 0; /* remove duplicate spaces */
+ } else {
+ f_prev = SP;
+ if (++f_line<=fold_len)
+ fold_state = SP; /* output ASCII space only */
+ else {
+ f_prev = SP; f_line = 0;
+ fold_state = CR; /* fold and output nothing */
+ }
+ }
+ } else {
+ prev0 = f_prev; /* we still need this one... , but almost done */
+ f_prev = c1;
+ if (c2 || c2 == JIS_X_0201_1976_K)
+ f_prev |= 0x80; /* this is Japanese */
+ f_line += c2 == JIS_X_0201_1976_K ? 1: char_size(c2,c1);
+ if (f_line<=fold_len) { /* normal case */
+ fold_state = 1;
+ } else {
+ if (f_line>fold_len+fold_margin) { /* too many kinsoku suspension */
+ f_line = char_size(c2,c1);
+ fold_state = LF; /* We can't wait, do fold now */
+ } else if (c2 == JIS_X_0201_1976_K) {
+ /* simple kinsoku rules return 1 means no folding */
+ if (c1==(0xde&0x7f)) fold_state = 1; /* $B!+(B*/
+ else if (c1==(0xdf&0x7f)) fold_state = 1; /* $B!,(B*/
+ else if (c1==(0xa4&0x7f)) fold_state = 1; /* $B!#(B*/
+ else if (c1==(0xa3&0x7f)) fold_state = 1; /* $B!$(B*/
+ else if (c1==(0xa1&0x7f)) fold_state = 1; /* $B!W(B*/
+ else if (c1==(0xb0&0x7f)) fold_state = 1; /* - */
+ else if (SP<=c1 && c1<=(0xdf&0x7f)) { /* X0201 */
+ f_line = 1;
+ fold_state = LF;/* add one new f_line before this character */
+ } else {
+ f_line = 1;
+ fold_state = LF;/* add one new f_line before this character */
+ }
+ } else if (c2==0) {
+ /* kinsoku point in ASCII */
+ if ( c1==')'|| /* { [ ( */
+ c1==']'||
+ c1=='}'||
+ c1=='.'||
+ c1==','||
+ c1=='!'||
+ c1=='?'||
+ c1=='/'||
+ c1==':'||
+ c1==';') {
+ fold_state = 1;
+ /* just after special */
+ } else if (!is_alnum(prev0)) {
+ f_line = char_size(c2,c1);
+ fold_state = LF;
+ } else if ((prev0==SP) || /* ignored new f_line */
+ (prev0==LF)|| /* ignored new f_line */
+ (prev0&0x80)) { /* X0208 - ASCII */
+ f_line = char_size(c2,c1);
+ fold_state = LF;/* add one new f_line before this character */
+ } else {
+ fold_state = 1; /* default no fold in ASCII */
+ }
+ } else {
+ if (c2=='!') {
+ if (c1=='"') fold_state = 1; /* $B!"(B */
+ else if (c1=='#') fold_state = 1; /* $B!#(B */
+ else if (c1=='W') fold_state = 1; /* $B!W(B */
+ else if (c1=='K') fold_state = 1; /* $B!K(B */
+ else if (c1=='$') fold_state = 1; /* $B!$(B */
+ else if (c1=='%') fold_state = 1; /* $B!%(B */
+ else if (c1=='\'') fold_state = 1; /* $B!\(B */
+ else if (c1=='(') fold_state = 1; /* $B!((B */
+ else if (c1==')') fold_state = 1; /* $B!)(B */
+ else if (c1=='*') fold_state = 1; /* $B!*(B */
+ else if (c1=='+') fold_state = 1; /* $B!+(B */
+ else if (c1==',') fold_state = 1; /* $B!,(B */
+ /* default no fold in kinsoku */
+ else {
+ fold_state = LF;
+ f_line = char_size(c2,c1);
+ /* add one new f_line before this character */
+ }
+ } else {
+ f_line = char_size(c2,c1);
+ fold_state = LF;
+ /* add one new f_line before this character */
+ }
+ }
+ }
+ }
+ /* terminator process */
+ switch(fold_state) {
+ case LF:
+ oconv_newline(o_fconv);
+ (*o_fconv)(c2,c1);
+ break;
+ case 0:
+ return;
+ case CR:
+ oconv_newline(o_fconv);
+ break;
+ case TAB:
+ case SP:
+ (*o_fconv)(0,SP);
+ break;
+ default:
+ (*o_fconv)(c2,c1);
+ }
+}
+
+static nkf_char z_prev2=0,z_prev1=0;
+
+static void
+z_conv(nkf_char c2, nkf_char c1)
+{
+
+ /* if (c2) c1 &= 0x7f; assertion */
+
+ if (c2 == JIS_X_0201_1976_K && (c1 == 0x20 || c1 == 0x7D || c1 == 0x7E)) {
+ (*o_zconv)(c2,c1);
+ return;
+ }
+
+ if (x0201_f) {
+ if (z_prev2 == JIS_X_0201_1976_K) {
+ if (c2 == JIS_X_0201_1976_K) {
+ if (c1 == (0xde&0x7f)) { /* $BByE@(B */
+ z_prev2 = 0;
+ (*o_zconv)(dv[(z_prev1-SP)*2], dv[(z_prev1-SP)*2+1]);
+ return;
+ } else if (c1 == (0xdf&0x7f) && ev[(z_prev1-SP)*2]) { /* $BH>ByE@(B */
+ z_prev2 = 0;
+ (*o_zconv)(ev[(z_prev1-SP)*2], ev[(z_prev1-SP)*2+1]);
+ return;
+ } else if (x0213_f && c1 == (0xdf&0x7f) && ev_x0213[(z_prev1-SP)*2]) { /* $BH>ByE@(B */
+ z_prev2 = 0;
+ (*o_zconv)(ev_x0213[(z_prev1-SP)*2], ev_x0213[(z_prev1-SP)*2+1]);
+ return;
+ }
+ }
+ z_prev2 = 0;
+ (*o_zconv)(cv[(z_prev1-SP)*2], cv[(z_prev1-SP)*2+1]);
+ }
+ if (c2 == JIS_X_0201_1976_K) {
+ if (dv[(c1-SP)*2] || ev[(c1-SP)*2] || (x0213_f && ev_x0213[(c1-SP)*2])) {
+ /* wait for $BByE@(B or $BH>ByE@(B */
+ z_prev1 = c1;
+ z_prev2 = c2;
+ return;
+ } else {
+ (*o_zconv)(cv[(c1-SP)*2], cv[(c1-SP)*2+1]);
+ return;
+ }
+ }
+ }
+
+ if (c2 == EOF) {
+ (*o_zconv)(c2, c1);
+ return;
+ }
+
+ if (alpha_f&1 && c2 == 0x23) {
+ /* JISX0208 Alphabet */
+ c2 = 0;
+ } else if (c2 == 0x21) {
+ /* JISX0208 Kigou */
+ if (0x21==c1) {
+ if (alpha_f&2) {
+ c2 = 0;
+ c1 = SP;
+ } else if (alpha_f&4) {
+ (*o_zconv)(0, SP);
+ (*o_zconv)(0, SP);
+ return;
+ }
+ } else if (alpha_f&1 && 0x20<c1 && c1<0x7f && fv[c1-0x20]) {
+ c2 = 0;
+ c1 = fv[c1-0x20];
+ }
+ }
+
+ if (alpha_f&8 && c2 == 0) {
+ /* HTML Entity */
+ const char *entity = 0;
+ switch (c1){
+ case '>': entity = "&gt;"; break;
+ case '<': entity = "&lt;"; break;
+ case '\"': entity = "&quot;"; break;
+ case '&': entity = "&amp;"; break;
+ }
+ if (entity){
+ while (*entity) (*o_zconv)(0, *entity++);
+ return;
+ }
+ }
+
+ if (alpha_f & 16) {
+ /* JIS X 0208 Katakana to JIS X 0201 Katakana */
+ if (c2 == 0x21) {
+ nkf_char c = 0;
+ switch (c1) {
+ case 0x23:
+ /* U+3002 (0x8142) Ideographic Full Stop -> U+FF61 (0xA1) Halfwidth Ideographic Full Stop */
+ c = 0xA1;
+ break;
+ case 0x56:
+ /* U+300C (0x8175) Left Corner Bracket -> U+FF62 (0xA2) Halfwidth Left Corner Bracket */
+ c = 0xA2;
+ break;
+ case 0x57:
+ /* U+300D (0x8176) Right Corner Bracket -> U+FF63 (0xA3) Halfwidth Right Corner Bracket */
+ c = 0xA3;
+ break;
+ case 0x22:
+ /* U+3001 (0x8141) Ideographic Comma -> U+FF64 (0xA4) Halfwidth Ideographic Comma */
+ c = 0xA4;
+ break;
+ case 0x26:
+ /* U+30FB (0x8145) Katakana Middle Dot -> U+FF65 (0xA5) Halfwidth Katakana Middle Dot */
+ c = 0xA5;
+ break;
+ case 0x3C:
+ /* U+30FC (0x815B) Katakana-Hiragana Prolonged Sound Mark -> U+FF70 (0xB0) Halfwidth Katakana-Hiragana Prolonged Sound Mark */
+ c = 0xB0;
+ break;
+ case 0x2B:
+ /* U+309B (0x814A) Katakana-Hiragana Voiced Sound Mark -> U+FF9E (0xDE) Halfwidth Katakana Voiced Sound Mark */
+ c = 0xDE;
+ break;
+ case 0x2C:
+ /* U+309C (0x814B) Katakana-Hiragana Semi-Voiced Sound Mark -> U+FF9F (0xDF) Halfwidth Katakana Semi-Voiced Sound Mark */
+ c = 0xDF;
+ break;
+ }
+ if (c) {
+ (*o_zconv)(JIS_X_0201_1976_K, c);
+ return;
+ }
+ } else if (c2 == 0x25) {
+ /* JISX0208 Katakana */
+ static const int fullwidth_to_halfwidth[] =
+ {
+ 0x0000, 0x2700, 0x3100, 0x2800, 0x3200, 0x2900, 0x3300, 0x2A00,
+ 0x3400, 0x2B00, 0x3500, 0x3600, 0x365E, 0x3700, 0x375E, 0x3800,
+ 0x385E, 0x3900, 0x395E, 0x3A00, 0x3A5E, 0x3B00, 0x3B5E, 0x3C00,
+ 0x3C5E, 0x3D00, 0x3D5E, 0x3E00, 0x3E5E, 0x3F00, 0x3F5E, 0x4000,
+ 0x405E, 0x4100, 0x415E, 0x2F00, 0x4200, 0x425E, 0x4300, 0x435E,
+ 0x4400, 0x445E, 0x4500, 0x4600, 0x4700, 0x4800, 0x4900, 0x4A00,
+ 0x4A5E, 0x4A5F, 0x4B00, 0x4B5E, 0x4B5F, 0x4C00, 0x4C5E, 0x4C5F,
+ 0x4D00, 0x4D5E, 0x4D5F, 0x4E00, 0x4E5E, 0x4E5F, 0x4F00, 0x5000,
+ 0x5100, 0x5200, 0x5300, 0x2C00, 0x5400, 0x2D00, 0x5500, 0x2E00,
+ 0x5600, 0x5700, 0x5800, 0x5900, 0x5A00, 0x5B00, 0x0000, 0x5C00,
+ 0x0000, 0x0000, 0x2600, 0x5D00, 0x335E, 0x0000, 0x0000, 0x365F,
+ 0x375F, 0x385F, 0x395F, 0x3A5F, 0x3E5F, 0x425F, 0x445F, 0x0000
+ };
+ if (fullwidth_to_halfwidth[c1-0x20]){
+ c2 = fullwidth_to_halfwidth[c1-0x20];
+ (*o_zconv)(JIS_X_0201_1976_K, c2>>8);
+ if (c2 & 0xFF) {
+ (*o_zconv)(JIS_X_0201_1976_K, c2&0xFF);
+ }
+ return;
+ }
+ } else if (c2 == 0 && nkf_char_unicode_p(c1) &&
+ ((c1&VALUE_MASK) == 0x3099 || (c1&VALUE_MASK) == 0x309A)) { /* $B9g@.MQByE@!&H>ByE@(B */
+ (*o_zconv)(JIS_X_0201_1976_K, 0x5E + (c1&VALUE_MASK) - 0x3099);
+ return;
+ }
+ }
+ (*o_zconv)(c2,c1);
+}
+
+
+#define rot13(c) ( \
+ ( c < 'A') ? c: \
+ (c <= 'M') ? (c + 13): \
+ (c <= 'Z') ? (c - 13): \
+ (c < 'a') ? (c): \
+ (c <= 'm') ? (c + 13): \
+ (c <= 'z') ? (c - 13): \
+ (c) \
+ )
+
+#define rot47(c) ( \
+ ( c < '!') ? c: \
+ ( c <= 'O') ? (c + 47) : \
+ ( c <= '~') ? (c - 47) : \
+ c \
+ )
+
+static void
+rot_conv(nkf_char c2, nkf_char c1)
+{
+ if (c2 == 0 || c2 == JIS_X_0201_1976_K || c2 == ISO_8859_1) {
+ c1 = rot13(c1);
+ } else if (c2) {
+ c1 = rot47(c1);
+ c2 = rot47(c2);
+ }
+ (*o_rot_conv)(c2,c1);
+}
+
+static void
+hira_conv(nkf_char c2, nkf_char c1)
+{
+ if (hira_f & 1) {
+ if (c2 == 0x25) {
+ if (0x20 < c1 && c1 < 0x74) {
+ c2 = 0x24;
+ (*o_hira_conv)(c2,c1);
+ return;
+ } else if (c1 == 0x74 && nkf_enc_unicode_p(output_encoding)) {
+ c2 = 0;
+ c1 = nkf_char_unicode_new(0x3094);
+ (*o_hira_conv)(c2,c1);
+ return;
+ }
+ } else if (c2 == 0x21 && (c1 == 0x33 || c1 == 0x34)) {
+ c1 += 2;
+ (*o_hira_conv)(c2,c1);
+ return;
+ }
+ }
+ if (hira_f & 2) {
+ if (c2 == 0 && c1 == nkf_char_unicode_new(0x3094)) {
+ c2 = 0x25;
+ c1 = 0x74;
+ } else if (c2 == 0x24 && 0x20 < c1 && c1 < 0x74) {
+ c2 = 0x25;
+ } else if (c2 == 0x21 && (c1 == 0x35 || c1 == 0x36)) {
+ c1 -= 2;
+ }
+ }
+ (*o_hira_conv)(c2,c1);
+}
+
+
+static void
+iso2022jp_check_conv(nkf_char c2, nkf_char c1)
+{
+#define RANGE_NUM_MAX 18
+ static const nkf_char range[RANGE_NUM_MAX][2] = {
+ {0x222f, 0x2239,},
+ {0x2242, 0x2249,},
+ {0x2251, 0x225b,},
+ {0x226b, 0x2271,},
+ {0x227a, 0x227d,},
+ {0x2321, 0x232f,},
+ {0x233a, 0x2340,},
+ {0x235b, 0x2360,},
+ {0x237b, 0x237e,},
+ {0x2474, 0x247e,},
+ {0x2577, 0x257e,},
+ {0x2639, 0x2640,},
+ {0x2659, 0x267e,},
+ {0x2742, 0x2750,},
+ {0x2772, 0x277e,},
+ {0x2841, 0x287e,},
+ {0x4f54, 0x4f7e,},
+ {0x7425, 0x747e},
+ };
+ nkf_char i;
+ nkf_char start, end, c;
+
+ if(c2 >= 0x00 && c2 <= 0x20 && c1 >= 0x7f && c1 <= 0xff) {
+ c2 = GETA1;
+ c1 = GETA2;
+ }
+ if((c2 >= 0x29 && c2 <= 0x2f) || (c2 >= 0x75 && c2 <= 0x7e)) {
+ c2 = GETA1;
+ c1 = GETA2;
+ }
+
+ for (i = 0; i < RANGE_NUM_MAX; i++) {
+ start = range[i][0];
+ end = range[i][1];
+ c = (c2 << 8) + c1;
+ if (c >= start && c <= end) {
+ c2 = GETA1;
+ c1 = GETA2;
+ }
+ }
+ (*o_iso2022jp_check_conv)(c2,c1);
+}
+
+
+/* This converts =?ISO-2022-JP?B?HOGE HOGE?= */
+
+static const unsigned char *mime_pattern[] = {
+ (const unsigned char *)"\075?EUC-JP?B?",
+ (const unsigned char *)"\075?SHIFT_JIS?B?",
+ (const unsigned char *)"\075?ISO-8859-1?Q?",
+ (const unsigned char *)"\075?ISO-8859-1?B?",
+ (const unsigned char *)"\075?ISO-2022-JP?B?",
+ (const unsigned char *)"\075?ISO-2022-JP?B?",
+ (const unsigned char *)"\075?ISO-2022-JP?Q?",
+#if defined(UTF8_INPUT_ENABLE)
+ (const unsigned char *)"\075?UTF-8?B?",
+ (const unsigned char *)"\075?UTF-8?Q?",
+#endif
+ (const unsigned char *)"\075?US-ASCII?Q?",
+ NULL
+};
+
+
+/* $B3:Ev$9$k%3!<%I$NM%@hEY$r>e$2$k$?$a$NL\0u(B */
+static nkf_char (*const mime_priority_func[])(nkf_char c2, nkf_char c1, nkf_char c0) = {
+ e_iconv, s_iconv, 0, 0, 0, 0, 0,
+#if defined(UTF8_INPUT_ENABLE)
+ w_iconv, w_iconv,
+#endif
+ 0,
+};
+
+static const nkf_char mime_encode[] = {
+ EUC_JP, SHIFT_JIS, ISO_8859_1, ISO_8859_1, JIS_X_0208, JIS_X_0201_1976_K, JIS_X_0201_1976_K,
+#if defined(UTF8_INPUT_ENABLE)
+ UTF_8, UTF_8,
+#endif
+ ASCII,
+ 0
+};
+
+static const nkf_char mime_encode_method[] = {
+ 'B', 'B','Q', 'B', 'B', 'B', 'Q',
+#if defined(UTF8_INPUT_ENABLE)
+ 'B', 'Q',
+#endif
+ 'Q',
+ 0
+};
+
+
+/* MIME preprocessor fifo */
+
+#define MIME_BUF_SIZE (1024) /* 2^n ring buffer */
+#define MIME_BUF_MASK (MIME_BUF_SIZE-1)
+#define mime_input_buf(n) mime_input_state.buf[(n)&MIME_BUF_MASK]
+static struct {
+ unsigned char buf[MIME_BUF_SIZE];
+ unsigned int top;
+ unsigned int last; /* decoded */
+ unsigned int input; /* undecoded */
+} mime_input_state;
+static nkf_char (*mime_iconv_back)(nkf_char c2,nkf_char c1,nkf_char c0) = NULL;
+
+#define MAXRECOVER 20
+
+static void
+mime_input_buf_unshift(nkf_char c)
+{
+ mime_input_buf(--mime_input_state.top) = (unsigned char)c;
+}
+
+static nkf_char
+mime_ungetc(nkf_char c, ARG_UNUSED FILE *f)
+{
+ mime_input_buf_unshift(c);
+ return c;
+}
+
+static nkf_char
+mime_ungetc_buf(nkf_char c, FILE *f)
+{
+ if (mimebuf_f)
+ (*i_mungetc_buf)(c,f);
+ else
+ mime_input_buf(--mime_input_state.input) = (unsigned char)c;
+ return c;
+}
+
+static nkf_char
+mime_getc_buf(FILE *f)
+{
+ /* we don't keep eof of mime_input_buf, because it contains ?= as
+ a terminator. It was checked in mime_integrity. */
+ return ((mimebuf_f)?
+ (*i_mgetc_buf)(f):mime_input_buf(mime_input_state.input++));
+}
+
+static void
+switch_mime_getc(void)
+{
+ if (i_getc!=mime_getc) {
+ i_mgetc = i_getc; i_getc = mime_getc;
+ i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
+ if(mime_f==STRICT_MIME) {
+ i_mgetc_buf = i_mgetc; i_mgetc = mime_getc_buf;
+ i_mungetc_buf = i_mungetc; i_mungetc = mime_ungetc_buf;
+ }
+ }
+}
+
+static void
+unswitch_mime_getc(void)
+{
+ if(mime_f==STRICT_MIME) {
+ i_mgetc = i_mgetc_buf;
+ i_mungetc = i_mungetc_buf;
+ }
+ i_getc = i_mgetc;
+ i_ungetc = i_mungetc;
+ if(mime_iconv_back)set_iconv(FALSE, mime_iconv_back);
+ mime_iconv_back = NULL;
+}
+
+static nkf_char
+mime_integrity(FILE *f, const unsigned char *p)
+{
+ nkf_char c,d;
+ unsigned int q;
+ /* In buffered mode, read until =? or NL or buffer full
+ */
+ mime_input_state.input = mime_input_state.top;
+ mime_input_state.last = mime_input_state.top;
+
+ while(*p) mime_input_buf(mime_input_state.input++) = *p++;
+ d = 0;
+ q = mime_input_state.input;
+ while((c=(*i_getc)(f))!=EOF) {
+ if (((mime_input_state.input-mime_input_state.top)&MIME_BUF_MASK)==0) {
+ break; /* buffer full */
+ }
+ if (c=='=' && d=='?') {
+ /* checked. skip header, start decode */
+ mime_input_buf(mime_input_state.input++) = (unsigned char)c;
+ /* mime_last_input = mime_input_state.input; */
+ mime_input_state.input = q;
+ switch_mime_getc();
+ return 1;
+ }
+ if (!( (c=='+'||c=='/'|| c=='=' || c=='?' || is_alnum(c))))
+ break;
+ /* Should we check length mod 4? */
+ mime_input_buf(mime_input_state.input++) = (unsigned char)c;
+ d=c;
+ }
+ /* In case of Incomplete MIME, no MIME decode */
+ mime_input_buf(mime_input_state.input++) = (unsigned char)c;
+ mime_input_state.last = mime_input_state.input; /* point undecoded buffer */
+ mime_decode_mode = 1; /* no decode on mime_input_buf last in mime_getc */
+ switch_mime_getc(); /* anyway we need buffered getc */
+ return 1;
+}
+
+static nkf_char
+mime_begin_strict(FILE *f)
+{
+ nkf_char c1 = 0;
+ int i,j,k;
+ const unsigned char *p,*q;
+ nkf_char r[MAXRECOVER]; /* recovery buffer, max mime pattern length */
+
+ mime_decode_mode = FALSE;
+ /* =? has been checked */
+ j = 0;
+ p = mime_pattern[j];
+ r[0]='='; r[1]='?';
+
+ for(i=2;p[i]>SP;i++) { /* start at =? */
+ if (((r[i] = c1 = (*i_getc)(f))==EOF) || nkf_toupper(c1) != p[i]) {
+ /* pattern fails, try next one */
+ q = p;
+ while (mime_pattern[++j]) {
+ p = mime_pattern[j];
+ for(k=2;k<i;k++) /* assume length(p) > i */
+ if (p[k]!=q[k]) break;
+ if (k==i && nkf_toupper(c1)==p[k]) break;
+ }
+ p = mime_pattern[j];
+ if (p) continue; /* found next one, continue */
+ /* all fails, output from recovery buffer */
+ (*i_ungetc)(c1,f);
+ for(j=0;j<i;j++) {
+ (*oconv)(0,r[j]);
+ }
+ return c1;
+ }
+ }
+ mime_decode_mode = p[i-2];
+
+ mime_iconv_back = iconv;
+ set_iconv(FALSE, mime_priority_func[j]);
+ clr_code_score(find_inputcode_byfunc(mime_priority_func[j]), SCORE_iMIME);
+
+ if (mime_decode_mode=='B') {
+ mimebuf_f = unbuf_f;
+ if (!unbuf_f) {
+ /* do MIME integrity check */
+ return mime_integrity(f,mime_pattern[j]);
+ }
+ }
+ switch_mime_getc();
+ mimebuf_f = TRUE;
+ return c1;
+}
+
+static nkf_char
+mime_begin(FILE *f)
+{
+ nkf_char c1 = 0;
+ int i,k;
+
+ /* In NONSTRICT mode, only =? is checked. In case of failure, we */
+ /* re-read and convert again from mime_buffer. */
+
+ /* =? has been checked */
+ k = mime_input_state.last;
+ mime_input_buf(mime_input_state.last++)='='; mime_input_buf(mime_input_state.last++)='?';
+ for(i=2;i<MAXRECOVER;i++) { /* start at =? */
+ /* We accept any character type even if it is breaked by new lines */
+ c1 = (*i_getc)(f); mime_input_buf(mime_input_state.last++) = (unsigned char)c1;
+ if (c1==LF||c1==SP||c1==CR||
+ c1=='-'||c1=='_'||is_alnum(c1)) continue;
+ if (c1=='=') {
+ /* Failed. But this could be another MIME preemble */
+ (*i_ungetc)(c1,f);
+ mime_input_state.last--;
+ break;
+ }
+ if (c1!='?') break;
+ else {
+ /* c1=='?' */
+ c1 = (*i_getc)(f); mime_input_buf(mime_input_state.last++) = (unsigned char)c1;
+ if (!(++i<MAXRECOVER) || c1==EOF) break;
+ if (c1=='b'||c1=='B') {
+ mime_decode_mode = 'B';
+ } else if (c1=='q'||c1=='Q') {
+ mime_decode_mode = 'Q';
+ } else {
+ break;
+ }
+ c1 = (*i_getc)(f); mime_input_buf(mime_input_state.last++) = (unsigned char)c1;
+ if (!(++i<MAXRECOVER) || c1==EOF) break;
+ if (c1!='?') {
+ mime_decode_mode = FALSE;
+ }
+ break;
+ }
+ }
+ switch_mime_getc();
+ if (!mime_decode_mode) {
+ /* false MIME premble, restart from mime_buffer */
+ mime_decode_mode = 1; /* no decode, but read from the mime_buffer */
+ /* Since we are in MIME mode until buffer becomes empty, */
+ /* we never go into mime_begin again for a while. */
+ return c1;
+ }
+ /* discard mime preemble, and goto MIME mode */
+ mime_input_state.last = k;
+ /* do no MIME integrity check */
+ return c1; /* used only for checking EOF */
+}
+
+#ifdef CHECK_OPTION
+static void
+no_putc(ARG_UNUSED nkf_char c)
+{
+ ;
+}
+
+static void
+debug(const char *str)
+{
+ if (debug_f){
+ fprintf(stderr, "%s\n", str ? str : "NULL");
+ }
+}
+#endif
+
+static void
+set_input_codename(const char *codename)
+{
+ if (!input_codename) {
+ input_codename = codename;
+ } else if (strcmp(codename, input_codename) != 0) {
+ input_codename = "";
+ }
+}
+
+static const char*
+get_guessed_code(void)
+{
+ if (input_codename && !*input_codename) {
+ input_codename = "BINARY";
+ } else {
+ struct input_code *p = find_inputcode_byfunc(iconv);
+ if (!input_codename) {
+ input_codename = "ASCII";
+ } else if (strcmp(input_codename, "Shift_JIS") == 0) {
+ if (p->score & (SCORE_DEPEND|SCORE_CP932))
+ input_codename = "CP932";
+ } else if (strcmp(input_codename, "EUC-JP") == 0) {
+ if (p->score & SCORE_X0213)
+ input_codename = "EUC-JIS-2004";
+ else if (p->score & (SCORE_X0212))
+ input_codename = "EUCJP-MS";
+ else if (p->score & (SCORE_DEPEND|SCORE_CP932))
+ input_codename = "CP51932";
+ } else if (strcmp(input_codename, "ISO-2022-JP") == 0) {
+ if (p->score & (SCORE_KANA))
+ input_codename = "CP50221";
+ else if (p->score & (SCORE_DEPEND|SCORE_CP932))
+ input_codename = "CP50220";
+ }
+ }
+ return input_codename;
+}
+
+#if !defined(PERL_XS) && !defined(WIN32DLL)
+static void
+print_guessed_code(char *filename)
+{
+ if (filename != NULL) printf("%s: ", filename);
+ if (input_codename && !*input_codename) {
+ printf("BINARY\n");
+ } else {
+ input_codename = get_guessed_code();
+ if (guess_f == 1) {
+ printf("%s\n", input_codename);
+ } else {
+ printf("%s%s%s%s\n",
+ input_codename,
+ iconv != w_iconv16 && iconv != w_iconv32 ? "" :
+ input_endian == ENDIAN_LITTLE ? " LE" :
+ input_endian == ENDIAN_BIG ? " BE" :
+ "[BUG]",
+ input_bom_f ? " (BOM)" : "",
+ input_eol == CR ? " (CR)" :
+ input_eol == LF ? " (LF)" :
+ input_eol == CRLF ? " (CRLF)" :
+ input_eol == EOF ? " (MIXED NL)" :
+ "");
+ }
+ }
+}
+#endif /*WIN32DLL*/
+
+#ifdef INPUT_OPTION
+
+static nkf_char
+hex_getc(nkf_char ch, FILE *f, nkf_char (*g)(FILE *f), nkf_char (*u)(nkf_char c, FILE *f))
+{
+ nkf_char c1, c2, c3;
+ c1 = (*g)(f);
+ if (c1 != ch){
+ return c1;
+ }
+ c2 = (*g)(f);
+ if (!nkf_isxdigit(c2)){
+ (*u)(c2, f);
+ return c1;
+ }
+ c3 = (*g)(f);
+ if (!nkf_isxdigit(c3)){
+ (*u)(c2, f);
+ (*u)(c3, f);
+ return c1;
+ }
+ return (hex2bin(c2) << 4) | hex2bin(c3);
+}
+
+static nkf_char
+cap_getc(FILE *f)
+{
+ return hex_getc(':', f, i_cgetc, i_cungetc);
+}
+
+static nkf_char
+cap_ungetc(nkf_char c, FILE *f)
+{
+ return (*i_cungetc)(c, f);
+}
+
+static nkf_char
+url_getc(FILE *f)
+{
+ return hex_getc('%', f, i_ugetc, i_uungetc);
+}
+
+static nkf_char
+url_ungetc(nkf_char c, FILE *f)
+{
+ return (*i_uungetc)(c, f);
+}
+#endif
+
+#ifdef NUMCHAR_OPTION
+static nkf_char
+numchar_getc(FILE *f)
+{
+ nkf_char (*g)(FILE *) = i_ngetc;
+ nkf_char (*u)(nkf_char c ,FILE *f) = i_nungetc;
+ int i = 0, j;
+ nkf_char buf[12];
+ nkf_char c = -1;
+
+ buf[i] = (*g)(f);
+ if (buf[i] == '&'){
+ buf[++i] = (*g)(f);
+ if (buf[i] == '#'){
+ c = 0;
+ buf[++i] = (*g)(f);
+ if (buf[i] == 'x' || buf[i] == 'X'){
+ for (j = 0; j < 7; j++){
+ buf[++i] = (*g)(f);
+ if (!nkf_isxdigit(buf[i])){
+ if (buf[i] != ';'){
+ c = -1;
+ }
+ break;
+ }
+ c <<= 4;
+ c |= hex2bin(buf[i]);
+ }
+ }else{
+ for (j = 0; j < 8; j++){
+ if (j){
+ buf[++i] = (*g)(f);
+ }
+ if (!nkf_isdigit(buf[i])){
+ if (buf[i] != ';'){
+ c = -1;
+ }
+ break;
+ }
+ c *= 10;
+ c += hex2bin(buf[i]);
+ }
+ }
+ }
+ }
+ if (c != -1){
+ return nkf_char_unicode_new(c);
+ }
+ while (i > 0){
+ (*u)(buf[i], f);
+ --i;
+ }
+ return buf[0];
+}
+
+static nkf_char
+numchar_ungetc(nkf_char c, FILE *f)
+{
+ return (*i_nungetc)(c, f);
+}
+#endif
+
+#ifdef UNICODE_NORMALIZATION
+
+static nkf_char
+nfc_getc(FILE *f)
+{
+ nkf_char (*g)(FILE *f) = i_nfc_getc;
+ nkf_char (*u)(nkf_char c ,FILE *f) = i_nfc_ungetc;
+ nkf_buf_t *buf = nkf_state->nfc_buf;
+ const unsigned char *array;
+ int lower=0, upper=NORMALIZATION_TABLE_LENGTH-1;
+ nkf_char c = (*g)(f);
+
+ if (c == EOF || c > 0xFF || (c & 0xc0) == 0x80) return c;
+
+ nkf_buf_push(buf, c);
+ do {
+ while (lower <= upper) {
+ int mid = (lower+upper) / 2;
+ int len;
+ array = normalization_table[mid].nfd;
+ for (len=0; len < NORMALIZATION_TABLE_NFD_LENGTH && array[len]; len++) {
+ if (len >= nkf_buf_length(buf)) {
+ c = (*g)(f);
+ if (c == EOF) {
+ len = 0;
+ lower = 1, upper = 0;
+ break;
+ }
+ nkf_buf_push(buf, c);
+ }
+ if (array[len] != nkf_buf_at(buf, len)) {
+ if (array[len] < nkf_buf_at(buf, len)) lower = mid + 1;
+ else upper = mid - 1;
+ len = 0;
+ break;
+ }
+ }
+ if (len > 0) {
+ int i;
+ array = normalization_table[mid].nfc;
+ nkf_buf_clear(buf);
+ for (i=0; i < NORMALIZATION_TABLE_NFC_LENGTH && array[i]; i++)
+ nkf_buf_push(buf, array[i]);
+ break;
+ }
+ }
+ } while (lower <= upper);
+
+ while (nkf_buf_length(buf) > 1) (*u)(nkf_buf_pop(buf), f);
+ c = nkf_buf_pop(buf);
+
+ return c;
+}
+
+static nkf_char
+nfc_ungetc(nkf_char c, FILE *f)
+{
+ return (*i_nfc_ungetc)(c, f);
+}
+#endif /* UNICODE_NORMALIZATION */
+
+
+static nkf_char
+base64decode(nkf_char c)
+{
+ int i;
+ if (c > '@') {
+ if (c < '[') {
+ i = c - 'A'; /* A..Z 0-25 */
+ } else if (c == '_') {
+ i = '?' /* 63 */ ; /* _ 63 */
+ } else {
+ i = c - 'G' /* - 'a' + 26 */ ; /* a..z 26-51 */
+ }
+ } else if (c > '/') {
+ i = c - '0' + '4' /* - '0' + 52 */ ; /* 0..9 52-61 */
+ } else if (c == '+' || c == '-') {
+ i = '>' /* 62 */ ; /* + and - 62 */
+ } else {
+ i = '?' /* 63 */ ; /* / 63 */
+ }
+ return (i);
+}
+
+static nkf_char
+mime_getc(FILE *f)
+{
+ nkf_char c1, c2, c3, c4, cc;
+ nkf_char t1, t2, t3, t4, mode, exit_mode;
+ nkf_char lwsp_count;
+ char *lwsp_buf;
+ char *lwsp_buf_new;
+ nkf_char lwsp_size = 128;
+
+ if (mime_input_state.top != mime_input_state.last) { /* Something is in FIFO */
+ return mime_input_buf(mime_input_state.top++);
+ }
+ if (mime_decode_mode==1 ||mime_decode_mode==FALSE) {
+ mime_decode_mode=FALSE;
+ unswitch_mime_getc();
+ return (*i_getc)(f);
+ }
+
+ if (mimebuf_f == FIXED_MIME)
+ exit_mode = mime_decode_mode;
+ else
+ exit_mode = FALSE;
+ if (mime_decode_mode == 'Q') {
+ if ((c1 = (*i_mgetc)(f)) == EOF) return (EOF);
+ restart_mime_q:
+ if (c1=='_' && mimebuf_f != FIXED_MIME) return SP;
+ if (c1<=SP || DEL<=c1) {
+ mime_decode_mode = exit_mode; /* prepare for quit */
+ return c1;
+ }
+ if (c1!='=' && (c1!='?' || mimebuf_f == FIXED_MIME)) {
+ return c1;
+ }
+
+ mime_decode_mode = exit_mode; /* prepare for quit */
+ if ((c2 = (*i_mgetc)(f)) == EOF) return (EOF);
+ if (c1=='?'&&c2=='=' && mimebuf_f != FIXED_MIME) {
+ /* end Q encoding */
+ input_mode = exit_mode;
+ lwsp_count = 0;
+ lwsp_buf = nkf_xmalloc((lwsp_size+5)*sizeof(char));
+ while ((c1=(*i_getc)(f))!=EOF) {
+ switch (c1) {
+ case LF:
+ case CR:
+ if (c1==LF) {
+ if ((c1=(*i_getc)(f))!=EOF && nkf_isblank(c1)) {
+ i_ungetc(SP,f);
+ continue;
+ } else {
+ i_ungetc(c1,f);
+ }
+ c1 = LF;
+ } else {
+ if ((c1=(*i_getc)(f))!=EOF && c1 == LF) {
+ if ((c1=(*i_getc)(f))!=EOF && nkf_isblank(c1)) {
+ i_ungetc(SP,f);
+ continue;
+ } else {
+ i_ungetc(c1,f);
+ }
+ i_ungetc(LF,f);
+ } else {
+ i_ungetc(c1,f);
+ }
+ c1 = CR;
+ }
+ break;
+ case SP:
+ case TAB:
+ lwsp_buf[lwsp_count] = (unsigned char)c1;
+ if (lwsp_count++>lwsp_size){
+ lwsp_size <<= 1;
+ lwsp_buf_new = nkf_xrealloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
+ lwsp_buf = lwsp_buf_new;
+ }
+ continue;
+ }
+ break;
+ }
+ if (lwsp_count > 0 && (c1 != '=' || (lwsp_buf[lwsp_count-1] != SP && lwsp_buf[lwsp_count-1] != TAB))) {
+ i_ungetc(c1,f);
+ for(lwsp_count--;lwsp_count>0;lwsp_count--)
+ i_ungetc(lwsp_buf[lwsp_count],f);
+ c1 = lwsp_buf[0];
+ }
+ nkf_xfree(lwsp_buf);
+ return c1;
+ }
+ if (c1=='='&&c2<SP) { /* this is soft wrap */
+ while((c1 = (*i_mgetc)(f)) <=SP) {
+ if (c1 == EOF) return (EOF);
+ }
+ mime_decode_mode = 'Q'; /* still in MIME */
+ goto restart_mime_q;
+ }
+ if (c1=='?') {
+ mime_decode_mode = 'Q'; /* still in MIME */
+ (*i_mungetc)(c2,f);
+ return c1;
+ }
+ if ((c3 = (*i_mgetc)(f)) == EOF) return (EOF);
+ if (c2<=SP) return c2;
+ mime_decode_mode = 'Q'; /* still in MIME */
+ return ((hex2bin(c2)<<4) + hex2bin(c3));
+ }
+
+ if (mime_decode_mode != 'B') {
+ mime_decode_mode = FALSE;
+ return (*i_mgetc)(f);
+ }
+
+
+ /* Base64 encoding */
+ /*
+ MIME allows line break in the middle of
+ Base64, but we are very pessimistic in decoding
+ in unbuf mode because MIME encoded code may broken by
+ less or editor's control sequence (such as ESC-[-K in unbuffered
+ mode. ignore incomplete MIME.
+ */
+ mode = mime_decode_mode;
+ mime_decode_mode = exit_mode; /* prepare for quit */
+
+ while ((c1 = (*i_mgetc)(f))<=SP) {
+ if (c1==EOF)
+ return (EOF);
+ }
+ mime_c2_retry:
+ if ((c2 = (*i_mgetc)(f))<=SP) {
+ if (c2==EOF)
+ return (EOF);
+ if (mime_f != STRICT_MIME) goto mime_c2_retry;
+ if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;
+ return c2;
+ }
+ if ((c1 == '?') && (c2 == '=')) {
+ input_mode = ASCII;
+ lwsp_count = 0;
+ lwsp_buf = nkf_xmalloc((lwsp_size+5)*sizeof(char));
+ while ((c1=(*i_getc)(f))!=EOF) {
+ switch (c1) {
+ case LF:
+ case CR:
+ if (c1==LF) {
+ if ((c1=(*i_getc)(f))!=EOF && nkf_isblank(c1)) {
+ i_ungetc(SP,f);
+ continue;
+ } else {
+ i_ungetc(c1,f);
+ }
+ c1 = LF;
+ } else {
+ if ((c1=(*i_getc)(f))!=EOF) {
+ if (c1==SP) {
+ i_ungetc(SP,f);
+ continue;
+ } else if ((c1=(*i_getc)(f))!=EOF && nkf_isblank(c1)) {
+ i_ungetc(SP,f);
+ continue;
+ } else {
+ i_ungetc(c1,f);
+ }
+ i_ungetc(LF,f);
+ } else {
+ i_ungetc(c1,f);
+ }
+ c1 = CR;
+ }
+ break;
+ case SP:
+ case TAB:
+ lwsp_buf[lwsp_count] = (unsigned char)c1;
+ if (lwsp_count++>lwsp_size){
+ lwsp_size <<= 1;
+ lwsp_buf_new = nkf_xrealloc(lwsp_buf, (lwsp_size+5)*sizeof(char));
+ lwsp_buf = lwsp_buf_new;
+ }
+ continue;
+ }
+ break;
+ }
+ if (lwsp_count > 0 && (c1 != '=' || (lwsp_buf[lwsp_count-1] != SP && lwsp_buf[lwsp_count-1] != TAB))) {
+ i_ungetc(c1,f);
+ for(lwsp_count--;lwsp_count>0;lwsp_count--)
+ i_ungetc(lwsp_buf[lwsp_count],f);
+ c1 = lwsp_buf[0];
+ }
+ nkf_xfree(lwsp_buf);
+ return c1;
+ }
+ mime_c3_retry:
+ if ((c3 = (*i_mgetc)(f))<=SP) {
+ if (c3==EOF)
+ return (EOF);
+ if (mime_f != STRICT_MIME) goto mime_c3_retry;
+ if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;
+ return c3;
+ }
+ mime_c4_retry:
+ if ((c4 = (*i_mgetc)(f))<=SP) {
+ if (c4==EOF)
+ return (EOF);
+ if (mime_f != STRICT_MIME) goto mime_c4_retry;
+ if (mimebuf_f!=FIXED_MIME) input_mode = ASCII;
+ return c4;
+ }
+
+ mime_decode_mode = mode; /* still in MIME sigh... */
+
+ /* BASE 64 decoding */
+
+ t1 = 0x3f & base64decode(c1);
+ t2 = 0x3f & base64decode(c2);
+ t3 = 0x3f & base64decode(c3);
+ t4 = 0x3f & base64decode(c4);
+ cc = ((t1 << 2) & 0x0fc) | ((t2 >> 4) & 0x03);
+ if (c2 != '=') {
+ mime_input_buf(mime_input_state.last++) = (unsigned char)cc;
+ cc = ((t2 << 4) & 0x0f0) | ((t3 >> 2) & 0x0f);
+ if (c3 != '=') {
+ mime_input_buf(mime_input_state.last++) = (unsigned char)cc;
+ cc = ((t3 << 6) & 0x0c0) | (t4 & 0x3f);
+ if (c4 != '=')
+ mime_input_buf(mime_input_state.last++) = (unsigned char)cc;
+ }
+ } else {
+ return c1;
+ }
+ return mime_input_buf(mime_input_state.top++);
+}
+
+static const char basis_64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define MIMEOUT_BUF_LENGTH 74
+static struct {
+ unsigned char buf[MIMEOUT_BUF_LENGTH+1];
+ int count;
+} mimeout_state;
+
+/*nkf_char mime_lastchar2, mime_lastchar1;*/
+
+static void
+open_mime(nkf_char mode)
+{
+ const unsigned char *p;
+ int i;
+ int j;
+ p = mime_pattern[0];
+ for(i=0;mime_pattern[i];i++) {
+ if (mode == mime_encode[i]) {
+ p = mime_pattern[i];
+ break;
+ }
+ }
+ mimeout_mode = mime_encode_method[i];
+ i = 0;
+ if (base64_count>45) {
+ if (mimeout_state.count>0 && nkf_isblank(mimeout_state.buf[i])){
+ (*o_mputc)(mimeout_state.buf[i]);
+ i++;
+ }
+ put_newline(o_mputc);
+ (*o_mputc)(SP);
+ base64_count = 1;
+ if (mimeout_state.count>0 && nkf_isspace(mimeout_state.buf[i])) {
+ i++;
+ }
+ }
+ for (;i<mimeout_state.count;i++) {
+ if (nkf_isspace(mimeout_state.buf[i])) {
+ (*o_mputc)(mimeout_state.buf[i]);
+ base64_count ++;
+ } else {
+ break;
+ }
+ }
+ while(*p) {
+ (*o_mputc)(*p++);
+ base64_count ++;
+ }
+ j = mimeout_state.count;
+ mimeout_state.count = 0;
+ for (;i<j;i++) {
+ mime_putc(mimeout_state.buf[i]);
+ }
+}
+
+static void
+mime_prechar(nkf_char c2, nkf_char c1)
+{
+ if (mimeout_mode > 0){
+ if (c2 == EOF){
+ if (base64_count + mimeout_state.count/3*4> 73){
+ (*o_base64conv)(EOF,0);
+ oconv_newline(o_base64conv);
+ (*o_base64conv)(0,SP);
+ base64_count = 1;
+ }
+ } else {
+ if ((c2 != 0 || c1 > DEL) && base64_count + mimeout_state.count/3*4> 66) {
+ (*o_base64conv)(EOF,0);
+ oconv_newline(o_base64conv);
+ (*o_base64conv)(0,SP);
+ base64_count = 1;
+ mimeout_mode = -1;
+ }
+ }
+ } else if (c2) {
+ if (c2 != EOF && base64_count + mimeout_state.count/3*4> 60) {
+ mimeout_mode = (output_mode==ASCII ||output_mode == ISO_8859_1) ? 'Q' : 'B';
+ open_mime(output_mode);
+ (*o_base64conv)(EOF,0);
+ oconv_newline(o_base64conv);
+ (*o_base64conv)(0,SP);
+ base64_count = 1;
+ mimeout_mode = -1;
+ }
+ }
+}
+
+static void
+close_mime(void)
+{
+ (*o_mputc)('?');
+ (*o_mputc)('=');
+ base64_count += 2;
+ mimeout_mode = 0;
+}
+
+static void
+eof_mime(void)
+{
+ switch(mimeout_mode) {
+ case 'Q':
+ case 'B':
+ break;
+ case 2:
+ (*o_mputc)(basis_64[((nkf_state->mimeout_state & 0x3)<< 4)]);
+ (*o_mputc)('=');
+ (*o_mputc)('=');
+ base64_count += 3;
+ break;
+ case 1:
+ (*o_mputc)(basis_64[((nkf_state->mimeout_state & 0xF) << 2)]);
+ (*o_mputc)('=');
+ base64_count += 2;
+ break;
+ }
+ if (mimeout_mode > 0) {
+ if (mimeout_f!=FIXED_MIME) {
+ close_mime();
+ } else if (mimeout_mode != 'Q')
+ mimeout_mode = 'B';
+ }
+}
+
+static void
+mimeout_addchar(nkf_char c)
+{
+ switch(mimeout_mode) {
+ case 'Q':
+ if (c==CR||c==LF) {
+ (*o_mputc)(c);
+ base64_count = 0;
+ } else if(!nkf_isalnum(c)) {
+ (*o_mputc)('=');
+ (*o_mputc)(bin2hex(((c>>4)&0xf)));
+ (*o_mputc)(bin2hex((c&0xf)));
+ base64_count += 3;
+ } else {
+ (*o_mputc)(c);
+ base64_count++;
+ }
+ break;
+ case 'B':
+ nkf_state->mimeout_state=c;
+ (*o_mputc)(basis_64[c>>2]);
+ mimeout_mode=2;
+ base64_count ++;
+ break;
+ case 2:
+ (*o_mputc)(basis_64[((nkf_state->mimeout_state & 0x3)<< 4) | ((c & 0xF0) >> 4)]);
+ nkf_state->mimeout_state=c;
+ mimeout_mode=1;
+ base64_count ++;
+ break;
+ case 1:
+ (*o_mputc)(basis_64[((nkf_state->mimeout_state & 0xF) << 2) | ((c & 0xC0) >>6)]);
+ (*o_mputc)(basis_64[c & 0x3F]);
+ mimeout_mode='B';
+ base64_count += 2;
+ break;
+ default:
+ (*o_mputc)(c);
+ base64_count++;
+ break;
+ }
+}
+
+static void
+mime_putc(nkf_char c)
+{
+ int i, j;
+ nkf_char lastchar;
+
+ if (mimeout_f == FIXED_MIME){
+ if (mimeout_mode == 'Q'){
+ if (base64_count > 71){
+ if (c!=CR && c!=LF) {
+ (*o_mputc)('=');
+ put_newline(o_mputc);
+ }
+ base64_count = 0;
+ }
+ }else{
+ if (base64_count > 71){
+ eof_mime();
+ put_newline(o_mputc);
+ base64_count = 0;
+ }
+ if (c == EOF) { /* c==EOF */
+ eof_mime();
+ }
+ }
+ if (c != EOF) { /* c==EOF */
+ mimeout_addchar(c);
+ }
+ return;
+ }
+
+ /* mimeout_f != FIXED_MIME */
+
+ if (c == EOF) { /* c==EOF */
+ if (mimeout_mode == -1 && mimeout_state.count > 1) open_mime(output_mode);
+ j = mimeout_state.count;
+ mimeout_state.count = 0;
+ i = 0;
+ if (mimeout_mode > 0) {
+ if (!nkf_isblank(mimeout_state.buf[j-1])) {
+ for (;i<j;i++) {
+ if (nkf_isspace(mimeout_state.buf[i]) && base64_count < 71){
+ break;
+ }
+ mimeout_addchar(mimeout_state.buf[i]);
+ }
+ eof_mime();
+ for (;i<j;i++) {
+ mimeout_addchar(mimeout_state.buf[i]);
+ }
+ } else {
+ for (;i<j;i++) {
+ mimeout_addchar(mimeout_state.buf[i]);
+ }
+ eof_mime();
+ }
+ } else {
+ for (;i<j;i++) {
+ mimeout_addchar(mimeout_state.buf[i]);
+ }
+ }
+ return;
+ }
+
+ if (mimeout_state.count > 0){
+ lastchar = mimeout_state.buf[mimeout_state.count - 1];
+ }else{
+ lastchar = -1;
+ }
+
+ if (mimeout_mode=='Q') {
+ if (c <= DEL && (output_mode==ASCII ||output_mode == ISO_8859_1)) {
+ if (c == CR || c == LF) {
+ close_mime();
+ (*o_mputc)(c);
+ base64_count = 0;
+ return;
+ } else if (c <= SP) {
+ close_mime();
+ if (base64_count > 70) {
+ put_newline(o_mputc);
+ base64_count = 0;
+ }
+ if (!nkf_isblank(c)) {
+ (*o_mputc)(SP);
+ base64_count++;
+ }
+ } else {
+ if (base64_count > 70) {
+ close_mime();
+ put_newline(o_mputc);
+ (*o_mputc)(SP);
+ base64_count = 1;
+ open_mime(output_mode);
+ }
+ if (!nkf_noescape_mime(c)) {
+ mimeout_addchar(c);
+ return;
+ }
+ }
+ if (c != 0x1B) {
+ (*o_mputc)(c);
+ base64_count++;
+ return;
+ }
+ }
+ }
+
+ if (mimeout_mode <= 0) {
+ if (c <= DEL && (output_mode==ASCII || output_mode == ISO_8859_1 ||
+ output_mode == UTF_8)) {
+ if (nkf_isspace(c)) {
+ int flag = 0;
+ if (mimeout_mode == -1) {
+ flag = 1;
+ }
+ if (c==CR || c==LF) {
+ if (flag) {
+ open_mime(output_mode);
+ output_mode = 0;
+ } else {
+ base64_count = 0;
+ }
+ }
+ for (i=0;i<mimeout_state.count;i++) {
+ (*o_mputc)(mimeout_state.buf[i]);
+ if (mimeout_state.buf[i] == CR || mimeout_state.buf[i] == LF){
+ base64_count = 0;
+ }else{
+ base64_count++;
+ }
+ }
+ if (flag) {
+ eof_mime();
+ base64_count = 0;
+ mimeout_mode = 0;
+ }
+ mimeout_state.buf[0] = (char)c;
+ mimeout_state.count = 1;
+ }else{
+ if (base64_count > 1
+ && base64_count + mimeout_state.count > 76
+ && mimeout_state.buf[0] != CR && mimeout_state.buf[0] != LF){
+ static const char *str = "boundary=\"";
+ static int len = 10;
+ i = 0;
+
+ for (; i < mimeout_state.count - len; ++i) {
+ if (!strncmp((char *)(mimeout_state.buf+i), str, len)) {
+ i += len - 2;
+ break;
+ }
+ }
+
+ if (i == 0 || i == mimeout_state.count - len) {
+ put_newline(o_mputc);
+ base64_count = 0;
+ if (!nkf_isspace(mimeout_state.buf[0])){
+ (*o_mputc)(SP);
+ base64_count++;
+ }
+ }
+ else {
+ int j;
+ for (j = 0; j <= i; ++j) {
+ (*o_mputc)(mimeout_state.buf[j]);
+ }
+ put_newline(o_mputc);
+ base64_count = 1;
+ for (; j <= mimeout_state.count; ++j) {
+ mimeout_state.buf[j - i] = mimeout_state.buf[j];
+ }
+ mimeout_state.count -= i;
+ }
+ }
+ mimeout_state.buf[mimeout_state.count++] = (char)c;
+ if (mimeout_state.count>MIMEOUT_BUF_LENGTH) {
+ open_mime(output_mode);
+ }
+ }
+ return;
+ }else{
+ if (lastchar==CR || lastchar == LF){
+ for (i=0;i<mimeout_state.count;i++) {
+ (*o_mputc)(mimeout_state.buf[i]);
+ }
+ base64_count = 0;
+ mimeout_state.count = 0;
+ }
+ if (lastchar==SP) {
+ for (i=0;i<mimeout_state.count-1;i++) {
+ (*o_mputc)(mimeout_state.buf[i]);
+ base64_count++;
+ }
+ mimeout_state.buf[0] = SP;
+ mimeout_state.count = 1;
+ }
+ open_mime(output_mode);
+ }
+ }else{
+ /* mimeout_mode == 'B', 1, 2 */
+ if (c <= DEL && (output_mode==ASCII || output_mode == ISO_8859_1 ||
+ output_mode == UTF_8)) {
+ if (lastchar == CR || lastchar == LF){
+ if (nkf_isblank(c)) {
+ for (i=0;i<mimeout_state.count;i++) {
+ mimeout_addchar(mimeout_state.buf[i]);
+ }
+ mimeout_state.count = 0;
+ } else {
+ eof_mime();
+ for (i=0;i<mimeout_state.count;i++) {
+ (*o_mputc)(mimeout_state.buf[i]);
+ }
+ base64_count = 0;
+ mimeout_state.count = 0;
+ }
+ mimeout_state.buf[mimeout_state.count++] = (char)c;
+ return;
+ }
+ if (nkf_isspace(c)) {
+ for (i=0;i<mimeout_state.count;i++) {
+ if (SP<mimeout_state.buf[i] && mimeout_state.buf[i]<DEL) {
+ eof_mime();
+ for (i=0;i<mimeout_state.count;i++) {
+ (*o_mputc)(mimeout_state.buf[i]);
+ base64_count++;
+ }
+ mimeout_state.count = 0;
+ }
+ }
+ mimeout_state.buf[mimeout_state.count++] = (char)c;
+ if (mimeout_state.count>MIMEOUT_BUF_LENGTH) {
+ eof_mime();
+ for (j=0;j<mimeout_state.count;j++) {
+ (*o_mputc)(mimeout_state.buf[j]);
+ base64_count++;
+ }
+ mimeout_state.count = 0;
+ }
+ return;
+ }
+ if (mimeout_state.count>0 && SP<c && c!='=') {
+ mimeout_state.buf[mimeout_state.count++] = (char)c;
+ if (mimeout_state.count>MIMEOUT_BUF_LENGTH) {
+ j = mimeout_state.count;
+ mimeout_state.count = 0;
+ for (i=0;i<j;i++) {
+ mimeout_addchar(mimeout_state.buf[i]);
+ }
+ }
+ return;
+ }
+ }
+ }
+ if (mimeout_state.count>0) {
+ j = mimeout_state.count;
+ mimeout_state.count = 0;
+ for (i=0;i<j;i++) {
+ if (mimeout_state.buf[i]==CR || mimeout_state.buf[i]==LF)
+ break;
+ mimeout_addchar(mimeout_state.buf[i]);
+ }
+ if (i<j) {
+ eof_mime();
+ base64_count=0;
+ for (;i<j;i++) {
+ (*o_mputc)(mimeout_state.buf[i]);
+ }
+ open_mime(output_mode);
+ }
+ }
+ mimeout_addchar(c);
+}
+
+static void
+base64_conv(nkf_char c2, nkf_char c1)
+{
+ mime_prechar(c2, c1);
+ (*o_base64conv)(c2,c1);
+}
+
+#ifdef HAVE_ICONV_H
+typedef struct nkf_iconv_t {
+ iconv_t cd;
+ char *input_buffer;
+ size_t input_buffer_size;
+ char *output_buffer;
+ size_t output_buffer_size;
+};
+
+static nkf_iconv_t
+nkf_iconv_new(char *tocode, char *fromcode)
+{
+ nkf_iconv_t converter;
+
+ converter->input_buffer_size = IOBUF_SIZE;
+ converter->input_buffer = nkf_xmalloc(converter->input_buffer_size);
+ converter->output_buffer_size = IOBUF_SIZE * 2;
+ converter->output_buffer = nkf_xmalloc(converter->output_buffer_size);
+ converter->cd = iconv_open(tocode, fromcode);
+ if (converter->cd == (iconv_t)-1)
+ {
+ switch (errno) {
+ case EINVAL:
+ perror(fprintf("iconv doesn't support %s to %s conversion.", fromcode, tocode));
+ return -1;
+ default:
+ perror("can't iconv_open");
+ }
+ }
+}
+
+static size_t
+nkf_iconv_convert(nkf_iconv_t *converter, FILE *input)
+{
+ size_t invalid = (size_t)0;
+ char *input_buffer = converter->input_buffer;
+ size_t input_length = (size_t)0;
+ char *output_buffer = converter->output_buffer;
+ size_t output_length = converter->output_buffer_size;
+ int c;
+
+ do {
+ if (c != EOF) {
+ while ((c = (*i_getc)(f)) != EOF) {
+ input_buffer[input_length++] = c;
+ if (input_length < converter->input_buffer_size) break;
+ }
+ }
+
+ size_t ret = iconv(converter->cd, &input_buffer, &input_length, &output_buffer, &output_length);
+ while (output_length-- > 0) {
+ (*o_putc)(output_buffer[converter->output_buffer_size-output_length]);
+ }
+ if (ret == (size_t) - 1) {
+ switch (errno) {
+ case EINVAL:
+ if (input_buffer != converter->input_buffer)
+ memmove(converter->input_buffer, input_buffer, input_length);
+ break;
+ case E2BIG:
+ converter->output_buffer_size *= 2;
+ output_buffer = realloc(converter->outbuf, converter->output_buffer_size);
+ if (output_buffer == NULL) {
+ perror("can't realloc");
+ return -1;
+ }
+ converter->output_buffer = output_buffer;
+ break;
+ default:
+ perror("can't iconv");
+ return -1;
+ }
+ } else {
+ invalid += ret;
+ }
+ } while (1);
+
+ return invalid;
+}
+
+
+static void
+nkf_iconv_close(nkf_iconv_t *convert)
+{
+ nkf_xfree(converter->inbuf);
+ nkf_xfree(converter->outbuf);
+ iconv_close(converter->cd);
+}
+#endif
+
+
+static void
+reinit(void)
+{
+ {
+ struct input_code *p = input_code_list;
+ while (p->name){
+ status_reinit(p++);
+ }
+ }
+ unbuf_f = FALSE;
+ estab_f = FALSE;
+ nop_f = FALSE;
+ binmode_f = TRUE;
+ rot_f = FALSE;
+ hira_f = FALSE;
+ alpha_f = FALSE;
+ mime_f = MIME_DECODE_DEFAULT;
+ mime_decode_f = FALSE;
+ mimebuf_f = FALSE;
+ broken_f = FALSE;
+ iso8859_f = FALSE;
+ mimeout_f = FALSE;
+ x0201_f = NKF_UNSPECIFIED;
+ iso2022jp_f = FALSE;
+#if defined(UTF8_INPUT_ENABLE) || defined(UTF8_OUTPUT_ENABLE)
+ ms_ucs_map_f = UCS_MAP_ASCII;
+#endif
+#ifdef UTF8_INPUT_ENABLE
+ no_cp932ext_f = FALSE;
+ no_best_fit_chars_f = FALSE;
+ encode_fallback = NULL;
+ unicode_subchar = '?';
+ input_endian = ENDIAN_BIG;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ output_bom_f = FALSE;
+ output_endian = ENDIAN_BIG;
+#endif
+#ifdef UNICODE_NORMALIZATION
+ nfc_f = FALSE;
+#endif
+#ifdef INPUT_OPTION
+ cap_f = FALSE;
+ url_f = FALSE;
+ numchar_f = FALSE;
+#endif
+#ifdef CHECK_OPTION
+ noout_f = FALSE;
+ debug_f = FALSE;
+#endif
+ guess_f = 0;
+#ifdef EXEC_IO
+ exec_f = 0;
+#endif
+#ifdef SHIFTJIS_CP932
+ cp51932_f = TRUE;
+ cp932inv_f = TRUE;
+#endif
+#ifdef X0212_ENABLE
+ x0212_f = FALSE;
+ x0213_f = FALSE;
+#endif
+ {
+ int i;
+ for (i = 0; i < 256; i++){
+ prefix_table[i] = 0;
+ }
+ }
+ hold_count = 0;
+ mimeout_state.count = 0;
+ mimeout_mode = 0;
+ base64_count = 0;
+ f_line = 0;
+ f_prev = 0;
+ fold_preserve_f = FALSE;
+ fold_f = FALSE;
+ fold_len = 0;
+ kanji_intro = DEFAULT_J;
+ ascii_intro = DEFAULT_R;
+ fold_margin = FOLD_MARGIN;
+ o_zconv = no_connection;
+ o_fconv = no_connection;
+ o_eol_conv = no_connection;
+ o_rot_conv = no_connection;
+ o_hira_conv = no_connection;
+ o_base64conv = no_connection;
+ o_iso2022jp_check_conv = no_connection;
+ o_putc = std_putc;
+ i_getc = std_getc;
+ i_ungetc = std_ungetc;
+ i_bgetc = std_getc;
+ i_bungetc = std_ungetc;
+ o_mputc = std_putc;
+ i_mgetc = std_getc;
+ i_mungetc = std_ungetc;
+ i_mgetc_buf = std_getc;
+ i_mungetc_buf = std_ungetc;
+ output_mode = ASCII;
+ input_mode = ASCII;
+ mime_decode_mode = FALSE;
+ file_out_f = FALSE;
+ eolmode_f = 0;
+ input_eol = 0;
+ prev_cr = 0;
+ option_mode = 0;
+ z_prev2=0,z_prev1=0;
+#ifdef CHECK_OPTION
+ iconv_for_check = 0;
+#endif
+ input_codename = NULL;
+ input_encoding = NULL;
+ output_encoding = NULL;
+ nkf_state_init();
+#ifdef WIN32DLL
+ reinitdll();
+#endif /*WIN32DLL*/
+}
+
+static int
+module_connection(void)
+{
+ if (input_encoding) set_input_encoding(input_encoding);
+ if (!output_encoding) {
+ output_encoding = nkf_default_encoding();
+ }
+ if (!output_encoding) {
+ if (noout_f || guess_f) output_encoding = nkf_enc_from_index(ISO_2022_JP);
+ else return -1;
+ }
+ set_output_encoding(output_encoding);
+ oconv = nkf_enc_to_oconv(output_encoding);
+ o_putc = std_putc;
+ if (nkf_enc_unicode_p(output_encoding))
+ output_mode = UTF_8;
+
+ if (x0201_f == NKF_UNSPECIFIED) {
+ x0201_f = X0201_DEFAULT;
+ }
+
+ /* replace continuation module, from output side */
+
+ /* output redirection */
+#ifdef CHECK_OPTION
+ if (noout_f || guess_f){
+ o_putc = no_putc;
+ }
+#endif
+ if (mimeout_f) {
+ o_mputc = o_putc;
+ o_putc = mime_putc;
+ if (mimeout_f == TRUE) {
+ o_base64conv = oconv; oconv = base64_conv;
+ }
+ /* base64_count = 0; */
+ }
+
+ if (eolmode_f || guess_f) {
+ o_eol_conv = oconv; oconv = eol_conv;
+ }
+ if (rot_f) {
+ o_rot_conv = oconv; oconv = rot_conv;
+ }
+ if (iso2022jp_f) {
+ o_iso2022jp_check_conv = oconv; oconv = iso2022jp_check_conv;
+ }
+ if (hira_f) {
+ o_hira_conv = oconv; oconv = hira_conv;
+ }
+ if (fold_f) {
+ o_fconv = oconv; oconv = fold_conv;
+ f_line = 0;
+ }
+ if (alpha_f || x0201_f) {
+ o_zconv = oconv; oconv = z_conv;
+ }
+
+ i_getc = std_getc;
+ i_ungetc = std_ungetc;
+ /* input redirection */
+#ifdef INPUT_OPTION
+ if (cap_f){
+ i_cgetc = i_getc; i_getc = cap_getc;
+ i_cungetc = i_ungetc; i_ungetc= cap_ungetc;
+ }
+ if (url_f){
+ i_ugetc = i_getc; i_getc = url_getc;
+ i_uungetc = i_ungetc; i_ungetc= url_ungetc;
+ }
+#endif
+#ifdef NUMCHAR_OPTION
+ if (numchar_f){
+ i_ngetc = i_getc; i_getc = numchar_getc;
+ i_nungetc = i_ungetc; i_ungetc= numchar_ungetc;
+ }
+#endif
+#ifdef UNICODE_NORMALIZATION
+ if (nfc_f){
+ i_nfc_getc = i_getc; i_getc = nfc_getc;
+ i_nfc_ungetc = i_ungetc; i_ungetc= nfc_ungetc;
+ }
+#endif
+ if (mime_f && mimebuf_f==FIXED_MIME) {
+ i_mgetc = i_getc; i_getc = mime_getc;
+ i_mungetc = i_ungetc; i_ungetc = mime_ungetc;
+ }
+ if (broken_f & 1) {
+ i_bgetc = i_getc; i_getc = broken_getc;
+ i_bungetc = i_ungetc; i_ungetc = broken_ungetc;
+ }
+ if (input_encoding) {
+ set_iconv(-TRUE, nkf_enc_to_iconv(input_encoding));
+ } else {
+ set_iconv(FALSE, e_iconv);
+ }
+
+ {
+ struct input_code *p = input_code_list;
+ while (p->name){
+ status_reinit(p++);
+ }
+ }
+ return 0;
+}
+
+/*
+ Conversion main loop. Code detection only.
+ */
+
+#if !defined(PERL_XS) && !defined(WIN32DLL)
+static nkf_char
+noconvert(FILE *f)
+{
+ nkf_char c;
+
+ if (nop_f == 2)
+ module_connection();
+ while ((c = (*i_getc)(f)) != EOF)
+ (*o_putc)(c);
+ (*o_putc)(EOF);
+ return 1;
+}
+#endif
+
+#define NEXT continue /* no output, get next */
+#define SKIP c2=0;continue /* no output, get next */
+#define MORE c2=c1;continue /* need one more byte */
+#define SEND (void)0 /* output c1 and c2, get next */
+#define LAST break /* end of loop, go closing */
+#define set_input_mode(mode) do { \
+ input_mode = mode; \
+ shift_mode = 0; \
+ set_input_codename("ISO-2022-JP"); \
+ debug("ISO-2022-JP"); \
+} while (0)
+
+static int
+kanji_convert(FILE *f)
+{
+ nkf_char c1=0, c2=0, c3=0, c4=0;
+ int shift_mode = 0; /* 0, 1, 2, 3 */
+ int g2 = 0;
+ int is_8bit = FALSE;
+
+ if (input_encoding && !nkf_enc_asciicompat(input_encoding)) {
+ is_8bit = TRUE;
+ }
+
+ input_mode = ASCII;
+ output_mode = ASCII;
+
+ if (module_connection() < 0) {
+#if !defined(PERL_XS) && !defined(WIN32DLL)
+ fprintf(stderr, "no output encoding given\n");
+#endif
+ return -1;
+ }
+ check_bom(f);
+
+#ifdef UTF8_INPUT_ENABLE
+ if(iconv == w_iconv32){
+ while ((c1 = (*i_getc)(f)) != EOF &&
+ (c2 = (*i_getc)(f)) != EOF &&
+ (c3 = (*i_getc)(f)) != EOF &&
+ (c4 = (*i_getc)(f)) != EOF) {
+ nkf_char c5, c6, c7, c8;
+ if (nkf_iconv_utf_32(c1, c2, c3, c4) == (size_t)NKF_ICONV_WAIT_COMBINING_CHAR) {
+ if ((c5 = (*i_getc)(f)) != EOF &&
+ (c6 = (*i_getc)(f)) != EOF &&
+ (c7 = (*i_getc)(f)) != EOF &&
+ (c8 = (*i_getc)(f)) != EOF) {
+ if (nkf_iconv_utf_32_combine(c1, c2, c3, c4, c5, c6, c7, c8)) {
+ (*i_ungetc)(c8, f);
+ (*i_ungetc)(c7, f);
+ (*i_ungetc)(c6, f);
+ (*i_ungetc)(c5, f);
+ nkf_iconv_utf_32_nocombine(c1, c2, c3, c4);
+ }
+ } else {
+ nkf_iconv_utf_32_nocombine(c1, c2, c3, c4);
+ }
+ }
+ }
+ goto finished;
+ }
+ else if (iconv == w_iconv16) {
+ while ((c1 = (*i_getc)(f)) != EOF &&
+ (c2 = (*i_getc)(f)) != EOF) {
+ size_t ret = nkf_iconv_utf_16(c1, c2, 0, 0);
+ if (ret == NKF_ICONV_NEED_TWO_MORE_BYTES &&
+ (c3 = (*i_getc)(f)) != EOF &&
+ (c4 = (*i_getc)(f)) != EOF) {
+ nkf_iconv_utf_16(c1, c2, c3, c4);
+ } else if (ret == (size_t)NKF_ICONV_WAIT_COMBINING_CHAR) {
+ if ((c3 = (*i_getc)(f)) != EOF &&
+ (c4 = (*i_getc)(f)) != EOF) {
+ if (nkf_iconv_utf_16_combine(c1, c2, c3, c4)) {
+ (*i_ungetc)(c4, f);
+ (*i_ungetc)(c3, f);
+ nkf_iconv_utf_16_nocombine(c1, c2);
+ }
+ } else {
+ nkf_iconv_utf_16_nocombine(c1, c2);
+ }
+ }
+ }
+ goto finished;
+ }
+#endif
+
+ while ((c1 = (*i_getc)(f)) != EOF) {
+#ifdef INPUT_CODE_FIX
+ if (!input_encoding)
+#endif
+ code_status(c1);
+ if (c2) {
+ /* second byte */
+ if (c2 > ((input_encoding && nkf_enc_cp5022x_p(input_encoding)) ? 0x92 : DEL)) {
+ /* in case of 8th bit is on */
+ if (!estab_f&&!mime_decode_mode) {
+ /* in case of not established yet */
+ /* It is still ambiguous */
+ if (h_conv(f, c2, c1)==EOF) {
+ LAST;
+ }
+ else {
+ SKIP;
+ }
+ }
+ else {
+ /* in case of already established */
+ if (c1 < 0x40) {
+ /* ignore bogus code */
+ SKIP;
+ } else {
+ SEND;
+ }
+ }
+ }
+ else {
+ /* 2nd byte of 7 bit code or SJIS */
+ SEND;
+ }
+ }
+ else if (nkf_char_unicode_p(c1)) {
+ (*oconv)(0, c1);
+ NEXT;
+ }
+ else {
+ /* first byte */
+ if (input_mode == JIS_X_0208 && DEL <= c1 && c1 < 0x92) {
+ /* CP5022x */
+ MORE;
+ }else if (input_codename && input_codename[0] == 'I' &&
+ 0xA1 <= c1 && c1 <= 0xDF) {
+ /* JIS X 0201 Katakana in 8bit JIS */
+ c2 = JIS_X_0201_1976_K;
+ c1 &= 0x7f;
+ SEND;
+ } else if (c1 > DEL) {
+ /* 8 bit code */
+ if (!estab_f && !iso8859_f) {
+ /* not established yet */
+ MORE;
+ } else { /* estab_f==TRUE */
+ if (iso8859_f) {
+ c2 = ISO_8859_1;
+ c1 &= 0x7f;
+ SEND;
+ }
+ else if ((iconv == s_iconv && 0xA0 <= c1 && c1 <= 0xDF) ||
+ (ms_ucs_map_f == UCS_MAP_CP10001 && (c1 == 0xFD || c1 == 0xFE))) {
+ /* JIS X 0201 */
+ c2 = JIS_X_0201_1976_K;
+ c1 &= 0x7f;
+ SEND;
+ }
+ else {
+ /* already established */
+ MORE;
+ }
+ }
+ } else if (SP < c1 && c1 < DEL) {
+ /* in case of Roman characters */
+ if (shift_mode) {
+ /* output 1 shifted byte */
+ if (iso8859_f) {
+ c2 = ISO_8859_1;
+ SEND;
+ } else if (nkf_byte_jisx0201_katakana_p(c1)){
+ /* output 1 shifted byte */
+ c2 = JIS_X_0201_1976_K;
+ SEND;
+ } else {
+ /* look like bogus code */
+ SKIP;
+ }
+ } else if (input_mode == JIS_X_0208 || input_mode == JIS_X_0212 ||
+ input_mode == JIS_X_0213_1 || input_mode == JIS_X_0213_2) {
+ /* in case of Kanji shifted */
+ MORE;
+ } else if (c1 == '=' && mime_f && !mime_decode_mode) {
+ /* Check MIME code */
+ if ((c1 = (*i_getc)(f)) == EOF) {
+ (*oconv)(0, '=');
+ LAST;
+ } else if (c1 == '?') {
+ /* =? is mime conversion start sequence */
+ if(mime_f == STRICT_MIME) {
+ /* check in real detail */
+ if (mime_begin_strict(f) == EOF)
+ LAST;
+ SKIP;
+ } else if (mime_begin(f) == EOF)
+ LAST;
+ SKIP;
+ } else {
+ (*oconv)(0, '=');
+ (*i_ungetc)(c1,f);
+ SKIP;
+ }
+ } else {
+ /* normal ASCII code */
+ SEND;
+ }
+ } else if (c1 == SI && (!is_8bit || mime_decode_mode)) {
+ shift_mode = 0;
+ SKIP;
+ } else if (c1 == SO && (!is_8bit || mime_decode_mode)) {
+ shift_mode = 1;
+ SKIP;
+ } else if (c1 == ESC && (!is_8bit || mime_decode_mode)) {
+ if ((c1 = (*i_getc)(f)) == EOF) {
+ (*oconv)(0, ESC);
+ LAST;
+ }
+ else if (c1 == '&') {
+ /* IRR */
+ if ((c1 = (*i_getc)(f)) == EOF) {
+ LAST;
+ } else {
+ SKIP;
+ }
+ }
+ else if (c1 == '$') {
+ /* GZDMx */
+ if ((c1 = (*i_getc)(f)) == EOF) {
+ /* don't send bogus code
+ (*oconv)(0, ESC);
+ (*oconv)(0, '$'); */
+ LAST;
+ } else if (c1 == '@' || c1 == 'B') {
+ /* JIS X 0208 */
+ set_input_mode(JIS_X_0208);
+ SKIP;
+ } else if (c1 == '(') {
+ /* GZDM4 */
+ if ((c1 = (*i_getc)(f)) == EOF) {
+ /* don't send bogus code
+ (*oconv)(0, ESC);
+ (*oconv)(0, '$');
+ (*oconv)(0, '(');
+ */
+ LAST;
+ } else if (c1 == '@'|| c1 == 'B') {
+ /* JIS X 0208 */
+ set_input_mode(JIS_X_0208);
+ SKIP;
+#ifdef X0212_ENABLE
+ } else if (c1 == 'D'){
+ set_input_mode(JIS_X_0212);
+ SKIP;
+#endif /* X0212_ENABLE */
+ } else if (c1 == 'O' || c1 == 'Q'){
+ set_input_mode(JIS_X_0213_1);
+ SKIP;
+ } else if (c1 == 'P'){
+ set_input_mode(JIS_X_0213_2);
+ SKIP;
+ } else {
+ /* could be some special code */
+ (*oconv)(0, ESC);
+ (*oconv)(0, '$');
+ (*oconv)(0, '(');
+ (*oconv)(0, c1);
+ SKIP;
+ }
+ } else if (broken_f&0x2) {
+ /* accept any ESC-(-x as broken code ... */
+ input_mode = JIS_X_0208;
+ shift_mode = 0;
+ SKIP;
+ } else {
+ (*oconv)(0, ESC);
+ (*oconv)(0, '$');
+ (*oconv)(0, c1);
+ SKIP;
+ }
+ } else if (c1 == '(') {
+ /* GZD4 */
+ if ((c1 = (*i_getc)(f)) == EOF) {
+ /* don't send bogus code
+ (*oconv)(0, ESC);
+ (*oconv)(0, '('); */
+ LAST;
+ }
+ else if (c1 == 'I') {
+ /* JIS X 0201 Katakana */
+ set_input_mode(JIS_X_0201_1976_K);
+ shift_mode = 1;
+ SKIP;
+ }
+ else if (c1 == 'B' || c1 == 'J' || c1 == 'H') {
+ /* ISO-646IRV:1983 or JIS X 0201 Roman or JUNET */
+ set_input_mode(ASCII);
+ SKIP;
+ }
+ else if (broken_f&0x2) {
+ set_input_mode(ASCII);
+ SKIP;
+ }
+ else {
+ (*oconv)(0, ESC);
+ (*oconv)(0, '(');
+ SEND;
+ }
+ }
+ else if (c1 == '.') {
+ /* G2D6 */
+ if ((c1 = (*i_getc)(f)) == EOF) {
+ LAST;
+ }
+ else if (c1 == 'A') {
+ /* ISO-8859-1 */
+ g2 = ISO_8859_1;
+ SKIP;
+ }
+ else {
+ (*oconv)(0, ESC);
+ (*oconv)(0, '.');
+ SEND;
+ }
+ }
+ else if (c1 == 'N') {
+ /* SS2 */
+ c1 = (*i_getc)(f);
+ if (g2 == ISO_8859_1) {
+ c2 = ISO_8859_1;
+ SEND;
+ }else{
+ (*i_ungetc)(c1, f);
+ /* lonely ESC */
+ (*oconv)(0, ESC);
+ SEND;
+ }
+ }
+ else {
+ i_ungetc(c1,f);
+ /* lonely ESC */
+ (*oconv)(0, ESC);
+ SKIP;
+ }
+ } else if (c1 == ESC && iconv == s_iconv) {
+ /* ESC in Shift_JIS */
+ if ((c1 = (*i_getc)(f)) == EOF) {
+ (*oconv)(0, ESC);
+ LAST;
+ } else if (c1 == '$') {
+ /* J-PHONE emoji */
+ if ((c1 = (*i_getc)(f)) == EOF) {
+ LAST;
+ } else if (('E' <= c1 && c1 <= 'G') ||
+ ('O' <= c1 && c1 <= 'Q')) {
+ /*
+ NUM : 0 1 2 3 4 5
+ BYTE: G E F O P Q
+ C%7 : 1 6 0 2 3 4
+ C%7 : 0 1 2 3 4 5 6
+ NUM : 2 0 3 4 5 X 1
+ */
+ static const nkf_char jphone_emoji_first_table[7] =
+ {0xE1E0, 0xDFE0, 0xE2E0, 0xE3E0, 0xE4E0, 0xDFE0, 0xE0E0};
+ c3 = nkf_char_unicode_new(jphone_emoji_first_table[c1 % 7]);
+ if ((c1 = (*i_getc)(f)) == EOF) LAST;
+ while (SP <= c1 && c1 <= 'z') {
+ (*oconv)(0, c1 + c3);
+ if ((c1 = (*i_getc)(f)) == EOF) LAST;
+ }
+ SKIP;
+ }
+ else {
+ (*oconv)(0, ESC);
+ (*oconv)(0, '$');
+ SEND;
+ }
+ }
+ else {
+ i_ungetc(c1,f);
+ /* lonely ESC */
+ (*oconv)(0, ESC);
+ SKIP;
+ }
+ } else if (c1 == LF || c1 == CR) {
+ if (broken_f&4) {
+ input_mode = ASCII; set_iconv(FALSE, 0);
+ SEND;
+ } else if (mime_decode_f && !mime_decode_mode){
+ if (c1 == LF) {
+ if ((c1=(*i_getc)(f))!=EOF && c1 == SP) {
+ i_ungetc(SP,f);
+ continue;
+ } else {
+ i_ungetc(c1,f);
+ }
+ c1 = LF;
+ SEND;
+ } else { /* if (c1 == CR)*/
+ if ((c1=(*i_getc)(f))!=EOF) {
+ if (c1==SP) {
+ i_ungetc(SP,f);
+ continue;
+ } else if (c1 == LF && (c1=(*i_getc)(f))!=EOF && c1 == SP) {
+ i_ungetc(SP,f);
+ continue;
+ } else {
+ i_ungetc(c1,f);
+ }
+ i_ungetc(LF,f);
+ } else {
+ i_ungetc(c1,f);
+ }
+ c1 = CR;
+ SEND;
+ }
+ }
+ } else
+ SEND;
+ }
+ /* send: */
+ switch(input_mode){
+ case ASCII:
+ switch ((*iconv)(c2, c1, 0)) { /* can be EUC / SJIS / UTF-8 */
+ case -2:
+ /* 4 bytes UTF-8 */
+ if ((c3 = (*i_getc)(f)) != EOF) {
+ code_status(c3);
+ c3 <<= 8;
+ if ((c4 = (*i_getc)(f)) != EOF) {
+ code_status(c4);
+ (*iconv)(c2, c1, c3|c4);
+ }
+ }
+ break;
+ case -3:
+ /* 4 bytes UTF-8 (check combining character) */
+ if ((c3 = (*i_getc)(f)) != EOF) {
+ if ((c4 = (*i_getc)(f)) != EOF) {
+ if (w_iconv_combine(c2, c1, 0, c3, c4, 0)) {
+ (*i_ungetc)(c4, f);
+ (*i_ungetc)(c3, f);
+ w_iconv_nocombine(c2, c1, 0);
+ }
+ } else {
+ (*i_ungetc)(c3, f);
+ w_iconv_nocombine(c2, c1, 0);
+ }
+ } else {
+ w_iconv_nocombine(c2, c1, 0);
+ }
+ break;
+ case -1:
+ /* 3 bytes EUC or UTF-8 */
+ if ((c3 = (*i_getc)(f)) != EOF) {
+ code_status(c3);
+ if ((*iconv)(c2, c1, c3) == -3) {
+ /* 6 bytes UTF-8 (check combining character) */
+ nkf_char c5, c6;
+ if ((c4 = (*i_getc)(f)) != EOF) {
+ if ((c5 = (*i_getc)(f)) != EOF) {
+ if ((c6 = (*i_getc)(f)) != EOF) {
+ if (w_iconv_combine(c2, c1, c3, c4, c5, c6)) {
+ (*i_ungetc)(c6, f);
+ (*i_ungetc)(c5, f);
+ (*i_ungetc)(c4, f);
+ w_iconv_nocombine(c2, c1, c3);
+ }
+ } else {
+ (*i_ungetc)(c5, f);
+ (*i_ungetc)(c4, f);
+ w_iconv_nocombine(c2, c1, c3);
+ }
+ } else {
+ (*i_ungetc)(c4, f);
+ w_iconv_nocombine(c2, c1, c3);
+ }
+ } else {
+ w_iconv_nocombine(c2, c1, c3);
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case JIS_X_0208:
+ case JIS_X_0213_1:
+ if (ms_ucs_map_f &&
+ 0x7F <= c2 && c2 <= 0x92 &&
+ 0x21 <= c1 && c1 <= 0x7E) {
+ /* CP932 UDC */
+ c1 = nkf_char_unicode_new((c2 - 0x7F) * 94 + c1 - 0x21 + 0xE000);
+ c2 = 0;
+ }
+ (*oconv)(c2, c1); /* this is JIS, not SJIS/EUC case */
+ break;
+#ifdef X0212_ENABLE
+ case JIS_X_0212:
+ (*oconv)(PREFIX_EUCG3 | c2, c1);
+ break;
+#endif /* X0212_ENABLE */
+ case JIS_X_0213_2:
+ (*oconv)(PREFIX_EUCG3 | c2, c1);
+ break;
+ default:
+ (*oconv)(input_mode, c1); /* other special case */
+ }
+
+ c2 = 0;
+ c3 = 0;
+ continue;
+ /* goto next_word */
+ }
+
+finished:
+ /* epilogue */
+ (*iconv)(EOF, 0, 0);
+ if (!input_codename)
+ {
+ if (is_8bit) {
+ struct input_code *p = input_code_list;
+ struct input_code *result = p;
+ while (p->name){
+ if (p->score < result->score) result = p;
+ ++p;
+ }
+ set_input_codename(result->name);
+#ifdef CHECK_OPTION
+ debug(result->name);
+#endif
+ }
+ }
+ return 0;
+}
+
+/*
+ * int options(unsigned char *cp)
+ *
+ * return values:
+ * 0: success
+ * -1: ArgumentError
+ */
+static int
+options(unsigned char *cp)
+{
+ nkf_char i, j;
+ unsigned char *p;
+ unsigned char *cp_back = NULL;
+ nkf_encoding *enc;
+
+ if (option_mode==1)
+ return 0;
+ while(*cp && *cp++!='-');
+ while (*cp || cp_back) {
+ if(!*cp){
+ cp = cp_back;
+ cp_back = NULL;
+ continue;
+ }
+ p = 0;
+ switch (*cp++) {
+ case '-': /* literal options */
+ if (!*cp || *cp == SP) { /* ignore the rest of arguments */
+ option_mode = 1;
+ return 0;
+ }
+ for (i=0;i<(int)(sizeof(long_option)/sizeof(long_option[0]));i++) {
+ p = (unsigned char *)long_option[i].name;
+ for (j=0;*p && *p != '=' && *p == cp[j];p++, j++);
+ if (*p == cp[j] || cp[j] == SP){
+ p = &cp[j] + 1;
+ break;
+ }
+ p = 0;
+ }
+ if (p == 0) {
+#if !defined(PERL_XS) && !defined(WIN32DLL)
+ fprintf(stderr, "unknown long option: --%s\n", cp);
+#endif
+ return -1;
+ }
+ while(*cp && *cp != SP && cp++);
+ if (long_option[i].alias[0]){
+ cp_back = cp;
+ cp = (unsigned char *)long_option[i].alias;
+ }else{
+#ifndef PERL_XS
+ if (strcmp(long_option[i].name, "help") == 0){
+ usage();
+ exit(EXIT_SUCCESS);
+ }
+#endif
+ if (strcmp(long_option[i].name, "ic=") == 0){
+ enc = nkf_enc_find((char *)p);
+ if (!enc) continue;
+ input_encoding = enc;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "oc=") == 0){
+ enc = nkf_enc_find((char *)p);
+ /* if (enc <= 0) continue; */
+ if (!enc) continue;
+ output_encoding = enc;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "guess=") == 0){
+ if (p[0] == '0' || p[0] == '1') {
+ guess_f = 1;
+ } else {
+ guess_f = 2;
+ }
+ continue;
+ }
+#ifdef OVERWRITE
+ if (strcmp(long_option[i].name, "overwrite") == 0){
+ file_out_f = TRUE;
+ overwrite_f = TRUE;
+ preserve_time_f = TRUE;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "overwrite=") == 0){
+ file_out_f = TRUE;
+ overwrite_f = TRUE;
+ preserve_time_f = TRUE;
+ backup_f = TRUE;
+ backup_suffix = (char *)p;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "in-place") == 0){
+ file_out_f = TRUE;
+ overwrite_f = TRUE;
+ preserve_time_f = FALSE;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "in-place=") == 0){
+ file_out_f = TRUE;
+ overwrite_f = TRUE;
+ preserve_time_f = FALSE;
+ backup_f = TRUE;
+ backup_suffix = (char *)p;
+ continue;
+ }
+#endif
+#ifdef INPUT_OPTION
+ if (strcmp(long_option[i].name, "cap-input") == 0){
+ cap_f = TRUE;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "url-input") == 0){
+ url_f = TRUE;
+ continue;
+ }
+#endif
+#ifdef NUMCHAR_OPTION
+ if (strcmp(long_option[i].name, "numchar-input") == 0){
+ numchar_f = TRUE;
+ continue;
+ }
+#endif
+#ifdef CHECK_OPTION
+ if (strcmp(long_option[i].name, "no-output") == 0){
+ noout_f = TRUE;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "debug") == 0){
+ debug_f = TRUE;
+ continue;
+ }
+#endif
+ if (strcmp(long_option[i].name, "cp932") == 0){
+#ifdef SHIFTJIS_CP932
+ cp51932_f = TRUE;
+ cp932inv_f = -TRUE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_CP932;
+#endif
+ continue;
+ }
+ if (strcmp(long_option[i].name, "no-cp932") == 0){
+#ifdef SHIFTJIS_CP932
+ cp51932_f = FALSE;
+ cp932inv_f = FALSE;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ ms_ucs_map_f = UCS_MAP_ASCII;
+#endif
+ continue;
+ }
+#ifdef SHIFTJIS_CP932
+ if (strcmp(long_option[i].name, "cp932inv") == 0){
+ cp932inv_f = -TRUE;
+ continue;
+ }
+#endif
+
+#ifdef X0212_ENABLE
+ if (strcmp(long_option[i].name, "x0212") == 0){
+ x0212_f = TRUE;
+ continue;
+ }
+#endif
+
+#ifdef EXEC_IO
+ if (strcmp(long_option[i].name, "exec-in") == 0){
+ exec_f = 1;
+ return 0;
+ }
+ if (strcmp(long_option[i].name, "exec-out") == 0){
+ exec_f = -1;
+ return 0;
+ }
+#endif
+#if defined(UTF8_OUTPUT_ENABLE) && defined(UTF8_INPUT_ENABLE)
+ if (strcmp(long_option[i].name, "no-cp932ext") == 0){
+ no_cp932ext_f = TRUE;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "no-best-fit-chars") == 0){
+ no_best_fit_chars_f = TRUE;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "fb-skip") == 0){
+ encode_fallback = NULL;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "fb-html") == 0){
+ encode_fallback = encode_fallback_html;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "fb-xml") == 0){
+ encode_fallback = encode_fallback_xml;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "fb-java") == 0){
+ encode_fallback = encode_fallback_java;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "fb-perl") == 0){
+ encode_fallback = encode_fallback_perl;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "fb-subchar") == 0){
+ encode_fallback = encode_fallback_subchar;
+ continue;
+ }
+ if (strcmp(long_option[i].name, "fb-subchar=") == 0){
+ encode_fallback = encode_fallback_subchar;
+ unicode_subchar = 0;
+ if (p[0] != '0'){
+ /* decimal number */
+ for (i = 0; i < 7 && nkf_isdigit(p[i]); i++){
+ unicode_subchar *= 10;
+ unicode_subchar += hex2bin(p[i]);
+ }
+ }else if(p[1] == 'x' || p[1] == 'X'){
+ /* hexadecimal number */
+ for (i = 2; i < 8 && nkf_isxdigit(p[i]); i++){
+ unicode_subchar <<= 4;
+ unicode_subchar |= hex2bin(p[i]);
+ }
+ }else{
+ /* octal number */
+ for (i = 1; i < 8 && nkf_isoctal(p[i]); i++){
+ unicode_subchar *= 8;
+ unicode_subchar += hex2bin(p[i]);
+ }
+ }
+ w16e_conv(unicode_subchar, &i, &j);
+ unicode_subchar = i<<8 | j;
+ continue;
+ }
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ if (strcmp(long_option[i].name, "ms-ucs-map") == 0){
+ ms_ucs_map_f = UCS_MAP_MS;
+ continue;
+ }
+#endif
+#ifdef UNICODE_NORMALIZATION
+ if (strcmp(long_option[i].name, "utf8mac-input") == 0){
+ nfc_f = TRUE;
+ continue;
+ }
+#endif
+ if (strcmp(long_option[i].name, "prefix=") == 0){
+ if (nkf_isgraph(p[0])){
+ for (i = 1; nkf_isgraph(p[i]); i++){
+ prefix_table[p[i]] = p[0];
+ }
+ }
+ continue;
+ }
+#if !defined(PERL_XS) && !defined(WIN32DLL)
+ fprintf(stderr, "unsupported long option: --%s\n", long_option[i].name);
+#endif
+ return -1;
+ }
+ continue;
+ case 'b': /* buffered mode */
+ unbuf_f = FALSE;
+ continue;
+ case 'u': /* non bufferd mode */
+ unbuf_f = TRUE;
+ continue;
+ case 't': /* transparent mode */
+ if (*cp=='1') {
+ /* alias of -t */
+ cp++;
+ nop_f = TRUE;
+ } else if (*cp=='2') {
+ /*
+ * -t with put/get
+ *
+ * nkf -t2MB hoge.bin | nkf -t2mB | diff -s - hoge.bin
+ *
+ */
+ cp++;
+ nop_f = 2;
+ } else
+ nop_f = TRUE;
+ continue;
+ case 'j': /* JIS output */
+ case 'n':
+ output_encoding = nkf_enc_from_index(ISO_2022_JP);
+ continue;
+ case 'e': /* AT&T EUC output */
+ output_encoding = nkf_enc_from_index(EUCJP_NKF);
+ continue;
+ case 's': /* SJIS output */
+ output_encoding = nkf_enc_from_index(SHIFT_JIS);
+ continue;
+ case 'l': /* ISO8859 Latin-1 support, no conversion */
+ iso8859_f = TRUE; /* Only compatible with ISO-2022-JP */
+ input_encoding = nkf_enc_from_index(ISO_8859_1);
+ continue;
+ case 'i': /* Kanji IN ESC-$-@/B */
+ if (*cp=='@'||*cp=='B')
+ kanji_intro = *cp++;
+ continue;
+ case 'o': /* ASCII IN ESC-(-J/B/H */
+ /* ESC ( H was used in initial JUNET messages */
+ if (*cp=='J'||*cp=='B'||*cp=='H')
+ ascii_intro = *cp++;
+ continue;
+ case 'h':
+ /*
+ bit:1 katakana->hiragana
+ bit:2 hiragana->katakana
+ */
+ if ('9'>= *cp && *cp>='0')
+ hira_f |= (*cp++ -'0');
+ else
+ hira_f |= 1;
+ continue;
+ case 'r':
+ rot_f = TRUE;
+ continue;
+#if defined(MSDOS) || defined(__OS2__)
+ case 'T':
+ binmode_f = FALSE;
+ continue;
+#endif
+#ifndef PERL_XS
+ case 'V':
+ show_configuration();
+ exit(EXIT_SUCCESS);
+ break;
+ case 'v':
+ version();
+ exit(EXIT_SUCCESS);
+ break;
+#endif
+#ifdef UTF8_OUTPUT_ENABLE
+ case 'w': /* UTF-{8,16,32} output */
+ if (cp[0] == '8') {
+ cp++;
+ if (cp[0] == '0'){
+ cp++;
+ output_encoding = nkf_enc_from_index(UTF_8N);
+ } else {
+ output_bom_f = TRUE;
+ output_encoding = nkf_enc_from_index(UTF_8_BOM);
+ }
+ } else {
+ int enc_idx;
+ if ('1'== cp[0] && '6'==cp[1]) {
+ cp += 2;
+ enc_idx = UTF_16;
+ } else if ('3'== cp[0] && '2'==cp[1]) {
+ cp += 2;
+ enc_idx = UTF_32;
+ } else {
+ output_encoding = nkf_enc_from_index(UTF_8);
+ continue;
+ }
+ if (cp[0]=='L') {
+ cp++;
+ output_endian = ENDIAN_LITTLE;
+ output_bom_f = TRUE;
+ } else if (cp[0] == 'B') {
+ cp++;
+ output_bom_f = TRUE;
+ }
+ if (cp[0] == '0'){
+ output_bom_f = FALSE;
+ cp++;
+ enc_idx = enc_idx == UTF_16
+ ? (output_endian == ENDIAN_LITTLE ? UTF_16LE : UTF_16BE)
+ : (output_endian == ENDIAN_LITTLE ? UTF_32LE : UTF_32BE);
+ } else {
+ enc_idx = enc_idx == UTF_16
+ ? (output_endian == ENDIAN_LITTLE ? UTF_16LE_BOM : UTF_16BE_BOM)
+ : (output_endian == ENDIAN_LITTLE ? UTF_32LE_BOM : UTF_32BE_BOM);
+ }
+ output_encoding = nkf_enc_from_index(enc_idx);
+ }
+ continue;
+#endif
+#ifdef UTF8_INPUT_ENABLE
+ case 'W': /* UTF input */
+ if (cp[0] == '8') {
+ cp++;
+ input_encoding = nkf_enc_from_index(UTF_8);
+ }else{
+ int enc_idx;
+ if ('1'== cp[0] && '6'==cp[1]) {
+ cp += 2;
+ input_endian = ENDIAN_BIG;
+ enc_idx = UTF_16;
+ } else if ('3'== cp[0] && '2'==cp[1]) {
+ cp += 2;
+ input_endian = ENDIAN_BIG;
+ enc_idx = UTF_32;
+ } else {
+ input_encoding = nkf_enc_from_index(UTF_8);
+ continue;
+ }
+ if (cp[0]=='L') {
+ cp++;
+ input_endian = ENDIAN_LITTLE;
+ } else if (cp[0] == 'B') {
+ cp++;
+ input_endian = ENDIAN_BIG;
+ }
+ enc_idx = (enc_idx == UTF_16
+ ? (input_endian == ENDIAN_LITTLE ? UTF_16LE : UTF_16BE)
+ : (input_endian == ENDIAN_LITTLE ? UTF_32LE : UTF_32BE));
+ input_encoding = nkf_enc_from_index(enc_idx);
+ }
+ continue;
+#endif
+ /* Input code assumption */
+ case 'J': /* ISO-2022-JP input */
+ input_encoding = nkf_enc_from_index(ISO_2022_JP);
+ continue;
+ case 'E': /* EUC-JP input */
+ input_encoding = nkf_enc_from_index(EUCJP_NKF);
+ continue;
+ case 'S': /* Shift_JIS input */
+ input_encoding = nkf_enc_from_index(SHIFT_JIS);
+ continue;
+ case 'Z': /* Convert X0208 alphabet to ascii */
+ /* alpha_f
+ bit:0 Convert JIS X 0208 Alphabet to ASCII
+ bit:1 Convert Kankaku to one space
+ bit:2 Convert Kankaku to two spaces
+ bit:3 Convert HTML Entity
+ bit:4 Convert JIS X 0208 Katakana to JIS X 0201 Katakana
+ */
+ while ('0'<= *cp && *cp <='4') {
+ alpha_f |= 1 << (*cp++ - '0');
+ }
+ alpha_f |= 1;
+ continue;
+ case 'x': /* Convert X0201 kana to X0208 or X0201 Conversion */
+ x0201_f = FALSE; /* No X0201->X0208 conversion */
+ /* accept X0201
+ ESC-(-I in JIS, EUC, MS Kanji
+ SI/SO in JIS, EUC, MS Kanji
+ SS2 in EUC, JIS, not in MS Kanji
+ MS Kanji (0xa0-0xdf)
+ output X0201
+ ESC-(-I in JIS (0x20-0x5f)
+ SS2 in EUC (0xa0-0xdf)
+ 0xa0-0xd in MS Kanji (0xa0-0xdf)
+ */
+ continue;
+ case 'X': /* Convert X0201 kana to X0208 */
+ x0201_f = TRUE;
+ continue;
+ case 'F': /* prserve new lines */
+ fold_preserve_f = TRUE;
+ case 'f': /* folding -f60 or -f */
+ fold_f = TRUE;
+ fold_len = 0;
+ while('0'<= *cp && *cp <='9') { /* we don't use atoi here */
+ fold_len *= 10;
+ fold_len += *cp++ - '0';
+ }
+ if (!(0<fold_len && fold_len<BUFSIZ))
+ fold_len = DEFAULT_FOLD;
+ if (*cp=='-') {
+ fold_margin = 0;
+ cp++;
+ while('0'<= *cp && *cp <='9') { /* we don't use atoi here */
+ fold_margin *= 10;
+ fold_margin += *cp++ - '0';
+ }
+ }
+ continue;
+ case 'm': /* MIME support */
+ /* mime_decode_f = TRUE; */ /* this has too large side effects... */
+ if (*cp=='B'||*cp=='Q') {
+ mime_decode_mode = *cp++;
+ mimebuf_f = FIXED_MIME;
+ } else if (*cp=='N') {
+ mime_f = TRUE; cp++;
+ } else if (*cp=='S') {
+ mime_f = STRICT_MIME; cp++;
+ } else if (*cp=='0') {
+ mime_decode_f = FALSE;
+ mime_f = FALSE; cp++;
+ } else {
+ mime_f = STRICT_MIME;
+ }
+ continue;
+ case 'M': /* MIME output */
+ if (*cp=='B') {
+ mimeout_mode = 'B';
+ mimeout_f = FIXED_MIME; cp++;
+ } else if (*cp=='Q') {
+ mimeout_mode = 'Q';
+ mimeout_f = FIXED_MIME; cp++;
+ } else {
+ mimeout_f = TRUE;
+ }
+ continue;
+ case 'B': /* Broken JIS support */
+ /* bit:0 no ESC JIS
+ bit:1 allow any x on ESC-(-x or ESC-$-x
+ bit:2 reset to ascii on NL
+ */
+ if ('9'>= *cp && *cp>='0')
+ broken_f |= 1<<(*cp++ -'0');
+ else
+ broken_f |= TRUE;
+ continue;
+#ifndef PERL_XS
+ case 'O':/* for Output file */
+ file_out_f = TRUE;
+ continue;
+#endif
+ case 'c':/* add cr code */
+ eolmode_f = CRLF;
+ continue;
+ case 'd':/* delete cr code */
+ eolmode_f = LF;
+ continue;
+ case 'I': /* ISO-2022-JP output */
+ iso2022jp_f = TRUE;
+ continue;
+ case 'L': /* line mode */
+ if (*cp=='u') { /* unix */
+ eolmode_f = LF; cp++;
+ } else if (*cp=='m') { /* mac */
+ eolmode_f = CR; cp++;
+ } else if (*cp=='w') { /* windows */
+ eolmode_f = CRLF; cp++;
+ } else if (*cp=='0') { /* no conversion */
+ eolmode_f = 0; cp++;
+ }
+ continue;
+#ifndef PERL_XS
+ case 'g':
+ if ('2' <= *cp && *cp <= '9') {
+ guess_f = 2;
+ cp++;
+ } else if (*cp == '0' || *cp == '1') {
+ guess_f = 1;
+ cp++;
+ } else {
+ guess_f = 1;
+ }
+ continue;
+#endif
+ case SP:
+ /* module multiple options in a string are allowed for Perl module */
+ while(*cp && *cp++!='-');
+ continue;
+ default:
+#if !defined(PERL_XS) && !defined(WIN32DLL)
+ fprintf(stderr, "unknown option: -%c\n", *(cp-1));
+#endif
+ /* bogus option but ignored */
+ return -1;
+ }
+ }
+ return 0;
+}
+
+#ifdef WIN32DLL
+#include "nkf32dll.c"
+#elif defined(PERL_XS)
+#else /* WIN32DLL */
+int
+main(int argc, char **argv)
+{
+ FILE *fin;
+ unsigned char *cp;
+
+ char *outfname = NULL;
+ char *origfname;
+
+#ifdef EASYWIN /*Easy Win */
+ _BufferSize.y = 400;/*Set Scroll Buffer Size*/
+#endif
+#ifdef DEFAULT_CODE_LOCALE
+ setlocale(LC_CTYPE, "");
+#endif
+ nkf_state_init();
+
+ for (argc--,argv++; (argc > 0) && **argv == '-'; argc--, argv++) {
+ cp = (unsigned char *)*argv;
+ options(cp);
+#ifdef EXEC_IO
+ if (exec_f){
+ int fds[2], pid;
+ if (pipe(fds) < 0 || (pid = fork()) < 0){
+ abort();
+ }
+ if (pid == 0){
+ if (exec_f > 0){
+ close(fds[0]);
+ dup2(fds[1], 1);
+ }else{
+ close(fds[1]);
+ dup2(fds[0], 0);
+ }
+ execvp(argv[1], &argv[1]);
+ }
+ if (exec_f > 0){
+ close(fds[1]);
+ dup2(fds[0], 0);
+ }else{
+ close(fds[0]);
+ dup2(fds[1], 1);
+ }
+ argc = 0;
+ break;
+ }
+#endif
+ }
+
+ if (guess_f) {
+#ifdef CHECK_OPTION
+ int debug_f_back = debug_f;
+#endif
+#ifdef EXEC_IO
+ int exec_f_back = exec_f;
+#endif
+#ifdef X0212_ENABLE
+ int x0212_f_back = x0212_f;
+#endif
+ int x0213_f_back = x0213_f;
+ int guess_f_back = guess_f;
+ reinit();
+ guess_f = guess_f_back;
+ mime_f = FALSE;
+#ifdef CHECK_OPTION
+ debug_f = debug_f_back;
+#endif
+#ifdef EXEC_IO
+ exec_f = exec_f_back;
+#endif
+ x0212_f = x0212_f_back;
+ x0213_f = x0213_f_back;
+ }
+
+ if (binmode_f == TRUE)
+#if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__))
+ if (freopen("","wb",stdout) == NULL)
+ return (-1);
+#else
+ setbinmode(stdout);
+#endif
+
+ if (unbuf_f)
+ setbuf(stdout, (char *) NULL);
+ else
+ setvbuffer(stdout, (char *) stdobuf, IOBUF_SIZE);
+
+ if (argc == 0) {
+ if (binmode_f == TRUE)
+#if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__))
+ if (freopen("","rb",stdin) == NULL) return (-1);
+#else
+ setbinmode(stdin);
+#endif
+ setvbuffer(stdin, (char *) stdibuf, IOBUF_SIZE);
+ if (nop_f)
+ noconvert(stdin);
+ else {
+ kanji_convert(stdin);
+ if (guess_f) print_guessed_code(NULL);
+ }
+ } else {
+ int nfiles = argc;
+ int is_argument_error = FALSE;
+ while (argc--) {
+ input_codename = NULL;
+ input_eol = 0;
+#ifdef CHECK_OPTION
+ iconv_for_check = 0;
+#endif
+ if ((fin = fopen((origfname = *argv++), "r")) == NULL) {
+ perror(*(argv-1));
+ is_argument_error = TRUE;
+ continue;
+ } else {
+#ifdef OVERWRITE
+ int fd = 0;
+ int fd_backup = 0;
+#endif
+
+ /* reopen file for stdout */
+ if (file_out_f == TRUE) {
+#ifdef OVERWRITE
+ if (overwrite_f){
+ outfname = nkf_xmalloc(strlen(origfname)
+ + strlen(".nkftmpXXXXXX")
+ + 1);
+ strcpy(outfname, origfname);
+#ifdef MSDOS
+ {
+ int i;
+ for (i = strlen(outfname); i; --i){
+ if (outfname[i - 1] == '/'
+ || outfname[i - 1] == '\\'){
+ break;
+ }
+ }
+ outfname[i] = '\0';
+ }
+ strcat(outfname, "ntXXXXXX");
+ mktemp(outfname);
+ fd = open(outfname, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
+ S_IREAD | S_IWRITE);
+#else
+ strcat(outfname, ".nkftmpXXXXXX");
+ fd = mkstemp(outfname);
+#endif
+ if (fd < 0
+ || (fd_backup = dup(fileno(stdout))) < 0
+ || dup2(fd, fileno(stdout)) < 0
+ ){
+ perror(origfname);
+ return -1;
+ }
+ }else
+#endif
+ if(argc == 1) {
+ outfname = *argv++;
+ argc--;
+ } else {
+ outfname = "nkf.out";
+ }
+
+ if(freopen(outfname, "w", stdout) == NULL) {
+ perror (outfname);
+ return (-1);
+ }
+ if (binmode_f == TRUE) {
+#if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__))
+ if (freopen("","wb",stdout) == NULL)
+ return (-1);
+#else
+ setbinmode(stdout);
+#endif
+ }
+ }
+ if (binmode_f == TRUE)
+#if defined(__OS2__) && (defined(__IBMC__) || defined(__IBMCPP__))
+ if (freopen("","rb",fin) == NULL)
+ return (-1);
+#else
+ setbinmode(fin);
+#endif
+ setvbuffer(fin, (char *) stdibuf, IOBUF_SIZE);
+ if (nop_f)
+ noconvert(fin);
+ else {
+ char *filename = NULL;
+ kanji_convert(fin);
+ if (nfiles > 1) filename = origfname;
+ if (guess_f) print_guessed_code(filename);
+ }
+ fclose(fin);
+#ifdef OVERWRITE
+ if (overwrite_f) {
+ struct stat sb;
+#if defined(MSDOS) && !defined(__MINGW32__) && !defined(__WIN32__) && !defined(__WATCOMC__) && !defined(__EMX__) && !defined(__OS2__) && !defined(__DJGPP__)
+ time_t tb[2];
+#else
+ struct utimbuf tb;
+#endif
+
+ fflush(stdout);
+ close(fd);
+ if (dup2(fd_backup, fileno(stdout)) < 0){
+ perror("dup2");
+ }
+ if (stat(origfname, &sb)) {
+ fprintf(stderr, "Can't stat %s\n", origfname);
+ }
+ /* $B%Q!<%_%C%7%g%s$rI|85(B */
+ if (chmod(outfname, sb.st_mode)) {
+ fprintf(stderr, "Can't set permission %s\n", outfname);
+ }
+
+ /* $B%?%$%`%9%?%s%W$rI|85(B */
+ if(preserve_time_f){
+#if defined(MSDOS) && !defined(__MINGW32__) && !defined(__WIN32__) && !defined(__WATCOMC__) && !defined(__EMX__) && !defined(__OS2__) && !defined(__DJGPP__)
+ tb[0] = tb[1] = sb.st_mtime;
+ if (utime(outfname, tb)) {
+ fprintf(stderr, "Can't set timestamp %s\n", outfname);
+ }
+#else
+ tb.actime = sb.st_atime;
+ tb.modtime = sb.st_mtime;
+ if (utime(outfname, &tb)) {
+ fprintf(stderr, "Can't set timestamp %s\n", outfname);
+ }
+#endif
+ }
+ if(backup_f){
+ char *backup_filename = get_backup_filename(backup_suffix, origfname);
+#ifdef MSDOS
+ unlink(backup_filename);
+#endif
+ if (rename(origfname, backup_filename)) {
+ perror(backup_filename);
+ fprintf(stderr, "Can't rename %s to %s\n",
+ origfname, backup_filename);
+ }
+ nkf_xfree(backup_filename);
+ }else{
+#ifdef MSDOS
+ if (unlink(origfname)){
+ perror(origfname);
+ }
+#endif
+ }
+ if (rename(outfname, origfname)) {
+ perror(origfname);
+ fprintf(stderr, "Can't rename %s to %s\n",
+ outfname, origfname);
+ }
+ nkf_xfree(outfname);
+ }
+#endif
+ }
+ }
+ if (is_argument_error)
+ return(-1);
+ }
+#ifdef EASYWIN /*Easy Win */
+ if (file_out_f == FALSE)
+ scanf("%d",&end_check);
+ else
+ fclose(stdout);
+#else /* for Other OS */
+ if (file_out_f == TRUE)
+ fclose(stdout);
+#endif /*Easy Win */
+ return (0);
+}
+#endif /* WIN32DLL */
diff --git a/ext/nkf/nkf-utf8/nkf.h b/ext/nkf/nkf-utf8/nkf.h
new file mode 100644
index 0000000000..b3a520da54
--- /dev/null
+++ b/ext/nkf/nkf-utf8/nkf.h
@@ -0,0 +1,189 @@
+/*
+ *
+ * nkf.h - Header file for nkf
+ *
+ */
+
+#ifndef NKF_H
+#define NKF_H
+
+/* Wrapper of configurations */
+
+#ifndef MIME_DECODE_DEFAULT
+#define MIME_DECODE_DEFAULT STRICT_MIME
+#endif
+#ifndef X0201_DEFAULT
+#define X0201_DEFAULT TRUE
+#endif
+
+#if defined(DEFAULT_NEWLINE) && DEFAULT_NEWLINE == 0x0D0A
+#elif defined(DEFAULT_NEWLINE) && DEFAULT_NEWLINE == 0x0D
+#else
+#define DEFAULT_NEWLINE 0x0A
+#endif
+#ifdef HELP_OUTPUT_STDERR
+#define HELP_OUTPUT stderr
+#else
+#define HELP_OUTPUT stdout
+#endif
+
+
+/* Compatibility definitions */
+
+#ifdef nkf_char
+#elif defined(INT_IS_SHORT)
+typedef long nkf_char;
+#define NKF_INT32_C(n) (n##L)
+#else
+typedef int nkf_char;
+#define NKF_INT32_C(n) (n)
+#endif
+
+#if (defined(__TURBOC__) || defined(_MSC_VER) || defined(LSI_C) || (defined(__WATCOMC__) && defined(__386__) && !defined(__LINUX__)) || defined(__MINGW32__) || defined(__EMX__) || defined(__MSDOS__) || defined(__WINDOWS__) || defined(__DOS__) || defined(__OS2__)) && !defined(MSDOS)
+#define MSDOS
+#if (defined(__Win32__) || defined(_WIN32)) && !defined(__WIN32__)
+#define __WIN32__
+#endif
+#endif
+
+#ifdef PERL_XS
+#undef OVERWRITE
+#endif
+
+#ifndef PERL_XS
+#include <stdio.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(MSDOS) || defined(__OS2__)
+#include <fcntl.h>
+#include <io.h>
+#if defined(_MSC_VER) || defined(__WATCOMC__)
+#define mktemp _mktemp
+#endif
+#endif
+
+#ifdef MSDOS
+#ifdef LSI_C
+#define setbinmode(fp) fsetbin(fp)
+#elif defined(__DJGPP__)
+#include <libc/dosio.h>
+void setbinmode(FILE *fp)
+{
+ /* we do not use libc's setmode(), which changes COOKED/RAW mode in device. */
+ int fd, m;
+ fd = fileno(fp);
+ m = (__file_handle_modes[fd] & (~O_TEXT)) | O_BINARY;
+ __file_handle_set(fd, m);
+}
+#else /* Microsoft C, Turbo C */
+#define setbinmode(fp) setmode(fileno(fp), O_BINARY)
+#endif
+#else /* UNIX */
+#define setbinmode(fp) (void)(fp)
+#endif
+
+#ifdef _IOFBF /* SysV and MSDOS, Windows */
+#define setvbuffer(fp, buf, size) setvbuf(fp, buf, _IOFBF, size)
+#else /* BSD */
+#define setvbuffer(fp, buf, size) setbuffer(fp, buf, size)
+#endif
+
+/*Borland C++ 4.5 EasyWin*/
+#if defined(__TURBOC__) && defined(_Windows) && !defined(__WIN32__) /*Easy Win */
+#define EASYWIN
+#ifndef __WIN16__
+#define __WIN16__
+#endif
+#include <windows.h>
+#endif
+
+#ifdef OVERWRITE
+/* added by satoru@isoternet.org */
+#if defined(__EMX__)
+#include <sys/types.h>
+#endif
+#include <sys/stat.h>
+#if !defined(MSDOS) || defined(__DJGPP__) /* UNIX, djgpp */
+#include <unistd.h>
+#if defined(__WATCOMC__)
+#include <sys/utime.h>
+#else
+#include <utime.h>
+#endif
+#else /* defined(MSDOS) */
+#ifdef __WIN32__
+#ifdef __BORLANDC__ /* BCC32 */
+#include <utime.h>
+#else /* !defined(__BORLANDC__) */
+#include <sys/utime.h>
+#endif /* (__BORLANDC__) */
+#else /* !defined(__WIN32__) */
+#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__WATCOMC__) || defined(__OS2__) || defined(__EMX__) || defined(__IBMC__) || defined(__IBMCPP__) /* VC++, MinGW, Watcom, emx+gcc, IBM VAC++ */
+#include <sys/utime.h>
+#elif defined(__TURBOC__) /* BCC */
+#include <utime.h>
+#elif defined(LSI_C) /* LSI C */
+#endif /* (__WIN32__) */
+#endif
+#endif
+#endif
+
+#if !defined(DEFAULT_CODE_JIS) && !defined(DEFAULT_CODE_SJIS) && \
+ !defined(DEFAULT_CODE_WINDOWS_31J) && !defined(DEFAULT_CODE_EUC) && \
+ !defined(DEFAULT_CODE_UTF8) && !defined(DEFAULT_CODE_LOCALE)
+#define DEFAULT_CODE_LOCALE
+#endif
+
+#ifdef DEFAULT_CODE_LOCALE
+
+#if defined(__WIN32__) /* not win32 should be posix */
+# ifndef HAVE_LOCALE_H
+# define HAVE_LOCALE_H
+# endif
+#elif defined(__OS2__)
+# undef HAVE_LANGINFO_H /* We do not use kLIBC's langinfo. */
+# ifndef HAVE_LOCALE_H
+# define HAVE_LOCALE_H
+# endif
+#elif defined(MSDOS)
+# ifndef HAVE_LOCALE_H
+# define HAVE_LOCALE_H
+# endif
+#elif defined(__BIONIC__) /* bionic doesn't have locale */
+#else
+# ifndef HAVE_LANGINFO_H
+# define HAVE_LANGINFO_H
+# endif
+# ifndef HAVE_LOCALE_H
+# define HAVE_LOCALE_H
+# endif
+#endif
+
+#ifdef HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#endif /* DEFAULT_CODE_LOCALE */
+
+#define FALSE 0
+#define TRUE 1
+
+#ifndef ARG_UNUSED
+#if defined(__GNUC__)
+# define ARG_UNUSED __attribute__ ((unused))
+#else
+# define ARG_UNUSED
+#endif
+#endif
+
+#ifdef WIN32DLL
+#include "nkf32.h"
+#endif
+
+#endif /* NKF_H */
diff --git a/ext/nkf/nkf-utf8/utf8tbl.c b/ext/nkf/nkf-utf8/utf8tbl.c
new file mode 100644
index 0000000000..a31e4e7805
--- /dev/null
+++ b/ext/nkf/nkf-utf8/utf8tbl.c
@@ -0,0 +1,14638 @@
+/*
+ * utf8tbl.c - Conversion Table for nkf
+ *
+ */
+
+#include "config.h"
+#include "utf8tbl.h"
+
+#ifdef UTF8_OUTPUT_ENABLE
+static const unsigned short euc_to_utf8_A1[] = {
+ 0x3000, 0x3001, 0x3002, 0xFF0C, 0xFF0E, 0x30FB, 0xFF1A,
+ 0xFF1B, 0xFF1F, 0xFF01, 0x309B, 0x309C, 0x00B4, 0xFF40, 0x00A8,
+ 0xFF3E, 0x203E, 0xFF3F, 0x30FD, 0x30FE, 0x309D, 0x309E, 0x3003,
+ 0x4EDD, 0x3005, 0x3006, 0x3007, 0x30FC, 0x2014, 0x2010, 0xFF0F,
+ 0xFF3C, 0x301C, 0x2016, 0xFF5C, 0x2026, 0x2025, 0x2018, 0x2019,
+ 0x201C, 0x201D, 0xFF08, 0xFF09, 0x3014, 0x3015, 0xFF3B, 0xFF3D,
+ 0xFF5B, 0xFF5D, 0x3008, 0x3009, 0x300A, 0x300B, 0x300C, 0x300D,
+ 0x300E, 0x300F, 0x3010, 0x3011, 0xFF0B, 0x2212, 0x00B1, 0x00D7,
+ 0x00F7, 0xFF1D, 0x2260, 0xFF1C, 0xFF1E, 0x2266, 0x2267, 0x221E,
+ 0x2234, 0x2642, 0x2640, 0x00B0, 0x2032, 0x2033, 0x2103, 0x00A5,
+ 0xFF04, 0x00A2, 0x00A3, 0xFF05, 0xFF03, 0xFF06, 0xFF0A, 0xFF20,
+ 0x00A7, 0x2606, 0x2605, 0x25CB, 0x25CF, 0x25CE, 0x25C7,
+};
+
+/* Microsoft UCS Mapping Compatible */
+static const unsigned short euc_to_utf8_A1_ms[] = {
+ 0x3000, 0x3001, 0x3002, 0xFF0C, 0xFF0E, 0x30FB, 0xFF1A,
+ 0xFF1B, 0xFF1F, 0xFF01, 0x309B, 0x309C, 0x00B4, 0xFF40, 0x00A8,
+ 0xFF3E, 0xFFE3, 0xFF3F, 0x30FD, 0x30FE, 0x309D, 0x309E, 0x3003,
+ 0x4EDD, 0x3005, 0x3006, 0x3007, 0x30FC, 0x2015, 0x2010, 0xFF0F,
+ 0xFF3C, 0xFF5E, 0x2225, 0xFF5C, 0x2026, 0x2025, 0x2018, 0x2019,
+ 0x201C, 0x201D, 0xFF08, 0xFF09, 0x3014, 0x3015, 0xFF3B, 0xFF3D,
+ 0xFF5B, 0xFF5D, 0x3008, 0x3009, 0x300A, 0x300B, 0x300C, 0x300D,
+ 0x300E, 0x300F, 0x3010, 0x3011, 0xFF0B, 0xFF0D, 0x00B1, 0x00D7,
+ 0x00F7, 0xFF1D, 0x2260, 0xFF1C, 0xFF1E, 0x2266, 0x2267, 0x221E,
+ 0x2234, 0x2642, 0x2640, 0x00B0, 0x2032, 0x2033, 0x2103, 0xFFE5,
+ 0xFF04, 0xFFE0, 0xFFE1, 0xFF05, 0xFF03, 0xFF06, 0xFF0A, 0xFF20,
+ 0x00A7, 0x2606, 0x2605, 0x25CB, 0x25CF, 0x25CE, 0x25C7,
+};
+static const unsigned short euc_to_utf8_A2[] = {
+ 0x25C6, 0x25A1, 0x25A0, 0x25B3, 0x25B2, 0x25BD, 0x25BC,
+ 0x203B, 0x3012, 0x2192, 0x2190, 0x2191, 0x2193, 0x3013, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2208, 0x220B, 0x2286, 0x2287, 0x2282, 0x2283,
+ 0x222A, 0x2229, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2227, 0x2228, 0x00AC, 0x21D2, 0x21D4, 0x2200,
+ 0x2203, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x2220, 0x22A5, 0x2312, 0x2202,
+ 0x2207, 0x2261, 0x2252, 0x226A, 0x226B, 0x221A, 0x223D, 0x221D,
+ 0x2235, 0x222B, 0x222C, 0, 0, 0, 0, 0,
+ 0, 0, 0x212B, 0x2030, 0x266F, 0x266D, 0x266A, 0x2020,
+ 0x2021, 0x00B6, 0, 0, 0, 0, 0x25EF,
+};
+
+/* Microsoft UCS Mapping Compatible */
+static const unsigned short euc_to_utf8_A2_ms[] = {
+ 0x25C6, 0x25A1, 0x25A0, 0x25B3, 0x25B2, 0x25BD, 0x25BC,
+ 0x203B, 0x3012, 0x2192, 0x2190, 0x2191, 0x2193, 0x3013, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2208, 0x220B, 0x2286, 0x2287, 0x2282, 0x2283,
+ 0x222A, 0x2229, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2227, 0x2228, 0xFFE2, 0x21D2, 0x21D4, 0x2200,
+ 0x2203, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x2220, 0x22A5, 0x2312, 0x2202,
+ 0x2207, 0x2261, 0x2252, 0x226A, 0x226B, 0x221A, 0x223D, 0x221D,
+ 0x2235, 0x222B, 0x222C, 0, 0, 0, 0, 0,
+ 0, 0, 0x212B, 0x2030, 0x266F, 0x266D, 0x266A, 0x2020,
+ 0x2021, 0x00B6, 0, 0, 0, 0, 0x25EF,
+};
+static const unsigned short euc_to_utf8_A2_x0213[] = {
+ 0x25C6, 0x25A1, 0x25A0, 0x25B3, 0x25B2, 0x25BD, 0x25BC,
+ 0x203B, 0x3012, 0x2192, 0x2190, 0x2191, 0x2193, 0x3013, 0xFF07,
+ 0xFF02, 0xFF0D, 0xFF5E, 0x3033, 0x3034, 0x3035, 0x303B, 0x303C,
+ 0x30FF, 0x309F, 0x2208, 0x220B, 0x2286, 0x2287, 0x2282, 0x2283,
+ 0x222A, 0x2229, 0x2284, 0x2285, 0x228A, 0x228B, 0x2209, 0x2205,
+ 0x2305, 0x2306, 0x2227, 0x2228, 0x00AC, 0x21D2, 0x21D4, 0x2200,
+ 0x2203, 0x2295, 0x2296, 0x2297, 0x2225, 0x2226, 0xFF5F, 0xFF60,
+ 0x3018, 0x3019, 0x3016, 0x3017, 0x2220, 0x22A5, 0x2312, 0x2202,
+ 0x2207, 0x2261, 0x2252, 0x226A, 0x226B, 0x221A, 0x223D, 0x221D,
+ 0x2235, 0x222B, 0x222C, 0x2262, 0x2243, 0x2245, 0x2248, 0x2276,
+ 0x2277, 0x2194, 0x212B, 0x2030, 0x266F, 0x266D, 0x266A, 0x2020,
+ 0x2021, 0x00B6, 0x266E, 0x266B, 0x266C, 0x2669, 0x25EF,
+};
+static const unsigned short euc_to_utf8_A3[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17,
+ 0xFF18, 0xFF19, 0, 0, 0, 0, 0, 0,
+ 0, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27,
+ 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F,
+ 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37,
+ 0xFF38, 0xFF39, 0xFF3A, 0, 0, 0, 0, 0,
+ 0, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47,
+ 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57,
+ 0xFF58, 0xFF59, 0xFF5A, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_A3_x0213[] = {
+ 0x25B7, 0x25B6, 0x25C1, 0x25C0, 0x2197, 0x2198, 0x2196,
+ 0x2199, 0x21C4, 0x21E8, 0x21E6, 0x21E7, 0x21E9, 0x2934, 0x2935,
+ 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17,
+ 0xFF18, 0xFF19, 0x29BF, 0x25C9, 0x303D, 0xFE46, 0xFE45, 0x25E6,
+ 0x2022, 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27,
+ 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F,
+ 0xFF30, 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37,
+ 0xFF38, 0xFF39, 0xFF3A, 0x2213, 0x2135, 0x210F, 0x33CB, 0x2113,
+ 0x2127, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47,
+ 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57,
+ 0xFF58, 0xFF59, 0xFF5A, 0x30A0, 0x2013, 0x29FA, 0x29FB,
+};
+static const unsigned short euc_to_utf8_A4[] = {
+ 0x3041, 0x3042, 0x3043, 0x3044, 0x3045, 0x3046, 0x3047,
+ 0x3048, 0x3049, 0x304A, 0x304B, 0x304C, 0x304D, 0x304E, 0x304F,
+ 0x3050, 0x3051, 0x3052, 0x3053, 0x3054, 0x3055, 0x3056, 0x3057,
+ 0x3058, 0x3059, 0x305A, 0x305B, 0x305C, 0x305D, 0x305E, 0x305F,
+ 0x3060, 0x3061, 0x3062, 0x3063, 0x3064, 0x3065, 0x3066, 0x3067,
+ 0x3068, 0x3069, 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, 0x306F,
+ 0x3070, 0x3071, 0x3072, 0x3073, 0x3074, 0x3075, 0x3076, 0x3077,
+ 0x3078, 0x3079, 0x307A, 0x307B, 0x307C, 0x307D, 0x307E, 0x307F,
+ 0x3080, 0x3081, 0x3082, 0x3083, 0x3084, 0x3085, 0x3086, 0x3087,
+ 0x3088, 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, 0x308E, 0x308F,
+ 0x3090, 0x3091, 0x3092, 0x3093, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_A4_x0213[] = {
+ 0x3041, 0x3042, 0x3043, 0x3044, 0x3045, 0x3046, 0x3047,
+ 0x3048, 0x3049, 0x304A, 0x304B, 0x304C, 0x304D, 0x304E, 0x304F,
+ 0x3050, 0x3051, 0x3052, 0x3053, 0x3054, 0x3055, 0x3056, 0x3057,
+ 0x3058, 0x3059, 0x305A, 0x305B, 0x305C, 0x305D, 0x305E, 0x305F,
+ 0x3060, 0x3061, 0x3062, 0x3063, 0x3064, 0x3065, 0x3066, 0x3067,
+ 0x3068, 0x3069, 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, 0x306F,
+ 0x3070, 0x3071, 0x3072, 0x3073, 0x3074, 0x3075, 0x3076, 0x3077,
+ 0x3078, 0x3079, 0x307A, 0x307B, 0x307C, 0x307D, 0x307E, 0x307F,
+ 0x3080, 0x3081, 0x3082, 0x3083, 0x3084, 0x3085, 0x3086, 0x3087,
+ 0x3088, 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, 0x308E, 0x308F,
+ 0x3090, 0x3091, 0x3092, 0x3093, 0x3094, 0x3095, 0x3096, /*0x304B*/ 0x309A,
+ /*0x304D*/ 0x309A, /*0x304F*/ 0x309A, /*0x3051*/ 0x309A, /*0x3053*/ 0x309A, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_A5[] = {
+ 0x30A1, 0x30A2, 0x30A3, 0x30A4, 0x30A5, 0x30A6, 0x30A7,
+ 0x30A8, 0x30A9, 0x30AA, 0x30AB, 0x30AC, 0x30AD, 0x30AE, 0x30AF,
+ 0x30B0, 0x30B1, 0x30B2, 0x30B3, 0x30B4, 0x30B5, 0x30B6, 0x30B7,
+ 0x30B8, 0x30B9, 0x30BA, 0x30BB, 0x30BC, 0x30BD, 0x30BE, 0x30BF,
+ 0x30C0, 0x30C1, 0x30C2, 0x30C3, 0x30C4, 0x30C5, 0x30C6, 0x30C7,
+ 0x30C8, 0x30C9, 0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, 0x30CF,
+ 0x30D0, 0x30D1, 0x30D2, 0x30D3, 0x30D4, 0x30D5, 0x30D6, 0x30D7,
+ 0x30D8, 0x30D9, 0x30DA, 0x30DB, 0x30DC, 0x30DD, 0x30DE, 0x30DF,
+ 0x30E0, 0x30E1, 0x30E2, 0x30E3, 0x30E4, 0x30E5, 0x30E6, 0x30E7,
+ 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x30EF,
+ 0x30F0, 0x30F1, 0x30F2, 0x30F3, 0x30F4, 0x30F5, 0x30F6, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_A5_x0213[] = {
+ 0x30A1, 0x30A2, 0x30A3, 0x30A4, 0x30A5, 0x30A6, 0x30A7,
+ 0x30A8, 0x30A9, 0x30AA, 0x30AB, 0x30AC, 0x30AD, 0x30AE, 0x30AF,
+ 0x30B0, 0x30B1, 0x30B2, 0x30B3, 0x30B4, 0x30B5, 0x30B6, 0x30B7,
+ 0x30B8, 0x30B9, 0x30BA, 0x30BB, 0x30BC, 0x30BD, 0x30BE, 0x30BF,
+ 0x30C0, 0x30C1, 0x30C2, 0x30C3, 0x30C4, 0x30C5, 0x30C6, 0x30C7,
+ 0x30C8, 0x30C9, 0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, 0x30CF,
+ 0x30D0, 0x30D1, 0x30D2, 0x30D3, 0x30D4, 0x30D5, 0x30D6, 0x30D7,
+ 0x30D8, 0x30D9, 0x30DA, 0x30DB, 0x30DC, 0x30DD, 0x30DE, 0x30DF,
+ 0x30E0, 0x30E1, 0x30E2, 0x30E3, 0x30E4, 0x30E5, 0x30E6, 0x30E7,
+ 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x30EF,
+ 0x30F0, 0x30F1, 0x30F2, 0x30F3, 0x30F4, 0x30F5, 0x30F6, /*0x30AB*/ 0x309A,
+ /*0x30AD*/ 0x309A, /*0x30AF*/ 0x309A, /*0x30B1*/ 0x309A, /*0x30B3*/ 0x309A, /*0x30BB*/ 0x309A, /*0x30C4*/ 0x309A, /*0x30C8*/ 0x309A,
+};
+static const unsigned short euc_to_utf8_A6[] = {
+ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+ 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
+ 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8,
+ 0x03A9, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+ 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+ 0x03C0, 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
+ 0x03C9, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_A6_x0213[] = {
+ 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+ 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
+ 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8,
+ 0x03A9, 0x2664, 0x2660, 0x2662, 0x2666, 0x2661, 0x2665, 0x2667,
+ 0x2663, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+ 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+ 0x03C0, 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
+ 0x03C9, 0x03C2, 0x24F5, 0x24F6, 0x24F7, 0x24F8, 0x24F9, 0x24FA,
+ 0x24FB, 0x24FC, 0x24FD, 0x24FE, 0x2616, 0x2617, 0x3020, 0x260E,
+ 0x2600, 0x2601, 0x2602, 0x2603, 0x2668, 0x25B1, 0x31F0, 0x31F1,
+ 0x31F2, 0x31F3, 0x31F4, 0x31F5, 0x31F6, 0x31F7, 0x31F8, 0x31F9,
+ /*0x31F7*/ 0x309A, 0x31FA, 0x31FB, 0x31FC, 0x31FD, 0x31FE, 0x31FF,
+};
+static const unsigned short euc_to_utf8_A7[] = {
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0401,
+ 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D,
+ 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425,
+ 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D,
+ 0x042E, 0x042F, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0451,
+ 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D,
+ 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445,
+ 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D,
+ 0x044E, 0x044F, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_A7_x0213[] = {
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0401,
+ 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D,
+ 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425,
+ 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D,
+ 0x042E, 0x042F, 0x23BE, 0x23BF, 0x23C0, 0x23C1, 0x23C2, 0x23C3,
+ 0x23C4, 0x23C5, 0x23C6, 0x23C7, 0x23C8, 0x23C9, 0x23CA, 0x23CB,
+ 0x23CC, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0451,
+ 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D,
+ 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445,
+ 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D,
+ 0x044E, 0x044F, 0x30F7, 0x30F8, 0x30F9, 0x30FA, 0x22DA, 0x22DB,
+ 0x2153, 0x2154, 0x2155, 0x2713, 0x2318, 0x2423, 0x23CE,
+};
+static const unsigned short euc_to_utf8_A8[] = {
+ 0x2500, 0x2502, 0x250C, 0x2510, 0x2518, 0x2514, 0x251C,
+ 0x252C, 0x2524, 0x2534, 0x253C, 0x2501, 0x2503, 0x250F, 0x2513,
+ 0x251B, 0x2517, 0x2523, 0x2533, 0x252B, 0x253B, 0x254B, 0x2520,
+ 0x252F, 0x2528, 0x2537, 0x253F, 0x251D, 0x2530, 0x2525, 0x2538,
+ 0x2542, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_A8_x0213[] = {
+ 0x2500, 0x2502, 0x250C, 0x2510, 0x2518, 0x2514, 0x251C,
+ 0x252C, 0x2524, 0x2534, 0x253C, 0x2501, 0x2503, 0x250F, 0x2513,
+ 0x251B, 0x2517, 0x2523, 0x2533, 0x252B, 0x253B, 0x254B, 0x2520,
+ 0x252F, 0x2528, 0x2537, 0x253F, 0x251D, 0x2530, 0x2525, 0x2538,
+ 0x2542, 0x3251, 0x3252, 0x3253, 0x3254, 0x3255, 0x3256, 0x3257,
+ 0x3258, 0x3259, 0x325A, 0x325B, 0x325C, 0x325D, 0x325E, 0x325F,
+ 0x32B1, 0x32B2, 0x32B3, 0x32B4, 0x32B5, 0x32B6, 0x32B7, 0x32B8,
+ 0x32B9, 0x32BA, 0x32BB, 0x32BC, 0x32BD, 0x32BE, 0x32BF, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x25D0,
+ 0x25D1, 0x25D2, 0x25D3, 0x203C, 0x2047, 0x2048, 0x2049, 0x01CD,
+ 0x01CE, 0x01D0, 0x1E3E, 0x1E3F, 0x01F8, 0x01F9, 0x01D1, 0x01D2,
+ 0x01D4, 0x01D6, 0x01D8, 0x01DA, 0x01DC, 0, 0,
+};
+static const unsigned short euc_to_utf8_A9[] = {
+ 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466,
+ 0x2467, 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E,
+ 0x246F, 0x2470, 0x2471, 0x2472, 0x2473, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x2474,
+ 0x2475, 0x2476, 0x2477, 0x2478, 0x2479, 0x247A, 0x247B, 0x247C,
+ 0x247D, 0x247E, 0x247F, 0x2480, 0x2481, 0x2482, 0x2483, 0x2484,
+ 0x2485, 0x2486, 0x2487, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x2776, 0x2777, 0x2778,
+ 0x2779, 0x277A, 0x277B, 0x277C, 0x277D, 0x277E, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2488, 0x2489, 0x248A, 0x248B, 0x248C, 0x248D,
+ 0x248E, 0x248F, 0x2490, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_A9_x0213[] = {
+ 0x20AC, 0x00A0, 0x00A1, 0x00A4, 0x00A6, 0x00A9, 0x00AA,
+ 0x00AB, 0x00AD, 0x00AE, 0x00AF, 0x00B2, 0x00B3, 0x00B7, 0x00B8,
+ 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0,
+ 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8,
+ 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0,
+ 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D8, 0x00D9,
+ 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, 0x00E1,
+ 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9,
+ 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1,
+ 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F8, 0x00F9, 0x00FA,
+ 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, 0x0100, 0x012A, 0x016A,
+ 0x0112, 0x014C, 0x0101, 0x012B, 0x016B, 0x0113, 0x014D,
+};
+static const unsigned short euc_to_utf8_AA[] = {
+ 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166,
+ 0x2167, 0x2168, 0x2169, 0x216A, 0x216B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x2170, 0x2171, 0x2172,
+ 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A,
+ 0x217B, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x249C, 0x249D, 0x249E,
+ 0x249F, 0x24A0, 0x24A1, 0x24A2, 0x24A3, 0x24A4, 0x24A5, 0x24A6,
+ 0x24A7, 0x24A8, 0x24A9, 0x24AA, 0x24AB, 0x24AC, 0x24AD, 0x24AE,
+ 0x24AF, 0x24B0, 0x24B1, 0x24B2, 0x24B3, 0x24B4, 0x24B5, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_AA_x0213[] = {
+ 0x0104, 0x02D8, 0x0141, 0x013D, 0x015A, 0x0160, 0x015E,
+ 0x0164, 0x0179, 0x017D, 0x017B, 0x0105, 0x02DB, 0x0142, 0x013E,
+ 0x015B, 0x02C7, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E,
+ 0x017C, 0x0154, 0x0102, 0x0139, 0x0106, 0x010C, 0x0118, 0x011A,
+ 0x010E, 0x0143, 0x0147, 0x0150, 0x0158, 0x016E, 0x0170, 0x0162,
+ 0x0155, 0x0103, 0x013A, 0x0107, 0x010D, 0x0119, 0x011B, 0x010F,
+ 0x0111, 0x0144, 0x0148, 0x0151, 0x0159, 0x016F, 0x0171, 0x0163,
+ 0x02D9, 0x0108, 0x011C, 0x0124, 0x0134, 0x015C, 0x016C, 0x0109,
+ 0x011D, 0x0125, 0x0135, 0x015D, 0x016D, 0x0271, 0x028B, 0x027E,
+ 0x0283, 0x0292, 0x026C, 0x026E, 0x0279, 0x0288, 0x0256, 0x0273,
+ 0x027D, 0x0282, 0x0290, 0x027B, 0x026D, 0x025F, 0x0272, 0x029D,
+ 0x028E, 0x0261, 0x014B, 0x0270, 0x0281, 0x0127, 0x0295,
+};
+static const unsigned short euc_to_utf8_AB[] = {
+ 0x339C, 0x339F, 0x339D, 0x33A0, 0x33A4, 0, 0x33A1,
+ 0x33A5, 0x339E, 0x33A2, 0x338E, 0, 0x338F, 0x33C4, 0x3396,
+ 0x3397, 0x2113, 0x3398, 0x33B3, 0x33B2, 0x33B1, 0x33B0, 0x2109,
+ 0x33D4, 0x33CB, 0x3390, 0x3385, 0x3386, 0x3387, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x2116, 0x33CD, 0x2121, 0,
+};
+static const unsigned short euc_to_utf8_AB_x0213[] = {
+ 0x0294, 0x0266, 0x0298, 0x01C2, 0x0253, 0x0257, 0x0284,
+ 0x0260, 0x0193, 0x0153, 0x0152, 0x0268, 0x0289, 0x0258, 0x0275,
+ 0x0259, 0x025C, 0x025E, 0x0250, 0x026F, 0x028A, 0x0264, 0x028C,
+ 0x0254, 0x0251, 0x0252, 0x028D, 0x0265, 0x02A2, 0x02A1, 0x0255,
+ 0x0291, 0x027A, 0x0267, 0x025A, /*0x00E6*/ 0x0300, 0x01FD, 0x1F70, 0x1F71,
+ /*0x0254*/ 0x0300, /*0x0254*/ 0x0301, /*0x028C*/ 0x0300, /*0x028C*/ 0x0301, /*0x0259*/ 0x0300, /*0x0259*/ 0x0301, /*0x025A*/ 0x0300, /*0x025A*/ 0x0301,
+ 0x1F72, 0x1F73, 0x0361, 0x02C8, 0x02CC, 0x02D0, 0x02D1, 0x0306,
+ 0x203F, 0x030B, /*0*/ 0x0301, 0x0304, /*0*/ 0x0300, 0x030F, 0x030C, 0x0302,
+ /*0*/ 0x02E5, 0x02E6, 0x02E7, 0x02E8, /*0*/ 0x02E9, /*0x02E9*/ 0x02E5, /*0x02E5*/ 0x02E9, 0x0325,
+ 0x032C, 0x0339, 0x031C, 0x031F, 0x0320, 0x0308, 0x033D, 0x0329,
+ 0x032F, 0x02DE, 0x0324, 0x0330, 0x033C, 0x0334, 0x031D, 0x031E,
+ 0x0318, 0x0319, 0x032A, 0x033A, 0x033B, 0x0303, 0x031A,
+};
+static const unsigned short euc_to_utf8_AC[] = {
+ 0x2664, 0x2667, 0x2661, 0x2662, 0x2660, 0x2663, 0x2665,
+ 0x2666, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x3020, 0x260E, 0x3004,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x261E, 0x261C, 0x261D, 0x261F, 0x21C6, 0x21C4, 0x21C5,
+ 0, 0x21E8, 0x21E6, 0x21E7, 0x21E9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_AC_mac[] = {
+ 0x2664, 0x2667, 0x2661, 0x2662, 0x2660, 0x2663, 0x2665,
+ 0x2666, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x3020, 0x260E, 0x3004,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x261E, 0x261C, 0x261D, 0x261F, 0x21C6, 0x21C4, 0x21C5,
+ 0, 0x21E8, 0x21E6, 0x21E7, 0x21E9, 0x2192, 0x2190, 0x2191,
+ 0x2193, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_AC_x0213[] = {
+ 0x2776, 0x2777, 0x2778, 0x2779, 0x277A, 0x277B, 0x277C,
+ 0x277D, 0x277E, 0x277F, 0x24EB, 0x24EC, 0x24ED, 0x24EE, 0x24EF,
+ 0x24F0, 0x24F1, 0x24F2, 0x24F3, 0x24F4, 0x2170, 0x2171, 0x2172,
+ 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A,
+ 0x217B, 0x24D0, 0x24D1, 0x24D2, 0x24D3, 0x24D4, 0x24D5, 0x24D6,
+ 0x24D7, 0x24D8, 0x24D9, 0x24DA, 0x24DB, 0x24DC, 0x24DD, 0x24DE,
+ 0x24DF, 0x24E0, 0x24E1, 0x24E2, 0x24E3, 0x24E4, 0x24E5, 0x24E6,
+ 0x24E7, 0x24E8, 0x24E9, 0x32D0, 0x32D1, 0x32D2, 0x32D3, 0x32D4,
+ 0x32D5, 0x32D6, 0x32D7, 0x32D8, 0x32D9, 0x32DA, 0x32DB, 0x32DC,
+ 0x32DD, 0x32DE, 0x32DF, 0x32E0, 0x32E1, 0x32E2, 0x32E3, 0x32FA,
+ 0x32E9, 0x32E5, 0x32ED, 0x32EC, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x2051, 0x2042,
+};
+static const unsigned short euc_to_utf8_AD[] = {
+ 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466,
+ 0x2467, 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E,
+ 0x246F, 0x2470, 0x2471, 0x2472, 0x2473, 0x2160, 0x2161, 0x2162,
+ 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0,
+ 0x3349, 0x3314, 0x3322, 0x334D, 0x3318, 0x3327, 0x3303, 0x3336,
+ 0x3351, 0x3357, 0x330D, 0x3326, 0x3323, 0x332B, 0x334A, 0x333B,
+ 0x339C, 0x339D, 0x339E, 0x338E, 0x338F, 0x33C4, 0x33A1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x337B,
+ 0x301D, 0x301F, 0x2116, 0x33CD, 0x2121, 0x32A4, 0x32A5, 0x32A6,
+ 0x32A7, 0x32A8, 0x3231, 0x3232, 0x3239, 0x337E, 0x337D, 0x337C,
+ 0x2252, 0x2261, 0x222B, 0x222E, 0x2211, 0x221A, 0x22A5, 0x2220,
+ 0x221F, 0x22BF, 0x2235, 0x2229, 0x222A, 0, 0x3299,
+};
+static const unsigned short euc_to_utf8_AD_mac[] = {
+ 0x65E5, 0x6708, 0x706B, 0x6C34, 0x6728, 0x91D1, 0x571F,
+ 0x796D, 0x795D, 0x81EA, 0x81F3, 0x3239, 0x547C, 0x3231, 0x8CC7,
+ 0x540D, 0x3232, 0x5B66, 0x8CA1, 0x793E, 0x7279, 0x76E3, 0x4F01,
+ 0x5354, 0x52B4, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0,
+ 0x3349, 0x3314, 0x3322, 0x334D, 0x3318, 0x3327, 0x3303, 0x3336,
+ 0x3351, 0x3357, 0x330D, 0x3326, 0x3323, 0x332B, 0x334A, 0x333B,
+ 0x339C, 0x339D, 0x339E, 0x338E, 0x338F, 0x33C4, 0x33A1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x337B,
+ 0x301D, 0x301F, 0x2116, 0x33CD, 0x2121, 0x32A4, 0x32A5, 0x32A6,
+ 0x32A7, 0x32A8, 0x3231, 0x3232, 0x3239, 0x337E, 0x337D, 0x337C,
+ 0x2252, 0x5927, 0x5C0F, 0x32A4, 0x32A5, 0x32A6, 0x32A7, 0x32A8,
+ 0x533B, 0x8CA1, 0x512A, 0x52B4, 0x5370, 0x63A7, 0x79D8,
+};
+static const unsigned short euc_to_utf8_AD_x0213[] = {
+ 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466,
+ 0x2467, 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E,
+ 0x246F, 0x2470, 0x2471, 0x2472, 0x2473, 0x2160, 0x2161, 0x2162,
+ 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x216A,
+ 0x3349, 0x3314, 0x3322, 0x334D, 0x3318, 0x3327, 0x3303, 0x3336,
+ 0x3351, 0x3357, 0x330D, 0x3326, 0x3323, 0x332B, 0x334A, 0x333B,
+ 0x339C, 0x339D, 0x339E, 0x338E, 0x338F, 0x33C4, 0x33A1, 0x216B,
+ 0, 0, 0, 0, 0, 0, 0, 0x337B,
+ 0x301D, 0x301F, 0x2116, 0x33CD, 0x2121, 0x32A4, 0x32A5, 0x32A6,
+ 0x32A7, 0x32A8, 0x3231, 0x3232, 0x3239, 0x337E, 0x337D, 0x337C,
+ 0x2252, 0x2261, 0x222B, 0x222E, 0x2211, 0x221A, 0x22A5, 0x2220,
+ 0x221F, 0x22BF, 0x2235, 0x2229, 0x222A, 0x2756, 0x261E,
+};
+static const unsigned short euc_to_utf8_AE[] = {
+ 0x3349, 0x3322, 0x334D, 0x3314, 0x3316, 0x3305, 0x3333,
+ 0x334E, 0x3303, 0x3336, 0x3318, 0x3315, 0x3327, 0x3351, 0x334A,
+ 0x3339, 0x3357, 0x330D, 0x3342, 0x3323, 0x3326, 0x333B, 0x332B,
+ 0, 0, 0, 0, 0, 0, 0, 0x3300,
+ 0x331E, 0x332A, 0x3331, 0x3347, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x337E,
+ 0x337D, 0x337C, 0x337B, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x337F, 0, 0,
+};
+static const unsigned short euc_to_utf8_AE_x0213[] = {
+ 0x4FF1, 0xD840 /*0xDC0B*/, 0x3402, 0x4E28, 0x4E2F, 0x4E30, 0x4E8D,
+ 0x4EE1, 0x4EFD, 0x4EFF, 0x4F03, 0x4F0B, 0x4F60, 0x4F48, 0x4F49,
+ 0x4F56, 0x4F5F, 0x4F6A, 0x4F6C, 0x4F7E, 0x4F8A, 0x4F94, 0x4F97,
+ 0xFA30, 0x4FC9, 0x4FE0, 0x5001, 0x5002, 0x500E, 0x5018, 0x5027,
+ 0x502E, 0x5040, 0x503B, 0x5041, 0x5094, 0x50CC, 0x50F2, 0x50D0,
+ 0x50E6, 0xFA31, 0x5106, 0x5103, 0x510B, 0x511E, 0x5135, 0x514A,
+ 0xFA32, 0x5155, 0x5157, 0x34B5, 0x519D, 0x51C3, 0x51CA, 0x51DE,
+ 0x51E2, 0x51EE, 0x5201, 0x34DB, 0x5213, 0x5215, 0x5249, 0x5257,
+ 0x5261, 0x5293, 0x52C8, 0xFA33, 0x52CC, 0x52D0, 0x52D6, 0x52DB,
+ 0xFA34, 0x52F0, 0x52FB, 0x5300, 0x5307, 0x531C, 0xFA35, 0x5361,
+ 0x5363, 0x537D, 0x5393, 0x539D, 0x53B2, 0x5412, 0x5427, 0x544D,
+ 0x549C, 0x546B, 0x5474, 0x547F, 0x5488, 0x5496, 0x54A1,
+};
+static const unsigned short euc_to_utf8_AF[] = {
+ 0x222E, 0x221F, 0x22BF, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x301D, 0x301F, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x3094, 0, 0x30F7, 0x30F8, 0x30F9, 0x30FA, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_AF_x0213[] = {
+ 0x54A9, 0x54C6, 0x54FF, 0x550E, 0x552B, 0x5535, 0x5550,
+ 0x555E, 0x5581, 0x5586, 0x558E, 0xFA36, 0x55AD, 0x55CE, 0xFA37,
+ 0x5608, 0x560E, 0x563B, 0x5649, 0x5676, 0x5666, 0xFA38, 0x566F,
+ 0x5671, 0x5672, 0x5699, 0x569E, 0x56A9, 0x56AC, 0x56B3, 0x56C9,
+ 0x56CA, 0x570A, 0xD844 /*0xDE3D*/, 0x5721, 0x572F, 0x5733, 0x5734, 0x5770,
+ 0x5777, 0x577C, 0x579C, 0xFA0F, 0xD844 /*0xDF1B*/, 0x57B8, 0x57C7, 0x57C8,
+ 0x57CF, 0x57E4, 0x57ED, 0x57F5, 0x57F6, 0x57FF, 0x5809, 0xFA10,
+ 0x5861, 0x5864, 0xFA39, 0x587C, 0x5889, 0x589E, 0xFA3A, 0x58A9,
+ 0xD845 /*0xDC6E*/, 0x58D2, 0x58CE, 0x58D4, 0x58DA, 0x58E0, 0x58E9, 0x590C,
+ 0x8641, 0x595D, 0x596D, 0x598B, 0x5992, 0x59A4, 0x59C3, 0x59D2,
+ 0x59DD, 0x5A13, 0x5A23, 0x5A67, 0x5A6D, 0x5A77, 0x5A7E, 0x5A84,
+ 0x5A9E, 0x5AA7, 0x5AC4, 0xD846 /*0xDCBD*/, 0x5B19, 0x5B25, 0x525D,
+};
+static const unsigned short euc_to_utf8_B0[] = {
+ 0x4E9C, 0x5516, 0x5A03, 0x963F, 0x54C0, 0x611B, 0x6328,
+ 0x59F6, 0x9022, 0x8475, 0x831C, 0x7A50, 0x60AA, 0x63E1, 0x6E25,
+ 0x65ED, 0x8466, 0x82A6, 0x9BF5, 0x6893, 0x5727, 0x65A1, 0x6271,
+ 0x5B9B, 0x59D0, 0x867B, 0x98F4, 0x7D62, 0x7DBE, 0x9B8E, 0x6216,
+ 0x7C9F, 0x88B7, 0x5B89, 0x5EB5, 0x6309, 0x6697, 0x6848, 0x95C7,
+ 0x978D, 0x674F, 0x4EE5, 0x4F0A, 0x4F4D, 0x4F9D, 0x5049, 0x56F2,
+ 0x5937, 0x59D4, 0x5A01, 0x5C09, 0x60DF, 0x610F, 0x6170, 0x6613,
+ 0x6905, 0x70BA, 0x754F, 0x7570, 0x79FB, 0x7DAD, 0x7DEF, 0x80C3,
+ 0x840E, 0x8863, 0x8B02, 0x9055, 0x907A, 0x533B, 0x4E95, 0x4EA5,
+ 0x57DF, 0x80B2, 0x90C1, 0x78EF, 0x4E00, 0x58F1, 0x6EA2, 0x9038,
+ 0x7A32, 0x8328, 0x828B, 0x9C2F, 0x5141, 0x5370, 0x54BD, 0x54E1,
+ 0x56E0, 0x59FB, 0x5F15, 0x98F2, 0x6DEB, 0x80E4, 0x852D,
+};
+static const unsigned short euc_to_utf8_B1[] = {
+ 0x9662, 0x9670, 0x96A0, 0x97FB, 0x540B, 0x53F3, 0x5B87,
+ 0x70CF, 0x7FBD, 0x8FC2, 0x96E8, 0x536F, 0x9D5C, 0x7ABA, 0x4E11,
+ 0x7893, 0x81FC, 0x6E26, 0x5618, 0x5504, 0x6B1D, 0x851A, 0x9C3B,
+ 0x59E5, 0x53A9, 0x6D66, 0x74DC, 0x958F, 0x5642, 0x4E91, 0x904B,
+ 0x96F2, 0x834F, 0x990C, 0x53E1, 0x55B6, 0x5B30, 0x5F71, 0x6620,
+ 0x66F3, 0x6804, 0x6C38, 0x6CF3, 0x6D29, 0x745B, 0x76C8, 0x7A4E,
+ 0x9834, 0x82F1, 0x885B, 0x8A60, 0x92ED, 0x6DB2, 0x75AB, 0x76CA,
+ 0x99C5, 0x60A6, 0x8B01, 0x8D8A, 0x95B2, 0x698E, 0x53AD, 0x5186,
+ 0x5712, 0x5830, 0x5944, 0x5BB4, 0x5EF6, 0x6028, 0x63A9, 0x63F4,
+ 0x6CBF, 0x6F14, 0x708E, 0x7114, 0x7159, 0x71D5, 0x733F, 0x7E01,
+ 0x8276, 0x82D1, 0x8597, 0x9060, 0x925B, 0x9D1B, 0x5869, 0x65BC,
+ 0x6C5A, 0x7525, 0x51F9, 0x592E, 0x5965, 0x5F80, 0x5FDC,
+};
+static const unsigned short euc_to_utf8_B2[] = {
+ 0x62BC, 0x65FA, 0x6A2A, 0x6B27, 0x6BB4, 0x738B, 0x7FC1,
+ 0x8956, 0x9D2C, 0x9D0E, 0x9EC4, 0x5CA1, 0x6C96, 0x837B, 0x5104,
+ 0x5C4B, 0x61B6, 0x81C6, 0x6876, 0x7261, 0x4E59, 0x4FFA, 0x5378,
+ 0x6069, 0x6E29, 0x7A4F, 0x97F3, 0x4E0B, 0x5316, 0x4EEE, 0x4F55,
+ 0x4F3D, 0x4FA1, 0x4F73, 0x52A0, 0x53EF, 0x5609, 0x590F, 0x5AC1,
+ 0x5BB6, 0x5BE1, 0x79D1, 0x6687, 0x679C, 0x67B6, 0x6B4C, 0x6CB3,
+ 0x706B, 0x73C2, 0x798D, 0x79BE, 0x7A3C, 0x7B87, 0x82B1, 0x82DB,
+ 0x8304, 0x8377, 0x83EF, 0x83D3, 0x8766, 0x8AB2, 0x5629, 0x8CA8,
+ 0x8FE6, 0x904E, 0x971E, 0x868A, 0x4FC4, 0x5CE8, 0x6211, 0x7259,
+ 0x753B, 0x81E5, 0x82BD, 0x86FE, 0x8CC0, 0x96C5, 0x9913, 0x99D5,
+ 0x4ECB, 0x4F1A, 0x89E3, 0x56DE, 0x584A, 0x58CA, 0x5EFB, 0x5FEB,
+ 0x602A, 0x6094, 0x6062, 0x61D0, 0x6212, 0x62D0, 0x6539,
+};
+static const unsigned short euc_to_utf8_B3[] = {
+ 0x9B41, 0x6666, 0x68B0, 0x6D77, 0x7070, 0x754C, 0x7686,
+ 0x7D75, 0x82A5, 0x87F9, 0x958B, 0x968E, 0x8C9D, 0x51F1, 0x52BE,
+ 0x5916, 0x54B3, 0x5BB3, 0x5D16, 0x6168, 0x6982, 0x6DAF, 0x788D,
+ 0x84CB, 0x8857, 0x8A72, 0x93A7, 0x9AB8, 0x6D6C, 0x99A8, 0x86D9,
+ 0x57A3, 0x67FF, 0x86CE, 0x920E, 0x5283, 0x5687, 0x5404, 0x5ED3,
+ 0x62E1, 0x64B9, 0x683C, 0x6838, 0x6BBB, 0x7372, 0x78BA, 0x7A6B,
+ 0x899A, 0x89D2, 0x8D6B, 0x8F03, 0x90ED, 0x95A3, 0x9694, 0x9769,
+ 0x5B66, 0x5CB3, 0x697D, 0x984D, 0x984E, 0x639B, 0x7B20, 0x6A2B,
+ 0x6A7F, 0x68B6, 0x9C0D, 0x6F5F, 0x5272, 0x559D, 0x6070, 0x62EC,
+ 0x6D3B, 0x6E07, 0x6ED1, 0x845B, 0x8910, 0x8F44, 0x4E14, 0x9C39,
+ 0x53F6, 0x691B, 0x6A3A, 0x9784, 0x682A, 0x515C, 0x7AC3, 0x84B2,
+ 0x91DC, 0x938C, 0x565B, 0x9D28, 0x6822, 0x8305, 0x8431,
+};
+static const unsigned short euc_to_utf8_B4[] = {
+ 0x7CA5, 0x5208, 0x82C5, 0x74E6, 0x4E7E, 0x4F83, 0x51A0,
+ 0x5BD2, 0x520A, 0x52D8, 0x52E7, 0x5DFB, 0x559A, 0x582A, 0x59E6,
+ 0x5B8C, 0x5B98, 0x5BDB, 0x5E72, 0x5E79, 0x60A3, 0x611F, 0x6163,
+ 0x61BE, 0x63DB, 0x6562, 0x67D1, 0x6853, 0x68FA, 0x6B3E, 0x6B53,
+ 0x6C57, 0x6F22, 0x6F97, 0x6F45, 0x74B0, 0x7518, 0x76E3, 0x770B,
+ 0x7AFF, 0x7BA1, 0x7C21, 0x7DE9, 0x7F36, 0x7FF0, 0x809D, 0x8266,
+ 0x839E, 0x89B3, 0x8ACC, 0x8CAB, 0x9084, 0x9451, 0x9593, 0x9591,
+ 0x95A2, 0x9665, 0x97D3, 0x9928, 0x8218, 0x4E38, 0x542B, 0x5CB8,
+ 0x5DCC, 0x73A9, 0x764C, 0x773C, 0x5CA9, 0x7FEB, 0x8D0B, 0x96C1,
+ 0x9811, 0x9854, 0x9858, 0x4F01, 0x4F0E, 0x5371, 0x559C, 0x5668,
+ 0x57FA, 0x5947, 0x5B09, 0x5BC4, 0x5C90, 0x5E0C, 0x5E7E, 0x5FCC,
+ 0x63EE, 0x673A, 0x65D7, 0x65E2, 0x671F, 0x68CB, 0x68C4,
+};
+static const unsigned short euc_to_utf8_B5[] = {
+ 0x6A5F, 0x5E30, 0x6BC5, 0x6C17, 0x6C7D, 0x757F, 0x7948,
+ 0x5B63, 0x7A00, 0x7D00, 0x5FBD, 0x898F, 0x8A18, 0x8CB4, 0x8D77,
+ 0x8ECC, 0x8F1D, 0x98E2, 0x9A0E, 0x9B3C, 0x4E80, 0x507D, 0x5100,
+ 0x5993, 0x5B9C, 0x622F, 0x6280, 0x64EC, 0x6B3A, 0x72A0, 0x7591,
+ 0x7947, 0x7FA9, 0x87FB, 0x8ABC, 0x8B70, 0x63AC, 0x83CA, 0x97A0,
+ 0x5409, 0x5403, 0x55AB, 0x6854, 0x6A58, 0x8A70, 0x7827, 0x6775,
+ 0x9ECD, 0x5374, 0x5BA2, 0x811A, 0x8650, 0x9006, 0x4E18, 0x4E45,
+ 0x4EC7, 0x4F11, 0x53CA, 0x5438, 0x5BAE, 0x5F13, 0x6025, 0x6551,
+ 0x673D, 0x6C42, 0x6C72, 0x6CE3, 0x7078, 0x7403, 0x7A76, 0x7AAE,
+ 0x7B08, 0x7D1A, 0x7CFE, 0x7D66, 0x65E7, 0x725B, 0x53BB, 0x5C45,
+ 0x5DE8, 0x62D2, 0x62E0, 0x6319, 0x6E20, 0x865A, 0x8A31, 0x8DDD,
+ 0x92F8, 0x6F01, 0x79A6, 0x9B5A, 0x4EA8, 0x4EAB, 0x4EAC,
+};
+static const unsigned short euc_to_utf8_B6[] = {
+ 0x4F9B, 0x4FA0, 0x50D1, 0x5147, 0x7AF6, 0x5171, 0x51F6,
+ 0x5354, 0x5321, 0x537F, 0x53EB, 0x55AC, 0x5883, 0x5CE1, 0x5F37,
+ 0x5F4A, 0x602F, 0x6050, 0x606D, 0x631F, 0x6559, 0x6A4B, 0x6CC1,
+ 0x72C2, 0x72ED, 0x77EF, 0x80F8, 0x8105, 0x8208, 0x854E, 0x90F7,
+ 0x93E1, 0x97FF, 0x9957, 0x9A5A, 0x4EF0, 0x51DD, 0x5C2D, 0x6681,
+ 0x696D, 0x5C40, 0x66F2, 0x6975, 0x7389, 0x6850, 0x7C81, 0x50C5,
+ 0x52E4, 0x5747, 0x5DFE, 0x9326, 0x65A4, 0x6B23, 0x6B3D, 0x7434,
+ 0x7981, 0x79BD, 0x7B4B, 0x7DCA, 0x82B9, 0x83CC, 0x887F, 0x895F,
+ 0x8B39, 0x8FD1, 0x91D1, 0x541F, 0x9280, 0x4E5D, 0x5036, 0x53E5,
+ 0x533A, 0x72D7, 0x7396, 0x77E9, 0x82E6, 0x8EAF, 0x99C6, 0x99C8,
+ 0x99D2, 0x5177, 0x611A, 0x865E, 0x55B0, 0x7A7A, 0x5076, 0x5BD3,
+ 0x9047, 0x9685, 0x4E32, 0x6ADB, 0x91E7, 0x5C51, 0x5C48,
+};
+static const unsigned short euc_to_utf8_B7[] = {
+ 0x6398, 0x7A9F, 0x6C93, 0x9774, 0x8F61, 0x7AAA, 0x718A,
+ 0x9688, 0x7C82, 0x6817, 0x7E70, 0x6851, 0x936C, 0x52F2, 0x541B,
+ 0x85AB, 0x8A13, 0x7FA4, 0x8ECD, 0x90E1, 0x5366, 0x8888, 0x7941,
+ 0x4FC2, 0x50BE, 0x5211, 0x5144, 0x5553, 0x572D, 0x73EA, 0x578B,
+ 0x5951, 0x5F62, 0x5F84, 0x6075, 0x6176, 0x6167, 0x61A9, 0x63B2,
+ 0x643A, 0x656C, 0x666F, 0x6842, 0x6E13, 0x7566, 0x7A3D, 0x7CFB,
+ 0x7D4C, 0x7D99, 0x7E4B, 0x7F6B, 0x830E, 0x834A, 0x86CD, 0x8A08,
+ 0x8A63, 0x8B66, 0x8EFD, 0x981A, 0x9D8F, 0x82B8, 0x8FCE, 0x9BE8,
+ 0x5287, 0x621F, 0x6483, 0x6FC0, 0x9699, 0x6841, 0x5091, 0x6B20,
+ 0x6C7A, 0x6F54, 0x7A74, 0x7D50, 0x8840, 0x8A23, 0x6708, 0x4EF6,
+ 0x5039, 0x5026, 0x5065, 0x517C, 0x5238, 0x5263, 0x55A7, 0x570F,
+ 0x5805, 0x5ACC, 0x5EFA, 0x61B2, 0x61F8, 0x62F3, 0x6372,
+};
+static const unsigned short euc_to_utf8_B8[] = {
+ 0x691C, 0x6A29, 0x727D, 0x72AC, 0x732E, 0x7814, 0x786F,
+ 0x7D79, 0x770C, 0x80A9, 0x898B, 0x8B19, 0x8CE2, 0x8ED2, 0x9063,
+ 0x9375, 0x967A, 0x9855, 0x9A13, 0x9E78, 0x5143, 0x539F, 0x53B3,
+ 0x5E7B, 0x5F26, 0x6E1B, 0x6E90, 0x7384, 0x73FE, 0x7D43, 0x8237,
+ 0x8A00, 0x8AFA, 0x9650, 0x4E4E, 0x500B, 0x53E4, 0x547C, 0x56FA,
+ 0x59D1, 0x5B64, 0x5DF1, 0x5EAB, 0x5F27, 0x6238, 0x6545, 0x67AF,
+ 0x6E56, 0x72D0, 0x7CCA, 0x88B4, 0x80A1, 0x80E1, 0x83F0, 0x864E,
+ 0x8A87, 0x8DE8, 0x9237, 0x96C7, 0x9867, 0x9F13, 0x4E94, 0x4E92,
+ 0x4F0D, 0x5348, 0x5449, 0x543E, 0x5A2F, 0x5F8C, 0x5FA1, 0x609F,
+ 0x68A7, 0x6A8E, 0x745A, 0x7881, 0x8A9E, 0x8AA4, 0x8B77, 0x9190,
+ 0x4E5E, 0x9BC9, 0x4EA4, 0x4F7C, 0x4FAF, 0x5019, 0x5016, 0x5149,
+ 0x516C, 0x529F, 0x52B9, 0x52FE, 0x539A, 0x53E3, 0x5411,
+};
+static const unsigned short euc_to_utf8_B9[] = {
+ 0x540E, 0x5589, 0x5751, 0x57A2, 0x597D, 0x5B54, 0x5B5D,
+ 0x5B8F, 0x5DE5, 0x5DE7, 0x5DF7, 0x5E78, 0x5E83, 0x5E9A, 0x5EB7,
+ 0x5F18, 0x6052, 0x614C, 0x6297, 0x62D8, 0x63A7, 0x653B, 0x6602,
+ 0x6643, 0x66F4, 0x676D, 0x6821, 0x6897, 0x69CB, 0x6C5F, 0x6D2A,
+ 0x6D69, 0x6E2F, 0x6E9D, 0x7532, 0x7687, 0x786C, 0x7A3F, 0x7CE0,
+ 0x7D05, 0x7D18, 0x7D5E, 0x7DB1, 0x8015, 0x8003, 0x80AF, 0x80B1,
+ 0x8154, 0x818F, 0x822A, 0x8352, 0x884C, 0x8861, 0x8B1B, 0x8CA2,
+ 0x8CFC, 0x90CA, 0x9175, 0x9271, 0x783F, 0x92FC, 0x95A4, 0x964D,
+ 0x9805, 0x9999, 0x9AD8, 0x9D3B, 0x525B, 0x52AB, 0x53F7, 0x5408,
+ 0x58D5, 0x62F7, 0x6FE0, 0x8C6A, 0x8F5F, 0x9EB9, 0x514B, 0x523B,
+ 0x544A, 0x56FD, 0x7A40, 0x9177, 0x9D60, 0x9ED2, 0x7344, 0x6F09,
+ 0x8170, 0x7511, 0x5FFD, 0x60DA, 0x9AA8, 0x72DB, 0x8FBC,
+};
+static const unsigned short euc_to_utf8_BA[] = {
+ 0x6B64, 0x9803, 0x4ECA, 0x56F0, 0x5764, 0x58BE, 0x5A5A,
+ 0x6068, 0x61C7, 0x660F, 0x6606, 0x6839, 0x68B1, 0x6DF7, 0x75D5,
+ 0x7D3A, 0x826E, 0x9B42, 0x4E9B, 0x4F50, 0x53C9, 0x5506, 0x5D6F,
+ 0x5DE6, 0x5DEE, 0x67FB, 0x6C99, 0x7473, 0x7802, 0x8A50, 0x9396,
+ 0x88DF, 0x5750, 0x5EA7, 0x632B, 0x50B5, 0x50AC, 0x518D, 0x6700,
+ 0x54C9, 0x585E, 0x59BB, 0x5BB0, 0x5F69, 0x624D, 0x63A1, 0x683D,
+ 0x6B73, 0x6E08, 0x707D, 0x91C7, 0x7280, 0x7815, 0x7826, 0x796D,
+ 0x658E, 0x7D30, 0x83DC, 0x88C1, 0x8F09, 0x969B, 0x5264, 0x5728,
+ 0x6750, 0x7F6A, 0x8CA1, 0x51B4, 0x5742, 0x962A, 0x583A, 0x698A,
+ 0x80B4, 0x54B2, 0x5D0E, 0x57FC, 0x7895, 0x9DFA, 0x4F5C, 0x524A,
+ 0x548B, 0x643E, 0x6628, 0x6714, 0x67F5, 0x7A84, 0x7B56, 0x7D22,
+ 0x932F, 0x685C, 0x9BAD, 0x7B39, 0x5319, 0x518A, 0x5237,
+};
+static const unsigned short euc_to_utf8_BB[] = {
+ 0x5BDF, 0x62F6, 0x64AE, 0x64E6, 0x672D, 0x6BBA, 0x85A9,
+ 0x96D1, 0x7690, 0x9BD6, 0x634C, 0x9306, 0x9BAB, 0x76BF, 0x6652,
+ 0x4E09, 0x5098, 0x53C2, 0x5C71, 0x60E8, 0x6492, 0x6563, 0x685F,
+ 0x71E6, 0x73CA, 0x7523, 0x7B97, 0x7E82, 0x8695, 0x8B83, 0x8CDB,
+ 0x9178, 0x9910, 0x65AC, 0x66AB, 0x6B8B, 0x4ED5, 0x4ED4, 0x4F3A,
+ 0x4F7F, 0x523A, 0x53F8, 0x53F2, 0x55E3, 0x56DB, 0x58EB, 0x59CB,
+ 0x59C9, 0x59FF, 0x5B50, 0x5C4D, 0x5E02, 0x5E2B, 0x5FD7, 0x601D,
+ 0x6307, 0x652F, 0x5B5C, 0x65AF, 0x65BD, 0x65E8, 0x679D, 0x6B62,
+ 0x6B7B, 0x6C0F, 0x7345, 0x7949, 0x79C1, 0x7CF8, 0x7D19, 0x7D2B,
+ 0x80A2, 0x8102, 0x81F3, 0x8996, 0x8A5E, 0x8A69, 0x8A66, 0x8A8C,
+ 0x8AEE, 0x8CC7, 0x8CDC, 0x96CC, 0x98FC, 0x6B6F, 0x4E8B, 0x4F3C,
+ 0x4F8D, 0x5150, 0x5B57, 0x5BFA, 0x6148, 0x6301, 0x6642,
+};
+static const unsigned short euc_to_utf8_BC[] = {
+ 0x6B21, 0x6ECB, 0x6CBB, 0x723E, 0x74BD, 0x75D4, 0x78C1,
+ 0x793A, 0x800C, 0x8033, 0x81EA, 0x8494, 0x8F9E, 0x6C50, 0x9E7F,
+ 0x5F0F, 0x8B58, 0x9D2B, 0x7AFA, 0x8EF8, 0x5B8D, 0x96EB, 0x4E03,
+ 0x53F1, 0x57F7, 0x5931, 0x5AC9, 0x5BA4, 0x6089, 0x6E7F, 0x6F06,
+ 0x75BE, 0x8CEA, 0x5B9F, 0x8500, 0x7BE0, 0x5072, 0x67F4, 0x829D,
+ 0x5C61, 0x854A, 0x7E1E, 0x820E, 0x5199, 0x5C04, 0x6368, 0x8D66,
+ 0x659C, 0x716E, 0x793E, 0x7D17, 0x8005, 0x8B1D, 0x8ECA, 0x906E,
+ 0x86C7, 0x90AA, 0x501F, 0x52FA, 0x5C3A, 0x6753, 0x707C, 0x7235,
+ 0x914C, 0x91C8, 0x932B, 0x82E5, 0x5BC2, 0x5F31, 0x60F9, 0x4E3B,
+ 0x53D6, 0x5B88, 0x624B, 0x6731, 0x6B8A, 0x72E9, 0x73E0, 0x7A2E,
+ 0x816B, 0x8DA3, 0x9152, 0x9996, 0x5112, 0x53D7, 0x546A, 0x5BFF,
+ 0x6388, 0x6A39, 0x7DAC, 0x9700, 0x56DA, 0x53CE, 0x5468,
+};
+static const unsigned short euc_to_utf8_BD[] = {
+ 0x5B97, 0x5C31, 0x5DDE, 0x4FEE, 0x6101, 0x62FE, 0x6D32,
+ 0x79C0, 0x79CB, 0x7D42, 0x7E4D, 0x7FD2, 0x81ED, 0x821F, 0x8490,
+ 0x8846, 0x8972, 0x8B90, 0x8E74, 0x8F2F, 0x9031, 0x914B, 0x916C,
+ 0x96C6, 0x919C, 0x4EC0, 0x4F4F, 0x5145, 0x5341, 0x5F93, 0x620E,
+ 0x67D4, 0x6C41, 0x6E0B, 0x7363, 0x7E26, 0x91CD, 0x9283, 0x53D4,
+ 0x5919, 0x5BBF, 0x6DD1, 0x795D, 0x7E2E, 0x7C9B, 0x587E, 0x719F,
+ 0x51FA, 0x8853, 0x8FF0, 0x4FCA, 0x5CFB, 0x6625, 0x77AC, 0x7AE3,
+ 0x821C, 0x99FF, 0x51C6, 0x5FAA, 0x65EC, 0x696F, 0x6B89, 0x6DF3,
+ 0x6E96, 0x6F64, 0x76FE, 0x7D14, 0x5DE1, 0x9075, 0x9187, 0x9806,
+ 0x51E6, 0x521D, 0x6240, 0x6691, 0x66D9, 0x6E1A, 0x5EB6, 0x7DD2,
+ 0x7F72, 0x66F8, 0x85AF, 0x85F7, 0x8AF8, 0x52A9, 0x53D9, 0x5973,
+ 0x5E8F, 0x5F90, 0x6055, 0x92E4, 0x9664, 0x50B7, 0x511F,
+};
+static const unsigned short euc_to_utf8_BE[] = {
+ 0x52DD, 0x5320, 0x5347, 0x53EC, 0x54E8, 0x5546, 0x5531,
+ 0x5617, 0x5968, 0x59BE, 0x5A3C, 0x5BB5, 0x5C06, 0x5C0F, 0x5C11,
+ 0x5C1A, 0x5E84, 0x5E8A, 0x5EE0, 0x5F70, 0x627F, 0x6284, 0x62DB,
+ 0x638C, 0x6377, 0x6607, 0x660C, 0x662D, 0x6676, 0x677E, 0x68A2,
+ 0x6A1F, 0x6A35, 0x6CBC, 0x6D88, 0x6E09, 0x6E58, 0x713C, 0x7126,
+ 0x7167, 0x75C7, 0x7701, 0x785D, 0x7901, 0x7965, 0x79F0, 0x7AE0,
+ 0x7B11, 0x7CA7, 0x7D39, 0x8096, 0x83D6, 0x848B, 0x8549, 0x885D,
+ 0x88F3, 0x8A1F, 0x8A3C, 0x8A54, 0x8A73, 0x8C61, 0x8CDE, 0x91A4,
+ 0x9266, 0x937E, 0x9418, 0x969C, 0x9798, 0x4E0A, 0x4E08, 0x4E1E,
+ 0x4E57, 0x5197, 0x5270, 0x57CE, 0x5834, 0x58CC, 0x5B22, 0x5E38,
+ 0x60C5, 0x64FE, 0x6761, 0x6756, 0x6D44, 0x72B6, 0x7573, 0x7A63,
+ 0x84B8, 0x8B72, 0x91B8, 0x9320, 0x5631, 0x57F4, 0x98FE,
+};
+static const unsigned short euc_to_utf8_BF[] = {
+ 0x62ED, 0x690D, 0x6B96, 0x71ED, 0x7E54, 0x8077, 0x8272,
+ 0x89E6, 0x98DF, 0x8755, 0x8FB1, 0x5C3B, 0x4F38, 0x4FE1, 0x4FB5,
+ 0x5507, 0x5A20, 0x5BDD, 0x5BE9, 0x5FC3, 0x614E, 0x632F, 0x65B0,
+ 0x664B, 0x68EE, 0x699B, 0x6D78, 0x6DF1, 0x7533, 0x75B9, 0x771F,
+ 0x795E, 0x79E6, 0x7D33, 0x81E3, 0x82AF, 0x85AA, 0x89AA, 0x8A3A,
+ 0x8EAB, 0x8F9B, 0x9032, 0x91DD, 0x9707, 0x4EBA, 0x4EC1, 0x5203,
+ 0x5875, 0x58EC, 0x5C0B, 0x751A, 0x5C3D, 0x814E, 0x8A0A, 0x8FC5,
+ 0x9663, 0x976D, 0x7B25, 0x8ACF, 0x9808, 0x9162, 0x56F3, 0x53A8,
+ 0x9017, 0x5439, 0x5782, 0x5E25, 0x63A8, 0x6C34, 0x708A, 0x7761,
+ 0x7C8B, 0x7FE0, 0x8870, 0x9042, 0x9154, 0x9310, 0x9318, 0x968F,
+ 0x745E, 0x9AC4, 0x5D07, 0x5D69, 0x6570, 0x67A2, 0x8DA8, 0x96DB,
+ 0x636E, 0x6749, 0x6919, 0x83C5, 0x9817, 0x96C0, 0x88FE,
+};
+static const unsigned short euc_to_utf8_C0[] = {
+ 0x6F84, 0x647A, 0x5BF8, 0x4E16, 0x702C, 0x755D, 0x662F,
+ 0x51C4, 0x5236, 0x52E2, 0x59D3, 0x5F81, 0x6027, 0x6210, 0x653F,
+ 0x6574, 0x661F, 0x6674, 0x68F2, 0x6816, 0x6B63, 0x6E05, 0x7272,
+ 0x751F, 0x76DB, 0x7CBE, 0x8056, 0x58F0, 0x88FD, 0x897F, 0x8AA0,
+ 0x8A93, 0x8ACB, 0x901D, 0x9192, 0x9752, 0x9759, 0x6589, 0x7A0E,
+ 0x8106, 0x96BB, 0x5E2D, 0x60DC, 0x621A, 0x65A5, 0x6614, 0x6790,
+ 0x77F3, 0x7A4D, 0x7C4D, 0x7E3E, 0x810A, 0x8CAC, 0x8D64, 0x8DE1,
+ 0x8E5F, 0x78A9, 0x5207, 0x62D9, 0x63A5, 0x6442, 0x6298, 0x8A2D,
+ 0x7A83, 0x7BC0, 0x8AAC, 0x96EA, 0x7D76, 0x820C, 0x8749, 0x4ED9,
+ 0x5148, 0x5343, 0x5360, 0x5BA3, 0x5C02, 0x5C16, 0x5DDD, 0x6226,
+ 0x6247, 0x64B0, 0x6813, 0x6834, 0x6CC9, 0x6D45, 0x6D17, 0x67D3,
+ 0x6F5C, 0x714E, 0x717D, 0x65CB, 0x7A7F, 0x7BAD, 0x7DDA,
+};
+static const unsigned short euc_to_utf8_C1[] = {
+ 0x7E4A, 0x7FA8, 0x817A, 0x821B, 0x8239, 0x85A6, 0x8A6E,
+ 0x8CCE, 0x8DF5, 0x9078, 0x9077, 0x92AD, 0x9291, 0x9583, 0x9BAE,
+ 0x524D, 0x5584, 0x6F38, 0x7136, 0x5168, 0x7985, 0x7E55, 0x81B3,
+ 0x7CCE, 0x564C, 0x5851, 0x5CA8, 0x63AA, 0x66FE, 0x66FD, 0x695A,
+ 0x72D9, 0x758F, 0x758E, 0x790E, 0x7956, 0x79DF, 0x7C97, 0x7D20,
+ 0x7D44, 0x8607, 0x8A34, 0x963B, 0x9061, 0x9F20, 0x50E7, 0x5275,
+ 0x53CC, 0x53E2, 0x5009, 0x55AA, 0x58EE, 0x594F, 0x723D, 0x5B8B,
+ 0x5C64, 0x531D, 0x60E3, 0x60F3, 0x635C, 0x6383, 0x633F, 0x63BB,
+ 0x64CD, 0x65E9, 0x66F9, 0x5DE3, 0x69CD, 0x69FD, 0x6F15, 0x71E5,
+ 0x4E89, 0x75E9, 0x76F8, 0x7A93, 0x7CDF, 0x7DCF, 0x7D9C, 0x8061,
+ 0x8349, 0x8358, 0x846C, 0x84BC, 0x85FB, 0x88C5, 0x8D70, 0x9001,
+ 0x906D, 0x9397, 0x971C, 0x9A12, 0x50CF, 0x5897, 0x618E,
+};
+static const unsigned short euc_to_utf8_C2[] = {
+ 0x81D3, 0x8535, 0x8D08, 0x9020, 0x4FC3, 0x5074, 0x5247,
+ 0x5373, 0x606F, 0x6349, 0x675F, 0x6E2C, 0x8DB3, 0x901F, 0x4FD7,
+ 0x5C5E, 0x8CCA, 0x65CF, 0x7D9A, 0x5352, 0x8896, 0x5176, 0x63C3,
+ 0x5B58, 0x5B6B, 0x5C0A, 0x640D, 0x6751, 0x905C, 0x4ED6, 0x591A,
+ 0x592A, 0x6C70, 0x8A51, 0x553E, 0x5815, 0x59A5, 0x60F0, 0x6253,
+ 0x67C1, 0x8235, 0x6955, 0x9640, 0x99C4, 0x9A28, 0x4F53, 0x5806,
+ 0x5BFE, 0x8010, 0x5CB1, 0x5E2F, 0x5F85, 0x6020, 0x614B, 0x6234,
+ 0x66FF, 0x6CF0, 0x6EDE, 0x80CE, 0x817F, 0x82D4, 0x888B, 0x8CB8,
+ 0x9000, 0x902E, 0x968A, 0x9EDB, 0x9BDB, 0x4EE3, 0x53F0, 0x5927,
+ 0x7B2C, 0x918D, 0x984C, 0x9DF9, 0x6EDD, 0x7027, 0x5353, 0x5544,
+ 0x5B85, 0x6258, 0x629E, 0x62D3, 0x6CA2, 0x6FEF, 0x7422, 0x8A17,
+ 0x9438, 0x6FC1, 0x8AFE, 0x8338, 0x51E7, 0x86F8, 0x53EA,
+};
+static const unsigned short euc_to_utf8_C3[] = {
+ 0x53E9, 0x4F46, 0x9054, 0x8FB0, 0x596A, 0x8131, 0x5DFD,
+ 0x7AEA, 0x8FBF, 0x68DA, 0x8C37, 0x72F8, 0x9C48, 0x6A3D, 0x8AB0,
+ 0x4E39, 0x5358, 0x5606, 0x5766, 0x62C5, 0x63A2, 0x65E6, 0x6B4E,
+ 0x6DE1, 0x6E5B, 0x70AD, 0x77ED, 0x7AEF, 0x7BAA, 0x7DBB, 0x803D,
+ 0x80C6, 0x86CB, 0x8A95, 0x935B, 0x56E3, 0x58C7, 0x5F3E, 0x65AD,
+ 0x6696, 0x6A80, 0x6BB5, 0x7537, 0x8AC7, 0x5024, 0x77E5, 0x5730,
+ 0x5F1B, 0x6065, 0x667A, 0x6C60, 0x75F4, 0x7A1A, 0x7F6E, 0x81F4,
+ 0x8718, 0x9045, 0x99B3, 0x7BC9, 0x755C, 0x7AF9, 0x7B51, 0x84C4,
+ 0x9010, 0x79E9, 0x7A92, 0x8336, 0x5AE1, 0x7740, 0x4E2D, 0x4EF2,
+ 0x5B99, 0x5FE0, 0x62BD, 0x663C, 0x67F1, 0x6CE8, 0x866B, 0x8877,
+ 0x8A3B, 0x914E, 0x92F3, 0x99D0, 0x6A17, 0x7026, 0x732A, 0x82E7,
+ 0x8457, 0x8CAF, 0x4E01, 0x5146, 0x51CB, 0x558B, 0x5BF5,
+};
+static const unsigned short euc_to_utf8_C4[] = {
+ 0x5E16, 0x5E33, 0x5E81, 0x5F14, 0x5F35, 0x5F6B, 0x5FB4,
+ 0x61F2, 0x6311, 0x66A2, 0x671D, 0x6F6E, 0x7252, 0x753A, 0x773A,
+ 0x8074, 0x8139, 0x8178, 0x8776, 0x8ABF, 0x8ADC, 0x8D85, 0x8DF3,
+ 0x929A, 0x9577, 0x9802, 0x9CE5, 0x52C5, 0x6357, 0x76F4, 0x6715,
+ 0x6C88, 0x73CD, 0x8CC3, 0x93AE, 0x9673, 0x6D25, 0x589C, 0x690E,
+ 0x69CC, 0x8FFD, 0x939A, 0x75DB, 0x901A, 0x585A, 0x6802, 0x63B4,
+ 0x69FB, 0x4F43, 0x6F2C, 0x67D8, 0x8FBB, 0x8526, 0x7DB4, 0x9354,
+ 0x693F, 0x6F70, 0x576A, 0x58F7, 0x5B2C, 0x7D2C, 0x722A, 0x540A,
+ 0x91E3, 0x9DB4, 0x4EAD, 0x4F4E, 0x505C, 0x5075, 0x5243, 0x8C9E,
+ 0x5448, 0x5824, 0x5B9A, 0x5E1D, 0x5E95, 0x5EAD, 0x5EF7, 0x5F1F,
+ 0x608C, 0x62B5, 0x633A, 0x63D0, 0x68AF, 0x6C40, 0x7887, 0x798E,
+ 0x7A0B, 0x7DE0, 0x8247, 0x8A02, 0x8AE6, 0x8E44, 0x9013,
+};
+static const unsigned short euc_to_utf8_C5[] = {
+ 0x90B8, 0x912D, 0x91D8, 0x9F0E, 0x6CE5, 0x6458, 0x64E2,
+ 0x6575, 0x6EF4, 0x7684, 0x7B1B, 0x9069, 0x93D1, 0x6EBA, 0x54F2,
+ 0x5FB9, 0x64A4, 0x8F4D, 0x8FED, 0x9244, 0x5178, 0x586B, 0x5929,
+ 0x5C55, 0x5E97, 0x6DFB, 0x7E8F, 0x751C, 0x8CBC, 0x8EE2, 0x985B,
+ 0x70B9, 0x4F1D, 0x6BBF, 0x6FB1, 0x7530, 0x96FB, 0x514E, 0x5410,
+ 0x5835, 0x5857, 0x59AC, 0x5C60, 0x5F92, 0x6597, 0x675C, 0x6E21,
+ 0x767B, 0x83DF, 0x8CED, 0x9014, 0x90FD, 0x934D, 0x7825, 0x783A,
+ 0x52AA, 0x5EA6, 0x571F, 0x5974, 0x6012, 0x5012, 0x515A, 0x51AC,
+ 0x51CD, 0x5200, 0x5510, 0x5854, 0x5858, 0x5957, 0x5B95, 0x5CF6,
+ 0x5D8B, 0x60BC, 0x6295, 0x642D, 0x6771, 0x6843, 0x68BC, 0x68DF,
+ 0x76D7, 0x6DD8, 0x6E6F, 0x6D9B, 0x706F, 0x71C8, 0x5F53, 0x75D8,
+ 0x7977, 0x7B49, 0x7B54, 0x7B52, 0x7CD6, 0x7D71, 0x5230,
+};
+static const unsigned short euc_to_utf8_C6[] = {
+ 0x8463, 0x8569, 0x85E4, 0x8A0E, 0x8B04, 0x8C46, 0x8E0F,
+ 0x9003, 0x900F, 0x9419, 0x9676, 0x982D, 0x9A30, 0x95D8, 0x50CD,
+ 0x52D5, 0x540C, 0x5802, 0x5C0E, 0x61A7, 0x649E, 0x6D1E, 0x77B3,
+ 0x7AE5, 0x80F4, 0x8404, 0x9053, 0x9285, 0x5CE0, 0x9D07, 0x533F,
+ 0x5F97, 0x5FB3, 0x6D9C, 0x7279, 0x7763, 0x79BF, 0x7BE4, 0x6BD2,
+ 0x72EC, 0x8AAD, 0x6803, 0x6A61, 0x51F8, 0x7A81, 0x6934, 0x5C4A,
+ 0x9CF6, 0x82EB, 0x5BC5, 0x9149, 0x701E, 0x5678, 0x5C6F, 0x60C7,
+ 0x6566, 0x6C8C, 0x8C5A, 0x9041, 0x9813, 0x5451, 0x66C7, 0x920D,
+ 0x5948, 0x90A3, 0x5185, 0x4E4D, 0x51EA, 0x8599, 0x8B0E, 0x7058,
+ 0x637A, 0x934B, 0x6962, 0x99B4, 0x7E04, 0x7577, 0x5357, 0x6960,
+ 0x8EDF, 0x96E3, 0x6C5D, 0x4E8C, 0x5C3C, 0x5F10, 0x8FE9, 0x5302,
+ 0x8CD1, 0x8089, 0x8679, 0x5EFF, 0x65E5, 0x4E73, 0x5165,
+};
+static const unsigned short euc_to_utf8_C7[] = {
+ 0x5982, 0x5C3F, 0x97EE, 0x4EFB, 0x598A, 0x5FCD, 0x8A8D,
+ 0x6FE1, 0x79B0, 0x7962, 0x5BE7, 0x8471, 0x732B, 0x71B1, 0x5E74,
+ 0x5FF5, 0x637B, 0x649A, 0x71C3, 0x7C98, 0x4E43, 0x5EFC, 0x4E4B,
+ 0x57DC, 0x56A2, 0x60A9, 0x6FC3, 0x7D0D, 0x80FD, 0x8133, 0x81BF,
+ 0x8FB2, 0x8997, 0x86A4, 0x5DF4, 0x628A, 0x64AD, 0x8987, 0x6777,
+ 0x6CE2, 0x6D3E, 0x7436, 0x7834, 0x5A46, 0x7F75, 0x82AD, 0x99AC,
+ 0x4FF3, 0x5EC3, 0x62DD, 0x6392, 0x6557, 0x676F, 0x76C3, 0x724C,
+ 0x80CC, 0x80BA, 0x8F29, 0x914D, 0x500D, 0x57F9, 0x5A92, 0x6885,
+ 0x6973, 0x7164, 0x72FD, 0x8CB7, 0x58F2, 0x8CE0, 0x966A, 0x9019,
+ 0x877F, 0x79E4, 0x77E7, 0x8429, 0x4F2F, 0x5265, 0x535A, 0x62CD,
+ 0x67CF, 0x6CCA, 0x767D, 0x7B94, 0x7C95, 0x8236, 0x8584, 0x8FEB,
+ 0x66DD, 0x6F20, 0x7206, 0x7E1B, 0x83AB, 0x99C1, 0x9EA6,
+};
+static const unsigned short euc_to_utf8_C8[] = {
+ 0x51FD, 0x7BB1, 0x7872, 0x7BB8, 0x8087, 0x7B48, 0x6AE8,
+ 0x5E61, 0x808C, 0x7551, 0x7560, 0x516B, 0x9262, 0x6E8C, 0x767A,
+ 0x9197, 0x9AEA, 0x4F10, 0x7F70, 0x629C, 0x7B4F, 0x95A5, 0x9CE9,
+ 0x567A, 0x5859, 0x86E4, 0x96BC, 0x4F34, 0x5224, 0x534A, 0x53CD,
+ 0x53DB, 0x5E06, 0x642C, 0x6591, 0x677F, 0x6C3E, 0x6C4E, 0x7248,
+ 0x72AF, 0x73ED, 0x7554, 0x7E41, 0x822C, 0x85E9, 0x8CA9, 0x7BC4,
+ 0x91C6, 0x7169, 0x9812, 0x98EF, 0x633D, 0x6669, 0x756A, 0x76E4,
+ 0x78D0, 0x8543, 0x86EE, 0x532A, 0x5351, 0x5426, 0x5983, 0x5E87,
+ 0x5F7C, 0x60B2, 0x6249, 0x6279, 0x62AB, 0x6590, 0x6BD4, 0x6CCC,
+ 0x75B2, 0x76AE, 0x7891, 0x79D8, 0x7DCB, 0x7F77, 0x80A5, 0x88AB,
+ 0x8AB9, 0x8CBB, 0x907F, 0x975E, 0x98DB, 0x6A0B, 0x7C38, 0x5099,
+ 0x5C3E, 0x5FAE, 0x6787, 0x6BD8, 0x7435, 0x7709, 0x7F8E,
+};
+static const unsigned short euc_to_utf8_C9[] = {
+ 0x9F3B, 0x67CA, 0x7A17, 0x5339, 0x758B, 0x9AED, 0x5F66,
+ 0x819D, 0x83F1, 0x8098, 0x5F3C, 0x5FC5, 0x7562, 0x7B46, 0x903C,
+ 0x6867, 0x59EB, 0x5A9B, 0x7D10, 0x767E, 0x8B2C, 0x4FF5, 0x5F6A,
+ 0x6A19, 0x6C37, 0x6F02, 0x74E2, 0x7968, 0x8868, 0x8A55, 0x8C79,
+ 0x5EDF, 0x63CF, 0x75C5, 0x79D2, 0x82D7, 0x9328, 0x92F2, 0x849C,
+ 0x86ED, 0x9C2D, 0x54C1, 0x5F6C, 0x658C, 0x6D5C, 0x7015, 0x8CA7,
+ 0x8CD3, 0x983B, 0x654F, 0x74F6, 0x4E0D, 0x4ED8, 0x57E0, 0x592B,
+ 0x5A66, 0x5BCC, 0x51A8, 0x5E03, 0x5E9C, 0x6016, 0x6276, 0x6577,
+ 0x65A7, 0x666E, 0x6D6E, 0x7236, 0x7B26, 0x8150, 0x819A, 0x8299,
+ 0x8B5C, 0x8CA0, 0x8CE6, 0x8D74, 0x961C, 0x9644, 0x4FAE, 0x64AB,
+ 0x6B66, 0x821E, 0x8461, 0x856A, 0x90E8, 0x5C01, 0x6953, 0x98A8,
+ 0x847A, 0x8557, 0x4F0F, 0x526F, 0x5FA9, 0x5E45, 0x670D,
+};
+static const unsigned short euc_to_utf8_CA[] = {
+ 0x798F, 0x8179, 0x8907, 0x8986, 0x6DF5, 0x5F17, 0x6255,
+ 0x6CB8, 0x4ECF, 0x7269, 0x9B92, 0x5206, 0x543B, 0x5674, 0x58B3,
+ 0x61A4, 0x626E, 0x711A, 0x596E, 0x7C89, 0x7CDE, 0x7D1B, 0x96F0,
+ 0x6587, 0x805E, 0x4E19, 0x4F75, 0x5175, 0x5840, 0x5E63, 0x5E73,
+ 0x5F0A, 0x67C4, 0x4E26, 0x853D, 0x9589, 0x965B, 0x7C73, 0x9801,
+ 0x50FB, 0x58C1, 0x7656, 0x78A7, 0x5225, 0x77A5, 0x8511, 0x7B86,
+ 0x504F, 0x5909, 0x7247, 0x7BC7, 0x7DE8, 0x8FBA, 0x8FD4, 0x904D,
+ 0x4FBF, 0x52C9, 0x5A29, 0x5F01, 0x97AD, 0x4FDD, 0x8217, 0x92EA,
+ 0x5703, 0x6355, 0x6B69, 0x752B, 0x88DC, 0x8F14, 0x7A42, 0x52DF,
+ 0x5893, 0x6155, 0x620A, 0x66AE, 0x6BCD, 0x7C3F, 0x83E9, 0x5023,
+ 0x4FF8, 0x5305, 0x5446, 0x5831, 0x5949, 0x5B9D, 0x5CF0, 0x5CEF,
+ 0x5D29, 0x5E96, 0x62B1, 0x6367, 0x653E, 0x65B9, 0x670B,
+};
+static const unsigned short euc_to_utf8_CB[] = {
+ 0x6CD5, 0x6CE1, 0x70F9, 0x7832, 0x7E2B, 0x80DE, 0x82B3,
+ 0x840C, 0x84EC, 0x8702, 0x8912, 0x8A2A, 0x8C4A, 0x90A6, 0x92D2,
+ 0x98FD, 0x9CF3, 0x9D6C, 0x4E4F, 0x4EA1, 0x508D, 0x5256, 0x574A,
+ 0x59A8, 0x5E3D, 0x5FD8, 0x5FD9, 0x623F, 0x66B4, 0x671B, 0x67D0,
+ 0x68D2, 0x5192, 0x7D21, 0x80AA, 0x81A8, 0x8B00, 0x8C8C, 0x8CBF,
+ 0x927E, 0x9632, 0x5420, 0x982C, 0x5317, 0x50D5, 0x535C, 0x58A8,
+ 0x64B2, 0x6734, 0x7267, 0x7766, 0x7A46, 0x91E6, 0x52C3, 0x6CA1,
+ 0x6B86, 0x5800, 0x5E4C, 0x5954, 0x672C, 0x7FFB, 0x51E1, 0x76C6,
+ 0x6469, 0x78E8, 0x9B54, 0x9EBB, 0x57CB, 0x59B9, 0x6627, 0x679A,
+ 0x6BCE, 0x54E9, 0x69D9, 0x5E55, 0x819C, 0x6795, 0x9BAA, 0x67FE,
+ 0x9C52, 0x685D, 0x4EA6, 0x4FE3, 0x53C8, 0x62B9, 0x672B, 0x6CAB,
+ 0x8FC4, 0x4FAD, 0x7E6D, 0x9EBF, 0x4E07, 0x6162, 0x6E80,
+};
+static const unsigned short euc_to_utf8_CC[] = {
+ 0x6F2B, 0x8513, 0x5473, 0x672A, 0x9B45, 0x5DF3, 0x7B95,
+ 0x5CAC, 0x5BC6, 0x871C, 0x6E4A, 0x84D1, 0x7A14, 0x8108, 0x5999,
+ 0x7C8D, 0x6C11, 0x7720, 0x52D9, 0x5922, 0x7121, 0x725F, 0x77DB,
+ 0x9727, 0x9D61, 0x690B, 0x5A7F, 0x5A18, 0x51A5, 0x540D, 0x547D,
+ 0x660E, 0x76DF, 0x8FF7, 0x9298, 0x9CF4, 0x59EA, 0x725D, 0x6EC5,
+ 0x514D, 0x68C9, 0x7DBF, 0x7DEC, 0x9762, 0x9EBA, 0x6478, 0x6A21,
+ 0x8302, 0x5984, 0x5B5F, 0x6BDB, 0x731B, 0x76F2, 0x7DB2, 0x8017,
+ 0x8499, 0x5132, 0x6728, 0x9ED9, 0x76EE, 0x6762, 0x52FF, 0x9905,
+ 0x5C24, 0x623B, 0x7C7E, 0x8CB0, 0x554F, 0x60B6, 0x7D0B, 0x9580,
+ 0x5301, 0x4E5F, 0x51B6, 0x591C, 0x723A, 0x8036, 0x91CE, 0x5F25,
+ 0x77E2, 0x5384, 0x5F79, 0x7D04, 0x85AC, 0x8A33, 0x8E8D, 0x9756,
+ 0x67F3, 0x85AE, 0x9453, 0x6109, 0x6108, 0x6CB9, 0x7652,
+};
+static const unsigned short euc_to_utf8_CD[] = {
+ 0x8AED, 0x8F38, 0x552F, 0x4F51, 0x512A, 0x52C7, 0x53CB,
+ 0x5BA5, 0x5E7D, 0x60A0, 0x6182, 0x63D6, 0x6709, 0x67DA, 0x6E67,
+ 0x6D8C, 0x7336, 0x7337, 0x7531, 0x7950, 0x88D5, 0x8A98, 0x904A,
+ 0x9091, 0x90F5, 0x96C4, 0x878D, 0x5915, 0x4E88, 0x4F59, 0x4E0E,
+ 0x8A89, 0x8F3F, 0x9810, 0x50AD, 0x5E7C, 0x5996, 0x5BB9, 0x5EB8,
+ 0x63DA, 0x63FA, 0x64C1, 0x66DC, 0x694A, 0x69D8, 0x6D0B, 0x6EB6,
+ 0x7194, 0x7528, 0x7AAF, 0x7F8A, 0x8000, 0x8449, 0x84C9, 0x8981,
+ 0x8B21, 0x8E0A, 0x9065, 0x967D, 0x990A, 0x617E, 0x6291, 0x6B32,
+ 0x6C83, 0x6D74, 0x7FCC, 0x7FFC, 0x6DC0, 0x7F85, 0x87BA, 0x88F8,
+ 0x6765, 0x83B1, 0x983C, 0x96F7, 0x6D1B, 0x7D61, 0x843D, 0x916A,
+ 0x4E71, 0x5375, 0x5D50, 0x6B04, 0x6FEB, 0x85CD, 0x862D, 0x89A7,
+ 0x5229, 0x540F, 0x5C65, 0x674E, 0x68A8, 0x7406, 0x7483,
+};
+static const unsigned short euc_to_utf8_CE[] = {
+ 0x75E2, 0x88CF, 0x88E1, 0x91CC, 0x96E2, 0x9678, 0x5F8B,
+ 0x7387, 0x7ACB, 0x844E, 0x63A0, 0x7565, 0x5289, 0x6D41, 0x6E9C,
+ 0x7409, 0x7559, 0x786B, 0x7C92, 0x9686, 0x7ADC, 0x9F8D, 0x4FB6,
+ 0x616E, 0x65C5, 0x865C, 0x4E86, 0x4EAE, 0x50DA, 0x4E21, 0x51CC,
+ 0x5BEE, 0x6599, 0x6881, 0x6DBC, 0x731F, 0x7642, 0x77AD, 0x7A1C,
+ 0x7CE7, 0x826F, 0x8AD2, 0x907C, 0x91CF, 0x9675, 0x9818, 0x529B,
+ 0x7DD1, 0x502B, 0x5398, 0x6797, 0x6DCB, 0x71D0, 0x7433, 0x81E8,
+ 0x8F2A, 0x96A3, 0x9C57, 0x9E9F, 0x7460, 0x5841, 0x6D99, 0x7D2F,
+ 0x985E, 0x4EE4, 0x4F36, 0x4F8B, 0x51B7, 0x52B1, 0x5DBA, 0x601C,
+ 0x73B2, 0x793C, 0x82D3, 0x9234, 0x96B7, 0x96F6, 0x970A, 0x9E97,
+ 0x9F62, 0x66A6, 0x6B74, 0x5217, 0x52A3, 0x70C8, 0x88C2, 0x5EC9,
+ 0x604B, 0x6190, 0x6F23, 0x7149, 0x7C3E, 0x7DF4, 0x806F,
+};
+static const unsigned short euc_to_utf8_CF[] = {
+ 0x84EE, 0x9023, 0x932C, 0x5442, 0x9B6F, 0x6AD3, 0x7089,
+ 0x8CC2, 0x8DEF, 0x9732, 0x52B4, 0x5A41, 0x5ECA, 0x5F04, 0x6717,
+ 0x697C, 0x6994, 0x6D6A, 0x6F0F, 0x7262, 0x72FC, 0x7BED, 0x8001,
+ 0x807E, 0x874B, 0x90CE, 0x516D, 0x9E93, 0x7984, 0x808B, 0x9332,
+ 0x8AD6, 0x502D, 0x548C, 0x8A71, 0x6B6A, 0x8CC4, 0x8107, 0x60D1,
+ 0x67A0, 0x9DF2, 0x4E99, 0x4E98, 0x9C10, 0x8A6B, 0x85C1, 0x8568,
+ 0x6900, 0x6E7E, 0x7897, 0x8155, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_CF_x0213[] = {
+ 0x84EE, 0x9023, 0x932C, 0x5442, 0x9B6F, 0x6AD3, 0x7089,
+ 0x8CC2, 0x8DEF, 0x9732, 0x52B4, 0x5A41, 0x5ECA, 0x5F04, 0x6717,
+ 0x697C, 0x6994, 0x6D6A, 0x6F0F, 0x7262, 0x72FC, 0x7BED, 0x8001,
+ 0x807E, 0x874B, 0x90CE, 0x516D, 0x9E93, 0x7984, 0x808B, 0x9332,
+ 0x8AD6, 0x502D, 0x548C, 0x8A71, 0x6B6A, 0x8CC4, 0x8107, 0x60D1,
+ 0x67A0, 0x9DF2, 0x4E99, 0x4E98, 0x9C10, 0x8A6B, 0x85C1, 0x8568,
+ 0x6900, 0x6E7E, 0x7897, 0x8155, 0xD842 /*0xDF9F*/, 0x5B41, 0x5B56, 0x5B7D,
+ 0x5B93, 0x5BD8, 0x5BEC, 0x5C12, 0x5C1E, 0x5C23, 0x5C2B, 0x378D,
+ 0x5C62, 0xFA3B, 0xFA3C, 0xD845 /*0xDEB4*/, 0x5C7A, 0x5C8F, 0x5C9F, 0x5CA3,
+ 0x5CAA, 0x5CBA, 0x5CCB, 0x5CD0, 0x5CD2, 0x5CF4, 0xD847 /*0xDE34*/, 0x37E2,
+ 0x5D0D, 0x5D27, 0xFA11, 0x5D46, 0x5D47, 0x5D53, 0x5D4A, 0x5D6D,
+ 0x5D81, 0x5DA0, 0x5DA4, 0x5DA7, 0x5DB8, 0x5DCB, 0x541E,
+};
+static const unsigned short euc_to_utf8_D0[] = {
+ 0x5F0C, 0x4E10, 0x4E15, 0x4E2A, 0x4E31, 0x4E36, 0x4E3C,
+ 0x4E3F, 0x4E42, 0x4E56, 0x4E58, 0x4E82, 0x4E85, 0x8C6B, 0x4E8A,
+ 0x8212, 0x5F0D, 0x4E8E, 0x4E9E, 0x4E9F, 0x4EA0, 0x4EA2, 0x4EB0,
+ 0x4EB3, 0x4EB6, 0x4ECE, 0x4ECD, 0x4EC4, 0x4EC6, 0x4EC2, 0x4ED7,
+ 0x4EDE, 0x4EED, 0x4EDF, 0x4EF7, 0x4F09, 0x4F5A, 0x4F30, 0x4F5B,
+ 0x4F5D, 0x4F57, 0x4F47, 0x4F76, 0x4F88, 0x4F8F, 0x4F98, 0x4F7B,
+ 0x4F69, 0x4F70, 0x4F91, 0x4F6F, 0x4F86, 0x4F96, 0x5118, 0x4FD4,
+ 0x4FDF, 0x4FCE, 0x4FD8, 0x4FDB, 0x4FD1, 0x4FDA, 0x4FD0, 0x4FE4,
+ 0x4FE5, 0x501A, 0x5028, 0x5014, 0x502A, 0x5025, 0x5005, 0x4F1C,
+ 0x4FF6, 0x5021, 0x5029, 0x502C, 0x4FFE, 0x4FEF, 0x5011, 0x5006,
+ 0x5043, 0x5047, 0x6703, 0x5055, 0x5050, 0x5048, 0x505A, 0x5056,
+ 0x506C, 0x5078, 0x5080, 0x509A, 0x5085, 0x50B4, 0x50B2,
+};
+static const unsigned short euc_to_utf8_D1[] = {
+ 0x50C9, 0x50CA, 0x50B3, 0x50C2, 0x50D6, 0x50DE, 0x50E5,
+ 0x50ED, 0x50E3, 0x50EE, 0x50F9, 0x50F5, 0x5109, 0x5101, 0x5102,
+ 0x5116, 0x5115, 0x5114, 0x511A, 0x5121, 0x513A, 0x5137, 0x513C,
+ 0x513B, 0x513F, 0x5140, 0x5152, 0x514C, 0x5154, 0x5162, 0x7AF8,
+ 0x5169, 0x516A, 0x516E, 0x5180, 0x5182, 0x56D8, 0x518C, 0x5189,
+ 0x518F, 0x5191, 0x5193, 0x5195, 0x5196, 0x51A4, 0x51A6, 0x51A2,
+ 0x51A9, 0x51AA, 0x51AB, 0x51B3, 0x51B1, 0x51B2, 0x51B0, 0x51B5,
+ 0x51BD, 0x51C5, 0x51C9, 0x51DB, 0x51E0, 0x8655, 0x51E9, 0x51ED,
+ 0x51F0, 0x51F5, 0x51FE, 0x5204, 0x520B, 0x5214, 0x520E, 0x5227,
+ 0x522A, 0x522E, 0x5233, 0x5239, 0x524F, 0x5244, 0x524B, 0x524C,
+ 0x525E, 0x5254, 0x526A, 0x5274, 0x5269, 0x5273, 0x527F, 0x527D,
+ 0x528D, 0x5294, 0x5292, 0x5271, 0x5288, 0x5291, 0x8FA8,
+};
+static const unsigned short euc_to_utf8_D2[] = {
+ 0x8FA7, 0x52AC, 0x52AD, 0x52BC, 0x52B5, 0x52C1, 0x52CD,
+ 0x52D7, 0x52DE, 0x52E3, 0x52E6, 0x98ED, 0x52E0, 0x52F3, 0x52F5,
+ 0x52F8, 0x52F9, 0x5306, 0x5308, 0x7538, 0x530D, 0x5310, 0x530F,
+ 0x5315, 0x531A, 0x5323, 0x532F, 0x5331, 0x5333, 0x5338, 0x5340,
+ 0x5346, 0x5345, 0x4E17, 0x5349, 0x534D, 0x51D6, 0x535E, 0x5369,
+ 0x536E, 0x5918, 0x537B, 0x5377, 0x5382, 0x5396, 0x53A0, 0x53A6,
+ 0x53A5, 0x53AE, 0x53B0, 0x53B6, 0x53C3, 0x7C12, 0x96D9, 0x53DF,
+ 0x66FC, 0x71EE, 0x53EE, 0x53E8, 0x53ED, 0x53FA, 0x5401, 0x543D,
+ 0x5440, 0x542C, 0x542D, 0x543C, 0x542E, 0x5436, 0x5429, 0x541D,
+ 0x544E, 0x548F, 0x5475, 0x548E, 0x545F, 0x5471, 0x5477, 0x5470,
+ 0x5492, 0x547B, 0x5480, 0x5476, 0x5484, 0x5490, 0x5486, 0x54C7,
+ 0x54A2, 0x54B8, 0x54A5, 0x54AC, 0x54C4, 0x54C8, 0x54A8,
+};
+static const unsigned short euc_to_utf8_D3[] = {
+ 0x54AB, 0x54C2, 0x54A4, 0x54BE, 0x54BC, 0x54D8, 0x54E5,
+ 0x54E6, 0x550F, 0x5514, 0x54FD, 0x54EE, 0x54ED, 0x54FA, 0x54E2,
+ 0x5539, 0x5540, 0x5563, 0x554C, 0x552E, 0x555C, 0x5545, 0x5556,
+ 0x5557, 0x5538, 0x5533, 0x555D, 0x5599, 0x5580, 0x54AF, 0x558A,
+ 0x559F, 0x557B, 0x557E, 0x5598, 0x559E, 0x55AE, 0x557C, 0x5583,
+ 0x55A9, 0x5587, 0x55A8, 0x55DA, 0x55C5, 0x55DF, 0x55C4, 0x55DC,
+ 0x55E4, 0x55D4, 0x5614, 0x55F7, 0x5616, 0x55FE, 0x55FD, 0x561B,
+ 0x55F9, 0x564E, 0x5650, 0x71DF, 0x5634, 0x5636, 0x5632, 0x5638,
+ 0x566B, 0x5664, 0x562F, 0x566C, 0x566A, 0x5686, 0x5680, 0x568A,
+ 0x56A0, 0x5694, 0x568F, 0x56A5, 0x56AE, 0x56B6, 0x56B4, 0x56C2,
+ 0x56BC, 0x56C1, 0x56C3, 0x56C0, 0x56C8, 0x56CE, 0x56D1, 0x56D3,
+ 0x56D7, 0x56EE, 0x56F9, 0x5700, 0x56FF, 0x5704, 0x5709,
+};
+static const unsigned short euc_to_utf8_D4[] = {
+ 0x5708, 0x570B, 0x570D, 0x5713, 0x5718, 0x5716, 0x55C7,
+ 0x571C, 0x5726, 0x5737, 0x5738, 0x574E, 0x573B, 0x5740, 0x574F,
+ 0x5769, 0x57C0, 0x5788, 0x5761, 0x577F, 0x5789, 0x5793, 0x57A0,
+ 0x57B3, 0x57A4, 0x57AA, 0x57B0, 0x57C3, 0x57C6, 0x57D4, 0x57D2,
+ 0x57D3, 0x580A, 0x57D6, 0x57E3, 0x580B, 0x5819, 0x581D, 0x5872,
+ 0x5821, 0x5862, 0x584B, 0x5870, 0x6BC0, 0x5852, 0x583D, 0x5879,
+ 0x5885, 0x58B9, 0x589F, 0x58AB, 0x58BA, 0x58DE, 0x58BB, 0x58B8,
+ 0x58AE, 0x58C5, 0x58D3, 0x58D1, 0x58D7, 0x58D9, 0x58D8, 0x58E5,
+ 0x58DC, 0x58E4, 0x58DF, 0x58EF, 0x58FA, 0x58F9, 0x58FB, 0x58FC,
+ 0x58FD, 0x5902, 0x590A, 0x5910, 0x591B, 0x68A6, 0x5925, 0x592C,
+ 0x592D, 0x5932, 0x5938, 0x593E, 0x7AD2, 0x5955, 0x5950, 0x594E,
+ 0x595A, 0x5958, 0x5962, 0x5960, 0x5967, 0x596C, 0x5969,
+};
+static const unsigned short euc_to_utf8_D5[] = {
+ 0x5978, 0x5981, 0x599D, 0x4F5E, 0x4FAB, 0x59A3, 0x59B2,
+ 0x59C6, 0x59E8, 0x59DC, 0x598D, 0x59D9, 0x59DA, 0x5A25, 0x5A1F,
+ 0x5A11, 0x5A1C, 0x5A09, 0x5A1A, 0x5A40, 0x5A6C, 0x5A49, 0x5A35,
+ 0x5A36, 0x5A62, 0x5A6A, 0x5A9A, 0x5ABC, 0x5ABE, 0x5ACB, 0x5AC2,
+ 0x5ABD, 0x5AE3, 0x5AD7, 0x5AE6, 0x5AE9, 0x5AD6, 0x5AFA, 0x5AFB,
+ 0x5B0C, 0x5B0B, 0x5B16, 0x5B32, 0x5AD0, 0x5B2A, 0x5B36, 0x5B3E,
+ 0x5B43, 0x5B45, 0x5B40, 0x5B51, 0x5B55, 0x5B5A, 0x5B5B, 0x5B65,
+ 0x5B69, 0x5B70, 0x5B73, 0x5B75, 0x5B78, 0x6588, 0x5B7A, 0x5B80,
+ 0x5B83, 0x5BA6, 0x5BB8, 0x5BC3, 0x5BC7, 0x5BC9, 0x5BD4, 0x5BD0,
+ 0x5BE4, 0x5BE6, 0x5BE2, 0x5BDE, 0x5BE5, 0x5BEB, 0x5BF0, 0x5BF6,
+ 0x5BF3, 0x5C05, 0x5C07, 0x5C08, 0x5C0D, 0x5C13, 0x5C20, 0x5C22,
+ 0x5C28, 0x5C38, 0x5C39, 0x5C41, 0x5C46, 0x5C4E, 0x5C53,
+};
+static const unsigned short euc_to_utf8_D6[] = {
+ 0x5C50, 0x5C4F, 0x5B71, 0x5C6C, 0x5C6E, 0x4E62, 0x5C76,
+ 0x5C79, 0x5C8C, 0x5C91, 0x5C94, 0x599B, 0x5CAB, 0x5CBB, 0x5CB6,
+ 0x5CBC, 0x5CB7, 0x5CC5, 0x5CBE, 0x5CC7, 0x5CD9, 0x5CE9, 0x5CFD,
+ 0x5CFA, 0x5CED, 0x5D8C, 0x5CEA, 0x5D0B, 0x5D15, 0x5D17, 0x5D5C,
+ 0x5D1F, 0x5D1B, 0x5D11, 0x5D14, 0x5D22, 0x5D1A, 0x5D19, 0x5D18,
+ 0x5D4C, 0x5D52, 0x5D4E, 0x5D4B, 0x5D6C, 0x5D73, 0x5D76, 0x5D87,
+ 0x5D84, 0x5D82, 0x5DA2, 0x5D9D, 0x5DAC, 0x5DAE, 0x5DBD, 0x5D90,
+ 0x5DB7, 0x5DBC, 0x5DC9, 0x5DCD, 0x5DD3, 0x5DD2, 0x5DD6, 0x5DDB,
+ 0x5DEB, 0x5DF2, 0x5DF5, 0x5E0B, 0x5E1A, 0x5E19, 0x5E11, 0x5E1B,
+ 0x5E36, 0x5E37, 0x5E44, 0x5E43, 0x5E40, 0x5E4E, 0x5E57, 0x5E54,
+ 0x5E5F, 0x5E62, 0x5E64, 0x5E47, 0x5E75, 0x5E76, 0x5E7A, 0x9EBC,
+ 0x5E7F, 0x5EA0, 0x5EC1, 0x5EC2, 0x5EC8, 0x5ED0, 0x5ECF,
+};
+static const unsigned short euc_to_utf8_D7[] = {
+ 0x5ED6, 0x5EE3, 0x5EDD, 0x5EDA, 0x5EDB, 0x5EE2, 0x5EE1,
+ 0x5EE8, 0x5EE9, 0x5EEC, 0x5EF1, 0x5EF3, 0x5EF0, 0x5EF4, 0x5EF8,
+ 0x5EFE, 0x5F03, 0x5F09, 0x5F5D, 0x5F5C, 0x5F0B, 0x5F11, 0x5F16,
+ 0x5F29, 0x5F2D, 0x5F38, 0x5F41, 0x5F48, 0x5F4C, 0x5F4E, 0x5F2F,
+ 0x5F51, 0x5F56, 0x5F57, 0x5F59, 0x5F61, 0x5F6D, 0x5F73, 0x5F77,
+ 0x5F83, 0x5F82, 0x5F7F, 0x5F8A, 0x5F88, 0x5F91, 0x5F87, 0x5F9E,
+ 0x5F99, 0x5F98, 0x5FA0, 0x5FA8, 0x5FAD, 0x5FBC, 0x5FD6, 0x5FFB,
+ 0x5FE4, 0x5FF8, 0x5FF1, 0x5FDD, 0x60B3, 0x5FFF, 0x6021, 0x6060,
+ 0x6019, 0x6010, 0x6029, 0x600E, 0x6031, 0x601B, 0x6015, 0x602B,
+ 0x6026, 0x600F, 0x603A, 0x605A, 0x6041, 0x606A, 0x6077, 0x605F,
+ 0x604A, 0x6046, 0x604D, 0x6063, 0x6043, 0x6064, 0x6042, 0x606C,
+ 0x606B, 0x6059, 0x6081, 0x608D, 0x60E7, 0x6083, 0x609A,
+};
+static const unsigned short euc_to_utf8_D8[] = {
+ 0x6084, 0x609B, 0x6096, 0x6097, 0x6092, 0x60A7, 0x608B,
+ 0x60E1, 0x60B8, 0x60E0, 0x60D3, 0x60B4, 0x5FF0, 0x60BD, 0x60C6,
+ 0x60B5, 0x60D8, 0x614D, 0x6115, 0x6106, 0x60F6, 0x60F7, 0x6100,
+ 0x60F4, 0x60FA, 0x6103, 0x6121, 0x60FB, 0x60F1, 0x610D, 0x610E,
+ 0x6147, 0x613E, 0x6128, 0x6127, 0x614A, 0x613F, 0x613C, 0x612C,
+ 0x6134, 0x613D, 0x6142, 0x6144, 0x6173, 0x6177, 0x6158, 0x6159,
+ 0x615A, 0x616B, 0x6174, 0x616F, 0x6165, 0x6171, 0x615F, 0x615D,
+ 0x6153, 0x6175, 0x6199, 0x6196, 0x6187, 0x61AC, 0x6194, 0x619A,
+ 0x618A, 0x6191, 0x61AB, 0x61AE, 0x61CC, 0x61CA, 0x61C9, 0x61F7,
+ 0x61C8, 0x61C3, 0x61C6, 0x61BA, 0x61CB, 0x7F79, 0x61CD, 0x61E6,
+ 0x61E3, 0x61F6, 0x61FA, 0x61F4, 0x61FF, 0x61FD, 0x61FC, 0x61FE,
+ 0x6200, 0x6208, 0x6209, 0x620D, 0x620C, 0x6214, 0x621B,
+};
+static const unsigned short euc_to_utf8_D9[] = {
+ 0x621E, 0x6221, 0x622A, 0x622E, 0x6230, 0x6232, 0x6233,
+ 0x6241, 0x624E, 0x625E, 0x6263, 0x625B, 0x6260, 0x6268, 0x627C,
+ 0x6282, 0x6289, 0x627E, 0x6292, 0x6293, 0x6296, 0x62D4, 0x6283,
+ 0x6294, 0x62D7, 0x62D1, 0x62BB, 0x62CF, 0x62FF, 0x62C6, 0x64D4,
+ 0x62C8, 0x62DC, 0x62CC, 0x62CA, 0x62C2, 0x62C7, 0x629B, 0x62C9,
+ 0x630C, 0x62EE, 0x62F1, 0x6327, 0x6302, 0x6308, 0x62EF, 0x62F5,
+ 0x6350, 0x633E, 0x634D, 0x641C, 0x634F, 0x6396, 0x638E, 0x6380,
+ 0x63AB, 0x6376, 0x63A3, 0x638F, 0x6389, 0x639F, 0x63B5, 0x636B,
+ 0x6369, 0x63BE, 0x63E9, 0x63C0, 0x63C6, 0x63E3, 0x63C9, 0x63D2,
+ 0x63F6, 0x63C4, 0x6416, 0x6434, 0x6406, 0x6413, 0x6426, 0x6436,
+ 0x651D, 0x6417, 0x6428, 0x640F, 0x6467, 0x646F, 0x6476, 0x644E,
+ 0x652A, 0x6495, 0x6493, 0x64A5, 0x64A9, 0x6488, 0x64BC,
+};
+static const unsigned short euc_to_utf8_DA[] = {
+ 0x64DA, 0x64D2, 0x64C5, 0x64C7, 0x64BB, 0x64D8, 0x64C2,
+ 0x64F1, 0x64E7, 0x8209, 0x64E0, 0x64E1, 0x62AC, 0x64E3, 0x64EF,
+ 0x652C, 0x64F6, 0x64F4, 0x64F2, 0x64FA, 0x6500, 0x64FD, 0x6518,
+ 0x651C, 0x6505, 0x6524, 0x6523, 0x652B, 0x6534, 0x6535, 0x6537,
+ 0x6536, 0x6538, 0x754B, 0x6548, 0x6556, 0x6555, 0x654D, 0x6558,
+ 0x655E, 0x655D, 0x6572, 0x6578, 0x6582, 0x6583, 0x8B8A, 0x659B,
+ 0x659F, 0x65AB, 0x65B7, 0x65C3, 0x65C6, 0x65C1, 0x65C4, 0x65CC,
+ 0x65D2, 0x65DB, 0x65D9, 0x65E0, 0x65E1, 0x65F1, 0x6772, 0x660A,
+ 0x6603, 0x65FB, 0x6773, 0x6635, 0x6636, 0x6634, 0x661C, 0x664F,
+ 0x6644, 0x6649, 0x6641, 0x665E, 0x665D, 0x6664, 0x6667, 0x6668,
+ 0x665F, 0x6662, 0x6670, 0x6683, 0x6688, 0x668E, 0x6689, 0x6684,
+ 0x6698, 0x669D, 0x66C1, 0x66B9, 0x66C9, 0x66BE, 0x66BC,
+};
+static const unsigned short euc_to_utf8_DB[] = {
+ 0x66C4, 0x66B8, 0x66D6, 0x66DA, 0x66E0, 0x663F, 0x66E6,
+ 0x66E9, 0x66F0, 0x66F5, 0x66F7, 0x670F, 0x6716, 0x671E, 0x6726,
+ 0x6727, 0x9738, 0x672E, 0x673F, 0x6736, 0x6741, 0x6738, 0x6737,
+ 0x6746, 0x675E, 0x6760, 0x6759, 0x6763, 0x6764, 0x6789, 0x6770,
+ 0x67A9, 0x677C, 0x676A, 0x678C, 0x678B, 0x67A6, 0x67A1, 0x6785,
+ 0x67B7, 0x67EF, 0x67B4, 0x67EC, 0x67B3, 0x67E9, 0x67B8, 0x67E4,
+ 0x67DE, 0x67DD, 0x67E2, 0x67EE, 0x67B9, 0x67CE, 0x67C6, 0x67E7,
+ 0x6A9C, 0x681E, 0x6846, 0x6829, 0x6840, 0x684D, 0x6832, 0x684E,
+ 0x68B3, 0x682B, 0x6859, 0x6863, 0x6877, 0x687F, 0x689F, 0x688F,
+ 0x68AD, 0x6894, 0x689D, 0x689B, 0x6883, 0x6AAE, 0x68B9, 0x6874,
+ 0x68B5, 0x68A0, 0x68BA, 0x690F, 0x688D, 0x687E, 0x6901, 0x68CA,
+ 0x6908, 0x68D8, 0x6922, 0x6926, 0x68E1, 0x690C, 0x68CD,
+};
+static const unsigned short euc_to_utf8_DC[] = {
+ 0x68D4, 0x68E7, 0x68D5, 0x6936, 0x6912, 0x6904, 0x68D7,
+ 0x68E3, 0x6925, 0x68F9, 0x68E0, 0x68EF, 0x6928, 0x692A, 0x691A,
+ 0x6923, 0x6921, 0x68C6, 0x6979, 0x6977, 0x695C, 0x6978, 0x696B,
+ 0x6954, 0x697E, 0x696E, 0x6939, 0x6974, 0x693D, 0x6959, 0x6930,
+ 0x6961, 0x695E, 0x695D, 0x6981, 0x696A, 0x69B2, 0x69AE, 0x69D0,
+ 0x69BF, 0x69C1, 0x69D3, 0x69BE, 0x69CE, 0x5BE8, 0x69CA, 0x69DD,
+ 0x69BB, 0x69C3, 0x69A7, 0x6A2E, 0x6991, 0x69A0, 0x699C, 0x6995,
+ 0x69B4, 0x69DE, 0x69E8, 0x6A02, 0x6A1B, 0x69FF, 0x6B0A, 0x69F9,
+ 0x69F2, 0x69E7, 0x6A05, 0x69B1, 0x6A1E, 0x69ED, 0x6A14, 0x69EB,
+ 0x6A0A, 0x6A12, 0x6AC1, 0x6A23, 0x6A13, 0x6A44, 0x6A0C, 0x6A72,
+ 0x6A36, 0x6A78, 0x6A47, 0x6A62, 0x6A59, 0x6A66, 0x6A48, 0x6A38,
+ 0x6A22, 0x6A90, 0x6A8D, 0x6AA0, 0x6A84, 0x6AA2, 0x6AA3,
+};
+static const unsigned short euc_to_utf8_DD[] = {
+ 0x6A97, 0x8617, 0x6ABB, 0x6AC3, 0x6AC2, 0x6AB8, 0x6AB3,
+ 0x6AAC, 0x6ADE, 0x6AD1, 0x6ADF, 0x6AAA, 0x6ADA, 0x6AEA, 0x6AFB,
+ 0x6B05, 0x8616, 0x6AFA, 0x6B12, 0x6B16, 0x9B31, 0x6B1F, 0x6B38,
+ 0x6B37, 0x76DC, 0x6B39, 0x98EE, 0x6B47, 0x6B43, 0x6B49, 0x6B50,
+ 0x6B59, 0x6B54, 0x6B5B, 0x6B5F, 0x6B61, 0x6B78, 0x6B79, 0x6B7F,
+ 0x6B80, 0x6B84, 0x6B83, 0x6B8D, 0x6B98, 0x6B95, 0x6B9E, 0x6BA4,
+ 0x6BAA, 0x6BAB, 0x6BAF, 0x6BB2, 0x6BB1, 0x6BB3, 0x6BB7, 0x6BBC,
+ 0x6BC6, 0x6BCB, 0x6BD3, 0x6BDF, 0x6BEC, 0x6BEB, 0x6BF3, 0x6BEF,
+ 0x9EBE, 0x6C08, 0x6C13, 0x6C14, 0x6C1B, 0x6C24, 0x6C23, 0x6C5E,
+ 0x6C55, 0x6C62, 0x6C6A, 0x6C82, 0x6C8D, 0x6C9A, 0x6C81, 0x6C9B,
+ 0x6C7E, 0x6C68, 0x6C73, 0x6C92, 0x6C90, 0x6CC4, 0x6CF1, 0x6CD3,
+ 0x6CBD, 0x6CD7, 0x6CC5, 0x6CDD, 0x6CAE, 0x6CB1, 0x6CBE,
+};
+static const unsigned short euc_to_utf8_DE[] = {
+ 0x6CBA, 0x6CDB, 0x6CEF, 0x6CD9, 0x6CEA, 0x6D1F, 0x884D,
+ 0x6D36, 0x6D2B, 0x6D3D, 0x6D38, 0x6D19, 0x6D35, 0x6D33, 0x6D12,
+ 0x6D0C, 0x6D63, 0x6D93, 0x6D64, 0x6D5A, 0x6D79, 0x6D59, 0x6D8E,
+ 0x6D95, 0x6FE4, 0x6D85, 0x6DF9, 0x6E15, 0x6E0A, 0x6DB5, 0x6DC7,
+ 0x6DE6, 0x6DB8, 0x6DC6, 0x6DEC, 0x6DDE, 0x6DCC, 0x6DE8, 0x6DD2,
+ 0x6DC5, 0x6DFA, 0x6DD9, 0x6DE4, 0x6DD5, 0x6DEA, 0x6DEE, 0x6E2D,
+ 0x6E6E, 0x6E2E, 0x6E19, 0x6E72, 0x6E5F, 0x6E3E, 0x6E23, 0x6E6B,
+ 0x6E2B, 0x6E76, 0x6E4D, 0x6E1F, 0x6E43, 0x6E3A, 0x6E4E, 0x6E24,
+ 0x6EFF, 0x6E1D, 0x6E38, 0x6E82, 0x6EAA, 0x6E98, 0x6EC9, 0x6EB7,
+ 0x6ED3, 0x6EBD, 0x6EAF, 0x6EC4, 0x6EB2, 0x6ED4, 0x6ED5, 0x6E8F,
+ 0x6EA5, 0x6EC2, 0x6E9F, 0x6F41, 0x6F11, 0x704C, 0x6EEC, 0x6EF8,
+ 0x6EFE, 0x6F3F, 0x6EF2, 0x6F31, 0x6EEF, 0x6F32, 0x6ECC,
+};
+static const unsigned short euc_to_utf8_DF[] = {
+ 0x6F3E, 0x6F13, 0x6EF7, 0x6F86, 0x6F7A, 0x6F78, 0x6F81,
+ 0x6F80, 0x6F6F, 0x6F5B, 0x6FF3, 0x6F6D, 0x6F82, 0x6F7C, 0x6F58,
+ 0x6F8E, 0x6F91, 0x6FC2, 0x6F66, 0x6FB3, 0x6FA3, 0x6FA1, 0x6FA4,
+ 0x6FB9, 0x6FC6, 0x6FAA, 0x6FDF, 0x6FD5, 0x6FEC, 0x6FD4, 0x6FD8,
+ 0x6FF1, 0x6FEE, 0x6FDB, 0x7009, 0x700B, 0x6FFA, 0x7011, 0x7001,
+ 0x700F, 0x6FFE, 0x701B, 0x701A, 0x6F74, 0x701D, 0x7018, 0x701F,
+ 0x7030, 0x703E, 0x7032, 0x7051, 0x7063, 0x7099, 0x7092, 0x70AF,
+ 0x70F1, 0x70AC, 0x70B8, 0x70B3, 0x70AE, 0x70DF, 0x70CB, 0x70DD,
+ 0x70D9, 0x7109, 0x70FD, 0x711C, 0x7119, 0x7165, 0x7155, 0x7188,
+ 0x7166, 0x7162, 0x714C, 0x7156, 0x716C, 0x718F, 0x71FB, 0x7184,
+ 0x7195, 0x71A8, 0x71AC, 0x71D7, 0x71B9, 0x71BE, 0x71D2, 0x71C9,
+ 0x71D4, 0x71CE, 0x71E0, 0x71EC, 0x71E7, 0x71F5, 0x71FC,
+};
+static const unsigned short euc_to_utf8_E0[] = {
+ 0x71F9, 0x71FF, 0x720D, 0x7210, 0x721B, 0x7228, 0x722D,
+ 0x722C, 0x7230, 0x7232, 0x723B, 0x723C, 0x723F, 0x7240, 0x7246,
+ 0x724B, 0x7258, 0x7274, 0x727E, 0x7282, 0x7281, 0x7287, 0x7292,
+ 0x7296, 0x72A2, 0x72A7, 0x72B9, 0x72B2, 0x72C3, 0x72C6, 0x72C4,
+ 0x72CE, 0x72D2, 0x72E2, 0x72E0, 0x72E1, 0x72F9, 0x72F7, 0x500F,
+ 0x7317, 0x730A, 0x731C, 0x7316, 0x731D, 0x7334, 0x732F, 0x7329,
+ 0x7325, 0x733E, 0x734E, 0x734F, 0x9ED8, 0x7357, 0x736A, 0x7368,
+ 0x7370, 0x7378, 0x7375, 0x737B, 0x737A, 0x73C8, 0x73B3, 0x73CE,
+ 0x73BB, 0x73C0, 0x73E5, 0x73EE, 0x73DE, 0x74A2, 0x7405, 0x746F,
+ 0x7425, 0x73F8, 0x7432, 0x743A, 0x7455, 0x743F, 0x745F, 0x7459,
+ 0x7441, 0x745C, 0x7469, 0x7470, 0x7463, 0x746A, 0x7476, 0x747E,
+ 0x748B, 0x749E, 0x74A7, 0x74CA, 0x74CF, 0x74D4, 0x73F1,
+};
+static const unsigned short euc_to_utf8_E1[] = {
+ 0x74E0, 0x74E3, 0x74E7, 0x74E9, 0x74EE, 0x74F2, 0x74F0,
+ 0x74F1, 0x74F8, 0x74F7, 0x7504, 0x7503, 0x7505, 0x750C, 0x750E,
+ 0x750D, 0x7515, 0x7513, 0x751E, 0x7526, 0x752C, 0x753C, 0x7544,
+ 0x754D, 0x754A, 0x7549, 0x755B, 0x7546, 0x755A, 0x7569, 0x7564,
+ 0x7567, 0x756B, 0x756D, 0x7578, 0x7576, 0x7586, 0x7587, 0x7574,
+ 0x758A, 0x7589, 0x7582, 0x7594, 0x759A, 0x759D, 0x75A5, 0x75A3,
+ 0x75C2, 0x75B3, 0x75C3, 0x75B5, 0x75BD, 0x75B8, 0x75BC, 0x75B1,
+ 0x75CD, 0x75CA, 0x75D2, 0x75D9, 0x75E3, 0x75DE, 0x75FE, 0x75FF,
+ 0x75FC, 0x7601, 0x75F0, 0x75FA, 0x75F2, 0x75F3, 0x760B, 0x760D,
+ 0x7609, 0x761F, 0x7627, 0x7620, 0x7621, 0x7622, 0x7624, 0x7634,
+ 0x7630, 0x763B, 0x7647, 0x7648, 0x7646, 0x765C, 0x7658, 0x7661,
+ 0x7662, 0x7668, 0x7669, 0x766A, 0x7667, 0x766C, 0x7670,
+};
+static const unsigned short euc_to_utf8_E2[] = {
+ 0x7672, 0x7676, 0x7678, 0x767C, 0x7680, 0x7683, 0x7688,
+ 0x768B, 0x768E, 0x7696, 0x7693, 0x7699, 0x769A, 0x76B0, 0x76B4,
+ 0x76B8, 0x76B9, 0x76BA, 0x76C2, 0x76CD, 0x76D6, 0x76D2, 0x76DE,
+ 0x76E1, 0x76E5, 0x76E7, 0x76EA, 0x862F, 0x76FB, 0x7708, 0x7707,
+ 0x7704, 0x7729, 0x7724, 0x771E, 0x7725, 0x7726, 0x771B, 0x7737,
+ 0x7738, 0x7747, 0x775A, 0x7768, 0x776B, 0x775B, 0x7765, 0x777F,
+ 0x777E, 0x7779, 0x778E, 0x778B, 0x7791, 0x77A0, 0x779E, 0x77B0,
+ 0x77B6, 0x77B9, 0x77BF, 0x77BC, 0x77BD, 0x77BB, 0x77C7, 0x77CD,
+ 0x77D7, 0x77DA, 0x77DC, 0x77E3, 0x77EE, 0x77FC, 0x780C, 0x7812,
+ 0x7926, 0x7820, 0x792A, 0x7845, 0x788E, 0x7874, 0x7886, 0x787C,
+ 0x789A, 0x788C, 0x78A3, 0x78B5, 0x78AA, 0x78AF, 0x78D1, 0x78C6,
+ 0x78CB, 0x78D4, 0x78BE, 0x78BC, 0x78C5, 0x78CA, 0x78EC,
+};
+static const unsigned short euc_to_utf8_E3[] = {
+ 0x78E7, 0x78DA, 0x78FD, 0x78F4, 0x7907, 0x7912, 0x7911,
+ 0x7919, 0x792C, 0x792B, 0x7940, 0x7960, 0x7957, 0x795F, 0x795A,
+ 0x7955, 0x7953, 0x797A, 0x797F, 0x798A, 0x799D, 0x79A7, 0x9F4B,
+ 0x79AA, 0x79AE, 0x79B3, 0x79B9, 0x79BA, 0x79C9, 0x79D5, 0x79E7,
+ 0x79EC, 0x79E1, 0x79E3, 0x7A08, 0x7A0D, 0x7A18, 0x7A19, 0x7A20,
+ 0x7A1F, 0x7980, 0x7A31, 0x7A3B, 0x7A3E, 0x7A37, 0x7A43, 0x7A57,
+ 0x7A49, 0x7A61, 0x7A62, 0x7A69, 0x9F9D, 0x7A70, 0x7A79, 0x7A7D,
+ 0x7A88, 0x7A97, 0x7A95, 0x7A98, 0x7A96, 0x7AA9, 0x7AC8, 0x7AB0,
+ 0x7AB6, 0x7AC5, 0x7AC4, 0x7ABF, 0x9083, 0x7AC7, 0x7ACA, 0x7ACD,
+ 0x7ACF, 0x7AD5, 0x7AD3, 0x7AD9, 0x7ADA, 0x7ADD, 0x7AE1, 0x7AE2,
+ 0x7AE6, 0x7AED, 0x7AF0, 0x7B02, 0x7B0F, 0x7B0A, 0x7B06, 0x7B33,
+ 0x7B18, 0x7B19, 0x7B1E, 0x7B35, 0x7B28, 0x7B36, 0x7B50,
+};
+static const unsigned short euc_to_utf8_E4[] = {
+ 0x7B7A, 0x7B04, 0x7B4D, 0x7B0B, 0x7B4C, 0x7B45, 0x7B75,
+ 0x7B65, 0x7B74, 0x7B67, 0x7B70, 0x7B71, 0x7B6C, 0x7B6E, 0x7B9D,
+ 0x7B98, 0x7B9F, 0x7B8D, 0x7B9C, 0x7B9A, 0x7B8B, 0x7B92, 0x7B8F,
+ 0x7B5D, 0x7B99, 0x7BCB, 0x7BC1, 0x7BCC, 0x7BCF, 0x7BB4, 0x7BC6,
+ 0x7BDD, 0x7BE9, 0x7C11, 0x7C14, 0x7BE6, 0x7BE5, 0x7C60, 0x7C00,
+ 0x7C07, 0x7C13, 0x7BF3, 0x7BF7, 0x7C17, 0x7C0D, 0x7BF6, 0x7C23,
+ 0x7C27, 0x7C2A, 0x7C1F, 0x7C37, 0x7C2B, 0x7C3D, 0x7C4C, 0x7C43,
+ 0x7C54, 0x7C4F, 0x7C40, 0x7C50, 0x7C58, 0x7C5F, 0x7C64, 0x7C56,
+ 0x7C65, 0x7C6C, 0x7C75, 0x7C83, 0x7C90, 0x7CA4, 0x7CAD, 0x7CA2,
+ 0x7CAB, 0x7CA1, 0x7CA8, 0x7CB3, 0x7CB2, 0x7CB1, 0x7CAE, 0x7CB9,
+ 0x7CBD, 0x7CC0, 0x7CC5, 0x7CC2, 0x7CD8, 0x7CD2, 0x7CDC, 0x7CE2,
+ 0x9B3B, 0x7CEF, 0x7CF2, 0x7CF4, 0x7CF6, 0x7CFA, 0x7D06,
+};
+static const unsigned short euc_to_utf8_E5[] = {
+ 0x7D02, 0x7D1C, 0x7D15, 0x7D0A, 0x7D45, 0x7D4B, 0x7D2E,
+ 0x7D32, 0x7D3F, 0x7D35, 0x7D46, 0x7D73, 0x7D56, 0x7D4E, 0x7D72,
+ 0x7D68, 0x7D6E, 0x7D4F, 0x7D63, 0x7D93, 0x7D89, 0x7D5B, 0x7D8F,
+ 0x7D7D, 0x7D9B, 0x7DBA, 0x7DAE, 0x7DA3, 0x7DB5, 0x7DC7, 0x7DBD,
+ 0x7DAB, 0x7E3D, 0x7DA2, 0x7DAF, 0x7DDC, 0x7DB8, 0x7D9F, 0x7DB0,
+ 0x7DD8, 0x7DDD, 0x7DE4, 0x7DDE, 0x7DFB, 0x7DF2, 0x7DE1, 0x7E05,
+ 0x7E0A, 0x7E23, 0x7E21, 0x7E12, 0x7E31, 0x7E1F, 0x7E09, 0x7E0B,
+ 0x7E22, 0x7E46, 0x7E66, 0x7E3B, 0x7E35, 0x7E39, 0x7E43, 0x7E37,
+ 0x7E32, 0x7E3A, 0x7E67, 0x7E5D, 0x7E56, 0x7E5E, 0x7E59, 0x7E5A,
+ 0x7E79, 0x7E6A, 0x7E69, 0x7E7C, 0x7E7B, 0x7E83, 0x7DD5, 0x7E7D,
+ 0x8FAE, 0x7E7F, 0x7E88, 0x7E89, 0x7E8C, 0x7E92, 0x7E90, 0x7E93,
+ 0x7E94, 0x7E96, 0x7E8E, 0x7E9B, 0x7E9C, 0x7F38, 0x7F3A,
+};
+static const unsigned short euc_to_utf8_E6[] = {
+ 0x7F45, 0x7F4C, 0x7F4D, 0x7F4E, 0x7F50, 0x7F51, 0x7F55,
+ 0x7F54, 0x7F58, 0x7F5F, 0x7F60, 0x7F68, 0x7F69, 0x7F67, 0x7F78,
+ 0x7F82, 0x7F86, 0x7F83, 0x7F88, 0x7F87, 0x7F8C, 0x7F94, 0x7F9E,
+ 0x7F9D, 0x7F9A, 0x7FA3, 0x7FAF, 0x7FB2, 0x7FB9, 0x7FAE, 0x7FB6,
+ 0x7FB8, 0x8B71, 0x7FC5, 0x7FC6, 0x7FCA, 0x7FD5, 0x7FD4, 0x7FE1,
+ 0x7FE6, 0x7FE9, 0x7FF3, 0x7FF9, 0x98DC, 0x8006, 0x8004, 0x800B,
+ 0x8012, 0x8018, 0x8019, 0x801C, 0x8021, 0x8028, 0x803F, 0x803B,
+ 0x804A, 0x8046, 0x8052, 0x8058, 0x805A, 0x805F, 0x8062, 0x8068,
+ 0x8073, 0x8072, 0x8070, 0x8076, 0x8079, 0x807D, 0x807F, 0x8084,
+ 0x8086, 0x8085, 0x809B, 0x8093, 0x809A, 0x80AD, 0x5190, 0x80AC,
+ 0x80DB, 0x80E5, 0x80D9, 0x80DD, 0x80C4, 0x80DA, 0x80D6, 0x8109,
+ 0x80EF, 0x80F1, 0x811B, 0x8129, 0x8123, 0x812F, 0x814B,
+};
+static const unsigned short euc_to_utf8_E7[] = {
+ 0x968B, 0x8146, 0x813E, 0x8153, 0x8151, 0x80FC, 0x8171,
+ 0x816E, 0x8165, 0x8166, 0x8174, 0x8183, 0x8188, 0x818A, 0x8180,
+ 0x8182, 0x81A0, 0x8195, 0x81A4, 0x81A3, 0x815F, 0x8193, 0x81A9,
+ 0x81B0, 0x81B5, 0x81BE, 0x81B8, 0x81BD, 0x81C0, 0x81C2, 0x81BA,
+ 0x81C9, 0x81CD, 0x81D1, 0x81D9, 0x81D8, 0x81C8, 0x81DA, 0x81DF,
+ 0x81E0, 0x81E7, 0x81FA, 0x81FB, 0x81FE, 0x8201, 0x8202, 0x8205,
+ 0x8207, 0x820A, 0x820D, 0x8210, 0x8216, 0x8229, 0x822B, 0x8238,
+ 0x8233, 0x8240, 0x8259, 0x8258, 0x825D, 0x825A, 0x825F, 0x8264,
+ 0x8262, 0x8268, 0x826A, 0x826B, 0x822E, 0x8271, 0x8277, 0x8278,
+ 0x827E, 0x828D, 0x8292, 0x82AB, 0x829F, 0x82BB, 0x82AC, 0x82E1,
+ 0x82E3, 0x82DF, 0x82D2, 0x82F4, 0x82F3, 0x82FA, 0x8393, 0x8303,
+ 0x82FB, 0x82F9, 0x82DE, 0x8306, 0x82DC, 0x8309, 0x82D9,
+};
+static const unsigned short euc_to_utf8_E8[] = {
+ 0x8335, 0x8334, 0x8316, 0x8332, 0x8331, 0x8340, 0x8339,
+ 0x8350, 0x8345, 0x832F, 0x832B, 0x8317, 0x8318, 0x8385, 0x839A,
+ 0x83AA, 0x839F, 0x83A2, 0x8396, 0x8323, 0x838E, 0x8387, 0x838A,
+ 0x837C, 0x83B5, 0x8373, 0x8375, 0x83A0, 0x8389, 0x83A8, 0x83F4,
+ 0x8413, 0x83EB, 0x83CE, 0x83FD, 0x8403, 0x83D8, 0x840B, 0x83C1,
+ 0x83F7, 0x8407, 0x83E0, 0x83F2, 0x840D, 0x8422, 0x8420, 0x83BD,
+ 0x8438, 0x8506, 0x83FB, 0x846D, 0x842A, 0x843C, 0x855A, 0x8484,
+ 0x8477, 0x846B, 0x84AD, 0x846E, 0x8482, 0x8469, 0x8446, 0x842C,
+ 0x846F, 0x8479, 0x8435, 0x84CA, 0x8462, 0x84B9, 0x84BF, 0x849F,
+ 0x84D9, 0x84CD, 0x84BB, 0x84DA, 0x84D0, 0x84C1, 0x84C6, 0x84D6,
+ 0x84A1, 0x8521, 0x84FF, 0x84F4, 0x8517, 0x8518, 0x852C, 0x851F,
+ 0x8515, 0x8514, 0x84FC, 0x8540, 0x8563, 0x8558, 0x8548,
+};
+static const unsigned short euc_to_utf8_E9[] = {
+ 0x8541, 0x8602, 0x854B, 0x8555, 0x8580, 0x85A4, 0x8588,
+ 0x8591, 0x858A, 0x85A8, 0x856D, 0x8594, 0x859B, 0x85EA, 0x8587,
+ 0x859C, 0x8577, 0x857E, 0x8590, 0x85C9, 0x85BA, 0x85CF, 0x85B9,
+ 0x85D0, 0x85D5, 0x85DD, 0x85E5, 0x85DC, 0x85F9, 0x860A, 0x8613,
+ 0x860B, 0x85FE, 0x85FA, 0x8606, 0x8622, 0x861A, 0x8630, 0x863F,
+ 0x864D, 0x4E55, 0x8654, 0x865F, 0x8667, 0x8671, 0x8693, 0x86A3,
+ 0x86A9, 0x86AA, 0x868B, 0x868C, 0x86B6, 0x86AF, 0x86C4, 0x86C6,
+ 0x86B0, 0x86C9, 0x8823, 0x86AB, 0x86D4, 0x86DE, 0x86E9, 0x86EC,
+ 0x86DF, 0x86DB, 0x86EF, 0x8712, 0x8706, 0x8708, 0x8700, 0x8703,
+ 0x86FB, 0x8711, 0x8709, 0x870D, 0x86F9, 0x870A, 0x8734, 0x873F,
+ 0x8737, 0x873B, 0x8725, 0x8729, 0x871A, 0x8760, 0x875F, 0x8778,
+ 0x874C, 0x874E, 0x8774, 0x8757, 0x8768, 0x876E, 0x8759,
+};
+static const unsigned short euc_to_utf8_EA[] = {
+ 0x8753, 0x8763, 0x876A, 0x8805, 0x87A2, 0x879F, 0x8782,
+ 0x87AF, 0x87CB, 0x87BD, 0x87C0, 0x87D0, 0x96D6, 0x87AB, 0x87C4,
+ 0x87B3, 0x87C7, 0x87C6, 0x87BB, 0x87EF, 0x87F2, 0x87E0, 0x880F,
+ 0x880D, 0x87FE, 0x87F6, 0x87F7, 0x880E, 0x87D2, 0x8811, 0x8816,
+ 0x8815, 0x8822, 0x8821, 0x8831, 0x8836, 0x8839, 0x8827, 0x883B,
+ 0x8844, 0x8842, 0x8852, 0x8859, 0x885E, 0x8862, 0x886B, 0x8881,
+ 0x887E, 0x889E, 0x8875, 0x887D, 0x88B5, 0x8872, 0x8882, 0x8897,
+ 0x8892, 0x88AE, 0x8899, 0x88A2, 0x888D, 0x88A4, 0x88B0, 0x88BF,
+ 0x88B1, 0x88C3, 0x88C4, 0x88D4, 0x88D8, 0x88D9, 0x88DD, 0x88F9,
+ 0x8902, 0x88FC, 0x88F4, 0x88E8, 0x88F2, 0x8904, 0x890C, 0x890A,
+ 0x8913, 0x8943, 0x891E, 0x8925, 0x892A, 0x892B, 0x8941, 0x8944,
+ 0x893B, 0x8936, 0x8938, 0x894C, 0x891D, 0x8960, 0x895E,
+};
+static const unsigned short euc_to_utf8_EB[] = {
+ 0x8966, 0x8964, 0x896D, 0x896A, 0x896F, 0x8974, 0x8977,
+ 0x897E, 0x8983, 0x8988, 0x898A, 0x8993, 0x8998, 0x89A1, 0x89A9,
+ 0x89A6, 0x89AC, 0x89AF, 0x89B2, 0x89BA, 0x89BD, 0x89BF, 0x89C0,
+ 0x89DA, 0x89DC, 0x89DD, 0x89E7, 0x89F4, 0x89F8, 0x8A03, 0x8A16,
+ 0x8A10, 0x8A0C, 0x8A1B, 0x8A1D, 0x8A25, 0x8A36, 0x8A41, 0x8A5B,
+ 0x8A52, 0x8A46, 0x8A48, 0x8A7C, 0x8A6D, 0x8A6C, 0x8A62, 0x8A85,
+ 0x8A82, 0x8A84, 0x8AA8, 0x8AA1, 0x8A91, 0x8AA5, 0x8AA6, 0x8A9A,
+ 0x8AA3, 0x8AC4, 0x8ACD, 0x8AC2, 0x8ADA, 0x8AEB, 0x8AF3, 0x8AE7,
+ 0x8AE4, 0x8AF1, 0x8B14, 0x8AE0, 0x8AE2, 0x8AF7, 0x8ADE, 0x8ADB,
+ 0x8B0C, 0x8B07, 0x8B1A, 0x8AE1, 0x8B16, 0x8B10, 0x8B17, 0x8B20,
+ 0x8B33, 0x97AB, 0x8B26, 0x8B2B, 0x8B3E, 0x8B28, 0x8B41, 0x8B4C,
+ 0x8B4F, 0x8B4E, 0x8B49, 0x8B56, 0x8B5B, 0x8B5A, 0x8B6B,
+};
+static const unsigned short euc_to_utf8_EC[] = {
+ 0x8B5F, 0x8B6C, 0x8B6F, 0x8B74, 0x8B7D, 0x8B80, 0x8B8C,
+ 0x8B8E, 0x8B92, 0x8B93, 0x8B96, 0x8B99, 0x8B9A, 0x8C3A, 0x8C41,
+ 0x8C3F, 0x8C48, 0x8C4C, 0x8C4E, 0x8C50, 0x8C55, 0x8C62, 0x8C6C,
+ 0x8C78, 0x8C7A, 0x8C82, 0x8C89, 0x8C85, 0x8C8A, 0x8C8D, 0x8C8E,
+ 0x8C94, 0x8C7C, 0x8C98, 0x621D, 0x8CAD, 0x8CAA, 0x8CBD, 0x8CB2,
+ 0x8CB3, 0x8CAE, 0x8CB6, 0x8CC8, 0x8CC1, 0x8CE4, 0x8CE3, 0x8CDA,
+ 0x8CFD, 0x8CFA, 0x8CFB, 0x8D04, 0x8D05, 0x8D0A, 0x8D07, 0x8D0F,
+ 0x8D0D, 0x8D10, 0x9F4E, 0x8D13, 0x8CCD, 0x8D14, 0x8D16, 0x8D67,
+ 0x8D6D, 0x8D71, 0x8D73, 0x8D81, 0x8D99, 0x8DC2, 0x8DBE, 0x8DBA,
+ 0x8DCF, 0x8DDA, 0x8DD6, 0x8DCC, 0x8DDB, 0x8DCB, 0x8DEA, 0x8DEB,
+ 0x8DDF, 0x8DE3, 0x8DFC, 0x8E08, 0x8E09, 0x8DFF, 0x8E1D, 0x8E1E,
+ 0x8E10, 0x8E1F, 0x8E42, 0x8E35, 0x8E30, 0x8E34, 0x8E4A,
+};
+static const unsigned short euc_to_utf8_ED[] = {
+ 0x8E47, 0x8E49, 0x8E4C, 0x8E50, 0x8E48, 0x8E59, 0x8E64,
+ 0x8E60, 0x8E2A, 0x8E63, 0x8E55, 0x8E76, 0x8E72, 0x8E7C, 0x8E81,
+ 0x8E87, 0x8E85, 0x8E84, 0x8E8B, 0x8E8A, 0x8E93, 0x8E91, 0x8E94,
+ 0x8E99, 0x8EAA, 0x8EA1, 0x8EAC, 0x8EB0, 0x8EC6, 0x8EB1, 0x8EBE,
+ 0x8EC5, 0x8EC8, 0x8ECB, 0x8EDB, 0x8EE3, 0x8EFC, 0x8EFB, 0x8EEB,
+ 0x8EFE, 0x8F0A, 0x8F05, 0x8F15, 0x8F12, 0x8F19, 0x8F13, 0x8F1C,
+ 0x8F1F, 0x8F1B, 0x8F0C, 0x8F26, 0x8F33, 0x8F3B, 0x8F39, 0x8F45,
+ 0x8F42, 0x8F3E, 0x8F4C, 0x8F49, 0x8F46, 0x8F4E, 0x8F57, 0x8F5C,
+ 0x8F62, 0x8F63, 0x8F64, 0x8F9C, 0x8F9F, 0x8FA3, 0x8FAD, 0x8FAF,
+ 0x8FB7, 0x8FDA, 0x8FE5, 0x8FE2, 0x8FEA, 0x8FEF, 0x9087, 0x8FF4,
+ 0x9005, 0x8FF9, 0x8FFA, 0x9011, 0x9015, 0x9021, 0x900D, 0x901E,
+ 0x9016, 0x900B, 0x9027, 0x9036, 0x9035, 0x9039, 0x8FF8,
+};
+static const unsigned short euc_to_utf8_EE[] = {
+ 0x904F, 0x9050, 0x9051, 0x9052, 0x900E, 0x9049, 0x903E,
+ 0x9056, 0x9058, 0x905E, 0x9068, 0x906F, 0x9076, 0x96A8, 0x9072,
+ 0x9082, 0x907D, 0x9081, 0x9080, 0x908A, 0x9089, 0x908F, 0x90A8,
+ 0x90AF, 0x90B1, 0x90B5, 0x90E2, 0x90E4, 0x6248, 0x90DB, 0x9102,
+ 0x9112, 0x9119, 0x9132, 0x9130, 0x914A, 0x9156, 0x9158, 0x9163,
+ 0x9165, 0x9169, 0x9173, 0x9172, 0x918B, 0x9189, 0x9182, 0x91A2,
+ 0x91AB, 0x91AF, 0x91AA, 0x91B5, 0x91B4, 0x91BA, 0x91C0, 0x91C1,
+ 0x91C9, 0x91CB, 0x91D0, 0x91D6, 0x91DF, 0x91E1, 0x91DB, 0x91FC,
+ 0x91F5, 0x91F6, 0x921E, 0x91FF, 0x9214, 0x922C, 0x9215, 0x9211,
+ 0x925E, 0x9257, 0x9245, 0x9249, 0x9264, 0x9248, 0x9295, 0x923F,
+ 0x924B, 0x9250, 0x929C, 0x9296, 0x9293, 0x929B, 0x925A, 0x92CF,
+ 0x92B9, 0x92B7, 0x92E9, 0x930F, 0x92FA, 0x9344, 0x932E,
+};
+static const unsigned short euc_to_utf8_EF[] = {
+ 0x9319, 0x9322, 0x931A, 0x9323, 0x933A, 0x9335, 0x933B,
+ 0x935C, 0x9360, 0x937C, 0x936E, 0x9356, 0x93B0, 0x93AC, 0x93AD,
+ 0x9394, 0x93B9, 0x93D6, 0x93D7, 0x93E8, 0x93E5, 0x93D8, 0x93C3,
+ 0x93DD, 0x93D0, 0x93C8, 0x93E4, 0x941A, 0x9414, 0x9413, 0x9403,
+ 0x9407, 0x9410, 0x9436, 0x942B, 0x9435, 0x9421, 0x943A, 0x9441,
+ 0x9452, 0x9444, 0x945B, 0x9460, 0x9462, 0x945E, 0x946A, 0x9229,
+ 0x9470, 0x9475, 0x9477, 0x947D, 0x945A, 0x947C, 0x947E, 0x9481,
+ 0x947F, 0x9582, 0x9587, 0x958A, 0x9594, 0x9596, 0x9598, 0x9599,
+ 0x95A0, 0x95A8, 0x95A7, 0x95AD, 0x95BC, 0x95BB, 0x95B9, 0x95BE,
+ 0x95CA, 0x6FF6, 0x95C3, 0x95CD, 0x95CC, 0x95D5, 0x95D4, 0x95D6,
+ 0x95DC, 0x95E1, 0x95E5, 0x95E2, 0x9621, 0x9628, 0x962E, 0x962F,
+ 0x9642, 0x964C, 0x964F, 0x964B, 0x9677, 0x965C, 0x965E,
+};
+static const unsigned short euc_to_utf8_F0[] = {
+ 0x965D, 0x965F, 0x9666, 0x9672, 0x966C, 0x968D, 0x9698,
+ 0x9695, 0x9697, 0x96AA, 0x96A7, 0x96B1, 0x96B2, 0x96B0, 0x96B4,
+ 0x96B6, 0x96B8, 0x96B9, 0x96CE, 0x96CB, 0x96C9, 0x96CD, 0x894D,
+ 0x96DC, 0x970D, 0x96D5, 0x96F9, 0x9704, 0x9706, 0x9708, 0x9713,
+ 0x970E, 0x9711, 0x970F, 0x9716, 0x9719, 0x9724, 0x972A, 0x9730,
+ 0x9739, 0x973D, 0x973E, 0x9744, 0x9746, 0x9748, 0x9742, 0x9749,
+ 0x975C, 0x9760, 0x9764, 0x9766, 0x9768, 0x52D2, 0x976B, 0x9771,
+ 0x9779, 0x9785, 0x977C, 0x9781, 0x977A, 0x9786, 0x978B, 0x978F,
+ 0x9790, 0x979C, 0x97A8, 0x97A6, 0x97A3, 0x97B3, 0x97B4, 0x97C3,
+ 0x97C6, 0x97C8, 0x97CB, 0x97DC, 0x97ED, 0x9F4F, 0x97F2, 0x7ADF,
+ 0x97F6, 0x97F5, 0x980F, 0x980C, 0x9838, 0x9824, 0x9821, 0x9837,
+ 0x983D, 0x9846, 0x984F, 0x984B, 0x986B, 0x986F, 0x9870,
+};
+static const unsigned short euc_to_utf8_F1[] = {
+ 0x9871, 0x9874, 0x9873, 0x98AA, 0x98AF, 0x98B1, 0x98B6,
+ 0x98C4, 0x98C3, 0x98C6, 0x98E9, 0x98EB, 0x9903, 0x9909, 0x9912,
+ 0x9914, 0x9918, 0x9921, 0x991D, 0x991E, 0x9924, 0x9920, 0x992C,
+ 0x992E, 0x993D, 0x993E, 0x9942, 0x9949, 0x9945, 0x9950, 0x994B,
+ 0x9951, 0x9952, 0x994C, 0x9955, 0x9997, 0x9998, 0x99A5, 0x99AD,
+ 0x99AE, 0x99BC, 0x99DF, 0x99DB, 0x99DD, 0x99D8, 0x99D1, 0x99ED,
+ 0x99EE, 0x99F1, 0x99F2, 0x99FB, 0x99F8, 0x9A01, 0x9A0F, 0x9A05,
+ 0x99E2, 0x9A19, 0x9A2B, 0x9A37, 0x9A45, 0x9A42, 0x9A40, 0x9A43,
+ 0x9A3E, 0x9A55, 0x9A4D, 0x9A5B, 0x9A57, 0x9A5F, 0x9A62, 0x9A65,
+ 0x9A64, 0x9A69, 0x9A6B, 0x9A6A, 0x9AAD, 0x9AB0, 0x9ABC, 0x9AC0,
+ 0x9ACF, 0x9AD1, 0x9AD3, 0x9AD4, 0x9ADE, 0x9ADF, 0x9AE2, 0x9AE3,
+ 0x9AE6, 0x9AEF, 0x9AEB, 0x9AEE, 0x9AF4, 0x9AF1, 0x9AF7,
+};
+static const unsigned short euc_to_utf8_F2[] = {
+ 0x9AFB, 0x9B06, 0x9B18, 0x9B1A, 0x9B1F, 0x9B22, 0x9B23,
+ 0x9B25, 0x9B27, 0x9B28, 0x9B29, 0x9B2A, 0x9B2E, 0x9B2F, 0x9B32,
+ 0x9B44, 0x9B43, 0x9B4F, 0x9B4D, 0x9B4E, 0x9B51, 0x9B58, 0x9B74,
+ 0x9B93, 0x9B83, 0x9B91, 0x9B96, 0x9B97, 0x9B9F, 0x9BA0, 0x9BA8,
+ 0x9BB4, 0x9BC0, 0x9BCA, 0x9BB9, 0x9BC6, 0x9BCF, 0x9BD1, 0x9BD2,
+ 0x9BE3, 0x9BE2, 0x9BE4, 0x9BD4, 0x9BE1, 0x9C3A, 0x9BF2, 0x9BF1,
+ 0x9BF0, 0x9C15, 0x9C14, 0x9C09, 0x9C13, 0x9C0C, 0x9C06, 0x9C08,
+ 0x9C12, 0x9C0A, 0x9C04, 0x9C2E, 0x9C1B, 0x9C25, 0x9C24, 0x9C21,
+ 0x9C30, 0x9C47, 0x9C32, 0x9C46, 0x9C3E, 0x9C5A, 0x9C60, 0x9C67,
+ 0x9C76, 0x9C78, 0x9CE7, 0x9CEC, 0x9CF0, 0x9D09, 0x9D08, 0x9CEB,
+ 0x9D03, 0x9D06, 0x9D2A, 0x9D26, 0x9DAF, 0x9D23, 0x9D1F, 0x9D44,
+ 0x9D15, 0x9D12, 0x9D41, 0x9D3F, 0x9D3E, 0x9D46, 0x9D48,
+};
+static const unsigned short euc_to_utf8_F3[] = {
+ 0x9D5D, 0x9D5E, 0x9D64, 0x9D51, 0x9D50, 0x9D59, 0x9D72,
+ 0x9D89, 0x9D87, 0x9DAB, 0x9D6F, 0x9D7A, 0x9D9A, 0x9DA4, 0x9DA9,
+ 0x9DB2, 0x9DC4, 0x9DC1, 0x9DBB, 0x9DB8, 0x9DBA, 0x9DC6, 0x9DCF,
+ 0x9DC2, 0x9DD9, 0x9DD3, 0x9DF8, 0x9DE6, 0x9DED, 0x9DEF, 0x9DFD,
+ 0x9E1A, 0x9E1B, 0x9E1E, 0x9E75, 0x9E79, 0x9E7D, 0x9E81, 0x9E88,
+ 0x9E8B, 0x9E8C, 0x9E92, 0x9E95, 0x9E91, 0x9E9D, 0x9EA5, 0x9EA9,
+ 0x9EB8, 0x9EAA, 0x9EAD, 0x9761, 0x9ECC, 0x9ECE, 0x9ECF, 0x9ED0,
+ 0x9ED4, 0x9EDC, 0x9EDE, 0x9EDD, 0x9EE0, 0x9EE5, 0x9EE8, 0x9EEF,
+ 0x9EF4, 0x9EF6, 0x9EF7, 0x9EF9, 0x9EFB, 0x9EFC, 0x9EFD, 0x9F07,
+ 0x9F08, 0x76B7, 0x9F15, 0x9F21, 0x9F2C, 0x9F3E, 0x9F4A, 0x9F52,
+ 0x9F54, 0x9F63, 0x9F5F, 0x9F60, 0x9F61, 0x9F66, 0x9F67, 0x9F6C,
+ 0x9F6A, 0x9F77, 0x9F72, 0x9F76, 0x9F95, 0x9F9C, 0x9FA0,
+};
+static const unsigned short euc_to_utf8_F4[] = {
+ 0x582F, 0x69C7, 0x9059, 0x7464, 0x51DC, 0x7199, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_F4_x0213[] = {
+ 0x582F, 0x69C7, 0x9059, 0x7464, 0x51DC, 0x7199, 0x5653,
+ 0x5DE2, 0x5E14, 0x5E18, 0x5E58, 0x5E5E, 0x5EBE, 0xF928, 0x5ECB,
+ 0x5EF9, 0x5F00, 0x5F02, 0x5F07, 0x5F1D, 0x5F23, 0x5F34, 0x5F36,
+ 0x5F3D, 0x5F40, 0x5F45, 0x5F54, 0x5F58, 0x5F64, 0x5F67, 0x5F7D,
+ 0x5F89, 0x5F9C, 0x5FA7, 0x5FAF, 0x5FB5, 0x5FB7, 0x5FC9, 0x5FDE,
+ 0x5FE1, 0x5FE9, 0x600D, 0x6014, 0x6018, 0x6033, 0x6035, 0x6047,
+ 0xFA3D, 0x609D, 0x609E, 0x60CB, 0x60D4, 0x60D5, 0x60DD, 0x60F8,
+ 0x611C, 0x612B, 0x6130, 0x6137, 0xFA3E, 0x618D, 0xFA3F, 0x61BC,
+ 0x61B9, 0xFA40, 0x6222, 0x623E, 0x6243, 0x6256, 0x625A, 0x626F,
+ 0x6285, 0x62C4, 0x62D6, 0x62FC, 0x630A, 0x6318, 0x6339, 0x6343,
+ 0x6365, 0x637C, 0x63E5, 0x63ED, 0x63F5, 0x6410, 0x6414, 0x6422,
+ 0x6479, 0x6451, 0x6460, 0x646D, 0x64CE, 0x64BE, 0x64BF,
+};
+static const unsigned short euc_to_utf8_F5[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFE33, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFE31, 0, 0,
+ 0, 0, 0, 0, 0, 0xFE30, 0, 0,
+ 0, 0, 0xFE35, 0xFE36, 0xFE39, 0xFE3A, 0, 0,
+ 0xFE37, 0xFE38, 0xFE3F, 0xFE40, 0xFE3D, 0xFE3E, 0xFE41, 0xFE42,
+ 0xFE43, 0xFE44, 0xFE3B, 0xFE3C, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_F5_x0213[] = {
+ 0x64C4, 0x64CA, 0x64D0, 0x64F7, 0x64FB, 0x6522, 0x6529,
+ 0xFA41, 0x6567, 0x659D, 0xFA42, 0x6600, 0x6609, 0x6615, 0x661E,
+ 0x663A, 0x6622, 0x6624, 0x662B, 0x6630, 0x6631, 0x6633, 0x66FB,
+ 0x6648, 0x664C, 0xD84C /*0xDDC4*/, 0x6659, 0x665A, 0x6661, 0x6665, 0x6673,
+ 0x6677, 0x6678, 0x668D, 0xFA43, 0x66A0, 0x66B2, 0x66BB, 0x66C6,
+ 0x66C8, 0x3B22, 0x66DB, 0x66E8, 0x66FA, 0x6713, 0xF929, 0x6733,
+ 0x6766, 0x6747, 0x6748, 0x677B, 0x6781, 0x6793, 0x6798, 0x679B,
+ 0x67BB, 0x67F9, 0x67C0, 0x67D7, 0x67FC, 0x6801, 0x6852, 0x681D,
+ 0x682C, 0x6831, 0x685B, 0x6872, 0x6875, 0xFA44, 0x68A3, 0x68A5,
+ 0x68B2, 0x68C8, 0x68D0, 0x68E8, 0x68ED, 0x68F0, 0x68F1, 0x68FC,
+ 0x690A, 0x6949, 0xD84D /*0xDDC4*/, 0x6935, 0x6942, 0x6957, 0x6963, 0x6964,
+ 0x6968, 0x6980, 0xFA14, 0x69A5, 0x69AD, 0x69CF, 0x3BB6,
+};
+static const unsigned short euc_to_utf8_F6_x0213[] = {
+ 0x3BC3, 0x69E2, 0x69E9, 0x69EA, 0x69F5, 0x69F6, 0x6A0F,
+ 0x6A15, 0xD84D /*0xDF3F*/, 0x6A3B, 0x6A3E, 0x6A45, 0x6A50, 0x6A56, 0x6A5B,
+ 0x6A6B, 0x6A73, 0xD84D /*0xDF63*/, 0x6A89, 0x6A94, 0x6A9D, 0x6A9E, 0x6AA5,
+ 0x6AE4, 0x6AE7, 0x3C0F, 0xF91D, 0x6B1B, 0x6B1E, 0x6B2C, 0x6B35,
+ 0x6B46, 0x6B56, 0x6B60, 0x6B65, 0x6B67, 0x6B77, 0x6B82, 0x6BA9,
+ 0x6BAD, 0xF970, 0x6BCF, 0x6BD6, 0x6BD7, 0x6BFF, 0x6C05, 0x6C10,
+ 0x6C33, 0x6C59, 0x6C5C, 0x6CAA, 0x6C74, 0x6C76, 0x6C85, 0x6C86,
+ 0x6C98, 0x6C9C, 0x6CFB, 0x6CC6, 0x6CD4, 0x6CE0, 0x6CEB, 0x6CEE,
+ 0xD84F /*0xDCFE*/, 0x6D04, 0x6D0E, 0x6D2E, 0x6D31, 0x6D39, 0x6D3F, 0x6D58,
+ 0x6D65, 0xFA45, 0x6D82, 0x6D87, 0x6D89, 0x6D94, 0x6DAA, 0x6DAC,
+ 0x6DBF, 0x6DC4, 0x6DD6, 0x6DDA, 0x6DDB, 0x6DDD, 0x6DFC, 0xFA46,
+ 0x6E34, 0x6E44, 0x6E5C, 0x6E5E, 0x6EAB, 0x6EB1, 0x6EC1,
+};
+static const unsigned short euc_to_utf8_F7_x0213[] = {
+ 0x6EC7, 0x6ECE, 0x6F10, 0x6F1A, 0xFA47, 0x6F2A, 0x6F2F,
+ 0x6F33, 0x6F51, 0x6F59, 0x6F5E, 0x6F61, 0x6F62, 0x6F7E, 0x6F88,
+ 0x6F8C, 0x6F8D, 0x6F94, 0x6FA0, 0x6FA7, 0x6FB6, 0x6FBC, 0x6FC7,
+ 0x6FCA, 0x6FF9, 0x6FF0, 0x6FF5, 0x7005, 0x7006, 0x7028, 0x704A,
+ 0x705D, 0x705E, 0x704E, 0x7064, 0x7075, 0x7085, 0x70A4, 0x70AB,
+ 0x70B7, 0x70D4, 0x70D8, 0x70E4, 0x710F, 0x712B, 0x711E, 0x7120,
+ 0x712E, 0x7130, 0x7146, 0x7147, 0x7151, 0xFA48, 0x7152, 0x715C,
+ 0x7160, 0x7168, 0xFA15, 0x7185, 0x7187, 0x7192, 0x71C1, 0x71BA,
+ 0x71C4, 0x71FE, 0x7200, 0x7215, 0x7255, 0x7256, 0x3E3F, 0x728D,
+ 0x729B, 0x72BE, 0x72C0, 0x72FB, 0xD851 /*0xDFF1*/, 0x7327, 0x7328, 0xFA16,
+ 0x7350, 0x7366, 0x737C, 0x7395, 0x739F, 0x73A0, 0x73A2, 0x73A6,
+ 0x73AB, 0x73C9, 0x73CF, 0x73D6, 0x73D9, 0x73E3, 0x73E9,
+};
+static const unsigned short euc_to_utf8_F8_x0213[] = {
+ 0x7407, 0x740A, 0x741A, 0x741B, 0xFA4A, 0x7426, 0x7428,
+ 0x742A, 0x742B, 0x742C, 0x742E, 0x742F, 0x7430, 0x7444, 0x7446,
+ 0x7447, 0x744B, 0x7457, 0x7462, 0x746B, 0x746D, 0x7486, 0x7487,
+ 0x7489, 0x7498, 0x749C, 0x749F, 0x74A3, 0x7490, 0x74A6, 0x74A8,
+ 0x74A9, 0x74B5, 0x74BF, 0x74C8, 0x74C9, 0x74DA, 0x74FF, 0x7501,
+ 0x7517, 0x752F, 0x756F, 0x7579, 0x7592, 0x3F72, 0x75CE, 0x75E4,
+ 0x7600, 0x7602, 0x7608, 0x7615, 0x7616, 0x7619, 0x761E, 0x762D,
+ 0x7635, 0x7643, 0x764B, 0x7664, 0x7665, 0x766D, 0x766F, 0x7671,
+ 0x7681, 0x769B, 0x769D, 0x769E, 0x76A6, 0x76AA, 0x76B6, 0x76C5,
+ 0x76CC, 0x76CE, 0x76D4, 0x76E6, 0x76F1, 0x76FC, 0x770A, 0x7719,
+ 0x7734, 0x7736, 0x7746, 0x774D, 0x774E, 0x775C, 0x775F, 0x7762,
+ 0x777A, 0x7780, 0x7794, 0x77AA, 0x77E0, 0x782D, 0xD855 /*0xDC8E*/,
+};
+static const unsigned short euc_to_utf8_F9[] = {
+ 0x7E8A, 0x891C, 0x9348, 0x9288, 0x84DC, 0x4FC9, 0x70BB,
+ 0x6631, 0x68C8, 0x92F9, 0x66FB, 0x5F45, 0x4E28, 0x4EE1, 0x4EFC,
+ 0x4F00, 0x4F03, 0x4F39, 0x4F56, 0x4F92, 0x4F8A, 0x4F9A, 0x4F94,
+ 0x4FCD, 0x5040, 0x5022, 0x4FFF, 0x501E, 0x5046, 0x5070, 0x5042,
+ 0x5094, 0x50F4, 0x50D8, 0x514A, 0x5164, 0x519D, 0x51BE, 0x51EC,
+ 0x5215, 0x529C, 0x52A6, 0x52C0, 0x52DB, 0x5300, 0x5307, 0x5324,
+ 0x5372, 0x5393, 0x53B2, 0x53DD, 0xFA0E, 0x549C, 0x548A, 0x54A9,
+ 0x54FF, 0x5586, 0x5759, 0x5765, 0x57AC, 0x57C8, 0x57C7, 0xFA0F,
+ 0xFA10, 0x589E, 0x58B2, 0x590B, 0x5953, 0x595B, 0x595D, 0x5963,
+ 0x59A4, 0x59BA, 0x5B56, 0x5BC0, 0x752F, 0x5BD8, 0x5BEC, 0x5C1E,
+ 0x5CA6, 0x5CBA, 0x5CF5, 0x5D27, 0x5D53, 0xFA11, 0x5D42, 0x5D6D,
+ 0x5DB8, 0x5DB9, 0x5DD0, 0x5F21, 0x5F34, 0x5F67, 0x5FB7,
+};
+static const unsigned short euc_to_utf8_F9_x0213[] = {
+ 0x7843, 0x784E, 0x784F, 0x7851, 0x7868, 0x786E, 0xFA4B,
+ 0x78B0, 0xD855 /*0xDD0E*/, 0x78AD, 0x78E4, 0x78F2, 0x7900, 0x78F7, 0x791C,
+ 0x792E, 0x7931, 0x7934, 0xFA4C, 0xFA4D, 0x7945, 0x7946, 0xFA4E,
+ 0xFA4F, 0xFA50, 0x795C, 0xFA51, 0xFA19, 0xFA1A, 0x7979, 0xFA52,
+ 0xFA53, 0xFA1B, 0x7998, 0x79B1, 0x79B8, 0x79C8, 0x79CA, 0xD855 /*0xDF71*/,
+ 0x79D4, 0x79DE, 0x79EB, 0x79ED, 0x7A03, 0xFA54, 0x7A39, 0x7A5D,
+ 0x7A6D, 0xFA55, 0x7A85, 0x7AA0, 0xD856 /*0xDDC4*/, 0x7AB3, 0x7ABB, 0x7ACE,
+ 0x7AEB, 0x7AFD, 0x7B12, 0x7B2D, 0x7B3B, 0x7B47, 0x7B4E, 0x7B60,
+ 0x7B6D, 0x7B6F, 0x7B72, 0x7B9E, 0xFA56, 0x7BD7, 0x7BD9, 0x7C01,
+ 0x7C31, 0x7C1E, 0x7C20, 0x7C33, 0x7C36, 0x4264, 0xD857 /*0xDDA1*/, 0x7C59,
+ 0x7C6D, 0x7C79, 0x7C8F, 0x7C94, 0x7CA0, 0x7CBC, 0x7CD5, 0x7CD9,
+ 0x7CDD, 0x7D07, 0x7D08, 0x7D13, 0x7D1D, 0x7D23, 0x7D31,
+};
+static const unsigned short euc_to_utf8_FA[] = {
+ 0x5FDE, 0x605D, 0x6085, 0x608A, 0x60DE, 0x60D5, 0x6120,
+ 0x60F2, 0x6111, 0x6137, 0x6130, 0x6198, 0x6213, 0x62A6, 0x63F5,
+ 0x6460, 0x649D, 0x64CE, 0x654E, 0x6600, 0x6615, 0x663B, 0x6609,
+ 0x662E, 0x661E, 0x6624, 0x6665, 0x6657, 0x6659, 0xFA12, 0x6673,
+ 0x6699, 0x66A0, 0x66B2, 0x66BF, 0x66FA, 0x670E, 0xF929, 0x6766,
+ 0x67BB, 0x6852, 0x67C0, 0x6801, 0x6844, 0x68CF, 0xFA13, 0x6968,
+ 0xFA14, 0x6998, 0x69E2, 0x6A30, 0x6A6B, 0x6A46, 0x6A73, 0x6A7E,
+ 0x6AE2, 0x6AE4, 0x6BD6, 0x6C3F, 0x6C5C, 0x6C86, 0x6C6F, 0x6CDA,
+ 0x6D04, 0x6D87, 0x6D6F, 0x6D96, 0x6DAC, 0x6DCF, 0x6DF8, 0x6DF2,
+ 0x6DFC, 0x6E39, 0x6E5C, 0x6E27, 0x6E3C, 0x6EBF, 0x6F88, 0x6FB5,
+ 0x6FF5, 0x7005, 0x7007, 0x7028, 0x7085, 0x70AB, 0x710F, 0x7104,
+ 0x715C, 0x7146, 0x7147, 0xFA15, 0x71C1, 0x71FE, 0x72B1,
+};
+static const unsigned short euc_to_utf8_FA_x0213[] = {
+ 0x7D41, 0x7D48, 0x7D53, 0x7D5C, 0x7D7A, 0x7D83, 0x7D8B,
+ 0x7DA0, 0x7DA6, 0x7DC2, 0x7DCC, 0x7DD6, 0x7DE3, 0xFA57, 0x7E28,
+ 0x7E08, 0x7E11, 0x7E15, 0xFA59, 0x7E47, 0x7E52, 0x7E61, 0x7E8A,
+ 0x7E8D, 0x7F47, 0xFA5A, 0x7F91, 0x7F97, 0x7FBF, 0x7FCE, 0x7FDB,
+ 0x7FDF, 0x7FEC, 0x7FEE, 0x7FFA, 0xFA5B, 0x8014, 0x8026, 0x8035,
+ 0x8037, 0x803C, 0x80CA, 0x80D7, 0x80E0, 0x80F3, 0x8118, 0x814A,
+ 0x8160, 0x8167, 0x8168, 0x816D, 0x81BB, 0x81CA, 0x81CF, 0x81D7,
+ 0xFA5C, 0x4453, 0x445B, 0x8260, 0x8274, 0xD85A /*0xDEFF*/, 0x828E, 0x82A1,
+ 0x82A3, 0x82A4, 0x82A9, 0x82AE, 0x82B7, 0x82BE, 0x82BF, 0x82C6,
+ 0x82D5, 0x82FD, 0x82FE, 0x8300, 0x8301, 0x8362, 0x8322, 0x832D,
+ 0x833A, 0x8343, 0x8347, 0x8351, 0x8355, 0x837D, 0x8386, 0x8392,
+ 0x8398, 0x83A7, 0x83A9, 0x83BF, 0x83C0, 0x83C7, 0x83CF,
+};
+static const unsigned short euc_to_utf8_FB[] = {
+ 0x72BE, 0x7324, 0xFA16, 0x7377, 0x73BD, 0x73C9, 0x73D6,
+ 0x73E3, 0x73D2, 0x7407, 0x73F5, 0x7426, 0x742A, 0x7429, 0x742E,
+ 0x7462, 0x7489, 0x749F, 0x7501, 0x756F, 0x7682, 0x769C, 0x769E,
+ 0x769B, 0x76A6, 0xFA17, 0x7746, 0x52AF, 0x7821, 0x784E, 0x7864,
+ 0x787A, 0x7930, 0xFA18, 0xFA19, 0xFA1A, 0x7994, 0xFA1B, 0x799B,
+ 0x7AD1, 0x7AE7, 0xFA1C, 0x7AEB, 0x7B9E, 0xFA1D, 0x7D48, 0x7D5C,
+ 0x7DB7, 0x7DA0, 0x7DD6, 0x7E52, 0x7F47, 0x7FA1, 0xFA1E, 0x8301,
+ 0x8362, 0x837F, 0x83C7, 0x83F6, 0x8448, 0x84B4, 0x8553, 0x8559,
+ 0x856B, 0xFA1F, 0x85B0, 0xFA20, 0xFA21, 0x8807, 0x88F5, 0x8A12,
+ 0x8A37, 0x8A79, 0x8AA7, 0x8ABE, 0x8ADF, 0xFA22, 0x8AF6, 0x8B53,
+ 0x8B7F, 0x8CF0, 0x8CF4, 0x8D12, 0x8D76, 0xFA23, 0x8ECF, 0xFA24,
+ 0xFA25, 0x9067, 0x90DE, 0xFA26, 0x9115, 0x9127, 0x91DA,
+};
+static const unsigned short euc_to_utf8_FB_x0213[] = {
+ 0x83D1, 0x83E1, 0x83EA, 0x8401, 0x8406, 0x840A, 0xFA5F,
+ 0x8448, 0x845F, 0x8470, 0x8473, 0x8485, 0x849E, 0x84AF, 0x84B4,
+ 0x84BA, 0x84C0, 0x84C2, 0xD85B /*0xDE40*/, 0x8532, 0x851E, 0x8523, 0x852F,
+ 0x8559, 0x8564, 0xFA1F, 0x85AD, 0x857A, 0x858C, 0x858F, 0x85A2,
+ 0x85B0, 0x85CB, 0x85CE, 0x85ED, 0x8612, 0x85FF, 0x8604, 0x8605,
+ 0x8610, 0xD85C /*0xDCF4*/, 0x8618, 0x8629, 0x8638, 0x8657, 0x865B, 0xF936,
+ 0x8662, 0x459D, 0x866C, 0x8675, 0x8698, 0x86B8, 0x86FA, 0x86FC,
+ 0x86FD, 0x870B, 0x8771, 0x8787, 0x8788, 0x87AC, 0x87AD, 0x87B5,
+ 0x45EA, 0x87D6, 0x87EC, 0x8806, 0x880A, 0x8810, 0x8814, 0x881F,
+ 0x8898, 0x88AA, 0x88CA, 0x88CE, 0xD85D /*0xDE84*/, 0x88F5, 0x891C, 0xFA60,
+ 0x8918, 0x8919, 0x891A, 0x8927, 0x8930, 0x8932, 0x8939, 0x8940,
+ 0x8994, 0xFA61, 0x89D4, 0x89E5, 0x89F6, 0x8A12, 0x8A15,
+};
+static const unsigned short euc_to_utf8_FC[] = {
+ 0x91D7, 0x91DE, 0x91ED, 0x91EE, 0x91E4, 0x91E5, 0x9206,
+ 0x9210, 0x920A, 0x923A, 0x9240, 0x923C, 0x924E, 0x9259, 0x9251,
+ 0x9239, 0x9267, 0x92A7, 0x9277, 0x9278, 0x92E7, 0x92D7, 0x92D9,
+ 0x92D0, 0xFA27, 0x92D5, 0x92E0, 0x92D3, 0x9325, 0x9321, 0x92FB,
+ 0xFA28, 0x931E, 0x92FF, 0x931D, 0x9302, 0x9370, 0x9357, 0x93A4,
+ 0x93C6, 0x93DE, 0x93F8, 0x9431, 0x9445, 0x9448, 0x9592, 0xF9DC,
+ 0xFA29, 0x969D, 0x96AF, 0x9733, 0x973B, 0x9743, 0x974D, 0x974F,
+ 0x9751, 0x9755, 0x9857, 0x9865, 0xFA2A, 0xFA2B, 0x9927, 0xFA2C,
+ 0x999E, 0x9A4E, 0x9AD9, 0x9ADC, 0x9B75, 0x9B72, 0x9B8F, 0x9BB1,
+ 0x9BBB, 0x9C00, 0x9D70, 0x9D6B, 0xFA2D, 0x9E19, 0x9ED1, 0,
+ 0, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176,
+ 0x2177, 0x2178, 0x2179, 0xFFE2, 0x00A6, 0xFF07, 0xFF02,
+};
+
+/* Microsoft UCS Mapping Compatible */
+static const unsigned short euc_to_utf8_FC_ms[] = {
+ 0x91D7, 0x91DE, 0x91ED, 0x91EE, 0x91E4, 0x91E5, 0x9206,
+ 0x9210, 0x920A, 0x923A, 0x9240, 0x923C, 0x924E, 0x9259, 0x9251,
+ 0x9239, 0x9267, 0x92A7, 0x9277, 0x9278, 0x92E7, 0x92D7, 0x92D9,
+ 0x92D0, 0xFA27, 0x92D5, 0x92E0, 0x92D3, 0x9325, 0x9321, 0x92FB,
+ 0xFA28, 0x931E, 0x92FF, 0x931D, 0x9302, 0x9370, 0x9357, 0x93A4,
+ 0x93C6, 0x93DE, 0x93F8, 0x9431, 0x9445, 0x9448, 0x9592, 0xF9DC,
+ 0xFA29, 0x969D, 0x96AF, 0x9733, 0x973B, 0x9743, 0x974D, 0x974F,
+ 0x9751, 0x9755, 0x9857, 0x9865, 0xFA2A, 0xFA2B, 0x9927, 0xFA2C,
+ 0x999E, 0x9A4E, 0x9AD9, 0x9ADC, 0x9B75, 0x9B72, 0x9B8F, 0x9BB1,
+ 0x9BBB, 0x9C00, 0x9D70, 0x9D6B, 0xFA2D, 0x9E19, 0x9ED1, 0,
+ 0, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176,
+ 0x2177, 0x2178, 0x2179, 0xFFE2, 0xFFE4, 0xFF07, 0xFF02,
+};
+static const unsigned short euc_to_utf8_FC_x0213[] = {
+ 0x8A22, 0x8A37, 0x8A47, 0x8A4E, 0x8A5D, 0x8A61, 0x8A75,
+ 0x8A79, 0x8AA7, 0x8AD0, 0x8ADF, 0x8AF4, 0x8AF6, 0xFA22, 0xFA62,
+ 0xFA63, 0x8B46, 0x8B54, 0x8B59, 0x8B69, 0x8B9D, 0x8C49, 0x8C68,
+ 0xFA64, 0x8CE1, 0x8CF4, 0x8CF8, 0x8CFE, 0xFA65, 0x8D12, 0x8D1B,
+ 0x8DAF, 0x8DCE, 0x8DD1, 0x8DD7, 0x8E20, 0x8E23, 0x8E3D, 0x8E70,
+ 0x8E7B, 0xD860 /*0xDE77*/, 0x8EC0, 0x4844, 0x8EFA, 0x8F1E, 0x8F2D, 0x8F36,
+ 0x8F54, 0xD860 /*0xDFCD*/, 0x8FA6, 0x8FB5, 0x8FE4, 0x8FE8, 0x8FEE, 0x9008,
+ 0x902D, 0xFA67, 0x9088, 0x9095, 0x9097, 0x9099, 0x909B, 0x90A2,
+ 0x90B3, 0x90BE, 0x90C4, 0x90C5, 0x90C7, 0x90D7, 0x90DD, 0x90DE,
+ 0x90EF, 0x90F4, 0xFA26, 0x9114, 0x9115, 0x9116, 0x9122, 0x9123,
+ 0x9127, 0x912F, 0x9131, 0x9134, 0x913D, 0x9148, 0x915B, 0x9183,
+ 0x919E, 0x91AC, 0x91B1, 0x91BC, 0x91D7, 0x91FB, 0x91E4,
+};
+static const unsigned short euc_to_utf8_FD_x0213[] = {
+ 0x91E5, 0x91ED, 0x91F1, 0x9207, 0x9210, 0x9238, 0x9239,
+ 0x923A, 0x923C, 0x9240, 0x9243, 0x924F, 0x9278, 0x9288, 0x92C2,
+ 0x92CB, 0x92CC, 0x92D3, 0x92E0, 0x92FF, 0x9304, 0x931F, 0x9321,
+ 0x9325, 0x9348, 0x9349, 0x934A, 0x9364, 0x9365, 0x936A, 0x9370,
+ 0x939B, 0x93A3, 0x93BA, 0x93C6, 0x93DE, 0x93DF, 0x9404, 0x93FD,
+ 0x9433, 0x944A, 0x9463, 0x946B, 0x9471, 0x9472, 0x958E, 0x959F,
+ 0x95A6, 0x95A9, 0x95AC, 0x95B6, 0x95BD, 0x95CB, 0x95D0, 0x95D3,
+ 0x49B0, 0x95DA, 0x95DE, 0x9658, 0x9684, 0xF9DC, 0x969D, 0x96A4,
+ 0x96A5, 0x96D2, 0x96DE, 0xFA68, 0x96E9, 0x96EF, 0x9733, 0x973B,
+ 0x974D, 0x974E, 0x974F, 0x975A, 0x976E, 0x9773, 0x9795, 0x97AE,
+ 0x97BA, 0x97C1, 0x97C9, 0x97DE, 0x97DB, 0x97F4, 0xFA69, 0x980A,
+ 0x981E, 0x982B, 0x9830, 0xFA6A, 0x9852, 0x9853, 0x9856,
+};
+static const unsigned short euc_to_utf8_FE_x0213[] = {
+ 0x9857, 0x9859, 0x985A, 0xF9D0, 0x9865, 0x986C, 0x98BA,
+ 0x98C8, 0x98E7, 0x9958, 0x999E, 0x9A02, 0x9A03, 0x9A24, 0x9A2D,
+ 0x9A2E, 0x9A38, 0x9A4A, 0x9A4E, 0x9A52, 0x9AB6, 0x9AC1, 0x9AC3,
+ 0x9ACE, 0x9AD6, 0x9AF9, 0x9B02, 0x9B08, 0x9B20, 0x4C17, 0x9B2D,
+ 0x9B5E, 0x9B79, 0x9B66, 0x9B72, 0x9B75, 0x9B84, 0x9B8A, 0x9B8F,
+ 0x9B9E, 0x9BA7, 0x9BC1, 0x9BCE, 0x9BE5, 0x9BF8, 0x9BFD, 0x9C00,
+ 0x9C23, 0x9C41, 0x9C4F, 0x9C50, 0x9C53, 0x9C63, 0x9C65, 0x9C77,
+ 0x9D1D, 0x9D1E, 0x9D43, 0x9D47, 0x9D52, 0x9D63, 0x9D70, 0x9D7C,
+ 0x9D8A, 0x9D96, 0x9DC0, 0x9DAC, 0x9DBC, 0x9DD7, 0xD868 /*0xDD90*/, 0x9DE7,
+ 0x9E07, 0x9E15, 0x9E7C, 0x9E9E, 0x9EA4, 0x9EAC, 0x9EAF, 0x9EB4,
+ 0x9EB5, 0x9EC3, 0x9ED1, 0x9F10, 0x9F39, 0x9F57, 0x9F90, 0x9F94,
+ 0x9F97, 0x9FA2, 0x59F8, 0x5C5B, 0x5E77, 0x7626, 0x7E6B,
+};
+
+static const unsigned short euc_to_utf8_8FA1_x0213[] = {
+ 0xD840 /*0xDC89*/, 0x4E02, 0x4E0F, 0x4E12, 0x4E29, 0x4E2B, 0x4E2E,
+ 0x4E40, 0x4E47, 0x4E48, 0xD840 /*0xDCA2*/, 0x4E51, 0x3406, 0xD840 /*0xDCA4*/, 0x4E5A,
+ 0x4E69, 0x4E9D, 0x342C, 0x342E, 0x4EB9, 0x4EBB, 0xD840 /*0xDDA2*/, 0x4EBC,
+ 0x4EC3, 0x4EC8, 0x4ED0, 0x4EEB, 0x4EDA, 0x4EF1, 0x4EF5, 0x4F00,
+ 0x4F16, 0x4F64, 0x4F37, 0x4F3E, 0x4F54, 0x4F58, 0xD840 /*0xDE13*/, 0x4F77,
+ 0x4F78, 0x4F7A, 0x4F7D, 0x4F82, 0x4F85, 0x4F92, 0x4F9A, 0x4FE6,
+ 0x4FB2, 0x4FBE, 0x4FC5, 0x4FCB, 0x4FCF, 0x4FD2, 0x346A, 0x4FF2,
+ 0x5000, 0x5010, 0x5013, 0x501C, 0x501E, 0x5022, 0x3468, 0x5042,
+ 0x5046, 0x504E, 0x5053, 0x5057, 0x5063, 0x5066, 0x506A, 0x5070,
+ 0x50A3, 0x5088, 0x5092, 0x5093, 0x5095, 0x5096, 0x509C, 0x50AA,
+ 0xD840 /*0xDF2B*/, 0x50B1, 0x50BA, 0x50BB, 0x50C4, 0x50C7, 0x50F3, 0xD840 /*0xDF81*/,
+ 0x50CE, 0xD840 /*0xDF71*/, 0x50D4, 0x50D9, 0x50E1, 0x50E9, 0x3492,
+};
+static const unsigned short euc_to_utf8_8FA3_x0213[] = {
+ 0x5108, 0xD840 /*0xDFF9*/, 0x5117, 0x511B, 0xD841 /*0xDC4A*/, 0x5160, 0xD841 /*0xDD09*/,
+ 0x5173, 0x5183, 0x518B, 0x34BC, 0x5198, 0x51A3, 0x51AD, 0x34C7,
+ 0x51BC, 0xD841 /*0xDDD6*/, 0xD841 /*0xDE28*/, 0x51F3, 0x51F4, 0x5202, 0x5212, 0x5216,
+ 0xD841 /*0xDF4F*/, 0x5255, 0x525C, 0x526C, 0x5277, 0x5284, 0x5282, 0xD842 /*0xDC07*/,
+ 0x5298, 0xD842 /*0xDC3A*/, 0x52A4, 0x52A6, 0x52AF, 0x52BA, 0x52BB, 0x52CA,
+ 0x351F, 0x52D1, 0xD842 /*0xDCB9*/, 0x52F7, 0x530A, 0x530B, 0x5324, 0x5335,
+ 0x533E, 0x5342, 0xD842 /*0xDD7C*/, 0xD842 /*0xDD9D*/, 0x5367, 0x536C, 0x537A, 0x53A4,
+ 0x53B4, 0xD842 /*0xDED3*/, 0x53B7, 0x53C0, 0xD842 /*0xDF1D*/, 0x355D, 0x355E, 0x53D5,
+ 0x53DA, 0x3563, 0x53F4, 0x53F5, 0x5455, 0x5424, 0x5428, 0x356E,
+ 0x5443, 0x5462, 0x5466, 0x546C, 0x548A, 0x548D, 0x5495, 0x54A0,
+ 0x54A6, 0x54AD, 0x54AE, 0x54B7, 0x54BA, 0x54BF, 0x54C3, 0xD843 /*0xDD45*/,
+ 0x54EC, 0x54EF, 0x54F1, 0x54F3, 0x5500, 0x5501, 0x5509,
+};
+static const unsigned short euc_to_utf8_8FA4_x0213[] = {
+ 0x553C, 0x5541, 0x35A6, 0x5547, 0x554A, 0x35A8, 0x5560,
+ 0x5561, 0x5564, 0xD843 /*0xDDE1*/, 0x557D, 0x5582, 0x5588, 0x5591, 0x35C5,
+ 0x55D2, 0xD843 /*0xDE95*/, 0xD843 /*0xDE6D*/, 0x55BF, 0x55C9, 0x55CC, 0x55D1, 0x55DD,
+ 0x35DA, 0x55E2, 0xD843 /*0xDE64*/, 0x55E9, 0x5628, 0xD843 /*0xDF5F*/, 0x5607, 0x5610,
+ 0x5630, 0x5637, 0x35F4, 0x563D, 0x563F, 0x5640, 0x5647, 0x565E,
+ 0x5660, 0x566D, 0x3605, 0x5688, 0x568C, 0x5695, 0x569A, 0x569D,
+ 0x56A8, 0x56AD, 0x56B2, 0x56C5, 0x56CD, 0x56DF, 0x56E8, 0x56F6,
+ 0x56F7, 0xD844 /*0xDE01*/, 0x5715, 0x5723, 0xD844 /*0xDE55*/, 0x5729, 0xD844 /*0xDE7B*/, 0x5745,
+ 0x5746, 0x574C, 0x574D, 0xD844 /*0xDE74*/, 0x5768, 0x576F, 0x5773, 0x5774,
+ 0x5775, 0x577B, 0xD844 /*0xDEE4*/, 0xD844 /*0xDED7*/, 0x57AC, 0x579A, 0x579D, 0x579E,
+ 0x57A8, 0x57D7, 0xD844 /*0xDEFD*/, 0x57CC, 0xD844 /*0xDF36*/, 0xD844 /*0xDF44*/, 0x57DE, 0x57E6,
+ 0x57F0, 0x364A, 0x57F8, 0x57FB, 0x57FD, 0x5804, 0x581E,
+};
+static const unsigned short euc_to_utf8_8FA5_x0213[] = {
+ 0x5820, 0x5827, 0x5832, 0x5839, 0xD844 /*0xDFC4*/, 0x5849, 0x584C,
+ 0x5867, 0x588A, 0x588B, 0x588D, 0x588F, 0x5890, 0x5894, 0x589D,
+ 0x58AA, 0x58B1, 0xD845 /*0xDC6D*/, 0x58C3, 0x58CD, 0x58E2, 0x58F3, 0x58F4,
+ 0x5905, 0x5906, 0x590B, 0x590D, 0x5914, 0x5924, 0xD845 /*0xDDD7*/, 0x3691,
+ 0x593D, 0x3699, 0x5946, 0x3696, 0xD85B /*0xDC29*/, 0x595B, 0x595F, 0xD845 /*0xDE47*/,
+ 0x5975, 0x5976, 0x597C, 0x599F, 0x59AE, 0x59BC, 0x59C8, 0x59CD,
+ 0x59DE, 0x59E3, 0x59E4, 0x59E7, 0x59EE, 0xD845 /*0xDF06*/, 0xD845 /*0xDF42*/, 0x36CF,
+ 0x5A0C, 0x5A0D, 0x5A17, 0x5A27, 0x5A2D, 0x5A55, 0x5A65, 0x5A7A,
+ 0x5A8B, 0x5A9C, 0x5A9F, 0x5AA0, 0x5AA2, 0x5AB1, 0x5AB3, 0x5AB5,
+ 0x5ABA, 0x5ABF, 0x5ADA, 0x5ADC, 0x5AE0, 0x5AE5, 0x5AF0, 0x5AEE,
+ 0x5AF5, 0x5B00, 0x5B08, 0x5B17, 0x5B34, 0x5B2D, 0x5B4C, 0x5B52,
+ 0x5B68, 0x5B6F, 0x5B7C, 0x5B7F, 0x5B81, 0x5B84, 0xD846 /*0xDDC3*/,
+};
+static const unsigned short euc_to_utf8_8FA8_x0213[] = {
+ 0x5B96, 0x5BAC, 0x3761, 0x5BC0, 0x3762, 0x5BCE, 0x5BD6,
+ 0x376C, 0x376B, 0x5BF1, 0x5BFD, 0x3775, 0x5C03, 0x5C29, 0x5C30,
+ 0xD847 /*0xDC56*/, 0x5C5F, 0x5C63, 0x5C67, 0x5C68, 0x5C69, 0x5C70, 0xD847 /*0xDD2D*/,
+ 0xD847 /*0xDD45*/, 0x5C7C, 0xD847 /*0xDD78*/, 0xD847 /*0xDD62*/, 0x5C88, 0x5C8A, 0x37C1, 0xD847 /*0xDDA1*/,
+ 0xD847 /*0xDD9C*/, 0x5CA0, 0x5CA2, 0x5CA6, 0x5CA7, 0xD847 /*0xDD92*/, 0x5CAD, 0x5CB5,
+ 0xD847 /*0xDDB7*/, 0x5CC9, 0xD847 /*0xDDE0*/, 0xD847 /*0xDE33*/, 0x5D06, 0x5D10, 0x5D2B, 0x5D1D,
+ 0x5D20, 0x5D24, 0x5D26, 0x5D31, 0x5D39, 0x5D42, 0x37E8, 0x5D61,
+ 0x5D6A, 0x37F4, 0x5D70, 0xD847 /*0xDF1E*/, 0x37FD, 0x5D88, 0x3800, 0x5D92,
+ 0x5D94, 0x5D97, 0x5D99, 0x5DB0, 0x5DB2, 0x5DB4, 0xD847 /*0xDF76*/, 0x5DB9,
+ 0x5DD1, 0x5DD7, 0x5DD8, 0x5DE0, 0xD847 /*0xDFFA*/, 0x5DE4, 0x5DE9, 0x382F,
+ 0x5E00, 0x3836, 0x5E12, 0x5E15, 0x3840, 0x5E1F, 0x5E2E, 0x5E3E,
+ 0x5E49, 0x385C, 0x5E56, 0x3861, 0x5E6B, 0x5E6C, 0x5E6D,
+};
+static const unsigned short euc_to_utf8_8FAC_x0213[] = {
+ 0x5E6E, 0xD848 /*0xDD7B*/, 0x5EA5, 0x5EAA, 0x5EAC, 0x5EB9, 0x5EBF,
+ 0x5EC6, 0x5ED2, 0x5ED9, 0xD848 /*0xDF1E*/, 0x5EFD, 0x5F08, 0x5F0E, 0x5F1C,
+ 0xD848 /*0xDFAD*/, 0x5F1E, 0x5F47, 0x5F63, 0x5F72, 0x5F7E, 0x5F8F, 0x5FA2,
+ 0x5FA4, 0x5FB8, 0x5FC4, 0x38FA, 0x5FC7, 0x5FCB, 0x5FD2, 0x5FD3,
+ 0x5FD4, 0x5FE2, 0x5FEE, 0x5FEF, 0x5FF3, 0x5FFC, 0x3917, 0x6017,
+ 0x6022, 0x6024, 0x391A, 0x604C, 0x607F, 0x608A, 0x6095, 0x60A8,
+ 0xD849 /*0xDEF3*/, 0x60B0, 0x60B1, 0x60BE, 0x60C8, 0x60D9, 0x60DB, 0x60EE,
+ 0x60F2, 0x60F5, 0x6110, 0x6112, 0x6113, 0x6119, 0x611E, 0x613A,
+ 0x396F, 0x6141, 0x6146, 0x6160, 0x617C, 0xD84A /*0xDC5B*/, 0x6192, 0x6193,
+ 0x6197, 0x6198, 0x61A5, 0x61A8, 0x61AD, 0xD84A /*0xDCAB*/, 0x61D5, 0x61DD,
+ 0x61DF, 0x61F5, 0xD84A /*0xDD8F*/, 0x6215, 0x6223, 0x6229, 0x6246, 0x624C,
+ 0x6251, 0x6252, 0x6261, 0x6264, 0x627B, 0x626D, 0x6273,
+};
+static const unsigned short euc_to_utf8_8FAD_x0213[] = {
+ 0x6299, 0x62A6, 0x62D5, 0xD84A /*0xDEB8*/, 0x62FD, 0x6303, 0x630D,
+ 0x6310, 0xD84A /*0xDF4F*/, 0xD84A /*0xDF50*/, 0x6332, 0x6335, 0x633B, 0x633C, 0x6341,
+ 0x6344, 0x634E, 0xD84A /*0xDF46*/, 0x6359, 0xD84B /*0xDC1D*/, 0xD84A /*0xDFA6*/, 0x636C, 0x6384,
+ 0x6399, 0xD84B /*0xDC24*/, 0x6394, 0x63BD, 0x63F7, 0x63D4, 0x63D5, 0x63DC,
+ 0x63E0, 0x63EB, 0x63EC, 0x63F2, 0x6409, 0x641E, 0x6425, 0x6429,
+ 0x642F, 0x645A, 0x645B, 0x645D, 0x6473, 0x647D, 0x6487, 0x6491,
+ 0x649D, 0x649F, 0x64CB, 0x64CC, 0x64D5, 0x64D7, 0xD84B /*0xDDE1*/, 0x64E4,
+ 0x64E5, 0x64FF, 0x6504, 0x3A6E, 0x650F, 0x6514, 0x6516, 0x3A73,
+ 0x651E, 0x6532, 0x6544, 0x6554, 0x656B, 0x657A, 0x6581, 0x6584,
+ 0x6585, 0x658A, 0x65B2, 0x65B5, 0x65B8, 0x65BF, 0x65C2, 0x65C9,
+ 0x65D4, 0x3AD6, 0x65F2, 0x65F9, 0x65FC, 0x6604, 0x6608, 0x6621,
+ 0x662A, 0x6645, 0x6651, 0x664E, 0x3AEA, 0xD84C /*0xDDC3*/, 0x6657,
+};
+static const unsigned short euc_to_utf8_8FAE_x0213[] = {
+ 0x665B, 0x6663, 0xD84C /*0xDDF5*/, 0xD84C /*0xDDB6*/, 0x666A, 0x666B, 0x666C,
+ 0x666D, 0x667B, 0x6680, 0x6690, 0x6692, 0x6699, 0x3B0E, 0x66AD,
+ 0x66B1, 0x66B5, 0x3B1A, 0x66BF, 0x3B1C, 0x66EC, 0x3AD7, 0x6701,
+ 0x6705, 0x6712, 0xD84C /*0xDF72*/, 0x6719, 0xD84C /*0xDFD3*/, 0xD84C /*0xDFD2*/, 0x674C, 0x674D,
+ 0x6754, 0x675D, 0xD84C /*0xDFD0*/, 0xD84C /*0xDFE4*/, 0xD84C /*0xDFD5*/, 0x6774, 0x6776, 0xD84C /*0xDFDA*/,
+ 0x6792, 0xD84C /*0xDFDF*/, 0x8363, 0x6810, 0x67B0, 0x67B2, 0x67C3, 0x67C8,
+ 0x67D2, 0x67D9, 0x67DB, 0x67F0, 0x67F7, 0xD84D /*0xDC4A*/, 0xD84D /*0xDC51*/, 0xD84D /*0xDC4B*/,
+ 0x6818, 0x681F, 0x682D, 0xD84D /*0xDC65*/, 0x6833, 0x683B, 0x683E, 0x6844,
+ 0x6845, 0x6849, 0x684C, 0x6855, 0x6857, 0x3B77, 0x686B, 0x686E,
+ 0x687A, 0x687C, 0x6882, 0x6890, 0x6896, 0x3B6D, 0x6898, 0x6899,
+ 0x689A, 0x689C, 0x68AA, 0x68AB, 0x68B4, 0x68BB, 0x68FB, 0xD84D /*0xDCE4*/,
+ 0xD84D /*0xDD5A*/, 0xFA13, 0x68C3, 0x68C5, 0x68CC, 0x68CF, 0x68D6,
+};
+static const unsigned short euc_to_utf8_8FAF_x0213[] = {
+ 0x68D9, 0x68E4, 0x68E5, 0x68EC, 0x68F7, 0x6903, 0x6907,
+ 0x3B87, 0x3B88, 0xD84D /*0xDD94*/, 0x693B, 0x3B8D, 0x6946, 0x6969, 0x696C,
+ 0x6972, 0x697A, 0x697F, 0x6992, 0x3BA4, 0x6996, 0x6998, 0x69A6,
+ 0x69B0, 0x69B7, 0x69BA, 0x69BC, 0x69C0, 0x69D1, 0x69D6, 0xD84D /*0xDE39*/,
+ 0xD84D /*0xDE47*/, 0x6A30, 0xD84D /*0xDE38*/, 0xD84D /*0xDE3A*/, 0x69E3, 0x69EE, 0x69EF, 0x69F3,
+ 0x3BCD, 0x69F4, 0x69FE, 0x6A11, 0x6A1A, 0x6A1D, 0xD84D /*0xDF1C*/, 0x6A32,
+ 0x6A33, 0x6A34, 0x6A3F, 0x6A46, 0x6A49, 0x6A7A, 0x6A4E, 0x6A52,
+ 0x6A64, 0xD84D /*0xDF0C*/, 0x6A7E, 0x6A83, 0x6A8B, 0x3BF0, 0x6A91, 0x6A9F,
+ 0x6AA1, 0xD84D /*0xDF64*/, 0x6AAB, 0x6ABD, 0x6AC6, 0x6AD4, 0x6AD0, 0x6ADC,
+ 0x6ADD, 0xD84D /*0xDFFF*/, 0xD84D /*0xDFE7*/, 0x6AEC, 0x6AF1, 0x6AF2, 0x6AF3, 0x6AFD,
+ 0xD84E /*0xDC24*/, 0x6B0B, 0x6B0F, 0x6B10, 0x6B11, 0xD84E /*0xDC3D*/, 0x6B17, 0x3C26,
+ 0x6B2F, 0x6B4A, 0x6B58, 0x6B6C, 0x6B75, 0x6B7A, 0x6B81,
+};
+static const unsigned short euc_to_utf8_8FEE_x0213[] = {
+ 0x6B9B, 0x6BAE, 0xD84E /*0xDE98*/, 0x6BBD, 0x6BBE, 0x6BC7, 0x6BC8,
+ 0x6BC9, 0x6BDA, 0x6BE6, 0x6BE7, 0x6BEE, 0x6BF1, 0x6C02, 0x6C0A,
+ 0x6C0E, 0x6C35, 0x6C36, 0x6C3A, 0xD84F /*0xDC7F*/, 0x6C3F, 0x6C4D, 0x6C5B,
+ 0x6C6D, 0x6C84, 0x6C89, 0x3CC3, 0x6C94, 0x6C95, 0x6C97, 0x6CAD,
+ 0x6CC2, 0x6CD0, 0x3CD2, 0x6CD6, 0x6CDA, 0x6CDC, 0x6CE9, 0x6CEC,
+ 0x6CED, 0xD84F /*0xDD00*/, 0x6D00, 0x6D0A, 0x6D24, 0x6D26, 0x6D27, 0x6C67,
+ 0x6D2F, 0x6D3C, 0x6D5B, 0x6D5E, 0x6D60, 0x6D70, 0x6D80, 0x6D81,
+ 0x6D8A, 0x6D8D, 0x6D91, 0x6D98, 0xD84F /*0xDD40*/, 0x6E17, 0xD84F /*0xDDFA*/, 0xD84F /*0xDDF9*/,
+ 0xD84F /*0xDDD3*/, 0x6DAB, 0x6DAE, 0x6DB4, 0x6DC2, 0x6D34, 0x6DC8, 0x6DCE,
+ 0x6DCF, 0x6DD0, 0x6DDF, 0x6DE9, 0x6DF6, 0x6E36, 0x6E1E, 0x6E22,
+ 0x6E27, 0x3D11, 0x6E32, 0x6E3C, 0x6E48, 0x6E49, 0x6E4B, 0x6E4C,
+ 0x6E4F, 0x6E51, 0x6E53, 0x6E54, 0x6E57, 0x6E63, 0x3D1E,
+};
+static const unsigned short euc_to_utf8_8FEF_x0213[] = {
+ 0x6E93, 0x6EA7, 0x6EB4, 0x6EBF, 0x6EC3, 0x6ECA, 0x6ED9,
+ 0x6F35, 0x6EEB, 0x6EF9, 0x6EFB, 0x6F0A, 0x6F0C, 0x6F18, 0x6F25,
+ 0x6F36, 0x6F3C, 0xD84F /*0xDF7E*/, 0x6F52, 0x6F57, 0x6F5A, 0x6F60, 0x6F68,
+ 0x6F98, 0x6F7D, 0x6F90, 0x6F96, 0x6FBE, 0x6F9F, 0x6FA5, 0x6FAF,
+ 0x3D64, 0x6FB5, 0x6FC8, 0x6FC9, 0x6FDA, 0x6FDE, 0x6FE9, 0xD850 /*0xDC96*/,
+ 0x6FFC, 0x7000, 0x7007, 0x700A, 0x7023, 0xD850 /*0xDD03*/, 0x7039, 0x703A,
+ 0x703C, 0x7043, 0x7047, 0x704B, 0x3D9A, 0x7054, 0x7065, 0x7069,
+ 0x706C, 0x706E, 0x7076, 0x707E, 0x7081, 0x7086, 0x7095, 0x7097,
+ 0x70BB, 0xD850 /*0xDDC6*/, 0x709F, 0x70B1, 0xD850 /*0xDDFE*/, 0x70EC, 0x70CA, 0x70D1,
+ 0x70D3, 0x70DC, 0x7103, 0x7104, 0x7106, 0x7107, 0x7108, 0x710C,
+ 0x3DC0, 0x712F, 0x7131, 0x7150, 0x714A, 0x7153, 0x715E, 0x3DD4,
+ 0x7196, 0x7180, 0x719B, 0x71A0, 0x71A2, 0x71AE, 0x71AF,
+};
+static const unsigned short euc_to_utf8_8FF0_x0213[] = {
+ 0x71B3, 0xD850 /*0xDFBC*/, 0x71CB, 0x71D3, 0x71D9, 0x71DC, 0x7207,
+ 0x3E05, 0xFA49, 0x722B, 0x7234, 0x7238, 0x7239, 0x4E2C, 0x7242,
+ 0x7253, 0x7257, 0x7263, 0xD851 /*0xDE29*/, 0x726E, 0x726F, 0x7278, 0x727F,
+ 0x728E, 0xD851 /*0xDEA5*/, 0x72AD, 0x72AE, 0x72B0, 0x72B1, 0x72C1, 0x3E60,
+ 0x72CC, 0x3E66, 0x3E68, 0x72F3, 0x72FA, 0x7307, 0x7312, 0x7318,
+ 0x7319, 0x3E83, 0x7339, 0x732C, 0x7331, 0x7333, 0x733D, 0x7352,
+ 0x3E94, 0x736B, 0x736C, 0xD852 /*0xDC96*/, 0x736E, 0x736F, 0x7371, 0x7377,
+ 0x7381, 0x7385, 0x738A, 0x7394, 0x7398, 0x739C, 0x739E, 0x73A5,
+ 0x73A8, 0x73B5, 0x73B7, 0x73B9, 0x73BC, 0x73BF, 0x73C5, 0x73CB,
+ 0x73E1, 0x73E7, 0x73F9, 0x7413, 0x73FA, 0x7401, 0x7424, 0x7431,
+ 0x7439, 0x7453, 0x7440, 0x7443, 0x744D, 0x7452, 0x745D, 0x7471,
+ 0x7481, 0x7485, 0x7488, 0xD852 /*0xDE4D*/, 0x7492, 0x7497, 0x7499,
+};
+static const unsigned short euc_to_utf8_8FF1_x0213[] = {
+ 0x74A0, 0x74A1, 0x74A5, 0x74AA, 0x74AB, 0x74B9, 0x74BB,
+ 0x74BA, 0x74D6, 0x74D8, 0x74DE, 0x74EF, 0x74EB, 0xD852 /*0xDF56*/, 0x74FA,
+ 0xD852 /*0xDF6F*/, 0x7520, 0x7524, 0x752A, 0x3F57, 0xD853 /*0xDC16*/, 0x753D, 0x753E,
+ 0x7540, 0x7548, 0x754E, 0x7550, 0x7552, 0x756C, 0x7572, 0x7571,
+ 0x757A, 0x757D, 0x757E, 0x7581, 0xD853 /*0xDD14*/, 0x758C, 0x3F75, 0x75A2,
+ 0x3F77, 0x75B0, 0x75B7, 0x75BF, 0x75C0, 0x75C6, 0x75CF, 0x75D3,
+ 0x75DD, 0x75DF, 0x75E0, 0x75E7, 0x75EC, 0x75EE, 0x75F1, 0x75F9,
+ 0x7603, 0x7618, 0x7607, 0x760F, 0x3FAE, 0xD853 /*0xDE0E*/, 0x7613, 0x761B,
+ 0x761C, 0xD853 /*0xDE37*/, 0x7625, 0x7628, 0x763C, 0x7633, 0xD853 /*0xDE6A*/, 0x3FC9,
+ 0x7641, 0xD853 /*0xDE8B*/, 0x7649, 0x7655, 0x3FD7, 0x766E, 0x7695, 0x769C,
+ 0x76A1, 0x76A0, 0x76A7, 0x76A8, 0x76AF, 0xD854 /*0xDC4A*/, 0x76C9, 0xD854 /*0xDC55*/,
+ 0x76E8, 0x76EC, 0xD854 /*0xDD22*/, 0x7717, 0x771A, 0x772D, 0x7735,
+};
+static const unsigned short euc_to_utf8_8FF2_x0213[] = {
+ 0xD854 /*0xDDA9*/, 0x4039, 0xD854 /*0xDDE5*/, 0xD854 /*0xDDCD*/, 0x7758, 0x7760, 0x776A,
+ 0xD854 /*0xDE1E*/, 0x7772, 0x777C, 0x777D, 0xD854 /*0xDE4C*/, 0x4058, 0x779A, 0x779F,
+ 0x77A2, 0x77A4, 0x77A9, 0x77DE, 0x77DF, 0x77E4, 0x77E6, 0x77EA,
+ 0x77EC, 0x4093, 0x77F0, 0x77F4, 0x77FB, 0xD855 /*0xDC2E*/, 0x7805, 0x7806,
+ 0x7809, 0x780D, 0x7819, 0x7821, 0x782C, 0x7847, 0x7864, 0x786A,
+ 0xD855 /*0xDCD9*/, 0x788A, 0x7894, 0x78A4, 0x789D, 0x789E, 0x789F, 0x78BB,
+ 0x78C8, 0x78CC, 0x78CE, 0x78D5, 0x78E0, 0x78E1, 0x78E6, 0x78F9,
+ 0x78FA, 0x78FB, 0x78FE, 0xD855 /*0xDDA7*/, 0x7910, 0x791B, 0x7930, 0x7925,
+ 0x793B, 0x794A, 0x7958, 0x795B, 0x4105, 0x7967, 0x7972, 0x7994,
+ 0x7995, 0x7996, 0x799B, 0x79A1, 0x79A9, 0x79B4, 0x79BB, 0x79C2,
+ 0x79C7, 0x79CC, 0x79CD, 0x79D6, 0x4148, 0xD855 /*0xDFA9*/, 0xD855 /*0xDFB4*/, 0x414F,
+ 0x7A0A, 0x7A11, 0x7A15, 0x7A1B, 0x7A1E, 0x4163, 0x7A2D,
+};
+static const unsigned short euc_to_utf8_8FF3_x0213[] = {
+ 0x7A38, 0x7A47, 0x7A4C, 0x7A56, 0x7A59, 0x7A5C, 0x7A5F,
+ 0x7A60, 0x7A67, 0x7A6A, 0x7A75, 0x7A78, 0x7A82, 0x7A8A, 0x7A90,
+ 0x7AA3, 0x7AAC, 0xD856 /*0xDDD4*/, 0x41B4, 0x7AB9, 0x7ABC, 0x7ABE, 0x41BF,
+ 0x7ACC, 0x7AD1, 0x7AE7, 0x7AE8, 0x7AF4, 0xD856 /*0xDEE4*/, 0xD856 /*0xDEE3*/, 0x7B07,
+ 0xD856 /*0xDEF1*/, 0x7B3D, 0x7B27, 0x7B2A, 0x7B2E, 0x7B2F, 0x7B31, 0x41E6,
+ 0x41F3, 0x7B7F, 0x7B41, 0x41EE, 0x7B55, 0x7B79, 0x7B64, 0x7B66,
+ 0x7B69, 0x7B73, 0xD856 /*0xDFB2*/, 0x4207, 0x7B90, 0x7B91, 0x7B9B, 0x420E,
+ 0x7BAF, 0x7BB5, 0x7BBC, 0x7BC5, 0x7BCA, 0xD857 /*0xDC4B*/, 0xD857 /*0xDC64*/, 0x7BD4,
+ 0x7BD6, 0x7BDA, 0x7BEA, 0x7BF0, 0x7C03, 0x7C0B, 0x7C0E, 0x7C0F,
+ 0x7C26, 0x7C45, 0x7C4A, 0x7C51, 0x7C57, 0x7C5E, 0x7C61, 0x7C69,
+ 0x7C6E, 0x7C6F, 0x7C70, 0xD857 /*0xDE2E*/, 0xD857 /*0xDE56*/, 0xD857 /*0xDE65*/, 0x7CA6, 0xD857 /*0xDE62*/,
+ 0x7CB6, 0x7CB7, 0x7CBF, 0xD857 /*0xDED8*/, 0x7CC4, 0xD857 /*0xDEC2*/, 0x7CC8,
+};
+static const unsigned short euc_to_utf8_8FF4_x0213[] = {
+ 0x7CCD, 0xD857 /*0xDEE8*/, 0x7CD7, 0xD857 /*0xDF23*/, 0x7CE6, 0x7CEB, 0xD857 /*0xDF5C*/,
+ 0x7CF5, 0x7D03, 0x7D09, 0x42C6, 0x7D12, 0x7D1E, 0xD857 /*0xDFE0*/, 0xD857 /*0xDFD4*/,
+ 0x7D3D, 0x7D3E, 0x7D40, 0x7D47, 0xD858 /*0xDC0C*/, 0xD857 /*0xDFFB*/, 0x42D6, 0x7D59,
+ 0x7D5A, 0x7D6A, 0x7D70, 0x42DD, 0x7D7F, 0xD858 /*0xDC17*/, 0x7D86, 0x7D88,
+ 0x7D8C, 0x7D97, 0xD858 /*0xDC60*/, 0x7D9D, 0x7DA7, 0x7DAA, 0x7DB6, 0x7DB7,
+ 0x7DC0, 0x7DD7, 0x7DD9, 0x7DE6, 0x7DF1, 0x7DF9, 0x4302, 0xD858 /*0xDCED*/,
+ 0xFA58, 0x7E10, 0x7E17, 0x7E1D, 0x7E20, 0x7E27, 0x7E2C, 0x7E45,
+ 0x7E73, 0x7E75, 0x7E7E, 0x7E86, 0x7E87, 0x432B, 0x7E91, 0x7E98,
+ 0x7E9A, 0x4343, 0x7F3C, 0x7F3B, 0x7F3E, 0x7F43, 0x7F44, 0x7F4F,
+ 0x34C1, 0xD858 /*0xDE70*/, 0x7F52, 0xD858 /*0xDE86*/, 0x7F61, 0x7F63, 0x7F64, 0x7F6D,
+ 0x7F7D, 0x7F7E, 0xD858 /*0xDF4C*/, 0x7F90, 0x517B, 0xD84F /*0xDD0E*/, 0x7F96, 0x7F9C,
+ 0x7FAD, 0xD859 /*0xDC02*/, 0x7FC3, 0x7FCF, 0x7FE3, 0x7FE5, 0x7FEF,
+};
+static const unsigned short euc_to_utf8_8FF5_x0213[] = {
+ 0x7FF2, 0x8002, 0x800A, 0x8008, 0x800E, 0x8011, 0x8016,
+ 0x8024, 0x802C, 0x8030, 0x8043, 0x8066, 0x8071, 0x8075, 0x807B,
+ 0x8099, 0x809C, 0x80A4, 0x80A7, 0x80B8, 0xD859 /*0xDE7E*/, 0x80C5, 0x80D5,
+ 0x80D8, 0x80E6, 0xD859 /*0xDEB0*/, 0x810D, 0x80F5, 0x80FB, 0x43EE, 0x8135,
+ 0x8116, 0x811E, 0x43F0, 0x8124, 0x8127, 0x812C, 0xD859 /*0xDF1D*/, 0x813D,
+ 0x4408, 0x8169, 0x4417, 0x8181, 0x441C, 0x8184, 0x8185, 0x4422,
+ 0x8198, 0x81B2, 0x81C1, 0x81C3, 0x81D6, 0x81DB, 0xD85A /*0xDCDD*/, 0x81E4,
+ 0xD85A /*0xDCEA*/, 0x81EC, 0xD85A /*0xDD51*/, 0x81FD, 0x81FF, 0xD85A /*0xDD6F*/, 0x8204, 0xD85A /*0xDDDD*/,
+ 0x8219, 0x8221, 0x8222, 0xD85A /*0xDE1E*/, 0x8232, 0x8234, 0x823C, 0x8246,
+ 0x8249, 0x8245, 0xD85A /*0xDE58*/, 0x824B, 0x4476, 0x824F, 0x447A, 0x8257,
+ 0xD85A /*0xDE8C*/, 0x825C, 0x8263, 0xD85A /*0xDEB7*/, 0xFA5D, 0xFA5E, 0x8279, 0x4491,
+ 0x827D, 0x827F, 0x8283, 0x828A, 0x8293, 0x82A7, 0x82A8,
+};
+static const unsigned short euc_to_utf8_8FF6_x0213[] = {
+ 0x82B2, 0x82B4, 0x82BA, 0x82BC, 0x82E2, 0x82E8, 0x82F7,
+ 0x8307, 0x8308, 0x830C, 0x8354, 0x831B, 0x831D, 0x8330, 0x833C,
+ 0x8344, 0x8357, 0x44BE, 0x837F, 0x44D4, 0x44B3, 0x838D, 0x8394,
+ 0x8395, 0x839B, 0x839D, 0x83C9, 0x83D0, 0x83D4, 0x83DD, 0x83E5,
+ 0x83F9, 0x840F, 0x8411, 0x8415, 0xD85B /*0xDC73*/, 0x8417, 0x8439, 0x844A,
+ 0x844F, 0x8451, 0x8452, 0x8459, 0x845A, 0x845C, 0xD85B /*0xDCDD*/, 0x8465,
+ 0x8476, 0x8478, 0x847C, 0x8481, 0x450D, 0x84DC, 0x8497, 0x84A6,
+ 0x84BE, 0x4508, 0x84CE, 0x84CF, 0x84D3, 0xD85B /*0xDE65*/, 0x84E7, 0x84EA,
+ 0x84EF, 0x84F0, 0x84F1, 0x84FA, 0x84FD, 0x850C, 0x851B, 0x8524,
+ 0x8525, 0x852B, 0x8534, 0x854F, 0x856F, 0x4525, 0x4543, 0x853E,
+ 0x8551, 0x8553, 0x855E, 0x8561, 0x8562, 0xD85B /*0xDF94*/, 0x857B, 0x857D,
+ 0x857F, 0x8581, 0x8586, 0x8593, 0x859D, 0x859F, 0xD85B /*0xDFF8*/,
+};
+static const unsigned short euc_to_utf8_8FF7_x0213[] = {
+ 0xD85B /*0xDFF6*/, 0xD85B /*0xDFF7*/, 0x85B7, 0x85BC, 0x85C7, 0x85CA, 0x85D8,
+ 0x85D9, 0x85DF, 0x85E1, 0x85E6, 0x85F6, 0x8600, 0x8611, 0x861E,
+ 0x8621, 0x8624, 0x8627, 0xD85C /*0xDD0D*/, 0x8639, 0x863C, 0xD85C /*0xDD39*/, 0x8640,
+ 0xFA20, 0x8653, 0x8656, 0x866F, 0x8677, 0x867A, 0x8687, 0x8689,
+ 0x868D, 0x8691, 0x869C, 0x869D, 0x86A8, 0xFA21, 0x86B1, 0x86B3,
+ 0x86C1, 0x86C3, 0x86D1, 0x86D5, 0x86D7, 0x86E3, 0x86E6, 0x45B8,
+ 0x8705, 0x8707, 0x870E, 0x8710, 0x8713, 0x8719, 0x871F, 0x8721,
+ 0x8723, 0x8731, 0x873A, 0x873E, 0x8740, 0x8743, 0x8751, 0x8758,
+ 0x8764, 0x8765, 0x8772, 0x877C, 0xD85C /*0xDFDB*/, 0xD85C /*0xDFDA*/, 0x87A7, 0x8789,
+ 0x878B, 0x8793, 0x87A0, 0xD85C /*0xDFFE*/, 0x45E5, 0x87BE, 0xD85D /*0xDC10*/, 0x87C1,
+ 0x87CE, 0x87F5, 0x87DF, 0xD85D /*0xDC49*/, 0x87E3, 0x87E5, 0x87E6, 0x87EA,
+ 0x87EB, 0x87ED, 0x8801, 0x8803, 0x880B, 0x8813, 0x8828,
+};
+static const unsigned short euc_to_utf8_8FF8_x0213[] = {
+ 0x882E, 0x8832, 0x883C, 0x460F, 0x884A, 0x8858, 0x885F,
+ 0x8864, 0xD85D /*0xDE15*/, 0xD85D /*0xDE14*/, 0x8869, 0xD85D /*0xDE31*/, 0x886F, 0x88A0, 0x88BC,
+ 0x88BD, 0x88BE, 0x88C0, 0x88D2, 0xD85D /*0xDE93*/, 0x88D1, 0x88D3, 0x88DB,
+ 0x88F0, 0x88F1, 0x4641, 0x8901, 0xD85D /*0xDF0E*/, 0x8937, 0xD85D /*0xDF23*/, 0x8942,
+ 0x8945, 0x8949, 0xD85D /*0xDF52*/, 0x4665, 0x8962, 0x8980, 0x8989, 0x8990,
+ 0x899F, 0x89B0, 0x89B7, 0x89D6, 0x89D8, 0x89EB, 0x46A1, 0x89F1,
+ 0x89F3, 0x89FD, 0x89FF, 0x46AF, 0x8A11, 0x8A14, 0xD85E /*0xDD85*/, 0x8A21,
+ 0x8A35, 0x8A3E, 0x8A45, 0x8A4D, 0x8A58, 0x8AAE, 0x8A90, 0x8AB7,
+ 0x8ABE, 0x8AD7, 0x8AFC, 0xD85E /*0xDE84*/, 0x8B0A, 0x8B05, 0x8B0D, 0x8B1C,
+ 0x8B1F, 0x8B2D, 0x8B43, 0x470C, 0x8B51, 0x8B5E, 0x8B76, 0x8B7F,
+ 0x8B81, 0x8B8B, 0x8B94, 0x8B95, 0x8B9C, 0x8B9E, 0x8C39, 0xD85E /*0xDFB3*/,
+ 0x8C3D, 0xD85E /*0xDFBE*/, 0xD85E /*0xDFC7*/, 0x8C45, 0x8C47, 0x8C4F, 0x8C54,
+};
+static const unsigned short euc_to_utf8_8FF9_x0213[] = {
+ 0x8C57, 0x8C69, 0x8C6D, 0x8C73, 0xD85F /*0xDCB8*/, 0x8C93, 0x8C92,
+ 0x8C99, 0x4764, 0x8C9B, 0x8CA4, 0x8CD6, 0x8CD5, 0x8CD9, 0xD85F /*0xDDA0*/,
+ 0x8CF0, 0x8CF1, 0xD85F /*0xDE10*/, 0x8D09, 0x8D0E, 0x8D6C, 0x8D84, 0x8D95,
+ 0x8DA6, 0xD85F /*0xDFB7*/, 0x8DC6, 0x8DC8, 0x8DD9, 0x8DEC, 0x8E0C, 0x47FD,
+ 0x8DFD, 0x8E06, 0xD860 /*0xDC8A*/, 0x8E14, 0x8E16, 0x8E21, 0x8E22, 0x8E27,
+ 0xD860 /*0xDCBB*/, 0x4816, 0x8E36, 0x8E39, 0x8E4B, 0x8E54, 0x8E62, 0x8E6C,
+ 0x8E6D, 0x8E6F, 0x8E98, 0x8E9E, 0x8EAE, 0x8EB3, 0x8EB5, 0x8EB6,
+ 0x8EBB, 0xD860 /*0xDE82*/, 0x8ED1, 0x8ED4, 0x484E, 0x8EF9, 0xD860 /*0xDEF3*/, 0x8F00,
+ 0x8F08, 0x8F17, 0x8F2B, 0x8F40, 0x8F4A, 0x8F58, 0xD861 /*0xDC0C*/, 0x8FA4,
+ 0x8FB4, 0xFA66, 0x8FB6, 0xD861 /*0xDC55*/, 0x8FC1, 0x8FC6, 0xFA24, 0x8FCA,
+ 0x8FCD, 0x8FD3, 0x8FD5, 0x8FE0, 0x8FF1, 0x8FF5, 0x8FFB, 0x9002,
+ 0x900C, 0x9037, 0xD861 /*0xDD6B*/, 0x9043, 0x9044, 0x905D, 0xD861 /*0xDDC8*/,
+};
+static const unsigned short euc_to_utf8_8FFA_x0213[] = {
+ 0xD861 /*0xDDC9*/, 0x9085, 0x908C, 0x9090, 0x961D, 0x90A1, 0x48B5,
+ 0x90B0, 0x90B6, 0x90C3, 0x90C8, 0xD861 /*0xDED7*/, 0x90DC, 0x90DF, 0xD861 /*0xDEFA*/,
+ 0x90F6, 0x90F2, 0x9100, 0x90EB, 0x90FE, 0x90FF, 0x9104, 0x9106,
+ 0x9118, 0x911C, 0x911E, 0x9137, 0x9139, 0x913A, 0x9146, 0x9147,
+ 0x9157, 0x9159, 0x9161, 0x9164, 0x9174, 0x9179, 0x9185, 0x918E,
+ 0x91A8, 0x91AE, 0x91B3, 0x91B6, 0x91C3, 0x91C4, 0x91DA, 0xD862 /*0xDD49*/,
+ 0xD862 /*0xDD46*/, 0x91EC, 0x91EE, 0x9201, 0x920A, 0x9216, 0x9217, 0xD862 /*0xDD6B*/,
+ 0x9233, 0x9242, 0x9247, 0x924A, 0x924E, 0x9251, 0x9256, 0x9259,
+ 0x9260, 0x9261, 0x9265, 0x9267, 0x9268, 0xD862 /*0xDD87*/, 0xD862 /*0xDD88*/, 0x927C,
+ 0x927D, 0x927F, 0x9289, 0x928D, 0x9297, 0x9299, 0x929F, 0x92A7,
+ 0x92AB, 0xD862 /*0xDDBA*/, 0xD862 /*0xDDBB*/, 0x92B2, 0x92BF, 0x92C0, 0x92C6, 0x92CE,
+ 0x92D0, 0x92D7, 0x92D9, 0x92E5, 0x92E7, 0x9311, 0xD862 /*0xDE1E*/,
+};
+static const unsigned short euc_to_utf8_8FFB_x0213[] = {
+ 0xD862 /*0xDE29*/, 0x92F7, 0x92F9, 0x92FB, 0x9302, 0x930D, 0x9315,
+ 0x931D, 0x931E, 0x9327, 0x9329, 0xD862 /*0xDE71*/, 0xD862 /*0xDE43*/, 0x9347, 0x9351,
+ 0x9357, 0x935A, 0x936B, 0x9371, 0x9373, 0x93A1, 0xD862 /*0xDE99*/, 0xD862 /*0xDECD*/,
+ 0x9388, 0x938B, 0x938F, 0x939E, 0x93F5, 0xD862 /*0xDEE4*/, 0xD862 /*0xDEDD*/, 0x93F1,
+ 0x93C1, 0x93C7, 0x93DC, 0x93E2, 0x93E7, 0x9409, 0x940F, 0x9416,
+ 0x9417, 0x93FB, 0x9432, 0x9434, 0x943B, 0x9445, 0xD862 /*0xDFC1*/, 0xD862 /*0xDFEF*/,
+ 0x946D, 0x946F, 0x9578, 0x9579, 0x9586, 0x958C, 0x958D, 0xD863 /*0xDD10*/,
+ 0x95AB, 0x95B4, 0xD863 /*0xDD71*/, 0x95C8, 0xD863 /*0xDDFB*/, 0xD863 /*0xDE1F*/, 0x962C, 0x9633,
+ 0x9634, 0xD863 /*0xDE36*/, 0x963C, 0x9641, 0x9661, 0xD863 /*0xDE89*/, 0x9682, 0xD863 /*0xDEEB*/,
+ 0x969A, 0xD863 /*0xDF32*/, 0x49E7, 0x96A9, 0x96AF, 0x96B3, 0x96BA, 0x96BD,
+ 0x49FA, 0xD863 /*0xDFF8*/, 0x96D8, 0x96DA, 0x96DD, 0x4A04, 0x9714, 0x9723,
+ 0x4A29, 0x9736, 0x9741, 0x9747, 0x9755, 0x9757, 0x975B,
+};
+static const unsigned short euc_to_utf8_8FFC_x0213[] = {
+ 0x976A, 0xD864 /*0xDEA0*/, 0xD864 /*0xDEB1*/, 0x9796, 0x979A, 0x979E, 0x97A2,
+ 0x97B1, 0x97B2, 0x97BE, 0x97CC, 0x97D1, 0x97D4, 0x97D8, 0x97D9,
+ 0x97E1, 0x97F1, 0x9804, 0x980D, 0x980E, 0x9814, 0x9816, 0x4ABC,
+ 0xD865 /*0xDC90*/, 0x9823, 0x9832, 0x9833, 0x9825, 0x9847, 0x9866, 0x98AB,
+ 0x98AD, 0x98B0, 0xD865 /*0xDDCF*/, 0x98B7, 0x98B8, 0x98BB, 0x98BC, 0x98BF,
+ 0x98C2, 0x98C7, 0x98CB, 0x98E0, 0xD865 /*0xDE7F*/, 0x98E1, 0x98E3, 0x98E5,
+ 0x98EA, 0x98F0, 0x98F1, 0x98F3, 0x9908, 0x4B3B, 0xD865 /*0xDEF0*/, 0x9916,
+ 0x9917, 0xD865 /*0xDF19*/, 0x991A, 0x991B, 0x991C, 0xD865 /*0xDF50*/, 0x9931, 0x9932,
+ 0x9933, 0x993A, 0x993B, 0x993C, 0x9940, 0x9941, 0x9946, 0x994D,
+ 0x994E, 0x995C, 0x995F, 0x9960, 0x99A3, 0x99A6, 0x99B9, 0x99BD,
+ 0x99BF, 0x99C3, 0x99C9, 0x99D4, 0x99D9, 0x99DE, 0xD866 /*0xDCC6*/, 0x99F0,
+ 0x99F9, 0x99FC, 0x9A0A, 0x9A11, 0x9A16, 0x9A1A, 0x9A20,
+};
+static const unsigned short euc_to_utf8_8FFD_x0213[] = {
+ 0x9A31, 0x9A36, 0x9A44, 0x9A4C, 0x9A58, 0x4BC2, 0x9AAF,
+ 0x4BCA, 0x9AB7, 0x4BD2, 0x9AB9, 0xD866 /*0xDE72*/, 0x9AC6, 0x9AD0, 0x9AD2,
+ 0x9AD5, 0x4BE8, 0x9ADC, 0x9AE0, 0x9AE5, 0x9AE9, 0x9B03, 0x9B0C,
+ 0x9B10, 0x9B12, 0x9B16, 0x9B1C, 0x9B2B, 0x9B33, 0x9B3D, 0x4C20,
+ 0x9B4B, 0x9B63, 0x9B65, 0x9B6B, 0x9B6C, 0x9B73, 0x9B76, 0x9B77,
+ 0x9BA6, 0x9BAC, 0x9BB1, 0xD867 /*0xDDDB*/, 0xD867 /*0xDE3D*/, 0x9BB2, 0x9BB8, 0x9BBE,
+ 0x9BC7, 0x9BF3, 0x9BD8, 0x9BDD, 0x9BE7, 0x9BEA, 0x9BEB, 0x9BEF,
+ 0x9BEE, 0xD867 /*0xDE15*/, 0x9BFA, 0xD867 /*0xDE8A*/, 0x9BF7, 0xD867 /*0xDE49*/, 0x9C16, 0x9C18,
+ 0x9C19, 0x9C1A, 0x9C1D, 0x9C22, 0x9C27, 0x9C29, 0x9C2A, 0xD867 /*0xDEC4*/,
+ 0x9C31, 0x9C36, 0x9C37, 0x9C45, 0x9C5C, 0xD867 /*0xDEE9*/, 0x9C49, 0x9C4A,
+ 0xD867 /*0xDEDB*/, 0x9C54, 0x9C58, 0x9C5B, 0x9C5D, 0x9C5F, 0x9C69, 0x9C6A,
+ 0x9C6B, 0x9C6D, 0x9C6E, 0x9C70, 0x9C72, 0x9C75, 0x9C7A,
+};
+static const unsigned short euc_to_utf8_8FFE_x0213[] = {
+ 0x9CE6, 0x9CF2, 0x9D0B, 0x9D02, 0xD867 /*0xDFCE*/, 0x9D11, 0x9D17,
+ 0x9D18, 0xD868 /*0xDC2F*/, 0x4CC4, 0xD868 /*0xDC1A*/, 0x9D32, 0x4CD1, 0x9D42, 0x9D4A,
+ 0x9D5F, 0x9D62, 0xD868 /*0xDCF9*/, 0x9D69, 0x9D6B, 0xD868 /*0xDC82*/, 0x9D73, 0x9D76,
+ 0x9D77, 0x9D7E, 0x9D84, 0x9D8D, 0x9D99, 0x9DA1, 0x9DBF, 0x9DB5,
+ 0x9DB9, 0x9DBD, 0x9DC3, 0x9DC7, 0x9DC9, 0x9DD6, 0x9DDA, 0x9DDF,
+ 0x9DE0, 0x9DE3, 0x9DF4, 0x4D07, 0x9E0A, 0x9E02, 0x9E0D, 0x9E19,
+ 0x9E1C, 0x9E1D, 0x9E7B, 0xD848 /*0xDE18*/, 0x9E80, 0x9E85, 0x9E9B, 0x9EA8,
+ 0xD868 /*0xDF8C*/, 0x9EBD, 0xD869 /*0xDC37*/, 0x9EDF, 0x9EE7, 0x9EEE, 0x9EFF, 0x9F02,
+ 0x4D77, 0x9F03, 0x9F17, 0x9F19, 0x9F2F, 0x9F37, 0x9F3A, 0x9F3D,
+ 0x9F41, 0x9F45, 0x9F46, 0x9F53, 0x9F55, 0x9F58, 0xD869 /*0xDDF1*/, 0x9F5D,
+ 0xD869 /*0xDE02*/, 0x9F69, 0xD869 /*0xDE1A*/, 0x9F6D, 0x9F70, 0x9F75, 0xD869 /*0xDEB2*/, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+
+#ifdef X0212_ENABLE
+static const unsigned short euc_to_utf8_8FA2[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x02D8,
+ 0x02C7, 0x00B8, 0x02D9, 0x02DD, 0x00AF, 0x02DB, 0x02DA, 0xFF5E,
+ 0x0384, 0x0385, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x00A1, 0xFFE4, 0x00BF, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x00BA, 0x00AA, 0x00A9, 0x00AE, 0x2122,
+ 0x00A4, 0x2116, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_8FA6[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x0386, 0x0388, 0x0389, 0x038A, 0x03AA, 0, 0x038C,
+ 0, 0x038E, 0x03AB, 0, 0x038F, 0, 0, 0,
+ 0, 0x03AC, 0x03AD, 0x03AE, 0x03AF, 0x03CA, 0x0390, 0x03CC,
+ 0x03C2, 0x03CD, 0x03CB, 0x03B0, 0x03CE, 0, 0,
+};
+static const unsigned short euc_to_utf8_8FA7[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407,
+ 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x040E, 0x040F, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+ 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045E, 0x045F,
+};
+static const unsigned short euc_to_utf8_8FA9[] = {
+ 0x00C6, 0x0110, 0, 0x0126, 0, 0x0132, 0,
+ 0x0141, 0x013F, 0, 0x014A, 0x00D8, 0x0152, 0, 0x0166,
+ 0x00DE, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x00E6, 0x0111, 0x00F0, 0x0127, 0x0131, 0x0133, 0x0138,
+ 0x0142, 0x0140, 0x0149, 0x014B, 0x00F8, 0x0153, 0x00DF, 0x0167,
+ 0x00FE, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_8FAA[] = {
+ 0x00C1, 0x00C0, 0x00C4, 0x00C2, 0x0102, 0x01CD, 0x0100,
+ 0x0104, 0x00C5, 0x00C3, 0x0106, 0x0108, 0x010C, 0x00C7, 0x010A,
+ 0x010E, 0x00C9, 0x00C8, 0x00CB, 0x00CA, 0x011A, 0x0116, 0x0112,
+ 0x0118, 0, 0x011C, 0x011E, 0x0122, 0x0120, 0x0124, 0x00CD,
+ 0x00CC, 0x00CF, 0x00CE, 0x01CF, 0x0130, 0x012A, 0x012E, 0x0128,
+ 0x0134, 0x0136, 0x0139, 0x013D, 0x013B, 0x0143, 0x0147, 0x0145,
+ 0x00D1, 0x00D3, 0x00D2, 0x00D6, 0x00D4, 0x01D1, 0x0150, 0x014C,
+ 0x00D5, 0x0154, 0x0158, 0x0156, 0x015A, 0x015C, 0x0160, 0x015E,
+ 0x0164, 0x0162, 0x00DA, 0x00D9, 0x00DC, 0x00DB, 0x016C, 0x01D3,
+ 0x0170, 0x016A, 0x0172, 0x016E, 0x0168, 0x01D7, 0x01DB, 0x01D9,
+ 0x01D5, 0x0174, 0x00DD, 0x0178, 0x0176, 0x0179, 0x017D, 0x017B,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_8FAB[] = {
+ 0x00E1, 0x00E0, 0x00E4, 0x00E2, 0x0103, 0x01CE, 0x0101,
+ 0x0105, 0x00E5, 0x00E3, 0x0107, 0x0109, 0x010D, 0x00E7, 0x010B,
+ 0x010F, 0x00E9, 0x00E8, 0x00EB, 0x00EA, 0x011B, 0x0117, 0x0113,
+ 0x0119, 0x01F5, 0x011D, 0x011F, 0, 0x0121, 0x0125, 0x00ED,
+ 0x00EC, 0x00EF, 0x00EE, 0x01D0, 0, 0x012B, 0x012F, 0x0129,
+ 0x0135, 0x0137, 0x013A, 0x013E, 0x013C, 0x0144, 0x0148, 0x0146,
+ 0x00F1, 0x00F3, 0x00F2, 0x00F6, 0x00F4, 0x01D2, 0x0151, 0x014D,
+ 0x00F5, 0x0155, 0x0159, 0x0157, 0x015B, 0x015D, 0x0161, 0x015F,
+ 0x0165, 0x0163, 0x00FA, 0x00F9, 0x00FC, 0x00FB, 0x016D, 0x01D4,
+ 0x0171, 0x016B, 0x0173, 0x016F, 0x0169, 0x01D8, 0x01DC, 0x01DA,
+ 0x01D6, 0x0175, 0x00FD, 0x00FF, 0x0177, 0x017A, 0x017E, 0x017C,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_8FB0[] = {
+ 0x4E02, 0x4E04, 0x4E05, 0x4E0C, 0x4E12, 0x4E1F, 0x4E23,
+ 0x4E24, 0x4E28, 0x4E2B, 0x4E2E, 0x4E2F, 0x4E30, 0x4E35, 0x4E40,
+ 0x4E41, 0x4E44, 0x4E47, 0x4E51, 0x4E5A, 0x4E5C, 0x4E63, 0x4E68,
+ 0x4E69, 0x4E74, 0x4E75, 0x4E79, 0x4E7F, 0x4E8D, 0x4E96, 0x4E97,
+ 0x4E9D, 0x4EAF, 0x4EB9, 0x4EC3, 0x4ED0, 0x4EDA, 0x4EDB, 0x4EE0,
+ 0x4EE1, 0x4EE2, 0x4EE8, 0x4EEF, 0x4EF1, 0x4EF3, 0x4EF5, 0x4EFD,
+ 0x4EFE, 0x4EFF, 0x4F00, 0x4F02, 0x4F03, 0x4F08, 0x4F0B, 0x4F0C,
+ 0x4F12, 0x4F15, 0x4F16, 0x4F17, 0x4F19, 0x4F2E, 0x4F31, 0x4F60,
+ 0x4F33, 0x4F35, 0x4F37, 0x4F39, 0x4F3B, 0x4F3E, 0x4F40, 0x4F42,
+ 0x4F48, 0x4F49, 0x4F4B, 0x4F4C, 0x4F52, 0x4F54, 0x4F56, 0x4F58,
+ 0x4F5F, 0x4F63, 0x4F6A, 0x4F6C, 0x4F6E, 0x4F71, 0x4F77, 0x4F78,
+ 0x4F79, 0x4F7A, 0x4F7D, 0x4F7E, 0x4F81, 0x4F82, 0x4F84,
+};
+static const unsigned short euc_to_utf8_8FB1[] = {
+ 0x4F85, 0x4F89, 0x4F8A, 0x4F8C, 0x4F8E, 0x4F90, 0x4F92,
+ 0x4F93, 0x4F94, 0x4F97, 0x4F99, 0x4F9A, 0x4F9E, 0x4F9F, 0x4FB2,
+ 0x4FB7, 0x4FB9, 0x4FBB, 0x4FBC, 0x4FBD, 0x4FBE, 0x4FC0, 0x4FC1,
+ 0x4FC5, 0x4FC6, 0x4FC8, 0x4FC9, 0x4FCB, 0x4FCC, 0x4FCD, 0x4FCF,
+ 0x4FD2, 0x4FDC, 0x4FE0, 0x4FE2, 0x4FF0, 0x4FF2, 0x4FFC, 0x4FFD,
+ 0x4FFF, 0x5000, 0x5001, 0x5004, 0x5007, 0x500A, 0x500C, 0x500E,
+ 0x5010, 0x5013, 0x5017, 0x5018, 0x501B, 0x501C, 0x501D, 0x501E,
+ 0x5022, 0x5027, 0x502E, 0x5030, 0x5032, 0x5033, 0x5035, 0x5040,
+ 0x5041, 0x5042, 0x5045, 0x5046, 0x504A, 0x504C, 0x504E, 0x5051,
+ 0x5052, 0x5053, 0x5057, 0x5059, 0x505F, 0x5060, 0x5062, 0x5063,
+ 0x5066, 0x5067, 0x506A, 0x506D, 0x5070, 0x5071, 0x503B, 0x5081,
+ 0x5083, 0x5084, 0x5086, 0x508A, 0x508E, 0x508F, 0x5090,
+};
+static const unsigned short euc_to_utf8_8FB2[] = {
+ 0x5092, 0x5093, 0x5094, 0x5096, 0x509B, 0x509C, 0x509E,
+ 0x509F, 0x50A0, 0x50A1, 0x50A2, 0x50AA, 0x50AF, 0x50B0, 0x50B9,
+ 0x50BA, 0x50BD, 0x50C0, 0x50C3, 0x50C4, 0x50C7, 0x50CC, 0x50CE,
+ 0x50D0, 0x50D3, 0x50D4, 0x50D8, 0x50DC, 0x50DD, 0x50DF, 0x50E2,
+ 0x50E4, 0x50E6, 0x50E8, 0x50E9, 0x50EF, 0x50F1, 0x50F6, 0x50FA,
+ 0x50FE, 0x5103, 0x5106, 0x5107, 0x5108, 0x510B, 0x510C, 0x510D,
+ 0x510E, 0x50F2, 0x5110, 0x5117, 0x5119, 0x511B, 0x511C, 0x511D,
+ 0x511E, 0x5123, 0x5127, 0x5128, 0x512C, 0x512D, 0x512F, 0x5131,
+ 0x5133, 0x5134, 0x5135, 0x5138, 0x5139, 0x5142, 0x514A, 0x514F,
+ 0x5153, 0x5155, 0x5157, 0x5158, 0x515F, 0x5164, 0x5166, 0x517E,
+ 0x5183, 0x5184, 0x518B, 0x518E, 0x5198, 0x519D, 0x51A1, 0x51A3,
+ 0x51AD, 0x51B8, 0x51BA, 0x51BC, 0x51BE, 0x51BF, 0x51C2,
+};
+static const unsigned short euc_to_utf8_8FB3[] = {
+ 0x51C8, 0x51CF, 0x51D1, 0x51D2, 0x51D3, 0x51D5, 0x51D8,
+ 0x51DE, 0x51E2, 0x51E5, 0x51EE, 0x51F2, 0x51F3, 0x51F4, 0x51F7,
+ 0x5201, 0x5202, 0x5205, 0x5212, 0x5213, 0x5215, 0x5216, 0x5218,
+ 0x5222, 0x5228, 0x5231, 0x5232, 0x5235, 0x523C, 0x5245, 0x5249,
+ 0x5255, 0x5257, 0x5258, 0x525A, 0x525C, 0x525F, 0x5260, 0x5261,
+ 0x5266, 0x526E, 0x5277, 0x5278, 0x5279, 0x5280, 0x5282, 0x5285,
+ 0x528A, 0x528C, 0x5293, 0x5295, 0x5296, 0x5297, 0x5298, 0x529A,
+ 0x529C, 0x52A4, 0x52A5, 0x52A6, 0x52A7, 0x52AF, 0x52B0, 0x52B6,
+ 0x52B7, 0x52B8, 0x52BA, 0x52BB, 0x52BD, 0x52C0, 0x52C4, 0x52C6,
+ 0x52C8, 0x52CC, 0x52CF, 0x52D1, 0x52D4, 0x52D6, 0x52DB, 0x52DC,
+ 0x52E1, 0x52E5, 0x52E8, 0x52E9, 0x52EA, 0x52EC, 0x52F0, 0x52F1,
+ 0x52F4, 0x52F6, 0x52F7, 0x5300, 0x5303, 0x530A, 0x530B,
+};
+static const unsigned short euc_to_utf8_8FB4[] = {
+ 0x530C, 0x5311, 0x5313, 0x5318, 0x531B, 0x531C, 0x531E,
+ 0x531F, 0x5325, 0x5327, 0x5328, 0x5329, 0x532B, 0x532C, 0x532D,
+ 0x5330, 0x5332, 0x5335, 0x533C, 0x533D, 0x533E, 0x5342, 0x534C,
+ 0x534B, 0x5359, 0x535B, 0x5361, 0x5363, 0x5365, 0x536C, 0x536D,
+ 0x5372, 0x5379, 0x537E, 0x5383, 0x5387, 0x5388, 0x538E, 0x5393,
+ 0x5394, 0x5399, 0x539D, 0x53A1, 0x53A4, 0x53AA, 0x53AB, 0x53AF,
+ 0x53B2, 0x53B4, 0x53B5, 0x53B7, 0x53B8, 0x53BA, 0x53BD, 0x53C0,
+ 0x53C5, 0x53CF, 0x53D2, 0x53D3, 0x53D5, 0x53DA, 0x53DD, 0x53DE,
+ 0x53E0, 0x53E6, 0x53E7, 0x53F5, 0x5402, 0x5413, 0x541A, 0x5421,
+ 0x5427, 0x5428, 0x542A, 0x542F, 0x5431, 0x5434, 0x5435, 0x5443,
+ 0x5444, 0x5447, 0x544D, 0x544F, 0x545E, 0x5462, 0x5464, 0x5466,
+ 0x5467, 0x5469, 0x546B, 0x546D, 0x546E, 0x5474, 0x547F,
+};
+static const unsigned short euc_to_utf8_8FB5[] = {
+ 0x5481, 0x5483, 0x5485, 0x5488, 0x5489, 0x548D, 0x5491,
+ 0x5495, 0x5496, 0x549C, 0x549F, 0x54A1, 0x54A6, 0x54A7, 0x54A9,
+ 0x54AA, 0x54AD, 0x54AE, 0x54B1, 0x54B7, 0x54B9, 0x54BA, 0x54BB,
+ 0x54BF, 0x54C6, 0x54CA, 0x54CD, 0x54CE, 0x54E0, 0x54EA, 0x54EC,
+ 0x54EF, 0x54F6, 0x54FC, 0x54FE, 0x54FF, 0x5500, 0x5501, 0x5505,
+ 0x5508, 0x5509, 0x550C, 0x550D, 0x550E, 0x5515, 0x552A, 0x552B,
+ 0x5532, 0x5535, 0x5536, 0x553B, 0x553C, 0x553D, 0x5541, 0x5547,
+ 0x5549, 0x554A, 0x554D, 0x5550, 0x5551, 0x5558, 0x555A, 0x555B,
+ 0x555E, 0x5560, 0x5561, 0x5564, 0x5566, 0x557F, 0x5581, 0x5582,
+ 0x5586, 0x5588, 0x558E, 0x558F, 0x5591, 0x5592, 0x5593, 0x5594,
+ 0x5597, 0x55A3, 0x55A4, 0x55AD, 0x55B2, 0x55BF, 0x55C1, 0x55C3,
+ 0x55C6, 0x55C9, 0x55CB, 0x55CC, 0x55CE, 0x55D1, 0x55D2,
+};
+static const unsigned short euc_to_utf8_8FB6[] = {
+ 0x55D3, 0x55D7, 0x55D8, 0x55DB, 0x55DE, 0x55E2, 0x55E9,
+ 0x55F6, 0x55FF, 0x5605, 0x5608, 0x560A, 0x560D, 0x560E, 0x560F,
+ 0x5610, 0x5611, 0x5612, 0x5619, 0x562C, 0x5630, 0x5633, 0x5635,
+ 0x5637, 0x5639, 0x563B, 0x563C, 0x563D, 0x563F, 0x5640, 0x5641,
+ 0x5643, 0x5644, 0x5646, 0x5649, 0x564B, 0x564D, 0x564F, 0x5654,
+ 0x565E, 0x5660, 0x5661, 0x5662, 0x5663, 0x5666, 0x5669, 0x566D,
+ 0x566F, 0x5671, 0x5672, 0x5675, 0x5684, 0x5685, 0x5688, 0x568B,
+ 0x568C, 0x5695, 0x5699, 0x569A, 0x569D, 0x569E, 0x569F, 0x56A6,
+ 0x56A7, 0x56A8, 0x56A9, 0x56AB, 0x56AC, 0x56AD, 0x56B1, 0x56B3,
+ 0x56B7, 0x56BE, 0x56C5, 0x56C9, 0x56CA, 0x56CB, 0x56CF, 0x56D0,
+ 0x56CC, 0x56CD, 0x56D9, 0x56DC, 0x56DD, 0x56DF, 0x56E1, 0x56E4,
+ 0x56E5, 0x56E6, 0x56E7, 0x56E8, 0x56F1, 0x56EB, 0x56ED,
+};
+static const unsigned short euc_to_utf8_8FB7[] = {
+ 0x56F6, 0x56F7, 0x5701, 0x5702, 0x5707, 0x570A, 0x570C,
+ 0x5711, 0x5715, 0x571A, 0x571B, 0x571D, 0x5720, 0x5722, 0x5723,
+ 0x5724, 0x5725, 0x5729, 0x572A, 0x572C, 0x572E, 0x572F, 0x5733,
+ 0x5734, 0x573D, 0x573E, 0x573F, 0x5745, 0x5746, 0x574C, 0x574D,
+ 0x5752, 0x5762, 0x5765, 0x5767, 0x5768, 0x576B, 0x576D, 0x576E,
+ 0x576F, 0x5770, 0x5771, 0x5773, 0x5774, 0x5775, 0x5777, 0x5779,
+ 0x577A, 0x577B, 0x577C, 0x577E, 0x5781, 0x5783, 0x578C, 0x5794,
+ 0x5797, 0x5799, 0x579A, 0x579C, 0x579D, 0x579E, 0x579F, 0x57A1,
+ 0x5795, 0x57A7, 0x57A8, 0x57A9, 0x57AC, 0x57B8, 0x57BD, 0x57C7,
+ 0x57C8, 0x57CC, 0x57CF, 0x57D5, 0x57DD, 0x57DE, 0x57E4, 0x57E6,
+ 0x57E7, 0x57E9, 0x57ED, 0x57F0, 0x57F5, 0x57F6, 0x57F8, 0x57FD,
+ 0x57FE, 0x57FF, 0x5803, 0x5804, 0x5808, 0x5809, 0x57E1,
+};
+static const unsigned short euc_to_utf8_8FB8[] = {
+ 0x580C, 0x580D, 0x581B, 0x581E, 0x581F, 0x5820, 0x5826,
+ 0x5827, 0x582D, 0x5832, 0x5839, 0x583F, 0x5849, 0x584C, 0x584D,
+ 0x584F, 0x5850, 0x5855, 0x585F, 0x5861, 0x5864, 0x5867, 0x5868,
+ 0x5878, 0x587C, 0x587F, 0x5880, 0x5881, 0x5887, 0x5888, 0x5889,
+ 0x588A, 0x588C, 0x588D, 0x588F, 0x5890, 0x5894, 0x5896, 0x589D,
+ 0x58A0, 0x58A1, 0x58A2, 0x58A6, 0x58A9, 0x58B1, 0x58B2, 0x58C4,
+ 0x58BC, 0x58C2, 0x58C8, 0x58CD, 0x58CE, 0x58D0, 0x58D2, 0x58D4,
+ 0x58D6, 0x58DA, 0x58DD, 0x58E1, 0x58E2, 0x58E9, 0x58F3, 0x5905,
+ 0x5906, 0x590B, 0x590C, 0x5912, 0x5913, 0x5914, 0x8641, 0x591D,
+ 0x5921, 0x5923, 0x5924, 0x5928, 0x592F, 0x5930, 0x5933, 0x5935,
+ 0x5936, 0x593F, 0x5943, 0x5946, 0x5952, 0x5953, 0x5959, 0x595B,
+ 0x595D, 0x595E, 0x595F, 0x5961, 0x5963, 0x596B, 0x596D,
+};
+static const unsigned short euc_to_utf8_8FB9[] = {
+ 0x596F, 0x5972, 0x5975, 0x5976, 0x5979, 0x597B, 0x597C,
+ 0x598B, 0x598C, 0x598E, 0x5992, 0x5995, 0x5997, 0x599F, 0x59A4,
+ 0x59A7, 0x59AD, 0x59AE, 0x59AF, 0x59B0, 0x59B3, 0x59B7, 0x59BA,
+ 0x59BC, 0x59C1, 0x59C3, 0x59C4, 0x59C8, 0x59CA, 0x59CD, 0x59D2,
+ 0x59DD, 0x59DE, 0x59DF, 0x59E3, 0x59E4, 0x59E7, 0x59EE, 0x59EF,
+ 0x59F1, 0x59F2, 0x59F4, 0x59F7, 0x5A00, 0x5A04, 0x5A0C, 0x5A0D,
+ 0x5A0E, 0x5A12, 0x5A13, 0x5A1E, 0x5A23, 0x5A24, 0x5A27, 0x5A28,
+ 0x5A2A, 0x5A2D, 0x5A30, 0x5A44, 0x5A45, 0x5A47, 0x5A48, 0x5A4C,
+ 0x5A50, 0x5A55, 0x5A5E, 0x5A63, 0x5A65, 0x5A67, 0x5A6D, 0x5A77,
+ 0x5A7A, 0x5A7B, 0x5A7E, 0x5A8B, 0x5A90, 0x5A93, 0x5A96, 0x5A99,
+ 0x5A9C, 0x5A9E, 0x5A9F, 0x5AA0, 0x5AA2, 0x5AA7, 0x5AAC, 0x5AB1,
+ 0x5AB2, 0x5AB3, 0x5AB5, 0x5AB8, 0x5ABA, 0x5ABB, 0x5ABF,
+};
+static const unsigned short euc_to_utf8_8FBA[] = {
+ 0x5AC4, 0x5AC6, 0x5AC8, 0x5ACF, 0x5ADA, 0x5ADC, 0x5AE0,
+ 0x5AE5, 0x5AEA, 0x5AEE, 0x5AF5, 0x5AF6, 0x5AFD, 0x5B00, 0x5B01,
+ 0x5B08, 0x5B17, 0x5B34, 0x5B19, 0x5B1B, 0x5B1D, 0x5B21, 0x5B25,
+ 0x5B2D, 0x5B38, 0x5B41, 0x5B4B, 0x5B4C, 0x5B52, 0x5B56, 0x5B5E,
+ 0x5B68, 0x5B6E, 0x5B6F, 0x5B7C, 0x5B7D, 0x5B7E, 0x5B7F, 0x5B81,
+ 0x5B84, 0x5B86, 0x5B8A, 0x5B8E, 0x5B90, 0x5B91, 0x5B93, 0x5B94,
+ 0x5B96, 0x5BA8, 0x5BA9, 0x5BAC, 0x5BAD, 0x5BAF, 0x5BB1, 0x5BB2,
+ 0x5BB7, 0x5BBA, 0x5BBC, 0x5BC0, 0x5BC1, 0x5BCD, 0x5BCF, 0x5BD6,
+ 0x5BD7, 0x5BD8, 0x5BD9, 0x5BDA, 0x5BE0, 0x5BEF, 0x5BF1, 0x5BF4,
+ 0x5BFD, 0x5C0C, 0x5C17, 0x5C1E, 0x5C1F, 0x5C23, 0x5C26, 0x5C29,
+ 0x5C2B, 0x5C2C, 0x5C2E, 0x5C30, 0x5C32, 0x5C35, 0x5C36, 0x5C59,
+ 0x5C5A, 0x5C5C, 0x5C62, 0x5C63, 0x5C67, 0x5C68, 0x5C69,
+};
+static const unsigned short euc_to_utf8_8FBB[] = {
+ 0x5C6D, 0x5C70, 0x5C74, 0x5C75, 0x5C7A, 0x5C7B, 0x5C7C,
+ 0x5C7D, 0x5C87, 0x5C88, 0x5C8A, 0x5C8F, 0x5C92, 0x5C9D, 0x5C9F,
+ 0x5CA0, 0x5CA2, 0x5CA3, 0x5CA6, 0x5CAA, 0x5CB2, 0x5CB4, 0x5CB5,
+ 0x5CBA, 0x5CC9, 0x5CCB, 0x5CD2, 0x5CDD, 0x5CD7, 0x5CEE, 0x5CF1,
+ 0x5CF2, 0x5CF4, 0x5D01, 0x5D06, 0x5D0D, 0x5D12, 0x5D2B, 0x5D23,
+ 0x5D24, 0x5D26, 0x5D27, 0x5D31, 0x5D34, 0x5D39, 0x5D3D, 0x5D3F,
+ 0x5D42, 0x5D43, 0x5D46, 0x5D48, 0x5D55, 0x5D51, 0x5D59, 0x5D4A,
+ 0x5D5F, 0x5D60, 0x5D61, 0x5D62, 0x5D64, 0x5D6A, 0x5D6D, 0x5D70,
+ 0x5D79, 0x5D7A, 0x5D7E, 0x5D7F, 0x5D81, 0x5D83, 0x5D88, 0x5D8A,
+ 0x5D92, 0x5D93, 0x5D94, 0x5D95, 0x5D99, 0x5D9B, 0x5D9F, 0x5DA0,
+ 0x5DA7, 0x5DAB, 0x5DB0, 0x5DB4, 0x5DB8, 0x5DB9, 0x5DC3, 0x5DC7,
+ 0x5DCB, 0x5DD0, 0x5DCE, 0x5DD8, 0x5DD9, 0x5DE0, 0x5DE4,
+};
+static const unsigned short euc_to_utf8_8FBC[] = {
+ 0x5DE9, 0x5DF8, 0x5DF9, 0x5E00, 0x5E07, 0x5E0D, 0x5E12,
+ 0x5E14, 0x5E15, 0x5E18, 0x5E1F, 0x5E20, 0x5E2E, 0x5E28, 0x5E32,
+ 0x5E35, 0x5E3E, 0x5E4B, 0x5E50, 0x5E49, 0x5E51, 0x5E56, 0x5E58,
+ 0x5E5B, 0x5E5C, 0x5E5E, 0x5E68, 0x5E6A, 0x5E6B, 0x5E6C, 0x5E6D,
+ 0x5E6E, 0x5E70, 0x5E80, 0x5E8B, 0x5E8E, 0x5EA2, 0x5EA4, 0x5EA5,
+ 0x5EA8, 0x5EAA, 0x5EAC, 0x5EB1, 0x5EB3, 0x5EBD, 0x5EBE, 0x5EBF,
+ 0x5EC6, 0x5ECC, 0x5ECB, 0x5ECE, 0x5ED1, 0x5ED2, 0x5ED4, 0x5ED5,
+ 0x5EDC, 0x5EDE, 0x5EE5, 0x5EEB, 0x5F02, 0x5F06, 0x5F07, 0x5F08,
+ 0x5F0E, 0x5F19, 0x5F1C, 0x5F1D, 0x5F21, 0x5F22, 0x5F23, 0x5F24,
+ 0x5F28, 0x5F2B, 0x5F2C, 0x5F2E, 0x5F30, 0x5F34, 0x5F36, 0x5F3B,
+ 0x5F3D, 0x5F3F, 0x5F40, 0x5F44, 0x5F45, 0x5F47, 0x5F4D, 0x5F50,
+ 0x5F54, 0x5F58, 0x5F5B, 0x5F60, 0x5F63, 0x5F64, 0x5F67,
+};
+static const unsigned short euc_to_utf8_8FBD[] = {
+ 0x5F6F, 0x5F72, 0x5F74, 0x5F75, 0x5F78, 0x5F7A, 0x5F7D,
+ 0x5F7E, 0x5F89, 0x5F8D, 0x5F8F, 0x5F96, 0x5F9C, 0x5F9D, 0x5FA2,
+ 0x5FA7, 0x5FAB, 0x5FA4, 0x5FAC, 0x5FAF, 0x5FB0, 0x5FB1, 0x5FB8,
+ 0x5FC4, 0x5FC7, 0x5FC8, 0x5FC9, 0x5FCB, 0x5FD0, 0x5FD1, 0x5FD2,
+ 0x5FD3, 0x5FD4, 0x5FDE, 0x5FE1, 0x5FE2, 0x5FE8, 0x5FE9, 0x5FEA,
+ 0x5FEC, 0x5FED, 0x5FEE, 0x5FEF, 0x5FF2, 0x5FF3, 0x5FF6, 0x5FFA,
+ 0x5FFC, 0x6007, 0x600A, 0x600D, 0x6013, 0x6014, 0x6017, 0x6018,
+ 0x601A, 0x601F, 0x6024, 0x602D, 0x6033, 0x6035, 0x6040, 0x6047,
+ 0x6048, 0x6049, 0x604C, 0x6051, 0x6054, 0x6056, 0x6057, 0x605D,
+ 0x6061, 0x6067, 0x6071, 0x607E, 0x607F, 0x6082, 0x6086, 0x6088,
+ 0x608A, 0x608E, 0x6091, 0x6093, 0x6095, 0x6098, 0x609D, 0x609E,
+ 0x60A2, 0x60A4, 0x60A5, 0x60A8, 0x60B0, 0x60B1, 0x60B7,
+};
+static const unsigned short euc_to_utf8_8FBE[] = {
+ 0x60BB, 0x60BE, 0x60C2, 0x60C4, 0x60C8, 0x60C9, 0x60CA,
+ 0x60CB, 0x60CE, 0x60CF, 0x60D4, 0x60D5, 0x60D9, 0x60DB, 0x60DD,
+ 0x60DE, 0x60E2, 0x60E5, 0x60F2, 0x60F5, 0x60F8, 0x60FC, 0x60FD,
+ 0x6102, 0x6107, 0x610A, 0x610C, 0x6110, 0x6111, 0x6112, 0x6113,
+ 0x6114, 0x6116, 0x6117, 0x6119, 0x611C, 0x611E, 0x6122, 0x612A,
+ 0x612B, 0x6130, 0x6131, 0x6135, 0x6136, 0x6137, 0x6139, 0x6141,
+ 0x6145, 0x6146, 0x6149, 0x615E, 0x6160, 0x616C, 0x6172, 0x6178,
+ 0x617B, 0x617C, 0x617F, 0x6180, 0x6181, 0x6183, 0x6184, 0x618B,
+ 0x618D, 0x6192, 0x6193, 0x6197, 0x6198, 0x619C, 0x619D, 0x619F,
+ 0x61A0, 0x61A5, 0x61A8, 0x61AA, 0x61AD, 0x61B8, 0x61B9, 0x61BC,
+ 0x61C0, 0x61C1, 0x61C2, 0x61CE, 0x61CF, 0x61D5, 0x61DC, 0x61DD,
+ 0x61DE, 0x61DF, 0x61E1, 0x61E2, 0x61E7, 0x61E9, 0x61E5,
+};
+static const unsigned short euc_to_utf8_8FBF[] = {
+ 0x61EC, 0x61ED, 0x61EF, 0x6201, 0x6203, 0x6204, 0x6207,
+ 0x6213, 0x6215, 0x621C, 0x6220, 0x6222, 0x6223, 0x6227, 0x6229,
+ 0x622B, 0x6239, 0x623D, 0x6242, 0x6243, 0x6244, 0x6246, 0x624C,
+ 0x6250, 0x6251, 0x6252, 0x6254, 0x6256, 0x625A, 0x625C, 0x6264,
+ 0x626D, 0x626F, 0x6273, 0x627A, 0x627D, 0x628D, 0x628E, 0x628F,
+ 0x6290, 0x62A6, 0x62A8, 0x62B3, 0x62B6, 0x62B7, 0x62BA, 0x62BE,
+ 0x62BF, 0x62C4, 0x62CE, 0x62D5, 0x62D6, 0x62DA, 0x62EA, 0x62F2,
+ 0x62F4, 0x62FC, 0x62FD, 0x6303, 0x6304, 0x630A, 0x630B, 0x630D,
+ 0x6310, 0x6313, 0x6316, 0x6318, 0x6329, 0x632A, 0x632D, 0x6335,
+ 0x6336, 0x6339, 0x633C, 0x6341, 0x6342, 0x6343, 0x6344, 0x6346,
+ 0x634A, 0x634B, 0x634E, 0x6352, 0x6353, 0x6354, 0x6358, 0x635B,
+ 0x6365, 0x6366, 0x636C, 0x636D, 0x6371, 0x6374, 0x6375,
+};
+static const unsigned short euc_to_utf8_8FC0[] = {
+ 0x6378, 0x637C, 0x637D, 0x637F, 0x6382, 0x6384, 0x6387,
+ 0x638A, 0x6390, 0x6394, 0x6395, 0x6399, 0x639A, 0x639E, 0x63A4,
+ 0x63A6, 0x63AD, 0x63AE, 0x63AF, 0x63BD, 0x63C1, 0x63C5, 0x63C8,
+ 0x63CE, 0x63D1, 0x63D3, 0x63D4, 0x63D5, 0x63DC, 0x63E0, 0x63E5,
+ 0x63EA, 0x63EC, 0x63F2, 0x63F3, 0x63F5, 0x63F8, 0x63F9, 0x6409,
+ 0x640A, 0x6410, 0x6412, 0x6414, 0x6418, 0x641E, 0x6420, 0x6422,
+ 0x6424, 0x6425, 0x6429, 0x642A, 0x642F, 0x6430, 0x6435, 0x643D,
+ 0x643F, 0x644B, 0x644F, 0x6451, 0x6452, 0x6453, 0x6454, 0x645A,
+ 0x645B, 0x645C, 0x645D, 0x645F, 0x6460, 0x6461, 0x6463, 0x646D,
+ 0x6473, 0x6474, 0x647B, 0x647D, 0x6485, 0x6487, 0x648F, 0x6490,
+ 0x6491, 0x6498, 0x6499, 0x649B, 0x649D, 0x649F, 0x64A1, 0x64A3,
+ 0x64A6, 0x64A8, 0x64AC, 0x64B3, 0x64BD, 0x64BE, 0x64BF,
+};
+static const unsigned short euc_to_utf8_8FC1[] = {
+ 0x64C4, 0x64C9, 0x64CA, 0x64CB, 0x64CC, 0x64CE, 0x64D0,
+ 0x64D1, 0x64D5, 0x64D7, 0x64E4, 0x64E5, 0x64E9, 0x64EA, 0x64ED,
+ 0x64F0, 0x64F5, 0x64F7, 0x64FB, 0x64FF, 0x6501, 0x6504, 0x6508,
+ 0x6509, 0x650A, 0x650F, 0x6513, 0x6514, 0x6516, 0x6519, 0x651B,
+ 0x651E, 0x651F, 0x6522, 0x6526, 0x6529, 0x652E, 0x6531, 0x653A,
+ 0x653C, 0x653D, 0x6543, 0x6547, 0x6549, 0x6550, 0x6552, 0x6554,
+ 0x655F, 0x6560, 0x6567, 0x656B, 0x657A, 0x657D, 0x6581, 0x6585,
+ 0x658A, 0x6592, 0x6595, 0x6598, 0x659D, 0x65A0, 0x65A3, 0x65A6,
+ 0x65AE, 0x65B2, 0x65B3, 0x65B4, 0x65BF, 0x65C2, 0x65C8, 0x65C9,
+ 0x65CE, 0x65D0, 0x65D4, 0x65D6, 0x65D8, 0x65DF, 0x65F0, 0x65F2,
+ 0x65F4, 0x65F5, 0x65F9, 0x65FE, 0x65FF, 0x6600, 0x6604, 0x6608,
+ 0x6609, 0x660D, 0x6611, 0x6612, 0x6615, 0x6616, 0x661D,
+};
+static const unsigned short euc_to_utf8_8FC2[] = {
+ 0x661E, 0x6621, 0x6622, 0x6623, 0x6624, 0x6626, 0x6629,
+ 0x662A, 0x662B, 0x662C, 0x662E, 0x6630, 0x6631, 0x6633, 0x6639,
+ 0x6637, 0x6640, 0x6645, 0x6646, 0x664A, 0x664C, 0x6651, 0x664E,
+ 0x6657, 0x6658, 0x6659, 0x665B, 0x665C, 0x6660, 0x6661, 0x66FB,
+ 0x666A, 0x666B, 0x666C, 0x667E, 0x6673, 0x6675, 0x667F, 0x6677,
+ 0x6678, 0x6679, 0x667B, 0x6680, 0x667C, 0x668B, 0x668C, 0x668D,
+ 0x6690, 0x6692, 0x6699, 0x669A, 0x669B, 0x669C, 0x669F, 0x66A0,
+ 0x66A4, 0x66AD, 0x66B1, 0x66B2, 0x66B5, 0x66BB, 0x66BF, 0x66C0,
+ 0x66C2, 0x66C3, 0x66C8, 0x66CC, 0x66CE, 0x66CF, 0x66D4, 0x66DB,
+ 0x66DF, 0x66E8, 0x66EB, 0x66EC, 0x66EE, 0x66FA, 0x6705, 0x6707,
+ 0x670E, 0x6713, 0x6719, 0x671C, 0x6720, 0x6722, 0x6733, 0x673E,
+ 0x6745, 0x6747, 0x6748, 0x674C, 0x6754, 0x6755, 0x675D,
+};
+static const unsigned short euc_to_utf8_8FC3[] = {
+ 0x6766, 0x676C, 0x676E, 0x6774, 0x6776, 0x677B, 0x6781,
+ 0x6784, 0x678E, 0x678F, 0x6791, 0x6793, 0x6796, 0x6798, 0x6799,
+ 0x679B, 0x67B0, 0x67B1, 0x67B2, 0x67B5, 0x67BB, 0x67BC, 0x67BD,
+ 0x67F9, 0x67C0, 0x67C2, 0x67C3, 0x67C5, 0x67C8, 0x67C9, 0x67D2,
+ 0x67D7, 0x67D9, 0x67DC, 0x67E1, 0x67E6, 0x67F0, 0x67F2, 0x67F6,
+ 0x67F7, 0x6852, 0x6814, 0x6819, 0x681D, 0x681F, 0x6828, 0x6827,
+ 0x682C, 0x682D, 0x682F, 0x6830, 0x6831, 0x6833, 0x683B, 0x683F,
+ 0x6844, 0x6845, 0x684A, 0x684C, 0x6855, 0x6857, 0x6858, 0x685B,
+ 0x686B, 0x686E, 0x686F, 0x6870, 0x6871, 0x6872, 0x6875, 0x6879,
+ 0x687A, 0x687B, 0x687C, 0x6882, 0x6884, 0x6886, 0x6888, 0x6896,
+ 0x6898, 0x689A, 0x689C, 0x68A1, 0x68A3, 0x68A5, 0x68A9, 0x68AA,
+ 0x68AE, 0x68B2, 0x68BB, 0x68C5, 0x68C8, 0x68CC, 0x68CF,
+};
+static const unsigned short euc_to_utf8_8FC4[] = {
+ 0x68D0, 0x68D1, 0x68D3, 0x68D6, 0x68D9, 0x68DC, 0x68DD,
+ 0x68E5, 0x68E8, 0x68EA, 0x68EB, 0x68EC, 0x68ED, 0x68F0, 0x68F1,
+ 0x68F5, 0x68F6, 0x68FB, 0x68FC, 0x68FD, 0x6906, 0x6909, 0x690A,
+ 0x6910, 0x6911, 0x6913, 0x6916, 0x6917, 0x6931, 0x6933, 0x6935,
+ 0x6938, 0x693B, 0x6942, 0x6945, 0x6949, 0x694E, 0x6957, 0x695B,
+ 0x6963, 0x6964, 0x6965, 0x6966, 0x6968, 0x6969, 0x696C, 0x6970,
+ 0x6971, 0x6972, 0x697A, 0x697B, 0x697F, 0x6980, 0x698D, 0x6992,
+ 0x6996, 0x6998, 0x69A1, 0x69A5, 0x69A6, 0x69A8, 0x69AB, 0x69AD,
+ 0x69AF, 0x69B7, 0x69B8, 0x69BA, 0x69BC, 0x69C5, 0x69C8, 0x69D1,
+ 0x69D6, 0x69D7, 0x69E2, 0x69E5, 0x69EE, 0x69EF, 0x69F1, 0x69F3,
+ 0x69F5, 0x69FE, 0x6A00, 0x6A01, 0x6A03, 0x6A0F, 0x6A11, 0x6A15,
+ 0x6A1A, 0x6A1D, 0x6A20, 0x6A24, 0x6A28, 0x6A30, 0x6A32,
+};
+static const unsigned short euc_to_utf8_8FC5[] = {
+ 0x6A34, 0x6A37, 0x6A3B, 0x6A3E, 0x6A3F, 0x6A45, 0x6A46,
+ 0x6A49, 0x6A4A, 0x6A4E, 0x6A50, 0x6A51, 0x6A52, 0x6A55, 0x6A56,
+ 0x6A5B, 0x6A64, 0x6A67, 0x6A6A, 0x6A71, 0x6A73, 0x6A7E, 0x6A81,
+ 0x6A83, 0x6A86, 0x6A87, 0x6A89, 0x6A8B, 0x6A91, 0x6A9B, 0x6A9D,
+ 0x6A9E, 0x6A9F, 0x6AA5, 0x6AAB, 0x6AAF, 0x6AB0, 0x6AB1, 0x6AB4,
+ 0x6ABD, 0x6ABE, 0x6ABF, 0x6AC6, 0x6AC9, 0x6AC8, 0x6ACC, 0x6AD0,
+ 0x6AD4, 0x6AD5, 0x6AD6, 0x6ADC, 0x6ADD, 0x6AE4, 0x6AE7, 0x6AEC,
+ 0x6AF0, 0x6AF1, 0x6AF2, 0x6AFC, 0x6AFD, 0x6B02, 0x6B03, 0x6B06,
+ 0x6B07, 0x6B09, 0x6B0F, 0x6B10, 0x6B11, 0x6B17, 0x6B1B, 0x6B1E,
+ 0x6B24, 0x6B28, 0x6B2B, 0x6B2C, 0x6B2F, 0x6B35, 0x6B36, 0x6B3B,
+ 0x6B3F, 0x6B46, 0x6B4A, 0x6B4D, 0x6B52, 0x6B56, 0x6B58, 0x6B5D,
+ 0x6B60, 0x6B67, 0x6B6B, 0x6B6E, 0x6B70, 0x6B75, 0x6B7D,
+};
+static const unsigned short euc_to_utf8_8FC6[] = {
+ 0x6B7E, 0x6B82, 0x6B85, 0x6B97, 0x6B9B, 0x6B9F, 0x6BA0,
+ 0x6BA2, 0x6BA3, 0x6BA8, 0x6BA9, 0x6BAC, 0x6BAD, 0x6BAE, 0x6BB0,
+ 0x6BB8, 0x6BB9, 0x6BBD, 0x6BBE, 0x6BC3, 0x6BC4, 0x6BC9, 0x6BCC,
+ 0x6BD6, 0x6BDA, 0x6BE1, 0x6BE3, 0x6BE6, 0x6BE7, 0x6BEE, 0x6BF1,
+ 0x6BF7, 0x6BF9, 0x6BFF, 0x6C02, 0x6C04, 0x6C05, 0x6C09, 0x6C0D,
+ 0x6C0E, 0x6C10, 0x6C12, 0x6C19, 0x6C1F, 0x6C26, 0x6C27, 0x6C28,
+ 0x6C2C, 0x6C2E, 0x6C33, 0x6C35, 0x6C36, 0x6C3A, 0x6C3B, 0x6C3F,
+ 0x6C4A, 0x6C4B, 0x6C4D, 0x6C4F, 0x6C52, 0x6C54, 0x6C59, 0x6C5B,
+ 0x6C5C, 0x6C6B, 0x6C6D, 0x6C6F, 0x6C74, 0x6C76, 0x6C78, 0x6C79,
+ 0x6C7B, 0x6C85, 0x6C86, 0x6C87, 0x6C89, 0x6C94, 0x6C95, 0x6C97,
+ 0x6C98, 0x6C9C, 0x6C9F, 0x6CB0, 0x6CB2, 0x6CB4, 0x6CC2, 0x6CC6,
+ 0x6CCD, 0x6CCF, 0x6CD0, 0x6CD1, 0x6CD2, 0x6CD4, 0x6CD6,
+};
+static const unsigned short euc_to_utf8_8FC7[] = {
+ 0x6CDA, 0x6CDC, 0x6CE0, 0x6CE7, 0x6CE9, 0x6CEB, 0x6CEC,
+ 0x6CEE, 0x6CF2, 0x6CF4, 0x6D04, 0x6D07, 0x6D0A, 0x6D0E, 0x6D0F,
+ 0x6D11, 0x6D13, 0x6D1A, 0x6D26, 0x6D27, 0x6D28, 0x6C67, 0x6D2E,
+ 0x6D2F, 0x6D31, 0x6D39, 0x6D3C, 0x6D3F, 0x6D57, 0x6D5E, 0x6D5F,
+ 0x6D61, 0x6D65, 0x6D67, 0x6D6F, 0x6D70, 0x6D7C, 0x6D82, 0x6D87,
+ 0x6D91, 0x6D92, 0x6D94, 0x6D96, 0x6D97, 0x6D98, 0x6DAA, 0x6DAC,
+ 0x6DB4, 0x6DB7, 0x6DB9, 0x6DBD, 0x6DBF, 0x6DC4, 0x6DC8, 0x6DCA,
+ 0x6DCE, 0x6DCF, 0x6DD6, 0x6DDB, 0x6DDD, 0x6DDF, 0x6DE0, 0x6DE2,
+ 0x6DE5, 0x6DE9, 0x6DEF, 0x6DF0, 0x6DF4, 0x6DF6, 0x6DFC, 0x6E00,
+ 0x6E04, 0x6E1E, 0x6E22, 0x6E27, 0x6E32, 0x6E36, 0x6E39, 0x6E3B,
+ 0x6E3C, 0x6E44, 0x6E45, 0x6E48, 0x6E49, 0x6E4B, 0x6E4F, 0x6E51,
+ 0x6E52, 0x6E53, 0x6E54, 0x6E57, 0x6E5C, 0x6E5D, 0x6E5E,
+};
+static const unsigned short euc_to_utf8_8FC8[] = {
+ 0x6E62, 0x6E63, 0x6E68, 0x6E73, 0x6E7B, 0x6E7D, 0x6E8D,
+ 0x6E93, 0x6E99, 0x6EA0, 0x6EA7, 0x6EAD, 0x6EAE, 0x6EB1, 0x6EB3,
+ 0x6EBB, 0x6EBF, 0x6EC0, 0x6EC1, 0x6EC3, 0x6EC7, 0x6EC8, 0x6ECA,
+ 0x6ECD, 0x6ECE, 0x6ECF, 0x6EEB, 0x6EED, 0x6EEE, 0x6EF9, 0x6EFB,
+ 0x6EFD, 0x6F04, 0x6F08, 0x6F0A, 0x6F0C, 0x6F0D, 0x6F16, 0x6F18,
+ 0x6F1A, 0x6F1B, 0x6F26, 0x6F29, 0x6F2A, 0x6F2F, 0x6F30, 0x6F33,
+ 0x6F36, 0x6F3B, 0x6F3C, 0x6F2D, 0x6F4F, 0x6F51, 0x6F52, 0x6F53,
+ 0x6F57, 0x6F59, 0x6F5A, 0x6F5D, 0x6F5E, 0x6F61, 0x6F62, 0x6F68,
+ 0x6F6C, 0x6F7D, 0x6F7E, 0x6F83, 0x6F87, 0x6F88, 0x6F8B, 0x6F8C,
+ 0x6F8D, 0x6F90, 0x6F92, 0x6F93, 0x6F94, 0x6F96, 0x6F9A, 0x6F9F,
+ 0x6FA0, 0x6FA5, 0x6FA6, 0x6FA7, 0x6FA8, 0x6FAE, 0x6FAF, 0x6FB0,
+ 0x6FB5, 0x6FB6, 0x6FBC, 0x6FC5, 0x6FC7, 0x6FC8, 0x6FCA,
+};
+static const unsigned short euc_to_utf8_8FC9[] = {
+ 0x6FDA, 0x6FDE, 0x6FE8, 0x6FE9, 0x6FF0, 0x6FF5, 0x6FF9,
+ 0x6FFC, 0x6FFD, 0x7000, 0x7005, 0x7006, 0x7007, 0x700D, 0x7017,
+ 0x7020, 0x7023, 0x702F, 0x7034, 0x7037, 0x7039, 0x703C, 0x7043,
+ 0x7044, 0x7048, 0x7049, 0x704A, 0x704B, 0x7054, 0x7055, 0x705D,
+ 0x705E, 0x704E, 0x7064, 0x7065, 0x706C, 0x706E, 0x7075, 0x7076,
+ 0x707E, 0x7081, 0x7085, 0x7086, 0x7094, 0x7095, 0x7096, 0x7097,
+ 0x7098, 0x709B, 0x70A4, 0x70AB, 0x70B0, 0x70B1, 0x70B4, 0x70B7,
+ 0x70CA, 0x70D1, 0x70D3, 0x70D4, 0x70D5, 0x70D6, 0x70D8, 0x70DC,
+ 0x70E4, 0x70FA, 0x7103, 0x7104, 0x7105, 0x7106, 0x7107, 0x710B,
+ 0x710C, 0x710F, 0x711E, 0x7120, 0x712B, 0x712D, 0x712F, 0x7130,
+ 0x7131, 0x7138, 0x7141, 0x7145, 0x7146, 0x7147, 0x714A, 0x714B,
+ 0x7150, 0x7152, 0x7157, 0x715A, 0x715C, 0x715E, 0x7160,
+};
+static const unsigned short euc_to_utf8_8FCA[] = {
+ 0x7168, 0x7179, 0x7180, 0x7185, 0x7187, 0x718C, 0x7192,
+ 0x719A, 0x719B, 0x71A0, 0x71A2, 0x71AF, 0x71B0, 0x71B2, 0x71B3,
+ 0x71BA, 0x71BF, 0x71C0, 0x71C1, 0x71C4, 0x71CB, 0x71CC, 0x71D3,
+ 0x71D6, 0x71D9, 0x71DA, 0x71DC, 0x71F8, 0x71FE, 0x7200, 0x7207,
+ 0x7208, 0x7209, 0x7213, 0x7217, 0x721A, 0x721D, 0x721F, 0x7224,
+ 0x722B, 0x722F, 0x7234, 0x7238, 0x7239, 0x7241, 0x7242, 0x7243,
+ 0x7245, 0x724E, 0x724F, 0x7250, 0x7253, 0x7255, 0x7256, 0x725A,
+ 0x725C, 0x725E, 0x7260, 0x7263, 0x7268, 0x726B, 0x726E, 0x726F,
+ 0x7271, 0x7277, 0x7278, 0x727B, 0x727C, 0x727F, 0x7284, 0x7289,
+ 0x728D, 0x728E, 0x7293, 0x729B, 0x72A8, 0x72AD, 0x72AE, 0x72B1,
+ 0x72B4, 0x72BE, 0x72C1, 0x72C7, 0x72C9, 0x72CC, 0x72D5, 0x72D6,
+ 0x72D8, 0x72DF, 0x72E5, 0x72F3, 0x72F4, 0x72FA, 0x72FB,
+};
+static const unsigned short euc_to_utf8_8FCB[] = {
+ 0x72FE, 0x7302, 0x7304, 0x7305, 0x7307, 0x730B, 0x730D,
+ 0x7312, 0x7313, 0x7318, 0x7319, 0x731E, 0x7322, 0x7324, 0x7327,
+ 0x7328, 0x732C, 0x7331, 0x7332, 0x7335, 0x733A, 0x733B, 0x733D,
+ 0x7343, 0x734D, 0x7350, 0x7352, 0x7356, 0x7358, 0x735D, 0x735E,
+ 0x735F, 0x7360, 0x7366, 0x7367, 0x7369, 0x736B, 0x736C, 0x736E,
+ 0x736F, 0x7371, 0x7377, 0x7379, 0x737C, 0x7380, 0x7381, 0x7383,
+ 0x7385, 0x7386, 0x738E, 0x7390, 0x7393, 0x7395, 0x7397, 0x7398,
+ 0x739C, 0x739E, 0x739F, 0x73A0, 0x73A2, 0x73A5, 0x73A6, 0x73AA,
+ 0x73AB, 0x73AD, 0x73B5, 0x73B7, 0x73B9, 0x73BC, 0x73BD, 0x73BF,
+ 0x73C5, 0x73C6, 0x73C9, 0x73CB, 0x73CC, 0x73CF, 0x73D2, 0x73D3,
+ 0x73D6, 0x73D9, 0x73DD, 0x73E1, 0x73E3, 0x73E6, 0x73E7, 0x73E9,
+ 0x73F4, 0x73F5, 0x73F7, 0x73F9, 0x73FA, 0x73FB, 0x73FD,
+};
+static const unsigned short euc_to_utf8_8FCC[] = {
+ 0x73FF, 0x7400, 0x7401, 0x7404, 0x7407, 0x740A, 0x7411,
+ 0x741A, 0x741B, 0x7424, 0x7426, 0x7428, 0x7429, 0x742A, 0x742B,
+ 0x742C, 0x742D, 0x742E, 0x742F, 0x7430, 0x7431, 0x7439, 0x7440,
+ 0x7443, 0x7444, 0x7446, 0x7447, 0x744B, 0x744D, 0x7451, 0x7452,
+ 0x7457, 0x745D, 0x7462, 0x7466, 0x7467, 0x7468, 0x746B, 0x746D,
+ 0x746E, 0x7471, 0x7472, 0x7480, 0x7481, 0x7485, 0x7486, 0x7487,
+ 0x7489, 0x748F, 0x7490, 0x7491, 0x7492, 0x7498, 0x7499, 0x749A,
+ 0x749C, 0x749F, 0x74A0, 0x74A1, 0x74A3, 0x74A6, 0x74A8, 0x74A9,
+ 0x74AA, 0x74AB, 0x74AE, 0x74AF, 0x74B1, 0x74B2, 0x74B5, 0x74B9,
+ 0x74BB, 0x74BF, 0x74C8, 0x74C9, 0x74CC, 0x74D0, 0x74D3, 0x74D8,
+ 0x74DA, 0x74DB, 0x74DE, 0x74DF, 0x74E4, 0x74E8, 0x74EA, 0x74EB,
+ 0x74EF, 0x74F4, 0x74FA, 0x74FB, 0x74FC, 0x74FF, 0x7506,
+};
+static const unsigned short euc_to_utf8_8FCD[] = {
+ 0x7512, 0x7516, 0x7517, 0x7520, 0x7521, 0x7524, 0x7527,
+ 0x7529, 0x752A, 0x752F, 0x7536, 0x7539, 0x753D, 0x753E, 0x753F,
+ 0x7540, 0x7543, 0x7547, 0x7548, 0x754E, 0x7550, 0x7552, 0x7557,
+ 0x755E, 0x755F, 0x7561, 0x756F, 0x7571, 0x7579, 0x757A, 0x757B,
+ 0x757C, 0x757D, 0x757E, 0x7581, 0x7585, 0x7590, 0x7592, 0x7593,
+ 0x7595, 0x7599, 0x759C, 0x75A2, 0x75A4, 0x75B4, 0x75BA, 0x75BF,
+ 0x75C0, 0x75C1, 0x75C4, 0x75C6, 0x75CC, 0x75CE, 0x75CF, 0x75D7,
+ 0x75DC, 0x75DF, 0x75E0, 0x75E1, 0x75E4, 0x75E7, 0x75EC, 0x75EE,
+ 0x75EF, 0x75F1, 0x75F9, 0x7600, 0x7602, 0x7603, 0x7604, 0x7607,
+ 0x7608, 0x760A, 0x760C, 0x760F, 0x7612, 0x7613, 0x7615, 0x7616,
+ 0x7619, 0x761B, 0x761C, 0x761D, 0x761E, 0x7623, 0x7625, 0x7626,
+ 0x7629, 0x762D, 0x7632, 0x7633, 0x7635, 0x7638, 0x7639,
+};
+static const unsigned short euc_to_utf8_8FCE[] = {
+ 0x763A, 0x763C, 0x764A, 0x7640, 0x7641, 0x7643, 0x7644,
+ 0x7645, 0x7649, 0x764B, 0x7655, 0x7659, 0x765F, 0x7664, 0x7665,
+ 0x766D, 0x766E, 0x766F, 0x7671, 0x7674, 0x7681, 0x7685, 0x768C,
+ 0x768D, 0x7695, 0x769B, 0x769C, 0x769D, 0x769F, 0x76A0, 0x76A2,
+ 0x76A3, 0x76A4, 0x76A5, 0x76A6, 0x76A7, 0x76A8, 0x76AA, 0x76AD,
+ 0x76BD, 0x76C1, 0x76C5, 0x76C9, 0x76CB, 0x76CC, 0x76CE, 0x76D4,
+ 0x76D9, 0x76E0, 0x76E6, 0x76E8, 0x76EC, 0x76F0, 0x76F1, 0x76F6,
+ 0x76F9, 0x76FC, 0x7700, 0x7706, 0x770A, 0x770E, 0x7712, 0x7714,
+ 0x7715, 0x7717, 0x7719, 0x771A, 0x771C, 0x7722, 0x7728, 0x772D,
+ 0x772E, 0x772F, 0x7734, 0x7735, 0x7736, 0x7739, 0x773D, 0x773E,
+ 0x7742, 0x7745, 0x7746, 0x774A, 0x774D, 0x774E, 0x774F, 0x7752,
+ 0x7756, 0x7757, 0x775C, 0x775E, 0x775F, 0x7760, 0x7762,
+};
+static const unsigned short euc_to_utf8_8FCF[] = {
+ 0x7764, 0x7767, 0x776A, 0x776C, 0x7770, 0x7772, 0x7773,
+ 0x7774, 0x777A, 0x777D, 0x7780, 0x7784, 0x778C, 0x778D, 0x7794,
+ 0x7795, 0x7796, 0x779A, 0x779F, 0x77A2, 0x77A7, 0x77AA, 0x77AE,
+ 0x77AF, 0x77B1, 0x77B5, 0x77BE, 0x77C3, 0x77C9, 0x77D1, 0x77D2,
+ 0x77D5, 0x77D9, 0x77DE, 0x77DF, 0x77E0, 0x77E4, 0x77E6, 0x77EA,
+ 0x77EC, 0x77F0, 0x77F1, 0x77F4, 0x77F8, 0x77FB, 0x7805, 0x7806,
+ 0x7809, 0x780D, 0x780E, 0x7811, 0x781D, 0x7821, 0x7822, 0x7823,
+ 0x782D, 0x782E, 0x7830, 0x7835, 0x7837, 0x7843, 0x7844, 0x7847,
+ 0x7848, 0x784C, 0x784E, 0x7852, 0x785C, 0x785E, 0x7860, 0x7861,
+ 0x7863, 0x7864, 0x7868, 0x786A, 0x786E, 0x787A, 0x787E, 0x788A,
+ 0x788F, 0x7894, 0x7898, 0x78A1, 0x789D, 0x789E, 0x789F, 0x78A4,
+ 0x78A8, 0x78AC, 0x78AD, 0x78B0, 0x78B1, 0x78B2, 0x78B3,
+};
+static const unsigned short euc_to_utf8_8FD0[] = {
+ 0x78BB, 0x78BD, 0x78BF, 0x78C7, 0x78C8, 0x78C9, 0x78CC,
+ 0x78CE, 0x78D2, 0x78D3, 0x78D5, 0x78D6, 0x78E4, 0x78DB, 0x78DF,
+ 0x78E0, 0x78E1, 0x78E6, 0x78EA, 0x78F2, 0x78F3, 0x7900, 0x78F6,
+ 0x78F7, 0x78FA, 0x78FB, 0x78FF, 0x7906, 0x790C, 0x7910, 0x791A,
+ 0x791C, 0x791E, 0x791F, 0x7920, 0x7925, 0x7927, 0x7929, 0x792D,
+ 0x7931, 0x7934, 0x7935, 0x793B, 0x793D, 0x793F, 0x7944, 0x7945,
+ 0x7946, 0x794A, 0x794B, 0x794F, 0x7951, 0x7954, 0x7958, 0x795B,
+ 0x795C, 0x7967, 0x7969, 0x796B, 0x7972, 0x7979, 0x797B, 0x797C,
+ 0x797E, 0x798B, 0x798C, 0x7991, 0x7993, 0x7994, 0x7995, 0x7996,
+ 0x7998, 0x799B, 0x799C, 0x79A1, 0x79A8, 0x79A9, 0x79AB, 0x79AF,
+ 0x79B1, 0x79B4, 0x79B8, 0x79BB, 0x79C2, 0x79C4, 0x79C7, 0x79C8,
+ 0x79CA, 0x79CF, 0x79D4, 0x79D6, 0x79DA, 0x79DD, 0x79DE,
+};
+static const unsigned short euc_to_utf8_8FD1[] = {
+ 0x79E0, 0x79E2, 0x79E5, 0x79EA, 0x79EB, 0x79ED, 0x79F1,
+ 0x79F8, 0x79FC, 0x7A02, 0x7A03, 0x7A07, 0x7A09, 0x7A0A, 0x7A0C,
+ 0x7A11, 0x7A15, 0x7A1B, 0x7A1E, 0x7A21, 0x7A27, 0x7A2B, 0x7A2D,
+ 0x7A2F, 0x7A30, 0x7A34, 0x7A35, 0x7A38, 0x7A39, 0x7A3A, 0x7A44,
+ 0x7A45, 0x7A47, 0x7A48, 0x7A4C, 0x7A55, 0x7A56, 0x7A59, 0x7A5C,
+ 0x7A5D, 0x7A5F, 0x7A60, 0x7A65, 0x7A67, 0x7A6A, 0x7A6D, 0x7A75,
+ 0x7A78, 0x7A7E, 0x7A80, 0x7A82, 0x7A85, 0x7A86, 0x7A8A, 0x7A8B,
+ 0x7A90, 0x7A91, 0x7A94, 0x7A9E, 0x7AA0, 0x7AA3, 0x7AAC, 0x7AB3,
+ 0x7AB5, 0x7AB9, 0x7ABB, 0x7ABC, 0x7AC6, 0x7AC9, 0x7ACC, 0x7ACE,
+ 0x7AD1, 0x7ADB, 0x7AE8, 0x7AE9, 0x7AEB, 0x7AEC, 0x7AF1, 0x7AF4,
+ 0x7AFB, 0x7AFD, 0x7AFE, 0x7B07, 0x7B14, 0x7B1F, 0x7B23, 0x7B27,
+ 0x7B29, 0x7B2A, 0x7B2B, 0x7B2D, 0x7B2E, 0x7B2F, 0x7B30,
+};
+static const unsigned short euc_to_utf8_8FD2[] = {
+ 0x7B31, 0x7B34, 0x7B3D, 0x7B3F, 0x7B40, 0x7B41, 0x7B47,
+ 0x7B4E, 0x7B55, 0x7B60, 0x7B64, 0x7B66, 0x7B69, 0x7B6A, 0x7B6D,
+ 0x7B6F, 0x7B72, 0x7B73, 0x7B77, 0x7B84, 0x7B89, 0x7B8E, 0x7B90,
+ 0x7B91, 0x7B96, 0x7B9B, 0x7B9E, 0x7BA0, 0x7BA5, 0x7BAC, 0x7BAF,
+ 0x7BB0, 0x7BB2, 0x7BB5, 0x7BB6, 0x7BBA, 0x7BBB, 0x7BBC, 0x7BBD,
+ 0x7BC2, 0x7BC5, 0x7BC8, 0x7BCA, 0x7BD4, 0x7BD6, 0x7BD7, 0x7BD9,
+ 0x7BDA, 0x7BDB, 0x7BE8, 0x7BEA, 0x7BF2, 0x7BF4, 0x7BF5, 0x7BF8,
+ 0x7BF9, 0x7BFA, 0x7BFC, 0x7BFE, 0x7C01, 0x7C02, 0x7C03, 0x7C04,
+ 0x7C06, 0x7C09, 0x7C0B, 0x7C0C, 0x7C0E, 0x7C0F, 0x7C19, 0x7C1B,
+ 0x7C20, 0x7C25, 0x7C26, 0x7C28, 0x7C2C, 0x7C31, 0x7C33, 0x7C34,
+ 0x7C36, 0x7C39, 0x7C3A, 0x7C46, 0x7C4A, 0x7C55, 0x7C51, 0x7C52,
+ 0x7C53, 0x7C59, 0x7C5A, 0x7C5B, 0x7C5C, 0x7C5D, 0x7C5E,
+};
+static const unsigned short euc_to_utf8_8FD3[] = {
+ 0x7C61, 0x7C63, 0x7C67, 0x7C69, 0x7C6D, 0x7C6E, 0x7C70,
+ 0x7C72, 0x7C79, 0x7C7C, 0x7C7D, 0x7C86, 0x7C87, 0x7C8F, 0x7C94,
+ 0x7C9E, 0x7CA0, 0x7CA6, 0x7CB0, 0x7CB6, 0x7CB7, 0x7CBA, 0x7CBB,
+ 0x7CBC, 0x7CBF, 0x7CC4, 0x7CC7, 0x7CC8, 0x7CC9, 0x7CCD, 0x7CCF,
+ 0x7CD3, 0x7CD4, 0x7CD5, 0x7CD7, 0x7CD9, 0x7CDA, 0x7CDD, 0x7CE6,
+ 0x7CE9, 0x7CEB, 0x7CF5, 0x7D03, 0x7D07, 0x7D08, 0x7D09, 0x7D0F,
+ 0x7D11, 0x7D12, 0x7D13, 0x7D16, 0x7D1D, 0x7D1E, 0x7D23, 0x7D26,
+ 0x7D2A, 0x7D2D, 0x7D31, 0x7D3C, 0x7D3D, 0x7D3E, 0x7D40, 0x7D41,
+ 0x7D47, 0x7D48, 0x7D4D, 0x7D51, 0x7D53, 0x7D57, 0x7D59, 0x7D5A,
+ 0x7D5C, 0x7D5D, 0x7D65, 0x7D67, 0x7D6A, 0x7D70, 0x7D78, 0x7D7A,
+ 0x7D7B, 0x7D7F, 0x7D81, 0x7D82, 0x7D83, 0x7D85, 0x7D86, 0x7D88,
+ 0x7D8B, 0x7D8C, 0x7D8D, 0x7D91, 0x7D96, 0x7D97, 0x7D9D,
+};
+static const unsigned short euc_to_utf8_8FD4[] = {
+ 0x7D9E, 0x7DA6, 0x7DA7, 0x7DAA, 0x7DB3, 0x7DB6, 0x7DB7,
+ 0x7DB9, 0x7DC2, 0x7DC3, 0x7DC4, 0x7DC5, 0x7DC6, 0x7DCC, 0x7DCD,
+ 0x7DCE, 0x7DD7, 0x7DD9, 0x7E00, 0x7DE2, 0x7DE5, 0x7DE6, 0x7DEA,
+ 0x7DEB, 0x7DED, 0x7DF1, 0x7DF5, 0x7DF6, 0x7DF9, 0x7DFA, 0x7E08,
+ 0x7E10, 0x7E11, 0x7E15, 0x7E17, 0x7E1C, 0x7E1D, 0x7E20, 0x7E27,
+ 0x7E28, 0x7E2C, 0x7E2D, 0x7E2F, 0x7E33, 0x7E36, 0x7E3F, 0x7E44,
+ 0x7E45, 0x7E47, 0x7E4E, 0x7E50, 0x7E52, 0x7E58, 0x7E5F, 0x7E61,
+ 0x7E62, 0x7E65, 0x7E6B, 0x7E6E, 0x7E6F, 0x7E73, 0x7E78, 0x7E7E,
+ 0x7E81, 0x7E86, 0x7E87, 0x7E8A, 0x7E8D, 0x7E91, 0x7E95, 0x7E98,
+ 0x7E9A, 0x7E9D, 0x7E9E, 0x7F3C, 0x7F3B, 0x7F3D, 0x7F3E, 0x7F3F,
+ 0x7F43, 0x7F44, 0x7F47, 0x7F4F, 0x7F52, 0x7F53, 0x7F5B, 0x7F5C,
+ 0x7F5D, 0x7F61, 0x7F63, 0x7F64, 0x7F65, 0x7F66, 0x7F6D,
+};
+static const unsigned short euc_to_utf8_8FD5[] = {
+ 0x7F71, 0x7F7D, 0x7F7E, 0x7F7F, 0x7F80, 0x7F8B, 0x7F8D,
+ 0x7F8F, 0x7F90, 0x7F91, 0x7F96, 0x7F97, 0x7F9C, 0x7FA1, 0x7FA2,
+ 0x7FA6, 0x7FAA, 0x7FAD, 0x7FB4, 0x7FBC, 0x7FBF, 0x7FC0, 0x7FC3,
+ 0x7FC8, 0x7FCE, 0x7FCF, 0x7FDB, 0x7FDF, 0x7FE3, 0x7FE5, 0x7FE8,
+ 0x7FEC, 0x7FEE, 0x7FEF, 0x7FF2, 0x7FFA, 0x7FFD, 0x7FFE, 0x7FFF,
+ 0x8007, 0x8008, 0x800A, 0x800D, 0x800E, 0x800F, 0x8011, 0x8013,
+ 0x8014, 0x8016, 0x801D, 0x801E, 0x801F, 0x8020, 0x8024, 0x8026,
+ 0x802C, 0x802E, 0x8030, 0x8034, 0x8035, 0x8037, 0x8039, 0x803A,
+ 0x803C, 0x803E, 0x8040, 0x8044, 0x8060, 0x8064, 0x8066, 0x806D,
+ 0x8071, 0x8075, 0x8081, 0x8088, 0x808E, 0x809C, 0x809E, 0x80A6,
+ 0x80A7, 0x80AB, 0x80B8, 0x80B9, 0x80C8, 0x80CD, 0x80CF, 0x80D2,
+ 0x80D4, 0x80D5, 0x80D7, 0x80D8, 0x80E0, 0x80ED, 0x80EE,
+};
+static const unsigned short euc_to_utf8_8FD6[] = {
+ 0x80F0, 0x80F2, 0x80F3, 0x80F6, 0x80F9, 0x80FA, 0x80FE,
+ 0x8103, 0x810B, 0x8116, 0x8117, 0x8118, 0x811C, 0x811E, 0x8120,
+ 0x8124, 0x8127, 0x812C, 0x8130, 0x8135, 0x813A, 0x813C, 0x8145,
+ 0x8147, 0x814A, 0x814C, 0x8152, 0x8157, 0x8160, 0x8161, 0x8167,
+ 0x8168, 0x8169, 0x816D, 0x816F, 0x8177, 0x8181, 0x8190, 0x8184,
+ 0x8185, 0x8186, 0x818B, 0x818E, 0x8196, 0x8198, 0x819B, 0x819E,
+ 0x81A2, 0x81AE, 0x81B2, 0x81B4, 0x81BB, 0x81CB, 0x81C3, 0x81C5,
+ 0x81CA, 0x81CE, 0x81CF, 0x81D5, 0x81D7, 0x81DB, 0x81DD, 0x81DE,
+ 0x81E1, 0x81E4, 0x81EB, 0x81EC, 0x81F0, 0x81F1, 0x81F2, 0x81F5,
+ 0x81F6, 0x81F8, 0x81F9, 0x81FD, 0x81FF, 0x8200, 0x8203, 0x820F,
+ 0x8213, 0x8214, 0x8219, 0x821A, 0x821D, 0x8221, 0x8222, 0x8228,
+ 0x8232, 0x8234, 0x823A, 0x8243, 0x8244, 0x8245, 0x8246,
+};
+static const unsigned short euc_to_utf8_8FD7[] = {
+ 0x824B, 0x824E, 0x824F, 0x8251, 0x8256, 0x825C, 0x8260,
+ 0x8263, 0x8267, 0x826D, 0x8274, 0x827B, 0x827D, 0x827F, 0x8280,
+ 0x8281, 0x8283, 0x8284, 0x8287, 0x8289, 0x828A, 0x828E, 0x8291,
+ 0x8294, 0x8296, 0x8298, 0x829A, 0x829B, 0x82A0, 0x82A1, 0x82A3,
+ 0x82A4, 0x82A7, 0x82A8, 0x82A9, 0x82AA, 0x82AE, 0x82B0, 0x82B2,
+ 0x82B4, 0x82B7, 0x82BA, 0x82BC, 0x82BE, 0x82BF, 0x82C6, 0x82D0,
+ 0x82D5, 0x82DA, 0x82E0, 0x82E2, 0x82E4, 0x82E8, 0x82EA, 0x82ED,
+ 0x82EF, 0x82F6, 0x82F7, 0x82FD, 0x82FE, 0x8300, 0x8301, 0x8307,
+ 0x8308, 0x830A, 0x830B, 0x8354, 0x831B, 0x831D, 0x831E, 0x831F,
+ 0x8321, 0x8322, 0x832C, 0x832D, 0x832E, 0x8330, 0x8333, 0x8337,
+ 0x833A, 0x833C, 0x833D, 0x8342, 0x8343, 0x8344, 0x8347, 0x834D,
+ 0x834E, 0x8351, 0x8355, 0x8356, 0x8357, 0x8370, 0x8378,
+};
+static const unsigned short euc_to_utf8_8FD8[] = {
+ 0x837D, 0x837F, 0x8380, 0x8382, 0x8384, 0x8386, 0x838D,
+ 0x8392, 0x8394, 0x8395, 0x8398, 0x8399, 0x839B, 0x839C, 0x839D,
+ 0x83A6, 0x83A7, 0x83A9, 0x83AC, 0x83BE, 0x83BF, 0x83C0, 0x83C7,
+ 0x83C9, 0x83CF, 0x83D0, 0x83D1, 0x83D4, 0x83DD, 0x8353, 0x83E8,
+ 0x83EA, 0x83F6, 0x83F8, 0x83F9, 0x83FC, 0x8401, 0x8406, 0x840A,
+ 0x840F, 0x8411, 0x8415, 0x8419, 0x83AD, 0x842F, 0x8439, 0x8445,
+ 0x8447, 0x8448, 0x844A, 0x844D, 0x844F, 0x8451, 0x8452, 0x8456,
+ 0x8458, 0x8459, 0x845A, 0x845C, 0x8460, 0x8464, 0x8465, 0x8467,
+ 0x846A, 0x8470, 0x8473, 0x8474, 0x8476, 0x8478, 0x847C, 0x847D,
+ 0x8481, 0x8485, 0x8492, 0x8493, 0x8495, 0x849E, 0x84A6, 0x84A8,
+ 0x84A9, 0x84AA, 0x84AF, 0x84B1, 0x84B4, 0x84BA, 0x84BD, 0x84BE,
+ 0x84C0, 0x84C2, 0x84C7, 0x84C8, 0x84CC, 0x84CF, 0x84D3,
+};
+static const unsigned short euc_to_utf8_8FD9[] = {
+ 0x84DC, 0x84E7, 0x84EA, 0x84EF, 0x84F0, 0x84F1, 0x84F2,
+ 0x84F7, 0x8532, 0x84FA, 0x84FB, 0x84FD, 0x8502, 0x8503, 0x8507,
+ 0x850C, 0x850E, 0x8510, 0x851C, 0x851E, 0x8522, 0x8523, 0x8524,
+ 0x8525, 0x8527, 0x852A, 0x852B, 0x852F, 0x8533, 0x8534, 0x8536,
+ 0x853F, 0x8546, 0x854F, 0x8550, 0x8551, 0x8552, 0x8553, 0x8556,
+ 0x8559, 0x855C, 0x855D, 0x855E, 0x855F, 0x8560, 0x8561, 0x8562,
+ 0x8564, 0x856B, 0x856F, 0x8579, 0x857A, 0x857B, 0x857D, 0x857F,
+ 0x8581, 0x8585, 0x8586, 0x8589, 0x858B, 0x858C, 0x858F, 0x8593,
+ 0x8598, 0x859D, 0x859F, 0x85A0, 0x85A2, 0x85A5, 0x85A7, 0x85B4,
+ 0x85B6, 0x85B7, 0x85B8, 0x85BC, 0x85BD, 0x85BE, 0x85BF, 0x85C2,
+ 0x85C7, 0x85CA, 0x85CB, 0x85CE, 0x85AD, 0x85D8, 0x85DA, 0x85DF,
+ 0x85E0, 0x85E6, 0x85E8, 0x85ED, 0x85F3, 0x85F6, 0x85FC,
+};
+static const unsigned short euc_to_utf8_8FDA[] = {
+ 0x85FF, 0x8600, 0x8604, 0x8605, 0x860D, 0x860E, 0x8610,
+ 0x8611, 0x8612, 0x8618, 0x8619, 0x861B, 0x861E, 0x8621, 0x8627,
+ 0x8629, 0x8636, 0x8638, 0x863A, 0x863C, 0x863D, 0x8640, 0x8642,
+ 0x8646, 0x8652, 0x8653, 0x8656, 0x8657, 0x8658, 0x8659, 0x865D,
+ 0x8660, 0x8661, 0x8662, 0x8663, 0x8664, 0x8669, 0x866C, 0x866F,
+ 0x8675, 0x8676, 0x8677, 0x867A, 0x868D, 0x8691, 0x8696, 0x8698,
+ 0x869A, 0x869C, 0x86A1, 0x86A6, 0x86A7, 0x86A8, 0x86AD, 0x86B1,
+ 0x86B3, 0x86B4, 0x86B5, 0x86B7, 0x86B8, 0x86B9, 0x86BF, 0x86C0,
+ 0x86C1, 0x86C3, 0x86C5, 0x86D1, 0x86D2, 0x86D5, 0x86D7, 0x86DA,
+ 0x86DC, 0x86E0, 0x86E3, 0x86E5, 0x86E7, 0x8688, 0x86FA, 0x86FC,
+ 0x86FD, 0x8704, 0x8705, 0x8707, 0x870B, 0x870E, 0x870F, 0x8710,
+ 0x8713, 0x8714, 0x8719, 0x871E, 0x871F, 0x8721, 0x8723,
+};
+static const unsigned short euc_to_utf8_8FDB[] = {
+ 0x8728, 0x872E, 0x872F, 0x8731, 0x8732, 0x8739, 0x873A,
+ 0x873C, 0x873D, 0x873E, 0x8740, 0x8743, 0x8745, 0x874D, 0x8758,
+ 0x875D, 0x8761, 0x8764, 0x8765, 0x876F, 0x8771, 0x8772, 0x877B,
+ 0x8783, 0x8784, 0x8785, 0x8786, 0x8787, 0x8788, 0x8789, 0x878B,
+ 0x878C, 0x8790, 0x8793, 0x8795, 0x8797, 0x8798, 0x8799, 0x879E,
+ 0x87A0, 0x87A3, 0x87A7, 0x87AC, 0x87AD, 0x87AE, 0x87B1, 0x87B5,
+ 0x87BE, 0x87BF, 0x87C1, 0x87C8, 0x87C9, 0x87CA, 0x87CE, 0x87D5,
+ 0x87D6, 0x87D9, 0x87DA, 0x87DC, 0x87DF, 0x87E2, 0x87E3, 0x87E4,
+ 0x87EA, 0x87EB, 0x87ED, 0x87F1, 0x87F3, 0x87F8, 0x87FA, 0x87FF,
+ 0x8801, 0x8803, 0x8806, 0x8809, 0x880A, 0x880B, 0x8810, 0x8819,
+ 0x8812, 0x8813, 0x8814, 0x8818, 0x881A, 0x881B, 0x881C, 0x881E,
+ 0x881F, 0x8828, 0x882D, 0x882E, 0x8830, 0x8832, 0x8835,
+};
+static const unsigned short euc_to_utf8_8FDC[] = {
+ 0x883A, 0x883C, 0x8841, 0x8843, 0x8845, 0x8848, 0x8849,
+ 0x884A, 0x884B, 0x884E, 0x8851, 0x8855, 0x8856, 0x8858, 0x885A,
+ 0x885C, 0x885F, 0x8860, 0x8864, 0x8869, 0x8871, 0x8879, 0x887B,
+ 0x8880, 0x8898, 0x889A, 0x889B, 0x889C, 0x889F, 0x88A0, 0x88A8,
+ 0x88AA, 0x88BA, 0x88BD, 0x88BE, 0x88C0, 0x88CA, 0x88CB, 0x88CC,
+ 0x88CD, 0x88CE, 0x88D1, 0x88D2, 0x88D3, 0x88DB, 0x88DE, 0x88E7,
+ 0x88EF, 0x88F0, 0x88F1, 0x88F5, 0x88F7, 0x8901, 0x8906, 0x890D,
+ 0x890E, 0x890F, 0x8915, 0x8916, 0x8918, 0x8919, 0x891A, 0x891C,
+ 0x8920, 0x8926, 0x8927, 0x8928, 0x8930, 0x8931, 0x8932, 0x8935,
+ 0x8939, 0x893A, 0x893E, 0x8940, 0x8942, 0x8945, 0x8946, 0x8949,
+ 0x894F, 0x8952, 0x8957, 0x895A, 0x895B, 0x895C, 0x8961, 0x8962,
+ 0x8963, 0x896B, 0x896E, 0x8970, 0x8973, 0x8975, 0x897A,
+};
+static const unsigned short euc_to_utf8_8FDD[] = {
+ 0x897B, 0x897C, 0x897D, 0x8989, 0x898D, 0x8990, 0x8994,
+ 0x8995, 0x899B, 0x899C, 0x899F, 0x89A0, 0x89A5, 0x89B0, 0x89B4,
+ 0x89B5, 0x89B6, 0x89B7, 0x89BC, 0x89D4, 0x89D5, 0x89D6, 0x89D7,
+ 0x89D8, 0x89E5, 0x89E9, 0x89EB, 0x89ED, 0x89F1, 0x89F3, 0x89F6,
+ 0x89F9, 0x89FD, 0x89FF, 0x8A04, 0x8A05, 0x8A07, 0x8A0F, 0x8A11,
+ 0x8A12, 0x8A14, 0x8A15, 0x8A1E, 0x8A20, 0x8A22, 0x8A24, 0x8A26,
+ 0x8A2B, 0x8A2C, 0x8A2F, 0x8A35, 0x8A37, 0x8A3D, 0x8A3E, 0x8A40,
+ 0x8A43, 0x8A45, 0x8A47, 0x8A49, 0x8A4D, 0x8A4E, 0x8A53, 0x8A56,
+ 0x8A57, 0x8A58, 0x8A5C, 0x8A5D, 0x8A61, 0x8A65, 0x8A67, 0x8A75,
+ 0x8A76, 0x8A77, 0x8A79, 0x8A7A, 0x8A7B, 0x8A7E, 0x8A7F, 0x8A80,
+ 0x8A83, 0x8A86, 0x8A8B, 0x8A8F, 0x8A90, 0x8A92, 0x8A96, 0x8A97,
+ 0x8A99, 0x8A9F, 0x8AA7, 0x8AA9, 0x8AAE, 0x8AAF, 0x8AB3,
+};
+static const unsigned short euc_to_utf8_8FDE[] = {
+ 0x8AB6, 0x8AB7, 0x8ABB, 0x8ABE, 0x8AC3, 0x8AC6, 0x8AC8,
+ 0x8AC9, 0x8ACA, 0x8AD1, 0x8AD3, 0x8AD4, 0x8AD5, 0x8AD7, 0x8ADD,
+ 0x8ADF, 0x8AEC, 0x8AF0, 0x8AF4, 0x8AF5, 0x8AF6, 0x8AFC, 0x8AFF,
+ 0x8B05, 0x8B06, 0x8B0B, 0x8B11, 0x8B1C, 0x8B1E, 0x8B1F, 0x8B0A,
+ 0x8B2D, 0x8B30, 0x8B37, 0x8B3C, 0x8B42, 0x8B43, 0x8B44, 0x8B45,
+ 0x8B46, 0x8B48, 0x8B52, 0x8B53, 0x8B54, 0x8B59, 0x8B4D, 0x8B5E,
+ 0x8B63, 0x8B6D, 0x8B76, 0x8B78, 0x8B79, 0x8B7C, 0x8B7E, 0x8B81,
+ 0x8B84, 0x8B85, 0x8B8B, 0x8B8D, 0x8B8F, 0x8B94, 0x8B95, 0x8B9C,
+ 0x8B9E, 0x8B9F, 0x8C38, 0x8C39, 0x8C3D, 0x8C3E, 0x8C45, 0x8C47,
+ 0x8C49, 0x8C4B, 0x8C4F, 0x8C51, 0x8C53, 0x8C54, 0x8C57, 0x8C58,
+ 0x8C5B, 0x8C5D, 0x8C59, 0x8C63, 0x8C64, 0x8C66, 0x8C68, 0x8C69,
+ 0x8C6D, 0x8C73, 0x8C75, 0x8C76, 0x8C7B, 0x8C7E, 0x8C86,
+};
+static const unsigned short euc_to_utf8_8FDF[] = {
+ 0x8C87, 0x8C8B, 0x8C90, 0x8C92, 0x8C93, 0x8C99, 0x8C9B,
+ 0x8C9C, 0x8CA4, 0x8CB9, 0x8CBA, 0x8CC5, 0x8CC6, 0x8CC9, 0x8CCB,
+ 0x8CCF, 0x8CD6, 0x8CD5, 0x8CD9, 0x8CDD, 0x8CE1, 0x8CE8, 0x8CEC,
+ 0x8CEF, 0x8CF0, 0x8CF2, 0x8CF5, 0x8CF7, 0x8CF8, 0x8CFE, 0x8CFF,
+ 0x8D01, 0x8D03, 0x8D09, 0x8D12, 0x8D17, 0x8D1B, 0x8D65, 0x8D69,
+ 0x8D6C, 0x8D6E, 0x8D7F, 0x8D82, 0x8D84, 0x8D88, 0x8D8D, 0x8D90,
+ 0x8D91, 0x8D95, 0x8D9E, 0x8D9F, 0x8DA0, 0x8DA6, 0x8DAB, 0x8DAC,
+ 0x8DAF, 0x8DB2, 0x8DB5, 0x8DB7, 0x8DB9, 0x8DBB, 0x8DC0, 0x8DC5,
+ 0x8DC6, 0x8DC7, 0x8DC8, 0x8DCA, 0x8DCE, 0x8DD1, 0x8DD4, 0x8DD5,
+ 0x8DD7, 0x8DD9, 0x8DE4, 0x8DE5, 0x8DE7, 0x8DEC, 0x8DF0, 0x8DBC,
+ 0x8DF1, 0x8DF2, 0x8DF4, 0x8DFD, 0x8E01, 0x8E04, 0x8E05, 0x8E06,
+ 0x8E0B, 0x8E11, 0x8E14, 0x8E16, 0x8E20, 0x8E21, 0x8E22,
+};
+static const unsigned short euc_to_utf8_8FE0[] = {
+ 0x8E23, 0x8E26, 0x8E27, 0x8E31, 0x8E33, 0x8E36, 0x8E37,
+ 0x8E38, 0x8E39, 0x8E3D, 0x8E40, 0x8E41, 0x8E4B, 0x8E4D, 0x8E4E,
+ 0x8E4F, 0x8E54, 0x8E5B, 0x8E5C, 0x8E5D, 0x8E5E, 0x8E61, 0x8E62,
+ 0x8E69, 0x8E6C, 0x8E6D, 0x8E6F, 0x8E70, 0x8E71, 0x8E79, 0x8E7A,
+ 0x8E7B, 0x8E82, 0x8E83, 0x8E89, 0x8E90, 0x8E92, 0x8E95, 0x8E9A,
+ 0x8E9B, 0x8E9D, 0x8E9E, 0x8EA2, 0x8EA7, 0x8EA9, 0x8EAD, 0x8EAE,
+ 0x8EB3, 0x8EB5, 0x8EBA, 0x8EBB, 0x8EC0, 0x8EC1, 0x8EC3, 0x8EC4,
+ 0x8EC7, 0x8ECF, 0x8ED1, 0x8ED4, 0x8EDC, 0x8EE8, 0x8EEE, 0x8EF0,
+ 0x8EF1, 0x8EF7, 0x8EF9, 0x8EFA, 0x8EED, 0x8F00, 0x8F02, 0x8F07,
+ 0x8F08, 0x8F0F, 0x8F10, 0x8F16, 0x8F17, 0x8F18, 0x8F1E, 0x8F20,
+ 0x8F21, 0x8F23, 0x8F25, 0x8F27, 0x8F28, 0x8F2C, 0x8F2D, 0x8F2E,
+ 0x8F34, 0x8F35, 0x8F36, 0x8F37, 0x8F3A, 0x8F40, 0x8F41,
+};
+static const unsigned short euc_to_utf8_8FE1[] = {
+ 0x8F43, 0x8F47, 0x8F4F, 0x8F51, 0x8F52, 0x8F53, 0x8F54,
+ 0x8F55, 0x8F58, 0x8F5D, 0x8F5E, 0x8F65, 0x8F9D, 0x8FA0, 0x8FA1,
+ 0x8FA4, 0x8FA5, 0x8FA6, 0x8FB5, 0x8FB6, 0x8FB8, 0x8FBE, 0x8FC0,
+ 0x8FC1, 0x8FC6, 0x8FCA, 0x8FCB, 0x8FCD, 0x8FD0, 0x8FD2, 0x8FD3,
+ 0x8FD5, 0x8FE0, 0x8FE3, 0x8FE4, 0x8FE8, 0x8FEE, 0x8FF1, 0x8FF5,
+ 0x8FF6, 0x8FFB, 0x8FFE, 0x9002, 0x9004, 0x9008, 0x900C, 0x9018,
+ 0x901B, 0x9028, 0x9029, 0x902F, 0x902A, 0x902C, 0x902D, 0x9033,
+ 0x9034, 0x9037, 0x903F, 0x9043, 0x9044, 0x904C, 0x905B, 0x905D,
+ 0x9062, 0x9066, 0x9067, 0x906C, 0x9070, 0x9074, 0x9079, 0x9085,
+ 0x9088, 0x908B, 0x908C, 0x908E, 0x9090, 0x9095, 0x9097, 0x9098,
+ 0x9099, 0x909B, 0x90A0, 0x90A1, 0x90A2, 0x90A5, 0x90B0, 0x90B2,
+ 0x90B3, 0x90B4, 0x90B6, 0x90BD, 0x90CC, 0x90BE, 0x90C3,
+};
+static const unsigned short euc_to_utf8_8FE2[] = {
+ 0x90C4, 0x90C5, 0x90C7, 0x90C8, 0x90D5, 0x90D7, 0x90D8,
+ 0x90D9, 0x90DC, 0x90DD, 0x90DF, 0x90E5, 0x90D2, 0x90F6, 0x90EB,
+ 0x90EF, 0x90F0, 0x90F4, 0x90FE, 0x90FF, 0x9100, 0x9104, 0x9105,
+ 0x9106, 0x9108, 0x910D, 0x9110, 0x9114, 0x9116, 0x9117, 0x9118,
+ 0x911A, 0x911C, 0x911E, 0x9120, 0x9125, 0x9122, 0x9123, 0x9127,
+ 0x9129, 0x912E, 0x912F, 0x9131, 0x9134, 0x9136, 0x9137, 0x9139,
+ 0x913A, 0x913C, 0x913D, 0x9143, 0x9147, 0x9148, 0x914F, 0x9153,
+ 0x9157, 0x9159, 0x915A, 0x915B, 0x9161, 0x9164, 0x9167, 0x916D,
+ 0x9174, 0x9179, 0x917A, 0x917B, 0x9181, 0x9183, 0x9185, 0x9186,
+ 0x918A, 0x918E, 0x9191, 0x9193, 0x9194, 0x9195, 0x9198, 0x919E,
+ 0x91A1, 0x91A6, 0x91A8, 0x91AC, 0x91AD, 0x91AE, 0x91B0, 0x91B1,
+ 0x91B2, 0x91B3, 0x91B6, 0x91BB, 0x91BC, 0x91BD, 0x91BF,
+};
+static const unsigned short euc_to_utf8_8FE3[] = {
+ 0x91C2, 0x91C3, 0x91C5, 0x91D3, 0x91D4, 0x91D7, 0x91D9,
+ 0x91DA, 0x91DE, 0x91E4, 0x91E5, 0x91E9, 0x91EA, 0x91EC, 0x91ED,
+ 0x91EE, 0x91EF, 0x91F0, 0x91F1, 0x91F7, 0x91F9, 0x91FB, 0x91FD,
+ 0x9200, 0x9201, 0x9204, 0x9205, 0x9206, 0x9207, 0x9209, 0x920A,
+ 0x920C, 0x9210, 0x9212, 0x9213, 0x9216, 0x9218, 0x921C, 0x921D,
+ 0x9223, 0x9224, 0x9225, 0x9226, 0x9228, 0x922E, 0x922F, 0x9230,
+ 0x9233, 0x9235, 0x9236, 0x9238, 0x9239, 0x923A, 0x923C, 0x923E,
+ 0x9240, 0x9242, 0x9243, 0x9246, 0x9247, 0x924A, 0x924D, 0x924E,
+ 0x924F, 0x9251, 0x9258, 0x9259, 0x925C, 0x925D, 0x9260, 0x9261,
+ 0x9265, 0x9267, 0x9268, 0x9269, 0x926E, 0x926F, 0x9270, 0x9275,
+ 0x9276, 0x9277, 0x9278, 0x9279, 0x927B, 0x927C, 0x927D, 0x927F,
+ 0x9288, 0x9289, 0x928A, 0x928D, 0x928E, 0x9292, 0x9297,
+};
+static const unsigned short euc_to_utf8_8FE4[] = {
+ 0x9299, 0x929F, 0x92A0, 0x92A4, 0x92A5, 0x92A7, 0x92A8,
+ 0x92AB, 0x92AF, 0x92B2, 0x92B6, 0x92B8, 0x92BA, 0x92BB, 0x92BC,
+ 0x92BD, 0x92BF, 0x92C0, 0x92C1, 0x92C2, 0x92C3, 0x92C5, 0x92C6,
+ 0x92C7, 0x92C8, 0x92CB, 0x92CC, 0x92CD, 0x92CE, 0x92D0, 0x92D3,
+ 0x92D5, 0x92D7, 0x92D8, 0x92D9, 0x92DC, 0x92DD, 0x92DF, 0x92E0,
+ 0x92E1, 0x92E3, 0x92E5, 0x92E7, 0x92E8, 0x92EC, 0x92EE, 0x92F0,
+ 0x92F9, 0x92FB, 0x92FF, 0x9300, 0x9302, 0x9308, 0x930D, 0x9311,
+ 0x9314, 0x9315, 0x931C, 0x931D, 0x931E, 0x931F, 0x9321, 0x9324,
+ 0x9325, 0x9327, 0x9329, 0x932A, 0x9333, 0x9334, 0x9336, 0x9337,
+ 0x9347, 0x9348, 0x9349, 0x9350, 0x9351, 0x9352, 0x9355, 0x9357,
+ 0x9358, 0x935A, 0x935E, 0x9364, 0x9365, 0x9367, 0x9369, 0x936A,
+ 0x936D, 0x936F, 0x9370, 0x9371, 0x9373, 0x9374, 0x9376,
+};
+static const unsigned short euc_to_utf8_8FE5[] = {
+ 0x937A, 0x937D, 0x937F, 0x9380, 0x9381, 0x9382, 0x9388,
+ 0x938A, 0x938B, 0x938D, 0x938F, 0x9392, 0x9395, 0x9398, 0x939B,
+ 0x939E, 0x93A1, 0x93A3, 0x93A4, 0x93A6, 0x93A8, 0x93AB, 0x93B4,
+ 0x93B5, 0x93B6, 0x93BA, 0x93A9, 0x93C1, 0x93C4, 0x93C5, 0x93C6,
+ 0x93C7, 0x93C9, 0x93CA, 0x93CB, 0x93CC, 0x93CD, 0x93D3, 0x93D9,
+ 0x93DC, 0x93DE, 0x93DF, 0x93E2, 0x93E6, 0x93E7, 0x93F9, 0x93F7,
+ 0x93F8, 0x93FA, 0x93FB, 0x93FD, 0x9401, 0x9402, 0x9404, 0x9408,
+ 0x9409, 0x940D, 0x940E, 0x940F, 0x9415, 0x9416, 0x9417, 0x941F,
+ 0x942E, 0x942F, 0x9431, 0x9432, 0x9433, 0x9434, 0x943B, 0x943F,
+ 0x943D, 0x9443, 0x9445, 0x9448, 0x944A, 0x944C, 0x9455, 0x9459,
+ 0x945C, 0x945F, 0x9461, 0x9463, 0x9468, 0x946B, 0x946D, 0x946E,
+ 0x946F, 0x9471, 0x9472, 0x9484, 0x9483, 0x9578, 0x9579,
+};
+static const unsigned short euc_to_utf8_8FE6[] = {
+ 0x957E, 0x9584, 0x9588, 0x958C, 0x958D, 0x958E, 0x959D,
+ 0x959E, 0x959F, 0x95A1, 0x95A6, 0x95A9, 0x95AB, 0x95AC, 0x95B4,
+ 0x95B6, 0x95BA, 0x95BD, 0x95BF, 0x95C6, 0x95C8, 0x95C9, 0x95CB,
+ 0x95D0, 0x95D1, 0x95D2, 0x95D3, 0x95D9, 0x95DA, 0x95DD, 0x95DE,
+ 0x95DF, 0x95E0, 0x95E4, 0x95E6, 0x961D, 0x961E, 0x9622, 0x9624,
+ 0x9625, 0x9626, 0x962C, 0x9631, 0x9633, 0x9637, 0x9638, 0x9639,
+ 0x963A, 0x963C, 0x963D, 0x9641, 0x9652, 0x9654, 0x9656, 0x9657,
+ 0x9658, 0x9661, 0x966E, 0x9674, 0x967B, 0x967C, 0x967E, 0x967F,
+ 0x9681, 0x9682, 0x9683, 0x9684, 0x9689, 0x9691, 0x9696, 0x969A,
+ 0x969D, 0x969F, 0x96A4, 0x96A5, 0x96A6, 0x96A9, 0x96AE, 0x96AF,
+ 0x96B3, 0x96BA, 0x96CA, 0x96D2, 0x5DB2, 0x96D8, 0x96DA, 0x96DD,
+ 0x96DE, 0x96DF, 0x96E9, 0x96EF, 0x96F1, 0x96FA, 0x9702,
+};
+static const unsigned short euc_to_utf8_8FE7[] = {
+ 0x9703, 0x9705, 0x9709, 0x971A, 0x971B, 0x971D, 0x9721,
+ 0x9722, 0x9723, 0x9728, 0x9731, 0x9733, 0x9741, 0x9743, 0x974A,
+ 0x974E, 0x974F, 0x9755, 0x9757, 0x9758, 0x975A, 0x975B, 0x9763,
+ 0x9767, 0x976A, 0x976E, 0x9773, 0x9776, 0x9777, 0x9778, 0x977B,
+ 0x977D, 0x977F, 0x9780, 0x9789, 0x9795, 0x9796, 0x9797, 0x9799,
+ 0x979A, 0x979E, 0x979F, 0x97A2, 0x97AC, 0x97AE, 0x97B1, 0x97B2,
+ 0x97B5, 0x97B6, 0x97B8, 0x97B9, 0x97BA, 0x97BC, 0x97BE, 0x97BF,
+ 0x97C1, 0x97C4, 0x97C5, 0x97C7, 0x97C9, 0x97CA, 0x97CC, 0x97CD,
+ 0x97CE, 0x97D0, 0x97D1, 0x97D4, 0x97D7, 0x97D8, 0x97D9, 0x97DD,
+ 0x97DE, 0x97E0, 0x97DB, 0x97E1, 0x97E4, 0x97EF, 0x97F1, 0x97F4,
+ 0x97F7, 0x97F8, 0x97FA, 0x9807, 0x980A, 0x9819, 0x980D, 0x980E,
+ 0x9814, 0x9816, 0x981C, 0x981E, 0x9820, 0x9823, 0x9826,
+};
+static const unsigned short euc_to_utf8_8FE8[] = {
+ 0x982B, 0x982E, 0x982F, 0x9830, 0x9832, 0x9833, 0x9835,
+ 0x9825, 0x983E, 0x9844, 0x9847, 0x984A, 0x9851, 0x9852, 0x9853,
+ 0x9856, 0x9857, 0x9859, 0x985A, 0x9862, 0x9863, 0x9865, 0x9866,
+ 0x986A, 0x986C, 0x98AB, 0x98AD, 0x98AE, 0x98B0, 0x98B4, 0x98B7,
+ 0x98B8, 0x98BA, 0x98BB, 0x98BF, 0x98C2, 0x98C5, 0x98C8, 0x98CC,
+ 0x98E1, 0x98E3, 0x98E5, 0x98E6, 0x98E7, 0x98EA, 0x98F3, 0x98F6,
+ 0x9902, 0x9907, 0x9908, 0x9911, 0x9915, 0x9916, 0x9917, 0x991A,
+ 0x991B, 0x991C, 0x991F, 0x9922, 0x9926, 0x9927, 0x992B, 0x9931,
+ 0x9932, 0x9933, 0x9934, 0x9935, 0x9939, 0x993A, 0x993B, 0x993C,
+ 0x9940, 0x9941, 0x9946, 0x9947, 0x9948, 0x994D, 0x994E, 0x9954,
+ 0x9958, 0x9959, 0x995B, 0x995C, 0x995E, 0x995F, 0x9960, 0x999B,
+ 0x999D, 0x999F, 0x99A6, 0x99B0, 0x99B1, 0x99B2, 0x99B5,
+};
+static const unsigned short euc_to_utf8_8FE9[] = {
+ 0x99B9, 0x99BA, 0x99BD, 0x99BF, 0x99C3, 0x99C9, 0x99D3,
+ 0x99D4, 0x99D9, 0x99DA, 0x99DC, 0x99DE, 0x99E7, 0x99EA, 0x99EB,
+ 0x99EC, 0x99F0, 0x99F4, 0x99F5, 0x99F9, 0x99FD, 0x99FE, 0x9A02,
+ 0x9A03, 0x9A04, 0x9A0B, 0x9A0C, 0x9A10, 0x9A11, 0x9A16, 0x9A1E,
+ 0x9A20, 0x9A22, 0x9A23, 0x9A24, 0x9A27, 0x9A2D, 0x9A2E, 0x9A33,
+ 0x9A35, 0x9A36, 0x9A38, 0x9A47, 0x9A41, 0x9A44, 0x9A4A, 0x9A4B,
+ 0x9A4C, 0x9A4E, 0x9A51, 0x9A54, 0x9A56, 0x9A5D, 0x9AAA, 0x9AAC,
+ 0x9AAE, 0x9AAF, 0x9AB2, 0x9AB4, 0x9AB5, 0x9AB6, 0x9AB9, 0x9ABB,
+ 0x9ABE, 0x9ABF, 0x9AC1, 0x9AC3, 0x9AC6, 0x9AC8, 0x9ACE, 0x9AD0,
+ 0x9AD2, 0x9AD5, 0x9AD6, 0x9AD7, 0x9ADB, 0x9ADC, 0x9AE0, 0x9AE4,
+ 0x9AE5, 0x9AE7, 0x9AE9, 0x9AEC, 0x9AF2, 0x9AF3, 0x9AF5, 0x9AF9,
+ 0x9AFA, 0x9AFD, 0x9AFF, 0x9B00, 0x9B01, 0x9B02, 0x9B03,
+};
+static const unsigned short euc_to_utf8_8FEA[] = {
+ 0x9B04, 0x9B05, 0x9B08, 0x9B09, 0x9B0B, 0x9B0C, 0x9B0D,
+ 0x9B0E, 0x9B10, 0x9B12, 0x9B16, 0x9B19, 0x9B1B, 0x9B1C, 0x9B20,
+ 0x9B26, 0x9B2B, 0x9B2D, 0x9B33, 0x9B34, 0x9B35, 0x9B37, 0x9B39,
+ 0x9B3A, 0x9B3D, 0x9B48, 0x9B4B, 0x9B4C, 0x9B55, 0x9B56, 0x9B57,
+ 0x9B5B, 0x9B5E, 0x9B61, 0x9B63, 0x9B65, 0x9B66, 0x9B68, 0x9B6A,
+ 0x9B6B, 0x9B6C, 0x9B6D, 0x9B6E, 0x9B73, 0x9B75, 0x9B77, 0x9B78,
+ 0x9B79, 0x9B7F, 0x9B80, 0x9B84, 0x9B85, 0x9B86, 0x9B87, 0x9B89,
+ 0x9B8A, 0x9B8B, 0x9B8D, 0x9B8F, 0x9B90, 0x9B94, 0x9B9A, 0x9B9D,
+ 0x9B9E, 0x9BA6, 0x9BA7, 0x9BA9, 0x9BAC, 0x9BB0, 0x9BB1, 0x9BB2,
+ 0x9BB7, 0x9BB8, 0x9BBB, 0x9BBC, 0x9BBE, 0x9BBF, 0x9BC1, 0x9BC7,
+ 0x9BC8, 0x9BCE, 0x9BD0, 0x9BD7, 0x9BD8, 0x9BDD, 0x9BDF, 0x9BE5,
+ 0x9BE7, 0x9BEA, 0x9BEB, 0x9BEF, 0x9BF3, 0x9BF7, 0x9BF8,
+};
+static const unsigned short euc_to_utf8_8FEB[] = {
+ 0x9BF9, 0x9BFA, 0x9BFD, 0x9BFF, 0x9C00, 0x9C02, 0x9C0B,
+ 0x9C0F, 0x9C11, 0x9C16, 0x9C18, 0x9C19, 0x9C1A, 0x9C1C, 0x9C1E,
+ 0x9C22, 0x9C23, 0x9C26, 0x9C27, 0x9C28, 0x9C29, 0x9C2A, 0x9C31,
+ 0x9C35, 0x9C36, 0x9C37, 0x9C3D, 0x9C41, 0x9C43, 0x9C44, 0x9C45,
+ 0x9C49, 0x9C4A, 0x9C4E, 0x9C4F, 0x9C50, 0x9C53, 0x9C54, 0x9C56,
+ 0x9C58, 0x9C5B, 0x9C5D, 0x9C5E, 0x9C5F, 0x9C63, 0x9C69, 0x9C6A,
+ 0x9C5C, 0x9C6B, 0x9C68, 0x9C6E, 0x9C70, 0x9C72, 0x9C75, 0x9C77,
+ 0x9C7B, 0x9CE6, 0x9CF2, 0x9CF7, 0x9CF9, 0x9D0B, 0x9D02, 0x9D11,
+ 0x9D17, 0x9D18, 0x9D1C, 0x9D1D, 0x9D1E, 0x9D2F, 0x9D30, 0x9D32,
+ 0x9D33, 0x9D34, 0x9D3A, 0x9D3C, 0x9D45, 0x9D3D, 0x9D42, 0x9D43,
+ 0x9D47, 0x9D4A, 0x9D53, 0x9D54, 0x9D5F, 0x9D63, 0x9D62, 0x9D65,
+ 0x9D69, 0x9D6A, 0x9D6B, 0x9D70, 0x9D76, 0x9D77, 0x9D7B,
+};
+static const unsigned short euc_to_utf8_8FEC[] = {
+ 0x9D7C, 0x9D7E, 0x9D83, 0x9D84, 0x9D86, 0x9D8A, 0x9D8D,
+ 0x9D8E, 0x9D92, 0x9D93, 0x9D95, 0x9D96, 0x9D97, 0x9D98, 0x9DA1,
+ 0x9DAA, 0x9DAC, 0x9DAE, 0x9DB1, 0x9DB5, 0x9DB9, 0x9DBC, 0x9DBF,
+ 0x9DC3, 0x9DC7, 0x9DC9, 0x9DCA, 0x9DD4, 0x9DD5, 0x9DD6, 0x9DD7,
+ 0x9DDA, 0x9DDE, 0x9DDF, 0x9DE0, 0x9DE5, 0x9DE7, 0x9DE9, 0x9DEB,
+ 0x9DEE, 0x9DF0, 0x9DF3, 0x9DF4, 0x9DFE, 0x9E0A, 0x9E02, 0x9E07,
+ 0x9E0E, 0x9E10, 0x9E11, 0x9E12, 0x9E15, 0x9E16, 0x9E19, 0x9E1C,
+ 0x9E1D, 0x9E7A, 0x9E7B, 0x9E7C, 0x9E80, 0x9E82, 0x9E83, 0x9E84,
+ 0x9E85, 0x9E87, 0x9E8E, 0x9E8F, 0x9E96, 0x9E98, 0x9E9B, 0x9E9E,
+ 0x9EA4, 0x9EA8, 0x9EAC, 0x9EAE, 0x9EAF, 0x9EB0, 0x9EB3, 0x9EB4,
+ 0x9EB5, 0x9EC6, 0x9EC8, 0x9ECB, 0x9ED5, 0x9EDF, 0x9EE4, 0x9EE7,
+ 0x9EEC, 0x9EED, 0x9EEE, 0x9EF0, 0x9EF1, 0x9EF2, 0x9EF5,
+};
+static const unsigned short euc_to_utf8_8FED[] = {
+ 0x9EF8, 0x9EFF, 0x9F02, 0x9F03, 0x9F09, 0x9F0F, 0x9F10,
+ 0x9F11, 0x9F12, 0x9F14, 0x9F16, 0x9F17, 0x9F19, 0x9F1A, 0x9F1B,
+ 0x9F1F, 0x9F22, 0x9F26, 0x9F2A, 0x9F2B, 0x9F2F, 0x9F31, 0x9F32,
+ 0x9F34, 0x9F37, 0x9F39, 0x9F3A, 0x9F3C, 0x9F3D, 0x9F3F, 0x9F41,
+ 0x9F43, 0x9F44, 0x9F45, 0x9F46, 0x9F47, 0x9F53, 0x9F55, 0x9F56,
+ 0x9F57, 0x9F58, 0x9F5A, 0x9F5D, 0x9F5E, 0x9F68, 0x9F69, 0x9F6D,
+ 0x9F6E, 0x9F6F, 0x9F70, 0x9F71, 0x9F73, 0x9F75, 0x9F7A, 0x9F7D,
+ 0x9F8F, 0x9F90, 0x9F91, 0x9F92, 0x9F94, 0x9F96, 0x9F97, 0x9F9E,
+ 0x9FA1, 0x9FA2, 0x9FA3, 0x9FA5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short euc_to_utf8_8FF3[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174,
+ 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x2160, 0x2161,
+};
+static const unsigned short euc_to_utf8_8FF4[] = {
+ 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167, 0x2168,
+ 0x2169, 0xff07, 0xff02, 0x3231, 0x2116, 0x2121, 0x70bb, 0x4efc,
+ 0x50f4, 0x51ec, 0x5307, 0x5324, 0xfa0e, 0x548a, 0x5759, 0xfa0f,
+ 0xfa10, 0x589e, 0x5bec, 0x5cf5, 0x5d53, 0xfa11, 0x5fb7, 0x6085,
+ 0x6120, 0x654e, 0x663b, 0x6665, 0xfa12, 0xf929, 0x6801, 0xfa13,
+ 0xfa14, 0x6a6b, 0x6ae2, 0x6df8, 0x6df2, 0x7028, 0xfa15, 0xfa16,
+ 0x7501, 0x7682, 0x769e, 0xfa17, 0x7930, 0xfa18, 0xfa19, 0xfa1a,
+ 0xfa1b, 0x7ae7, 0xfa1c, 0xfa1d, 0x7da0, 0x7dd6, 0xfa1e, 0x8362,
+ 0xfa1f, 0x85b0, 0xfa20, 0xfa21, 0x8807, 0xfa22, 0x8b7f, 0x8cf4,
+ 0x8d76, 0xfa23, 0xfa24, 0xfa25, 0x90de, 0xfa26, 0x9115, 0xfa27,
+ 0xfa28, 0x9592, 0xf9dc, 0xfa29, 0x973b, 0x974d, 0x9751, 0xfa2a,
+ 0xfa2b, 0xfa2c, 0x999e, 0x9ad9, 0x9b72, 0xfa2d, 0x9ed1,
+};
+#endif /* X0212_ENABLE */
+
+const unsigned short euc_to_utf8_1byte[] = {
+ 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67,
+ 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,
+ 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77,
+ 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F,
+ 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87,
+ 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F,
+ 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97,
+ 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x00A9, 0x2122,
+};
+const unsigned short *const euc_to_utf8_2bytes[] = {
+ euc_to_utf8_A1, euc_to_utf8_A2, euc_to_utf8_A3,
+ euc_to_utf8_A4, euc_to_utf8_A5, euc_to_utf8_A6, euc_to_utf8_A7,
+ euc_to_utf8_A8, euc_to_utf8_A9, euc_to_utf8_AA, euc_to_utf8_AB,
+ euc_to_utf8_AC, euc_to_utf8_AD, euc_to_utf8_AE, euc_to_utf8_AF,
+ euc_to_utf8_B0, euc_to_utf8_B1, euc_to_utf8_B2, euc_to_utf8_B3,
+ euc_to_utf8_B4, euc_to_utf8_B5, euc_to_utf8_B6, euc_to_utf8_B7,
+ euc_to_utf8_B8, euc_to_utf8_B9, euc_to_utf8_BA, euc_to_utf8_BB,
+ euc_to_utf8_BC, euc_to_utf8_BD, euc_to_utf8_BE, euc_to_utf8_BF,
+ euc_to_utf8_C0, euc_to_utf8_C1, euc_to_utf8_C2, euc_to_utf8_C3,
+ euc_to_utf8_C4, euc_to_utf8_C5, euc_to_utf8_C6, euc_to_utf8_C7,
+ euc_to_utf8_C8, euc_to_utf8_C9, euc_to_utf8_CA, euc_to_utf8_CB,
+ euc_to_utf8_CC, euc_to_utf8_CD, euc_to_utf8_CE, euc_to_utf8_CF,
+ euc_to_utf8_D0, euc_to_utf8_D1, euc_to_utf8_D2, euc_to_utf8_D3,
+ euc_to_utf8_D4, euc_to_utf8_D5, euc_to_utf8_D6, euc_to_utf8_D7,
+ euc_to_utf8_D8, euc_to_utf8_D9, euc_to_utf8_DA, euc_to_utf8_DB,
+ euc_to_utf8_DC, euc_to_utf8_DD, euc_to_utf8_DE, euc_to_utf8_DF,
+ euc_to_utf8_E0, euc_to_utf8_E1, euc_to_utf8_E2, euc_to_utf8_E3,
+ euc_to_utf8_E4, euc_to_utf8_E5, euc_to_utf8_E6, euc_to_utf8_E7,
+ euc_to_utf8_E8, euc_to_utf8_E9, euc_to_utf8_EA, euc_to_utf8_EB,
+ euc_to_utf8_EC, euc_to_utf8_ED, euc_to_utf8_EE, euc_to_utf8_EF,
+ euc_to_utf8_F0, euc_to_utf8_F1, euc_to_utf8_F2, euc_to_utf8_F3,
+ euc_to_utf8_F4, euc_to_utf8_F5, 0, 0,
+ 0, euc_to_utf8_F9, euc_to_utf8_FA, euc_to_utf8_FB,
+ euc_to_utf8_FC, 0, 0,
+};
+/* Microsoft UCS Mapping Compatible */
+const unsigned short *const euc_to_utf8_2bytes_ms[] = {
+ euc_to_utf8_A1_ms, euc_to_utf8_A2_ms, euc_to_utf8_A3,
+ euc_to_utf8_A4, euc_to_utf8_A5, euc_to_utf8_A6, euc_to_utf8_A7,
+ euc_to_utf8_A8, euc_to_utf8_A9, euc_to_utf8_AA, euc_to_utf8_AB,
+ euc_to_utf8_AC, euc_to_utf8_AD, euc_to_utf8_AE, euc_to_utf8_AF,
+ euc_to_utf8_B0, euc_to_utf8_B1, euc_to_utf8_B2, euc_to_utf8_B3,
+ euc_to_utf8_B4, euc_to_utf8_B5, euc_to_utf8_B6, euc_to_utf8_B7,
+ euc_to_utf8_B8, euc_to_utf8_B9, euc_to_utf8_BA, euc_to_utf8_BB,
+ euc_to_utf8_BC, euc_to_utf8_BD, euc_to_utf8_BE, euc_to_utf8_BF,
+ euc_to_utf8_C0, euc_to_utf8_C1, euc_to_utf8_C2, euc_to_utf8_C3,
+ euc_to_utf8_C4, euc_to_utf8_C5, euc_to_utf8_C6, euc_to_utf8_C7,
+ euc_to_utf8_C8, euc_to_utf8_C9, euc_to_utf8_CA, euc_to_utf8_CB,
+ euc_to_utf8_CC, euc_to_utf8_CD, euc_to_utf8_CE, euc_to_utf8_CF,
+ euc_to_utf8_D0, euc_to_utf8_D1, euc_to_utf8_D2, euc_to_utf8_D3,
+ euc_to_utf8_D4, euc_to_utf8_D5, euc_to_utf8_D6, euc_to_utf8_D7,
+ euc_to_utf8_D8, euc_to_utf8_D9, euc_to_utf8_DA, euc_to_utf8_DB,
+ euc_to_utf8_DC, euc_to_utf8_DD, euc_to_utf8_DE, euc_to_utf8_DF,
+ euc_to_utf8_E0, euc_to_utf8_E1, euc_to_utf8_E2, euc_to_utf8_E3,
+ euc_to_utf8_E4, euc_to_utf8_E5, euc_to_utf8_E6, euc_to_utf8_E7,
+ euc_to_utf8_E8, euc_to_utf8_E9, euc_to_utf8_EA, euc_to_utf8_EB,
+ euc_to_utf8_EC, euc_to_utf8_ED, euc_to_utf8_EE, euc_to_utf8_EF,
+ euc_to_utf8_F0, euc_to_utf8_F1, euc_to_utf8_F2, euc_to_utf8_F3,
+ euc_to_utf8_F4, euc_to_utf8_F5, 0, 0,
+ 0, euc_to_utf8_F9, euc_to_utf8_FA, euc_to_utf8_FB,
+ euc_to_utf8_FC_ms, 0, 0,
+};
+/* CP10001 */
+const unsigned short *const euc_to_utf8_2bytes_mac[] = {
+ euc_to_utf8_A1_ms, euc_to_utf8_A2_ms, euc_to_utf8_A3,
+ euc_to_utf8_A4, euc_to_utf8_A5, euc_to_utf8_A6, euc_to_utf8_A7,
+ euc_to_utf8_A8, euc_to_utf8_A9, euc_to_utf8_AA, euc_to_utf8_AB,
+ euc_to_utf8_AC_mac, euc_to_utf8_AD_mac, euc_to_utf8_AE, euc_to_utf8_AF,
+ euc_to_utf8_B0, euc_to_utf8_B1, euc_to_utf8_B2, euc_to_utf8_B3,
+ euc_to_utf8_B4, euc_to_utf8_B5, euc_to_utf8_B6, euc_to_utf8_B7,
+ euc_to_utf8_B8, euc_to_utf8_B9, euc_to_utf8_BA, euc_to_utf8_BB,
+ euc_to_utf8_BC, euc_to_utf8_BD, euc_to_utf8_BE, euc_to_utf8_BF,
+ euc_to_utf8_C0, euc_to_utf8_C1, euc_to_utf8_C2, euc_to_utf8_C3,
+ euc_to_utf8_C4, euc_to_utf8_C5, euc_to_utf8_C6, euc_to_utf8_C7,
+ euc_to_utf8_C8, euc_to_utf8_C9, euc_to_utf8_CA, euc_to_utf8_CB,
+ euc_to_utf8_CC, euc_to_utf8_CD, euc_to_utf8_CE, euc_to_utf8_CF,
+ euc_to_utf8_D0, euc_to_utf8_D1, euc_to_utf8_D2, euc_to_utf8_D3,
+ euc_to_utf8_D4, euc_to_utf8_D5, euc_to_utf8_D6, euc_to_utf8_D7,
+ euc_to_utf8_D8, euc_to_utf8_D9, euc_to_utf8_DA, euc_to_utf8_DB,
+ euc_to_utf8_DC, euc_to_utf8_DD, euc_to_utf8_DE, euc_to_utf8_DF,
+ euc_to_utf8_E0, euc_to_utf8_E1, euc_to_utf8_E2, euc_to_utf8_E3,
+ euc_to_utf8_E4, euc_to_utf8_E5, euc_to_utf8_E6, euc_to_utf8_E7,
+ euc_to_utf8_E8, euc_to_utf8_E9, euc_to_utf8_EA, euc_to_utf8_EB,
+ euc_to_utf8_EC, euc_to_utf8_ED, euc_to_utf8_EE, euc_to_utf8_EF,
+ euc_to_utf8_F0, euc_to_utf8_F1, euc_to_utf8_F2, euc_to_utf8_F3,
+ euc_to_utf8_F4, euc_to_utf8_F5, 0, 0,
+ 0, euc_to_utf8_F9, euc_to_utf8_FA, euc_to_utf8_FB,
+ euc_to_utf8_FC_ms, 0, 0,
+};
+const unsigned short *const euc_to_utf8_2bytes_x0213[] = {
+ euc_to_utf8_A1, euc_to_utf8_A2_x0213, euc_to_utf8_A3_x0213,
+ euc_to_utf8_A4_x0213, euc_to_utf8_A5_x0213, euc_to_utf8_A6_x0213, euc_to_utf8_A7_x0213,
+ euc_to_utf8_A8_x0213, euc_to_utf8_A9_x0213, euc_to_utf8_AA_x0213, euc_to_utf8_AB_x0213,
+ euc_to_utf8_AC_x0213, euc_to_utf8_AD_x0213, euc_to_utf8_AE_x0213, euc_to_utf8_AF_x0213,
+ euc_to_utf8_B0, euc_to_utf8_B1, euc_to_utf8_B2, euc_to_utf8_B3,
+ euc_to_utf8_B4, euc_to_utf8_B5, euc_to_utf8_B6, euc_to_utf8_B7,
+ euc_to_utf8_B8, euc_to_utf8_B9, euc_to_utf8_BA, euc_to_utf8_BB,
+ euc_to_utf8_BC, euc_to_utf8_BD, euc_to_utf8_BE, euc_to_utf8_BF,
+ euc_to_utf8_C0, euc_to_utf8_C1, euc_to_utf8_C2, euc_to_utf8_C3,
+ euc_to_utf8_C4, euc_to_utf8_C5, euc_to_utf8_C6, euc_to_utf8_C7,
+ euc_to_utf8_C8, euc_to_utf8_C9, euc_to_utf8_CA, euc_to_utf8_CB,
+ euc_to_utf8_CC, euc_to_utf8_CD, euc_to_utf8_CE, euc_to_utf8_CF_x0213,
+ euc_to_utf8_D0, euc_to_utf8_D1, euc_to_utf8_D2, euc_to_utf8_D3,
+ euc_to_utf8_D4, euc_to_utf8_D5, euc_to_utf8_D6, euc_to_utf8_D7,
+ euc_to_utf8_D8, euc_to_utf8_D9, euc_to_utf8_DA, euc_to_utf8_DB,
+ euc_to_utf8_DC, euc_to_utf8_DD, euc_to_utf8_DE, euc_to_utf8_DF,
+ euc_to_utf8_E0, euc_to_utf8_E1, euc_to_utf8_E2, euc_to_utf8_E3,
+ euc_to_utf8_E4, euc_to_utf8_E5, euc_to_utf8_E6, euc_to_utf8_E7,
+ euc_to_utf8_E8, euc_to_utf8_E9, euc_to_utf8_EA, euc_to_utf8_EB,
+ euc_to_utf8_EC, euc_to_utf8_ED, euc_to_utf8_EE, euc_to_utf8_EF,
+ euc_to_utf8_F0, euc_to_utf8_F1, euc_to_utf8_F2, euc_to_utf8_F3,
+ euc_to_utf8_F4_x0213, euc_to_utf8_F5_x0213, euc_to_utf8_F6_x0213, euc_to_utf8_F7_x0213,
+ euc_to_utf8_F8_x0213, euc_to_utf8_F9_x0213, euc_to_utf8_FA_x0213, euc_to_utf8_FB_x0213,
+ euc_to_utf8_FC_x0213, euc_to_utf8_FD_x0213, euc_to_utf8_FE_x0213,
+};
+
+#ifdef X0212_ENABLE
+const unsigned short *const x0212_to_utf8_2bytes[] = {
+ 0, euc_to_utf8_8FA2, 0,
+ 0, 0, euc_to_utf8_8FA6, euc_to_utf8_8FA7,
+ 0, euc_to_utf8_8FA9, euc_to_utf8_8FAA, euc_to_utf8_8FAB,
+ 0, 0, 0, 0,
+ euc_to_utf8_8FB0, euc_to_utf8_8FB1, euc_to_utf8_8FB2, euc_to_utf8_8FB3,
+ euc_to_utf8_8FB4, euc_to_utf8_8FB5, euc_to_utf8_8FB6, euc_to_utf8_8FB7,
+ euc_to_utf8_8FB8, euc_to_utf8_8FB9, euc_to_utf8_8FBA, euc_to_utf8_8FBB,
+ euc_to_utf8_8FBC, euc_to_utf8_8FBD, euc_to_utf8_8FBE, euc_to_utf8_8FBF,
+ euc_to_utf8_8FC0, euc_to_utf8_8FC1, euc_to_utf8_8FC2, euc_to_utf8_8FC3,
+ euc_to_utf8_8FC4, euc_to_utf8_8FC5, euc_to_utf8_8FC6, euc_to_utf8_8FC7,
+ euc_to_utf8_8FC8, euc_to_utf8_8FC9, euc_to_utf8_8FCA, euc_to_utf8_8FCB,
+ euc_to_utf8_8FCC, euc_to_utf8_8FCD, euc_to_utf8_8FCE, euc_to_utf8_8FCF,
+ euc_to_utf8_8FD0, euc_to_utf8_8FD1, euc_to_utf8_8FD2, euc_to_utf8_8FD3,
+ euc_to_utf8_8FD4, euc_to_utf8_8FD5, euc_to_utf8_8FD6, euc_to_utf8_8FD7,
+ euc_to_utf8_8FD8, euc_to_utf8_8FD9, euc_to_utf8_8FDA, euc_to_utf8_8FDB,
+ euc_to_utf8_8FDC, euc_to_utf8_8FDD, euc_to_utf8_8FDE, euc_to_utf8_8FDF,
+ euc_to_utf8_8FE0, euc_to_utf8_8FE1, euc_to_utf8_8FE2, euc_to_utf8_8FE3,
+ euc_to_utf8_8FE4, euc_to_utf8_8FE5, euc_to_utf8_8FE6, euc_to_utf8_8FE7,
+ euc_to_utf8_8FE8, euc_to_utf8_8FE9, euc_to_utf8_8FEA, euc_to_utf8_8FEB,
+ euc_to_utf8_8FEC, euc_to_utf8_8FED, 0, 0,
+ 0, 0, 0, euc_to_utf8_8FF3,
+ euc_to_utf8_8FF4, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0,};
+
+const unsigned short *const x0212_to_utf8_2bytes_x0213[] = {
+ euc_to_utf8_8FA1_x0213, euc_to_utf8_8FA2, euc_to_utf8_8FA3_x0213,
+ euc_to_utf8_8FA4_x0213, euc_to_utf8_8FA5_x0213, euc_to_utf8_8FA6, euc_to_utf8_8FA7,
+ euc_to_utf8_8FA8_x0213, euc_to_utf8_8FA9, euc_to_utf8_8FAA, euc_to_utf8_8FAB,
+ euc_to_utf8_8FAC_x0213, euc_to_utf8_8FAD_x0213, euc_to_utf8_8FAE_x0213, euc_to_utf8_8FAF_x0213,
+ euc_to_utf8_8FB0, euc_to_utf8_8FB1, euc_to_utf8_8FB2, euc_to_utf8_8FB3,
+ euc_to_utf8_8FB4, euc_to_utf8_8FB5, euc_to_utf8_8FB6, euc_to_utf8_8FB7,
+ euc_to_utf8_8FB8, euc_to_utf8_8FB9, euc_to_utf8_8FBA, euc_to_utf8_8FBB,
+ euc_to_utf8_8FBC, euc_to_utf8_8FBD, euc_to_utf8_8FBE, euc_to_utf8_8FBF,
+ euc_to_utf8_8FC0, euc_to_utf8_8FC1, euc_to_utf8_8FC2, euc_to_utf8_8FC3,
+ euc_to_utf8_8FC4, euc_to_utf8_8FC5, euc_to_utf8_8FC6, euc_to_utf8_8FC7,
+ euc_to_utf8_8FC8, euc_to_utf8_8FC9, euc_to_utf8_8FCA, euc_to_utf8_8FCB,
+ euc_to_utf8_8FCC, euc_to_utf8_8FCD, euc_to_utf8_8FCE, euc_to_utf8_8FCF,
+ euc_to_utf8_8FD0, euc_to_utf8_8FD1, euc_to_utf8_8FD2, euc_to_utf8_8FD3,
+ euc_to_utf8_8FD4, euc_to_utf8_8FD5, euc_to_utf8_8FD6, euc_to_utf8_8FD7,
+ euc_to_utf8_8FD8, euc_to_utf8_8FD9, euc_to_utf8_8FDA, euc_to_utf8_8FDB,
+ euc_to_utf8_8FDC, euc_to_utf8_8FDD, euc_to_utf8_8FDE, euc_to_utf8_8FDF,
+ euc_to_utf8_8FE0, euc_to_utf8_8FE1, euc_to_utf8_8FE2, euc_to_utf8_8FE3,
+ euc_to_utf8_8FE4, euc_to_utf8_8FE5, euc_to_utf8_8FE6, euc_to_utf8_8FE7,
+ euc_to_utf8_8FE8, euc_to_utf8_8FE9, euc_to_utf8_8FEA, euc_to_utf8_8FEB,
+ euc_to_utf8_8FEC, euc_to_utf8_8FED, euc_to_utf8_8FEE_x0213, euc_to_utf8_8FEF_x0213,
+ euc_to_utf8_8FF0_x0213, euc_to_utf8_8FF1_x0213, euc_to_utf8_8FF2_x0213, euc_to_utf8_8FF3_x0213,
+ euc_to_utf8_8FF4_x0213, euc_to_utf8_8FF5_x0213, euc_to_utf8_8FF6_x0213, euc_to_utf8_8FF7_x0213,
+ euc_to_utf8_8FF8_x0213, euc_to_utf8_8FF9_x0213, euc_to_utf8_8FFA_x0213, euc_to_utf8_8FFB_x0213,
+ euc_to_utf8_8FFC_x0213, euc_to_utf8_8FFD_x0213, euc_to_utf8_8FFE_x0213,};
+#endif /* X0212_ENABLE */
+
+const unsigned short x0213_combining_chars[sizeof_x0213_combining_chars] = {
+ 0x309A, 0x0300, 0x0301, 0x02E5, 0x02E9,
+};
+const unsigned short x0213_combining_table[sizeof_x0213_combining_table][3] = {
+ {0x2477, 0x304B, 0x309A},
+ {0x2478, 0x304D, 0x309A},
+ {0x2479, 0x304F, 0x309A},
+ {0x247A, 0x3051, 0x309A},
+ {0x247B, 0x3053, 0x309A},
+ {0x2577, 0x30AB, 0x309A},
+ {0x2578, 0x30AD, 0x309A},
+ {0x2579, 0x30AF, 0x309A},
+ {0x257A, 0x30B1, 0x309A},
+ {0x257B, 0x30B3, 0x309A},
+ {0x257C, 0x30BB, 0x309A},
+ {0x257D, 0x30C4, 0x309A},
+ {0x257E, 0x30C8, 0x309A},
+ {0x2678, 0x31F7, 0x309A},
+ {0x2B44, 0x00E6, 0x0300},
+ {0x2B48, 0x0254, 0x0300},
+ {0x2B49, 0x0254, 0x0301},
+ {0x2B4A, 0x028C, 0x0300},
+ {0x2B4B, 0x028C, 0x0301},
+ {0x2B4C, 0x0259, 0x0300},
+ {0x2B4D, 0x0259, 0x0301},
+ {0x2B4E, 0x025A, 0x0300},
+ {0x2B4F, 0x025A, 0x0301},
+ {0x2B65, 0x02E9, 0x02E5},
+ {0x2B66, 0x02E5, 0x02E9},
+};
+const unsigned short x0213_1_surrogate_table[sizeof_x0213_1_surrogate_table][3] = {
+ {0x2E22, 0xD840, 0xDC0B},
+ {0x2F42, 0xD844, 0xDE3D},
+ {0x2F4C, 0xD844, 0xDF1B},
+ {0x2F60, 0xD845, 0xDC6E},
+ {0x2F7B, 0xD846, 0xDCBD},
+ {0x4F54, 0xD842, 0xDF9F},
+ {0x4F63, 0xD845, 0xDEB4},
+ {0x4F6E, 0xD847, 0xDE34},
+ {0x753A, 0xD84C, 0xDDC4},
+ {0x7572, 0xD84D, 0xDDC4},
+ {0x7629, 0xD84D, 0xDF3F},
+ {0x7632, 0xD84D, 0xDF63},
+ {0x7660, 0xD84F, 0xDCFE},
+ {0x776C, 0xD851, 0xDFF1},
+ {0x787E, 0xD855, 0xDC8E},
+ {0x7929, 0xD855, 0xDD0E},
+ {0x7947, 0xD855, 0xDF71},
+ {0x7954, 0xD856, 0xDDC4},
+ {0x796E, 0xD857, 0xDDA1},
+ {0x7A5D, 0xD85A, 0xDEFF},
+ {0x7B33, 0xD85B, 0xDE40},
+ {0x7B49, 0xD85C, 0xDCF4},
+ {0x7B6C, 0xD85D, 0xDE84},
+ {0x7C49, 0xD860, 0xDE77},
+ {0x7C51, 0xD860, 0xDFCD},
+ {0x7E66, 0xD868, 0xDD90},
+};
+const unsigned short x0213_2_surrogate_table[sizeof_x0213_2_surrogate_table][3] = {
+ {0x2121, 0xD840, 0xDC89},
+ {0x212B, 0xD840, 0xDCA2},
+ {0x212E, 0xD840, 0xDCA4},
+ {0x2136, 0xD840, 0xDDA2},
+ {0x2146, 0xD840, 0xDE13},
+ {0x2170, 0xD840, 0xDF2B},
+ {0x2177, 0xD840, 0xDF81},
+ {0x2179, 0xD840, 0xDF71},
+ {0x2322, 0xD840, 0xDFF9},
+ {0x2325, 0xD841, 0xDC4A},
+ {0x2327, 0xD841, 0xDD09},
+ {0x2331, 0xD841, 0xDDD6},
+ {0x2332, 0xD841, 0xDE28},
+ {0x2338, 0xD841, 0xDF4F},
+ {0x233F, 0xD842, 0xDC07},
+ {0x2341, 0xD842, 0xDC3A},
+ {0x234A, 0xD842, 0xDCB9},
+ {0x2352, 0xD842, 0xDD7C},
+ {0x2353, 0xD842, 0xDD9D},
+ {0x2359, 0xD842, 0xDED3},
+ {0x235C, 0xD842, 0xDF1D},
+ {0x2377, 0xD843, 0xDD45},
+ {0x242A, 0xD843, 0xDDE1},
+ {0x2431, 0xD843, 0xDE95},
+ {0x2432, 0xD843, 0xDE6D},
+ {0x243A, 0xD843, 0xDE64},
+ {0x243D, 0xD843, 0xDF5F},
+ {0x2459, 0xD844, 0xDE01},
+ {0x245C, 0xD844, 0xDE55},
+ {0x245E, 0xD844, 0xDE7B},
+ {0x2463, 0xD844, 0xDE74},
+ {0x246A, 0xD844, 0xDEE4},
+ {0x246B, 0xD844, 0xDED7},
+ {0x2472, 0xD844, 0xDEFD},
+ {0x2474, 0xD844, 0xDF36},
+ {0x2475, 0xD844, 0xDF44},
+ {0x2525, 0xD844, 0xDFC4},
+ {0x2532, 0xD845, 0xDC6D},
+ {0x253E, 0xD845, 0xDDD7},
+ {0x2544, 0xD85B, 0xDC29},
+ {0x2547, 0xD845, 0xDE47},
+ {0x2555, 0xD845, 0xDF06},
+ {0x2556, 0xD845, 0xDF42},
+ {0x257E, 0xD846, 0xDDC3},
+ {0x2830, 0xD847, 0xDC56},
+ {0x2837, 0xD847, 0xDD2D},
+ {0x2838, 0xD847, 0xDD45},
+ {0x283A, 0xD847, 0xDD78},
+ {0x283B, 0xD847, 0xDD62},
+ {0x283F, 0xD847, 0xDDA1},
+ {0x2840, 0xD847, 0xDD9C},
+ {0x2845, 0xD847, 0xDD92},
+ {0x2848, 0xD847, 0xDDB7},
+ {0x284A, 0xD847, 0xDDE0},
+ {0x284B, 0xD847, 0xDE33},
+ {0x285B, 0xD847, 0xDF1E},
+ {0x2866, 0xD847, 0xDF76},
+ {0x286C, 0xD847, 0xDFFA},
+ {0x2C22, 0xD848, 0xDD7B},
+ {0x2C2B, 0xD848, 0xDF1E},
+ {0x2C30, 0xD848, 0xDFAD},
+ {0x2C50, 0xD849, 0xDEF3},
+ {0x2C65, 0xD84A, 0xDC5B},
+ {0x2C6D, 0xD84A, 0xDCAB},
+ {0x2C72, 0xD84A, 0xDD8F},
+ {0x2D24, 0xD84A, 0xDEB8},
+ {0x2D29, 0xD84A, 0xDF4F},
+ {0x2D2A, 0xD84A, 0xDF50},
+ {0x2D32, 0xD84A, 0xDF46},
+ {0x2D34, 0xD84B, 0xDC1D},
+ {0x2D35, 0xD84A, 0xDFA6},
+ {0x2D39, 0xD84B, 0xDC24},
+ {0x2D56, 0xD84B, 0xDDE1},
+ {0x2D7D, 0xD84C, 0xDDC3},
+ {0x2E23, 0xD84C, 0xDDF5},
+ {0x2E24, 0xD84C, 0xDDB6},
+ {0x2E3A, 0xD84C, 0xDF72},
+ {0x2E3C, 0xD84C, 0xDFD3},
+ {0x2E3D, 0xD84C, 0xDFD2},
+ {0x2E42, 0xD84C, 0xDFD0},
+ {0x2E43, 0xD84C, 0xDFE4},
+ {0x2E44, 0xD84C, 0xDFD5},
+ {0x2E47, 0xD84C, 0xDFDA},
+ {0x2E49, 0xD84C, 0xDFDF},
+ {0x2E55, 0xD84D, 0xDC4A},
+ {0x2E56, 0xD84D, 0xDC51},
+ {0x2E57, 0xD84D, 0xDC4B},
+ {0x2E5B, 0xD84D, 0xDC65},
+ {0x2E77, 0xD84D, 0xDCE4},
+ {0x2E78, 0xD84D, 0xDD5A},
+ {0x2F2A, 0xD84D, 0xDD94},
+ {0x2F3F, 0xD84D, 0xDE39},
+ {0x2F40, 0xD84D, 0xDE47},
+ {0x2F42, 0xD84D, 0xDE38},
+ {0x2F43, 0xD84D, 0xDE3A},
+ {0x2F4E, 0xD84D, 0xDF1C},
+ {0x2F59, 0xD84D, 0xDF0C},
+ {0x2F61, 0xD84D, 0xDF64},
+ {0x2F69, 0xD84D, 0xDFFF},
+ {0x2F6A, 0xD84D, 0xDFE7},
+ {0x2F70, 0xD84E, 0xDC24},
+ {0x2F75, 0xD84E, 0xDC3D},
+ {0x6E23, 0xD84E, 0xDE98},
+ {0x6E34, 0xD84F, 0xDC7F},
+ {0x6E49, 0xD84F, 0xDD00},
+ {0x6E5C, 0xD84F, 0xDD40},
+ {0x6E5E, 0xD84F, 0xDDFA},
+ {0x6E5F, 0xD84F, 0xDDF9},
+ {0x6E60, 0xD84F, 0xDDD3},
+ {0x6F32, 0xD84F, 0xDF7E},
+ {0x6F47, 0xD850, 0xDC96},
+ {0x6F4D, 0xD850, 0xDD03},
+ {0x6F61, 0xD850, 0xDDC6},
+ {0x6F64, 0xD850, 0xDDFE},
+ {0x7022, 0xD850, 0xDFBC},
+ {0x7033, 0xD851, 0xDE29},
+ {0x7039, 0xD851, 0xDEA5},
+ {0x7053, 0xD852, 0xDC96},
+ {0x707B, 0xD852, 0xDE4D},
+ {0x712E, 0xD852, 0xDF56},
+ {0x7130, 0xD852, 0xDF6F},
+ {0x7135, 0xD853, 0xDC16},
+ {0x7144, 0xD853, 0xDD14},
+ {0x715D, 0xD853, 0xDE0E},
+ {0x7161, 0xD853, 0xDE37},
+ {0x7166, 0xD853, 0xDE6A},
+ {0x7169, 0xD853, 0xDE8B},
+ {0x7175, 0xD854, 0xDC4A},
+ {0x7177, 0xD854, 0xDC55},
+ {0x717A, 0xD854, 0xDD22},
+ {0x7221, 0xD854, 0xDDA9},
+ {0x7223, 0xD854, 0xDDE5},
+ {0x7224, 0xD854, 0xDDCD},
+ {0x7228, 0xD854, 0xDE1E},
+ {0x722C, 0xD854, 0xDE4C},
+ {0x723D, 0xD855, 0xDC2E},
+ {0x7248, 0xD855, 0xDCD9},
+ {0x725B, 0xD855, 0xDDA7},
+ {0x7275, 0xD855, 0xDFA9},
+ {0x7276, 0xD855, 0xDFB4},
+ {0x7332, 0xD856, 0xDDD4},
+ {0x733D, 0xD856, 0xDEE4},
+ {0x733E, 0xD856, 0xDEE3},
+ {0x7340, 0xD856, 0xDEF1},
+ {0x7352, 0xD856, 0xDFB2},
+ {0x735D, 0xD857, 0xDC4B},
+ {0x735E, 0xD857, 0xDC64},
+ {0x7373, 0xD857, 0xDE2E},
+ {0x7374, 0xD857, 0xDE56},
+ {0x7375, 0xD857, 0xDE65},
+ {0x7377, 0xD857, 0xDE62},
+ {0x737B, 0xD857, 0xDED8},
+ {0x737D, 0xD857, 0xDEC2},
+ {0x7422, 0xD857, 0xDEE8},
+ {0x7424, 0xD857, 0xDF23},
+ {0x7427, 0xD857, 0xDF5C},
+ {0x742E, 0xD857, 0xDFE0},
+ {0x742F, 0xD857, 0xDFD4},
+ {0x7434, 0xD858, 0xDC0C},
+ {0x7435, 0xD857, 0xDFFB},
+ {0x743D, 0xD858, 0xDC17},
+ {0x7442, 0xD858, 0xDC60},
+ {0x744F, 0xD858, 0xDCED},
+ {0x7469, 0xD858, 0xDE70},
+ {0x746B, 0xD858, 0xDE86},
+ {0x7472, 0xD858, 0xDF4C},
+ {0x7475, 0xD84F, 0xDD0E},
+ {0x7479, 0xD859, 0xDC02},
+ {0x7535, 0xD859, 0xDE7E},
+ {0x753A, 0xD859, 0xDEB0},
+ {0x7546, 0xD859, 0xDF1D},
+ {0x7556, 0xD85A, 0xDCDD},
+ {0x7558, 0xD85A, 0xDCEA},
+ {0x755A, 0xD85A, 0xDD51},
+ {0x755D, 0xD85A, 0xDD6F},
+ {0x755F, 0xD85A, 0xDDDD},
+ {0x7563, 0xD85A, 0xDE1E},
+ {0x756A, 0xD85A, 0xDE58},
+ {0x7570, 0xD85A, 0xDE8C},
+ {0x7573, 0xD85A, 0xDEB7},
+ {0x7644, 0xD85B, 0xDC73},
+ {0x764E, 0xD85B, 0xDCDD},
+ {0x765D, 0xD85B, 0xDE65},
+ {0x7675, 0xD85B, 0xDF94},
+ {0x767E, 0xD85B, 0xDFF8},
+ {0x7721, 0xD85B, 0xDFF6},
+ {0x7722, 0xD85B, 0xDFF7},
+ {0x7733, 0xD85C, 0xDD0D},
+ {0x7736, 0xD85C, 0xDD39},
+ {0x7764, 0xD85C, 0xDFDB},
+ {0x7765, 0xD85C, 0xDFDA},
+ {0x776B, 0xD85C, 0xDFFE},
+ {0x776E, 0xD85D, 0xDC10},
+ {0x7773, 0xD85D, 0xDC49},
+ {0x7829, 0xD85D, 0xDE15},
+ {0x782A, 0xD85D, 0xDE14},
+ {0x782C, 0xD85D, 0xDE31},
+ {0x7834, 0xD85D, 0xDE93},
+ {0x783C, 0xD85D, 0xDF0E},
+ {0x783E, 0xD85D, 0xDF23},
+ {0x7842, 0xD85D, 0xDF52},
+ {0x7856, 0xD85E, 0xDD85},
+ {0x7863, 0xD85E, 0xDE84},
+ {0x7877, 0xD85E, 0xDFB3},
+ {0x7879, 0xD85E, 0xDFBE},
+ {0x787A, 0xD85E, 0xDFC7},
+ {0x7925, 0xD85F, 0xDCB8},
+ {0x792F, 0xD85F, 0xDDA0},
+ {0x7932, 0xD85F, 0xDE10},
+ {0x7939, 0xD85F, 0xDFB7},
+ {0x7942, 0xD860, 0xDC8A},
+ {0x7948, 0xD860, 0xDCBB},
+ {0x7959, 0xD860, 0xDE82},
+ {0x795E, 0xD860, 0xDEF3},
+ {0x7966, 0xD861, 0xDC0C},
+ {0x796B, 0xD861, 0xDC55},
+ {0x797A, 0xD861, 0xDD6B},
+ {0x797E, 0xD861, 0xDDC8},
+ {0x7A21, 0xD861, 0xDDC9},
+ {0x7A2C, 0xD861, 0xDED7},
+ {0x7A2F, 0xD861, 0xDEFA},
+ {0x7A4F, 0xD862, 0xDD49},
+ {0x7A50, 0xD862, 0xDD46},
+ {0x7A57, 0xD862, 0xDD6B},
+ {0x7A65, 0xD862, 0xDD87},
+ {0x7A66, 0xD862, 0xDD88},
+ {0x7A71, 0xD862, 0xDDBA},
+ {0x7A72, 0xD862, 0xDDBB},
+ {0x7A7E, 0xD862, 0xDE1E},
+ {0x7B21, 0xD862, 0xDE29},
+ {0x7B2C, 0xD862, 0xDE71},
+ {0x7B2D, 0xD862, 0xDE43},
+ {0x7B36, 0xD862, 0xDE99},
+ {0x7B37, 0xD862, 0xDECD},
+ {0x7B3D, 0xD862, 0xDEE4},
+ {0x7B3E, 0xD862, 0xDEDD},
+ {0x7B4E, 0xD862, 0xDFC1},
+ {0x7B4F, 0xD862, 0xDFEF},
+ {0x7B57, 0xD863, 0xDD10},
+ {0x7B5A, 0xD863, 0xDD71},
+ {0x7B5C, 0xD863, 0xDDFB},
+ {0x7B5D, 0xD863, 0xDE1F},
+ {0x7B61, 0xD863, 0xDE36},
+ {0x7B65, 0xD863, 0xDE89},
+ {0x7B67, 0xD863, 0xDEEB},
+ {0x7B69, 0xD863, 0xDF32},
+ {0x7B71, 0xD863, 0xDFF8},
+ {0x7C22, 0xD864, 0xDEA0},
+ {0x7C23, 0xD864, 0xDEB1},
+ {0x7C38, 0xD865, 0xDC90},
+ {0x7C42, 0xD865, 0xDDCF},
+ {0x7C4C, 0xD865, 0xDE7F},
+ {0x7C56, 0xD865, 0xDEF0},
+ {0x7C59, 0xD865, 0xDF19},
+ {0x7C5D, 0xD865, 0xDF50},
+ {0x7C76, 0xD866, 0xDCC6},
+ {0x7D2C, 0xD866, 0xDE72},
+ {0x7D4B, 0xD867, 0xDDDB},
+ {0x7D4C, 0xD867, 0xDE3D},
+ {0x7D59, 0xD867, 0xDE15},
+ {0x7D5B, 0xD867, 0xDE8A},
+ {0x7D5D, 0xD867, 0xDE49},
+ {0x7D67, 0xD867, 0xDEC4},
+ {0x7D6D, 0xD867, 0xDEE9},
+ {0x7D70, 0xD867, 0xDEDB},
+ {0x7E25, 0xD867, 0xDFCE},
+ {0x7E29, 0xD868, 0xDC2F},
+ {0x7E2B, 0xD868, 0xDC1A},
+ {0x7E32, 0xD868, 0xDCF9},
+ {0x7E35, 0xD868, 0xDC82},
+ {0x7E53, 0xD848, 0xDE18},
+ {0x7E58, 0xD868, 0xDF8C},
+ {0x7E5A, 0xD869, 0xDC37},
+ {0x7E6E, 0xD869, 0xDDF1},
+ {0x7E70, 0xD869, 0xDE02},
+ {0x7E72, 0xD869, 0xDE1A},
+ {0x7E76, 0xD869, 0xDEB2},
+};
+#endif /* UTF8_OUTPUT_ENABLE */
+
+#ifdef UTF8_INPUT_ENABLE
+static const unsigned short utf8_to_euc_C2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xA242, 0x2171, 0x2172, 0xA270, 0x216F, 0xA243, 0x2178,
+ 0x212F, 0xA26D, 0xA26C, 0, 0x224C, 0, 0xA26E, 0xA234,
+ 0x216B, 0x215E, 0, 0, 0x212D, 0, 0x2279, 0,
+ 0xA231, 0, 0xA26B, 0, 0, 0, 0, 0xA244,
+};
+static const unsigned short utf8_to_euc_C2_ms[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xA242, 0x2171, 0x2172, 0xA270, 0x5C, 0xA243, 0x2178,
+ 0x212F, 0xA26D, 0xA26C, 0, 0x224C, 0, 0xA26E, 0xA234,
+ 0x216B, 0x215E, 0, 0, 0x212D, 0, 0x2279, 0,
+ 0xA231, 0, 0xA26B, 0, 0, 0, 0, 0xA244,
+};
+static const unsigned short utf8_to_euc_C2_mac[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x00A0, 0xA242, 0x2171, 0x2172, 0xA270, 0x5C, 0xA243, 0x2178,
+ 0x212F, 0x00FD, 0xA26C, 0, 0x224C, 0, 0xA26E, 0xA234,
+ 0x216B, 0x215E, 0, 0, 0x212D, 0, 0x2279, 0,
+ 0xA231, 0, 0xA26B, 0, 0, 0, 0, 0xA244,
+};
+static const unsigned short utf8_to_euc_C2_932[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x21, 0x2171, 0x2172, 0, 0x5C, 0x7C, 0x2178,
+ 0x212F, 0x63, 0x61, 0x2263, 0x224C, 0x2D, 0x52, 0x2131,
+ 0x216B, 0x215E, 0x32, 0x33, 0x212D, 0x264C, 0x2279, 0x2126,
+ 0x2124, 0x31, 0x6F, 0x2264, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_C2_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2922, 0x2923, 0x2171, 0x2172, 0x2924, 0x216F, 0x2925, 0x2178,
+ 0x212F, 0x2926, 0x2927, 0x2928, 0x224C, 0x2929, 0x292A, 0x292B,
+ 0x216B, 0x215E, 0x292C, 0x292D, 0x212D, 0, 0x2279, 0x292E,
+ 0x292F, 0x2930, 0x2931, 0x2932, 0x2933, 0x2934, 0x2935, 0x2936,
+};
+static const unsigned short utf8_to_euc_C3[] = {
+ 0xAA22, 0xAA21, 0xAA24, 0xAA2A, 0xAA23, 0xAA29, 0xA921, 0xAA2E,
+ 0xAA32, 0xAA31, 0xAA34, 0xAA33, 0xAA40, 0xAA3F, 0xAA42, 0xAA41,
+ 0, 0xAA50, 0xAA52, 0xAA51, 0xAA54, 0xAA58, 0xAA53, 0x215F,
+ 0xA92C, 0xAA63, 0xAA62, 0xAA65, 0xAA64, 0xAA72, 0xA930, 0xA94E,
+ 0xAB22, 0xAB21, 0xAB24, 0xAB2A, 0xAB23, 0xAB29, 0xA941, 0xAB2E,
+ 0xAB32, 0xAB31, 0xAB34, 0xAB33, 0xAB40, 0xAB3F, 0xAB42, 0xAB41,
+ 0xA943, 0xAB50, 0xAB52, 0xAB51, 0xAB54, 0xAB58, 0xAB53, 0x2160,
+ 0xA94C, 0xAB63, 0xAB62, 0xAB65, 0xAB64, 0xAB72, 0xA950, 0xAB73,
+};
+static const unsigned short utf8_to_euc_C3_932[] = {
+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43,
+ 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49,
+ 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x215F,
+ 0x4F, 0x55, 0x55, 0x55, 0x55, 0x59, 0x54, 0x73,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x63,
+ 0x65, 0x65, 0x65, 0x65, 0x69, 0x69, 0x69, 0x69,
+ 0x64, 0x6E, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x2160,
+ 0x6F, 0x75, 0x75, 0x75, 0x75, 0x79, 0x74, 0x79,
+};
+static const unsigned short utf8_to_euc_C3_x0213[] = {
+ 0x2937, 0x2938, 0x2939, 0x293A, 0x293B, 0x293C, 0x293D, 0x293E,
+ 0x293F, 0x2940, 0x2941, 0x2942, 0x2943, 0x2944, 0x2945, 0x2946,
+ 0x2947, 0x2948, 0x2949, 0x294A, 0x294B, 0x294C, 0x294D, 0x215F,
+ 0x294E, 0x294F, 0x2950, 0x2951, 0x2952, 0x2953, 0x2954, 0x2955,
+ 0x2956, 0x2957, 0x2958, 0x2959, 0x295A, 0x295B, 0x295C, 0x295D,
+ 0x295E, 0x295F, 0x2960, 0x2961, 0x2962, 0x2963, 0x2964, 0x2965,
+ 0x2966, 0x2967, 0x2968, 0x2969, 0x296A, 0x296B, 0x296C, 0x2160,
+ 0x296D, 0x296E, 0x296F, 0x2970, 0x2971, 0x2972, 0x2973, 0x2974,
+};
+static const unsigned short utf8_to_euc_C4[] = {
+ 0xAA27, 0xAB27, 0xAA25, 0xAB25, 0xAA28, 0xAB28, 0xAA2B, 0xAB2B,
+ 0xAA2C, 0xAB2C, 0xAA2F, 0xAB2F, 0xAA2D, 0xAB2D, 0xAA30, 0xAB30,
+ 0xA922, 0xA942, 0xAA37, 0xAB37, 0, 0, 0xAA36, 0xAB36,
+ 0xAA38, 0xAB38, 0xAA35, 0xAB35, 0xAA3A, 0xAB3A, 0xAA3B, 0xAB3B,
+ 0xAA3D, 0xAB3D, 0xAA3C, 0, 0xAA3E, 0xAB3E, 0xA924, 0xA944,
+ 0xAA47, 0xAB47, 0xAA45, 0xAB45, 0, 0, 0xAA46, 0xAB46,
+ 0xAA44, 0xA945, 0xA926, 0xA946, 0xAA48, 0xAB48, 0xAA49, 0xAB49,
+ 0xA947, 0xAA4A, 0xAB4A, 0xAA4C, 0xAB4C, 0xAA4B, 0xAB4B, 0xA929,
+};
+static const unsigned short utf8_to_euc_C4_x0213[] = {
+ 0x2975, 0x297A, 0x2A3A, 0x2A49, 0x2A21, 0x2A2C, 0x2A3C, 0x2A4B,
+ 0x2A59, 0x2A5F, 0xAA2F, 0xAB2F, 0x2A3D, 0x2A4C, 0x2A40, 0x2A4F,
+ 0xA922, 0x2A50, 0x2978, 0x297D, 0, 0, 0xAA36, 0xAB36,
+ 0x2A3E, 0x2A4D, 0x2A3F, 0x2A4E, 0x2A5A, 0x2A60, 0xAA3B, 0xAB3B,
+ 0xAA3D, 0xAB3D, 0xAA3C, 0, 0x2A5B, 0x2A61, 0xA924, 0x2A7D,
+ 0xAA47, 0xAB47, 0x2976, 0x297B, 0, 0, 0xAA46, 0xAB46,
+ 0xAA44, 0xA945, 0xA926, 0xA946, 0x2A5C, 0x2A62, 0xAA49, 0xAB49,
+ 0xA947, 0x2A3B, 0x2A4A, 0xAA4C, 0xAB4C, 0x2A24, 0x2A2F, 0xA929,
+};
+static const unsigned short utf8_to_euc_C5[] = {
+ 0xA949, 0xA928, 0xA948, 0xAA4D, 0xAB4D, 0xAA4F, 0xAB4F, 0xAA4E,
+ 0xAB4E, 0xA94A, 0xA92B, 0xA94B, 0xAA57, 0xAB57, 0, 0,
+ 0xAA56, 0xAB56, 0xA92D, 0xA94D, 0xAA59, 0xAB59, 0xAA5B, 0xAB5B,
+ 0xAA5A, 0xAB5A, 0xAA5C, 0xAB5C, 0xAA5D, 0xAB5D, 0xAA5F, 0xAB5F,
+ 0xAA5E, 0xAB5E, 0xAA61, 0xAB61, 0xAA60, 0xAB60, 0xA92F, 0xA94F,
+ 0xAA6C, 0xAB6C, 0xAA69, 0xAB69, 0xAA66, 0xAB66, 0xAA6B, 0xAB6B,
+ 0xAA68, 0xAB68, 0xAA6A, 0xAB6A, 0xAA71, 0xAB71, 0xAA74, 0xAB74,
+ 0xAA73, 0xAA75, 0xAB75, 0xAA77, 0xAB77, 0xAA76, 0xAB76, 0,
+};
+static const unsigned short utf8_to_euc_C5_x0213[] = {
+ 0xA949, 0x2A23, 0x2A2E, 0x2A41, 0x2A51, 0xAA4F, 0xAB4F, 0x2A42,
+ 0x2A52, 0xA94A, 0xA92B, 0x2A7A, 0x2979, 0x297E, 0, 0,
+ 0x2A43, 0x2A53, 0x2B2B, 0x2B2A, 0x2A39, 0x2A48, 0xAA5B, 0xAB5B,
+ 0x2A44, 0x2A54, 0x2A25, 0x2A30, 0x2A5D, 0x2A63, 0x2A27, 0x2A33,
+ 0x2A26, 0x2A32, 0x2A47, 0x2A57, 0x2A28, 0x2A34, 0xA92F, 0xA94F,
+ 0xAA6C, 0xAB6C, 0x2977, 0x297C, 0x2A5E, 0x2A64, 0x2A45, 0x2A55,
+ 0x2A46, 0x2A56, 0xAA6A, 0xAB6A, 0xAA71, 0xAB71, 0xAA74, 0xAB74,
+ 0xAA73, 0x2A29, 0x2A35, 0x2A2B, 0x2A38, 0x2A2A, 0x2A37, 0,
+};
+static const unsigned short utf8_to_euc_C6_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x2B29, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_C7[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xAA26, 0xAB26, 0xAA43,
+ 0xAB43, 0xAA55, 0xAB55, 0xAA67, 0xAB67, 0xAA70, 0xAB70, 0xAA6D,
+ 0xAB6D, 0xAA6F, 0xAB6F, 0xAA6E, 0xAB6E, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xAB39, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_C7_x0213[] = {
+ 0, 0, 0x2B24, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x286F, 0x2870, 0xAA43,
+ 0x2871, 0x2876, 0x2877, 0xAA67, 0x2878, 0xAA70, 0x2879, 0xAA6D,
+ 0x287A, 0xAA6F, 0x287B, 0xAA6E, 0x287C, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xAB39, 0, 0,
+ 0x2874, 0x2875, 0, 0, 0, 0x2B45, 0, 0,
+};
+static const unsigned short utf8_to_euc_C9_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2B33, 0x2B39, 0x2B3A, 0x2B25, 0x2B38, 0x2B3F, 0x2A6E, 0x2B26,
+ 0x2B2E, 0x2B30, 0x2B43, 0, 0x2B31, 0, 0x2B32, 0x2A75,
+ 0x2B28, 0x2A79, 0, 0, 0x2B36, 0x2B3C, 0x2B22, 0x2B42,
+ 0x2B2C, 0, 0, 0, 0x2A6A, 0x2A74, 0x2A6B, 0x2B34,
+ 0x2A7B, 0x2A65, 0x2A76, 0x2A6F, 0, 0x2B2F, 0, 0,
+ 0, 0x2A6C, 0x2B41, 0x2A73, 0, 0x2A70, 0x2A67, 0,
+};
+static const unsigned short utf8_to_euc_CA_x0213[] = {
+ 0, 0x2A7C, 0x2A71, 0x2A68, 0x2B27, 0, 0, 0,
+ 0x2A6D, 0x2B2D, 0x2B35, 0x2A66, 0x2B37, 0x2B3B, 0x2A78, 0,
+ 0x2A72, 0x2B40, 0x2A69, 0, 0x2B21, 0x2A7E, 0, 0,
+ 0x2B23, 0, 0, 0, 0, 0x2A77, 0, 0,
+ 0, 0x2B3E, 0x2B3D, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_CB[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0xA230,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xA22F, 0xA232, 0xA236, 0xA235, 0, 0xA233, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_CB_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0x2A31,
+ 0x2B53, 0, 0, 0, 0x2B54, 0, 0, 0,
+ 0x2B55, 0x2B56, 0, 0, 0, 0, 0, 0,
+ 0x2A22, 0x2A58, 0xA236, 0x2A2D, 0, 0x2A36, 0x2B71, 0,
+ 0, 0, 0, 0, 0, 0x2B60, 0x2B61, 0x2B62,
+ 0x2B63, 0x2B64, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_CC_x0213[] = {
+ 0x2B5C, 0x2B5A, 0x2B5F, 0x2B7D, 0x2B5B, 0, 0x2B57, 0,
+ 0x2B6D, 0, 0, 0x2B59, 0x2B5E, 0, 0, 0x2B5D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2B78, 0x2B79, 0x2B7E, 0, 0x2B6A, 0x2B76, 0x2B77, 0x2B6B,
+ 0x2B6C, 0, 0, 0, 0x2B72, 0x2B67, 0, 0,
+ 0, 0x2B6F, 0x2B7A, 0, 0x2B68, 0, 0, 0x2B70,
+ 0x2B73, 0, 0, 0, 0x2B75, 0, 0, 0,
+ 0, 0x2B69, 0x2B7B, 0x2B7C, 0x2B74, 0x2B6E, 0, 0,
+};
+static const unsigned short utf8_to_euc_CD_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x2B52, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_CE[] = {
+ 0, 0, 0, 0, 0xA238, 0xA239, 0xA661, 0,
+ 0xA662, 0xA663, 0xA664, 0, 0xA667, 0, 0xA669, 0xA66C,
+ 0xA676, 0x2621, 0x2622, 0x2623, 0x2624, 0x2625, 0x2626, 0x2627,
+ 0x2628, 0x2629, 0x262A, 0x262B, 0x262C, 0x262D, 0x262E, 0x262F,
+ 0x2630, 0x2631, 0, 0x2632, 0x2633, 0x2634, 0x2635, 0x2636,
+ 0x2637, 0x2638, 0xA665, 0xA66A, 0xA671, 0xA672, 0xA673, 0xA674,
+ 0xA67B, 0x2641, 0x2642, 0x2643, 0x2644, 0x2645, 0x2646, 0x2647,
+ 0x2648, 0x2649, 0x264A, 0x264B, 0x264C, 0x264D, 0x264E, 0x264F,
+};
+static const unsigned short utf8_to_euc_CF[] = {
+ 0x2650, 0x2651, 0xA678, 0x2652, 0x2653, 0x2654, 0x2655, 0x2656,
+ 0x2657, 0x2658, 0xA675, 0xA67A, 0xA677, 0xA679, 0xA67C, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_CF_x0213[] = {
+ 0x2650, 0x2651, 0x2659, 0x2652, 0x2653, 0x2654, 0x2655, 0x2656,
+ 0x2657, 0x2658, 0xA675, 0xA67A, 0xA677, 0xA679, 0xA67C, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_D0[] = {
+ 0, 0x2727, 0xA742, 0xA743, 0xA744, 0xA745, 0xA746, 0xA747,
+ 0xA748, 0xA749, 0xA74A, 0xA74B, 0xA74C, 0, 0xA74D, 0xA74E,
+ 0x2721, 0x2722, 0x2723, 0x2724, 0x2725, 0x2726, 0x2728, 0x2729,
+ 0x272A, 0x272B, 0x272C, 0x272D, 0x272E, 0x272F, 0x2730, 0x2731,
+ 0x2732, 0x2733, 0x2734, 0x2735, 0x2736, 0x2737, 0x2738, 0x2739,
+ 0x273A, 0x273B, 0x273C, 0x273D, 0x273E, 0x273F, 0x2740, 0x2741,
+ 0x2751, 0x2752, 0x2753, 0x2754, 0x2755, 0x2756, 0x2758, 0x2759,
+ 0x275A, 0x275B, 0x275C, 0x275D, 0x275E, 0x275F, 0x2760, 0x2761,
+};
+static const unsigned short utf8_to_euc_D1[] = {
+ 0x2762, 0x2763, 0x2764, 0x2765, 0x2766, 0x2767, 0x2768, 0x2769,
+ 0x276A, 0x276B, 0x276C, 0x276D, 0x276E, 0x276F, 0x2770, 0x2771,
+ 0, 0x2757, 0xA772, 0xA773, 0xA774, 0xA775, 0xA776, 0xA777,
+ 0xA778, 0xA779, 0xA77A, 0xA77B, 0xA77C, 0, 0xA77D, 0xA77E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E1B8_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x2872, 0x2873,
+};
+static const unsigned short utf8_to_euc_E1BD_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2B46, 0x2B47, 0x2B50, 0x2B51, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E280[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x213E, 0, 0, 0, 0x213D, 0x213D, 0x2142, 0,
+ 0x2146, 0x2147, 0, 0, 0x2148, 0x2149, 0, 0,
+ 0x2277, 0x2278, 0, 0, 0, 0x2145, 0x2144, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2273, 0, 0x216C, 0x216D, 0, 0, 0, 0,
+ 0, 0, 0, 0x2228, 0, 0, 0x2131, 0,
+};
+static const unsigned short utf8_to_euc_E280_ms[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x213E, 0, 0, 0, 0x213D, 0x213D, 0x2142, 0,
+ 0x2146, 0x2147, 0, 0, 0x2148, 0x2149, 0, 0,
+ 0x2277, 0x2278, 0, 0, 0, 0x2145, 0x2144, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2273, 0, 0x216C, 0x216D, 0, 0, 0, 0,
+ 0, 0, 0, 0x2228, 0, 0, 0x7E, 0,
+};
+static const unsigned short utf8_to_euc_E280_932[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x213E, 0, 0, 0, 0, 0x213D, 0, 0,
+ 0x2146, 0x2147, 0, 0, 0x2148, 0x2149, 0, 0,
+ 0x2277, 0x2278, 0, 0, 0, 0x2145, 0x2144, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2273, 0, 0x216C, 0x216D, 0, 0, 0, 0,
+ 0, 0, 0, 0x2228, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E280_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x213E, 0, 0, 0x237C, 0x213D, 0x213D, 0x2142, 0,
+ 0x2146, 0x2147, 0, 0, 0x2148, 0x2149, 0, 0,
+ 0x2277, 0x2278, 0x2340, 0, 0, 0x2145, 0x2144, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2273, 0, 0x216C, 0x216D, 0, 0, 0, 0,
+ 0, 0, 0, 0x2228, 0x286B, 0, 0x2131, 0x2B58,
+};
+static const unsigned short utf8_to_euc_E281_x0213[] = {
+ 0, 0, 0x2C7E, 0, 0, 0, 0, 0x286C,
+ 0x286D, 0x286E, 0, 0, 0, 0, 0, 0,
+ 0, 0x2C7D, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E282_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x2921, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E284[] = {
+ 0, 0, 0, 0x216E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x2D62, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x2D64, 0xA26F, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x2272, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E284_mac[] = {
+ 0, 0, 0, 0x216E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x2B7B, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x2B7D, 0x00FE, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x2272, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E284_x0213[] = {
+ 0, 0, 0, 0x216E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x235D,
+ 0, 0, 0, 0x235F, 0, 0, 0x2D62, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x2D64, 0xA26F, 0, 0, 0, 0, 0x2360,
+ 0, 0, 0, 0x2272, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x235C, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E285[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2D35, 0x2D36, 0x2D37, 0x2D38, 0x2D39, 0x2D3A, 0x2D3B, 0x2D3C,
+ 0x2D3D, 0x2D3E, 0, 0, 0, 0, 0, 0,
+ 0xF373, 0xF374, 0xF375, 0xF376, 0xF377, 0xF378, 0xF379, 0xF37A,
+ 0xF37B, 0xF37C, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E285_mac[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2A21, 0x2A22, 0x2A23, 0x2A24, 0x2A25, 0x2A26, 0x2A27, 0x2A28,
+ 0x2A29, 0x2A2A, 0, 0, 0, 0, 0, 0,
+ 0x2A35, 0x2A36, 0x2A37, 0x2A38, 0x2A39, 0x2A3A, 0x2A3B, 0x2A3C,
+ 0x2A3D, 0x2A3E, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E285_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x2778, 0x2779, 0x277A, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2D35, 0x2D36, 0x2D37, 0x2D38, 0x2D39, 0x2D3A, 0x2D3B, 0x2D3C,
+ 0x2D3D, 0x2D3E, 0x2D3F, 0x2D57, 0, 0, 0, 0,
+ 0x2C35, 0x2C36, 0x2C37, 0x2C38, 0x2C39, 0x2C3A, 0x2C3B, 0x2C3C,
+ 0x2C3D, 0x2C3E, 0x2C3F, 0x2C40, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E286[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x222B, 0x222C, 0x222A, 0x222D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E286_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x222B, 0x222C, 0x222A, 0x222D, 0x2271, 0, 0x2327, 0x2325,
+ 0x2326, 0x2328, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E287[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x224D, 0, 0x224E, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E287_x0213[] = {
+ 0, 0, 0, 0, 0x2329, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x224D, 0, 0x224E, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x232B, 0x232C,
+ 0x232A, 0x232D, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E288[] = {
+ 0x224F, 0, 0x225F, 0x2250, 0, 0, 0, 0x2260,
+ 0x223A, 0, 0, 0x223B, 0, 0, 0, 0,
+ 0, 0x2D74, 0x215D, 0, 0, 0, 0, 0,
+ 0, 0, 0x2265, 0, 0, 0x2267, 0x2167, 0x2D78,
+ 0x225C, 0, 0, 0, 0, 0x2142, 0, 0x224A,
+ 0x224B, 0x2241, 0x2240, 0x2269, 0x226A, 0, 0x2D73, 0,
+ 0, 0, 0, 0, 0x2168, 0x2268, 0, 0,
+ 0, 0, 0, 0, 0, 0x2266, 0, 0,
+};
+static const unsigned short utf8_to_euc_E288_932[] = {
+ 0x224F, 0, 0x225F, 0x2250, 0, 0, 0, 0x2260,
+ 0x223A, 0, 0, 0x223B, 0, 0, 0, 0,
+ 0, 0x2D74, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2265, 0, 0, 0x2267, 0x2167, 0x2D78,
+ 0x225C, 0, 0, 0, 0, 0x2142, 0, 0x224A,
+ 0x224B, 0x2241, 0x2240, 0x2269, 0x226A, 0, 0x2D73, 0,
+ 0, 0, 0, 0, 0x2168, 0x2268, 0, 0,
+ 0, 0, 0, 0, 0, 0x2266, 0, 0,
+};
+static const unsigned short utf8_to_euc_E288_mac[] = {
+ 0x224F, 0, 0x225F, 0x2250, 0, 0, 0, 0x2260,
+ 0x223A, 0, 0, 0x223B, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2265, 0, 0, 0x2267, 0x2167, 0x2F22,
+ 0x225C, 0, 0, 0, 0, 0x2142, 0, 0x224A,
+ 0x224B, 0x2241, 0x2240, 0x2269, 0x226A, 0, 0x2F21, 0,
+ 0, 0, 0, 0, 0x2168, 0x2268, 0, 0,
+ 0, 0, 0, 0, 0, 0x2266, 0, 0,
+};
+static const unsigned short utf8_to_euc_E288_x0213[] = {
+ 0x224F, 0, 0x225F, 0x2250, 0, 0x2247, 0, 0x2260,
+ 0x223A, 0x2246, 0, 0x223B, 0, 0, 0, 0,
+ 0, 0x2D74, 0x215D, 0x235B, 0, 0, 0, 0,
+ 0, 0, 0x2265, 0, 0, 0x2267, 0x2167, 0x2D78,
+ 0x225C, 0, 0, 0, 0, 0x2254, 0x2255, 0x224A,
+ 0x224B, 0x2241, 0x2240, 0x2269, 0x226A, 0, 0x2D73, 0,
+ 0, 0, 0, 0, 0x2168, 0x2268, 0, 0,
+ 0, 0, 0, 0, 0, 0x2266, 0, 0,
+};
+static const unsigned short utf8_to_euc_E289[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2262, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2162, 0x2261, 0, 0, 0, 0, 0x2165, 0x2166,
+ 0, 0, 0x2263, 0x2264, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E289_x0213[] = {
+ 0, 0, 0, 0x226C, 0, 0x226D, 0, 0,
+ 0x226E, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2262, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2162, 0x2261, 0x226B, 0, 0, 0, 0x2165, 0x2166,
+ 0, 0, 0x2263, 0x2264, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x226F, 0x2270,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E28A[] = {
+ 0, 0, 0x223E, 0x223F, 0, 0, 0x223C, 0x223D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x225D, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x2D79,
+};
+static const unsigned short utf8_to_euc_E28A_mac[] = {
+ 0, 0, 0x223E, 0x223F, 0, 0, 0x223C, 0x223D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x225D, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x2F23,
+};
+static const unsigned short utf8_to_euc_E28A_x0213[] = {
+ 0, 0, 0x223E, 0x223F, 0x2242, 0x2243, 0x223C, 0x223D,
+ 0, 0, 0x2244, 0x2245, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x2251, 0x2252, 0x2253,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x225D, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x2D79,
+};
+static const unsigned short utf8_to_euc_E28B_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2776, 0x2777, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E28C[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x225E, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E28C_x0213[] = {
+ 0, 0, 0, 0, 0, 0x2248, 0x2249, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x225E, 0, 0, 0, 0, 0,
+ 0x277C, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E28E_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x2742, 0x2743,
+};
+static const unsigned short utf8_to_euc_E28F_x0213[] = {
+ 0x2744, 0x2745, 0x2746, 0x2747, 0x2748, 0x2749, 0x274A, 0x274B,
+ 0x274C, 0x274D, 0x274E, 0x274F, 0x2750, 0, 0x277E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E290_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x277D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E291[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2D21, 0x2D22, 0x2D23, 0x2D24, 0x2D25, 0x2D26, 0x2D27, 0x2D28,
+ 0x2D29, 0x2D2A, 0x2D2B, 0x2D2C, 0x2D2D, 0x2D2E, 0x2D2F, 0x2D30,
+ 0x2D31, 0x2D32, 0x2D33, 0x2D34, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E291_mac[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2921, 0x2922, 0x2923, 0x2924, 0x2925, 0x2926, 0x2927, 0x2928,
+ 0x2929, 0x292A, 0x292B, 0x292C, 0x292D, 0x292E, 0x292F, 0x2930,
+ 0x2931, 0x2932, 0x2933, 0x2934, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E293_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2C41, 0x2C42, 0x2C43, 0x2C44, 0x2C45, 0x2C46, 0x2C47, 0x2C48,
+ 0x2C49, 0x2C4A, 0x2C4B, 0x2C4C, 0x2C4D, 0x2C4E, 0x2C4F, 0x2C50,
+ 0x2C51, 0x2C52, 0x2C53, 0x2C54, 0x2C55, 0x2C56, 0x2C57, 0x2C58,
+ 0x2C59, 0x2C5A, 0, 0x2C2B, 0x2C2C, 0x2C2D, 0x2C2E, 0x2C2F,
+ 0x2C30, 0x2C31, 0x2C32, 0x2C33, 0x2C34, 0x265A, 0x265B, 0x265C,
+ 0x265D, 0x265E, 0x265F, 0x2660, 0x2661, 0x2662, 0x2663, 0,
+};
+static const unsigned short utf8_to_euc_E294[] = {
+ 0x2821, 0x282C, 0x2822, 0x282D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x2823, 0, 0, 0x282E,
+ 0x2824, 0, 0, 0x282F, 0x2826, 0, 0, 0x2831,
+ 0x2825, 0, 0, 0x2830, 0x2827, 0x283C, 0, 0,
+ 0x2837, 0, 0, 0x2832, 0x2829, 0x283E, 0, 0,
+ 0x2839, 0, 0, 0x2834, 0x2828, 0, 0, 0x2838,
+ 0x283D, 0, 0, 0x2833, 0x282A, 0, 0, 0x283A,
+ 0x283F, 0, 0, 0x2835, 0x282B, 0, 0, 0x283B,
+};
+static const unsigned short utf8_to_euc_E295[] = {
+ 0, 0, 0x2840, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x2836, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E296[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2223, 0x2222, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2225, 0x2224, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x2227, 0x2226, 0, 0,
+};
+static const unsigned short utf8_to_euc_E296_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2223, 0x2222, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x266D, 0x2225, 0x2224, 0, 0, 0x2322, 0x2321,
+ 0, 0, 0, 0, 0x2227, 0x2226, 0, 0,
+};
+static const unsigned short utf8_to_euc_E297[] = {
+ 0, 0, 0, 0, 0, 0, 0x2221, 0x217E,
+ 0, 0, 0, 0x217B, 0, 0, 0x217D, 0x217C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x227E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E297_x0213[] = {
+ 0x2324, 0x2323, 0, 0, 0, 0, 0x2221, 0x217E,
+ 0, 0x233B, 0, 0x217B, 0, 0, 0x217D, 0x217C,
+ 0x2867, 0x2868, 0x2869, 0x286A, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x233F, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x227E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E298[] = {
+ 0, 0, 0, 0, 0, 0x217A, 0x2179, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E298_x0213[] = {
+ 0x2668, 0x2669, 0x266A, 0x266B, 0, 0x217A, 0x2179, 0,
+ 0, 0, 0, 0, 0, 0, 0x2667, 0,
+ 0, 0, 0, 0, 0, 0, 0x2664, 0x2665,
+ 0, 0, 0, 0, 0, 0, 0x2D7E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E299[] = {
+ 0x216A, 0, 0x2169, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2276, 0, 0, 0x2275, 0, 0x2274,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E299_x0213[] = {
+ 0x216A, 0, 0x2169, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x263A, 0x263D, 0x263B, 0x2640, 0x2639, 0x263E, 0x263C, 0x263F,
+ 0x266C, 0x227D, 0x2276, 0x227B, 0x227C, 0x2275, 0x227A, 0x2274,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E29C_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x277B, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E29D_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x2D7D, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x2C21, 0x2C22,
+ 0x2C23, 0x2C24, 0x2C25, 0x2C26, 0x2C27, 0x2C28, 0x2C29, 0x2C2A,
+};
+static const unsigned short utf8_to_euc_E2A4_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x232E, 0x232F, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E2A6_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x233A,
+};
+static const unsigned short utf8_to_euc_E2A7_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x237D, 0x237E, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E380[] = {
+ 0x2121, 0x2122, 0x2123, 0x2137, 0, 0x2139, 0x213A, 0x213B,
+ 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159,
+ 0x215A, 0x215B, 0x2229, 0x222E, 0x214C, 0x214D, 0, 0,
+ 0, 0, 0, 0, 0x2141, 0x2D60, 0, 0x2D61,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E380_932[] = {
+ 0x2121, 0x2122, 0x2123, 0x2137, 0, 0x2139, 0x213A, 0x213B,
+ 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159,
+ 0x215A, 0x215B, 0x2229, 0x222E, 0x214C, 0x214D, 0, 0,
+ 0, 0, 0, 0, 0, 0x2D60, 0, 0x2D61,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E380_x0213[] = {
+ 0x2121, 0x2122, 0x2123, 0x2137, 0, 0x2139, 0x213A, 0x213B,
+ 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159,
+ 0x215A, 0x215B, 0x2229, 0x222E, 0x214C, 0x214D, 0x225A, 0x225B,
+ 0x2258, 0x2259, 0, 0, 0x2141, 0x2D60, 0, 0x2D61,
+ 0x2666, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x2233, 0x2234, 0x2235, 0, 0,
+ 0, 0, 0, 0x2236, 0x2237, 0x233C, 0, 0,
+};
+static const unsigned short utf8_to_euc_E381[] = {
+ 0, 0x2421, 0x2422, 0x2423, 0x2424, 0x2425, 0x2426, 0x2427,
+ 0x2428, 0x2429, 0x242A, 0x242B, 0x242C, 0x242D, 0x242E, 0x242F,
+ 0x2430, 0x2431, 0x2432, 0x2433, 0x2434, 0x2435, 0x2436, 0x2437,
+ 0x2438, 0x2439, 0x243A, 0x243B, 0x243C, 0x243D, 0x243E, 0x243F,
+ 0x2440, 0x2441, 0x2442, 0x2443, 0x2444, 0x2445, 0x2446, 0x2447,
+ 0x2448, 0x2449, 0x244A, 0x244B, 0x244C, 0x244D, 0x244E, 0x244F,
+ 0x2450, 0x2451, 0x2452, 0x2453, 0x2454, 0x2455, 0x2456, 0x2457,
+ 0x2458, 0x2459, 0x245A, 0x245B, 0x245C, 0x245D, 0x245E, 0x245F,
+};
+static const unsigned short utf8_to_euc_E382[] = {
+ 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467,
+ 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E, 0x246F,
+ 0x2470, 0x2471, 0x2472, 0x2473, 0, 0, 0, 0,
+ 0, 0, 0, 0x212B, 0x212C, 0x2135, 0x2136, 0,
+ 0, 0x2521, 0x2522, 0x2523, 0x2524, 0x2525, 0x2526, 0x2527,
+ 0x2528, 0x2529, 0x252A, 0x252B, 0x252C, 0x252D, 0x252E, 0x252F,
+ 0x2530, 0x2531, 0x2532, 0x2533, 0x2534, 0x2535, 0x2536, 0x2537,
+ 0x2538, 0x2539, 0x253A, 0x253B, 0x253C, 0x253D, 0x253E, 0x253F,
+};
+static const unsigned short utf8_to_euc_E382_932[] = {
+ 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467,
+ 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E, 0x246F,
+ 0x2470, 0x2471, 0x2472, 0x2473, 0x2574, 0, 0, 0,
+ 0, 0, 0, 0x212B, 0x212C, 0x2135, 0x2136, 0,
+ 0, 0x2521, 0x2522, 0x2523, 0x2524, 0x2525, 0x2526, 0x2527,
+ 0x2528, 0x2529, 0x252A, 0x252B, 0x252C, 0x252D, 0x252E, 0x252F,
+ 0x2530, 0x2531, 0x2532, 0x2533, 0x2534, 0x2535, 0x2536, 0x2537,
+ 0x2538, 0x2539, 0x253A, 0x253B, 0x253C, 0x253D, 0x253E, 0x253F,
+};
+static const unsigned short utf8_to_euc_E382_x0213[] = {
+ 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467,
+ 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E, 0x246F,
+ 0x2470, 0x2471, 0x2472, 0x2473, 0x2474, 0x2475, 0x2476, 0,
+ 0, 0, 0, 0x212B, 0x212C, 0x2135, 0x2136, 0x2239,
+ 0x237B, 0x2521, 0x2522, 0x2523, 0x2524, 0x2525, 0x2526, 0x2527,
+ 0x2528, 0x2529, 0x252A, 0x252B, 0x252C, 0x252D, 0x252E, 0x252F,
+ 0x2530, 0x2531, 0x2532, 0x2533, 0x2534, 0x2535, 0x2536, 0x2537,
+ 0x2538, 0x2539, 0x253A, 0x253B, 0x253C, 0x253D, 0x253E, 0x253F,
+};
+static const unsigned short utf8_to_euc_E383[] = {
+ 0x2540, 0x2541, 0x2542, 0x2543, 0x2544, 0x2545, 0x2546, 0x2547,
+ 0x2548, 0x2549, 0x254A, 0x254B, 0x254C, 0x254D, 0x254E, 0x254F,
+ 0x2550, 0x2551, 0x2552, 0x2553, 0x2554, 0x2555, 0x2556, 0x2557,
+ 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E, 0x255F,
+ 0x2560, 0x2561, 0x2562, 0x2563, 0x2564, 0x2565, 0x2566, 0x2567,
+ 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x256D, 0x256E, 0x256F,
+ 0x2570, 0x2571, 0x2572, 0x2573, 0x2574, 0x2575, 0x2576, 0,
+ 0, 0, 0, 0x2126, 0x213C, 0x2133, 0x2134, 0,
+};
+static const unsigned short utf8_to_euc_E383_x0213[] = {
+ 0x2540, 0x2541, 0x2542, 0x2543, 0x2544, 0x2545, 0x2546, 0x2547,
+ 0x2548, 0x2549, 0x254A, 0x254B, 0x254C, 0x254D, 0x254E, 0x254F,
+ 0x2550, 0x2551, 0x2552, 0x2553, 0x2554, 0x2555, 0x2556, 0x2557,
+ 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E, 0x255F,
+ 0x2560, 0x2561, 0x2562, 0x2563, 0x2564, 0x2565, 0x2566, 0x2567,
+ 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x256D, 0x256E, 0x256F,
+ 0x2570, 0x2571, 0x2572, 0x2573, 0x2574, 0x2575, 0x2576, 0x2772,
+ 0x2773, 0x2774, 0x2775, 0x2126, 0x213C, 0x2133, 0x2134, 0x2238,
+};
+static const unsigned short utf8_to_euc_E387_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x266E, 0x266F, 0x2670, 0x2671, 0x2672, 0x2673, 0x2674, 0x2675,
+ 0x2676, 0x2677, 0x2679, 0x267A, 0x267B, 0x267C, 0x267D, 0x267E,
+};
+static const unsigned short utf8_to_euc_E388[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x2D6A, 0x2D6B, 0, 0, 0, 0, 0,
+ 0, 0x2D6C, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E388_mac[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x2D2E, 0x2D31, 0, 0, 0, 0, 0,
+ 0, 0x2D2C, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E389_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x2841, 0x2842, 0x2843, 0x2844, 0x2845, 0x2846, 0x2847,
+ 0x2848, 0x2849, 0x284A, 0x284B, 0x284C, 0x284D, 0x284E, 0x284F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E38A[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x2D65, 0x2D66, 0x2D67, 0x2D68,
+ 0x2D69, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E38A_mac[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x2D73, 0x2D74, 0x2D75, 0x2D76,
+ 0x2D77, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E38A_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x2D65, 0x2D66, 0x2D67, 0x2D68,
+ 0x2D69, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x2850, 0x2851, 0x2852, 0x2853, 0x2854, 0x2855, 0x2856,
+ 0x2857, 0x2858, 0x2859, 0x285A, 0x285B, 0x285C, 0x285D, 0x285E,
+};
+static const unsigned short utf8_to_euc_E38B_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2C5B, 0x2C5C, 0x2C5D, 0x2C5E, 0x2C5F, 0x2C60, 0x2C61, 0x2C62,
+ 0x2C63, 0x2C64, 0x2C65, 0x2C66, 0x2C67, 0x2C68, 0x2C69, 0x2C6A,
+ 0x2C6B, 0x2C6C, 0x2C6D, 0x2C6E, 0, 0x2C71, 0, 0,
+ 0, 0x2C70, 0, 0, 0x2C73, 0x2C72, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2C6F, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E38C[] = {
+ 0, 0, 0, 0x2D46, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x2D4A, 0, 0,
+ 0, 0, 0, 0, 0x2D41, 0, 0, 0,
+ 0x2D44, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2D42, 0x2D4C, 0, 0, 0x2D4B, 0x2D45,
+ 0, 0, 0, 0x2D4D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x2D47, 0,
+ 0, 0, 0, 0x2D4F, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E38C_mac[] = {
+ 0, 0, 0, 0x2E29, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x2E32, 0, 0,
+ 0, 0, 0, 0, 0x2E24, 0, 0, 0,
+ 0x2E2B, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x2E22, 0x2E34, 0, 0, 0x2E35, 0x2E2D,
+ 0, 0, 0, 0x2E37, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x2E2A, 0,
+ 0, 0, 0, 0x2E36, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E38D[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x2D40, 0x2D4E, 0, 0, 0x2D43, 0, 0,
+ 0, 0x2D48, 0, 0, 0, 0, 0, 0x2D49,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x2D5F, 0x2D6F, 0x2D6E, 0x2D6D, 0,
+};
+static const unsigned short utf8_to_euc_E38D_mac[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x2E21, 0x2E2F, 0, 0, 0x2E23, 0, 0,
+ 0, 0x2E2E, 0, 0, 0, 0, 0, 0x2E31,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x2E6A, 0x2E69, 0x2E68, 0x2E67, 0,
+};
+static const unsigned short utf8_to_euc_E38E[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x2D53, 0x2D54,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x2D50, 0x2D51, 0x2D52, 0,
+ 0, 0x2D56, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E38E_mac[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x2B2B, 0x2B2D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x2B21, 0x2B23, 0x2B29, 0,
+ 0, 0x2B27, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E38F[] = {
+ 0, 0, 0, 0, 0x2D55, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x2D63, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E38F_mac[] = {
+ 0, 0, 0, 0, 0x2B2E, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x2B7C, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E38F_x0213[] = {
+ 0, 0, 0, 0, 0x2D55, 0, 0, 0,
+ 0, 0, 0, 0x235E, 0, 0x2D63, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E390_x0213[] = {
+ 0, 0, 0x2E23, 0, 0, 0, 0xA12D, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xA132, 0, 0xA133, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E391_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xA15E, 0, 0xA156, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E392_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xA17E, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x2E53, 0, 0,
+ 0, 0, 0, 0, 0xA32B, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E393_x0213[] = {
+ 0, 0xF468, 0, 0, 0, 0, 0, 0xA32F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x2E5B, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E394_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xA348,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E395_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xA35D, 0xA35E, 0,
+ 0, 0, 0, 0xA361, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xA367, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E396_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xA423, 0,
+ 0xA426, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E397_x0213[] = {
+ 0, 0, 0, 0, 0, 0xA42F, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xA438, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xA442, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E398_x0213[] = {
+ 0, 0, 0, 0, 0, 0xA44A, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E399_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xA479, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E39A_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xA53F, 0, 0, 0, 0, 0xA543, 0,
+ 0, 0xA541, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E39B_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xA557,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E39D_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xA823, 0xA825, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xA829, 0xA828, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xA82C, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E39E_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x4F5F, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E39F_x0213[] = {
+ 0, 0xA83E, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x4F6F, 0, 0, 0, 0, 0,
+ 0xA856, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xA859, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xA85C, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3A0_x0213[] = {
+ 0xA85E, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xA86F,
+ 0, 0, 0, 0, 0, 0, 0xA871, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3A1_x0213[] = {
+ 0xA874, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xA879, 0, 0, 0,
+ 0, 0xA87B, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3A3_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xAC3B, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3A4_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xAC46,
+ 0, 0, 0xAC4A, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3A5_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xAC60,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3A9_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xAD5B, 0,
+ 0, 0, 0, 0xAD5F, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3AB_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xAD71, 0xAE36,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xAD7C, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3AC_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xAE2E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xAE32, 0, 0xAE34, 0, 0, 0,
+ 0, 0, 0x7549, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3AD_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xAE6D, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xAE65,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3AE_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0xAF28,
+ 0xAF29, 0, 0, 0, 0, 0xAF2C, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xAF34, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x757E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3AF_x0213[] = {
+ 0, 0, 0, 0x7621, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xAF48, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xAF5D, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3B0_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x763A,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xAF77, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3B3_x0213[] = {
+ 0, 0, 0, 0xEE3B, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xEE42, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3B4_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xEE71, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xEE7E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3B5_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xEF40, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3B6_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xEF54, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3B7_x0213[] = {
+ 0xEF70, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xEF77, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3B8_x0213[] = {
+ 0, 0, 0, 0, 0, 0xF028, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x7766,
+};
+static const unsigned short utf8_to_euc_E3B9_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xF03F, 0, 0, 0, 0, 0, 0xF041, 0,
+ 0xF042, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3BA_x0213[] = {
+ 0, 0, 0, 0xF049, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xF050, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3BD_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xF134,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x784D, 0, 0, 0xF146, 0, 0xF148,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3BE_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xF15C, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E3BF_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xF167, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xF16C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E480_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xF222, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E481_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xF22D, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E482_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xF239, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E484_x0213[] = {
+ 0, 0, 0, 0, 0, 0xF264, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E485_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xF274, 0, 0, 0, 0, 0, 0, 0xF277,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xF27D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E486_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xF333, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xF337,
+};
+static const unsigned short utf8_to_euc_E487_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xF347, 0,
+ 0, 0, 0, 0, 0, 0, 0xF34B, 0,
+ 0, 0, 0, 0xF348, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E488_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0xF353,
+ 0, 0, 0, 0, 0, 0, 0xF357, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E489_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x796D, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E48B_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0xF42B, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xF436, 0,
+ 0, 0, 0, 0, 0, 0xF43B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E48C_x0213[] = {
+ 0, 0, 0xF44E, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xF45D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E48D_x0213[] = {
+ 0, 0, 0, 0xF461, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E48F_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xF53E, 0,
+ 0xF542, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E490_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xF548, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xF54A,
+ 0, 0, 0, 0, 0xF54C, 0, 0, 0,
+ 0, 0, 0xF54F, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E491_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x7A59, 0, 0, 0, 0,
+ 0, 0, 0, 0x7A5A, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xF56C, 0,
+ 0, 0, 0xF56E, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E492_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xF577, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xF635, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xF632, 0,
+};
+static const unsigned short utf8_to_euc_E493_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xF634, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E494_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xF659, 0, 0, 0, 0, 0xF654, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xF66D, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E495_x0213[] = {
+ 0, 0, 0, 0xF66E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E496_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x7B51, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xF74F, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E497_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xF76C, 0, 0,
+ 0, 0, 0x7B60, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E498_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xF824,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E499_x0213[] = {
+ 0, 0xF83A, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xF843, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E49A_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xF84E, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xF853,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E49C_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xF86B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E49D_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xF929, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E49F_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xF93F, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4A0_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xF949, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4A1_x0213[] = {
+ 0, 0, 0, 0, 0x7C4B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xF95C, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4A2_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFA27, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4A6_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x7D58, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4A7_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xFB6A,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFB70, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4A8_x0213[] = {
+ 0, 0, 0, 0, 0xFB75, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFB78, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4AA_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFC37, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4AC_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFC55, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4AF_x0213[] = {
+ 0, 0, 0xFD26, 0, 0, 0, 0, 0,
+ 0, 0, 0xFD28, 0, 0, 0, 0, 0,
+ 0, 0, 0xFD2A, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFD31, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4B0_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x7E3E,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFD3F, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4B3_x0213[] = {
+ 0, 0, 0, 0, 0xFE2A, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFE2D, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4B4_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0xFE4B,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4B5_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xFE60,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4B8[] = {
+ 0x306C, 0x437A, 0xB021, 0x3C37, 0xB022, 0xB023, 0, 0x4B7C,
+ 0x3E66, 0x3B30, 0x3E65, 0x323C, 0xB024, 0x4954, 0x4D3F, 0,
+ 0x5022, 0x312F, 0xB025, 0, 0x336E, 0x5023, 0x4024, 0x5242,
+ 0x3556, 0x4A3A, 0, 0, 0, 0, 0x3E67, 0xB026,
+ 0, 0x4E3E, 0, 0xB027, 0xB028, 0, 0x4A42, 0,
+ 0xB029, 0, 0x5024, 0xB02A, 0, 0x4366, 0xB02B, 0xB02C,
+ 0xB02D, 0x5025, 0x367A, 0, 0, 0xB02E, 0x5026, 0,
+ 0x345D, 0x4330, 0, 0x3C67, 0x5027, 0, 0, 0x5028,
+};
+static const unsigned short utf8_to_euc_E4B8_x0213[] = {
+ 0x306C, 0x437A, 0xA122, 0x3C37, 0xB022, 0xB023, 0, 0x4B7C,
+ 0x3E66, 0x3B30, 0x3E65, 0x323C, 0xB024, 0x4954, 0x4D3F, 0xA123,
+ 0x5022, 0x312F, 0xA124, 0, 0x336E, 0x5023, 0x4024, 0x5242,
+ 0x3556, 0x4A3A, 0, 0, 0, 0, 0x3E67, 0xB026,
+ 0, 0x4E3E, 0, 0xB027, 0xB028, 0, 0x4A42, 0,
+ 0x2E24, 0xA125, 0x5024, 0xA126, 0xF02E, 0x4366, 0xA127, 0x2E25,
+ 0x2E26, 0x5025, 0x367A, 0, 0, 0xB02E, 0x5026, 0,
+ 0x345D, 0x4330, 0, 0x3C67, 0x5027, 0, 0, 0x5028,
+};
+static const unsigned short utf8_to_euc_E4B9[] = {
+ 0xB02F, 0xB030, 0x5029, 0x4735, 0xB031, 0x3557, 0, 0xB032,
+ 0, 0, 0, 0x4737, 0, 0x4663, 0x3843, 0x4B33,
+ 0, 0xB033, 0, 0, 0, 0x6949, 0x502A, 0x3E68,
+ 0x502B, 0x3235, 0xB034, 0, 0xB035, 0x3665, 0x3870, 0x4C69,
+ 0, 0, 0x5626, 0xB036, 0, 0, 0, 0,
+ 0xB037, 0xB038, 0, 0, 0, 0, 0, 0,
+ 0, 0x4D70, 0, 0x467D, 0xB039, 0xB03A, 0, 0,
+ 0, 0xB03B, 0, 0, 0, 0, 0x3425, 0xB03C,
+};
+static const unsigned short utf8_to_euc_E4B9_x0213[] = {
+ 0xA128, 0xB030, 0x5029, 0x4735, 0xB031, 0x3557, 0, 0xA129,
+ 0xA12A, 0, 0, 0x4737, 0, 0x4663, 0x3843, 0x4B33,
+ 0, 0xA12C, 0, 0, 0, 0x6949, 0x502A, 0x3E68,
+ 0x502B, 0x3235, 0xA12F, 0, 0xB035, 0x3665, 0x3870, 0x4C69,
+ 0, 0, 0x5626, 0xB036, 0, 0, 0, 0,
+ 0xB037, 0xA130, 0, 0, 0, 0, 0, 0,
+ 0, 0x4D70, 0, 0x467D, 0xB039, 0xB03A, 0, 0,
+ 0, 0xB03B, 0, 0, 0, 0, 0x3425, 0xB03C,
+};
+static const unsigned short utf8_to_euc_E4BA[] = {
+ 0x3535, 0, 0x502C, 0, 0, 0x502D, 0x4E3B, 0,
+ 0x4D3D, 0x4168, 0x502F, 0x3B76, 0x4673, 0xB03D, 0x5032, 0,
+ 0, 0x313E, 0x385F, 0, 0x385E, 0x3066, 0xB03E, 0xB03F,
+ 0x4F4B, 0x4F4A, 0, 0x3A33, 0x3021, 0xB040, 0x5033, 0x5034,
+ 0x5035, 0x4B34, 0x5036, 0, 0x3872, 0x3067, 0x4B72, 0,
+ 0x357C, 0, 0, 0x357D, 0x357E, 0x4462, 0x4E3C, 0xB041,
+ 0x5037, 0, 0, 0x5038, 0, 0, 0x5039, 0,
+ 0, 0xB042, 0x3F4D, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4BA_x0213[] = {
+ 0x3535, 0, 0x502C, 0, 0, 0x502D, 0x4E3B, 0,
+ 0x4D3D, 0x4168, 0x502F, 0x3B76, 0x4673, 0x2E27, 0x5032, 0,
+ 0, 0x313E, 0x385F, 0, 0x385E, 0x3066, 0xB03E, 0xB03F,
+ 0x4F4B, 0x4F4A, 0, 0x3A33, 0x3021, 0xA131, 0x5033, 0x5034,
+ 0x5035, 0x4B34, 0x5036, 0, 0x3872, 0x3067, 0x4B72, 0,
+ 0x357C, 0, 0, 0x357D, 0x357E, 0x4462, 0x4E3C, 0xB041,
+ 0x5037, 0, 0, 0x5038, 0, 0, 0x5039, 0,
+ 0, 0xA134, 0x3F4D, 0xA135, 0xA137, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E4BB[] = {
+ 0x3D3A, 0x3F4E, 0x503E, 0xB043, 0x503C, 0, 0x503D, 0x3558,
+ 0, 0, 0x3A23, 0x3270, 0, 0x503B, 0x503A, 0x4A29,
+ 0xB044, 0, 0, 0, 0x3B46, 0x3B45, 0x423E, 0x503F,
+ 0x4955, 0x4067, 0xB045, 0xB046, 0, 0x2138, 0x5040, 0x5042,
+ 0xB047, 0xB048, 0xB049, 0x4265, 0x4E61, 0x304A, 0, 0,
+ 0xB04A, 0, 0, 0, 0, 0x5041, 0x323E, 0xB04B,
+ 0x3644, 0xB04C, 0x4367, 0xB04D, 0, 0xB04E, 0x376F, 0x5043,
+ 0, 0, 0, 0x4724, 0xF42F, 0xB04F, 0xB050, 0xB051,
+};
+static const unsigned short utf8_to_euc_E4BB_x0213[] = {
+ 0x3D3A, 0x3F4E, 0x503E, 0xA138, 0x503C, 0, 0x503D, 0x3558,
+ 0xA139, 0, 0x3A23, 0x3270, 0, 0x503B, 0x503A, 0x4A29,
+ 0xA13A, 0, 0, 0, 0x3B46, 0x3B45, 0x423E, 0x503F,
+ 0x4955, 0x4067, 0xA13C, 0xB046, 0, 0x2138, 0x5040, 0x5042,
+ 0xB047, 0x2E28, 0xB049, 0x4265, 0x4E61, 0x304A, 0, 0,
+ 0xB04A, 0, 0, 0xA13B, 0, 0x5041, 0x323E, 0xB04B,
+ 0x3644, 0xA13D, 0x4367, 0xB04D, 0, 0xA13E, 0x376F, 0x5043,
+ 0, 0, 0, 0x4724, 0, 0x2E29, 0xB050, 0x2E2A,
+};
+static const unsigned short utf8_to_euc_E4BC[] = {
+ 0xB052, 0x346B, 0xB053, 0xB054, 0, 0, 0, 0,
+ 0xB055, 0x5044, 0x304B, 0xB056, 0xB057, 0x3860, 0x346C, 0x497A,
+ 0x4832, 0x3559, 0xB058, 0, 0, 0xB059, 0xB05A, 0xB05B,
+ 0, 0xB05C, 0x3271, 0, 0x5067, 0x4541, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xB05D, 0x476C,
+ 0x5046, 0xB05E, 0, 0xB060, 0x483C, 0xB061, 0x4E62, 0xB062,
+ 0x3F2D, 0xB063, 0x3B47, 0xB064, 0x3B77, 0x3240, 0xB065, 0,
+};
+static const unsigned short utf8_to_euc_E4BC_x0213[] = {
+ 0xA13F, 0x346B, 0xB053, 0x2E2B, 0, 0, 0, 0,
+ 0xB055, 0x5044, 0x304B, 0x2E2C, 0xB057, 0x3860, 0x346C, 0x497A,
+ 0x4832, 0x3559, 0xB058, 0, 0, 0xB059, 0xA140, 0xB05B,
+ 0, 0xB05C, 0x3271, 0, 0x5067, 0x4541, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xB05D, 0x476C,
+ 0x5046, 0xB05E, 0, 0xB060, 0x483C, 0xB061, 0x4E62, 0xA142,
+ 0x3F2D, 0, 0x3B47, 0xB064, 0x3B77, 0x3240, 0xA143, 0,
+};
+static const unsigned short utf8_to_euc_E4BD[] = {
+ 0xB066, 0, 0xB067, 0x4451, 0, 0, 0x4322, 0x504A,
+ 0xB068, 0xB069, 0, 0xB06A, 0xB06B, 0x304C, 0x4463, 0x3D3B,
+ 0x3A34, 0x4D24, 0xB06C, 0x424E, 0xB06D, 0x323F, 0xB06E, 0x5049,
+ 0xB06F, 0x4D3E, 0x5045, 0x5047, 0x3A6E, 0x5048, 0x5524, 0xB070,
+ 0xB05F, 0, 0, 0xB071, 0, 0, 0, 0,
+ 0, 0x5050, 0xB072, 0, 0xB073, 0, 0xB074, 0x5053,
+ 0x5051, 0xB075, 0, 0x3242, 0, 0x4A3B, 0x504B, 0xB076,
+ 0xB077, 0xB078, 0xB079, 0x504F, 0x3873, 0xB07A, 0xB07B, 0x3B48,
+};
+static const unsigned short utf8_to_euc_E4BD_x0213[] = {
+ 0xB066, 0, 0xB067, 0x4451, 0, 0, 0x4322, 0x504A,
+ 0x2E2E, 0x2E2F, 0, 0xB06A, 0xB06B, 0x304C, 0x4463, 0x3D3B,
+ 0x3A34, 0x4D24, 0xB06C, 0x424E, 0xA144, 0x323F, 0x2E30, 0x5049,
+ 0xA145, 0x4D3E, 0x5045, 0x5047, 0x3A6E, 0x5048, 0x5524, 0x2E31,
+ 0x2E2D, 0, 0, 0xB071, 0xA141, 0, 0, 0,
+ 0, 0x5050, 0x2E32, 0, 0x2E33, 0, 0xB074, 0x5053,
+ 0x5051, 0xB075, 0, 0x3242, 0, 0x4A3B, 0x504B, 0xA147,
+ 0xA148, 0xB078, 0xA149, 0x504F, 0x3873, 0xA14A, 0x2E34, 0x3B48,
+};
+static const unsigned short utf8_to_euc_E4BE[] = {
+ 0, 0xB07C, 0xB07D, 0x3426, 0xB07E, 0xB121, 0x5054, 0,
+ 0x504C, 0xB122, 0xB123, 0x4E63, 0xB124, 0x3B78, 0xB125, 0x504D,
+ 0xB126, 0x5052, 0xB127, 0xB128, 0xB129, 0, 0x5055, 0xB12A,
+ 0x504E, 0xB12B, 0xB12C, 0x3621, 0, 0x304D, 0xB12D, 0xB12E,
+ 0x3622, 0x3241, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x5525, 0, 0x4B79, 0x496E, 0x3874,
+ 0, 0, 0xB12F, 0, 0, 0x3F2F, 0x4E37, 0xB130,
+ 0, 0xB131, 0, 0xB132, 0xB133, 0xB134, 0xB135, 0x4A58,
+};
+static const unsigned short utf8_to_euc_E4BE_x0213[] = {
+ 0, 0xB07C, 0xA14B, 0x3426, 0xB07E, 0xA14C, 0x5054, 0,
+ 0x504C, 0xB122, 0x2E35, 0x4E63, 0xB124, 0x3B78, 0xB125, 0x504D,
+ 0xB126, 0x5052, 0xA14D, 0xB128, 0x2E36, 0, 0x5055, 0x2E37,
+ 0x504E, 0xB12B, 0xA14E, 0x3621, 0, 0x304D, 0xB12D, 0xB12E,
+ 0x3622, 0x3241, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x5525, 0, 0x4B79, 0x496E, 0x3874,
+ 0, 0, 0xA150, 0, 0, 0x3F2F, 0x4E37, 0xB130,
+ 0, 0xB131, 0, 0xB132, 0xB133, 0xB134, 0xA151, 0x4A58,
+};
+static const unsigned short utf8_to_euc_E4BF[] = {
+ 0xB136, 0xB137, 0x3738, 0x4225, 0x3264, 0xB138, 0xB139, 0,
+ 0xB13A, 0xB13B, 0x3D53, 0xB13C, 0xB13D, 0xB13E, 0x5059, 0xB13F,
+ 0x505E, 0x505C, 0xB140, 0, 0x5057, 0, 0, 0x422F,
+ 0x505A, 0, 0x505D, 0x505B, 0xB141, 0x4A5D, 0, 0x5058,
+ 0xB142, 0x3F2E, 0xB143, 0x4B73, 0x505F, 0x5060, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x3D24, 0x506D,
+ 0xB144, 0, 0xB145, 0x4750, 0, 0x4936, 0x5068, 0,
+ 0x4A70, 0, 0x3236, 0, 0xB146, 0xB147, 0x506C, 0xB148,
+};
+static const unsigned short utf8_to_euc_E4BF_x0213[] = {
+ 0xB136, 0xB137, 0x3738, 0x4225, 0x3264, 0xA152, 0xB139, 0,
+ 0xB13A, 0x2E39, 0x3D53, 0xA153, 0xB13D, 0, 0x5059, 0xA154,
+ 0x505E, 0x505C, 0xA155, 0, 0x5057, 0, 0, 0x422F,
+ 0x505A, 0, 0x505D, 0x505B, 0xB141, 0x4A5D, 0, 0x5058,
+ 0x2E3A, 0x3F2E, 0xB143, 0x4B73, 0x505F, 0x5060, 0xA14F, 0,
+ 0, 0, 0, 0, 0, 0, 0x3D24, 0x506D,
+ 0xB144, 0x2E21, 0xA157, 0x4750, 0, 0x4936, 0x5068, 0,
+ 0x4A70, 0, 0x3236, 0, 0xB146, 0xB147, 0x506C, 0,
+};
+static const unsigned short utf8_to_euc_E580[] = {
+ 0xB149, 0xB14A, 0, 0, 0xB14B, 0x5066, 0x506F, 0xB14C,
+ 0, 0x4152, 0xB14D, 0x3844, 0xB14E, 0x475C, 0xB14F, 0x6047,
+ 0xB150, 0x506E, 0x455D, 0xB151, 0x5063, 0, 0x3876, 0xB152,
+ 0xB153, 0x3875, 0x5061, 0xB154, 0xB155, 0xB156, 0xB157, 0x3C5A,
+ 0, 0x5069, 0xB158, 0x4A6F, 0x434D, 0x5065, 0x3771, 0xB159,
+ 0x5062, 0x506A, 0x5064, 0x4E51, 0x506B, 0x4F41, 0xB15A, 0,
+ 0xB15B, 0, 0xB15C, 0xB15D, 0, 0xB15E, 0x3666, 0,
+ 0, 0x3770, 0, 0xB176, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E580_x0213[] = {
+ 0xA158, 0x2E3B, 0x2E3C, 0, 0xB14B, 0x5066, 0x506F, 0xB14C,
+ 0, 0x4152, 0xB14D, 0x3844, 0xB14E, 0x475C, 0x2E3D, 0x6047,
+ 0xA159, 0x506E, 0x455D, 0xA15A, 0x5063, 0, 0x3876, 0xB152,
+ 0x2E3E, 0x3875, 0x5061, 0xB154, 0xA15B, 0xB156, 0xA15C, 0x3C5A,
+ 0, 0x5069, 0xA15D, 0x4A6F, 0x434D, 0x5065, 0x3771, 0x2E3F,
+ 0x5062, 0x506A, 0x5064, 0x4E51, 0x506B, 0x4F41, 0x2E40, 0,
+ 0xB15B, 0, 0xB15C, 0xB15D, 0, 0xB15E, 0x3666, 0,
+ 0, 0x3770, 0, 0x2E42, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E581[] = {
+ 0xB15F, 0xB160, 0xB161, 0x5070, 0, 0xB162, 0xB163, 0x5071,
+ 0x5075, 0x304E, 0xB164, 0, 0xB165, 0, 0xB166, 0x4A50,
+ 0x5074, 0xB167, 0xB168, 0xB169, 0, 0x5073, 0x5077, 0xB16A,
+ 0, 0xB16B, 0x5076, 0, 0x4464, 0, 0, 0xB16C,
+ 0xB16D, 0, 0xB16E, 0xB16F, 0, 0x3772, 0xB170, 0xB171,
+ 0, 0, 0xB172, 0, 0x5078, 0xB173, 0, 0,
+ 0xB174, 0xB175, 0x3C45, 0, 0x4226, 0x4465, 0x3676, 0,
+ 0x5079, 0, 0, 0, 0, 0x3536, 0, 0,
+};
+static const unsigned short utf8_to_euc_E581_x0213[] = {
+ 0x2E41, 0x2E43, 0xA15F, 0x5070, 0, 0xB162, 0xA160, 0x5071,
+ 0x5075, 0x304E, 0xB164, 0, 0xB165, 0, 0xA161, 0x4A50,
+ 0x5074, 0xB167, 0xB168, 0xA162, 0, 0x5073, 0x5077, 0xA163,
+ 0, 0xB16B, 0x5076, 0, 0x4464, 0, 0, 0xB16C,
+ 0xB16D, 0, 0xB16E, 0xA164, 0, 0x3772, 0xA165, 0xB171,
+ 0, 0, 0xA166, 0, 0x5078, 0xB173, 0, 0,
+ 0xA167, 0xB175, 0x3C45, 0, 0x4226, 0x4465, 0x3676, 0,
+ 0x5079, 0, 0, 0, 0, 0x3536, 0, 0,
+};
+static const unsigned short utf8_to_euc_E582[] = {
+ 0x507A, 0xB177, 0, 0xB178, 0xB179, 0x507C, 0xB17A, 0,
+ 0, 0, 0xB17B, 0, 0, 0x4B35, 0xB17C, 0xB17D,
+ 0xB17E, 0x3766, 0xB221, 0xB222, 0xB223, 0, 0xB224, 0,
+ 0x3B31, 0x4877, 0x507B, 0xB225, 0xB226, 0, 0xB227, 0xB228,
+ 0xB229, 0xB22A, 0xB22B, 0, 0, 0, 0, 0,
+ 0, 0, 0xB22C, 0, 0x3A45, 0x4D43, 0, 0xB22D,
+ 0xB22E, 0, 0x507E, 0x5123, 0x507D, 0x3A44, 0, 0x3D7D,
+ 0, 0xB22F, 0xB230, 0, 0, 0xB231, 0x3739, 0,
+};
+static const unsigned short utf8_to_euc_E582_x0213[] = {
+ 0x507A, 0xB177, 0, 0xB178, 0xB179, 0x507C, 0xB17A, 0,
+ 0xA169, 0, 0xB17B, 0, 0, 0x4B35, 0xB17C, 0xB17D,
+ 0xB17E, 0x3766, 0xA16A, 0xA16B, 0x2E44, 0xA16C, 0xA16D, 0,
+ 0x3B31, 0x4877, 0x507B, 0xB225, 0xA16E, 0, 0xB227, 0xB228,
+ 0xB229, 0xB22A, 0xB22B, 0xA168, 0, 0, 0, 0,
+ 0, 0, 0xA16F, 0, 0x3A45, 0x4D43, 0, 0xB22D,
+ 0xB22E, 0xA171, 0x507E, 0x5123, 0x507D, 0x3A44, 0, 0x3D7D,
+ 0, 0xB22F, 0xA172, 0xA173, 0, 0xB231, 0x3739, 0,
+};
+static const unsigned short utf8_to_euc_E583[] = {
+ 0xB232, 0, 0x5124, 0xB233, 0xB234, 0x364F, 0, 0xB235,
+ 0, 0x5121, 0x5122, 0, 0xB236, 0x462F, 0xB237, 0x417C,
+ 0xB238, 0x3623, 0, 0xB239, 0xB23A, 0x4B4D, 0x5125, 0,
+ 0xB23B, 0, 0x4E3D, 0, 0xB23C, 0xB23D, 0x5126, 0xB23E,
+ 0, 0, 0xB23F, 0x5129, 0xB240, 0x5127, 0xB241, 0x414E,
+ 0xB242, 0xB243, 0, 0, 0, 0x5128, 0x512A, 0xB244,
+ 0, 0xB245, 0xB251, 0, 0xF430, 0x512C, 0xB246, 0,
+ 0, 0x512B, 0xB247, 0x4A48, 0, 0, 0xB248, 0,
+};
+static const unsigned short utf8_to_euc_E583_x0213[] = {
+ 0xB232, 0, 0x5124, 0xB233, 0xA174, 0x364F, 0, 0xA175,
+ 0, 0x5121, 0x5122, 0, 0x2E45, 0x462F, 0xA178, 0x417C,
+ 0x2E47, 0x3623, 0, 0xB239, 0xA17A, 0x4B4D, 0x5125, 0,
+ 0, 0xA17B, 0x4E3D, 0, 0xB23C, 0xB23D, 0x5126, 0xB23E,
+ 0, 0xA17C, 0xB23F, 0x5129, 0xB240, 0x5127, 0x2E48, 0x414E,
+ 0xB242, 0xA17D, 0, 0, 0, 0x5128, 0x512A, 0xB244,
+ 0, 0xB245, 0x2E46, 0xA176, 0, 0x512C, 0xB246, 0,
+ 0, 0x512B, 0xB247, 0x4A48, 0, 0, 0xB248, 0,
+};
+static const unsigned short utf8_to_euc_E584[] = {
+ 0x3537, 0x512E, 0x512F, 0xB249, 0x322F, 0, 0xB24A, 0xB24B,
+ 0xB24C, 0x512D, 0, 0xB24D, 0xB24E, 0xB24F, 0xB250, 0,
+ 0xB252, 0, 0x3C74, 0, 0x5132, 0x5131, 0x5130, 0xB253,
+ 0x5056, 0xB254, 0x5133, 0xB255, 0xB256, 0xB257, 0xB258, 0x3D7E,
+ 0, 0x5134, 0, 0xB259, 0, 0, 0, 0xB25A,
+ 0xB25B, 0, 0x4D25, 0, 0xB25C, 0xB25D, 0, 0xB25E,
+ 0, 0xB25F, 0x4C59, 0xB260, 0xB261, 0xB262, 0, 0x5136,
+ 0xB263, 0xB264, 0x5135, 0x5138, 0x5137, 0, 0, 0x5139,
+};
+static const unsigned short utf8_to_euc_E584_x0213[] = {
+ 0x3537, 0x512E, 0x512F, 0x2E4B, 0x322F, 0, 0x2E4A, 0xB24B,
+ 0xA321, 0x512D, 0, 0x2E4C, 0xB24E, 0xB24F, 0xB250, 0,
+ 0xB252, 0, 0x3C74, 0, 0x5132, 0x5131, 0x5130, 0xA323,
+ 0x5056, 0xB254, 0x5133, 0xA324, 0xB256, 0xB257, 0x2E4D, 0x3D7E,
+ 0, 0x5134, 0, 0xB259, 0, 0, 0, 0xB25A,
+ 0xB25B, 0, 0x4D25, 0, 0xB25C, 0xB25D, 0, 0xB25E,
+ 0, 0xB25F, 0x4C59, 0xB260, 0xB261, 0x2E4E, 0, 0x5136,
+ 0xB263, 0xB264, 0x5135, 0x5138, 0x5137, 0, 0, 0x5139,
+};
+static const unsigned short utf8_to_euc_E585[] = {
+ 0x513A, 0x3074, 0xB265, 0x3835, 0x373B, 0x3D3C, 0x437B, 0x3624,
+ 0x4068, 0x3877, 0xB266, 0x396E, 0x513C, 0x4C48, 0x4546, 0xB267,
+ 0x3B79, 0, 0x513B, 0xB268, 0x513D, 0xB269, 0, 0xB26A,
+ 0xB26B, 0, 0x455E, 0, 0x3375, 0, 0, 0xB26C,
+ 0, 0, 0x513E, 0, 0xB26D, 0x467E, 0xB26E, 0,
+ 0x4134, 0x5140, 0x5141, 0x482C, 0x3878, 0x4F3B, 0x5142, 0,
+ 0, 0x3626, 0, 0, 0, 0x4A3C, 0x4236, 0x3671,
+ 0x4535, 0, 0, 0, 0x3773, 0, 0xB26F, 0,
+};
+static const unsigned short utf8_to_euc_E585_x0213[] = {
+ 0x513A, 0x3074, 0xB265, 0x3835, 0x373B, 0x3D3C, 0x437B, 0x3624,
+ 0x4068, 0x3877, 0x2E4F, 0x396E, 0x513C, 0x4C48, 0x4546, 0xB267,
+ 0x3B79, 0, 0x513B, 0xB268, 0x513D, 0x2E51, 0, 0x2E52,
+ 0xB26B, 0, 0x455E, 0, 0x3375, 0, 0, 0xB26C,
+ 0xA326, 0, 0x513E, 0, 0, 0x467E, 0xB26E, 0,
+ 0x4134, 0x5140, 0x5141, 0x482C, 0x3878, 0x4F3B, 0x5142, 0,
+ 0, 0x3626, 0, 0xA328, 0, 0x4A3C, 0x4236, 0x3671,
+ 0x4535, 0, 0, 0xF474, 0x3773, 0, 0xB26F, 0,
+};
+static const unsigned short utf8_to_euc_E586[] = {
+ 0x5143, 0, 0x5144, 0xB270, 0xB271, 0x4662, 0x315F, 0,
+ 0, 0x5147, 0x3A7D, 0xB272, 0x5146, 0x3A46, 0xB273, 0x5148,
+ 0x666E, 0x5149, 0x4B41, 0x514A, 0, 0x514B, 0x514C, 0x3E69,
+ 0xB274, 0x3C4C, 0, 0, 0, 0xB275, 0, 0,
+ 0x3427, 0xB276, 0x514F, 0xB277, 0x514D, 0x4C3D, 0x514E, 0,
+ 0x495A, 0x5150, 0x5151, 0x5152, 0x455F, 0xB278, 0, 0,
+ 0x5156, 0x5154, 0x5155, 0x5153, 0x3A63, 0x5157, 0x4C6A, 0x4E64,
+ 0xB279, 0, 0xB27A, 0, 0xB27B, 0x5158, 0xB27C, 0xB27D,
+};
+static const unsigned short utf8_to_euc_E586_x0213[] = {
+ 0x5143, 0, 0x5144, 0xA329, 0xB271, 0x4662, 0x315F, 0,
+ 0, 0x5147, 0x3A7D, 0xA32A, 0x5146, 0x3A46, 0xB273, 0x5148,
+ 0x666E, 0x5149, 0x4B41, 0x514A, 0, 0x514B, 0x514C, 0x3E69,
+ 0xA32C, 0x3C4C, 0, 0, 0, 0x2E54, 0, 0,
+ 0x3427, 0xB276, 0x514F, 0xA32D, 0x514D, 0x4C3D, 0x514E, 0,
+ 0x495A, 0x5150, 0x5151, 0x5152, 0x455F, 0xA32E, 0, 0,
+ 0x5156, 0x5154, 0x5155, 0x5153, 0x3A63, 0x5157, 0x4C6A, 0x4E64,
+ 0xB279, 0, 0xB27A, 0, 0xA330, 0x5158, 0, 0xB27D,
+};
+static const unsigned short utf8_to_euc_E587[] = {
+ 0, 0, 0xB27E, 0, 0x4028, 0x5159, 0x3D5A, 0,
+ 0xB321, 0x515A, 0, 0x437C, 0x4E3F, 0x4560, 0, 0xB322,
+ 0, 0xB323, 0xB324, 0xB325, 0, 0xB326, 0x5245, 0,
+ 0xB327, 0, 0, 0x515B, 0x7425, 0x3645, 0xB328, 0,
+ 0x515C, 0x4B5E, 0xB329, 0, 0, 0xB32A, 0x3D68, 0x427C,
+ 0, 0x515E, 0x4664, 0, 0xF431, 0x515F, 0xB32B, 0,
+ 0x5160, 0x332E, 0xB32C, 0xB32D, 0xB32E, 0x5161, 0x3627, 0xB32F,
+ 0x464C, 0x317A, 0x3D50, 0, 0, 0x4821, 0x5162, 0,
+};
+static const unsigned short utf8_to_euc_E587_x0213[] = {
+ 0, 0, 0xB27E, 0x2E55, 0x4028, 0x5159, 0x3D5A, 0,
+ 0xB321, 0x515A, 0x2E56, 0x437C, 0x4E3F, 0x4560, 0, 0xB322,
+ 0, 0xB323, 0xB324, 0xB325, 0, 0xB326, 0x5245, 0,
+ 0xB327, 0, 0, 0x515B, 0x7425, 0x3645, 0x2E57, 0,
+ 0x515C, 0x4B5E, 0x2E58, 0, 0, 0xB32A, 0x3D68, 0x427C,
+ 0, 0x515E, 0x4664, 0, 0, 0x515F, 0x2E59, 0,
+ 0x5160, 0x332E, 0xB32C, 0xA333, 0xA334, 0x5161, 0x3627, 0xB32F,
+ 0x464C, 0x317A, 0x3D50, 0, 0, 0x4821, 0x5162, 0,
+};
+static const unsigned short utf8_to_euc_E588[] = {
+ 0x4561, 0xB330, 0xB331, 0x3F4F, 0x5163, 0xB332, 0x4A2C, 0x405A,
+ 0x3422, 0, 0x3429, 0x5164, 0, 0, 0x5166, 0,
+ 0, 0x373A, 0xB333, 0xB334, 0x5165, 0xB335, 0xB336, 0x4E73,
+ 0xB337, 0, 0, 0, 0, 0x3D69, 0, 0,
+ 0, 0, 0xB338, 0, 0x483D, 0x4A4C, 0, 0x5167,
+ 0xB339, 0x4D78, 0x5168, 0, 0, 0, 0x5169, 0,
+ 0x457E, 0xB33A, 0xB33B, 0x516A, 0, 0xB33C, 0x4029, 0x3A7E,
+ 0x3774, 0x516B, 0x3B49, 0x396F, 0xB33D, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E588_x0213[] = {
+ 0x4561, 0x2E5A, 0xA335, 0x3F4F, 0x5163, 0xB332, 0x4A2C, 0x405A,
+ 0x3422, 0, 0x3429, 0x5164, 0, 0, 0x5166, 0,
+ 0, 0x373A, 0xA336, 0x2E5C, 0x5165, 0x2E5D, 0xA337, 0x4E73,
+ 0xB337, 0, 0, 0, 0, 0x3D69, 0, 0,
+ 0, 0, 0xB338, 0, 0x483D, 0x4A4C, 0, 0x5167,
+ 0xB339, 0x4D78, 0x5168, 0, 0, 0, 0x5169, 0,
+ 0x457E, 0xB33A, 0xB33B, 0x516A, 0, 0xB33C, 0x4029, 0x3A7E,
+ 0x3774, 0x516B, 0x3B49, 0x396F, 0xB33D, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E589[] = {
+ 0, 0, 0, 0x4466, 0x516D, 0xB33E, 0, 0x4227,
+ 0, 0xB33F, 0x3A6F, 0x516E, 0x516F, 0x4130, 0, 0x516C,
+ 0, 0, 0, 0, 0x5171, 0xB340, 0x4B36, 0xB341,
+ 0xB342, 0, 0xB343, 0x3964, 0xB344, 0, 0x5170, 0xB345,
+ 0xB346, 0xB347, 0, 0x3775, 0x3A5E, 0x476D, 0xB348, 0,
+ 0, 0x5174, 0x5172, 0, 0, 0, 0xB349, 0x497B,
+ 0x3E6A, 0x517B, 0x3364, 0x5175, 0x5173, 0x414F, 0, 0xB34A,
+ 0xB34B, 0xB34C, 0, 0, 0, 0x5177, 0, 0x5176,
+};
+static const unsigned short utf8_to_euc_E589_x0213[] = {
+ 0, 0, 0, 0x4466, 0x516D, 0xB33E, 0, 0x4227,
+ 0, 0x2E5E, 0x3A6F, 0x516E, 0x516F, 0x4130, 0, 0x516C,
+ 0, 0, 0, 0, 0x5171, 0xA339, 0x4B36, 0x2E5F,
+ 0xB342, 0, 0xB343, 0x3964, 0xA33A, 0x2F7E, 0x5170, 0xB345,
+ 0xB346, 0x2E60, 0, 0x3775, 0x3A5E, 0x476D, 0xB348, 0,
+ 0, 0x5174, 0x5172, 0, 0xA33B, 0, 0xB349, 0x497B,
+ 0x3E6A, 0x517B, 0x3364, 0x5175, 0x5173, 0x414F, 0, 0xA33C,
+ 0xB34B, 0xB34C, 0, 0, 0, 0x5177, 0, 0x5176,
+};
+static const unsigned short utf8_to_euc_E58A[] = {
+ 0xB34D, 0, 0xB34E, 0x3344, 0, 0xB34F, 0, 0x3760,
+ 0x517C, 0x4E2D, 0xB350, 0, 0xB351, 0x5178, 0, 0,
+ 0, 0x517D, 0x517A, 0xB352, 0x5179, 0xB353, 0xB354, 0xB355,
+ 0xB356, 0, 0xB357, 0x4E4F, 0xB358, 0, 0, 0x3879,
+ 0x3243, 0, 0, 0x4E74, 0xB359, 0xB35A, 0xB35B, 0xB35C,
+ 0, 0x3D75, 0x4558, 0x3965, 0x5222, 0x5223, 0, 0xB35D,
+ 0xB35E, 0x4E65, 0, 0, 0x4F2B, 0x5225, 0xB35F, 0xB360,
+ 0xB361, 0x387A, 0xB362, 0xB363, 0x5224, 0xB364, 0x332F, 0,
+};
+static const unsigned short utf8_to_euc_E58A_x0213[] = {
+ 0xB34D, 0, 0xA33E, 0x3344, 0xA33D, 0xB34F, 0, 0x3760,
+ 0x517C, 0x4E2D, 0xB350, 0, 0xB351, 0x5178, 0, 0,
+ 0, 0x517D, 0x517A, 0x2E61, 0x5179, 0xB353, 0xB354, 0xB355,
+ 0xA340, 0, 0xB357, 0x4E4F, 0, 0, 0, 0x3879,
+ 0x3243, 0, 0, 0x4E74, 0xA342, 0xB35A, 0xA343, 0xB35C,
+ 0, 0x3D75, 0x4558, 0x3965, 0x5222, 0x5223, 0, 0xA344,
+ 0xB35E, 0x4E65, 0, 0, 0x4F2B, 0x5225, 0xB35F, 0xB360,
+ 0xB361, 0x387A, 0xA345, 0xA346, 0x5224, 0xB364, 0x332F, 0,
+};
+static const unsigned short utf8_to_euc_E58B[] = {
+ 0xB365, 0x5226, 0, 0x4B56, 0xB366, 0x443C, 0xB367, 0x4D26,
+ 0xB368, 0x4A59, 0, 0, 0xB369, 0x5227, 0, 0xB36A,
+ 0, 0xB36B, 0x7055, 0, 0xB36C, 0x4630, 0xB36D, 0x5228,
+ 0x342A, 0x4C33, 0, 0xB36E, 0xB36F, 0x3E21, 0x5229, 0x4A67,
+ 0x522D, 0xB370, 0x402A, 0x522A, 0x3650, 0xB371, 0x522B, 0x342B,
+ 0xB372, 0xB373, 0xB374, 0, 0xB375, 0, 0, 0,
+ 0xB376, 0xB377, 0x372E, 0x522E, 0xB378, 0x522F, 0xB379, 0xB37A,
+ 0x5230, 0x5231, 0x3C5B, 0, 0, 0, 0x387B, 0x4C5E,
+};
+static const unsigned short utf8_to_euc_E58B_x0213[] = {
+ 0, 0x5226, 0, 0x4B56, 0xB366, 0x443C, 0xB367, 0x4D26,
+ 0x2E62, 0x4A59, 0xA347, 0, 0x2E64, 0x5227, 0, 0xB36A,
+ 0x2E65, 0xA349, 0x7055, 0, 0xB36C, 0x4630, 0x2E66, 0x5228,
+ 0x342A, 0x4C33, 0, 0x2E67, 0xB36F, 0x3E21, 0x5229, 0x4A67,
+ 0x522D, 0xB370, 0x402A, 0x522A, 0x3650, 0xB371, 0x522B, 0x342B,
+ 0xB372, 0xB373, 0xB374, 0, 0xB375, 0, 0, 0,
+ 0x2E69, 0xB377, 0x372E, 0x522E, 0xB378, 0x522F, 0xB379, 0xA34B,
+ 0x5230, 0x5231, 0x3C5B, 0x2E6A, 0, 0, 0x387B, 0x4C5E,
+};
+static const unsigned short utf8_to_euc_E58C[] = {
+ 0xB37B, 0x4C68, 0x4677, 0xB37C, 0, 0x4A71, 0x5232, 0xF432,
+ 0x5233, 0, 0xB37D, 0xB37E, 0xB421, 0x5235, 0, 0x5237,
+ 0x5236, 0xB422, 0, 0xB423, 0, 0x5238, 0x323D, 0x4B4C,
+ 0xB424, 0x3A7C, 0x5239, 0xB425, 0xB426, 0x4159, 0xB427, 0xB428,
+ 0x3E22, 0x3629, 0, 0x523A, 0xF433, 0xB429, 0, 0xB42A,
+ 0xB42B, 0xB42C, 0x485B, 0xB42D, 0xB42E, 0xB42F, 0, 0x523B,
+ 0xB430, 0x523C, 0xB431, 0x523D, 0, 0xB432, 0, 0,
+ 0x523E, 0x4924, 0x3668, 0x3065, 0xB433, 0xB434, 0xB435, 0x463F,
+};
+static const unsigned short utf8_to_euc_E58C_x0213[] = {
+ 0x2E6B, 0x4C68, 0x4677, 0xB37C, 0, 0x4A71, 0x5232, 0x2E6C,
+ 0x5233, 0, 0xA34C, 0xA34D, 0xB421, 0x5235, 0, 0x5237,
+ 0x5236, 0xB422, 0, 0xB423, 0, 0x5238, 0x323D, 0x4B4C,
+ 0xB424, 0x3A7C, 0x5239, 0xB425, 0x2E6D, 0x4159, 0xB427, 0xB428,
+ 0x3E22, 0x3629, 0, 0x523A, 0xA34E, 0xB429, 0, 0xB42A,
+ 0xB42B, 0xB42C, 0x485B, 0xB42D, 0xB42E, 0xB42F, 0, 0x523B,
+ 0xB430, 0x523C, 0xB431, 0x523D, 0, 0xA34F, 0, 0,
+ 0x523E, 0x4924, 0x3668, 0x3065, 0xB433, 0xB434, 0xA350, 0x463F,
+};
+static const unsigned short utf8_to_euc_E58D[] = {
+ 0x523F, 0x3D3D, 0xB436, 0x4069, 0, 0x5241, 0x5240, 0x3E23,
+ 0x3861, 0x5243, 0x483E, 0xB438, 0xB437, 0x5244, 0, 0,
+ 0, 0x485C, 0x4234, 0x426E, 0x3628, 0, 0, 0x466E,
+ 0x4331, 0xB439, 0x476E, 0xB43A, 0x4B4E, 0, 0x5246, 0,
+ 0x406A, 0xB43B, 0, 0xB43C, 0, 0xB43D, 0x3735, 0,
+ 0, 0x5247, 0, 0, 0xB43E, 0xB43F, 0x5248, 0x312C,
+ 0x3075, 0x346D, 0xB440, 0x4228, 0x3551, 0x4D71, 0, 0x524B,
+ 0x3237, 0xB441, 0, 0x524A, 0, 0, 0xB442, 0x362A,
+};
+static const unsigned short utf8_to_euc_E58D_x0213[] = {
+ 0x523F, 0x3D3D, 0xA351, 0x4069, 0, 0x5241, 0x5240, 0x3E23,
+ 0x3861, 0x5243, 0x483E, 0xB438, 0xB437, 0x5244, 0, 0,
+ 0, 0x485C, 0x4234, 0x426E, 0x3628, 0, 0, 0x466E,
+ 0x4331, 0xB439, 0x476E, 0xB43A, 0x4B4E, 0, 0x5246, 0,
+ 0x406A, 0x2E6F, 0, 0x2E70, 0, 0xB43D, 0x3735, 0xA354,
+ 0, 0x5247, 0, 0, 0xA355, 0xB43F, 0x5248, 0x312C,
+ 0x3075, 0x346D, 0, 0x4228, 0x3551, 0x4D71, 0, 0x524B,
+ 0x3237, 0xB441, 0xA356, 0x524A, 0, 0x2E71, 0xB442, 0x362A,
+};
+static const unsigned short utf8_to_euc_E58E[] = {
+ 0, 0, 0x524C, 0xB443, 0x4C71, 0, 0, 0xB444,
+ 0xB445, 0, 0, 0, 0, 0, 0xB446, 0,
+ 0, 0, 0, 0xB447, 0xB448, 0, 0x524D, 0,
+ 0x4E52, 0xB449, 0x387C, 0, 0, 0xB44A, 0, 0x3836,
+ 0x524E, 0xB44B, 0, 0, 0xB44C, 0x5250, 0x524F, 0,
+ 0x3F5F, 0x3139, 0xB44D, 0xB44E, 0, 0x315E, 0x5251, 0xB44F,
+ 0x5252, 0, 0xB450, 0x3837, 0xB451, 0xB452, 0x5253, 0xB453,
+ 0xB454, 0, 0xB455, 0x356E, 0, 0xB456, 0, 0,
+};
+static const unsigned short utf8_to_euc_E58E_x0213[] = {
+ 0, 0, 0x524C, 0xB443, 0x4C71, 0, 0, 0xB444,
+ 0xB445, 0, 0, 0, 0, 0, 0xB446, 0,
+ 0, 0, 0, 0x2E72, 0xB448, 0, 0x524D, 0,
+ 0x4E52, 0xB449, 0x387C, 0, 0, 0x2E73, 0, 0x3836,
+ 0x524E, 0xB44B, 0, 0, 0xA357, 0x5250, 0x524F, 0,
+ 0x3F5F, 0x3139, 0xB44D, 0xB44E, 0, 0x315E, 0x5251, 0xB44F,
+ 0x5252, 0, 0x2E74, 0x3837, 0xA358, 0xB452, 0x5253, 0xA35A,
+ 0xB454, 0, 0xB455, 0x356E, 0, 0xB456, 0, 0,
+};
+static const unsigned short utf8_to_euc_E58F[] = {
+ 0xB457, 0, 0x3B32, 0x5254, 0, 0xB458, 0, 0,
+ 0x4B74, 0x3A35, 0x355A, 0x4D27, 0x4150, 0x483F, 0x3C7D, 0xB459,
+ 0, 0, 0xB45A, 0xB45B, 0x3D47, 0xB45C, 0x3C68, 0x3C75,
+ 0, 0x3D76, 0xB45D, 0x4840, 0, 0xB45E, 0xB45F, 0x5257,
+ 0xB460, 0x3143, 0x4151, 0x387D, 0x3845, 0x3667, 0xB461, 0xB462,
+ 0x525B, 0x4321, 0x427E, 0x362B, 0x3E24, 0x525C, 0x525A, 0x3244,
+ 0x4266, 0x3C38, 0x3B4B, 0x3126, 0, 0xB463, 0x3370, 0x3966,
+ 0x3B4A, 0, 0x525D, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E58F_x0213[] = {
+ 0xA35B, 0, 0x3B32, 0x5254, 0, 0xB458, 0, 0,
+ 0x4B74, 0x3A35, 0x355A, 0x4D27, 0x4150, 0x483F, 0x3C7D, 0xB459,
+ 0, 0, 0xB45A, 0xB45B, 0x3D47, 0xA35F, 0x3C68, 0x3C75,
+ 0, 0x3D76, 0xA360, 0x4840, 0, 0, 0xB45F, 0x5257,
+ 0xB460, 0x3143, 0x4151, 0x387D, 0x3845, 0x3667, 0xB461, 0xB462,
+ 0x525B, 0x4321, 0x427E, 0x362B, 0x3E24, 0x525C, 0x525A, 0x3244,
+ 0x4266, 0x3C38, 0x3B4B, 0x3126, 0xA362, 0xA363, 0x3370, 0x3966,
+ 0x3B4A, 0, 0x525D, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E590[] = {
+ 0, 0x525E, 0xB464, 0x3549, 0x3346, 0, 0, 0,
+ 0x3967, 0x3548, 0x445F, 0x3125, 0x4631, 0x4C3E, 0x3921, 0x4D79,
+ 0x4547, 0x387E, 0, 0xB465, 0, 0, 0, 0,
+ 0, 0, 0xB466, 0x372F, 0, 0x5267, 0, 0x3663,
+ 0x4B4A, 0xB467, 0, 0, 0, 0, 0x485D, 0xB468,
+ 0xB469, 0x5266, 0xB46A, 0x345E, 0x5261, 0x5262, 0x5264, 0xB46B,
+ 0, 0xB46C, 0, 0, 0xB46D, 0xB46E, 0x5265, 0,
+ 0x355B, 0x3F61, 0, 0x4A2D, 0x5263, 0x525F, 0x3863, 0,
+};
+static const unsigned short utf8_to_euc_E590_x0213[] = {
+ 0, 0x525E, 0xB464, 0x3549, 0x3346, 0, 0, 0,
+ 0x3967, 0x3548, 0x445F, 0x3125, 0x4631, 0x4C3E, 0x3921, 0x4D79,
+ 0x4547, 0x387E, 0x2E75, 0xB465, 0, 0, 0, 0,
+ 0, 0, 0xB466, 0x372F, 0, 0x5267, 0x4F7E, 0x3663,
+ 0x4B4A, 0xB467, 0, 0, 0xA365, 0, 0x485D, 0x2E76,
+ 0xA366, 0x5266, 0xB46A, 0x345E, 0x5261, 0x5262, 0x5264, 0xB46B,
+ 0, 0xB46C, 0, 0, 0xB46D, 0xB46E, 0x5265, 0,
+ 0x355B, 0x3F61, 0, 0x4A2D, 0x5263, 0x525F, 0x3863, 0,
+};
+static const unsigned short utf8_to_euc_E591[] = {
+ 0x5260, 0, 0x4F24, 0xB46F, 0xB470, 0, 0x4A72, 0xB471,
+ 0x4468, 0x3862, 0x3970, 0, 0, 0xB472, 0x5268, 0xB473,
+ 0, 0x465D, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xB474, 0x526C,
+ 0, 0, 0xB475, 0, 0xB476, 0, 0xB477, 0xB478,
+ 0x3C7E, 0xB479, 0x3C76, 0xB47A, 0, 0xB47B, 0xB47C, 0,
+ 0x526F, 0x526D, 0, 0x4C23, 0xB47D, 0x526A, 0x5273, 0x526E,
+ 0, 0, 0, 0x5271, 0x3846, 0x4C3F, 0, 0xB47E,
+};
+static const unsigned short utf8_to_euc_E591_x0213[] = {
+ 0x5260, 0, 0x4F24, 0xA368, 0xB470, 0, 0x4A72, 0xB471,
+ 0x4468, 0x3862, 0x3970, 0, 0, 0x2E77, 0x5268, 0xB473,
+ 0, 0x465D, 0, 0, 0, 0xA364, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xB474, 0x526C,
+ 0, 0, 0xA369, 0, 0xB476, 0, 0xA36A, 0xB478,
+ 0x3C7E, 0xB479, 0x3C76, 0x2E79, 0xA36B, 0xB47B, 0xB47C, 0,
+ 0x526F, 0x526D, 0, 0x4C23, 0x2E7A, 0x526A, 0x5273, 0x526E,
+ 0, 0, 0, 0x5271, 0x3846, 0x4C3F, 0, 0x2E7B,
+};
+static const unsigned short utf8_to_euc_E592[] = {
+ 0x5272, 0xB521, 0, 0xB522, 0x5274, 0xB523, 0x5276, 0,
+ 0xB524, 0xB525, 0xF435, 0x3A70, 0x4F42, 0xB526, 0x526B, 0x5269,
+ 0x5275, 0xB527, 0x5270, 0, 0, 0xB528, 0xB529, 0,
+ 0, 0, 0, 0, 0xB52A, 0, 0, 0xB52B,
+ 0, 0xB52C, 0x5278, 0, 0x5323, 0x527A, 0xB52D, 0xB52E,
+ 0x527E, 0xB52F, 0xB530, 0x5321, 0x527B, 0xB531, 0xB532, 0x533E,
+ 0, 0xB533, 0x3A69, 0x3331, 0, 0, 0, 0xB534,
+ 0x5279, 0xB535, 0xB536, 0xB537, 0x5325, 0x3076, 0x5324, 0xB538,
+};
+static const unsigned short utf8_to_euc_E592_x0213[] = {
+ 0x5272, 0xB521, 0, 0xB522, 0x5274, 0xB523, 0x5276, 0,
+ 0x2E7C, 0xB525, 0xA36C, 0x3A70, 0x4F42, 0xA36D, 0x526B, 0x5269,
+ 0x5275, 0xB527, 0x5270, 0, 0, 0xA36E, 0x2E7D, 0,
+ 0, 0, 0, 0, 0x2E78, 0, 0, 0xB52B,
+ 0xA36F, 0x2E7E, 0x5278, 0, 0x5323, 0x527A, 0xA370, 0xB52E,
+ 0x527E, 0x2F21, 0xB530, 0x5321, 0x527B, 0xA371, 0xA372, 0x533E,
+ 0, 0xB533, 0x3A69, 0x3331, 0, 0, 0, 0xA373,
+ 0x5279, 0xB535, 0xA374, 0xB537, 0x5325, 0x3076, 0x5324, 0xA375,
+};
+static const unsigned short utf8_to_euc_E593[] = {
+ 0x3025, 0x494A, 0x5322, 0, 0x527C, 0, 0xB539, 0x5277,
+ 0x527D, 0x3A48, 0xB53A, 0, 0, 0xB53B, 0xB53C, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x5326, 0, 0, 0, 0, 0, 0, 0,
+ 0xB53D, 0x3077, 0x532F, 0, 0, 0x5327, 0x5328, 0,
+ 0x3E25, 0x4B69, 0xB53E, 0, 0xB53F, 0x532D, 0x532C, 0xB540,
+ 0, 0, 0x452F, 0, 0, 0, 0xB541, 0,
+ 0, 0, 0x532E, 0, 0xB542, 0x532B, 0xB543, 0xB544,
+};
+static const unsigned short utf8_to_euc_E593_x0213[] = {
+ 0x3025, 0x494A, 0x5322, 0xA376, 0x527C, 0, 0x2F22, 0x5277,
+ 0x527D, 0x3A48, 0xB53A, 0, 0, 0xB53B, 0xB53C, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x5326, 0, 0, 0, 0, 0, 0, 0,
+ 0xB53D, 0x3077, 0x532F, 0, 0, 0x5327, 0x5328, 0,
+ 0x3E25, 0x4B69, 0xB53E, 0, 0xA378, 0x532D, 0x532C, 0xA379,
+ 0, 0xA37A, 0x452F, 0xA37B, 0, 0, 0xB541, 0,
+ 0, 0, 0x532E, 0, 0xB542, 0x532B, 0xB543, 0x2F23,
+};
+static const unsigned short utf8_to_euc_E594[] = {
+ 0xB545, 0xB546, 0, 0, 0x3134, 0xB547, 0x3A36, 0x3F30,
+ 0xB548, 0xB549, 0, 0, 0xB54A, 0xB54B, 0xB54C, 0x5329,
+ 0x4562, 0, 0, 0, 0x532A, 0xB54D, 0x3022, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xB54E, 0xB54F, 0, 0, 0x5334, 0x4D23,
+ 0, 0x3E27, 0xB550, 0x533A, 0, 0xB551, 0xB552, 0,
+ 0x5339, 0x5330, 0, 0xB553, 0xB554, 0xB555, 0x4243, 0,
+};
+static const unsigned short utf8_to_euc_E594_x0213[] = {
+ 0xA37C, 0xA37D, 0, 0, 0x3134, 0xB547, 0x3A36, 0x3F30,
+ 0xB548, 0xA37E, 0, 0, 0xB54A, 0xB54B, 0x2F24, 0x5329,
+ 0x4562, 0, 0, 0, 0x532A, 0xB54D, 0x3022, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xB54E, 0x2F25, 0, 0, 0x5334, 0x4D23,
+ 0, 0x3E27, 0xB550, 0x533A, 0, 0x2F26, 0xB552, 0,
+ 0x5339, 0x5330, 0, 0xB553, 0xA421, 0xB555, 0x4243, 0,
+};
+static const unsigned short utf8_to_euc_E595[] = {
+ 0x5331, 0xB556, 0, 0, 0x426F, 0x5336, 0x3E26, 0xB557,
+ 0, 0xB558, 0xB559, 0, 0x5333, 0xB55A, 0, 0x4C64,
+ 0xB55B, 0xB55C, 0, 0x373C, 0, 0, 0x5337, 0x5338,
+ 0xB55D, 0, 0xB55E, 0xB55F, 0x5335, 0x533B, 0xB560, 0,
+ 0xB561, 0xB562, 0, 0x5332, 0xB563, 0, 0xB564, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x5341, 0x5346, 0, 0x5342, 0xB565,
+};
+static const unsigned short utf8_to_euc_E595_x0213[] = {
+ 0x5331, 0xA422, 0, 0, 0x426F, 0x5336, 0x3E26, 0xA424,
+ 0, 0xB558, 0xA425, 0, 0x5333, 0xB55A, 0, 0x4C64,
+ 0x2F27, 0xB55C, 0, 0x373C, 0, 0, 0x5337, 0x5338,
+ 0xB55D, 0, 0xB55E, 0xB55F, 0x5335, 0x533B, 0x2F28, 0,
+ 0xA427, 0xA428, 0, 0x5332, 0xA429, 0, 0xB564, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x5341, 0x5346, 0xA42B, 0x5342, 0xB565,
+};
+static const unsigned short utf8_to_euc_E596[] = {
+ 0x533D, 0xB566, 0xB567, 0x5347, 0x4131, 0, 0xB568, 0x5349,
+ 0xB569, 0x3922, 0x533F, 0x437D, 0, 0, 0xB56A, 0xB56B,
+ 0, 0xB56C, 0xB56D, 0xB56E, 0xB56F, 0, 0, 0xB570,
+ 0x5343, 0x533C, 0x342D, 0, 0x346E, 0x3365, 0x5344, 0x5340,
+ 0, 0, 0, 0xB571, 0xB572, 0, 0, 0x3776,
+ 0x534A, 0x5348, 0x4153, 0x354A, 0x362C, 0xB573, 0x5345, 0,
+ 0x3674, 0, 0xB574, 0, 0, 0, 0x3144, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xB575,
+};
+static const unsigned short utf8_to_euc_E596_x0213[] = {
+ 0x533D, 0x2F29, 0xA42C, 0x5347, 0x4131, 0, 0x2F2A, 0x5349,
+ 0xA42D, 0x3922, 0x533F, 0x437D, 0, 0, 0x2F2B, 0xB56B,
+ 0, 0xA42E, 0xB56D, 0xB56E, 0xB56F, 0, 0, 0xB570,
+ 0x5343, 0x533C, 0x342D, 0, 0x346E, 0x3365, 0x5344, 0x5340,
+ 0, 0, 0, 0xB571, 0xB572, 0, 0, 0x3776,
+ 0x534A, 0x5348, 0x4153, 0x354A, 0x362C, 0x2F2D, 0x5345, 0,
+ 0x3674, 0, 0xB574, 0, 0, 0, 0x3144, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xA433,
+};
+static const unsigned short utf8_to_euc_E597[] = {
+ 0, 0xB576, 0, 0xB577, 0x534E, 0x534C, 0xB578, 0x5427,
+ 0, 0xB579, 0, 0xB57A, 0xB57B, 0, 0xB57C, 0,
+ 0, 0xB57D, 0xB57E, 0xB621, 0x5351, 0, 0, 0xB622,
+ 0xB623, 0, 0x534B, 0xB624, 0x534F, 0, 0xB625, 0x534D,
+ 0, 0, 0xB626, 0x3B4C, 0x5350, 0, 0, 0,
+ 0, 0xB627, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xB628, 0x5353,
+ 0, 0x5358, 0, 0, 0, 0x5356, 0x5355, 0xB629,
+};
+static const unsigned short utf8_to_euc_E597_x0213[] = {
+ 0, 0xB576, 0, 0xB577, 0x534E, 0x534C, 0xB578, 0x5427,
+ 0, 0xA434, 0, 0xB57A, 0xA435, 0, 0x2F2E, 0,
+ 0, 0xA436, 0xA430, 0xB621, 0x5351, 0, 0, 0xB622,
+ 0xB623, 0, 0x534B, 0xB624, 0x534F, 0xA437, 0xB625, 0x534D,
+ 0, 0, 0xA439, 0x3B4C, 0x5350, 0, 0, 0,
+ 0, 0xA43B, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xB628, 0x5353,
+ 0, 0x5358, 0, 0, 0, 0x5356, 0x5355, 0xB629,
+};
+static const unsigned short utf8_to_euc_E598[] = {
+ 0, 0, 0, 0, 0, 0xB62A, 0x4332, 0,
+ 0xB62B, 0x3245, 0xB62C, 0, 0, 0xB62D, 0xB62E, 0xB62F,
+ 0xB630, 0xB631, 0xB632, 0, 0x5352, 0, 0x5354, 0x3E28,
+ 0x3133, 0xB633, 0, 0x5357, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x325E, 0, 0, 0xB634, 0, 0, 0x5362,
+ 0xB635, 0x3E7C, 0x535E, 0xB636, 0x535C, 0xB637, 0x535D, 0xB638,
+ 0x535F, 0xB639, 0, 0xB63A, 0xB63B, 0xB63C, 0, 0xB63D,
+};
+static const unsigned short utf8_to_euc_E598_x0213[] = {
+ 0, 0, 0, 0, 0, 0xB62A, 0x4332, 0xA43E,
+ 0x2F30, 0x3245, 0xB62C, 0, 0, 0xB62D, 0x2F31, 0xB62F,
+ 0xA43F, 0xB631, 0xB632, 0, 0x5352, 0, 0x5354, 0x3E28,
+ 0x3133, 0xB633, 0, 0x5357, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xA43C, 0x325E, 0, 0, 0xB634, 0, 0, 0x5362,
+ 0xA440, 0x3E7C, 0x535E, 0xB636, 0x535C, 0xB637, 0x535D, 0xA441,
+ 0x535F, 0xB639, 0, 0x2F32, 0xB63B, 0xA443, 0, 0xA444,
+};
+static const unsigned short utf8_to_euc_E599[] = {
+ 0xB63E, 0xB63F, 0x313D, 0xB640, 0xB641, 0, 0xB642, 0,
+ 0, 0xB643, 0, 0xB644, 0x4139, 0xB645, 0x5359, 0xB646,
+ 0x535A, 0, 0, 0, 0xB647, 0, 0, 0,
+ 0, 0, 0, 0x337A, 0, 0, 0xB648, 0,
+ 0xB649, 0xB64A, 0xB64B, 0xB64C, 0x5361, 0, 0xB64D, 0,
+ 0x346F, 0xB64E, 0x5364, 0x5360, 0x5363, 0xB64F, 0, 0xB650,
+ 0, 0xB651, 0xB652, 0, 0x4A2E, 0xB653, 0, 0,
+ 0x4655, 0, 0x4838, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E599_x0213[] = {
+ 0xA445, 0xB63F, 0x313D, 0xB640, 0xB641, 0, 0xB642, 0xA446,
+ 0, 0x2F33, 0, 0xB644, 0x4139, 0xB645, 0x5359, 0xB646,
+ 0x535A, 0, 0, 0x7427, 0xB647, 0, 0, 0,
+ 0, 0, 0, 0x337A, 0, 0, 0xA447, 0,
+ 0xA448, 0xB64A, 0xB64B, 0xB64C, 0x5361, 0, 0x2F35, 0,
+ 0x346F, 0xB64E, 0x5364, 0x5360, 0x5363, 0xA449, 0, 0x2F37,
+ 0, 0x2F38, 0x2F39, 0, 0x4A2E, 0xB653, 0x2F34, 0,
+ 0x4655, 0, 0x4838, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E59A[] = {
+ 0x5366, 0, 0, 0, 0xB654, 0xB655, 0x5365, 0x3345,
+ 0xB656, 0, 0x5367, 0xB657, 0xB658, 0, 0, 0x536A,
+ 0, 0, 0, 0, 0x5369, 0xB659, 0, 0,
+ 0, 0xB65A, 0xB65B, 0, 0, 0xB65C, 0xB65D, 0xB65E,
+ 0x5368, 0, 0x4739, 0, 0, 0x536B, 0xB65F, 0xB660,
+ 0xB661, 0xB662, 0, 0xB663, 0xB664, 0xB665, 0x536C, 0,
+ 0, 0xB666, 0, 0xB667, 0x536E, 0, 0x536D, 0xB668,
+ 0, 0, 0, 0, 0x5370, 0, 0xB669, 0,
+};
+static const unsigned short utf8_to_euc_E59A_x0213[] = {
+ 0x5366, 0, 0, 0, 0xB654, 0xB655, 0x5365, 0x3345,
+ 0xA44B, 0, 0x5367, 0xB657, 0xA44C, 0, 0, 0x536A,
+ 0, 0, 0, 0, 0x5369, 0xA44D, 0, 0,
+ 0, 0x2F3A, 0xA44E, 0, 0, 0xA44F, 0x2F3B, 0xB65E,
+ 0x5368, 0, 0x4739, 0, 0, 0x536B, 0xB65F, 0xB660,
+ 0xA450, 0x2F3C, 0, 0xB663, 0x2F3D, 0xA451, 0x536C, 0,
+ 0, 0xB666, 0xA452, 0x2F3E, 0x536E, 0, 0x536D, 0xB668,
+ 0, 0, 0, 0, 0x5370, 0, 0xB669, 0,
+};
+static const unsigned short utf8_to_euc_E59B[] = {
+ 0x5373, 0x5371, 0x536F, 0x5372, 0, 0xB66A, 0, 0,
+ 0x5374, 0xB66B, 0xB66C, 0xB66D, 0xB670, 0xB671, 0x5375, 0xB66E,
+ 0xB66F, 0x5376, 0, 0x5377, 0, 0, 0, 0x5378,
+ 0x5145, 0xB672, 0x3C7C, 0x3B4D, 0xB673, 0xB674, 0x3273, 0xB675,
+ 0x3078, 0xB676, 0, 0x4344, 0xB677, 0xB678, 0xB679, 0xB67A,
+ 0xB67B, 0, 0, 0xB67D, 0, 0xB67E, 0x5379, 0,
+ 0x3A24, 0xB67C, 0x304F, 0x3F5E, 0, 0, 0xB721, 0xB722,
+ 0, 0x537A, 0x3847, 0, 0, 0x3971, 0, 0x537C,
+};
+static const unsigned short utf8_to_euc_E59B_x0213[] = {
+ 0x5373, 0x5371, 0x536F, 0x5372, 0, 0xA453, 0, 0,
+ 0x5374, 0x2F3F, 0x2F40, 0xB66D, 0xB670, 0xA454, 0x5375, 0xB66E,
+ 0xB66F, 0x5376, 0, 0x5377, 0, 0, 0, 0x5378,
+ 0x5145, 0xB672, 0x3C7C, 0x3B4D, 0xB673, 0xB674, 0x3273, 0xA455,
+ 0x3078, 0xB676, 0, 0x4344, 0xB677, 0xB678, 0xB679, 0xB67A,
+ 0xA456, 0, 0, 0xB67D, 0, 0xB67E, 0x5379, 0,
+ 0x3A24, 0xB67C, 0x304F, 0x3F5E, 0, 0, 0xA457, 0xA458,
+ 0, 0x537A, 0x3847, 0, 0, 0x3971, 0, 0x537C,
+};
+static const unsigned short utf8_to_euc_E59C[] = {
+ 0x537B, 0xB723, 0xB724, 0x4A60, 0x537D, 0, 0, 0xB725,
+ 0x5421, 0x537E, 0xB726, 0x5422, 0xB727, 0x5423, 0, 0x3777,
+ 0, 0xB728, 0x3160, 0x5424, 0, 0xB729, 0x5426, 0,
+ 0x5425, 0, 0xB72A, 0xB72B, 0x5428, 0xB72C, 0, 0x455A,
+ 0xB72D, 0, 0xB72E, 0xB72F, 0xB730, 0xB731, 0x5429, 0x3035,
+ 0x3A5F, 0xB732, 0xB733, 0, 0xB734, 0x373D, 0xB735, 0xB736,
+ 0x434F, 0, 0, 0xB737, 0xB738, 0, 0, 0x542A,
+ 0x542B, 0, 0, 0x542D, 0, 0xB739, 0xB73A, 0xB73B,
+};
+static const unsigned short utf8_to_euc_E59C_x0213[] = {
+ 0x537B, 0xB723, 0xB724, 0x4A60, 0x537D, 0, 0, 0xB725,
+ 0x5421, 0x537E, 0x2F41, 0x5422, 0xB727, 0x5423, 0, 0x3777,
+ 0, 0xB728, 0x3160, 0x5424, 0, 0xA45A, 0x5426, 0,
+ 0x5425, 0, 0xB72A, 0xB72B, 0x5428, 0xB72C, 0, 0x455A,
+ 0xB72D, 0x2F43, 0xB72E, 0xA45B, 0xB730, 0xB731, 0x5429, 0x3035,
+ 0x3A5F, 0xA45D, 0xB733, 0, 0xB734, 0x373D, 0xB735, 0x2F44,
+ 0x434F, 0, 0, 0x2F45, 0x2F46, 0, 0, 0x542A,
+ 0x542B, 0, 0, 0x542D, 0, 0xB739, 0xB73A, 0xB73B,
+};
+static const unsigned short utf8_to_euc_E59D[] = {
+ 0x542E, 0, 0x3A64, 0, 0, 0xB73C, 0xB73D, 0x3651,
+ 0, 0, 0x4B37, 0, 0xB73E, 0xB73F, 0x542C, 0x542F,
+ 0x3A41, 0x3923, 0xB740, 0, 0, 0, 0, 0,
+ 0, 0xF436, 0, 0, 0, 0, 0, 0,
+ 0, 0x5433, 0xB741, 0, 0x3A25, 0xB742, 0x4333, 0xB743,
+ 0xB744, 0x5430, 0x445A, 0xB745, 0, 0xB746, 0xB747, 0xB748,
+ 0xB749, 0xB74A, 0, 0xB74B, 0xB74C, 0xB74D, 0, 0xB74E,
+ 0, 0xB74F, 0xB750, 0xB751, 0xB752, 0, 0xB753, 0x5434,
+};
+static const unsigned short utf8_to_euc_E59D_x0213[] = {
+ 0x542E, 0, 0x3A64, 0, 0, 0xA45F, 0xA460, 0x3651,
+ 0, 0, 0x4B37, 0, 0xA461, 0xA462, 0x542C, 0x542F,
+ 0x3A41, 0x3923, 0xB740, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x5433, 0xB741, 0, 0x3A25, 0, 0x4333, 0xB743,
+ 0xA464, 0x5430, 0x445A, 0xB745, 0, 0xB746, 0xB747, 0xA465,
+ 0x2F47, 0xB74A, 0, 0xA466, 0xA467, 0xA468, 0, 0x2F48,
+ 0, 0xB74F, 0xB750, 0xA469, 0x2F49, 0, 0xB753, 0x5434,
+};
+static const unsigned short utf8_to_euc_E59E[] = {
+ 0, 0xB754, 0x3F62, 0xB755, 0, 0, 0, 0,
+ 0x5432, 0x5435, 0, 0x373F, 0xB756, 0, 0, 0,
+ 0, 0, 0, 0x5436, 0xB757, 0xB760, 0, 0xB758,
+ 0, 0xB759, 0xB75A, 0, 0xB75B, 0xB75C, 0xB75D, 0xB75E,
+ 0x5437, 0xB75F, 0x3924, 0x3340, 0x5439, 0, 0, 0xB761,
+ 0xB762, 0xB763, 0x543A, 0, 0xB764, 0, 0, 0,
+ 0x543B, 0, 0, 0x5438, 0, 0, 0, 0,
+ 0xB765, 0, 0, 0, 0, 0xB766, 0, 0,
+};
+static const unsigned short utf8_to_euc_E59E_x0213[] = {
+ 0, 0xB754, 0x3F62, 0xB755, 0, 0, 0, 0,
+ 0x5432, 0x5435, 0, 0x373F, 0xB756, 0, 0, 0,
+ 0, 0, 0, 0x5436, 0xB757, 0xB760, 0, 0xB758,
+ 0, 0xB759, 0xA46D, 0, 0x2F4A, 0xA46E, 0xA46F, 0xB75E,
+ 0x5437, 0xB75F, 0x3924, 0x3340, 0x5439, 0, 0, 0xB761,
+ 0xA470, 0xB763, 0x543A, 0, 0xA46C, 0, 0, 0,
+ 0x543B, 0, 0, 0x5438, 0, 0, 0, 0,
+ 0x2F4D, 0, 0, 0, 0, 0xB766, 0, 0,
+};
+static const unsigned short utf8_to_euc_E59F[] = {
+ 0x5431, 0, 0, 0x543C, 0, 0, 0x543D, 0xB767,
+ 0xB768, 0, 0, 0x4B64, 0xB769, 0, 0x3E6B, 0xB76A,
+ 0, 0, 0x543F, 0x5440, 0x543E, 0xB76B, 0x5442, 0,
+ 0, 0, 0, 0, 0x4738, 0xB76C, 0xB76D, 0x3068,
+ 0x4956, 0xB77E, 0, 0x5443, 0xB76E, 0, 0xB76F, 0xB770,
+ 0, 0xB771, 0, 0, 0, 0xB772, 0, 0,
+ 0xB773, 0, 0, 0, 0x3E7D, 0xB774, 0xB775, 0x3C39,
+ 0xB776, 0x475D, 0x3470, 0, 0x3A6B, 0xB777, 0xB778, 0xB779,
+};
+static const unsigned short utf8_to_euc_E59F_x0213[] = {
+ 0x5431, 0, 0, 0x543C, 0, 0, 0x543D, 0x2F4E,
+ 0x2F4F, 0, 0, 0x4B64, 0xA473, 0, 0x3E6B, 0x2F50,
+ 0, 0, 0x543F, 0x5440, 0x543E, 0xB76B, 0x5442, 0xA471,
+ 0, 0, 0, 0, 0x4738, 0xB76C, 0xA476, 0x3068,
+ 0x4956, 0xB77E, 0, 0x5443, 0x2F51, 0, 0xA477, 0xB770,
+ 0, 0xB771, 0, 0, 0, 0x2F52, 0, 0,
+ 0xA478, 0, 0, 0, 0x3E7D, 0x2F53, 0x2F54, 0x3C39,
+ 0xA47A, 0x475D, 0x3470, 0xA47B, 0x3A6B, 0xA47C, 0xB778, 0x2F55,
+};
+static const unsigned short utf8_to_euc_E5A0[] = {
+ 0x4B59, 0, 0x4632, 0xB77A, 0xB77B, 0x3778, 0x424F, 0,
+ 0xB77C, 0xB77D, 0x5441, 0x5444, 0xB821, 0xB822, 0, 0,
+ 0, 0, 0, 0, 0, 0x4244, 0, 0,
+ 0, 0x5445, 0, 0xB823, 0, 0x5446, 0xB824, 0xB825,
+ 0xB826, 0x5448, 0, 0, 0x4469, 0, 0xB827, 0xB828,
+ 0, 0, 0x342E, 0, 0, 0xB829, 0, 0x7421,
+ 0x3161, 0x4A73, 0xB82A, 0, 0x3E6C, 0x4548, 0, 0,
+ 0, 0xB82B, 0x3A66, 0, 0, 0x544E, 0, 0xB82C,
+};
+static const unsigned short utf8_to_euc_E5A0_x0213[] = {
+ 0x4B59, 0, 0x4632, 0xB77A, 0xA47D, 0x3778, 0x424F, 0,
+ 0xB77C, 0x2F56, 0x5441, 0x5444, 0xB821, 0xB822, 0, 0,
+ 0, 0, 0, 0, 0, 0x4244, 0, 0,
+ 0, 0x5445, 0, 0xB823, 0, 0x5446, 0xA47E, 0xB825,
+ 0xA521, 0x5448, 0, 0, 0x4469, 0, 0xB827, 0xA522,
+ 0, 0, 0x342E, 0, 0, 0xB829, 0, 0x7421,
+ 0x3161, 0x4A73, 0xA523, 0, 0x3E6C, 0x4548, 0, 0,
+ 0, 0xA524, 0x3A66, 0, 0, 0x544E, 0, 0xB82C,
+};
+static const unsigned short utf8_to_euc_E5A1[] = {
+ 0x4A3D, 0x4E5D, 0, 0, 0, 0, 0, 0,
+ 0, 0xB82D, 0x3274, 0x544A, 0xB82E, 0xB82F, 0, 0xB830,
+ 0xB831, 0x413A, 0x544D, 0, 0x4563, 0xB832, 0, 0x4549,
+ 0x4564, 0x4839, 0x444D, 0, 0, 0, 0x3A49, 0xB833,
+ 0, 0xB834, 0x5449, 0, 0xB835, 0, 0, 0xB836,
+ 0xB837, 0x3176, 0, 0x4536, 0, 0, 0, 0,
+ 0x544B, 0, 0x5447, 0, 0, 0x3F50, 0, 0,
+ 0xB838, 0x544F, 0, 0, 0xB839, 0, 0x3D4E, 0xB83A,
+};
+static const unsigned short utf8_to_euc_E5A1_x0213[] = {
+ 0x4A3D, 0x4E5D, 0, 0, 0, 0, 0, 0,
+ 0, 0xA526, 0x3274, 0x544A, 0xA527, 0xB82F, 0, 0xB830,
+ 0xB831, 0x413A, 0x544D, 0, 0x4563, 0xB832, 0, 0x4549,
+ 0x4564, 0x4839, 0x444D, 0, 0, 0, 0x3A49, 0xB833,
+ 0, 0x2F58, 0x5449, 0, 0x2F59, 0, 0, 0xA528,
+ 0xB837, 0x3176, 0, 0x4536, 0, 0, 0, 0,
+ 0x544B, 0, 0x5447, 0, 0, 0x3F50, 0, 0,
+ 0xB838, 0x544F, 0, 0, 0x2F5B, 0, 0x3D4E, 0xB83A,
+};
+static const unsigned short utf8_to_euc_E5A2[] = {
+ 0xB83B, 0xB83C, 0, 0x362D, 0, 0x5450, 0, 0xB83D,
+ 0xB83E, 0xB83F, 0xB840, 0, 0xB841, 0xB842, 0, 0xB843,
+ 0xB844, 0, 0, 0x4A68, 0xB845, 0, 0xB846, 0x417D,
+ 0, 0, 0, 0, 0x4446, 0xB847, 0xF439, 0x5452,
+ 0xB848, 0xB849, 0xB84A, 0, 0, 0, 0xB84B, 0,
+ 0x4B4F, 0xB84C, 0, 0x5453, 0, 0, 0x5458, 0,
+ 0, 0xB84D, 0xB84E, 0x4A2F, 0, 0, 0, 0,
+ 0x5457, 0x5451, 0x5454, 0x5456, 0xB850, 0, 0x3A26, 0,
+};
+static const unsigned short utf8_to_euc_E5A2_x0213[] = {
+ 0xB83B, 0xB83C, 0, 0x362D, 0, 0x5450, 0, 0xB83D,
+ 0xB83E, 0x2F5C, 0xA529, 0xA52A, 0xB841, 0xA52B, 0, 0xA52C,
+ 0xA52D, 0, 0, 0x4A68, 0xA52E, 0, 0xB846, 0x417D,
+ 0, 0, 0, 0, 0x4446, 0xA52F, 0x2F5D, 0x5452,
+ 0xB848, 0xB849, 0xB84A, 0, 0, 0, 0xB84B, 0,
+ 0x4B4F, 0x2F5F, 0xA530, 0x5453, 0, 0, 0x5458, 0,
+ 0, 0xA531, 0, 0x4A2F, 0, 0, 0, 0,
+ 0x5457, 0x5451, 0x5454, 0x5456, 0xB850, 0, 0x3A26, 0,
+};
+static const unsigned short utf8_to_euc_E5A3[] = {
+ 0, 0x4A49, 0xB851, 0, 0xB84F, 0x5459, 0, 0x4345,
+ 0xB852, 0, 0x3275, 0, 0x3E6D, 0xB853, 0xB854, 0,
+ 0xB855, 0x545B, 0xB856, 0x545A, 0xB857, 0x3968, 0xB858, 0x545C,
+ 0x545E, 0x545D, 0xB859, 0, 0x5460, 0xB85A, 0x5455, 0x5462,
+ 0, 0xB85B, 0xB85C, 0, 0x5461, 0x545F, 0, 0,
+ 0, 0xB85D, 0, 0x3B4E, 0x3F51, 0, 0x4154, 0x5463,
+ 0x403C, 0x306D, 0x4764, 0xB85E, 0, 0, 0, 0x445B,
+ 0, 0x5465, 0x5464, 0x5466, 0x5467, 0x5468, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5A3_x0213[] = {
+ 0, 0x4A49, 0xB851, 0xA533, 0xB84F, 0x5459, 0, 0x4345,
+ 0xB852, 0, 0x3275, 0, 0x3E6D, 0xA534, 0x2F62, 0,
+ 0xB855, 0x545B, 0x2F61, 0x545A, 0x2F63, 0x3968, 0xB858, 0x545C,
+ 0x545E, 0x545D, 0x2F64, 0, 0x5460, 0xB85A, 0x5455, 0x5462,
+ 0x2F65, 0xB85B, 0xA535, 0, 0x5461, 0x545F, 0, 0,
+ 0, 0x2F66, 0, 0x3B4E, 0x3F51, 0, 0x4154, 0x5463,
+ 0x403C, 0x306D, 0x4764, 0xA536, 0xA537, 0, 0, 0x445B,
+ 0, 0x5465, 0x5464, 0x5466, 0x5467, 0x5468, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5A4[] = {
+ 0, 0, 0x5469, 0, 0, 0xB85F, 0xB860, 0,
+ 0, 0x4A51, 0x546A, 0xB861, 0xB862, 0, 0, 0x3246,
+ 0x546B, 0, 0xB863, 0xB864, 0xB865, 0x4D3C, 0x3330, 0,
+ 0x5249, 0x3D48, 0x423F, 0x546C, 0x4C6B, 0xB867, 0, 0,
+ 0, 0xB868, 0x4C34, 0xB869, 0xB86A, 0x546E, 0, 0x4267,
+ 0xB86B, 0x4537, 0x4240, 0x4957, 0x546F, 0x5470, 0x317B, 0xB86C,
+ 0xB86D, 0x3C3A, 0x5471, 0xB86E, 0, 0xB86F, 0xB870, 0x3050,
+ 0x5472, 0, 0, 0, 0, 0, 0x5473, 0xB871,
+};
+static const unsigned short utf8_to_euc_E5A4_x0213[] = {
+ 0, 0, 0x5469, 0, 0, 0xA538, 0xA539, 0,
+ 0, 0x4A51, 0x546A, 0xA53A, 0x2F67, 0xA53B, 0, 0x3246,
+ 0x546B, 0, 0xB863, 0xB864, 0xA53C, 0x4D3C, 0x3330, 0,
+ 0x5249, 0x3D48, 0x423F, 0x546C, 0x4C6B, 0xB867, 0, 0,
+ 0, 0xB868, 0x4C34, 0xB869, 0xA53D, 0x546E, 0, 0x4267,
+ 0xB86B, 0x4537, 0x4240, 0x4957, 0x546F, 0x5470, 0x317B, 0xB86C,
+ 0xB86D, 0x3C3A, 0x5471, 0xB86E, 0, 0xB86F, 0xB870, 0x3050,
+ 0x5472, 0, 0, 0, 0, 0xA540, 0x5473, 0xB871,
+};
+static const unsigned short utf8_to_euc_E5A5[] = {
+ 0, 0, 0, 0xB872, 0x3162, 0, 0xB873, 0x3471,
+ 0x4660, 0x4A74, 0, 0, 0, 0, 0x5477, 0x4155,
+ 0x5476, 0x3740, 0xB874, 0xB875, 0x4B5B, 0x5475, 0, 0x4565,
+ 0x5479, 0xB876, 0x5478, 0xB877, 0, 0xB878, 0xB879, 0xB87A,
+ 0x547B, 0xB87B, 0x547A, 0xB87C, 0, 0x317C, 0, 0x547C,
+ 0x3E29, 0x547E, 0x4325, 0xB87D, 0x547D, 0xB87E, 0x4A33, 0xB921,
+ 0, 0, 0xB922, 0x3D77, 0x455B, 0xB923, 0xB924, 0,
+ 0x5521, 0xB925, 0, 0xB926, 0xB927, 0x3925, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5A5_x0213[] = {
+ 0, 0, 0, 0xB872, 0x3162, 0, 0xA542, 0x3471,
+ 0x4660, 0x4A74, 0, 0, 0, 0, 0x5477, 0x4155,
+ 0x5476, 0x3740, 0xB874, 0, 0x4B5B, 0x5475, 0, 0x4565,
+ 0x5479, 0xB876, 0x5478, 0xA545, 0, 0x2F69, 0xB879, 0xA546,
+ 0x547B, 0xB87B, 0x547A, 0, 0, 0x317C, 0, 0x547C,
+ 0x3E29, 0x547E, 0x4325, 0xB87D, 0x547D, 0x2F6A, 0x4A33, 0xB921,
+ 0, 0, 0xB922, 0x3D77, 0x455B, 0xA548, 0xA549, 0,
+ 0x5521, 0xB925, 0, 0xB926, 0xA54A, 0x3925, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5A6[] = {
+ 0, 0x5522, 0x4721, 0x485E, 0x4C51, 0, 0, 0,
+ 0, 0, 0x4725, 0xB928, 0xB929, 0x552B, 0xB92A, 0,
+ 0, 0, 0xB92B, 0x3538, 0, 0xB92C, 0x4D45, 0xB92D,
+ 0, 0x4C2F, 0, 0x562C, 0, 0x5523, 0, 0xB92E,
+ 0, 0, 0, 0x5526, 0xB92F, 0x4245, 0, 0xB930,
+ 0x4B38, 0, 0, 0, 0x454A, 0xB931, 0xB932, 0xB933,
+ 0xB934, 0, 0x5527, 0xB935, 0, 0, 0, 0xB936,
+ 0, 0x4B65, 0xB937, 0x3A4A, 0xB938, 0, 0x3E2A, 0,
+};
+static const unsigned short utf8_to_euc_E5A6_x0213[] = {
+ 0, 0x5522, 0x4721, 0x485E, 0x4C51, 0, 0, 0,
+ 0, 0, 0x4725, 0x2F6B, 0xB929, 0x552B, 0xB92A, 0,
+ 0, 0, 0x2F6C, 0x3538, 0, 0xB92C, 0x4D45, 0xB92D,
+ 0, 0x4C2F, 0, 0x562C, 0, 0x5523, 0, 0xA54B,
+ 0, 0, 0, 0x5526, 0x2F6D, 0x4245, 0, 0xB930,
+ 0x4B38, 0, 0, 0, 0x454A, 0xB931, 0xA54C, 0xB933,
+ 0xB934, 0, 0x5527, 0xB935, 0, 0, 0, 0xB936,
+ 0, 0x4B65, 0, 0x3A4A, 0xA54D, 0, 0x3E2A, 0,
+};
+static const unsigned short utf8_to_euc_E5A7[] = {
+ 0, 0xB939, 0, 0xB93A, 0xB93B, 0, 0x5528, 0,
+ 0xB93C, 0x3B50, 0xB93D, 0x3B4F, 0, 0xB93E, 0, 0,
+ 0x3039, 0x3848, 0xB93F, 0x402B, 0x3051, 0, 0, 0,
+ 0, 0x552C, 0x552D, 0, 0x552A, 0xB940, 0xB941, 0xB942,
+ 0, 0, 0, 0xB943, 0xB944, 0x3138, 0x342F, 0xB945,
+ 0x5529, 0, 0x4C45, 0x4931, 0, 0, 0xB946, 0xB947,
+ 0, 0xB948, 0xB949, 0, 0xB94A, 0, 0x3028, 0xB94B,
+ 0, 0, 0, 0x3079, 0, 0, 0, 0x3B51,
+};
+static const unsigned short utf8_to_euc_E5A7_x0213[] = {
+ 0, 0xB939, 0, 0x2F6E, 0xB93B, 0, 0x5528, 0,
+ 0xA54E, 0x3B50, 0xB93D, 0x3B4F, 0, 0xA54F, 0, 0,
+ 0x3039, 0x3848, 0x2F6F, 0x402B, 0x3051, 0, 0, 0,
+ 0, 0x552C, 0x552D, 0, 0x552A, 0x2F70, 0xA550, 0xB942,
+ 0, 0, 0, 0xA551, 0xA552, 0x3138, 0x342F, 0xA553,
+ 0x5529, 0, 0x4C45, 0x4931, 0, 0, 0xA554, 0xB947,
+ 0, 0xB948, 0xB949, 0, 0xB94A, 0, 0x3028, 0xB94B,
+ 0x7E7A, 0, 0, 0x3079, 0, 0, 0, 0x3B51,
+};
+static const unsigned short utf8_to_euc_E5A8[] = {
+ 0xB94C, 0x3052, 0, 0x3023, 0xB94D, 0, 0, 0,
+ 0, 0x5532, 0, 0, 0xB94E, 0xB94F, 0xB950, 0,
+ 0, 0x5530, 0xB951, 0xB952, 0, 0, 0, 0,
+ 0x4C3C, 0, 0x5533, 0, 0x5531, 0, 0xB953, 0x552F,
+ 0x3F31, 0, 0, 0xB954, 0xB955, 0x552E, 0, 0xB956,
+ 0xB957, 0x4A5A, 0xB958, 0, 0, 0xB959, 0, 0x3864,
+ 0xB95A, 0, 0, 0, 0, 0x5537, 0x5538, 0,
+ 0, 0, 0, 0, 0x3E2B, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5A8_x0213[] = {
+ 0xB94C, 0x3052, 0, 0x3023, 0xB94D, 0, 0, 0,
+ 0, 0x5532, 0, 0, 0xA558, 0xA559, 0xB950, 0,
+ 0, 0x5530, 0xB951, 0x2F71, 0, 0, 0, 0xA55A,
+ 0x4C3C, 0, 0x5533, 0, 0x5531, 0, 0xB953, 0x552F,
+ 0x3F31, 0, 0, 0x2F72, 0xB955, 0x552E, 0, 0xA55B,
+ 0xB957, 0x4A5A, 0xB958, 0, 0, 0xA55C, 0, 0x3864,
+ 0xB95A, 0, 0, 0, 0, 0x5537, 0x5538, 0,
+ 0, 0, 0, 0, 0x3E2B, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5A9[] = {
+ 0x5534, 0x4F2C, 0, 0, 0xB95B, 0xB95C, 0x474C, 0xB95D,
+ 0xB95E, 0x5536, 0, 0, 0xB95F, 0, 0, 0,
+ 0xB960, 0, 0, 0, 0, 0xB961, 0, 0,
+ 0, 0, 0x3A27, 0, 0, 0, 0xB962, 0,
+ 0, 0, 0x5539, 0xB963, 0, 0xB964, 0x4958, 0xB965,
+ 0, 0, 0x553A, 0, 0x5535, 0xB966, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xB967,
+ 0, 0, 0xB968, 0xB969, 0, 0, 0xB96A, 0x4C3B,
+};
+static const unsigned short utf8_to_euc_E5A9_x0213[] = {
+ 0x5534, 0x4F2C, 0, 0, 0xB95B, 0xB95C, 0x474C, 0xB95D,
+ 0xB95E, 0x5536, 0, 0, 0xB95F, 0, 0, 0,
+ 0xB960, 0, 0, 0, 0, 0xA55D, 0, 0,
+ 0, 0, 0x3A27, 0, 0, 0, 0xB962, 0,
+ 0, 0, 0x5539, 0xB963, 0, 0xA55E, 0x4958, 0x2F73,
+ 0, 0, 0x553A, 0, 0x5535, 0x2F74, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x2F75,
+ 0, 0, 0xA55F, 0xB969, 0, 0, 0x2F76, 0x4C3B,
+};
+static const unsigned short utf8_to_euc_E5AA[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xB96B, 0, 0, 0, 0,
+ 0xB96C, 0, 0x475E, 0xB96D, 0, 0, 0xB96E, 0,
+ 0, 0xB96F, 0x553B, 0x4932, 0xB970, 0, 0xB971, 0xB972,
+ 0xB973, 0, 0xB974, 0, 0, 0, 0, 0xB975,
+ 0, 0, 0, 0, 0xB976, 0, 0, 0,
+ 0, 0xB977, 0xB978, 0xB979, 0, 0xB97A, 0, 0,
+ 0xB97B, 0, 0xB97C, 0xB97D, 0x553C, 0x5540, 0x553D, 0xB97E,
+};
+static const unsigned short utf8_to_euc_E5AA_x0213[] = {
+ 0, 0, 0, 0, 0x2F77, 0, 0, 0,
+ 0, 0, 0, 0xA560, 0, 0, 0, 0,
+ 0xB96C, 0, 0x475E, 0xB96D, 0, 0, 0xB96E, 0,
+ 0, 0xB96F, 0x553B, 0x4932, 0xA561, 0, 0x2F78, 0xA562,
+ 0xA563, 0, 0xA564, 0, 0, 0, 0, 0x2F79,
+ 0, 0, 0, 0, 0xB976, 0, 0, 0,
+ 0, 0xA565, 0xB978, 0xA566, 0, 0xA567, 0, 0,
+ 0xB97B, 0, 0xA568, 0xB97D, 0x553C, 0x5540, 0x553D, 0xA569,
+};
+static const unsigned short utf8_to_euc_E5AB[] = {
+ 0, 0x3247, 0x553F, 0, 0xBA21, 0, 0xBA22, 0,
+ 0xBA23, 0x3C3B, 0, 0x553E, 0x3779, 0, 0, 0xBA24,
+ 0x554C, 0, 0, 0, 0, 0, 0x5545, 0x5542,
+ 0, 0, 0xBA25, 0, 0xBA26, 0, 0, 0,
+ 0xBA27, 0x4364, 0, 0x5541, 0, 0xBA28, 0x5543, 0,
+ 0, 0x5544, 0xBA29, 0, 0, 0, 0xBA2A, 0,
+ 0, 0, 0, 0, 0, 0xBA2B, 0xBA2C, 0,
+ 0, 0, 0x5546, 0x5547, 0, 0xBA2D, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5AB_x0213[] = {
+ 0, 0x3247, 0x553F, 0, 0x2F7A, 0, 0xBA22, 0,
+ 0xBA23, 0x3C3B, 0, 0x553E, 0x3779, 0, 0, 0xBA24,
+ 0x554C, 0, 0, 0, 0, 0, 0x5545, 0x5542,
+ 0, 0, 0xA56A, 0, 0xA56B, 0, 0, 0,
+ 0xA56C, 0x4364, 0, 0x5541, 0, 0xA56D, 0x5543, 0,
+ 0, 0x5544, 0xBA29, 0, 0, 0, 0xA56F, 0,
+ 0xA56E, 0, 0, 0, 0, 0xA570, 0xBA2C, 0,
+ 0, 0, 0x5546, 0x5547, 0, 0xBA2D, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5AC[] = {
+ 0xBA2E, 0xBA2F, 0, 0, 0, 0, 0, 0,
+ 0xBA30, 0x3472, 0, 0x5549, 0x5548, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x554A, 0xBA31,
+ 0, 0xBA33, 0, 0xBA34, 0, 0xBA35, 0, 0,
+ 0, 0xBA36, 0x3E6E, 0, 0, 0xBA37, 0, 0,
+ 0, 0, 0x554D, 0, 0x445C, 0xBA38, 0, 0,
+ 0x3145, 0, 0x554B, 0, 0xBA32, 0, 0x554E, 0,
+ 0xBA39, 0, 0, 0, 0, 0, 0x554F, 0,
+};
+static const unsigned short utf8_to_euc_E5AC_x0213[] = {
+ 0xA571, 0xBA2F, 0, 0, 0, 0, 0, 0,
+ 0xA572, 0x3472, 0, 0x5549, 0x5548, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x554A, 0xA573,
+ 0, 0x2F7C, 0, 0xBA34, 0, 0xBA35, 0, 0,
+ 0, 0xBA36, 0x3E6E, 0, 0, 0x2F7D, 0, 0,
+ 0, 0, 0x554D, 0, 0x445C, 0xA575, 0, 0,
+ 0x3145, 0, 0x554B, 0, 0xA574, 0, 0x554E, 0,
+ 0xBA39, 0, 0, 0, 0, 0, 0x554F, 0,
+};
+static const unsigned short utf8_to_euc_E5AD[] = {
+ 0x5552, 0xBA3A, 0, 0x5550, 0, 0x5551, 0, 0,
+ 0, 0, 0, 0xBA3B, 0xBA3C, 0, 0, 0,
+ 0x3B52, 0x5553, 0xBA3D, 0, 0x3926, 0x5554, 0xBA3E, 0x3B7A,
+ 0x4238, 0, 0x5555, 0x5556, 0x3B5A, 0x3927, 0xBA3F, 0x4C52,
+ 0, 0, 0, 0x3528, 0x3849, 0x5557, 0x3358, 0,
+ 0xBA40, 0x5558, 0, 0x4239, 0, 0, 0xBA41, 0xBA42,
+ 0x5559, 0x5623, 0, 0x555A, 0, 0x555B, 0, 0,
+ 0x555C, 0, 0x555E, 0, 0xBA43, 0xBA44, 0xBA45, 0xBA46,
+};
+static const unsigned short utf8_to_euc_E5AD_x0213[] = {
+ 0x5552, 0x4F55, 0, 0x5550, 0, 0x5551, 0, 0,
+ 0, 0, 0, 0xBA3B, 0xA576, 0, 0, 0,
+ 0x3B52, 0x5553, 0xA577, 0, 0x3926, 0x5554, 0x4F56, 0x3B7A,
+ 0x4238, 0, 0x5555, 0x5556, 0x3B5A, 0x3927, 0xBA3F, 0x4C52,
+ 0, 0, 0, 0x3528, 0x3849, 0x5557, 0x3358, 0,
+ 0xA578, 0x5558, 0, 0x4239, 0, 0, 0xBA41, 0xA579,
+ 0x5559, 0x5623, 0, 0x555A, 0, 0x555B, 0, 0,
+ 0x555C, 0, 0x555E, 0, 0xA57A, 0x4F57, 0xBA45, 0xA57B,
+};
+static const unsigned short utf8_to_euc_E5AE[] = {
+ 0x555F, 0xBA47, 0, 0x5560, 0xBA48, 0x4270, 0xBA49, 0x3127,
+ 0x3C69, 0x3042, 0xBA4A, 0x4157, 0x3430, 0x3C35, 0xBA4B, 0x3928,
+ 0xBA4C, 0xBA4D, 0, 0xBA4E, 0xBA4F, 0x4566, 0xBA50, 0x3D21,
+ 0x3431, 0x4368, 0x446A, 0x3038, 0x3539, 0x4A75, 0, 0x3C42,
+ 0, 0, 0x3552, 0x406B, 0x3C3C, 0x4D28, 0x5561, 0,
+ 0xBA51, 0xBA52, 0, 0, 0xBA53, 0xBA54, 0x355C, 0xBA55,
+ 0x3A4B, 0xBA56, 0xBA57, 0x3332, 0x3163, 0x3E2C, 0x3248, 0xBA58,
+ 0x5562, 0x4D46, 0xBA59, 0, 0xBA5A, 0, 0, 0x3D49,
+};
+static const unsigned short utf8_to_euc_E5AE_x0213[] = {
+ 0x555F, 0xA57C, 0, 0x5560, 0xA57D, 0x4270, 0xBA49, 0x3127,
+ 0x3C69, 0x3042, 0xBA4A, 0x4157, 0x3430, 0x3C35, 0xBA4B, 0x3928,
+ 0xBA4C, 0xBA4D, 0, 0x4F58, 0xBA4F, 0x4566, 0xA821, 0x3D21,
+ 0x3431, 0x4368, 0x446A, 0x3038, 0x3539, 0x4A75, 0, 0x3C42,
+ 0, 0, 0x3552, 0x406B, 0x3C3C, 0x4D28, 0x5561, 0,
+ 0xBA51, 0xBA52, 0, 0, 0xA822, 0xBA54, 0x355C, 0xBA55,
+ 0x3A4B, 0xBA56, 0xBA57, 0x3332, 0x3163, 0x3E2C, 0x3248, 0xBA58,
+ 0x5562, 0x4D46, 0xBA59, 0, 0xBA5A, 0, 0, 0x3D49,
+};
+static const unsigned short utf8_to_euc_E5AF[] = {
+ 0xBA5B, 0xBA5C, 0x3C64, 0x5563, 0x3473, 0x4652, 0x4C29, 0x5564,
+ 0, 0x5565, 0, 0, 0x4959, 0xBA5D, 0, 0xBA5E,
+ 0x5567, 0, 0x3428, 0x3677, 0x5566, 0, 0xBA5F, 0xBA60,
+ 0xBA61, 0xBA62, 0xBA63, 0x3432, 0, 0x3F32, 0x556B, 0x3B21,
+ 0xBA64, 0x3249, 0x556A, 0, 0x5568, 0x556C, 0x5569, 0x472B,
+ 0x5C4D, 0x3F33, 0, 0x556D, 0xF43A, 0, 0x4E40, 0xBA65,
+ 0x556E, 0xBA66, 0, 0x5570, 0xBA67, 0x437E, 0x556F, 0,
+ 0x4023, 0, 0x3B7B, 0, 0, 0xBA68, 0x4250, 0x3C77,
+};
+static const unsigned short utf8_to_euc_E5AF_x0213[] = {
+ 0xA824, 0xBA5C, 0x3C64, 0x5563, 0x3473, 0x4652, 0x4C29, 0x5564,
+ 0, 0x5565, 0, 0, 0x4959, 0xBA5D, 0xA826, 0xBA5E,
+ 0x5567, 0, 0x3428, 0x3677, 0x5566, 0, 0xA827, 0xBA60,
+ 0x4F59, 0xBA62, 0xBA63, 0x3432, 0, 0x3F32, 0x556B, 0x3B21,
+ 0xBA64, 0x3249, 0x556A, 0, 0x5568, 0x556C, 0x5569, 0x472B,
+ 0x5C4D, 0x3F33, 0, 0x556D, 0x4F5A, 0, 0x4E40, 0xBA65,
+ 0x556E, 0xA82A, 0, 0x5570, 0xBA67, 0x437E, 0x556F, 0,
+ 0x4023, 0, 0x3B7B, 0, 0, 0xA82B, 0x4250, 0x3C77,
+};
+static const unsigned short utf8_to_euc_E5B0[] = {
+ 0, 0x4975, 0x406C, 0, 0x3C4D, 0x5571, 0x3E2D, 0x5572,
+ 0x5573, 0x3053, 0x423A, 0x3F52, 0xBA69, 0x5574, 0x4633, 0x3E2E,
+ 0, 0x3E2F, 0, 0x5575, 0, 0, 0x406D, 0xBA6A,
+ 0, 0, 0x3E30, 0, 0, 0, 0xBA6B, 0xBA6C,
+ 0x5576, 0, 0x5577, 0xBA6D, 0x4C60, 0, 0xBA6E, 0,
+ 0x5578, 0xBA6F, 0, 0xBA70, 0xBA71, 0x3646, 0xBA72, 0,
+ 0xBA73, 0x3D22, 0xBA74, 0, 0, 0xBA75, 0xBA76, 0,
+ 0x5579, 0x557A, 0x3C5C, 0x3F2C, 0x4674, 0x3F54, 0x4878, 0x4722,
+};
+static const unsigned short utf8_to_euc_E5B0_x0213[] = {
+ 0, 0x4975, 0x406C, 0xA82D, 0x3C4D, 0x5571, 0x3E2D, 0x5572,
+ 0x5573, 0x3053, 0x423A, 0x3F52, 0xBA69, 0x5574, 0x4633, 0x3E2E,
+ 0, 0x3E2F, 0x4F5B, 0x5575, 0, 0, 0x406D, 0xBA6A,
+ 0, 0, 0x3E30, 0, 0, 0, 0x4F5C, 0xBA6C,
+ 0x5576, 0, 0x5577, 0x4F5D, 0x4C60, 0, 0xBA6E, 0,
+ 0x5578, 0xA82E, 0, 0x4F5E, 0xBA71, 0x3646, 0xBA72, 0,
+ 0xA82F, 0x3D22, 0xBA74, 0, 0, 0xBA75, 0xBA76, 0,
+ 0x5579, 0x557A, 0x3C5C, 0x3F2C, 0x4674, 0x3F54, 0x4878, 0x4722,
+};
+static const unsigned short utf8_to_euc_E5B1[] = {
+ 0x3649, 0x557B, 0, 0, 0, 0x356F, 0x557C, 0,
+ 0x367E, 0, 0x464F, 0x3230, 0, 0x3B53, 0x557D, 0x5622,
+ 0x5621, 0x367D, 0, 0x557E, 0, 0x4538, 0, 0,
+ 0, 0xBA77, 0xBA78, 0, 0xBA79, 0, 0x4230, 0,
+ 0x454B, 0x3C48, 0xBA7A, 0xBA7B, 0x4158, 0x4D7A, 0, 0xBA7C,
+ 0xBA7D, 0xBA7E, 0, 0, 0x5624, 0xBB21, 0x5625, 0x4656,
+ 0xBB22, 0x3B33, 0, 0, 0xBB23, 0xBB24, 0x5627, 0,
+ 0, 0x5628, 0xBB25, 0xBB26, 0xBB27, 0xBB28, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5B1_x0213[] = {
+ 0x3649, 0x557B, 0, 0, 0, 0x356F, 0x557C, 0,
+ 0x367E, 0, 0x464F, 0x3230, 0, 0x3B53, 0x557D, 0x5622,
+ 0x5621, 0x367D, 0, 0x557E, 0, 0x4538, 0, 0,
+ 0, 0xBA77, 0xBA78, 0x7E7B, 0xBA79, 0, 0x4230, 0xA831,
+ 0x454B, 0x3C48, 0x4F60, 0xA832, 0x4158, 0x4D7A, 0, 0xA833,
+ 0xA834, 0xA835, 0, 0, 0x5624, 0xBB21, 0x5625, 0x4656,
+ 0xA836, 0x3B33, 0, 0, 0xBB23, 0xBB24, 0x5627, 0,
+ 0, 0x5628, 0x4F64, 0xBB26, 0xA839, 0xBB28, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5B2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0xBB29,
+ 0xBB2A, 0, 0xBB2B, 0, 0x5629, 0, 0, 0xBB2C,
+ 0x3474, 0x562A, 0xBB2D, 0, 0x562B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xBB2E, 0, 0xBB2F,
+ 0xBB30, 0x322C, 0xBB31, 0xBB32, 0, 0, 0xBB33, 0,
+ 0x413B, 0x3464, 0xBB34, 0x562D, 0x4C28, 0, 0, 0,
+ 0, 0x4252, 0xBB35, 0x3359, 0xBB36, 0xBB37, 0x562F, 0x5631,
+ 0x345F, 0, 0xBB38, 0x562E, 0x5630, 0, 0x5633, 0,
+};
+static const unsigned short utf8_to_euc_E5B2_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0xBB29,
+ 0xA83C, 0, 0xA83D, 0, 0x5629, 0, 0, 0x4F65,
+ 0x3474, 0x562A, 0xBB2D, 0, 0x562B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xBB2E, 0, 0x4F66,
+ 0xA841, 0x322C, 0xA842, 0x4F67, 0, 0, 0xA843, 0xA844,
+ 0x413B, 0x3464, 0x4F68, 0x562D, 0x4C28, 0xA846, 0, 0,
+ 0, 0x4252, 0xBB35, 0x3359, 0xBB36, 0xA847, 0x562F, 0x5631,
+ 0x345F, 0, 0x4F69, 0x562E, 0x5630, 0, 0x5633, 0,
+};
+static const unsigned short utf8_to_euc_E5B3[] = {
+ 0, 0, 0, 0, 0, 0x5632, 0, 0x5634,
+ 0, 0xBB39, 0, 0xBB3A, 0, 0, 0, 0,
+ 0, 0, 0xBB3B, 0, 0, 0, 0, 0xBB3D,
+ 0, 0x5635, 0, 0, 0, 0xBB3C, 0, 0,
+ 0x463D, 0x362E, 0, 0, 0, 0, 0, 0,
+ 0x3265, 0x5636, 0x563B, 0, 0, 0x5639, 0xBB3E, 0x4A77,
+ 0x4A76, 0xBB3F, 0xBB40, 0, 0xBB41, 0xF43B, 0x4567, 0,
+ 0, 0, 0x5638, 0x3D54, 0, 0x5637, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5B3_x0213[] = {
+ 0, 0, 0, 0, 0, 0x5632, 0, 0x5634,
+ 0, 0xA849, 0, 0x4F6A, 0, 0, 0, 0,
+ 0x4F6B, 0, 0x4F6C, 0, 0, 0, 0, 0xBB3D,
+ 0, 0x5635, 0, 0, 0, 0xBB3C, 0, 0,
+ 0x463D, 0x362E, 0, 0, 0, 0, 0, 0,
+ 0x3265, 0x5636, 0x563B, 0, 0, 0x5639, 0xBB3E, 0x4A77,
+ 0x4A76, 0xBB3F, 0xBB40, 0, 0x4F6D, 0, 0x4567, 0,
+ 0, 0, 0x5638, 0x3D54, 0, 0x5637, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5B4[] = {
+ 0, 0xBB42, 0, 0, 0, 0, 0xBB43, 0x3F72,
+ 0, 0, 0, 0x563C, 0, 0xBB44, 0x3A6A, 0,
+ 0, 0x5642, 0xBB45, 0, 0x5643, 0x563D, 0x3333, 0x563E,
+ 0x5647, 0x5646, 0x5645, 0x5641, 0, 0, 0, 0x5640,
+ 0, 0, 0x5644, 0xBB47, 0xBB48, 0, 0xBB49, 0xBB4A,
+ 0, 0x4A78, 0, 0xBB46, 0, 0, 0, 0,
+ 0, 0xBB4B, 0, 0, 0xBB4C, 0, 0, 0,
+ 0, 0xBB4D, 0, 0, 0, 0xBB4E, 0, 0xBB4F,
+};
+static const unsigned short utf8_to_euc_E5B4_x0213[] = {
+ 0, 0xBB42, 0, 0, 0, 0, 0xA84C, 0x3F72,
+ 0, 0, 0, 0x563C, 0, 0x4F70, 0x3A6A, 0,
+ 0xA84D, 0x5642, 0xBB45, 0, 0x5643, 0x563D, 0x3333, 0x563E,
+ 0x5647, 0x5646, 0x5645, 0x5641, 0, 0xA84F, 0, 0x5640,
+ 0xA850, 0, 0x5644, 0xBB47, 0xA851, 0, 0xA852, 0x4F71,
+ 0, 0x4A78, 0, 0xA84E, 0, 0, 0, 0,
+ 0, 0xA853, 0, 0, 0xBB4C, 0, 0, 0,
+ 0, 0xA854, 0, 0, 0, 0xBB4E, 0, 0xBB4F,
+};
+static const unsigned short utf8_to_euc_E5B5[] = {
+ 0, 0, 0xBB50, 0xBB51, 0, 0, 0xBB52, 0,
+ 0xBB53, 0, 0xBB57, 0x564B, 0x5648, 0, 0x564A, 0,
+ 0x4D72, 0xBB55, 0x5649, 0xF43C, 0, 0xBB54, 0, 0,
+ 0, 0xBB56, 0, 0, 0x563F, 0, 0, 0xBB58,
+ 0xBB59, 0xBB5A, 0xBB5B, 0, 0xBB5C, 0, 0, 0,
+ 0, 0x3F73, 0xBB5D, 0, 0x564C, 0xBB5E, 0, 0x3A37,
+ 0xBB5F, 0, 0, 0x564D, 0, 0, 0x564E, 0,
+ 0, 0xBB60, 0xBB61, 0, 0, 0, 0xBB62, 0xBB63,
+};
+static const unsigned short utf8_to_euc_E5B5_x0213[] = {
+ 0, 0, 0xA855, 0xBB51, 0, 0, 0x4F73, 0x4F74,
+ 0xBB53, 0, 0x4F76, 0x564B, 0x5648, 0, 0x564A, 0,
+ 0x4D72, 0xBB55, 0x5649, 0x4F75, 0, 0xBB54, 0, 0,
+ 0, 0xBB56, 0, 0, 0x563F, 0, 0, 0xBB58,
+ 0xBB59, 0xA857, 0xBB5B, 0, 0xBB5C, 0, 0, 0,
+ 0, 0x3F73, 0xA858, 0, 0x564C, 0x4F77, 0, 0x3A37,
+ 0xA85A, 0, 0, 0x564D, 0, 0, 0x564E, 0,
+ 0, 0xBB60, 0xBB61, 0, 0, 0, 0xBB62, 0xBB63,
+};
+static const unsigned short utf8_to_euc_E5B6[] = {
+ 0, 0xBB64, 0x5651, 0xBB65, 0x5650, 0, 0, 0x564F,
+ 0xBB66, 0, 0xBB67, 0x4568, 0x563A, 0, 0, 0,
+ 0x5657, 0, 0xBB68, 0xBB69, 0xBB6A, 0xBB6B, 0, 0,
+ 0, 0xBB6C, 0, 0xBB6D, 0, 0x5653, 0, 0xBB6E,
+ 0xBB6F, 0, 0x5652, 0, 0, 0, 0, 0xBB70,
+ 0, 0, 0, 0xBB71, 0x5654, 0, 0x5655, 0,
+ 0xBB72, 0, 0xE674, 0, 0xBB73, 0, 0, 0x5658,
+ 0xBB74, 0xBB75, 0x4E66, 0, 0x5659, 0x5656, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5B6_x0213[] = {
+ 0, 0x4F78, 0x5651, 0xBB65, 0x5650, 0, 0, 0x564F,
+ 0xA85D, 0, 0xBB67, 0x4568, 0x563A, 0, 0, 0,
+ 0x5657, 0, 0xA85F, 0xBB69, 0xA860, 0xBB6B, 0, 0xA861,
+ 0, 0xA862, 0, 0xBB6D, 0, 0x5653, 0, 0xBB6E,
+ 0x4F79, 0, 0x5652, 0, 0x4F7A, 0, 0, 0x4F7B,
+ 0, 0, 0, 0xBB71, 0x5654, 0, 0x5655, 0,
+ 0xA863, 0, 0xA864, 0, 0xA865, 0, 0, 0x5658,
+ 0x4F7C, 0xA867, 0x4E66, 0, 0x5659, 0x5656, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5B7[] = {
+ 0, 0, 0, 0xBB76, 0, 0, 0, 0xBB77,
+ 0, 0x565A, 0, 0xBB78, 0x3460, 0x565B, 0xBB7A, 0,
+ 0xBB79, 0, 0x565D, 0x565C, 0, 0, 0x565E, 0,
+ 0xBB7B, 0xBB7C, 0, 0x565F, 0, 0x406E, 0x3D23, 0,
+ 0xBB7D, 0x3D64, 0, 0x4163, 0xBB7E, 0x3929, 0x3A38, 0x392A,
+ 0x3570, 0xBC21, 0, 0x5660, 0, 0, 0x3A39, 0,
+ 0, 0x384A, 0x5661, 0x4C26, 0x4743, 0x5662, 0, 0x392B,
+ 0xBC22, 0xBC23, 0, 0x342C, 0, 0x4327, 0x3652, 0,
+};
+static const unsigned short utf8_to_euc_E5B7_x0213[] = {
+ 0, 0, 0, 0xBB76, 0, 0, 0, 0xBB77,
+ 0, 0x565A, 0, 0x4F7D, 0x3460, 0x565B, 0xBB7A, 0,
+ 0, 0xA868, 0x565D, 0x565C, 0, 0, 0x565E, 0xA869,
+ 0xA86A, 0xBB7C, 0, 0x565F, 0, 0x406E, 0x3D23, 0,
+ 0xA86B, 0x3D64, 0x7428, 0x4163, 0xA86D, 0x3929, 0x3A38, 0x392A,
+ 0x3570, 0xA86E, 0, 0x5660, 0, 0, 0x3A39, 0,
+ 0, 0x384A, 0x5661, 0x4C26, 0x4743, 0x5662, 0, 0x392B,
+ 0xBC22, 0xBC23, 0, 0x342C, 0, 0x4327, 0x3652, 0,
+};
+static const unsigned short utf8_to_euc_E5B8[] = {
+ 0xBC24, 0, 0x3B54, 0x495B, 0, 0, 0x4841, 0xBC25,
+ 0, 0, 0, 0x5663, 0x3475, 0xBC26, 0, 0,
+ 0, 0x5666, 0xBC27, 0, 0xBC28, 0xBC29, 0x4421, 0,
+ 0xBC2A, 0x5665, 0x5664, 0x5667, 0, 0x446B, 0, 0xBC2B,
+ 0xBC2C, 0, 0, 0, 0, 0x3F63, 0, 0,
+ 0xBC2E, 0, 0, 0x3B55, 0, 0x404A, 0xBC2D, 0x4253,
+ 0x3522, 0, 0xBC2F, 0x4422, 0, 0xBC30, 0x5668, 0x5669,
+ 0x3E6F, 0, 0, 0, 0, 0x4B39, 0xBC31, 0,
+};
+static const unsigned short utf8_to_euc_E5B8_x0213[] = {
+ 0xA870, 0, 0x3B54, 0x495B, 0, 0, 0x4841, 0xBC25,
+ 0, 0, 0, 0x5663, 0x3475, 0xBC26, 0, 0,
+ 0, 0x5666, 0xA872, 0, 0x7429, 0xA873, 0x4421, 0,
+ 0x742A, 0x5665, 0x5664, 0x5667, 0, 0x446B, 0, 0xA875,
+ 0xBC2C, 0, 0, 0, 0, 0x3F63, 0, 0,
+ 0xBC2E, 0, 0, 0x3B55, 0, 0x404A, 0xA876, 0x4253,
+ 0x3522, 0, 0xBC2F, 0x4422, 0, 0xBC30, 0x5668, 0x5669,
+ 0x3E6F, 0, 0, 0, 0, 0x4B39, 0xA877, 0,
+};
+static const unsigned short utf8_to_euc_E5B9[] = {
+ 0x566C, 0, 0, 0x566B, 0x566A, 0x497D, 0, 0x5673,
+ 0, 0xBC34, 0, 0xBC32, 0x4B5A, 0, 0x566D, 0,
+ 0xBC33, 0xBC35, 0, 0, 0x566F, 0x4B6B, 0xBC36, 0x566E,
+ 0xBC37, 0, 0, 0xBC38, 0xBC39, 0, 0xBC3A, 0x5670,
+ 0, 0x4828, 0x5671, 0x4A3E, 0x5672, 0, 0, 0,
+ 0xBC3B, 0, 0xBC3C, 0xBC3D, 0xBC3E, 0xBC3F, 0xBC40, 0,
+ 0xBC41, 0, 0x3433, 0x4A3F, 0x472F, 0x5674, 0x5675, 0,
+ 0x392C, 0x3434, 0x5676, 0x3838, 0x4D44, 0x4D29, 0x3476, 0x5678,
+};
+static const unsigned short utf8_to_euc_E5B9_x0213[] = {
+ 0x566C, 0, 0, 0x566B, 0x566A, 0x497D, 0, 0x5673,
+ 0, 0xA878, 0, 0xBC32, 0x4B5A, 0, 0x566D, 0,
+ 0xBC33, 0xBC35, 0, 0, 0x566F, 0x4B6B, 0xA87A, 0x566E,
+ 0x742B, 0, 0, 0xBC38, 0xBC39, 0, 0x742C, 0x5670,
+ 0, 0x4828, 0x5671, 0x4A3E, 0x5672, 0, 0, 0,
+ 0xBC3B, 0, 0xBC3C, 0xA87C, 0xA87D, 0xA87E, 0xAC21, 0,
+ 0xBC41, 0, 0x3433, 0x4A3F, 0x472F, 0x5674, 0x5675, 0x7E7C,
+ 0x392C, 0x3434, 0x5676, 0x3838, 0x4D44, 0x4D29, 0x3476, 0x5678,
+};
+static const unsigned short utf8_to_euc_E5BA[] = {
+ 0xBC42, 0x4423, 0, 0x392D, 0x3E31, 0, 0, 0x485F,
+ 0, 0, 0x3E32, 0xBC43, 0, 0, 0xBC44, 0x3D78,
+ 0, 0, 0, 0, 0, 0x446C, 0x4A79, 0x4539,
+ 0, 0, 0x392E, 0, 0x495C, 0, 0, 0,
+ 0x5679, 0, 0xBC45, 0, 0xBC46, 0xBC47, 0x4559, 0x3A42,
+ 0xBC48, 0, 0xBC49, 0x384B, 0xBC4A, 0x446D, 0, 0,
+ 0, 0xBC4B, 0, 0xBC4C, 0, 0x3043, 0x3D6E, 0x392F,
+ 0x4D47, 0, 0, 0, 0, 0xBC4D, 0xBC4E, 0xBC4F,
+};
+static const unsigned short utf8_to_euc_E5BA_x0213[] = {
+ 0xBC42, 0x4423, 0, 0x392D, 0x3E31, 0, 0, 0x485F,
+ 0, 0, 0x3E32, 0xBC43, 0, 0, 0xBC44, 0x3D78,
+ 0, 0, 0, 0, 0, 0x446C, 0x4A79, 0x4539,
+ 0, 0, 0x392E, 0, 0x495C, 0, 0, 0,
+ 0x5679, 0, 0xBC45, 0, 0xBC46, 0xAC23, 0x4559, 0x3A42,
+ 0xBC48, 0, 0xAC24, 0x384B, 0xAC25, 0x446D, 0, 0,
+ 0, 0xBC4B, 0, 0xBC4C, 0, 0x3043, 0x3D6E, 0x392F,
+ 0x4D47, 0xAC26, 0, 0, 0, 0xBC4D, 0x742D, 0xAC27,
+};
+static const unsigned short utf8_to_euc_E5BB[] = {
+ 0, 0x567A, 0x567B, 0x4751, 0, 0, 0xBC50, 0,
+ 0x567C, 0x4E77, 0x4F2D, 0xBC52, 0xBC51, 0, 0xBC53, 0x567E,
+ 0x567D, 0xBC54, 0xBC55, 0x3347, 0xBC56, 0xBC57, 0x5721, 0,
+ 0, 0, 0x5724, 0x5725, 0xBC58, 0x5723, 0xBC59, 0x4940,
+ 0x3E33, 0x5727, 0x5726, 0x5722, 0, 0xBC5A, 0, 0,
+ 0x5728, 0x5729, 0, 0xBC5B, 0x572A, 0, 0, 0,
+ 0x572D, 0x572B, 0, 0x572C, 0x572E, 0, 0x3164, 0x446E,
+ 0x572F, 0, 0x377A, 0x3276, 0x4736, 0, 0x5730, 0x467B,
+};
+static const unsigned short utf8_to_euc_E5BB_x0213[] = {
+ 0, 0x567A, 0x567B, 0x4751, 0, 0, 0xAC28, 0,
+ 0x567C, 0x4E77, 0x4F2D, 0x742F, 0xBC51, 0, 0xBC53, 0x567E,
+ 0x567D, 0xBC54, 0xAC29, 0x3347, 0xBC56, 0xBC57, 0x5721, 0,
+ 0, 0xAC2A, 0x5724, 0x5725, 0xBC58, 0x5723, 0xBC59, 0x4940,
+ 0x3E33, 0x5727, 0x5726, 0x5722, 0, 0xBC5A, 0, 0,
+ 0x5728, 0x5729, 0, 0xBC5B, 0x572A, 0, 0, 0,
+ 0x572D, 0x572B, 0, 0x572C, 0x572E, 0, 0x3164, 0x446E,
+ 0x572F, 0x7430, 0x377A, 0x3276, 0x4736, 0xAC2C, 0x5730, 0x467B,
+};
+static const unsigned short utf8_to_euc_E5BC[] = {
+ 0, 0x4A5B, 0xBC5C, 0x5731, 0x4F2E, 0, 0xBC5D, 0xBC5E,
+ 0xBC5F, 0x5732, 0x4A40, 0x5735, 0x5021, 0x5031, 0xBC60, 0x3C30,
+ 0x4675, 0x5736, 0, 0x355D, 0x4424, 0x307A, 0x5737, 0x4A26,
+ 0x3930, 0xBC61, 0, 0x4350, 0xBC62, 0xBC63, 0, 0x446F,
+ 0, 0xBC64, 0xBC65, 0xBC66, 0xBC67, 0x4C6F, 0x3839, 0x384C,
+ 0xBC68, 0x5738, 0, 0xBC69, 0xBC6A, 0x5739, 0xBC6B, 0x573F,
+ 0xBC6C, 0x3C65, 0, 0, 0xBC6D, 0x4425, 0xBC6E, 0x362F,
+ 0x573A, 0, 0, 0xBC6F, 0x492B, 0xBC70, 0x4346, 0xBC71,
+};
+static const unsigned short utf8_to_euc_E5BC_x0213[] = {
+ 0x7431, 0x4A5B, 0x7432, 0x5731, 0x4F2E, 0, 0xBC5D, 0x7433,
+ 0xAC2D, 0x5732, 0x4A40, 0x5735, 0x5021, 0x5031, 0xAC2E, 0x3C30,
+ 0x4675, 0x5736, 0, 0x355D, 0x4424, 0x307A, 0x5737, 0x4A26,
+ 0x3930, 0xBC61, 0, 0x4350, 0xAC2F, 0x7434, 0xAC31, 0x446F,
+ 0, 0, 0xBC65, 0x7435, 0xBC67, 0x4C6F, 0x3839, 0x384C,
+ 0xBC68, 0x5738, 0, 0xBC69, 0xBC6A, 0x5739, 0xBC6B, 0x573F,
+ 0xBC6C, 0x3C65, 0, 0, 0x7436, 0x4425, 0x7437, 0x362F,
+ 0x573A, 0, 0, 0xBC6F, 0x492B, 0x7438, 0x4346, 0xBC71,
+};
+static const unsigned short utf8_to_euc_E5BD[] = {
+ 0xBC72, 0x573B, 0, 0, 0xBC73, 0xBC74, 0, 0xBC75,
+ 0x573C, 0, 0x3630, 0, 0x573D, 0xBC76, 0x573E, 0,
+ 0xBC77, 0x5740, 0, 0x4576, 0xBC78, 0, 0x5741, 0x5742,
+ 0xBC79, 0x5743, 0, 0xBC7A, 0x5734, 0x5733, 0, 0,
+ 0xBC7B, 0x5744, 0x3741, 0xBC7C, 0xBC7D, 0, 0x4927, 0xBC7E,
+ 0, 0x3A4C, 0x4937, 0x4426, 0x494B, 0x5745, 0, 0xBD21,
+ 0x3E34, 0x3146, 0xBD22, 0x5746, 0xBD23, 0xBD24, 0, 0x5747,
+ 0xBD25, 0x4C72, 0xBD26, 0, 0x4860, 0xBD27, 0xBD28, 0x574A,
+};
+static const unsigned short utf8_to_euc_E5BD_x0213[] = {
+ 0x7439, 0x573B, 0, 0, 0xBC73, 0x743A, 0, 0xAC32,
+ 0x573C, 0, 0x3630, 0, 0x573D, 0xBC76, 0x573E, 0,
+ 0xBC77, 0x5740, 0, 0x4576, 0x743B, 0, 0x5741, 0x5742,
+ 0x743C, 0x5743, 0, 0xBC7A, 0x5734, 0x5733, 0, 0,
+ 0xBC7B, 0x5744, 0x3741, 0xAC33, 0x743D, 0, 0x4927, 0x743E,
+ 0, 0x3A4C, 0x4937, 0x4426, 0x494B, 0x5745, 0, 0xBD21,
+ 0x3E34, 0x3146, 0xAC34, 0x5746, 0xBD23, 0xBD24, 0, 0x5747,
+ 0xBD25, 0x4C72, 0xBD26, 0, 0x4860, 0x743F, 0xAC35, 0x574A,
+};
+static const unsigned short utf8_to_euc_E5BE[] = {
+ 0x317D, 0x402C, 0x5749, 0x5748, 0x3742, 0x4254, 0, 0x574E,
+ 0x574C, 0xBD29, 0x574B, 0x4E27, 0x3865, 0xBD2A, 0, 0xBD2B,
+ 0x3D79, 0x574D, 0x454C, 0x3D3E, 0, 0, 0xBD2C, 0x4640,
+ 0x5751, 0x5750, 0, 0, 0xBD2D, 0xBD2E, 0x574F, 0,
+ 0x5752, 0x3866, 0xBD2F, 0, 0xBD32, 0, 0, 0xBD30,
+ 0x5753, 0x497C, 0x3D5B, 0xBD31, 0xBD33, 0x5754, 0x4879, 0xBD34,
+ 0xBD35, 0xBD36, 0, 0x4641, 0x4427, 0, 0, 0xF43E,
+ 0xBD37, 0x4530, 0, 0, 0x5755, 0x352B, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5BE_x0213[] = {
+ 0x317D, 0x402C, 0x5749, 0x5748, 0x3742, 0x4254, 0, 0x574E,
+ 0x574C, 0x7440, 0x574B, 0x4E27, 0x3865, 0xBD2A, 0, 0xAC36,
+ 0x3D79, 0x574D, 0x454C, 0x3D3E, 0, 0, 0xBD2C, 0x4640,
+ 0x5751, 0x5750, 0, 0, 0x7441, 0xBD2E, 0x574F, 0,
+ 0x5752, 0x3866, 0xAC37, 0, 0xAC38, 0, 0, 0x7442,
+ 0x5753, 0x497C, 0x3D5B, 0xBD31, 0xBD33, 0x5754, 0x4879, 0x7443,
+ 0xBD35, 0xBD36, 0, 0x4641, 0x4427, 0x7444, 0, 0x7445,
+ 0xAC39, 0x4530, 0, 0, 0x5755, 0x352B, 0, 0,
+};
+static const unsigned short utf8_to_euc_E5BF[] = {
+ 0, 0, 0, 0x3F34, 0xBD38, 0x492C, 0, 0xBD39,
+ 0xBD3A, 0xBD3B, 0, 0xBD3C, 0x3477, 0x4726, 0, 0,
+ 0xBD3D, 0xBD3E, 0xBD3F, 0xBD40, 0xBD41, 0, 0x5756, 0x3B56,
+ 0x4B3A, 0x4B3B, 0, 0, 0x317E, 0x575B, 0xBD42, 0,
+ 0x4369, 0xBD43, 0xBD44, 0, 0x5758, 0, 0, 0,
+ 0xBD45, 0xBD46, 0xBD47, 0x3277, 0xBD48, 0xBD49, 0xBD4A, 0xBD4B,
+ 0x582D, 0x575A, 0xBD4C, 0xBD4D, 0, 0x4730, 0xBD4E, 0,
+ 0x5759, 0, 0xBD4F, 0x5757, 0xBD50, 0x397A, 0, 0x575D,
+};
+static const unsigned short utf8_to_euc_E5BF_x0213[] = {
+ 0, 0, 0, 0x3F34, 0xAC3A, 0x492C, 0, 0xAC3C,
+ 0xBD3A, 0x7446, 0, 0xAC3D, 0x3477, 0x4726, 0, 0,
+ 0xBD3D, 0xBD3E, 0xAC3E, 0xAC3F, 0xAC40, 0, 0x5756, 0x3B56,
+ 0x4B3A, 0x4B3B, 0, 0, 0x317E, 0x575B, 0x7447, 0,
+ 0x4369, 0x7448, 0xAC41, 0, 0x5758, 0, 0, 0,
+ 0xBD45, 0x7449, 0xBD47, 0x3277, 0xBD48, 0xBD49, 0xAC42, 0xAC43,
+ 0x582D, 0x575A, 0xBD4C, 0xAC44, 0, 0x4730, 0xBD4E, 0,
+ 0x5759, 0, 0xBD4F, 0x5757, 0xAC45, 0x397A, 0, 0x575D,
+};
+static const unsigned short utf8_to_euc_E680[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0xBD51,
+ 0, 0, 0xBD52, 0, 0, 0xBD53, 0x5763, 0x5769,
+ 0x5761, 0, 0x455C, 0xBD54, 0xBD55, 0x5766, 0x495D, 0xBD56,
+ 0xBD57, 0x5760, 0xBD58, 0x5765, 0x4E67, 0x3B57, 0, 0xBD59,
+ 0x4255, 0x575E, 0, 0, 0xBD5A, 0x355E, 0x5768, 0x402D,
+ 0x3165, 0x5762, 0x3278, 0x5767, 0, 0xBD5B, 0, 0x3631,
+ 0, 0x5764, 0, 0xBD5C, 0, 0xBD5D, 0, 0,
+ 0, 0, 0x576A, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E680_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0xBD51,
+ 0, 0, 0xBD52, 0, 0, 0x744A, 0x5763, 0x5769,
+ 0x5761, 0, 0x455C, 0xBD54, 0x744B, 0x5766, 0x495D, 0xAC47,
+ 0x744C, 0x5760, 0xBD58, 0x5765, 0x4E67, 0x3B57, 0, 0xBD59,
+ 0x4255, 0x575E, 0xAC48, 0, 0xAC49, 0x355E, 0x5768, 0x402D,
+ 0x3165, 0x5762, 0x3278, 0x5767, 0, 0xBD5B, 0, 0x3631,
+ 0, 0x5764, 0, 0x744D, 0, 0x744E, 0, 0,
+ 0, 0, 0x576A, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E681[] = {
+ 0xBD5E, 0x576C, 0x5776, 0x5774, 0, 0, 0x5771, 0xBD5F,
+ 0xBD60, 0xBD61, 0x5770, 0x4E78, 0xBD62, 0x5772, 0, 0,
+ 0x3632, 0xBD63, 0x3931, 0, 0xBD64, 0x3D7A, 0xBD65, 0xBD66,
+ 0, 0x5779, 0x576B, 0, 0, 0xBD67, 0, 0x576F,
+ 0x575F, 0xBD68, 0x327A, 0x5773, 0x5775, 0x4351, 0, 0xBD69,
+ 0x3A28, 0x3238, 0x576D, 0x5778, 0x5777, 0x3633, 0, 0x4229,
+ 0x3366, 0xBD6A, 0, 0, 0, 0x3743, 0, 0x576E,
+ 0, 0, 0, 0, 0, 0, 0xBD6B, 0xBD6C,
+};
+static const unsigned short utf8_to_euc_E681_x0213[] = {
+ 0xBD5E, 0x576C, 0x5776, 0x5774, 0, 0, 0x5771, 0x744F,
+ 0xBD60, 0xBD61, 0x5770, 0x4E78, 0xAC4B, 0x5772, 0, 0,
+ 0x3632, 0xBD63, 0x3931, 0, 0xBD64, 0x3D7A, 0xBD65, 0xBD66,
+ 0, 0x5779, 0x576B, 0, 0, 0, 0, 0x576F,
+ 0x575F, 0xBD68, 0x327A, 0x5773, 0x5775, 0x4351, 0, 0xBD69,
+ 0x3A28, 0x3238, 0x576D, 0x5778, 0x5777, 0x3633, 0, 0x4229,
+ 0x3366, 0xBD6A, 0, 0, 0, 0x3743, 0, 0x576E,
+ 0, 0, 0, 0, 0, 0, 0xBD6B, 0xAC4C,
+};
+static const unsigned short utf8_to_euc_E682[] = {
+ 0, 0x577A, 0xBD6D, 0x577D, 0x5821, 0xF43F, 0xBD6E, 0,
+ 0xBD6F, 0x3C3D, 0xBD70, 0x5827, 0x4470, 0x577B, 0xBD71, 0,
+ 0, 0xBD72, 0x5825, 0xBD73, 0x3279, 0xBD74, 0x5823, 0x5824,
+ 0xBD75, 0, 0x577E, 0x5822, 0, 0xBD76, 0xBD77, 0x3867,
+ 0x4D2A, 0, 0xBD78, 0x3435, 0xBD79, 0xBD7A, 0x3159, 0x5826,
+ 0xBD7B, 0x473A, 0x302D, 0, 0, 0, 0, 0,
+ 0xBD7C, 0xBD7D, 0x4861, 0x575C, 0x582C, 0x5830, 0x4C65, 0xBD7E,
+ 0x5829, 0, 0, 0xBE21, 0x4569, 0x582E, 0xBE22, 0,
+};
+static const unsigned short utf8_to_euc_E682_x0213[] = {
+ 0, 0x577A, 0xBD6D, 0x577D, 0x5821, 0, 0xBD6E, 0,
+ 0xBD6F, 0x3C3D, 0xAC4D, 0x5827, 0x4470, 0x577B, 0xBD71, 0,
+ 0, 0xBD72, 0x5825, 0xBD73, 0x3279, 0xAC4E, 0x5823, 0x5824,
+ 0xBD75, 0, 0x577E, 0x5822, 0, 0x7451, 0x7452, 0x3867,
+ 0x4D2A, 0, 0xBD78, 0x3435, 0xBD79, 0xBD7A, 0x3159, 0x5826,
+ 0xAC4F, 0x473A, 0x302D, 0, 0, 0, 0, 0,
+ 0xAC51, 0xAC52, 0x4861, 0x575C, 0x582C, 0x5830, 0x4C65, 0xBD7E,
+ 0x5829, 0, 0, 0xBE21, 0x4569, 0x582E, 0xAC53, 0,
+};
+static const unsigned short utf8_to_euc_E683[] = {
+ 0, 0, 0xBE23, 0, 0xBE24, 0x3E70, 0x582F, 0x4657,
+ 0xBE25, 0xBE26, 0xBE27, 0xBE28, 0, 0, 0xBE29, 0xBE2A,
+ 0, 0x4F47, 0, 0x582B, 0xBE2B, 0xBE2C, 0, 0,
+ 0x5831, 0xBE2D, 0x397B, 0xBE2E, 0x404B, 0xBE2F, 0xBE30, 0x3054,
+ 0x582A, 0x5828, 0xBE31, 0x415A, 0, 0xBE32, 0, 0x577C,
+ 0x3B34, 0, 0, 0, 0, 0, 0, 0,
+ 0x4246, 0x583D, 0xBE33, 0x415B, 0x5838, 0xBE34, 0x5835, 0x5836,
+ 0xBE35, 0x3C66, 0x5839, 0x583C, 0xBE36, 0xBE37, 0, 0,
+};
+static const unsigned short utf8_to_euc_E683_x0213[] = {
+ 0, 0, 0xBE23, 0, 0xBE24, 0x3E70, 0x582F, 0x4657,
+ 0xAC54, 0xBE26, 0xBE27, 0x7453, 0, 0, 0xBE29, 0xBE2A,
+ 0, 0x4F47, 0, 0x582B, 0x7454, 0x7455, 0, 0,
+ 0x5831, 0xAC55, 0x397B, 0xAC56, 0x404B, 0x7456, 0, 0x3054,
+ 0x582A, 0x5828, 0xBE31, 0x415A, 0, 0xBE32, 0, 0x577C,
+ 0x3B34, 0, 0, 0, 0, 0, 0xAC57, 0,
+ 0x4246, 0x583D, 0xAC58, 0x415B, 0x5838, 0xAC59, 0x5835, 0x5836,
+ 0x7457, 0x3C66, 0x5839, 0x583C, 0xBE36, 0xBE37, 0, 0,
+};
+static const unsigned short utf8_to_euc_E684[] = {
+ 0x5837, 0x3D25, 0xBE38, 0x583A, 0, 0, 0x5834, 0xBE39,
+ 0x4C7C, 0x4C7B, 0xBE3A, 0, 0xBE3B, 0x583E, 0x583F, 0x3055,
+ 0xBE3C, 0xBE3D, 0xBE3E, 0xBE3F, 0xBE40, 0x5833, 0xBE41, 0xBE42,
+ 0, 0xBE43, 0x3672, 0x3026, 0xBE44, 0, 0xBE45, 0x3436,
+ 0xF440, 0x583B, 0xBE46, 0, 0, 0, 0, 0x5843,
+ 0x5842, 0, 0xBE47, 0xBE48, 0x5847, 0, 0, 0,
+ 0xBE49, 0xBE4A, 0, 0, 0x5848, 0xBE4B, 0xBE4C, 0xBE4D,
+ 0, 0xBE4E, 0, 0, 0x5846, 0x5849, 0x5841, 0x5845,
+};
+static const unsigned short utf8_to_euc_E684_x0213[] = {
+ 0x5837, 0x3D25, 0xBE38, 0x583A, 0, 0, 0x5834, 0xBE39,
+ 0x4C7C, 0x4C7B, 0xBE3A, 0, 0xBE3B, 0x583E, 0x583F, 0x3055,
+ 0xAC5A, 0, 0xAC5B, 0xAC5C, 0xBE40, 0x5833, 0xBE41, 0xBE42,
+ 0, 0xAC5D, 0x3672, 0x3026, 0x7458, 0, 0xAC5E, 0x3436,
+ 0, 0x583B, 0xBE46, 0, 0, 0, 0, 0x5843,
+ 0x5842, 0, 0xBE47, 0x7459, 0x5847, 0, 0, 0,
+ 0x745A, 0xBE4A, 0, 0, 0x5848, 0xBE4B, 0xBE4C, 0x745B,
+ 0, 0xBE4E, 0xAC5F, 0, 0x5846, 0x5849, 0x5841, 0x5845,
+};
+static const unsigned short utf8_to_euc_E685[] = {
+ 0, 0xBE4F, 0x584A, 0, 0x584B, 0xBE50, 0xBE51, 0x5840,
+ 0x3B7C, 0xBE52, 0x5844, 0x4256, 0x3932, 0x5832, 0x3F35, 0,
+ 0, 0, 0, 0x5858, 0, 0x4A69, 0, 0,
+ 0x584E, 0x584F, 0x5850, 0, 0, 0x5857, 0xBE53, 0x5856,
+ 0xBE54, 0, 0x4B7D, 0x3437, 0, 0x5854, 0, 0x3745,
+ 0x3334, 0, 0, 0x5851, 0xBE55, 0, 0x4E38, 0x5853,
+ 0x3056, 0x5855, 0xBE56, 0x584C, 0x5852, 0x5859, 0x3744, 0x584D,
+ 0xBE57, 0, 0, 0xBE58, 0xBE59, 0, 0x4D5D, 0xBE5A,
+};
+static const unsigned short utf8_to_euc_E685_x0213[] = {
+ 0, 0xAC61, 0x584A, 0, 0x584B, 0xBE50, 0xAC62, 0x5840,
+ 0x3B7C, 0xBE52, 0x5844, 0x4256, 0x3932, 0x5832, 0x3F35, 0,
+ 0, 0, 0, 0x5858, 0, 0x4A69, 0, 0,
+ 0x584E, 0x584F, 0x5850, 0, 0, 0x5857, 0xBE53, 0x5856,
+ 0xAC63, 0, 0x4B7D, 0x3437, 0, 0x5854, 0, 0x3745,
+ 0x3334, 0, 0, 0x5851, 0xBE55, 0, 0x4E38, 0x5853,
+ 0x3056, 0x5855, 0xBE56, 0x584C, 0x5852, 0x5859, 0x3744, 0x584D,
+ 0xBE57, 0, 0, 0xBE58, 0xAC64, 0, 0x4D5D, 0xBE5A,
+};
+static const unsigned short utf8_to_euc_E686[] = {
+ 0xBE5B, 0xBE5C, 0x4D2B, 0xBE5D, 0xBE5E, 0, 0, 0x585C,
+ 0, 0, 0x5860, 0xBE5F, 0, 0xBE60, 0x417E, 0,
+ 0x4E79, 0x5861, 0xBE61, 0xBE62, 0x585E, 0, 0x585B, 0xBE63,
+ 0xBE64, 0x585A, 0x585F, 0, 0xBE65, 0xBE66, 0, 0xBE67,
+ 0xBE68, 0, 0, 0, 0x4A30, 0xBE69, 0, 0x4634,
+ 0xBE6A, 0x3746, 0xBE6B, 0x5862, 0x585D, 0xBE6C, 0x5863, 0,
+ 0, 0, 0x377B, 0, 0, 0, 0x3231, 0,
+ 0xBE6D, 0xBE6E, 0x586B, 0, 0xBE6F, 0, 0x3438, 0,
+};
+static const unsigned short utf8_to_euc_E686_x0213[] = {
+ 0xBE5B, 0xBE5C, 0x4D2B, 0xBE5D, 0xBE5E, 0, 0, 0x585C,
+ 0, 0, 0x5860, 0xBE5F, 0, 0x745D, 0x417E, 0,
+ 0x4E79, 0x5861, 0xAC66, 0xAC67, 0x585E, 0, 0x585B, 0xAC68,
+ 0xAC69, 0x585A, 0x585F, 0, 0xBE65, 0xBE66, 0, 0xBE67,
+ 0xBE68, 0, 0, 0, 0x4A30, 0xAC6A, 0, 0x4634,
+ 0xAC6B, 0x3746, 0xBE6B, 0x5862, 0x585D, 0xAC6C, 0x5863, 0,
+ 0, 0, 0x377B, 0, 0, 0, 0x3231, 0,
+ 0xBE6D, 0x7460, 0x586B, 0, 0x745F, 0, 0x3438, 0,
+};
+static const unsigned short utf8_to_euc_E687[] = {
+ 0xBE70, 0xBE71, 0xBE72, 0x5869, 0, 0, 0x586A, 0x3A29,
+ 0x5868, 0x5866, 0x5865, 0x586C, 0x5864, 0x586E, 0xBE73, 0xBE74,
+ 0x327B, 0, 0, 0, 0, 0xBE75, 0, 0,
+ 0, 0, 0, 0, 0xBE76, 0xBE77, 0xBE78, 0xBE79,
+ 0, 0xBE7A, 0xBE7B, 0x5870, 0, 0xBE7E, 0x586F, 0xBE7C,
+ 0, 0xBE7D, 0, 0, 0xBF21, 0xBF22, 0, 0xBF23,
+ 0, 0, 0x4428, 0, 0x5873, 0, 0x5871, 0x5867,
+ 0x377C, 0, 0x5872, 0, 0x5876, 0x5875, 0x5877, 0x5874,
+};
+static const unsigned short utf8_to_euc_E687_x0213[] = {
+ 0xBE70, 0xBE71, 0xBE72, 0x5869, 0, 0, 0x586A, 0x3A29,
+ 0x5868, 0x5866, 0x5865, 0x586C, 0x5864, 0x586E, 0xBE73, 0xBE74,
+ 0x327B, 0, 0, 0, 0, 0xAC6E, 0, 0,
+ 0, 0, 0, 0, 0xBE76, 0xAC6F, 0xBE78, 0xAC70,
+ 0, 0xBE7A, 0xBE7B, 0x5870, 0, 0xBE7E, 0x586F, 0xBE7C,
+ 0, 0xBE7D, 0, 0, 0xBF21, 0xBF22, 0, 0xBF23,
+ 0, 0, 0x4428, 0, 0x5873, 0xAC71, 0x5871, 0x5867,
+ 0x377C, 0, 0x5872, 0, 0x5876, 0x5875, 0x5877, 0x5874,
+};
+static const unsigned short utf8_to_euc_E688[] = {
+ 0x5878, 0xBF24, 0, 0xBF25, 0xBF26, 0, 0, 0xBF27,
+ 0x5879, 0x587A, 0x4A6A, 0, 0x587C, 0x587B, 0x3D3F, 0,
+ 0x402E, 0x3266, 0x327C, 0xBF28, 0x587D, 0xBF29, 0x303F, 0,
+ 0, 0, 0x404C, 0x587E, 0xBF2A, 0x6C43, 0x5921, 0x3761,
+ 0xBF2B, 0x5922, 0xBF2C, 0xBF2D, 0, 0, 0x406F, 0xBF2E,
+ 0, 0xBF2F, 0x5923, 0xBF30, 0, 0, 0x5924, 0x353A,
+ 0x5925, 0, 0x5926, 0x5927, 0x4257, 0, 0, 0,
+ 0x384D, 0xBF31, 0, 0x4C61, 0, 0xBF32, 0, 0x4B3C,
+};
+static const unsigned short utf8_to_euc_E688_x0213[] = {
+ 0x5878, 0xBF24, 0, 0xBF25, 0xBF26, 0, 0, 0xBF27,
+ 0x5879, 0x587A, 0x4A6A, 0, 0x587C, 0x587B, 0x3D3F, 0,
+ 0x402E, 0x3266, 0x327C, 0, 0x587D, 0xAC73, 0x303F, 0,
+ 0, 0, 0x404C, 0x587E, 0xBF2A, 0x6C43, 0x5921, 0x3761,
+ 0xBF2B, 0x5922, 0x7462, 0xAC74, 0, 0, 0x406F, 0xBF2E,
+ 0, 0xAC75, 0x5923, 0xBF30, 0, 0, 0x5924, 0x353A,
+ 0x5925, 0, 0x5926, 0x5927, 0x4257, 0, 0, 0,
+ 0x384D, 0xBF31, 0, 0x4C61, 0, 0xBF32, 0x7463, 0x4B3C,
+};
+static const unsigned short utf8_to_euc_E689[] = {
+ 0x3D6A, 0x5928, 0xBF33, 0xBF34, 0xBF35, 0, 0xBF36, 0x4070,
+ 0x6E3D, 0x4862, 0, 0x3C6A, 0xBF37, 0x3A4D, 0x5929, 0,
+ 0xBF38, 0xBF39, 0xBF3A, 0x4247, 0xBF3B, 0x4A27, 0xBF3C, 0,
+ 0x4271, 0, 0xBF3D, 0x592C, 0xBF3E, 0, 0x592A, 0,
+ 0x592D, 0, 0, 0x592B, 0xBF3F, 0, 0, 0,
+ 0x592E, 0, 0, 0, 0, 0xBF40, 0x4A31, 0xBF41,
+ 0, 0x3037, 0, 0xBF42, 0, 0, 0x495E, 0,
+ 0, 0x4863, 0xBF43, 0, 0x592F, 0xBF44, 0x5932, 0x3E35,
+};
+static const unsigned short utf8_to_euc_E689_x0213[] = {
+ 0x3D6A, 0x5928, 0xBF33, 0x7464, 0xBF35, 0, 0xAC76, 0x4070,
+ 0x6E3D, 0x4862, 0, 0x3C6A, 0xAC77, 0x3A4D, 0x5929, 0,
+ 0xBF38, 0xAC78, 0xAC79, 0x4247, 0xBF3B, 0x4A27, 0x7465, 0,
+ 0x4271, 0, 0x7466, 0x592C, 0xBF3E, 0, 0x592A, 0,
+ 0x592D, 0xAC7A, 0, 0x592B, 0xAC7B, 0, 0, 0,
+ 0x592E, 0, 0, 0, 0, 0xAC7D, 0x4A31, 0x7467,
+ 0, 0x3037, 0, 0xAC7E, 0, 0, 0x495E, 0,
+ 0, 0x4863, 0xBF43, 0xAC7C, 0x592F, 0xBF44, 0x5932, 0x3E35,
+};
+static const unsigned short utf8_to_euc_E68A[] = {
+ 0x353B, 0, 0x5930, 0x5937, 0x3E36, 0, 0, 0,
+ 0, 0x5931, 0x4744, 0, 0, 0xBF45, 0xBF46, 0xBF47,
+ 0xBF48, 0x4D5E, 0x5933, 0x5934, 0x5938, 0x456A, 0x5935, 0x3933,
+ 0x405E, 0, 0, 0x5946, 0x4834, 0, 0x4272, 0,
+ 0, 0, 0, 0, 0, 0, 0xBF49, 0,
+ 0xBF4A, 0, 0, 0x4864, 0x5A2D, 0, 0, 0,
+ 0, 0x4A7A, 0, 0xBF4B, 0, 0x4471, 0xBF4C, 0xBF4D,
+ 0, 0x4B75, 0xBF4E, 0x593B, 0x3221, 0x436A, 0xBF4F, 0xBF50,
+};
+static const unsigned short utf8_to_euc_E68A_x0213[] = {
+ 0x353B, 0, 0x5930, 0x5937, 0x3E36, 0x7468, 0, 0,
+ 0, 0x5931, 0x4744, 0, 0, 0xBF45, 0xBF46, 0xBF47,
+ 0xBF48, 0x4D5E, 0x5933, 0x5934, 0x5938, 0x456A, 0x5935, 0x3933,
+ 0x405E, 0xAD21, 0, 0x5946, 0x4834, 0, 0x4272, 0,
+ 0, 0, 0, 0, 0, 0, 0xAD22, 0,
+ 0xBF4A, 0, 0, 0x4864, 0x5A2D, 0, 0, 0,
+ 0, 0x4A7A, 0, 0xBF4B, 0, 0x4471, 0xBF4C, 0xBF4D,
+ 0, 0x4B75, 0xBF4E, 0x593B, 0x3221, 0x436A, 0xBF4F, 0xBF50,
+};
+static const unsigned short utf8_to_euc_E68B[] = {
+ 0, 0, 0x5944, 0, 0xBF51, 0x4334, 0x593E, 0x5945,
+ 0x5940, 0x5947, 0x5943, 0, 0x5942, 0x476F, 0xBF52, 0x593C,
+ 0x327D, 0x593A, 0x3571, 0x4273, 0x5936, 0xBF53, 0xBF54, 0x5939,
+ 0x3934, 0x405B, 0xBF55, 0x3E37, 0x5941, 0x4752, 0, 0,
+ 0x3572, 0x3348, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xBF56, 0, 0x3367, 0x3F21, 0x5949, 0x594E,
+ 0, 0x594A, 0xBF57, 0x377D, 0xBF58, 0x594F, 0x3B22, 0x3969,
+ 0, 0, 0, 0, 0xBF59, 0xBF5A, 0x3D26, 0x593D,
+};
+static const unsigned short utf8_to_euc_E68B_x0213[] = {
+ 0, 0, 0x5944, 0, 0x7469, 0x4334, 0x593E, 0x5945,
+ 0x5940, 0x5947, 0x5943, 0, 0x5942, 0x476F, 0xBF52, 0x593C,
+ 0x327D, 0x593A, 0x3571, 0x4273, 0x5936, 0xAD23, 0x746A, 0x5939,
+ 0x3934, 0x405B, 0xBF55, 0x3E37, 0x5941, 0x4752, 0, 0,
+ 0x3572, 0x3348, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xBF56, 0, 0x3367, 0x3F21, 0x5949, 0x594E,
+ 0, 0x594A, 0xBF57, 0x377D, 0xBF58, 0x594F, 0x3B22, 0x3969,
+ 0, 0, 0, 0, 0x746B, 0xAD25, 0x3D26, 0x593D,
+};
+static const unsigned short utf8_to_euc_E68C[] = {
+ 0, 0x3B7D, 0x594C, 0xBF5B, 0xBF5C, 0, 0, 0x3B58,
+ 0x594D, 0x3044, 0xBF5D, 0xBF5E, 0x5948, 0xBF5F, 0, 0,
+ 0xBF60, 0x4429, 0, 0xBF61, 0, 0, 0xBF62, 0,
+ 0xBF63, 0x3573, 0, 0, 0, 0, 0, 0x3634,
+ 0, 0, 0, 0, 0, 0, 0, 0x594B,
+ 0x3027, 0xBF64, 0xBF65, 0x3A43, 0, 0xBF66, 0, 0x3F36,
+ 0, 0, 0, 0, 0, 0xBF67, 0xBF68, 0,
+ 0, 0xBF69, 0x4472, 0, 0xBF6A, 0x4854, 0x5951, 0x415E,
+};
+static const unsigned short utf8_to_euc_E68C_x0213[] = {
+ 0, 0x3B7D, 0x594C, 0xAD26, 0xBF5C, 0, 0, 0x3B58,
+ 0x594D, 0x3044, 0x746C, 0xBF5E, 0x5948, 0xAD27, 0, 0,
+ 0xAD28, 0x4429, 0, 0xBF61, 0, 0, 0xBF62, 0,
+ 0x746D, 0x3573, 0, 0, 0, 0, 0, 0x3634,
+ 0, 0, 0, 0, 0, 0, 0, 0x594B,
+ 0x3027, 0xBF64, 0xBF65, 0x3A43, 0, 0xBF66, 0, 0x3F36,
+ 0, 0, 0xAD2B, 0, 0, 0xAD2C, 0xBF68, 0,
+ 0, 0x746E, 0x4472, 0xAD2D, 0xAD2E, 0x4854, 0x5951, 0x415E,
+};
+static const unsigned short utf8_to_euc_E68D[] = {
+ 0, 0xBF6B, 0xBF6C, 0xBF6D, 0xBF6E, 0, 0xBF6F, 0,
+ 0, 0x422A, 0xBF70, 0xBF71, 0x3B2B, 0x5952, 0xBF72, 0x5954,
+ 0x5950, 0, 0xBF73, 0xBF74, 0xBF75, 0x4A61, 0, 0x443D,
+ 0xBF76, 0, 0, 0xBF77, 0x415C, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xBF78, 0xBF79, 0x4A7B,
+ 0x3C4E, 0x5960, 0, 0x595F, 0xBF7A, 0xBF7B, 0x3F78, 0,
+ 0, 0xBF7C, 0x377E, 0, 0xBF7D, 0xBF7E, 0x5959, 0x3E39,
+ 0xC021, 0, 0x4668, 0x4731, 0xC022, 0xC023, 0, 0xC024,
+};
+static const unsigned short utf8_to_euc_E68D_x0213[] = {
+ 0, 0xAD2F, 0xBF6C, 0x746F, 0xAD30, 0, 0xBF6F, 0,
+ 0, 0x422A, 0xBF70, 0xBF71, 0x3B2B, 0x5952, 0xAD31, 0x5954,
+ 0x5950, 0, 0xBF73, 0xBF74, 0xBF75, 0x4A61, 0, 0x443D,
+ 0xBF76, 0xAD33, 0, 0xBF77, 0x415C, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x7470, 0xBF79, 0x4A7B,
+ 0x3C4E, 0x5960, 0, 0x595F, 0xAD36, 0xBF7B, 0x3F78, 0,
+ 0, 0xBF7C, 0x377E, 0, 0xBF7D, 0xBF7E, 0x5959, 0x3E39,
+ 0xC021, 0, 0x4668, 0x4731, 0x7471, 0xC023, 0, 0xC024,
+};
+static const unsigned short utf8_to_euc_E68E[] = {
+ 0x5957, 0, 0xC025, 0x415D, 0xC026, 0, 0, 0xC027,
+ 0x3C78, 0x595C, 0xC028, 0, 0x3E38, 0, 0x5956, 0x595B,
+ 0xC029, 0, 0x4753, 0, 0xC02A, 0xC02B, 0x5955, 0,
+ 0x3721, 0xC02C, 0xC02D, 0x335D, 0, 0, 0xC02E, 0x595D,
+ 0x4E2B, 0x3A4E, 0x4335, 0x595A, 0xC02F, 0x405C, 0xC030, 0x3935,
+ 0x3F64, 0x3166, 0x413C, 0x5958, 0x3545, 0xC031, 0xC032, 0xC033,
+ 0, 0, 0x3747, 0, 0x444F, 0x595E, 0, 0,
+ 0, 0, 0, 0x415F, 0, 0xC034, 0x5961, 0,
+};
+static const unsigned short utf8_to_euc_E68E_x0213[] = {
+ 0x5957, 0, 0xC025, 0x415D, 0xAD37, 0, 0, 0xC027,
+ 0x3C78, 0x595C, 0xC028, 0, 0x3E38, 0, 0x5956, 0x595B,
+ 0xC029, 0, 0x4753, 0, 0xAD3A, 0xC02B, 0x5955, 0,
+ 0x3721, 0xAD38, 0xC02D, 0x335D, 0, 0, 0xC02E, 0x595D,
+ 0x4E2B, 0x3A4E, 0x4335, 0x595A, 0xC02F, 0x405C, 0xC030, 0x3935,
+ 0x3F64, 0x3166, 0x413C, 0x5958, 0x3545, 0xC031, 0xC032, 0xC033,
+ 0, 0, 0x3747, 0, 0x444F, 0x595E, 0, 0,
+ 0, 0, 0, 0x415F, 0, 0xAD3B, 0x5961, 0,
+};
+static const unsigned short utf8_to_euc_E68F[] = {
+ 0x5963, 0xC035, 0, 0x4237, 0x5969, 0xC036, 0x5964, 0,
+ 0xC037, 0x5966, 0, 0, 0, 0, 0xC038, 0x4941,
+ 0x4473, 0xC039, 0x5967, 0xC03A, 0xC03B, 0xC03C, 0x4D2C, 0,
+ 0, 0, 0x4D48, 0x3439, 0xC03D, 0, 0, 0,
+ 0xC03E, 0x302E, 0, 0x5965, 0, 0xC03F, 0, 0,
+ 0, 0x5962, 0xC040, 0, 0xC041, 0, 0x3478, 0,
+ 0, 0, 0xC042, 0xC043, 0x3167, 0xC044, 0x5968, 0,
+ 0xC045, 0xC046, 0x4D49, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E68F_x0213[] = {
+ 0x5963, 0xC035, 0, 0x4237, 0x5969, 0xC036, 0x5964, 0,
+ 0xC037, 0x5966, 0, 0, 0, 0, 0xC038, 0x4941,
+ 0x4473, 0xC039, 0x5967, 0xC03A, 0xAD3D, 0xAD3E, 0x4D2C, 0,
+ 0, 0, 0x4D48, 0x3439, 0xAD3F, 0, 0, 0,
+ 0xAD40, 0x302E, 0, 0x5965, 0, 0x7472, 0, 0,
+ 0, 0x5962, 0xC040, 0xAD41, 0xAD42, 0x7473, 0x3478, 0,
+ 0, 0, 0xAD43, 0xC043, 0x3167, 0x7474, 0x5968, 0xAD3C,
+ 0xC045, 0xC046, 0x4D49, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E690[] = {
+ 0, 0, 0, 0, 0, 0, 0x596C, 0,
+ 0, 0xC047, 0xC048, 0, 0, 0x423B, 0, 0x5973,
+ 0xC049, 0, 0xC04A, 0x596D, 0xC04B, 0, 0x596A, 0x5971,
+ 0xC04C, 0, 0, 0, 0x5953, 0, 0xC04D, 0,
+ 0xC04E, 0, 0xC04F, 0, 0xC050, 0xC051, 0x596E, 0,
+ 0x5972, 0xC052, 0xC053, 0, 0x4842, 0x456B, 0, 0xC054,
+ 0xC055, 0, 0, 0, 0x596B, 0xC056, 0x596F, 0,
+ 0, 0, 0x3748, 0, 0, 0xC057, 0x3A71, 0xC058,
+};
+static const unsigned short utf8_to_euc_E690_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0x596C, 0,
+ 0, 0xAD44, 0xC048, 0, 0, 0x423B, 0, 0x5973,
+ 0x7475, 0, 0xC04A, 0x596D, 0x7476, 0, 0x596A, 0x5971,
+ 0xC04C, 0, 0, 0, 0x5953, 0, 0xAD45, 0,
+ 0xC04E, 0, 0x7477, 0, 0xC050, 0xAD46, 0x596E, 0,
+ 0x5972, 0xAD47, 0xC053, 0, 0x4842, 0x456B, 0, 0xAD48,
+ 0xC055, 0, 0, 0, 0x596B, 0xC056, 0x596F, 0,
+ 0, 0, 0x3748, 0, 0, 0xC057, 0x3A71, 0xC058,
+};
+static const unsigned short utf8_to_euc_E691[] = {
+ 0, 0, 0x405D, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xC059, 0, 0, 0x5977, 0xC05A,
+ 0, 0xC05B, 0xC05C, 0xC05D, 0xC05E, 0, 0, 0,
+ 0x4526, 0, 0xC05F, 0xC060, 0xC061, 0xC062, 0, 0xC063,
+ 0xC064, 0xC065, 0, 0xC066, 0, 0, 0, 0x5974,
+ 0, 0x4B60, 0, 0, 0, 0xC067, 0, 0x5975,
+ 0, 0, 0, 0xC068, 0xC069, 0, 0x5976, 0,
+ 0x4C4E, 0, 0x4022, 0xC06A, 0, 0xC06B, 0, 0,
+};
+static const unsigned short utf8_to_euc_E691_x0213[] = {
+ 0, 0, 0x405D, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xC059, 0, 0, 0x5977, 0xC05A,
+ 0, 0x7479, 0xC05C, 0xC05D, 0xC05E, 0, 0, 0,
+ 0x4526, 0, 0xAD49, 0xAD4A, 0xC061, 0xAD4B, 0, 0xC063,
+ 0x747A, 0xC065, 0, 0xC066, 0, 0, 0, 0x5974,
+ 0, 0x4B60, 0, 0, 0, 0x747B, 0, 0x5975,
+ 0, 0, 0, 0xAD4C, 0xC069, 0, 0x5976, 0,
+ 0x4C4E, 0x7478, 0x4022, 0xC06A, 0, 0xAD4D, 0, 0,
+};
+static const unsigned short utf8_to_euc_E692[] = {
+ 0, 0, 0, 0x3762, 0, 0xC06C, 0, 0xC06D,
+ 0x597D, 0, 0, 0, 0, 0, 0, 0xC06E,
+ 0xC06F, 0xC070, 0x3B35, 0x597A, 0, 0x5979, 0, 0,
+ 0xC071, 0xC072, 0x4732, 0xC073, 0, 0xC074, 0x4635, 0xC075,
+ 0, 0xC076, 0, 0xC077, 0x4531, 0x597B, 0xC078, 0,
+ 0xC079, 0x597C, 0, 0x496F, 0xC07A, 0x4745, 0x3B23, 0,
+ 0x4071, 0, 0x4B50, 0xC07B, 0, 0, 0, 0,
+ 0, 0x3349, 0, 0x5A25, 0x597E, 0xC07C, 0xC07D, 0xC07E,
+};
+static const unsigned short utf8_to_euc_E692_x0213[] = {
+ 0, 0, 0, 0x3762, 0, 0xC06C, 0, 0xAD4E,
+ 0x597D, 0, 0, 0, 0, 0, 0, 0xC06E,
+ 0xC06F, 0xAD4F, 0x3B35, 0x597A, 0, 0x5979, 0, 0,
+ 0xC071, 0xC072, 0x4732, 0xC073, 0, 0xAD50, 0x4635, 0xAD51,
+ 0, 0xC076, 0, 0xC077, 0x4531, 0x597B, 0xC078, 0,
+ 0xC079, 0x597C, 0, 0x496F, 0xC07A, 0x4745, 0x3B23, 0,
+ 0x4071, 0, 0x4B50, 0xC07B, 0, 0, 0, 0,
+ 0, 0x3349, 0, 0x5A25, 0x597E, 0xC07C, 0x747D, 0x747E,
+};
+static const unsigned short utf8_to_euc_E693[] = {
+ 0, 0x4D4A, 0x5A27, 0, 0xC121, 0x5A23, 0, 0x5A24,
+ 0, 0xC122, 0xC123, 0xC124, 0xC125, 0x4160, 0xC126, 0,
+ 0xC127, 0xC128, 0x5A22, 0, 0x593F, 0xC129, 0, 0xC12A,
+ 0x5A26, 0, 0x5A21, 0, 0, 0, 0, 0,
+ 0x5A2B, 0x5A2C, 0x4527, 0x5A2E, 0xC12B, 0xC12C, 0x3B24, 0x5A29,
+ 0, 0xC12D, 0xC12E, 0, 0x353C, 0xC12F, 0, 0x5A2F,
+ 0xC130, 0x5A28, 0x5A33, 0, 0x5A32, 0xC131, 0x5A31, 0xC132,
+ 0, 0, 0x5A34, 0xC133, 0, 0x5A36, 0x3E71, 0xC134,
+};
+static const unsigned short utf8_to_euc_E693_x0213[] = {
+ 0, 0x4D4A, 0x5A27, 0, 0x7521, 0x5A23, 0, 0x5A24,
+ 0, 0xC122, 0x7522, 0xAD52, 0xAD53, 0x4160, 0x747C, 0,
+ 0x7523, 0xC128, 0x5A22, 0, 0x593F, 0xAD54, 0, 0xAD55,
+ 0x5A26, 0, 0x5A21, 0, 0, 0, 0, 0,
+ 0x5A2B, 0x5A2C, 0x4527, 0x5A2E, 0xAD57, 0xAD58, 0x3B24, 0x5A29,
+ 0, 0xC12D, 0xC12E, 0, 0x353C, 0xC12F, 0, 0x5A2F,
+ 0xC130, 0x5A28, 0x5A33, 0, 0x5A32, 0xC131, 0x5A31, 0x7524,
+ 0, 0, 0x5A34, 0x7525, 0, 0x5A36, 0x3E71, 0xAD59,
+};
+static const unsigned short utf8_to_euc_E694[] = {
+ 0x5A35, 0xC135, 0, 0, 0xC136, 0x5A39, 0, 0,
+ 0xC137, 0xC138, 0xC139, 0, 0, 0, 0, 0xC13A,
+ 0, 0, 0, 0xC13B, 0xC13C, 0, 0xC13D, 0,
+ 0x5A37, 0xC13E, 0, 0xC13F, 0x5A38, 0x5970, 0xC140, 0xC141,
+ 0, 0, 0xC142, 0x5A3B, 0x5A3A, 0, 0xC143, 0,
+ 0, 0xC144, 0x5978, 0x5A3C, 0x5A30, 0, 0xC145, 0x3B59,
+ 0, 0xC146, 0, 0, 0x5A3D, 0x5A3E, 0x5A40, 0x5A3F,
+ 0x5A41, 0x327E, 0xC147, 0x3936, 0xC148, 0xC149, 0x4A7C, 0x402F,
+};
+static const unsigned short utf8_to_euc_E694_x0213[] = {
+ 0x5A35, 0xC135, 0, 0, 0xAD5A, 0x5A39, 0, 0,
+ 0xC137, 0xC138, 0xC139, 0, 0, 0, 0, 0xAD5C,
+ 0, 0, 0, 0xC13B, 0xAD5D, 0, 0xAD5E, 0,
+ 0x5A37, 0xC13E, 0, 0xC13F, 0x5A38, 0x5970, 0xAD60, 0xC141,
+ 0, 0, 0x7526, 0x5A3B, 0x5A3A, 0, 0xC143, 0,
+ 0, 0x7527, 0x5978, 0x5A3C, 0x5A30, 0, 0xC145, 0x3B59,
+ 0, 0xC146, 0xAD61, 0, 0x5A3D, 0x5A3E, 0x5A40, 0x5A3F,
+ 0x5A41, 0x327E, 0xC147, 0x3936, 0xC148, 0xC149, 0x4A7C, 0x402F,
+};
+static const unsigned short utf8_to_euc_E695[] = {
+ 0, 0, 0, 0xC14A, 0, 0x384E, 0, 0xC14B,
+ 0x5A43, 0xC14C, 0, 0, 0, 0x5A46, 0xF441, 0x4952,
+ 0xC14D, 0x355F, 0xC14E, 0, 0xC14F, 0x5A45, 0x5A44, 0x4754,
+ 0x5A47, 0x3635, 0, 0, 0, 0x5A49, 0x5A48, 0xC150,
+ 0xC151, 0, 0x343A, 0x3B36, 0, 0, 0x4658, 0xC152,
+ 0, 0, 0, 0xC153, 0x3749, 0, 0, 0,
+ 0x3F74, 0, 0x5A4A, 0, 0x4030, 0x4528, 0, 0x495F,
+ 0x5A4B, 0, 0xC154, 0, 0, 0xC155, 0, 0,
+};
+static const unsigned short utf8_to_euc_E695_x0213[] = {
+ 0, 0, 0, 0xC14A, 0xAD62, 0x384E, 0, 0xC14B,
+ 0x5A43, 0xC14C, 0, 0, 0, 0x5A46, 0, 0x4952,
+ 0xC14D, 0x355F, 0xC14E, 0, 0xAD63, 0x5A45, 0x5A44, 0x4754,
+ 0x5A47, 0x3635, 0, 0, 0, 0x5A49, 0x5A48, 0xC150,
+ 0xC151, 0, 0x343A, 0x3B36, 0, 0, 0x4658, 0x7529,
+ 0, 0, 0, 0xAD64, 0x3749, 0, 0, 0,
+ 0x3F74, 0, 0x5A4A, 0, 0x4030, 0x4528, 0, 0x495F,
+ 0x5A4B, 0, 0xAD65, 0, 0, 0xC155, 0, 0,
+};
+static const unsigned short utf8_to_euc_E696[] = {
+ 0, 0xC156, 0x5A4C, 0x5A4D, 0, 0xC157, 0, 0x4A38,
+ 0x555D, 0x4046, 0xC158, 0, 0x494C, 0, 0x3A58, 0,
+ 0x4865, 0x4843, 0xC159, 0, 0, 0xC15A, 0, 0x454D,
+ 0xC15B, 0x4E41, 0, 0x5A4F, 0x3C50, 0xC15C, 0, 0x5A50,
+ 0xC15D, 0x3036, 0, 0xC15E, 0x3654, 0x404D, 0xC15F, 0x4960,
+ 0, 0, 0, 0x5A51, 0x3B42, 0x4347, 0xC160, 0x3B5B,
+ 0x3F37, 0, 0xC161, 0xC162, 0xC163, 0, 0, 0x5A52,
+ 0, 0x4A7D, 0, 0, 0x3177, 0x3B5C, 0, 0xC164,
+};
+static const unsigned short utf8_to_euc_E696_x0213[] = {
+ 0, 0xAD66, 0x5A4C, 0x5A4D, 0xAD67, 0xAD68, 0, 0x4A38,
+ 0x555D, 0x4046, 0xAD69, 0, 0x494C, 0, 0x3A58, 0,
+ 0x4865, 0x4843, 0xC159, 0, 0, 0xC15A, 0, 0x454D,
+ 0xC15B, 0x4E41, 0, 0x5A4F, 0x3C50, 0x752A, 0, 0x5A50,
+ 0xC15D, 0x3036, 0, 0xC15E, 0x3654, 0x404D, 0xC15F, 0x4960,
+ 0, 0, 0, 0x5A51, 0x3B42, 0x4347, 0xC160, 0x3B5B,
+ 0x3F37, 0, 0xAD6A, 0xC162, 0xC163, 0xAD6B, 0, 0x5A52,
+ 0xAD6C, 0x4A7D, 0, 0, 0x3177, 0x3B5C, 0, 0xAD6D,
+};
+static const unsigned short utf8_to_euc_E697[] = {
+ 0, 0x5A55, 0xC165, 0x5A53, 0x5A56, 0x4E39, 0x5A54, 0,
+ 0xC166, 0xC167, 0, 0x407B, 0x5A57, 0, 0xC168, 0x4232,
+ 0xC169, 0, 0x5A58, 0, 0xC16A, 0, 0xC16B, 0x347A,
+ 0xC16C, 0x5A5A, 0, 0x5A59, 0, 0, 0, 0xC16D,
+ 0x5A5B, 0x5A5C, 0x347B, 0, 0, 0x467C, 0x4336, 0x356C,
+ 0x3B5D, 0x4161, 0, 0, 0x3D5C, 0x3030, 0, 0,
+ 0xC16E, 0x5A5D, 0xC16F, 0, 0xC170, 0xC171, 0, 0,
+ 0, 0xC172, 0x3222, 0x5A61, 0, 0, 0xC173, 0xC174,
+};
+static const unsigned short utf8_to_euc_E697_x0213[] = {
+ 0, 0x5A55, 0xAD6E, 0x5A53, 0x5A56, 0x4E39, 0x5A54, 0,
+ 0xC166, 0xAD6F, 0, 0x407B, 0x5A57, 0, 0xC168, 0x4232,
+ 0xC169, 0, 0x5A58, 0, 0xAD70, 0, 0xC16B, 0x347A,
+ 0xC16C, 0x5A5A, 0, 0x5A59, 0, 0, 0, 0xC16D,
+ 0x5A5B, 0x5A5C, 0x347B, 0, 0, 0x467C, 0x4336, 0x356C,
+ 0x3B5D, 0x4161, 0, 0, 0x3D5C, 0x3030, 0, 0,
+ 0xC16E, 0x5A5D, 0xAD72, 0, 0xC170, 0xC171, 0, 0,
+ 0, 0xAD73, 0x3222, 0x5A61, 0xAD74, 0, 0xC173, 0xC174,
+};
+static const unsigned short utf8_to_euc_E698[] = {
+ 0xC175, 0, 0x3937, 0x5A60, 0xC176, 0, 0x3A2B, 0x3E3A,
+ 0xC177, 0xC178, 0x5A5F, 0, 0x3E3B, 0xC179, 0x4C40, 0x3A2A,
+ 0, 0xC17A, 0xC17B, 0x3057, 0x404E, 0xC17C, 0xC17D, 0,
+ 0, 0, 0, 0, 0x5A66, 0xC17E, 0xC221, 0x4031,
+ 0x3147, 0xC222, 0xC223, 0xC224, 0xC225, 0x3D55, 0xC226, 0x4B66,
+ 0x3A72, 0xC227, 0xC228, 0xC229, 0xC22A, 0x3E3C, 0xC22B, 0x4027,
+ 0xC22C, 0xC22D, 0, 0xC22E, 0x5A65, 0x5A63, 0x5A64, 0xC230,
+ 0, 0xC22F, 0, 0xF442, 0x436B, 0, 0, 0x5B26,
+};
+static const unsigned short utf8_to_euc_E698_x0213[] = {
+ 0x752C, 0, 0x3937, 0x5A60, 0xAD75, 0, 0x3A2B, 0x3E3A,
+ 0xAD76, 0x752D, 0x5A5F, 0, 0x3E3B, 0xC179, 0x4C40, 0x3A2A,
+ 0, 0xC17A, 0xC17B, 0x3057, 0x404E, 0x752E, 0xC17D, 0,
+ 0, 0, 0, 0, 0x5A66, 0xC17E, 0x752F, 0x4031,
+ 0x3147, 0xAD77, 0x7531, 0xC224, 0x7532, 0x3D55, 0xC226, 0x4B66,
+ 0x3A72, 0xC227, 0xAD78, 0x7533, 0xC22A, 0x3E3C, 0, 0x4027,
+ 0x7534, 0x7535, 0, 0x7536, 0x5A65, 0x5A63, 0x5A64, 0xC230,
+ 0, 0xC22F, 0x7530, 0, 0x436B, 0, 0, 0x5B26,
+};
+static const unsigned short utf8_to_euc_E699[] = {
+ 0xC231, 0x5A6A, 0x3B7E, 0x3938, 0x5A68, 0xC232, 0xC233, 0,
+ 0, 0x5A69, 0xC234, 0x3F38, 0xC235, 0, 0xC237, 0x5A67,
+ 0, 0xC236, 0x3B2F, 0, 0, 0, 0, 0xC238,
+ 0xC239, 0xC23A, 0, 0xC23B, 0xC23C, 0x5A6C, 0x5A6B, 0x5A70,
+ 0xC23D, 0xC23E, 0x5A71, 0, 0x5A6D, 0xF443, 0x3322, 0x5A6E,
+ 0x5A6F, 0x4855, 0xC240, 0xC241, 0xC242, 0, 0x4961, 0x374A,
+ 0x5A72, 0, 0, 0xC244, 0x4032, 0xC245, 0x3E3D, 0xC247,
+ 0xC248, 0xC249, 0x4352, 0xC24A, 0xC24C, 0, 0xC243, 0xC246,
+};
+static const unsigned short utf8_to_euc_E699_x0213[] = {
+ 0xC231, 0x5A6A, 0x3B7E, 0x3938, 0x5A68, 0xAD79, 0xC233, 0,
+ 0x7538, 0x5A69, 0xC234, 0x3F38, 0x7539, 0, 0xAD7B, 0x5A67,
+ 0, 0xAD7A, 0x3B2F, 0, 0, 0, 0, 0xAD7E,
+ 0xC239, 0x753B, 0x753C, 0xAE21, 0xC23C, 0x5A6C, 0x5A6B, 0x5A70,
+ 0xC23D, 0x753D, 0x5A71, 0xAE22, 0x5A6D, 0x753E, 0x3322, 0x5A6E,
+ 0x5A6F, 0x4855, 0xAE25, 0xAE26, 0xAE27, 0xAE28, 0x4961, 0x374A,
+ 0x5A72, 0, 0, 0x753F, 0x4032, 0xC245, 0x3E3D, 0x7540,
+ 0x7541, 0xC249, 0x4352, 0xAE29, 0xC24C, 0, 0xC243, 0xC246,
+};
+static const unsigned short utf8_to_euc_E69A[] = {
+ 0xC24B, 0x3647, 0, 0x5A73, 0x5A77, 0, 0, 0x324B,
+ 0x5A74, 0x5A76, 0, 0xC24D, 0xC24E, 0xC24F, 0x5A75, 0,
+ 0xC250, 0x3D6B, 0xC251, 0, 0, 0, 0x4348, 0x3045,
+ 0x5A78, 0xC252, 0xC253, 0xC254, 0xC255, 0x5A79, 0, 0xC256,
+ 0xC257, 0, 0x442A, 0, 0xC258, 0, 0x4E71, 0,
+ 0, 0, 0, 0x3B43, 0, 0xC259, 0x4A6B, 0,
+ 0, 0xC25A, 0xC25B, 0, 0x4B3D, 0xC25C, 0, 0,
+ 0x5B22, 0x5A7B, 0, 0xC25D, 0x5A7E, 0, 0x5A7D, 0xC25E,
+};
+static const unsigned short utf8_to_euc_E69A_x0213[] = {
+ 0xAE2A, 0x3647, 0, 0x5A73, 0x5A77, 0, 0, 0x324B,
+ 0x5A74, 0x5A76, 0, 0xC24D, 0xC24E, 0x7542, 0x5A75, 0,
+ 0xAE2B, 0x3D6B, 0xAE2C, 0, 0, 0, 0x4348, 0x3045,
+ 0x5A78, 0xAE2D, 0xC253, 0xC254, 0xC255, 0x5A79, 0, 0xC256,
+ 0x7544, 0, 0x442A, 0, 0xC258, 0, 0x4E71, 0,
+ 0, 0, 0, 0x3B43, 0, 0xAE2F, 0x4A6B, 0,
+ 0, 0xAE30, 0x7545, 0, 0x4B3D, 0xAE31, 0, 0,
+ 0x5B22, 0x5A7B, 0, 0x7546, 0x5A7E, 0, 0x5A7D, 0xAE33,
+};
+static const unsigned short utf8_to_euc_E69B[] = {
+ 0xC25F, 0x5A7A, 0xC260, 0xC261, 0x5B21, 0, 0, 0x465E,
+ 0xC262, 0x5A7C, 0, 0, 0xC263, 0, 0xC264, 0xC265,
+ 0, 0, 0, 0, 0xC266, 0, 0x5B23, 0,
+ 0, 0x3D6C, 0x5B24, 0xC267, 0x4D4B, 0x4778, 0, 0xC268,
+ 0x5B25, 0, 0, 0, 0, 0, 0x5B27, 0,
+ 0xC269, 0x5B28, 0, 0xC26A, 0xC26B, 0, 0xC26C, 0,
+ 0x5B29, 0, 0x364A, 0x3148, 0x3939, 0x5B2A, 0, 0x5B2B,
+ 0x3D71, 0x4162, 0xC26D, 0xC23F, 0x5258, 0x413E, 0x413D, 0x4258,
+};
+static const unsigned short utf8_to_euc_E69B_x0213[] = {
+ 0xC25F, 0x5A7A, 0xC260, 0xC261, 0x5B21, 0, 0x7547, 0x465E,
+ 0x7548, 0x5A7C, 0, 0, 0xC263, 0, 0xC264, 0xC265,
+ 0, 0, 0, 0, 0xC266, 0, 0x5B23, 0,
+ 0, 0x3D6C, 0x5B24, 0x754A, 0x4D4B, 0x4778, 0, 0xC268,
+ 0x5B25, 0, 0, 0, 0, 0, 0x5B27, 0,
+ 0x754B, 0x5B28, 0, 0xC26A, 0xAE35, 0, 0xC26C, 0,
+ 0x5B29, 0, 0x364A, 0x3148, 0x3939, 0x5B2A, 0, 0x5B2B,
+ 0x3D71, 0x4162, 0x754C, 0x7537, 0x5258, 0x413E, 0x413D, 0x4258,
+};
+static const unsigned short utf8_to_euc_E69C[] = {
+ 0x3A47, 0, 0, 0x5072, 0, 0xC26E, 0, 0xC26F,
+ 0x376E, 0x4D2D, 0, 0x4A7E, 0, 0x497E, 0xC270, 0x5B2C,
+ 0, 0, 0, 0xC271, 0x3A73, 0x443F, 0x5B2D, 0x4F2F,
+ 0, 0xC272, 0, 0x4B3E, 0xC273, 0x442B, 0x5B2E, 0x347C,
+ 0xC274, 0, 0xC275, 0, 0, 0, 0x5B2F, 0x5B30,
+ 0x4C5A, 0, 0x4C24, 0x4B76, 0x4B5C, 0x3B25, 0x5B32, 0,
+ 0, 0x3C6B, 0, 0xC276, 0x4B51, 0, 0x5B34, 0x5B37,
+ 0x5B36, 0, 0x3479, 0, 0, 0x3560, 0xC277, 0x5B33,
+};
+static const unsigned short utf8_to_euc_E69C_x0213[] = {
+ 0x3A47, 0xAE37, 0, 0x5072, 0, 0xAE38, 0, 0xC26F,
+ 0x376E, 0x4D2D, 0, 0x4A7E, 0, 0x497E, 0, 0x5B2C,
+ 0, 0, 0xAE39, 0x754D, 0x3A73, 0x443F, 0x5B2D, 0x4F2F,
+ 0, 0xAE3B, 0, 0x4B3E, 0xC273, 0x442B, 0x5B2E, 0x347C,
+ 0xC274, 0, 0xC275, 0, 0, 0, 0x5B2F, 0x5B30,
+ 0x4C5A, 0, 0x4C24, 0x4B76, 0x4B5C, 0x3B25, 0x5B32, 0,
+ 0, 0x3C6B, 0, 0x754F, 0x4B51, 0, 0x5B34, 0x5B37,
+ 0x5B36, 0, 0x3479, 0, 0, 0x3560, 0xC277, 0x5B33,
+};
+static const unsigned short utf8_to_euc_E69D[] = {
+ 0, 0x5B35, 0, 0, 0, 0xC278, 0x5B38, 0xC279,
+ 0xC27A, 0x3F79, 0, 0, 0xC27B, 0, 0x4D7B, 0x3049,
+ 0x3A60, 0x423C, 0, 0x3C5D, 0xC27C, 0xC27D, 0x3E73, 0,
+ 0, 0x5B3B, 0, 0, 0x454E, 0xC27E, 0x5B39, 0x422B,
+ 0x5B3A, 0x3E72, 0x4C5D, 0x5B3C, 0x5B3D, 0x4D68, 0xC321, 0,
+ 0, 0, 0x5B42, 0, 0xC322, 0x393A, 0xC323, 0x4755,
+ 0x5B3F, 0x456C, 0x5A5E, 0x5A62, 0xC324, 0x354F, 0xC325, 0x4747,
+ 0, 0, 0, 0xC326, 0x5B41, 0, 0x3E3E, 0x4844,
+};
+static const unsigned short utf8_to_euc_E69D_x0213[] = {
+ 0, 0x5B35, 0, 0, 0, 0xC278, 0x5B38, 0x7551,
+ 0x7552, 0x3F79, 0, 0, 0xAE3E, 0xAE3F, 0x4D7B, 0x3049,
+ 0x3A60, 0x423C, 0, 0x3C5D, 0xAE40, 0xC27D, 0x3E73, 0,
+ 0, 0x5B3B, 0, 0, 0x454E, 0xAE41, 0x5B39, 0x422B,
+ 0x5B3A, 0x3E72, 0x4C5D, 0x5B3C, 0x5B3D, 0x4D68, 0x7550, 0,
+ 0, 0, 0x5B42, 0, 0xC322, 0x393A, 0xC323, 0x4755,
+ 0x5B3F, 0x456C, 0x5A5E, 0x5A62, 0xAE45, 0x354F, 0xAE46, 0x4747,
+ 0, 0, 0, 0x7553, 0x5B41, 0, 0x3E3E, 0x4844,
+};
+static const unsigned short utf8_to_euc_E69E[] = {
+ 0, 0xC327, 0, 0, 0xC328, 0x5B47, 0, 0x487A,
+ 0, 0x5B3E, 0, 0x5B44, 0x5B43, 0, 0xC329, 0xC32A,
+ 0x404F, 0xC32B, 0, 0xC32C, 0, 0x4B6D, 0xC32D, 0x4E53,
+ 0xC32E, 0xC32F, 0x4B67, 0xC330, 0x324C, 0x3B5E, 0, 0,
+ 0x4F48, 0x5B46, 0x3F75, 0, 0, 0, 0x5B45, 0,
+ 0, 0x5B40, 0, 0, 0, 0, 0, 0x384F,
+ 0xC331, 0xC332, 0xC333, 0x5B4C, 0x5B4A, 0xC334, 0x324D, 0x5B48,
+ 0x5B4E, 0x5B54, 0, 0xC335, 0xC336, 0xC337, 0, 0,
+};
+static const unsigned short utf8_to_euc_E69E_x0213[] = {
+ 0, 0x7554, 0, 0, 0xC328, 0x5B47, 0, 0x487A,
+ 0, 0x5B3E, 0, 0x5B44, 0x5B43, 0, 0xC329, 0xC32A,
+ 0x404F, 0xC32B, 0xAE48, 0x7555, 0, 0x4B6D, 0xC32D, 0x4E53,
+ 0x7556, 0xC32F, 0x4B67, 0x7557, 0x324C, 0x3B5E, 0, 0,
+ 0x4F48, 0x5B46, 0x3F75, 0, 0, 0, 0x5B45, 0,
+ 0, 0x5B40, 0, 0, 0, 0, 0, 0x384F,
+ 0xAE4C, 0xC332, 0xAE4D, 0x5B4C, 0x5B4A, 0xC334, 0x324D, 0x5B48,
+ 0x5B4E, 0x5B54, 0, 0x7558, 0xC336, 0xC337, 0, 0,
+};
+static const unsigned short utf8_to_euc_E69F[] = {
+ 0xC339, 0x4248, 0xC33A, 0xC33B, 0x4A41, 0xC33C, 0x5B56, 0,
+ 0xC33D, 0xC33E, 0x4922, 0, 0, 0, 0x5B55, 0x4770,
+ 0x4B3F, 0x343B, 0xC33F, 0x4077, 0x3D40, 0, 0, 0xC340,
+ 0x4453, 0xC341, 0x4D2E, 0, 0xC342, 0x5B51, 0x5B50, 0,
+ 0, 0xC343, 0x5B52, 0, 0x5B4F, 0, 0xC344, 0x5B57,
+ 0, 0x5B4D, 0, 0, 0x5B4B, 0, 0x5B53, 0x5B49,
+ 0xC345, 0x436C, 0xC346, 0x4C78, 0x3C46, 0x3A74, 0xC347, 0xC348,
+ 0, 0xC338, 0, 0x3A3A, 0, 0, 0x4B6F, 0x3341,
+};
+static const unsigned short utf8_to_euc_E69F_x0213[] = {
+ 0x755A, 0x4248, 0xC33A, 0xAE4E, 0x4A41, 0xC33C, 0x5B56, 0,
+ 0xAE4F, 0xC33E, 0x4922, 0, 0, 0, 0x5B55, 0x4770,
+ 0x4B3F, 0x343B, 0xAE50, 0x4077, 0x3D40, 0, 0, 0x755B,
+ 0x4453, 0xAE51, 0x4D2E, 0xAE52, 0xC342, 0x5B51, 0x5B50, 0,
+ 0, 0xC343, 0x5B52, 0, 0x5B4F, 0, 0xC344, 0x5B57,
+ 0, 0x5B4D, 0, 0, 0x5B4B, 0, 0x5B53, 0x5B49,
+ 0xAE53, 0x436C, 0xC346, 0x4C78, 0x3C46, 0x3A74, 0xC347, 0xAE54,
+ 0, 0x7559, 0, 0x3A3A, 0x755C, 0, 0x4B6F, 0x3341,
+};
+static const unsigned short utf8_to_euc_E6A0[] = {
+ 0, 0xF446, 0x444E, 0x464A, 0x3149, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x4072, 0xC34A, 0, 0x4034, 0x372A,
+ 0, 0xC34B, 0, 0, 0, 0xC34C, 0x5B59, 0xC34D,
+ 0, 0x393B, 0x337C, 0, 0, 0, 0, 0xC34F,
+ 0xC34E, 0x5B5B, 0x3374, 0x5B61, 0xC350, 0xC351, 0, 0xC352,
+ 0xC353, 0xC354, 0x5B5E, 0xC355, 0x4073, 0, 0, 0,
+ 0x334B, 0x3A2C, 0, 0xC356, 0x334A, 0x3A4F, 0, 0xC357,
+};
+static const unsigned short utf8_to_euc_E6A0_x0213[] = {
+ 0, 0x755D, 0x444E, 0x464A, 0x3149, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xAE4B, 0, 0, 0x4072, 0xC34A, 0, 0x4034, 0x372A,
+ 0xAE58, 0xC34B, 0, 0, 0, 0x755F, 0x5B59, 0xAE59,
+ 0, 0x393B, 0x337C, 0, 0, 0, 0, 0xC34F,
+ 0xC34E, 0x5B5B, 0x3374, 0x5B61, 0x7560, 0xAE5A, 0, 0xC352,
+ 0xC353, 0x7561, 0x5B5E, 0xAE5C, 0x4073, 0, 0, 0,
+ 0x334B, 0x3A2C, 0, 0xAE5D, 0x334A, 0x3A4F, 0xAE5E, 0xC357,
+};
+static const unsigned short utf8_to_euc_E6A1[] = {
+ 0x5B5C, 0x3765, 0x374B, 0x456D, 0xC358, 0xC359, 0x5B5A, 0,
+ 0x3046, 0, 0xC35A, 0, 0xC35B, 0x5B5D, 0x5B5F, 0,
+ 0x364D, 0x372C, 0xC349, 0x343C, 0x354B, 0xC35C, 0, 0xC35D,
+ 0xC35E, 0x5B62, 0, 0xC35F, 0x3A79, 0x4B71, 0, 0x3B37,
+ 0, 0, 0, 0x5B63, 0, 0, 0, 0x4930,
+ 0, 0, 0, 0xC360, 0, 0, 0xC361, 0xC362,
+ 0xC363, 0xC364, 0xC365, 0, 0x5B6F, 0xC366, 0x3233, 0x5B64,
+ 0, 0xC367, 0xC368, 0xC369, 0xC36A, 0, 0x5B75, 0x5B65,
+};
+static const unsigned short utf8_to_euc_E6A1_x0213[] = {
+ 0x5B5C, 0x3765, 0x374B, 0x456D, 0xAE5F, 0xAE60, 0x5B5A, 0,
+ 0x3046, 0xAE61, 0xC35A, 0, 0xAE62, 0x5B5D, 0x5B5F, 0,
+ 0x364D, 0x372C, 0x755E, 0x343C, 0x354B, 0xAE63, 0, 0xAE64,
+ 0xC35E, 0x5B62, 0, 0x7562, 0x3A79, 0x4B71, 0, 0x3B37,
+ 0, 0, 0, 0x5B63, 0, 0, 0, 0x4930,
+ 0, 0, 0, 0xAE66, 0, 0, 0xAE67, 0xC362,
+ 0xC363, 0xC364, 0x7563, 0, 0x5B6F, 0x7564, 0x3233, 0x5B64,
+ 0, 0xC367, 0xAE68, 0xC369, 0xAE69, 0, 0x5B75, 0x5B65,
+};
+static const unsigned short utf8_to_euc_E6A2[] = {
+ 0, 0x4E42, 0xC36B, 0x5B6C, 0xC36C, 0x475F, 0xC36D, 0,
+ 0xC36E, 0, 0, 0, 0, 0x5B74, 0, 0x5B67,
+ 0, 0, 0, 0x3034, 0x5B69, 0, 0xC36F, 0x393C,
+ 0xC370, 0, 0xC371, 0x5B6B, 0xC372, 0x5B6A, 0, 0x5B66,
+ 0x5B71, 0xC373, 0x3E3F, 0xC374, 0, 0xC375, 0x546D, 0x3868,
+ 0x4D7C, 0xC376, 0xC377, 0, 0, 0x5B68, 0xC378, 0x4474,
+ 0x3323, 0x3A2D, 0xC379, 0x5B60, 0, 0x5B70, 0x3361, 0,
+ 0, 0x5B6E, 0x5B72, 0xC37A, 0x456E, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E6A2_x0213[] = {
+ 0, 0x4E42, 0xAE6A, 0x5B6C, 0xC36C, 0x475F, 0xC36D, 0,
+ 0xC36E, 0, 0, 0, 0, 0x5B74, 0, 0x5B67,
+ 0xAE6B, 0, 0, 0x3034, 0x5B69, 0, 0xAE6C, 0x393C,
+ 0xAE6E, 0xAE6F, 0xAE70, 0x5B6B, 0xAE71, 0x5B6A, 0, 0x5B66,
+ 0x5B71, 0xC373, 0x3E3F, 0x7566, 0, 0x7567, 0x546D, 0x3868,
+ 0x4D7C, 0xC376, 0xAE72, 0xAE73, 0, 0x5B68, 0xC378, 0x4474,
+ 0x3323, 0x3A2D, 0x7568, 0x5B60, 0xAE74, 0x5B70, 0x3361, 0,
+ 0, 0x5B6E, 0x5B72, 0xAE75, 0x456E, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E6A3[] = {
+ 0, 0, 0, 0, 0x347E, 0xC37B, 0x5C32, 0,
+ 0xC37C, 0x4C49, 0x5B77, 0x347D, 0xC37D, 0x5B7E, 0, 0xC37E,
+ 0xC421, 0xC422, 0x4B40, 0xC423, 0x5C21, 0x5C23, 0xC424, 0x5C27,
+ 0x5B79, 0xC425, 0x432A, 0, 0xC426, 0xC427, 0, 0x456F,
+ 0x5C2B, 0x5B7C, 0, 0x5C28, 0, 0xC428, 0, 0x5C22,
+ 0xC429, 0, 0xC42A, 0xC42B, 0xC42C, 0xC42D, 0x3F39, 0x5C2C,
+ 0xC42E, 0xC42F, 0x4033, 0, 0, 0xC430, 0xC431, 0,
+ 0, 0x5C2A, 0x343D, 0xC432, 0xC433, 0xC434, 0, 0,
+};
+static const unsigned short utf8_to_euc_E6A3_x0213[] = {
+ 0, 0, 0, 0xAE7A, 0x347E, 0xAE7B, 0x5C32, 0,
+ 0x7569, 0x4C49, 0x5B77, 0x347D, 0xAE7C, 0x5B7E, 0, 0xAE7D,
+ 0x756A, 0xC422, 0x4B40, 0xC423, 0x5C21, 0x5C23, 0xAE7E, 0x5C27,
+ 0x5B79, 0xAF21, 0x432A, 0, 0xC426, 0xC427, 0, 0x456F,
+ 0x5C2B, 0x5B7C, 0, 0x5C28, 0xAF22, 0xAF23, 0, 0x5C22,
+ 0x756B, 0, 0xC42A, 0xC42B, 0xAF24, 0x756C, 0x3F39, 0x5C2C,
+ 0x756D, 0x756E, 0x4033, 0, 0, 0xC430, 0xC431, 0xAF25,
+ 0, 0x5C2A, 0x343D, 0xAE76, 0x756F, 0xC434, 0, 0,
+};
+static const unsigned short utf8_to_euc_E6A4[] = {
+ 0x4F50, 0x5B76, 0, 0, 0x5C26, 0x3058, 0xC435, 0,
+ 0x5B78, 0xC436, 0xC437, 0x4C3A, 0x5B7D, 0x3F22, 0x4447, 0x5B73,
+ 0xC438, 0xC439, 0x5C25, 0xC43A, 0, 0, 0xC43B, 0xC43C,
+ 0, 0x3F7A, 0x5C2F, 0x3371, 0x3821, 0, 0, 0,
+ 0, 0x5C31, 0x5B7A, 0x5C30, 0, 0x5C29, 0x5B7B, 0,
+ 0x5C2D, 0, 0x5C2E, 0, 0, 0, 0, 0,
+ 0x5C3F, 0xC43D, 0, 0xC43E, 0x464E, 0xC43F, 0x5C24, 0,
+ 0xC440, 0x5C3B, 0, 0xC441, 0, 0x5C3D, 0, 0x4458,
+};
+static const unsigned short utf8_to_euc_E6A4_x0213[] = {
+ 0x4F50, 0x5B76, 0, 0xAF26, 0x5C26, 0x3058, 0xC435, 0xAF27,
+ 0x5B78, 0xC436, 0x7570, 0x4C3A, 0x5B7D, 0x3F22, 0x4447, 0x5B73,
+ 0xC438, 0xC439, 0x5C25, 0xC43A, 0, 0, 0xC43B, 0xC43C,
+ 0, 0x3F7A, 0x5C2F, 0x3371, 0x3821, 0, 0, 0,
+ 0, 0x5C31, 0x5B7A, 0x5C30, 0, 0x5C29, 0x5B7B, 0,
+ 0x5C2D, 0, 0x5C2E, 0, 0, 0, 0, 0,
+ 0x5C3F, 0xC43D, 0, 0xC43E, 0x464E, 0x7573, 0x5C24, 0,
+ 0xC440, 0x5C3B, 0, 0xAF2B, 0, 0x5C3D, 0, 0x4458,
+};
+static const unsigned short utf8_to_euc_E6A5[] = {
+ 0, 0, 0xC442, 0, 0, 0xC443, 0, 0,
+ 0, 0xC444, 0x4D4C, 0, 0, 0, 0xC445, 0,
+ 0, 0, 0, 0x4976, 0x5C38, 0x424A, 0, 0xC446,
+ 0, 0x5C3E, 0x413F, 0xC447, 0x5C35, 0x5C42, 0x5C41, 0,
+ 0x466F, 0x5C40, 0x466A, 0xC448, 0xC449, 0xC44A, 0xC44B, 0,
+ 0xC44C, 0xC44D, 0x5C44, 0x5C37, 0xC44E, 0x3648, 0x5C3A, 0x3D5D,
+ 0xC44F, 0xC450, 0xC451, 0x4760, 0x5C3C, 0x364B, 0, 0x5C34,
+ 0x5C36, 0x5C33, 0xC452, 0xC453, 0x4F30, 0x335A, 0x5C39, 0xC454,
+};
+static const unsigned short utf8_to_euc_E6A5_x0213[] = {
+ 0, 0, 0x7574, 0, 0, 0xC443, 0xAF2D, 0,
+ 0, 0x7571, 0x4D4C, 0, 0, 0, 0xC445, 0,
+ 0, 0, 0, 0x4976, 0x5C38, 0x424A, 0, 0x7575,
+ 0, 0x5C3E, 0x413F, 0xC447, 0x5C35, 0x5C42, 0x5C41, 0,
+ 0x466F, 0x5C40, 0x466A, 0x7576, 0x7577, 0xC44A, 0xC44B, 0,
+ 0x7578, 0xAF2E, 0x5C44, 0x5C37, 0xAF2F, 0x3648, 0x5C3A, 0x3D5D,
+ 0xC44F, 0xC450, 0xAF30, 0x4760, 0x5C3C, 0x364B, 0, 0x5C34,
+ 0x5C36, 0x5C33, 0xAF31, 0xC453, 0x4F30, 0x335A, 0x5C39, 0xAF32,
+};
+static const unsigned short utf8_to_euc_E6A6[] = {
+ 0xC455, 0x5C43, 0x3335, 0, 0, 0, 0, 0,
+ 0, 0, 0x3A67, 0, 0, 0xC456, 0x315D, 0,
+ 0, 0x5C54, 0xC457, 0, 0x4F31, 0x5C57, 0xC458, 0,
+ 0xC459, 0, 0, 0x3F3A, 0x5C56, 0, 0, 0,
+ 0x5C55, 0xC45A, 0, 0, 0, 0xC45B, 0xC45C, 0x5C52,
+ 0xC45D, 0, 0, 0xC45E, 0, 0xC45F, 0x5C46, 0xC460,
+ 0, 0x5C63, 0x5C45, 0, 0x5C58, 0, 0, 0xC461,
+ 0xC462, 0, 0xC463, 0x5C50, 0xC464, 0, 0x5C4B, 0x5C48,
+};
+static const unsigned short utf8_to_euc_E6A6_x0213[] = {
+ 0x7579, 0x5C43, 0x3335, 0, 0, 0, 0, 0,
+ 0, 0, 0x3A67, 0, 0, 0xC456, 0x315D, 0,
+ 0, 0x5C54, 0xAF33, 0, 0x4F31, 0x5C57, 0xAF35, 0,
+ 0xAF36, 0, 0, 0x3F3A, 0x5C56, 0, 0, 0,
+ 0x5C55, 0xC45A, 0, 0, 0, 0x757B, 0xAF37, 0x5C52,
+ 0xC45D, 0, 0, 0xC45E, 0, 0x757C, 0x5C46, 0xC460,
+ 0xAF38, 0x5C63, 0x5C45, 0, 0x5C58, 0, 0, 0xAF39,
+ 0xC462, 0, 0xAF3A, 0x5C50, 0xAF3B, 0, 0x5C4B, 0x5C48,
+};
+static const unsigned short utf8_to_euc_E6A7[] = {
+ 0, 0x5C49, 0, 0x5C51, 0, 0xC465, 0, 0x7422,
+ 0xC466, 0, 0x5C4E, 0x393D, 0x4448, 0x4164, 0x5C4C, 0,
+ 0x5C47, 0xC467, 0, 0x5C4A, 0, 0, 0xC468, 0xC469,
+ 0x4D4D, 0x4B6A, 0, 0, 0, 0x5C4F, 0x5C59, 0,
+ 0, 0, 0xC46A, 0, 0, 0xC46B, 0, 0x5C61,
+ 0x5C5A, 0, 0, 0x5C67, 0, 0x5C65, 0xC46C, 0xC46D,
+ 0, 0xC46E, 0x5C60, 0xC46F, 0, 0xC470, 0, 0,
+ 0, 0x5C5F, 0, 0x4450, 0, 0x4165, 0xC471, 0x5C5D,
+};
+static const unsigned short utf8_to_euc_E6A7_x0213[] = {
+ 0xAF3C, 0x5C49, 0, 0x5C51, 0, 0xC465, 0, 0x7422,
+ 0xC466, 0, 0x5C4E, 0x393D, 0x4448, 0x4164, 0x5C4C, 0x757D,
+ 0x5C47, 0xAF3D, 0, 0x5C4A, 0, 0, 0xAF3E, 0xC469,
+ 0x4D4D, 0x4B6A, 0, 0, 0, 0x5C4F, 0x5C59, 0,
+ 0, 0, 0x7622, 0xAF44, 0, 0xC46B, 0, 0x5C61,
+ 0x5C5A, 0x7623, 0x7624, 0x5C67, 0, 0x5C65, 0xAF45, 0xAF46,
+ 0, 0xC46E, 0x5C60, 0xAF47, 0xAF49, 0x7625, 0x7626, 0,
+ 0, 0x5C5F, 0, 0x4450, 0, 0x4165, 0xAF4A, 0x5C5D,
+};
+static const unsigned short utf8_to_euc_E6A8[] = {
+ 0xC472, 0xC473, 0x5C5B, 0xC474, 0, 0x5C62, 0, 0,
+ 0, 0, 0x5C68, 0x4875, 0x5C6E, 0, 0, 0xC475,
+ 0, 0xC476, 0x5C69, 0x5C6C, 0x5C66, 0xC477, 0, 0x4374,
+ 0, 0x4938, 0xC478, 0x5C5C, 0, 0xC479, 0x5C64, 0x3E40,
+ 0xC47A, 0x4C4F, 0x5C78, 0x5C6B, 0xC47B, 0, 0, 0,
+ 0xC47C, 0x3822, 0x3223, 0x335F, 0, 0, 0x5C53, 0,
+ 0xC47D, 0, 0xC47E, 0, 0xC521, 0x3E41, 0x5C70, 0xC522,
+ 0x5C77, 0x3C79, 0x3372, 0xC523, 0, 0x432E, 0xC524, 0xC525,
+};
+static const unsigned short utf8_to_euc_E6A8_x0213[] = {
+ 0xC472, 0xC473, 0x5C5B, 0xC474, 0, 0x5C62, 0, 0,
+ 0, 0, 0x5C68, 0x4875, 0x5C6E, 0, 0, 0x7627,
+ 0, 0xAF4B, 0x5C69, 0x5C6C, 0x5C66, 0x7628, 0, 0x4374,
+ 0, 0x4938, 0xAF4C, 0x5C5C, 0, 0xAF4D, 0x5C64, 0x3E40,
+ 0xC47A, 0x4C4F, 0x5C78, 0x5C6B, 0xC47B, 0, 0, 0,
+ 0xC47C, 0x3822, 0x3223, 0x335F, 0, 0, 0x5C53, 0,
+ 0xAF41, 0, 0xAF4F, 0xAF50, 0xAF51, 0x3E41, 0x5C70, 0xC522,
+ 0x5C77, 0x3C79, 0x3372, 0x762A, 0, 0x432E, 0x762B, 0xAF52,
+};
+static const unsigned short utf8_to_euc_E6A9[] = {
+ 0, 0, 0, 0, 0x5C6D, 0xC526, 0xC527, 0x5C72,
+ 0x5C76, 0xC528, 0xC529, 0x3636, 0, 0, 0xC52A, 0,
+ 0xC52B, 0xC52C, 0xC52D, 0, 0, 0xC52E, 0xC52F, 0,
+ 0x354C, 0x5C74, 0, 0xC530, 0, 0, 0, 0x3521,
+ 0, 0x464B, 0x5C73, 0, 0xC531, 0, 0x5C75, 0xC532,
+ 0, 0, 0xC533, 0xF449, 0, 0, 0, 0,
+ 0, 0xC534, 0x5C6F, 0xC535, 0, 0, 0, 0,
+ 0x5C71, 0, 0, 0, 0, 0, 0xC536, 0x3360,
+};
+static const unsigned short utf8_to_euc_E6A9_x0213[] = {
+ 0, 0, 0, 0, 0x5C6D, 0x762C, 0xAF53, 0x5C72,
+ 0x5C76, 0xAF54, 0xC529, 0x3636, 0, 0, 0xAF56, 0,
+ 0x762D, 0xC52C, 0xAF57, 0, 0, 0xC52E, 0x762E, 0,
+ 0x354C, 0x5C74, 0, 0x762F, 0, 0, 0, 0x3521,
+ 0, 0x464B, 0x5C73, 0, 0xAF58, 0, 0x5C75, 0xC532,
+ 0, 0, 0xC533, 0x7630, 0, 0, 0, 0,
+ 0, 0xC534, 0x5C6F, 0x7631, 0, 0, 0, 0,
+ 0x5C71, 0, 0xAF55, 0, 0, 0, 0xAF5A, 0x3360,
+};
+static const unsigned short utf8_to_euc_E6AA[] = {
+ 0x4349, 0xC537, 0, 0xC538, 0x5C7C, 0, 0xC539, 0xC53A,
+ 0, 0xC53B, 0, 0xC53C, 0, 0x5C7A, 0x3869, 0,
+ 0x5C79, 0xC53D, 0, 0, 0, 0, 0, 0x5D21,
+ 0, 0, 0, 0xC53E, 0x5B58, 0xC53F, 0xC540, 0xC541,
+ 0x5C7B, 0, 0x5C7D, 0x5C7E, 0, 0xC542, 0, 0,
+ 0, 0, 0x5D2C, 0xC543, 0x5D28, 0, 0x5B6D, 0xC544,
+ 0xC545, 0xC546, 0, 0x5D27, 0xC547, 0, 0, 0,
+ 0x5D26, 0, 0, 0x5D23, 0, 0xC548, 0xC549, 0xC54A,
+};
+static const unsigned short utf8_to_euc_E6AA_x0213[] = {
+ 0x4349, 0xC537, 0, 0xAF5B, 0x5C7C, 0, 0xC539, 0xC53A,
+ 0, 0x7633, 0, 0xAF5C, 0, 0x5C7A, 0x3869, 0,
+ 0x5C79, 0xAF5E, 0, 0, 0x7634, 0, 0, 0x5D21,
+ 0, 0, 0, 0xC53E, 0x5B58, 0x7635, 0x7636, 0xAF5F,
+ 0x5C7B, 0xAF60, 0x5C7D, 0x5C7E, 0, 0x7637, 0, 0,
+ 0, 0, 0x5D2C, 0xAF62, 0x5D28, 0, 0x5B6D, 0xC544,
+ 0xC545, 0xC546, 0, 0x5D27, 0xC547, 0, 0, 0,
+ 0x5D26, 0, 0, 0x5D23, 0, 0xAF63, 0xC549, 0xC54A,
+};
+static const unsigned short utf8_to_euc_E6AB[] = {
+ 0, 0x5C6A, 0x5D25, 0x5D24, 0, 0, 0xC54B, 0,
+ 0xC54D, 0xC54C, 0, 0, 0xC54E, 0, 0, 0,
+ 0xC54F, 0x5D2A, 0, 0x4F26, 0xC550, 0xC551, 0xC552, 0,
+ 0, 0, 0x5D2D, 0x367B, 0xC553, 0xC554, 0x5D29, 0x5D2B,
+ 0, 0, 0xF44A, 0, 0xC555, 0, 0, 0xC556,
+ 0x4827, 0, 0x5D2E, 0, 0xC557, 0, 0, 0,
+ 0xC558, 0xC559, 0xC55A, 0, 0, 0, 0, 0,
+ 0, 0, 0x5D32, 0x5D2F, 0xC55B, 0xC55C, 0, 0,
+};
+static const unsigned short utf8_to_euc_E6AB_x0213[] = {
+ 0, 0x5C6A, 0x5D25, 0x5D24, 0, 0, 0xAF64, 0,
+ 0xC54D, 0xC54C, 0, 0, 0xC54E, 0, 0, 0,
+ 0xAF66, 0x5D2A, 0, 0x4F26, 0xAF65, 0xC551, 0xC552, 0,
+ 0, 0, 0x5D2D, 0x367B, 0xAF67, 0xAF68, 0x5D29, 0x5D2B,
+ 0, 0, 0, 0, 0x7638, 0, 0, 0x7639,
+ 0x4827, 0, 0x5D2E, 0, 0xAF6B, 0, 0, 0,
+ 0xC558, 0xAF6C, 0xAF6D, 0xAF6E, 0, 0, 0, 0,
+ 0, 0, 0x5D32, 0x5D2F, 0xC55B, 0xAF6F, 0, 0,
+};
+static const unsigned short utf8_to_euc_E6AC[] = {
+ 0, 0, 0xC55D, 0xC55E, 0x4D73, 0x5D30, 0xC55F, 0xC560,
+ 0, 0xC561, 0x5C5E, 0, 0, 0, 0, 0xC562,
+ 0xC563, 0xC564, 0x5D33, 0, 0, 0, 0x5D34, 0xC565,
+ 0, 0, 0, 0xC566, 0, 0x3135, 0xC567, 0x5D36,
+ 0x3767, 0x3C21, 0, 0x3655, 0xC568, 0, 0, 0x3224,
+ 0xC569, 0, 0, 0xC56A, 0xC56B, 0, 0, 0xC56C,
+ 0, 0, 0x4D5F, 0, 0, 0xC56D, 0xC56E, 0x5D38,
+ 0x5D37, 0x5D3A, 0x353D, 0xC56F, 0, 0x3656, 0x343E, 0xC570,
+};
+static const unsigned short utf8_to_euc_E6AC_x0213[] = {
+ 0, 0, 0xC55D, 0xC55E, 0x4D73, 0x5D30, 0xC55F, 0xC560,
+ 0, 0xC561, 0x5C5E, 0xAF71, 0, 0, 0, 0xAF72,
+ 0xAF73, 0xAF74, 0x5D33, 0, 0, 0, 0x5D34, 0xAF76,
+ 0, 0, 0, 0x763C, 0, 0x3135, 0x763D, 0x5D36,
+ 0x3767, 0x3C21, 0, 0x3655, 0xC568, 0, 0, 0x3224,
+ 0xC569, 0, 0, 0xC56A, 0x763E, 0, 0, 0xAF78,
+ 0, 0, 0x4D5F, 0, 0, 0x763F, 0xC56E, 0x5D38,
+ 0x5D37, 0x5D3A, 0x353D, 0xC56F, 0, 0x3656, 0x343E, 0xC570,
+};
+static const unsigned short utf8_to_euc_E6AD[] = {
+ 0, 0, 0, 0x5D3D, 0, 0, 0xC571, 0x5D3C,
+ 0, 0x5D3E, 0xC572, 0, 0x324E, 0xC573, 0x4337, 0,
+ 0x5D3F, 0, 0xC574, 0x343F, 0x5D41, 0, 0xC575, 0,
+ 0xC576, 0x5D40, 0, 0x5D42, 0, 0xC577, 0, 0x5D43,
+ 0xC578, 0x5D44, 0x3B5F, 0x4035, 0x3A21, 0, 0x4970, 0xC579,
+ 0, 0x4A62, 0x4F44, 0xC57A, 0, 0, 0xC57B, 0x3B75,
+ 0xC57C, 0, 0, 0x3A50, 0x4E72, 0xC57D, 0, 0,
+ 0x5D45, 0x5D46, 0, 0x3B60, 0, 0xC57E, 0xC621, 0x5D47,
+};
+static const unsigned short utf8_to_euc_E6AD_x0213[] = {
+ 0, 0, 0, 0x5D3D, 0, 0, 0x7640, 0x5D3C,
+ 0, 0x5D3E, 0xAF79, 0, 0x324E, 0xC573, 0x4337, 0,
+ 0x5D3F, 0, 0xC574, 0x343F, 0x5D41, 0, 0x7641, 0,
+ 0xAF7A, 0x5D40, 0, 0x5D42, 0, 0xC577, 0, 0x5D43,
+ 0x7642, 0x5D44, 0x3B5F, 0x4035, 0x3A21, 0x7643, 0x4970, 0x7644,
+ 0, 0x4A62, 0x4F44, 0xC57A, 0xAF7B, 0, 0xC57B, 0x3B75,
+ 0xC57C, 0, 0, 0x3A50, 0x4E72, 0xAF7C, 0, 0x7645,
+ 0x5D45, 0x5D46, 0xAF7D, 0x3B60, 0, 0xC57E, 0xC621, 0x5D47,
+};
+static const unsigned short utf8_to_euc_E6AE[] = {
+ 0x5D48, 0, 0xC622, 0x5D4A, 0x5D49, 0xC623, 0x4B58, 0,
+ 0, 0x3D5E, 0x3C6C, 0x3B44, 0, 0x5D4B, 0, 0,
+ 0, 0, 0, 0, 0, 0x5D4D, 0x3F23, 0xC624,
+ 0x5D4C, 0, 0, 0xC625, 0, 0, 0x5D4E, 0xC626,
+ 0xC627, 0, 0xC628, 0xC629, 0x5D4F, 0, 0, 0,
+ 0xC62A, 0xC62B, 0x5D50, 0x5D51, 0xC62C, 0xC62D, 0xC62E, 0x5D52,
+ 0xC62F, 0x5D54, 0x5D53, 0x5D55, 0x3225, 0x434A, 0, 0x5D56,
+ 0xC630, 0xC631, 0x3B26, 0x334C, 0x5D57, 0xC632, 0xC633, 0x4542,
+};
+static const unsigned short utf8_to_euc_E6AE_x0213[] = {
+ 0x5D48, 0xAF7E, 0x7646, 0x5D4A, 0x5D49, 0xC623, 0x4B58, 0,
+ 0, 0x3D5E, 0x3C6C, 0x3B44, 0, 0x5D4B, 0, 0,
+ 0, 0, 0, 0, 0, 0x5D4D, 0x3F23, 0xC624,
+ 0x5D4C, 0, 0, 0xEE21, 0, 0, 0x5D4E, 0xC626,
+ 0xC627, 0, 0xC628, 0xC629, 0x5D4F, 0, 0, 0,
+ 0xC62A, 0x7647, 0x5D50, 0x5D51, 0xC62C, 0x7648, 0xEE22, 0x5D52,
+ 0xC62F, 0x5D54, 0x5D53, 0x5D55, 0x3225, 0x434A, 0, 0x5D56,
+ 0xC630, 0xC631, 0x3B26, 0x334C, 0x5D57, 0xEE24, 0xEE25, 0x4542,
+};
+static const unsigned short utf8_to_euc_E6AF[] = {
+ 0x544C, 0, 0, 0xC634, 0xC635, 0x3523, 0x5D58, 0,
+ 0, 0xC636, 0, 0x5D59, 0xC637, 0x4A6C, 0x4B68, 0,
+ 0, 0, 0x4647, 0x5D5A, 0x4866, 0, 0xC638, 0,
+ 0x487B, 0, 0xC639, 0x4C53, 0, 0, 0, 0x5D5B,
+ 0, 0xC63A, 0, 0xC63B, 0, 0, 0xC63C, 0xC63D,
+ 0, 0, 0, 0x5D5D, 0x5D5C, 0, 0xC63E, 0x5D5F,
+ 0, 0xC63F, 0, 0x5D5E, 0, 0, 0, 0xC640,
+ 0, 0xC641, 0, 0, 0, 0, 0, 0xC642,
+};
+static const unsigned short utf8_to_euc_E6AF_x0213[] = {
+ 0x544C, 0, 0, 0xC634, 0xC635, 0x3523, 0x5D58, 0xEE26,
+ 0xEE27, 0xEE28, 0, 0x5D59, 0xC637, 0x4A6C, 0x4B68, 0x764A,
+ 0, 0, 0x4647, 0x5D5A, 0x4866, 0, 0x764B, 0x764C,
+ 0x487B, 0, 0xEE29, 0x4C53, 0, 0, 0, 0x5D5B,
+ 0, 0xC63A, 0, 0xC63B, 0, 0, 0xEE2A, 0xEE2B,
+ 0, 0, 0, 0x5D5D, 0x5D5C, 0, 0xEE2C, 0x5D5F,
+ 0, 0xEE2D, 0, 0x5D5E, 0, 0, 0, 0xC640,
+ 0, 0xC641, 0, 0, 0, 0, 0, 0x764D,
+};
+static const unsigned short utf8_to_euc_E6B0[] = {
+ 0, 0, 0xC643, 0, 0xC644, 0xC645, 0, 0,
+ 0x5D61, 0xC646, 0, 0, 0, 0xC647, 0xC648, 0x3B61,
+ 0xC649, 0x4C31, 0xC64A, 0x5D62, 0x5D63, 0, 0, 0x3524,
+ 0, 0xC64B, 0, 0x5D64, 0, 0, 0, 0xC64C,
+ 0, 0, 0, 0x5D66, 0x5D65, 0, 0xC64D, 0xC64E,
+ 0xC64F, 0, 0, 0, 0xC650, 0, 0xC651, 0,
+ 0, 0, 0, 0xC652, 0x3F65, 0xC653, 0xC654, 0x4939,
+ 0x314A, 0, 0xC655, 0xC656, 0, 0, 0x4845, 0xC657,
+};
+static const unsigned short utf8_to_euc_E6B0_x0213[] = {
+ 0, 0, 0xEE2E, 0, 0xC644, 0x764E, 0, 0,
+ 0x5D61, 0xC646, 0xEE2F, 0, 0, 0xC647, 0xEE30, 0x3B61,
+ 0x764F, 0x4C31, 0xC64A, 0x5D62, 0x5D63, 0, 0, 0x3524,
+ 0, 0xC64B, 0, 0x5D64, 0, 0, 0, 0xC64C,
+ 0, 0, 0, 0x5D66, 0x5D65, 0, 0xC64D, 0xC64E,
+ 0xC64F, 0, 0, 0, 0xC650, 0, 0xC651, 0,
+ 0, 0, 0, 0x7650, 0x3F65, 0xEE31, 0xEE32, 0x4939,
+ 0x314A, 0, 0xEE33, 0xC656, 0, 0, 0x4845, 0xEE35,
+};
+static const unsigned short utf8_to_euc_E6B1[] = {
+ 0x4475, 0x3D41, 0x3561, 0, 0, 0, 0, 0,
+ 0, 0, 0xC658, 0xC659, 0, 0xC65A, 0x4846, 0xC65B,
+ 0x3C2E, 0, 0xC65C, 0, 0xC65D, 0x5D68, 0, 0x3440,
+ 0, 0xC65E, 0x3178, 0xC65F, 0xC660, 0x4672, 0x5D67, 0x393E,
+ 0x4353, 0, 0x5D69, 0, 0, 0, 0, 0xC736,
+ 0x5D71, 0, 0x5D6A, 0xC661, 0, 0xC662, 0, 0xC663,
+ 0x4241, 0, 0x3562, 0x5D72, 0xC664, 0, 0xC665, 0,
+ 0xC666, 0xC667, 0x3768, 0xC668, 0, 0x3525, 0x5D70, 0,
+};
+static const unsigned short utf8_to_euc_E6B1_x0213[] = {
+ 0x4475, 0x3D41, 0x3561, 0, 0, 0, 0, 0,
+ 0, 0, 0xC658, 0xC659, 0, 0xEE36, 0x4846, 0xC65B,
+ 0x3C2E, 0, 0xC65C, 0, 0xC65D, 0x5D68, 0, 0x3440,
+ 0, 0x7651, 0x3178, 0xEE37, 0x7652, 0x4672, 0x5D67, 0x393E,
+ 0x4353, 0, 0x5D69, 0, 0, 0, 0, 0xEE4F,
+ 0x5D71, 0, 0x5D6A, 0xC661, 0, 0xEE38, 0, 0,
+ 0x4241, 0, 0x3562, 0x5D72, 0x7654, 0, 0x7655, 0,
+ 0xC666, 0xC667, 0x3768, 0xC668, 0, 0x3525, 0x5D70, 0,
+};
+static const unsigned short utf8_to_euc_E6B2[] = {
+ 0, 0x5D6E, 0x5D6B, 0x4D60, 0, 0xC669, 0xC66A, 0xC66B,
+ 0x4440, 0xC66C, 0, 0, 0x4659, 0x5D6C, 0, 0,
+ 0x5D74, 0, 0x5D73, 0x3723, 0xC66D, 0xC66E, 0x322D, 0xC66F,
+ 0xC670, 0x3A3B, 0x5D6D, 0x5D6F, 0xC671, 0, 0, 0xC672,
+ 0, 0x4B57, 0x4274, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x4B77, 0, 0, 0x5D7C, 0,
+ 0xC673, 0x5D7D, 0xC674, 0x324F, 0xC675, 0, 0, 0,
+ 0x4A28, 0x4C7D, 0x5E21, 0x3C23, 0x3E42, 0x5D78, 0x5D7E, 0x3168,
+};
+static const unsigned short utf8_to_euc_E6B2_x0213[] = {
+ 0, 0x5D6E, 0x5D6B, 0x4D60, 0xEE39, 0x7656, 0x7657, 0xC66B,
+ 0x4440, 0xEE3A, 0, 0, 0x4659, 0x5D6C, 0, 0,
+ 0x5D74, 0, 0x5D73, 0x3723, 0xEE3C, 0xEE3D, 0x322D, 0xEE3E,
+ 0x7658, 0x3A3B, 0x5D6D, 0x5D6F, 0x7659, 0, 0, 0xC672,
+ 0, 0x4B57, 0x4274, 0, 0, 0, 0, 0,
+ 0, 0, 0x7653, 0x4B77, 0, 0xEE3F, 0x5D7C, 0,
+ 0xC673, 0x5D7D, 0xC674, 0x324F, 0xC675, 0, 0, 0,
+ 0x4A28, 0x4C7D, 0x5E21, 0x3C23, 0x3E42, 0x5D78, 0x5D7E, 0x3168,
+};
+static const unsigned short utf8_to_euc_E6B3[] = {
+ 0, 0x3637, 0xC676, 0, 0x5D75, 0x5D7A, 0xC677, 0,
+ 0, 0x4074, 0x4771, 0, 0x4867, 0xC678, 0, 0xC679,
+ 0xC67A, 0xC67B, 0xC67C, 0x5D77, 0xC67D, 0x4B21, 0xC67E, 0x5D79,
+ 0, 0x5E24, 0xC721, 0x5E22, 0xC722, 0x5D7B, 0, 0,
+ 0xC723, 0x4B22, 0x4748, 0x3563, 0, 0x4525, 0, 0xC724,
+ 0x436D, 0xC725, 0x5E25, 0xC726, 0xC727, 0, 0xC728, 0x5E23,
+ 0x4259, 0x5D76, 0xC729, 0x314B, 0xC72A, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E6B3_x0213[] = {
+ 0, 0x3637, 0xEE40, 0, 0x5D75, 0x5D7A, 0x765B, 0,
+ 0, 0x4074, 0x4771, 0, 0x4867, 0xC678, 0, 0xC679,
+ 0xEE41, 0xC67B, 0xC67C, 0x5D77, 0x765C, 0x4B21, 0xEE43, 0x5D79,
+ 0, 0x5E24, 0xEE44, 0x5E22, 0xEE45, 0x5D7B, 0, 0,
+ 0x765D, 0x4B22, 0x4748, 0x3563, 0, 0x4525, 0, 0xC724,
+ 0x436D, 0xEE46, 0x5E25, 0x765E, 0xEE47, 0xEE48, 0x765F, 0x5E23,
+ 0x4259, 0x5D76, 0xC729, 0x314B, 0xC72A, 0, 0, 0,
+ 0, 0, 0, 0x765A, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E6B4[] = {
+ 0, 0, 0, 0, 0xC72B, 0, 0, 0xC72C,
+ 0, 0, 0xC72D, 0x4D4E, 0x5E30, 0, 0xC72E, 0xC72F,
+ 0, 0xC730, 0x5E2F, 0xC731, 0, 0, 0, 0x4076,
+ 0, 0x5E2C, 0xC732, 0x4D6C, 0, 0, 0x4636, 0x5E26,
+ 0, 0, 0, 0, 0, 0x4445, 0xC733, 0xC734,
+ 0xC735, 0x314C, 0x393F, 0x5E29, 0, 0, 0xC737, 0xC738,
+ 0, 0xC739, 0x3D27, 0x5E2E, 0, 0x5E2D, 0x5E28, 0,
+ 0x5E2B, 0xC73A, 0, 0x3368, 0xC73B, 0x5E2A, 0x4749, 0xC73C,
+};
+static const unsigned short utf8_to_euc_E6B4_x0213[] = {
+ 0xEE4A, 0, 0, 0, 0x7661, 0, 0, 0xC72C,
+ 0, 0, 0xEE4B, 0x4D4E, 0x5E30, 0, 0x7662, 0xC72F,
+ 0, 0xC730, 0x5E2F, 0xC731, 0, 0, 0, 0x4076,
+ 0, 0x5E2C, 0xC732, 0x4D6C, 0, 0, 0x4636, 0x5E26,
+ 0, 0, 0, 0, 0xEE4C, 0x4445, 0xEE4D, 0xEE4E,
+ 0xC735, 0x314C, 0x393F, 0x5E29, 0, 0, 0x7663, 0xEE50,
+ 0, 0x7664, 0x3D27, 0x5E2E, 0xEE65, 0x5E2D, 0x5E28, 0,
+ 0x5E2B, 0x7665, 0, 0x3368, 0xEE51, 0x5E2A, 0x4749, 0x7666,
+};
+static const unsigned short utf8_to_euc_E6B5[] = {
+ 0, 0x4E2E, 0, 0, 0x3E74, 0x4075, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xC73D,
+ 0, 0x5E36, 0x5E34, 0, 0x494D, 0, 0xC73E, 0xC73F,
+ 0, 0xC740, 0, 0x5E31, 0x5E33, 0xC741, 0x313A, 0xC742,
+ 0, 0x3940, 0x4F32, 0, 0x333D, 0, 0x4962, 0xC743,
+ 0xC744, 0, 0, 0, 0x4D61, 0, 0, 0x3324,
+ 0x3F3B, 0x5E35, 0, 0, 0xC745, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E6B5_x0213[] = {
+ 0, 0x4E2E, 0, 0, 0x3E74, 0x4075, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xC73D,
+ 0x7667, 0x5E36, 0x5E34, 0xEE52, 0x494D, 0, 0xEE53, 0xC73F,
+ 0xEE54, 0xC740, 0, 0x5E31, 0x5E33, 0x7668, 0x313A, 0xC742,
+ 0, 0x3940, 0x4F32, 0, 0x333D, 0, 0x4962, 0,
+ 0xEE55, 0, 0, 0, 0x4D61, 0, 0, 0x3324,
+ 0x3F3B, 0x5E35, 0, 0, 0xC745, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E6B6[] = {
+ 0, 0, 0xC746, 0, 0, 0x5E3A, 0, 0xC747,
+ 0x3E43, 0, 0, 0, 0x4D30, 0, 0x5E37, 0,
+ 0, 0xC748, 0xC749, 0x5E32, 0xC74A, 0x5E38, 0xC74B, 0xC74C,
+ 0xC74D, 0x4E5E, 0, 0x4573, 0x4642, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xC74E, 0, 0xC74F, 0, 0, 0x3336,
+ 0, 0, 0x3155, 0, 0xC750, 0x5E3E, 0, 0xC751,
+ 0x5E41, 0xC752, 0, 0, 0x4E43, 0xC753, 0, 0xC754,
+};
+static const unsigned short utf8_to_euc_E6B6_x0213[] = {
+ 0xEE56, 0xEE57, 0x766A, 0, 0, 0x5E3A, 0, 0x766B,
+ 0x3E43, 0x766C, 0xEE58, 0, 0x4D30, 0xEE59, 0x5E37, 0,
+ 0, 0xEE5A, 0xC749, 0x5E32, 0x766D, 0x5E38, 0, 0xC74C,
+ 0xEE5B, 0x4E5E, 0, 0x4573, 0x4642, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x766E, 0xEE61, 0x766F, 0, 0xEE62, 0x3336,
+ 0, 0, 0x3155, 0, 0xEE63, 0x5E3E, 0, 0xC751,
+ 0x5E41, 0xC752, 0, 0, 0x4E43, 0xC753, 0, 0x7670,
+};
+static const unsigned short utf8_to_euc_E6B7[] = {
+ 0x4D64, 0, 0, 0, 0xC755, 0x5E48, 0x5E42, 0x5E3F,
+ 0xC756, 0, 0xC757, 0x4E54, 0x5E45, 0, 0xC758, 0xC759,
+ 0, 0x3D4A, 0x5E47, 0, 0, 0x5E4C, 0xC75A, 0,
+ 0x4571, 0x5E4A, 0, 0xC75B, 0, 0xC75C, 0x5E44, 0xC75D,
+ 0xC75E, 0x4338, 0xC75F, 0, 0x5E4B, 0xC760, 0x5E40, 0,
+ 0x5E46, 0xC761, 0x5E4D, 0x307C, 0x5E43, 0, 0x5E4E, 0xC762,
+ 0xC763, 0x3F3C, 0xF44C, 0x3D5F, 0xC764, 0x4A25, 0xC765, 0x3A2E,
+ 0xF44B, 0x5E3B, 0x5E49, 0x453A, 0xC766, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E6B7_x0213[] = {
+ 0x4D64, 0, 0xEE64, 0, 0x7671, 0x5E48, 0x5E42, 0x5E3F,
+ 0xEE66, 0, 0xC757, 0x4E54, 0x5E45, 0, 0xEE67, 0xEE68,
+ 0xEE69, 0x3D4A, 0x5E47, 0, 0, 0x5E4C, 0x7672, 0,
+ 0x4571, 0x5E4A, 0x7673, 0x7674, 0, 0x7675, 0x5E44, 0xEE6A,
+ 0xC75E, 0x4338, 0xC75F, 0, 0x5E4B, 0xC760, 0x5E40, 0,
+ 0x5E46, 0xEE6B, 0x5E4D, 0x307C, 0x5E43, 0, 0x5E4E, 0xC762,
+ 0xC763, 0x3F3C, 0, 0x3D5F, 0xC764, 0x4A25, 0xEE6C, 0x3A2E,
+ 0, 0x5E3B, 0x5E49, 0x453A, 0x7676, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E6B8[] = {
+ 0xC767, 0, 0, 0, 0xC768, 0x4036, 0, 0x3369,
+ 0x3A51, 0x3E44, 0x5E3D, 0x3D42, 0, 0, 0, 0,
+ 0, 0, 0, 0x374C, 0, 0x5E3C, 0, 0,
+ 0, 0x5E52, 0x3D6D, 0x383A, 0, 0x5E61, 0xC769, 0x5E5B,
+ 0x3574, 0x454F, 0xC76A, 0x5E56, 0x5E5F, 0x302F, 0x3132, 0xC76B,
+ 0, 0x3239, 0, 0x5E58, 0x422C, 0x5E4F, 0x5E51, 0x3941,
+ 0, 0, 0xC76C, 0, 0, 0, 0xC76D, 0,
+ 0x5E62, 0xC76E, 0x5E5D, 0xC76F, 0xC770, 0, 0x5E55, 0,
+};
+static const unsigned short utf8_to_euc_E6B8_x0213[] = {
+ 0xC767, 0, 0, 0, 0xC768, 0x4036, 0, 0x3369,
+ 0x3A51, 0x3E44, 0x5E3D, 0x3D42, 0, 0, 0, 0,
+ 0, 0, 0, 0x374C, 0, 0x5E3C, 0, 0xEE5D,
+ 0, 0x5E52, 0x3D6D, 0x383A, 0, 0x5E61, 0xEE6E, 0x5E5B,
+ 0x3574, 0x454F, 0xEE6F, 0x5E56, 0x5E5F, 0x302F, 0x3132, 0xEE70,
+ 0, 0x3239, 0, 0x5E58, 0x422C, 0x5E4F, 0x5E51, 0x3941,
+ 0, 0, 0xEE72, 0, 0x7678, 0, 0xEE6D, 0,
+ 0x5E62, 0, 0x5E5D, 0xC76F, 0xEE73, 0, 0x5E55, 0,
+};
+static const unsigned short utf8_to_euc_E6B9[] = {
+ 0, 0, 0, 0x5E5C, 0xC771, 0xC772, 0, 0,
+ 0xC773, 0xC774, 0x4C2B, 0xC775, 0, 0x5E5A, 0x5E5E, 0xC776,
+ 0, 0xC777, 0xC778, 0xC779, 0xC77A, 0, 0x3850, 0xC77B,
+ 0x3E45, 0, 0, 0x4339, 0xC77C, 0xC77D, 0xC77E, 0x5E54,
+ 0, 0, 0xC821, 0xC822, 0, 0, 0, 0x4D2F,
+ 0xC823, 0, 0, 0x5E57, 0, 0, 0x5E50, 0x4572,
+ 0, 0, 0x5E53, 0xC824, 0, 0, 0x5E59, 0,
+ 0, 0, 0, 0xC825, 0, 0xC826, 0x4F51, 0x3C3E,
+};
+static const unsigned short utf8_to_euc_E6B9_x0213[] = {
+ 0, 0, 0, 0x5E5C, 0x7679, 0xC772, 0, 0,
+ 0xEE74, 0xEE75, 0x4C2B, 0xEE76, 0xEE77, 0x5E5A, 0x5E5E, 0xEE78,
+ 0, 0xEE79, 0xC778, 0xEE7A, 0xEE7B, 0, 0x3850, 0xEE7C,
+ 0x3E45, 0, 0, 0x4339, 0x767A, 0xC77D, 0x767B, 0x5E54,
+ 0, 0, 0xC821, 0xEE7D, 0, 0, 0, 0x4D2F,
+ 0xC823, 0, 0, 0x5E57, 0, 0, 0x5E50, 0x4572,
+ 0, 0, 0x5E53, 0xC824, 0, 0, 0x5E59, 0,
+ 0, 0, 0, 0xC825, 0, 0xC826, 0x4F51, 0x3C3E,
+};
+static const unsigned short utf8_to_euc_E6BA[] = {
+ 0x4B7E, 0, 0x5E63, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x482E, 0xC827, 0, 0x5E6F,
+ 0x383B, 0, 0, 0xC828, 0, 0, 0x3D60, 0,
+ 0x5E65, 0xC829, 0, 0, 0x4E2F, 0x3942, 0, 0x5E72,
+ 0xC82A, 0, 0x306E, 0, 0, 0x5E70, 0, 0xC82B,
+ 0, 0, 0x5E64, 0, 0, 0xC82C, 0xC82D, 0x5E6A,
+ 0, 0xC82E, 0x5E6C, 0xC82F, 0, 0, 0x4D4F, 0x5E67,
+ 0, 0, 0x452E, 0xC830, 0, 0x5E69, 0, 0xC831,
+};
+static const unsigned short utf8_to_euc_E6BA_x0213[] = {
+ 0x4B7E, 0, 0x5E63, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x482E, 0xC827, 0, 0x5E6F,
+ 0x383B, 0, 0, 0xEF21, 0, 0, 0x3D60, 0,
+ 0x5E65, 0xC829, 0, 0, 0x4E2F, 0x3942, 0, 0x5E72,
+ 0xC82A, 0, 0x306E, 0, 0, 0x5E70, 0, 0xEF22,
+ 0, 0, 0x5E64, 0x767C, 0, 0xC82C, 0xC82D, 0x5E6A,
+ 0, 0x767D, 0x5E6C, 0xC82F, 0xEF23, 0, 0x4D4F, 0x5E67,
+ 0, 0, 0x452E, 0xC830, 0, 0x5E69, 0, 0xEF24,
+};
+static const unsigned short utf8_to_euc_E6BB[] = {
+ 0xC832, 0xC833, 0x5E71, 0xC834, 0x5E6B, 0x4C47, 0, 0xC835,
+ 0xC836, 0x5E66, 0xC837, 0x3C22, 0x5E7E, 0xC838, 0xC839, 0xC83A,
+ 0, 0x336A, 0, 0x5E68, 0x5E6D, 0x5E6E, 0, 0,
+ 0, 0, 0, 0, 0, 0x426C, 0x425A, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xC83B, 0x5E76, 0xC83C, 0xC83D, 0x5E7C,
+ 0, 0, 0x5E7A, 0, 0x4529, 0, 0, 0x5F23,
+ 0x5E77, 0xC83E, 0, 0xC83F, 0, 0xC840, 0x5E78, 0x5E60,
+};
+static const unsigned short utf8_to_euc_E6BB_x0213[] = {
+ 0xC832, 0x767E, 0x5E71, 0xEF25, 0x5E6B, 0x4C47, 0, 0x7721,
+ 0xC836, 0x5E66, 0xEF26, 0x3C22, 0x5E7E, 0xC838, 0x7722, 0xC83A,
+ 0, 0x336A, 0, 0x5E68, 0x5E6D, 0x5E6E, 0, 0,
+ 0, 0xEF27, 0, 0, 0, 0x426C, 0x425A, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xEF29, 0x5E76, 0xC83C, 0xC83D, 0x5E7C,
+ 0, 0, 0x5E7A, 0, 0x4529, 0, 0, 0x5F23,
+ 0x5E77, 0xEF2A, 0, 0xEF2B, 0, 0xC840, 0x5E78, 0x5E60,
+};
+static const unsigned short utf8_to_euc_E6BC[] = {
+ 0, 0x3579, 0x493A, 0, 0xC841, 0, 0x3C3F, 0,
+ 0xC842, 0x3977, 0xC843, 0, 0xC844, 0xC845, 0, 0x4F33,
+ 0, 0x5E74, 0, 0x5F22, 0x3169, 0x4166, 0xC846, 0,
+ 0xC847, 0, 0xC848, 0xC849, 0, 0, 0, 0,
+ 0x4779, 0, 0x3441, 0x4E7A, 0, 0, 0xC84A, 0,
+ 0, 0xC84B, 0xC84C, 0x4C21, 0x4452, 0xC853, 0, 0xC84D,
+ 0xC84E, 0x5E7B, 0x5E7D, 0xC84F, 0, 0, 0xC850, 0,
+ 0x4132, 0, 0, 0xC851, 0xC852, 0, 0x5F21, 0x5E79,
+};
+static const unsigned short utf8_to_euc_E6BC_x0213[] = {
+ 0, 0x3579, 0x493A, 0, 0xC841, 0, 0x3C3F, 0,
+ 0xC842, 0x3977, 0xEF2C, 0, 0xEF2D, 0xC845, 0, 0x4F33,
+ 0x7723, 0x5E74, 0, 0x5F22, 0x3169, 0x4166, 0xC846, 0,
+ 0xEF2E, 0, 0x7724, 0xC849, 0, 0, 0, 0,
+ 0x4779, 0, 0x3441, 0x4E7A, 0, 0xEF2F, 0xC84A, 0,
+ 0, 0xC84B, 0x7726, 0x4C21, 0x4452, 0xC853, 0, 0x7727,
+ 0xC84E, 0x5E7B, 0x5E7D, 0x7728, 0, 0xEF28, 0xEF30, 0,
+ 0x4132, 0, 0, 0xC851, 0xEF31, 0, 0x5F21, 0x5E79,
+};
+static const unsigned short utf8_to_euc_E6BD[] = {
+ 0, 0x5E73, 0, 0, 0, 0x3443, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xC854,
+ 0, 0xC855, 0xC856, 0xC857, 0x3769, 0, 0, 0xC858,
+ 0x5F2F, 0xC859, 0xC85A, 0x5F2A, 0x4078, 0xC85B, 0xC85C, 0x3363,
+ 0, 0xC85D, 0xC85E, 0, 0x3D61, 0, 0x5F33, 0,
+ 0xC85F, 0, 0, 0, 0xC860, 0x5F2C, 0x442C, 0x5F29,
+ 0x4459, 0, 0, 0, 0x5F4C, 0, 0, 0,
+ 0x5F26, 0, 0x5F25, 0, 0x5F2E, 0xC861, 0xC862, 0,
+};
+static const unsigned short utf8_to_euc_E6BD_x0213[] = {
+ 0, 0x5E73, 0, 0, 0, 0x3443, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xC854,
+ 0, 0x7729, 0xEF33, 0xC857, 0x3769, 0, 0, 0xEF34,
+ 0x5F2F, 0x772A, 0xEF35, 0x5F2A, 0x4078, 0xC85B, 0x772B, 0x3363,
+ 0xEF36, 0x772C, 0x772D, 0, 0x3D61, 0, 0x5F33, 0,
+ 0xEF37, 0, 0, 0, 0xC860, 0x5F2C, 0x442C, 0x5F29,
+ 0x4459, 0, 0, 0, 0x5F4C, 0, 0, 0,
+ 0x5F26, 0, 0x5F25, 0, 0x5F2E, 0xEF39, 0x772E, 0,
+};
+static const unsigned short utf8_to_euc_E6BE[] = {
+ 0x5F28, 0x5F27, 0x5F2D, 0xC863, 0x4021, 0, 0x5F24, 0xC864,
+ 0xC865, 0, 0, 0xC866, 0xC867, 0xC868, 0x5F30, 0,
+ 0xC869, 0x5F31, 0xC86A, 0xC86B, 0xC86C, 0, 0xC86D, 0x3442,
+ 0, 0, 0xC86E, 0, 0, 0, 0, 0xC86F,
+ 0xC870, 0x5F36, 0, 0x5F35, 0x5F37, 0xC871, 0xC872, 0xC873,
+ 0xC874, 0, 0x5F3A, 0, 0, 0, 0xC875, 0xC876,
+ 0xC877, 0x4543, 0, 0x5F34, 0, 0xC878, 0xC879, 0,
+ 0, 0x5F38, 0, 0, 0xC87A, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E6BE_x0213[] = {
+ 0x5F28, 0x5F27, 0x5F2D, 0xC863, 0x4021, 0, 0x5F24, 0xC864,
+ 0x772F, 0, 0, 0xC866, 0x7730, 0x7731, 0x5F30, 0,
+ 0xEF3A, 0x5F31, 0xC86A, 0xC86B, 0x7732, 0, 0xEF3B, 0x3442,
+ 0xEF38, 0, 0xC86E, 0, 0, 0, 0, 0xEF3D,
+ 0x7733, 0x5F36, 0, 0x5F35, 0x5F37, 0xEF3E, 0xC872, 0x7734,
+ 0xC874, 0, 0x5F3A, 0, 0, 0, 0xC875, 0xEF3F,
+ 0xC877, 0x4543, 0, 0x5F34, 0, 0xEF41, 0x7735, 0,
+ 0, 0x5F38, 0, 0, 0x7736, 0, 0xEF3C, 0,
+};
+static const unsigned short utf8_to_euc_E6BF[] = {
+ 0x3763, 0x4279, 0x5F32, 0x473B, 0, 0xC87B, 0x5F39, 0xC87C,
+ 0xC87D, 0, 0xC87E, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x5F3E, 0x5F3C, 0, 0,
+ 0x5F3F, 0, 0xC921, 0x5F42, 0, 0, 0xC922, 0x5F3B,
+ 0x396A, 0x4728, 0, 0, 0x5E39, 0, 0, 0,
+ 0xC923, 0xC924, 0, 0x4D74, 0x5F3D, 0, 0x5F41, 0x4275,
+ 0xC925, 0x5F40, 0, 0x5F2B, 0, 0xC926, 0x6F69, 0,
+ 0, 0xC927, 0x5F45, 0, 0xC928, 0xC929, 0x5F49, 0,
+};
+static const unsigned short utf8_to_euc_E6BF_x0213[] = {
+ 0x3763, 0x4279, 0x5F32, 0x473B, 0, 0xC87B, 0x5F39, 0x7737,
+ 0xEF42, 0xEF43, 0x7738, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x5F3E, 0x5F3C, 0, 0,
+ 0x5F3F, 0, 0xEF44, 0x5F42, 0, 0, 0xEF45, 0x5F3B,
+ 0x396A, 0x4728, 0, 0, 0x5E39, 0, 0, 0,
+ 0xC923, 0xEF46, 0, 0x4D74, 0x5F3D, 0, 0x5F41, 0x4275,
+ 0x773A, 0x5F40, 0, 0x5F2B, 0, 0x773B, 0x6F69, 0,
+ 0, 0x7739, 0x5F45, 0, 0xEF48, 0xC929, 0x5F49, 0,
+};
+static const unsigned short utf8_to_euc_E780[] = {
+ 0xC92A, 0x5F47, 0, 0, 0, 0xC92B, 0xC92C, 0xC92D,
+ 0, 0x5F43, 0, 0x5F44, 0, 0xC92E, 0, 0x5F48,
+ 0, 0x5F46, 0, 0, 0, 0x494E, 0, 0xC92F,
+ 0x5F4E, 0, 0x5F4B, 0x5F4A, 0, 0x5F4D, 0x4654, 0x5F4F,
+ 0xC930, 0, 0, 0xC931, 0, 0, 0x4375, 0x426D,
+ 0xF44D, 0, 0, 0, 0x4025, 0, 0, 0xC932,
+ 0x5F50, 0, 0x5F52, 0, 0xC933, 0, 0, 0xC934,
+ 0, 0xC935, 0, 0, 0xC936, 0, 0x5F51, 0,
+};
+static const unsigned short utf8_to_euc_E780_x0213[] = {
+ 0xEF49, 0x5F47, 0, 0, 0, 0x773C, 0x773D, 0xEF4A,
+ 0, 0x5F43, 0xEF4B, 0x5F44, 0, 0xC92E, 0, 0x5F48,
+ 0, 0x5F46, 0, 0, 0, 0x494E, 0, 0xC92F,
+ 0x5F4E, 0, 0x5F4B, 0x5F4A, 0, 0x5F4D, 0x4654, 0x5F4F,
+ 0xC930, 0, 0, 0xEF4C, 0, 0, 0x4375, 0x426D,
+ 0x773E, 0, 0, 0, 0x4025, 0, 0, 0xC932,
+ 0x5F50, 0, 0x5F52, 0, 0xC933, 0, 0, 0xC934,
+ 0, 0xEF4E, 0xEF4F, 0, 0xEF50, 0, 0x5F51, 0,
+};
+static const unsigned short utf8_to_euc_E781[] = {
+ 0, 0, 0, 0xC937, 0xC938, 0, 0, 0,
+ 0xC939, 0xC93A, 0xC93B, 0xC93C, 0x5E75, 0, 0xC941, 0,
+ 0, 0x5F53, 0, 0, 0xC93D, 0xC93E, 0, 0,
+ 0x4667, 0, 0, 0, 0, 0xC93F, 0xC940, 0,
+ 0, 0, 0, 0x5F54, 0xC942, 0xC943, 0, 0,
+ 0, 0, 0, 0x3250, 0xC944, 0, 0xC945, 0x4574,
+ 0x3325, 0, 0, 0, 0, 0xC946, 0xC947, 0,
+ 0x3564, 0, 0, 0, 0x3C5E, 0x3A52, 0xC948, 0,
+};
+static const unsigned short utf8_to_euc_E781_x0213[] = {
+ 0, 0, 0, 0xEF51, 0xC938, 0, 0, 0xEF52,
+ 0xC939, 0xC93A, 0x773F, 0xEF53, 0x5E75, 0, 0x7742, 0,
+ 0, 0x5F53, 0, 0, 0xEF55, 0xC93E, 0, 0,
+ 0x4667, 0, 0, 0, 0, 0x7740, 0x7741, 0,
+ 0, 0, 0, 0x5F54, 0x7743, 0xEF56, 0, 0,
+ 0, 0xEF57, 0, 0x3250, 0xEF58, 0, 0xEF59, 0x4574,
+ 0x3325, 0, 0, 0, 0, 0x7744, 0xEF5A, 0,
+ 0x3564, 0, 0, 0, 0x3C5E, 0x3A52, 0xEF5B, 0,
+};
+static const unsigned short utf8_to_euc_E782[] = {
+ 0, 0xC949, 0, 0, 0, 0xC94A, 0xC94B, 0,
+ 0, 0x4F27, 0x3F66, 0, 0, 0, 0x316A, 0,
+ 0, 0, 0x5F56, 0, 0xC94C, 0xC94D, 0xC94E, 0xC94F,
+ 0xC950, 0x5F55, 0, 0xC951, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xC952, 0, 0, 0,
+ 0, 0, 0, 0xC953, 0x5F59, 0x433A, 0x5F5C, 0x5F57,
+ 0xC954, 0xC955, 0, 0x5F5B, 0xC956, 0, 0, 0xC957,
+ 0x5F5A, 0x4540, 0x3059, 0xF42E, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E782_x0213[] = {
+ 0, 0xEF5C, 0, 0, 0, 0x7745, 0xEF5D, 0,
+ 0, 0x4F27, 0x3F66, 0, 0, 0, 0x316A, 0,
+ 0, 0, 0x5F56, 0, 0xC94C, 0xEF5E, 0xC94E, 0xEF5F,
+ 0xC950, 0x5F55, 0, 0xC951, 0, 0, 0, 0xEF62,
+ 0, 0, 0, 0, 0x7746, 0, 0, 0,
+ 0, 0, 0, 0x7747, 0x5F59, 0x433A, 0x5F5C, 0x5F57,
+ 0xC954, 0xEF63, 0, 0x5F5B, 0xC956, 0, 0, 0x7748,
+ 0x5F5A, 0x4540, 0x3059, 0xEF60, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E783[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x4E75, 0, 0xC958, 0x5F5E, 0, 0, 0, 0x3128,
+ 0, 0xC959, 0, 0xC95A, 0xC95B, 0xC95C, 0xC95D, 0,
+ 0xC95E, 0x5F60, 0, 0, 0xC95F, 0x5F5F, 0, 0x5F5D,
+ 0, 0, 0, 0, 0xC960, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x5F58, 0, 0, 0, 0, 0, 0,
+ 0, 0x4B23, 0xC961, 0, 0, 0x5F62, 0, 0,
+};
+static const unsigned short utf8_to_euc_E783_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x4E75, 0, 0xEF66, 0x5F5E, 0, 0, 0, 0x3128,
+ 0, 0xEF67, 0, 0xEF68, 0x7749, 0xC95C, 0xC95D, 0,
+ 0x774A, 0x5F60, 0, 0, 0xEF69, 0x5F5F, 0, 0x5F5D,
+ 0, 0, 0, 0, 0x774B, 0, 0, 0,
+ 0, 0, 0, 0, 0xEF65, 0, 0, 0,
+ 0, 0x5F58, 0, 0, 0, 0, 0, 0,
+ 0, 0x4B23, 0xC961, 0, 0, 0x5F62, 0, 0,
+};
+static const unsigned short utf8_to_euc_E784[] = {
+ 0, 0, 0, 0xC962, 0xC963, 0xC964, 0xC965, 0xC966,
+ 0, 0x5F61, 0, 0xC967, 0xC968, 0, 0, 0xC969,
+ 0, 0, 0, 0, 0x316B, 0, 0, 0,
+ 0, 0x5F64, 0x4A32, 0, 0x5F63, 0, 0xC96A, 0,
+ 0xC96B, 0x4C35, 0, 0, 0, 0, 0x3E47, 0,
+ 0, 0, 0, 0xC96C, 0, 0xC96D, 0, 0xC96E,
+ 0xC96F, 0xC970, 0, 0, 0, 0, 0x4133, 0,
+ 0xC971, 0, 0, 0, 0x3E46, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E784_x0213[] = {
+ 0, 0, 0, 0xEF6A, 0xEF6B, 0xC964, 0xEF6C, 0xEF6D,
+ 0xEF6E, 0x5F61, 0, 0xC967, 0xEF6F, 0, 0, 0x774C,
+ 0, 0, 0, 0, 0x316B, 0, 0, 0,
+ 0, 0x5F64, 0x4A32, 0, 0x5F63, 0, 0x774E, 0,
+ 0x774F, 0x4C35, 0, 0, 0, 0, 0x3E47, 0,
+ 0, 0, 0, 0x774D, 0, 0xC96D, 0x7750, 0xEF71,
+ 0x7751, 0xEF72, 0, 0, 0, 0, 0x4133, 0,
+ 0xC971, 0, 0, 0, 0x3E46, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E785[] = {
+ 0, 0xC972, 0, 0, 0, 0xC973, 0xC974, 0xC975,
+ 0, 0x4E7B, 0xC976, 0xC977, 0x5F6A, 0, 0x4079, 0,
+ 0xC978, 0, 0xC979, 0, 0, 0x5F66, 0x5F6B, 0xC97A,
+ 0, 0x316C, 0xC97B, 0, 0xC97C, 0, 0xC97D, 0,
+ 0xC97E, 0, 0x5F69, 0, 0x4761, 0x5F65, 0x5F68, 0x3E48,
+ 0xCA21, 0x4851, 0, 0, 0x5F6C, 0, 0x3C51, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xCA22, 0, 0, 0, 0x407A, 0, 0,
+};
+static const unsigned short utf8_to_euc_E785_x0213[] = {
+ 0, 0xC972, 0, 0, 0, 0xC973, 0x7752, 0x7753,
+ 0, 0x4E7B, 0xEF74, 0xC977, 0x5F6A, 0, 0x4079, 0,
+ 0xEF73, 0x7754, 0x7756, 0xEF75, 0, 0x5F66, 0x5F6B, 0xC97A,
+ 0, 0x316C, 0xC97B, 0, 0x7757, 0, 0xEF76, 0,
+ 0x7758, 0, 0x5F69, 0, 0x4761, 0x5F65, 0x5F68, 0x3E48,
+ 0x7759, 0x4851, 0, 0, 0x5F6C, 0, 0x3C51, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xCA22, 0, 0, 0, 0x407A, 0, 0,
+};
+static const unsigned short utf8_to_euc_E786[] = {
+ 0xCA23, 0, 0, 0, 0x5F6F, 0xCA24, 0, 0xCA25,
+ 0x5F67, 0, 0x3727, 0, 0xCA26, 0, 0, 0x5F6D,
+ 0, 0, 0xCA27, 0, 0x4D50, 0x5F70, 0, 0,
+ 0, 0x7426, 0xCA28, 0xCA29, 0, 0, 0, 0x3D4F,
+ 0xCA2A, 0, 0xCA2B, 0, 0, 0, 0, 0,
+ 0x5F71, 0, 0, 0, 0x5F72, 0, 0, 0xCA2C,
+ 0xCA2D, 0x472E, 0xCA2E, 0xCA2F, 0, 0, 0, 0,
+ 0, 0x5F74, 0xCA30, 0, 0, 0, 0x5F75, 0xCA31,
+};
+static const unsigned short utf8_to_euc_E786_x0213[] = {
+ 0xEF79, 0, 0, 0, 0x5F6F, 0x775B, 0, 0x775C,
+ 0x5F67, 0, 0x3727, 0, 0xCA26, 0, 0, 0x5F6D,
+ 0, 0, 0x775D, 0, 0x4D50, 0x5F70, 0xEF78, 0,
+ 0, 0x7426, 0xCA28, 0xEF7A, 0, 0, 0, 0x3D4F,
+ 0xEF7B, 0, 0xEF7C, 0, 0, 0, 0, 0,
+ 0x5F71, 0, 0, 0, 0x5F72, 0, 0xEF7D, 0xEF7E,
+ 0xCA2D, 0x472E, 0xCA2E, 0xF021, 0, 0, 0, 0,
+ 0, 0x5F74, 0x775F, 0, 0, 0, 0x5F75, 0xCA31,
+};
+static const unsigned short utf8_to_euc_E787[] = {
+ 0xCA32, 0xCA33, 0, 0x4733, 0xCA34, 0, 0, 0,
+ 0x4575, 0x5F77, 0, 0xCA35, 0xCA36, 0, 0x5F79, 0,
+ 0x4E55, 0, 0x5F76, 0xCA37, 0x5F78, 0x316D, 0xCA38, 0x5F73,
+ 0, 0xCA39, 0xCA3A, 0, 0xCA3B, 0, 0, 0x535B,
+ 0x5F7A, 0, 0, 0, 0, 0x4167, 0x3B38, 0x5F7C,
+ 0, 0, 0, 0, 0x5F7B, 0x3F24, 0x5259, 0,
+ 0, 0, 0, 0, 0, 0x5F7D, 0, 0,
+ 0xCA3C, 0x6021, 0, 0x5F6E, 0x5F7E, 0, 0xCA3D, 0x6022,
+};
+static const unsigned short utf8_to_euc_E787_x0213[] = {
+ 0xCA32, 0x775E, 0, 0x4733, 0x7760, 0, 0, 0,
+ 0x4575, 0x5F77, 0, 0xF023, 0xCA36, 0, 0x5F79, 0,
+ 0x4E55, 0, 0x5F76, 0xF024, 0x5F78, 0x316D, 0xCA38, 0x5F73,
+ 0, 0xF025, 0xCA3A, 0, 0xF026, 0, 0, 0x535B,
+ 0x5F7A, 0, 0, 0, 0, 0x4167, 0x3B38, 0x5F7C,
+ 0, 0, 0, 0, 0x5F7B, 0x3F24, 0x5259, 0,
+ 0, 0, 0, 0, 0, 0x5F7D, 0, 0,
+ 0xCA3C, 0x6021, 0, 0x5F6E, 0x5F7E, 0, 0x7761, 0x6022,
+};
+static const unsigned short utf8_to_euc_E788[] = {
+ 0xCA3E, 0, 0, 0, 0, 0, 0x477A, 0xCA3F,
+ 0xCA40, 0xCA41, 0, 0, 0, 0x6023, 0, 0,
+ 0x6024, 0, 0, 0xCA42, 0, 0, 0, 0xCA43,
+ 0, 0, 0xCA44, 0x6025, 0, 0xCA45, 0, 0xCA46,
+ 0, 0, 0, 0, 0xCA47, 0, 0, 0,
+ 0x6026, 0, 0x445E, 0xCA48, 0x6028, 0x6027, 0, 0xCA49,
+ 0x6029, 0, 0x602A, 0, 0xCA4A, 0x3C5F, 0x4963, 0,
+ 0xCA4B, 0xCA4C, 0x4C6C, 0x602B, 0x602C, 0x4156, 0x3C24, 0x602D,
+};
+static const unsigned short utf8_to_euc_E788_x0213[] = {
+ 0x7762, 0, 0, 0, 0, 0, 0x477A, 0xF027,
+ 0xCA40, 0xCA41, 0, 0, 0, 0x6023, 0, 0,
+ 0x6024, 0, 0, 0xCA42, 0, 0x7763, 0, 0xCA43,
+ 0, 0, 0xCA44, 0x6025, 0, 0xCA45, 0, 0xCA46,
+ 0, 0, 0, 0, 0xCA47, 0, 0, 0,
+ 0x6026, 0, 0x445E, 0xF02A, 0x6028, 0x6027, 0, 0xCA49,
+ 0x6029, 0, 0x602A, 0, 0xF02B, 0x3C5F, 0x4963, 0,
+ 0xF02C, 0xF02D, 0x4C6C, 0x602B, 0x602C, 0x4156, 0x3C24, 0x602D,
+};
+static const unsigned short utf8_to_euc_E789[] = {
+ 0x602E, 0xCA4D, 0xCA4E, 0xCA4F, 0, 0xCA50, 0x602F, 0x4A52,
+ 0x4847, 0, 0, 0x6030, 0x4757, 0, 0xCA51, 0xCA52,
+ 0xCA53, 0, 0x442D, 0xCA54, 0, 0xCA55, 0xCA56, 0,
+ 0x6031, 0x3267, 0xCA57, 0x356D, 0xCA58, 0x4C46, 0xCA59, 0x4C36,
+ 0xCA5A, 0x3234, 0x4F34, 0xCA5B, 0, 0, 0, 0x4B52,
+ 0xCA5C, 0x4A2A, 0, 0xCA5D, 0, 0, 0xCA5E, 0xCA5F,
+ 0, 0xCA60, 0x4037, 0, 0x6032, 0, 0, 0xCA61,
+ 0xCA62, 0x4643, 0, 0xCA63, 0xCA64, 0x3823, 0x6033, 0xCA65,
+};
+static const unsigned short utf8_to_euc_E789_x0213[] = {
+ 0x602E, 0xCA4D, 0xF02F, 0xCA4F, 0, 0xCA50, 0x602F, 0x4A52,
+ 0x4847, 0, 0, 0x6030, 0x4757, 0, 0xCA51, 0xCA52,
+ 0xCA53, 0, 0x442D, 0xF030, 0, 0x7764, 0x7765, 0xF031,
+ 0x6031, 0x3267, 0xCA57, 0x356D, 0xCA58, 0x4C46, 0xCA59, 0x4C36,
+ 0xCA5A, 0x3234, 0x4F34, 0xF032, 0, 0, 0, 0x4B52,
+ 0xCA5C, 0x4A2A, 0, 0xCA5D, 0, 0, 0xF034, 0xF035,
+ 0, 0xCA60, 0x4037, 0, 0x6032, 0, 0, 0xCA61,
+ 0xF036, 0x4643, 0, 0xCA63, 0xCA64, 0x3823, 0x6033, 0xF037,
+};
+static const unsigned short utf8_to_euc_E78A[] = {
+ 0x3A54, 0x6035, 0x6034, 0, 0xCA66, 0, 0, 0x6036,
+ 0, 0xCA67, 0, 0, 0, 0xCA68, 0xCA69, 0,
+ 0, 0, 0x6037, 0xCA6A, 0, 0, 0x6038, 0,
+ 0, 0, 0, 0xCA6B, 0, 0, 0, 0,
+ 0x353E, 0, 0x6039, 0, 0, 0, 0, 0x603A,
+ 0xCA6C, 0, 0, 0, 0x3824, 0xCA6D, 0xCA6E, 0x4848,
+ 0, 0xCA6F, 0x603C, 0, 0xCA70, 0, 0x3E75, 0,
+ 0, 0x603B, 0, 0, 0, 0, 0xCA71, 0,
+};
+static const unsigned short utf8_to_euc_E78A_x0213[] = {
+ 0x3A54, 0x6035, 0x6034, 0, 0xCA66, 0, 0, 0x6036,
+ 0, 0xCA67, 0, 0, 0, 0x7767, 0xF038, 0,
+ 0, 0, 0x6037, 0xCA6A, 0, 0, 0x6038, 0,
+ 0, 0, 0, 0x7768, 0, 0, 0, 0,
+ 0x353E, 0, 0x6039, 0, 0, 0, 0, 0x603A,
+ 0xCA6C, 0, 0, 0, 0x3824, 0xF03A, 0xF03B, 0x4848,
+ 0xF03C, 0xF03D, 0x603C, 0, 0xCA70, 0, 0x3E75, 0,
+ 0, 0x603B, 0, 0, 0, 0, 0x7769, 0,
+};
+static const unsigned short utf8_to_euc_E78B[] = {
+ 0, 0xCA72, 0x3638, 0x603D, 0x603F, 0, 0x603E, 0xCA73,
+ 0, 0xCA74, 0, 0, 0xCA75, 0, 0x6040, 0,
+ 0x3851, 0, 0x6041, 0, 0, 0xCA76, 0xCA77, 0x3669,
+ 0xCA78, 0x4140, 0, 0x397D, 0, 0, 0, 0xCA79,
+ 0x6043, 0x6044, 0x6042, 0, 0, 0xCA7A, 0, 0,
+ 0, 0x3C6D, 0, 0, 0x4648, 0x3639, 0, 0,
+ 0, 0, 0, 0xCA7B, 0xCA7C, 0, 0, 0x6046,
+ 0x432C, 0x6045, 0xCA7D, 0xCA7E, 0x4F35, 0x4762, 0xCB21, 0,
+};
+static const unsigned short utf8_to_euc_E78B_x0213[] = {
+ 0x776A, 0xF03E, 0x3638, 0x603D, 0x603F, 0, 0x603E, 0xCA73,
+ 0, 0xCA74, 0, 0, 0xF040, 0, 0x6040, 0,
+ 0x3851, 0, 0x6041, 0, 0, 0xCA76, 0xCA77, 0x3669,
+ 0xCA78, 0x4140, 0, 0x397D, 0, 0, 0, 0xCA79,
+ 0x6043, 0x6044, 0x6042, 0, 0, 0xCA7A, 0, 0,
+ 0, 0x3C6D, 0, 0, 0x4648, 0x3639, 0, 0,
+ 0, 0, 0, 0xF043, 0xCA7C, 0, 0, 0x6046,
+ 0x432C, 0x6045, 0xF044, 0x776B, 0x4F35, 0x4762, 0xCB21, 0,
+};
+static const unsigned short utf8_to_euc_E78C[] = {
+ 0, 0, 0xCB22, 0, 0xCB23, 0xCB24, 0, 0xCB25,
+ 0, 0, 0x6049, 0xCB26, 0, 0xCB27, 0, 0,
+ 0, 0, 0xCB28, 0xCB29, 0, 0, 0x604B, 0x6048,
+ 0xCB2A, 0xCB2B, 0, 0x4C54, 0x604A, 0x604C, 0xCB2C, 0x4E44,
+ 0, 0, 0xCB2D, 0, 0xCB2E, 0x6050, 0, 0xCB2F,
+ 0xCB30, 0x604F, 0x4376, 0x472D, 0xCB31, 0, 0x3825, 0x604E,
+ 0, 0xCB32, 0xCB33, 0, 0x604D, 0xCB34, 0x4D31, 0x4D32,
+ 0, 0, 0xCB35, 0xCB36, 0, 0xCB37, 0x6051, 0x316E,
+};
+static const unsigned short utf8_to_euc_E78C_x0213[] = {
+ 0, 0, 0xCB22, 0, 0xCB23, 0xCB24, 0, 0xF045,
+ 0, 0, 0x6049, 0xCB26, 0, 0xCB27, 0, 0,
+ 0, 0, 0xF046, 0xCB29, 0, 0, 0x604B, 0x6048,
+ 0xF047, 0xF048, 0, 0x4C54, 0x604A, 0x604C, 0xCB2C, 0x4E44,
+ 0, 0, 0xCB2D, 0, 0, 0x6050, 0, 0x776D,
+ 0x776E, 0x604F, 0x4376, 0x472D, 0xF04B, 0, 0x3825, 0x604E,
+ 0, 0xF04C, 0xCB33, 0xF04D, 0x604D, 0xCB34, 0x4D31, 0x4D32,
+ 0, 0xF04A, 0xCB35, 0xCB36, 0, 0xF04E, 0x6051, 0x316E,
+};
+static const unsigned short utf8_to_euc_E78D[] = {
+ 0, 0, 0, 0xCB38, 0x3976, 0x3B62, 0, 0,
+ 0, 0, 0, 0, 0, 0xCB39, 0x6052, 0x6053,
+ 0xCB3A, 0, 0xCB3B, 0, 0, 0, 0xCB3C, 0x6055,
+ 0xCB3D, 0, 0, 0, 0, 0xCB3E, 0xCB3F, 0xCB40,
+ 0xCB41, 0, 0, 0x3D43, 0, 0, 0xCB42, 0xCB43,
+ 0x6057, 0xCB44, 0x6056, 0xCB45, 0xCB46, 0, 0xCB47, 0xCB48,
+ 0x6058, 0xCB49, 0x334D, 0, 0, 0x605A, 0, 0xCB4A,
+ 0x6059, 0xCB4B, 0x605C, 0x605B, 0xCB4C, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E78D_x0213[] = {
+ 0, 0, 0, 0xCB38, 0x3976, 0x3B62, 0, 0,
+ 0, 0, 0, 0, 0, 0xCB39, 0x6052, 0x6053,
+ 0x7770, 0, 0xF04F, 0, 0, 0, 0xCB3C, 0x6055,
+ 0xCB3D, 0, 0, 0, 0, 0xCB3E, 0xCB3F, 0xCB40,
+ 0xCB41, 0, 0, 0x3D43, 0, 0, 0x7771, 0xCB43,
+ 0x6057, 0xCB44, 0x6056, 0xF051, 0xF052, 0, 0xF054, 0xF055,
+ 0x6058, 0xF056, 0x334D, 0, 0, 0x605A, 0, 0xF057,
+ 0x6059, 0xCB4B, 0x605C, 0x605B, 0x7772, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E78E[] = {
+ 0xCB4D, 0xCB4E, 0, 0xCB4F, 0x383C, 0xCB50, 0xCB51, 0x4E28,
+ 0, 0x364C, 0, 0x3226, 0, 0, 0xCB52, 0,
+ 0xCB53, 0, 0, 0xCB54, 0, 0xCB55, 0x366A, 0xCB56,
+ 0xCB57, 0, 0, 0, 0xCB58, 0, 0xCB59, 0xCB5A,
+ 0xCB5B, 0, 0xCB5C, 0, 0, 0xCB5D, 0xCB5E, 0,
+ 0, 0x3461, 0xCB5F, 0xCB60, 0, 0xCB61, 0, 0,
+ 0, 0, 0x4E68, 0x605E, 0, 0xCB62, 0, 0xCB63,
+ 0, 0xCB64, 0, 0x6060, 0xCB65, 0xCB66, 0, 0xCB67,
+};
+static const unsigned short utf8_to_euc_E78E_x0213[] = {
+ 0xCB4D, 0xF058, 0, 0xCB4F, 0x383C, 0xF059, 0xCB51, 0x4E28,
+ 0, 0x364C, 0xF05A, 0x3226, 0, 0, 0xCB52, 0,
+ 0xCB53, 0, 0, 0xCB54, 0xF05B, 0x7773, 0x366A, 0xCB56,
+ 0xF05C, 0, 0, 0, 0xF05D, 0, 0xF05E, 0x7774,
+ 0x7775, 0, 0x7776, 0, 0, 0xF05F, 0x7777, 0,
+ 0xF060, 0x3461, 0xCB5F, 0x7778, 0, 0xCB61, 0, 0,
+ 0, 0, 0x4E68, 0x605E, 0, 0xF061, 0, 0xF062,
+ 0, 0xF063, 0, 0x6060, 0xF064, 0, 0, 0xF065,
+};
+static const unsigned short utf8_to_euc_E78F[] = {
+ 0x6061, 0, 0x3251, 0, 0, 0xCB68, 0xCB69, 0,
+ 0x605D, 0xCB6A, 0x3B39, 0xCB6B, 0xCB6C, 0x4441, 0x605F, 0xCB6D,
+ 0, 0, 0xCB6E, 0xCB6F, 0, 0, 0xCB70, 0,
+ 0, 0xCB71, 0, 0, 0, 0xCB72, 0x6064, 0,
+ 0x3C6E, 0xCB73, 0, 0xCB74, 0, 0x6062, 0xCB75, 0xCB76,
+ 0, 0xCB77, 0x373E, 0, 0, 0x4849, 0x6063, 0,
+ 0, 0x607E, 0, 0, 0xCB78, 0xCB79, 0, 0xCB7A,
+ 0x6069, 0xCB7B, 0xCB7C, 0xCB7D, 0, 0xCB7E, 0x383D, 0xCC21,
+};
+static const unsigned short utf8_to_euc_E78F_x0213[] = {
+ 0x6061, 0, 0x3251, 0, 0, 0xF066, 0xCB69, 0,
+ 0x605D, 0x7779, 0x3B39, 0xF067, 0xCB6C, 0x4441, 0x605F, 0x777A,
+ 0, 0, 0, 0xCB6F, 0, 0, 0x777B, 0,
+ 0, 0x777C, 0, 0, 0, 0xCB72, 0x6064, 0,
+ 0x3C6E, 0xF068, 0, 0x777D, 0, 0x6062, 0xCB75, 0xF069,
+ 0, 0x777E, 0x373E, 0, 0, 0x4849, 0x6063, 0,
+ 0, 0x607E, 0, 0, 0xCB78, 0, 0, 0xCB7A,
+ 0x6069, 0xF06A, 0xF06C, 0xCB7D, 0, 0xCB7E, 0x383D, 0xCC21,
+};
+static const unsigned short utf8_to_euc_E790[] = {
+ 0xCC22, 0xCC23, 0, 0x3565, 0xCC24, 0x6066, 0x4D7D, 0xCC25,
+ 0, 0x4E30, 0xCC26, 0, 0, 0, 0, 0,
+ 0, 0xCC27, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xCC28, 0xCC29, 0, 0, 0, 0,
+ 0, 0, 0x4276, 0, 0xCC2A, 0x6068, 0xCC2B, 0,
+ 0xCC2C, 0xCC2D, 0xCC2E, 0xCC2F, 0xCC30, 0xCC31, 0xCC32, 0xCC33,
+ 0xCC34, 0xCC35, 0x606A, 0x4E56, 0x3657, 0x487C, 0x474A, 0,
+ 0, 0xCC36, 0x606B, 0, 0, 0, 0, 0x606D,
+};
+static const unsigned short utf8_to_euc_E790_x0213[] = {
+ 0xCC22, 0xF06D, 0, 0x3565, 0xCC24, 0x6066, 0x4D7D, 0x7821,
+ 0, 0x4E30, 0x7822, 0, 0, 0, 0, 0,
+ 0, 0xCC27, 0, 0xF06B, 0, 0, 0, 0,
+ 0, 0, 0x7823, 0x7824, 0, 0, 0, 0,
+ 0, 0, 0x4276, 0, 0xF06E, 0x6068, 0x7826, 0,
+ 0x7827, 0, 0x7828, 0x7829, 0x782A, 0xCC31, 0x782B, 0x782C,
+ 0x782D, 0xF06F, 0x606A, 0x4E56, 0x3657, 0x487C, 0x474A, 0,
+ 0, 0xF070, 0x606B, 0, 0, 0, 0, 0x606D,
+};
+static const unsigned short utf8_to_euc_E791[] = {
+ 0xCC37, 0x6070, 0, 0xCC38, 0xCC39, 0, 0xCC3A, 0xCC3B,
+ 0, 0, 0, 0xCC3C, 0, 0xCC3D, 0, 0,
+ 0, 0xCC3E, 0xCC3F, 0, 0, 0x606C, 0, 0xCC40,
+ 0, 0x606F, 0x386A, 0x314D, 0x6071, 0xCC41, 0x3F70, 0x606E,
+ 0x4E5C, 0, 0xCC42, 0x6074, 0x7424, 0, 0xCC43, 0xCC44,
+ 0xCC45, 0x6072, 0x6075, 0xCC46, 0, 0xCC47, 0xCC48, 0x6067,
+ 0x6073, 0xCC49, 0xCC4A, 0x3A3C, 0, 0, 0x6076, 0,
+ 0, 0, 0, 0, 0, 0, 0x6077, 0,
+};
+static const unsigned short utf8_to_euc_E791_x0213[] = {
+ 0xF072, 0x6070, 0, 0xF073, 0x782E, 0, 0x782F, 0x7830,
+ 0, 0, 0, 0x7831, 0, 0xF074, 0, 0,
+ 0, 0xCC3E, 0xF075, 0xF071, 0, 0x606C, 0, 0x7832,
+ 0, 0x606F, 0x386A, 0x314D, 0x6071, 0xF076, 0x3F70, 0x606E,
+ 0x4E5C, 0, 0x7833, 0x6074, 0x7424, 0, 0xCC43, 0xCC44,
+ 0xCC45, 0x6072, 0x6075, 0x7834, 0, 0x7835, 0xCC48, 0x6067,
+ 0x6073, 0xF077, 0xCC4A, 0x3A3C, 0, 0, 0x6076, 0,
+ 0, 0, 0, 0, 0, 0, 0x6077, 0,
+};
+static const unsigned short utf8_to_euc_E792[] = {
+ 0xCC4B, 0xCC4C, 0, 0x4D7E, 0, 0xCC4D, 0xCC4E, 0xCC4F,
+ 0, 0xCC50, 0, 0x6078, 0, 0, 0, 0xCC51,
+ 0xCC52, 0xCC53, 0xCC54, 0, 0, 0, 0, 0,
+ 0xCC55, 0xCC56, 0xCC57, 0, 0xCC58, 0, 0x6079, 0xCC59,
+ 0xCC5A, 0xCC5B, 0x6065, 0xCC5C, 0, 0, 0xCC5D, 0x607A,
+ 0xCC5E, 0xCC5F, 0xCC60, 0xCC61, 0, 0, 0xCC62, 0xCC63,
+ 0x3444, 0xCC64, 0xCC65, 0, 0, 0xCC66, 0, 0,
+ 0, 0xCC67, 0, 0xCC68, 0, 0x3C25, 0, 0xCC69,
+};
+static const unsigned short utf8_to_euc_E792_x0213[] = {
+ 0xCC4B, 0xF078, 0, 0x4D7E, 0, 0xF079, 0x7836, 0x7837,
+ 0xF07A, 0x7838, 0, 0x6078, 0, 0, 0, 0xCC51,
+ 0x783D, 0xCC53, 0xF07C, 0, 0, 0, 0, 0xF07D,
+ 0x7839, 0xF07E, 0xCC57, 0, 0x783A, 0, 0x6079, 0x783B,
+ 0xF121, 0xF122, 0x6065, 0x783C, 0, 0xF123, 0x783E, 0x607A,
+ 0x783F, 0x7840, 0xF124, 0xF125, 0, 0, 0xCC62, 0xCC63,
+ 0x3444, 0xCC64, 0xCC65, 0, 0, 0x7841, 0, 0,
+ 0, 0xF126, 0xF128, 0xF127, 0, 0x3C25, 0, 0x7842,
+};
+static const unsigned short utf8_to_euc_E793[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xCC6A, 0xCC6B, 0x607B, 0, 0xCC6C, 0, 0, 0x607C,
+ 0xCC6D, 0, 0, 0xCC6E, 0x607D, 0, 0, 0,
+ 0xCC6F, 0, 0xCC70, 0xCC71, 0x313B, 0, 0xCC72, 0xCC73,
+ 0x6121, 0, 0x493B, 0x6122, 0xCC74, 0, 0x3424, 0x6123,
+ 0xCC75, 0x6124, 0xCC76, 0xCC77, 0, 0, 0x6125, 0xCC78,
+ 0x6127, 0x6128, 0x6126, 0, 0xCC79, 0, 0x4953, 0x612A,
+ 0x6129, 0, 0xCC7A, 0xCC7B, 0xCC7C, 0, 0, 0xCC7D,
+};
+static const unsigned short utf8_to_euc_E793_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x7843, 0x7844, 0x607B, 0, 0xCC6C, 0, 0, 0x607C,
+ 0xCC6D, 0, 0, 0xCC6E, 0x607D, 0, 0xF129, 0,
+ 0xF12A, 0, 0x7845, 0xCC71, 0x313B, 0, 0xF12B, 0xCC73,
+ 0x6121, 0, 0x493B, 0x6122, 0xCC74, 0, 0x3424, 0x6123,
+ 0xCC75, 0x6124, 0xCC76, 0xF12D, 0, 0, 0x6125, 0xF12C,
+ 0x6127, 0x6128, 0x6126, 0, 0xCC79, 0, 0x4953, 0x612A,
+ 0x6129, 0, 0xF12F, 0xCC7B, 0xCC7C, 0, 0, 0x7846,
+};
+static const unsigned short utf8_to_euc_E794[] = {
+ 0, 0xF450, 0, 0x612C, 0x612B, 0x612D, 0xCC7E, 0,
+ 0, 0, 0, 0, 0x612E, 0x6130, 0x612F, 0,
+ 0, 0x3979, 0xCD21, 0x6132, 0, 0x6131, 0xCD22, 0xCD23,
+ 0x3445, 0, 0x3F53, 0, 0x453C, 0, 0x6133, 0x4038,
+ 0xCD24, 0xCD25, 0, 0x3B3A, 0xCD26, 0x3179, 0x6134, 0xCD27,
+ 0x4D51, 0xCD28, 0xCD29, 0x4A63, 0x6135, 0, 0, 0xCD2A,
+ 0x4544, 0x4D33, 0x3943, 0x3F3D, 0, 0, 0xCD2B, 0x434B,
+ 0x5234, 0xCD2C, 0x442E, 0x3268, 0x6136, 0xCD2D, 0xCD2E, 0xCD2F,
+};
+static const unsigned short utf8_to_euc_E794_x0213[] = {
+ 0, 0x7847, 0, 0x612C, 0x612B, 0x612D, 0xCC7E, 0,
+ 0, 0, 0, 0, 0x612E, 0x6130, 0x612F, 0,
+ 0, 0x3979, 0xCD21, 0x6132, 0, 0x6131, 0xCD22, 0x7848,
+ 0x3445, 0, 0x3F53, 0, 0x453C, 0, 0x6133, 0x4038,
+ 0xF131, 0xCD25, 0, 0x3B3A, 0xF132, 0x3179, 0x6134, 0xCD27,
+ 0x4D51, 0xCD28, 0xF133, 0x4A63, 0x6135, 0, 0, 0x7849,
+ 0x4544, 0x4D33, 0x3943, 0x3F3D, 0, 0, 0xCD2B, 0x434B,
+ 0x5234, 0xCD2C, 0x442E, 0x3268, 0x6136, 0xF136, 0xF137, 0xCD2F,
+};
+static const unsigned short utf8_to_euc_E795[] = {
+ 0xCD30, 0, 0, 0xCD31, 0x6137, 0, 0x613C, 0xCD32,
+ 0xCD33, 0x613A, 0x6139, 0x5A42, 0x3326, 0x6138, 0xCD34, 0x305A,
+ 0xCD35, 0x482A, 0xCD36, 0, 0x484A, 0, 0, 0xCD37,
+ 0, 0x4E31, 0x613D, 0x613B, 0x435C, 0x4026, 0xCD38, 0xCD39,
+ 0x482B, 0xCD3A, 0x492D, 0, 0x613F, 0x4E2C, 0x374D, 0x6140,
+ 0, 0x613E, 0x4856, 0x6141, 0, 0x6142, 0, 0xCD3B,
+ 0x305B, 0xCD3C, 0, 0x3E76, 0x6147, 0, 0x6144, 0x466D,
+ 0x6143, 0xCD3D, 0xCD3E, 0xCD3F, 0xCD40, 0xCD41, 0xCD42, 0x3526,
+};
+static const unsigned short utf8_to_euc_E795_x0213[] = {
+ 0xF138, 0, 0, 0xCD31, 0x6137, 0, 0x613C, 0xCD32,
+ 0xF139, 0x613A, 0x6139, 0x5A42, 0x3326, 0x6138, 0xF13A, 0x305A,
+ 0xF13B, 0x482A, 0xF13C, 0, 0x484A, 0, 0, 0xCD37,
+ 0, 0x4E31, 0x613D, 0x613B, 0x435C, 0x4026, 0xCD38, 0xCD39,
+ 0x482B, 0xCD3A, 0x492D, 0, 0x613F, 0x4E2C, 0x374D, 0x6140,
+ 0, 0x613E, 0x4856, 0x6141, 0xF13D, 0x6142, 0, 0x784A,
+ 0x305B, 0xF13F, 0xF13E, 0x3E76, 0x6147, 0, 0x6144, 0x466D,
+ 0x6143, 0x784B, 0xF140, 0xCD3F, 0xCD40, 0xF141, 0xF142, 0x3526,
+};
+static const unsigned short utf8_to_euc_E796[] = {
+ 0, 0xCD43, 0x614A, 0, 0, 0xCD44, 0x6145, 0x6146,
+ 0, 0x6149, 0x6148, 0x4925, 0, 0, 0x4142, 0x4141,
+ 0xCD45, 0x353F, 0xCD46, 0xCD47, 0x614B, 0xCD48, 0, 0,
+ 0, 0xCD49, 0x614C, 0, 0xCD4A, 0x614D, 0, 0,
+ 0, 0, 0xCD4B, 0x614F, 0xCD4C, 0x614E, 0, 0,
+ 0, 0, 0, 0x3156, 0, 0, 0, 0,
+ 0, 0x6157, 0x4868, 0x6151, 0xCD4D, 0x6153, 0, 0,
+ 0x6155, 0x3F3E, 0xCD4E, 0, 0x6156, 0x6154, 0x3C40, 0xCD4F,
+};
+static const unsigned short utf8_to_euc_E796_x0213[] = {
+ 0, 0xF143, 0x614A, 0, 0, 0xCD44, 0x6145, 0x6146,
+ 0, 0x6149, 0x6148, 0x4925, 0xF145, 0, 0x4142, 0x4141,
+ 0xCD45, 0x353F, 0x784C, 0xCD47, 0x614B, 0xCD48, 0, 0,
+ 0, 0xCD49, 0x614C, 0, 0xCD4A, 0x614D, 0, 0,
+ 0, 0, 0xF147, 0x614F, 0xCD4C, 0x614E, 0, 0,
+ 0, 0, 0, 0x3156, 0, 0, 0, 0,
+ 0xF149, 0x6157, 0x4868, 0x6151, 0xCD4D, 0x6153, 0, 0xF14A,
+ 0x6155, 0x3F3E, 0xCD4E, 0, 0x6156, 0x6154, 0x3C40, 0xF14B,
+};
+static const unsigned short utf8_to_euc_E797[] = {
+ 0xCD50, 0xCD51, 0x6150, 0x6152, 0xCD52, 0x4942, 0xCD53, 0x3E49,
+ 0, 0, 0x6159, 0, 0xCD54, 0x6158, 0xCD55, 0xCD56,
+ 0, 0, 0x615A, 0, 0x3C26, 0x3A2F, 0, 0xCD57,
+ 0x4577, 0x615B, 0, 0x444B, 0xCD58, 0, 0x615D, 0xCD59,
+ 0xCD5A, 0xCD5B, 0x4E21, 0x615C, 0xCD5C, 0, 0, 0xCD5D,
+ 0, 0x4169, 0, 0, 0xCD5E, 0, 0xCD5F, 0xCD60,
+ 0x6162, 0xCD61, 0x6164, 0x6165, 0x4354, 0, 0, 0,
+ 0, 0xCD62, 0x6163, 0, 0x6160, 0, 0x615E, 0x615F,
+};
+static const unsigned short utf8_to_euc_E797_x0213[] = {
+ 0xF14C, 0xCD51, 0x6150, 0x6152, 0xCD52, 0x4942, 0xF14D, 0x3E49,
+ 0, 0, 0x6159, 0, 0xCD54, 0x6158, 0x784E, 0xF14E,
+ 0, 0, 0x615A, 0xF14F, 0x3C26, 0x3A2F, 0, 0xCD57,
+ 0x4577, 0x615B, 0, 0x444B, 0xCD58, 0xF150, 0x615D, 0xF151,
+ 0xF152, 0xCD5B, 0x4E21, 0x615C, 0x784F, 0, 0, 0xF153,
+ 0, 0x4169, 0, 0, 0xF154, 0, 0xF155, 0xCD60,
+ 0x6162, 0xF156, 0x6164, 0x6165, 0x4354, 0, 0, 0,
+ 0, 0xF157, 0x6163, 0, 0x6160, 0, 0x615E, 0x615F,
+};
+static const unsigned short utf8_to_euc_E798[] = {
+ 0xCD63, 0x6161, 0xCD64, 0xCD65, 0xCD66, 0, 0, 0xCD67,
+ 0xCD68, 0x6168, 0xCD69, 0x6166, 0xCD6A, 0x6167, 0, 0xCD6B,
+ 0, 0, 0xCD6C, 0xCD6D, 0, 0xCD6E, 0xCD6F, 0,
+ 0, 0xCD70, 0, 0xCD71, 0xCD72, 0xCD73, 0xCD74, 0x6169,
+ 0x616B, 0x616C, 0x616D, 0xCD75, 0x616E, 0xCD76, 0xCD77, 0x616A,
+ 0, 0xCD78, 0, 0, 0, 0xCD79, 0, 0,
+ 0x6170, 0, 0xCD7A, 0xCD7B, 0x616F, 0xCD7C, 0, 0,
+ 0xCD7D, 0xCD7E, 0xCE21, 0x6171, 0xCE22, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E798_x0213[] = {
+ 0x7850, 0x6161, 0x7851, 0xF158, 0xCD66, 0, 0, 0xF15A,
+ 0x7852, 0x6168, 0xCD69, 0x6166, 0xCD6A, 0x6167, 0, 0xF15B,
+ 0, 0, 0xCD6C, 0xF15E, 0, 0x7853, 0x7854, 0,
+ 0xF159, 0x7855, 0, 0xF15F, 0xF160, 0xCD73, 0x7856, 0x6169,
+ 0x616B, 0x616C, 0x616D, 0xCD75, 0x616E, 0xF162, 0x7E7D, 0x616A,
+ 0xF163, 0xCD78, 0, 0, 0, 0x7857, 0, 0,
+ 0x6170, 0, 0xCD7A, 0xF165, 0x616F, 0x7858, 0, 0,
+ 0xCD7D, 0xCD7E, 0xCE21, 0x6171, 0xF164, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E799[] = {
+ 0xCE24, 0xCE25, 0x4E45, 0xCE26, 0xCE27, 0xCE28, 0x6174, 0x6172,
+ 0x6173, 0xCE29, 0xCE23, 0xCE2A, 0x3462, 0, 0, 0,
+ 0, 0, 0x4C7E, 0, 0, 0xCE2B, 0x4A4A, 0,
+ 0x6176, 0xCE2C, 0, 0, 0x6175, 0, 0, 0xCE2D,
+ 0, 0x6177, 0x6178, 0, 0xCE2E, 0xCE2F, 0, 0x617C,
+ 0x6179, 0x617A, 0x617B, 0, 0x617D, 0xCE30, 0xCE31, 0xCE32,
+ 0x617E, 0xCE33, 0x6221, 0, 0xCE34, 0, 0x6222, 0,
+ 0x6223, 0, 0x482F, 0x4550, 0x6224, 0x4772, 0x4934, 0,
+};
+static const unsigned short utf8_to_euc_E799_x0213[] = {
+ 0xCE24, 0xF168, 0x4E45, 0x7859, 0xCE27, 0xCE28, 0x6174, 0x6172,
+ 0x6173, 0xF16A, 0xCE23, 0x785A, 0x3462, 0, 0, 0,
+ 0, 0, 0x4C7E, 0, 0, 0xF16B, 0x4A4A, 0,
+ 0x6176, 0xCE2C, 0, 0, 0x6175, 0, 0, 0xCE2D,
+ 0, 0x6177, 0x6178, 0, 0x785B, 0x785C, 0, 0x617C,
+ 0x6179, 0x617A, 0x617B, 0, 0x617D, 0x785D, 0xF16D, 0x785E,
+ 0x617E, 0x785F, 0x6221, 0, 0xCE34, 0, 0x6222, 0,
+ 0x6223, 0, 0x482F, 0x4550, 0x6224, 0x4772, 0x4934, 0,
+};
+static const unsigned short utf8_to_euc_E79A[] = {
+ 0x6225, 0xCE35, 0xF451, 0x6226, 0x452A, 0xCE36, 0x3327, 0x3944,
+ 0x6227, 0, 0, 0x6228, 0xCE37, 0xCE38, 0x6229, 0,
+ 0x3B29, 0, 0, 0x622B, 0, 0xCE39, 0x622A, 0,
+ 0, 0x622C, 0x622D, 0xCE3A, 0xCE3B, 0xCE3C, 0xF452, 0xCE3D,
+ 0xCE3E, 0, 0xCE3F, 0xCE40, 0xCE41, 0xCE42, 0xCE43, 0xCE44,
+ 0xCE45, 0, 0xCE46, 0, 0, 0xCE47, 0x4869, 0,
+ 0x622E, 0, 0, 0, 0x622F, 0, 0, 0x7369,
+ 0x6230, 0x6231, 0x6232, 0, 0, 0xCE48, 0, 0x3B2E,
+};
+static const unsigned short utf8_to_euc_E79A_x0213[] = {
+ 0x6225, 0x7860, 0, 0x6226, 0x452A, 0xCE36, 0x3327, 0x3944,
+ 0x6227, 0, 0, 0x6228, 0xCE37, 0xCE38, 0x6229, 0,
+ 0x3B29, 0, 0, 0x622B, 0, 0xF16E, 0x622A, 0,
+ 0, 0x622C, 0x622D, 0x7861, 0xF16F, 0x7862, 0x7863, 0xCE3D,
+ 0xF171, 0xF170, 0xCE3F, 0xCE40, 0xCE41, 0xCE42, 0x7864, 0xF172,
+ 0xF173, 0, 0x7865, 0, 0, 0xCE47, 0x4869, 0xF174,
+ 0x622E, 0, 0, 0, 0x622F, 0, 0x7866, 0x7369,
+ 0x6230, 0x6231, 0x6232, 0, 0, 0xCE48, 0, 0x3B2E,
+};
+static const unsigned short utf8_to_euc_E79B[] = {
+ 0, 0xCE49, 0x6233, 0x4756, 0, 0xCE4A, 0x4B5F, 0,
+ 0x314E, 0xCE4B, 0x3157, 0xCE4C, 0xCE4D, 0x6234, 0xCE4E, 0,
+ 0, 0, 0x6236, 0, 0xCE4F, 0, 0x6235, 0x4570,
+ 0, 0xCE50, 0, 0x4039, 0x5D39, 0, 0x6237, 0x4C41,
+ 0xCE51, 0x6238, 0, 0x3446, 0x4857, 0x6239, 0xCE52, 0x623A,
+ 0xCE53, 0, 0x623B, 0, 0xCE54, 0, 0x4C5C, 0,
+ 0xCE55, 0xCE56, 0x4C55, 0, 0x443E, 0, 0xCE57, 0,
+ 0x416A, 0xCE58, 0, 0x623D, 0xCE59, 0, 0x3D62, 0,
+};
+static const unsigned short utf8_to_euc_E79B_x0213[] = {
+ 0, 0xCE49, 0x6233, 0x4756, 0, 0x7867, 0x4B5F, 0,
+ 0x314E, 0xF176, 0x3157, 0xCE4C, 0x7868, 0x6234, 0x7869, 0,
+ 0, 0, 0x6236, 0, 0x786A, 0, 0x6235, 0x4570,
+ 0, 0xCE50, 0, 0x4039, 0x5D39, 0, 0x6237, 0x4C41,
+ 0xCE51, 0x6238, 0, 0x3446, 0x4857, 0x6239, 0x786B, 0x623A,
+ 0xF178, 0, 0x623B, 0, 0xF179, 0, 0x4C5C, 0,
+ 0xCE55, 0x786C, 0x4C55, 0, 0x443E, 0, 0xCE57, 0,
+ 0x416A, 0xCE58, 0, 0x623D, 0x786D, 0, 0x3D62, 0,
+};
+static const unsigned short utf8_to_euc_E79C[] = {
+ 0xCE5A, 0x3E4A, 0, 0, 0x6240, 0, 0xCE5B, 0x623F,
+ 0x623E, 0x487D, 0xCE5C, 0x3447, 0x3829, 0, 0xCE5D, 0,
+ 0, 0, 0xCE5E, 0, 0xCE5F, 0xCE60, 0, 0xCE61,
+ 0, 0xCE62, 0xCE63, 0x6246, 0xCE64, 0, 0x6243, 0x3F3F,
+ 0x4C32, 0, 0xCE65, 0, 0x6242, 0x6244, 0x6245, 0,
+ 0xCE66, 0x6241, 0, 0, 0, 0xCE67, 0xCE68, 0xCE69,
+ 0, 0, 0, 0, 0xCE6A, 0xCE6B, 0xCE6C, 0x6247,
+ 0x6248, 0xCE6D, 0x442F, 0, 0x3463, 0xCE6E, 0xCE6F, 0,
+};
+static const unsigned short utf8_to_euc_E79C_x0213[] = {
+ 0xCE5A, 0x3E4A, 0, 0, 0x6240, 0, 0xCE5B, 0x623F,
+ 0x623E, 0x487D, 0x786E, 0x3447, 0x3829, 0, 0xCE5D, 0,
+ 0, 0, 0xCE5E, 0, 0xCE5F, 0xCE60, 0, 0xF17B,
+ 0, 0x786F, 0xF17C, 0x6246, 0xCE64, 0, 0x6243, 0x3F3F,
+ 0x4C32, 0, 0xCE65, 0, 0x6242, 0x6244, 0x6245, 0,
+ 0xCE66, 0x6241, 0, 0, 0, 0xF17D, 0xCE68, 0xCE69,
+ 0, 0, 0, 0, 0x7870, 0xF17E, 0x7871, 0x6247,
+ 0x6248, 0xCE6D, 0x442F, 0, 0x3463, 0xCE6E, 0xCE6F, 0,
+};
+static const unsigned short utf8_to_euc_E79D[] = {
+ 0x4365, 0, 0xCE70, 0, 0, 0xCE71, 0xCE72, 0x6249,
+ 0, 0, 0xCE73, 0, 0, 0xCE74, 0xCE75, 0xCE76,
+ 0, 0, 0xCE77, 0, 0, 0, 0xCE78, 0xCE79,
+ 0, 0, 0x624A, 0x624D, 0xCE7A, 0, 0xCE7B, 0xCE7C,
+ 0xCE7D, 0x3F67, 0xCE7E, 0x4644, 0xCF21, 0x624E, 0x4B53, 0xCF22,
+ 0x624B, 0, 0xCF23, 0x624C, 0xCF24, 0, 0, 0,
+ 0xCF25, 0, 0xCF26, 0xCF27, 0xCF28, 0, 0, 0,
+ 0, 0x6251, 0xCF29, 0, 0, 0xCF2A, 0x6250, 0x624F,
+};
+static const unsigned short utf8_to_euc_E79D_x0213[] = {
+ 0x4365, 0, 0xCE70, 0, 0, 0xCE71, 0x7872, 0x6249,
+ 0, 0, 0xCE73, 0, 0, 0x7873, 0x7874, 0xCE76,
+ 0, 0, 0xCE77, 0, 0, 0, 0xCE78, 0xCE79,
+ 0xF225, 0, 0x624A, 0x624D, 0x7875, 0, 0xCE7B, 0x7876,
+ 0xF226, 0x3F67, 0x7877, 0x4644, 0xCF21, 0x624E, 0x4B53, 0xCF22,
+ 0x624B, 0, 0xF227, 0x624C, 0xCF24, 0, 0, 0,
+ 0xCF25, 0, 0xF229, 0xCF27, 0xCF28, 0, 0, 0,
+ 0, 0x6251, 0x7878, 0, 0xF22A, 0xF22B, 0x6250, 0x624F,
+};
+static const unsigned short utf8_to_euc_E79E[] = {
+ 0xCF2B, 0, 0, 0, 0xCF2C, 0, 0, 0,
+ 0, 0, 0, 0x6253, 0xCF2D, 0xCF2E, 0x6252, 0,
+ 0, 0x6254, 0, 0, 0xCF2F, 0xCF30, 0xCF31, 0,
+ 0, 0, 0xCF32, 0, 0, 0, 0x6256, 0xCF33,
+ 0x6255, 0, 0xCF34, 0, 0, 0x4A4D, 0, 0xCF35,
+ 0, 0, 0xCF36, 0, 0x3D56, 0x4E46, 0xCF37, 0xCF38,
+ 0x6257, 0xCF39, 0, 0x4637, 0, 0xCF3A, 0x6258, 0,
+ 0, 0x6259, 0, 0x625D, 0x625B, 0x625C, 0xCF3B, 0x625A,
+};
+static const unsigned short utf8_to_euc_E79E_x0213[] = {
+ 0x7879, 0, 0, 0, 0xCF2C, 0, 0, 0,
+ 0, 0, 0, 0x6253, 0xCF2D, 0xCF2E, 0x6252, 0,
+ 0, 0x6254, 0, 0, 0x787A, 0xCF30, 0xCF31, 0,
+ 0, 0, 0xF22E, 0, 0, 0, 0x6256, 0xF22F,
+ 0x6255, 0, 0xF230, 0, 0xF231, 0x4A4D, 0, 0xCF35,
+ 0, 0xF232, 0x787B, 0, 0x3D56, 0x4E46, 0xCF37, 0xCF38,
+ 0x6257, 0xCF39, 0, 0x4637, 0, 0xCF3A, 0x6258, 0,
+ 0, 0x6259, 0, 0x625D, 0x625B, 0x625C, 0xCF3B, 0x625A,
+};
+static const unsigned short utf8_to_euc_E79F[] = {
+ 0, 0, 0, 0xCF3C, 0, 0, 0, 0x625E,
+ 0, 0xCF3D, 0, 0, 0, 0x625F, 0, 0,
+ 0, 0xCF3E, 0xCF3F, 0, 0, 0xCF40, 0, 0x6260,
+ 0, 0xCF41, 0x6261, 0x4C37, 0x6262, 0, 0xCF42, 0xCF43,
+ 0xCF44, 0, 0x4C70, 0x6263, 0xCF45, 0x434E, 0xCF46, 0x476A,
+ 0, 0x366B, 0xCF47, 0, 0xCF48, 0x433B, 0x6264, 0x363A,
+ 0xCF49, 0xCF4A, 0, 0x4050, 0xCF4B, 0, 0, 0,
+ 0xCF4C, 0, 0, 0xCF4D, 0x6265, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E79F_x0213[] = {
+ 0, 0, 0, 0xCF3C, 0, 0, 0, 0x625E,
+ 0, 0xCF3D, 0, 0, 0, 0x625F, 0, 0,
+ 0, 0xCF3E, 0xCF3F, 0, 0, 0xCF40, 0, 0x6260,
+ 0, 0xCF41, 0x6261, 0x4C37, 0x6262, 0, 0xF233, 0xF234,
+ 0x787C, 0, 0x4C70, 0x6263, 0xF235, 0x434E, 0xF236, 0x476A,
+ 0, 0x366B, 0xF237, 0, 0xF238, 0x433B, 0x6264, 0x363A,
+ 0xF23A, 0xCF4A, 0, 0x4050, 0xF23B, 0, 0, 0,
+ 0xCF4C, 0, 0, 0xF23C, 0x6265, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E7A0[] = {
+ 0, 0, 0x3A3D, 0, 0, 0xCF4E, 0xCF4F, 0,
+ 0, 0xCF50, 0, 0, 0x6266, 0xCF51, 0xCF52, 0,
+ 0, 0xCF53, 0x6267, 0, 0x3826, 0x3A55, 0, 0,
+ 0, 0, 0, 0, 0, 0xCF54, 0, 0,
+ 0x6269, 0xCF55, 0xCF56, 0xCF57, 0, 0x4556, 0x3A56, 0x354E,
+ 0, 0, 0, 0, 0, 0xCF58, 0xCF59, 0,
+ 0xCF5A, 0, 0x4B24, 0, 0x474B, 0xCF5B, 0, 0xCF5C,
+ 0, 0, 0x4557, 0, 0, 0, 0, 0x395C,
+};
+static const unsigned short utf8_to_euc_E7A0_x0213[] = {
+ 0, 0, 0x3A3D, 0, 0, 0xF23E, 0xF23F, 0,
+ 0, 0xF240, 0, 0, 0x6266, 0xF241, 0xCF52, 0,
+ 0, 0xCF53, 0x6267, 0, 0x3826, 0x3A55, 0, 0,
+ 0, 0xF242, 0, 0, 0, 0xCF54, 0, 0,
+ 0x6269, 0xF243, 0xCF56, 0xCF57, 0, 0x4556, 0x3A56, 0x354E,
+ 0, 0, 0, 0, 0xF244, 0x787D, 0xCF59, 0,
+ 0xCF5A, 0, 0x4B24, 0, 0x474B, 0xCF5B, 0, 0xCF5C,
+ 0, 0, 0x4557, 0, 0, 0, 0, 0x395C,
+};
+static const unsigned short utf8_to_euc_E7A1[] = {
+ 0, 0, 0, 0xCF5D, 0xCF5E, 0x626B, 0, 0xCF5F,
+ 0xCF60, 0, 0, 0, 0xCF61, 0, 0xCF62, 0,
+ 0, 0, 0xCF63, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xCF64, 0x3E4B, 0xCF65, 0,
+ 0xCF66, 0xCF67, 0, 0xCF68, 0xCF69, 0, 0, 0,
+ 0xCF6A, 0, 0xCF6B, 0x4E32, 0x3945, 0, 0xCF6C, 0x3827,
+ 0, 0, 0x4823, 0, 0x626D, 0, 0, 0,
+ 0, 0, 0xCF6D, 0, 0x626F, 0, 0xCF6E, 0,
+};
+static const unsigned short utf8_to_euc_E7A1_x0213[] = {
+ 0, 0, 0, 0x7921, 0xCF5E, 0x626B, 0, 0xF245,
+ 0xCF60, 0, 0, 0, 0xCF61, 0, 0x7922, 0x7923,
+ 0, 0x7924, 0xCF63, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xCF64, 0x3E4B, 0xCF65, 0,
+ 0xCF66, 0xCF67, 0, 0xCF68, 0xF246, 0, 0, 0,
+ 0x7925, 0, 0xF247, 0x4E32, 0x3945, 0, 0x7926, 0x3827,
+ 0, 0, 0x4823, 0, 0x626D, 0, 0, 0,
+ 0, 0, 0, 0, 0x626F, 0, 0xCF6E, 0,
+};
+static const unsigned short utf8_to_euc_E7A2[] = {
+ 0, 0x386B, 0, 0, 0, 0, 0x626E, 0x4476,
+ 0, 0, 0xCF6F, 0, 0x6271, 0x3337, 0x626C, 0xCF70,
+ 0, 0x486A, 0, 0x3130, 0xCF71, 0x3A6C, 0, 0x4F52,
+ 0xCF72, 0, 0x6270, 0, 0, 0xCF74, 0xCF75, 0xCF76,
+ 0, 0xCF73, 0, 0x6272, 0xCF77, 0, 0, 0x4A4B,
+ 0xCF78, 0x4059, 0x6274, 0, 0xCF79, 0xCF7A, 0, 0x6275,
+ 0xCF7B, 0xCF7C, 0xCF7D, 0xCF7E, 0, 0x6273, 0, 0,
+ 0, 0, 0x334E, 0xD021, 0x627B, 0xD022, 0x627A, 0xD023,
+};
+static const unsigned short utf8_to_euc_E7A2_x0213[] = {
+ 0, 0x386B, 0, 0, 0, 0, 0x626E, 0x4476,
+ 0, 0, 0xF249, 0, 0x6271, 0x3337, 0x626C, 0xCF70,
+ 0, 0x486A, 0, 0x3130, 0xF24A, 0x3A6C, 0, 0x4F52,
+ 0xCF72, 0, 0x6270, 0, 0, 0xF24C, 0xF24D, 0xF24E,
+ 0, 0xCF73, 0, 0x6272, 0xF24B, 0, 0, 0x4A4B,
+ 0xCF78, 0x4059, 0x6274, 0, 0xCF79, 0x792A, 0, 0x6275,
+ 0x7928, 0xCF7C, 0xCF7D, 0xCF7E, 0, 0x6273, 0, 0,
+ 0, 0, 0x334E, 0xF24F, 0x627B, 0xD022, 0x627A, 0xD023,
+};
+static const unsigned short utf8_to_euc_E7A3[] = {
+ 0, 0x3C27, 0, 0, 0, 0x627C, 0x6277, 0xD024,
+ 0xD025, 0xD026, 0x627D, 0x6278, 0xD027, 0, 0xD028, 0,
+ 0x4858, 0x6276, 0xD029, 0xD02A, 0x6279, 0xD02B, 0xD02C, 0,
+ 0, 0, 0x6322, 0xD02E, 0, 0, 0, 0xD02F,
+ 0xD030, 0xD031, 0, 0, 0xD02D, 0, 0xD032, 0x6321,
+ 0x4B61, 0, 0xD033, 0, 0x627E, 0, 0, 0x306B,
+ 0, 0, 0xD034, 0xD035, 0x6324, 0, 0xD037, 0xD038,
+ 0, 0, 0xD039, 0xD03A, 0, 0x6323, 0, 0xD03B,
+};
+static const unsigned short utf8_to_euc_E7A3_x0213[] = {
+ 0, 0x3C27, 0, 0, 0, 0x627C, 0x6277, 0xD024,
+ 0xF250, 0xD026, 0x627D, 0x6278, 0xF251, 0, 0xF252, 0,
+ 0x4858, 0x6276, 0xD029, 0xD02A, 0x6279, 0xF253, 0xD02C, 0,
+ 0, 0, 0x6322, 0xD02E, 0, 0, 0, 0xD02F,
+ 0xF254, 0xF255, 0, 0, 0x792B, 0, 0xF256, 0x6321,
+ 0x4B61, 0, 0xD033, 0, 0x627E, 0, 0, 0x306B,
+ 0, 0, 0x792C, 0xD035, 0x6324, 0, 0xD037, 0x792E,
+ 0, 0xF257, 0xF258, 0xF259, 0, 0x6323, 0xF25A, 0xD03B,
+};
+static const unsigned short utf8_to_euc_E7A4[] = {
+ 0xD036, 0x3E4C, 0, 0, 0, 0, 0xD03C, 0x6325,
+ 0, 0, 0, 0, 0xD03D, 0, 0x4143, 0,
+ 0xD03E, 0x6327, 0x6326, 0, 0, 0, 0, 0,
+ 0, 0x6328, 0xD03F, 0, 0xD040, 0, 0xD041, 0xD042,
+ 0xD043, 0, 0, 0, 0, 0xD044, 0x6268, 0xD045,
+ 0, 0xD046, 0x626A, 0x632A, 0x6329, 0xD047, 0, 0,
+ 0xF454, 0xD048, 0, 0, 0xD049, 0xD04A, 0, 0,
+ 0, 0, 0x3C28, 0xD04B, 0x4E69, 0xD04C, 0x3C52, 0xD04D,
+};
+static const unsigned short utf8_to_euc_E7A4_x0213[] = {
+ 0x792D, 0x3E4C, 0, 0, 0, 0, 0xD03C, 0x6325,
+ 0, 0, 0, 0, 0xD03D, 0, 0x4143, 0,
+ 0xF25C, 0x6327, 0x6326, 0, 0, 0, 0, 0,
+ 0, 0x6328, 0xD03F, 0xF25D, 0x792F, 0, 0xD041, 0xD042,
+ 0xD043, 0, 0, 0, 0, 0xF25F, 0x6268, 0xD045,
+ 0, 0xD046, 0x626A, 0x632A, 0x6329, 0xD047, 0x7930, 0,
+ 0xF25E, 0x7931, 0, 0, 0x7932, 0xD04A, 0, 0,
+ 0, 0, 0x3C28, 0xF260, 0x4E69, 0xD04C, 0x3C52, 0xD04D,
+};
+static const unsigned short utf8_to_euc_E7A5[] = {
+ 0x632B, 0x3737, 0, 0, 0xD04E, 0xD04F, 0xD050, 0x3540,
+ 0x3527, 0x3B63, 0xD051, 0xD052, 0, 0, 0, 0xD053,
+ 0x4D34, 0xD054, 0, 0x6331, 0xD055, 0x6330, 0x4144, 0x632D,
+ 0xD056, 0, 0x632F, 0xD057, 0xD058, 0x3D4B, 0x3F40, 0x632E,
+ 0x632C, 0, 0x472A, 0, 0, 0x3E4D, 0, 0xD059,
+ 0x493C, 0xD05A, 0, 0xD05B, 0, 0x3A57, 0, 0,
+ 0, 0, 0xD05C, 0, 0, 0, 0, 0x4578,
+ 0, 0xD05D, 0x6332, 0xD05E, 0xD05F, 0, 0xD060, 0x6333,
+};
+static const unsigned short utf8_to_euc_E7A5_x0213[] = {
+ 0x632B, 0x3737, 0, 0, 0xD04E, 0x7935, 0x7936, 0x3540,
+ 0x3527, 0x3B63, 0xF261, 0xD052, 0, 0, 0, 0xD053,
+ 0x4D34, 0xD054, 0, 0x6331, 0xD055, 0x6330, 0x4144, 0x632D,
+ 0xF262, 0, 0x632F, 0xF263, 0x793A, 0x3D4B, 0x3F40, 0x632E,
+ 0x632C, 0, 0x472A, 0, 0, 0x3E4D, 0, 0xF265,
+ 0x493C, 0xD05A, 0, 0xD05B, 0, 0x3A57, 0, 0,
+ 0, 0, 0xF266, 0, 0, 0, 0, 0x4578,
+ 0, 0x793E, 0x6332, 0xD05E, 0xD05F, 0, 0xD060, 0x6333,
+};
+static const unsigned short utf8_to_euc_E7A6[] = {
+ 0x6349, 0x3658, 0, 0, 0x4F3D, 0x4135, 0, 0,
+ 0, 0, 0x6334, 0xD061, 0xD062, 0x3252, 0x4477, 0x4A21,
+ 0, 0xD063, 0, 0xD064, 0xD065, 0xD066, 0xD067, 0,
+ 0xD068, 0, 0, 0xD069, 0xD06A, 0x6335, 0, 0,
+ 0, 0xD06B, 0, 0, 0, 0, 0x357A, 0x6336,
+ 0xD06C, 0xD06D, 0x6338, 0xD06E, 0, 0, 0x6339, 0xD06F,
+ 0x4729, 0xD070, 0, 0x633A, 0xD071, 0, 0, 0,
+ 0xD072, 0x633B, 0x633C, 0xD073, 0, 0x3659, 0x3253, 0x4645,
+};
+static const unsigned short utf8_to_euc_E7A6_x0213[] = {
+ 0x6349, 0x3658, 0, 0, 0x4F3D, 0x4135, 0, 0,
+ 0, 0, 0x6334, 0xD061, 0xD062, 0x3252, 0x4477, 0x4A21,
+ 0, 0xD063, 0, 0xD064, 0xF267, 0xF268, 0xF269, 0,
+ 0x7942, 0, 0, 0xF26A, 0xD06A, 0x6335, 0, 0,
+ 0, 0xF26B, 0, 0, 0, 0, 0x357A, 0x6336,
+ 0xD06C, 0xF26C, 0x6338, 0xD06E, 0, 0, 0x6339, 0xD06F,
+ 0x4729, 0x7943, 0, 0x633A, 0xF26D, 0, 0, 0,
+ 0x7944, 0x633B, 0x633C, 0xF26E, 0, 0x3659, 0x3253, 0x4645,
+};
+static const unsigned short utf8_to_euc_E7A7[] = {
+ 0x3D28, 0x3B64, 0xD074, 0, 0xD075, 0, 0, 0xD076,
+ 0xD077, 0x633D, 0xD078, 0x3D29, 0, 0, 0, 0xD079,
+ 0, 0x324A, 0x4943, 0, 0xD07A, 0x633E, 0xD07B, 0,
+ 0x486B, 0, 0xD07C, 0, 0, 0xD07D, 0xD07E, 0x4145,
+ 0xD121, 0x6341, 0xD122, 0x6342, 0x4769, 0xD123, 0x3F41, 0x633F,
+ 0, 0x4361, 0xD124, 0xD125, 0x6340, 0xD126, 0, 0,
+ 0x3E4E, 0xD127, 0, 0, 0, 0, 0, 0,
+ 0xD128, 0, 0, 0x305C, 0xD129, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E7A7_x0213[] = {
+ 0x3D28, 0x3B64, 0xF26F, 0, 0xD075, 0, 0, 0xF270,
+ 0x7945, 0x633D, 0x7946, 0x3D29, 0xF271, 0xF272, 0, 0xD079,
+ 0, 0x324A, 0x4943, 0, 0x7948, 0x633E, 0xF273, 0,
+ 0x486B, 0, 0xD07C, 0, 0, 0xD07D, 0x7949, 0x4145,
+ 0xD121, 0x6341, 0xD122, 0x6342, 0x4769, 0xD123, 0x3F41, 0x633F,
+ 0, 0x4361, 0xD124, 0x794A, 0x6340, 0x794B, 0, 0,
+ 0x3E4E, 0xD127, 0, 0, 0, 0, 0, 0,
+ 0xD128, 0, 0, 0x305C, 0xD129, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E7A8[] = {
+ 0x3529, 0, 0xD12A, 0xD12B, 0, 0, 0, 0xD12C,
+ 0x6343, 0xD12D, 0xD12E, 0x4478, 0xD12F, 0x6344, 0x4047, 0,
+ 0, 0xD130, 0, 0, 0x4C2D, 0xD131, 0, 0x4923,
+ 0x6345, 0x6346, 0x4355, 0xD132, 0x4E47, 0, 0xD133, 0x6348,
+ 0x6347, 0xD134, 0, 0, 0, 0, 0, 0xD135,
+ 0, 0, 0, 0xD136, 0, 0xD137, 0x3C6F, 0xD138,
+ 0xD139, 0x634A, 0x3070, 0, 0xD13A, 0xD13B, 0, 0x634D,
+ 0xD13C, 0xD13D, 0xD13E, 0x634B, 0x3254, 0x374E, 0x634C, 0x3946,
+};
+static const unsigned short utf8_to_euc_E7A8_x0213[] = {
+ 0x3529, 0, 0xD12A, 0x794C, 0, 0, 0, 0xD12C,
+ 0x6343, 0xD12D, 0xF278, 0x4478, 0xD12F, 0x6344, 0x4047, 0,
+ 0, 0xF279, 0, 0, 0x4C2D, 0xF27A, 0, 0x4923,
+ 0x6345, 0x6346, 0x4355, 0xF27B, 0x4E47, 0, 0xF27C, 0x6348,
+ 0x6347, 0xD134, 0, 0, 0, 0, 0, 0xD135,
+ 0, 0, 0, 0xD136, 0, 0xF27E, 0x3C6F, 0xD138,
+ 0xD139, 0x634A, 0x3070, 0, 0xD13A, 0xD13B, 0, 0x634D,
+ 0xF321, 0x794E, 0xD13E, 0x634B, 0x3254, 0x374E, 0x634C, 0x3946,
+};
+static const unsigned short utf8_to_euc_E7A9[] = {
+ 0x3972, 0, 0x4A66, 0x634E, 0xD13F, 0xD140, 0x4B54, 0xD141,
+ 0xD142, 0x6350, 0, 0, 0xD143, 0x4051, 0x314F, 0x323A,
+ 0x302C, 0, 0, 0, 0, 0xD144, 0xD145, 0x634F,
+ 0, 0xD146, 0, 0, 0xD147, 0xD148, 0, 0xD149,
+ 0xD14A, 0x6351, 0x6352, 0x3E77, 0, 0xD14B, 0, 0xD14C,
+ 0, 0x6353, 0xD14D, 0x334F, 0, 0xD14E, 0, 0,
+ 0x6355, 0, 0, 0, 0x376A, 0xD14F, 0x3566, 0,
+ 0xD150, 0x6356, 0x3675, 0, 0, 0x6357, 0xD151, 0x407C,
+};
+static const unsigned short utf8_to_euc_E7A9_x0213[] = {
+ 0x3972, 0, 0x4A66, 0x634E, 0xD13F, 0xD140, 0x4B54, 0xF322,
+ 0xD142, 0x6350, 0, 0, 0xF323, 0x4051, 0x314F, 0x323A,
+ 0x302C, 0, 0, 0, 0, 0xD144, 0xF324, 0x634F,
+ 0, 0xF325, 0, 0, 0xF326, 0x794F, 0, 0xF327,
+ 0xF328, 0x6351, 0x6352, 0x3E77, 0, 0xD14B, 0, 0xF329,
+ 0, 0x6353, 0xF32A, 0x334F, 0, 0x7950, 0, 0,
+ 0x6355, 0, 0, 0, 0x376A, 0xF32B, 0x3566, 0,
+ 0xF32C, 0x6356, 0x3675, 0, 0, 0x6357, 0xD151, 0x407C,
+};
+static const unsigned short utf8_to_euc_E7AA[] = {
+ 0xD152, 0x464D, 0xD153, 0x4060, 0x3A75, 0xD154, 0xD155, 0,
+ 0x6358, 0, 0xD156, 0xD157, 0, 0, 0, 0,
+ 0xD158, 0xD159, 0x4362, 0x416B, 0xD15A, 0x635A, 0x635C, 0x6359,
+ 0x635B, 0, 0, 0, 0, 0, 0xD15B, 0x3722,
+ 0xD15C, 0, 0, 0xD15D, 0, 0, 0, 0,
+ 0, 0x635D, 0x3726, 0, 0xD15E, 0, 0x3567, 0x4D52,
+ 0x635F, 0, 0, 0xD15F, 0, 0xD160, 0x6360, 0,
+ 0, 0xD161, 0x312E, 0xD162, 0xD163, 0, 0, 0x6363,
+};
+static const unsigned short utf8_to_euc_E7AA_x0213[] = {
+ 0xD152, 0x464D, 0xF32D, 0x4060, 0x3A75, 0x7952, 0xD155, 0,
+ 0x6358, 0, 0xF32E, 0xD157, 0, 0, 0, 0,
+ 0xF32F, 0xD159, 0x4362, 0x416B, 0xD15A, 0x635A, 0x635C, 0x6359,
+ 0x635B, 0, 0, 0, 0, 0, 0xD15B, 0x3722,
+ 0x7953, 0, 0, 0xF330, 0, 0, 0, 0,
+ 0, 0x635D, 0x3726, 0, 0xF331, 0, 0x3567, 0x4D52,
+ 0x635F, 0, 0, 0x7955, 0, 0xD160, 0x6360, 0,
+ 0, 0xF334, 0x312E, 0x7956, 0xF335, 0, 0xF336, 0x6363,
+};
+static const unsigned short utf8_to_euc_E7AB[] = {
+ 0, 0, 0, 0x3376, 0x6362, 0x6361, 0xD164, 0x6365,
+ 0x635E, 0xD165, 0x6366, 0x4E29, 0xD166, 0x6367, 0xD167, 0x6368,
+ 0, 0xD168, 0x5474, 0x636A, 0, 0x6369, 0, 0,
+ 0, 0x636B, 0x636C, 0xD169, 0x4E35, 0x636D, 0, 0x706F,
+ 0x3E4F, 0x636E, 0x636F, 0x3D57, 0, 0x4638, 0x6370, 0xF459,
+ 0xD16A, 0xD16B, 0x4328, 0xD16C, 0xD16D, 0x6371, 0, 0x433C,
+ 0x6372, 0xD16E, 0, 0, 0xD16F, 0, 0x3625, 0,
+ 0x513F, 0x435D, 0x3C33, 0xD170, 0, 0xD171, 0xD172, 0x3448,
+};
+static const unsigned short utf8_to_euc_E7AB_x0213[] = {
+ 0, 0, 0, 0x3376, 0x6362, 0x6361, 0xD164, 0x6365,
+ 0x635E, 0xD165, 0x6366, 0x4E29, 0xF338, 0x6367, 0x7957, 0x6368,
+ 0, 0xF339, 0x5474, 0x636A, 0, 0x6369, 0, 0,
+ 0, 0x636B, 0x636C, 0xD169, 0x4E35, 0x636D, 0, 0x706F,
+ 0x3E4F, 0x636E, 0x636F, 0x3D57, 0, 0x4638, 0x6370, 0xF33A,
+ 0xF33B, 0xD16B, 0x4328, 0x7958, 0xD16D, 0x6371, 0, 0x433C,
+ 0x6372, 0xD16E, 0, 0, 0xF33C, 0, 0x3625, 0,
+ 0x513F, 0x435D, 0x3C33, 0xD170, 0, 0x7959, 0xD172, 0x3448,
+};
+static const unsigned short utf8_to_euc_E7AC[] = {
+ 0, 0, 0x6373, 0, 0x6422, 0, 0x6376, 0xD173,
+ 0x3568, 0, 0x6375, 0x6424, 0, 0, 0, 0x6374,
+ 0, 0x3E50, 0, 0, 0xD174, 0, 0, 0,
+ 0x6378, 0x6379, 0, 0x452B, 0, 0, 0x637A, 0xD175,
+ 0x335E, 0, 0, 0xD176, 0, 0x3F5A, 0x4964, 0xD177,
+ 0x637C, 0xD178, 0xD179, 0xD17A, 0x4268, 0xD17B, 0xD17C, 0xD17D,
+ 0xD17E, 0xD221, 0, 0x6377, 0xD222, 0x637B, 0x637D, 0,
+ 0, 0x3A7B, 0, 0, 0, 0xD223, 0, 0xD224,
+};
+static const unsigned short utf8_to_euc_E7AC_x0213[] = {
+ 0, 0, 0x6373, 0, 0x6422, 0, 0x6376, 0xF33F,
+ 0x3568, 0, 0x6375, 0x6424, 0, 0, 0, 0x6374,
+ 0, 0x3E50, 0x795A, 0, 0xD174, 0, 0, 0,
+ 0x6378, 0x6379, 0, 0x452B, 0, 0, 0x637A, 0xD175,
+ 0x335E, 0, 0, 0xD176, 0, 0x3F5A, 0x4964, 0xF342,
+ 0x637C, 0xD178, 0xF343, 0xD17A, 0x4268, 0x795B, 0xF344, 0xF345,
+ 0xD17E, 0xF346, 0, 0x6377, 0xD222, 0x637B, 0x637D, 0,
+ 0, 0x3A7B, 0, 0x795C, 0, 0xF341, 0, 0xD224,
+};
+static const unsigned short utf8_to_euc_E7AD[] = {
+ 0xD225, 0xD226, 0, 0, 0, 0x6426, 0x492E, 0xD227,
+ 0x4826, 0x4579, 0, 0x365A, 0x6425, 0x6423, 0xD228, 0x4835,
+ 0x637E, 0x435E, 0x457B, 0, 0x457A, 0xD229, 0x3A76, 0,
+ 0, 0, 0, 0, 0, 0x6438, 0, 0,
+ 0xD22A, 0, 0, 0, 0xD22B, 0x6428, 0xD22C, 0x642A,
+ 0, 0xD22D, 0xD22E, 0, 0x642D, 0xD22F, 0x642E, 0xD230,
+ 0x642B, 0x642C, 0xD231, 0xD232, 0x6429, 0x6427, 0, 0xD233,
+ 0, 0, 0x6421, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E7AD_x0213[] = {
+ 0xD225, 0xF34A, 0, 0, 0, 0x6426, 0x492E, 0x795D,
+ 0x4826, 0x4579, 0, 0x365A, 0x6425, 0x6423, 0x795E, 0x4835,
+ 0x637E, 0x435E, 0x457B, 0, 0x457A, 0xF34C, 0x3A76, 0,
+ 0, 0, 0, 0, 0, 0x6438, 0, 0,
+ 0x795F, 0, 0, 0, 0xF34E, 0x6428, 0xF34F, 0x642A,
+ 0, 0xF350, 0xD22E, 0, 0x642D, 0x7960, 0x642E, 0x7961,
+ 0x642B, 0x642C, 0x7962, 0xF351, 0x6429, 0x6427, 0, 0xD233,
+ 0, 0xF34D, 0x6421, 0, 0, 0, 0, 0xF349,
+};
+static const unsigned short utf8_to_euc_E7AE[] = {
+ 0, 0, 0, 0, 0xD234, 0, 0x4A4F, 0x3255,
+ 0, 0xD235, 0, 0x6435, 0, 0x6432, 0xD236, 0x6437,
+ 0xD237, 0xD238, 0x6436, 0, 0x4773, 0x4C27, 0xD239, 0x3B3B,
+ 0x6430, 0x6439, 0x6434, 0xD23A, 0x6433, 0x642F, 0xD23B, 0x6431,
+ 0xD23C, 0x3449, 0, 0, 0, 0xD23D, 0, 0,
+ 0, 0, 0x433D, 0, 0xD23E, 0x407D, 0, 0xD23F,
+ 0xD240, 0x4822, 0xD241, 0, 0x643E, 0xD242, 0xD243, 0,
+ 0x4824, 0, 0xD244, 0xD245, 0xD246, 0xD247, 0, 0,
+};
+static const unsigned short utf8_to_euc_E7AE_x0213[] = {
+ 0, 0, 0, 0, 0xD234, 0, 0x4A4F, 0x3255,
+ 0, 0xD235, 0, 0x6435, 0, 0x6432, 0xD236, 0x6437,
+ 0xF354, 0xF355, 0x6436, 0, 0x4773, 0x4C27, 0xD239, 0x3B3B,
+ 0x6430, 0x6439, 0x6434, 0xF356, 0x6433, 0x642F, 0x7963, 0x6431,
+ 0xD23C, 0x3449, 0, 0, 0, 0xD23D, 0, 0,
+ 0, 0, 0x433D, 0, 0xD23E, 0x407D, 0, 0xF358,
+ 0xD240, 0x4822, 0xD241, 0, 0x643E, 0xF359, 0xD243, 0,
+ 0x4824, 0, 0xD244, 0xD245, 0xF35A, 0xD247, 0, 0,
+};
+static const unsigned short utf8_to_euc_E7AF[] = {
+ 0x4061, 0x643B, 0xD248, 0, 0x484F, 0xD249, 0x643F, 0x4A53,
+ 0xD24A, 0x435B, 0xD24B, 0x643A, 0x643C, 0, 0, 0x643D,
+ 0, 0, 0, 0, 0xD24C, 0, 0xD24D, 0xD24E,
+ 0, 0xD24F, 0xD250, 0xD251, 0, 0x6440, 0, 0,
+ 0x3C44, 0, 0, 0, 0x4646, 0x6445, 0x6444, 0,
+ 0xD252, 0x6441, 0xD253, 0, 0, 0x4F36, 0, 0,
+ 0, 0, 0xD254, 0x644A, 0xD255, 0xD256, 0x644E, 0x644B,
+ 0xD257, 0xD258, 0xD259, 0, 0xD25A, 0, 0xD25B, 0,
+};
+static const unsigned short utf8_to_euc_E7AF_x0213[] = {
+ 0x4061, 0x643B, 0xD248, 0, 0x484F, 0xF35B, 0x643F, 0x4A53,
+ 0xD24A, 0x435B, 0xF35C, 0x643A, 0x643C, 0, 0, 0x643D,
+ 0, 0, 0, 0, 0xF35F, 0, 0xF360, 0x7965,
+ 0, 0x7966, 0xF361, 0xD251, 0, 0x6440, 0, 0,
+ 0x3C44, 0, 0, 0, 0x4646, 0x6445, 0x6444, 0,
+ 0xD252, 0x6441, 0xF362, 0, 0, 0x4F36, 0, 0,
+ 0xF363, 0, 0xD254, 0x644A, 0xD255, 0xD256, 0x644E, 0x644B,
+ 0xD257, 0xD258, 0xD259, 0, 0xD25A, 0, 0xD25B, 0,
+};
+static const unsigned short utf8_to_euc_E7B0[] = {
+ 0x6447, 0xD25C, 0xD25D, 0xD25E, 0xD25F, 0, 0xD260, 0x6448,
+ 0, 0xD261, 0, 0xD262, 0xD263, 0x644D, 0xD264, 0xD265,
+ 0, 0x6442, 0x5255, 0x6449, 0x6443, 0, 0, 0x644C,
+ 0, 0xD266, 0, 0xD267, 0, 0, 0, 0x6452,
+ 0xD268, 0x344A, 0, 0x644F, 0, 0xD269, 0xD26A, 0x6450,
+ 0xD26B, 0, 0x6451, 0x6454, 0xD26C, 0, 0, 0,
+ 0, 0xD26D, 0, 0xD26E, 0xD26F, 0, 0xD270, 0x6453,
+ 0x4876, 0xD271, 0xD272, 0, 0, 0x6455, 0x4E7C, 0x4A6D,
+};
+static const unsigned short utf8_to_euc_E7B0_x0213[] = {
+ 0x6447, 0x7967, 0xD25D, 0xF364, 0xD25F, 0, 0xD260, 0x6448,
+ 0, 0xD261, 0, 0xF365, 0xD263, 0x644D, 0xF366, 0xF367,
+ 0, 0x6442, 0x5255, 0x6449, 0x6443, 0, 0, 0x644C,
+ 0, 0xD266, 0, 0xD267, 0, 0, 0x7969, 0x6452,
+ 0x796A, 0x344A, 0, 0x644F, 0, 0xD269, 0xF368, 0x6450,
+ 0xD26B, 0, 0x6451, 0x6454, 0xD26C, 0, 0, 0,
+ 0, 0x7968, 0, 0x796B, 0xD26F, 0, 0x796C, 0x6453,
+ 0x4876, 0xD271, 0xD272, 0, 0, 0x6455, 0x4E7C, 0x4A6D,
+};
+static const unsigned short utf8_to_euc_E7B1[] = {
+ 0x645A, 0, 0, 0x6457, 0, 0, 0xD273, 0,
+ 0, 0, 0xD274, 0, 0x6456, 0x4052, 0, 0x6459,
+ 0x645B, 0xD276, 0xD277, 0xD278, 0x6458, 0xD275, 0x645F, 0,
+ 0x645C, 0xD279, 0xD27A, 0xD27B, 0xD27C, 0xD27D, 0xD27E, 0x645D,
+ 0x6446, 0xD321, 0, 0xD322, 0x645E, 0x6460, 0, 0xD323,
+ 0, 0xD324, 0, 0, 0x6461, 0xD325, 0xD326, 0,
+ 0xD327, 0, 0xD328, 0x4A46, 0, 0x6462, 0, 0,
+ 0, 0xD329, 0, 0, 0xD32A, 0xD32B, 0x4C62, 0,
+};
+static const unsigned short utf8_to_euc_E7B1_x0213[] = {
+ 0x645A, 0, 0, 0x6457, 0, 0xF369, 0xD273, 0,
+ 0, 0, 0xF36A, 0, 0x6456, 0x4052, 0, 0x6459,
+ 0x645B, 0xF36B, 0xD277, 0xD278, 0x6458, 0xD275, 0x645F, 0xF36C,
+ 0x645C, 0x796F, 0xD27A, 0xD27B, 0xD27C, 0xD27D, 0xF36D, 0x645D,
+ 0x6446, 0xF36E, 0, 0xD322, 0x645E, 0x6460, 0, 0xD323,
+ 0, 0xF36F, 0, 0, 0x6461, 0x7970, 0xF370, 0xF371,
+ 0xF372, 0, 0xD328, 0x4A46, 0, 0x6462, 0, 0,
+ 0, 0x7971, 0, 0, 0xD32A, 0xD32B, 0x4C62, 0,
+};
+static const unsigned short utf8_to_euc_E7B2[] = {
+ 0, 0x364E, 0x3729, 0x6463, 0, 0, 0xD32C, 0xD32D,
+ 0, 0x4A34, 0, 0x3F68, 0, 0x4C30, 0, 0xD32E,
+ 0x6464, 0, 0x4E33, 0, 0xD32F, 0x4774, 0, 0x4146,
+ 0x4734, 0, 0, 0x3D4D, 0, 0, 0xD330, 0x3040,
+ 0xD331, 0x6469, 0x6467, 0, 0x6465, 0x3421, 0xD332, 0x3E51,
+ 0x646A, 0, 0, 0x6468, 0, 0x6466, 0x646E, 0,
+ 0xD333, 0x646D, 0x646C, 0x646B, 0, 0, 0xD334, 0xD335,
+ 0, 0x646F, 0xD336, 0xD337, 0xD338, 0x6470, 0x403A, 0xD339,
+};
+static const unsigned short utf8_to_euc_E7B2_x0213[] = {
+ 0, 0x364E, 0x3729, 0x6463, 0, 0, 0xD32C, 0xD32D,
+ 0, 0x4A34, 0, 0x3F68, 0, 0x4C30, 0, 0x7972,
+ 0x6464, 0, 0x4E33, 0, 0x7973, 0x4774, 0, 0x4146,
+ 0x4734, 0, 0, 0x3D4D, 0, 0, 0xD330, 0x3040,
+ 0x7974, 0x6469, 0x6467, 0, 0x6465, 0x3421, 0xF376, 0x3E51,
+ 0x646A, 0, 0, 0x6468, 0, 0x6466, 0x646E, 0,
+ 0xD333, 0x646D, 0x646C, 0x646B, 0, 0, 0xF378, 0xF379,
+ 0, 0x646F, 0xD336, 0xD337, 0x7975, 0x6470, 0x403A, 0xF37A,
+};
+static const unsigned short utf8_to_euc_E7B3[] = {
+ 0x6471, 0, 0x6473, 0, 0xD33A, 0x6472, 0, 0xD33B,
+ 0xD33C, 0xD33D, 0x3852, 0, 0, 0xD33E, 0x4138, 0xD33F,
+ 0, 0, 0x6475, 0xD340, 0xD341, 0xD342, 0x457C, 0xD343,
+ 0x6474, 0xD344, 0xD345, 0, 0x6476, 0xD346, 0x4A35, 0x416C,
+ 0x3947, 0, 0x6477, 0, 0, 0, 0xD347, 0x4E48,
+ 0, 0xD348, 0, 0xD349, 0, 0, 0, 0x6479,
+ 0, 0, 0x647A, 0, 0x647B, 0xD34A, 0x647C, 0,
+ 0x3B65, 0, 0x647D, 0x374F, 0, 0, 0x356A, 0,
+};
+static const unsigned short utf8_to_euc_E7B3_x0213[] = {
+ 0x6471, 0, 0x6473, 0, 0xF37C, 0x6472, 0, 0xD33B,
+ 0xF37E, 0xD33D, 0x3852, 0, 0, 0xF421, 0x4138, 0xD33F,
+ 0, 0, 0x6475, 0xD340, 0xD341, 0x7976, 0x457C, 0xF423,
+ 0x6474, 0x7977, 0xD345, 0, 0x6476, 0x7978, 0x4A35, 0x416C,
+ 0x3947, 0, 0x6477, 0, 0, 0, 0xF425, 0x4E48,
+ 0, 0xD348, 0, 0xF426, 0, 0, 0, 0x6479,
+ 0, 0, 0x647A, 0, 0x647B, 0xF428, 0x647C, 0,
+ 0x3B65, 0, 0x647D, 0x374F, 0, 0, 0x356A, 0,
+};
+static const unsigned short utf8_to_euc_E7B4[] = {
+ 0x352A, 0, 0x6521, 0xD34B, 0x4C73, 0x3948, 0x647E, 0xD34C,
+ 0xD34D, 0xD34E, 0x6524, 0x4C66, 0, 0x473C, 0, 0xD34F,
+ 0x4933, 0xD350, 0xD351, 0xD352, 0x3D63, 0x6523, 0xD353, 0x3C53,
+ 0x3949, 0x3B66, 0x3569, 0x4A36, 0x6522, 0xD354, 0xD355, 0,
+ 0x4147, 0x4B42, 0x3A77, 0xD356, 0, 0, 0xD357, 0,
+ 0, 0, 0xD358, 0x3B67, 0x445D, 0xD359, 0x6527, 0x4E5F,
+ 0x3A59, 0xD35A, 0x6528, 0x3F42, 0, 0x652A, 0, 0,
+ 0, 0x3E52, 0x3A30, 0, 0xD35B, 0xD35C, 0xD35D, 0x6529,
+};
+static const unsigned short utf8_to_euc_E7B4_x0213[] = {
+ 0x352A, 0, 0x6521, 0xF429, 0x4C73, 0x3948, 0x647E, 0x7979,
+ 0x797A, 0xF42A, 0x6524, 0x4C66, 0, 0x473C, 0, 0xD34F,
+ 0x4933, 0xD350, 0xF42C, 0x797B, 0x3D63, 0x6523, 0xD353, 0x3C53,
+ 0x3949, 0x3B66, 0x3569, 0x4A36, 0x6522, 0x797C, 0xF42D, 0,
+ 0x4147, 0x4B42, 0x3A77, 0x797D, 0, 0, 0xD357, 0,
+ 0, 0, 0xD358, 0x3B67, 0x445D, 0xD359, 0x6527, 0x4E5F,
+ 0x3A59, 0x797E, 0x6528, 0x3F42, 0, 0x652A, 0, 0,
+ 0, 0x3E52, 0x3A30, 0, 0xD35B, 0xF430, 0xF431, 0x6529,
+};
+static const unsigned short utf8_to_euc_E7B5[] = {
+ 0xD35E, 0xD35F, 0x3D2A, 0x383E, 0x4148, 0x6525, 0x652B, 0xD360,
+ 0xD361, 0, 0, 0x6526, 0x3750, 0xD362, 0x652E, 0x6532,
+ 0x376B, 0xD363, 0, 0xD364, 0, 0, 0x652D, 0xD365,
+ 0, 0xD366, 0xD367, 0x6536, 0xD368, 0xD369, 0x394A, 0,
+ 0, 0x4D6D, 0x303C, 0x6533, 0, 0xD36A, 0x356B, 0xD36B,
+ 0x6530, 0, 0xD36C, 0, 0, 0, 0x6531, 0,
+ 0xD36D, 0x457D, 0x652F, 0x652C, 0, 0x3328, 0x4064, 0,
+ 0xD36E, 0x3828, 0xD36F, 0xD370, 0, 0x6538, 0, 0xD371,
+};
+static const unsigned short utf8_to_euc_E7B5_x0213[] = {
+ 0xF432, 0x7A21, 0x3D2A, 0x383E, 0x4148, 0x6525, 0x652B, 0xF433,
+ 0x7A22, 0, 0, 0x6526, 0x3750, 0xD362, 0x652E, 0x6532,
+ 0x376B, 0xD363, 0, 0x7A23, 0, 0, 0x652D, 0xD365,
+ 0, 0xF437, 0xF438, 0x6536, 0x7A24, 0xD369, 0x394A, 0,
+ 0, 0x4D6D, 0x303C, 0x6533, 0, 0xD36A, 0x356B, 0xD36B,
+ 0x6530, 0, 0xF439, 0, 0, 0, 0x6531, 0,
+ 0xF43A, 0x457D, 0x652F, 0x652C, 0, 0x3328, 0x4064, 0,
+ 0xD36E, 0x3828, 0x7A25, 0xD370, 0, 0x6538, 0, 0xF43C,
+};
+static const unsigned short utf8_to_euc_E7B6[] = {
+ 0, 0xD372, 0xD373, 0xD374, 0, 0xD375, 0xD376, 0,
+ 0xD377, 0x6535, 0, 0xD378, 0xD379, 0xD37A, 0, 0x6537,
+ 0, 0xD37B, 0, 0x6534, 0, 0, 0xD37C, 0xD37D,
+ 0, 0x3751, 0x4233, 0x6539, 0x416E, 0xD37E, 0xD421, 0x6546,
+ 0xF45C, 0, 0x6542, 0x653C, 0, 0, 0xD422, 0xD423,
+ 0, 0, 0xD424, 0x6540, 0x3C7A, 0x305D, 0x653B, 0x6543,
+ 0x6547, 0x394B, 0x4C56, 0xD425, 0x4456, 0x653D, 0xD426, 0xD427,
+ 0x6545, 0xD428, 0x653A, 0x433E, 0, 0x653F, 0x303D, 0x4C4A,
+};
+static const unsigned short utf8_to_euc_E7B6_x0213[] = {
+ 0, 0xD372, 0xD373, 0x7A26, 0, 0xD375, 0xF43E, 0,
+ 0xF43F, 0x6535, 0, 0x7A27, 0xF440, 0xD37A, 0, 0x6537,
+ 0, 0xD37B, 0, 0x6534, 0, 0, 0xD37C, 0xF441,
+ 0, 0x3751, 0x4233, 0x6539, 0x416E, 0xF443, 0xD421, 0x6546,
+ 0x7A28, 0, 0x6542, 0x653C, 0, 0, 0x7A29, 0xF444,
+ 0, 0, 0xF445, 0x6540, 0x3C7A, 0x305D, 0x653B, 0x6543,
+ 0x6547, 0x394B, 0x4C56, 0xD425, 0x4456, 0x653D, 0xF446, 0xF447,
+ 0x6545, 0xD428, 0x653A, 0x433E, 0, 0x653F, 0x303D, 0x4C4A,
+};
+static const unsigned short utf8_to_euc_E7B7[] = {
+ 0, 0, 0xD429, 0xD42A, 0xD42B, 0xD42C, 0xD42D, 0x653E,
+ 0, 0, 0x365B, 0x486C, 0xD42E, 0xD42F, 0xD430, 0x416D,
+ 0, 0x4E50, 0x3D6F, 0, 0, 0x656E, 0xF45D, 0xD431,
+ 0x6548, 0xD432, 0x407E, 0, 0x6544, 0x6549, 0x654B, 0,
+ 0x4479, 0x654E, 0xD434, 0, 0x654A, 0xD435, 0xD436, 0,
+ 0x4A54, 0x344B, 0xD437, 0xD438, 0x4C4B, 0xD439, 0, 0x305E,
+ 0, 0xD43A, 0x654D, 0, 0x4E7D, 0xD43B, 0xD43C, 0,
+ 0, 0xD43D, 0xD43E, 0x654C, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E7B7_x0213[] = {
+ 0xF448, 0, 0x7A2A, 0xD42A, 0xD42B, 0xD42C, 0xD42D, 0x653E,
+ 0, 0, 0x365B, 0x486C, 0x7A2B, 0xD42F, 0xD430, 0x416D,
+ 0, 0x4E50, 0x3D6F, 0, 0, 0x656E, 0x7A2C, 0xF449,
+ 0x6548, 0xF44A, 0x407E, 0, 0x6544, 0x6549, 0x654B, 0,
+ 0x4479, 0x654E, 0xD434, 0x7A2D, 0x654A, 0xD435, 0xF44B, 0,
+ 0x4A54, 0x344B, 0xD437, 0xD438, 0x4C4B, 0xD439, 0, 0x305E,
+ 0, 0xF44C, 0x654D, 0, 0x4E7D, 0xD43B, 0xD43C, 0,
+ 0, 0xF44D, 0xD43E, 0x654C, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E7B8[] = {
+ 0xD433, 0x316F, 0, 0, 0x466C, 0x654F, 0, 0,
+ 0xD43F, 0x6556, 0x6550, 0x6557, 0, 0, 0, 0,
+ 0xD440, 0xD441, 0x6553, 0, 0, 0xD442, 0, 0xD443,
+ 0, 0, 0, 0x477B, 0xD444, 0xD445, 0x3C4A, 0x6555,
+ 0xD446, 0x6552, 0x6558, 0x6551, 0, 0, 0x3D44, 0xD447,
+ 0xD448, 0, 0, 0x4B25, 0xD449, 0xD44A, 0x3D4C, 0xD44B,
+ 0, 0x6554, 0x6560, 0xD44C, 0, 0x655C, 0xD44D, 0x655F,
+ 0, 0x655D, 0x6561, 0x655B, 0, 0x6541, 0x4053, 0xD44E,
+};
+static const unsigned short utf8_to_euc_E7B8_x0213[] = {
+ 0xD433, 0x316F, 0, 0, 0x466C, 0x654F, 0, 0,
+ 0x7A30, 0x6556, 0x6550, 0x6557, 0, 0, 0, 0,
+ 0xF451, 0x7A31, 0x6553, 0, 0, 0x7A32, 0, 0xF452,
+ 0, 0, 0, 0x477B, 0xD444, 0xF453, 0x3C4A, 0x6555,
+ 0xF454, 0x6552, 0x6558, 0x6551, 0, 0, 0x3D44, 0xF455,
+ 0x7A2F, 0, 0, 0x4B25, 0xF456, 0xD44A, 0x3D4C, 0xD44B,
+ 0, 0x6554, 0x6560, 0xD44C, 0, 0x655C, 0xD44D, 0x655F,
+ 0, 0x655D, 0x6561, 0x655B, 0, 0x6541, 0x4053, 0xD44E,
+};
+static const unsigned short utf8_to_euc_E7B9[] = {
+ 0, 0x484B, 0, 0x655E, 0xD44F, 0xD450, 0x6559, 0xD451,
+ 0, 0, 0x4121, 0x3752, 0, 0x3D2B, 0xD452, 0,
+ 0xD453, 0, 0xD454, 0, 0x3F25, 0x4136, 0x6564, 0,
+ 0xD455, 0x6566, 0x6567, 0, 0, 0x6563, 0x6565, 0xD456,
+ 0, 0xD457, 0xD458, 0, 0, 0xD459, 0x655A, 0x6562,
+ 0, 0x656A, 0x6569, 0xD45A, 0, 0x4B7A, 0xD45B, 0xD45C,
+ 0x372B, 0, 0, 0xD45D, 0, 0, 0, 0,
+ 0xD45E, 0x6568, 0, 0x656C, 0x656B, 0x656F, 0xD45F, 0x6571,
+};
+static const unsigned short utf8_to_euc_E7B9_x0213[] = {
+ 0, 0x484B, 0, 0x655E, 0xD44F, 0xF457, 0x6559, 0x7A34,
+ 0, 0, 0x4121, 0x3752, 0, 0x3D2B, 0xD452, 0,
+ 0xD453, 0, 0x7A35, 0, 0x3F25, 0x4136, 0x6564, 0,
+ 0xD455, 0x6566, 0x6567, 0, 0, 0x6563, 0x6565, 0xD456,
+ 0, 0x7A36, 0xD458, 0, 0, 0xD459, 0x655A, 0x6562,
+ 0, 0x656A, 0x6569, 0x7E7E, 0, 0x4B7A, 0xD45B, 0xD45C,
+ 0x372B, 0, 0, 0xF458, 0, 0xF459, 0, 0,
+ 0xD45E, 0x6568, 0, 0x656C, 0x656B, 0x656F, 0xF45A, 0x6571,
+};
+static const unsigned short utf8_to_euc_E7BA[] = {
+ 0, 0xD460, 0x3B3C, 0x656D, 0, 0, 0xD461, 0xD462,
+ 0x6572, 0x6573, 0xD463, 0, 0x6574, 0xD464, 0x657A, 0x453B,
+ 0x6576, 0xD465, 0x6575, 0x6577, 0x6578, 0xD466, 0x6579, 0,
+ 0xD467, 0, 0xD468, 0x657B, 0x657C, 0xD469, 0xD46A, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E7BA_x0213[] = {
+ 0, 0xD460, 0x3B3C, 0x656D, 0, 0, 0xF45B, 0xF45C,
+ 0x6572, 0x6573, 0x7A37, 0, 0x6574, 0x7A38, 0x657A, 0x453B,
+ 0x6576, 0xF45E, 0x6575, 0x6577, 0x6578, 0xD466, 0x6579, 0,
+ 0xF45F, 0, 0xF460, 0x657B, 0x657C, 0xD469, 0xD46A, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E7BC[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x344C, 0,
+ 0x657D, 0, 0x657E, 0xD46C, 0xD46B, 0xD46D, 0xD46E, 0xD46F,
+};
+static const unsigned short utf8_to_euc_E7BC_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x344C, 0,
+ 0x657D, 0, 0x657E, 0xF463, 0xF462, 0xD46D, 0xF464, 0xD46F,
+};
+static const unsigned short utf8_to_euc_E7BD[] = {
+ 0, 0, 0, 0xD470, 0xD471, 0x6621, 0, 0xD472,
+ 0, 0, 0, 0, 0x6622, 0x6623, 0x6624, 0xD473,
+ 0x6625, 0x6626, 0xD474, 0xD475, 0x6628, 0x6627, 0, 0,
+ 0x6629, 0, 0, 0xD476, 0xD477, 0xD478, 0, 0x662A,
+ 0x662B, 0xD479, 0, 0xD47A, 0xD47B, 0xD47C, 0xD47D, 0x662E,
+ 0x662C, 0x662D, 0x3A61, 0x3753, 0, 0xD47E, 0x4356, 0,
+ 0x4833, 0xD521, 0x3D70, 0, 0, 0x474D, 0, 0x486D,
+ 0x662F, 0x586D, 0, 0, 0, 0xD522, 0xD523, 0xD524,
+};
+static const unsigned short utf8_to_euc_E7BD_x0213[] = {
+ 0, 0, 0, 0xF465, 0xF466, 0x6621, 0, 0x7A39,
+ 0, 0, 0, 0, 0x6622, 0x6623, 0x6624, 0xF467,
+ 0x6625, 0x6626, 0xF46A, 0xD475, 0x6628, 0x6627, 0, 0,
+ 0x6629, 0, 0, 0xD476, 0xD477, 0xD478, 0, 0x662A,
+ 0x662B, 0xF46C, 0, 0xF46D, 0xF46E, 0xD47C, 0xD47D, 0x662E,
+ 0x662C, 0x662D, 0x3A61, 0x3753, 0, 0xF46F, 0x4356, 0,
+ 0x4833, 0xD521, 0x3D70, 0, 0, 0x474D, 0, 0x486D,
+ 0x662F, 0x586D, 0, 0, 0, 0xF470, 0xF471, 0xD524,
+};
+static const unsigned short utf8_to_euc_E7BE[] = {
+ 0xD525, 0, 0x6630, 0x6632, 0, 0x4D65, 0x6631, 0x6634,
+ 0x6633, 0, 0x4D53, 0xD526, 0x6635, 0xD527, 0x487E, 0xD528,
+ 0xD529, 0xD52A, 0, 0, 0x6636, 0, 0xD52B, 0xD52C,
+ 0, 0, 0x6639, 0, 0xD52D, 0x6638, 0x6637, 0,
+ 0, 0xD52E, 0xD52F, 0x663A, 0x3732, 0, 0xD530, 0,
+ 0x4122, 0x3541, 0xD531, 0, 0, 0xD532, 0x663E, 0x663B,
+ 0, 0, 0x663C, 0, 0xD533, 0, 0x663F, 0,
+ 0x6640, 0x663D, 0, 0, 0xD534, 0x3129, 0, 0xD535,
+};
+static const unsigned short utf8_to_euc_E7BE_x0213[] = {
+ 0xD525, 0, 0x6630, 0x6632, 0, 0x4D65, 0x6631, 0x6634,
+ 0x6633, 0, 0x4D53, 0xD526, 0x6635, 0xD527, 0x487E, 0xD528,
+ 0xF473, 0x7A3B, 0, 0, 0x6636, 0, 0xF476, 0x7A3C,
+ 0, 0, 0x6639, 0, 0xF477, 0x6638, 0x6637, 0,
+ 0, 0, 0xD52F, 0x663A, 0x3732, 0, 0xD530, 0,
+ 0x4122, 0x3541, 0xD531, 0, 0, 0xF478, 0x663E, 0x663B,
+ 0, 0, 0x663C, 0, 0xD533, 0, 0x663F, 0,
+ 0x6640, 0x663D, 0, 0, 0xD534, 0x3129, 0, 0x7A3D,
+};
+static const unsigned short utf8_to_euc_E7BF[] = {
+ 0xD536, 0x3227, 0, 0xD537, 0, 0x6642, 0x6643, 0,
+ 0xD538, 0, 0x6644, 0, 0x4D62, 0, 0xD539, 0xD53A,
+ 0, 0, 0x3D2C, 0, 0x6646, 0x6645, 0, 0,
+ 0, 0, 0, 0xD53B, 0, 0, 0, 0xD53C,
+ 0x3F69, 0x6647, 0, 0xD53D, 0, 0xD53E, 0x6648, 0,
+ 0xD53F, 0x6649, 0, 0x3465, 0xD540, 0, 0xD541, 0xD542,
+ 0x344D, 0, 0xD543, 0x664A, 0, 0, 0, 0,
+ 0, 0x664B, 0xD544, 0x4B5D, 0x4D63, 0xD545, 0xD546, 0xD547,
+};
+static const unsigned short utf8_to_euc_E7BF_x0213[] = {
+ 0xD536, 0x3227, 0, 0xF47A, 0, 0x6642, 0x6643, 0,
+ 0xD538, 0, 0x6644, 0, 0x4D62, 0, 0x7A3E, 0xF47B,
+ 0, 0, 0x3D2C, 0, 0x6646, 0x6645, 0, 0,
+ 0, 0, 0, 0x7A3F, 0, 0, 0, 0x7A40,
+ 0x3F69, 0x6647, 0, 0xF47C, 0, 0xF47D, 0x6648, 0,
+ 0xD53F, 0x6649, 0, 0x3465, 0x7A41, 0, 0x7A42, 0xF47E,
+ 0x344D, 0, 0xF521, 0x664A, 0, 0, 0, 0,
+ 0, 0x664B, 0x7A43, 0x4B5D, 0x4D63, 0xD545, 0xD546, 0xD547,
+};
+static const unsigned short utf8_to_euc_E880[] = {
+ 0x4D54, 0x4F37, 0, 0x394D, 0x664E, 0x3C54, 0x664D, 0xD548,
+ 0xD549, 0, 0xD54A, 0x664F, 0x3C29, 0xD54B, 0xD54C, 0xD54D,
+ 0x4251, 0xD54E, 0x6650, 0xD54F, 0xD550, 0x394C, 0xD551, 0x4C57,
+ 0x6651, 0x6652, 0, 0, 0x6653, 0xD552, 0xD553, 0xD554,
+ 0xD555, 0x6654, 0, 0, 0xD556, 0, 0xD557, 0,
+ 0x6655, 0, 0, 0, 0xD558, 0, 0xD559, 0,
+ 0xD55A, 0, 0, 0x3C2A, 0xD55B, 0xD55C, 0x4C6D, 0xD55D,
+ 0, 0xD55E, 0xD55F, 0x6657, 0xD560, 0x433F, 0xD561, 0x6656,
+};
+static const unsigned short utf8_to_euc_E880_x0213[] = {
+ 0x4D54, 0x4F37, 0xF522, 0x394D, 0x664E, 0x3C54, 0x664D, 0xD548,
+ 0xF524, 0, 0xF523, 0x664F, 0x3C29, 0xD54B, 0xF525, 0xD54D,
+ 0x4251, 0xF526, 0x6650, 0xD54F, 0x7A45, 0x394C, 0xF527, 0x4C57,
+ 0x6651, 0x6652, 0, 0, 0x6653, 0xD552, 0xD553, 0xD554,
+ 0xD555, 0x6654, 0, 0, 0xF528, 0, 0x7A46, 0,
+ 0x6655, 0, 0, 0, 0xF529, 0, 0xD559, 0,
+ 0xF52A, 0, 0, 0x3C2A, 0xD55B, 0x7A47, 0x4C6D, 0x7A48,
+ 0, 0xD55E, 0xD55F, 0x6657, 0x7A49, 0x433F, 0xD561, 0x6656,
+};
+static const unsigned short utf8_to_euc_E881[] = {
+ 0xD562, 0, 0, 0, 0xD563, 0, 0x6659, 0,
+ 0, 0, 0x6658, 0, 0, 0, 0, 0,
+ 0, 0, 0x665A, 0, 0, 0, 0x403B, 0,
+ 0x665B, 0, 0x665C, 0, 0, 0, 0x4A39, 0x665D,
+ 0xD564, 0x416F, 0x665E, 0, 0xD565, 0, 0xD566, 0,
+ 0x665F, 0, 0, 0, 0, 0xD567, 0, 0x4E7E,
+ 0x6662, 0xD568, 0x6661, 0x6660, 0x4430, 0xD569, 0x6663, 0x3F26,
+ 0, 0x6664, 0, 0, 0, 0x6665, 0x4F38, 0x6666,
+};
+static const unsigned short utf8_to_euc_E881_x0213[] = {
+ 0xD562, 0, 0, 0xF52B, 0xD563, 0, 0x6659, 0,
+ 0, 0, 0x6658, 0, 0, 0, 0, 0,
+ 0, 0, 0x665A, 0, 0, 0, 0x403B, 0,
+ 0x665B, 0, 0x665C, 0, 0, 0, 0x4A39, 0x665D,
+ 0xD564, 0x416F, 0x665E, 0, 0xD565, 0, 0xF52C, 0,
+ 0x665F, 0, 0, 0, 0, 0xD567, 0, 0x4E7E,
+ 0x6662, 0xF52D, 0x6661, 0x6660, 0x4430, 0xF52E, 0x6663, 0x3F26,
+ 0, 0x6664, 0, 0xF52F, 0, 0x6665, 0x4F38, 0x6666,
+};
+static const unsigned short utf8_to_euc_E882[] = {
+ 0, 0xD56A, 0, 0, 0x6667, 0x6669, 0x6668, 0x4825,
+ 0xD56B, 0x4679, 0, 0x4F3E, 0x4829, 0, 0xD56C, 0,
+ 0, 0, 0, 0x666B, 0, 0, 0x3E53, 0,
+ 0x492A, 0, 0x666C, 0x666A, 0xD56D, 0x344E, 0xD56E, 0,
+ 0, 0x3854, 0x3B68, 0, 0, 0x486E, 0xD56F, 0xD570,
+ 0, 0x382A, 0x4B43, 0xD571, 0x666F, 0x666D, 0, 0x394E,
+ 0, 0x394F, 0x3069, 0, 0x3A68, 0, 0, 0,
+ 0xD572, 0xD573, 0x4759, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E882_x0213[] = {
+ 0, 0xD56A, 0, 0, 0x6667, 0x6669, 0x6668, 0x4825,
+ 0xD56B, 0x4679, 0, 0x4F3E, 0x4829, 0, 0xD56C, 0,
+ 0, 0, 0, 0x666B, 0, 0, 0x3E53, 0,
+ 0x492A, 0xF530, 0x666C, 0x666A, 0xF531, 0x344E, 0xD56E, 0,
+ 0, 0x3854, 0x3B68, 0, 0xF532, 0x486E, 0xD56F, 0xF533,
+ 0, 0x382A, 0x4B43, 0xD571, 0x666F, 0x666D, 0, 0x394E,
+ 0, 0x394F, 0x3069, 0, 0x3A68, 0, 0, 0,
+ 0xF534, 0xD573, 0x4759, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E883[] = {
+ 0, 0, 0, 0x305F, 0x6674, 0, 0x4340, 0,
+ 0xD574, 0, 0, 0, 0x4758, 0xD575, 0x425B, 0xD576,
+ 0, 0, 0xD577, 0, 0xD578, 0xD579, 0x6676, 0xD57A,
+ 0xD57B, 0x6672, 0x6675, 0x6670, 0, 0x6673, 0x4B26, 0,
+ 0xD57C, 0x3855, 0, 0, 0x307D, 0x6671, 0, 0,
+ 0, 0, 0, 0, 0, 0xD57D, 0xD57E, 0x6678,
+ 0xD621, 0x6679, 0xD622, 0xD623, 0x4639, 0, 0xD624, 0,
+ 0x363B, 0xD625, 0xD626, 0, 0x6726, 0x473D, 0xD627, 0,
+};
+static const unsigned short utf8_to_euc_E883_x0213[] = {
+ 0, 0, 0, 0x305F, 0x6674, 0xF536, 0x4340, 0,
+ 0xD574, 0, 0x7A4A, 0, 0x4758, 0xD575, 0x425B, 0xD576,
+ 0, 0, 0xD577, 0, 0xD578, 0xF537, 0x6676, 0x7A4B,
+ 0xF538, 0x6672, 0x6675, 0x6670, 0, 0x6673, 0x4B26, 0,
+ 0x7A4C, 0x3855, 0, 0, 0x307D, 0x6671, 0xF539, 0,
+ 0, 0, 0, 0, 0, 0xD57D, 0xD57E, 0x6678,
+ 0xD621, 0x6679, 0xD622, 0x7A4D, 0x4639, 0xF53C, 0xD624, 0,
+ 0x363B, 0xD625, 0xD626, 0xF53D, 0x6726, 0x473D, 0xD627, 0,
+};
+static const unsigned short utf8_to_euc_E884[] = {
+ 0, 0, 0x3B69, 0xD628, 0, 0x363C, 0x4048, 0x4F46,
+ 0x4C2E, 0x6677, 0x4054, 0xD629, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xD62A, 0xD62B,
+ 0xD62C, 0, 0x3553, 0x667A, 0xD62D, 0, 0xD62E, 0,
+ 0xD62F, 0, 0, 0x667C, 0xD630, 0, 0, 0xD631,
+ 0, 0x667B, 0, 0, 0xD632, 0, 0, 0x667D,
+ 0xD633, 0x4326, 0, 0x473E, 0, 0xD634, 0, 0,
+ 0, 0x4431, 0xD635, 0, 0xD636, 0, 0x6723, 0,
+};
+static const unsigned short utf8_to_euc_E884_x0213[] = {
+ 0, 0, 0x3B69, 0xD628, 0, 0x363C, 0x4048, 0x4F46,
+ 0x4C2E, 0x6677, 0x4054, 0xD629, 0, 0xF53B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xF540, 0xD62B,
+ 0x7A4E, 0, 0x3553, 0x667A, 0xD62D, 0, 0xF541, 0,
+ 0xD62F, 0, 0, 0x667C, 0xF543, 0, 0, 0xF544,
+ 0, 0x667B, 0, 0, 0xF545, 0, 0, 0x667D,
+ 0xD633, 0x4326, 0, 0x473E, 0, 0xF53F, 0, 0,
+ 0, 0x4431, 0xD635, 0, 0xD636, 0xF547, 0x6723, 0,
+};
+static const unsigned short utf8_to_euc_E885[] = {
+ 0, 0, 0, 0, 0, 0xD637, 0x6722, 0xD638,
+ 0, 0, 0xD639, 0x667E, 0xD63A, 0, 0x3F55, 0,
+ 0x4965, 0x6725, 0xD63B, 0x6724, 0x3950, 0x4F53, 0, 0xD63C,
+ 0, 0, 0, 0, 0, 0, 0, 0x6735,
+ 0xD63D, 0xD63E, 0, 0, 0, 0x6729, 0x672A, 0xD63F,
+ 0xD640, 0xD641, 0, 0x3C70, 0, 0xD642, 0x6728, 0xD643,
+ 0x3978, 0x6727, 0, 0, 0x672B, 0, 0, 0xD644,
+ 0x4432, 0x4A22, 0x4123, 0, 0, 0, 0, 0x425C,
+};
+static const unsigned short utf8_to_euc_E885_x0213[] = {
+ 0, 0, 0, 0, 0, 0xD637, 0x6722, 0xD638,
+ 0, 0, 0x7A4F, 0x667E, 0xD63A, 0, 0x3F55, 0,
+ 0x4965, 0x6725, 0xD63B, 0x6724, 0x3950, 0x4F53, 0, 0xD63C,
+ 0, 0, 0, 0, 0, 0, 0, 0x6735,
+ 0x7A50, 0xD63E, 0, 0, 0, 0x6729, 0x672A, 0x7A51,
+ 0x7A52, 0xF549, 0, 0x3C70, 0, 0x7A53, 0x6728, 0xD643,
+ 0x3978, 0x6727, 0, 0, 0x672B, 0, 0, 0xD644,
+ 0x4432, 0x4A22, 0x4123, 0, 0, 0, 0, 0x425C,
+};
+static const unsigned short utf8_to_euc_E886[] = {
+ 0x672F, 0xD645, 0x6730, 0x672C, 0xD647, 0xD648, 0xD649, 0,
+ 0x672D, 0, 0x672E, 0xD64A, 0, 0, 0xD64B, 0x3951,
+ 0xD646, 0, 0, 0x6736, 0, 0x6732, 0xD64C, 0,
+ 0xD64D, 0, 0x4966, 0xD64E, 0x4B6C, 0x4928, 0xD64F, 0,
+ 0x6731, 0, 0xD650, 0x6734, 0x6733, 0, 0, 0,
+ 0x4B44, 0x6737, 0, 0, 0, 0, 0xD651, 0,
+ 0x6738, 0, 0xD652, 0x4137, 0xD653, 0x6739, 0, 0,
+ 0x673B, 0, 0x673F, 0xD654, 0, 0x673C, 0x673A, 0x473F,
+};
+static const unsigned short utf8_to_euc_E886_x0213[] = {
+ 0x672F, 0xF54B, 0x6730, 0x672C, 0xF54D, 0xF54E, 0xD649, 0,
+ 0x672D, 0, 0x672E, 0xD64A, 0, 0, 0xD64B, 0x3951,
+ 0xD646, 0, 0, 0x6736, 0, 0x6732, 0xD64C, 0,
+ 0xF550, 0, 0x4966, 0xD64E, 0x4B6C, 0x4928, 0xD64F, 0,
+ 0x6731, 0, 0xD650, 0x6734, 0x6733, 0, 0, 0,
+ 0x4B44, 0x6737, 0, 0, 0, 0, 0xD651, 0,
+ 0x6738, 0, 0xF551, 0x4137, 0xD653, 0x6739, 0, 0,
+ 0x673B, 0, 0x673F, 0x7A54, 0, 0x673C, 0x673A, 0x473F,
+};
+static const unsigned short utf8_to_euc_E887[] = {
+ 0x673D, 0, 0x673E, 0xD656, 0, 0xD657, 0x3232, 0,
+ 0x6745, 0x6740, 0xD658, 0xD655, 0, 0x6741, 0xD659, 0xD65A,
+ 0, 0x6742, 0, 0x4221, 0, 0xD65B, 0, 0xD65C,
+ 0x6744, 0x6743, 0x6746, 0xD65D, 0, 0xD65E, 0xD65F, 0x6747,
+ 0x6748, 0xD660, 0, 0x3F43, 0xD661, 0x3269, 0, 0x6749,
+ 0x4E57, 0, 0x3C2B, 0xD662, 0xD663, 0x3D2D, 0, 0,
+ 0xD664, 0xD665, 0xD666, 0x3B6A, 0x4357, 0xD667, 0xD668, 0,
+ 0xD669, 0xD66A, 0x674A, 0x674B, 0x3131, 0xD66B, 0x674C, 0xD66C,
+};
+static const unsigned short utf8_to_euc_E887_x0213[] = {
+ 0x673D, 0xF552, 0x673E, 0xF553, 0, 0xD657, 0x3232, 0,
+ 0x6745, 0x6740, 0x7A55, 0xD655, 0, 0x6741, 0xD659, 0x7A56,
+ 0, 0x6742, 0, 0x4221, 0, 0xD65B, 0xF554, 0x7A57,
+ 0x6744, 0x6743, 0x6746, 0xF555, 0, 0xD65E, 0xD65F, 0x6747,
+ 0x6748, 0xD660, 0, 0x3F43, 0xF557, 0x3269, 0, 0x6749,
+ 0x4E57, 0, 0x3C2B, 0xD662, 0xF559, 0x3D2D, 0, 0,
+ 0xD664, 0xD665, 0xD666, 0x3B6A, 0x4357, 0xD667, 0xD668, 0,
+ 0xD669, 0xD66A, 0x674A, 0x674B, 0x3131, 0xF55B, 0x674C, 0xF55C,
+};
+static const unsigned short utf8_to_euc_E888[] = {
+ 0xD66D, 0x674D, 0x674E, 0xD66E, 0, 0x674F, 0, 0x6750,
+ 0x363D, 0x5A2A, 0x6751, 0, 0x4065, 0x6752, 0x3C4B, 0xD66F,
+ 0x6753, 0, 0x5030, 0xD670, 0xD671, 0, 0x6754, 0x4A5E,
+ 0x345C, 0xD672, 0xD673, 0x4124, 0x3D58, 0xD674, 0x4971, 0x3D2E,
+ 0, 0xD675, 0xD676, 0, 0, 0, 0, 0,
+ 0xD677, 0x6755, 0x3952, 0x6756, 0x484C, 0, 0x6764, 0,
+ 0, 0, 0xD678, 0x6758, 0xD679, 0x4249, 0x4775, 0x383F,
+ 0x6757, 0x4125, 0xD67A, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E888_x0213[] = {
+ 0xD66D, 0x674D, 0x674E, 0xD66E, 0xF55E, 0x674F, 0, 0x6750,
+ 0x363D, 0x5A2A, 0x6751, 0, 0x4065, 0x6752, 0x3C4B, 0xD66F,
+ 0x6753, 0, 0x5030, 0xD670, 0xD671, 0, 0x6754, 0x4A5E,
+ 0x345C, 0xF560, 0xD673, 0x4124, 0x3D58, 0xD674, 0x4971, 0x3D2E,
+ 0, 0xF561, 0xF562, 0, 0, 0, 0, 0,
+ 0xD677, 0x6755, 0x3952, 0x6756, 0x484C, 0, 0x6764, 0,
+ 0, 0, 0xF564, 0x6758, 0xF565, 0x4249, 0x4775, 0x383F,
+ 0x6757, 0x4125, 0xD67A, 0, 0xF566, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E889[] = {
+ 0x6759, 0, 0, 0xD67B, 0xD67C, 0xD67D, 0xD67E, 0x447A,
+ 0, 0, 0, 0xD721, 0, 0, 0xD722, 0xD723,
+ 0, 0xD724, 0, 0, 0, 0, 0xD725, 0,
+ 0x675B, 0x675A, 0x675D, 0, 0xD726, 0x675C, 0, 0x675E,
+ 0xD727, 0, 0x6760, 0xD728, 0x675F, 0, 0x344F, 0xD729,
+ 0x6761, 0, 0x6762, 0x6763, 0, 0xD72A, 0x3A31, 0x4E49,
+ 0, 0x6765, 0x3F27, 0, 0xD72B, 0, 0x3170, 0x6766,
+ 0x6767, 0, 0, 0xD72C, 0, 0xD72D, 0x6768, 0xD72E,
+};
+static const unsigned short utf8_to_euc_E889_x0213[] = {
+ 0x6759, 0, 0, 0xD67B, 0xD67C, 0xF569, 0xF567, 0x447A,
+ 0, 0xF568, 0, 0xF56B, 0, 0, 0xD722, 0xF56D,
+ 0, 0xD724, 0, 0, 0, 0, 0xD725, 0xF56F,
+ 0x675B, 0x675A, 0x675D, 0, 0xF571, 0x675C, 0, 0x675E,
+ 0x7A5B, 0, 0x6760, 0xF572, 0x675F, 0, 0x344F, 0xD729,
+ 0x6761, 0, 0x6762, 0x6763, 0, 0xD72A, 0x3A31, 0x4E49,
+ 0, 0x6765, 0x3F27, 0, 0x7A5C, 0, 0x3170, 0x6766,
+ 0x6767, 0xF576, 0, 0xD72C, 0, 0xF578, 0x6768, 0xF579,
+};
+static const unsigned short utf8_to_euc_E88A[] = {
+ 0xD72F, 0xD730, 0, 0xD731, 0xD732, 0, 0, 0xD733,
+ 0, 0xD734, 0xD735, 0x3072, 0, 0x6769, 0xD736, 0,
+ 0, 0xD737, 0x676A, 0, 0xD738, 0, 0xD739, 0,
+ 0xD73A, 0x4967, 0xD73B, 0xD73C, 0, 0x3C47, 0, 0x676C,
+ 0xD73D, 0xD73E, 0, 0xD73F, 0xD740, 0x3329, 0x3032, 0xD741,
+ 0xD742, 0xD743, 0xD744, 0x676B, 0x676E, 0x474E, 0xD745, 0x3F44,
+ 0xD746, 0x3256, 0xD747, 0x4B27, 0xD748, 0, 0, 0xD749,
+ 0x375D, 0x365C, 0xD74A, 0x676D, 0xD74B, 0x326A, 0xD74C, 0xD74D,
+};
+static const unsigned short utf8_to_euc_E88A_x0213[] = {
+ 0xD72F, 0xD730, 0, 0xF57A, 0xD732, 0, 0, 0xD733,
+ 0, 0xD734, 0xF57B, 0x3072, 0, 0x6769, 0x7A5E, 0,
+ 0, 0xD737, 0x676A, 0xF57C, 0xD738, 0, 0xD739, 0,
+ 0xD73A, 0x4967, 0xD73B, 0xD73C, 0, 0x3C47, 0, 0x676C,
+ 0xD73D, 0x7A5F, 0, 0x7A60, 0x7A61, 0x3329, 0x3032, 0xF57D,
+ 0xF57E, 0x7A62, 0xD744, 0x676B, 0x676E, 0x474E, 0x7A63, 0x3F44,
+ 0xD746, 0x3256, 0xF621, 0x4B27, 0xF622, 0, 0, 0x7A64,
+ 0x375D, 0x365C, 0xF623, 0x676D, 0xF624, 0x326A, 0x7A65, 0x7A66,
+};
+static const unsigned short utf8_to_euc_E88B[] = {
+ 0, 0, 0, 0, 0, 0x3423, 0xD74E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xD74F, 0x3171, 0x6772, 0x4E6A, 0x425D, 0xD750, 0, 0x4944,
+ 0, 0x677E, 0xD751, 0x3257, 0x677C, 0, 0x677A, 0x6771,
+ 0xD752, 0x676F, 0xD753, 0x6770, 0xD754, 0x3C63, 0x366C, 0x4377,
+ 0xD755, 0, 0xD756, 0x4651, 0, 0xD757, 0, 0xD758,
+ 0, 0x3151, 0, 0x6774, 0x6773, 0, 0xD759, 0xD75A,
+ 0, 0x6779, 0x6775, 0x6778, 0, 0xD75B, 0xD75C, 0,
+};
+static const unsigned short utf8_to_euc_E88B_x0213[] = {
+ 0, 0, 0, 0, 0, 0x3423, 0x7A67, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xD74F, 0x3171, 0x6772, 0x4E6A, 0x425D, 0x7A68, 0, 0x4944,
+ 0, 0x677E, 0xD751, 0x3257, 0x677C, 0, 0x677A, 0x6771,
+ 0xD752, 0x676F, 0xF625, 0x6770, 0xD754, 0x3C63, 0x366C, 0x4377,
+ 0xF626, 0, 0xD756, 0x4651, 0, 0xD757, 0, 0xD758,
+ 0, 0x3151, 0, 0x6774, 0x6773, 0, 0xD759, 0xF627,
+ 0, 0x6779, 0x6775, 0x6778, 0, 0x7A69, 0x7A6A, 0,
+};
+static const unsigned short utf8_to_euc_E88C[] = {
+ 0xD75D, 0xD75E, 0x4C50, 0x6777, 0x3258, 0x337D, 0x677B, 0xD75F,
+ 0xD760, 0x677D, 0xD761, 0xD762, 0, 0, 0x3754, 0,
+ 0, 0, 0, 0, 0, 0, 0x6823, 0x682C,
+ 0x682D, 0, 0, 0xD764, 0x302B, 0xD765, 0xD766, 0xD767,
+ 0, 0xD768, 0xD769, 0x6834, 0, 0, 0, 0,
+ 0x3071, 0, 0, 0x682B, 0xD76A, 0xD76B, 0xD76C, 0x682A,
+ 0xD76D, 0x6825, 0x6824, 0xD76E, 0x6822, 0x6821, 0x4363, 0xD76F,
+ 0x427B, 0x6827, 0xD770, 0, 0xD771, 0xD772, 0, 0,
+};
+static const unsigned short utf8_to_euc_E88C_x0213[] = {
+ 0x7A6B, 0x7A6C, 0x4C50, 0x6777, 0x3258, 0x337D, 0x677B, 0xF628,
+ 0xF629, 0x677D, 0xD761, 0xD762, 0xF62A, 0, 0x3754, 0,
+ 0, 0, 0, 0, 0, 0, 0x6823, 0x682C,
+ 0x682D, 0, 0, 0xF62C, 0x302B, 0xF62D, 0xD766, 0xD767,
+ 0, 0xD768, 0x7A6E, 0x6834, 0, 0, 0, 0,
+ 0x3071, 0, 0, 0x682B, 0xD76A, 0x7A6F, 0xD76C, 0x682A,
+ 0xF62E, 0x6825, 0x6824, 0xD76E, 0x6822, 0x6821, 0x4363, 0xD76F,
+ 0x427B, 0x6827, 0x7A70, 0, 0xF62F, 0xD772, 0, 0,
+};
+static const unsigned short utf8_to_euc_E88D[] = {
+ 0x6826, 0, 0xD773, 0xD774, 0xD775, 0x6829, 0, 0xD776,
+ 0, 0x4170, 0x3755, 0, 0, 0xD777, 0xD778, 0x3141,
+ 0x6828, 0xD779, 0x3953, 0xD83E, 0xD763, 0xD77A, 0xD77B, 0xD77C,
+ 0x4171, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xF45F, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xD77D, 0, 0, 0x683A, 0, 0x683B, 0, 0x3259,
+ 0xD77E, 0, 0, 0x322E, 0x6838, 0xD821, 0, 0xD822,
+};
+static const unsigned short utf8_to_euc_E88D_x0213[] = {
+ 0x6826, 0, 0xD773, 0x7A71, 0xF630, 0x6829, 0, 0x7A72,
+ 0, 0x4170, 0x3755, 0, 0, 0xD777, 0xD778, 0x3141,
+ 0x6828, 0x7A73, 0x3953, 0xD83E, 0xF62B, 0x7A74, 0xD77B, 0xF631,
+ 0x4171, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x7A6D, 0xAE4A, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xD77D, 0, 0, 0x683A, 0, 0x683B, 0, 0x3259,
+ 0xD77E, 0, 0, 0x322E, 0x6838, 0x7A75, 0, 0xF633,
+};
+static const unsigned short utf8_to_euc_E88E[] = {
+ 0xD823, 0, 0xD824, 0, 0xD825, 0x682E, 0xD826, 0x6836,
+ 0, 0x683D, 0x6837, 0, 0, 0xD827, 0x6835, 0,
+ 0, 0, 0xD828, 0x6776, 0xD829, 0xD82A, 0x6833, 0,
+ 0xD82B, 0xD82C, 0x682F, 0xD82D, 0xD82E, 0xD82F, 0x3450, 0x6831,
+ 0x683C, 0, 0x6832, 0, 0, 0, 0xD830, 0xD831,
+ 0x683E, 0xD832, 0x6830, 0x477C, 0xD833, 0xD84C, 0, 0,
+ 0, 0x4D69, 0, 0, 0, 0x6839, 0, 0,
+ 0, 0, 0, 0, 0, 0x684F, 0xD834, 0xD835,
+};
+static const unsigned short utf8_to_euc_E88E_x0213[] = {
+ 0xD823, 0, 0xD824, 0, 0xD825, 0x682E, 0x7A76, 0x6836,
+ 0, 0x683D, 0x6837, 0, 0, 0xF636, 0x6835, 0,
+ 0, 0, 0x7A77, 0x6776, 0xF637, 0xF638, 0x6833, 0,
+ 0x7A78, 0xD82C, 0x682F, 0xF639, 0xD82E, 0xF63A, 0x3450, 0x6831,
+ 0x683C, 0, 0x6832, 0, 0, 0, 0xD830, 0x7A79,
+ 0x683E, 0x7A7A, 0x6830, 0x477C, 0xD833, 0xD84C, 0, 0,
+ 0, 0x4D69, 0, 0, 0, 0x6839, 0, 0,
+ 0, 0, 0, 0, 0, 0x684F, 0xD834, 0x7A7B,
+};
+static const unsigned short utf8_to_euc_E88F[] = {
+ 0xD836, 0x6847, 0, 0, 0, 0x3F7B, 0, 0xD837,
+ 0, 0xD838, 0x3546, 0, 0x365D, 0, 0x6842, 0xD839,
+ 0xD83A, 0xD83B, 0, 0x325B, 0xD83C, 0, 0x3E54, 0,
+ 0x6845, 0, 0, 0, 0x3A5A, 0xD83D, 0, 0x4551,
+ 0x684A, 0, 0, 0, 0, 0, 0, 0,
+ 0xD83F, 0x4A6E, 0xD840, 0x6841, 0, 0, 0, 0x325A,
+ 0x3856, 0x4929, 0x684B, 0, 0x683F, 0, 0xD841, 0x6848,
+ 0xD842, 0xD843, 0, 0x6852, 0xD844, 0x6843, 0, 0,
+};
+static const unsigned short utf8_to_euc_E88F_x0213[] = {
+ 0x7A7C, 0x6847, 0, 0, 0, 0x3F7B, 0, 0x7A7D,
+ 0, 0xF63B, 0x3546, 0, 0x365D, 0, 0x6842, 0x7A7E,
+ 0xF63C, 0x7B21, 0, 0x325B, 0xF63D, 0, 0x3E54, 0,
+ 0x6845, 0, 0, 0, 0x3A5A, 0xF63E, 0, 0x4551,
+ 0x684A, 0x7B22, 0, 0, 0, 0xF63F, 0, 0,
+ 0xD83F, 0x4A6E, 0x7B23, 0x6841, 0, 0, 0, 0x325A,
+ 0x3856, 0x4929, 0x684B, 0, 0x683F, 0, 0, 0x6848,
+ 0xD842, 0xF640, 0, 0x6852, 0xD844, 0x6843, 0, 0,
+};
+static const unsigned short utf8_to_euc_E890[] = {
+ 0, 0xD845, 0, 0x6844, 0x463A, 0, 0xD846, 0x6849,
+ 0, 0, 0xD847, 0x6846, 0x4B28, 0x684C, 0x3060, 0xD848,
+ 0, 0xD849, 0, 0x6840, 0, 0xD84A, 0, 0,
+ 0, 0xD84B, 0, 0, 0, 0, 0, 0,
+ 0x684E, 0, 0x684D, 0, 0, 0, 0, 0,
+ 0, 0x476B, 0x6854, 0, 0x685F, 0, 0, 0xD84D,
+ 0, 0x337E, 0, 0, 0, 0x6862, 0, 0,
+ 0x6850, 0xD84E, 0, 0, 0x6855, 0x4D6E, 0, 0,
+};
+static const unsigned short utf8_to_euc_E890_x0213[] = {
+ 0, 0x7B24, 0, 0x6844, 0x463A, 0, 0x7B25, 0x6849,
+ 0, 0, 0x7B26, 0x6846, 0x4B28, 0x684C, 0x3060, 0xF641,
+ 0, 0xF642, 0, 0x6840, 0, 0xF643, 0, 0xF645,
+ 0, 0xD84B, 0, 0, 0, 0, 0, 0,
+ 0x684E, 0, 0x684D, 0, 0, 0, 0, 0,
+ 0, 0x476B, 0x6854, 0, 0x685F, 0, 0, 0xD84D,
+ 0, 0x337E, 0, 0, 0, 0x6862, 0, 0,
+ 0x6850, 0xF646, 0, 0, 0x6855, 0x4D6E, 0, 0,
+};
+static const unsigned short utf8_to_euc_E891[] = {
+ 0, 0, 0, 0, 0, 0xD84F, 0x685E, 0xD850,
+ 0xD851, 0x4D55, 0xD852, 0, 0, 0xD853, 0x4E2A, 0xD854,
+ 0, 0xD855, 0xD856, 0, 0, 0, 0xD857, 0x4378,
+ 0xD858, 0xD859, 0xD85A, 0x336B, 0xD85B, 0, 0, 0,
+ 0xD85C, 0x4972, 0x6864, 0x4621, 0xD85D, 0xD85E, 0x3031, 0xD85F,
+ 0, 0x685D, 0xD860, 0x6859, 0x4172, 0x6853, 0x685B, 0x6860,
+ 0xD861, 0x472C, 0, 0xD862, 0xD863, 0x302A, 0xD864, 0x6858,
+ 0xD865, 0x6861, 0x4978, 0, 0xD866, 0xD867, 0, 0,
+};
+static const unsigned short utf8_to_euc_E891_x0213[] = {
+ 0, 0, 0, 0, 0, 0xD84F, 0x685E, 0xD850,
+ 0x7B28, 0x4D55, 0xF647, 0, 0, 0xD853, 0x4E2A, 0xF648,
+ 0, 0xF649, 0xF64A, 0, 0, 0, 0xD857, 0x4378,
+ 0xD858, 0xF64B, 0xF64C, 0x336B, 0xF64D, 0, 0, 0x7B29,
+ 0xD85C, 0x4972, 0x6864, 0x4621, 0xD85D, 0xF64F, 0x3031, 0xD85F,
+ 0, 0x685D, 0xD860, 0x6859, 0x4172, 0x6853, 0x685B, 0x6860,
+ 0x7B2A, 0x472C, 0, 0x7B2B, 0xD863, 0x302A, 0xF650, 0x6858,
+ 0xF651, 0x6861, 0x4978, 0, 0xF652, 0xD867, 0, 0,
+};
+static const unsigned short utf8_to_euc_E892[] = {
+ 0, 0xD868, 0x685C, 0, 0x6857, 0xD869, 0, 0,
+ 0, 0, 0, 0x3E55, 0, 0, 0, 0,
+ 0x3D2F, 0, 0xD86A, 0xD86B, 0x3C2C, 0xD86C, 0, 0,
+ 0, 0x4C58, 0, 0, 0x4947, 0, 0xD86D, 0x6867,
+ 0, 0x6870, 0, 0, 0, 0, 0xD86E, 0,
+ 0xD86F, 0xD870, 0xD871, 0, 0, 0x685A, 0, 0xD872,
+ 0, 0xD873, 0x3377, 0, 0xD874, 0, 0, 0,
+ 0x3E78, 0x6865, 0xD875, 0x686A, 0x4173, 0xD876, 0xD877, 0x6866,
+};
+static const unsigned short utf8_to_euc_E892_x0213[] = {
+ 0, 0xF653, 0x685C, 0, 0x6857, 0x7B2C, 0, 0,
+ 0, 0, 0, 0x3E55, 0, 0, 0, 0,
+ 0x3D2F, 0, 0xD86A, 0xD86B, 0x3C2C, 0xD86C, 0, 0xF656,
+ 0, 0x4C58, 0, 0, 0x4947, 0, 0x7B2D, 0x6867,
+ 0, 0x6870, 0, 0, 0, 0, 0xF657, 0,
+ 0xD86F, 0xD870, 0xD871, 0, 0, 0x685A, 0, 0x7B2E,
+ 0, 0xD873, 0x3377, 0, 0x7B2F, 0, 0, 0,
+ 0x3E78, 0x6865, 0x7B30, 0x686A, 0x4173, 0xD876, 0xF658, 0x6866,
+};
+static const unsigned short utf8_to_euc_E893[] = {
+ 0xD878, 0x686D, 0xD879, 0, 0x435F, 0, 0x686E, 0xD87A,
+ 0xD87B, 0x4D56, 0x6863, 0x3338, 0xD87C, 0x6869, 0, 0xD87D,
+ 0x686C, 0x4C2C, 0, 0xD87E, 0, 0, 0x686F, 0,
+ 0, 0x6868, 0x686B, 0, 0xD921, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xD922,
+ 0, 0, 0xD923, 0, 0x4B29, 0, 0x4F21, 0xD924,
+ 0xD925, 0xD926, 0xD927, 0, 0x6873, 0, 0, 0xD928,
+ 0, 0, 0xD92A, 0xD92B, 0x687A, 0xD92C, 0, 0x6872,
+};
+static const unsigned short utf8_to_euc_E893_x0213[] = {
+ 0x7B31, 0x686D, 0x7B32, 0, 0x435F, 0, 0x686E, 0xD87A,
+ 0xD87B, 0x4D56, 0x6863, 0x3338, 0xD87C, 0x6869, 0xF65A, 0xF65B,
+ 0x686C, 0x4C2C, 0, 0xF65C, 0, 0, 0x686F, 0,
+ 0, 0x6868, 0x686B, 0, 0xF655, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xF65E,
+ 0, 0, 0xF65F, 0, 0x4B29, 0, 0x4F21, 0xF660,
+ 0xF661, 0xF662, 0xD927, 0, 0x6873, 0, 0, 0xD928,
+ 0, 0, 0xF663, 0xD92B, 0x687A, 0xF664, 0, 0x6872,
+};
+static const unsigned short utf8_to_euc_E894[] = {
+ 0x3C43, 0, 0xD92D, 0xD92E, 0, 0, 0x6851, 0xD92F,
+ 0, 0, 0, 0, 0xD930, 0, 0xD931, 0,
+ 0xD932, 0x4A4E, 0, 0x4C22, 0x6879, 0x6878, 0, 0x6874,
+ 0x6875, 0, 0x3136, 0, 0xD933, 0, 0xD934, 0x6877,
+ 0, 0x6871, 0xD935, 0xD936, 0xD937, 0xD938, 0x4455, 0xD939,
+ 0, 0, 0xD93A, 0xD93B, 0x6876, 0x307E, 0, 0xD93C,
+ 0, 0, 0xD929, 0xD93D, 0xD93E, 0x4222, 0xD93F, 0,
+ 0, 0, 0, 0, 0, 0x4A43, 0, 0xD940,
+};
+static const unsigned short utf8_to_euc_E894_x0213[] = {
+ 0x3C43, 0, 0xD92D, 0xD92E, 0, 0, 0x6851, 0xD92F,
+ 0, 0, 0, 0, 0xF665, 0, 0xD931, 0,
+ 0xD932, 0x4A4E, 0, 0x4C22, 0x6879, 0x6878, 0, 0x6874,
+ 0x6875, 0, 0x3136, 0xF666, 0xD933, 0, 0x7B35, 0x6877,
+ 0, 0x6871, 0xD935, 0x7B36, 0xF667, 0xF668, 0x4455, 0xD939,
+ 0, 0, 0xD93A, 0xF669, 0x6876, 0x307E, 0, 0x7B37,
+ 0, 0, 0x7B34, 0xD93D, 0xF66A, 0x4222, 0xD93F, 0,
+ 0, 0, 0, 0, 0, 0x4A43, 0xF66F, 0xD940,
+};
+static const unsigned short utf8_to_euc_E895[] = {
+ 0x687B, 0x6921, 0, 0x4859, 0, 0, 0xD941, 0,
+ 0x687E, 0x3E56, 0x3C49, 0x6923, 0, 0, 0x363E, 0xD942,
+ 0xD943, 0xD944, 0xD945, 0xD946, 0, 0x6924, 0xD947, 0x4979,
+ 0x687D, 0xD948, 0x6856, 0, 0xD949, 0xD94A, 0xD94B, 0xD94C,
+ 0xD94D, 0xD94E, 0xD94F, 0x687C, 0xD950, 0, 0, 0,
+ 0x4F4F, 0x4622, 0x4973, 0xD951, 0, 0x692B, 0, 0xD952,
+ 0, 0, 0, 0, 0, 0, 0, 0x6931,
+ 0, 0xD953, 0xD954, 0xD955, 0, 0xD956, 0x6932, 0xD957,
+};
+static const unsigned short utf8_to_euc_E895_x0213[] = {
+ 0x687B, 0x6921, 0, 0x4859, 0, 0, 0xD941, 0,
+ 0x687E, 0x3E56, 0x3C49, 0x6923, 0, 0, 0x363E, 0xF66B,
+ 0xD943, 0xF670, 0xD945, 0xF671, 0, 0x6924, 0xD947, 0x4979,
+ 0x687D, 0x7B38, 0x6856, 0, 0xD949, 0xD94A, 0xF672, 0xD94C,
+ 0xD94D, 0xF673, 0xF674, 0x687C, 0x7B39, 0, 0, 0,
+ 0x4F4F, 0x4622, 0x4973, 0, 0, 0x692B, 0, 0xF66C,
+ 0, 0, 0, 0, 0, 0, 0, 0x6931,
+ 0, 0xD953, 0x7B3C, 0xF676, 0, 0xF677, 0x6932, 0xF678,
+};
+static const unsigned short utf8_to_euc_E896[] = {
+ 0x6925, 0xD958, 0, 0, 0x4776, 0xD959, 0xD95A, 0x692F,
+ 0x6927, 0xD95B, 0x6929, 0xD95C, 0xD95D, 0, 0, 0xD95E,
+ 0x6933, 0x6928, 0, 0xD95F, 0x692C, 0, 0, 0x3172,
+ 0xD960, 0x4665, 0, 0x692D, 0x6930, 0xD961, 0, 0xD962,
+ 0xD963, 0, 0xD964, 0, 0x6926, 0xD965, 0x4126, 0xD966,
+ 0x692A, 0x3B27, 0x3F45, 0x3730, 0x4C74, 0xD974, 0x4C79, 0x3D72,
+ 0xF461, 0, 0, 0, 0xD967, 0, 0xD968, 0xD969,
+ 0xD96A, 0x6937, 0x6935, 0, 0xD96B, 0xD96C, 0xD96D, 0xD96E,
+};
+static const unsigned short utf8_to_euc_E896_x0213[] = {
+ 0x6925, 0xF679, 0, 0, 0x4776, 0xD959, 0xF67A, 0x692F,
+ 0x6927, 0xD95B, 0x6929, 0xD95C, 0x7B3D, 0, 0, 0x7B3E,
+ 0x6933, 0x6928, 0, 0xF67B, 0x692C, 0, 0, 0x3172,
+ 0xD960, 0x4665, 0, 0x692D, 0x6930, 0xF67C, 0, 0xF67D,
+ 0xD963, 0, 0x7B3F, 0, 0x6926, 0xD965, 0x4126, 0xD966,
+ 0x692A, 0x3B27, 0x3F45, 0x3730, 0x4C74, 0x7B3B, 0x4C79, 0x3D72,
+ 0x7B40, 0, 0, 0, 0xD967, 0, 0xD968, 0xF723,
+ 0xD96A, 0x6937, 0x6935, 0, 0xF724, 0xD96C, 0xD96D, 0xD96E,
+};
+static const unsigned short utf8_to_euc_E897[] = {
+ 0, 0x4F4E, 0xD96F, 0, 0, 0, 0, 0xD970,
+ 0, 0x6934, 0xD971, 0xD972, 0, 0x4D75, 0xD973, 0x6936,
+ 0x6938, 0, 0, 0, 0, 0x6939, 0, 0,
+ 0xD975, 0, 0xD976, 0, 0x693C, 0x693A, 0, 0xD977,
+ 0xD978, 0, 0, 0, 0x4623, 0x693B, 0xD979, 0,
+ 0xD97A, 0x484D, 0x692E, 0, 0, 0xD97B, 0, 0,
+ 0, 0, 0, 0xD97C, 0, 0, 0xD97D, 0x3D73,
+ 0, 0x693D, 0x6942, 0x4174, 0xD97E, 0, 0x6941, 0xDA21,
+};
+static const unsigned short utf8_to_euc_E897_x0213[] = {
+ 0, 0x4F4E, 0xD96F, 0, 0, 0, 0, 0xF725,
+ 0, 0x6934, 0xF726, 0x7B41, 0, 0x4D75, 0x7B42, 0x6936,
+ 0x6938, 0, 0, 0, 0, 0x6939, 0, 0,
+ 0xF727, 0xF728, 0xD976, 0, 0x693C, 0x693A, 0, 0xF729,
+ 0xD978, 0xF72A, 0, 0, 0x4623, 0x693B, 0xF72B, 0,
+ 0xD97A, 0x484D, 0x692E, 0, 0, 0x7B43, 0, 0,
+ 0, 0, 0, 0xD97C, 0, 0, 0xF72C, 0x3D73,
+ 0, 0x693D, 0x6942, 0x4174, 0xD97E, 0, 0x6941, 0x7B45,
+};
+static const unsigned short utf8_to_euc_E898[] = {
+ 0xDA22, 0, 0x6922, 0, 0xDA23, 0xDA24, 0x6943, 0x4149,
+ 0, 0, 0x693E, 0x6940, 0, 0xDA25, 0xDA26, 0,
+ 0xDA27, 0xDA28, 0xDA29, 0x693F, 0, 0, 0x5D31, 0x5D22,
+ 0xDA2A, 0xDA2B, 0x6945, 0xDA2C, 0, 0, 0xDA2D, 0,
+ 0, 0xDA2E, 0x6944, 0, 0, 0, 0, 0xDA2F,
+ 0, 0xDA30, 0, 0, 0, 0x4D76, 0, 0x623C,
+ 0x6946, 0, 0, 0, 0, 0, 0xDA31, 0,
+ 0xDA32, 0, 0xDA33, 0, 0xDA34, 0xDA35, 0, 0x6947,
+};
+static const unsigned short utf8_to_euc_E898_x0213[] = {
+ 0xF72D, 0, 0x6922, 0, 0x7B46, 0x7B47, 0x6943, 0x4149,
+ 0, 0, 0x693E, 0x6940, 0, 0xDA25, 0xDA26, 0,
+ 0x7B48, 0xF72E, 0x7B44, 0x693F, 0, 0, 0x5D31, 0x5D22,
+ 0x7B4A, 0xDA2B, 0x6945, 0xDA2C, 0, 0, 0xF72F, 0,
+ 0, 0xF730, 0x6944, 0, 0xF731, 0, 0, 0xF732,
+ 0, 0x7B4B, 0, 0, 0, 0x4D76, 0, 0x623C,
+ 0x6946, 0, 0, 0, 0, 0, 0xDA31, 0,
+ 0x7B4C, 0xF734, 0xDA33, 0, 0xF735, 0xDA35, 0, 0x6947,
+};
+static const unsigned short utf8_to_euc_E899[] = {
+ 0xDA36, 0xB866, 0xDA37, 0, 0, 0, 0xDA38, 0,
+ 0, 0, 0, 0, 0, 0x6948, 0x3857, 0,
+ 0x3554, 0, 0xDA39, 0xDA3A, 0x694A, 0x515D, 0xDA3B, 0xDA3C,
+ 0xDA3D, 0xDA3E, 0x3575, 0, 0x4E3A, 0xDA3F, 0x3673, 0x694B,
+ 0xDA40, 0xDA41, 0xDA42, 0xDA43, 0xDA44, 0, 0, 0x694C,
+ 0, 0xDA45, 0, 0x436E, 0xDA46, 0, 0, 0xDA47,
+ 0, 0x694D, 0, 0, 0, 0xDA48, 0xDA49, 0xDA4A,
+ 0, 0x467A, 0xDA4B, 0x303A, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E899_x0213[] = {
+ 0xF737, 0x2F68, 0xDA37, 0, 0, 0, 0xDA38, 0,
+ 0, 0, 0, 0, 0, 0x6948, 0x3857, 0,
+ 0x3554, 0, 0xDA39, 0xF739, 0x694A, 0x515D, 0xF73A, 0x7B4D,
+ 0xDA3D, 0xDA3E, 0x3575, 0x7B4E, 0x4E3A, 0xDA3F, 0x3673, 0x694B,
+ 0xDA40, 0xDA41, 0x7B50, 0xDA43, 0xDA44, 0, 0, 0x694C,
+ 0, 0xDA45, 0, 0x436E, 0x7B52, 0, 0, 0xF73B,
+ 0, 0x694D, 0, 0, 0, 0x7B53, 0xDA49, 0xF73C,
+ 0, 0x467A, 0xF73D, 0x303A, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E89A[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xDA6D, 0, 0x3263, 0x6952, 0x6953, 0xDA4C, 0, 0,
+ 0, 0xDA4D, 0, 0x694E, 0, 0x3B3D, 0xDA4E, 0,
+ 0xDA4F, 0, 0xDA50, 0, 0xDA51, 0, 0, 0,
+ 0, 0xDA52, 0, 0x694F, 0x4742, 0, 0xDA53, 0xDA54,
+ 0xDA55, 0x6950, 0x6951, 0x695B, 0, 0xDA56, 0, 0x6955,
+ 0x6958, 0xDA57, 0, 0xDA58, 0xDA59, 0xDA5A, 0x6954, 0xDA5B,
+ 0xDA5C, 0xDA5D, 0, 0, 0, 0, 0, 0xDA5E,
+};
+static const unsigned short utf8_to_euc_E89A_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0xF73E,
+ 0xDA6D, 0xF73F, 0x3263, 0x6952, 0x6953, 0xF740, 0, 0,
+ 0, 0xF741, 0, 0x694E, 0, 0x3B3D, 0xDA4E, 0,
+ 0x7B54, 0, 0xDA50, 0, 0xF742, 0xF743, 0, 0,
+ 0, 0xDA52, 0, 0x694F, 0x4742, 0, 0xDA53, 0xDA54,
+ 0xF744, 0x6950, 0x6951, 0x695B, 0, 0xDA56, 0, 0x6955,
+ 0x6958, 0xF746, 0, 0xF747, 0xDA59, 0xDA5A, 0x6954, 0xDA5B,
+ 0x7B55, 0xDA5D, 0, 0, 0, 0, 0, 0xDA5E,
+};
+static const unsigned short utf8_to_euc_E89B[] = {
+ 0xDA5F, 0xDA60, 0, 0xDA61, 0x6956, 0xDA62, 0x6957, 0x3C58,
+ 0, 0x6959, 0, 0x4341, 0, 0x3756, 0x3342, 0,
+ 0, 0xDA63, 0xDA64, 0, 0x695C, 0xDA65, 0, 0xDA66,
+ 0, 0x333F, 0xDA67, 0x6961, 0xDA68, 0, 0x695D, 0x6960,
+ 0xDA69, 0, 0, 0xDA6A, 0x483A, 0xDA6B, 0, 0xDA6C,
+ 0, 0x695E, 0, 0, 0x695F, 0x4948, 0x485A, 0x6962,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x427D, 0x696C, 0xDA6E, 0x6968, 0xDA6F, 0xDA70, 0x326B, 0,
+};
+static const unsigned short utf8_to_euc_E89B_x0213[] = {
+ 0xDA5F, 0xF748, 0, 0xF749, 0x6956, 0xDA62, 0x6957, 0x3C58,
+ 0, 0x6959, 0, 0x4341, 0, 0x3756, 0x3342, 0,
+ 0, 0xF74A, 0xDA64, 0, 0x695C, 0xF74B, 0, 0xF74C,
+ 0, 0x333F, 0xDA67, 0x6961, 0xDA68, 0, 0x695D, 0x6960,
+ 0xDA69, 0, 0, 0xF74D, 0x483A, 0xDA6B, 0xF74E, 0xDA6C,
+ 0, 0x695E, 0, 0, 0x695F, 0x4948, 0x485A, 0x6962,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x427D, 0x696C, 0x7B56, 0x6968, 0x7B57, 0x7B58, 0x326B, 0,
+};
+static const unsigned short utf8_to_euc_E89C[] = {
+ 0x6966, 0, 0x4B2A, 0x6967, 0xDA71, 0xDA72, 0x6964, 0xDA73,
+ 0x6965, 0x696A, 0x696D, 0xDA74, 0, 0x696B, 0xDA75, 0xDA76,
+ 0xDA77, 0x6969, 0x6963, 0xDA78, 0xDA79, 0, 0, 0,
+ 0x4358, 0xDA7A, 0x6974, 0, 0x4C2A, 0, 0xDA7B, 0xDA7C,
+ 0, 0xDA7D, 0, 0xDA7E, 0, 0x6972, 0, 0,
+ 0xDB21, 0x6973, 0, 0, 0, 0, 0xDB22, 0xDB23,
+ 0, 0xDB24, 0xDB25, 0, 0x696E, 0, 0, 0x6970,
+ 0, 0xDB26, 0xDB27, 0x6971, 0xDB28, 0xDB29, 0xDB2A, 0x696F,
+};
+static const unsigned short utf8_to_euc_E89C_x0213[] = {
+ 0x6966, 0, 0x4B2A, 0x6967, 0xDA71, 0xF750, 0x6964, 0xF751,
+ 0x6965, 0x696A, 0x696D, 0x7B59, 0, 0x696B, 0xF752, 0xDA76,
+ 0xF753, 0x6969, 0x6963, 0xF754, 0xDA79, 0, 0, 0,
+ 0x4358, 0xF755, 0x6974, 0, 0x4C2A, 0, 0xDA7B, 0xF756,
+ 0, 0xF757, 0, 0xF758, 0, 0x6972, 0, 0,
+ 0xDB21, 0x6973, 0, 0, 0, 0, 0xDB22, 0xDB23,
+ 0, 0xF759, 0xDB25, 0, 0x696E, 0, 0, 0x6970,
+ 0, 0xDB26, 0xF75A, 0x6971, 0xDB28, 0xDB29, 0xF75B, 0x696F,
+};
+static const unsigned short utf8_to_euc_E89D[] = {
+ 0xDB2B, 0, 0, 0xDB2C, 0, 0xDB2D, 0, 0,
+ 0, 0x4066, 0, 0x4F39, 0x6978, 0xDB2E, 0x6979, 0,
+ 0, 0, 0, 0x6A21, 0, 0x3F2A, 0, 0x697B,
+ 0xDB2F, 0x697E, 0, 0, 0, 0xDB30, 0, 0x6976,
+ 0x6975, 0xDB31, 0, 0x6A22, 0xDB32, 0xDB33, 0x325C, 0,
+ 0x697C, 0, 0x6A23, 0, 0, 0, 0x697D, 0xDB34,
+ 0, 0xDB35, 0xDB36, 0, 0x697A, 0, 0x4433, 0,
+ 0x6977, 0, 0, 0xDB37, 0, 0, 0, 0x4768,
+};
+static const unsigned short utf8_to_euc_E89D_x0213[] = {
+ 0xF75C, 0, 0, 0xF75D, 0, 0xDB2D, 0, 0,
+ 0, 0x4066, 0, 0x4F39, 0x6978, 0xDB2E, 0x6979, 0,
+ 0, 0xF75E, 0, 0x6A21, 0, 0x3F2A, 0, 0x697B,
+ 0xF75F, 0x697E, 0, 0, 0, 0xDB30, 0, 0x6976,
+ 0x6975, 0xDB31, 0, 0x6A22, 0xF760, 0xF761, 0x325C, 0,
+ 0x697C, 0, 0x6A23, 0, 0, 0, 0x697D, 0xDB34,
+ 0, 0x7B5A, 0xF762, 0, 0x697A, 0, 0x4433, 0,
+ 0x6977, 0, 0, 0xDB37, 0xF763, 0, 0, 0x4768,
+};
+static const unsigned short utf8_to_euc_E89E[] = {
+ 0, 0, 0x6A27, 0xDB38, 0xDB39, 0xDB3A, 0xDB3B, 0xDB3C,
+ 0xDB3D, 0xDB3E, 0, 0xDB3F, 0xDB40, 0x4D3B, 0, 0,
+ 0xDB41, 0, 0, 0xDB42, 0, 0xDB43, 0, 0xDB44,
+ 0xDB45, 0xDB46, 0, 0, 0, 0, 0xDB47, 0x6A26,
+ 0xDB48, 0, 0x6A25, 0xDB49, 0, 0, 0, 0xDB4A,
+ 0, 0, 0, 0x6A2E, 0xDB4B, 0xDB4C, 0xDB4D, 0x6A28,
+ 0, 0xDB4E, 0, 0x6A30, 0, 0xDB4F, 0, 0,
+ 0, 0, 0x4D66, 0x6A33, 0, 0x6A2A, 0xDB50, 0xDB51,
+};
+static const unsigned short utf8_to_euc_E89E_x0213[] = {
+ 0, 0, 0x6A27, 0xDB38, 0xDB39, 0xDB3A, 0xDB3B, 0x7B5B,
+ 0x7B5C, 0xF767, 0, 0xF768, 0xDB40, 0x4D3B, 0, 0,
+ 0xDB41, 0, 0, 0xF769, 0, 0xDB43, 0, 0xDB44,
+ 0xDB45, 0xDB46, 0, 0, 0, 0, 0xDB47, 0x6A26,
+ 0xF76A, 0, 0x6A25, 0xDB49, 0, 0, 0, 0xF766,
+ 0, 0, 0, 0x6A2E, 0x7B5D, 0x7B5E, 0xDB4D, 0x6A28,
+ 0, 0xDB4E, 0, 0x6A30, 0, 0x7B5F, 0, 0,
+ 0, 0, 0x4D66, 0x6A33, 0, 0x6A2A, 0xF76D, 0xDB51,
+};
+static const unsigned short utf8_to_euc_E89F[] = {
+ 0x6A2B, 0xDB52, 0, 0, 0x6A2F, 0, 0x6A32, 0x6A31,
+ 0xDB53, 0xDB54, 0xDB55, 0x6A29, 0, 0, 0xDB56, 0,
+ 0x6A2C, 0, 0x6A3D, 0, 0, 0xDB57, 0xDB58, 0,
+ 0, 0xDB59, 0xDB5A, 0, 0xDB5B, 0, 0, 0xDB5C,
+ 0x6A36, 0, 0xDB5D, 0xDB5E, 0xDB5F, 0, 0, 0,
+ 0, 0, 0xDB60, 0xDB61, 0, 0xDB62, 0, 0x6A34,
+ 0, 0xDB63, 0x6A35, 0xDB64, 0, 0, 0x6A3A, 0x6A3B,
+ 0xDB65, 0x332A, 0xDB66, 0x3542, 0, 0, 0x6A39, 0xDB67,
+};
+static const unsigned short utf8_to_euc_E89F_x0213[] = {
+ 0x6A2B, 0xF76F, 0, 0, 0x6A2F, 0, 0x6A32, 0x6A31,
+ 0xDB53, 0xDB54, 0xDB55, 0x6A29, 0, 0, 0xF770, 0,
+ 0x6A2C, 0, 0x6A3D, 0, 0, 0xDB57, 0x7B61, 0,
+ 0, 0xDB59, 0xDB5A, 0, 0xDB5B, 0, 0, 0xF772,
+ 0x6A36, 0, 0xDB5D, 0xF774, 0xDB5F, 0xF775, 0xF776, 0,
+ 0, 0, 0xF777, 0xF778, 0x7B62, 0xF779, 0, 0x6A34,
+ 0, 0xDB63, 0x6A35, 0xDB64, 0, 0xF771, 0x6A3A, 0x6A3B,
+ 0xDB65, 0x332A, 0xDB66, 0x3542, 0, 0, 0x6A39, 0xDB67,
+};
+static const unsigned short utf8_to_euc_E8A0[] = {
+ 0, 0xDB68, 0, 0xDB69, 0, 0x6A24, 0xDB6A, 0xF464,
+ 0, 0xDB6B, 0xDB6C, 0xDB6D, 0, 0x6A38, 0x6A3C, 0x6A37,
+ 0xDB6E, 0x6A3E, 0xDB70, 0xDB71, 0xDB72, 0x6A40, 0x6A3F, 0,
+ 0xDB73, 0xDB6F, 0xDB74, 0xDB75, 0xDB76, 0, 0xDB77, 0xDB78,
+ 0, 0x6A42, 0x6A41, 0x695A, 0, 0, 0, 0x6A46,
+ 0xDB79, 0, 0, 0, 0, 0xDB7A, 0xDB7B, 0,
+ 0xDB7C, 0x6A43, 0xDB7D, 0, 0, 0xDB7E, 0x6A44, 0,
+ 0, 0x6A45, 0xDC21, 0x6A47, 0xDC22, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E8A0_x0213[] = {
+ 0, 0xF77A, 0, 0xF77B, 0, 0x6A24, 0x7B63, 0,
+ 0, 0xDB6B, 0x7B64, 0xF77C, 0, 0x6A38, 0x6A3C, 0x6A37,
+ 0x7B65, 0x6A3E, 0xDB70, 0xF77D, 0x7B66, 0x6A40, 0x6A3F, 0,
+ 0xDB73, 0xDB6F, 0xDB74, 0xDB75, 0xDB76, 0, 0xDB77, 0x7B67,
+ 0, 0x6A42, 0x6A41, 0x695A, 0, 0, 0, 0x6A46,
+ 0xF77E, 0, 0, 0, 0, 0xDB7A, 0xF821, 0,
+ 0xDB7C, 0x6A43, 0xF822, 0, 0, 0xDB7E, 0x6A44, 0,
+ 0, 0x6A45, 0xDC21, 0x6A47, 0xF823, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E8A1[] = {
+ 0x376C, 0xDC23, 0x6A49, 0xDC24, 0x6A48, 0xDC25, 0x3D30, 0,
+ 0xDC26, 0xDC27, 0xDC28, 0xDC29, 0x3954, 0x5E27, 0xDC2A, 0,
+ 0, 0xDC2B, 0x6A4A, 0x3D51, 0, 0xDC2C, 0xDC2D, 0x3339,
+ 0xDC2E, 0x6A4B, 0xDC2F, 0x3152, 0xDC30, 0x3E57, 0x6A4C, 0xDC31,
+ 0xDC32, 0x3955, 0x6A4D, 0x3061, 0xDC33, 0, 0, 0,
+ 0x493D, 0xDC34, 0, 0x6A4E, 0, 0, 0, 0,
+ 0x3F6A, 0xDC35, 0x6A55, 0, 0, 0x6A52, 0, 0x436F,
+ 0, 0xDC36, 0, 0xDC37, 0, 0x6A53, 0x6A50, 0x365E,
+};
+static const unsigned short utf8_to_euc_E8A1_x0213[] = {
+ 0x376C, 0xDC23, 0x6A49, 0xDC24, 0x6A48, 0xDC25, 0x3D30, 0,
+ 0xDC26, 0xDC27, 0xF825, 0xDC29, 0x3954, 0x5E27, 0xDC2A, 0,
+ 0, 0xDC2B, 0x6A4A, 0x3D51, 0, 0xDC2C, 0xDC2D, 0x3339,
+ 0xF826, 0x6A4B, 0xDC2F, 0x3152, 0xDC30, 0x3E57, 0x6A4C, 0xF827,
+ 0xDC32, 0x3955, 0x6A4D, 0x3061, 0xF828, 0, 0, 0,
+ 0x493D, 0xF82B, 0, 0x6A4E, 0, 0, 0, 0xF82D,
+ 0x3F6A, 0xDC35, 0x6A55, 0, 0, 0x6A52, 0, 0x436F,
+ 0, 0xDC36, 0, 0xDC37, 0, 0x6A53, 0x6A50, 0x365E,
+};
+static const unsigned short utf8_to_euc_E8A2[] = {
+ 0xDC38, 0x6A4F, 0x6A56, 0, 0, 0, 0, 0,
+ 0x3736, 0, 0, 0x425E, 0, 0x6A5C, 0, 0,
+ 0, 0, 0x6A58, 0, 0, 0, 0x4235, 0x6A57,
+ 0xDC39, 0x6A5A, 0xDC3A, 0xDC3B, 0xDC3C, 0, 0x6A51, 0xDC3D,
+ 0xDC3E, 0, 0x6A5B, 0, 0x6A5D, 0, 0, 0,
+ 0xDC3F, 0, 0xDC40, 0x486F, 0, 0, 0x6A59, 0,
+ 0x6A5E, 0x6A60, 0, 0, 0x3853, 0x6A54, 0, 0x3041,
+ 0, 0, 0xDC41, 0, 0, 0xDC42, 0xDC43, 0x6A5F,
+};
+static const unsigned short utf8_to_euc_E8A2_x0213[] = {
+ 0xDC38, 0x6A4F, 0x6A56, 0, 0, 0, 0, 0,
+ 0x3736, 0, 0, 0x425E, 0, 0x6A5C, 0, 0,
+ 0, 0, 0x6A58, 0, 0, 0, 0x4235, 0x6A57,
+ 0x7B68, 0x6A5A, 0xDC3A, 0xDC3B, 0xDC3C, 0, 0x6A51, 0xDC3D,
+ 0xF82E, 0, 0x6A5B, 0, 0x6A5D, 0, 0, 0,
+ 0xDC3F, 0, 0x7B69, 0x486F, 0, 0, 0x6A59, 0,
+ 0x6A5E, 0x6A60, 0, 0, 0x3853, 0x6A54, 0, 0x3041,
+ 0, 0, 0xDC41, 0, 0xF82F, 0xF830, 0xF831, 0x6A5F,
+};
+static const unsigned short utf8_to_euc_E8A3[] = {
+ 0xDC44, 0x3A5B, 0x4E76, 0x6A61, 0x6A62, 0x4175, 0, 0,
+ 0, 0, 0xDC45, 0xDC46, 0xDC47, 0xDC48, 0xDC49, 0x4E22,
+ 0, 0xDC4A, 0xDC4B, 0xDC4C, 0x6A63, 0x4D35, 0, 0,
+ 0x6A64, 0x6A65, 0, 0xDC4D, 0x4A64, 0x6A66, 0xDC4E, 0x3A40,
+ 0, 0x4E23, 0, 0, 0, 0, 0, 0xDC4F,
+ 0x6A6B, 0, 0, 0, 0, 0, 0, 0xDC50,
+ 0xDC51, 0xDC52, 0x6A6C, 0x3E58, 0x6A6A, 0xDC53, 0, 0xDC54,
+ 0x4D67, 0x6A67, 0, 0, 0x6A69, 0x403D, 0x3F7E, 0,
+};
+static const unsigned short utf8_to_euc_E8A3_x0213[] = {
+ 0xF832, 0x3A5B, 0x4E76, 0x6A61, 0x6A62, 0x4175, 0, 0,
+ 0, 0, 0x7B6A, 0xDC46, 0xDC47, 0xDC48, 0x7B6B, 0x4E22,
+ 0, 0xF835, 0xF833, 0xF836, 0x6A63, 0x4D35, 0, 0,
+ 0x6A64, 0x6A65, 0, 0xF837, 0x4A64, 0x6A66, 0xDC4E, 0x3A40,
+ 0, 0x4E23, 0, 0, 0, 0, 0, 0xDC4F,
+ 0x6A6B, 0, 0, 0, 0, 0, 0, 0xDC50,
+ 0xF838, 0xF839, 0x6A6C, 0x3E58, 0x6A6A, 0x7B6D, 0, 0xDC54,
+ 0x4D67, 0x6A67, 0, 0, 0x6A69, 0x403D, 0x3F7E, 0,
+};
+static const unsigned short utf8_to_euc_E8A4[] = {
+ 0, 0xDC55, 0x6A68, 0, 0x6A6D, 0, 0xDC56, 0x4A23,
+ 0, 0, 0x6A6F, 0, 0x6A6E, 0xDC57, 0xDC58, 0xDC59,
+ 0x336C, 0, 0x4B2B, 0x6A70, 0, 0xDC5A, 0xDC5B, 0,
+ 0xDC5C, 0xDC5D, 0xDC5E, 0, 0xDC5F, 0x6A7C, 0x6A72, 0,
+ 0xDC60, 0, 0, 0, 0, 0x6A73, 0xDC61, 0xDC62,
+ 0xDC63, 0, 0x6A74, 0x6A75, 0, 0, 0, 0,
+ 0xDC64, 0xDC65, 0xDC66, 0, 0, 0xDC67, 0x6A79, 0,
+ 0x6A7A, 0xDC68, 0xDC69, 0x6A78, 0, 0, 0xDC6A, 0,
+};
+static const unsigned short utf8_to_euc_E8A4_x0213[] = {
+ 0, 0xF83B, 0x6A68, 0, 0x6A6D, 0, 0xDC56, 0x4A23,
+ 0, 0, 0x6A6F, 0, 0x6A6E, 0xDC57, 0xDC58, 0xDC59,
+ 0x336C, 0, 0x4B2B, 0x6A70, 0, 0xDC5A, 0xDC5B, 0,
+ 0x7B70, 0x7B71, 0x7B72, 0, 0x7B6E, 0x6A7C, 0x6A72, 0,
+ 0xDC60, 0, 0, 0, 0, 0x6A73, 0xDC61, 0x7B73,
+ 0xDC63, 0, 0x6A74, 0x6A75, 0, 0, 0, 0,
+ 0x7B74, 0xDC65, 0x7B75, 0, 0, 0xDC67, 0x6A79, 0xF83D,
+ 0x6A7A, 0x7B76, 0xDC69, 0x6A78, 0, 0, 0xDC6A, 0,
+};
+static const unsigned short utf8_to_euc_E8A5[] = {
+ 0xDC6B, 0x6A76, 0xDC6C, 0x6A71, 0x6A77, 0xDC6D, 0xDC6E, 0,
+ 0, 0xDC6F, 0, 0, 0x6A7B, 0x7037, 0, 0xDC70,
+ 0, 0, 0xDC71, 0, 0, 0, 0x3228, 0xDC72,
+ 0, 0, 0xDC73, 0xDC74, 0xDC75, 0, 0x6A7E, 0x365F,
+ 0x6A7D, 0xDC76, 0xDC77, 0xDC78, 0x6B22, 0, 0x6B21, 0,
+ 0, 0, 0x6B24, 0xDC79, 0, 0x6B23, 0xDC7A, 0x6B25,
+ 0xDC7B, 0, 0x3D31, 0xDC7C, 0x6B26, 0xDC7D, 0, 0x6B27,
+ 0, 0, 0xDC7E, 0xDD21, 0xDD22, 0xDD23, 0x6B28, 0x403E,
+};
+static const unsigned short utf8_to_euc_E8A5_x0213[] = {
+ 0x7B77, 0x6A76, 0xF83F, 0x6A71, 0x6A77, 0xF840, 0xDC6E, 0,
+ 0, 0xF841, 0, 0, 0x6A7B, 0x7037, 0, 0xDC70,
+ 0, 0, 0xDC71, 0, 0, 0, 0x3228, 0xDC72,
+ 0, 0, 0xDC73, 0xDC74, 0xDC75, 0, 0x6A7E, 0x365F,
+ 0x6A7D, 0xDC76, 0xF844, 0xDC78, 0x6B22, 0, 0x6B21, 0,
+ 0, 0, 0x6B24, 0xDC79, 0, 0x6B23, 0xDC7A, 0x6B25,
+ 0xDC7B, 0, 0x3D31, 0xDC7C, 0x6B26, 0xDC7D, 0, 0x6B27,
+ 0, 0, 0xDC7E, 0xDD21, 0xDD22, 0xDD23, 0x6B28, 0x403E,
+};
+static const unsigned short utf8_to_euc_E8A6[] = {
+ 0, 0x4D57, 0, 0x6B29, 0, 0, 0x4A24, 0x4746,
+ 0x6B2A, 0xDD24, 0x6B2B, 0x382B, 0, 0xDD25, 0, 0x352C,
+ 0xDD26, 0, 0, 0x6B2C, 0xDD27, 0xDD28, 0x3B6B, 0x4741,
+ 0x6B2D, 0, 0x3350, 0xDD29, 0xDD2A, 0, 0, 0xDD2B,
+ 0xDD2C, 0x6B2E, 0, 0, 0, 0xDD2D, 0x6B30, 0x4D77,
+ 0, 0x6B2F, 0x3F46, 0, 0x6B31, 0, 0, 0x6B32,
+ 0xDD2E, 0, 0x6B33, 0x3451, 0xDD2F, 0xDD30, 0xDD31, 0xDD32,
+ 0, 0, 0x6B34, 0, 0xDD33, 0x6B35, 0, 0x6B36,
+};
+static const unsigned short utf8_to_euc_E8A6_x0213[] = {
+ 0xF845, 0x4D57, 0, 0x6B29, 0, 0, 0x4A24, 0x4746,
+ 0x6B2A, 0xF846, 0x6B2B, 0x382B, 0, 0xDD25, 0, 0x352C,
+ 0xF847, 0, 0, 0x6B2C, 0x7B78, 0xDD28, 0x3B6B, 0x4741,
+ 0x6B2D, 0, 0x3350, 0xDD29, 0xDD2A, 0, 0, 0xF848,
+ 0xDD2C, 0x6B2E, 0, 0, 0, 0xDD2D, 0x6B30, 0x4D77,
+ 0, 0x6B2F, 0x3F46, 0, 0x6B31, 0, 0, 0x6B32,
+ 0xF849, 0, 0x6B33, 0x3451, 0xDD2F, 0xDD30, 0xDD31, 0xF84A,
+ 0, 0, 0x6B34, 0, 0xDD33, 0x6B35, 0, 0x6B36,
+};
+static const unsigned short utf8_to_euc_E8A7[] = {
+ 0x6B37, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x3351, 0, 0xDD34, 0xDD35, 0xDD36, 0xDD37,
+ 0xDD38, 0, 0x6B38, 0, 0x6B39, 0x6B3A, 0, 0,
+ 0, 0, 0, 0x3272, 0, 0xDD39, 0x3F28, 0x6B3B,
+ 0, 0xDD3A, 0, 0xDD3B, 0, 0xDD3C, 0, 0,
+ 0, 0xDD3D, 0, 0xDD3E, 0x6B3C, 0, 0xDD3F, 0,
+ 0x6B3D, 0xDD40, 0, 0, 0, 0xDD41, 0, 0xDD42,
+};
+static const unsigned short utf8_to_euc_E8A7_x0213[] = {
+ 0x6B37, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0x3351, 0, 0x7B7A, 0xDD35, 0xF84B, 0xDD37,
+ 0xF84C, 0, 0x6B38, 0, 0x6B39, 0x6B3A, 0, 0,
+ 0, 0, 0, 0x3272, 0, 0x7B7B, 0x3F28, 0x6B3B,
+ 0, 0xDD3A, 0, 0xF84D, 0, 0xDD3C, 0, 0,
+ 0, 0xF84F, 0, 0xF850, 0x6B3C, 0, 0x7B7C, 0,
+ 0x6B3D, 0xDD40, 0, 0, 0, 0xF851, 0, 0xF852,
+};
+static const unsigned short utf8_to_euc_E8A8[] = {
+ 0x3840, 0, 0x447B, 0x6B3E, 0xDD43, 0xDD44, 0, 0xDD45,
+ 0x3757, 0, 0x3F56, 0, 0x6B41, 0, 0x4624, 0xDD46,
+ 0x6B40, 0xDD47, 0xDD48, 0x3731, 0xDD49, 0xDD4A, 0x6B3F, 0x4277,
+ 0x352D, 0, 0, 0x6B42, 0, 0x6B43, 0xDD4B, 0x3E59,
+ 0xDD4C, 0, 0xDD4D, 0x376D, 0xDD4E, 0x6B44, 0xDD4F, 0,
+ 0, 0, 0x4B2C, 0xDD50, 0xDD51, 0x405F, 0, 0xDD52,
+ 0, 0x3576, 0, 0x4C75, 0x414A, 0xDD53, 0x6B45, 0xDD54,
+ 0, 0, 0x3F47, 0x4370, 0x3E5A, 0xDD55, 0xDD56, 0,
+};
+static const unsigned short utf8_to_euc_E8A8_x0213[] = {
+ 0x3840, 0, 0x447B, 0x6B3E, 0xDD43, 0xDD44, 0, 0xDD45,
+ 0x3757, 0, 0x3F56, 0, 0x6B41, 0, 0x4624, 0xDD46,
+ 0x6B40, 0xF854, 0x7B7D, 0x3731, 0xF855, 0x7B7E, 0x6B3F, 0x4277,
+ 0x352D, 0, 0, 0x6B42, 0, 0x6B43, 0xDD4B, 0x3E59,
+ 0xDD4C, 0xF857, 0x7C21, 0x376D, 0xDD4E, 0x6B44, 0xDD4F, 0,
+ 0, 0, 0x4B2C, 0xDD50, 0xDD51, 0x405F, 0, 0xDD52,
+ 0, 0x3576, 0, 0x4C75, 0x414A, 0xF858, 0x6B45, 0x7C22,
+ 0, 0, 0x3F47, 0x4370, 0x3E5A, 0xDD55, 0xF859, 0,
+};
+static const unsigned short utf8_to_euc_E8A9[] = {
+ 0xDD57, 0x6B46, 0, 0xDD58, 0, 0xDD59, 0x6B49, 0xDD5A,
+ 0x6B4A, 0xDD5B, 0, 0, 0, 0xDD5C, 0xDD5D, 0,
+ 0x3A3E, 0x4242, 0x6B48, 0xDD5E, 0x3E5B, 0x493E, 0xDD5F, 0xDD60,
+ 0xDD61, 0, 0, 0x6B47, 0xDD62, 0xDD63, 0x3B6C, 0,
+ 0x3153, 0xDD64, 0x6B4E, 0x3758, 0, 0xDD65, 0x3B6E, 0xDD66,
+ 0, 0x3B6D, 0, 0x4F4D, 0x6B4D, 0x6B4C, 0x4127, 0,
+ 0x354D, 0x4F43, 0x333A, 0x3E5C, 0, 0xDD67, 0xDD68, 0xDD69,
+ 0, 0xDD6A, 0xDD6B, 0xDD6C, 0x6B4B, 0, 0xDD6D, 0xDD6E,
+};
+static const unsigned short utf8_to_euc_E8A9_x0213[] = {
+ 0xDD57, 0x6B46, 0, 0xDD58, 0, 0xF85A, 0x6B49, 0x7C23,
+ 0x6B4A, 0xDD5B, 0, 0, 0, 0xF85B, 0x7C24, 0,
+ 0x3A3E, 0x4242, 0x6B48, 0xDD5E, 0x3E5B, 0x493E, 0xDD5F, 0xDD60,
+ 0xF85C, 0, 0, 0x6B47, 0xDD62, 0x7C25, 0x3B6C, 0,
+ 0x3153, 0x7C26, 0x6B4E, 0x3758, 0, 0xDD65, 0x3B6E, 0xDD66,
+ 0, 0x3B6D, 0, 0x4F4D, 0x6B4D, 0x6B4C, 0x4127, 0,
+ 0x354D, 0x4F43, 0x333A, 0x3E5C, 0, 0x7C27, 0xDD68, 0xDD69,
+ 0, 0x7C28, 0xDD6B, 0xDD6C, 0x6B4B, 0, 0xDD6D, 0xDD6E,
+};
+static const unsigned short utf8_to_euc_E8AA[] = {
+ 0xDD6F, 0, 0x6B50, 0xDD70, 0x6B51, 0x6B4F, 0xDD71, 0x3858,
+ 0, 0x4D40, 0, 0xDD72, 0x3B6F, 0x4727, 0, 0xDD73,
+ 0xDD74, 0x6B54, 0xDD75, 0x4040, 0, 0x4342, 0xDD76, 0xDD77,
+ 0x4D36, 0xDD78, 0x6B57, 0, 0, 0, 0x386C, 0xDD79,
+ 0x403F, 0x6B53, 0, 0x6B58, 0x386D, 0x6B55, 0x6B56, 0xDD7A,
+ 0x6B52, 0xDD7B, 0, 0, 0x4062, 0x4649, 0xDD7C, 0xDD7D,
+ 0x432F, 0, 0x325D, 0xDD7E, 0, 0, 0xDE21, 0xDE22,
+ 0, 0x4870, 0, 0xDE23, 0x3543, 0, 0xDE24, 0x4434,
+};
+static const unsigned short utf8_to_euc_E8AA_x0213[] = {
+ 0xDD6F, 0, 0x6B50, 0xDD70, 0x6B51, 0x6B4F, 0xDD71, 0x3858,
+ 0, 0x4D40, 0, 0xDD72, 0x3B6F, 0x4727, 0, 0xDD73,
+ 0xF85E, 0x6B54, 0xDD75, 0x4040, 0, 0x4342, 0xDD76, 0xDD77,
+ 0x4D36, 0xDD78, 0x6B57, 0, 0, 0, 0x386C, 0xDD79,
+ 0x403F, 0x6B53, 0, 0x6B58, 0x386D, 0x6B55, 0x6B56, 0x7C29,
+ 0x6B52, 0xDD7B, 0, 0, 0x4062, 0x4649, 0xF85D, 0xDD7D,
+ 0x432F, 0, 0x325D, 0xDD7E, 0, 0, 0xDE21, 0xF85F,
+ 0, 0x4870, 0, 0xDE23, 0x3543, 0, 0xF860, 0x4434,
+};
+static const unsigned short utf8_to_euc_E8AB[] = {
+ 0, 0, 0x6B5B, 0xDE25, 0x6B59, 0, 0xDE26, 0x434C,
+ 0xDE27, 0xDE28, 0xDE29, 0x4041, 0x3452, 0x6B5A, 0, 0x3F5B,
+ 0, 0xDE2A, 0x4E4A, 0xDE2B, 0xDE2C, 0xDE2D, 0x4F40, 0xDE2E,
+ 0, 0, 0x6B5C, 0x6B67, 0x4435, 0xDE2F, 0x6B66, 0xDE30,
+ 0x6B63, 0x6B6B, 0x6B64, 0, 0x6B60, 0, 0x447C, 0x6B5F,
+ 0, 0, 0, 0x6B5D, 0xDE31, 0x4D21, 0x3B70, 0,
+ 0xDE32, 0x6B61, 0, 0x6B5E, 0xDE33, 0xDE34, 0xDE35, 0x6B65,
+ 0x3D74, 0, 0x3841, 0, 0xDE36, 0, 0x427A, 0xDE37,
+};
+static const unsigned short utf8_to_euc_E8AB_x0213[] = {
+ 0, 0, 0x6B5B, 0xDE25, 0x6B59, 0, 0xDE26, 0x434C,
+ 0xDE27, 0xDE28, 0xDE29, 0x4041, 0x3452, 0x6B5A, 0, 0x3F5B,
+ 0x7C2A, 0xDE2A, 0x4E4A, 0xDE2B, 0xDE2C, 0xDE2D, 0x4F40, 0xF861,
+ 0, 0, 0x6B5C, 0x6B67, 0x4435, 0xDE2F, 0x6B66, 0x7C2B,
+ 0x6B63, 0x6B6B, 0x6B64, 0, 0x6B60, 0, 0x447C, 0x6B5F,
+ 0, 0, 0, 0x6B5D, 0xDE31, 0x4D21, 0x3B70, 0,
+ 0xDE32, 0x6B61, 0, 0x6B5E, 0x7C2C, 0xDE34, 0x7C2D, 0x6B65,
+ 0x3D74, 0, 0x3841, 0, 0xF862, 0, 0x427A, 0xDE37,
+};
+static const unsigned short utf8_to_euc_E8AC[] = {
+ 0x4B45, 0x315A, 0x3062, 0, 0x4625, 0xDE38, 0xDE39, 0x6B69,
+ 0, 0, 0xDE3F, 0xDE3A, 0x6B68, 0, 0x4666, 0,
+ 0x6B6D, 0xDE3B, 0, 0, 0x6B62, 0, 0x6B6C, 0x6B6E,
+ 0, 0x382C, 0x6B6A, 0x3956, 0xDE3C, 0x3C55, 0xDE3D, 0xDE3E,
+ 0x6B6F, 0x4D58, 0, 0, 0, 0, 0x6B72, 0,
+ 0x6B75, 0, 0, 0x6B73, 0x4935, 0xDE40, 0, 0,
+ 0xDE41, 0, 0, 0x6B70, 0, 0, 0, 0xDE42,
+ 0, 0x3660, 0, 0, 0xDE43, 0, 0x6B74, 0,
+};
+static const unsigned short utf8_to_euc_E8AC_x0213[] = {
+ 0x4B45, 0x315A, 0x3062, 0, 0x4625, 0xF865, 0xDE39, 0x6B69,
+ 0, 0, 0xF864, 0xDE3A, 0x6B68, 0xF866, 0x4666, 0,
+ 0x6B6D, 0xDE3B, 0, 0, 0x6B62, 0, 0x6B6C, 0x6B6E,
+ 0, 0x382C, 0x6B6A, 0x3956, 0xF867, 0x3C55, 0xDE3D, 0xF868,
+ 0x6B6F, 0x4D58, 0, 0, 0, 0, 0x6B72, 0,
+ 0x6B75, 0, 0, 0x6B73, 0x4935, 0xF869, 0, 0,
+ 0xDE41, 0, 0, 0x6B70, 0, 0, 0, 0xDE42,
+ 0, 0x3660, 0, 0, 0xDE43, 0, 0x6B74, 0,
+};
+static const unsigned short utf8_to_euc_E8AD[] = {
+ 0, 0x6B76, 0xDE44, 0xDE45, 0xDE46, 0xDE47, 0xDE48, 0,
+ 0xDE49, 0x6B7A, 0, 0, 0x6B77, 0xDE4E, 0x6B79, 0x6B78,
+ 0, 0, 0xDE4A, 0xDE4B, 0xDE4C, 0, 0x6B7B, 0,
+ 0x3C31, 0xDE4D, 0x6B7D, 0x6B7C, 0x4968, 0, 0xDE4F, 0x6C21,
+ 0, 0, 0, 0xDE50, 0, 0, 0x3759, 0,
+ 0, 0, 0, 0x6B7E, 0x6C22, 0xDE51, 0, 0x6C23,
+ 0x3544, 0x6641, 0x3E79, 0, 0x6C24, 0, 0xDE52, 0x386E,
+ 0xDE53, 0xDE54, 0, 0, 0xDE55, 0x6C25, 0xDE56, 0xF466,
+};
+static const unsigned short utf8_to_euc_E8AD_x0213[] = {
+ 0, 0x6B76, 0xDE44, 0xF86A, 0xDE46, 0xDE47, 0x7C31, 0,
+ 0xDE49, 0x6B7A, 0, 0, 0x6B77, 0xDE4E, 0x6B79, 0x6B78,
+ 0, 0xF86C, 0xDE4A, 0, 0x7C32, 0, 0x6B7B, 0,
+ 0x3C31, 0x7C33, 0x6B7D, 0x6B7C, 0x4968, 0, 0xF86D, 0x6C21,
+ 0, 0, 0, 0xDE50, 0, 0, 0x3759, 0,
+ 0, 0x7C34, 0, 0x6B7E, 0x6C22, 0xDE51, 0, 0x6C23,
+ 0x3544, 0x6641, 0x3E79, 0, 0x6C24, 0, 0xF86E, 0x386E,
+ 0xDE53, 0xDE54, 0, 0, 0xDE55, 0x6C25, 0xDE56, 0xF86F,
+};
+static const unsigned short utf8_to_euc_E8AE[] = {
+ 0x6C26, 0xDE57, 0, 0x3B3E, 0xDE58, 0xDE59, 0, 0,
+ 0, 0, 0x5A4E, 0xDE5A, 0x6C27, 0xDE5B, 0x6C28, 0xDE5C,
+ 0x3D32, 0, 0x6C29, 0x6C2A, 0xDE5D, 0xDE5E, 0x6C2B, 0,
+ 0, 0x6C2C, 0x6C2D, 0, 0xDE5F, 0, 0xDE60, 0xDE61,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E8AE_x0213[] = {
+ 0x6C26, 0xF870, 0, 0x3B3E, 0xDE58, 0xDE59, 0, 0,
+ 0, 0, 0x5A4E, 0xF871, 0x6C27, 0xDE5B, 0x6C28, 0xDE5C,
+ 0x3D32, 0, 0x6C29, 0x6C2A, 0xF872, 0xF873, 0x6C2B, 0,
+ 0, 0x6C2C, 0x6C2D, 0, 0xF874, 0x7C35, 0xF875, 0xDE61,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E8B0[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x432B,
+ 0xDE62, 0xDE63, 0x6C2E, 0, 0, 0xDE64, 0xDE65, 0x6C30,
+};
+static const unsigned short utf8_to_euc_E8B0_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x432B,
+ 0xDE62, 0xF876, 0x6C2E, 0, 0, 0xF878, 0xDE65, 0x6C30,
+};
+static const unsigned short utf8_to_euc_E8B1[] = {
+ 0, 0x6C2F, 0, 0, 0, 0xDE66, 0x4626, 0xDE67,
+ 0x6C31, 0xDE68, 0x4B2D, 0xDE69, 0x6C32, 0, 0x6C33, 0xDE6A,
+ 0x6C34, 0xDE6B, 0, 0xDE6C, 0xDE6D, 0x6C35, 0, 0xDE6E,
+ 0xDE6F, 0xDE72, 0x465A, 0xDE70, 0, 0xDE71, 0, 0,
+ 0, 0x3E5D, 0x6C36, 0xDE73, 0xDE74, 0, 0xDE75, 0,
+ 0xDE76, 0xDE77, 0x396B, 0x502E, 0x6C37, 0xDE78, 0, 0,
+ 0, 0, 0, 0xDE79, 0, 0xDE7A, 0xDE7B, 0,
+ 0x6C38, 0x493F, 0x6C39, 0xDE7C, 0x6C41, 0, 0xDE7D, 0,
+};
+static const unsigned short utf8_to_euc_E8B1_x0213[] = {
+ 0, 0x6C2F, 0, 0, 0, 0xF87B, 0x4626, 0xF87C,
+ 0x6C31, 0x7C36, 0x4B2D, 0xDE69, 0x6C32, 0, 0x6C33, 0xF87D,
+ 0x6C34, 0xDE6B, 0, 0xDE6C, 0xF87E, 0x6C35, 0, 0xF921,
+ 0xDE6F, 0xDE72, 0x465A, 0xDE70, 0, 0xDE71, 0, 0,
+ 0, 0x3E5D, 0x6C36, 0xDE73, 0xDE74, 0, 0xDE75, 0,
+ 0x7C37, 0xF922, 0x396B, 0x502E, 0x6C37, 0xF923, 0, 0,
+ 0, 0, 0, 0xF924, 0, 0xDE7A, 0xDE7B, 0,
+ 0x6C38, 0x493F, 0x6C39, 0xDE7C, 0x6C41, 0, 0xDE7D, 0,
+};
+static const unsigned short utf8_to_euc_E8B2[] = {
+ 0, 0, 0x6C3A, 0, 0, 0x6C3C, 0xDE7E, 0xDF21,
+ 0, 0x6C3B, 0x6C3D, 0xDF22, 0x4B46, 0x6C3E, 0x6C3F, 0,
+ 0xDF23, 0, 0xDF24, 0xDF25, 0x6C40, 0, 0, 0,
+ 0x6C42, 0xDF26, 0, 0xDF27, 0xDF28, 0x332D, 0x4467, 0,
+ 0x4969, 0x3A62, 0x3957, 0, 0xDF29, 0, 0, 0x494F,
+ 0x325F, 0x484E, 0x6C45, 0x3453, 0x4055, 0x6C44, 0x6C49, 0x4379,
+ 0x4C63, 0, 0x6C47, 0x6C48, 0x352E, 0, 0x6C4A, 0x4763,
+ 0x425F, 0xDF2A, 0xDF2B, 0x4871, 0x453D, 0x6C46, 0, 0x4B47,
+};
+static const unsigned short utf8_to_euc_E8B2_x0213[] = {
+ 0, 0, 0x6C3A, 0, 0, 0x6C3C, 0xDE7E, 0xDF21,
+ 0, 0x6C3B, 0x6C3D, 0xDF22, 0x4B46, 0x6C3E, 0x6C3F, 0,
+ 0xDF23, 0, 0xF927, 0xF926, 0x6C40, 0, 0, 0,
+ 0x6C42, 0xF928, 0, 0xF92A, 0xDF28, 0x332D, 0x4467, 0,
+ 0x4969, 0x3A62, 0x3957, 0, 0xF92B, 0, 0, 0x494F,
+ 0x325F, 0x484E, 0x6C45, 0x3453, 0x4055, 0x6C44, 0x6C49, 0x4379,
+ 0x4C63, 0, 0x6C47, 0x6C48, 0x352E, 0, 0x6C4A, 0x4763,
+ 0x425F, 0xDF2A, 0xDF2B, 0x4871, 0x453D, 0x6C46, 0, 0x4B47,
+};
+static const unsigned short utf8_to_euc_E8B3[] = {
+ 0x326C, 0x6C4C, 0x4F28, 0x4442, 0x4F45, 0xDF2C, 0xDF2D, 0x3B71,
+ 0x6C4B, 0xDF2E, 0x4231, 0xDF2F, 0, 0x6C5C, 0x4128, 0xDF30,
+ 0, 0x4678, 0, 0x4950, 0, 0xDF32, 0xDF31, 0,
+ 0, 0xDF33, 0x6C4F, 0x3B3F, 0x3B72, 0xDF34, 0x3E5E, 0,
+ 0x4765, 0xDF35, 0x382D, 0x6C4E, 0x6C4D, 0, 0x496A, 0,
+ 0xDF36, 0, 0x3C41, 0, 0xDF37, 0x4552, 0, 0xDF38,
+ 0xDF39, 0, 0xDF3A, 0, 0xF467, 0xDF3B, 0, 0xDF3C,
+ 0xDF3D, 0, 0x6C51, 0x6C52, 0x3958, 0x6C50, 0xDF3E, 0xDF3F,
+};
+static const unsigned short utf8_to_euc_E8B3_x0213[] = {
+ 0x326C, 0x6C4C, 0x4F28, 0x4442, 0x4F45, 0xDF2C, 0xDF2D, 0x3B71,
+ 0x6C4B, 0xDF2E, 0x4231, 0xDF2F, 0, 0x6C5C, 0x4128, 0xDF30,
+ 0, 0x4678, 0, 0x4950, 0, 0xF92D, 0xF92C, 0,
+ 0, 0xF92E, 0x6C4F, 0x3B3F, 0x3B72, 0xDF34, 0x3E5E, 0,
+ 0x4765, 0x7C39, 0x382D, 0x6C4E, 0x6C4D, 0, 0x496A, 0,
+ 0xDF36, 0, 0x3C41, 0, 0xDF37, 0x4552, 0, 0xDF38,
+ 0xF930, 0xF931, 0xDF3A, 0, 0x7C3A, 0xDF3B, 0, 0xDF3C,
+ 0x7C3B, 0, 0x6C51, 0x6C52, 0x3958, 0x6C50, 0x7C3C, 0xDF3F,
+};
+static const unsigned short utf8_to_euc_E8B4[] = {
+ 0, 0xDF40, 0, 0xDF41, 0x6C53, 0x6C54, 0, 0x6C56,
+ 0x4223, 0xDF42, 0x6C55, 0x3466, 0, 0x6C58, 0, 0x6C57,
+ 0x6C59, 0, 0xDF43, 0x6C5B, 0x6C5D, 0, 0x6C5E, 0xDF44,
+ 0, 0, 0, 0xDF45, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E8B4_x0213[] = {
+ 0, 0xDF40, 0, 0xDF41, 0x6C53, 0x6C54, 0, 0x6C56,
+ 0x4223, 0xF933, 0x6C55, 0x3466, 0, 0x6C58, 0xF934, 0x6C57,
+ 0x6C59, 0, 0x7C3E, 0x6C5B, 0x6C5D, 0, 0x6C5E, 0xDF44,
+ 0, 0, 0, 0x7C3F, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E8B5[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x4056, 0xDF46, 0x3C4F, 0x6C5F,
+ 0, 0xDF47, 0, 0x3352, 0xDF48, 0x6C60, 0xDF49, 0,
+ 0x4176, 0x6C61, 0, 0x6C62, 0x496B, 0, 0xF468, 0x352F,
+ 0, 0, 0, 0, 0, 0, 0, 0xDF4A,
+};
+static const unsigned short utf8_to_euc_E8B5_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x4056, 0xDF46, 0x3C4F, 0x6C5F,
+ 0, 0xDF47, 0, 0x3352, 0xF935, 0x6C60, 0xDF49, 0,
+ 0x4176, 0x6C61, 0, 0x6C62, 0x496B, 0, 0, 0x352F,
+ 0, 0, 0, 0, 0, 0, 0, 0xDF4A,
+};
+static const unsigned short utf8_to_euc_E8B6[] = {
+ 0, 0x6C63, 0xDF4B, 0, 0xDF4C, 0x4436, 0, 0,
+ 0xDF4D, 0, 0x315B, 0, 0, 0xDF4E, 0, 0,
+ 0xDF4F, 0xDF50, 0, 0, 0, 0xDF51, 0, 0,
+ 0, 0x6C64, 0, 0, 0, 0, 0xDF52, 0xDF53,
+ 0xDF54, 0, 0, 0x3C71, 0, 0, 0xDF55, 0,
+ 0x3F76, 0, 0, 0xDF56, 0xDF57, 0, 0, 0xDF58,
+ 0, 0, 0xDF59, 0x422D, 0, 0xDF5A, 0, 0xDF5B,
+ 0, 0xDF5C, 0x6C67, 0xDF5D, 0xDF6F, 0, 0x6C66, 0,
+};
+static const unsigned short utf8_to_euc_E8B6_x0213[] = {
+ 0, 0x6C63, 0xDF4B, 0, 0xF936, 0x4436, 0, 0,
+ 0xDF4D, 0, 0x315B, 0, 0, 0xDF4E, 0, 0,
+ 0xDF4F, 0xDF50, 0, 0, 0, 0xF937, 0, 0,
+ 0, 0x6C64, 0, 0, 0, 0, 0xDF52, 0xDF53,
+ 0xDF54, 0, 0, 0x3C71, 0, 0, 0xF938, 0,
+ 0x3F76, 0, 0, 0xDF56, 0xDF57, 0, 0, 0x7C40,
+ 0, 0, 0xDF59, 0x422D, 0, 0xDF5A, 0, 0xDF5B,
+ 0, 0xDF5C, 0x6C67, 0xDF5D, 0xDF6F, 0, 0x6C66, 0,
+};
+static const unsigned short utf8_to_euc_E8B7[] = {
+ 0xDF5E, 0, 0x6C65, 0, 0, 0xDF5F, 0xDF60, 0xDF61,
+ 0xDF62, 0, 0xDF63, 0x6C6D, 0x6C6B, 0, 0xDF64, 0x6C68,
+ 0, 0xDF65, 0, 0, 0xDF66, 0xDF67, 0x6C6A, 0xDF68,
+ 0, 0xDF69, 0x6C69, 0x6C6C, 0, 0x3577, 0, 0x6C70,
+ 0, 0x4057, 0, 0x6C71, 0xDF6A, 0xDF6B, 0, 0xDF6C,
+ 0x3859, 0, 0x6C6E, 0x6C6F, 0xDF6D, 0, 0, 0x4F29,
+ 0xDF6E, 0xDF70, 0xDF71, 0x4437, 0xDF72, 0x4129, 0, 0,
+ 0, 0, 0, 0, 0x6C72, 0xDF73, 0, 0x6C75,
+};
+static const unsigned short utf8_to_euc_E8B7_x0213[] = {
+ 0xDF5E, 0, 0x6C65, 0, 0, 0xDF5F, 0xF93A, 0xDF61,
+ 0xF93B, 0, 0xDF63, 0x6C6D, 0x6C6B, 0, 0x7C41, 0x6C68,
+ 0, 0x7C42, 0, 0, 0xDF66, 0xDF67, 0x6C6A, 0x7C43,
+ 0, 0xF93C, 0x6C69, 0x6C6C, 0, 0x3577, 0, 0x6C70,
+ 0, 0x4057, 0, 0x6C71, 0xDF6A, 0xDF6B, 0, 0xDF6C,
+ 0x3859, 0, 0x6C6E, 0x6C6F, 0xF93D, 0, 0, 0x4F29,
+ 0xDF6E, 0xDF70, 0xDF71, 0x4437, 0xDF72, 0x4129, 0, 0,
+ 0, 0, 0, 0, 0x6C72, 0xF940, 0, 0x6C75,
+};
+static const unsigned short utf8_to_euc_E8B8[] = {
+ 0, 0xDF74, 0, 0, 0xDF75, 0xDF76, 0xDF77, 0,
+ 0x6C73, 0x6C74, 0x4D59, 0xDF78, 0, 0, 0, 0x4627,
+ 0x6C78, 0xDF79, 0, 0, 0xDF7A, 0, 0xDF7B, 0,
+ 0, 0, 0, 0, 0, 0x6C76, 0x6C77, 0x6C79,
+ 0xDF7C, 0xDF7D, 0xDF7E, 0xE021, 0, 0, 0xE022, 0xE023,
+ 0, 0, 0x6D29, 0, 0, 0, 0, 0,
+ 0x6C7C, 0xE024, 0, 0xE025, 0x6C7D, 0x6C7B, 0xE026, 0xE027,
+ 0xE028, 0xE029, 0, 0, 0, 0xE02A, 0, 0,
+};
+static const unsigned short utf8_to_euc_E8B8_x0213[] = {
+ 0, 0xDF74, 0, 0, 0xDF75, 0xDF76, 0xF941, 0,
+ 0x6C73, 0x6C74, 0x4D59, 0xDF78, 0xF93E, 0, 0, 0x4627,
+ 0x6C78, 0xDF79, 0, 0, 0xF943, 0, 0xF944, 0,
+ 0, 0, 0, 0, 0, 0x6C76, 0x6C77, 0x6C79,
+ 0x7C44, 0xF945, 0xF946, 0x7C45, 0, 0, 0xE022, 0xF947,
+ 0, 0, 0x6D29, 0, 0, 0, 0, 0,
+ 0x6C7C, 0xE024, 0, 0xE025, 0x6C7D, 0x6C7B, 0xF94A, 0xE027,
+ 0xE028, 0xF94B, 0, 0, 0, 0x7C46, 0, 0,
+};
+static const unsigned short utf8_to_euc_E8B9[] = {
+ 0xE02B, 0xE02C, 0x6C7A, 0, 0x447D, 0, 0, 0x6D21,
+ 0x6D25, 0x6D22, 0x6C7E, 0xE02D, 0x6D23, 0xE02E, 0xE02F, 0xE030,
+ 0x6D24, 0, 0, 0, 0xE031, 0x6D2B, 0, 0,
+ 0, 0x6D26, 0, 0xE032, 0xE033, 0xE034, 0xE035, 0x4058,
+ 0x6D28, 0xE036, 0xE037, 0x6D2A, 0x6D27, 0, 0, 0,
+ 0, 0xE038, 0, 0, 0xE039, 0xE03A, 0, 0xE03B,
+ 0xE03C, 0xE03D, 0x6D2D, 0, 0x3D33, 0, 0x6D2C, 0,
+ 0, 0xE03E, 0xE03F, 0xE040, 0x6D2E, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E8B9_x0213[] = {
+ 0xE02B, 0xE02C, 0x6C7A, 0, 0x447D, 0, 0, 0x6D21,
+ 0x6D25, 0x6D22, 0x6C7E, 0xF94C, 0x6D23, 0xE02E, 0xE02F, 0xE030,
+ 0x6D24, 0, 0, 0, 0xF94D, 0x6D2B, 0, 0,
+ 0, 0x6D26, 0, 0xE032, 0xE033, 0xE034, 0xE035, 0x4058,
+ 0x6D28, 0xE036, 0xF94E, 0x6D2A, 0x6D27, 0, 0, 0,
+ 0, 0xE038, 0, 0, 0xF94F, 0xF950, 0, 0xF951,
+ 0x7C47, 0xE03D, 0x6D2D, 0, 0x3D33, 0, 0x6D2C, 0,
+ 0, 0xE03E, 0xE03F, 0x7C48, 0x6D2E, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E8BA[] = {
+ 0, 0x6D2F, 0xE041, 0xE042, 0x6D32, 0x6D31, 0, 0x6D30,
+ 0, 0xE043, 0x6D34, 0x6D33, 0, 0x4C76, 0, 0,
+ 0xE044, 0x6D36, 0xE045, 0x6D35, 0x6D37, 0xE046, 0, 0,
+ 0, 0x6D38, 0xE047, 0xE048, 0, 0xE049, 0xE04A, 0,
+ 0, 0x6D3A, 0xE04B, 0, 0, 0, 0, 0xE04C,
+ 0, 0xE04D, 0x6D39, 0x3F48, 0x6D3B, 0xE04E, 0xE04F, 0x366D,
+ 0x6D3C, 0x6D3E, 0, 0xE050, 0, 0xE051, 0, 0,
+ 0, 0, 0xE052, 0xE053, 0, 0, 0x6D3F, 0,
+};
+static const unsigned short utf8_to_euc_E8BA_x0213[] = {
+ 0, 0x6D2F, 0xE041, 0xE042, 0x6D32, 0x6D31, 0, 0x6D30,
+ 0, 0xE043, 0x6D34, 0x6D33, 0, 0x4C76, 0, 0,
+ 0xE044, 0x6D36, 0xE045, 0x6D35, 0x6D37, 0xE046, 0, 0,
+ 0xF952, 0x6D38, 0xE047, 0xE048, 0, 0xE049, 0xF953, 0,
+ 0, 0x6D3A, 0xE04B, 0, 0, 0, 0, 0xE04C,
+ 0, 0xE04D, 0x6D39, 0x3F48, 0x6D3B, 0xE04E, 0xF954, 0x366D,
+ 0x6D3C, 0x6D3E, 0, 0xF955, 0, 0xF956, 0xF957, 0,
+ 0, 0, 0xE052, 0xF958, 0, 0, 0x6D3F, 0,
+};
+static const unsigned short utf8_to_euc_E8BB[] = {
+ 0xE054, 0xE055, 0, 0xE056, 0xE057, 0x6D40, 0x6D3D, 0xE058,
+ 0x6D41, 0, 0x3C56, 0x6D42, 0x3530, 0x3733, 0, 0xE059,
+ 0, 0xE05A, 0x382E, 0, 0xE05B, 0, 0, 0,
+ 0, 0, 0, 0x6D43, 0xE05C, 0, 0, 0x4670,
+ 0, 0, 0x453E, 0x6D44, 0, 0, 0, 0,
+ 0xE05D, 0, 0, 0x6D47, 0, 0xE064, 0xE05E, 0,
+ 0xE05F, 0xE060, 0, 0, 0, 0, 0, 0xE061,
+ 0x3C34, 0xE062, 0xE063, 0x6D46, 0x6D45, 0x375A, 0x6D48, 0,
+};
+static const unsigned short utf8_to_euc_E8BB_x0213[] = {
+ 0x7C4A, 0xE055, 0, 0xE056, 0xE057, 0x6D40, 0x6D3D, 0xE058,
+ 0x6D41, 0, 0x3C56, 0x6D42, 0x3530, 0x3733, 0, 0,
+ 0, 0xF95A, 0x382E, 0, 0xF95B, 0, 0, 0,
+ 0, 0, 0, 0x6D43, 0xE05C, 0, 0, 0x4670,
+ 0, 0, 0x453E, 0x6D44, 0, 0, 0, 0,
+ 0xE05D, 0, 0, 0x6D47, 0, 0xE064, 0xE05E, 0,
+ 0xE05F, 0xE060, 0, 0, 0, 0, 0, 0xE061,
+ 0x3C34, 0xF95D, 0x7C4C, 0x6D46, 0x6D45, 0x375A, 0x6D48, 0,
+};
+static const unsigned short utf8_to_euc_E8BC[] = {
+ 0xE065, 0, 0xE066, 0x3353, 0, 0x6D4A, 0, 0xE067,
+ 0xE068, 0x3A5C, 0x6D49, 0, 0x6D52, 0, 0, 0xE069,
+ 0xE06A, 0, 0x6D4C, 0x6D4E, 0x4A65, 0x6D4B, 0xE06B, 0xE06C,
+ 0xE06D, 0x6D4D, 0, 0x6D51, 0x6D4F, 0x3531, 0xE06E, 0x6D50,
+ 0xE06F, 0xE070, 0, 0xE071, 0, 0xE072, 0x6D53, 0xE073,
+ 0xE074, 0x475A, 0x4E58, 0, 0xE075, 0xE076, 0xE077, 0x3D34,
+ 0, 0, 0, 0x6D54, 0xE078, 0xE079, 0xE07A, 0xE07B,
+ 0x4D22, 0x6D56, 0xE07C, 0x6D55, 0, 0, 0x6D59, 0x4D41,
+};
+static const unsigned short utf8_to_euc_E8BC_x0213[] = {
+ 0xF95F, 0, 0xE066, 0x3353, 0, 0x6D4A, 0, 0xE067,
+ 0xF960, 0x3A5C, 0x6D49, 0, 0x6D52, 0, 0, 0xE069,
+ 0xE06A, 0, 0x6D4C, 0x6D4E, 0x4A65, 0x6D4B, 0xE06B, 0xF961,
+ 0xE06D, 0x6D4D, 0, 0x6D51, 0x6D4F, 0x3531, 0x7C4D, 0x6D50,
+ 0xE06F, 0xE070, 0, 0xE071, 0, 0xE072, 0x6D53, 0xE073,
+ 0xE074, 0x475A, 0x4E58, 0xF962, 0xE075, 0x7C4E, 0xE077, 0x3D34,
+ 0, 0, 0, 0x6D54, 0xE078, 0xE079, 0x7C4F, 0xE07B,
+ 0x4D22, 0x6D56, 0xE07C, 0x6D55, 0, 0, 0x6D59, 0x4D41,
+};
+static const unsigned short utf8_to_euc_E8BD[] = {
+ 0xE07D, 0xE07E, 0x6D58, 0xE121, 0x336D, 0x6D57, 0x6D5C, 0xE122,
+ 0, 0x6D5B, 0, 0, 0x6D5A, 0x4532, 0x6D5D, 0xE123,
+ 0, 0xE124, 0xE125, 0xE126, 0xE127, 0xE128, 0, 0x6D5E,
+ 0xE129, 0, 0, 0, 0x6D5F, 0xE12A, 0xE12B, 0x396C,
+ 0, 0x3725, 0x6D60, 0x6D61, 0x6D62, 0xE12C, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E8BD_x0213[] = {
+ 0xF963, 0xE07E, 0x6D58, 0xE121, 0x336D, 0x6D57, 0x6D5C, 0xE122,
+ 0, 0x6D5B, 0xF964, 0, 0x6D5A, 0x4532, 0x6D5D, 0xE123,
+ 0, 0xE124, 0xE125, 0xE126, 0x7C50, 0xE128, 0, 0x6D5E,
+ 0xF965, 0, 0, 0, 0x6D5F, 0xE12A, 0xE12B, 0x396C,
+ 0, 0x3725, 0x6D60, 0x6D61, 0x6D62, 0xE12C, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E8BE[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x3F49, 0x6D63, 0xE12D, 0x3C2D, 0x6D64,
+ 0xE12E, 0xE12F, 0, 0x6D65, 0xE130, 0xE131, 0xE132, 0x5221,
+ 0x517E, 0, 0, 0, 0, 0x6D66, 0x6570, 0x6D67,
+ 0x4324, 0x3F2B, 0x4740, 0, 0, 0xE133, 0xE134, 0x6D68,
+ 0xE135, 0, 0x4A55, 0x4454, 0x397E, 0, 0xE136, 0x4329,
+};
+static const unsigned short utf8_to_euc_E8BE_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x3F49, 0x6D63, 0xE12D, 0x3C2D, 0x6D64,
+ 0xE12E, 0xE12F, 0, 0x6D65, 0xF967, 0xE131, 0x7C52, 0x5221,
+ 0x517E, 0, 0, 0, 0, 0x6D66, 0x6570, 0x6D67,
+ 0x4324, 0x3F2B, 0x4740, 0, 0xF968, 0x7C53, 0xF96A, 0x6D68,
+ 0xE135, 0, 0x4A55, 0x4454, 0x397E, 0, 0xE136, 0x4329,
+};
+static const unsigned short utf8_to_euc_E8BF[] = {
+ 0xE137, 0xE138, 0x312A, 0, 0x4B78, 0x3F57, 0xE139, 0,
+ 0, 0, 0xE13A, 0xE13B, 0, 0xE13C, 0x375E, 0,
+ 0xE13D, 0x3661, 0xE13E, 0xE13F, 0x4A56, 0xE140, 0, 0,
+ 0, 0, 0x6D69, 0, 0, 0, 0, 0,
+ 0xE141, 0, 0x6D6B, 0xE142, 0xE143, 0x6D6A, 0x3260, 0,
+ 0xE144, 0x4676, 0x6D6C, 0x4777, 0, 0x4533, 0xE145, 0x6D6D,
+ 0x3D52, 0xE146, 0, 0, 0x6D6F, 0xE147, 0xE148, 0x4C42,
+ 0x6D7E, 0x6D71, 0x6D72, 0xE149, 0, 0x4449, 0xE14A, 0,
+};
+static const unsigned short utf8_to_euc_E8BF_x0213[] = {
+ 0xE137, 0xF96C, 0x312A, 0, 0x4B78, 0x3F57, 0xF96D, 0,
+ 0, 0, 0xF96F, 0xE13B, 0, 0xF970, 0x375E, 0,
+ 0xE13D, 0x3661, 0xE13E, 0xF971, 0x4A56, 0xF972, 0, 0,
+ 0, 0, 0x6D69, 0, 0, 0, 0, 0,
+ 0xF973, 0, 0x6D6B, 0xE142, 0x7C54, 0x6D6A, 0x3260, 0,
+ 0x7C55, 0x4676, 0x6D6C, 0x4777, 0, 0x4533, 0x7C56, 0x6D6D,
+ 0x3D52, 0xF974, 0, 0, 0x6D6F, 0xF975, 0xE148, 0x4C42,
+ 0x6D7E, 0x6D71, 0x6D72, 0xF976, 0, 0x4449, 0xE14A, 0,
+};
+static const unsigned short utf8_to_euc_E980[] = {
+ 0x4260, 0x4177, 0xE14B, 0x4628, 0xE14C, 0x6D70, 0x3555, 0,
+ 0xE14D, 0, 0, 0x6D79, 0xE14E, 0x6D76, 0x6E25, 0x4629,
+ 0x4360, 0x6D73, 0, 0x447E, 0x4553, 0x6D74, 0x6D78, 0x3F60,
+ 0xE14F, 0x4767, 0x444C, 0xE150, 0, 0x4042, 0x6D77, 0x422E,
+ 0x4224, 0x6D75, 0x3029, 0x4F22, 0, 0, 0, 0x6D7A,
+ 0xE151, 0xE152, 0xE154, 0, 0xE155, 0xE156, 0x4261, 0xE153,
+ 0, 0x3D35, 0x3F4A, 0xE157, 0xE158, 0x6D7C, 0x6D7B, 0xE159,
+ 0x306F, 0x6D7D, 0, 0, 0x492F, 0, 0x6E27, 0xE15A,
+};
+static const unsigned short utf8_to_euc_E980_x0213[] = {
+ 0x4260, 0x4177, 0xF977, 0x4628, 0xE14C, 0x6D70, 0x3555, 0,
+ 0x7C57, 0, 0, 0x6D79, 0xF978, 0x6D76, 0x6E25, 0x4629,
+ 0x4360, 0x6D73, 0, 0x447E, 0x4553, 0x6D74, 0x6D78, 0x3F60,
+ 0xE14F, 0x4767, 0x444C, 0xE150, 0, 0x4042, 0x6D77, 0x422E,
+ 0x4224, 0x6D75, 0x3029, 0x4F22, 0, 0, 0, 0x6D7A,
+ 0xE151, 0xE152, 0xE154, 0, 0xE155, 0x7C58, 0x4261, 0xE153,
+ 0, 0x3D35, 0x3F4A, 0xE157, 0xE158, 0x6D7C, 0x6D7B, 0xF979,
+ 0x306F, 0x6D7D, 0, 0, 0x492F, 0, 0x6E27, 0xE15A,
+};
+static const unsigned short utf8_to_euc_E981[] = {
+ 0, 0x465B, 0x3F6B, 0xE15B, 0xE15C, 0x4359, 0, 0x3678,
+ 0, 0x6E26, 0x4D37, 0x313F, 0xE15D, 0x4A57, 0x3261, 0x6E21,
+ 0x6E22, 0x6E23, 0x6E24, 0x463B, 0x4323, 0x3063, 0x6E28, 0,
+ 0x6E29, 0x7423, 0, 0xE15E, 0x423D, 0xE15F, 0x6E2A, 0,
+ 0x3173, 0x414C, 0xE160, 0x382F, 0, 0x4D5A, 0xE161, 0xE162,
+ 0x6E2B, 0x452C, 0, 0, 0xE163, 0x4178, 0x3C57, 0x6E2C,
+ 0xE164, 0, 0x6E2F, 0, 0xE165, 0x3D65, 0x6E2D, 0x412B,
+ 0x412A, 0xE166, 0x3064, 0, 0x4E4B, 0x6E31, 0, 0x4872,
+};
+static const unsigned short utf8_to_euc_E981_x0213[] = {
+ 0, 0x465B, 0x3F6B, 0xF97B, 0xF97C, 0x4359, 0, 0x3678,
+ 0, 0x6E26, 0x4D37, 0x313F, 0xE15D, 0x4A57, 0x3261, 0x6E21,
+ 0x6E22, 0x6E23, 0x6E24, 0x463B, 0x4323, 0x3063, 0x6E28, 0,
+ 0x6E29, 0x7423, 0, 0xE15E, 0x423D, 0xF97D, 0x6E2A, 0,
+ 0x3173, 0x414C, 0xE160, 0x382F, 0, 0x4D5A, 0xE161, 0,
+ 0x6E2B, 0x452C, 0, 0, 0xE163, 0x4178, 0x3C57, 0x6E2C,
+ 0xE164, 0, 0x6E2F, 0, 0xE165, 0x3D65, 0x6E2D, 0x412B,
+ 0x412A, 0xE166, 0x3064, 0, 0x4E4B, 0x6E31, 0, 0x4872,
+};
+static const unsigned short utf8_to_euc_E982[] = {
+ 0x6E33, 0x6E32, 0x6E30, 0x6364, 0x3454, 0xE167, 0, 0x6D6E,
+ 0xE168, 0x6E35, 0x6E34, 0xE169, 0xE16A, 0, 0xE16B, 0x6E36,
+ 0xE16C, 0x4D38, 0, 0, 0, 0xE16D, 0, 0xE16E,
+ 0xE16F, 0xE170, 0, 0xE171, 0, 0, 0, 0,
+ 0xE172, 0xE173, 0xE174, 0x4661, 0, 0xE175, 0x4B2E, 0,
+ 0x6E37, 0, 0x3C59, 0, 0, 0, 0, 0x6E38,
+ 0xE176, 0x6E39, 0xE177, 0xE178, 0xE179, 0x6E3A, 0xE17A, 0,
+ 0x4521, 0, 0, 0, 0, 0xE17B, 0xE17D, 0,
+};
+static const unsigned short utf8_to_euc_E982_x0213[] = {
+ 0x6E33, 0x6E32, 0x6E30, 0x6364, 0x3454, 0xFA22, 0, 0x6D6E,
+ 0x7C5A, 0x6E35, 0x6E34, 0xE169, 0xFA23, 0, 0xE16B, 0x6E36,
+ 0xFA24, 0x4D38, 0, 0, 0, 0x7C5B, 0, 0x7C5C,
+ 0xE16F, 0x7C5D, 0, 0x7C5E, 0, 0, 0, 0,
+ 0xE172, 0xFA26, 0x7C5F, 0x4661, 0, 0xE175, 0x4B2E, 0,
+ 0x6E37, 0, 0x3C59, 0, 0, 0, 0, 0x6E38,
+ 0xFA28, 0x6E39, 0xE177, 0x7C60, 0xE179, 0x6E3A, 0xFA29, 0,
+ 0x4521, 0, 0, 0, 0, 0xE17B, 0x7C61, 0,
+};
+static const unsigned short utf8_to_euc_E983[] = {
+ 0, 0x306A, 0, 0xE17E, 0xE221, 0xE222, 0, 0xE223,
+ 0xE224, 0, 0x3959, 0, 0xE17C, 0, 0x4F3A, 0,
+ 0, 0, 0xE22D, 0, 0, 0xE225, 0, 0xE226,
+ 0xE227, 0xE228, 0, 0x6E3E, 0xE229, 0xE22A, 0xF46C, 0xE22B,
+ 0, 0x3734, 0x6E3B, 0, 0x6E3C, 0xE22C, 0, 0,
+ 0x4974, 0, 0, 0xE22F, 0, 0x3354, 0, 0xE230,
+ 0xE231, 0, 0, 0, 0xE232, 0x4D39, 0xE22E, 0x363F,
+ 0, 0, 0, 0, 0, 0x4554, 0xE233, 0xE234,
+};
+static const unsigned short utf8_to_euc_E983_x0213[] = {
+ 0, 0x306A, 0, 0xFA2A, 0x7C62, 0x7C63, 0, 0x7C64,
+ 0xFA2B, 0, 0x3959, 0, 0xE17C, 0, 0x4F3A, 0,
+ 0, 0, 0xE22D, 0, 0, 0xE225, 0, 0x7C65,
+ 0xE227, 0xE228, 0, 0x6E3E, 0xFA2D, 0x7C66, 0x7C67, 0xFA2E,
+ 0, 0x3734, 0x6E3B, 0, 0x6E3C, 0xE22C, 0, 0,
+ 0x4974, 0, 0, 0xFA33, 0, 0x3354, 0, 0x7C68,
+ 0xE231, 0, 0xFA31, 0, 0x7C69, 0x4D39, 0xFA30, 0x363F,
+ 0, 0, 0, 0, 0, 0x4554, 0xFA34, 0xFA35,
+};
+static const unsigned short utf8_to_euc_E984[] = {
+ 0xE235, 0, 0x6E3F, 0, 0xE236, 0xE237, 0xE238, 0,
+ 0xE239, 0, 0, 0, 0, 0xE23A, 0, 0,
+ 0xE23B, 0, 0x6E40, 0, 0xE23C, 0xF46E, 0xE23D, 0xE23E,
+ 0xE23F, 0x6E41, 0xE240, 0, 0xE241, 0, 0xE242, 0,
+ 0xE243, 0, 0xE245, 0xE246, 0, 0xE244, 0, 0xE247,
+ 0, 0xE248, 0, 0, 0, 0x4522, 0xE249, 0xE24A,
+ 0x6E43, 0xE24B, 0x6E42, 0, 0xE24C, 0, 0xE24D, 0xE24E,
+ 0, 0xE24F, 0xE250, 0, 0xE251, 0xE252, 0, 0,
+};
+static const unsigned short utf8_to_euc_E984_x0213[] = {
+ 0xFA32, 0, 0x6E3F, 0, 0xFA36, 0xE237, 0xFA37, 0,
+ 0xE239, 0, 0, 0, 0, 0xE23A, 0, 0,
+ 0xE23B, 0, 0x6E40, 0, 0x7C6B, 0x7C6C, 0x7C6D, 0xE23E,
+ 0xFA38, 0x6E41, 0xE240, 0, 0xFA39, 0, 0xFA3A, 0,
+ 0xE243, 0, 0x7C6E, 0x7C6F, 0, 0xE244, 0, 0x7C70,
+ 0, 0xE248, 0, 0, 0, 0x4522, 0xE249, 0x7C71,
+ 0x6E43, 0x7C72, 0x6E42, 0, 0x7C73, 0, 0xE24D, 0xFA3B,
+ 0, 0xFA3C, 0xFA3D, 0, 0xE251, 0x7C74, 0, 0,
+};
+static const unsigned short utf8_to_euc_E985[] = {
+ 0, 0, 0, 0xE253, 0, 0, 0, 0xE254,
+ 0xE255, 0x4653, 0x6E44, 0x3D36, 0x3C60, 0x475B, 0x4371, 0xE256,
+ 0, 0, 0x3C72, 0xE257, 0x3F6C, 0, 0x6E45, 0xE258,
+ 0x6E46, 0xE259, 0xE25A, 0xE25B, 0, 0, 0, 0,
+ 0, 0xE25C, 0x3F5D, 0x6E47, 0xE25D, 0x6E48, 0, 0xE25E,
+ 0, 0x6E49, 0x4D6F, 0, 0x3D37, 0xE25F, 0, 0,
+ 0, 0, 0x6E4B, 0x6E4A, 0xE260, 0x395A, 0, 0x3973,
+ 0x3B40, 0xE261, 0xE262, 0xE263, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E985_x0213[] = {
+ 0, 0, 0, 0xE253, 0, 0, 0xFA3E, 0xFA3F,
+ 0x7C75, 0x4653, 0x6E44, 0x3D36, 0x3C60, 0x475B, 0x4371, 0xE256,
+ 0, 0, 0x3C72, 0xE257, 0x3F6C, 0, 0x6E45, 0xFA40,
+ 0x6E46, 0xFA41, 0xE25A, 0x7C76, 0, 0, 0, 0,
+ 0, 0xFA42, 0x3F5D, 0x6E47, 0xFA43, 0x6E48, 0, 0xE25E,
+ 0, 0x6E49, 0x4D6F, 0, 0x3D37, 0xE25F, 0, 0,
+ 0, 0, 0x6E4B, 0x6E4A, 0xFA44, 0x395A, 0, 0x3973,
+ 0x3B40, 0xFA45, 0xE262, 0xE263, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E986[] = {
+ 0, 0xE264, 0x6E4E, 0xE265, 0, 0xE266, 0xE267, 0x3D66,
+ 0, 0x6E4D, 0xE268, 0x6E4C, 0, 0x4269, 0xE269, 0,
+ 0x386F, 0xE26A, 0x4043, 0xE26B, 0xE26C, 0xE26D, 0, 0x4830,
+ 0xE26E, 0, 0, 0, 0x3D39, 0, 0xE26F, 0,
+ 0, 0xE270, 0x6E4F, 0, 0x3E5F, 0, 0xE271, 0,
+ 0xE272, 0, 0x6E52, 0x6E50, 0xE273, 0xE274, 0xE275, 0x6E51,
+ 0xE276, 0xE277, 0xE278, 0xE279, 0x6E54, 0x6E53, 0xE27A, 0,
+ 0x3E7A, 0, 0x6E55, 0xE27B, 0xE27C, 0xE27D, 0, 0xE27E,
+};
+static const unsigned short utf8_to_euc_E986_x0213[] = {
+ 0, 0xE264, 0x6E4E, 0x7C77, 0, 0xFA46, 0xE267, 0x3D66,
+ 0, 0x6E4D, 0xE268, 0x6E4C, 0, 0x4269, 0xFA47, 0,
+ 0x386F, 0xE26A, 0x4043, 0xE26B, 0xE26C, 0xE26D, 0, 0x4830,
+ 0xE26E, 0, 0, 0, 0x3D39, 0, 0x7C78, 0,
+ 0, 0xE270, 0x6E4F, 0, 0x3E5F, 0, 0xE271, 0,
+ 0xFA48, 0, 0x6E52, 0x6E50, 0x7C79, 0xE274, 0xFA49, 0x6E51,
+ 0xE276, 0x7C7A, 0xE278, 0xFA4A, 0x6E54, 0x6E53, 0xFA4B, 0,
+ 0x3E7A, 0, 0x6E55, 0xE27B, 0x7C7B, 0xE27D, 0, 0xE27E,
+};
+static const unsigned short utf8_to_euc_E987[] = {
+ 0x6E56, 0x6E57, 0xE321, 0xE322, 0, 0xE323, 0x4850, 0x3A53,
+ 0x3C61, 0x6E58, 0, 0x6E59, 0x4E24, 0x3D45, 0x4C6E, 0x4E4C,
+ 0x6E5A, 0x3662, 0, 0xE324, 0xE325, 0, 0x6E5B, 0xE326,
+ 0x4523, 0xE327, 0xE328, 0x6E5E, 0x3378, 0x3F4B, 0xE329, 0x6E5C,
+ 0, 0x6E5D, 0, 0x4460, 0xE32A, 0xE32B, 0x4B55, 0x367C,
+ 0, 0xE32C, 0xE32D, 0, 0xE32E, 0xE32F, 0xE330, 0xE331,
+ 0xE332, 0xE333, 0, 0, 0, 0x6E60, 0x6E61, 0xE334,
+ 0, 0xE335, 0, 0xE336, 0x6E5F, 0xE337, 0, 0x6E63,
+};
+static const unsigned short utf8_to_euc_E987_x0213[] = {
+ 0x6E56, 0x6E57, 0xE321, 0xFA4C, 0xFA4D, 0xE323, 0x4850, 0x3A53,
+ 0x3C61, 0x6E58, 0, 0x6E59, 0x4E24, 0x3D45, 0x4C6E, 0x4E4C,
+ 0x6E5A, 0x3662, 0, 0xE324, 0xE325, 0, 0x6E5B, 0x7C7C,
+ 0x4523, 0xE327, 0xFA4E, 0x6E5E, 0x3378, 0x3F4B, 0, 0x6E5C,
+ 0, 0x6E5D, 0, 0x4460, 0x7C7E, 0x7D21, 0x4B55, 0x367C,
+ 0, 0xE32C, 0xE32D, 0, 0xFA51, 0x7D22, 0xFA52, 0xE331,
+ 0xE332, 0x7D23, 0, 0, 0, 0x6E60, 0x6E61, 0xE334,
+ 0, 0xE335, 0, 0x7C7D, 0x6E5F, 0xE337, 0, 0x6E63,
+};
+static const unsigned short utf8_to_euc_E988[] = {
+ 0xE338, 0xE339, 0, 0, 0xE33A, 0xE33B, 0xE33C, 0xE33D,
+ 0, 0xE33E, 0xE33F, 0, 0xE340, 0x465F, 0x3343, 0,
+ 0xE341, 0x6E67, 0xE342, 0xE343, 0x6E64, 0x6E66, 0xE344, 0,
+ 0xE345, 0, 0, 0, 0xE346, 0xE347, 0x6E62, 0,
+ 0, 0, 0, 0xE348, 0xE349, 0xE34A, 0xE34B, 0,
+ 0xE34C, 0x6F4F, 0, 0, 0x6E65, 0, 0xE34D, 0xE34E,
+ 0xE34F, 0, 0, 0xE350, 0x4E6B, 0xE351, 0xE352, 0x385A,
+ 0xE353, 0xE354, 0xE355, 0, 0xE356, 0, 0xE357, 0x6E6F,
+};
+static const unsigned short utf8_to_euc_E988_x0213[] = {
+ 0xE338, 0xFA53, 0, 0, 0xE33A, 0xE33B, 0, 0x7D24,
+ 0, 0xE33E, 0xFA54, 0, 0xE340, 0x465F, 0x3343, 0,
+ 0x7D25, 0x6E67, 0xE342, 0xE343, 0x6E64, 0x6E66, 0xFA55, 0xFA56,
+ 0xE345, 0, 0, 0, 0xE346, 0xE347, 0x6E62, 0,
+ 0, 0, 0, 0xE348, 0xE349, 0xE34A, 0xE34B, 0,
+ 0xE34C, 0x6F4F, 0, 0, 0x6E65, 0, 0xE34D, 0xE34E,
+ 0xE34F, 0, 0, 0xFA58, 0x4E6B, 0xE351, 0xE352, 0x385A,
+ 0x7D26, 0x7D27, 0x7D28, 0, 0x7D29, 0, 0xE357, 0x6E6F,
+};
+static const unsigned short utf8_to_euc_E989[] = {
+ 0xE358, 0, 0xE359, 0xE35A, 0x4534, 0x6E6A, 0xE35B, 0xE35C,
+ 0x6E6D, 0x6E6B, 0xE35D, 0x6E70, 0, 0xE35E, 0xE35F, 0xE360,
+ 0x6E71, 0xE361, 0, 0, 0, 0, 0, 0x6E69,
+ 0xE362, 0xE363, 0x6E76, 0x3174, 0xE364, 0xE365, 0x6E68, 0,
+ 0xE366, 0xE367, 0x482D, 0, 0x6E6C, 0xE368, 0x3E60, 0xE369,
+ 0xE36A, 0xE36B, 0, 0, 0, 0, 0xE36C, 0xE36D,
+ 0xE36E, 0x395B, 0, 0, 0, 0xE36F, 0xE370, 0xE371,
+ 0xE372, 0xE373, 0, 0xE374, 0xE375, 0xE376, 0x4B48, 0xE377,
+};
+static const unsigned short utf8_to_euc_E989_x0213[] = {
+ 0x7D2A, 0, 0xFA59, 0x7D2B, 0x4534, 0x6E6A, 0xE35B, 0xFA5A,
+ 0x6E6D, 0x6E6B, 0xFA5B, 0x6E70, 0, 0xE35E, 0xFA5C, 0x7D2C,
+ 0x6E71, 0xFA5D, 0, 0, 0, 0, 0xFA5E, 0x6E69,
+ 0xE362, 0xFA5F, 0x6E76, 0x3174, 0xE364, 0xE365, 0x6E68, 0,
+ 0xFA60, 0xFA61, 0x482D, 0, 0x6E6C, 0xFA62, 0x3E60, 0xFA63,
+ 0xFA64, 0xE36B, 0, 0, 0, 0, 0xE36C, 0xE36D,
+ 0xE36E, 0x395B, 0, 0, 0, 0xE36F, 0xE370, 0,
+ 0x7D2D, 0xE373, 0, 0xE374, 0xFA67, 0xFA68, 0x4B48, 0xFA69,
+};
+static const unsigned short utf8_to_euc_E98A[] = {
+ 0x3664, 0, 0, 0x3D46, 0, 0x463C, 0, 0,
+ 0xE378, 0xE379, 0xE37A, 0, 0, 0xE37B, 0xE37C, 0,
+ 0, 0x412D, 0xE37D, 0x6E74, 0, 0x6E6E, 0x6E73, 0xE37E,
+ 0x4C43, 0xE421, 0x4438, 0x6E75, 0x6E72, 0, 0, 0xE422,
+ 0xE423, 0, 0, 0, 0xE424, 0xE425, 0, 0xE426,
+ 0xE427, 0, 0, 0xE428, 0, 0x412C, 0, 0xE429,
+ 0, 0, 0xE42A, 0, 0, 0, 0xE42B, 0x6E79,
+ 0xE42C, 0x6E78, 0xE42D, 0xE42E, 0xE42F, 0xE430, 0, 0xE431,
+};
+static const unsigned short utf8_to_euc_E98A_x0213[] = {
+ 0x3664, 0, 0, 0x3D46, 0, 0x463C, 0, 0,
+ 0x7D2E, 0xFA6A, 0xE37A, 0, 0, 0xFA6B, 0xE37C, 0,
+ 0, 0x412D, 0xE37D, 0x6E74, 0, 0x6E6E, 0x6E73, 0xFA6C,
+ 0x4C43, 0xFA6D, 0x4438, 0x6E75, 0x6E72, 0, 0, 0xFA6E,
+ 0xE423, 0, 0, 0, 0xE424, 0xE425, 0, 0xFA6F,
+ 0xE427, 0, 0, 0xFA70, 0, 0x412C, 0, 0xE429,
+ 0, 0, 0xFA73, 0, 0, 0, 0xE42B, 0x6E79,
+ 0xE42C, 0x6E78, 0xE42D, 0xE42E, 0xE42F, 0xE430, 0, 0xFA74,
+};
+static const unsigned short utf8_to_euc_E98B[] = {
+ 0xE432, 0xE433, 0xE434, 0xE435, 0, 0xE436, 0xE437, 0xE438,
+ 0xE439, 0, 0, 0xE43A, 0xE43B, 0xE43C, 0xE43D, 0x6E77,
+ 0xE43E, 0, 0x4B2F, 0xE43F, 0, 0xE440, 0, 0xE441,
+ 0xE442, 0xE443, 0, 0, 0xE444, 0xE445, 0, 0xE446,
+ 0xE447, 0xE448, 0, 0xE449, 0x3D7B, 0xE44A, 0, 0xE44B,
+ 0xE44C, 0x6E7A, 0x4A5F, 0, 0xE44D, 0x3154, 0xE44E, 0,
+ 0xE44F, 0, 0x4946, 0x4372, 0, 0, 0, 0,
+ 0x3578, 0xE450, 0x6E7C, 0xE451, 0x395D, 0, 0, 0xE452,
+};
+static const unsigned short utf8_to_euc_E98B_x0213[] = {
+ 0xFA75, 0xE433, 0x7D2F, 0xE435, 0, 0xE436, 0xFA76, 0xE438,
+ 0xE439, 0, 0, 0x7D30, 0x7D31, 0xE43C, 0xFA77, 0x6E77,
+ 0xFA78, 0, 0x4B2F, 0x7D32, 0, 0, 0, 0xFA79,
+ 0xE442, 0xFA7A, 0, 0, 0xE444, 0xE445, 0, 0xE446,
+ 0x7D33, 0xE448, 0, 0xE449, 0x3D7B, 0xFA7B, 0, 0xFA7C,
+ 0xE44C, 0x6E7A, 0x4A5F, 0, 0xE44D, 0x3154, 0xE44E, 0,
+ 0xE44F, 0, 0x4946, 0x4372, 0, 0, 0, 0xFB22,
+ 0x3578, 0xFB23, 0x6E7C, 0xFB24, 0x395D, 0, 0, 0x7D34,
+};
+static const unsigned short utf8_to_euc_E98C[] = {
+ 0xE453, 0, 0xE454, 0, 0, 0, 0x3B2C, 0,
+ 0xE455, 0, 0, 0, 0, 0xE456, 0, 0x6E7B,
+ 0x3F6D, 0xE457, 0, 0, 0xE458, 0xE459, 0, 0,
+ 0x3F6E, 0x6F21, 0x6F23, 0, 0xE45A, 0xE45B, 0xE45C, 0xE45D,
+ 0x3E7B, 0xE45E, 0x6F22, 0x6F24, 0xE45F, 0xE460, 0x3653, 0xE461,
+ 0x4945, 0xE462, 0xE463, 0x3C62, 0x4F23, 0, 0x6E7E, 0x3A78,
+ 0, 0, 0x4F3F, 0xE464, 0xE465, 0x6F26, 0xE466, 0xE467,
+ 0, 0, 0x6F25, 0x6F27, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E98C_x0213[] = {
+ 0xE453, 0, 0xFB25, 0, 0x7D35, 0, 0x3B2C, 0,
+ 0xE455, 0, 0, 0, 0, 0xFB26, 0, 0x6E7B,
+ 0x3F6D, 0xFA7D, 0, 0, 0xE458, 0xFB27, 0, 0,
+ 0x3F6E, 0x6F21, 0x6F23, 0, 0xE45A, 0xFB28, 0xFB29, 0x7D36,
+ 0x3E7B, 0x7D37, 0x6F22, 0x6F24, 0xE45F, 0x7D38, 0x3653, 0xFB2A,
+ 0x4945, 0xFB2B, 0xE463, 0x3C62, 0x4F23, 0, 0x6E7E, 0x3A78,
+ 0, 0, 0x4F3F, 0xE464, 0xE465, 0x6F26, 0xE466, 0xE467,
+ 0, 0, 0x6F25, 0x6F27, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E98D[] = {
+ 0, 0, 0, 0, 0x6E7D, 0, 0, 0xE468,
+ 0xE469, 0xE46A, 0, 0x4669, 0, 0x4555, 0, 0,
+ 0xE46B, 0xE46C, 0xE46D, 0, 0x4457, 0xE46E, 0x6F2C, 0xE46F,
+ 0xE470, 0, 0xE471, 0x4343, 0x6F28, 0, 0xE472, 0,
+ 0x6F29, 0, 0, 0, 0xE473, 0xE474, 0, 0xE475,
+ 0, 0xE476, 0xE477, 0, 0x372D, 0xE478, 0x6F2B, 0xE479,
+ 0xE47A, 0xE47B, 0, 0xE47C, 0xE47D, 0x3830, 0xE47E, 0,
+ 0, 0, 0xE521, 0, 0x6F2A, 0xE522, 0x3E61, 0xE523,
+};
+static const unsigned short utf8_to_euc_E98D_x0213[] = {
+ 0, 0, 0, 0, 0x6E7D, 0, 0, 0xFB2E,
+ 0x7D39, 0x7D3A, 0x7D3B, 0x4669, 0, 0x4555, 0, 0,
+ 0xE46B, 0xFB2F, 0xE46D, 0, 0x4457, 0xE46E, 0x6F2C, 0xFB30,
+ 0xE470, 0, 0xFB31, 0x4343, 0x6F28, 0, 0xE472, 0,
+ 0x6F29, 0, 0, 0, 0x7D3C, 0x7D3D, 0, 0xE475,
+ 0, 0xE476, 0x7D3E, 0xFB32, 0x372D, 0xE478, 0x6F2B, 0xE479,
+ 0x7D3F, 0xFB33, 0, 0xFB34, 0xE47D, 0x3830, 0xE47E, 0,
+ 0, 0, 0xE521, 0, 0x6F2A, 0xE522, 0x3E61, 0xE523,
+};
+static const unsigned short utf8_to_euc_E98E[] = {
+ 0xE524, 0xE525, 0xE526, 0, 0, 0, 0, 0,
+ 0xE527, 0, 0xE528, 0xE529, 0x3379, 0xE52A, 0, 0xE52B,
+ 0, 0, 0xE52C, 0, 0x6F30, 0xE52D, 0x3A3F, 0x4179,
+ 0xE52E, 0, 0x444A, 0xE52F, 0, 0, 0xE530, 0,
+ 0, 0xE531, 0, 0xE532, 0xE533, 0, 0xE534, 0x333B,
+ 0xE535, 0xE53B, 0, 0xE536, 0x6F2E, 0x6F2F, 0x4443, 0,
+ 0x6F2D, 0, 0, 0, 0xE537, 0xE538, 0xE539, 0,
+ 0, 0x6F31, 0xE53A, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E98E_x0213[] = {
+ 0xE524, 0xE525, 0xE526, 0, 0, 0, 0, 0,
+ 0xFB38, 0, 0xE528, 0xFB39, 0x3379, 0xE52A, 0, 0xFB3A,
+ 0, 0, 0xE52C, 0, 0x6F30, 0xE52D, 0x3A3F, 0x4179,
+ 0xE52E, 0, 0x444A, 0x7D40, 0, 0, 0xFB3B, 0,
+ 0, 0xFB35, 0, 0x7D41, 0, 0, 0xE534, 0x333B,
+ 0xE535, 0xE53B, 0, 0xE536, 0x6F2E, 0x6F2F, 0x4443, 0,
+ 0x6F2D, 0, 0, 0, 0xE537, 0xE538, 0xE539, 0,
+ 0, 0x6F31, 0x7D42, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E98F[] = {
+ 0, 0xE53C, 0, 0x6F37, 0xE53D, 0xE53E, 0xE53F, 0xE540,
+ 0x6F3A, 0xE541, 0xE542, 0xE543, 0xE544, 0xE545, 0, 0,
+ 0x6F39, 0x452D, 0, 0xE546, 0, 0, 0x6F32, 0x6F33,
+ 0x6F36, 0xE547, 0, 0, 0xE548, 0x6F38, 0xE549, 0xE54A,
+ 0, 0x3640, 0xE54B, 0, 0x6F3B, 0x6F35, 0xE54C, 0xE54D,
+ 0x6F34, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xE54F,
+ 0xE550, 0xE54E, 0xE551, 0xE552, 0, 0xE553, 0, 0,
+};
+static const unsigned short utf8_to_euc_E98F_x0213[] = {
+ 0, 0xFB40, 0, 0x6F37, 0xE53D, 0xE53E, 0x7D43, 0xFB41,
+ 0x6F3A, 0xE541, 0xE542, 0xE543, 0xE544, 0xE545, 0, 0,
+ 0x6F39, 0x452D, 0, 0xE546, 0, 0, 0x6F32, 0x6F33,
+ 0x6F36, 0xE547, 0, 0, 0xFB42, 0x6F38, 0x7D44, 0x7D45,
+ 0, 0x3640, 0xFB43, 0, 0x6F3B, 0x6F35, 0xE54C, 0xFB44,
+ 0x6F34, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFB3F, 0, 0, 0, 0xFB3C, 0, 0xE54F,
+ 0, 0xE54E, 0xE551, 0xFB49, 0, 0x7D47, 0, 0,
+};
+static const unsigned short utf8_to_euc_E990[] = {
+ 0, 0xE554, 0xE555, 0x6F3F, 0xE556, 0, 0, 0x6F40,
+ 0xE557, 0xE558, 0, 0, 0, 0xE559, 0xE55A, 0xE55B,
+ 0x6F41, 0, 0, 0x6F3E, 0x6F3D, 0xE55C, 0xE55D, 0xE55E,
+ 0x3E62, 0x462A, 0x6F3C, 0, 0, 0, 0, 0xE55F,
+ 0, 0x6F45, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x6F43, 0, 0, 0xE560, 0xE561,
+ 0, 0xE562, 0xE563, 0xE564, 0xE565, 0x6F44, 0x6F42, 0,
+ 0x4278, 0, 0x6F46, 0xE566, 0, 0xE568, 0, 0xE567,
+};
+static const unsigned short utf8_to_euc_E990_x0213[] = {
+ 0, 0xE554, 0xE555, 0x6F3F, 0x7D46, 0, 0, 0x6F40,
+ 0xE557, 0xFB45, 0, 0, 0, 0xE559, 0xE55A, 0xFB46,
+ 0x6F41, 0, 0, 0x6F3E, 0x6F3D, 0xE55C, 0xFB47, 0xFB48,
+ 0x3E62, 0x462A, 0x6F3C, 0, 0, 0, 0, 0xE55F,
+ 0, 0x6F45, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x6F43, 0, 0, 0xE560, 0xE561,
+ 0, 0, 0xFB4A, 0x7D48, 0xFB4B, 0x6F44, 0x6F42, 0,
+ 0x4278, 0, 0x6F46, 0xFB4C, 0, 0xE568, 0, 0xE567,
+};
+static const unsigned short utf8_to_euc_E991[] = {
+ 0, 0x6F47, 0, 0xE569, 0x6F49, 0xE56A, 0, 0,
+ 0xE56B, 0, 0xE56C, 0, 0xE56D, 0, 0, 0,
+ 0, 0x3455, 0x6F48, 0x4C7A, 0, 0xE56E, 0, 0,
+ 0, 0xE56F, 0x6F54, 0x6F4A, 0xE570, 0, 0x6F4D, 0xE571,
+ 0x6F4B, 0xE572, 0x6F4C, 0xE573, 0, 0, 0, 0,
+ 0xE574, 0, 0x6F4E, 0xE575, 0, 0xE576, 0xE577, 0xE578,
+ 0x6F50, 0xE579, 0xE57A, 0, 0, 0x6F51, 0, 0x6F52,
+ 0, 0, 0, 0, 0x6F55, 0x6F53, 0x6F56, 0x6F58,
+};
+static const unsigned short utf8_to_euc_E991_x0213[] = {
+ 0, 0x6F47, 0, 0xE569, 0x6F49, 0xFB4D, 0, 0,
+ 0, 0, 0x7D49, 0, 0xE56D, 0, 0, 0,
+ 0, 0x3455, 0x6F48, 0x4C7A, 0, 0xE56E, 0, 0,
+ 0, 0xE56F, 0x6F54, 0x6F4A, 0xE570, 0, 0x6F4D, 0xE571,
+ 0x6F4B, 0xE572, 0x6F4C, 0x7D4A, 0, 0, 0, 0,
+ 0xE574, 0, 0x6F4E, 0x7D4B, 0, 0xFB50, 0xE577, 0xFB51,
+ 0x6F50, 0x7D4C, 0x7D4D, 0, 0, 0x6F51, 0, 0x6F52,
+ 0, 0, 0, 0, 0x6F55, 0x6F53, 0x6F56, 0x6F58,
+};
+static const unsigned short utf8_to_euc_E992[] = {
+ 0, 0x6F57, 0, 0xE57C, 0xE57B, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E995[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x4439,
+ 0xE57D, 0xE57E, 0, 0, 0, 0, 0xE621, 0,
+};
+static const unsigned short utf8_to_euc_E995_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x4439,
+ 0xFB52, 0xFB53, 0, 0, 0, 0, 0xE621, 0,
+};
+static const unsigned short utf8_to_euc_E996[] = {
+ 0x4C67, 0, 0x6F59, 0x412E, 0xE622, 0, 0, 0x6F5A,
+ 0xE623, 0x4A44, 0x6F5B, 0x332B, 0xE624, 0xE625, 0xE626, 0x313C,
+ 0, 0x3457, 0xF471, 0x3456, 0x6F5C, 0, 0x6F5D, 0,
+ 0x6F5E, 0x6F5F, 0, 0, 0, 0xE627, 0xE628, 0xE629,
+ 0x6F60, 0xE62A, 0x3458, 0x3355, 0x395E, 0x4836, 0xE62B, 0x6F62,
+ 0x6F61, 0xE62C, 0, 0xE62D, 0xE62E, 0x6F63, 0, 0,
+ 0, 0, 0x315C, 0, 0xE62F, 0, 0xE630, 0,
+ 0, 0x6F66, 0xE631, 0x6F65, 0x6F64, 0xE632, 0x6F67, 0xE633,
+};
+static const unsigned short utf8_to_euc_E996_x0213[] = {
+ 0x4C67, 0, 0x6F59, 0x412E, 0xE622, 0, 0xFB54, 0x6F5A,
+ 0xE623, 0x4A44, 0x6F5B, 0x332B, 0xFB55, 0xFB56, 0x7D4E, 0x313C,
+ 0, 0x3457, 0, 0x3456, 0x6F5C, 0, 0x6F5D, 0,
+ 0x6F5E, 0x6F5F, 0, 0, 0, 0xE627, 0xE628, 0x7D4F,
+ 0x6F60, 0xE62A, 0x3458, 0x3355, 0x395E, 0x4836, 0x7D50, 0x6F62,
+ 0x6F61, 0x7D51, 0, 0xFB58, 0x7D52, 0x6F63, 0, 0,
+ 0, 0, 0x315C, 0, 0xFB59, 0, 0x7D53, 0,
+ 0, 0x6F66, 0xE631, 0x6F65, 0x6F64, 0x7D54, 0x6F67, 0xE633,
+};
+static const unsigned short utf8_to_euc_E997[] = {
+ 0, 0, 0, 0x6F6A, 0, 0, 0xE634, 0x3047,
+ 0xE635, 0xE636, 0x6F68, 0xE637, 0x6F6C, 0x6F6B, 0, 0,
+ 0xE638, 0xE639, 0xE63A, 0xE63B, 0x6F6E, 0x6F6D, 0x6F6F, 0,
+ 0x462E, 0xE63C, 0xE63D, 0, 0x6F70, 0xE63E, 0xE63F, 0xE640,
+ 0xE641, 0x6F71, 0x6F73, 0, 0xE642, 0x6F72, 0xE643, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E997_x0213[] = {
+ 0, 0, 0, 0x6F6A, 0, 0, 0xE634, 0x3047,
+ 0xFB5B, 0xE636, 0x6F68, 0x7D55, 0x6F6C, 0x6F6B, 0, 0,
+ 0x7D56, 0xE639, 0xE63A, 0x7D57, 0x6F6E, 0x6F6D, 0x6F6F, 0,
+ 0x462E, 0xE63C, 0x7D59, 0, 0x6F70, 0xE63E, 0x7D5A, 0xE640,
+ 0xE641, 0x6F71, 0x6F73, 0, 0xE642, 0x6F72, 0xE643, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E998[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x496C, 0xE644, 0xE645, 0,
+ 0, 0x6F74, 0xE646, 0, 0xE647, 0xE648, 0xE649, 0,
+ 0x6F75, 0, 0x3A65, 0, 0xE64A, 0, 0x6F76, 0x6F77,
+ 0, 0xE64B, 0x4B49, 0xE64C, 0, 0, 0, 0xE64D,
+ 0xE64E, 0xE64F, 0xE650, 0x414B, 0xE651, 0xE652, 0, 0x3024,
+};
+static const unsigned short utf8_to_euc_E998_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x496C, 0xFA25, 0xE645, 0,
+ 0, 0x6F74, 0xE646, 0, 0xE647, 0xE648, 0xE649, 0,
+ 0x6F75, 0, 0x3A65, 0, 0xFB5E, 0, 0x6F76, 0x6F77,
+ 0, 0xE64B, 0x4B49, 0xFB5F, 0xFB60, 0, 0, 0xE64D,
+ 0xE64E, 0xE64F, 0xE650, 0x414B, 0xFB62, 0xE652, 0, 0x3024,
+};
+static const unsigned short utf8_to_euc_E999[] = {
+ 0x424B, 0xE653, 0x6F78, 0, 0x496D, 0, 0, 0,
+ 0, 0, 0, 0x6F7B, 0x6F79, 0x395F, 0, 0x6F7A,
+ 0x3842, 0, 0xE654, 0, 0xE655, 0, 0xE656, 0xE657,
+ 0xE658, 0, 0, 0x4A45, 0x6F7D, 0x7021, 0x6F7E, 0x7022,
+ 0, 0xE659, 0x3121, 0x3F58, 0x3D7C, 0x3459, 0x7023, 0,
+ 0, 0, 0x4766, 0, 0x7025, 0, 0xE65A, 0,
+ 0x3122, 0, 0x7024, 0x4444, 0xE65B, 0x4E4D, 0x462B, 0x6F7C,
+ 0x4E26, 0, 0x3831, 0xE65C, 0xE65D, 0x4D5B, 0xE65E, 0xE65F,
+};
+static const unsigned short utf8_to_euc_E999_x0213[] = {
+ 0x424B, 0xFB63, 0x6F78, 0, 0x496D, 0, 0, 0,
+ 0, 0, 0, 0x6F7B, 0x6F79, 0x395F, 0, 0x6F7A,
+ 0x3842, 0, 0xE654, 0, 0xE655, 0, 0xE656, 0xE657,
+ 0x7D5B, 0, 0, 0x4A45, 0x6F7D, 0x7021, 0x6F7E, 0x7022,
+ 0, 0xFB64, 0x3121, 0x3F58, 0x3D7C, 0x3459, 0x7023, 0,
+ 0, 0, 0x4766, 0, 0x7025, 0, 0xE65A, 0,
+ 0x3122, 0, 0x7024, 0x4444, 0xE65B, 0x4E4D, 0x462B, 0x6F7C,
+ 0x4E26, 0, 0x3831, 0xE65C, 0xE65D, 0x4D5B, 0xE65E, 0xE65F,
+};
+static const unsigned short utf8_to_euc_E99A[] = {
+ 0, 0xE660, 0xE661, 0xE662, 0xE663, 0x3679, 0x4E34, 0,
+ 0x3728, 0xE664, 0x4262, 0x6721, 0, 0x7026, 0x332C, 0x3F6F,
+ 0, 0xE665, 0, 0, 0x3356, 0x7028, 0xE666, 0x7029,
+ 0x7027, 0x3764, 0xE667, 0x3A5D, 0x3E63, 0xE668, 0, 0xE669,
+ 0x3123, 0, 0, 0x4E59, 0xE66A, 0xE66B, 0xE66C, 0x702B,
+ 0x6E2E, 0xE66D, 0x702A, 0, 0, 0, 0xE66E, 0xE66F,
+ 0x702E, 0x702C, 0x702D, 0xE670, 0x702F, 0, 0x7030, 0x4E6C,
+ 0x7031, 0x7032, 0xE671, 0x4049, 0x483B, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E99A_x0213[] = {
+ 0, 0xE660, 0xFB66, 0xE662, 0x7D5C, 0x3679, 0x4E34, 0,
+ 0x3728, 0xE664, 0x4262, 0x6721, 0, 0x7026, 0x332C, 0x3F6F,
+ 0, 0xE665, 0, 0, 0x3356, 0x7028, 0xE666, 0x7029,
+ 0x7027, 0x3764, 0xFB68, 0x3A5D, 0x3E63, 0x7D5E, 0, 0xE669,
+ 0x3123, 0, 0, 0x4E59, 0x7D5F, 0x7D60, 0xE66C, 0x702B,
+ 0x6E2E, 0xFB6B, 0x702A, 0, 0, 0, 0xE66E, 0xFB6C,
+ 0x702E, 0x702C, 0x702D, 0xFB6D, 0x702F, 0, 0x7030, 0x4E6C,
+ 0x7031, 0x7032, 0xFB6E, 0x4049, 0x483B, 0xFB6F, 0, 0,
+};
+static const unsigned short utf8_to_euc_E99B[] = {
+ 0x3F7D, 0x3467, 0, 0, 0x4D3A, 0x326D, 0x3D38, 0x385B,
+ 0, 0x7035, 0xE672, 0x7034, 0x3B73, 0x7036, 0x7033, 0,
+ 0, 0x3B28, 0xE673, 0, 0, 0x703A, 0x6A2D, 0,
+ 0xE675, 0x5256, 0xE676, 0x3F77, 0x7038, 0xE677, 0xE678, 0xE679,
+ 0, 0, 0x4E25, 0x4671, 0, 0, 0, 0,
+ 0x312B, 0xE67A, 0x4063, 0x3C36, 0, 0, 0, 0xE67B,
+ 0x4A37, 0xE67C, 0x3140, 0, 0, 0, 0x4E6D, 0x4D6B,
+ 0, 0x703B, 0xE67D, 0x4545, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E99B_x0213[] = {
+ 0x3F7D, 0x3467, 0, 0, 0x4D3A, 0x326D, 0x3D38, 0x385B,
+ 0, 0x7035, 0xE672, 0x7034, 0x3B73, 0x7036, 0x7033, 0,
+ 0, 0x3B28, 0x7D61, 0, 0, 0x703A, 0x6A2D, 0,
+ 0xFB72, 0x5256, 0xFB73, 0x3F77, 0x7038, 0xFB74, 0x7D62, 0xE679,
+ 0, 0, 0x4E25, 0x4671, 0, 0, 0, 0,
+ 0x312B, 0x7D64, 0x4063, 0x3C36, 0, 0, 0, 0x7D65,
+ 0x4A37, 0xE67C, 0x3140, 0, 0, 0, 0x4E6D, 0x4D6B,
+ 0, 0x703B, 0xE67D, 0x4545, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E99C[] = {
+ 0x3C7B, 0, 0xE67E, 0xE721, 0x703C, 0xE722, 0x703D, 0x3F4C,
+ 0x703E, 0xE723, 0x4E6E, 0, 0, 0x7039, 0x7040, 0x7042,
+ 0, 0x7041, 0, 0x703F, 0, 0, 0x7043, 0,
+ 0, 0x7044, 0xE724, 0xE725, 0x417A, 0xE726, 0x3262, 0,
+ 0, 0xE727, 0xE728, 0xE729, 0x7045, 0, 0, 0x4C38,
+ 0xE72A, 0, 0x7046, 0, 0, 0, 0, 0,
+ 0x7047, 0xE72B, 0x4F2A, 0xE72C, 0, 0, 0, 0,
+ 0x5B31, 0x7048, 0, 0xF474, 0, 0x7049, 0x704A, 0,
+};
+static const unsigned short utf8_to_euc_E99C_x0213[] = {
+ 0x3C7B, 0, 0xE67E, 0xE721, 0x703C, 0xE722, 0x703D, 0x3F4C,
+ 0x703E, 0xE723, 0x4E6E, 0, 0, 0x7039, 0x7040, 0x7042,
+ 0, 0x7041, 0, 0x703F, 0xFB76, 0, 0x7043, 0,
+ 0, 0x7044, 0xE724, 0xE725, 0x417A, 0xE726, 0x3262, 0,
+ 0, 0xE727, 0xE728, 0xFB77, 0x7045, 0, 0, 0x4C38,
+ 0xE72A, 0, 0x7046, 0, 0, 0, 0, 0,
+ 0x7047, 0xE72B, 0x4F2A, 0x7D66, 0, 0, 0xFB79, 0,
+ 0x5B31, 0x7048, 0, 0x7D67, 0, 0x7049, 0x704A, 0,
+};
+static const unsigned short utf8_to_euc_E99D[] = {
+ 0, 0xE72D, 0x704E, 0xE72E, 0x704B, 0, 0x704C, 0,
+ 0x704D, 0x704F, 0xE72F, 0, 0, 0xF475, 0xE730, 0xE731,
+ 0, 0xF476, 0x4044, 0, 0, 0xE732, 0x4C77, 0xE733,
+ 0xE734, 0x4045, 0xE735, 0xE736, 0x7050, 0, 0x4873, 0,
+ 0x7051, 0x7353, 0x4C4C, 0xE737, 0x7052, 0, 0x7053, 0xE738,
+ 0x7054, 0x3357, 0xE739, 0x7056, 0, 0x3F59, 0xE73A, 0,
+ 0, 0x7057, 0, 0xE73B, 0x3724, 0, 0xE73C, 0xE73D,
+ 0xE73E, 0x7058, 0x705C, 0xE73F, 0x705A, 0xE740, 0, 0xE741,
+};
+static const unsigned short utf8_to_euc_E99D_x0213[] = {
+ 0, 0xFB7A, 0x704E, 0, 0x704B, 0, 0x704C, 0xFB7B,
+ 0x704D, 0x704F, 0xE72F, 0, 0, 0x7D68, 0x7D69, 0x7D6A,
+ 0, 0, 0x4044, 0, 0, 0xFB7C, 0x4C77, 0xFB7D,
+ 0xE734, 0x4045, 0x7D6B, 0xFB7E, 0x7050, 0, 0x4873, 0,
+ 0x7051, 0x7353, 0x4C4C, 0xE737, 0x7052, 0, 0x7053, 0xE738,
+ 0x7054, 0x3357, 0xFC21, 0x7056, 0, 0x3F59, 0x7D6C, 0,
+ 0, 0x7057, 0, 0x7D6D, 0x3724, 0, 0xE73C, 0xE73D,
+ 0xE73E, 0x7058, 0x705C, 0xE73F, 0x705A, 0xE740, 0, 0xE741,
+};
+static const unsigned short utf8_to_euc_E99E[] = {
+ 0xE742, 0x705B, 0, 0, 0x3373, 0x7059, 0x705D, 0,
+ 0, 0xE743, 0, 0x705E, 0, 0x3048, 0, 0x705F,
+ 0x7060, 0, 0, 0, 0, 0xE744, 0xE745, 0xE746,
+ 0x3E64, 0xE747, 0xE748, 0, 0x7061, 0, 0xE749, 0xE74A,
+ 0x3547, 0, 0xE74B, 0x7064, 0, 0, 0x7063, 0,
+ 0x7062, 0, 0, 0x6B71, 0xE74C, 0x4A5C, 0xE74D, 0,
+ 0, 0xE74E, 0xE74F, 0x7065, 0x7066, 0xE750, 0xE751, 0,
+ 0xE752, 0xE753, 0xE754, 0, 0xE755, 0, 0xE756, 0xE757,
+};
+static const unsigned short utf8_to_euc_E99E_x0213[] = {
+ 0xE742, 0x705B, 0, 0, 0x3373, 0x7059, 0x705D, 0,
+ 0, 0xE743, 0, 0x705E, 0, 0x3048, 0, 0x705F,
+ 0x7060, 0, 0, 0, 0, 0x7D6E, 0xFC24, 0xE746,
+ 0x3E64, 0xE747, 0xFC25, 0, 0x7061, 0, 0xFC26, 0xE74A,
+ 0x3547, 0, 0xFC27, 0x7064, 0, 0, 0x7063, 0,
+ 0x7062, 0, 0, 0x6B71, 0xE74C, 0x4A5C, 0x7D6F, 0,
+ 0, 0xFC28, 0xFC29, 0x7065, 0x7066, 0xE750, 0xE751, 0,
+ 0xE752, 0xE753, 0x7D70, 0, 0xE755, 0, 0xFC2A, 0xE757,
+};
+static const unsigned short utf8_to_euc_E99F[] = {
+ 0, 0xE758, 0, 0x7067, 0xE759, 0xE75A, 0x7068, 0xE75B,
+ 0x7069, 0xE75C, 0xE75D, 0x706A, 0xE75E, 0xE75F, 0xE760, 0,
+ 0xE761, 0xE762, 0, 0x345A, 0xE763, 0, 0, 0xE764,
+ 0xE765, 0xE766, 0, 0xE76A, 0x706B, 0xE767, 0xE768, 0,
+ 0xE769, 0xE76B, 0, 0, 0xE76C, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x706C, 0x4723, 0xE76D,
+ 0, 0xE76E, 0x706E, 0x323B, 0xE76F, 0x7071, 0x7070, 0xE770,
+ 0xE771, 0, 0xE772, 0x3124, 0, 0, 0, 0x3641,
+};
+static const unsigned short utf8_to_euc_E99F_x0213[] = {
+ 0, 0x7D71, 0, 0x7067, 0xE759, 0xE75A, 0x7068, 0xE75B,
+ 0x7069, 0x7D72, 0xE75D, 0x706A, 0xFC2B, 0xE75F, 0xE760, 0,
+ 0xE761, 0xFC2C, 0, 0x345A, 0xFC2D, 0, 0, 0xE764,
+ 0xFC2E, 0xFC2F, 0, 0x7D74, 0x706B, 0xE767, 0x7D73, 0,
+ 0xE769, 0xFC30, 0, 0, 0xE76C, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x706C, 0x4723, 0xE76D,
+ 0, 0xFC31, 0x706E, 0x323B, 0x7D75, 0x7071, 0x7070, 0xE770,
+ 0xE771, 0, 0xE772, 0x3124, 0, 0, 0, 0x3641,
+};
+static const unsigned short utf8_to_euc_E9A0[] = {
+ 0, 0x4A47, 0x443A, 0x3A22, 0, 0x3960, 0x3D67, 0xE773,
+ 0x3F5C, 0, 0xE774, 0, 0x7073, 0xE776, 0xE777, 0x7072,
+ 0x4D42, 0x3468, 0x4852, 0x465C, 0xE778, 0, 0xE779, 0x3F7C,
+ 0x4E4E, 0xE775, 0x375B, 0, 0xE77A, 0, 0xE77B, 0,
+ 0xE77C, 0x7076, 0, 0xE77D, 0x7075, 0xE828, 0xE77E, 0,
+ 0, 0, 0, 0xE821, 0x4B4B, 0x462C, 0xE822, 0xE823,
+ 0xE824, 0, 0xE825, 0xE826, 0x3150, 0xE827, 0, 0x7077,
+ 0x7074, 0, 0, 0x4951, 0x4D6A, 0x7078, 0xE829, 0,
+};
+static const unsigned short utf8_to_euc_E9A0_x0213[] = {
+ 0, 0x4A47, 0x443A, 0x3A22, 0xFC32, 0x3960, 0x3D67, 0xE773,
+ 0x3F5C, 0, 0x7D77, 0, 0x7073, 0xFC33, 0xFC34, 0x7072,
+ 0x4D42, 0x3468, 0x4852, 0x465C, 0xFC35, 0, 0xFC36, 0x3F7C,
+ 0x4E4E, 0xE775, 0x375B, 0, 0xE77A, 0, 0x7D78, 0,
+ 0xE77C, 0x7076, 0, 0xFC39, 0x7075, 0xFC3C, 0xE77E, 0,
+ 0, 0, 0, 0x7D79, 0x4B4B, 0x462C, 0xE822, 0xE823,
+ 0x7D7A, 0, 0xFC3A, 0xFC3B, 0x3150, 0xE827, 0, 0x7077,
+ 0x7074, 0, 0, 0x4951, 0x4D6A, 0x7078, 0xE829, 0,
+};
+static const unsigned short utf8_to_euc_E9A1[] = {
+ 0, 0, 0, 0, 0xE82A, 0, 0x7079, 0xE82B,
+ 0, 0, 0xE82C, 0x707B, 0x426A, 0x335B, 0x335C, 0x707A,
+ 0, 0xE82D, 0xE82E, 0xE82F, 0x3469, 0x3832, 0xE830, 0xE831,
+ 0x346A, 0xE832, 0xE833, 0x453F, 0, 0, 0x4E60, 0,
+ 0, 0, 0xE834, 0xE835, 0, 0xE836, 0xE837, 0x385C,
+ 0, 0, 0xE838, 0x707C, 0xE839, 0, 0, 0x707D,
+ 0x707E, 0x7121, 0, 0x7123, 0x7122, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9A1_x0213[] = {
+ 0, 0, 0, 0, 0xE82A, 0, 0x7079, 0xFC3D,
+ 0, 0, 0xE82C, 0x707B, 0x426A, 0x335B, 0x335C, 0x707A,
+ 0, 0xE82D, 0x7D7C, 0x7D7D, 0x3469, 0x3832, 0x7D7E, 0x7E21,
+ 0x346A, 0x7E22, 0x7E23, 0x453F, 0, 0, 0x4E60, 0,
+ 0, 0, 0xE834, 0xE835, 0, 0x7E25, 0xFC3E, 0x385C,
+ 0, 0, 0xE838, 0x707C, 0x7E26, 0, 0, 0x707D,
+ 0x707E, 0x7121, 0, 0x7123, 0x7122, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9A2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x4977, 0, 0x7124, 0xE83A, 0, 0xE83B, 0xE83C, 0x7125,
+ 0xE83D, 0x7126, 0, 0, 0xE83E, 0, 0x7127, 0xE83F,
+ 0xE840, 0, 0xE841, 0xE842, 0, 0, 0, 0xE843,
+};
+static const unsigned short utf8_to_euc_E9A2_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x4977, 0, 0x7124, 0xFC3F, 0, 0xFC40, 0xE83C, 0x7125,
+ 0xFC41, 0x7126, 0, 0, 0xE83E, 0, 0x7127, 0xFC43,
+ 0xFC44, 0, 0x7E27, 0xFC45, 0xFC46, 0, 0, 0xFC47,
+};
+static const unsigned short utf8_to_euc_E9A3[] = {
+ 0, 0, 0xE844, 0x7129, 0x7128, 0xE845, 0x712A, 0,
+ 0xE846, 0, 0, 0, 0xE847, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x4874, 0x664C, 0, 0, 0x3F29,
+ 0, 0xE848, 0x3532, 0xE849, 0, 0xE84A, 0xE84B, 0xE84C,
+ 0, 0x712B, 0xE84D, 0x712C, 0, 0x522C, 0x5D3B, 0x4853,
+ 0, 0, 0x307B, 0xE84E, 0x303B, 0, 0xE84F, 0,
+ 0, 0, 0, 0, 0x3B74, 0x4B30, 0x3E7E, 0,
+};
+static const unsigned short utf8_to_euc_E9A3_x0213[] = {
+ 0, 0, 0xFC48, 0x7129, 0x7128, 0xE845, 0x712A, 0xFC49,
+ 0x7E28, 0, 0, 0xFC4A, 0xE847, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x4874, 0x664C, 0, 0, 0x3F29,
+ 0xFC4B, 0xFC4D, 0x3532, 0xFC4E, 0, 0xFC4F, 0xE84B, 0x7E29,
+ 0, 0x712B, 0xFC50, 0x712C, 0, 0x522C, 0x5D3B, 0x4853,
+ 0xFC51, 0xFC52, 0x307B, 0xFC53, 0x303B, 0, 0xE84F, 0,
+ 0, 0, 0, 0, 0x3B74, 0x4B30, 0x3E7E, 0,
+};
+static const unsigned short utf8_to_euc_E9A4[] = {
+ 0, 0, 0xE850, 0x712D, 0, 0x4C5F, 0, 0xE851,
+ 0xE852, 0x712E, 0x4D5C, 0, 0x3142, 0, 0, 0,
+ 0x3B41, 0xE853, 0x712F, 0x326E, 0x7130, 0xE854, 0xE855, 0xE856,
+ 0x7131, 0, 0xE857, 0xE858, 0xE859, 0x7133, 0x7134, 0xE85A,
+ 0x7136, 0x7132, 0xE85B, 0, 0x7135, 0, 0xE85C, 0xE85D,
+ 0x345B, 0, 0, 0xE85E, 0x7137, 0, 0x7138, 0,
+ 0, 0xE85F, 0xE860, 0xE861, 0xE862, 0xE863, 0, 0,
+ 0, 0xE864, 0xE865, 0xE866, 0xE867, 0x7139, 0x713A, 0,
+};
+static const unsigned short utf8_to_euc_E9A4_x0213[] = {
+ 0, 0, 0xE850, 0x712D, 0, 0x4C5F, 0, 0xE851,
+ 0xFC54, 0x712E, 0x4D5C, 0, 0x3142, 0, 0, 0,
+ 0x3B41, 0xE853, 0x712F, 0x326E, 0x7130, 0xE854, 0xFC57, 0xFC58,
+ 0x7131, 0, 0xFC5A, 0xFC5B, 0xFC5C, 0x7133, 0x7134, 0xE85A,
+ 0x7136, 0x7132, 0xE85B, 0, 0x7135, 0, 0xE85C, 0,
+ 0x345B, 0, 0, 0xE85E, 0x7137, 0, 0x7138, 0,
+ 0, 0xFC5E, 0xFC5F, 0xFC60, 0xE862, 0xE863, 0, 0,
+ 0, 0xE864, 0xFC61, 0xFC62, 0xFC63, 0x7139, 0x713A, 0,
+};
+static const unsigned short utf8_to_euc_E9A5[] = {
+ 0xE868, 0xE869, 0x713B, 0, 0, 0x713D, 0xE86A, 0xE86B,
+ 0xE86C, 0x713C, 0, 0x713F, 0x7142, 0xE86D, 0xE86E, 0,
+ 0x713E, 0x7140, 0x7141, 0, 0xE86F, 0x7143, 0, 0x3642,
+ 0xE870, 0xE871, 0, 0xE872, 0xE873, 0, 0xE874, 0xE875,
+ 0xE876, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9A5_x0213[] = {
+ 0xFC64, 0xFC65, 0x713B, 0, 0, 0x713D, 0xFC66, 0xE86B,
+ 0xE86C, 0x713C, 0, 0x713F, 0x7142, 0xFC67, 0xFC68, 0,
+ 0x713E, 0x7140, 0x7141, 0, 0xE86F, 0x7143, 0, 0x3642,
+ 0x7E2A, 0xE871, 0, 0xE872, 0xFC69, 0, 0xE874, 0xFC6A,
+ 0xFC6B, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9A6[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x3C73, 0x7144,
+ 0x7145, 0x3961, 0, 0xE877, 0, 0xE878, 0xF47A, 0xE879,
+ 0, 0, 0, 0, 0, 0x7146, 0xE87A, 0,
+ 0x333E, 0, 0, 0, 0x474F, 0x7147, 0x7148, 0,
+ 0xE87B, 0xE87C, 0xE87D, 0x435A, 0x466B, 0xE87E, 0, 0,
+ 0, 0xE921, 0xE922, 0, 0x7149, 0xE923, 0, 0xE924,
+};
+static const unsigned short utf8_to_euc_E9A6_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x3C73, 0x7144,
+ 0x7145, 0x3961, 0, 0xE877, 0, 0xE878, 0x7E2B, 0xE879,
+ 0, 0, 0, 0xFC6C, 0, 0x7146, 0xFC6D, 0,
+ 0x333E, 0, 0, 0, 0x474F, 0x7147, 0x7148, 0,
+ 0xE87B, 0xE87C, 0xE87D, 0x435A, 0x466B, 0xE87E, 0, 0,
+ 0, 0xFC6E, 0xE922, 0, 0x7149, 0xFC6F, 0, 0xFC70,
+};
+static const unsigned short utf8_to_euc_E9A7[] = {
+ 0, 0x477D, 0, 0xE925, 0x424C, 0x3158, 0x366E, 0,
+ 0x366F, 0xE926, 0, 0, 0, 0, 0, 0,
+ 0x4373, 0x714E, 0x3670, 0xE927, 0xE928, 0x326F, 0, 0,
+ 0x714D, 0xE929, 0xE92A, 0x714B, 0xE92B, 0x714C, 0xE92C, 0x714A,
+ 0, 0, 0x7158, 0, 0, 0, 0, 0xE92D,
+ 0, 0, 0xE92E, 0xE92F, 0xE930, 0x714F, 0x7150, 0,
+ 0xE931, 0x7151, 0x7152, 0, 0xE932, 0xE933, 0, 0,
+ 0x7154, 0xE934, 0, 0x7153, 0, 0xE935, 0xE936, 0x3D59,
+};
+static const unsigned short utf8_to_euc_E9A7_x0213[] = {
+ 0, 0x477D, 0, 0xFC71, 0x424C, 0x3158, 0x366E, 0,
+ 0x366F, 0xFC72, 0, 0, 0, 0, 0, 0,
+ 0x4373, 0x714E, 0x3670, 0xE927, 0xFC73, 0x326F, 0, 0,
+ 0x714D, 0xFC74, 0xE92A, 0x714B, 0xE92B, 0x714C, 0xFC75, 0x714A,
+ 0, 0, 0x7158, 0, 0, 0, 0, 0xE92D,
+ 0, 0, 0xE92E, 0xE92F, 0xE930, 0x714F, 0x7150, 0,
+ 0xFC77, 0x7151, 0x7152, 0, 0xE932, 0xE933, 0, 0,
+ 0x7154, 0xFC78, 0, 0x7153, 0xFC79, 0xE935, 0xE936, 0x3D59,
+};
+static const unsigned short utf8_to_euc_E9A8[] = {
+ 0, 0x7155, 0xE937, 0xE938, 0xE939, 0x7157, 0, 0,
+ 0, 0, 0, 0xE93A, 0xE93B, 0, 0x3533, 0x7156,
+ 0xE93C, 0xE93D, 0x417B, 0x3833, 0, 0, 0xE93E, 0,
+ 0, 0x7159, 0, 0, 0, 0, 0xE93F, 0,
+ 0xE940, 0, 0xE941, 0xE942, 0xE943, 0, 0, 0xE944,
+ 0x424D, 0, 0, 0x715A, 0, 0xE945, 0xE946, 0,
+ 0x462D, 0, 0, 0xE947, 0, 0xE948, 0xE949, 0x715B,
+ 0xE94A, 0, 0, 0, 0, 0, 0x7160, 0,
+};
+static const unsigned short utf8_to_euc_E9A8_x0213[] = {
+ 0, 0x7155, 0x7E2C, 0x7E2D, 0xE939, 0x7157, 0, 0,
+ 0, 0, 0xFC7A, 0xE93A, 0xE93B, 0, 0x3533, 0x7156,
+ 0xE93C, 0xFC7B, 0x417B, 0x3833, 0, 0, 0xFC7C, 0,
+ 0, 0x7159, 0xFC7D, 0, 0, 0, 0xE93F, 0,
+ 0xFC7E, 0, 0xE941, 0xE942, 0x7E2E, 0, 0, 0xE944,
+ 0x424D, 0, 0, 0x715A, 0, 0x7E2F, 0x7E30, 0,
+ 0x462D, 0xFD21, 0, 0xE947, 0, 0xE948, 0xFD22, 0x715B,
+ 0x7E31, 0, 0, 0, 0, 0, 0x7160, 0,
+};
+static const unsigned short utf8_to_euc_E9A9[] = {
+ 0x715E, 0xE94C, 0x715D, 0x715F, 0xE94D, 0x715C, 0, 0xE94B,
+ 0, 0, 0xE94E, 0xE94F, 0xE950, 0x7162, 0xE951, 0,
+ 0, 0xE952, 0, 0, 0xE953, 0x7161, 0xE954, 0x7164,
+ 0, 0, 0x3643, 0x7163, 0, 0xE955, 0, 0x7165,
+ 0, 0, 0x7166, 0, 0x7168, 0x7167, 0, 0,
+ 0, 0x7169, 0x716B, 0x716A, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9A9_x0213[] = {
+ 0x715E, 0xE94C, 0x715D, 0x715F, 0xFD23, 0x715C, 0, 0xE94B,
+ 0, 0, 0x7E32, 0xE94F, 0xFD24, 0x7162, 0x7E33, 0,
+ 0, 0xE952, 0x7E34, 0, 0xE953, 0x7161, 0xE954, 0x7164,
+ 0xFD25, 0, 0x3643, 0x7163, 0, 0xE955, 0, 0x7165,
+ 0, 0, 0x7166, 0, 0x7168, 0x7167, 0, 0,
+ 0, 0x7169, 0x716B, 0x716A, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9AA[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x397C, 0, 0xE956, 0, 0xE957, 0x716C, 0xE958, 0xE959,
+ 0x716D, 0, 0xE95A, 0, 0xE95B, 0xE95C, 0xE95D, 0,
+ 0x333C, 0xE95E, 0, 0xE95F, 0x716E, 0, 0xE960, 0xE961,
+};
+static const unsigned short utf8_to_euc_E9AA_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x397C, 0, 0xE956, 0, 0xE957, 0x716C, 0xE958, 0xFD27,
+ 0x716D, 0, 0xE95A, 0, 0xE95B, 0xE95C, 0x7E35, 0xFD29,
+ 0x333C, 0xFD2B, 0, 0xE95F, 0x716E, 0, 0xE960, 0xE961,
+};
+static const unsigned short utf8_to_euc_E9AB[] = {
+ 0x716F, 0xE962, 0, 0xE963, 0x3F71, 0, 0xE964, 0,
+ 0xE965, 0, 0, 0, 0, 0, 0xE966, 0x7170,
+ 0xE967, 0x7171, 0xE968, 0x7172, 0x7173, 0xE969, 0xE96A, 0xE96B,
+ 0x3962, 0xF47B, 0, 0xE96C, 0xE96D, 0, 0x7174, 0x7175,
+ 0xE96E, 0, 0x7176, 0x7177, 0xE96F, 0xE970, 0x7178, 0xE971,
+ 0, 0xE972, 0x4831, 0x717A, 0xE973, 0x4926, 0x717B, 0x7179,
+ 0, 0x717D, 0xE974, 0xE975, 0x717C, 0xE976, 0, 0x717E,
+ 0, 0xE977, 0xE978, 0x7221, 0, 0xE979, 0, 0xE97A,
+};
+static const unsigned short utf8_to_euc_E9AB_x0213[] = {
+ 0x716F, 0x7E36, 0, 0x7E37, 0x3F71, 0, 0xFD2D, 0,
+ 0xE965, 0, 0, 0, 0, 0, 0x7E38, 0x7170,
+ 0xFD2E, 0x7171, 0xFD2F, 0x7172, 0x7173, 0xFD30, 0x7E39, 0xE96B,
+ 0x3962, 0, 0, 0xE96C, 0xFD32, 0, 0x7174, 0x7175,
+ 0xFD33, 0, 0x7176, 0x7177, 0xE96F, 0xFD34, 0x7178, 0xE971,
+ 0, 0xFD35, 0x4831, 0x717A, 0xE973, 0x4926, 0x717B, 0x7179,
+ 0, 0x717D, 0xE974, 0xE975, 0x717C, 0xE976, 0, 0x717E,
+ 0, 0x7E3A, 0xE978, 0x7221, 0, 0xE979, 0, 0xE97A,
+};
+static const unsigned short utf8_to_euc_E9AC[] = {
+ 0xE97B, 0xE97C, 0xE97D, 0xE97E, 0xEA21, 0xEA22, 0x7222, 0,
+ 0xEA23, 0xEA24, 0, 0xEA25, 0xEA26, 0xEA27, 0xEA28, 0,
+ 0xEA29, 0, 0xEA2A, 0, 0, 0, 0xEA2B, 0,
+ 0x7223, 0xEA2C, 0x7224, 0xEA2D, 0xEA2E, 0, 0, 0x7225,
+ 0xEA2F, 0, 0x7226, 0x7227, 0, 0x7228, 0xEA30, 0x7229,
+ 0x722A, 0x722B, 0x722C, 0xEA31, 0, 0xEA32, 0x722D, 0x722E,
+ 0, 0x5D35, 0x722F, 0xEA33, 0xEA34, 0xEA35, 0, 0xEA36,
+ 0, 0xEA37, 0xEA38, 0x6478, 0x3534, 0xEA39, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9AC_x0213[] = {
+ 0xE97B, 0xE97C, 0x7E3B, 0xFD36, 0xEA21, 0xEA22, 0x7222, 0,
+ 0x7E3C, 0xEA24, 0, 0xEA25, 0xFD37, 0xEA27, 0xEA28, 0,
+ 0xFD38, 0, 0xFD39, 0, 0, 0, 0xFD3A, 0,
+ 0x7223, 0xEA2C, 0x7224, 0xEA2D, 0xFD3B, 0, 0, 0x7225,
+ 0x7E3D, 0, 0x7226, 0x7227, 0, 0x7228, 0xEA30, 0x7229,
+ 0x722A, 0x722B, 0x722C, 0xFD3C, 0, 0x7E3F, 0x722D, 0x722E,
+ 0, 0x5D35, 0x722F, 0xFD3D, 0xEA34, 0xEA35, 0, 0xEA36,
+ 0, 0xEA37, 0xEA38, 0x6478, 0x3534, 0xFD3E, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9AD[] = {
+ 0, 0x3321, 0x3A32, 0x7231, 0x7230, 0x4C25, 0, 0,
+ 0xEA3A, 0, 0, 0xEA3B, 0xEA3C, 0x7233, 0x7234, 0x7232,
+ 0, 0x7235, 0, 0, 0x4B62, 0xEA3D, 0xEA3E, 0xEA3F,
+ 0x7236, 0, 0x357B, 0xEA40, 0, 0, 0xEA41, 0,
+ 0, 0xEA42, 0, 0xEA43, 0, 0xEA44, 0xEA45, 0,
+ 0xEA46, 0, 0xEA47, 0xEA48, 0xEA49, 0xEA4A, 0xEA4B, 0x4F25,
+ 0, 0, 0xF47C, 0xEA4C, 0x7237, 0xEA4D, 0, 0xEA4E,
+ 0xEA4F, 0xEA50, 0, 0, 0, 0, 0, 0xEA51,
+};
+static const unsigned short utf8_to_euc_E9AD_x0213[] = {
+ 0, 0x3321, 0x3A32, 0x7231, 0x7230, 0x4C25, 0, 0,
+ 0xEA3A, 0, 0, 0xFD40, 0xEA3C, 0x7233, 0x7234, 0x7232,
+ 0, 0x7235, 0, 0, 0x4B62, 0xEA3D, 0xEA3E, 0xEA3F,
+ 0x7236, 0, 0x357B, 0xEA40, 0, 0, 0x7E40, 0,
+ 0, 0xEA42, 0, 0xFD41, 0, 0xFD42, 0x7E42, 0,
+ 0xEA46, 0, 0xEA47, 0xFD43, 0xFD44, 0xEA4A, 0xEA4B, 0x4F25,
+ 0, 0, 0x7E43, 0xFD45, 0x7237, 0x7E44, 0xFD46, 0xFD47,
+ 0xEA4F, 0x7E41, 0, 0, 0, 0, 0, 0xEA51,
+};
+static const unsigned short utf8_to_euc_E9AE[] = {
+ 0xEA52, 0, 0, 0x7239, 0xEA53, 0xEA54, 0xEA55, 0xEA56,
+ 0, 0xEA57, 0xEA58, 0xEA59, 0, 0xEA5A, 0x303E, 0xEA5B,
+ 0xEA5C, 0x723A, 0x4A2B, 0x7238, 0xEA5D, 0, 0x723B, 0x723C,
+ 0, 0, 0xEA5E, 0, 0, 0xEA5F, 0xEA60, 0x723D,
+ 0x723E, 0, 0, 0, 0, 0, 0xEA61, 0xEA62,
+ 0x723F, 0xEA63, 0x4B6E, 0x3B2D, 0xEA64, 0x3A7A, 0x412F, 0,
+ 0xEA65, 0xEA66, 0xEA67, 0, 0x7240, 0, 0, 0xEA68,
+ 0xEA69, 0x7243, 0, 0xEA6A, 0xEA6B, 0, 0xEA6C, 0xEA6D,
+};
+static const unsigned short utf8_to_euc_E9AE_x0213[] = {
+ 0xEA52, 0, 0, 0x7239, 0x7E45, 0xEA54, 0xEA55, 0xEA56,
+ 0, 0xEA57, 0x7E46, 0xEA59, 0, 0xEA5A, 0x303E, 0x7E47,
+ 0xEA5C, 0x723A, 0x4A2B, 0x7238, 0xEA5D, 0, 0x723B, 0x723C,
+ 0, 0, 0xEA5E, 0, 0, 0xEA5F, 0x7E48, 0x723D,
+ 0x723E, 0, 0, 0, 0, 0, 0xFD48, 0x7E49,
+ 0x723F, 0xEA63, 0x4B6E, 0x3B2D, 0xFD49, 0x3A7A, 0x412F, 0,
+ 0xEA65, 0xFD4A, 0xFD4D, 0, 0x7240, 0, 0, 0xEA68,
+ 0xFD4E, 0x7243, 0, 0, 0xEA6B, 0, 0xFD4F, 0xEA6D,
+};
+static const unsigned short utf8_to_euc_E9AF[] = {
+ 0x7241, 0xEA6E, 0, 0, 0, 0, 0x7244, 0xEA6F,
+ 0xEA70, 0x3871, 0x7242, 0, 0, 0, 0xEA71, 0x7245,
+ 0xEA72, 0x7246, 0x7247, 0, 0x724B, 0, 0x3B2A, 0xEA73,
+ 0xEA74, 0, 0, 0x4264, 0, 0xEA75, 0, 0xEA76,
+ 0, 0x724C, 0x7249, 0x7248, 0x724A, 0xEA77, 0, 0xEA78,
+ 0x375F, 0, 0xEA79, 0xEA7A, 0, 0, 0, 0xEA7B,
+ 0x7250, 0x724F, 0x724E, 0xEA7C, 0, 0x3033, 0, 0xEA7D,
+ 0xEA7E, 0xEB21, 0xEB22, 0, 0, 0xEB23, 0, 0xEB24,
+};
+static const unsigned short utf8_to_euc_E9AF_x0213[] = {
+ 0x7241, 0x7E4A, 0, 0, 0, 0, 0x7244, 0xFD50,
+ 0xEA70, 0x3871, 0x7242, 0, 0, 0, 0x7E4B, 0x7245,
+ 0xEA72, 0x7246, 0x7247, 0, 0x724B, 0, 0x3B2A, 0xEA73,
+ 0xFD52, 0, 0, 0x4264, 0, 0xFD53, 0, 0xEA76,
+ 0, 0x724C, 0x7249, 0x7248, 0x724A, 0x7E4C, 0, 0xFD54,
+ 0x375F, 0, 0xFD55, 0xFD56, 0, 0, 0xFD58, 0xFD57,
+ 0x7250, 0x724F, 0x724E, 0xFD51, 0, 0x3033, 0, 0xFD5C,
+ 0x7E4D, 0xEB21, 0xFD5A, 0, 0, 0x7E4E, 0, 0xEB24,
+};
+static const unsigned short utf8_to_euc_E9B0[] = {
+ 0xEB25, 0, 0xEB26, 0, 0x725A, 0, 0x7256, 0,
+ 0x7257, 0x7253, 0x7259, 0xEB27, 0x7255, 0x3362, 0, 0xEB28,
+ 0x4F4C, 0xEB29, 0x7258, 0x7254, 0x7252, 0x7251, 0xEB2A, 0,
+ 0xEB2B, 0xEB2C, 0xEB2D, 0x725C, 0xEB2E, 0, 0xEB2F, 0,
+ 0, 0x725F, 0xEB30, 0xEB31, 0x725E, 0x725D, 0xEB32, 0xEB33,
+ 0xEB34, 0xEB35, 0xEB36, 0, 0, 0x4949, 0x725B, 0x3073,
+ 0x7260, 0xEB37, 0x7262, 0, 0, 0xEB38, 0xEB39, 0xEB3A,
+ 0, 0x336F, 0x724D, 0x3137, 0, 0xEB3B, 0x7264, 0,
+};
+static const unsigned short utf8_to_euc_E9B0_x0213[] = {
+ 0x7E4F, 0, 0xEB26, 0, 0x725A, 0, 0x7256, 0,
+ 0x7257, 0x7253, 0x7259, 0xEB27, 0x7255, 0x3362, 0, 0xEB28,
+ 0x4F4C, 0xEB29, 0x7258, 0x7254, 0x7252, 0x7251, 0xFD5E, 0,
+ 0xFD5F, 0xFD60, 0xFD61, 0x725C, 0xEB2E, 0xFD62, 0xEB2F, 0,
+ 0, 0x725F, 0xFD63, 0x7E50, 0x725E, 0x725D, 0xEB32, 0xFD64,
+ 0xEB34, 0xFD65, 0xFD66, 0, 0, 0x4949, 0x725B, 0x3073,
+ 0x7260, 0xFD68, 0x7262, 0, 0, 0xEB38, 0xFD69, 0xFD6A,
+ 0, 0x336F, 0x724D, 0x3137, 0, 0xEB3B, 0x7264, 0,
+};
+static const unsigned short utf8_to_euc_E9B1[] = {
+ 0, 0xEB3C, 0, 0xEB3D, 0xEB3E, 0xEB3F, 0x7263, 0x7261,
+ 0x432D, 0xEB40, 0xEB41, 0, 0, 0, 0xEB42, 0xEB43,
+ 0xEB44, 0, 0x4B70, 0xEB45, 0xEB46, 0, 0xEB47, 0x4E5A,
+ 0xEB48, 0, 0x7265, 0xEB49, 0xEB50, 0xEB4A, 0xEB4B, 0xEB4C,
+ 0x7266, 0, 0, 0xEB4D, 0, 0, 0, 0x7267,
+ 0xEB52, 0xEB4E, 0xEB4F, 0xEB51, 0, 0, 0xEB53, 0,
+ 0xEB54, 0, 0xEB55, 0, 0, 0xEB56, 0x7268, 0xEB57,
+ 0x7269, 0, 0, 0xEB58, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9B1_x0213[] = {
+ 0, 0x7E51, 0, 0xEB3D, 0xEB3E, 0xFD6B, 0x7263, 0x7261,
+ 0x432D, 0xFD6E, 0xFD6F, 0, 0, 0, 0xEB42, 0x7E52,
+ 0x7E53, 0, 0x4B70, 0x7E54, 0xFD71, 0, 0xEB47, 0x4E5A,
+ 0xFD72, 0, 0x7265, 0xFD73, 0xFD6C, 0xFD74, 0xEB4B, 0xFD75,
+ 0x7266, 0, 0, 0x7E55, 0, 0x7E56, 0, 0x7267,
+ 0xEB52, 0xFD76, 0xFD77, 0xFD78, 0, 0xFD79, 0xFD7A, 0,
+ 0xFD7B, 0, 0xFD7C, 0, 0, 0xFD7D, 0x7268, 0x7E57,
+ 0x7269, 0, 0xFD7E, 0xEB58, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9B3[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x443B, 0xEB59, 0x726A,
+ 0, 0x4837, 0, 0x726F, 0x726B, 0, 0, 0,
+ 0x726C, 0, 0xEB5A, 0x4B31, 0x4C44, 0, 0x4650, 0xEB5B,
+ 0, 0xEB5C, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9B3_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x443B, 0xFE21, 0x726A,
+ 0, 0x4837, 0, 0x726F, 0x726B, 0, 0, 0,
+ 0x726C, 0, 0xFE22, 0x4B31, 0x4C44, 0, 0x4650, 0xEB5B,
+ 0, 0xEB5C, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9B4[] = {
+ 0, 0, 0xEB5E, 0x7270, 0, 0, 0x7271, 0x463E,
+ 0x726E, 0x726D, 0, 0xEB5D, 0, 0, 0x322A, 0,
+ 0, 0xEB5F, 0x7279, 0, 0, 0x7278, 0, 0xEB60,
+ 0xEB61, 0, 0, 0x3175, 0xEB62, 0xEB63, 0xEB64, 0x7276,
+ 0, 0, 0, 0x7275, 0, 0, 0x7273, 0,
+ 0x337B, 0, 0x7272, 0x3C32, 0x3229, 0, 0, 0xEB65,
+ 0xEB66, 0, 0xEB67, 0xEB68, 0xEB69, 0, 0, 0,
+ 0, 0, 0xEB6A, 0x3963, 0xEB6B, 0xEB6D, 0x727C, 0x727B,
+};
+static const unsigned short utf8_to_euc_E9B4_x0213[] = {
+ 0, 0, 0xFE24, 0x7270, 0, 0, 0x7271, 0x463E,
+ 0x726E, 0x726D, 0, 0xFE23, 0, 0, 0x322A, 0,
+ 0, 0xFE26, 0x7279, 0, 0, 0x7278, 0, 0xFE27,
+ 0xFE28, 0, 0, 0x3175, 0xEB62, 0x7E58, 0x7E59, 0x7276,
+ 0, 0, 0, 0x7275, 0, 0, 0x7273, 0,
+ 0x337B, 0, 0x7272, 0x3C32, 0x3229, 0, 0, 0xEB65,
+ 0xEB66, 0, 0xFE2C, 0xEB68, 0xEB69, 0, 0, 0,
+ 0, 0, 0xEB6A, 0x3963, 0xEB6B, 0xEB6D, 0x727C, 0x727B,
+};
+static const unsigned short utf8_to_euc_E9B5[] = {
+ 0, 0x727A, 0xEB6E, 0xEB6F, 0x7277, 0xEB6C, 0x727D, 0xEB70,
+ 0x727E, 0, 0xEB71, 0, 0, 0, 0, 0,
+ 0x7325, 0x7324, 0, 0xEB72, 0xEB73, 0, 0, 0,
+ 0, 0x7326, 0, 0, 0x312D, 0x7321, 0x7322, 0xEB74,
+ 0x3974, 0x4C39, 0xEB76, 0xEB75, 0x7323, 0xEB77, 0, 0,
+ 0, 0xEB78, 0xEB79, 0xEB7A, 0x4B32, 0, 0, 0x732B,
+ 0xEB7B, 0, 0x7327, 0, 0, 0, 0xEB7C, 0xEB7D,
+ 0, 0, 0x732C, 0xEB7E, 0xEC21, 0, 0xEC22, 0,
+};
+static const unsigned short utf8_to_euc_E9B5_x0213[] = {
+ 0, 0x727A, 0xFE2E, 0x7E5A, 0x7277, 0xEB6C, 0x727D, 0x7E5B,
+ 0x727E, 0, 0xFE2F, 0, 0, 0, 0, 0,
+ 0x7325, 0x7324, 0x7E5C, 0xEB72, 0xEB73, 0, 0, 0,
+ 0, 0x7326, 0, 0, 0x312D, 0x7321, 0x7322, 0xFE30,
+ 0x3974, 0x4C39, 0xFE31, 0x7E5D, 0x7323, 0xEB77, 0, 0,
+ 0, 0xFE33, 0xEB79, 0xFE34, 0x4B32, 0, 0, 0x732B,
+ 0x7E5E, 0, 0x7327, 0xFE36, 0, 0, 0xFE37, 0xFE38,
+ 0, 0, 0x732C, 0xEB7E, 0x7E5F, 0, 0xFE39, 0,
+};
+static const unsigned short utf8_to_euc_E9B6[] = {
+ 0, 0, 0, 0xEC23, 0xEC24, 0, 0xEC25, 0x7329,
+ 0, 0x7328, 0xEC26, 0, 0, 0xEC27, 0xEC28, 0x375C,
+ 0, 0, 0xEC29, 0xEC2A, 0, 0xEC2B, 0xEC2C, 0xEC2D,
+ 0xEC2E, 0, 0x732D, 0, 0, 0, 0, 0,
+ 0, 0xEC2F, 0, 0, 0x732E, 0, 0, 0,
+ 0, 0x732F, 0xEC30, 0x732A, 0xEC31, 0, 0xEC32, 0x7274,
+ 0, 0xEC33, 0x7330, 0, 0x4461, 0xEC34, 0, 0,
+ 0x7334, 0xEC35, 0x7335, 0x7333, 0xEC36, 0, 0, 0xEC37,
+};
+static const unsigned short utf8_to_euc_E9B6_x0213[] = {
+ 0, 0, 0, 0xEC23, 0xFE3A, 0, 0xEC25, 0x7329,
+ 0, 0x7328, 0x7E60, 0, 0, 0xFE3B, 0xEC28, 0x375C,
+ 0, 0, 0xEC29, 0xEC2A, 0, 0xEC2B, 0x7E61, 0xEC2D,
+ 0xEC2E, 0xFE3C, 0x732D, 0, 0, 0, 0, 0,
+ 0, 0xFE3D, 0, 0, 0x732E, 0, 0, 0,
+ 0, 0x732F, 0xEC30, 0x732A, 0x7E63, 0, 0xEC32, 0x7274,
+ 0, 0xEC33, 0x7330, 0, 0x4461, 0xFE3F, 0, 0,
+ 0x7334, 0xFE40, 0x7335, 0x7333, 0x7E64, 0xFE41, 0, 0xFE3E,
+};
+static const unsigned short utf8_to_euc_E9B7[] = {
+ 0, 0x7332, 0x7338, 0xEC38, 0x7331, 0, 0x7336, 0xEC39,
+ 0, 0xEC3A, 0xEC3B, 0, 0, 0, 0, 0x7337,
+ 0, 0, 0, 0x733A, 0xEC3C, 0xEC3D, 0xEC3E, 0xEC3F,
+ 0, 0x7339, 0xEC40, 0, 0, 0, 0xEC41, 0xEC42,
+ 0xEC43, 0, 0, 0, 0, 0xEC44, 0x733C, 0xEC45,
+ 0, 0xEC46, 0, 0xEC47, 0, 0x733D, 0xEC48, 0x733E,
+ 0xEC49, 0, 0x4F49, 0xEC4A, 0xEC4B, 0, 0, 0,
+ 0x733B, 0x426B, 0x3A6D, 0, 0, 0x733F, 0xEC4C, 0,
+};
+static const unsigned short utf8_to_euc_E9B7_x0213[] = {
+ 0x7E62, 0x7332, 0x7338, 0xFE42, 0x7331, 0, 0x7336, 0xFE43,
+ 0, 0xFE44, 0xEC3B, 0, 0, 0, 0, 0x7337,
+ 0, 0, 0, 0x733A, 0xEC3C, 0xEC3D, 0xFE45, 0x7E65,
+ 0, 0x7339, 0xFE46, 0, 0, 0, 0xEC41, 0xFE47,
+ 0xFE48, 0, 0, 0xFE49, 0, 0xEC44, 0x733C, 0x7E67,
+ 0, 0xEC46, 0, 0xEC47, 0, 0x733D, 0xEC48, 0x733E,
+ 0xEC49, 0, 0x4F49, 0xEC4A, 0xFE4A, 0, 0, 0,
+ 0x733B, 0x426B, 0x3A6D, 0, 0, 0x733F, 0xEC4C, 0,
+};
+static const unsigned short utf8_to_euc_E9B8[] = {
+ 0, 0, 0xEC4E, 0, 0, 0, 0, 0xEC4F,
+ 0, 0, 0xEC4D, 0, 0, 0, 0xEC50, 0,
+ 0xEC51, 0xEC52, 0xEC53, 0, 0, 0xEC54, 0xEC55, 0,
+ 0, 0xEC56, 0x7340, 0x7341, 0xEC57, 0xEC58, 0x7342, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9B8_x0213[] = {
+ 0, 0, 0xFE4D, 0, 0, 0, 0, 0x7E68,
+ 0, 0, 0xFE4C, 0, 0, 0xFE4E, 0xEC50, 0,
+ 0xEC51, 0xEC52, 0xEC53, 0, 0, 0x7E69, 0xEC55, 0,
+ 0, 0xFE4F, 0x7340, 0x7341, 0xFE50, 0xFE51, 0x7342, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9B9[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x7343, 0, 0,
+ 0x3834, 0x7344, 0xEC59, 0xEC5A, 0xEC5B, 0x7345, 0, 0x3C2F,
+};
+static const unsigned short utf8_to_euc_E9B9_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x7343, 0, 0,
+ 0x3834, 0x7344, 0xEC59, 0xFE52, 0x7E6A, 0x7345, 0, 0x3C2F,
+};
+static const unsigned short utf8_to_euc_E9BA[] = {
+ 0xEC5C, 0x7346, 0xEC5D, 0xEC5E, 0xEC5F, 0xEC60, 0, 0xEC61,
+ 0x7347, 0, 0, 0x7348, 0x7349, 0, 0xEC62, 0xEC63,
+ 0, 0x734C, 0x734A, 0x4F3C, 0, 0x734B, 0xEC64, 0x4E6F,
+ 0xEC65, 0, 0, 0xEC66, 0, 0x734D, 0xEC67, 0x4E5B,
+ 0, 0, 0, 0, 0xEC68, 0x734E, 0x477E, 0,
+ 0xEC69, 0x734F, 0x7351, 0, 0xEC6A, 0x7352, 0xEC6B, 0xEC6C,
+ 0xEC6D, 0, 0, 0xEC6E, 0xEC6F, 0xEC70, 0, 0,
+ 0x7350, 0x396D, 0x4C4D, 0x4B63, 0x5677, 0, 0x5D60, 0x4B7B,
+};
+static const unsigned short utf8_to_euc_E9BA_x0213[] = {
+ 0xFE54, 0x7346, 0xEC5D, 0xEC5E, 0xEC5F, 0xFE55, 0, 0xEC61,
+ 0x7347, 0, 0, 0x7348, 0x7349, 0, 0xEC62, 0xEC63,
+ 0, 0x734C, 0x734A, 0x4F3C, 0, 0x734B, 0xEC64, 0x4E6F,
+ 0xEC65, 0, 0, 0xFE56, 0, 0x734D, 0x7E6B, 0x4E5B,
+ 0, 0, 0, 0, 0x7E6C, 0x734E, 0x477E, 0,
+ 0xFE57, 0x734F, 0x7351, 0, 0x7E6D, 0x7352, 0xEC6B, 0x7E6E,
+ 0xEC6D, 0, 0, 0xEC6E, 0x7E6F, 0x7E70, 0, 0,
+ 0x7350, 0x396D, 0x4C4D, 0x4B63, 0x5677, 0xFE59, 0x5D60, 0x4B7B,
+};
+static const unsigned short utf8_to_euc_E9BB[] = {
+ 0, 0, 0, 0, 0x322B, 0, 0xEC71, 0,
+ 0xEC72, 0, 0, 0xEC73, 0x7354, 0x3550, 0x7355, 0x7356,
+ 0x7357, 0xF47E, 0x3975, 0, 0x7358, 0xEC74, 0, 0,
+ 0x6054, 0x4C5B, 0, 0x4263, 0x7359, 0x735B, 0x735A, 0xEC75,
+ 0x735C, 0, 0, 0, 0xEC76, 0x735D, 0, 0xEC77,
+ 0x735E, 0, 0, 0, 0xEC78, 0xEC79, 0xEC7A, 0x735F,
+ 0xEC7B, 0xEC7C, 0xEC7D, 0, 0x7360, 0xEC7E, 0x7361, 0x7362,
+ 0xED21, 0x7363, 0, 0x7364, 0x7365, 0x7366, 0, 0xED22,
+};
+static const unsigned short utf8_to_euc_E9BB_x0213[] = {
+ 0, 0, 0, 0x7E71, 0x322B, 0, 0xEC71, 0,
+ 0xEC72, 0, 0, 0xEC73, 0x7354, 0x3550, 0x7355, 0x7356,
+ 0x7357, 0x7E72, 0x3975, 0, 0x7358, 0xEC74, 0, 0,
+ 0x6054, 0x4C5B, 0, 0x4263, 0x7359, 0x735B, 0x735A, 0xFE5B,
+ 0x735C, 0, 0, 0, 0xEC76, 0x735D, 0, 0xFE5C,
+ 0x735E, 0, 0, 0, 0xEC78, 0xEC79, 0xFE5D, 0x735F,
+ 0xEC7B, 0xEC7C, 0xEC7D, 0, 0x7360, 0xEC7E, 0x7361, 0x7362,
+ 0xED21, 0x7363, 0, 0x7364, 0x7365, 0x7366, 0, 0xFE5E,
+};
+static const unsigned short utf8_to_euc_E9BC[] = {
+ 0, 0, 0xED23, 0xED24, 0, 0, 0, 0x7367,
+ 0x7368, 0xED25, 0, 0, 0, 0, 0x4524, 0xED26,
+ 0xED27, 0xED28, 0xED29, 0x385D, 0xED2A, 0x736A, 0xED2B, 0xED2C,
+ 0, 0xED2D, 0xED2E, 0xED2F, 0, 0, 0, 0xED30,
+ 0x414D, 0x736B, 0xED31, 0, 0, 0, 0xED32, 0,
+ 0, 0, 0xED33, 0xED34, 0x736C, 0, 0, 0xED35,
+ 0, 0xED36, 0xED37, 0, 0xED38, 0, 0, 0xED39,
+ 0, 0xED3A, 0xED3B, 0x4921, 0xED3C, 0xED3D, 0x736D, 0xED3E,
+};
+static const unsigned short utf8_to_euc_E9BC_x0213[] = {
+ 0, 0, 0xFE5F, 0xFE61, 0, 0, 0, 0x7367,
+ 0x7368, 0xED25, 0, 0, 0, 0, 0x4524, 0xED26,
+ 0x7E73, 0xED28, 0xED29, 0x385D, 0xED2A, 0x736A, 0xED2B, 0xFE62,
+ 0, 0xFE63, 0xED2E, 0xED2F, 0, 0, 0, 0xED30,
+ 0x414D, 0x736B, 0xED31, 0, 0, 0, 0xED32, 0,
+ 0, 0, 0xED33, 0xED34, 0x736C, 0, 0, 0xFE64,
+ 0, 0xED36, 0xED37, 0, 0xED38, 0, 0, 0xFE65,
+ 0, 0x7E74, 0xFE66, 0x4921, 0xED3C, 0xFE67, 0x736D, 0xED3E,
+};
+static const unsigned short utf8_to_euc_E9BD[] = {
+ 0, 0xED3F, 0, 0xED40, 0xED41, 0xED42, 0xED43, 0xED44,
+ 0, 0, 0x736E, 0x6337, 0, 0, 0x6C5A, 0x706D,
+ 0, 0, 0x736F, 0xED45, 0x7370, 0xED46, 0xED47, 0xED48,
+ 0xED49, 0, 0xED4A, 0, 0, 0xED4B, 0xED4C, 0x7372,
+ 0x7373, 0x7374, 0x4E70, 0x7371, 0, 0, 0x7375, 0x7376,
+ 0xED4D, 0xED4E, 0x7378, 0, 0x7377, 0xED4F, 0xED50, 0xED51,
+ 0xED52, 0xED53, 0x737A, 0xED54, 0, 0xED55, 0x737B, 0x7379,
+ 0, 0, 0xED56, 0, 0, 0xED57, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9BD_x0213[] = {
+ 0, 0xFE68, 0, 0xED40, 0xED41, 0xFE69, 0xFE6A, 0xED44,
+ 0, 0, 0x736E, 0x6337, 0, 0, 0x6C5A, 0x706D,
+ 0, 0, 0x736F, 0xFE6B, 0x7370, 0xFE6C, 0xED47, 0x7E75,
+ 0xFE6D, 0, 0xED4A, 0, 0, 0xFE6F, 0xED4C, 0x7372,
+ 0x7373, 0x7374, 0x4E70, 0x7371, 0, 0, 0x7375, 0x7376,
+ 0xED4D, 0xFE71, 0x7378, 0, 0x7377, 0xFE73, 0xED50, 0xED51,
+ 0xFE74, 0xED53, 0x737A, 0xED54, 0, 0xFE75, 0x737B, 0x7379,
+ 0, 0, 0xED56, 0, 0, 0xED57, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9BE[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x4E36, 0, 0xED58,
+ 0xED59, 0xED5A, 0xED5B, 0, 0xED5C, 0x737C, 0xED5D, 0xED5E,
+ 0, 0, 0, 0, 0x737D, 0x6354, 0xED5F, 0,
+ 0x737E, 0xED60, 0xED61, 0xED62, 0, 0xED63, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_E9BE_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x4E36, 0, 0xED58,
+ 0x7E76, 0xED5A, 0xED5B, 0, 0x7E77, 0x737C, 0xED5D, 0x7E78,
+ 0, 0, 0, 0, 0x737D, 0x6354, 0xED5F, 0,
+ 0x737E, 0xED60, 0x7E79, 0xED62, 0, 0xED63, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_EFA4[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xF445, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_EFA4_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0x763B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x742E, 0x754E, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0x7B4F, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_EFA5_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x7649, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_EFA7[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xF472, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_EFA7_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x7E24, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0x7D5D, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_EFA8[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xF434, 0xF437,
+ 0xF438, 0xF43D, 0xF444, 0xF447, 0xF448, 0xF44E, 0xF44F, 0xF453,
+ 0xF455, 0xF456, 0xF457, 0xF458, 0xF45A, 0xF45B, 0xF45E, 0xF460,
+ 0xF462, 0xF463, 0xF465, 0xF469, 0xF46A, 0xF46B, 0xF46D, 0xF46F,
+ 0xF470, 0xF473, 0xF477, 0xF478, 0xF479, 0xF47D, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_EFA8_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x2F4B,
+ 0x2F57, 0x4F72, 0, 0xAE79, 0x757A, 0x775A, 0x776F, 0,
+ 0, 0x793C, 0x793D, 0x7941, 0, 0, 0, 0x7B3A,
+ 0xF738, 0xF745, 0x7C2E, 0, 0xF96E, 0, 0x7C6A, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2E38, 0x2E49, 0x2E50, 0x2E63, 0x2E68, 0x2E6E, 0x2F2C, 0x2F2F,
+ 0x2F36, 0x2F5A, 0x2F5E, 0x4F61, 0x4F62, 0x7450, 0x745C, 0x745E,
+};
+static const unsigned short utf8_to_euc_EFA9_x0213[] = {
+ 0x7461, 0x7528, 0x752B, 0x7543, 0x7565, 0x7669, 0x7677, 0x7725,
+ 0x7755, 0xF029, 0x7825, 0x7927, 0x7933, 0x7934, 0x7937, 0x7938,
+ 0x7939, 0x793B, 0x793F, 0x7940, 0x794D, 0x7951, 0x7964, 0x7A2E,
+ 0xF450, 0x7A33, 0x7A3A, 0x7A44, 0x7A58, 0xF574, 0xF575, 0x7B27,
+ 0x7B6F, 0x7B79, 0x7C2F, 0x7C30, 0x7C38, 0x7C3D, 0xF969, 0x7C59,
+ 0x7D63, 0x7D76, 0x7D7B, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_EFB9_x0213[] = {
+ 0, 0, 0, 0, 0, 0x233E, 0x233D, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_EFBC[] = {
+ 0, 0x212A, 0xF42A, 0x2174, 0x2170, 0x2173, 0x2175, 0xF429,
+ 0x214A, 0x214B, 0x2176, 0x215C, 0x2124, 0x215D, 0x2125, 0x213F,
+ 0x2330, 0x2331, 0x2332, 0x2333, 0x2334, 0x2335, 0x2336, 0x2337,
+ 0x2338, 0x2339, 0x2127, 0x2128, 0x2163, 0x2161, 0x2164, 0x2129,
+ 0x2177, 0x2341, 0x2342, 0x2343, 0x2344, 0x2345, 0x2346, 0x2347,
+ 0x2348, 0x2349, 0x234A, 0x234B, 0x234C, 0x234D, 0x234E, 0x234F,
+ 0x2350, 0x2351, 0x2352, 0x2353, 0x2354, 0x2355, 0x2356, 0x2357,
+ 0x2358, 0x2359, 0x235A, 0x214E, 0x2140, 0x214F, 0x2130, 0x2132,
+};
+static const unsigned short utf8_to_euc_EFBC_x0213[] = {
+ 0, 0x212A, 0x2230, 0x2174, 0x2170, 0x2173, 0x2175, 0x222F,
+ 0x214A, 0x214B, 0x2176, 0x215C, 0x2124, 0x2231, 0x2125, 0x213F,
+ 0x2330, 0x2331, 0x2332, 0x2333, 0x2334, 0x2335, 0x2336, 0x2337,
+ 0x2338, 0x2339, 0x2127, 0x2128, 0x2163, 0x2161, 0x2164, 0x2129,
+ 0x2177, 0x2341, 0x2342, 0x2343, 0x2344, 0x2345, 0x2346, 0x2347,
+ 0x2348, 0x2349, 0x234A, 0x234B, 0x234C, 0x234D, 0x234E, 0x234F,
+ 0x2350, 0x2351, 0x2352, 0x2353, 0x2354, 0x2355, 0x2356, 0x2357,
+ 0x2358, 0x2359, 0x235A, 0x214E, 0x2140, 0x214F, 0x2130, 0x2132,
+};
+static const unsigned short utf8_to_euc_EFBD[] = {
+ 0x212E, 0x2361, 0x2362, 0x2363, 0x2364, 0x2365, 0x2366, 0x2367,
+ 0x2368, 0x2369, 0x236A, 0x236B, 0x236C, 0x236D, 0x236E, 0x236F,
+ 0x2370, 0x2371, 0x2372, 0x2373, 0x2374, 0x2375, 0x2376, 0x2377,
+ 0x2378, 0x2379, 0x237A, 0x2150, 0x2143, 0x2151, 0xA237, 0,
+ 0, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+ 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+ 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+ 0x0E38, 0x0E39, 0x0E3A, 0x0E3B, 0x0E3C, 0x0E3D, 0x0E3E, 0x0E3F,
+};
+static const unsigned short utf8_to_euc_EFBD_ms[] = {
+ 0x212E, 0x2361, 0x2362, 0x2363, 0x2364, 0x2365, 0x2366, 0x2367,
+ 0x2368, 0x2369, 0x236A, 0x236B, 0x236C, 0x236D, 0x236E, 0x236F,
+ 0x2370, 0x2371, 0x2372, 0x2373, 0x2374, 0x2375, 0x2376, 0x2377,
+ 0x2378, 0x2379, 0x237A, 0x2150, 0x2143, 0x2151, 0x2141, 0,
+ 0, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+ 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+ 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+ 0x0E38, 0x0E39, 0x0E3A, 0x0E3B, 0x0E3C, 0x0E3D, 0x0E3E, 0x0E3F,
+};
+static const unsigned short utf8_to_euc_EFBD_x0213[] = {
+ 0x212E, 0x2361, 0x2362, 0x2363, 0x2364, 0x2365, 0x2366, 0x2367,
+ 0x2368, 0x2369, 0x236A, 0x236B, 0x236C, 0x236D, 0x236E, 0x236F,
+ 0x2370, 0x2371, 0x2372, 0x2373, 0x2374, 0x2375, 0x2376, 0x2377,
+ 0x2378, 0x2379, 0x237A, 0x2150, 0x2143, 0x2151, 0x2232, 0x2256,
+ 0x2257, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
+ 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
+ 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
+ 0x0E38, 0x0E39, 0x0E3A, 0x0E3B, 0x0E3C, 0x0E3D, 0x0E3E, 0x0E3F,
+};
+static const unsigned short utf8_to_euc_EFBE[] = {
+ 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
+ 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
+ 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
+ 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0x0E5C, 0x0E5D, 0x0E5E, 0x0E5F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_EFBF[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0x2171, 0x2172, 0x224C, 0x2131, 0xA243, 0x216F, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short utf8_to_euc_EFBF_x0213[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0x2131, 0, 0x216F, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short *const utf8_to_euc_E1_x0213[] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ utf8_to_euc_E1B8_x0213, 0, 0, 0,
+ 0, utf8_to_euc_E1BD_x0213, 0, 0,
+};
+static const unsigned short *const utf8_to_euc_E2[] = {
+ utf8_to_euc_E280, 0, 0, 0,
+ utf8_to_euc_E284, utf8_to_euc_E285, utf8_to_euc_E286, utf8_to_euc_E287,
+ utf8_to_euc_E288, utf8_to_euc_E289, utf8_to_euc_E28A, 0,
+ utf8_to_euc_E28C, 0, 0, 0,
+ 0, utf8_to_euc_E291, 0, 0,
+ utf8_to_euc_E294, utf8_to_euc_E295, utf8_to_euc_E296, utf8_to_euc_E297,
+ utf8_to_euc_E298, utf8_to_euc_E299, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+static const unsigned short *const utf8_to_euc_E2_ms[] = {
+ utf8_to_euc_E280_ms, 0, 0, 0,
+ utf8_to_euc_E284, utf8_to_euc_E285, utf8_to_euc_E286, utf8_to_euc_E287,
+ utf8_to_euc_E288, utf8_to_euc_E289, utf8_to_euc_E28A, 0,
+ utf8_to_euc_E28C, 0, 0, 0,
+ 0, utf8_to_euc_E291, 0, 0,
+ utf8_to_euc_E294, utf8_to_euc_E295, utf8_to_euc_E296, utf8_to_euc_E297,
+ utf8_to_euc_E298, utf8_to_euc_E299, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+static const unsigned short *const utf8_to_euc_E2_932[] = {
+ utf8_to_euc_E280_932, 0, 0, 0,
+ utf8_to_euc_E284, utf8_to_euc_E285, utf8_to_euc_E286, utf8_to_euc_E287,
+ utf8_to_euc_E288_932, utf8_to_euc_E289, utf8_to_euc_E28A, 0,
+ utf8_to_euc_E28C, 0, 0, 0,
+ 0, utf8_to_euc_E291, 0, 0,
+ utf8_to_euc_E294, utf8_to_euc_E295, utf8_to_euc_E296, utf8_to_euc_E297,
+ utf8_to_euc_E298, utf8_to_euc_E299, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+static const unsigned short *const utf8_to_euc_E2_mac[] = {
+ utf8_to_euc_E280_932, 0, 0, 0,
+ utf8_to_euc_E284_mac, utf8_to_euc_E285_mac, utf8_to_euc_E286, utf8_to_euc_E287,
+ utf8_to_euc_E288_mac, utf8_to_euc_E289, utf8_to_euc_E28A_mac, 0,
+ utf8_to_euc_E28C, 0, 0, 0,
+ 0, utf8_to_euc_E291_mac, 0, 0,
+ utf8_to_euc_E294, utf8_to_euc_E295, utf8_to_euc_E296, utf8_to_euc_E297,
+ utf8_to_euc_E298, utf8_to_euc_E299, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+static const unsigned short *const utf8_to_euc_E2_x0213[] = {
+ utf8_to_euc_E280_x0213, utf8_to_euc_E281_x0213, utf8_to_euc_E282_x0213, 0,
+ utf8_to_euc_E284_x0213, utf8_to_euc_E285_x0213, utf8_to_euc_E286_x0213, utf8_to_euc_E287_x0213,
+ utf8_to_euc_E288_x0213, utf8_to_euc_E289_x0213, utf8_to_euc_E28A_x0213, utf8_to_euc_E28B_x0213,
+ utf8_to_euc_E28C_x0213, 0, utf8_to_euc_E28E_x0213, utf8_to_euc_E28F_x0213,
+ utf8_to_euc_E290_x0213, utf8_to_euc_E291, 0, utf8_to_euc_E293_x0213,
+ utf8_to_euc_E294, utf8_to_euc_E295, utf8_to_euc_E296_x0213, utf8_to_euc_E297_x0213,
+ utf8_to_euc_E298_x0213, utf8_to_euc_E299_x0213, 0, 0,
+ utf8_to_euc_E29C_x0213, utf8_to_euc_E29D_x0213, 0, 0,
+ 0, 0, 0, 0,
+ utf8_to_euc_E2A4_x0213, 0, utf8_to_euc_E2A6_x0213, utf8_to_euc_E2A7_x0213,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+static const unsigned short *const utf8_to_euc_E3[] = {
+ utf8_to_euc_E380, utf8_to_euc_E381, utf8_to_euc_E382, utf8_to_euc_E383,
+ 0, 0, 0, 0,
+ utf8_to_euc_E388, 0, utf8_to_euc_E38A, 0,
+ utf8_to_euc_E38C, utf8_to_euc_E38D, utf8_to_euc_E38E, utf8_to_euc_E38F,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+static const unsigned short *const utf8_to_euc_E3_932[] = {
+ utf8_to_euc_E380_932, utf8_to_euc_E381, utf8_to_euc_E382_932, utf8_to_euc_E383,
+ 0, 0, 0, 0,
+ utf8_to_euc_E388, 0, utf8_to_euc_E38A, 0,
+ utf8_to_euc_E38C, utf8_to_euc_E38D, utf8_to_euc_E38E, utf8_to_euc_E38F,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+static const unsigned short *const utf8_to_euc_E3_mac[] = {
+ utf8_to_euc_E380_932, utf8_to_euc_E381, utf8_to_euc_E382_932, utf8_to_euc_E383,
+ 0, 0, 0, 0,
+ utf8_to_euc_E388_mac, 0, utf8_to_euc_E38A_mac, 0,
+ utf8_to_euc_E38C_mac, utf8_to_euc_E38D_mac, utf8_to_euc_E38E_mac, utf8_to_euc_E38F_mac,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+static const unsigned short *const utf8_to_euc_E3_x0213[] = {
+ utf8_to_euc_E380_x0213, utf8_to_euc_E381, utf8_to_euc_E382_x0213, utf8_to_euc_E383_x0213,
+ 0, 0, 0, utf8_to_euc_E387_x0213,
+ utf8_to_euc_E388, utf8_to_euc_E389_x0213, utf8_to_euc_E38A_x0213, utf8_to_euc_E38B_x0213,
+ utf8_to_euc_E38C, utf8_to_euc_E38D, utf8_to_euc_E38E, utf8_to_euc_E38F_x0213,
+ utf8_to_euc_E390_x0213, utf8_to_euc_E391_x0213, utf8_to_euc_E392_x0213, utf8_to_euc_E393_x0213,
+ utf8_to_euc_E394_x0213, utf8_to_euc_E395_x0213, utf8_to_euc_E396_x0213, utf8_to_euc_E397_x0213,
+ utf8_to_euc_E398_x0213, utf8_to_euc_E399_x0213, utf8_to_euc_E39A_x0213, utf8_to_euc_E39B_x0213,
+ 0, utf8_to_euc_E39D_x0213, utf8_to_euc_E39E_x0213, utf8_to_euc_E39F_x0213,
+ utf8_to_euc_E3A0_x0213, utf8_to_euc_E3A1_x0213, 0, utf8_to_euc_E3A3_x0213,
+ utf8_to_euc_E3A4_x0213, utf8_to_euc_E3A5_x0213, 0, 0,
+ 0, utf8_to_euc_E3A9_x0213, 0, utf8_to_euc_E3AB_x0213,
+ utf8_to_euc_E3AC_x0213, utf8_to_euc_E3AD_x0213, utf8_to_euc_E3AE_x0213, utf8_to_euc_E3AF_x0213,
+ utf8_to_euc_E3B0_x0213, 0, 0, utf8_to_euc_E3B3_x0213,
+ utf8_to_euc_E3B4_x0213, utf8_to_euc_E3B5_x0213, utf8_to_euc_E3B6_x0213, utf8_to_euc_E3B7_x0213,
+ utf8_to_euc_E3B8_x0213, utf8_to_euc_E3B9_x0213, utf8_to_euc_E3BA_x0213, 0,
+ 0, utf8_to_euc_E3BD_x0213, utf8_to_euc_E3BE_x0213, utf8_to_euc_E3BF_x0213,
+};
+static const unsigned short *const utf8_to_euc_E4[] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ utf8_to_euc_E4B8, utf8_to_euc_E4B9, utf8_to_euc_E4BA, utf8_to_euc_E4BB,
+ utf8_to_euc_E4BC, utf8_to_euc_E4BD, utf8_to_euc_E4BE, utf8_to_euc_E4BF,
+};
+static const unsigned short *const utf8_to_euc_E4_x0213[] = {
+ utf8_to_euc_E480_x0213, utf8_to_euc_E481_x0213, utf8_to_euc_E482_x0213, 0,
+ utf8_to_euc_E484_x0213, utf8_to_euc_E485_x0213, utf8_to_euc_E486_x0213, utf8_to_euc_E487_x0213,
+ utf8_to_euc_E488_x0213, utf8_to_euc_E489_x0213, 0, utf8_to_euc_E48B_x0213,
+ utf8_to_euc_E48C_x0213, utf8_to_euc_E48D_x0213, 0, utf8_to_euc_E48F_x0213,
+ utf8_to_euc_E490_x0213, utf8_to_euc_E491_x0213, utf8_to_euc_E492_x0213, utf8_to_euc_E493_x0213,
+ utf8_to_euc_E494_x0213, utf8_to_euc_E495_x0213, utf8_to_euc_E496_x0213, utf8_to_euc_E497_x0213,
+ utf8_to_euc_E498_x0213, utf8_to_euc_E499_x0213, utf8_to_euc_E49A_x0213, 0,
+ utf8_to_euc_E49C_x0213, utf8_to_euc_E49D_x0213, 0, utf8_to_euc_E49F_x0213,
+ utf8_to_euc_E4A0_x0213, utf8_to_euc_E4A1_x0213, utf8_to_euc_E4A2_x0213, 0,
+ 0, 0, utf8_to_euc_E4A6_x0213, utf8_to_euc_E4A7_x0213,
+ utf8_to_euc_E4A8_x0213, 0, utf8_to_euc_E4AA_x0213, 0,
+ utf8_to_euc_E4AC_x0213, 0, 0, utf8_to_euc_E4AF_x0213,
+ utf8_to_euc_E4B0_x0213, 0, 0, utf8_to_euc_E4B3_x0213,
+ utf8_to_euc_E4B4_x0213, utf8_to_euc_E4B5_x0213, 0, 0,
+ utf8_to_euc_E4B8_x0213, utf8_to_euc_E4B9_x0213, utf8_to_euc_E4BA_x0213, utf8_to_euc_E4BB_x0213,
+ utf8_to_euc_E4BC_x0213, utf8_to_euc_E4BD_x0213, utf8_to_euc_E4BE_x0213, utf8_to_euc_E4BF_x0213,
+};
+static const unsigned short *const utf8_to_euc_E5[] = {
+ utf8_to_euc_E580, utf8_to_euc_E581, utf8_to_euc_E582, utf8_to_euc_E583,
+ utf8_to_euc_E584, utf8_to_euc_E585, utf8_to_euc_E586, utf8_to_euc_E587,
+ utf8_to_euc_E588, utf8_to_euc_E589, utf8_to_euc_E58A, utf8_to_euc_E58B,
+ utf8_to_euc_E58C, utf8_to_euc_E58D, utf8_to_euc_E58E, utf8_to_euc_E58F,
+ utf8_to_euc_E590, utf8_to_euc_E591, utf8_to_euc_E592, utf8_to_euc_E593,
+ utf8_to_euc_E594, utf8_to_euc_E595, utf8_to_euc_E596, utf8_to_euc_E597,
+ utf8_to_euc_E598, utf8_to_euc_E599, utf8_to_euc_E59A, utf8_to_euc_E59B,
+ utf8_to_euc_E59C, utf8_to_euc_E59D, utf8_to_euc_E59E, utf8_to_euc_E59F,
+ utf8_to_euc_E5A0, utf8_to_euc_E5A1, utf8_to_euc_E5A2, utf8_to_euc_E5A3,
+ utf8_to_euc_E5A4, utf8_to_euc_E5A5, utf8_to_euc_E5A6, utf8_to_euc_E5A7,
+ utf8_to_euc_E5A8, utf8_to_euc_E5A9, utf8_to_euc_E5AA, utf8_to_euc_E5AB,
+ utf8_to_euc_E5AC, utf8_to_euc_E5AD, utf8_to_euc_E5AE, utf8_to_euc_E5AF,
+ utf8_to_euc_E5B0, utf8_to_euc_E5B1, utf8_to_euc_E5B2, utf8_to_euc_E5B3,
+ utf8_to_euc_E5B4, utf8_to_euc_E5B5, utf8_to_euc_E5B6, utf8_to_euc_E5B7,
+ utf8_to_euc_E5B8, utf8_to_euc_E5B9, utf8_to_euc_E5BA, utf8_to_euc_E5BB,
+ utf8_to_euc_E5BC, utf8_to_euc_E5BD, utf8_to_euc_E5BE, utf8_to_euc_E5BF,
+};
+static const unsigned short *const utf8_to_euc_E5_x0213[] = {
+ utf8_to_euc_E580_x0213, utf8_to_euc_E581_x0213, utf8_to_euc_E582_x0213, utf8_to_euc_E583_x0213,
+ utf8_to_euc_E584_x0213, utf8_to_euc_E585_x0213, utf8_to_euc_E586_x0213, utf8_to_euc_E587_x0213,
+ utf8_to_euc_E588_x0213, utf8_to_euc_E589_x0213, utf8_to_euc_E58A_x0213, utf8_to_euc_E58B_x0213,
+ utf8_to_euc_E58C_x0213, utf8_to_euc_E58D_x0213, utf8_to_euc_E58E_x0213, utf8_to_euc_E58F_x0213,
+ utf8_to_euc_E590_x0213, utf8_to_euc_E591_x0213, utf8_to_euc_E592_x0213, utf8_to_euc_E593_x0213,
+ utf8_to_euc_E594_x0213, utf8_to_euc_E595_x0213, utf8_to_euc_E596_x0213, utf8_to_euc_E597_x0213,
+ utf8_to_euc_E598_x0213, utf8_to_euc_E599_x0213, utf8_to_euc_E59A_x0213, utf8_to_euc_E59B_x0213,
+ utf8_to_euc_E59C_x0213, utf8_to_euc_E59D_x0213, utf8_to_euc_E59E_x0213, utf8_to_euc_E59F_x0213,
+ utf8_to_euc_E5A0_x0213, utf8_to_euc_E5A1_x0213, utf8_to_euc_E5A2_x0213, utf8_to_euc_E5A3_x0213,
+ utf8_to_euc_E5A4_x0213, utf8_to_euc_E5A5_x0213, utf8_to_euc_E5A6_x0213, utf8_to_euc_E5A7_x0213,
+ utf8_to_euc_E5A8_x0213, utf8_to_euc_E5A9_x0213, utf8_to_euc_E5AA_x0213, utf8_to_euc_E5AB_x0213,
+ utf8_to_euc_E5AC_x0213, utf8_to_euc_E5AD_x0213, utf8_to_euc_E5AE_x0213, utf8_to_euc_E5AF_x0213,
+ utf8_to_euc_E5B0_x0213, utf8_to_euc_E5B1_x0213, utf8_to_euc_E5B2_x0213, utf8_to_euc_E5B3_x0213,
+ utf8_to_euc_E5B4_x0213, utf8_to_euc_E5B5_x0213, utf8_to_euc_E5B6_x0213, utf8_to_euc_E5B7_x0213,
+ utf8_to_euc_E5B8_x0213, utf8_to_euc_E5B9_x0213, utf8_to_euc_E5BA_x0213, utf8_to_euc_E5BB_x0213,
+ utf8_to_euc_E5BC_x0213, utf8_to_euc_E5BD_x0213, utf8_to_euc_E5BE_x0213, utf8_to_euc_E5BF_x0213,
+};
+static const unsigned short *const utf8_to_euc_E6[] = {
+ utf8_to_euc_E680, utf8_to_euc_E681, utf8_to_euc_E682, utf8_to_euc_E683,
+ utf8_to_euc_E684, utf8_to_euc_E685, utf8_to_euc_E686, utf8_to_euc_E687,
+ utf8_to_euc_E688, utf8_to_euc_E689, utf8_to_euc_E68A, utf8_to_euc_E68B,
+ utf8_to_euc_E68C, utf8_to_euc_E68D, utf8_to_euc_E68E, utf8_to_euc_E68F,
+ utf8_to_euc_E690, utf8_to_euc_E691, utf8_to_euc_E692, utf8_to_euc_E693,
+ utf8_to_euc_E694, utf8_to_euc_E695, utf8_to_euc_E696, utf8_to_euc_E697,
+ utf8_to_euc_E698, utf8_to_euc_E699, utf8_to_euc_E69A, utf8_to_euc_E69B,
+ utf8_to_euc_E69C, utf8_to_euc_E69D, utf8_to_euc_E69E, utf8_to_euc_E69F,
+ utf8_to_euc_E6A0, utf8_to_euc_E6A1, utf8_to_euc_E6A2, utf8_to_euc_E6A3,
+ utf8_to_euc_E6A4, utf8_to_euc_E6A5, utf8_to_euc_E6A6, utf8_to_euc_E6A7,
+ utf8_to_euc_E6A8, utf8_to_euc_E6A9, utf8_to_euc_E6AA, utf8_to_euc_E6AB,
+ utf8_to_euc_E6AC, utf8_to_euc_E6AD, utf8_to_euc_E6AE, utf8_to_euc_E6AF,
+ utf8_to_euc_E6B0, utf8_to_euc_E6B1, utf8_to_euc_E6B2, utf8_to_euc_E6B3,
+ utf8_to_euc_E6B4, utf8_to_euc_E6B5, utf8_to_euc_E6B6, utf8_to_euc_E6B7,
+ utf8_to_euc_E6B8, utf8_to_euc_E6B9, utf8_to_euc_E6BA, utf8_to_euc_E6BB,
+ utf8_to_euc_E6BC, utf8_to_euc_E6BD, utf8_to_euc_E6BE, utf8_to_euc_E6BF,
+};
+static const unsigned short *const utf8_to_euc_E6_x0213[] = {
+ utf8_to_euc_E680_x0213, utf8_to_euc_E681_x0213, utf8_to_euc_E682_x0213, utf8_to_euc_E683_x0213,
+ utf8_to_euc_E684_x0213, utf8_to_euc_E685_x0213, utf8_to_euc_E686_x0213, utf8_to_euc_E687_x0213,
+ utf8_to_euc_E688_x0213, utf8_to_euc_E689_x0213, utf8_to_euc_E68A_x0213, utf8_to_euc_E68B_x0213,
+ utf8_to_euc_E68C_x0213, utf8_to_euc_E68D_x0213, utf8_to_euc_E68E_x0213, utf8_to_euc_E68F_x0213,
+ utf8_to_euc_E690_x0213, utf8_to_euc_E691_x0213, utf8_to_euc_E692_x0213, utf8_to_euc_E693_x0213,
+ utf8_to_euc_E694_x0213, utf8_to_euc_E695_x0213, utf8_to_euc_E696_x0213, utf8_to_euc_E697_x0213,
+ utf8_to_euc_E698_x0213, utf8_to_euc_E699_x0213, utf8_to_euc_E69A_x0213, utf8_to_euc_E69B_x0213,
+ utf8_to_euc_E69C_x0213, utf8_to_euc_E69D_x0213, utf8_to_euc_E69E_x0213, utf8_to_euc_E69F_x0213,
+ utf8_to_euc_E6A0_x0213, utf8_to_euc_E6A1_x0213, utf8_to_euc_E6A2_x0213, utf8_to_euc_E6A3_x0213,
+ utf8_to_euc_E6A4_x0213, utf8_to_euc_E6A5_x0213, utf8_to_euc_E6A6_x0213, utf8_to_euc_E6A7_x0213,
+ utf8_to_euc_E6A8_x0213, utf8_to_euc_E6A9_x0213, utf8_to_euc_E6AA_x0213, utf8_to_euc_E6AB_x0213,
+ utf8_to_euc_E6AC_x0213, utf8_to_euc_E6AD_x0213, utf8_to_euc_E6AE_x0213, utf8_to_euc_E6AF_x0213,
+ utf8_to_euc_E6B0_x0213, utf8_to_euc_E6B1_x0213, utf8_to_euc_E6B2_x0213, utf8_to_euc_E6B3_x0213,
+ utf8_to_euc_E6B4_x0213, utf8_to_euc_E6B5_x0213, utf8_to_euc_E6B6_x0213, utf8_to_euc_E6B7_x0213,
+ utf8_to_euc_E6B8_x0213, utf8_to_euc_E6B9_x0213, utf8_to_euc_E6BA_x0213, utf8_to_euc_E6BB_x0213,
+ utf8_to_euc_E6BC_x0213, utf8_to_euc_E6BD_x0213, utf8_to_euc_E6BE_x0213, utf8_to_euc_E6BF_x0213,
+};
+static const unsigned short *const utf8_to_euc_E7[] = {
+ utf8_to_euc_E780, utf8_to_euc_E781, utf8_to_euc_E782, utf8_to_euc_E783,
+ utf8_to_euc_E784, utf8_to_euc_E785, utf8_to_euc_E786, utf8_to_euc_E787,
+ utf8_to_euc_E788, utf8_to_euc_E789, utf8_to_euc_E78A, utf8_to_euc_E78B,
+ utf8_to_euc_E78C, utf8_to_euc_E78D, utf8_to_euc_E78E, utf8_to_euc_E78F,
+ utf8_to_euc_E790, utf8_to_euc_E791, utf8_to_euc_E792, utf8_to_euc_E793,
+ utf8_to_euc_E794, utf8_to_euc_E795, utf8_to_euc_E796, utf8_to_euc_E797,
+ utf8_to_euc_E798, utf8_to_euc_E799, utf8_to_euc_E79A, utf8_to_euc_E79B,
+ utf8_to_euc_E79C, utf8_to_euc_E79D, utf8_to_euc_E79E, utf8_to_euc_E79F,
+ utf8_to_euc_E7A0, utf8_to_euc_E7A1, utf8_to_euc_E7A2, utf8_to_euc_E7A3,
+ utf8_to_euc_E7A4, utf8_to_euc_E7A5, utf8_to_euc_E7A6, utf8_to_euc_E7A7,
+ utf8_to_euc_E7A8, utf8_to_euc_E7A9, utf8_to_euc_E7AA, utf8_to_euc_E7AB,
+ utf8_to_euc_E7AC, utf8_to_euc_E7AD, utf8_to_euc_E7AE, utf8_to_euc_E7AF,
+ utf8_to_euc_E7B0, utf8_to_euc_E7B1, utf8_to_euc_E7B2, utf8_to_euc_E7B3,
+ utf8_to_euc_E7B4, utf8_to_euc_E7B5, utf8_to_euc_E7B6, utf8_to_euc_E7B7,
+ utf8_to_euc_E7B8, utf8_to_euc_E7B9, utf8_to_euc_E7BA, 0,
+ utf8_to_euc_E7BC, utf8_to_euc_E7BD, utf8_to_euc_E7BE, utf8_to_euc_E7BF,
+};
+static const unsigned short *const utf8_to_euc_E7_x0213[] = {
+ utf8_to_euc_E780_x0213, utf8_to_euc_E781_x0213, utf8_to_euc_E782_x0213, utf8_to_euc_E783_x0213,
+ utf8_to_euc_E784_x0213, utf8_to_euc_E785_x0213, utf8_to_euc_E786_x0213, utf8_to_euc_E787_x0213,
+ utf8_to_euc_E788_x0213, utf8_to_euc_E789_x0213, utf8_to_euc_E78A_x0213, utf8_to_euc_E78B_x0213,
+ utf8_to_euc_E78C_x0213, utf8_to_euc_E78D_x0213, utf8_to_euc_E78E_x0213, utf8_to_euc_E78F_x0213,
+ utf8_to_euc_E790_x0213, utf8_to_euc_E791_x0213, utf8_to_euc_E792_x0213, utf8_to_euc_E793_x0213,
+ utf8_to_euc_E794_x0213, utf8_to_euc_E795_x0213, utf8_to_euc_E796_x0213, utf8_to_euc_E797_x0213,
+ utf8_to_euc_E798_x0213, utf8_to_euc_E799_x0213, utf8_to_euc_E79A_x0213, utf8_to_euc_E79B_x0213,
+ utf8_to_euc_E79C_x0213, utf8_to_euc_E79D_x0213, utf8_to_euc_E79E_x0213, utf8_to_euc_E79F_x0213,
+ utf8_to_euc_E7A0_x0213, utf8_to_euc_E7A1_x0213, utf8_to_euc_E7A2_x0213, utf8_to_euc_E7A3_x0213,
+ utf8_to_euc_E7A4_x0213, utf8_to_euc_E7A5_x0213, utf8_to_euc_E7A6_x0213, utf8_to_euc_E7A7_x0213,
+ utf8_to_euc_E7A8_x0213, utf8_to_euc_E7A9_x0213, utf8_to_euc_E7AA_x0213, utf8_to_euc_E7AB_x0213,
+ utf8_to_euc_E7AC_x0213, utf8_to_euc_E7AD_x0213, utf8_to_euc_E7AE_x0213, utf8_to_euc_E7AF_x0213,
+ utf8_to_euc_E7B0_x0213, utf8_to_euc_E7B1_x0213, utf8_to_euc_E7B2_x0213, utf8_to_euc_E7B3_x0213,
+ utf8_to_euc_E7B4_x0213, utf8_to_euc_E7B5_x0213, utf8_to_euc_E7B6_x0213, utf8_to_euc_E7B7_x0213,
+ utf8_to_euc_E7B8_x0213, utf8_to_euc_E7B9_x0213, utf8_to_euc_E7BA_x0213, 0,
+ utf8_to_euc_E7BC_x0213, utf8_to_euc_E7BD_x0213, utf8_to_euc_E7BE_x0213, utf8_to_euc_E7BF_x0213,
+};
+static const unsigned short *const utf8_to_euc_E8[] = {
+ utf8_to_euc_E880, utf8_to_euc_E881, utf8_to_euc_E882, utf8_to_euc_E883,
+ utf8_to_euc_E884, utf8_to_euc_E885, utf8_to_euc_E886, utf8_to_euc_E887,
+ utf8_to_euc_E888, utf8_to_euc_E889, utf8_to_euc_E88A, utf8_to_euc_E88B,
+ utf8_to_euc_E88C, utf8_to_euc_E88D, utf8_to_euc_E88E, utf8_to_euc_E88F,
+ utf8_to_euc_E890, utf8_to_euc_E891, utf8_to_euc_E892, utf8_to_euc_E893,
+ utf8_to_euc_E894, utf8_to_euc_E895, utf8_to_euc_E896, utf8_to_euc_E897,
+ utf8_to_euc_E898, utf8_to_euc_E899, utf8_to_euc_E89A, utf8_to_euc_E89B,
+ utf8_to_euc_E89C, utf8_to_euc_E89D, utf8_to_euc_E89E, utf8_to_euc_E89F,
+ utf8_to_euc_E8A0, utf8_to_euc_E8A1, utf8_to_euc_E8A2, utf8_to_euc_E8A3,
+ utf8_to_euc_E8A4, utf8_to_euc_E8A5, utf8_to_euc_E8A6, utf8_to_euc_E8A7,
+ utf8_to_euc_E8A8, utf8_to_euc_E8A9, utf8_to_euc_E8AA, utf8_to_euc_E8AB,
+ utf8_to_euc_E8AC, utf8_to_euc_E8AD, utf8_to_euc_E8AE, 0,
+ utf8_to_euc_E8B0, utf8_to_euc_E8B1, utf8_to_euc_E8B2, utf8_to_euc_E8B3,
+ utf8_to_euc_E8B4, utf8_to_euc_E8B5, utf8_to_euc_E8B6, utf8_to_euc_E8B7,
+ utf8_to_euc_E8B8, utf8_to_euc_E8B9, utf8_to_euc_E8BA, utf8_to_euc_E8BB,
+ utf8_to_euc_E8BC, utf8_to_euc_E8BD, utf8_to_euc_E8BE, utf8_to_euc_E8BF,
+};
+static const unsigned short *const utf8_to_euc_E8_x0213[] = {
+ utf8_to_euc_E880_x0213, utf8_to_euc_E881_x0213, utf8_to_euc_E882_x0213, utf8_to_euc_E883_x0213,
+ utf8_to_euc_E884_x0213, utf8_to_euc_E885_x0213, utf8_to_euc_E886_x0213, utf8_to_euc_E887_x0213,
+ utf8_to_euc_E888_x0213, utf8_to_euc_E889_x0213, utf8_to_euc_E88A_x0213, utf8_to_euc_E88B_x0213,
+ utf8_to_euc_E88C_x0213, utf8_to_euc_E88D_x0213, utf8_to_euc_E88E_x0213, utf8_to_euc_E88F_x0213,
+ utf8_to_euc_E890_x0213, utf8_to_euc_E891_x0213, utf8_to_euc_E892_x0213, utf8_to_euc_E893_x0213,
+ utf8_to_euc_E894_x0213, utf8_to_euc_E895_x0213, utf8_to_euc_E896_x0213, utf8_to_euc_E897_x0213,
+ utf8_to_euc_E898_x0213, utf8_to_euc_E899_x0213, utf8_to_euc_E89A_x0213, utf8_to_euc_E89B_x0213,
+ utf8_to_euc_E89C_x0213, utf8_to_euc_E89D_x0213, utf8_to_euc_E89E_x0213, utf8_to_euc_E89F_x0213,
+ utf8_to_euc_E8A0_x0213, utf8_to_euc_E8A1_x0213, utf8_to_euc_E8A2_x0213, utf8_to_euc_E8A3_x0213,
+ utf8_to_euc_E8A4_x0213, utf8_to_euc_E8A5_x0213, utf8_to_euc_E8A6_x0213, utf8_to_euc_E8A7_x0213,
+ utf8_to_euc_E8A8_x0213, utf8_to_euc_E8A9_x0213, utf8_to_euc_E8AA_x0213, utf8_to_euc_E8AB_x0213,
+ utf8_to_euc_E8AC_x0213, utf8_to_euc_E8AD_x0213, utf8_to_euc_E8AE_x0213, 0,
+ utf8_to_euc_E8B0_x0213, utf8_to_euc_E8B1_x0213, utf8_to_euc_E8B2_x0213, utf8_to_euc_E8B3_x0213,
+ utf8_to_euc_E8B4_x0213, utf8_to_euc_E8B5_x0213, utf8_to_euc_E8B6_x0213, utf8_to_euc_E8B7_x0213,
+ utf8_to_euc_E8B8_x0213, utf8_to_euc_E8B9_x0213, utf8_to_euc_E8BA_x0213, utf8_to_euc_E8BB_x0213,
+ utf8_to_euc_E8BC_x0213, utf8_to_euc_E8BD_x0213, utf8_to_euc_E8BE_x0213, utf8_to_euc_E8BF_x0213,
+};
+static const unsigned short *const utf8_to_euc_E9[] = {
+ utf8_to_euc_E980, utf8_to_euc_E981, utf8_to_euc_E982, utf8_to_euc_E983,
+ utf8_to_euc_E984, utf8_to_euc_E985, utf8_to_euc_E986, utf8_to_euc_E987,
+ utf8_to_euc_E988, utf8_to_euc_E989, utf8_to_euc_E98A, utf8_to_euc_E98B,
+ utf8_to_euc_E98C, utf8_to_euc_E98D, utf8_to_euc_E98E, utf8_to_euc_E98F,
+ utf8_to_euc_E990, utf8_to_euc_E991, utf8_to_euc_E992, 0,
+ 0, utf8_to_euc_E995, utf8_to_euc_E996, utf8_to_euc_E997,
+ utf8_to_euc_E998, utf8_to_euc_E999, utf8_to_euc_E99A, utf8_to_euc_E99B,
+ utf8_to_euc_E99C, utf8_to_euc_E99D, utf8_to_euc_E99E, utf8_to_euc_E99F,
+ utf8_to_euc_E9A0, utf8_to_euc_E9A1, utf8_to_euc_E9A2, utf8_to_euc_E9A3,
+ utf8_to_euc_E9A4, utf8_to_euc_E9A5, utf8_to_euc_E9A6, utf8_to_euc_E9A7,
+ utf8_to_euc_E9A8, utf8_to_euc_E9A9, utf8_to_euc_E9AA, utf8_to_euc_E9AB,
+ utf8_to_euc_E9AC, utf8_to_euc_E9AD, utf8_to_euc_E9AE, utf8_to_euc_E9AF,
+ utf8_to_euc_E9B0, utf8_to_euc_E9B1, 0, utf8_to_euc_E9B3,
+ utf8_to_euc_E9B4, utf8_to_euc_E9B5, utf8_to_euc_E9B6, utf8_to_euc_E9B7,
+ utf8_to_euc_E9B8, utf8_to_euc_E9B9, utf8_to_euc_E9BA, utf8_to_euc_E9BB,
+ utf8_to_euc_E9BC, utf8_to_euc_E9BD, utf8_to_euc_E9BE, 0,
+};
+static const unsigned short *const utf8_to_euc_E9_x0213[] = {
+ utf8_to_euc_E980_x0213, utf8_to_euc_E981_x0213, utf8_to_euc_E982_x0213, utf8_to_euc_E983_x0213,
+ utf8_to_euc_E984_x0213, utf8_to_euc_E985_x0213, utf8_to_euc_E986_x0213, utf8_to_euc_E987_x0213,
+ utf8_to_euc_E988_x0213, utf8_to_euc_E989_x0213, utf8_to_euc_E98A_x0213, utf8_to_euc_E98B_x0213,
+ utf8_to_euc_E98C_x0213, utf8_to_euc_E98D_x0213, utf8_to_euc_E98E_x0213, utf8_to_euc_E98F_x0213,
+ utf8_to_euc_E990_x0213, utf8_to_euc_E991_x0213, utf8_to_euc_E992, 0,
+ 0, utf8_to_euc_E995_x0213, utf8_to_euc_E996_x0213, utf8_to_euc_E997_x0213,
+ utf8_to_euc_E998_x0213, utf8_to_euc_E999_x0213, utf8_to_euc_E99A_x0213, utf8_to_euc_E99B_x0213,
+ utf8_to_euc_E99C_x0213, utf8_to_euc_E99D_x0213, utf8_to_euc_E99E_x0213, utf8_to_euc_E99F_x0213,
+ utf8_to_euc_E9A0_x0213, utf8_to_euc_E9A1_x0213, utf8_to_euc_E9A2_x0213, utf8_to_euc_E9A3_x0213,
+ utf8_to_euc_E9A4_x0213, utf8_to_euc_E9A5_x0213, utf8_to_euc_E9A6_x0213, utf8_to_euc_E9A7_x0213,
+ utf8_to_euc_E9A8_x0213, utf8_to_euc_E9A9_x0213, utf8_to_euc_E9AA_x0213, utf8_to_euc_E9AB_x0213,
+ utf8_to_euc_E9AC_x0213, utf8_to_euc_E9AD_x0213, utf8_to_euc_E9AE_x0213, utf8_to_euc_E9AF_x0213,
+ utf8_to_euc_E9B0_x0213, utf8_to_euc_E9B1_x0213, 0, utf8_to_euc_E9B3_x0213,
+ utf8_to_euc_E9B4_x0213, utf8_to_euc_E9B5_x0213, utf8_to_euc_E9B6_x0213, utf8_to_euc_E9B7_x0213,
+ utf8_to_euc_E9B8_x0213, utf8_to_euc_E9B9_x0213, utf8_to_euc_E9BA_x0213, utf8_to_euc_E9BB_x0213,
+ utf8_to_euc_E9BC_x0213, utf8_to_euc_E9BD_x0213, utf8_to_euc_E9BE_x0213, 0,
+};
+static const unsigned short *const utf8_to_euc_EF[] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ utf8_to_euc_EFA4, 0, 0, utf8_to_euc_EFA7,
+ utf8_to_euc_EFA8, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ utf8_to_euc_EFBC, utf8_to_euc_EFBD, utf8_to_euc_EFBE, utf8_to_euc_EFBF,
+};
+static const unsigned short *const utf8_to_euc_EF_ms[] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ utf8_to_euc_EFA4, 0, 0, utf8_to_euc_EFA7,
+ utf8_to_euc_EFA8, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ utf8_to_euc_EFBC, utf8_to_euc_EFBD_ms, utf8_to_euc_EFBE, utf8_to_euc_EFBF,
+};
+static const unsigned short *const utf8_to_euc_EF_x0213[] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ utf8_to_euc_EFA4_x0213, utf8_to_euc_EFA5_x0213, 0, utf8_to_euc_EFA7_x0213,
+ utf8_to_euc_EFA8_x0213, utf8_to_euc_EFA9_x0213, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, utf8_to_euc_EFB9_x0213, 0, 0,
+ utf8_to_euc_EFBC_x0213, utf8_to_euc_EFBD_x0213, utf8_to_euc_EFBE, utf8_to_euc_EFBF_x0213,
+};
+const unsigned short *const utf8_to_euc_2bytes[] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, utf8_to_euc_C2, utf8_to_euc_C3,
+ utf8_to_euc_C4, utf8_to_euc_C5, 0, utf8_to_euc_C7,
+ 0, 0, 0, utf8_to_euc_CB,
+ 0, 0, utf8_to_euc_CE, utf8_to_euc_CF,
+ utf8_to_euc_D0, utf8_to_euc_D1, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+const unsigned short *const utf8_to_euc_2bytes_ms[] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, utf8_to_euc_C2_ms, utf8_to_euc_C3,
+ utf8_to_euc_C4, utf8_to_euc_C5, 0, utf8_to_euc_C7,
+ 0, 0, 0, utf8_to_euc_CB,
+ 0, 0, utf8_to_euc_CE, utf8_to_euc_CF,
+ utf8_to_euc_D0, utf8_to_euc_D1, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+const unsigned short *const utf8_to_euc_2bytes_932[] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, utf8_to_euc_C2_932, utf8_to_euc_C3_932,
+ utf8_to_euc_C4, utf8_to_euc_C5, 0, utf8_to_euc_C7,
+ 0, 0, 0, utf8_to_euc_CB,
+ 0, 0, utf8_to_euc_CE, utf8_to_euc_CF,
+ utf8_to_euc_D0, utf8_to_euc_D1, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+const unsigned short *const utf8_to_euc_2bytes_mac[] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, utf8_to_euc_C2_mac, utf8_to_euc_C3,
+ utf8_to_euc_C4, utf8_to_euc_C5, 0, utf8_to_euc_C7,
+ 0, 0, 0, utf8_to_euc_CB,
+ 0, 0, utf8_to_euc_CE, utf8_to_euc_CF,
+ utf8_to_euc_D0, utf8_to_euc_D1, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+const unsigned short *const utf8_to_euc_2bytes_x0213[] = {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, utf8_to_euc_C2_x0213, utf8_to_euc_C3_x0213,
+ utf8_to_euc_C4_x0213, utf8_to_euc_C5_x0213, utf8_to_euc_C6_x0213, utf8_to_euc_C7_x0213,
+ 0, utf8_to_euc_C9_x0213, utf8_to_euc_CA_x0213, utf8_to_euc_CB_x0213,
+ utf8_to_euc_CC_x0213, utf8_to_euc_CD_x0213, utf8_to_euc_CE, utf8_to_euc_CF_x0213,
+ utf8_to_euc_D0, utf8_to_euc_D1, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+const unsigned short *const *const utf8_to_euc_3bytes[] = {
+ 0, 0, utf8_to_euc_E2, utf8_to_euc_E3,
+ utf8_to_euc_E4, utf8_to_euc_E5, utf8_to_euc_E6, utf8_to_euc_E7,
+ utf8_to_euc_E8, utf8_to_euc_E9, 0, 0,
+ 0, 0, 0, utf8_to_euc_EF,
+};
+const unsigned short *const *const utf8_to_euc_3bytes_ms[] = {
+ 0, 0, utf8_to_euc_E2_ms, utf8_to_euc_E3,
+ utf8_to_euc_E4, utf8_to_euc_E5, utf8_to_euc_E6, utf8_to_euc_E7,
+ utf8_to_euc_E8, utf8_to_euc_E9, 0, 0,
+ 0, 0, 0, utf8_to_euc_EF_ms,
+};
+const unsigned short *const *const utf8_to_euc_3bytes_932[] = {
+ 0, 0, utf8_to_euc_E2_932, utf8_to_euc_E3_932,
+ utf8_to_euc_E4, utf8_to_euc_E5, utf8_to_euc_E6, utf8_to_euc_E7,
+ utf8_to_euc_E8, utf8_to_euc_E9, 0, 0,
+ 0, 0, 0, utf8_to_euc_EF_ms,
+};
+const unsigned short *const *const utf8_to_euc_3bytes_mac[] = {
+ 0, 0, utf8_to_euc_E2_mac, utf8_to_euc_E3_mac,
+ utf8_to_euc_E4, utf8_to_euc_E5, utf8_to_euc_E6, utf8_to_euc_E7,
+ utf8_to_euc_E8, utf8_to_euc_E9, 0, 0,
+ 0, 0, 0, utf8_to_euc_EF_ms,
+};
+const unsigned short *const *const utf8_to_euc_3bytes_x0213[] = {
+ 0, utf8_to_euc_E1_x0213, utf8_to_euc_E2_x0213, utf8_to_euc_E3_x0213,
+ utf8_to_euc_E4_x0213, utf8_to_euc_E5_x0213, utf8_to_euc_E6_x0213, utf8_to_euc_E7_x0213,
+ utf8_to_euc_E8_x0213, utf8_to_euc_E9_x0213, 0, 0,
+ 0, 0, 0, utf8_to_euc_EF_x0213,
+};
+
+#ifdef UNICODE_NORMALIZATION
+
+/* Normalization Table by Apple */
+/* http://developer.apple.com/technotes/tn/tn1150table.html */
+
+const struct normalization_pair normalization_table[] = {
+ {{0xcd,0xbe}, {0x3b}},
+ {{0xc3,0x80}, {0x41,0xcc,0x80,0x00}},
+ {{0xc3,0x81}, {0x41,0xcc,0x81}},
+ {{0xc3,0x82}, {0x41,0xcc,0x82}},
+ {{0xe1,0xba,0xa6}, {0x41,0xcc,0x82,0xcc,0x80}},
+ {{0xe1,0xba,0xa4}, {0x41,0xcc,0x82,0xcc,0x81}},
+ {{0xe1,0xba,0xaa}, {0x41,0xcc,0x82,0xcc,0x83}},
+ {{0xe1,0xba,0xa8}, {0x41,0xcc,0x82,0xcc,0x89}},
+ {{0xc3,0x83}, {0x41,0xcc,0x83}},
+ {{0xc4,0x80}, {0x41,0xcc,0x84}},
+ {{0xc4,0x82}, {0x41,0xcc,0x86}},
+ {{0xe1,0xba,0xb0}, {0x41,0xcc,0x86,0xcc,0x80}},
+ {{0xe1,0xba,0xae}, {0x41,0xcc,0x86,0xcc,0x81}},
+ {{0xe1,0xba,0xb4}, {0x41,0xcc,0x86,0xcc,0x83}},
+ {{0xe1,0xba,0xb2}, {0x41,0xcc,0x86,0xcc,0x89}},
+ {{0xc7,0xa0}, {0x41,0xcc,0x87,0xcc,0x84}},
+ {{0xc3,0x84}, {0x41,0xcc,0x88}},
+ {{0xc7,0x9e}, {0x41,0xcc,0x88,0xcc,0x84}},
+ {{0xe1,0xba,0xa2}, {0x41,0xcc,0x89}},
+ {{0xc3,0x85}, {0x41,0xcc,0x8a}},
+ {{0xc7,0xba}, {0x41,0xcc,0x8a,0xcc,0x81}},
+ {{0xc7,0x8d}, {0x41,0xcc,0x8c}},
+ {{0xc8,0x80}, {0x41,0xcc,0x8f}},
+ {{0xc8,0x82}, {0x41,0xcc,0x91}},
+ {{0xe1,0xba,0xa0}, {0x41,0xcc,0xa3}},
+ {{0xe1,0xba,0xac}, {0x41,0xcc,0xa3,0xcc,0x82}},
+ {{0xe1,0xba,0xb6}, {0x41,0xcc,0xa3,0xcc,0x86}},
+ {{0xe1,0xb8,0x80}, {0x41,0xcc,0xa5}},
+ {{0xc4,0x84}, {0x41,0xcc,0xa8}},
+ {{0xe1,0xb8,0x82}, {0x42,0xcc,0x87}},
+ {{0xe1,0xb8,0x84}, {0x42,0xcc,0xa3}},
+ {{0xe1,0xb8,0x86}, {0x42,0xcc,0xb1}},
+ {{0xc4,0x86}, {0x43,0xcc,0x81}},
+ {{0xc4,0x88}, {0x43,0xcc,0x82}},
+ {{0xc4,0x8a}, {0x43,0xcc,0x87}},
+ {{0xc4,0x8c}, {0x43,0xcc,0x8c}},
+ {{0xc3,0x87}, {0x43,0xcc,0xa7}},
+ {{0xe1,0xb8,0x88}, {0x43,0xcc,0xa7,0xcc,0x81}},
+ {{0xe1,0xb8,0x8a}, {0x44,0xcc,0x87}},
+ {{0xc4,0x8e}, {0x44,0xcc,0x8c}},
+ {{0xe1,0xb8,0x8c}, {0x44,0xcc,0xa3}},
+ {{0xe1,0xb8,0x90}, {0x44,0xcc,0xa7}},
+ {{0xe1,0xb8,0x92}, {0x44,0xcc,0xad}},
+ {{0xe1,0xb8,0x8e}, {0x44,0xcc,0xb1}},
+ {{0xc3,0x88}, {0x45,0xcc,0x80}},
+ {{0xc3,0x89}, {0x45,0xcc,0x81}},
+ {{0xc3,0x8a}, {0x45,0xcc,0x82}},
+ {{0xe1,0xbb,0x80}, {0x45,0xcc,0x82,0xcc,0x80}},
+ {{0xe1,0xba,0xbe}, {0x45,0xcc,0x82,0xcc,0x81}},
+ {{0xe1,0xbb,0x84}, {0x45,0xcc,0x82,0xcc,0x83}},
+ {{0xe1,0xbb,0x82}, {0x45,0xcc,0x82,0xcc,0x89}},
+ {{0xe1,0xba,0xbc}, {0x45,0xcc,0x83}},
+ {{0xc4,0x92}, {0x45,0xcc,0x84}},
+ {{0xe1,0xb8,0x94}, {0x45,0xcc,0x84,0xcc,0x80}},
+ {{0xe1,0xb8,0x96}, {0x45,0xcc,0x84,0xcc,0x81}},
+ {{0xc4,0x94}, {0x45,0xcc,0x86}},
+ {{0xc4,0x96}, {0x45,0xcc,0x87}},
+ {{0xc3,0x8b}, {0x45,0xcc,0x88}},
+ {{0xe1,0xba,0xba}, {0x45,0xcc,0x89}},
+ {{0xc4,0x9a}, {0x45,0xcc,0x8c}},
+ {{0xc8,0x84}, {0x45,0xcc,0x8f}},
+ {{0xc8,0x86}, {0x45,0xcc,0x91}},
+ {{0xe1,0xba,0xb8}, {0x45,0xcc,0xa3}},
+ {{0xe1,0xbb,0x86}, {0x45,0xcc,0xa3,0xcc,0x82}},
+ {{0xe1,0xb8,0x9c}, {0x45,0xcc,0xa7,0xcc,0x86}},
+ {{0xc4,0x98}, {0x45,0xcc,0xa8}},
+ {{0xe1,0xb8,0x98}, {0x45,0xcc,0xad}},
+ {{0xe1,0xb8,0x9a}, {0x45,0xcc,0xb0}},
+ {{0xe1,0xb8,0x9e}, {0x46,0xcc,0x87}},
+ {{0xc7,0xb4}, {0x47,0xcc,0x81}},
+ {{0xc4,0x9c}, {0x47,0xcc,0x82}},
+ {{0xe1,0xb8,0xa0}, {0x47,0xcc,0x84}},
+ {{0xc4,0x9e}, {0x47,0xcc,0x86}},
+ {{0xc4,0xa0}, {0x47,0xcc,0x87}},
+ {{0xc7,0xa6}, {0x47,0xcc,0x8c}},
+ {{0xc4,0xa2}, {0x47,0xcc,0xa7}},
+ {{0xc4,0xa4}, {0x48,0xcc,0x82}},
+ {{0xe1,0xb8,0xa2}, {0x48,0xcc,0x87}},
+ {{0xe1,0xb8,0xa6}, {0x48,0xcc,0x88}},
+ {{0xe1,0xb8,0xa4}, {0x48,0xcc,0xa3}},
+ {{0xe1,0xb8,0xa8}, {0x48,0xcc,0xa7}},
+ {{0xe1,0xb8,0xaa}, {0x48,0xcc,0xae}},
+ {{0xc3,0x8c}, {0x49,0xcc,0x80}},
+ {{0xc3,0x8d}, {0x49,0xcc,0x81}},
+ {{0xc3,0x8e}, {0x49,0xcc,0x82}},
+ {{0xc4,0xa8}, {0x49,0xcc,0x83}},
+ {{0xc4,0xaa}, {0x49,0xcc,0x84}},
+ {{0xc4,0xac}, {0x49,0xcc,0x86}},
+ {{0xc4,0xb0}, {0x49,0xcc,0x87}},
+ {{0xc3,0x8f}, {0x49,0xcc,0x88}},
+ {{0xe1,0xb8,0xae}, {0x49,0xcc,0x88,0xcc,0x81}},
+ {{0xe1,0xbb,0x88}, {0x49,0xcc,0x89}},
+ {{0xc7,0x8f}, {0x49,0xcc,0x8c}},
+ {{0xc8,0x88}, {0x49,0xcc,0x8f}},
+ {{0xc8,0x8a}, {0x49,0xcc,0x91}},
+ {{0xe1,0xbb,0x8a}, {0x49,0xcc,0xa3}},
+ {{0xc4,0xae}, {0x49,0xcc,0xa8}},
+ {{0xe1,0xb8,0xac}, {0x49,0xcc,0xb0}},
+ {{0xc4,0xb4}, {0x4a,0xcc,0x82}},
+ {{0xe1,0xb8,0xb0}, {0x4b,0xcc,0x81}},
+ {{0xc7,0xa8}, {0x4b,0xcc,0x8c}},
+ {{0xe1,0xb8,0xb2}, {0x4b,0xcc,0xa3}},
+ {{0xc4,0xb6}, {0x4b,0xcc,0xa7}},
+ {{0xe1,0xb8,0xb4}, {0x4b,0xcc,0xb1}},
+ {{0xc4,0xb9}, {0x4c,0xcc,0x81}},
+ {{0xc4,0xbd}, {0x4c,0xcc,0x8c}},
+ {{0xe1,0xb8,0xb6}, {0x4c,0xcc,0xa3}},
+ {{0xe1,0xb8,0xb8}, {0x4c,0xcc,0xa3,0xcc,0x84}},
+ {{0xc4,0xbb}, {0x4c,0xcc,0xa7}},
+ {{0xe1,0xb8,0xbc}, {0x4c,0xcc,0xad}},
+ {{0xe1,0xb8,0xba}, {0x4c,0xcc,0xb1}},
+ {{0xe1,0xb8,0xbe}, {0x4d,0xcc,0x81}},
+ {{0xe1,0xb9,0x80}, {0x4d,0xcc,0x87}},
+ {{0xe1,0xb9,0x82}, {0x4d,0xcc,0xa3}},
+ {{0xc5,0x83}, {0x4e,0xcc,0x81}},
+ {{0xc3,0x91}, {0x4e,0xcc,0x83}},
+ {{0xe1,0xb9,0x84}, {0x4e,0xcc,0x87}},
+ {{0xc5,0x87}, {0x4e,0xcc,0x8c}},
+ {{0xe1,0xb9,0x86}, {0x4e,0xcc,0xa3}},
+ {{0xc5,0x85}, {0x4e,0xcc,0xa7}},
+ {{0xe1,0xb9,0x8a}, {0x4e,0xcc,0xad}},
+ {{0xe1,0xb9,0x88}, {0x4e,0xcc,0xb1}},
+ {{0xc3,0x92}, {0x4f,0xcc,0x80}},
+ {{0xc3,0x93}, {0x4f,0xcc,0x81}},
+ {{0xc3,0x94}, {0x4f,0xcc,0x82}},
+ {{0xe1,0xbb,0x92}, {0x4f,0xcc,0x82,0xcc,0x80}},
+ {{0xe1,0xbb,0x90}, {0x4f,0xcc,0x82,0xcc,0x81}},
+ {{0xe1,0xbb,0x96}, {0x4f,0xcc,0x82,0xcc,0x83}},
+ {{0xe1,0xbb,0x94}, {0x4f,0xcc,0x82,0xcc,0x89}},
+ {{0xc3,0x95}, {0x4f,0xcc,0x83}},
+ {{0xe1,0xb9,0x8c}, {0x4f,0xcc,0x83,0xcc,0x81}},
+ {{0xe1,0xb9,0x8e}, {0x4f,0xcc,0x83,0xcc,0x88}},
+ {{0xc5,0x8c}, {0x4f,0xcc,0x84}},
+ {{0xe1,0xb9,0x90}, {0x4f,0xcc,0x84,0xcc,0x80}},
+ {{0xe1,0xb9,0x92}, {0x4f,0xcc,0x84,0xcc,0x81}},
+ {{0xc5,0x8e}, {0x4f,0xcc,0x86}},
+ {{0xc3,0x96}, {0x4f,0xcc,0x88}},
+ {{0xe1,0xbb,0x8e}, {0x4f,0xcc,0x89}},
+ {{0xc5,0x90}, {0x4f,0xcc,0x8b}},
+ {{0xc7,0x91}, {0x4f,0xcc,0x8c}},
+ {{0xc8,0x8c}, {0x4f,0xcc,0x8f}},
+ {{0xc8,0x8e}, {0x4f,0xcc,0x91}},
+ {{0xc6,0xa0}, {0x4f,0xcc,0x9b}},
+ {{0xe1,0xbb,0x9c}, {0x4f,0xcc,0x9b,0xcc,0x80}},
+ {{0xe1,0xbb,0x9a}, {0x4f,0xcc,0x9b,0xcc,0x81}},
+ {{0xe1,0xbb,0xa0}, {0x4f,0xcc,0x9b,0xcc,0x83}},
+ {{0xe1,0xbb,0x9e}, {0x4f,0xcc,0x9b,0xcc,0x89}},
+ {{0xe1,0xbb,0xa2}, {0x4f,0xcc,0x9b,0xcc,0xa3}},
+ {{0xe1,0xbb,0x8c}, {0x4f,0xcc,0xa3}},
+ {{0xe1,0xbb,0x98}, {0x4f,0xcc,0xa3,0xcc,0x82}},
+ {{0xc7,0xaa}, {0x4f,0xcc,0xa8}},
+ {{0xc7,0xac}, {0x4f,0xcc,0xa8,0xcc,0x84}},
+ {{0xe1,0xb9,0x94}, {0x50,0xcc,0x81}},
+ {{0xe1,0xb9,0x96}, {0x50,0xcc,0x87}},
+ {{0xc5,0x94}, {0x52,0xcc,0x81}},
+ {{0xe1,0xb9,0x98}, {0x52,0xcc,0x87}},
+ {{0xc5,0x98}, {0x52,0xcc,0x8c}},
+ {{0xc8,0x90}, {0x52,0xcc,0x8f}},
+ {{0xc8,0x92}, {0x52,0xcc,0x91}},
+ {{0xe1,0xb9,0x9a}, {0x52,0xcc,0xa3}},
+ {{0xe1,0xb9,0x9c}, {0x52,0xcc,0xa3,0xcc,0x84}},
+ {{0xc5,0x96}, {0x52,0xcc,0xa7}},
+ {{0xe1,0xb9,0x9e}, {0x52,0xcc,0xb1}},
+ {{0xc5,0x9a}, {0x53,0xcc,0x81}},
+ {{0xe1,0xb9,0xa4}, {0x53,0xcc,0x81,0xcc,0x87}},
+ {{0xc5,0x9c}, {0x53,0xcc,0x82}},
+ {{0xe1,0xb9,0xa0}, {0x53,0xcc,0x87}},
+ {{0xc5,0xa0}, {0x53,0xcc,0x8c}},
+ {{0xe1,0xb9,0xa6}, {0x53,0xcc,0x8c,0xcc,0x87}},
+ {{0xe1,0xb9,0xa2}, {0x53,0xcc,0xa3}},
+ {{0xe1,0xb9,0xa8}, {0x53,0xcc,0xa3,0xcc,0x87}},
+ {{0xc5,0x9e}, {0x53,0xcc,0xa7}},
+ {{0xe1,0xb9,0xaa}, {0x54,0xcc,0x87}},
+ {{0xc5,0xa4}, {0x54,0xcc,0x8c}},
+ {{0xe1,0xb9,0xac}, {0x54,0xcc,0xa3}},
+ {{0xc5,0xa2}, {0x54,0xcc,0xa7}},
+ {{0xe1,0xb9,0xb0}, {0x54,0xcc,0xad}},
+ {{0xe1,0xb9,0xae}, {0x54,0xcc,0xb1}},
+ {{0xc3,0x99}, {0x55,0xcc,0x80}},
+ {{0xc3,0x9a}, {0x55,0xcc,0x81}},
+ {{0xc3,0x9b}, {0x55,0xcc,0x82}},
+ {{0xc5,0xa8}, {0x55,0xcc,0x83}},
+ {{0xe1,0xb9,0xb8}, {0x55,0xcc,0x83,0xcc,0x81}},
+ {{0xc5,0xaa}, {0x55,0xcc,0x84}},
+ {{0xe1,0xb9,0xba}, {0x55,0xcc,0x84,0xcc,0x88}},
+ {{0xc5,0xac}, {0x55,0xcc,0x86}},
+ {{0xc3,0x9c}, {0x55,0xcc,0x88}},
+ {{0xc7,0x9b}, {0x55,0xcc,0x88,0xcc,0x80}},
+ {{0xc7,0x97}, {0x55,0xcc,0x88,0xcc,0x81}},
+ {{0xc7,0x95}, {0x55,0xcc,0x88,0xcc,0x84}},
+ {{0xc7,0x99}, {0x55,0xcc,0x88,0xcc,0x8c}},
+ {{0xe1,0xbb,0xa6}, {0x55,0xcc,0x89}},
+ {{0xc5,0xae}, {0x55,0xcc,0x8a}},
+ {{0xc5,0xb0}, {0x55,0xcc,0x8b}},
+ {{0xc7,0x93}, {0x55,0xcc,0x8c}},
+ {{0xc8,0x94}, {0x55,0xcc,0x8f}},
+ {{0xc8,0x96}, {0x55,0xcc,0x91}},
+ {{0xc6,0xaf}, {0x55,0xcc,0x9b}},
+ {{0xe1,0xbb,0xaa}, {0x55,0xcc,0x9b,0xcc,0x80}},
+ {{0xe1,0xbb,0xa8}, {0x55,0xcc,0x9b,0xcc,0x81}},
+ {{0xe1,0xbb,0xae}, {0x55,0xcc,0x9b,0xcc,0x83}},
+ {{0xe1,0xbb,0xac}, {0x55,0xcc,0x9b,0xcc,0x89}},
+ {{0xe1,0xbb,0xb0}, {0x55,0xcc,0x9b,0xcc,0xa3}},
+ {{0xe1,0xbb,0xa4}, {0x55,0xcc,0xa3}},
+ {{0xe1,0xb9,0xb2}, {0x55,0xcc,0xa4}},
+ {{0xc5,0xb2}, {0x55,0xcc,0xa8}},
+ {{0xe1,0xb9,0xb6}, {0x55,0xcc,0xad}},
+ {{0xe1,0xb9,0xb4}, {0x55,0xcc,0xb0}},
+ {{0xe1,0xb9,0xbc}, {0x56,0xcc,0x83}},
+ {{0xe1,0xb9,0xbe}, {0x56,0xcc,0xa3}},
+ {{0xe1,0xba,0x80}, {0x57,0xcc,0x80}},
+ {{0xe1,0xba,0x82}, {0x57,0xcc,0x81}},
+ {{0xc5,0xb4}, {0x57,0xcc,0x82}},
+ {{0xe1,0xba,0x86}, {0x57,0xcc,0x87}},
+ {{0xe1,0xba,0x84}, {0x57,0xcc,0x88}},
+ {{0xe1,0xba,0x88}, {0x57,0xcc,0xa3}},
+ {{0xe1,0xba,0x8a}, {0x58,0xcc,0x87}},
+ {{0xe1,0xba,0x8c}, {0x58,0xcc,0x88}},
+ {{0xe1,0xbb,0xb2}, {0x59,0xcc,0x80}},
+ {{0xc3,0x9d}, {0x59,0xcc,0x81}},
+ {{0xc5,0xb6}, {0x59,0xcc,0x82}},
+ {{0xe1,0xbb,0xb8}, {0x59,0xcc,0x83}},
+ {{0xe1,0xba,0x8e}, {0x59,0xcc,0x87}},
+ {{0xc5,0xb8}, {0x59,0xcc,0x88}},
+ {{0xe1,0xbb,0xb6}, {0x59,0xcc,0x89}},
+ {{0xe1,0xbb,0xb4}, {0x59,0xcc,0xa3}},
+ {{0xc5,0xb9}, {0x5a,0xcc,0x81}},
+ {{0xe1,0xba,0x90}, {0x5a,0xcc,0x82}},
+ {{0xc5,0xbb}, {0x5a,0xcc,0x87}},
+ {{0xc5,0xbd}, {0x5a,0xcc,0x8c}},
+ {{0xe1,0xba,0x92}, {0x5a,0xcc,0xa3}},
+ {{0xe1,0xba,0x94}, {0x5a,0xcc,0xb1}},
+ {{0xe1,0xbf,0xaf}, {0x60}},
+ {{0xc3,0xa0}, {0x61,0xcc,0x80}},
+ {{0xc3,0xa1}, {0x61,0xcc,0x81}},
+ {{0xc3,0xa2}, {0x61,0xcc,0x82}},
+ {{0xe1,0xba,0xa7}, {0x61,0xcc,0x82,0xcc,0x80}},
+ {{0xe1,0xba,0xa5}, {0x61,0xcc,0x82,0xcc,0x81}},
+ {{0xe1,0xba,0xab}, {0x61,0xcc,0x82,0xcc,0x83}},
+ {{0xe1,0xba,0xa9}, {0x61,0xcc,0x82,0xcc,0x89}},
+ {{0xc3,0xa3}, {0x61,0xcc,0x83}},
+ {{0xc4,0x81}, {0x61,0xcc,0x84}},
+ {{0xc4,0x83}, {0x61,0xcc,0x86}},
+ {{0xe1,0xba,0xb1}, {0x61,0xcc,0x86,0xcc,0x80}},
+ {{0xe1,0xba,0xaf}, {0x61,0xcc,0x86,0xcc,0x81}},
+ {{0xe1,0xba,0xb5}, {0x61,0xcc,0x86,0xcc,0x83}},
+ {{0xe1,0xba,0xb3}, {0x61,0xcc,0x86,0xcc,0x89}},
+ {{0xc7,0xa1}, {0x61,0xcc,0x87,0xcc,0x84}},
+ {{0xc3,0xa4}, {0x61,0xcc,0x88}},
+ {{0xc7,0x9f}, {0x61,0xcc,0x88,0xcc,0x84}},
+ {{0xe1,0xba,0xa3}, {0x61,0xcc,0x89}},
+ {{0xc3,0xa5}, {0x61,0xcc,0x8a}},
+ {{0xc7,0xbb}, {0x61,0xcc,0x8a,0xcc,0x81}},
+ {{0xc7,0x8e}, {0x61,0xcc,0x8c}},
+ {{0xc8,0x81}, {0x61,0xcc,0x8f}},
+ {{0xc8,0x83}, {0x61,0xcc,0x91}},
+ {{0xe1,0xba,0xa1}, {0x61,0xcc,0xa3}},
+ {{0xe1,0xba,0xad}, {0x61,0xcc,0xa3,0xcc,0x82}},
+ {{0xe1,0xba,0xb7}, {0x61,0xcc,0xa3,0xcc,0x86}},
+ {{0xe1,0xb8,0x81}, {0x61,0xcc,0xa5}},
+ {{0xc4,0x85}, {0x61,0xcc,0xa8}},
+ {{0xe1,0xb8,0x83}, {0x62,0xcc,0x87}},
+ {{0xe1,0xb8,0x85}, {0x62,0xcc,0xa3}},
+ {{0xe1,0xb8,0x87}, {0x62,0xcc,0xb1}},
+ {{0xc4,0x87}, {0x63,0xcc,0x81}},
+ {{0xc4,0x89}, {0x63,0xcc,0x82}},
+ {{0xc4,0x8b}, {0x63,0xcc,0x87}},
+ {{0xc4,0x8d}, {0x63,0xcc,0x8c}},
+ {{0xc3,0xa7}, {0x63,0xcc,0xa7}},
+ {{0xe1,0xb8,0x89}, {0x63,0xcc,0xa7,0xcc,0x81}},
+ {{0xe1,0xb8,0x8b}, {0x64,0xcc,0x87}},
+ {{0xc4,0x8f}, {0x64,0xcc,0x8c}},
+ {{0xe1,0xb8,0x8d}, {0x64,0xcc,0xa3}},
+ {{0xe1,0xb8,0x91}, {0x64,0xcc,0xa7}},
+ {{0xe1,0xb8,0x93}, {0x64,0xcc,0xad}},
+ {{0xe1,0xb8,0x8f}, {0x64,0xcc,0xb1}},
+ {{0xc3,0xa8}, {0x65,0xcc,0x80}},
+ {{0xc3,0xa9}, {0x65,0xcc,0x81}},
+ {{0xc3,0xaa}, {0x65,0xcc,0x82}},
+ {{0xe1,0xbb,0x81}, {0x65,0xcc,0x82,0xcc,0x80}},
+ {{0xe1,0xba,0xbf}, {0x65,0xcc,0x82,0xcc,0x81}},
+ {{0xe1,0xbb,0x85}, {0x65,0xcc,0x82,0xcc,0x83}},
+ {{0xe1,0xbb,0x83}, {0x65,0xcc,0x82,0xcc,0x89}},
+ {{0xe1,0xba,0xbd}, {0x65,0xcc,0x83}},
+ {{0xc4,0x93}, {0x65,0xcc,0x84}},
+ {{0xe1,0xb8,0x95}, {0x65,0xcc,0x84,0xcc,0x80}},
+ {{0xe1,0xb8,0x97}, {0x65,0xcc,0x84,0xcc,0x81}},
+ {{0xc4,0x95}, {0x65,0xcc,0x86}},
+ {{0xc4,0x97}, {0x65,0xcc,0x87}},
+ {{0xc3,0xab}, {0x65,0xcc,0x88}},
+ {{0xe1,0xba,0xbb}, {0x65,0xcc,0x89}},
+ {{0xc4,0x9b}, {0x65,0xcc,0x8c}},
+ {{0xc8,0x85}, {0x65,0xcc,0x8f}},
+ {{0xc8,0x87}, {0x65,0xcc,0x91}},
+ {{0xe1,0xba,0xb9}, {0x65,0xcc,0xa3}},
+ {{0xe1,0xbb,0x87}, {0x65,0xcc,0xa3,0xcc,0x82}},
+ {{0xe1,0xb8,0x9d}, {0x65,0xcc,0xa7,0xcc,0x86}},
+ {{0xc4,0x99}, {0x65,0xcc,0xa8}},
+ {{0xe1,0xb8,0x99}, {0x65,0xcc,0xad}},
+ {{0xe1,0xb8,0x9b}, {0x65,0xcc,0xb0}},
+ {{0xe1,0xb8,0x9f}, {0x66,0xcc,0x87}},
+ {{0xc7,0xb5}, {0x67,0xcc,0x81}},
+ {{0xc4,0x9d}, {0x67,0xcc,0x82}},
+ {{0xe1,0xb8,0xa1}, {0x67,0xcc,0x84}},
+ {{0xc4,0x9f}, {0x67,0xcc,0x86}},
+ {{0xc4,0xa1}, {0x67,0xcc,0x87}},
+ {{0xc7,0xa7}, {0x67,0xcc,0x8c}},
+ {{0xc4,0xa3}, {0x67,0xcc,0xa7}},
+ {{0xc4,0xa5}, {0x68,0xcc,0x82}},
+ {{0xe1,0xb8,0xa3}, {0x68,0xcc,0x87}},
+ {{0xe1,0xb8,0xa7}, {0x68,0xcc,0x88}},
+ {{0xe1,0xb8,0xa5}, {0x68,0xcc,0xa3}},
+ {{0xe1,0xb8,0xa9}, {0x68,0xcc,0xa7}},
+ {{0xe1,0xb8,0xab}, {0x68,0xcc,0xae}},
+ {{0xe1,0xba,0x96}, {0x68,0xcc,0xb1}},
+ {{0xc3,0xac}, {0x69,0xcc,0x80}},
+ {{0xc3,0xad}, {0x69,0xcc,0x81}},
+ {{0xc3,0xae}, {0x69,0xcc,0x82}},
+ {{0xc4,0xa9}, {0x69,0xcc,0x83}},
+ {{0xc4,0xab}, {0x69,0xcc,0x84}},
+ {{0xc4,0xad}, {0x69,0xcc,0x86}},
+ {{0xc3,0xaf}, {0x69,0xcc,0x88}},
+ {{0xe1,0xb8,0xaf}, {0x69,0xcc,0x88,0xcc,0x81}},
+ {{0xe1,0xbb,0x89}, {0x69,0xcc,0x89}},
+ {{0xc7,0x90}, {0x69,0xcc,0x8c}},
+ {{0xc8,0x89}, {0x69,0xcc,0x8f}},
+ {{0xc8,0x8b}, {0x69,0xcc,0x91}},
+ {{0xe1,0xbb,0x8b}, {0x69,0xcc,0xa3}},
+ {{0xc4,0xaf}, {0x69,0xcc,0xa8}},
+ {{0xe1,0xb8,0xad}, {0x69,0xcc,0xb0}},
+ {{0xc4,0xb5}, {0x6a,0xcc,0x82}},
+ {{0xc7,0xb0}, {0x6a,0xcc,0x8c}},
+ {{0xe1,0xb8,0xb1}, {0x6b,0xcc,0x81}},
+ {{0xc7,0xa9}, {0x6b,0xcc,0x8c}},
+ {{0xe1,0xb8,0xb3}, {0x6b,0xcc,0xa3}},
+ {{0xc4,0xb7}, {0x6b,0xcc,0xa7}},
+ {{0xe1,0xb8,0xb5}, {0x6b,0xcc,0xb1}},
+ {{0xc4,0xba}, {0x6c,0xcc,0x81}},
+ {{0xc4,0xbe}, {0x6c,0xcc,0x8c}},
+ {{0xe1,0xb8,0xb7}, {0x6c,0xcc,0xa3}},
+ {{0xe1,0xb8,0xb9}, {0x6c,0xcc,0xa3,0xcc,0x84}},
+ {{0xc4,0xbc}, {0x6c,0xcc,0xa7}},
+ {{0xe1,0xb8,0xbd}, {0x6c,0xcc,0xad}},
+ {{0xe1,0xb8,0xbb}, {0x6c,0xcc,0xb1}},
+ {{0xe1,0xb8,0xbf}, {0x6d,0xcc,0x81}},
+ {{0xe1,0xb9,0x81}, {0x6d,0xcc,0x87}},
+ {{0xe1,0xb9,0x83}, {0x6d,0xcc,0xa3}},
+ {{0xc5,0x84}, {0x6e,0xcc,0x81}},
+ {{0xc3,0xb1}, {0x6e,0xcc,0x83}},
+ {{0xe1,0xb9,0x85}, {0x6e,0xcc,0x87}},
+ {{0xc5,0x88}, {0x6e,0xcc,0x8c}},
+ {{0xe1,0xb9,0x87}, {0x6e,0xcc,0xa3}},
+ {{0xc5,0x86}, {0x6e,0xcc,0xa7}},
+ {{0xe1,0xb9,0x8b}, {0x6e,0xcc,0xad}},
+ {{0xe1,0xb9,0x89}, {0x6e,0xcc,0xb1}},
+ {{0xc3,0xb2}, {0x6f,0xcc,0x80}},
+ {{0xc3,0xb3}, {0x6f,0xcc,0x81}},
+ {{0xc3,0xb4}, {0x6f,0xcc,0x82}},
+ {{0xe1,0xbb,0x93}, {0x6f,0xcc,0x82,0xcc,0x80}},
+ {{0xe1,0xbb,0x91}, {0x6f,0xcc,0x82,0xcc,0x81}},
+ {{0xe1,0xbb,0x97}, {0x6f,0xcc,0x82,0xcc,0x83}},
+ {{0xe1,0xbb,0x95}, {0x6f,0xcc,0x82,0xcc,0x89}},
+ {{0xc3,0xb5}, {0x6f,0xcc,0x83}},
+ {{0xe1,0xb9,0x8d}, {0x6f,0xcc,0x83,0xcc,0x81}},
+ {{0xe1,0xb9,0x8f}, {0x6f,0xcc,0x83,0xcc,0x88}},
+ {{0xc5,0x8d}, {0x6f,0xcc,0x84}},
+ {{0xe1,0xb9,0x91}, {0x6f,0xcc,0x84,0xcc,0x80}},
+ {{0xe1,0xb9,0x93}, {0x6f,0xcc,0x84,0xcc,0x81}},
+ {{0xc5,0x8f}, {0x6f,0xcc,0x86}},
+ {{0xc3,0xb6}, {0x6f,0xcc,0x88}},
+ {{0xe1,0xbb,0x8f}, {0x6f,0xcc,0x89}},
+ {{0xc5,0x91}, {0x6f,0xcc,0x8b}},
+ {{0xc7,0x92}, {0x6f,0xcc,0x8c}},
+ {{0xc8,0x8d}, {0x6f,0xcc,0x8f}},
+ {{0xc8,0x8f}, {0x6f,0xcc,0x91}},
+ {{0xc6,0xa1}, {0x6f,0xcc,0x9b}},
+ {{0xe1,0xbb,0x9d}, {0x6f,0xcc,0x9b,0xcc,0x80}},
+ {{0xe1,0xbb,0x9b}, {0x6f,0xcc,0x9b,0xcc,0x81}},
+ {{0xe1,0xbb,0xa1}, {0x6f,0xcc,0x9b,0xcc,0x83}},
+ {{0xe1,0xbb,0x9f}, {0x6f,0xcc,0x9b,0xcc,0x89}},
+ {{0xe1,0xbb,0xa3}, {0x6f,0xcc,0x9b,0xcc,0xa3}},
+ {{0xe1,0xbb,0x8d}, {0x6f,0xcc,0xa3}},
+ {{0xe1,0xbb,0x99}, {0x6f,0xcc,0xa3,0xcc,0x82}},
+ {{0xc7,0xab}, {0x6f,0xcc,0xa8}},
+ {{0xc7,0xad}, {0x6f,0xcc,0xa8,0xcc,0x84}},
+ {{0xe1,0xb9,0x95}, {0x70,0xcc,0x81}},
+ {{0xe1,0xb9,0x97}, {0x70,0xcc,0x87}},
+ {{0xc5,0x95}, {0x72,0xcc,0x81}},
+ {{0xe1,0xb9,0x99}, {0x72,0xcc,0x87}},
+ {{0xc5,0x99}, {0x72,0xcc,0x8c}},
+ {{0xc8,0x91}, {0x72,0xcc,0x8f}},
+ {{0xc8,0x93}, {0x72,0xcc,0x91}},
+ {{0xe1,0xb9,0x9b}, {0x72,0xcc,0xa3}},
+ {{0xe1,0xb9,0x9d}, {0x72,0xcc,0xa3,0xcc,0x84}},
+ {{0xc5,0x97}, {0x72,0xcc,0xa7}},
+ {{0xe1,0xb9,0x9f}, {0x72,0xcc,0xb1}},
+ {{0xc5,0x9b}, {0x73,0xcc,0x81}},
+ {{0xe1,0xb9,0xa5}, {0x73,0xcc,0x81,0xcc,0x87}},
+ {{0xc5,0x9d}, {0x73,0xcc,0x82}},
+ {{0xe1,0xb9,0xa1}, {0x73,0xcc,0x87}},
+ {{0xc5,0xa1}, {0x73,0xcc,0x8c}},
+ {{0xe1,0xb9,0xa7}, {0x73,0xcc,0x8c,0xcc,0x87}},
+ {{0xe1,0xb9,0xa3}, {0x73,0xcc,0xa3}},
+ {{0xe1,0xb9,0xa9}, {0x73,0xcc,0xa3,0xcc,0x87}},
+ {{0xc5,0x9f}, {0x73,0xcc,0xa7}},
+ {{0xe1,0xb9,0xab}, {0x74,0xcc,0x87}},
+ {{0xe1,0xba,0x97}, {0x74,0xcc,0x88}},
+ {{0xc5,0xa5}, {0x74,0xcc,0x8c}},
+ {{0xe1,0xb9,0xad}, {0x74,0xcc,0xa3}},
+ {{0xc5,0xa3}, {0x74,0xcc,0xa7}},
+ {{0xe1,0xb9,0xb1}, {0x74,0xcc,0xad}},
+ {{0xe1,0xb9,0xaf}, {0x74,0xcc,0xb1}},
+ {{0xc3,0xb9}, {0x75,0xcc,0x80}},
+ {{0xc3,0xba}, {0x75,0xcc,0x81}},
+ {{0xc3,0xbb}, {0x75,0xcc,0x82}},
+ {{0xc5,0xa9}, {0x75,0xcc,0x83}},
+ {{0xe1,0xb9,0xb9}, {0x75,0xcc,0x83,0xcc,0x81}},
+ {{0xc5,0xab}, {0x75,0xcc,0x84}},
+ {{0xe1,0xb9,0xbb}, {0x75,0xcc,0x84,0xcc,0x88}},
+ {{0xc5,0xad}, {0x75,0xcc,0x86}},
+ {{0xc3,0xbc}, {0x75,0xcc,0x88}},
+ {{0xc7,0x9c}, {0x75,0xcc,0x88,0xcc,0x80}},
+ {{0xc7,0x98}, {0x75,0xcc,0x88,0xcc,0x81}},
+ {{0xc7,0x96}, {0x75,0xcc,0x88,0xcc,0x84}},
+ {{0xc7,0x9a}, {0x75,0xcc,0x88,0xcc,0x8c}},
+ {{0xe1,0xbb,0xa7}, {0x75,0xcc,0x89}},
+ {{0xc5,0xaf}, {0x75,0xcc,0x8a}},
+ {{0xc5,0xb1}, {0x75,0xcc,0x8b}},
+ {{0xc7,0x94}, {0x75,0xcc,0x8c}},
+ {{0xc8,0x95}, {0x75,0xcc,0x8f}},
+ {{0xc8,0x97}, {0x75,0xcc,0x91}},
+ {{0xc6,0xb0}, {0x75,0xcc,0x9b}},
+ {{0xe1,0xbb,0xab}, {0x75,0xcc,0x9b,0xcc,0x80}},
+ {{0xe1,0xbb,0xa9}, {0x75,0xcc,0x9b,0xcc,0x81}},
+ {{0xe1,0xbb,0xaf}, {0x75,0xcc,0x9b,0xcc,0x83}},
+ {{0xe1,0xbb,0xad}, {0x75,0xcc,0x9b,0xcc,0x89}},
+ {{0xe1,0xbb,0xb1}, {0x75,0xcc,0x9b,0xcc,0xa3}},
+ {{0xe1,0xbb,0xa5}, {0x75,0xcc,0xa3}},
+ {{0xe1,0xb9,0xb3}, {0x75,0xcc,0xa4}},
+ {{0xc5,0xb3}, {0x75,0xcc,0xa8}},
+ {{0xe1,0xb9,0xb7}, {0x75,0xcc,0xad}},
+ {{0xe1,0xb9,0xb5}, {0x75,0xcc,0xb0}},
+ {{0xe1,0xb9,0xbd}, {0x76,0xcc,0x83}},
+ {{0xe1,0xb9,0xbf}, {0x76,0xcc,0xa3}},
+ {{0xe1,0xba,0x81}, {0x77,0xcc,0x80}},
+ {{0xe1,0xba,0x83}, {0x77,0xcc,0x81}},
+ {{0xc5,0xb5}, {0x77,0xcc,0x82}},
+ {{0xe1,0xba,0x87}, {0x77,0xcc,0x87}},
+ {{0xe1,0xba,0x85}, {0x77,0xcc,0x88}},
+ {{0xe1,0xba,0x98}, {0x77,0xcc,0x8a}},
+ {{0xe1,0xba,0x89}, {0x77,0xcc,0xa3}},
+ {{0xe1,0xba,0x8b}, {0x78,0xcc,0x87}},
+ {{0xe1,0xba,0x8d}, {0x78,0xcc,0x88}},
+ {{0xe1,0xbb,0xb3}, {0x79,0xcc,0x80}},
+ {{0xc3,0xbd}, {0x79,0xcc,0x81}},
+ {{0xc5,0xb7}, {0x79,0xcc,0x82}},
+ {{0xe1,0xbb,0xb9}, {0x79,0xcc,0x83}},
+ {{0xe1,0xba,0x8f}, {0x79,0xcc,0x87}},
+ {{0xc3,0xbf}, {0x79,0xcc,0x88}},
+ {{0xe1,0xbb,0xb7}, {0x79,0xcc,0x89}},
+ {{0xe1,0xba,0x99}, {0x79,0xcc,0x8a}},
+ {{0xe1,0xbb,0xb5}, {0x79,0xcc,0xa3}},
+ {{0xc5,0xba}, {0x7a,0xcc,0x81}},
+ {{0xe1,0xba,0x91}, {0x7a,0xcc,0x82}},
+ {{0xc5,0xbc}, {0x7a,0xcc,0x87}},
+ {{0xc5,0xbe}, {0x7a,0xcc,0x8c}},
+ {{0xe1,0xba,0x93}, {0x7a,0xcc,0xa3}},
+ {{0xe1,0xba,0x95}, {0x7a,0xcc,0xb1}},
+ {{0xe1,0xbf,0xad}, {0xc2,0xa8,0xcc,0x80}},
+ {{0xe1,0xbf,0xae}, {0xc2,0xa8,0xcc,0x81}},
+ {{0xce,0x85}, {0xc2,0xa8,0xcc,0x8d}},
+ {{0xe1,0xbf,0x81}, {0xc2,0xa8,0xcd,0x82}},
+ {{0xe1,0xbf,0xbd}, {0xc2,0xb4}},
+ {{0xce,0x87}, {0xc2,0xb7}},
+ {{0xd3,0x94}, {0xc3,0x86}},
+ {{0xc7,0xbc}, {0xc3,0x86,0xcc,0x81}},
+ {{0xc7,0xa2}, {0xc3,0x86,0xcc,0x84}},
+ {{0xc7,0xbe}, {0xc3,0x98,0xcc,0x81}},
+ {{0xd3,0x95}, {0xc3,0xa6}},
+ {{0xc7,0xbd}, {0xc3,0xa6,0xcc,0x81}},
+ {{0xc7,0xa3}, {0xc3,0xa6,0xcc,0x84}},
+ {{0xc7,0xbf}, {0xc3,0xb8,0xcc,0x81}},
+ {{0xe1,0xba,0x9b}, {0xc5,0xbf,0xcc,0x87}},
+ {{0xd3,0x98}, {0xc6,0x8f}},
+ {{0xd3,0x9a}, {0xc6,0x8f,0xcc,0x88}},
+ {{0xd3,0xa8}, {0xc6,0x9f}},
+ {{0xd3,0xaa}, {0xc6,0x9f,0xcc,0x88}},
+ {{0xd3,0xa0}, {0xc6,0xb7}},
+ {{0xc7,0xae}, {0xc6,0xb7,0xcc,0x8c}},
+ {{0xd3,0x99}, {0xc9,0x99}},
+ {{0xd3,0x9b}, {0xc9,0x99,0xcc,0x88}},
+ {{0xd3,0xa9}, {0xc9,0xb5}},
+ {{0xd3,0xab}, {0xc9,0xb5,0xcc,0x88}},
+ {{0xd3,0xa1}, {0xca,0x92}},
+ {{0xc7,0xaf}, {0xca,0x92,0xcc,0x8c}},
+ {{0xcd,0xb4}, {0xca,0xb9}},
+ {{0xcd,0x80}, {0xcc,0x80}},
+ {{0xcd,0x81}, {0xcc,0x81}},
+ {{0xcc,0x90}, {0xcc,0x86,0xcc,0x87}},
+ {{0xcd,0x84}, {0xcc,0x88,0xcc,0x8d}},
+ {{0xcd,0x83}, {0xcc,0x93}},
+ {{0xe1,0xbe,0xba}, {0xce,0x91,0xcc,0x80}},
+ {{0xe1,0xbe,0xbb}, {0xce,0x91,0xcc,0x81}},
+ {{0xe1,0xbe,0xb9}, {0xce,0x91,0xcc,0x84}},
+ {{0xe1,0xbe,0xb8}, {0xce,0x91,0xcc,0x86}},
+ {{0xce,0x86}, {0xce,0x91,0xcc,0x8d}},
+ {{0xe1,0xbc,0x88}, {0xce,0x91,0xcc,0x93}},
+ {{0xe1,0xbc,0x8a}, {0xce,0x91,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbc,0x8c}, {0xce,0x91,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbc,0x8e}, {0xce,0x91,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbc,0x89}, {0xce,0x91,0xcc,0x94}},
+ {{0xe1,0xbc,0x8b}, {0xce,0x91,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbc,0x8d}, {0xce,0x91,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbc,0x8f}, {0xce,0x91,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbe,0xbc}, {0xce,0x91,0xcd,0x85}},
+ {{0xe1,0xbe,0x88}, {0xce,0x91,0xcd,0x85,0xcc,0x93}},
+ {{0xe1,0xbe,0x8a}, {0xce,0x91,0xcd,0x85,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbe,0x8c}, {0xce,0x91,0xcd,0x85,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbe,0x8e}, {0xce,0x91,0xcd,0x85,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbe,0x89}, {0xce,0x91,0xcd,0x85,0xcc,0x94}},
+ {{0xe1,0xbe,0x8b}, {0xce,0x91,0xcd,0x85,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbe,0x8d}, {0xce,0x91,0xcd,0x85,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbe,0x8f}, {0xce,0x91,0xcd,0x85,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbf,0x88}, {0xce,0x95,0xcc,0x80}},
+ {{0xe1,0xbf,0x89}, {0xce,0x95,0xcc,0x81}},
+ {{0xce,0x88}, {0xce,0x95,0xcc,0x8d}},
+ {{0xe1,0xbc,0x98}, {0xce,0x95,0xcc,0x93}},
+ {{0xe1,0xbc,0x9a}, {0xce,0x95,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbc,0x9c}, {0xce,0x95,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbc,0x99}, {0xce,0x95,0xcc,0x94}},
+ {{0xe1,0xbc,0x9b}, {0xce,0x95,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbc,0x9d}, {0xce,0x95,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbf,0x8a}, {0xce,0x97,0xcc,0x80}},
+ {{0xe1,0xbf,0x8b}, {0xce,0x97,0xcc,0x81}},
+ {{0xce,0x89}, {0xce,0x97,0xcc,0x8d}},
+ {{0xe1,0xbc,0xa8}, {0xce,0x97,0xcc,0x93}},
+ {{0xe1,0xbc,0xaa}, {0xce,0x97,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbc,0xac}, {0xce,0x97,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbc,0xae}, {0xce,0x97,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbc,0xa9}, {0xce,0x97,0xcc,0x94}},
+ {{0xe1,0xbc,0xab}, {0xce,0x97,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbc,0xad}, {0xce,0x97,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbc,0xaf}, {0xce,0x97,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbf,0x8c}, {0xce,0x97,0xcd,0x85}},
+ {{0xe1,0xbe,0x98}, {0xce,0x97,0xcd,0x85,0xcc,0x93}},
+ {{0xe1,0xbe,0x9a}, {0xce,0x97,0xcd,0x85,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbe,0x9c}, {0xce,0x97,0xcd,0x85,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbe,0x9e}, {0xce,0x97,0xcd,0x85,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbe,0x99}, {0xce,0x97,0xcd,0x85,0xcc,0x94}},
+ {{0xe1,0xbe,0x9b}, {0xce,0x97,0xcd,0x85,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbe,0x9d}, {0xce,0x97,0xcd,0x85,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbe,0x9f}, {0xce,0x97,0xcd,0x85,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbf,0x9a}, {0xce,0x99,0xcc,0x80}},
+ {{0xe1,0xbf,0x9b}, {0xce,0x99,0xcc,0x81}},
+ {{0xe1,0xbf,0x99}, {0xce,0x99,0xcc,0x84}},
+ {{0xe1,0xbf,0x98}, {0xce,0x99,0xcc,0x86}},
+ {{0xce,0xaa}, {0xce,0x99,0xcc,0x88}},
+ {{0xce,0x8a}, {0xce,0x99,0xcc,0x8d}},
+ {{0xe1,0xbc,0xb8}, {0xce,0x99,0xcc,0x93}},
+ {{0xe1,0xbc,0xba}, {0xce,0x99,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbc,0xbc}, {0xce,0x99,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbc,0xbe}, {0xce,0x99,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbc,0xb9}, {0xce,0x99,0xcc,0x94}},
+ {{0xe1,0xbc,0xbb}, {0xce,0x99,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbc,0xbd}, {0xce,0x99,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbc,0xbf}, {0xce,0x99,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbf,0xb8}, {0xce,0x9f,0xcc,0x80}},
+ {{0xe1,0xbf,0xb9}, {0xce,0x9f,0xcc,0x81}},
+ {{0xce,0x8c}, {0xce,0x9f,0xcc,0x8d}},
+ {{0xe1,0xbd,0x88}, {0xce,0x9f,0xcc,0x93}},
+ {{0xe1,0xbd,0x8a}, {0xce,0x9f,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbd,0x8c}, {0xce,0x9f,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbd,0x89}, {0xce,0x9f,0xcc,0x94}},
+ {{0xe1,0xbd,0x8b}, {0xce,0x9f,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbd,0x8d}, {0xce,0x9f,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbf,0xac}, {0xce,0xa1,0xcc,0x94}},
+ {{0xe1,0xbf,0xaa}, {0xce,0xa5,0xcc,0x80}},
+ {{0xe1,0xbf,0xab}, {0xce,0xa5,0xcc,0x81}},
+ {{0xe1,0xbf,0xa9}, {0xce,0xa5,0xcc,0x84}},
+ {{0xe1,0xbf,0xa8}, {0xce,0xa5,0xcc,0x86}},
+ {{0xce,0xab}, {0xce,0xa5,0xcc,0x88}},
+ {{0xce,0x8e}, {0xce,0xa5,0xcc,0x8d}},
+ {{0xe1,0xbd,0x99}, {0xce,0xa5,0xcc,0x94}},
+ {{0xe1,0xbd,0x9b}, {0xce,0xa5,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbd,0x9d}, {0xce,0xa5,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbd,0x9f}, {0xce,0xa5,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbf,0xba}, {0xce,0xa9,0xcc,0x80}},
+ {{0xe1,0xbf,0xbb}, {0xce,0xa9,0xcc,0x81}},
+ {{0xce,0x8f}, {0xce,0xa9,0xcc,0x8d}},
+ {{0xe1,0xbd,0xa8}, {0xce,0xa9,0xcc,0x93}},
+ {{0xe1,0xbd,0xaa}, {0xce,0xa9,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbd,0xac}, {0xce,0xa9,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbd,0xae}, {0xce,0xa9,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbd,0xa9}, {0xce,0xa9,0xcc,0x94}},
+ {{0xe1,0xbd,0xab}, {0xce,0xa9,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbd,0xad}, {0xce,0xa9,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbd,0xaf}, {0xce,0xa9,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbf,0xbc}, {0xce,0xa9,0xcd,0x85}},
+ {{0xe1,0xbe,0xa8}, {0xce,0xa9,0xcd,0x85,0xcc,0x93}},
+ {{0xe1,0xbe,0xaa}, {0xce,0xa9,0xcd,0x85,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbe,0xac}, {0xce,0xa9,0xcd,0x85,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbe,0xae}, {0xce,0xa9,0xcd,0x85,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbe,0xa9}, {0xce,0xa9,0xcd,0x85,0xcc,0x94}},
+ {{0xe1,0xbe,0xab}, {0xce,0xa9,0xcd,0x85,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbe,0xad}, {0xce,0xa9,0xcd,0x85,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbe,0xaf}, {0xce,0xa9,0xcd,0x85,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbd,0xb0}, {0xce,0xb1,0xcc,0x80}},
+ {{0xe1,0xbd,0xb1}, {0xce,0xb1,0xcc,0x81}},
+ {{0xe1,0xbe,0xb1}, {0xce,0xb1,0xcc,0x84}},
+ {{0xe1,0xbe,0xb0}, {0xce,0xb1,0xcc,0x86}},
+ {{0xce,0xac}, {0xce,0xb1,0xcc,0x8d}},
+ {{0xe1,0xbc,0x80}, {0xce,0xb1,0xcc,0x93}},
+ {{0xe1,0xbc,0x82}, {0xce,0xb1,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbc,0x84}, {0xce,0xb1,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbc,0x86}, {0xce,0xb1,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbc,0x81}, {0xce,0xb1,0xcc,0x94}},
+ {{0xe1,0xbc,0x83}, {0xce,0xb1,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbc,0x85}, {0xce,0xb1,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbc,0x87}, {0xce,0xb1,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbe,0xb6}, {0xce,0xb1,0xcd,0x82}},
+ {{0xe1,0xbe,0xb3}, {0xce,0xb1,0xcd,0x85}},
+ {{0xe1,0xbe,0xb2}, {0xce,0xb1,0xcd,0x85,0xcc,0x80}},
+ {{0xe1,0xbe,0xb4}, {0xce,0xb1,0xcd,0x85,0xcc,0x81}},
+ {{0xe1,0xbe,0x80}, {0xce,0xb1,0xcd,0x85,0xcc,0x93}},
+ {{0xe1,0xbe,0x82}, {0xce,0xb1,0xcd,0x85,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbe,0x84}, {0xce,0xb1,0xcd,0x85,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbe,0x86}, {0xce,0xb1,0xcd,0x85,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbe,0x81}, {0xce,0xb1,0xcd,0x85,0xcc,0x94}},
+ {{0xe1,0xbe,0x83}, {0xce,0xb1,0xcd,0x85,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbe,0x85}, {0xce,0xb1,0xcd,0x85,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbe,0x87}, {0xce,0xb1,0xcd,0x85,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbe,0xb7}, {0xce,0xb1,0xcd,0x85,0xcd,0x82}},
+ {{0xe1,0xbd,0xb2}, {0xce,0xb5,0xcc,0x80}},
+ {{0xe1,0xbd,0xb3}, {0xce,0xb5,0xcc,0x81}},
+ {{0xce,0xad}, {0xce,0xb5,0xcc,0x8d}},
+ {{0xe1,0xbc,0x90}, {0xce,0xb5,0xcc,0x93}},
+ {{0xe1,0xbc,0x92}, {0xce,0xb5,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbc,0x94}, {0xce,0xb5,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbc,0x91}, {0xce,0xb5,0xcc,0x94}},
+ {{0xe1,0xbc,0x93}, {0xce,0xb5,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbc,0x95}, {0xce,0xb5,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbd,0xb4}, {0xce,0xb7,0xcc,0x80}},
+ {{0xe1,0xbd,0xb5}, {0xce,0xb7,0xcc,0x81}},
+ {{0xce,0xae}, {0xce,0xb7,0xcc,0x8d}},
+ {{0xe1,0xbc,0xa0}, {0xce,0xb7,0xcc,0x93}},
+ {{0xe1,0xbc,0xa2}, {0xce,0xb7,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbc,0xa4}, {0xce,0xb7,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbc,0xa6}, {0xce,0xb7,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbc,0xa1}, {0xce,0xb7,0xcc,0x94}},
+ {{0xe1,0xbc,0xa3}, {0xce,0xb7,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbc,0xa5}, {0xce,0xb7,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbc,0xa7}, {0xce,0xb7,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbf,0x86}, {0xce,0xb7,0xcd,0x82}},
+ {{0xe1,0xbf,0x83}, {0xce,0xb7,0xcd,0x85}},
+ {{0xe1,0xbf,0x82}, {0xce,0xb7,0xcd,0x85,0xcc,0x80}},
+ {{0xe1,0xbf,0x84}, {0xce,0xb7,0xcd,0x85,0xcc,0x81}},
+ {{0xe1,0xbe,0x90}, {0xce,0xb7,0xcd,0x85,0xcc,0x93}},
+ {{0xe1,0xbe,0x92}, {0xce,0xb7,0xcd,0x85,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbe,0x94}, {0xce,0xb7,0xcd,0x85,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbe,0x96}, {0xce,0xb7,0xcd,0x85,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbe,0x91}, {0xce,0xb7,0xcd,0x85,0xcc,0x94}},
+ {{0xe1,0xbe,0x93}, {0xce,0xb7,0xcd,0x85,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbe,0x95}, {0xce,0xb7,0xcd,0x85,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbe,0x97}, {0xce,0xb7,0xcd,0x85,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbf,0x87}, {0xce,0xb7,0xcd,0x85,0xcd,0x82}},
+ {{0xe1,0xbe,0xbe}, {0xce,0xb9}},
+ {{0xe1,0xbd,0xb6}, {0xce,0xb9,0xcc,0x80}},
+ {{0xe1,0xbd,0xb7}, {0xce,0xb9,0xcc,0x81}},
+ {{0xe1,0xbf,0x91}, {0xce,0xb9,0xcc,0x84}},
+ {{0xe1,0xbf,0x90}, {0xce,0xb9,0xcc,0x86}},
+ {{0xcf,0x8a}, {0xce,0xb9,0xcc,0x88}},
+ {{0xe1,0xbf,0x92}, {0xce,0xb9,0xcc,0x88,0xcc,0x80}},
+ {{0xe1,0xbf,0x93}, {0xce,0xb9,0xcc,0x88,0xcc,0x81}},
+ {{0xce,0x90}, {0xce,0xb9,0xcc,0x88,0xcc,0x8d}},
+ {{0xe1,0xbf,0x97}, {0xce,0xb9,0xcc,0x88,0xcd,0x82}},
+ {{0xce,0xaf}, {0xce,0xb9,0xcc,0x8d}},
+ {{0xe1,0xbc,0xb0}, {0xce,0xb9,0xcc,0x93}},
+ {{0xe1,0xbc,0xb2}, {0xce,0xb9,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbc,0xb4}, {0xce,0xb9,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbc,0xb6}, {0xce,0xb9,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbc,0xb1}, {0xce,0xb9,0xcc,0x94}},
+ {{0xe1,0xbc,0xb3}, {0xce,0xb9,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbc,0xb5}, {0xce,0xb9,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbc,0xb7}, {0xce,0xb9,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbf,0x96}, {0xce,0xb9,0xcd,0x82}},
+ {{0xe1,0xbd,0xb8}, {0xce,0xbf,0xcc,0x80}},
+ {{0xe1,0xbd,0xb9}, {0xce,0xbf,0xcc,0x81}},
+ {{0xcf,0x8c}, {0xce,0xbf,0xcc,0x8d}},
+ {{0xe1,0xbd,0x80}, {0xce,0xbf,0xcc,0x93}},
+ {{0xe1,0xbd,0x82}, {0xce,0xbf,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbd,0x84}, {0xce,0xbf,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbd,0x81}, {0xce,0xbf,0xcc,0x94}},
+ {{0xe1,0xbd,0x83}, {0xce,0xbf,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbd,0x85}, {0xce,0xbf,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbf,0xb4}, {0xce,0xbf,0xcd,0x85,0xcc,0x81}},
+ {{0xe1,0xbf,0xa4}, {0xcf,0x81,0xcc,0x93}},
+ {{0xe1,0xbf,0xa5}, {0xcf,0x81,0xcc,0x94}},
+ {{0xe1,0xbd,0xba}, {0xcf,0x85,0xcc,0x80}},
+ {{0xe1,0xbd,0xbb}, {0xcf,0x85,0xcc,0x81}},
+ {{0xe1,0xbf,0xa1}, {0xcf,0x85,0xcc,0x84}},
+ {{0xe1,0xbf,0xa0}, {0xcf,0x85,0xcc,0x86}},
+ {{0xcf,0x8b}, {0xcf,0x85,0xcc,0x88}},
+ {{0xe1,0xbf,0xa2}, {0xcf,0x85,0xcc,0x88,0xcc,0x80}},
+ {{0xe1,0xbf,0xa3}, {0xcf,0x85,0xcc,0x88,0xcc,0x81}},
+ {{0xce,0xb0}, {0xcf,0x85,0xcc,0x88,0xcc,0x8d}},
+ {{0xe1,0xbf,0xa7}, {0xcf,0x85,0xcc,0x88,0xcd,0x82}},
+ {{0xcf,0x8d}, {0xcf,0x85,0xcc,0x8d}},
+ {{0xe1,0xbd,0x90}, {0xcf,0x85,0xcc,0x93}},
+ {{0xe1,0xbd,0x92}, {0xcf,0x85,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbd,0x94}, {0xcf,0x85,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbd,0x96}, {0xcf,0x85,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbd,0x91}, {0xcf,0x85,0xcc,0x94}},
+ {{0xe1,0xbd,0x93}, {0xcf,0x85,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbd,0x95}, {0xcf,0x85,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbd,0x97}, {0xcf,0x85,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbf,0xa6}, {0xcf,0x85,0xcd,0x82}},
+ {{0xe1,0xbd,0xbc}, {0xcf,0x89,0xcc,0x80}},
+ {{0xe1,0xbd,0xbd}, {0xcf,0x89,0xcc,0x81}},
+ {{0xcf,0x8e}, {0xcf,0x89,0xcc,0x8d}},
+ {{0xe1,0xbd,0xa0}, {0xcf,0x89,0xcc,0x93}},
+ {{0xe1,0xbd,0xa2}, {0xcf,0x89,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbd,0xa4}, {0xcf,0x89,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbd,0xa6}, {0xcf,0x89,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbd,0xa1}, {0xcf,0x89,0xcc,0x94}},
+ {{0xe1,0xbd,0xa3}, {0xcf,0x89,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbd,0xa5}, {0xcf,0x89,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbd,0xa7}, {0xcf,0x89,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbf,0xb6}, {0xcf,0x89,0xcd,0x82}},
+ {{0xe1,0xbf,0xb3}, {0xcf,0x89,0xcd,0x85}},
+ {{0xe1,0xbf,0xb2}, {0xcf,0x89,0xcd,0x85,0xcc,0x80}},
+ {{0xe1,0xbe,0xa0}, {0xcf,0x89,0xcd,0x85,0xcc,0x93}},
+ {{0xe1,0xbe,0xa2}, {0xcf,0x89,0xcd,0x85,0xcc,0x93,0xcc,0x80}},
+ {{0xe1,0xbe,0xa4}, {0xcf,0x89,0xcd,0x85,0xcc,0x93,0xcc,0x81}},
+ {{0xe1,0xbe,0xa6}, {0xcf,0x89,0xcd,0x85,0xcc,0x93,0xcd,0x82}},
+ {{0xe1,0xbe,0xa1}, {0xcf,0x89,0xcd,0x85,0xcc,0x94}},
+ {{0xe1,0xbe,0xa3}, {0xcf,0x89,0xcd,0x85,0xcc,0x94,0xcc,0x80}},
+ {{0xe1,0xbe,0xa5}, {0xcf,0x89,0xcd,0x85,0xcc,0x94,0xcc,0x81}},
+ {{0xe1,0xbe,0xa7}, {0xcf,0x89,0xcd,0x85,0xcc,0x94,0xcd,0x82}},
+ {{0xe1,0xbf,0xb7}, {0xcf,0x89,0xcd,0x85,0xcd,0x82}},
+ {{0xcf,0x94}, {0xcf,0x92,0xcc,0x88}},
+ {{0xcf,0x93}, {0xcf,0x92,0xcc,0x8d}},
+ {{0xd0,0x87}, {0xd0,0x86,0xcc,0x88}},
+ {{0xd3,0x90}, {0xd0,0x90,0xcc,0x86}},
+ {{0xd3,0x92}, {0xd0,0x90,0xcc,0x88}},
+ {{0xd0,0x83}, {0xd0,0x93,0xcc,0x81}},
+ {{0xd3,0x96}, {0xd0,0x95,0xcc,0x86}},
+ {{0xd0,0x81}, {0xd0,0x95,0xcc,0x88}},
+ {{0xd3,0x81}, {0xd0,0x96,0xcc,0x86}},
+ {{0xd3,0x9c}, {0xd0,0x96,0xcc,0x88}},
+ {{0xd3,0x9e}, {0xd0,0x97,0xcc,0x88}},
+ {{0xd3,0xa2}, {0xd0,0x98,0xcc,0x84}},
+ {{0xd0,0x99}, {0xd0,0x98,0xcc,0x86}},
+ {{0xd3,0xa4}, {0xd0,0x98,0xcc,0x88}},
+ {{0xd0,0x8c}, {0xd0,0x9a,0xcc,0x81}},
+ {{0xd3,0xa6}, {0xd0,0x9e,0xcc,0x88}},
+ {{0xd3,0xae}, {0xd0,0xa3,0xcc,0x84}},
+ {{0xd0,0x8e}, {0xd0,0xa3,0xcc,0x86}},
+ {{0xd3,0xb0}, {0xd0,0xa3,0xcc,0x88}},
+ {{0xd3,0xb2}, {0xd0,0xa3,0xcc,0x8b}},
+ {{0xd3,0xb4}, {0xd0,0xa7,0xcc,0x88}},
+ {{0xd3,0xb8}, {0xd0,0xab,0xcc,0x88}},
+ {{0xd3,0x91}, {0xd0,0xb0,0xcc,0x86}},
+ {{0xd3,0x93}, {0xd0,0xb0,0xcc,0x88}},
+ {{0xd1,0x93}, {0xd0,0xb3,0xcc,0x81}},
+ {{0xd3,0x97}, {0xd0,0xb5,0xcc,0x86}},
+ {{0xd1,0x91}, {0xd0,0xb5,0xcc,0x88}},
+ {{0xd3,0x82}, {0xd0,0xb6,0xcc,0x86}},
+ {{0xd3,0x9d}, {0xd0,0xb6,0xcc,0x88}},
+ {{0xd3,0x9f}, {0xd0,0xb7,0xcc,0x88}},
+ {{0xd3,0xa3}, {0xd0,0xb8,0xcc,0x84}},
+ {{0xd0,0xb9}, {0xd0,0xb8,0xcc,0x86}},
+ {{0xd3,0xa5}, {0xd0,0xb8,0xcc,0x88}},
+ {{0xd1,0x9c}, {0xd0,0xba,0xcc,0x81}},
+ {{0xd3,0xa7}, {0xd0,0xbe,0xcc,0x88}},
+ {{0xd3,0xaf}, {0xd1,0x83,0xcc,0x84}},
+ {{0xd1,0x9e}, {0xd1,0x83,0xcc,0x86}},
+ {{0xd3,0xb1}, {0xd1,0x83,0xcc,0x88}},
+ {{0xd3,0xb3}, {0xd1,0x83,0xcc,0x8b}},
+ {{0xd3,0xb5}, {0xd1,0x87,0xcc,0x88}},
+ {{0xd3,0xb9}, {0xd1,0x8b,0xcc,0x88}},
+ {{0xd1,0x97}, {0xd1,0x96,0xcc,0x88}},
+ {{0xd1,0xb6}, {0xd1,0xb4,0xcc,0x8f}},
+ {{0xd1,0xb7}, {0xd1,0xb5,0xcc,0x8f}},
+ {{0xef,0xac,0xae}, {0xd7,0x90,0xd6,0xb7}},
+ {{0xef,0xac,0xaf}, {0xd7,0x90,0xd6,0xb8}},
+ {{0xef,0xac,0xb0}, {0xd7,0x90,0xd6,0xbc}},
+ {{0xef,0xac,0xb1}, {0xd7,0x91,0xd6,0xbc}},
+ {{0xef,0xad,0x8c}, {0xd7,0x91,0xd6,0xbf}},
+ {{0xef,0xac,0xb2}, {0xd7,0x92,0xd6,0xbc}},
+ {{0xef,0xac,0xb3}, {0xd7,0x93,0xd6,0xbc}},
+ {{0xef,0xac,0xb4}, {0xd7,0x94,0xd6,0xbc}},
+ {{0xef,0xad,0x8b}, {0xd7,0x95,0xd6,0xb9}},
+ {{0xef,0xac,0xb5}, {0xd7,0x95,0xd6,0xbc}},
+ {{0xef,0xac,0xb6}, {0xd7,0x96,0xd6,0xbc}},
+ {{0xef,0xac,0xb8}, {0xd7,0x98,0xd6,0xbc}},
+ {{0xef,0xac,0xb9}, {0xd7,0x99,0xd6,0xbc}},
+ {{0xef,0xac,0xba}, {0xd7,0x9a,0xd6,0xbc}},
+ {{0xef,0xac,0xbb}, {0xd7,0x9b,0xd6,0xbc}},
+ {{0xef,0xad,0x8d}, {0xd7,0x9b,0xd6,0xbf}},
+ {{0xef,0xac,0xbc}, {0xd7,0x9c,0xd6,0xbc}},
+ {{0xef,0xac,0xbe}, {0xd7,0x9e,0xd6,0xbc}},
+ {{0xef,0xad,0x80}, {0xd7,0xa0,0xd6,0xbc}},
+ {{0xef,0xad,0x81}, {0xd7,0xa1,0xd6,0xbc}},
+ {{0xef,0xad,0x83}, {0xd7,0xa3,0xd6,0xbc}},
+ {{0xef,0xad,0x84}, {0xd7,0xa4,0xd6,0xbc}},
+ {{0xef,0xad,0x8e}, {0xd7,0xa4,0xd6,0xbf}},
+ {{0xef,0xad,0x86}, {0xd7,0xa6,0xd6,0xbc}},
+ {{0xef,0xad,0x87}, {0xd7,0xa7,0xd6,0xbc}},
+ {{0xef,0xad,0x88}, {0xd7,0xa8,0xd6,0xbc}},
+ {{0xef,0xad,0x89}, {0xd7,0xa9,0xd6,0xbc}},
+ {{0xef,0xac,0xac}, {0xd7,0xa9,0xd6,0xbc,0xd7,0x81}},
+ {{0xef,0xac,0xad}, {0xd7,0xa9,0xd6,0xbc,0xd7,0x82}},
+ {{0xef,0xac,0xaa}, {0xd7,0xa9,0xd7,0x81}},
+ {{0xef,0xac,0xab}, {0xd7,0xa9,0xd7,0x82}},
+ {{0xef,0xad,0x8a}, {0xd7,0xaa,0xd6,0xbc}},
+ {{0xef,0xac,0x9f}, {0xd7,0xb2,0xd6,0xb7}},
+ {{0xe0,0xa5,0x98}, {0xe0,0xa4,0x95,0xe0,0xa4,0xbc}},
+ {{0xe0,0xa5,0x99}, {0xe0,0xa4,0x96,0xe0,0xa4,0xbc}},
+ {{0xe0,0xa5,0x9a}, {0xe0,0xa4,0x97,0xe0,0xa4,0xbc}},
+ {{0xe0,0xa5,0x9b}, {0xe0,0xa4,0x9c,0xe0,0xa4,0xbc}},
+ {{0xe0,0xa5,0x9c}, {0xe0,0xa4,0xa1,0xe0,0xa4,0xbc}},
+ {{0xe0,0xa5,0x9d}, {0xe0,0xa4,0xa2,0xe0,0xa4,0xbc}},
+ {{0xe0,0xa4,0xa9}, {0xe0,0xa4,0xa8,0xe0,0xa4,0xbc}},
+ {{0xe0,0xa5,0x9e}, {0xe0,0xa4,0xab,0xe0,0xa4,0xbc}},
+ {{0xe0,0xa5,0x9f}, {0xe0,0xa4,0xaf,0xe0,0xa4,0xbc}},
+ {{0xe0,0xa4,0xb1}, {0xe0,0xa4,0xb0,0xe0,0xa4,0xbc}},
+ {{0xe0,0xa4,0xb4}, {0xe0,0xa4,0xb3,0xe0,0xa4,0xbc}},
+ {{0xe0,0xa7,0x9c}, {0xe0,0xa6,0xa1,0xe0,0xa6,0xbc}},
+ {{0xe0,0xa7,0x9d}, {0xe0,0xa6,0xa2,0xe0,0xa6,0xbc}},
+ {{0xe0,0xa6,0xb0}, {0xe0,0xa6,0xac,0xe0,0xa6,0xbc}},
+ {{0xe0,0xa7,0x9f}, {0xe0,0xa6,0xaf,0xe0,0xa6,0xbc}},
+ {{0xe0,0xa7,0x8b}, {0xe0,0xa7,0x87,0xe0,0xa6,0xbe}},
+ {{0xe0,0xa7,0x8c}, {0xe0,0xa7,0x87,0xe0,0xa7,0x97}},
+ {{0xe0,0xa9,0x99}, {0xe0,0xa8,0x96,0xe0,0xa8,0xbc}},
+ {{0xe0,0xa9,0x9a}, {0xe0,0xa8,0x97,0xe0,0xa8,0xbc}},
+ {{0xe0,0xa9,0x9b}, {0xe0,0xa8,0x9c,0xe0,0xa8,0xbc}},
+ {{0xe0,0xa9,0x9c}, {0xe0,0xa8,0xa1,0xe0,0xa8,0xbc}},
+ {{0xe0,0xa9,0x9e}, {0xe0,0xa8,0xab,0xe0,0xa8,0xbc}},
+ {{0xe0,0xad,0x9c}, {0xe0,0xac,0xa1,0xe0,0xac,0xbc}},
+ {{0xe0,0xad,0x9d}, {0xe0,0xac,0xa2,0xe0,0xac,0xbc}},
+ {{0xe0,0xad,0x9f}, {0xe0,0xac,0xaf,0xe0,0xac,0xbc}},
+ {{0xe0,0xad,0x8b}, {0xe0,0xad,0x87,0xe0,0xac,0xbe}},
+ {{0xe0,0xad,0x88}, {0xe0,0xad,0x87,0xe0,0xad,0x96}},
+ {{0xe0,0xad,0x8c}, {0xe0,0xad,0x87,0xe0,0xad,0x97}},
+ {{0xe0,0xae,0x94}, {0xe0,0xae,0x92,0xe0,0xaf,0x97}},
+ {{0xe0,0xaf,0x8a}, {0xe0,0xaf,0x86,0xe0,0xae,0xbe}},
+ {{0xe0,0xaf,0x8c}, {0xe0,0xaf,0x86,0xe0,0xaf,0x97}},
+ {{0xe0,0xaf,0x8b}, {0xe0,0xaf,0x87,0xe0,0xae,0xbe}},
+ {{0xe0,0xb1,0x88}, {0xe0,0xb1,0x86,0xe0,0xb1,0x96}},
+ {{0xe0,0xb3,0x80}, {0xe0,0xb2,0xbf,0xe0,0xb3,0x95}},
+ {{0xe0,0xb3,0x8a}, {0xe0,0xb3,0x86,0xe0,0xb3,0x82}},
+ {{0xe0,0xb3,0x8b}, {0xe0,0xb3,0x86,0xe0,0xb3,0x82,0xe0,0xb3,0x95}},
+ {{0xe0,0xb3,0x87}, {0xe0,0xb3,0x86,0xe0,0xb3,0x95}},
+ {{0xe0,0xb3,0x88}, {0xe0,0xb3,0x86,0xe0,0xb3,0x96}},
+ {{0xe0,0xb5,0x8a}, {0xe0,0xb5,0x86,0xe0,0xb4,0xbe}},
+ {{0xe0,0xb5,0x8c}, {0xe0,0xb5,0x86,0xe0,0xb5,0x97}},
+ {{0xe0,0xb5,0x8b}, {0xe0,0xb5,0x87,0xe0,0xb4,0xbe}},
+ {{0xe0,0xb8,0xb3}, {0xe0,0xb9,0x8d,0xe0,0xb8,0xb2}},
+ {{0xe0,0xba,0xb3}, {0xe0,0xbb,0x8d,0xe0,0xba,0xb2}},
+ {{0xe0,0xbd,0xa9}, {0xe0,0xbd,0x80,0xe0,0xbe,0xb5}},
+ {{0xe0,0xbd,0x83}, {0xe0,0xbd,0x82,0xe0,0xbe,0xb7}},
+ {{0xe0,0xbd,0x8d}, {0xe0,0xbd,0x8c,0xe0,0xbe,0xb7}},
+ {{0xe0,0xbd,0x92}, {0xe0,0xbd,0x91,0xe0,0xbe,0xb7}},
+ {{0xe0,0xbd,0x97}, {0xe0,0xbd,0x96,0xe0,0xbe,0xb7}},
+ {{0xe0,0xbd,0x9c}, {0xe0,0xbd,0x9b,0xe0,0xbe,0xb7}},
+ {{0xe0,0xbd,0xb3}, {0xe0,0xbd,0xb2,0xe0,0xbd,0xb1}},
+ {{0xe0,0xbd,0xb5}, {0xe0,0xbd,0xb4,0xe0,0xbd,0xb1}},
+ {{0xe0,0xbe,0x81}, {0xe0,0xbe,0x80,0xe0,0xbd,0xb1}},
+ {{0xe0,0xbe,0xb9}, {0xe0,0xbe,0x90,0xe0,0xbe,0xb5}},
+ {{0xe0,0xbe,0x93}, {0xe0,0xbe,0x92,0xe0,0xbe,0xb7}},
+ {{0xe0,0xbe,0x9d}, {0xe0,0xbe,0x9c,0xe0,0xbe,0xb7}},
+ {{0xe0,0xbe,0xa2}, {0xe0,0xbe,0xa1,0xe0,0xbe,0xb7}},
+ {{0xe0,0xbe,0xa7}, {0xe0,0xbe,0xa6,0xe0,0xbe,0xb7}},
+ {{0xe0,0xbe,0xac}, {0xe0,0xbe,0xab,0xe0,0xbe,0xb7}},
+ {{0xe0,0xbd,0xb6}, {0xe0,0xbe,0xb2,0xe0,0xbe,0x80}},
+ {{0xe0,0xbd,0xb7}, {0xe0,0xbe,0xb2,0xe0,0xbe,0x80,0xe0,0xbd,0xb1}},
+ {{0xe0,0xbd,0xb8}, {0xe0,0xbe,0xb3,0xe0,0xbe,0x80}},
+ {{0xe0,0xbd,0xb9}, {0xe0,0xbe,0xb3,0xe0,0xbe,0x80,0xe0,0xbd,0xb1}},
+ {{0xe1,0xbf,0x8d}, {0xe1,0xbe,0xbf,0xcc,0x80}},
+ {{0xe1,0xbf,0x8e}, {0xe1,0xbe,0xbf,0xcc,0x81}},
+ {{0xe1,0xbf,0x8f}, {0xe1,0xbe,0xbf,0xcd,0x82}},
+ {{0xe1,0xbf,0x9d}, {0xe1,0xbf,0xbe,0xcc,0x80}},
+ {{0xe1,0xbf,0x9e}, {0xe1,0xbf,0xbe,0xcc,0x81}},
+ {{0xe1,0xbf,0x9f}, {0xe1,0xbf,0xbe,0xcd,0x82}},
+ {{0xe3,0x82,0x94}, {0xe3,0x81,0x86,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0x8c}, {0xe3,0x81,0x8b,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0x8e}, {0xe3,0x81,0x8d,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0x90}, {0xe3,0x81,0x8f,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0x92}, {0xe3,0x81,0x91,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0x94}, {0xe3,0x81,0x93,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0x96}, {0xe3,0x81,0x95,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0x98}, {0xe3,0x81,0x97,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0x9a}, {0xe3,0x81,0x99,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0x9c}, {0xe3,0x81,0x9b,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0x9e}, {0xe3,0x81,0x9d,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0xa0}, {0xe3,0x81,0x9f,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0xa2}, {0xe3,0x81,0xa1,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0xa5}, {0xe3,0x81,0xa4,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0xa7}, {0xe3,0x81,0xa6,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0xa9}, {0xe3,0x81,0xa8,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0xb0}, {0xe3,0x81,0xaf,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0xb1}, {0xe3,0x81,0xaf,0xe3,0x82,0x9a}},
+ {{0xe3,0x81,0xb3}, {0xe3,0x81,0xb2,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0xb4}, {0xe3,0x81,0xb2,0xe3,0x82,0x9a}},
+ {{0xe3,0x81,0xb6}, {0xe3,0x81,0xb5,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0xb7}, {0xe3,0x81,0xb5,0xe3,0x82,0x9a}},
+ {{0xe3,0x81,0xb9}, {0xe3,0x81,0xb8,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0xba}, {0xe3,0x81,0xb8,0xe3,0x82,0x9a}},
+ {{0xe3,0x81,0xbc}, {0xe3,0x81,0xbb,0xe3,0x82,0x99}},
+ {{0xe3,0x81,0xbd}, {0xe3,0x81,0xbb,0xe3,0x82,0x9a}},
+ {{0xe3,0x82,0x9e}, {0xe3,0x82,0x9d,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0xb4}, {0xe3,0x82,0xa6,0xe3,0x82,0x99}},
+ {{0xe3,0x82,0xac}, {0xe3,0x82,0xab,0xe3,0x82,0x99}},
+ {{0xe3,0x82,0xae}, {0xe3,0x82,0xad,0xe3,0x82,0x99}},
+ {{0xe3,0x82,0xb0}, {0xe3,0x82,0xaf,0xe3,0x82,0x99}},
+ {{0xe3,0x82,0xb2}, {0xe3,0x82,0xb1,0xe3,0x82,0x99}},
+ {{0xe3,0x82,0xb4}, {0xe3,0x82,0xb3,0xe3,0x82,0x99}},
+ {{0xe3,0x82,0xb6}, {0xe3,0x82,0xb5,0xe3,0x82,0x99}},
+ {{0xe3,0x82,0xb8}, {0xe3,0x82,0xb7,0xe3,0x82,0x99}},
+ {{0xe3,0x82,0xba}, {0xe3,0x82,0xb9,0xe3,0x82,0x99}},
+ {{0xe3,0x82,0xbc}, {0xe3,0x82,0xbb,0xe3,0x82,0x99}},
+ {{0xe3,0x82,0xbe}, {0xe3,0x82,0xbd,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0x80}, {0xe3,0x82,0xbf,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0x82}, {0xe3,0x83,0x81,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0x85}, {0xe3,0x83,0x84,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0x87}, {0xe3,0x83,0x86,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0x89}, {0xe3,0x83,0x88,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0x90}, {0xe3,0x83,0x8f,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0x91}, {0xe3,0x83,0x8f,0xe3,0x82,0x9a}},
+ {{0xe3,0x83,0x93}, {0xe3,0x83,0x92,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0x94}, {0xe3,0x83,0x92,0xe3,0x82,0x9a}},
+ {{0xe3,0x83,0x96}, {0xe3,0x83,0x95,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0x97}, {0xe3,0x83,0x95,0xe3,0x82,0x9a}},
+ {{0xe3,0x83,0x99}, {0xe3,0x83,0x98,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0x9a}, {0xe3,0x83,0x98,0xe3,0x82,0x9a}},
+ {{0xe3,0x83,0x9c}, {0xe3,0x83,0x9b,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0x9d}, {0xe3,0x83,0x9b,0xe3,0x82,0x9a}},
+ {{0xe3,0x83,0xb7}, {0xe3,0x83,0xaf,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0xb8}, {0xe3,0x83,0xb0,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0xb9}, {0xe3,0x83,0xb1,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0xba}, {0xe3,0x83,0xb2,0xe3,0x82,0x99}},
+ {{0xe3,0x83,0xbe}, {0xe3,0x83,0xbd,0xe3,0x82,0x99}},
+};
+#endif /* UNICODE_NORMALIZATION */
+#endif /* UTF8_INPUT_ENABLE */
+
+#ifdef SHIFTJIS_CP932
+const unsigned short shiftjis_cp932[3][189] = {
+ {
+ 0xEEEF, 0xEEF0, 0xEEF1, 0xEEF2, 0xEEF3, 0xEEF4, 0xEEF5, 0xEEF6,
+ 0xEEF7, 0xEEF8, 0x8754, 0x8755, 0x8756, 0x8757, 0x8758, 0x8759,
+ 0x875A, 0x875B, 0x875C, 0x875D, 0x81CA, 0xEEFA, 0xEEFB, 0xEEFC,
+ 0x878A, 0x8782, 0x8784, 0x81E6, 0xED40, 0xED41, 0xED42, 0xED43,
+ 0xED44, 0xED45, 0xED46, 0xED47, 0xED48, 0xED49, 0xED4A, 0xED4B,
+ 0xED4C, 0xED4D, 0xED4E, 0xED4F, 0xED50, 0xED51, 0xED52, 0xED53,
+ 0xED54, 0xED55, 0xED56, 0xED57, 0xED58, 0xED59, 0xED5A, 0xED5B,
+ 0xED5C, 0xED5D, 0xED5E, 0xED5F, 0xED60, 0xED61, 0xED62, 0,
+ 0xED63, 0xED64, 0xED65, 0xED66, 0xED67, 0xED68, 0xED69, 0xED6A,
+ 0xED6B, 0xED6C, 0xED6D, 0xED6E, 0xED6F, 0xED70, 0xED71, 0xED72,
+ 0xED73, 0xED74, 0xED75, 0xED76, 0xED77, 0xED78, 0xED79, 0xED7A,
+ 0xED7B, 0xED7C, 0xED7D, 0xED7E, 0xED80, 0xED81, 0xED82, 0xED83,
+ 0xED84, 0xED85, 0xED86, 0xED87, 0xED88, 0xED89, 0xED8A, 0xED8B,
+ 0xED8C, 0xED8D, 0xED8E, 0xED8F, 0xED90, 0xED91, 0xED92, 0xED93,
+ 0xED94, 0xED95, 0xED96, 0xED97, 0xED98, 0xED99, 0xED9A, 0xED9B,
+ 0xED9C, 0xED9D, 0xED9E, 0xED9F, 0xEDA0, 0xEDA1, 0xEDA2, 0xEDA3,
+ 0xEDA4, 0xEDA5, 0xEDA6, 0xEDA7, 0xEDA8, 0xEDA9, 0xEDAA, 0xEDAB,
+ 0xEDAC, 0xEDAD, 0xEDAE, 0xEDAF, 0xEDB0, 0xEDB1, 0xEDB2, 0xEDB3,
+ 0xEDB4, 0xEDB5, 0xEDB6, 0xEDB7, 0xEDB8, 0xEDB9, 0xEDBA, 0xEDBB,
+ 0xEDBC, 0xEDBD, 0xEDBE, 0xEDBF, 0xEDC0, 0xEDC1, 0xEDC2, 0xEDC3,
+ 0xEDC4, 0xEDC5, 0xEDC6, 0xEDC7, 0xEDC8, 0xEDC9, 0xEDCA, 0xEDCB,
+ 0xEDCC, 0xEDCD, 0xEDCE, 0xEDCF, 0xEDD0, 0xEDD1, 0xEDD2, 0xEDD3,
+ 0xEDD4, 0xEDD5, 0xEDD6, 0xEDD7, 0xEDD8, 0xEDD9, 0xEDDA, 0xEDDB,
+ 0xEDDC, 0xEDDD, 0xEDDE, 0xEDDF, 0xEDE0,
+ },
+ {
+ 0xEDE1, 0xEDE2, 0xEDE3, 0xEDE4, 0xEDE5, 0xEDE6, 0xEDE7, 0xEDE8,
+ 0xEDE9, 0xEDEA, 0xEDEB, 0xEDEC, 0xEDED, 0xEDEE, 0xEDEF, 0xEDF0,
+ 0xEDF1, 0xEDF2, 0xEDF3, 0xEDF4, 0xEDF5, 0xEDF6, 0xEDF7, 0xEDF8,
+ 0xEDF9, 0xEDFA, 0xEDFB, 0xEDFC, 0xEE40, 0xEE41, 0xEE42, 0xEE43,
+ 0xEE44, 0xEE45, 0xEE46, 0xEE47, 0xEE48, 0xEE49, 0xEE4A, 0xEE4B,
+ 0xEE4C, 0xEE4D, 0xEE4E, 0xEE4F, 0xEE50, 0xEE51, 0xEE52, 0xEE53,
+ 0xEE54, 0xEE55, 0xEE56, 0xEE57, 0xEE58, 0xEE59, 0xEE5A, 0xEE5B,
+ 0xEE5C, 0xEE5D, 0xEE5E, 0xEE5F, 0xEE60, 0xEE61, 0xEE62, 0,
+ 0xEE63, 0xEE64, 0xEE65, 0xEE66, 0xEE67, 0xEE68, 0xEE69, 0xEE6A,
+ 0xEE6B, 0xEE6C, 0xEE6D, 0xEE6E, 0xEE6F, 0xEE70, 0xEE71, 0xEE72,
+ 0xEE73, 0xEE74, 0xEE75, 0xEE76, 0xEE77, 0xEE78, 0xEE79, 0xEE7A,
+ 0xEE7B, 0xEE7C, 0xEE7D, 0xEE7E, 0xEE80, 0xEE81, 0xEE82, 0xEE83,
+ 0xEE84, 0xEE85, 0xEE86, 0xEE87, 0xEE88, 0xEE89, 0xEE8A, 0xEE8B,
+ 0xEE8C, 0xEE8D, 0xEE8E, 0xEE8F, 0xEE90, 0xEE91, 0xEE92, 0xEE93,
+ 0xEE94, 0xEE95, 0xEE96, 0xEE97, 0xEE98, 0xEE99, 0xEE9A, 0xEE9B,
+ 0xEE9C, 0xEE9D, 0xEE9E, 0xEE9F, 0xEEA0, 0xEEA1, 0xEEA2, 0xEEA3,
+ 0xEEA4, 0xEEA5, 0xEEA6, 0xEEA7, 0xEEA8, 0xEEA9, 0xEEAA, 0xEEAB,
+ 0xEEAC, 0xEEAD, 0xEEAE, 0xEEAF, 0xEEB0, 0xEEB1, 0xEEB2, 0xEEB3,
+ 0xEEB4, 0xEEB5, 0xEEB6, 0xEEB7, 0xEEB8, 0xEEB9, 0xEEBA, 0xEEBB,
+ 0xEEBC, 0xEEBD, 0xEEBE, 0xEEBF, 0xEEC0, 0xEEC1, 0xEEC2, 0xEEC3,
+ 0xEEC4, 0xEEC5, 0xEEC6, 0xEEC7, 0xEEC8, 0xEEC9, 0xEECA, 0xEECB,
+ 0xEECC, 0xEECD, 0xEECE, 0xEECF, 0xEED0, 0xEED1, 0xEED2, 0xEED3,
+ 0xEED4, 0xEED5, 0xEED6, 0xEED7, 0xEED8, 0xEED9, 0xEEDA, 0xEEDB,
+ 0xEEDC, 0xEEDD, 0xEEDE, 0xEEDF, 0xEEE0,
+ },
+ {
+ 0xEEE1, 0xEEE2, 0xEEE3, 0xEEE4, 0xEEE5, 0xEEE6, 0xEEE7, 0xEEE8,
+ 0xEEE9, 0xEEEA, 0xEEEB, 0xEEEC, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ },
+};
+const unsigned short cp932inv[2][189] = {
+ {
+ 0xFA5C, 0xFA5D, 0xFA5E, 0xFA5F, 0xFA60, 0xFA61, 0xFA62, 0xFA63,
+ 0xFA64, 0xFA65, 0xFA66, 0xFA67, 0xFA68, 0xFA69, 0xFA6A, 0xFA6B,
+ 0xFA6C, 0xFA6D, 0xFA6E, 0xFA6F, 0xFA70, 0xFA71, 0xFA72, 0xFA73,
+ 0xFA74, 0xFA75, 0xFA76, 0xFA77, 0xFA78, 0xFA79, 0xFA7A, 0xFA7B,
+ 0xFA7C, 0xFA7D, 0xFA7E, 0xFA80, 0xFA81, 0xFA82, 0xFA83, 0xFA84,
+ 0xFA85, 0xFA86, 0xFA87, 0xFA88, 0xFA89, 0xFA8A, 0xFA8B, 0xFA8C,
+ 0xFA8D, 0xFA8E, 0xFA8F, 0xFA90, 0xFA91, 0xFA92, 0xFA93, 0xFA94,
+ 0xFA95, 0xFA96, 0xFA97, 0xFA98, 0xFA99, 0xFA9A, 0xFA9B, 0,
+ 0xFA9C, 0xFA9D, 0xFA9E, 0xFA9F, 0xFAA0, 0xFAA1, 0xFAA2, 0xFAA3,
+ 0xFAA4, 0xFAA5, 0xFAA6, 0xFAA7, 0xFAA8, 0xFAA9, 0xFAAA, 0xFAAB,
+ 0xFAAC, 0xFAAD, 0xFAAE, 0xFAAF, 0xFAB0, 0xFAB1, 0xFAB2, 0xFAB3,
+ 0xFAB4, 0xFAB5, 0xFAB6, 0xFAB7, 0xFAB8, 0xFAB9, 0xFABA, 0xFABB,
+ 0xFABC, 0xFABD, 0xFABE, 0xFABF, 0xFAC0, 0xFAC1, 0xFAC2, 0xFAC3,
+ 0xFAC4, 0xFAC5, 0xFAC6, 0xFAC7, 0xFAC8, 0xFAC9, 0xFACA, 0xFACB,
+ 0xFACC, 0xFACD, 0xFACE, 0xFACF, 0xFAD0, 0xFAD1, 0xFAD2, 0xFAD3,
+ 0xFAD4, 0xFAD5, 0xFAD6, 0xFAD7, 0xFAD8, 0xFAD9, 0xFADA, 0xFADB,
+ 0xFADC, 0xFADD, 0xFADE, 0xFADF, 0xFAE0, 0xFAE1, 0xFAE2, 0xFAE3,
+ 0xFAE4, 0xFAE5, 0xFAE6, 0xFAE7, 0xFAE8, 0xFAE9, 0xFAEA, 0xFAEB,
+ 0xFAEC, 0xFAED, 0xFAEE, 0xFAEF, 0xFAF0, 0xFAF1, 0xFAF2, 0xFAF3,
+ 0xFAF4, 0xFAF5, 0xFAF6, 0xFAF7, 0xFAF8, 0xFAF9, 0xFAFA, 0xFAFB,
+ 0xFAFC, 0xFB40, 0xFB41, 0xFB42, 0xFB43, 0xFB44, 0xFB45, 0xFB46,
+ 0xFB47, 0xFB48, 0xFB49, 0xFB4A, 0xFB4B, 0xFB4C, 0xFB4D, 0xFB4E,
+ 0xFB4F, 0xFB50, 0xFB51, 0xFB52, 0xFB53, 0xFB54, 0xFB55, 0xFB56,
+ 0xFB57, 0xFB58, 0xFB59, 0xFB5A, 0xFB5B,
+ },
+ {
+ 0xFB5C, 0xFB5D, 0xFB5E, 0xFB5F, 0xFB60, 0xFB61, 0xFB62, 0xFB63,
+ 0xFB64, 0xFB65, 0xFB66, 0xFB67, 0xFB68, 0xFB69, 0xFB6A, 0xFB6B,
+ 0xFB6C, 0xFB6D, 0xFB6E, 0xFB6F, 0xFB70, 0xFB71, 0xFB72, 0xFB73,
+ 0xFB74, 0xFB75, 0xFB76, 0xFB77, 0xFB78, 0xFB79, 0xFB7A, 0xFB7B,
+ 0xFB7C, 0xFB7D, 0xFB7E, 0xFB80, 0xFB81, 0xFB82, 0xFB83, 0xFB84,
+ 0xFB85, 0xFB86, 0xFB87, 0xFB88, 0xFB89, 0xFB8A, 0xFB8B, 0xFB8C,
+ 0xFB8D, 0xFB8E, 0xFB8F, 0xFB90, 0xFB91, 0xFB92, 0xFB93, 0xFB94,
+ 0xFB95, 0xFB96, 0xFB97, 0xFB98, 0xFB99, 0xFB9A, 0xFB9B, 0,
+ 0xFB9C, 0xFB9D, 0xFB9E, 0xFB9F, 0xFBA0, 0xFBA1, 0xFBA2, 0xFBA3,
+ 0xFBA4, 0xFBA5, 0xFBA6, 0xFBA7, 0xFBA8, 0xFBA9, 0xFBAA, 0xFBAB,
+ 0xFBAC, 0xFBAD, 0xFBAE, 0xFBAF, 0xFBB0, 0xFBB1, 0xFBB2, 0xFBB3,
+ 0xFBB4, 0xFBB5, 0xFBB6, 0xFBB7, 0xFBB8, 0xFBB9, 0xFBBA, 0xFBBB,
+ 0xFBBC, 0xFBBD, 0xFBBE, 0xFBBF, 0xFBC0, 0xFBC1, 0xFBC2, 0xFBC3,
+ 0xFBC4, 0xFBC5, 0xFBC6, 0xFBC7, 0xFBC8, 0xFBC9, 0xFBCA, 0xFBCB,
+ 0xFBCC, 0xFBCD, 0xFBCE, 0xFBCF, 0xFBD0, 0xFBD1, 0xFBD2, 0xFBD3,
+ 0xFBD4, 0xFBD5, 0xFBD6, 0xFBD7, 0xFBD8, 0xFBD9, 0xFBDA, 0xFBDB,
+ 0xFBDC, 0xFBDD, 0xFBDE, 0xFBDF, 0xFBE0, 0xFBE1, 0xFBE2, 0xFBE3,
+ 0xFBE4, 0xFBE5, 0xFBE6, 0xFBE7, 0xFBE8, 0xFBE9, 0xFBEA, 0xFBEB,
+ 0xFBEC, 0xFBED, 0xFBEE, 0xFBEF, 0xFBF0, 0xFBF1, 0xFBF2, 0xFBF3,
+ 0xFBF4, 0xFBF5, 0xFBF6, 0xFBF7, 0xFBF8, 0xFBF9, 0xFBFA, 0xFBFB,
+ 0xFBFC, 0xFC40, 0xFC41, 0xFC42, 0xFC43, 0xFC44, 0xFC45, 0xFC46,
+ 0xFC47, 0xFC48, 0xFC49, 0xFC4A, 0xFC4B, 0, 0, 0xFA40,
+ 0xFA41, 0xFA42, 0xFA43, 0xFA44, 0xFA45, 0xFA46, 0xFA47, 0xFA48,
+ 0xFA49, 0x81CA, 0xFA55, 0xFA56, 0xFA57,
+ },
+};
+#endif /* SHIFTJIS_CP932 */
+
+#ifdef X0212_ENABLE
+const unsigned short shiftjis_x0212[3][189] = {
+ {
+ 0xF373, 0xF374, 0xF375, 0xF376, 0xF377, 0xF378, 0xF379, 0xF37A,
+ 0xF37B, 0xF37C, 0xF37D, 0xF37E, 0xF421, 0xF422, 0xF423, 0xF424,
+ 0xF425, 0xF426, 0xF427, 0xF428, 0x224C, 0xA243, 0xF429, 0xF42A,
+ 0xF42B, 0xF42C, 0xF42D, 0x2268, 0xD463, 0xDC5F, 0xE469, 0xE378,
+ 0xD921, 0xB13B, 0xF42E, 0xC22D, 0xC37C, 0xE450, 0xC23F, 0xBC74,
+ 0xB029, 0xB048, 0xF42F, 0xB052, 0xB054, 0xB063, 0xB06E, 0xB127,
+ 0xB123, 0xB12C, 0xB129, 0xB13E, 0xB15F, 0xB158, 0xB148, 0xB157,
+ 0xB163, 0xB174, 0xB161, 0xB223, 0xF430, 0xB23B, 0xB266, 0,
+ 0xB26D, 0xB275, 0xB27C, 0xF431, 0xB335, 0xB358, 0xB35B, 0xB365,
+ 0xB36E, 0xB37B, 0xF432, 0xF433, 0xB440, 0xB447, 0xB450, 0xB45E,
+ 0xF434, 0xB52A, 0xF435, 0xB52F, 0xB544, 0xB568, 0xF436, 0xB742,
+ 0xB764, 0xB768, 0xB767, 0xF437, 0xF438, 0xF439, 0xB84E, 0xB861,
+ 0xB875, 0xB877, 0xB878, 0xB87C, 0xB92F, 0xB937, 0xBA3E, 0xBA5B,
+ 0xCD2A, 0xBA61, 0xF43A, 0xBA6B, 0xBB33, 0xBB38, 0xF43B, 0xBB4A,
+ 0xF43C, 0xF43D, 0xBB50, 0xBB5E, 0xBB74, 0xBB75, 0xBB79, 0xBC64,
+ 0xBC6D, 0xBC7E, 0xF43E, 0xBD42, 0xBD67, 0xF43F, 0xBD70, 0xBE30,
+ 0xBE2C, 0xF440, 0xBE33, 0xBE3D, 0xBE4D, 0xBE49, 0xBE64, 0xBF28,
+ 0xBF49, 0xC044, 0xC064, 0xC074, 0xC126, 0xF441, 0xC175, 0xC17C,
+ 0xF442, 0xC178, 0xC22B, 0xC221, 0xC225, 0xF443, 0xC238, 0xC23A,
+ 0xF444, 0xC244, 0xC252, 0xC257, 0xC25B, 0xC25E, 0xC26D, 0xC270,
+ 0xF445, 0xC321, 0xC335, 0xC349, 0xC339, 0xF446, 0xC358, 0xC37E,
+ 0xF447, 0xC44C, 0xF448, 0xC459, 0xC46A, 0xC47D, 0xF449, 0xC527,
+ 0xC535, 0xC536, 0xF44A, 0xC555, 0xC638, 0xC657, 0xC660, 0xC66A,
+ 0xC663, 0xC721, 0xC72B, 0xC747, 0xC743,
+ },
+ {
+ 0xC74B, 0xC74F, 0xC759, 0xF44B, 0xF44C, 0xC766, 0xC76E, 0xC77C,
+ 0xC76B, 0xC770, 0xC831, 0xC865, 0xC878, 0xC926, 0xC92B, 0xC92D,
+ 0xF44D, 0xC94A, 0xC953, 0xC969, 0xC963, 0xC97C, 0xC974, 0xC975,
+ 0xF44E, 0xCA33, 0xCA3D, 0xCA6F, 0xCA71, 0xCB2E, 0xF44F, 0xCB4A,
+ 0xCB66, 0xCB6A, 0xCB70, 0xCB74, 0xCB6E, 0xCC25, 0xCB79, 0xCC2B,
+ 0xCC2E, 0xCC2D, 0xCC32, 0xCC42, 0xCC50, 0xCC59, 0xF450, 0xCD3B,
+ 0xF451, 0xCE3B, 0xF452, 0xCE3A, 0xCE43, 0xF453, 0xCE72, 0xB35D,
+ 0xCF55, 0xCF62, 0xCF69, 0xCF6D, 0xF454, 0xF455, 0xF456, 0,
+ 0xF457, 0xD065, 0xF458, 0xD069, 0xD168, 0xF459, 0xF45A, 0xD16C,
+ 0xD23B, 0xF45B, 0xD361, 0xD368, 0xD427, 0xF45C, 0xF45D, 0xD454,
+ 0xD472, 0xD52E, 0xF45E, 0xD75E, 0xF45F, 0xD822, 0xD837, 0xD841,
+ 0xD851, 0xD874, 0xD946, 0xD948, 0xD951, 0xF460, 0xF461, 0xF462,
+ 0xF463, 0xF464, 0xDC53, 0xDD48, 0xDD54, 0xDD6A, 0xDD7A, 0xDE24,
+ 0xDE30, 0xF465, 0xDE35, 0xDE4B, 0xF466, 0xDF39, 0xF467, 0xDF43,
+ 0xF468, 0xF469, 0xE059, 0xF46A, 0xF46B, 0xE162, 0xF46C, 0xF46D,
+ 0xF46E, 0xE247, 0xE328, 0xE326, 0xE329, 0xE32F, 0xE330, 0xE32A,
+ 0xE32B, 0xE33C, 0xE341, 0xE33F, 0xE355, 0xE358, 0xE356, 0xE35F,
+ 0xE363, 0xE361, 0xE354, 0xE369, 0xE426, 0xE371, 0xE372, 0xE44B,
+ 0xE441, 0xE443, 0xE43E, 0xF46F, 0xE440, 0xE447, 0xE43F, 0xE460,
+ 0xE45E, 0xE451, 0xF470, 0xE45C, 0xE452, 0xE45B, 0xE454, 0xE47A,
+ 0xE46F, 0xE533, 0xE53F, 0xE549, 0xE550, 0xE562, 0xE56A, 0xE56B,
+ 0xF471, 0xF472, 0xF473, 0xE668, 0xE66F, 0xE72C, 0xF474, 0xE72E,
+ 0xF475, 0xE731, 0xF476, 0xE732, 0xE831, 0xE836, 0xF477, 0xF478,
+ 0xE85D, 0xF479, 0xF47A, 0xE951, 0xF47B,
+ },
+ {
+ 0xE96D, 0xEA4D, 0xF47C, 0xEA5B, 0xEA66, 0xEA6A, 0xEB25, 0xEB7B,
+ 0xEB7A, 0xF47D, 0xEC56, 0xF47E, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ },
+};
+
+static const unsigned short x0212_shiftjis_A2[] = {
+ 0x819F, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0x8143, 0, 0, 0x8150, 0, 0, 0x8160,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFA55, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_B0[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFA68, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFA69, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFA6B, 0, 0xFA6C, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFA6D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFA6E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_B1[] = {
+ 0, 0, 0xFA70, 0, 0, 0, 0xFA6F,
+ 0, 0xFA72, 0, 0, 0xFA71, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFA61, 0, 0, 0xFA73, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFA76, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xFA77,
+ 0xFA75, 0, 0, 0, 0, 0, 0, 0xFA74,
+ 0, 0xFA7A, 0, 0xFA78, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFA79, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_B2[] = {
+ 0, 0, 0xFA7B, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFA7D, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFA7E, 0,
+ 0, 0, 0, 0, 0, 0xFA80, 0, 0,
+ 0, 0, 0, 0, 0, 0xFA81, 0, 0,
+ 0, 0, 0, 0, 0xFA82, 0, 0,
+};
+static const unsigned short x0212_shiftjis_B3[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFA84, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFA85, 0, 0, 0xFA86, 0, 0xFB77, 0, 0,
+ 0, 0, 0, 0, 0, 0xFA87, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFA88, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFA89, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_B4[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFA8C, 0, 0, 0, 0, 0, 0, 0xFA8D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFA8E, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFA8F, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_B5[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFA91, 0, 0, 0, 0, 0xFA93,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFA94, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFA95, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_B7[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFA97, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFA98, 0, 0, 0xFA9A,
+ 0xFA99, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_B8[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFA9E, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFA9F, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFAA0, 0, 0xFAA1,
+ 0xFAA2, 0, 0, 0, 0xFAA3, 0, 0,
+};
+static const unsigned short x0212_shiftjis_B9[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xFAA4,
+ 0, 0, 0, 0, 0, 0, 0, 0xFAA5,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_BA[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFAA6, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFAA7, 0, 0, 0, 0,
+ 0, 0xFAA9, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFAAB, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_BB[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFAAC, 0, 0, 0, 0,
+ 0xFAAD, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFAAF, 0, 0, 0, 0, 0,
+ 0xFAB2, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFAB3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFAB4, 0xFAB5, 0, 0,
+ 0, 0xFAB6, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_BC[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFAB7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFAB8, 0, 0,
+ 0, 0, 0, 0, 0xFA67, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFAB9,
+};
+static const unsigned short x0212_shiftjis_BD[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFABB, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xFABC,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFABE, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_BE[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFAC0, 0, 0, 0,
+ 0xFABF, 0, 0, 0xFAC2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFAC3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFAC5, 0, 0, 0, 0xFAC4, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFAC6, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_BF[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0xFAC7, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFAC8, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_C0[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFAC9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFACA, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFACB, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_C1[] = {
+ 0, 0, 0, 0, 0, 0xFACC, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFACE, 0, 0,
+ 0xFAD1, 0, 0, 0, 0xFACF, 0, 0,
+};
+static const unsigned short x0212_shiftjis_C2[] = {
+ 0xFAD3, 0, 0, 0, 0xFAD4, 0, 0,
+ 0, 0, 0, 0xFAD2, 0, 0xFA63, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFAD6, 0, 0xFAD7, 0, 0, 0, 0, 0xFA66,
+ 0, 0, 0, 0, 0xFAD9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFADA, 0, 0, 0, 0, 0xFADB,
+ 0, 0, 0, 0xFADC, 0, 0, 0xFADD, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFADE, 0, 0,
+ 0xFADF, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_C3[] = {
+ 0xFAE1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFAE2, 0, 0,
+ 0, 0xFAE4, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFAE3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFAE6, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFA64, 0, 0xFAE7,
+};
+static const unsigned short x0212_shiftjis_C4[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFAE9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFAEB, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFAEC, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFAED, 0,
+};
+static const unsigned short x0212_shiftjis_C5[] = {
+ 0, 0, 0, 0, 0, 0, 0xFAEF,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFAF0, 0xFAF1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFAF3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_C6[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFAF4, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xFAF5,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFAF6, 0, 0, 0xFAF8, 0, 0, 0, 0,
+ 0, 0, 0xFAF7, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_C7[] = {
+ 0xFAF9, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFAFA, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFAFC, 0, 0, 0, 0xFAFB,
+ 0, 0, 0, 0xFB40, 0, 0, 0, 0xFB41,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFB42, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFB45, 0,
+ 0, 0, 0, 0xFB48, 0, 0, 0xFB46, 0,
+ 0xFB49, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFB47, 0, 0,
+};
+static const unsigned short x0212_shiftjis_C8[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFB4A, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFB4B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFB4C, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_C9[] = {
+ 0, 0, 0, 0, 0, 0xFB4D, 0,
+ 0, 0, 0, 0xFB4E, 0, 0xFB4F, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFB51, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFB52, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFB54, 0, 0, 0, 0,
+ 0, 0xFB53, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFB56, 0xFB57, 0, 0,
+ 0, 0, 0, 0, 0xFB55, 0, 0,
+};
+static const unsigned short x0212_shiftjis_CA[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFB59, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFB5A, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xFB5B,
+ 0, 0xFB5C, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_CB[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFB5D, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFB5F, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFB60, 0,
+ 0, 0, 0xFB61, 0, 0, 0, 0xFB64, 0,
+ 0xFB62, 0, 0, 0, 0xFB63, 0, 0, 0,
+ 0, 0xFB66, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_CC[] = {
+ 0, 0, 0, 0, 0xFB65, 0, 0,
+ 0, 0, 0, 0xFB67, 0, 0xFB69, 0xFB68, 0,
+ 0, 0, 0xFB6A, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFB6B, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFB6C, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFB6D, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_CD[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFAA8, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFB6F, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_CE[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFB73, 0xFB71, 0, 0, 0, 0,
+ 0, 0, 0, 0xFB74, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFB76, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_CF[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFB78, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFB79, 0, 0, 0, 0, 0,
+ 0, 0xFB7A, 0, 0, 0, 0xFB7B, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_D0[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFB81, 0, 0,
+ 0, 0xFB83, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_D1[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFB84, 0, 0, 0, 0xFB87, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_D2[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFB88, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_D3[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFB8A, 0, 0, 0, 0, 0, 0,
+ 0xFB8B, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_D4[] = {
+ 0, 0, 0, 0, 0, 0, 0xFB8C,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFB8F, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFA5C, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFB90, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_D5[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFB91, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_D7[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFB93, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_D8[] = {
+ 0, 0xFB95, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xFB96,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFB97, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFB98, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFB99, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_D9[] = {
+ 0xFA60, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFB9A, 0,
+ 0xFB9B, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFB9C, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_DC[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFBA2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xFA5D,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_DD[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFBA3, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFBA4, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFBA5, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFBA6, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_DE[] = {
+ 0, 0, 0, 0xFBA7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFBA8, 0, 0, 0, 0, 0xFBAA, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFBAB, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_DF[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFBAD, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFBAF, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_E0[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFBB2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_E1[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFBB5, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_E2[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xFBB9,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_E3[] = {
+ 0, 0, 0, 0, 0, 0xFBBB, 0,
+ 0xFBBA, 0xFBBC, 0xFBBF, 0xFBC0, 0, 0, 0, 0xFBBD,
+ 0xFBBE, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFBC1, 0, 0, 0xFBC3,
+ 0, 0xFBC2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFBCA, 0xFBC4, 0xFBC6, 0,
+ 0xFBC5, 0, 0, 0, 0, 0, 0, 0xFBC7,
+ 0, 0xFBC9, 0, 0xFBC8, 0, 0, 0, 0,
+ 0, 0xFBCB, 0, 0, 0, 0, 0, 0,
+ 0, 0xFBCD, 0xFBCE, 0, 0, 0, 0, 0,
+ 0xFA5F, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_E4[] = {
+ 0, 0, 0, 0, 0, 0xFBCC, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFBD2, 0xFBD6,
+ 0xFBD4, 0xFBD0, 0, 0xFBD1, 0, 0, 0, 0xFBD5,
+ 0, 0, 0, 0xFBCF, 0, 0, 0, 0,
+ 0xFA65, 0xFBD9, 0xFBDC, 0, 0xFBDE, 0, 0, 0,
+ 0, 0, 0, 0xFBDD, 0xFBDB, 0, 0xFBD8, 0,
+ 0xFBD7, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFA5E, 0, 0, 0, 0, 0, 0xFBE0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFBDF, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_E5[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFBE1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0xFBE2,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFBE3, 0, 0, 0, 0, 0, 0,
+ 0xFBE4, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFBE5, 0, 0, 0, 0, 0,
+ 0, 0, 0xFBE6, 0xFBE7, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_E6[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0xFBEB, 0, 0, 0, 0, 0, 0, 0xFBEC,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_E7[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0xFBED, 0, 0xFBEF, 0,
+ 0, 0xFBF1, 0xFBF3, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_E8[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFBF4, 0, 0, 0, 0, 0xFBF5, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFBF8, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_E9[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0xFBFB, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFC40, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_EA[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0xFC41, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFC43, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFC44, 0,
+ 0, 0, 0xFC45, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_EB[] = {
+ 0, 0, 0, 0, 0xFC46, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0xFC48, 0xFC47, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_EC[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0xFC4A, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+};
+static const unsigned short x0212_shiftjis_F3[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0xFA40, 0xFA41, 0xFA42, 0xFA43, 0xFA44,
+ 0xFA45, 0xFA46, 0xFA47, 0xFA48, 0xFA49, 0xFA4A, 0xFA4B,
+};
+static const unsigned short x0212_shiftjis_F4[] = {
+ 0xFA4C, 0xFA4D, 0xFA4E, 0xFA4F, 0xFA50, 0xFA51, 0xFA52,
+ 0xFA53, 0xFA56, 0xFA57, 0xFA58, 0xFA59, 0xFA5A, 0xFA62, 0xFA6A,
+ 0xFA7C, 0xFA83, 0xFA8A, 0xFA8B, 0xFA90, 0xFA92, 0xFA96, 0xFA9B,
+ 0xFA9C, 0xFA9D, 0xFAAA, 0xFAAE, 0xFAB0, 0xFAB1, 0xFABA, 0xFABD,
+ 0xFAC1, 0xFACD, 0xFAD0, 0xFAD5, 0xFAD8, 0xFAE0, 0xFAE5, 0xFAE8,
+ 0xFAEA, 0xFAEE, 0xFAF2, 0xFB43, 0xFB44, 0xFB50, 0xFB58, 0xFB5E,
+ 0xFB6E, 0xFB70, 0xFB72, 0xFB75, 0xFB7C, 0xFB7D, 0xFB7E, 0xFB80,
+ 0xFB82, 0xFB85, 0xFB86, 0xFB89, 0xFB8D, 0xFB8E, 0xFB92, 0xFB94,
+ 0xFB9D, 0xFB9E, 0xFB9F, 0xFBA0, 0xFBA1, 0xFBA9, 0xFBAC, 0xFBAE,
+ 0xFBB0, 0xFBB1, 0xFBB3, 0xFBB4, 0xFBB6, 0xFBB7, 0xFBB8, 0xFBD3,
+ 0xFBDA, 0xFBE8, 0xFBE9, 0xFBEA, 0xFBEE, 0xFBF0, 0xFBF2, 0xFBF6,
+ 0xFBF7, 0xFBF9, 0xFBFA, 0xFBFC, 0xFC42, 0xFC49, 0xFC4B,
+};
+const unsigned short *const x0212_shiftjis[] = {
+ 0, x0212_shiftjis_A2, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ x0212_shiftjis_B0, x0212_shiftjis_B1, x0212_shiftjis_B2, x0212_shiftjis_B3,
+ x0212_shiftjis_B4, x0212_shiftjis_B5, 0, x0212_shiftjis_B7,
+ x0212_shiftjis_B8, x0212_shiftjis_B9, x0212_shiftjis_BA, x0212_shiftjis_BB,
+ x0212_shiftjis_BC, x0212_shiftjis_BD, x0212_shiftjis_BE, x0212_shiftjis_BF,
+ x0212_shiftjis_C0, x0212_shiftjis_C1, x0212_shiftjis_C2, x0212_shiftjis_C3,
+ x0212_shiftjis_C4, x0212_shiftjis_C5, x0212_shiftjis_C6, x0212_shiftjis_C7,
+ x0212_shiftjis_C8, x0212_shiftjis_C9, x0212_shiftjis_CA, x0212_shiftjis_CB,
+ x0212_shiftjis_CC, x0212_shiftjis_CD, x0212_shiftjis_CE, x0212_shiftjis_CF,
+ x0212_shiftjis_D0, x0212_shiftjis_D1, x0212_shiftjis_D2, x0212_shiftjis_D3,
+ x0212_shiftjis_D4, x0212_shiftjis_D5, 0, x0212_shiftjis_D7,
+ x0212_shiftjis_D8, x0212_shiftjis_D9, 0, 0,
+ x0212_shiftjis_DC, x0212_shiftjis_DD, x0212_shiftjis_DE, x0212_shiftjis_DF,
+ x0212_shiftjis_E0, x0212_shiftjis_E1, x0212_shiftjis_E2, x0212_shiftjis_E3,
+ x0212_shiftjis_E4, x0212_shiftjis_E5, x0212_shiftjis_E6, x0212_shiftjis_E7,
+ x0212_shiftjis_E8, x0212_shiftjis_E9, x0212_shiftjis_EA, x0212_shiftjis_EB,
+ x0212_shiftjis_EC, 0, 0, 0,
+ 0, 0, 0, x0212_shiftjis_F3,
+ x0212_shiftjis_F4, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0,
+};
+#endif /* X0212_ENABLE */
diff --git a/ext/nkf/nkf-utf8/utf8tbl.h b/ext/nkf/nkf-utf8/utf8tbl.h
new file mode 100644
index 0000000000..54a34271dd
--- /dev/null
+++ b/ext/nkf/nkf-utf8/utf8tbl.h
@@ -0,0 +1,72 @@
+/*
+ * utf8tbl.h - Header file for Conversion Table
+ *
+ */
+
+#ifndef _UTF8TBL_H_
+#define _UTF8TBL_H_
+
+#ifdef UTF8_OUTPUT_ENABLE
+#define sizeof_euc_to_utf8_1byte 94
+#define sizeof_euc_to_utf8_2bytes 94
+extern const unsigned short euc_to_utf8_1byte[];
+extern const unsigned short *const euc_to_utf8_2bytes[];
+extern const unsigned short *const euc_to_utf8_2bytes_ms[];
+extern const unsigned short *const euc_to_utf8_2bytes_mac[];
+extern const unsigned short *const euc_to_utf8_2bytes_x0213[];
+extern const unsigned short *const x0212_to_utf8_2bytes[];
+extern const unsigned short *const x0212_to_utf8_2bytes_x0213[];
+#define sizeof_x0213_combining_chars 5
+#define sizeof_x0213_combining_table 25
+#define sizeof_x0213_1_surrogate_table 26
+#define sizeof_x0213_2_surrogate_table 277
+extern const unsigned short x0213_combining_chars[sizeof_x0213_combining_chars];
+extern const unsigned short x0213_combining_table[sizeof_x0213_combining_table][3];
+extern const unsigned short x0213_1_surrogate_table[sizeof_x0213_1_surrogate_table][3];
+extern const unsigned short x0213_2_surrogate_table[sizeof_x0213_2_surrogate_table][3];
+#endif /* UTF8_OUTPUT_ENABLE */
+
+#ifdef UTF8_INPUT_ENABLE
+#define sizeof_utf8_to_euc_C2 64
+#define sizeof_utf8_to_euc_E5B8 64
+#define sizeof_utf8_to_euc_2bytes 112
+#define sizeof_utf8_to_euc_3bytes 16
+extern const unsigned short *const utf8_to_euc_2bytes[];
+extern const unsigned short *const utf8_to_euc_2bytes_ms[];
+extern const unsigned short *const utf8_to_euc_2bytes_932[];
+extern const unsigned short *const utf8_to_euc_2bytes_mac[];
+extern const unsigned short *const utf8_to_euc_2bytes_x0213[];
+extern const unsigned short *const *const utf8_to_euc_3bytes[];
+extern const unsigned short *const *const utf8_to_euc_3bytes_ms[];
+extern const unsigned short *const *const utf8_to_euc_3bytes_932[];
+extern const unsigned short *const *const utf8_to_euc_3bytes_mac[];
+extern const unsigned short *const *const utf8_to_euc_3bytes_x0213[];
+#endif /* UTF8_INPUT_ENABLE */
+
+#ifdef UNICODE_NORMALIZATION
+
+#define NORMALIZATION_TABLE_LENGTH 942
+#define NORMALIZATION_TABLE_NFC_LENGTH 3
+#define NORMALIZATION_TABLE_NFD_LENGTH 9
+struct normalization_pair {
+ const unsigned char nfc[NORMALIZATION_TABLE_NFC_LENGTH];
+ const unsigned char nfd[NORMALIZATION_TABLE_NFD_LENGTH];
+};
+extern const struct normalization_pair normalization_table[];
+#endif
+
+#ifdef SHIFTJIS_CP932
+#define CP932_TABLE_BEGIN 0xFA
+#define CP932_TABLE_END 0xFC
+extern const unsigned short shiftjis_cp932[3][189];
+#define CP932INV_TABLE_BEGIN 0xED
+#define CP932INV_TABLE_END 0xEE
+extern const unsigned short cp932inv[2][189];
+#endif /* SHIFTJIS_CP932 */
+
+#ifdef X0212_ENABLE
+extern const unsigned short shiftjis_x0212[3][189];
+extern const unsigned short *const x0212_shiftjis[];
+#endif /* X0212_ENABLE */
+
+#endif
diff --git a/ext/nkf/nkf.c b/ext/nkf/nkf.c
new file mode 100644
index 0000000000..c6ddee1976
--- /dev/null
+++ b/ext/nkf/nkf.c
@@ -0,0 +1,503 @@
+/*
+ * NKF - Ruby extension for Network Kanji Filter
+ *
+ * original nkf2.x is maintained at http://sourceforge.jp/projects/nkf/
+ *
+ * $Id$
+ *
+ */
+
+#define RUBY_NKF_REVISION "$Revision$"
+#define RUBY_NKF_VERSION NKF_VERSION " (" NKF_RELEASE_DATE ")"
+
+#include "ruby/ruby.h"
+#include "ruby/encoding.h"
+
+/* Replace nkf's getchar/putchar for variable modification */
+/* we never use getc, ungetc */
+
+#undef getc
+#undef ungetc
+#define getc(f) (input_ctr>=i_len?-1:input[input_ctr++])
+#define ungetc(c,f) input_ctr--
+
+#define INCSIZE 32
+#undef putchar
+#undef TRUE
+#undef FALSE
+#define putchar(c) rb_nkf_putchar(c)
+
+/* Input/Output pointers */
+
+static unsigned char *output;
+static unsigned char *input;
+static int input_ctr;
+static int i_len;
+static int output_ctr;
+static int o_len;
+static int incsize;
+
+static VALUE result;
+
+static int
+rb_nkf_putchar(unsigned int c)
+{
+ if (output_ctr >= o_len) {
+ o_len += incsize;
+ rb_str_resize(result, o_len);
+ incsize *= 2;
+ output = (unsigned char *)RSTRING_PTR(result);
+ }
+ output[output_ctr++] = c;
+
+ return c;
+}
+
+/* Include kanji filter main part */
+/* getchar and putchar will be replaced during inclusion */
+
+#define PERL_XS 1
+#include "nkf-utf8/config.h"
+#include "nkf-utf8/utf8tbl.c"
+#include "nkf-utf8/nkf.c"
+
+rb_encoding* rb_nkf_enc_get(const char *name)
+{
+ int idx = rb_enc_find_index(name);
+ if (idx < 0) {
+ nkf_encoding *nkf_enc = nkf_enc_find(name);
+ idx = rb_enc_find_index(nkf_enc_name(nkf_enc_to_base_encoding(nkf_enc)));
+ if (idx < 0) {
+ idx = rb_define_dummy_encoding(name);
+ }
+ }
+ return rb_enc_from_index(idx);
+}
+
+int nkf_split_options(const char *arg)
+{
+ int count = 0;
+ unsigned char option[256];
+ int i = 0, j = 0;
+ int is_escaped = FALSE;
+ int is_single_quoted = FALSE;
+ int is_double_quoted = FALSE;
+ for(i = 0; arg[i]; i++){
+ if(j == 255){
+ return -1;
+ }else if(is_single_quoted){
+ if(arg[i] == '\''){
+ is_single_quoted = FALSE;
+ }else{
+ option[j++] = arg[i];
+ }
+ }else if(is_escaped){
+ is_escaped = FALSE;
+ option[j++] = arg[i];
+ }else if(arg[i] == '\\'){
+ is_escaped = TRUE;
+ }else if(is_double_quoted){
+ if(arg[i] == '"'){
+ is_double_quoted = FALSE;
+ }else{
+ option[j++] = arg[i];
+ }
+ }else if(arg[i] == '\''){
+ is_single_quoted = TRUE;
+ }else if(arg[i] == '"'){
+ is_double_quoted = TRUE;
+ }else if(arg[i] == ' '){
+ option[j] = '\0';
+ options(option);
+ j = 0;
+ }else{
+ option[j++] = arg[i];
+ }
+ }
+ if(j){
+ option[j] = '\0';
+ options(option);
+ }
+ return count;
+}
+
+/*
+ * call-seq:
+ * NKF.nkf(opt, str) => string
+ *
+ * Convert _str_ and return converted result.
+ * Conversion details are specified by _opt_ as String.
+ *
+ * require 'nkf'
+ * output = NKF.nkf("-s", input)
+ */
+
+static VALUE
+rb_nkf_convert(VALUE obj, VALUE opt, VALUE src)
+{
+ VALUE tmp;
+ reinit();
+ nkf_split_options(StringValueCStr(opt));
+ if (!output_encoding) rb_raise(rb_eArgError, "no output encoding given");
+
+ switch (nkf_enc_to_index(output_encoding)) {
+ case UTF_8_BOM: output_encoding = nkf_enc_from_index(UTF_8); break;
+ case UTF_16BE_BOM: output_encoding = nkf_enc_from_index(UTF_16BE); break;
+ case UTF_16LE_BOM: output_encoding = nkf_enc_from_index(UTF_16LE); break;
+ case UTF_32BE_BOM: output_encoding = nkf_enc_from_index(UTF_32BE); break;
+ case UTF_32LE_BOM: output_encoding = nkf_enc_from_index(UTF_32LE); break;
+ }
+ output_bom_f = FALSE;
+
+ incsize = INCSIZE;
+
+ input_ctr = 0;
+ input = (unsigned char *)StringValuePtr(src);
+ i_len = RSTRING_LENINT(src);
+ tmp = rb_str_new(0, i_len*3 + 10);
+
+ output_ctr = 0;
+ output = (unsigned char *)RSTRING_PTR(tmp);
+ o_len = RSTRING_LENINT(tmp);
+ *output = '\0';
+
+ /* use _result_ begin*/
+ result = tmp;
+ kanji_convert(NULL);
+ result = Qnil;
+ /* use _result_ end */
+
+ rb_str_set_len(tmp, output_ctr);
+
+ if (mimeout_f)
+ rb_enc_associate(tmp, rb_usascii_encoding());
+ else
+ rb_enc_associate(tmp, rb_nkf_enc_get(nkf_enc_name(output_encoding)));
+
+ return tmp;
+}
+
+
+/*
+ * call-seq:
+ * NKF.guess(str) => encoding
+ *
+ * Returns guessed encoding of _str_ by nkf routine.
+ *
+ */
+
+static VALUE
+rb_nkf_guess(VALUE obj, VALUE src)
+{
+ reinit();
+
+ input_ctr = 0;
+ input = (unsigned char *)StringValuePtr(src);
+ i_len = RSTRING_LENINT(src);
+
+ guess_f = TRUE;
+ kanji_convert( NULL );
+ guess_f = FALSE;
+
+ return rb_enc_from_encoding(rb_nkf_enc_get(get_guessed_code()));
+}
+
+
+/*
+ * NKF - Ruby extension for Network Kanji Filter
+ *
+ * == Description
+ *
+ * This is a Ruby Extension version of nkf (Network Kanji Filter).
+ * It converts the first argument and returns converted result. Conversion
+ * details are specified by flags as the first argument.
+ *
+ * *Nkf* is a yet another kanji code converter among networks, hosts and terminals.
+ * It converts input kanji code to designated kanji code
+ * such as ISO-2022-JP, Shift_JIS, EUC-JP, UTF-8 or UTF-16.
+ *
+ * One of the most unique faculty of *nkf* is the guess of the input kanji encodings.
+ * It currently recognizes ISO-2022-JP, Shift_JIS, EUC-JP, UTF-8 and UTF-16.
+ * So users needn't set the input kanji code explicitly.
+ *
+ * By default, X0201 kana is converted into X0208 kana.
+ * For X0201 kana, SO/SI, SSO and ESC-(-I methods are supported.
+ * For automatic code detection, nkf assumes no X0201 kana in Shift_JIS.
+ * To accept X0201 in Shift_JIS, use <b>-X</b>, <b>-x</b> or <b>-S</b>.
+ *
+ * == Flags
+ *
+ * === -b -u
+ *
+ * Output is buffered (DEFAULT), Output is unbuffered.
+ *
+ * === -j -s -e -w -w16 -w32
+ *
+ * Output code is ISO-2022-JP (7bit JIS), Shift_JIS, EUC-JP,
+ * UTF-8N, UTF-16BE, UTF-32BE.
+ * Without this option and compile option, ISO-2022-JP is assumed.
+ *
+ * === -J -S -E -W -W16 -W32
+ *
+ * Input assumption is JIS 7 bit, Shift_JIS, EUC-JP,
+ * UTF-8, UTF-16, UTF-32.
+ *
+ * ==== -J
+ *
+ * Assume JIS input. It also accepts EUC-JP.
+ * This is the default. This flag does not exclude Shift_JIS.
+ *
+ * ==== -S
+ *
+ * Assume Shift_JIS and X0201 kana input. It also accepts JIS.
+ * EUC-JP is recognized as X0201 kana. Without <b>-x</b> flag,
+ * X0201 kana (halfwidth kana) is converted into X0208.
+ *
+ * ==== -E
+ *
+ * Assume EUC-JP input. It also accepts JIS.
+ * Same as -J.
+ *
+ * === -t
+ *
+ * No conversion.
+ *
+ * === -i_
+ *
+ * Output sequence to designate JIS-kanji. (DEFAULT B)
+ *
+ * === -o_
+ *
+ * Output sequence to designate ASCII. (DEFAULT B)
+ *
+ * === -r
+ *
+ * {de/en}crypt ROT13/47
+ *
+ * === \-h[123] --hiragana --katakana --katakana-hiragana
+ *
+ * [-h1 --hiragana] Katakana to Hiragana conversion.
+ *
+ * [-h2 --katakana] Hiragana to Katakana conversion.
+ *
+ * [-h3 --katakana-hiragana] Katakana to Hiragana and Hiragana to Katakana conversion.
+ *
+ * === -T
+ *
+ * Text mode output (MS-DOS)
+ *
+ * === -l
+ *
+ * ISO8859-1 (Latin-1) support
+ *
+ * === -f[<code>m</code> [- <code>n</code>]]
+ *
+ * Folding on <code>m</code> length with <code>n</code> margin in a line.
+ * Without this option, fold length is 60 and fold margin is 10.
+ *
+ * === -F
+ *
+ * New line preserving line folding.
+ *
+ * === \-Z[0-3]
+ *
+ * Convert X0208 alphabet (Fullwidth Alphabets) to ASCII.
+ *
+ * [-Z -Z0] Convert X0208 alphabet to ASCII.
+ *
+ * [-Z1] Converts X0208 kankaku to single ASCII space.
+ *
+ * [-Z2] Converts X0208 kankaku to double ASCII spaces.
+ *
+ * [-Z3] Replacing Fullwidth >, <, ", & into '&gt;', '&lt;', '&quot;', '&amp;' as in HTML.
+ *
+ * === -X -x
+ *
+ * Assume X0201 kana in MS-Kanji.
+ * With <b>-X</b> or without this option, X0201 is converted into X0208 Kana.
+ * With <b>-x</b>, try to preserve X0208 kana and do not convert X0201 kana to X0208.
+ * In JIS output, ESC-(-I is used. In EUC output, SSO is used.
+ *
+ * === \-B[0-2]
+ *
+ * Assume broken JIS-Kanji input, which lost ESC.
+ * Useful when your site is using old B-News Nihongo patch.
+ *
+ * [-B1] allows any char after ESC-( or ESC-$.
+ *
+ * [-B2] forces ASCII after NL.
+ *
+ * === -I
+ *
+ * Replacing non iso-2022-jp char into a geta character
+ * (substitute character in Japanese).
+ *
+ * === -d -c
+ *
+ * Delete \r in line feed, Add \r in line feed.
+ *
+ * === \-m[BQN0]
+ *
+ * MIME ISO-2022-JP/ISO8859-1 decode. (DEFAULT)
+ * To see ISO8859-1 (Latin-1) -l is necessary.
+ *
+ * [-mB] Decode MIME base64 encoded stream. Remove header or other part before
+ * conversion.
+ *
+ * [-mQ] Decode MIME quoted stream. '_' in quoted stream is converted to space.
+ *
+ * [-mN] Non-strict decoding.
+ * It allows line break in the middle of the base64 encoding.
+ *
+ * [-m0] No MIME decode.
+ *
+ * === -M
+ *
+ * MIME encode. Header style. All ASCII code and control characters are intact.
+ * Kanji conversion is performed before encoding, so this cannot be used as a picture encoder.
+ *
+ * [-MB] MIME encode Base64 stream.
+ *
+ * [-MQ] Perform quoted encoding.
+ *
+ * === -l
+ *
+ * Input and output code is ISO8859-1 (Latin-1) and ISO-2022-JP.
+ * <b>-s</b>, <b>-e</b> and <b>-x</b> are not compatible with this option.
+ *
+ * === \-L[uwm]
+ *
+ * new line mode
+ * Without this option, nkf doesn't convert line breaks.
+ *
+ * [-Lu] unix (LF)
+ *
+ * [-Lw] windows (CRLF)
+ *
+ * [-Lm] mac (CR)
+ *
+ * === --fj --unix --mac --msdos --windows
+ *
+ * convert for these system
+ *
+ * === --jis --euc --sjis --mime --base64
+ *
+ * convert for named code
+ *
+ * === --jis-input --euc-input --sjis-input --mime-input --base64-input
+ *
+ * assume input system
+ *
+ * === --ic=<code>input codeset</code> --oc=<code>output codeset</code>
+ *
+ * Set the input or output codeset.
+ * NKF supports following codesets and those codeset name are case insensitive.
+ *
+ * [ISO-2022-JP] a.k.a. RFC1468, 7bit JIS, JUNET
+ *
+ * [EUC-JP (eucJP-nkf)] a.k.a. AT&T JIS, Japanese EUC, UJIS
+ *
+ * [eucJP-ascii] a.k.a. x-eucjp-open-19970715-ascii
+ *
+ * [eucJP-ms] a.k.a. x-eucjp-open-19970715-ms
+ *
+ * [CP51932] Microsoft Version of EUC-JP.
+ *
+ * [Shift_JIS] SJIS, MS-Kanji
+ *
+ * [Windows-31J] a.k.a. CP932
+ *
+ * [UTF-8] same as UTF-8N
+ *
+ * [UTF-8N] UTF-8 without BOM
+ *
+ * [UTF-8-BOM] UTF-8 with BOM
+ *
+ * [UTF-16] same as UTF-16BE
+ *
+ * [UTF-16BE] UTF-16 Big Endian without BOM
+ *
+ * [UTF-16BE-BOM] UTF-16 Big Endian with BOM
+ *
+ * [UTF-16LE] UTF-16 Little Endian without BOM
+ *
+ * [UTF-16LE-BOM] UTF-16 Little Endian with BOM
+ *
+ * [UTF-32] same as UTF-32BE
+ *
+ * [UTF-32BE] UTF-32 Big Endian without BOM
+ *
+ * [UTF-32BE-BOM] UTF-32 Big Endian with BOM
+ *
+ * [UTF-32LE] UTF-32 Little Endian without BOM
+ *
+ * [UTF-32LE-BOM] UTF-32 Little Endian with BOM
+ *
+ * [UTF8-MAC] NKDed UTF-8, a.k.a. UTF8-NFD (input only)
+ *
+ * === --fb-{skip, html, xml, perl, java, subchar}
+ *
+ * Specify the way that nkf handles unassigned characters.
+ * Without this option, --fb-skip is assumed.
+ *
+ * === --prefix= <code>escape character</code> <code>target character</code> ..
+ *
+ * When nkf converts to Shift_JIS,
+ * nkf adds a specified escape character to specified 2nd byte of Shift_JIS characters.
+ * 1st byte of argument is the escape character and following bytes are target characters.
+ *
+ * === --no-cp932ext
+ *
+ * Handle the characters extended in CP932 as unassigned characters.
+ *
+ * == --no-best-fit-chars
+ *
+ * When Unicode to Encoded byte conversion,
+ * don't convert characters which is not round trip safe.
+ * When Unicode to Unicode conversion,
+ * with this and -x option, nkf can be used as UTF converter.
+ * (In other words, without this and -x option, nkf doesn't save some characters)
+ *
+ * When nkf convert string which related to path, you should use this option.
+ *
+ * === --cap-input
+ *
+ * Decode hex encoded characters.
+ *
+ * === --url-input
+ *
+ * Unescape percent escaped characters.
+ *
+ * === --
+ *
+ * Ignore rest of -option.
+ */
+
+void
+Init_nkf(void)
+{
+ VALUE mNKF = rb_define_module("NKF");
+
+ rb_define_module_function(mNKF, "nkf", rb_nkf_convert, 2);
+ rb_define_module_function(mNKF, "guess", rb_nkf_guess, 1);
+ rb_define_alias(rb_singleton_class(mNKF), "guess", "guess");
+
+ rb_define_const(mNKF, "AUTO", Qnil);
+ rb_define_const(mNKF, "NOCONV", Qnil);
+ rb_define_const(mNKF, "UNKNOWN", Qnil);
+ rb_define_const(mNKF, "BINARY", rb_enc_from_encoding(rb_nkf_enc_get("BINARY")));
+ rb_define_const(mNKF, "ASCII", rb_enc_from_encoding(rb_nkf_enc_get("US-ASCII")));
+ rb_define_const(mNKF, "JIS", rb_enc_from_encoding(rb_nkf_enc_get("ISO-2022-JP")));
+ rb_define_const(mNKF, "EUC", rb_enc_from_encoding(rb_nkf_enc_get("EUC-JP")));
+ rb_define_const(mNKF, "SJIS", rb_enc_from_encoding(rb_nkf_enc_get("Shift_JIS")));
+ rb_define_const(mNKF, "UTF8", rb_enc_from_encoding(rb_utf8_encoding()));
+ rb_define_const(mNKF, "UTF16", rb_enc_from_encoding(rb_nkf_enc_get("UTF-16BE")));
+ rb_define_const(mNKF, "UTF32", rb_enc_from_encoding(rb_nkf_enc_get("UTF-32BE")));
+
+ /* Full version string of nkf */
+ rb_define_const(mNKF, "VERSION", rb_str_new2(RUBY_NKF_VERSION));
+ /* Version of nkf */
+ rb_define_const(mNKF, "NKF_VERSION", rb_str_new2(NKF_VERSION));
+ /* Release date of nkf */
+ rb_define_const(mNKF, "NKF_RELEASE_DATE", rb_str_new2(NKF_RELEASE_DATE));
+}
diff --git a/ext/nkf/nkf.gemspec b/ext/nkf/nkf.gemspec
new file mode 100644
index 0000000000..7f3bd4a4b1
--- /dev/null
+++ b/ext/nkf/nkf.gemspec
@@ -0,0 +1,24 @@
+Gem::Specification.new do |spec|
+ spec.name = "nkf"
+ spec.version = "0.1.2"
+ spec.authors = ["NARUSE Yui"]
+ spec.email = ["naruse@airemix.jp"]
+
+ spec.summary = %q{Ruby extension for Network Kanji Filter}
+ spec.description = %q{Ruby extension for Network Kanji Filter}
+ spec.homepage = "https://github.com/ruby/nkf"
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+end
diff --git a/ext/objspace/depend b/ext/objspace/depend
index a02168b06a..52797664e0 100644
--- a/ext/objspace/depend
+++ b/ext/objspace/depend
@@ -2,12 +2,10 @@
object_tracing.o: $(RUBY_EXTCONF_H)
object_tracing.o: $(arch_hdrdir)/ruby/config.h
object_tracing.o: $(hdrdir)/ruby/assert.h
-object_tracing.o: $(hdrdir)/ruby/atomic.h
object_tracing.o: $(hdrdir)/ruby/backward.h
object_tracing.o: $(hdrdir)/ruby/backward/2/assume.h
object_tracing.o: $(hdrdir)/ruby/backward/2/attributes.h
object_tracing.o: $(hdrdir)/ruby/backward/2/bool.h
-object_tracing.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
object_tracing.o: $(hdrdir)/ruby/backward/2/inttypes.h
object_tracing.o: $(hdrdir)/ruby/backward/2/limits.h
object_tracing.o: $(hdrdir)/ruby/backward/2/long_long.h
@@ -15,7 +13,6 @@ object_tracing.o: $(hdrdir)/ruby/backward/2/stdalign.h
object_tracing.o: $(hdrdir)/ruby/backward/2/stdarg.h
object_tracing.o: $(hdrdir)/ruby/debug.h
object_tracing.o: $(hdrdir)/ruby/defines.h
-object_tracing.o: $(hdrdir)/ruby/encoding.h
object_tracing.o: $(hdrdir)/ruby/intern.h
object_tracing.o: $(hdrdir)/ruby/internal/abi.h
object_tracing.o: $(hdrdir)/ruby/internal/anyargs.h
@@ -55,7 +52,6 @@ object_tracing.o: $(hdrdir)/ruby/internal/attr/noexcept.h
object_tracing.o: $(hdrdir)/ruby/internal/attr/noinline.h
object_tracing.o: $(hdrdir)/ruby/internal/attr/nonnull.h
object_tracing.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-object_tracing.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
object_tracing.o: $(hdrdir)/ruby/internal/attr/pure.h
object_tracing.o: $(hdrdir)/ruby/internal/attr/restrict.h
object_tracing.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -88,15 +84,6 @@ object_tracing.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
object_tracing.o: $(hdrdir)/ruby/internal/ctype.h
object_tracing.o: $(hdrdir)/ruby/internal/dllexport.h
object_tracing.o: $(hdrdir)/ruby/internal/dosish.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/re.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/string.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-object_tracing.o: $(hdrdir)/ruby/internal/encoding/transcode.h
object_tracing.o: $(hdrdir)/ruby/internal/error.h
object_tracing.o: $(hdrdir)/ruby/internal/eval.h
object_tracing.o: $(hdrdir)/ruby/internal/event.h
@@ -124,6 +111,7 @@ object_tracing.o: $(hdrdir)/ruby/internal/intern/enumerator.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/error.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/eval.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/file.h
+object_tracing.o: $(hdrdir)/ruby/internal/intern/gc.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/hash.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/io.h
object_tracing.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -154,12 +142,12 @@ object_tracing.o: $(hdrdir)/ruby/internal/memory.h
object_tracing.o: $(hdrdir)/ruby/internal/method.h
object_tracing.o: $(hdrdir)/ruby/internal/module.h
object_tracing.o: $(hdrdir)/ruby/internal/newobj.h
+object_tracing.o: $(hdrdir)/ruby/internal/rgengc.h
object_tracing.o: $(hdrdir)/ruby/internal/scan_args.h
object_tracing.o: $(hdrdir)/ruby/internal/special_consts.h
object_tracing.o: $(hdrdir)/ruby/internal/static_assert.h
object_tracing.o: $(hdrdir)/ruby/internal/stdalign.h
object_tracing.o: $(hdrdir)/ruby/internal/stdbool.h
-object_tracing.o: $(hdrdir)/ruby/internal/stdckdint.h
object_tracing.o: $(hdrdir)/ruby/internal/symbol.h
object_tracing.o: $(hdrdir)/ruby/internal/value.h
object_tracing.o: $(hdrdir)/ruby/internal/value_type.h
@@ -167,38 +155,13 @@ object_tracing.o: $(hdrdir)/ruby/internal/variable.h
object_tracing.o: $(hdrdir)/ruby/internal/warning_push.h
object_tracing.o: $(hdrdir)/ruby/internal/xmalloc.h
object_tracing.o: $(hdrdir)/ruby/missing.h
-object_tracing.o: $(hdrdir)/ruby/onigmo.h
-object_tracing.o: $(hdrdir)/ruby/oniguruma.h
object_tracing.o: $(hdrdir)/ruby/ruby.h
object_tracing.o: $(hdrdir)/ruby/st.h
object_tracing.o: $(hdrdir)/ruby/subst.h
-object_tracing.o: $(hdrdir)/ruby/thread_native.h
-object_tracing.o: $(top_srcdir)/ccan/check_type/check_type.h
-object_tracing.o: $(top_srcdir)/ccan/container_of/container_of.h
-object_tracing.o: $(top_srcdir)/ccan/list/list.h
-object_tracing.o: $(top_srcdir)/ccan/str/str.h
+object_tracing.o: $(top_srcdir)/gc.h
object_tracing.o: $(top_srcdir)/internal.h
-object_tracing.o: $(top_srcdir)/internal/array.h
-object_tracing.o: $(top_srcdir)/internal/basic_operators.h
-object_tracing.o: $(top_srcdir)/internal/compilers.h
-object_tracing.o: $(top_srcdir)/internal/gc.h
-object_tracing.o: $(top_srcdir)/internal/imemo.h
-object_tracing.o: $(top_srcdir)/internal/sanitizers.h
-object_tracing.o: $(top_srcdir)/internal/serial.h
-object_tracing.o: $(top_srcdir)/internal/static_assert.h
-object_tracing.o: $(top_srcdir)/internal/vm.h
-object_tracing.o: $(top_srcdir)/internal/warnings.h
-object_tracing.o: $(top_srcdir)/method.h
-object_tracing.o: $(top_srcdir)/node.h
-object_tracing.o: $(top_srcdir)/ruby_assert.h
-object_tracing.o: $(top_srcdir)/ruby_atomic.h
-object_tracing.o: $(top_srcdir)/rubyparser.h
-object_tracing.o: $(top_srcdir)/thread_pthread.h
-object_tracing.o: $(top_srcdir)/vm_core.h
-object_tracing.o: $(top_srcdir)/vm_opts.h
object_tracing.o: object_tracing.c
object_tracing.o: objspace.h
-object_tracing.o: {$(VPATH)}id.h
objspace.o: $(RUBY_EXTCONF_H)
objspace.o: $(arch_hdrdir)/ruby/config.h
objspace.o: $(hdrdir)/ruby/assert.h
@@ -254,7 +217,6 @@ objspace.o: $(hdrdir)/ruby/internal/attr/noexcept.h
objspace.o: $(hdrdir)/ruby/internal/attr/noinline.h
objspace.o: $(hdrdir)/ruby/internal/attr/nonnull.h
objspace.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-objspace.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
objspace.o: $(hdrdir)/ruby/internal/attr/pure.h
objspace.o: $(hdrdir)/ruby/internal/attr/restrict.h
objspace.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -324,6 +286,7 @@ objspace.o: $(hdrdir)/ruby/internal/intern/enumerator.h
objspace.o: $(hdrdir)/ruby/internal/intern/error.h
objspace.o: $(hdrdir)/ruby/internal/intern/eval.h
objspace.o: $(hdrdir)/ruby/internal/intern/file.h
+objspace.o: $(hdrdir)/ruby/internal/intern/gc.h
objspace.o: $(hdrdir)/ruby/internal/intern/hash.h
objspace.o: $(hdrdir)/ruby/internal/intern/io.h
objspace.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -354,12 +317,12 @@ objspace.o: $(hdrdir)/ruby/internal/memory.h
objspace.o: $(hdrdir)/ruby/internal/method.h
objspace.o: $(hdrdir)/ruby/internal/module.h
objspace.o: $(hdrdir)/ruby/internal/newobj.h
+objspace.o: $(hdrdir)/ruby/internal/rgengc.h
objspace.o: $(hdrdir)/ruby/internal/scan_args.h
objspace.o: $(hdrdir)/ruby/internal/special_consts.h
objspace.o: $(hdrdir)/ruby/internal/static_assert.h
objspace.o: $(hdrdir)/ruby/internal/stdalign.h
objspace.o: $(hdrdir)/ruby/internal/stdbool.h
-objspace.o: $(hdrdir)/ruby/internal/stdckdint.h
objspace.o: $(hdrdir)/ruby/internal/symbol.h
objspace.o: $(hdrdir)/ruby/internal/value.h
objspace.o: $(hdrdir)/ruby/internal/value_type.h
@@ -380,8 +343,7 @@ objspace.o: $(top_srcdir)/ccan/check_type/check_type.h
objspace.o: $(top_srcdir)/ccan/container_of/container_of.h
objspace.o: $(top_srcdir)/ccan/list/list.h
objspace.o: $(top_srcdir)/ccan/str/str.h
-objspace.o: $(top_srcdir)/constant.h
-objspace.o: $(top_srcdir)/debug_counter.h
+objspace.o: $(top_srcdir)/gc.h
objspace.o: $(top_srcdir)/id_table.h
objspace.o: $(top_srcdir)/internal.h
objspace.o: $(top_srcdir)/internal/array.h
@@ -394,21 +356,17 @@ objspace.o: $(top_srcdir)/internal/imemo.h
objspace.o: $(top_srcdir)/internal/sanitizers.h
objspace.o: $(top_srcdir)/internal/serial.h
objspace.o: $(top_srcdir)/internal/static_assert.h
-objspace.o: $(top_srcdir)/internal/variable.h
objspace.o: $(top_srcdir)/internal/vm.h
objspace.o: $(top_srcdir)/internal/warnings.h
objspace.o: $(top_srcdir)/method.h
objspace.o: $(top_srcdir)/node.h
objspace.o: $(top_srcdir)/ruby_assert.h
objspace.o: $(top_srcdir)/ruby_atomic.h
-objspace.o: $(top_srcdir)/rubyparser.h
objspace.o: $(top_srcdir)/shape.h
objspace.o: $(top_srcdir)/symbol.h
objspace.o: $(top_srcdir)/thread_pthread.h
objspace.o: $(top_srcdir)/vm_core.h
-objspace.o: $(top_srcdir)/vm_debug.h
objspace.o: $(top_srcdir)/vm_opts.h
-objspace.o: $(top_srcdir)/vm_sync.h
objspace.o: objspace.c
objspace.o: {$(VPATH)}id.h
objspace_dump.o: $(RUBY_EXTCONF_H)
@@ -467,7 +425,6 @@ objspace_dump.o: $(hdrdir)/ruby/internal/attr/noexcept.h
objspace_dump.o: $(hdrdir)/ruby/internal/attr/noinline.h
objspace_dump.o: $(hdrdir)/ruby/internal/attr/nonnull.h
objspace_dump.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-objspace_dump.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
objspace_dump.o: $(hdrdir)/ruby/internal/attr/pure.h
objspace_dump.o: $(hdrdir)/ruby/internal/attr/restrict.h
objspace_dump.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -536,6 +493,7 @@ objspace_dump.o: $(hdrdir)/ruby/internal/intern/enumerator.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/error.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/eval.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/file.h
+objspace_dump.o: $(hdrdir)/ruby/internal/intern/gc.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/hash.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/io.h
objspace_dump.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -566,12 +524,12 @@ objspace_dump.o: $(hdrdir)/ruby/internal/memory.h
objspace_dump.o: $(hdrdir)/ruby/internal/method.h
objspace_dump.o: $(hdrdir)/ruby/internal/module.h
objspace_dump.o: $(hdrdir)/ruby/internal/newobj.h
+objspace_dump.o: $(hdrdir)/ruby/internal/rgengc.h
objspace_dump.o: $(hdrdir)/ruby/internal/scan_args.h
objspace_dump.o: $(hdrdir)/ruby/internal/special_consts.h
objspace_dump.o: $(hdrdir)/ruby/internal/static_assert.h
objspace_dump.o: $(hdrdir)/ruby/internal/stdalign.h
objspace_dump.o: $(hdrdir)/ruby/internal/stdbool.h
-objspace_dump.o: $(hdrdir)/ruby/internal/stdckdint.h
objspace_dump.o: $(hdrdir)/ruby/internal/symbol.h
objspace_dump.o: $(hdrdir)/ruby/internal/value.h
objspace_dump.o: $(hdrdir)/ruby/internal/value_type.h
@@ -592,7 +550,7 @@ objspace_dump.o: $(top_srcdir)/ccan/container_of/container_of.h
objspace_dump.o: $(top_srcdir)/ccan/list/list.h
objspace_dump.o: $(top_srcdir)/ccan/str/str.h
objspace_dump.o: $(top_srcdir)/constant.h
-objspace_dump.o: $(top_srcdir)/debug_counter.h
+objspace_dump.o: $(top_srcdir)/gc.h
objspace_dump.o: $(top_srcdir)/id_table.h
objspace_dump.o: $(top_srcdir)/internal.h
objspace_dump.o: $(top_srcdir)/internal/array.h
@@ -602,7 +560,6 @@ objspace_dump.o: $(top_srcdir)/internal/compilers.h
objspace_dump.o: $(top_srcdir)/internal/gc.h
objspace_dump.o: $(top_srcdir)/internal/hash.h
objspace_dump.o: $(top_srcdir)/internal/imemo.h
-objspace_dump.o: $(top_srcdir)/internal/io.h
objspace_dump.o: $(top_srcdir)/internal/sanitizers.h
objspace_dump.o: $(top_srcdir)/internal/serial.h
objspace_dump.o: $(top_srcdir)/internal/static_assert.h
@@ -614,15 +571,11 @@ objspace_dump.o: $(top_srcdir)/method.h
objspace_dump.o: $(top_srcdir)/node.h
objspace_dump.o: $(top_srcdir)/ruby_assert.h
objspace_dump.o: $(top_srcdir)/ruby_atomic.h
-objspace_dump.o: $(top_srcdir)/rubyparser.h
objspace_dump.o: $(top_srcdir)/shape.h
objspace_dump.o: $(top_srcdir)/symbol.h
objspace_dump.o: $(top_srcdir)/thread_pthread.h
-objspace_dump.o: $(top_srcdir)/vm_callinfo.h
objspace_dump.o: $(top_srcdir)/vm_core.h
-objspace_dump.o: $(top_srcdir)/vm_debug.h
objspace_dump.o: $(top_srcdir)/vm_opts.h
-objspace_dump.o: $(top_srcdir)/vm_sync.h
objspace_dump.o: objspace.h
objspace_dump.o: objspace_dump.c
objspace_dump.o: {$(VPATH)}id.h
diff --git a/ext/objspace/lib/objspace.rb b/ext/objspace/lib/objspace.rb
index 47873f5112..6865fdda4c 100644
--- a/ext/objspace/lib/objspace.rb
+++ b/ext/objspace/lib/objspace.rb
@@ -11,15 +11,12 @@ module ObjectSpace
module_function
- # Dump the contents of a ruby object as JSON.
- #
- # _output_ can be one of: +:stdout+, +:file+, +:string+, or IO object.
+ # call-seq:
+ # ObjectSpace.dump(obj[, output: :string]) -> "{ ... }"
+ # ObjectSpace.dump(obj, output: :file) -> #<File:/tmp/rubyobj20131125-88733-1xkfmpv.json>
+ # ObjectSpace.dump(obj, output: :stdout) -> nil
#
- # * +:file+ means dumping to a tempfile and returning corresponding File object;
- # * +:stdout+ means printing the dump and returning +nil+;
- # * +:string+ means returning a string with the dump;
- # * if an instance of IO object is provided, the output goes there, and the object
- # is returned.
+ # Dump the contents of a ruby object as JSON.
#
# This method is only expected to work with C Ruby.
# This is an experimental method and is subject to change.
@@ -46,11 +43,16 @@ module ObjectSpace
end
- # Dump the contents of the ruby heap as JSON.
+ # call-seq:
+ # ObjectSpace.dump_all([output: :file]) -> #<File:/tmp/rubyheap20131125-88469-laoj3v.json>
+ # ObjectSpace.dump_all(output: :stdout) -> nil
+ # ObjectSpace.dump_all(output: :string) -> "{...}\n{...}\n..."
+ # ObjectSpace.dump_all(output: File.open('heap.json','w')) -> #<File:heap.json>
+ # ObjectSpace.dump_all(output: :string, since: 42) -> "{...}\n{...}\n..."
#
- # _output_ argument is the same as for #dump.
+ # Dump the contents of the ruby heap as JSON.
#
- # _full_ must be a boolean. If true, all heap slots are dumped including the empty ones (+T_NONE+).
+ # _full_ must be a boolean. If true all heap slots are dumped including the empty ones (T_NONE).
#
# _since_ must be a non-negative integer or +nil+.
#
@@ -102,11 +104,16 @@ module ObjectSpace
ret
end
- # Dump the contents of the ruby shape tree as JSON.
+ # call-seq:
+ # ObjectSpace.dump_shapes([output: :file]) -> #<File:/tmp/rubyshapes20131125-88469-laoj3v.json>
+ # ObjectSpace.dump_shapes(output: :stdout) -> nil
+ # ObjectSpace.dump_shapes(output: :string) -> "{...}\n{...}\n..."
+ # ObjectSpace.dump_shapes(output: File.open('shapes.json','w')) -> #<File:shapes.json>
+ # ObjectSpace.dump_all(output: :string, since: 42) -> "{...}\n{...}\n..."
#
- # _output_ argument is the same as for #dump.
+ # Dump the contents of the ruby shape tree as JSON.
#
- # If _since_ is a positive integer, only shapes newer than the provided
+ # If _shapes_ is a positive integer, only shapes newer than the provided
# shape id are dumped. The current shape_id can be accessed using <tt>RubyVM.stat(:next_shape_id)</tt>.
#
# This method is only expected to work with C Ruby.
diff --git a/ext/objspace/object_tracing.c b/ext/objspace/object_tracing.c
index c1c93c51f5..8c54d51eab 100644
--- a/ext/objspace/object_tracing.c
+++ b/ext/objspace/object_tracing.c
@@ -13,8 +13,8 @@
**********************************************************************/
+#include "gc.h"
#include "internal.h"
-#include "internal/gc.h"
#include "ruby/debug.h"
#include "objspace.h"
diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c
index e3269b5cd9..ca08604c95 100644
--- a/ext/objspace/objspace.c
+++ b/ext/objspace/objspace.c
@@ -12,13 +12,14 @@
**********************************************************************/
+#include "gc.h"
#include "internal.h"
#include "internal/class.h"
#include "internal/compilers.h"
-#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/imemo.h"
#include "internal/sanitizers.h"
+#include "node.h"
#include "ruby/io.h"
#include "ruby/re.h"
#include "ruby/st.h"
@@ -169,7 +170,8 @@ setup_hash(int argc, VALUE *argv)
hash = rb_hash_new();
}
else if (!RHASH_EMPTY_P(hash)) {
- rb_hash_foreach(hash, set_zero_i, (st_data_t)hash);
+ /* WB: no new reference */
+ st_foreach(RHASH_TBL_RAW(hash), set_zero_i, hash);
}
return hash;
@@ -335,6 +337,17 @@ count_symbols(int argc, VALUE *argv, VALUE os)
return hash;
}
+static void
+cn_i(VALUE v, void *n)
+{
+ size_t *nodes = (size_t *)n;
+
+ if (BUILTIN_TYPE(v) == T_NODE) {
+ size_t s = nd_type((NODE *)v);
+ nodes[s]++;
+ }
+}
+
/*
* call-seq:
* ObjectSpace.count_nodes([result_hash]) -> hash
@@ -361,7 +374,135 @@ count_symbols(int argc, VALUE *argv, VALUE os)
static VALUE
count_nodes(int argc, VALUE *argv, VALUE os)
{
- return setup_hash(argc, argv);
+ size_t nodes[NODE_LAST+1];
+ enum node_type i;
+ VALUE hash = setup_hash(argc, argv);
+
+ for (i = 0; i <= NODE_LAST; i++) {
+ nodes[i] = 0;
+ }
+
+ each_object_with_flags(cn_i, &nodes[0]);
+
+ for (i=0; i<NODE_LAST; i++) {
+ if (nodes[i] != 0) {
+ VALUE node;
+ switch (i) {
+#define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); goto set
+ COUNT_NODE(NODE_SCOPE);
+ COUNT_NODE(NODE_BLOCK);
+ COUNT_NODE(NODE_IF);
+ COUNT_NODE(NODE_UNLESS);
+ COUNT_NODE(NODE_CASE);
+ COUNT_NODE(NODE_CASE2);
+ COUNT_NODE(NODE_CASE3);
+ COUNT_NODE(NODE_WHEN);
+ COUNT_NODE(NODE_IN);
+ COUNT_NODE(NODE_WHILE);
+ COUNT_NODE(NODE_UNTIL);
+ COUNT_NODE(NODE_ITER);
+ COUNT_NODE(NODE_FOR);
+ COUNT_NODE(NODE_FOR_MASGN);
+ COUNT_NODE(NODE_BREAK);
+ COUNT_NODE(NODE_NEXT);
+ COUNT_NODE(NODE_REDO);
+ COUNT_NODE(NODE_RETRY);
+ COUNT_NODE(NODE_BEGIN);
+ COUNT_NODE(NODE_RESCUE);
+ COUNT_NODE(NODE_RESBODY);
+ COUNT_NODE(NODE_ENSURE);
+ COUNT_NODE(NODE_AND);
+ COUNT_NODE(NODE_OR);
+ COUNT_NODE(NODE_MASGN);
+ COUNT_NODE(NODE_LASGN);
+ COUNT_NODE(NODE_DASGN);
+ COUNT_NODE(NODE_GASGN);
+ COUNT_NODE(NODE_IASGN);
+ COUNT_NODE(NODE_CDECL);
+ COUNT_NODE(NODE_CVASGN);
+ COUNT_NODE(NODE_OP_ASGN1);
+ COUNT_NODE(NODE_OP_ASGN2);
+ COUNT_NODE(NODE_OP_ASGN_AND);
+ COUNT_NODE(NODE_OP_ASGN_OR);
+ COUNT_NODE(NODE_OP_CDECL);
+ COUNT_NODE(NODE_CALL);
+ COUNT_NODE(NODE_OPCALL);
+ COUNT_NODE(NODE_FCALL);
+ COUNT_NODE(NODE_VCALL);
+ COUNT_NODE(NODE_QCALL);
+ COUNT_NODE(NODE_SUPER);
+ COUNT_NODE(NODE_ZSUPER);
+ COUNT_NODE(NODE_LIST);
+ COUNT_NODE(NODE_ZLIST);
+ COUNT_NODE(NODE_VALUES);
+ COUNT_NODE(NODE_HASH);
+ COUNT_NODE(NODE_RETURN);
+ COUNT_NODE(NODE_YIELD);
+ COUNT_NODE(NODE_LVAR);
+ COUNT_NODE(NODE_DVAR);
+ COUNT_NODE(NODE_GVAR);
+ COUNT_NODE(NODE_IVAR);
+ COUNT_NODE(NODE_CONST);
+ COUNT_NODE(NODE_CVAR);
+ COUNT_NODE(NODE_NTH_REF);
+ COUNT_NODE(NODE_BACK_REF);
+ COUNT_NODE(NODE_MATCH);
+ COUNT_NODE(NODE_MATCH2);
+ COUNT_NODE(NODE_MATCH3);
+ COUNT_NODE(NODE_LIT);
+ COUNT_NODE(NODE_STR);
+ COUNT_NODE(NODE_DSTR);
+ COUNT_NODE(NODE_XSTR);
+ COUNT_NODE(NODE_DXSTR);
+ COUNT_NODE(NODE_EVSTR);
+ COUNT_NODE(NODE_DREGX);
+ COUNT_NODE(NODE_ONCE);
+ COUNT_NODE(NODE_ARGS);
+ COUNT_NODE(NODE_ARGS_AUX);
+ COUNT_NODE(NODE_OPT_ARG);
+ COUNT_NODE(NODE_KW_ARG);
+ COUNT_NODE(NODE_POSTARG);
+ COUNT_NODE(NODE_ARGSCAT);
+ COUNT_NODE(NODE_ARGSPUSH);
+ COUNT_NODE(NODE_SPLAT);
+ COUNT_NODE(NODE_BLOCK_PASS);
+ COUNT_NODE(NODE_DEFN);
+ COUNT_NODE(NODE_DEFS);
+ COUNT_NODE(NODE_ALIAS);
+ COUNT_NODE(NODE_VALIAS);
+ COUNT_NODE(NODE_UNDEF);
+ COUNT_NODE(NODE_CLASS);
+ COUNT_NODE(NODE_MODULE);
+ COUNT_NODE(NODE_SCLASS);
+ COUNT_NODE(NODE_COLON2);
+ COUNT_NODE(NODE_COLON3);
+ COUNT_NODE(NODE_DOT2);
+ COUNT_NODE(NODE_DOT3);
+ COUNT_NODE(NODE_FLIP2);
+ COUNT_NODE(NODE_FLIP3);
+ COUNT_NODE(NODE_SELF);
+ COUNT_NODE(NODE_NIL);
+ COUNT_NODE(NODE_TRUE);
+ COUNT_NODE(NODE_FALSE);
+ COUNT_NODE(NODE_ERRINFO);
+ COUNT_NODE(NODE_DEFINED);
+ COUNT_NODE(NODE_POSTEXE);
+ COUNT_NODE(NODE_DSYM);
+ COUNT_NODE(NODE_ATTRASGN);
+ COUNT_NODE(NODE_LAMBDA);
+ COUNT_NODE(NODE_ARYPTN);
+ COUNT_NODE(NODE_FNDPTN);
+ COUNT_NODE(NODE_HSHPTN);
+ COUNT_NODE(NODE_ERROR);
+#undef COUNT_NODE
+ case NODE_LAST: break;
+ }
+ UNREACHABLE;
+ set:
+ rb_hash_aset(hash, node, SIZET2NUM(nodes[i]));
+ }
+ }
+ return hash;
}
static void
@@ -577,7 +718,7 @@ reachable_object_from_i(VALUE obj, void *data_ptr)
VALUE key = obj;
VALUE val = obj;
- if (!rb_objspace_garbage_object_p(obj)) {
+ if (rb_objspace_markable_object_p(obj)) {
if (NIL_P(rb_hash_lookup(data->refs, key))) {
rb_hash_aset(data->refs, key, Qtrue);
@@ -623,7 +764,7 @@ collect_values(st_data_t key, st_data_t value, st_data_t data)
*
* With this method, you can find memory leaks.
*
- * This method is only expected to work with C Ruby.
+ * This method is only expected to work except with C Ruby.
*
* Example:
* ObjectSpace.reachable_objects_from(['a', 'b', 'c'])
@@ -643,7 +784,7 @@ collect_values(st_data_t key, st_data_t value, st_data_t data)
static VALUE
reachable_objects_from(VALUE self, VALUE obj)
{
- if (!RB_SPECIAL_CONST_P(obj)) {
+ if (rb_objspace_markable_object_p(obj)) {
struct rof_data data;
if (rb_typeddata_is_kind_of(obj, &iow_data_type)) {
@@ -690,7 +831,7 @@ reachable_object_from_root_i(const char *category, VALUE obj, void *ptr)
rb_hash_aset(data->categories, category_str, category_objects);
}
- if (!rb_objspace_garbage_object_p(obj) &&
+ if (rb_objspace_markable_object_p(obj) &&
obj != data->categories &&
obj != data->last_category_objects) {
if (rb_objspace_internal_object_p(obj)) {
@@ -813,7 +954,7 @@ void Init_objspace_dump(VALUE rb_mObjSpace);
*
* You need to <code>require 'objspace'</code> to use this extension module.
*
- * Generally, you *SHOULD* *NOT* use this library if you do not know
+ * Generally, you *SHOULD NOT* use this library if you do not know
* about the MRI implementation. Mainly, this library is for (memory)
* profiler developers and MRI developers who need to know about MRI
* memory usage.
diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c
index bb479b91c5..c3cc9a1e7b 100644
--- a/ext/objspace/objspace_dump.c
+++ b/ext/objspace/objspace_dump.c
@@ -12,13 +12,12 @@
**********************************************************************/
+#include "gc.h"
#include "id_table.h"
#include "internal.h"
#include "internal/array.h"
#include "internal/class.h"
-#include "internal/gc.h"
#include "internal/hash.h"
-#include "internal/io.h"
#include "internal/string.h"
#include "internal/sanitizers.h"
#include "symbol.h"
@@ -28,7 +27,6 @@
#include "ruby/debug.h"
#include "ruby/util.h"
#include "ruby/io.h"
-#include "vm_callinfo.h"
#include "vm_core.h"
RUBY_EXTERN const char ruby_hexdigits[];
@@ -168,8 +166,10 @@ dump_append_c(struct dump_config *dc, unsigned char c)
}
static void
-dump_append_ptr(struct dump_config *dc, VALUE ref)
+dump_append_ref(struct dump_config *dc, VALUE ref)
{
+ RUBY_ASSERT(ref > 0);
+
char buffer[roomof(sizeof(VALUE) * CHAR_BIT, 4) + rb_strlen_lit("\"0x\"")];
char *buffer_start, *buffer_end;
@@ -186,14 +186,6 @@ dump_append_ptr(struct dump_config *dc, VALUE ref)
}
static void
-dump_append_ref(struct dump_config *dc, VALUE ref)
-{
- RUBY_ASSERT(ref > 0);
- dump_append_ptr(dc, ref);
-}
-
-
-static void
dump_append_string_value(struct dump_config *dc, VALUE obj)
{
long i;
@@ -366,9 +358,8 @@ dump_append_string_content(struct dump_config *dc, VALUE obj)
static inline void
dump_append_id(struct dump_config *dc, ID id)
{
- VALUE str = rb_sym2str(ID2SYM(id));
- if (RTEST(str)) {
- dump_append_string_value(dc, str);
+ if (is_instance_id(id)) {
+ dump_append_string_value(dc, rb_sym2str(ID2SYM(id)));
}
else {
dump_append(dc, "\"ID_INTERNAL(");
@@ -386,7 +377,6 @@ dump_object(VALUE obj, struct dump_config *dc)
rb_io_t *fptr;
ID flags[RB_OBJ_GC_FLAGS_MAX];
size_t n, i;
- ID mid;
if (SPECIAL_CONST_P(obj)) {
dump_append_special_const(dc, obj);
@@ -438,33 +428,6 @@ dump_object(VALUE obj, struct dump_config *dc)
dump_append(dc, ", \"imemo_type\":\"");
dump_append(dc, rb_imemo_name(imemo_type(obj)));
dump_append(dc, "\"");
-
- switch (imemo_type(obj)) {
- case imemo_callinfo:
- mid = vm_ci_mid((const struct rb_callinfo *)obj);
- if (mid != 0) {
- dump_append(dc, ", \"mid\":");
- dump_append_id(dc, mid);
- }
- break;
-
- case imemo_callcache:
- mid = vm_cc_cme((const struct rb_callcache *)obj)->called_id;
- if (mid != 0) {
- dump_append(dc, ", \"called_id\":");
- dump_append_id(dc, mid);
-
- VALUE klass = ((const struct rb_callcache *)obj)->klass;
- if (klass != 0) {
- dump_append(dc, ", \"receiver_class\":");
- dump_append_ref(dc, klass);
- }
- }
- break;
-
- default:
- break;
- }
break;
case T_SYMBOL:
@@ -476,8 +439,6 @@ dump_object(VALUE obj, struct dump_config *dc)
dump_append(dc, ", \"embedded\":true");
if (FL_TEST(obj, RSTRING_FSTR))
dump_append(dc, ", \"fstring\":true");
- if (CHILLED_STRING_P(obj))
- dump_append(dc, ", \"chilled\":true");
if (STR_SHARED_P(obj))
dump_append(dc, ", \"shared\":true");
else
@@ -562,7 +523,7 @@ dump_object(VALUE obj, struct dump_config *dc)
}
}
- if (RCLASS_SINGLETON_P(obj)) {
+ if (FL_TEST(obj, FL_SINGLETON)) {
dump_append(dc, ", \"singleton\":true");
}
}
@@ -583,10 +544,6 @@ dump_object(VALUE obj, struct dump_config *dc)
break;
case T_OBJECT:
- if (FL_TEST(obj, ROBJECT_EMBED)) {
- dump_append(dc, ", \"embedded\":true");
- }
-
dump_append(dc, ", \"ivars\":");
dump_append_lu(dc, ROBJECT_IV_COUNT(obj));
if (rb_shape_obj_too_complex(obj)) {
@@ -794,6 +751,16 @@ shape_i(rb_shape_t *shape, void *data)
case SHAPE_FROZEN:
dump_append(dc, "\"FROZEN\"");
break;
+ case SHAPE_CAPACITY_CHANGE:
+ dump_append(dc, "\"CAPACITY_CHANGE\"");
+ dump_append(dc, ", \"capacity\":");
+ dump_append_sizet(dc, shape->capacity);
+ break;
+ case SHAPE_INITIAL_CAPACITY:
+ dump_append(dc, "\"INITIAL_CAPACITY\"");
+ dump_append(dc, ", \"capacity\":");
+ dump_append_sizet(dc, shape->capacity);
+ break;
case SHAPE_T_OBJECT:
dump_append(dc, "\"T_OBJECT\"");
break;
diff --git a/ext/openssl/History.md b/ext/openssl/History.md
index 3249f6617a..1e0df7dd87 100644
--- a/ext/openssl/History.md
+++ b/ext/openssl/History.md
@@ -1,43 +1,3 @@
-Version 3.2.0
-=============
-
-Compatibility
--------------
-
-* Ruby >= 2.7
- - Support for Ruby 2.6 has been removed. Note that Ruby 2.6 reached the
- end-of-life in 2022-04.
- [[GitHub #639]](https://github.com/ruby/openssl/pull/639)
-* OpenSSL >= 1.0.2 or LibreSSL >= 3.1
-
-Notable changes
----------------
-
-* Add a stub gemspec for JRuby, which depends on the `jruby-openssl` gem.
- [[GitHub #598]](https://github.com/ruby/openssl/pull/598)
-* Add support for the FIPS module in OpenSSL 3.0/3.1.
- [[GitHub #608]](https://github.com/ruby/openssl/pull/608)
-* Rework `OpenSSL::PKey` routines for loading DER or PEM encoded keys for better
- compatibility with OpenSSL 3.0/3.1 with the FIPS module.
- [[GitHub #615]](https://github.com/ruby/openssl/pull/615)
- [[GitHub #669]](https://github.com/ruby/openssl/pull/669)
-* Add `OpenSSL::Provider` module for loading and unloading OpenSSL 3 providers.
- [[GitHub #635]](https://github.com/ruby/openssl/pull/635)
-* Add `OpenSSL::PKey.new_raw_private_key`, `.new_raw_public_key`,
- `OpenSSL::PKey::PKey#raw_private_key`, and `#raw_public_key` for public key
- algorithms that use "raw private/public key", such as X25519 and Ed25519.
- [[GitHub #646]](https://github.com/ruby/openssl/pull/646)
-* Improve OpenSSL error messages to include additional information when
- it is available in OpenSSL's error queue.
- [[GitHub #648]](https://github.com/ruby/openssl/pull/648)
-* Change `OpenSSL::SSL::SSLContext#ca_file=` and `#ca_path=` to raise
- `OpenSSL::SSL::SSLError` instead of printing a warning message.
- [[GitHub #659]](https://github.com/ruby/openssl/pull/659)
-* Allow `OpenSSL::X509::ExtensionFactory#create_extension` to take OIDs in the
- dotted-decimal notation.
- [[GitHub #141]](https://github.com/ruby/openssl/pull/141)
-
-
Version 3.1.0
=============
@@ -457,7 +417,7 @@ Security fixes
Bug fixes
---------
-* Fixed OpenSSL::PKey::\*.{new,generate} immediately aborting if the thread is
+* Fixed OpenSSL::PKey::*.{new,generate} immediately aborting if the thread is
interrupted.
[[Bug #14882]](https://bugs.ruby-lang.org/issues/14882)
[[GitHub #205]](https://github.com/ruby/openssl/pull/205)
diff --git a/ext/openssl/depend b/ext/openssl/depend
index 12c6793939..c38d224c85 100644
--- a/ext/openssl/depend
+++ b/ext/openssl/depend
@@ -57,7 +57,6 @@ ossl.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -126,6 +125,7 @@ ossl.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl.o: $(hdrdir)/ruby/internal/intern/error.h
ossl.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl.o: $(hdrdir)/ruby/internal/intern/io.h
ossl.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -156,12 +156,12 @@ ossl.o: $(hdrdir)/ruby/internal/memory.h
ossl.o: $(hdrdir)/ruby/internal/method.h
ossl.o: $(hdrdir)/ruby/internal/module.h
ossl.o: $(hdrdir)/ruby/internal/newobj.h
+ossl.o: $(hdrdir)/ruby/internal/rgengc.h
ossl.o: $(hdrdir)/ruby/internal/scan_args.h
ossl.o: $(hdrdir)/ruby/internal/special_consts.h
ossl.o: $(hdrdir)/ruby/internal/static_assert.h
ossl.o: $(hdrdir)/ruby/internal/stdalign.h
ossl.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl.o: $(hdrdir)/ruby/internal/symbol.h
ossl.o: $(hdrdir)/ruby/internal/value.h
ossl.o: $(hdrdir)/ruby/internal/value_type.h
@@ -193,7 +193,6 @@ ossl.o: ossl_ocsp.h
ossl.o: ossl_pkcs12.h
ossl.o: ossl_pkcs7.h
ossl.o: ossl_pkey.h
-ossl.o: ossl_provider.h
ossl.o: ossl_rand.h
ossl.o: ossl_ssl.h
ossl.o: ossl_ts.h
@@ -252,7 +251,6 @@ ossl_asn1.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_asn1.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_asn1.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_asn1.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_asn1.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_asn1.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_asn1.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_asn1.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -321,6 +319,7 @@ ossl_asn1.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_asn1.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_asn1.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -351,12 +350,12 @@ ossl_asn1.o: $(hdrdir)/ruby/internal/memory.h
ossl_asn1.o: $(hdrdir)/ruby/internal/method.h
ossl_asn1.o: $(hdrdir)/ruby/internal/module.h
ossl_asn1.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_asn1.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_asn1.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_asn1.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_asn1.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_asn1.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_asn1.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_asn1.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_asn1.o: $(hdrdir)/ruby/internal/symbol.h
ossl_asn1.o: $(hdrdir)/ruby/internal/value.h
ossl_asn1.o: $(hdrdir)/ruby/internal/value_type.h
@@ -388,7 +387,6 @@ ossl_asn1.o: ossl_ocsp.h
ossl_asn1.o: ossl_pkcs12.h
ossl_asn1.o: ossl_pkcs7.h
ossl_asn1.o: ossl_pkey.h
-ossl_asn1.o: ossl_provider.h
ossl_asn1.o: ossl_rand.h
ossl_asn1.o: ossl_ssl.h
ossl_asn1.o: ossl_ts.h
@@ -447,7 +445,6 @@ ossl_bio.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_bio.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_bio.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_bio.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_bio.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_bio.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_bio.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_bio.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -516,6 +513,7 @@ ossl_bio.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_bio.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_bio.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -546,12 +544,12 @@ ossl_bio.o: $(hdrdir)/ruby/internal/memory.h
ossl_bio.o: $(hdrdir)/ruby/internal/method.h
ossl_bio.o: $(hdrdir)/ruby/internal/module.h
ossl_bio.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_bio.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_bio.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_bio.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_bio.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_bio.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_bio.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_bio.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_bio.o: $(hdrdir)/ruby/internal/symbol.h
ossl_bio.o: $(hdrdir)/ruby/internal/value.h
ossl_bio.o: $(hdrdir)/ruby/internal/value_type.h
@@ -583,7 +581,6 @@ ossl_bio.o: ossl_ocsp.h
ossl_bio.o: ossl_pkcs12.h
ossl_bio.o: ossl_pkcs7.h
ossl_bio.o: ossl_pkey.h
-ossl_bio.o: ossl_provider.h
ossl_bio.o: ossl_rand.h
ossl_bio.o: ossl_ssl.h
ossl_bio.o: ossl_ts.h
@@ -642,7 +639,6 @@ ossl_bn.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_bn.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_bn.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_bn.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_bn.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_bn.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_bn.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_bn.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -711,6 +707,7 @@ ossl_bn.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_bn.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_bn.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -741,12 +738,12 @@ ossl_bn.o: $(hdrdir)/ruby/internal/memory.h
ossl_bn.o: $(hdrdir)/ruby/internal/method.h
ossl_bn.o: $(hdrdir)/ruby/internal/module.h
ossl_bn.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_bn.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_bn.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_bn.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_bn.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_bn.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_bn.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_bn.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_bn.o: $(hdrdir)/ruby/internal/symbol.h
ossl_bn.o: $(hdrdir)/ruby/internal/value.h
ossl_bn.o: $(hdrdir)/ruby/internal/value_type.h
@@ -779,7 +776,6 @@ ossl_bn.o: ossl_ocsp.h
ossl_bn.o: ossl_pkcs12.h
ossl_bn.o: ossl_pkcs7.h
ossl_bn.o: ossl_pkey.h
-ossl_bn.o: ossl_provider.h
ossl_bn.o: ossl_rand.h
ossl_bn.o: ossl_ssl.h
ossl_bn.o: ossl_ts.h
@@ -838,7 +834,6 @@ ossl_cipher.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_cipher.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_cipher.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_cipher.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_cipher.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_cipher.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_cipher.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_cipher.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -907,6 +902,7 @@ ossl_cipher.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_cipher.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_cipher.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -937,12 +933,12 @@ ossl_cipher.o: $(hdrdir)/ruby/internal/memory.h
ossl_cipher.o: $(hdrdir)/ruby/internal/method.h
ossl_cipher.o: $(hdrdir)/ruby/internal/module.h
ossl_cipher.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_cipher.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_cipher.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_cipher.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_cipher.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_cipher.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_cipher.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_cipher.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_cipher.o: $(hdrdir)/ruby/internal/symbol.h
ossl_cipher.o: $(hdrdir)/ruby/internal/value.h
ossl_cipher.o: $(hdrdir)/ruby/internal/value_type.h
@@ -974,7 +970,6 @@ ossl_cipher.o: ossl_ocsp.h
ossl_cipher.o: ossl_pkcs12.h
ossl_cipher.o: ossl_pkcs7.h
ossl_cipher.o: ossl_pkey.h
-ossl_cipher.o: ossl_provider.h
ossl_cipher.o: ossl_rand.h
ossl_cipher.o: ossl_ssl.h
ossl_cipher.o: ossl_ts.h
@@ -1033,7 +1028,6 @@ ossl_config.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_config.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_config.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_config.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_config.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_config.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_config.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_config.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1102,6 +1096,7 @@ ossl_config.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_config.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_config.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1132,12 +1127,12 @@ ossl_config.o: $(hdrdir)/ruby/internal/memory.h
ossl_config.o: $(hdrdir)/ruby/internal/method.h
ossl_config.o: $(hdrdir)/ruby/internal/module.h
ossl_config.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_config.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_config.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_config.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_config.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_config.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_config.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_config.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_config.o: $(hdrdir)/ruby/internal/symbol.h
ossl_config.o: $(hdrdir)/ruby/internal/value.h
ossl_config.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1169,7 +1164,6 @@ ossl_config.o: ossl_ocsp.h
ossl_config.o: ossl_pkcs12.h
ossl_config.o: ossl_pkcs7.h
ossl_config.o: ossl_pkey.h
-ossl_config.o: ossl_provider.h
ossl_config.o: ossl_rand.h
ossl_config.o: ossl_ssl.h
ossl_config.o: ossl_ts.h
@@ -1228,7 +1222,6 @@ ossl_digest.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_digest.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_digest.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_digest.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_digest.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_digest.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_digest.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_digest.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1297,6 +1290,7 @@ ossl_digest.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_digest.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_digest.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1327,12 +1321,12 @@ ossl_digest.o: $(hdrdir)/ruby/internal/memory.h
ossl_digest.o: $(hdrdir)/ruby/internal/method.h
ossl_digest.o: $(hdrdir)/ruby/internal/module.h
ossl_digest.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_digest.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_digest.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_digest.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_digest.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_digest.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_digest.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_digest.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_digest.o: $(hdrdir)/ruby/internal/symbol.h
ossl_digest.o: $(hdrdir)/ruby/internal/value.h
ossl_digest.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1364,7 +1358,6 @@ ossl_digest.o: ossl_ocsp.h
ossl_digest.o: ossl_pkcs12.h
ossl_digest.o: ossl_pkcs7.h
ossl_digest.o: ossl_pkey.h
-ossl_digest.o: ossl_provider.h
ossl_digest.o: ossl_rand.h
ossl_digest.o: ossl_ssl.h
ossl_digest.o: ossl_ts.h
@@ -1423,7 +1416,6 @@ ossl_engine.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_engine.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_engine.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_engine.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_engine.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_engine.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_engine.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_engine.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1492,6 +1484,7 @@ ossl_engine.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_engine.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_engine.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1522,12 +1515,12 @@ ossl_engine.o: $(hdrdir)/ruby/internal/memory.h
ossl_engine.o: $(hdrdir)/ruby/internal/method.h
ossl_engine.o: $(hdrdir)/ruby/internal/module.h
ossl_engine.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_engine.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_engine.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_engine.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_engine.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_engine.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_engine.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_engine.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_engine.o: $(hdrdir)/ruby/internal/symbol.h
ossl_engine.o: $(hdrdir)/ruby/internal/value.h
ossl_engine.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1559,7 +1552,6 @@ ossl_engine.o: ossl_ocsp.h
ossl_engine.o: ossl_pkcs12.h
ossl_engine.o: ossl_pkcs7.h
ossl_engine.o: ossl_pkey.h
-ossl_engine.o: ossl_provider.h
ossl_engine.o: ossl_rand.h
ossl_engine.o: ossl_ssl.h
ossl_engine.o: ossl_ts.h
@@ -1618,7 +1610,6 @@ ossl_hmac.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_hmac.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_hmac.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_hmac.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_hmac.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_hmac.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_hmac.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_hmac.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1687,6 +1678,7 @@ ossl_hmac.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_hmac.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_hmac.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1717,12 +1709,12 @@ ossl_hmac.o: $(hdrdir)/ruby/internal/memory.h
ossl_hmac.o: $(hdrdir)/ruby/internal/method.h
ossl_hmac.o: $(hdrdir)/ruby/internal/module.h
ossl_hmac.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_hmac.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_hmac.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_hmac.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_hmac.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_hmac.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_hmac.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_hmac.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_hmac.o: $(hdrdir)/ruby/internal/symbol.h
ossl_hmac.o: $(hdrdir)/ruby/internal/value.h
ossl_hmac.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1754,7 +1746,6 @@ ossl_hmac.o: ossl_ocsp.h
ossl_hmac.o: ossl_pkcs12.h
ossl_hmac.o: ossl_pkcs7.h
ossl_hmac.o: ossl_pkey.h
-ossl_hmac.o: ossl_provider.h
ossl_hmac.o: ossl_rand.h
ossl_hmac.o: ossl_ssl.h
ossl_hmac.o: ossl_ts.h
@@ -1813,7 +1804,6 @@ ossl_kdf.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_kdf.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_kdf.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_kdf.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_kdf.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_kdf.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_kdf.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_kdf.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1882,6 +1872,7 @@ ossl_kdf.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_kdf.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_kdf.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1912,12 +1903,12 @@ ossl_kdf.o: $(hdrdir)/ruby/internal/memory.h
ossl_kdf.o: $(hdrdir)/ruby/internal/method.h
ossl_kdf.o: $(hdrdir)/ruby/internal/module.h
ossl_kdf.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_kdf.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_kdf.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_kdf.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_kdf.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_kdf.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_kdf.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_kdf.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_kdf.o: $(hdrdir)/ruby/internal/symbol.h
ossl_kdf.o: $(hdrdir)/ruby/internal/value.h
ossl_kdf.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1949,7 +1940,6 @@ ossl_kdf.o: ossl_ocsp.h
ossl_kdf.o: ossl_pkcs12.h
ossl_kdf.o: ossl_pkcs7.h
ossl_kdf.o: ossl_pkey.h
-ossl_kdf.o: ossl_provider.h
ossl_kdf.o: ossl_rand.h
ossl_kdf.o: ossl_ssl.h
ossl_kdf.o: ossl_ts.h
@@ -2008,7 +1998,6 @@ ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2077,6 +2066,7 @@ ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2107,12 +2097,12 @@ ossl_ns_spki.o: $(hdrdir)/ruby/internal/memory.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/method.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/module.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_ns_spki.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_ns_spki.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/symbol.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/value.h
ossl_ns_spki.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2144,7 +2134,6 @@ ossl_ns_spki.o: ossl_ocsp.h
ossl_ns_spki.o: ossl_pkcs12.h
ossl_ns_spki.o: ossl_pkcs7.h
ossl_ns_spki.o: ossl_pkey.h
-ossl_ns_spki.o: ossl_provider.h
ossl_ns_spki.o: ossl_rand.h
ossl_ns_spki.o: ossl_ssl.h
ossl_ns_spki.o: ossl_ts.h
@@ -2203,7 +2192,6 @@ ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2272,6 +2260,7 @@ ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2302,12 +2291,12 @@ ossl_ocsp.o: $(hdrdir)/ruby/internal/memory.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/method.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/module.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_ocsp.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_ocsp.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/symbol.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/value.h
ossl_ocsp.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2339,7 +2328,6 @@ ossl_ocsp.o: ossl_ocsp.h
ossl_ocsp.o: ossl_pkcs12.h
ossl_ocsp.o: ossl_pkcs7.h
ossl_ocsp.o: ossl_pkey.h
-ossl_ocsp.o: ossl_provider.h
ossl_ocsp.o: ossl_rand.h
ossl_ocsp.o: ossl_ssl.h
ossl_ocsp.o: ossl_ts.h
@@ -2398,7 +2386,6 @@ ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2467,6 +2454,7 @@ ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2497,12 +2485,12 @@ ossl_pkcs12.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/method.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/module.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkcs12.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_pkcs12.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/value.h
ossl_pkcs12.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2534,7 +2522,6 @@ ossl_pkcs12.o: ossl_pkcs12.c
ossl_pkcs12.o: ossl_pkcs12.h
ossl_pkcs12.o: ossl_pkcs7.h
ossl_pkcs12.o: ossl_pkey.h
-ossl_pkcs12.o: ossl_provider.h
ossl_pkcs12.o: ossl_rand.h
ossl_pkcs12.o: ossl_ssl.h
ossl_pkcs12.o: ossl_ts.h
@@ -2593,7 +2580,6 @@ ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2662,6 +2648,7 @@ ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2692,12 +2679,12 @@ ossl_pkcs7.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/method.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/module.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkcs7.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_pkcs7.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/value.h
ossl_pkcs7.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2729,7 +2716,6 @@ ossl_pkcs7.o: ossl_pkcs12.h
ossl_pkcs7.o: ossl_pkcs7.c
ossl_pkcs7.o: ossl_pkcs7.h
ossl_pkcs7.o: ossl_pkey.h
-ossl_pkcs7.o: ossl_provider.h
ossl_pkcs7.o: ossl_rand.h
ossl_pkcs7.o: ossl_ssl.h
ossl_pkcs7.o: ossl_ts.h
@@ -2788,7 +2774,6 @@ ossl_pkey.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkey.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkey.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkey.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkey.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkey.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkey.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkey.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2857,6 +2842,7 @@ ossl_pkey.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkey.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkey.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2887,12 +2873,12 @@ ossl_pkey.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkey.o: $(hdrdir)/ruby/internal/method.h
ossl_pkey.o: $(hdrdir)/ruby/internal/module.h
ossl_pkey.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkey.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkey.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkey.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkey.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkey.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_pkey.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkey.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkey.o: $(hdrdir)/ruby/internal/value.h
ossl_pkey.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2924,7 +2910,6 @@ ossl_pkey.o: ossl_pkcs12.h
ossl_pkey.o: ossl_pkcs7.h
ossl_pkey.o: ossl_pkey.c
ossl_pkey.o: ossl_pkey.h
-ossl_pkey.o: ossl_provider.h
ossl_pkey.o: ossl_rand.h
ossl_pkey.o: ossl_ssl.h
ossl_pkey.o: ossl_ts.h
@@ -2983,7 +2968,6 @@ ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -3052,6 +3036,7 @@ ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -3082,12 +3067,12 @@ ossl_pkey_dh.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/method.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/module.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkey_dh.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_pkey_dh.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/value.h
ossl_pkey_dh.o: $(hdrdir)/ruby/internal/value_type.h
@@ -3119,7 +3104,6 @@ ossl_pkey_dh.o: ossl_pkcs12.h
ossl_pkey_dh.o: ossl_pkcs7.h
ossl_pkey_dh.o: ossl_pkey.h
ossl_pkey_dh.o: ossl_pkey_dh.c
-ossl_pkey_dh.o: ossl_provider.h
ossl_pkey_dh.o: ossl_rand.h
ossl_pkey_dh.o: ossl_ssl.h
ossl_pkey_dh.o: ossl_ts.h
@@ -3178,7 +3162,6 @@ ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -3247,6 +3230,7 @@ ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -3277,12 +3261,12 @@ ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/method.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/module.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/value.h
ossl_pkey_dsa.o: $(hdrdir)/ruby/internal/value_type.h
@@ -3314,7 +3298,6 @@ ossl_pkey_dsa.o: ossl_pkcs12.h
ossl_pkey_dsa.o: ossl_pkcs7.h
ossl_pkey_dsa.o: ossl_pkey.h
ossl_pkey_dsa.o: ossl_pkey_dsa.c
-ossl_pkey_dsa.o: ossl_provider.h
ossl_pkey_dsa.o: ossl_rand.h
ossl_pkey_dsa.o: ossl_ssl.h
ossl_pkey_dsa.o: ossl_ts.h
@@ -3373,7 +3356,6 @@ ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -3442,6 +3424,7 @@ ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -3472,12 +3455,12 @@ ossl_pkey_ec.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/method.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/module.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkey_ec.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_pkey_ec.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/value.h
ossl_pkey_ec.o: $(hdrdir)/ruby/internal/value_type.h
@@ -3509,7 +3492,6 @@ ossl_pkey_ec.o: ossl_pkcs12.h
ossl_pkey_ec.o: ossl_pkcs7.h
ossl_pkey_ec.o: ossl_pkey.h
ossl_pkey_ec.o: ossl_pkey_ec.c
-ossl_pkey_ec.o: ossl_provider.h
ossl_pkey_ec.o: ossl_rand.h
ossl_pkey_ec.o: ossl_ssl.h
ossl_pkey_ec.o: ossl_ts.h
@@ -3568,7 +3550,6 @@ ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -3637,6 +3618,7 @@ ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -3667,12 +3649,12 @@ ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/memory.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/method.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/module.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/symbol.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/value.h
ossl_pkey_rsa.o: $(hdrdir)/ruby/internal/value_type.h
@@ -3704,206 +3686,10 @@ ossl_pkey_rsa.o: ossl_pkcs12.h
ossl_pkey_rsa.o: ossl_pkcs7.h
ossl_pkey_rsa.o: ossl_pkey.h
ossl_pkey_rsa.o: ossl_pkey_rsa.c
-ossl_pkey_rsa.o: ossl_provider.h
ossl_pkey_rsa.o: ossl_rand.h
ossl_pkey_rsa.o: ossl_ssl.h
ossl_pkey_rsa.o: ossl_ts.h
ossl_pkey_rsa.o: ossl_x509.h
-ossl_provider.o: $(RUBY_EXTCONF_H)
-ossl_provider.o: $(arch_hdrdir)/ruby/config.h
-ossl_provider.o: $(hdrdir)/ruby.h
-ossl_provider.o: $(hdrdir)/ruby/assert.h
-ossl_provider.o: $(hdrdir)/ruby/backward.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/assume.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/attributes.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/bool.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/inttypes.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/limits.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/long_long.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/stdalign.h
-ossl_provider.o: $(hdrdir)/ruby/backward/2/stdarg.h
-ossl_provider.o: $(hdrdir)/ruby/defines.h
-ossl_provider.o: $(hdrdir)/ruby/encoding.h
-ossl_provider.o: $(hdrdir)/ruby/intern.h
-ossl_provider.o: $(hdrdir)/ruby/internal/abi.h
-ossl_provider.o: $(hdrdir)/ruby/internal/anyargs.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-ossl_provider.o: $(hdrdir)/ruby/internal/assume.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/artificial.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/cold.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/const.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/error.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/format.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/noalias.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/noinline.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/pure.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/restrict.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/warning.h
-ossl_provider.o: $(hdrdir)/ruby/internal/attr/weakref.h
-ossl_provider.o: $(hdrdir)/ruby/internal/cast.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-ossl_provider.o: $(hdrdir)/ruby/internal/compiler_since.h
-ossl_provider.o: $(hdrdir)/ruby/internal/config.h
-ossl_provider.o: $(hdrdir)/ruby/internal/constant_p.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rarray.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rbasic.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rbignum.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rclass.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rdata.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rfile.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rhash.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/robject.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rregexp.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rstring.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rstruct.h
-ossl_provider.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-ossl_provider.o: $(hdrdir)/ruby/internal/ctype.h
-ossl_provider.o: $(hdrdir)/ruby/internal/dllexport.h
-ossl_provider.o: $(hdrdir)/ruby/internal/dosish.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/re.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/string.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-ossl_provider.o: $(hdrdir)/ruby/internal/encoding/transcode.h
-ossl_provider.o: $(hdrdir)/ruby/internal/error.h
-ossl_provider.o: $(hdrdir)/ruby/internal/eval.h
-ossl_provider.o: $(hdrdir)/ruby/internal/event.h
-ossl_provider.o: $(hdrdir)/ruby/internal/fl_type.h
-ossl_provider.o: $(hdrdir)/ruby/internal/gc.h
-ossl_provider.o: $(hdrdir)/ruby/internal/glob.h
-ossl_provider.o: $(hdrdir)/ruby/internal/globals.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/attribute.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/builtin.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/extension.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/feature.h
-ossl_provider.o: $(hdrdir)/ruby/internal/has/warning.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/array.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/bignum.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/class.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/compar.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/complex.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/cont.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/dir.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/enum.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/error.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/eval.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/file.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/hash.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/io.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/load.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/marshal.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/numeric.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/object.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/parse.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/proc.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/process.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/random.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/range.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/rational.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/re.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/ruby.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/select.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/signal.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/string.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/struct.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/thread.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/time.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/variable.h
-ossl_provider.o: $(hdrdir)/ruby/internal/intern/vm.h
-ossl_provider.o: $(hdrdir)/ruby/internal/interpreter.h
-ossl_provider.o: $(hdrdir)/ruby/internal/iterator.h
-ossl_provider.o: $(hdrdir)/ruby/internal/memory.h
-ossl_provider.o: $(hdrdir)/ruby/internal/method.h
-ossl_provider.o: $(hdrdir)/ruby/internal/module.h
-ossl_provider.o: $(hdrdir)/ruby/internal/newobj.h
-ossl_provider.o: $(hdrdir)/ruby/internal/scan_args.h
-ossl_provider.o: $(hdrdir)/ruby/internal/special_consts.h
-ossl_provider.o: $(hdrdir)/ruby/internal/static_assert.h
-ossl_provider.o: $(hdrdir)/ruby/internal/stdalign.h
-ossl_provider.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_provider.o: $(hdrdir)/ruby/internal/stdckdint.h
-ossl_provider.o: $(hdrdir)/ruby/internal/symbol.h
-ossl_provider.o: $(hdrdir)/ruby/internal/value.h
-ossl_provider.o: $(hdrdir)/ruby/internal/value_type.h
-ossl_provider.o: $(hdrdir)/ruby/internal/variable.h
-ossl_provider.o: $(hdrdir)/ruby/internal/warning_push.h
-ossl_provider.o: $(hdrdir)/ruby/internal/xmalloc.h
-ossl_provider.o: $(hdrdir)/ruby/io.h
-ossl_provider.o: $(hdrdir)/ruby/missing.h
-ossl_provider.o: $(hdrdir)/ruby/onigmo.h
-ossl_provider.o: $(hdrdir)/ruby/oniguruma.h
-ossl_provider.o: $(hdrdir)/ruby/ruby.h
-ossl_provider.o: $(hdrdir)/ruby/st.h
-ossl_provider.o: $(hdrdir)/ruby/subst.h
-ossl_provider.o: $(hdrdir)/ruby/thread.h
-ossl_provider.o: openssl_missing.h
-ossl_provider.o: ossl.h
-ossl_provider.o: ossl_asn1.h
-ossl_provider.o: ossl_bio.h
-ossl_provider.o: ossl_bn.h
-ossl_provider.o: ossl_cipher.h
-ossl_provider.o: ossl_config.h
-ossl_provider.o: ossl_digest.h
-ossl_provider.o: ossl_engine.h
-ossl_provider.o: ossl_hmac.h
-ossl_provider.o: ossl_kdf.h
-ossl_provider.o: ossl_ns_spki.h
-ossl_provider.o: ossl_ocsp.h
-ossl_provider.o: ossl_pkcs12.h
-ossl_provider.o: ossl_pkcs7.h
-ossl_provider.o: ossl_pkey.h
-ossl_provider.o: ossl_provider.c
-ossl_provider.o: ossl_provider.h
-ossl_provider.o: ossl_rand.h
-ossl_provider.o: ossl_ssl.h
-ossl_provider.o: ossl_ts.h
-ossl_provider.o: ossl_x509.h
ossl_rand.o: $(RUBY_EXTCONF_H)
ossl_rand.o: $(arch_hdrdir)/ruby/config.h
ossl_rand.o: $(hdrdir)/ruby.h
@@ -3958,7 +3744,6 @@ ossl_rand.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_rand.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_rand.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_rand.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_rand.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_rand.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_rand.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_rand.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -4027,6 +3812,7 @@ ossl_rand.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_rand.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_rand.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -4057,12 +3843,12 @@ ossl_rand.o: $(hdrdir)/ruby/internal/memory.h
ossl_rand.o: $(hdrdir)/ruby/internal/method.h
ossl_rand.o: $(hdrdir)/ruby/internal/module.h
ossl_rand.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_rand.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_rand.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_rand.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_rand.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_rand.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_rand.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_rand.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_rand.o: $(hdrdir)/ruby/internal/symbol.h
ossl_rand.o: $(hdrdir)/ruby/internal/value.h
ossl_rand.o: $(hdrdir)/ruby/internal/value_type.h
@@ -4093,7 +3879,6 @@ ossl_rand.o: ossl_ocsp.h
ossl_rand.o: ossl_pkcs12.h
ossl_rand.o: ossl_pkcs7.h
ossl_rand.o: ossl_pkey.h
-ossl_rand.o: ossl_provider.h
ossl_rand.o: ossl_rand.c
ossl_rand.o: ossl_rand.h
ossl_rand.o: ossl_ssl.h
@@ -4153,7 +3938,6 @@ ossl_ssl.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_ssl.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_ssl.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_ssl.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_ssl.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_ssl.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_ssl.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_ssl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -4222,6 +4006,7 @@ ossl_ssl.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_ssl.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_ssl.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -4252,12 +4037,12 @@ ossl_ssl.o: $(hdrdir)/ruby/internal/memory.h
ossl_ssl.o: $(hdrdir)/ruby/internal/method.h
ossl_ssl.o: $(hdrdir)/ruby/internal/module.h
ossl_ssl.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_ssl.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_ssl.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_ssl.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ssl.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_ssl.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_ssl.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_ssl.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_ssl.o: $(hdrdir)/ruby/internal/symbol.h
ossl_ssl.o: $(hdrdir)/ruby/internal/value.h
ossl_ssl.o: $(hdrdir)/ruby/internal/value_type.h
@@ -4288,7 +4073,6 @@ ossl_ssl.o: ossl_ocsp.h
ossl_ssl.o: ossl_pkcs12.h
ossl_ssl.o: ossl_pkcs7.h
ossl_ssl.o: ossl_pkey.h
-ossl_ssl.o: ossl_provider.h
ossl_ssl.o: ossl_rand.h
ossl_ssl.o: ossl_ssl.c
ossl_ssl.o: ossl_ssl.h
@@ -4348,7 +4132,6 @@ ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -4417,6 +4200,7 @@ ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -4447,12 +4231,12 @@ ossl_ssl_session.o: $(hdrdir)/ruby/internal/memory.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/method.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/module.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_ssl_session.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_ssl_session.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/symbol.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/value.h
ossl_ssl_session.o: $(hdrdir)/ruby/internal/value_type.h
@@ -4483,7 +4267,6 @@ ossl_ssl_session.o: ossl_ocsp.h
ossl_ssl_session.o: ossl_pkcs12.h
ossl_ssl_session.o: ossl_pkcs7.h
ossl_ssl_session.o: ossl_pkey.h
-ossl_ssl_session.o: ossl_provider.h
ossl_ssl_session.o: ossl_rand.h
ossl_ssl_session.o: ossl_ssl.h
ossl_ssl_session.o: ossl_ssl_session.c
@@ -4543,7 +4326,6 @@ ossl_ts.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_ts.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_ts.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_ts.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_ts.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_ts.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_ts.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_ts.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -4612,6 +4394,7 @@ ossl_ts.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_ts.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_ts.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -4642,12 +4425,12 @@ ossl_ts.o: $(hdrdir)/ruby/internal/memory.h
ossl_ts.o: $(hdrdir)/ruby/internal/method.h
ossl_ts.o: $(hdrdir)/ruby/internal/module.h
ossl_ts.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_ts.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_ts.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_ts.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_ts.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_ts.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_ts.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_ts.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_ts.o: $(hdrdir)/ruby/internal/symbol.h
ossl_ts.o: $(hdrdir)/ruby/internal/value.h
ossl_ts.o: $(hdrdir)/ruby/internal/value_type.h
@@ -4678,7 +4461,6 @@ ossl_ts.o: ossl_ocsp.h
ossl_ts.o: ossl_pkcs12.h
ossl_ts.o: ossl_pkcs7.h
ossl_ts.o: ossl_pkey.h
-ossl_ts.o: ossl_provider.h
ossl_ts.o: ossl_rand.h
ossl_ts.o: ossl_ssl.h
ossl_ts.o: ossl_ts.c
@@ -4738,7 +4520,6 @@ ossl_x509.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -4807,6 +4588,7 @@ ossl_x509.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -4837,12 +4619,12 @@ ossl_x509.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509.o: $(hdrdir)/ruby/internal/method.h
ossl_x509.o: $(hdrdir)/ruby/internal/module.h
ossl_x509.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_x509.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509.o: $(hdrdir)/ruby/internal/value.h
ossl_x509.o: $(hdrdir)/ruby/internal/value_type.h
@@ -4873,7 +4655,6 @@ ossl_x509.o: ossl_ocsp.h
ossl_x509.o: ossl_pkcs12.h
ossl_x509.o: ossl_pkcs7.h
ossl_x509.o: ossl_pkey.h
-ossl_x509.o: ossl_provider.h
ossl_x509.o: ossl_rand.h
ossl_x509.o: ossl_ssl.h
ossl_x509.o: ossl_ts.h
@@ -4933,7 +4714,6 @@ ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -5002,6 +4782,7 @@ ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -5032,12 +4813,12 @@ ossl_x509attr.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/method.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/module.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509attr.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_x509attr.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/value.h
ossl_x509attr.o: $(hdrdir)/ruby/internal/value_type.h
@@ -5068,7 +4849,6 @@ ossl_x509attr.o: ossl_ocsp.h
ossl_x509attr.o: ossl_pkcs12.h
ossl_x509attr.o: ossl_pkcs7.h
ossl_x509attr.o: ossl_pkey.h
-ossl_x509attr.o: ossl_provider.h
ossl_x509attr.o: ossl_rand.h
ossl_x509attr.o: ossl_ssl.h
ossl_x509attr.o: ossl_ts.h
@@ -5128,7 +4908,6 @@ ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -5197,6 +4976,7 @@ ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -5227,12 +5007,12 @@ ossl_x509cert.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/method.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/module.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509cert.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_x509cert.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/value.h
ossl_x509cert.o: $(hdrdir)/ruby/internal/value_type.h
@@ -5263,7 +5043,6 @@ ossl_x509cert.o: ossl_ocsp.h
ossl_x509cert.o: ossl_pkcs12.h
ossl_x509cert.o: ossl_pkcs7.h
ossl_x509cert.o: ossl_pkey.h
-ossl_x509cert.o: ossl_provider.h
ossl_x509cert.o: ossl_rand.h
ossl_x509cert.o: ossl_ssl.h
ossl_x509cert.o: ossl_ts.h
@@ -5323,7 +5102,6 @@ ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -5392,6 +5170,7 @@ ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -5422,12 +5201,12 @@ ossl_x509crl.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/method.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/module.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509crl.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_x509crl.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/value.h
ossl_x509crl.o: $(hdrdir)/ruby/internal/value_type.h
@@ -5458,7 +5237,6 @@ ossl_x509crl.o: ossl_ocsp.h
ossl_x509crl.o: ossl_pkcs12.h
ossl_x509crl.o: ossl_pkcs7.h
ossl_x509crl.o: ossl_pkey.h
-ossl_x509crl.o: ossl_provider.h
ossl_x509crl.o: ossl_rand.h
ossl_x509crl.o: ossl_ssl.h
ossl_x509crl.o: ossl_ts.h
@@ -5518,7 +5296,6 @@ ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -5587,6 +5364,7 @@ ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -5617,12 +5395,12 @@ ossl_x509ext.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/method.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/module.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509ext.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_x509ext.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/value.h
ossl_x509ext.o: $(hdrdir)/ruby/internal/value_type.h
@@ -5653,7 +5431,6 @@ ossl_x509ext.o: ossl_ocsp.h
ossl_x509ext.o: ossl_pkcs12.h
ossl_x509ext.o: ossl_pkcs7.h
ossl_x509ext.o: ossl_pkey.h
-ossl_x509ext.o: ossl_provider.h
ossl_x509ext.o: ossl_rand.h
ossl_x509ext.o: ossl_ssl.h
ossl_x509ext.o: ossl_ts.h
@@ -5713,7 +5490,6 @@ ossl_x509name.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509name.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509name.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509name.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509name.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509name.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509name.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509name.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -5782,6 +5558,7 @@ ossl_x509name.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509name.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509name.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -5812,12 +5589,12 @@ ossl_x509name.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509name.o: $(hdrdir)/ruby/internal/method.h
ossl_x509name.o: $(hdrdir)/ruby/internal/module.h
ossl_x509name.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509name.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509name.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509name.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509name.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509name.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509name.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_x509name.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509name.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509name.o: $(hdrdir)/ruby/internal/value.h
ossl_x509name.o: $(hdrdir)/ruby/internal/value_type.h
@@ -5848,7 +5625,6 @@ ossl_x509name.o: ossl_ocsp.h
ossl_x509name.o: ossl_pkcs12.h
ossl_x509name.o: ossl_pkcs7.h
ossl_x509name.o: ossl_pkey.h
-ossl_x509name.o: ossl_provider.h
ossl_x509name.o: ossl_rand.h
ossl_x509name.o: ossl_ssl.h
ossl_x509name.o: ossl_ts.h
@@ -5908,7 +5684,6 @@ ossl_x509req.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509req.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509req.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509req.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509req.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509req.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509req.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509req.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -5977,6 +5752,7 @@ ossl_x509req.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509req.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509req.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -6007,12 +5783,12 @@ ossl_x509req.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509req.o: $(hdrdir)/ruby/internal/method.h
ossl_x509req.o: $(hdrdir)/ruby/internal/module.h
ossl_x509req.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509req.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509req.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509req.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509req.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509req.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509req.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_x509req.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509req.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509req.o: $(hdrdir)/ruby/internal/value.h
ossl_x509req.o: $(hdrdir)/ruby/internal/value_type.h
@@ -6043,7 +5819,6 @@ ossl_x509req.o: ossl_ocsp.h
ossl_x509req.o: ossl_pkcs12.h
ossl_x509req.o: ossl_pkcs7.h
ossl_x509req.o: ossl_pkey.h
-ossl_x509req.o: ossl_provider.h
ossl_x509req.o: ossl_rand.h
ossl_x509req.o: ossl_ssl.h
ossl_x509req.o: ossl_ts.h
@@ -6103,7 +5878,6 @@ ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -6172,6 +5946,7 @@ ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -6202,12 +5977,12 @@ ossl_x509revoked.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/method.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/module.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509revoked.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_x509revoked.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/value.h
ossl_x509revoked.o: $(hdrdir)/ruby/internal/value_type.h
@@ -6238,7 +6013,6 @@ ossl_x509revoked.o: ossl_ocsp.h
ossl_x509revoked.o: ossl_pkcs12.h
ossl_x509revoked.o: ossl_pkcs7.h
ossl_x509revoked.o: ossl_pkey.h
-ossl_x509revoked.o: ossl_provider.h
ossl_x509revoked.o: ossl_rand.h
ossl_x509revoked.o: ossl_ssl.h
ossl_x509revoked.o: ossl_ts.h
@@ -6298,7 +6072,6 @@ ossl_x509store.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ossl_x509store.o: $(hdrdir)/ruby/internal/attr/noinline.h
ossl_x509store.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ossl_x509store.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ossl_x509store.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ossl_x509store.o: $(hdrdir)/ruby/internal/attr/pure.h
ossl_x509store.o: $(hdrdir)/ruby/internal/attr/restrict.h
ossl_x509store.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -6367,6 +6140,7 @@ ossl_x509store.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/error.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/eval.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/file.h
+ossl_x509store.o: $(hdrdir)/ruby/internal/intern/gc.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/hash.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/io.h
ossl_x509store.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -6397,12 +6171,12 @@ ossl_x509store.o: $(hdrdir)/ruby/internal/memory.h
ossl_x509store.o: $(hdrdir)/ruby/internal/method.h
ossl_x509store.o: $(hdrdir)/ruby/internal/module.h
ossl_x509store.o: $(hdrdir)/ruby/internal/newobj.h
+ossl_x509store.o: $(hdrdir)/ruby/internal/rgengc.h
ossl_x509store.o: $(hdrdir)/ruby/internal/scan_args.h
ossl_x509store.o: $(hdrdir)/ruby/internal/special_consts.h
ossl_x509store.o: $(hdrdir)/ruby/internal/static_assert.h
ossl_x509store.o: $(hdrdir)/ruby/internal/stdalign.h
ossl_x509store.o: $(hdrdir)/ruby/internal/stdbool.h
-ossl_x509store.o: $(hdrdir)/ruby/internal/stdckdint.h
ossl_x509store.o: $(hdrdir)/ruby/internal/symbol.h
ossl_x509store.o: $(hdrdir)/ruby/internal/value.h
ossl_x509store.o: $(hdrdir)/ruby/internal/value_type.h
@@ -6433,7 +6207,6 @@ ossl_x509store.o: ossl_ocsp.h
ossl_x509store.o: ossl_pkcs12.h
ossl_x509store.o: ossl_pkcs7.h
ossl_x509store.o: ossl_pkey.h
-ossl_x509store.o: ossl_provider.h
ossl_x509store.o: ossl_rand.h
ossl_x509store.o: ossl_ssl.h
ossl_x509store.o: ossl_ts.h
diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb
index adca064904..bc3e4d3a21 100644
--- a/ext/openssl/extconf.rb
+++ b/ext/openssl/extconf.rb
@@ -8,41 +8,26 @@
= Licence
This program is licensed under the same licence as Ruby.
- (See the file 'COPYING'.)
+ (See the file 'LICENCE'.)
=end
require "mkmf"
-ssl_dirs = dir_config("openssl")
-dir_config_given = ssl_dirs.any?
-
-_, ssl_ldir = ssl_dirs
-if ssl_ldir&.split(File::PATH_SEPARATOR)&.none? { |dir| File.directory?(dir) }
- # According to the `mkmf.rb#dir_config`, the `--with-openssl-dir=<dir>` uses
- # the value of the `File.basename(RbConfig::MAKEFILE_CONFIG["libdir"])` as a
- # loaded library directory name.
- ruby_ldir_name = File.basename(RbConfig::MAKEFILE_CONFIG["libdir"])
-
- raise "OpenSSL library directory could not be found in '#{ssl_ldir}'. " \
- "You might want to fix this error in one of the following ways.\n" \
- " * Recompile OpenSSL by configuring it with --libdir=#{ruby_ldir_name} " \
- " to specify the OpenSSL library directory.\n" \
- " * Recompile Ruby by configuring it with --libdir=<dir> to specify the " \
- "Ruby library directory.\n" \
- " * Compile this openssl gem with --with-openssl-include=<dir> and " \
- "--with-openssl-lib=<dir> options to specify the OpenSSL include and " \
- "library directories."
-end
-
+dir_config_given = dir_config("openssl").any?
dir_config("kerberos")
Logging::message "=== OpenSSL for Ruby configurator ===\n"
+##
+# Adds -DOSSL_DEBUG for compilation and some more targets when GCC is used
+# To turn it on, use: --with-debug or --enable-debug
+#
+if with_config("debug") or enable_config("debug")
+ $defs.push("-DOSSL_DEBUG")
+end
$defs.push("-D""OPENSSL_SUPPRESS_DEPRECATED")
-have_func("rb_io_descriptor")
have_func("rb_io_maybe_wait(0, Qnil, Qnil, Qnil)", "ruby/io.h") # Ruby 3.1
-have_func("rb_io_timeout", "ruby/io.h")
Logging::message "=== Checking for system dependent stuff... ===\n"
have_library("nsl", "t_open")
@@ -149,9 +134,6 @@ engines.each { |name|
have_func("ENGINE_load_#{name}()", "openssl/engine.h")
}
-# missing in libressl < 3.5
-have_func("i2d_re_X509_tbs(NULL, NULL)", x509_h)
-
# added in 1.1.0
if !have_struct_member("SSL", "ctx", "openssl/ssl.h") || is_libressl
$defs.push("-DHAVE_OPAQUE_OPENSSL")
@@ -190,7 +172,6 @@ have_func("TS_VERIFY_CTX_add_flags(NULL, 0)", ts_h)
have_func("TS_RESP_CTX_set_time_cb(NULL, NULL, NULL)", ts_h)
have_func("EVP_PBE_scrypt(\"\", 0, (unsigned char *)\"\", 0, 0, 0, 0, 0, NULL, 0)", evp_h)
have_func("SSL_CTX_set_post_handshake_auth(NULL, 0)", ssl_h)
-have_func("X509_STORE_get0_param(NULL)", x509_h)
# added in 1.1.1
have_func("EVP_PKEY_check(NULL)", evp_h)
@@ -210,12 +191,6 @@ have_func("EVP_PKEY_dup(NULL)", evp_h)
Logging::message "=== Checking done. ===\n"
-# Append flags from environment variables.
-extcflags = ENV["RUBY_OPENSSL_EXTCFLAGS"]
-append_cflags(extcflags.split) if extcflags
-extldflags = ENV["RUBY_OPENSSL_EXTLDFLAGS"]
-append_ldflags(extldflags.split) if extldflags
-
create_header
create_makefile("openssl")
Logging::message "Done.\n"
diff --git a/ext/openssl/lib/openssl.rb b/ext/openssl/lib/openssl.rb
index 0889923890..8a342f15b6 100644
--- a/ext/openssl/lib/openssl.rb
+++ b/ext/openssl/lib/openssl.rb
@@ -7,13 +7,12 @@
= Licence
This program is licensed under the same licence as Ruby.
- (See the file 'COPYING'.)
+ (See the file 'LICENCE'.)
=end
require 'openssl.so'
require_relative 'openssl/bn'
-require_relative 'openssl/asn1'
require_relative 'openssl/pkey'
require_relative 'openssl/cipher'
require_relative 'openssl/digest'
diff --git a/ext/openssl/lib/openssl/asn1.rb b/ext/openssl/lib/openssl/asn1.rb
deleted file mode 100644
index 89fa28e1fb..0000000000
--- a/ext/openssl/lib/openssl/asn1.rb
+++ /dev/null
@@ -1,188 +0,0 @@
-# frozen_string_literal: true
-#--
-#
-# = Ruby-space definitions that completes C-space funcs for ASN.1
-#
-# = Licence
-# This program is licensed under the same licence as Ruby.
-# (See the file 'COPYING'.)
-#++
-
-module OpenSSL
- module ASN1
- class ASN1Data
- #
- # Carries the value of a ASN.1 type.
- # Please confer Constructive and Primitive for the mappings between
- # ASN.1 data types and Ruby classes.
- #
- attr_accessor :value
-
- # An Integer representing the tag number of this ASN1Data. Never +nil+.
- attr_accessor :tag
-
- # A Symbol representing the tag class of this ASN1Data. Never +nil+.
- # See ASN1Data for possible values.
- attr_accessor :tag_class
-
- #
- # Never +nil+. A boolean value indicating whether the encoding uses
- # indefinite length (in the case of parsing) or whether an indefinite
- # length form shall be used (in the encoding case).
- # In DER, every value uses definite length form. But in scenarios where
- # large amounts of data need to be transferred it might be desirable to
- # have some kind of streaming support available.
- # For example, huge OCTET STRINGs are preferably sent in smaller-sized
- # chunks, each at a time.
- # This is possible in BER by setting the length bytes of an encoding
- # to zero and by this indicating that the following value will be
- # sent in chunks. Indefinite length encodings are always constructed.
- # The end of such a stream of chunks is indicated by sending a EOC
- # (End of Content) tag. SETs and SEQUENCEs may use an indefinite length
- # encoding, but also primitive types such as e.g. OCTET STRINGS or
- # BIT STRINGS may leverage this functionality (cf. ITU-T X.690).
- #
- attr_accessor :indefinite_length
-
- alias infinite_length indefinite_length
- alias infinite_length= indefinite_length=
-
- #
- # :call-seq:
- # OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data
- #
- # _value_: Please have a look at Constructive and Primitive to see how Ruby
- # types are mapped to ASN.1 types and vice versa.
- #
- # _tag_: An Integer indicating the tag number.
- #
- # _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for
- # possible values.
- #
- # == Example
- # asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42)
- # tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER
- #
- def initialize(value, tag, tag_class)
- raise ASN1Error, "invalid tag class" unless tag_class.is_a?(Symbol)
-
- @tag = tag
- @value = value
- @tag_class = tag_class
- @indefinite_length = false
- end
- end
-
- module TaggedASN1Data
- #
- # May be used as a hint for encoding a value either implicitly or
- # explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
- # _tagging_ is not set when a ASN.1 structure is parsed using
- # OpenSSL::ASN1.decode.
- #
- attr_accessor :tagging
-
- # :call-seq:
- # OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive
- #
- # _value_: is mandatory.
- #
- # _tag_: optional, may be specified for tagged values. If no _tag_ is
- # specified, the UNIVERSAL tag corresponding to the Primitive sub-class
- # is used by default.
- #
- # _tagging_: may be used as an encoding hint to encode a value either
- # explicitly or implicitly, see ASN1 for possible values.
- #
- # _tag_class_: if _tag_ and _tagging_ are +nil+ then this is set to
- # +:UNIVERSAL+ by default. If either _tag_ or _tagging_ are set then
- # +:CONTEXT_SPECIFIC+ is used as the default. For possible values please
- # cf. ASN1.
- #
- # == Example
- # int = OpenSSL::ASN1::Integer.new(42)
- # zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT)
- # private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE)
- #
- def initialize(value, tag = nil, tagging = nil, tag_class = nil)
- tag ||= ASN1.take_default_tag(self.class)
-
- raise ASN1Error, "must specify tag number" unless tag
-
- if tagging
- raise ASN1Error, "invalid tagging method" unless tagging.is_a?(Symbol)
- end
-
- tag_class ||= tagging ? :CONTEXT_SPECIFIC : :UNIVERSAL
-
- raise ASN1Error, "invalid tag class" unless tag_class.is_a?(Symbol)
-
- @tagging = tagging
- super(value ,tag, tag_class)
- end
- end
-
- class Primitive < ASN1Data
- include TaggedASN1Data
-
- undef_method :indefinite_length=
- undef_method :infinite_length=
- end
-
- class Constructive < ASN1Data
- include TaggedASN1Data
- include Enumerable
-
- # :call-seq:
- # asn1_ary.each { |asn1| block } => asn1_ary
- #
- # Calls the given block once for each element in self, passing that element
- # as parameter _asn1_. If no block is given, an enumerator is returned
- # instead.
- #
- # == Example
- # asn1_ary.each do |asn1|
- # puts asn1
- # end
- #
- def each(&blk)
- @value.each(&blk)
-
- self
- end
- end
-
- class Boolean < Primitive ; end
- class Integer < Primitive ; end
- class Enumerated < Primitive ; end
-
- class BitString < Primitive
- attr_accessor :unused_bits
-
- def initialize(*)
- super
-
- @unused_bits = 0
- end
- end
-
- class EndOfContent < ASN1Data
- def initialize
- super("", 0, :UNIVERSAL)
- end
- end
-
- # :nodoc:
- def self.take_default_tag(klass)
- tag = CLASS_TAG_MAP[klass]
-
- return tag if tag
-
- sklass = klass.superclass
-
- return unless sklass
-
- take_default_tag(sklass)
- end
- end
-end
diff --git a/ext/openssl/lib/openssl/bn.rb b/ext/openssl/lib/openssl/bn.rb
index e4889a140c..0a5e11b4c2 100644
--- a/ext/openssl/lib/openssl/bn.rb
+++ b/ext/openssl/lib/openssl/bn.rb
@@ -10,7 +10,7 @@
#
# = Licence
# This program is licensed under the same licence as Ruby.
-# (See the file 'COPYING'.)
+# (See the file 'LICENCE'.)
#++
module OpenSSL
diff --git a/ext/openssl/lib/openssl/buffering.rb b/ext/openssl/lib/openssl/buffering.rb
index 85f593af0f..d47e1082ef 100644
--- a/ext/openssl/lib/openssl/buffering.rb
+++ b/ext/openssl/lib/openssl/buffering.rb
@@ -8,7 +8,7 @@
#
#= Licence
# This program is licensed under the same licence as Ruby.
-# (See the file 'COPYING'.)
+# (See the file 'LICENCE'.)
#++
##
@@ -93,7 +93,9 @@ module OpenSSL::Buffering
nil
else
size = @rbuffer.size unless size
- @rbuffer.slice!(0, size)
+ ret = @rbuffer[0, size]
+ @rbuffer[0, size] = ""
+ ret
end
end
@@ -104,13 +106,8 @@ module OpenSSL::Buffering
#
# Get the next 8bit byte from `ssl`. Returns `nil` on EOF
def getbyte
- read(1)&.ord
- end
-
- # Get the next 8bit byte. Raises EOFError on EOF
- def readbyte
- raise EOFError if eof?
- getbyte
+ byte = read(1)
+ byte && byte.unpack1("C")
end
##
@@ -235,7 +232,7 @@ module OpenSSL::Buffering
#
# Unlike IO#gets the separator must be provided if a limit is provided.
- def gets(eol=$/, limit=nil, chomp: false)
+ def gets(eol=$/, limit=nil)
idx = @rbuffer.index(eol)
until @eof
break if idx
@@ -250,11 +247,7 @@ module OpenSSL::Buffering
if size && limit && limit >= 0
size = [size, limit].min
end
- line = consume_rbuff(size)
- if chomp && line
- line.chomp!(eol)
- end
- line
+ consume_rbuff(size)
end
##
@@ -355,18 +348,13 @@ module OpenSSL::Buffering
@wbuffer << s
@wbuffer.force_encoding(Encoding::BINARY)
@sync ||= false
- buffer_size = @wbuffer.size
- if @sync or buffer_size > BLOCK_SIZE
- nwrote = 0
- begin
- while nwrote < buffer_size do
- begin
- nwrote += syswrite(@wbuffer[nwrote, buffer_size - nwrote])
- rescue Errno::EAGAIN
- retry
- end
+ if @sync or @wbuffer.size > BLOCK_SIZE
+ until @wbuffer.empty?
+ begin
+ nwrote = syswrite(@wbuffer)
+ rescue Errno::EAGAIN
+ retry
end
- ensure
@wbuffer[0, nwrote] = ""
end
end
diff --git a/ext/openssl/lib/openssl/cipher.rb b/ext/openssl/lib/openssl/cipher.rb
index ab75ac8e1a..8ad8c35dd3 100644
--- a/ext/openssl/lib/openssl/cipher.rb
+++ b/ext/openssl/lib/openssl/cipher.rb
@@ -9,7 +9,7 @@
#
# = Licence
# This program is licensed under the same licence as Ruby.
-# (See the file 'COPYING'.)
+# (See the file 'LICENCE'.)
#++
module OpenSSL
diff --git a/ext/openssl/lib/openssl/digest.rb b/ext/openssl/lib/openssl/digest.rb
index 5cda1e931c..2ff8398e44 100644
--- a/ext/openssl/lib/openssl/digest.rb
+++ b/ext/openssl/lib/openssl/digest.rb
@@ -9,7 +9,7 @@
#
# = Licence
# This program is licensed under the same licence as Ruby.
-# (See the file 'COPYING'.)
+# (See the file 'LICENCE'.)
#++
module OpenSSL
@@ -18,9 +18,13 @@ module OpenSSL
# Return the hash value computed with _name_ Digest. _name_ is either the
# long name or short name of a supported digest algorithm.
#
- # === Example
+ # === Examples
#
# OpenSSL::Digest.digest("SHA256", "abc")
+ #
+ # which is equivalent to:
+ #
+ # OpenSSL::Digest.digest('SHA256', "abc")
def self.digest(name, data)
super(data, name)
diff --git a/ext/openssl/lib/openssl/marshal.rb b/ext/openssl/lib/openssl/marshal.rb
index eb8eda4748..af5647192a 100644
--- a/ext/openssl/lib/openssl/marshal.rb
+++ b/ext/openssl/lib/openssl/marshal.rb
@@ -9,7 +9,7 @@
#
# = Licence
# This program is licensed under the same licence as Ruby.
-# (See the file 'COPYING'.)
+# (See the file 'LICENCE'.)
#++
module OpenSSL
module Marshal
diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb
index 2186f5f43a..ea8bb2a18e 100644
--- a/ext/openssl/lib/openssl/ssl.rb
+++ b/ext/openssl/lib/openssl/ssl.rb
@@ -7,7 +7,7 @@
= Licence
This program is licensed under the same licence as Ruby.
- (See the file 'COPYING'.)
+ (See the file 'LICENCE'.)
=end
require "openssl/buffering"
@@ -22,6 +22,7 @@ module OpenSSL
module SSL
class SSLContext
DEFAULT_PARAMS = { # :nodoc:
+ :min_version => OpenSSL::SSL::TLS1_VERSION,
:verify_mode => OpenSSL::SSL::VERIFY_PEER,
:verify_hostname => true,
:options => -> {
@@ -33,28 +34,27 @@ module OpenSSL
}
if defined?(OpenSSL::PKey::DH)
- DH_ffdhe2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_
+ DEFAULT_2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_
-----BEGIN DH PARAMETERS-----
-MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
-+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
-87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
-YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
-7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
-ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
+MIIBCAKCAQEA7E6kBrYiyvmKAMzQ7i8WvwVk9Y/+f8S7sCTN712KkK3cqd1jhJDY
+JbrYeNV3kUIKhPxWHhObHKpD1R84UpL+s2b55+iMd6GmL7OYmNIT/FccKhTcveab
+VBmZT86BZKYyf45hUF9FOuUM9xPzuK3Vd8oJQvfYMCd7LPC0taAEljQLR4Edf8E6
+YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
+1bNveX5wInh5GDx1FGhKBZ+s1H+aedudCm7sCgRwv8lKWYGiHzObSma8A86KG+MD
+7Lo5JquQ3DlBodj3IDyPrxIv96lvRPFtAwIBAg==
-----END DH PARAMETERS-----
_end_of_pem_
- private_constant :DH_ffdhe2048
+ private_constant :DEFAULT_2048
DEFAULT_TMP_DH_CALLBACK = lambda { |ctx, is_export, keylen| # :nodoc:
warn "using default DH parameters." if $VERBOSE
- DH_ffdhe2048
+ DEFAULT_2048
}
end
if !(OpenSSL::OPENSSL_VERSION.start_with?("OpenSSL") &&
OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10100000)
DEFAULT_PARAMS.merge!(
- min_version: OpenSSL::SSL::TLS1_VERSION,
ciphers: %w{
ECDHE-ECDSA-AES128-GCM-SHA256
ECDHE-RSA-AES128-GCM-SHA256
@@ -252,14 +252,6 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
to_io.peeraddr
end
- def local_address
- to_io.local_address
- end
-
- def remote_address
- to_io.remote_address
- end
-
def setsockopt(level, optname, optval)
to_io.setsockopt(level, optname, optval)
end
@@ -279,36 +271,6 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
def do_not_reverse_lookup=(flag)
to_io.do_not_reverse_lookup = flag
end
-
- def close_on_exec=(value)
- to_io.close_on_exec = value
- end
-
- def close_on_exec?
- to_io.close_on_exec?
- end
-
- def wait(*args)
- to_io.wait(*args)
- end
-
- def wait_readable(*args)
- to_io.wait_readable(*args)
- end
-
- def wait_writable(*args)
- to_io.wait_writable(*args)
- end
-
- if IO.method_defined?(:timeout)
- def timeout
- to_io.timeout
- end
-
- def timeout=(value)
- to_io.timeout=(value)
- end
- end
end
def verify_certificate_identity(cert, hostname)
@@ -459,32 +421,6 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
nil
end
- # Close the stream for reading.
- # This method is ignored by OpenSSL as there is no reasonable way to
- # implement it, but exists for compatibility with IO.
- def close_read
- # Unsupported and ignored.
- # Just don't read any more.
- end
-
- # Closes the stream for writing. The behavior of this method depends on
- # the version of OpenSSL and the TLS protocol in use.
- #
- # - Sends a 'close_notify' alert to the peer.
- # - Does not wait for the peer's 'close_notify' alert in response.
- #
- # In TLS 1.2 and earlier:
- # - On receipt of a 'close_notify' alert, responds with a 'close_notify'
- # alert of its own and close down the connection immediately,
- # discarding any pending writes.
- #
- # Therefore, on TLS 1.2, this method will cause the connection to be
- # completely shut down. On TLS 1.3, the connection will remain open for
- # reading only.
- def close_write
- stop
- end
-
private
def using_anon_cipher?
@@ -558,7 +494,7 @@ ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
unless ctx.session_id_context
# see #6137 - session id may not exceed 32 bytes
prng = ::Random.new($0.hash)
- session_id = prng.bytes(16).unpack1('H*')
+ session_id = prng.bytes(16).unpack('H*')[0]
@ctx.session_id_context = session_id
end
@start_immediately = true
diff --git a/ext/openssl/lib/openssl/version.rb b/ext/openssl/lib/openssl/version.rb
index 9315a79381..4163f55064 100644
--- a/ext/openssl/lib/openssl/version.rb
+++ b/ext/openssl/lib/openssl/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module OpenSSL
- VERSION = "3.2.0"
+ VERSION = "3.1.0"
end
diff --git a/ext/openssl/lib/openssl/x509.rb b/ext/openssl/lib/openssl/x509.rb
index b66727420e..f973f4f4dc 100644
--- a/ext/openssl/lib/openssl/x509.rb
+++ b/ext/openssl/lib/openssl/x509.rb
@@ -9,7 +9,7 @@
#
# = Licence
# This program is licensed under the same licence as Ruby.
-# (See the file 'COPYING'.)
+# (See the file 'LICENCE'.)
#++
require_relative 'marshal'
diff --git a/ext/openssl/openssl.gemspec b/ext/openssl/openssl.gemspec
index e692e661c4..8d83b69193 100644
--- a/ext/openssl/openssl.gemspec
+++ b/ext/openssl/openssl.gemspec
@@ -1,27 +1,21 @@
Gem::Specification.new do |spec|
spec.name = "openssl"
- spec.version = "3.2.0"
+ spec.version = "3.1.0"
spec.authors = ["Martin Bosslet", "SHIBATA Hiroshi", "Zachary Scott", "Kazuki Yamaguchi"]
spec.email = ["ruby-core@ruby-lang.org"]
- spec.summary = %q{SSL/TLS and general-purpose cryptography for Ruby}
- spec.description = %q{OpenSSL for Ruby provides access to SSL/TLS and general-purpose cryptography based on the OpenSSL library.}
+ spec.summary = %q{OpenSSL provides SSL, TLS and general purpose cryptography.}
+ spec.description = %q{It wraps the OpenSSL library.}
spec.homepage = "https://github.com/ruby/openssl"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
+ spec.license = "Ruby"
- if Gem::Platform === spec.platform and spec.platform =~ 'java' or RUBY_ENGINE == 'jruby'
- spec.platform = "java"
- spec.files = []
- spec.add_runtime_dependency('jruby-openssl', '~> 0.14')
- else
- spec.files = Dir["lib/**/*.rb", "ext/**/*.{c,h,rb}", "*.md", "BSDL", "COPYING"]
- spec.require_paths = ["lib"]
- spec.extensions = ["ext/openssl/extconf.rb"]
- end
+ spec.files = Dir["lib/**/*.rb", "ext/**/*.{c,h,rb}", "*.md", "BSDL", "LICENSE.txt"]
+ spec.require_paths = ["lib"]
+ spec.extensions = ["ext/openssl/extconf.rb"]
spec.extra_rdoc_files = Dir["*.md"]
spec.rdoc_options = ["--main", "README.md"]
- spec.required_ruby_version = ">= 2.7.0"
+ spec.required_ruby_version = ">= 2.6.0"
spec.metadata["msys2_mingw_dependencies"] = "openssl"
end
diff --git a/ext/openssl/openssl_missing.c b/ext/openssl/openssl_missing.c
index 5a6d23e106..4415703db4 100644
--- a/ext/openssl/openssl_missing.c
+++ b/ext/openssl/openssl_missing.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include RUBY_EXTCONF_H
diff --git a/ext/openssl/openssl_missing.h b/ext/openssl/openssl_missing.h
index 0711f924e5..8629bfe505 100644
--- a/ext/openssl/openssl_missing.h
+++ b/ext/openssl/openssl_missing.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_OPENSSL_MISSING_H_)
#define _OSSL_OPENSSL_MISSING_H_
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index 59ad7d19a4..6c532aca94 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
#include <stdarg.h> /* for ossl_raise */
@@ -207,7 +207,7 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_)
while (1) {
/*
- * when the flag is nonzero, this password
+ * when the flag is nonzero, this passphrase
* will be used to perform encryption; otherwise it will
* be used to perform decryption.
*/
@@ -272,28 +272,23 @@ VALUE
ossl_make_error(VALUE exc, VALUE str)
{
unsigned long e;
- const char *data;
- int flags;
- if (NIL_P(str))
- str = rb_str_new(NULL, 0);
-
-#ifdef HAVE_ERR_GET_ERROR_ALL
- e = ERR_peek_last_error_all(NULL, NULL, NULL, &data, &flags);
-#else
- e = ERR_peek_last_error_line_data(NULL, NULL, &data, &flags);
-#endif
+ e = ERR_peek_last_error();
if (e) {
- const char *msg = ERR_reason_error_string(e);
+ const char *msg = ERR_reason_error_string(e);
- if (RSTRING_LEN(str)) rb_str_cat_cstr(str, ": ");
- rb_str_cat_cstr(str, msg ? msg : "(null)");
- if (flags & ERR_TXT_STRING && data)
- rb_str_catf(str, " (%s)", data);
- ossl_clear_error();
+ if (NIL_P(str)) {
+ if (msg) str = rb_str_new_cstr(msg);
+ }
+ else {
+ if (RSTRING_LEN(str)) rb_str_cat2(str, ": ");
+ rb_str_cat2(str, msg ? msg : "(null)");
+ }
+ ossl_clear_error();
}
- return rb_exc_new_str(exc, str);
+ if (NIL_P(str)) str = rb_str_new(0, 0);
+ return rb_exc_new3(exc, str);
}
void
@@ -374,6 +369,22 @@ ossl_get_errors(VALUE _)
*/
VALUE dOSSL;
+#if !defined(HAVE_VA_ARGS_MACRO)
+void
+ossl_debug(const char *fmt, ...)
+{
+ va_list args;
+
+ if (dOSSL == Qtrue) {
+ fprintf(stderr, "OSSL_DEBUG: ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, " [CONTEXT N/A]\n");
+ }
+}
+#endif
+
/*
* call-seq:
* OpenSSL.debug -> true | false
@@ -407,11 +418,7 @@ static VALUE
ossl_fips_mode_get(VALUE self)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
- VALUE enabled;
- enabled = EVP_default_properties_is_fips_enabled(NULL) ? Qtrue : Qfalse;
- return enabled;
-#elif defined(OPENSSL_FIPS)
+#ifdef OPENSSL_FIPS
VALUE enabled;
enabled = FIPS_mode() ? Qtrue : Qfalse;
return enabled;
@@ -435,18 +442,8 @@ ossl_fips_mode_get(VALUE self)
static VALUE
ossl_fips_mode_set(VALUE self, VALUE enabled)
{
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
- if (RTEST(enabled)) {
- if (!EVP_default_properties_enable_fips(NULL, 1)) {
- ossl_raise(eOSSLError, "Turning on FIPS mode failed");
- }
- } else {
- if (!EVP_default_properties_enable_fips(NULL, 0)) {
- ossl_raise(eOSSLError, "Turning off FIPS mode failed");
- }
- }
- return enabled;
-#elif defined(OPENSSL_FIPS)
+
+#ifdef OPENSSL_FIPS
if (RTEST(enabled)) {
int mode = FIPS_mode();
if(!mode && !FIPS_mode_set(1)) /* turning on twice leads to an error */
@@ -463,6 +460,75 @@ ossl_fips_mode_set(VALUE self, VALUE enabled)
#endif
}
+#if defined(OSSL_DEBUG)
+#if !defined(LIBRESSL_VERSION_NUMBER) && \
+ (OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(OPENSSL_NO_CRYPTO_MDEBUG) || \
+ defined(CRYPTO_malloc_debug_init))
+/*
+ * call-seq:
+ * OpenSSL.mem_check_start -> nil
+ *
+ * Calls CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON). Starts tracking memory
+ * allocations. See also OpenSSL.print_mem_leaks.
+ *
+ * This is available only when built with a capable OpenSSL and --enable-debug
+ * configure option.
+ */
+static VALUE
+mem_check_start(VALUE self)
+{
+ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * OpenSSL.print_mem_leaks -> true | false
+ *
+ * For debugging the Ruby/OpenSSL library. Calls CRYPTO_mem_leaks_fp(stderr).
+ * Prints detected memory leaks to standard error. This cleans the global state
+ * up thus you cannot use any methods of the library after calling this.
+ *
+ * Returns +true+ if leaks detected, +false+ otherwise.
+ *
+ * This is available only when built with a capable OpenSSL and --enable-debug
+ * configure option.
+ *
+ * === Example
+ * OpenSSL.mem_check_start
+ * NOT_GCED = OpenSSL::PKey::RSA.new(256)
+ *
+ * END {
+ * GC.start
+ * OpenSSL.print_mem_leaks # will print the leakage
+ * }
+ */
+static VALUE
+print_mem_leaks(VALUE self)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000
+ int ret;
+#endif
+
+#ifndef HAVE_RB_EXT_RACTOR_SAFE
+ // for Ruby 2.x
+ void ossl_bn_ctx_free(void); // ossl_bn.c
+ ossl_bn_ctx_free();
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000
+ ret = CRYPTO_mem_leaks_fp(stderr);
+ if (ret < 0)
+ ossl_raise(eOSSLError, "CRYPTO_mem_leaks_fp");
+ return ret ? Qfalse : Qtrue;
+#else
+ CRYPTO_mem_leaks_fp(stderr);
+ return Qnil;
+#endif
+}
+#endif
+#endif
+
#if !defined(HAVE_OPENSSL_110_THREADING_API)
/**
* Stores locks needed for OpenSSL thread safety
@@ -605,21 +671,23 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* key = OpenSSL::PKey::RSA.new 2048
*
- * File.write 'private_key.pem', key.private_to_pem
- * File.write 'public_key.pem', key.public_to_pem
+ * open 'private_key.pem', 'w' do |io| io.write key.to_pem end
+ * open 'public_key.pem', 'w' do |io| io.write key.public_key.to_pem end
*
* === Exporting a Key
*
* Keys saved to disk without encryption are not secure as anyone who gets
* ahold of the key may use it unless it is encrypted. In order to securely
- * export a key you may export it with a password.
+ * export a key you may export it with a pass phrase.
*
* cipher = OpenSSL::Cipher.new 'aes-256-cbc'
- * password = 'my secure password goes here'
+ * pass_phrase = 'my secure pass phrase goes here'
*
- * key_secure = key.private_to_pem cipher, password
+ * key_secure = key.export cipher, pass_phrase
*
- * File.write 'private.secure.pem', key_secure
+ * open 'private.secure.pem', 'w' do |io|
+ * io.write key_secure
+ * end
*
* OpenSSL::Cipher.ciphers returns a list of available ciphers.
*
@@ -639,13 +707,13 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* === Loading an Encrypted Key
*
- * OpenSSL will prompt you for your password when loading an encrypted key.
- * If you will not be able to type in the password you may provide it when
+ * OpenSSL will prompt you for your pass phrase when loading an encrypted key.
+ * If you will not be able to type in the pass phrase you may provide it when
* loading the key:
*
* key4_pem = File.read 'private.secure.pem'
- * password = 'my secure password goes here'
- * key4 = OpenSSL::PKey.read key4_pem, password
+ * pass_phrase = 'my secure pass phrase goes here'
+ * key4 = OpenSSL::PKey.read key4_pem, pass_phrase
*
* == RSA Encryption
*
@@ -761,6 +829,45 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* decrypted = cipher.update encrypted
* decrypted << cipher.final
*
+ * == PKCS #5 Password-based Encryption
+ *
+ * PKCS #5 is a password-based encryption standard documented at
+ * RFC2898[http://www.ietf.org/rfc/rfc2898.txt]. It allows a short password or
+ * passphrase to be used to create a secure encryption key. If possible, PBKDF2
+ * as described above should be used if the circumstances allow it.
+ *
+ * PKCS #5 uses a Cipher, a pass phrase and a salt to generate an encryption
+ * key.
+ *
+ * pass_phrase = 'my secure pass phrase goes here'
+ * salt = '8 octets'
+ *
+ * === Encryption
+ *
+ * First set up the cipher for encryption
+ *
+ * encryptor = OpenSSL::Cipher.new 'aes-256-cbc'
+ * encryptor.encrypt
+ * encryptor.pkcs5_keyivgen pass_phrase, salt
+ *
+ * Then pass the data you want to encrypt through
+ *
+ * encrypted = encryptor.update 'top secret document'
+ * encrypted << encryptor.final
+ *
+ * === Decryption
+ *
+ * Use a new Cipher instance set up for decryption
+ *
+ * decryptor = OpenSSL::Cipher.new 'aes-256-cbc'
+ * decryptor.decrypt
+ * decryptor.pkcs5_keyivgen pass_phrase, salt
+ *
+ * Then pass the data you want to decrypt through
+ *
+ * plain = decryptor.update encrypted
+ * plain << decryptor.final
+ *
* == X509 Certificates
*
* === Creating a Certificate
@@ -838,12 +945,12 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* not readable by other users.
*
* ca_key = OpenSSL::PKey::RSA.new 2048
- * password = 'my secure password goes here'
+ * pass_phrase = 'my secure pass phrase goes here'
*
- * cipher = 'aes-256-cbc'
+ * cipher = OpenSSL::Cipher.new 'aes-256-cbc'
*
* open 'ca_key.pem', 'w', 0400 do |io|
- * io.write ca_key.private_to_pem(cipher, password)
+ * io.write ca_key.export(cipher, pass_phrase)
* end
*
* === CA Certificate
@@ -1063,8 +1170,8 @@ Init_openssl(void)
/*
* Init main module
*/
- rb_global_variable(&mOSSL);
mOSSL = rb_define_module("OpenSSL");
+ rb_global_variable(&mOSSL);
rb_define_singleton_method(mOSSL, "fixed_length_secure_compare", ossl_crypto_fixed_length_secure_compare, 2);
/*
@@ -1083,35 +1190,15 @@ Init_openssl(void)
/*
* Version number of OpenSSL the ruby OpenSSL extension was built with
- * (base 16). The formats are below.
- *
- * [OpenSSL 3] <tt>0xMNN00PP0 (major minor 00 patch 0)</tt>
- * [OpenSSL before 3] <tt>0xMNNFFPPS (major minor fix patch status)</tt>
- * [LibreSSL] <tt>0x20000000 (fixed value)</tt>
- *
- * See also the man page OPENSSL_VERSION_NUMBER(3).
+ * (base 16)
*/
rb_define_const(mOSSL, "OPENSSL_VERSION_NUMBER", INT2NUM(OPENSSL_VERSION_NUMBER));
-#if defined(LIBRESSL_VERSION_NUMBER)
- /*
- * Version number of LibreSSL the ruby OpenSSL extension was built with
- * (base 16). The format is <tt>0xMNNFF00f (major minor fix 00
- * status)</tt>. This constant is only defined in LibreSSL cases.
- *
- * See also the man page LIBRESSL_VERSION_NUMBER(3).
- */
- rb_define_const(mOSSL, "LIBRESSL_VERSION_NUMBER", INT2NUM(LIBRESSL_VERSION_NUMBER));
-#endif
-
/*
* Boolean indicating whether OpenSSL is FIPS-capable or not
*/
rb_define_const(mOSSL, "OPENSSL_FIPS",
-/* OpenSSL 3 is FIPS-capable even when it is installed without fips option */
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
- Qtrue
-#elif defined(OPENSSL_FIPS)
+#ifdef OPENSSL_FIPS
Qtrue
#else
Qfalse
@@ -1121,12 +1208,12 @@ Init_openssl(void)
rb_define_module_function(mOSSL, "fips_mode", ossl_fips_mode_get, 0);
rb_define_module_function(mOSSL, "fips_mode=", ossl_fips_mode_set, 1);
- rb_global_variable(&eOSSLError);
/*
* Generic error,
* common for all classes under OpenSSL module
*/
eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError);
+ rb_global_variable(&eOSSLError);
/*
* Init debug core
@@ -1167,7 +1254,42 @@ Init_openssl(void)
Init_ossl_x509();
Init_ossl_ocsp();
Init_ossl_engine();
- Init_ossl_provider();
Init_ossl_asn1();
Init_ossl_kdf();
+
+#if defined(OSSL_DEBUG)
+ /*
+ * For debugging Ruby/OpenSSL. Enable only when built with --enable-debug
+ */
+#if !defined(LIBRESSL_VERSION_NUMBER) && \
+ (OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(OPENSSL_NO_CRYPTO_MDEBUG) || \
+ defined(CRYPTO_malloc_debug_init))
+ rb_define_module_function(mOSSL, "mem_check_start", mem_check_start, 0);
+ rb_define_module_function(mOSSL, "print_mem_leaks", print_mem_leaks, 0);
+
+#if defined(CRYPTO_malloc_debug_init) /* <= 1.0.2 */
+ CRYPTO_malloc_debug_init();
+#endif
+
+#if defined(V_CRYPTO_MDEBUG_ALL) /* <= 1.0.2 */
+ CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL);
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000 /* <= 1.0.2 */
+ {
+ int i;
+ /*
+ * See crypto/ex_data.c; call def_get_class() immediately to avoid
+ * allocations. 15 is the maximum number that is used as the class index
+ * in OpenSSL 1.0.2.
+ */
+ for (i = 0; i <= 15; i++) {
+ if (CRYPTO_get_ex_new_index(i, 0, (void *)"ossl-mdebug-dummy", 0, 0, 0) < 0)
+ rb_raise(rb_eRuntimeError, "CRYPTO_get_ex_new_index for "
+ "class index %d failed", i);
+ }
+ }
+#endif
+#endif
+#endif
}
diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h
index c3140ac3ef..facb80aa73 100644
--- a/ext/openssl/ossl.h
+++ b/ext/openssl/ossl.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_H_)
#define _OSSL_H_
@@ -62,10 +62,6 @@
# define OSSL_USE_ENGINE
#endif
-#if OSSL_OPENSSL_PREREQ(3, 0, 0)
-# define OSSL_USE_PROVIDER
-#endif
-
/*
* Common Module
*/
@@ -161,6 +157,7 @@ VALUE ossl_to_der_if_possible(VALUE);
*/
extern VALUE dOSSL;
+#if defined(HAVE_VA_ARGS_MACRO)
#define OSSL_Debug(...) do { \
if (dOSSL == Qtrue) { \
fprintf(stderr, "OSSL_DEBUG: "); \
@@ -169,6 +166,11 @@ extern VALUE dOSSL;
} \
} while (0)
+#else
+void ossl_debug(const char *, ...);
+#define OSSL_Debug ossl_debug
+#endif
+
/*
* Include all parts
*/
@@ -192,7 +194,6 @@ extern VALUE dOSSL;
#endif
#include "ossl_x509.h"
#include "ossl_engine.h"
-#include "ossl_provider.h"
#include "ossl_kdf.h"
void Init_openssl(void);
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c
index 1676defd0e..71c452c88a 100644
--- a/ext/openssl/ossl_asn1.c
+++ b/ext/openssl/ossl_asn1.c
@@ -5,12 +5,13 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset,
int depth, int yield, long *num_read);
+static VALUE ossl_asn1_initialize(int argc, VALUE *argv, VALUE self);
/*
* DATE conversion
@@ -157,6 +158,10 @@ asn1integer_to_num_i(VALUE arg)
#define ossl_asn1_get_tag_class(o) rb_attr_get((o),sivTAG_CLASS)
#define ossl_asn1_get_indefinite_length(o) rb_attr_get((o),sivINDEFINITE_LENGTH)
+#define ossl_asn1_set_value(o,v) rb_ivar_set((o),sivVALUE,(v))
+#define ossl_asn1_set_tag(o,v) rb_ivar_set((o),sivTAG,(v))
+#define ossl_asn1_set_tagging(o,v) rb_ivar_set((o),sivTAGGING,(v))
+#define ossl_asn1_set_tag_class(o,v) rb_ivar_set((o),sivTAG_CLASS,(v))
#define ossl_asn1_set_indefinite_length(o,v) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v))
VALUE mASN1;
@@ -184,6 +189,7 @@ VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
static VALUE sym_IMPLICIT, sym_EXPLICIT;
static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE;
static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINDEFINITE_LENGTH, sivUNUSED_BITS;
+static ID id_each;
/*
* Ruby to ASN1 converters
@@ -497,7 +503,7 @@ static VALUE class_tag_map;
static int ossl_asn1_default_tag(VALUE obj);
-static ASN1_TYPE *
+ASN1_TYPE*
ossl_asn1_get_asn1type(VALUE obj)
{
ASN1_TYPE *ret;
@@ -632,6 +638,35 @@ ossl_asn1_class2sym(int tc)
return sym_UNIVERSAL;
}
+/*
+ * call-seq:
+ * OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data
+ *
+ * _value_: Please have a look at Constructive and Primitive to see how Ruby
+ * types are mapped to ASN.1 types and vice versa.
+ *
+ * _tag_: An Integer indicating the tag number.
+ *
+ * _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for
+ * possible values.
+ *
+ * == Example
+ * asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42)
+ * tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER
+ */
+static VALUE
+ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class)
+{
+ if(!SYMBOL_P(tag_class))
+ ossl_raise(eASN1Error, "invalid tag class");
+ ossl_asn1_set_tag(self, tag);
+ ossl_asn1_set_value(self, value);
+ ossl_asn1_set_tag_class(self, tag_class);
+ ossl_asn1_set_indefinite_length(self, Qfalse);
+
+ return self;
+}
+
static VALUE
to_der_internal(VALUE self, int constructed, int indef_len, VALUE body)
{
@@ -760,19 +795,20 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
if (tc == sym_UNIVERSAL &&
tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) {
VALUE klass = *ossl_asn1_info[tag].klass;
- if (tag == V_ASN1_EOC)
- asn1data = rb_funcall(cASN1EndOfContent, rb_intern("new"), 0);
- else {
- VALUE args[4] = { value, INT2NUM(tag), Qnil, tc };
- asn1data = rb_funcallv_public(klass, rb_intern("new"), 4, args);
- }
+ VALUE args[4];
+ args[0] = value;
+ args[1] = INT2NUM(tag);
+ args[2] = Qnil;
+ args[3] = tc;
+ asn1data = rb_obj_alloc(klass);
+ ossl_asn1_initialize(4, args, asn1data);
if(tag == V_ASN1_BIT_STRING){
rb_ivar_set(asn1data, sivUNUSED_BITS, LONG2NUM(flag));
}
}
else {
- VALUE args[3] = { value, INT2NUM(tag), tc };
- asn1data = rb_funcallv_public(cASN1Data, rb_intern("new"), 3, args);
+ asn1data = rb_obj_alloc(cASN1Data);
+ ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), tc);
}
return asn1data;
@@ -806,20 +842,20 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
}
if (tc == sym_UNIVERSAL) {
- if (tag == V_ASN1_SEQUENCE) {
- VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
- asn1data = rb_funcallv_public(cASN1Sequence, rb_intern("new"), 4, args);
- } else if (tag == V_ASN1_SET) {
- VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
- asn1data = rb_funcallv_public(cASN1Set, rb_intern("new"), 4, args);
- } else {
- VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
- asn1data = rb_funcallv_public(cASN1Constructive, rb_intern("new"), 4, args);
- }
+ VALUE args[4];
+ if (tag == V_ASN1_SEQUENCE || tag == V_ASN1_SET)
+ asn1data = rb_obj_alloc(*ossl_asn1_info[tag].klass);
+ else
+ asn1data = rb_obj_alloc(cASN1Constructive);
+ args[0] = ary;
+ args[1] = INT2NUM(tag);
+ args[2] = Qnil;
+ args[3] = tc;
+ ossl_asn1_initialize(4, args, asn1data);
}
else {
- VALUE args[3] = {ary, INT2NUM(tag), tc};
- asn1data = rb_funcallv_public(cASN1Data, rb_intern("new"), 3, args);
+ asn1data = rb_obj_alloc(cASN1Data);
+ ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), tc);
}
if (indefinite)
@@ -1012,6 +1048,83 @@ ossl_asn1_decode_all(VALUE self, VALUE obj)
return ary;
}
+/*
+ * call-seq:
+ * OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive
+ *
+ * _value_: is mandatory.
+ *
+ * _tag_: optional, may be specified for tagged values. If no _tag_ is
+ * specified, the UNIVERSAL tag corresponding to the Primitive sub-class
+ * is used by default.
+ *
+ * _tagging_: may be used as an encoding hint to encode a value either
+ * explicitly or implicitly, see ASN1 for possible values.
+ *
+ * _tag_class_: if _tag_ and _tagging_ are +nil+ then this is set to
+ * +:UNIVERSAL+ by default. If either _tag_ or _tagging_ are set then
+ * +:CONTEXT_SPECIFIC+ is used as the default. For possible values please
+ * cf. ASN1.
+ *
+ * == Example
+ * int = OpenSSL::ASN1::Integer.new(42)
+ * zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT)
+ * private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE)
+ */
+static VALUE
+ossl_asn1_initialize(int argc, VALUE *argv, VALUE self)
+{
+ VALUE value, tag, tagging, tag_class;
+ int default_tag;
+
+ rb_scan_args(argc, argv, "13", &value, &tag, &tagging, &tag_class);
+ default_tag = ossl_asn1_default_tag(self);
+
+ if (default_tag == -1 || argc > 1) {
+ if(NIL_P(tag))
+ ossl_raise(eASN1Error, "must specify tag number");
+ if(!NIL_P(tagging) && !SYMBOL_P(tagging))
+ ossl_raise(eASN1Error, "invalid tagging method");
+ if(NIL_P(tag_class)) {
+ if (NIL_P(tagging))
+ tag_class = sym_UNIVERSAL;
+ else
+ tag_class = sym_CONTEXT_SPECIFIC;
+ }
+ if(!SYMBOL_P(tag_class))
+ ossl_raise(eASN1Error, "invalid tag class");
+ }
+ else{
+ tag = INT2NUM(default_tag);
+ tagging = Qnil;
+ tag_class = sym_UNIVERSAL;
+ }
+ ossl_asn1_set_tag(self, tag);
+ ossl_asn1_set_value(self, value);
+ ossl_asn1_set_tagging(self, tagging);
+ ossl_asn1_set_tag_class(self, tag_class);
+ ossl_asn1_set_indefinite_length(self, Qfalse);
+ if (default_tag == V_ASN1_BIT_STRING)
+ rb_ivar_set(self, sivUNUSED_BITS, INT2FIX(0));
+
+ return self;
+}
+
+static VALUE
+ossl_asn1eoc_initialize(VALUE self) {
+ VALUE tag, tagging, tag_class, value;
+ tag = INT2FIX(0);
+ tagging = Qnil;
+ tag_class = sym_UNIVERSAL;
+ value = rb_str_new("", 0);
+ ossl_asn1_set_tag(self, tag);
+ ossl_asn1_set_value(self, value);
+ ossl_asn1_set_tagging(self, tagging);
+ ossl_asn1_set_tag_class(self, tag_class);
+ ossl_asn1_set_indefinite_length(self, Qfalse);
+ return self;
+}
+
static VALUE
ossl_asn1eoc_to_der(VALUE self)
{
@@ -1050,12 +1163,9 @@ ossl_asn1prim_to_der(VALUE self)
rb_jump_tag(state);
}
p0 = p1 = (unsigned char *)RSTRING_PTR(str);
- if (i2d_ASN1_TYPE(asn1, &p0) < 0) {
- ASN1_TYPE_free(asn1);
- ossl_raise(eASN1Error, "i2d_ASN1_TYPE");
- }
+ i2d_ASN1_TYPE(asn1, &p0);
ASN1_TYPE_free(asn1);
- ossl_str_adjust(str, p0);
+ assert(p0 - p1 == alllen);
/* Strip header since to_der_internal() wants only the payload */
j = ASN1_get_object((const unsigned char **)&p1, &bodylen, &tag, &tc, alllen);
@@ -1105,6 +1215,27 @@ ossl_asn1cons_to_der(VALUE self)
/*
* call-seq:
+ * asn1_ary.each { |asn1| block } => asn1_ary
+ *
+ * Calls the given block once for each element in self, passing that element
+ * as parameter _asn1_. If no block is given, an enumerator is returned
+ * instead.
+ *
+ * == Example
+ * asn1_ary.each do |asn1|
+ * puts asn1
+ * end
+ */
+static VALUE
+ossl_asn1cons_each(VALUE self)
+{
+ rb_block_call(ossl_asn1_get_value(self), id_each, 0, 0, 0, 0);
+
+ return self;
+}
+
+/*
+ * call-seq:
* OpenSSL::ASN1::ObjectId.register(object_id, short_name, long_name)
*
* This adds a new ObjectId to the internal tables. Where _object_id_ is the
@@ -1237,7 +1368,7 @@ ossl_asn1obj_get_oid(VALUE self)
#define OSSL_ASN1_IMPL_FACTORY_METHOD(klass) \
static VALUE ossl_asn1_##klass(int argc, VALUE *argv, VALUE self)\
-{ return rb_funcallv_public(cASN1##klass, rb_intern("new"), argc, argv); }
+{ return rb_funcall3(cASN1##klass, rb_intern("new"), argc, argv); }
OSSL_ASN1_IMPL_FACTORY_METHOD(Boolean)
OSSL_ASN1_IMPL_FACTORY_METHOD(Integer)
@@ -1523,6 +1654,42 @@ Init_ossl_asn1(void)
* puts int2.value # => 1
*/
cASN1Data = rb_define_class_under(mASN1, "ASN1Data", rb_cObject);
+ /*
+ * Carries the value of a ASN.1 type.
+ * Please confer Constructive and Primitive for the mappings between
+ * ASN.1 data types and Ruby classes.
+ */
+ rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0);
+ /*
+ * An Integer representing the tag number of this ASN1Data. Never +nil+.
+ */
+ rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0);
+ /*
+ * A Symbol representing the tag class of this ASN1Data. Never +nil+.
+ * See ASN1Data for possible values.
+ */
+ rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, 0);
+ /*
+ * Never +nil+. A boolean value indicating whether the encoding uses
+ * indefinite length (in the case of parsing) or whether an indefinite
+ * length form shall be used (in the encoding case).
+ * In DER, every value uses definite length form. But in scenarios where
+ * large amounts of data need to be transferred it might be desirable to
+ * have some kind of streaming support available.
+ * For example, huge OCTET STRINGs are preferably sent in smaller-sized
+ * chunks, each at a time.
+ * This is possible in BER by setting the length bytes of an encoding
+ * to zero and by this indicating that the following value will be
+ * sent in chunks. Indefinite length encodings are always constructed.
+ * The end of such a stream of chunks is indicated by sending a EOC
+ * (End of Content) tag. SETs and SEQUENCEs may use an indefinite length
+ * encoding, but also primitive types such as e.g. OCTET STRINGS or
+ * BIT STRINGS may leverage this functionality (cf. ITU-T X.690).
+ */
+ rb_attr(cASN1Data, rb_intern("indefinite_length"), 1, 1, 0);
+ rb_define_alias(cASN1Data, "infinite_length", "indefinite_length");
+ rb_define_alias(cASN1Data, "infinite_length=", "indefinite_length=");
+ rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3);
rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0);
/* Document-class: OpenSSL::ASN1::Primitive
@@ -1590,6 +1757,16 @@ Init_ossl_asn1(void)
* prim_zero_tagged_explicit = <class>.new(value, 0, :EXPLICIT)
*/
cASN1Primitive = rb_define_class_under(mASN1, "Primitive", cASN1Data);
+ /*
+ * May be used as a hint for encoding a value either implicitly or
+ * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
+ * _tagging_ is not set when a ASN.1 structure is parsed using
+ * OpenSSL::ASN1.decode.
+ */
+ rb_attr(cASN1Primitive, rb_intern("tagging"), 1, 1, Qtrue);
+ rb_undef_method(cASN1Primitive, "indefinite_length=");
+ rb_undef_method(cASN1Primitive, "infinite_length=");
+ rb_define_method(cASN1Primitive, "initialize", ossl_asn1_initialize, -1);
rb_define_method(cASN1Primitive, "to_der", ossl_asn1prim_to_der, 0);
/* Document-class: OpenSSL::ASN1::Constructive
@@ -1620,7 +1797,17 @@ Init_ossl_asn1(void)
* set = OpenSSL::ASN1::Set.new( [ int, str ] )
*/
cASN1Constructive = rb_define_class_under(mASN1,"Constructive", cASN1Data);
+ rb_include_module(cASN1Constructive, rb_mEnumerable);
+ /*
+ * May be used as a hint for encoding a value either implicitly or
+ * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
+ * _tagging_ is not set when a ASN.1 structure is parsed using
+ * OpenSSL::ASN1.decode.
+ */
+ rb_attr(cASN1Constructive, rb_intern("tagging"), 1, 1, Qtrue);
+ rb_define_method(cASN1Constructive, "initialize", ossl_asn1_initialize, -1);
rb_define_method(cASN1Constructive, "to_der", ossl_asn1cons_to_der, 0);
+ rb_define_method(cASN1Constructive, "each", ossl_asn1cons_each, 0);
#define OSSL_ASN1_DEFINE_CLASS(name, super) \
do{\
@@ -1669,10 +1856,13 @@ do{\
rb_define_alias(cASN1ObjectId, "short_name", "sn");
rb_define_alias(cASN1ObjectId, "long_name", "ln");
rb_define_method(cASN1ObjectId, "==", ossl_asn1obj_eq, 1);
+ rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, 0);
+ rb_define_method(cASN1EndOfContent, "initialize", ossl_asn1eoc_initialize, 0);
rb_define_method(cASN1EndOfContent, "to_der", ossl_asn1eoc_to_der, 0);
class_tag_map = rb_hash_new();
+ rb_gc_register_mark_object(class_tag_map);
rb_hash_aset(class_tag_map, cASN1EndOfContent, INT2NUM(V_ASN1_EOC));
rb_hash_aset(class_tag_map, cASN1Boolean, INT2NUM(V_ASN1_BOOLEAN));
rb_hash_aset(class_tag_map, cASN1Integer, INT2NUM(V_ASN1_INTEGER));
@@ -1696,5 +1886,6 @@ do{\
rb_hash_aset(class_tag_map, cASN1GeneralString, INT2NUM(V_ASN1_GENERALSTRING));
rb_hash_aset(class_tag_map, cASN1UniversalString, INT2NUM(V_ASN1_UNIVERSALSTRING));
rb_hash_aset(class_tag_map, cASN1BMPString, INT2NUM(V_ASN1_BMPSTRING));
- rb_define_const(mASN1, "CLASS_TAG_MAP", class_tag_map);
+
+ id_each = rb_intern_const("each");
}
diff --git a/ext/openssl/ossl_asn1.h b/ext/openssl/ossl_asn1.h
index 3a99400e18..939a96ce74 100644
--- a/ext/openssl/ossl_asn1.h
+++ b/ext/openssl/ossl_asn1.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_ASN1_H_)
#define _OSSL_ASN1_H_
@@ -55,7 +55,7 @@ extern VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */
extern VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */
extern VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
-extern VALUE cASN1EndOfContent; /* END OF CONTENT */
+ASN1_TYPE *ossl_asn1_get_asn1type(VALUE);
void Init_ossl_asn1(void);
diff --git a/ext/openssl/ossl_bio.c b/ext/openssl/ossl_bio.c
index 2ef2080507..42833d901a 100644
--- a/ext/openssl/ossl_bio.c
+++ b/ext/openssl/ossl_bio.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
diff --git a/ext/openssl/ossl_bio.h b/ext/openssl/ossl_bio.h
index 1b871f1cd7..da68c5e5a2 100644
--- a/ext/openssl/ossl_bio.h
+++ b/ext/openssl/ossl_bio.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_BIO_H_)
#define _OSSL_BIO_H_
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c
index 7393fdea56..bf2bac3679 100644
--- a/ext/openssl/ossl_bn.c
+++ b/ext/openssl/ossl_bn.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
/* modified by Michal Rokos <m.rokos@sh.cvut.cz> */
#include "ossl.h"
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_bn_type = {
{
0, ossl_bn_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_bn.h b/ext/openssl/ossl_bn.h
index 800f84cb1e..1cc041fc22 100644
--- a/ext/openssl/ossl_bn.h
+++ b/ext/openssl/ossl_bn.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_BN_H_)
#define _OSSL_BN_H_
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index cc0114f579..cb8fbc3ca2 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -42,7 +42,7 @@ static const rb_data_type_t ossl_cipher_type = {
{
0, ossl_cipher_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
@@ -386,23 +386,11 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
in = (unsigned char *)RSTRING_PTR(data);
in_len = RSTRING_LEN(data);
GetCipher(self, ctx);
-
- /*
- * As of OpenSSL 3.2, there is no reliable way to determine the required
- * output buffer size for arbitrary cipher modes.
- * https://github.com/openssl/openssl/issues/22628
- *
- * in_len+block_size is usually sufficient, but AES key wrap with padding
- * ciphers require in_len+15 even though they have a block size of 8 bytes.
- *
- * Using EVP_MAX_BLOCK_LENGTH (32) as a safe upper bound for ciphers
- * currently implemented in OpenSSL, but this can change in the future.
- */
- if (in_len > LONG_MAX - EVP_MAX_BLOCK_LENGTH) {
+ out_len = in_len+EVP_CIPHER_CTX_block_size(ctx);
+ if (out_len <= 0) {
ossl_raise(rb_eRangeError,
"data too big to make output buffer: %ld bytes", in_len);
}
- out_len = in_len + EVP_MAX_BLOCK_LENGTH;
if (NIL_P(str)) {
str = rb_str_new(0, out_len);
@@ -413,7 +401,7 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len))
ossl_raise(eCipherError, NULL);
- assert(out_len <= RSTRING_LEN(str));
+ assert(out_len < RSTRING_LEN(str));
rb_str_set_len(str, out_len);
return str;
@@ -454,8 +442,8 @@ ossl_cipher_final(VALUE self)
* call-seq:
* cipher.name -> string
*
- * Returns the short name of the cipher which may differ slightly from the
- * original name provided.
+ * Returns the name of the cipher which may differ slightly from the original
+ * name provided.
*/
static VALUE
ossl_cipher_name(VALUE self)
diff --git a/ext/openssl/ossl_cipher.h b/ext/openssl/ossl_cipher.h
index 07b50c3bd5..2392d41c6a 100644
--- a/ext/openssl/ossl_cipher.h
+++ b/ext/openssl/ossl_cipher.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_CIPHER_H_)
#define _OSSL_CIPHER_H_
diff --git a/ext/openssl/ossl_config.c b/ext/openssl/ossl_config.c
index 55875028b2..0bac027487 100644
--- a/ext/openssl/ossl_config.c
+++ b/ext/openssl/ossl_config.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -22,7 +22,7 @@ static const rb_data_type_t ossl_config_type = {
{
0, nconf_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
CONF *
diff --git a/ext/openssl/ossl_config.h b/ext/openssl/ossl_config.h
index a254360c2c..4e604f1aed 100644
--- a/ext/openssl/ossl_config.h
+++ b/ext/openssl/ossl_config.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#ifndef OSSL_CONFIG_H
#define OSSL_CONFIG_H
diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c
index 00ec8931ab..fc326ec14a 100644
--- a/ext/openssl/ossl_digest.c
+++ b/ext/openssl/ossl_digest.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -35,7 +35,7 @@ static const rb_data_type_t ossl_digest_type = {
{
0, ossl_digest_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
@@ -103,8 +103,7 @@ VALUE ossl_digest_update(VALUE, VALUE);
* Digest.new(string [, data]) -> Digest
*
* Creates a Digest instance based on _string_, which is either the ln
- * (long name) or sn (short name) of a supported digest algorithm. A list of
- * supported algorithms can be obtained by calling OpenSSL::Digest.digests.
+ * (long name) or sn (short name) of a supported digest algorithm.
*
* If _data_ (a String) is given, it is used as the initial input to the
* Digest instance, i.e.
@@ -163,32 +162,6 @@ ossl_digest_copy(VALUE self, VALUE other)
return self;
}
-static void
-add_digest_name_to_ary(const OBJ_NAME *name, void *arg)
-{
- VALUE ary = (VALUE)arg;
- rb_ary_push(ary, rb_str_new2(name->name));
-}
-
-/*
- * call-seq:
- * OpenSSL::Digest.digests -> array[string...]
- *
- * Returns the names of all available digests in an array.
- */
-static VALUE
-ossl_s_digests(VALUE self)
-{
- VALUE ary;
-
- ary = rb_ary_new();
- OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH,
- add_digest_name_to_ary,
- (void*)ary);
-
- return ary;
-}
-
/*
* call-seq:
* digest.reset -> self
@@ -272,8 +245,7 @@ ossl_digest_finish(int argc, VALUE *argv, VALUE self)
* call-seq:
* digest.name -> string
*
- * Returns the short name of this Digest algorithm which may differ slightly
- * from the original name provided.
+ * Returns the sn of this Digest algorithm.
*
* === Example
* digest = OpenSSL::Digest.new('SHA512')
@@ -440,7 +412,6 @@ Init_ossl_digest(void)
rb_define_alloc_func(cDigest, ossl_digest_alloc);
- rb_define_module_function(cDigest, "digests", ossl_s_digests, 0);
rb_define_method(cDigest, "initialize", ossl_digest_initialize, -1);
rb_define_method(cDigest, "initialize_copy", ossl_digest_copy, 1);
rb_define_method(cDigest, "reset", ossl_digest_reset, 0);
diff --git a/ext/openssl/ossl_digest.h b/ext/openssl/ossl_digest.h
index 99771b8ae1..50bf5666a3 100644
--- a/ext/openssl/ossl_digest.h
+++ b/ext/openssl/ossl_digest.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_DIGEST_H_)
#define _OSSL_DIGEST_H_
diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c
index 294d58adef..1abde7f766 100644
--- a/ext/openssl/ossl_engine.c
+++ b/ext/openssl/ossl_engine.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -78,7 +78,7 @@ static const rb_data_type_t ossl_engine_type = {
{
0, ossl_engine_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_engine.h b/ext/openssl/ossl_engine.h
index f6f4ff4c1f..cd548beea3 100644
--- a/ext/openssl/ossl_engine.h
+++ b/ext/openssl/ossl_engine.h
@@ -6,7 +6,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(OSSL_ENGINE_H)
#define OSSL_ENGINE_H
diff --git a/ext/openssl/ossl_hmac.c b/ext/openssl/ossl_hmac.c
index b1163f6127..1a5f471a27 100644
--- a/ext/openssl/ossl_hmac.c
+++ b/ext/openssl/ossl_hmac.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -42,7 +42,7 @@ static const rb_data_type_t ossl_hmac_type = {
{
0, ossl_hmac_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
diff --git a/ext/openssl/ossl_hmac.h b/ext/openssl/ossl_hmac.h
index 17427587b2..7c51f4722d 100644
--- a/ext/openssl/ossl_hmac.h
+++ b/ext/openssl/ossl_hmac.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_HMAC_H_)
#define _OSSL_HMAC_H_
diff --git a/ext/openssl/ossl_kdf.c b/ext/openssl/ossl_kdf.c
index ba197a659e..0d25a7304b 100644
--- a/ext/openssl/ossl_kdf.c
+++ b/ext/openssl/ossl_kdf.c
@@ -18,10 +18,10 @@ static VALUE mKDF, eKDF;
* of _length_ bytes.
*
* For more information about PBKDF2, see RFC 2898 Section 5.2
- * (https://www.rfc-editor.org/rfc/rfc2898#section-5.2).
+ * (https://tools.ietf.org/html/rfc2898#section-5.2).
*
* === Parameters
- * pass :: The password.
+ * pass :: The passphrase.
* salt :: The salt. Salts prevent attacks based on dictionaries of common
* passwords and attacks based on rainbow tables. It is a public
* value that can be safely stored along with the password (e.g.
@@ -81,10 +81,10 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
* bcrypt.
*
* The keyword arguments _N_, _r_ and _p_ can be used to tune scrypt. RFC 7914
- * (published on 2016-08, https://www.rfc-editor.org/rfc/rfc7914#section-2) states
+ * (published on 2016-08, https://tools.ietf.org/html/rfc7914#section-2) states
* that using values r=8 and p=1 appears to yield good results.
*
- * See RFC 7914 (https://www.rfc-editor.org/rfc/rfc7914) for more information.
+ * See RFC 7914 (https://tools.ietf.org/html/rfc7914) for more information.
*
* === Parameters
* pass :: Passphrase.
@@ -147,7 +147,7 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
* KDF.hkdf(ikm, salt:, info:, length:, hash:) -> String
*
* HMAC-based Extract-and-Expand Key Derivation Function (HKDF) as specified in
- * {RFC 5869}[https://www.rfc-editor.org/rfc/rfc5869].
+ * {RFC 5869}[https://tools.ietf.org/html/rfc5869].
*
* New in OpenSSL 1.1.0.
*
@@ -165,7 +165,7 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
* The hash function.
*
* === Example
- * # The values from https://www.rfc-editor.org/rfc/rfc5869#appendix-A.1
+ * # The values from https://datatracker.ietf.org/doc/html/rfc5869#appendix-A.1
* ikm = ["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*")
* salt = ["000102030405060708090a0b0c"].pack("H*")
* info = ["f0f1f2f3f4f5f6f7f8f9"].pack("H*")
diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c
index e822d5e0a9..9b1147367a 100644
--- a/ext/openssl/ossl_ns_spki.c
+++ b/ext/openssl/ossl_ns_spki.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -50,7 +50,7 @@ static const rb_data_type_t ossl_netscape_spki_type = {
{
0, ossl_netscape_spki_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -365,8 +365,8 @@ ossl_spki_verify(VALUE self, VALUE key)
*
* OpenSSL::Netscape is a namespace for SPKI (Simple Public Key
* Infrastructure) which implements Signed Public Key and Challenge.
- * See {RFC 2692}[https://www.rfc-editor.org/rfc/rfc2692] and {RFC
- * 2693}[https://www.rfc-editor.org/rfc/rfc2692] for details.
+ * See {RFC 2692}[http://tools.ietf.org/html/rfc2692] and {RFC
+ * 2693}[http://tools.ietf.org/html/rfc2692] for details.
*/
/* Document-class: OpenSSL::Netscape::SPKIError
diff --git a/ext/openssl/ossl_ns_spki.h b/ext/openssl/ossl_ns_spki.h
index 20d6857682..62ba8cb163 100644
--- a/ext/openssl/ossl_ns_spki.h
+++ b/ext/openssl/ossl_ns_spki.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_NS_SPKI_H_)
#define _OSSL_NS_SPKI_H_
diff --git a/ext/openssl/ossl_ocsp.c b/ext/openssl/ossl_ocsp.c
index 9796d44a26..9c8d768d87 100644
--- a/ext/openssl/ossl_ocsp.c
+++ b/ext/openssl/ossl_ocsp.c
@@ -6,7 +6,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -86,7 +86,7 @@ static const rb_data_type_t ossl_ocsp_request_type = {
{
0, ossl_ocsp_request_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -100,7 +100,7 @@ static const rb_data_type_t ossl_ocsp_response_type = {
{
0, ossl_ocsp_response_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -114,7 +114,7 @@ static const rb_data_type_t ossl_ocsp_basicresp_type = {
{
0, ossl_ocsp_basicresp_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -128,7 +128,7 @@ static const rb_data_type_t ossl_ocsp_singleresp_type = {
{
0, ossl_ocsp_singleresp_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -142,7 +142,7 @@ static const rb_data_type_t ossl_ocsp_certid_type = {
{
0, ossl_ocsp_certid_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
@@ -1701,7 +1701,7 @@ Init_ossl_ocsp(void)
* require 'net/http'
*
* http_response =
- * Net::HTTP.start ocsp_uri.hostname, ocsp_uri.port do |http|
+ * Net::HTTP.start ocsp_uri.hostname, ocsp.port do |http|
* http.post ocsp_uri.path, request.to_der,
* 'content-type' => 'application/ocsp-request'
* end
diff --git a/ext/openssl/ossl_ocsp.h b/ext/openssl/ossl_ocsp.h
index 07da7d1684..6d2aac8657 100644
--- a/ext/openssl/ossl_ocsp.h
+++ b/ext/openssl/ossl_ocsp.h
@@ -6,7 +6,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_OCSP_H_)
#define _OSSL_OCSP_H_
diff --git a/ext/openssl/ossl_pkcs12.c b/ext/openssl/ossl_pkcs12.c
index 1fcb1a88d3..fb947df1d0 100644
--- a/ext/openssl/ossl_pkcs12.c
+++ b/ext/openssl/ossl_pkcs12.c
@@ -1,6 +1,6 @@
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -44,7 +44,7 @@ static const rb_data_type_t ossl_pkcs12_type = {
{
0, ossl_pkcs12_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -134,10 +134,6 @@ ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self)
if (!NIL_P(keytype))
ktype = NUM2INT(keytype);
- if (ktype != 0 && ktype != KEY_SIG && ktype != KEY_EX) {
- ossl_raise(rb_eArgError, "Unknown key usage type %"PRIsVALUE, INT2NUM(ktype));
- }
-
obj = NewPKCS12(cPKCS12);
x509s = NIL_P(ca) ? NULL : ossl_x509_ary2sk(ca);
p12 = PKCS12_create(passphrase, friendlyname, key, x509, x509s,
@@ -276,8 +272,4 @@ Init_ossl_pkcs12(void)
rb_attr(cPKCS12, rb_intern("ca_certs"), 1, 0, Qfalse);
rb_define_method(cPKCS12, "initialize", ossl_pkcs12_initialize, -1);
rb_define_method(cPKCS12, "to_der", ossl_pkcs12_to_der, 0);
-
- /* MSIE specific PKCS12 key usage extensions */
- rb_define_const(cPKCS12, "KEY_EX", INT2NUM(KEY_EX));
- rb_define_const(cPKCS12, "KEY_SIG", INT2NUM(KEY_SIG));
}
diff --git a/ext/openssl/ossl_pkcs12.h b/ext/openssl/ossl_pkcs12.h
index d4003e81c9..fe4f15ef60 100644
--- a/ext/openssl/ossl_pkcs12.h
+++ b/ext/openssl/ossl_pkcs12.h
@@ -1,6 +1,6 @@
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_PKCS12_H_)
#define _OSSL_PKCS12_H_
diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c
index b7e6d330b2..dbe5347639 100644
--- a/ext/openssl/ossl_pkcs7.c
+++ b/ext/openssl/ossl_pkcs7.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -65,7 +65,7 @@ const rb_data_type_t ossl_pkcs7_type = {
{
0, ossl_pkcs7_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -79,7 +79,7 @@ static const rb_data_type_t ossl_pkcs7_signer_info_type = {
{
0, ossl_pkcs7_signer_info_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -93,7 +93,7 @@ static const rb_data_type_t ossl_pkcs7_recip_info_type = {
{
0, ossl_pkcs7_recip_info_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
@@ -165,11 +165,7 @@ ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg)
out = NULL;
pkcs7 = SMIME_read_PKCS7(in, &out);
BIO_free(in);
- if (!pkcs7)
- ossl_raise(ePKCS7Error, "Could not parse the PKCS7");
- if (!pkcs7->d.ptr)
- ossl_raise(ePKCS7Error, "No content in PKCS7");
-
+ if(!pkcs7) ossl_raise(ePKCS7Error, NULL);
data = out ? ossl_membio2str(out) : Qnil;
SetPKCS7(ret, pkcs7);
ossl_pkcs7_set_data(ret, data);
@@ -350,8 +346,6 @@ ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
BIO_free(in);
if (!p7)
ossl_raise(rb_eArgError, "Could not parse the PKCS7");
- if (!p7->d.ptr)
- ossl_raise(rb_eArgError, "No content in PKCS7");
RTYPEDDATA_DATA(self) = p7;
PKCS7_free(p7_orig);
@@ -848,25 +842,6 @@ ossl_pkcs7_to_der(VALUE self)
}
static VALUE
-ossl_pkcs7_to_text(VALUE self)
-{
- PKCS7 *pkcs7;
- BIO *out;
- VALUE str;
-
- GetPKCS7(self, pkcs7);
- if(!(out = BIO_new(BIO_s_mem())))
- ossl_raise(ePKCS7Error, NULL);
- if(!PKCS7_print_ctx(out, pkcs7, 0, NULL)) {
- BIO_free(out);
- ossl_raise(ePKCS7Error, NULL);
- }
- str = ossl_membio2str(out);
-
- return str;
-}
-
-static VALUE
ossl_pkcs7_to_pem(VALUE self)
{
PKCS7 *pkcs7;
@@ -1075,7 +1050,6 @@ Init_ossl_pkcs7(void)
rb_define_method(cPKCS7, "to_pem", ossl_pkcs7_to_pem, 0);
rb_define_alias(cPKCS7, "to_s", "to_pem");
rb_define_method(cPKCS7, "to_der", ossl_pkcs7_to_der, 0);
- rb_define_method(cPKCS7, "to_text", ossl_pkcs7_to_text, 0);
cPKCS7Signer = rb_define_class_under(cPKCS7, "SignerInfo", rb_cObject);
rb_define_const(cPKCS7, "Signer", cPKCS7Signer);
diff --git a/ext/openssl/ossl_pkcs7.h b/ext/openssl/ossl_pkcs7.h
index 4cbbc6a1ae..3e1b094670 100644
--- a/ext/openssl/ossl_pkcs7.h
+++ b/ext/openssl/ossl_pkcs7.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_PKCS7_H_)
#define _OSSL_PKCS7_H_
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index 6af2245f39..476256679b 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -35,7 +35,7 @@ const rb_data_type_t ossl_evp_pkey_type = {
{
0, ossl_evp_pkey_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -82,62 +82,31 @@ ossl_pkey_new(EVP_PKEY *pkey)
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
# include <openssl/decoder.h>
-static EVP_PKEY *
-ossl_pkey_read(BIO *bio, const char *input_type, int selection, VALUE pass)
+EVP_PKEY *
+ossl_pkey_read_generic(BIO *bio, VALUE pass)
{
void *ppass = (void *)pass;
OSSL_DECODER_CTX *dctx;
EVP_PKEY *pkey = NULL;
int pos = 0, pos2;
- dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, input_type, NULL, NULL,
- selection, NULL, NULL);
+ dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, NULL, 0, NULL, NULL);
if (!dctx)
goto out;
- if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
- ppass) != 1)
+ if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1)
+ goto out;
+
+ /* First check DER */
+ if (OSSL_DECODER_from_bio(dctx, bio) == 1)
goto out;
- while (1) {
- if (OSSL_DECODER_from_bio(dctx, bio) == 1)
- goto out;
- if (BIO_eof(bio))
- break;
- pos2 = BIO_tell(bio);
- if (pos2 < 0 || pos2 <= pos)
- break;
- ossl_clear_error();
- pos = pos2;
- }
- out:
OSSL_BIO_reset(bio);
- OSSL_DECODER_CTX_free(dctx);
- return pkey;
-}
-EVP_PKEY *
-ossl_pkey_read_generic(BIO *bio, VALUE pass)
-{
- EVP_PKEY *pkey = NULL;
- /* First check DER, then check PEM. */
- const char *input_types[] = {"DER", "PEM"};
- int input_type_num = (int)(sizeof(input_types) / sizeof(char *));
+ /* Then check PEM; multiple OSSL_DECODER_from_bio() calls may be needed */
+ if (OSSL_DECODER_CTX_set_input_type(dctx, "PEM") != 1)
+ goto out;
/*
- * Non-zero selections to try to decode.
- *
- * See EVP_PKEY_fromdata(3) - Selections to see all the selections.
- *
- * This is a workaround for the decoder failing to decode or returning
- * bogus keys with selection 0, if a key management provider is different
- * from a decoder provider. The workaround is to avoid using selection 0.
- *
- * Affected OpenSSL versions: >= 3.1.0, <= 3.1.2, or >= 3.0.0, <= 3.0.10
- * Fixed OpenSSL versions: 3.2, next release of the 3.1.z and 3.0.z
- *
- * See https://github.com/openssl/openssl/pull/21519 for details.
- *
- * First check for private key formats (EVP_PKEY_KEYPAIR). This is to keep
- * compatibility with ruby/openssl < 3.0 which decoded the following as a
- * private key.
+ * First check for private key formats. This is to keep compatibility with
+ * ruby/openssl < 3.0 which decoded the following as a private key.
*
* $ openssl ecparam -name prime256v1 -genkey -outform PEM
* -----BEGIN EC PARAMETERS-----
@@ -155,28 +124,36 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass)
*
* Note that normally, the input is supposed to contain a single decodable
* PEM block only, so this special handling should not create a new problem.
- *
- * Note that we need to create the OSSL_DECODER_CTX variable each time when
- * we use the different selection as a workaround.
- * See https://github.com/openssl/openssl/issues/20657 for details.
*/
- int selections[] = {
- EVP_PKEY_KEYPAIR,
- EVP_PKEY_KEY_PARAMETERS,
- EVP_PKEY_PUBLIC_KEY
- };
- int selection_num = (int)(sizeof(selections) / sizeof(int));
- int i, j;
-
- for (i = 0; i < input_type_num; i++) {
- for (j = 0; j < selection_num; j++) {
- pkey = ossl_pkey_read(bio, input_types[i], selections[j], pass);
- if (pkey) {
- goto out;
- }
- }
+ OSSL_DECODER_CTX_set_selection(dctx, EVP_PKEY_KEYPAIR);
+ while (1) {
+ if (OSSL_DECODER_from_bio(dctx, bio) == 1)
+ goto out;
+ if (BIO_eof(bio))
+ break;
+ pos2 = BIO_tell(bio);
+ if (pos2 < 0 || pos2 <= pos)
+ break;
+ ossl_clear_error();
+ pos = pos2;
}
+
+ OSSL_BIO_reset(bio);
+ OSSL_DECODER_CTX_set_selection(dctx, 0);
+ while (1) {
+ if (OSSL_DECODER_from_bio(dctx, bio) == 1)
+ goto out;
+ if (BIO_eof(bio))
+ break;
+ pos2 = BIO_tell(bio);
+ if (pos2 < 0 || pos2 <= pos)
+ break;
+ ossl_clear_error();
+ pos = pos2;
+ }
+
out:
+ OSSL_DECODER_CTX_free(dctx);
return pkey;
}
#else
@@ -283,9 +260,9 @@ struct pkey_blocking_generate_arg {
EVP_PKEY_CTX *ctx;
EVP_PKEY *pkey;
int state;
- unsigned int yield: 1;
- unsigned int genparam: 1;
- unsigned int interrupted: 1;
+ int yield: 1;
+ int genparam: 1;
+ int interrupted: 1;
};
static VALUE
@@ -635,72 +612,6 @@ ossl_pkey_initialize_copy(VALUE self, VALUE other)
}
#endif
-#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
-/*
- * call-seq:
- * OpenSSL::PKey.new_raw_private_key(algo, string) -> PKey
- *
- * See the OpenSSL documentation for EVP_PKEY_new_raw_private_key()
- */
-
-static VALUE
-ossl_pkey_new_raw_private_key(VALUE self, VALUE type, VALUE key)
-{
- EVP_PKEY *pkey;
- const EVP_PKEY_ASN1_METHOD *ameth;
- int pkey_id;
- size_t keylen;
-
- StringValue(type);
- StringValue(key);
- ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
- if (!ameth)
- ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
- EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
-
- keylen = RSTRING_LEN(key);
-
- pkey = EVP_PKEY_new_raw_private_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
- if (!pkey)
- ossl_raise(ePKeyError, "EVP_PKEY_new_raw_private_key");
-
- return ossl_pkey_new(pkey);
-}
-#endif
-
-#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
-/*
- * call-seq:
- * OpenSSL::PKey.new_raw_public_key(algo, string) -> PKey
- *
- * See the OpenSSL documentation for EVP_PKEY_new_raw_public_key()
- */
-
-static VALUE
-ossl_pkey_new_raw_public_key(VALUE self, VALUE type, VALUE key)
-{
- EVP_PKEY *pkey;
- const EVP_PKEY_ASN1_METHOD *ameth;
- int pkey_id;
- size_t keylen;
-
- StringValue(type);
- StringValue(key);
- ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
- if (!ameth)
- ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
- EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
-
- keylen = RSTRING_LEN(key);
-
- pkey = EVP_PKEY_new_raw_public_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
- if (!pkey)
- ossl_raise(ePKeyError, "EVP_PKEY_new_raw_public_key");
-
- return ossl_pkey_new(pkey);
-}
-#endif
-
/*
* call-seq:
* pkey.oid -> string
@@ -882,18 +793,6 @@ ossl_pkey_private_to_der(int argc, VALUE *argv, VALUE self)
*
* Serializes the private key to PEM-encoded PKCS #8 format. See #private_to_der
* for more details.
- *
- * An unencrypted PEM-encoded key will look like:
- *
- * -----BEGIN PRIVATE KEY-----
- * [...]
- * -----END PRIVATE KEY-----
- *
- * An encrypted PEM-encoded key will look like:
- *
- * -----BEGIN ENCRYPTED PRIVATE KEY-----
- * [...]
- * -----END ENCRYPTED PRIVATE KEY-----
*/
static VALUE
ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
@@ -901,35 +800,6 @@ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
return do_pkcs8_export(argc, argv, self, 0);
}
-#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
-/*
- * call-seq:
- * pkey.raw_private_key => string
- *
- * See the OpenSSL documentation for EVP_PKEY_get_raw_private_key()
- */
-
-static VALUE
-ossl_pkey_raw_private_key(VALUE self)
-{
- EVP_PKEY *pkey;
- VALUE str;
- size_t len;
-
- GetPKey(self, pkey);
- if (EVP_PKEY_get_raw_private_key(pkey, NULL, &len) != 1)
- ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key");
- str = rb_str_new(NULL, len);
-
- if (EVP_PKEY_get_raw_private_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1)
- ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key");
-
- rb_str_set_len(str, len);
-
- return str;
-}
-#endif
-
VALUE
ossl_pkey_export_spki(VALUE self, int to_der)
{
@@ -972,12 +842,6 @@ ossl_pkey_public_to_der(VALUE self)
* pkey.public_to_pem -> string
*
* Serializes the public key to PEM-encoded X.509 SubjectPublicKeyInfo format.
- *
- * A PEM-encoded key will look like:
- *
- * -----BEGIN PUBLIC KEY-----
- * [...]
- * -----END PUBLIC KEY-----
*/
static VALUE
ossl_pkey_public_to_pem(VALUE self)
@@ -985,35 +849,6 @@ ossl_pkey_public_to_pem(VALUE self)
return ossl_pkey_export_spki(self, 0);
}
-#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
-/*
- * call-seq:
- * pkey.raw_public_key => string
- *
- * See the OpenSSL documentation for EVP_PKEY_get_raw_public_key()
- */
-
-static VALUE
-ossl_pkey_raw_public_key(VALUE self)
-{
- EVP_PKEY *pkey;
- VALUE str;
- size_t len;
-
- GetPKey(self, pkey);
- if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1)
- ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key");
- str = rb_str_new(NULL, len);
-
- if (EVP_PKEY_get_raw_public_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1)
- ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key");
-
- rb_str_set_len(str, len);
-
- return str;
-}
-#endif
-
/*
* call-seq:
* pkey.compare?(another_pkey) -> true | false
@@ -1751,10 +1586,6 @@ Init_ossl_pkey(void)
rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
rb_define_module_function(mPKey, "generate_parameters", ossl_pkey_s_generate_parameters, -1);
rb_define_module_function(mPKey, "generate_key", ossl_pkey_s_generate_key, -1);
-#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
- rb_define_module_function(mPKey, "new_raw_private_key", ossl_pkey_new_raw_private_key, 2);
- rb_define_module_function(mPKey, "new_raw_public_key", ossl_pkey_new_raw_public_key, 2);
-#endif
rb_define_alloc_func(cPKey, ossl_pkey_alloc);
rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
@@ -1770,10 +1601,6 @@ Init_ossl_pkey(void)
rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1);
rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);
rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0);
-#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
- rb_define_method(cPKey, "raw_private_key", ossl_pkey_raw_private_key, 0);
- rb_define_method(cPKey, "raw_public_key", ossl_pkey_raw_public_key, 0);
-#endif
rb_define_method(cPKey, "compare?", ossl_pkey_compare, 1);
rb_define_method(cPKey, "sign", ossl_pkey_sign, -1);
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
index 37d828e048..10669b824c 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(OSSL_PKEY_H)
#define OSSL_PKEY_H
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index 00699b9b07..83c41378fe 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -216,20 +216,9 @@ ossl_dh_is_private(VALUE self)
* dh.to_pem -> aString
* dh.to_s -> aString
*
- * Serializes the DH parameters to a PEM-encoding.
- *
- * Note that any existing per-session public/private keys will *not* get
- * encoded, just the Diffie-Hellman parameters will be encoded.
- *
- * PEM-encoded parameters will look like:
- *
- * -----BEGIN DH PARAMETERS-----
- * [...]
- * -----END DH PARAMETERS-----
- *
- * See also #public_to_pem (X.509 SubjectPublicKeyInfo) and
- * #private_to_pem (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) for
- * serialization with the private or public key components.
+ * Encodes this DH to its PEM encoding. Note that any existing per-session
+ * public/private keys will *not* get encoded, just the Diffie-Hellman
+ * parameters will be encoded.
*/
static VALUE
ossl_dh_export(VALUE self)
@@ -255,14 +244,10 @@ ossl_dh_export(VALUE self)
* call-seq:
* dh.to_der -> aString
*
- * Serializes the DH parameters to a DER-encoding
- *
- * Note that any existing per-session public/private keys will *not* get
- * encoded, just the Diffie-Hellman parameters will be encoded.
- *
- * See also #public_to_der (X.509 SubjectPublicKeyInfo) and
- * #private_to_der (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) for
- * serialization with the private or public key components.
+ * Encodes this DH to its DER encoding. Note that any existing per-session
+ * public/private keys will *not* get encoded, just the Diffie-Hellman
+ * parameters will be encoded.
+
*/
static VALUE
ossl_dh_to_der(VALUE self)
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
index a7598d1e80..b097f8c9d2 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -211,58 +211,16 @@ ossl_dsa_is_private(VALUE self)
* dsa.to_pem([cipher, password]) -> aString
* dsa.to_s([cipher, password]) -> aString
*
- * Serializes a private or public key to a PEM-encoding.
+ * Encodes this DSA to its PEM encoding.
*
- * [When the key contains public components only]
+ * === Parameters
+ * * _cipher_ is an OpenSSL::Cipher.
+ * * _password_ is a string containing your password.
*
- * Serializes it into an X.509 SubjectPublicKeyInfo.
- * The parameters _cipher_ and _password_ are ignored.
+ * === Examples
+ * DSA.to_pem -> aString
+ * DSA.to_pem(cipher, 'mypassword') -> aString
*
- * A PEM-encoded key will look like:
- *
- * -----BEGIN PUBLIC KEY-----
- * [...]
- * -----END PUBLIC KEY-----
- *
- * Consider using #public_to_pem instead. This serializes the key into an
- * X.509 SubjectPublicKeyInfo regardless of whether it is a public key
- * or a private key.
- *
- * [When the key contains private components, and no parameters are given]
- *
- * Serializes it into a traditional \OpenSSL DSAPrivateKey.
- *
- * A PEM-encoded key will look like:
- *
- * -----BEGIN DSA PRIVATE KEY-----
- * [...]
- * -----END DSA PRIVATE KEY-----
- *
- * [When the key contains private components, and _cipher_ and _password_ are given]
- *
- * Serializes it into a traditional \OpenSSL DSAPrivateKey and encrypts it in
- * OpenSSL's traditional PEM encryption format.
- * _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an
- * instance of OpenSSL::Cipher.
- *
- * An encrypted PEM-encoded key will look like:
- *
- * -----BEGIN DSA PRIVATE KEY-----
- * Proc-Type: 4,ENCRYPTED
- * DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0
- *
- * [...]
- * -----END DSA PRIVATE KEY-----
- *
- * Note that this format uses MD5 to derive the encryption key, and hence
- * will not be available on FIPS-compliant systems.
- *
- * <b>This method is kept for compatibility.</b>
- * This should only be used when the traditional, non-standard \OpenSSL format
- * is required.
- *
- * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem
- * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead.
*/
static VALUE
ossl_dsa_export(int argc, VALUE *argv, VALUE self)
@@ -280,15 +238,8 @@ ossl_dsa_export(int argc, VALUE *argv, VALUE self)
* call-seq:
* dsa.to_der -> aString
*
- * Serializes a private or public key to a DER-encoding.
- *
- * See #to_pem for details.
- *
- * <b>This method is kept for compatibility.</b>
- * This should only be used when the traditional, non-standard \OpenSSL format
- * is required.
+ * Encodes this DSA to its DER encoding.
*
- * Consider using #public_to_der or #private_to_der instead.
*/
static VALUE
ossl_dsa_to_der(VALUE self)
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index 4b3a1fd0fe..92842f95ac 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -400,61 +400,13 @@ static VALUE ossl_ec_key_is_private(VALUE self)
/*
* call-seq:
- * key.export([cipher, password]) => String
- * key.to_pem([cipher, password]) => String
+ * key.export([cipher, pass_phrase]) => String
+ * key.to_pem([cipher, pass_phrase]) => String
*
- * Serializes a private or public key to a PEM-encoding.
- *
- * [When the key contains public components only]
- *
- * Serializes it into an X.509 SubjectPublicKeyInfo.
- * The parameters _cipher_ and _password_ are ignored.
- *
- * A PEM-encoded key will look like:
- *
- * -----BEGIN PUBLIC KEY-----
- * [...]
- * -----END PUBLIC KEY-----
- *
- * Consider using #public_to_pem instead. This serializes the key into an
- * X.509 SubjectPublicKeyInfo regardless of whether it is a public key
- * or a private key.
- *
- * [When the key contains private components, and no parameters are given]
- *
- * Serializes it into a SEC 1/RFC 5915 ECPrivateKey.
- *
- * A PEM-encoded key will look like:
- *
- * -----BEGIN EC PRIVATE KEY-----
- * [...]
- * -----END EC PRIVATE KEY-----
- *
- * [When the key contains private components, and _cipher_ and _password_ are given]
- *
- * Serializes it into a SEC 1/RFC 5915 ECPrivateKey
- * and encrypts it in OpenSSL's traditional PEM encryption format.
- * _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an
- * instance of OpenSSL::Cipher.
- *
- * An encrypted PEM-encoded key will look like:
- *
- * -----BEGIN EC PRIVATE KEY-----
- * Proc-Type: 4,ENCRYPTED
- * DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0
- *
- * [...]
- * -----END EC PRIVATE KEY-----
- *
- * Note that this format uses MD5 to derive the encryption key, and hence
- * will not be available on FIPS-compliant systems.
- *
- * <b>This method is kept for compatibility.</b>
- * This should only be used when the SEC 1/RFC 5915 ECPrivateKey format is
- * required.
- *
- * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem
- * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead.
+ * Outputs the EC key in PEM encoding. If _cipher_ and _pass_phrase_ are given
+ * they will be used to encrypt the key. _cipher_ must be an OpenSSL::Cipher
+ * instance. Note that encryption will only be effective for a private key,
+ * public keys will always be encoded in plain text.
*/
static VALUE
ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
@@ -474,15 +426,7 @@ ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
* call-seq:
* key.to_der => String
*
- * Serializes a private or public key to a DER-encoding.
- *
- * See #to_pem for details.
- *
- * <b>This method is kept for compatibility.</b>
- * This should only be used when the SEC 1/RFC 5915 ECPrivateKey format is
- * required.
- *
- * Consider using #public_to_der or #private_to_der instead.
+ * See the OpenSSL documentation for i2d_ECPrivateKey_bio()
*/
static VALUE
ossl_ec_key_to_der(VALUE self)
@@ -586,7 +530,7 @@ static const rb_data_type_t ossl_ec_group_type = {
{
0, ossl_ec_group_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -1171,7 +1115,7 @@ static const rb_data_type_t ossl_ec_point_type = {
{
0, ossl_ec_point_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 7d986989e5..072adabe62 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -50,8 +50,8 @@ VALUE eRSAError;
/*
* call-seq:
* RSA.new -> rsa
- * RSA.new(encoded_key [, password ]) -> rsa
- * RSA.new(encoded_key) { password } -> rsa
+ * RSA.new(encoded_key [, passphrase]) -> rsa
+ * RSA.new(encoded_key) { passphrase } -> rsa
* RSA.new(size [, exponent]) -> rsa
*
* Generates or loads an \RSA keypair.
@@ -61,9 +61,9 @@ VALUE eRSAError;
* #set_crt_params.
*
* If called with a String, tries to parse as DER or PEM encoding of an \RSA key.
- * Note that if _password_ is not specified, but the key is encrypted with a
- * password, \OpenSSL will prompt for it.
- * See also OpenSSL::PKey.read which can parse keys of any kind.
+ * Note that, if _passphrase_ is not specified but the key is encrypted with a
+ * passphrase, \OpenSSL will prompt for it.
+ * See also OpenSSL::PKey.read which can parse keys of any kinds.
*
* If called with a number, generates a new key pair. This form works as an
* alias of RSA.generate.
@@ -71,7 +71,7 @@ VALUE eRSAError;
* Examples:
* OpenSSL::PKey::RSA.new 2048
* OpenSSL::PKey::RSA.new File.read 'rsa.pem'
- * OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my password'
+ * OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my pass phrase'
*/
static VALUE
ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
@@ -217,61 +217,13 @@ can_export_rsaprivatekey(VALUE self)
/*
* call-seq:
- * rsa.export([cipher, password]) => PEM-format String
- * rsa.to_pem([cipher, password]) => PEM-format String
- * rsa.to_s([cipher, password]) => PEM-format String
+ * rsa.export([cipher, pass_phrase]) => PEM-format String
+ * rsa.to_pem([cipher, pass_phrase]) => PEM-format String
+ * rsa.to_s([cipher, pass_phrase]) => PEM-format String
*
- * Serializes a private or public key to a PEM-encoding.
- *
- * [When the key contains public components only]
- *
- * Serializes it into an X.509 SubjectPublicKeyInfo.
- * The parameters _cipher_ and _password_ are ignored.
- *
- * A PEM-encoded key will look like:
- *
- * -----BEGIN PUBLIC KEY-----
- * [...]
- * -----END PUBLIC KEY-----
- *
- * Consider using #public_to_pem instead. This serializes the key into an
- * X.509 SubjectPublicKeyInfo regardless of whether the key is a public key
- * or a private key.
- *
- * [When the key contains private components, and no parameters are given]
- *
- * Serializes it into a PKCS #1 RSAPrivateKey.
- *
- * A PEM-encoded key will look like:
- *
- * -----BEGIN RSA PRIVATE KEY-----
- * [...]
- * -----END RSA PRIVATE KEY-----
- *
- * [When the key contains private components, and _cipher_ and _password_ are given]
- *
- * Serializes it into a PKCS #1 RSAPrivateKey
- * and encrypts it in OpenSSL's traditional PEM encryption format.
- * _cipher_ must be a cipher name understood by OpenSSL::Cipher.new or an
- * instance of OpenSSL::Cipher.
- *
- * An encrypted PEM-encoded key will look like:
- *
- * -----BEGIN RSA PRIVATE KEY-----
- * Proc-Type: 4,ENCRYPTED
- * DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0
- *
- * [...]
- * -----END RSA PRIVATE KEY-----
- *
- * Note that this format uses MD5 to derive the encryption key, and hence
- * will not be available on FIPS-compliant systems.
- *
- * <b>This method is kept for compatibility.</b>
- * This should only be used when the PKCS #1 RSAPrivateKey format is required.
- *
- * Consider using #public_to_pem (X.509 SubjectPublicKeyInfo) or #private_to_pem
- * (PKCS #8 PrivateKeyInfo or EncryptedPrivateKeyInfo) instead.
+ * Outputs this keypair in PEM encoding. If _cipher_ and _pass_phrase_ are
+ * given they will be used to encrypt the key. _cipher_ must be an
+ * OpenSSL::Cipher instance.
*/
static VALUE
ossl_rsa_export(int argc, VALUE *argv, VALUE self)
@@ -286,14 +238,7 @@ ossl_rsa_export(int argc, VALUE *argv, VALUE self)
* call-seq:
* rsa.to_der => DER-format String
*
- * Serializes a private or public key to a DER-encoding.
- *
- * See #to_pem for details.
- *
- * <b>This method is kept for compatibility.</b>
- * This should only be used when the PKCS #1 RSAPrivateKey format is required.
- *
- * Consider using #public_to_der or #private_to_der instead.
+ * Outputs this keypair in DER encoding.
*/
static VALUE
ossl_rsa_to_der(VALUE self)
diff --git a/ext/openssl/ossl_provider.c b/ext/openssl/ossl_provider.c
deleted file mode 100644
index d1f6c5d427..0000000000
--- a/ext/openssl/ossl_provider.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
- */
-#include "ossl.h"
-
-#ifdef OSSL_USE_PROVIDER
-# include <openssl/provider.h>
-
-#define NewProvider(klass) \
- TypedData_Wrap_Struct((klass), &ossl_provider_type, 0)
-#define SetProvider(obj, provider) do { \
- if (!(provider)) { \
- ossl_raise(rb_eRuntimeError, "Provider wasn't initialized."); \
- } \
- RTYPEDDATA_DATA(obj) = (provider); \
-} while(0)
-#define GetProvider(obj, provider) do { \
- TypedData_Get_Struct((obj), OSSL_PROVIDER, &ossl_provider_type, (provider)); \
- if (!(provider)) { \
- ossl_raise(rb_eRuntimeError, "PROVIDER wasn't initialized."); \
- } \
-} while (0)
-
-static const rb_data_type_t ossl_provider_type = {
- "OpenSSL/Provider",
- {
- 0,
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
-};
-
-/*
- * Classes
- */
-/* Document-class: OpenSSL::Provider
- *
- * This class is the access to openssl's Provider
- * See also, https://www.openssl.org/docs/manmaster/man7/provider.html
- */
-static VALUE cProvider;
-/* Document-class: OpenSSL::Provider::ProviderError
- *
- * This is the generic exception for OpenSSL::Provider related errors
- */
-static VALUE eProviderError;
-
-/*
- * call-seq:
- * OpenSSL::Provider.load(name) -> provider
- *
- * This method loads and initializes a provider
- */
-static VALUE
-ossl_provider_s_load(VALUE klass, VALUE name)
-{
- OSSL_PROVIDER *provider = NULL;
- VALUE obj;
-
- const char *provider_name_ptr = StringValueCStr(name);
-
- provider = OSSL_PROVIDER_load(NULL, provider_name_ptr);
- if (provider == NULL) {
- ossl_raise(eProviderError, "Failed to load %s provider", provider_name_ptr);
- }
- obj = NewProvider(klass);
- SetProvider(obj, provider);
-
- return obj;
-}
-
-struct ary_with_state { VALUE ary; int state; };
-struct rb_push_provider_name_args { OSSL_PROVIDER *prov; VALUE ary; };
-
-static VALUE
-rb_push_provider_name(VALUE rb_push_provider_name_args)
-{
- struct rb_push_provider_name_args *args = (struct rb_push_provider_name_args *)rb_push_provider_name_args;
-
- VALUE name = rb_str_new2(OSSL_PROVIDER_get0_name(args->prov));
- return rb_ary_push(args->ary, name);
-}
-
-static int
-push_provider(OSSL_PROVIDER *prov, void *cbdata)
-{
- struct ary_with_state *ary_with_state = (struct ary_with_state *)cbdata;
- struct rb_push_provider_name_args args = { prov, ary_with_state->ary };
-
- rb_protect(rb_push_provider_name, (VALUE)&args, &ary_with_state->state);
- if (ary_with_state->state) {
- return 0;
- } else {
- return 1;
- }
-}
-
-/*
- * call-seq:
- * OpenSSL::Provider.provider_names -> [provider_name, ...]
- *
- * Returns an array of currently loaded provider names.
- */
-static VALUE
-ossl_provider_s_provider_names(VALUE klass)
-{
- VALUE ary = rb_ary_new();
- struct ary_with_state cbdata = { ary, 0 };
-
- int result = OSSL_PROVIDER_do_all(NULL, &push_provider, (void*)&cbdata);
- if (result != 1 ) {
- if (cbdata.state) {
- rb_jump_tag(cbdata.state);
- } else {
- ossl_raise(eProviderError, "Failed to load provider names");
- }
- }
-
- return ary;
-}
-
-/*
- * call-seq:
- * provider.unload -> true
- *
- * This method unloads this provider.
- *
- * if provider unload fails or already unloaded, it raises OpenSSL::Provider::ProviderError
- */
-static VALUE
-ossl_provider_unload(VALUE self)
-{
- OSSL_PROVIDER *prov;
- if (RTYPEDDATA_DATA(self) == NULL) {
- ossl_raise(eProviderError, "Provider already unloaded.");
- }
- GetProvider(self, prov);
-
- int result = OSSL_PROVIDER_unload(prov);
-
- if (result != 1) {
- ossl_raise(eProviderError, "Failed to unload provider");
- }
- RTYPEDDATA_DATA(self) = NULL;
- return Qtrue;
-}
-
-/*
- * call-seq:
- * provider.name -> string
- *
- * Get the name of this provider.
- *
- * if this provider is already unloaded, it raises OpenSSL::Provider::ProviderError
- */
-static VALUE
-ossl_provider_get_name(VALUE self)
-{
- OSSL_PROVIDER *prov;
- if (RTYPEDDATA_DATA(self) == NULL) {
- ossl_raise(eProviderError, "Provider already unloaded.");
- }
- GetProvider(self, prov);
-
- return rb_str_new2(OSSL_PROVIDER_get0_name(prov));
-}
-
-/*
- * call-seq:
- * provider.inspect -> string
- *
- * Pretty prints this provider.
- */
-static VALUE
-ossl_provider_inspect(VALUE self)
-{
- OSSL_PROVIDER *prov;
- if (RTYPEDDATA_DATA(self) == NULL ) {
- return rb_sprintf("#<%"PRIsVALUE" unloaded provider>", rb_obj_class(self));
- }
- GetProvider(self, prov);
-
- return rb_sprintf("#<%"PRIsVALUE" name=\"%s\">",
- rb_obj_class(self), OSSL_PROVIDER_get0_name(prov));
-}
-
-void
-Init_ossl_provider(void)
-{
-#if 0
- mOSSL = rb_define_module("OpenSSL");
- eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
-#endif
-
- cProvider = rb_define_class_under(mOSSL, "Provider", rb_cObject);
- eProviderError = rb_define_class_under(cProvider, "ProviderError", eOSSLError);
-
- rb_undef_alloc_func(cProvider);
- rb_define_singleton_method(cProvider, "load", ossl_provider_s_load, 1);
- rb_define_singleton_method(cProvider, "provider_names", ossl_provider_s_provider_names, 0);
-
- rb_define_method(cProvider, "unload", ossl_provider_unload, 0);
- rb_define_method(cProvider, "name", ossl_provider_get_name, 0);
- rb_define_method(cProvider, "inspect", ossl_provider_inspect, 0);
-}
-#else
-void
-Init_ossl_provider(void)
-{
-}
-#endif
diff --git a/ext/openssl/ossl_provider.h b/ext/openssl/ossl_provider.h
deleted file mode 100644
index 1d69cb1e44..0000000000
--- a/ext/openssl/ossl_provider.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#if !defined(OSSL_PROVIDER_H)
-#define OSSL_PROVIDER_H
-
-void Init_ossl_provider(void);
-#endif
diff --git a/ext/openssl/ossl_rand.c b/ext/openssl/ossl_rand.c
index 774e7836dc..659dc818b6 100644
--- a/ext/openssl/ossl_rand.c
+++ b/ext/openssl/ossl_rand.c
@@ -5,7 +5,7 @@
* All rights reserved.
*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
diff --git a/ext/openssl/ossl_rand.h b/ext/openssl/ossl_rand.h
index 874ab539b8..8f77a3b239 100644
--- a/ext/openssl/ossl_rand.h
+++ b/ext/openssl/ossl_rand.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_RAND_H_)
#define _OSSL_RAND_H_
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c
index 457630ddc8..f63992664a 100644
--- a/ext/openssl/ossl_ssl.c
+++ b/ext/openssl/ossl_ssl.c
@@ -7,7 +7,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -77,7 +77,7 @@ static const rb_data_type_t ossl_sslctx_type = {
{
ossl_sslctx_mark, ossl_sslctx_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -885,9 +885,9 @@ ossl_sslctx_setup(VALUE self)
if (ca_path && !SSL_CTX_load_verify_dir(ctx, ca_path))
ossl_raise(eSSLError, "SSL_CTX_load_verify_dir");
#else
- if (ca_file || ca_path) {
- if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
- ossl_raise(eSSLError, "SSL_CTX_load_verify_locations");
+ if(ca_file || ca_path){
+ if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
+ rb_warning("can't set verify locations");
}
#endif
@@ -1553,10 +1553,6 @@ ossl_ssl_mark(void *ptr)
{
SSL *ssl = ptr;
rb_gc_mark((VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx));
-
- // Note: this reference is stored as @verify_callback so we don't need to mark it.
- // However we do need to ensure GC compaction won't move it, hence why
- // we call rb_gc_mark here.
rb_gc_mark((VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_vcb_idx));
}
@@ -1571,7 +1567,7 @@ const rb_data_type_t ossl_ssl_type = {
{
ossl_ssl_mark, ossl_ssl_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -1650,8 +1646,6 @@ ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)
SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void *)self);
SSL_set_info_callback(ssl, ssl_info_cb);
verify_cb = rb_attr_get(v_ctx, id_i_verify_callback);
- // We don't need to trigger a write barrier because it's already
- // an instance variable of this object.
SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)verify_cb);
rb_call_super(0, NULL);
@@ -1659,17 +1653,6 @@ ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)
return self;
}
-#ifndef HAVE_RB_IO_DESCRIPTOR
-static int
-io_descriptor_fallback(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- return fptr->fd;
-}
-#define rb_io_descriptor io_descriptor_fallback
-#endif
-
static VALUE
ossl_ssl_setup(VALUE self)
{
@@ -1685,8 +1668,8 @@ ossl_ssl_setup(VALUE self)
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
rb_io_check_writable(fptr);
- if (!SSL_set_fd(ssl, TO_SOCKET(rb_io_descriptor(io))))
- ossl_raise(eSSLError, "SSL_set_fd");
+ if (!SSL_set_fd(ssl, TO_SOCKET(fptr->fd)))
+ ossl_raise(eSSLError, "SSL_set_fd");
return Qtrue;
}
@@ -1725,37 +1708,22 @@ no_exception_p(VALUE opts)
#define RUBY_IO_TIMEOUT_DEFAULT Qnil
#endif
-#ifdef HAVE_RB_IO_TIMEOUT
-#define IO_TIMEOUT_ERROR rb_eIOTimeoutError
-#else
-#define IO_TIMEOUT_ERROR rb_eIOError
-#endif
-
-
static void
-io_wait_writable(VALUE io)
+io_wait_writable(rb_io_t *fptr)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
- if (!rb_io_maybe_wait_writable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
- rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become writable!");
- }
+ rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
#else
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
rb_io_wait_writable(fptr->fd);
#endif
}
static void
-io_wait_readable(VALUE io)
+io_wait_readable(rb_io_t *fptr)
{
#ifdef HAVE_RB_IO_MAYBE_WAIT
- if (!rb_io_maybe_wait_readable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
- rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become readable!");
- }
+ rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
#else
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
rb_io_wait_readable(fptr->fd);
#endif
}
@@ -1764,74 +1732,75 @@ static VALUE
ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
{
SSL *ssl;
+ rb_io_t *fptr;
int ret, ret2;
VALUE cb_state;
int nonblock = opts != Qfalse;
+#if defined(SSL_R_CERTIFICATE_VERIFY_FAILED)
+ unsigned long err;
+#endif
rb_ivar_set(self, ID_callback_state, Qnil);
GetSSL(self, ssl);
- VALUE io = rb_attr_get(self, id_i_io);
- for (;;) {
- ret = func(ssl);
+ GetOpenFile(rb_attr_get(self, id_i_io), fptr);
+ for(;;){
+ ret = func(ssl);
- cb_state = rb_attr_get(self, ID_callback_state);
+ cb_state = rb_attr_get(self, ID_callback_state);
if (!NIL_P(cb_state)) {
- /* must cleanup OpenSSL error stack before re-raising */
- ossl_clear_error();
- rb_jump_tag(NUM2INT(cb_state));
- }
+ /* must cleanup OpenSSL error stack before re-raising */
+ ossl_clear_error();
+ rb_jump_tag(NUM2INT(cb_state));
+ }
- if (ret > 0)
- break;
+ if (ret > 0)
+ break;
- switch ((ret2 = ssl_get_error(ssl, ret))) {
- case SSL_ERROR_WANT_WRITE:
+ switch((ret2 = ssl_get_error(ssl, ret))){
+ case SSL_ERROR_WANT_WRITE:
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
- io_wait_writable(io);
+ io_wait_writable(fptr);
continue;
- case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_READ:
if (no_exception_p(opts)) { return sym_wait_readable; }
read_would_block(nonblock);
- io_wait_readable(io);
+ io_wait_readable(fptr);
continue;
- case SSL_ERROR_SYSCALL:
+ case SSL_ERROR_SYSCALL:
#ifdef __APPLE__
/* See ossl_ssl_write_internal() */
if (errno == EPROTOTYPE)
continue;
#endif
- if (errno) rb_sys_fail(funcname);
- /* fallthrough */
- default: {
- VALUE error_append = Qnil;
+ if (errno) rb_sys_fail(funcname);
+ ossl_raise(eSSLError, "%s SYSCALL returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s",
+ funcname, ret2, errno, peeraddr_ip_str(self), SSL_state_string_long(ssl));
+
#if defined(SSL_R_CERTIFICATE_VERIFY_FAILED)
- unsigned long err = ERR_peek_last_error();
- if (ERR_GET_LIB(err) == ERR_LIB_SSL &&
- ERR_GET_REASON(err) == SSL_R_CERTIFICATE_VERIFY_FAILED) {
- const char *err_msg = ERR_reason_error_string(err),
- *verify_msg = X509_verify_cert_error_string(SSL_get_verify_result(ssl));
- if (!err_msg)
- err_msg = "(null)";
- if (!verify_msg)
- verify_msg = "(null)";
- ossl_clear_error(); /* let ossl_raise() not append message */
- error_append = rb_sprintf(": %s (%s)", err_msg, verify_msg);
- }
+ case SSL_ERROR_SSL:
+ err = ERR_peek_last_error();
+ if (ERR_GET_LIB(err) == ERR_LIB_SSL &&
+ ERR_GET_REASON(err) == SSL_R_CERTIFICATE_VERIFY_FAILED) {
+ const char *err_msg = ERR_reason_error_string(err),
+ *verify_msg = X509_verify_cert_error_string(SSL_get_verify_result(ssl));
+ if (!err_msg)
+ err_msg = "(null)";
+ if (!verify_msg)
+ verify_msg = "(null)";
+ ossl_clear_error(); /* let ossl_raise() not append message */
+ ossl_raise(eSSLError, "%s returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s: %s (%s)",
+ funcname, ret2, errno, peeraddr_ip_str(self), SSL_state_string_long(ssl),
+ err_msg, verify_msg);
+ }
#endif
- ossl_raise(eSSLError,
- "%s%s returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s%"PRIsVALUE,
- funcname,
- ret2 == SSL_ERROR_SYSCALL ? " SYSCALL" : "",
- ret2,
- errno,
- peeraddr_ip_str(self),
- SSL_state_string_long(ssl),
- error_append);
- }
- }
+ /* fallthrough */
+ default:
+ ossl_raise(eSSLError, "%s returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s",
+ funcname, ret2, errno, peeraddr_ip_str(self), SSL_state_string_long(ssl));
+ }
}
return self;
@@ -1937,7 +1906,8 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
SSL *ssl;
int ilen;
VALUE len, str;
- VALUE opts = Qnil;
+ rb_io_t *fptr;
+ VALUE io, opts = Qnil;
if (nonblock) {
rb_scan_args(argc, argv, "11:", &len, &str, &opts);
@@ -1958,13 +1928,12 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
else
rb_str_modify_expand(str, ilen - RSTRING_LEN(str));
}
+ rb_str_set_len(str, 0);
+ if (ilen == 0)
+ return str;
- if (ilen == 0) {
- rb_str_set_len(str, 0);
- return str;
- }
-
- VALUE io = rb_attr_get(self, id_i_io);
+ io = rb_attr_get(self, id_i_io);
+ GetOpenFile(io, fptr);
rb_str_locktmp(str);
for (;;) {
@@ -1984,7 +1953,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
}
- io_wait_writable(io);
+ io_wait_writable(fptr);
continue;
case SSL_ERROR_WANT_READ:
if (nonblock) {
@@ -1992,7 +1961,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
if (no_exception_p(opts)) { return sym_wait_readable; }
read_would_block(nonblock);
}
- io_wait_readable(io);
+ io_wait_readable(fptr);
continue;
case SSL_ERROR_SYSCALL:
if (!ERR_peek_error()) {
@@ -2058,14 +2027,14 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts)
SSL *ssl;
rb_io_t *fptr;
int num, nonblock = opts != Qfalse;
- VALUE tmp;
+ VALUE tmp, io;
GetSSL(self, ssl);
if (!ssl_started(ssl))
rb_raise(eSSLError, "SSL session is not started yet");
tmp = rb_str_new_frozen(StringValue(str));
- VALUE io = rb_attr_get(self, id_i_io);
+ io = rb_attr_get(self, id_i_io);
GetOpenFile(io, fptr);
/* SSL_write(3ssl) manpage states num == 0 is undefined */
@@ -2081,12 +2050,12 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts)
case SSL_ERROR_WANT_WRITE:
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
- io_wait_writable(io);
+ io_wait_writable(fptr);
continue;
case SSL_ERROR_WANT_READ:
if (no_exception_p(opts)) { return sym_wait_readable; }
read_would_block(nonblock);
- io_wait_readable(io);
+ io_wait_readable(fptr);
continue;
case SSL_ERROR_SYSCALL:
#ifdef __APPLE__
diff --git a/ext/openssl/ossl_ssl.h b/ext/openssl/ossl_ssl.h
index a92985c601..535c56097c 100644
--- a/ext/openssl/ossl_ssl.h
+++ b/ext/openssl/ossl_ssl.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_SSL_H_)
#define _OSSL_SSL_H_
diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c
index c5df902c60..139a474b04 100644
--- a/ext/openssl/ossl_ssl_session.c
+++ b/ext/openssl/ossl_ssl_session.c
@@ -19,7 +19,7 @@ const rb_data_type_t ossl_ssl_session_type = {
{
0, ossl_ssl_session_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE ossl_ssl_session_alloc(VALUE klass)
diff --git a/ext/openssl/ossl_ts.c b/ext/openssl/ossl_ts.c
index d6a5fc9892..b33ff10c10 100644
--- a/ext/openssl/ossl_ts.c
+++ b/ext/openssl/ossl_ts.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licenced under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -83,7 +83,7 @@ static const rb_data_type_t ossl_ts_req_type = {
{
0, ossl_ts_req_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -97,7 +97,7 @@ static const rb_data_type_t ossl_ts_resp_type = {
{
0, ossl_ts_resp_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static void
@@ -111,7 +111,7 @@ static const rb_data_type_t ossl_ts_token_info_type = {
{
0, ossl_ts_token_info_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -504,25 +504,6 @@ ossl_ts_req_to_der(VALUE self)
}
static VALUE
-ossl_ts_req_to_text(VALUE self)
-{
- TS_REQ *req;
- BIO *out;
-
- GetTSRequest(self, req);
-
- out = BIO_new(BIO_s_mem());
- if (!out) ossl_raise(eTimestampError, NULL);
-
- if (!TS_REQ_print_bio(out, req)) {
- BIO_free(out);
- ossl_raise(eTimestampError, NULL);
- }
-
- return ossl_membio2str(out);
-}
-
-static VALUE
ossl_ts_resp_alloc(VALUE klass)
{
TS_RESP *resp;
@@ -776,25 +757,6 @@ ossl_ts_resp_to_der(VALUE self)
return asn1_to_der((void *)resp, (int (*)(void *, unsigned char **))i2d_TS_RESP);
}
-static VALUE
-ossl_ts_resp_to_text(VALUE self)
-{
- TS_RESP *resp;
- BIO *out;
-
- GetTSResponse(self, resp);
-
- out = BIO_new(BIO_s_mem());
- if (!out) ossl_raise(eTimestampError, NULL);
-
- if (!TS_RESP_print_bio(out, resp)) {
- BIO_free(out);
- ossl_raise(eTimestampError, NULL);
- }
-
- return ossl_membio2str(out);
-}
-
/*
* Verifies a timestamp token by checking the signature, validating the
* certificate chain implied by tsa_certificate and by checking conformance to
@@ -1111,25 +1073,6 @@ ossl_ts_token_info_to_der(VALUE self)
return asn1_to_der((void *)info, (int (*)(void *, unsigned char **))i2d_TS_TST_INFO);
}
-static VALUE
-ossl_ts_token_info_to_text(VALUE self)
-{
- TS_TST_INFO *info;
- BIO *out;
-
- GetTSTokenInfo(self, info);
-
- out = BIO_new(BIO_s_mem());
- if (!out) ossl_raise(eTimestampError, NULL);
-
- if (!TS_TST_INFO_print_bio(out, info)) {
- BIO_free(out);
- ossl_raise(eTimestampError, NULL);
- }
-
- return ossl_membio2str(out);
-}
-
static ASN1_INTEGER *
ossl_tsfac_serial_cb(struct TS_resp_ctx *ctx, void *data)
{
@@ -1413,7 +1356,6 @@ Init_ossl_ts(void)
rb_define_method(cTimestampResponse, "token_info", ossl_ts_resp_get_token_info, 0);
rb_define_method(cTimestampResponse, "tsa_certificate", ossl_ts_resp_get_tsa_certificate, 0);
rb_define_method(cTimestampResponse, "to_der", ossl_ts_resp_to_der, 0);
- rb_define_method(cTimestampResponse, "to_text", ossl_ts_resp_to_text, 0);
rb_define_method(cTimestampResponse, "verify", ossl_ts_resp_verify, -1);
/* Document-class: OpenSSL::Timestamp::TokenInfo
@@ -1432,7 +1374,6 @@ Init_ossl_ts(void)
rb_define_method(cTimestampTokenInfo, "ordering", ossl_ts_token_info_get_ordering, 0);
rb_define_method(cTimestampTokenInfo, "nonce", ossl_ts_token_info_get_nonce, 0);
rb_define_method(cTimestampTokenInfo, "to_der", ossl_ts_token_info_to_der, 0);
- rb_define_method(cTimestampTokenInfo, "to_text", ossl_ts_token_info_to_text, 0);
/* Document-class: OpenSSL::Timestamp::Request
* Allows to create timestamp requests or parse existing ones. A Request is
@@ -1458,7 +1399,6 @@ Init_ossl_ts(void)
rb_define_method(cTimestampRequest, "cert_requested=", ossl_ts_req_set_cert_requested, 1);
rb_define_method(cTimestampRequest, "cert_requested?", ossl_ts_req_get_cert_requested, 0);
rb_define_method(cTimestampRequest, "to_der", ossl_ts_req_to_der, 0);
- rb_define_method(cTimestampRequest, "to_text", ossl_ts_req_to_text, 0);
/*
* Indicates a successful response. Equal to +0+.
diff --git a/ext/openssl/ossl_ts.h b/ext/openssl/ossl_ts.h
index eeca3046eb..25fb0e1d64 100644
--- a/ext/openssl/ossl_ts.h
+++ b/ext/openssl/ossl_ts.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licenced under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_TS_H_)
diff --git a/ext/openssl/ossl_x509.c b/ext/openssl/ossl_x509.c
index 9686fc1a9c..f8470703fc 100644
--- a/ext/openssl/ossl_x509.c
+++ b/ext/openssl/ossl_x509.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
diff --git a/ext/openssl/ossl_x509.h b/ext/openssl/ossl_x509.h
index 88e3f16a1a..4fadfa6b82 100644
--- a/ext/openssl/ossl_x509.h
+++ b/ext/openssl/ossl_x509.h
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#if !defined(_OSSL_X509_H_)
#define _OSSL_X509_H_
diff --git a/ext/openssl/ossl_x509attr.c b/ext/openssl/ossl_x509attr.c
index 967fe89f01..60846cfe9d 100644
--- a/ext/openssl/ossl_x509attr.c
+++ b/ext/openssl/ossl_x509attr.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_x509attr_type = {
{
0, ossl_x509attr_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
@@ -201,36 +201,37 @@ static VALUE
ossl_x509attr_set_value(VALUE self, VALUE value)
{
X509_ATTRIBUTE *attr;
- GetX509Attr(self, attr);
+ VALUE asn1_value;
+ int i, asn1_tag;
OSSL_Check_Kind(value, cASN1Data);
- VALUE der = ossl_to_der(value);
- const unsigned char *p = (const unsigned char *)RSTRING_PTR(der);
- STACK_OF(ASN1_TYPE) *sk = d2i_ASN1_SET_ANY(NULL, &p, RSTRING_LEN(der));
- if (!sk)
- ossl_raise(eX509AttrError, "attribute value must be ASN1::Set");
+ asn1_tag = NUM2INT(rb_attr_get(value, rb_intern("@tag")));
+ asn1_value = rb_attr_get(value, rb_intern("@value"));
+ if (asn1_tag != V_ASN1_SET)
+ ossl_raise(eASN1Error, "argument must be ASN1::Set");
+ if (!RB_TYPE_P(asn1_value, T_ARRAY))
+ ossl_raise(eASN1Error, "ASN1::Set has non-array value");
+ GetX509Attr(self, attr);
if (X509_ATTRIBUTE_count(attr)) { /* populated, reset first */
- ASN1_OBJECT *obj = X509_ATTRIBUTE_get0_object(attr);
- X509_ATTRIBUTE *new_attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, 0, NULL, -1);
- if (!new_attr) {
- sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free);
- ossl_raise(eX509AttrError, "X509_ATTRIBUTE_create_by_OBJ");
- }
- SetX509Attr(self, new_attr);
- X509_ATTRIBUTE_free(attr);
- attr = new_attr;
+ ASN1_OBJECT *obj = X509_ATTRIBUTE_get0_object(attr);
+ X509_ATTRIBUTE *new_attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, 0, NULL, -1);
+ if (!new_attr)
+ ossl_raise(eX509AttrError, NULL);
+ SetX509Attr(self, new_attr);
+ X509_ATTRIBUTE_free(attr);
+ attr = new_attr;
}
- for (int i = 0; i < sk_ASN1_TYPE_num(sk); i++) {
- ASN1_TYPE *a1type = sk_ASN1_TYPE_value(sk, i);
- if (!X509_ATTRIBUTE_set1_data(attr, ASN1_TYPE_get(a1type),
- a1type->value.ptr, -1)) {
- sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free);
- ossl_raise(eX509AttrError, "X509_ATTRIBUTE_set1_data");
- }
+ for (i = 0; i < RARRAY_LEN(asn1_value); i++) {
+ ASN1_TYPE *a1type = ossl_asn1_get_asn1type(RARRAY_AREF(asn1_value, i));
+ if (!X509_ATTRIBUTE_set1_data(attr, ASN1_TYPE_get(a1type),
+ a1type->value.ptr, -1)) {
+ ASN1_TYPE_free(a1type);
+ ossl_raise(eX509AttrError, NULL);
+ }
+ ASN1_TYPE_free(a1type);
}
- sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free);
return value;
}
diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c
index 846dd0701c..9443541645 100644
--- a/ext/openssl/ossl_x509cert.c
+++ b/ext/openssl/ossl_x509cert.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_x509_type = {
{
0, ossl_x509_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
@@ -539,11 +539,7 @@ ossl_x509_sign(VALUE self, VALUE key, VALUE digest)
const EVP_MD *md;
pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
- if (NIL_P(digest)) {
- md = NULL; /* needed for some key types, e.g. Ed25519 */
- } else {
- md = ossl_evp_get_digestbyname(digest);
- }
+ md = ossl_evp_get_digestbyname(digest);
GetX509(self, x509);
if (!X509_sign(x509, pkey, md)) {
ossl_raise(eX509CertError, NULL);
@@ -711,38 +707,6 @@ ossl_x509_eq(VALUE self, VALUE other)
return !X509_cmp(a, b) ? Qtrue : Qfalse;
}
-#ifdef HAVE_I2D_RE_X509_TBS
-/*
- * call-seq:
- * cert.tbs_bytes => string
- *
- * Returns the DER-encoded bytes of the certificate's to be signed certificate.
- * This is mainly useful for validating embedded certificate transparency signatures.
- */
-static VALUE
-ossl_x509_tbs_bytes(VALUE self)
-{
- X509 *x509;
- int len;
- unsigned char *p0;
- VALUE str;
-
- GetX509(self, x509);
- len = i2d_re_X509_tbs(x509, NULL);
- if (len <= 0) {
- ossl_raise(eX509CertError, "i2d_re_X509_tbs");
- }
- str = rb_str_new(NULL, len);
- p0 = (unsigned char *)RSTRING_PTR(str);
- if (i2d_re_X509_tbs(x509, &p0) <= 0) {
- ossl_raise(eX509CertError, "i2d_re_X509_tbs");
- }
- ossl_str_adjust(str, p0);
-
- return str;
-}
-#endif
-
struct load_chained_certificates_arguments {
VALUE certificates;
X509 *certificate;
@@ -1035,7 +999,4 @@ Init_ossl_x509cert(void)
rb_define_method(cX509Cert, "add_extension", ossl_x509_add_extension, 1);
rb_define_method(cX509Cert, "inspect", ossl_x509_inspect, 0);
rb_define_method(cX509Cert, "==", ossl_x509_eq, 1);
-#ifdef HAVE_I2D_RE_X509_TBS
- rb_define_method(cX509Cert, "tbs_bytes", ossl_x509_tbs_bytes, 0);
-#endif
}
diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c
index 368270ce11..6c1d915370 100644
--- a/ext/openssl/ossl_x509crl.c
+++ b/ext/openssl/ossl_x509crl.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_x509crl_type = {
{
0, ossl_x509crl_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_x509ext.c b/ext/openssl/ossl_x509ext.c
index 7f47cd7cce..e54102c771 100644
--- a/ext/openssl/ossl_x509ext.c
+++ b/ext/openssl/ossl_x509ext.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -55,7 +55,7 @@ static const rb_data_type_t ossl_x509ext_type = {
{
0, ossl_x509ext_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
@@ -108,7 +108,7 @@ static const rb_data_type_t ossl_x509extfactory_type = {
{
0, ossl_x509extfactory_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -209,16 +209,15 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
int nid;
VALUE rconf;
CONF *conf;
- const char *oid_cstr = NULL;
rb_scan_args(argc, argv, "21", &oid, &value, &critical);
+ StringValueCStr(oid);
StringValue(value);
if(NIL_P(critical)) critical = Qfalse;
- oid_cstr = StringValueCStr(oid);
- nid = OBJ_ln2nid(oid_cstr);
- if (nid != NID_undef)
- oid_cstr = OBJ_nid2sn(nid);
+ nid = OBJ_ln2nid(RSTRING_PTR(oid));
+ if(!nid) nid = OBJ_sn2nid(RSTRING_PTR(oid));
+ if(!nid) ossl_raise(eX509ExtError, "unknown OID `%"PRIsVALUE"'", oid);
valstr = rb_str_new2(RTEST(critical) ? "critical," : "");
rb_str_append(valstr, value);
@@ -229,12 +228,7 @@ ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
rconf = rb_iv_get(self, "@config");
conf = NIL_P(rconf) ? NULL : GetConfig(rconf);
X509V3_set_nconf(ctx, conf);
-
-#if OSSL_OPENSSL_PREREQ(1, 1, 0) || OSSL_IS_LIBRESSL
- ext = X509V3_EXT_nconf(conf, ctx, oid_cstr, RSTRING_PTR(valstr));
-#else
- ext = X509V3_EXT_nconf(conf, ctx, (char *)oid_cstr, RSTRING_PTR(valstr));
-#endif
+ ext = X509V3_EXT_nconf_nid(conf, ctx, nid, RSTRING_PTR(valstr));
X509V3_set_ctx_nodb(ctx);
if (!ext){
ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr);
diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c
index 5060be92cc..13a2b2c030 100644
--- a/ext/openssl/ossl_x509name.c
+++ b/ext/openssl/ossl_x509name.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -46,7 +46,7 @@ static const rb_data_type_t ossl_x509name_type = {
{
0, ossl_x509name_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c
index 37ba03728f..77a7d3f2ff 100644
--- a/ext/openssl/ossl_x509req.c
+++ b/ext/openssl/ossl_x509req.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_x509req_type = {
{
0, ossl_x509req_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_x509revoked.c b/ext/openssl/ossl_x509revoked.c
index 5b82470c83..10b8aa4ad6 100644
--- a/ext/openssl/ossl_x509revoked.c
+++ b/ext/openssl/ossl_x509revoked.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -41,7 +41,7 @@ static const rb_data_type_t ossl_x509rev_type = {
{
0, ossl_x509rev_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c
index 670519febc..7c546187c3 100644
--- a/ext/openssl/ossl_x509store.c
+++ b/ext/openssl/ossl_x509store.c
@@ -5,7 +5,7 @@
*/
/*
* This program is licensed under the same licence as Ruby.
- * (See the file 'COPYING'.)
+ * (See the file 'LICENCE'.)
*/
#include "ossl.h"
@@ -116,9 +116,6 @@ static void
ossl_x509store_mark(void *ptr)
{
X509_STORE *store = ptr;
- // Note: this reference is stored as @verify_callback so we don't need to mark it.
- // However we do need to ensure GC compaction won't move it, hence why
- // we call rb_gc_mark here.
rb_gc_mark((VALUE)X509_STORE_get_ex_data(store, store_ex_verify_cb_idx));
}
@@ -133,7 +130,7 @@ static const rb_data_type_t ossl_x509store_type = {
{
ossl_x509store_mark, ossl_x509store_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
/*
@@ -190,9 +187,8 @@ ossl_x509store_set_vfy_cb(VALUE self, VALUE cb)
X509_STORE *store;
GetX509Store(self, store);
- rb_iv_set(self, "@verify_callback", cb);
- // We don't need to trigger a write barrier because `rb_iv_set` did it.
X509_STORE_set_ex_data(store, store_ex_verify_cb_idx, (void *)cb);
+ rb_iv_set(self, "@verify_callback", cb);
return cb;
}
@@ -223,6 +219,7 @@ ossl_x509store_initialize(int argc, VALUE *argv, VALUE self)
rb_iv_set(self, "@error", Qnil);
rb_iv_set(self, "@error_string", Qnil);
rb_iv_set(self, "@chain", Qnil);
+ rb_iv_set(self, "@time", Qnil);
return self;
}
@@ -328,16 +325,7 @@ ossl_x509store_set_trust(VALUE self, VALUE trust)
static VALUE
ossl_x509store_set_time(VALUE self, VALUE time)
{
- X509_STORE *store;
- X509_VERIFY_PARAM *param;
-
- GetX509Store(self, store);
-#ifdef HAVE_X509_STORE_GET0_PARAM
- param = X509_STORE_get0_param(store);
-#else
- param = store->param;
-#endif
- X509_VERIFY_PARAM_set_time(param, NUM2LONG(rb_Integer(time)));
+ rb_iv_set(self, "@time", time);
return time;
}
@@ -519,9 +507,6 @@ static void
ossl_x509stctx_mark(void *ptr)
{
X509_STORE_CTX *ctx = ptr;
- // Note: this reference is stored as @verify_callback so we don't need to mark it.
- // However we do need to ensure GC compaction won't move it, hence why
- // we call rb_gc_mark here.
rb_gc_mark((VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx));
}
@@ -541,7 +526,7 @@ static const rb_data_type_t ossl_x509stctx_type = {
{
ossl_x509stctx_mark, ossl_x509stctx_free,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
@@ -572,6 +557,7 @@ ossl_x509stctx_new(X509_STORE_CTX *ctx)
static VALUE ossl_x509stctx_set_flags(VALUE, VALUE);
static VALUE ossl_x509stctx_set_purpose(VALUE, VALUE);
static VALUE ossl_x509stctx_set_trust(VALUE, VALUE);
+static VALUE ossl_x509stctx_set_time(VALUE, VALUE);
/*
* call-seq:
@@ -582,7 +568,7 @@ static VALUE ossl_x509stctx_set_trust(VALUE, VALUE);
static VALUE
ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self)
{
- VALUE store, cert, chain;
+ VALUE store, cert, chain, t;
X509_STORE_CTX *ctx;
X509_STORE *x509st;
X509 *x509 = NULL;
@@ -606,6 +592,8 @@ ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self)
sk_X509_pop_free(x509s, X509_free);
ossl_raise(eX509StoreError, "X509_STORE_CTX_init");
}
+ if (!NIL_P(t = rb_iv_get(store, "@time")))
+ ossl_x509stctx_set_time(self, t);
rb_iv_set(self, "@verify_callback", rb_iv_get(store, "@verify_callback"));
rb_iv_set(self, "@cert", cert);
@@ -626,8 +614,8 @@ ossl_x509stctx_verify(VALUE self)
X509_STORE_CTX *ctx;
GetX509StCtx(self, ctx);
- VALUE cb = rb_iv_get(self, "@verify_callback");
- X509_STORE_CTX_set_ex_data(ctx, stctx_ex_verify_cb_idx, (void *)cb);
+ X509_STORE_CTX_set_ex_data(ctx, stctx_ex_verify_cb_idx,
+ (void *)rb_iv_get(self, "@verify_callback"));
switch (X509_verify_cert(ctx)) {
case 1:
diff --git a/ext/pathname/depend b/ext/pathname/depend
index cca7877dad..a6b000e305 100644
--- a/ext/pathname/depend
+++ b/ext/pathname/depend
@@ -53,7 +53,6 @@ pathname.o: $(hdrdir)/ruby/internal/attr/noexcept.h
pathname.o: $(hdrdir)/ruby/internal/attr/noinline.h
pathname.o: $(hdrdir)/ruby/internal/attr/nonnull.h
pathname.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-pathname.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
pathname.o: $(hdrdir)/ruby/internal/attr/pure.h
pathname.o: $(hdrdir)/ruby/internal/attr/restrict.h
pathname.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ pathname.o: $(hdrdir)/ruby/internal/intern/enumerator.h
pathname.o: $(hdrdir)/ruby/internal/intern/error.h
pathname.o: $(hdrdir)/ruby/internal/intern/eval.h
pathname.o: $(hdrdir)/ruby/internal/intern/file.h
+pathname.o: $(hdrdir)/ruby/internal/intern/gc.h
pathname.o: $(hdrdir)/ruby/internal/intern/hash.h
pathname.o: $(hdrdir)/ruby/internal/intern/io.h
pathname.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,12 +152,12 @@ pathname.o: $(hdrdir)/ruby/internal/memory.h
pathname.o: $(hdrdir)/ruby/internal/method.h
pathname.o: $(hdrdir)/ruby/internal/module.h
pathname.o: $(hdrdir)/ruby/internal/newobj.h
+pathname.o: $(hdrdir)/ruby/internal/rgengc.h
pathname.o: $(hdrdir)/ruby/internal/scan_args.h
pathname.o: $(hdrdir)/ruby/internal/special_consts.h
pathname.o: $(hdrdir)/ruby/internal/static_assert.h
pathname.o: $(hdrdir)/ruby/internal/stdalign.h
pathname.o: $(hdrdir)/ruby/internal/stdbool.h
-pathname.o: $(hdrdir)/ruby/internal/stdckdint.h
pathname.o: $(hdrdir)/ruby/internal/symbol.h
pathname.o: $(hdrdir)/ruby/internal/value.h
pathname.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/pathname/extconf.rb b/ext/pathname/extconf.rb
index b4e1617b9e..84e68277aa 100644
--- a/ext/pathname/extconf.rb
+++ b/ext/pathname/extconf.rb
@@ -1,3 +1,4 @@
# frozen_string_literal: false
require 'mkmf'
+have_func("rb_file_s_birthtime")
create_makefile('pathname')
diff --git a/ext/pathname/lib/pathname.rb b/ext/pathname/lib/pathname.rb
index 2deda00ff2..7bdfd0eb39 100644
--- a/ext/pathname/lib/pathname.rb
+++ b/ext/pathname/lib/pathname.rb
@@ -14,8 +14,6 @@ require 'pathname.so'
class Pathname
- VERSION = "0.3.0"
-
# :stopdoc:
# to_path is implemented so Pathname objects are usable with File.open, etc.
@@ -572,7 +570,7 @@ class Pathname # * Find *
return to_enum(__method__, ignore_error: ignore_error) unless block_given?
require 'find'
if @path == '.'
- Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f.delete_prefix('./')) }
+ Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f.sub(%r{\A\./}, '')) }
else
Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f) }
end
@@ -580,15 +578,16 @@ class Pathname # * Find *
end
+autoload(:FileUtils, 'fileutils')
+
class Pathname # * FileUtils *
# Creates a full path, including any intermediate directories that don't yet
# exist.
#
# See FileUtils.mkpath and FileUtils.mkdir_p
def mkpath(mode: nil)
- require 'fileutils'
FileUtils.mkpath(@path, mode: mode)
- self
+ nil
end
# Recursively deletes a directory, including all directories beneath it.
@@ -599,23 +598,7 @@ class Pathname # * FileUtils *
# File::Path provides "mkpath" and "rmtree".
require 'fileutils'
FileUtils.rm_rf(@path, noop: noop, verbose: verbose, secure: secure)
- self
+ nil
end
end
-class Pathname # * tmpdir *
- # Creates a tmp directory and wraps the returned path in a Pathname object.
- #
- # See Dir.mktmpdir
- def self.mktmpdir
- require 'tmpdir' unless defined?(Dir.mktmpdir)
- if block_given?
- Dir.mktmpdir do |dir|
- dir = self.new(dir)
- yield dir
- end
- else
- self.new(Dir.mktmpdir)
- end
- end
-end
diff --git a/ext/pathname/pathname.c b/ext/pathname/pathname.c
index cdecb3f897..8ee4bcec5b 100644
--- a/ext/pathname/pathname.c
+++ b/ext/pathname/pathname.c
@@ -131,6 +131,32 @@ path_freeze(VALUE self)
}
/*
+ * call-seq:
+ * pathname.taint -> obj
+ *
+ * Returns pathname. This method is deprecated and will be removed in Ruby 3.2.
+ */
+static VALUE
+path_taint(VALUE self)
+{
+ rb_warn("Pathname#taint is deprecated and will be removed in Ruby 3.2.");
+ return self;
+}
+
+/*
+ * call-seq:
+ * pathname.untaint -> obj
+ *
+ * Returns pathname. This method is deprecated and will be removed in Ruby 3.2.
+ */
+static VALUE
+path_untaint(VALUE self)
+{
+ rb_warn("Pathname#untaint is deprecated and will be removed in Ruby 3.2.");
+ return self;
+}
+
+/*
* Compare this pathname with +other+. The comparison is string-based.
* Be aware that two different paths (<tt>foo.txt</tt> and <tt>./foo.txt</tt>)
* can refer to the same file.
@@ -479,6 +505,7 @@ path_atime(VALUE self)
return rb_funcall(rb_cFile, id_atime, 1, get_strpath(self));
}
+#if defined(HAVE_RB_FILE_S_BIRTHTIME)
/*
* call-seq:
* pathname.birthtime -> time
@@ -493,6 +520,10 @@ path_birthtime(VALUE self)
{
return rb_funcall(rb_cFile, id_birthtime, 1, get_strpath(self));
}
+#else
+/* check at compilation time for `respond_to?` */
+# define path_birthtime rb_f_notimplement
+#endif
/*
* call-seq:
@@ -1506,6 +1537,8 @@ Init_pathname(void)
rb_cPathname = rb_define_class("Pathname", rb_cObject);
rb_define_method(rb_cPathname, "initialize", path_initialize, 1);
rb_define_method(rb_cPathname, "freeze", path_freeze, 0);
+ rb_define_method(rb_cPathname, "taint", path_taint, 0);
+ rb_define_method(rb_cPathname, "untaint", path_untaint, 0);
rb_define_method(rb_cPathname, "==", path_eq, 1);
rb_define_method(rb_cPathname, "===", path_eq, 1);
rb_define_method(rb_cPathname, "eql?", path_eq, 1);
diff --git a/ext/pathname/pathname.gemspec b/ext/pathname/pathname.gemspec
index 890bc2fde9..92bc02b0db 100644
--- a/ext/pathname/pathname.gemspec
+++ b/ext/pathname/pathname.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", "ext/lib"].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "pathname"
+ spec.version = "0.2.1"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
diff --git a/ext/psych/depend b/ext/psych/depend
index a4d9ca9a6a..78bde9a53d 100644
--- a/ext/psych/depend
+++ b/ext/psych/depend
@@ -67,7 +67,6 @@ psych.o: $(hdrdir)/ruby/internal/attr/noexcept.h
psych.o: $(hdrdir)/ruby/internal/attr/noinline.h
psych.o: $(hdrdir)/ruby/internal/attr/nonnull.h
psych.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-psych.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
psych.o: $(hdrdir)/ruby/internal/attr/pure.h
psych.o: $(hdrdir)/ruby/internal/attr/restrict.h
psych.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -136,6 +135,7 @@ psych.o: $(hdrdir)/ruby/internal/intern/enumerator.h
psych.o: $(hdrdir)/ruby/internal/intern/error.h
psych.o: $(hdrdir)/ruby/internal/intern/eval.h
psych.o: $(hdrdir)/ruby/internal/intern/file.h
+psych.o: $(hdrdir)/ruby/internal/intern/gc.h
psych.o: $(hdrdir)/ruby/internal/intern/hash.h
psych.o: $(hdrdir)/ruby/internal/intern/io.h
psych.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -166,12 +166,12 @@ psych.o: $(hdrdir)/ruby/internal/memory.h
psych.o: $(hdrdir)/ruby/internal/method.h
psych.o: $(hdrdir)/ruby/internal/module.h
psych.o: $(hdrdir)/ruby/internal/newobj.h
+psych.o: $(hdrdir)/ruby/internal/rgengc.h
psych.o: $(hdrdir)/ruby/internal/scan_args.h
psych.o: $(hdrdir)/ruby/internal/special_consts.h
psych.o: $(hdrdir)/ruby/internal/static_assert.h
psych.o: $(hdrdir)/ruby/internal/stdalign.h
psych.o: $(hdrdir)/ruby/internal/stdbool.h
-psych.o: $(hdrdir)/ruby/internal/stdckdint.h
psych.o: $(hdrdir)/ruby/internal/symbol.h
psych.o: $(hdrdir)/ruby/internal/value.h
psych.o: $(hdrdir)/ruby/internal/value_type.h
@@ -244,7 +244,6 @@ psych_emitter.o: $(hdrdir)/ruby/internal/attr/noexcept.h
psych_emitter.o: $(hdrdir)/ruby/internal/attr/noinline.h
psych_emitter.o: $(hdrdir)/ruby/internal/attr/nonnull.h
psych_emitter.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-psych_emitter.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
psych_emitter.o: $(hdrdir)/ruby/internal/attr/pure.h
psych_emitter.o: $(hdrdir)/ruby/internal/attr/restrict.h
psych_emitter.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -313,6 +312,7 @@ psych_emitter.o: $(hdrdir)/ruby/internal/intern/enumerator.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/error.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/eval.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/file.h
+psych_emitter.o: $(hdrdir)/ruby/internal/intern/gc.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/hash.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/io.h
psych_emitter.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -343,12 +343,12 @@ psych_emitter.o: $(hdrdir)/ruby/internal/memory.h
psych_emitter.o: $(hdrdir)/ruby/internal/method.h
psych_emitter.o: $(hdrdir)/ruby/internal/module.h
psych_emitter.o: $(hdrdir)/ruby/internal/newobj.h
+psych_emitter.o: $(hdrdir)/ruby/internal/rgengc.h
psych_emitter.o: $(hdrdir)/ruby/internal/scan_args.h
psych_emitter.o: $(hdrdir)/ruby/internal/special_consts.h
psych_emitter.o: $(hdrdir)/ruby/internal/static_assert.h
psych_emitter.o: $(hdrdir)/ruby/internal/stdalign.h
psych_emitter.o: $(hdrdir)/ruby/internal/stdbool.h
-psych_emitter.o: $(hdrdir)/ruby/internal/stdckdint.h
psych_emitter.o: $(hdrdir)/ruby/internal/symbol.h
psych_emitter.o: $(hdrdir)/ruby/internal/value.h
psych_emitter.o: $(hdrdir)/ruby/internal/value_type.h
@@ -421,7 +421,6 @@ psych_parser.o: $(hdrdir)/ruby/internal/attr/noexcept.h
psych_parser.o: $(hdrdir)/ruby/internal/attr/noinline.h
psych_parser.o: $(hdrdir)/ruby/internal/attr/nonnull.h
psych_parser.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-psych_parser.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
psych_parser.o: $(hdrdir)/ruby/internal/attr/pure.h
psych_parser.o: $(hdrdir)/ruby/internal/attr/restrict.h
psych_parser.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -490,6 +489,7 @@ psych_parser.o: $(hdrdir)/ruby/internal/intern/enumerator.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/error.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/eval.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/file.h
+psych_parser.o: $(hdrdir)/ruby/internal/intern/gc.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/hash.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/io.h
psych_parser.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -520,12 +520,12 @@ psych_parser.o: $(hdrdir)/ruby/internal/memory.h
psych_parser.o: $(hdrdir)/ruby/internal/method.h
psych_parser.o: $(hdrdir)/ruby/internal/module.h
psych_parser.o: $(hdrdir)/ruby/internal/newobj.h
+psych_parser.o: $(hdrdir)/ruby/internal/rgengc.h
psych_parser.o: $(hdrdir)/ruby/internal/scan_args.h
psych_parser.o: $(hdrdir)/ruby/internal/special_consts.h
psych_parser.o: $(hdrdir)/ruby/internal/static_assert.h
psych_parser.o: $(hdrdir)/ruby/internal/stdalign.h
psych_parser.o: $(hdrdir)/ruby/internal/stdbool.h
-psych_parser.o: $(hdrdir)/ruby/internal/stdckdint.h
psych_parser.o: $(hdrdir)/ruby/internal/symbol.h
psych_parser.o: $(hdrdir)/ruby/internal/value.h
psych_parser.o: $(hdrdir)/ruby/internal/value_type.h
@@ -598,7 +598,6 @@ psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noexcept.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noinline.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/nonnull.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/pure.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/restrict.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -667,6 +666,7 @@ psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/enumerator.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/error.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/eval.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/file.h
+psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/gc.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/hash.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/io.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -697,12 +697,12 @@ psych_to_ruby.o: $(hdrdir)/ruby/internal/memory.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/method.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/module.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/newobj.h
+psych_to_ruby.o: $(hdrdir)/ruby/internal/rgengc.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/scan_args.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/special_consts.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/static_assert.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/stdalign.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/stdbool.h
-psych_to_ruby.o: $(hdrdir)/ruby/internal/stdckdint.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/symbol.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/value.h
psych_to_ruby.o: $(hdrdir)/ruby/internal/value_type.h
@@ -775,7 +775,6 @@ psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noexcept.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noinline.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/nonnull.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/pure.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/restrict.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -844,6 +843,7 @@ psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/enumerator.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/error.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/eval.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/file.h
+psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/gc.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/hash.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/io.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -874,12 +874,12 @@ psych_yaml_tree.o: $(hdrdir)/ruby/internal/memory.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/method.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/module.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/newobj.h
+psych_yaml_tree.o: $(hdrdir)/ruby/internal/rgengc.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/scan_args.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/special_consts.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/static_assert.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/stdalign.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/stdbool.h
-psych_yaml_tree.o: $(hdrdir)/ruby/internal/stdckdint.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/symbol.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/value.h
psych_yaml_tree.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/psych/extconf.rb b/ext/psych/extconf.rb
index e7dd0bb60a..41daf8c238 100644
--- a/ext/psych/extconf.rb
+++ b/ext/psych/extconf.rb
@@ -22,7 +22,7 @@ if yaml_source
args = [
yaml_configure,
"--enable-#{shared ? 'shared' : 'static'}",
- "--host=#{RbConfig::CONFIG['host'].sub(/-unknown-/, '-').sub(/arm64/, 'arm')}",
+ "--host=#{RbConfig::CONFIG['host'].sub(/-unknown-/, '-')}",
"CC=#{RbConfig::CONFIG['CC']}",
*(["CFLAGS=-w"] if RbConfig::CONFIG["GCC"] == "yes"),
]
diff --git a/ext/psych/lib/psych.rb b/ext/psych/lib/psych.rb
index d227b1f225..4a2ab58514 100644
--- a/ext/psych/lib/psych.rb
+++ b/ext/psych/lib/psych.rb
@@ -340,7 +340,7 @@ module Psych
# provided, the object contained in the first document will be returned.
# +filename+ will be used in the exception message if any exception
# is raised while parsing. If +yaml+ is empty, it returns
- # the specified +fallback+ return value, which defaults to +nil+.
+ # the specified +fallback+ return value, which defaults to +false+.
#
# Raises a Psych::SyntaxError when a YAML syntax error is detected.
#
@@ -479,7 +479,6 @@ module Psych
#
# Default: <tt>2</tt>.
# [<tt>:line_width</tt>] Max character to wrap line at.
- # For unlimited line width use <tt>-1</tt>.
#
# Default: <tt>0</tt> (meaning "wrap at 81").
# [<tt>:canonical</tt>] Write "canonical" YAML form (very verbose, yet
@@ -490,10 +489,6 @@ module Psych
#
# Default: <tt>false</tt>.
#
- # [<tt>:stringify_names</tt>] Dump symbol keys in Hash objects as string.
- #
- # Default: <tt>false</tt>.
- #
# Example:
#
# # Dump an array, get back a YAML string
@@ -507,9 +502,6 @@ module Psych
#
# # Dump an array to an IO with indentation set
# Psych.dump(['a', ['b']], StringIO.new, indentation: 3)
- #
- # # Dump hash with symbol keys as string
- # Psych.dump({a: "b"}, stringify_names: true) # => "---\na: b\n"
def self.dump o, io = nil, options = {}
if Hash === io
options = io
@@ -560,7 +552,6 @@ module Psych
#
# Default: <tt>2</tt>.
# [<tt>:line_width</tt>] Max character to wrap line at.
- # For unlimited line width use <tt>-1</tt>.
#
# Default: <tt>0</tt> (meaning "wrap at 81").
# [<tt>:canonical</tt>] Write "canonical" YAML form (very verbose, yet
@@ -571,10 +562,6 @@ module Psych
#
# Default: <tt>false</tt>.
#
- # [<tt>:stringify_names</tt>] Dump symbol keys in Hash objects as string.
- #
- # Default: <tt>false</tt>.
- #
# Example:
#
# # Dump an array, get back a YAML string
@@ -588,9 +575,6 @@ module Psych
#
# # Dump an array to an IO with indentation set
# Psych.safe_dump(['a', ['b']], StringIO.new, indentation: 3)
- #
- # # Dump hash with symbol keys as string
- # Psych.dump({a: "b"}, stringify_names: true) # => "---\na: b\n"
def self.safe_dump o, io = nil, options = {}
if Hash === io
options = io
@@ -669,7 +653,7 @@ module Psych
###
# Safely loads the document contained in +filename+. Returns the yaml contained in
# +filename+ as a Ruby object, or if the file is empty, it returns
- # the specified +fallback+ return value, which defaults to +nil+.
+ # the specified +fallback+ return value, which defaults to +false+.
# See safe_load for options.
def self.safe_load_file filename, **kwargs
File.open(filename, 'r:bom|utf-8') { |f|
@@ -680,7 +664,7 @@ module Psych
###
# Loads the document contained in +filename+. Returns the yaml contained in
# +filename+ as a Ruby object, or if the file is empty, it returns
- # the specified +fallback+ return value, which defaults to +nil+.
+ # the specified +fallback+ return value, which defaults to +false+.
# See load for options.
def self.load_file filename, **kwargs
File.open(filename, 'r:bom|utf-8') { |f|
@@ -710,8 +694,26 @@ module Psych
dump_tags[klass] = tag
end
+ # Workaround for emulating `warn '...', uplevel: 1` in Ruby 2.4 or lower.
+ def self.warn_with_uplevel(message, uplevel: 1)
+ at = parse_caller(caller[uplevel]).join(':')
+ warn "#{at}: #{message}"
+ end
+
+ def self.parse_caller(at)
+ if /^(.+?):(\d+)(?::in `.*')?/ =~ at
+ file = $1
+ line = $2.to_i
+ [file, line]
+ end
+ end
+ private_class_method :warn_with_uplevel, :parse_caller
+
class << self
if defined?(Ractor)
+ require 'forwardable'
+ extend Forwardable
+
class Config
attr_accessor :load_tags, :dump_tags, :domain_types
def initialize
@@ -725,29 +727,7 @@ module Psych
Ractor.current[:PsychConfig] ||= Config.new
end
- def load_tags
- config.load_tags
- end
-
- def dump_tags
- config.dump_tags
- end
-
- def domain_types
- config.domain_types
- end
-
- def load_tags=(value)
- config.load_tags = value
- end
-
- def dump_tags=(value)
- config.dump_tags = value
- end
-
- def domain_types=(value)
- config.domain_types = value
- end
+ def_delegators :config, :load_tags, :dump_tags, :domain_types, :load_tags=, :dump_tags=, :domain_types=
else
attr_accessor :load_tags
attr_accessor :dump_tags
diff --git a/ext/psych/lib/psych/class_loader.rb b/ext/psych/lib/psych/class_loader.rb
index 50efc35ee2..c2e4ea4c93 100644
--- a/ext/psych/lib/psych/class_loader.rb
+++ b/ext/psych/lib/psych/class_loader.rb
@@ -35,7 +35,7 @@ module Psych
constants.each do |const|
konst = const_get const
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
+ class_eval <<~RUBY
def #{const.to_s.downcase}
load #{konst.inspect}
end
diff --git a/ext/psych/lib/psych/nodes/node.rb b/ext/psych/lib/psych/nodes/node.rb
index 1a4ea5531f..f44fce5f05 100644
--- a/ext/psych/lib/psych/nodes/node.rb
+++ b/ext/psych/lib/psych/nodes/node.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+require 'stringio'
require_relative '../class_loader'
require_relative '../scalar_scanner'
@@ -55,7 +56,6 @@ module Psych
#
# See also Psych::Visitors::Emitter
def yaml io = nil, options = {}
- require "stringio"
real_io = io || StringIO.new(''.encode('utf-8'))
Visitors::Emitter.new(real_io, options).accept self
diff --git a/ext/psych/lib/psych/scalar_scanner.rb b/ext/psych/lib/psych/scalar_scanner.rb
index de21442344..3cb4bf3c7e 100644
--- a/ext/psych/lib/psych/scalar_scanner.rb
+++ b/ext/psych/lib/psych/scalar_scanner.rb
@@ -4,8 +4,6 @@ module Psych
###
# Scan scalars for built in types
class ScalarScanner
- autoload :Date, "date"
-
# Taken from http://yaml.org/type/timestamp.html
TIME = /^-?\d{4}-\d{1,2}-\d{1,2}(?:[Tt]|\s+)\d{1,2}:\d\d:\d\d(?:\.\d*)?(?:\s*(?:Z|[-+]\d{1,2}:?(?:\d\d)?))?$/
@@ -13,18 +11,18 @@ module Psych
# Base 60, [-+]inf and NaN are handled separately
FLOAT = /^(?:[-+]?([0-9][0-9_,]*)?\.[0-9]*([eE][-+][0-9]+)?(?# base 10))$/x
- # Taken from http://yaml.org/type/int.html and modified to ensure at least one numerical symbol exists
- INTEGER_STRICT = /^(?:[-+]?0b[_]*[0-1][0-1_]* (?# base 2)
- |[-+]?0[_]*[0-7][0-7_]* (?# base 8)
- |[-+]?(0|[1-9][0-9_]*) (?# base 10)
- |[-+]?0x[_]*[0-9a-fA-F][0-9a-fA-F_]* (?# base 16))$/x
+ # Taken from http://yaml.org/type/int.html
+ INTEGER_STRICT = /^(?:[-+]?0b[0-1_]+ (?# base 2)
+ |[-+]?0[0-7_]+ (?# base 8)
+ |[-+]?(0|[1-9][0-9_]*) (?# base 10)
+ |[-+]?0x[0-9a-fA-F_]+ (?# base 16))$/x
# Same as above, but allows commas.
# Not to YML spec, but kept for backwards compatibility
- INTEGER_LEGACY = /^(?:[-+]?0b[_,]*[0-1][0-1_,]* (?# base 2)
- |[-+]?0[_,]*[0-7][0-7_,]* (?# base 8)
+ INTEGER_LEGACY = /^(?:[-+]?0b[0-1_,]+ (?# base 2)
+ |[-+]?0[0-7_,]+ (?# base 8)
|[-+]?(?:0|[1-9](?:[0-9]|,[0-9]|_[0-9])*) (?# base 10)
- |[-+]?0x[_,]*[0-9a-fA-F][0-9a-fA-F_,]* (?# base 16))$/x
+ |[-+]?0x[0-9a-fA-F_,]+ (?# base 16))$/x
attr_reader :class_loader
@@ -63,6 +61,7 @@ module Psych
string
end
elsif string.match?(/^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/)
+ require 'date'
begin
class_loader.date.strptime(string, '%F', Date::GREGORIAN)
rescue ArgumentError
diff --git a/ext/psych/lib/psych/tree_builder.rb b/ext/psych/lib/psych/tree_builder.rb
index 83115bd721..414ca02bf7 100644
--- a/ext/psych/lib/psych/tree_builder.rb
+++ b/ext/psych/lib/psych/tree_builder.rb
@@ -41,7 +41,7 @@ module Psych
Sequence
Mapping
}.each do |node|
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
+ class_eval %{
def start_#{node.downcase}(anchor, tag, implicit, style)
n = Nodes::#{node}.new(anchor, tag, implicit, style)
set_start_location(n)
@@ -54,7 +54,7 @@ module Psych
set_end_location(n)
n
end
- RUBY
+ }
end
###
diff --git a/ext/psych/lib/psych/versions.rb b/ext/psych/lib/psych/versions.rb
index 3d69bf38a1..a592a6916c 100644
--- a/ext/psych/lib/psych/versions.rb
+++ b/ext/psych/lib/psych/versions.rb
@@ -2,9 +2,9 @@
module Psych
# The version of Psych you are using
- VERSION = '5.2.0.beta1'
+ VERSION = '5.0.1'
if RUBY_ENGINE == 'jruby'
- DEFAULT_SNAKEYAML_VERSION = '2.7'.freeze
+ DEFAULT_SNAKEYAML_VERSION = '1.33'.freeze
end
end
diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb
index 9e4da5ef0d..8614251ca9 100644
--- a/ext/psych/lib/psych/visitors/to_ruby.rb
+++ b/ext/psych/lib/psych/visitors/to_ruby.rb
@@ -36,7 +36,7 @@ module Psych
unless @domain_types.empty? || !target.tag
key = target.tag.sub(/^[!\/]*/, '').sub(/(,\d+)\//, '\1:')
- key = "tag:#{key}" unless key.match?(/^(?:tag:|x-private)/)
+ key = "tag:#{key}" unless key =~ /^(?:tag:|x-private)/
if @domain_types.key? key
value, block = @domain_types[key]
@@ -101,7 +101,7 @@ module Psych
source = $1
options = 0
lang = nil
- $2&.each_char do |option|
+ ($2 || '').split('').each do |option|
case option
when 'x' then options |= Regexp::EXTENDED
when 'i' then options |= Regexp::IGNORECASE
diff --git a/ext/psych/lib/psych/visitors/yaml_tree.rb b/ext/psych/lib/psych/visitors/yaml_tree.rb
index e27c927996..31858798e4 100644
--- a/ext/psych/lib/psych/visitors/yaml_tree.rb
+++ b/ext/psych/lib/psych/visitors/yaml_tree.rb
@@ -15,25 +15,30 @@ module Psych
class YAMLTree < Psych::Visitors::Visitor
class Registrar # :nodoc:
def initialize
- @obj_to_id = {}.compare_by_identity
- @obj_to_node = {}.compare_by_identity
+ @obj_to_id = {}
+ @obj_to_node = {}
+ @targets = []
@counter = 0
end
def register target, node
- @obj_to_node[target] = node
+ return unless target.respond_to? :object_id
+ @targets << target
+ @obj_to_node[target.object_id] = node
end
def key? target
- @obj_to_node.key? target
+ @obj_to_node.key? target.object_id
+ rescue NoMethodError
+ false
end
def id_for target
- @obj_to_id[target] ||= (@counter += 1)
+ @obj_to_id[target.object_id] ||= (@counter += 1)
end
def node_for target
- @obj_to_node[target]
+ @obj_to_node[target.object_id]
end
end
@@ -65,7 +70,6 @@ module Psych
fail(ArgumentError, "Invalid line_width #{@line_width}, must be non-negative or -1 for unlimited.")
end
end
- @stringify_names = options[:stringify_names]
@coders = []
@dispatch_cache = Hash.new do |h,klass|
@@ -261,20 +265,20 @@ module Psych
style = Nodes::Scalar::LITERAL
plain = false
quote = false
- elsif o.match?(/\n(?!\Z)/) # match \n except blank line at the end of string
+ elsif o =~ /\n(?!\Z)/ # match \n except blank line at the end of string
style = Nodes::Scalar::LITERAL
elsif o == '<<'
style = Nodes::Scalar::SINGLE_QUOTED
tag = 'tag:yaml.org,2002:str'
plain = false
quote = false
- elsif o == 'y' || o == 'Y' || o == 'n' || o == 'N'
+ elsif o == 'y' || o == 'n'
style = Nodes::Scalar::DOUBLE_QUOTED
elsif @line_width && o.length > @line_width
style = Nodes::Scalar::FOLDED
- elsif o.match?(/^[^[:word:]][^"]*$/)
+ elsif o =~ /^[^[:word:]][^"]*$/
style = Nodes::Scalar::DOUBLE_QUOTED
- elsif not String === @ss.tokenize(o) or /\A0[0-7]*[89]/.match?(o)
+ elsif not String === @ss.tokenize(o) or /\A0[0-7]*[89]/ =~ o
style = Nodes::Scalar::SINGLE_QUOTED
end
@@ -324,7 +328,7 @@ module Psych
if o.class == ::Hash
register(o, @emitter.start_mapping(nil, nil, true, Psych::Nodes::Mapping::BLOCK))
o.each do |k,v|
- accept(@stringify_names && Symbol === k ? k.to_s : k)
+ accept k
accept v
end
@emitter.end_mapping
@@ -337,7 +341,7 @@ module Psych
register(o, @emitter.start_mapping(nil, '!set', false, Psych::Nodes::Mapping::BLOCK))
o.each do |k,v|
- accept(@stringify_names && Symbol === k ? k.to_s : k)
+ accept k
accept v
end
@@ -564,7 +568,7 @@ module Psych
raise BadAlias, "Tried to dump an aliased object"
end
- unless Symbol === target || @permitted_classes[target.class]
+ unless @permitted_classes[target.class]
raise DisallowedClass.new('dump', target.class.name || target.class.inspect)
end
@@ -572,7 +576,7 @@ module Psych
end
def visit_Symbol sym
- unless @permitted_classes[Symbol] || @permitted_symbols[sym]
+ unless @permitted_symbols[sym]
raise DisallowedClass.new('dump', "Symbol(#{sym.inspect})")
end
diff --git a/ext/psych/psych.c b/ext/psych/psych.c
index 3a701b677e..8af0bb6a5a 100644
--- a/ext/psych/psych.c
+++ b/ext/psych/psych.c
@@ -23,7 +23,7 @@ VALUE mPsych;
void Init_psych(void)
{
#ifdef HAVE_RB_EXT_RACTOR_SAFE
- RB_EXT_RACTOR_SAFE(true);
+ RB_EXT_RACTOR_SAFE(true);
#endif
mPsych = rb_define_module("Psych");
diff --git a/ext/psych/psych.gemspec b/ext/psych/psych.gemspec
index a3fc53a8b9..5f5168ddb0 100644
--- a/ext/psych/psych.gemspec
+++ b/ext/psych/psych.gemspec
@@ -21,41 +21,28 @@ DESCRIPTION
s.licenses = ["MIT"]
s.require_paths = ["lib"]
- # for ruby core repository.
- # It was generated by
- # `git ls-files -z`.split("\x0").reject { |f|
- # f.match(%r{^\.git|^(test|spec|features|bin|tool)/|^[A-Z]\w+file$|/extlibs$|\.(gemspec|java)$|jar})
- # }
+ # for ruby core repository. It was generated by `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
s.files = [
- "CONTRIBUTING.md", "LICENSE", "README.md", "ext/psych/depend",
- "ext/psych/extconf.rb", "ext/psych/psych.c", "ext/psych/psych.h",
- "ext/psych/psych_emitter.c", "ext/psych/psych_emitter.h",
- "ext/psych/psych_parser.c", "ext/psych/psych_parser.h",
- "ext/psych/psych_to_ruby.c", "ext/psych/psych_to_ruby.h",
- "ext/psych/psych_yaml_tree.c", "ext/psych/psych_yaml_tree.h",
- "lib/psych.rb", "lib/psych/class_loader.rb", "lib/psych/coder.rb",
- "lib/psych/core_ext.rb", "lib/psych/exception.rb", "lib/psych/handler.rb",
- "lib/psych/handlers/document_stream.rb", "lib/psych/handlers/recorder.rb",
- "lib/psych/json/ruby_events.rb", "lib/psych/json/stream.rb",
- "lib/psych/json/tree_builder.rb", "lib/psych/json/yaml_events.rb",
- "lib/psych/nodes.rb", "lib/psych/nodes/alias.rb",
- "lib/psych/nodes/document.rb", "lib/psych/nodes/mapping.rb",
- "lib/psych/nodes/node.rb", "lib/psych/nodes/scalar.rb",
- "lib/psych/nodes/sequence.rb", "lib/psych/nodes/stream.rb",
- "lib/psych/omap.rb", "lib/psych/parser.rb", "lib/psych/scalar_scanner.rb",
- "lib/psych/set.rb", "lib/psych/stream.rb", "lib/psych/streaming.rb",
- "lib/psych/syntax_error.rb", "lib/psych/tree_builder.rb",
- "lib/psych/versions.rb", "lib/psych/visitors.rb",
- "lib/psych/visitors/depth_first.rb", "lib/psych/visitors/emitter.rb",
- "lib/psych/visitors/json_tree.rb", "lib/psych/visitors/to_ruby.rb",
- "lib/psych/visitors/visitor.rb", "lib/psych/visitors/yaml_tree.rb",
- "lib/psych/y.rb"
+ ".gitignore", "Gemfile", "LICENSE", "Mavenfile", "README.md", "Rakefile", "bin/console",
+ "bin/setup", "ext/psych/depend", "ext/psych/extconf.rb", "ext/psych/psych.c", "ext/psych/psych.h",
+ "ext/psych/psych_emitter.c", "ext/psych/psych_emitter.h", "ext/psych/psych_parser.c", "ext/psych/psych_parser.h",
+ "ext/psych/psych_to_ruby.c", "ext/psych/psych_to_ruby.h", "ext/psych/psych_yaml_tree.c", "ext/psych/psych_yaml_tree.h",
+ "lib/psych.rb", "lib/psych/class_loader.rb", "lib/psych/coder.rb", "lib/psych/core_ext.rb", "lib/psych/exception.rb",
+ "lib/psych/handler.rb", "lib/psych/handlers/document_stream.rb", "lib/psych/handlers/recorder.rb",
+ "lib/psych/json/ruby_events.rb", "lib/psych/json/stream.rb", "lib/psych/json/tree_builder.rb",
+ "lib/psych/json/yaml_events.rb", "lib/psych/nodes.rb", "lib/psych/nodes/alias.rb", "lib/psych/nodes/document.rb",
+ "lib/psych/nodes/mapping.rb", "lib/psych/nodes/node.rb", "lib/psych/nodes/scalar.rb", "lib/psych/nodes/sequence.rb",
+ "lib/psych/nodes/stream.rb", "lib/psych/omap.rb", "lib/psych/parser.rb", "lib/psych/scalar_scanner.rb",
+ "lib/psych/set.rb", "lib/psych/stream.rb", "lib/psych/streaming.rb", "lib/psych/syntax_error.rb",
+ "lib/psych/tree_builder.rb", "lib/psych/versions.rb", "lib/psych/visitors.rb","lib/psych/visitors/depth_first.rb",
+ "lib/psych/visitors/emitter.rb", "lib/psych/visitors/json_tree.rb", "lib/psych/visitors/to_ruby.rb",
+ "lib/psych/visitors/visitor.rb", "lib/psych/visitors/yaml_tree.rb", "lib/psych/y.rb", "psych.gemspec"
]
s.rdoc_options = ["--main", "README.md"]
s.extra_rdoc_files = ["README.md"]
- s.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
+ s.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
s.required_rubygems_version = Gem::Requirement.new(">= 0")
if RUBY_ENGINE == 'jruby'
@@ -65,16 +52,15 @@ DESCRIPTION
"ext/java/org/jruby/ext/psych/PsychLibrary.java",
"ext/java/org/jruby/ext/psych/PsychParser.java",
"ext/java/org/jruby/ext/psych/PsychToRuby.java",
+ "ext/java/org/jruby/ext/psych/PsychYamlTree.java",
"lib/psych_jars.rb",
"lib/psych.jar"
]
- s.requirements = "jar org.snakeyaml:snakeyaml-engine, #{version_module::Psych::DEFAULT_SNAKEYAML_VERSION}"
+ s.requirements = "jar org.yaml:snakeyaml, #{version_module::Psych::DEFAULT_SNAKEYAML_VERSION}"
s.add_dependency 'jar-dependencies', '>= 0.1.7'
else
s.extensions = ["ext/psych/extconf.rb"]
s.add_dependency 'stringio'
end
- s.metadata['msys2_mingw_dependencies'] = 'libyaml'
- s.metadata['changelog_uri'] = s.homepage + '/releases'
end
diff --git a/ext/psych/psych_emitter.c b/ext/psych/psych_emitter.c
index 0c5875f343..022ffa0946 100644
--- a/ext/psych/psych_emitter.c
+++ b/ext/psych/psych_emitter.c
@@ -17,7 +17,7 @@ static ID id_canonical;
static void emit(yaml_emitter_t * emitter, yaml_event_t * event)
{
if(!yaml_emitter_emit(emitter, event))
- rb_raise(rb_eRuntimeError, "%s", emitter->problem);
+ rb_raise(rb_eRuntimeError, "%s", emitter->problem);
}
static int writer(void *ctx, unsigned char *buffer, size_t size)
@@ -82,13 +82,13 @@ static VALUE initialize(int argc, VALUE *argv, VALUE self)
TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
if (rb_scan_args(argc, argv, "11", &io, &options) == 2) {
- line_width = rb_funcall(options, id_line_width, 0);
- indent = rb_funcall(options, id_indentation, 0);
- canonical = rb_funcall(options, id_canonical, 0);
+ line_width = rb_funcall(options, id_line_width, 0);
+ indent = rb_funcall(options, id_indentation, 0);
+ canonical = rb_funcall(options, id_canonical, 0);
- yaml_emitter_set_width(emitter, NUM2INT(line_width));
- yaml_emitter_set_indent(emitter, NUM2INT(indent));
- yaml_emitter_set_canonical(emitter, Qtrue == canonical ? 1 : 0);
+ yaml_emitter_set_width(emitter, NUM2INT(line_width));
+ yaml_emitter_set_indent(emitter, NUM2INT(indent));
+ yaml_emitter_set_canonical(emitter, Qtrue == canonical ? 1 : 0);
}
rb_ivar_set(self, id_io, io);
@@ -136,116 +136,82 @@ static VALUE end_stream(VALUE self)
return self;
}
-struct start_document_data {
- VALUE self;
- VALUE version;
- VALUE tags;
- VALUE imp;
-
- yaml_tag_directive_t * head;
-};
-
-static VALUE start_document_try(VALUE d)
+/* call-seq: emitter.start_document(version, tags, implicit)
+ *
+ * Start a document emission with YAML +version+, +tags+, and an +implicit+
+ * start.
+ *
+ * See Psych::Handler#start_document
+ */
+static VALUE start_document(VALUE self, VALUE version, VALUE tags, VALUE imp)
{
- struct start_document_data * data = (struct start_document_data *)d;
- VALUE self = data->self;
- VALUE version = data->version;
- VALUE tags = data->tags;
- VALUE imp = data->imp;
-
yaml_emitter_t * emitter;
+ yaml_tag_directive_t * head = NULL;
yaml_tag_directive_t * tail = NULL;
yaml_event_t event;
yaml_version_directive_t version_directive;
TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
+
Check_Type(version, T_ARRAY);
if(RARRAY_LEN(version) > 0) {
- VALUE major = rb_ary_entry(version, (long)0);
- VALUE minor = rb_ary_entry(version, (long)1);
+ VALUE major = rb_ary_entry(version, (long)0);
+ VALUE minor = rb_ary_entry(version, (long)1);
- version_directive.major = NUM2INT(major);
- version_directive.minor = NUM2INT(minor);
+ version_directive.major = NUM2INT(major);
+ version_directive.minor = NUM2INT(minor);
}
if(RTEST(tags)) {
- long i = 0;
- long len;
- rb_encoding * encoding = rb_utf8_encoding();
-
- Check_Type(tags, T_ARRAY);
-
- len = RARRAY_LEN(tags);
- data->head = xcalloc((size_t)len, sizeof(yaml_tag_directive_t));
- tail = data->head;
-
- for(i = 0; i < len && i < RARRAY_LEN(tags); i++) {
- VALUE tuple = RARRAY_AREF(tags, i);
- VALUE name;
- VALUE value;
-
- Check_Type(tuple, T_ARRAY);
-
- if(RARRAY_LEN(tuple) < 2) {
- rb_raise(rb_eRuntimeError, "tag tuple must be of length 2");
- }
-
- name = RARRAY_AREF(tuple, 0);
- value = RARRAY_AREF(tuple, 1);
- StringValue(name);
- StringValue(value);
- name = rb_str_export_to_enc(name, encoding);
- value = rb_str_export_to_enc(value, encoding);
-
- tail->handle = (yaml_char_t *)StringValueCStr(name);
- tail->prefix = (yaml_char_t *)StringValueCStr(value);
-
- tail++;
- }
+ long i = 0;
+ long len;
+ rb_encoding * encoding = rb_utf8_encoding();
+
+ Check_Type(tags, T_ARRAY);
+
+ len = RARRAY_LEN(tags);
+ head = xcalloc((size_t)len, sizeof(yaml_tag_directive_t));
+ tail = head;
+
+ for(i = 0; i < len && i < RARRAY_LEN(tags); i++) {
+ VALUE tuple = RARRAY_AREF(tags, i);
+ VALUE name;
+ VALUE value;
+
+ Check_Type(tuple, T_ARRAY);
+
+ if(RARRAY_LEN(tuple) < 2) {
+ xfree(head);
+ rb_raise(rb_eRuntimeError, "tag tuple must be of length 2");
+ }
+ name = RARRAY_AREF(tuple, 0);
+ value = RARRAY_AREF(tuple, 1);
+ StringValue(name);
+ StringValue(value);
+ name = rb_str_export_to_enc(name, encoding);
+ value = rb_str_export_to_enc(value, encoding);
+
+ tail->handle = (yaml_char_t *)StringValueCStr(name);
+ tail->prefix = (yaml_char_t *)StringValueCStr(value);
+
+ tail++;
+ }
}
yaml_document_start_event_initialize(
- &event,
- (RARRAY_LEN(version) > 0) ? &version_directive : NULL,
- data->head,
- tail,
- imp ? 1 : 0
- );
+ &event,
+ (RARRAY_LEN(version) > 0) ? &version_directive : NULL,
+ head,
+ tail,
+ imp ? 1 : 0
+ );
emit(emitter, &event);
- return self;
-}
-
-static VALUE start_document_ensure(VALUE d)
-{
- struct start_document_data * data = (struct start_document_data *)d;
-
- xfree(data->head);
-
- return Qnil;
-}
-
-/* call-seq: emitter.start_document(version, tags, implicit)
- *
- * Start a document emission with YAML +version+, +tags+, and an +implicit+
- * start.
- *
- * See Psych::Handler#start_document
- */
-static VALUE start_document(VALUE self, VALUE version, VALUE tags, VALUE imp)
-{
- struct start_document_data data = {
- .self = self,
- .version = version,
- .tags = tags,
- .imp = imp,
-
- .head = NULL,
- };
+ if(head) xfree(head);
- return rb_ensure(start_document_try, (VALUE)&data, start_document_ensure, (VALUE)&data);
+ return self;
}
/* call-seq: emitter.end_document(implicit)
@@ -275,14 +241,14 @@ static VALUE end_document(VALUE self, VALUE imp)
* See Psych::Handler#scalar
*/
static VALUE scalar(
- VALUE self,
- VALUE value,
- VALUE anchor,
- VALUE tag,
- VALUE plain,
- VALUE quoted,
- VALUE style
- ) {
+ VALUE self,
+ VALUE value,
+ VALUE anchor,
+ VALUE tag,
+ VALUE plain,
+ VALUE quoted,
+ VALUE style
+ ) {
yaml_emitter_t * emitter;
yaml_event_t event;
rb_encoding *encoding;
@@ -295,25 +261,25 @@ static VALUE scalar(
value = rb_str_export_to_enc(value, encoding);
if(!NIL_P(anchor)) {
- Check_Type(anchor, T_STRING);
- anchor = rb_str_export_to_enc(anchor, encoding);
+ Check_Type(anchor, T_STRING);
+ anchor = rb_str_export_to_enc(anchor, encoding);
}
if(!NIL_P(tag)) {
- Check_Type(tag, T_STRING);
- tag = rb_str_export_to_enc(tag, encoding);
+ Check_Type(tag, T_STRING);
+ tag = rb_str_export_to_enc(tag, encoding);
}
yaml_scalar_event_initialize(
- &event,
- (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)),
- (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)),
- (yaml_char_t*)StringValuePtr(value),
- (int)RSTRING_LEN(value),
- plain ? 1 : 0,
- quoted ? 1 : 0,
- (yaml_scalar_style_t)NUM2INT(style)
- );
+ &event,
+ (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)),
+ (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)),
+ (yaml_char_t*)StringValuePtr(value),
+ (int)RSTRING_LEN(value),
+ plain ? 1 : 0,
+ quoted ? 1 : 0,
+ (yaml_scalar_style_t)NUM2INT(style)
+ );
emit(emitter, &event);
@@ -328,36 +294,36 @@ static VALUE scalar(
* See Psych::Handler#start_sequence
*/
static VALUE start_sequence(
- VALUE self,
- VALUE anchor,
- VALUE tag,
- VALUE implicit,
- VALUE style
- ) {
+ VALUE self,
+ VALUE anchor,
+ VALUE tag,
+ VALUE implicit,
+ VALUE style
+ ) {
yaml_emitter_t * emitter;
yaml_event_t event;
rb_encoding * encoding = rb_utf8_encoding();
if(!NIL_P(anchor)) {
- Check_Type(anchor, T_STRING);
- anchor = rb_str_export_to_enc(anchor, encoding);
+ Check_Type(anchor, T_STRING);
+ anchor = rb_str_export_to_enc(anchor, encoding);
}
if(!NIL_P(tag)) {
- Check_Type(tag, T_STRING);
- tag = rb_str_export_to_enc(tag, encoding);
+ Check_Type(tag, T_STRING);
+ tag = rb_str_export_to_enc(tag, encoding);
}
TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
yaml_sequence_start_event_initialize(
- &event,
- (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)),
- (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)),
- implicit ? 1 : 0,
- (yaml_sequence_style_t)NUM2INT(style)
- );
+ &event,
+ (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)),
+ (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)),
+ implicit ? 1 : 0,
+ (yaml_sequence_style_t)NUM2INT(style)
+ );
emit(emitter, &event);
@@ -391,12 +357,12 @@ static VALUE end_sequence(VALUE self)
* See Psych::Handler#start_mapping
*/
static VALUE start_mapping(
- VALUE self,
- VALUE anchor,
- VALUE tag,
- VALUE implicit,
- VALUE style
- ) {
+ VALUE self,
+ VALUE anchor,
+ VALUE tag,
+ VALUE implicit,
+ VALUE style
+ ) {
yaml_emitter_t * emitter;
yaml_event_t event;
rb_encoding *encoding;
@@ -406,22 +372,22 @@ static VALUE start_mapping(
encoding = rb_utf8_encoding();
if(!NIL_P(anchor)) {
- Check_Type(anchor, T_STRING);
- anchor = rb_str_export_to_enc(anchor, encoding);
+ Check_Type(anchor, T_STRING);
+ anchor = rb_str_export_to_enc(anchor, encoding);
}
if(!NIL_P(tag)) {
- Check_Type(tag, T_STRING);
- tag = rb_str_export_to_enc(tag, encoding);
+ Check_Type(tag, T_STRING);
+ tag = rb_str_export_to_enc(tag, encoding);
}
yaml_mapping_start_event_initialize(
- &event,
- (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)),
- (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)),
- implicit ? 1 : 0,
- (yaml_mapping_style_t)NUM2INT(style)
- );
+ &event,
+ (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)),
+ (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)),
+ implicit ? 1 : 0,
+ (yaml_mapping_style_t)NUM2INT(style)
+ );
emit(emitter, &event);
@@ -460,14 +426,14 @@ static VALUE alias(VALUE self, VALUE anchor)
TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter);
if(!NIL_P(anchor)) {
- Check_Type(anchor, T_STRING);
- anchor = rb_str_export_to_enc(anchor, rb_utf8_encoding());
+ Check_Type(anchor, T_STRING);
+ anchor = rb_str_export_to_enc(anchor, rb_utf8_encoding());
}
yaml_alias_event_initialize(
- &event,
- (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor))
- );
+ &event,
+ (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor))
+ );
emit(emitter, &event);
diff --git a/ext/psych/psych_parser.c b/ext/psych/psych_parser.c
index 26e2d41e06..9c5179cc44 100644
--- a/ext/psych/psych_parser.c
+++ b/ext/psych/psych_parser.c
@@ -32,9 +32,9 @@ static int io_reader(void * data, unsigned char *buf, size_t size, size_t *read)
*read = 0;
if(! NIL_P(string)) {
- void * str = (void *)StringValuePtr(string);
- *read = (size_t)RSTRING_LEN(string);
- memcpy(buf, str, *read);
+ void * str = (void *)StringValuePtr(string);
+ *read = (size_t)RSTRING_LEN(string);
+ memcpy(buf, str, *read);
}
return 1;
@@ -80,23 +80,23 @@ static VALUE allocate(VALUE klass)
static VALUE make_exception(yaml_parser_t * parser, VALUE path)
{
if (parser->error == YAML_MEMORY_ERROR) {
- return rb_eNoMemError;
+ return rb_eNoMemError;
} else {
- size_t line, column;
- VALUE ePsychSyntaxError;
+ size_t line, column;
+ VALUE ePsychSyntaxError;
- line = parser->context_mark.line + 1;
- column = parser->context_mark.column + 1;
+ line = parser->context_mark.line + 1;
+ column = parser->context_mark.column + 1;
- ePsychSyntaxError = rb_const_get(mPsych, rb_intern("SyntaxError"));
+ ePsychSyntaxError = rb_const_get(mPsych, rb_intern("SyntaxError"));
- return rb_funcall(ePsychSyntaxError, rb_intern("new"), 6,
- path,
- SIZET2NUM(line),
- SIZET2NUM(column),
- SIZET2NUM(parser->problem_offset),
- parser->problem ? rb_usascii_str_new2(parser->problem) : Qnil,
- parser->context ? rb_usascii_str_new2(parser->context) : Qnil);
+ return rb_funcall(ePsychSyntaxError, rb_intern("new"), 6,
+ path,
+ SIZET2NUM(line),
+ SIZET2NUM(column),
+ SIZET2NUM(parser->problem_offset),
+ parser->problem ? rb_usascii_str_new2(parser->problem) : Qnil,
+ parser->context ? rb_usascii_str_new2(parser->context) : Qnil);
}
}
@@ -108,18 +108,18 @@ static VALUE transcode_string(VALUE src, int * parser_encoding)
int source_encoding = rb_enc_get_index(src);
if (source_encoding == utf8) {
- *parser_encoding = YAML_UTF8_ENCODING;
- return src;
+ *parser_encoding = YAML_UTF8_ENCODING;
+ return src;
}
if (source_encoding == utf16le) {
- *parser_encoding = YAML_UTF16LE_ENCODING;
- return src;
+ *parser_encoding = YAML_UTF16LE_ENCODING;
+ return src;
}
if (source_encoding == utf16be) {
- *parser_encoding = YAML_UTF16BE_ENCODING;
- return src;
+ *parser_encoding = YAML_UTF16BE_ENCODING;
+ return src;
}
src = rb_str_export_to_enc(src, rb_utf8_encoding());
@@ -138,36 +138,36 @@ static VALUE transcode_io(VALUE src, int * parser_encoding)
/* if no encoding is returned, assume ascii8bit. */
if (NIL_P(io_external_encoding)) {
- io_external_enc_index = rb_ascii8bit_encindex();
+ io_external_enc_index = rb_ascii8bit_encindex();
} else {
- io_external_enc_index = rb_to_encoding_index(io_external_encoding);
+ io_external_enc_index = rb_to_encoding_index(io_external_encoding);
}
/* Treat US-ASCII as utf_8 */
if (io_external_enc_index == rb_usascii_encindex()) {
- *parser_encoding = YAML_UTF8_ENCODING;
- return src;
+ *parser_encoding = YAML_UTF8_ENCODING;
+ return src;
}
if (io_external_enc_index == rb_utf8_encindex()) {
- *parser_encoding = YAML_UTF8_ENCODING;
- return src;
+ *parser_encoding = YAML_UTF8_ENCODING;
+ return src;
}
if (io_external_enc_index == rb_enc_find_index("UTF-16LE")) {
- *parser_encoding = YAML_UTF16LE_ENCODING;
- return src;
+ *parser_encoding = YAML_UTF16LE_ENCODING;
+ return src;
}
if (io_external_enc_index == rb_enc_find_index("UTF-16BE")) {
- *parser_encoding = YAML_UTF16BE_ENCODING;
- return src;
+ *parser_encoding = YAML_UTF16BE_ENCODING;
+ return src;
}
/* Just guess on ASCII-8BIT */
if (io_external_enc_index == rb_ascii8bit_encindex()) {
- *parser_encoding = YAML_ANY_ENCODING;
- return src;
+ *parser_encoding = YAML_ANY_ENCODING;
+ return src;
}
/* If the external encoding is something we don't know how to handle,
@@ -261,238 +261,238 @@ static VALUE parse(VALUE self, VALUE handler, VALUE yaml, VALUE path)
yaml_parser_initialize(parser);
if (rb_respond_to(yaml, id_read)) {
- yaml = transcode_io(yaml, &parser_encoding);
- yaml_parser_set_encoding(parser, parser_encoding);
- yaml_parser_set_input(parser, io_reader, (void *)yaml);
+ yaml = transcode_io(yaml, &parser_encoding);
+ yaml_parser_set_encoding(parser, parser_encoding);
+ yaml_parser_set_input(parser, io_reader, (void *)yaml);
} else {
- StringValue(yaml);
- yaml = transcode_string(yaml, &parser_encoding);
- yaml_parser_set_encoding(parser, parser_encoding);
- yaml_parser_set_input_string(
- parser,
- (const unsigned char *)RSTRING_PTR(yaml),
- (size_t)RSTRING_LEN(yaml)
- );
+ StringValue(yaml);
+ yaml = transcode_string(yaml, &parser_encoding);
+ yaml_parser_set_encoding(parser, parser_encoding);
+ yaml_parser_set_input_string(
+ parser,
+ (const unsigned char *)RSTRING_PTR(yaml),
+ (size_t)RSTRING_LEN(yaml)
+ );
}
while(!done) {
- VALUE event_args[5];
- VALUE start_line, start_column, end_line, end_column;
-
- if(parser->error || !yaml_parser_parse(parser, &event)) {
- VALUE exception;
-
- exception = make_exception(parser, path);
- yaml_parser_delete(parser);
- yaml_parser_initialize(parser);
-
- rb_exc_raise(exception);
- }
-
- start_line = SIZET2NUM(event.start_mark.line);
- start_column = SIZET2NUM(event.start_mark.column);
- end_line = SIZET2NUM(event.end_mark.line);
- end_column = SIZET2NUM(event.end_mark.column);
-
- event_args[0] = handler;
- event_args[1] = start_line;
- event_args[2] = start_column;
- event_args[3] = end_line;
- event_args[4] = end_column;
- rb_protect(protected_event_location, (VALUE)event_args, &state);
-
- switch(event.type) {
- case YAML_STREAM_START_EVENT:
- {
- VALUE args[2];
-
- args[0] = handler;
- args[1] = INT2NUM(event.data.stream_start.encoding);
- rb_protect(protected_start_stream, (VALUE)args, &state);
- }
- break;
- case YAML_DOCUMENT_START_EVENT:
- {
- VALUE args[4];
- /* Get a list of tag directives (if any) */
- VALUE tag_directives = rb_ary_new();
- /* Grab the document version */
- VALUE version = event.data.document_start.version_directive ?
- rb_ary_new3(
- (long)2,
- INT2NUM(event.data.document_start.version_directive->major),
- INT2NUM(event.data.document_start.version_directive->minor)
- ) : rb_ary_new();
-
- if(event.data.document_start.tag_directives.start) {
- yaml_tag_directive_t *start =
- event.data.document_start.tag_directives.start;
- yaml_tag_directive_t *end =
- event.data.document_start.tag_directives.end;
- for(; start != end; start++) {
- VALUE handle = Qnil;
- VALUE prefix = Qnil;
- if(start->handle) {
- handle = rb_str_new2((const char *)start->handle);
- PSYCH_TRANSCODE(handle, encoding, internal_enc);
- }
-
- if(start->prefix) {
- prefix = rb_str_new2((const char *)start->prefix);
- PSYCH_TRANSCODE(prefix, encoding, internal_enc);
- }
-
- rb_ary_push(tag_directives, rb_ary_new3((long)2, handle, prefix));
- }
- }
- args[0] = handler;
- args[1] = version;
- args[2] = tag_directives;
- args[3] = event.data.document_start.implicit == 1 ? Qtrue : Qfalse;
- rb_protect(protected_start_document, (VALUE)args, &state);
- }
- break;
- case YAML_DOCUMENT_END_EVENT:
- {
- VALUE args[2];
-
- args[0] = handler;
- args[1] = event.data.document_end.implicit == 1 ? Qtrue : Qfalse;
- rb_protect(protected_end_document, (VALUE)args, &state);
- }
- break;
- case YAML_ALIAS_EVENT:
- {
- VALUE args[2];
- VALUE alias = Qnil;
- if(event.data.alias.anchor) {
- alias = rb_str_new2((const char *)event.data.alias.anchor);
- PSYCH_TRANSCODE(alias, encoding, internal_enc);
- }
-
- args[0] = handler;
- args[1] = alias;
- rb_protect(protected_alias, (VALUE)args, &state);
- }
- break;
- case YAML_SCALAR_EVENT:
- {
- VALUE args[7];
- VALUE anchor = Qnil;
- VALUE tag = Qnil;
- VALUE plain_implicit, quoted_implicit, style;
- VALUE val = rb_str_new(
- (const char *)event.data.scalar.value,
- (long)event.data.scalar.length
- );
-
- PSYCH_TRANSCODE(val, encoding, internal_enc);
-
- if(event.data.scalar.anchor) {
- anchor = rb_str_new2((const char *)event.data.scalar.anchor);
- PSYCH_TRANSCODE(anchor, encoding, internal_enc);
- }
-
- if(event.data.scalar.tag) {
- tag = rb_str_new2((const char *)event.data.scalar.tag);
- PSYCH_TRANSCODE(tag, encoding, internal_enc);
- }
-
- plain_implicit =
- event.data.scalar.plain_implicit == 0 ? Qfalse : Qtrue;
-
- quoted_implicit =
- event.data.scalar.quoted_implicit == 0 ? Qfalse : Qtrue;
-
- style = INT2NUM(event.data.scalar.style);
-
- args[0] = handler;
- args[1] = val;
- args[2] = anchor;
- args[3] = tag;
- args[4] = plain_implicit;
- args[5] = quoted_implicit;
- args[6] = style;
- rb_protect(protected_scalar, (VALUE)args, &state);
- }
- break;
- case YAML_SEQUENCE_START_EVENT:
- {
- VALUE args[5];
- VALUE anchor = Qnil;
- VALUE tag = Qnil;
- VALUE implicit, style;
- if(event.data.sequence_start.anchor) {
- anchor = rb_str_new2((const char *)event.data.sequence_start.anchor);
- PSYCH_TRANSCODE(anchor, encoding, internal_enc);
- }
-
- tag = Qnil;
- if(event.data.sequence_start.tag) {
- tag = rb_str_new2((const char *)event.data.sequence_start.tag);
- PSYCH_TRANSCODE(tag, encoding, internal_enc);
- }
-
- implicit =
- event.data.sequence_start.implicit == 0 ? Qfalse : Qtrue;
-
- style = INT2NUM(event.data.sequence_start.style);
-
- args[0] = handler;
- args[1] = anchor;
- args[2] = tag;
- args[3] = implicit;
- args[4] = style;
-
- rb_protect(protected_start_sequence, (VALUE)args, &state);
- }
- break;
- case YAML_SEQUENCE_END_EVENT:
- rb_protect(protected_end_sequence, handler, &state);
- break;
- case YAML_MAPPING_START_EVENT:
- {
- VALUE args[5];
- VALUE anchor = Qnil;
- VALUE tag = Qnil;
- VALUE implicit, style;
- if(event.data.mapping_start.anchor) {
- anchor = rb_str_new2((const char *)event.data.mapping_start.anchor);
- PSYCH_TRANSCODE(anchor, encoding, internal_enc);
- }
-
- if(event.data.mapping_start.tag) {
- tag = rb_str_new2((const char *)event.data.mapping_start.tag);
- PSYCH_TRANSCODE(tag, encoding, internal_enc);
- }
-
- implicit =
- event.data.mapping_start.implicit == 0 ? Qfalse : Qtrue;
-
- style = INT2NUM(event.data.mapping_start.style);
-
- args[0] = handler;
- args[1] = anchor;
- args[2] = tag;
- args[3] = implicit;
- args[4] = style;
-
- rb_protect(protected_start_mapping, (VALUE)args, &state);
- }
- break;
- case YAML_MAPPING_END_EVENT:
- rb_protect(protected_end_mapping, handler, &state);
- break;
- case YAML_NO_EVENT:
- rb_protect(protected_empty, handler, &state);
- break;
- case YAML_STREAM_END_EVENT:
- rb_protect(protected_end_stream, handler, &state);
- done = 1;
- break;
- }
- yaml_event_delete(&event);
- if (state) rb_jump_tag(state);
+ VALUE event_args[5];
+ VALUE start_line, start_column, end_line, end_column;
+
+ if(parser->error || !yaml_parser_parse(parser, &event)) {
+ VALUE exception;
+
+ exception = make_exception(parser, path);
+ yaml_parser_delete(parser);
+ yaml_parser_initialize(parser);
+
+ rb_exc_raise(exception);
+ }
+
+ start_line = SIZET2NUM(event.start_mark.line);
+ start_column = SIZET2NUM(event.start_mark.column);
+ end_line = SIZET2NUM(event.end_mark.line);
+ end_column = SIZET2NUM(event.end_mark.column);
+
+ event_args[0] = handler;
+ event_args[1] = start_line;
+ event_args[2] = start_column;
+ event_args[3] = end_line;
+ event_args[4] = end_column;
+ rb_protect(protected_event_location, (VALUE)event_args, &state);
+
+ switch(event.type) {
+ case YAML_STREAM_START_EVENT:
+ {
+ VALUE args[2];
+
+ args[0] = handler;
+ args[1] = INT2NUM(event.data.stream_start.encoding);
+ rb_protect(protected_start_stream, (VALUE)args, &state);
+ }
+ break;
+ case YAML_DOCUMENT_START_EVENT:
+ {
+ VALUE args[4];
+ /* Get a list of tag directives (if any) */
+ VALUE tag_directives = rb_ary_new();
+ /* Grab the document version */
+ VALUE version = event.data.document_start.version_directive ?
+ rb_ary_new3(
+ (long)2,
+ INT2NUM(event.data.document_start.version_directive->major),
+ INT2NUM(event.data.document_start.version_directive->minor)
+ ) : rb_ary_new();
+
+ if(event.data.document_start.tag_directives.start) {
+ yaml_tag_directive_t *start =
+ event.data.document_start.tag_directives.start;
+ yaml_tag_directive_t *end =
+ event.data.document_start.tag_directives.end;
+ for(; start != end; start++) {
+ VALUE handle = Qnil;
+ VALUE prefix = Qnil;
+ if(start->handle) {
+ handle = rb_str_new2((const char *)start->handle);
+ PSYCH_TRANSCODE(handle, encoding, internal_enc);
+ }
+
+ if(start->prefix) {
+ prefix = rb_str_new2((const char *)start->prefix);
+ PSYCH_TRANSCODE(prefix, encoding, internal_enc);
+ }
+
+ rb_ary_push(tag_directives, rb_ary_new3((long)2, handle, prefix));
+ }
+ }
+ args[0] = handler;
+ args[1] = version;
+ args[2] = tag_directives;
+ args[3] = event.data.document_start.implicit == 1 ? Qtrue : Qfalse;
+ rb_protect(protected_start_document, (VALUE)args, &state);
+ }
+ break;
+ case YAML_DOCUMENT_END_EVENT:
+ {
+ VALUE args[2];
+
+ args[0] = handler;
+ args[1] = event.data.document_end.implicit == 1 ? Qtrue : Qfalse;
+ rb_protect(protected_end_document, (VALUE)args, &state);
+ }
+ break;
+ case YAML_ALIAS_EVENT:
+ {
+ VALUE args[2];
+ VALUE alias = Qnil;
+ if(event.data.alias.anchor) {
+ alias = rb_str_new2((const char *)event.data.alias.anchor);
+ PSYCH_TRANSCODE(alias, encoding, internal_enc);
+ }
+
+ args[0] = handler;
+ args[1] = alias;
+ rb_protect(protected_alias, (VALUE)args, &state);
+ }
+ break;
+ case YAML_SCALAR_EVENT:
+ {
+ VALUE args[7];
+ VALUE anchor = Qnil;
+ VALUE tag = Qnil;
+ VALUE plain_implicit, quoted_implicit, style;
+ VALUE val = rb_str_new(
+ (const char *)event.data.scalar.value,
+ (long)event.data.scalar.length
+ );
+
+ PSYCH_TRANSCODE(val, encoding, internal_enc);
+
+ if(event.data.scalar.anchor) {
+ anchor = rb_str_new2((const char *)event.data.scalar.anchor);
+ PSYCH_TRANSCODE(anchor, encoding, internal_enc);
+ }
+
+ if(event.data.scalar.tag) {
+ tag = rb_str_new2((const char *)event.data.scalar.tag);
+ PSYCH_TRANSCODE(tag, encoding, internal_enc);
+ }
+
+ plain_implicit =
+ event.data.scalar.plain_implicit == 0 ? Qfalse : Qtrue;
+
+ quoted_implicit =
+ event.data.scalar.quoted_implicit == 0 ? Qfalse : Qtrue;
+
+ style = INT2NUM(event.data.scalar.style);
+
+ args[0] = handler;
+ args[1] = val;
+ args[2] = anchor;
+ args[3] = tag;
+ args[4] = plain_implicit;
+ args[5] = quoted_implicit;
+ args[6] = style;
+ rb_protect(protected_scalar, (VALUE)args, &state);
+ }
+ break;
+ case YAML_SEQUENCE_START_EVENT:
+ {
+ VALUE args[5];
+ VALUE anchor = Qnil;
+ VALUE tag = Qnil;
+ VALUE implicit, style;
+ if(event.data.sequence_start.anchor) {
+ anchor = rb_str_new2((const char *)event.data.sequence_start.anchor);
+ PSYCH_TRANSCODE(anchor, encoding, internal_enc);
+ }
+
+ tag = Qnil;
+ if(event.data.sequence_start.tag) {
+ tag = rb_str_new2((const char *)event.data.sequence_start.tag);
+ PSYCH_TRANSCODE(tag, encoding, internal_enc);
+ }
+
+ implicit =
+ event.data.sequence_start.implicit == 0 ? Qfalse : Qtrue;
+
+ style = INT2NUM(event.data.sequence_start.style);
+
+ args[0] = handler;
+ args[1] = anchor;
+ args[2] = tag;
+ args[3] = implicit;
+ args[4] = style;
+
+ rb_protect(protected_start_sequence, (VALUE)args, &state);
+ }
+ break;
+ case YAML_SEQUENCE_END_EVENT:
+ rb_protect(protected_end_sequence, handler, &state);
+ break;
+ case YAML_MAPPING_START_EVENT:
+ {
+ VALUE args[5];
+ VALUE anchor = Qnil;
+ VALUE tag = Qnil;
+ VALUE implicit, style;
+ if(event.data.mapping_start.anchor) {
+ anchor = rb_str_new2((const char *)event.data.mapping_start.anchor);
+ PSYCH_TRANSCODE(anchor, encoding, internal_enc);
+ }
+
+ if(event.data.mapping_start.tag) {
+ tag = rb_str_new2((const char *)event.data.mapping_start.tag);
+ PSYCH_TRANSCODE(tag, encoding, internal_enc);
+ }
+
+ implicit =
+ event.data.mapping_start.implicit == 0 ? Qfalse : Qtrue;
+
+ style = INT2NUM(event.data.mapping_start.style);
+
+ args[0] = handler;
+ args[1] = anchor;
+ args[2] = tag;
+ args[3] = implicit;
+ args[4] = style;
+
+ rb_protect(protected_start_mapping, (VALUE)args, &state);
+ }
+ break;
+ case YAML_MAPPING_END_EVENT:
+ rb_protect(protected_end_mapping, handler, &state);
+ break;
+ case YAML_NO_EVENT:
+ rb_protect(protected_empty, handler, &state);
+ break;
+ case YAML_STREAM_END_EVENT:
+ rb_protect(protected_end_stream, handler, &state);
+ done = 1;
+ break;
+ }
+ yaml_event_delete(&event);
+ if (state) rb_jump_tag(state);
}
return self;
diff --git a/ext/pty/depend b/ext/pty/depend
index adecfff862..f251caae3f 100644
--- a/ext/pty/depend
+++ b/ext/pty/depend
@@ -53,7 +53,6 @@ pty.o: $(hdrdir)/ruby/internal/attr/noexcept.h
pty.o: $(hdrdir)/ruby/internal/attr/noinline.h
pty.o: $(hdrdir)/ruby/internal/attr/nonnull.h
pty.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-pty.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
pty.o: $(hdrdir)/ruby/internal/attr/pure.h
pty.o: $(hdrdir)/ruby/internal/attr/restrict.h
pty.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ pty.o: $(hdrdir)/ruby/internal/intern/enumerator.h
pty.o: $(hdrdir)/ruby/internal/intern/error.h
pty.o: $(hdrdir)/ruby/internal/intern/eval.h
pty.o: $(hdrdir)/ruby/internal/intern/file.h
+pty.o: $(hdrdir)/ruby/internal/intern/gc.h
pty.o: $(hdrdir)/ruby/internal/intern/hash.h
pty.o: $(hdrdir)/ruby/internal/intern/io.h
pty.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,12 +152,12 @@ pty.o: $(hdrdir)/ruby/internal/memory.h
pty.o: $(hdrdir)/ruby/internal/method.h
pty.o: $(hdrdir)/ruby/internal/module.h
pty.o: $(hdrdir)/ruby/internal/newobj.h
+pty.o: $(hdrdir)/ruby/internal/rgengc.h
pty.o: $(hdrdir)/ruby/internal/scan_args.h
pty.o: $(hdrdir)/ruby/internal/special_consts.h
pty.o: $(hdrdir)/ruby/internal/static_assert.h
pty.o: $(hdrdir)/ruby/internal/stdalign.h
pty.o: $(hdrdir)/ruby/internal/stdbool.h
-pty.o: $(hdrdir)/ruby/internal/stdckdint.h
pty.o: $(hdrdir)/ruby/internal/symbol.h
pty.o: $(hdrdir)/ruby/internal/value.h
pty.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/pty/extconf.rb b/ext/pty/extconf.rb
index da3655cf4d..ba0c4286fd 100644
--- a/ext/pty/extconf.rb
+++ b/ext/pty/extconf.rb
@@ -13,13 +13,10 @@ if /mswin|mingw|bccwin/ !~ RUBY_PLATFORM
have_header("util.h") # OpenBSD openpty
util = have_library("util", "openpty")
end
- openpt = have_func("posix_openpt")
- if openpt
- have_func("ptsname_r") or have_func("ptsname")
- end
- if openpt or
+ if have_func("posix_openpt") or
(util or have_func("openpty")) or
have_func("_getpty") or
+ have_func("ptsname") or
have_func("ioctl")
create_makefile('pty')
end
diff --git a/ext/pty/pty.c b/ext/pty/pty.c
index 0e04b02d83..acec33f9bf 100644
--- a/ext/pty/pty.c
+++ b/ext/pty/pty.c
@@ -92,13 +92,9 @@ struct pty_info {
static void getDevice(int*, int*, char [DEVICELEN], int);
-static int start_new_session(char *errbuf, size_t errbuf_len);
-static int obtain_ctty(int master, int slave, const char *slavename, char *errbuf, size_t errbuf_len);
-static int drop_privilige(char *errbuf, size_t errbuf_len);
-
struct child_info {
int master, slave;
- const char *slavename;
+ char *slavename;
VALUE execarg_obj;
struct rb_execarg *eargp;
};
@@ -106,42 +102,26 @@ struct child_info {
static int
chfunc(void *data, char *errbuf, size_t errbuf_len)
{
- const struct child_info *carg = data;
+ struct child_info *carg = data;
int master = carg->master;
int slave = carg->slave;
- const char *slavename = carg->slavename;
-
- if (start_new_session(errbuf, errbuf_len))
- return -1;
-
- if (obtain_ctty(master, slave, slavename, errbuf, errbuf_len))
- return -1;
-
- if (drop_privilige(errbuf, errbuf_len))
- return -1;
-
- return rb_exec_async_signal_safe(carg->eargp, errbuf, errbuf_len);
-}
#define ERROR_EXIT(str) do { \
strlcpy(errbuf, (str), errbuf_len); \
return -1; \
} while (0)
-/*
- * Set free from process group and controlling terminal
- */
-static int
-start_new_session(char *errbuf, size_t errbuf_len)
-{
+ /*
+ * Set free from process group and controlling terminal
+ */
#ifdef HAVE_SETSID
(void) setsid();
#else /* HAS_SETSID */
# ifdef HAVE_SETPGRP
-# ifdef SETPGRP_VOID
+# ifdef SETGRP_VOID
if (setpgrp() == -1)
ERROR_EXIT("setpgrp()");
-# else /* SETPGRP_VOID */
+# else /* SETGRP_VOID */
if (setpgrp(0, getpid()) == -1)
ERROR_EXIT("setpgrp()");
{
@@ -152,25 +132,20 @@ start_new_session(char *errbuf, size_t errbuf_len)
ERROR_EXIT("ioctl(TIOCNOTTY)");
close(i);
}
-# endif /* SETPGRP_VOID */
+# endif /* SETGRP_VOID */
# endif /* HAVE_SETPGRP */
#endif /* HAS_SETSID */
- return 0;
-}
-/*
- * obtain new controlling terminal
- */
-static int
-obtain_ctty(int master, int slave, const char *slavename, char *errbuf, size_t errbuf_len)
-{
+ /*
+ * obtain new controlling terminal
+ */
#if defined(TIOCSCTTY)
close(master);
(void) ioctl(slave, TIOCSCTTY, (char *)0);
/* errors ignored for sun */
#else
close(slave);
- slave = rb_cloexec_open(slavename, O_RDWR, 0);
+ slave = rb_cloexec_open(carg->slavename, O_RDWR, 0);
if (slave < 0) {
ERROR_EXIT("open: pty slave");
}
@@ -181,19 +156,13 @@ obtain_ctty(int master, int slave, const char *slavename, char *errbuf, size_t e
dup2(slave,1);
dup2(slave,2);
if (slave < 0 || slave > 2) (void)!close(slave);
- return 0;
-}
-
-static int
-drop_privilige(char *errbuf, size_t errbuf_len)
-{
#if defined(HAVE_SETEUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRESUID)
if (seteuid(getuid())) ERROR_EXIT("seteuid()");
#endif
- return 0;
-}
+ return rb_exec_async_signal_safe(carg->eargp, errbuf, sizeof(errbuf_len));
#undef ERROR_EXIT
+}
static void
establishShell(int argc, VALUE *argv, struct pty_info *info,
@@ -215,13 +184,9 @@ establishShell(int argc, VALUE *argv, struct pty_info *info,
else {
#if defined HAVE_PWD_H
const char *username = getenv("USER");
- if (username == NULL)
- username = getlogin();
- if (username != NULL) {
- struct passwd *pwent = getpwnam(username);
- if (pwent && pwent->pw_shell)
- shellname = pwent->pw_shell;
- }
+ struct passwd *pwent = getpwnam(username ? username : getlogin());
+ if (pwent && pwent->pw_shell)
+ shellname = pwent->pw_shell;
#endif
}
v = rb_str_new2(shellname);
@@ -260,21 +225,7 @@ establishShell(int argc, VALUE *argv, struct pty_info *info,
RB_GC_GUARD(carg.execarg_obj);
}
-#if (defined(HAVE_POSIX_OPENPT) || defined(HAVE_PTSNAME)) && !defined(HAVE_PTSNAME_R)
-/* glibc only, not obsolete interface on Tru64 or HP-UX */
-static int
-ptsname_r(int fd, char *buf, size_t buflen)
-{
- extern char *ptsname(int);
- char *name = ptsname(fd);
- if (!name) return -1;
- strlcpy(buf, name, buflen);
- return 0;
-}
-# define HAVE_PTSNAME_R 1
-#endif
-
-#if defined(HAVE_POSIX_OPENPT) || defined(HAVE_OPENPTY) || defined(HAVE_PTSNAME_R)
+#if defined(HAVE_POSIX_OPENPT) || defined(HAVE_OPENPTY) || defined(HAVE_PTSNAME)
static int
no_mesg(char *slavedevice, int nomesg)
{
@@ -307,19 +258,13 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
/* Unix98 PTY */
int masterfd = -1, slavefd = -1;
char *slavedevice;
- struct sigaction dfl, old;
-
- dfl.sa_handler = SIG_DFL;
- dfl.sa_flags = 0;
- sigemptyset(&dfl.sa_mask);
#if defined(__sun) || defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD_version < 902000)
/* workaround for Solaris 10: grantpt() doesn't work if FD_CLOEXEC is set. [ruby-dev:44688] */
/* FreeBSD 9.2 or later supports O_CLOEXEC
* http://www.freebsd.org/cgi/query-pr.cgi?pr=162374 */
if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1) goto error;
- if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
- if (grantpt(masterfd) == -1) goto grantpt_error;
+ if (rb_grantpt(masterfd) == -1) goto error;
rb_fd_fix_cloexec(masterfd);
#else
{
@@ -333,13 +278,10 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
if ((masterfd = posix_openpt(flags)) == -1) goto error;
}
rb_fd_fix_cloexec(masterfd);
- if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
- if (grantpt(masterfd) == -1) goto grantpt_error;
+ if (rb_grantpt(masterfd) == -1) goto error;
#endif
- if (sigaction(SIGCHLD, &old, NULL) == -1) goto error;
if (unlockpt(masterfd) == -1) goto error;
- if (ptsname_r(masterfd, SlaveName, DEVICELEN) != 0) goto error;
- slavedevice = SlaveName;
+ if ((slavedevice = ptsname(masterfd)) == NULL) goto error;
if (no_mesg(slavedevice, nomesg) == -1) goto error;
if ((slavefd = rb_cloexec_open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1) goto error;
rb_update_max_fd(slavefd);
@@ -352,10 +294,9 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
*master = masterfd;
*slave = slavefd;
+ strlcpy(SlaveName, slavedevice, DEVICELEN);
return 0;
- grantpt_error:
- sigaction(SIGCHLD, &old, NULL);
error:
if (slavefd != -1) close(slavefd);
if (masterfd != -1) close(masterfd);
@@ -405,25 +346,21 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
char *slavedevice;
void (*s)();
+ extern char *ptsname(int);
extern int unlockpt(int);
- extern int grantpt(int);
#if defined(__sun)
/* workaround for Solaris 10: grantpt() doesn't work if FD_CLOEXEC is set. [ruby-dev:44688] */
if((masterfd = open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
- s = signal(SIGCHLD, SIG_DFL);
- if(grantpt(masterfd) == -1) goto error;
+ if(rb_grantpt(masterfd) == -1) goto error;
rb_fd_fix_cloexec(masterfd);
#else
if((masterfd = rb_cloexec_open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
rb_update_max_fd(masterfd);
- s = signal(SIGCHLD, SIG_DFL);
- if(grantpt(masterfd) == -1) goto error;
+ if(rb_grantpt(masterfd) == -1) goto error;
#endif
- signal(SIGCHLD, s);
if(unlockpt(masterfd) == -1) goto error;
- if (ptsname_r(masterfd, SlaveName, DEVICELEN) != 0) goto error;
- slavedevice = SlaveName;
+ if((slavedevice = ptsname(masterfd)) == NULL) goto error;
if (no_mesg(slavedevice, nomesg) == -1) goto error;
if((slavefd = rb_cloexec_open(slavedevice, O_RDWR, 0)) == -1) goto error;
rb_update_max_fd(slavefd);
@@ -434,6 +371,7 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
#endif
*master = masterfd;
*slave = slavefd;
+ strlcpy(SlaveName, slavedevice, DEVICELEN);
return 0;
error:
@@ -510,10 +448,8 @@ pty_close_pty(VALUE assoc)
for (i = 0; i < 2; i++) {
io = rb_ary_entry(assoc, i);
- if (RB_TYPE_P(io, T_FILE)) {
- /* it's OK to call rb_io_close again even if it's already closed */
+ if (RB_TYPE_P(io, T_FILE) && 0 <= RFILE(io)->fptr->fd)
rb_io_close(io);
- }
}
return Qnil;
}
@@ -563,21 +499,28 @@ pty_open(VALUE klass)
{
int master_fd, slave_fd;
char slavename[DEVICELEN];
+ VALUE master_io, slave_file;
+ rb_io_t *master_fptr, *slave_fptr;
+ VALUE assoc;
getDevice(&master_fd, &slave_fd, slavename, 1);
- VALUE master_path = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
- VALUE master_io = rb_io_open_descriptor(rb_cIO, master_fd, FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX, master_path, RUBY_IO_TIMEOUT_DEFAULT, NULL);
+ master_io = rb_obj_alloc(rb_cIO);
+ MakeOpenFile(master_io, master_fptr);
+ master_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX;
+ master_fptr->fd = master_fd;
+ master_fptr->pathv = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
- VALUE slave_path = rb_obj_freeze(rb_str_new_cstr(slavename));
- VALUE slave_file = rb_io_open_descriptor(rb_cFile, slave_fd, FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY, slave_path, RUBY_IO_TIMEOUT_DEFAULT, NULL);
-
- VALUE assoc = rb_assoc_new(master_io, slave_file);
+ slave_file = rb_obj_alloc(rb_cFile);
+ MakeOpenFile(slave_file, slave_fptr);
+ slave_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY;
+ slave_fptr->fd = slave_fd;
+ slave_fptr->pathv = rb_obj_freeze(rb_str_new_cstr(slavename));
+ assoc = rb_assoc_new(master_io, slave_file);
if (rb_block_given_p()) {
return rb_ensure(rb_yield, assoc, pty_close_pty, assoc);
}
-
return assoc;
}
@@ -610,17 +553,9 @@ pty_detach_process(VALUE v)
* +env+ is an optional hash that provides additional environment variables to the spawned pty.
*
* # sets FOO to "bar"
- * PTY.spawn({"FOO"=>"bar"}, "printenv", "FOO") do |r, w, pid|
- * p r.read #=> "bar\r\n"
- * ensure
- * r.close; w.close; Process.wait(pid)
- * end
+ * PTY.spawn({"FOO"=>"bar"}, "printenv", "FOO") { |r,w,pid| p r.read } #=> "bar\r\n"
* # unsets FOO
- * PTY.spawn({"FOO"=>nil}, "printenv", "FOO") do |r, w, pid|
- * p r.read #=> ""
- * ensure
- * r.close; w.close; Process.wait(pid)
- * end
+ * PTY.spawn({"FOO"=>nil}, "printenv", "FOO") { |r,w,pid| p r.read } #=> ""
*
* +command+ and +command_line+ are the full commands to run, given a String.
* Any additional +arguments+ will be passed to the command.
@@ -636,42 +571,36 @@ pty_detach_process(VALUE v)
* standard output and standard error
* +w+:: A writable IO that is the command's standard input
* +pid+:: The process identifier for the command.
- *
- * === Clean up
- *
- * This method does not clean up like closing IOs or waiting for child
- * process, except that the process is detached in the block form to
- * prevent it from becoming a zombie (see Process.detach). Any other
- * cleanup is the responsibility of the caller. If waiting for +pid+,
- * be sure to close both +r+ and +w+ before doing so; doing it in the
- * reverse order may cause deadlock on some OSes.
*/
static VALUE
pty_getpty(int argc, VALUE *argv, VALUE self)
{
VALUE res;
struct pty_info info;
+ rb_io_t *wfptr,*rfptr;
+ VALUE rport = rb_obj_alloc(rb_cFile);
+ VALUE wport = rb_obj_alloc(rb_cFile);
char SlaveName[DEVICELEN];
+ MakeOpenFile(rport, rfptr);
+ MakeOpenFile(wport, wfptr);
+
establishShell(argc, argv, &info, SlaveName);
- VALUE pty_path = rb_obj_freeze(rb_str_new_cstr(SlaveName));
- VALUE rport = rb_io_open_descriptor(
- rb_cFile, info.fd, FMODE_READABLE, pty_path, RUBY_IO_TIMEOUT_DEFAULT, NULL
- );
+ rfptr->mode = rb_io_modestr_fmode("r");
+ rfptr->fd = info.fd;
+ rfptr->pathv = rb_obj_freeze(rb_str_new_cstr(SlaveName));
- int wpty_fd = rb_cloexec_dup(info.fd);
- if (wpty_fd == -1) {
+ wfptr->mode = rb_io_modestr_fmode("w") | FMODE_SYNC;
+ wfptr->fd = rb_cloexec_dup(info.fd);
+ if (wfptr->fd == -1)
rb_sys_fail("dup()");
- }
- VALUE wport = rb_io_open_descriptor(
- rb_cFile, wpty_fd, FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE | FMODE_SYNC,
- pty_path, RUBY_IO_TIMEOUT_DEFAULT, NULL
- );
+ rb_update_max_fd(wfptr->fd);
+ wfptr->pathv = rfptr->pathv;
res = rb_ary_new2(3);
- rb_ary_store(res, 0, rport);
- rb_ary_store(res, 1, wport);
+ rb_ary_store(res,0,(VALUE)rport);
+ rb_ary_store(res,1,(VALUE)wport);
rb_ary_store(res,2,PIDT2NUM(info.child_pid));
if (rb_block_given_p()) {
@@ -824,13 +753,8 @@ void
Init_pty(void)
{
cPTY = rb_define_module("PTY");
-#if 1
- rb_define_module_function(cPTY,"get""pty",pty_getpty,-1);
-#else /* for RDoc */
- /* show getpty as an alias of spawn */
- VALUE sPTY = rb_singleton_class(cPTY);
- rb_define_alias(sPTY, "getpty", "spawn");
-#endif
+ /* :nodoc: */
+ rb_define_module_function(cPTY,"getpty",pty_getpty,-1);
rb_define_module_function(cPTY,"spawn",pty_getpty,-1);
rb_define_singleton_method(cPTY,"check",pty_check,-1);
rb_define_singleton_method(cPTY,"open",pty_open,0);
diff --git a/ext/racc/cparse/README b/ext/racc/cparse/README
new file mode 100644
index 0000000000..550e8d49fe
--- /dev/null
+++ b/ext/racc/cparse/README
@@ -0,0 +1,11 @@
+Racc Runtime README
+===================
+
+This directory contains a runtime library of
+Racc parser generator. If you want to generate
+your own parser, you must get Racc full package.
+Get it from:
+
+ - http://i.loveruby.net/en/projects/racc
+ - https://github.com/ruby/racc
+
diff --git a/ext/racc/cparse/cparse.c b/ext/racc/cparse/cparse.c
new file mode 100644
index 0000000000..f752eb7749
--- /dev/null
+++ b/ext/racc/cparse/cparse.c
@@ -0,0 +1,861 @@
+/*
+
+ cparse.c -- Racc Runtime Core
+
+ Copyright (c) 1999-2006 Minero Aoki
+
+ This library is free software.
+ You can distribute/modify this program under the same terms of ruby.
+
+*/
+
+#include <ruby.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+/* -----------------------------------------------------------------------
+ Important Constants
+----------------------------------------------------------------------- */
+
+#define RACC_VERSION "1.6.2"
+
+#define DEFAULT_TOKEN -1
+#define ERROR_TOKEN 1
+#define FINAL_TOKEN 0
+
+#define vDEFAULT_TOKEN INT2FIX(DEFAULT_TOKEN)
+#define vERROR_TOKEN INT2FIX(ERROR_TOKEN)
+#define vFINAL_TOKEN INT2FIX(FINAL_TOKEN)
+
+/* -----------------------------------------------------------------------
+ File Local Variables
+----------------------------------------------------------------------- */
+
+static VALUE RaccBug;
+static VALUE CparseParams;
+
+static ID id_yydebug;
+static ID id_nexttoken;
+static ID id_onerror;
+static ID id_noreduce;
+static ID id_errstatus;
+
+static ID id_d_shift;
+static ID id_d_reduce;
+static ID id_d_accept;
+static ID id_d_read_token;
+static ID id_d_next_state;
+static ID id_d_e_pop;
+
+/* -----------------------------------------------------------------------
+ Utils
+----------------------------------------------------------------------- */
+
+/* For backward compatibility */
+#ifndef ID2SYM
+# define ID2SYM(i) ULONG2NUM(i)
+#endif
+#ifndef SYM2ID
+# define SYM2ID(v) ((ID)NUM2ULONG(v))
+#endif
+#ifndef SYMBOL_P
+# define SYMBOL_P(v) FIXNUM_P(v)
+#endif
+#ifndef LONG2NUM
+# define LONG2NUM(i) INT2NUM(i)
+#endif
+
+#ifndef HAVE_RB_ARY_SUBSEQ
+# define rb_ary_subseq(ary, beg, len) rb_ary_new4(len, RARRAY_PTR(ary) + beg)
+#endif
+
+static ID value_to_id _((VALUE v));
+static inline long num_to_long _((VALUE n));
+
+static ID
+value_to_id(VALUE v)
+{
+ if (! SYMBOL_P(v)) {
+ rb_raise(rb_eTypeError, "not symbol");
+ }
+ return SYM2ID(v);
+}
+
+static inline long
+num_to_long(VALUE n)
+{
+ return NUM2LONG(n);
+}
+
+#define AREF(s, idx) \
+ ((0 <= idx && idx < RARRAY_LEN(s)) ? rb_ary_entry(s, idx) : Qnil)
+
+/* -----------------------------------------------------------------------
+ Parser Stack Interfaces
+----------------------------------------------------------------------- */
+
+static VALUE get_stack_tail _((VALUE stack, long len));
+static void cut_stack_tail _((VALUE stack, long len));
+
+static VALUE
+get_stack_tail(VALUE stack, long len)
+{
+ if (len < 0) return Qnil; /* system error */
+ if (len > RARRAY_LEN(stack)) len = RARRAY_LEN(stack);
+ return rb_ary_subseq(stack, RARRAY_LEN(stack) - len, len);
+}
+
+static void
+cut_stack_tail(VALUE stack, long len)
+{
+ while (len > 0) {
+ rb_ary_pop(stack);
+ len--;
+ }
+}
+
+#define STACK_INIT_LEN 64
+#define NEW_STACK() rb_ary_new2(STACK_INIT_LEN)
+#define PUSH(s, i) rb_ary_store(s, RARRAY_LEN(s), i)
+#define POP(s) rb_ary_pop(s)
+#define LAST_I(s) \
+ ((RARRAY_LEN(s) > 0) ? rb_ary_entry(s, RARRAY_LEN(s) - 1) : Qnil)
+#define GET_TAIL(s, len) get_stack_tail(s, len)
+#define CUT_TAIL(s, len) cut_stack_tail(s, len)
+
+/* -----------------------------------------------------------------------
+ struct cparse_params
+----------------------------------------------------------------------- */
+
+struct cparse_params {
+ VALUE value_v; /* VALUE version of this struct */
+
+ VALUE parser; /* parser object */
+
+ int lex_is_iterator;
+ VALUE lexer; /* scanner object */
+ ID lexmid; /* name of scanner method (must be an iterator) */
+
+ /* State transition tables (immutable)
+ Data structure is from Dragon Book 4.9 */
+ /* action table */
+ VALUE action_table;
+ VALUE action_check;
+ VALUE action_default;
+ VALUE action_pointer;
+ /* goto table */
+ VALUE goto_table;
+ VALUE goto_check;
+ VALUE goto_default;
+ VALUE goto_pointer;
+
+ long nt_base; /* NonTerminal BASE index */
+ VALUE reduce_table; /* reduce data table */
+ VALUE token_table; /* token conversion table */
+
+ /* parser stacks and parameters */
+ VALUE state;
+ long curstate;
+ VALUE vstack;
+ VALUE tstack;
+ VALUE t;
+ long shift_n;
+ long reduce_n;
+ long ruleno;
+
+ long errstatus; /* nonzero in error recovering mode */
+ long nerr; /* number of error */
+
+ int use_result_var;
+
+ VALUE retval; /* return value of parser routine */
+ long fin; /* parse result status */
+#define CP_FIN_ACCEPT 1
+#define CP_FIN_EOT 2
+#define CP_FIN_CANTPOP 3
+
+ int debug; /* user level debug */
+ int sys_debug; /* system level debug */
+
+ long i; /* table index */
+};
+
+/* -----------------------------------------------------------------------
+ Parser Main Routines
+----------------------------------------------------------------------- */
+
+static VALUE racc_cparse _((VALUE parser, VALUE arg, VALUE sysdebug));
+static VALUE racc_yyparse _((VALUE parser, VALUE lexer, VALUE lexmid,
+ VALUE arg, VALUE sysdebug));
+
+static void call_lexer _((struct cparse_params *v));
+static VALUE lexer_i _((RB_BLOCK_CALL_FUNC_ARGLIST(block_args, data)));
+
+static VALUE assert_array _((VALUE a));
+static long assert_integer _((VALUE n));
+static VALUE assert_hash _((VALUE h));
+static VALUE initialize_params _((VALUE vparams, VALUE parser, VALUE arg,
+ VALUE lexer, VALUE lexmid));
+static void cparse_params_mark _((void *ptr));
+static size_t cparse_params_memsize _((const void *ptr));
+
+static void parse_main _((struct cparse_params *v,
+ VALUE tok, VALUE val, int resume));
+static void extract_user_token _((struct cparse_params *v,
+ VALUE block_args, VALUE *tok, VALUE *val));
+static void shift _((struct cparse_params* v, long act, VALUE tok, VALUE val));
+static int reduce _((struct cparse_params* v, long act));
+static rb_block_call_func reduce0;
+
+#ifdef DEBUG
+# define D_puts(msg) if (v->sys_debug) puts(msg)
+# define D_printf(fmt,arg) if (v->sys_debug) printf(fmt,arg)
+#else
+# define D_puts(msg)
+# define D_printf(fmt,arg)
+#endif
+
+#undef RUBY_UNTYPED_DATA_WARNING
+#define RUBY_UNTYPED_DATA_WARNING 1
+
+static const rb_data_type_t cparse_params_type = {
+ "racc/cparse",
+ {
+ cparse_params_mark,
+ RUBY_TYPED_DEFAULT_FREE,
+ cparse_params_memsize,
+ },
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
+ 0, 0,
+ RUBY_TYPED_FREE_IMMEDIATELY,
+#endif
+};
+
+static VALUE
+racc_cparse(VALUE parser, VALUE arg, VALUE sysdebug)
+{
+ VALUE vparams;
+ struct cparse_params *v;
+
+ vparams = TypedData_Make_Struct(CparseParams, struct cparse_params,
+ &cparse_params_type, v);
+ D_puts("starting cparse");
+ v->sys_debug = RTEST(sysdebug);
+ vparams = initialize_params(vparams, parser, arg, Qnil, Qnil);
+ v->lex_is_iterator = FALSE;
+ parse_main(v, Qnil, Qnil, 0);
+
+ RB_GC_GUARD(vparams);
+ return v->retval;
+}
+
+static VALUE
+racc_yyparse(VALUE parser, VALUE lexer, VALUE lexmid, VALUE arg, VALUE sysdebug)
+{
+ VALUE vparams;
+ struct cparse_params *v;
+
+ vparams = TypedData_Make_Struct(CparseParams, struct cparse_params,
+ &cparse_params_type, v);
+ v->sys_debug = RTEST(sysdebug);
+ D_puts("start C yyparse");
+ vparams = initialize_params(vparams, parser, arg, lexer, lexmid);
+ v->lex_is_iterator = TRUE;
+ D_puts("params initialized");
+ parse_main(v, Qnil, Qnil, 0);
+ call_lexer(v);
+ if (!v->fin) {
+ rb_raise(rb_eArgError, "%s() is finished before EndOfToken",
+ rb_id2name(v->lexmid));
+ }
+
+ RB_GC_GUARD(vparams);
+ return v->retval;
+}
+
+#ifdef HAVE_RB_BLOCK_CALL
+static void
+call_lexer(struct cparse_params *v)
+{
+ rb_block_call(v->lexer, v->lexmid, 0, NULL, lexer_i, v->value_v);
+}
+#else
+static VALUE
+lexer_iter(VALUE data)
+{
+ struct cparse_params *v = rb_check_typeddata(data, &cparse_params_type);
+
+ rb_funcall(v->lexer, v->lexmid, 0);
+ return Qnil;
+}
+
+static void
+call_lexer(struct cparse_params *v)
+{
+ rb_iterate(lexer_iter, v->value_v, lexer_i, v->value_v);
+}
+#endif
+
+static VALUE
+lexer_i(RB_BLOCK_CALL_FUNC_ARGLIST(block_args, data))
+{
+ struct cparse_params *v = rb_check_typeddata(data, &cparse_params_type);
+ VALUE tok, val;
+
+ if (v->fin)
+ rb_raise(rb_eArgError, "extra token after EndOfToken");
+ extract_user_token(v, block_args, &tok, &val);
+ parse_main(v, tok, val, 1);
+ if (v->fin && v->fin != CP_FIN_ACCEPT)
+ rb_iter_break();
+ return Qnil;
+}
+
+static VALUE
+assert_array(VALUE a)
+{
+ Check_Type(a, T_ARRAY);
+ return a;
+}
+
+static VALUE
+assert_hash(VALUE h)
+{
+ Check_Type(h, T_HASH);
+ return h;
+}
+
+static long
+assert_integer(VALUE n)
+{
+ return NUM2LONG(n);
+}
+
+static VALUE
+initialize_params(VALUE vparams, VALUE parser, VALUE arg, VALUE lexer, VALUE lexmid)
+{
+ struct cparse_params *v = rb_check_typeddata(vparams, &cparse_params_type);
+
+ v->value_v = vparams;
+ v->parser = parser;
+ v->lexer = lexer;
+ if (! NIL_P(lexmid))
+ v->lexmid = value_to_id(lexmid);
+
+ v->debug = RTEST(rb_ivar_get(parser, id_yydebug));
+
+ Check_Type(arg, T_ARRAY);
+ if (!(13 <= RARRAY_LEN(arg) && RARRAY_LEN(arg) <= 14))
+ rb_raise(RaccBug, "[Racc Bug] wrong arg.size %ld", RARRAY_LEN(arg));
+ v->action_table = assert_array (rb_ary_entry(arg, 0));
+ v->action_check = assert_array (rb_ary_entry(arg, 1));
+ v->action_default = assert_array (rb_ary_entry(arg, 2));
+ v->action_pointer = assert_array (rb_ary_entry(arg, 3));
+ v->goto_table = assert_array (rb_ary_entry(arg, 4));
+ v->goto_check = assert_array (rb_ary_entry(arg, 5));
+ v->goto_default = assert_array (rb_ary_entry(arg, 6));
+ v->goto_pointer = assert_array (rb_ary_entry(arg, 7));
+ v->nt_base = assert_integer(rb_ary_entry(arg, 8));
+ v->reduce_table = assert_array (rb_ary_entry(arg, 9));
+ v->token_table = assert_hash (rb_ary_entry(arg, 10));
+ v->shift_n = assert_integer(rb_ary_entry(arg, 11));
+ v->reduce_n = assert_integer(rb_ary_entry(arg, 12));
+ if (RARRAY_LEN(arg) > 13) {
+ v->use_result_var = RTEST(rb_ary_entry(arg, 13));
+ }
+ else {
+ v->use_result_var = TRUE;
+ }
+
+ v->tstack = v->debug ? NEW_STACK() : Qnil;
+ v->vstack = NEW_STACK();
+ v->state = NEW_STACK();
+ v->curstate = 0;
+ PUSH(v->state, INT2FIX(0));
+ v->t = INT2FIX(FINAL_TOKEN + 1); /* must not init to FINAL_TOKEN */
+ v->nerr = 0;
+ v->errstatus = 0;
+ rb_ivar_set(parser, id_errstatus, LONG2NUM(v->errstatus));
+
+ v->retval = Qnil;
+ v->fin = 0;
+
+ v->lex_is_iterator = FALSE;
+
+ rb_iv_set(parser, "@vstack", v->vstack);
+ if (v->debug) {
+ rb_iv_set(parser, "@tstack", v->tstack);
+ }
+ else {
+ rb_iv_set(parser, "@tstack", Qnil);
+ }
+
+ return vparams;
+}
+
+static void
+cparse_params_mark(void *ptr)
+{
+ struct cparse_params *v = (struct cparse_params*)ptr;
+
+ rb_gc_mark(v->value_v);
+ rb_gc_mark(v->parser);
+ rb_gc_mark(v->lexer);
+ rb_gc_mark(v->action_table);
+ rb_gc_mark(v->action_check);
+ rb_gc_mark(v->action_default);
+ rb_gc_mark(v->action_pointer);
+ rb_gc_mark(v->goto_table);
+ rb_gc_mark(v->goto_check);
+ rb_gc_mark(v->goto_default);
+ rb_gc_mark(v->goto_pointer);
+ rb_gc_mark(v->reduce_table);
+ rb_gc_mark(v->token_table);
+ rb_gc_mark(v->state);
+ rb_gc_mark(v->vstack);
+ rb_gc_mark(v->tstack);
+ rb_gc_mark(v->t);
+ rb_gc_mark(v->retval);
+}
+
+static size_t
+cparse_params_memsize(const void *ptr)
+{
+ return sizeof(struct cparse_params);
+}
+
+static void
+extract_user_token(struct cparse_params *v, VALUE block_args,
+ VALUE *tok, VALUE *val)
+{
+ if (NIL_P(block_args)) {
+ /* EOF */
+ *tok = Qfalse;
+ *val = rb_str_new("$", 1);
+ return;
+ }
+
+ if (!RB_TYPE_P(block_args, T_ARRAY)) {
+ rb_raise(rb_eTypeError,
+ "%s() %s %"PRIsVALUE" (must be Array[2])",
+ v->lex_is_iterator ? rb_id2name(v->lexmid) : "next_token",
+ v->lex_is_iterator ? "yielded" : "returned",
+ rb_obj_class(block_args));
+ }
+ if (RARRAY_LEN(block_args) != 2) {
+ rb_raise(rb_eArgError,
+ "%s() %s wrong size of array (%ld for 2)",
+ v->lex_is_iterator ? rb_id2name(v->lexmid) : "next_token",
+ v->lex_is_iterator ? "yielded" : "returned",
+ RARRAY_LEN(block_args));
+ }
+ *tok = AREF(block_args, 0);
+ *val = AREF(block_args, 1);
+}
+
+#define SHIFT(v,act,tok,val) shift(v,act,tok,val)
+#define REDUCE(v,act) do {\
+ switch (reduce(v,act)) { \
+ case 0: /* normal */ \
+ break; \
+ case 1: /* yyerror */ \
+ goto user_yyerror; \
+ case 2: /* yyaccept */ \
+ D_puts("u accept"); \
+ goto accept; \
+ default: \
+ break; \
+ } \
+} while (0)
+
+static void
+parse_main(struct cparse_params *v, VALUE tok, VALUE val, int resume)
+{
+ long i; /* table index */
+ long act; /* action type */
+ VALUE act_value; /* action type, VALUE version */
+ int read_next = 1; /* true if we need to read next token */
+ VALUE tmp;
+
+ if (resume)
+ goto resume;
+
+ while (1) {
+ D_puts("");
+ D_puts("---- enter new loop ----");
+ D_puts("");
+
+ D_printf("(act) k1=%ld\n", v->curstate);
+ tmp = AREF(v->action_pointer, v->curstate);
+ if (NIL_P(tmp)) goto notfound;
+ D_puts("(act) pointer[k1] ok");
+ i = NUM2LONG(tmp);
+
+ D_printf("read_next=%d\n", read_next);
+ if (read_next && (v->t != vFINAL_TOKEN)) {
+ if (v->lex_is_iterator) {
+ D_puts("resuming...");
+ if (v->fin) rb_raise(rb_eArgError, "token given after EOF");
+ v->i = i; /* save i */
+ return;
+ resume:
+ D_puts("resumed");
+ i = v->i; /* load i */
+ }
+ else {
+ D_puts("next_token");
+ tmp = rb_funcall(v->parser, id_nexttoken, 0);
+ extract_user_token(v, tmp, &tok, &val);
+ }
+ /* convert token */
+ v->t = rb_hash_aref(v->token_table, tok);
+ if (NIL_P(v->t)) {
+ v->t = vERROR_TOKEN;
+ }
+ D_printf("(act) t(k2)=%ld\n", NUM2LONG(v->t));
+ if (v->debug) {
+ rb_funcall(v->parser, id_d_read_token,
+ 3, v->t, tok, val);
+ }
+ }
+ read_next = 0;
+
+ i += NUM2LONG(v->t);
+ D_printf("(act) i=%ld\n", i);
+ if (i < 0) goto notfound;
+
+ act_value = AREF(v->action_table, i);
+ if (NIL_P(act_value)) goto notfound;
+ act = NUM2LONG(act_value);
+ D_printf("(act) table[i]=%ld\n", act);
+
+ tmp = AREF(v->action_check, i);
+ if (NIL_P(tmp)) goto notfound;
+ if (NUM2LONG(tmp) != v->curstate) goto notfound;
+ D_printf("(act) check[i]=%ld\n", NUM2LONG(tmp));
+
+ D_puts("(act) found");
+ act_fixed:
+ D_printf("act=%ld\n", act);
+ goto handle_act;
+
+ notfound:
+ D_puts("(act) not found: use default");
+ act_value = AREF(v->action_default, v->curstate);
+ act = NUM2LONG(act_value);
+ goto act_fixed;
+
+
+ handle_act:
+ if (act > 0 && act < v->shift_n) {
+ D_puts("shift");
+ if (v->errstatus > 0) {
+ v->errstatus--;
+ rb_ivar_set(v->parser, id_errstatus, LONG2NUM(v->errstatus));
+ }
+ SHIFT(v, act, v->t, val);
+ read_next = 1;
+ }
+ else if (act < 0 && act > -(v->reduce_n)) {
+ D_puts("reduce");
+ REDUCE(v, act);
+ }
+ else if (act == -(v->reduce_n)) {
+ goto error;
+ error_recovered:
+ ; /* goto label requires stmt */
+ }
+ else if (act == v->shift_n) {
+ D_puts("accept");
+ goto accept;
+ }
+ else {
+ rb_raise(RaccBug, "[Racc Bug] unknown act value %ld", act);
+ }
+
+ if (v->debug) {
+ rb_funcall(v->parser, id_d_next_state,
+ 2, LONG2NUM(v->curstate), v->state);
+ }
+ }
+ /* not reach */
+
+
+ accept:
+ if (v->debug) rb_funcall(v->parser, id_d_accept, 0);
+ v->retval = rb_ary_entry(v->vstack, 0);
+ v->fin = CP_FIN_ACCEPT;
+ return;
+
+
+ error:
+ D_printf("error detected, status=%ld\n", v->errstatus);
+ if (v->errstatus == 0) {
+ v->nerr++;
+ rb_funcall(v->parser, id_onerror,
+ 3, v->t, val, v->vstack);
+ }
+ user_yyerror:
+ if (v->errstatus == 3) {
+ if (v->t == vFINAL_TOKEN) {
+ v->retval = Qnil;
+ v->fin = CP_FIN_EOT;
+ return;
+ }
+ read_next = 1;
+ }
+ v->errstatus = 3;
+ rb_ivar_set(v->parser, id_errstatus, LONG2NUM(v->errstatus));
+
+ /* check if we can shift/reduce error token */
+ D_printf("(err) k1=%ld\n", v->curstate);
+ D_printf("(err) k2=%d (error)\n", ERROR_TOKEN);
+ while (1) {
+ tmp = AREF(v->action_pointer, v->curstate);
+ if (NIL_P(tmp)) goto error_pop;
+ D_puts("(err) pointer[k1] ok");
+
+ i = NUM2LONG(tmp) + ERROR_TOKEN;
+ D_printf("(err) i=%ld\n", i);
+ if (i < 0) goto error_pop;
+
+ act_value = AREF(v->action_table, i);
+ if (NIL_P(act_value)) {
+ D_puts("(err) table[i] == nil");
+ goto error_pop;
+ }
+ act = NUM2LONG(act_value);
+ D_printf("(err) table[i]=%ld\n", act);
+
+ tmp = AREF(v->action_check, i);
+ if (NIL_P(tmp)) {
+ D_puts("(err) check[i] == nil");
+ goto error_pop;
+ }
+ if (NUM2LONG(tmp) != v->curstate) {
+ D_puts("(err) check[i] != k1");
+ goto error_pop;
+ }
+
+ D_puts("(err) found: can handle error token");
+ break;
+
+ error_pop:
+ D_puts("(err) act not found: can't handle error token; pop");
+
+ if (RARRAY_LEN(v->state) <= 1) {
+ v->retval = Qnil;
+ v->fin = CP_FIN_CANTPOP;
+ return;
+ }
+ POP(v->state);
+ POP(v->vstack);
+ v->curstate = num_to_long(LAST_I(v->state));
+ if (v->debug) {
+ POP(v->tstack);
+ rb_funcall(v->parser, id_d_e_pop,
+ 3, v->state, v->tstack, v->vstack);
+ }
+ }
+
+ /* shift/reduce error token */
+ if (act > 0 && act < v->shift_n) {
+ D_puts("e shift");
+ SHIFT(v, act, ERROR_TOKEN, val);
+ }
+ else if (act < 0 && act > -(v->reduce_n)) {
+ D_puts("e reduce");
+ REDUCE(v, act);
+ }
+ else if (act == v->shift_n) {
+ D_puts("e accept");
+ goto accept;
+ }
+ else {
+ rb_raise(RaccBug, "[Racc Bug] unknown act value %ld", act);
+ }
+ goto error_recovered;
+}
+
+static void
+shift(struct cparse_params *v, long act, VALUE tok, VALUE val)
+{
+ PUSH(v->vstack, val);
+ if (v->debug) {
+ PUSH(v->tstack, tok);
+ rb_funcall(v->parser, id_d_shift,
+ 3, tok, v->tstack, v->vstack);
+ }
+ v->curstate = act;
+ PUSH(v->state, LONG2NUM(v->curstate));
+}
+
+static int
+reduce(struct cparse_params *v, long act)
+{
+ VALUE code;
+ v->ruleno = -act * 3;
+ code = rb_catch("racc_jump", reduce0, v->value_v);
+ v->errstatus = num_to_long(rb_ivar_get(v->parser, id_errstatus));
+ return NUM2INT(code);
+}
+
+static VALUE
+reduce0(RB_BLOCK_CALL_FUNC_ARGLIST(_, data))
+{
+ struct cparse_params *v = rb_check_typeddata(data, &cparse_params_type);
+ VALUE reduce_to, reduce_len, method_id;
+ long len;
+ ID mid;
+ VALUE tmp, tmp_t = Qundef, tmp_v = Qundef;
+ long i, k1, k2;
+ VALUE goto_state;
+
+ reduce_len = rb_ary_entry(v->reduce_table, v->ruleno);
+ reduce_to = rb_ary_entry(v->reduce_table, v->ruleno+1);
+ method_id = rb_ary_entry(v->reduce_table, v->ruleno+2);
+ len = NUM2LONG(reduce_len);
+ mid = value_to_id(method_id);
+
+ /* call action */
+ if (len == 0) {
+ tmp = Qnil;
+ if (mid != id_noreduce)
+ tmp_v = rb_ary_new();
+ if (v->debug)
+ tmp_t = rb_ary_new();
+ }
+ else {
+ if (mid != id_noreduce) {
+ tmp_v = GET_TAIL(v->vstack, len);
+ tmp = rb_ary_entry(tmp_v, 0);
+ }
+ else {
+ tmp = rb_ary_entry(v->vstack, RARRAY_LEN(v->vstack) - len);
+ }
+ CUT_TAIL(v->vstack, len);
+ if (v->debug) {
+ tmp_t = GET_TAIL(v->tstack, len);
+ CUT_TAIL(v->tstack, len);
+ }
+ CUT_TAIL(v->state, len);
+ }
+ if (mid != id_noreduce) {
+ if (v->use_result_var) {
+ tmp = rb_funcall(v->parser, mid,
+ 3, tmp_v, v->vstack, tmp);
+ }
+ else {
+ tmp = rb_funcall(v->parser, mid,
+ 2, tmp_v, v->vstack);
+ }
+ }
+
+ /* then push result */
+ PUSH(v->vstack, tmp);
+ if (v->debug) {
+ PUSH(v->tstack, reduce_to);
+ rb_funcall(v->parser, id_d_reduce,
+ 4, tmp_t, reduce_to, v->tstack, v->vstack);
+ }
+
+ /* calculate transition state */
+ if (RARRAY_LEN(v->state) == 0)
+ rb_raise(RaccBug, "state stack unexpectedly empty");
+ k2 = num_to_long(LAST_I(v->state));
+ k1 = num_to_long(reduce_to) - v->nt_base;
+ D_printf("(goto) k1=%ld\n", k1);
+ D_printf("(goto) k2=%ld\n", k2);
+
+ tmp = AREF(v->goto_pointer, k1);
+ if (NIL_P(tmp)) goto notfound;
+
+ i = NUM2LONG(tmp) + k2;
+ D_printf("(goto) i=%ld\n", i);
+ if (i < 0) goto notfound;
+
+ goto_state = AREF(v->goto_table, i);
+ if (NIL_P(goto_state)) {
+ D_puts("(goto) table[i] == nil");
+ goto notfound;
+ }
+ D_printf("(goto) table[i]=%ld (goto_state)\n", NUM2LONG(goto_state));
+
+ tmp = AREF(v->goto_check, i);
+ if (NIL_P(tmp)) {
+ D_puts("(goto) check[i] == nil");
+ goto notfound;
+ }
+ if (tmp != LONG2NUM(k1)) {
+ D_puts("(goto) check[i] != table[i]");
+ goto notfound;
+ }
+ D_printf("(goto) check[i]=%ld\n", NUM2LONG(tmp));
+
+ D_puts("(goto) found");
+ transit:
+ PUSH(v->state, goto_state);
+ v->curstate = NUM2LONG(goto_state);
+ return INT2FIX(0);
+
+ notfound:
+ D_puts("(goto) not found: use default");
+ /* overwrite `goto-state' by default value */
+ goto_state = AREF(v->goto_default, k1);
+ goto transit;
+}
+
+/* -----------------------------------------------------------------------
+ Ruby Interface
+----------------------------------------------------------------------- */
+
+void
+Init_cparse(void)
+{
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
+ rb_ext_ractor_safe(true);
+#endif
+
+ VALUE Racc, Parser;
+ ID id_racc = rb_intern_const("Racc");
+
+ if (rb_const_defined(rb_cObject, id_racc)) {
+ Racc = rb_const_get(rb_cObject, id_racc);
+ Parser = rb_const_get_at(Racc, rb_intern_const("Parser"));
+ }
+ else {
+ Racc = rb_define_module("Racc");
+ Parser = rb_define_class_under(Racc, "Parser", rb_cObject);
+ }
+ rb_define_private_method(Parser, "_racc_do_parse_c", racc_cparse, 2);
+ rb_define_private_method(Parser, "_racc_yyparse_c", racc_yyparse, 4);
+ rb_define_const(Parser, "Racc_Runtime_Core_Version_C",
+ rb_str_new2(RACC_VERSION));
+ rb_define_const(Parser, "Racc_Runtime_Core_Id_C",
+ rb_str_new2("$originalId: cparse.c,v 1.8 2006/07/06 11:39:46 aamine Exp $"));
+
+ CparseParams = rb_define_class_under(Racc, "CparseParams", rb_cObject);
+ rb_undef_alloc_func(CparseParams);
+ rb_undef_method(CparseParams, "initialize");
+ rb_undef_method(CparseParams, "initialize_copy");
+
+ RaccBug = rb_eRuntimeError;
+
+ id_yydebug = rb_intern_const("@yydebug");
+ id_nexttoken = rb_intern_const("next_token");
+ id_onerror = rb_intern_const("on_error");
+ id_noreduce = rb_intern_const("_reduce_none");
+ id_errstatus = rb_intern_const("@racc_error_status");
+
+ id_d_shift = rb_intern_const("racc_shift");
+ id_d_reduce = rb_intern_const("racc_reduce");
+ id_d_accept = rb_intern_const("racc_accept");
+ id_d_read_token = rb_intern_const("racc_read_token");
+ id_d_next_state = rb_intern_const("racc_next_state");
+ id_d_e_pop = rb_intern_const("racc_e_pop");
+}
diff --git a/ext/racc/cparse/depend b/ext/racc/cparse/depend
new file mode 100644
index 0000000000..9dc509dc7c
--- /dev/null
+++ b/ext/racc/cparse/depend
@@ -0,0 +1,162 @@
+# AUTOGENERATED DEPENDENCIES START
+cparse.o: $(RUBY_EXTCONF_H)
+cparse.o: $(arch_hdrdir)/ruby/config.h
+cparse.o: $(hdrdir)/ruby.h
+cparse.o: $(hdrdir)/ruby/assert.h
+cparse.o: $(hdrdir)/ruby/backward.h
+cparse.o: $(hdrdir)/ruby/backward/2/assume.h
+cparse.o: $(hdrdir)/ruby/backward/2/attributes.h
+cparse.o: $(hdrdir)/ruby/backward/2/bool.h
+cparse.o: $(hdrdir)/ruby/backward/2/inttypes.h
+cparse.o: $(hdrdir)/ruby/backward/2/limits.h
+cparse.o: $(hdrdir)/ruby/backward/2/long_long.h
+cparse.o: $(hdrdir)/ruby/backward/2/stdalign.h
+cparse.o: $(hdrdir)/ruby/backward/2/stdarg.h
+cparse.o: $(hdrdir)/ruby/defines.h
+cparse.o: $(hdrdir)/ruby/intern.h
+cparse.o: $(hdrdir)/ruby/internal/abi.h
+cparse.o: $(hdrdir)/ruby/internal/anyargs.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+cparse.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+cparse.o: $(hdrdir)/ruby/internal/assume.h
+cparse.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+cparse.o: $(hdrdir)/ruby/internal/attr/artificial.h
+cparse.o: $(hdrdir)/ruby/internal/attr/cold.h
+cparse.o: $(hdrdir)/ruby/internal/attr/const.h
+cparse.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+cparse.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+cparse.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+cparse.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+cparse.o: $(hdrdir)/ruby/internal/attr/error.h
+cparse.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+cparse.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+cparse.o: $(hdrdir)/ruby/internal/attr/format.h
+cparse.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+cparse.o: $(hdrdir)/ruby/internal/attr/noalias.h
+cparse.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+cparse.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+cparse.o: $(hdrdir)/ruby/internal/attr/noinline.h
+cparse.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+cparse.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+cparse.o: $(hdrdir)/ruby/internal/attr/pure.h
+cparse.o: $(hdrdir)/ruby/internal/attr/restrict.h
+cparse.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+cparse.o: $(hdrdir)/ruby/internal/attr/warning.h
+cparse.o: $(hdrdir)/ruby/internal/attr/weakref.h
+cparse.o: $(hdrdir)/ruby/internal/cast.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+cparse.o: $(hdrdir)/ruby/internal/compiler_since.h
+cparse.o: $(hdrdir)/ruby/internal/config.h
+cparse.o: $(hdrdir)/ruby/internal/constant_p.h
+cparse.o: $(hdrdir)/ruby/internal/core.h
+cparse.o: $(hdrdir)/ruby/internal/core/rarray.h
+cparse.o: $(hdrdir)/ruby/internal/core/rbasic.h
+cparse.o: $(hdrdir)/ruby/internal/core/rbignum.h
+cparse.o: $(hdrdir)/ruby/internal/core/rclass.h
+cparse.o: $(hdrdir)/ruby/internal/core/rdata.h
+cparse.o: $(hdrdir)/ruby/internal/core/rfile.h
+cparse.o: $(hdrdir)/ruby/internal/core/rhash.h
+cparse.o: $(hdrdir)/ruby/internal/core/robject.h
+cparse.o: $(hdrdir)/ruby/internal/core/rregexp.h
+cparse.o: $(hdrdir)/ruby/internal/core/rstring.h
+cparse.o: $(hdrdir)/ruby/internal/core/rstruct.h
+cparse.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+cparse.o: $(hdrdir)/ruby/internal/ctype.h
+cparse.o: $(hdrdir)/ruby/internal/dllexport.h
+cparse.o: $(hdrdir)/ruby/internal/dosish.h
+cparse.o: $(hdrdir)/ruby/internal/error.h
+cparse.o: $(hdrdir)/ruby/internal/eval.h
+cparse.o: $(hdrdir)/ruby/internal/event.h
+cparse.o: $(hdrdir)/ruby/internal/fl_type.h
+cparse.o: $(hdrdir)/ruby/internal/gc.h
+cparse.o: $(hdrdir)/ruby/internal/glob.h
+cparse.o: $(hdrdir)/ruby/internal/globals.h
+cparse.o: $(hdrdir)/ruby/internal/has/attribute.h
+cparse.o: $(hdrdir)/ruby/internal/has/builtin.h
+cparse.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+cparse.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+cparse.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+cparse.o: $(hdrdir)/ruby/internal/has/extension.h
+cparse.o: $(hdrdir)/ruby/internal/has/feature.h
+cparse.o: $(hdrdir)/ruby/internal/has/warning.h
+cparse.o: $(hdrdir)/ruby/internal/intern/array.h
+cparse.o: $(hdrdir)/ruby/internal/intern/bignum.h
+cparse.o: $(hdrdir)/ruby/internal/intern/class.h
+cparse.o: $(hdrdir)/ruby/internal/intern/compar.h
+cparse.o: $(hdrdir)/ruby/internal/intern/complex.h
+cparse.o: $(hdrdir)/ruby/internal/intern/cont.h
+cparse.o: $(hdrdir)/ruby/internal/intern/dir.h
+cparse.o: $(hdrdir)/ruby/internal/intern/enum.h
+cparse.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+cparse.o: $(hdrdir)/ruby/internal/intern/error.h
+cparse.o: $(hdrdir)/ruby/internal/intern/eval.h
+cparse.o: $(hdrdir)/ruby/internal/intern/file.h
+cparse.o: $(hdrdir)/ruby/internal/intern/gc.h
+cparse.o: $(hdrdir)/ruby/internal/intern/hash.h
+cparse.o: $(hdrdir)/ruby/internal/intern/io.h
+cparse.o: $(hdrdir)/ruby/internal/intern/load.h
+cparse.o: $(hdrdir)/ruby/internal/intern/marshal.h
+cparse.o: $(hdrdir)/ruby/internal/intern/numeric.h
+cparse.o: $(hdrdir)/ruby/internal/intern/object.h
+cparse.o: $(hdrdir)/ruby/internal/intern/parse.h
+cparse.o: $(hdrdir)/ruby/internal/intern/proc.h
+cparse.o: $(hdrdir)/ruby/internal/intern/process.h
+cparse.o: $(hdrdir)/ruby/internal/intern/random.h
+cparse.o: $(hdrdir)/ruby/internal/intern/range.h
+cparse.o: $(hdrdir)/ruby/internal/intern/rational.h
+cparse.o: $(hdrdir)/ruby/internal/intern/re.h
+cparse.o: $(hdrdir)/ruby/internal/intern/ruby.h
+cparse.o: $(hdrdir)/ruby/internal/intern/select.h
+cparse.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+cparse.o: $(hdrdir)/ruby/internal/intern/signal.h
+cparse.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+cparse.o: $(hdrdir)/ruby/internal/intern/string.h
+cparse.o: $(hdrdir)/ruby/internal/intern/struct.h
+cparse.o: $(hdrdir)/ruby/internal/intern/thread.h
+cparse.o: $(hdrdir)/ruby/internal/intern/time.h
+cparse.o: $(hdrdir)/ruby/internal/intern/variable.h
+cparse.o: $(hdrdir)/ruby/internal/intern/vm.h
+cparse.o: $(hdrdir)/ruby/internal/interpreter.h
+cparse.o: $(hdrdir)/ruby/internal/iterator.h
+cparse.o: $(hdrdir)/ruby/internal/memory.h
+cparse.o: $(hdrdir)/ruby/internal/method.h
+cparse.o: $(hdrdir)/ruby/internal/module.h
+cparse.o: $(hdrdir)/ruby/internal/newobj.h
+cparse.o: $(hdrdir)/ruby/internal/rgengc.h
+cparse.o: $(hdrdir)/ruby/internal/scan_args.h
+cparse.o: $(hdrdir)/ruby/internal/special_consts.h
+cparse.o: $(hdrdir)/ruby/internal/static_assert.h
+cparse.o: $(hdrdir)/ruby/internal/stdalign.h
+cparse.o: $(hdrdir)/ruby/internal/stdbool.h
+cparse.o: $(hdrdir)/ruby/internal/symbol.h
+cparse.o: $(hdrdir)/ruby/internal/value.h
+cparse.o: $(hdrdir)/ruby/internal/value_type.h
+cparse.o: $(hdrdir)/ruby/internal/variable.h
+cparse.o: $(hdrdir)/ruby/internal/warning_push.h
+cparse.o: $(hdrdir)/ruby/internal/xmalloc.h
+cparse.o: $(hdrdir)/ruby/missing.h
+cparse.o: $(hdrdir)/ruby/ruby.h
+cparse.o: $(hdrdir)/ruby/st.h
+cparse.o: $(hdrdir)/ruby/subst.h
+cparse.o: cparse.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/racc/cparse/extconf.rb b/ext/racc/cparse/extconf.rb
new file mode 100644
index 0000000000..18c5689ad8
--- /dev/null
+++ b/ext/racc/cparse/extconf.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: false
+#
+
+require 'mkmf'
+
+have_func('rb_block_call')
+have_func('rb_ary_subseq')
+
+create_makefile 'racc/cparse'
diff --git a/ext/rbconfig/sizeof/depend b/ext/rbconfig/sizeof/depend
index 5f75fa8c76..5b65b83772 100644
--- a/ext/rbconfig/sizeof/depend
+++ b/ext/rbconfig/sizeof/depend
@@ -66,7 +66,6 @@ limits.o: $(hdrdir)/ruby/internal/attr/noexcept.h
limits.o: $(hdrdir)/ruby/internal/attr/noinline.h
limits.o: $(hdrdir)/ruby/internal/attr/nonnull.h
limits.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-limits.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
limits.o: $(hdrdir)/ruby/internal/attr/pure.h
limits.o: $(hdrdir)/ruby/internal/attr/restrict.h
limits.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -126,6 +125,7 @@ limits.o: $(hdrdir)/ruby/internal/intern/enumerator.h
limits.o: $(hdrdir)/ruby/internal/intern/error.h
limits.o: $(hdrdir)/ruby/internal/intern/eval.h
limits.o: $(hdrdir)/ruby/internal/intern/file.h
+limits.o: $(hdrdir)/ruby/internal/intern/gc.h
limits.o: $(hdrdir)/ruby/internal/intern/hash.h
limits.o: $(hdrdir)/ruby/internal/intern/io.h
limits.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -156,12 +156,12 @@ limits.o: $(hdrdir)/ruby/internal/memory.h
limits.o: $(hdrdir)/ruby/internal/method.h
limits.o: $(hdrdir)/ruby/internal/module.h
limits.o: $(hdrdir)/ruby/internal/newobj.h
+limits.o: $(hdrdir)/ruby/internal/rgengc.h
limits.o: $(hdrdir)/ruby/internal/scan_args.h
limits.o: $(hdrdir)/ruby/internal/special_consts.h
limits.o: $(hdrdir)/ruby/internal/static_assert.h
limits.o: $(hdrdir)/ruby/internal/stdalign.h
limits.o: $(hdrdir)/ruby/internal/stdbool.h
-limits.o: $(hdrdir)/ruby/internal/stdckdint.h
limits.o: $(hdrdir)/ruby/internal/symbol.h
limits.o: $(hdrdir)/ruby/internal/value.h
limits.o: $(hdrdir)/ruby/internal/value_type.h
@@ -225,7 +225,6 @@ sizes.o: $(hdrdir)/ruby/internal/attr/noexcept.h
sizes.o: $(hdrdir)/ruby/internal/attr/noinline.h
sizes.o: $(hdrdir)/ruby/internal/attr/nonnull.h
sizes.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-sizes.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
sizes.o: $(hdrdir)/ruby/internal/attr/pure.h
sizes.o: $(hdrdir)/ruby/internal/attr/restrict.h
sizes.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -285,6 +284,7 @@ sizes.o: $(hdrdir)/ruby/internal/intern/enumerator.h
sizes.o: $(hdrdir)/ruby/internal/intern/error.h
sizes.o: $(hdrdir)/ruby/internal/intern/eval.h
sizes.o: $(hdrdir)/ruby/internal/intern/file.h
+sizes.o: $(hdrdir)/ruby/internal/intern/gc.h
sizes.o: $(hdrdir)/ruby/internal/intern/hash.h
sizes.o: $(hdrdir)/ruby/internal/intern/io.h
sizes.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -315,12 +315,12 @@ sizes.o: $(hdrdir)/ruby/internal/memory.h
sizes.o: $(hdrdir)/ruby/internal/method.h
sizes.o: $(hdrdir)/ruby/internal/module.h
sizes.o: $(hdrdir)/ruby/internal/newobj.h
+sizes.o: $(hdrdir)/ruby/internal/rgengc.h
sizes.o: $(hdrdir)/ruby/internal/scan_args.h
sizes.o: $(hdrdir)/ruby/internal/special_consts.h
sizes.o: $(hdrdir)/ruby/internal/static_assert.h
sizes.o: $(hdrdir)/ruby/internal/stdalign.h
sizes.o: $(hdrdir)/ruby/internal/stdbool.h
-sizes.o: $(hdrdir)/ruby/internal/stdckdint.h
sizes.o: $(hdrdir)/ruby/internal/symbol.h
sizes.o: $(hdrdir)/ruby/internal/value.h
sizes.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/readline/.gitignore b/ext/readline/.gitignore
new file mode 100644
index 0000000000..3d372989ae
--- /dev/null
+++ b/ext/readline/.gitignore
@@ -0,0 +1 @@
+/readline-[1-9]*.*
diff --git a/ext/readline/README b/ext/readline/README
new file mode 100644
index 0000000000..57c51b5f5d
--- /dev/null
+++ b/ext/readline/README
@@ -0,0 +1,10 @@
+The Readline module provides interface for GNU Readline.
+This module defines a number of methods to facilitate completion
+and accesses input history from the Ruby interpreter.
+This module supported Edit Line(libedit) too.
+libedit is compatible with GNU Readline.
+
+GNU Readline:: http://www.gnu.org/directory/readline.html
+libedit:: http://www.thrysoee.dk/editline/
+
+See RDoc for Readline module.
diff --git a/ext/readline/README.ja b/ext/readline/README.ja
new file mode 100644
index 0000000000..57a6ee4126
--- /dev/null
+++ b/ext/readline/README.ja
@@ -0,0 +1,386 @@
+GNU Readline ã«ã‚ˆã‚‹ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³å…¥åŠ›ã‚¤ãƒ³ã‚¿ãƒ•ã‚§ãƒ¼ã‚¹ã‚’æä¾›ã™ã‚‹ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«
+ã§ã™ã€‚GNU Readline ã®äº’æ›ãƒ©ã‚¤ãƒ–ラリã®ã²ã¨ã¤ã§ã‚ã‚‹ Edit Line(libedit) ã‚‚
+サãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã™ã€‚
+
+GNU Readline:: http://www.gnu.org/directory/readline.html
+libedit:: http://www.thrysoee.dk/editline/
+
+Readline.readline を使用ã—ã¦ãƒ¦ãƒ¼ã‚¶ã‹ã‚‰ã®å…¥åŠ›ã‚’å–å¾—ã§ãã¾ã™ã€‚ã“ã®ã¨ãã€
+GNU Readline ã®ã‚ˆã†ã«å…¥åŠ›ã®è£œå®Œã‚„Emacs ã®ã‚ˆã†ãªã‚­ãƒ¼æ“作ãªã©ãŒã§ãã¾ã™ã€‚
+
+ require "readline"
+ while buf = Readline.readline("> ", true)
+ p buf
+ end
+
+ユーザãŒå…¥åŠ›ã—ãŸå†…容を履歴(以下ã€ãƒ’ストリ)ã¨ã—ã¦è¨˜éŒ²ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
+定数 Readline::HISTORY を使用ã—ã¦ãƒ’ストリã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã™ã€‚
+
+ require "readline"
+ while buf = Readline.readline("> ", true)
+ p Readline::HISTORY.to_a
+ print("-> ", buf, "\n")
+ end
+
+使用ã™ã‚‹ãƒ©ã‚¤ãƒ–ラリã«ã‚ˆã‚Šã€ã„ãã¤ã‹ã®ãƒ¡ã‚½ãƒƒãƒ‰ã§ä¾‹å¤– NotImplementedError
+ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+== Readline モジュール
+
+=== モジュール関数
+
+readline([prompt, [add_hist]]) -> String | nil
+
+ prompt を出力ã—ã€ãƒ¦ãƒ¼ã‚¶ã‹ã‚‰ã®ã‚­ãƒ¼å…¥åŠ›ã‚’å¾…ã¡ã¾ã™ã€‚
+ ã‚¨ãƒ³ã‚¿ãƒ¼ã‚­ãƒ¼ã®æŠ¼ä¸‹ãªã©ã§ãƒ¦ãƒ¼ã‚¶ãŒæ–‡å­—列を入力ã—終ãˆã‚‹ã¨ã€
+ 入力ã—ãŸæ–‡å­—列を返ã—ã¾ã™ã€‚
+ ã“ã®ã¨ãã€add_hist ㌠true ã§ã‚れã°ã€å…¥åŠ›ã—ãŸæ–‡å­—列をヒストリã«è¿½åŠ ã—ã¾ã™ã€‚
+
+ 何も入力ã—ã¦ã„ãªã„状態㧠EOF(UNIX ã§ã¯ ^D) を入力ã™ã‚‹ãªã©ã§ã€
+ ユーザã‹ã‚‰ã®å…¥åŠ›ãŒãªã„å ´åˆã¯ nil ã‚’è¿”ã—ã¾ã™ã€‚
+
+ æ¬¡ã®æ¡ä»¶ã‚’å…¨ã¦æº€ãŸã™å ´åˆã€ä¾‹å¤– IOError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+ 1. 標準入力㌠tty ã§ãªã„。
+ 2. 標準入力をクローズã—ã¦ã„る。(isatty(2) ã® errno ㌠EBADF ã§ã‚る。)
+
+ 本メソッドã¯ã‚¹ãƒ¬ãƒƒãƒ‰ã«å¯¾å¿œã—ã¦ã„ã¾ã™ã€‚
+ 入力待ã¡çŠ¶æ…‹ã®ã¨ãã¯ã‚¹ãƒ¬ãƒƒãƒ‰ã‚³ãƒ³ãƒ†ã‚­ã‚¹ãƒˆã®åˆ‡æ›¿ãˆãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+ 入力時ã«ã¯è¡Œå†…編集ãŒå¯èƒ½ã§ã€vi モード㨠Emacs モードãŒç”¨æ„ã•れã¦ã„ã¾ã™ã€‚
+ デフォルト㯠Emacs モードã§ã™ã€‚
+
+ 本メソッドã«ã¯æ³¨æ„事項ãŒã‚りã¾ã™ã€‚
+ 入力待ã¡ã®çŠ¶æ…‹ã§ ^C ã™ã‚‹ã¨ ruby インタプリタãŒçµ‚了ã—ã€ç«¯æœ«çŠ¶æ…‹ã‚’å¾©å¸°ã—ã¾ã›ã‚“。
+ ã“れを回é¿ã™ã‚‹ãŸã‚ã®ä¾‹ã‚’3ã¤æŒ™ã’ã¾ã™ã€‚
+
+ * ^Cã«ã‚ˆã‚‹Interrupt例外を補足ã—ã¦ã€ç«¯æœ«çŠ¶æ…‹ã‚’å¾©å¸°ã—ã¾ã™:
+
+ require "readline"
+
+ stty_save = `stty -g`.chomp
+ begin
+ while buf = Readline.readline
+ p buf
+ end
+ rescue Interrupt
+ system("stty", stty_save)
+ exit
+ end
+ end
+ end
+
+ * INTシグナルを補足ã—ã¦ã€ç«¯æœ«çŠ¶æ…‹ã‚’å¾©å¸°ã—ã¾ã™:
+
+ require "readline"
+
+ stty_save = `stty -g`.chomp
+ trap("INT") { system "stty", stty_save; exit }
+
+ while buf = Readline.readline
+ p buf
+ end
+
+ * å˜ã« ^C を無視ã™ã‚‹æ–¹æ³•ã‚‚ã‚りã¾ã™:
+
+ require "readline"
+
+ trap("INT", "SIG_IGN")
+
+ while buf = Readline.readline
+ p buf
+ end
+
+ 入力履歴 Readline::HISTORY を使用ã—ã¦ã€ç©ºè¡Œã‚„ç›´å‰ã®å…¥åŠ›ã¨åŒã˜å†…容ã¯å…¥åŠ›
+ å±¥æ­´ã«æ®‹ã•ãªã„ã¨ã„ã†ã“ã¨ã‚‚ã§ãã¾ã™ã€‚
+
+ require "readline"
+
+ while buf = Readline.readline("> ", true)
+ # p Readline::HISTORY.to_a
+ Readline::HISTORY.pop if /^\s*$/ =~ buf
+
+ begin
+ if Readline::HISTORY[Readline::HISTORY.length-2] == buf
+ Readline::HISTORY.pop
+ end
+ rescue IndexError
+ end
+
+ # p Readline::HISTORY.to_a
+ print "-> ", buf, "\n"
+ end
+
+=== クラスメソッド
+
+Readline.input = input
+
+ Readline.readline メソッドã§ä½¿ç”¨ã™ã‚‹å…¥åŠ›ç”¨ã® File オブジェクト input
+ を指定ã—ã¾ã™ã€‚
+
+Readline.output = output
+
+ Readline.readline メソッドã§ä½¿ç”¨ã™ã‚‹å‡ºåŠ›ç”¨ã® File オブジェクト
+ output を指定ã—ã¾ã™ã€‚
+
+Readline.completion_proc = proc
+
+ ユーザã‹ã‚‰ã®å…¥åŠ›ã‚’è£œå®Œã™ã‚‹æ™‚ã®å€™è£œã‚’å–å¾—ã™ã‚‹ Proc オブジェクト proc ã‚’
+ 指定ã—ã¾ã™ã€‚proc ã¯ã€æ¬¡ã®ã‚‚ã®ã‚’想定ã—ã¦ã„ã¾ã™ã€‚
+ 1. call メソッドをæŒã¡ã¾ã™ã€‚
+ call メソッドをæŒãŸãªã„å ´åˆã€ä¾‹å¤– ArgumentError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+ 2. 引数ã«ãƒ¦ãƒ¼ã‚¶ã‹ã‚‰ã®å…¥åŠ›æ–‡å­—åˆ—(注1)ã‚’å–りã¾ã™ã€‚
+ 3. å€™è£œã®æ–‡å­—列ã®é…列を返ã—ã¾ã™ã€‚
+
+ 注1:「/var/lib /vã€ã®å¾Œã§è£œå®Œã‚’行ã†ã¨ã€
+ デフォルトã§ã¯ proc ã®å¼•æ•°ã«ã€Œ/vã€ãŒæ¸¡ã•れã¾ã™ã€‚
+ ã“ã®ã‚ˆã†ã«ã€ãƒ¦ãƒ¼ã‚¶ãŒå…¥åŠ›ã—ãŸæ–‡å­—列を
+ Readline.completer_word_break_characters ã«å«ã¾ã‚Œã‚‹æ–‡å­—ã§åŒºåˆ‡ã£ãŸã‚‚
+ ã®ã‚’å˜èªžã¨ã™ã‚‹ã¨ã€ã‚«ãƒ¼ã‚½ãƒ«ãŒã‚ã‚‹å˜èªžã®æœ€åˆã®æ–‡å­—ã‹ã‚‰ç¾åœ¨ã®ã‚«ãƒ¼ã‚½ãƒ«ä½
+ ç½®ã¾ã§ã®æ–‡å­—列㌠proc ã®å¼•æ•°ã«æ¸¡ã•れã¾ã™ã€‚
+
+Readline.completion_proc -> proc
+
+ ユーザã‹ã‚‰ã®å…¥åŠ›ã‚’è£œå®Œã™ã‚‹æ™‚ã®å€™è£œã‚’å–å¾—ã™ã‚‹ Proc オブジェクト proc
+ ã‚’å–å¾—ã—ã¾ã™ã€‚
+
+Readline.completion_case_fold = bool
+
+ ユーザã®å…¥åŠ›ã‚’è£œå®Œã™ã‚‹éš›ã€å¤§æ–‡å­—ã¨å°æ–‡å­—を区別ã™ã‚‹ï¼ã—ãªã„を指定ã—ã¾ã™ã€‚
+ bool ãŒçœŸãªã‚‰ã°åŒºåˆ¥ã—ã¾ã›ã‚“。bool ãŒå½ãªã‚‰ã°åŒºåˆ¥ã—ã¾ã™ã€‚
+
+Readline.completion_case_fold -> bool
+
+ ユーザã®å…¥åŠ›ã‚’è£œå®Œã™ã‚‹éš›ã€å¤§æ–‡å­—ã¨å°æ–‡å­—を区別ã™ã‚‹ï¼ã—ãªã„ã‚’å–å¾—ã—ã¾ã™ã€‚
+ bool ãŒçœŸãªã‚‰ã°åŒºåˆ¥ã—ã¾ã›ã‚“。bool ãŒå½ãªã‚‰ã°åŒºåˆ¥ã—ã¾ã™ã€‚
+
+ ãªãŠã€Readline.completion_case_fold= ãƒ¡ã‚½ãƒƒãƒ‰ã§æŒ‡å®šã—ãŸã‚ªãƒ–ジェクトを
+ ãã®ã¾ã¾å–å¾—ã™ã‚‹ã®ã§ã€æ¬¡ã®ã‚ˆã†ãªå‹•作をã—ã¾ã™ã€‚
+
+ require "readline"
+
+ Readline.completion_case_fold = "This is a String."
+ p Readline.completion_case_fold # => "This is a String."
+
+Readline.line_buffer -> string
+
+ 入力中ã®è¡Œå…¨ä½“ã‚’è¿”ã—ã¾ã™ã€‚complete_proc ã®ä¸­ã§ä½¿ç”¨ã™ã‚‹ã“ã¨ã‚’想定ã—
+ ã¦ã„ã¾ã™ã€‚Readline.line_buffer ã®é•·ã•㯠GNU Readline ã® rl_end 変数ã®
+ 値ã¨ä¸€è‡´ã—ã¾ã™ã€‚
+
+Readline.point -> int
+
+ ç¾åœ¨ã®ã‚«ãƒ¼ã‚½ãƒ«ã®ä½ç½®ã‚’è¿”ã—ã¾ã™ã€‚
+ Readline モジュールã¯è£œå®Œå¯¾è±¡ã®å˜èªžã®é–‹å§‹ä½ç½®ã®æƒ…報をæä¾›ã—ã¦ã„ã¾ã›ã‚“。
+ ã—ã‹ã—ãªãŒã‚‰ã€ completion_proc ã®ä¸­ã§å…¥åŠ›ã—ãŸå˜èªž text ã¨
+ Readline.point を使用ã™ã‚‹ã“ã¨ã§é–‹å§‹ä½ç½®ã‚’å°Žãã“ã¨ãŒã§ãã¾ã™ã€‚
+
+ é–‹å§‹ä½ç½® = 入力ã—ãŸå˜èªžã®é•·ã• - Readline.point
+
+Readline.vi_editing_mode -> nil
+
+ 編集モードを vi モードã«ã—ã¾ã™ã€‚
+ vi モードã®è©³ç´°ã¯ã€GNU Readline ã®ãƒžãƒ‹ãƒ¥ã‚¢ãƒ«ã‚’å‚ç…§ã—ã¦ãã ã•ã„。
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.vi_editing_mode? -> bool
+
+ 編集モード㌠vi モードã®å ´åˆã€true ã‚’è¿”ã—ã¾ã™ã€‚ãã†ã§ãªã‘れ㰠false
+ ã‚’è¿”ã—ã¾ã™ã€‚
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.emacs_editing_mode -> nil
+
+ 編集モードを Emacs モードã«ã—ã¾ã™ã€‚
+ デフォルト㯠Emacs モードã§ã™ã€‚
+ Emacs モードã®è©³ç´°ã¯ã€GNU Readline ã®ãƒžãƒ‹ãƒ¥ã‚¢ãƒ«ã‚’å‚ç…§ã—ã¦ãã ã•ã„。
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.emacs_editing_mode? -> bool
+
+ 編集モード㌠Emacs モードã®å ´åˆã€true ã‚’è¿”ã—ã¾ã™ã€‚ãã†ã§ãªã‘れ㰠false
+ ã‚’è¿”ã—ã¾ã™ã€‚
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.completion_append_character = char
+
+ ユーザã®å…¥åŠ›ã®è£œå®ŒãŒå®Œäº†ã—ãŸå ´åˆã«ã€æœ€å¾Œã«ä»˜åŠ ã™ã‚‹æ–‡å­— char を指定ã—
+ ã¾ã™ã€‚åŠè§’スペース「" "ã€ãªã©ã®å˜èªžã‚’区切る文字を指定ã™ã‚Œã°ã€é€£ç¶šã—ã¦
+ 入力ã™ã‚‹éš›ã«ä¾¿åˆ©ã§ã™ã€‚
+
+ 使用例:
+
+ require "readline"
+
+ Readline.readline("> ", true)
+ Readline.completion_append_character = " "
+
+ 実行例:
+
+ >
+ ã“ã“ã§ "/var/li" を入力ã—ã¾ã™ã€‚
+
+ > /var/li
+ ã“ã“ã§ TAB キーを入力ã—ã¾ã™ã€‚
+
+ > /var/lib
+ "b" ãŒè£œå®Œã•ã‚Œã€æœ€å¾Œã« " " ãŒè¿½åŠ ã•れるã®ã§ã€"/usr" を連続ã—ã¦å…¥åŠ›ã§ãã¾ã™ã€‚
+
+ > /var/lib /usr
+
+ ãªãŠã€1文字ã—ã‹æŒ‡å®šã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。
+ 例ãˆã°ã€"string"を指定ã—ãŸå ´åˆã¯æœ€åˆã®æ–‡å­—ã§ã‚ã‚‹"s"ã ã‘を使用ã—ã¾ã™ã€‚
+
+ require "readline"
+
+ Readline.completion_append_character = "string"
+ p Readline.completion_append_character # => "s"
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.completion_append_character -> char
+
+ ユーザã®å…¥åŠ›ã®è£œå®ŒãŒå®Œäº†ã—ãŸå ´åˆã«ã€æœ€å¾Œã«ä»˜åŠ ã™ã‚‹æ–‡å­—ã‚’å–å¾—ã—ã¾ã™ã€‚
+ デフォルトã¯ç©ºç™½ (" ") ã§ã™ã€‚
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.basic_word_break_characters = string
+
+ ユーザã®å…¥åŠ›ã®è£œå®Œã‚’行ã†éš›ã€å˜èªžã®åŒºåˆ‡ã‚Šã‚’示ã™è¤‡æ•°ã®æ–‡å­—ã§æ§‹æˆã•れる
+ 文字列 string を指定ã—ã¾ã™ã€‚
+
+ GNU Readline ã®ãƒ‡ãƒ•ォルトã®å€¤ã¯ã€Bash ã®è£œå®Œå‡¦ç†ã§ä½¿ç”¨ã—ã¦ã„る文字列
+ " \t\n\"\\'`@$><=;|&{(" (スペースをå«ã‚€) ã«ãªã£ã¦ã„ã¾ã™ã€‚
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.basic_word_break_characters -> string
+
+ ユーザã®å…¥åŠ›ã®è£œå®Œã‚’行ã†éš›ã€å˜èªžã®åŒºåˆ‡ã‚Šã‚’示ã™è¤‡æ•°ã®æ–‡å­—ã§æ§‹æˆã•れる
+ 文字列をå–å¾—ã—ã¾ã™ã€‚
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.completer_word_break_characters = string
+
+ ユーザã®å…¥åŠ›ã®è£œå®Œã‚’行ã†éš›ã€å˜èªžã®åŒºåˆ‡ã‚Šã‚’示ã™è¤‡æ•°ã®æ–‡å­—ã§æ§‹æˆã•れる
+ 文字列 string を指定ã—ã¾ã™ã€‚
+ Readline.basic_word_break_characters= ã¨ã®é•ã„ã¯ã€
+ GNU Readline ã® rl_complete_internal 関数ã§ä½¿ç”¨ã•れるã“ã¨ã§ã™ã€‚
+
+ GNU Readline ã®ãƒ‡ãƒ•ォルトã®å€¤ã¯ã€
+ Readline.basic_word_break_characters ã¨åŒã˜ã§ã™ã€‚
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.completer_word_break_characters -> string
+
+ ユーザã®å…¥åŠ›ã®è£œå®Œã‚’行ã†éš›ã€å˜èªžã®åŒºåˆ‡ã‚Šã‚’示ã™è¤‡æ•°ã®æ–‡å­—ã§æ§‹æˆã•れãŸ
+ 文字列をå–å¾—ã—ã¾ã™ã€‚
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.basic_quote_characters = string
+
+ スペースãªã©ã®å˜èªžã®åŒºåˆ‡ã‚Šã‚’クオートã™ã‚‹ãŸã‚ã®è¤‡æ•°ã®æ–‡å­—ã§æ§‹æˆã•れる
+ 文字列 string を指定ã—ã¾ã™ã€‚
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.basic_quote_characters -> string
+
+ スペースãªã©ã®å˜èªžã®åŒºåˆ‡ã‚Šã‚’クオートã™ã‚‹ãŸã‚ã®è¤‡æ•°ã®æ–‡å­—ã§æ§‹æˆã•れる
+ 文字列をå–å¾—ã—ã¾ã™ã€‚
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.completer_quote_characters = string
+
+ ユーザã®å…¥åŠ›ã®è£œå®Œã‚’行ã†éš›ã€ã‚¹ãƒšãƒ¼ã‚¹ãªã©ã®å˜èªžã®åŒºåˆ‡ã‚Šã‚’
+ クオートã™ã‚‹ãŸã‚ã®è¤‡æ•°ã®æ–‡å­—ã§æ§‹æˆã•れる文字列 string を指定ã—ã¾ã™ã€‚
+ 指定ã—ãŸæ–‡å­—ã®é–“ã§ã¯ã€Readline.completer_word_break_characters=
+ ã§æŒ‡å®šã—ãŸæ–‡å­—列ã«å«ã¾ã‚Œã‚‹æ–‡å­—ã‚‚ã€æ™®é€šã®æ–‡å­—列ã¨ã—ã¦æ‰±ã‚れã¾ã™ã€‚
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.completer_quote_characters -> string
+
+ ユーザã®å…¥åŠ›ã®è£œå®Œã‚’行ã†éš›ã€ã‚¹ãƒšãƒ¼ã‚¹ãªã©ã®å˜èªžã®åŒºåˆ‡ã‚Šã‚’
+ クオートã™ã‚‹ãŸã‚ã®è¤‡æ•°ã®æ–‡å­—ã§æ§‹æˆã•れる文字列をå–å¾—ã—ã¾ã™ã€‚
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.filename_quote_characters = string
+
+ ユーザã®å…¥åŠ›æ™‚ã«ãƒ•ァイルåã®è£œå®Œã‚’行ã†éš›ã€ã‚¹ãƒšãƒ¼ã‚¹ãªã©ã®å˜èªžã®åŒºåˆ‡ã‚Šã‚’
+ クオートã™ã‚‹ãŸã‚ã®è¤‡æ•°ã®æ–‡å­—ã§æ§‹æˆã•れる文字列 string を指定ã—ã¾ã™ã€‚
+
+ GNU Readline ã®ãƒ‡ãƒ•ォルト値㯠nil ã§ã™ã€‚
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+Readline.filename_quote_characters -> string
+
+ ユーザã®å…¥åŠ›æ™‚ã«ãƒ•ァイルåã®è£œå®Œã‚’行ã†éš›ã€ã‚¹ãƒšãƒ¼ã‚¹ãªã©ã®å˜èªžã®åŒºåˆ‡ã‚Šã‚’
+ クオートã™ã‚‹ãŸã‚ã®è¤‡æ•°ã®æ–‡å­—ã§æ§‹æˆã•れる文字列をå–å¾—ã—ã¾ã™ã€‚
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€ä¾‹å¤– NotImplementedError ãŒç™ºç”Ÿã—ã¾ã™ã€‚
+
+=== クラス定数
+
+HISTORY
+
+ 定数 HISTORY を使用ã—ã¦ãƒ’ストリã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã™ã€‚
+ Enumerable モジュールを extend ã—ã¦ãŠã‚Šã€
+ é…列ã®ã‚ˆã†ã«æŒ¯ã‚‹èˆžã†ã“ã¨ãŒã§ãã¾ã™ã€‚
+ 例ãˆã°ã€HISTORY[4] ã«ã‚ˆã‚Š 5 番目ã«å…¥åŠ›ã—ãŸå†…容をå–り出ã™ã“ã¨ãŒã§ãã¾ã™ã€‚
+
+ require "readline"
+
+ Readline::HISTORY.push("a", "b", "c", "d", "e")
+ p Readline::HISTORY[4] # => "e"
+
+ 実装ã—ã¦ã„ã‚‹ãƒ¡ã‚½ãƒƒãƒ‰ã‚’æ¬¡ã«æŒ™ã’ã¾ã™ã€‚
+ * HISTORY.to_s -> "HISTORY"
+ * HISTORY[index] -> string
+ * HISTORY[index] = string
+ * HISTORY.push(string[, string, ...]) -> self
+ * HISTORY << string -> self
+ * HISTORY.pop -> string
+ * HISTORY.shift -> string
+ * HISTORY.each -> Enumerator
+ * HISTORY.each { |i| } -> [string]
+ * HISTORY.length -> Integer
+ * HISTORY.empty? -> true or false
+ * HISTORY.delete_at(index) -> string
+ * HISTORY.clear -> self
+
+ サãƒãƒ¼ãƒˆã—ã¦ã„ãªã„環境ã§ã¯ã€æ¬¡ã®ãƒ¡ã‚½ãƒƒãƒ‰ã§ä¾‹å¤– NotImplementedError ãŒ
+ 発生ã—ã¾ã™ã€‚
+ * HISTORY[index] = string
+ * HISTORY.pop -> string
+ * HISTORY.shift -> string
+ * HISTORY.delete_at(index) -> string
+ * HISTORY.clear -> self
+
+FILENAME_COMPLETION_PROC
+
+ ファイルåã®è£œå®Œã‚’行ㆠcall メソッドをæŒã¤ã‚ªãƒ–ジェクトã§ã™ã€‚
+
+ Readline.completion_proc= ã«ã‚ˆã‚Šã€ãƒ¦ãƒ¼ã‚¶ã®å…¥åŠ›æ™‚ã«ãƒ•ァイルåã®è£œå®Œã‚’
+ 行ã†ã‚ˆã†ã«è¨­å®šã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã™ã‚‹ã“ã¨ã‚’想定ã—ã¦ã¾ã™ã€‚
+
+USERNAME_COMPLETION_PROC
+
+ ユーザåã®è£œå®Œã‚’行ㆠcall メソッドをæŒã¤ã‚ªãƒ–ジェクトã§ã™ã€‚
+
+ Readline.completion_proc= ã«ã‚ˆã‚Šã€ãƒ¦ãƒ¼ã‚¶ã®å…¥åŠ›æ™‚ã«ãƒ¦ãƒ¼ã‚¶åã®è£œå®Œã‚’行
+ ã†ã‚ˆã†ã«è¨­å®šã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã™ã‚‹ã“ã¨ã‚’想定ã—ã¦ã¾ã™ã€‚
+
+VERSION
+
+ 使用ã—ã¦ã„ã‚‹ GNU Readline ã¾ãŸã¯ libedit ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã™ã€‚
diff --git a/ext/readline/depend b/ext/readline/depend
new file mode 100644
index 0000000000..c62309622a
--- /dev/null
+++ b/ext/readline/depend
@@ -0,0 +1,175 @@
+# AUTOGENERATED DEPENDENCIES START
+readline.o: $(RUBY_EXTCONF_H)
+readline.o: $(arch_hdrdir)/ruby/config.h
+readline.o: $(hdrdir)/ruby/assert.h
+readline.o: $(hdrdir)/ruby/backward.h
+readline.o: $(hdrdir)/ruby/backward/2/assume.h
+readline.o: $(hdrdir)/ruby/backward/2/attributes.h
+readline.o: $(hdrdir)/ruby/backward/2/bool.h
+readline.o: $(hdrdir)/ruby/backward/2/inttypes.h
+readline.o: $(hdrdir)/ruby/backward/2/limits.h
+readline.o: $(hdrdir)/ruby/backward/2/long_long.h
+readline.o: $(hdrdir)/ruby/backward/2/stdalign.h
+readline.o: $(hdrdir)/ruby/backward/2/stdarg.h
+readline.o: $(hdrdir)/ruby/defines.h
+readline.o: $(hdrdir)/ruby/encoding.h
+readline.o: $(hdrdir)/ruby/intern.h
+readline.o: $(hdrdir)/ruby/internal/abi.h
+readline.o: $(hdrdir)/ruby/internal/anyargs.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+readline.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+readline.o: $(hdrdir)/ruby/internal/assume.h
+readline.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+readline.o: $(hdrdir)/ruby/internal/attr/artificial.h
+readline.o: $(hdrdir)/ruby/internal/attr/cold.h
+readline.o: $(hdrdir)/ruby/internal/attr/const.h
+readline.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+readline.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+readline.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+readline.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+readline.o: $(hdrdir)/ruby/internal/attr/error.h
+readline.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+readline.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+readline.o: $(hdrdir)/ruby/internal/attr/format.h
+readline.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+readline.o: $(hdrdir)/ruby/internal/attr/noalias.h
+readline.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+readline.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+readline.o: $(hdrdir)/ruby/internal/attr/noinline.h
+readline.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+readline.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+readline.o: $(hdrdir)/ruby/internal/attr/pure.h
+readline.o: $(hdrdir)/ruby/internal/attr/restrict.h
+readline.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+readline.o: $(hdrdir)/ruby/internal/attr/warning.h
+readline.o: $(hdrdir)/ruby/internal/attr/weakref.h
+readline.o: $(hdrdir)/ruby/internal/cast.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+readline.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+readline.o: $(hdrdir)/ruby/internal/compiler_since.h
+readline.o: $(hdrdir)/ruby/internal/config.h
+readline.o: $(hdrdir)/ruby/internal/constant_p.h
+readline.o: $(hdrdir)/ruby/internal/core.h
+readline.o: $(hdrdir)/ruby/internal/core/rarray.h
+readline.o: $(hdrdir)/ruby/internal/core/rbasic.h
+readline.o: $(hdrdir)/ruby/internal/core/rbignum.h
+readline.o: $(hdrdir)/ruby/internal/core/rclass.h
+readline.o: $(hdrdir)/ruby/internal/core/rdata.h
+readline.o: $(hdrdir)/ruby/internal/core/rfile.h
+readline.o: $(hdrdir)/ruby/internal/core/rhash.h
+readline.o: $(hdrdir)/ruby/internal/core/robject.h
+readline.o: $(hdrdir)/ruby/internal/core/rregexp.h
+readline.o: $(hdrdir)/ruby/internal/core/rstring.h
+readline.o: $(hdrdir)/ruby/internal/core/rstruct.h
+readline.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+readline.o: $(hdrdir)/ruby/internal/ctype.h
+readline.o: $(hdrdir)/ruby/internal/dllexport.h
+readline.o: $(hdrdir)/ruby/internal/dosish.h
+readline.o: $(hdrdir)/ruby/internal/encoding/coderange.h
+readline.o: $(hdrdir)/ruby/internal/encoding/ctype.h
+readline.o: $(hdrdir)/ruby/internal/encoding/encoding.h
+readline.o: $(hdrdir)/ruby/internal/encoding/pathname.h
+readline.o: $(hdrdir)/ruby/internal/encoding/re.h
+readline.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
+readline.o: $(hdrdir)/ruby/internal/encoding/string.h
+readline.o: $(hdrdir)/ruby/internal/encoding/symbol.h
+readline.o: $(hdrdir)/ruby/internal/encoding/transcode.h
+readline.o: $(hdrdir)/ruby/internal/error.h
+readline.o: $(hdrdir)/ruby/internal/eval.h
+readline.o: $(hdrdir)/ruby/internal/event.h
+readline.o: $(hdrdir)/ruby/internal/fl_type.h
+readline.o: $(hdrdir)/ruby/internal/gc.h
+readline.o: $(hdrdir)/ruby/internal/glob.h
+readline.o: $(hdrdir)/ruby/internal/globals.h
+readline.o: $(hdrdir)/ruby/internal/has/attribute.h
+readline.o: $(hdrdir)/ruby/internal/has/builtin.h
+readline.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+readline.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+readline.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+readline.o: $(hdrdir)/ruby/internal/has/extension.h
+readline.o: $(hdrdir)/ruby/internal/has/feature.h
+readline.o: $(hdrdir)/ruby/internal/has/warning.h
+readline.o: $(hdrdir)/ruby/internal/intern/array.h
+readline.o: $(hdrdir)/ruby/internal/intern/bignum.h
+readline.o: $(hdrdir)/ruby/internal/intern/class.h
+readline.o: $(hdrdir)/ruby/internal/intern/compar.h
+readline.o: $(hdrdir)/ruby/internal/intern/complex.h
+readline.o: $(hdrdir)/ruby/internal/intern/cont.h
+readline.o: $(hdrdir)/ruby/internal/intern/dir.h
+readline.o: $(hdrdir)/ruby/internal/intern/enum.h
+readline.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+readline.o: $(hdrdir)/ruby/internal/intern/error.h
+readline.o: $(hdrdir)/ruby/internal/intern/eval.h
+readline.o: $(hdrdir)/ruby/internal/intern/file.h
+readline.o: $(hdrdir)/ruby/internal/intern/gc.h
+readline.o: $(hdrdir)/ruby/internal/intern/hash.h
+readline.o: $(hdrdir)/ruby/internal/intern/io.h
+readline.o: $(hdrdir)/ruby/internal/intern/load.h
+readline.o: $(hdrdir)/ruby/internal/intern/marshal.h
+readline.o: $(hdrdir)/ruby/internal/intern/numeric.h
+readline.o: $(hdrdir)/ruby/internal/intern/object.h
+readline.o: $(hdrdir)/ruby/internal/intern/parse.h
+readline.o: $(hdrdir)/ruby/internal/intern/proc.h
+readline.o: $(hdrdir)/ruby/internal/intern/process.h
+readline.o: $(hdrdir)/ruby/internal/intern/random.h
+readline.o: $(hdrdir)/ruby/internal/intern/range.h
+readline.o: $(hdrdir)/ruby/internal/intern/rational.h
+readline.o: $(hdrdir)/ruby/internal/intern/re.h
+readline.o: $(hdrdir)/ruby/internal/intern/ruby.h
+readline.o: $(hdrdir)/ruby/internal/intern/select.h
+readline.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+readline.o: $(hdrdir)/ruby/internal/intern/signal.h
+readline.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+readline.o: $(hdrdir)/ruby/internal/intern/string.h
+readline.o: $(hdrdir)/ruby/internal/intern/struct.h
+readline.o: $(hdrdir)/ruby/internal/intern/thread.h
+readline.o: $(hdrdir)/ruby/internal/intern/time.h
+readline.o: $(hdrdir)/ruby/internal/intern/variable.h
+readline.o: $(hdrdir)/ruby/internal/intern/vm.h
+readline.o: $(hdrdir)/ruby/internal/interpreter.h
+readline.o: $(hdrdir)/ruby/internal/iterator.h
+readline.o: $(hdrdir)/ruby/internal/memory.h
+readline.o: $(hdrdir)/ruby/internal/method.h
+readline.o: $(hdrdir)/ruby/internal/module.h
+readline.o: $(hdrdir)/ruby/internal/newobj.h
+readline.o: $(hdrdir)/ruby/internal/rgengc.h
+readline.o: $(hdrdir)/ruby/internal/scan_args.h
+readline.o: $(hdrdir)/ruby/internal/special_consts.h
+readline.o: $(hdrdir)/ruby/internal/static_assert.h
+readline.o: $(hdrdir)/ruby/internal/stdalign.h
+readline.o: $(hdrdir)/ruby/internal/stdbool.h
+readline.o: $(hdrdir)/ruby/internal/symbol.h
+readline.o: $(hdrdir)/ruby/internal/value.h
+readline.o: $(hdrdir)/ruby/internal/value_type.h
+readline.o: $(hdrdir)/ruby/internal/variable.h
+readline.o: $(hdrdir)/ruby/internal/warning_push.h
+readline.o: $(hdrdir)/ruby/internal/xmalloc.h
+readline.o: $(hdrdir)/ruby/io.h
+readline.o: $(hdrdir)/ruby/missing.h
+readline.o: $(hdrdir)/ruby/onigmo.h
+readline.o: $(hdrdir)/ruby/oniguruma.h
+readline.o: $(hdrdir)/ruby/ruby.h
+readline.o: $(hdrdir)/ruby/st.h
+readline.o: $(hdrdir)/ruby/subst.h
+readline.o: $(hdrdir)/ruby/thread.h
+readline.o: readline.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/readline/depend-gem b/ext/readline/depend-gem
new file mode 100644
index 0000000000..df01bd2a86
--- /dev/null
+++ b/ext/readline/depend-gem
@@ -0,0 +1,4 @@
+# AUTOGENERATED DEPENDENCIES START
+readline.o: $(RUBY_EXTCONF_H)
+readline.o: readline.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/readline/extconf.rb b/ext/readline/extconf.rb
new file mode 100644
index 0000000000..d3e7872e65
--- /dev/null
+++ b/ext/readline/extconf.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: false
+require "mkmf"
+
+readline = Struct.new(:headers, :extra_check).new(["stdio.h"])
+
+def readline.have_header(header)
+ if super(header, &extra_check)
+ headers.push(header)
+ return true
+ else
+ return false
+ end
+end
+
+def readline.have_var(var)
+ return super(var, headers)
+end
+
+def readline.have_func(func)
+ return super(func, headers)
+end
+
+def readline.have_type(type)
+ return super(type, headers)
+end
+
+dir_config('curses')
+dir_config('ncurses')
+dir_config('termcap')
+dir_config("readline")
+enable_libedit = enable_config("libedit")
+
+have_library("user32", nil) if /cygwin/ === RUBY_PLATFORM
+have_library("ncurses", "tgetnum") ||
+ have_library("termcap", "tgetnum") ||
+ have_library("curses", "tgetnum")
+
+case enable_libedit
+when true
+ # --enable-libedit
+ dir_config("libedit")
+ unless (readline.have_header("editline/readline.h") ||
+ readline.have_header("readline/readline.h")) &&
+ have_library("edit", "readline")
+ raise "libedit not found"
+ end
+when false
+ # --disable-libedit
+ unless ((readline.have_header("readline/readline.h") &&
+ readline.have_header("readline/history.h")) &&
+ have_library("readline", "readline"))
+ raise "readline not found"
+ end
+else
+ # does not specify
+ unless ((readline.have_header("readline/readline.h") &&
+ readline.have_header("readline/history.h")) &&
+ (have_library("readline", "readline") ||
+ have_library("edit", "readline"))) ||
+ (readline.have_header("editline/readline.h") &&
+ have_library("edit", "readline"))
+ raise "Neither readline nor libedit was found"
+ end
+end
+
+readline.have_func("rl_getc")
+readline.have_func("rl_getc_function")
+readline.have_func("rl_filename_completion_function")
+readline.have_func("rl_username_completion_function")
+readline.have_func("rl_completion_matches")
+readline.have_func("rl_refresh_line")
+readline.have_var("rl_deprep_term_function")
+readline.have_var("rl_completion_append_character")
+readline.have_var("rl_completion_quote_character")
+readline.have_var("rl_basic_word_break_characters")
+readline.have_var("rl_completer_word_break_characters")
+readline.have_var("rl_basic_quote_characters")
+readline.have_var("rl_completer_quote_characters")
+readline.have_var("rl_filename_quote_characters")
+readline.have_var("rl_attempted_completion_over")
+readline.have_var("rl_library_version")
+readline.have_var("rl_editing_mode")
+readline.have_var("rl_line_buffer")
+readline.have_var("rl_point")
+readline.have_var("rl_char_is_quoted_p")
+# workaround for native windows.
+/mswin|bccwin/ !~ RUBY_PLATFORM && readline.have_var("rl_event_hook")
+/mswin|bccwin/ !~ RUBY_PLATFORM && readline.have_var("rl_catch_sigwinch")
+/mswin|bccwin/ !~ RUBY_PLATFORM && readline.have_var("rl_catch_signals")
+readline.have_var("rl_pre_input_hook")
+readline.have_var("rl_special_prefixes")
+readline.have_func("rl_cleanup_after_signal")
+readline.have_func("rl_free_line_state")
+readline.have_func("rl_clear_signals")
+readline.have_func("rl_set_screen_size")
+readline.have_func("rl_get_screen_size")
+readline.have_func("rl_vi_editing_mode")
+readline.have_func("rl_emacs_editing_mode")
+readline.have_func("replace_history_entry")
+readline.have_func("remove_history")
+readline.have_func("clear_history")
+readline.have_func("rl_redisplay")
+readline.have_func("rl_insert_text")
+readline.have_func("rl_delete_text")
+unless readline.have_type("rl_hook_func_t*")
+ # rl_hook_func_t is available since readline-4.2 (2001).
+ # Function is removed at readline-6.3 (2014).
+ # However, editline (NetBSD 6.1.3, 2014) doesn't have rl_hook_func_t.
+ $defs << "-Drl_hook_func_t=Function"
+end
+
+create_makefile("readline")
diff --git a/ext/readline/readline-ext.gemspec b/ext/readline/readline-ext.gemspec
new file mode 100644
index 0000000000..1e16edbfe6
--- /dev/null
+++ b/ext/readline/readline-ext.gemspec
@@ -0,0 +1,22 @@
+Gem::Specification.new do |spec|
+ spec.name = "readline-ext"
+ spec.version = "0.1.5"
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{Provides an interface for GNU Readline and Edit Line (libedit).}
+ spec.description = %q{Provides an interface for GNU Readline and Edit Line (libedit).}
+ spec.homepage = "https://github.com/ruby/readline-ext"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+ spec.extensions = %w[ext/readline/extconf.rb]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+end
diff --git a/ext/readline/readline.c b/ext/readline/readline.c
new file mode 100644
index 0000000000..fc254ce315
--- /dev/null
+++ b/ext/readline/readline.c
@@ -0,0 +1,2144 @@
+/************************************************
+
+ readline.c - GNU Readline module
+
+ $Author$
+ created at: Wed Jan 20 13:59:32 JST 1999
+
+ Copyright (C) 1997-2008 Shugo Maeda
+ Copyright (C) 2008-2013 Kouji Takao
+
+ $Id$
+
+ Contact:
+ - Kouji Takao <kouji dot takao at gmail dot com> (current maintainer)
+
+************************************************/
+
+#ifdef RUBY_EXTCONF_H
+#include RUBY_EXTCONF_H
+#endif
+
+#include "ruby/config.h"
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_READLINE_READLINE_H
+#include <readline/readline.h>
+#endif
+#ifdef HAVE_READLINE_HISTORY_H
+#include <readline/history.h>
+#endif
+#ifdef HAVE_EDITLINE_READLINE_H
+#include <editline/readline.h>
+#endif
+
+#include "ruby/io.h"
+#include "ruby/thread.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+static VALUE mReadline;
+
+#define EDIT_LINE_LIBRARY_VERSION "EditLine wrapper"
+#ifndef USE_INSERT_IGNORE_ESCAPE
+# if !defined(HAVE_EDITLINE_READLINE_H) && defined(RL_PROMPT_START_IGNORE) && defined(RL_PROMPT_END_IGNORE)
+# define USE_INSERT_IGNORE_ESCAPE 1
+# else
+# define USE_INSERT_IGNORE_ESCAPE 0
+# endif
+#endif
+
+#define COMPLETION_PROC "completion_proc"
+#define COMPLETION_CASE_FOLD "completion_case_fold"
+static ID id_call, completion_proc, completion_case_fold;
+#if defined HAVE_RL_CHAR_IS_QUOTED_P
+#define QUOTING_DETECTION_PROC "quoting_detection_proc"
+static ID quoting_detection_proc;
+#endif
+#if USE_INSERT_IGNORE_ESCAPE
+static ID id_orig_prompt, id_last_prompt;
+#endif
+#if defined(HAVE_RL_PRE_INPUT_HOOK)
+static ID id_pre_input_hook;
+#endif
+#if defined(HAVE_RL_SPECIAL_PREFIXES)
+static ID id_special_prefixes;
+#endif
+
+#ifndef HAVE_RL_FILENAME_COMPLETION_FUNCTION
+# define rl_filename_completion_function filename_completion_function
+#endif
+#ifndef HAVE_RL_USERNAME_COMPLETION_FUNCTION
+# define rl_username_completion_function username_completion_function
+#else
+RUBY_EXTERN char *rl_username_completion_function(const char *, int);
+#endif
+#ifndef HAVE_RL_COMPLETION_MATCHES
+# define rl_completion_matches completion_matches
+#endif
+
+static int (*history_get_offset_func)(int);
+static int (*history_replace_offset_func)(int);
+#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
+static int readline_completion_append_character;
+#endif
+
+static char **readline_attempted_completion_function(const char *text,
+ int start, int end);
+
+#define OutputStringValue(str) do {\
+ StringValueCStr(str);\
+ (str) = rb_str_conv_enc((str), rb_enc_get(str), rb_locale_encoding());\
+} while (0)\
+
+
+/*
+ * Document-class: Readline
+ *
+ * The Readline module provides interface for GNU Readline.
+ * This module defines a number of methods to facilitate completion
+ * and accesses input history from the Ruby interpreter.
+ * This module supported Edit Line(libedit) too.
+ * libedit is compatible with GNU Readline.
+ *
+ * GNU Readline:: http://www.gnu.org/directory/readline.html
+ * libedit:: http://www.thrysoee.dk/editline/
+ *
+ * Reads one inputted line with line edit by Readline.readline method.
+ * At this time, the facilitatation completion and the key
+ * bind like Emacs can be operated like GNU Readline.
+ *
+ * require "readline"
+ * while buf = Readline.readline("> ", true)
+ * p buf
+ * end
+ *
+ * The content that the user input can be recorded to the history.
+ * The history can be accessed by Readline::HISTORY constant.
+ *
+ * require "readline"
+ * while buf = Readline.readline("> ", true)
+ * p Readline::HISTORY.to_a
+ * print("-> ", buf, "\n")
+ * end
+ *
+ * Documented by Kouji Takao <kouji dot takao at gmail dot com>.
+ */
+
+static VALUE readline_instream;
+static VALUE readline_outstream;
+static FILE *readline_rl_instream;
+static FILE *readline_rl_outstream;
+
+static void
+mustbe_callable(VALUE proc)
+{
+ if (!NIL_P(proc) && !rb_respond_to(proc, id_call))
+ rb_raise(rb_eArgError, "argument must respond to `call'");
+}
+
+#if defined HAVE_RL_GETC_FUNCTION
+
+#ifndef HAVE_RL_GETC
+#define rl_getc(f) EOF
+#endif
+
+struct getc_struct {
+ FILE *input;
+ int fd;
+ int ret;
+ int err;
+};
+
+static int
+getc_body(struct getc_struct *p)
+{
+ char ch;
+ ssize_t ss;
+
+#if defined(_WIN32)
+ {
+ INPUT_RECORD ir;
+ DWORD n;
+ static int prior_key = '0';
+ for (;;) {
+ HANDLE h;
+ if (prior_key > 0xff) {
+ prior_key = rl_getc(p->input);
+ return prior_key;
+ }
+ h = (HANDLE)_get_osfhandle(p->fd);
+ if (PeekConsoleInput(h, &ir, 1, &n)) {
+ if (n == 1) {
+ if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown) {
+ prior_key = rl_getc(p->input);
+ return prior_key;
+ } else {
+ ReadConsoleInput(h, &ir, 1, &n);
+ }
+ } else {
+ rb_w32_wait_events_blocking(&h, 1, INFINITE);
+ }
+ } else {
+ break;
+ }
+ }
+ }
+#endif
+
+ ss = read(p->fd, &ch, 1);
+ if (ss == 0) {
+ errno = 0;
+ return EOF;
+ }
+ if (ss != 1)
+ return EOF;
+ return (unsigned char)ch;
+}
+
+static void *
+getc_func(void *data1)
+{
+ struct getc_struct *p = data1;
+ errno = 0;
+ p->ret = getc_body(p);
+ p->err = errno;
+ return NULL;
+}
+
+static int
+readline_getc(FILE *input)
+{
+ struct getc_struct data;
+ if (input == NULL) /* editline may give NULL as input. */
+ input = stdin;
+ data.input = input;
+ data.fd = fileno(input);
+ again:
+ data.ret = EOF;
+ data.err = EINTR; /* getc_func is not called if already interrupted. */
+ rb_thread_call_without_gvl2(getc_func, &data, RUBY_UBF_IO, NULL);
+ if (data.ret == EOF) {
+ if (data.err == 0) {
+ return EOF;
+ }
+ if (data.err == EINTR) {
+ rb_thread_check_ints();
+ goto again;
+ }
+ if (data.err == EWOULDBLOCK || data.err == EAGAIN) {
+ int ret;
+ if (fileno(input) != data.fd)
+ rb_bug("readline_getc: input closed unexpectedly or memory corrupted");
+ ret = rb_wait_for_single_fd(data.fd, RB_WAITFD_IN, NULL);
+ if (ret != -1 || errno == EINTR)
+ goto again;
+ rb_sys_fail("rb_wait_for_single_fd");
+ }
+ rb_syserr_fail(data.err, "read");
+ }
+ return data.ret;
+}
+
+#elif defined HAVE_RL_EVENT_HOOK
+#define BUSY_WAIT 0
+
+static int readline_event(void);
+static int
+readline_event(void)
+{
+#if BUSY_WAIT
+ rb_thread_schedule();
+#else
+ rb_wait_for_single_fd(fileno(rl_instream), RB_WAITFD_IN, NULL);
+ return 0;
+#endif
+}
+#endif
+
+#if USE_INSERT_IGNORE_ESCAPE
+static VALUE
+insert_ignore_escape(VALUE self, VALUE prompt)
+{
+ VALUE last_prompt, orig_prompt = rb_attr_get(self, id_orig_prompt);
+ int ignoring = 0;
+ const char *s0, *s, *e;
+ long len;
+ static const char ignore_code[2] = {RL_PROMPT_START_IGNORE, RL_PROMPT_END_IGNORE};
+
+ prompt = rb_str_new_shared(prompt);
+ last_prompt = rb_attr_get(self, id_last_prompt);
+ if (orig_prompt == prompt) return last_prompt;
+ len = RSTRING_LEN(prompt);
+ if (NIL_P(last_prompt)) {
+ last_prompt = rb_str_tmp_new(len);
+ }
+
+ s = s0 = RSTRING_PTR(prompt);
+ e = s0 + len;
+ rb_str_set_len(last_prompt, 0);
+ while (s < e && *s) {
+ switch (*s) {
+ case RL_PROMPT_START_IGNORE:
+ ignoring = -1;
+ rb_str_cat(last_prompt, s0, ++s - s0);
+ s0 = s;
+ break;
+ case RL_PROMPT_END_IGNORE:
+ ignoring = 0;
+ rb_str_cat(last_prompt, s0, ++s - s0);
+ s0 = s;
+ break;
+ case '\033':
+ if (++s < e && *s == '[') {
+ rb_str_cat(last_prompt, s0, s - s0 - 1);
+ s0 = s - 1;
+ while (++s < e && *s) {
+ if (ISALPHA(*(unsigned char *)s)) {
+ if (!ignoring) {
+ ignoring = 1;
+ rb_str_cat(last_prompt, ignore_code+0, 1);
+ }
+ rb_str_cat(last_prompt, s0, ++s - s0);
+ s0 = s;
+ break;
+ }
+ else if (!(('0' <= *s && *s <= '9') || *s == ';')) {
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ if (ignoring > 0) {
+ ignoring = 0;
+ rb_str_cat(last_prompt, ignore_code+1, 1);
+ }
+ s++;
+ break;
+ }
+ }
+ if (ignoring > 0) {
+ ignoring = 0;
+ rb_str_cat(last_prompt, ignore_code+1, 1);
+ }
+ rb_str_cat(last_prompt, s0, s - s0);
+
+ rb_ivar_set(self, id_orig_prompt, prompt);
+ rb_ivar_set(self, id_last_prompt, last_prompt);
+
+ return last_prompt;
+}
+#endif
+
+static VALUE
+readline_get(VALUE prompt)
+{
+#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
+ readline_completion_append_character = rl_completion_append_character;
+#endif
+ return (VALUE)readline((char *)prompt);
+}
+
+static void
+clear_rl_instream(void)
+{
+ if (readline_rl_instream) {
+ fclose(readline_rl_instream);
+ if (rl_instream == readline_rl_instream)
+ rl_instream = NULL;
+ readline_rl_instream = NULL;
+ }
+ readline_instream = Qfalse;
+}
+
+static void
+clear_rl_outstream(void)
+{
+ if (readline_rl_outstream) {
+ fclose(readline_rl_outstream);
+ if (rl_outstream == readline_rl_outstream)
+ rl_outstream = NULL;
+ readline_rl_outstream = NULL;
+ }
+ readline_outstream = Qfalse;
+}
+
+static void
+prepare_readline(void)
+{
+ static int initialized = 0;
+ if (!initialized) {
+ rl_initialize();
+ initialized = 1;
+ }
+
+ if (readline_instream) {
+ rb_io_t *ifp;
+ rb_io_check_initialized(ifp = RFILE(rb_io_taint_check(readline_instream))->fptr);
+ if (ifp->fd < 0) {
+ clear_rl_instream();
+ rb_raise(rb_eIOError, "closed readline input");
+ }
+ }
+
+ if (readline_outstream) {
+ rb_io_t *ofp;
+ rb_io_check_initialized(ofp = RFILE(rb_io_taint_check(readline_outstream))->fptr);
+ if (ofp->fd < 0) {
+ clear_rl_outstream();
+ rb_raise(rb_eIOError, "closed readline output");
+ }
+ }
+}
+
+/*
+ * call-seq:
+ * Readline.readline(prompt = "", add_hist = false) -> string or nil
+ *
+ * Shows the +prompt+ and reads the inputted line with line editing.
+ * The inputted line is added to the history if +add_hist+ is true.
+ *
+ * Returns nil when the inputted line is empty and user inputs EOF
+ * (Presses ^D on UNIX).
+ *
+ * Raises IOError exception if one of below conditions are satisfied.
+ * 1. stdin was closed.
+ * 2. stdout was closed.
+ *
+ * This method supports thread. Switches the thread context when waits
+ * inputting line.
+ *
+ * Supports line edit when inputs line. Provides VI and Emacs editing mode.
+ * Default is Emacs editing mode.
+ *
+ * NOTE: Terminates ruby interpreter and does not return the terminal
+ * status after user pressed '^C' when wait inputting line.
+ * Give 3 examples that avoid it.
+ *
+ * * Catches the Interrupt exception by pressed ^C after returns
+ * terminal status:
+ *
+ * require "readline"
+ *
+ * stty_save = `stty -g`.chomp
+ * begin
+ * while buf = Readline.readline
+ * p buf
+ * end
+ * rescue Interrupt
+ * system("stty", stty_save)
+ * exit
+ * end
+ * end
+ * end
+ *
+ * * Catches the INT signal by pressed ^C after returns terminal
+ * status:
+ *
+ * require "readline"
+ *
+ * stty_save = `stty -g`.chomp
+ * trap("INT") { system "stty", stty_save; exit }
+ *
+ * while buf = Readline.readline
+ * p buf
+ * end
+ *
+ * * Ignores pressing ^C:
+ *
+ * require "readline"
+ *
+ * trap("INT", "SIG_IGN")
+ *
+ * while buf = Readline.readline
+ * p buf
+ * end
+ *
+ * Can make as follows with Readline::HISTORY constant.
+ * It does not record to the history if the inputted line is empty or
+ * the same it as last one.
+ *
+ * require "readline"
+ *
+ * while buf = Readline.readline("> ", true)
+ * # p Readline::HISTORY.to_a
+ * Readline::HISTORY.pop if /^\s*$/ =~ buf
+ *
+ * begin
+ * if Readline::HISTORY[Readline::HISTORY.length-2] == buf
+ * Readline::HISTORY.pop
+ * end
+ * rescue IndexError
+ * end
+ *
+ * # p Readline::HISTORY.to_a
+ * print "-> ", buf, "\n"
+ * end
+ */
+static VALUE
+readline_readline(int argc, VALUE *argv, VALUE self)
+{
+ VALUE tmp, add_hist, result;
+ char *prompt = NULL;
+ char *buff;
+ int status;
+
+ if (rb_scan_args(argc, argv, "02", &tmp, &add_hist) > 0) {
+ OutputStringValue(tmp);
+#if USE_INSERT_IGNORE_ESCAPE
+ tmp = insert_ignore_escape(self, tmp);
+ rb_str_locktmp(tmp);
+#endif
+ prompt = RSTRING_PTR(tmp);
+ }
+
+ prepare_readline();
+
+#ifdef _WIN32
+ rl_prep_terminal(1);
+#endif
+ buff = (char*)rb_protect(readline_get, (VALUE)prompt, &status);
+#if USE_INSERT_IGNORE_ESCAPE
+ if (prompt) {
+ rb_str_unlocktmp(tmp);
+ }
+#endif
+ if (status) {
+#if defined HAVE_RL_CLEANUP_AFTER_SIGNAL
+ /* restore terminal mode and signal handler*/
+#if defined HAVE_RL_FREE_LINE_STATE
+ rl_free_line_state();
+#endif
+ rl_cleanup_after_signal();
+#elif defined HAVE_RL_DEPREP_TERM_FUNCTION
+ /* restore terminal mode */
+ if (rl_deprep_term_function != NULL) /* NULL in libedit. [ruby-dev:29116] */
+ (*rl_deprep_term_function)();
+ else
+#else
+ rl_deprep_terminal();
+#endif
+ rb_jump_tag(status);
+ }
+
+ if (RTEST(add_hist) && buff) {
+ add_history(buff);
+ }
+ if (buff) {
+ result = rb_locale_str_new_cstr(buff);
+ }
+ else
+ result = Qnil;
+ if (buff) free(buff);
+ return result;
+}
+
+/*
+ * call-seq:
+ * Readline.input = input
+ *
+ * Specifies a File object +input+ that is input stream for
+ * Readline.readline method.
+ */
+static VALUE
+readline_s_set_input(VALUE self, VALUE input)
+{
+ rb_io_t *ifp;
+ int fd;
+ FILE *f;
+
+ if (NIL_P(input)) {
+ clear_rl_instream();
+ }
+ else {
+ Check_Type(input, T_FILE);
+ GetOpenFile(input, ifp);
+ clear_rl_instream();
+ fd = rb_cloexec_dup(ifp->fd);
+ if (fd == -1)
+ rb_sys_fail("dup");
+ f = fdopen(fd, "r");
+ if (f == NULL) {
+ int save_errno = errno;
+ close(fd);
+ rb_syserr_fail(save_errno, "fdopen");
+ }
+ rl_instream = readline_rl_instream = f;
+ readline_instream = input;
+ }
+ return input;
+}
+
+/*
+ * call-seq:
+ * Readline.output = output
+ *
+ * Specifies a File object +output+ that is output stream for
+ * Readline.readline method.
+ */
+static VALUE
+readline_s_set_output(VALUE self, VALUE output)
+{
+ rb_io_t *ofp;
+ int fd;
+ FILE *f;
+
+ if (NIL_P(output)) {
+ clear_rl_outstream();
+ }
+ else {
+ Check_Type(output, T_FILE);
+ GetOpenFile(output, ofp);
+ clear_rl_outstream();
+ fd = rb_cloexec_dup(ofp->fd);
+ if (fd == -1)
+ rb_sys_fail("dup");
+ f = fdopen(fd, "w");
+ if (f == NULL) {
+ int save_errno = errno;
+ close(fd);
+ rb_syserr_fail(save_errno, "fdopen");
+ }
+ rl_outstream = readline_rl_outstream = f;
+ readline_outstream = output;
+ }
+ return output;
+}
+
+#if defined(HAVE_RL_PRE_INPUT_HOOK)
+/*
+ * call-seq:
+ * Readline.pre_input_hook = proc
+ *
+ * Specifies a Proc object +proc+ to call after the first prompt has
+ * been printed and just before readline starts reading input
+ * characters.
+ *
+ * See GNU Readline's rl_pre_input_hook variable.
+ *
+ * Raises ArgumentError if +proc+ does not respond to the call method.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_pre_input_hook(VALUE self, VALUE proc)
+{
+ mustbe_callable(proc);
+ return rb_ivar_set(mReadline, id_pre_input_hook, proc);
+}
+
+/*
+ * call-seq:
+ * Readline.pre_input_hook -> proc
+ *
+ * Returns a Proc object +proc+ to call after the first prompt has
+ * been printed and just before readline starts reading input
+ * characters. The default is nil.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_pre_input_hook(VALUE self)
+{
+ return rb_attr_get(mReadline, id_pre_input_hook);
+}
+
+static int
+readline_pre_input_hook(void)
+{
+ VALUE proc;
+
+ proc = rb_attr_get(mReadline, id_pre_input_hook);
+ if (!NIL_P(proc))
+ rb_funcall(proc, id_call, 0);
+ return 0;
+}
+#else
+#define readline_s_set_pre_input_hook rb_f_notimplement
+#define readline_s_get_pre_input_hook rb_f_notimplement
+#endif
+
+#if defined(HAVE_RL_INSERT_TEXT)
+/*
+ * call-seq:
+ * Readline.insert_text(string) -> self
+ *
+ * Insert text into the line at the current cursor position.
+ *
+ * See GNU Readline's rl_insert_text function.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_insert_text(VALUE self, VALUE str)
+{
+ OutputStringValue(str);
+ rl_insert_text(RSTRING_PTR(str));
+ return self;
+}
+#else
+#define readline_s_insert_text rb_f_notimplement
+#endif
+
+#if defined(HAVE_RL_DELETE_TEXT)
+RUBY_EXTERN int rl_delete_text(int, int);
+static const char *
+str_subpos(const char *ptr, const char *end, long beg, long *sublen, rb_encoding *enc)
+{
+ VALUE str = rb_enc_str_new_static(ptr, end-ptr, enc);
+ OBJ_FREEZE(str);
+ ptr = rb_str_subpos(str, beg, sublen);
+ return ptr;
+}
+
+/*
+ * call-seq:
+ * Readline.delete_text([start[, length]]) -> self
+ * Readline.delete_text(start..end) -> self
+ * Readline.delete_text() -> self
+ *
+ * Delete text between start and end in the current line.
+ *
+ * See GNU Readline's rl_delete_text function.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_delete_text(int argc, VALUE *argv, VALUE self)
+{
+ rb_check_arity(argc, 0, 2);
+ if (rl_line_buffer) {
+ const char *p, *ptr = rl_line_buffer;
+ long beg = 0, len = strlen(ptr);
+ const char *end = ptr + len;
+ rb_encoding *enc = rb_locale_encoding();
+ if (argc == 2) {
+ beg = NUM2LONG(argv[0]);
+ len = NUM2LONG(argv[1]);
+ num_pos:
+ p = str_subpos(ptr, end, beg, &len, enc);
+ if (!p) rb_raise(rb_eArgError, "invalid index");
+ beg = p - ptr;
+ }
+ else if (argc == 1) {
+ len = rb_enc_strlen(ptr, ptr + len, enc);
+ if (!rb_range_beg_len(argv[0], &beg, &len, len, 1)) {
+ beg = NUM2LONG(argv[0]);
+ goto num_pos;
+ }
+ }
+ rl_delete_text(rb_long2int(beg), rb_long2int(beg + len));
+ }
+ return self;
+}
+#else
+#define readline_s_delete_text rb_f_notimplement
+#endif
+
+#if defined(HAVE_RL_REDISPLAY)
+/*
+ * call-seq:
+ * Readline.redisplay -> self
+ *
+ * Change what's displayed on the screen to reflect the current
+ * contents.
+ *
+ * See GNU Readline's rl_redisplay function.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_redisplay(VALUE self)
+{
+ rl_redisplay();
+ return self;
+}
+#else
+#define readline_s_redisplay rb_f_notimplement
+#endif
+
+/*
+ * call-seq:
+ * Readline.completion_proc = proc
+ *
+ * Specifies a Proc object +proc+ to determine completion behavior. It
+ * should take input string and return an array of completion candidates.
+ *
+ * The default completion is used if +proc+ is nil.
+ *
+ * The String that is passed to the Proc depends on the
+ * Readline.completer_word_break_characters property. By default the word
+ * under the cursor is passed to the Proc. For example, if the input is "foo
+ * bar" then only "bar" would be passed to the completion Proc.
+ *
+ * Upon successful completion the Readline.completion_append_character will be
+ * appended to the input so the user can start working on their next argument.
+ *
+ * = Examples
+ *
+ * == Completion for a Static List
+ *
+ * require 'readline'
+ *
+ * LIST = [
+ * 'search', 'download', 'open',
+ * 'help', 'history', 'quit',
+ * 'url', 'next', 'clear',
+ * 'prev', 'past'
+ * ].sort
+ *
+ * comp = proc { |s| LIST.grep(/^#{Regexp.escape(s)}/) }
+ *
+ * Readline.completion_append_character = " "
+ * Readline.completion_proc = comp
+ *
+ * while line = Readline.readline('> ', true)
+ * p line
+ * end
+ *
+ * == Completion For Directory Contents
+ *
+ * require 'readline'
+ *
+ * Readline.completion_append_character = " "
+ * Readline.completion_proc = Proc.new do |str|
+ * Dir[str+'*'].grep(/^#{Regexp.escape(str)}/)
+ * end
+ *
+ * while line = Readline.readline('> ', true)
+ * p line
+ * end
+ *
+ * = Autocomplete strategies
+ *
+ * When working with auto-complete there are some strategies that work well.
+ * To get some ideas you can take a look at the
+ * completion.rb[https://git.ruby-lang.org/ruby.git/tree/lib/irb/completion.rb]
+ * file for irb.
+ *
+ * The common strategy is to take a list of possible completions and filter it
+ * down to those completions that start with the user input. In the above
+ * examples Enumerator.grep is used. The input is escaped to prevent Regexp
+ * special characters from interfering with the matching.
+ *
+ * It may also be helpful to use the Abbrev library to generate completions.
+ *
+ * Raises ArgumentError if +proc+ does not respond to the call method.
+ */
+static VALUE
+readline_s_set_completion_proc(VALUE self, VALUE proc)
+{
+ mustbe_callable(proc);
+ return rb_ivar_set(mReadline, completion_proc, proc);
+}
+
+/*
+ * call-seq:
+ * Readline.completion_proc -> proc
+ *
+ * Returns the completion Proc object.
+ */
+static VALUE
+readline_s_get_completion_proc(VALUE self)
+{
+ return rb_attr_get(mReadline, completion_proc);
+}
+
+#ifdef HAVE_RL_CHAR_IS_QUOTED_P
+/*
+ * call-seq:
+ * Readline.quoting_detection_proc = proc
+ *
+ * Specifies a Proc object +proc+ to determine if a character in the user's
+ * input is escaped. It should take the user's input and the index of the
+ * character in question as input, and return a boolean (true if the specified
+ * character is escaped).
+ *
+ * Readline will only call this proc with characters specified in
+ * +completer_quote_characters+, to discover if they indicate the end of a
+ * quoted argument, or characters specified in
+ * +completer_word_break_characters+, to discover if they indicate a break
+ * between arguments.
+ *
+ * If +completer_quote_characters+ is not set, or if the user input doesn't
+ * contain one of the +completer_quote_characters+ or a +\+ character,
+ * Readline will not attempt to use this proc at all.
+ *
+ * Raises ArgumentError if +proc+ does not respond to the call method.
+ */
+static VALUE
+readline_s_set_quoting_detection_proc(VALUE self, VALUE proc)
+{
+ mustbe_callable(proc);
+ return rb_ivar_set(mReadline, quoting_detection_proc, proc);
+}
+
+/*
+ * call-seq:
+ * Readline.quoting_detection_proc -> proc
+ *
+ * Returns the quoting detection Proc object.
+ */
+static VALUE
+readline_s_get_quoting_detection_proc(VALUE self)
+{
+ return rb_attr_get(mReadline, quoting_detection_proc);
+}
+#else
+#define readline_s_set_quoting_detection_proc rb_f_notimplement
+#define readline_s_get_quoting_detection_proc rb_f_notimplement
+#endif
+
+/*
+ * call-seq:
+ * Readline.completion_case_fold = bool
+ *
+ * Sets whether or not to ignore case on completion.
+ */
+static VALUE
+readline_s_set_completion_case_fold(VALUE self, VALUE val)
+{
+ return rb_ivar_set(mReadline, completion_case_fold, val);
+}
+
+/*
+ * call-seq:
+ * Readline.completion_case_fold -> bool
+ *
+ * Returns true if completion ignores case. If no, returns false.
+ *
+ * NOTE: Returns the same object that is specified by
+ * Readline.completion_case_fold= method.
+ *
+ * require "readline"
+ *
+ * Readline.completion_case_fold = "This is a String."
+ * p Readline.completion_case_fold # => "This is a String."
+ */
+static VALUE
+readline_s_get_completion_case_fold(VALUE self)
+{
+ return rb_attr_get(mReadline, completion_case_fold);
+}
+
+#ifdef HAVE_RL_LINE_BUFFER
+/*
+ * call-seq:
+ * Readline.line_buffer -> string
+ *
+ * Returns the full line that is being edited. This is useful from
+ * within the complete_proc for determining the context of the
+ * completion request.
+ *
+ * The length of +Readline.line_buffer+ and GNU Readline's rl_end are
+ * same.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_line_buffer(VALUE self)
+{
+ if (rl_line_buffer == NULL)
+ return Qnil;
+ return rb_locale_str_new_cstr(rl_line_buffer);
+}
+#else
+#define readline_s_get_line_buffer rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_POINT
+/*
+ * call-seq:
+ * Readline.point -> int
+ *
+ * Returns the index of the current cursor position in
+ * +Readline.line_buffer+.
+ *
+ * The index in +Readline.line_buffer+ which matches the start of
+ * input-string passed to completion_proc is computed by subtracting
+ * the length of input-string from +Readline.point+.
+ *
+ * start = (the length of input-string) - Readline.point
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_point(VALUE self)
+{
+ return INT2NUM(rl_point);
+}
+
+/*
+ * call-seq:
+ * Readline.point = int
+ *
+ * Set the index of the current cursor position in
+ * +Readline.line_buffer+.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ *
+ * See +Readline.point+.
+ */
+static VALUE
+readline_s_set_point(VALUE self, VALUE pos)
+{
+ rl_point = NUM2INT(pos);
+ return pos;
+}
+#else
+#define readline_s_get_point rb_f_notimplement
+#define readline_s_set_point rb_f_notimplement
+#endif
+
+static char **
+readline_attempted_completion_function(const char *text, int start, int end)
+{
+ VALUE proc, ary, temp;
+ char **result;
+ int case_fold;
+ long i, matches;
+ rb_encoding *enc;
+ VALUE encobj;
+
+ proc = rb_attr_get(mReadline, completion_proc);
+ if (NIL_P(proc))
+ return NULL;
+#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
+ rl_completion_append_character = readline_completion_append_character;
+#endif
+#ifdef HAVE_RL_ATTEMPTED_COMPLETION_OVER
+ rl_attempted_completion_over = 1;
+#endif
+ case_fold = RTEST(rb_attr_get(mReadline, completion_case_fold));
+ ary = rb_funcall(proc, id_call, 1, rb_locale_str_new_cstr(text));
+ if (!RB_TYPE_P(ary, T_ARRAY))
+ ary = rb_Array(ary);
+ matches = RARRAY_LEN(ary);
+ if (matches == 0) return NULL;
+ result = (char**)malloc((matches + 2)*sizeof(char*));
+ if (result == NULL) rb_memerror();
+ enc = rb_locale_encoding();
+ encobj = rb_enc_from_encoding(enc);
+ for (i = 0; i < matches; i++) {
+ temp = rb_obj_as_string(RARRAY_AREF(ary, i));
+ StringValueCStr(temp); /* must be NUL-terminated */
+ rb_enc_check(encobj, temp);
+ result[i + 1] = (char*)malloc(RSTRING_LEN(temp) + 1);
+ if (result[i + 1] == NULL) rb_memerror();
+ strcpy(result[i + 1], RSTRING_PTR(temp));
+ }
+ result[matches + 1] = NULL;
+
+ if (matches == 1) {
+ result[0] = strdup(result[1]);
+ }
+ else {
+ const char *result1 = result[1];
+ long low = strlen(result1);
+
+ for (i = 1; i < matches; ++i) {
+ register int c1, c2;
+ long i1, i2, l2;
+ int n1, n2;
+ const char *p2 = result[i + 1];
+
+ l2 = strlen(p2);
+ for (i1 = i2 = 0; i1 < low && i2 < l2; i1 += n1, i2 += n2) {
+ c1 = rb_enc_codepoint_len(result1 + i1, result1 + low, &n1, enc);
+ c2 = rb_enc_codepoint_len(p2 + i2, p2 + l2, &n2, enc);
+ if (case_fold) {
+ c1 = rb_tolower(c1);
+ c2 = rb_tolower(c2);
+ }
+ if (c1 != c2) break;
+ }
+
+ low = i1;
+ }
+ result[0] = (char*)malloc(low + 1);
+ if (result[0] == NULL) rb_memerror();
+ strncpy(result[0], result[1], low);
+ result[0][low] = '\0';
+ }
+
+ return result;
+}
+
+#ifdef HAVE_RL_CHAR_IS_QUOTED_P
+static int
+readline_char_is_quoted(char *text, int byte_index)
+{
+ VALUE proc, result, str;
+ long char_index;
+ size_t len;
+
+ proc = rb_attr_get(mReadline, quoting_detection_proc);
+ if (NIL_P(proc)) {
+ return 0;
+ }
+
+ len = strlen(text);
+ if (byte_index < 0 || len < (size_t)byte_index) {
+ rb_raise(rb_eIndexError, "invalid byte index (%d in %"PRIdSIZE")",
+ byte_index, len);
+ }
+
+ str = rb_locale_str_new(text, len);
+ char_index = rb_str_sublen(str, byte_index);
+ result = rb_funcall(proc, id_call, 2, str, LONG2FIX(char_index));
+ return RTEST(result);
+}
+#endif
+
+#ifdef HAVE_RL_SET_SCREEN_SIZE
+/*
+ * call-seq:
+ * Readline.set_screen_size(rows, columns) -> self
+ *
+ * Set terminal size to +rows+ and +columns+.
+ *
+ * See GNU Readline's rl_set_screen_size function.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_screen_size(VALUE self, VALUE rows, VALUE columns)
+{
+ rl_set_screen_size(NUM2INT(rows), NUM2INT(columns));
+ return self;
+}
+#else
+#define readline_s_set_screen_size rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_GET_SCREEN_SIZE
+/*
+ * call-seq:
+ * Readline.get_screen_size -> [rows, columns]
+ *
+ * Returns the terminal's rows and columns.
+ *
+ * See GNU Readline's rl_get_screen_size function.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_screen_size(VALUE self)
+{
+ int rows, columns;
+ VALUE res;
+
+ rl_get_screen_size(&rows, &columns);
+ res = rb_ary_new();
+ rb_ary_push(res, INT2NUM(rows));
+ rb_ary_push(res, INT2NUM(columns));
+ return res;
+}
+#else
+#define readline_s_get_screen_size rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_VI_EDITING_MODE
+RUBY_EXTERN int rl_vi_editing_mode(int, int);
+/*
+ * call-seq:
+ * Readline.vi_editing_mode -> nil
+ *
+ * Specifies VI editing mode. See the manual of GNU Readline for
+ * details of VI editing mode.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_vi_editing_mode(VALUE self)
+{
+ rl_vi_editing_mode(1,0);
+ return Qnil;
+}
+#else
+#define readline_s_vi_editing_mode rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_EDITING_MODE
+/*
+ * call-seq:
+ * Readline.vi_editing_mode? -> bool
+ *
+ * Returns true if vi mode is active. Returns false if not.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_vi_editing_mode_p(VALUE self)
+{
+ return rl_editing_mode == 0 ? Qtrue : Qfalse;
+}
+#else
+#define readline_s_vi_editing_mode_p rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_EMACS_EDITING_MODE
+RUBY_EXTERN int rl_emacs_editing_mode(int, int);
+/*
+ * call-seq:
+ * Readline.emacs_editing_mode -> nil
+ *
+ * Specifies Emacs editing mode. The default is this mode. See the
+ * manual of GNU Readline for details of Emacs editing mode.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_emacs_editing_mode(VALUE self)
+{
+ rl_emacs_editing_mode(1,0);
+ return Qnil;
+}
+#else
+#define readline_s_emacs_editing_mode rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_EDITING_MODE
+/*
+ * call-seq:
+ * Readline.emacs_editing_mode? -> bool
+ *
+ * Returns true if emacs mode is active. Returns false if not.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_emacs_editing_mode_p(VALUE self)
+{
+ return rl_editing_mode == 1 ? Qtrue : Qfalse;
+}
+#else
+#define readline_s_emacs_editing_mode_p rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
+/*
+ * call-seq:
+ * Readline.completion_append_character = char
+ *
+ * Specifies a character to be appended on completion.
+ * Nothing will be appended if an empty string ("") or nil is
+ * specified.
+ *
+ * For example:
+ * require "readline"
+ *
+ * Readline.readline("> ", true)
+ * Readline.completion_append_character = " "
+ *
+ * Result:
+ * >
+ * Input "/var/li".
+ *
+ * > /var/li
+ * Press TAB key.
+ *
+ * > /var/lib
+ * Completes "b" and appends " ". So, you can continuously input "/usr".
+ *
+ * > /var/lib /usr
+ *
+ * NOTE: Only one character can be specified. When "string" is
+ * specified, sets only "s" that is the first.
+ *
+ * require "readline"
+ *
+ * Readline.completion_append_character = "string"
+ * p Readline.completion_append_character # => "s"
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_completion_append_character(VALUE self, VALUE str)
+{
+ if (NIL_P(str)) {
+ rl_completion_append_character = '\0';
+ }
+ else {
+ OutputStringValue(str);
+ if (RSTRING_LEN(str) == 0) {
+ rl_completion_append_character = '\0';
+ } else {
+ rl_completion_append_character = RSTRING_PTR(str)[0];
+ }
+ }
+ return self;
+}
+#else
+#define readline_s_set_completion_append_character rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
+/*
+ * call-seq:
+ * Readline.completion_append_character -> char
+ *
+ * Returns a string containing a character to be appended on
+ * completion. The default is a space (" ").
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_completion_append_character(VALUE self)
+{
+ char buf[1];
+
+ if (rl_completion_append_character == '\0')
+ return Qnil;
+
+ buf[0] = (char) rl_completion_append_character;
+ return rb_locale_str_new(buf, 1);
+}
+#else
+#define readline_s_get_completion_append_character rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETION_QUOTE_CHARACTER
+/*
+ * call-seq:
+ * Readline.completion_quote_character -> char
+ *
+ * When called during a completion (e.g. from within your completion_proc),
+ * it will return a string containing the character used to quote the
+ * argument being completed, or nil if the argument is unquoted.
+ *
+ * When called at other times, it will always return nil.
+ *
+ * Note that Readline.completer_quote_characters must be set,
+ * or this method will always return nil.
+ */
+static VALUE
+readline_s_get_completion_quote_character(VALUE self)
+{
+ char buf[1];
+
+ if (rl_completion_quote_character == '\0')
+ return Qnil;
+
+ buf[0] = (char) rl_completion_quote_character;
+ return rb_locale_str_new(buf, 1);
+}
+#else
+#define readline_s_get_completion_quote_character rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_BASIC_WORD_BREAK_CHARACTERS
+/*
+ * call-seq:
+ * Readline.basic_word_break_characters = string
+ *
+ * Sets the basic list of characters that signal a break between words
+ * for the completer routine. The default is the characters which
+ * break words for completion in Bash: " \t\n\"\\'`@$><=;|&{(".
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_basic_word_break_characters(VALUE self, VALUE str)
+{
+ static char *basic_word_break_characters = NULL;
+
+ OutputStringValue(str);
+ if (basic_word_break_characters == NULL) {
+ basic_word_break_characters =
+ ALLOC_N(char, RSTRING_LEN(str) + 1);
+ }
+ else {
+ REALLOC_N(basic_word_break_characters, char, RSTRING_LEN(str) + 1);
+ }
+ strncpy(basic_word_break_characters,
+ RSTRING_PTR(str), RSTRING_LEN(str));
+ basic_word_break_characters[RSTRING_LEN(str)] = '\0';
+ rl_basic_word_break_characters = basic_word_break_characters;
+ return self;
+}
+#else
+#define readline_s_set_basic_word_break_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_BASIC_WORD_BREAK_CHARACTERS
+/*
+ * call-seq:
+ * Readline.basic_word_break_characters -> string
+ *
+ * Gets the basic list of characters that signal a break between words
+ * for the completer routine.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_basic_word_break_characters(VALUE self)
+{
+ if (rl_basic_word_break_characters == NULL)
+ return Qnil;
+ return rb_locale_str_new_cstr(rl_basic_word_break_characters);
+}
+#else
+#define readline_s_get_basic_word_break_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS
+/*
+ * call-seq:
+ * Readline.completer_word_break_characters = string
+ *
+ * Sets the basic list of characters that signal a break between words
+ * for rl_complete_internal(). The default is the value of
+ * Readline.basic_word_break_characters.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_completer_word_break_characters(VALUE self, VALUE str)
+{
+ static char *completer_word_break_characters = NULL;
+
+ OutputStringValue(str);
+ if (completer_word_break_characters == NULL) {
+ completer_word_break_characters =
+ ALLOC_N(char, RSTRING_LEN(str) + 1);
+ }
+ else {
+ REALLOC_N(completer_word_break_characters, char, RSTRING_LEN(str) + 1);
+ }
+ strncpy(completer_word_break_characters,
+ RSTRING_PTR(str), RSTRING_LEN(str));
+ completer_word_break_characters[RSTRING_LEN(str)] = '\0';
+ rl_completer_word_break_characters = completer_word_break_characters;
+ return self;
+}
+#else
+#define readline_s_set_completer_word_break_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS
+/*
+ * call-seq:
+ * Readline.completer_word_break_characters -> string
+ *
+ * Gets the basic list of characters that signal a break between words
+ * for rl_complete_internal().
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_completer_word_break_characters(VALUE self)
+{
+ if (rl_completer_word_break_characters == NULL)
+ return Qnil;
+ return rb_locale_str_new_cstr(rl_completer_word_break_characters);
+}
+#else
+#define readline_s_get_completer_word_break_characters rb_f_notimplement
+#endif
+
+#if defined(HAVE_RL_SPECIAL_PREFIXES)
+/*
+ * call-seq:
+ * Readline.special_prefixes = string
+ *
+ * Sets the list of characters that are word break characters, but
+ * should be left in text when it is passed to the completion
+ * function. Programs can use this to help determine what kind of
+ * completing to do. For instance, Bash sets this variable to "$@" so
+ * that it can complete shell variables and hostnames.
+ *
+ * See GNU Readline's rl_special_prefixes variable.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_special_prefixes(VALUE self, VALUE str)
+{
+ if (!NIL_P(str)) {
+ OutputStringValue(str);
+ str = rb_str_dup_frozen(str);
+ rb_obj_hide(str);
+ }
+ rb_ivar_set(mReadline, id_special_prefixes, str);
+ if (NIL_P(str)) {
+ rl_special_prefixes = NULL;
+ }
+ else {
+ rl_special_prefixes = RSTRING_PTR(str);
+ }
+ return self;
+}
+
+/*
+ * call-seq:
+ * Readline.special_prefixes -> string
+ *
+ * Gets the list of characters that are word break characters, but
+ * should be left in text when it is passed to the completion
+ * function.
+ *
+ * See GNU Readline's rl_special_prefixes variable.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_special_prefixes(VALUE self)
+{
+ VALUE str;
+ if (rl_special_prefixes == NULL) return Qnil;
+ str = rb_ivar_get(mReadline, id_special_prefixes);
+ if (!NIL_P(str)) {
+ str = rb_str_dup_frozen(str);
+ rb_obj_reveal(str, rb_cString);
+ }
+ return str;
+}
+#else
+#define readline_s_set_special_prefixes rb_f_notimplement
+#define readline_s_get_special_prefixes rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_BASIC_QUOTE_CHARACTERS
+/*
+ * call-seq:
+ * Readline.basic_quote_characters = string
+ *
+ * Sets a list of quote characters which can cause a word break.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_basic_quote_characters(VALUE self, VALUE str)
+{
+ static char *basic_quote_characters = NULL;
+
+ OutputStringValue(str);
+ if (basic_quote_characters == NULL) {
+ basic_quote_characters =
+ ALLOC_N(char, RSTRING_LEN(str) + 1);
+ }
+ else {
+ REALLOC_N(basic_quote_characters, char, RSTRING_LEN(str) + 1);
+ }
+ strncpy(basic_quote_characters,
+ RSTRING_PTR(str), RSTRING_LEN(str));
+ basic_quote_characters[RSTRING_LEN(str)] = '\0';
+ rl_basic_quote_characters = basic_quote_characters;
+
+ return self;
+}
+#else
+#define readline_s_set_basic_quote_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_BASIC_QUOTE_CHARACTERS
+/*
+ * call-seq:
+ * Readline.basic_quote_characters -> string
+ *
+ * Gets a list of quote characters which can cause a word break.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_basic_quote_characters(VALUE self)
+{
+ if (rl_basic_quote_characters == NULL)
+ return Qnil;
+ return rb_locale_str_new_cstr(rl_basic_quote_characters);
+}
+#else
+#define readline_s_get_basic_quote_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETER_QUOTE_CHARACTERS
+/*
+ * call-seq:
+ * Readline.completer_quote_characters = string
+ *
+ * Sets a list of characters which can be used to quote a substring of
+ * the line. Completion occurs on the entire substring, and within
+ * the substring Readline.completer_word_break_characters are treated
+ * as any other character, unless they also appear within this list.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_completer_quote_characters(VALUE self, VALUE str)
+{
+ static char *completer_quote_characters = NULL;
+
+ OutputStringValue(str);
+ if (completer_quote_characters == NULL) {
+ completer_quote_characters =
+ ALLOC_N(char, RSTRING_LEN(str) + 1);
+ }
+ else {
+ REALLOC_N(completer_quote_characters, char, RSTRING_LEN(str) + 1);
+ }
+ strncpy(completer_quote_characters, RSTRING_PTR(str), RSTRING_LEN(str));
+ completer_quote_characters[RSTRING_LEN(str)] = '\0';
+ rl_completer_quote_characters = completer_quote_characters;
+
+ return self;
+}
+#else
+#define readline_s_set_completer_quote_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_COMPLETER_QUOTE_CHARACTERS
+/*
+ * call-seq:
+ * Readline.completer_quote_characters -> string
+ *
+ * Gets a list of characters which can be used to quote a substring of
+ * the line.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_completer_quote_characters(VALUE self)
+{
+ if (rl_completer_quote_characters == NULL)
+ return Qnil;
+ return rb_locale_str_new_cstr(rl_completer_quote_characters);
+}
+#else
+#define readline_s_get_completer_quote_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_FILENAME_QUOTE_CHARACTERS
+/*
+ * call-seq:
+ * Readline.filename_quote_characters = string
+ *
+ * Sets a list of characters that cause a filename to be quoted by the completer
+ * when they appear in a completed filename. The default is nil.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_set_filename_quote_characters(VALUE self, VALUE str)
+{
+ static char *filename_quote_characters = NULL;
+
+ OutputStringValue(str);
+ if (filename_quote_characters == NULL) {
+ filename_quote_characters =
+ ALLOC_N(char, RSTRING_LEN(str) + 1);
+ }
+ else {
+ REALLOC_N(filename_quote_characters, char, RSTRING_LEN(str) + 1);
+ }
+ strncpy(filename_quote_characters, RSTRING_PTR(str), RSTRING_LEN(str));
+ filename_quote_characters[RSTRING_LEN(str)] = '\0';
+ rl_filename_quote_characters = filename_quote_characters;
+
+ return self;
+}
+#else
+#define readline_s_set_filename_quote_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_FILENAME_QUOTE_CHARACTERS
+/*
+ * call-seq:
+ * Readline.filename_quote_characters -> string
+ *
+ * Gets a list of characters that cause a filename to be quoted by the completer
+ * when they appear in a completed filename.
+ *
+ * Raises NotImplementedError if the using readline library does not support.
+ */
+static VALUE
+readline_s_get_filename_quote_characters(VALUE self)
+{
+ if (rl_filename_quote_characters == NULL)
+ return Qnil;
+ return rb_locale_str_new_cstr(rl_filename_quote_characters);
+}
+#else
+#define readline_s_get_filename_quote_characters rb_f_notimplement
+#endif
+
+#ifdef HAVE_RL_REFRESH_LINE
+RUBY_EXTERN int rl_refresh_line(int, int);
+/*
+ * call-seq:
+ * Readline.refresh_line -> nil
+ *
+ * Clear the current input line.
+ */
+static VALUE
+readline_s_refresh_line(VALUE self)
+{
+ prepare_readline();
+ rl_refresh_line(0, 0);
+ return Qnil;
+}
+#else
+#define readline_s_refresh_line rb_f_notimplement
+#endif
+
+static VALUE
+hist_to_s(VALUE self)
+{
+ return rb_str_new_cstr("HISTORY");
+}
+
+static int
+history_get_offset_history_base(int offset)
+{
+ return history_base + offset;
+}
+
+static int
+history_get_offset_0(int offset)
+{
+ return offset;
+}
+
+static VALUE
+hist_get(VALUE self, VALUE index)
+{
+ HIST_ENTRY *entry = NULL;
+ int i;
+
+ i = NUM2INT(index);
+ if (i < 0) {
+ i += history_length;
+ }
+ if (i >= 0) {
+ entry = history_get(history_get_offset_func(i));
+ }
+ if (entry == NULL) {
+ rb_raise(rb_eIndexError, "invalid index");
+ }
+ return rb_locale_str_new_cstr(entry->line);
+}
+
+#ifdef HAVE_REPLACE_HISTORY_ENTRY
+static VALUE
+hist_set(VALUE self, VALUE index, VALUE str)
+{
+ HIST_ENTRY *entry = NULL;
+ int i;
+
+ i = NUM2INT(index);
+ OutputStringValue(str);
+ if (i < 0) {
+ i += history_length;
+ }
+ if (i >= 0) {
+ entry = replace_history_entry(history_replace_offset_func(i), RSTRING_PTR(str), NULL);
+ }
+ if (entry == NULL) {
+ rb_raise(rb_eIndexError, "invalid index");
+ }
+ return str;
+}
+#else
+#define hist_set rb_f_notimplement
+#endif
+
+static VALUE
+hist_push(VALUE self, VALUE str)
+{
+ OutputStringValue(str);
+ add_history(RSTRING_PTR(str));
+ return self;
+}
+
+static VALUE
+hist_push_method(int argc, VALUE *argv, VALUE self)
+{
+ VALUE str;
+
+ while (argc--) {
+ str = *argv++;
+ OutputStringValue(str);
+ add_history(RSTRING_PTR(str));
+ }
+ return self;
+}
+
+static VALUE
+rb_remove_history(int index)
+{
+#ifdef HAVE_REMOVE_HISTORY
+ HIST_ENTRY *entry;
+ VALUE val;
+
+ entry = remove_history(index);
+ if (entry) {
+ val = rb_locale_str_new_cstr(entry->line);
+ free((void *) entry->line);
+ free(entry);
+ return val;
+ }
+ return Qnil;
+#else
+ rb_notimplement();
+
+ UNREACHABLE_RETURN(Qnil);
+#endif
+}
+
+static VALUE
+hist_pop(VALUE self)
+{
+ if (history_length > 0) {
+ return rb_remove_history(history_length - 1);
+ } else {
+ return Qnil;
+ }
+}
+
+static VALUE
+hist_shift(VALUE self)
+{
+ if (history_length > 0) {
+ return rb_remove_history(0);
+ } else {
+ return Qnil;
+ }
+}
+
+static VALUE
+hist_each(VALUE self)
+{
+ HIST_ENTRY *entry;
+ int i;
+
+ RETURN_ENUMERATOR(self, 0, 0);
+
+ for (i = 0; i < history_length; i++) {
+ entry = history_get(history_get_offset_func(i));
+ if (entry == NULL)
+ break;
+ rb_yield(rb_locale_str_new_cstr(entry->line));
+ }
+ return self;
+}
+
+static VALUE
+hist_length(VALUE self)
+{
+ return INT2NUM(history_length);
+}
+
+static VALUE
+hist_empty_p(VALUE self)
+{
+ return history_length == 0 ? Qtrue : Qfalse;
+}
+
+static VALUE
+hist_delete_at(VALUE self, VALUE index)
+{
+ int i;
+
+ i = NUM2INT(index);
+ if (i < 0)
+ i += history_length;
+ if (i < 0 || i > history_length - 1) {
+ rb_raise(rb_eIndexError, "invalid index");
+ }
+ return rb_remove_history(i);
+}
+
+#ifdef HAVE_CLEAR_HISTORY
+static VALUE
+hist_clear(VALUE self)
+{
+ clear_history();
+ return self;
+}
+#else
+#define hist_clear rb_f_notimplement
+#endif
+
+static VALUE
+filename_completion_proc_call(VALUE self, VALUE str)
+{
+ VALUE result;
+ char **matches;
+ int i;
+
+ matches = rl_completion_matches(StringValuePtr(str),
+ rl_filename_completion_function);
+ if (matches) {
+ result = rb_ary_new();
+ for (i = 0; matches[i]; i++) {
+ rb_ary_push(result, rb_locale_str_new_cstr(matches[i]));
+ free(matches[i]);
+ }
+ free(matches);
+ if (RARRAY_LEN(result) >= 2)
+ rb_ary_shift(result);
+ }
+ else {
+ result = Qnil;
+ }
+ return result;
+}
+
+static VALUE
+username_completion_proc_call(VALUE self, VALUE str)
+{
+ VALUE result;
+ char **matches;
+ int i;
+
+ matches = rl_completion_matches(StringValuePtr(str),
+ rl_username_completion_function);
+ if (matches) {
+ result = rb_ary_new();
+ for (i = 0; matches[i]; i++) {
+ rb_ary_push(result, rb_locale_str_new_cstr(matches[i]));
+ free(matches[i]);
+ }
+ free(matches);
+ if (RARRAY_LEN(result) >= 2)
+ rb_ary_shift(result);
+ }
+ else {
+ result = Qnil;
+ }
+ return result;
+}
+
+#ifdef HAVE_RL_CATCH_SIGNALS
+RUBY_EXTERN int rl_catch_signals;
+#endif
+#ifdef HAVE_RL_CLEAR_SIGNALS
+RUBY_EXTERN int rl_clear_signals(void);
+#endif
+
+#undef rb_intern
+void
+Init_readline(void)
+{
+ VALUE history, fcomp, ucomp, version;
+
+ /* Allow conditional parsing of the ~/.inputrc file. */
+ rl_readline_name = (char *)"Ruby";
+
+#if defined HAVE_RL_GETC_FUNCTION
+ /* libedit check rl_getc_function only when rl_initialize() is called, */
+ /* and using_history() call rl_initialize(). */
+ /* This assignment should be placed before using_history() */
+ rl_getc_function = readline_getc;
+#elif defined HAVE_RL_EVENT_HOOK
+ rl_event_hook = readline_event;
+#endif
+
+ using_history();
+
+ id_call = rb_intern("call");
+ completion_proc = rb_intern(COMPLETION_PROC);
+ completion_case_fold = rb_intern(COMPLETION_CASE_FOLD);
+#if defined(HAVE_RL_PRE_INPUT_HOOK)
+ id_pre_input_hook = rb_intern("pre_input_hook");
+#endif
+#if defined(HAVE_RL_SPECIAL_PREFIXES)
+ id_special_prefixes = rb_intern("special_prefixes");
+#endif
+#if defined HAVE_RL_CHAR_IS_QUOTED_P
+ quoting_detection_proc = rb_intern(QUOTING_DETECTION_PROC);
+#endif
+
+ mReadline = rb_define_module("Readline");
+ rb_define_module_function(mReadline, "readline",
+ readline_readline, -1);
+ rb_define_singleton_method(mReadline, "input=",
+ readline_s_set_input, 1);
+ rb_define_singleton_method(mReadline, "output=",
+ readline_s_set_output, 1);
+ rb_define_singleton_method(mReadline, "completion_proc=",
+ readline_s_set_completion_proc, 1);
+ rb_define_singleton_method(mReadline, "completion_proc",
+ readline_s_get_completion_proc, 0);
+ rb_define_singleton_method(mReadline, "quoting_detection_proc=",
+ readline_s_set_quoting_detection_proc, 1);
+ rb_define_singleton_method(mReadline, "quoting_detection_proc",
+ readline_s_get_quoting_detection_proc, 0);
+ rb_define_singleton_method(mReadline, "completion_case_fold=",
+ readline_s_set_completion_case_fold, 1);
+ rb_define_singleton_method(mReadline, "completion_case_fold",
+ readline_s_get_completion_case_fold, 0);
+ rb_define_singleton_method(mReadline, "line_buffer",
+ readline_s_get_line_buffer, 0);
+ rb_define_singleton_method(mReadline, "point",
+ readline_s_get_point, 0);
+ rb_define_singleton_method(mReadline, "point=",
+ readline_s_set_point, 1);
+ rb_define_singleton_method(mReadline, "set_screen_size",
+ readline_s_set_screen_size, 2);
+ rb_define_singleton_method(mReadline, "get_screen_size",
+ readline_s_get_screen_size, 0);
+ rb_define_singleton_method(mReadline, "vi_editing_mode",
+ readline_s_vi_editing_mode, 0);
+ rb_define_singleton_method(mReadline, "vi_editing_mode?",
+ readline_s_vi_editing_mode_p, 0);
+ rb_define_singleton_method(mReadline, "emacs_editing_mode",
+ readline_s_emacs_editing_mode, 0);
+ rb_define_singleton_method(mReadline, "emacs_editing_mode?",
+ readline_s_emacs_editing_mode_p, 0);
+ rb_define_singleton_method(mReadline, "completion_append_character=",
+ readline_s_set_completion_append_character, 1);
+ rb_define_singleton_method(mReadline, "completion_append_character",
+ readline_s_get_completion_append_character, 0);
+ rb_define_singleton_method(mReadline, "completion_quote_character",
+ readline_s_get_completion_quote_character, 0);
+ rb_define_singleton_method(mReadline, "basic_word_break_characters=",
+ readline_s_set_basic_word_break_characters, 1);
+ rb_define_singleton_method(mReadline, "basic_word_break_characters",
+ readline_s_get_basic_word_break_characters, 0);
+ rb_define_singleton_method(mReadline, "completer_word_break_characters=",
+ readline_s_set_completer_word_break_characters, 1);
+ rb_define_singleton_method(mReadline, "completer_word_break_characters",
+ readline_s_get_completer_word_break_characters, 0);
+ rb_define_singleton_method(mReadline, "basic_quote_characters=",
+ readline_s_set_basic_quote_characters, 1);
+ rb_define_singleton_method(mReadline, "basic_quote_characters",
+ readline_s_get_basic_quote_characters, 0);
+ rb_define_singleton_method(mReadline, "completer_quote_characters=",
+ readline_s_set_completer_quote_characters, 1);
+ rb_define_singleton_method(mReadline, "completer_quote_characters",
+ readline_s_get_completer_quote_characters, 0);
+ rb_define_singleton_method(mReadline, "filename_quote_characters=",
+ readline_s_set_filename_quote_characters, 1);
+ rb_define_singleton_method(mReadline, "filename_quote_characters",
+ readline_s_get_filename_quote_characters, 0);
+ rb_define_singleton_method(mReadline, "refresh_line",
+ readline_s_refresh_line, 0);
+ rb_define_singleton_method(mReadline, "pre_input_hook=",
+ readline_s_set_pre_input_hook, 1);
+ rb_define_singleton_method(mReadline, "pre_input_hook",
+ readline_s_get_pre_input_hook, 0);
+ rb_define_singleton_method(mReadline, "insert_text",
+ readline_s_insert_text, 1);
+ rb_define_singleton_method(mReadline, "delete_text",
+ readline_s_delete_text, -1);
+ rb_define_singleton_method(mReadline, "redisplay",
+ readline_s_redisplay, 0);
+ rb_define_singleton_method(mReadline, "special_prefixes=",
+ readline_s_set_special_prefixes, 1);
+ rb_define_singleton_method(mReadline, "special_prefixes",
+ readline_s_get_special_prefixes, 0);
+
+#if USE_INSERT_IGNORE_ESCAPE
+ id_orig_prompt = rb_intern("orig_prompt");
+ id_last_prompt = rb_intern("last_prompt");
+#endif
+
+ history = rb_obj_alloc(rb_cObject);
+ rb_extend_object(history, rb_mEnumerable);
+ rb_define_singleton_method(history,"to_s", hist_to_s, 0);
+ rb_define_singleton_method(history,"[]", hist_get, 1);
+ rb_define_singleton_method(history,"[]=", hist_set, 2);
+ rb_define_singleton_method(history,"<<", hist_push, 1);
+ rb_define_singleton_method(history,"push", hist_push_method, -1);
+ rb_define_singleton_method(history,"pop", hist_pop, 0);
+ rb_define_singleton_method(history,"shift", hist_shift, 0);
+ rb_define_singleton_method(history,"each", hist_each, 0);
+ rb_define_singleton_method(history,"length", hist_length, 0);
+ rb_define_singleton_method(history,"size", hist_length, 0);
+ rb_define_singleton_method(history,"empty?", hist_empty_p, 0);
+ rb_define_singleton_method(history,"delete_at", hist_delete_at, 1);
+ rb_define_singleton_method(history,"clear", hist_clear, 0);
+
+ /*
+ * The history buffer. It extends Enumerable module, so it behaves
+ * just like an array.
+ * For example, gets the fifth content that the user input by
+ * <code>HISTORY[4]</code>.
+ */
+ rb_define_const(mReadline, "HISTORY", history);
+
+ fcomp = rb_obj_alloc(rb_cObject);
+ rb_define_singleton_method(fcomp, "call",
+ filename_completion_proc_call, 1);
+ /*
+ * The Object with the call method that is a completion for filename.
+ * This is sets by Readline.completion_proc= method.
+ */
+ rb_define_const(mReadline, "FILENAME_COMPLETION_PROC", fcomp);
+
+ ucomp = rb_obj_alloc(rb_cObject);
+ rb_define_singleton_method(ucomp, "call",
+ username_completion_proc_call, 1);
+ /*
+ * The Object with the call method that is a completion for usernames.
+ * This is sets by Readline.completion_proc= method.
+ */
+ rb_define_const(mReadline, "USERNAME_COMPLETION_PROC", ucomp);
+ history_get_offset_func = history_get_offset_history_base;
+ history_replace_offset_func = history_get_offset_0;
+#if defined HAVE_RL_LIBRARY_VERSION
+ version = rb_str_new_cstr(rl_library_version);
+#if defined HAVE_CLEAR_HISTORY || defined HAVE_REMOVE_HISTORY
+ if (strncmp(rl_library_version, EDIT_LINE_LIBRARY_VERSION,
+ strlen(EDIT_LINE_LIBRARY_VERSION)) == 0) {
+ prepare_readline();
+ add_history("1");
+ if (history_get(history_get_offset_func(0)) == NULL) {
+ history_get_offset_func = history_get_offset_0;
+ }
+#ifdef HAVE_REPLACE_HISTORY_ENTRY
+ if (replace_history_entry(0, "a", NULL) == NULL) {
+ history_replace_offset_func = history_get_offset_history_base;
+ }
+#endif
+#ifdef HAVE_CLEAR_HISTORY
+ clear_history();
+#else
+ {
+ HIST_ENTRY *entry = remove_history(0);
+ if (entry) {
+ free((char *)entry->line);
+ free(entry);
+ }
+ }
+#endif
+ }
+#endif
+#else
+ version = rb_str_new_cstr("2.0 or prior version");
+#endif
+ /* Version string of GNU Readline or libedit. */
+ rb_define_const(mReadline, "VERSION", version);
+
+ rl_attempted_completion_function = readline_attempted_completion_function;
+#if defined(HAVE_RL_PRE_INPUT_HOOK)
+ rl_pre_input_hook = (rl_hook_func_t *)readline_pre_input_hook;
+#endif
+#if defined HAVE_RL_CHAR_IS_QUOTED_P
+ rl_char_is_quoted_p = &readline_char_is_quoted;
+#endif
+#ifdef HAVE_RL_CATCH_SIGNALS
+ rl_catch_signals = 0;
+#endif
+#ifdef HAVE_RL_CLEAR_SIGNALS
+ rl_clear_signals();
+#endif
+
+ rb_gc_register_address(&readline_instream);
+ rb_gc_register_address(&readline_outstream);
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * end:
+ */
diff --git a/ext/ripper/README b/ext/ripper/README
index 70fa208920..2ae2470e13 100644
--- a/ext/ripper/README
+++ b/ext/ripper/README
@@ -13,6 +13,7 @@ Requirements
------------
* ruby 1.9 (support CVS HEAD only)
+ * bison 1.28 or later (Other yaccs do not work)
Usage
-----
diff --git a/ext/ripper/depend b/ext/ripper/depend
index fe6bd872bd..856283e177 100644
--- a/ext/ripper/depend
+++ b/ext/ripper/depend
@@ -1,26 +1,27 @@
GEN = $(srcdir)/tools/generate.rb
SRC1 = $(top_srcdir)/parse.y
SRC2 = $(srcdir)/eventids2.c
-BISON = $(BASERUBY) $(top_srcdir)/tool/lrama/exe/lrama
.SUFFIXES: .y
-src: ripper.c ripper_init.c eventids1.c eventids1.h eventids2table.c
-ripper.c ripper_init.c eventids1.c eventids1.h eventids2table.c: depend
+src: ripper.c eventids1.c eventids2table.c
ripper.o: ripper.c
.y.c:
$(ECHO) compiling compiler $<
- $(Q) $(BISON) -t -v -o$@ - $< < $<
+ $(Q) $(BISON) -t -v -oy.tab.c $<
+ $(Q) sed -e "/^#/s!y\.tab\.c!$@!" -f $(top_srcdir)/tool/ytab.sed y.tab.c > $@
+ @$(RM) y.tab.c
all: check
static: check
ripper.y: $(srcdir)/tools/preproc.rb $(srcdir)/tools/dsl.rb $(top_srcdir)/parse.y $(top_srcdir)/defs/id.def
$(ECHO) extracting $@ from $(top_srcdir)/parse.y
- $(Q) $(RUBY) $(top_srcdir)/tool/id2token.rb $(top_srcdir)/parse.y | \
- $(RUBY) $(srcdir)/tools/preproc.rb --output=$@ - ripper.y
+ $(Q) $(RUBY) $(top_srcdir)/tool/id2token.rb $(top_srcdir)/parse.y > ripper.tmp.y
+ $(Q) $(RUBY) $(srcdir)/tools/preproc.rb ripper.tmp.y --output=$@
+ $(Q) $(RM) ripper.tmp.y
check: .eventids2-check
@@ -29,10 +30,6 @@ check: .eventids2-check
$(Q) $(RUBY) $(GEN) --mode=check --ids1src=$(SRC1) --ids2src=$(SRC2)
@exit > $@
-eventids1.h: $(GEN) $(srcdir)/tools/dsl.rb $(SRC1)
- $(ECHO) generating $@ from $(SRC1)
- $(Q) $(RUBY) $(GEN) --mode=eventids1_h --ids1src=$(SRC1) --output=$@
-
eventids1.c: $(GEN) $(srcdir)/tools/dsl.rb $(SRC1)
$(ECHO) generating $@ from $(SRC1)
$(Q) $(RUBY) $(GEN) --mode=eventids1 --ids1src=$(SRC1) --output=$@
@@ -41,10 +38,6 @@ eventids2table.c: $(GEN) $(srcdir)/tools/dsl.rb $(SRC2)
$(ECHO) generating $@ from $(SRC2)
$(Q) $(RUBY) $(GEN) --mode=eventids2table --ids2src=$(SRC2) --output=$@
-ripper_init.c: $(srcdir)/ripper_init.c.tmpl ripper.y $(srcdir)/tools/preproc.rb $(top_srcdir)/internal/ruby_parser.h
- $(ECHO) generating $@ from $(srcdir)/ripper_init.c.tmpl
- $(Q) $(RUBY) $(srcdir)/tools/preproc.rb --output=$@ --template=$(srcdir)/ripper_init.c.tmpl $(top_srcdir)/internal/ruby_parser.h
-
# Entries for Ripper maintainer
preproc: ripper.E
@@ -53,349 +46,10 @@ ripper.E: ripper.c
$(Q) $(CC) -E $(INCFLAGS) $(CPPFLAGS) $< | $(RUBY) $(srcdir)/tools/strip.rb > $@
# AUTOGENERATED DEPENDENCIES START
-eventids1.o: $(RUBY_EXTCONF_H)
-eventids1.o: $(arch_hdrdir)/ruby/config.h
-eventids1.o: $(hdrdir)/ruby/assert.h
-eventids1.o: $(hdrdir)/ruby/backward.h
-eventids1.o: $(hdrdir)/ruby/backward/2/assume.h
-eventids1.o: $(hdrdir)/ruby/backward/2/attributes.h
-eventids1.o: $(hdrdir)/ruby/backward/2/bool.h
-eventids1.o: $(hdrdir)/ruby/backward/2/inttypes.h
-eventids1.o: $(hdrdir)/ruby/backward/2/limits.h
-eventids1.o: $(hdrdir)/ruby/backward/2/long_long.h
-eventids1.o: $(hdrdir)/ruby/backward/2/stdalign.h
-eventids1.o: $(hdrdir)/ruby/backward/2/stdarg.h
-eventids1.o: $(hdrdir)/ruby/defines.h
-eventids1.o: $(hdrdir)/ruby/intern.h
-eventids1.o: $(hdrdir)/ruby/internal/abi.h
-eventids1.o: $(hdrdir)/ruby/internal/anyargs.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-eventids1.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-eventids1.o: $(hdrdir)/ruby/internal/assume.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/artificial.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/cold.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/const.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/error.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/format.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/noalias.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/noinline.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/pure.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/restrict.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/warning.h
-eventids1.o: $(hdrdir)/ruby/internal/attr/weakref.h
-eventids1.o: $(hdrdir)/ruby/internal/cast.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-eventids1.o: $(hdrdir)/ruby/internal/compiler_since.h
-eventids1.o: $(hdrdir)/ruby/internal/config.h
-eventids1.o: $(hdrdir)/ruby/internal/constant_p.h
-eventids1.o: $(hdrdir)/ruby/internal/core.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rarray.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rbasic.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rbignum.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rclass.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rdata.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rfile.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rhash.h
-eventids1.o: $(hdrdir)/ruby/internal/core/robject.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rregexp.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rstring.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rstruct.h
-eventids1.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-eventids1.o: $(hdrdir)/ruby/internal/ctype.h
-eventids1.o: $(hdrdir)/ruby/internal/dllexport.h
-eventids1.o: $(hdrdir)/ruby/internal/dosish.h
-eventids1.o: $(hdrdir)/ruby/internal/error.h
-eventids1.o: $(hdrdir)/ruby/internal/eval.h
-eventids1.o: $(hdrdir)/ruby/internal/event.h
-eventids1.o: $(hdrdir)/ruby/internal/fl_type.h
-eventids1.o: $(hdrdir)/ruby/internal/gc.h
-eventids1.o: $(hdrdir)/ruby/internal/glob.h
-eventids1.o: $(hdrdir)/ruby/internal/globals.h
-eventids1.o: $(hdrdir)/ruby/internal/has/attribute.h
-eventids1.o: $(hdrdir)/ruby/internal/has/builtin.h
-eventids1.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-eventids1.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-eventids1.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-eventids1.o: $(hdrdir)/ruby/internal/has/extension.h
-eventids1.o: $(hdrdir)/ruby/internal/has/feature.h
-eventids1.o: $(hdrdir)/ruby/internal/has/warning.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/array.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/bignum.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/class.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/compar.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/complex.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/cont.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/dir.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/enum.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/error.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/eval.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/file.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/hash.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/io.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/load.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/marshal.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/numeric.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/object.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/parse.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/proc.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/process.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/random.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/range.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/rational.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/re.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/ruby.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/select.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/signal.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/string.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/struct.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/thread.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/time.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/variable.h
-eventids1.o: $(hdrdir)/ruby/internal/intern/vm.h
-eventids1.o: $(hdrdir)/ruby/internal/interpreter.h
-eventids1.o: $(hdrdir)/ruby/internal/iterator.h
-eventids1.o: $(hdrdir)/ruby/internal/memory.h
-eventids1.o: $(hdrdir)/ruby/internal/method.h
-eventids1.o: $(hdrdir)/ruby/internal/module.h
-eventids1.o: $(hdrdir)/ruby/internal/newobj.h
-eventids1.o: $(hdrdir)/ruby/internal/scan_args.h
-eventids1.o: $(hdrdir)/ruby/internal/special_consts.h
-eventids1.o: $(hdrdir)/ruby/internal/static_assert.h
-eventids1.o: $(hdrdir)/ruby/internal/stdalign.h
-eventids1.o: $(hdrdir)/ruby/internal/stdbool.h
-eventids1.o: $(hdrdir)/ruby/internal/stdckdint.h
-eventids1.o: $(hdrdir)/ruby/internal/symbol.h
-eventids1.o: $(hdrdir)/ruby/internal/value.h
-eventids1.o: $(hdrdir)/ruby/internal/value_type.h
-eventids1.o: $(hdrdir)/ruby/internal/variable.h
-eventids1.o: $(hdrdir)/ruby/internal/warning_push.h
-eventids1.o: $(hdrdir)/ruby/internal/xmalloc.h
-eventids1.o: $(hdrdir)/ruby/missing.h
-eventids1.o: $(hdrdir)/ruby/ruby.h
-eventids1.o: $(hdrdir)/ruby/st.h
-eventids1.o: $(hdrdir)/ruby/subst.h
-eventids1.o: eventids1.h
-eventids1.o: {$(VPATH)}eventids1.c
-eventids1.o: {$(VPATH)}eventids1.h
-eventids2.o: $(RUBY_EXTCONF_H)
-eventids2.o: $(arch_hdrdir)/ruby/config.h
-eventids2.o: $(hdrdir)/ruby/assert.h
-eventids2.o: $(hdrdir)/ruby/backward.h
-eventids2.o: $(hdrdir)/ruby/backward/2/assume.h
-eventids2.o: $(hdrdir)/ruby/backward/2/attributes.h
-eventids2.o: $(hdrdir)/ruby/backward/2/bool.h
-eventids2.o: $(hdrdir)/ruby/backward/2/inttypes.h
-eventids2.o: $(hdrdir)/ruby/backward/2/limits.h
-eventids2.o: $(hdrdir)/ruby/backward/2/long_long.h
-eventids2.o: $(hdrdir)/ruby/backward/2/stdalign.h
-eventids2.o: $(hdrdir)/ruby/backward/2/stdarg.h
-eventids2.o: $(hdrdir)/ruby/defines.h
-eventids2.o: $(hdrdir)/ruby/encoding.h
-eventids2.o: $(hdrdir)/ruby/intern.h
-eventids2.o: $(hdrdir)/ruby/internal/abi.h
-eventids2.o: $(hdrdir)/ruby/internal/anyargs.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-eventids2.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-eventids2.o: $(hdrdir)/ruby/internal/assume.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/artificial.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/cold.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/const.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/error.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/format.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/noalias.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/noinline.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/pure.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/restrict.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/warning.h
-eventids2.o: $(hdrdir)/ruby/internal/attr/weakref.h
-eventids2.o: $(hdrdir)/ruby/internal/cast.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-eventids2.o: $(hdrdir)/ruby/internal/compiler_since.h
-eventids2.o: $(hdrdir)/ruby/internal/config.h
-eventids2.o: $(hdrdir)/ruby/internal/constant_p.h
-eventids2.o: $(hdrdir)/ruby/internal/core.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rarray.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rbasic.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rbignum.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rclass.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rdata.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rfile.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rhash.h
-eventids2.o: $(hdrdir)/ruby/internal/core/robject.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rregexp.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rstring.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rstruct.h
-eventids2.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-eventids2.o: $(hdrdir)/ruby/internal/ctype.h
-eventids2.o: $(hdrdir)/ruby/internal/dllexport.h
-eventids2.o: $(hdrdir)/ruby/internal/dosish.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/re.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/string.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-eventids2.o: $(hdrdir)/ruby/internal/encoding/transcode.h
-eventids2.o: $(hdrdir)/ruby/internal/error.h
-eventids2.o: $(hdrdir)/ruby/internal/eval.h
-eventids2.o: $(hdrdir)/ruby/internal/event.h
-eventids2.o: $(hdrdir)/ruby/internal/fl_type.h
-eventids2.o: $(hdrdir)/ruby/internal/gc.h
-eventids2.o: $(hdrdir)/ruby/internal/glob.h
-eventids2.o: $(hdrdir)/ruby/internal/globals.h
-eventids2.o: $(hdrdir)/ruby/internal/has/attribute.h
-eventids2.o: $(hdrdir)/ruby/internal/has/builtin.h
-eventids2.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-eventids2.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-eventids2.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-eventids2.o: $(hdrdir)/ruby/internal/has/extension.h
-eventids2.o: $(hdrdir)/ruby/internal/has/feature.h
-eventids2.o: $(hdrdir)/ruby/internal/has/warning.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/array.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/bignum.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/class.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/compar.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/complex.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/cont.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/dir.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/enum.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/error.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/eval.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/file.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/hash.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/io.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/load.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/marshal.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/numeric.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/object.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/parse.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/proc.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/process.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/random.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/range.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/rational.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/re.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/ruby.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/select.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/signal.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/string.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/struct.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/thread.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/time.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/variable.h
-eventids2.o: $(hdrdir)/ruby/internal/intern/vm.h
-eventids2.o: $(hdrdir)/ruby/internal/interpreter.h
-eventids2.o: $(hdrdir)/ruby/internal/iterator.h
-eventids2.o: $(hdrdir)/ruby/internal/memory.h
-eventids2.o: $(hdrdir)/ruby/internal/method.h
-eventids2.o: $(hdrdir)/ruby/internal/module.h
-eventids2.o: $(hdrdir)/ruby/internal/newobj.h
-eventids2.o: $(hdrdir)/ruby/internal/scan_args.h
-eventids2.o: $(hdrdir)/ruby/internal/special_consts.h
-eventids2.o: $(hdrdir)/ruby/internal/static_assert.h
-eventids2.o: $(hdrdir)/ruby/internal/stdalign.h
-eventids2.o: $(hdrdir)/ruby/internal/stdbool.h
-eventids2.o: $(hdrdir)/ruby/internal/stdckdint.h
-eventids2.o: $(hdrdir)/ruby/internal/symbol.h
-eventids2.o: $(hdrdir)/ruby/internal/value.h
-eventids2.o: $(hdrdir)/ruby/internal/value_type.h
-eventids2.o: $(hdrdir)/ruby/internal/variable.h
-eventids2.o: $(hdrdir)/ruby/internal/warning_push.h
-eventids2.o: $(hdrdir)/ruby/internal/xmalloc.h
-eventids2.o: $(hdrdir)/ruby/missing.h
-eventids2.o: $(hdrdir)/ruby/onigmo.h
-eventids2.o: $(hdrdir)/ruby/oniguruma.h
-eventids2.o: $(hdrdir)/ruby/ruby.h
-eventids2.o: $(hdrdir)/ruby/st.h
-eventids2.o: $(hdrdir)/ruby/subst.h
-eventids2.o: $(top_srcdir)/internal.h
-eventids2.o: $(top_srcdir)/internal/static_assert.h
-eventids2.o: $(top_srcdir)/rubyparser.h
-eventids2.o: eventids2.c
-eventids2.o: eventids2.h
-eventids2.o: {$(VPATH)}eventids2table.c
-eventids2.o: {$(VPATH)}parse.h
ripper.o: $(RUBY_EXTCONF_H)
ripper.o: $(arch_hdrdir)/ruby/config.h
ripper.o: $(hdrdir)/ruby.h
ripper.o: $(hdrdir)/ruby/assert.h
-ripper.o: $(hdrdir)/ruby/atomic.h
ripper.o: $(hdrdir)/ruby/backward.h
ripper.o: $(hdrdir)/ruby/backward/2/assume.h
ripper.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -447,7 +101,6 @@ ripper.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ripper.o: $(hdrdir)/ruby/internal/attr/noinline.h
ripper.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ripper.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ripper.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ripper.o: $(hdrdir)/ruby/internal/attr/pure.h
ripper.o: $(hdrdir)/ruby/internal/attr/restrict.h
ripper.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -516,6 +169,7 @@ ripper.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ripper.o: $(hdrdir)/ruby/internal/intern/error.h
ripper.o: $(hdrdir)/ruby/internal/intern/eval.h
ripper.o: $(hdrdir)/ruby/internal/intern/file.h
+ripper.o: $(hdrdir)/ruby/internal/intern/gc.h
ripper.o: $(hdrdir)/ruby/internal/intern/hash.h
ripper.o: $(hdrdir)/ruby/internal/intern/io.h
ripper.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -546,12 +200,12 @@ ripper.o: $(hdrdir)/ruby/internal/memory.h
ripper.o: $(hdrdir)/ruby/internal/method.h
ripper.o: $(hdrdir)/ruby/internal/module.h
ripper.o: $(hdrdir)/ruby/internal/newobj.h
+ripper.o: $(hdrdir)/ruby/internal/rgengc.h
ripper.o: $(hdrdir)/ruby/internal/scan_args.h
ripper.o: $(hdrdir)/ruby/internal/special_consts.h
ripper.o: $(hdrdir)/ruby/internal/static_assert.h
ripper.o: $(hdrdir)/ruby/internal/stdalign.h
ripper.o: $(hdrdir)/ruby/internal/stdbool.h
-ripper.o: $(hdrdir)/ruby/internal/stdckdint.h
ripper.o: $(hdrdir)/ruby/internal/symbol.h
ripper.o: $(hdrdir)/ruby/internal/value.h
ripper.o: $(hdrdir)/ruby/internal/value_type.h
@@ -567,18 +221,11 @@ ripper.o: $(hdrdir)/ruby/regex.h
ripper.o: $(hdrdir)/ruby/ruby.h
ripper.o: $(hdrdir)/ruby/st.h
ripper.o: $(hdrdir)/ruby/subst.h
-ripper.o: $(hdrdir)/ruby/thread_native.h
ripper.o: $(hdrdir)/ruby/util.h
-ripper.o: $(hdrdir)/ruby/version.h
-ripper.o: $(top_srcdir)/ccan/check_type/check_type.h
-ripper.o: $(top_srcdir)/ccan/container_of/container_of.h
-ripper.o: $(top_srcdir)/ccan/list/list.h
-ripper.o: $(top_srcdir)/ccan/str/str.h
ripper.o: $(top_srcdir)/constant.h
ripper.o: $(top_srcdir)/id_table.h
ripper.o: $(top_srcdir)/internal.h
ripper.o: $(top_srcdir)/internal/array.h
-ripper.o: $(top_srcdir)/internal/basic_operators.h
ripper.o: $(top_srcdir)/internal/bignum.h
ripper.o: $(top_srcdir)/internal/bits.h
ripper.o: $(top_srcdir)/internal/compile.h
@@ -595,8 +242,6 @@ ripper.o: $(top_srcdir)/internal/numeric.h
ripper.o: $(top_srcdir)/internal/parse.h
ripper.o: $(top_srcdir)/internal/rational.h
ripper.o: $(top_srcdir)/internal/re.h
-ripper.o: $(top_srcdir)/internal/ruby_parser.h
-ripper.o: $(top_srcdir)/internal/sanitizers.h
ripper.o: $(top_srcdir)/internal/serial.h
ripper.o: $(top_srcdir)/internal/static_assert.h
ripper.o: $(top_srcdir)/internal/string.h
@@ -605,25 +250,14 @@ ripper.o: $(top_srcdir)/internal/thread.h
ripper.o: $(top_srcdir)/internal/variable.h
ripper.o: $(top_srcdir)/internal/vm.h
ripper.o: $(top_srcdir)/internal/warnings.h
-ripper.o: $(top_srcdir)/method.h
ripper.o: $(top_srcdir)/node.h
-ripper.o: $(top_srcdir)/parser_node.h
-ripper.o: $(top_srcdir)/parser_st.h
ripper.o: $(top_srcdir)/regenc.h
ripper.o: $(top_srcdir)/ruby_assert.h
-ripper.o: $(top_srcdir)/ruby_atomic.h
-ripper.o: $(top_srcdir)/rubyparser.h
ripper.o: $(top_srcdir)/shape.h
ripper.o: $(top_srcdir)/symbol.h
-ripper.o: $(top_srcdir)/thread_pthread.h
-ripper.o: $(top_srcdir)/vm_core.h
-ripper.o: $(top_srcdir)/vm_opts.h
ripper.o: ../../probes.h
-ripper.o: eventids1.h
ripper.o: eventids2.c
-ripper.o: eventids2.h
ripper.o: ripper.y
-ripper.o: ripper_init.h
ripper.o: {$(VPATH)}eventids1.c
ripper.o: {$(VPATH)}eventids2table.c
ripper.o: {$(VPATH)}id.h
@@ -631,198 +265,4 @@ ripper.o: {$(VPATH)}lex.c
ripper.o: {$(VPATH)}parse.h
ripper.o: {$(VPATH)}probes.dmyh
ripper.o: {$(VPATH)}ripper.c
-ripper_init.o: $(RUBY_EXTCONF_H)
-ripper_init.o: $(arch_hdrdir)/ruby/config.h
-ripper_init.o: $(hdrdir)/ruby/assert.h
-ripper_init.o: $(hdrdir)/ruby/backward.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/assume.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/attributes.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/bool.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/gcc_version_since.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/inttypes.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/limits.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/long_long.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/stdalign.h
-ripper_init.o: $(hdrdir)/ruby/backward/2/stdarg.h
-ripper_init.o: $(hdrdir)/ruby/defines.h
-ripper_init.o: $(hdrdir)/ruby/encoding.h
-ripper_init.o: $(hdrdir)/ruby/intern.h
-ripper_init.o: $(hdrdir)/ruby/internal/abi.h
-ripper_init.o: $(hdrdir)/ruby/internal/anyargs.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/char.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/double.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/int.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/long.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/short.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
-ripper_init.o: $(hdrdir)/ruby/internal/assume.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/artificial.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/cold.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/const.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/constexpr.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/deprecated.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/error.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/forceinline.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/format.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/noalias.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/noinline.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/pure.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/restrict.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/warning.h
-ripper_init.o: $(hdrdir)/ruby/internal/attr/weakref.h
-ripper_init.o: $(hdrdir)/ruby/internal/cast.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
-ripper_init.o: $(hdrdir)/ruby/internal/compiler_since.h
-ripper_init.o: $(hdrdir)/ruby/internal/config.h
-ripper_init.o: $(hdrdir)/ruby/internal/constant_p.h
-ripper_init.o: $(hdrdir)/ruby/internal/core.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rarray.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rbasic.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rbignum.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rclass.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rdata.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rfile.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rhash.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/robject.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rregexp.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rstring.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rstruct.h
-ripper_init.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
-ripper_init.o: $(hdrdir)/ruby/internal/ctype.h
-ripper_init.o: $(hdrdir)/ruby/internal/dllexport.h
-ripper_init.o: $(hdrdir)/ruby/internal/dosish.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/coderange.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/ctype.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/encoding.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/pathname.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/re.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/sprintf.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/string.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/symbol.h
-ripper_init.o: $(hdrdir)/ruby/internal/encoding/transcode.h
-ripper_init.o: $(hdrdir)/ruby/internal/error.h
-ripper_init.o: $(hdrdir)/ruby/internal/eval.h
-ripper_init.o: $(hdrdir)/ruby/internal/event.h
-ripper_init.o: $(hdrdir)/ruby/internal/fl_type.h
-ripper_init.o: $(hdrdir)/ruby/internal/gc.h
-ripper_init.o: $(hdrdir)/ruby/internal/glob.h
-ripper_init.o: $(hdrdir)/ruby/internal/globals.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/attribute.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/builtin.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/c_attribute.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/extension.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/feature.h
-ripper_init.o: $(hdrdir)/ruby/internal/has/warning.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/array.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/bignum.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/class.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/compar.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/complex.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/cont.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/dir.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/enum.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/error.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/eval.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/file.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/hash.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/io.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/load.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/marshal.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/numeric.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/object.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/parse.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/proc.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/process.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/random.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/range.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/rational.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/re.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/ruby.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/select.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/signal.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/string.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/struct.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/thread.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/time.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/variable.h
-ripper_init.o: $(hdrdir)/ruby/internal/intern/vm.h
-ripper_init.o: $(hdrdir)/ruby/internal/interpreter.h
-ripper_init.o: $(hdrdir)/ruby/internal/iterator.h
-ripper_init.o: $(hdrdir)/ruby/internal/memory.h
-ripper_init.o: $(hdrdir)/ruby/internal/method.h
-ripper_init.o: $(hdrdir)/ruby/internal/module.h
-ripper_init.o: $(hdrdir)/ruby/internal/newobj.h
-ripper_init.o: $(hdrdir)/ruby/internal/scan_args.h
-ripper_init.o: $(hdrdir)/ruby/internal/special_consts.h
-ripper_init.o: $(hdrdir)/ruby/internal/static_assert.h
-ripper_init.o: $(hdrdir)/ruby/internal/stdalign.h
-ripper_init.o: $(hdrdir)/ruby/internal/stdbool.h
-ripper_init.o: $(hdrdir)/ruby/internal/stdckdint.h
-ripper_init.o: $(hdrdir)/ruby/internal/symbol.h
-ripper_init.o: $(hdrdir)/ruby/internal/value.h
-ripper_init.o: $(hdrdir)/ruby/internal/value_type.h
-ripper_init.o: $(hdrdir)/ruby/internal/variable.h
-ripper_init.o: $(hdrdir)/ruby/internal/warning_push.h
-ripper_init.o: $(hdrdir)/ruby/internal/xmalloc.h
-ripper_init.o: $(hdrdir)/ruby/missing.h
-ripper_init.o: $(hdrdir)/ruby/onigmo.h
-ripper_init.o: $(hdrdir)/ruby/oniguruma.h
-ripper_init.o: $(hdrdir)/ruby/ruby.h
-ripper_init.o: $(hdrdir)/ruby/st.h
-ripper_init.o: $(hdrdir)/ruby/subst.h
-ripper_init.o: $(top_srcdir)/internal.h
-ripper_init.o: $(top_srcdir)/internal/array.h
-ripper_init.o: $(top_srcdir)/internal/bignum.h
-ripper_init.o: $(top_srcdir)/internal/bits.h
-ripper_init.o: $(top_srcdir)/internal/compilers.h
-ripper_init.o: $(top_srcdir)/internal/complex.h
-ripper_init.o: $(top_srcdir)/internal/fixnum.h
-ripper_init.o: $(top_srcdir)/internal/imemo.h
-ripper_init.o: $(top_srcdir)/internal/numeric.h
-ripper_init.o: $(top_srcdir)/internal/parse.h
-ripper_init.o: $(top_srcdir)/internal/rational.h
-ripper_init.o: $(top_srcdir)/internal/ruby_parser.h
-ripper_init.o: $(top_srcdir)/internal/serial.h
-ripper_init.o: $(top_srcdir)/internal/static_assert.h
-ripper_init.o: $(top_srcdir)/internal/vm.h
-ripper_init.o: $(top_srcdir)/node.h
-ripper_init.o: $(top_srcdir)/ruby_assert.h
-ripper_init.o: $(top_srcdir)/rubyparser.h
-ripper_init.o: eventids1.h
-ripper_init.o: eventids2.h
-ripper_init.o: ripper_init.h
-ripper_init.o: {$(VPATH)}parse.h
-ripper_init.o: {$(VPATH)}ripper_init.c
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/ripper/eventids2.c b/ext/ripper/eventids2.c
index 439663f0fd..05687497ac 100644
--- a/ext/ripper/eventids2.c
+++ b/ext/ripper/eventids2.c
@@ -1,11 +1,3 @@
-#include "ruby/ruby.h"
-#include "rubyparser.h"
-#define YYSTYPE_IS_DECLARED
-#include "parse.h"
-#include "eventids2.h"
-#include "internal.h"
-#include "internal/static_assert.h"
-
typedef struct {
ID ripper_id_backref;
ID ripper_id_backtick;
@@ -65,9 +57,7 @@ static ripper_scanner_ids_t ripper_scanner_ids;
#include "eventids2table.c"
-STATIC_ASSERT(eventids2_table_size, RIPPER_EVENTIDS2_TABLE_SIZE == sizeof(ripper_scanner_ids)/sizeof(ID));
-
-void
+static void
ripper_init_eventids2(void)
{
#define set_id2(name) ripper_scanner_ids.ripper_id_##name = rb_intern_const("on_"#name)
@@ -128,7 +118,7 @@ ripper_init_eventids2(void)
STATIC_ASSERT(k__END___range, k__END__ < SHRT_MAX);
STATIC_ASSERT(ripper_scanner_ids_size, sizeof(ripper_scanner_ids) < SHRT_MAX);
-ID
+static ID
ripper_token2eventid(enum yytokentype tok)
{
#define O(member) (int)offsetof(ripper_scanner_ids_t, ripper_id_##member)+1
diff --git a/ext/ripper/eventids2.h b/ext/ripper/eventids2.h
deleted file mode 100644
index 49e46432b9..0000000000
--- a/ext/ripper/eventids2.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef RIPPER_EVENTIDS2
-#define RIPPER_EVENTIDS2
-
-void ripper_init_eventids2(void);
-void ripper_init_eventids2_table(VALUE self);
-ID ripper_token2eventid(enum yytokentype tok);
-
-#endif /* RIPPER_EVENTIDS2 */
diff --git a/ext/ripper/extconf.rb b/ext/ripper/extconf.rb
index c3c56c27c5..65cb5030d3 100644
--- a/ext/ripper/extconf.rb
+++ b/ext/ripper/extconf.rb
@@ -5,14 +5,23 @@ require 'mkmf'
require 'rbconfig'
def main
- $objs = %w(eventids1.o eventids2.o ripper.o ripper_init.o)
- $distcleanfiles.concat %w(ripper.y ripper.c eventids1.c eventids1.h eventids2table.c ripper_init.c)
+ yacc = ENV["YACC"] || "bison"
+
+ unless find_executable(yacc)
+ unless File.exist?('ripper.c') or File.exist?("#{$srcdir}/ripper.c")
+ raise 'missing bison; abort'
+ end
+ end
+ $objs = %w(ripper.o)
+ $distcleanfiles.concat %w(ripper.y ripper.c eventids1.c eventids2table.c)
$cleanfiles.concat %w(ripper.E ripper.output y.output .eventids2-check)
$defs << '-DRIPPER'
$defs << '-DRIPPER_DEBUG' if $debug
$VPATH << '$(topdir)' << '$(top_srcdir)'
$INCFLAGS << ' -I$(topdir) -I$(top_srcdir)'
- create_makefile 'ripper'
+ create_makefile 'ripper' do |conf|
+ conf << "BISON = #{yacc}"
+ end
end
main
diff --git a/ext/ripper/ripper_init.c.tmpl b/ext/ripper/ripper_init.c.tmpl
deleted file mode 100644
index 11e432423d..0000000000
--- a/ext/ripper/ripper_init.c.tmpl
+++ /dev/null
@@ -1,680 +0,0 @@
-%# -*- c -*-
-#include "ruby/ruby.h"
-#include "ruby/encoding.h"
-#include "internal.h"
-#include "rubyparser.h"
-#define YYSTYPE_IS_DECLARED
-#include "parse.h"
-#include "internal/parse.h"
-#include "internal/ruby_parser.h"
-#include "node.h"
-#include "eventids1.h"
-#include "eventids2.h"
-#include "ripper_init.h"
-
-#define STR_NEW2(ptr) rb_enc_str_new((ptr),strlen(ptr),rb_ruby_parser_enc(p))
-#define RIPPER_VERSION "0.1.0"
-
-ID id_warn, id_warning, id_gets, id_assoc;
-
-enum lex_type {
- lex_type_str,
- lex_type_io,
- lex_type_generic,
-};
-
-struct ripper {
- rb_parser_t *p;
- enum lex_type type;
- union {
- struct lex_pointer_string ptr_str;
- VALUE val;
- } data;
-};
-
-static void
-ripper_parser_mark2(void *ptr)
-{
- struct ripper *r = (struct ripper*)ptr;
- if (r->p) {
- ripper_parser_mark(r->p);
-
- switch (r->type) {
- case lex_type_str:
- rb_gc_mark(r->data.ptr_str.str);
- break;
- case lex_type_io:
- rb_gc_mark(r->data.val);
- break;
- case lex_type_generic:
- rb_gc_mark(r->data.val);
- break;
- }
- }
-}
-
-static void
-ripper_parser_free2(void *ptr)
-{
- struct ripper *r = (struct ripper*)ptr;
- if (r->p) ripper_parser_free(r->p);
- xfree(r);
-}
-
-static size_t
-ripper_parser_memsize2(const void *ptr)
-{
- struct ripper *r = (struct ripper*)ptr;
- return (r->p) ? ripper_parser_memsize(r->p) : 0;
-}
-
-static const rb_data_type_t parser_data_type = {
- "ripper",
- {
- ripper_parser_mark2,
- ripper_parser_free2,
- ripper_parser_memsize2,
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
-};
-
-static rb_parser_string_t *
-ripper_lex_get_generic(struct parser_params *p, rb_parser_input_data input, int line_count)
-{
- VALUE src = (VALUE)input;
- VALUE line = rb_funcallv_public(src, id_gets, 0, 0);
- if (NIL_P(line)) return 0;
- if (!RB_TYPE_P(line, T_STRING)) {
- rb_raise(rb_eTypeError,
- "gets returned %"PRIsVALUE" (expected String or nil)",
- rb_obj_class(line));
- }
- return rb_str_to_parser_string(p, line);
-}
-
-void
-ripper_compile_error(struct parser_params *p, const char *fmt, ...)
-{
- VALUE str;
- va_list args;
-
- va_start(args, fmt);
- str = rb_vsprintf(fmt, args);
- va_end(args);
- rb_funcall(ripper_value(p), rb_intern("compile_error"), 1, str);
- ripper_error(p);
-}
-
-static rb_parser_string_t *
-ripper_lex_io_get(struct parser_params *p, rb_parser_input_data input, int line_count)
-{
- VALUE src = (VALUE)input;
- VALUE line = rb_io_gets(src);
- if (NIL_P(line)) return 0;
- return rb_str_to_parser_string(p, line);
-}
-
-static rb_parser_string_t *
-ripper_lex_get_str(struct parser_params *p, rb_parser_input_data input, int line_count)
-{
- return rb_parser_lex_get_str(p, (struct lex_pointer_string *)input);
-}
-
-static VALUE
-ripper_s_allocate(VALUE klass)
-{
- struct ripper *r;
-
- VALUE self = TypedData_Make_Struct(klass, struct ripper,
- &parser_data_type, r);
-
-#ifdef UNIVERSAL_PARSER
- const rb_parser_config_t *config = rb_ruby_parser_config();
- r->p = rb_ripper_parser_params_allocate(config);
-#else
- r->p = rb_ruby_ripper_parser_allocate();
-#endif
- rb_ruby_parser_set_value(r->p, self);
- return self;
-}
-
-static struct parser_params *
-ripper_parser_params(VALUE self, bool initialized)
-{
- struct ripper *r;
- struct parser_params *p;
-
- TypedData_Get_Struct(self, struct ripper, &parser_data_type, r);
- p = r->p;
- if (initialized && !rb_ruby_ripper_initialized_p(p)) {
- rb_raise(rb_eArgError, "method called for uninitialized object");
- }
- return p;
-}
-
-/*
- * call-seq:
- * ripper.error? -> Boolean
- *
- * Return true if parsed source has errors.
- */
-static VALUE
-ripper_error_p(VALUE vparser)
-{
- struct parser_params *p = ripper_parser_params(vparser, false);
-
- return RBOOL(rb_ruby_parser_error_p(p));
-}
-
-/*
- * call-seq:
- * ripper.end_seen? -> Boolean
- *
- * Return true if parsed source ended by +\_\_END\_\_+.
- */
-static VALUE
-ripper_parser_end_seen_p(VALUE vparser)
-{
- struct parser_params *p = ripper_parser_params(vparser, false);
-
- return RBOOL(rb_ruby_parser_end_seen_p(p));
-}
-
-/*
- * call-seq:
- * ripper.encoding -> encoding
- *
- * Return encoding of the source.
- */
-static VALUE
-ripper_parser_encoding(VALUE vparser)
-{
- struct parser_params *p = ripper_parser_params(vparser, false);
-
- return rb_enc_from_encoding(rb_ruby_parser_encoding(p));
-}
-
-/*
- * call-seq:
- * ripper.yydebug -> true or false
- *
- * Get yydebug.
- */
-static VALUE
-ripper_parser_get_yydebug(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, false);
-
- return RBOOL(rb_ruby_parser_get_yydebug(p));
-}
-
-/*
- * call-seq:
- * ripper.yydebug = flag
- *
- * Set yydebug.
- */
-static VALUE
-ripper_parser_set_yydebug(VALUE self, VALUE flag)
-{
- struct parser_params *p = ripper_parser_params(self, false);
-
- rb_ruby_parser_set_yydebug(p, RTEST(flag));
- return flag;
-}
-
-/*
- * call-seq:
- * ripper.debug_output -> obj
- *
- * Get debug output.
- */
-static VALUE
-ripper_parser_get_debug_output(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, false);
-
- return rb_ruby_parser_debug_output(p);
-}
-
-/*
- * call-seq:
- * ripper.debug_output = obj
- *
- * Set debug output.
- */
-static VALUE
-ripper_parser_set_debug_output(VALUE self, VALUE output)
-{
- struct parser_params *p = ripper_parser_params(self, false);
-
- rb_ruby_parser_set_debug_output(p, output);
- return output;
-}
-
-static int
-ripper_parser_dedent_string(struct parser_params *p, VALUE string, int width)
-{
- int col;
- rb_parser_string_t *str;
- str = rb_str_to_parser_string(p, string);
- col = rb_ruby_ripper_dedent_string(p, str, width);
- rb_str_replace(string, rb_str_new_parser_string(str));
- rb_parser_string_free(p, str);
- return col;
-}
-
-#ifdef UNIVERSAL_PARSER
-struct dedent_string_arg {
- struct parser_params *p;
- VALUE input;
- VALUE width;
-};
-
-static VALUE
-parser_dedent_string0(VALUE a)
-{
- struct dedent_string_arg *arg = (void *)a;
- int wid, col;
-
- StringValue(arg->input);
- wid = NUM2UINT(arg->width);
- col = ripper_parser_dedent_string(arg->p, arg->input, wid);
- return INT2NUM(col);
-}
-
-static VALUE
-parser_free(VALUE a)
-{
- struct parser_params *p = (void *)a;
-
- rb_ruby_parser_free(p);
- return Qnil;
-}
-#endif
-
-/*
- * call-seq:
- * Ripper.dedent_string(input, width) -> Integer
- *
- * USE OF RIPPER LIBRARY ONLY.
- *
- * Strips up to +width+ leading whitespaces from +input+,
- * and returns the stripped column width.
- */
-#ifdef UNIVERSAL_PARSER
-static VALUE
-parser_dedent_string(VALUE self, VALUE input, VALUE width)
-{
- struct parser_params *p;
- struct dedent_string_arg args;
-
- p = rb_parser_params_new();
-
- args.p = p;
- args.input = input;
- args.width = width;
- return rb_ensure(parser_dedent_string0, (VALUE)&args, parser_free, (VALUE)p);
-}
-#else
-static VALUE
-parser_dedent_string(VALUE self, VALUE input, VALUE width)
-{
- int wid, col;
-
- StringValue(input);
- wid = NUM2UINT(width);
- col = ripper_parser_dedent_string(0, input, wid);
- return INT2NUM(col);
-}
-#endif
-
-/*
- * call-seq:
- * Ripper.new(src, filename="(ripper)", lineno=1) -> ripper
- *
- * Create a new Ripper object.
- * _src_ must be a String, an IO, or an Object which has #gets method.
- *
- * This method does not starts parsing.
- * See also Ripper#parse and Ripper.parse.
- */
-static VALUE
-ripper_initialize(int argc, VALUE *argv, VALUE self)
-{
- struct ripper *r;
- struct parser_params *p;
- VALUE src, fname, lineno;
- rb_parser_lex_gets_func *gets;
- VALUE sourcefile_string;
- const char *sourcefile;
- int sourceline;
- rb_parser_input_data input;
-
- p = ripper_parser_params(self, false);
- TypedData_Get_Struct(self, struct ripper, &parser_data_type, r);
- rb_scan_args(argc, argv, "12", &src, &fname, &lineno);
- if (RB_TYPE_P(src, T_FILE)) {
- gets = ripper_lex_io_get;
- r->type = lex_type_io;
- r->data.val = src;
- input = (rb_parser_input_data)src;
- }
- else if (rb_respond_to(src, id_gets)) {
- gets = ripper_lex_get_generic;
- r->type = lex_type_generic;
- r->data.val = src;
- input = (rb_parser_input_data)src;
- }
- else {
- StringValue(src);
- gets = ripper_lex_get_str;
- r->type = lex_type_str;
- r->data.ptr_str.str = src;
- r->data.ptr_str.ptr = 0;
- input = (rb_parser_input_data)&r->data.ptr_str;
- }
- if (NIL_P(fname)) {
- fname = STR_NEW2("(ripper)");
- OBJ_FREEZE(fname);
- }
- else {
- StringValueCStr(fname);
- fname = rb_str_new_frozen(fname);
- }
- rb_ruby_ripper_parser_initialize(p);
-
- sourcefile_string = fname;
- sourcefile = RSTRING_PTR(fname);
- sourceline = NIL_P(lineno) ? 0 : NUM2INT(lineno) - 1;
-
- rb_ruby_parser_ripper_initialize(p, gets, input, sourcefile_string, sourcefile, sourceline);
-
- return Qnil;
-}
-
-static VALUE
-ripper_parse0(VALUE vparser)
-{
- struct parser_params *p = ripper_parser_params(vparser, false);
-
- rb_ruby_ripper_parse0(p);
- return rb_ruby_parser_result(p);
-}
-
-static VALUE
-ripper_ensure(VALUE vparser)
-{
- struct parser_params *p = ripper_parser_params(vparser, false);
-
- rb_ruby_parser_set_parsing_thread(p, Qnil);
- return Qnil;
-}
-
-/*
- * call-seq:
- * ripper.parse
- *
- * Start parsing and returns the value of the root action.
- */
-static VALUE
-ripper_parse(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, true);
- VALUE result;
-
- if (!NIL_P(rb_ruby_parser_parsing_thread(p))) {
- if (rb_ruby_parser_parsing_thread(p) == rb_thread_current())
- rb_raise(rb_eArgError, "Ripper#parse is not reentrant");
- else
- rb_raise(rb_eArgError, "Ripper#parse is not multithread-safe");
- }
- rb_ruby_parser_set_parsing_thread(p, rb_thread_current());
- result = rb_ensure(ripper_parse0, self, ripper_ensure, self);
- RB_GC_GUARD(self);
-
- return result;
-}
-
-/*
- * call-seq:
- * ripper.column -> Integer
- *
- * Return column number of current parsing line.
- * This number starts from 0.
- */
-static VALUE
-ripper_column(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, true);
- long col;
-
- if (NIL_P(rb_ruby_parser_parsing_thread(p))) return Qnil;
- col = rb_ruby_ripper_column(p);
- return LONG2NUM(col);
-}
-
-/*
- * call-seq:
- * ripper.filename -> String
- *
- * Return current parsing filename.
- */
-static VALUE
-ripper_filename(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, true);
-
- return rb_ruby_parser_ruby_sourcefile_string(p);
-}
-
-/*
- * call-seq:
- * ripper.lineno -> Integer
- *
- * Return line number of current parsing line.
- * This number starts from 1.
- */
-static VALUE
-ripper_lineno(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, true);
-
- if (NIL_P(rb_ruby_parser_parsing_thread(p))) return Qnil;
- return INT2NUM(rb_ruby_parser_ruby_sourceline(p));
-}
-
-/*
- * call-seq:
- * ripper.state -> Integer
- *
- * Return scanner state of current token.
- */
-static VALUE
-ripper_state(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, true);
-
- if (NIL_P(rb_ruby_parser_parsing_thread(p))) return Qnil;
- return INT2NUM(rb_ruby_parser_lex_state(p));
-}
-
-/*
- * call-seq:
- * ripper.token -> String
- *
- * Return the current token string.
- */
-static VALUE
-ripper_token(VALUE self)
-{
- struct parser_params *p = ripper_parser_params(self, true);
- long pos, len;
- VALUE str;
-
- if (NIL_P(rb_ruby_parser_parsing_thread(p))) return Qnil;
- pos = rb_ruby_ripper_column(p);
- len = rb_ruby_ripper_token_len(p);
- str = rb_str_new_parser_string(rb_ruby_ripper_lex_lastline(p));
- return rb_str_subseq(str, pos, len);
-}
-
-#ifdef RIPPER_DEBUG
-/* :nodoc: */
-static VALUE
-ripper_assert_Qundef(VALUE self, VALUE obj, VALUE msg)
-{
- StringValue(msg);
- if (UNDEF_P(obj)) {
- rb_raise(rb_eArgError, "%"PRIsVALUE, msg);
- }
- return Qnil;
-}
-
-/* :nodoc: */
-static VALUE
-ripper_raw_value(VALUE self, VALUE obj)
-{
- return ULONG2NUM(obj);
-}
-
-/* :nodoc: */
-static VALUE
-ripper_validate_object(VALUE self, VALUE x)
-{
- if (x == Qfalse) return x;
- if (x == Qtrue) return x;
- if (NIL_P(x)) return x;
- if (UNDEF_P(x))
- rb_raise(rb_eArgError, "Qundef given");
- if (FIXNUM_P(x)) return x;
- if (SYMBOL_P(x)) return x;
- switch (BUILTIN_TYPE(x)) {
- case T_STRING:
- case T_OBJECT:
- case T_ARRAY:
- case T_BIGNUM:
- case T_FLOAT:
- case T_COMPLEX:
- case T_RATIONAL:
- break;
- default:
- rb_raise(rb_eArgError, "wrong type of ruby object: %p (%s)",
- (void *)x, rb_obj_classname(x));
- }
- if (!RBASIC_CLASS(x)) {
- rb_raise(rb_eArgError, "hidden ruby object: %p (%s)",
- (void *)x, rb_builtin_type_name(TYPE(x)));
- }
- return x;
-}
-#endif
-
-#ifdef UNIVERSAL_PARSER
-struct lex_state_name_arg {
- struct parser_params *p;
- VALUE state;
-};
-
-static VALUE
-lex_state_name0(VALUE a)
-{
- struct lex_state_name_arg *arg = (void *)a;
-
- return rb_ruby_ripper_lex_state_name(arg->p, NUM2INT(arg->state));
-}
-#endif
-
-/*
- * call-seq:
- * Ripper.lex_state_name(integer) -> string
- *
- * Returns a string representation of lex_state.
- */
-#ifdef UNIVERSAL_PARSER
-static VALUE
-ripper_lex_state_name(VALUE self, VALUE state)
-{
- struct parser_params *p;
- struct lex_state_name_arg args;
-
- p = rb_parser_params_new();
-
- args.p = p;
- args.state = state;
-
- return rb_ensure(lex_state_name0, (VALUE)&args, parser_free, (VALUE)p);
-}
-#else
-static VALUE
-ripper_lex_state_name(VALUE self, VALUE state)
-{
- return rb_ruby_ripper_lex_state_name(0, NUM2INT(state));
-}
-#endif
-
-void
-Init_ripper(void)
-{
- ripper_init_eventids1();
- ripper_init_eventids2();
- id_warn = rb_intern_const("warn");
- id_warning = rb_intern_const("warning");
- id_gets = rb_intern_const("gets");
- id_assoc = rb_intern_const("=>");
-
- InitVM(ripper);
-}
-
-void
-InitVM_ripper(void)
-{
- VALUE Ripper;
-
- Ripper = rb_define_class("Ripper", rb_cObject);
- /* version of Ripper */
- rb_define_const(Ripper, "Version", rb_usascii_str_new2(RIPPER_VERSION));
- rb_define_alloc_func(Ripper, ripper_s_allocate);
- rb_define_method(Ripper, "initialize", ripper_initialize, -1);
- rb_define_method(Ripper, "parse", ripper_parse, 0);
- rb_define_method(Ripper, "column", ripper_column, 0);
- rb_define_method(Ripper, "filename", ripper_filename, 0);
- rb_define_method(Ripper, "lineno", ripper_lineno, 0);
- rb_define_method(Ripper, "state", ripper_state, 0);
- rb_define_method(Ripper, "token", ripper_token, 0);
- rb_define_method(Ripper, "end_seen?", ripper_parser_end_seen_p, 0);
- rb_define_method(Ripper, "encoding", ripper_parser_encoding, 0);
- rb_define_method(Ripper, "yydebug", ripper_parser_get_yydebug, 0);
- rb_define_method(Ripper, "yydebug=", ripper_parser_set_yydebug, 1);
- rb_define_method(Ripper, "debug_output", ripper_parser_get_debug_output, 0);
- rb_define_method(Ripper, "debug_output=", ripper_parser_set_debug_output, 1);
- rb_define_method(Ripper, "error?", ripper_error_p, 0);
-#ifdef RIPPER_DEBUG
- rb_define_method(Ripper, "assert_Qundef", ripper_assert_Qundef, 2);
- rb_define_method(Ripper, "rawVALUE", ripper_raw_value, 1);
- rb_define_method(Ripper, "validate_object", ripper_validate_object, 1);
-#endif
-
- rb_define_singleton_method(Ripper, "dedent_string", parser_dedent_string, 2);
- rb_define_private_method(Ripper, "dedent_string", parser_dedent_string, 2);
-
- rb_define_singleton_method(Ripper, "lex_state_name", ripper_lex_state_name, 1);
-
-<% @exprs.each do |expr, desc| -%>
- /* <%=desc%> */
- rb_define_const(Ripper, "<%=expr%>", INT2NUM(<%=expr%>));
-<% end %>
- ripper_init_eventids1_table(Ripper);
- ripper_init_eventids2_table(Ripper);
-
-# if 0
- /* Hack to let RDoc document SCRIPT_LINES__ */
-
- /*
- * When a Hash is assigned to +SCRIPT_LINES__+ the contents of files loaded
- * after the assignment will be added as an Array of lines with the file
- * name as the key.
- */
- rb_define_global_const("SCRIPT_LINES__", Qnil);
-#endif
-}
diff --git a/ext/ripper/ripper_init.h b/ext/ripper/ripper_init.h
deleted file mode 100644
index 9d228107d1..0000000000
--- a/ext/ripper/ripper_init.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef RIPPER_INIT_H
-#define RIPPER_INIT_H
-
-PRINTF_ARGS(void ripper_compile_error(struct parser_params*, const char *fmt, ...), 2, 3);
-
-#endif /* RIPPER_INIT_H */
diff --git a/ext/ripper/tools/dsl.rb b/ext/ripper/tools/dsl.rb
index 38f859dd97..49ff51711f 100644
--- a/ext/ripper/tools/dsl.rb
+++ b/ext/ripper/tools/dsl.rb
@@ -1,177 +1,83 @@
-# frozen_string_literal: true
-
# Simple DSL implementation for Ripper code generation
#
-# input: /*% ripper: stmts_add!(stmts_new!, void_stmt!) %*/
+# input: /*% ripper: stmts_add(stmts_new, void_stmt) %*/
# output:
# VALUE v1, v2;
# v1 = dispatch0(stmts_new);
# v2 = dispatch0(void_stmt);
# $$ = dispatch2(stmts_add, v1, v2);
-#
-# - The code must be a single line.
-#
-# - The code is basically Ruby code, even if it appears like in C and
-# the result will be processed as C. e.g., comments need to be in
-# Ruby style.
-
-class DSL
- TAG_PATTERN = /(?><[a-zA-Z0-9_]+>)/.source
- NAME_PATTERN = /(?>\$|\d+|[a-zA-Z_][a-zA-Z0-9_]*|\[[a-zA-Z_.][-a-zA-Z0-9_.]*\])(?>(?:\.|->)[a-zA-Z_][a-zA-Z0-9_]*)*/.source
- NOT_REF_PATTERN = /(?>\#.*|[^\"$@]*|"(?>\\.|[^\"])*")/.source
-
- def self.line?(line, lineno = nil, indent: nil)
- if %r<(?<space>\s*)/\*% *ripper(?:\[(?<option>.*?)\])?: *(?<code>.*?) *%\*/> =~ line
- new(code, comma_split(option), lineno, indent: indent || space)
- end
- end
-
- def self.comma_split(str)
- str or return []
- str.scan(/(([^(,)]+|\((?:,|\g<0>)*\))+)/).map(&:first)
- end
-
- using Module.new {
- refine Array do
- def to_s
- if empty?
- "rb_ary_new()"
- else
- "rb_ary_new_from_args(#{size}, #{map(&:to_s).join(', ')})"
- end
- end
- end
- }
-
- class Var
- class Table < Hash
- def initialize(&block)
- super() {|tbl, arg|
- tbl.fetch(arg, &block)
- }
- end
-
- def fetch(arg, &block)
- super {
- self[arg] = Var.new(self, arg, &block)
- }
- end
-
- def add(&block)
- v = new_var
- self[v] = Var.new(self, v, &block)
- end
-
- def defined?(name)
- name = name.to_s
- any? {|_, v| v.var == name}
- end
-
- def new_var
- "v#{size+1}"
- end
- end
- attr_reader :var, :value
+$dollar = "$$"
+alias $$ $dollar
- PRETTY_PRINT_INSTANCE_VARIABLES = instance_methods(false).freeze
-
- def pretty_print_instance_variables
- PRETTY_PRINT_INSTANCE_VARIABLES
- end
-
- alias to_s var
-
- def initialize(table, arg, &block)
- @var = table.new_var
- @value = yield arg
- @table = table
- end
-
- # Indexing.
- #
- # $:1 -> v1=get_value($:1)
- # $:1[0] -> rb_ary_entry(v1, 0)
- # $:1[0..1] -> [rb_ary_entry(v1, 0), rb_ary_entry(v1, 1)]
- # *$:1[0..1] -> rb_ary_entry(v1, 0), rb_ary_entry(v1, 1)
- #
- # Splat needs `[range]` because `Var` does not have the length info.
- def [](idx)
- if ::Range === idx
- idx.map {|i| self[i]}
- else
- @table.fetch("#@var[#{idx}]") {"rb_ary_entry(#{@var}, #{idx})"}
- end
- end
- end
-
- def initialize(code, options, lineno = nil, indent: "\t\t\t")
- @lineno = lineno
- @indent = indent
+class DSL
+ def initialize(code, options)
@events = {}
@error = options.include?("error")
+ @brace = options.include?("brace")
if options.include?("final")
@final = "p->result"
else
- @final = (options.grep(/\A\$#{NAME_PATTERN}\z/o)[0] || "p->s_lvalue")
+ @final = (options.grep(/\A\$(?:\$|\d+)\z/)[0] || "$$")
end
+ @vars = 0
- bind = dsl_binding
- @var_table = Var::Table.new {|arg| "get_value(#{arg})"}
- code = code.gsub(%r[\G#{NOT_REF_PATTERN}\K(\$|\$:|@)#{TAG_PATTERN}?#{NAME_PATTERN}]o) {
- if (arg = $&) == "$:$"
- '"p->s_lvalue"'
- elsif arg.start_with?("$:")
- "(#{@var_table[arg]}=@var_table[#{arg.dump}])"
- else
- arg.dump
- end
- }
- @last_value = bind.eval(code)
- rescue SyntaxError
- $stderr.puts "error on line #{@lineno}" if @lineno
- raise
- end
+ # create $1 == "$1", $2 == "$2", ...
+ s = (1..20).map {|n| "$#{n}"}
+ re = Array.new(s.size, "([^\0]+)")
+ /#{re.join("\0")}/ =~ s.join("\0")
- def dsl_binding(p = "p")
# struct parser_params *p
- binding
+ p = p = "p"
+
+ @code = ""
+ @last_value = eval(code)
end
attr_reader :events
undef lambda
undef hash
- undef :class
+ undef class
def generate
- s = "#@final=#@last_value;"
+ s = "#@code#@final=#@last_value;"
+ s = "{VALUE #{ (1..@vars).map {|v| "v#{ v }" }.join(",") };#{ s }}" if @vars > 0
s << "ripper_error(p);" if @error
- unless @var_table.empty?
- vars = @var_table.map {|_, v| "#{v.var}=#{v.value}"}.join(", ")
- s = "VALUE #{ vars }; #{ s }"
- end
- "#{@indent}{#{s}}"
+ s = "{#{ s }}" if @brace
+ "\t\t\t#{s}"
end
- def add_event(event, args)
+ def new_var
+ "v#{ @vars += 1 }"
+ end
+
+ def opt_event(event, default, addend)
+ add_event(event, [default, addend], true)
+ end
+
+ def add_event(event, args, qundef_check = false)
event = event.to_s.sub(/!\z/, "")
@events[event] = args.size
vars = []
args.each do |arg|
- arg = @var_table.add {arg} unless Var === arg
- vars << arg
+ vars << v = new_var
+ @code << "#{ v }=#{ arg };"
end
- @var_table.add {"dispatch#{ args.size }(#{ [event, *vars].join(",") })"}
+ v = new_var
+ d = "dispatch#{ args.size }(#{ [event, *vars].join(",") })"
+ d = "#{ vars.last }==Qundef ? #{ vars.first } : #{ d }" if qundef_check
+ @code << "#{ v }=#{ d };"
+ v
end
def method_missing(event, *args)
if event.to_s =~ /!\z/
add_event(event, args)
- elsif args.empty? and (/\Aid[A-Z_]/ =~ event or @var_table.defined?(event))
+ elsif args.empty? and /\Aid[A-Z_]/ =~ event.to_s
event
else
- "#{ event }(#{ args.map(&:to_s).join(", ") })"
+ "#{ event }(#{ args.join(", ") })"
end
end
@@ -179,3 +85,4 @@ class DSL
name
end
end
+
diff --git a/ext/ripper/tools/generate.rb b/ext/ripper/tools/generate.rb
index 57ecac0b39..883e6ef2df 100644
--- a/ext/ripper/tools/generate.rb
+++ b/ext/ripper/tools/generate.rb
@@ -11,7 +11,7 @@ def main
parser = @parser = OptionParser.new
parser.banner = "Usage: #{File.basename($0)} --mode=MODE [--ids1src=PATH] [--ids2src=PATH] [--output=PATH]"
- parser.on('--mode=MODE', 'check, eventids1_h, eventids1, or eventids2table.') {|m|
+ parser.on('--mode=MODE', 'check, eventids1, or eventids2table.') {|m|
mode = m
}
parser.on('--ids1src=PATH', 'A source file of event-IDs 1 (parse.y).') {|path|
@@ -45,9 +45,6 @@ def main
abort "event crash: #{common.join(' ')}"
end
exit 0
- when 'eventids1_h'
- usage 'no --ids1src' unless ids1src
- result = generate_eventids1_h(read_ids1(ids1src))
when 'eventids1'
usage 'no --ids1src' unless ids1src
result = generate_eventids1(read_ids1(ids1src))
@@ -70,44 +67,28 @@ def usage(msg)
exit false
end
-def generate_eventids1_h(ids)
+def generate_eventids1(ids)
buf = "".dup
- buf << %Q[#ifndef RIPPER_EVENTIDS1\n]
- buf << %Q[#define RIPPER_EVENTIDS1\n]
- buf << %Q[\n]
- buf << %Q[#define RIPPER_ID(n) ripper_parser_ids.id_ ## n\n]
- buf << %Q[void ripper_init_eventids1(void);\n]
- buf << %Q[void ripper_init_eventids1_table(VALUE self);\n]
- buf << %Q[\n]
- buf << %Q[struct ripper_parser_ids {\n]
+ buf << %Q[static struct {\n]
ids.each do |id, arity|
buf << %Q[ ID id_#{id};\n]
end
- buf << %Q[};\n]
- buf << %Q[\n]
- buf << %Q[#endif /* RIPPER_EVENTIDS1 */\n]
- buf << %Q[\n]
-end
-
-def generate_eventids1(ids)
- buf = "".dup
- buf << %Q[#include "ruby/ruby.h"\n]
- buf << %Q[#include "eventids1.h"\n]
+ buf << %Q[} ripper_parser_ids;\n]
buf << %Q[\n]
- buf << %Q[struct ripper_parser_ids ripper_parser_ids;\n]
+ ids.each do |id, arity|
+ buf << %Q[#define ripper_id_#{id} ripper_parser_ids.id_#{id}\n]
+ end
buf << %Q[\n]
- buf << %Q[void\n]
+ buf << %Q[static void\n]
buf << %Q[ripper_init_eventids1(void)\n]
buf << %Q[{\n]
- buf << %Q[#define set_id1(name) RIPPER_ID(name) = rb_intern_const("on_"#name)\n]
+ buf << %Q[#define set_id1(name) ripper_id_##name = rb_intern_const("on_"#name)\n]
ids.each do |id, arity|
buf << %Q[ set_id1(#{id});\n]
end
buf << %Q[}\n]
buf << %Q[\n]
- buf << %Q[#define intern_sym(name) ID2SYM(rb_intern_const(name))\n]
- buf << %Q[\n]
- buf << %Q[void\n]
+ buf << %Q[static void\n]
buf << %Q[ripper_init_eventids1_table(VALUE self)\n]
buf << %Q[{\n]
buf << %Q[ VALUE h = rb_hash_new();\n]
@@ -121,11 +102,7 @@ end
def generate_eventids2_table(ids)
buf = "".dup
- buf << %Q[#include "ruby/ruby.h"\n]
- buf << %Q[\n]
- buf << %Q[#define intern_sym(name) ID2SYM(rb_intern_const(name))\n]
- buf << %Q[\n]
- buf << %Q[void\n]
+ buf << %Q[static void\n]
buf << %Q[ripper_init_eventids2_table(VALUE self)\n]
buf << %Q[{\n]
buf << %Q[ VALUE h = rb_hash_new();\n]
@@ -134,8 +111,6 @@ def generate_eventids2_table(ids)
buf << %Q[ rb_hash_aset(h, intern_sym("#{id}"), INT2FIX(1));\n]
end
buf << %Q[}\n]
- buf << %Q[\n]
- buf << %Q[#define RIPPER_EVENTIDS2_TABLE_SIZE #{ids.size}\n]
buf
end
@@ -171,7 +146,9 @@ def read_ids1_with_locations(path)
line.scan(/\bdispatch(\d)\((\w+)/) do |arity, event|
(h[event] ||= []).push [f.lineno, arity.to_i]
end
- if gen = DSL.line?(line, f.lineno)
+ if line =~ %r</\*% *ripper(?:\[(.*?)\])?: *(.*?) *%\*/>
+ gen = DSL.new($2, ($1 || "").split(","))
+ gen.generate
gen.events.each do |event, arity|
(h[event] ||= []).push [f.lineno, arity.to_i]
end
diff --git a/ext/ripper/tools/preproc.rb b/ext/ripper/tools/preproc.rb
index 5e8a6e0cb5..cd85a5da61 100644
--- a/ext/ripper/tools/preproc.rb
+++ b/ext/ripper/tools/preproc.rb
@@ -5,15 +5,11 @@ require 'optparse'
def main
output = nil
- template = nil
parser = OptionParser.new
- parser.banner = "Usage: #{File.basename($0)} [--output=PATH] [--template=PATH] <parse.y>"
+ parser.banner = "Usage: #{File.basename($0)} [--output=PATH] <parse.y>"
parser.on('--output=PATH', 'An output file.') {|path|
output = path
}
- parser.on('--template=PATH', 'An template file.') {|path|
- template = path
- }
parser.on('--help', 'Prints this message and quit.') {
puts parser.help
exit true
@@ -21,56 +17,50 @@ def main
begin
parser.parse!
rescue OptionParser::ParseError => err
- warn err.message
- abort parser.help
+ $stderr.puts err.message
+ $stderr.puts parser.help
+ exit false
end
- out = "".dup
- if ARGV[0] == "-"
- unless ARGV.size == 2
- abort "wrong number of arguments (#{ARGV.size} for 2)"
- end
- process STDIN, out, ARGV[1], template
- else
- unless ARGV.size == 1
- abort "wrong number of arguments (#{ARGV.size} for 1)"
- end
- File.open(ARGV[0]) {|f|
- process f, out, ARGV[0], template
- }
+ unless ARGV.size == 1
+ abort "wrong number of arguments (#{ARGV.size} for 1)"
end
+ out = "".dup
+ File.open(ARGV[0]) {|f|
+ prelude f, out
+ grammar f, out
+ usercode f, out
+ }
if output
- File.write(output, out)
+ File.open(output, 'w') {|f|
+ f.write out
+ }
else
print out
end
end
-def process(f, out, path, template)
- prelude f, out
- grammar f, out
- usercode f, out, path, template
-end
-
-require_relative 'dsl'
-
-def generate_line(f, out)
+def prelude(f, out)
+ @exprs = {}
+ lex_state_def = false
while line = f.gets
- case
- when gen = DSL.line?(line, f.lineno)
- out << gen.generate << "\n"
- when line.start_with?("%%")
+ case line
+ when /\A%%/
out << "%%\n"
- break
+ return
+ when /\A%token/, /\A} <node>/
+ out << line.sub(/<\w+>/, '<val>')
+ when /\A%type/
+ out << line.sub(/<\w+>/, '<val>')
+ when /^enum lex_state_(?:bits|e) \{/
+ lex_state_def = true
+ out << line
+ when /^\}/
+ lex_state_def = false
+ out << line
else
- out << yield(line)
+ out << line
end
- end
-end
-
-def prelude(f, out)
- @exprs = {}
- generate_line(f, out) do |line|
- if (/^enum lex_state_(?:bits|e) \{/ =~ line)..(/^\}/ =~ line)
+ if lex_state_def
case line
when /^\s*(EXPR_\w+),\s+\/\*(.+)\*\//
@exprs[$1.chomp("_bit")] = $2.strip
@@ -80,45 +70,38 @@ def prelude(f, out)
@exprs[name] = "equals to " + (val.start_with?("(") ? "<tt>#{val}</tt>" : "+#{val}+")
end
end
- line
end
end
+require_relative "dsl"
+
def grammar(f, out)
- generate_line(f, out) do |line|
+ while line = f.gets
case line
+ when %r</\*% *ripper(?:\[(.*?)\])?: *(.*?) *%\*/>
+ out << DSL.new($2, ($1 || "").split(",")).generate << "\n"
when %r</\*%%%\*/>
- "#if 0\n"
+ out << "#if 0\n"
when %r</\*%>
- "#endif\n"
+ out << "#endif\n"
when %r<%\*/>
- "\n"
+ out << "\n"
+ when /\A%%/
+ out << "%%\n"
+ return
else
- line
+ out << line
end
end
end
-def usercode(f, out, path, template)
+def usercode(f, out)
require 'erb'
- lineno = nil
- src = nil
compiler = ERB::Compiler.new('%-')
compiler.put_cmd = compiler.insert_cmd = "out.<<"
-
- if template
- File.open(template) do |f|
- out.clear
- lineno = f.lineno
- src, = compiler.compile(f.read)
- path = template
- end
- else
- lineno = f.lineno
- src, = compiler.compile(f.read)
- end
-
- eval(src, binding, path, lineno)
+ lineno = f.lineno
+ src, = compiler.compile(f.read)
+ eval(src, binding, f.path, lineno)
end
main
diff --git a/ext/socket/ancdata.c b/ext/socket/ancdata.c
index 6ef040b692..7406177de2 100644
--- a/ext/socket/ancdata.c
+++ b/ext/socket/ancdata.c
@@ -1555,10 +1555,6 @@ bsock_recvmsg_internal(VALUE sock,
ss = rb_recvmsg(fptr->fd, &mh, flags);
- if (ss == 0 && !rsock_is_dgram(fptr)) {
- return Qnil;
- }
-
if (ss == -1) {
int e;
if (!nonblock && rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
diff --git a/ext/socket/basicsocket.c b/ext/socket/basicsocket.c
index 8af8374ecf..54c369f6fc 100644
--- a/ext/socket/basicsocket.c
+++ b/ext/socket/basicsocket.c
@@ -124,7 +124,7 @@ bsock_close_read(VALUE sock)
rb_io_t *fptr;
GetOpenFile(sock, fptr);
- shutdown(fptr->fd, SHUT_RD);
+ shutdown(fptr->fd, 0);
if (!(fptr->mode & FMODE_WRITABLE)) {
return rb_io_close(sock);
}
@@ -157,7 +157,7 @@ bsock_close_write(VALUE sock)
if (!(fptr->mode & FMODE_READABLE)) {
return rb_io_close(sock);
}
- shutdown(fptr->fd, SHUT_WR);
+ shutdown(fptr->fd, 1);
fptr->mode &= ~FMODE_WRITABLE;
return Qnil;
diff --git a/ext/socket/depend b/ext/socket/depend
index 750bb0734f..28c5540cd6 100644
--- a/ext/socket/depend
+++ b/ext/socket/depend
@@ -13,7 +13,6 @@ constdefs.c: constdefs.h
ancdata.o: $(RUBY_EXTCONF_H)
ancdata.o: $(arch_hdrdir)/ruby/config.h
ancdata.o: $(hdrdir)/ruby/assert.h
-ancdata.o: $(hdrdir)/ruby/atomic.h
ancdata.o: $(hdrdir)/ruby/backward.h
ancdata.o: $(hdrdir)/ruby/backward/2/assume.h
ancdata.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -66,7 +65,6 @@ ancdata.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ancdata.o: $(hdrdir)/ruby/internal/attr/noinline.h
ancdata.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ancdata.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ancdata.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ancdata.o: $(hdrdir)/ruby/internal/attr/pure.h
ancdata.o: $(hdrdir)/ruby/internal/attr/restrict.h
ancdata.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -135,6 +133,7 @@ ancdata.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ancdata.o: $(hdrdir)/ruby/internal/intern/error.h
ancdata.o: $(hdrdir)/ruby/internal/intern/eval.h
ancdata.o: $(hdrdir)/ruby/internal/intern/file.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/gc.h
ancdata.o: $(hdrdir)/ruby/internal/intern/hash.h
ancdata.o: $(hdrdir)/ruby/internal/intern/io.h
ancdata.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -165,12 +164,12 @@ ancdata.o: $(hdrdir)/ruby/internal/memory.h
ancdata.o: $(hdrdir)/ruby/internal/method.h
ancdata.o: $(hdrdir)/ruby/internal/module.h
ancdata.o: $(hdrdir)/ruby/internal/newobj.h
+ancdata.o: $(hdrdir)/ruby/internal/rgengc.h
ancdata.o: $(hdrdir)/ruby/internal/scan_args.h
ancdata.o: $(hdrdir)/ruby/internal/special_consts.h
ancdata.o: $(hdrdir)/ruby/internal/static_assert.h
ancdata.o: $(hdrdir)/ruby/internal/stdalign.h
ancdata.o: $(hdrdir)/ruby/internal/stdbool.h
-ancdata.o: $(hdrdir)/ruby/internal/stdckdint.h
ancdata.o: $(hdrdir)/ruby/internal/symbol.h
ancdata.o: $(hdrdir)/ruby/internal/value.h
ancdata.o: $(hdrdir)/ruby/internal/value_type.h
@@ -185,46 +184,27 @@ ancdata.o: $(hdrdir)/ruby/ruby.h
ancdata.o: $(hdrdir)/ruby/st.h
ancdata.o: $(hdrdir)/ruby/subst.h
ancdata.o: $(hdrdir)/ruby/thread.h
-ancdata.o: $(hdrdir)/ruby/thread_native.h
ancdata.o: $(hdrdir)/ruby/util.h
-ancdata.o: $(hdrdir)/ruby/version.h
-ancdata.o: $(top_srcdir)/ccan/check_type/check_type.h
-ancdata.o: $(top_srcdir)/ccan/container_of/container_of.h
-ancdata.o: $(top_srcdir)/ccan/list/list.h
-ancdata.o: $(top_srcdir)/ccan/str/str.h
ancdata.o: $(top_srcdir)/internal.h
ancdata.o: $(top_srcdir)/internal/array.h
-ancdata.o: $(top_srcdir)/internal/basic_operators.h
ancdata.o: $(top_srcdir)/internal/compilers.h
ancdata.o: $(top_srcdir)/internal/error.h
ancdata.o: $(top_srcdir)/internal/gc.h
-ancdata.o: $(top_srcdir)/internal/imemo.h
ancdata.o: $(top_srcdir)/internal/io.h
-ancdata.o: $(top_srcdir)/internal/sanitizers.h
ancdata.o: $(top_srcdir)/internal/serial.h
ancdata.o: $(top_srcdir)/internal/static_assert.h
ancdata.o: $(top_srcdir)/internal/string.h
ancdata.o: $(top_srcdir)/internal/thread.h
ancdata.o: $(top_srcdir)/internal/vm.h
ancdata.o: $(top_srcdir)/internal/warnings.h
-ancdata.o: $(top_srcdir)/method.h
-ancdata.o: $(top_srcdir)/node.h
-ancdata.o: $(top_srcdir)/ruby_assert.h
-ancdata.o: $(top_srcdir)/ruby_atomic.h
-ancdata.o: $(top_srcdir)/rubyparser.h
ancdata.o: $(top_srcdir)/shape.h
-ancdata.o: $(top_srcdir)/thread_pthread.h
-ancdata.o: $(top_srcdir)/vm_core.h
-ancdata.o: $(top_srcdir)/vm_opts.h
ancdata.o: ancdata.c
ancdata.o: constdefs.h
ancdata.o: rubysocket.h
ancdata.o: sockport.h
-ancdata.o: {$(VPATH)}id.h
basicsocket.o: $(RUBY_EXTCONF_H)
basicsocket.o: $(arch_hdrdir)/ruby/config.h
basicsocket.o: $(hdrdir)/ruby/assert.h
-basicsocket.o: $(hdrdir)/ruby/atomic.h
basicsocket.o: $(hdrdir)/ruby/backward.h
basicsocket.o: $(hdrdir)/ruby/backward/2/assume.h
basicsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -277,7 +257,6 @@ basicsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
basicsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
basicsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
basicsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-basicsocket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
basicsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
basicsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
basicsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -346,6 +325,7 @@ basicsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/error.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/io.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -376,12 +356,12 @@ basicsocket.o: $(hdrdir)/ruby/internal/memory.h
basicsocket.o: $(hdrdir)/ruby/internal/method.h
basicsocket.o: $(hdrdir)/ruby/internal/module.h
basicsocket.o: $(hdrdir)/ruby/internal/newobj.h
+basicsocket.o: $(hdrdir)/ruby/internal/rgengc.h
basicsocket.o: $(hdrdir)/ruby/internal/scan_args.h
basicsocket.o: $(hdrdir)/ruby/internal/special_consts.h
basicsocket.o: $(hdrdir)/ruby/internal/static_assert.h
basicsocket.o: $(hdrdir)/ruby/internal/stdalign.h
basicsocket.o: $(hdrdir)/ruby/internal/stdbool.h
-basicsocket.o: $(hdrdir)/ruby/internal/stdckdint.h
basicsocket.o: $(hdrdir)/ruby/internal/symbol.h
basicsocket.o: $(hdrdir)/ruby/internal/value.h
basicsocket.o: $(hdrdir)/ruby/internal/value_type.h
@@ -396,46 +376,27 @@ basicsocket.o: $(hdrdir)/ruby/ruby.h
basicsocket.o: $(hdrdir)/ruby/st.h
basicsocket.o: $(hdrdir)/ruby/subst.h
basicsocket.o: $(hdrdir)/ruby/thread.h
-basicsocket.o: $(hdrdir)/ruby/thread_native.h
basicsocket.o: $(hdrdir)/ruby/util.h
-basicsocket.o: $(hdrdir)/ruby/version.h
-basicsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
-basicsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
-basicsocket.o: $(top_srcdir)/ccan/list/list.h
-basicsocket.o: $(top_srcdir)/ccan/str/str.h
basicsocket.o: $(top_srcdir)/internal.h
basicsocket.o: $(top_srcdir)/internal/array.h
-basicsocket.o: $(top_srcdir)/internal/basic_operators.h
basicsocket.o: $(top_srcdir)/internal/compilers.h
basicsocket.o: $(top_srcdir)/internal/error.h
basicsocket.o: $(top_srcdir)/internal/gc.h
-basicsocket.o: $(top_srcdir)/internal/imemo.h
basicsocket.o: $(top_srcdir)/internal/io.h
-basicsocket.o: $(top_srcdir)/internal/sanitizers.h
basicsocket.o: $(top_srcdir)/internal/serial.h
basicsocket.o: $(top_srcdir)/internal/static_assert.h
basicsocket.o: $(top_srcdir)/internal/string.h
basicsocket.o: $(top_srcdir)/internal/thread.h
basicsocket.o: $(top_srcdir)/internal/vm.h
basicsocket.o: $(top_srcdir)/internal/warnings.h
-basicsocket.o: $(top_srcdir)/method.h
-basicsocket.o: $(top_srcdir)/node.h
-basicsocket.o: $(top_srcdir)/ruby_assert.h
-basicsocket.o: $(top_srcdir)/ruby_atomic.h
-basicsocket.o: $(top_srcdir)/rubyparser.h
basicsocket.o: $(top_srcdir)/shape.h
-basicsocket.o: $(top_srcdir)/thread_pthread.h
-basicsocket.o: $(top_srcdir)/vm_core.h
-basicsocket.o: $(top_srcdir)/vm_opts.h
basicsocket.o: basicsocket.c
basicsocket.o: constdefs.h
basicsocket.o: rubysocket.h
basicsocket.o: sockport.h
-basicsocket.o: {$(VPATH)}id.h
constants.o: $(RUBY_EXTCONF_H)
constants.o: $(arch_hdrdir)/ruby/config.h
constants.o: $(hdrdir)/ruby/assert.h
-constants.o: $(hdrdir)/ruby/atomic.h
constants.o: $(hdrdir)/ruby/backward.h
constants.o: $(hdrdir)/ruby/backward/2/assume.h
constants.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -488,7 +449,6 @@ constants.o: $(hdrdir)/ruby/internal/attr/noexcept.h
constants.o: $(hdrdir)/ruby/internal/attr/noinline.h
constants.o: $(hdrdir)/ruby/internal/attr/nonnull.h
constants.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-constants.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
constants.o: $(hdrdir)/ruby/internal/attr/pure.h
constants.o: $(hdrdir)/ruby/internal/attr/restrict.h
constants.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -557,6 +517,7 @@ constants.o: $(hdrdir)/ruby/internal/intern/enumerator.h
constants.o: $(hdrdir)/ruby/internal/intern/error.h
constants.o: $(hdrdir)/ruby/internal/intern/eval.h
constants.o: $(hdrdir)/ruby/internal/intern/file.h
+constants.o: $(hdrdir)/ruby/internal/intern/gc.h
constants.o: $(hdrdir)/ruby/internal/intern/hash.h
constants.o: $(hdrdir)/ruby/internal/intern/io.h
constants.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -587,12 +548,12 @@ constants.o: $(hdrdir)/ruby/internal/memory.h
constants.o: $(hdrdir)/ruby/internal/method.h
constants.o: $(hdrdir)/ruby/internal/module.h
constants.o: $(hdrdir)/ruby/internal/newobj.h
+constants.o: $(hdrdir)/ruby/internal/rgengc.h
constants.o: $(hdrdir)/ruby/internal/scan_args.h
constants.o: $(hdrdir)/ruby/internal/special_consts.h
constants.o: $(hdrdir)/ruby/internal/static_assert.h
constants.o: $(hdrdir)/ruby/internal/stdalign.h
constants.o: $(hdrdir)/ruby/internal/stdbool.h
-constants.o: $(hdrdir)/ruby/internal/stdckdint.h
constants.o: $(hdrdir)/ruby/internal/symbol.h
constants.o: $(hdrdir)/ruby/internal/value.h
constants.o: $(hdrdir)/ruby/internal/value_type.h
@@ -607,47 +568,28 @@ constants.o: $(hdrdir)/ruby/ruby.h
constants.o: $(hdrdir)/ruby/st.h
constants.o: $(hdrdir)/ruby/subst.h
constants.o: $(hdrdir)/ruby/thread.h
-constants.o: $(hdrdir)/ruby/thread_native.h
constants.o: $(hdrdir)/ruby/util.h
-constants.o: $(hdrdir)/ruby/version.h
-constants.o: $(top_srcdir)/ccan/check_type/check_type.h
-constants.o: $(top_srcdir)/ccan/container_of/container_of.h
-constants.o: $(top_srcdir)/ccan/list/list.h
-constants.o: $(top_srcdir)/ccan/str/str.h
constants.o: $(top_srcdir)/internal.h
constants.o: $(top_srcdir)/internal/array.h
-constants.o: $(top_srcdir)/internal/basic_operators.h
constants.o: $(top_srcdir)/internal/compilers.h
constants.o: $(top_srcdir)/internal/error.h
constants.o: $(top_srcdir)/internal/gc.h
-constants.o: $(top_srcdir)/internal/imemo.h
constants.o: $(top_srcdir)/internal/io.h
-constants.o: $(top_srcdir)/internal/sanitizers.h
constants.o: $(top_srcdir)/internal/serial.h
constants.o: $(top_srcdir)/internal/static_assert.h
constants.o: $(top_srcdir)/internal/string.h
constants.o: $(top_srcdir)/internal/thread.h
constants.o: $(top_srcdir)/internal/vm.h
constants.o: $(top_srcdir)/internal/warnings.h
-constants.o: $(top_srcdir)/method.h
-constants.o: $(top_srcdir)/node.h
-constants.o: $(top_srcdir)/ruby_assert.h
-constants.o: $(top_srcdir)/ruby_atomic.h
-constants.o: $(top_srcdir)/rubyparser.h
constants.o: $(top_srcdir)/shape.h
-constants.o: $(top_srcdir)/thread_pthread.h
-constants.o: $(top_srcdir)/vm_core.h
-constants.o: $(top_srcdir)/vm_opts.h
constants.o: constants.c
constants.o: constdefs.c
constants.o: constdefs.h
constants.o: rubysocket.h
constants.o: sockport.h
-constants.o: {$(VPATH)}id.h
ifaddr.o: $(RUBY_EXTCONF_H)
ifaddr.o: $(arch_hdrdir)/ruby/config.h
ifaddr.o: $(hdrdir)/ruby/assert.h
-ifaddr.o: $(hdrdir)/ruby/atomic.h
ifaddr.o: $(hdrdir)/ruby/backward.h
ifaddr.o: $(hdrdir)/ruby/backward/2/assume.h
ifaddr.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -700,7 +642,6 @@ ifaddr.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ifaddr.o: $(hdrdir)/ruby/internal/attr/noinline.h
ifaddr.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ifaddr.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ifaddr.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ifaddr.o: $(hdrdir)/ruby/internal/attr/pure.h
ifaddr.o: $(hdrdir)/ruby/internal/attr/restrict.h
ifaddr.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -769,6 +710,7 @@ ifaddr.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/error.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/eval.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/file.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/gc.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/hash.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/io.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -799,12 +741,12 @@ ifaddr.o: $(hdrdir)/ruby/internal/memory.h
ifaddr.o: $(hdrdir)/ruby/internal/method.h
ifaddr.o: $(hdrdir)/ruby/internal/module.h
ifaddr.o: $(hdrdir)/ruby/internal/newobj.h
+ifaddr.o: $(hdrdir)/ruby/internal/rgengc.h
ifaddr.o: $(hdrdir)/ruby/internal/scan_args.h
ifaddr.o: $(hdrdir)/ruby/internal/special_consts.h
ifaddr.o: $(hdrdir)/ruby/internal/static_assert.h
ifaddr.o: $(hdrdir)/ruby/internal/stdalign.h
ifaddr.o: $(hdrdir)/ruby/internal/stdbool.h
-ifaddr.o: $(hdrdir)/ruby/internal/stdckdint.h
ifaddr.o: $(hdrdir)/ruby/internal/symbol.h
ifaddr.o: $(hdrdir)/ruby/internal/value.h
ifaddr.o: $(hdrdir)/ruby/internal/value_type.h
@@ -819,46 +761,27 @@ ifaddr.o: $(hdrdir)/ruby/ruby.h
ifaddr.o: $(hdrdir)/ruby/st.h
ifaddr.o: $(hdrdir)/ruby/subst.h
ifaddr.o: $(hdrdir)/ruby/thread.h
-ifaddr.o: $(hdrdir)/ruby/thread_native.h
ifaddr.o: $(hdrdir)/ruby/util.h
-ifaddr.o: $(hdrdir)/ruby/version.h
-ifaddr.o: $(top_srcdir)/ccan/check_type/check_type.h
-ifaddr.o: $(top_srcdir)/ccan/container_of/container_of.h
-ifaddr.o: $(top_srcdir)/ccan/list/list.h
-ifaddr.o: $(top_srcdir)/ccan/str/str.h
ifaddr.o: $(top_srcdir)/internal.h
ifaddr.o: $(top_srcdir)/internal/array.h
-ifaddr.o: $(top_srcdir)/internal/basic_operators.h
ifaddr.o: $(top_srcdir)/internal/compilers.h
ifaddr.o: $(top_srcdir)/internal/error.h
ifaddr.o: $(top_srcdir)/internal/gc.h
-ifaddr.o: $(top_srcdir)/internal/imemo.h
ifaddr.o: $(top_srcdir)/internal/io.h
-ifaddr.o: $(top_srcdir)/internal/sanitizers.h
ifaddr.o: $(top_srcdir)/internal/serial.h
ifaddr.o: $(top_srcdir)/internal/static_assert.h
ifaddr.o: $(top_srcdir)/internal/string.h
ifaddr.o: $(top_srcdir)/internal/thread.h
ifaddr.o: $(top_srcdir)/internal/vm.h
ifaddr.o: $(top_srcdir)/internal/warnings.h
-ifaddr.o: $(top_srcdir)/method.h
-ifaddr.o: $(top_srcdir)/node.h
-ifaddr.o: $(top_srcdir)/ruby_assert.h
-ifaddr.o: $(top_srcdir)/ruby_atomic.h
-ifaddr.o: $(top_srcdir)/rubyparser.h
ifaddr.o: $(top_srcdir)/shape.h
-ifaddr.o: $(top_srcdir)/thread_pthread.h
-ifaddr.o: $(top_srcdir)/vm_core.h
-ifaddr.o: $(top_srcdir)/vm_opts.h
ifaddr.o: constdefs.h
ifaddr.o: ifaddr.c
ifaddr.o: rubysocket.h
ifaddr.o: sockport.h
-ifaddr.o: {$(VPATH)}id.h
init.o: $(RUBY_EXTCONF_H)
init.o: $(arch_hdrdir)/ruby/config.h
init.o: $(hdrdir)/ruby/assert.h
-init.o: $(hdrdir)/ruby/atomic.h
init.o: $(hdrdir)/ruby/backward.h
init.o: $(hdrdir)/ruby/backward/2/assume.h
init.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -911,7 +834,6 @@ init.o: $(hdrdir)/ruby/internal/attr/noexcept.h
init.o: $(hdrdir)/ruby/internal/attr/noinline.h
init.o: $(hdrdir)/ruby/internal/attr/nonnull.h
init.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-init.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
init.o: $(hdrdir)/ruby/internal/attr/pure.h
init.o: $(hdrdir)/ruby/internal/attr/restrict.h
init.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -980,6 +902,7 @@ init.o: $(hdrdir)/ruby/internal/intern/enumerator.h
init.o: $(hdrdir)/ruby/internal/intern/error.h
init.o: $(hdrdir)/ruby/internal/intern/eval.h
init.o: $(hdrdir)/ruby/internal/intern/file.h
+init.o: $(hdrdir)/ruby/internal/intern/gc.h
init.o: $(hdrdir)/ruby/internal/intern/hash.h
init.o: $(hdrdir)/ruby/internal/intern/io.h
init.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1010,12 +933,12 @@ init.o: $(hdrdir)/ruby/internal/memory.h
init.o: $(hdrdir)/ruby/internal/method.h
init.o: $(hdrdir)/ruby/internal/module.h
init.o: $(hdrdir)/ruby/internal/newobj.h
+init.o: $(hdrdir)/ruby/internal/rgengc.h
init.o: $(hdrdir)/ruby/internal/scan_args.h
init.o: $(hdrdir)/ruby/internal/special_consts.h
init.o: $(hdrdir)/ruby/internal/static_assert.h
init.o: $(hdrdir)/ruby/internal/stdalign.h
init.o: $(hdrdir)/ruby/internal/stdbool.h
-init.o: $(hdrdir)/ruby/internal/stdckdint.h
init.o: $(hdrdir)/ruby/internal/symbol.h
init.o: $(hdrdir)/ruby/internal/value.h
init.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1030,46 +953,27 @@ init.o: $(hdrdir)/ruby/ruby.h
init.o: $(hdrdir)/ruby/st.h
init.o: $(hdrdir)/ruby/subst.h
init.o: $(hdrdir)/ruby/thread.h
-init.o: $(hdrdir)/ruby/thread_native.h
init.o: $(hdrdir)/ruby/util.h
-init.o: $(hdrdir)/ruby/version.h
-init.o: $(top_srcdir)/ccan/check_type/check_type.h
-init.o: $(top_srcdir)/ccan/container_of/container_of.h
-init.o: $(top_srcdir)/ccan/list/list.h
-init.o: $(top_srcdir)/ccan/str/str.h
init.o: $(top_srcdir)/internal.h
init.o: $(top_srcdir)/internal/array.h
-init.o: $(top_srcdir)/internal/basic_operators.h
init.o: $(top_srcdir)/internal/compilers.h
init.o: $(top_srcdir)/internal/error.h
init.o: $(top_srcdir)/internal/gc.h
-init.o: $(top_srcdir)/internal/imemo.h
init.o: $(top_srcdir)/internal/io.h
-init.o: $(top_srcdir)/internal/sanitizers.h
init.o: $(top_srcdir)/internal/serial.h
init.o: $(top_srcdir)/internal/static_assert.h
init.o: $(top_srcdir)/internal/string.h
init.o: $(top_srcdir)/internal/thread.h
init.o: $(top_srcdir)/internal/vm.h
init.o: $(top_srcdir)/internal/warnings.h
-init.o: $(top_srcdir)/method.h
-init.o: $(top_srcdir)/node.h
-init.o: $(top_srcdir)/ruby_assert.h
-init.o: $(top_srcdir)/ruby_atomic.h
-init.o: $(top_srcdir)/rubyparser.h
init.o: $(top_srcdir)/shape.h
-init.o: $(top_srcdir)/thread_pthread.h
-init.o: $(top_srcdir)/vm_core.h
-init.o: $(top_srcdir)/vm_opts.h
init.o: constdefs.h
init.o: init.c
init.o: rubysocket.h
init.o: sockport.h
-init.o: {$(VPATH)}id.h
ipsocket.o: $(RUBY_EXTCONF_H)
ipsocket.o: $(arch_hdrdir)/ruby/config.h
ipsocket.o: $(hdrdir)/ruby/assert.h
-ipsocket.o: $(hdrdir)/ruby/atomic.h
ipsocket.o: $(hdrdir)/ruby/backward.h
ipsocket.o: $(hdrdir)/ruby/backward/2/assume.h
ipsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -1122,7 +1026,6 @@ ipsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
ipsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
ipsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
ipsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-ipsocket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
ipsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
ipsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
ipsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1191,6 +1094,7 @@ ipsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/error.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/io.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1221,12 +1125,12 @@ ipsocket.o: $(hdrdir)/ruby/internal/memory.h
ipsocket.o: $(hdrdir)/ruby/internal/method.h
ipsocket.o: $(hdrdir)/ruby/internal/module.h
ipsocket.o: $(hdrdir)/ruby/internal/newobj.h
+ipsocket.o: $(hdrdir)/ruby/internal/rgengc.h
ipsocket.o: $(hdrdir)/ruby/internal/scan_args.h
ipsocket.o: $(hdrdir)/ruby/internal/special_consts.h
ipsocket.o: $(hdrdir)/ruby/internal/static_assert.h
ipsocket.o: $(hdrdir)/ruby/internal/stdalign.h
ipsocket.o: $(hdrdir)/ruby/internal/stdbool.h
-ipsocket.o: $(hdrdir)/ruby/internal/stdckdint.h
ipsocket.o: $(hdrdir)/ruby/internal/symbol.h
ipsocket.o: $(hdrdir)/ruby/internal/value.h
ipsocket.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1241,46 +1145,27 @@ ipsocket.o: $(hdrdir)/ruby/ruby.h
ipsocket.o: $(hdrdir)/ruby/st.h
ipsocket.o: $(hdrdir)/ruby/subst.h
ipsocket.o: $(hdrdir)/ruby/thread.h
-ipsocket.o: $(hdrdir)/ruby/thread_native.h
ipsocket.o: $(hdrdir)/ruby/util.h
-ipsocket.o: $(hdrdir)/ruby/version.h
-ipsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
-ipsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
-ipsocket.o: $(top_srcdir)/ccan/list/list.h
-ipsocket.o: $(top_srcdir)/ccan/str/str.h
ipsocket.o: $(top_srcdir)/internal.h
ipsocket.o: $(top_srcdir)/internal/array.h
-ipsocket.o: $(top_srcdir)/internal/basic_operators.h
ipsocket.o: $(top_srcdir)/internal/compilers.h
ipsocket.o: $(top_srcdir)/internal/error.h
ipsocket.o: $(top_srcdir)/internal/gc.h
-ipsocket.o: $(top_srcdir)/internal/imemo.h
ipsocket.o: $(top_srcdir)/internal/io.h
-ipsocket.o: $(top_srcdir)/internal/sanitizers.h
ipsocket.o: $(top_srcdir)/internal/serial.h
ipsocket.o: $(top_srcdir)/internal/static_assert.h
ipsocket.o: $(top_srcdir)/internal/string.h
ipsocket.o: $(top_srcdir)/internal/thread.h
ipsocket.o: $(top_srcdir)/internal/vm.h
ipsocket.o: $(top_srcdir)/internal/warnings.h
-ipsocket.o: $(top_srcdir)/method.h
-ipsocket.o: $(top_srcdir)/node.h
-ipsocket.o: $(top_srcdir)/ruby_assert.h
-ipsocket.o: $(top_srcdir)/ruby_atomic.h
-ipsocket.o: $(top_srcdir)/rubyparser.h
ipsocket.o: $(top_srcdir)/shape.h
-ipsocket.o: $(top_srcdir)/thread_pthread.h
-ipsocket.o: $(top_srcdir)/vm_core.h
-ipsocket.o: $(top_srcdir)/vm_opts.h
ipsocket.o: constdefs.h
ipsocket.o: ipsocket.c
ipsocket.o: rubysocket.h
ipsocket.o: sockport.h
-ipsocket.o: {$(VPATH)}id.h
option.o: $(RUBY_EXTCONF_H)
option.o: $(arch_hdrdir)/ruby/config.h
option.o: $(hdrdir)/ruby/assert.h
-option.o: $(hdrdir)/ruby/atomic.h
option.o: $(hdrdir)/ruby/backward.h
option.o: $(hdrdir)/ruby/backward/2/assume.h
option.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -1333,7 +1218,6 @@ option.o: $(hdrdir)/ruby/internal/attr/noexcept.h
option.o: $(hdrdir)/ruby/internal/attr/noinline.h
option.o: $(hdrdir)/ruby/internal/attr/nonnull.h
option.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-option.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
option.o: $(hdrdir)/ruby/internal/attr/pure.h
option.o: $(hdrdir)/ruby/internal/attr/restrict.h
option.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1402,6 +1286,7 @@ option.o: $(hdrdir)/ruby/internal/intern/enumerator.h
option.o: $(hdrdir)/ruby/internal/intern/error.h
option.o: $(hdrdir)/ruby/internal/intern/eval.h
option.o: $(hdrdir)/ruby/internal/intern/file.h
+option.o: $(hdrdir)/ruby/internal/intern/gc.h
option.o: $(hdrdir)/ruby/internal/intern/hash.h
option.o: $(hdrdir)/ruby/internal/intern/io.h
option.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1432,12 +1317,12 @@ option.o: $(hdrdir)/ruby/internal/memory.h
option.o: $(hdrdir)/ruby/internal/method.h
option.o: $(hdrdir)/ruby/internal/module.h
option.o: $(hdrdir)/ruby/internal/newobj.h
+option.o: $(hdrdir)/ruby/internal/rgengc.h
option.o: $(hdrdir)/ruby/internal/scan_args.h
option.o: $(hdrdir)/ruby/internal/special_consts.h
option.o: $(hdrdir)/ruby/internal/static_assert.h
option.o: $(hdrdir)/ruby/internal/stdalign.h
option.o: $(hdrdir)/ruby/internal/stdbool.h
-option.o: $(hdrdir)/ruby/internal/stdckdint.h
option.o: $(hdrdir)/ruby/internal/symbol.h
option.o: $(hdrdir)/ruby/internal/value.h
option.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1452,46 +1337,27 @@ option.o: $(hdrdir)/ruby/ruby.h
option.o: $(hdrdir)/ruby/st.h
option.o: $(hdrdir)/ruby/subst.h
option.o: $(hdrdir)/ruby/thread.h
-option.o: $(hdrdir)/ruby/thread_native.h
option.o: $(hdrdir)/ruby/util.h
-option.o: $(hdrdir)/ruby/version.h
-option.o: $(top_srcdir)/ccan/check_type/check_type.h
-option.o: $(top_srcdir)/ccan/container_of/container_of.h
-option.o: $(top_srcdir)/ccan/list/list.h
-option.o: $(top_srcdir)/ccan/str/str.h
option.o: $(top_srcdir)/internal.h
option.o: $(top_srcdir)/internal/array.h
-option.o: $(top_srcdir)/internal/basic_operators.h
option.o: $(top_srcdir)/internal/compilers.h
option.o: $(top_srcdir)/internal/error.h
option.o: $(top_srcdir)/internal/gc.h
-option.o: $(top_srcdir)/internal/imemo.h
option.o: $(top_srcdir)/internal/io.h
-option.o: $(top_srcdir)/internal/sanitizers.h
option.o: $(top_srcdir)/internal/serial.h
option.o: $(top_srcdir)/internal/static_assert.h
option.o: $(top_srcdir)/internal/string.h
option.o: $(top_srcdir)/internal/thread.h
option.o: $(top_srcdir)/internal/vm.h
option.o: $(top_srcdir)/internal/warnings.h
-option.o: $(top_srcdir)/method.h
-option.o: $(top_srcdir)/node.h
-option.o: $(top_srcdir)/ruby_assert.h
-option.o: $(top_srcdir)/ruby_atomic.h
-option.o: $(top_srcdir)/rubyparser.h
option.o: $(top_srcdir)/shape.h
-option.o: $(top_srcdir)/thread_pthread.h
-option.o: $(top_srcdir)/vm_core.h
-option.o: $(top_srcdir)/vm_opts.h
option.o: constdefs.h
option.o: option.c
option.o: rubysocket.h
option.o: sockport.h
-option.o: {$(VPATH)}id.h
raddrinfo.o: $(RUBY_EXTCONF_H)
raddrinfo.o: $(arch_hdrdir)/ruby/config.h
raddrinfo.o: $(hdrdir)/ruby/assert.h
-raddrinfo.o: $(hdrdir)/ruby/atomic.h
raddrinfo.o: $(hdrdir)/ruby/backward.h
raddrinfo.o: $(hdrdir)/ruby/backward/2/assume.h
raddrinfo.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -1544,7 +1410,6 @@ raddrinfo.o: $(hdrdir)/ruby/internal/attr/noexcept.h
raddrinfo.o: $(hdrdir)/ruby/internal/attr/noinline.h
raddrinfo.o: $(hdrdir)/ruby/internal/attr/nonnull.h
raddrinfo.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-raddrinfo.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
raddrinfo.o: $(hdrdir)/ruby/internal/attr/pure.h
raddrinfo.o: $(hdrdir)/ruby/internal/attr/restrict.h
raddrinfo.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1613,6 +1478,7 @@ raddrinfo.o: $(hdrdir)/ruby/internal/intern/enumerator.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/error.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/eval.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/file.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/gc.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/hash.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/io.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1643,12 +1509,12 @@ raddrinfo.o: $(hdrdir)/ruby/internal/memory.h
raddrinfo.o: $(hdrdir)/ruby/internal/method.h
raddrinfo.o: $(hdrdir)/ruby/internal/module.h
raddrinfo.o: $(hdrdir)/ruby/internal/newobj.h
+raddrinfo.o: $(hdrdir)/ruby/internal/rgengc.h
raddrinfo.o: $(hdrdir)/ruby/internal/scan_args.h
raddrinfo.o: $(hdrdir)/ruby/internal/special_consts.h
raddrinfo.o: $(hdrdir)/ruby/internal/static_assert.h
raddrinfo.o: $(hdrdir)/ruby/internal/stdalign.h
raddrinfo.o: $(hdrdir)/ruby/internal/stdbool.h
-raddrinfo.o: $(hdrdir)/ruby/internal/stdckdint.h
raddrinfo.o: $(hdrdir)/ruby/internal/symbol.h
raddrinfo.o: $(hdrdir)/ruby/internal/value.h
raddrinfo.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1663,46 +1529,27 @@ raddrinfo.o: $(hdrdir)/ruby/ruby.h
raddrinfo.o: $(hdrdir)/ruby/st.h
raddrinfo.o: $(hdrdir)/ruby/subst.h
raddrinfo.o: $(hdrdir)/ruby/thread.h
-raddrinfo.o: $(hdrdir)/ruby/thread_native.h
raddrinfo.o: $(hdrdir)/ruby/util.h
-raddrinfo.o: $(hdrdir)/ruby/version.h
-raddrinfo.o: $(top_srcdir)/ccan/check_type/check_type.h
-raddrinfo.o: $(top_srcdir)/ccan/container_of/container_of.h
-raddrinfo.o: $(top_srcdir)/ccan/list/list.h
-raddrinfo.o: $(top_srcdir)/ccan/str/str.h
raddrinfo.o: $(top_srcdir)/internal.h
raddrinfo.o: $(top_srcdir)/internal/array.h
-raddrinfo.o: $(top_srcdir)/internal/basic_operators.h
raddrinfo.o: $(top_srcdir)/internal/compilers.h
raddrinfo.o: $(top_srcdir)/internal/error.h
raddrinfo.o: $(top_srcdir)/internal/gc.h
-raddrinfo.o: $(top_srcdir)/internal/imemo.h
raddrinfo.o: $(top_srcdir)/internal/io.h
-raddrinfo.o: $(top_srcdir)/internal/sanitizers.h
raddrinfo.o: $(top_srcdir)/internal/serial.h
raddrinfo.o: $(top_srcdir)/internal/static_assert.h
raddrinfo.o: $(top_srcdir)/internal/string.h
raddrinfo.o: $(top_srcdir)/internal/thread.h
raddrinfo.o: $(top_srcdir)/internal/vm.h
raddrinfo.o: $(top_srcdir)/internal/warnings.h
-raddrinfo.o: $(top_srcdir)/method.h
-raddrinfo.o: $(top_srcdir)/node.h
-raddrinfo.o: $(top_srcdir)/ruby_assert.h
-raddrinfo.o: $(top_srcdir)/ruby_atomic.h
-raddrinfo.o: $(top_srcdir)/rubyparser.h
raddrinfo.o: $(top_srcdir)/shape.h
-raddrinfo.o: $(top_srcdir)/thread_pthread.h
-raddrinfo.o: $(top_srcdir)/vm_core.h
-raddrinfo.o: $(top_srcdir)/vm_opts.h
raddrinfo.o: constdefs.h
raddrinfo.o: raddrinfo.c
raddrinfo.o: rubysocket.h
raddrinfo.o: sockport.h
-raddrinfo.o: {$(VPATH)}id.h
socket.o: $(RUBY_EXTCONF_H)
socket.o: $(arch_hdrdir)/ruby/config.h
socket.o: $(hdrdir)/ruby/assert.h
-socket.o: $(hdrdir)/ruby/atomic.h
socket.o: $(hdrdir)/ruby/backward.h
socket.o: $(hdrdir)/ruby/backward/2/assume.h
socket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -1755,7 +1602,6 @@ socket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
socket.o: $(hdrdir)/ruby/internal/attr/noinline.h
socket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
socket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-socket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
socket.o: $(hdrdir)/ruby/internal/attr/pure.h
socket.o: $(hdrdir)/ruby/internal/attr/restrict.h
socket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -1824,6 +1670,7 @@ socket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
socket.o: $(hdrdir)/ruby/internal/intern/error.h
socket.o: $(hdrdir)/ruby/internal/intern/eval.h
socket.o: $(hdrdir)/ruby/internal/intern/file.h
+socket.o: $(hdrdir)/ruby/internal/intern/gc.h
socket.o: $(hdrdir)/ruby/internal/intern/hash.h
socket.o: $(hdrdir)/ruby/internal/intern/io.h
socket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -1854,12 +1701,12 @@ socket.o: $(hdrdir)/ruby/internal/memory.h
socket.o: $(hdrdir)/ruby/internal/method.h
socket.o: $(hdrdir)/ruby/internal/module.h
socket.o: $(hdrdir)/ruby/internal/newobj.h
+socket.o: $(hdrdir)/ruby/internal/rgengc.h
socket.o: $(hdrdir)/ruby/internal/scan_args.h
socket.o: $(hdrdir)/ruby/internal/special_consts.h
socket.o: $(hdrdir)/ruby/internal/static_assert.h
socket.o: $(hdrdir)/ruby/internal/stdalign.h
socket.o: $(hdrdir)/ruby/internal/stdbool.h
-socket.o: $(hdrdir)/ruby/internal/stdckdint.h
socket.o: $(hdrdir)/ruby/internal/symbol.h
socket.o: $(hdrdir)/ruby/internal/value.h
socket.o: $(hdrdir)/ruby/internal/value_type.h
@@ -1874,46 +1721,27 @@ socket.o: $(hdrdir)/ruby/ruby.h
socket.o: $(hdrdir)/ruby/st.h
socket.o: $(hdrdir)/ruby/subst.h
socket.o: $(hdrdir)/ruby/thread.h
-socket.o: $(hdrdir)/ruby/thread_native.h
socket.o: $(hdrdir)/ruby/util.h
-socket.o: $(hdrdir)/ruby/version.h
-socket.o: $(top_srcdir)/ccan/check_type/check_type.h
-socket.o: $(top_srcdir)/ccan/container_of/container_of.h
-socket.o: $(top_srcdir)/ccan/list/list.h
-socket.o: $(top_srcdir)/ccan/str/str.h
socket.o: $(top_srcdir)/internal.h
socket.o: $(top_srcdir)/internal/array.h
-socket.o: $(top_srcdir)/internal/basic_operators.h
socket.o: $(top_srcdir)/internal/compilers.h
socket.o: $(top_srcdir)/internal/error.h
socket.o: $(top_srcdir)/internal/gc.h
-socket.o: $(top_srcdir)/internal/imemo.h
socket.o: $(top_srcdir)/internal/io.h
-socket.o: $(top_srcdir)/internal/sanitizers.h
socket.o: $(top_srcdir)/internal/serial.h
socket.o: $(top_srcdir)/internal/static_assert.h
socket.o: $(top_srcdir)/internal/string.h
socket.o: $(top_srcdir)/internal/thread.h
socket.o: $(top_srcdir)/internal/vm.h
socket.o: $(top_srcdir)/internal/warnings.h
-socket.o: $(top_srcdir)/method.h
-socket.o: $(top_srcdir)/node.h
-socket.o: $(top_srcdir)/ruby_assert.h
-socket.o: $(top_srcdir)/ruby_atomic.h
-socket.o: $(top_srcdir)/rubyparser.h
socket.o: $(top_srcdir)/shape.h
-socket.o: $(top_srcdir)/thread_pthread.h
-socket.o: $(top_srcdir)/vm_core.h
-socket.o: $(top_srcdir)/vm_opts.h
socket.o: constdefs.h
socket.o: rubysocket.h
socket.o: socket.c
socket.o: sockport.h
-socket.o: {$(VPATH)}id.h
sockssocket.o: $(RUBY_EXTCONF_H)
sockssocket.o: $(arch_hdrdir)/ruby/config.h
sockssocket.o: $(hdrdir)/ruby/assert.h
-sockssocket.o: $(hdrdir)/ruby/atomic.h
sockssocket.o: $(hdrdir)/ruby/backward.h
sockssocket.o: $(hdrdir)/ruby/backward/2/assume.h
sockssocket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -1966,7 +1794,6 @@ sockssocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
sockssocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
sockssocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
sockssocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-sockssocket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
sockssocket.o: $(hdrdir)/ruby/internal/attr/pure.h
sockssocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
sockssocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2035,6 +1862,7 @@ sockssocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/error.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/eval.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/file.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/gc.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/hash.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/io.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2065,12 +1893,12 @@ sockssocket.o: $(hdrdir)/ruby/internal/memory.h
sockssocket.o: $(hdrdir)/ruby/internal/method.h
sockssocket.o: $(hdrdir)/ruby/internal/module.h
sockssocket.o: $(hdrdir)/ruby/internal/newobj.h
+sockssocket.o: $(hdrdir)/ruby/internal/rgengc.h
sockssocket.o: $(hdrdir)/ruby/internal/scan_args.h
sockssocket.o: $(hdrdir)/ruby/internal/special_consts.h
sockssocket.o: $(hdrdir)/ruby/internal/static_assert.h
sockssocket.o: $(hdrdir)/ruby/internal/stdalign.h
sockssocket.o: $(hdrdir)/ruby/internal/stdbool.h
-sockssocket.o: $(hdrdir)/ruby/internal/stdckdint.h
sockssocket.o: $(hdrdir)/ruby/internal/symbol.h
sockssocket.o: $(hdrdir)/ruby/internal/value.h
sockssocket.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2085,46 +1913,27 @@ sockssocket.o: $(hdrdir)/ruby/ruby.h
sockssocket.o: $(hdrdir)/ruby/st.h
sockssocket.o: $(hdrdir)/ruby/subst.h
sockssocket.o: $(hdrdir)/ruby/thread.h
-sockssocket.o: $(hdrdir)/ruby/thread_native.h
sockssocket.o: $(hdrdir)/ruby/util.h
-sockssocket.o: $(hdrdir)/ruby/version.h
-sockssocket.o: $(top_srcdir)/ccan/check_type/check_type.h
-sockssocket.o: $(top_srcdir)/ccan/container_of/container_of.h
-sockssocket.o: $(top_srcdir)/ccan/list/list.h
-sockssocket.o: $(top_srcdir)/ccan/str/str.h
sockssocket.o: $(top_srcdir)/internal.h
sockssocket.o: $(top_srcdir)/internal/array.h
-sockssocket.o: $(top_srcdir)/internal/basic_operators.h
sockssocket.o: $(top_srcdir)/internal/compilers.h
sockssocket.o: $(top_srcdir)/internal/error.h
sockssocket.o: $(top_srcdir)/internal/gc.h
-sockssocket.o: $(top_srcdir)/internal/imemo.h
sockssocket.o: $(top_srcdir)/internal/io.h
-sockssocket.o: $(top_srcdir)/internal/sanitizers.h
sockssocket.o: $(top_srcdir)/internal/serial.h
sockssocket.o: $(top_srcdir)/internal/static_assert.h
sockssocket.o: $(top_srcdir)/internal/string.h
sockssocket.o: $(top_srcdir)/internal/thread.h
sockssocket.o: $(top_srcdir)/internal/vm.h
sockssocket.o: $(top_srcdir)/internal/warnings.h
-sockssocket.o: $(top_srcdir)/method.h
-sockssocket.o: $(top_srcdir)/node.h
-sockssocket.o: $(top_srcdir)/ruby_assert.h
-sockssocket.o: $(top_srcdir)/ruby_atomic.h
-sockssocket.o: $(top_srcdir)/rubyparser.h
sockssocket.o: $(top_srcdir)/shape.h
-sockssocket.o: $(top_srcdir)/thread_pthread.h
-sockssocket.o: $(top_srcdir)/vm_core.h
-sockssocket.o: $(top_srcdir)/vm_opts.h
sockssocket.o: constdefs.h
sockssocket.o: rubysocket.h
sockssocket.o: sockport.h
sockssocket.o: sockssocket.c
-sockssocket.o: {$(VPATH)}id.h
tcpserver.o: $(RUBY_EXTCONF_H)
tcpserver.o: $(arch_hdrdir)/ruby/config.h
tcpserver.o: $(hdrdir)/ruby/assert.h
-tcpserver.o: $(hdrdir)/ruby/atomic.h
tcpserver.o: $(hdrdir)/ruby/backward.h
tcpserver.o: $(hdrdir)/ruby/backward/2/assume.h
tcpserver.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -2177,7 +1986,6 @@ tcpserver.o: $(hdrdir)/ruby/internal/attr/noexcept.h
tcpserver.o: $(hdrdir)/ruby/internal/attr/noinline.h
tcpserver.o: $(hdrdir)/ruby/internal/attr/nonnull.h
tcpserver.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-tcpserver.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
tcpserver.o: $(hdrdir)/ruby/internal/attr/pure.h
tcpserver.o: $(hdrdir)/ruby/internal/attr/restrict.h
tcpserver.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2246,6 +2054,7 @@ tcpserver.o: $(hdrdir)/ruby/internal/intern/enumerator.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/error.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/eval.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/file.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/gc.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/hash.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/io.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2276,12 +2085,12 @@ tcpserver.o: $(hdrdir)/ruby/internal/memory.h
tcpserver.o: $(hdrdir)/ruby/internal/method.h
tcpserver.o: $(hdrdir)/ruby/internal/module.h
tcpserver.o: $(hdrdir)/ruby/internal/newobj.h
+tcpserver.o: $(hdrdir)/ruby/internal/rgengc.h
tcpserver.o: $(hdrdir)/ruby/internal/scan_args.h
tcpserver.o: $(hdrdir)/ruby/internal/special_consts.h
tcpserver.o: $(hdrdir)/ruby/internal/static_assert.h
tcpserver.o: $(hdrdir)/ruby/internal/stdalign.h
tcpserver.o: $(hdrdir)/ruby/internal/stdbool.h
-tcpserver.o: $(hdrdir)/ruby/internal/stdckdint.h
tcpserver.o: $(hdrdir)/ruby/internal/symbol.h
tcpserver.o: $(hdrdir)/ruby/internal/value.h
tcpserver.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2296,46 +2105,27 @@ tcpserver.o: $(hdrdir)/ruby/ruby.h
tcpserver.o: $(hdrdir)/ruby/st.h
tcpserver.o: $(hdrdir)/ruby/subst.h
tcpserver.o: $(hdrdir)/ruby/thread.h
-tcpserver.o: $(hdrdir)/ruby/thread_native.h
tcpserver.o: $(hdrdir)/ruby/util.h
-tcpserver.o: $(hdrdir)/ruby/version.h
-tcpserver.o: $(top_srcdir)/ccan/check_type/check_type.h
-tcpserver.o: $(top_srcdir)/ccan/container_of/container_of.h
-tcpserver.o: $(top_srcdir)/ccan/list/list.h
-tcpserver.o: $(top_srcdir)/ccan/str/str.h
tcpserver.o: $(top_srcdir)/internal.h
tcpserver.o: $(top_srcdir)/internal/array.h
-tcpserver.o: $(top_srcdir)/internal/basic_operators.h
tcpserver.o: $(top_srcdir)/internal/compilers.h
tcpserver.o: $(top_srcdir)/internal/error.h
tcpserver.o: $(top_srcdir)/internal/gc.h
-tcpserver.o: $(top_srcdir)/internal/imemo.h
tcpserver.o: $(top_srcdir)/internal/io.h
-tcpserver.o: $(top_srcdir)/internal/sanitizers.h
tcpserver.o: $(top_srcdir)/internal/serial.h
tcpserver.o: $(top_srcdir)/internal/static_assert.h
tcpserver.o: $(top_srcdir)/internal/string.h
tcpserver.o: $(top_srcdir)/internal/thread.h
tcpserver.o: $(top_srcdir)/internal/vm.h
tcpserver.o: $(top_srcdir)/internal/warnings.h
-tcpserver.o: $(top_srcdir)/method.h
-tcpserver.o: $(top_srcdir)/node.h
-tcpserver.o: $(top_srcdir)/ruby_assert.h
-tcpserver.o: $(top_srcdir)/ruby_atomic.h
-tcpserver.o: $(top_srcdir)/rubyparser.h
tcpserver.o: $(top_srcdir)/shape.h
-tcpserver.o: $(top_srcdir)/thread_pthread.h
-tcpserver.o: $(top_srcdir)/vm_core.h
-tcpserver.o: $(top_srcdir)/vm_opts.h
tcpserver.o: constdefs.h
tcpserver.o: rubysocket.h
tcpserver.o: sockport.h
tcpserver.o: tcpserver.c
-tcpserver.o: {$(VPATH)}id.h
tcpsocket.o: $(RUBY_EXTCONF_H)
tcpsocket.o: $(arch_hdrdir)/ruby/config.h
tcpsocket.o: $(hdrdir)/ruby/assert.h
-tcpsocket.o: $(hdrdir)/ruby/atomic.h
tcpsocket.o: $(hdrdir)/ruby/backward.h
tcpsocket.o: $(hdrdir)/ruby/backward/2/assume.h
tcpsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -2388,7 +2178,6 @@ tcpsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
tcpsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
tcpsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
tcpsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-tcpsocket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
tcpsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
tcpsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
tcpsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2457,6 +2246,7 @@ tcpsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/error.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/io.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2487,12 +2277,12 @@ tcpsocket.o: $(hdrdir)/ruby/internal/memory.h
tcpsocket.o: $(hdrdir)/ruby/internal/method.h
tcpsocket.o: $(hdrdir)/ruby/internal/module.h
tcpsocket.o: $(hdrdir)/ruby/internal/newobj.h
+tcpsocket.o: $(hdrdir)/ruby/internal/rgengc.h
tcpsocket.o: $(hdrdir)/ruby/internal/scan_args.h
tcpsocket.o: $(hdrdir)/ruby/internal/special_consts.h
tcpsocket.o: $(hdrdir)/ruby/internal/static_assert.h
tcpsocket.o: $(hdrdir)/ruby/internal/stdalign.h
tcpsocket.o: $(hdrdir)/ruby/internal/stdbool.h
-tcpsocket.o: $(hdrdir)/ruby/internal/stdckdint.h
tcpsocket.o: $(hdrdir)/ruby/internal/symbol.h
tcpsocket.o: $(hdrdir)/ruby/internal/value.h
tcpsocket.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2507,46 +2297,27 @@ tcpsocket.o: $(hdrdir)/ruby/ruby.h
tcpsocket.o: $(hdrdir)/ruby/st.h
tcpsocket.o: $(hdrdir)/ruby/subst.h
tcpsocket.o: $(hdrdir)/ruby/thread.h
-tcpsocket.o: $(hdrdir)/ruby/thread_native.h
tcpsocket.o: $(hdrdir)/ruby/util.h
-tcpsocket.o: $(hdrdir)/ruby/version.h
-tcpsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
-tcpsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
-tcpsocket.o: $(top_srcdir)/ccan/list/list.h
-tcpsocket.o: $(top_srcdir)/ccan/str/str.h
tcpsocket.o: $(top_srcdir)/internal.h
tcpsocket.o: $(top_srcdir)/internal/array.h
-tcpsocket.o: $(top_srcdir)/internal/basic_operators.h
tcpsocket.o: $(top_srcdir)/internal/compilers.h
tcpsocket.o: $(top_srcdir)/internal/error.h
tcpsocket.o: $(top_srcdir)/internal/gc.h
-tcpsocket.o: $(top_srcdir)/internal/imemo.h
tcpsocket.o: $(top_srcdir)/internal/io.h
-tcpsocket.o: $(top_srcdir)/internal/sanitizers.h
tcpsocket.o: $(top_srcdir)/internal/serial.h
tcpsocket.o: $(top_srcdir)/internal/static_assert.h
tcpsocket.o: $(top_srcdir)/internal/string.h
tcpsocket.o: $(top_srcdir)/internal/thread.h
tcpsocket.o: $(top_srcdir)/internal/vm.h
tcpsocket.o: $(top_srcdir)/internal/warnings.h
-tcpsocket.o: $(top_srcdir)/method.h
-tcpsocket.o: $(top_srcdir)/node.h
-tcpsocket.o: $(top_srcdir)/ruby_assert.h
-tcpsocket.o: $(top_srcdir)/ruby_atomic.h
-tcpsocket.o: $(top_srcdir)/rubyparser.h
tcpsocket.o: $(top_srcdir)/shape.h
-tcpsocket.o: $(top_srcdir)/thread_pthread.h
-tcpsocket.o: $(top_srcdir)/vm_core.h
-tcpsocket.o: $(top_srcdir)/vm_opts.h
tcpsocket.o: constdefs.h
tcpsocket.o: rubysocket.h
tcpsocket.o: sockport.h
tcpsocket.o: tcpsocket.c
-tcpsocket.o: {$(VPATH)}id.h
udpsocket.o: $(RUBY_EXTCONF_H)
udpsocket.o: $(arch_hdrdir)/ruby/config.h
udpsocket.o: $(hdrdir)/ruby/assert.h
-udpsocket.o: $(hdrdir)/ruby/atomic.h
udpsocket.o: $(hdrdir)/ruby/backward.h
udpsocket.o: $(hdrdir)/ruby/backward/2/assume.h
udpsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -2599,7 +2370,6 @@ udpsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
udpsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
udpsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
udpsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-udpsocket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
udpsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
udpsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
udpsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2668,6 +2438,7 @@ udpsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/error.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/io.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2698,12 +2469,12 @@ udpsocket.o: $(hdrdir)/ruby/internal/memory.h
udpsocket.o: $(hdrdir)/ruby/internal/method.h
udpsocket.o: $(hdrdir)/ruby/internal/module.h
udpsocket.o: $(hdrdir)/ruby/internal/newobj.h
+udpsocket.o: $(hdrdir)/ruby/internal/rgengc.h
udpsocket.o: $(hdrdir)/ruby/internal/scan_args.h
udpsocket.o: $(hdrdir)/ruby/internal/special_consts.h
udpsocket.o: $(hdrdir)/ruby/internal/static_assert.h
udpsocket.o: $(hdrdir)/ruby/internal/stdalign.h
udpsocket.o: $(hdrdir)/ruby/internal/stdbool.h
-udpsocket.o: $(hdrdir)/ruby/internal/stdckdint.h
udpsocket.o: $(hdrdir)/ruby/internal/symbol.h
udpsocket.o: $(hdrdir)/ruby/internal/value.h
udpsocket.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2718,46 +2489,27 @@ udpsocket.o: $(hdrdir)/ruby/ruby.h
udpsocket.o: $(hdrdir)/ruby/st.h
udpsocket.o: $(hdrdir)/ruby/subst.h
udpsocket.o: $(hdrdir)/ruby/thread.h
-udpsocket.o: $(hdrdir)/ruby/thread_native.h
udpsocket.o: $(hdrdir)/ruby/util.h
-udpsocket.o: $(hdrdir)/ruby/version.h
-udpsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
-udpsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
-udpsocket.o: $(top_srcdir)/ccan/list/list.h
-udpsocket.o: $(top_srcdir)/ccan/str/str.h
udpsocket.o: $(top_srcdir)/internal.h
udpsocket.o: $(top_srcdir)/internal/array.h
-udpsocket.o: $(top_srcdir)/internal/basic_operators.h
udpsocket.o: $(top_srcdir)/internal/compilers.h
udpsocket.o: $(top_srcdir)/internal/error.h
udpsocket.o: $(top_srcdir)/internal/gc.h
-udpsocket.o: $(top_srcdir)/internal/imemo.h
udpsocket.o: $(top_srcdir)/internal/io.h
-udpsocket.o: $(top_srcdir)/internal/sanitizers.h
udpsocket.o: $(top_srcdir)/internal/serial.h
udpsocket.o: $(top_srcdir)/internal/static_assert.h
udpsocket.o: $(top_srcdir)/internal/string.h
udpsocket.o: $(top_srcdir)/internal/thread.h
udpsocket.o: $(top_srcdir)/internal/vm.h
udpsocket.o: $(top_srcdir)/internal/warnings.h
-udpsocket.o: $(top_srcdir)/method.h
-udpsocket.o: $(top_srcdir)/node.h
-udpsocket.o: $(top_srcdir)/ruby_assert.h
-udpsocket.o: $(top_srcdir)/ruby_atomic.h
-udpsocket.o: $(top_srcdir)/rubyparser.h
udpsocket.o: $(top_srcdir)/shape.h
-udpsocket.o: $(top_srcdir)/thread_pthread.h
-udpsocket.o: $(top_srcdir)/vm_core.h
-udpsocket.o: $(top_srcdir)/vm_opts.h
udpsocket.o: constdefs.h
udpsocket.o: rubysocket.h
udpsocket.o: sockport.h
udpsocket.o: udpsocket.c
-udpsocket.o: {$(VPATH)}id.h
unixserver.o: $(RUBY_EXTCONF_H)
unixserver.o: $(arch_hdrdir)/ruby/config.h
unixserver.o: $(hdrdir)/ruby/assert.h
-unixserver.o: $(hdrdir)/ruby/atomic.h
unixserver.o: $(hdrdir)/ruby/backward.h
unixserver.o: $(hdrdir)/ruby/backward/2/assume.h
unixserver.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -2810,7 +2562,6 @@ unixserver.o: $(hdrdir)/ruby/internal/attr/noexcept.h
unixserver.o: $(hdrdir)/ruby/internal/attr/noinline.h
unixserver.o: $(hdrdir)/ruby/internal/attr/nonnull.h
unixserver.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-unixserver.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
unixserver.o: $(hdrdir)/ruby/internal/attr/pure.h
unixserver.o: $(hdrdir)/ruby/internal/attr/restrict.h
unixserver.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -2879,6 +2630,7 @@ unixserver.o: $(hdrdir)/ruby/internal/intern/enumerator.h
unixserver.o: $(hdrdir)/ruby/internal/intern/error.h
unixserver.o: $(hdrdir)/ruby/internal/intern/eval.h
unixserver.o: $(hdrdir)/ruby/internal/intern/file.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/gc.h
unixserver.o: $(hdrdir)/ruby/internal/intern/hash.h
unixserver.o: $(hdrdir)/ruby/internal/intern/io.h
unixserver.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -2909,12 +2661,12 @@ unixserver.o: $(hdrdir)/ruby/internal/memory.h
unixserver.o: $(hdrdir)/ruby/internal/method.h
unixserver.o: $(hdrdir)/ruby/internal/module.h
unixserver.o: $(hdrdir)/ruby/internal/newobj.h
+unixserver.o: $(hdrdir)/ruby/internal/rgengc.h
unixserver.o: $(hdrdir)/ruby/internal/scan_args.h
unixserver.o: $(hdrdir)/ruby/internal/special_consts.h
unixserver.o: $(hdrdir)/ruby/internal/static_assert.h
unixserver.o: $(hdrdir)/ruby/internal/stdalign.h
unixserver.o: $(hdrdir)/ruby/internal/stdbool.h
-unixserver.o: $(hdrdir)/ruby/internal/stdckdint.h
unixserver.o: $(hdrdir)/ruby/internal/symbol.h
unixserver.o: $(hdrdir)/ruby/internal/value.h
unixserver.o: $(hdrdir)/ruby/internal/value_type.h
@@ -2929,46 +2681,27 @@ unixserver.o: $(hdrdir)/ruby/ruby.h
unixserver.o: $(hdrdir)/ruby/st.h
unixserver.o: $(hdrdir)/ruby/subst.h
unixserver.o: $(hdrdir)/ruby/thread.h
-unixserver.o: $(hdrdir)/ruby/thread_native.h
unixserver.o: $(hdrdir)/ruby/util.h
-unixserver.o: $(hdrdir)/ruby/version.h
-unixserver.o: $(top_srcdir)/ccan/check_type/check_type.h
-unixserver.o: $(top_srcdir)/ccan/container_of/container_of.h
-unixserver.o: $(top_srcdir)/ccan/list/list.h
-unixserver.o: $(top_srcdir)/ccan/str/str.h
unixserver.o: $(top_srcdir)/internal.h
unixserver.o: $(top_srcdir)/internal/array.h
-unixserver.o: $(top_srcdir)/internal/basic_operators.h
unixserver.o: $(top_srcdir)/internal/compilers.h
unixserver.o: $(top_srcdir)/internal/error.h
unixserver.o: $(top_srcdir)/internal/gc.h
-unixserver.o: $(top_srcdir)/internal/imemo.h
unixserver.o: $(top_srcdir)/internal/io.h
-unixserver.o: $(top_srcdir)/internal/sanitizers.h
unixserver.o: $(top_srcdir)/internal/serial.h
unixserver.o: $(top_srcdir)/internal/static_assert.h
unixserver.o: $(top_srcdir)/internal/string.h
unixserver.o: $(top_srcdir)/internal/thread.h
unixserver.o: $(top_srcdir)/internal/vm.h
unixserver.o: $(top_srcdir)/internal/warnings.h
-unixserver.o: $(top_srcdir)/method.h
-unixserver.o: $(top_srcdir)/node.h
-unixserver.o: $(top_srcdir)/ruby_assert.h
-unixserver.o: $(top_srcdir)/ruby_atomic.h
-unixserver.o: $(top_srcdir)/rubyparser.h
unixserver.o: $(top_srcdir)/shape.h
-unixserver.o: $(top_srcdir)/thread_pthread.h
-unixserver.o: $(top_srcdir)/vm_core.h
-unixserver.o: $(top_srcdir)/vm_opts.h
unixserver.o: constdefs.h
unixserver.o: rubysocket.h
unixserver.o: sockport.h
unixserver.o: unixserver.c
-unixserver.o: {$(VPATH)}id.h
unixsocket.o: $(RUBY_EXTCONF_H)
unixsocket.o: $(arch_hdrdir)/ruby/config.h
unixsocket.o: $(hdrdir)/ruby/assert.h
-unixsocket.o: $(hdrdir)/ruby/atomic.h
unixsocket.o: $(hdrdir)/ruby/backward.h
unixsocket.o: $(hdrdir)/ruby/backward/2/assume.h
unixsocket.o: $(hdrdir)/ruby/backward/2/attributes.h
@@ -3021,7 +2754,6 @@ unixsocket.o: $(hdrdir)/ruby/internal/attr/noexcept.h
unixsocket.o: $(hdrdir)/ruby/internal/attr/noinline.h
unixsocket.o: $(hdrdir)/ruby/internal/attr/nonnull.h
unixsocket.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-unixsocket.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
unixsocket.o: $(hdrdir)/ruby/internal/attr/pure.h
unixsocket.o: $(hdrdir)/ruby/internal/attr/restrict.h
unixsocket.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -3090,6 +2822,7 @@ unixsocket.o: $(hdrdir)/ruby/internal/intern/enumerator.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/error.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/eval.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/file.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/gc.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/hash.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/io.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -3120,12 +2853,12 @@ unixsocket.o: $(hdrdir)/ruby/internal/memory.h
unixsocket.o: $(hdrdir)/ruby/internal/method.h
unixsocket.o: $(hdrdir)/ruby/internal/module.h
unixsocket.o: $(hdrdir)/ruby/internal/newobj.h
+unixsocket.o: $(hdrdir)/ruby/internal/rgengc.h
unixsocket.o: $(hdrdir)/ruby/internal/scan_args.h
unixsocket.o: $(hdrdir)/ruby/internal/special_consts.h
unixsocket.o: $(hdrdir)/ruby/internal/static_assert.h
unixsocket.o: $(hdrdir)/ruby/internal/stdalign.h
unixsocket.o: $(hdrdir)/ruby/internal/stdbool.h
-unixsocket.o: $(hdrdir)/ruby/internal/stdckdint.h
unixsocket.o: $(hdrdir)/ruby/internal/symbol.h
unixsocket.o: $(hdrdir)/ruby/internal/value.h
unixsocket.o: $(hdrdir)/ruby/internal/value_type.h
@@ -3140,40 +2873,22 @@ unixsocket.o: $(hdrdir)/ruby/ruby.h
unixsocket.o: $(hdrdir)/ruby/st.h
unixsocket.o: $(hdrdir)/ruby/subst.h
unixsocket.o: $(hdrdir)/ruby/thread.h
-unixsocket.o: $(hdrdir)/ruby/thread_native.h
unixsocket.o: $(hdrdir)/ruby/util.h
-unixsocket.o: $(hdrdir)/ruby/version.h
-unixsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
-unixsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
-unixsocket.o: $(top_srcdir)/ccan/list/list.h
-unixsocket.o: $(top_srcdir)/ccan/str/str.h
unixsocket.o: $(top_srcdir)/internal.h
unixsocket.o: $(top_srcdir)/internal/array.h
-unixsocket.o: $(top_srcdir)/internal/basic_operators.h
unixsocket.o: $(top_srcdir)/internal/compilers.h
unixsocket.o: $(top_srcdir)/internal/error.h
unixsocket.o: $(top_srcdir)/internal/gc.h
-unixsocket.o: $(top_srcdir)/internal/imemo.h
unixsocket.o: $(top_srcdir)/internal/io.h
-unixsocket.o: $(top_srcdir)/internal/sanitizers.h
unixsocket.o: $(top_srcdir)/internal/serial.h
unixsocket.o: $(top_srcdir)/internal/static_assert.h
unixsocket.o: $(top_srcdir)/internal/string.h
unixsocket.o: $(top_srcdir)/internal/thread.h
unixsocket.o: $(top_srcdir)/internal/vm.h
unixsocket.o: $(top_srcdir)/internal/warnings.h
-unixsocket.o: $(top_srcdir)/method.h
-unixsocket.o: $(top_srcdir)/node.h
-unixsocket.o: $(top_srcdir)/ruby_assert.h
-unixsocket.o: $(top_srcdir)/ruby_atomic.h
-unixsocket.o: $(top_srcdir)/rubyparser.h
unixsocket.o: $(top_srcdir)/shape.h
-unixsocket.o: $(top_srcdir)/thread_pthread.h
-unixsocket.o: $(top_srcdir)/vm_core.h
-unixsocket.o: $(top_srcdir)/vm_opts.h
unixsocket.o: constdefs.h
unixsocket.o: rubysocket.h
unixsocket.o: sockport.h
unixsocket.o: unixsocket.c
-unixsocket.o: {$(VPATH)}id.h
# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index d44ce31b0a..37ff216560 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -327,8 +327,6 @@ end
net/if_dl.h
arpa/nameser.h
resolv.h
- pthread.h
- sched.h
].each {|h|
if have_header(h, headers)
headers << h
@@ -349,22 +347,10 @@ have_type("struct sockaddr_storage", headers)
have_type("struct addrinfo", headers)
-def check_socklen(headers)
- def (fmt = "none").%(x)
- x || self
- end
- s = checking_for("RSTRING_SOCKLEN", fmt) do
- if try_static_assert("sizeof(socklen_t) >= sizeof(long)", headers)
- "RSTRING_LEN"
- else
- "RSTRING_LENINT"
- end
- end
- $defs << "-DRSTRING_SOCKLEN=(socklen_t)"+s
-end
-
if have_type("socklen_t", headers)
- check_socklen(headers)
+ if try_static_assert("sizeof(socklen_t) >= sizeof(long)", headers)
+ $defs << "-DRSTRING_SOCKLEN=(socklen_t)RSTRING_LEN"
+ end
end
have_type("struct in_pktinfo", headers) {|src|
@@ -701,10 +687,5 @@ SRC
"not needed"
end
end
-
- have_func("pthread_create")
- have_func("pthread_detach")
-
- $VPATH << '$(topdir)' << '$(top_srcdir)'
create_makefile("socket")
end
diff --git a/ext/socket/getaddrinfo.c b/ext/socket/getaddrinfo.c
index bf0d90129f..95a2feb3be 100644
--- a/ext/socket/getaddrinfo.c
+++ b/ext/socket/getaddrinfo.c
@@ -219,7 +219,8 @@ freeaddrinfo(struct addrinfo *ai)
do {
next = ai->ai_next;
- free(ai->ai_canonname);
+ if (ai->ai_canonname)
+ free(ai->ai_canonname);
/* no need to free(ai->ai_addr) */
free(ai);
} while ((ai = next) != NULL);
diff --git a/ext/socket/init.c b/ext/socket/init.c
index 0e312b540e..557d4374a5 100644
--- a/ext/socket/init.c
+++ b/ext/socket/init.c
@@ -27,7 +27,6 @@ VALUE rb_cSocket;
VALUE rb_cAddrinfo;
VALUE rb_eSocket;
-VALUE rb_eResolution;
#ifdef SOCKS
VALUE rb_cSOCKSSocket;
@@ -35,10 +34,9 @@ VALUE rb_cSOCKSSocket;
int rsock_do_not_reverse_lookup = 1;
static VALUE sym_wait_readable;
-static ID id_error_code;
void
-rsock_raise_resolution_error(const char *reason, int error)
+rsock_raise_socket_error(const char *reason, int error)
{
#ifdef EAI_SYSTEM
int e;
@@ -50,14 +48,10 @@ rsock_raise_resolution_error(const char *reason, int error)
VALUE msg = rb_sprintf("%s: ", reason);
if (!enc) enc = rb_default_internal_encoding();
rb_str_concat(msg, rb_w32_conv_from_wchar(gai_strerrorW(error), enc));
+ rb_exc_raise(rb_exc_new_str(rb_eSocket, msg));
#else
- VALUE msg = rb_sprintf("%s: %s", reason, gai_strerror(error));
+ rb_raise(rb_eSocket, "%s: %s", reason, gai_strerror(error));
#endif
-
- StringValue(msg);
- VALUE self = rb_class_new_instance(1, &msg, rb_eResolution);
- rb_ivar_set(self, id_error_code, INT2NUM(error));
- rb_exc_raise(self);
}
#if defined __APPLE__
@@ -122,7 +116,6 @@ recvfrom_blocking(void *data)
ssize_t ret;
ret = recvfrom(arg->fd, RSTRING_PTR(arg->str), arg->length,
arg->flags, &arg->buf.addr, &arg->alen);
-
if (ret != -1 && len0 < arg->alen)
arg->alen = len0;
@@ -154,18 +147,6 @@ recvfrom_locktmp(VALUE v)
return rb_thread_io_blocking_region(recvfrom_blocking, arg, arg->fd);
}
-int
-rsock_is_dgram(rb_io_t *fptr)
-{
- int socktype;
- socklen_t optlen = (socklen_t)sizeof(socktype);
- int ret = getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen);
- if (ret == -1) {
- rb_sys_fail("getsockopt(SO_TYPE)");
- }
- return socktype == SOCK_DGRAM;
-}
-
VALUE
rsock_s_recvfrom(VALUE socket, int argc, VALUE *argv, enum sock_recv_type from)
{
@@ -204,12 +185,8 @@ rsock_s_recvfrom(VALUE socket, int argc, VALUE *argv, enum sock_recv_type from)
rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
#endif
- rb_str_locktmp(str);
- slen = (long)rb_ensure(recvfrom_locktmp, (VALUE)&arg, rb_str_unlocktmp, str);
+ slen = (long)rb_str_locktmp_ensure(str, recvfrom_locktmp, (VALUE)&arg);
- if (slen == 0 && !rsock_is_dgram(fptr)) {
- return Qnil;
- }
if (slen >= 0) break;
if (!rb_io_maybe_wait_readable(errno, socket, RUBY_IO_TIMEOUT_DEFAULT))
@@ -282,10 +259,6 @@ rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
if (slen != -1 && len0 < alen)
alen = len0;
- if (slen == 0 && !rsock_is_dgram(fptr)) {
- return Qnil;
- }
-
if (slen < 0) {
int e = errno;
switch (e) {
@@ -419,7 +392,7 @@ rsock_write_nonblock(VALUE sock, VALUE str, VALUE ex)
if (e == EWOULDBLOCK || e == EAGAIN) {
if (ex == Qfalse) return sym_wait_writable;
rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e,
- "write would block");
+ "write would block");
}
rb_syserr_fail_path(e, fptr->pathv);
}
@@ -460,9 +433,9 @@ rsock_socket(int domain, int type, int proto)
fd = rsock_socket0(domain, type, proto);
if (fd < 0) {
- if (rb_gc_for_fd(errno)) {
- fd = rsock_socket0(domain, type, proto);
- }
+ if (rb_gc_for_fd(errno)) {
+ fd = rsock_socket0(domain, type, proto);
+ }
}
if (0 <= fd)
rb_update_max_fd(fd);
@@ -519,10 +492,10 @@ wait_connectable(int fd, struct timeval *timeout)
switch (sockerr) {
case 0:
- /*
- * be defensive in case some platforms set SO_ERROR on the original,
- * interrupted connect()
- */
+ /*
+ * be defensive in case some platforms set SO_ERROR on the original,
+ * interrupted connect()
+ */
/* when the connection timed out, no errno is set and revents is 0. */
if (timeout && revents == 0) {
@@ -708,9 +681,9 @@ rsock_s_accept(VALUE klass, VALUE io, struct sockaddr *sockaddr, socklen_t *len)
RB_IO_POINTER(io, fptr);
struct accept_arg accept_arg = {
- .fd = fptr->fd,
- .sockaddr = sockaddr,
- .len = len
+ .fd = fptr->fd,
+ .sockaddr = sockaddr,
+ .len = len
};
int retry = 0, peer;
@@ -757,10 +730,10 @@ rsock_getfamily(rb_io_t *fptr)
if (cached) {
switch (cached) {
#ifdef AF_UNIX
- case FMODE_UNIX: return AF_UNIX;
+ case FMODE_UNIX: return AF_UNIX;
#endif
- case FMODE_INET: return AF_INET;
- case FMODE_INET6: return AF_INET6;
+ case FMODE_INET: return AF_INET;
+ case FMODE_INET6: return AF_INET6;
}
}
@@ -779,18 +752,6 @@ rsock_getfamily(rb_io_t *fptr)
return ss.addr.sa_family;
}
-/*
- * call-seq:
- * error_code -> integer
- *
- * Returns the raw error code occurred at name resolution.
- */
-static VALUE
-sock_resolv_error_code(VALUE self)
-{
- return rb_attr_get(self, id_error_code);
-}
-
void
rsock_init_socket_init(void)
{
@@ -798,11 +759,6 @@ rsock_init_socket_init(void)
* SocketError is the error class for socket.
*/
rb_eSocket = rb_define_class("SocketError", rb_eStandardError);
- /*
- * ResolutionError is the error class for socket name resolution.
- */
- rb_eResolution = rb_define_class_under(rb_cSocket, "ResolutionError", rb_eSocket);
- rb_define_method(rb_eResolution, "error_code", sock_resolv_error_code, 0);
rsock_init_ipsocket();
rsock_init_tcpsocket();
rsock_init_tcpserver();
@@ -816,8 +772,6 @@ rsock_init_socket_init(void)
rsock_init_sockifaddr();
rsock_init_socket_constants();
- id_error_code = rb_intern_const("error_code");
-
#undef rb_intern
sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb
index d61de1e8e9..eecdc7d4b8 100644
--- a/ext/socket/lib/socket.rb
+++ b/ext/socket/lib/socket.rb
@@ -333,10 +333,9 @@ class BasicSocket < IO
# _flags_ is zero or more of the +MSG_+ options.
# The result, _mesg_, is the data received.
#
- # When recvfrom(2) returns 0, Socket#recv_nonblock returns nil.
- # In most cases it means the connection was closed, but for UDP connections
- # it may mean an empty packet was received, as the underlying API makes
- # it impossible to distinguish these two cases.
+ # When recvfrom(2) returns 0, Socket#recv_nonblock returns
+ # an empty string as data.
+ # The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
#
# === Parameters
# * +maxlen+ - the number of bytes to receive from the socket
@@ -481,10 +480,9 @@ class Socket < BasicSocket
# The second element, _sender_addrinfo_, contains protocol-specific address
# information of the sender.
#
- # When recvfrom(2) returns 0, Socket#recv_nonblock returns nil.
- # In most cases it means the connection was closed, but for UDP connections
- # it may mean an empty packet was received, as the underlying API makes
- # it impossible to distinguish these two cases.
+ # When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
+ # an empty string as data.
+ # The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
#
# === Parameters
# * +maxlen+ - the maximum number of bytes to receive from the socket
@@ -599,30 +597,6 @@ class Socket < BasicSocket
__accept_nonblock(exception)
end
- RESOLUTION_DELAY = 0.05
- private_constant :RESOLUTION_DELAY
-
- CONNECTION_ATTEMPT_DELAY = 0.25
- private_constant :CONNECTION_ATTEMPT_DELAY
-
- ADDRESS_FAMILIES = {
- ipv6: Socket::AF_INET6,
- ipv4: Socket::AF_INET
- }.freeze
- private_constant :ADDRESS_FAMILIES
-
- HOSTNAME_RESOLUTION_QUEUE_UPDATED = 0
- private_constant :HOSTNAME_RESOLUTION_QUEUE_UPDATED
-
- IPV6_ADRESS_FORMAT = /\A(?i:(?:(?:[0-9A-F]{1,4}:){7}(?:[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){6}(?:[0-9A-F]{1,4}|:(?:[0-9A-F]{1,4}:){1,5}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){5}(?:(?::[0-9A-F]{1,4}){1,2}|:(?:[0-9A-F]{1,4}:){1,4}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){4}(?:(?::[0-9A-F]{1,4}){1,3}|:(?:[0-9A-F]{1,4}:){1,3}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){3}(?:(?::[0-9A-F]{1,4}){1,4}|:(?:[0-9A-F]{1,4}:){1,2}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){2}(?:(?::[0-9A-F]{1,4}){1,5}|:(?:[0-9A-F]{1,4}:)[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){1}(?:(?::[0-9A-F]{1,4}){1,6}|:(?:[0-9A-F]{1,4}:){0,5}[0-9A-F]{1,4}|:)|(?:::(?:[0-9A-F]{1,4}:){0,7}[0-9A-F]{1,4}|::)))(?:%.+)?\z/
- private_constant :IPV6_ADRESS_FORMAT
-
- @tcp_fast_fallback = true
-
- class << self
- attr_accessor :tcp_fast_fallback
- end
-
# :call-seq:
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts]) {|socket| ... }
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts])
@@ -648,256 +622,8 @@ class Socket < BasicSocket
# sock.close_write
# puts sock.read
# }
- def self.tcp(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, fast_fallback: tcp_fast_fallback, &) # :yield: socket
- sock = if fast_fallback && !(host && ip_address?(host))
- tcp_with_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:)
- else
- tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:)
- end
-
- if block_given?
- begin
- yield sock
- ensure
- sock.close
- end
- else
- sock
- end
- end
-
- def self.tcp_with_fast_fallback(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil)
- if local_host || local_port
- local_addrinfos = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, timeout: resolv_timeout)
- resolving_family_names = local_addrinfos.map { |lai| ADDRESS_FAMILIES.key(lai.afamily) }.uniq
- else
- local_addrinfos = []
- resolving_family_names = ADDRESS_FAMILIES.keys
- end
-
- hostname_resolution_threads = []
- resolution_store = HostnameResolutionStore.new(resolving_family_names)
- connecting_sockets = {}
- is_windows_environment ||= (RUBY_PLATFORM =~ /mswin|mingw|cygwin/)
-
- now = current_clock_time
- resolution_delay_expires_at = nil
- connection_attempt_delay_expires_at = nil
- user_specified_connect_timeout_at = nil
- last_error = nil
-
- if resolving_family_names.size == 1
- family_name = resolving_family_names.first
- addrinfos = Addrinfo.getaddrinfo(host, port, family_name, :STREAM, timeout: resolv_timeout)
- resolution_store.add_resolved(family_name, addrinfos)
- hostname_resolution_result = nil
- hostname_resolution_notifier = nil
- user_specified_resolv_timeout_at = nil
- else
- hostname_resolution_result = HostnameResolutionResult.new(resolving_family_names.size)
- hostname_resolution_notifier = hostname_resolution_result.notifier
-
- hostname_resolution_threads.concat(
- resolving_family_names.map { |family|
- thread_args = [family, host, port, hostname_resolution_result]
- thread = Thread.new(*thread_args) { |*thread_args| resolve_hostname(*thread_args) }
- Thread.pass
- thread
- }
- )
-
- user_specified_resolv_timeout_at = resolv_timeout ? now + resolv_timeout : Float::INFINITY
- end
-
- loop do
- if resolution_store.any_addrinfos? &&
- !resolution_delay_expires_at &&
- !connection_attempt_delay_expires_at
- while (addrinfo = resolution_store.get_addrinfo)
- if local_addrinfos.any?
- local_addrinfo = local_addrinfos.find { |lai| lai.afamily == addrinfo.afamily }
-
- if local_addrinfo.nil? # Connecting addrinfoã¨åŒã˜ã‚¢ãƒ‰ãƒ¬ã‚¹ãƒ•ァミリã®Local addrinfoãŒãªã„
- if resolution_store.any_addrinfos?
- # Try other Addrinfo in next "while"
- next
- elsif connecting_sockets.any? || resolution_store.any_unresolved_family?
- # Exit this "while" and wait for connections to be established or hostname resolution in next loop
- # Or exit this "while" and wait for hostname resolution in next loop
- break
- else
- raise SocketError.new 'no appropriate local address'
- end
- end
- end
-
- begin
- if resolution_store.any_addrinfos? ||
- connecting_sockets.any? ||
- resolution_store.any_unresolved_family?
- socket = Socket.new(addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol)
- socket.bind(local_addrinfo) if local_addrinfo
- result = socket.connect_nonblock(addrinfo, exception: false)
- else
- result = socket = local_addrinfo ?
- addrinfo.connect_from(local_addrinfo, timeout: connect_timeout) :
- addrinfo.connect(timeout: connect_timeout)
- end
-
- if result == :wait_writable
- connection_attempt_delay_expires_at = now + CONNECTION_ATTEMPT_DELAY
- if resolution_store.empty_addrinfos?
- user_specified_connect_timeout_at = connect_timeout ? now + connect_timeout : Float::INFINITY
- end
-
- connecting_sockets[socket] = addrinfo
- break
- else
- return socket # connection established
- end
- rescue SystemCallError => e
- socket&.close
- last_error = e
-
- if resolution_store.any_addrinfos?
- # Try other Addrinfo in next "while"
- next
- elsif connecting_sockets.any? || resolution_store.any_unresolved_family?
- # Exit this "while" and wait for connections to be established or hostname resolution in next loop
- # Or exit this "while" and wait for hostname resolution in next loop
- break
- else
- raise last_error
- end
- end
- end
- end
-
- ends_at =
- if resolution_store.any_addrinfos?
- resolution_delay_expires_at || connection_attempt_delay_expires_at
- else
- [user_specified_resolv_timeout_at, user_specified_connect_timeout_at].compact.max
- end
-
- hostname_resolved, writable_sockets, except_sockets = IO.select(
- hostname_resolution_notifier,
- connecting_sockets.keys,
- # Use errorfds to wait for non-blocking connect failures on Windows
- is_windows_environment ? connecting_sockets.keys : nil,
- second_to_timeout(current_clock_time, ends_at),
- )
- now = current_clock_time
- resolution_delay_expires_at = nil if expired?(now, resolution_delay_expires_at)
- connection_attempt_delay_expires_at = nil if expired?(now, connection_attempt_delay_expires_at)
-
- if writable_sockets&.any?
- while (writable_socket = writable_sockets.pop)
- is_connected = is_windows_environment || (
- sockopt = writable_socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR)
- sockopt.int.zero?
- )
-
- if is_connected
- connecting_sockets.delete writable_socket
- return writable_socket
- else
- failed_ai = connecting_sockets.delete writable_socket
- writable_socket.close
- ip_address = failed_ai.ipv6? ? "[#{failed_ai.ip_address}]" : failed_ai.ip_address
- last_error = SystemCallError.new("connect(2) for #{ip_address}:#{failed_ai.ip_port}", sockopt.int)
-
- if writable_sockets.any? ||
- resolution_store.any_addrinfos? ||
- connecting_sockets.any? ||
- resolution_store.any_unresolved_family?
- user_specified_connect_timeout_at = nil if connecting_sockets.empty?
- # Try other writable socket in next "while"
- # Or exit this "while" and try other connection attempt
- # Or exit this "while" and wait for connections to be established or hostname resolution in next loop
- # Or exit this "while" and wait for hostname resolution in next loop
- else
- raise last_error
- end
- end
- end
- end
-
- if except_sockets&.any?
- except_sockets.each do |except_socket|
- failed_ai = connecting_sockets.delete except_socket
- sockopt = except_socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_CONNECT_TIME)
- except_socket.close
- ip_address = failed_ai.ipv6? ? "[#{failed_ai.ip_address}]" : failed_ai.ip_address
- last_error = SystemCallError.new("connect(2) for #{ip_address}:#{failed_ai.ip_port}", sockopt.int)
-
- if writable_sockets.any? ||
- resolution_store.any_addrinfos? ||
- connecting_sockets.any? ||
- resolution_store.any_unresolved_family?
- user_specified_connect_timeout_at = nil if connecting_sockets.empty?
- # Try other writable socket in next "while"
- # Or exit this "while" and try other connection attempt
- # Or exit this "while" and wait for connections to be established or hostname resolution in next loop
- # Or exit this "while" and wait for hostname resolution in next loop
- else
- raise last_error
- end
- end
- end
-
- if hostname_resolved&.any?
- while (family_and_result = hostname_resolution_result.get)
- family_name, result = family_and_result
-
- if result.is_a? Exception
- resolution_store.add_error(family_name, result)
-
- unless (Socket.const_defined?(:EAI_ADDRFAMILY)) &&
- (result.is_a?(Socket::ResolutionError)) &&
- (result.error_code == Socket::EAI_ADDRFAMILY)
- last_error = result
- end
- else
- resolution_store.add_resolved(family_name, result)
- end
- end
-
- if resolution_store.resolved?(:ipv4)
- if resolution_store.resolved?(:ipv6)
- hostname_resolution_notifier = nil
- resolution_delay_expires_at = nil
- user_specified_resolv_timeout_at = nil
- elsif resolution_store.resolved_successfully?(:ipv4)
- resolution_delay_expires_at = now + RESOLUTION_DELAY
- end
- end
- end
-
- if resolution_store.empty_addrinfos?
- if connecting_sockets.empty? && resolution_store.resolved_all_families?
- raise last_error
- end
-
- if (expired?(now, user_specified_resolv_timeout_at) || resolution_store.resolved_all_families?) &&
- (expired?(now, user_specified_connect_timeout_at) || connecting_sockets.empty?)
- raise Errno::ETIMEDOUT, 'user specified timeout'
- end
- end
- end
- ensure
- hostname_resolution_threads.each do |thread|
- thread.exit
- end
-
- hostname_resolution_result&.close
-
- connecting_sockets.each_key do |connecting_socket|
- connecting_socket.close
- end
- end
-
- def self.tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:)
+ #
+ def self.tcp(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil) # :yield: socket
last_error = nil
ret = nil
@@ -931,149 +657,16 @@ class Socket < BasicSocket
raise SocketError, "no appropriate local address"
end
end
-
- ret
- end
- private_class_method :tcp_without_fast_fallback
-
- def self.ip_address?(hostname)
- hostname.match?(IPV6_ADRESS_FORMAT) || hostname.match?(/\A([0-9]{1,3}\.){3}[0-9]{1,3}\z/)
- end
- private_class_method :ip_address?
-
- def self.resolve_hostname(family, host, port, hostname_resolution_result)
- begin
- resolved_addrinfos = Addrinfo.getaddrinfo(host, port, ADDRESS_FAMILIES[family], :STREAM)
- hostname_resolution_result.add(family, resolved_addrinfos)
- rescue => e
- hostname_resolution_result.add(family, e)
- end
- end
- private_class_method :resolve_hostname
-
- def self.current_clock_time
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
- end
- private_class_method :current_clock_time
-
- def self.second_to_timeout(started_at, ends_at)
- return nil if ends_at == Float::INFINITY || ends_at.nil?
-
- remaining = (ends_at - started_at)
- remaining.negative? ? 0 : remaining
- end
- private_class_method :second_to_timeout
-
- def self.expired?(started_at, ends_at)
- second_to_timeout(started_at, ends_at)&.zero?
- end
- private_class_method :expired?
-
- class HostnameResolutionResult
- def initialize(size)
- @size = size
- @taken_count = 0
- @rpipe, @wpipe = IO.pipe
- @results = []
- @mutex = Mutex.new
- end
-
- def notifier
- [@rpipe]
- end
-
- def add(family, result)
- @mutex.synchronize do
- @results.push [family, result]
- @wpipe.putc HOSTNAME_RESOLUTION_QUEUE_UPDATED
- end
- end
-
- def get
- return nil if @results.empty?
-
- res = nil
-
- @mutex.synchronize do
- @rpipe.getbyte
- res = @results.shift
- end
-
- @taken_count += 1
- close if @taken_count == @size
- res
- end
-
- def close
- @rpipe.close
- @wpipe.close
- end
- end
- private_constant :HostnameResolutionResult
-
- class HostnameResolutionStore
- PRIORITY_ON_V6 = [:ipv6, :ipv4]
- PRIORITY_ON_V4 = [:ipv4, :ipv6]
-
- def initialize(family_names)
- @family_names = family_names
- @addrinfo_dict = {}
- @error_dict = {}
- @last_family = nil
- end
-
- def add_resolved(family_name, addrinfos)
- @addrinfo_dict[family_name] = addrinfos
- end
-
- def add_error(family_name, error)
- @addrinfo_dict[family_name] = []
- @error_dict[family_name] = error
- end
-
- def get_addrinfo
- precedences =
- case @last_family
- when :ipv4, nil then PRIORITY_ON_V6
- when :ipv6 then PRIORITY_ON_V4
- end
-
- precedences.each do |family_name|
- addrinfo = @addrinfo_dict[family_name]&.shift
- next unless addrinfo
-
- @last_family = family_name
- return addrinfo
+ if block_given?
+ begin
+ yield ret
+ ensure
+ ret.close
end
-
- nil
- end
-
- def empty_addrinfos?
- @addrinfo_dict.all? { |_, addrinfos| addrinfos.empty? }
- end
-
- def any_addrinfos?
- !empty_addrinfos?
- end
-
- def resolved?(family)
- @addrinfo_dict.has_key? family
- end
-
- def resolved_successfully?(family)
- resolved?(family) && !!@error_dict[family]
- end
-
- def resolved_all_families?
- (@family_names - @addrinfo_dict.keys).empty?
- end
-
- def any_unresolved_family?
- !resolved_all_families?
+ else
+ ret
end
end
- private_constant :HostnameResolutionStore
# :stopdoc:
def self.ip_sockets_port0(ai_list, reuseaddr)
@@ -1636,10 +1229,9 @@ class UDPSocket < IPSocket
# The first element of the results, _mesg_, is the data received.
# The second element, _sender_inet_addr_, is an array to represent the sender address.
#
- # When recvfrom(2) returns 0, Socket#recv_nonblock returns nil.
- # In most cases it means the connection was closed, but it may also mean
- # an empty packet was received, as the underlying API makes
- # it impossible to distinguish these two cases.
+ # When recvfrom(2) returns 0,
+ # Socket#recvfrom_nonblock returns an empty string as data.
+ # It means an empty packet.
#
# === Parameters
# * +maxlen+ - the number of bytes to receive from the socket
diff --git a/ext/socket/mkconstants.rb b/ext/socket/mkconstants.rb
index 4271e40cd8..5e6c0668f6 100644
--- a/ext/socket/mkconstants.rb
+++ b/ext/socket/mkconstants.rb
@@ -51,10 +51,7 @@ DATA.each_line {|s|
next
end
h[name] = default_value
- if comment
- # Stop unintentional references
- COMMENTS[name] = comment.gsub(/\b(Data|Kernel|Process|Set|Socket|Time)\b/, '\\\\\\&')
- end
+ COMMENTS[name] = comment
}
DEFS = h.to_a
@@ -76,11 +73,15 @@ def each_name(pat)
}
end
-erb_new = lambda do |src, trim|
- ERB.new(src, trim_mode: trim)
+erb_new = lambda do |src, safe, trim|
+ if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
+ ERB.new(src, trim_mode: trim)
+ else
+ ERB.new(src, safe, trim)
+ end
end
-erb_new.call(<<'EOS', '%').def_method(Object, "gen_const_decls")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_const_decls")
% each_const {|guard, name, default_value|
#if !defined(<%=name%>)
# if defined(HAVE_CONST_<%=name.upcase%>)
@@ -94,7 +95,7 @@ erb_new.call(<<'EOS', '%').def_method(Object, "gen_const_decls")
% }
EOS
-erb_new.call(<<'EOS', '%').def_method(Object, "gen_const_defs_in_guard(name, default_value)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_const_defs_in_guard(name, default_value)")
#if defined(<%=name%>)
/* <%= COMMENTS[name] %> */
rb_define_const(rb_cSocket, <%=c_str name%>, INTEGER2NUM(<%=name%>));
@@ -103,7 +104,7 @@ erb_new.call(<<'EOS', '%').def_method(Object, "gen_const_defs_in_guard(name, def
#endif
EOS
-erb_new.call(<<'EOS', '%').def_method(Object, "gen_const_defs")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_const_defs")
% each_const {|guard, name, default_value|
% if guard
#if <%=guard%>
@@ -153,7 +154,7 @@ def each_names_with_len(pat, prefix_optional=nil)
}
end
-erb_new.call(<<'EOS', '%').def_method(Object, "gen_name_to_int_decl(funcname, pat, prefix_optional, guard=nil)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_name_to_int_decl(funcname, pat, prefix_optional, guard=nil)")
%if guard
#ifdef <%=guard%>
int <%=funcname%>(const char *str, long len, int *valp);
@@ -163,7 +164,7 @@ int <%=funcname%>(const char *str, long len, int *valp);
%end
EOS
-erb_new.call(<<'EOS', '%').def_method(Object, "gen_name_to_int_func_in_guard(funcname, pat, prefix_optional, guard=nil)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_name_to_int_func_in_guard(funcname, pat, prefix_optional, guard=nil)")
int
<%=funcname%>(const char *str, long len, int *valp)
{
@@ -185,7 +186,7 @@ int
}
EOS
-erb_new.call(<<'EOS', '%').def_method(Object, "gen_name_to_int_func(funcname, pat, prefix_optional, guard=nil)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_name_to_int_func(funcname, pat, prefix_optional, guard=nil)")
%if guard
#ifdef <%=guard%>
<%=gen_name_to_int_func_in_guard(funcname, pat, prefix_optional, guard)%>
@@ -214,7 +215,7 @@ def reverse_each_name_with_prefix_optional(pat, prefix_pat)
end
end
-erb_new.call(<<'EOS', '%').def_method(Object, "gen_int_to_name_hash(hash_var, pat, prefix_pat)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_int_to_name_hash(hash_var, pat, prefix_pat)")
<%=hash_var%> = st_init_numtable();
% reverse_each_name_with_prefix_optional(pat, prefix_pat) {|n,s|
#ifdef <%=n%>
@@ -223,7 +224,7 @@ erb_new.call(<<'EOS', '%').def_method(Object, "gen_int_to_name_hash(hash_var, pa
% }
EOS
-erb_new.call(<<'EOS', '%').def_method(Object, "gen_int_to_name_func(func_name, hash_var)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_int_to_name_func(func_name, hash_var)")
ID
<%=func_name%>(int val)
{
@@ -234,7 +235,7 @@ ID
}
EOS
-erb_new.call(<<'EOS', '%').def_method(Object, "gen_int_to_name_decl(func_name, hash_var)")
+erb_new.call(<<'EOS', nil, '%').def_method(Object, "gen_int_to_name_decl(func_name, hash_var)")
ID <%=func_name%>(int val);
EOS
@@ -283,7 +284,7 @@ def_intern('rsock_intern_udp_optname', /\AUDP_/, "UDP_")
def_intern('rsock_intern_scm_optname', /\ASCM_/, "SCM_")
def_intern('rsock_intern_local_optname', /\ALOCAL_/, "LOCAL_")
-result = erb_new.call(<<'EOS', '%').result(binding)
+result = erb_new.call(<<'EOS', nil, '%').result(binding)
/* autogenerated file */
<%= INTERN_DEFS.map {|vardef, gen_hash, decl, func| vardef }.join("\n") %>
@@ -326,7 +327,7 @@ init_constants(void)
EOS
-header_result = erb_new.call(<<'EOS', '%').result(binding)
+header_result = erb_new.call(<<'EOS', nil, '%').result(binding)
/* autogenerated file */
<%= gen_const_decls %>
<%= NAME_TO_INT_DEFS.map {|decl, func| decl }.join("\n") %>
@@ -422,8 +423,8 @@ AF_ISDN nil Integrated Services Digital Network
PF_ISDN nil Integrated Services Digital Network
AF_NATM nil Native ATM access
PF_NATM nil Native ATM access
-AF_SYSTEM nil Kernel event messages
-PF_SYSTEM nil Kernel event messages
+AF_SYSTEM
+PF_SYSTEM
AF_NETBIOS nil NetBIOS
PF_NETBIOS nil NetBIOS
AF_PPP nil Point-to-Point Protocol
@@ -439,8 +440,8 @@ PF_PACKET nil Direct link-layer access
AF_E164 nil CCITT (ITU-T) E.164 recommendation
PF_XTP nil eXpress Transfer Protocol
-PF_RTIP nil Help Identify RTIP packets
-PF_PIP nil Help Identify PIP packets
+PF_RTIP
+PF_PIP
AF_KEY nil Key management protocol, originally developed for usage with IPsec
PF_KEY nil Key management protocol, originally developed for usage with IPsec
AF_NETLINK nil Kernel user interface device
@@ -665,7 +666,6 @@ SO_SETFIB nil Set the associated routing table for the socket (FreeBSD
SO_RTABLE nil Set the routing table for this socket (OpenBSD)
SO_INCOMING_CPU nil Receive the cpu attached to the socket (Linux 3.19)
SO_INCOMING_NAPI_ID nil Receive the napi ID attached to a RX queue (Linux 4.12)
-SO_CONNECT_TIME nil Returns the number of seconds a socket has been connected. This option is only valid for connection-oriented protocols (Windows)
SOPRI_INTERACTIVE nil Interactive socket priority
SOPRI_NORMAL nil Normal socket priority
@@ -745,7 +745,6 @@ SHUT_RDWR 2 Shut down the both sides of the socket
IPV6_JOIN_GROUP nil Join a group membership
IPV6_LEAVE_GROUP nil Leave a group membership
-IPV6_MTU_DISCOVER nil Path MTU discovery
IPV6_MULTICAST_HOPS nil IP6 multicast hops
IPV6_MULTICAST_IF nil IP6 multicast interface
IPV6_MULTICAST_LOOP nil IP6 multicast loopback
@@ -760,7 +759,6 @@ IPV6_NEXTHOP nil Next hop address
IPV6_PATHMTU nil Retrieve current path MTU
IPV6_PKTINFO nil Receive packet information with datagram
IPV6_RECVDSTOPTS nil Receive all IP6 options for response
-IPV6_RECVERR nil Enable extended reliable error message passing
IPV6_RECVHOPLIMIT nil Receive hop limit with datagram
IPV6_RECVHOPOPTS nil Receive hop-by-hop options
IPV6_RECVPKTINFO nil Receive destination IP address and incoming interface
diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c
index 7ec700075e..45b4cad38f 100644
--- a/ext/socket/raddrinfo.c
+++ b/ext/socket/raddrinfo.c
@@ -10,22 +10,6 @@
#include "rubysocket.h"
-// GETADDRINFO_IMPL == 0 : call getaddrinfo/getnameinfo directly
-// GETADDRINFO_IMPL == 1 : call getaddrinfo/getnameinfo without gvl (but uncancellable)
-// GETADDRINFO_IMPL == 2 : call getaddrinfo/getnameinfo in a dedicated pthread
-// (and if the call is interrupted, the pthread is detached)
-
-#ifndef GETADDRINFO_IMPL
-# ifdef GETADDRINFO_EMU
-# define GETADDRINFO_IMPL 0
-# elif !defined(HAVE_PTHREAD_CREATE) || !defined(HAVE_PTHREAD_DETACH) || defined(__MINGW32__) || defined(__MINGW64__)
-# define GETADDRINFO_IMPL 1
-# else
-# define GETADDRINFO_IMPL 2
-# include "ruby/thread_native.h"
-# endif
-#endif
-
#if defined(INET6) && (defined(LOOKUP_ORDER_HACK_INET) || defined(LOOKUP_ORDER_HACK_INET6))
#define LOOKUP_ORDERS (sizeof(lookup_order_table) / sizeof(lookup_order_table[0]))
static const int lookup_order_table[] = {
@@ -189,6 +173,32 @@ parse_numeric_port(const char *service, int *portp)
}
#endif
+#ifndef GETADDRINFO_EMU
+struct getaddrinfo_arg
+{
+ const char *node;
+ const char *service;
+ const struct addrinfo *hints;
+ struct addrinfo **res;
+};
+
+static void *
+nogvl_getaddrinfo(void *arg)
+{
+ int ret;
+ struct getaddrinfo_arg *ptr = arg;
+ ret = getaddrinfo(ptr->node, ptr->service, ptr->hints, ptr->res);
+#ifdef __linux__
+ /* On Linux (mainly Ubuntu 13.04) /etc/nsswitch.conf has mdns4 and
+ * it cause getaddrinfo to return EAI_SYSTEM/ENOENT. [ruby-list:49420]
+ */
+ if (ret == EAI_SYSTEM && errno == ENOENT)
+ ret = EAI_NONAME;
+#endif
+ return (void *)(VALUE)ret;
+}
+#endif
+
static int
numeric_getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
@@ -293,277 +303,7 @@ rb_freeaddrinfo(struct rb_addrinfo *ai)
xfree(ai);
}
-#if GETADDRINFO_IMPL == 0
-
-static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
-{
- return getaddrinfo(hostp, portp, hints, ai);
-}
-
-#elif GETADDRINFO_IMPL == 1
-
-struct getaddrinfo_arg
-{
- const char *node;
- const char *service;
- const struct addrinfo *hints;
- struct addrinfo **res;
-};
-
-static void *
-nogvl_getaddrinfo(void *arg)
-{
- int ret;
- struct getaddrinfo_arg *ptr = arg;
- ret = getaddrinfo(ptr->node, ptr->service, ptr->hints, ptr->res);
-#ifdef __linux__
- /* On Linux (mainly Ubuntu 13.04) /etc/nsswitch.conf has mdns4 and
- * it cause getaddrinfo to return EAI_SYSTEM/ENOENT. [ruby-list:49420]
- */
- if (ret == EAI_SYSTEM && errno == ENOENT)
- ret = EAI_NONAME;
-#endif
- return (void *)(VALUE)ret;
-}
-
-static void *
-fork_safe_getaddrinfo(void *arg)
-{
- return rb_thread_prevent_fork(nogvl_getaddrinfo, arg);
-}
-
-static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
-{
- struct getaddrinfo_arg arg;
- MEMZERO(&arg, struct getaddrinfo_arg, 1);
- arg.node = hostp;
- arg.service = portp;
- arg.hints = hints;
- arg.res = ai;
- return (int)(VALUE)rb_thread_call_without_gvl(fork_safe_getaddrinfo, &arg, RUBY_UBF_IO, 0);
-}
-
-#elif GETADDRINFO_IMPL == 2
-
-struct getaddrinfo_arg
-{
- char *node, *service;
- struct addrinfo hints;
- struct addrinfo *ai;
- int err, gai_errno, refcount, done, cancelled;
- rb_nativethread_lock_t lock;
- rb_nativethread_cond_t cond;
-};
-
-static struct getaddrinfo_arg *
-allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints)
-{
- size_t hostp_offset = sizeof(struct getaddrinfo_arg);
- size_t portp_offset = hostp_offset + (hostp ? strlen(hostp) + 1 : 0);
- size_t bufsize = portp_offset + (portp ? strlen(portp) + 1 : 0);
-
- char *buf = malloc(bufsize);
- if (!buf) {
- rb_gc();
- buf = malloc(bufsize);
- if (!buf) return NULL;
- }
- struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)buf;
-
- if (hostp) {
- arg->node = buf + hostp_offset;
- strcpy(arg->node, hostp);
- }
- else {
- arg->node = NULL;
- }
-
- if (portp) {
- arg->service = buf + portp_offset;
- strcpy(arg->service, portp);
- }
- else {
- arg->service = NULL;
- }
-
- arg->hints = *hints;
- arg->ai = NULL;
-
- arg->refcount = 2;
- arg->done = arg->cancelled = 0;
-
- rb_nativethread_lock_initialize(&arg->lock);
- rb_native_cond_initialize(&arg->cond);
-
- return arg;
-}
-
-static void
-free_getaddrinfo_arg(struct getaddrinfo_arg *arg)
-{
- rb_native_cond_destroy(&arg->cond);
- rb_nativethread_lock_destroy(&arg->lock);
- free(arg);
-}
-
-static void *
-do_getaddrinfo(void *ptr)
-{
- struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)ptr;
-
- int err, gai_errno;
- err = getaddrinfo(arg->node, arg->service, &arg->hints, &arg->ai);
- gai_errno = errno;
-#ifdef __linux__
- /* On Linux (mainly Ubuntu 13.04) /etc/nsswitch.conf has mdns4 and
- * it cause getaddrinfo to return EAI_SYSTEM/ENOENT. [ruby-list:49420]
- */
- if (err == EAI_SYSTEM && errno == ENOENT)
- err = EAI_NONAME;
-#endif
-
- int need_free = 0;
- rb_nativethread_lock_lock(&arg->lock);
- {
- arg->err = err;
- arg->gai_errno = gai_errno;
- if (arg->cancelled) {
- if (arg->ai) freeaddrinfo(arg->ai);
- }
- else {
- arg->done = 1;
- rb_native_cond_signal(&arg->cond);
- }
- if (--arg->refcount == 0) need_free = 1;
- }
- rb_nativethread_lock_unlock(&arg->lock);
-
- if (need_free) free_getaddrinfo_arg(arg);
-
- return 0;
-}
-
-static void *
-wait_getaddrinfo(void *ptr)
-{
- struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)ptr;
- rb_nativethread_lock_lock(&arg->lock);
- while (!arg->done && !arg->cancelled) {
- rb_native_cond_wait(&arg->cond, &arg->lock);
- }
- rb_nativethread_lock_unlock(&arg->lock);
- return 0;
-}
-
-static void
-cancel_getaddrinfo(void *ptr)
-{
- struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)ptr;
- rb_nativethread_lock_lock(&arg->lock);
- {
- arg->cancelled = 1;
- rb_native_cond_signal(&arg->cond);
- }
- rb_nativethread_lock_unlock(&arg->lock);
-}
-
-static int
-do_pthread_create(pthread_t *th, void *(*start_routine) (void *), void *arg)
-{
- int limit = 3, ret;
- do {
- // It is said that pthread_create may fail spuriously, so we follow the JDK and retry several times.
- //
- // https://bugs.openjdk.org/browse/JDK-8268605
- // https://github.com/openjdk/jdk/commit/e35005d5ce383ddd108096a3079b17cb0bcf76f1
- ret = pthread_create(th, 0, start_routine, arg);
- } while (ret == EAGAIN && limit-- > 0);
- return ret;
-}
-
-static void *
-fork_safe_do_getaddrinfo(void *ptr)
-{
- return rb_thread_prevent_fork(do_getaddrinfo, ptr);
-}
-
-static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
-{
- int retry;
- struct getaddrinfo_arg *arg;
- int err = 0, gai_errno = 0;
-
-start:
- retry = 0;
-
- arg = allocate_getaddrinfo_arg(hostp, portp, hints);
- if (!arg) {
- return EAI_MEMORY;
- }
-
- pthread_t th;
- if (do_pthread_create(&th, fork_safe_do_getaddrinfo, arg) != 0) {
- int err = errno;
- free_getaddrinfo_arg(arg);
- errno = err;
- return EAI_SYSTEM;
- }
- pthread_detach(th);
-
- rb_thread_call_without_gvl2(wait_getaddrinfo, arg, cancel_getaddrinfo, arg);
-
- int need_free = 0;
- rb_nativethread_lock_lock(&arg->lock);
- {
- if (arg->done) {
- err = arg->err;
- gai_errno = arg->gai_errno;
- if (err == 0) *ai = arg->ai;
- }
- else if (arg->cancelled) {
- retry = 1;
- }
- else {
- // If already interrupted, rb_thread_call_without_gvl2 may return without calling wait_getaddrinfo.
- // In this case, it could be !arg->done && !arg->cancelled.
- arg->cancelled = 1; // to make do_getaddrinfo call freeaddrinfo
- retry = 1;
- }
- if (--arg->refcount == 0) need_free = 1;
- }
- rb_nativethread_lock_unlock(&arg->lock);
-
- if (need_free) free_getaddrinfo_arg(arg);
-
- // If the current thread is interrupted by asynchronous exception, the following raises the exception.
- // But if the current thread is interrupted by timer thread, the following returns; we need to manually retry.
- rb_thread_check_ints();
- if (retry) goto start;
-
- /* Because errno is threadlocal, the errno value we got from the call to getaddrinfo() in the thread
- * (in case of EAI_SYSTEM return value) is not propagated to the caller of _this_ function. Set errno
- * explicitly, as round-tripped through struct getaddrinfo_arg, to deal with that */
- if (gai_errno) errno = gai_errno;
- return err;
-}
-
-#endif
-
-#if GETADDRINFO_IMPL == 0
-
-int
-rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
- char *host, size_t hostlen,
- char *serv, size_t servlen, int flags)
-{
- return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
-}
-
-#elif GETADDRINFO_IMPL == 1
-
+#ifndef GETADDRINFO_EMU
struct getnameinfo_arg
{
const struct sockaddr *sa;
@@ -584,11 +324,16 @@ nogvl_getnameinfo(void *arg)
ptr->serv, (socklen_t)ptr->servlen,
ptr->flags);
}
+#endif
+
int
rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
- char *host, size_t hostlen,
- char *serv, size_t servlen, int flags)
+ char *host, size_t hostlen,
+ char *serv, size_t servlen, int flags)
{
+#ifdef GETADDRINFO_EMU
+ return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+#else
struct getnameinfo_arg arg;
int ret;
arg.sa = sa;
@@ -600,178 +345,8 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
arg.flags = flags;
ret = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getnameinfo, &arg, RUBY_UBF_IO, 0);
return ret;
-}
-
-#elif GETADDRINFO_IMPL == 2
-
-struct getnameinfo_arg
-{
- struct sockaddr *sa;
- socklen_t salen;
- int flags;
- char *host;
- size_t hostlen;
- char *serv;
- size_t servlen;
- int err, gni_errno, refcount, done, cancelled;
- rb_nativethread_lock_t lock;
- rb_nativethread_cond_t cond;
-};
-
-static struct getnameinfo_arg *
-allocate_getnameinfo_arg(const struct sockaddr *sa, socklen_t salen, size_t hostlen, size_t servlen, int flags)
-{
- size_t sa_offset = sizeof(struct getnameinfo_arg);
- size_t host_offset = sa_offset + salen;
- size_t serv_offset = host_offset + hostlen;
- size_t bufsize = serv_offset + servlen;
-
- char *buf = malloc(bufsize);
- if (!buf) {
- rb_gc();
- buf = malloc(bufsize);
- if (!buf) return NULL;
- }
- struct getnameinfo_arg *arg = (struct getnameinfo_arg *)buf;
-
- arg->sa = (struct sockaddr *)(buf + sa_offset);
- memcpy(arg->sa, sa, salen);
- arg->salen = salen;
- arg->host = buf + host_offset;
- arg->hostlen = hostlen;
- arg->serv = buf + serv_offset;
- arg->servlen = servlen;
- arg->flags = flags;
-
- arg->refcount = 2;
- arg->done = arg->cancelled = 0;
-
- rb_nativethread_lock_initialize(&arg->lock);
- rb_native_cond_initialize(&arg->cond);
-
- return arg;
-}
-
-static void
-free_getnameinfo_arg(struct getnameinfo_arg *arg)
-{
- rb_native_cond_destroy(&arg->cond);
- rb_nativethread_lock_destroy(&arg->lock);
-
- free(arg);
-}
-
-static void *
-do_getnameinfo(void *ptr)
-{
- struct getnameinfo_arg *arg = (struct getnameinfo_arg *)ptr;
-
- int err, gni_errno;
- err = getnameinfo(arg->sa, arg->salen, arg->host, (socklen_t)arg->hostlen, arg->serv, (socklen_t)arg->servlen, arg->flags);
- gni_errno = errno;
-
- int need_free = 0;
- rb_nativethread_lock_lock(&arg->lock);
- arg->err = err;
- arg->gni_errno = gni_errno;
- if (!arg->cancelled) {
- arg->done = 1;
- rb_native_cond_signal(&arg->cond);
- }
- if (--arg->refcount == 0) need_free = 1;
- rb_nativethread_lock_unlock(&arg->lock);
-
- if (need_free) free_getnameinfo_arg(arg);
-
- return 0;
-}
-
-static void *
-wait_getnameinfo(void *ptr)
-{
- struct getnameinfo_arg *arg = (struct getnameinfo_arg *)ptr;
- rb_nativethread_lock_lock(&arg->lock);
- while (!arg->done && !arg->cancelled) {
- rb_native_cond_wait(&arg->cond, &arg->lock);
- }
- rb_nativethread_lock_unlock(&arg->lock);
- return 0;
-}
-
-static void
-cancel_getnameinfo(void *ptr)
-{
- struct getnameinfo_arg *arg = (struct getnameinfo_arg *)ptr;
- rb_nativethread_lock_lock(&arg->lock);
- arg->cancelled = 1;
- rb_native_cond_signal(&arg->cond);
- rb_nativethread_lock_unlock(&arg->lock);
-}
-
-int
-rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
- char *host, size_t hostlen,
- char *serv, size_t servlen, int flags)
-{
- int retry;
- struct getnameinfo_arg *arg;
- int err, gni_errno = 0;
-
-start:
- retry = 0;
-
- arg = allocate_getnameinfo_arg(sa, salen, hostlen, servlen, flags);
- if (!arg) {
- return EAI_MEMORY;
- }
-
- pthread_t th;
- if (do_pthread_create(&th, do_getnameinfo, arg) != 0) {
- int err = errno;
- free_getnameinfo_arg(arg);
- errno = err;
- return EAI_SYSTEM;
- }
- pthread_detach(th);
-
- rb_thread_call_without_gvl2(wait_getnameinfo, arg, cancel_getnameinfo, arg);
-
- int need_free = 0;
- rb_nativethread_lock_lock(&arg->lock);
- if (arg->done) {
- err = arg->err;
- gni_errno = arg->gni_errno;
- if (err == 0) {
- if (host) memcpy(host, arg->host, hostlen);
- if (serv) memcpy(serv, arg->serv, servlen);
- }
- }
- else if (arg->cancelled) {
- retry = 1;
- }
- else {
- // If already interrupted, rb_thread_call_without_gvl2 may return without calling wait_getnameinfo.
- // In this case, it could be !arg->done && !arg->cancelled.
- arg->cancelled = 1;
- retry = 1;
- }
- if (--arg->refcount == 0) need_free = 1;
- rb_nativethread_lock_unlock(&arg->lock);
-
- if (need_free) free_getnameinfo_arg(arg);
-
- // If the current thread is interrupted by asynchronous exception, the following raises the exception.
- // But if the current thread is interrupted by timer thread, the following returns; we need to manually retry.
- rb_thread_check_ints();
- if (retry) goto start;
-
- /* Make sure we copy the thread-local errno value from the getnameinfo thread back to this thread, so
- * calling code sees the correct errno */
- if (gni_errno) errno = gni_errno;
- return err;
-}
-
#endif
+}
static void
make_ipaddr0(struct sockaddr *addr, socklen_t addrlen, char *buf, size_t buflen)
@@ -780,7 +355,7 @@ make_ipaddr0(struct sockaddr *addr, socklen_t addrlen, char *buf, size_t buflen)
error = rb_getnameinfo(addr, addrlen, buf, buflen, NULL, 0, NI_NUMERICHOST);
if (error) {
- rsock_raise_resolution_error("getnameinfo", error);
+ rsock_raise_socket_error("getnameinfo", error);
}
}
@@ -976,7 +551,17 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h
}
if (!resolved) {
- error = rb_getaddrinfo(hostp, portp, hints, &ai);
+#ifdef GETADDRINFO_EMU
+ error = getaddrinfo(hostp, portp, hints, &ai);
+#else
+ struct getaddrinfo_arg arg;
+ MEMZERO(&arg, struct getaddrinfo_arg, 1);
+ arg.node = hostp;
+ arg.service = portp;
+ arg.hints = hints;
+ arg.res = &ai;
+ error = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getaddrinfo, &arg, RUBY_UBF_IO, 0);
+#endif
if (error == 0) {
res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
res->allocated_by_malloc = 0;
@@ -989,7 +574,7 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h
if (hostp && hostp[strlen(hostp)-1] == '\n') {
rb_raise(rb_eSocket, "newline at the end of hostname");
}
- rsock_raise_resolution_error("getaddrinfo", error);
+ rsock_raise_socket_error("getaddrinfo", error);
}
return res;
@@ -1048,7 +633,7 @@ rsock_ipaddr(struct sockaddr *sockaddr, socklen_t sockaddrlen, int norevlookup)
error = rb_getnameinfo(sockaddr, sockaddrlen, hbuf, sizeof(hbuf),
pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
if (error) {
- rsock_raise_resolution_error("getnameinfo", error);
+ rsock_raise_socket_error("getnameinfo", error);
}
addr2 = rb_str_new2(hbuf);
if (addr1 == Qnil) {
@@ -1682,11 +1267,11 @@ rsock_inspect_sockaddr(struct sockaddr *sockaddr_arg, socklen_t socklen, VALUE r
* RFC 4007: IPv6 Scoped Address Architecture
* draft-ietf-ipv6-scope-api-00.txt: Scoped Address Extensions to the IPv6 Basic Socket API
*/
- error = rb_getnameinfo(&sockaddr->addr, socklen,
- hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
- NI_NUMERICHOST|NI_NUMERICSERV);
+ error = getnameinfo(&sockaddr->addr, socklen,
+ hbuf, (socklen_t)sizeof(hbuf), NULL, 0,
+ NI_NUMERICHOST|NI_NUMERICSERV);
if (error) {
- rsock_raise_resolution_error("getnameinfo", error);
+ rsock_raise_socket_error("getnameinfo", error);
}
if (addr->sin6_port == 0) {
rb_str_cat2(ret, hbuf);
@@ -2050,11 +1635,11 @@ addrinfo_mdump(VALUE self)
{
char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
int error;
- error = rb_getnameinfo(&rai->addr.addr, rai->sockaddr_len,
- hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
- NI_NUMERICHOST|NI_NUMERICSERV);
+ error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
+ hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
+ NI_NUMERICHOST|NI_NUMERICSERV);
if (error) {
- rsock_raise_resolution_error("getnameinfo", error);
+ rsock_raise_socket_error("getnameinfo", error);
}
sockaddr = rb_assoc_new(rb_str_new_cstr(hbuf), rb_str_new_cstr(pbuf));
break;
@@ -2396,11 +1981,11 @@ addrinfo_getnameinfo(int argc, VALUE *argv, VALUE self)
if (rai->socktype == SOCK_DGRAM)
flags |= NI_DGRAM;
- error = rb_getnameinfo(&rai->addr.addr, rai->sockaddr_len,
- hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
- flags);
+ error = getnameinfo(&rai->addr.addr, rai->sockaddr_len,
+ hbuf, (socklen_t)sizeof(hbuf), pbuf, (socklen_t)sizeof(pbuf),
+ flags);
if (error) {
- rsock_raise_resolution_error("getnameinfo", error);
+ rsock_raise_socket_error("getnameinfo", error);
}
return rb_assoc_new(rb_str_new2(hbuf), rb_str_new2(pbuf));
@@ -3030,12 +2615,12 @@ rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len)
void
rsock_init_addrinfo(void)
{
- id_timeout = rb_intern("timeout");
-
/*
* The Addrinfo class maps <tt>struct addrinfo</tt> to ruby. This
* structure identifies an Internet host and a service.
*/
+ id_timeout = rb_intern("timeout");
+
rb_cAddrinfo = rb_define_class("Addrinfo", rb_cObject);
rb_define_alloc_func(rb_cAddrinfo, addrinfo_s_allocate);
rb_define_method(rb_cAddrinfo, "initialize", addrinfo_initialize, -1);
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index f486db4262..5f803ba0da 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -35,7 +35,6 @@
#ifdef _WIN32
# include <winsock2.h>
# include <ws2tcpip.h>
-# include <mswsock.h>
# include <iphlpapi.h>
# if defined(_MSC_VER)
# undef HAVE_TYPE_STRUCT_SOCKADDR_DL
@@ -286,7 +285,6 @@ extern VALUE rb_cAddrinfo;
extern VALUE rb_cSockOpt;
extern VALUE rb_eSocket;
-extern VALUE rb_eResolution;
#ifdef SOCKS
extern VALUE rb_cSOCKSSocket;
@@ -309,7 +307,7 @@ VALUE rsock_sockaddr_string_value_with_addrinfo(volatile VALUE *v, VALUE *ai_ret
VALUE rb_check_sockaddr_string_type(VALUE);
-NORETURN(void rsock_raise_resolution_error(const char *, int));
+NORETURN(void rsock_raise_socket_error(const char *, int));
int rsock_family_arg(VALUE domain);
int rsock_socktype_arg(VALUE type);
@@ -461,8 +459,6 @@ VALUE rsock_write_nonblock(VALUE sock, VALUE buf, VALUE ex);
void rsock_make_fd_nonblock(int fd);
-int rsock_is_dgram(rb_io_t *fptr);
-
#if !defined HAVE_INET_NTOP && ! defined _WIN32
const char *inet_ntop(int, const void *, char *, size_t);
#elif defined __MINGW32__
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index c780d77cf6..eb74f7a936 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -1313,7 +1313,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
saved_errno = errno;
if (res) rb_freeaddrinfo(res);
errno = saved_errno;
- rsock_raise_resolution_error("getnameinfo", error);
+ rsock_raise_socket_error("getnameinfo", error);
UNREACHABLE_RETURN(Qnil);
}
@@ -1654,7 +1654,8 @@ socket_s_ip_address_list(VALUE self)
finish:
save_errno = errno;
- xfree(lc.lifc_req);
+ if (lc.lifc_buf != NULL)
+ xfree(lc.lifc_req);
if (fd != -1)
close(fd);
errno = save_errno;
diff --git a/ext/socket/sockssocket.c b/ext/socket/sockssocket.c
index 1e94186cd0..f263ac3804 100644
--- a/ext/socket/sockssocket.c
+++ b/ext/socket/sockssocket.c
@@ -48,7 +48,7 @@ socks_s_close(VALUE sock)
rb_io_t *fptr;
GetOpenFile(sock, fptr);
- shutdown(fptr->fd, SHUT_RDWR);
+ shutdown(fptr->fd, 2);
return rb_io_close(sock);
}
#endif
diff --git a/ext/socket/unixsocket.c b/ext/socket/unixsocket.c
index a8475e3e60..26ab76fc9f 100644
--- a/ext/socket/unixsocket.c
+++ b/ext/socket/unixsocket.c
@@ -540,7 +540,7 @@ unix_peeraddr(VALUE sock)
*
* Creates a pair of sockets connected to each other.
*
- * _type_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
+ * _socktype_ should be a socket type such as: :STREAM, :DGRAM, :RAW, etc.
*
* _protocol_ should be a protocol defined in the domain.
* 0 is default protocol for the domain.
diff --git a/ext/stringio/.document b/ext/stringio/.document
deleted file mode 100644
index decba0135a..0000000000
--- a/ext/stringio/.document
+++ /dev/null
@@ -1 +0,0 @@
-*.[ch]
diff --git a/ext/stringio/depend b/ext/stringio/depend
index b9fba7e9fa..828fc6e842 100644
--- a/ext/stringio/depend
+++ b/ext/stringio/depend
@@ -53,7 +53,6 @@ stringio.o: $(hdrdir)/ruby/internal/attr/noexcept.h
stringio.o: $(hdrdir)/ruby/internal/attr/noinline.h
stringio.o: $(hdrdir)/ruby/internal/attr/nonnull.h
stringio.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-stringio.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
stringio.o: $(hdrdir)/ruby/internal/attr/pure.h
stringio.o: $(hdrdir)/ruby/internal/attr/restrict.h
stringio.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ stringio.o: $(hdrdir)/ruby/internal/intern/enumerator.h
stringio.o: $(hdrdir)/ruby/internal/intern/error.h
stringio.o: $(hdrdir)/ruby/internal/intern/eval.h
stringio.o: $(hdrdir)/ruby/internal/intern/file.h
+stringio.o: $(hdrdir)/ruby/internal/intern/gc.h
stringio.o: $(hdrdir)/ruby/internal/intern/hash.h
stringio.o: $(hdrdir)/ruby/internal/intern/io.h
stringio.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,12 +152,12 @@ stringio.o: $(hdrdir)/ruby/internal/memory.h
stringio.o: $(hdrdir)/ruby/internal/method.h
stringio.o: $(hdrdir)/ruby/internal/module.h
stringio.o: $(hdrdir)/ruby/internal/newobj.h
+stringio.o: $(hdrdir)/ruby/internal/rgengc.h
stringio.o: $(hdrdir)/ruby/internal/scan_args.h
stringio.o: $(hdrdir)/ruby/internal/special_consts.h
stringio.o: $(hdrdir)/ruby/internal/static_assert.h
stringio.o: $(hdrdir)/ruby/internal/stdalign.h
stringio.o: $(hdrdir)/ruby/internal/stdbool.h
-stringio.o: $(hdrdir)/ruby/internal/stdckdint.h
stringio.o: $(hdrdir)/ruby/internal/symbol.h
stringio.o: $(hdrdir)/ruby/internal/value.h
stringio.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/stringio/extconf.rb b/ext/stringio/extconf.rb
index 553732f79c..a933159766 100644
--- a/ext/stringio/extconf.rb
+++ b/ext/stringio/extconf.rb
@@ -1,7 +1,4 @@
# frozen_string_literal: false
require 'mkmf'
-if RUBY_ENGINE == 'ruby'
- create_makefile('stringio')
-else
- File.write('Makefile', dummy_makefile("").join)
-end
+have_func("rb_io_extract_modeenc", "ruby/io.h")
+create_makefile('stringio')
diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c
index 07e970f295..0054766dac 100644
--- a/ext/stringio/stringio.c
+++ b/ext/stringio/stringio.c
@@ -12,10 +12,7 @@
**********************************************************************/
-static const char *const
-STRINGIO_VERSION = "3.1.2.dev";
-
-#include <stdbool.h>
+#define STRINGIO_VERSION "3.0.4"
#include "ruby.h"
#include "ruby/io.h"
@@ -35,6 +32,86 @@ STRINGIO_VERSION = "3.1.2.dev";
# define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
#endif
+#ifndef HAVE_RB_IO_EXTRACT_MODEENC
+#define rb_io_extract_modeenc strio_extract_modeenc
+static void
+strio_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
+ int *oflags_p, int *fmode_p, struct rb_io_enc_t *convconfig_p)
+{
+ VALUE mode = *vmode_p;
+ VALUE intmode;
+ int fmode;
+ int has_enc = 0, has_vmode = 0;
+
+ convconfig_p->enc = convconfig_p->enc2 = 0;
+
+ vmode_handle:
+ if (NIL_P(mode)) {
+ fmode = FMODE_READABLE;
+ }
+ else if (!NIL_P(intmode = rb_check_to_integer(mode, "to_int"))) {
+ int flags = NUM2INT(intmode);
+ fmode = rb_io_oflags_fmode(flags);
+ }
+ else {
+ const char *m = StringValueCStr(mode), *n, *e;
+ fmode = rb_io_modestr_fmode(m);
+ n = strchr(m, ':');
+ if (n) {
+ long len;
+ char encname[ENCODING_MAXNAMELEN+1];
+ has_enc = 1;
+ if (fmode & FMODE_SETENC_BY_BOM) {
+ n = strchr(n, '|');
+ }
+ e = strchr(++n, ':');
+ len = e ? e - n : (long)strlen(n);
+ if (len > 0 && len <= ENCODING_MAXNAMELEN) {
+ rb_encoding *enc;
+ if (e) {
+ memcpy(encname, n, len);
+ encname[len] = '\0';
+ n = encname;
+ }
+ enc = rb_enc_find(n);
+ if (e)
+ convconfig_p->enc2 = enc;
+ else
+ convconfig_p->enc = enc;
+ }
+ if (e && (len = strlen(++e)) > 0 && len <= ENCODING_MAXNAMELEN) {
+ convconfig_p->enc = rb_enc_find(e);
+ }
+ }
+ }
+
+ if (!NIL_P(opthash)) {
+ rb_encoding *extenc = 0, *intenc = 0;
+ VALUE v;
+ if (!has_vmode) {
+ ID id_mode;
+ CONST_ID(id_mode, "mode");
+ v = rb_hash_aref(opthash, ID2SYM(id_mode));
+ if (!NIL_P(v)) {
+ if (!NIL_P(mode)) {
+ rb_raise(rb_eArgError, "mode specified twice");
+ }
+ has_vmode = 1;
+ mode = v;
+ goto vmode_handle;
+ }
+ }
+
+ if (rb_io_extract_encoding_option(opthash, &extenc, &intenc, &fmode)) {
+ if (has_enc) {
+ rb_raise(rb_eArgError, "encoding specified twice");
+ }
+ }
+ }
+ *fmode_p = fmode;
+}
+#endif
+
struct StringIO {
VALUE string;
rb_encoding *enc;
@@ -50,13 +127,7 @@ static long strio_write(VALUE self, VALUE str);
#define IS_STRIO(obj) (rb_typeddata_is_kind_of((obj), &strio_data_type))
#define error_inval(msg) (rb_syserr_fail(EINVAL, msg))
-#define get_enc(ptr) ((ptr)->enc ? (ptr)->enc : !NIL_P((ptr)->string) ? rb_enc_get((ptr)->string) : NULL)
-
-static bool
-readonly_string_p(VALUE string)
-{
- return OBJ_FROZEN_RAW(string);
-}
+#define get_enc(ptr) ((ptr)->enc ? (ptr)->enc : rb_enc_get((ptr)->string))
static struct StringIO *
strio_alloc(void)
@@ -100,7 +171,7 @@ static const rb_data_type_t strio_data_type = {
strio_free,
strio_memsize,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
#define check_strio(self) ((struct StringIO*)rb_check_typeddata((self), &strio_data_type))
@@ -174,10 +245,7 @@ writable(VALUE strio)
static void
check_modifiable(struct StringIO *ptr)
{
- if (NIL_P(ptr->string)) {
- /* Null device StringIO */
- }
- else if (OBJ_FROZEN_RAW(ptr->string)) {
+ if (OBJ_FROZEN(ptr->string)) {
rb_raise(rb_eIOError, "not modifiable string");
}
}
@@ -288,18 +356,17 @@ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
{
VALUE string, vmode, opt;
int oflags;
- rb_io_enc_t convconfig;
+ struct rb_io_enc_t convconfig;
argc = rb_scan_args(argc, argv, "02:", &string, &vmode, &opt);
rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &ptr->flags, &convconfig);
- if (!NIL_P(string)) {
+ if (argc) {
StringValue(string);
}
- else if (!argc) {
+ else {
string = rb_enc_str_new("", 0, rb_default_external_encoding());
}
-
- if (!NIL_P(string) && readonly_string_p(string)) {
+ if (OBJ_FROZEN_RAW(string)) {
if (ptr->flags & FMODE_WRITABLE) {
rb_syserr_fail(EACCES, 0);
}
@@ -309,11 +376,11 @@ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
ptr->flags |= FMODE_WRITABLE;
}
}
- if (!NIL_P(string) && (ptr->flags & FMODE_TRUNC)) {
+ if (ptr->flags & FMODE_TRUNC) {
rb_str_resize(string, 0);
}
- RB_OBJ_WRITE(self, &ptr->string, string);
- if (argc == 1 && !NIL_P(string)) {
+ ptr->string = string;
+ if (argc == 1) {
ptr->enc = rb_enc_get(string);
}
else {
@@ -330,7 +397,7 @@ static VALUE
strio_finalize(VALUE self)
{
struct StringIO *ptr = StringIO(self);
- RB_OBJ_WRITE(self, &ptr->string, Qnil);
+ ptr->string = Qnil;
ptr->flags &= ~FMODE_READWRITE;
return self;
}
@@ -493,11 +560,10 @@ strio_set_string(VALUE self, VALUE string)
rb_io_taint_check(self);
ptr->flags &= ~FMODE_READWRITE;
StringValue(string);
- ptr->flags = readonly_string_p(string) ? FMODE_READABLE : FMODE_READWRITE;
+ ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
ptr->pos = 0;
ptr->lineno = 0;
- RB_OBJ_WRITE(self, &ptr->string, string);
- return string;
+ return ptr->string = string;
}
/*
@@ -607,7 +673,6 @@ static struct StringIO *
strio_to_read(VALUE self)
{
struct StringIO *ptr = readable(self);
- if (NIL_P(ptr->string)) return NULL;
if (ptr->pos < RSTRING_LEN(ptr->string)) return ptr;
return NULL;
}
@@ -617,9 +682,11 @@ strio_to_read(VALUE self)
* eof? -> true or false
*
* Returns +true+ if positioned at end-of-stream, +false+ otherwise;
- * see {Position}[rdoc-ref:IO@Position].
+ * see {Position}[rdoc-ref:File@Position].
*
* Raises IOError if the stream is not opened for reading.
+ *
+ * StreamIO#eof is an alias for StreamIO#eof?.
*/
static VALUE
strio_eof(VALUE self)
@@ -632,19 +699,15 @@ strio_eof(VALUE self)
static VALUE
strio_copy(VALUE copy, VALUE orig)
{
- struct StringIO *ptr, *old_ptr;
- VALUE old_string = Qundef;
+ struct StringIO *ptr;
orig = rb_convert_type(orig, T_DATA, "StringIO", "to_strio");
if (copy == orig) return copy;
ptr = StringIO(orig);
- old_ptr = check_strio(copy);
- if (old_ptr) {
- old_string = old_ptr->string;
- strio_free(old_ptr);
+ if (check_strio(copy)) {
+ strio_free(DATA_PTR(copy));
}
DATA_PTR(copy) = ptr;
- RB_OBJ_WRITTEN(copy, old_string, ptr->string);
RBASIC(copy)->flags &= ~STRIO_READWRITE;
RBASIC(copy)->flags |= RBASIC(orig)->flags & STRIO_READWRITE;
++ptr->count;
@@ -745,6 +808,8 @@ strio_reopen(int argc, VALUE *argv, VALUE self)
*
* Returns the current position (in bytes);
* see {Position}[rdoc-ref:IO@Position].
+ *
+ * StringIO#tell is an alias for StringIO#pos.
*/
static VALUE
strio_get_pos(VALUE self)
@@ -885,7 +950,7 @@ strio_getc(VALUE self)
int len;
char *p;
- if (NIL_P(str) || pos >= RSTRING_LEN(str)) {
+ if (pos >= RSTRING_LEN(str)) {
return Qnil;
}
p = RSTRING_PTR(str)+pos;
@@ -906,7 +971,7 @@ strio_getbyte(VALUE self)
{
struct StringIO *ptr = readable(self);
int c;
- if (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string)) {
+ if (ptr->pos >= RSTRING_LEN(ptr->string)) {
return Qnil;
}
c = RSTRING_PTR(ptr->string)[ptr->pos++];
@@ -928,6 +993,9 @@ strio_extend(struct StringIO *ptr, long pos, long len)
if (pos > olen)
MEMZERO(RSTRING_PTR(ptr->string) + olen, char, pos - olen);
}
+ else {
+ rb_str_modify(ptr->string);
+ }
}
/*
@@ -944,7 +1012,6 @@ strio_ungetc(VALUE self, VALUE c)
rb_encoding *enc, *enc2;
check_modifiable(ptr);
- if (NIL_P(ptr->string)) return Qnil;
if (NIL_P(c)) return Qnil;
if (RB_INTEGER_TYPE_P(c)) {
int len, cc = NUM2INT(c);
@@ -982,13 +1049,12 @@ strio_ungetbyte(VALUE self, VALUE c)
struct StringIO *ptr = readable(self);
check_modifiable(ptr);
- if (NIL_P(ptr->string)) return Qnil;
if (NIL_P(c)) return Qnil;
if (RB_INTEGER_TYPE_P(c)) {
- /* rb_int_and() not visible from exts */
- VALUE v = rb_funcall(c, '&', 1, INT2FIX(0xff));
- const char cc = NUM2INT(v) & 0xFF;
- strio_unget_bytes(ptr, &cc, 1);
+ /* rb_int_and() not visible from exts */
+ VALUE v = rb_funcall(c, '&', 1, INT2FIX(0xff));
+ const char cc = NUM2INT(v) & 0xFF;
+ strio_unget_bytes(ptr, &cc, 1);
}
else {
long cl;
@@ -1155,57 +1221,38 @@ struct getline_arg {
};
static struct getline_arg *
-prepare_getline_args(struct StringIO *ptr, struct getline_arg *arg, int argc, VALUE *argv)
+prepare_getline_args(struct getline_arg *arg, int argc, VALUE *argv)
{
- VALUE rs, lim, opts;
+ VALUE str, lim, opts;
long limit = -1;
int respect_chomp;
- argc = rb_scan_args(argc, argv, "02:", &rs, &lim, &opts);
- respect_chomp = argc == 0 || !NIL_P(rs);
+ argc = rb_scan_args(argc, argv, "02:", &str, &lim, &opts);
+ respect_chomp = argc == 0 || !NIL_P(str);
switch (argc) {
case 0:
- rs = rb_rs;
+ str = rb_rs;
break;
case 1:
- if (!NIL_P(rs) && !RB_TYPE_P(rs, T_STRING)) {
- VALUE tmp = rb_check_string_type(rs);
+ if (!NIL_P(str) && !RB_TYPE_P(str, T_STRING)) {
+ VALUE tmp = rb_check_string_type(str);
if (NIL_P(tmp)) {
- limit = NUM2LONG(rs);
- rs = rb_rs;
+ limit = NUM2LONG(str);
+ str = rb_rs;
}
else {
- rs = tmp;
+ str = tmp;
}
}
break;
case 2:
- if (!NIL_P(rs)) StringValue(rs);
+ if (!NIL_P(str)) StringValue(str);
if (!NIL_P(lim)) limit = NUM2LONG(lim);
break;
}
- if (!NIL_P(ptr->string) && !NIL_P(rs)) {
- rb_encoding *enc_rs, *enc_io;
- enc_rs = rb_enc_get(rs);
- enc_io = get_enc(ptr);
- if (enc_rs != enc_io &&
- (rb_enc_str_coderange(rs) != ENC_CODERANGE_7BIT ||
- (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
- if (rs == rb_rs) {
- rs = rb_enc_str_new(0, 0, enc_io);
- rb_str_buf_cat_ascii(rs, "\n");
- rs = rs;
- }
- else {
- rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
- rb_enc_name(enc_io),
- rb_enc_name(enc_rs));
- }
- }
- }
- arg->rs = rs;
+ arg->rs = str;
arg->limit = limit;
arg->chomp = 0;
if (!NIL_P(opts)) {
@@ -1215,9 +1262,9 @@ prepare_getline_args(struct StringIO *ptr, struct getline_arg *arg, int argc, VA
keywords[0] = rb_intern_const("chomp");
}
rb_get_kwargs(opts, keywords, 0, 1, &vchomp);
- if (respect_chomp) {
+ if (respect_chomp) {
arg->chomp = (vchomp != Qundef) && RTEST(vchomp);
- }
+ }
}
return arg;
}
@@ -1241,7 +1288,7 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
long w = 0;
rb_encoding *enc = get_enc(ptr);
- if (NIL_P(ptr->string) || ptr->pos >= (n = RSTRING_LEN(ptr->string))) {
+ if (ptr->pos >= (n = RSTRING_LEN(ptr->string))) {
return Qnil;
}
s = RSTRING_PTR(ptr->string);
@@ -1257,7 +1304,7 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
str = strio_substr(ptr, ptr->pos, e - s - w, enc);
}
else if ((n = RSTRING_LEN(str)) == 0) {
- const char *paragraph_end = NULL;
+ const char *paragraph_end = NULL;
p = s;
while (p[(p + 1 < e) && (*p == '\r') && 0] == '\n') {
p += *p == '\r';
@@ -1267,18 +1314,18 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
}
s = p;
while ((p = memchr(p, '\n', e - p)) && (p != e)) {
- p++;
- if (!((p < e && *p == '\n') ||
- (p + 1 < e && *p == '\r' && *(p+1) == '\n'))) {
- continue;
- }
- paragraph_end = p - ((*(p-2) == '\r') ? 2 : 1);
- while ((p < e && *p == '\n') ||
- (p + 1 < e && *p == '\r' && *(p+1) == '\n')) {
- p += (*p == '\r') ? 2 : 1;
- }
- e = p;
- break;
+ p++;
+ if (!((p < e && *p == '\n') ||
+ (p + 1 < e && *p == '\r' && *(p+1) == '\n'))) {
+ continue;
+ }
+ paragraph_end = p - ((*(p-2) == '\r') ? 2 : 1);
+ while ((p < e && *p == '\n') ||
+ (p + 1 < e && *p == '\r' && *(p+1) == '\n')) {
+ p += (*p == '\r') ? 2 : 1;
+ }
+ e = p;
+ break;
}
if (arg->chomp && paragraph_end) {
w = e - paragraph_end;
@@ -1333,16 +1380,15 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
static VALUE
strio_gets(int argc, VALUE *argv, VALUE self)
{
- struct StringIO *ptr = readable(self);
struct getline_arg arg;
VALUE str;
- if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
- if (NIL_P(ptr->string)) return Qnil;
+ if (prepare_getline_args(&arg, argc, argv)->limit == 0) {
+ struct StringIO *ptr = readable(self);
return rb_enc_str_new(0, 0, get_enc(ptr));
}
- str = strio_getline(&arg, ptr);
+ str = strio_getline(&arg, readable(self));
rb_lastline_set(str);
return str;
}
@@ -1374,21 +1420,23 @@ strio_readline(int argc, VALUE *argv, VALUE self)
* does nothing if already at end-of-file;
* returns +self+.
* See {Line IO}[rdoc-ref:IO@Line+IO].
+ *
+ * StringIO#each is an alias for StringIO#each_line.
*/
static VALUE
strio_each(int argc, VALUE *argv, VALUE self)
{
VALUE line;
- struct StringIO *ptr = readable(self);
struct getline_arg arg;
+ StringIO(self);
RETURN_ENUMERATOR(self, argc, argv);
- if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
+ if (prepare_getline_args(&arg, argc, argv)->limit == 0) {
rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
}
- while (!NIL_P(line = strio_getline(&arg, ptr))) {
+ while (!NIL_P(line = strio_getline(&arg, readable(self)))) {
rb_yield(line);
}
return self;
@@ -1406,15 +1454,15 @@ static VALUE
strio_readlines(int argc, VALUE *argv, VALUE self)
{
VALUE ary, line;
- struct StringIO *ptr = readable(self);
struct getline_arg arg;
- if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
+ StringIO(self);
+ ary = rb_ary_new();
+ if (prepare_getline_args(&arg, argc, argv)->limit == 0) {
rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
}
- ary = rb_ary_new();
- while (!NIL_P(line = strio_getline(&arg, ptr))) {
+ while (!NIL_P(line = strio_getline(&arg, readable(self)))) {
rb_ary_push(ary, line);
}
return ary;
@@ -1453,7 +1501,6 @@ strio_write(VALUE self, VALUE str)
if (!RB_TYPE_P(str, T_STRING))
str = rb_obj_as_string(str);
enc = get_enc(ptr);
- if (!enc) return 0;
enc2 = rb_enc_get(str);
if (enc != enc2 && enc != ascii8bit && enc != (usascii = rb_usascii_encoding())) {
VALUE converted = rb_str_conv_enc(str, enc2, enc);
@@ -1479,7 +1526,6 @@ strio_write(VALUE self, VALUE str)
}
else {
strio_extend(ptr, ptr->pos, len);
- rb_str_modify(ptr->string);
memmove(RSTRING_PTR(ptr->string)+ptr->pos, RSTRING_PTR(str), len);
}
RB_GC_GUARD(str);
@@ -1526,12 +1572,10 @@ strio_putc(VALUE self, VALUE ch)
check_modifiable(ptr);
if (RB_TYPE_P(ch, T_STRING)) {
- if (NIL_P(ptr->string)) return ch;
str = rb_str_substr(ch, 0, 1);
}
else {
char c = NUM2CHR(ch);
- if (NIL_P(ptr->string)) return ch;
str = rb_str_new(&c, 1);
}
strio_write(self, str);
@@ -1574,8 +1618,7 @@ strio_read(int argc, VALUE *argv, VALUE self)
if (len < 0) {
rb_raise(rb_eArgError, "negative length %ld given", len);
}
- if (len > 0 &&
- (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string))) {
+ if (len > 0 && ptr->pos >= RSTRING_LEN(ptr->string)) {
if (!NIL_P(str)) rb_str_resize(str, 0);
return Qnil;
}
@@ -1584,7 +1627,6 @@ strio_read(int argc, VALUE *argv, VALUE self)
}
/* fall through */
case 0:
- if (NIL_P(ptr->string)) return Qnil;
len = RSTRING_LEN(ptr->string);
if (len <= ptr->pos) {
rb_encoding *enc = get_enc(ptr);
@@ -1602,7 +1644,7 @@ strio_read(int argc, VALUE *argv, VALUE self)
}
break;
default:
- rb_error_arity(argc, 0, 2);
+ rb_error_arity(argc, 0, 2);
}
if (NIL_P(str)) {
rb_encoding *enc = binary ? rb_ascii8bit_encoding() : get_enc(ptr);
@@ -1613,64 +1655,16 @@ strio_read(int argc, VALUE *argv, VALUE self)
if (len > rest) len = rest;
rb_str_resize(str, len);
MEMCPY(RSTRING_PTR(str), RSTRING_PTR(ptr->string) + ptr->pos, char, len);
- if (!binary) {
+ if (binary)
+ rb_enc_associate(str, rb_ascii8bit_encoding());
+ else
rb_enc_copy(str, ptr->string);
- }
}
ptr->pos += RSTRING_LEN(str);
return str;
}
/*
- * call-seq:
- * pread(maxlen, offset) -> string
- * pread(maxlen, offset, out_string) -> string
- *
- * See IO#pread.
- */
-static VALUE
-strio_pread(int argc, VALUE *argv, VALUE self)
-{
- VALUE rb_len, rb_offset, rb_buf;
- rb_scan_args(argc, argv, "21", &rb_len, &rb_offset, &rb_buf);
- long len = NUM2LONG(rb_len);
- long offset = NUM2LONG(rb_offset);
-
- if (len < 0) {
- rb_raise(rb_eArgError, "negative string size (or size too big): %" PRIsVALUE, rb_len);
- }
-
- if (len == 0) {
- if (NIL_P(rb_buf)) {
- return rb_str_new("", 0);
- }
- return rb_buf;
- }
-
- if (offset < 0) {
- rb_syserr_fail_str(EINVAL, rb_sprintf("pread: Invalid offset argument: %" PRIsVALUE, rb_offset));
- }
-
- struct StringIO *ptr = readable(self);
-
- if (offset >= RSTRING_LEN(ptr->string)) {
- rb_eof_error();
- }
-
- if (NIL_P(rb_buf)) {
- return strio_substr(ptr, offset, len, rb_ascii8bit_encoding());
- }
-
- long rest = RSTRING_LEN(ptr->string) - offset;
- if (len > rest) len = rest;
- rb_str_resize(rb_buf, len);
- rb_enc_associate(rb_buf, rb_ascii8bit_encoding());
- MEMCPY(RSTRING_PTR(rb_buf), RSTRING_PTR(ptr->string) + offset, char, len);
- return rb_buf;
-}
-
-
-/*
* call-seq:
* strio.sysread(integer[, outbuf]) -> string
* strio.readpartial(integer[, outbuf]) -> string
@@ -1718,14 +1712,8 @@ strio_read_nonblock(int argc, VALUE *argv, VALUE self)
return val;
}
-/*
- * See IO#write
- */
#define strio_syswrite rb_io_write
-/*
- * See IO#write_nonblock
- */
static VALUE
strio_syswrite_nonblock(int argc, VALUE *argv, VALUE self)
{
@@ -1753,7 +1741,7 @@ strio_size(VALUE self)
{
VALUE string = StringIO(self)->string;
if (NIL_P(string)) {
- return INT2FIX(0);
+ rb_raise(rb_eIOError, "not opened");
}
return ULONG2NUM(RSTRING_LEN(string));
}
@@ -1770,12 +1758,10 @@ strio_truncate(VALUE self, VALUE len)
{
VALUE string = writable(self)->string;
long l = NUM2LONG(len);
- long plen;
+ long plen = RSTRING_LEN(string);
if (l < 0) {
error_inval("negative length");
}
- if (NIL_P(string)) return 0;
- plen = RSTRING_LEN(string);
rb_str_resize(string, l);
if (plen < l) {
MEMZERO(RSTRING_PTR(string) + plen, char, l - plen);
@@ -1838,7 +1824,7 @@ strio_set_encoding(int argc, VALUE *argv, VALUE self)
else {
enc = rb_find_encoding(ext_enc);
if (!enc) {
- rb_io_enc_t convconfig;
+ struct rb_io_enc_t convconfig;
int oflags, fmode;
VALUE vmode = rb_str_append(rb_str_new_cstr("r:"), ext_enc);
rb_io_extract_modeenc(&vmode, 0, Qnil, &oflags, &fmode, &convconfig);
@@ -1846,22 +1832,13 @@ strio_set_encoding(int argc, VALUE *argv, VALUE self)
}
}
ptr->enc = enc;
- if (!NIL_P(ptr->string) && WRITABLE(self)) {
+ if (WRITABLE(self)) {
rb_enc_associate(ptr->string, enc);
}
return self;
}
-/*
- * call-seq:
- * strio.set_encoding_by_bom => strio or nil
- *
- * Sets the encoding according to the BOM (Byte Order Mark) in the
- * string.
- *
- * Returns +self+ if the BOM is found, otherwise +nil.
- */
static VALUE
strio_set_encoding_by_bom(VALUE self)
{
@@ -1894,15 +1871,10 @@ Init_stringio(void)
VALUE StringIO = rb_define_class("StringIO", rb_cObject);
- /* The version string */
rb_define_const(StringIO, "VERSION", rb_str_new_cstr(STRINGIO_VERSION));
rb_include_module(StringIO, rb_mEnumerable);
rb_define_alloc_func(StringIO, strio_s_allocate);
-
- /* Maximum length that a StringIO instance can hold */
- rb_define_const(StringIO, "MAX_LENGTH", LONG2NUM(LONG_MAX));
-
rb_define_singleton_method(StringIO, "new", strio_s_new, -1);
rb_define_singleton_method(StringIO, "open", strio_s_open, -1);
rb_define_method(StringIO, "initialize", strio_initialize, -1);
@@ -1952,7 +1924,6 @@ Init_stringio(void)
rb_define_method(StringIO, "gets", strio_gets, -1);
rb_define_method(StringIO, "readlines", strio_readlines, -1);
rb_define_method(StringIO, "read", strio_read, -1);
- rb_define_method(StringIO, "pread", strio_pread, -1);
rb_define_method(StringIO, "write", strio_write_m, -1);
rb_define_method(StringIO, "putc", strio_putc, 1);
diff --git a/ext/stringio/stringio.gemspec b/ext/stringio/stringio.gemspec
index b40b7fc824..1015d261f5 100644
--- a/ext/stringio/stringio.gemspec
+++ b/ext/stringio/stringio.gemspec
@@ -4,7 +4,7 @@
source_version = ["", "ext/stringio/"].find do |dir|
begin
break File.open(File.join(__dir__, "#{dir}stringio.c")) {|f|
- f.gets("\nSTRINGIO_VERSION ")
+ f.gets("\n#define STRINGIO_VERSION ")
f.gets[/\s*"(.+)"/, 1]
}
rescue Errno::ENOENT
@@ -14,6 +14,7 @@ Gem::Specification.new do |s|
s.name = "stringio"
s.version = source_version
+ s.required_rubygems_version = Gem::Requirement.new(">= 2.6")
s.require_paths = ["lib"]
s.authors = ["Nobu Nakada", "Charles Oliver Nutter"]
s.description = "Pseudo `IO` class from/to `String`."
@@ -21,22 +22,15 @@ Gem::Specification.new do |s|
s.files = ["README.md"]
jruby = true if Gem::Platform.new('java') =~ s.platform or RUBY_ENGINE == 'jruby'
if jruby
- s.require_paths = "lib/java"
- s.files += ["lib/java/stringio.rb", "lib/java/stringio.jar"]
+ s.files += ["lib/stringio.rb", "lib/stringio.jar"]
s.platform = "java"
else
s.extensions = ["ext/stringio/extconf.rb"]
s.files += ["ext/stringio/extconf.rb", "ext/stringio/stringio.c"]
end
-
- s.extra_rdoc_files = [
- ".document", ".rdoc_options", "COPYING", "LICENSE.txt",
- "NEWS.md", "README.md", "docs/io.rb", "ext/stringio/.document",
- ]
-
s.homepage = "https://github.com/ruby/stringio"
s.licenses = ["Ruby", "BSD-2-Clause"]
- s.required_ruby_version = ">= 2.7"
+ s.required_ruby_version = ">= 2.5"
s.summary = "Pseudo IO on String"
# s.cert_chain = %w[certs/nobu.pem]
diff --git a/ext/strscan/depend b/ext/strscan/depend
index 8dbae206d4..8fe3cb23d9 100644
--- a/ext/strscan/depend
+++ b/ext/strscan/depend
@@ -52,7 +52,6 @@ strscan.o: $(hdrdir)/ruby/internal/attr/noexcept.h
strscan.o: $(hdrdir)/ruby/internal/attr/noinline.h
strscan.o: $(hdrdir)/ruby/internal/attr/nonnull.h
strscan.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-strscan.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
strscan.o: $(hdrdir)/ruby/internal/attr/pure.h
strscan.o: $(hdrdir)/ruby/internal/attr/restrict.h
strscan.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ strscan.o: $(hdrdir)/ruby/internal/intern/enumerator.h
strscan.o: $(hdrdir)/ruby/internal/intern/error.h
strscan.o: $(hdrdir)/ruby/internal/intern/eval.h
strscan.o: $(hdrdir)/ruby/internal/intern/file.h
+strscan.o: $(hdrdir)/ruby/internal/intern/gc.h
strscan.o: $(hdrdir)/ruby/internal/intern/hash.h
strscan.o: $(hdrdir)/ruby/internal/intern/io.h
strscan.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,12 +152,12 @@ strscan.o: $(hdrdir)/ruby/internal/memory.h
strscan.o: $(hdrdir)/ruby/internal/method.h
strscan.o: $(hdrdir)/ruby/internal/module.h
strscan.o: $(hdrdir)/ruby/internal/newobj.h
+strscan.o: $(hdrdir)/ruby/internal/rgengc.h
strscan.o: $(hdrdir)/ruby/internal/scan_args.h
strscan.o: $(hdrdir)/ruby/internal/special_consts.h
strscan.o: $(hdrdir)/ruby/internal/static_assert.h
strscan.o: $(hdrdir)/ruby/internal/stdalign.h
strscan.o: $(hdrdir)/ruby/internal/stdbool.h
-strscan.o: $(hdrdir)/ruby/internal/stdckdint.h
strscan.o: $(hdrdir)/ruby/internal/symbol.h
strscan.o: $(hdrdir)/ruby/internal/value.h
strscan.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/strscan/extconf.rb b/ext/strscan/extconf.rb
index bd65606a4e..3c311d2364 100644
--- a/ext/strscan/extconf.rb
+++ b/ext/strscan/extconf.rb
@@ -2,8 +2,8 @@
require 'mkmf'
if RUBY_ENGINE == 'ruby'
$INCFLAGS << " -I$(top_srcdir)" if $extmk
- have_func("onig_region_memsize", "ruby.h")
- have_func("rb_reg_onig_match", "ruby.h")
+ have_func("onig_region_memsize(NULL)")
+ have_func("rb_reg_onig_match", "ruby/re.h")
create_makefile 'strscan'
else
File.write('Makefile', dummy_makefile("").join)
diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c
index e272f92249..16d669d8a5 100644
--- a/ext/strscan/strscan.c
+++ b/ext/strscan/strscan.c
@@ -22,7 +22,7 @@ extern size_t onig_region_memsize(const struct re_registers *regs);
#include <stdbool.h>
-#define STRSCAN_VERSION "3.1.1.dev"
+#define STRSCAN_VERSION "3.0.7"
/* =======================================================================
Data Type Definitions
@@ -218,28 +218,16 @@ strscan_s_allocate(VALUE klass)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
* call-seq:
- * StringScanner.new(string, fixed_anchor: false) -> string_scanner
- *
- * Returns a new `StringScanner` object whose [stored string][1]
- * is the given `string`;
- * sets the [fixed-anchor property][10]:
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.string # => "foobarbaz"
- * scanner.fixed_anchor? # => false
- * put_situation(scanner)
- * # Situation:
- * # pos: 0
- * # charpos: 0
- * # rest: "foobarbaz"
- * # rest_size: 9
- * ```
+ * StringScanner.new(string, fixed_anchor: false)
+ * StringScanner.new(string, dup = false)
+ *
+ * Creates a new StringScanner object to scan over the given +string+.
*
+ * If +fixed_anchor+ is +true+, +\A+ always matches the beginning of
+ * the string. Otherwise, +\A+ always matches the current position.
+ *
+ * +dup+ argument is obsolete and not used now.
*/
static VALUE
strscan_initialize(int argc, VALUE *argv, VALUE self)
@@ -278,14 +266,11 @@ check_strscan(VALUE obj)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
* call-seq:
- * dup -> shallow_copy
+ * dup
+ * clone
*
- * Returns a shallow copy of `self`;
- * the [stored string][1] in the copy is the same string as in `self`.
+ * Duplicates a StringScanner object.
*/
static VALUE
strscan_init_copy(VALUE vself, VALUE vorig)
@@ -312,13 +297,10 @@ strscan_init_copy(VALUE vself, VALUE vorig)
======================================================================= */
/*
- * call-seq:
- * StringScanner.must_C_version -> self
+ * call-seq: StringScanner.must_C_version
*
- * Returns +self+; defined for backward compatibility.
+ * This method is defined for backward compatibility.
*/
-
- /* :nodoc: */
static VALUE
strscan_s_mustc(VALUE self)
{
@@ -326,30 +308,7 @@ strscan_s_mustc(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * reset -> self
- *
- * Sets both [byte position][2] and [character position][7] to zero,
- * and clears [match values][9];
- * returns +self+:
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.exist?(/bar/) # => 6
- * scanner.reset # => #<StringScanner 0/9 @ "fooba...">
- * put_situation(scanner)
- * # Situation:
- * # pos: 0
- * # charpos: 0
- * # rest: "foobarbaz"
- * # rest_size: 9
- * # => nil
- * match_values_cleared?(scanner) # => true
- * ```
- *
+ * Reset the scan pointer (index 0) and clear matching data.
*/
static VALUE
strscan_reset(VALUE self)
@@ -363,9 +322,11 @@ strscan_reset(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- * :include: strscan/methods/terminate.md
+ * call-seq:
+ * terminate
+ * clear
+ *
+ * Sets the scan pointer to the end of the string and clear matching data.
*/
static VALUE
strscan_terminate(VALUE self)
@@ -379,13 +340,9 @@ strscan_terminate(VALUE self)
}
/*
- * call-seq:
- * clear -> self
- *
- * This method is obsolete; use the equivalent method StringScanner#terminate.
+ * Equivalent to #terminate.
+ * This method is obsolete; use #terminate instead.
*/
-
- /* :nodoc: */
static VALUE
strscan_clear(VALUE self)
{
@@ -394,21 +351,7 @@ strscan_clear(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * string -> stored_string
- *
- * Returns the [stored string][1]:
- *
- * ```
- * scanner = StringScanner.new('foobar')
- * scanner.string # => "foobar"
- * scanner.concat('baz')
- * scanner.string # => "foobarbaz"
- * ```
- *
+ * Returns the string being scanned.
*/
static VALUE
strscan_get_string(VALUE self)
@@ -420,39 +363,10 @@ strscan_get_string(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * string = other_string -> other_string
- *
- * Replaces the [stored string][1] with the given `other_string`:
- *
- * - Sets both [positions][11] to zero.
- * - Clears [match values][9].
- * - Returns `other_string`.
- *
- * ```
- * scanner = StringScanner.new('foobar')
- * scanner.scan(/foo/)
- * put_situation(scanner)
- * # Situation:
- * # pos: 3
- * # charpos: 3
- * # rest: "bar"
- * # rest_size: 3
- * match_values_cleared?(scanner) # => false
- *
- * scanner.string = 'baz' # => "baz"
- * put_situation(scanner)
- * # Situation:
- * # pos: 0
- * # charpos: 0
- * # rest: "baz"
- * # rest_size: 3
- * match_values_cleared?(scanner) # => true
- * ```
+ * call-seq: string=(str)
*
+ * Changes the string being scanned to +str+ and resets the scanner.
+ * Returns +str+.
*/
static VALUE
strscan_set_string(VALUE self, VALUE str)
@@ -467,33 +381,18 @@ strscan_set_string(VALUE self, VALUE str)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
* call-seq:
- * concat(more_string) -> self
- *
- * - Appends the given `more_string`
- * to the [stored string][1].
- * - Returns `self`.
- * - Does not affect the [positions][11]
- * or [match values][9].
- *
- *
- * ```
- * scanner = StringScanner.new('foo')
- * scanner.string # => "foo"
- * scanner.terminate
- * scanner.concat('barbaz') # => #<StringScanner 3/9 "foo" @ "barba...">
- * scanner.string # => "foobarbaz"
- * put_situation(scanner)
- * # Situation:
- * # pos: 3
- * # charpos: 3
- * # rest: "barbaz"
- * # rest_size: 6
- * ```
+ * concat(str)
+ * <<(str)
*
+ * Appends +str+ to the string being scanned.
+ * This method does not affect scan pointer.
+ *
+ * s = StringScanner.new("Fri Dec 12 1975 14:39")
+ * s.scan(/Fri /)
+ * s << " +1000 GMT"
+ * s.string # -> "Fri Dec 12 1975 14:39 +1000 GMT"
+ * s.scan(/Dec/) # -> "Dec"
*/
static VALUE
strscan_concat(VALUE self, VALUE str)
@@ -507,9 +406,18 @@ strscan_concat(VALUE self, VALUE str)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- * :include: strscan/methods/get_pos.md
+ * Returns the byte position of the scan pointer. In the 'reset' position, this
+ * value is zero. In the 'terminated' position (i.e. the string is exhausted),
+ * this value is the bytesize of the string.
+ *
+ * In short, it's a 0-based index into bytes of the string.
+ *
+ * s = StringScanner.new('test string')
+ * s.pos # -> 0
+ * s.scan_until /str/ # -> "test str"
+ * s.pos # -> 8
+ * s.terminate # -> #<StringScanner fin>
+ * s.pos # -> 11
*/
static VALUE
strscan_get_pos(VALUE self)
@@ -521,9 +429,17 @@ strscan_get_pos(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- * :include: strscan/methods/get_charpos.md
+ * Returns the character position of the scan pointer. In the 'reset' position, this
+ * value is zero. In the 'terminated' position (i.e. the string is exhausted),
+ * this value is the size of the string.
+ *
+ * In short, it's a 0-based index into the string.
+ *
+ * s = StringScanner.new("abc\u00e4def\u00f6ghi")
+ * s.charpos # -> 0
+ * s.scan_until(/\u00e4/) # -> "abc\u00E4"
+ * s.pos # -> 5
+ * s.charpos # -> 4
*/
static VALUE
strscan_get_charpos(VALUE self)
@@ -536,9 +452,13 @@ strscan_get_charpos(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- * :include: strscan/methods/set_pos.md
+ * call-seq: pos=(n)
+ *
+ * Sets the byte position of the scan pointer.
+ *
+ * s = StringScanner.new('test string')
+ * s.pos = 7 # -> 7
+ * s.rest # -> "ring"
*/
static VALUE
strscan_set_pos(VALUE self, VALUE v)
@@ -686,6 +606,14 @@ strscan_do_scan(VALUE self, VALUE pattern, int succptr, int getstr, int headonly
{
struct strscanner *p;
+ if (headonly) {
+ if (!RB_TYPE_P(pattern, T_REGEXP)) {
+ StringValue(pattern);
+ }
+ }
+ else {
+ Check_Type(pattern, T_REGEXP);
+ }
GET_SCANNER(self, p);
CLEAR_MATCH_STATUS(p);
@@ -706,25 +634,14 @@ strscan_do_scan(VALUE self, VALUE pattern, int succptr, int getstr, int headonly
}
}
else {
- StringValue(pattern);
rb_enc_check(p->str, pattern);
if (S_RESTLEN(p) < RSTRING_LEN(pattern)) {
return Qnil;
}
-
- if (headonly) {
- if (memcmp(CURPTR(p), RSTRING_PTR(pattern), RSTRING_LEN(pattern)) != 0) {
- return Qnil;
- }
- set_registers(p, RSTRING_LEN(pattern));
- } else {
- long pos = rb_memsearch(RSTRING_PTR(pattern), RSTRING_LEN(pattern),
- CURPTR(p), S_RESTLEN(p), rb_enc_get(pattern));
- if (pos == -1) {
- return Qnil;
- }
- set_registers(p, RSTRING_LEN(pattern) + pos);
+ if (memcmp(CURPTR(p), RSTRING_PTR(pattern), RSTRING_LEN(pattern)) != 0) {
+ return Qnil;
}
+ set_registers(p, RSTRING_LEN(pattern));
}
MATCHED(p);
@@ -745,9 +662,20 @@ strscan_do_scan(VALUE self, VALUE pattern, int succptr, int getstr, int headonly
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- * :include: strscan/methods/scan.md
+ * call-seq: scan(pattern) => String
+ *
+ * Tries to match with +pattern+ at the current position. If there's a match,
+ * the scanner advances the "scan pointer" and returns the matched string.
+ * Otherwise, the scanner returns +nil+.
+ *
+ * s = StringScanner.new('test string')
+ * p s.scan(/\w+/) # -> "test"
+ * p s.scan(/\w+/) # -> nil
+ * p s.scan(/\s+/) # -> " "
+ * p s.scan("str") # -> "str"
+ * p s.scan(/\w+/) # -> "ing"
+ * p s.scan(/./) # -> nil
+ *
*/
static VALUE
strscan_scan(VALUE self, VALUE re)
@@ -756,60 +684,16 @@ strscan_scan(VALUE self, VALUE re)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
+ * call-seq: match?(pattern)
*
- * call-seq:
- * match?(pattern) -> updated_position or nil
- *
- * Attempts to [match][17] the given `pattern`
- * at the beginning of the [target substring][3];
- * does not modify the [positions][11].
- *
- * If the match succeeds:
- *
- * - Sets [match values][9].
- * - Returns the size in bytes of the matched substring.
- *
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.pos = 3
- * scanner.match?(/bar/) => 3
- * put_match_values(scanner)
- * # Basic match values:
- * # matched?: true
- * # matched_size: 3
- * # pre_match: "foo"
- * # matched : "bar"
- * # post_match: "baz"
- * # Captured match values:
- * # size: 1
- * # captures: []
- * # named_captures: {}
- * # values_at: ["bar", nil]
- * # []:
- * # [0]: "bar"
- * # [1]: nil
- * put_situation(scanner)
- * # Situation:
- * # pos: 3
- * # charpos: 3
- * # rest: "barbaz"
- * # rest_size: 6
- * ```
- *
- * If the match fails:
- *
- * - Clears match values.
- * - Returns `nil`.
- * - Does not increment positions.
- *
- * ```
- * scanner.match?(/nope/) # => nil
- * match_values_cleared?(scanner) # => true
- * ```
+ * Tests whether the given +pattern+ is matched from the current scan pointer.
+ * Returns the length of the match, or +nil+. The scan pointer is not advanced.
*
+ * s = StringScanner.new('test string')
+ * p s.match?(/\w+/) # -> 4
+ * p s.match?(/\w+/) # -> 4
+ * p s.match?("test") # -> 4
+ * p s.match?(/\s+/) # -> nil
*/
static VALUE
strscan_match_p(VALUE self, VALUE re)
@@ -818,9 +702,22 @@ strscan_match_p(VALUE self, VALUE re)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- * :include: strscan/methods/skip.md
+ * call-seq: skip(pattern)
+ *
+ * Attempts to skip over the given +pattern+ beginning with the scan pointer.
+ * If it matches, the scan pointer is advanced to the end of the match, and the
+ * length of the match is returned. Otherwise, +nil+ is returned.
+ *
+ * It's similar to #scan, but without returning the matched string.
+ *
+ * s = StringScanner.new('test string')
+ * p s.skip(/\w+/) # -> 4
+ * p s.skip(/\w+/) # -> nil
+ * p s.skip(/\s+/) # -> 1
+ * p s.skip("st") # -> 2
+ * p s.skip(/\w+/) # -> 4
+ * p s.skip(/./) # -> nil
+ *
*/
static VALUE
strscan_skip(VALUE self, VALUE re)
@@ -829,59 +726,19 @@ strscan_skip(VALUE self, VALUE re)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
+ * call-seq: check(pattern)
*
- * call-seq:
- * check(pattern) -> matched_substring or nil
- *
- * Attempts to [match][17] the given `pattern`
- * at the beginning of the [target substring][3];
- * does not modify the [positions][11].
- *
- * If the match succeeds:
- *
- * - Returns the matched substring.
- * - Sets all [match values][9].
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.pos = 3
- * scanner.check('bar') # => "bar"
- * put_match_values(scanner)
- * # Basic match values:
- * # matched?: true
- * # matched_size: 3
- * # pre_match: "foo"
- * # matched : "bar"
- * # post_match: "baz"
- * # Captured match values:
- * # size: 1
- * # captures: []
- * # named_captures: {}
- * # values_at: ["bar", nil]
- * # []:
- * # [0]: "bar"
- * # [1]: nil
- * # => 0..1
- * put_situation(scanner)
- * # Situation:
- * # pos: 3
- * # charpos: 3
- * # rest: "barbaz"
- * # rest_size: 6
- * ```
- *
- * If the match fails:
- *
- * - Returns `nil`.
- * - Clears all [match values][9].
- *
- * ```
- * scanner.check(/nope/) # => nil
- * match_values_cleared?(scanner) # => true
- * ```
+ * This returns the value that #scan would return, without advancing the scan
+ * pointer. The match register is affected, though.
+ *
+ * s = StringScanner.new("Fri Dec 12 1975 14:39")
+ * s.check /Fri/ # -> "Fri"
+ * s.pos # -> 0
+ * s.matched # -> "Fri"
+ * s.check /12/ # -> nil
+ * s.matched # -> nil
*
+ * Mnemonic: it "checks" to see whether a #scan will return a value.
*/
static VALUE
strscan_check(VALUE self, VALUE re)
@@ -890,24 +747,15 @@ strscan_check(VALUE self, VALUE re)
}
/*
- * call-seq:
- * scan_full(pattern, advance_pointer_p, return_string_p) -> matched_substring or nil
- *
- * Equivalent to one of the following:
+ * call-seq: scan_full(pattern, advance_pointer_p, return_string_p)
*
- * - +advance_pointer_p+ +true+:
- *
- * - +return_string_p+ +true+: StringScanner#scan(pattern).
- * - +return_string_p+ +false+: StringScanner#skip(pattern).
- *
- * - +advance_pointer_p+ +false+:
- *
- * - +return_string_p+ +true+: StringScanner#check(pattern).
- * - +return_string_p+ +false+: StringScanner#match?(pattern).
+ * Tests whether the given +pattern+ is matched from the current scan pointer.
+ * Advances the scan pointer if +advance_pointer_p+ is true.
+ * Returns the matched string if +return_string_p+ is true.
+ * The match register is affected.
*
+ * "full" means "#scan with full parameters".
*/
-
- /* :nodoc: */
static VALUE
strscan_scan_full(VALUE self, VALUE re, VALUE s, VALUE f)
{
@@ -915,9 +763,16 @@ strscan_scan_full(VALUE self, VALUE re, VALUE s, VALUE f)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- * :include: strscan/methods/scan_until.md
+ * call-seq: scan_until(pattern)
+ *
+ * Scans the string _until_ the +pattern+ is matched. Returns the substring up
+ * to and including the end of the match, advancing the scan pointer to that
+ * location. If there is no match, +nil+ is returned.
+ *
+ * s = StringScanner.new("Fri Dec 12 1975 14:39")
+ * s.scan_until(/1/) # -> "Fri Dec 1"
+ * s.pre_match # -> "Fri Dec "
+ * s.scan_until(/XYZ/) # -> nil
*/
static VALUE
strscan_scan_until(VALUE self, VALUE re)
@@ -926,61 +781,17 @@ strscan_scan_until(VALUE self, VALUE re)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
+ * call-seq: exist?(pattern)
*
- * call-seq:
- * exist?(pattern) -> byte_offset or nil
- *
- * Attempts to [match][17] the given `pattern`
- * anywhere (at any [position][2])
- * n the [target substring][3];
- * does not modify the [positions][11].
- *
- * If the match succeeds:
- *
- * - Returns a byte offset:
- * the distance in bytes between the current [position][2]
- * and the end of the matched substring.
- * - Sets all [match values][9].
- *
- * ```
- * scanner = StringScanner.new('foobarbazbatbam')
- * scanner.pos = 6
- * scanner.exist?(/bat/) # => 6
- * put_match_values(scanner)
- * # Basic match values:
- * # matched?: true
- * # matched_size: 3
- * # pre_match: "foobarbaz"
- * # matched : "bat"
- * # post_match: "bam"
- * # Captured match values:
- * # size: 1
- * # captures: []
- * # named_captures: {}
- * # values_at: ["bat", nil]
- * # []:
- * # [0]: "bat"
- * # [1]: nil
- * put_situation(scanner)
- * # Situation:
- * # pos: 6
- * # charpos: 6
- * # rest: "bazbatbam"
- * # rest_size: 9
- * ```
- *
- * If the match fails:
- *
- * - Returns `nil`.
- * - Clears all [match values][9].
- *
- * ```
- * scanner.exist?(/nope/) # => nil
- * match_values_cleared?(scanner) # => true
- * ```
+ * Looks _ahead_ to see if the +pattern+ exists _anywhere_ in the string,
+ * without advancing the scan pointer. This predicates whether a #scan_until
+ * will return a value.
*
+ * s = StringScanner.new('test string')
+ * s.exist? /s/ # -> 3
+ * s.scan /test/ # -> "test"
+ * s.exist? /s/ # -> 2
+ * s.exist? /e/ # -> nil
*/
static VALUE
strscan_exist_p(VALUE self, VALUE re)
@@ -989,9 +800,20 @@ strscan_exist_p(VALUE self, VALUE re)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- * :include: strscan/methods/skip_until.md
+ * call-seq: skip_until(pattern)
+ *
+ * Advances the scan pointer until +pattern+ is matched and consumed. Returns
+ * the number of bytes advanced, or +nil+ if no match was found.
+ *
+ * Look ahead to match +pattern+, and advance the scan pointer to the _end_
+ * of the match. Return the number of characters advanced, or +nil+ if the
+ * match was unsuccessful.
+ *
+ * It's similar to #scan_until, but without returning the intervening string.
+ *
+ * s = StringScanner.new("Fri Dec 12 1975 14:39")
+ * s.skip_until /12/ # -> 10
+ * s #
*/
static VALUE
strscan_skip_until(VALUE self, VALUE re)
@@ -1000,61 +822,17 @@ strscan_skip_until(VALUE self, VALUE re)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
+ * call-seq: check_until(pattern)
*
- * call-seq:
- * check_until(pattern) -> substring or nil
- *
- * Attempts to [match][17] the given `pattern`
- * anywhere (at any [position][2])
- * in the [target substring][3];
- * does not modify the [positions][11].
- *
- * If the match succeeds:
- *
- * - Sets all [match values][9].
- * - Returns the matched substring,
- * which extends from the current [position][2]
- * to the end of the matched substring.
- *
- * ```
- * scanner = StringScanner.new('foobarbazbatbam')
- * scanner.pos = 6
- * scanner.check_until(/bat/) # => "bazbat"
- * put_match_values(scanner)
- * # Basic match values:
- * # matched?: true
- * # matched_size: 3
- * # pre_match: "foobarbaz"
- * # matched : "bat"
- * # post_match: "bam"
- * # Captured match values:
- * # size: 1
- * # captures: []
- * # named_captures: {}
- * # values_at: ["bat", nil]
- * # []:
- * # [0]: "bat"
- * # [1]: nil
- * put_situation(scanner)
- * # Situation:
- * # pos: 6
- * # charpos: 6
- * # rest: "bazbatbam"
- * # rest_size: 9
- * ```
- *
- * If the match fails:
- *
- * - Clears all [match values][9].
- * - Returns `nil`.
- *
- * ```
- * scanner.check_until(/nope/) # => nil
- * match_values_cleared?(scanner) # => true
- * ```
+ * This returns the value that #scan_until would return, without advancing the
+ * scan pointer. The match register is affected, though.
*
+ * s = StringScanner.new("Fri Dec 12 1975 14:39")
+ * s.check_until /12/ # -> "Fri Dec 12"
+ * s.pos # -> 0
+ * s.matched # -> 12
+ *
+ * Mnemonic: it "checks" to see whether a #scan_until will return a value.
*/
static VALUE
strscan_check_until(VALUE self, VALUE re)
@@ -1063,24 +841,14 @@ strscan_check_until(VALUE self, VALUE re)
}
/*
- * call-seq:
- * search_full(pattern, advance_pointer_p, return_string_p) -> matched_substring or position_delta or nil
- *
- * Equivalent to one of the following:
- *
- * - +advance_pointer_p+ +true+:
- *
- * - +return_string_p+ +true+: StringScanner#scan_until(pattern).
- * - +return_string_p+ +false+: StringScanner#skip_until(pattern).
- *
- * - +advance_pointer_p+ +false+:
- *
- * - +return_string_p+ +true+: StringScanner#check_until(pattern).
- * - +return_string_p+ +false+: StringScanner#exist?(pattern).
+ * call-seq: search_full(pattern, advance_pointer_p, return_string_p)
*
+ * Scans the string _until_ the +pattern+ is matched.
+ * Advances the scan pointer if +advance_pointer_p+, otherwise not.
+ * Returns the matched string if +return_string_p+ is true, otherwise
+ * returns the number of bytes advanced.
+ * This method does affect the match register.
*/
-
- /* :nodoc: */
static VALUE
strscan_search_full(VALUE self, VALUE re, VALUE s, VALUE f)
{
@@ -1100,9 +868,17 @@ adjust_registers_to_matched(struct strscanner *p)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- * :include: strscan/methods/getch.md
+ * Scans one character and returns it.
+ * This method is multibyte character sensitive.
+ *
+ * s = StringScanner.new("ab")
+ * s.getch # => "a"
+ * s.getch # => "b"
+ * s.getch # => nil
+ *
+ * s = StringScanner.new("\244\242".force_encoding("euc-jp"))
+ * s.getch # => "\x{A4A2}" # Japanese hira-kana "A" in EUC-JP
+ * s.getch # => nil
*/
static VALUE
strscan_getch(VALUE self)
@@ -1127,54 +903,19 @@ strscan_getch(VALUE self)
}
/*
- * call-seq:
- * scan_byte -> integer_byte
- *
- * Scans one byte and returns it as an integer.
+ * Scans one byte and returns it.
* This method is not multibyte character sensitive.
* See also: #getch.
*
- */
-static VALUE
-strscan_scan_byte(VALUE self)
-{
- struct strscanner *p;
-
- GET_SCANNER(self, p);
- CLEAR_MATCH_STATUS(p);
- if (EOS_P(p))
- return Qnil;
-
- VALUE byte = INT2FIX((unsigned char)*CURPTR(p));
- p->prev = p->curr;
- p->curr++;
- MATCHED(p);
- adjust_registers_to_matched(p);
- return byte;
-}
-
-/*
- * Peeks at the current byte and returns it as an integer.
- *
* s = StringScanner.new('ab')
- * s.peek_byte # => 97
- */
-static VALUE
-strscan_peek_byte(VALUE self)
-{
- struct strscanner *p;
-
- GET_SCANNER(self, p);
- if (EOS_P(p))
- return Qnil;
-
- return INT2FIX((unsigned char)*CURPTR(p));
-}
-
-/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- * :include: strscan/methods/get_byte.md
+ * s.get_byte # => "a"
+ * s.get_byte # => "b"
+ * s.get_byte # => nil
+ *
+ * s = StringScanner.new("\244\242".force_encoding("euc-jp"))
+ * s.get_byte # => "\xA4"
+ * s.get_byte # => "\xA2"
+ * s.get_byte # => nil
*/
static VALUE
strscan_get_byte(VALUE self)
@@ -1196,14 +937,9 @@ strscan_get_byte(VALUE self)
}
/*
- * call-seq:
- * getbyte
- *
* Equivalent to #get_byte.
* This method is obsolete; use #get_byte instead.
*/
-
- /* :nodoc: */
static VALUE
strscan_getbyte(VALUE self)
{
@@ -1212,22 +948,14 @@ strscan_getbyte(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
+ * call-seq: peek(len)
*
- * call-seq:
- * peek(length) -> substring
+ * Extracts a string corresponding to <tt>string[pos,len]</tt>, without
+ * advancing the scan pointer.
*
- * Returns the substring `string[pos, length]`;
- * does not update [match values][9] or [positions][11]:
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.pos = 3
- * scanner.peek(3) # => "bar"
- * scanner.terminate
- * scanner.peek(3) # => ""
- * ```
+ * s = StringScanner.new('test string')
+ * s.peek(7) # => "test st"
+ * s.peek(7) # => "test st"
*
*/
static VALUE
@@ -1247,14 +975,9 @@ strscan_peek(VALUE self, VALUE vlen)
}
/*
- * call-seq:
- * peep
- *
* Equivalent to #peek.
* This method is obsolete; use #peek instead.
*/
-
- /* :nodoc: */
static VALUE
strscan_peep(VALUE self, VALUE vlen)
{
@@ -1263,42 +986,15 @@ strscan_peep(VALUE self, VALUE vlen)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * unscan -> self
- *
- * Sets the [position][2] to its value previous to the recent successful
- * [match][17] attempt:
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.scan(/foo/)
- * put_situation(scanner)
- * # Situation:
- * # pos: 3
- * # charpos: 3
- * # rest: "barbaz"
- * # rest_size: 6
- * scanner.unscan
- * # => #<StringScanner 0/9 @ "fooba...">
- * put_situation(scanner)
- * # Situation:
- * # pos: 0
- * # charpos: 0
- * # rest: "foobarbaz"
- * # rest_size: 9
- * ```
- *
- * Raises an exception if match values are clear:
- *
- * ```
- * scanner.scan(/nope/) # => nil
- * match_values_cleared?(scanner) # => true
- * scanner.unscan # Raises StringScanner::Error.
- * ```
+ * Sets the scan pointer to the previous position. Only one previous position is
+ * remembered, and it changes with each scanning operation.
*
+ * s = StringScanner.new('test string')
+ * s.scan(/\w+/) # => "test"
+ * s.unscan
+ * s.scan(/../) # => "te"
+ * s.scan(/\d/) # => nil
+ * s.unscan # ScanError: unscan failed: previous match record not exist
*/
static VALUE
strscan_unscan(VALUE self)
@@ -1314,37 +1010,16 @@ strscan_unscan(VALUE self)
}
/*
- *
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * beginning_of_line? -> true or false
- *
- * Returns whether the [position][2] is at the beginning of a line;
- * that is, at the beginning of the [stored string][1]
- * or immediately after a newline:
- *
- * scanner = StringScanner.new(MULTILINE_TEXT)
- * scanner.string
- * # => "Go placidly amid the noise and haste,\nand remember what peace there may be in silence.\n"
- * scanner.pos # => 0
- * scanner.beginning_of_line? # => true
- *
- * scanner.scan_until(/,/) # => "Go placidly amid the noise and haste,"
- * scanner.beginning_of_line? # => false
- *
- * scanner.scan(/\n/) # => "\n"
- * scanner.beginning_of_line? # => true
- *
- * scanner.terminate
- * scanner.beginning_of_line? # => true
- *
- * scanner.concat('x')
- * scanner.terminate
- * scanner.beginning_of_line? # => false
- *
- * StringScanner#bol? is an alias for StringScanner#beginning_of_line?.
+ * Returns +true+ if and only if the scan pointer is at the beginning of the line.
+ *
+ * s = StringScanner.new("test\ntest\n")
+ * s.bol? # => true
+ * s.scan(/te/)
+ * s.bol? # => false
+ * s.scan(/st\n/)
+ * s.bol? # => true
+ * s.terminate
+ * s.bol? # => true
*/
static VALUE
strscan_bol_p(VALUE self)
@@ -1358,24 +1033,14 @@ strscan_bol_p(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * eos? -> true or false
- *
- * Returns whether the [position][2]
- * is at the end of the [stored string][1]:
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.eos? # => false
- * pos = 3
- * scanner.eos? # => false
- * scanner.terminate
- * scanner.eos? # => true
- * ```
+ * Returns +true+ if the scan pointer is at the end of the string.
*
+ * s = StringScanner.new('test string')
+ * p s.eos? # => false
+ * s.scan(/test/)
+ * p s.eos? # => false
+ * s.terminate
+ * p s.eos? # => true
*/
static VALUE
strscan_eos_p(VALUE self)
@@ -1387,14 +1052,9 @@ strscan_eos_p(VALUE self)
}
/*
- * call-seq:
- * empty?
- *
* Equivalent to #eos?.
* This method is obsolete, use #eos? instead.
*/
-
- /* :nodoc: */
static VALUE
strscan_empty_p(VALUE self)
{
@@ -1403,9 +1063,6 @@ strscan_empty_p(VALUE self)
}
/*
- * call-seq:
- * rest?
- *
* Returns true if and only if there is more data in the string. See #eos?.
* This method is obsolete; use #eos? instead.
*
@@ -1414,8 +1071,6 @@ strscan_empty_p(VALUE self)
* s.eos? # => false
* s.rest? # => true
*/
-
- /* :nodoc: */
static VALUE
strscan_rest_p(VALUE self)
{
@@ -1426,26 +1081,13 @@ strscan_rest_p(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * matched? -> true or false
- *
- * Returns `true` of the most recent [match attempt][17] was successful,
- * `false` otherwise;
- * see [Basic Matched Values][18]:
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.matched? # => false
- * scanner.pos = 3
- * scanner.exist?(/baz/) # => 6
- * scanner.matched? # => true
- * scanner.exist?(/nope/) # => nil
- * scanner.matched? # => false
- * ```
+ * Returns +true+ if and only if the last match was successful.
*
+ * s = StringScanner.new('test string')
+ * s.match?(/\w+/) # => 4
+ * s.matched? # => true
+ * s.match?(/\d+/) # => nil
+ * s.matched? # => false
*/
static VALUE
strscan_matched_p(VALUE self)
@@ -1457,27 +1099,11 @@ strscan_matched_p(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * matched -> matched_substring or nil
- *
- * Returns the matched substring from the most recent [match][17] attempt
- * if it was successful,
- * or `nil` otherwise;
- * see [Basic Matched Values][18]:
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.matched # => nil
- * scanner.pos = 3
- * scanner.match?(/bar/) # => 3
- * scanner.matched # => "bar"
- * scanner.match?(/nope/) # => nil
- * scanner.matched # => nil
- * ```
+ * Returns the last matched string.
*
+ * s = StringScanner.new('test string')
+ * s.match?(/\w+/) # -> 4
+ * s.matched # -> "test"
*/
static VALUE
strscan_matched(VALUE self)
@@ -1492,29 +1118,15 @@ strscan_matched(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * matched_size -> substring_size or nil
- *
- * Returns the size (in bytes) of the matched substring
- * from the most recent match [match attempt][17] if it was successful,
- * or `nil` otherwise;
- * see [Basic Matched Values][18]:
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.matched_size # => nil
- *
- * pos = 3
- * scanner.exist?(/baz/) # => 9
- * scanner.matched_size # => 3
- *
- * scanner.exist?(/nope/) # => nil
- * scanner.matched_size # => nil
- * ```
+ * Returns the size of the most recent match in bytes, or +nil+ if there
+ * was no recent match. This is different than <tt>matched.size</tt>,
+ * which will return the size in characters.
*
+ * s = StringScanner.new('test string')
+ * s.check /\w+/ # -> "test"
+ * s.matched_size # -> 4
+ * s.check /\d+/ # -> nil
+ * s.matched_size # -> nil
*/
static VALUE
strscan_matched_size(VALUE self)
@@ -1545,75 +1157,30 @@ name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name
}
/*
- *
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * [](specifier) -> substring or nil
- *
- * Returns a captured substring or `nil`;
- * see [Captured Match Values][13].
- *
- * When there are captures:
- *
- * ```
- * scanner = StringScanner.new('Fri Dec 12 1975 14:39')
- * scanner.scan(/(?<wday>\w+) (?<month>\w+) (?<day>\d+) /)
- * ```
- *
- * - `specifier` zero: returns the entire matched substring:
- *
- * ```
- * scanner[0] # => "Fri Dec 12 "
- * scanner.pre_match # => ""
- * scanner.post_match # => "1975 14:39"
- * ```
- *
- * - `specifier` positive integer. returns the `n`th capture, or `nil` if out of range:
- *
- * ```
- * scanner[1] # => "Fri"
- * scanner[2] # => "Dec"
- * scanner[3] # => "12"
- * scanner[4] # => nil
- * ```
- *
- * - `specifier` negative integer. counts backward from the last subgroup:
- *
- * ```
- * scanner[-1] # => "12"
- * scanner[-4] # => "Fri Dec 12 "
- * scanner[-5] # => nil
- * ```
- *
- * - `specifier` symbol or string. returns the named subgroup, or `nil` if no such:
- *
- * ```
- * scanner[:wday] # => "Fri"
- * scanner['wday'] # => "Fri"
- * scanner[:month] # => "Dec"
- * scanner[:day] # => "12"
- * scanner[:nope] # => nil
- * ```
- *
- * When there are no captures, only `[0]` returns non-`nil`:
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.exist?(/bar/)
- * scanner[0] # => "bar"
- * scanner[1] # => nil
- * ```
- *
- * For a failed match, even `[0]` returns `nil`:
- *
- * ```
- * scanner.scan(/nope/) # => nil
- * scanner[0] # => nil
- * scanner[1] # => nil
- * ```
- *
+ * call-seq: [](n)
+ *
+ * Returns the n-th subgroup in the most recent match.
+ *
+ * s = StringScanner.new("Fri Dec 12 1975 14:39")
+ * s.scan(/(\w+) (\w+) (\d+) /) # -> "Fri Dec 12 "
+ * s[0] # -> "Fri Dec 12 "
+ * s[1] # -> "Fri"
+ * s[2] # -> "Dec"
+ * s[3] # -> "12"
+ * s.post_match # -> "1975 14:39"
+ * s.pre_match # -> ""
+ *
+ * s.reset
+ * s.scan(/(?<wday>\w+) (?<month>\w+) (?<day>\d+) /) # -> "Fri Dec 12 "
+ * s[0] # -> "Fri Dec 12 "
+ * s[1] # -> "Fri"
+ * s[2] # -> "Dec"
+ * s[3] # -> "12"
+ * s[:wday] # -> "Fri"
+ * s[:month] # -> "Dec"
+ * s[:day] # -> "12"
+ * s.post_match # -> "1975 14:39"
+ * s.pre_match # -> ""
*/
static VALUE
strscan_aref(VALUE self, VALUE idx)
@@ -1650,28 +1217,14 @@ strscan_aref(VALUE self, VALUE idx)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * size -> captures_count
+ * call-seq: size
*
- * Returns the count of captures if the most recent match attempt succeeded, `nil` otherwise;
- * see [Captures Match Values][13]:
- *
- * ```
- * scanner = StringScanner.new('Fri Dec 12 1975 14:39')
- * scanner.size # => nil
- *
- * pattern = /(?<wday>\w+) (?<month>\w+) (?<day>\d+) /
- * scanner.match?(pattern)
- * scanner.values_at(*0..scanner.size) # => ["Fri Dec 12 ", "Fri", "Dec", "12", nil]
- * scanner.size # => 4
- *
- * scanner.match?(/nope/) # => nil
- * scanner.size # => nil
- * ```
+ * Returns the amount of subgroups in the most recent match.
+ * The full match counts as a subgroup.
*
+ * s = StringScanner.new("Fri Dec 12 1975 14:39")
+ * s.scan(/(\w+) (\w+) (\d+) /) # -> "Fri Dec 12 "
+ * s.size # -> 4
*/
static VALUE
strscan_size(VALUE self)
@@ -1684,30 +1237,16 @@ strscan_size(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * captures -> substring_array or nil
- *
- * Returns the array of [captured match values][13] at indexes `(1..)`
- * if the most recent match attempt succeeded, or `nil` otherwise:
- *
- * ```
- * scanner = StringScanner.new('Fri Dec 12 1975 14:39')
- * scanner.captures # => nil
- *
- * scanner.exist?(/(?<wday>\w+) (?<month>\w+) (?<day>\d+) /)
- * scanner.captures # => ["Fri", "Dec", "12"]
- * scanner.values_at(*0..4) # => ["Fri Dec 12 ", "Fri", "Dec", "12", nil]
+ * call-seq: captures
*
- * scanner.exist?(/Fri/)
- * scanner.captures # => []
- *
- * scanner.scan(/nope/)
- * scanner.captures # => nil
- * ```
+ * Returns the subgroups in the most recent match (not including the full match).
+ * If nothing was priorly matched, it returns nil.
*
+ * s = StringScanner.new("Fri Dec 12 1975 14:39")
+ * s.scan(/(\w+) (\w+) (\d+) /) # -> "Fri Dec 12 "
+ * s.captures # -> ["Fri", "Dec", "12"]
+ * s.scan(/(\w+) (\w+) (\d+) /) # -> nil
+ * s.captures # -> nil
*/
static VALUE
strscan_captures(VALUE self)
@@ -1723,13 +1262,9 @@ strscan_captures(VALUE self)
new_ary = rb_ary_new2(num_regs);
for (i = 1; i < num_regs; i++) {
- VALUE str;
- if (p->regs.beg[i] == -1)
- str = Qnil;
- else
- str = extract_range(p,
- adjust_register_position(p, p->regs.beg[i]),
- adjust_register_position(p, p->regs.end[i]));
+ VALUE str = extract_range(p,
+ adjust_register_position(p, p->regs.beg[i]),
+ adjust_register_position(p, p->regs.end[i]));
rb_ary_push(new_ary, str);
}
@@ -1737,25 +1272,17 @@ strscan_captures(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * values_at(*specifiers) -> array_of_captures or nil
- *
- * Returns an array of captured substrings, or `nil` of none.
+ * call-seq:
+ * scanner.values_at( i1, i2, ... iN ) -> an_array
*
- * For each `specifier`, the returned substring is `[specifier]`;
- * see #[].
- *
- * ```
- * scanner = StringScanner.new('Fri Dec 12 1975 14:39')
- * pattern = /(?<wday>\w+) (?<month>\w+) (?<day>\d+) /
- * scanner.match?(pattern)
- * scanner.values_at(*0..3) # => ["Fri Dec 12 ", "Fri", "Dec", "12"]
- * scanner.values_at(*%i[wday month day]) # => ["Fri", "Dec", "12"]
- * ```
+ * Returns the subgroups in the most recent match at the given indices.
+ * If nothing was priorly matched, it returns nil.
*
+ * s = StringScanner.new("Fri Dec 12 1975 14:39")
+ * s.scan(/(\w+) (\w+) (\d+) /) # -> "Fri Dec 12 "
+ * s.values_at 0, -1, 5, 2 # -> ["Fri Dec 12 ", "12", nil, "Dec"]
+ * s.scan(/(\w+) (\w+) (\d+) /) # -> nil
+ * s.values_at 0, -1, 5, 2 # -> nil
*/
static VALUE
@@ -1777,29 +1304,13 @@ strscan_values_at(int argc, VALUE *argv, VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * pre_match -> substring
- *
- * Returns the substring that precedes the matched substring
- * from the most recent match attempt if it was successful,
- * or `nil` otherwise;
- * see [Basic Match Values][18]:
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.pre_match # => nil
- *
- * scanner.pos = 3
- * scanner.exist?(/baz/) # => 6
- * scanner.pre_match # => "foobar" # Substring of entire string, not just target string.
- *
- * scanner.exist?(/nope/) # => nil
- * scanner.pre_match # => nil
- * ```
+ * Returns the <i><b>pre</b>-match</i> (in the regular expression sense) of the last scan.
*
+ * s = StringScanner.new('test string')
+ * s.scan(/\w+/) # -> "test"
+ * s.scan(/\s+/) # -> " "
+ * s.pre_match # -> "test"
+ * s.post_match # -> "string"
*/
static VALUE
strscan_pre_match(VALUE self)
@@ -1814,29 +1325,13 @@ strscan_pre_match(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * post_match -> substring
- *
- * Returns the substring that follows the matched substring
- * from the most recent match attempt if it was successful,
- * or `nil` otherwise;
- * see [Basic Match Values][18]:
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.post_match # => nil
- *
- * scanner.pos = 3
- * scanner.match?(/bar/) # => 3
- * scanner.post_match # => "baz"
- *
- * scanner.match?(/nope/) # => nil
- * scanner.post_match # => nil
- * ```
+ * Returns the <i><b>post</b>-match</i> (in the regular expression sense) of the last scan.
*
+ * s = StringScanner.new('test string')
+ * s.scan(/\w+/) # -> "test"
+ * s.scan(/\s+/) # -> " "
+ * s.pre_match # -> "test"
+ * s.post_match # -> "string"
*/
static VALUE
strscan_post_match(VALUE self)
@@ -1851,24 +1346,8 @@ strscan_post_match(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * rest -> target_substring
- *
- * Returns the 'rest' of the [stored string][1] (all after the current [position][2]),
- * which is the [target substring][3]:
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.rest # => "foobarbaz"
- * scanner.pos = 3
- * scanner.rest # => "barbaz"
- * scanner.terminate
- * scanner.rest # => ""
- * ```
- *
+ * Returns the "rest" of the string (i.e. everything after the scan pointer).
+ * If there is no more data (eos? = true), it returns <tt>""</tt>.
*/
static VALUE
strscan_rest(VALUE self)
@@ -1883,26 +1362,7 @@ strscan_rest(VALUE self)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * rest_size -> integer
- *
- * Returns the size (in bytes) of the #rest of the [stored string][1]:
- *
- * ```
- * scanner = StringScanner.new('foobarbaz')
- * scanner.rest # => "foobarbaz"
- * scanner.rest_size # => 9
- * scanner.pos = 3
- * scanner.rest # => "barbaz"
- * scanner.rest_size # => 6
- * scanner.terminate
- * scanner.rest # => ""
- * scanner.rest_size # => 0
- * ```
- *
+ * <tt>s.rest_size</tt> is equivalent to <tt>s.rest.size</tt>.
*/
static VALUE
strscan_rest_size(VALUE self)
@@ -1919,14 +1379,9 @@ strscan_rest_size(VALUE self)
}
/*
- * call-seq:
- * restsize
- *
* <tt>s.restsize</tt> is equivalent to <tt>s.rest_size</tt>.
* This method is obsolete; use #rest_size instead.
*/
-
- /* :nodoc: */
static VALUE
strscan_restsize(VALUE self)
{
@@ -1937,39 +1392,15 @@ strscan_restsize(VALUE self)
#define INSPECT_LENGTH 5
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
- * call-seq:
- * inspect -> string
- *
- * Returns a string representation of `self` that may show:
- *
- * 1. The current [position][2].
- * 2. The size (in bytes) of the [stored string][1].
- * 3. The substring preceding the current position.
- * 4. The substring following the current position (which is also the [target substring][3]).
- *
- * ```
- * scanner = StringScanner.new("Fri Dec 12 1975 14:39")
- * scanner.pos = 11
- * scanner.inspect # => "#<StringScanner 11/21 \"...c 12 \" @ \"1975 ...\">"
- * ```
- *
- * If at beginning-of-string, item 4 above (following substring) is omitted:
- *
- * ```
- * scanner.reset
- * scanner.inspect # => "#<StringScanner 0/21 @ \"Fri D...\">"
- * ```
- *
- * If at end-of-string, all items above are omitted:
- *
- * ```
- * scanner.terminate
- * scanner.inspect # => "#<StringScanner fin>"
- * ```
- *
+ * Returns a string that represents the StringScanner object, showing:
+ * - the current position
+ * - the size of the string
+ * - the characters surrounding the scan pointer
+ *
+ * s = StringScanner.new("Fri Dec 12 1975 14:39")
+ * s.inspect # -> '#<StringScanner 0/21 @ "Fri D...">'
+ * s.scan_until /12/ # -> "Fri Dec 12"
+ * s.inspect # -> '#<StringScanner 10/21 "...ec 12" @ " 1975...">'
*/
static VALUE
strscan_inspect(VALUE self)
@@ -2041,13 +1472,13 @@ inspect2(struct strscanner *p)
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
* call-seq:
- * fixed_anchor? -> true or false
+ * scanner.fixed_anchor? -> true or false
+ *
+ * Whether +scanner+ uses fixed anchor mode or not.
*
- * Returns whether the [fixed-anchor property][10] is set.
+ * If fixed anchor mode is used, +\A+ always matches the beginning of
+ * the string. Otherwise, +\A+ always matches the current position.
*/
static VALUE
strscan_fixed_anchor_p(VALUE self)
@@ -2083,32 +1514,14 @@ named_captures_iter(const OnigUChar *name,
}
/*
- * :markup: markdown
- * :include: strscan/link_refs.txt
- *
* call-seq:
- * named_captures -> hash
- *
- * Returns the array of captured match values at indexes (1..)
- * if the most recent match attempt succeeded, or nil otherwise;
- * see [Captured Match Values][13]:
- *
- * ```
- * scanner = StringScanner.new('Fri Dec 12 1975 14:39')
- * scanner.named_captures # => {}
- *
- * pattern = /(?<wday>\w+) (?<month>\w+) (?<day>\d+) /
- * scanner.match?(pattern)
- * scanner.named_captures # => {"wday"=>"Fri", "month"=>"Dec", "day"=>"12"}
+ * scanner.named_captures -> hash
*
- * scanner.string = 'nope'
- * scanner.match?(pattern)
- * scanner.named_captures # => {"wday"=>nil, "month"=>nil, "day"=>nil}
- *
- * scanner.match?(/nosuch/)
- * scanner.named_captures # => {}
- * ```
+ * Returns a hash of string variables matching the regular expression.
*
+ * scan = StringScanner.new('foobarbaz')
+ * scan.match?(/(?<f>foo)(?<r>bar)(?<z>baz)/)
+ * scan.named_captures # -> {"f"=>"foo", "r"=>"bar", "z"=>"baz"}
*/
static VALUE
strscan_named_captures(VALUE self)
@@ -2132,11 +1545,107 @@ strscan_named_captures(VALUE self)
/*
* Document-class: StringScanner
*
- * :markup: markdown
+ * StringScanner provides for lexical scanning operations on a String. Here is
+ * an example of its usage:
+ *
+ * require 'strscan'
+ *
+ * s = StringScanner.new('This is an example string')
+ * s.eos? # -> false
+ *
+ * p s.scan(/\w+/) # -> "This"
+ * p s.scan(/\w+/) # -> nil
+ * p s.scan(/\s+/) # -> " "
+ * p s.scan(/\s+/) # -> nil
+ * p s.scan(/\w+/) # -> "is"
+ * s.eos? # -> false
+ *
+ * p s.scan(/\s+/) # -> " "
+ * p s.scan(/\w+/) # -> "an"
+ * p s.scan(/\s+/) # -> " "
+ * p s.scan(/\w+/) # -> "example"
+ * p s.scan(/\s+/) # -> " "
+ * p s.scan(/\w+/) # -> "string"
+ * s.eos? # -> true
+ *
+ * p s.scan(/\s+/) # -> nil
+ * p s.scan(/\w+/) # -> nil
+ *
+ * Scanning a string means remembering the position of a <i>scan pointer</i>,
+ * which is just an index. The point of scanning is to move forward a bit at
+ * a time, so matches are sought after the scan pointer; usually immediately
+ * after it.
+ *
+ * Given the string "test string", here are the pertinent scan pointer
+ * positions:
+ *
+ * t e s t s t r i n g
+ * 0 1 2 ... 1
+ * 0
+ *
+ * When you #scan for a pattern (a regular expression), the match must occur
+ * at the character after the scan pointer. If you use #scan_until, then the
+ * match can occur anywhere after the scan pointer. In both cases, the scan
+ * pointer moves <i>just beyond</i> the last character of the match, ready to
+ * scan again from the next character onwards. This is demonstrated by the
+ * example above.
+ *
+ * == Method Categories
+ *
+ * There are other methods besides the plain scanners. You can look ahead in
+ * the string without actually scanning. You can access the most recent match.
+ * You can modify the string being scanned, reset or terminate the scanner,
+ * find out or change the position of the scan pointer, skip ahead, and so on.
+ *
+ * === Advancing the Scan Pointer
+ *
+ * - #getch
+ * - #get_byte
+ * - #scan
+ * - #scan_until
+ * - #skip
+ * - #skip_until
+ *
+ * === Looking Ahead
+ *
+ * - #check
+ * - #check_until
+ * - #exist?
+ * - #match?
+ * - #peek
+ *
+ * === Finding Where we Are
+ *
+ * - #beginning_of_line? (<tt>#bol?</tt>)
+ * - #eos?
+ * - #rest?
+ * - #rest_size
+ * - #pos
+ *
+ * === Setting Where we Are
+ *
+ * - #reset
+ * - #terminate
+ * - #pos=
+ *
+ * === Match Data
+ *
+ * - #matched
+ * - #matched?
+ * - #matched_size
+ * - <tt>#[]</tt>
+ * - #pre_match
+ * - #post_match
+ *
+ * === Miscellaneous
*
- * :include: strscan/link_refs.txt
- * :include: strscan/strscan.md
+ * - <tt><<</tt>
+ * - #concat
+ * - #string
+ * - #string=
+ * - #unscan
*
+ * There are aliases to several of the methods.
*/
void
Init_strscan(void)
@@ -2195,9 +1704,7 @@ Init_strscan(void)
rb_define_method(StringScanner, "getch", strscan_getch, 0);
rb_define_method(StringScanner, "get_byte", strscan_get_byte, 0);
rb_define_method(StringScanner, "getbyte", strscan_getbyte, 0);
- rb_define_method(StringScanner, "scan_byte", strscan_scan_byte, 0);
rb_define_method(StringScanner, "peek", strscan_peek, 1);
- rb_define_method(StringScanner, "peek_byte", strscan_peek_byte, 0);
rb_define_method(StringScanner, "peep", strscan_peep, 1);
rb_define_method(StringScanner, "unscan", strscan_unscan, 0);
diff --git a/ext/strscan/strscan.gemspec b/ext/strscan/strscan.gemspec
index 925edcd2d3..8a61c7abe6 100644
--- a/ext/strscan/strscan.gemspec
+++ b/ext/strscan/strscan.gemspec
@@ -29,11 +29,6 @@ Gem::Specification.new do |s|
s.require_paths = %w{lib}
files << "ext/strscan/extconf.rb"
files << "ext/strscan/strscan.c"
- s.rdoc_options << "-idoc"
- s.extra_rdoc_files = [
- ".rdoc_options",
- *Dir.glob("doc/strscan/**/*")
- ]
s.extensions = %w{ext/strscan/extconf.rb}
end
s.files = files
diff --git a/ext/syslog/depend b/ext/syslog/depend
new file mode 100644
index 0000000000..4eea8c3bf9
--- /dev/null
+++ b/ext/syslog/depend
@@ -0,0 +1,162 @@
+# AUTOGENERATED DEPENDENCIES START
+syslog.o: $(RUBY_EXTCONF_H)
+syslog.o: $(arch_hdrdir)/ruby/config.h
+syslog.o: $(hdrdir)/ruby/assert.h
+syslog.o: $(hdrdir)/ruby/backward.h
+syslog.o: $(hdrdir)/ruby/backward/2/assume.h
+syslog.o: $(hdrdir)/ruby/backward/2/attributes.h
+syslog.o: $(hdrdir)/ruby/backward/2/bool.h
+syslog.o: $(hdrdir)/ruby/backward/2/inttypes.h
+syslog.o: $(hdrdir)/ruby/backward/2/limits.h
+syslog.o: $(hdrdir)/ruby/backward/2/long_long.h
+syslog.o: $(hdrdir)/ruby/backward/2/stdalign.h
+syslog.o: $(hdrdir)/ruby/backward/2/stdarg.h
+syslog.o: $(hdrdir)/ruby/defines.h
+syslog.o: $(hdrdir)/ruby/intern.h
+syslog.o: $(hdrdir)/ruby/internal/abi.h
+syslog.o: $(hdrdir)/ruby/internal/anyargs.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/char.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/double.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/int.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/long.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/short.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h
+syslog.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h
+syslog.o: $(hdrdir)/ruby/internal/assume.h
+syslog.o: $(hdrdir)/ruby/internal/attr/alloc_size.h
+syslog.o: $(hdrdir)/ruby/internal/attr/artificial.h
+syslog.o: $(hdrdir)/ruby/internal/attr/cold.h
+syslog.o: $(hdrdir)/ruby/internal/attr/const.h
+syslog.o: $(hdrdir)/ruby/internal/attr/constexpr.h
+syslog.o: $(hdrdir)/ruby/internal/attr/deprecated.h
+syslog.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h
+syslog.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h
+syslog.o: $(hdrdir)/ruby/internal/attr/error.h
+syslog.o: $(hdrdir)/ruby/internal/attr/flag_enum.h
+syslog.o: $(hdrdir)/ruby/internal/attr/forceinline.h
+syslog.o: $(hdrdir)/ruby/internal/attr/format.h
+syslog.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h
+syslog.o: $(hdrdir)/ruby/internal/attr/noalias.h
+syslog.o: $(hdrdir)/ruby/internal/attr/nodiscard.h
+syslog.o: $(hdrdir)/ruby/internal/attr/noexcept.h
+syslog.o: $(hdrdir)/ruby/internal/attr/noinline.h
+syslog.o: $(hdrdir)/ruby/internal/attr/nonnull.h
+syslog.o: $(hdrdir)/ruby/internal/attr/noreturn.h
+syslog.o: $(hdrdir)/ruby/internal/attr/pure.h
+syslog.o: $(hdrdir)/ruby/internal/attr/restrict.h
+syslog.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
+syslog.o: $(hdrdir)/ruby/internal/attr/warning.h
+syslog.o: $(hdrdir)/ruby/internal/attr/weakref.h
+syslog.o: $(hdrdir)/ruby/internal/cast.h
+syslog.o: $(hdrdir)/ruby/internal/compiler_is.h
+syslog.o: $(hdrdir)/ruby/internal/compiler_is/apple.h
+syslog.o: $(hdrdir)/ruby/internal/compiler_is/clang.h
+syslog.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h
+syslog.o: $(hdrdir)/ruby/internal/compiler_is/intel.h
+syslog.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h
+syslog.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h
+syslog.o: $(hdrdir)/ruby/internal/compiler_since.h
+syslog.o: $(hdrdir)/ruby/internal/config.h
+syslog.o: $(hdrdir)/ruby/internal/constant_p.h
+syslog.o: $(hdrdir)/ruby/internal/core.h
+syslog.o: $(hdrdir)/ruby/internal/core/rarray.h
+syslog.o: $(hdrdir)/ruby/internal/core/rbasic.h
+syslog.o: $(hdrdir)/ruby/internal/core/rbignum.h
+syslog.o: $(hdrdir)/ruby/internal/core/rclass.h
+syslog.o: $(hdrdir)/ruby/internal/core/rdata.h
+syslog.o: $(hdrdir)/ruby/internal/core/rfile.h
+syslog.o: $(hdrdir)/ruby/internal/core/rhash.h
+syslog.o: $(hdrdir)/ruby/internal/core/robject.h
+syslog.o: $(hdrdir)/ruby/internal/core/rregexp.h
+syslog.o: $(hdrdir)/ruby/internal/core/rstring.h
+syslog.o: $(hdrdir)/ruby/internal/core/rstruct.h
+syslog.o: $(hdrdir)/ruby/internal/core/rtypeddata.h
+syslog.o: $(hdrdir)/ruby/internal/ctype.h
+syslog.o: $(hdrdir)/ruby/internal/dllexport.h
+syslog.o: $(hdrdir)/ruby/internal/dosish.h
+syslog.o: $(hdrdir)/ruby/internal/error.h
+syslog.o: $(hdrdir)/ruby/internal/eval.h
+syslog.o: $(hdrdir)/ruby/internal/event.h
+syslog.o: $(hdrdir)/ruby/internal/fl_type.h
+syslog.o: $(hdrdir)/ruby/internal/gc.h
+syslog.o: $(hdrdir)/ruby/internal/glob.h
+syslog.o: $(hdrdir)/ruby/internal/globals.h
+syslog.o: $(hdrdir)/ruby/internal/has/attribute.h
+syslog.o: $(hdrdir)/ruby/internal/has/builtin.h
+syslog.o: $(hdrdir)/ruby/internal/has/c_attribute.h
+syslog.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h
+syslog.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h
+syslog.o: $(hdrdir)/ruby/internal/has/extension.h
+syslog.o: $(hdrdir)/ruby/internal/has/feature.h
+syslog.o: $(hdrdir)/ruby/internal/has/warning.h
+syslog.o: $(hdrdir)/ruby/internal/intern/array.h
+syslog.o: $(hdrdir)/ruby/internal/intern/bignum.h
+syslog.o: $(hdrdir)/ruby/internal/intern/class.h
+syslog.o: $(hdrdir)/ruby/internal/intern/compar.h
+syslog.o: $(hdrdir)/ruby/internal/intern/complex.h
+syslog.o: $(hdrdir)/ruby/internal/intern/cont.h
+syslog.o: $(hdrdir)/ruby/internal/intern/dir.h
+syslog.o: $(hdrdir)/ruby/internal/intern/enum.h
+syslog.o: $(hdrdir)/ruby/internal/intern/enumerator.h
+syslog.o: $(hdrdir)/ruby/internal/intern/error.h
+syslog.o: $(hdrdir)/ruby/internal/intern/eval.h
+syslog.o: $(hdrdir)/ruby/internal/intern/file.h
+syslog.o: $(hdrdir)/ruby/internal/intern/gc.h
+syslog.o: $(hdrdir)/ruby/internal/intern/hash.h
+syslog.o: $(hdrdir)/ruby/internal/intern/io.h
+syslog.o: $(hdrdir)/ruby/internal/intern/load.h
+syslog.o: $(hdrdir)/ruby/internal/intern/marshal.h
+syslog.o: $(hdrdir)/ruby/internal/intern/numeric.h
+syslog.o: $(hdrdir)/ruby/internal/intern/object.h
+syslog.o: $(hdrdir)/ruby/internal/intern/parse.h
+syslog.o: $(hdrdir)/ruby/internal/intern/proc.h
+syslog.o: $(hdrdir)/ruby/internal/intern/process.h
+syslog.o: $(hdrdir)/ruby/internal/intern/random.h
+syslog.o: $(hdrdir)/ruby/internal/intern/range.h
+syslog.o: $(hdrdir)/ruby/internal/intern/rational.h
+syslog.o: $(hdrdir)/ruby/internal/intern/re.h
+syslog.o: $(hdrdir)/ruby/internal/intern/ruby.h
+syslog.o: $(hdrdir)/ruby/internal/intern/select.h
+syslog.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+syslog.o: $(hdrdir)/ruby/internal/intern/signal.h
+syslog.o: $(hdrdir)/ruby/internal/intern/sprintf.h
+syslog.o: $(hdrdir)/ruby/internal/intern/string.h
+syslog.o: $(hdrdir)/ruby/internal/intern/struct.h
+syslog.o: $(hdrdir)/ruby/internal/intern/thread.h
+syslog.o: $(hdrdir)/ruby/internal/intern/time.h
+syslog.o: $(hdrdir)/ruby/internal/intern/variable.h
+syslog.o: $(hdrdir)/ruby/internal/intern/vm.h
+syslog.o: $(hdrdir)/ruby/internal/interpreter.h
+syslog.o: $(hdrdir)/ruby/internal/iterator.h
+syslog.o: $(hdrdir)/ruby/internal/memory.h
+syslog.o: $(hdrdir)/ruby/internal/method.h
+syslog.o: $(hdrdir)/ruby/internal/module.h
+syslog.o: $(hdrdir)/ruby/internal/newobj.h
+syslog.o: $(hdrdir)/ruby/internal/rgengc.h
+syslog.o: $(hdrdir)/ruby/internal/scan_args.h
+syslog.o: $(hdrdir)/ruby/internal/special_consts.h
+syslog.o: $(hdrdir)/ruby/internal/static_assert.h
+syslog.o: $(hdrdir)/ruby/internal/stdalign.h
+syslog.o: $(hdrdir)/ruby/internal/stdbool.h
+syslog.o: $(hdrdir)/ruby/internal/symbol.h
+syslog.o: $(hdrdir)/ruby/internal/value.h
+syslog.o: $(hdrdir)/ruby/internal/value_type.h
+syslog.o: $(hdrdir)/ruby/internal/variable.h
+syslog.o: $(hdrdir)/ruby/internal/warning_push.h
+syslog.o: $(hdrdir)/ruby/internal/xmalloc.h
+syslog.o: $(hdrdir)/ruby/missing.h
+syslog.o: $(hdrdir)/ruby/ruby.h
+syslog.o: $(hdrdir)/ruby/st.h
+syslog.o: $(hdrdir)/ruby/subst.h
+syslog.o: $(hdrdir)/ruby/util.h
+syslog.o: syslog.c
+# AUTOGENERATED DEPENDENCIES END
diff --git a/ext/syslog/extconf.rb b/ext/syslog/extconf.rb
new file mode 100644
index 0000000000..1230a4d52e
--- /dev/null
+++ b/ext/syslog/extconf.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: false
+# $RoughId: extconf.rb,v 1.3 2001/11/24 17:49:26 knu Exp $
+# $Id$
+
+require 'mkmf'
+
+have_library("log") # for Android
+
+have_header("syslog.h") &&
+ have_func("openlog") &&
+ have_func("setlogmask") &&
+ create_makefile("syslog")
+
diff --git a/ext/syslog/lib/syslog/logger.rb b/ext/syslog/lib/syslog/logger.rb
new file mode 100644
index 0000000000..453ca2785c
--- /dev/null
+++ b/ext/syslog/lib/syslog/logger.rb
@@ -0,0 +1,209 @@
+# frozen_string_literal: false
+require 'syslog'
+require 'logger'
+
+##
+# Syslog::Logger is a Logger work-alike that logs via syslog instead of to a
+# file. You can use Syslog::Logger to aggregate logs between multiple
+# machines.
+#
+# By default, Syslog::Logger uses the program name 'ruby', but this can be
+# changed via the first argument to Syslog::Logger.new.
+#
+# NOTE! You can only set the Syslog::Logger program name when you initialize
+# Syslog::Logger for the first time. This is a limitation of the way
+# Syslog::Logger uses syslog (and in some ways, a limitation of the way
+# syslog(3) works). Attempts to change Syslog::Logger's program name after
+# the first initialization will be ignored.
+#
+# === Example
+#
+# The following will log to syslogd on your local machine:
+#
+# require 'syslog/logger'
+#
+# log = Syslog::Logger.new 'my_program'
+# log.info 'this line will be logged via syslog(3)'
+#
+# Also the facility may be set to specify the facility level which will be used:
+#
+# log.info 'this line will be logged using Syslog default facility level'
+#
+# log_local1 = Syslog::Logger.new 'my_program', Syslog::LOG_LOCAL1
+# log_local1.info 'this line will be logged using local1 facility level'
+#
+#
+# You may need to perform some syslog.conf setup first. For a BSD machine add
+# the following lines to /etc/syslog.conf:
+#
+# !my_program
+# *.* /var/log/my_program.log
+#
+# Then touch /var/log/my_program.log and signal syslogd with a HUP
+# (killall -HUP syslogd, on FreeBSD).
+#
+# If you wish to have logs automatically roll over and archive, see the
+# newsyslog.conf(5) and newsyslog(8) man pages.
+
+class Syslog::Logger
+ # Default formatter for log messages.
+ class Formatter
+ def call severity, time, progname, msg
+ clean msg
+ end
+
+ private
+
+ ##
+ # Clean up messages so they're nice and pretty.
+
+ def clean message
+ message = message.to_s.strip
+ message.gsub!(/\e\[[0-9;]*m/, '') # remove useless ansi color codes
+ return message
+ end
+ end
+
+ ##
+ # The version of Syslog::Logger you are using.
+
+ VERSION = '2.1.0'
+
+ ##
+ # Maps Logger warning types to syslog(3) warning types.
+ #
+ # Messages from Ruby applications are not considered as critical as messages
+ # from other system daemons using syslog(3), so most messages are reduced by
+ # one level. For example, a fatal message for Ruby's Logger is considered
+ # an error for syslog(3).
+
+ LEVEL_MAP = {
+ ::Logger::UNKNOWN => Syslog::LOG_ALERT,
+ ::Logger::FATAL => Syslog::LOG_ERR,
+ ::Logger::ERROR => Syslog::LOG_WARNING,
+ ::Logger::WARN => Syslog::LOG_NOTICE,
+ ::Logger::INFO => Syslog::LOG_INFO,
+ ::Logger::DEBUG => Syslog::LOG_DEBUG,
+ }
+
+ ##
+ # Returns the internal Syslog object that is initialized when the
+ # first instance is created.
+
+ def self.syslog
+ @@syslog
+ end
+
+ ##
+ # Specifies the internal Syslog object to be used.
+
+ def self.syslog= syslog
+ @@syslog = syslog
+ end
+
+ ##
+ # Builds a methods for level +meth+.
+
+ def self.make_methods meth
+ level = ::Logger.const_get(meth.upcase)
+ eval <<-EOM, nil, __FILE__, __LINE__ + 1
+ def #{meth}(message = nil, &block)
+ add(#{level}, message, &block)
+ end
+
+ def #{meth}?
+ level <= #{level}
+ end
+ EOM
+ end
+
+ ##
+ # :method: unknown
+ #
+ # Logs a +message+ at the unknown (syslog alert) log level, or logs the
+ # message returned from the block.
+
+ ##
+ # :method: fatal
+ #
+ # Logs a +message+ at the fatal (syslog err) log level, or logs the message
+ # returned from the block.
+
+ ##
+ # :method: error
+ #
+ # Logs a +message+ at the error (syslog warning) log level, or logs the
+ # message returned from the block.
+
+ ##
+ # :method: warn
+ #
+ # Logs a +message+ at the warn (syslog notice) log level, or logs the
+ # message returned from the block.
+
+ ##
+ # :method: info
+ #
+ # Logs a +message+ at the info (syslog info) log level, or logs the message
+ # returned from the block.
+
+ ##
+ # :method: debug
+ #
+ # Logs a +message+ at the debug (syslog debug) log level, or logs the
+ # message returned from the block.
+
+ Logger::Severity::constants.each do |severity|
+ make_methods severity.downcase
+ end
+
+ ##
+ # Log level for Logger compatibility.
+
+ attr_accessor :level
+
+ # Logging formatter, as a +Proc+ that will take four arguments and
+ # return the formatted message. The arguments are:
+ #
+ # +severity+:: The Severity of the log message.
+ # +time+:: A Time instance representing when the message was logged.
+ # +progname+:: The #progname configured, or passed to the logger method.
+ # +msg+:: The _Object_ the user passed to the log message; not necessarily a
+ # String.
+ #
+ # The block should return an Object that can be written to the logging
+ # device via +write+. The default formatter is used when no formatter is
+ # set.
+ attr_accessor :formatter
+
+ ##
+ # The facility argument is used to specify what type of program is logging the message.
+
+ attr_accessor :facility
+
+ ##
+ # Fills in variables for Logger compatibility. If this is the first
+ # instance of Syslog::Logger, +program_name+ may be set to change the logged
+ # program name. The +facility+ may be set to specify the facility level which will be used.
+ #
+ # Due to the way syslog works, only one program name may be chosen.
+
+ def initialize program_name = 'ruby', facility = nil
+ @level = ::Logger::DEBUG
+ @formatter = Formatter.new
+
+ @@syslog ||= Syslog.open(program_name)
+
+ @facility = (facility || @@syslog.facility)
+ end
+
+ ##
+ # Almost duplicates Logger#add. +progname+ is ignored.
+
+ def add severity, message = nil, progname = nil, &block
+ severity ||= ::Logger::UNKNOWN
+ level <= severity and
+ @@syslog.log( (LEVEL_MAP[severity] | @facility), '%s', formatter.call(severity, Time.now, progname, (message || block.call)) )
+ true
+ end
+end
diff --git a/ext/syslog/syslog.c b/ext/syslog/syslog.c
new file mode 100644
index 0000000000..8f3674aa8d
--- /dev/null
+++ b/ext/syslog/syslog.c
@@ -0,0 +1,588 @@
+/*
+ * UNIX Syslog extension for Ruby
+ * Amos Gouaux, University of Texas at Dallas
+ * <amos+ruby@utdallas.edu>
+ * Documented by mathew <meta@pobox.com>
+ *
+ * $RoughId: syslog.c,v 1.21 2002/02/25 12:21:17 knu Exp $
+ * $Id$
+ */
+
+#include "ruby/ruby.h"
+#include "ruby/util.h"
+#include <syslog.h>
+
+/* Syslog class */
+static VALUE mSyslog;
+/*
+ * Module holding all Syslog constants. See Syslog::log and
+ * Syslog::open for constant descriptions.
+ */
+static VALUE mSyslogConstants;
+/* Module holding Syslog option constants */
+static VALUE mSyslogOption;
+/* Module holding Syslog facility constants */
+static VALUE mSyslogFacility;
+/* Module holding Syslog level constants */
+static VALUE mSyslogLevel;
+/* Module holding Syslog utility macros */
+static VALUE mSyslogMacros;
+
+static const char *syslog_ident = NULL;
+static int syslog_options = -1, syslog_facility = -1, syslog_mask = -1;
+static int syslog_opened = 0;
+
+/* Package helper routines */
+static void syslog_write(int pri, int argc, VALUE *argv)
+{
+ VALUE str;
+
+ if (argc < 1) {
+ rb_raise(rb_eArgError, "no log message supplied");
+ }
+
+ if (!syslog_opened) {
+ rb_raise(rb_eRuntimeError, "must open syslog before write");
+ }
+
+ str = rb_f_sprintf(argc, argv);
+
+ syslog(pri, "%s", RSTRING_PTR(str));
+}
+
+/* Closes the syslog facility.
+ * Raises a runtime exception if it is not open.
+ */
+static VALUE mSyslog_close(VALUE self)
+{
+ if (!syslog_opened) {
+ rb_raise(rb_eRuntimeError, "syslog not opened");
+ }
+
+ closelog();
+
+ xfree((void *)syslog_ident);
+ syslog_ident = NULL;
+ syslog_options = syslog_facility = syslog_mask = -1;
+ syslog_opened = 0;
+
+ return Qnil;
+}
+
+/* call-seq:
+ * open(ident, options, facility) => syslog
+ *
+ * :yields: syslog
+ *
+ * Open the syslog facility.
+ * Raises a runtime exception if it is already open.
+ *
+ * Can be called with or without a code block. If called with a block, the
+ * Syslog object created is passed to the block.
+ *
+ * If the syslog is already open, raises a RuntimeError.
+ *
+ * +ident+ is a String which identifies the calling program.
+ *
+ * +options+ is the logical OR of any of the following:
+ *
+ * LOG_CONS:: If there is an error while sending to the system logger,
+ * write directly to the console instead.
+ *
+ * LOG_NDELAY:: Open the connection now, rather than waiting for the first
+ * message to be written.
+ *
+ * LOG_NOWAIT:: Don't wait for any child processes created while logging
+ * messages. (Has no effect on Linux.)
+ *
+ * LOG_ODELAY:: Opposite of LOG_NDELAY; wait until a message is sent before
+ * opening the connection. (This is the default.)
+ *
+ * LOG_PERROR:: Print the message to stderr as well as sending it to syslog.
+ * (Not in POSIX.1-2001.)
+ *
+ * LOG_PID:: Include the current process ID with each message.
+ *
+ * +facility+ describes the type of program opening the syslog, and is
+ * the logical OR of any of the following which are defined for the host OS:
+ *
+ * LOG_AUTH:: Security or authorization. Deprecated, use LOG_AUTHPRIV
+ * instead.
+ *
+ * LOG_AUTHPRIV:: Security or authorization messages which should be kept
+ * private.
+ *
+ * LOG_CONSOLE:: System console message.
+ *
+ * LOG_CRON:: System task scheduler (cron or at).
+ *
+ * LOG_DAEMON:: A system daemon which has no facility value of its own.
+ *
+ * LOG_FTP:: An FTP server.
+ *
+ * LOG_KERN:: A kernel message (not sendable by user processes, so not of
+ * much use to Ruby, but listed here for completeness).
+ *
+ * LOG_LPR:: Line printer subsystem.
+ *
+ * LOG_MAIL:: Mail delivery or transport subsystem.
+ *
+ * LOG_NEWS:: Usenet news system.
+ *
+ * LOG_NTP:: Network Time Protocol server.
+ *
+ * LOG_SECURITY:: General security message.
+ *
+ * LOG_SYSLOG:: Messages generated internally by syslog.
+ *
+ * LOG_USER:: Generic user-level message.
+ *
+ * LOG_UUCP:: UUCP subsystem.
+ *
+ * LOG_LOCAL0 to LOG_LOCAL7:: Locally-defined facilities.
+ *
+ * Example:
+ *
+ * Syslog.open("webrick", Syslog::LOG_PID,
+ * Syslog::LOG_DAEMON | Syslog::LOG_LOCAL3)
+ *
+ */
+static VALUE mSyslog_open(int argc, VALUE *argv, VALUE self)
+{
+ VALUE ident, opt, fac;
+ const char *ident_ptr;
+
+ if (syslog_opened) {
+ rb_raise(rb_eRuntimeError, "syslog already open");
+ }
+
+ rb_scan_args(argc, argv, "03", &ident, &opt, &fac);
+
+ if (NIL_P(ident)) {
+ ident = rb_gv_get("$0");
+ }
+ ident_ptr = StringValueCStr(ident);
+ syslog_ident = strdup(ident_ptr);
+
+ if (NIL_P(opt)) {
+ syslog_options = LOG_PID | LOG_CONS;
+ } else {
+ syslog_options = NUM2INT(opt);
+ }
+
+ if (NIL_P(fac)) {
+ syslog_facility = LOG_USER;
+ } else {
+ syslog_facility = NUM2INT(fac);
+ }
+
+ openlog(syslog_ident, syslog_options, syslog_facility);
+
+ syslog_opened = 1;
+
+ setlogmask(syslog_mask = setlogmask(0));
+
+ /* be like File.new.open {...} */
+ if (rb_block_given_p()) {
+ rb_ensure(rb_yield, self, mSyslog_close, self);
+ }
+
+ return self;
+}
+
+/* call-seq:
+ * reopen(ident, options, facility) => syslog
+ *
+ * :yields: syslog
+ *
+ * Closes and then reopens the syslog.
+ *
+ * Arguments are the same as for open().
+ */
+static VALUE mSyslog_reopen(int argc, VALUE *argv, VALUE self)
+{
+ mSyslog_close(self);
+
+ return mSyslog_open(argc, argv, self);
+}
+
+/* call-seq:
+ * opened?
+ *
+ * Returns true if the syslog is open.
+ */
+static VALUE mSyslog_isopen(VALUE self)
+{
+ return syslog_opened ? Qtrue : Qfalse;
+}
+
+/* Returns the identity string used in the last call to open()
+ */
+static VALUE mSyslog_ident(VALUE self)
+{
+ return syslog_opened ? rb_str_new2(syslog_ident) : Qnil;
+}
+
+/* Returns the options bitmask used in the last call to open()
+ */
+static VALUE mSyslog_options(VALUE self)
+{
+ return syslog_opened ? INT2NUM(syslog_options) : Qnil;
+}
+
+/* Returns the facility number used in the last call to open()
+ */
+static VALUE mSyslog_facility(VALUE self)
+{
+ return syslog_opened ? INT2NUM(syslog_facility) : Qnil;
+}
+
+/* Returns the log priority mask in effect. The mask is not reset by opening
+ * or closing syslog.
+ */
+static VALUE mSyslog_get_mask(VALUE self)
+{
+ return syslog_opened ? INT2NUM(syslog_mask) : Qnil;
+}
+
+/* call-seq:
+ * mask=(priority_mask)
+ *
+ * Sets the log priority mask. A method LOG_UPTO is defined to make it easier
+ * to set mask values. Example:
+ *
+ * Syslog.mask = Syslog::LOG_UPTO(Syslog::LOG_ERR)
+ *
+ * Alternatively, specific priorities can be selected and added together using
+ * binary OR. Example:
+ *
+ * Syslog.mask = Syslog::LOG_MASK(Syslog::LOG_ERR) | Syslog::LOG_MASK(Syslog::LOG_CRIT)
+ *
+ * The priority mask persists through calls to open() and close().
+ */
+static VALUE mSyslog_set_mask(VALUE self, VALUE mask)
+{
+ if (!syslog_opened) {
+ rb_raise(rb_eRuntimeError, "must open syslog before setting log mask");
+ }
+
+ setlogmask(syslog_mask = NUM2INT(mask));
+
+ return mask;
+}
+
+/* call-seq:
+ * log(priority, format_string, *format_args)
+ *
+ * Log a message with the specified priority. Example:
+ *
+ * Syslog.log(Syslog::LOG_CRIT, "Out of disk space")
+ * Syslog.log(Syslog::LOG_CRIT, "User %s logged in", ENV['USER'])
+ *
+ * The priority levels, in descending order, are:
+ *
+ * LOG_EMERG:: System is unusable
+ * LOG_ALERT:: Action needs to be taken immediately
+ * LOG_CRIT:: A critical condition has occurred
+ * LOG_ERR:: An error occurred
+ * LOG_WARNING:: Warning of a possible problem
+ * LOG_NOTICE:: A normal but significant condition occurred
+ * LOG_INFO:: Informational message
+ * LOG_DEBUG:: Debugging information
+ *
+ * Each priority level also has a shortcut method that logs with it's named priority.
+ * As an example, the two following statements would produce the same result:
+ *
+ * Syslog.log(Syslog::LOG_ALERT, "Out of memory")
+ * Syslog.alert("Out of memory")
+ *
+ */
+static VALUE mSyslog_log(int argc, VALUE *argv, VALUE self)
+{
+ VALUE pri;
+
+ rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS);
+
+ argc--;
+ pri = *argv++;
+
+ if (!FIXNUM_P(pri)) {
+ rb_raise(rb_eTypeError, "type mismatch: %"PRIsVALUE" given", rb_obj_class(pri));
+ }
+
+ syslog_write(FIX2INT(pri), argc, argv);
+
+ return self;
+}
+
+/* Returns an inspect() string summarizing the object state.
+ */
+static VALUE mSyslog_inspect(VALUE self)
+{
+ Check_Type(self, T_MODULE);
+
+ if (!syslog_opened)
+ return rb_sprintf("<#%"PRIsVALUE": opened=false>", self);
+
+ return rb_sprintf("<#%"PRIsVALUE": opened=true, ident=\"%s\", options=%d, facility=%d, mask=%d>",
+ self,
+ syslog_ident,
+ syslog_options,
+ syslog_facility,
+ syslog_mask);
+}
+
+/* Returns self, for backward compatibility.
+ */
+static VALUE mSyslog_instance(VALUE self)
+{
+ return self;
+}
+
+#define define_syslog_shortcut_method(pri, name) \
+static VALUE mSyslog_##name(int argc, VALUE *argv, VALUE self) \
+{ \
+ syslog_write((pri), argc, argv); \
+\
+ return self; \
+}
+
+#ifdef LOG_EMERG
+define_syslog_shortcut_method(LOG_EMERG, emerg)
+#endif
+#ifdef LOG_ALERT
+define_syslog_shortcut_method(LOG_ALERT, alert)
+#endif
+#ifdef LOG_CRIT
+define_syslog_shortcut_method(LOG_CRIT, crit)
+#endif
+#ifdef LOG_ERR
+define_syslog_shortcut_method(LOG_ERR, err)
+#endif
+#ifdef LOG_WARNING
+define_syslog_shortcut_method(LOG_WARNING, warning)
+#endif
+#ifdef LOG_NOTICE
+define_syslog_shortcut_method(LOG_NOTICE, notice)
+#endif
+#ifdef LOG_INFO
+define_syslog_shortcut_method(LOG_INFO, info)
+#endif
+#ifdef LOG_DEBUG
+define_syslog_shortcut_method(LOG_DEBUG, debug)
+#endif
+
+/* call-seq:
+ * LOG_MASK(priority_level) => priority_mask
+ *
+ * Generates a mask bit for a priority level. See #mask=
+ */
+static VALUE mSyslogMacros_LOG_MASK(VALUE mod, VALUE pri)
+{
+ return INT2FIX(LOG_MASK(NUM2INT(pri)));
+}
+
+/* call-seq:
+ * LOG_UPTO(priority_level) => priority_mask
+ *
+ * Generates a mask value for priority levels at or below the level specified.
+ * See #mask=
+ */
+static VALUE mSyslogMacros_LOG_UPTO(VALUE mod, VALUE pri)
+{
+ return INT2FIX(LOG_UPTO(NUM2INT(pri)));
+}
+
+static VALUE mSyslogMacros_included(VALUE mod, VALUE target)
+{
+ rb_extend_object(target, mSyslogMacros);
+ return mod;
+}
+
+/* The syslog package provides a Ruby interface to the POSIX system logging
+ * facility.
+ *
+ * Syslog messages are typically passed to a central logging daemon.
+ * The daemon may filter them; route them into different files (usually
+ * found under /var/log); place them in SQL databases; forward
+ * them to centralized logging servers via TCP or UDP; or even alert the
+ * system administrator via email, pager or text message.
+ *
+ * Unlike application-level logging via Logger or Log4r, syslog is designed
+ * to allow secure tamper-proof logging.
+ *
+ * The syslog protocol is standardized in RFC 5424.
+ */
+void Init_syslog(void)
+{
+#undef rb_intern
+ mSyslog = rb_define_module("Syslog");
+
+ mSyslogConstants = rb_define_module_under(mSyslog, "Constants");
+
+ mSyslogOption = rb_define_module_under(mSyslog, "Option");
+ mSyslogFacility = rb_define_module_under(mSyslog, "Facility");
+ mSyslogLevel = rb_define_module_under(mSyslog, "Level");
+ mSyslogMacros = rb_define_module_under(mSyslog, "Macros");
+
+ rb_define_module_function(mSyslog, "open", mSyslog_open, -1);
+ rb_define_module_function(mSyslog, "reopen", mSyslog_reopen, -1);
+ rb_define_module_function(mSyslog, "open!", mSyslog_reopen, -1);
+ rb_define_module_function(mSyslog, "opened?", mSyslog_isopen, 0);
+
+ rb_define_module_function(mSyslog, "ident", mSyslog_ident, 0);
+ rb_define_module_function(mSyslog, "options", mSyslog_options, 0);
+ rb_define_module_function(mSyslog, "facility", mSyslog_facility, 0);
+
+ rb_define_module_function(mSyslog, "log", mSyslog_log, -1);
+ rb_define_module_function(mSyslog, "close", mSyslog_close, 0);
+ rb_define_module_function(mSyslog, "mask", mSyslog_get_mask, 0);
+ rb_define_module_function(mSyslog, "mask=", mSyslog_set_mask, 1);
+
+ rb_define_singleton_method(mSyslog, "inspect", mSyslog_inspect, 0);
+ rb_define_module_function(mSyslog, "instance", mSyslog_instance, 0);
+
+ /* Syslog options */
+
+#define rb_define_syslog_option(c) \
+ rb_define_const(mSyslogOption, #c, INT2NUM(c))
+
+#ifdef LOG_PID
+ rb_define_syslog_option(LOG_PID);
+#endif
+#ifdef LOG_CONS
+ rb_define_syslog_option(LOG_CONS);
+#endif
+#ifdef LOG_ODELAY
+ rb_define_syslog_option(LOG_ODELAY); /* deprecated */
+#endif
+#ifdef LOG_NDELAY
+ rb_define_syslog_option(LOG_NDELAY);
+#endif
+#ifdef LOG_NOWAIT
+ rb_define_syslog_option(LOG_NOWAIT); /* deprecated */
+#endif
+#ifdef LOG_PERROR
+ rb_define_syslog_option(LOG_PERROR);
+#endif
+
+ /* Syslog facilities */
+
+#define rb_define_syslog_facility(c) \
+ rb_define_const(mSyslogFacility, #c, INT2NUM(c))
+
+#ifdef LOG_AUTH
+ rb_define_syslog_facility(LOG_AUTH);
+#endif
+#ifdef LOG_AUTHPRIV
+ rb_define_syslog_facility(LOG_AUTHPRIV);
+#endif
+#ifdef LOG_CONSOLE
+ rb_define_syslog_facility(LOG_CONSOLE);
+#endif
+#ifdef LOG_CRON
+ rb_define_syslog_facility(LOG_CRON);
+#endif
+#ifdef LOG_DAEMON
+ rb_define_syslog_facility(LOG_DAEMON);
+#endif
+#ifdef LOG_FTP
+ rb_define_syslog_facility(LOG_FTP);
+#endif
+#ifdef LOG_KERN
+ rb_define_syslog_facility(LOG_KERN);
+#endif
+#ifdef LOG_LPR
+ rb_define_syslog_facility(LOG_LPR);
+#endif
+#ifdef LOG_MAIL
+ rb_define_syslog_facility(LOG_MAIL);
+#endif
+#ifdef LOG_NEWS
+ rb_define_syslog_facility(LOG_NEWS);
+#endif
+#ifdef LOG_NTP
+ rb_define_syslog_facility(LOG_NTP);
+#endif
+#ifdef LOG_SECURITY
+ rb_define_syslog_facility(LOG_SECURITY);
+#endif
+#ifdef LOG_SYSLOG
+ rb_define_syslog_facility(LOG_SYSLOG);
+#endif
+#ifdef LOG_USER
+ rb_define_syslog_facility(LOG_USER);
+#endif
+#ifdef LOG_UUCP
+ rb_define_syslog_facility(LOG_UUCP);
+#endif
+#ifdef LOG_LOCAL0
+ rb_define_syslog_facility(LOG_LOCAL0);
+#endif
+#ifdef LOG_LOCAL1
+ rb_define_syslog_facility(LOG_LOCAL1);
+#endif
+#ifdef LOG_LOCAL2
+ rb_define_syslog_facility(LOG_LOCAL2);
+#endif
+#ifdef LOG_LOCAL3
+ rb_define_syslog_facility(LOG_LOCAL3);
+#endif
+#ifdef LOG_LOCAL4
+ rb_define_syslog_facility(LOG_LOCAL4);
+#endif
+#ifdef LOG_LOCAL5
+ rb_define_syslog_facility(LOG_LOCAL5);
+#endif
+#ifdef LOG_LOCAL6
+ rb_define_syslog_facility(LOG_LOCAL6);
+#endif
+#ifdef LOG_LOCAL7
+ rb_define_syslog_facility(LOG_LOCAL7);
+#endif
+
+ /* Syslog levels and the shortcut methods */
+
+#define rb_define_syslog_level(c, m) \
+ rb_define_const(mSyslogLevel, #c, INT2NUM(c)); \
+ rb_define_module_function(mSyslog, #m, mSyslog_##m, -1)
+
+#ifdef LOG_EMERG
+ rb_define_syslog_level(LOG_EMERG, emerg);
+#endif
+#ifdef LOG_ALERT
+ rb_define_syslog_level(LOG_ALERT, alert);
+#endif
+#ifdef LOG_CRIT
+ rb_define_syslog_level(LOG_CRIT, crit);
+#endif
+#ifdef LOG_ERR
+ rb_define_syslog_level(LOG_ERR, err);
+#endif
+#ifdef LOG_WARNING
+ rb_define_syslog_level(LOG_WARNING, warning);
+#endif
+#ifdef LOG_NOTICE
+ rb_define_syslog_level(LOG_NOTICE, notice);
+#endif
+#ifdef LOG_INFO
+ rb_define_syslog_level(LOG_INFO, info);
+#endif
+#ifdef LOG_DEBUG
+ rb_define_syslog_level(LOG_DEBUG, debug);
+#endif
+
+ /* Syslog macros */
+
+ rb_define_method(mSyslogMacros, "LOG_MASK", mSyslogMacros_LOG_MASK, 1);
+ rb_define_method(mSyslogMacros, "LOG_UPTO", mSyslogMacros_LOG_UPTO, 1);
+ rb_define_singleton_method(mSyslogMacros, "included", mSyslogMacros_included, 1);
+
+ rb_include_module(mSyslogConstants, mSyslogOption);
+ rb_include_module(mSyslogConstants, mSyslogFacility);
+ rb_include_module(mSyslogConstants, mSyslogLevel);
+ rb_funcall(mSyslogConstants, rb_intern("include"), 1, mSyslogMacros);
+
+ rb_define_singleton_method(mSyslogConstants, "included", mSyslogMacros_included, 1);
+ rb_funcall(mSyslog, rb_intern("include"), 1, mSyslogConstants);
+}
diff --git a/ext/syslog/syslog.gemspec b/ext/syslog/syslog.gemspec
new file mode 100644
index 0000000000..6aa2e9570d
--- /dev/null
+++ b/ext/syslog/syslog.gemspec
@@ -0,0 +1,23 @@
+Gem::Specification.new do |spec|
+ spec.name = "syslog"
+ spec.version = "0.1.1"
+ spec.authors = ["Akinori MUSHA"]
+ spec.email = ["knu@idaemons.org"]
+
+ spec.summary = %q{Ruby interface for the POSIX system logging facility.}
+ spec.description = %q{Ruby interface for the POSIX system logging facility.}
+ spec.homepage = "https://github.com/ruby/syslog"
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.extensions = ["ext/syslog/extconf.rb"]
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+end
diff --git a/ext/syslog/syslog.txt b/ext/syslog/syslog.txt
new file mode 100644
index 0000000000..1507a87924
--- /dev/null
+++ b/ext/syslog/syslog.txt
@@ -0,0 +1,124 @@
+.\" syslog.txt - -*- Indented-Text -*-
+$RoughId: syslog.txt,v 1.18 2002/02/25 08:20:14 knu Exp $
+$Id$
+
+UNIX Syslog extension for Ruby
+Amos Gouaux, University of Texas at Dallas
+<amos+ruby@utdallas.edu>
+&
+Akinori MUSHA
+<knu@iDaemons.org>
+
+Contact:
+ - Akinori MUSHA <knu@iDaemons.org> (current maintainer)
+
+** Syslog(Module)
+
+Included Modules: Syslog::Constants
+
+require 'syslog'
+
+A Simple wrapper for the UNIX syslog system calls that might be handy
+if you're writing a server in Ruby. For the details of the syslog(8)
+architecture and constants, see the syslog(3) manual page of your
+platform.
+
+Module Methods:
+
+ open(ident = $0, logopt = Syslog::LOG_PID | Syslog::LOG_CONS,
+ facility = Syslog::LOG_USER) [{ |syslog| ... }]
+
+ Opens syslog with the given options and returns the module
+ itself. If a block is given, calls it with an argument of
+ itself. If syslog is already opened, raises RuntimeError.
+
+ Example:
+ Syslog.open('ftpd', Syslog::LOG_PID | Syslog::LOG_NDELAY,
+ Syslog::LOG_FTP)
+
+ open!(ident = $0, logopt = Syslog::LOG_PID | Syslog::LOG_CONS,
+ facility = Syslog::LOG_USER)
+ reopen(ident = $0, logopt = Syslog::LOG_PID | Syslog::LOG_CONS,
+ facility = Syslog::LOG_USER)
+
+ Same as open, but does a close first.
+
+ opened?
+
+ Returns true if syslog opened, otherwise false.
+
+ ident
+ options
+ facility
+
+ Returns the parameters given in the last open, respectively.
+ Every call of Syslog::open resets these values.
+
+ log(pri, message, ...)
+
+ Writes message to syslog.
+
+ Example:
+ Syslog.log(Syslog::LOG_CRIT, "the sky is falling in %d seconds!", 10)
+
+ crit(message, ...)
+ emerg(message, ...)
+ alert(message, ...)
+ err(message, ...)
+ warning(message, ...)
+ notice(message, ...)
+ info(message, ...)
+ debug(message, ...)
+
+ These are shortcut methods of Syslog::log(). The lineup may
+ vary depending on what priorities are defined on your system.
+
+ Example:
+ Syslog.crit("the sky is falling in %d seconds!", 5)
+
+ mask
+ mask=(mask)
+
+ Returns or sets the log priority mask. The value of the mask
+ is persistent and will not be reset by Syslog::open or
+ Syslog::close.
+
+ Example:
+ Syslog.mask = Syslog::LOG_UPTO(Syslog::LOG_ERR)
+
+ close
+
+ Closes syslog.
+
+ inspect
+
+ Returns the "inspect" string of the Syslog module.
+
+ instance
+
+ Returns the module itself. (Just for backward compatibility)
+
+ LOG_MASK(pri)
+
+ Creates a mask for one priority.
+
+ LOG_UPTO(pri)
+
+ Creates a mask for all priorities up to pri.
+
+** Syslog::Constants(Module)
+
+require 'syslog'
+include Syslog::Constants
+
+This module includes the LOG_* constants available on the system.
+
+Module Methods:
+
+ LOG_MASK(pri)
+
+ Creates a mask for one priority.
+
+ LOG_UPTO(pri)
+
+ Creates a mask for all priorities up to pri.
diff --git a/ext/win32/lib/win32/registry.rb b/ext/win32/lib/win32/registry.rb
index c801b1327b..bda8bb012f 100644
--- a/ext/win32/lib/win32/registry.rb
+++ b/ext/win32/lib/win32/registry.rb
@@ -1,4 +1,4 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
require 'fiddle/import'
module Win32
@@ -258,34 +258,30 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
/^(?:x64|x86_64)/ =~ RUBY_PLATFORM
end
- TEMPLATE_HANDLE = 'J<'
-
def packhandle(h)
- [h].pack(TEMPLATE_HANDLE)
+ win64? ? packqw(h) : packdw(h)
end
def unpackhandle(h)
- (h + [0].pack(TEMPLATE_HANDLE)).unpack1(TEMPLATE_HANDLE)
+ win64? ? unpackqw(h) : unpackdw(h)
end
- TEMPLATE_DWORD = 'V'
-
def packdw(dw)
- [dw].pack(TEMPLATE_DWORD)
+ [dw].pack('V')
end
def unpackdw(dw)
- (dw + [0].pack(TEMPLATE_DWORD)).unpack1(TEMPLATE_DWORD)
+ dw += [0].pack('V')
+ dw.unpack('V')[0]
end
- TEMPLATE_QWORD = 'Q<'
-
def packqw(qw)
- [qw].pack(TEMPLATE_QWORD)
+ [ qw & 0xFFFFFFFF, qw >> 32 ].pack('VV')
end
def unpackqw(qw)
- (qw + [0].pack(TEMPLATE_QWORD)).unpack1(TEMPLATE_QWORD)
+ qw = qw.unpack('VV')
+ (qw[1] << 32) | qw[0]
end
def make_wstr(str)
@@ -326,7 +322,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
size = packdw(0)
name = make_wstr(name)
check RegQueryValueExW.call(hkey, name, 0, type, 0, size)
- data = "\0".b * unpackdw(size)
+ data = "\0".force_encoding('ASCII-8BIT') * unpackdw(size)
check RegQueryValueExW.call(hkey, name, 0, type, data, size)
[ unpackdw(type), data[0, unpackdw(size)] ]
end
@@ -381,7 +377,8 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
def self.expand_environ(str)
str.gsub(Regexp.compile("%([^%]+)%".encode(str.encoding))) {
v = $1.encode(LOCALE)
- (ENV[v] || ENV[v.upcase])&.encode(str.encoding) || $&
+ (e = ENV[v] || ENV[v.upcase]; e.encode(str.encoding) if e) ||
+ $&
}
end
@@ -391,6 +388,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
REG_RESOURCE_LIST REG_FULL_RESOURCE_DESCRIPTOR
REG_RESOURCE_REQUIREMENTS_LIST REG_QWORD
].inject([]) do |ary, type|
+ type.freeze
ary[Constants.const_get(type)] = type
ary
end.freeze
@@ -663,7 +661,7 @@ For detail, see the MSDN[http://msdn.microsoft.com/library/en-us/sysinfo/base/pr
when REG_DWORD
[ type, API.unpackdw(data) ]
when REG_DWORD_BIG_ENDIAN
- [ type, data.unpack1('N') ]
+ [ type, data.unpack('N')[0] ]
when REG_QWORD
[ type, API.unpackqw(data) ]
else
diff --git a/ext/win32/lib/win32/sspi.rb b/ext/win32/lib/win32/sspi.rb
index f382f3cf50..20205fd4d6 100644
--- a/ext/win32/lib/win32/sspi.rb
+++ b/ext/win32/lib/win32/sspi.rb
@@ -56,11 +56,11 @@ module Win32
# SecHandle struct
class SecurityHandle
def upper
- @struct.unpack1("x4L")
+ @struct.unpack("LL")[1]
end
def lower
- @struct.unpack1("L")
+ @struct.unpack("LL")[0]
end
def to_p
@@ -129,7 +129,7 @@ module Win32
def unpack
if ! @unpacked && @sec_buffer && @struct
@bufferSize, @type = @sec_buffer.unpack("LL")
- @buffer = @sec_buffer.unpack1("x8P#{@bufferSize}")
+ @buffer = @sec_buffer.unpack("LLP#{@bufferSize}")[2]
@struct = nil
@sec_buffer = nil
@unpacked = true
@@ -181,19 +181,20 @@ module Win32
SEC_E_SECPKG_NOT_FOUND = 0x80090305
SEC_E_UNKNOWN_CREDENTIALS = 0x8009030D
- RESULT_MAP = constants.to_h {|v| [const_get(v), v]}.freeze
+ @@map = {}
+ constants.each { |v| @@map[self.const_get(v.to_s)] = v }
attr_reader :value
def initialize(value)
# convert to unsigned long
- value &= 0xffffffff
- raise "#{value.to_s(16)} is not a recognized result" unless RESULT_MAP.key? value
+ value = [value].pack("L").unpack("L").first
+ raise "#{value.to_s(16)} is not a recognized result" unless @@map.has_key? value
@value = value
end
def to_s
- RESULT_MAP[@value].to_s
+ @@map[@value].to_s
end
def ok?
@@ -201,13 +202,10 @@ module Win32
end
def ==(other)
- case other
- when SSPIResult
+ if other.is_a?(SSPIResult)
@value == other.value
- when Integer
- @value == other
- when Symbol
- RESULT_MAP[@value] == other
+ elsif other.is_a?(Fixnum)
+ @value == @@map[other]
else
false
end
@@ -283,18 +281,18 @@ module Win32
# Nil token OK, just set it to empty string
token = "" if token.nil?
- if token.start_with? "Negotiate"
+ if token.include? "Negotiate"
# If the Negotiate prefix is passed in, assume we are seeing "Negotiate <token>" and get the token.
- token = token.split(" ", 2).last
+ token = token.split(" ").last
end
- if token.start_with? B64_TOKEN_PREFIX
+ if token.include? B64_TOKEN_PREFIX
# indicates base64 encoded token
- token = token.strip.unpack1("m")
+ token = token.strip.unpack("m")[0]
end
outputBuffer = SecurityBuffer.new
- result = SSPIResult.new(API::InitializeSecurityContextA.call(@credentials.to_p, @context.to_p, nil,
+ result = SSPIResult.new(API::InitializeSecurityContext.call(@credentials.to_p, @context.to_p, nil,
REQUEST_FLAGS, 0, SECURITY_NETWORK_DREP, SecurityBuffer.new(token).to_p, 0,
@context.to_p,
outputBuffer.to_p, @contextAttributes, TimeStamp.new.to_p))
@@ -309,7 +307,7 @@ module Win32
clean_up unless @cleaned_up
end
- private
+ private
def clean_up
# free structures allocated
@@ -332,7 +330,8 @@ module Win32
end
def encode_token(t)
- [t].pack("m0")
+ # encode64 will add newlines every 60 characters so we need to remove those.
+ [t].pack("m").delete("\n")
end
end
end
diff --git a/ext/win32/resolv/extconf.rb b/ext/win32/resolv/extconf.rb
index ac865ec5e1..01f3df730a 100644
--- a/ext/win32/resolv/extconf.rb
+++ b/ext/win32/resolv/extconf.rb
@@ -1,6 +1,3 @@
-require 'mkmf'
if have_library('iphlpapi', 'GetNetworkParams')
create_makefile('win32/resolv')
-else
- File.write('Makefile', "all clean install:\n\t@echo Done: $(@)\n")
end
diff --git a/ext/win32ole/.document b/ext/win32ole/.document
deleted file mode 100644
index decba0135a..0000000000
--- a/ext/win32ole/.document
+++ /dev/null
@@ -1 +0,0 @@
-*.[ch]
diff --git a/ext/win32ole/lib/win32ole.rb b/ext/win32ole/lib/win32ole.rb
index f5c8a52c4a..d7034f7845 100644
--- a/ext/win32ole/lib/win32ole.rb
+++ b/ext/win32ole/lib/win32ole.rb
@@ -5,6 +5,7 @@ rescue LoadError
end
if defined?(WIN32OLE)
+ # WIN32OLE
class WIN32OLE
#
@@ -25,7 +26,7 @@ if defined?(WIN32OLE)
def ole_methods_safely
ole_methods
- rescue WIN32OLE::QueryInterfaceError
+ rescue WIN32OLEQueryInterfaceError
[]
end
end
diff --git a/ext/win32ole/lib/win32ole/property.rb b/ext/win32ole/lib/win32ole/property.rb
index 558056b32b..fea047cd19 100644
--- a/ext/win32ole/lib/win32ole/property.rb
+++ b/ext/win32ole/lib/win32ole/property.rb
@@ -1,12 +1,7 @@
# frozen_string_literal: false
-
-class WIN32OLE
-end
-
-# OLEProperty is a helper class of Property with arguments, used by
-# `olegen.rb`-generated files.
-class WIN32OLE::Property
- # :stopdoc:
+# OLEProperty
+# helper class of Property with arguments.
+class OLEProperty
def initialize(obj, dispid, gettypes, settypes)
@obj = obj
@dispid = dispid
@@ -19,11 +14,4 @@ class WIN32OLE::Property
def []=(*args)
@obj._setproperty(@dispid, args, @settypes)
end
- # :stopdoc:
-end
-
-module WIN32OLE::VariantType
- # Alias for `olegen.rb`-generated files, that should include
- # WIN32OLE::VARIANT.
- OLEProperty = WIN32OLE::Property
end
diff --git a/sample/win32ole/excel1.rb b/ext/win32ole/sample/excel1.rb
index 4fe1d0c2a9..4fe1d0c2a9 100644
--- a/sample/win32ole/excel1.rb
+++ b/ext/win32ole/sample/excel1.rb
diff --git a/sample/win32ole/excel2.rb b/ext/win32ole/sample/excel2.rb
index 47a5715f84..47a5715f84 100644
--- a/sample/win32ole/excel2.rb
+++ b/ext/win32ole/sample/excel2.rb
diff --git a/sample/win32ole/excel3.rb b/ext/win32ole/sample/excel3.rb
index 72aee2a929..72aee2a929 100644
--- a/sample/win32ole/excel3.rb
+++ b/ext/win32ole/sample/excel3.rb
diff --git a/sample/win32ole/ie.rb b/ext/win32ole/sample/ie.rb
index 4db64eed30..4db64eed30 100644
--- a/sample/win32ole/ie.rb
+++ b/ext/win32ole/sample/ie.rb
diff --git a/sample/win32ole/ieconst.rb b/ext/win32ole/sample/ieconst.rb
index 363a4f8153..363a4f8153 100644
--- a/sample/win32ole/ieconst.rb
+++ b/ext/win32ole/sample/ieconst.rb
diff --git a/sample/win32ole/ienavi.rb b/ext/win32ole/sample/ienavi.rb
index 5d0536028b..5d0536028b 100644
--- a/sample/win32ole/ienavi.rb
+++ b/ext/win32ole/sample/ienavi.rb
diff --git a/sample/win32ole/ienavi2.rb b/ext/win32ole/sample/ienavi2.rb
index 3248393077..3248393077 100644
--- a/sample/win32ole/ienavi2.rb
+++ b/ext/win32ole/sample/ienavi2.rb
diff --git a/sample/win32ole/oledirs.rb b/ext/win32ole/sample/oledirs.rb
index e52a0fd7ac..e52a0fd7ac 100644
--- a/sample/win32ole/oledirs.rb
+++ b/ext/win32ole/sample/oledirs.rb
diff --git a/ext/win32ole/sample/olegen.rb b/ext/win32ole/sample/olegen.rb
new file mode 100644
index 0000000000..4b088a774f
--- /dev/null
+++ b/ext/win32ole/sample/olegen.rb
@@ -0,0 +1,348 @@
+# frozen_string_literal: false
+#-----------------------------
+# olegen.rb
+# $Revision$
+#-----------------------------
+
+require 'win32ole'
+
+class WIN32COMGen
+ def initialize(typelib)
+ @typelib = typelib
+ @receiver = ""
+ end
+ attr_reader :typelib
+
+ def ole_classes(typelib)
+ begin
+ @ole = WIN32OLE.new(typelib)
+ [@ole.ole_obj_help]
+ rescue
+ WIN32OLE_TYPE.ole_classes(typelib)
+ end
+ end
+
+ def generate_args(method)
+ args = []
+ if method.size_opt_params >= 0
+ size_required_params = method.size_params - method.size_opt_params
+ else
+ size_required_params = method.size_params - 1
+ end
+ size_required_params.times do |i|
+ if method.params[i] && method.params[i].optional?
+ args.push "arg#{i}=nil"
+ else
+ args.push "arg#{i}"
+ end
+ end
+ if method.size_opt_params >= 0
+ method.size_opt_params.times do |i|
+ args.push "arg#{i + size_required_params}=nil"
+ end
+ else
+ args.push "*arg"
+ end
+ args.join(", ")
+ end
+
+ def generate_argtype(typedetails)
+ ts = ''
+ typedetails.each do |t|
+ case t
+ when 'CARRAY', 'VOID', 'UINT', 'RESULT', 'DECIMAL', 'I8', 'UI8'
+# raise "Sorry type\"" + t + "\" not supported"
+ ts << "\"??? NOT SUPPORTED TYPE:`#{t}'\""
+ when 'USERDEFINED', 'Unknown Type 9'
+ ts << 'VT_DISPATCH'
+ break;
+ when 'SAFEARRAY'
+ ts << 'VT_ARRAY|'
+ when 'PTR'
+ ts << 'VT_BYREF|'
+ when 'INT'
+ ts << 'VT_I4'
+ else
+ if String === t
+ ts << 'VT_' + t
+ end
+ end
+ end
+ if ts.empty?
+ ts = 'VT_VARIANT'
+ elsif ts[-1] == ?|
+ ts += 'VT_VARIANT'
+ end
+ ts
+ end
+
+ def generate_argtypes(method, proptypes)
+ types = method.params.collect{|param|
+ generate_argtype(param.ole_type_detail)
+ }.join(", ")
+ if proptypes
+ types += ", " if types.size > 0
+ types += generate_argtype(proptypes)
+ end
+ types
+ end
+
+ def generate_method_body(method, disptype, types=nil)
+ " ret = #{@receiver}#{disptype}(#{method.dispid}, [" +
+ generate_args(method).gsub("=nil", "") +
+ "], [" +
+ generate_argtypes(method, types) +
+ "])\n" +
+ " @lastargs = WIN32OLE::ARGV\n" +
+ " ret"
+ end
+
+ def generate_method_help(method, type = nil)
+ str = " # "
+ if type
+ str += type
+ else
+ str += method.return_type
+ end
+ str += " #{method.name}"
+ if method.event?
+ str += " EVENT"
+ str += " in #{method.event_interface}"
+ end
+ if method.helpstring && method.helpstring != ""
+ str += "\n # "
+ str += method.helpstring
+ end
+ args_help = generate_method_args_help(method)
+ if args_help
+ str += "\n"
+ str += args_help
+ end
+ str
+ end
+
+ def generate_method_args_help(method)
+ args = []
+ method.params.each_with_index {|param, i|
+ h = " # #{param.ole_type} arg#{i} --- #{param.name}"
+ inout = []
+ inout.push "IN" if param.input?
+ inout.push "OUT" if param.output?
+ h += " [#{inout.join('/')}]"
+ h += " ( = #{param.default})" if param.default
+ args.push h
+ }
+ if args.size > 0
+ args.join("\n")
+ else
+ nil
+ end
+ end
+
+ def generate_method(method, disptype, io = STDOUT, types = nil)
+ io.puts "\n"
+ io.puts generate_method_help(method)
+ if method.invoke_kind == 'PROPERTYPUT'
+ io.print " def #{method.name}=("
+ else
+ io.print " def #{method.name}("
+ end
+ io.print generate_args(method)
+ io.puts ")"
+ io.puts generate_method_body(method, disptype, types)
+ io.puts " end"
+ end
+
+ def generate_propputref_methods(klass, io = STDOUT)
+ klass.ole_methods.select {|method|
+ method.invoke_kind == 'PROPERTYPUTREF' && method.visible?
+ }.each do |method|
+ generate_method(method, io)
+ end
+ end
+
+ def generate_properties_with_args(klass, io = STDOUT)
+ klass.ole_methods.select {|method|
+ method.invoke_kind == 'PROPERTYGET' &&
+ method.visible? &&
+ method.size_params > 0
+ }.each do |method|
+ types = method.return_type_detail
+ io.puts "\n"
+ io.puts generate_method_help(method, types[0])
+ io.puts " def #{method.name}"
+ if klass.ole_type == "Class"
+ io.print " OLEProperty.new(@dispatch, #{method.dispid}, ["
+ else
+ io.print " OLEProperty.new(self, #{method.dispid}, ["
+ end
+ io.print generate_argtypes(method, nil)
+ io.print "], ["
+ io.print generate_argtypes(method, types)
+ io.puts "])"
+ io.puts " end"
+ end
+ end
+
+ def generate_propput_methods(klass, io = STDOUT)
+ klass.ole_methods.select {|method|
+ method.invoke_kind == 'PROPERTYPUT' && method.visible? &&
+ method.size_params == 1
+ }.each do |method|
+ ms = klass.ole_methods.select {|m|
+ m.invoke_kind == 'PROPERTYGET' &&
+ m.dispid == method.dispid
+ }
+ types = []
+ if ms.size == 1
+ types = ms[0].return_type_detail
+ end
+ generate_method(method, '_setproperty', io, types)
+ end
+ end
+
+ def generate_propget_methods(klass, io = STDOUT)
+ klass.ole_methods.select {|method|
+ method.invoke_kind == 'PROPERTYGET' && method.visible? &&
+ method.size_params == 0
+ }.each do |method|
+ generate_method(method, '_getproperty', io)
+ end
+ end
+
+ def generate_func_methods(klass, io = STDOUT)
+ klass.ole_methods.select {|method|
+ method.invoke_kind == "FUNC" && method.visible?
+ }.each do |method|
+ generate_method(method, '_invoke', io)
+ end
+ end
+
+ def generate_methods(klass, io = STDOUT)
+ generate_propget_methods(klass, io)
+ generate_propput_methods(klass, io)
+ generate_properties_with_args(klass, io)
+ generate_func_methods(klass, io)
+# generate_propputref_methods(klass, io)
+ end
+
+ def generate_constants(klass, io = STDOUT)
+ klass.variables.select {|v|
+ v.visible? && v.variable_kind == 'CONSTANT'
+ }.each do |v|
+ io.print " "
+ io.print v.name.sub(/^./){$&.upcase}
+ io.print " = "
+ io.puts v.value
+ end
+ end
+
+ def class_name(klass)
+ klass_name = klass.name
+ if klass.ole_type == "Class" &&
+ klass.guid &&
+ klass.progid
+ klass_name = klass.progid.gsub(/\./, '_')
+ end
+ if /^[A-Z]/ !~ klass_name || Module.constants.include?(klass_name)
+ klass_name = 'OLE' + klass_name
+ end
+ klass_name
+ end
+
+ def define_initialize(klass)
+ <<STR
+
+ def initialize(obj = nil)
+ @clsid = "#{klass.guid}"
+ @progid = "#{klass.progid}"
+ if obj.nil?
+ @dispatch = WIN32OLE.new @progid
+ else
+ @dispatch = obj
+ end
+ end
+STR
+ end
+
+ def define_include
+ " include WIN32OLE::VARIANT"
+ end
+
+ def define_instance_variables
+ " attr_reader :lastargs"
+ end
+
+ def define_method_missing
+ <<STR
+
+ def method_missing(cmd, *arg)
+ @dispatch.method_missing(cmd, *arg)
+ end
+STR
+ end
+
+ def define_class(klass, io = STDOUT)
+ io.puts "class #{class_name(klass)} # #{klass.name}"
+ io.puts define_include
+ io.puts define_instance_variables
+ io.puts " attr_reader :dispatch"
+ io.puts " attr_reader :clsid"
+ io.puts " attr_reader :progid"
+ io.puts define_initialize(klass)
+ io.puts define_method_missing
+ end
+
+ def define_module(klass, io = STDOUT)
+ io.puts "module #{class_name(klass)}"
+ io.puts define_include
+ io.puts define_instance_variables
+ end
+
+ def generate_class(klass, io = STDOUT)
+ io.puts "\n# #{klass.helpstring}"
+ if klass.ole_type == "Class" &&
+ klass.guid &&
+ klass.progid
+ @receiver = "@dispatch."
+ define_class(klass, io)
+ else
+ @receiver = ""
+ define_module(klass, io)
+ end
+ generate_constants(klass, io)
+ generate_methods(klass, io)
+ io.puts "end"
+ end
+
+ def generate(io = STDOUT)
+ io.puts "require 'win32ole'"
+ io.puts "require 'win32ole/property'"
+
+ ole_classes(typelib).select{|klass|
+ klass.visible? &&
+ (klass.ole_type == "Class" ||
+ klass.ole_type == "Interface" ||
+ klass.ole_type == "Dispatch" ||
+ klass.ole_type == "Enum")
+ }.each do |klass|
+ generate_class(klass, io)
+ end
+ begin
+ @ole.quit if @ole
+ rescue
+ end
+ end
+end
+
+require 'win32ole'
+if __FILE__ == $0
+ if ARGV.size == 0
+ $stderr.puts "usage: #{$0} Type Library [...]"
+ exit 1
+ end
+ ARGV.each do |typelib|
+ comgen = WIN32COMGen.new(typelib)
+ comgen.generate
+ end
+end
diff --git a/sample/win32ole/xml.rb b/ext/win32ole/sample/xml.rb
index 5a239c9336..5a239c9336 100644
--- a/sample/win32ole/xml.rb
+++ b/ext/win32ole/sample/xml.rb
diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c
index cabbeb8431..3f083bb12d 100644
--- a/ext/win32ole/win32ole.c
+++ b/ext/win32ole/win32ole.c
@@ -27,7 +27,7 @@
const IID IID_IMultiLanguage2 = {0xDCCFC164, 0x2B38, 0x11d2, {0xB7, 0xEC, 0x00, 0xC0, 0x4F, 0x8F, 0x5D, 0x9A}};
#endif
-#define WIN32OLE_VERSION "1.8.10"
+#define WIN32OLE_VERSION "1.8.8"
typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX)
(REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*);
@@ -1426,10 +1426,9 @@ ole_variant2val(VARIANT *pvar)
vt = V_VT(pvar);
}
-#define ARG_AS(type, pvar) (V_ISBYREF(pvar) ? *V_##type##REF(pvar) : V_##type(pvar))
if(V_ISARRAY(pvar)) {
VARTYPE vt_base = vt & VT_TYPEMASK;
- SAFEARRAY *psa = ARG_AS(ARRAY, pvar);
+ SAFEARRAY *psa = V_ISBYREF(pvar) ? *V_ARRAYREF(pvar) : V_ARRAY(pvar);
UINT i = 0;
LONG *pid, *plb, *pub;
VARIANT variant;
@@ -1496,58 +1495,109 @@ ole_variant2val(VARIANT *pvar)
case VT_NULL:
break;
case VT_I1:
- obj = RB_INT2NUM((long)ARG_AS(I1, pvar));
+ if(V_ISBYREF(pvar))
+ obj = RB_INT2NUM((long)*V_I1REF(pvar));
+ else
+ obj = RB_INT2NUM((long)V_I1(pvar));
break;
case VT_UI1:
- obj = RB_INT2NUM((long)ARG_AS(UI1, pvar));
+ if(V_ISBYREF(pvar))
+ obj = RB_INT2NUM((long)*V_UI1REF(pvar));
+ else
+ obj = RB_INT2NUM((long)V_UI1(pvar));
break;
case VT_I2:
- obj = RB_INT2NUM((long)ARG_AS(I2, pvar));
+ if(V_ISBYREF(pvar))
+ obj = RB_INT2NUM((long)*V_I2REF(pvar));
+ else
+ obj = RB_INT2NUM((long)V_I2(pvar));
break;
case VT_UI2:
- obj = RB_INT2NUM((long)ARG_AS(UI2, pvar));
+ if(V_ISBYREF(pvar))
+ obj = RB_INT2NUM((long)*V_UI2REF(pvar));
+ else
+ obj = RB_INT2NUM((long)V_UI2(pvar));
break;
case VT_I4:
- obj = RB_INT2NUM((long)ARG_AS(I4, pvar));
+ if(V_ISBYREF(pvar))
+ obj = RB_INT2NUM((long)*V_I4REF(pvar));
+ else
+ obj = RB_INT2NUM((long)V_I4(pvar));
break;
case VT_UI4:
- obj = RB_INT2NUM((long)ARG_AS(UI4, pvar));
+ if(V_ISBYREF(pvar))
+ obj = RB_INT2NUM((long)*V_UI4REF(pvar));
+ else
+ obj = RB_INT2NUM((long)V_UI4(pvar));
break;
case VT_INT:
- obj = RB_INT2NUM((long)ARG_AS(INT, pvar));
+ if(V_ISBYREF(pvar))
+ obj = RB_INT2NUM((long)*V_INTREF(pvar));
+ else
+ obj = RB_INT2NUM((long)V_INT(pvar));
break;
case VT_UINT:
- obj = RB_INT2NUM((long)ARG_AS(UINT, pvar));
+ if(V_ISBYREF(pvar))
+ obj = RB_INT2NUM((long)*V_UINTREF(pvar));
+ else
+ obj = RB_INT2NUM((long)V_UINT(pvar));
break;
#if (defined(_MSC_VER) && (_MSC_VER >= 1300)) || defined(__CYGWIN__) || defined(__MINGW32__)
case VT_I8:
- obj = I8_2_NUM(ARG_AS(I8, pvar));
+ if(V_ISBYREF(pvar))
+#if (defined(_MSC_VER) && (_MSC_VER >= 1300)) || defined(__CYGWIN__) || defined(__MINGW32__)
+#ifdef V_I8REF
+ obj = I8_2_NUM(*V_I8REF(pvar));
+#endif
+#else
+ obj = Qnil;
+#endif
+ else
+ obj = I8_2_NUM(V_I8(pvar));
break;
case VT_UI8:
- obj = UI8_2_NUM(ARG_AS(UI8, pvar));
+ if(V_ISBYREF(pvar))
+#if (defined(_MSC_VER) && (_MSC_VER >= 1300)) || defined(__CYGWIN__) || defined(__MINGW32__)
+#ifdef V_UI8REF
+ obj = UI8_2_NUM(*V_UI8REF(pvar));
+#endif
+#else
+ obj = Qnil;
+#endif
+ else
+ obj = UI8_2_NUM(V_UI8(pvar));
break;
#endif /* (defined(_MSC_VER) && (_MSC_VER >= 1300)) || defined(__CYGWIN__) || defined(__MINGW32__) */
case VT_R4:
- obj = rb_float_new(ARG_AS(R4, pvar));
+ if(V_ISBYREF(pvar))
+ obj = rb_float_new(*V_R4REF(pvar));
+ else
+ obj = rb_float_new(V_R4(pvar));
break;
case VT_R8:
- obj = rb_float_new(ARG_AS(R8, pvar));
+ if(V_ISBYREF(pvar))
+ obj = rb_float_new(*V_R8REF(pvar));
+ else
+ obj = rb_float_new(V_R8(pvar));
break;
case VT_BSTR:
{
BSTR bstr;
- bstr = ARG_AS(BSTR, pvar);
+ if(V_ISBYREF(pvar))
+ bstr = *V_BSTRREF(pvar);
+ else
+ bstr = V_BSTR(pvar);
obj = (SysStringLen(bstr) == 0)
? rb_str_new2("")
: ole_wc2vstr(bstr, FALSE);
@@ -1555,18 +1605,27 @@ ole_variant2val(VARIANT *pvar)
}
case VT_ERROR:
- obj = RB_INT2NUM(ARG_AS(ERROR, pvar));
+ if(V_ISBYREF(pvar))
+ obj = RB_INT2NUM(*V_ERRORREF(pvar));
+ else
+ obj = RB_INT2NUM(V_ERROR(pvar));
break;
case VT_BOOL:
- obj = (ARG_AS(BOOL, pvar) ? Qtrue : Qfalse);
+ if (V_ISBYREF(pvar))
+ obj = (*V_BOOLREF(pvar) ? Qtrue : Qfalse);
+ else
+ obj = (V_BOOL(pvar) ? Qtrue : Qfalse);
break;
case VT_DISPATCH:
{
IDispatch *pDispatch;
- pDispatch = ARG_AS(DISPATCH, pvar);
+ if (V_ISBYREF(pvar))
+ pDispatch = *V_DISPATCHREF(pvar);
+ else
+ pDispatch = V_DISPATCH(pvar);
if (pDispatch != NULL ) {
OLE_ADDREF(pDispatch);
@@ -1583,7 +1642,10 @@ ole_variant2val(VARIANT *pvar)
void *p;
HRESULT hr;
- punk = ARG_AS(UNKNOWN, pvar);
+ if (V_ISBYREF(pvar))
+ punk = *V_UNKNOWNREF(pvar);
+ else
+ punk = V_UNKNOWN(pvar);
if(punk != NULL) {
hr = punk->lpVtbl->QueryInterface(punk, &IID_IDispatch, &p);
@@ -1598,7 +1660,10 @@ ole_variant2val(VARIANT *pvar)
case VT_DATE:
{
DATE date;
- date = ARG_AS(DATE, pvar);
+ if(V_ISBYREF(pvar))
+ date = *V_DATEREF(pvar);
+ else
+ date = V_DATE(pvar);
obj = vtdate2rbtime(date);
break;
@@ -1628,7 +1693,6 @@ ole_variant2val(VARIANT *pvar)
}
}
return obj;
-#undef ARG_AS
}
LONG
@@ -1898,7 +1962,7 @@ ole_bind_obj(VALUE moniker, int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * connect(ole) --> aWIN32OLE
+ * WIN32OLE.connect( ole ) --> aWIN32OLE
*
* Returns running OLE Automation object or WIN32OLE object from moniker.
* 1st argument should be OLE program id or class id or moniker.
@@ -1955,7 +2019,7 @@ fole_s_connect(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * const_load(ole, mod = WIN32OLE)
+ * WIN32OLE.const_load( ole, mod = WIN32OLE)
*
* Defines the constants of OLE Automation server as mod's constants.
* The first argument is WIN32OLE object or type library name.
@@ -2060,7 +2124,7 @@ reference_count(struct oledata * pole)
/*
* call-seq:
- * ole_reference_count(aWIN32OLE) --> number
+ * WIN32OLE.ole_reference_count(aWIN32OLE) --> number
*
* Returns reference counter of Dispatch interface of WIN32OLE object.
* You should not use this method because this method
@@ -2076,7 +2140,7 @@ fole_s_reference_count(VALUE self, VALUE obj)
/*
* call-seq:
- * ole_free(aWIN32OLE) --> number
+ * WIN32OLE.ole_free(aWIN32OLE) --> number
*
* Invokes Release method of Dispatch interface of WIN32OLE object.
* You should not use this method because this method
@@ -2120,10 +2184,10 @@ ole_show_help(VALUE helpfile, VALUE helpcontext)
/*
* call-seq:
- * ole_show_help(obj [,helpcontext])
+ * WIN32OLE.ole_show_help(obj [,helpcontext])
*
- * Displays helpfile. The 1st argument specifies WIN32OLE::Type
- * object or WIN32OLE::Method object or helpfile.
+ * Displays helpfile. The 1st argument specifies WIN32OLE_TYPE
+ * object or WIN32OLE_METHOD object or helpfile.
*
* excel = WIN32OLE.new('Excel.Application')
* typeobj = excel.ole_type
@@ -2151,7 +2215,7 @@ fole_s_show_help(int argc, VALUE *argv, VALUE self)
helpfile = target;
}
if (!RB_TYPE_P(helpfile, T_STRING)) {
- rb_raise(rb_eTypeError, "1st parameter must be (String|WIN32OLE::Type|WIN32OLE::Method)");
+ rb_raise(rb_eTypeError, "1st parameter must be (String|WIN32OLE_TYPE|WIN32OLE_METHOD)");
}
hwnd = ole_show_help(helpfile, helpcontext);
if(hwnd == 0) {
@@ -2163,7 +2227,7 @@ fole_s_show_help(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * codepage
+ * WIN32OLE.codepage
*
* Returns current codepage.
* WIN32OLE.codepage # => WIN32OLE::CP_ACP
@@ -2194,7 +2258,7 @@ code_page_installed(UINT cp)
/*
* call-seq:
- * codepage = CP
+ * WIN32OLE.codepage = CP
*
* Sets current codepage.
* The WIN32OLE.codepage is initialized according to
@@ -2218,7 +2282,7 @@ fole_s_set_code_page(VALUE self, VALUE vcp)
/*
* call-seq:
- * locale -> locale id.
+ * WIN32OLE.locale -> locale id.
*
* Returns current locale id (lcid). The default locale is
* WIN32OLE::LOCALE_SYSTEM_DEFAULT.
@@ -2252,12 +2316,12 @@ lcid_installed(LCID lcid)
/*
* call-seq:
- * locale = lcid
+ * WIN32OLE.locale = lcid
*
* Sets current locale id (lcid).
*
* WIN32OLE.locale = 1033 # set locale English(U.S)
- * obj = WIN32OLE::Variant.new("$100,000", WIN32OLE::VARIANT::VT_CY)
+ * obj = WIN32OLE_VARIANT.new("$100,000", WIN32OLE::VARIANT::VT_CY)
*
*/
static VALUE
@@ -2281,7 +2345,7 @@ fole_s_set_locale(VALUE self, VALUE vlcid)
/*
* call-seq:
- * create_guid
+ * WIN32OLE.create_guid
*
* Creates GUID.
* WIN32OLE.create_guid # => {1CB530F1-F6B1-404D-BCE6-1959BF91F4A8}
@@ -2329,9 +2393,9 @@ fole_s_ole_uninitialize(VALUE self)
/*
* Document-class: WIN32OLE
*
- * +WIN32OLE+ objects represent OLE Automation object in Ruby.
+ * <code>WIN32OLE</code> objects represent OLE Automation object in Ruby.
*
- * By using +WIN32OLE+, you can access OLE server like VBScript.
+ * By using WIN32OLE, you can access OLE server like VBScript.
*
* Here is sample script.
*
@@ -2355,18 +2419,18 @@ fole_s_ole_uninitialize(VALUE self)
* excel.ActiveWorkbook.Close(0);
* excel.Quit();
*
- * Unfortunately, +WIN32OLE+ doesn't support the argument passed by
+ * Unfortunately, Win32OLE doesn't support the argument passed by
* reference directly.
- * Instead, +WIN32OLE+ provides WIN32OLE::ARGV or WIN32OLE::Variant object.
+ * Instead, Win32OLE provides WIN32OLE::ARGV or WIN32OLE_VARIANT object.
* If you want to get the result value of argument passed by reference,
- * you can use WIN32OLE::ARGV or WIN32OLE::Variant.
+ * you can use WIN32OLE::ARGV or WIN32OLE_VARIANT.
*
* oleobj.method(arg1, arg2, refargv3)
* puts WIN32OLE::ARGV[2] # the value of refargv3 after called oleobj.method
*
* or
*
- * refargv3 = WIN32OLE::Variant.new(XXX,
+ * refargv3 = WIN32OLE_VARIANT.new(XXX,
* WIN32OLE::VARIANT::VT_BYREF|WIN32OLE::VARIANT::VT_XXX)
* oleobj.method(arg1, arg2, refargv3)
* p refargv3.value # the value of refargv3 after called oleobj.method.
@@ -2375,7 +2439,7 @@ fole_s_ole_uninitialize(VALUE self)
/*
* call-seq:
- * new(server, [host]) -> WIN32OLE object
+ * WIN32OLE.new(server, [host]) -> WIN32OLE object
* WIN32OLE.new(server, license: 'key') -> WIN32OLE object
*
* Returns a new WIN32OLE object(OLE Automation object).
@@ -2762,7 +2826,7 @@ ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket)
/*
* call-seq:
- * invoke(method, [arg1,...]) => return value of method.
+ * WIN32OLE#invoke(method, [arg1,...]) => return value of method.
*
* Runs OLE method.
* The first argument specifies the method name of OLE Automation object.
@@ -2974,7 +3038,7 @@ ole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types, USHORT dispkind)
/*
* call-seq:
- * _invoke(dispid, args, types)
+ * WIN32OLE#_invoke(dispid, args, types)
*
* Runs the early binding method.
* The 1st argument specifies dispatch ID,
@@ -2992,7 +3056,7 @@ fole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types)
/*
* call-seq:
- * _getproperty(dispid, args, types)
+ * WIN32OLE#_getproperty(dispid, args, types)
*
* Runs the early binding method to get property.
* The 1st argument specifies dispatch ID,
@@ -3010,7 +3074,7 @@ fole_getproperty2(VALUE self, VALUE dispid, VALUE args, VALUE types)
/*
* call-seq:
- * _setproperty(dispid, args, types)
+ * WIN32OLE#_setproperty(dispid, args, types)
*
* Runs the early binding method to set property.
* The 1st argument specifies dispatch ID,
@@ -3056,7 +3120,7 @@ fole_setproperty_with_bracket(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * setproperty('property', [arg1, arg2,...] val)
+ * WIN32OLE.setproperty('property', [arg1, arg2,...] val)
*
* Sets property of OLE object.
* When you want to set property with argument, you can use this method.
@@ -3162,7 +3226,7 @@ ole_propertyput(VALUE self, VALUE property, VALUE value)
/*
* call-seq:
- * ole_free
+ * WIN32OLE#ole_free
*
* invokes Release method of Dispatch interface of WIN32OLE object.
* Usually, you do not need to call this method because Release method
@@ -3205,7 +3269,7 @@ ole_ienum_free(VALUE pEnumV)
/*
* call-seq:
- * each {|i|...}
+ * WIN32OLE#each {|i|...}
*
* Iterates over each item of OLE collection which has IEnumVARIANT interface.
*
@@ -3276,7 +3340,7 @@ fole_each(VALUE self)
/*
* call-seq:
- * method_missing(id [,arg1, arg2, ...])
+ * WIN32OLE#method_missing(id [,arg1, arg2, ...])
*
* Calls WIN32OLE#invoke method.
*/
@@ -3374,9 +3438,9 @@ ole_methods(VALUE self, int mask)
/*
* call-seq:
- * ole_methods
+ * WIN32OLE#ole_methods
*
- * Returns the array of WIN32OLE::Method object.
+ * Returns the array of WIN32OLE_METHOD object.
* The element is OLE method of WIN32OLE object.
*
* excel = WIN32OLE.new('Excel.Application')
@@ -3391,9 +3455,9 @@ fole_methods(VALUE self)
/*
* call-seq:
- * ole_get_methods
+ * WIN32OLE#ole_get_methods
*
- * Returns the array of WIN32OLE::Method object .
+ * Returns the array of WIN32OLE_METHOD object .
* The element of the array is property (gettable) of WIN32OLE object.
*
* excel = WIN32OLE.new('Excel.Application')
@@ -3407,9 +3471,9 @@ fole_get_methods(VALUE self)
/*
* call-seq:
- * ole_put_methods
+ * WIN32OLE#ole_put_methods
*
- * Returns the array of WIN32OLE::Method object .
+ * Returns the array of WIN32OLE_METHOD object .
* The element of the array is property (settable) of WIN32OLE object.
*
* excel = WIN32OLE.new('Excel.Application')
@@ -3423,9 +3487,9 @@ fole_put_methods(VALUE self)
/*
* call-seq:
- * ole_func_methods
+ * WIN32OLE#ole_func_methods
*
- * Returns the array of WIN32OLE::Method object .
+ * Returns the array of WIN32OLE_METHOD object .
* The element of the array is property (settable) of WIN32OLE object.
*
* excel = WIN32OLE.new('Excel.Application')
@@ -3440,9 +3504,9 @@ fole_func_methods(VALUE self)
/*
* call-seq:
- * ole_type
+ * WIN32OLE#ole_type
*
- * Returns WIN32OLE::Type object.
+ * Returns WIN32OLE_TYPE object.
*
* excel = WIN32OLE.new('Excel.Application')
* tobj = excel.ole_type
@@ -3465,16 +3529,16 @@ fole_type(VALUE self)
type = ole_type_from_itypeinfo(pTypeInfo);
OLE_RELEASE(pTypeInfo);
if (type == Qnil) {
- rb_raise(rb_eRuntimeError, "failed to create WIN32OLE::Type obj from ITypeInfo");
+ rb_raise(rb_eRuntimeError, "failed to create WIN32OLE_TYPE obj from ITypeInfo");
}
return type;
}
/*
* call-seq:
- * ole_typelib -> The WIN32OLE_TYPELIB object
+ * WIN32OLE#ole_typelib -> The WIN32OLE_TYPELIB object
*
- * Returns the WIN32OLE::TypeLib object. The object represents the
+ * Returns the WIN32OLE_TYPELIB object. The object represents the
* type library which contains the WIN32OLE object.
*
* excel = WIN32OLE.new('Excel.Application')
@@ -3506,7 +3570,7 @@ fole_typelib(VALUE self)
/*
* call-seq:
- * ole_query_interface(iid) -> WIN32OLE object
+ * WIN32OLE#ole_query_interface(iid) -> WIN32OLE object
*
* Returns WIN32OLE object for a specific dispatch or dual
* interface specified by iid.
@@ -3552,7 +3616,7 @@ fole_query_interface(VALUE self, VALUE str_iid)
/*
* call-seq:
- * ole_respond_to?(method) -> true or false
+ * WIN32OLE#ole_respond_to?(method) -> true or false
*
* Returns true when OLE object has OLE method, otherwise returns false.
*
@@ -3761,9 +3825,9 @@ ole_typedesc2val(ITypeInfo *pTypeInfo, TYPEDESC *pTypeDesc, VALUE typedetails)
/*
* call-seq:
- * ole_method_help(method)
+ * WIN32OLE#ole_method_help(method)
*
- * Returns WIN32OLE::Method object corresponding with method
+ * Returns WIN32OLE_METHOD object corresponding with method
* specified by 1st argument.
*
* excel = WIN32OLE.new('Excel.Application')
@@ -3795,7 +3859,7 @@ fole_method_help(VALUE self, VALUE cmdname)
/*
* call-seq:
- * ole_activex_initialize() -> Qnil
+ * WIN32OLE#ole_activex_initialize() -> Qnil
*
* Initialize WIN32OLE object(ActiveX Control) by calling
* IPersistMemory::InitNew.
@@ -4009,7 +4073,7 @@ Init_win32ole(void)
* p c # => 0
* p WIN32OLE::ARGV # => [10, 20, 30]
*
- * You can use WIN32OLE::Variant object to retrieve the value of reference
+ * You can use WIN32OLE_VARIANT object to retrieve the value of reference
* arguments instead of referring WIN32OLE::ARGV.
*
*/
diff --git a/ext/win32ole/win32ole.gemspec b/ext/win32ole/win32ole.gemspec
index 425942d5a0..b6ea8e8a55 100644
--- a/ext/win32ole/win32ole.gemspec
+++ b/ext/win32ole/win32ole.gemspec
@@ -1,16 +1,6 @@
-source_version = ["", "ext/win32ole/"].find do |dir|
- begin
- break File.open(File.join(__dir__, "#{dir}win32ole.c")) {|f|
- f.gets("\n#define WIN32OLE_VERSION ")
- f.gets[/\s*"(.+)"/, 1]
- }
- rescue Errno::ENOENT
- end
-end
-
Gem::Specification.new do |spec|
spec.name = "win32ole"
- spec.version = source_version
+ spec.version = "1.8.9"
spec.authors = ["Masaki Suketa"]
spec.email = ["suke@ruby-lang.org"]
@@ -23,13 +13,10 @@ Gem::Specification.new do |spec|
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
- pathspecs = %W[
- :(exclude,literal)#{File.basename(__FILE__)}
- :^/bin/ :^/test/ :^/rakelib/ :^/.git* :^/Gemfile* :^/Rakefile*
- ]
- spec.files = IO.popen(%w[git ls-files -z --] + pathspecs, chdir: __dir__, err: IO::NULL, exception: false, &:read).split("\x0")
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
- spec.extensions = "ext/win32ole/extconf.rb"
spec.require_paths = ["lib"]
end
diff --git a/ext/win32ole/win32ole_error.c b/ext/win32ole/win32ole_error.c
index 66b5136dee..2bb5156263 100644
--- a/ext/win32ole/win32ole_error.c
+++ b/ext/win32ole/win32ole_error.c
@@ -67,7 +67,7 @@ void
Init_win32ole_error(void)
{
/*
- * Document-class: WIN32OLE::RuntimeError
+ * Document-class: WIN32OLERuntimeError
*
* Raised when OLE processing failed.
*
@@ -77,20 +77,11 @@ Init_win32ole_error(void)
*
* raises the exception:
*
- * WIN32OLE::RuntimeError: unknown OLE server: `NonExistProgID'
+ * WIN32OLERuntimeError: unknown OLE server: `NonExistProgID'
* HRESULT error code:0x800401f3
* Invalid class string
*
*/
- eWIN32OLERuntimeError = rb_define_class_under(cWIN32OLE, "RuntimeError", rb_eRuntimeError);
- /* Alias of WIN32OLE::RuntimeError, for the backward compatibility */
- rb_define_const(rb_cObject, "WIN32OLERuntimeError", eWIN32OLERuntimeError);
- /*
- * Document-class: WIN32OLE::QueryInterfaceError
- *
- * Raised when OLE query failed.
- */
- eWIN32OLEQueryInterfaceError = rb_define_class_under(cWIN32OLE, "QueryInterfaceError", eWIN32OLERuntimeError);
- /* Alias of WIN32OLE::QueryInterfaceError, for the backward compatibility */
- rb_define_const(rb_cObject, "WIN32OLEQueryInterfaceError", eWIN32OLEQueryInterfaceError);
+ eWIN32OLERuntimeError = rb_define_class("WIN32OLERuntimeError", rb_eRuntimeError);
+ eWIN32OLEQueryInterfaceError = rb_define_class("WIN32OLEQueryInterfaceError", eWIN32OLERuntimeError);
}
diff --git a/ext/win32ole/win32ole_event.c b/ext/win32ole/win32ole_event.c
index ff6835e3e4..45ebf13433 100644
--- a/ext/win32ole/win32ole_event.c
+++ b/ext/win32ole/win32ole_event.c
@@ -1,9 +1,9 @@
#include "win32ole.h"
/*
- * Document-class: WIN32OLE::Event
+ * Document-class: WIN32OLE_EVENT
*
- * +WIN32OLE::Event+ objects controls OLE event.
+ * <code>WIN32OLE_EVENT</code> objects controls OLE event.
*/
RUBY_EXTERN void rb_write_error_str(VALUE mesg);
@@ -974,13 +974,13 @@ ev_advise(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * new(ole, event) #=> WIN32OLE::Event object.
+ * WIN32OLE_EVENT.new(ole, event) #=> WIN32OLE_EVENT object.
*
* Returns OLE event object.
* The first argument specifies WIN32OLE object.
* The second argument specifies OLE event name.
* ie = WIN32OLE.new('InternetExplorer.Application')
- * ev = WIN32OLE::Event.new(ie, 'DWebBrowserEvents')
+ * ev = WIN32OLE_EVENT.new(ie, 'DWebBrowserEvents')
*/
static VALUE
fev_initialize(int argc, VALUE *argv, VALUE self)
@@ -1004,7 +1004,7 @@ ole_msg_loop(void)
/*
* call-seq:
- * message_loop
+ * WIN32OLE_EVENT.message_loop
*
* Translates and dispatches Windows message.
*/
@@ -1052,7 +1052,7 @@ ev_on_event(int argc, VALUE *argv, VALUE self, VALUE is_ary_arg)
/*
* call-seq:
- * on_event([event]){...}
+ * WIN32OLE_EVENT#on_event([event]){...}
*
* Defines the callback event.
* If argument is omitted, this method defines the callback of all events.
@@ -1061,12 +1061,12 @@ ev_on_event(int argc, VALUE *argv, VALUE self, VALUE is_ary_arg)
* use `return' or :return.
*
* ie = WIN32OLE.new('InternetExplorer.Application')
- * ev = WIN32OLE::Event.new(ie)
+ * ev = WIN32OLE_EVENT.new(ie)
* ev.on_event("NavigateComplete") {|url| puts url}
* ev.on_event() {|ev, *args| puts "#{ev} fired"}
*
* ev.on_event("BeforeNavigate2") {|*args|
- * # ...
+ * ...
* # set true to BeforeNavigate reference argument `Cancel'.
* # Cancel is 7-th argument of BeforeNavigate,
* # so you can use 6 as key of hash instead of 'Cancel'.
@@ -1075,7 +1075,7 @@ ev_on_event(int argc, VALUE *argv, VALUE self, VALUE is_ary_arg)
* {:Cancel => true} # or {'Cancel' => true} or {6 => true}
* }
*
- * ev.on_event(event_name) {|*args|
+ * ev.on_event(...) {|*args|
* {:return => 1, :xxx => yyy}
* }
*/
@@ -1087,14 +1087,14 @@ fev_on_event(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * on_event_with_outargs([event]){...}
+ * WIN32OLE_EVENT#on_event_with_outargs([event]){...}
*
* Defines the callback of event.
* If you want modify argument in callback,
- * you could use this method instead of WIN32OLE::Event#on_event.
+ * you could use this method instead of WIN32OLE_EVENT#on_event.
*
* ie = WIN32OLE.new('InternetExplorer.Application')
- * ev = WIN32OLE::Event.new(ie)
+ * ev = WIN32OLE_EVENT.new(ie)
* ev.on_event_with_outargs('BeforeNavigate2') {|*args|
* args.last[6] = true
* }
@@ -1107,18 +1107,18 @@ fev_on_event_with_outargs(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * off_event([event])
+ * WIN32OLE_EVENT#off_event([event])
*
* removes the callback of event.
*
* ie = WIN32OLE.new('InternetExplorer.Application')
- * ev = WIN32OLE::Event.new(ie)
+ * ev = WIN32OLE_EVENT.new(ie)
* ev.on_event('BeforeNavigate2') {|*args|
* args.last[6] = true
* }
- * # ...
+ * ...
* ev.off_event('BeforeNavigate2')
- * # ...
+ * ...
*/
static VALUE
fev_off_event(int argc, VALUE *argv, VALUE self)
@@ -1145,16 +1145,16 @@ fev_off_event(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * unadvise -> nil
+ * WIN32OLE_EVENT#unadvise -> nil
*
- * disconnects OLE server. If this method called, then the WIN32OLE::Event object
+ * disconnects OLE server. If this method called, then the WIN32OLE_EVENT object
* does not receive the OLE server event any more.
* This method is trial implementation.
*
* ie = WIN32OLE.new('InternetExplorer.Application')
- * ev = WIN32OLE::Event.new(ie)
- * ev.on_event() { something }
- * # ...
+ * ev = WIN32OLE_EVENT.new(ie)
+ * ev.on_event() {...}
+ * ...
* ev.unadvise
*
*/
@@ -1201,7 +1201,7 @@ evs_length(void)
/*
* call-seq:
- * handler=
+ * WIN32OLE_EVENT#handler=
*
* sets event handler object. If handler object has onXXX
* method according to XXX event, then onXXX method is called
@@ -1212,7 +1212,7 @@ evs_length(void)
* called and 1-st argument is event name.
*
* If handler object has onXXX method and there is block
- * defined by <code>on_event('XXX'){}</code>,
+ * defined by WIN32OLE_EVENT#on_event('XXX'){},
* then block is executed but handler object method is not called
* when XXX event occurs.
*
@@ -1230,7 +1230,7 @@ evs_length(void)
*
* handler = Handler.new
* ie = WIN32OLE.new('InternetExplorer.Application')
- * ev = WIN32OLE::Event.new(ie)
+ * ev = WIN32OLE_EVENT.new(ie)
* ev.on_event("StatusTextChange") {|*args|
* puts "this block executed."
* puts "handler.onStatusTextChange method is not called."
@@ -1246,7 +1246,7 @@ fev_set_handler(VALUE self, VALUE val)
/*
* call-seq:
- * handler
+ * WIN32OLE_EVENT#handler
*
* returns handler object.
*
@@ -1265,7 +1265,6 @@ Init_win32ole_event(void)
rb_gc_register_mark_object(ary_ole_event);
id_events = rb_intern("events");
cWIN32OLE_EVENT = rb_define_class_under(cWIN32OLE, "Event", rb_cObject);
- /* Alias of WIN32OLE::Event, for the backward compatibility */
rb_define_const(rb_cObject, "WIN32OLE_EVENT", cWIN32OLE_EVENT);
rb_define_singleton_method(cWIN32OLE_EVENT, "message_loop", fev_s_msg_loop, 0);
rb_define_alloc_func(cWIN32OLE_EVENT, fev_s_allocate);
diff --git a/ext/win32ole/win32ole_method.c b/ext/win32ole/win32ole_method.c
index a0278729f0..646fdaf60c 100644
--- a/ext/win32ole/win32ole_method.c
+++ b/ext/win32ole/win32ole_method.c
@@ -216,9 +216,9 @@ create_win32ole_method(ITypeInfo *pTypeInfo, VALUE name)
}
/*
- * Document-class: WIN32OLE::Method
+ * Document-class: WIN32OLE_METHOD
*
- * +WIN32OLE::Method+ objects represent OLE method information.
+ * <code>WIN32OLE_METHOD</code> objects represent OLE method information.
*/
static VALUE
@@ -251,16 +251,16 @@ folemethod_s_allocate(VALUE klass)
/*
* call-seq:
- * WIN32OLE::Method.new(ole_type, method) -> WIN32OLE::Method object
+ * WIN32OLE_METHOD.new(ole_type, method) -> WIN32OLE_METHOD object
*
- * Returns a new WIN32OLE::Method object which represents the information
+ * Returns a new WIN32OLE_METHOD object which represents the information
* about OLE method.
- * The first argument <i>ole_type</i> specifies WIN32OLE::Type object.
+ * The first argument <i>ole_type</i> specifies WIN32OLE_TYPE object.
* The second argument <i>method</i> specifies OLE method name defined OLE class
- * which represents WIN32OLE::Type object.
+ * which represents WIN32OLE_TYPE object.
*
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbook')
- * method = WIN32OLE::Method.new(tobj, 'SaveAs')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
+ * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
*/
static VALUE
folemethod_initialize(VALUE self, VALUE oletype, VALUE method)
@@ -277,19 +277,19 @@ folemethod_initialize(VALUE self, VALUE oletype, VALUE method)
}
}
else {
- rb_raise(rb_eTypeError, "1st argument should be WIN32OLE::Type object");
+ rb_raise(rb_eTypeError, "1st argument should be WIN32OLE_TYPE object");
}
return obj;
}
/*
* call-seq:
- * name
+ * WIN32OLE_METHOD#name
*
* Returns the name of the method.
*
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbook')
- * method = WIN32OLE::Method.new(tobj, 'SaveAs')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
+ * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
* puts method.name # => SaveAs
*
*/
@@ -317,11 +317,11 @@ ole_method_return_type(ITypeInfo *pTypeInfo, UINT method_index)
/*
* call-seq:
- * return_type
+ * WIN32OLE_METHOD#return_type
*
* Returns string of return value type of method.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
- * method = WIN32OLE::Method.new(tobj, 'Add')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
+ * method = WIN32OLE_METHOD.new(tobj, 'Add')
* puts method.return_type # => Workbook
*
*/
@@ -351,11 +351,11 @@ ole_method_return_vtype(ITypeInfo *pTypeInfo, UINT method_index)
/*
* call-seq:
- * return_vtype
+ * WIN32OLE_METHOD#return_vtype
*
* Returns number of return value type of method.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
- * method = WIN32OLE::Method.new(tobj, 'Add')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
+ * method = WIN32OLE_METHOD.new(tobj, 'Add')
* puts method.return_vtype # => 26
*
*/
@@ -385,12 +385,12 @@ ole_method_return_type_detail(ITypeInfo *pTypeInfo, UINT method_index)
/*
* call-seq:
- * return_type_detail
+ * WIN32OLE_METHOD#return_type_detail
*
* Returns detail information of return value type of method.
* The information is array.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
- * method = WIN32OLE::Method.new(tobj, 'Add')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
+ * method = WIN32OLE_METHOD.new(tobj, 'Add')
* p method.return_type_detail # => ["PTR", "USERDEFINED", "Workbook"]
*/
static VALUE
@@ -437,11 +437,11 @@ ole_method_invoke_kind(ITypeInfo *pTypeInfo, UINT method_index)
/*
* call-seq:
- * invkind
+ * WIN32OLE_METHOD#invkind
*
* Returns the method invoke kind.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
- * method = WIN32OLE::Method.new(tobj, 'Add')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
+ * method = WIN32OLE_METHOD.new(tobj, 'Add')
* puts method.invkind # => 1
*
*/
@@ -455,13 +455,13 @@ folemethod_invkind(VALUE self)
/*
* call-seq:
- * invoke_kind
+ * WIN32OLE_METHOD#invoke_kind
*
* Returns the method kind string. The string is "UNKNOWN" or "PROPERTY"
* or "PROPERTY" or "PROPERTYGET" or "PROPERTYPUT" or "PROPERTYPPUTREF"
* or "FUNC".
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
- * method = WIN32OLE::Method.new(tobj, 'Add')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
+ * method = WIN32OLE_METHOD.new(tobj, 'Add')
* puts method.invoke_kind # => "FUNC"
*/
static VALUE
@@ -494,11 +494,11 @@ ole_method_visible(ITypeInfo *pTypeInfo, UINT method_index)
/*
* call-seq:
- * visible?
+ * WIN32OLE_METHOD#visible?
*
* Returns true if the method is public.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
- * method = WIN32OLE::Method.new(tobj, 'Add')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
+ * method = WIN32OLE_METHOD.new(tobj, 'Add')
* puts method.visible? # => true
*/
static VALUE
@@ -575,11 +575,11 @@ ole_method_event(ITypeInfo *pTypeInfo, UINT method_index, VALUE method_name)
/*
* call-seq:
- * event?
+ * WIN32OLE_METHOD#event?
*
* Returns true if the method is event.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbook')
- * method = WIN32OLE::Method.new(tobj, 'SheetActivate')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
+ * method = WIN32OLE_METHOD.new(tobj, 'SheetActivate')
* puts method.event? # => true
*
*/
@@ -597,11 +597,11 @@ folemethod_event(VALUE self)
/*
* call-seq:
- * event_interface
+ * WIN32OLE_METHOD#event_interface
*
* Returns event interface name if the method is event.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbook')
- * method = WIN32OLE::Method.new(tobj, 'SheetActivate')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
+ * method = WIN32OLE_METHOD.new(tobj, 'SheetActivate')
* puts method.event_interface # => WorkbookEvents
*/
static VALUE
@@ -655,12 +655,12 @@ ole_method_helpstring(ITypeInfo *pTypeInfo, UINT method_index)
/*
* call-seq:
- * helpstring
+ * WIN32OLE_METHOD#helpstring
*
* Returns help string of OLE method. If the help string is not found,
* then the method returns nil.
- * tobj = WIN32OLE::Type.new('Microsoft Internet Controls', 'IWebBrowser')
- * method = WIN32OLE::Method.new(tobj, 'Navigate')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', 'IWebBrowser')
+ * method = WIN32OLE_METHOD.new(tobj, 'Navigate')
* puts method.helpstring # => Navigates to a URL or file.
*
*/
@@ -686,12 +686,12 @@ ole_method_helpfile(ITypeInfo *pTypeInfo, UINT method_index)
/*
* call-seq:
- * helpfile
+ * WIN32OLE_METHOD#helpfile
*
* Returns help file. If help file is not found, then
* the method returns nil.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
- * method = WIN32OLE::Method.new(tobj, 'Add')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
+ * method = WIN32OLE_METHOD.new(tobj, 'Add')
* puts method.helpfile # => C:\...\VBAXL9.CHM
*/
static VALUE
@@ -717,11 +717,11 @@ ole_method_helpcontext(ITypeInfo *pTypeInfo, UINT method_index)
/*
* call-seq:
- * helpcontext
+ * WIN32OLE_METHOD#helpcontext
*
* Returns help context.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
- * method = WIN32OLE::Method.new(tobj, 'Add')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
+ * method = WIN32OLE_METHOD.new(tobj, 'Add')
* puts method.helpcontext # => 65717
*/
static VALUE
@@ -748,11 +748,11 @@ ole_method_dispid(ITypeInfo *pTypeInfo, UINT method_index)
/*
* call-seq:
- * dispid
+ * WIN32OLE_METHOD#dispid
*
* Returns dispatch ID.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
- * method = WIN32OLE::Method.new(tobj, 'Add')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
+ * method = WIN32OLE_METHOD.new(tobj, 'Add')
* puts method.dispid # => 181
*/
static VALUE
@@ -779,11 +779,11 @@ ole_method_offset_vtbl(ITypeInfo *pTypeInfo, UINT method_index)
/*
* call-seq:
- * offset_vtbl
+ * WIN32OLE_METHOD#offset_vtbl
*
* Returns the offset ov VTBL.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
- * method = WIN32OLE::Method.new(tobj, 'Add')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbooks')
+ * method = WIN32OLE_METHOD.new(tobj, 'Add')
* puts method.offset_vtbl # => 40
*/
static VALUE
@@ -810,11 +810,11 @@ ole_method_size_params(ITypeInfo *pTypeInfo, UINT method_index)
/*
* call-seq:
- * size_params
+ * WIN32OLE_METHOD#size_params
*
* Returns the size of arguments of the method.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbook')
- * method = WIN32OLE::Method.new(tobj, 'SaveAs')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
+ * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
* puts method.size_params # => 11
*
*/
@@ -842,11 +842,11 @@ ole_method_size_opt_params(ITypeInfo *pTypeInfo, UINT method_index)
/*
* call-seq:
- * size_opt_params
+ * WIN32OLE_METHOD#size_opt_params
*
* Returns the size of optional parameters.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbook')
- * method = WIN32OLE::Method.new(tobj, 'SaveAs')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
+ * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
* puts method.size_opt_params # => 4
*/
static VALUE
@@ -892,11 +892,11 @@ ole_method_params(ITypeInfo *pTypeInfo, UINT method_index)
/*
* call-seq:
- * params
+ * WIN32OLE_METHOD#params
*
- * returns array of WIN32OLE::Param object corresponding with method parameters.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbook')
- * method = WIN32OLE::Method.new(tobj, 'SaveAs')
+ * returns array of WIN32OLE_PARAM object corresponding with method parameters.
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
+ * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
* p method.params # => [Filename, FileFormat, Password, WriteResPassword,
* ReadOnlyRecommended, CreateBackup, AccessMode,
* ConflictResolution, AddToMru, TextCodepage,
@@ -912,7 +912,7 @@ folemethod_params(VALUE self)
/*
* call-seq:
- * inspect -> String
+ * WIN32OLE_METHOD#inspect -> String
*
* Returns the method name with class name.
*
@@ -920,7 +920,7 @@ folemethod_params(VALUE self)
static VALUE
folemethod_inspect(VALUE self)
{
- return default_inspect(self, "WIN32OLE::Method");
+ return default_inspect(self, "WIN32OLE_METHOD");
}
VALUE cWIN32OLE_METHOD;
@@ -928,7 +928,6 @@ VALUE cWIN32OLE_METHOD;
void Init_win32ole_method(void)
{
cWIN32OLE_METHOD = rb_define_class_under(cWIN32OLE, "Method", rb_cObject);
- /* Alias of WIN32OLE::Method, for the backward compatibility */
rb_define_const(rb_cObject, "WIN32OLE_METHOD", cWIN32OLE_METHOD);
rb_define_alloc_func(cWIN32OLE_METHOD, folemethod_s_allocate);
rb_define_method(cWIN32OLE_METHOD, "initialize", folemethod_initialize, 2);
diff --git a/ext/win32ole/win32ole_param.c b/ext/win32ole/win32ole_param.c
index 0c4b185921..b654aaa845 100644
--- a/ext/win32ole/win32ole_param.c
+++ b/ext/win32ole/win32ole_param.c
@@ -64,9 +64,9 @@ create_win32ole_param(ITypeInfo *pTypeInfo, UINT method_index, UINT index, VALUE
}
/*
- * Document-class: WIN32OLE::Param
+ * Document-class: WIN32OLE_PARAM
*
- * +WIN32OLE::Param+ objects represent param information of
+ * <code>WIN32OLE_PARAM</code> objects represent param information of
* the OLE method.
*/
static VALUE
@@ -131,15 +131,15 @@ oleparam_ole_param(VALUE self, VALUE olemethod, int n)
/*
* call-seq:
- * new(method, n) -> WIN32OLE::Param object
+ * WIN32OLE_PARAM.new(method, n) -> WIN32OLE_PARAM object
*
- * Returns WIN32OLE::Param object which represents OLE parameter information.
- * 1st argument should be WIN32OLE::Method object.
+ * Returns WIN32OLE_PARAM object which represents OLE parameter information.
+ * 1st argument should be WIN32OLE_METHOD object.
* 2nd argument `n' is n-th parameter of the method specified by 1st argument.
*
- * tobj = WIN32OLE::Type.new('Microsoft Scripting Runtime', 'IFileSystem')
- * method = WIN32OLE::Method.new(tobj, 'CreateTextFile')
- * param = WIN32OLE::Param.new(method, 2) # => #<WIN32OLE::Param:Overwrite=true>
+ * tobj = WIN32OLE_TYPE.new('Microsoft Scripting Runtime', 'IFileSystem')
+ * method = WIN32OLE_METHOD.new(tobj, 'CreateTextFile')
+ * param = WIN32OLE_PARAM.new(method, 2) # => #<WIN32OLE_PARAM:Overwrite=true>
*
*/
static VALUE
@@ -147,7 +147,7 @@ foleparam_initialize(VALUE self, VALUE olemethod, VALUE n)
{
int idx;
if (!rb_obj_is_kind_of(olemethod, cWIN32OLE_METHOD)) {
- rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE::Method object");
+ rb_raise(rb_eTypeError, "1st parameter must be WIN32OLE_METHOD object");
}
idx = RB_FIX2INT(n);
return oleparam_ole_param(self, olemethod, idx);
@@ -155,11 +155,11 @@ foleparam_initialize(VALUE self, VALUE olemethod, VALUE n)
/*
* call-seq:
- * name
+ * WIN32OLE_PARAM#name
*
* Returns name.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbook')
- * method = WIN32OLE::Method.new(tobj, 'SaveAs')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
+ * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
* param1 = method.params[0]
* puts param1.name # => Filename
*/
@@ -186,11 +186,11 @@ ole_param_ole_type(ITypeInfo *pTypeInfo, UINT method_index, UINT index)
/*
* call-seq:
- * ole_type
+ * WIN32OLE_PARAM#ole_type
*
- * Returns OLE type of WIN32OLE::Param object(parameter of OLE method).
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbook')
- * method = WIN32OLE::Method.new(tobj, 'SaveAs')
+ * Returns OLE type of WIN32OLE_PARAM object(parameter of OLE method).
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
+ * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
* param1 = method.params[0]
* puts param1.ole_type # => VARIANT
*/
@@ -220,11 +220,11 @@ ole_param_ole_type_detail(ITypeInfo *pTypeInfo, UINT method_index, UINT index)
/*
* call-seq:
- * ole_type_detail
+ * WIN32OLE_PARAM#ole_type_detail
*
* Returns detail information of type of argument.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'IWorksheetFunction')
- * method = WIN32OLE::Method.new(tobj, 'SumIf')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'IWorksheetFunction')
+ * method = WIN32OLE_METHOD.new(tobj, 'SumIf')
* param1 = method.params[0]
* p param1.ole_type_detail # => ["PTR", "USERDEFINED", "Range"]
*/
@@ -254,11 +254,11 @@ ole_param_flag_mask(ITypeInfo *pTypeInfo, UINT method_index, UINT index, USHORT
/*
* call-seq:
- * input?
+ * WIN32OLE_PARAM#input?
*
* Returns true if the parameter is input.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbook')
- * method = WIN32OLE::Method.new(tobj, 'SaveAs')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
+ * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
* param1 = method.params[0]
* puts param1.input? # => true
*/
@@ -273,22 +273,22 @@ foleparam_input(VALUE self)
/*
* call-seq:
- * output?
+ * WIN32OLE#output?
*
* Returns true if argument is output.
- * tobj = WIN32OLE::Type.new('Microsoft Internet Controls', 'DWebBrowserEvents')
- * method = WIN32OLE::Method.new(tobj, 'NewWindow')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', 'DWebBrowserEvents')
+ * method = WIN32OLE_METHOD.new(tobj, 'NewWindow')
* method.params.each do |param|
* puts "#{param.name} #{param.output?}"
* end
*
- * The result of above script is following:
- * URL false
- * Flags false
- * TargetFrameName false
- * PostData false
- * Headers false
- * Processed true
+ * The result of above script is following:
+ * URL false
+ * Flags false
+ * TargetFrameName false
+ * PostData false
+ * Headers false
+ * Processed true
*/
static VALUE
foleparam_output(VALUE self)
@@ -301,11 +301,11 @@ foleparam_output(VALUE self)
/*
* call-seq:
- * optional?
+ * WIN32OLE_PARAM#optional?
*
* Returns true if argument is optional.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbook')
- * method = WIN32OLE::Method.new(tobj, 'SaveAs')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
+ * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
* param1 = method.params[0]
* puts "#{param1.name} #{param1.optional?}" # => Filename true
*/
@@ -320,12 +320,12 @@ foleparam_optional(VALUE self)
/*
* call-seq:
- * retval?
+ * WIN32OLE_PARAM#retval?
*
* Returns true if argument is return value.
- * tobj = WIN32OLE::Type.new('DirectX 7 for Visual Basic Type Library',
- * 'DirectPlayLobbyConnection')
- * method = WIN32OLE::Method.new(tobj, 'GetPlayerShortName')
+ * tobj = WIN32OLE_TYPE.new('DirectX 7 for Visual Basic Type Library',
+ * 'DirectPlayLobbyConnection')
+ * method = WIN32OLE_METHOD.new(tobj, 'GetPlayerShortName')
* param = method.params[0]
* puts "#{param.name} #{param.retval?}" # => name true
*/
@@ -363,12 +363,12 @@ ole_param_default(ITypeInfo *pTypeInfo, UINT method_index, UINT index)
/*
* call-seq:
- * default
+ * WIN32OLE_PARAM#default
*
* Returns default value. If the default value does not exist,
* this method returns nil.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Workbook')
- * method = WIN32OLE::Method.new(tobj, 'SaveAs')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Workbook')
+ * method = WIN32OLE_METHOD.new(tobj, 'SaveAs')
* method.params.each do |param|
* if param.default
* puts "#{param.name} (= #{param.default})"
@@ -377,18 +377,18 @@ ole_param_default(ITypeInfo *pTypeInfo, UINT method_index, UINT index)
* end
* end
*
- * The above script result is following:
- * Filename
- * FileFormat
- * Password
- * WriteResPassword
- * ReadOnlyRecommended
- * CreateBackup
- * AccessMode (= 1)
- * ConflictResolution
- * AddToMru
- * TextCodepage
- * TextVisualLayout
+ * The above script result is following:
+ * Filename
+ * FileFormat
+ * Password
+ * WriteResPassword
+ * ReadOnlyRecommended
+ * CreateBackup
+ * AccessMode (= 1)
+ * ConflictResolution
+ * AddToMru
+ * TextCodepage
+ * TextVisualLayout
*/
static VALUE
foleparam_default(VALUE self)
@@ -401,7 +401,7 @@ foleparam_default(VALUE self)
/*
* call-seq:
- * inspect -> String
+ * WIN32OLE_PARAM#inspect -> String
*
* Returns the parameter name with class name. If the parameter has default value,
* then returns name=value string with class name.
@@ -416,14 +416,13 @@ foleparam_inspect(VALUE self)
rb_str_cat2(detail, "=");
rb_str_concat(detail, rb_inspect(defval));
}
- return make_inspect("WIN32OLE::Param", detail);
+ return make_inspect("WIN32OLE_PARAM", detail);
}
void
Init_win32ole_param(void)
{
cWIN32OLE_PARAM = rb_define_class_under(cWIN32OLE, "Param", rb_cObject);
- /* Alias of WIN32OLE::Param, for the backward compatibility */
rb_define_const(rb_cObject, "WIN32OLE_PARAM", cWIN32OLE_PARAM);
rb_define_alloc_func(cWIN32OLE_PARAM, foleparam_s_allocate);
rb_define_method(cWIN32OLE_PARAM, "initialize", foleparam_initialize, 2);
diff --git a/ext/win32ole/win32ole_record.c b/ext/win32ole/win32ole_record.c
index 02f05a3fa7..9e18653db9 100644
--- a/ext/win32ole/win32ole_record.c
+++ b/ext/win32ole/win32ole_record.c
@@ -177,10 +177,10 @@ create_win32ole_record(IRecordInfo *pri, void *prec)
}
/*
- * Document-class: WIN32OLE::Record
+ * Document-class: WIN32OLE_RECORD
*
- * +WIN32OLE::Record+ objects represents VT_RECORD OLE variant.
- * Win32OLE returns WIN32OLE::Record object if the result value of invoking
+ * <code>WIN32OLE_RECORD</code> objects represents VT_RECORD OLE variant.
+ * Win32OLE returns WIN32OLE_RECORD object if the result value of invoking
* OLE methods.
*
* If COM server in VB.NET ComServer project is the following:
@@ -206,7 +206,7 @@ create_win32ole_record(IRecordInfo *pri, void *prec)
* require 'win32ole'
* obj = WIN32OLE.new('ComServer.ComClass')
* book = obj.getBook
- * book.class # => WIN32OLE::Record
+ * book.class # => WIN32OLE_RECORD
* book.title # => "The Ruby Book"
* book.cost # => 20
*
@@ -253,11 +253,11 @@ folerecord_s_allocate(VALUE klass) {
/*
* call-seq:
- * new(typename, obj) -> WIN32OLE::Record object
+ * WIN32OLE_RECORD.new(typename, obj) -> WIN32OLE_RECORD object
*
- * Returns WIN32OLE::Record object. The first argument is struct name (String
+ * Returns WIN32OLE_RECORD object. The first argument is struct name (String
* or Symbol).
- * The second parameter obj should be WIN32OLE object or WIN32OLE::TypeLib object.
+ * The second parameter obj should be WIN32OLE object or WIN32OLE_TYPELIB object.
* If COM server in VB.NET ComServer project is the following:
*
* Imports System.Runtime.InteropServices
@@ -269,13 +269,13 @@ folerecord_s_allocate(VALUE klass) {
* End Structure
* End Class
*
- * then, you can create WIN32OLE::Record object is as following:
+ * then, you can create WIN32OLE_RECORD object is as following:
*
* require 'win32ole'
* obj = WIN32OLE.new('ComServer.ComClass')
- * book1 = WIN32OLE::Record.new('Book', obj) # => WIN32OLE::Record object
+ * book1 = WIN32OLE_RECORD.new('Book', obj) # => WIN32OLE_RECORD object
* tlib = obj.ole_typelib
- * book2 = WIN32OLE::Record.new('Book', tlib) # => WIN32OLE::Record object
+ * book2 = WIN32OLE_RECORD.new('Book', tlib) # => WIN32OLE_RECORD object
*
*/
static VALUE
@@ -303,7 +303,7 @@ folerecord_initialize(VALUE self, VALUE typename, VALUE oleobj) {
hr = E_FAIL;
}
} else {
- rb_raise(rb_eArgError, "2nd argument should be WIN32OLE object or WIN32OLE::TypeLib object");
+ rb_raise(rb_eArgError, "2nd argument should be WIN32OLE object or WIN32OLE_TYPELIB object");
}
if (FAILED(hr)) {
@@ -323,7 +323,7 @@ folerecord_initialize(VALUE self, VALUE typename, VALUE oleobj) {
/*
* call-seq:
- * WIN32OLE::Record#to_h #=> Ruby Hash object.
+ * WIN32OLE_RECORD#to_h #=> Ruby Hash object.
*
* Returns Ruby Hash object which represents VT_RECORD variable.
* The keys of Hash object are member names of VT_RECORD OLE variable and
@@ -346,7 +346,7 @@ folerecord_initialize(VALUE self, VALUE typename, VALUE oleobj) {
* End Function
* End Class
*
- * then, the result of WIN32OLE::Record#to_h is the following:
+ * then, the result of WIN32OLE_RECORD#to_h is the following:
*
* require 'win32ole'
* obj = WIN32OLE.new('ComServer.ComClass')
@@ -362,7 +362,7 @@ folerecord_to_h(VALUE self)
/*
* call-seq:
- * typename #=> String object
+ * WIN32OLE_RECORD#typename #=> String object
*
* Returns the type name of VT_RECORD OLE variable.
*
@@ -383,7 +383,7 @@ folerecord_to_h(VALUE self)
* End Function
* End Class
*
- * then, the result of WIN32OLE::Record#typename is the following:
+ * then, the result of WIN32OLE_RECORD#typename is the following:
*
* require 'win32ole'
* obj = WIN32OLE.new('ComServer.ComClass')
@@ -423,7 +423,7 @@ olerecord_ivar_set(VALUE self, VALUE name, VALUE val)
/*
* call-seq:
- * method_missing(name)
+ * WIN32OLE_RECORD#method_missing(name)
*
* Returns value specified by the member name of VT_RECORD OLE variable.
* Or sets value specified by the member name of VT_RECORD OLE variable.
@@ -443,7 +443,7 @@ olerecord_ivar_set(VALUE self, VALUE name, VALUE val)
* Then getting/setting value from Ruby is as the following:
*
* obj = WIN32OLE.new('ComServer.ComClass')
- * book = WIN32OLE::Record.new('Book', obj)
+ * book = WIN32OLE_RECORD.new('Book', obj)
* book.title # => nil ( book.method_missing(:title) is invoked. )
* book.title = "Ruby" # ( book.method_missing(:title=, "Ruby") is invoked. )
*/
@@ -473,7 +473,7 @@ folerecord_method_missing(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * ole_instance_variable_get(name)
+ * WIN32OLE_RECORD#ole_instance_variable_get(name)
*
* Returns value specified by the member name of VT_RECORD OLE object.
* If the member name is not correct, KeyError exception is raised.
@@ -494,7 +494,7 @@ folerecord_method_missing(int argc, VALUE *argv, VALUE self)
* then accessing object_id of ComObject from Ruby is as the following:
*
* srver = WIN32OLE.new('ComServer.ComClass')
- * obj = WIN32OLE::Record.new('ComObject', server)
+ * obj = WIN32OLE_RECORD.new('ComObject', server)
* # obj.object_id returns Ruby Object#object_id
* obj.ole_instance_variable_get(:object_id) # => nil
*
@@ -515,7 +515,7 @@ folerecord_ole_instance_variable_get(VALUE self, VALUE name)
/*
* call-seq:
- * ole_instance_variable_set(name, val)
+ * WIN32OLE_RECORD#ole_instance_variable_set(name, val)
*
* Sets value specified by the member name of VT_RECORD OLE object.
* If the member name is not correct, KeyError exception is raised.
@@ -534,7 +534,7 @@ folerecord_ole_instance_variable_get(VALUE self, VALUE name)
* then setting value of the `title' member is as following:
*
* srver = WIN32OLE.new('ComServer.ComClass')
- * obj = WIN32OLE::Record.new('Book', server)
+ * obj = WIN32OLE_RECORD.new('Book', server)
* obj.ole_instance_variable_set(:title, "The Ruby Book")
*
*/
@@ -554,7 +554,7 @@ folerecord_ole_instance_variable_set(VALUE self, VALUE name, VALUE val)
/*
* call-seq:
- * inspect -> String
+ * WIN32OLE_RECORD#inspect -> String
*
* Returns the OLE struct name and member name and the value of member
*
@@ -570,8 +570,8 @@ folerecord_ole_instance_variable_set(VALUE self, VALUE name, VALUE val)
* then
*
* srver = WIN32OLE.new('ComServer.ComClass')
- * obj = WIN32OLE::Record.new('Book', server)
- * obj.inspect # => <WIN32OLE::Record(ComClass) {"title" => nil, "cost" => nil}>
+ * obj = WIN32OLE_RECORD.new('Book', server)
+ * obj.inspect # => <WIN32OLE_RECORD(ComClass) {"title" => nil, "cost" => nil}>
*
*/
static VALUE
@@ -584,7 +584,7 @@ folerecord_inspect(VALUE self)
tname = rb_inspect(tname);
}
field = rb_inspect(folerecord_to_h(self));
- return rb_sprintf("#<WIN32OLE::Record(%"PRIsVALUE") %"PRIsVALUE">",
+ return rb_sprintf("#<WIN32OLE_RECORD(%"PRIsVALUE") %"PRIsVALUE">",
tname,
field);
}
@@ -595,7 +595,6 @@ void
Init_win32ole_record(void)
{
cWIN32OLE_RECORD = rb_define_class_under(cWIN32OLE, "Record", rb_cObject);
- /* Alias of WIN32OLE::Record, for the backward compatibility */
rb_define_const(rb_cObject, "WIN32OLE_RECORD", cWIN32OLE_RECORD);
rb_define_alloc_func(cWIN32OLE_RECORD, folerecord_s_allocate);
rb_define_method(cWIN32OLE_RECORD, "initialize", folerecord_initialize, 2);
diff --git a/ext/win32ole/win32ole_type.c b/ext/win32ole/win32ole_type.c
index 45b16d6722..1b96aea858 100644
--- a/ext/win32ole/win32ole_type.c
+++ b/ext/win32ole/win32ole_type.c
@@ -54,9 +54,9 @@ static const rb_data_type_t oletype_datatype = {
};
/*
- * Document-class: WIN32OLE::Type
+ * Document-class: WIN32OLE_TYPE
*
- * +WIN32OLE::Type+ objects represent OLE type library information.
+ * <code>WIN32OLE_TYPE</code> objects represent OLE type library information.
*/
static void
@@ -106,12 +106,10 @@ ole_type_from_itypeinfo(ITypeInfo *pTypeInfo)
/*
* call-seq:
- * ole_classes(typelib)
+ * WIN32OLE_TYPE.ole_classes(typelib)
*
- * Returns array of WIN32OLE::Type objects defined by the <i>typelib</i> type library.
- *
- * This method will be OBSOLETE.
- * Use <code>WIN32OLE::TypeLib.new(typelib).ole_classes</code> instead.
+ * Returns array of WIN32OLE_TYPE objects defined by the <i>typelib</i> type library.
+ * This method will be OBSOLETE. Use WIN32OLE_TYPELIB.new(typelib).ole_classes instead.
*/
static VALUE
foletype_s_ole_classes(VALUE self, VALUE typelib)
@@ -120,8 +118,8 @@ foletype_s_ole_classes(VALUE self, VALUE typelib)
/*
rb_warn("%s is obsolete; use %s instead.",
- "WIN32OLE::Type.ole_classes",
- "WIN32OLE::TypeLib.new(typelib).ole_types");
+ "WIN32OLE_TYPE.ole_classes",
+ "WIN32OLE_TYPELIB.new(typelib).ole_types");
*/
obj = rb_funcall(cWIN32OLE_TYPELIB, rb_intern("new"), 1, typelib);
return rb_funcall(obj, rb_intern("ole_types"), 0);
@@ -129,12 +127,10 @@ foletype_s_ole_classes(VALUE self, VALUE typelib)
/*
* call-seq:
- * typelibs
+ * WIN32OLE_TYPE.typelibs
*
* Returns array of type libraries.
- *
- * This method will be OBSOLETE.
- * Use <code>WIN32OLE::TypeLib.typelibs.collect{|t| t.name}</code> instead.
+ * This method will be OBSOLETE. Use WIN32OLE_TYPELIB.typelibs.collect{|t| t.name} instead.
*
*/
static VALUE
@@ -142,15 +138,15 @@ foletype_s_typelibs(VALUE self)
{
/*
rb_warn("%s is obsolete. use %s instead.",
- "WIN32OLE::Type.typelibs",
- "WIN32OLE::TypeLib.typelibs.collect{t|t.name}");
+ "WIN32OLE_TYPE.typelibs",
+ "WIN32OLE_TYPELIB.typelibs.collect{t|t.name}");
*/
- return rb_eval_string("WIN32OLE::TypeLib.typelibs.collect{|t|t.name}");
+ return rb_eval_string("WIN32OLE_TYPELIB.typelibs.collect{|t|t.name}");
}
/*
* call-seq:
- * progids
+ * WIN32OLE_TYPE.progids
*
* Returns array of ProgID.
*/
@@ -218,6 +214,7 @@ create_win32ole_type(ITypeInfo *pTypeInfo, VALUE name)
static VALUE
oleclass_from_typelib(VALUE self, ITypeLib *pTypeLib, VALUE oleclass)
{
+
long count;
int i;
HRESULT hr;
@@ -248,14 +245,14 @@ oleclass_from_typelib(VALUE self, ITypeLib *pTypeLib, VALUE oleclass)
/*
* call-seq:
- * new(typelib, ole_class) -> WIN32OLE::Type object
+ * WIN32OLE_TYPE.new(typelib, ole_class) -> WIN32OLE_TYPE object
*
- * Returns a new WIN32OLE::Type object.
+ * Returns a new WIN32OLE_TYPE object.
* The first argument <i>typelib</i> specifies OLE type library name.
* The second argument specifies OLE class name.
*
- * WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Application')
- * # => WIN32OLE::Type object of Application class of Excel.
+ * WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
+ * # => WIN32OLE_TYPE object of Application class of Excel.
*/
static VALUE
foletype_initialize(VALUE self, VALUE typelib, VALUE oleclass)
@@ -287,10 +284,10 @@ foletype_initialize(VALUE self, VALUE typelib, VALUE oleclass)
/*
* call-seq:
- * name #=> OLE type name
+ * WIN32OLE_TYPE#name #=> OLE type name
*
* Returns OLE type name.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Application')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
* puts tobj.name # => Application
*/
static VALUE
@@ -347,10 +344,10 @@ ole_ole_type(ITypeInfo *pTypeInfo)
/*
* call-seq:
- * ole_type #=> OLE type string.
+ * WIN32OLE_TYPE#ole_type #=> OLE type string.
*
* returns type of OLE class.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Application')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
* puts tobj.ole_type # => Class
*/
static VALUE
@@ -381,10 +378,10 @@ ole_type_guid(ITypeInfo *pTypeInfo)
/*
* call-seq:
- * guid #=> GUID
+ * WIN32OLE_TYPE#guid #=> GUID
*
* Returns GUID.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Application')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
* puts tobj.guid # => {00024500-0000-0000-C000-000000000046}
*/
static VALUE
@@ -415,10 +412,10 @@ ole_type_progid(ITypeInfo *pTypeInfo)
/*
* call-seq:
- * progid #=> ProgID
+ * WIN32OLE_TYPE#progid #=> ProgID
*
* Returns ProgID if it exists. If not found, then returns nil.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Application')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
* puts tobj.progid # => Excel.Application.9
*/
static VALUE
@@ -449,10 +446,10 @@ ole_type_visible(ITypeInfo *pTypeInfo)
/*
* call-seq:
- * visible? #=> true or false
+ * WIN32OLE_TYPE#visible? #=> true or false
*
* Returns true if the OLE class is public.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Application')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Application')
* puts tobj.visible # => true
*/
static VALUE
@@ -478,10 +475,10 @@ ole_type_major_version(ITypeInfo *pTypeInfo)
/*
* call-seq:
- * major_version
+ * WIN32OLE_TYPE#major_version
*
* Returns major version.
- * tobj = WIN32OLE::Type.new('Microsoft Word 10.0 Object Library', 'Documents')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Word 10.0 Object Library', 'Documents')
* puts tobj.major_version # => 8
*/
static VALUE
@@ -507,10 +504,10 @@ ole_type_minor_version(ITypeInfo *pTypeInfo)
/*
* call-seq:
- * minor_version #=> OLE minor version
+ * WIN32OLE_TYPE#minor_version #=> OLE minor version
*
* Returns minor version.
- * tobj = WIN32OLE::Type.new('Microsoft Word 10.0 Object Library', 'Documents')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Word 10.0 Object Library', 'Documents')
* puts tobj.minor_version # => 2
*/
static VALUE
@@ -536,10 +533,10 @@ ole_type_typekind(ITypeInfo *pTypeInfo)
/*
* call-seq:
- * typekind #=> number of type.
+ * WIN32OLE_TYPE#typekind #=> number of type.
*
* Returns number which represents type.
- * tobj = WIN32OLE::Type.new('Microsoft Word 10.0 Object Library', 'Documents')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Word 10.0 Object Library', 'Documents')
* puts tobj.typekind # => 4
*
*/
@@ -564,10 +561,10 @@ ole_type_helpstring(ITypeInfo *pTypeInfo)
/*
* call-seq:
- * helpstring #=> help string.
+ * WIN32OLE_TYPE#helpstring #=> help string.
*
* Returns help string.
- * tobj = WIN32OLE::Type.new('Microsoft Internet Controls', 'IWebBrowser')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', 'IWebBrowser')
* puts tobj.helpstring # => Web Browser interface
*/
static VALUE
@@ -597,10 +594,10 @@ ole_type_src_type(ITypeInfo *pTypeInfo)
/*
* call-seq:
- * src_type #=> OLE source class
+ * WIN32OLE_TYPE#src_type #=> OLE source class
*
* Returns source class when the OLE class is 'Alias'.
- * tobj = WIN32OLE::Type.new('Microsoft Office 9.0 Object Library', 'MsoRGBType')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Office 9.0 Object Library', 'MsoRGBType')
* puts tobj.src_type # => I4
*
*/
@@ -625,10 +622,10 @@ ole_type_helpfile(ITypeInfo *pTypeInfo)
/*
* call-seq:
- * helpfile
+ * WIN32OLE_TYPE#helpfile
*
* Returns helpfile path. If helpfile is not found, then returns nil.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
* puts tobj.helpfile # => C:\...\VBAXL9.CHM
*
*/
@@ -653,10 +650,10 @@ ole_type_helpcontext(ITypeInfo *pTypeInfo)
/*
* call-seq:
- * helpcontext
+ * WIN32OLE_TYPE#helpcontext
*
* Returns helpcontext. If helpcontext is not found, then returns nil.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
* puts tobj.helpfile # => 131185
*/
static VALUE
@@ -704,11 +701,11 @@ ole_variables(ITypeInfo *pTypeInfo)
/*
* call-seq:
- * variables
+ * WIN32OLE_TYPE#variables
*
- * Returns array of WIN32OLE::Variable objects which represent variables
+ * Returns array of WIN32OLE_VARIABLE objects which represent variables
* defined in OLE class.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
* vars = tobj.variables
* vars.each do |v|
* puts "#{v.name} = #{v.value}"
@@ -731,11 +728,11 @@ foletype_variables(VALUE self)
/*
* call-seq:
- * ole_methods # the array of WIN32OLE::Method objects.
+ * WIN32OLE_TYPE#ole_methods # the array of WIN32OLE_METHOD objects.
*
- * Returns array of WIN32OLE::Method objects which represent OLE method defined in
+ * Returns array of WIN32OLE_METHOD objects which represent OLE method defined in
* OLE type library.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
* methods = tobj.ole_methods.collect{|m|
* m.name
* }
@@ -750,11 +747,11 @@ foletype_methods(VALUE self)
/*
* call-seq:
- * ole_typelib
+ * WIN32OLE_TYPE#ole_typelib
*
- * Returns the WIN32OLE::TypeLib object which is including the WIN32OLE::Type
+ * Returns the WIN32OLE_TYPELIB object which is including the WIN32OLE_TYPE
* object. If it is not found, then returns nil.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
* puts tobj.ole_typelib # => 'Microsoft Excel 9.0 Object Library'
*/
static VALUE
@@ -807,11 +804,11 @@ ole_type_impl_ole_types(ITypeInfo *pTypeInfo, int implflags)
/*
* call-seq:
- * implemented_ole_types
+ * WIN32OLE_TYPE#implemented_ole_types
*
- * Returns the array of WIN32OLE::Type object which is implemented by the WIN32OLE::Type
+ * Returns the array of WIN32OLE_TYPE object which is implemented by the WIN32OLE_TYPE
* object.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'Worksheet')
* p tobj.implemented_ole_types # => [_Worksheet, DocEvents]
*/
static VALUE
@@ -823,13 +820,13 @@ foletype_impl_ole_types(VALUE self)
/*
* call-seq:
- * source_ole_types
+ * WIN32OLE_TYPE#source_ole_types
*
- * Returns the array of WIN32OLE::Type object which is implemented by the WIN32OLE::Type
+ * Returns the array of WIN32OLE_TYPE object which is implemented by the WIN32OLE_TYPE
* object and having IMPLTYPEFLAG_FSOURCE.
- * tobj = WIN32OLE::Type.new('Microsoft Internet Controls', "InternetExplorer")
+ * tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', "InternetExplorer")
* p tobj.source_ole_types
- * # => [#<WIN32OLE::Type:DWebBrowserEvents2>, #<WIN32OLE::Type:DWebBrowserEvents>]
+ * # => [#<WIN32OLE_TYPE:DWebBrowserEvents2>, #<WIN32OLE_TYPE:DWebBrowserEvents>]
*/
static VALUE
foletype_source_ole_types(VALUE self)
@@ -840,12 +837,12 @@ foletype_source_ole_types(VALUE self)
/*
* call-seq:
- * default_event_sources
+ * WIN32OLE_TYPE#default_event_sources
*
- * Returns the array of WIN32OLE::Type object which is implemented by the WIN32OLE::Type
+ * Returns the array of WIN32OLE_TYPE object which is implemented by the WIN32OLE_TYPE
* object and having IMPLTYPEFLAG_FSOURCE and IMPLTYPEFLAG_FDEFAULT.
- * tobj = WIN32OLE::Type.new('Microsoft Internet Controls', "InternetExplorer")
- * p tobj.default_event_sources # => [#<WIN32OLE::Type:DWebBrowserEvents2>]
+ * tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', "InternetExplorer")
+ * p tobj.default_event_sources # => [#<WIN32OLE_TYPE:DWebBrowserEvents2>]
*/
static VALUE
foletype_default_event_sources(VALUE self)
@@ -856,13 +853,13 @@ foletype_default_event_sources(VALUE self)
/*
* call-seq:
- * default_ole_types
+ * WIN32OLE_TYPE#default_ole_types
*
- * Returns the array of WIN32OLE::Type object which is implemented by the WIN32OLE::Type
+ * Returns the array of WIN32OLE_TYPE object which is implemented by the WIN32OLE_TYPE
* object and having IMPLTYPEFLAG_FDEFAULT.
- * tobj = WIN32OLE::Type.new('Microsoft Internet Controls', "InternetExplorer")
+ * tobj = WIN32OLE_TYPE.new('Microsoft Internet Controls', "InternetExplorer")
* p tobj.default_ole_types
- * # => [#<WIN32OLE::Type:IWebBrowser2>, #<WIN32OLE::Type:DWebBrowserEvents2>]
+ * # => [#<WIN32OLE_TYPE:IWebBrowser2>, #<WIN32OLE_TYPE:DWebBrowserEvents2>]
*/
static VALUE
foletype_default_ole_types(VALUE self)
@@ -873,17 +870,17 @@ foletype_default_ole_types(VALUE self)
/*
* call-seq:
- * inspect -> String
+ * WIN32OLE_TYPE#inspect -> String
*
* Returns the type name with class name.
*
* ie = WIN32OLE.new('InternetExplorer.Application')
- * ie.ole_type.inspect => #<WIN32OLE::Type:IWebBrowser2>
+ * ie.ole_type.inspect => #<WIN32OLE_TYPE:IWebBrowser2>
*/
static VALUE
foletype_inspect(VALUE self)
{
- return default_inspect(self, "WIN32OLE::Type");
+ return default_inspect(self, "WIN32OLE_TYPE");
}
VALUE cWIN32OLE_TYPE;
@@ -891,7 +888,6 @@ VALUE cWIN32OLE_TYPE;
void Init_win32ole_type(void)
{
cWIN32OLE_TYPE = rb_define_class_under(cWIN32OLE, "Type", rb_cObject);
- /* Alias of WIN32OLE::Type, for the backward compatibility */
rb_define_const(rb_cObject, "WIN32OLE_TYPE", cWIN32OLE_TYPE);
rb_define_singleton_method(cWIN32OLE_TYPE, "ole_classes", foletype_s_ole_classes, 1);
rb_define_singleton_method(cWIN32OLE_TYPE, "typelibs", foletype_s_typelibs, 0);
diff --git a/ext/win32ole/win32ole_typelib.c b/ext/win32ole/win32ole_typelib.c
index e5eda07e76..fb68bebda8 100644
--- a/ext/win32ole/win32ole_typelib.c
+++ b/ext/win32ole/win32ole_typelib.c
@@ -127,19 +127,19 @@ ole_typelib_from_itypeinfo(ITypeInfo *pTypeInfo)
}
/*
- * Document-class: WIN32OLE::TypeLib
+ * Document-class: WIN32OLE_TYPELIB
*
- * +WIN32OLE::TypeLib+ objects represent OLE tyblib information.
+ * <code>WIN32OLE_TYPELIB</code> objects represent OLE tyblib information.
*/
/*
* call-seq:
*
- * typelibs
+ * WIN32OLE_TYPELIB.typelibs
*
- * Returns the array of WIN32OLE::TypeLib object.
+ * Returns the array of WIN32OLE_TYPELIB object.
*
- * tlibs = WIN32OLE::TypeLib.typelibs
+ * tlibs = WIN32OLE_TYPELIB.typelibs
*
*/
static VALUE
@@ -364,9 +364,9 @@ oletypelib_search_registry2(VALUE self, VALUE args)
/*
* call-seq:
- * new(typelib [, version1, version2]) -> WIN32OLE::TypeLib object
+ * WIN32OLE_TYPELIB.new(typelib [, version1, version2]) -> WIN32OLE_TYPELIB object
*
- * Returns a new WIN32OLE::TypeLib object.
+ * Returns a new WIN32OLE_TYPELIB object.
*
* The first argument <i>typelib</i> specifies OLE type library name or GUID or
* OLE library file.
@@ -376,11 +376,11 @@ oletypelib_search_registry2(VALUE self, VALUE args)
* If the first argument is type library name, then the second and third argument
* are ignored.
*
- * tlib1 = WIN32OLE::TypeLib.new('Microsoft Excel 9.0 Object Library')
- * tlib2 = WIN32OLE::TypeLib.new('{00020813-0000-0000-C000-000000000046}')
- * tlib3 = WIN32OLE::TypeLib.new('{00020813-0000-0000-C000-000000000046}', 1.3)
- * tlib4 = WIN32OLE::TypeLib.new('{00020813-0000-0000-C000-000000000046}', 1, 3)
- * tlib5 = WIN32OLE::TypeLib.new("C:\\WINNT\\SYSTEM32\\SHELL32.DLL")
+ * tlib1 = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
+ * tlib2 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}')
+ * tlib3 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}', 1.3)
+ * tlib4 = WIN32OLE_TYPELIB.new('{00020813-0000-0000-C000-000000000046}', 1, 3)
+ * tlib5 = WIN32OLE_TYPELIB.new("C:\\WINNT\\SYSTEM32\\SHELL32.DLL")
* puts tlib1.name # -> 'Microsoft Excel 9.0 Object Library'
* puts tlib2.name # -> 'Microsoft Excel 9.0 Object Library'
* puts tlib3.name # -> 'Microsoft Excel 9.0 Object Library'
@@ -428,11 +428,11 @@ foletypelib_initialize(VALUE self, VALUE args)
/*
* call-seq:
- * guid -> The guid string.
+ * WIN32OLE_TYPELIB#guid -> The guid string.
*
* Returns guid string which specifies type library.
*
- * tlib = WIN32OLE::TypeLib.new('Microsoft Excel 9.0 Object Library')
+ * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
* guid = tlib.guid # -> '{00020813-0000-0000-C000-000000000046}'
*/
static VALUE
@@ -456,11 +456,11 @@ foletypelib_guid(VALUE self)
/*
* call-seq:
- * name -> The type library name
+ * WIN32OLE_TYPELIB#name -> The type library name
*
* Returns the type library name.
*
- * tlib = WIN32OLE::TypeLib.new('Microsoft Excel 9.0 Object Library')
+ * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
* name = tlib.name # -> 'Microsoft Excel 9.0 Object Library'
*/
static VALUE
@@ -500,11 +500,11 @@ make_version_str(VALUE major, VALUE minor)
/*
* call-seq:
- * version -> The type library version String object.
+ * WIN32OLE_TYPELIB#version -> The type library version String object.
*
* Returns the type library version.
*
- * tlib = WIN32OLE::TypeLib.new('Microsoft Excel 9.0 Object Library')
+ * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
* puts tlib.version #-> "1.3"
*/
static VALUE
@@ -523,11 +523,11 @@ foletypelib_version(VALUE self)
/*
* call-seq:
- * major_version -> The type library major version.
+ * WIN32OLE_TYPELIB#major_version -> The type library major version.
*
* Returns the type library major version.
*
- * tlib = WIN32OLE::TypeLib.new('Microsoft Excel 9.0 Object Library')
+ * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
* puts tlib.major_version # -> 1
*/
static VALUE
@@ -546,11 +546,11 @@ foletypelib_major_version(VALUE self)
/*
* call-seq:
- * minor_version -> The type library minor version.
+ * WIN32OLE_TYPELIB#minor_version -> The type library minor version.
*
* Returns the type library minor version.
*
- * tlib = WIN32OLE::TypeLib.new('Microsoft Excel 9.0 Object Library')
+ * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
* puts tlib.minor_version # -> 3
*/
static VALUE
@@ -568,11 +568,11 @@ foletypelib_minor_version(VALUE self)
/*
* call-seq:
- * path -> The type library file path.
+ * WIN32OLE_TYPELIB#path -> The type library file path.
*
* Returns the type library file path.
*
- * tlib = WIN32OLE::TypeLib.new('Microsoft Excel 9.0 Object Library')
+ * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
* puts tlib.path #-> 'C:\...\EXCEL9.OLB'
*/
static VALUE
@@ -604,15 +604,15 @@ foletypelib_path(VALUE self)
/*
* call-seq:
- * visible?
+ * WIN32OLE_TYPELIB#visible?
*
* Returns true if the type library information is not hidden.
* If wLibFlags of TLIBATTR is 0 or LIBFLAG_FRESTRICTED or LIBFLAG_FHIDDEN,
* the method returns false, otherwise, returns true.
* If the method fails to access the TLIBATTR information, then
- * WIN32OLE::RuntimeError is raised.
+ * WIN32OLERuntimeError is raised.
*
- * tlib = WIN32OLE::TypeLib.new('Microsoft Excel 9.0 Object Library')
+ * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
* tlib.visible? # => true
*/
static VALUE
@@ -636,12 +636,12 @@ foletypelib_visible(VALUE self)
/*
* call-seq:
- * library_name
+ * WIN32OLE_TYPELIB#library_name
*
* Returns library name.
- * If the method fails to access library name, WIN32OLE::RuntimeError is raised.
+ * If the method fails to access library name, WIN32OLERuntimeError is raised.
*
- * tlib = WIN32OLE::TypeLib.new('Microsoft Excel 9.0 Object Library')
+ * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
* tlib.library_name # => Excel
*/
static VALUE
@@ -790,11 +790,11 @@ typelib_file(VALUE ole)
/*
* call-seq:
- * ole_types -> The array of WIN32OLE::Type object included the type library.
+ * WIN32OLE_TYPELIB#ole_types -> The array of WIN32OLE_TYPE object included the type library.
*
* Returns the type library file path.
*
- * tlib = WIN32OLE::TypeLib.new('Microsoft Excel 9.0 Object Library')
+ * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
* classes = tlib.ole_types.collect{|k| k.name} # -> ['AddIn', 'AddIns' ...]
*/
static VALUE
@@ -809,17 +809,17 @@ foletypelib_ole_types(VALUE self)
/*
* call-seq:
- * inspect -> String
+ * WIN32OLE_TYPELIB#inspect -> String
*
* Returns the type library name with class name.
*
- * tlib = WIN32OLE::TypeLib.new('Microsoft Excel 9.0 Object Library')
- * tlib.inspect # => "<#WIN32OLE::TypeLib:Microsoft Excel 9.0 Object Library>"
+ * tlib = WIN32OLE_TYPELIB.new('Microsoft Excel 9.0 Object Library')
+ * tlib.inspect # => "<#WIN32OLE_TYPELIB:Microsoft Excel 9.0 Object Library>"
*/
static VALUE
foletypelib_inspect(VALUE self)
{
- return default_inspect(self, "WIN32OLE::TypeLib");
+ return default_inspect(self, "WIN32OLE_TYPELIB");
}
VALUE cWIN32OLE_TYPELIB;
@@ -827,8 +827,7 @@ VALUE cWIN32OLE_TYPELIB;
void
Init_win32ole_typelib(void)
{
- cWIN32OLE_TYPELIB = rb_define_class_under(cWIN32OLE, "TypeLib", rb_cObject);
- /* Alias of WIN32OLE::TypeLib, for the backward compatibility */
+ cWIN32OLE_TYPELIB = rb_define_class_under(cWIN32OLE, "Typelib", rb_cObject);
rb_define_const(rb_cObject, "WIN32OLE_TYPELIB", cWIN32OLE_TYPELIB);
rb_define_singleton_method(cWIN32OLE_TYPELIB, "typelibs", foletypelib_s_typelibs, 0);
rb_define_alloc_func(cWIN32OLE_TYPELIB, foletypelib_s_allocate);
diff --git a/ext/win32ole/win32ole_variable.c b/ext/win32ole/win32ole_variable.c
index 34435301d4..e7f58c891e 100644
--- a/ext/win32ole/win32ole_variable.c
+++ b/ext/win32ole/win32ole_variable.c
@@ -43,9 +43,9 @@ olevariable_size(const void *ptr)
}
/*
- * Document-class: WIN32OLE::Variable
+ * Document-class: WIN32OLE_VARIABLE
*
- * +WIN32OLE::Variable+ objects represent OLE variable information.
+ * <code>WIN32OLE_VARIABLE</code> objects represent OLE variable information.
*/
VALUE
@@ -63,11 +63,11 @@ create_win32ole_variable(ITypeInfo *pTypeInfo, UINT index, VALUE name)
/*
* call-seq:
- * name
+ * WIN32OLE_VARIABLE#name
*
* Returns the name of variable.
*
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
* variables = tobj.variables
* variables.each do |variable|
* puts "#{variable.name}"
@@ -103,11 +103,11 @@ ole_variable_ole_type(ITypeInfo *pTypeInfo, UINT var_index)
/*
* call-seq:
- * ole_type
+ * WIN32OLE_VARIABLE#ole_type
*
* Returns OLE type string.
*
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
* variables = tobj.variables
* variables.each do |variable|
* puts "#{variable.ole_type} #{variable.name}"
@@ -145,11 +145,11 @@ ole_variable_ole_type_detail(ITypeInfo *pTypeInfo, UINT var_index)
/*
* call-seq:
- * ole_type_detail
+ * WIN32OLE_VARIABLE#ole_type_detail
*
* Returns detail information of type. The information is array of type.
*
- * tobj = WIN32OLE::Type.new('DirectX 7 for Visual Basic Type Library', 'D3DCLIPSTATUS')
+ * tobj = WIN32OLE_TYPE.new('DirectX 7 for Visual Basic Type Library', 'D3DCLIPSTATUS')
* variable = tobj.variables.find {|variable| variable.name == 'lFlags'}
* tdetail = variable.ole_type_detail
* p tdetail # => ["USERDEFINED", "CONST_D3DCLIPSTATUSFLAGS"]
@@ -180,12 +180,12 @@ ole_variable_value(ITypeInfo *pTypeInfo, UINT var_index)
/*
* call-seq:
- * value
+ * WIN32OLE_VARIABLE#value
*
* Returns value if value is exists. If the value does not exist,
* this method returns nil.
*
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
* variables = tobj.variables
* variables.each do |variable|
* puts "#{variable.name} #{variable.value}"
@@ -227,11 +227,11 @@ ole_variable_visible(ITypeInfo *pTypeInfo, UINT var_index)
/*
* call-seq:
- * visible?
+ * WIN32OLE_VARIABLE#visible?
*
* Returns true if the variable is public.
*
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
* variables = tobj.variables
* variables.each do |variable|
* puts "#{variable.name} #{variable.visible?}"
@@ -284,11 +284,11 @@ ole_variable_kind(ITypeInfo *pTypeInfo, UINT var_index)
/*
* call-seq:
- * variable_kind
+ * WIN32OLE_VARIABLE#variable_kind
*
* Returns variable kind string.
*
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
* variables = tobj.variables
* variables.each do |variable|
* puts "#{variable.name} #{variable.variable_kind}"
@@ -325,10 +325,10 @@ ole_variable_varkind(ITypeInfo *pTypeInfo, UINT var_index)
/*
* call-seq:
- * varkind
+ * WIN32OLE_VARIABLE#varkind
*
* Returns the number which represents variable kind.
- * tobj = WIN32OLE::Type.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
+ * tobj = WIN32OLE_TYPE.new('Microsoft Excel 9.0 Object Library', 'XlSheetType')
* variables = tobj.variables
* variables.each do |variable|
* puts "#{variable.name} #{variable.varkind}"
@@ -351,7 +351,7 @@ folevariable_varkind(VALUE self)
/*
* call-seq:
- * inspect -> String
+ * WIN32OLE_VARIABLE#inspect -> String
*
* Returns the OLE variable name and the value with class name.
*
@@ -362,7 +362,7 @@ folevariable_inspect(VALUE self)
VALUE v = rb_inspect(folevariable_value(self));
VALUE n = folevariable_name(self);
VALUE detail = rb_sprintf("%"PRIsVALUE"=%"PRIsVALUE, n, v);
- return make_inspect("WIN32OLE::Variable", detail);
+ return make_inspect("WIN32OLE_VARIABLE", detail);
}
VALUE cWIN32OLE_VARIABLE;
@@ -370,7 +370,6 @@ VALUE cWIN32OLE_VARIABLE;
void Init_win32ole_variable(void)
{
cWIN32OLE_VARIABLE = rb_define_class_under(cWIN32OLE, "Variable", rb_cObject);
- /* Alias of WIN32OLE::Variable, for the backward compatibility */
rb_define_const(rb_cObject, "WIN32OLE_VARIABLE", cWIN32OLE_VARIABLE);
rb_undef_alloc_func(cWIN32OLE_VARIABLE);
rb_define_method(cWIN32OLE_VARIABLE, "name", folevariable_name, 0);
diff --git a/ext/win32ole/win32ole_variant.c b/ext/win32ole/win32ole_variant.c
index 45c70b1dc3..f1d83ed2e1 100644
--- a/ext/win32ole/win32ole_variant.c
+++ b/ext/win32ole/win32ole_variant.c
@@ -267,7 +267,7 @@ folevariant_s_allocate(VALUE klass)
/*
* call-seq:
- * array(ary, vt)
+ * WIN32OLE_VARIANT.array(ary, vt)
*
* Returns Ruby object wrapping OLE variant whose variant type is VT_ARRAY.
* The first argument should be Array object which specifies dimensions
@@ -277,7 +277,7 @@ folevariant_s_allocate(VALUE klass)
* The following create 2 dimensions OLE array. The first dimensions size
* is 3, and the second is 4.
*
- * ole_ary = WIN32OLE::Variant.array([3,4], VT_I4)
+ * ole_ary = WIN32OLE_VARIANT.array([3,4], VT_I4)
* ruby_ary = ole_ary.value # => [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
*
*/
@@ -357,44 +357,44 @@ check_type_val2variant(VALUE val)
case T_NIL:
break;
default:
- rb_raise(rb_eTypeError, "can not convert WIN32OLE::Variant from type %s",
+ rb_raise(rb_eTypeError, "can not convert WIN32OLE_VARIANT from type %s",
rb_obj_classname(val));
}
}
}
/*
- * Document-class: WIN32OLE::Variant
+ * Document-class: WIN32OLE_VARIANT
*
- * +WIN32OLE::Variant+ objects represents OLE variant.
+ * <code>WIN32OLE_VARIANT</code> objects represents OLE variant.
*
* Win32OLE converts Ruby object into OLE variant automatically when
* invoking OLE methods. If OLE method requires the argument which is
* different from the variant by automatic conversion of Win32OLE, you
- * can convert the specified variant type by using WIN32OLE::Variant class.
+ * can convert the specified variant type by using WIN32OLE_VARIANT class.
*
- * param = WIN32OLE::Variant.new(10, WIN32OLE::VARIANT::VT_R4)
+ * param = WIN32OLE_VARIANT.new(10, WIN32OLE::VARIANT::VT_R4)
* oleobj.method(param)
*
- * WIN32OLE::Variant does not support VT_RECORD variant. Use WIN32OLE::Record
- * class instead of WIN32OLE::Variant if the VT_RECORD variant is needed.
+ * WIN32OLE_VARIANT does not support VT_RECORD variant. Use WIN32OLE_RECORD
+ * class instead of WIN32OLE_VARIANT if the VT_RECORD variant is needed.
*/
/*
* call-seq:
- * new(val, vartype) #=> WIN32OLE::Variant object.
+ * WIN32OLE_VARIANT.new(val, vartype) #=> WIN32OLE_VARIANT object.
*
* Returns Ruby object wrapping OLE variant.
* The first argument specifies Ruby object to convert OLE variant variable.
* The second argument specifies VARIANT type.
- * In some situation, you need the WIN32OLE::Variant object to pass OLE method
+ * In some situation, you need the WIN32OLE_VARIANT object to pass OLE method
*
* shell = WIN32OLE.new("Shell.Application")
* folder = shell.NameSpace("C:\\Windows")
* item = folder.ParseName("tmp.txt")
* # You can't use Ruby String object to call FolderItem.InvokeVerb.
- * # Instead, you have to use WIN32OLE::Variant object to call the method.
- * shortcut = WIN32OLE::Variant.new("Create Shortcut(\&S)")
+ * # Instead, you have to use WIN32OLE_VARIANT object to call the method.
+ * shortcut = WIN32OLE_VARIANT.new("Create Shortcut(\&S)")
* item.invokeVerb(shortcut)
*
*/
@@ -422,7 +422,7 @@ folevariant_initialize(VALUE self, VALUE args)
vvt = rb_ary_entry(args, 1);
vt = RB_NUM2INT(vvt);
if ((vt & VT_TYPEMASK) == VT_RECORD) {
- rb_raise(rb_eArgError, "not supported VT_RECORD WIN32OLE::Variant object");
+ rb_raise(rb_eArgError, "not supported VT_RECORD WIN32OLE_VARIANT object");
}
ole_val2olevariantdata(val, vt, pvar);
}
@@ -482,22 +482,22 @@ unlock_safe_array(SAFEARRAY *psa)
/*
* call-seq:
- * variant[i,j,...] #=> element of OLE array.
+ * WIN32OLE_VARIANT[i,j,...] #=> element of OLE array.
*
- * Returns the element of WIN32OLE::Variant object(OLE array).
+ * Returns the element of WIN32OLE_VARIANT object(OLE array).
* This method is available only when the variant type of
- * WIN32OLE::Variant object is VT_ARRAY.
+ * WIN32OLE_VARIANT object is VT_ARRAY.
*
* REMARK:
* The all indices should be 0 or natural number and
* lower than or equal to max indices.
* (This point is different with Ruby Array indices.)
*
- * obj = WIN32OLE::Variant.new([[1,2,3],[4,5,6]])
+ * obj = WIN32OLE_VARIANT.new([[1,2,3],[4,5,6]])
* p obj[0,0] # => 1
* p obj[1,0] # => 4
- * p obj[2,0] # => WIN32OLE::RuntimeError
- * p obj[0, -1] # => WIN32OLE::RuntimeError
+ * p obj[2,0] # => WIN32OLERuntimeError
+ * p obj[0, -1] # => WIN32OLERuntimeError
*
*/
static VALUE
@@ -537,23 +537,23 @@ folevariant_ary_aref(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * variant[i,j,...] = val #=> set the element of OLE array
+ * WIN32OLE_VARIANT[i,j,...] = val #=> set the element of OLE array
*
- * Set the element of WIN32OLE::Variant object(OLE array) to val.
+ * Set the element of WIN32OLE_VARIANT object(OLE array) to val.
* This method is available only when the variant type of
- * WIN32OLE::Variant object is VT_ARRAY.
+ * WIN32OLE_VARIANT object is VT_ARRAY.
*
* REMARK:
* The all indices should be 0 or natural number and
* lower than or equal to max indices.
* (This point is different with Ruby Array indices.)
*
- * obj = WIN32OLE::Variant.new([[1,2,3],[4,5,6]])
+ * obj = WIN32OLE_VARIANT.new([[1,2,3],[4,5,6]])
* obj[0,0] = 7
* obj[1,0] = 8
* p obj.value # => [[7,2,3], [8,5,6]]
- * obj[2,0] = 9 # => WIN32OLE::RuntimeError
- * obj[0, -1] = 9 # => WIN32OLE::RuntimeError
+ * obj[2,0] = 9 # => WIN32OLERuntimeError
+ * obj[0, -1] = 9 # => WIN32OLERuntimeError
*
*/
static VALUE
@@ -598,10 +598,10 @@ folevariant_ary_aset(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * value #=> Ruby object.
+ * WIN32OLE_VARIANT.value #=> Ruby object.
*
* Returns Ruby object value from OLE variant.
- * obj = WIN32OLE::Variant.new(1, WIN32OLE::VARIANT::VT_BSTR)
+ * obj = WIN32OLE_VARIANT.new(1, WIN32OLE::VARIANT::VT_BSTR)
* obj.value # => "1" (not Integer object, but String object "1")
*
*/
@@ -637,10 +637,10 @@ folevariant_value(VALUE self)
/*
* call-seq:
- * vartype #=> OLE variant type.
+ * WIN32OLE_VARIANT.vartype #=> OLE variant type.
*
* Returns OLE variant type.
- * obj = WIN32OLE::Variant.new("string")
+ * obj = WIN32OLE_VARIANT.new("string")
* obj.vartype # => WIN32OLE::VARIANT::VT_BSTR
*
*/
@@ -654,7 +654,7 @@ folevariant_vartype(VALUE self)
/*
* call-seq:
- * variant.value = val #=> set WIN32OLE::Variant value to val.
+ * WIN32OLE_VARIANT.value = val #=> set WIN32OLE_VARIANT value to val.
*
* Sets variant value to val. If the val type does not match variant value
* type(vartype), then val is changed to match variant value type(vartype)
@@ -662,7 +662,7 @@ folevariant_vartype(VALUE self)
* This method is not available when vartype is VT_ARRAY(except VT_UI1|VT_ARRAY).
* If the vartype is VT_UI1|VT_ARRAY, the val should be String object.
*
- * obj = WIN32OLE::Variant.new(1) # obj.vartype is WIN32OLE::VARIANT::VT_I4
+ * obj = WIN32OLE_VARIANT.new(1) # obj.vartype is WIN32OLE::VARIANT::VT_I4
* obj.value = 3.2 # 3.2 is changed to 3 when setting value.
* p obj.value # => 3
*/
@@ -696,7 +696,6 @@ Init_win32ole_variant(void)
{
#undef rb_intern
cWIN32OLE_VARIANT = rb_define_class_under(cWIN32OLE, "Variant", rb_cObject);
- /* Alias of WIN32OLE::Variant, for the backward compatibility */
rb_define_const(rb_cObject, "WIN32OLE_VARIANT", cWIN32OLE_VARIANT);
rb_define_alloc_func(cWIN32OLE_VARIANT, folevariant_s_allocate);
rb_define_singleton_method(cWIN32OLE_VARIANT, "array", folevariant_s_array, 2);
@@ -730,7 +729,7 @@ Init_win32ole_variant(void)
* This constants is used for not specified parameter.
*
* fso = WIN32OLE.new("Scripting.FileSystemObject")
- * fso.openTextFile(filename, WIN32OLE::Variant::NoParam, false)
+ * fso.openTextFile(filename, WIN32OLE_VARIANT::NoParam, false)
*/
rb_define_const(cWIN32OLE_VARIANT, "NoParam",
rb_funcall(cWIN32OLE_VARIANT, rb_intern("new"), 2, INT2NUM(DISP_E_PARAMNOTFOUND), RB_INT2FIX(VT_ERROR)));
diff --git a/ext/win32ole/win32ole_variant_m.c b/ext/win32ole/win32ole_variant_m.c
index d879506be3..c285a00177 100644
--- a/ext/win32ole/win32ole_variant_m.c
+++ b/ext/win32ole/win32ole_variant_m.c
@@ -5,18 +5,16 @@ VALUE mWIN32OLE_VARIANT;
void Init_win32ole_variant_m(void)
{
/*
- * Document-module: WIN32OLE::VariantType
+ * Document-module: WIN32OLE::VARIANT
*
- * The +WIN32OLE::VariantType+ module includes constants of VARIANT type constants.
- * The constants is used when creating WIN32OLE::Variant object.
+ * The WIN32OLE::VARIANT module includes constants of VARIANT type constants.
+ * The constants is used when creating WIN32OLE_VARIANT object.
*
- * obj = WIN32OLE::Variant.new("2e3", WIN32OLE::VARIANT::VT_R4)
+ * obj = WIN32OLE_VARIANT.new("2e3", WIN32OLE::VARIANT::VT_R4)
* obj.value # => 2000.0
*
*/
- mWIN32OLE_VARIANT = rb_define_module_under(cWIN32OLE, "VariantType");
- /* Alias of WIN32OLE::VariantType, for the backward compatibility */
- rb_define_const(cWIN32OLE, "VARIANT", mWIN32OLE_VARIANT);
+ mWIN32OLE_VARIANT = rb_define_module_under(cWIN32OLE, "VARIANT");
/*
* represents VT_EMPTY type constant.
diff --git a/ext/zlib/depend b/ext/zlib/depend
index bdce420264..15186f8266 100644
--- a/ext/zlib/depend
+++ b/ext/zlib/depend
@@ -53,7 +53,6 @@ zlib.o: $(hdrdir)/ruby/internal/attr/noexcept.h
zlib.o: $(hdrdir)/ruby/internal/attr/noinline.h
zlib.o: $(hdrdir)/ruby/internal/attr/nonnull.h
zlib.o: $(hdrdir)/ruby/internal/attr/noreturn.h
-zlib.o: $(hdrdir)/ruby/internal/attr/packed_struct.h
zlib.o: $(hdrdir)/ruby/internal/attr/pure.h
zlib.o: $(hdrdir)/ruby/internal/attr/restrict.h
zlib.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h
@@ -122,6 +121,7 @@ zlib.o: $(hdrdir)/ruby/internal/intern/enumerator.h
zlib.o: $(hdrdir)/ruby/internal/intern/error.h
zlib.o: $(hdrdir)/ruby/internal/intern/eval.h
zlib.o: $(hdrdir)/ruby/internal/intern/file.h
+zlib.o: $(hdrdir)/ruby/internal/intern/gc.h
zlib.o: $(hdrdir)/ruby/internal/intern/hash.h
zlib.o: $(hdrdir)/ruby/internal/intern/io.h
zlib.o: $(hdrdir)/ruby/internal/intern/load.h
@@ -152,12 +152,12 @@ zlib.o: $(hdrdir)/ruby/internal/memory.h
zlib.o: $(hdrdir)/ruby/internal/method.h
zlib.o: $(hdrdir)/ruby/internal/module.h
zlib.o: $(hdrdir)/ruby/internal/newobj.h
+zlib.o: $(hdrdir)/ruby/internal/rgengc.h
zlib.o: $(hdrdir)/ruby/internal/scan_args.h
zlib.o: $(hdrdir)/ruby/internal/special_consts.h
zlib.o: $(hdrdir)/ruby/internal/static_assert.h
zlib.o: $(hdrdir)/ruby/internal/stdalign.h
zlib.o: $(hdrdir)/ruby/internal/stdbool.h
-zlib.o: $(hdrdir)/ruby/internal/stdckdint.h
zlib.o: $(hdrdir)/ruby/internal/symbol.h
zlib.o: $(hdrdir)/ruby/internal/value.h
zlib.o: $(hdrdir)/ruby/internal/value_type.h
diff --git a/ext/zlib/extconf.rb b/ext/zlib/extconf.rb
index 2b2dbb1a5b..5477f49178 100644
--- a/ext/zlib/extconf.rb
+++ b/ext/zlib/extconf.rb
@@ -11,9 +11,10 @@ require 'rbconfig'
dir_config 'zlib'
libs = $libs
-have_zlib = %w'z libz zlib1 zlib zdll zlibwapi'.any? {|z| have_library(z, 'deflateReset(NULL)', 'zlib.h')}
-
-unless have_zlib
+if %w'z libz zlib1 zlib zdll zlibwapi'.find {|z| have_library(z, 'deflateReset')} and
+ have_header('zlib.h') then
+ have_zlib = true
+else
$libs = libs
unless File.directory?(zsrc = "#{$srcdir}/zlib")
dirs = Dir.open($srcdir) {|z| z.grep(/\Azlib-\d+[.\d]*\z/) {|x|"#{$srcdir}/#{x}"}}
@@ -120,18 +121,12 @@ if have_zlib
$defs << "-DHAVE_CRC32_COMBINE"
$defs << "-DHAVE_ADLER32_COMBINE"
$defs << "-DHAVE_TYPE_Z_CRC_T"
- $defs << "-DHAVE_CRC32_Z"
- $defs << "-DHAVE_ADLER32_Z"
- $defs << "-DHAVE_ZLIB_SIZE_T_FUNCS"
+ $defs << "-DHAVE_TYPE_Z_SIZE_T"
else
have_func('crc32_combine', 'zlib.h')
have_func('adler32_combine', 'zlib.h')
have_type('z_crc_t', 'zlib.h')
- if (have_type('z_size_t', 'zlib.h') &&
- have_func('crc32_z', 'zlib.h') &&
- have_func('adler32_z', 'zlib.h'))
- $defs << "-DHAVE_ZLIB_SIZE_T_FUNCS"
- end
+ have_type('z_size_t', 'zlib.h')
end
create_makefile('zlib') {|conf|
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index 50d8dd40c6..aefdba0ebd 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -25,7 +25,7 @@
# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0
#endif
-#define RUBY_ZLIB_VERSION "3.1.1"
+#define RUBY_ZLIB_VERSION "3.0.0"
#ifndef RB_PASS_CALLED_KEYWORDS
# define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
@@ -44,7 +44,7 @@
#endif
#endif
-#if defined(HAVE_ZLIB_SIZE_T_FUNCS)
+#if defined(HAVE_TYPE_Z_SIZE_T)
typedef uLong (*checksum_func)(uLong, const Bytef*, z_size_t);
# define crc32 crc32_z
# define adler32 adler32_z
@@ -90,7 +90,7 @@ static void zstream_expand_buffer_into(struct zstream*, unsigned long);
static int zstream_expand_buffer_non_stream(struct zstream *z);
static void zstream_append_buffer(struct zstream*, const Bytef*, long);
static VALUE zstream_detach_buffer(struct zstream*);
-static VALUE zstream_shift_buffer(struct zstream*, long, VALUE);
+static VALUE zstream_shift_buffer(struct zstream*, long);
static void zstream_buffer_ungets(struct zstream*, const Bytef*, unsigned long);
static void zstream_buffer_ungetbyte(struct zstream*, int);
static void zstream_append_input(struct zstream*, const Bytef*, long);
@@ -170,8 +170,8 @@ static void gzfile_check_footer(struct gzfile*, VALUE outbuf);
static void gzfile_write(struct gzfile*, Bytef*, long);
static long gzfile_read_more(struct gzfile*, VALUE outbuf);
static void gzfile_calc_crc(struct gzfile*, VALUE);
-static VALUE gzfile_read(struct gzfile*, long, VALUE);
-static VALUE gzfile_read_all(struct gzfile*, VALUE);
+static VALUE gzfile_read(struct gzfile*, long);
+static VALUE gzfile_read_all(struct gzfile*);
static void gzfile_ungets(struct gzfile*, const Bytef*, long);
static void gzfile_ungetbyte(struct gzfile*, int);
static VALUE gzfile_writer_end_run(VALUE);
@@ -388,7 +388,7 @@ rb_zlib_version(VALUE klass)
# define mask32(x) (x)
#endif
-#if SIZEOF_LONG > SIZEOF_INT && !defined(HAVE_ZLIB_SIZE_T_FUNCS)
+#if SIZEOF_LONG > SIZEOF_INT && !defined(HAVE_TYPE_Z_SIZE_T)
static uLong
checksum_long(uLong (*func)(uLong, const Bytef*, uInt), uLong sum, const Bytef *ptr, long len)
{
@@ -820,31 +820,19 @@ zstream_detach_buffer(struct zstream *z)
}
static VALUE
-zstream_shift_buffer(struct zstream *z, long len, VALUE dst)
+zstream_shift_buffer(struct zstream *z, long len)
{
+ VALUE dst;
char *bufptr;
long buflen = ZSTREAM_BUF_FILLED(z);
if (buflen <= len) {
- if (NIL_P(dst) || (!ZSTREAM_IS_FINISHED(z) && !ZSTREAM_IS_GZFILE(z) &&
- rb_block_given_p())) {
- return zstream_detach_buffer(z);
- } else {
- bufptr = RSTRING_PTR(z->buf);
- rb_str_resize(dst, buflen);
- memcpy(RSTRING_PTR(dst), bufptr, buflen);
- }
- buflen = 0;
- } else {
- bufptr = RSTRING_PTR(z->buf);
- if (NIL_P(dst)) {
- dst = rb_str_new(bufptr, len);
- } else {
- rb_str_resize(dst, len);
- memcpy(RSTRING_PTR(dst), bufptr, len);
- }
- buflen -= len;
+ return zstream_detach_buffer(z);
}
+
+ bufptr = RSTRING_PTR(z->buf);
+ dst = rb_str_new(bufptr, len);
+ buflen -= len;
memmove(bufptr, bufptr + len, buflen);
rb_str_set_len(z->buf, buflen);
z->stream.next_out = (Bytef*)RSTRING_END(z->buf);
@@ -935,7 +923,7 @@ zstream_discard_input(struct zstream *z, long len)
z->input = Qnil;
}
else {
- z->input = rb_str_subseq(z->input, len,
+ z->input = rb_str_substr(z->input, len,
RSTRING_LEN(z->input) - len);
}
}
@@ -2886,18 +2874,18 @@ gzfile_newstr(struct gzfile *gz, VALUE str)
}
static long
-gzfile_fill(struct gzfile *gz, long len, VALUE outbuf)
+gzfile_fill(struct gzfile *gz, long len)
{
if (len < 0)
rb_raise(rb_eArgError, "negative length %ld given", len);
if (len == 0)
return 0;
while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) < len) {
- gzfile_read_more(gz, outbuf);
+ gzfile_read_more(gz, Qnil);
}
if (GZFILE_IS_FINISHED(gz)) {
if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
- gzfile_check_footer(gz, outbuf);
+ gzfile_check_footer(gz, Qnil);
}
return -1;
}
@@ -2905,27 +2893,14 @@ gzfile_fill(struct gzfile *gz, long len, VALUE outbuf)
}
static VALUE
-gzfile_read(struct gzfile *gz, long len, VALUE outbuf)
+gzfile_read(struct gzfile *gz, long len)
{
VALUE dst;
- len = gzfile_fill(gz, len, outbuf);
-
- if (len < 0) {
- if (!NIL_P(outbuf))
- rb_str_resize(outbuf, 0);
- return Qnil;
- }
- if (len == 0) {
- if (NIL_P(outbuf))
- return rb_str_new(0, 0);
- else {
- rb_str_resize(outbuf, 0);
- return outbuf;
- }
- }
-
- dst = zstream_shift_buffer(&gz->z, len, outbuf);
+ len = gzfile_fill(gz, len);
+ if (len == 0) return rb_str_new(0, 0);
+ if (len < 0) return Qnil;
+ dst = zstream_shift_buffer(&gz->z, len);
if (!NIL_P(dst)) gzfile_calc_crc(gz, dst);
return dst;
}
@@ -2958,26 +2933,29 @@ gzfile_readpartial(struct gzfile *gz, long len, VALUE outbuf)
rb_raise(rb_eEOFError, "end of file reached");
}
- dst = zstream_shift_buffer(&gz->z, len, outbuf);
+ dst = zstream_shift_buffer(&gz->z, len);
gzfile_calc_crc(gz, dst);
+ if (!NIL_P(outbuf)) {
+ rb_str_resize(outbuf, RSTRING_LEN(dst));
+ memcpy(RSTRING_PTR(outbuf), RSTRING_PTR(dst), RSTRING_LEN(dst));
+ dst = outbuf;
+ }
return dst;
}
static VALUE
-gzfile_read_all(struct gzfile *gz, VALUE dst)
+gzfile_read_all(struct gzfile *gz)
{
+ VALUE dst;
+
while (!ZSTREAM_IS_FINISHED(&gz->z)) {
- gzfile_read_more(gz, dst);
+ gzfile_read_more(gz, Qnil);
}
if (GZFILE_IS_FINISHED(gz)) {
if (!(gz->z.flags & GZFILE_FLAG_FOOTER_FINISHED)) {
- gzfile_check_footer(gz, dst);
+ gzfile_check_footer(gz, Qnil);
}
- if (!NIL_P(dst)) {
- rb_str_resize(dst, 0);
- return dst;
- }
return rb_str_new(0, 0);
}
@@ -3015,7 +2993,7 @@ gzfile_getc(struct gzfile *gz)
de = (unsigned char *)ds + GZFILE_CBUF_CAPA;
(void)rb_econv_convert(gz->ec, &sp, se, &dp, de, ECONV_PARTIAL_INPUT|ECONV_AFTER_OUTPUT);
rb_econv_check_error(gz->ec);
- dst = zstream_shift_buffer(&gz->z, sp - ss, Qnil);
+ dst = zstream_shift_buffer(&gz->z, sp - ss);
gzfile_calc_crc(gz, dst);
rb_str_resize(cbuf, dp - ds);
return cbuf;
@@ -3023,7 +3001,7 @@ gzfile_getc(struct gzfile *gz)
else {
buf = gz->z.buf;
len = rb_enc_mbclen(RSTRING_PTR(buf), RSTRING_END(buf), gz->enc);
- dst = gzfile_read(gz, len, Qnil);
+ dst = gzfile_read(gz, len);
if (NIL_P(dst)) return dst;
return gzfile_newstr(gz, dst);
}
@@ -3522,9 +3500,6 @@ static VALUE
rb_gzfile_eof_p(VALUE obj)
{
struct gzfile *gz = get_gzfile(obj);
- while (!ZSTREAM_IS_FINISHED(&gz->z) && ZSTREAM_BUF_FILLED(&gz->z) == 0) {
- gzfile_read_more(gz, Qnil);
- }
return GZFILE_IS_FINISHED(gz) ? Qtrue : Qfalse;
}
@@ -3931,7 +3906,7 @@ rb_gzreader_s_zcat(int argc, VALUE *argv, VALUE klass)
if (!buf) {
buf = rb_str_new(0, 0);
}
- tmpbuf = gzfile_read_all(get_gzfile(obj), Qnil);
+ tmpbuf = gzfile_read_all(get_gzfile(obj));
rb_str_cat(buf, RSTRING_PTR(tmpbuf), RSTRING_LEN(tmpbuf));
}
@@ -4033,19 +4008,19 @@ static VALUE
rb_gzreader_read(int argc, VALUE *argv, VALUE obj)
{
struct gzfile *gz = get_gzfile(obj);
- VALUE vlen, outbuf;
+ VALUE vlen;
long len;
- rb_scan_args(argc, argv, "02", &vlen, &outbuf);
+ rb_scan_args(argc, argv, "01", &vlen);
if (NIL_P(vlen)) {
- return gzfile_read_all(gz, outbuf);
+ return gzfile_read_all(gz);
}
len = NUM2INT(vlen);
if (len < 0) {
rb_raise(rb_eArgError, "negative length %ld given", len);
}
- return gzfile_read(gz, len, outbuf);
+ return gzfile_read(gz, len);
}
/*
@@ -4118,7 +4093,7 @@ rb_gzreader_getbyte(VALUE obj)
struct gzfile *gz = get_gzfile(obj);
VALUE dst;
- dst = gzfile_read(gz, 1, Qnil);
+ dst = gzfile_read(gz, 1);
if (!NIL_P(dst)) {
dst = INT2FIX((unsigned int)(RSTRING_PTR(dst)[0]) & 0xff);
}
@@ -4239,7 +4214,7 @@ gzreader_skip_linebreaks(struct gzfile *gz)
}
}
- str = zstream_shift_buffer(&gz->z, n - 1, Qnil);
+ str = zstream_shift_buffer(&gz->z, n - 1);
gzfile_calc_crc(gz, str);
}
@@ -4260,7 +4235,7 @@ gzreader_charboundary(struct gzfile *gz, long n)
if (l < n) {
int n_bytes = rb_enc_precise_mbclen(p, e, gz->enc);
if (MBCLEN_NEEDMORE_P(n_bytes)) {
- if ((l = gzfile_fill(gz, n + MBCLEN_NEEDMORE_LEN(n_bytes), Qnil)) > 0) {
+ if ((l = gzfile_fill(gz, n + MBCLEN_NEEDMORE_LEN(n_bytes))) > 0) {
return l;
}
}
@@ -4312,10 +4287,10 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
if (NIL_P(rs)) {
if (limit < 0) {
- dst = gzfile_read_all(gz, Qnil);
+ dst = gzfile_read_all(gz);
if (RSTRING_LEN(dst) == 0) return Qnil;
}
- else if ((n = gzfile_fill(gz, limit, Qnil)) <= 0) {
+ else if ((n = gzfile_fill(gz, limit)) <= 0) {
return Qnil;
}
else {
@@ -4325,7 +4300,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
else {
n = limit;
}
- dst = zstream_shift_buffer(&gz->z, n, Qnil);
+ dst = zstream_shift_buffer(&gz->z, n);
if (NIL_P(dst)) return dst;
gzfile_calc_crc(gz, dst);
dst = gzfile_newstr(gz, dst);
@@ -4352,7 +4327,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
while (ZSTREAM_BUF_FILLED(&gz->z) < rslen) {
if (ZSTREAM_IS_FINISHED(&gz->z)) {
if (ZSTREAM_BUF_FILLED(&gz->z) > 0) gz->lineno++;
- return gzfile_read(gz, rslen, Qnil);
+ return gzfile_read(gz, rslen);
}
gzfile_read_more(gz, Qnil);
}
@@ -4389,7 +4364,7 @@ gzreader_gets(int argc, VALUE *argv, VALUE obj)
}
gz->lineno++;
- dst = gzfile_read(gz, n, Qnil);
+ dst = gzfile_read(gz, n);
if (NIL_P(dst)) return dst;
if (rspara) {
gzreader_skip_linebreaks(gz);
diff --git a/ext/zlib/zlib.gemspec b/ext/zlib/zlib.gemspec
index 345dc5f225..4a5f8f2ee8 100644
--- a/ext/zlib/zlib.gemspec
+++ b/ext/zlib/zlib.gemspec
@@ -22,10 +22,10 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/ruby/zlib"
spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.files = ["COPYING", "BSDL", "README.md", "ext/zlib/extconf.rb", "ext/zlib/zlib.c", "zlib.gemspec"]
+ spec.files = ["LICENSE.txt", "README.md", "ext/zlib/extconf.rb", "ext/zlib/zlib.c", "zlib.gemspec"]
spec.bindir = "exe"
spec.executables = []
spec.require_paths = ["lib"]
spec.extensions = "ext/zlib/extconf.rb"
- spec.required_ruby_version = ">= 2.5.0"
+ spec.required_ruby_version = ">= 2.3.0"
end
diff --git a/file.c b/file.c
index 1ba2eae98f..3a8439ef07 100644
--- a/file.c
+++ b/file.c
@@ -129,7 +129,7 @@ int flock(int, int);
# endif
#else
# define STAT(p, s) stat((p), (s))
-#endif /* _WIN32 */
+#endif
#if defined _WIN32 || defined __APPLE__
# define USE_OSPATH 1
@@ -169,6 +169,7 @@ int flock(int, int);
#include "internal/thread.h"
#include "internal/vm.h"
#include "ruby/encoding.h"
+#include "ruby/io.h"
#include "ruby/thread.h"
#include "ruby/util.h"
@@ -263,7 +264,7 @@ rb_str_encode_ospath(VALUE path)
rb_encoding *utf8 = rb_utf8_encoding();
path = rb_str_conv_enc(path, enc, utf8);
}
-#endif /* USE_OSPATH */
+#endif
return path;
}
@@ -271,18 +272,6 @@ rb_str_encode_ospath(VALUE path)
# define NORMALIZE_UTF8PATH 1
# ifdef HAVE_WORKING_FORK
-static CFMutableStringRef
-mutable_CFString_new(CFStringRef *s, const char *ptr, long len)
-{
- const CFAllocatorRef alloc = kCFAllocatorDefault;
- *s = CFStringCreateWithBytesNoCopy(alloc, (const UInt8 *)ptr, len,
- kCFStringEncodingUTF8, FALSE,
- kCFAllocatorNull);
- return CFStringCreateMutableCopy(alloc, len, *s);
-}
-
-# define mutable_CFString_release(m, s) (CFRelease(m), CFRelease(s))
-
static void
rb_CFString_class_initialize_before_fork(void)
{
@@ -309,19 +298,28 @@ rb_CFString_class_initialize_before_fork(void)
/* Enough small but non-empty ASCII string to fit in NSTaggedPointerString. */
const char small_str[] = "/";
long len = sizeof(small_str) - 1;
- CFStringRef s;
- CFMutableStringRef m = mutable_CFString_new(&s, small_str, len);
- mutable_CFString_release(m, s);
+
+ const CFAllocatorRef alloc = kCFAllocatorDefault;
+ CFStringRef s = CFStringCreateWithBytesNoCopy(alloc,
+ (const UInt8 *)small_str,
+ len, kCFStringEncodingUTF8,
+ FALSE, kCFAllocatorNull);
+ CFMutableStringRef m = CFStringCreateMutableCopy(alloc, len, s);
+ CFRelease(m);
+ CFRelease(s);
}
-# endif /* HAVE_WORKING_FORK */
+# endif
static VALUE
rb_str_append_normalized_ospath(VALUE str, const char *ptr, long len)
{
CFIndex buflen = 0;
CFRange all;
- CFStringRef s;
- CFMutableStringRef m = mutable_CFString_new(&s, ptr, len);
+ CFStringRef s = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault,
+ (const UInt8 *)ptr, len,
+ kCFStringEncodingUTF8, FALSE,
+ kCFAllocatorNull);
+ CFMutableStringRef m = CFStringCreateMutableCopy(kCFAllocatorDefault, len, s);
long oldlen = RSTRING_LEN(str);
CFStringNormalize(m, kCFStringNormalizationFormC);
@@ -331,7 +329,8 @@ rb_str_append_normalized_ospath(VALUE str, const char *ptr, long len)
CFStringGetBytes(m, all, kCFStringEncodingUTF8, '?', FALSE,
(UInt8 *)(RSTRING_PTR(str) + oldlen), buflen, &buflen);
rb_str_set_len(str, oldlen + buflen);
- mutable_CFString_release(m, s);
+ CFRelease(m);
+ CFRelease(s);
return str;
}
@@ -410,9 +409,9 @@ ignored_char_p(const char *p, const char *e, rb_encoding *enc)
}
return 0;
}
-#else /* !__APPLE__ */
+#else
# define NORMALIZE_UTF8PATH 0
-#endif /* __APPLE__ */
+#endif
#define apply2args(n) (rb_check_arity(argc, n, UNLIMITED_ARGUMENTS), argc-=n)
@@ -470,7 +469,7 @@ apply2files(int (*func)(const char *, void *), int argc, VALUE *argv, void *arg)
aa->fn[aa->i].path = path;
}
- IO_WITHOUT_GVL(no_gvl_apply2files, aa);
+ rb_thread_call_without_gvl(no_gvl_apply2files, aa, RUBY_UBF_IO, 0);
if (aa->errnum) {
#ifdef UTIME_EINVAL
if (func == utime_internal) {
@@ -485,29 +484,28 @@ apply2files(int (*func)(const char *, void *), int argc, VALUE *argv, void *arg)
return LONG2FIX(argc);
}
+static size_t
+stat_memsize(const void *p)
+{
+ return sizeof(struct stat);
+}
+
static const rb_data_type_t stat_data_type = {
"stat",
- {
- NULL,
- RUBY_TYPED_DEFAULT_FREE,
- NULL, // No external memory to report
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
-};
-
-struct rb_stat {
- struct stat stat;
- bool initialized;
+ {NULL, RUBY_TYPED_DEFAULT_FREE, stat_memsize,},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static VALUE
stat_new_0(VALUE klass, const struct stat *st)
{
- struct rb_stat *rb_st;
- VALUE obj = TypedData_Make_Struct(klass, struct rb_stat, &stat_data_type, rb_st);
+ struct stat *nst = 0;
+ VALUE obj = TypedData_Wrap_Struct(klass, &stat_data_type, 0);
+
if (st) {
- rb_st->stat = *st;
- rb_st->initialized = true;
+ nst = ALLOC(struct stat);
+ *nst = *st;
+ RTYPEDDATA_DATA(obj) = nst;
}
return obj;
}
@@ -521,10 +519,10 @@ rb_stat_new(const struct stat *st)
static struct stat*
get_stat(VALUE self)
{
- struct rb_stat* rb_st;
- TypedData_Get_Struct(self, struct rb_stat, &stat_data_type, rb_st);
- if (!rb_st->initialized) rb_raise(rb_eTypeError, "uninitialized File::Stat");
- return &rb_st->stat;
+ struct stat* st;
+ TypedData_Get_Struct(self, struct stat, &stat_data_type, st);
+ if (!st) rb_raise(rb_eTypeError, "uninitialized File::Stat");
+ return st;
}
static struct timespec stat_mtimespec(const struct stat *st);
@@ -966,7 +964,7 @@ typedef struct stat statx_data;
# define stat_birthtime stat_ctime
#else
# undef HAVE_STAT_BIRTHTIME
-#endif /* defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) */
+#endif
/*
* call-seq:
@@ -1095,9 +1093,9 @@ rb_stat_inspect(VALUE self)
#endif
};
- struct rb_stat* rb_st;
- TypedData_Get_Struct(self, struct rb_stat, &stat_data_type, rb_st);
- if (!rb_st->initialized) {
+ struct stat* st;
+ TypedData_Get_Struct(self, struct stat, &stat_data_type, st);
+ if (!st) {
return rb_sprintf("#<%s: uninitialized>", rb_obj_classname(self));
}
@@ -1145,14 +1143,14 @@ no_gvl_fstat(void *data)
}
static int
-fstat_without_gvl(rb_io_t *fptr, struct stat *st)
+fstat_without_gvl(int fd, struct stat *st)
{
no_gvl_stat_data data;
- data.file.fd = fptr->fd;
+ data.file.fd = fd;
data.st = st;
- return (int)rb_io_blocking_region(fptr, no_gvl_fstat, &data);
+ return (int)(VALUE)rb_thread_io_blocking_region(no_gvl_fstat, &data, fd);
}
static void *
@@ -1170,7 +1168,8 @@ stat_without_gvl(const char *path, struct stat *st)
data.file.path = path;
data.st = st;
- return IO_WITHOUT_GVL_INT(no_gvl_stat, &data);
+ return (int)(VALUE)rb_thread_call_without_gvl(no_gvl_stat, &data,
+ RUBY_UBF_IO, NULL);
}
#if !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) && \
@@ -1190,8 +1189,8 @@ statx(int dirfd, const char *pathname, int flags,
{
return (int)syscall(__NR_statx, dirfd, pathname, flags, mask, statxbuf);
}
-# endif /* __linux__ */
-# endif /* HAVE_STATX */
+# endif
+# endif
typedef struct no_gvl_statx_data {
struct statx *stx;
@@ -1220,16 +1219,17 @@ statx_without_gvl(const char *path, struct statx *stx, unsigned int mask)
no_gvl_statx_data data = {stx, AT_FDCWD, path, 0, mask};
/* call statx(2) with pathname */
- return IO_WITHOUT_GVL_INT(no_gvl_statx, &data);
+ return (int)(VALUE)rb_thread_call_without_gvl(no_gvl_statx, &data,
+ RUBY_UBF_IO, NULL);
}
static int
-fstatx_without_gvl(rb_io_t *fptr, struct statx *stx, unsigned int mask)
+fstatx_without_gvl(int fd, struct statx *stx, unsigned int mask)
{
- no_gvl_statx_data data = {stx, fptr->fd, "", AT_EMPTY_PATH, mask};
+ no_gvl_statx_data data = {stx, fd, "", AT_EMPTY_PATH, mask};
/* call statx(2) with fd */
- return (int)rb_io_blocking_region(fptr, io_blocking_statx, &data);
+ return (int)rb_thread_io_blocking_region(io_blocking_statx, &data, fd);
}
static int
@@ -1242,7 +1242,7 @@ rb_statx(VALUE file, struct statx *stx, unsigned int mask)
if (!NIL_P(tmp)) {
rb_io_t *fptr;
GetOpenFile(tmp, fptr);
- result = fstatx_without_gvl(fptr, stx, mask);
+ result = fstatx_without_gvl(fptr->fd, stx, mask);
file = tmp;
}
else {
@@ -1283,14 +1283,13 @@ typedef struct statx statx_data;
#elif defined(HAVE_STAT_BIRTHTIME)
# define statx_without_gvl(path, st, mask) stat_without_gvl(path, st)
-# define fstatx_without_gvl(fptr, st, mask) fstat_without_gvl(fptr, st)
+# define fstatx_without_gvl(fd, st, mask) fstat_without_gvl(fd, st)
# define statx_birthtime(st, fname) stat_birthtime(st)
# define statx_has_birthtime(st) 1
# define rb_statx(file, st, mask) rb_stat(file, st)
#else
# define statx_has_birthtime(st) 0
-#endif /* !defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC) && \
- defined(HAVE_STRUCT_STATX_STX_BTIME) */
+#endif
static int
rb_stat(VALUE file, struct stat *st)
@@ -1303,7 +1302,7 @@ rb_stat(VALUE file, struct stat *st)
rb_io_t *fptr;
GetOpenFile(tmp, fptr);
- result = fstat_without_gvl(fptr, st);
+ result = fstat_without_gvl(fptr->fd, st);
file = tmp;
}
else {
@@ -1382,7 +1381,8 @@ lstat_without_gvl(const char *path, struct stat *st)
data.file.path = path;
data.st = st;
- return IO_WITHOUT_GVL_INT(no_gvl_lstat, &data);
+ return (int)(VALUE)rb_thread_call_without_gvl(no_gvl_lstat, &data,
+ RUBY_UBF_IO, NULL);
}
#endif /* HAVE_LSTAT */
@@ -1478,7 +1478,7 @@ rb_group_member(GETGROUPS_T gid)
ALLOCV_END(v);
return rv;
-#endif /* defined(_WIN32) || !defined(HAVE_GETGROUPS) */
+#endif
}
#ifndef S_IXUGO
@@ -1529,9 +1529,9 @@ eaccess(const char *path, int mode)
return -1;
#else
return access(path, mode);
-#endif /* USE_GETEUID */
+#endif
}
-#endif /* HAVE_EACCESS */
+#endif
struct access_arg {
const char *path;
@@ -1556,7 +1556,8 @@ rb_eaccess(VALUE fname, int mode)
aa.path = StringValueCStr(fname);
aa.mode = mode;
- return IO_WITHOUT_GVL_INT(nogvl_eaccess, &aa);
+ return (int)(VALUE)rb_thread_call_without_gvl(nogvl_eaccess, &aa,
+ RUBY_UBF_IO, 0);
}
static void *
@@ -1577,7 +1578,8 @@ rb_access(VALUE fname, int mode)
aa.path = StringValueCStr(fname);
aa.mode = mode;
- return IO_WITHOUT_GVL_INT(nogvl_access, &aa);
+ return (int)(VALUE)rb_thread_call_without_gvl(nogvl_access, &aa,
+ RUBY_UBF_IO, 0);
}
/*
@@ -1591,6 +1593,8 @@ rb_access(VALUE fname, int mode)
*/
/*
+ * Document-method: directory?
+ *
* call-seq:
* File.directory?(path) -> true or false
*
@@ -1769,7 +1773,7 @@ rb_file_blockdev_p(VALUE obj, VALUE fname)
*
* Returns +true+ if +filepath+ points to a character device, +false+ otherwise.
*
- * File.chardev?($stdin) # => true
+ * File.chardev?($stdin) # => true
* File.chardev?('t.txt') # => false
*
*/
@@ -2450,7 +2454,6 @@ rb_file_ctime(VALUE obj)
return stat_ctime(&st);
}
-#if defined(HAVE_STAT_BIRTHTIME)
/*
* call-seq:
* File.birthtime(file_name) -> time
@@ -2465,7 +2468,8 @@ rb_file_ctime(VALUE obj)
*
*/
-VALUE
+#if defined(HAVE_STAT_BIRTHTIME)
+RUBY_FUNC_EXPORTED VALUE
rb_file_s_birthtime(VALUE klass, VALUE fname)
{
statx_data st;
@@ -2501,7 +2505,7 @@ rb_file_birthtime(VALUE obj)
statx_data st;
GetOpenFile(obj, fptr);
- if (fstatx_without_gvl(fptr, &st, STATX_BTIME) == -1) {
+ if (fstatx_without_gvl(fptr->fd, &st, STATX_BTIME) == -1) {
rb_sys_fail_path(fptr->pathv);
}
return statx_birthtime(&st, fptr->pathv);
@@ -2510,6 +2514,16 @@ rb_file_birthtime(VALUE obj)
# define rb_file_birthtime rb_f_notimplement
#endif
+/*
+ * call-seq:
+ * file.size -> integer
+ *
+ * Returns the size of <i>file</i> in bytes.
+ *
+ * File.new("testfile").size #=> 66
+ *
+ */
+
rb_off_t
rb_file_size(VALUE file)
{
@@ -2533,45 +2547,12 @@ rb_file_size(VALUE file)
}
}
-/*
- * call-seq:
- * file.size -> integer
- *
- * Returns the size of <i>file</i> in bytes.
- *
- * File.new("testfile").size #=> 66
- *
- */
-
static VALUE
file_size(VALUE self)
{
return OFFT2NUM(rb_file_size(self));
}
-struct nogvl_chmod_data {
- const char *path;
- mode_t mode;
-};
-
-static void *
-nogvl_chmod(void *ptr)
-{
- struct nogvl_chmod_data *data = ptr;
- int ret = chmod(data->path, data->mode);
- return (void *)(VALUE)ret;
-}
-
-static int
-rb_chmod(const char *path, mode_t mode)
-{
- struct nogvl_chmod_data data = {
- .path = path,
- .mode = mode,
- };
- return IO_WITHOUT_GVL_INT(nogvl_chmod, &data);
-}
-
static int
chmod_internal(const char *path, void *mode)
{
@@ -2602,29 +2583,6 @@ rb_file_s_chmod(int argc, VALUE *argv, VALUE _)
return apply2files(chmod_internal, argc, argv, &mode);
}
-#ifdef HAVE_FCHMOD
-struct nogvl_fchmod_data {
- int fd;
- mode_t mode;
-};
-
-static VALUE
-io_blocking_fchmod(void *ptr)
-{
- struct nogvl_fchmod_data *data = ptr;
- int ret = fchmod(data->fd, data->mode);
- return (VALUE)ret;
-}
-
-static int
-rb_fchmod(int fd, mode_t mode)
-{
- (void)rb_chmod; /* suppress unused-function warning when HAVE_FCHMOD */
- struct nogvl_fchmod_data data = {.fd = fd, .mode = mode};
- return (int)rb_thread_io_blocking_region(io_blocking_fchmod, &data, fd);
-}
-#endif
-
/*
* call-seq:
* file.chmod(mode_int) -> 0
@@ -2651,7 +2609,7 @@ rb_file_chmod(VALUE obj, VALUE vmode)
GetOpenFile(obj, fptr);
#ifdef HAVE_FCHMOD
- if (rb_fchmod(fptr->fd, mode) == -1) {
+ if (fchmod(fptr->fd, mode) == -1) {
if (HAVE_FCHMOD || errno != ENOSYS)
rb_sys_fail_path(fptr->pathv);
}
@@ -2662,7 +2620,7 @@ rb_file_chmod(VALUE obj, VALUE vmode)
#if !defined HAVE_FCHMOD || !HAVE_FCHMOD
if (NIL_P(fptr->pathv)) return Qnil;
path = rb_str_encode_ospath(fptr->pathv);
- if (rb_chmod(RSTRING_PTR(path), mode) == -1)
+ if (chmod(RSTRING_PTR(path), mode) == -1)
rb_sys_fail_path(fptr->pathv);
#endif
@@ -2757,51 +2715,6 @@ rb_file_s_chown(int argc, VALUE *argv, VALUE _)
return apply2files(chown_internal, argc, argv, &arg);
}
-struct nogvl_chown_data {
- union {
- const char *path;
- int fd;
- } as;
- struct chown_args new;
-};
-
-static void *
-nogvl_chown(void *ptr)
-{
- struct nogvl_chown_data *data = ptr;
- return (void *)(VALUE)chown(data->as.path, data->new.owner, data->new.group);
-}
-
-static int
-rb_chown(const char *path, rb_uid_t owner, rb_gid_t group)
-{
- struct nogvl_chown_data data = {
- .as = {.path = path},
- .new = {.owner = owner, .group = group},
- };
- return IO_WITHOUT_GVL_INT(nogvl_chown, &data);
-}
-
-#ifdef HAVE_FCHOWN
-static void *
-nogvl_fchown(void *ptr)
-{
- struct nogvl_chown_data *data = ptr;
- return (void *)(VALUE)fchown(data->as.fd, data->new.owner, data->new.group);
-}
-
-static int
-rb_fchown(int fd, rb_uid_t owner, rb_gid_t group)
-{
- (void)rb_chown; /* suppress unused-function warning when HAVE_FCHMOD */
- struct nogvl_chown_data data = {
- .as = {.fd = fd},
- .new = {.owner = owner, .group = group},
- };
- return IO_WITHOUT_GVL_INT(nogvl_fchown, &data);
-}
-#endif
-
/*
* call-seq:
* file.chown(owner_int, group_int ) -> 0
@@ -2833,10 +2746,10 @@ rb_file_chown(VALUE obj, VALUE owner, VALUE group)
#ifndef HAVE_FCHOWN
if (NIL_P(fptr->pathv)) return Qnil;
path = rb_str_encode_ospath(fptr->pathv);
- if (rb_chown(RSTRING_PTR(path), o, g) == -1)
+ if (chown(RSTRING_PTR(path), o, g) == -1)
rb_sys_fail_path(fptr->pathv);
#else
- if (rb_fchown(fptr->fd, o, g) == -1)
+ if (fchown(fptr->fd, o, g) == -1)
rb_sys_fail_path(fptr->pathv);
#endif
@@ -2923,7 +2836,7 @@ utime_failed(struct apply_arg *aa)
}
rb_syserr_fail_path(e, path);
}
-#endif /* UTIME_EINVAL */
+#endif
#if defined(HAVE_UTIMES)
@@ -2932,7 +2845,7 @@ utime_failed(struct apply_arg *aa)
# elif defined(__APPLE__) && \
(!defined(MAC_OS_X_VERSION_13_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_13_0))
-# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
+# if defined(__has_attribute) && __has_attribute(availability)
typedef int utimensat_func(int, const char *, const struct timespec [2], int);
RBIMPL_WARNING_PUSH()
@@ -2947,8 +2860,8 @@ RBIMPL_WARNING_POP()
# define utimensat rb_utimensat()
# else /* __API_AVAILABLE macro does nothing on gcc */
__attribute__((weak)) int utimensat(int, const char *, const struct timespec [2], int);
-# endif /* utimesat availability */
-# endif /* __APPLE__ && < MAC_OS_X_VERSION_13_0 */
+# endif
+# endif
static int
utime_internal(const char *path, void *arg)
@@ -2961,15 +2874,15 @@ utime_internal(const char *path, void *arg)
# if defined(__APPLE__)
const int try_utimensat = utimensat != NULL;
const int try_utimensat_follow = utimensat != NULL;
-# else /* !__APPLE__ */
+# else
# define TRY_UTIMENSAT 1
static int try_utimensat = 1;
-# ifdef AT_SYMLINK_NOFOLLOW
+# ifdef AT_SYMLINK_NOFOLLOW
static int try_utimensat_follow = 1;
-# else
+# else
const int try_utimensat_follow = 0;
-# endif
-# endif /* __APPLE__ */
+# endif
+# endif
int flags = 0;
if (v->follow ? try_utimensat_follow : try_utimensat) {
@@ -2984,15 +2897,15 @@ utime_internal(const char *path, void *arg)
if (result < 0 && errno == ENOSYS) {
# ifdef AT_SYMLINK_NOFOLLOW
try_utimensat_follow = 0;
-# endif /* AT_SYMLINK_NOFOLLOW */
+# endif
if (!v->follow)
try_utimensat = 0;
}
else
-# endif /* TRY_UTIMESAT */
+# endif
return result;
}
-#endif /* defined(HAVE_UTIMENSAT) */
+#endif
if (tsp) {
tvbuf[0].tv_sec = tsp[0].tv_sec;
@@ -3007,7 +2920,7 @@ utime_internal(const char *path, void *arg)
return utimes(path, tvp);
}
-#else /* !defined(HAVE_UTIMES) */
+#else
#if !defined HAVE_UTIME_H && !defined HAVE_SYS_UTIME_H
struct utimbuf {
@@ -3029,7 +2942,8 @@ utime_internal(const char *path, void *arg)
}
return utime(path, utp);
}
-#endif /* !defined(HAVE_UTIMES) */
+
+#endif
static VALUE
utime_internal_i(int argc, VALUE *argv, int follow)
@@ -3228,7 +3142,8 @@ readlink_without_gvl(VALUE path, VALUE buf, size_t size)
ra.buf = RSTRING_PTR(buf);
ra.size = size;
- return (ssize_t)IO_WITHOUT_GVL(nogvl_readlink, &ra);
+ return (ssize_t)rb_thread_call_without_gvl(nogvl_readlink, &ra,
+ RUBY_UBF_IO, 0);
}
VALUE
@@ -3329,7 +3244,8 @@ rb_file_s_rename(VALUE klass, VALUE from, VALUE to)
#if defined __CYGWIN__
errno = 0;
#endif
- if (IO_WITHOUT_GVL_INT(no_gvl_rename, &ra) < 0) {
+ if ((int)(VALUE)rb_thread_call_without_gvl(no_gvl_rename, &ra,
+ RUBY_UBF_IO, 0) < 0) {
int e = errno;
#if defined DOSISH
switch (e) {
@@ -3398,13 +3314,12 @@ static const char file_alt_separator[] = {FILE_ALT_SEPARATOR, '\0'};
#endif
#ifndef USE_NTFS
-# if defined _WIN32
-# define USE_NTFS 1
-# else
-# define USE_NTFS 0
-# endif
+#if defined _WIN32
+#define USE_NTFS 1
+#else
+#define USE_NTFS 0
+#endif
#endif
-
#ifndef USE_NTFS_ADS
# if USE_NTFS
# define USE_NTFS_ADS 1
@@ -3418,7 +3333,6 @@ static const char file_alt_separator[] = {FILE_ALT_SEPARATOR, '\0'};
#else
#define istrailinggarbage(x) 0
#endif
-
#if USE_NTFS_ADS
# define isADS(x) ((x) == ':')
#else
@@ -3486,8 +3400,8 @@ not_same_drive(VALUE path, int drive)
return has_unc(p);
}
}
-#endif /* _WIN32 */
-#endif /* DOSISH_DRIVE_LETTER */
+#endif
+#endif
static inline char *
skiproot(const char *path, const char *end, rb_encoding *enc)
@@ -3531,7 +3445,7 @@ rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc)
if (has_drive_letter(path))
return (char *)(path + 2);
#endif
-#endif /* defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER) */
+#endif
return (char *)path;
}
@@ -3626,7 +3540,7 @@ ntfs_tail(const char *path, const char *end, rb_encoding *enc)
}
return (char *)path;
}
-#endif /* USE_NTFS */
+#endif
#define BUFCHECK(cond) do {\
bdiff = p - buf;\
@@ -3696,16 +3610,12 @@ VALUE
rb_home_dir_of(VALUE user, VALUE result)
{
#ifdef HAVE_PWD_H
- VALUE dirname = rb_getpwdirnam_for_login(user);
- if (dirname == Qnil) {
- rb_raise(rb_eArgError, "user %"PRIsVALUE" doesn't exist", user);
- }
- const char *dir = RSTRING_PTR(dirname);
+ struct passwd *pwPtr;
#else
extern char *getlogin(void);
const char *pwPtr = 0;
- const char *login;
# define endpwent() ((void)0)
+#endif
const char *dir, *username = RSTRING_PTR(user);
rb_encoding *enc = rb_enc_get(user);
#if defined _WIN32
@@ -3717,17 +3627,25 @@ rb_home_dir_of(VALUE user, VALUE result)
dir = username = RSTRING_PTR(rb_str_conv_enc(user, enc, fsenc));
}
- if ((login = getlogin()) && strcasecmp(username, login) == 0)
+#ifdef HAVE_PWD_H
+ pwPtr = getpwnam(username);
+#else
+ if (strcasecmp(username, getlogin()) == 0)
dir = pwPtr = getenv("HOME");
+#endif
if (!pwPtr) {
+ endpwent();
rb_raise(rb_eArgError, "user %"PRIsVALUE" doesn't exist", user);
}
+#ifdef HAVE_PWD_H
+ dir = pwPtr->pw_dir;
#endif
copy_home_path(result, dir);
+ endpwent();
return result;
}
-#ifndef _WIN32 /* this encompasses rb_file_expand_path_internal */
+#ifndef _WIN32
VALUE
rb_default_home_dir(VALUE result)
{
@@ -3755,15 +3673,15 @@ rb_default_home_dir(VALUE result)
* lookup by getuid() has a chance of succeeding.
*/
if (NIL_P(login_name)) {
- rb_raise(rb_eArgError, "couldn't find login name -- expanding '~'");
+ rb_raise(rb_eArgError, "couldn't find login name -- expanding `~'");
}
-# endif /* !defined(HAVE_GETPWUID_R) && !defined(HAVE_GETPWUID) */
+# endif
VALUE pw_dir = rb_getpwdirnam_for_login(login_name);
if (NIL_P(pw_dir)) {
pw_dir = rb_getpwdiruid();
if (NIL_P(pw_dir)) {
- rb_raise(rb_eArgError, "couldn't find home for uid '%ld'", (long)getuid());
+ rb_raise(rb_eArgError, "couldn't find home for uid `%ld'", (long)getuid());
}
}
@@ -3772,9 +3690,9 @@ rb_default_home_dir(VALUE result)
rb_str_resize(pw_dir, 0);
return result;
}
-#endif /* defined HAVE_PWD_H */
+#endif
if (!dir) {
- rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding '~'");
+ rb_raise(rb_eArgError, "couldn't find HOME environment -- expanding `~'");
}
return copy_home_path(result, dir);
}
@@ -3799,15 +3717,7 @@ append_fspath(VALUE result, VALUE fname, char *dir, rb_encoding **enc, rb_encodi
size_t dirlen = strlen(dir), buflen = rb_str_capacity(result);
if (NORMALIZE_UTF8PATH || *enc != fsenc) {
- dirname = ospath_new(dir, dirlen, fsenc);
- if (!rb_enc_compatible(fname, dirname)) {
- xfree(dir);
- /* rb_enc_check must raise because the two encodings are not
- * compatible. */
- rb_enc_check(fname, dirname);
- rb_bug("unreachable");
- }
- rb_encoding *direnc = fs_enc_check(fname, dirname);
+ rb_encoding *direnc = fs_enc_check(fname, dirname = ospath_new(dir, dirlen, fsenc));
if (direnc != fsenc) {
dirname = rb_str_conv_enc(dirname, fsenc, direnc);
RSTRING_GETMEM(dirname, cwdp, dirlen);
@@ -3910,7 +3820,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
s += 2;
}
}
-#endif /* DOSISH_DRIVE_LETTER */
+#endif
else if (!rb_is_absolute_path(s)) {
if (!NIL_P(dname)) {
rb_file_expand_path_internal(dname, Qnil, abs_mode, long_name, result);
@@ -3930,7 +3840,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
p = skipprefix(buf, p, enc);
}
else
-#endif /* defined DOSISH || defined __CYGWIN__ */
+#endif
p = chompdirsep(skiproot(buf, p, enc), p, enc);
}
else {
@@ -3983,7 +3893,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
else {
do ++s; while (istrailinggarbage(*s));
}
-#endif /* USE_NTFS */
+#endif
break;
case '/':
#if defined DOSISH || defined __CYGWIN__
@@ -4008,7 +3918,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
}
}
-#endif /* USE_NTFS */
+#endif
break;
case '/':
#if defined DOSISH || defined __CYGWIN__
@@ -4033,7 +3943,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
break;
}
}
-#endif /* __APPLE__ */
+#endif
Inc(s, fend, enc);
break;
}
@@ -4057,8 +3967,8 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
s -= prime_len; /* alternative */
}
}
-# endif /* USE_NTFS_ADS */
-#endif /* USE_NTFS */
+# endif
+#endif
BUFCOPY(b, s-b);
rb_str_set_len(result, p-buf);
}
@@ -4079,7 +3989,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
const int flags = CCP_POSIX_TO_WIN_A | CCP_RELATIVE;
#else
char w32buf[MAXPATHLEN];
-#endif /* HAVE_CYGWIN_CONV_PATH */
+#endif
const char *path;
ssize_t bufsize;
int lnk_added = 0, is_symlink = 0;
@@ -4103,12 +4013,12 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
b = w32buf;
}
}
-#else /* !HAVE_CYGWIN_CONV_PATH */
+#else
bufsize = MAXPATHLEN;
if (cygwin_conv_to_win32_path(path, w32buf) == 0) {
b = w32buf;
}
-#endif /* !HAVE_CYGWIN_CONV_PATH */
+#endif
if (is_symlink && b == w32buf) {
*p = '\\';
strlcat(w32buf, p, bufsize);
@@ -4120,7 +4030,7 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
lnk_added = 0;
}
*p = '/';
-#endif /* __CYGWIN__ */
+#endif
rb_str_set_len(result, p - buf + strlen(p));
encidx = ENCODING_GET(result);
tmp = result;
@@ -4168,14 +4078,14 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na
}
#endif
}
-#endif /* USE_NTFS */
+#endif
rb_str_set_len(result, p - buf);
rb_enc_check(fname, result);
ENC_CODERANGE_CLEAR(result);
return result;
}
-#endif /* !_WIN32 (this ifdef started above rb_default_home_dir) */
+#endif /* _WIN32 */
#define EXPAND_PATH_BUFFER() rb_usascii_str_new(0, 1)
@@ -4415,7 +4325,7 @@ realpath_rec(long *prefixlenp, VALUE *resolvedp, const char *unresolved, VALUE f
rb_hash_aset(loopcheck, testpath, rb_str_dup_frozen(*resolvedp));
}
else
-#endif /* HAVE_READLINK */
+#endif
{
VALUE s = rb_str_dup_frozen(testpath);
rb_hash_aset(loopcheck, s, s);
@@ -4535,11 +4445,6 @@ rb_check_realpath_emulate_rescue(VALUE arg, VALUE exc)
{
return Qnil;
}
-#elif !defined(NEEDS_REALPATH_BUFFER) && defined(__APPLE__) && \
- (!defined(MAC_OS_X_VERSION_10_6) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6))
-/* realpath() on OSX < 10.6 doesn't implement automatic allocation */
-# include <sys/syslimits.h>
-# define NEEDS_REALPATH_BUFFER 1
#endif /* HAVE_REALPATH */
static VALUE
@@ -4549,11 +4454,6 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, rb_encoding *origenc, enum
VALUE unresolved_path;
char *resolved_ptr = NULL;
VALUE resolved;
-# if defined(NEEDS_REALPATH_BUFFER) && NEEDS_REALPATH_BUFFER
- char resolved_buffer[PATH_MAX];
-# else
- char *const resolved_buffer = NULL;
-# endif
if (mode == RB_REALPATH_DIR) {
return rb_check_realpath_emulate(basedir, path, origenc, mode);
@@ -4565,7 +4465,7 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, rb_encoding *origenc, enum
}
if (origenc) unresolved_path = TO_OSPATH(unresolved_path);
- if ((resolved_ptr = realpath(RSTRING_PTR(unresolved_path), resolved_buffer)) == NULL) {
+ if ((resolved_ptr = realpath(RSTRING_PTR(unresolved_path), NULL)) == NULL) {
/* glibc realpath(3) does not allow /path/to/file.rb/../other_file.rb,
returning ENOTDIR in that case.
glibc realpath(3) can also return ENOENT for paths that exist,
@@ -4582,9 +4482,7 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, rb_encoding *origenc, enum
rb_sys_fail_path(unresolved_path);
}
resolved = ospath_new(resolved_ptr, strlen(resolved_ptr), rb_filesystem_encoding());
-# if !(defined(NEEDS_REALPATH_BUFFER) && NEEDS_REALPATH_BUFFER)
free(resolved_ptr);
-# endif
# if !defined(__LINUX__) && !defined(__APPLE__)
/* As `resolved` is a String in the filesystem encoding, no
@@ -4596,7 +4494,7 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, rb_encoding *origenc, enum
}
rb_sys_fail_path(unresolved_path);
}
-# endif /* !defined(__LINUX__) && !defined(__APPLE__) */
+# endif
if (origenc && origenc != rb_enc_get(resolved)) {
if (!rb_enc_str_asciionly_p(resolved)) {
@@ -4614,7 +4512,7 @@ rb_check_realpath_internal(VALUE basedir, VALUE path, rb_encoding *origenc, enum
RB_GC_GUARD(unresolved_path);
return resolved;
-#else /* !HAVE_REALPATH */
+#else
if (mode == RB_REALPATH_CHECK) {
VALUE arg[3];
arg[0] = basedir;
@@ -4711,7 +4609,7 @@ rmext(const char *p, long l0, long l1, const char *e, long l2, rb_encoding *enc)
if (l1 < l2) return l1;
s = p+l1-l2;
- if (!at_char_boundary(p, s, p+l1, enc)) return 0;
+ if (rb_enc_left_char_head(p, s, p+l1, enc) != s) return 0;
#if CASEFOLD_FILESYSTEM
#define fncomp strncasecmp
#else
@@ -4751,13 +4649,13 @@ ruby_enc_find_basename(const char *name, long *baselen, long *alllen, rb_encodin
p++;
f = 0;
}
-#endif /* DOSISH_DRIVE_LETTER */
+#endif
#ifdef DOSISH_UNC
else {
p = "/";
}
-#endif /* DOSISH_UNC */
-#endif /* defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC */
+#endif
+#endif
}
else {
if (!(p = strrdirsep(name, end, enc))) {
@@ -4999,7 +4897,7 @@ ruby_enc_find_extname(const char *name, long *len, rb_encoding *enc)
continue;
#else
e = p; /* get the last dot of the last component */
-#endif /* USE_NTFS */
+#endif
}
#if USE_NTFS
else if (isADS(*p)) {
@@ -5072,7 +4970,7 @@ rb_file_s_extname(VALUE klass, VALUE fname)
*
* Returns the string representation of the path
*
- * File.path(File::NULL) #=> "/dev/null"
+ * File.path("/dev/null") #=> "/dev/null"
* File.path(Pathname.new("/tmp")) #=> "/tmp"
*
*/
@@ -5230,7 +5128,8 @@ rb_file_s_truncate(VALUE klass, VALUE path, VALUE len)
path = rb_str_encode_ospath(path);
ta.path = StringValueCStr(path);
- r = IO_WITHOUT_GVL_INT(nogvl_truncate, &ta);
+ r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_truncate, &ta,
+ RUBY_UBF_IO, NULL);
if (r < 0)
rb_sys_fail_path(path);
return INT2FIX(0);
@@ -5280,7 +5179,7 @@ rb_file_truncate(VALUE obj, VALUE len)
}
rb_io_flush_raw(obj, 0);
fa.fd = fptr->fd;
- if ((int)rb_io_blocking_region(fptr, nogvl_ftruncate, &fa) < 0) {
+ if ((int)rb_thread_io_blocking_region(nogvl_ftruncate, &fa, fa.fd) < 0) {
rb_sys_fail_path(fptr->pathv);
}
return INT2FIX(0);
@@ -5323,46 +5222,47 @@ rb_thread_flock(void *data)
return (VALUE)ret;
}
-/* :markup: markdown
- *
+/*
* call-seq:
- * flock(locking_constant) -> 0 or false
- *
- * Locks or unlocks file +self+ according to the given `locking_constant`,
- * a bitwise OR of the values in the table below.
- *
- * Not available on all platforms.
- *
- * Returns `false` if `File::LOCK_NB` is specified and the operation would have blocked;
- * otherwise returns `0`.
- *
- * | Constant | Lock | Effect
- * |-----------------|--------------|-----------------------------------------------------------------------------------------------------------------|
- * | +File::LOCK_EX+ | Exclusive | Only one process may hold an exclusive lock for +self+ at a time. |
- * | +File::LOCK_NB+ | Non-blocking | No blocking; may be combined with +File::LOCK_SH+ or +File::LOCK_EX+ using the bitwise OR operator <tt>\|</tt>. |
- * | +File::LOCK_SH+ | Shared | Multiple processes may each hold a shared lock for +self+ at the same time. |
- * | +File::LOCK_UN+ | Unlock | Remove an existing lock held by this process. |
+ * file.flock(locking_constant) -> 0 or false
+ *
+ * Locks or unlocks a file according to <i>locking_constant</i> (a
+ * logical <em>or</em> of the values in the table below).
+ * Returns <code>false</code> if File::LOCK_NB is specified and the
+ * operation would otherwise have blocked. Not available on all
+ * platforms.
+ *
+ * Locking constants (in class File):
+ *
+ * LOCK_EX | Exclusive lock. Only one process may hold an
+ * | exclusive lock for a given file at a time.
+ * ----------+------------------------------------------------
+ * LOCK_NB | Don't block when locking. May be combined
+ * | with other lock options using logical or.
+ * ----------+------------------------------------------------
+ * LOCK_SH | Shared lock. Multiple processes may each hold a
+ * | shared lock for a given file at the same time.
+ * ----------+------------------------------------------------
+ * LOCK_UN | Unlock.
*
* Example:
*
- * ```ruby
- * # Update a counter using an exclusive lock.
- * # Don't use File::WRONLY because it truncates the file.
- * File.open('counter', File::RDWR | File::CREAT, 0644) do |f|
- * f.flock(File::LOCK_EX)
- * value = f.read.to_i + 1
- * f.rewind
- * f.write("#{value}\n")
- * f.flush
- * f.truncate(f.pos)
- * end
- *
- * # Read the counter using a shared lock.
- * File.open('counter', 'r') do |f|
- * f.flock(File::LOCK_SH)
- * f.read
- * end
- * ```
+ * # update a counter using write lock
+ * # don't use "w" because it truncates the file before lock.
+ * File.open("counter", File::RDWR|File::CREAT, 0644) {|f|
+ * f.flock(File::LOCK_EX)
+ * value = f.read.to_i + 1
+ * f.rewind
+ * f.write("#{value}\n")
+ * f.flush
+ * f.truncate(f.pos)
+ * }
+ *
+ * # read the counter using read lock
+ * File.open("counter", "r") {|f|
+ * f.flock(File::LOCK_SH)
+ * p f.read
+ * }
*
*/
@@ -5380,7 +5280,7 @@ rb_file_flock(VALUE obj, VALUE operation)
if (fptr->mode & FMODE_WRITABLE) {
rb_io_flush_raw(obj, 0);
}
- while ((int)rb_io_blocking_region(fptr, rb_thread_flock, op) < 0) {
+ while ((int)rb_thread_io_blocking_region(rb_thread_flock, op, fptr->fd) < 0) {
int e = errno;
switch (e) {
case EAGAIN:
@@ -5426,83 +5326,60 @@ test_check(int n, int argc, VALUE *argv)
#define CHECK(n) test_check((n), argc, argv)
/*
- * :markup: markdown
- *
* call-seq:
- * test(char, path0, path1 = nil) -> object
- *
- * Performs a test on one or both of the <i>filesystem entities</i> at the given paths
- * `path0` and `path1`:
- *
- * - Each path `path0` or `path1` points to a file, directory, device, pipe, etc.
- * - Character `char` selects a specific test.
- *
- * The tests:
- *
- * - Each of these tests operates only on the entity at `path0`,
- * and returns `true` or `false`;
- * for a non-existent entity, returns `false` (does not raise exception):
- *
- * | Character | Test |
- * |:------------:|:--------------------------------------------------------------------------|
- * | <tt>'b'</tt> | Whether the entity is a block device. |
- * | <tt>'c'</tt> | Whether the entity is a character device. |
- * | <tt>'d'</tt> | Whether the entity is a directory. |
- * | <tt>'e'</tt> | Whether the entity is an existing entity. |
- * | <tt>'f'</tt> | Whether the entity is an existing regular file. |
- * | <tt>'g'</tt> | Whether the entity's setgid bit is set. |
- * | <tt>'G'</tt> | Whether the entity's group ownership is equal to the caller's. |
- * | <tt>'k'</tt> | Whether the entity's sticky bit is set. |
- * | <tt>'l'</tt> | Whether the entity is a symbolic link. |
- * | <tt>'o'</tt> | Whether the entity is owned by the caller's effective uid. |
- * | <tt>'O'</tt> | Like <tt>'o'</tt>, but uses the real uid (not the effective uid). |
- * | <tt>'p'</tt> | Whether the entity is a FIFO device (named pipe). |
- * | <tt>'r'</tt> | Whether the entity is readable by the caller's effecive uid/gid. |
- * | <tt>'R'</tt> | Like <tt>'r'</tt>, but uses the real uid/gid (not the effective uid/gid). |
- * | <tt>'S'</tt> | Whether the entity is a socket. |
- * | <tt>'u'</tt> | Whether the entity's setuid bit is set. |
- * | <tt>'w'</tt> | Whether the entity is writable by the caller's effective uid/gid. |
- * | <tt>'W'</tt> | Like <tt>'w'</tt>, but uses the real uid/gid (not the effective uid/gid). |
- * | <tt>'x'</tt> | Whether the entity is executable by the caller's effective uid/gid. |
- * | <tt>'X'</tt> | Like <tt>'x'</tt>, but uses the real uid/gid (not the effecive uid/git). |
- * | <tt>'z'</tt> | Whether the entity exists and is of length zero. |
- *
- * - This test operates only on the entity at `path0`,
- * and returns an integer size or +nil+:
- *
- * | Character | Test |
- * |:------------:|:---------------------------------------------------------------------------------------------|
- * | <tt>'s'</tt> | Returns positive integer size if the entity exists and has non-zero length, +nil+ otherwise. |
- *
- * - Each of these tests operates only on the entity at `path0`,
- * and returns a Time object;
- * raises an exception if the entity does not exist:
- *
- * | Character | Test |
- * |:------------:|:---------------------------------------|
- * | <tt>'A'</tt> | Last access time for the entity. |
- * | <tt>'C'</tt> | Last change time for the entity. |
- * | <tt>'M'</tt> | Last modification time for the entity. |
- *
- * - Each of these tests operates on the modification time (`mtime`)
- * of each of the entities at `path0` and `path1`,
- * and returns a `true` or `false`;
- * returns `false` if either entity does not exist:
- *
- * | Character | Test |
- * |:------------:|:----------------------------------------------------------------|
- * | <tt>'<'</tt> | Whether the `mtime` at `path0` is less than that at `path1`. |
- * | <tt>'='</tt> | Whether the `mtime` at `path0` is equal to that at `path1`. |
- * | <tt>'>'</tt> | Whether the `mtime` at `path0` is greater than that at `path1`. |
- *
- * - This test operates on the content of each of the entities at `path0` and `path1`,
- * and returns a `true` or `false`;
- * returns `false` if either entity does not exist:
- *
- * | Character | Test |
- * |:------------:|:----------------------------------------------|
- * | <tt>'-'</tt> | Whether the entities exist and are identical. |
- *
+ * test(cmd, file1 [, file2] ) -> obj
+ *
+ * Uses the character +cmd+ to perform various tests on +file1+ (first
+ * table below) or on +file1+ and +file2+ (second table).
+ *
+ * File tests on a single file:
+ *
+ * Cmd Returns Meaning
+ * "A" | Time | Last access time for file1
+ * "b" | boolean | True if file1 is a block device
+ * "c" | boolean | True if file1 is a character device
+ * "C" | Time | Last change time for file1
+ * "d" | boolean | True if file1 exists and is a directory
+ * "e" | boolean | True if file1 exists
+ * "f" | boolean | True if file1 exists and is a regular file
+ * "g" | boolean | True if file1 has the setgid bit set
+ * "G" | boolean | True if file1 exists and has a group
+ * | | ownership equal to the caller's group
+ * "k" | boolean | True if file1 exists and has the sticky bit set
+ * "l" | boolean | True if file1 exists and is a symbolic link
+ * "M" | Time | Last modification time for file1
+ * "o" | boolean | True if file1 exists and is owned by
+ * | | the caller's effective uid
+ * "O" | boolean | True if file1 exists and is owned by
+ * | | the caller's real uid
+ * "p" | boolean | True if file1 exists and is a fifo
+ * "r" | boolean | True if file1 is readable by the effective
+ * | | uid/gid of the caller
+ * "R" | boolean | True if file is readable by the real
+ * | | uid/gid of the caller
+ * "s" | int/nil | If file1 has nonzero size, return the size,
+ * | | otherwise return nil
+ * "S" | boolean | True if file1 exists and is a socket
+ * "u" | boolean | True if file1 has the setuid bit set
+ * "w" | boolean | True if file1 exists and is writable by
+ * | | the effective uid/gid
+ * "W" | boolean | True if file1 exists and is writable by
+ * | | the real uid/gid
+ * "x" | boolean | True if file1 exists and is executable by
+ * | | the effective uid/gid
+ * "X" | boolean | True if file1 exists and is executable by
+ * | | the real uid/gid
+ * "z" | boolean | True if file1 exists and has a zero length
+ *
+ * Tests that take two files:
+ *
+ * "-" | boolean | True if file1 and file2 are identical
+ * "=" | boolean | True if the modification times of file1
+ * | | and file2 are equal
+ * "<" | boolean | True if the modification time of file1
+ * | | is prior to that of file2
+ * ">" | boolean | True if the modification time of file1
+ * | | is after that of file2
*/
static VALUE
@@ -5681,7 +5558,7 @@ rb_stat_s_alloc(VALUE klass)
static VALUE
rb_stat_init(VALUE obj, VALUE fname)
{
- struct stat st;
+ struct stat st, *nst;
FilePathValue(fname);
fname = rb_str_encode_ospath(fname);
@@ -5689,11 +5566,13 @@ rb_stat_init(VALUE obj, VALUE fname)
rb_sys_fail_path(fname);
}
- struct rb_stat *rb_st;
- TypedData_Get_Struct(obj, struct rb_stat, &stat_data_type, rb_st);
-
- rb_st->stat = st;
- rb_st->initialized = true;
+ if (DATA_PTR(obj)) {
+ xfree(DATA_PTR(obj));
+ DATA_PTR(obj) = NULL;
+ }
+ nst = ALLOC(struct stat);
+ *nst = st;
+ DATA_PTR(obj) = nst;
return Qnil;
}
@@ -5702,15 +5581,19 @@ rb_stat_init(VALUE obj, VALUE fname)
static VALUE
rb_stat_init_copy(VALUE copy, VALUE orig)
{
- if (!OBJ_INIT_COPY(copy, orig)) return copy;
-
- struct rb_stat *orig_rb_st;
- TypedData_Get_Struct(orig, struct rb_stat, &stat_data_type, orig_rb_st);
+ struct stat *nst;
- struct rb_stat *copy_rb_st;
- TypedData_Get_Struct(copy, struct rb_stat, &stat_data_type, copy_rb_st);
+ if (!OBJ_INIT_COPY(copy, orig)) return copy;
+ if (DATA_PTR(copy)) {
+ xfree(DATA_PTR(copy));
+ DATA_PTR(copy) = 0;
+ }
+ if (DATA_PTR(orig)) {
+ nst = ALLOC(struct stat);
+ *nst = *(struct stat*)DATA_PTR(orig);
+ DATA_PTR(copy) = nst;
+ }
- *copy_rb_st = *orig_rb_st;
return copy;
}
@@ -5994,8 +5877,10 @@ rb_stat_wr(VALUE obj)
if ((st->st_mode & (S_IROTH)) == S_IROTH) {
return UINT2NUM(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
}
+ else {
+ return Qnil;
+ }
#endif
- return Qnil;
}
/*
@@ -6080,13 +5965,15 @@ rb_stat_W(VALUE obj)
static VALUE
rb_stat_ww(VALUE obj)
{
-#ifdef S_IWOTH
+#ifdef S_IROTH
struct stat *st = get_stat(obj);
if ((st->st_mode & (S_IWOTH)) == S_IWOTH) {
return UINT2NUM(st->st_mode & (S_IRUGO|S_IWUGO|S_IXUGO));
}
+ else {
+ return Qnil;
+ }
#endif
- return Qnil;
}
/*
@@ -6202,7 +6089,7 @@ rb_stat_z(VALUE obj)
* the file otherwise.
*
* File.stat("testfile").size? #=> 66
- * File.stat(File::NULL).size? #=> nil
+ * File.stat("/dev/null").size? #=> nil
*
*/
@@ -6321,7 +6208,7 @@ rb_file_s_mkfifo(int argc, VALUE *argv, VALUE _)
FilePathValue(path);
path = rb_str_encode_ospath(path);
ma.path = RSTRING_PTR(path);
- if (IO_WITHOUT_GVL(nogvl_mkfifo, &ma)) {
+ if (rb_thread_call_without_gvl(nogvl_mkfifo, &ma, RUBY_UBF_IO, 0)) {
rb_sys_fail_path(path);
}
return INT2FIX(0);
@@ -6485,11 +6372,7 @@ rb_file_load_ok(const char *path)
#endif
0);
int fd = rb_cloexec_open(path, mode, 0);
- if (fd < 0) {
- if (!rb_gc_for_fd(errno)) return 0;
- fd = rb_cloexec_open(path, mode, 0);
- if (fd < 0) return 0;
- }
+ if (fd == -1) return 0;
rb_update_max_fd(fd);
ret = ruby_is_fd_loadable(fd);
(void)close(fd);
@@ -6647,7 +6530,7 @@ const char ruby_null_device[] =
* \Class \File extends module FileTest, supporting such singleton methods
* as <tt>File.exist?</tt>.
*
- * == About the Examples
+ * === About the Examples
*
* Many examples here use these variables:
*
@@ -6655,11 +6538,11 @@ const char ruby_null_device[] =
*
* == Access Modes
*
- * Methods File.new and File.open each create a \File object for a given file path.
+ * \Methods File.new and File.open each create a \File object for a given file path.
*
* === \String Access Modes
*
- * Methods File.new and File.open each may take string argument +mode+, which:
+ * \Methods File.new and File.open each may take string argument +mode+, which:
*
* - Begins with a 1- or 2-character
* {read/write mode}[rdoc-ref:File@Read-2FWrite+Mode].
@@ -6728,7 +6611,7 @@ const char ruby_null_device[] =
*
* - <tt>'r'</tt>:
*
- * - \File is not initially truncated:
+ * - File is not initially truncated:
*
* f = File.new('t.txt') # => #<File:t.txt>
* f.size == 0 # => false
@@ -6737,7 +6620,7 @@ const char ruby_null_device[] =
*
* f.pos # => 0
*
- * - \File may be read anywhere; see IO#rewind, IO#pos=, IO#seek:
+ * - File may be read anywhere; see IO#rewind, IO#pos=, IO#seek:
*
* f.readline # => "First line\n"
* f.readline # => "Second line\n"
@@ -6757,7 +6640,7 @@ const char ruby_null_device[] =
*
* - <tt>'w'</tt>:
*
- * - \File is initially truncated:
+ * - File is initially truncated:
*
* path = 't.tmp'
* File.write(path, text)
@@ -6768,7 +6651,7 @@ const char ruby_null_device[] =
*
* f.pos # => 0
*
- * - \File may be written anywhere (even past end-of-file);
+ * - File may be written anywhere (even past end-of-file);
* see IO#rewind, IO#pos=, IO#seek:
*
* f.write('foo')
@@ -6811,7 +6694,7 @@ const char ruby_null_device[] =
*
* - <tt>'a'</tt>:
*
- * - \File is not initially truncated:
+ * - File is not initially truncated:
*
* path = 't.tmp'
* File.write(path, 'foo')
@@ -6822,7 +6705,7 @@ const char ruby_null_device[] =
*
* f.pos # => 0
*
- * - \File may be written only at end-of-file;
+ * - File may be written only at end-of-file;
* IO#rewind, IO#pos=, IO#seek do not affect writing:
*
* f.write('bar')
@@ -6843,7 +6726,7 @@ const char ruby_null_device[] =
*
* - <tt>'r+'</tt>:
*
- * - \File is not initially truncated:
+ * - File is not initially truncated:
*
* path = 't.tmp'
* File.write(path, text)
@@ -6854,7 +6737,7 @@ const char ruby_null_device[] =
*
* f.pos # => 0
*
- * - \File may be read or written anywhere (even past end-of-file);
+ * - File may be read or written anywhere (even past end-of-file);
* see IO#rewind, IO#pos=, IO#seek:
*
* f.readline # => "First line\n"
@@ -6899,7 +6782,7 @@ const char ruby_null_device[] =
*
* - <tt>'a+'</tt>:
*
- * - \File is not initially truncated:
+ * - File is not initially truncated:
*
* path = 't.tmp'
* File.write(path, 'foo')
@@ -6910,7 +6793,7 @@ const char ruby_null_device[] =
*
* f.pos # => 0
*
- * - \File may be written only at end-of-file;
+ * - File may be written only at end-of-file;
* IO#rewind, IO#pos=, IO#seek do not affect writing:
*
* f.write('bar')
@@ -6925,7 +6808,7 @@ const char ruby_null_device[] =
* f.flush
* File.read(path) # => "foobarbazbat"
*
- * - \File may be read anywhere; see IO#rewind, IO#pos=, IO#seek:
+ * - File may be read anywhere; see IO#rewind, IO#pos=, IO#seek:
*
* f.rewind
* f.read # => "foobarbazbat"
@@ -6950,7 +6833,7 @@ const char ruby_null_device[] =
* f = File.new(path, 'w')
* f.pos # => 0
*
- * - \File may be written anywhere (even past end-of-file);
+ * - File may be written anywhere (even past end-of-file);
* see IO#rewind, IO#pos=, IO#seek:
*
* f.write('foo')
@@ -7027,7 +6910,7 @@ const char ruby_null_device[] =
* f = File.new(path, 'w+')
* f.pos # => 0
*
- * - \File may be written anywhere (even past end-of-file);
+ * - File may be written anywhere (even past end-of-file);
* see IO#rewind, IO#pos=, IO#seek:
*
* f.write('foo')
@@ -7064,7 +6947,7 @@ const char ruby_null_device[] =
* File.read(path) # => "bazbam\u0000\u0000bah"
* f.pos # => 11
*
- * - \File may be read anywhere (even past end-of-file);
+ * - File may be read anywhere (even past end-of-file);
* see IO#rewind, IO#pos=, IO#seek:
*
* f.rewind
@@ -7105,7 +6988,7 @@ const char ruby_null_device[] =
* f.flush
* File.read(path) # => "foobarbaz"
*
- * - \File may be read anywhere (even past end-of-file);
+ * - File may be read anywhere (even past end-of-file);
* see IO#rewind, IO#pos=, IO#seek:
*
* f.rewind
@@ -7250,6 +7133,7 @@ const char ruby_null_device[] =
*
* Note that file permissions are quite different from the _mode_
* of a file stream (\File object).
+ * See IO@Modes.
*
* In a \File object, the permissions are available thus,
* where method +mode+, despite its name, returns permissions:
@@ -7295,7 +7179,7 @@ const char ruby_null_device[] =
*
* == \File \Constants
*
- * Various constants for use in \File and IO methods
+ * Various constants for use in \File and \IO methods
* may be found in module File::Constants;
* an array of their names is returned by <tt>File::Constants.constants</tt>.
*
@@ -7305,7 +7189,7 @@ const char ruby_null_device[] =
*
* - Inherits from {class IO}[rdoc-ref:IO@What-27s+Here],
* in particular, methods for creating, reading, and writing files
- * - Includes module FileTest,
+ * - Includes {module FileTest}[rdoc-ref:FileTest@What-27s+Here].
* which provides dozens of additional methods.
*
* Here, class \File provides methods that are useful for:
@@ -7350,15 +7234,15 @@ const char ruby_null_device[] =
*
* _Times_
*
- * - ::atime: Returns a Time for the most recent access to the given file.
- * - ::birthtime: Returns a Time for the creation of the given file.
- * - ::ctime: Returns a Time for the metadata change of the given file.
- * - ::mtime: Returns a Time for the most recent data modification to
+ * - ::atime: Returns a \Time for the most recent access to the given file.
+ * - ::birthtime: Returns a \Time for the creation of the given file.
+ * - ::ctime: Returns a \Time for the metadata change of the given file.
+ * - ::mtime: Returns a \Time for the most recent data modification to
* the content of the given file.
- * - #atime: Returns a Time for the most recent access to +self+.
- * - #birthtime: Returns a Time the creation for +self+.
- * - #ctime: Returns a Time for the metadata change of +self+.
- * - #mtime: Returns a Time for the most recent data modification
+ * - #atime: Returns a \Time for the most recent access to +self+.
+ * - #birthtime: Returns a \Time the creation for +self+.
+ * - #ctime: Returns a \Time for the metadata change of +self+.
+ * - #mtime: Returns a \Time for the most recent data modification
* to the content of +self+.
*
* _Types_
@@ -7547,400 +7431,93 @@ Init_File(void)
/*
* Document-module: File::Constants
*
- * \Module +File::Constants+ defines file-related constants.
- *
- * There are two families of constants here:
- *
- * - Those having to do with {file access}[rdoc-ref:File::Constants@File+Access].
- * - Those having to do with {filename globbing}[rdoc-ref:File::Constants@Filename+Globbing+Constants+-28File-3A-3AFNM_-2A-29].
- *
- * \File constants defined for the local process may be retrieved
- * with method File::Constants.constants:
- *
- * File::Constants.constants.take(5)
- * # => [:RDONLY, :WRONLY, :RDWR, :APPEND, :CREAT]
- *
- * == \File Access
- *
- * \File-access constants may be used with optional argument +mode+ in calls
- * to the following methods:
- *
- * - File.new.
- * - File.open.
- * - IO.for_fd.
- * - IO.new.
- * - IO.open.
- * - IO.popen.
- * - IO.reopen.
- * - IO.sysopen.
- * - StringIO.new.
- * - StringIO.open.
- * - StringIO#reopen.
- *
- * === Read/Write Access
- *
- * Read-write access for a stream
- * may be specified by a file-access constant.
- *
- * The constant may be specified as part of a bitwise OR of other such constants.
- *
- * Any combination of the constants in this section may be specified.
- *
- * ==== File::RDONLY
- *
- * Flag File::RDONLY specifies the stream should be opened for reading only:
- *
- * filepath = '/tmp/t.tmp'
- * f = File.new(filepath, File::RDONLY)
- * f.write('Foo') # Raises IOError (not opened for writing).
- *
- * ==== File::WRONLY
- *
- * Flag File::WRONLY specifies that the stream should be opened for writing only:
- *
- * f = File.new(filepath, File::WRONLY)
- * f.read # Raises IOError (not opened for reading).
- *
- * ==== File::RDWR
- *
- * Flag File::RDWR specifies that the stream should be opened
- * for both reading and writing:
- *
- * f = File.new(filepath, File::RDWR)
- * f.write('Foo') # => 3
- * f.rewind # => 0
- * f.read # => "Foo"
- *
- * === \File Positioning
- *
- * ==== File::APPEND
- *
- * Flag File::APPEND specifies that the stream should be opened
- * in append mode.
- *
- * Before each write operation, the position is set to end-of-stream.
- * The modification of the position and the following write operation
- * are performed as a single atomic step.
- *
- * ==== File::TRUNC
- *
- * Flag File::TRUNC specifies that the stream should be truncated
- * at its beginning.
- * If the file exists and is successfully opened for writing,
- * it is to be truncated to position zero;
- * its ctime and mtime are updated.
- *
- * There is no effect on a FIFO special file or a terminal device.
- * The effect on other file types is implementation-defined.
- * The result of using File::TRUNC with File::RDONLY is undefined.
- *
- * === Creating and Preserving
- *
- * ==== File::CREAT
- *
- * Flag File::CREAT specifies that the stream should be created
- * if it does not already exist.
- *
- * If the file exists:
- *
- * - Raise an exception if File::EXCL is also specified.
- * - Otherwise, do nothing.
+ * File::Constants provides file-related constants. All possible
+ * file constants are listed in the documentation but they may not all
+ * be present on your platform.
*
- * If the file does not exist, then it is created.
- * Upon successful completion, the atime, ctime, and mtime of the file are updated,
- * and the ctime and mtime of the parent directory are updated.
- *
- * ==== File::EXCL
- *
- * Flag File::EXCL specifies that the stream should not already exist;
- * If flags File::CREAT and File::EXCL are both specified
- * and the stream already exists, an exception is raised.
- *
- * The check for the existence and creation of the file is performed as an
- * atomic operation.
- *
- * If both File::EXCL and File::CREAT are specified and the path names a symbolic link,
- * an exception is raised regardless of the contents of the symbolic link.
- *
- * If File::EXCL is specified and File::CREAT is not specified,
- * the result is undefined.
- *
- * === POSIX \File \Constants
- *
- * Some file-access constants are defined only on POSIX-compliant systems;
- * those are:
- *
- * - File::SYNC.
- * - File::DSYNC.
- * - File::RSYNC.
- * - File::DIRECT.
- * - File::NOATIME.
- * - File::NOCTTY.
- * - File::NOFOLLOW.
- * - File::TMPFILE.
- *
- * ==== File::SYNC, File::RSYNC, and File::DSYNC
- *
- * Flag File::SYNC, File::RSYNC, or File::DSYNC
- * specifies synchronization of I/O operations with the underlying file system.
- *
- * These flags are valid only for POSIX-compliant systems.
- *
- * - File::SYNC specifies that all write operations (both data and metadata)
- * are immediately to be flushed to the underlying storage device.
- * This means that the data is written to the storage device,
- * and the file's metadata (e.g., file size, timestamps, permissions)
- * are also synchronized.
- * This guarantees that data is safely stored on the storage medium
- * before returning control to the calling program.
- * This flag can have a significant impact on performance
- * since it requires synchronous writes, which can be slower
- * compared to asynchronous writes.
- *
- * - File::RSYNC specifies that any read operations on the file will not return
- * until all outstanding write operations
- * (those that have been issued but not completed) are also synchronized.
- * This is useful when you want to read the most up-to-date data,
- * which may still be in the process of being written.
- *
- * - File::DSYNC specifies that all _data_ write operations
- * are immediately to be flushed to the underlying storage device;
- * this differs from File::SYNC, which requires that _metadata_
- * also be synchronized.
- *
- * Note that the behavior of these flags may vary slightly
- * depending on the operating system and filesystem being used.
- * Additionally, using these flags can have an impact on performance
- * due to the synchronous nature of the I/O operations,
- * so they should be used judiciously,
- * especially in performance-critical applications.
- *
- * ==== File::NOCTTY
- *
- * Flag File::NOCTTY specifies that if the stream is a terminal device,
- * that device does not become the controlling terminal for the process.
- *
- * Defined only for POSIX-compliant systems.
- *
- * ==== File::DIRECT
- *
- * Flag File::DIRECT requests that cache effects of the I/O to and from the stream
- * be minimized.
- *
- * Defined only for POSIX-compliant systems.
- *
- * ==== File::NOATIME
- *
- * Flag File::NOATIME specifies that act of opening the stream
- * should not modify its access time (atime).
- *
- * Defined only for POSIX-compliant systems.
- *
- * ==== File::NOFOLLOW
- *
- * Flag File::NOFOLLOW specifies that if path is a symbolic link,
- * it should not be followed.
- *
- * Defined only for POSIX-compliant systems.
- *
- * ==== File::TMPFILE
- *
- * Flag File::TMPFILE specifies that the opened stream
- * should be a new temporary file.
- *
- * Defined only for POSIX-compliant systems.
- *
- * === Other File-Access \Constants
- *
- * ==== File::NONBLOCK
- *
- * When possible, the file is opened in nonblocking mode.
- * Neither the open operation nor any subsequent I/O operations on
- * the file will cause the calling process to wait.
- *
- * ==== File::BINARY
- *
- * Flag File::BINARY specifies that the stream is to be accessed in binary mode.
- *
- * ==== File::SHARE_DELETE
- *
- * Flag File::SHARE_DELETE enables other processes to open the stream
- * with delete access.
- *
- * Windows only.
- *
- * If the stream is opened for (local) delete access without File::SHARE_DELETE,
- * and another process attempts to open it with delete access,
- * the attempt fails and the stream is not opened for that process.
- *
- * == Locking
- *
- * Four file constants relate to stream locking;
- * see File#flock:
- *
- * ==== File::LOCK_EX
- *
- * Flag File::LOCK_EX specifies an exclusive lock;
- * only one process a a time may lock the stream.
- *
- * ==== File::LOCK_NB
- *
- * Flag File::LOCK_NB specifies non-blocking locking for the stream;
- * may be combined with File::LOCK_EX or File::LOCK_SH.
- *
- * ==== File::LOCK_SH
- *
- * Flag File::LOCK_SH specifies that multiple processes may lock
- * the stream at the same time.
- *
- * ==== File::LOCK_UN
- *
- * Flag File::LOCK_UN specifies that the stream is not to be locked.
- *
- * == Filename Globbing \Constants (File::FNM_*)
- *
- * Filename-globbing constants may be used with optional argument +flags+
- * in calls to the following methods:
- *
- * - Dir.glob.
- * - File.fnmatch.
- * - Pathname#fnmatch.
- * - Pathname.glob.
- * - Pathname#glob.
- *
- * The constants are:
- *
- * ==== File::FNM_CASEFOLD
- *
- * Flag File::FNM_CASEFOLD makes patterns case insensitive
- * for File.fnmatch (but not Dir.glob).
- *
- * ==== File::FNM_DOTMATCH
- *
- * Flag File::FNM_DOTMATCH makes the <tt>'*'</tt> pattern
- * match a filename starting with <tt>'.'</tt>.
- *
- * ==== File::FNM_EXTGLOB
- *
- * Flag File::FNM_EXTGLOB enables pattern <tt>'{_a_,_b_}'</tt>,
- * which matches pattern '_a_' and pattern '_b_';
- * behaves like
- * a {regexp union}[rdoc-ref:Regexp.union]
- * (e.g., <tt>'(?:_a_|_b_)'</tt>):
- *
- * pattern = '{LEGAL,BSDL}'
- * Dir.glob(pattern) # => ["LEGAL", "BSDL"]
- * Pathname.glob(pattern) # => [#<Pathname:LEGAL>, #<Pathname:BSDL>]
- * pathname.glob(pattern) # => [#<Pathname:LEGAL>, #<Pathname:BSDL>]
- *
- * ==== File::FNM_NOESCAPE
- *
- * Flag File::FNM_NOESCAPE disables <tt>'\'</tt> escaping.
- *
- * ==== File::FNM_PATHNAME
- *
- * Flag File::FNM_PATHNAME specifies that patterns <tt>'*'</tt> and <tt>'?'</tt>
- * do not match the directory separator
- * (the value of constant File::SEPARATOR).
- *
- * ==== File::FNM_SHORTNAME
- *
- * Flag File::FNM_SHORTNAME allows patterns to match short names if they exist.
- *
- * Windows only.
- *
- * ==== File::FNM_SYSCASE
- *
- * Flag File::FNM_SYSCASE specifies that case sensitivity
- * is the same as in the underlying operating system;
- * effective for File.fnmatch, but not Dir.glob.
- *
- * == Other \Constants
- *
- * ==== File::NULL
- *
- * Flag File::NULL contains the string value of the null device:
- *
- * - On a Unix-like OS, <tt>'/dev/null'</tt>.
- * - On Windows, <tt>'NUL'</tt>.
+ * If the underlying platform doesn't define a constant the corresponding
+ * Ruby constant is not defined.
*
+ * Your platform documentations (e.g. man open(2)) may describe more
+ * detailed information.
*/
rb_mFConst = rb_define_module_under(rb_cFile, "Constants");
rb_include_module(rb_cIO, rb_mFConst);
- /* {File::RDONLY}[rdoc-ref:File::Constants@File-3A-3ARDONLY] */
+
+ /* open for reading only */
rb_define_const(rb_mFConst, "RDONLY", INT2FIX(O_RDONLY));
- /* {File::WRONLY}[rdoc-ref:File::Constants@File-3A-3AWRONLY] */
+ /* open for writing only */
rb_define_const(rb_mFConst, "WRONLY", INT2FIX(O_WRONLY));
- /* {File::RDWR}[rdoc-ref:File::Constants@File-3A-3ARDWR] */
+ /* open for reading and writing */
rb_define_const(rb_mFConst, "RDWR", INT2FIX(O_RDWR));
- /* {File::APPEND}[rdoc-ref:File::Constants@File-3A-3AAPPEND] */
+ /* append on each write */
rb_define_const(rb_mFConst, "APPEND", INT2FIX(O_APPEND));
- /* {File::CREAT}[rdoc-ref:File::Constants@File-3A-3ACREAT] */
+ /* create file if it does not exist */
rb_define_const(rb_mFConst, "CREAT", INT2FIX(O_CREAT));
- /* {File::EXCL}[rdoc-ref:File::Constants@File-3A-3AEXCL] */
+ /* error if CREAT and the file exists */
rb_define_const(rb_mFConst, "EXCL", INT2FIX(O_EXCL));
#if defined(O_NDELAY) || defined(O_NONBLOCK)
# ifndef O_NONBLOCK
# define O_NONBLOCK O_NDELAY
# endif
- /* {File::NONBLOCK}[rdoc-ref:File::Constants@File-3A-3ANONBLOCK] */
+ /* do not block on open or for data to become available */
rb_define_const(rb_mFConst, "NONBLOCK", INT2FIX(O_NONBLOCK));
#endif
- /* {File::TRUNC}[rdoc-ref:File::Constants@File-3A-3ATRUNC] */
+ /* truncate size to 0 */
rb_define_const(rb_mFConst, "TRUNC", INT2FIX(O_TRUNC));
#ifdef O_NOCTTY
- /* {File::NOCTTY}[rdoc-ref:File::Constants@File-3A-3ANOCTTY] */
+ /* not to make opened IO the controlling terminal device */
rb_define_const(rb_mFConst, "NOCTTY", INT2FIX(O_NOCTTY));
#endif
#ifndef O_BINARY
# define O_BINARY 0
#endif
- /* {File::BINARY}[rdoc-ref:File::Constants@File-3A-3ABINARY] */
+ /* disable line code conversion */
rb_define_const(rb_mFConst, "BINARY", INT2FIX(O_BINARY));
#ifndef O_SHARE_DELETE
# define O_SHARE_DELETE 0
#endif
- /* {File::SHARE_DELETE}[rdoc-ref:File::Constants@File-3A-3ASHARE_DELETE] */
+ /* can delete opened file */
rb_define_const(rb_mFConst, "SHARE_DELETE", INT2FIX(O_SHARE_DELETE));
#ifdef O_SYNC
- /* {File::SYNC}[rdoc-ref:File::Constants@File-3A-3ASYNC-2C+File-3A-3ARSYNC-2C+and+File-3A-3ADSYNC] */
+ /* any write operation perform synchronously */
rb_define_const(rb_mFConst, "SYNC", INT2FIX(O_SYNC));
#endif
#ifdef O_DSYNC
- /* {File::DSYNC}[rdoc-ref:File::Constants@File-3A-3ASYNC-2C+File-3A-3ARSYNC-2C+and+File-3A-3ADSYNC] */
+ /* any write operation perform synchronously except some meta data */
rb_define_const(rb_mFConst, "DSYNC", INT2FIX(O_DSYNC));
#endif
#ifdef O_RSYNC
- /* {File::RSYNC}[rdoc-ref:File::Constants@File-3A-3ASYNC-2C+File-3A-3ARSYNC-2C+and+File-3A-3ADSYNC] */
+ /* any read operation perform synchronously. used with SYNC or DSYNC. */
rb_define_const(rb_mFConst, "RSYNC", INT2FIX(O_RSYNC));
#endif
#ifdef O_NOFOLLOW
- /* {File::NOFOLLOW}[rdoc-ref:File::Constants@File-3A-3ANOFOLLOW] */
+ /* do not follow symlinks */
rb_define_const(rb_mFConst, "NOFOLLOW", INT2FIX(O_NOFOLLOW)); /* FreeBSD, Linux */
#endif
#ifdef O_NOATIME
- /* {File::NOATIME}[rdoc-ref:File::Constants@File-3A-3ANOATIME] */
+ /* do not change atime */
rb_define_const(rb_mFConst, "NOATIME", INT2FIX(O_NOATIME)); /* Linux */
#endif
#ifdef O_DIRECT
- /* {File::DIRECT}[rdoc-ref:File::Constants@File-3A-3ADIRECT] */
+ /* Try to minimize cache effects of the I/O to and from this file. */
rb_define_const(rb_mFConst, "DIRECT", INT2FIX(O_DIRECT));
#endif
#ifdef O_TMPFILE
- /* {File::TMPFILE}[rdoc-ref:File::Constants@File-3A-3ATMPFILE] */
+ /* Create an unnamed temporary file */
rb_define_const(rb_mFConst, "TMPFILE", INT2FIX(O_TMPFILE));
#endif
- /* {File::LOCK_SH}[rdoc-ref:File::Constants@File-3A-3ALOCK_SH] */
+ /* shared lock. see File#flock */
rb_define_const(rb_mFConst, "LOCK_SH", INT2FIX(LOCK_SH));
- /* {File::LOCK_EX}[rdoc-ref:File::Constants@File-3A-3ALOCK_EX] */
+ /* exclusive lock. see File#flock */
rb_define_const(rb_mFConst, "LOCK_EX", INT2FIX(LOCK_EX));
- /* {File::LOCK_UN}[rdoc-ref:File::Constants@File-3A-3ALOCK_UN] */
+ /* unlock. see File#flock */
rb_define_const(rb_mFConst, "LOCK_UN", INT2FIX(LOCK_UN));
- /* {File::LOCK_NB}[rdoc-ref:File::Constants@File-3A-3ALOCK_NB] */
+ /* non-blocking lock. used with LOCK_SH or LOCK_EX. see File#flock */
rb_define_const(rb_mFConst, "LOCK_NB", INT2FIX(LOCK_NB));
- /* {File::NULL}[rdoc-ref:File::Constants@File-3A-3ANULL] */
+ /* Name of the null device */
rb_define_const(rb_mFConst, "NULL", rb_fstring_cstr(ruby_null_device));
rb_define_global_function("test", rb_f_test, -1);
diff --git a/gc.c b/gc.c
index 9760f343f8..919d57989a 100644
--- a/gc.c
+++ b/gc.c
@@ -19,6 +19,15 @@
# include "ruby/ruby.h"
#endif
+#include <signal.h>
+
+#define sighandler_t ruby_sighandler_t
+
+#ifndef _WIN32
+#include <unistd.h>
+#include <sys/mman.h>
+#endif
+
#if defined(__wasm__) && !defined(__EMSCRIPTEN__)
# include "wasm/setjmp.h"
# include "wasm/machine.h"
@@ -30,6 +39,16 @@
/* MALLOC_HEADERS_BEGIN */
#ifndef HAVE_MALLOC_USABLE_SIZE
+# ifdef _WIN32
+# define HAVE_MALLOC_USABLE_SIZE
+# define malloc_usable_size(a) _msize(a)
+# elif defined HAVE_MALLOC_SIZE
+# define HAVE_MALLOC_USABLE_SIZE
+# define malloc_usable_size(a) malloc_size(a)
+# endif
+#endif
+
+#ifdef HAVE_MALLOC_USABLE_SIZE
# ifdef RUBY_ALTERNATIVE_MALLOC_HEADER
/* Alternative malloc header is included in ruby/missing.h */
# elif defined(HAVE_MALLOC_H)
@@ -39,18 +58,12 @@
# elif defined(HAVE_MALLOC_MALLOC_H)
# include <malloc/malloc.h>
# endif
-
-# ifdef _WIN32
-# define HAVE_MALLOC_USABLE_SIZE
-# define malloc_usable_size(a) _msize(a)
-# elif defined HAVE_MALLOC_SIZE
-# define HAVE_MALLOC_USABLE_SIZE
-# define malloc_usable_size(a) malloc_size(a)
-# endif
-#else
-# include <malloc.h>
#endif
+#if !defined(PAGE_SIZE) && defined(HAVE_SYS_USER_H)
+/* LIST_HEAD conflicts with sys/queue.h on macOS */
+# include <sys/user.h>
+#endif
/* MALLOC_HEADERS_END */
#ifdef HAVE_SYS_TIME_H
@@ -74,17 +87,20 @@
#include <emscripten.h>
#endif
+#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS
+# include <mach/task.h>
+# include <mach/mach_init.h>
+# include <mach/mach_port.h>
+#endif
#undef LIST_HEAD /* ccan/list conflicts with BSD-origin sys/queue.h. */
#include "constant.h"
-#include "darray.h"
#include "debug_counter.h"
#include "eval_intern.h"
-#include "gc/gc.h"
+#include "gc.h"
#include "id_table.h"
#include "internal.h"
#include "internal/class.h"
-#include "internal/compile.h"
#include "internal/complex.h"
#include "internal/cont.h"
#include "internal/error.h"
@@ -103,7 +119,7 @@
#include "internal/thread.h"
#include "internal/variable.h"
#include "internal/warnings.h"
-#include "rjit.h"
+#include "mjit.h"
#include "probes.h"
#include "regint.h"
#include "ruby/debug.h"
@@ -112,816 +128,2981 @@
#include "ruby/st.h"
#include "ruby/thread.h"
#include "ruby/util.h"
-#include "ruby/vm.h"
#include "ruby_assert.h"
#include "ruby_atomic.h"
#include "symbol.h"
+#include "transient_heap.h"
#include "vm_core.h"
#include "vm_sync.h"
#include "vm_callinfo.h"
#include "ractor_core.h"
-#include "yjit.h"
#include "builtin.h"
#include "shape.h"
-unsigned int
-rb_gc_vm_lock(void)
+#define rb_setjmp(env) RUBY_SETJMP(env)
+#define rb_jmp_buf rb_jmpbuf_t
+#undef rb_data_object_wrap
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+static inline struct rbimpl_size_mul_overflow_tag
+size_add_overflow(size_t x, size_t y)
{
- unsigned int lev;
- RB_VM_LOCK_ENTER_LEV(&lev);
- return lev;
+ size_t z;
+ bool p;
+#if 0
+
+#elif __has_builtin(__builtin_add_overflow)
+ p = __builtin_add_overflow(x, y, &z);
+
+#elif defined(DSIZE_T)
+ RB_GNUC_EXTENSION DSIZE_T dx = x;
+ RB_GNUC_EXTENSION DSIZE_T dy = y;
+ RB_GNUC_EXTENSION DSIZE_T dz = dx + dy;
+ p = dz > SIZE_MAX;
+ z = (size_t)dz;
+
+#else
+ z = x + y;
+ p = z < y;
+
+#endif
+ return (struct rbimpl_size_mul_overflow_tag) { p, z, };
}
-void
-rb_gc_vm_unlock(unsigned int lev)
+static inline struct rbimpl_size_mul_overflow_tag
+size_mul_add_overflow(size_t x, size_t y, size_t z) /* x * y + z */
{
- RB_VM_LOCK_LEAVE_LEV(&lev);
+ struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(x, y);
+ struct rbimpl_size_mul_overflow_tag u = size_add_overflow(t.right, z);
+ return (struct rbimpl_size_mul_overflow_tag) { t.left || u.left, u.right };
}
-unsigned int
-rb_gc_cr_lock(void)
+static inline struct rbimpl_size_mul_overflow_tag
+size_mul_add_mul_overflow(size_t x, size_t y, size_t z, size_t w) /* x * y + z * w */
{
- unsigned int lev;
- RB_VM_LOCK_ENTER_CR_LEV(GET_RACTOR(), &lev);
- return lev;
+ struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(x, y);
+ struct rbimpl_size_mul_overflow_tag u = rbimpl_size_mul_overflow(z, w);
+ struct rbimpl_size_mul_overflow_tag v = size_add_overflow(t.right, u.right);
+ return (struct rbimpl_size_mul_overflow_tag) { t.left || u.left || v.left, v.right };
}
-void
-rb_gc_cr_unlock(unsigned int lev)
+PRINTF_ARGS(NORETURN(static void gc_raise(VALUE, const char*, ...)), 2, 3);
+
+static inline size_t
+size_mul_or_raise(size_t x, size_t y, VALUE exc)
{
- RB_VM_LOCK_LEAVE_CR_LEV(GET_RACTOR(), &lev);
+ struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(x, y);
+ if (LIKELY(!t.left)) {
+ return t.right;
+ }
+ else if (rb_during_gc()) {
+ rb_memerror(); /* or...? */
+ }
+ else {
+ gc_raise(
+ exc,
+ "integer overflow: %"PRIuSIZE
+ " * %"PRIuSIZE
+ " > %"PRIuSIZE,
+ x, y, (size_t)SIZE_MAX);
+ }
}
-unsigned int
-rb_gc_vm_lock_no_barrier(void)
+size_t
+rb_size_mul_or_raise(size_t x, size_t y, VALUE exc)
{
- unsigned int lev = 0;
- RB_VM_LOCK_ENTER_LEV_NB(&lev);
- return lev;
+ return size_mul_or_raise(x, y, exc);
}
-void
-rb_gc_vm_unlock_no_barrier(unsigned int lev)
+static inline size_t
+size_mul_add_or_raise(size_t x, size_t y, size_t z, VALUE exc)
{
- RB_VM_LOCK_LEAVE_LEV(&lev);
+ struct rbimpl_size_mul_overflow_tag t = size_mul_add_overflow(x, y, z);
+ if (LIKELY(!t.left)) {
+ return t.right;
+ }
+ else if (rb_during_gc()) {
+ rb_memerror(); /* or...? */
+ }
+ else {
+ gc_raise(
+ exc,
+ "integer overflow: %"PRIuSIZE
+ " * %"PRIuSIZE
+ " + %"PRIuSIZE
+ " > %"PRIuSIZE,
+ x, y, z, (size_t)SIZE_MAX);
+ }
}
-void
-rb_gc_vm_barrier(void)
+size_t
+rb_size_mul_add_or_raise(size_t x, size_t y, size_t z, VALUE exc)
{
- rb_vm_barrier();
+ return size_mul_add_or_raise(x, y, z, exc);
}
-void
-rb_gc_event_hook(VALUE obj, rb_event_flag_t event)
+static inline size_t
+size_mul_add_mul_or_raise(size_t x, size_t y, size_t z, size_t w, VALUE exc)
{
- if (LIKELY(!(ruby_vm_event_flags & event))) return;
+ struct rbimpl_size_mul_overflow_tag t = size_mul_add_mul_overflow(x, y, z, w);
+ if (LIKELY(!t.left)) {
+ return t.right;
+ }
+ else if (rb_during_gc()) {
+ rb_memerror(); /* or...? */
+ }
+ else {
+ gc_raise(
+ exc,
+ "integer overflow: %"PRIdSIZE
+ " * %"PRIdSIZE
+ " + %"PRIdSIZE
+ " * %"PRIdSIZE
+ " > %"PRIdSIZE,
+ x, y, z, w, (size_t)SIZE_MAX);
+ }
+}
- rb_execution_context_t *ec = GET_EC();
- if (!ec->cfp) return;
+#if defined(HAVE_RB_GC_GUARDED_PTR_VAL) && HAVE_RB_GC_GUARDED_PTR_VAL
+/* trick the compiler into thinking a external signal handler uses this */
+volatile VALUE rb_gc_guarded_val;
+volatile VALUE *
+rb_gc_guarded_ptr_val(volatile VALUE *ptr, VALUE val)
+{
+ rb_gc_guarded_val = val;
- EXEC_EVENT_HOOK(ec, event, ec->cfp->self, 0, 0, 0, obj);
+ return ptr;
}
+#endif
-void *
-rb_gc_get_objspace(void)
+#ifndef GC_HEAP_INIT_SLOTS
+#define GC_HEAP_INIT_SLOTS 10000
+#endif
+#ifndef GC_HEAP_FREE_SLOTS
+#define GC_HEAP_FREE_SLOTS 4096
+#endif
+#ifndef GC_HEAP_GROWTH_FACTOR
+#define GC_HEAP_GROWTH_FACTOR 1.8
+#endif
+#ifndef GC_HEAP_GROWTH_MAX_SLOTS
+#define GC_HEAP_GROWTH_MAX_SLOTS 0 /* 0 is disable */
+#endif
+#ifndef GC_HEAP_OLDOBJECT_LIMIT_FACTOR
+#define GC_HEAP_OLDOBJECT_LIMIT_FACTOR 2.0
+#endif
+
+#ifndef GC_HEAP_FREE_SLOTS_MIN_RATIO
+#define GC_HEAP_FREE_SLOTS_MIN_RATIO 0.20
+#endif
+#ifndef GC_HEAP_FREE_SLOTS_GOAL_RATIO
+#define GC_HEAP_FREE_SLOTS_GOAL_RATIO 0.40
+#endif
+#ifndef GC_HEAP_FREE_SLOTS_MAX_RATIO
+#define GC_HEAP_FREE_SLOTS_MAX_RATIO 0.65
+#endif
+
+#ifndef GC_MALLOC_LIMIT_MIN
+#define GC_MALLOC_LIMIT_MIN (16 * 1024 * 1024 /* 16MB */)
+#endif
+#ifndef GC_MALLOC_LIMIT_MAX
+#define GC_MALLOC_LIMIT_MAX (32 * 1024 * 1024 /* 32MB */)
+#endif
+#ifndef GC_MALLOC_LIMIT_GROWTH_FACTOR
+#define GC_MALLOC_LIMIT_GROWTH_FACTOR 1.4
+#endif
+
+#ifndef GC_OLDMALLOC_LIMIT_MIN
+#define GC_OLDMALLOC_LIMIT_MIN (16 * 1024 * 1024 /* 16MB */)
+#endif
+#ifndef GC_OLDMALLOC_LIMIT_GROWTH_FACTOR
+#define GC_OLDMALLOC_LIMIT_GROWTH_FACTOR 1.2
+#endif
+#ifndef GC_OLDMALLOC_LIMIT_MAX
+#define GC_OLDMALLOC_LIMIT_MAX (128 * 1024 * 1024 /* 128MB */)
+#endif
+
+#ifndef PRINT_MEASURE_LINE
+#define PRINT_MEASURE_LINE 0
+#endif
+#ifndef PRINT_ENTER_EXIT_TICK
+#define PRINT_ENTER_EXIT_TICK 0
+#endif
+#ifndef PRINT_ROOT_TICKS
+#define PRINT_ROOT_TICKS 0
+#endif
+
+#define USE_TICK_T (PRINT_ENTER_EXIT_TICK || PRINT_MEASURE_LINE || PRINT_ROOT_TICKS)
+#define TICK_TYPE 1
+
+typedef struct {
+ size_t heap_init_slots;
+ size_t heap_free_slots;
+ double growth_factor;
+ size_t growth_max_slots;
+
+ double heap_free_slots_min_ratio;
+ double heap_free_slots_goal_ratio;
+ double heap_free_slots_max_ratio;
+ double oldobject_limit_factor;
+
+ size_t malloc_limit_min;
+ size_t malloc_limit_max;
+ double malloc_limit_growth_factor;
+
+ size_t oldmalloc_limit_min;
+ size_t oldmalloc_limit_max;
+ double oldmalloc_limit_growth_factor;
+
+ VALUE gc_stress;
+} ruby_gc_params_t;
+
+static ruby_gc_params_t gc_params = {
+ GC_HEAP_INIT_SLOTS,
+ GC_HEAP_FREE_SLOTS,
+ GC_HEAP_GROWTH_FACTOR,
+ GC_HEAP_GROWTH_MAX_SLOTS,
+
+ GC_HEAP_FREE_SLOTS_MIN_RATIO,
+ GC_HEAP_FREE_SLOTS_GOAL_RATIO,
+ GC_HEAP_FREE_SLOTS_MAX_RATIO,
+ GC_HEAP_OLDOBJECT_LIMIT_FACTOR,
+
+ GC_MALLOC_LIMIT_MIN,
+ GC_MALLOC_LIMIT_MAX,
+ GC_MALLOC_LIMIT_GROWTH_FACTOR,
+
+ GC_OLDMALLOC_LIMIT_MIN,
+ GC_OLDMALLOC_LIMIT_MAX,
+ GC_OLDMALLOC_LIMIT_GROWTH_FACTOR,
+
+ FALSE,
+};
+
+/* GC_DEBUG:
+ * enable to embed GC debugging information.
+ */
+#ifndef GC_DEBUG
+#define GC_DEBUG 0
+#endif
+
+/* RGENGC_DEBUG:
+ * 1: basic information
+ * 2: remember set operation
+ * 3: mark
+ * 4:
+ * 5: sweep
+ */
+#ifndef RGENGC_DEBUG
+#ifdef RUBY_DEVEL
+#define RGENGC_DEBUG -1
+#else
+#define RGENGC_DEBUG 0
+#endif
+#endif
+#if RGENGC_DEBUG < 0 && !defined(_MSC_VER)
+# define RGENGC_DEBUG_ENABLED(level) (-(RGENGC_DEBUG) >= (level) && ruby_rgengc_debug >= (level))
+#elif defined(HAVE_VA_ARGS_MACRO)
+# define RGENGC_DEBUG_ENABLED(level) ((RGENGC_DEBUG) >= (level))
+#else
+# define RGENGC_DEBUG_ENABLED(level) 0
+#endif
+int ruby_rgengc_debug;
+
+/* RGENGC_CHECK_MODE
+ * 0: disable all assertions
+ * 1: enable assertions (to debug RGenGC)
+ * 2: enable internal consistency check at each GC (for debugging)
+ * 3: enable internal consistency check at each GC steps (for debugging)
+ * 4: enable liveness check
+ * 5: show all references
+ */
+#ifndef RGENGC_CHECK_MODE
+#define RGENGC_CHECK_MODE 0
+#endif
+
+// Note: using RUBY_ASSERT_WHEN() extend a macro in expr (info by nobu).
+#define GC_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(RGENGC_CHECK_MODE > 0, expr, #expr)
+
+/* RGENGC_OLD_NEWOBJ_CHECK
+ * 0: disable all assertions
+ * >0: make a OLD object when new object creation.
+ *
+ * Make one OLD object per RGENGC_OLD_NEWOBJ_CHECK WB protected objects creation.
+ */
+#ifndef RGENGC_OLD_NEWOBJ_CHECK
+#define RGENGC_OLD_NEWOBJ_CHECK 0
+#endif
+
+/* RGENGC_PROFILE
+ * 0: disable RGenGC profiling
+ * 1: enable profiling for basic information
+ * 2: enable profiling for each types
+ */
+#ifndef RGENGC_PROFILE
+#define RGENGC_PROFILE 0
+#endif
+
+/* RGENGC_ESTIMATE_OLDMALLOC
+ * Enable/disable to estimate increase size of malloc'ed size by old objects.
+ * If estimation exceeds threshold, then will invoke full GC.
+ * 0: disable estimation.
+ * 1: enable estimation.
+ */
+#ifndef RGENGC_ESTIMATE_OLDMALLOC
+#define RGENGC_ESTIMATE_OLDMALLOC 1
+#endif
+
+/* RGENGC_FORCE_MAJOR_GC
+ * Force major/full GC if this macro is not 0.
+ */
+#ifndef RGENGC_FORCE_MAJOR_GC
+#define RGENGC_FORCE_MAJOR_GC 0
+#endif
+
+#ifndef GC_PROFILE_MORE_DETAIL
+#define GC_PROFILE_MORE_DETAIL 0
+#endif
+#ifndef GC_PROFILE_DETAIL_MEMORY
+#define GC_PROFILE_DETAIL_MEMORY 0
+#endif
+#ifndef GC_ENABLE_INCREMENTAL_MARK
+#define GC_ENABLE_INCREMENTAL_MARK USE_RINCGC
+#endif
+#ifndef GC_ENABLE_LAZY_SWEEP
+#define GC_ENABLE_LAZY_SWEEP 1
+#endif
+#ifndef CALC_EXACT_MALLOC_SIZE
+#define CALC_EXACT_MALLOC_SIZE USE_GC_MALLOC_OBJ_INFO_DETAILS
+#endif
+#if defined(HAVE_MALLOC_USABLE_SIZE) || CALC_EXACT_MALLOC_SIZE > 0
+#ifndef MALLOC_ALLOCATED_SIZE
+#define MALLOC_ALLOCATED_SIZE 0
+#endif
+#else
+#define MALLOC_ALLOCATED_SIZE 0
+#endif
+#ifndef MALLOC_ALLOCATED_SIZE_CHECK
+#define MALLOC_ALLOCATED_SIZE_CHECK 0
+#endif
+
+#ifndef GC_DEBUG_STRESS_TO_CLASS
+#define GC_DEBUG_STRESS_TO_CLASS 0
+#endif
+
+#ifndef RGENGC_OBJ_INFO
+#define RGENGC_OBJ_INFO (RGENGC_DEBUG | RGENGC_CHECK_MODE)
+#endif
+
+typedef enum {
+ GPR_FLAG_NONE = 0x000,
+ /* major reason */
+ GPR_FLAG_MAJOR_BY_NOFREE = 0x001,
+ GPR_FLAG_MAJOR_BY_OLDGEN = 0x002,
+ GPR_FLAG_MAJOR_BY_SHADY = 0x004,
+ GPR_FLAG_MAJOR_BY_FORCE = 0x008,
+#if RGENGC_ESTIMATE_OLDMALLOC
+ GPR_FLAG_MAJOR_BY_OLDMALLOC = 0x020,
+#endif
+ GPR_FLAG_MAJOR_MASK = 0x0ff,
+
+ /* gc reason */
+ GPR_FLAG_NEWOBJ = 0x100,
+ GPR_FLAG_MALLOC = 0x200,
+ GPR_FLAG_METHOD = 0x400,
+ GPR_FLAG_CAPI = 0x800,
+ GPR_FLAG_STRESS = 0x1000,
+
+ /* others */
+ GPR_FLAG_IMMEDIATE_SWEEP = 0x2000,
+ GPR_FLAG_HAVE_FINALIZE = 0x4000,
+ GPR_FLAG_IMMEDIATE_MARK = 0x8000,
+ GPR_FLAG_FULL_MARK = 0x10000,
+ GPR_FLAG_COMPACT = 0x20000,
+
+ GPR_DEFAULT_REASON =
+ (GPR_FLAG_FULL_MARK | GPR_FLAG_IMMEDIATE_MARK |
+ GPR_FLAG_IMMEDIATE_SWEEP | GPR_FLAG_CAPI),
+} gc_profile_record_flag;
+
+typedef struct gc_profile_record {
+ unsigned int flags;
+
+ double gc_time;
+ double gc_invoke_time;
+
+ size_t heap_total_objects;
+ size_t heap_use_size;
+ size_t heap_total_size;
+ size_t moved_objects;
+
+#if GC_PROFILE_MORE_DETAIL
+ double gc_mark_time;
+ double gc_sweep_time;
+
+ size_t heap_use_pages;
+ size_t heap_live_objects;
+ size_t heap_free_objects;
+
+ size_t allocate_increase;
+ size_t allocate_limit;
+
+ double prepare_time;
+ size_t removing_objects;
+ size_t empty_objects;
+#if GC_PROFILE_DETAIL_MEMORY
+ long maxrss;
+ long minflt;
+ long majflt;
+#endif
+#endif
+#if MALLOC_ALLOCATED_SIZE
+ size_t allocated_size;
+#endif
+
+#if RGENGC_PROFILE > 0
+ size_t old_objects;
+ size_t remembered_normal_objects;
+ size_t remembered_shady_objects;
+#endif
+} gc_profile_record;
+
+struct RMoved {
+ VALUE flags;
+ VALUE dummy;
+ VALUE destination;
+ shape_id_t original_shape_id;
+};
+
+#define RMOVED(obj) ((struct RMoved *)(obj))
+
+typedef struct RVALUE {
+ union {
+ struct {
+ VALUE flags; /* always 0 for freed obj */
+ struct RVALUE *next;
+ } free;
+ struct RMoved moved;
+ struct RBasic basic;
+ struct RObject object;
+ struct RClass klass;
+ struct RFloat flonum;
+ struct RString string;
+ struct RArray array;
+ struct RRegexp regexp;
+ struct RHash hash;
+ struct RData data;
+ struct RTypedData typeddata;
+ struct RStruct rstruct;
+ struct RBignum bignum;
+ struct RFile file;
+ struct RMatch match;
+ struct RRational rational;
+ struct RComplex complex;
+ struct RSymbol symbol;
+ union {
+ rb_cref_t cref;
+ struct vm_svar svar;
+ struct vm_throw_data throw_data;
+ struct vm_ifunc ifunc;
+ struct MEMO memo;
+ struct rb_method_entry_struct ment;
+ const rb_iseq_t iseq;
+ rb_env_t env;
+ struct rb_imemo_tmpbuf_struct alloc;
+ rb_ast_t ast;
+ } imemo;
+ struct {
+ struct RBasic basic;
+ VALUE v1;
+ VALUE v2;
+ VALUE v3;
+ } values;
+ } as;
+
+ /* Start of RVALUE_OVERHEAD.
+ * Do not directly read these members from the RVALUE as they're located
+ * at the end of the slot (which may differ in size depending on the size
+ * pool). */
+#if RACTOR_CHECK_MODE
+ uint32_t _ractor_belonging_id;
+#endif
+#if GC_DEBUG
+ const char *file;
+ int line;
+#endif
+} RVALUE;
+
+#if RACTOR_CHECK_MODE
+# define RVALUE_OVERHEAD (sizeof(RVALUE) - offsetof(RVALUE, _ractor_belonging_id))
+#elif GC_DEBUG
+# define RVALUE_OVERHEAD (sizeof(RVALUE) - offsetof(RVALUE, file))
+#else
+# define RVALUE_OVERHEAD 0
+#endif
+
+STATIC_ASSERT(sizeof_rvalue, sizeof(RVALUE) == (SIZEOF_VALUE * 5) + RVALUE_OVERHEAD);
+STATIC_ASSERT(alignof_rvalue, RUBY_ALIGNOF(RVALUE) == SIZEOF_VALUE);
+
+typedef uintptr_t bits_t;
+enum {
+ BITS_SIZE = sizeof(bits_t),
+ BITS_BITLENGTH = ( BITS_SIZE * CHAR_BIT )
+};
+#define popcount_bits rb_popcount_intptr
+
+struct heap_page_header {
+ struct heap_page *page;
+};
+
+struct heap_page_body {
+ struct heap_page_header header;
+ /* char gap[]; */
+ /* RVALUE values[]; */
+};
+
+struct gc_list {
+ VALUE *varptr;
+ struct gc_list *next;
+};
+
+#define STACK_CHUNK_SIZE 500
+
+typedef struct stack_chunk {
+ VALUE data[STACK_CHUNK_SIZE];
+ struct stack_chunk *next;
+} stack_chunk_t;
+
+typedef struct mark_stack {
+ stack_chunk_t *chunk;
+ stack_chunk_t *cache;
+ int index;
+ int limit;
+ size_t cache_size;
+ size_t unused_cache_size;
+} mark_stack_t;
+
+#define SIZE_POOL_EDEN_HEAP(size_pool) (&(size_pool)->eden_heap)
+#define SIZE_POOL_TOMB_HEAP(size_pool) (&(size_pool)->tomb_heap)
+
+typedef struct rb_heap_struct {
+ struct heap_page *free_pages;
+ struct ccan_list_head pages;
+ struct heap_page *sweeping_page; /* iterator for .pages */
+ struct heap_page *compact_cursor;
+ uintptr_t compact_cursor_index;
+#if GC_ENABLE_INCREMENTAL_MARK
+ struct heap_page *pooled_pages;
+#endif
+ size_t total_pages; /* total page count in a heap */
+ size_t total_slots; /* total slot count (about total_pages * HEAP_PAGE_OBJ_LIMIT) */
+} rb_heap_t;
+
+typedef struct rb_size_pool_struct {
+ short slot_size;
+
+ size_t allocatable_pages;
+
+ /* Basic statistics */
+ size_t total_allocated_pages;
+ size_t total_freed_pages;
+ size_t force_major_gc_count;
+
+#if USE_RVARGC
+ /* Sweeping statistics */
+ size_t freed_slots;
+ size_t empty_slots;
+#endif
+
+ rb_heap_t eden_heap;
+ rb_heap_t tomb_heap;
+} rb_size_pool_t;
+
+enum gc_mode {
+ gc_mode_none,
+ gc_mode_marking,
+ gc_mode_sweeping,
+ gc_mode_compacting,
+};
+
+typedef struct rb_objspace {
+ struct {
+ size_t limit;
+ size_t increase;
+#if MALLOC_ALLOCATED_SIZE
+ size_t allocated_size;
+ size_t allocations;
+#endif
+
+ } malloc_params;
+
+ struct {
+ unsigned int mode : 2;
+ unsigned int immediate_sweep : 1;
+ unsigned int dont_gc : 1;
+ unsigned int dont_incremental : 1;
+ unsigned int during_gc : 1;
+ unsigned int during_compacting : 1;
+ unsigned int gc_stressful: 1;
+ unsigned int has_hook: 1;
+ unsigned int during_minor_gc : 1;
+#if GC_ENABLE_INCREMENTAL_MARK
+ unsigned int during_incremental_marking : 1;
+#endif
+ unsigned int measure_gc : 1;
+ } flags;
+
+ rb_event_flag_t hook_events;
+ size_t total_allocated_objects;
+ VALUE next_object_id;
+
+ rb_size_pool_t size_pools[SIZE_POOL_COUNT];
+
+ struct {
+ rb_atomic_t finalizing;
+ } atomic_flags;
+
+ mark_stack_t mark_stack;
+ size_t marked_slots;
+
+ struct {
+ struct heap_page **sorted;
+ size_t allocated_pages;
+ size_t allocatable_pages;
+ size_t sorted_length;
+ uintptr_t range[2];
+ size_t freeable_pages;
+
+ /* final */
+ size_t final_slots;
+ VALUE deferred_final;
+ } heap_pages;
+
+ st_table *finalizer_table;
+
+ struct {
+ int run;
+ unsigned int latest_gc_info;
+ gc_profile_record *records;
+ gc_profile_record *current_record;
+ size_t next_index;
+ size_t size;
+
+#if GC_PROFILE_MORE_DETAIL
+ double prepare_time;
+#endif
+ double invoke_time;
+
+ size_t minor_gc_count;
+ size_t major_gc_count;
+ size_t compact_count;
+ size_t read_barrier_faults;
+#if RGENGC_PROFILE > 0
+ size_t total_generated_normal_object_count;
+ size_t total_generated_shady_object_count;
+ size_t total_shade_operation_count;
+ size_t total_promoted_count;
+ size_t total_remembered_normal_object_count;
+ size_t total_remembered_shady_object_count;
+
+#if RGENGC_PROFILE >= 2
+ size_t generated_normal_object_count_types[RUBY_T_MASK];
+ size_t generated_shady_object_count_types[RUBY_T_MASK];
+ size_t shade_operation_count_types[RUBY_T_MASK];
+ size_t promoted_types[RUBY_T_MASK];
+ size_t remembered_normal_object_count_types[RUBY_T_MASK];
+ size_t remembered_shady_object_count_types[RUBY_T_MASK];
+#endif
+#endif /* RGENGC_PROFILE */
+
+ /* temporary profiling space */
+ double gc_sweep_start_time;
+ size_t total_allocated_objects_at_gc_start;
+ size_t heap_used_at_gc_start;
+
+ /* basic statistics */
+ size_t count;
+ size_t total_freed_objects;
+ uint64_t total_time_ns;
+ struct timespec start_time;
+ } profile;
+ struct gc_list *global_list;
+
+ VALUE gc_stress_mode;
+
+ struct {
+ VALUE parent_object;
+ int need_major_gc;
+ size_t last_major_gc;
+ size_t uncollectible_wb_unprotected_objects;
+ size_t uncollectible_wb_unprotected_objects_limit;
+ size_t old_objects;
+ size_t old_objects_limit;
+
+#if RGENGC_ESTIMATE_OLDMALLOC
+ size_t oldmalloc_increase;
+ size_t oldmalloc_increase_limit;
+#endif
+
+#if RGENGC_CHECK_MODE >= 2
+ struct st_table *allrefs_table;
+ size_t error_count;
+#endif
+ } rgengc;
+
+ struct {
+ size_t considered_count_table[T_MASK];
+ size_t moved_count_table[T_MASK];
+ size_t moved_up_count_table[T_MASK];
+ size_t moved_down_count_table[T_MASK];
+ size_t total_moved;
+ } rcompactor;
+
+#if GC_ENABLE_INCREMENTAL_MARK
+ struct {
+ size_t pooled_slots;
+ size_t step_slots;
+ } rincgc;
+#endif
+
+ st_table *id_to_obj_tbl;
+ st_table *obj_to_id_tbl;
+
+#if GC_DEBUG_STRESS_TO_CLASS
+ VALUE stress_to_class;
+#endif
+} rb_objspace_t;
+
+
+#ifndef HEAP_PAGE_ALIGN_LOG
+/* default tiny heap size: 64KiB */
+#define HEAP_PAGE_ALIGN_LOG 16
+#endif
+
+#define BASE_SLOT_SIZE sizeof(RVALUE)
+
+#define CEILDIV(i, mod) roomof(i, mod)
+enum {
+ HEAP_PAGE_ALIGN = (1UL << HEAP_PAGE_ALIGN_LOG),
+ HEAP_PAGE_ALIGN_MASK = (~(~0UL << HEAP_PAGE_ALIGN_LOG)),
+ HEAP_PAGE_SIZE = HEAP_PAGE_ALIGN,
+ HEAP_PAGE_OBJ_LIMIT = (unsigned int)((HEAP_PAGE_SIZE - sizeof(struct heap_page_header)) / BASE_SLOT_SIZE),
+ HEAP_PAGE_BITMAP_LIMIT = CEILDIV(CEILDIV(HEAP_PAGE_SIZE, BASE_SLOT_SIZE), BITS_BITLENGTH),
+ HEAP_PAGE_BITMAP_SIZE = (BITS_SIZE * HEAP_PAGE_BITMAP_LIMIT),
+};
+#define HEAP_PAGE_ALIGN (1 << HEAP_PAGE_ALIGN_LOG)
+#define HEAP_PAGE_SIZE HEAP_PAGE_ALIGN
+
+#if GC_ENABLE_INCREMENTAL_MARK && !defined(INCREMENTAL_MARK_STEP_ALLOCATIONS)
+# define INCREMENTAL_MARK_STEP_ALLOCATIONS 500
+#endif
+
+#undef INIT_HEAP_PAGE_ALLOC_USE_MMAP
+/* Must define either HEAP_PAGE_ALLOC_USE_MMAP or
+ * INIT_HEAP_PAGE_ALLOC_USE_MMAP. */
+
+#ifndef HAVE_MMAP
+/* We can't use mmap of course, if it is not available. */
+static const bool HEAP_PAGE_ALLOC_USE_MMAP = false;
+
+#elif defined(__wasm__)
+/* wasmtime does not have proper support for mmap.
+ * See https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-rationale.md#why-no-mmap-and-friends
+ */
+static const bool HEAP_PAGE_ALLOC_USE_MMAP = false;
+
+#elif HAVE_CONST_PAGE_SIZE
+/* If we have the PAGE_SIZE and it is a constant, then we can directly use it. */
+static const bool HEAP_PAGE_ALLOC_USE_MMAP = (PAGE_SIZE <= HEAP_PAGE_SIZE);
+
+#elif defined(PAGE_MAX_SIZE) && (PAGE_MAX_SIZE <= HEAP_PAGE_SIZE)
+/* If we can use the maximum page size. */
+static const bool HEAP_PAGE_ALLOC_USE_MMAP = true;
+
+#elif defined(PAGE_SIZE)
+/* If the PAGE_SIZE macro can be used dynamically. */
+# define INIT_HEAP_PAGE_ALLOC_USE_MMAP (PAGE_SIZE <= HEAP_PAGE_SIZE)
+
+#elif defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
+/* If we can use sysconf to determine the page size. */
+# define INIT_HEAP_PAGE_ALLOC_USE_MMAP (sysconf(_SC_PAGE_SIZE) <= HEAP_PAGE_SIZE)
+
+#else
+/* Otherwise we can't determine the system page size, so don't use mmap. */
+static const bool HEAP_PAGE_ALLOC_USE_MMAP = false;
+#endif
+
+#ifdef INIT_HEAP_PAGE_ALLOC_USE_MMAP
+/* We can determine the system page size at runtime. */
+# define HEAP_PAGE_ALLOC_USE_MMAP (heap_page_alloc_use_mmap != false)
+
+static bool heap_page_alloc_use_mmap;
+#endif
+
+struct heap_page {
+ short slot_size;
+ short total_slots;
+ short free_slots;
+ short final_slots;
+ struct {
+ unsigned int before_sweep : 1;
+ unsigned int has_remembered_objects : 1;
+ unsigned int has_uncollectible_shady_objects : 1;
+ unsigned int in_tomb : 1;
+ } flags;
+
+ rb_size_pool_t *size_pool;
+
+ struct heap_page *free_next;
+ uintptr_t start;
+ RVALUE *freelist;
+ struct ccan_list_node page_node;
+
+ bits_t wb_unprotected_bits[HEAP_PAGE_BITMAP_LIMIT];
+ /* the following three bitmaps are cleared at the beginning of full GC */
+ bits_t mark_bits[HEAP_PAGE_BITMAP_LIMIT];
+ bits_t uncollectible_bits[HEAP_PAGE_BITMAP_LIMIT];
+ bits_t marking_bits[HEAP_PAGE_BITMAP_LIMIT];
+
+ /* If set, the object is not movable */
+ bits_t pinned_bits[HEAP_PAGE_BITMAP_LIMIT];
+};
+
+/*
+ * When asan is enabled, this will prohibit writing to the freelist until it is unlocked
+ */
+static void
+asan_lock_freelist(struct heap_page *page)
{
- return GET_VM()->gc.objspace;
+ asan_poison_memory_region(&page->freelist, sizeof(RVALUE*));
}
-void
-rb_gc_ractor_newobj_cache_foreach(void (*func)(void *cache, void *data), void *data)
+/*
+ * When asan is enabled, this will enable the ability to write to the freelist
+ */
+static void
+asan_unlock_freelist(struct heap_page *page)
+{
+ asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false);
+}
+
+#define GET_PAGE_BODY(x) ((struct heap_page_body *)((bits_t)(x) & ~(HEAP_PAGE_ALIGN_MASK)))
+#define GET_PAGE_HEADER(x) (&GET_PAGE_BODY(x)->header)
+#define GET_HEAP_PAGE(x) (GET_PAGE_HEADER(x)->page)
+
+#define NUM_IN_PAGE(p) (((bits_t)(p) & HEAP_PAGE_ALIGN_MASK) / BASE_SLOT_SIZE)
+#define BITMAP_INDEX(p) (NUM_IN_PAGE(p) / BITS_BITLENGTH )
+#define BITMAP_OFFSET(p) (NUM_IN_PAGE(p) & (BITS_BITLENGTH-1))
+#define BITMAP_BIT(p) ((bits_t)1 << BITMAP_OFFSET(p))
+
+/* Bitmap Operations */
+#define MARKED_IN_BITMAP(bits, p) ((bits)[BITMAP_INDEX(p)] & BITMAP_BIT(p))
+#define MARK_IN_BITMAP(bits, p) ((bits)[BITMAP_INDEX(p)] = (bits)[BITMAP_INDEX(p)] | BITMAP_BIT(p))
+#define CLEAR_IN_BITMAP(bits, p) ((bits)[BITMAP_INDEX(p)] = (bits)[BITMAP_INDEX(p)] & ~BITMAP_BIT(p))
+
+/* getting bitmap */
+#define GET_HEAP_MARK_BITS(x) (&GET_HEAP_PAGE(x)->mark_bits[0])
+#define GET_HEAP_PINNED_BITS(x) (&GET_HEAP_PAGE(x)->pinned_bits[0])
+#define GET_HEAP_UNCOLLECTIBLE_BITS(x) (&GET_HEAP_PAGE(x)->uncollectible_bits[0])
+#define GET_HEAP_WB_UNPROTECTED_BITS(x) (&GET_HEAP_PAGE(x)->wb_unprotected_bits[0])
+#define GET_HEAP_MARKING_BITS(x) (&GET_HEAP_PAGE(x)->marking_bits[0])
+
+#define GC_SWEEP_PAGES_FREEABLE_PER_STEP 3
+
+/* Aliases */
+#define rb_objspace (*rb_objspace_of(GET_VM()))
+#define rb_objspace_of(vm) ((vm)->objspace)
+
+#define ruby_initial_gc_stress gc_params.gc_stress
+
+VALUE *ruby_initial_gc_stress_ptr = &ruby_initial_gc_stress;
+
+#define malloc_limit objspace->malloc_params.limit
+#define malloc_increase objspace->malloc_params.increase
+#define malloc_allocated_size objspace->malloc_params.allocated_size
+#define heap_pages_sorted objspace->heap_pages.sorted
+#define heap_allocated_pages objspace->heap_pages.allocated_pages
+#define heap_pages_sorted_length objspace->heap_pages.sorted_length
+#define heap_pages_lomem objspace->heap_pages.range[0]
+#define heap_pages_himem objspace->heap_pages.range[1]
+#define heap_pages_freeable_pages objspace->heap_pages.freeable_pages
+#define heap_pages_final_slots objspace->heap_pages.final_slots
+#define heap_pages_deferred_final objspace->heap_pages.deferred_final
+#define size_pools objspace->size_pools
+#define during_gc objspace->flags.during_gc
+#define finalizing objspace->atomic_flags.finalizing
+#define finalizer_table objspace->finalizer_table
+#define global_list objspace->global_list
+#define ruby_gc_stressful objspace->flags.gc_stressful
+#define ruby_gc_stress_mode objspace->gc_stress_mode
+#if GC_DEBUG_STRESS_TO_CLASS
+#define stress_to_class objspace->stress_to_class
+#else
+#define stress_to_class 0
+#endif
+
+#if 0
+#define dont_gc_on() (fprintf(stderr, "dont_gc_on@%s:%d\n", __FILE__, __LINE__), objspace->flags.dont_gc = 1)
+#define dont_gc_off() (fprintf(stderr, "dont_gc_off@%s:%d\n", __FILE__, __LINE__), objspace->flags.dont_gc = 0)
+#define dont_gc_set(b) (fprintf(stderr, "dont_gc_set(%d)@%s:%d\n", __FILE__, __LINE__), (int)b), objspace->flags.dont_gc = (b))
+#define dont_gc_val() (objspace->flags.dont_gc)
+#else
+#define dont_gc_on() (objspace->flags.dont_gc = 1)
+#define dont_gc_off() (objspace->flags.dont_gc = 0)
+#define dont_gc_set(b) (((int)b), objspace->flags.dont_gc = (b))
+#define dont_gc_val() (objspace->flags.dont_gc)
+#endif
+
+static inline enum gc_mode
+gc_mode_verify(enum gc_mode mode)
{
- rb_ractor_t *r = NULL;
- ccan_list_for_each(&GET_VM()->ractor.set, r, vmlr_node) {
- func(r->newobj_cache, data);
+#if RGENGC_CHECK_MODE > 0
+ switch (mode) {
+ case gc_mode_none:
+ case gc_mode_marking:
+ case gc_mode_sweeping:
+ case gc_mode_compacting:
+ break;
+ default:
+ rb_bug("gc_mode_verify: unreachable (%d)", (int)mode);
}
+#endif
+ return mode;
}
-void
-rb_gc_run_obj_finalizer(VALUE objid, long count, VALUE (*callback)(long i, void *data), void *data)
+static inline bool
+has_sweeping_pages(rb_objspace_t *objspace)
{
- volatile struct {
- VALUE errinfo;
- VALUE final;
- rb_control_frame_t *cfp;
- VALUE *sp;
- long finished;
- } saved;
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ if (SIZE_POOL_EDEN_HEAP(&size_pools[i])->sweeping_page) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
- rb_execution_context_t * volatile ec = GET_EC();
-#define RESTORE_FINALIZER() (\
- ec->cfp = saved.cfp, \
- ec->cfp->sp = saved.sp, \
- ec->errinfo = saved.errinfo)
+static inline size_t
+heap_eden_total_pages(rb_objspace_t *objspace)
+{
+ size_t count = 0;
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ count += SIZE_POOL_EDEN_HEAP(&size_pools[i])->total_pages;
+ }
+ return count;
+}
- saved.errinfo = ec->errinfo;
- saved.cfp = ec->cfp;
- saved.sp = ec->cfp->sp;
- saved.finished = 0;
- saved.final = Qundef;
+static inline size_t
+heap_eden_total_slots(rb_objspace_t *objspace)
+{
+ size_t count = 0;
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ count += SIZE_POOL_EDEN_HEAP(&size_pools[i])->total_slots;
+ }
+ return count;
+}
- EC_PUSH_TAG(ec);
- enum ruby_tag_type state = EC_EXEC_TAG();
- if (state != TAG_NONE) {
- ++saved.finished; /* skip failed finalizer */
+static inline size_t
+heap_tomb_total_pages(rb_objspace_t *objspace)
+{
+ size_t count = 0;
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ count += SIZE_POOL_TOMB_HEAP(&size_pools[i])->total_pages;
+ }
+ return count;
+}
- VALUE failed_final = saved.final;
- saved.final = Qundef;
- if (!UNDEF_P(failed_final) && !NIL_P(ruby_verbose)) {
- rb_warn("Exception in finalizer %+"PRIsVALUE, failed_final);
- rb_ec_error_print(ec, ec->errinfo);
- }
+static inline size_t
+heap_allocatable_pages(rb_objspace_t *objspace)
+{
+ size_t count = 0;
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ count += size_pools[i].allocatable_pages;
}
+ return count;
+}
- for (long i = saved.finished; RESTORE_FINALIZER(), i < count; saved.finished = ++i) {
- saved.final = callback(i, data);
- rb_check_funcall(saved.final, idCall, 1, &objid);
+static inline size_t
+heap_allocatable_slots(rb_objspace_t *objspace)
+{
+ size_t count = 0;
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ int slot_size_multiple = size_pool->slot_size / BASE_SLOT_SIZE;
+ count += size_pool->allocatable_pages * HEAP_PAGE_OBJ_LIMIT / slot_size_multiple;
}
- EC_POP_TAG();
-#undef RESTORE_FINALIZER
+ return count;
}
-void
-rb_gc_set_pending_interrupt(void)
+static inline size_t
+total_allocated_pages(rb_objspace_t *objspace)
{
- rb_execution_context_t *ec = GET_EC();
- ec->interrupt_mask |= PENDING_INTERRUPT_MASK;
+ size_t count = 0;
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ count += size_pool->total_allocated_pages;
+ }
+ return count;
}
-void
-rb_gc_unset_pending_interrupt(void)
+static inline size_t
+total_freed_pages(rb_objspace_t *objspace)
{
- rb_execution_context_t *ec = GET_EC();
- ec->interrupt_mask &= ~PENDING_INTERRUPT_MASK;
+ size_t count = 0;
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ count += size_pool->total_freed_pages;
+ }
+ return count;
}
-bool
-rb_gc_multi_ractor_p(void)
+#define gc_mode(objspace) gc_mode_verify((enum gc_mode)(objspace)->flags.mode)
+#define gc_mode_set(objspace, mode) ((objspace)->flags.mode = (unsigned int)gc_mode_verify(mode))
+
+#define is_marking(objspace) (gc_mode(objspace) == gc_mode_marking)
+#define is_sweeping(objspace) (gc_mode(objspace) == gc_mode_sweeping)
+#define is_full_marking(objspace) ((objspace)->flags.during_minor_gc == FALSE)
+#if GC_ENABLE_INCREMENTAL_MARK
+#define is_incremental_marking(objspace) ((objspace)->flags.during_incremental_marking != FALSE)
+#else
+#define is_incremental_marking(objspace) FALSE
+#endif
+#if GC_ENABLE_INCREMENTAL_MARK
+#define will_be_incremental_marking(objspace) ((objspace)->rgengc.need_major_gc != GPR_FLAG_NONE)
+#else
+#define will_be_incremental_marking(objspace) FALSE
+#endif
+#if GC_ENABLE_INCREMENTAL_MARK
+#define GC_INCREMENTAL_SWEEP_SLOT_COUNT 2048
+#endif
+#define is_lazy_sweeping(objspace) (GC_ENABLE_LAZY_SWEEP && has_sweeping_pages(objspace))
+
+#if SIZEOF_LONG == SIZEOF_VOIDP
+# define nonspecial_obj_id(obj) (VALUE)((SIGNED_VALUE)(obj)|FIXNUM_FLAG)
+# define obj_id_to_ref(objid) ((objid) ^ FIXNUM_FLAG) /* unset FIXNUM_FLAG */
+#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
+# define nonspecial_obj_id(obj) LL2NUM((SIGNED_VALUE)(obj) / 2)
+# define obj_id_to_ref(objid) (FIXNUM_P(objid) ? \
+ ((objid) ^ FIXNUM_FLAG) : (NUM2PTR(objid) << 1))
+#else
+# error not supported
+#endif
+
+#define RANY(o) ((RVALUE*)(o))
+
+struct RZombie {
+ struct RBasic basic;
+ VALUE next;
+ void (*dfree)(void *);
+ void *data;
+};
+
+#define RZOMBIE(o) ((struct RZombie *)(o))
+
+#define nomem_error GET_VM()->special_exceptions[ruby_error_nomemory]
+
+#if RUBY_MARK_FREE_DEBUG
+int ruby_gc_debug_indent = 0;
+#endif
+VALUE rb_mGC;
+int ruby_disable_gc = 0;
+int ruby_enable_autocompact = 0;
+
+void rb_iseq_mark(const rb_iseq_t *iseq);
+void rb_iseq_update_references(rb_iseq_t *iseq);
+void rb_iseq_free(const rb_iseq_t *iseq);
+size_t rb_iseq_memsize(const rb_iseq_t *iseq);
+void rb_vm_update_references(void *ptr);
+
+void rb_gcdebug_print_obj_condition(VALUE obj);
+
+static VALUE define_final0(VALUE obj, VALUE block);
+
+NORETURN(static void *gc_vraise(void *ptr));
+NORETURN(static void gc_raise(VALUE exc, const char *fmt, ...));
+NORETURN(static void negative_size_allocation_error(const char *));
+
+static void init_mark_stack(mark_stack_t *stack);
+
+static int ready_to_gc(rb_objspace_t *objspace);
+
+static int garbage_collect(rb_objspace_t *, unsigned int reason);
+
+static int gc_start(rb_objspace_t *objspace, unsigned int reason);
+static void gc_rest(rb_objspace_t *objspace);
+
+enum gc_enter_event {
+ gc_enter_event_start,
+ gc_enter_event_mark_continue,
+ gc_enter_event_sweep_continue,
+ gc_enter_event_rest,
+ gc_enter_event_finalizer,
+ gc_enter_event_rb_memerror,
+};
+
+static inline void gc_enter(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_lev);
+static inline void gc_exit(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_lev);
+
+static void gc_marks(rb_objspace_t *objspace, int full_mark);
+static void gc_marks_start(rb_objspace_t *objspace, int full);
+static void gc_marks_finish(rb_objspace_t *objspace);
+static void gc_marks_rest(rb_objspace_t *objspace);
+static void gc_marks_continue(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap);
+
+static void gc_sweep(rb_objspace_t *objspace);
+static void gc_sweep_start(rb_objspace_t *objspace);
+#if USE_RVARGC
+static void gc_sweep_finish_size_pool(rb_objspace_t *objspace, rb_size_pool_t *size_pool);
+#endif
+static void gc_sweep_finish(rb_objspace_t *objspace);
+static int gc_sweep_step(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap);
+static void gc_sweep_rest(rb_objspace_t *objspace);
+static void gc_sweep_continue(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap);
+
+static inline void gc_mark(rb_objspace_t *objspace, VALUE ptr);
+static inline void gc_pin(rb_objspace_t *objspace, VALUE ptr);
+static inline void gc_mark_and_pin(rb_objspace_t *objspace, VALUE ptr);
+static void gc_mark_ptr(rb_objspace_t *objspace, VALUE ptr);
+NO_SANITIZE("memory", static void gc_mark_maybe(rb_objspace_t *objspace, VALUE ptr));
+static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr);
+
+static int gc_mark_stacked_objects_incremental(rb_objspace_t *, size_t count);
+static int gc_mark_stacked_objects_all(rb_objspace_t *);
+static void gc_grey(rb_objspace_t *objspace, VALUE ptr);
+
+static inline int gc_mark_set(rb_objspace_t *objspace, VALUE obj);
+NO_SANITIZE("memory", static inline int is_pointer_to_heap(rb_objspace_t *objspace, void *ptr));
+
+static void push_mark_stack(mark_stack_t *, VALUE);
+static int pop_mark_stack(mark_stack_t *, VALUE *);
+static size_t mark_stack_size(mark_stack_t *stack);
+static void shrink_stack_chunk_cache(mark_stack_t *stack);
+
+static size_t obj_memsize_of(VALUE obj, int use_all_types);
+static void gc_verify_internal_consistency(rb_objspace_t *objspace);
+static int gc_verify_heap_page(rb_objspace_t *objspace, struct heap_page *page, VALUE obj);
+static int gc_verify_heap_pages(rb_objspace_t *objspace);
+
+static void gc_stress_set(rb_objspace_t *objspace, VALUE flag);
+static VALUE gc_disable_no_rest(rb_objspace_t *);
+
+static double getrusage_time(void);
+static inline void gc_prof_setup_new_record(rb_objspace_t *objspace, unsigned int reason);
+static inline void gc_prof_timer_start(rb_objspace_t *);
+static inline void gc_prof_timer_stop(rb_objspace_t *);
+static inline void gc_prof_mark_timer_start(rb_objspace_t *);
+static inline void gc_prof_mark_timer_stop(rb_objspace_t *);
+static inline void gc_prof_sweep_timer_start(rb_objspace_t *);
+static inline void gc_prof_sweep_timer_stop(rb_objspace_t *);
+static inline void gc_prof_set_malloc_info(rb_objspace_t *);
+static inline void gc_prof_set_heap_info(rb_objspace_t *);
+
+#define TYPED_UPDATE_IF_MOVED(_objspace, _type, _thing) do { \
+ if (gc_object_moved_p((_objspace), (VALUE)(_thing))) { \
+ *(_type *)&(_thing) = (_type)RMOVED(_thing)->destination; \
+ } \
+} while (0)
+
+#define UPDATE_IF_MOVED(_objspace, _thing) TYPED_UPDATE_IF_MOVED(_objspace, VALUE, _thing)
+
+#define gc_prof_record(objspace) (objspace)->profile.current_record
+#define gc_prof_enabled(objspace) ((objspace)->profile.run && (objspace)->profile.current_record)
+
+#ifdef HAVE_VA_ARGS_MACRO
+# define gc_report(level, objspace, ...) \
+ if (!RGENGC_DEBUG_ENABLED(level)) {} else gc_report_body(level, objspace, __VA_ARGS__)
+#else
+# define gc_report if (!RGENGC_DEBUG_ENABLED(0)) {} else gc_report_body
+#endif
+PRINTF_ARGS(static void gc_report_body(int level, rb_objspace_t *objspace, const char *fmt, ...), 3, 4);
+static const char *obj_info(VALUE obj);
+static const char *obj_type_name(VALUE obj);
+
+/*
+ * 1 - TSC (H/W Time Stamp Counter)
+ * 2 - getrusage
+ */
+#ifndef TICK_TYPE
+#define TICK_TYPE 1
+#endif
+
+#if USE_TICK_T
+
+#if TICK_TYPE == 1
+/* the following code is only for internal tuning. */
+
+/* Source code to use RDTSC is quoted and modified from
+ * https://www.mcs.anl.gov/~kazutomo/rdtsc.html
+ * written by Kazutomo Yoshii <kazutomo@mcs.anl.gov>
+ */
+
+#if defined(__GNUC__) && defined(__i386__)
+typedef unsigned long long tick_t;
+#define PRItick "llu"
+static inline tick_t
+tick(void)
{
- return rb_multi_ractor_p();
+ unsigned long long int x;
+ __asm__ __volatile__ ("rdtsc" : "=A" (x));
+ return x;
}
-bool rb_obj_is_main_ractor(VALUE gv);
+#elif defined(__GNUC__) && defined(__x86_64__)
+typedef unsigned long long tick_t;
+#define PRItick "llu"
-bool
-rb_gc_shutdown_call_finalizer_p(VALUE obj)
+static __inline__ tick_t
+tick(void)
{
- switch (BUILTIN_TYPE(obj)) {
- case T_DATA:
- if (!ruby_free_at_exit_p() && (!DATA_PTR(obj) || !RDATA(obj)->dfree)) return false;
- if (rb_obj_is_thread(obj)) return false;
- if (rb_obj_is_mutex(obj)) return false;
- if (rb_obj_is_fiber(obj)) return false;
- if (rb_obj_is_main_ractor(obj)) return false;
+ unsigned long hi, lo;
+ __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+ return ((unsigned long long)lo)|( ((unsigned long long)hi)<<32);
+}
- return true;
+#elif defined(__powerpc64__) && GCC_VERSION_SINCE(4,8,0)
+typedef unsigned long long tick_t;
+#define PRItick "llu"
- case T_FILE:
- return true;
+static __inline__ tick_t
+tick(void)
+{
+ unsigned long long val = __builtin_ppc_get_timebase();
+ return val;
+}
- case T_SYMBOL:
- if (RSYMBOL(obj)->fstr &&
- (BUILTIN_TYPE(RSYMBOL(obj)->fstr) == T_NONE ||
- BUILTIN_TYPE(RSYMBOL(obj)->fstr) == T_ZOMBIE)) {
- RSYMBOL(obj)->fstr = 0;
- }
- return true;
+/* Implementation for macOS PPC by @nobu
+ * See: https://github.com/ruby/ruby/pull/5975#discussion_r890045558
+ */
+#elif defined(__POWERPC__) && defined(__APPLE__)
+typedef unsigned long long tick_t;
+#define PRItick "llu"
- case T_NONE:
- return false;
+static __inline__ tick_t
+tick(void)
+{
+ unsigned long int upper, lower, tmp;
+ # define mftbu(r) __asm__ volatile("mftbu %0" : "=r"(r))
+ # define mftb(r) __asm__ volatile("mftb %0" : "=r"(r))
+ do {
+ mftbu(upper);
+ mftb(lower);
+ mftbu(tmp);
+ } while (tmp != upper);
+ return ((tick_t)upper << 32) | lower;
+}
- default:
- return ruby_free_at_exit_p();
- }
+#elif defined(__aarch64__) && defined(__GNUC__)
+typedef unsigned long tick_t;
+#define PRItick "lu"
+
+static __inline__ tick_t
+tick(void)
+{
+ unsigned long val;
+ __asm__ __volatile__ ("mrs %0, cntvct_el0" : "=r" (val));
+ return val;
}
-uint32_t
-rb_gc_get_shape(VALUE obj)
+
+#elif defined(_WIN32) && defined(_MSC_VER)
+#include <intrin.h>
+typedef unsigned __int64 tick_t;
+#define PRItick "llu"
+
+static inline tick_t
+tick(void)
{
- return (uint32_t)rb_shape_get_shape_id(obj);
+ return __rdtsc();
}
-void
-rb_gc_set_shape(VALUE obj, uint32_t shape_id)
+#else /* use clock */
+typedef clock_t tick_t;
+#define PRItick "llu"
+
+static inline tick_t
+tick(void)
{
- rb_shape_set_shape_id(obj, (uint32_t)shape_id);
+ return clock();
}
+#endif /* TSC */
+
+#elif TICK_TYPE == 2
+typedef double tick_t;
+#define PRItick "4.9f"
-uint32_t
-rb_gc_rebuild_shape(VALUE obj, size_t heap_id)
+static inline tick_t
+tick(void)
{
- rb_shape_t *orig_shape = rb_shape_get_shape(obj);
+ return getrusage_time();
+}
+#else /* TICK_TYPE */
+#error "choose tick type"
+#endif /* TICK_TYPE */
- if (rb_shape_obj_too_complex(obj)) return (uint32_t)OBJ_TOO_COMPLEX_SHAPE_ID;
+#define MEASURE_LINE(expr) do { \
+ volatile tick_t start_time = tick(); \
+ volatile tick_t end_time; \
+ expr; \
+ end_time = tick(); \
+ fprintf(stderr, "0\t%"PRItick"\t%s\n", end_time - start_time, #expr); \
+} while (0)
- rb_shape_t *initial_shape = rb_shape_get_shape_by_id((shape_id_t)(heap_id + FIRST_T_OBJECT_SHAPE_ID));
- rb_shape_t *new_shape = rb_shape_traverse_from_new_root(initial_shape, orig_shape);
+#else /* USE_TICK_T */
+#define MEASURE_LINE(expr) expr
+#endif /* USE_TICK_T */
- if (!new_shape) return 0;
+static inline void *
+asan_unpoison_object_temporary(VALUE obj)
+{
+ void *ptr = asan_poisoned_object_p(obj);
+ asan_unpoison_object(obj, false);
+ return ptr;
+}
- return (uint32_t)rb_shape_id(new_shape);
+static inline void *
+asan_poison_object_restore(VALUE obj, void *ptr)
+{
+ if (ptr) {
+ asan_poison_object(obj);
+ }
+ return NULL;
}
-void rb_vm_update_references(void *ptr);
+#define asan_unpoisoning_object(obj) \
+ for (void *poisoned = asan_unpoison_object_temporary(obj), \
+ *unpoisoning = &poisoned; /* flag to loop just once */ \
+ unpoisoning; \
+ unpoisoning = asan_poison_object_restore(obj, poisoned))
-#define rb_setjmp(env) RUBY_SETJMP(env)
-#define rb_jmp_buf rb_jmpbuf_t
-#undef rb_data_object_wrap
+#define FL_CHECK2(name, x, pred) \
+ ((RGENGC_CHECK_MODE && SPECIAL_CONST_P(x)) ? \
+ (rb_bug(name": SPECIAL_CONST (%p)", (void *)(x)), 0) : (pred))
+#define FL_TEST2(x,f) FL_CHECK2("FL_TEST2", x, FL_TEST_RAW((x),(f)) != 0)
+#define FL_SET2(x,f) FL_CHECK2("FL_SET2", x, RBASIC(x)->flags |= (f))
+#define FL_UNSET2(x,f) FL_CHECK2("FL_UNSET2", x, RBASIC(x)->flags &= ~(f))
-#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
-#define MAP_ANONYMOUS MAP_ANON
-#endif
+#define RVALUE_MARK_BITMAP(obj) MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), (obj))
+#define RVALUE_PIN_BITMAP(obj) MARKED_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), (obj))
+#define RVALUE_PAGE_MARKED(page, obj) MARKED_IN_BITMAP((page)->mark_bits, (obj))
-#define unless_objspace(objspace) \
- void *objspace; \
- rb_vm_t *unless_objspace_vm = GET_VM(); \
- if (unless_objspace_vm) objspace = unless_objspace_vm->gc.objspace; \
- else /* return; or objspace will be warned uninitialized */
+#define RVALUE_WB_UNPROTECTED_BITMAP(obj) MARKED_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), (obj))
+#define RVALUE_UNCOLLECTIBLE_BITMAP(obj) MARKED_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS(obj), (obj))
+#define RVALUE_MARKING_BITMAP(obj) MARKED_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), (obj))
-#define RMOVED(obj) ((struct RMoved *)(obj))
+#define RVALUE_PAGE_WB_UNPROTECTED(page, obj) MARKED_IN_BITMAP((page)->wb_unprotected_bits, (obj))
+#define RVALUE_PAGE_UNCOLLECTIBLE(page, obj) MARKED_IN_BITMAP((page)->uncollectible_bits, (obj))
+#define RVALUE_PAGE_MARKING(page, obj) MARKED_IN_BITMAP((page)->marking_bits, (obj))
-#define TYPED_UPDATE_IF_MOVED(_objspace, _type, _thing) do { \
- if (rb_gc_impl_object_moved_p((_objspace), (VALUE)(_thing))) { \
- *(_type *)&(_thing) = (_type)rb_gc_impl_location(_objspace, (VALUE)_thing); \
- } \
-} while (0)
+#define RVALUE_OLD_AGE 3
+#define RVALUE_AGE_SHIFT 5 /* FL_PROMOTED0 bit */
-#define UPDATE_IF_MOVED(_objspace, _thing) TYPED_UPDATE_IF_MOVED(_objspace, VALUE, _thing)
+static int rgengc_remembered(rb_objspace_t *objspace, VALUE obj);
+static int rgengc_remembered_sweep(rb_objspace_t *objspace, VALUE obj);
+static int rgengc_remember(rb_objspace_t *objspace, VALUE obj);
+static void rgengc_mark_and_rememberset_clear(rb_objspace_t *objspace, rb_heap_t *heap);
+static void rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap);
-#if RUBY_MARK_FREE_DEBUG
-int ruby_gc_debug_indent = 0;
-#endif
+static inline int
+RVALUE_FLAGS_AGE(VALUE flags)
+{
+ return (int)((flags & (FL_PROMOTED0 | FL_PROMOTED1)) >> RVALUE_AGE_SHIFT);
+}
-#ifndef RGENGC_OBJ_INFO
-# define RGENGC_OBJ_INFO RGENGC_CHECK_MODE
-#endif
+static int
+check_rvalue_consistency_force(const VALUE obj, int terminate)
+{
+ int err = 0;
+ rb_objspace_t *objspace = &rb_objspace;
-#ifndef CALC_EXACT_MALLOC_SIZE
-# define CALC_EXACT_MALLOC_SIZE 0
-#endif
+ RB_VM_LOCK_ENTER_NO_BARRIER();
+ {
+ if (SPECIAL_CONST_P(obj)) {
+ fprintf(stderr, "check_rvalue_consistency: %p is a special const.\n", (void *)obj);
+ err++;
+ }
+ else if (!is_pointer_to_heap(objspace, (void *)obj)) {
+ /* check if it is in tomb_pages */
+ struct heap_page *page = NULL;
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ ccan_list_for_each(&size_pool->tomb_heap.pages, page, page_node) {
+ if (page->start <= (uintptr_t)obj &&
+ (uintptr_t)obj < (page->start + (page->total_slots * size_pool->slot_size))) {
+ fprintf(stderr, "check_rvalue_consistency: %p is in a tomb_heap (%p).\n",
+ (void *)obj, (void *)page);
+ err++;
+ goto skip;
+ }
+ }
+ }
+ bp();
+ fprintf(stderr, "check_rvalue_consistency: %p is not a Ruby object.\n", (void *)obj);
+ err++;
+ skip:
+ ;
+ }
+ else {
+ const int wb_unprotected_bit = RVALUE_WB_UNPROTECTED_BITMAP(obj) != 0;
+ const int uncollectible_bit = RVALUE_UNCOLLECTIBLE_BITMAP(obj) != 0;
+ const int mark_bit = RVALUE_MARK_BITMAP(obj) != 0;
+ const int marking_bit = RVALUE_MARKING_BITMAP(obj) != 0, remembered_bit = marking_bit;
+ const int age = RVALUE_FLAGS_AGE(RBASIC(obj)->flags);
+
+ if (GET_HEAP_PAGE(obj)->flags.in_tomb) {
+ fprintf(stderr, "check_rvalue_consistency: %s is in tomb page.\n", obj_info(obj));
+ err++;
+ }
+ if (BUILTIN_TYPE(obj) == T_NONE) {
+ fprintf(stderr, "check_rvalue_consistency: %s is T_NONE.\n", obj_info(obj));
+ err++;
+ }
+ if (BUILTIN_TYPE(obj) == T_ZOMBIE) {
+ fprintf(stderr, "check_rvalue_consistency: %s is T_ZOMBIE.\n", obj_info(obj));
+ err++;
+ }
-VALUE rb_mGC;
+ obj_memsize_of((VALUE)obj, FALSE);
-static size_t malloc_offset = 0;
-#if defined(HAVE_MALLOC_USABLE_SIZE)
-static size_t
-gc_compute_malloc_offset(void)
-{
- // Different allocators use different metadata storage strategies which result in different
- // ideal sizes.
- // For instance malloc(64) will waste 8B with glibc, but waste 0B with jemalloc.
- // But malloc(56) will waste 0B with glibc, but waste 8B with jemalloc.
- // So we try allocating 64, 56 and 48 bytes and select the first offset that doesn't
- // waste memory.
- // This was tested on Linux with glibc 2.35 and jemalloc 5, and for both it result in
- // no wasted memory.
- size_t offset = 0;
- for (offset = 0; offset <= 16; offset += 8) {
- size_t allocated = (64 - offset);
- void *test_ptr = malloc(allocated);
- size_t wasted = malloc_usable_size(test_ptr) - allocated;
- free(test_ptr);
-
- if (wasted == 0) {
- return offset;
+ /* check generation
+ *
+ * OLD == age == 3 && old-bitmap && mark-bit (except incremental marking)
+ */
+ if (age > 0 && wb_unprotected_bit) {
+ fprintf(stderr, "check_rvalue_consistency: %s is not WB protected, but age is %d > 0.\n", obj_info(obj), age);
+ err++;
+ }
+
+ if (!is_marking(objspace) && uncollectible_bit && !mark_bit) {
+ fprintf(stderr, "check_rvalue_consistency: %s is uncollectible, but is not marked while !gc.\n", obj_info(obj));
+ err++;
+ }
+
+ if (!is_full_marking(objspace)) {
+ if (uncollectible_bit && age != RVALUE_OLD_AGE && !wb_unprotected_bit) {
+ fprintf(stderr, "check_rvalue_consistency: %s is uncollectible, but not old (age: %d) and not WB unprotected.\n",
+ obj_info(obj), age);
+ err++;
+ }
+ if (remembered_bit && age != RVALUE_OLD_AGE) {
+ fprintf(stderr, "check_rvalue_consistency: %s is remembered, but not old (age: %d).\n",
+ obj_info(obj), age);
+ err++;
+ }
+ }
+
+ /*
+ * check coloring
+ *
+ * marking:false marking:true
+ * marked:false white *invalid*
+ * marked:true black grey
+ */
+ if (is_incremental_marking(objspace) && marking_bit) {
+ if (!is_marking(objspace) && !mark_bit) {
+ fprintf(stderr, "check_rvalue_consistency: %s is marking, but not marked.\n", obj_info(obj));
+ err++;
+ }
+ }
}
}
- return 0;
+ RB_VM_LOCK_LEAVE_NO_BARRIER();
+
+ if (err > 0 && terminate) {
+ rb_bug("check_rvalue_consistency_force: there is %d errors.", err);
+ }
+ return err;
+}
+
+#if RGENGC_CHECK_MODE == 0
+static inline VALUE
+check_rvalue_consistency(const VALUE obj)
+{
+ return obj;
}
#else
-static size_t
-gc_compute_malloc_offset(void)
+static VALUE
+check_rvalue_consistency(const VALUE obj)
{
- // If we don't have malloc_usable_size, we use powers of 2.
- return 0;
+ check_rvalue_consistency_force(obj, TRUE);
+ return obj;
}
#endif
-size_t
-rb_malloc_grow_capa(size_t current, size_t type_size)
+static inline int
+gc_object_moved_p(rb_objspace_t * objspace, VALUE obj)
{
- size_t current_capacity = current;
- if (current_capacity < 4) {
- current_capacity = 4;
+ if (RB_SPECIAL_CONST_P(obj)) {
+ return FALSE;
}
- current_capacity *= type_size;
+ else {
+ void *poisoned = asan_unpoison_object_temporary(obj);
+
+ int ret = BUILTIN_TYPE(obj) == T_MOVED;
+ /* Re-poison slot if it's not the one we want */
+ if (poisoned) {
+ GC_ASSERT(BUILTIN_TYPE(obj) == T_NONE);
+ asan_poison_object(obj);
+ }
+ return ret;
+ }
+}
+
+static inline int
+RVALUE_MARKED(VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ return RVALUE_MARK_BITMAP(obj) != 0;
+}
- // We double the current capacity.
- size_t new_capacity = (current_capacity * 2);
+static inline int
+RVALUE_PINNED(VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ return RVALUE_PIN_BITMAP(obj) != 0;
+}
+
+static inline int
+RVALUE_WB_UNPROTECTED(VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ return RVALUE_WB_UNPROTECTED_BITMAP(obj) != 0;
+}
+
+static inline int
+RVALUE_MARKING(VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ return RVALUE_MARKING_BITMAP(obj) != 0;
+}
+
+static inline int
+RVALUE_REMEMBERED(VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ return RVALUE_MARKING_BITMAP(obj) != 0;
+}
- // And round up to the next power of 2 if it's not already one.
- if (rb_popcount64(new_capacity) != 1) {
- new_capacity = (size_t)(1 << (64 - nlz_int64(new_capacity)));
+static inline int
+RVALUE_UNCOLLECTIBLE(VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ return RVALUE_UNCOLLECTIBLE_BITMAP(obj) != 0;
+}
+
+static inline int
+RVALUE_OLD_P_RAW(VALUE obj)
+{
+ const VALUE promoted = FL_PROMOTED0 | FL_PROMOTED1;
+ return (RBASIC(obj)->flags & promoted) == promoted;
+}
+
+static inline int
+RVALUE_OLD_P(VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ return RVALUE_OLD_P_RAW(obj);
+}
+
+#if RGENGC_CHECK_MODE || GC_DEBUG
+static inline int
+RVALUE_AGE(VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ return RVALUE_FLAGS_AGE(RBASIC(obj)->flags);
+}
+#endif
+
+static inline void
+RVALUE_PAGE_OLD_UNCOLLECTIBLE_SET(rb_objspace_t *objspace, struct heap_page *page, VALUE obj)
+{
+ MARK_IN_BITMAP(&page->uncollectible_bits[0], obj);
+ objspace->rgengc.old_objects++;
+ rb_transient_heap_promote(obj);
+
+#if RGENGC_PROFILE >= 2
+ objspace->profile.total_promoted_count++;
+ objspace->profile.promoted_types[BUILTIN_TYPE(obj)]++;
+#endif
+}
+
+static inline void
+RVALUE_OLD_UNCOLLECTIBLE_SET(rb_objspace_t *objspace, VALUE obj)
+{
+ RB_DEBUG_COUNTER_INC(obj_promote);
+ RVALUE_PAGE_OLD_UNCOLLECTIBLE_SET(objspace, GET_HEAP_PAGE(obj), obj);
+}
+
+static inline VALUE
+RVALUE_FLAGS_AGE_SET(VALUE flags, int age)
+{
+ flags &= ~(FL_PROMOTED0 | FL_PROMOTED1);
+ flags |= (age << RVALUE_AGE_SHIFT);
+ return flags;
+}
+
+/* set age to age+1 */
+static inline void
+RVALUE_AGE_INC(rb_objspace_t *objspace, VALUE obj)
+{
+ VALUE flags = RBASIC(obj)->flags;
+ int age = RVALUE_FLAGS_AGE(flags);
+
+ if (RGENGC_CHECK_MODE && age == RVALUE_OLD_AGE) {
+ rb_bug("RVALUE_AGE_INC: can not increment age of OLD object %s.", obj_info(obj));
}
- new_capacity -= malloc_offset;
- new_capacity /= type_size;
- if (current > new_capacity) {
- rb_bug("rb_malloc_grow_capa: current_capacity=%zu, new_capacity=%zu, malloc_offset=%zu", current, new_capacity, malloc_offset);
+ age++;
+ RBASIC(obj)->flags = RVALUE_FLAGS_AGE_SET(flags, age);
+
+ if (age == RVALUE_OLD_AGE) {
+ RVALUE_OLD_UNCOLLECTIBLE_SET(objspace, obj);
}
- RUBY_ASSERT(new_capacity > current);
- return new_capacity;
+ check_rvalue_consistency(obj);
}
-static inline struct rbimpl_size_mul_overflow_tag
-size_add_overflow(size_t x, size_t y)
+/* set age to RVALUE_OLD_AGE */
+static inline void
+RVALUE_AGE_SET_OLD(rb_objspace_t *objspace, VALUE obj)
{
- size_t z;
- bool p;
-#if 0
+ check_rvalue_consistency(obj);
+ GC_ASSERT(!RVALUE_OLD_P(obj));
-#elif defined(ckd_add)
- p = ckd_add(&z, x, y);
+ RBASIC(obj)->flags = RVALUE_FLAGS_AGE_SET(RBASIC(obj)->flags, RVALUE_OLD_AGE);
+ RVALUE_OLD_UNCOLLECTIBLE_SET(objspace, obj);
-#elif __has_builtin(__builtin_add_overflow)
- p = __builtin_add_overflow(x, y, &z);
+ check_rvalue_consistency(obj);
+}
-#elif defined(DSIZE_T)
- RB_GNUC_EXTENSION DSIZE_T dx = x;
- RB_GNUC_EXTENSION DSIZE_T dy = y;
- RB_GNUC_EXTENSION DSIZE_T dz = dx + dy;
- p = dz > SIZE_MAX;
- z = (size_t)dz;
+/* set age to RVALUE_OLD_AGE - 1 */
+static inline void
+RVALUE_AGE_SET_CANDIDATE(rb_objspace_t *objspace, VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ GC_ASSERT(!RVALUE_OLD_P(obj));
-#else
- z = x + y;
- p = z < y;
+ RBASIC(obj)->flags = RVALUE_FLAGS_AGE_SET(RBASIC(obj)->flags, RVALUE_OLD_AGE - 1);
+
+ check_rvalue_consistency(obj);
+}
+
+static inline void
+RVALUE_DEMOTE_RAW(rb_objspace_t *objspace, VALUE obj)
+{
+ RBASIC(obj)->flags = RVALUE_FLAGS_AGE_SET(RBASIC(obj)->flags, 0);
+ CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS(obj), obj);
+}
+
+static inline void
+RVALUE_DEMOTE(rb_objspace_t *objspace, VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ GC_ASSERT(RVALUE_OLD_P(obj));
+
+ if (!is_incremental_marking(objspace) && RVALUE_REMEMBERED(obj)) {
+ CLEAR_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), obj);
+ }
+
+ RVALUE_DEMOTE_RAW(objspace, obj);
+
+ if (RVALUE_MARKED(obj)) {
+ objspace->rgengc.old_objects--;
+ }
+
+ check_rvalue_consistency(obj);
+}
+
+static inline void
+RVALUE_AGE_RESET_RAW(VALUE obj)
+{
+ RBASIC(obj)->flags = RVALUE_FLAGS_AGE_SET(RBASIC(obj)->flags, 0);
+}
+
+static inline void
+RVALUE_AGE_RESET(VALUE obj)
+{
+ check_rvalue_consistency(obj);
+ GC_ASSERT(!RVALUE_OLD_P(obj));
+
+ RVALUE_AGE_RESET_RAW(obj);
+ check_rvalue_consistency(obj);
+}
+
+static inline int
+RVALUE_BLACK_P(VALUE obj)
+{
+ return RVALUE_MARKED(obj) && !RVALUE_MARKING(obj);
+}
+#if 0
+static inline int
+RVALUE_GREY_P(VALUE obj)
+{
+ return RVALUE_MARKED(obj) && RVALUE_MARKING(obj);
+}
#endif
- return (struct rbimpl_size_mul_overflow_tag) { p, z, };
+
+static inline int
+RVALUE_WHITE_P(VALUE obj)
+{
+ return RVALUE_MARKED(obj) == FALSE;
}
-static inline struct rbimpl_size_mul_overflow_tag
-size_mul_add_overflow(size_t x, size_t y, size_t z) /* x * y + z */
+/*
+ --------------------------- ObjectSpace -----------------------------
+*/
+
+static inline void *
+calloc1(size_t n)
{
- struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(x, y);
- struct rbimpl_size_mul_overflow_tag u = size_add_overflow(t.right, z);
- return (struct rbimpl_size_mul_overflow_tag) { t.left || u.left, u.right };
+ return calloc(1, n);
}
-static inline struct rbimpl_size_mul_overflow_tag
-size_mul_add_mul_overflow(size_t x, size_t y, size_t z, size_t w) /* x * y + z * w */
+rb_objspace_t *
+rb_objspace_alloc(void)
{
- struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(x, y);
- struct rbimpl_size_mul_overflow_tag u = rbimpl_size_mul_overflow(z, w);
- struct rbimpl_size_mul_overflow_tag v = size_add_overflow(t.right, u.right);
- return (struct rbimpl_size_mul_overflow_tag) { t.left || u.left || v.left, v.right };
+ rb_objspace_t *objspace = calloc1(sizeof(rb_objspace_t));
+ objspace->flags.measure_gc = 1;
+ malloc_limit = gc_params.malloc_limit_min;
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+
+ size_pool->slot_size = (1 << i) * BASE_SLOT_SIZE;
+
+ ccan_list_head_init(&SIZE_POOL_EDEN_HEAP(size_pool)->pages);
+ ccan_list_head_init(&SIZE_POOL_TOMB_HEAP(size_pool)->pages);
+ }
+
+ dont_gc_on();
+
+ return objspace;
}
-PRINTF_ARGS(NORETURN(static void gc_raise(VALUE, const char*, ...)), 2, 3);
+static void free_stack_chunks(mark_stack_t *);
+static void mark_stack_free_cache(mark_stack_t *);
+static void heap_page_free(rb_objspace_t *objspace, struct heap_page *page);
-static inline size_t
-size_mul_or_raise(size_t x, size_t y, VALUE exc)
+void
+rb_objspace_free(rb_objspace_t *objspace)
{
- struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(x, y);
- if (LIKELY(!t.left)) {
- return t.right;
+ if (is_lazy_sweeping(objspace))
+ rb_bug("lazy sweeping underway when freeing object space");
+
+ if (objspace->profile.records) {
+ free(objspace->profile.records);
+ objspace->profile.records = 0;
}
- else if (rb_during_gc()) {
- rb_memerror(); /* or...? */
+
+ if (global_list) {
+ struct gc_list *list, *next;
+ for (list = global_list; list; list = next) {
+ next = list->next;
+ xfree(list);
+ }
+ }
+ if (heap_pages_sorted) {
+ size_t i;
+ for (i = 0; i < heap_allocated_pages; ++i) {
+ heap_page_free(objspace, heap_pages_sorted[i]);
+ }
+ free(heap_pages_sorted);
+ heap_allocated_pages = 0;
+ heap_pages_sorted_length = 0;
+ heap_pages_lomem = 0;
+ heap_pages_himem = 0;
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ SIZE_POOL_EDEN_HEAP(size_pool)->total_pages = 0;
+ SIZE_POOL_EDEN_HEAP(size_pool)->total_slots = 0;
+ }
+ }
+ st_free_table(objspace->id_to_obj_tbl);
+ st_free_table(objspace->obj_to_id_tbl);
+
+ free_stack_chunks(&objspace->mark_stack);
+ mark_stack_free_cache(&objspace->mark_stack);
+
+ free(objspace);
+}
+
+static void
+heap_pages_expand_sorted_to(rb_objspace_t *objspace, size_t next_length)
+{
+ struct heap_page **sorted;
+ size_t size = size_mul_or_raise(next_length, sizeof(struct heap_page *), rb_eRuntimeError);
+
+ gc_report(3, objspace, "heap_pages_expand_sorted: next_length: %"PRIdSIZE", size: %"PRIdSIZE"\n",
+ next_length, size);
+
+ if (heap_pages_sorted_length > 0) {
+ sorted = (struct heap_page **)realloc(heap_pages_sorted, size);
+ if (sorted) heap_pages_sorted = sorted;
}
else {
- gc_raise(
- exc,
- "integer overflow: %"PRIuSIZE
- " * %"PRIuSIZE
- " > %"PRIuSIZE,
- x, y, (size_t)SIZE_MAX);
+ sorted = heap_pages_sorted = (struct heap_page **)malloc(size);
+ }
+
+ if (sorted == 0) {
+ rb_memerror();
}
+
+ heap_pages_sorted_length = next_length;
}
-size_t
-rb_size_mul_or_raise(size_t x, size_t y, VALUE exc)
+static void
+heap_pages_expand_sorted(rb_objspace_t *objspace)
{
- return size_mul_or_raise(x, y, exc);
+ /* usually heap_allocatable_pages + heap_eden->total_pages == heap_pages_sorted_length
+ * because heap_allocatable_pages contains heap_tomb->total_pages (recycle heap_tomb pages).
+ * however, if there are pages which do not have empty slots, then try to create new pages
+ * so that the additional allocatable_pages counts (heap_tomb->total_pages) are added.
+ */
+ size_t next_length = heap_allocatable_pages(objspace);
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ next_length += SIZE_POOL_EDEN_HEAP(size_pool)->total_pages;
+ next_length += SIZE_POOL_TOMB_HEAP(size_pool)->total_pages;
+ }
+
+ if (next_length > heap_pages_sorted_length) {
+ heap_pages_expand_sorted_to(objspace, next_length);
+ }
+
+ GC_ASSERT(heap_allocatable_pages(objspace) + heap_eden_total_pages(objspace) <= heap_pages_sorted_length);
+ GC_ASSERT(heap_allocated_pages <= heap_pages_sorted_length);
}
-static inline size_t
-size_mul_add_or_raise(size_t x, size_t y, size_t z, VALUE exc)
+static void
+size_pool_allocatable_pages_set(rb_objspace_t *objspace, rb_size_pool_t *size_pool, size_t s)
{
- struct rbimpl_size_mul_overflow_tag t = size_mul_add_overflow(x, y, z);
- if (LIKELY(!t.left)) {
- return t.right;
+ size_pool->allocatable_pages = s;
+ heap_pages_expand_sorted(objspace);
+}
+
+static inline void
+heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj)
+{
+ ASSERT_vm_locking();
+
+ RVALUE *p = (RVALUE *)obj;
+
+ asan_unpoison_object(obj, false);
+
+ asan_unlock_freelist(page);
+
+ p->as.free.flags = 0;
+ p->as.free.next = page->freelist;
+ page->freelist = p;
+ asan_lock_freelist(page);
+
+ if (RGENGC_CHECK_MODE &&
+ /* obj should belong to page */
+ !(page->start <= (uintptr_t)obj &&
+ (uintptr_t)obj < ((uintptr_t)page->start + (page->total_slots * page->slot_size)) &&
+ obj % BASE_SLOT_SIZE == 0)) {
+ rb_bug("heap_page_add_freeobj: %p is not rvalue.", (void *)p);
}
- else if (rb_during_gc()) {
- rb_memerror(); /* or...? */
+
+ asan_poison_object(obj);
+ gc_report(3, objspace, "heap_page_add_freeobj: add %p to freelist\n", (void *)obj);
+}
+
+static inline void
+heap_add_freepage(rb_heap_t *heap, struct heap_page *page)
+{
+ asan_unlock_freelist(page);
+ GC_ASSERT(page->free_slots != 0);
+ GC_ASSERT(page->freelist != NULL);
+
+ page->free_next = heap->free_pages;
+ heap->free_pages = page;
+
+ RUBY_DEBUG_LOG("page:%p freelist:%p", (void *)page, (void *)page->freelist);
+
+ asan_lock_freelist(page);
+}
+
+#if GC_ENABLE_INCREMENTAL_MARK
+static inline void
+heap_add_poolpage(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
+{
+ asan_unlock_freelist(page);
+ GC_ASSERT(page->free_slots != 0);
+ GC_ASSERT(page->freelist != NULL);
+
+ page->free_next = heap->pooled_pages;
+ heap->pooled_pages = page;
+ objspace->rincgc.pooled_slots += page->free_slots;
+
+ asan_lock_freelist(page);
+}
+#endif
+
+static void
+heap_unlink_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
+{
+ ccan_list_del(&page->page_node);
+ heap->total_pages--;
+ heap->total_slots -= page->total_slots;
+}
+
+static void rb_aligned_free(void *ptr, size_t size);
+
+static void
+heap_page_body_free(struct heap_page_body *page_body)
+{
+ GC_ASSERT((uintptr_t)page_body % HEAP_PAGE_ALIGN == 0);
+
+ if (HEAP_PAGE_ALLOC_USE_MMAP) {
+#ifdef HAVE_MMAP
+ GC_ASSERT(HEAP_PAGE_SIZE % sysconf(_SC_PAGE_SIZE) == 0);
+ if (munmap(page_body, HEAP_PAGE_SIZE)) {
+ rb_bug("heap_page_body_free: munmap failed");
+ }
+#endif
}
else {
- gc_raise(
- exc,
- "integer overflow: %"PRIuSIZE
- " * %"PRIuSIZE
- " + %"PRIuSIZE
- " > %"PRIuSIZE,
- x, y, z, (size_t)SIZE_MAX);
+ rb_aligned_free(page_body, HEAP_PAGE_SIZE);
}
}
-size_t
-rb_size_mul_add_or_raise(size_t x, size_t y, size_t z, VALUE exc)
+static void
+heap_page_free(rb_objspace_t *objspace, struct heap_page *page)
{
- return size_mul_add_or_raise(x, y, z, exc);
+ heap_allocated_pages--;
+ page->size_pool->total_freed_pages++;
+ heap_page_body_free(GET_PAGE_BODY(page->start));
+ free(page);
}
-static inline size_t
-size_mul_add_mul_or_raise(size_t x, size_t y, size_t z, size_t w, VALUE exc)
+static void
+heap_pages_free_unused_pages(rb_objspace_t *objspace)
{
- struct rbimpl_size_mul_overflow_tag t = size_mul_add_mul_overflow(x, y, z, w);
- if (LIKELY(!t.left)) {
- return t.right;
+ size_t i, j;
+
+ bool has_pages_in_tomb_heap = FALSE;
+ for (i = 0; i < SIZE_POOL_COUNT; i++) {
+ if (!ccan_list_empty(&SIZE_POOL_TOMB_HEAP(&size_pools[i])->pages)) {
+ has_pages_in_tomb_heap = TRUE;
+ break;
+ }
}
- else if (rb_during_gc()) {
- rb_memerror(); /* or...? */
+
+ if (has_pages_in_tomb_heap) {
+ for (i = j = 1; j < heap_allocated_pages; i++) {
+ struct heap_page *page = heap_pages_sorted[i];
+
+ if (page->flags.in_tomb && page->free_slots == page->total_slots) {
+ heap_unlink_page(objspace, SIZE_POOL_TOMB_HEAP(page->size_pool), page);
+ heap_page_free(objspace, page);
+ }
+ else {
+ if (i != j) {
+ heap_pages_sorted[j] = page;
+ }
+ j++;
+ }
+ }
+
+ struct heap_page *hipage = heap_pages_sorted[heap_allocated_pages - 1];
+ uintptr_t himem = (uintptr_t)hipage->start + (hipage->total_slots * hipage->slot_size);
+ GC_ASSERT(himem <= heap_pages_himem);
+ heap_pages_himem = himem;
+
+ GC_ASSERT(j == heap_allocated_pages);
+ }
+}
+
+static struct heap_page_body *
+heap_page_body_allocate(void)
+{
+ struct heap_page_body *page_body;
+
+ if (HEAP_PAGE_ALLOC_USE_MMAP) {
+#ifdef HAVE_MMAP
+ GC_ASSERT(HEAP_PAGE_ALIGN % sysconf(_SC_PAGE_SIZE) == 0);
+
+ char *ptr = mmap(NULL, HEAP_PAGE_ALIGN + HEAP_PAGE_SIZE,
+ PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (ptr == MAP_FAILED) {
+ return NULL;
+ }
+
+ char *aligned = ptr + HEAP_PAGE_ALIGN;
+ aligned -= ((VALUE)aligned & (HEAP_PAGE_ALIGN - 1));
+ GC_ASSERT(aligned > ptr);
+ GC_ASSERT(aligned <= ptr + HEAP_PAGE_ALIGN);
+
+ size_t start_out_of_range_size = aligned - ptr;
+ GC_ASSERT(start_out_of_range_size % sysconf(_SC_PAGE_SIZE) == 0);
+ if (start_out_of_range_size > 0) {
+ if (munmap(ptr, start_out_of_range_size)) {
+ rb_bug("heap_page_body_allocate: munmap failed for start");
+ }
+ }
+
+ size_t end_out_of_range_size = HEAP_PAGE_ALIGN - start_out_of_range_size;
+ GC_ASSERT(end_out_of_range_size % sysconf(_SC_PAGE_SIZE) == 0);
+ if (end_out_of_range_size > 0) {
+ if (munmap(aligned + HEAP_PAGE_SIZE, end_out_of_range_size)) {
+ rb_bug("heap_page_body_allocate: munmap failed for end");
+ }
+ }
+
+ page_body = (struct heap_page_body *)aligned;
+#endif
}
else {
- gc_raise(
- exc,
- "integer overflow: %"PRIdSIZE
- " * %"PRIdSIZE
- " + %"PRIdSIZE
- " * %"PRIdSIZE
- " > %"PRIdSIZE,
- x, y, z, w, (size_t)SIZE_MAX);
+ page_body = rb_aligned_malloc(HEAP_PAGE_ALIGN, HEAP_PAGE_SIZE);
}
+
+ GC_ASSERT((uintptr_t)page_body % HEAP_PAGE_ALIGN == 0);
+
+ return page_body;
}
-#if defined(HAVE_RB_GC_GUARDED_PTR_VAL) && HAVE_RB_GC_GUARDED_PTR_VAL
-/* trick the compiler into thinking a external signal handler uses this */
-volatile VALUE rb_gc_guarded_val;
-volatile VALUE *
-rb_gc_guarded_ptr_val(volatile VALUE *ptr, VALUE val)
+static struct heap_page *
+heap_page_allocate(rb_objspace_t *objspace, rb_size_pool_t *size_pool)
{
- rb_gc_guarded_val = val;
+ uintptr_t start, end, p;
+ struct heap_page *page;
+ uintptr_t hi, lo, mid;
+ size_t stride = size_pool->slot_size;
+ unsigned int limit = (unsigned int)((HEAP_PAGE_SIZE - sizeof(struct heap_page_header)))/(int)stride;
- return ptr;
+ /* assign heap_page body (contains heap_page_header and RVALUEs) */
+ struct heap_page_body *page_body = heap_page_body_allocate();
+ if (page_body == 0) {
+ rb_memerror();
+ }
+
+ /* assign heap_page entry */
+ page = calloc1(sizeof(struct heap_page));
+ if (page == 0) {
+ heap_page_body_free(page_body);
+ rb_memerror();
+ }
+
+ /* adjust obj_limit (object number available in this page) */
+ start = (uintptr_t)((VALUE)page_body + sizeof(struct heap_page_header));
+
+ if (start % BASE_SLOT_SIZE != 0) {
+ int delta = BASE_SLOT_SIZE - (start % BASE_SLOT_SIZE);
+ start = start + delta;
+ GC_ASSERT(NUM_IN_PAGE(start) == 0 || NUM_IN_PAGE(start) == 1);
+
+ /* Find a num in page that is evenly divisible by `stride`.
+ * This is to ensure that objects are aligned with bit planes.
+ * In other words, ensure there are an even number of objects
+ * per bit plane. */
+ if (NUM_IN_PAGE(start) == 1) {
+ start += stride - BASE_SLOT_SIZE;
+ }
+
+ GC_ASSERT(NUM_IN_PAGE(start) * BASE_SLOT_SIZE % stride == 0);
+
+ limit = (HEAP_PAGE_SIZE - (int)(start - (uintptr_t)page_body))/(int)stride;
+ }
+ end = start + (limit * (int)stride);
+
+ /* setup heap_pages_sorted */
+ lo = 0;
+ hi = (uintptr_t)heap_allocated_pages;
+ while (lo < hi) {
+ struct heap_page *mid_page;
+
+ mid = (lo + hi) / 2;
+ mid_page = heap_pages_sorted[mid];
+ if ((uintptr_t)mid_page->start < start) {
+ lo = mid + 1;
+ }
+ else if ((uintptr_t)mid_page->start > start) {
+ hi = mid;
+ }
+ else {
+ rb_bug("same heap page is allocated: %p at %"PRIuVALUE, (void *)page_body, (VALUE)mid);
+ }
+ }
+
+ if (hi < (uintptr_t)heap_allocated_pages) {
+ MEMMOVE(&heap_pages_sorted[hi+1], &heap_pages_sorted[hi], struct heap_page_header*, heap_allocated_pages - hi);
+ }
+
+ heap_pages_sorted[hi] = page;
+
+ heap_allocated_pages++;
+
+ GC_ASSERT(heap_eden_total_pages(objspace) + heap_allocatable_pages(objspace) <= heap_pages_sorted_length);
+ GC_ASSERT(heap_eden_total_pages(objspace) + heap_tomb_total_pages(objspace) == heap_allocated_pages - 1);
+ GC_ASSERT(heap_allocated_pages <= heap_pages_sorted_length);
+
+ size_pool->total_allocated_pages++;
+
+ if (heap_allocated_pages > heap_pages_sorted_length) {
+ rb_bug("heap_page_allocate: allocated(%"PRIdSIZE") > sorted(%"PRIdSIZE")",
+ heap_allocated_pages, heap_pages_sorted_length);
+ }
+
+ if (heap_pages_lomem == 0 || heap_pages_lomem > start) heap_pages_lomem = start;
+ if (heap_pages_himem < end) heap_pages_himem = end;
+
+ page->start = start;
+ page->total_slots = limit;
+ page->slot_size = size_pool->slot_size;
+ page->size_pool = size_pool;
+ page_body->header.page = page;
+
+ for (p = start; p != end; p += stride) {
+ gc_report(3, objspace, "assign_heap_page: %p is added to freelist\n", (void *)p);
+ heap_page_add_freeobj(objspace, page, (VALUE)p);
+ }
+ page->free_slots = limit;
+
+ asan_lock_freelist(page);
+ return page;
}
-#endif
-static const char *obj_type_name(VALUE obj);
-#define RB_AMALGAMATED_DEFAULT_GC
-#include "gc/default.c"
-
-#if USE_SHARED_GC && !defined(HAVE_DLOPEN)
-# error "Shared GC requires dlopen"
-#elif USE_SHARED_GC
-#include <dlfcn.h>
-
-typedef struct gc_function_map {
- // Bootup
- void *(*objspace_alloc)(void);
- void (*objspace_init)(void *objspace_ptr);
- void (*objspace_free)(void *objspace_ptr);
- void *(*ractor_cache_alloc)(void *objspace_ptr);
- void (*ractor_cache_free)(void *objspace_ptr, void *cache);
- void (*set_params)(void *objspace_ptr);
- void (*init)(void);
- size_t *(*heap_sizes)(void *objspace_ptr);
- // Shutdown
- void (*shutdown_free_objects)(void *objspace_ptr);
- // GC
- void (*start)(void *objspace_ptr, bool full_mark, bool immediate_mark, bool immediate_sweep, bool compact);
- bool (*during_gc_p)(void *objspace_ptr);
- void (*prepare_heap)(void *objspace_ptr);
- void (*gc_enable)(void *objspace_ptr);
- void (*gc_disable)(void *objspace_ptr, bool finish_current_gc);
- bool (*gc_enabled_p)(void *objspace_ptr);
- VALUE (*config_get)(void *objpace_ptr);
- VALUE (*config_set)(void *objspace_ptr, VALUE hash);
- void (*stress_set)(void *objspace_ptr, VALUE flag);
- VALUE (*stress_get)(void *objspace_ptr);
- // Object allocation
- VALUE (*new_obj)(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, bool wb_protected, size_t alloc_size);
- size_t (*obj_slot_size)(VALUE obj);
- size_t (*heap_id_for_size)(void *objspace_ptr, size_t size);
- bool (*size_allocatable_p)(size_t size);
- // Malloc
- void *(*malloc)(void *objspace_ptr, size_t size);
- void *(*calloc)(void *objspace_ptr, size_t size);
- void *(*realloc)(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size);
- void (*free)(void *objspace_ptr, void *ptr, size_t old_size);
- void (*adjust_memory_usage)(void *objspace_ptr, ssize_t diff);
- // Marking
- void (*mark)(void *objspace_ptr, VALUE obj);
- void (*mark_and_move)(void *objspace_ptr, VALUE *ptr);
- void (*mark_and_pin)(void *objspace_ptr, VALUE obj);
- void (*mark_maybe)(void *objspace_ptr, VALUE obj);
- void (*mark_weak)(void *objspace_ptr, VALUE *ptr);
- void (*remove_weak)(void *objspace_ptr, VALUE parent_obj, VALUE *ptr);
- // Compaction
- bool (*object_moved_p)(void *objspace_ptr, VALUE obj);
- VALUE (*location)(void *objspace_ptr, VALUE value);
- // Write barriers
- void (*writebarrier)(void *objspace_ptr, VALUE a, VALUE b);
- void (*writebarrier_unprotect)(void *objspace_ptr, VALUE obj);
- void (*writebarrier_remember)(void *objspace_ptr, VALUE obj);
- // Heap walking
- void (*each_objects)(void *objspace_ptr, int (*callback)(void *, void *, size_t, void *), void *data);
- void (*each_object)(void *objspace_ptr, void (*func)(VALUE obj, void *data), void *data);
- // Finalizers
- void (*make_zombie)(void *objspace_ptr, VALUE obj, void (*dfree)(void *), void *data);
- VALUE (*define_finalizer)(void *objspace_ptr, VALUE obj, VALUE block);
- void (*undefine_finalizer)(void *objspace_ptr, VALUE obj);
- void (*copy_finalizer)(void *objspace_ptr, VALUE dest, VALUE obj);
- void (*shutdown_call_finalizer)(void *objspace_ptr);
- // Object ID
- VALUE (*object_id)(void *objspace_ptr, VALUE obj);
- VALUE (*object_id_to_ref)(void *objspace_ptr, VALUE object_id);
- // Statistics
- void (*set_measure_total_time)(void *objspace_ptr, VALUE flag);
- bool (*get_measure_total_time)(void *objspace_ptr);
- unsigned long long (*get_total_time)(void *objspace_ptr);
- size_t (*gc_count)(void *objspace_ptr);
- VALUE (*latest_gc_info)(void *objspace_ptr, VALUE key);
- size_t (*stat)(void *objspace_ptr, VALUE hash_or_sym);
- size_t (*stat_heap)(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym);
- // Miscellaneous
- size_t (*obj_flags)(void *objspace_ptr, VALUE obj, ID* flags, size_t max);
- bool (*pointer_to_heap_p)(void *objspace_ptr, const void *ptr);
- bool (*garbage_object_p)(void *objspace_ptr, VALUE obj);
- void (*set_event_hook)(void *objspace_ptr, const rb_event_flag_t event);
- void (*copy_attributes)(void *objspace_ptr, VALUE dest, VALUE obj);
-} rb_gc_function_map_t;
-
-static rb_gc_function_map_t rb_gc_functions;
-
-# define RUBY_GC_LIBRARY "RUBY_GC_LIBRARY"
-
-static void
-ruby_external_gc_init(void)
-{
- // Assert that the directory path ends with a /
- RUBY_ASSERT_ALWAYS(SHARED_GC_DIR[sizeof(SHARED_GC_DIR) - 2] == '/');
-
- char *gc_so_file = getenv(RUBY_GC_LIBRARY);
-
- char *gc_so_path = NULL;
- void *handle = NULL;
- if (gc_so_file) {
- /* Check to make sure that gc_so_file matches /[\w-_.]+/ so that it does
- * not load a shared object outside of the directory. */
- for (size_t i = 0; i < strlen(gc_so_file); i++) {
- char c = gc_so_file[i];
- if (isalnum(c)) continue;
- switch (c) {
- case '-':
- case '_':
- case '.':
- break;
- default:
- fprintf(stderr, "Only alphanumeric, dash, underscore, and period is allowed in "RUBY_GC_LIBRARY"\n");
- exit(1);
- }
+static struct heap_page *
+heap_page_resurrect(rb_objspace_t *objspace, rb_size_pool_t *size_pool)
+{
+ struct heap_page *page = 0, *next;
+
+ ccan_list_for_each_safe(&SIZE_POOL_TOMB_HEAP(size_pool)->pages, page, next, page_node) {
+ asan_unlock_freelist(page);
+ if (page->freelist != NULL) {
+ heap_unlink_page(objspace, &size_pool->tomb_heap, page);
+ asan_lock_freelist(page);
+ return page;
}
+ }
+
+ return NULL;
+}
+
+static struct heap_page *
+heap_page_create(rb_objspace_t *objspace, rb_size_pool_t *size_pool)
+{
+ struct heap_page *page;
+ const char *method = "recycle";
+
+ size_pool->allocatable_pages--;
+
+ page = heap_page_resurrect(objspace, size_pool);
+
+ if (page == NULL) {
+ page = heap_page_allocate(objspace, size_pool);
+ method = "allocate";
+ }
+ if (0) fprintf(stderr, "heap_page_create: %s - %p, "
+ "heap_allocated_pages: %"PRIdSIZE", "
+ "heap_allocated_pages: %"PRIdSIZE", "
+ "tomb->total_pages: %"PRIdSIZE"\n",
+ method, (void *)page, heap_pages_sorted_length, heap_allocated_pages, SIZE_POOL_TOMB_HEAP(size_pool)->total_pages);
+ return page;
+}
+
+static void
+heap_add_page(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap, struct heap_page *page)
+{
+ /* Adding to eden heap during incremental sweeping is forbidden */
+ GC_ASSERT(!(heap == SIZE_POOL_EDEN_HEAP(size_pool) && heap->sweeping_page));
+ page->flags.in_tomb = (heap == SIZE_POOL_TOMB_HEAP(size_pool));
+ ccan_list_add_tail(&heap->pages, &page->page_node);
+ heap->total_pages++;
+ heap->total_slots += page->total_slots;
+}
- gc_so_path = alloca(strlen(SHARED_GC_DIR) + strlen(gc_so_file) + 1);
- strcpy(gc_so_path, SHARED_GC_DIR);
- strcpy(gc_so_path + strlen(SHARED_GC_DIR), gc_so_file);
+static void
+heap_assign_page(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap)
+{
+ struct heap_page *page = heap_page_create(objspace, size_pool);
+ heap_add_page(objspace, size_pool, heap, page);
+ heap_add_freepage(heap, page);
+}
+
+static void
+heap_add_pages(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap, size_t add)
+{
+ size_t i;
- handle = dlopen(gc_so_path, RTLD_LAZY | RTLD_GLOBAL);
- if (!handle) {
- fprintf(stderr, "ruby_external_gc_init: Shared library %s cannot be opened: %s\n", gc_so_path, dlerror());
- exit(1);
+ size_pool_allocatable_pages_set(objspace, size_pool, add);
+
+ for (i = 0; i < add; i++) {
+ heap_assign_page(objspace, size_pool, heap);
+ }
+
+ GC_ASSERT(size_pool->allocatable_pages == 0);
+}
+
+static size_t
+heap_extend_pages(rb_objspace_t *objspace, rb_size_pool_t *size_pool, size_t free_slots, size_t total_slots, size_t used)
+{
+ double goal_ratio = gc_params.heap_free_slots_goal_ratio;
+ size_t next_used;
+
+ if (goal_ratio == 0.0) {
+ next_used = (size_t)(used * gc_params.growth_factor);
+ }
+ else if (total_slots == 0) {
+ int multiple = size_pool->slot_size / BASE_SLOT_SIZE;
+ next_used = (gc_params.heap_init_slots * multiple) / HEAP_PAGE_OBJ_LIMIT;
+ }
+ else {
+ /* Find `f' where free_slots = f * total_slots * goal_ratio
+ * => f = (total_slots - free_slots) / ((1 - goal_ratio) * total_slots)
+ */
+ double f = (double)(total_slots - free_slots) / ((1 - goal_ratio) * total_slots);
+
+ if (f > gc_params.growth_factor) f = gc_params.growth_factor;
+ if (f < 1.0) f = 1.1;
+
+ next_used = (size_t)(f * used);
+
+ if (0) {
+ fprintf(stderr,
+ "free_slots(%8"PRIuSIZE")/total_slots(%8"PRIuSIZE")=%1.2f,"
+ " G(%1.2f), f(%1.2f),"
+ " used(%8"PRIuSIZE") => next_used(%8"PRIuSIZE")\n",
+ free_slots, total_slots, free_slots/(double)total_slots,
+ goal_ratio, f, used, next_used);
}
}
- rb_gc_function_map_t gc_functions;
+ if (gc_params.growth_max_slots > 0) {
+ size_t max_used = (size_t)(used + gc_params.growth_max_slots/HEAP_PAGE_OBJ_LIMIT);
+ if (next_used > max_used) next_used = max_used;
+ }
-# define load_external_gc_func(name) do { \
- if (handle) { \
- gc_functions.name = dlsym(handle, "rb_gc_impl_" #name); \
- if (!gc_functions.name) { \
- fprintf(stderr, "ruby_external_gc_init: " #name " func not exported by library %s\n", gc_so_path); \
- exit(1); \
- } \
- } \
- else { \
- gc_functions.name = rb_gc_impl_##name; \
+ size_t extend_page_count = next_used - used;
+ /* Extend by at least 1 page. */
+ if (extend_page_count == 0) extend_page_count = 1;
+
+ return extend_page_count;
+}
+
+static int
+heap_increment(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap)
+{
+ if (size_pool->allocatable_pages > 0) {
+ gc_report(1, objspace, "heap_increment: heap_pages_sorted_length: %"PRIdSIZE", "
+ "heap_pages_inc: %"PRIdSIZE", heap->total_pages: %"PRIdSIZE"\n",
+ heap_pages_sorted_length, size_pool->allocatable_pages, heap->total_pages);
+
+ GC_ASSERT(heap_allocatable_pages(objspace) + heap_eden_total_pages(objspace) <= heap_pages_sorted_length);
+ GC_ASSERT(heap_allocated_pages <= heap_pages_sorted_length);
+
+ heap_assign_page(objspace, size_pool, heap);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+gc_continue(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap)
+{
+ /* Continue marking if in incremental marking. */
+ if (heap->free_pages == NULL && is_incremental_marking(objspace)) {
+ gc_marks_continue(objspace, size_pool, heap);
+ }
+
+ /* Continue sweeping if in lazy sweeping or the previous incremental
+ * marking finished and did not yield a free page. */
+ if (heap->free_pages == NULL && is_lazy_sweeping(objspace)) {
+ gc_sweep_continue(objspace, size_pool, heap);
+ }
+}
+
+static void
+heap_prepare(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap)
+{
+ GC_ASSERT(heap->free_pages == NULL);
+
+ /* Continue incremental marking or lazy sweeping, if in any of those steps. */
+ gc_continue(objspace, size_pool, heap);
+
+ /* If we still don't have a free page and not allowed to create a new page,
+ * we should start a new GC cycle. */
+ if (heap->free_pages == NULL &&
+ (will_be_incremental_marking(objspace) ||
+ (heap_increment(objspace, size_pool, heap) == FALSE))) {
+ if (gc_start(objspace, GPR_FLAG_NEWOBJ) == FALSE) {
+ rb_memerror();
+ }
+ else {
+ /* Do steps of incremental marking or lazy sweeping if the GC run permits. */
+ gc_continue(objspace, size_pool, heap);
+
+ /* If we're not incremental marking (e.g. a minor GC) or finished
+ * sweeping and still don't have a free page, then
+ * gc_sweep_finish_size_pool should allow us to create a new page. */
+ if (heap->free_pages == NULL && !heap_increment(objspace, size_pool, heap)) {
+ if (objspace->rgengc.need_major_gc == GPR_FLAG_NONE) {
+ rb_bug("cannot create a new page after GC");
+ }
+ else { // Major GC is required, which will allow us to create new page
+ if (gc_start(objspace, GPR_FLAG_NEWOBJ) == FALSE) {
+ rb_memerror();
+ }
+ else {
+ /* Do steps of incremental marking or lazy sweeping. */
+ gc_continue(objspace, size_pool, heap);
+
+ if (heap->free_pages == NULL &&
+ !heap_increment(objspace, size_pool, heap)) {
+ rb_bug("cannot create a new page after major GC");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ GC_ASSERT(heap->free_pages != NULL);
+}
+
+void
+rb_objspace_set_event_hook(const rb_event_flag_t event)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ objspace->hook_events = event & RUBY_INTERNAL_EVENT_OBJSPACE_MASK;
+ objspace->flags.has_hook = (objspace->hook_events != 0);
+}
+
+static void
+gc_event_hook_body(rb_execution_context_t *ec, rb_objspace_t *objspace, const rb_event_flag_t event, VALUE data)
+{
+ if (UNLIKELY(!ec->cfp)) return;
+ const VALUE *pc = ec->cfp->pc;
+ if (pc && VM_FRAME_RUBYFRAME_P(ec->cfp)) {
+ /* increment PC because source line is calculated with PC-1 */
+ ec->cfp->pc++;
+ }
+ EXEC_EVENT_HOOK(ec, event, ec->cfp->self, 0, 0, 0, data);
+ ec->cfp->pc = pc;
+}
+
+#define gc_event_hook_available_p(objspace) ((objspace)->flags.has_hook)
+#define gc_event_hook_needed_p(objspace, event) ((objspace)->hook_events & (event))
+
+#define gc_event_hook_prep(objspace, event, data, prep) do { \
+ if (UNLIKELY(gc_event_hook_needed_p(objspace, event))) { \
+ prep; \
+ gc_event_hook_body(GET_EC(), (objspace), (event), (data)); \
} \
} while (0)
- // Bootup
- load_external_gc_func(objspace_alloc);
- load_external_gc_func(objspace_init);
- load_external_gc_func(objspace_free);
- load_external_gc_func(ractor_cache_alloc);
- load_external_gc_func(ractor_cache_free);
- load_external_gc_func(set_params);
- load_external_gc_func(init);
- load_external_gc_func(heap_sizes);
- // Shutdown
- load_external_gc_func(shutdown_free_objects);
- // GC
- load_external_gc_func(start);
- load_external_gc_func(during_gc_p);
- load_external_gc_func(prepare_heap);
- load_external_gc_func(gc_enable);
- load_external_gc_func(gc_disable);
- load_external_gc_func(gc_enabled_p);
- load_external_gc_func(config_set);
- load_external_gc_func(config_get);
- load_external_gc_func(stress_set);
- load_external_gc_func(stress_get);
- // Object allocation
- load_external_gc_func(new_obj);
- load_external_gc_func(obj_slot_size);
- load_external_gc_func(heap_id_for_size);
- load_external_gc_func(size_allocatable_p);
- // Malloc
- load_external_gc_func(malloc);
- load_external_gc_func(calloc);
- load_external_gc_func(realloc);
- load_external_gc_func(free);
- load_external_gc_func(adjust_memory_usage);
- // Marking
- load_external_gc_func(mark);
- load_external_gc_func(mark_and_move);
- load_external_gc_func(mark_and_pin);
- load_external_gc_func(mark_maybe);
- load_external_gc_func(mark_weak);
- load_external_gc_func(remove_weak);
- // Compaction
- load_external_gc_func(object_moved_p);
- load_external_gc_func(location);
- // Write barriers
- load_external_gc_func(writebarrier);
- load_external_gc_func(writebarrier_unprotect);
- load_external_gc_func(writebarrier_remember);
- // Heap walking
- load_external_gc_func(each_objects);
- load_external_gc_func(each_object);
- // Finalizers
- load_external_gc_func(make_zombie);
- load_external_gc_func(define_finalizer);
- load_external_gc_func(undefine_finalizer);
- load_external_gc_func(copy_finalizer);
- load_external_gc_func(shutdown_call_finalizer);
- // Object ID
- load_external_gc_func(object_id);
- load_external_gc_func(object_id_to_ref);
- // Statistics
- load_external_gc_func(set_measure_total_time);
- load_external_gc_func(get_measure_total_time);
- load_external_gc_func(get_total_time);
- load_external_gc_func(gc_count);
- load_external_gc_func(latest_gc_info);
- load_external_gc_func(stat);
- load_external_gc_func(stat_heap);
- // Miscellaneous
- load_external_gc_func(obj_flags);
- load_external_gc_func(pointer_to_heap_p);
- load_external_gc_func(garbage_object_p);
- load_external_gc_func(set_event_hook);
- load_external_gc_func(copy_attributes);
-
-# undef load_external_gc_func
-
- rb_gc_functions = gc_functions;
-}
-
-// Bootup
-# define rb_gc_impl_objspace_alloc rb_gc_functions.objspace_alloc
-# define rb_gc_impl_objspace_init rb_gc_functions.objspace_init
-# define rb_gc_impl_objspace_free rb_gc_functions.objspace_free
-# define rb_gc_impl_ractor_cache_alloc rb_gc_functions.ractor_cache_alloc
-# define rb_gc_impl_ractor_cache_free rb_gc_functions.ractor_cache_free
-# define rb_gc_impl_set_params rb_gc_functions.set_params
-# define rb_gc_impl_init rb_gc_functions.init
-# define rb_gc_impl_heap_sizes rb_gc_functions.heap_sizes
-// Shutdown
-# define rb_gc_impl_shutdown_free_objects rb_gc_functions.shutdown_free_objects
-// GC
-# define rb_gc_impl_start rb_gc_functions.start
-# define rb_gc_impl_during_gc_p rb_gc_functions.during_gc_p
-# define rb_gc_impl_prepare_heap rb_gc_functions.prepare_heap
-# define rb_gc_impl_gc_enable rb_gc_functions.gc_enable
-# define rb_gc_impl_gc_disable rb_gc_functions.gc_disable
-# define rb_gc_impl_gc_enabled_p rb_gc_functions.gc_enabled_p
-# define rb_gc_impl_config_get rb_gc_functions.config_get
-# define rb_gc_impl_config_set rb_gc_functions.config_set
-# define rb_gc_impl_stress_set rb_gc_functions.stress_set
-# define rb_gc_impl_stress_get rb_gc_functions.stress_get
-// Object allocation
-# define rb_gc_impl_new_obj rb_gc_functions.new_obj
-# define rb_gc_impl_obj_slot_size rb_gc_functions.obj_slot_size
-# define rb_gc_impl_heap_id_for_size rb_gc_functions.heap_id_for_size
-# define rb_gc_impl_size_allocatable_p rb_gc_functions.size_allocatable_p
-// Malloc
-# define rb_gc_impl_malloc rb_gc_functions.malloc
-# define rb_gc_impl_calloc rb_gc_functions.calloc
-# define rb_gc_impl_realloc rb_gc_functions.realloc
-# define rb_gc_impl_free rb_gc_functions.free
-# define rb_gc_impl_adjust_memory_usage rb_gc_functions.adjust_memory_usage
-// Marking
-# define rb_gc_impl_mark rb_gc_functions.mark
-# define rb_gc_impl_mark_and_move rb_gc_functions.mark_and_move
-# define rb_gc_impl_mark_and_pin rb_gc_functions.mark_and_pin
-# define rb_gc_impl_mark_maybe rb_gc_functions.mark_maybe
-# define rb_gc_impl_mark_weak rb_gc_functions.mark_weak
-# define rb_gc_impl_remove_weak rb_gc_functions.remove_weak
-// Compaction
-# define rb_gc_impl_object_moved_p rb_gc_functions.object_moved_p
-# define rb_gc_impl_location rb_gc_functions.location
-// Write barriers
-# define rb_gc_impl_writebarrier rb_gc_functions.writebarrier
-# define rb_gc_impl_writebarrier_unprotect rb_gc_functions.writebarrier_unprotect
-# define rb_gc_impl_writebarrier_remember rb_gc_functions.writebarrier_remember
-// Heap walking
-# define rb_gc_impl_each_objects rb_gc_functions.each_objects
-# define rb_gc_impl_each_object rb_gc_functions.each_object
-// Finalizers
-# define rb_gc_impl_make_zombie rb_gc_functions.make_zombie
-# define rb_gc_impl_define_finalizer rb_gc_functions.define_finalizer
-# define rb_gc_impl_undefine_finalizer rb_gc_functions.undefine_finalizer
-# define rb_gc_impl_copy_finalizer rb_gc_functions.copy_finalizer
-# define rb_gc_impl_shutdown_call_finalizer rb_gc_functions.shutdown_call_finalizer
-// Object ID
-# define rb_gc_impl_object_id rb_gc_functions.object_id
-# define rb_gc_impl_object_id_to_ref rb_gc_functions.object_id_to_ref
-// Statistics
-# define rb_gc_impl_set_measure_total_time rb_gc_functions.set_measure_total_time
-# define rb_gc_impl_get_measure_total_time rb_gc_functions.get_measure_total_time
-# define rb_gc_impl_get_total_time rb_gc_functions.get_total_time
-# define rb_gc_impl_gc_count rb_gc_functions.gc_count
-# define rb_gc_impl_latest_gc_info rb_gc_functions.latest_gc_info
-# define rb_gc_impl_stat rb_gc_functions.stat
-# define rb_gc_impl_stat_heap rb_gc_functions.stat_heap
-// Miscellaneous
-# define rb_gc_impl_obj_flags rb_gc_functions.obj_flags
-# define rb_gc_impl_pointer_to_heap_p rb_gc_functions.pointer_to_heap_p
-# define rb_gc_impl_garbage_object_p rb_gc_functions.garbage_object_p
-# define rb_gc_impl_set_event_hook rb_gc_functions.set_event_hook
-# define rb_gc_impl_copy_attributes rb_gc_functions.copy_attributes
-#endif
-
-static VALUE initial_stress = Qfalse;
+#define gc_event_hook(objspace, event, data) gc_event_hook_prep(objspace, event, data, (void)0)
-void *
-rb_objspace_alloc(void)
+static inline VALUE
+newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace, VALUE obj)
{
-#if USE_SHARED_GC
- ruby_external_gc_init();
+#if !__has_feature(memory_sanitizer)
+ GC_ASSERT(BUILTIN_TYPE(obj) == T_NONE);
+ GC_ASSERT((flags & FL_WB_PROTECTED) == 0);
+#endif
+ RVALUE *p = RANY(obj);
+ p->as.basic.flags = flags;
+ *((VALUE *)&p->as.basic.klass) = klass;
+
+#if RACTOR_CHECK_MODE
+ rb_ractor_setup_belonging(obj);
#endif
- void *objspace = rb_gc_impl_objspace_alloc();
- ruby_current_vm_ptr->gc.objspace = objspace;
+#if RGENGC_CHECK_MODE
+ p->as.values.v1 = p->as.values.v2 = p->as.values.v3 = 0;
- rb_gc_impl_objspace_init(objspace);
- rb_gc_impl_stress_set(objspace, initial_stress);
+ RB_VM_LOCK_ENTER_NO_BARRIER();
+ {
+ check_rvalue_consistency(obj);
- return objspace;
+ GC_ASSERT(RVALUE_MARKED(obj) == FALSE);
+ GC_ASSERT(RVALUE_MARKING(obj) == FALSE);
+ GC_ASSERT(RVALUE_OLD_P(obj) == FALSE);
+ GC_ASSERT(RVALUE_WB_UNPROTECTED(obj) == FALSE);
+
+ if (flags & FL_PROMOTED1) {
+ if (RVALUE_AGE(obj) != 2) rb_bug("newobj: %s of age (%d) != 2.", obj_info(obj), RVALUE_AGE(obj));
+ }
+ else {
+ if (RVALUE_AGE(obj) > 0) rb_bug("newobj: %s of age (%d) > 0.", obj_info(obj), RVALUE_AGE(obj));
+ }
+ if (rgengc_remembered(objspace, (VALUE)obj)) rb_bug("newobj: %s is remembered.", obj_info(obj));
+ }
+ RB_VM_LOCK_LEAVE_NO_BARRIER();
+#endif
+
+ if (UNLIKELY(wb_protected == FALSE)) {
+ ASSERT_vm_locking();
+ MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), obj);
+ }
+
+ // TODO: make it atomic, or ractor local
+ objspace->total_allocated_objects++;
+
+#if RGENGC_PROFILE
+ if (wb_protected) {
+ objspace->profile.total_generated_normal_object_count++;
+#if RGENGC_PROFILE >= 2
+ objspace->profile.generated_normal_object_count_types[BUILTIN_TYPE(obj)]++;
+#endif
+ }
+ else {
+ objspace->profile.total_generated_shady_object_count++;
+#if RGENGC_PROFILE >= 2
+ objspace->profile.generated_shady_object_count_types[BUILTIN_TYPE(obj)]++;
+#endif
+ }
+#endif
+
+#if GC_DEBUG
+ RANY(obj)->file = rb_source_location_cstr(&RANY(obj)->line);
+ GC_ASSERT(!SPECIAL_CONST_P(obj)); /* check alignment */
+#endif
+
+ gc_report(5, objspace, "newobj: %s\n", obj_info(obj));
+
+#if RGENGC_OLD_NEWOBJ_CHECK > 0
+ {
+ static int newobj_cnt = RGENGC_OLD_NEWOBJ_CHECK;
+
+ if (!is_incremental_marking(objspace) &&
+ flags & FL_WB_PROTECTED && /* do not promote WB unprotected objects */
+ ! RB_TYPE_P(obj, T_ARRAY)) { /* array.c assumes that allocated objects are new */
+ if (--newobj_cnt == 0) {
+ newobj_cnt = RGENGC_OLD_NEWOBJ_CHECK;
+
+ gc_mark_set(objspace, obj);
+ RVALUE_AGE_SET_OLD(objspace, obj);
+
+ rb_gc_writebarrier_remember(obj);
+ }
+ }
+ }
+#endif
+ // RUBY_DEBUG_LOG("obj:%p (%s)", (void *)obj, obj_type_name(obj));
+ return obj;
}
-void
-rb_objspace_free(void *objspace)
+size_t
+rb_gc_obj_slot_size(VALUE obj)
{
- rb_gc_impl_objspace_free(objspace);
+ return GET_HEAP_PAGE(obj)->slot_size - RVALUE_OVERHEAD;
+}
+
+static inline size_t
+size_pool_slot_size(unsigned char pool_id)
+{
+ GC_ASSERT(pool_id < SIZE_POOL_COUNT);
+
+ size_t slot_size = (1 << pool_id) * BASE_SLOT_SIZE;
+
+#if RGENGC_CHECK_MODE
+ rb_objspace_t *objspace = &rb_objspace;
+ GC_ASSERT(size_pools[pool_id].slot_size == (short)slot_size);
+#endif
+
+ slot_size -= RVALUE_OVERHEAD;
+
+ return slot_size;
}
size_t
-rb_gc_obj_slot_size(VALUE obj)
+rb_size_pool_slot_size(unsigned char pool_id)
{
- return rb_gc_impl_obj_slot_size(obj);
+ return size_pool_slot_size(pool_id);
+}
+
+bool
+rb_gc_size_allocatable_p(size_t size)
+{
+ return size <= size_pool_slot_size(SIZE_POOL_COUNT - 1);
}
static inline VALUE
-newobj_of(rb_ractor_t *cr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, bool wb_protected, size_t size)
+ractor_cache_allocate_slot(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache,
+ size_t size_pool_idx)
{
- VALUE obj = rb_gc_impl_new_obj(rb_gc_get_objspace(), cr->newobj_cache, klass, flags, v1, v2, v3, wb_protected, size);
+ rb_ractor_newobj_size_pool_cache_t *size_pool_cache = &cache->size_pool_caches[size_pool_idx];
+ RVALUE *p = size_pool_cache->freelist;
+
+#if GC_ENABLE_INCREMENTAL_MARK
+ if (is_incremental_marking(objspace)) {
+ // Not allowed to allocate without running an incremental marking step
+ if (cache->incremental_mark_step_allocated_slots >= INCREMENTAL_MARK_STEP_ALLOCATIONS) {
+ return Qfalse;
+ }
+
+ if (p) {
+ cache->incremental_mark_step_allocated_slots++;
+ }
+ }
+#endif
- if (UNLIKELY(ruby_vm_event_flags & RUBY_INTERNAL_EVENT_NEWOBJ)) {
+ if (p) {
+ VALUE obj = (VALUE)p;
+ MAYBE_UNUSED(const size_t) stride = size_pool_slot_size(size_pool_idx);
+ size_pool_cache->freelist = p->as.free.next;
+#if USE_RVARGC
+ asan_unpoison_memory_region(p, stride, true);
+#else
+ asan_unpoison_object(obj, true);
+#endif
+#if RGENGC_CHECK_MODE
+ GC_ASSERT(rb_gc_obj_slot_size(obj) == stride);
+ // zero clear
+ MEMZERO((char *)obj, char, stride);
+#endif
+ return obj;
+ }
+ else {
+ return Qfalse;
+ }
+}
+
+static struct heap_page *
+heap_next_free_page(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap)
+{
+ ASSERT_vm_locking();
+
+ struct heap_page *page;
+
+ if (heap->free_pages == NULL) {
+ heap_prepare(objspace, size_pool, heap);
+ }
+
+ page = heap->free_pages;
+ heap->free_pages = page->free_next;
+
+ GC_ASSERT(page->free_slots != 0);
+ RUBY_DEBUG_LOG("page:%p freelist:%p cnt:%d", (void *)page, (void *)page->freelist, page->free_slots);
+
+ asan_unlock_freelist(page);
+
+ return page;
+}
+
+static inline void
+ractor_cache_set_page(rb_ractor_newobj_cache_t *cache, size_t size_pool_idx,
+ struct heap_page *page)
+{
+ gc_report(3, &rb_objspace, "ractor_set_cache: Using page %p\n", (void *)GET_PAGE_BODY(page->start));
+
+ rb_ractor_newobj_size_pool_cache_t *size_pool_cache = &cache->size_pool_caches[size_pool_idx];
+
+ GC_ASSERT(size_pool_cache->freelist == NULL);
+ GC_ASSERT(page->free_slots != 0);
+ GC_ASSERT(page->freelist != NULL);
+
+ size_pool_cache->using_page = page;
+ size_pool_cache->freelist = page->freelist;
+ page->free_slots = 0;
+ page->freelist = NULL;
+
+ asan_unpoison_object((VALUE)size_pool_cache->freelist, false);
+ GC_ASSERT(RB_TYPE_P((VALUE)size_pool_cache->freelist, T_NONE));
+ asan_poison_object((VALUE)size_pool_cache->freelist);
+}
+
+static inline VALUE
+newobj_fill(VALUE obj, VALUE v1, VALUE v2, VALUE v3)
+{
+ RVALUE *p = (RVALUE *)obj;
+ p->as.values.v1 = v1;
+ p->as.values.v2 = v2;
+ p->as.values.v3 = v3;
+ return obj;
+}
+
+static inline size_t
+size_pool_idx_for_size(size_t size)
+{
+#if USE_RVARGC
+ size += RVALUE_OVERHEAD;
+
+ size_t slot_count = CEILDIV(size, BASE_SLOT_SIZE);
+
+ /* size_pool_idx is ceil(log2(slot_count)) */
+ size_t size_pool_idx = 64 - nlz_int64(slot_count - 1);
+
+ if (size_pool_idx >= SIZE_POOL_COUNT) {
+ rb_bug("size_pool_idx_for_size: allocation size too large");
+ }
+
+#if RGENGC_CHECK_MODE
+ rb_objspace_t *objspace = &rb_objspace;
+ GC_ASSERT(size <= (size_t)size_pools[size_pool_idx].slot_size);
+ if (size_pool_idx > 0) GC_ASSERT(size > (size_t)size_pools[size_pool_idx - 1].slot_size);
+#endif
+
+ return size_pool_idx;
+#else
+ GC_ASSERT(size <= sizeof(RVALUE));
+ return 0;
+#endif
+}
+
+static VALUE
+newobj_alloc(rb_objspace_t *objspace, rb_ractor_t *cr, size_t size_pool_idx, bool vm_locked)
+{
+ rb_size_pool_t *size_pool = &size_pools[size_pool_idx];
+ rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
+ rb_ractor_newobj_cache_t *cache = &cr->newobj_cache;
+
+ VALUE obj = ractor_cache_allocate_slot(objspace, cache, size_pool_idx);
+
+ if (UNLIKELY(obj == Qfalse)) {
unsigned int lev;
- RB_VM_LOCK_ENTER_CR_LEV(cr, &lev);
+ bool unlock_vm = false;
+
+ if (!vm_locked) {
+ RB_VM_LOCK_ENTER_CR_LEV(cr, &lev);
+ vm_locked = true;
+ unlock_vm = true;
+ }
+
{
- memset((char *)obj + RVALUE_SIZE, 0, rb_gc_obj_slot_size(obj) - RVALUE_SIZE);
+ ASSERT_vm_locking();
+
+#if GC_ENABLE_INCREMENTAL_MARK
+ if (is_incremental_marking(objspace)) {
+ gc_marks_continue(objspace, size_pool, heap);
+ cache->incremental_mark_step_allocated_slots = 0;
+
+ // Retry allocation after resetting incremental_mark_step_allocated_slots
+ obj = ractor_cache_allocate_slot(objspace, cache, size_pool_idx);
+ }
+#endif
+
+ if (obj == Qfalse) {
+ // Get next free page (possibly running GC)
+ struct heap_page *page = heap_next_free_page(objspace, size_pool, heap);
+ ractor_cache_set_page(cache, size_pool_idx, page);
+
+ // Retry allocation after moving to new page
+ obj = ractor_cache_allocate_slot(objspace, cache, size_pool_idx);
+
+ GC_ASSERT(obj != Qfalse);
+ }
+ }
+
+ if (unlock_vm) {
+ RB_VM_LOCK_LEAVE_CR_LEV(cr, &lev);
+ }
+ }
+
+ return obj;
+}
+
+static void
+newobj_zero_slot(VALUE obj)
+{
+ memset((char *)obj + sizeof(struct RBasic), 0, rb_gc_obj_slot_size(obj) - sizeof(struct RBasic));
+}
+
+ALWAYS_INLINE(static VALUE newobj_slowpath(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_t *cr, int wb_protected, size_t size_pool_idx));
+
+static inline VALUE
+newobj_slowpath(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_t *cr, int wb_protected, size_t size_pool_idx)
+{
+ VALUE obj;
+ unsigned int lev;
+
+ RB_VM_LOCK_ENTER_CR_LEV(cr, &lev);
+ {
+ if (UNLIKELY(during_gc || ruby_gc_stressful)) {
+ if (during_gc) {
+ dont_gc_on();
+ during_gc = 0;
+ rb_bug("object allocation during garbage collection phase");
+ }
- rb_gc_event_hook(obj, RUBY_INTERNAL_EVENT_NEWOBJ);
+ if (ruby_gc_stressful) {
+ if (!garbage_collect(objspace, GPR_FLAG_NEWOBJ)) {
+ rb_memerror();
+ }
+ }
}
- RB_VM_LOCK_LEAVE_CR_LEV(cr, &lev);
+
+ obj = newobj_alloc(objspace, cr, size_pool_idx, true);
+#if SHAPE_IN_BASIC_FLAGS
+ flags |= (VALUE)(size_pool_idx) << SHAPE_FLAG_SHIFT;
+#endif
+ newobj_init(klass, flags, wb_protected, objspace, obj);
+
+ gc_event_hook_prep(objspace, RUBY_INTERNAL_EVENT_NEWOBJ, obj, newobj_zero_slot(obj));
}
+ RB_VM_LOCK_LEAVE_CR_LEV(cr, &lev);
return obj;
}
+NOINLINE(static VALUE newobj_slowpath_wb_protected(VALUE klass, VALUE flags,
+ rb_objspace_t *objspace, rb_ractor_t *cr, size_t size_pool_idx));
+NOINLINE(static VALUE newobj_slowpath_wb_unprotected(VALUE klass, VALUE flags,
+ rb_objspace_t *objspace, rb_ractor_t *cr, size_t size_pool_idx));
+
+static VALUE
+newobj_slowpath_wb_protected(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_t *cr, size_t size_pool_idx)
+{
+ return newobj_slowpath(klass, flags, objspace, cr, TRUE, size_pool_idx);
+}
+
+static VALUE
+newobj_slowpath_wb_unprotected(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_t *cr, size_t size_pool_idx)
+{
+ return newobj_slowpath(klass, flags, objspace, cr, FALSE, size_pool_idx);
+}
+
+static inline VALUE
+newobj_of0(VALUE klass, VALUE flags, int wb_protected, rb_ractor_t *cr, size_t alloc_size)
+{
+ VALUE obj;
+ rb_objspace_t *objspace = &rb_objspace;
+
+ RB_DEBUG_COUNTER_INC(obj_newobj);
+ (void)RB_DEBUG_COUNTER_INC_IF(obj_newobj_wb_unprotected, !wb_protected);
+
+#if GC_DEBUG_STRESS_TO_CLASS
+ if (UNLIKELY(stress_to_class)) {
+ long i, cnt = RARRAY_LEN(stress_to_class);
+ for (i = 0; i < cnt; ++i) {
+ if (klass == RARRAY_AREF(stress_to_class, i)) rb_memerror();
+ }
+ }
+#endif
+
+ size_t size_pool_idx = size_pool_idx_for_size(alloc_size);
+
+ if (!UNLIKELY(during_gc ||
+ ruby_gc_stressful ||
+ gc_event_hook_available_p(objspace)) &&
+ wb_protected) {
+ obj = newobj_alloc(objspace, cr, size_pool_idx, false);
+#if SHAPE_IN_BASIC_FLAGS
+ flags |= (VALUE)size_pool_idx << SHAPE_FLAG_SHIFT;
+#endif
+ newobj_init(klass, flags, wb_protected, objspace, obj);
+ }
+ else {
+ RB_DEBUG_COUNTER_INC(obj_newobj_slowpath);
+
+ obj = wb_protected ?
+ newobj_slowpath_wb_protected(klass, flags, objspace, cr, size_pool_idx) :
+ newobj_slowpath_wb_unprotected(klass, flags, objspace, cr, size_pool_idx);
+ }
+
+ return obj;
+}
+
+static inline VALUE
+newobj_of(VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, int wb_protected, size_t alloc_size)
+{
+ VALUE obj = newobj_of0(klass, flags, wb_protected, GET_RACTOR(), alloc_size);
+ return newobj_fill(obj, v1, v2, v3);
+}
+
+static inline VALUE
+newobj_of_cr(rb_ractor_t *cr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, int wb_protected, size_t alloc_size)
+{
+ VALUE obj = newobj_of0(klass, flags, wb_protected, cr, alloc_size);
+ return newobj_fill(obj, v1, v2, v3);
+}
+
VALUE
rb_wb_unprotected_newobj_of(VALUE klass, VALUE flags, size_t size)
{
GC_ASSERT((flags & FL_WB_PROTECTED) == 0);
- return newobj_of(GET_RACTOR(), klass, flags, 0, 0, 0, FALSE, size);
+ return newobj_of(klass, flags, 0, 0, 0, FALSE, size);
+}
+
+VALUE
+rb_wb_protected_newobj_of(VALUE klass, VALUE flags, size_t size)
+{
+ GC_ASSERT((flags & FL_WB_PROTECTED) == 0);
+ return newobj_of(klass, flags, 0, 0, 0, TRUE, size);
}
VALUE
-rb_wb_protected_newobj_of(rb_execution_context_t *ec, VALUE klass, VALUE flags, size_t size)
+rb_ec_wb_protected_newobj_of(rb_execution_context_t *ec, VALUE klass, VALUE flags, size_t size)
{
GC_ASSERT((flags & FL_WB_PROTECTED) == 0);
- return newobj_of(rb_ec_ractor_ptr(ec), klass, flags, 0, 0, 0, TRUE, size);
+ return newobj_of_cr(rb_ec_ractor_ptr(ec), klass, flags, 0, 0, 0, TRUE, size);
+}
+
+/* for compatibility */
+
+VALUE
+rb_newobj(void)
+{
+ return newobj_of(0, T_NONE, 0, 0, 0, FALSE, RVALUE_SIZE);
+}
+
+static size_t
+rb_obj_embedded_size(uint32_t numiv)
+{
+ return offsetof(struct RObject, as.ary) + (sizeof(VALUE) * numiv);
+}
+
+static VALUE
+rb_class_instance_allocate_internal(VALUE klass, VALUE flags, bool wb_protected)
+{
+ GC_ASSERT((flags & RUBY_T_MASK) == T_OBJECT);
+ GC_ASSERT(flags & ROBJECT_EMBED);
+
+ size_t size;
+#if USE_RVARGC
+ uint32_t index_tbl_num_entries = RCLASS_EXT(klass)->max_iv_count;
+
+ size = rb_obj_embedded_size(index_tbl_num_entries);
+ if (!rb_gc_size_allocatable_p(size)) {
+ size = sizeof(struct RObject);
+ }
+#else
+ size = sizeof(struct RObject);
+#endif
+
+ VALUE obj = newobj_of(klass, flags, 0, 0, 0, wb_protected, size);
+ RUBY_ASSERT(rb_shape_get_shape(obj)->type == SHAPE_ROOT ||
+ rb_shape_get_shape(obj)->type == SHAPE_INITIAL_CAPACITY);
+
+ // Set the shape to the specific T_OBJECT shape which is always
+ // SIZE_POOL_COUNT away from the root shape.
+ ROBJECT_SET_SHAPE_ID(obj, ROBJECT_SHAPE_ID(obj) + SIZE_POOL_COUNT);
+
+#if RUBY_DEBUG
+ RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
+ VALUE *ptr = ROBJECT_IVPTR(obj);
+ for (size_t i = 0; i < ROBJECT_IV_CAPACITY(obj); i++) {
+ ptr[i] = Qundef;
+ }
+#endif
+
+ return obj;
+}
+
+VALUE
+rb_newobj_of(VALUE klass, VALUE flags)
+{
+ if ((flags & RUBY_T_MASK) == T_OBJECT) {
+ return rb_class_instance_allocate_internal(klass, (flags | ROBJECT_EMBED) & ~FL_WB_PROTECTED, flags & FL_WB_PROTECTED);
+ }
+ else {
+ return newobj_of(klass, flags & ~FL_WB_PROTECTED, 0, 0, 0, flags & FL_WB_PROTECTED, RVALUE_SIZE);
+ }
}
#define UNEXPECTED_NODE(func) \
rb_bug(#func"(): GC does not handle T_NODE 0x%x(%p) 0x%"PRIxVALUE, \
BUILTIN_TYPE(obj), (void*)(obj), RBASIC(obj)->flags)
+const char *
+rb_imemo_name(enum imemo_type type)
+{
+ // put no default case to get a warning if an imemo type is missing
+ switch (type) {
+#define IMEMO_NAME(x) case imemo_##x: return #x;
+ IMEMO_NAME(env);
+ IMEMO_NAME(cref);
+ IMEMO_NAME(svar);
+ IMEMO_NAME(throw_data);
+ IMEMO_NAME(ifunc);
+ IMEMO_NAME(memo);
+ IMEMO_NAME(ment);
+ IMEMO_NAME(iseq);
+ IMEMO_NAME(tmpbuf);
+ IMEMO_NAME(ast);
+ IMEMO_NAME(parser_strterm);
+ IMEMO_NAME(callinfo);
+ IMEMO_NAME(callcache);
+ IMEMO_NAME(constcache);
+#undef IMEMO_NAME
+ }
+ return "unknown";
+}
+
+#undef rb_imemo_new
+
+VALUE
+rb_imemo_new(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0)
+{
+ size_t size = RVALUE_SIZE;
+ VALUE flags = T_IMEMO | (type << FL_USHIFT);
+ return newobj_of(v0, flags, v1, v2, v3, TRUE, size);
+}
+
+static VALUE
+rb_imemo_tmpbuf_new(VALUE v1, VALUE v2, VALUE v3, VALUE v0)
+{
+ size_t size = sizeof(struct rb_imemo_tmpbuf_struct);
+ VALUE flags = T_IMEMO | (imemo_tmpbuf << FL_USHIFT);
+ return newobj_of(v0, flags, v1, v2, v3, FALSE, size);
+}
+
+static VALUE
+rb_imemo_tmpbuf_auto_free_maybe_mark_buffer(void *buf, size_t cnt)
+{
+ return rb_imemo_tmpbuf_new((VALUE)buf, 0, (VALUE)cnt, 0);
+}
+
+rb_imemo_tmpbuf_t *
+rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt)
+{
+ return (rb_imemo_tmpbuf_t *)rb_imemo_tmpbuf_new((VALUE)buf, (VALUE)old_heap, (VALUE)cnt, 0);
+}
+
+static size_t
+imemo_memsize(VALUE obj)
+{
+ size_t size = 0;
+ switch (imemo_type(obj)) {
+ case imemo_ment:
+ size += sizeof(RANY(obj)->as.imemo.ment.def);
+ break;
+ case imemo_iseq:
+ size += rb_iseq_memsize((rb_iseq_t *)obj);
+ break;
+ case imemo_env:
+ size += RANY(obj)->as.imemo.env.env_size * sizeof(VALUE);
+ break;
+ case imemo_tmpbuf:
+ size += RANY(obj)->as.imemo.alloc.cnt * sizeof(VALUE);
+ break;
+ case imemo_ast:
+ size += rb_ast_memsize(&RANY(obj)->as.imemo.ast);
+ break;
+ case imemo_cref:
+ case imemo_svar:
+ case imemo_throw_data:
+ case imemo_ifunc:
+ case imemo_memo:
+ case imemo_parser_strterm:
+ break;
+ default:
+ /* unreachable */
+ break;
+ }
+ return size;
+}
+
+#if IMEMO_DEBUG
+VALUE
+rb_imemo_new_debug(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0, const char *file, int line)
+{
+ VALUE memo = rb_imemo_new(type, v1, v2, v3, v0);
+ fprintf(stderr, "memo %p (type: %d) @ %s:%d\n", (void *)memo, imemo_type(memo), file, line);
+ return memo;
+}
+#endif
+
+MJIT_FUNC_EXPORTED VALUE
+rb_class_allocate_instance(VALUE klass)
+{
+ return rb_class_instance_allocate_internal(klass, T_OBJECT | ROBJECT_EMBED, RGENGC_WB_PROTECTED_OBJECT);
+}
+
static inline void
rb_data_object_check(VALUE klass)
{
@@ -936,7 +3117,7 @@ rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FU
{
RUBY_ASSERT_ALWAYS(dfree != (RUBY_DATA_FUNC)1);
if (klass) rb_data_object_check(klass);
- return newobj_of(GET_RACTOR(), klass, T_DATA, (VALUE)dmark, (VALUE)dfree, (VALUE)datap, !dmark, sizeof(struct RTypedData));
+ return newobj_of(klass, T_DATA, (VALUE)dmark, (VALUE)dfree, (VALUE)datap, FALSE, sizeof(struct RTypedData));
}
VALUE
@@ -947,66 +3128,33 @@ rb_data_object_zalloc(VALUE klass, size_t size, RUBY_DATA_FUNC dmark, RUBY_DATA_
return obj;
}
-static VALUE
-typed_data_alloc(VALUE klass, VALUE typed_flag, void *datap, const rb_data_type_t *type, size_t size)
-{
- RBIMPL_NONNULL_ARG(type);
- if (klass) rb_data_object_check(klass);
- bool wb_protected = (type->flags & RUBY_FL_WB_PROTECTED) || !type->function.dmark;
- return newobj_of(GET_RACTOR(), klass, T_DATA, (VALUE)type, 1 | typed_flag, (VALUE)datap, wb_protected, size);
-}
-
VALUE
rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type)
{
- if (UNLIKELY(type->flags & RUBY_TYPED_EMBEDDABLE)) {
- rb_raise(rb_eTypeError, "Cannot wrap an embeddable TypedData");
- }
-
- return typed_data_alloc(klass, 0, datap, type, sizeof(struct RTypedData));
+ RBIMPL_NONNULL_ARG(type);
+ if (klass) rb_data_object_check(klass);
+ return newobj_of(klass, T_DATA, (VALUE)type, (VALUE)1, (VALUE)datap, type->flags & RUBY_FL_WB_PROTECTED, sizeof(struct RTypedData));
}
VALUE
rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type)
{
- if (type->flags & RUBY_TYPED_EMBEDDABLE) {
- if (!(type->flags & RUBY_TYPED_FREE_IMMEDIATELY)) {
- rb_raise(rb_eTypeError, "Embeddable TypedData must be freed immediately");
- }
-
- size_t embed_size = offsetof(struct RTypedData, data) + size;
- if (rb_gc_size_allocatable_p(embed_size)) {
- VALUE obj = typed_data_alloc(klass, TYPED_DATA_EMBEDDED, 0, type, embed_size);
- memset((char *)obj + offsetof(struct RTypedData, data), 0, size);
- return obj;
- }
- }
-
- VALUE obj = typed_data_alloc(klass, 0, NULL, type, sizeof(struct RTypedData));
+ VALUE obj = rb_data_typed_object_wrap(klass, 0, type);
DATA_PTR(obj) = xcalloc(1, size);
return obj;
}
-static size_t
+size_t
rb_objspace_data_type_memsize(VALUE obj)
{
- size_t size = 0;
if (RTYPEDDATA_P(obj)) {
const rb_data_type_t *type = RTYPEDDATA_TYPE(obj);
- const void *ptr = RTYPEDDATA_GET_DATA(obj);
-
- if (RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_EMBEDDABLE && !RTYPEDDATA_EMBEDDED_P(obj)) {
-#ifdef HAVE_MALLOC_USABLE_SIZE
- size += malloc_usable_size((void *)ptr);
-#endif
- }
-
+ const void *ptr = RTYPEDDATA_DATA(obj);
if (ptr && type->function.dsize) {
- size += type->function.dsize(ptr);
+ return type->function.dsize(ptr);
}
}
-
- return size;
+ return 0;
}
const char *
@@ -1020,69 +3168,264 @@ rb_objspace_data_type_name(VALUE obj)
}
}
-static enum rb_id_table_iterator_result
-cvar_table_free_i(VALUE value, void *ctx)
+static int
+ptr_in_page_body_p(const void *ptr, const void *memb)
{
- xfree((void *)value);
- return ID_TABLE_CONTINUE;
+ struct heap_page *page = *(struct heap_page **)memb;
+ uintptr_t p_body = (uintptr_t)GET_PAGE_BODY(page->start);
+
+ if ((uintptr_t)ptr >= p_body) {
+ return (uintptr_t)ptr < (p_body + HEAP_PAGE_SIZE) ? 0 : 1;
+ }
+ else {
+ return -1;
+ }
}
-static inline void
-make_io_zombie(void *objspace, VALUE obj)
+PUREFUNC(static inline struct heap_page * heap_page_for_ptr(rb_objspace_t *objspace, uintptr_t ptr);)
+static inline struct heap_page *
+heap_page_for_ptr(rb_objspace_t *objspace, uintptr_t ptr)
{
- rb_io_t *fptr = RFILE(obj)->fptr;
- rb_gc_impl_make_zombie(objspace, obj, rb_io_fptr_finalize_internal, fptr);
+ struct heap_page **res;
+
+ if (ptr < (uintptr_t)heap_pages_lomem ||
+ ptr > (uintptr_t)heap_pages_himem) {
+ return NULL;
+ }
+
+ res = bsearch((void *)ptr, heap_pages_sorted,
+ (size_t)heap_allocated_pages, sizeof(struct heap_page *),
+ ptr_in_page_body_p);
+
+ if (res) {
+ return *res;
+ }
+ else {
+ return NULL;
+ }
}
-static bool
-rb_data_free(void *objspace, VALUE obj)
+PUREFUNC(static inline int is_pointer_to_heap(rb_objspace_t *objspace, void *ptr);)
+static inline int
+is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)
{
- void *data = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
- if (data) {
- int free_immediately = false;
- void (*dfree)(void *);
+ register uintptr_t p = (uintptr_t)ptr;
+ register struct heap_page *page;
+
+ RB_DEBUG_COUNTER_INC(gc_isptr_trial);
+
+ if (p < heap_pages_lomem || p > heap_pages_himem) return FALSE;
+ RB_DEBUG_COUNTER_INC(gc_isptr_range);
- if (RTYPEDDATA_P(obj)) {
- free_immediately = (RTYPEDDATA(obj)->type->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0;
- dfree = RTYPEDDATA(obj)->type->function.dfree;
+ if (p % BASE_SLOT_SIZE != 0) return FALSE;
+ RB_DEBUG_COUNTER_INC(gc_isptr_align);
+
+ page = heap_page_for_ptr(objspace, (uintptr_t)ptr);
+ if (page) {
+ RB_DEBUG_COUNTER_INC(gc_isptr_maybe);
+ if (page->flags.in_tomb) {
+ return FALSE;
}
else {
- dfree = RDATA(obj)->dfree;
+ if (p < page->start) return FALSE;
+ if (p >= page->start + (page->total_slots * page->slot_size)) return FALSE;
+ if ((NUM_IN_PAGE(p) * BASE_SLOT_SIZE) % page->slot_size != 0) return FALSE;
+
+ return TRUE;
}
+ }
+ return FALSE;
+}
- if (dfree) {
- if (dfree == RUBY_DEFAULT_FREE) {
- if (!RTYPEDDATA_P(obj) || !RTYPEDDATA_EMBEDDED_P(obj)) {
- xfree(data);
- RB_DEBUG_COUNTER_INC(obj_data_xfree);
+static enum rb_id_table_iterator_result
+free_const_entry_i(VALUE value, void *data)
+{
+ rb_const_entry_t *ce = (rb_const_entry_t *)value;
+ xfree(ce);
+ return ID_TABLE_CONTINUE;
+}
+
+void
+rb_free_const_table(struct rb_id_table *tbl)
+{
+ rb_id_table_foreach_values(tbl, free_const_entry_i, 0);
+ rb_id_table_free(tbl);
+}
+
+// alive: if false, target pointers can be freed already.
+// To check it, we need objspace parameter.
+static void
+vm_ccs_free(struct rb_class_cc_entries *ccs, int alive, rb_objspace_t *objspace, VALUE klass)
+{
+ if (ccs->entries) {
+ for (int i=0; i<ccs->len; i++) {
+ const struct rb_callcache *cc = ccs->entries[i].cc;
+ if (!alive) {
+ void *ptr = asan_unpoison_object_temporary((VALUE)cc);
+ // ccs can be free'ed.
+ if (is_pointer_to_heap(objspace, (void *)cc) &&
+ IMEMO_TYPE_P(cc, imemo_callcache) &&
+ cc->klass == klass) {
+ // OK. maybe target cc.
}
- }
- else if (free_immediately) {
- (*dfree)(data);
- if (RTYPEDDATA_TYPE(obj)->flags & RUBY_TYPED_EMBEDDABLE && !RTYPEDDATA_EMBEDDED_P(obj)) {
- xfree(data);
+ else {
+ if (ptr) {
+ asan_poison_object((VALUE)cc);
+ }
+ continue;
+ }
+ if (ptr) {
+ asan_poison_object((VALUE)cc);
}
-
- RB_DEBUG_COUNTER_INC(obj_data_imm_free);
- }
- else {
- rb_gc_impl_make_zombie(rb_gc_get_objspace(), obj, dfree, data);
- RB_DEBUG_COUNTER_INC(obj_data_zombie);
- return FALSE;
}
+ vm_cc_invalidate(cc);
}
- else {
- RB_DEBUG_COUNTER_INC(obj_data_empty);
+ ruby_xfree(ccs->entries);
+ }
+ ruby_xfree(ccs);
+}
+
+void
+rb_vm_ccs_free(struct rb_class_cc_entries *ccs)
+{
+ RB_DEBUG_COUNTER_INC(ccs_free);
+ vm_ccs_free(ccs, TRUE, NULL, Qundef);
+}
+
+struct cc_tbl_i_data {
+ rb_objspace_t *objspace;
+ VALUE klass;
+ bool alive;
+};
+
+static enum rb_id_table_iterator_result
+cc_table_mark_i(ID id, VALUE ccs_ptr, void *data_ptr)
+{
+ struct cc_tbl_i_data *data = data_ptr;
+ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
+ VM_ASSERT(vm_ccs_p(ccs));
+ VM_ASSERT(id == ccs->cme->called_id);
+
+ if (METHOD_ENTRY_INVALIDATED(ccs->cme)) {
+ rb_vm_ccs_free(ccs);
+ return ID_TABLE_DELETE;
+ }
+ else {
+ gc_mark(data->objspace, (VALUE)ccs->cme);
+
+ for (int i=0; i<ccs->len; i++) {
+ VM_ASSERT(data->klass == ccs->entries[i].cc->klass);
+ VM_ASSERT(vm_cc_check_cme(ccs->entries[i].cc, ccs->cme));
+
+ gc_mark(data->objspace, (VALUE)ccs->entries[i].ci);
+ gc_mark(data->objspace, (VALUE)ccs->entries[i].cc);
}
+ return ID_TABLE_CONTINUE;
}
+}
- return true;
+static void
+cc_table_mark(rb_objspace_t *objspace, VALUE klass)
+{
+ struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
+ if (cc_tbl) {
+ struct cc_tbl_i_data data = {
+ .objspace = objspace,
+ .klass = klass,
+ };
+ rb_id_table_foreach(cc_tbl, cc_table_mark_i, &data);
+ }
}
-bool
-rb_gc_obj_free(void *objspace, VALUE obj)
+static enum rb_id_table_iterator_result
+cc_table_free_i(VALUE ccs_ptr, void *data_ptr)
+{
+ struct cc_tbl_i_data *data = data_ptr;
+ struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
+ VM_ASSERT(vm_ccs_p(ccs));
+ vm_ccs_free(ccs, data->alive, data->objspace, data->klass);
+ return ID_TABLE_CONTINUE;
+}
+
+static void
+cc_table_free(rb_objspace_t *objspace, VALUE klass, bool alive)
+{
+ struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
+
+ if (cc_tbl) {
+ struct cc_tbl_i_data data = {
+ .objspace = objspace,
+ .klass = klass,
+ .alive = alive,
+ };
+ rb_id_table_foreach_values(cc_tbl, cc_table_free_i, &data);
+ rb_id_table_free(cc_tbl);
+ }
+}
+
+static enum rb_id_table_iterator_result
+cvar_table_free_i(VALUE value, void * ctx)
+{
+ xfree((void *) value);
+ return ID_TABLE_CONTINUE;
+}
+
+void
+rb_cc_table_free(VALUE klass)
+{
+ cc_table_free(&rb_objspace, klass, TRUE);
+}
+
+static inline void
+make_zombie(rb_objspace_t *objspace, VALUE obj, void (*dfree)(void *), void *data)
+{
+ struct RZombie *zombie = RZOMBIE(obj);
+ zombie->basic.flags = T_ZOMBIE | (zombie->basic.flags & FL_SEEN_OBJ_ID);
+ zombie->dfree = dfree;
+ zombie->data = data;
+ VALUE prev, next = heap_pages_deferred_final;
+ do {
+ zombie->next = prev = next;
+ next = RUBY_ATOMIC_VALUE_CAS(heap_pages_deferred_final, prev, obj);
+ } while (next != prev);
+
+ struct heap_page *page = GET_HEAP_PAGE(obj);
+ page->final_slots++;
+ heap_pages_final_slots++;
+}
+
+static inline void
+make_io_zombie(rb_objspace_t *objspace, VALUE obj)
+{
+ rb_io_t *fptr = RANY(obj)->as.file.fptr;
+ make_zombie(objspace, obj, rb_io_fptr_finalize_internal, fptr);
+}
+
+static void
+obj_free_object_id(rb_objspace_t *objspace, VALUE obj)
+{
+ ASSERT_vm_locking();
+ st_data_t o = (st_data_t)obj, id;
+
+ GC_ASSERT(FL_TEST(obj, FL_SEEN_OBJ_ID));
+ FL_UNSET(obj, FL_SEEN_OBJ_ID);
+
+ if (st_delete(objspace->obj_to_id_tbl, &o, &id)) {
+ GC_ASSERT(id);
+ st_delete(objspace->id_to_obj_tbl, &id, NULL);
+ }
+ else {
+ rb_bug("Object ID seen, but not in mapping table: %s\n", obj_info(obj));
+ }
+}
+
+static int
+obj_free(rb_objspace_t *objspace, VALUE obj)
{
RB_DEBUG_COUNTER_INC(obj_free);
+ // RUBY_DEBUG_LOG("obj:%p (%s)", (void *)obj, obj_type_name(obj));
+
+ gc_event_hook(objspace, RUBY_INTERNAL_EVENT_FREEOBJ, obj);
switch (BUILTIN_TYPE(obj)) {
case T_NIL:
@@ -1100,31 +3443,45 @@ rb_gc_obj_free(void *objspace, VALUE obj)
FL_UNSET(obj, FL_EXIVAR);
}
+ if (FL_TEST(obj, FL_SEEN_OBJ_ID) && !FL_TEST(obj, FL_FINALIZE)) {
+ obj_free_object_id(objspace, obj);
+ }
+
+ if (RVALUE_WB_UNPROTECTED(obj)) CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), obj);
+
+#if RGENGC_CHECK_MODE
+#define CHECK(x) if (x(obj) != FALSE) rb_bug("obj_free: " #x "(%s) != FALSE", obj_info(obj))
+ CHECK(RVALUE_WB_UNPROTECTED);
+ CHECK(RVALUE_MARKED);
+ CHECK(RVALUE_MARKING);
+ CHECK(RVALUE_UNCOLLECTIBLE);
+#undef CHECK
+#endif
+
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
if (rb_shape_obj_too_complex(obj)) {
RB_DEBUG_COUNTER_INC(obj_obj_too_complex);
st_free_table(ROBJECT_IV_HASH(obj));
}
- else if (RBASIC(obj)->flags & ROBJECT_EMBED) {
+ else if (RANY(obj)->as.basic.flags & ROBJECT_EMBED) {
RB_DEBUG_COUNTER_INC(obj_obj_embed);
}
+ else if (ROBJ_TRANSIENT_P(obj)) {
+ RB_DEBUG_COUNTER_INC(obj_obj_transient);
+ }
else {
- xfree(ROBJECT(obj)->as.heap.ivptr);
+ xfree(RANY(obj)->as.object.as.heap.ivptr);
RB_DEBUG_COUNTER_INC(obj_obj_ptr);
}
break;
case T_MODULE:
case T_CLASS:
rb_id_table_free(RCLASS_M_TBL(obj));
- rb_cc_table_free(obj);
- if (rb_shape_obj_too_complex(obj)) {
- st_free_table((st_table *)RCLASS_IVPTR(obj));
- }
- else {
+ cc_table_free(objspace, obj, FALSE);
+ if (RCLASS_IVPTR(obj)) {
xfree(RCLASS_IVPTR(obj));
}
-
if (RCLASS_CONST_TBL(obj)) {
rb_free_const_table(RCLASS_CONST_TBL(obj));
}
@@ -1139,6 +3496,11 @@ rb_gc_obj_free(void *objspace, VALUE obj)
xfree(RCLASS_SUPERCLASSES(obj));
}
+#if SIZE_POOL_COUNT == 1
+ if (RCLASS_EXT(obj))
+ xfree(RCLASS_EXT(obj));
+#endif
+
(void)RB_DEBUG_COUNTER_INC_IF(obj_module_ptr, BUILTIN_TYPE(obj) == T_MODULE);
(void)RB_DEBUG_COUNTER_INC_IF(obj_class_ptr, BUILTIN_TYPE(obj) == T_CLASS);
break;
@@ -1189,21 +3551,70 @@ rb_gc_obj_free(void *objspace, VALUE obj)
RB_DEBUG_COUNTER_INC(obj_hash_st);
}
#endif
+ if (/* RHASH_AR_TABLE_P(obj) */ !FL_TEST_RAW(obj, RHASH_ST_TABLE_FLAG)) {
+ struct ar_table_struct *tab = RHASH(obj)->as.ar;
- rb_hash_free(obj);
+ if (tab) {
+ if (RHASH_TRANSIENT_P(obj)) {
+ RB_DEBUG_COUNTER_INC(obj_hash_transient);
+ }
+ else {
+ ruby_xfree(tab);
+ }
+ }
+ }
+ else {
+ GC_ASSERT(RHASH_ST_TABLE_P(obj));
+ st_free_table(RHASH(obj)->as.st);
+ }
break;
case T_REGEXP:
- if (RREGEXP(obj)->ptr) {
- onig_free(RREGEXP(obj)->ptr);
+ if (RANY(obj)->as.regexp.ptr) {
+ onig_free(RANY(obj)->as.regexp.ptr);
RB_DEBUG_COUNTER_INC(obj_regexp_ptr);
}
break;
case T_DATA:
- if (!rb_data_free(objspace, obj)) return false;
+ if (DATA_PTR(obj)) {
+ int free_immediately = FALSE;
+ void (*dfree)(void *);
+ void *data = DATA_PTR(obj);
+
+ if (RTYPEDDATA_P(obj)) {
+ free_immediately = (RANY(obj)->as.typeddata.type->flags & RUBY_TYPED_FREE_IMMEDIATELY) != 0;
+ dfree = RANY(obj)->as.typeddata.type->function.dfree;
+ if (0 && free_immediately == 0) {
+ /* to expose non-free-immediate T_DATA */
+ fprintf(stderr, "not immediate -> %s\n", RANY(obj)->as.typeddata.type->wrap_struct_name);
+ }
+ }
+ else {
+ dfree = RANY(obj)->as.data.dfree;
+ }
+
+ if (dfree) {
+ if (dfree == RUBY_DEFAULT_FREE) {
+ xfree(data);
+ RB_DEBUG_COUNTER_INC(obj_data_xfree);
+ }
+ else if (free_immediately) {
+ (*dfree)(data);
+ RB_DEBUG_COUNTER_INC(obj_data_imm_free);
+ }
+ else {
+ make_zombie(objspace, obj, dfree, data);
+ RB_DEBUG_COUNTER_INC(obj_data_zombie);
+ return FALSE;
+ }
+ }
+ else {
+ RB_DEBUG_COUNTER_INC(obj_data_empty);
+ }
+ }
break;
case T_MATCH:
- {
- rb_matchext_t *rm = RMATCH_EXT(obj);
+ if (RANY(obj)->as.match.rmatch) {
+ struct rmatch *rm = RANY(obj)->as.match.rmatch;
#if USE_DEBUG_COUNTER
if (rm->regs.num_regs >= 8) {
RB_DEBUG_COUNTER_INC(obj_match_ge8);
@@ -1216,13 +3627,15 @@ rb_gc_obj_free(void *objspace, VALUE obj)
}
#endif
onig_region_free(&rm->regs, 0);
- xfree(rm->char_offset);
+ if (rm->char_offset)
+ xfree(rm->char_offset);
+ xfree(rm);
RB_DEBUG_COUNTER_INC(obj_match_ptr);
}
break;
case T_FILE:
- if (RFILE(obj)->fptr) {
+ if (RANY(obj)->as.file.fptr) {
make_io_zombie(objspace, obj);
RB_DEBUG_COUNTER_INC(obj_file_ptr);
return FALSE;
@@ -1246,9 +3659,12 @@ rb_gc_obj_free(void *objspace, VALUE obj)
rb_id_table_free(RCLASS_CALLABLE_M_TBL(obj));
}
rb_class_remove_subclass_head(obj);
- rb_cc_table_free(obj);
+ cc_table_free(objspace, obj, FALSE);
rb_class_remove_from_module_subclasses(obj);
rb_class_remove_from_super_subclasses(obj);
+#if !RCLASS_EXT_EMBEDDED
+ xfree(RCLASS_EXT(obj));
+#endif
RB_DEBUG_COUNTER_INC(obj_iclass_ptr);
break;
@@ -1273,11 +3689,14 @@ rb_gc_obj_free(void *objspace, VALUE obj)
case T_STRUCT:
if ((RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK) ||
- RSTRUCT(obj)->as.heap.ptr == NULL) {
+ RANY(obj)->as.rstruct.as.heap.ptr == NULL) {
RB_DEBUG_COUNTER_INC(obj_struct_embed);
}
+ else if (RSTRUCT_TRANSIENT_P(obj)) {
+ RB_DEBUG_COUNTER_INC(obj_struct_transient);
+ }
else {
- xfree((void *)RSTRUCT(obj)->as.heap.ptr);
+ xfree((void *)RANY(obj)->as.rstruct.as.heap.ptr);
RB_DEBUG_COUNTER_INC(obj_struct_ptr);
}
break;
@@ -1290,8 +3709,57 @@ rb_gc_obj_free(void *objspace, VALUE obj)
break;
case T_IMEMO:
- rb_imemo_free((VALUE)obj);
- break;
+ switch (imemo_type(obj)) {
+ case imemo_ment:
+ rb_free_method_entry(&RANY(obj)->as.imemo.ment);
+ RB_DEBUG_COUNTER_INC(obj_imemo_ment);
+ break;
+ case imemo_iseq:
+ rb_iseq_free(&RANY(obj)->as.imemo.iseq);
+ RB_DEBUG_COUNTER_INC(obj_imemo_iseq);
+ break;
+ case imemo_env:
+ GC_ASSERT(VM_ENV_ESCAPED_P(RANY(obj)->as.imemo.env.ep));
+ xfree((VALUE *)RANY(obj)->as.imemo.env.env);
+ RB_DEBUG_COUNTER_INC(obj_imemo_env);
+ break;
+ case imemo_tmpbuf:
+ xfree(RANY(obj)->as.imemo.alloc.ptr);
+ RB_DEBUG_COUNTER_INC(obj_imemo_tmpbuf);
+ break;
+ case imemo_ast:
+ rb_ast_free(&RANY(obj)->as.imemo.ast);
+ RB_DEBUG_COUNTER_INC(obj_imemo_ast);
+ break;
+ case imemo_cref:
+ RB_DEBUG_COUNTER_INC(obj_imemo_cref);
+ break;
+ case imemo_svar:
+ RB_DEBUG_COUNTER_INC(obj_imemo_svar);
+ break;
+ case imemo_throw_data:
+ RB_DEBUG_COUNTER_INC(obj_imemo_throw_data);
+ break;
+ case imemo_ifunc:
+ RB_DEBUG_COUNTER_INC(obj_imemo_ifunc);
+ break;
+ case imemo_memo:
+ RB_DEBUG_COUNTER_INC(obj_imemo_memo);
+ break;
+ case imemo_parser_strterm:
+ RB_DEBUG_COUNTER_INC(obj_imemo_parser_strterm);
+ break;
+ case imemo_callinfo:
+ RB_DEBUG_COUNTER_INC(obj_imemo_callinfo);
+ break;
+ case imemo_callcache:
+ RB_DEBUG_COUNTER_INC(obj_imemo_callcache);
+ break;
+ case imemo_constcache:
+ RB_DEBUG_COUNTER_INC(obj_imemo_constcache);
+ break;
+ }
+ return TRUE;
default:
rb_bug("gc_sweep(): unknown data type 0x%x(%p) 0x%"PRIxVALUE,
@@ -1299,27 +3767,272 @@ rb_gc_obj_free(void *objspace, VALUE obj)
}
if (FL_TEST(obj, FL_FINALIZE)) {
- rb_gc_impl_make_zombie(rb_gc_get_objspace(), obj, 0, 0);
+ make_zombie(objspace, obj, 0, 0);
return FALSE;
}
else {
- RBASIC(obj)->flags = 0;
return TRUE;
}
}
+
+#define OBJ_ID_INCREMENT (sizeof(RVALUE) / 2)
+#define OBJ_ID_INITIAL (OBJ_ID_INCREMENT * 2)
+
+static int
+object_id_cmp(st_data_t x, st_data_t y)
+{
+ if (RB_BIGNUM_TYPE_P(x)) {
+ return !rb_big_eql(x, y);
+ }
+ else {
+ return x != y;
+ }
+}
+
+static st_index_t
+object_id_hash(st_data_t n)
+{
+ if (RB_BIGNUM_TYPE_P(n)) {
+ return FIX2LONG(rb_big_hash(n));
+ }
+ else {
+ return st_numhash(n);
+ }
+}
+static const struct st_hash_type object_id_hash_type = {
+ object_id_cmp,
+ object_id_hash,
+};
+
void
-rb_objspace_set_event_hook(const rb_event_flag_t event)
+Init_heap(void)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+
+#if defined(INIT_HEAP_PAGE_ALLOC_USE_MMAP)
+ /* Need to determine if we can use mmap at runtime. */
+ heap_page_alloc_use_mmap = INIT_HEAP_PAGE_ALLOC_USE_MMAP;
+#endif
+
+ objspace->next_object_id = INT2FIX(OBJ_ID_INITIAL);
+ objspace->id_to_obj_tbl = st_init_table(&object_id_hash_type);
+ objspace->obj_to_id_tbl = st_init_numtable();
+
+#if RGENGC_ESTIMATE_OLDMALLOC
+ objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_min;
+#endif
+
+ heap_add_pages(objspace, &size_pools[0], SIZE_POOL_EDEN_HEAP(&size_pools[0]), gc_params.heap_init_slots / HEAP_PAGE_OBJ_LIMIT);
+
+ /* Give other size pools allocatable pages. */
+ for (int i = 1; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ int multiple = size_pool->slot_size / BASE_SLOT_SIZE;
+ size_pool->allocatable_pages = gc_params.heap_init_slots * multiple / HEAP_PAGE_OBJ_LIMIT;
+ }
+ heap_pages_expand_sorted(objspace);
+
+ init_mark_stack(&objspace->mark_stack);
+
+ objspace->profile.invoke_time = getrusage_time();
+ finalizer_table = st_init_numtable();
+}
+
+void
+Init_gc_stress(void)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+
+ gc_stress_set(objspace, ruby_initial_gc_stress);
+}
+
+typedef int each_obj_callback(void *, void *, size_t, void *);
+
+static void objspace_each_objects(rb_objspace_t *objspace, each_obj_callback *callback, void *data, bool protected);
+static void objspace_reachable_objects_from_root(rb_objspace_t *, void (func)(const char *, VALUE, void *), void *);
+
+struct each_obj_data {
+ rb_objspace_t *objspace;
+ bool reenable_incremental;
+
+ each_obj_callback *callback;
+ void *data;
+
+ struct heap_page **pages[SIZE_POOL_COUNT];
+ size_t pages_counts[SIZE_POOL_COUNT];
+};
+
+static VALUE
+objspace_each_objects_ensure(VALUE arg)
{
- rb_gc_impl_set_event_hook(rb_gc_get_objspace(), event);
+ struct each_obj_data *data = (struct each_obj_data *)arg;
+ rb_objspace_t *objspace = data->objspace;
+
+ /* Reenable incremental GC */
+ if (data->reenable_incremental) {
+ objspace->flags.dont_incremental = FALSE;
+ }
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ struct heap_page **pages = data->pages[i];
+ /* pages could be NULL if an error was raised during setup (e.g.
+ * malloc failed due to out of memory). */
+ if (pages) {
+ free(pages);
+ }
+ }
+
+ return Qnil;
}
+static VALUE
+objspace_each_objects_try(VALUE arg)
+{
+ struct each_obj_data *data = (struct each_obj_data *)arg;
+ rb_objspace_t *objspace = data->objspace;
+
+ /* Copy pages from all size_pools to their respective buffers. */
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ size_t size = size_mul_or_raise(SIZE_POOL_EDEN_HEAP(size_pool)->total_pages, sizeof(struct heap_page *), rb_eRuntimeError);
+
+ struct heap_page **pages = malloc(size);
+ if (!pages) rb_memerror();
+
+ /* Set up pages buffer by iterating over all pages in the current eden
+ * heap. This will be a snapshot of the state of the heap before we
+ * call the callback over each page that exists in this buffer. Thus it
+ * is safe for the callback to allocate objects without possibly entering
+ * an infinite loop. */
+ struct heap_page *page = 0;
+ size_t pages_count = 0;
+ ccan_list_for_each(&SIZE_POOL_EDEN_HEAP(size_pool)->pages, page, page_node) {
+ pages[pages_count] = page;
+ pages_count++;
+ }
+ data->pages[i] = pages;
+ data->pages_counts[i] = pages_count;
+ GC_ASSERT(pages_count == SIZE_POOL_EDEN_HEAP(size_pool)->total_pages);
+ }
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ size_t pages_count = data->pages_counts[i];
+ struct heap_page **pages = data->pages[i];
+
+ struct heap_page *page = ccan_list_top(&SIZE_POOL_EDEN_HEAP(size_pool)->pages, struct heap_page, page_node);
+ for (size_t i = 0; i < pages_count; i++) {
+ /* If we have reached the end of the linked list then there are no
+ * more pages, so break. */
+ if (page == NULL) break;
+
+ /* If this page does not match the one in the buffer, then move to
+ * the next page in the buffer. */
+ if (pages[i] != page) continue;
+
+ uintptr_t pstart = (uintptr_t)page->start;
+ uintptr_t pend = pstart + (page->total_slots * size_pool->slot_size);
+
+ if (!__asan_region_is_poisoned((void *)pstart, pend - pstart) &&
+ (*data->callback)((void *)pstart, (void *)pend, size_pool->slot_size, data->data)) {
+ break;
+ }
+
+ page = ccan_list_next(&SIZE_POOL_EDEN_HEAP(size_pool)->pages, page, page_node);
+ }
+ }
+
+ return Qnil;
+}
+
+/*
+ * rb_objspace_each_objects() is special C API to walk through
+ * Ruby object space. This C API is too difficult to use it.
+ * To be frank, you should not use it. Or you need to read the
+ * source code of this function and understand what this function does.
+ *
+ * 'callback' will be called several times (the number of heap page,
+ * at current implementation) with:
+ * vstart: a pointer to the first living object of the heap_page.
+ * vend: a pointer to next to the valid heap_page area.
+ * stride: a distance to next VALUE.
+ *
+ * If callback() returns non-zero, the iteration will be stopped.
+ *
+ * This is a sample callback code to iterate liveness objects:
+ *
+ * int
+ * sample_callback(void *vstart, void *vend, int stride, void *data) {
+ * VALUE v = (VALUE)vstart;
+ * for (; v != (VALUE)vend; v += stride) {
+ * if (RBASIC(v)->flags) { // liveness check
+ * // do something with live object 'v'
+ * }
+ * return 0; // continue to iteration
+ * }
+ *
+ * Note: 'vstart' is not a top of heap_page. This point the first
+ * living object to grasp at least one object to avoid GC issue.
+ * This means that you can not walk through all Ruby object page
+ * including freed object page.
+ *
+ * Note: On this implementation, 'stride' is the same as sizeof(RVALUE).
+ * However, there are possibilities to pass variable values with
+ * 'stride' with some reasons. You must use stride instead of
+ * use some constant value in the iteration.
+ */
+void
+rb_objspace_each_objects(each_obj_callback *callback, void *data)
+{
+ objspace_each_objects(&rb_objspace, callback, data, TRUE);
+}
+
+static void
+objspace_each_objects(rb_objspace_t *objspace, each_obj_callback *callback, void *data, bool protected)
+{
+ /* Disable incremental GC */
+ bool reenable_incremental = FALSE;
+ if (protected) {
+ reenable_incremental = !objspace->flags.dont_incremental;
+
+ gc_rest(objspace);
+ objspace->flags.dont_incremental = TRUE;
+ }
+
+ struct each_obj_data each_obj_data = {
+ .objspace = objspace,
+ .reenable_incremental = reenable_incremental,
+
+ .callback = callback,
+ .data = data,
+
+ .pages = {NULL},
+ .pages_counts = {0},
+ };
+ rb_ensure(objspace_each_objects_try, (VALUE)&each_obj_data,
+ objspace_each_objects_ensure, (VALUE)&each_obj_data);
+}
+
+void
+rb_objspace_each_objects_without_setup(each_obj_callback *callback, void *data)
+{
+ objspace_each_objects(&rb_objspace, callback, data, FALSE);
+}
+
+struct os_each_struct {
+ size_t num;
+ VALUE of;
+};
+
static int
internal_object_p(VALUE obj)
{
+ RVALUE *p = (RVALUE *)obj;
void *ptr = asan_unpoison_object_temporary(obj);
+ bool used_p = p->as.basic.flags;
- if (RBASIC(obj)->flags) {
+ if (used_p) {
switch (BUILTIN_TYPE(obj)) {
case T_NODE:
UNEXPECTED_NODE(internal_object_p);
@@ -1331,17 +4044,17 @@ internal_object_p(VALUE obj)
case T_ZOMBIE:
break;
case T_CLASS:
- if (!RBASIC(obj)->klass) break;
- if (RCLASS_SINGLETON_P(obj)) {
+ if (!p->as.basic.klass) break;
+ if (FL_TEST(obj, FL_SINGLETON)) {
return rb_singleton_class_internal_p(obj);
}
return 0;
default:
- if (!RBASIC(obj)->klass) break;
+ if (!p->as.basic.klass) break;
return 0;
}
}
- if (ptr || !RBASIC(obj)->flags) {
+ if (ptr || ! used_p) {
asan_poison_object(obj);
}
return 1;
@@ -1353,11 +4066,6 @@ rb_objspace_internal_object_p(VALUE obj)
return internal_object_p(obj);
}
-struct os_each_struct {
- size_t num;
- VALUE of;
-};
-
static int
os_obj_of_i(void *vstart, void *vend, size_t stride, void *data)
{
@@ -1446,10 +4154,17 @@ os_each_obj(int argc, VALUE *argv, VALUE os)
static VALUE
undefine_final(VALUE os, VALUE obj)
{
- rb_check_frozen(obj);
-
- rb_gc_impl_undefine_finalizer(rb_gc_get_objspace(), obj);
+ return rb_undefine_finalizer(obj);
+}
+VALUE
+rb_undefine_finalizer(VALUE obj)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ st_data_t data = obj;
+ rb_check_frozen(obj);
+ st_delete(finalizer_table, &data, 0);
+ FL_UNSET(obj, FL_FINALIZE);
return obj;
}
@@ -1472,12 +4187,6 @@ should_be_finalizable(VALUE obj)
rb_check_frozen(obj);
}
-void
-rb_gc_copy_finalizer(VALUE dest, VALUE obj)
-{
- rb_gc_impl_copy_finalizer(rb_gc_get_objspace(), dest, obj);
-}
-
/*
* call-seq:
* ObjectSpace.define_finalizer(obj, aProc=proc())
@@ -1546,46 +4255,413 @@ define_final(int argc, VALUE *argv, VALUE os)
VALUE obj, block;
rb_scan_args(argc, argv, "11", &obj, &block);
+ should_be_finalizable(obj);
if (argc == 1) {
block = rb_block_proc();
}
+ else {
+ should_be_callable(block);
+ }
if (rb_callable_receiver(block) == obj) {
rb_warn("finalizer references object to be finalized");
}
- return rb_define_finalizer(obj, block);
+ return define_final0(obj, block);
}
-VALUE
-rb_define_finalizer(VALUE obj, VALUE block)
+static VALUE
+define_final0(VALUE obj, VALUE block)
{
- should_be_finalizable(obj);
- should_be_callable(block);
+ rb_objspace_t *objspace = &rb_objspace;
+ VALUE table;
+ st_data_t data;
- block = rb_gc_impl_define_finalizer(rb_gc_get_objspace(), obj, block);
+ RBASIC(obj)->flags |= FL_FINALIZE;
+ if (st_lookup(finalizer_table, obj, &data)) {
+ table = (VALUE)data;
+
+ /* avoid duplicate block, table is usually small */
+ {
+ long len = RARRAY_LEN(table);
+ long i;
+
+ for (i = 0; i < len; i++) {
+ VALUE recv = RARRAY_AREF(table, i);
+ if (rb_equal(recv, block)) {
+ block = recv;
+ goto end;
+ }
+ }
+ }
+
+ rb_ary_push(table, block);
+ }
+ else {
+ table = rb_ary_new3(1, block);
+ RBASIC_CLEAR_CLASS(table);
+ st_add_direct(finalizer_table, obj, table);
+ }
+ end:
block = rb_ary_new3(2, INT2FIX(0), block);
OBJ_FREEZE(block);
return block;
}
+VALUE
+rb_define_finalizer(VALUE obj, VALUE block)
+{
+ should_be_finalizable(obj);
+ should_be_callable(block);
+ return define_final0(obj, block);
+}
+
void
-rb_objspace_call_finalizer(void)
+rb_gc_copy_finalizer(VALUE dest, VALUE obj)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ VALUE table;
+ st_data_t data;
+
+ if (!FL_TEST(obj, FL_FINALIZE)) return;
+ if (st_lookup(finalizer_table, obj, &data)) {
+ table = (VALUE)data;
+ st_insert(finalizer_table, dest, table);
+ }
+ FL_SET(dest, FL_FINALIZE);
+}
+
+static VALUE
+run_single_final(VALUE cmd, VALUE objid)
+{
+ return rb_check_funcall(cmd, idCall, 1, &objid);
+}
+
+static void
+warn_exception_in_finalizer(rb_execution_context_t *ec, VALUE final)
+{
+ if (!UNDEF_P(final) && !NIL_P(ruby_verbose)) {
+ VALUE errinfo = ec->errinfo;
+ rb_warn("Exception in finalizer %+"PRIsVALUE, final);
+ rb_ec_error_print(ec, errinfo);
+ }
+}
+
+static void
+run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE table)
+{
+ long i;
+ enum ruby_tag_type state;
+ volatile struct {
+ VALUE errinfo;
+ VALUE objid;
+ VALUE final;
+ rb_control_frame_t *cfp;
+ VALUE *sp;
+ long finished;
+ } saved;
+
+ rb_execution_context_t * volatile ec = GET_EC();
+#define RESTORE_FINALIZER() (\
+ ec->cfp = saved.cfp, \
+ ec->cfp->sp = saved.sp, \
+ ec->errinfo = saved.errinfo)
+
+ saved.errinfo = ec->errinfo;
+ saved.objid = rb_obj_id(obj);
+ saved.cfp = ec->cfp;
+ saved.sp = ec->cfp->sp;
+ saved.finished = 0;
+ saved.final = Qundef;
+
+ EC_PUSH_TAG(ec);
+ state = EC_EXEC_TAG();
+ if (state != TAG_NONE) {
+ ++saved.finished; /* skip failed finalizer */
+ warn_exception_in_finalizer(ec, ATOMIC_VALUE_EXCHANGE(saved.final, Qundef));
+ }
+ for (i = saved.finished;
+ RESTORE_FINALIZER(), i<RARRAY_LEN(table);
+ saved.finished = ++i) {
+ run_single_final(saved.final = RARRAY_AREF(table, i), saved.objid);
+ }
+ EC_POP_TAG();
+#undef RESTORE_FINALIZER
+}
+
+static void
+run_final(rb_objspace_t *objspace, VALUE zombie)
{
- rb_gc_impl_shutdown_call_finalizer(rb_gc_get_objspace());
+ st_data_t key, table;
+
+ if (RZOMBIE(zombie)->dfree) {
+ RZOMBIE(zombie)->dfree(RZOMBIE(zombie)->data);
+ }
+
+ key = (st_data_t)zombie;
+ if (st_delete(finalizer_table, &key, &table)) {
+ run_finalizer(objspace, zombie, (VALUE)table);
+ }
+}
+
+static void
+finalize_list(rb_objspace_t *objspace, VALUE zombie)
+{
+ while (zombie) {
+ VALUE next_zombie;
+ struct heap_page *page;
+ asan_unpoison_object(zombie, false);
+ next_zombie = RZOMBIE(zombie)->next;
+ page = GET_HEAP_PAGE(zombie);
+
+ run_final(objspace, zombie);
+
+ RB_VM_LOCK_ENTER();
+ {
+ GC_ASSERT(BUILTIN_TYPE(zombie) == T_ZOMBIE);
+ if (FL_TEST(zombie, FL_SEEN_OBJ_ID)) {
+ obj_free_object_id(objspace, zombie);
+ }
+
+ GC_ASSERT(heap_pages_final_slots > 0);
+ GC_ASSERT(page->final_slots > 0);
+
+ heap_pages_final_slots--;
+ page->final_slots--;
+ page->free_slots++;
+ heap_page_add_freeobj(objspace, page, zombie);
+ objspace->profile.total_freed_objects++;
+ }
+ RB_VM_LOCK_LEAVE();
+
+ zombie = next_zombie;
+ }
}
+static void
+finalize_deferred_heap_pages(rb_objspace_t *objspace)
+{
+ VALUE zombie;
+ while ((zombie = ATOMIC_VALUE_EXCHANGE(heap_pages_deferred_final, 0)) != 0) {
+ finalize_list(objspace, zombie);
+ }
+}
+
+static void
+finalize_deferred(rb_objspace_t *objspace)
+{
+ rb_execution_context_t *ec = GET_EC();
+ ec->interrupt_mask |= PENDING_INTERRUPT_MASK;
+ finalize_deferred_heap_pages(objspace);
+ ec->interrupt_mask &= ~PENDING_INTERRUPT_MASK;
+}
+
+static void
+gc_finalize_deferred(void *dmy)
+{
+ rb_objspace_t *objspace = dmy;
+ if (ATOMIC_EXCHANGE(finalizing, 1)) return;
+
+ finalize_deferred(objspace);
+ ATOMIC_SET(finalizing, 0);
+}
+
+static void
+gc_finalize_deferred_register(rb_objspace_t *objspace)
+{
+ if (rb_postponed_job_register_one(0, gc_finalize_deferred, objspace) == 0) {
+ rb_bug("gc_finalize_deferred_register: can't register finalizer.");
+ }
+}
+
+struct force_finalize_list {
+ VALUE obj;
+ VALUE table;
+ struct force_finalize_list *next;
+};
+
+static int
+force_chain_object(st_data_t key, st_data_t val, st_data_t arg)
+{
+ struct force_finalize_list **prev = (struct force_finalize_list **)arg;
+ struct force_finalize_list *curr = ALLOC(struct force_finalize_list);
+ curr->obj = key;
+ curr->table = val;
+ curr->next = *prev;
+ *prev = curr;
+ return ST_CONTINUE;
+}
+
+bool rb_obj_is_main_ractor(VALUE gv);
+
void
-rb_objspace_free_objects(void *objspace)
+rb_objspace_call_finalizer(rb_objspace_t *objspace)
+{
+ size_t i;
+
+#if RGENGC_CHECK_MODE >= 2
+ gc_verify_internal_consistency(objspace);
+#endif
+ gc_rest(objspace);
+
+ if (ATOMIC_EXCHANGE(finalizing, 1)) return;
+
+ /* run finalizers */
+ finalize_deferred(objspace);
+ GC_ASSERT(heap_pages_deferred_final == 0);
+
+ gc_rest(objspace);
+ /* prohibit incremental GC */
+ objspace->flags.dont_incremental = 1;
+
+ /* force to run finalizer */
+ while (finalizer_table->num_entries) {
+ struct force_finalize_list *list = 0;
+ st_foreach(finalizer_table, force_chain_object, (st_data_t)&list);
+ while (list) {
+ struct force_finalize_list *curr = list;
+ st_data_t obj = (st_data_t)curr->obj;
+ run_finalizer(objspace, curr->obj, curr->table);
+ st_delete(finalizer_table, &obj, 0);
+ list = curr->next;
+ xfree(curr);
+ }
+ }
+
+ /* prohibit GC because force T_DATA finalizers can break an object graph consistency */
+ dont_gc_on();
+
+ /* running data/file finalizers are part of garbage collection */
+ unsigned int lock_lev;
+ gc_enter(objspace, gc_enter_event_finalizer, &lock_lev);
+
+ /* run data/file object's finalizers */
+ for (i = 0; i < heap_allocated_pages; i++) {
+ struct heap_page *page = heap_pages_sorted[i];
+ short stride = page->slot_size;
+
+ uintptr_t p = (uintptr_t)page->start;
+ uintptr_t pend = p + page->total_slots * stride;
+ for (; p < pend; p += stride) {
+ VALUE vp = (VALUE)p;
+ void *poisoned = asan_unpoison_object_temporary(vp);
+ switch (BUILTIN_TYPE(vp)) {
+ case T_DATA:
+ if (!DATA_PTR(p) || !RANY(p)->as.data.dfree) break;
+ if (rb_obj_is_thread(vp)) break;
+ if (rb_obj_is_mutex(vp)) break;
+ if (rb_obj_is_fiber(vp)) break;
+ if (rb_obj_is_main_ractor(vp)) break;
+ if (RTYPEDDATA_P(vp)) {
+ RDATA(p)->dfree = RANY(p)->as.typeddata.type->function.dfree;
+ }
+ RANY(p)->as.free.flags = 0;
+ if (RANY(p)->as.data.dfree == RUBY_DEFAULT_FREE) {
+ xfree(DATA_PTR(p));
+ }
+ else if (RANY(p)->as.data.dfree) {
+ make_zombie(objspace, vp, RANY(p)->as.data.dfree, RANY(p)->as.data.data);
+ }
+ break;
+ case T_FILE:
+ if (RANY(p)->as.file.fptr) {
+ make_io_zombie(objspace, vp);
+ }
+ break;
+ default:
+ break;
+ }
+ if (poisoned) {
+ GC_ASSERT(BUILTIN_TYPE(vp) == T_NONE);
+ asan_poison_object(vp);
+ }
+ }
+ }
+
+ gc_exit(objspace, gc_enter_event_finalizer, &lock_lev);
+
+ finalize_deferred_heap_pages(objspace);
+
+ st_free_table(finalizer_table);
+ finalizer_table = 0;
+ ATOMIC_SET(finalizing, 0);
+}
+
+static inline int
+is_swept_object(rb_objspace_t *objspace, VALUE ptr)
+{
+ struct heap_page *page = GET_HEAP_PAGE(ptr);
+ return page->flags.before_sweep ? FALSE : TRUE;
+}
+
+/* garbage objects will be collected soon. */
+static inline int
+is_garbage_object(rb_objspace_t *objspace, VALUE ptr)
{
- rb_gc_impl_shutdown_free_objects(objspace);
+ if (!is_lazy_sweeping(objspace) ||
+ is_swept_object(objspace, ptr) ||
+ MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(ptr), ptr)) {
+
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+}
+
+static inline int
+is_live_object(rb_objspace_t *objspace, VALUE ptr)
+{
+ switch (BUILTIN_TYPE(ptr)) {
+ case T_NONE:
+ case T_MOVED:
+ case T_ZOMBIE:
+ return FALSE;
+ default:
+ break;
+ }
+
+ if (!is_garbage_object(objspace, ptr)) {
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+static inline int
+is_markable_object(rb_objspace_t *objspace, VALUE obj)
+{
+ if (rb_special_const_p(obj)) return FALSE; /* special const is not markable */
+ check_rvalue_consistency(obj);
+ return TRUE;
+}
+
+int
+rb_objspace_markable_object_p(VALUE obj)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ return is_markable_object(objspace, obj) && is_live_object(objspace, obj);
}
int
rb_objspace_garbage_object_p(VALUE obj)
{
- return rb_gc_impl_garbage_object_p(rb_gc_get_objspace(), obj);
+ rb_objspace_t *objspace = &rb_objspace;
+ return is_garbage_object(objspace, obj);
+}
+
+static VALUE
+id2ref_obj_tbl(rb_objspace_t *objspace, VALUE objid)
+{
+ VALUE orig;
+ if (st_lookup(objspace->id_to_obj_tbl, objid, &orig)) {
+ return orig;
+ }
+ else {
+ return Qundef;
+ }
}
/*
@@ -1611,36 +4687,46 @@ id2ref(VALUE objid)
#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
#define NUM2PTR(x) NUM2ULL(x)
#endif
+ rb_objspace_t *objspace = &rb_objspace;
+ VALUE ptr;
+ VALUE orig;
+ void *p0;
+
objid = rb_to_int(objid);
if (FIXNUM_P(objid) || rb_big_size(objid) <= SIZEOF_VOIDP) {
- VALUE ptr = NUM2PTR(objid);
- if (SPECIAL_CONST_P(ptr)) {
- if (ptr == Qtrue) return Qtrue;
- if (ptr == Qfalse) return Qfalse;
- if (NIL_P(ptr)) return Qnil;
- if (FIXNUM_P(ptr)) return ptr;
- if (FLONUM_P(ptr)) return ptr;
-
- if (SYMBOL_P(ptr)) {
- // Check that the symbol is valid
- if (rb_static_id_valid_p(SYM2ID(ptr))) {
- return ptr;
- }
- else {
- rb_raise(rb_eRangeError, "%p is not symbol id value", (void *)ptr);
- }
- }
+ ptr = NUM2PTR(objid);
+ if (ptr == Qtrue) return Qtrue;
+ if (ptr == Qfalse) return Qfalse;
+ if (NIL_P(ptr)) return Qnil;
+ if (FIXNUM_P(ptr)) return (VALUE)ptr;
+ if (FLONUM_P(ptr)) return (VALUE)ptr;
+
+ ptr = obj_id_to_ref(objid);
+ if ((ptr % sizeof(RVALUE)) == (4 << 2)) {
+ ID symid = ptr / sizeof(RVALUE);
+ p0 = (void *)ptr;
+ if (!rb_static_id_valid_p(symid))
+ rb_raise(rb_eRangeError, "%p is not symbol id value", p0);
+ return ID2SYM(symid);
+ }
+ }
+
+ if (!UNDEF_P(orig = id2ref_obj_tbl(objspace, objid)) &&
+ is_live_object(objspace, orig)) {
- rb_raise(rb_eRangeError, "%+"PRIsVALUE" is not id value", rb_int2str(objid, 10));
+ if (!rb_multi_ractor_p() || rb_ractor_shareable_p(orig)) {
+ return orig;
+ }
+ else {
+ rb_raise(rb_eRangeError, "%+"PRIsVALUE" is id of the unshareable object on multi-ractor", rb_int2str(objid, 10));
}
}
- VALUE obj = rb_gc_impl_object_id_to_ref(rb_gc_get_objspace(), objid);
- if (!rb_multi_ractor_p() || rb_ractor_shareable_p(obj)) {
- return obj;
+ if (rb_int_ge(objid, objspace->next_object_id)) {
+ rb_raise(rb_eRangeError, "%+"PRIsVALUE" is not id value", rb_int2str(objid, 10));
}
else {
- rb_raise(rb_eRangeError, "%+"PRIsVALUE" is id of the unshareable object on multi-ractor", rb_int2str(objid, 10));
+ rb_raise(rb_eRangeError, "%+"PRIsVALUE" is recycled object", rb_int2str(objid, 10));
}
}
@@ -1652,35 +4738,63 @@ os_id2ref(VALUE os, VALUE objid)
}
static VALUE
-rb_find_object_id(void *objspace, VALUE obj, VALUE (*get_heap_object_id)(void *, VALUE))
+rb_find_object_id(VALUE obj, VALUE (*get_heap_object_id)(VALUE))
{
- if (SPECIAL_CONST_P(obj)) {
+ if (STATIC_SYM_P(obj)) {
+ return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;
+ }
+ else if (FLONUM_P(obj)) {
#if SIZEOF_LONG == SIZEOF_VOIDP
return LONG2NUM((SIGNED_VALUE)obj);
#else
return LL2NUM((SIGNED_VALUE)obj);
#endif
}
+ else if (SPECIAL_CONST_P(obj)) {
+ return LONG2NUM((SIGNED_VALUE)obj);
+ }
- return get_heap_object_id(objspace, obj);
+ return get_heap_object_id(obj);
}
static VALUE
-nonspecial_obj_id(void *_objspace, VALUE obj)
+cached_object_id(VALUE obj)
{
-#if SIZEOF_LONG == SIZEOF_VOIDP
- return (VALUE)((SIGNED_VALUE)(obj)|FIXNUM_FLAG);
-#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
- return LL2NUM((SIGNED_VALUE)(obj) / 2);
-#else
-# error not supported
-#endif
+ VALUE id;
+ rb_objspace_t *objspace = &rb_objspace;
+
+ RB_VM_LOCK_ENTER();
+ if (st_lookup(objspace->obj_to_id_tbl, (st_data_t)obj, &id)) {
+ GC_ASSERT(FL_TEST(obj, FL_SEEN_OBJ_ID));
+ }
+ else {
+ GC_ASSERT(!FL_TEST(obj, FL_SEEN_OBJ_ID));
+
+ id = objspace->next_object_id;
+ objspace->next_object_id = rb_int_plus(id, INT2FIX(OBJ_ID_INCREMENT));
+
+ VALUE already_disabled = rb_gc_disable_no_rest();
+ st_insert(objspace->obj_to_id_tbl, (st_data_t)obj, (st_data_t)id);
+ st_insert(objspace->id_to_obj_tbl, (st_data_t)id, (st_data_t)obj);
+ if (already_disabled == Qfalse) rb_objspace_gc_enable(objspace);
+ FL_SET(obj, FL_SEEN_OBJ_ID);
+ }
+ RB_VM_LOCK_LEAVE();
+
+ return id;
+}
+
+static VALUE
+nonspecial_obj_id_(VALUE obj)
+{
+ return nonspecial_obj_id(obj);
}
+
VALUE
rb_memory_id(VALUE obj)
{
- return rb_find_object_id(NULL, obj, nonspecial_obj_id);
+ return rb_find_object_id(obj, nonspecial_obj_id_);
}
/*
@@ -1713,11 +4827,36 @@ rb_memory_id(VALUE obj)
VALUE
rb_obj_id(VALUE obj)
{
- /* If obj is an immediate, the object ID is obj directly converted to a Numeric.
- * Otherwise, the object ID is a Numeric that is a non-zero multiple of
- * (RUBY_IMMEDIATE_MASK + 1) which guarantees that it does not collide with
- * any immediates. */
- return rb_find_object_id(rb_gc_get_objspace(), obj, rb_gc_impl_object_id);
+ /*
+ * 32-bit VALUE space
+ * MSB ------------------------ LSB
+ * false 00000000000000000000000000000000
+ * true 00000000000000000000000000000010
+ * nil 00000000000000000000000000000100
+ * undef 00000000000000000000000000000110
+ * symbol ssssssssssssssssssssssss00001110
+ * object oooooooooooooooooooooooooooooo00 = 0 (mod sizeof(RVALUE))
+ * fixnum fffffffffffffffffffffffffffffff1
+ *
+ * object_id space
+ * LSB
+ * false 00000000000000000000000000000000
+ * true 00000000000000000000000000000010
+ * nil 00000000000000000000000000000100
+ * undef 00000000000000000000000000000110
+ * symbol 000SSSSSSSSSSSSSSSSSSSSSSSSSSS0 S...S % A = 4 (S...S = s...s * A + 4)
+ * object oooooooooooooooooooooooooooooo0 o...o % A = 0
+ * fixnum fffffffffffffffffffffffffffffff1 bignum if required
+ *
+ * where A = sizeof(RVALUE)/4
+ *
+ * sizeof(RVALUE) is
+ * 20 if 32-bit, double is 4-byte aligned
+ * 24 if 32-bit, double is 8-byte aligned
+ * 40 if 64-bit
+ */
+
+ return rb_find_object_id(obj, cached_object_id);
}
static enum rb_id_table_iterator_result
@@ -1738,8 +4877,8 @@ cc_table_memsize(struct rb_id_table *cc_table)
return total;
}
-size_t
-rb_obj_memsize_of(VALUE obj)
+static size_t
+obj_memsize_of(VALUE obj, int use_all_types)
{
size_t size = 0;
@@ -1762,22 +4901,27 @@ rb_obj_memsize_of(VALUE obj)
break;
case T_MODULE:
case T_CLASS:
- if (RCLASS_M_TBL(obj)) {
- size += rb_id_table_memsize(RCLASS_M_TBL(obj));
- }
- // class IV sizes are allocated as powers of two
- size += SIZEOF_VALUE << bit_length(RCLASS_IV_COUNT(obj));
- if (RCLASS_CVC_TBL(obj)) {
- size += rb_id_table_memsize(RCLASS_CVC_TBL(obj));
- }
- if (RCLASS_EXT(obj)->const_tbl) {
- size += rb_id_table_memsize(RCLASS_EXT(obj)->const_tbl);
- }
- if (RCLASS_CC_TBL(obj)) {
- size += cc_table_memsize(RCLASS_CC_TBL(obj));
- }
- if (FL_TEST_RAW(obj, RCLASS_SUPERCLASSES_INCLUDE_SELF)) {
- size += (RCLASS_SUPERCLASS_DEPTH(obj) + 1) * sizeof(VALUE);
+ if (RCLASS_EXT(obj)) {
+ if (RCLASS_M_TBL(obj)) {
+ size += rb_id_table_memsize(RCLASS_M_TBL(obj));
+ }
+ // class IV sizes are allocated as powers of two
+ size += SIZEOF_VALUE << bit_length(RCLASS_IV_COUNT(obj));
+ if (RCLASS_CVC_TBL(obj)) {
+ size += rb_id_table_memsize(RCLASS_CVC_TBL(obj));
+ }
+ if (RCLASS_EXT(obj)->const_tbl) {
+ size += rb_id_table_memsize(RCLASS_EXT(obj)->const_tbl);
+ }
+ if (RCLASS_CC_TBL(obj)) {
+ size += cc_table_memsize(RCLASS_CC_TBL(obj));
+ }
+ if (FL_TEST_RAW(obj, RCLASS_SUPERCLASSES_INCLUDE_SELF)) {
+ size += (RCLASS_SUPERCLASS_DEPTH(obj) + 1) * sizeof(VALUE);
+ }
+#if SIZE_POOL_COUNT == 1
+ size += sizeof(rb_classext_t);
+#endif
}
break;
case T_ICLASS:
@@ -1786,7 +4930,7 @@ rb_obj_memsize_of(VALUE obj)
size += rb_id_table_memsize(RCLASS_M_TBL(obj));
}
}
- if (RCLASS_CC_TBL(obj)) {
+ if (RCLASS_EXT(obj) && RCLASS_CC_TBL(obj)) {
size += cc_table_memsize(RCLASS_CC_TBL(obj));
}
break;
@@ -1797,10 +4941,15 @@ rb_obj_memsize_of(VALUE obj)
size += rb_ary_memsize(obj);
break;
case T_HASH:
- if (RHASH_ST_TABLE_P(obj)) {
+ if (RHASH_AR_TABLE_P(obj)) {
+ if (RHASH_AR_TABLE(obj) != NULL) {
+ size_t rb_hash_ar_table_size(void);
+ size += rb_hash_ar_table_size();
+ }
+ }
+ else {
VM_ASSERT(RHASH_ST_TABLE(obj) != NULL);
- /* st_table is in the slot */
- size += st_memsize(RHASH_ST_TABLE(obj)) - sizeof(st_table);
+ size += st_memsize(RHASH_ST_TABLE(obj));
}
break;
case T_REGEXP:
@@ -1809,13 +4958,14 @@ rb_obj_memsize_of(VALUE obj)
}
break;
case T_DATA:
- size += rb_objspace_data_type_memsize(obj);
+ if (use_all_types) size += rb_objspace_data_type_memsize(obj);
break;
case T_MATCH:
- {
- rb_matchext_t *rm = RMATCH_EXT(obj);
+ if (RMATCH(obj)->rmatch) {
+ struct rmatch *rm = RMATCH(obj)->rmatch;
size += onig_region_memsize(&rm->regs);
size += sizeof(struct rmatch_offset) * rm->char_offset_num_allocated;
+ size += sizeof(struct rmatch);
}
break;
case T_FILE:
@@ -1827,7 +4977,7 @@ rb_obj_memsize_of(VALUE obj)
case T_COMPLEX:
break;
case T_IMEMO:
- size += rb_imemo_memsize(obj);
+ size += imemo_memsize(obj);
break;
case T_FLOAT:
@@ -1863,6 +5013,12 @@ rb_obj_memsize_of(VALUE obj)
return size + rb_gc_obj_slot_size(obj);
}
+size_t
+rb_obj_memsize_of(VALUE obj)
+{
+ return obj_memsize_of(obj, TRUE);
+}
+
static int
set_zero(st_data_t key, st_data_t val, st_data_t arg)
{
@@ -1872,25 +5028,41 @@ set_zero(st_data_t key, st_data_t val, st_data_t arg)
return ST_CONTINUE;
}
-struct count_objects_data {
- size_t counts[T_MASK+1];
- size_t freed;
- size_t total;
-};
-
-static void
-count_objects_i(VALUE obj, void *d)
+static VALUE
+type_sym(size_t type)
{
- struct count_objects_data *data = (struct count_objects_data *)d;
-
- if (RBASIC(obj)->flags) {
- data->counts[BUILTIN_TYPE(obj)]++;
- }
- else {
- data->freed++;
+ switch (type) {
+#define COUNT_TYPE(t) case (t): return ID2SYM(rb_intern(#t)); break;
+ COUNT_TYPE(T_NONE);
+ COUNT_TYPE(T_OBJECT);
+ COUNT_TYPE(T_CLASS);
+ COUNT_TYPE(T_MODULE);
+ COUNT_TYPE(T_FLOAT);
+ COUNT_TYPE(T_STRING);
+ COUNT_TYPE(T_REGEXP);
+ COUNT_TYPE(T_ARRAY);
+ COUNT_TYPE(T_HASH);
+ COUNT_TYPE(T_STRUCT);
+ COUNT_TYPE(T_BIGNUM);
+ COUNT_TYPE(T_FILE);
+ COUNT_TYPE(T_DATA);
+ COUNT_TYPE(T_MATCH);
+ COUNT_TYPE(T_COMPLEX);
+ COUNT_TYPE(T_RATIONAL);
+ COUNT_TYPE(T_NIL);
+ COUNT_TYPE(T_TRUE);
+ COUNT_TYPE(T_FALSE);
+ COUNT_TYPE(T_SYMBOL);
+ COUNT_TYPE(T_FIXNUM);
+ COUNT_TYPE(T_IMEMO);
+ COUNT_TYPE(T_UNDEF);
+ COUNT_TYPE(T_NODE);
+ COUNT_TYPE(T_ICLASS);
+ COUNT_TYPE(T_ZOMBIE);
+ COUNT_TYPE(T_MOVED);
+#undef COUNT_TYPE
+ default: return SIZET2NUM(type); break;
}
-
- data->total++;
}
/*
@@ -1931,7 +5103,11 @@ count_objects_i(VALUE obj, void *d)
static VALUE
count_objects(int argc, VALUE *argv, VALUE os)
{
- struct count_objects_data data = { 0 };
+ rb_objspace_t *objspace = &rb_objspace;
+ size_t counts[T_MASK+1];
+ size_t freed = 0;
+ size_t total = 0;
+ size_t i;
VALUE hash = Qnil;
if (rb_check_arity(argc, 0, 1) == 1) {
@@ -1940,7 +5116,34 @@ count_objects(int argc, VALUE *argv, VALUE os)
rb_raise(rb_eTypeError, "non-hash given");
}
- rb_gc_impl_each_object(rb_gc_get_objspace(), count_objects_i, &data);
+ for (i = 0; i <= T_MASK; i++) {
+ counts[i] = 0;
+ }
+
+ for (i = 0; i < heap_allocated_pages; i++) {
+ struct heap_page *page = heap_pages_sorted[i];
+ short stride = page->slot_size;
+
+ uintptr_t p = (uintptr_t)page->start;
+ uintptr_t pend = p + page->total_slots * stride;
+ for (;p < pend; p += stride) {
+ VALUE vp = (VALUE)p;
+ GC_ASSERT((NUM_IN_PAGE(vp) * BASE_SLOT_SIZE) % page->slot_size == 0);
+
+ void *poisoned = asan_unpoison_object_temporary(vp);
+ if (RANY(p)->as.basic.flags) {
+ counts[BUILTIN_TYPE(vp)]++;
+ }
+ else {
+ freed++;
+ }
+ if (poisoned) {
+ GC_ASSERT(BUILTIN_TYPE(vp) == T_NONE);
+ asan_poison_object(vp);
+ }
+ }
+ total += page->total_slots;
+ }
if (NIL_P(hash)) {
hash = rb_hash_new();
@@ -1948,18 +5151,1284 @@ count_objects(int argc, VALUE *argv, VALUE os)
else if (!RHASH_EMPTY_P(hash)) {
rb_hash_stlike_foreach(hash, set_zero, hash);
}
- rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(data.total));
- rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(data.freed));
+ rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
+ rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(freed));
- for (size_t i = 0; i <= T_MASK; i++) {
+ for (i = 0; i <= T_MASK; i++) {
VALUE type = type_sym(i);
- if (data.counts[i])
- rb_hash_aset(hash, type, SIZET2NUM(data.counts[i]));
+ if (counts[i])
+ rb_hash_aset(hash, type, SIZET2NUM(counts[i]));
}
return hash;
}
+/*
+ ------------------------ Garbage Collection ------------------------
+*/
+
+/* Sweeping */
+
+static size_t
+objspace_available_slots(rb_objspace_t *objspace)
+{
+ size_t total_slots = 0;
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ total_slots += SIZE_POOL_EDEN_HEAP(size_pool)->total_slots;
+ total_slots += SIZE_POOL_TOMB_HEAP(size_pool)->total_slots;
+ }
+ return total_slots;
+}
+
+static size_t
+objspace_live_slots(rb_objspace_t *objspace)
+{
+ return (objspace->total_allocated_objects - objspace->profile.total_freed_objects) - heap_pages_final_slots;
+}
+
+static size_t
+objspace_free_slots(rb_objspace_t *objspace)
+{
+ return objspace_available_slots(objspace) - objspace_live_slots(objspace) - heap_pages_final_slots;
+}
+
+static void
+gc_setup_mark_bits(struct heap_page *page)
+{
+ /* copy oldgen bitmap to mark bitmap */
+ memcpy(&page->mark_bits[0], &page->uncollectible_bits[0], HEAP_PAGE_BITMAP_SIZE);
+}
+
+static int gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj);
+static VALUE gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, size_t slot_size);
+
+#if defined(_WIN32)
+enum {HEAP_PAGE_LOCK = PAGE_NOACCESS, HEAP_PAGE_UNLOCK = PAGE_READWRITE};
+
+static BOOL
+protect_page_body(struct heap_page_body *body, DWORD protect)
+{
+ DWORD old_protect;
+ return VirtualProtect(body, HEAP_PAGE_SIZE, protect, &old_protect) != 0;
+}
+#else
+enum {HEAP_PAGE_LOCK = PROT_NONE, HEAP_PAGE_UNLOCK = PROT_READ | PROT_WRITE};
+#define protect_page_body(body, protect) !mprotect((body), HEAP_PAGE_SIZE, (protect))
+#endif
+
+static void
+lock_page_body(rb_objspace_t *objspace, struct heap_page_body *body)
+{
+ if (!protect_page_body(body, HEAP_PAGE_LOCK)) {
+ rb_bug("Couldn't protect page %p, errno: %s", (void *)body, strerror(errno));
+ }
+ else {
+ gc_report(5, objspace, "Protecting page in move %p\n", (void *)body);
+ }
+}
+
+static void
+unlock_page_body(rb_objspace_t *objspace, struct heap_page_body *body)
+{
+ if (!protect_page_body(body, HEAP_PAGE_UNLOCK)) {
+ rb_bug("Couldn't unprotect page %p, errno: %s", (void *)body, strerror(errno));
+ }
+ else {
+ gc_report(5, objspace, "Unprotecting page in move %p\n", (void *)body);
+ }
+}
+
+static bool
+try_move(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *free_page, VALUE src)
+{
+ GC_ASSERT(gc_is_moveable_obj(objspace, src));
+
+ struct heap_page *src_page = GET_HEAP_PAGE(src);
+ if (!free_page) {
+ return false;
+ }
+
+ /* We should return true if either src is successfully moved, or src is
+ * unmoveable. A false return will cause the sweeping cursor to be
+ * incremented to the next page, and src will attempt to move again */
+ GC_ASSERT(MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(src), src));
+
+ asan_unlock_freelist(free_page);
+ VALUE dest = (VALUE)free_page->freelist;
+ asan_lock_freelist(free_page);
+ asan_unpoison_object(dest, false);
+ if (!dest) {
+ /* if we can't get something from the freelist then the page must be
+ * full */
+ return false;
+ }
+ free_page->freelist = RANY(dest)->as.free.next;
+
+ GC_ASSERT(RB_BUILTIN_TYPE(dest) == T_NONE);
+
+ if (src_page->slot_size > free_page->slot_size) {
+ objspace->rcompactor.moved_down_count_table[BUILTIN_TYPE(src)]++;
+ }
+ else if (free_page->slot_size > src_page->slot_size) {
+ objspace->rcompactor.moved_up_count_table[BUILTIN_TYPE(src)]++;
+ }
+ objspace->rcompactor.moved_count_table[BUILTIN_TYPE(src)]++;
+ objspace->rcompactor.total_moved++;
+
+ gc_move(objspace, src, dest, src_page->slot_size, free_page->slot_size);
+ gc_pin(objspace, src);
+ free_page->free_slots--;
+
+ return true;
+}
+
+static void
+gc_unprotect_pages(rb_objspace_t *objspace, rb_heap_t *heap)
+{
+ struct heap_page *cursor = heap->compact_cursor;
+
+ while (cursor) {
+ unlock_page_body(objspace, GET_PAGE_BODY(cursor->start));
+ cursor = ccan_list_next(&heap->pages, cursor, page_node);
+ }
+}
+
+static void gc_update_references(rb_objspace_t * objspace);
+static void invalidate_moved_page(rb_objspace_t *objspace, struct heap_page *page);
+
+#ifndef GC_CAN_COMPILE_COMPACTION
+#if defined(__wasi__) /* WebAssembly doesn't support signals */
+# define GC_CAN_COMPILE_COMPACTION 0
+#else
+# define GC_CAN_COMPILE_COMPACTION 1
+#endif
+#endif
+
+#if defined(__MINGW32__) || defined(_WIN32)
+# define GC_COMPACTION_SUPPORTED 1
+#else
+/* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for
+ * the read barrier, so we must disable compaction. */
+# define GC_COMPACTION_SUPPORTED (GC_CAN_COMPILE_COMPACTION && HEAP_PAGE_ALLOC_USE_MMAP)
+#endif
+
+#if GC_CAN_COMPILE_COMPACTION
+static void
+read_barrier_handler(uintptr_t original_address)
+{
+ VALUE obj;
+ rb_objspace_t * objspace = &rb_objspace;
+
+ /* Calculate address aligned to slots. */
+ uintptr_t address = original_address - (original_address % BASE_SLOT_SIZE);
+
+ obj = (VALUE)address;
+
+ struct heap_page_body *page_body = GET_PAGE_BODY(obj);
+
+ /* If the page_body is NULL, then mprotect cannot handle it and will crash
+ * with "Cannot allocate memory". */
+ if (page_body == NULL) {
+ rb_bug("read_barrier_handler: segmentation fault at %p", (void *)original_address);
+ }
+
+ RB_VM_LOCK_ENTER();
+ {
+ unlock_page_body(objspace, page_body);
+
+ objspace->profile.read_barrier_faults++;
+
+ invalidate_moved_page(objspace, GET_HEAP_PAGE(obj));
+ }
+ RB_VM_LOCK_LEAVE();
+}
+#endif
+
+#if !GC_CAN_COMPILE_COMPACTION
+static void
+uninstall_handlers(void)
+{
+ /* no-op */
+}
+
+static void
+install_handlers(void)
+{
+ /* no-op */
+}
+#elif defined(_WIN32)
+static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
+typedef void (*signal_handler)(int);
+static signal_handler old_sigsegv_handler;
+
+static LONG WINAPI
+read_barrier_signal(EXCEPTION_POINTERS * info)
+{
+ /* EXCEPTION_ACCESS_VIOLATION is what's raised by access to protected pages */
+ if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
+ /* > The second array element specifies the virtual address of the inaccessible data.
+ * https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record
+ *
+ * Use this address to invalidate the page */
+ read_barrier_handler((uintptr_t)info->ExceptionRecord->ExceptionInformation[1]);
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+ else {
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+}
+
+static void
+uninstall_handlers(void)
+{
+ signal(SIGSEGV, old_sigsegv_handler);
+ SetUnhandledExceptionFilter(old_handler);
+}
+
+static void
+install_handlers(void)
+{
+ /* Remove SEGV handler so that the Unhandled Exception Filter handles it */
+ old_sigsegv_handler = signal(SIGSEGV, NULL);
+ /* Unhandled Exception Filter has access to the violation address similar
+ * to si_addr from sigaction */
+ old_handler = SetUnhandledExceptionFilter(read_barrier_signal);
+}
+#else
+static struct sigaction old_sigbus_handler;
+static struct sigaction old_sigsegv_handler;
+
+#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS
+static exception_mask_t old_exception_masks[32];
+static mach_port_t old_exception_ports[32];
+static exception_behavior_t old_exception_behaviors[32];
+static thread_state_flavor_t old_exception_flavors[32];
+static mach_msg_type_number_t old_exception_count;
+
+static void
+disable_mach_bad_access_exc(void)
+{
+ old_exception_count = sizeof(old_exception_masks) / sizeof(old_exception_masks[0]);
+ task_swap_exception_ports(
+ mach_task_self(), EXC_MASK_BAD_ACCESS,
+ MACH_PORT_NULL, EXCEPTION_DEFAULT, 0,
+ old_exception_masks, &old_exception_count,
+ old_exception_ports, old_exception_behaviors, old_exception_flavors
+ );
+}
+
+static void
+restore_mach_bad_access_exc(void)
+{
+ for (mach_msg_type_number_t i = 0; i < old_exception_count; i++) {
+ task_set_exception_ports(
+ mach_task_self(),
+ old_exception_masks[i], old_exception_ports[i],
+ old_exception_behaviors[i], old_exception_flavors[i]
+ );
+ }
+}
+#endif
+
+static void
+read_barrier_signal(int sig, siginfo_t * info, void * data)
+{
+ // setup SEGV/BUS handlers for errors
+ struct sigaction prev_sigbus, prev_sigsegv;
+ sigaction(SIGBUS, &old_sigbus_handler, &prev_sigbus);
+ sigaction(SIGSEGV, &old_sigsegv_handler, &prev_sigsegv);
+
+ // enable SIGBUS/SEGV
+ sigset_t set, prev_set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGBUS);
+ sigaddset(&set, SIGSEGV);
+ sigprocmask(SIG_UNBLOCK, &set, &prev_set);
+#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS
+ disable_mach_bad_access_exc();
+#endif
+ // run handler
+ read_barrier_handler((uintptr_t)info->si_addr);
+
+ // reset SEGV/BUS handlers
+#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS
+ restore_mach_bad_access_exc();
+#endif
+ sigaction(SIGBUS, &prev_sigbus, NULL);
+ sigaction(SIGSEGV, &prev_sigsegv, NULL);
+ sigprocmask(SIG_SETMASK, &prev_set, NULL);
+}
+
+static void
+uninstall_handlers(void)
+{
+#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS
+ restore_mach_bad_access_exc();
+#endif
+ sigaction(SIGBUS, &old_sigbus_handler, NULL);
+ sigaction(SIGSEGV, &old_sigsegv_handler, NULL);
+}
+
+static void
+install_handlers(void)
+{
+ struct sigaction action;
+ memset(&action, 0, sizeof(struct sigaction));
+ sigemptyset(&action.sa_mask);
+ action.sa_sigaction = read_barrier_signal;
+ action.sa_flags = SA_SIGINFO | SA_ONSTACK;
+
+ sigaction(SIGBUS, &action, &old_sigbus_handler);
+ sigaction(SIGSEGV, &action, &old_sigsegv_handler);
+#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS
+ disable_mach_bad_access_exc();
+#endif
+}
+#endif
+
+static void
+revert_stack_objects(VALUE stack_obj, void *ctx)
+{
+ rb_objspace_t * objspace = (rb_objspace_t*)ctx;
+
+ if (BUILTIN_TYPE(stack_obj) == T_MOVED) {
+ /* For now we'll revert the whole page if the object made it to the
+ * stack. I think we can change this to move just the one object
+ * back though */
+ invalidate_moved_page(objspace, GET_HEAP_PAGE(stack_obj));
+ }
+}
+
+static void
+revert_machine_stack_references(rb_objspace_t *objspace, VALUE v)
+{
+ if (is_pointer_to_heap(objspace, (void *)v)) {
+ if (BUILTIN_TYPE(v) == T_MOVED) {
+ /* For now we'll revert the whole page if the object made it to the
+ * stack. I think we can change this to move just the one object
+ * back though */
+ invalidate_moved_page(objspace, GET_HEAP_PAGE(v));
+ }
+ }
+}
+
+static void each_machine_stack_value(const rb_execution_context_t *ec, void (*cb)(rb_objspace_t *, VALUE));
+
+static void
+check_stack_for_moved(rb_objspace_t *objspace)
+{
+ rb_execution_context_t *ec = GET_EC();
+ rb_vm_t *vm = rb_ec_vm_ptr(ec);
+ rb_vm_each_stack_value(vm, revert_stack_objects, (void*)objspace);
+ each_machine_stack_value(ec, revert_machine_stack_references);
+}
+
+static void gc_mode_transition(rb_objspace_t *objspace, enum gc_mode mode);
+
+static void
+gc_compact_finish(rb_objspace_t *objspace)
+{
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
+ gc_unprotect_pages(objspace, heap);
+ }
+
+ uninstall_handlers();
+
+ /* The mutator is allowed to run during incremental sweeping. T_MOVED
+ * objects can get pushed on the stack and when the compaction process
+ * finishes up, it may remove the read barrier before anything has a
+ * chance to read from the T_MOVED address. To fix this, we scan the stack
+ * then revert any moved objects that made it to the stack. */
+ check_stack_for_moved(objspace);
+
+ gc_update_references(objspace);
+ objspace->profile.compact_count++;
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
+ heap->compact_cursor = NULL;
+ heap->free_pages = NULL;
+ heap->compact_cursor_index = 0;
+ }
+
+ if (gc_prof_enabled(objspace)) {
+ gc_profile_record *record = gc_prof_record(objspace);
+ record->moved_objects = objspace->rcompactor.total_moved - record->moved_objects;
+ }
+ objspace->flags.during_compacting = FALSE;
+}
+
+struct gc_sweep_context {
+ struct heap_page *page;
+ int final_slots;
+ int freed_slots;
+ int empty_slots;
+};
+
+static inline void
+gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bitset, struct gc_sweep_context *ctx)
+{
+ struct heap_page * sweep_page = ctx->page;
+ short slot_size = sweep_page->slot_size;
+ short slot_bits = slot_size / BASE_SLOT_SIZE;
+ GC_ASSERT(slot_bits > 0);
+
+ do {
+ VALUE vp = (VALUE)p;
+ GC_ASSERT(vp % BASE_SLOT_SIZE == 0);
+
+ asan_unpoison_object(vp, false);
+ if (bitset & 1) {
+ switch (BUILTIN_TYPE(vp)) {
+ default: /* majority case */
+ gc_report(2, objspace, "page_sweep: free %p\n", (void *)p);
+#if RGENGC_CHECK_MODE
+ if (!is_full_marking(objspace)) {
+ if (RVALUE_OLD_P(vp)) rb_bug("page_sweep: %p - old while minor GC.", (void *)p);
+ if (rgengc_remembered_sweep(objspace, vp)) rb_bug("page_sweep: %p - remembered.", (void *)p);
+ }
+#endif
+ if (obj_free(objspace, vp)) {
+ // always add free slots back to the swept pages freelist,
+ // so that if we're comapacting, we can re-use the slots
+ (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, BASE_SLOT_SIZE);
+ heap_page_add_freeobj(objspace, sweep_page, vp);
+ gc_report(3, objspace, "page_sweep: %s is added to freelist\n", obj_info(vp));
+ ctx->freed_slots++;
+ }
+ else {
+ ctx->final_slots++;
+ }
+ break;
+
+ case T_MOVED:
+ if (objspace->flags.during_compacting) {
+ /* The sweep cursor shouldn't have made it to any
+ * T_MOVED slots while the compact flag is enabled.
+ * The sweep cursor and compact cursor move in
+ * opposite directions, and when they meet references will
+ * get updated and "during_compacting" should get disabled */
+ rb_bug("T_MOVED shouldn't be seen until compaction is finished\n");
+ }
+ gc_report(3, objspace, "page_sweep: %s is added to freelist\n", obj_info(vp));
+ ctx->empty_slots++;
+ heap_page_add_freeobj(objspace, sweep_page, vp);
+ break;
+ case T_ZOMBIE:
+ /* already counted */
+ break;
+ case T_NONE:
+ ctx->empty_slots++; /* already freed */
+ break;
+ }
+ }
+ p += slot_size;
+ bitset >>= slot_bits;
+ } while (bitset);
+}
+
+static inline void
+gc_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct gc_sweep_context *ctx)
+{
+ struct heap_page *sweep_page = ctx->page;
+ GC_ASSERT(SIZE_POOL_EDEN_HEAP(sweep_page->size_pool) == heap);
+
+ uintptr_t p;
+ bits_t *bits, bitset;
+
+ gc_report(2, objspace, "page_sweep: start.\n");
+
+#if RGENGC_CHECK_MODE
+ if (!objspace->flags.immediate_sweep) {
+ GC_ASSERT(sweep_page->flags.before_sweep == TRUE);
+ }
+#endif
+ sweep_page->flags.before_sweep = FALSE;
+ sweep_page->free_slots = 0;
+
+ p = (uintptr_t)sweep_page->start;
+ bits = sweep_page->mark_bits;
+
+ int page_rvalue_count = sweep_page->total_slots * (sweep_page->slot_size / BASE_SLOT_SIZE);
+ int out_of_range_bits = (NUM_IN_PAGE(p) + page_rvalue_count) % BITS_BITLENGTH;
+ if (out_of_range_bits != 0) { // sizeof(RVALUE) == 64
+ bits[BITMAP_INDEX(p) + page_rvalue_count / BITS_BITLENGTH] |= ~(((bits_t)1 << out_of_range_bits) - 1);
+ }
+
+ /* The last bitmap plane may not be used if the last plane does not
+ * have enough space for the slot_size. In that case, the last plane must
+ * be skipped since none of the bits will be set. */
+ int bitmap_plane_count = CEILDIV(NUM_IN_PAGE(p) + page_rvalue_count, BITS_BITLENGTH);
+ GC_ASSERT(bitmap_plane_count == HEAP_PAGE_BITMAP_LIMIT - 1 ||
+ bitmap_plane_count == HEAP_PAGE_BITMAP_LIMIT);
+
+ // Skip out of range slots at the head of the page
+ bitset = ~bits[0];
+ bitset >>= NUM_IN_PAGE(p);
+ if (bitset) {
+ gc_sweep_plane(objspace, heap, p, bitset, ctx);
+ }
+ p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
+
+ for (int i = 1; i < bitmap_plane_count; i++) {
+ bitset = ~bits[i];
+ if (bitset) {
+ gc_sweep_plane(objspace, heap, p, bitset, ctx);
+ }
+ p += BITS_BITLENGTH * BASE_SLOT_SIZE;
+ }
+
+ if (!heap->compact_cursor) {
+ gc_setup_mark_bits(sweep_page);
+ }
+
+#if GC_PROFILE_MORE_DETAIL
+ if (gc_prof_enabled(objspace)) {
+ gc_profile_record *record = gc_prof_record(objspace);
+ record->removing_objects += ctx->final_slots + ctx->freed_slots;
+ record->empty_objects += ctx->empty_slots;
+ }
+#endif
+ if (0) fprintf(stderr, "gc_sweep_page(%"PRIdSIZE"): total_slots: %d, freed_slots: %d, empty_slots: %d, final_slots: %d\n",
+ rb_gc_count(),
+ sweep_page->total_slots,
+ ctx->freed_slots, ctx->empty_slots, ctx->final_slots);
+
+ sweep_page->free_slots += ctx->freed_slots + ctx->empty_slots;
+ objspace->profile.total_freed_objects += ctx->freed_slots;
+
+ if (heap_pages_deferred_final && !finalizing) {
+ rb_thread_t *th = GET_THREAD();
+ if (th) {
+ gc_finalize_deferred_register(objspace);
+ }
+ }
+
+#if RGENGC_CHECK_MODE
+ short freelist_len = 0;
+ asan_unlock_freelist(sweep_page);
+ RVALUE *ptr = sweep_page->freelist;
+ while (ptr) {
+ freelist_len++;
+ ptr = ptr->as.free.next;
+ }
+ asan_lock_freelist(sweep_page);
+ if (freelist_len != sweep_page->free_slots) {
+ rb_bug("inconsistent freelist length: expected %d but was %d", sweep_page->free_slots, freelist_len);
+ }
+#endif
+
+ gc_report(2, objspace, "page_sweep: end.\n");
+}
+
+#if !USE_RVARGC
+/* allocate additional minimum page to work */
+static void
+gc_heap_prepare_minimum_pages(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap)
+{
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ if (!heap->free_pages && heap_increment(objspace, size_pool, heap) == FALSE) {
+ /* there is no free after page_sweep() */
+ size_pool_allocatable_pages_set(objspace, size_pool, 1);
+ if (!heap_increment(objspace, size_pool, heap)) { /* can't allocate additional free objects */
+ rb_memerror();
+ }
+ }
+ }
+}
+#endif
+
+static const char *
+gc_mode_name(enum gc_mode mode)
+{
+ switch (mode) {
+ case gc_mode_none: return "none";
+ case gc_mode_marking: return "marking";
+ case gc_mode_sweeping: return "sweeping";
+ case gc_mode_compacting: return "compacting";
+ default: rb_bug("gc_mode_name: unknown mode: %d", (int)mode);
+ }
+}
+
+static void
+gc_mode_transition(rb_objspace_t *objspace, enum gc_mode mode)
+{
+#if RGENGC_CHECK_MODE
+ enum gc_mode prev_mode = gc_mode(objspace);
+ switch (prev_mode) {
+ case gc_mode_none: GC_ASSERT(mode == gc_mode_marking); break;
+ case gc_mode_marking: GC_ASSERT(mode == gc_mode_sweeping); break;
+ case gc_mode_sweeping: GC_ASSERT(mode == gc_mode_none || mode == gc_mode_compacting); break;
+ case gc_mode_compacting: GC_ASSERT(mode == gc_mode_none); break;
+ }
+#endif
+ if (0) fprintf(stderr, "gc_mode_transition: %s->%s\n", gc_mode_name(gc_mode(objspace)), gc_mode_name(mode));
+ gc_mode_set(objspace, mode);
+}
+
+static void
+heap_page_freelist_append(struct heap_page *page, RVALUE *freelist)
+{
+ if (freelist) {
+ asan_unlock_freelist(page);
+ if (page->freelist) {
+ RVALUE *p = page->freelist;
+ asan_unpoison_object((VALUE)p, false);
+ while (p->as.free.next) {
+ RVALUE *prev = p;
+ p = p->as.free.next;
+ asan_poison_object((VALUE)prev);
+ asan_unpoison_object((VALUE)p, false);
+ }
+ p->as.free.next = freelist;
+ asan_poison_object((VALUE)p);
+ }
+ else {
+ page->freelist = freelist;
+ }
+ asan_lock_freelist(page);
+ }
+}
+
+static void
+gc_sweep_start_heap(rb_objspace_t *objspace, rb_heap_t *heap)
+{
+ heap->sweeping_page = ccan_list_top(&heap->pages, struct heap_page, page_node);
+ heap->free_pages = NULL;
+#if GC_ENABLE_INCREMENTAL_MARK
+ heap->pooled_pages = NULL;
+#endif
+ if (!objspace->flags.immediate_sweep) {
+ struct heap_page *page = NULL;
+
+ ccan_list_for_each(&heap->pages, page, page_node) {
+ page->flags.before_sweep = TRUE;
+ }
+ }
+}
+
+#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 4
+__attribute__((noinline))
+#endif
+static void
+gc_sweep_start(rb_objspace_t *objspace)
+{
+ gc_mode_transition(objspace, gc_mode_sweeping);
+
+#if GC_ENABLE_INCREMENTAL_MARK
+ objspace->rincgc.pooled_slots = 0;
+#endif
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
+
+ gc_sweep_start_heap(objspace, heap);
+
+#if USE_RVARGC
+ /* We should call gc_sweep_finish_size_pool for size pools with no pages. */
+ if (heap->sweeping_page == NULL) {
+ GC_ASSERT(heap->total_pages == 0);
+ GC_ASSERT(heap->total_slots == 0);
+ gc_sweep_finish_size_pool(objspace, size_pool);
+ }
+#endif
+ }
+
+ rb_ractor_t *r = NULL;
+ ccan_list_for_each(&GET_VM()->ractor.set, r, vmlr_node) {
+ rb_gc_ractor_newobj_cache_clear(&r->newobj_cache);
+ }
+}
+
+#if USE_RVARGC
+static void
+gc_sweep_finish_size_pool(rb_objspace_t *objspace, rb_size_pool_t *size_pool)
+{
+ rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
+ size_t total_slots = heap->total_slots + SIZE_POOL_TOMB_HEAP(size_pool)->total_slots;
+ size_t total_pages = heap->total_pages + SIZE_POOL_TOMB_HEAP(size_pool)->total_pages;
+ size_t swept_slots = size_pool->freed_slots + size_pool->empty_slots;
+
+ size_t min_free_slots = (size_t)(total_slots * gc_params.heap_free_slots_min_ratio);
+
+ /* If we don't have enough slots and we have pages on the tomb heap, move
+ * pages from the tomb heap to the eden heap. This may prevent page
+ * creation thrashing (frequently allocating and deallocting pages) and
+ * GC thrashing (running GC more frequently than required). */
+ struct heap_page *resurrected_page;
+ while ((swept_slots < min_free_slots || swept_slots < gc_params.heap_init_slots) &&
+ (resurrected_page = heap_page_resurrect(objspace, size_pool))) {
+ swept_slots += resurrected_page->free_slots;
+
+ heap_add_page(objspace, size_pool, heap, resurrected_page);
+ heap_add_freepage(heap, resurrected_page);
+ }
+
+ /* Some size pools may have very few pages (or even no pages). These size pools
+ * should still have allocatable pages. */
+ if (min_free_slots < gc_params.heap_init_slots && swept_slots < gc_params.heap_init_slots) {
+ int multiple = size_pool->slot_size / BASE_SLOT_SIZE;
+ size_t extra_slots = gc_params.heap_init_slots - swept_slots;
+ size_t extend_page_count = CEILDIV(extra_slots * multiple, HEAP_PAGE_OBJ_LIMIT);
+ if (extend_page_count > size_pool->allocatable_pages) {
+ size_pool_allocatable_pages_set(objspace, size_pool, extend_page_count);
+ }
+ }
+
+ if (swept_slots < min_free_slots) {
+ bool grow_heap = is_full_marking(objspace);
+
+ if (!is_full_marking(objspace)) {
+ /* The heap is a growth heap if it freed more slots than had empty
+ * slots and used up all of its allocatable pages. */
+ bool is_growth_heap = (size_pool->empty_slots == 0 ||
+ size_pool->freed_slots > size_pool->empty_slots) &&
+ size_pool->allocatable_pages == 0;
+
+ if (objspace->profile.count - objspace->rgengc.last_major_gc < RVALUE_OLD_AGE) {
+ grow_heap = TRUE;
+ }
+ else if (is_growth_heap) { /* Only growth heaps are allowed to start a major GC. */
+ objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_NOFREE;
+ size_pool->force_major_gc_count++;
+ }
+ }
+
+ if (grow_heap) {
+ size_t extend_page_count = heap_extend_pages(objspace, size_pool, swept_slots, total_slots, total_pages);
+
+ if (extend_page_count > size_pool->allocatable_pages) {
+ size_pool_allocatable_pages_set(objspace, size_pool, extend_page_count);
+ }
+ }
+ }
+}
+#endif
+
+static void
+gc_sweep_finish(rb_objspace_t *objspace)
+{
+ gc_report(1, objspace, "gc_sweep_finish\n");
+
+ gc_prof_set_heap_info(objspace);
+ heap_pages_free_unused_pages(objspace);
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+
+ /* if heap_pages has unused pages, then assign them to increment */
+ size_t tomb_pages = SIZE_POOL_TOMB_HEAP(size_pool)->total_pages;
+ if (size_pool->allocatable_pages < tomb_pages) {
+ size_pool->allocatable_pages = tomb_pages;
+ }
+
+#if USE_RVARGC
+ size_pool->freed_slots = 0;
+ size_pool->empty_slots = 0;
+
+#if GC_ENABLE_INCREMENTAL_MARK
+ if (!will_be_incremental_marking(objspace)) {
+ rb_heap_t *eden_heap = SIZE_POOL_EDEN_HEAP(size_pool);
+ struct heap_page *end_page = eden_heap->free_pages;
+ if (end_page) {
+ while (end_page->free_next) end_page = end_page->free_next;
+ end_page->free_next = eden_heap->pooled_pages;
+ }
+ else {
+ eden_heap->free_pages = eden_heap->pooled_pages;
+ }
+ eden_heap->pooled_pages = NULL;
+ objspace->rincgc.pooled_slots = 0;
+ }
+#endif
+#endif
+ }
+ heap_pages_expand_sorted(objspace);
+
+ gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_END_SWEEP, 0);
+ gc_mode_transition(objspace, gc_mode_none);
+}
+
+static int
+gc_sweep_step(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap)
+{
+ struct heap_page *sweep_page = heap->sweeping_page;
+ int unlink_limit = GC_SWEEP_PAGES_FREEABLE_PER_STEP;
+
+#if GC_ENABLE_INCREMENTAL_MARK
+ int swept_slots = 0;
+#if USE_RVARGC
+ bool need_pool = TRUE;
+#else
+ int need_pool = will_be_incremental_marking(objspace) ? TRUE : FALSE;
+#endif
+
+ gc_report(2, objspace, "gc_sweep_step (need_pool: %d)\n", need_pool);
+#else
+ gc_report(2, objspace, "gc_sweep_step\n");
+#endif
+
+ if (sweep_page == NULL) return FALSE;
+
+#if GC_ENABLE_LAZY_SWEEP
+ gc_prof_sweep_timer_start(objspace);
+#endif
+
+ do {
+ RUBY_DEBUG_LOG("sweep_page:%p", (void *)sweep_page);
+
+ struct gc_sweep_context ctx = {
+ .page = sweep_page,
+ .final_slots = 0,
+ .freed_slots = 0,
+ .empty_slots = 0,
+ };
+ gc_sweep_page(objspace, heap, &ctx);
+ int free_slots = ctx.freed_slots + ctx.empty_slots;
+
+ heap->sweeping_page = ccan_list_next(&heap->pages, sweep_page, page_node);
+
+ if (sweep_page->final_slots + free_slots == sweep_page->total_slots &&
+ heap_pages_freeable_pages > 0 &&
+ unlink_limit > 0) {
+ heap_pages_freeable_pages--;
+ unlink_limit--;
+ /* there are no living objects -> move this page to tomb heap */
+ heap_unlink_page(objspace, heap, sweep_page);
+ heap_add_page(objspace, size_pool, SIZE_POOL_TOMB_HEAP(size_pool), sweep_page);
+ }
+ else if (free_slots > 0) {
+#if USE_RVARGC
+ size_pool->freed_slots += ctx.freed_slots;
+ size_pool->empty_slots += ctx.empty_slots;
+#endif
+
+#if GC_ENABLE_INCREMENTAL_MARK
+ if (need_pool) {
+ heap_add_poolpage(objspace, heap, sweep_page);
+ need_pool = FALSE;
+ }
+ else {
+ heap_add_freepage(heap, sweep_page);
+ swept_slots += free_slots;
+ if (swept_slots > GC_INCREMENTAL_SWEEP_SLOT_COUNT) {
+ break;
+ }
+ }
+#else
+ heap_add_freepage(heap, sweep_page);
+ break;
+#endif
+ }
+ else {
+ sweep_page->free_next = NULL;
+ }
+ } while ((sweep_page = heap->sweeping_page));
+
+ if (!heap->sweeping_page) {
+#if USE_RVARGC
+ gc_sweep_finish_size_pool(objspace, size_pool);
+#endif
+
+ if (!has_sweeping_pages(objspace)) {
+ gc_sweep_finish(objspace);
+ }
+ }
+
+#if GC_ENABLE_LAZY_SWEEP
+ gc_prof_sweep_timer_stop(objspace);
+#endif
+
+ return heap->free_pages != NULL;
+}
+
+static void
+gc_sweep_rest(rb_objspace_t *objspace)
+{
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+
+ while (SIZE_POOL_EDEN_HEAP(size_pool)->sweeping_page) {
+ gc_sweep_step(objspace, size_pool, SIZE_POOL_EDEN_HEAP(size_pool));
+ }
+ }
+}
+
+static void
+gc_sweep_continue(rb_objspace_t *objspace, rb_size_pool_t *sweep_size_pool, rb_heap_t *heap)
+{
+ GC_ASSERT(dont_gc_val() == FALSE);
+ if (!GC_ENABLE_LAZY_SWEEP) return;
+
+ unsigned int lock_lev;
+ gc_enter(objspace, gc_enter_event_sweep_continue, &lock_lev);
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ if (!gc_sweep_step(objspace, size_pool, SIZE_POOL_EDEN_HEAP(size_pool))) {
+#if USE_RVARGC
+ /* sweep_size_pool requires a free slot but sweeping did not yield any. */
+ if (size_pool == sweep_size_pool) {
+ if (size_pool->allocatable_pages > 0) {
+ heap_increment(objspace, size_pool, heap);
+ }
+ else {
+ /* Not allowed to create a new page so finish sweeping. */
+ gc_sweep_rest(objspace);
+ break;
+ }
+ }
+#endif
+ }
+ }
+
+ gc_exit(objspace, gc_enter_event_sweep_continue, &lock_lev);
+}
+
+static void
+invalidate_moved_plane(rb_objspace_t *objspace, struct heap_page *page, uintptr_t p, bits_t bitset)
+{
+ if (bitset) {
+ do {
+ if (bitset & 1) {
+ VALUE forwarding_object = (VALUE)p;
+ VALUE object;
+
+ if (BUILTIN_TYPE(forwarding_object) == T_MOVED) {
+ GC_ASSERT(MARKED_IN_BITMAP(GET_HEAP_PINNED_BITS(forwarding_object), forwarding_object));
+ GC_ASSERT(!MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(forwarding_object), forwarding_object));
+
+ CLEAR_IN_BITMAP(GET_HEAP_PINNED_BITS(forwarding_object), forwarding_object);
+
+ object = rb_gc_location(forwarding_object);
+
+ shape_id_t original_shape_id = 0;
+ if (RB_TYPE_P(object, T_OBJECT)) {
+ original_shape_id = RMOVED(forwarding_object)->original_shape_id;
+ }
+
+ gc_move(objspace, object, forwarding_object, GET_HEAP_PAGE(object)->slot_size, page->slot_size);
+ /* forwarding_object is now our actual object, and "object"
+ * is the free slot for the original page */
+
+ if (original_shape_id) {
+ ROBJECT_SET_SHAPE_ID(forwarding_object, original_shape_id);
+ }
+
+ struct heap_page *orig_page = GET_HEAP_PAGE(object);
+ orig_page->free_slots++;
+ heap_page_add_freeobj(objspace, orig_page, object);
+
+ GC_ASSERT(MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(forwarding_object), forwarding_object));
+ GC_ASSERT(BUILTIN_TYPE(forwarding_object) != T_MOVED);
+ GC_ASSERT(BUILTIN_TYPE(forwarding_object) != T_NONE);
+ }
+ }
+ p += BASE_SLOT_SIZE;
+ bitset >>= 1;
+ } while (bitset);
+ }
+}
+
+static void
+invalidate_moved_page(rb_objspace_t *objspace, struct heap_page *page)
+{
+ int i;
+ bits_t *mark_bits, *pin_bits;
+ bits_t bitset;
+
+ mark_bits = page->mark_bits;
+ pin_bits = page->pinned_bits;
+
+ uintptr_t p = page->start;
+
+ // Skip out of range slots at the head of the page
+ bitset = pin_bits[0] & ~mark_bits[0];
+ bitset >>= NUM_IN_PAGE(p);
+ invalidate_moved_plane(objspace, page, p, bitset);
+ p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
+
+ for (i=1; i < HEAP_PAGE_BITMAP_LIMIT; i++) {
+ /* Moved objects are pinned but never marked. We reuse the pin bits
+ * to indicate there is a moved object in this slot. */
+ bitset = pin_bits[i] & ~mark_bits[i];
+
+ invalidate_moved_plane(objspace, page, p, bitset);
+ p += BITS_BITLENGTH * BASE_SLOT_SIZE;
+ }
+}
+
+static void
+gc_compact_start(rb_objspace_t *objspace)
+{
+ struct heap_page *page = NULL;
+ gc_mode_transition(objspace, gc_mode_compacting);
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(&size_pools[i]);
+ ccan_list_for_each(&heap->pages, page, page_node) {
+ page->flags.before_sweep = TRUE;
+ }
+
+ heap->compact_cursor = ccan_list_tail(&heap->pages, struct heap_page, page_node);
+ heap->compact_cursor_index = 0;
+ }
+
+ if (gc_prof_enabled(objspace)) {
+ gc_profile_record *record = gc_prof_record(objspace);
+ record->moved_objects = objspace->rcompactor.total_moved;
+ }
+
+ memset(objspace->rcompactor.considered_count_table, 0, T_MASK * sizeof(size_t));
+ memset(objspace->rcompactor.moved_count_table, 0, T_MASK * sizeof(size_t));
+ memset(objspace->rcompactor.moved_up_count_table, 0, T_MASK * sizeof(size_t));
+ memset(objspace->rcompactor.moved_down_count_table, 0, T_MASK * sizeof(size_t));
+
+ /* Set up read barrier for pages containing MOVED objects */
+ install_handlers();
+}
+
+static void gc_sweep_compact(rb_objspace_t *objspace);
+
+static void
+gc_sweep(rb_objspace_t *objspace)
+{
+ const unsigned int immediate_sweep = objspace->flags.immediate_sweep;
+
+ gc_report(1, objspace, "gc_sweep: immediate: %d\n", immediate_sweep);
+
+ gc_sweep_start(objspace);
+ if (objspace->flags.during_compacting) {
+ gc_sweep_compact(objspace);
+ }
+
+ if (immediate_sweep) {
+#if !GC_ENABLE_LAZY_SWEEP
+ gc_prof_sweep_timer_start(objspace);
+#endif
+ gc_sweep_rest(objspace);
+#if !GC_ENABLE_LAZY_SWEEP
+ gc_prof_sweep_timer_stop(objspace);
+#endif
+ }
+ else {
+
+ /* Sweep every size pool. */
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ gc_sweep_step(objspace, size_pool, SIZE_POOL_EDEN_HEAP(size_pool));
+ }
+ }
+
+#if !USE_RVARGC
+ rb_size_pool_t *size_pool = &size_pools[0];
+ gc_heap_prepare_minimum_pages(objspace, size_pool, SIZE_POOL_EDEN_HEAP(size_pool));
+#endif
+}
+
+/* Marking - Marking stack */
+
+static stack_chunk_t *
+stack_chunk_alloc(void)
+{
+ stack_chunk_t *res;
+
+ res = malloc(sizeof(stack_chunk_t));
+ if (!res)
+ rb_memerror();
+
+ return res;
+}
+
+static inline int
+is_mark_stack_empty(mark_stack_t *stack)
+{
+ return stack->chunk == NULL;
+}
+
+static size_t
+mark_stack_size(mark_stack_t *stack)
+{
+ size_t size = stack->index;
+ stack_chunk_t *chunk = stack->chunk ? stack->chunk->next : NULL;
+
+ while (chunk) {
+ size += stack->limit;
+ chunk = chunk->next;
+ }
+ return size;
+}
+
+static void
+add_stack_chunk_cache(mark_stack_t *stack, stack_chunk_t *chunk)
+{
+ chunk->next = stack->cache;
+ stack->cache = chunk;
+ stack->cache_size++;
+}
+
+static void
+shrink_stack_chunk_cache(mark_stack_t *stack)
+{
+ stack_chunk_t *chunk;
+
+ if (stack->unused_cache_size > (stack->cache_size/2)) {
+ chunk = stack->cache;
+ stack->cache = stack->cache->next;
+ stack->cache_size--;
+ free(chunk);
+ }
+ stack->unused_cache_size = stack->cache_size;
+}
+
+static void
+push_mark_stack_chunk(mark_stack_t *stack)
+{
+ stack_chunk_t *next;
+
+ GC_ASSERT(stack->index == stack->limit);
+
+ if (stack->cache_size > 0) {
+ next = stack->cache;
+ stack->cache = stack->cache->next;
+ stack->cache_size--;
+ if (stack->unused_cache_size > stack->cache_size)
+ stack->unused_cache_size = stack->cache_size;
+ }
+ else {
+ next = stack_chunk_alloc();
+ }
+ next->next = stack->chunk;
+ stack->chunk = next;
+ stack->index = 0;
+}
+
+static void
+pop_mark_stack_chunk(mark_stack_t *stack)
+{
+ stack_chunk_t *prev;
+
+ prev = stack->chunk->next;
+ GC_ASSERT(stack->index == 0);
+ add_stack_chunk_cache(stack, stack->chunk);
+ stack->chunk = prev;
+ stack->index = stack->limit;
+}
+
+static void
+mark_stack_chunk_list_free(stack_chunk_t *chunk)
+{
+ stack_chunk_t *next = NULL;
+
+ while (chunk != NULL) {
+ next = chunk->next;
+ free(chunk);
+ chunk = next;
+ }
+}
+
+static void
+free_stack_chunks(mark_stack_t *stack)
+{
+ mark_stack_chunk_list_free(stack->chunk);
+}
+
+static void
+mark_stack_free_cache(mark_stack_t *stack)
+{
+ mark_stack_chunk_list_free(stack->cache);
+ stack->cache_size = 0;
+ stack->unused_cache_size = 0;
+}
+
+static void
+push_mark_stack(mark_stack_t *stack, VALUE data)
+{
+ VALUE obj = data;
+ switch (BUILTIN_TYPE(obj)) {
+ case T_OBJECT:
+ case T_CLASS:
+ case T_MODULE:
+ case T_FLOAT:
+ case T_STRING:
+ case T_REGEXP:
+ case T_ARRAY:
+ case T_HASH:
+ case T_STRUCT:
+ case T_BIGNUM:
+ case T_FILE:
+ case T_DATA:
+ case T_MATCH:
+ case T_COMPLEX:
+ case T_RATIONAL:
+ case T_TRUE:
+ case T_FALSE:
+ case T_SYMBOL:
+ case T_IMEMO:
+ case T_ICLASS:
+ if (stack->index == stack->limit) {
+ push_mark_stack_chunk(stack);
+ }
+ stack->chunk->data[stack->index++] = data;
+ return;
+
+ case T_NONE:
+ case T_NIL:
+ case T_FIXNUM:
+ case T_MOVED:
+ case T_ZOMBIE:
+ case T_UNDEF:
+ case T_MASK:
+ rb_bug("push_mark_stack() called for broken object");
+ break;
+
+ case T_NODE:
+ UNEXPECTED_NODE(push_mark_stack);
+ break;
+ }
+
+ rb_bug("rb_gc_mark(): unknown data type 0x%x(%p) %s",
+ BUILTIN_TYPE(obj), (void *)data,
+ is_pointer_to_heap(&rb_objspace, (void *)data) ? "corrupted object" : "non object");
+}
+
+static int
+pop_mark_stack(mark_stack_t *stack, VALUE *data)
+{
+ if (is_mark_stack_empty(stack)) {
+ return FALSE;
+ }
+ if (stack->index == 1) {
+ *data = stack->chunk->data[--stack->index];
+ pop_mark_stack_chunk(stack);
+ }
+ else {
+ *data = stack->chunk->data[--stack->index];
+ }
+ return TRUE;
+}
+
+static void
+init_mark_stack(mark_stack_t *stack)
+{
+ int i;
+
+ MEMZERO(stack, mark_stack_t, 1);
+ stack->index = stack->limit = STACK_CHUNK_SIZE;
+
+ for (i=0; i < 4; i++) {
+ add_stack_chunk_cache(stack, stack_chunk_alloc());
+ }
+ stack->unused_cache_size = stack->cache_size;
+}
+
+/* Marking */
+
#define SET_STACK_END SET_MACHINE_STACK_END(&ec->machine.stack_end)
#define STACK_START (ec->machine.stack_start)
@@ -2021,7 +6490,7 @@ stack_check(rb_execution_context_t *ec, int water_mark)
#define STACKFRAME_FOR_CALL_CFUNC 2048
-int
+MJIT_FUNC_EXPORTED int
rb_ec_stack_check(rb_execution_context_t *ec)
{
return stack_check(ec, STACKFRAME_FOR_CALL_CFUNC);
@@ -2033,221 +6502,285 @@ ruby_stack_check(void)
return stack_check(GET_EC(), STACKFRAME_FOR_CALL_CFUNC);
}
-/* ==================== Marking ==================== */
-
-#define RB_GC_MARK_OR_TRAVERSE(func, obj_or_ptr, obj, check_obj) do { \
- if (!RB_SPECIAL_CONST_P(obj)) { \
- rb_vm_t *vm = GET_VM(); \
- void *objspace = vm->gc.objspace; \
- if (LIKELY(vm->gc.mark_func_data == NULL)) { \
- GC_ASSERT(rb_gc_impl_during_gc_p(objspace)); \
- (func)(objspace, (obj_or_ptr)); \
- } \
- else if (check_obj ? \
- rb_gc_impl_pointer_to_heap_p(objspace, (const void *)obj) && \
- !rb_gc_impl_garbage_object_p(objspace, obj) : \
- true) { \
- GC_ASSERT(!rb_gc_impl_during_gc_p(objspace)); \
- struct gc_mark_func_data_struct *mark_func_data = vm->gc.mark_func_data; \
- vm->gc.mark_func_data = NULL; \
- mark_func_data->mark_func((obj), mark_func_data->data); \
- vm->gc.mark_func_data = mark_func_data; \
- } \
- } \
-} while (0)
-
-static inline void
-gc_mark_internal(VALUE obj)
-{
- RB_GC_MARK_OR_TRAVERSE(rb_gc_impl_mark, obj, obj, false);
-}
-
-void
-rb_gc_mark_movable(VALUE obj)
+ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(static void each_location(rb_objspace_t *objspace, register const VALUE *x, register long n, void (*cb)(rb_objspace_t *, VALUE)));
+static void
+each_location(rb_objspace_t *objspace, register const VALUE *x, register long n, void (*cb)(rb_objspace_t *, VALUE))
{
- gc_mark_internal(obj);
+ VALUE v;
+ while (n--) {
+ v = *x;
+ cb(objspace, v);
+ x++;
+ }
}
-void
-rb_gc_mark_and_move(VALUE *ptr)
+static void
+gc_mark_locations(rb_objspace_t *objspace, const VALUE *start, const VALUE *end, void (*cb)(rb_objspace_t *, VALUE))
{
- RB_GC_MARK_OR_TRAVERSE(rb_gc_impl_mark_and_move, ptr, *ptr, false);
-}
+ long n;
-static inline void
-gc_mark_and_pin_internal(VALUE obj)
-{
- RB_GC_MARK_OR_TRAVERSE(rb_gc_impl_mark_and_pin, obj, obj, false);
+ if (end <= start) return;
+ n = end - start;
+ each_location(objspace, start, n, cb);
}
void
-rb_gc_mark(VALUE obj)
+rb_gc_mark_locations(const VALUE *start, const VALUE *end)
{
- gc_mark_and_pin_internal(obj);
+ gc_mark_locations(&rb_objspace, start, end, gc_mark_maybe);
}
-static inline void
-gc_mark_maybe_internal(VALUE obj)
+static void
+gc_mark_values(rb_objspace_t *objspace, long n, const VALUE *values)
{
- RB_GC_MARK_OR_TRAVERSE(rb_gc_impl_mark_maybe, obj, obj, true);
+ long i;
+
+ for (i=0; i<n; i++) {
+ gc_mark(objspace, values[i]);
+ }
}
void
-rb_gc_mark_maybe(VALUE obj)
+rb_gc_mark_values(long n, const VALUE *values)
{
- gc_mark_maybe_internal(obj);
+ long i;
+ rb_objspace_t *objspace = &rb_objspace;
+
+ for (i=0; i<n; i++) {
+ gc_mark_and_pin(objspace, values[i]);
+ }
}
-void
-rb_gc_mark_weak(VALUE *ptr)
+static void
+gc_mark_stack_values(rb_objspace_t *objspace, long n, const VALUE *values)
{
- if (RB_SPECIAL_CONST_P(*ptr)) return;
-
- rb_vm_t *vm = GET_VM();
- void *objspace = vm->gc.objspace;
- if (LIKELY(vm->gc.mark_func_data == NULL)) {
- GC_ASSERT(rb_gc_impl_during_gc_p(objspace));
+ long i;
- rb_gc_impl_mark_weak(objspace, ptr);
- }
- else {
- GC_ASSERT(!rb_gc_impl_during_gc_p(objspace));
+ for (i=0; i<n; i++) {
+ if (is_markable_object(objspace, values[i])) {
+ gc_mark_and_pin(objspace, values[i]);
+ }
}
}
void
-rb_gc_remove_weak(VALUE parent_obj, VALUE *ptr)
+rb_gc_mark_vm_stack_values(long n, const VALUE *values)
{
- rb_gc_impl_remove_weak(rb_gc_get_objspace(), parent_obj, ptr);
+ rb_objspace_t *objspace = &rb_objspace;
+ gc_mark_stack_values(objspace, n, values);
}
-ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(static void each_location(register const VALUE *x, register long n, void (*cb)(VALUE, void *), void *data));
-static void
-each_location(register const VALUE *x, register long n, void (*cb)(VALUE, void *), void *data)
+static int
+mark_value(st_data_t key, st_data_t value, st_data_t data)
{
- VALUE v;
- while (n--) {
- v = *x;
- cb(v, data);
- x++;
- }
+ rb_objspace_t *objspace = (rb_objspace_t *)data;
+ gc_mark(objspace, (VALUE)value);
+ return ST_CONTINUE;
}
-static void
-each_location_ptr(const VALUE *start, const VALUE *end, void (*cb)(VALUE, void *), void *data)
+static int
+mark_value_pin(st_data_t key, st_data_t value, st_data_t data)
{
- if (end <= start) return;
- each_location(start, end - start, cb, data);
+ rb_objspace_t *objspace = (rb_objspace_t *)data;
+ gc_mark_and_pin(objspace, (VALUE)value);
+ return ST_CONTINUE;
}
static void
-gc_mark_maybe_each_location(VALUE obj, void *data)
+mark_tbl_no_pin(rb_objspace_t *objspace, st_table *tbl)
{
- gc_mark_maybe_internal(obj);
+ if (!tbl || tbl->num_entries == 0) return;
+ st_foreach(tbl, mark_value, (st_data_t)objspace);
}
-void
-rb_gc_mark_locations(const VALUE *start, const VALUE *end)
+static void
+mark_tbl(rb_objspace_t *objspace, st_table *tbl)
{
- each_location_ptr(start, end, gc_mark_maybe_each_location, NULL);
+ if (!tbl || tbl->num_entries == 0) return;
+ st_foreach(tbl, mark_value_pin, (st_data_t)objspace);
}
-void
-rb_gc_mark_values(long n, const VALUE *values)
+static int
+mark_key(st_data_t key, st_data_t value, st_data_t data)
{
- for (long i = 0; i < n; i++) {
- gc_mark_internal(values[i]);
- }
+ rb_objspace_t *objspace = (rb_objspace_t *)data;
+ gc_mark_and_pin(objspace, (VALUE)key);
+ return ST_CONTINUE;
}
-void
-rb_gc_mark_vm_stack_values(long n, const VALUE *values)
+static void
+mark_set(rb_objspace_t *objspace, st_table *tbl)
{
- for (long i = 0; i < n; i++) {
- gc_mark_and_pin_internal(values[i]);
- }
+ if (!tbl) return;
+ st_foreach(tbl, mark_key, (st_data_t)objspace);
}
static int
-mark_key(st_data_t key, st_data_t value, st_data_t data)
+pin_value(st_data_t key, st_data_t value, st_data_t data)
{
- gc_mark_and_pin_internal((VALUE)key);
-
+ rb_objspace_t *objspace = (rb_objspace_t *)data;
+ gc_mark_and_pin(objspace, (VALUE)value);
return ST_CONTINUE;
}
-void
-rb_mark_set(st_table *tbl)
+static void
+mark_finalizer_tbl(rb_objspace_t *objspace, st_table *tbl)
{
if (!tbl) return;
+ st_foreach(tbl, pin_value, (st_data_t)objspace);
+}
- st_foreach(tbl, mark_key, (st_data_t)rb_gc_get_objspace());
+void
+rb_mark_set(st_table *tbl)
+{
+ mark_set(&rb_objspace, tbl);
}
static int
mark_keyvalue(st_data_t key, st_data_t value, st_data_t data)
{
- gc_mark_internal((VALUE)key);
- gc_mark_internal((VALUE)value);
+ rb_objspace_t *objspace = (rb_objspace_t *)data;
+ gc_mark(objspace, (VALUE)key);
+ gc_mark(objspace, (VALUE)value);
return ST_CONTINUE;
}
static int
pin_key_pin_value(st_data_t key, st_data_t value, st_data_t data)
{
- gc_mark_and_pin_internal((VALUE)key);
- gc_mark_and_pin_internal((VALUE)value);
+ rb_objspace_t *objspace = (rb_objspace_t *)data;
+ gc_mark_and_pin(objspace, (VALUE)key);
+ gc_mark_and_pin(objspace, (VALUE)value);
return ST_CONTINUE;
}
static int
pin_key_mark_value(st_data_t key, st_data_t value, st_data_t data)
{
- gc_mark_and_pin_internal((VALUE)key);
- gc_mark_internal((VALUE)value);
+ rb_objspace_t *objspace = (rb_objspace_t *)data;
+ gc_mark_and_pin(objspace, (VALUE)key);
+ gc_mark(objspace, (VALUE)value);
return ST_CONTINUE;
}
static void
-mark_hash(VALUE hash)
+mark_hash(rb_objspace_t *objspace, VALUE hash)
{
if (rb_hash_compare_by_id_p(hash)) {
- rb_hash_stlike_foreach(hash, pin_key_mark_value, 0);
+ rb_hash_stlike_foreach(hash, pin_key_mark_value, (st_data_t)objspace);
}
else {
- rb_hash_stlike_foreach(hash, mark_keyvalue, 0);
+ rb_hash_stlike_foreach(hash, mark_keyvalue, (st_data_t)objspace);
}
- gc_mark_internal(RHASH(hash)->ifnone);
+ if (RHASH_AR_TABLE_P(hash)) {
+ if (LIKELY(during_gc) && RHASH_TRANSIENT_P(hash)) {
+ rb_transient_heap_mark(hash, RHASH_AR_TABLE(hash));
+ }
+ }
+ else {
+ VM_ASSERT(!RHASH_TRANSIENT_P(hash));
+ }
+ gc_mark(objspace, RHASH(hash)->ifnone);
+}
+
+static void
+mark_st(rb_objspace_t *objspace, st_table *tbl)
+{
+ if (!tbl) return;
+ st_foreach(tbl, pin_key_pin_value, (st_data_t)objspace);
}
void
rb_mark_hash(st_table *tbl)
{
- if (!tbl) return;
+ mark_st(&rb_objspace, tbl);
+}
+
+static void
+mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
+{
+ const rb_method_definition_t *def = me->def;
+
+ gc_mark(objspace, me->owner);
+ gc_mark(objspace, me->defined_class);
+
+ if (def) {
+ switch (def->type) {
+ case VM_METHOD_TYPE_ISEQ:
+ if (def->body.iseq.iseqptr) gc_mark(objspace, (VALUE)def->body.iseq.iseqptr);
+ gc_mark(objspace, (VALUE)def->body.iseq.cref);
- st_foreach(tbl, pin_key_pin_value, 0);
+ if (def->iseq_overload && me->defined_class) {
+ // it can be a key of "overloaded_cme" table
+ // so it should be pinned.
+ gc_mark_and_pin(objspace, (VALUE)me);
+ }
+ break;
+ case VM_METHOD_TYPE_ATTRSET:
+ case VM_METHOD_TYPE_IVAR:
+ gc_mark(objspace, def->body.attr.location);
+ break;
+ case VM_METHOD_TYPE_BMETHOD:
+ gc_mark(objspace, def->body.bmethod.proc);
+ if (def->body.bmethod.hooks) rb_hook_list_mark(def->body.bmethod.hooks);
+ break;
+ case VM_METHOD_TYPE_ALIAS:
+ gc_mark(objspace, (VALUE)def->body.alias.original_me);
+ return;
+ case VM_METHOD_TYPE_REFINED:
+ gc_mark(objspace, (VALUE)def->body.refined.orig_me);
+ gc_mark(objspace, (VALUE)def->body.refined.owner);
+ break;
+ case VM_METHOD_TYPE_CFUNC:
+ case VM_METHOD_TYPE_ZSUPER:
+ case VM_METHOD_TYPE_MISSING:
+ case VM_METHOD_TYPE_OPTIMIZED:
+ case VM_METHOD_TYPE_UNDEF:
+ case VM_METHOD_TYPE_NOTIMPLEMENTED:
+ break;
+ }
+ }
}
static enum rb_id_table_iterator_result
-mark_method_entry_i(VALUE me, void *objspace)
+mark_method_entry_i(VALUE me, void *data)
{
- gc_mark_internal(me);
+ rb_objspace_t *objspace = (rb_objspace_t *)data;
+ gc_mark(objspace, me);
return ID_TABLE_CONTINUE;
}
static void
-mark_m_tbl(void *objspace, struct rb_id_table *tbl)
+mark_m_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl)
{
if (tbl) {
rb_id_table_foreach_values(tbl, mark_method_entry_i, objspace);
}
}
+static enum rb_id_table_iterator_result
+mark_const_entry_i(VALUE value, void *data)
+{
+ const rb_const_entry_t *ce = (const rb_const_entry_t *)value;
+ rb_objspace_t *objspace = data;
+
+ gc_mark(objspace, ce->value);
+ gc_mark(objspace, ce->file);
+ return ID_TABLE_CONTINUE;
+}
+
+static void
+mark_const_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl)
+{
+ if (!tbl) return;
+ rb_id_table_foreach_values(tbl, mark_const_entry_i, objspace);
+}
+
#if STACK_GROW_DIRECTION < 0
#define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_END, (end) = STACK_START)
#elif STACK_GROW_DIRECTION > 0
@@ -2258,25 +6791,8 @@ mark_m_tbl(void *objspace, struct rb_id_table *tbl)
((start) = STACK_END, (end) = STACK_START) : ((start) = STACK_START, (end) = STACK_END+(appendix)))
#endif
-static void
-gc_mark_machine_stack_location_maybe(VALUE obj, void *data)
-{
- gc_mark_maybe_internal(obj);
-
-#ifdef RUBY_ASAN_ENABLED
- const rb_execution_context_t *ec = (const rb_execution_context_t *)data;
- void *fake_frame_start;
- void *fake_frame_end;
- bool is_fake_frame = asan_get_fake_stack_extents(
- ec->machine.asan_fake_stack_handle, obj,
- ec->machine.stack_start, ec->machine.stack_end,
- &fake_frame_start, &fake_frame_end
- );
- if (is_fake_frame) {
- each_location_ptr(fake_frame_start, fake_frame_end, gc_mark_maybe_each_location, NULL);
- }
-#endif
-}
+static void each_stack_location(rb_objspace_t *objspace, const rb_execution_context_t *ec,
+ const VALUE *stack_start, const VALUE *stack_end, void (*cb)(rb_objspace_t *, VALUE));
#if defined(__wasm__)
@@ -2293,26 +6809,26 @@ rb_mark_locations(void *begin, void *end)
# if defined(__EMSCRIPTEN__)
static void
-mark_current_machine_context(rb_execution_context_t *ec)
+mark_current_machine_context(rb_objspace_t *objspace, rb_execution_context_t *ec)
{
emscripten_scan_stack(rb_mark_locations);
- each_location_ptr(rb_stack_range_tmp[0], rb_stack_range_tmp[1], gc_mark_maybe_each_location, NULL);
+ each_stack_location(objspace, ec, rb_stack_range_tmp[0], rb_stack_range_tmp[1], gc_mark_maybe);
emscripten_scan_registers(rb_mark_locations);
- each_location_ptr(rb_stack_range_tmp[0], rb_stack_range_tmp[1], gc_mark_maybe_each_location, NULL);
+ each_stack_location(objspace, ec, rb_stack_range_tmp[0], rb_stack_range_tmp[1], gc_mark_maybe);
}
# else // use Asyncify version
static void
-mark_current_machine_context(rb_execution_context_t *ec)
+mark_current_machine_context(rb_objspace_t *objspace, rb_execution_context_t *ec)
{
VALUE *stack_start, *stack_end;
SET_STACK_END;
GET_STACK_BOUNDS(stack_start, stack_end, 1);
- each_location_ptr(stack_start, stack_end, gc_mark_maybe_each_location, NULL);
+ each_stack_location(objspace, ec, stack_start, stack_end, gc_mark_maybe);
rb_wasm_scan_locals(rb_mark_locations);
- each_location_ptr(rb_stack_range_tmp[0], rb_stack_range_tmp[1], gc_mark_maybe_each_location, NULL);
+ each_stack_location(objspace, ec, rb_stack_range_tmp[0], rb_stack_range_tmp[1], gc_mark_maybe);
}
# endif
@@ -2320,7 +6836,7 @@ mark_current_machine_context(rb_execution_context_t *ec)
#else // !defined(__wasm__)
static void
-mark_current_machine_context(rb_execution_context_t *ec)
+mark_current_machine_context(rb_objspace_t *objspace, rb_execution_context_t *ec)
{
union {
rb_jmp_buf j;
@@ -2339,147 +6855,378 @@ mark_current_machine_context(rb_execution_context_t *ec)
SET_STACK_END;
GET_STACK_BOUNDS(stack_start, stack_end, 1);
- void *data =
-#ifdef RUBY_ASAN_ENABLED
- ec;
-#else
- NULL;
-#endif
+ each_location(objspace, save_regs_gc_mark.v, numberof(save_regs_gc_mark.v), gc_mark_maybe);
- each_location(save_regs_gc_mark.v, numberof(save_regs_gc_mark.v), gc_mark_machine_stack_location_maybe, data);
- each_location_ptr(stack_start, stack_end, gc_mark_machine_stack_location_maybe, data);
+ each_stack_location(objspace, ec, stack_start, stack_end, gc_mark_maybe);
}
#endif
-void
-rb_gc_mark_machine_context(const rb_execution_context_t *ec)
+static void
+each_machine_stack_value(const rb_execution_context_t *ec, void (*cb)(rb_objspace_t *, VALUE))
{
+ rb_objspace_t *objspace = &rb_objspace;
VALUE *stack_start, *stack_end;
GET_STACK_BOUNDS(stack_start, stack_end, 0);
- RUBY_DEBUG_LOG("ec->th:%u stack_start:%p stack_end:%p", rb_ec_thread_ptr(ec)->serial, stack_start, stack_end);
-
- void *data =
-#ifdef RUBY_ASAN_ENABLED
- /* gc_mark_machine_stack_location_maybe() uses data as const */
- (rb_execution_context_t *)ec;
-#else
- NULL;
-#endif
+ each_stack_location(objspace, ec, stack_start, stack_end, cb);
+}
- each_location_ptr(stack_start, stack_end, gc_mark_machine_stack_location_maybe, data);
- int num_regs = sizeof(ec->machine.regs)/(sizeof(VALUE));
- each_location((VALUE*)&ec->machine.regs, num_regs, gc_mark_machine_stack_location_maybe, data);
+void
+rb_gc_mark_machine_stack(const rb_execution_context_t *ec)
+{
+ each_machine_stack_value(ec, gc_mark_maybe);
}
-static int
-rb_mark_tbl_i(st_data_t key, st_data_t value, st_data_t data)
+static void
+each_stack_location(rb_objspace_t *objspace, const rb_execution_context_t *ec,
+ const VALUE *stack_start, const VALUE *stack_end, void (*cb)(rb_objspace_t *, VALUE))
{
- gc_mark_and_pin_internal((VALUE)value);
- return ST_CONTINUE;
+ gc_mark_locations(objspace, stack_start, stack_end, cb);
+
+#if defined(__mc68000__)
+ gc_mark_locations(objspace,
+ (VALUE*)((char*)stack_start + 2),
+ (VALUE*)((char*)stack_end - 2), cb);
+#endif
}
void
rb_mark_tbl(st_table *tbl)
{
- if (!tbl || tbl->num_entries == 0) return;
+ mark_tbl(&rb_objspace, tbl);
+}
- st_foreach(tbl, rb_mark_tbl_i, 0);
+void
+rb_mark_tbl_no_pin(st_table *tbl)
+{
+ mark_tbl_no_pin(&rb_objspace, tbl);
}
static void
-gc_mark_tbl_no_pin(st_table *tbl)
+gc_mark_maybe(rb_objspace_t *objspace, VALUE obj)
{
- if (!tbl || tbl->num_entries == 0) return;
+ (void)VALGRIND_MAKE_MEM_DEFINED(&obj, sizeof(obj));
+
+ if (is_pointer_to_heap(objspace, (void *)obj)) {
+ void *ptr = asan_unpoison_object_temporary(obj);
+
+ /* Garbage can live on the stack, so do not mark or pin */
+ switch (BUILTIN_TYPE(obj)) {
+ case T_ZOMBIE:
+ case T_NONE:
+ break;
+ default:
+ gc_mark_and_pin(objspace, obj);
+ break;
+ }
- st_foreach(tbl, gc_mark_tbl_no_pin_i, 0);
+ if (ptr) {
+ GC_ASSERT(BUILTIN_TYPE(obj) == T_NONE);
+ asan_poison_object(obj);
+ }
+ }
}
void
-rb_mark_tbl_no_pin(st_table *tbl)
+rb_gc_mark_maybe(VALUE obj)
{
- gc_mark_tbl_no_pin(tbl);
+ gc_mark_maybe(&rb_objspace, obj);
}
-static enum rb_id_table_iterator_result
-mark_cvc_tbl_i(VALUE cvc_entry, void *objspace)
+static inline int
+gc_mark_set(rb_objspace_t *objspace, VALUE obj)
{
- struct rb_cvar_class_tbl_entry *entry;
+ ASSERT_vm_locking();
+ if (RVALUE_MARKED(obj)) return 0;
+ MARK_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj);
+ return 1;
+}
- entry = (struct rb_cvar_class_tbl_entry *)cvc_entry;
+static int
+gc_remember_unprotected(rb_objspace_t *objspace, VALUE obj)
+{
+ struct heap_page *page = GET_HEAP_PAGE(obj);
+ bits_t *uncollectible_bits = &page->uncollectible_bits[0];
- RUBY_ASSERT(entry->cref == 0 || (BUILTIN_TYPE((VALUE)entry->cref) == T_IMEMO && IMEMO_TYPE_P(entry->cref, imemo_cref)));
- gc_mark_internal((VALUE)entry->cref);
+ if (!MARKED_IN_BITMAP(uncollectible_bits, obj)) {
+ page->flags.has_uncollectible_shady_objects = TRUE;
+ MARK_IN_BITMAP(uncollectible_bits, obj);
+ objspace->rgengc.uncollectible_wb_unprotected_objects++;
- return ID_TABLE_CONTINUE;
+#if RGENGC_PROFILE > 0
+ objspace->profile.total_remembered_shady_object_count++;
+#if RGENGC_PROFILE >= 2
+ objspace->profile.remembered_shady_object_count_types[BUILTIN_TYPE(obj)]++;
+#endif
+#endif
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
}
static void
-mark_cvc_tbl(void *objspace, VALUE klass)
+rgengc_check_relation(rb_objspace_t *objspace, VALUE obj)
{
- struct rb_id_table *tbl = RCLASS_CVC_TBL(klass);
- if (tbl) {
- rb_id_table_foreach_values(tbl, mark_cvc_tbl_i, objspace);
+ const VALUE old_parent = objspace->rgengc.parent_object;
+
+ if (old_parent) { /* parent object is old */
+ if (RVALUE_WB_UNPROTECTED(obj)) {
+ if (gc_remember_unprotected(objspace, obj)) {
+ gc_report(2, objspace, "relation: (O->S) %s -> %s\n", obj_info(old_parent), obj_info(obj));
+ }
+ }
+ else {
+ if (!RVALUE_OLD_P(obj)) {
+ if (RVALUE_MARKED(obj)) {
+ /* An object pointed from an OLD object should be OLD. */
+ gc_report(2, objspace, "relation: (O->unmarked Y) %s -> %s\n", obj_info(old_parent), obj_info(obj));
+ RVALUE_AGE_SET_OLD(objspace, obj);
+ if (is_incremental_marking(objspace)) {
+ if (!RVALUE_MARKING(obj)) {
+ gc_grey(objspace, obj);
+ }
+ }
+ else {
+ rgengc_remember(objspace, obj);
+ }
+ }
+ else {
+ gc_report(2, objspace, "relation: (O->Y) %s -> %s\n", obj_info(old_parent), obj_info(obj));
+ RVALUE_AGE_SET_CANDIDATE(objspace, obj);
+ }
+ }
+ }
}
+
+ GC_ASSERT(old_parent == objspace->rgengc.parent_object);
}
-static bool
-gc_declarative_marking_p(const rb_data_type_t *type)
+static void
+gc_grey(rb_objspace_t *objspace, VALUE obj)
{
- return (type->flags & RUBY_TYPED_DECL_MARKING) != 0;
+#if RGENGC_CHECK_MODE
+ if (RVALUE_MARKED(obj) == FALSE) rb_bug("gc_grey: %s is not marked.", obj_info(obj));
+ if (RVALUE_MARKING(obj) == TRUE) rb_bug("gc_grey: %s is marking/remembered.", obj_info(obj));
+#endif
+
+#if GC_ENABLE_INCREMENTAL_MARK
+ if (is_incremental_marking(objspace)) {
+ MARK_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), obj);
+ }
+#endif
+
+ push_mark_stack(&objspace->mark_stack, obj);
}
-static enum rb_id_table_iterator_result
-mark_const_table_i(VALUE value, void *objspace)
+static void
+gc_aging(rb_objspace_t *objspace, VALUE obj)
{
- const rb_const_entry_t *ce = (const rb_const_entry_t *)value;
+ struct heap_page *page = GET_HEAP_PAGE(obj);
- gc_mark_internal(ce->value);
- gc_mark_internal(ce->file);
+ GC_ASSERT(RVALUE_MARKING(obj) == FALSE);
+ check_rvalue_consistency(obj);
- return ID_TABLE_CONTINUE;
+ if (!RVALUE_PAGE_WB_UNPROTECTED(page, obj)) {
+ if (!RVALUE_OLD_P(obj)) {
+ gc_report(3, objspace, "gc_aging: YOUNG: %s\n", obj_info(obj));
+ RVALUE_AGE_INC(objspace, obj);
+ }
+ else if (is_full_marking(objspace)) {
+ GC_ASSERT(RVALUE_PAGE_UNCOLLECTIBLE(page, obj) == FALSE);
+ RVALUE_PAGE_OLD_UNCOLLECTIBLE_SET(objspace, page, obj);
+ }
+ }
+ check_rvalue_consistency(obj);
+
+ objspace->marked_slots++;
}
-void
-rb_gc_mark_roots(void *objspace, const char **categoryp)
+NOINLINE(static void gc_mark_ptr(rb_objspace_t *objspace, VALUE obj));
+static void reachable_objects_from_callback(VALUE obj);
+
+static void
+gc_mark_ptr(rb_objspace_t *objspace, VALUE obj)
{
- rb_execution_context_t *ec = GET_EC();
- rb_vm_t *vm = rb_ec_vm_ptr(ec);
+ if (LIKELY(during_gc)) {
+ rgengc_check_relation(objspace, obj);
+ if (!gc_mark_set(objspace, obj)) return; /* already marked */
-#define MARK_CHECKPOINT(category) do { \
- if (categoryp) *categoryp = category; \
-} while (0)
+ if (0) { // for debug GC marking miss
+ if (objspace->rgengc.parent_object) {
+ RUBY_DEBUG_LOG("%p (%s) parent:%p (%s)",
+ (void *)obj, obj_type_name(obj),
+ (void *)objspace->rgengc.parent_object, obj_type_name(objspace->rgengc.parent_object));
+ }
+ else {
+ RUBY_DEBUG_LOG("%p (%s)", (void *)obj, obj_type_name(obj));
+ }
+ }
- MARK_CHECKPOINT("vm");
- rb_vm_mark(vm);
- if (vm->self) gc_mark_internal(vm->self);
+ if (UNLIKELY(RB_TYPE_P(obj, T_NONE))) {
+ rp(obj);
+ rb_bug("try to mark T_NONE object"); /* check here will help debugging */
+ }
+ gc_aging(objspace, obj);
+ gc_grey(objspace, obj);
+ }
+ else {
+ reachable_objects_from_callback(obj);
+ }
+}
- MARK_CHECKPOINT("machine_context");
- mark_current_machine_context(ec);
+static inline void
+gc_pin(rb_objspace_t *objspace, VALUE obj)
+{
+ GC_ASSERT(is_markable_object(objspace, obj));
+ if (UNLIKELY(objspace->flags.during_compacting)) {
+ if (LIKELY(during_gc)) {
+ MARK_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj);
+ }
+ }
+}
- MARK_CHECKPOINT("end_proc");
- rb_mark_end_proc();
+static inline void
+gc_mark_and_pin(rb_objspace_t *objspace, VALUE obj)
+{
+ if (!is_markable_object(objspace, obj)) return;
+ gc_pin(objspace, obj);
+ gc_mark_ptr(objspace, obj);
+}
- MARK_CHECKPOINT("global_tbl");
- rb_gc_mark_global_tbl();
+static inline void
+gc_mark(rb_objspace_t *objspace, VALUE obj)
+{
+ if (!is_markable_object(objspace, obj)) return;
+ gc_mark_ptr(objspace, obj);
+}
+
+void
+rb_gc_mark_movable(VALUE ptr)
+{
+ gc_mark(&rb_objspace, ptr);
+}
+
+void
+rb_gc_mark(VALUE ptr)
+{
+ gc_mark_and_pin(&rb_objspace, ptr);
+}
-#if USE_YJIT
- void rb_yjit_root_mark(void); // in Rust
+/* CAUTION: THIS FUNCTION ENABLE *ONLY BEFORE* SWEEPING.
+ * This function is only for GC_END_MARK timing.
+ */
+
+int
+rb_objspace_marked_object_p(VALUE obj)
+{
+ return RVALUE_MARKED(obj) ? TRUE : FALSE;
+}
- if (rb_yjit_enabled_p) {
- MARK_CHECKPOINT("YJIT");
- rb_yjit_root_mark();
+static inline void
+gc_mark_set_parent(rb_objspace_t *objspace, VALUE obj)
+{
+ if (RVALUE_OLD_P(obj)) {
+ objspace->rgengc.parent_object = obj;
}
-#endif
+ else {
+ objspace->rgengc.parent_object = Qfalse;
+ }
+}
- MARK_CHECKPOINT("finish");
-#undef MARK_CHECKPOINT
+static void
+gc_mark_imemo(rb_objspace_t *objspace, VALUE obj)
+{
+ switch (imemo_type(obj)) {
+ case imemo_env:
+ {
+ const rb_env_t *env = (const rb_env_t *)obj;
+
+ if (LIKELY(env->ep)) {
+ // just after newobj() can be NULL here.
+ GC_ASSERT(env->ep[VM_ENV_DATA_INDEX_ENV] == obj);
+ GC_ASSERT(VM_ENV_ESCAPED_P(env->ep));
+ gc_mark_values(objspace, (long)env->env_size, env->env);
+ VM_ENV_FLAGS_SET(env->ep, VM_ENV_FLAG_WB_REQUIRED);
+ gc_mark(objspace, (VALUE)rb_vm_env_prev_env(env));
+ gc_mark(objspace, (VALUE)env->iseq);
+ }
+ }
+ return;
+ case imemo_cref:
+ gc_mark(objspace, RANY(obj)->as.imemo.cref.klass_or_self);
+ gc_mark(objspace, (VALUE)RANY(obj)->as.imemo.cref.next);
+ gc_mark(objspace, RANY(obj)->as.imemo.cref.refinements);
+ return;
+ case imemo_svar:
+ gc_mark(objspace, RANY(obj)->as.imemo.svar.cref_or_me);
+ gc_mark(objspace, RANY(obj)->as.imemo.svar.lastline);
+ gc_mark(objspace, RANY(obj)->as.imemo.svar.backref);
+ gc_mark(objspace, RANY(obj)->as.imemo.svar.others);
+ return;
+ case imemo_throw_data:
+ gc_mark(objspace, RANY(obj)->as.imemo.throw_data.throw_obj);
+ return;
+ case imemo_ifunc:
+ gc_mark_maybe(objspace, (VALUE)RANY(obj)->as.imemo.ifunc.data);
+ return;
+ case imemo_memo:
+ gc_mark(objspace, RANY(obj)->as.imemo.memo.v1);
+ gc_mark(objspace, RANY(obj)->as.imemo.memo.v2);
+ gc_mark_maybe(objspace, RANY(obj)->as.imemo.memo.u3.value);
+ return;
+ case imemo_ment:
+ mark_method_entry(objspace, &RANY(obj)->as.imemo.ment);
+ return;
+ case imemo_iseq:
+ rb_iseq_mark((rb_iseq_t *)obj);
+ return;
+ case imemo_tmpbuf:
+ {
+ const rb_imemo_tmpbuf_t *m = &RANY(obj)->as.imemo.alloc;
+ do {
+ rb_gc_mark_locations(m->ptr, m->ptr + m->cnt);
+ } while ((m = m->next) != NULL);
+ }
+ return;
+ case imemo_ast:
+ rb_ast_mark(&RANY(obj)->as.imemo.ast);
+ return;
+ case imemo_parser_strterm:
+ rb_strterm_mark(obj);
+ return;
+ case imemo_callinfo:
+ return;
+ case imemo_callcache:
+ {
+ const struct rb_callcache *cc = (const struct rb_callcache *)obj;
+ // should not mark klass here
+ gc_mark(objspace, (VALUE)vm_cc_cme(cc));
+ }
+ return;
+ case imemo_constcache:
+ {
+ const struct iseq_inline_constant_cache_entry *ice = (struct iseq_inline_constant_cache_entry *)obj;
+ gc_mark(objspace, ice->value);
+ }
+ return;
+#if VM_CHECK_MODE > 0
+ default:
+ VM_UNREACHABLE(gc_mark_imemo);
+#endif
+ }
}
-void
-rb_gc_mark_children(void *objspace, VALUE obj)
+static void mark_cvc_tbl(rb_objspace_t *objspace, VALUE klass);
+
+static void
+gc_mark_children(rb_objspace_t *objspace, VALUE obj)
{
+ register RVALUE *any = RANY(obj);
+ gc_mark_set_parent(objspace, obj);
+
if (FL_TEST(obj, FL_EXIVAR)) {
rb_mark_generic_ivar(obj);
}
@@ -2488,10 +7235,8 @@ rb_gc_mark_children(void *objspace, VALUE obj)
case T_FLOAT:
case T_BIGNUM:
case T_SYMBOL:
- /* Not immediates, but does not have references and singleton class.
- *
- * RSYMBOL(obj)->fstr intentionally not marked. See log for 96815f1e
- * ("symbol.c: remove rb_gc_mark_symbols()") */
+ /* Not immediates, but does not have references and singleton
+ * class */
return;
case T_NIL:
@@ -2504,43 +7249,30 @@ rb_gc_mark_children(void *objspace, VALUE obj)
break;
case T_IMEMO:
- rb_imemo_mark_and_move(obj, false);
+ gc_mark_imemo(objspace, obj);
return;
default:
break;
}
- gc_mark_internal(RBASIC(obj)->klass);
+ gc_mark(objspace, any->as.basic.klass);
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
- if (FL_TEST(obj, FL_SINGLETON)) {
- gc_mark_internal(RCLASS_ATTACHED_OBJECT(obj));
- }
- // Continue to the shared T_CLASS/T_MODULE
case T_MODULE:
if (RCLASS_SUPER(obj)) {
- gc_mark_internal(RCLASS_SUPER(obj));
+ gc_mark(objspace, RCLASS_SUPER(obj));
}
+ if (!RCLASS_EXT(obj)) break;
mark_m_tbl(objspace, RCLASS_M_TBL(obj));
mark_cvc_tbl(objspace, obj);
- rb_cc_table_mark(obj);
- if (rb_shape_obj_too_complex(obj)) {
- gc_mark_tbl_no_pin((st_table *)RCLASS_IVPTR(obj));
- }
- else {
- for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
- gc_mark_internal(RCLASS_IVPTR(obj)[i]);
- }
- }
-
- if (RCLASS_CONST_TBL(obj)) {
- rb_id_table_foreach_values(RCLASS_CONST_TBL(obj), mark_const_table_i, objspace);
+ cc_table_mark(objspace, obj);
+ for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
+ gc_mark(objspace, RCLASS_IVPTR(obj)[i]);
}
-
- gc_mark_internal(RCLASS_EXT(obj)->classpath);
+ mark_const_tbl(objspace, RCLASS_CONST_TBL(obj));
break;
case T_ICLASS:
@@ -2548,248 +7280,2013 @@ rb_gc_mark_children(void *objspace, VALUE obj)
mark_m_tbl(objspace, RCLASS_M_TBL(obj));
}
if (RCLASS_SUPER(obj)) {
- gc_mark_internal(RCLASS_SUPER(obj));
+ gc_mark(objspace, RCLASS_SUPER(obj));
}
+ if (!RCLASS_EXT(obj)) break;
if (RCLASS_INCLUDER(obj)) {
- gc_mark_internal(RCLASS_INCLUDER(obj));
+ gc_mark(objspace, RCLASS_INCLUDER(obj));
}
mark_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj));
- rb_cc_table_mark(obj);
+ cc_table_mark(objspace, obj);
break;
case T_ARRAY:
if (ARY_SHARED_P(obj)) {
VALUE root = ARY_SHARED_ROOT(obj);
- gc_mark_internal(root);
+ gc_mark(objspace, root);
}
else {
- long len = RARRAY_LEN(obj);
- const VALUE *ptr = RARRAY_CONST_PTR(obj);
- for (long i = 0; i < len; i++) {
- gc_mark_internal(ptr[i]);
+ long i, len = RARRAY_LEN(obj);
+ const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(obj);
+ for (i=0; i < len; i++) {
+ gc_mark(objspace, ptr[i]);
+ }
+
+ if (LIKELY(during_gc)) {
+ if (!ARY_EMBED_P(obj) && RARRAY_TRANSIENT_P(obj)) {
+ rb_transient_heap_mark(obj, ptr);
+ }
}
}
break;
case T_HASH:
- mark_hash(obj);
+ mark_hash(objspace, obj);
break;
case T_STRING:
if (STR_SHARED_P(obj)) {
- if (STR_EMBED_P(RSTRING(obj)->as.heap.aux.shared)) {
- /* Embedded shared strings cannot be moved because this string
- * points into the slot of the shared string. There may be code
- * using the RSTRING_PTR on the stack, which would pin this
- * string but not pin the shared string, causing it to move. */
- gc_mark_and_pin_internal(RSTRING(obj)->as.heap.aux.shared);
- }
- else {
- gc_mark_internal(RSTRING(obj)->as.heap.aux.shared);
- }
+ gc_mark(objspace, any->as.string.as.heap.aux.shared);
}
break;
- case T_DATA: {
- void *const ptr = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
-
- if (ptr) {
- if (RTYPEDDATA_P(obj) && gc_declarative_marking_p(RTYPEDDATA(obj)->type)) {
- size_t *offset_list = (size_t *)RTYPEDDATA(obj)->type->function.dmark;
-
- for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) {
- gc_mark_internal(*(VALUE *)((char *)ptr + offset));
- }
- }
- else {
+ case T_DATA:
+ {
+ void *const ptr = DATA_PTR(obj);
+ if (ptr) {
RUBY_DATA_FUNC mark_func = RTYPEDDATA_P(obj) ?
- RTYPEDDATA(obj)->type->function.dmark :
- RDATA(obj)->dmark;
+ any->as.typeddata.type->function.dmark :
+ any->as.data.dmark;
if (mark_func) (*mark_func)(ptr);
}
}
-
break;
- }
- case T_OBJECT: {
- rb_shape_t *shape = rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj));
+ case T_OBJECT:
+ {
+ rb_shape_t *shape = rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj));
+ if (rb_shape_obj_too_complex(obj)) {
+ mark_tbl_no_pin(objspace, ROBJECT_IV_HASH(obj));
+ }
+ else {
+ const VALUE * const ptr = ROBJECT_IVPTR(obj);
- if (rb_shape_obj_too_complex(obj)) {
- gc_mark_tbl_no_pin(ROBJECT_IV_HASH(obj));
- }
- else {
- const VALUE * const ptr = ROBJECT_IVPTR(obj);
+ uint32_t i, len = ROBJECT_IV_COUNT(obj);
+ for (i = 0; i < len; i++) {
+ gc_mark(objspace, ptr[i]);
+ }
- uint32_t len = ROBJECT_IV_COUNT(obj);
- for (uint32_t i = 0; i < len; i++) {
- gc_mark_internal(ptr[i]);
+ if (LIKELY(during_gc) &&
+ ROBJ_TRANSIENT_P(obj)) {
+ rb_transient_heap_mark(obj, ptr);
+ }
}
- }
+ if (shape) {
+ VALUE klass = RBASIC_CLASS(obj);
- if (shape) {
- VALUE klass = RBASIC_CLASS(obj);
-
- // Increment max_iv_count if applicable, used to determine size pool allocation
- attr_index_t num_of_ivs = shape->next_iv_index;
- if (RCLASS_EXT(klass)->max_iv_count < num_of_ivs) {
- RCLASS_EXT(klass)->max_iv_count = num_of_ivs;
+ // Increment max_iv_count if applicable, used to determine size pool allocation
+ uint32_t num_of_ivs = shape->next_iv_index;
+ if (RCLASS_EXT(klass)->max_iv_count < num_of_ivs) {
+ RCLASS_EXT(klass)->max_iv_count = num_of_ivs;
+ }
}
}
-
break;
- }
case T_FILE:
- if (RFILE(obj)->fptr) {
- gc_mark_internal(RFILE(obj)->fptr->self);
- gc_mark_internal(RFILE(obj)->fptr->pathv);
- gc_mark_internal(RFILE(obj)->fptr->tied_io_for_writing);
- gc_mark_internal(RFILE(obj)->fptr->writeconv_asciicompat);
- gc_mark_internal(RFILE(obj)->fptr->writeconv_pre_ecopts);
- gc_mark_internal(RFILE(obj)->fptr->encs.ecopts);
- gc_mark_internal(RFILE(obj)->fptr->write_lock);
- gc_mark_internal(RFILE(obj)->fptr->timeout);
+ if (any->as.file.fptr) {
+ gc_mark(objspace, any->as.file.fptr->self);
+ gc_mark(objspace, any->as.file.fptr->pathv);
+ gc_mark(objspace, any->as.file.fptr->tied_io_for_writing);
+ gc_mark(objspace, any->as.file.fptr->writeconv_asciicompat);
+ gc_mark(objspace, any->as.file.fptr->writeconv_pre_ecopts);
+ gc_mark(objspace, any->as.file.fptr->encs.ecopts);
+ gc_mark(objspace, any->as.file.fptr->write_lock);
+ gc_mark(objspace, any->as.file.fptr->timeout);
}
break;
case T_REGEXP:
- gc_mark_internal(RREGEXP(obj)->src);
+ gc_mark(objspace, any->as.regexp.src);
break;
case T_MATCH:
- gc_mark_internal(RMATCH(obj)->regexp);
- if (RMATCH(obj)->str) {
- gc_mark_internal(RMATCH(obj)->str);
+ gc_mark(objspace, any->as.match.regexp);
+ if (any->as.match.str) {
+ gc_mark(objspace, any->as.match.str);
}
break;
case T_RATIONAL:
- gc_mark_internal(RRATIONAL(obj)->num);
- gc_mark_internal(RRATIONAL(obj)->den);
+ gc_mark(objspace, any->as.rational.num);
+ gc_mark(objspace, any->as.rational.den);
break;
case T_COMPLEX:
- gc_mark_internal(RCOMPLEX(obj)->real);
- gc_mark_internal(RCOMPLEX(obj)->imag);
+ gc_mark(objspace, any->as.complex.real);
+ gc_mark(objspace, any->as.complex.imag);
break;
- case T_STRUCT: {
- const long len = RSTRUCT_LEN(obj);
- const VALUE * const ptr = RSTRUCT_CONST_PTR(obj);
+ case T_STRUCT:
+ {
+ long i;
+ const long len = RSTRUCT_LEN(obj);
+ const VALUE * const ptr = RSTRUCT_CONST_PTR(obj);
- for (long i = 0; i < len; i++) {
- gc_mark_internal(ptr[i]);
- }
+ for (i=0; i<len; i++) {
+ gc_mark(objspace, ptr[i]);
+ }
+ if (LIKELY(during_gc) &&
+ RSTRUCT_TRANSIENT_P(obj)) {
+ rb_transient_heap_mark(obj, ptr);
+ }
+ }
break;
- }
default:
+#if GC_DEBUG
+ rb_gcdebug_print_obj_condition((VALUE)obj);
+#endif
if (BUILTIN_TYPE(obj) == T_MOVED) rb_bug("rb_gc_mark(): %p is T_MOVED", (void *)obj);
if (BUILTIN_TYPE(obj) == T_NONE) rb_bug("rb_gc_mark(): %p is T_NONE", (void *)obj);
if (BUILTIN_TYPE(obj) == T_ZOMBIE) rb_bug("rb_gc_mark(): %p is T_ZOMBIE", (void *)obj);
rb_bug("rb_gc_mark(): unknown data type 0x%x(%p) %s",
- BUILTIN_TYPE(obj), (void *)obj,
- rb_gc_impl_pointer_to_heap_p(rb_gc_get_objspace(), (void *)obj) ? "corrupted object" : "non object");
+ BUILTIN_TYPE(obj), (void *)any,
+ is_pointer_to_heap(objspace, any) ? "corrupted object" : "non object");
}
}
-size_t
-rb_gc_obj_optimal_size(VALUE obj)
+/**
+ * incremental: 0 -> not incremental (do all)
+ * incremental: n -> mark at most `n' objects
+ */
+static inline int
+gc_mark_stacked_objects(rb_objspace_t *objspace, int incremental, size_t count)
+{
+ mark_stack_t *mstack = &objspace->mark_stack;
+ VALUE obj;
+#if GC_ENABLE_INCREMENTAL_MARK
+ size_t marked_slots_at_the_beginning = objspace->marked_slots;
+ size_t popped_count = 0;
+#endif
+
+ while (pop_mark_stack(mstack, &obj)) {
+ if (UNDEF_P(obj)) continue; /* skip */
+
+ if (RGENGC_CHECK_MODE && !RVALUE_MARKED(obj)) {
+ rb_bug("gc_mark_stacked_objects: %s is not marked.", obj_info(obj));
+ }
+ gc_mark_children(objspace, obj);
+
+#if GC_ENABLE_INCREMENTAL_MARK
+ if (incremental) {
+ if (RGENGC_CHECK_MODE && !RVALUE_MARKING(obj)) {
+ rb_bug("gc_mark_stacked_objects: incremental, but marking bit is 0");
+ }
+ CLEAR_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), obj);
+ popped_count++;
+
+ if (popped_count + (objspace->marked_slots - marked_slots_at_the_beginning) > count) {
+ break;
+ }
+ }
+ else {
+ /* just ignore marking bits */
+ }
+#endif
+ }
+
+ if (RGENGC_CHECK_MODE >= 3) gc_verify_internal_consistency(objspace);
+
+ if (is_mark_stack_empty(mstack)) {
+ shrink_stack_chunk_cache(mstack);
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+static int
+gc_mark_stacked_objects_incremental(rb_objspace_t *objspace, size_t count)
{
- switch (BUILTIN_TYPE(obj)) {
+ return gc_mark_stacked_objects(objspace, TRUE, count);
+}
+
+static int
+gc_mark_stacked_objects_all(rb_objspace_t *objspace)
+{
+ return gc_mark_stacked_objects(objspace, FALSE, 0);
+}
+
+#if PRINT_ROOT_TICKS
+#define MAX_TICKS 0x100
+static tick_t mark_ticks[MAX_TICKS];
+static const char *mark_ticks_categories[MAX_TICKS];
+
+static void
+show_mark_ticks(void)
+{
+ int i;
+ fprintf(stderr, "mark ticks result:\n");
+ for (i=0; i<MAX_TICKS; i++) {
+ const char *category = mark_ticks_categories[i];
+ if (category) {
+ fprintf(stderr, "%s\t%8lu\n", category, (unsigned long)mark_ticks[i]);
+ }
+ else {
+ break;
+ }
+ }
+}
+
+#endif /* PRINT_ROOT_TICKS */
+
+static void
+gc_mark_roots(rb_objspace_t *objspace, const char **categoryp)
+{
+ struct gc_list *list;
+ rb_execution_context_t *ec = GET_EC();
+ rb_vm_t *vm = rb_ec_vm_ptr(ec);
+
+#if PRINT_ROOT_TICKS
+ tick_t start_tick = tick();
+ int tick_count = 0;
+ const char *prev_category = 0;
+
+ if (mark_ticks_categories[0] == 0) {
+ atexit(show_mark_ticks);
+ }
+#endif
+
+ if (categoryp) *categoryp = "xxx";
+
+ objspace->rgengc.parent_object = Qfalse;
+
+#if PRINT_ROOT_TICKS
+#define MARK_CHECKPOINT_PRINT_TICK(category) do { \
+ if (prev_category) { \
+ tick_t t = tick(); \
+ mark_ticks[tick_count] = t - start_tick; \
+ mark_ticks_categories[tick_count] = prev_category; \
+ tick_count++; \
+ } \
+ prev_category = category; \
+ start_tick = tick(); \
+} while (0)
+#else /* PRINT_ROOT_TICKS */
+#define MARK_CHECKPOINT_PRINT_TICK(category)
+#endif
+
+#define MARK_CHECKPOINT(category) do { \
+ if (categoryp) *categoryp = category; \
+ MARK_CHECKPOINT_PRINT_TICK(category); \
+} while (0)
+
+ MARK_CHECKPOINT("vm");
+ SET_STACK_END;
+ rb_vm_mark(vm);
+ if (vm->self) gc_mark(objspace, vm->self);
+
+ MARK_CHECKPOINT("finalizers");
+ mark_finalizer_tbl(objspace, finalizer_table);
+
+ MARK_CHECKPOINT("machine_context");
+ mark_current_machine_context(objspace, ec);
+
+ /* mark protected global variables */
+ MARK_CHECKPOINT("global_list");
+ for (list = global_list; list; list = list->next) {
+ gc_mark_maybe(objspace, *list->varptr);
+ }
+
+ MARK_CHECKPOINT("end_proc");
+ rb_mark_end_proc();
+
+ MARK_CHECKPOINT("global_tbl");
+ rb_gc_mark_global_tbl();
+
+ MARK_CHECKPOINT("object_id");
+ rb_gc_mark(objspace->next_object_id);
+ mark_tbl_no_pin(objspace, objspace->obj_to_id_tbl); /* Only mark ids */
+
+ if (stress_to_class) rb_gc_mark(stress_to_class);
+
+ MARK_CHECKPOINT("finish");
+#undef MARK_CHECKPOINT
+}
+
+#if RGENGC_CHECK_MODE >= 4
+
+#define MAKE_ROOTSIG(obj) (((VALUE)(obj) << 1) | 0x01)
+#define IS_ROOTSIG(obj) ((VALUE)(obj) & 0x01)
+#define GET_ROOTSIG(obj) ((const char *)((VALUE)(obj) >> 1))
+
+struct reflist {
+ VALUE *list;
+ int pos;
+ int size;
+};
+
+static struct reflist *
+reflist_create(VALUE obj)
+{
+ struct reflist *refs = xmalloc(sizeof(struct reflist));
+ refs->size = 1;
+ refs->list = ALLOC_N(VALUE, refs->size);
+ refs->list[0] = obj;
+ refs->pos = 1;
+ return refs;
+}
+
+static void
+reflist_destruct(struct reflist *refs)
+{
+ xfree(refs->list);
+ xfree(refs);
+}
+
+static void
+reflist_add(struct reflist *refs, VALUE obj)
+{
+ if (refs->pos == refs->size) {
+ refs->size *= 2;
+ SIZED_REALLOC_N(refs->list, VALUE, refs->size, refs->size/2);
+ }
+
+ refs->list[refs->pos++] = obj;
+}
+
+static void
+reflist_dump(struct reflist *refs)
+{
+ int i;
+ for (i=0; i<refs->pos; i++) {
+ VALUE obj = refs->list[i];
+ if (IS_ROOTSIG(obj)) { /* root */
+ fprintf(stderr, "<root@%s>", GET_ROOTSIG(obj));
+ }
+ else {
+ fprintf(stderr, "<%s>", obj_info(obj));
+ }
+ if (i+1 < refs->pos) fprintf(stderr, ", ");
+ }
+}
+
+static int
+reflist_referred_from_machine_context(struct reflist *refs)
+{
+ int i;
+ for (i=0; i<refs->pos; i++) {
+ VALUE obj = refs->list[i];
+ if (IS_ROOTSIG(obj) && strcmp(GET_ROOTSIG(obj), "machine_context") == 0) return 1;
+ }
+ return 0;
+}
+
+struct allrefs {
+ rb_objspace_t *objspace;
+ /* a -> obj1
+ * b -> obj1
+ * c -> obj1
+ * c -> obj2
+ * d -> obj3
+ * #=> {obj1 => [a, b, c], obj2 => [c, d]}
+ */
+ struct st_table *references;
+ const char *category;
+ VALUE root_obj;
+ mark_stack_t mark_stack;
+};
+
+static int
+allrefs_add(struct allrefs *data, VALUE obj)
+{
+ struct reflist *refs;
+ st_data_t r;
+
+ if (st_lookup(data->references, obj, &r)) {
+ refs = (struct reflist *)r;
+ reflist_add(refs, data->root_obj);
+ return 0;
+ }
+ else {
+ refs = reflist_create(data->root_obj);
+ st_insert(data->references, obj, (st_data_t)refs);
+ return 1;
+ }
+}
+
+static void
+allrefs_i(VALUE obj, void *ptr)
+{
+ struct allrefs *data = (struct allrefs *)ptr;
+
+ if (allrefs_add(data, obj)) {
+ push_mark_stack(&data->mark_stack, obj);
+ }
+}
+
+static void
+allrefs_roots_i(VALUE obj, void *ptr)
+{
+ struct allrefs *data = (struct allrefs *)ptr;
+ if (strlen(data->category) == 0) rb_bug("!!!");
+ data->root_obj = MAKE_ROOTSIG(data->category);
+
+ if (allrefs_add(data, obj)) {
+ push_mark_stack(&data->mark_stack, obj);
+ }
+}
+#define PUSH_MARK_FUNC_DATA(v) do { \
+ struct gc_mark_func_data_struct *prev_mark_func_data = GET_RACTOR()->mfd; \
+ GET_RACTOR()->mfd = (v);
+
+#define POP_MARK_FUNC_DATA() GET_RACTOR()->mfd = prev_mark_func_data;} while (0)
+
+static st_table *
+objspace_allrefs(rb_objspace_t *objspace)
+{
+ struct allrefs data;
+ struct gc_mark_func_data_struct mfd;
+ VALUE obj;
+ int prev_dont_gc = dont_gc_val();
+ dont_gc_on();
+
+ data.objspace = objspace;
+ data.references = st_init_numtable();
+ init_mark_stack(&data.mark_stack);
+
+ mfd.mark_func = allrefs_roots_i;
+ mfd.data = &data;
+
+ /* traverse root objects */
+ PUSH_MARK_FUNC_DATA(&mfd);
+ GET_RACTOR()->mfd = &mfd;
+ gc_mark_roots(objspace, &data.category);
+ POP_MARK_FUNC_DATA();
+
+ /* traverse rest objects reachable from root objects */
+ while (pop_mark_stack(&data.mark_stack, &obj)) {
+ rb_objspace_reachable_objects_from(data.root_obj = obj, allrefs_i, &data);
+ }
+ free_stack_chunks(&data.mark_stack);
+
+ dont_gc_set(prev_dont_gc);
+ return data.references;
+}
+
+static int
+objspace_allrefs_destruct_i(st_data_t key, st_data_t value, st_data_t ptr)
+{
+ struct reflist *refs = (struct reflist *)value;
+ reflist_destruct(refs);
+ return ST_CONTINUE;
+}
+
+static void
+objspace_allrefs_destruct(struct st_table *refs)
+{
+ st_foreach(refs, objspace_allrefs_destruct_i, 0);
+ st_free_table(refs);
+}
+
+#if RGENGC_CHECK_MODE >= 5
+static int
+allrefs_dump_i(st_data_t k, st_data_t v, st_data_t ptr)
+{
+ VALUE obj = (VALUE)k;
+ struct reflist *refs = (struct reflist *)v;
+ fprintf(stderr, "[allrefs_dump_i] %s <- ", obj_info(obj));
+ reflist_dump(refs);
+ fprintf(stderr, "\n");
+ return ST_CONTINUE;
+}
+
+static void
+allrefs_dump(rb_objspace_t *objspace)
+{
+ VALUE size = objspace->rgengc.allrefs_table->num_entries;
+ fprintf(stderr, "[all refs] (size: %"PRIuVALUE")\n", size);
+ st_foreach(objspace->rgengc.allrefs_table, allrefs_dump_i, 0);
+}
+#endif
+
+static int
+gc_check_after_marks_i(st_data_t k, st_data_t v, st_data_t ptr)
+{
+ VALUE obj = k;
+ struct reflist *refs = (struct reflist *)v;
+ rb_objspace_t *objspace = (rb_objspace_t *)ptr;
+
+ /* object should be marked or oldgen */
+ if (!MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj)) {
+ fprintf(stderr, "gc_check_after_marks_i: %s is not marked and not oldgen.\n", obj_info(obj));
+ fprintf(stderr, "gc_check_after_marks_i: %p is referred from ", (void *)obj);
+ reflist_dump(refs);
+
+ if (reflist_referred_from_machine_context(refs)) {
+ fprintf(stderr, " (marked from machine stack).\n");
+ /* marked from machine context can be false positive */
+ }
+ else {
+ objspace->rgengc.error_count++;
+ fprintf(stderr, "\n");
+ }
+ }
+ return ST_CONTINUE;
+}
+
+static void
+gc_marks_check(rb_objspace_t *objspace, st_foreach_callback_func *checker_func, const char *checker_name)
+{
+ size_t saved_malloc_increase = objspace->malloc_params.increase;
+#if RGENGC_ESTIMATE_OLDMALLOC
+ size_t saved_oldmalloc_increase = objspace->rgengc.oldmalloc_increase;
+#endif
+ VALUE already_disabled = rb_objspace_gc_disable(objspace);
+
+ objspace->rgengc.allrefs_table = objspace_allrefs(objspace);
+
+ if (checker_func) {
+ st_foreach(objspace->rgengc.allrefs_table, checker_func, (st_data_t)objspace);
+ }
+
+ if (objspace->rgengc.error_count > 0) {
+#if RGENGC_CHECK_MODE >= 5
+ allrefs_dump(objspace);
+#endif
+ if (checker_name) rb_bug("%s: GC has problem.", checker_name);
+ }
+
+ objspace_allrefs_destruct(objspace->rgengc.allrefs_table);
+ objspace->rgengc.allrefs_table = 0;
+
+ if (already_disabled == Qfalse) rb_objspace_gc_enable(objspace);
+ objspace->malloc_params.increase = saved_malloc_increase;
+#if RGENGC_ESTIMATE_OLDMALLOC
+ objspace->rgengc.oldmalloc_increase = saved_oldmalloc_increase;
+#endif
+}
+#endif /* RGENGC_CHECK_MODE >= 4 */
+
+struct verify_internal_consistency_struct {
+ rb_objspace_t *objspace;
+ int err_count;
+ size_t live_object_count;
+ size_t zombie_object_count;
+
+ VALUE parent;
+ size_t old_object_count;
+ size_t remembered_shady_count;
+};
+
+static void
+check_generation_i(const VALUE child, void *ptr)
+{
+ struct verify_internal_consistency_struct *data = (struct verify_internal_consistency_struct *)ptr;
+ const VALUE parent = data->parent;
+
+ if (RGENGC_CHECK_MODE) GC_ASSERT(RVALUE_OLD_P(parent));
+
+ if (!RVALUE_OLD_P(child)) {
+ if (!RVALUE_REMEMBERED(parent) &&
+ !RVALUE_REMEMBERED(child) &&
+ !RVALUE_UNCOLLECTIBLE(child)) {
+ fprintf(stderr, "verify_internal_consistency_reachable_i: WB miss (O->Y) %s -> %s\n", obj_info(parent), obj_info(child));
+ data->err_count++;
+ }
+ }
+}
+
+static void
+check_color_i(const VALUE child, void *ptr)
+{
+ struct verify_internal_consistency_struct *data = (struct verify_internal_consistency_struct *)ptr;
+ const VALUE parent = data->parent;
+
+ if (!RVALUE_WB_UNPROTECTED(parent) && RVALUE_WHITE_P(child)) {
+ fprintf(stderr, "verify_internal_consistency_reachable_i: WB miss (B->W) - %s -> %s\n",
+ obj_info(parent), obj_info(child));
+ data->err_count++;
+ }
+}
+
+static void
+check_children_i(const VALUE child, void *ptr)
+{
+ struct verify_internal_consistency_struct *data = (struct verify_internal_consistency_struct *)ptr;
+ if (check_rvalue_consistency_force(child, FALSE) != 0) {
+ fprintf(stderr, "check_children_i: %s has error (referenced from %s)",
+ obj_info(child), obj_info(data->parent));
+ rb_print_backtrace(); /* C backtrace will help to debug */
+
+ data->err_count++;
+ }
+}
+
+static int
+verify_internal_consistency_i(void *page_start, void *page_end, size_t stride,
+ struct verify_internal_consistency_struct *data)
+{
+ VALUE obj;
+ rb_objspace_t *objspace = data->objspace;
+
+ for (obj = (VALUE)page_start; obj != (VALUE)page_end; obj += stride) {
+ void *poisoned = asan_unpoison_object_temporary(obj);
+
+ if (is_live_object(objspace, obj)) {
+ /* count objects */
+ data->live_object_count++;
+ data->parent = obj;
+
+ /* Normally, we don't expect T_MOVED objects to be in the heap.
+ * But they can stay alive on the stack, */
+ if (!gc_object_moved_p(objspace, obj)) {
+ /* moved slots don't have children */
+ rb_objspace_reachable_objects_from(obj, check_children_i, (void *)data);
+ }
+
+ /* check health of children */
+ if (RVALUE_OLD_P(obj)) data->old_object_count++;
+ if (RVALUE_WB_UNPROTECTED(obj) && RVALUE_UNCOLLECTIBLE(obj)) data->remembered_shady_count++;
+
+ if (!is_marking(objspace) && RVALUE_OLD_P(obj)) {
+ /* reachable objects from an oldgen object should be old or (young with remember) */
+ data->parent = obj;
+ rb_objspace_reachable_objects_from(obj, check_generation_i, (void *)data);
+ }
+
+ if (is_incremental_marking(objspace)) {
+ if (RVALUE_BLACK_P(obj)) {
+ /* reachable objects from black objects should be black or grey objects */
+ data->parent = obj;
+ rb_objspace_reachable_objects_from(obj, check_color_i, (void *)data);
+ }
+ }
+ }
+ else {
+ if (BUILTIN_TYPE(obj) == T_ZOMBIE) {
+ GC_ASSERT((RBASIC(obj)->flags & ~FL_SEEN_OBJ_ID) == T_ZOMBIE);
+ data->zombie_object_count++;
+ }
+ }
+ if (poisoned) {
+ GC_ASSERT(BUILTIN_TYPE(obj) == T_NONE);
+ asan_poison_object(obj);
+ }
+ }
+
+ return 0;
+}
+
+static int
+gc_verify_heap_page(rb_objspace_t *objspace, struct heap_page *page, VALUE obj)
+{
+ unsigned int has_remembered_shady = FALSE;
+ unsigned int has_remembered_old = FALSE;
+ int remembered_old_objects = 0;
+ int free_objects = 0;
+ int zombie_objects = 0;
+
+ short slot_size = page->slot_size;
+ uintptr_t start = (uintptr_t)page->start;
+ uintptr_t end = start + page->total_slots * slot_size;
+
+ for (uintptr_t ptr = start; ptr < end; ptr += slot_size) {
+ VALUE val = (VALUE)ptr;
+ void *poisoned = asan_unpoison_object_temporary(val);
+ enum ruby_value_type type = BUILTIN_TYPE(val);
+
+ if (type == T_NONE) free_objects++;
+ if (type == T_ZOMBIE) zombie_objects++;
+ if (RVALUE_PAGE_UNCOLLECTIBLE(page, val) && RVALUE_PAGE_WB_UNPROTECTED(page, val)) {
+ has_remembered_shady = TRUE;
+ }
+ if (RVALUE_PAGE_MARKING(page, val)) {
+ has_remembered_old = TRUE;
+ remembered_old_objects++;
+ }
+
+ if (poisoned) {
+ GC_ASSERT(BUILTIN_TYPE(val) == T_NONE);
+ asan_poison_object(val);
+ }
+ }
+
+ if (!is_incremental_marking(objspace) &&
+ page->flags.has_remembered_objects == FALSE && has_remembered_old == TRUE) {
+
+ for (uintptr_t ptr = start; ptr < end; ptr += slot_size) {
+ VALUE val = (VALUE)ptr;
+ if (RVALUE_PAGE_MARKING(page, val)) {
+ fprintf(stderr, "marking -> %s\n", obj_info(val));
+ }
+ }
+ rb_bug("page %p's has_remembered_objects should be false, but there are remembered old objects (%d). %s",
+ (void *)page, remembered_old_objects, obj ? obj_info(obj) : "");
+ }
+
+ if (page->flags.has_uncollectible_shady_objects == FALSE && has_remembered_shady == TRUE) {
+ rb_bug("page %p's has_remembered_shady should be false, but there are remembered shady objects. %s",
+ (void *)page, obj ? obj_info(obj) : "");
+ }
+
+ if (0) {
+ /* free_slots may not equal to free_objects */
+ if (page->free_slots != free_objects) {
+ rb_bug("page %p's free_slots should be %d, but %d\n", (void *)page, page->free_slots, free_objects);
+ }
+ }
+ if (page->final_slots != zombie_objects) {
+ rb_bug("page %p's final_slots should be %d, but %d\n", (void *)page, page->final_slots, zombie_objects);
+ }
+
+ return remembered_old_objects;
+}
+
+static int
+gc_verify_heap_pages_(rb_objspace_t *objspace, struct ccan_list_head *head)
+{
+ int remembered_old_objects = 0;
+ struct heap_page *page = 0;
+
+ ccan_list_for_each(head, page, page_node) {
+ asan_unlock_freelist(page);
+ RVALUE *p = page->freelist;
+ while (p) {
+ VALUE vp = (VALUE)p;
+ VALUE prev = vp;
+ asan_unpoison_object(vp, false);
+ if (BUILTIN_TYPE(vp) != T_NONE) {
+ fprintf(stderr, "freelist slot expected to be T_NONE but was: %s\n", obj_info(vp));
+ }
+ p = p->as.free.next;
+ asan_poison_object(prev);
+ }
+ asan_lock_freelist(page);
+
+ if (page->flags.has_remembered_objects == FALSE) {
+ remembered_old_objects += gc_verify_heap_page(objspace, page, Qfalse);
+ }
+ }
+
+ return remembered_old_objects;
+}
+
+static int
+gc_verify_heap_pages(rb_objspace_t *objspace)
+{
+ int remembered_old_objects = 0;
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ remembered_old_objects += gc_verify_heap_pages_(objspace, &(SIZE_POOL_EDEN_HEAP(&size_pools[i])->pages));
+ remembered_old_objects += gc_verify_heap_pages_(objspace, &(SIZE_POOL_TOMB_HEAP(&size_pools[i])->pages));
+ }
+ return remembered_old_objects;
+}
+
+/*
+ * call-seq:
+ * GC.verify_internal_consistency -> nil
+ *
+ * Verify internal consistency.
+ *
+ * This method is implementation specific.
+ * Now this method checks generational consistency
+ * if RGenGC is supported.
+ */
+static VALUE
+gc_verify_internal_consistency_m(VALUE dummy)
+{
+ gc_verify_internal_consistency(&rb_objspace);
+ return Qnil;
+}
+
+static void
+gc_verify_internal_consistency_(rb_objspace_t *objspace)
+{
+ struct verify_internal_consistency_struct data = {0};
+
+ data.objspace = objspace;
+ gc_report(5, objspace, "gc_verify_internal_consistency: start\n");
+
+ /* check relations */
+ for (size_t i = 0; i < heap_allocated_pages; i++) {
+ struct heap_page *page = heap_pages_sorted[i];
+ short slot_size = page->slot_size;
+
+ uintptr_t start = (uintptr_t)page->start;
+ uintptr_t end = start + page->total_slots * slot_size;
+
+ verify_internal_consistency_i((void *)start, (void *)end, slot_size, &data);
+ }
+
+ if (data.err_count != 0) {
+#if RGENGC_CHECK_MODE >= 5
+ objspace->rgengc.error_count = data.err_count;
+ gc_marks_check(objspace, NULL, NULL);
+ allrefs_dump(objspace);
+#endif
+ rb_bug("gc_verify_internal_consistency: found internal inconsistency.");
+ }
+
+ /* check heap_page status */
+ gc_verify_heap_pages(objspace);
+
+ /* check counters */
+
+ if (!is_lazy_sweeping(objspace) &&
+ !finalizing &&
+ ruby_single_main_ractor != NULL) {
+ if (objspace_live_slots(objspace) != data.live_object_count) {
+ fprintf(stderr, "heap_pages_final_slots: %"PRIdSIZE", "
+ "objspace->profile.total_freed_objects: %"PRIdSIZE"\n",
+ heap_pages_final_slots, objspace->profile.total_freed_objects);
+ rb_bug("inconsistent live slot number: expect %"PRIuSIZE", but %"PRIuSIZE".",
+ objspace_live_slots(objspace), data.live_object_count);
+ }
+ }
+
+ if (!is_marking(objspace)) {
+ if (objspace->rgengc.old_objects != data.old_object_count) {
+ rb_bug("inconsistent old slot number: expect %"PRIuSIZE", but %"PRIuSIZE".",
+ objspace->rgengc.old_objects, data.old_object_count);
+ }
+ if (objspace->rgengc.uncollectible_wb_unprotected_objects != data.remembered_shady_count) {
+ rb_bug("inconsistent number of wb unprotected objects: expect %"PRIuSIZE", but %"PRIuSIZE".",
+ objspace->rgengc.uncollectible_wb_unprotected_objects, data.remembered_shady_count);
+ }
+ }
+
+ if (!finalizing) {
+ size_t list_count = 0;
+
+ {
+ VALUE z = heap_pages_deferred_final;
+ while (z) {
+ list_count++;
+ z = RZOMBIE(z)->next;
+ }
+ }
+
+ if (heap_pages_final_slots != data.zombie_object_count ||
+ heap_pages_final_slots != list_count) {
+
+ rb_bug("inconsistent finalizing object count:\n"
+ " expect %"PRIuSIZE"\n"
+ " but %"PRIuSIZE" zombies\n"
+ " heap_pages_deferred_final list has %"PRIuSIZE" items.",
+ heap_pages_final_slots,
+ data.zombie_object_count,
+ list_count);
+ }
+ }
+
+ gc_report(5, objspace, "gc_verify_internal_consistency: OK\n");
+}
+
+static void
+gc_verify_internal_consistency(rb_objspace_t *objspace)
+{
+ RB_VM_LOCK_ENTER();
+ {
+ rb_vm_barrier(); // stop other ractors
+
+ unsigned int prev_during_gc = during_gc;
+ during_gc = FALSE; // stop gc here
+ {
+ gc_verify_internal_consistency_(objspace);
+ }
+ during_gc = prev_during_gc;
+ }
+ RB_VM_LOCK_LEAVE();
+}
+
+void
+rb_gc_verify_internal_consistency(void)
+{
+ gc_verify_internal_consistency(&rb_objspace);
+}
+
+static VALUE
+gc_verify_transient_heap_internal_consistency(VALUE dmy)
+{
+ rb_transient_heap_verify();
+ return Qnil;
+}
+
+#if GC_ENABLE_INCREMENTAL_MARK
+static void
+heap_move_pooled_pages_to_free_pages(rb_heap_t *heap)
+{
+ if (heap->pooled_pages) {
+ if (heap->free_pages) {
+ struct heap_page *free_pages_tail = heap->free_pages;
+ while (free_pages_tail->free_next) {
+ free_pages_tail = free_pages_tail->free_next;
+ }
+ free_pages_tail->free_next = heap->pooled_pages;
+ }
+ else {
+ heap->free_pages = heap->pooled_pages;
+ }
+
+ heap->pooled_pages = NULL;
+ }
+}
+#endif
+
+/* marks */
+
+static void
+gc_marks_start(rb_objspace_t *objspace, int full_mark)
+{
+ /* start marking */
+ gc_report(1, objspace, "gc_marks_start: (%s)\n", full_mark ? "full" : "minor");
+ gc_mode_transition(objspace, gc_mode_marking);
+
+ if (full_mark) {
+#if GC_ENABLE_INCREMENTAL_MARK
+ size_t incremental_marking_steps = (objspace->rincgc.pooled_slots / INCREMENTAL_MARK_STEP_ALLOCATIONS) + 1;
+ objspace->rincgc.step_slots = (objspace->marked_slots * 2) / incremental_marking_steps;
+
+ if (0) fprintf(stderr, "objspace->marked_slots: %"PRIdSIZE", "
+ "objspace->rincgc.pooled_page_num: %"PRIdSIZE", "
+ "objspace->rincgc.step_slots: %"PRIdSIZE", \n",
+ objspace->marked_slots, objspace->rincgc.pooled_slots, objspace->rincgc.step_slots);
+#endif
+ objspace->flags.during_minor_gc = FALSE;
+ if (ruby_enable_autocompact) {
+ objspace->flags.during_compacting |= TRUE;
+ }
+ objspace->profile.major_gc_count++;
+ objspace->rgengc.uncollectible_wb_unprotected_objects = 0;
+ objspace->rgengc.old_objects = 0;
+ objspace->rgengc.last_major_gc = objspace->profile.count;
+ objspace->marked_slots = 0;
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
+ rgengc_mark_and_rememberset_clear(objspace, heap);
+ heap_move_pooled_pages_to_free_pages(heap);
+ }
+ }
+ else {
+ objspace->flags.during_minor_gc = TRUE;
+ objspace->marked_slots =
+ objspace->rgengc.old_objects + objspace->rgengc.uncollectible_wb_unprotected_objects; /* uncollectible objects are marked already */
+ objspace->profile.minor_gc_count++;
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rgengc_rememberset_mark(objspace, SIZE_POOL_EDEN_HEAP(&size_pools[i]));
+ }
+ }
+
+ gc_mark_roots(objspace, NULL);
+
+ gc_report(1, objspace, "gc_marks_start: (%s) end, stack in %"PRIdSIZE"\n",
+ full_mark ? "full" : "minor", mark_stack_size(&objspace->mark_stack));
+}
+
+#if GC_ENABLE_INCREMENTAL_MARK
+static inline void
+gc_marks_wb_unprotected_objects_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bits)
+{
+ if (bits) {
+ do {
+ if (bits & 1) {
+ gc_report(2, objspace, "gc_marks_wb_unprotected_objects: marked shady: %s\n", obj_info((VALUE)p));
+ GC_ASSERT(RVALUE_WB_UNPROTECTED((VALUE)p));
+ GC_ASSERT(RVALUE_MARKED((VALUE)p));
+ gc_mark_children(objspace, (VALUE)p);
+ }
+ p += BASE_SLOT_SIZE;
+ bits >>= 1;
+ } while (bits);
+ }
+}
+
+static void
+gc_marks_wb_unprotected_objects(rb_objspace_t *objspace, rb_heap_t *heap)
+{
+ struct heap_page *page = 0;
+
+ ccan_list_for_each(&heap->pages, page, page_node) {
+ bits_t *mark_bits = page->mark_bits;
+ bits_t *wbun_bits = page->wb_unprotected_bits;
+ uintptr_t p = page->start;
+ size_t j;
+
+ bits_t bits = mark_bits[0] & wbun_bits[0];
+ bits >>= NUM_IN_PAGE(p);
+ gc_marks_wb_unprotected_objects_plane(objspace, p, bits);
+ p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
+
+ for (j=1; j<HEAP_PAGE_BITMAP_LIMIT; j++) {
+ bits_t bits = mark_bits[j] & wbun_bits[j];
+
+ gc_marks_wb_unprotected_objects_plane(objspace, p, bits);
+ p += BITS_BITLENGTH * BASE_SLOT_SIZE;
+ }
+ }
+
+ gc_mark_stacked_objects_all(objspace);
+}
+#endif
+
+static void
+gc_marks_finish(rb_objspace_t *objspace)
+{
+#if GC_ENABLE_INCREMENTAL_MARK
+ /* finish incremental GC */
+ if (is_incremental_marking(objspace)) {
+ if (RGENGC_CHECK_MODE && is_mark_stack_empty(&objspace->mark_stack) == 0) {
+ rb_bug("gc_marks_finish: mark stack is not empty (%"PRIdSIZE").",
+ mark_stack_size(&objspace->mark_stack));
+ }
+
+ gc_mark_roots(objspace, 0);
+ while (gc_mark_stacked_objects_incremental(objspace, INT_MAX) == false);
+
+#if RGENGC_CHECK_MODE >= 2
+ if (gc_verify_heap_pages(objspace) != 0) {
+ rb_bug("gc_marks_finish (incremental): there are remembered old objects.");
+ }
+#endif
+
+ objspace->flags.during_incremental_marking = FALSE;
+ /* check children of all marked wb-unprotected objects */
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ gc_marks_wb_unprotected_objects(objspace, SIZE_POOL_EDEN_HEAP(&size_pools[i]));
+ }
+ }
+#endif /* GC_ENABLE_INCREMENTAL_MARK */
+
+#if RGENGC_CHECK_MODE >= 2
+ gc_verify_internal_consistency(objspace);
+#endif
+
+ if (is_full_marking(objspace)) {
+ /* See the comment about RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR */
+ const double r = gc_params.oldobject_limit_factor;
+ objspace->rgengc.uncollectible_wb_unprotected_objects_limit = (size_t)(objspace->rgengc.uncollectible_wb_unprotected_objects * r);
+ objspace->rgengc.old_objects_limit = (size_t)(objspace->rgengc.old_objects * r);
+ }
+
+#if RGENGC_CHECK_MODE >= 4
+ during_gc = FALSE;
+ gc_marks_check(objspace, gc_check_after_marks_i, "after_marks");
+ during_gc = TRUE;
+#endif
+
+ {
+ /* decide full GC is needed or not */
+ size_t total_slots = heap_allocatable_slots(objspace) + heap_eden_total_slots(objspace);
+ size_t sweep_slots = total_slots - objspace->marked_slots; /* will be swept slots */
+ size_t max_free_slots = (size_t)(total_slots * gc_params.heap_free_slots_max_ratio);
+ size_t min_free_slots = (size_t)(total_slots * gc_params.heap_free_slots_min_ratio);
+ int full_marking = is_full_marking(objspace);
+ const int r_cnt = GET_VM()->ractor.cnt;
+ const int r_mul = r_cnt > 8 ? 8 : r_cnt; // upto 8
+
+ GC_ASSERT(heap_eden_total_slots(objspace) >= objspace->marked_slots);
+
+ /* setup free-able page counts */
+ if (max_free_slots < gc_params.heap_init_slots * r_mul) {
+ max_free_slots = gc_params.heap_init_slots * r_mul;
+ }
+
+ if (sweep_slots > max_free_slots) {
+ heap_pages_freeable_pages = (sweep_slots - max_free_slots) / HEAP_PAGE_OBJ_LIMIT;
+ }
+ else {
+ heap_pages_freeable_pages = 0;
+ }
+
+ /* check free_min */
+ if (min_free_slots < gc_params.heap_free_slots * r_mul) {
+ min_free_slots = gc_params.heap_free_slots * r_mul;
+ }
+
+ if (sweep_slots < min_free_slots) {
+ if (!full_marking) {
+ if (objspace->profile.count - objspace->rgengc.last_major_gc < RVALUE_OLD_AGE) {
+ full_marking = TRUE;
+ /* do not update last_major_gc, because full marking is not done. */
+ /* goto increment; */
+ }
+ else {
+ gc_report(1, objspace, "gc_marks_finish: next is full GC!!)\n");
+ objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_NOFREE;
+ }
+ }
+
+#if !USE_RVARGC
+ if (full_marking) {
+ /* increment: */
+ gc_report(1, objspace, "gc_marks_finish: heap_set_increment!!\n");
+ rb_size_pool_t *size_pool = &size_pools[0];
+ size_pool_allocatable_pages_set(objspace, size_pool, heap_extend_pages(objspace, size_pool, sweep_slots, total_slots, heap_allocated_pages + heap_allocatable_pages(objspace)));
+
+ heap_increment(objspace, size_pool, SIZE_POOL_EDEN_HEAP(size_pool));
+ }
+#endif
+ }
+
+ if (full_marking) {
+ /* See the comment about RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR */
+ const double r = gc_params.oldobject_limit_factor;
+ objspace->rgengc.uncollectible_wb_unprotected_objects_limit = (size_t)(objspace->rgengc.uncollectible_wb_unprotected_objects * r);
+ objspace->rgengc.old_objects_limit = (size_t)(objspace->rgengc.old_objects * r);
+ }
+
+ if (objspace->rgengc.uncollectible_wb_unprotected_objects > objspace->rgengc.uncollectible_wb_unprotected_objects_limit) {
+ objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_SHADY;
+ }
+ if (objspace->rgengc.old_objects > objspace->rgengc.old_objects_limit) {
+ objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_OLDGEN;
+ }
+ if (RGENGC_FORCE_MAJOR_GC) {
+ objspace->rgengc.need_major_gc = GPR_FLAG_MAJOR_BY_FORCE;
+ }
+
+ gc_report(1, objspace, "gc_marks_finish (marks %"PRIdSIZE" objects, "
+ "old %"PRIdSIZE" objects, total %"PRIdSIZE" slots, "
+ "sweep %"PRIdSIZE" slots, increment: %"PRIdSIZE", next GC: %s)\n",
+ objspace->marked_slots, objspace->rgengc.old_objects, heap_eden_total_slots(objspace), sweep_slots, heap_allocatable_pages(objspace),
+ objspace->rgengc.need_major_gc ? "major" : "minor");
+ }
+
+ rb_transient_heap_finish_marking();
+ rb_ractor_finish_marking();
+
+ gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_END_MARK, 0);
+}
+
+#if GC_ENABLE_INCREMENTAL_MARK
+static void
+gc_marks_step(rb_objspace_t *objspace, size_t slots)
+{
+ GC_ASSERT(is_marking(objspace));
+
+ if (gc_mark_stacked_objects_incremental(objspace, slots)) {
+ gc_marks_finish(objspace);
+ gc_sweep(objspace);
+ }
+ if (0) fprintf(stderr, "objspace->marked_slots: %"PRIdSIZE"\n", objspace->marked_slots);
+}
+#endif
+
+static bool
+gc_compact_heap_cursors_met_p(rb_heap_t *heap)
+{
+ return heap->sweeping_page == heap->compact_cursor;
+}
+
+static rb_size_pool_t *
+gc_compact_destination_pool(rb_objspace_t *objspace, rb_size_pool_t *src_pool, VALUE src)
+{
+ size_t obj_size;
+ size_t idx = 0;
+
+ switch (BUILTIN_TYPE(src)) {
case T_ARRAY:
- return rb_ary_size_as_embedded(obj);
+ obj_size = rb_ary_size_as_embedded(src);
+ break;
case T_OBJECT:
- if (rb_shape_obj_too_complex(obj)) {
- return sizeof(struct RObject);
+ if (rb_shape_obj_too_complex(src)) {
+ return &size_pools[0];
}
else {
- return rb_obj_embedded_size(ROBJECT_IV_CAPACITY(obj));
+ obj_size = rb_obj_embedded_size(ROBJECT_IV_CAPACITY(src));
}
+ break;
case T_STRING:
- return rb_str_size_as_embedded(obj);
-
- case T_HASH:
- return sizeof(struct RHash) + (RHASH_ST_TABLE_P(obj) ? sizeof(st_table) : sizeof(ar_table));
+ obj_size = rb_str_size_as_embedded(src);
+ break;
default:
- return 0;
+ return src_pool;
+ }
+
+ if (rb_gc_size_allocatable_p(obj_size)){
+ idx = size_pool_idx_for_size(obj_size);
}
+ return &size_pools[idx];
}
+static bool
+gc_compact_move(rb_objspace_t *objspace, rb_heap_t *heap, rb_size_pool_t *size_pool, VALUE src)
+{
+ GC_ASSERT(BUILTIN_TYPE(src) != T_MOVED);
+ GC_ASSERT(gc_is_moveable_obj(objspace, src));
+
+ rb_size_pool_t *dest_pool = gc_compact_destination_pool(objspace, size_pool, src);
+ rb_heap_t *dheap = SIZE_POOL_EDEN_HEAP(dest_pool);
+ rb_shape_t *new_shape = NULL;
+ rb_shape_t *orig_shape = NULL;
+
+ if (gc_compact_heap_cursors_met_p(dheap)) {
+ return dheap != heap;
+ }
+
+ if (RB_TYPE_P(src, T_OBJECT)) {
+ orig_shape = rb_shape_get_shape(src);
+ if (dheap != heap && !rb_shape_obj_too_complex(src)) {
+ rb_shape_t *initial_shape = rb_shape_get_shape_by_id((shape_id_t)((dest_pool - size_pools) + SIZE_POOL_COUNT));
+ new_shape = rb_shape_traverse_from_new_root(initial_shape, orig_shape);
+
+ if (!new_shape) {
+ dest_pool = size_pool;
+ dheap = heap;
+ }
+ }
+ }
+
+ while (!try_move(objspace, dheap, dheap->free_pages, src)) {
+ struct gc_sweep_context ctx = {
+ .page = dheap->sweeping_page,
+ .final_slots = 0,
+ .freed_slots = 0,
+ .empty_slots = 0,
+ };
+
+ /* The page of src could be partially compacted, so it may contain
+ * T_MOVED. Sweeping a page may read objects on this page, so we
+ * need to lock the page. */
+ lock_page_body(objspace, GET_PAGE_BODY(src));
+ gc_sweep_page(objspace, dheap, &ctx);
+ unlock_page_body(objspace, GET_PAGE_BODY(src));
+
+ if (dheap->sweeping_page->free_slots > 0) {
+ heap_add_freepage(dheap, dheap->sweeping_page);
+ };
+
+ dheap->sweeping_page = ccan_list_next(&dheap->pages, dheap->sweeping_page, page_node);
+ if (gc_compact_heap_cursors_met_p(dheap)) {
+ return dheap != heap;
+ }
+ }
+
+ if (orig_shape) {
+ if (new_shape) {
+ VALUE dest = rb_gc_location(src);
+ rb_shape_set_shape(dest, new_shape);
+ }
+ RMOVED(src)->original_shape_id = rb_shape_id(orig_shape);
+ }
+
+ return true;
+}
+
+static bool
+gc_compact_plane(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap, uintptr_t p, bits_t bitset, struct heap_page *page)
+{
+ short slot_size = page->slot_size;
+ short slot_bits = slot_size / BASE_SLOT_SIZE;
+ GC_ASSERT(slot_bits > 0);
+
+ do {
+ VALUE vp = (VALUE)p;
+ GC_ASSERT(vp % sizeof(RVALUE) == 0);
+
+ if (bitset & 1) {
+ objspace->rcompactor.considered_count_table[BUILTIN_TYPE(vp)]++;
+
+ if (gc_is_moveable_obj(objspace, vp)) {
+ if (!gc_compact_move(objspace, heap, size_pool, vp)) {
+ //the cursors met. bubble up
+ return false;
+ }
+ }
+ }
+ p += slot_size;
+ bitset >>= slot_bits;
+ } while (bitset);
+
+ return true;
+}
+
+// Iterate up all the objects in page, moving them to where they want to go
+static bool
+gc_compact_page(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap, struct heap_page *page)
+{
+ GC_ASSERT(page == heap->compact_cursor);
+
+ bits_t *mark_bits, *pin_bits;
+ bits_t bitset;
+ uintptr_t p = page->start;
+
+ mark_bits = page->mark_bits;
+ pin_bits = page->pinned_bits;
+
+ // objects that can be moved are marked and not pinned
+ bitset = (mark_bits[0] & ~pin_bits[0]);
+ bitset >>= NUM_IN_PAGE(p);
+ if (bitset) {
+ if (!gc_compact_plane(objspace, size_pool, heap, (uintptr_t)p, bitset, page))
+ return false;
+ }
+ p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
+
+ for (int j = 1; j < HEAP_PAGE_BITMAP_LIMIT; j++) {
+ bitset = (mark_bits[j] & ~pin_bits[j]);
+ if (bitset) {
+ if (!gc_compact_plane(objspace, size_pool, heap, (uintptr_t)p, bitset, page))
+ return false;
+ }
+ p += BITS_BITLENGTH * BASE_SLOT_SIZE;
+ }
+
+ return true;
+}
+
+static bool
+gc_compact_all_compacted_p(rb_objspace_t *objspace)
+{
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
+
+ if (heap->total_pages > 0 &&
+ !gc_compact_heap_cursors_met_p(heap)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void
+gc_sweep_compact(rb_objspace_t *objspace)
+{
+ gc_compact_start(objspace);
+#if RGENGC_CHECK_MODE >= 2
+ gc_verify_internal_consistency(objspace);
+#endif
+
+ while (!gc_compact_all_compacted_p(objspace)) {
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
+
+ if (gc_compact_heap_cursors_met_p(heap)) {
+ continue;
+ }
+
+ struct heap_page *start_page = heap->compact_cursor;
+
+ if (!gc_compact_page(objspace, size_pool, heap, start_page)) {
+ lock_page_body(objspace, GET_PAGE_BODY(start_page->start));
+
+ continue;
+ }
+
+ // If we get here, we've finished moving all objects on the compact_cursor page
+ // So we can lock it and move the cursor on to the next one.
+ lock_page_body(objspace, GET_PAGE_BODY(start_page->start));
+ heap->compact_cursor = ccan_list_prev(&heap->pages, heap->compact_cursor, page_node);
+ }
+ }
+
+ gc_compact_finish(objspace);
+
+#if RGENGC_CHECK_MODE >= 2
+ gc_verify_internal_consistency(objspace);
+#endif
+}
+
+static void
+gc_marks_rest(rb_objspace_t *objspace)
+{
+ gc_report(1, objspace, "gc_marks_rest\n");
+
+#if GC_ENABLE_INCREMENTAL_MARK
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ SIZE_POOL_EDEN_HEAP(&size_pools[i])->pooled_pages = NULL;
+ }
+#endif
+
+ if (is_incremental_marking(objspace)) {
+ while (gc_mark_stacked_objects_incremental(objspace, INT_MAX) == FALSE);
+ }
+ else {
+ gc_mark_stacked_objects_all(objspace);
+ }
+
+ gc_marks_finish(objspace);
+
+ /* move to sweep */
+ gc_sweep(objspace);
+}
+
+static void
+gc_marks_continue(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap)
+{
+ GC_ASSERT(dont_gc_val() == FALSE);
+#if GC_ENABLE_INCREMENTAL_MARK
+
+ unsigned int lock_lev;
+ gc_enter(objspace, gc_enter_event_mark_continue, &lock_lev);
+
+ if (heap->free_pages) {
+ gc_report(2, objspace, "gc_marks_continue: has pooled pages");
+ gc_marks_step(objspace, objspace->rincgc.step_slots);
+ }
+ else {
+ gc_report(2, objspace, "gc_marks_continue: no more pooled pages (stack depth: %"PRIdSIZE").\n",
+ mark_stack_size(&objspace->mark_stack));
+ gc_marks_rest(objspace);
+ }
+
+ gc_exit(objspace, gc_enter_event_mark_continue, &lock_lev);
+#endif
+}
+
+static void
+gc_marks(rb_objspace_t *objspace, int full_mark)
+{
+ gc_prof_mark_timer_start(objspace);
+
+ /* setup marking */
+
+ gc_marks_start(objspace, full_mark);
+ if (!is_incremental_marking(objspace)) {
+ gc_marks_rest(objspace);
+ }
+
+#if RGENGC_PROFILE > 0
+ if (gc_prof_record(objspace)) {
+ gc_profile_record *record = gc_prof_record(objspace);
+ record->old_objects = objspace->rgengc.old_objects;
+ }
+#endif
+ gc_prof_mark_timer_stop(objspace);
+}
+
+/* RGENGC */
+
+static void
+gc_report_body(int level, rb_objspace_t *objspace, const char *fmt, ...)
+{
+ if (level <= RGENGC_DEBUG) {
+ char buf[1024];
+ FILE *out = stderr;
+ va_list args;
+ const char *status = " ";
+
+ if (during_gc) {
+ status = is_full_marking(objspace) ? "+" : "-";
+ }
+ else {
+ if (is_lazy_sweeping(objspace)) {
+ status = "S";
+ }
+ if (is_incremental_marking(objspace)) {
+ status = "M";
+ }
+ }
+
+ va_start(args, fmt);
+ vsnprintf(buf, 1024, fmt, args);
+ va_end(args);
+
+ fprintf(out, "%s|", status);
+ fputs(buf, out);
+ }
+}
+
+/* bit operations */
+
+static int
+rgengc_remembersetbits_get(rb_objspace_t *objspace, VALUE obj)
+{
+ return RVALUE_REMEMBERED(obj);
+}
+
+static int
+rgengc_remembersetbits_set(rb_objspace_t *objspace, VALUE obj)
+{
+ struct heap_page *page = GET_HEAP_PAGE(obj);
+ bits_t *bits = &page->marking_bits[0];
+
+ GC_ASSERT(!is_incremental_marking(objspace));
+
+ if (MARKED_IN_BITMAP(bits, obj)) {
+ return FALSE;
+ }
+ else {
+ page->flags.has_remembered_objects = TRUE;
+ MARK_IN_BITMAP(bits, obj);
+ return TRUE;
+ }
+}
+
+/* wb, etc */
+
+/* return FALSE if already remembered */
+static int
+rgengc_remember(rb_objspace_t *objspace, VALUE obj)
+{
+ gc_report(6, objspace, "rgengc_remember: %s %s\n", obj_info(obj),
+ rgengc_remembersetbits_get(objspace, obj) ? "was already remembered" : "is remembered now");
+
+ check_rvalue_consistency(obj);
+
+ if (RGENGC_CHECK_MODE) {
+ if (RVALUE_WB_UNPROTECTED(obj)) rb_bug("rgengc_remember: %s is not wb protected.", obj_info(obj));
+ }
+
+#if RGENGC_PROFILE > 0
+ if (!rgengc_remembered(objspace, obj)) {
+ if (RVALUE_WB_UNPROTECTED(obj) == 0) {
+ objspace->profile.total_remembered_normal_object_count++;
+#if RGENGC_PROFILE >= 2
+ objspace->profile.remembered_normal_object_count_types[BUILTIN_TYPE(obj)]++;
+#endif
+ }
+ }
+#endif /* RGENGC_PROFILE > 0 */
+
+ return rgengc_remembersetbits_set(objspace, obj);
+}
+
+static int
+rgengc_remembered_sweep(rb_objspace_t *objspace, VALUE obj)
+{
+ int result = rgengc_remembersetbits_get(objspace, obj);
+ check_rvalue_consistency(obj);
+ return result;
+}
+
+static int
+rgengc_remembered(rb_objspace_t *objspace, VALUE obj)
+{
+ gc_report(6, objspace, "rgengc_remembered: %s\n", obj_info(obj));
+ return rgengc_remembered_sweep(objspace, obj);
+}
+
+#ifndef PROFILE_REMEMBERSET_MARK
+#define PROFILE_REMEMBERSET_MARK 0
+#endif
+
+static inline void
+rgengc_rememberset_mark_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bitset)
+{
+ if (bitset) {
+ do {
+ if (bitset & 1) {
+ VALUE obj = (VALUE)p;
+ gc_report(2, objspace, "rgengc_rememberset_mark: mark %s\n", obj_info(obj));
+ GC_ASSERT(RVALUE_UNCOLLECTIBLE(obj));
+ GC_ASSERT(RVALUE_OLD_P(obj) || RVALUE_WB_UNPROTECTED(obj));
+
+ gc_mark_children(objspace, obj);
+ }
+ p += BASE_SLOT_SIZE;
+ bitset >>= 1;
+ } while (bitset);
+ }
+}
+
+static void
+rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap)
+{
+ size_t j;
+ struct heap_page *page = 0;
+#if PROFILE_REMEMBERSET_MARK
+ int has_old = 0, has_shady = 0, has_both = 0, skip = 0;
+#endif
+ gc_report(1, objspace, "rgengc_rememberset_mark: start\n");
+
+ ccan_list_for_each(&heap->pages, page, page_node) {
+ if (page->flags.has_remembered_objects | page->flags.has_uncollectible_shady_objects) {
+ uintptr_t p = page->start;
+ bits_t bitset, bits[HEAP_PAGE_BITMAP_LIMIT];
+ bits_t *marking_bits = page->marking_bits;
+ bits_t *uncollectible_bits = page->uncollectible_bits;
+ bits_t *wb_unprotected_bits = page->wb_unprotected_bits;
+#if PROFILE_REMEMBERSET_MARK
+ if (page->flags.has_remembered_objects && page->flags.has_uncollectible_shady_objects) has_both++;
+ else if (page->flags.has_remembered_objects) has_old++;
+ else if (page->flags.has_uncollectible_shady_objects) has_shady++;
+#endif
+ for (j=0; j<HEAP_PAGE_BITMAP_LIMIT; j++) {
+ bits[j] = marking_bits[j] | (uncollectible_bits[j] & wb_unprotected_bits[j]);
+ marking_bits[j] = 0;
+ }
+ page->flags.has_remembered_objects = FALSE;
+
+ bitset = bits[0];
+ bitset >>= NUM_IN_PAGE(p);
+ rgengc_rememberset_mark_plane(objspace, p, bitset);
+ p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
+
+ for (j=1; j < HEAP_PAGE_BITMAP_LIMIT; j++) {
+ bitset = bits[j];
+ rgengc_rememberset_mark_plane(objspace, p, bitset);
+ p += BITS_BITLENGTH * BASE_SLOT_SIZE;
+ }
+ }
+#if PROFILE_REMEMBERSET_MARK
+ else {
+ skip++;
+ }
+#endif
+ }
+
+#if PROFILE_REMEMBERSET_MARK
+ fprintf(stderr, "%d\t%d\t%d\t%d\n", has_both, has_old, has_shady, skip);
+#endif
+ gc_report(1, objspace, "rgengc_rememberset_mark: finished\n");
+}
+
+static void
+rgengc_mark_and_rememberset_clear(rb_objspace_t *objspace, rb_heap_t *heap)
+{
+ struct heap_page *page = 0;
+
+ ccan_list_for_each(&heap->pages, page, page_node) {
+ memset(&page->mark_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
+ memset(&page->uncollectible_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
+ memset(&page->marking_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
+ memset(&page->pinned_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
+ page->flags.has_uncollectible_shady_objects = FALSE;
+ page->flags.has_remembered_objects = FALSE;
+ }
+}
+
+/* RGENGC: APIs */
+
+NOINLINE(static void gc_writebarrier_generational(VALUE a, VALUE b, rb_objspace_t *objspace));
+
+static void
+gc_writebarrier_generational(VALUE a, VALUE b, rb_objspace_t *objspace)
+{
+ if (RGENGC_CHECK_MODE) {
+ if (!RVALUE_OLD_P(a)) rb_bug("gc_writebarrier_generational: %s is not an old object.", obj_info(a));
+ if ( RVALUE_OLD_P(b)) rb_bug("gc_writebarrier_generational: %s is an old object.", obj_info(b));
+ if (is_incremental_marking(objspace)) rb_bug("gc_writebarrier_generational: called while incremental marking: %s -> %s", obj_info(a), obj_info(b));
+ }
+
+#if 1
+ /* mark `a' and remember (default behavior) */
+ if (!rgengc_remembered(objspace, a)) {
+ RB_VM_LOCK_ENTER_NO_BARRIER();
+ {
+ rgengc_remember(objspace, a);
+ }
+ RB_VM_LOCK_LEAVE_NO_BARRIER();
+ gc_report(1, objspace, "gc_writebarrier_generational: %s (remembered) -> %s\n", obj_info(a), obj_info(b));
+ }
+#else
+ /* mark `b' and remember */
+ MARK_IN_BITMAP(GET_HEAP_MARK_BITS(b), b);
+ if (RVALUE_WB_UNPROTECTED(b)) {
+ gc_remember_unprotected(objspace, b);
+ }
+ else {
+ RVALUE_AGE_SET_OLD(objspace, b);
+ rgengc_remember(objspace, b);
+ }
+
+ gc_report(1, objspace, "gc_writebarrier_generational: %s -> %s (remembered)\n", obj_info(a), obj_info(b));
+#endif
+
+ check_rvalue_consistency(a);
+ check_rvalue_consistency(b);
+}
+
+#if GC_ENABLE_INCREMENTAL_MARK
+static void
+gc_mark_from(rb_objspace_t *objspace, VALUE obj, VALUE parent)
+{
+ gc_mark_set_parent(objspace, parent);
+ rgengc_check_relation(objspace, obj);
+ if (gc_mark_set(objspace, obj) == FALSE) return;
+ gc_aging(objspace, obj);
+ gc_grey(objspace, obj);
+}
+
+NOINLINE(static void gc_writebarrier_incremental(VALUE a, VALUE b, rb_objspace_t *objspace));
+
+static void
+gc_writebarrier_incremental(VALUE a, VALUE b, rb_objspace_t *objspace)
+{
+ gc_report(2, objspace, "gc_writebarrier_incremental: [LG] %p -> %s\n", (void *)a, obj_info(b));
+
+ if (RVALUE_BLACK_P(a)) {
+ if (RVALUE_WHITE_P(b)) {
+ if (!RVALUE_WB_UNPROTECTED(a)) {
+ gc_report(2, objspace, "gc_writebarrier_incremental: [IN] %p -> %s\n", (void *)a, obj_info(b));
+ gc_mark_from(objspace, b, a);
+ }
+ }
+ else if (RVALUE_OLD_P(a) && !RVALUE_OLD_P(b)) {
+ if (!RVALUE_WB_UNPROTECTED(b)) {
+ gc_report(1, objspace, "gc_writebarrier_incremental: [GN] %p -> %s\n", (void *)a, obj_info(b));
+ RVALUE_AGE_SET_OLD(objspace, b);
+
+ if (RVALUE_BLACK_P(b)) {
+ gc_grey(objspace, b);
+ }
+ }
+ else {
+ gc_report(1, objspace, "gc_writebarrier_incremental: [LL] %p -> %s\n", (void *)a, obj_info(b));
+ gc_remember_unprotected(objspace, b);
+ }
+ }
+
+ if (UNLIKELY(objspace->flags.during_compacting)) {
+ MARK_IN_BITMAP(GET_HEAP_PINNED_BITS(b), b);
+ }
+ }
+}
+#else
+#define gc_writebarrier_incremental(a, b, objspace)
+#endif
+
void
rb_gc_writebarrier(VALUE a, VALUE b)
{
- rb_gc_impl_writebarrier(rb_gc_get_objspace(), a, b);
+ rb_objspace_t *objspace = &rb_objspace;
+
+ if (RGENGC_CHECK_MODE) {
+ if (SPECIAL_CONST_P(a)) rb_bug("rb_gc_writebarrier: a is special const: %"PRIxVALUE, a);
+ if (SPECIAL_CONST_P(b)) rb_bug("rb_gc_writebarrier: b is special const: %"PRIxVALUE, b);
+ }
+
+ retry:
+ if (!is_incremental_marking(objspace)) {
+ if (!RVALUE_OLD_P(a) || RVALUE_OLD_P(b)) {
+ // do nothing
+ }
+ else {
+ gc_writebarrier_generational(a, b, objspace);
+ }
+ }
+ else {
+ bool retry = false;
+ /* slow path */
+ RB_VM_LOCK_ENTER_NO_BARRIER();
+ {
+ if (is_incremental_marking(objspace)) {
+ gc_writebarrier_incremental(a, b, objspace);
+ }
+ else {
+ retry = true;
+ }
+ }
+ RB_VM_LOCK_LEAVE_NO_BARRIER();
+
+ if (retry) goto retry;
+ }
+ return;
}
void
rb_gc_writebarrier_unprotect(VALUE obj)
{
- rb_gc_impl_writebarrier_unprotect(rb_gc_get_objspace(), obj);
+ if (RVALUE_WB_UNPROTECTED(obj)) {
+ return;
+ }
+ else {
+ rb_objspace_t *objspace = &rb_objspace;
+
+ gc_report(2, objspace, "rb_gc_writebarrier_unprotect: %s %s\n", obj_info(obj),
+ rgengc_remembered(objspace, obj) ? " (already remembered)" : "");
+
+ RB_VM_LOCK_ENTER_NO_BARRIER();
+ {
+ if (RVALUE_OLD_P(obj)) {
+ gc_report(1, objspace, "rb_gc_writebarrier_unprotect: %s\n", obj_info(obj));
+ RVALUE_DEMOTE(objspace, obj);
+ gc_mark_set(objspace, obj);
+ gc_remember_unprotected(objspace, obj);
+
+#if RGENGC_PROFILE
+ objspace->profile.total_shade_operation_count++;
+#if RGENGC_PROFILE >= 2
+ objspace->profile.shade_operation_count_types[BUILTIN_TYPE(obj)]++;
+#endif /* RGENGC_PROFILE >= 2 */
+#endif /* RGENGC_PROFILE */
+ }
+ else {
+ RVALUE_AGE_RESET(obj);
+ }
+
+ RB_DEBUG_COUNTER_INC(obj_wb_unprotect);
+ MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), obj);
+ }
+ RB_VM_LOCK_LEAVE_NO_BARRIER();
+ }
}
/*
* remember `obj' if needed.
*/
-void
+MJIT_FUNC_EXPORTED void
rb_gc_writebarrier_remember(VALUE obj)
{
- rb_gc_impl_writebarrier_remember(rb_gc_get_objspace(), obj);
+ rb_objspace_t *objspace = &rb_objspace;
+
+ gc_report(1, objspace, "rb_gc_writebarrier_remember: %s\n", obj_info(obj));
+
+ if (is_incremental_marking(objspace)) {
+ if (RVALUE_BLACK_P(obj)) {
+ gc_grey(objspace, obj);
+ }
+ }
+ else {
+ if (RVALUE_OLD_P(obj)) {
+ rgengc_remember(objspace, obj);
+ }
+ }
+}
+
+static st_table *rgengc_unprotect_logging_table;
+
+static int
+rgengc_unprotect_logging_exit_func_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ fprintf(stderr, "%s\t%"PRIuVALUE"\n", (char *)key, (VALUE)val);
+ return ST_CONTINUE;
+}
+
+static void
+rgengc_unprotect_logging_exit_func(void)
+{
+ st_foreach(rgengc_unprotect_logging_table, rgengc_unprotect_logging_exit_func_i, 0);
+}
+
+void
+rb_gc_unprotect_logging(void *objptr, const char *filename, int line)
+{
+ VALUE obj = (VALUE)objptr;
+
+ if (rgengc_unprotect_logging_table == 0) {
+ rgengc_unprotect_logging_table = st_init_strtable();
+ atexit(rgengc_unprotect_logging_exit_func);
+ }
+
+ if (RVALUE_WB_UNPROTECTED(obj) == 0) {
+ char buff[0x100];
+ st_data_t cnt = 1;
+ char *ptr = buff;
+
+ snprintf(ptr, 0x100 - 1, "%s|%s:%d", obj_info(obj), filename, line);
+
+ if (st_lookup(rgengc_unprotect_logging_table, (st_data_t)ptr, &cnt)) {
+ cnt++;
+ }
+ else {
+ ptr = (strdup)(buff);
+ if (!ptr) rb_memerror();
+ }
+ st_insert(rgengc_unprotect_logging_table, (st_data_t)ptr, cnt);
+ }
}
void
-rb_gc_copy_attributes(VALUE dest, VALUE obj)
+rb_copy_wb_protected_attribute(VALUE dest, VALUE obj)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+
+ if (RVALUE_WB_UNPROTECTED(obj) && !RVALUE_WB_UNPROTECTED(dest)) {
+ if (!RVALUE_OLD_P(dest)) {
+ MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(dest), dest);
+ RVALUE_AGE_RESET_RAW(dest);
+ }
+ else {
+ RVALUE_DEMOTE(objspace, dest);
+ }
+ }
+
+ check_rvalue_consistency(dest);
+}
+
+/* RGENGC analysis information */
+
+VALUE
+rb_obj_rgengc_writebarrier_protected_p(VALUE obj)
+{
+ return RBOOL(!RVALUE_WB_UNPROTECTED(obj));
+}
+
+VALUE
+rb_obj_rgengc_promoted_p(VALUE obj)
{
- rb_gc_impl_copy_attributes(rb_gc_get_objspace(), dest, obj);
+ return RBOOL(OBJ_PROMOTED(obj));
}
-// TODO: rearchitect this function to work for a generic GC
size_t
rb_obj_gc_flags(VALUE obj, ID* flags, size_t max)
{
- return rb_gc_impl_obj_flags(rb_gc_get_objspace(), obj, flags, max);
+ size_t n = 0;
+ static ID ID_marked;
+ static ID ID_wb_protected, ID_old, ID_marking, ID_uncollectible, ID_pinned;
+
+ if (!ID_marked) {
+#define I(s) ID_##s = rb_intern(#s);
+ I(marked);
+ I(wb_protected);
+ I(old);
+ I(marking);
+ I(uncollectible);
+ I(pinned);
+#undef I
+ }
+
+ if (RVALUE_WB_UNPROTECTED(obj) == 0 && n<max) flags[n++] = ID_wb_protected;
+ if (RVALUE_OLD_P(obj) && n<max) flags[n++] = ID_old;
+ if (RVALUE_UNCOLLECTIBLE(obj) && n<max) flags[n++] = ID_uncollectible;
+ if (MARKED_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), obj) && n<max) flags[n++] = ID_marking;
+ if (MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj) && n<max) flags[n++] = ID_marked;
+ if (MARKED_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj) && n<max) flags[n++] = ID_pinned;
+ return n;
}
/* GC */
-void *
-rb_gc_ractor_cache_alloc(void)
+void
+rb_gc_ractor_newobj_cache_clear(rb_ractor_newobj_cache_t *newobj_cache)
{
- return rb_gc_impl_ractor_cache_alloc(rb_gc_get_objspace());
+#if GC_ENABLE_INCREMENTAL_MARK
+ newobj_cache->incremental_mark_step_allocated_slots = 0;
+#endif
+
+ for (size_t size_pool_idx = 0; size_pool_idx < SIZE_POOL_COUNT; size_pool_idx++) {
+ rb_ractor_newobj_size_pool_cache_t *cache = &newobj_cache->size_pool_caches[size_pool_idx];
+
+ struct heap_page *page = cache->using_page;
+ RVALUE *freelist = cache->freelist;
+ RUBY_DEBUG_LOG("ractor using_page:%p freelist:%p", (void *)page, (void *)freelist);
+
+ heap_page_freelist_append(page, freelist);
+
+ cache->using_page = NULL;
+ cache->freelist = NULL;
+ }
}
void
-rb_gc_ractor_cache_free(void *cache)
+rb_gc_force_recycle(VALUE obj)
{
- rb_gc_impl_ractor_cache_free(rb_gc_get_objspace(), cache);
+ /* no-op */
}
+#ifndef MARK_OBJECT_ARY_BUCKET_SIZE
+#define MARK_OBJECT_ARY_BUCKET_SIZE 1024
+#endif
+
void
rb_gc_register_mark_object(VALUE obj)
{
- if (!rb_gc_impl_pointer_to_heap_p(rb_gc_get_objspace(), (void *)obj))
+ if (!is_pointer_to_heap(&rb_objspace, (void *)obj))
return;
- rb_vm_register_global_object(obj);
+ RB_VM_LOCK_ENTER();
+ {
+ VALUE ary_ary = GET_VM()->mark_object_ary;
+ VALUE ary = rb_ary_last(0, 0, ary_ary);
+
+ if (NIL_P(ary) || RARRAY_LEN(ary) >= MARK_OBJECT_ARY_BUCKET_SIZE) {
+ ary = rb_ary_hidden_new(MARK_OBJECT_ARY_BUCKET_SIZE);
+ rb_ary_push(ary_ary, ary);
+ }
+
+ rb_ary_push(ary, obj);
+ }
+ RB_VM_LOCK_LEAVE();
}
void
rb_gc_register_address(VALUE *addr)
{
- rb_vm_t *vm = GET_VM();
+ rb_objspace_t *objspace = &rb_objspace;
+ struct gc_list *tmp;
VALUE obj = *addr;
- struct global_object_list *tmp = ALLOC(struct global_object_list);
- tmp->next = vm->global_object_list;
+ tmp = ALLOC(struct gc_list);
+ tmp->next = global_list;
tmp->varptr = addr;
- vm->global_object_list = tmp;
+ global_list = tmp;
/*
* Because some C extensions have assignment-then-register bugs,
@@ -2797,26 +9294,26 @@ rb_gc_register_address(VALUE *addr)
*/
RB_GC_GUARD(obj);
if (0 && !SPECIAL_CONST_P(obj)) {
- rb_warn("Object is assigned to registering address already: %"PRIsVALUE,
- rb_obj_class(obj));
- rb_print_backtrace(stderr);
+ rb_warn("Object is assigned to registering address already: %"PRIsVALUE,
+ rb_obj_class(obj));
+ rb_print_backtrace();
}
}
void
rb_gc_unregister_address(VALUE *addr)
{
- rb_vm_t *vm = GET_VM();
- struct global_object_list *tmp = vm->global_object_list;
+ rb_objspace_t *objspace = &rb_objspace;
+ struct gc_list *tmp = global_list;
if (tmp->varptr == addr) {
- vm->global_object_list = tmp->next;
+ global_list = tmp->next;
xfree(tmp);
return;
}
while (tmp->next) {
if (tmp->next->varptr == addr) {
- struct global_object_list *t = tmp->next;
+ struct gc_list *t = tmp->next;
tmp->next = tmp->next->next;
xfree(t);
@@ -2832,66 +9329,786 @@ rb_global_variable(VALUE *var)
rb_gc_register_address(var);
}
+#define GC_NOTIFY 0
+
+enum {
+ gc_stress_no_major,
+ gc_stress_no_immediate_sweep,
+ gc_stress_full_mark_after_malloc,
+ gc_stress_max
+};
+
+#define gc_stress_full_mark_after_malloc_p() \
+ (FIXNUM_P(ruby_gc_stress_mode) && (FIX2LONG(ruby_gc_stress_mode) & (1<<gc_stress_full_mark_after_malloc)))
+
+static void
+heap_ready_to_gc(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap)
+{
+ if (!heap->free_pages) {
+ if (!heap_increment(objspace, size_pool, heap)) {
+ size_pool_allocatable_pages_set(objspace, size_pool, 1);
+ heap_increment(objspace, size_pool, heap);
+ }
+ }
+}
+
+static int
+ready_to_gc(rb_objspace_t *objspace)
+{
+ if (dont_gc_val() || during_gc || ruby_disable_gc) {
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ heap_ready_to_gc(objspace, size_pool, SIZE_POOL_EDEN_HEAP(size_pool));
+ }
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+}
+
+static void
+gc_reset_malloc_info(rb_objspace_t *objspace, bool full_mark)
+{
+ gc_prof_set_malloc_info(objspace);
+ {
+ size_t inc = ATOMIC_SIZE_EXCHANGE(malloc_increase, 0);
+ size_t old_limit = malloc_limit;
+
+ if (inc > malloc_limit) {
+ malloc_limit = (size_t)(inc * gc_params.malloc_limit_growth_factor);
+ if (malloc_limit > gc_params.malloc_limit_max) {
+ malloc_limit = gc_params.malloc_limit_max;
+ }
+ }
+ else {
+ malloc_limit = (size_t)(malloc_limit * 0.98); /* magic number */
+ if (malloc_limit < gc_params.malloc_limit_min) {
+ malloc_limit = gc_params.malloc_limit_min;
+ }
+ }
+
+ if (0) {
+ if (old_limit != malloc_limit) {
+ fprintf(stderr, "[%"PRIuSIZE"] malloc_limit: %"PRIuSIZE" -> %"PRIuSIZE"\n",
+ rb_gc_count(), old_limit, malloc_limit);
+ }
+ else {
+ fprintf(stderr, "[%"PRIuSIZE"] malloc_limit: not changed (%"PRIuSIZE")\n",
+ rb_gc_count(), malloc_limit);
+ }
+ }
+ }
+
+ /* reset oldmalloc info */
+#if RGENGC_ESTIMATE_OLDMALLOC
+ if (!full_mark) {
+ if (objspace->rgengc.oldmalloc_increase > objspace->rgengc.oldmalloc_increase_limit) {
+ objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_OLDMALLOC;
+ objspace->rgengc.oldmalloc_increase_limit =
+ (size_t)(objspace->rgengc.oldmalloc_increase_limit * gc_params.oldmalloc_limit_growth_factor);
+
+ if (objspace->rgengc.oldmalloc_increase_limit > gc_params.oldmalloc_limit_max) {
+ objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_max;
+ }
+ }
+
+ if (0) fprintf(stderr, "%"PRIdSIZE"\t%d\t%"PRIuSIZE"\t%"PRIuSIZE"\t%"PRIdSIZE"\n",
+ rb_gc_count(),
+ objspace->rgengc.need_major_gc,
+ objspace->rgengc.oldmalloc_increase,
+ objspace->rgengc.oldmalloc_increase_limit,
+ gc_params.oldmalloc_limit_max);
+ }
+ else {
+ /* major GC */
+ objspace->rgengc.oldmalloc_increase = 0;
+
+ if ((objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_BY_OLDMALLOC) == 0) {
+ objspace->rgengc.oldmalloc_increase_limit =
+ (size_t)(objspace->rgengc.oldmalloc_increase_limit / ((gc_params.oldmalloc_limit_growth_factor - 1)/10 + 1));
+ if (objspace->rgengc.oldmalloc_increase_limit < gc_params.oldmalloc_limit_min) {
+ objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_min;
+ }
+ }
+ }
+#endif
+}
+
+static int
+garbage_collect(rb_objspace_t *objspace, unsigned int reason)
+{
+ int ret;
+
+ RB_VM_LOCK_ENTER();
+ {
+#if GC_PROFILE_MORE_DETAIL
+ objspace->profile.prepare_time = getrusage_time();
+#endif
+
+ gc_rest(objspace);
+
+#if GC_PROFILE_MORE_DETAIL
+ objspace->profile.prepare_time = getrusage_time() - objspace->profile.prepare_time;
+#endif
+
+ ret = gc_start(objspace, reason);
+ }
+ RB_VM_LOCK_LEAVE();
+
+ return ret;
+}
+
+static int
+gc_start(rb_objspace_t *objspace, unsigned int reason)
+{
+ unsigned int do_full_mark = !!(reason & GPR_FLAG_FULL_MARK);
+#if GC_ENABLE_INCREMENTAL_MARK
+ unsigned int immediate_mark = reason & GPR_FLAG_IMMEDIATE_MARK;
+#endif
+
+ /* reason may be clobbered, later, so keep set immediate_sweep here */
+ objspace->flags.immediate_sweep = !!(reason & GPR_FLAG_IMMEDIATE_SWEEP);
+
+ /* Explicitly enable compaction (GC.compact) */
+ if (do_full_mark && ruby_enable_autocompact) {
+ objspace->flags.during_compacting = TRUE;
+ }
+ else {
+ objspace->flags.during_compacting = !!(reason & GPR_FLAG_COMPACT);
+ }
+
+ if (!heap_allocated_pages) return FALSE; /* heap is not ready */
+ if (!(reason & GPR_FLAG_METHOD) && !ready_to_gc(objspace)) return TRUE; /* GC is not allowed */
+
+ GC_ASSERT(gc_mode(objspace) == gc_mode_none);
+ GC_ASSERT(!is_lazy_sweeping(objspace));
+ GC_ASSERT(!is_incremental_marking(objspace));
+
+ unsigned int lock_lev;
+ gc_enter(objspace, gc_enter_event_start, &lock_lev);
+
+#if RGENGC_CHECK_MODE >= 2
+ gc_verify_internal_consistency(objspace);
+#endif
+
+ if (ruby_gc_stressful) {
+ int flag = FIXNUM_P(ruby_gc_stress_mode) ? FIX2INT(ruby_gc_stress_mode) : 0;
+
+ if ((flag & (1<<gc_stress_no_major)) == 0) {
+ do_full_mark = TRUE;
+ }
+
+ objspace->flags.immediate_sweep = !(flag & (1<<gc_stress_no_immediate_sweep));
+ }
+ else {
+ if (objspace->rgengc.need_major_gc) {
+ reason |= objspace->rgengc.need_major_gc;
+ do_full_mark = TRUE;
+ }
+ else if (RGENGC_FORCE_MAJOR_GC) {
+ reason = GPR_FLAG_MAJOR_BY_FORCE;
+ do_full_mark = TRUE;
+ }
+
+ objspace->rgengc.need_major_gc = GPR_FLAG_NONE;
+ }
+
+ if (do_full_mark && (reason & GPR_FLAG_MAJOR_MASK) == 0) {
+ reason |= GPR_FLAG_MAJOR_BY_FORCE; /* GC by CAPI, METHOD, and so on. */
+ }
+
+#if GC_ENABLE_INCREMENTAL_MARK
+ if (!GC_ENABLE_INCREMENTAL_MARK || objspace->flags.dont_incremental || immediate_mark) {
+ objspace->flags.during_incremental_marking = FALSE;
+ }
+ else {
+ objspace->flags.during_incremental_marking = do_full_mark;
+ }
+#endif
+
+ if (!GC_ENABLE_LAZY_SWEEP || objspace->flags.dont_incremental) {
+ objspace->flags.immediate_sweep = TRUE;
+ }
+
+ if (objspace->flags.immediate_sweep) reason |= GPR_FLAG_IMMEDIATE_SWEEP;
+
+ gc_report(1, objspace, "gc_start(reason: %x) => %u, %d, %d\n",
+ reason,
+ do_full_mark, !is_incremental_marking(objspace), objspace->flags.immediate_sweep);
+
+#if USE_DEBUG_COUNTER
+ RB_DEBUG_COUNTER_INC(gc_count);
+
+ if (reason & GPR_FLAG_MAJOR_MASK) {
+ (void)RB_DEBUG_COUNTER_INC_IF(gc_major_nofree, reason & GPR_FLAG_MAJOR_BY_NOFREE);
+ (void)RB_DEBUG_COUNTER_INC_IF(gc_major_oldgen, reason & GPR_FLAG_MAJOR_BY_OLDGEN);
+ (void)RB_DEBUG_COUNTER_INC_IF(gc_major_shady, reason & GPR_FLAG_MAJOR_BY_SHADY);
+ (void)RB_DEBUG_COUNTER_INC_IF(gc_major_force, reason & GPR_FLAG_MAJOR_BY_FORCE);
+#if RGENGC_ESTIMATE_OLDMALLOC
+ (void)RB_DEBUG_COUNTER_INC_IF(gc_major_oldmalloc, reason & GPR_FLAG_MAJOR_BY_OLDMALLOC);
+#endif
+ }
+ else {
+ (void)RB_DEBUG_COUNTER_INC_IF(gc_minor_newobj, reason & GPR_FLAG_NEWOBJ);
+ (void)RB_DEBUG_COUNTER_INC_IF(gc_minor_malloc, reason & GPR_FLAG_MALLOC);
+ (void)RB_DEBUG_COUNTER_INC_IF(gc_minor_method, reason & GPR_FLAG_METHOD);
+ (void)RB_DEBUG_COUNTER_INC_IF(gc_minor_capi, reason & GPR_FLAG_CAPI);
+ (void)RB_DEBUG_COUNTER_INC_IF(gc_minor_stress, reason & GPR_FLAG_STRESS);
+ }
+#endif
+
+ objspace->profile.count++;
+ objspace->profile.latest_gc_info = reason;
+ objspace->profile.total_allocated_objects_at_gc_start = objspace->total_allocated_objects;
+ objspace->profile.heap_used_at_gc_start = heap_allocated_pages;
+ gc_prof_setup_new_record(objspace, reason);
+ gc_reset_malloc_info(objspace, do_full_mark);
+ rb_transient_heap_start_marking(do_full_mark);
+
+ gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_START, 0 /* TODO: pass minor/immediate flag? */);
+ GC_ASSERT(during_gc);
+
+ gc_prof_timer_start(objspace);
+ {
+ gc_marks(objspace, do_full_mark);
+ }
+ gc_prof_timer_stop(objspace);
+
+ gc_exit(objspace, gc_enter_event_start, &lock_lev);
+ return TRUE;
+}
+
+static void
+gc_rest(rb_objspace_t *objspace)
+{
+ int marking = is_incremental_marking(objspace);
+ int sweeping = is_lazy_sweeping(objspace);
+
+ if (marking || sweeping) {
+ unsigned int lock_lev;
+ gc_enter(objspace, gc_enter_event_rest, &lock_lev);
+
+ if (RGENGC_CHECK_MODE >= 2) gc_verify_internal_consistency(objspace);
+
+ if (is_incremental_marking(objspace)) {
+ gc_marks_rest(objspace);
+ }
+ if (is_lazy_sweeping(objspace)) {
+ gc_sweep_rest(objspace);
+ }
+ gc_exit(objspace, gc_enter_event_rest, &lock_lev);
+ }
+}
+
+struct objspace_and_reason {
+ rb_objspace_t *objspace;
+ unsigned int reason;
+};
+
+static void
+gc_current_status_fill(rb_objspace_t *objspace, char *buff)
+{
+ int i = 0;
+ if (is_marking(objspace)) {
+ buff[i++] = 'M';
+ if (is_full_marking(objspace)) buff[i++] = 'F';
+#if GC_ENABLE_INCREMENTAL_MARK
+ if (is_incremental_marking(objspace)) buff[i++] = 'I';
+#endif
+ }
+ else if (is_sweeping(objspace)) {
+ buff[i++] = 'S';
+ if (is_lazy_sweeping(objspace)) buff[i++] = 'L';
+ }
+ else {
+ buff[i++] = 'N';
+ }
+ buff[i] = '\0';
+}
+
+static const char *
+gc_current_status(rb_objspace_t *objspace)
+{
+ static char buff[0x10];
+ gc_current_status_fill(objspace, buff);
+ return buff;
+}
+
+#if PRINT_ENTER_EXIT_TICK
+
+static tick_t last_exit_tick;
+static tick_t enter_tick;
+static int enter_count = 0;
+static char last_gc_status[0x10];
+
+static inline void
+gc_record(rb_objspace_t *objspace, int direction, const char *event)
+{
+ if (direction == 0) { /* enter */
+ enter_count++;
+ enter_tick = tick();
+ gc_current_status_fill(objspace, last_gc_status);
+ }
+ else { /* exit */
+ tick_t exit_tick = tick();
+ char current_gc_status[0x10];
+ gc_current_status_fill(objspace, current_gc_status);
+#if 1
+ /* [last mutator time] [gc time] [event] */
+ fprintf(stderr, "%"PRItick"\t%"PRItick"\t%s\t[%s->%s|%c]\n",
+ enter_tick - last_exit_tick,
+ exit_tick - enter_tick,
+ event,
+ last_gc_status, current_gc_status,
+ (objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_MASK) ? '+' : '-');
+ last_exit_tick = exit_tick;
+#else
+ /* [enter_tick] [gc time] [event] */
+ fprintf(stderr, "%"PRItick"\t%"PRItick"\t%s\t[%s->%s|%c]\n",
+ enter_tick,
+ exit_tick - enter_tick,
+ event,
+ last_gc_status, current_gc_status,
+ (objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_MASK) ? '+' : '-');
+#endif
+ }
+}
+#else /* PRINT_ENTER_EXIT_TICK */
+static inline void
+gc_record(rb_objspace_t *objspace, int direction, const char *event)
+{
+ /* null */
+}
+#endif /* PRINT_ENTER_EXIT_TICK */
+
+static const char *
+gc_enter_event_cstr(enum gc_enter_event event)
+{
+ switch (event) {
+ case gc_enter_event_start: return "start";
+ case gc_enter_event_mark_continue: return "mark_continue";
+ case gc_enter_event_sweep_continue: return "sweep_continue";
+ case gc_enter_event_rest: return "rest";
+ case gc_enter_event_finalizer: return "finalizer";
+ case gc_enter_event_rb_memerror: return "rb_memerror";
+ }
+ return NULL;
+}
+
+static void
+gc_enter_count(enum gc_enter_event event)
+{
+ switch (event) {
+ case gc_enter_event_start: RB_DEBUG_COUNTER_INC(gc_enter_start); break;
+ case gc_enter_event_mark_continue: RB_DEBUG_COUNTER_INC(gc_enter_mark_continue); break;
+ case gc_enter_event_sweep_continue: RB_DEBUG_COUNTER_INC(gc_enter_sweep_continue); break;
+ case gc_enter_event_rest: RB_DEBUG_COUNTER_INC(gc_enter_rest); break;
+ case gc_enter_event_finalizer: RB_DEBUG_COUNTER_INC(gc_enter_finalizer); break;
+ case gc_enter_event_rb_memerror: /* nothing */ break;
+ }
+}
+
+#ifndef MEASURE_GC
+#define MEASURE_GC (objspace->flags.measure_gc)
+#endif
+
+static bool
+gc_enter_event_measure_p(rb_objspace_t *objspace, enum gc_enter_event event)
+{
+ if (!MEASURE_GC) return false;
+
+ switch (event) {
+ case gc_enter_event_start:
+ case gc_enter_event_mark_continue:
+ case gc_enter_event_sweep_continue:
+ case gc_enter_event_rest:
+ return true;
+
+ default:
+ // case gc_enter_event_finalizer:
+ // case gc_enter_event_rb_memerror:
+ return false;
+ }
+}
+
+static bool current_process_time(struct timespec *ts);
+
+static void
+gc_enter_clock(rb_objspace_t *objspace, enum gc_enter_event event)
+{
+ if (gc_enter_event_measure_p(objspace, event)) {
+ if (!current_process_time(&objspace->profile.start_time)) {
+ objspace->profile.start_time.tv_sec = 0;
+ objspace->profile.start_time.tv_nsec = 0;
+ }
+ }
+}
+
+static void
+gc_exit_clock(rb_objspace_t *objspace, enum gc_enter_event event)
+{
+ if (gc_enter_event_measure_p(objspace, event)) {
+ struct timespec end_time;
+
+ if ((objspace->profile.start_time.tv_sec > 0 ||
+ objspace->profile.start_time.tv_nsec > 0) &&
+ current_process_time(&end_time)) {
+
+ if (end_time.tv_sec < objspace->profile.start_time.tv_sec) {
+ return; // ignore
+ }
+ else {
+ uint64_t ns =
+ (uint64_t)(end_time.tv_sec - objspace->profile.start_time.tv_sec) * (1000 * 1000 * 1000) +
+ (end_time.tv_nsec - objspace->profile.start_time.tv_nsec);
+ objspace->profile.total_time_ns += ns;
+ }
+ }
+ }
+}
+
+static inline void
+gc_enter(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_lev)
+{
+ RB_VM_LOCK_ENTER_LEV(lock_lev);
+
+ gc_enter_clock(objspace, event);
+
+ switch (event) {
+ case gc_enter_event_rest:
+ if (!is_marking(objspace)) break;
+ // fall through
+ case gc_enter_event_start:
+ case gc_enter_event_mark_continue:
+ // stop other ractors
+ rb_vm_barrier();
+ break;
+ default:
+ break;
+ }
+
+ gc_enter_count(event);
+ if (UNLIKELY(during_gc != 0)) rb_bug("during_gc != 0");
+ if (RGENGC_CHECK_MODE >= 3) gc_verify_internal_consistency(objspace);
+
+ during_gc = TRUE;
+ RUBY_DEBUG_LOG("%s (%s)",gc_enter_event_cstr(event), gc_current_status(objspace));
+ gc_report(1, objspace, "gc_enter: %s [%s]\n", gc_enter_event_cstr(event), gc_current_status(objspace));
+ gc_record(objspace, 0, gc_enter_event_cstr(event));
+ gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_ENTER, 0); /* TODO: which parameter should be passed? */
+}
+
+static inline void
+gc_exit(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_lev)
+{
+ GC_ASSERT(during_gc != 0);
+
+ gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_EXIT, 0); /* TODO: which parameter should be passsed? */
+ gc_record(objspace, 1, gc_enter_event_cstr(event));
+ RUBY_DEBUG_LOG("%s (%s)", gc_enter_event_cstr(event), gc_current_status(objspace));
+ gc_report(1, objspace, "gc_exit: %s [%s]\n", gc_enter_event_cstr(event), gc_current_status(objspace));
+ during_gc = FALSE;
+
+ gc_exit_clock(objspace, event);
+ RB_VM_LOCK_LEAVE_LEV(lock_lev);
+
+#if RGENGC_CHECK_MODE >= 2
+ if (event == gc_enter_event_sweep_continue && gc_mode(objspace) == gc_mode_none) {
+ GC_ASSERT(!during_gc);
+ // sweep finished
+ gc_verify_internal_consistency(objspace);
+ }
+#endif
+}
+
+static void *
+gc_with_gvl(void *ptr)
+{
+ struct objspace_and_reason *oar = (struct objspace_and_reason *)ptr;
+ return (void *)(VALUE)garbage_collect(oar->objspace, oar->reason);
+}
+
+static int
+garbage_collect_with_gvl(rb_objspace_t *objspace, unsigned int reason)
+{
+ if (dont_gc_val()) return TRUE;
+ if (ruby_thread_has_gvl_p()) {
+ return garbage_collect(objspace, reason);
+ }
+ else {
+ if (ruby_native_thread_p()) {
+ struct objspace_and_reason oar;
+ oar.objspace = objspace;
+ oar.reason = reason;
+ return (int)(VALUE)rb_thread_call_with_gvl(gc_with_gvl, (void *)&oar);
+ }
+ else {
+ /* no ruby thread */
+ fprintf(stderr, "[FATAL] failed to allocate memory\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
static VALUE
gc_start_internal(rb_execution_context_t *ec, VALUE self, VALUE full_mark, VALUE immediate_mark, VALUE immediate_sweep, VALUE compact)
{
- rb_gc_impl_start(rb_gc_get_objspace(), RTEST(full_mark), RTEST(immediate_mark), RTEST(immediate_sweep), RTEST(compact));
+ rb_objspace_t *objspace = &rb_objspace;
+ unsigned int reason = (GPR_FLAG_FULL_MARK |
+ GPR_FLAG_IMMEDIATE_MARK |
+ GPR_FLAG_IMMEDIATE_SWEEP |
+ GPR_FLAG_METHOD);
+
+ /* For now, compact implies full mark / sweep, so ignore other flags */
+ if (RTEST(compact)) {
+ GC_ASSERT(GC_COMPACTION_SUPPORTED);
+
+ reason |= GPR_FLAG_COMPACT;
+ }
+ else {
+ if (!RTEST(full_mark)) reason &= ~GPR_FLAG_FULL_MARK;
+ if (!RTEST(immediate_mark)) reason &= ~GPR_FLAG_IMMEDIATE_MARK;
+ if (!RTEST(immediate_sweep)) reason &= ~GPR_FLAG_IMMEDIATE_SWEEP;
+ }
+
+ garbage_collect(objspace, reason);
+ gc_finalize_deferred(objspace);
return Qnil;
}
-/*
- * rb_objspace_each_objects() is special C API to walk through
- * Ruby object space. This C API is too difficult to use it.
- * To be frank, you should not use it. Or you need to read the
- * source code of this function and understand what this function does.
- *
- * 'callback' will be called several times (the number of heap page,
- * at current implementation) with:
- * vstart: a pointer to the first living object of the heap_page.
- * vend: a pointer to next to the valid heap_page area.
- * stride: a distance to next VALUE.
- *
- * If callback() returns non-zero, the iteration will be stopped.
- *
- * This is a sample callback code to iterate liveness objects:
- *
- * static int
- * sample_callback(void *vstart, void *vend, int stride, void *data)
- * {
- * VALUE v = (VALUE)vstart;
- * for (; v != (VALUE)vend; v += stride) {
- * if (!rb_objspace_internal_object_p(v)) { // liveness check
- * // do something with live object 'v'
- * }
- * }
- * return 0; // continue to iteration
- * }
- *
- * Note: 'vstart' is not a top of heap_page. This point the first
- * living object to grasp at least one object to avoid GC issue.
- * This means that you can not walk through all Ruby object page
- * including freed object page.
- *
- * Note: On this implementation, 'stride' is the same as sizeof(RVALUE).
- * However, there are possibilities to pass variable values with
- * 'stride' with some reasons. You must use stride instead of
- * use some constant value in the iteration.
- */
-void
-rb_objspace_each_objects(int (*callback)(void *, void *, size_t, void *), void *data)
+static int
+gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj)
+{
+ GC_ASSERT(!SPECIAL_CONST_P(obj));
+
+ switch (BUILTIN_TYPE(obj)) {
+ case T_NONE:
+ case T_NIL:
+ case T_MOVED:
+ case T_ZOMBIE:
+ return FALSE;
+ case T_SYMBOL:
+ if (DYNAMIC_SYM_P(obj) && (RSYMBOL(obj)->id & ~ID_SCOPE_MASK)) {
+ return FALSE;
+ }
+ /* fall through */
+ case T_STRING:
+ case T_OBJECT:
+ case T_FLOAT:
+ case T_IMEMO:
+ case T_ARRAY:
+ case T_BIGNUM:
+ case T_ICLASS:
+ case T_MODULE:
+ case T_REGEXP:
+ case T_DATA:
+ case T_MATCH:
+ case T_STRUCT:
+ case T_HASH:
+ case T_FILE:
+ case T_COMPLEX:
+ case T_RATIONAL:
+ case T_NODE:
+ case T_CLASS:
+ if (FL_TEST(obj, FL_FINALIZE)) {
+ /* The finalizer table is a numtable. It looks up objects by address.
+ * We can't mark the keys in the finalizer table because that would
+ * prevent the objects from being collected. This check prevents
+ * objects that are keys in the finalizer table from being moved
+ * without directly pinning them. */
+ if (st_is_member(finalizer_table, obj)) {
+ return FALSE;
+ }
+ }
+ GC_ASSERT(RVALUE_MARKED(obj));
+ GC_ASSERT(!RVALUE_PINNED(obj));
+
+ return TRUE;
+
+ default:
+ rb_bug("gc_is_moveable_obj: unreachable (%d)", (int)BUILTIN_TYPE(obj));
+ break;
+ }
+
+ return FALSE;
+}
+
+/* Used in places that could malloc, which can cause the GC to run. We need to
+ * temporarily disable the GC to allow the malloc to happen. */
+#define COULD_MALLOC_REGION_START() \
+ GC_ASSERT(during_gc); \
+ VALUE _already_disabled = rb_gc_disable_no_rest(); \
+ during_gc = false;
+
+#define COULD_MALLOC_REGION_END() \
+ during_gc = true; \
+ if (_already_disabled == Qfalse) rb_objspace_gc_enable(objspace);
+
+static VALUE
+gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, size_t slot_size)
+{
+ int marked;
+ int wb_unprotected;
+ int uncollectible;
+ int marking;
+ RVALUE *dest = (RVALUE *)free;
+ RVALUE *src = (RVALUE *)scan;
+
+ gc_report(4, objspace, "Moving object: %p -> %p\n", (void*)scan, (void *)free);
+
+ GC_ASSERT(BUILTIN_TYPE(scan) != T_NONE);
+ GC_ASSERT(!MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(free), free));
+
+ /* Save off bits for current object. */
+ marked = rb_objspace_marked_object_p((VALUE)src);
+ wb_unprotected = RVALUE_WB_UNPROTECTED((VALUE)src);
+ uncollectible = RVALUE_UNCOLLECTIBLE((VALUE)src);
+ marking = RVALUE_MARKING((VALUE)src);
+
+ /* Clear bits for eventual T_MOVED */
+ CLEAR_IN_BITMAP(GET_HEAP_MARK_BITS((VALUE)src), (VALUE)src);
+ CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS((VALUE)src), (VALUE)src);
+ CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS((VALUE)src), (VALUE)src);
+ CLEAR_IN_BITMAP(GET_HEAP_MARKING_BITS((VALUE)src), (VALUE)src);
+
+ if (FL_TEST((VALUE)src, FL_EXIVAR)) {
+ /* Resizing the st table could cause a malloc */
+ COULD_MALLOC_REGION_START();
+ {
+ rb_mv_generic_ivar((VALUE)src, (VALUE)dest);
+ }
+ COULD_MALLOC_REGION_END();
+ }
+
+ st_data_t srcid = (st_data_t)src, id;
+
+ /* If the source object's object_id has been seen, we need to update
+ * the object to object id mapping. */
+ if (st_lookup(objspace->obj_to_id_tbl, srcid, &id)) {
+ gc_report(4, objspace, "Moving object with seen id: %p -> %p\n", (void *)src, (void *)dest);
+ /* Resizing the st table could cause a malloc */
+ COULD_MALLOC_REGION_START();
+ {
+ st_delete(objspace->obj_to_id_tbl, &srcid, 0);
+ st_insert(objspace->obj_to_id_tbl, (st_data_t)dest, id);
+ }
+ COULD_MALLOC_REGION_END();
+ }
+
+ /* Move the object */
+ memcpy(dest, src, MIN(src_slot_size, slot_size));
+
+ if (RVALUE_OVERHEAD > 0) {
+ void *dest_overhead = (void *)(((uintptr_t)dest) + slot_size - RVALUE_OVERHEAD);
+ void *src_overhead = (void *)(((uintptr_t)src) + src_slot_size - RVALUE_OVERHEAD);
+
+ memcpy(dest_overhead, src_overhead, RVALUE_OVERHEAD);
+ }
+
+ memset(src, 0, src_slot_size);
+
+ /* Set bits for object in new location */
+ if (marking) {
+ MARK_IN_BITMAP(GET_HEAP_MARKING_BITS((VALUE)dest), (VALUE)dest);
+ }
+ else {
+ CLEAR_IN_BITMAP(GET_HEAP_MARKING_BITS((VALUE)dest), (VALUE)dest);
+ }
+
+ if (marked) {
+ MARK_IN_BITMAP(GET_HEAP_MARK_BITS((VALUE)dest), (VALUE)dest);
+ }
+ else {
+ CLEAR_IN_BITMAP(GET_HEAP_MARK_BITS((VALUE)dest), (VALUE)dest);
+ }
+
+ if (wb_unprotected) {
+ MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS((VALUE)dest), (VALUE)dest);
+ }
+ else {
+ CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS((VALUE)dest), (VALUE)dest);
+ }
+
+ if (uncollectible) {
+ MARK_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS((VALUE)dest), (VALUE)dest);
+ }
+ else {
+ CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS((VALUE)dest), (VALUE)dest);
+ }
+
+ /* Assign forwarding address */
+ src->as.moved.flags = T_MOVED;
+ src->as.moved.dummy = Qundef;
+ src->as.moved.destination = (VALUE)dest;
+ GC_ASSERT(BUILTIN_TYPE((VALUE)dest) != T_NONE);
+
+ return (VALUE)src;
+}
+
+#if GC_CAN_COMPILE_COMPACTION
+static int
+compare_free_slots(const void *left, const void *right, void *dummy)
{
- rb_gc_impl_each_objects(rb_gc_get_objspace(), callback, data);
+ struct heap_page *left_page;
+ struct heap_page *right_page;
+
+ left_page = *(struct heap_page * const *)left;
+ right_page = *(struct heap_page * const *)right;
+
+ return left_page->free_slots - right_page->free_slots;
}
static void
-gc_ref_update_array(void *objspace, VALUE v)
+gc_sort_heap_by_empty_slots(rb_objspace_t *objspace)
+{
+ for (int j = 0; j < SIZE_POOL_COUNT; j++) {
+ rb_size_pool_t *size_pool = &size_pools[j];
+
+ size_t total_pages = SIZE_POOL_EDEN_HEAP(size_pool)->total_pages;
+ size_t size = size_mul_or_raise(total_pages, sizeof(struct heap_page *), rb_eRuntimeError);
+ struct heap_page *page = 0, **page_list = malloc(size);
+ size_t i = 0;
+
+ SIZE_POOL_EDEN_HEAP(size_pool)->free_pages = NULL;
+ ccan_list_for_each(&SIZE_POOL_EDEN_HEAP(size_pool)->pages, page, page_node) {
+ page_list[i++] = page;
+ GC_ASSERT(page);
+ }
+
+ GC_ASSERT((size_t)i == total_pages);
+
+ /* Sort the heap so "filled pages" are first. `heap_add_page` adds to the
+ * head of the list, so empty pages will end up at the start of the heap */
+ ruby_qsort(page_list, total_pages, sizeof(struct heap_page *), compare_free_slots, NULL);
+
+ /* Reset the eden heap */
+ ccan_list_head_init(&SIZE_POOL_EDEN_HEAP(size_pool)->pages);
+
+ for (i = 0; i < total_pages; i++) {
+ ccan_list_add(&SIZE_POOL_EDEN_HEAP(size_pool)->pages, &page_list[i]->page_node);
+ if (page_list[i]->free_slots != 0) {
+ heap_add_freepage(SIZE_POOL_EDEN_HEAP(size_pool), page_list[i]);
+ }
+ }
+
+ free(page_list);
+ }
+}
+#endif
+
+static void
+gc_ref_update_array(rb_objspace_t * objspace, VALUE v)
{
if (ARY_SHARED_P(v)) {
+#if USE_RVARGC
VALUE old_root = RARRAY(v)->as.heap.aux.shared_root;
+#endif
UPDATE_IF_MOVED(objspace, RARRAY(v)->as.heap.aux.shared_root);
+#if USE_RVARGC
VALUE new_root = RARRAY(v)->as.heap.aux.shared_root;
// If the root is embedded and its location has changed
if (ARY_EMBED_P(new_root) && new_root != old_root) {
@@ -2899,133 +10116,339 @@ gc_ref_update_array(void *objspace, VALUE v)
GC_ASSERT(RARRAY(v)->as.heap.ptr >= RARRAY(old_root)->as.ary);
RARRAY(v)->as.heap.ptr = RARRAY(new_root)->as.ary + offset;
}
+#endif
}
else {
long len = RARRAY_LEN(v);
if (len > 0) {
- VALUE *ptr = (VALUE *)RARRAY_CONST_PTR(v);
+ VALUE *ptr = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(v);
for (long i = 0; i < len; i++) {
UPDATE_IF_MOVED(objspace, ptr[i]);
}
}
+#if USE_RVARGC
if (rb_gc_obj_slot_size(v) >= rb_ary_size_as_embedded(v)) {
if (rb_ary_embeddable_p(v)) {
rb_ary_make_embedded(v);
}
}
+#endif
}
}
static void
-gc_ref_update_object(void *objspace, VALUE v)
+gc_ref_update_object(rb_objspace_t *objspace, VALUE v)
{
VALUE *ptr = ROBJECT_IVPTR(v);
if (rb_shape_obj_too_complex(v)) {
- gc_ref_update_table_values_only(ROBJECT_IV_HASH(v));
+ rb_gc_update_tbl_refs(ROBJECT_IV_HASH(v));
return;
}
+#if USE_RVARGC
size_t slot_size = rb_gc_obj_slot_size(v);
size_t embed_size = rb_obj_embedded_size(ROBJECT_IV_CAPACITY(v));
if (slot_size >= embed_size && !RB_FL_TEST_RAW(v, ROBJECT_EMBED)) {
// Object can be re-embedded
memcpy(ROBJECT(v)->as.ary, ptr, sizeof(VALUE) * ROBJECT_IV_COUNT(v));
RB_FL_SET_RAW(v, ROBJECT_EMBED);
- xfree(ptr);
+ if (ROBJ_TRANSIENT_P(v)) {
+ ROBJ_TRANSIENT_UNSET(v);
+ }
+ else {
+ xfree(ptr);
+ }
ptr = ROBJECT(v)->as.ary;
}
+#endif
for (uint32_t i = 0; i < ROBJECT_IV_COUNT(v); i++) {
UPDATE_IF_MOVED(objspace, ptr[i]);
}
}
-void
-rb_gc_ref_update_table_values_only(st_table *tbl)
+static int
+hash_replace_ref(st_data_t *key, st_data_t *value, st_data_t argp, int existing)
+{
+ rb_objspace_t *objspace = (rb_objspace_t *)argp;
+
+ if (gc_object_moved_p(objspace, (VALUE)*key)) {
+ *key = rb_gc_location((VALUE)*key);
+ }
+
+ if (gc_object_moved_p(objspace, (VALUE)*value)) {
+ *value = rb_gc_location((VALUE)*value);
+ }
+
+ return ST_CONTINUE;
+}
+
+static int
+hash_foreach_replace(st_data_t key, st_data_t value, st_data_t argp, int error)
+{
+ rb_objspace_t *objspace;
+
+ objspace = (rb_objspace_t *)argp;
+
+ if (gc_object_moved_p(objspace, (VALUE)key)) {
+ return ST_REPLACE;
+ }
+
+ if (gc_object_moved_p(objspace, (VALUE)value)) {
+ return ST_REPLACE;
+ }
+ return ST_CONTINUE;
+}
+
+static int
+hash_replace_ref_value(st_data_t *key, st_data_t *value, st_data_t argp, int existing)
+{
+ rb_objspace_t *objspace = (rb_objspace_t *)argp;
+
+ if (gc_object_moved_p(objspace, (VALUE)*value)) {
+ *value = rb_gc_location((VALUE)*value);
+ }
+
+ return ST_CONTINUE;
+}
+
+static int
+hash_foreach_replace_value(st_data_t key, st_data_t value, st_data_t argp, int error)
{
- gc_ref_update_table_values_only(tbl);
+ rb_objspace_t *objspace;
+
+ objspace = (rb_objspace_t *)argp;
+
+ if (gc_object_moved_p(objspace, (VALUE)value)) {
+ return ST_REPLACE;
+ }
+ return ST_CONTINUE;
+}
+
+static void
+gc_update_tbl_refs(rb_objspace_t * objspace, st_table *tbl)
+{
+ if (!tbl || tbl->num_entries == 0) return;
+
+ if (st_foreach_with_replace(tbl, hash_foreach_replace_value, hash_replace_ref_value, (st_data_t)objspace)) {
+ rb_raise(rb_eRuntimeError, "hash modified during iteration");
+ }
+}
+
+static void
+gc_update_table_refs(rb_objspace_t * objspace, st_table *tbl)
+{
+ if (!tbl || tbl->num_entries == 0) return;
+
+ if (st_foreach_with_replace(tbl, hash_foreach_replace, hash_replace_ref, (st_data_t)objspace)) {
+ rb_raise(rb_eRuntimeError, "hash modified during iteration");
+ }
}
-/* Update MOVED references in a VALUE=>VALUE st_table */
+/* Update MOVED references in an st_table */
void
rb_gc_update_tbl_refs(st_table *ptr)
{
- gc_update_table_refs(ptr);
+ rb_objspace_t *objspace = &rb_objspace;
+ gc_update_table_refs(objspace, ptr);
}
static void
-gc_ref_update_hash(void *objspace, VALUE v)
+gc_ref_update_hash(rb_objspace_t * objspace, VALUE v)
{
rb_hash_stlike_foreach_with_replace(v, hash_foreach_replace, hash_replace_ref, (st_data_t)objspace);
}
static void
-gc_update_values(void *objspace, long n, VALUE *values)
+gc_ref_update_method_entry(rb_objspace_t *objspace, rb_method_entry_t *me)
{
- for (long i = 0; i < n; i++) {
+ rb_method_definition_t *def = me->def;
+
+ UPDATE_IF_MOVED(objspace, me->owner);
+ UPDATE_IF_MOVED(objspace, me->defined_class);
+
+ if (def) {
+ switch (def->type) {
+ case VM_METHOD_TYPE_ISEQ:
+ if (def->body.iseq.iseqptr) {
+ TYPED_UPDATE_IF_MOVED(objspace, rb_iseq_t *, def->body.iseq.iseqptr);
+ }
+ TYPED_UPDATE_IF_MOVED(objspace, rb_cref_t *, def->body.iseq.cref);
+ break;
+ case VM_METHOD_TYPE_ATTRSET:
+ case VM_METHOD_TYPE_IVAR:
+ UPDATE_IF_MOVED(objspace, def->body.attr.location);
+ break;
+ case VM_METHOD_TYPE_BMETHOD:
+ UPDATE_IF_MOVED(objspace, def->body.bmethod.proc);
+ break;
+ case VM_METHOD_TYPE_ALIAS:
+ TYPED_UPDATE_IF_MOVED(objspace, struct rb_method_entry_struct *, def->body.alias.original_me);
+ return;
+ case VM_METHOD_TYPE_REFINED:
+ TYPED_UPDATE_IF_MOVED(objspace, struct rb_method_entry_struct *, def->body.refined.orig_me);
+ UPDATE_IF_MOVED(objspace, def->body.refined.owner);
+ break;
+ case VM_METHOD_TYPE_CFUNC:
+ case VM_METHOD_TYPE_ZSUPER:
+ case VM_METHOD_TYPE_MISSING:
+ case VM_METHOD_TYPE_OPTIMIZED:
+ case VM_METHOD_TYPE_UNDEF:
+ case VM_METHOD_TYPE_NOTIMPLEMENTED:
+ break;
+ }
+ }
+}
+
+static void
+gc_update_values(rb_objspace_t *objspace, long n, VALUE *values)
+{
+ long i;
+
+ for (i=0; i<n; i++) {
UPDATE_IF_MOVED(objspace, values[i]);
}
}
-void
-rb_gc_update_values(long n, VALUE *values)
+static void
+gc_ref_update_imemo(rb_objspace_t *objspace, VALUE obj)
{
- gc_update_values(rb_gc_get_objspace(), n, values);
+ switch (imemo_type(obj)) {
+ case imemo_env:
+ {
+ rb_env_t *env = (rb_env_t *)obj;
+ if (LIKELY(env->ep)) {
+ // just after newobj() can be NULL here.
+ TYPED_UPDATE_IF_MOVED(objspace, rb_iseq_t *, env->iseq);
+ UPDATE_IF_MOVED(objspace, env->ep[VM_ENV_DATA_INDEX_ENV]);
+ gc_update_values(objspace, (long)env->env_size, (VALUE *)env->env);
+ }
+ }
+ break;
+ case imemo_cref:
+ UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.cref.klass_or_self);
+ TYPED_UPDATE_IF_MOVED(objspace, struct rb_cref_struct *, RANY(obj)->as.imemo.cref.next);
+ UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.cref.refinements);
+ break;
+ case imemo_svar:
+ UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.cref_or_me);
+ UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.lastline);
+ UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.backref);
+ UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.svar.others);
+ break;
+ case imemo_throw_data:
+ UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.throw_data.throw_obj);
+ break;
+ case imemo_ifunc:
+ break;
+ case imemo_memo:
+ UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.memo.v1);
+ UPDATE_IF_MOVED(objspace, RANY(obj)->as.imemo.memo.v2);
+ break;
+ case imemo_ment:
+ gc_ref_update_method_entry(objspace, &RANY(obj)->as.imemo.ment);
+ break;
+ case imemo_iseq:
+ rb_iseq_update_references((rb_iseq_t *)obj);
+ break;
+ case imemo_ast:
+ rb_ast_update_references((rb_ast_t *)obj);
+ break;
+ case imemo_callcache:
+ {
+ const struct rb_callcache *cc = (const struct rb_callcache *)obj;
+ if (cc->klass) {
+ UPDATE_IF_MOVED(objspace, cc->klass);
+ if (!is_live_object(objspace, cc->klass)) {
+ *((VALUE *)(&cc->klass)) = (VALUE)0;
+ }
+ }
+
+ if (cc->cme_) {
+ TYPED_UPDATE_IF_MOVED(objspace, struct rb_callable_method_entry_struct *, cc->cme_);
+ if (!is_live_object(objspace, (VALUE)cc->cme_)) {
+ *((struct rb_callable_method_entry_struct **)(&cc->cme_)) = (struct rb_callable_method_entry_struct *)0;
+ }
+ }
+ }
+ break;
+ case imemo_constcache:
+ {
+ const struct iseq_inline_constant_cache_entry *ice = (struct iseq_inline_constant_cache_entry *)obj;
+ UPDATE_IF_MOVED(objspace, ice->value);
+ }
+ break;
+ case imemo_parser_strterm:
+ case imemo_tmpbuf:
+ case imemo_callinfo:
+ break;
+ default:
+ rb_bug("not reachable %d", imemo_type(obj));
+ break;
+ }
}
static enum rb_id_table_iterator_result
check_id_table_move(VALUE value, void *data)
{
- void *objspace = (void *)data;
+ rb_objspace_t *objspace = (rb_objspace_t *)data;
- if (rb_gc_impl_object_moved_p(objspace, (VALUE)value)) {
+ if (gc_object_moved_p(objspace, (VALUE)value)) {
return ID_TABLE_REPLACE;
}
return ID_TABLE_CONTINUE;
}
+/* Returns the new location of an object, if it moved. Otherwise returns
+ * the existing location. */
VALUE
rb_gc_location(VALUE value)
{
- return rb_gc_impl_location(rb_gc_get_objspace(), value);
-}
-void
-rb_gc_prepare_heap(void)
-{
- rb_gc_impl_prepare_heap(rb_gc_get_objspace());
-}
+ VALUE destination;
-size_t
-rb_gc_heap_id_for_size(size_t size)
-{
- return rb_gc_impl_heap_id_for_size(rb_gc_get_objspace(), size);
-}
+ if (!SPECIAL_CONST_P(value)) {
+ void *poisoned = asan_unpoison_object_temporary(value);
-bool
-rb_gc_size_allocatable_p(size_t size)
-{
- return rb_gc_impl_size_allocatable_p(size);
+ if (BUILTIN_TYPE(value) == T_MOVED) {
+ destination = (VALUE)RMOVED(value)->destination;
+ GC_ASSERT(BUILTIN_TYPE(destination) != T_NONE);
+ }
+ else {
+ destination = value;
+ }
+
+ /* Re-poison slot if it's not the one we want */
+ if (poisoned) {
+ GC_ASSERT(BUILTIN_TYPE(value) == T_NONE);
+ asan_poison_object(value);
+ }
+ }
+ else {
+ destination = value;
+ }
+
+ return destination;
}
static enum rb_id_table_iterator_result
update_id_table(VALUE *value, void *data, int existing)
{
- void *objspace = (void *)data;
+ rb_objspace_t *objspace = (rb_objspace_t *)data;
- if (rb_gc_impl_object_moved_p(objspace, (VALUE)*value)) {
- *value = rb_gc_impl_location(objspace, (VALUE)*value);
+ if (gc_object_moved_p(objspace, (VALUE)*value)) {
+ *value = rb_gc_location((VALUE)*value);
}
return ID_TABLE_CONTINUE;
}
static void
-update_m_tbl(void *objspace, struct rb_id_table *tbl)
+update_m_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl)
{
if (tbl) {
rb_id_table_foreach_values_with_replace(tbl, check_id_table_move, update_id_table, objspace);
@@ -3033,17 +10456,21 @@ update_m_tbl(void *objspace, struct rb_id_table *tbl)
}
static enum rb_id_table_iterator_result
-update_cc_tbl_i(VALUE ccs_ptr, void *objspace)
+update_cc_tbl_i(VALUE ccs_ptr, void *data)
{
+ rb_objspace_t *objspace = (rb_objspace_t *)data;
struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
VM_ASSERT(vm_ccs_p(ccs));
- if (rb_gc_impl_object_moved_p(objspace, (VALUE)ccs->cme)) {
- ccs->cme = (const rb_callable_method_entry_t *)rb_gc_impl_location(objspace, (VALUE)ccs->cme);
+ if (gc_object_moved_p(objspace, (VALUE)ccs->cme)) {
+ ccs->cme = (const rb_callable_method_entry_t *)rb_gc_location((VALUE)ccs->cme);
}
for (int i=0; i<ccs->len; i++) {
- if (rb_gc_impl_object_moved_p(objspace, (VALUE)ccs->entries[i].cc)) {
+ if (gc_object_moved_p(objspace, (VALUE)ccs->entries[i].ci)) {
+ ccs->entries[i].ci = (struct rb_callinfo *)rb_gc_location((VALUE)ccs->entries[i].ci);
+ }
+ if (gc_object_moved_p(objspace, (VALUE)ccs->entries[i].cc)) {
ccs->entries[i].cc = (struct rb_callcache *)rb_gc_location((VALUE)ccs->entries[i].cc);
}
}
@@ -3053,7 +10480,7 @@ update_cc_tbl_i(VALUE ccs_ptr, void *objspace)
}
static void
-update_cc_tbl(void *objspace, VALUE klass)
+update_cc_tbl(rb_objspace_t *objspace, VALUE klass)
{
struct rb_id_table *tbl = RCLASS_CC_TBL(klass);
if (tbl) {
@@ -3062,9 +10489,10 @@ update_cc_tbl(void *objspace, VALUE klass)
}
static enum rb_id_table_iterator_result
-update_cvc_tbl_i(VALUE cvc_entry, void *objspace)
+update_cvc_tbl_i(VALUE cvc_entry, void *data)
{
struct rb_cvar_class_tbl_entry *entry;
+ rb_objspace_t * objspace = (rb_objspace_t *)data;
entry = (struct rb_cvar_class_tbl_entry *)cvc_entry;
@@ -3072,13 +10500,13 @@ update_cvc_tbl_i(VALUE cvc_entry, void *objspace)
TYPED_UPDATE_IF_MOVED(objspace, rb_cref_t *, entry->cref);
}
- entry->class_value = rb_gc_impl_location(objspace, entry->class_value);
+ entry->class_value = rb_gc_location(entry->class_value);
return ID_TABLE_CONTINUE;
}
static void
-update_cvc_tbl(void *objspace, VALUE klass)
+update_cvc_tbl(rb_objspace_t *objspace, VALUE klass)
{
struct rb_id_table *tbl = RCLASS_CVC_TBL(klass);
if (tbl) {
@@ -3087,30 +10515,53 @@ update_cvc_tbl(void *objspace, VALUE klass)
}
static enum rb_id_table_iterator_result
-update_const_table(VALUE value, void *objspace)
+mark_cvc_tbl_i(VALUE cvc_entry, void *data)
+{
+ struct rb_cvar_class_tbl_entry *entry;
+
+ entry = (struct rb_cvar_class_tbl_entry *)cvc_entry;
+
+ RUBY_ASSERT(entry->cref == 0 || (BUILTIN_TYPE((VALUE)entry->cref) == T_IMEMO && IMEMO_TYPE_P(entry->cref, imemo_cref)));
+ rb_gc_mark((VALUE) entry->cref);
+
+ return ID_TABLE_CONTINUE;
+}
+
+static void
+mark_cvc_tbl(rb_objspace_t *objspace, VALUE klass)
+{
+ struct rb_id_table *tbl = RCLASS_CVC_TBL(klass);
+ if (tbl) {
+ rb_id_table_foreach_values(tbl, mark_cvc_tbl_i, objspace);
+ }
+}
+
+static enum rb_id_table_iterator_result
+update_const_table(VALUE value, void *data)
{
rb_const_entry_t *ce = (rb_const_entry_t *)value;
+ rb_objspace_t * objspace = (rb_objspace_t *)data;
- if (rb_gc_impl_object_moved_p(objspace, ce->value)) {
- ce->value = rb_gc_impl_location(objspace, ce->value);
+ if (gc_object_moved_p(objspace, ce->value)) {
+ ce->value = rb_gc_location(ce->value);
}
- if (rb_gc_impl_object_moved_p(objspace, ce->file)) {
- ce->file = rb_gc_impl_location(objspace, ce->file);
+ if (gc_object_moved_p(objspace, ce->file)) {
+ ce->file = rb_gc_location(ce->file);
}
return ID_TABLE_CONTINUE;
}
static void
-update_const_tbl(void *objspace, struct rb_id_table *tbl)
+update_const_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl)
{
if (!tbl) return;
rb_id_table_foreach_values(tbl, update_const_table, objspace);
}
static void
-update_subclass_entries(void *objspace, rb_subclass_entry_t *entry)
+update_subclass_entries(rb_objspace_t *objspace, rb_subclass_entry_t *entry)
{
while (entry) {
UPDATE_IF_MOVED(objspace, entry->klass);
@@ -3119,7 +10570,7 @@ update_subclass_entries(void *objspace, rb_subclass_entry_t *entry)
}
static void
-update_class_ext(void *objspace, rb_classext_t *ext)
+update_class_ext(rb_objspace_t *objspace, rb_classext_t *ext)
{
UPDATE_IF_MOVED(objspace, ext->origin_);
UPDATE_IF_MOVED(objspace, ext->includer);
@@ -3128,7 +10579,7 @@ update_class_ext(void *objspace, rb_classext_t *ext)
}
static void
-update_superclasses(void *objspace, VALUE obj)
+update_superclasses(rb_objspace_t *objspace, VALUE obj)
{
if (FL_TEST_RAW(obj, RCLASS_SUPERCLASSES_INCLUDE_SELF)) {
for (size_t i = 0; i < RCLASS_SUPERCLASS_DEPTH(obj) + 1; i++) {
@@ -3137,81 +10588,49 @@ update_superclasses(void *objspace, VALUE obj)
}
}
-extern rb_symbols_t ruby_global_symbols;
-#define global_symbols ruby_global_symbols
-
-void
-rb_gc_update_vm_references(void *objspace)
+static void
+gc_update_object_references(rb_objspace_t *objspace, VALUE obj)
{
- rb_execution_context_t *ec = GET_EC();
- rb_vm_t *vm = rb_ec_vm_ptr(ec);
-
- rb_vm_update_references(vm);
- rb_gc_update_global_tbl();
- global_symbols.ids = rb_gc_impl_location(objspace, global_symbols.ids);
- global_symbols.dsymbol_fstr_hash = rb_gc_impl_location(objspace, global_symbols.dsymbol_fstr_hash);
- gc_update_table_refs(global_symbols.str_sym);
-
-#if USE_YJIT
- void rb_yjit_root_update_references(void); // in Rust
+ RVALUE *any = RANY(obj);
- if (rb_yjit_enabled_p) {
- rb_yjit_root_update_references();
- }
-#endif
-}
-
-void
-rb_gc_update_object_references(void *objspace, VALUE obj)
-{
- if (FL_TEST(obj, FL_EXIVAR)) {
- rb_ref_update_generic_ivar(obj);
- }
+ gc_report(4, objspace, "update-refs: %p ->\n", (void *)obj);
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
- if (FL_TEST(obj, FL_SINGLETON)) {
- UPDATE_IF_MOVED(objspace, RCLASS_ATTACHED_OBJECT(obj));
- }
- // Continue to the shared T_CLASS/T_MODULE
case T_MODULE:
if (RCLASS_SUPER((VALUE)obj)) {
UPDATE_IF_MOVED(objspace, RCLASS(obj)->super);
}
+ if (!RCLASS_EXT(obj)) break;
update_m_tbl(objspace, RCLASS_M_TBL(obj));
update_cc_tbl(objspace, obj);
update_cvc_tbl(objspace, obj);
update_superclasses(objspace, obj);
- if (rb_shape_obj_too_complex(obj)) {
- gc_ref_update_table_values_only(RCLASS_IV_HASH(obj));
- }
- else {
- for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
- UPDATE_IF_MOVED(objspace, RCLASS_IVPTR(obj)[i]);
- }
+ for (attr_index_t i = 0; i < RCLASS_IV_COUNT(obj); i++) {
+ UPDATE_IF_MOVED(objspace, RCLASS_IVPTR(obj)[i]);
}
update_class_ext(objspace, RCLASS_EXT(obj));
update_const_tbl(objspace, RCLASS_CONST_TBL(obj));
-
- UPDATE_IF_MOVED(objspace, RCLASS_EXT(obj)->classpath);
break;
case T_ICLASS:
- if (RICLASS_OWNS_M_TBL_P(obj)) {
+ if (FL_TEST(obj, RICLASS_IS_ORIGIN) &&
+ !FL_TEST(obj, RICLASS_ORIGIN_SHARED_MTBL)) {
update_m_tbl(objspace, RCLASS_M_TBL(obj));
}
if (RCLASS_SUPER((VALUE)obj)) {
UPDATE_IF_MOVED(objspace, RCLASS(obj)->super);
}
+ if (!RCLASS_EXT(obj)) break;
update_class_ext(objspace, RCLASS_EXT(obj));
update_m_tbl(objspace, RCLASS_CALLABLE_M_TBL(obj));
update_cc_tbl(objspace, obj);
break;
case T_IMEMO:
- rb_imemo_mark_and_move(obj, true);
+ gc_ref_update_imemo(objspace, obj);
return;
case T_NIL:
@@ -3228,15 +10647,26 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
case T_HASH:
gc_ref_update_hash(objspace, obj);
- UPDATE_IF_MOVED(objspace, RHASH(obj)->ifnone);
+ UPDATE_IF_MOVED(objspace, any->as.hash.ifnone);
break;
case T_STRING:
{
+#if USE_RVARGC
+#endif
+
if (STR_SHARED_P(obj)) {
- UPDATE_IF_MOVED(objspace, RSTRING(obj)->as.heap.aux.shared);
+#if USE_RVARGC
+ VALUE old_root = any->as.string.as.heap.aux.shared;
+#endif
+ UPDATE_IF_MOVED(objspace, any->as.string.as.heap.aux.shared);
+#if USE_RVARGC
+ VALUE new_root = any->as.string.as.heap.aux.shared;
+ rb_str_update_shared_ary(obj, old_root, new_root);
+#endif
}
+#if USE_RVARGC
/* If, after move the string is not embedded, and can fit in the
* slot it's been placed in, then re-embed it. */
if (rb_gc_obj_slot_size(obj) >= rb_str_size_as_embedded(obj)) {
@@ -3244,25 +10674,17 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
rb_str_make_embedded(obj);
}
}
+#endif
break;
}
case T_DATA:
/* Call the compaction callback, if it exists */
{
- void *const ptr = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
+ void *const ptr = DATA_PTR(obj);
if (ptr) {
- if (RTYPEDDATA_P(obj) && gc_declarative_marking_p(RTYPEDDATA(obj)->type)) {
- size_t *offset_list = (size_t *)RTYPEDDATA(obj)->type->function.dmark;
-
- for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) {
- VALUE *ref = (VALUE *)((char *)ptr + offset);
- if (SPECIAL_CONST_P(*ref)) continue;
- *ref = rb_gc_impl_location(objspace, *ref);
- }
- }
- else if (RTYPEDDATA_P(obj)) {
- RUBY_DATA_FUNC compact_func = RTYPEDDATA(obj)->type->function.dcompact;
+ if (RTYPEDDATA_P(obj)) {
+ RUBY_DATA_FUNC compact_func = any->as.typeddata.type->function.dcompact;
if (compact_func) (*compact_func)(ptr);
}
}
@@ -3274,22 +10696,24 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
break;
case T_FILE:
- if (RFILE(obj)->fptr) {
- UPDATE_IF_MOVED(objspace, RFILE(obj)->fptr->self);
- UPDATE_IF_MOVED(objspace, RFILE(obj)->fptr->pathv);
- UPDATE_IF_MOVED(objspace, RFILE(obj)->fptr->tied_io_for_writing);
- UPDATE_IF_MOVED(objspace, RFILE(obj)->fptr->writeconv_asciicompat);
- UPDATE_IF_MOVED(objspace, RFILE(obj)->fptr->writeconv_pre_ecopts);
- UPDATE_IF_MOVED(objspace, RFILE(obj)->fptr->encs.ecopts);
- UPDATE_IF_MOVED(objspace, RFILE(obj)->fptr->write_lock);
+ if (any->as.file.fptr) {
+ UPDATE_IF_MOVED(objspace, any->as.file.fptr->self);
+ UPDATE_IF_MOVED(objspace, any->as.file.fptr->pathv);
+ UPDATE_IF_MOVED(objspace, any->as.file.fptr->tied_io_for_writing);
+ UPDATE_IF_MOVED(objspace, any->as.file.fptr->writeconv_asciicompat);
+ UPDATE_IF_MOVED(objspace, any->as.file.fptr->writeconv_pre_ecopts);
+ UPDATE_IF_MOVED(objspace, any->as.file.fptr->encs.ecopts);
+ UPDATE_IF_MOVED(objspace, any->as.file.fptr->write_lock);
}
break;
case T_REGEXP:
- UPDATE_IF_MOVED(objspace, RREGEXP(obj)->src);
+ UPDATE_IF_MOVED(objspace, any->as.regexp.src);
break;
case T_SYMBOL:
- UPDATE_IF_MOVED(objspace, RSYMBOL(obj)->fstr);
+ if (DYNAMIC_SYM_P((VALUE)any)) {
+ UPDATE_IF_MOVED(objspace, RSYMBOL(any)->fstr);
+ }
break;
case T_FLOAT:
@@ -3297,21 +10721,21 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
break;
case T_MATCH:
- UPDATE_IF_MOVED(objspace, RMATCH(obj)->regexp);
+ UPDATE_IF_MOVED(objspace, any->as.match.regexp);
- if (RMATCH(obj)->str) {
- UPDATE_IF_MOVED(objspace, RMATCH(obj)->str);
+ if (any->as.match.str) {
+ UPDATE_IF_MOVED(objspace, any->as.match.str);
}
break;
case T_RATIONAL:
- UPDATE_IF_MOVED(objspace, RRATIONAL(obj)->num);
- UPDATE_IF_MOVED(objspace, RRATIONAL(obj)->den);
+ UPDATE_IF_MOVED(objspace, any->as.rational.num);
+ UPDATE_IF_MOVED(objspace, any->as.rational.den);
break;
case T_COMPLEX:
- UPDATE_IF_MOVED(objspace, RCOMPLEX(obj)->real);
- UPDATE_IF_MOVED(objspace, RCOMPLEX(obj)->imag);
+ UPDATE_IF_MOVED(objspace, any->as.complex.real);
+ UPDATE_IF_MOVED(objspace, any->as.complex.imag);
break;
@@ -3326,13 +10750,285 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
}
break;
default:
+#if GC_DEBUG
+ rb_gcdebug_print_obj_condition((VALUE)obj);
+ rb_obj_info_dump(obj);
rb_bug("unreachable");
+#endif
break;
+
}
UPDATE_IF_MOVED(objspace, RBASIC(obj)->klass);
+
+ gc_report(4, objspace, "update-refs: %p <-\n", (void *)obj);
+}
+
+static int
+gc_ref_update(void *vstart, void *vend, size_t stride, rb_objspace_t * objspace, struct heap_page *page)
+{
+ VALUE v = (VALUE)vstart;
+ asan_unlock_freelist(page);
+ asan_lock_freelist(page);
+ page->flags.has_uncollectible_shady_objects = FALSE;
+ page->flags.has_remembered_objects = FALSE;
+
+ /* For each object on the page */
+ for (; v != (VALUE)vend; v += stride) {
+ void *poisoned = asan_unpoison_object_temporary(v);
+
+ switch (BUILTIN_TYPE(v)) {
+ case T_NONE:
+ case T_MOVED:
+ case T_ZOMBIE:
+ break;
+ default:
+ if (RVALUE_WB_UNPROTECTED(v)) {
+ page->flags.has_uncollectible_shady_objects = TRUE;
+ }
+ if (RVALUE_PAGE_MARKING(page, v)) {
+ page->flags.has_remembered_objects = TRUE;
+ }
+ if (page->flags.before_sweep) {
+ if (RVALUE_MARKED(v)) {
+ gc_update_object_references(objspace, v);
+ }
+ }
+ else {
+ gc_update_object_references(objspace, v);
+ }
+ }
+
+ if (poisoned) {
+ asan_poison_object(v);
+ }
+ }
+
+ return 0;
+}
+
+extern rb_symbols_t ruby_global_symbols;
+#define global_symbols ruby_global_symbols
+
+static void
+gc_update_references(rb_objspace_t *objspace)
+{
+ rb_execution_context_t *ec = GET_EC();
+ rb_vm_t *vm = rb_ec_vm_ptr(ec);
+
+ struct heap_page *page = NULL;
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ bool should_set_mark_bits = TRUE;
+ rb_size_pool_t *size_pool = &size_pools[i];
+ rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
+
+ ccan_list_for_each(&heap->pages, page, page_node) {
+ uintptr_t start = (uintptr_t)page->start;
+ uintptr_t end = start + (page->total_slots * size_pool->slot_size);
+
+ gc_ref_update((void *)start, (void *)end, size_pool->slot_size, objspace, page);
+ if (page == heap->sweeping_page) {
+ should_set_mark_bits = FALSE;
+ }
+ if (should_set_mark_bits) {
+ gc_setup_mark_bits(page);
+ }
+ }
+ }
+ rb_vm_update_references(vm);
+ rb_transient_heap_update_references();
+ rb_gc_update_global_tbl();
+ global_symbols.ids = rb_gc_location(global_symbols.ids);
+ global_symbols.dsymbol_fstr_hash = rb_gc_location(global_symbols.dsymbol_fstr_hash);
+ gc_update_tbl_refs(objspace, objspace->obj_to_id_tbl);
+ gc_update_table_refs(objspace, objspace->id_to_obj_tbl);
+ gc_update_table_refs(objspace, global_symbols.str_sym);
+ gc_update_table_refs(objspace, finalizer_table);
}
+#if GC_CAN_COMPILE_COMPACTION
+/*
+ * call-seq:
+ * GC.latest_compact_info -> hash
+ *
+ * Returns information about object moved in the most recent \GC compaction.
+ *
+ * The returned hash has two keys :considered and :moved. The hash for
+ * :considered lists the number of objects that were considered for movement
+ * by the compactor, and the :moved hash lists the number of objects that
+ * were actually moved. Some objects can't be moved (maybe they were pinned)
+ * so these numbers can be used to calculate compaction efficiency.
+ */
+static VALUE
+gc_compact_stats(VALUE self)
+{
+ size_t i;
+ rb_objspace_t *objspace = &rb_objspace;
+ VALUE h = rb_hash_new();
+ VALUE considered = rb_hash_new();
+ VALUE moved = rb_hash_new();
+ VALUE moved_up = rb_hash_new();
+ VALUE moved_down = rb_hash_new();
+
+ for (i=0; i<T_MASK; i++) {
+ if (objspace->rcompactor.considered_count_table[i]) {
+ rb_hash_aset(considered, type_sym(i), SIZET2NUM(objspace->rcompactor.considered_count_table[i]));
+ }
+
+ if (objspace->rcompactor.moved_count_table[i]) {
+ rb_hash_aset(moved, type_sym(i), SIZET2NUM(objspace->rcompactor.moved_count_table[i]));
+ }
+
+ if (objspace->rcompactor.moved_up_count_table[i]) {
+ rb_hash_aset(moved_up, type_sym(i), SIZET2NUM(objspace->rcompactor.moved_up_count_table[i]));
+ }
+
+ if (objspace->rcompactor.moved_down_count_table[i]) {
+ rb_hash_aset(moved_down, type_sym(i), SIZET2NUM(objspace->rcompactor.moved_down_count_table[i]));
+ }
+ }
+
+ rb_hash_aset(h, ID2SYM(rb_intern("considered")), considered);
+ rb_hash_aset(h, ID2SYM(rb_intern("moved")), moved);
+ rb_hash_aset(h, ID2SYM(rb_intern("moved_up")), moved_up);
+ rb_hash_aset(h, ID2SYM(rb_intern("moved_down")), moved_down);
+
+ return h;
+}
+#else
+# define gc_compact_stats rb_f_notimplement
+#endif
+
+#if GC_CAN_COMPILE_COMPACTION
+static void
+root_obj_check_moved_i(const char *category, VALUE obj, void *data)
+{
+ if (gc_object_moved_p(&rb_objspace, obj)) {
+ rb_bug("ROOT %s points to MOVED: %p -> %s\n", category, (void *)obj, obj_info(rb_gc_location(obj)));
+ }
+}
+
+static void
+reachable_object_check_moved_i(VALUE ref, void *data)
+{
+ VALUE parent = (VALUE)data;
+ if (gc_object_moved_p(&rb_objspace, ref)) {
+ rb_bug("Object %s points to MOVED: %p -> %s\n", obj_info(parent), (void *)ref, obj_info(rb_gc_location(ref)));
+ }
+}
+
+static int
+heap_check_moved_i(void *vstart, void *vend, size_t stride, void *data)
+{
+ VALUE v = (VALUE)vstart;
+ for (; v != (VALUE)vend; v += stride) {
+ if (gc_object_moved_p(&rb_objspace, v)) {
+ /* Moved object still on the heap, something may have a reference. */
+ }
+ else {
+ void *poisoned = asan_unpoison_object_temporary(v);
+
+ switch (BUILTIN_TYPE(v)) {
+ case T_NONE:
+ case T_ZOMBIE:
+ break;
+ default:
+ if (!rb_objspace_garbage_object_p(v)) {
+ rb_objspace_reachable_objects_from(v, reachable_object_check_moved_i, (void *)v);
+ }
+ }
+
+ if (poisoned) {
+ GC_ASSERT(BUILTIN_TYPE(v) == T_NONE);
+ asan_poison_object(v);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * call-seq:
+ * GC.compact
+ *
+ * This function compacts objects together in Ruby's heap. It eliminates
+ * unused space (or fragmentation) in the heap by moving objects in to that
+ * unused space. This function returns a hash which contains statistics about
+ * which objects were moved. See <tt>GC.latest_gc_info</tt> for details about
+ * compaction statistics.
+ *
+ * This method is implementation specific and not expected to be implemented
+ * in any implementation besides MRI.
+ *
+ * To test whether \GC compaction is supported, use the idiom:
+ *
+ * GC.respond_to?(:compact)
+ */
+static VALUE
+gc_compact(VALUE self)
+{
+ /* Run GC with compaction enabled */
+ gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qtrue);
+
+ return gc_compact_stats(self);
+}
+#else
+# define gc_compact rb_f_notimplement
+#endif
+
+#if GC_CAN_COMPILE_COMPACTION
+static VALUE
+gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE double_heap, VALUE expand_heap, VALUE toward_empty)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+
+ /* Clear the heap. */
+ gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qfalse);
+ size_t growth_slots = gc_params.heap_init_slots;
+
+ if (RTEST(double_heap)) {
+ rb_warn("double_heap is deprecated, please use expand_heap instead");
+ }
+
+ RB_VM_LOCK_ENTER();
+ {
+ gc_rest(objspace);
+
+ /* if both double_heap and expand_heap are set, expand_heap takes precedence */
+ if (RTEST(double_heap) || RTEST(expand_heap)) {
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+ rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool);
+
+ if (RTEST(expand_heap)) {
+ size_t required_pages = growth_slots / size_pool->slot_size;
+ heap_add_pages(objspace, size_pool, heap, MAX(required_pages, heap->total_pages));
+ }
+ else {
+ heap_add_pages(objspace, size_pool, heap, heap->total_pages);
+ }
+ }
+ }
+
+ if (RTEST(toward_empty)) {
+ gc_sort_heap_by_empty_slots(objspace);
+ }
+ }
+ RB_VM_LOCK_LEAVE();
+
+ gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qtrue);
+
+ objspace_reachable_objects_from_root(objspace, root_obj_check_moved_i, NULL);
+ objspace_each_objects(objspace, heap_check_moved_i, NULL, TRUE);
+
+ return gc_compact_stats(self);
+}
+#else
+# define gc_verify_compaction_references (rb_builtin_arity3_function_type)rb_f_notimplement
+#endif
+
VALUE
rb_gc_start(void)
{
@@ -3343,23 +11039,39 @@ rb_gc_start(void)
void
rb_gc(void)
{
- unless_objspace(objspace) { return; }
-
- rb_gc_impl_start(objspace, true, true, true, false);
+ rb_objspace_t *objspace = &rb_objspace;
+ unsigned int reason = GPR_DEFAULT_REASON;
+ garbage_collect(objspace, reason);
}
int
rb_during_gc(void)
{
- unless_objspace(objspace) { return FALSE; }
+ rb_objspace_t *objspace = &rb_objspace;
+ return during_gc;
+}
- return rb_gc_impl_during_gc_p(objspace);
+#if RGENGC_PROFILE >= 2
+
+static const char *type_name(int type, VALUE obj);
+
+static void
+gc_count_add_each_types(VALUE hash, const char *name, const size_t *types)
+{
+ VALUE result = rb_hash_new_with_size(T_MASK);
+ int i;
+ for (i=0; i<T_MASK; i++) {
+ const char *type = type_name(i, 0);
+ rb_hash_aset(result, ID2SYM(rb_intern(type)), SIZET2NUM(types[i]));
+ }
+ rb_hash_aset(hash, ID2SYM(rb_intern(name)), result);
}
+#endif
size_t
rb_gc_count(void)
{
- return rb_gc_impl_gc_count(rb_gc_get_objspace());
+ return rb_objspace.profile.count;
}
static VALUE
@@ -3368,108 +11080,516 @@ gc_count(rb_execution_context_t *ec, VALUE self)
return SIZET2NUM(rb_gc_count());
}
+static VALUE
+gc_info_decode(rb_objspace_t *objspace, const VALUE hash_or_key, const unsigned int orig_flags)
+{
+ static VALUE sym_major_by = Qnil, sym_gc_by, sym_immediate_sweep, sym_have_finalizer, sym_state, sym_need_major_by;
+ static VALUE sym_nofree, sym_oldgen, sym_shady, sym_force, sym_stress;
+#if RGENGC_ESTIMATE_OLDMALLOC
+ static VALUE sym_oldmalloc;
+#endif
+ static VALUE sym_newobj, sym_malloc, sym_method, sym_capi;
+ static VALUE sym_none, sym_marking, sym_sweeping;
+ VALUE hash = Qnil, key = Qnil;
+ VALUE major_by, need_major_by;
+ unsigned int flags = orig_flags ? orig_flags : objspace->profile.latest_gc_info;
+
+ if (SYMBOL_P(hash_or_key)) {
+ key = hash_or_key;
+ }
+ else if (RB_TYPE_P(hash_or_key, T_HASH)) {
+ hash = hash_or_key;
+ }
+ else {
+ rb_raise(rb_eTypeError, "non-hash or symbol given");
+ }
+
+ if (NIL_P(sym_major_by)) {
+#define S(s) sym_##s = ID2SYM(rb_intern_const(#s))
+ S(major_by);
+ S(gc_by);
+ S(immediate_sweep);
+ S(have_finalizer);
+ S(state);
+ S(need_major_by);
+
+ S(stress);
+ S(nofree);
+ S(oldgen);
+ S(shady);
+ S(force);
+#if RGENGC_ESTIMATE_OLDMALLOC
+ S(oldmalloc);
+#endif
+ S(newobj);
+ S(malloc);
+ S(method);
+ S(capi);
+
+ S(none);
+ S(marking);
+ S(sweeping);
+#undef S
+ }
+
+#define SET(name, attr) \
+ if (key == sym_##name) \
+ return (attr); \
+ else if (hash != Qnil) \
+ rb_hash_aset(hash, sym_##name, (attr));
+
+ major_by =
+ (flags & GPR_FLAG_MAJOR_BY_NOFREE) ? sym_nofree :
+ (flags & GPR_FLAG_MAJOR_BY_OLDGEN) ? sym_oldgen :
+ (flags & GPR_FLAG_MAJOR_BY_SHADY) ? sym_shady :
+ (flags & GPR_FLAG_MAJOR_BY_FORCE) ? sym_force :
+#if RGENGC_ESTIMATE_OLDMALLOC
+ (flags & GPR_FLAG_MAJOR_BY_OLDMALLOC) ? sym_oldmalloc :
+#endif
+ Qnil;
+ SET(major_by, major_by);
+
+ if (orig_flags == 0) { /* set need_major_by only if flags not set explicitly */
+ unsigned int need_major_flags = objspace->rgengc.need_major_gc;
+ need_major_by =
+ (need_major_flags & GPR_FLAG_MAJOR_BY_NOFREE) ? sym_nofree :
+ (need_major_flags & GPR_FLAG_MAJOR_BY_OLDGEN) ? sym_oldgen :
+ (need_major_flags & GPR_FLAG_MAJOR_BY_SHADY) ? sym_shady :
+ (need_major_flags & GPR_FLAG_MAJOR_BY_FORCE) ? sym_force :
+#if RGENGC_ESTIMATE_OLDMALLOC
+ (need_major_flags & GPR_FLAG_MAJOR_BY_OLDMALLOC) ? sym_oldmalloc :
+#endif
+ Qnil;
+ SET(need_major_by, need_major_by);
+ }
+
+ SET(gc_by,
+ (flags & GPR_FLAG_NEWOBJ) ? sym_newobj :
+ (flags & GPR_FLAG_MALLOC) ? sym_malloc :
+ (flags & GPR_FLAG_METHOD) ? sym_method :
+ (flags & GPR_FLAG_CAPI) ? sym_capi :
+ (flags & GPR_FLAG_STRESS) ? sym_stress :
+ Qnil
+ );
+
+ SET(have_finalizer, RBOOL(flags & GPR_FLAG_HAVE_FINALIZE));
+ SET(immediate_sweep, RBOOL(flags & GPR_FLAG_IMMEDIATE_SWEEP));
+
+ if (orig_flags == 0) {
+ SET(state, gc_mode(objspace) == gc_mode_none ? sym_none :
+ gc_mode(objspace) == gc_mode_marking ? sym_marking : sym_sweeping);
+ }
+#undef SET
+
+ if (!NIL_P(key)) {/* matched key should return above */
+ rb_raise(rb_eArgError, "unknown key: %"PRIsVALUE, rb_sym2str(key));
+ }
+
+ return hash;
+}
+
VALUE
rb_gc_latest_gc_info(VALUE key)
{
- return rb_gc_impl_latest_gc_info(rb_gc_get_objspace(), key);
+ rb_objspace_t *objspace = &rb_objspace;
+ return gc_info_decode(objspace, key, 0);
}
static VALUE
-gc_stat(rb_execution_context_t *ec, VALUE self, VALUE arg) // arg is (nil || hash || symbol)
+gc_latest_gc_info(rb_execution_context_t *ec, VALUE self, VALUE arg)
{
+ rb_objspace_t *objspace = &rb_objspace;
+
if (NIL_P(arg)) {
arg = rb_hash_new();
}
+ else if (!SYMBOL_P(arg) && !RB_TYPE_P(arg, T_HASH)) {
+ rb_raise(rb_eTypeError, "non-hash or symbol given");
+ }
- size_t val = rb_gc_impl_stat(rb_gc_get_objspace(), arg);
+ return gc_info_decode(objspace, arg, 0);
+}
+
+enum gc_stat_sym {
+ gc_stat_sym_count,
+ gc_stat_sym_time,
+ gc_stat_sym_heap_allocated_pages,
+ gc_stat_sym_heap_sorted_length,
+ gc_stat_sym_heap_allocatable_pages,
+ gc_stat_sym_heap_available_slots,
+ gc_stat_sym_heap_live_slots,
+ gc_stat_sym_heap_free_slots,
+ gc_stat_sym_heap_final_slots,
+ gc_stat_sym_heap_marked_slots,
+ gc_stat_sym_heap_eden_pages,
+ gc_stat_sym_heap_tomb_pages,
+ gc_stat_sym_total_allocated_pages,
+ gc_stat_sym_total_freed_pages,
+ gc_stat_sym_total_allocated_objects,
+ gc_stat_sym_total_freed_objects,
+ gc_stat_sym_malloc_increase_bytes,
+ gc_stat_sym_malloc_increase_bytes_limit,
+ gc_stat_sym_minor_gc_count,
+ gc_stat_sym_major_gc_count,
+ gc_stat_sym_compact_count,
+ gc_stat_sym_read_barrier_faults,
+ gc_stat_sym_total_moved_objects,
+ gc_stat_sym_remembered_wb_unprotected_objects,
+ gc_stat_sym_remembered_wb_unprotected_objects_limit,
+ gc_stat_sym_old_objects,
+ gc_stat_sym_old_objects_limit,
+#if RGENGC_ESTIMATE_OLDMALLOC
+ gc_stat_sym_oldmalloc_increase_bytes,
+ gc_stat_sym_oldmalloc_increase_bytes_limit,
+#endif
+#if RGENGC_PROFILE
+ gc_stat_sym_total_generated_normal_object_count,
+ gc_stat_sym_total_generated_shady_object_count,
+ gc_stat_sym_total_shade_operation_count,
+ gc_stat_sym_total_promoted_count,
+ gc_stat_sym_total_remembered_normal_object_count,
+ gc_stat_sym_total_remembered_shady_object_count,
+#endif
+ gc_stat_sym_last
+};
- if (SYMBOL_P(arg)) {
- return SIZET2NUM(val);
- }
- else {
- return arg;
+static VALUE gc_stat_symbols[gc_stat_sym_last];
+
+static void
+setup_gc_stat_symbols(void)
+{
+ if (gc_stat_symbols[0] == 0) {
+#define S(s) gc_stat_symbols[gc_stat_sym_##s] = ID2SYM(rb_intern_const(#s))
+ S(count);
+ S(time);
+ S(heap_allocated_pages);
+ S(heap_sorted_length);
+ S(heap_allocatable_pages);
+ S(heap_available_slots);
+ S(heap_live_slots);
+ S(heap_free_slots);
+ S(heap_final_slots);
+ S(heap_marked_slots);
+ S(heap_eden_pages);
+ S(heap_tomb_pages);
+ S(total_allocated_pages);
+ S(total_freed_pages);
+ S(total_allocated_objects);
+ S(total_freed_objects);
+ S(malloc_increase_bytes);
+ S(malloc_increase_bytes_limit);
+ S(minor_gc_count);
+ S(major_gc_count);
+ S(compact_count);
+ S(read_barrier_faults);
+ S(total_moved_objects);
+ S(remembered_wb_unprotected_objects);
+ S(remembered_wb_unprotected_objects_limit);
+ S(old_objects);
+ S(old_objects_limit);
+#if RGENGC_ESTIMATE_OLDMALLOC
+ S(oldmalloc_increase_bytes);
+ S(oldmalloc_increase_bytes_limit);
+#endif
+#if RGENGC_PROFILE
+ S(total_generated_normal_object_count);
+ S(total_generated_shady_object_count);
+ S(total_shade_operation_count);
+ S(total_promoted_count);
+ S(total_remembered_normal_object_count);
+ S(total_remembered_shady_object_count);
+#endif /* RGENGC_PROFILE */
+#undef S
}
}
-size_t
-rb_gc_stat(VALUE key)
+static size_t
+gc_stat_internal(VALUE hash_or_sym)
{
- if (SYMBOL_P(key)) {
- return rb_gc_impl_stat(rb_gc_get_objspace(), key);
+ rb_objspace_t *objspace = &rb_objspace;
+ VALUE hash = Qnil, key = Qnil;
+
+ setup_gc_stat_symbols();
+
+ if (RB_TYPE_P(hash_or_sym, T_HASH)) {
+ hash = hash_or_sym;
+ }
+ else if (SYMBOL_P(hash_or_sym)) {
+ key = hash_or_sym;
}
else {
- rb_gc_impl_stat(rb_gc_get_objspace(), key);
- return 0;
+ rb_raise(rb_eTypeError, "non-hash or symbol argument");
+ }
+
+#define SET(name, attr) \
+ if (key == gc_stat_symbols[gc_stat_sym_##name]) \
+ return attr; \
+ else if (hash != Qnil) \
+ rb_hash_aset(hash, gc_stat_symbols[gc_stat_sym_##name], SIZET2NUM(attr));
+
+ SET(count, objspace->profile.count);
+ SET(time, (size_t) (objspace->profile.total_time_ns / (1000 * 1000) /* ns -> ms */)); // TODO: UINT64T2NUM
+
+ /* implementation dependent counters */
+ SET(heap_allocated_pages, heap_allocated_pages);
+ SET(heap_sorted_length, heap_pages_sorted_length);
+ SET(heap_allocatable_pages, heap_allocatable_pages(objspace));
+ SET(heap_available_slots, objspace_available_slots(objspace));
+ SET(heap_live_slots, objspace_live_slots(objspace));
+ SET(heap_free_slots, objspace_free_slots(objspace));
+ SET(heap_final_slots, heap_pages_final_slots);
+ SET(heap_marked_slots, objspace->marked_slots);
+ SET(heap_eden_pages, heap_eden_total_pages(objspace));
+ SET(heap_tomb_pages, heap_tomb_total_pages(objspace));
+ SET(total_allocated_pages, total_allocated_pages(objspace));
+ SET(total_freed_pages, total_freed_pages(objspace));
+ SET(total_allocated_objects, objspace->total_allocated_objects);
+ SET(total_freed_objects, objspace->profile.total_freed_objects);
+ SET(malloc_increase_bytes, malloc_increase);
+ SET(malloc_increase_bytes_limit, malloc_limit);
+ SET(minor_gc_count, objspace->profile.minor_gc_count);
+ SET(major_gc_count, objspace->profile.major_gc_count);
+ SET(compact_count, objspace->profile.compact_count);
+ SET(read_barrier_faults, objspace->profile.read_barrier_faults);
+ SET(total_moved_objects, objspace->rcompactor.total_moved);
+ SET(remembered_wb_unprotected_objects, objspace->rgengc.uncollectible_wb_unprotected_objects);
+ SET(remembered_wb_unprotected_objects_limit, objspace->rgengc.uncollectible_wb_unprotected_objects_limit);
+ SET(old_objects, objspace->rgengc.old_objects);
+ SET(old_objects_limit, objspace->rgengc.old_objects_limit);
+#if RGENGC_ESTIMATE_OLDMALLOC
+ SET(oldmalloc_increase_bytes, objspace->rgengc.oldmalloc_increase);
+ SET(oldmalloc_increase_bytes_limit, objspace->rgengc.oldmalloc_increase_limit);
+#endif
+
+#if RGENGC_PROFILE
+ SET(total_generated_normal_object_count, objspace->profile.total_generated_normal_object_count);
+ SET(total_generated_shady_object_count, objspace->profile.total_generated_shady_object_count);
+ SET(total_shade_operation_count, objspace->profile.total_shade_operation_count);
+ SET(total_promoted_count, objspace->profile.total_promoted_count);
+ SET(total_remembered_normal_object_count, objspace->profile.total_remembered_normal_object_count);
+ SET(total_remembered_shady_object_count, objspace->profile.total_remembered_shady_object_count);
+#endif /* RGENGC_PROFILE */
+#undef SET
+
+ if (!NIL_P(key)) { /* matched key should return above */
+ rb_raise(rb_eArgError, "unknown key: %"PRIsVALUE, rb_sym2str(key));
+ }
+
+#if defined(RGENGC_PROFILE) && RGENGC_PROFILE >= 2
+ if (hash != Qnil) {
+ gc_count_add_each_types(hash, "generated_normal_object_count_types", objspace->profile.generated_normal_object_count_types);
+ gc_count_add_each_types(hash, "generated_shady_object_count_types", objspace->profile.generated_shady_object_count_types);
+ gc_count_add_each_types(hash, "shade_operation_count_types", objspace->profile.shade_operation_count_types);
+ gc_count_add_each_types(hash, "promoted_types", objspace->profile.promoted_types);
+ gc_count_add_each_types(hash, "remembered_normal_object_count_types", objspace->profile.remembered_normal_object_count_types);
+ gc_count_add_each_types(hash, "remembered_shady_object_count_types", objspace->profile.remembered_shady_object_count_types);
}
+#endif
+
+ return 0;
}
static VALUE
-gc_stat_heap(rb_execution_context_t *ec, VALUE self, VALUE heap_name, VALUE arg)
+gc_stat(rb_execution_context_t *ec, VALUE self, VALUE arg) // arg is (nil || hash || symbol)
{
if (NIL_P(arg)) {
arg = rb_hash_new();
}
+ else if (SYMBOL_P(arg)) {
+ size_t value = gc_stat_internal(arg);
+ return SIZET2NUM(value);
+ }
+ else if (RB_TYPE_P(arg, T_HASH)) {
+ // ok
+ }
+ else {
+ rb_raise(rb_eTypeError, "non-hash or symbol given");
+ }
- size_t val = rb_gc_impl_stat_heap(rb_gc_get_objspace(), heap_name, arg);
+ gc_stat_internal(arg);
+ return arg;
+}
- if (SYMBOL_P(arg)) {
- return SIZET2NUM(val);
+size_t
+rb_gc_stat(VALUE key)
+{
+ if (SYMBOL_P(key)) {
+ size_t value = gc_stat_internal(key);
+ return value;
}
else {
- return arg;
+ gc_stat_internal(key);
+ return 0;
}
}
-static VALUE
-gc_config_get(rb_execution_context_t *ec, VALUE self)
-{
- return rb_gc_impl_config_get(rb_gc_get_objspace());
+
+enum gc_stat_heap_sym {
+ gc_stat_heap_sym_slot_size,
+ gc_stat_heap_sym_heap_allocatable_pages,
+ gc_stat_heap_sym_heap_eden_pages,
+ gc_stat_heap_sym_heap_eden_slots,
+ gc_stat_heap_sym_heap_tomb_pages,
+ gc_stat_heap_sym_heap_tomb_slots,
+ gc_stat_heap_sym_total_allocated_pages,
+ gc_stat_heap_sym_total_freed_pages,
+ gc_stat_heap_sym_force_major_gc_count,
+ gc_stat_heap_sym_last
+};
+
+static VALUE gc_stat_heap_symbols[gc_stat_heap_sym_last];
+
+static void
+setup_gc_stat_heap_symbols(void)
+{
+ if (gc_stat_heap_symbols[0] == 0) {
+#define S(s) gc_stat_heap_symbols[gc_stat_heap_sym_##s] = ID2SYM(rb_intern_const(#s))
+ S(slot_size);
+ S(heap_allocatable_pages);
+ S(heap_eden_pages);
+ S(heap_eden_slots);
+ S(heap_tomb_pages);
+ S(heap_tomb_slots);
+ S(total_allocated_pages);
+ S(total_freed_pages);
+ S(force_major_gc_count);
+#undef S
+ }
}
-static VALUE
-gc_config_set(rb_execution_context_t *ec, VALUE self, VALUE hash)
+static size_t
+gc_stat_heap_internal(int size_pool_idx, VALUE hash_or_sym)
{
- return rb_gc_impl_config_set(rb_gc_get_objspace(), hash);
+ rb_objspace_t *objspace = &rb_objspace;
+ VALUE hash = Qnil, key = Qnil;
+
+ setup_gc_stat_heap_symbols();
+
+ if (RB_TYPE_P(hash_or_sym, T_HASH)) {
+ hash = hash_or_sym;
+ }
+ else if (SYMBOL_P(hash_or_sym)) {
+ key = hash_or_sym;
+ }
+ else {
+ rb_raise(rb_eTypeError, "non-hash or symbol argument");
+ }
+
+ if (size_pool_idx < 0 || size_pool_idx >= SIZE_POOL_COUNT) {
+ rb_raise(rb_eArgError, "size pool index out of range");
+ }
+
+ rb_size_pool_t *size_pool = &size_pools[size_pool_idx];
+
+#define SET(name, attr) \
+ if (key == gc_stat_heap_symbols[gc_stat_heap_sym_##name]) \
+ return attr; \
+ else if (hash != Qnil) \
+ rb_hash_aset(hash, gc_stat_heap_symbols[gc_stat_heap_sym_##name], SIZET2NUM(attr));
+
+ SET(slot_size, size_pool->slot_size);
+ SET(heap_allocatable_pages, size_pool->allocatable_pages);
+ SET(heap_eden_pages, SIZE_POOL_EDEN_HEAP(size_pool)->total_pages);
+ SET(heap_eden_slots, SIZE_POOL_EDEN_HEAP(size_pool)->total_slots);
+ SET(heap_tomb_pages, SIZE_POOL_TOMB_HEAP(size_pool)->total_pages);
+ SET(heap_tomb_slots, SIZE_POOL_TOMB_HEAP(size_pool)->total_slots);
+ SET(total_allocated_pages, size_pool->total_allocated_pages);
+ SET(total_freed_pages, size_pool->total_freed_pages);
+ SET(force_major_gc_count, size_pool->force_major_gc_count);
+#undef SET
+
+ if (!NIL_P(key)) { /* matched key should return above */
+ rb_raise(rb_eArgError, "unknown key: %"PRIsVALUE, rb_sym2str(key));
+ }
+
+ return 0;
}
static VALUE
-gc_stress_get(rb_execution_context_t *ec, VALUE self)
+gc_stat_heap(rb_execution_context_t *ec, VALUE self, VALUE heap_name, VALUE arg)
{
- return rb_gc_impl_stress_get(rb_gc_get_objspace());
+ if (NIL_P(heap_name)) {
+ if (NIL_P(arg)) {
+ arg = rb_hash_new();
+ }
+ else if (RB_TYPE_P(arg, T_HASH)) {
+ // ok
+ }
+ else {
+ rb_raise(rb_eTypeError, "non-hash given");
+ }
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ VALUE hash = rb_hash_aref(arg, INT2FIX(i));
+ if (NIL_P(hash)) {
+ hash = rb_hash_new();
+ rb_hash_aset(arg, INT2FIX(i), hash);
+ }
+ gc_stat_heap_internal(i, hash);
+ }
+ }
+ else if (FIXNUM_P(heap_name)) {
+ int size_pool_idx = FIX2INT(heap_name);
+
+ if (NIL_P(arg)) {
+ arg = rb_hash_new();
+ }
+ else if (SYMBOL_P(arg)) {
+ size_t value = gc_stat_heap_internal(size_pool_idx, arg);
+ return SIZET2NUM(value);
+ }
+ else if (RB_TYPE_P(arg, T_HASH)) {
+ // ok
+ }
+ else {
+ rb_raise(rb_eTypeError, "non-hash or symbol given");
+ }
+
+ gc_stat_heap_internal(size_pool_idx, arg);
+ }
+ else {
+ rb_raise(rb_eTypeError, "heap_name must be nil or an Integer");
+ }
+
+ return arg;
}
static VALUE
-gc_stress_set_m(rb_execution_context_t *ec, VALUE self, VALUE flag)
+gc_stress_get(rb_execution_context_t *ec, VALUE self)
{
- rb_gc_impl_stress_set(rb_gc_get_objspace(), flag);
-
- return flag;
+ rb_objspace_t *objspace = &rb_objspace;
+ return ruby_gc_stress_mode;
}
-void
-rb_gc_initial_stress_set(VALUE flag)
+static void
+gc_stress_set(rb_objspace_t *objspace, VALUE flag)
{
- initial_stress = flag;
+ objspace->flags.gc_stressful = RTEST(flag);
+ objspace->gc_stress_mode = flag;
}
-size_t *
-rb_gc_heap_sizes(void)
+static VALUE
+gc_stress_set_m(rb_execution_context_t *ec, VALUE self, VALUE flag)
{
- return rb_gc_impl_heap_sizes(rb_gc_get_objspace());
+ rb_objspace_t *objspace = &rb_objspace;
+ gc_stress_set(objspace, flag);
+ return flag;
}
VALUE
rb_gc_enable(void)
{
- return rb_objspace_gc_enable(rb_gc_get_objspace());
+ rb_objspace_t *objspace = &rb_objspace;
+ return rb_objspace_gc_enable(objspace);
}
VALUE
-rb_objspace_gc_enable(void *objspace)
+rb_objspace_gc_enable(rb_objspace_t *objspace)
{
- bool disabled = !rb_gc_impl_gc_enabled_p(objspace);
- rb_gc_impl_gc_enable(objspace);
- return RBOOL(disabled);
+ int old = dont_gc_val();
+
+ dont_gc_off();
+ return RBOOL(old);
}
static VALUE
@@ -3478,32 +11598,33 @@ gc_enable(rb_execution_context_t *ec, VALUE _)
return rb_gc_enable();
}
-static VALUE
-gc_disable_no_rest(void *objspace)
+VALUE
+rb_gc_disable_no_rest(void)
{
- bool disabled = !rb_gc_impl_gc_enabled_p(objspace);
- rb_gc_impl_gc_disable(objspace, false);
- return RBOOL(disabled);
+ rb_objspace_t *objspace = &rb_objspace;
+ return gc_disable_no_rest(objspace);
}
-VALUE
-rb_gc_disable_no_rest(void)
+static VALUE
+gc_disable_no_rest(rb_objspace_t *objspace)
{
- return gc_disable_no_rest(rb_gc_get_objspace());
+ int old = dont_gc_val();
+ dont_gc_on();
+ return RBOOL(old);
}
VALUE
rb_gc_disable(void)
{
- return rb_objspace_gc_disable(rb_gc_get_objspace());
+ rb_objspace_t *objspace = &rb_objspace;
+ return rb_objspace_gc_disable(objspace);
}
VALUE
-rb_objspace_gc_disable(void *objspace)
+rb_objspace_gc_disable(rb_objspace_t *objspace)
{
- bool disabled = !rb_gc_impl_gc_enabled_p(objspace);
- rb_gc_impl_gc_disable(objspace, true);
- return RBOOL(disabled);
+ gc_rest(objspace);
+ return gc_disable_no_rest(objspace);
}
static VALUE
@@ -3512,33 +11633,277 @@ gc_disable(rb_execution_context_t *ec, VALUE _)
return rb_gc_disable();
}
+#if GC_CAN_COMPILE_COMPACTION
+/*
+ * call-seq:
+ * GC.auto_compact = flag
+ *
+ * Updates automatic compaction mode.
+ *
+ * When enabled, the compactor will execute on every major collection.
+ *
+ * Enabling compaction will degrade performance on major collections.
+ */
+static VALUE
+gc_set_auto_compact(VALUE _, VALUE v)
+{
+ GC_ASSERT(GC_COMPACTION_SUPPORTED);
+ ruby_enable_autocompact = RTEST(v);
+ return v;
+}
+#else
+# define gc_set_auto_compact rb_f_notimplement
+#endif
+
+#if GC_CAN_COMPILE_COMPACTION
+/*
+ * call-seq:
+ * GC.auto_compact -> true or false
+ *
+ * Returns whether or not automatic compaction has been enabled.
+ */
+static VALUE
+gc_get_auto_compact(VALUE _)
+{
+ return RBOOL(ruby_enable_autocompact);
+}
+#else
+# define gc_get_auto_compact rb_f_notimplement
+#endif
+
+static int
+get_envparam_size(const char *name, size_t *default_value, size_t lower_bound)
+{
+ const char *ptr = getenv(name);
+ ssize_t val;
+
+ if (ptr != NULL && *ptr) {
+ size_t unit = 0;
+ char *end;
+#if SIZEOF_SIZE_T == SIZEOF_LONG_LONG
+ val = strtoll(ptr, &end, 0);
+#else
+ val = strtol(ptr, &end, 0);
+#endif
+ switch (*end) {
+ case 'k': case 'K':
+ unit = 1024;
+ ++end;
+ break;
+ case 'm': case 'M':
+ unit = 1024*1024;
+ ++end;
+ break;
+ case 'g': case 'G':
+ unit = 1024*1024*1024;
+ ++end;
+ break;
+ }
+ while (*end && isspace((unsigned char)*end)) end++;
+ if (*end) {
+ if (RTEST(ruby_verbose)) fprintf(stderr, "invalid string for %s: %s\n", name, ptr);
+ return 0;
+ }
+ if (unit > 0) {
+ if (val < -(ssize_t)(SIZE_MAX / 2 / unit) || (ssize_t)(SIZE_MAX / 2 / unit) < val) {
+ if (RTEST(ruby_verbose)) fprintf(stderr, "%s=%s is ignored because it overflows\n", name, ptr);
+ return 0;
+ }
+ val *= unit;
+ }
+ if (val > 0 && (size_t)val > lower_bound) {
+ if (RTEST(ruby_verbose)) {
+ fprintf(stderr, "%s=%"PRIdSIZE" (default value: %"PRIuSIZE")\n", name, val, *default_value);
+ }
+ *default_value = (size_t)val;
+ return 1;
+ }
+ else {
+ if (RTEST(ruby_verbose)) {
+ fprintf(stderr, "%s=%"PRIdSIZE" (default value: %"PRIuSIZE") is ignored because it must be greater than %"PRIuSIZE".\n",
+ name, val, *default_value, lower_bound);
+ }
+ return 0;
+ }
+ }
+ return 0;
+}
+
+static int
+get_envparam_double(const char *name, double *default_value, double lower_bound, double upper_bound, int accept_zero)
+{
+ const char *ptr = getenv(name);
+ double val;
+
+ if (ptr != NULL && *ptr) {
+ char *end;
+ val = strtod(ptr, &end);
+ if (!*ptr || *end) {
+ if (RTEST(ruby_verbose)) fprintf(stderr, "invalid string for %s: %s\n", name, ptr);
+ return 0;
+ }
+
+ if (accept_zero && val == 0.0) {
+ goto accept;
+ }
+ else if (val <= lower_bound) {
+ if (RTEST(ruby_verbose)) {
+ fprintf(stderr, "%s=%f (default value: %f) is ignored because it must be greater than %f.\n",
+ name, val, *default_value, lower_bound);
+ }
+ }
+ else if (upper_bound != 0.0 && /* ignore upper_bound if it is 0.0 */
+ val > upper_bound) {
+ if (RTEST(ruby_verbose)) {
+ fprintf(stderr, "%s=%f (default value: %f) is ignored because it must be lower than %f.\n",
+ name, val, *default_value, upper_bound);
+ }
+ }
+ else {
+ goto accept;
+ }
+ }
+ return 0;
+
+ accept:
+ if (RTEST(ruby_verbose)) fprintf(stderr, "%s=%f (default value: %f)\n", name, val, *default_value);
+ *default_value = val;
+ return 1;
+}
+
+static void
+gc_set_initial_pages(rb_objspace_t *objspace)
+{
+ gc_rest(objspace);
+
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_size_pool_t *size_pool = &size_pools[i];
+
+ if (gc_params.heap_init_slots > size_pool->eden_heap.total_slots) {
+ size_t slots = gc_params.heap_init_slots - size_pool->eden_heap.total_slots;
+ int multiple = size_pool->slot_size / BASE_SLOT_SIZE;
+ size_pool->allocatable_pages = slots * multiple / HEAP_PAGE_OBJ_LIMIT;
+ }
+ else {
+ /* We already have more slots than heap_init_slots allows, so
+ * prevent creating more pages. */
+ size_pool->allocatable_pages = 0;
+ }
+ }
+ heap_pages_expand_sorted(objspace);
+}
+
+/*
+ * GC tuning environment variables
+ *
+ * * RUBY_GC_HEAP_INIT_SLOTS
+ * - Initial allocation slots.
+ * * RUBY_GC_HEAP_FREE_SLOTS
+ * - Prepare at least this amount of slots after GC.
+ * - Allocate slots if there are not enough slots.
+ * * RUBY_GC_HEAP_GROWTH_FACTOR (new from 2.1)
+ * - Allocate slots by this factor.
+ * - (next slots number) = (current slots number) * (this factor)
+ * * RUBY_GC_HEAP_GROWTH_MAX_SLOTS (new from 2.1)
+ * - Allocation rate is limited to this number of slots.
+ * * RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO (new from 2.4)
+ * - Allocate additional pages when the number of free slots is
+ * lower than the value (total_slots * (this ratio)).
+ * * RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO (new from 2.4)
+ * - Allocate slots to satisfy this formula:
+ * free_slots = total_slots * goal_ratio
+ * - In other words, prepare (total_slots * goal_ratio) free slots.
+ * - if this value is 0.0, then use RUBY_GC_HEAP_GROWTH_FACTOR directly.
+ * * RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO (new from 2.4)
+ * - Allow to free pages when the number of free slots is
+ * greater than the value (total_slots * (this ratio)).
+ * * RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR (new from 2.1.1)
+ * - Do full GC when the number of old objects is more than R * N
+ * where R is this factor and
+ * N is the number of old objects just after last full GC.
+ *
+ * * obsolete
+ * * RUBY_FREE_MIN -> RUBY_GC_HEAP_FREE_SLOTS (from 2.1)
+ * * RUBY_HEAP_MIN_SLOTS -> RUBY_GC_HEAP_INIT_SLOTS (from 2.1)
+ *
+ * * RUBY_GC_MALLOC_LIMIT
+ * * RUBY_GC_MALLOC_LIMIT_MAX (new from 2.1)
+ * * RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR (new from 2.1)
+ *
+ * * RUBY_GC_OLDMALLOC_LIMIT (new from 2.1)
+ * * RUBY_GC_OLDMALLOC_LIMIT_MAX (new from 2.1)
+ * * RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR (new from 2.1)
+ */
-// TODO: think about moving ruby_gc_set_params into Init_heap or Init_gc
void
ruby_gc_set_params(void)
{
- rb_gc_impl_set_params(rb_gc_get_objspace());
+ rb_objspace_t *objspace = &rb_objspace;
+ /* RUBY_GC_HEAP_FREE_SLOTS */
+ if (get_envparam_size("RUBY_GC_HEAP_FREE_SLOTS", &gc_params.heap_free_slots, 0)) {
+ /* ok */
+ }
+
+ /* RUBY_GC_HEAP_INIT_SLOTS */
+ if (get_envparam_size("RUBY_GC_HEAP_INIT_SLOTS", &gc_params.heap_init_slots, 0)) {
+ gc_set_initial_pages(objspace);
+ }
+
+ get_envparam_double("RUBY_GC_HEAP_GROWTH_FACTOR", &gc_params.growth_factor, 1.0, 0.0, FALSE);
+ get_envparam_size ("RUBY_GC_HEAP_GROWTH_MAX_SLOTS", &gc_params.growth_max_slots, 0);
+ get_envparam_double("RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO", &gc_params.heap_free_slots_min_ratio,
+ 0.0, 1.0, FALSE);
+ get_envparam_double("RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO", &gc_params.heap_free_slots_max_ratio,
+ gc_params.heap_free_slots_min_ratio, 1.0, FALSE);
+ get_envparam_double("RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO", &gc_params.heap_free_slots_goal_ratio,
+ gc_params.heap_free_slots_min_ratio, gc_params.heap_free_slots_max_ratio, TRUE);
+ get_envparam_double("RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR", &gc_params.oldobject_limit_factor, 0.0, 0.0, TRUE);
+
+ if (get_envparam_size("RUBY_GC_MALLOC_LIMIT", &gc_params.malloc_limit_min, 0)) {
+ malloc_limit = gc_params.malloc_limit_min;
+ }
+ get_envparam_size ("RUBY_GC_MALLOC_LIMIT_MAX", &gc_params.malloc_limit_max, 0);
+ if (!gc_params.malloc_limit_max) { /* ignore max-check if 0 */
+ gc_params.malloc_limit_max = SIZE_MAX;
+ }
+ get_envparam_double("RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR", &gc_params.malloc_limit_growth_factor, 1.0, 0.0, FALSE);
+
+#if RGENGC_ESTIMATE_OLDMALLOC
+ if (get_envparam_size("RUBY_GC_OLDMALLOC_LIMIT", &gc_params.oldmalloc_limit_min, 0)) {
+ objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_min;
+ }
+ get_envparam_size ("RUBY_GC_OLDMALLOC_LIMIT_MAX", &gc_params.oldmalloc_limit_max, 0);
+ get_envparam_double("RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR", &gc_params.oldmalloc_limit_growth_factor, 1.0, 0.0, FALSE);
+#endif
+}
+
+static void
+reachable_objects_from_callback(VALUE obj)
+{
+ rb_ractor_t *cr = GET_RACTOR();
+ cr->mfd->mark_func(obj, cr->mfd->data);
}
void
rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data)
{
+ rb_objspace_t *objspace = &rb_objspace;
+
RB_VM_LOCK_ENTER();
{
- if (rb_gc_impl_during_gc_p(rb_gc_get_objspace())) rb_bug("rb_objspace_reachable_objects_from() is not supported while during GC");
+ if (during_gc) rb_bug("rb_objspace_reachable_objects_from() is not supported while during_gc == true");
- if (!RB_SPECIAL_CONST_P(obj)) {
- rb_vm_t *vm = GET_VM();
- struct gc_mark_func_data_struct *prev_mfd = vm->gc.mark_func_data;
+ if (is_markable_object(objspace, obj)) {
+ rb_ractor_t *cr = GET_RACTOR();
struct gc_mark_func_data_struct mfd = {
.mark_func = func,
.data = data,
- };
+ }, *prev_mfd = cr->mfd;
- vm->gc.mark_func_data = &mfd;
- rb_gc_mark_children(rb_gc_get_objspace(), obj);
- vm->gc.mark_func_data = prev_mfd;
+ cr->mfd = &mfd;
+ gc_mark_children(objspace, obj);
+ cr->mfd = prev_mfd;
}
}
RB_VM_LOCK_LEAVE();
@@ -3560,24 +11925,2099 @@ root_objects_from(VALUE obj, void *ptr)
void
rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *passing_data)
{
- if (rb_gc_impl_during_gc_p(rb_gc_get_objspace())) rb_bug("rb_gc_impl_objspace_reachable_objects_from_root() is not supported while during GC");
+ rb_objspace_t *objspace = &rb_objspace;
+ objspace_reachable_objects_from_root(objspace, func, passing_data);
+}
- rb_vm_t *vm = GET_VM();
+static void
+objspace_reachable_objects_from_root(rb_objspace_t *objspace, void (func)(const char *category, VALUE, void *), void *passing_data)
+{
+ if (during_gc) rb_bug("objspace_reachable_objects_from_root() is not supported while during_gc == true");
+ rb_ractor_t *cr = GET_RACTOR();
struct root_objects_data data = {
.func = func,
.data = passing_data,
};
-
- struct gc_mark_func_data_struct *prev_mfd = vm->gc.mark_func_data;
struct gc_mark_func_data_struct mfd = {
.mark_func = root_objects_from,
.data = &data,
+ }, *prev_mfd = cr->mfd;
+
+ cr->mfd = &mfd;
+ gc_mark_roots(objspace, &data.category);
+ cr->mfd = prev_mfd;
+}
+
+/*
+ ------------------------ Extended allocator ------------------------
+*/
+
+struct gc_raise_tag {
+ VALUE exc;
+ const char *fmt;
+ va_list *ap;
+};
+
+static void *
+gc_vraise(void *ptr)
+{
+ struct gc_raise_tag *argv = ptr;
+ rb_vraise(argv->exc, argv->fmt, *argv->ap);
+ UNREACHABLE_RETURN(NULL);
+}
+
+static void
+gc_raise(VALUE exc, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ struct gc_raise_tag argv = {
+ exc, fmt, &ap,
};
- vm->gc.mark_func_data = &mfd;
- rb_gc_mark_roots(rb_gc_get_objspace(), &data.category);
- vm->gc.mark_func_data = prev_mfd;
+ if (ruby_thread_has_gvl_p()) {
+ gc_vraise(&argv);
+ UNREACHABLE;
+ }
+ else if (ruby_native_thread_p()) {
+ rb_thread_call_with_gvl(gc_vraise, &argv);
+ UNREACHABLE;
+ }
+ else {
+ /* Not in a ruby thread */
+ fprintf(stderr, "%s", "[FATAL] ");
+ vfprintf(stderr, fmt, ap);
+ }
+
+ va_end(ap);
+ abort();
+}
+
+static void objspace_xfree(rb_objspace_t *objspace, void *ptr, size_t size);
+
+static void
+negative_size_allocation_error(const char *msg)
+{
+ gc_raise(rb_eNoMemError, "%s", msg);
+}
+
+static void *
+ruby_memerror_body(void *dummy)
+{
+ rb_memerror();
+ return 0;
+}
+
+NORETURN(static void ruby_memerror(void));
+RBIMPL_ATTR_MAYBE_UNUSED()
+static void
+ruby_memerror(void)
+{
+ if (ruby_thread_has_gvl_p()) {
+ rb_memerror();
+ }
+ else {
+ if (ruby_native_thread_p()) {
+ rb_thread_call_with_gvl(ruby_memerror_body, 0);
+ }
+ else {
+ /* no ruby thread */
+ fprintf(stderr, "[FATAL] failed to allocate memory\n");
+ }
+ }
+ exit(EXIT_FAILURE);
+}
+
+void
+rb_memerror(void)
+{
+ rb_execution_context_t *ec = GET_EC();
+ rb_objspace_t *objspace = rb_objspace_of(rb_ec_vm_ptr(ec));
+ VALUE exc;
+
+ if (0) {
+ // Print out pid, sleep, so you can attach debugger to see what went wrong:
+ fprintf(stderr, "rb_memerror pid=%"PRI_PIDT_PREFIX"d\n", getpid());
+ sleep(60);
+ }
+
+ if (during_gc) {
+ // TODO: OMG!! How to implement it?
+ gc_exit(objspace, gc_enter_event_rb_memerror, NULL);
+ }
+
+ exc = nomem_error;
+ if (!exc ||
+ rb_ec_raised_p(ec, RAISED_NOMEMORY)) {
+ fprintf(stderr, "[FATAL] failed to allocate memory\n");
+ exit(EXIT_FAILURE);
+ }
+ if (rb_ec_raised_p(ec, RAISED_NOMEMORY)) {
+ rb_ec_raised_clear(ec);
+ }
+ else {
+ rb_ec_raised_set(ec, RAISED_NOMEMORY);
+ exc = ruby_vm_special_exception_copy(exc);
+ }
+ ec->errinfo = exc;
+ EC_JUMP_TAG(ec, TAG_RAISE);
+}
+
+void *
+rb_aligned_malloc(size_t alignment, size_t size)
+{
+ /* alignment must be a power of 2 */
+ GC_ASSERT(((alignment - 1) & alignment) == 0);
+ GC_ASSERT(alignment % sizeof(void*) == 0);
+
+ void *res;
+
+#if defined __MINGW32__
+ res = __mingw_aligned_malloc(size, alignment);
+#elif defined _WIN32
+ void *_aligned_malloc(size_t, size_t);
+ res = _aligned_malloc(size, alignment);
+#elif defined(HAVE_POSIX_MEMALIGN)
+ if (posix_memalign(&res, alignment, size) != 0) {
+ return NULL;
+ }
+#elif defined(HAVE_MEMALIGN)
+ res = memalign(alignment, size);
+#else
+ char* aligned;
+ res = malloc(alignment + size + sizeof(void*));
+ aligned = (char*)res + alignment + sizeof(void*);
+ aligned -= ((VALUE)aligned & (alignment - 1));
+ ((void**)aligned)[-1] = res;
+ res = (void*)aligned;
+#endif
+
+ GC_ASSERT((uintptr_t)res % alignment == 0);
+
+ return res;
+}
+
+static void
+rb_aligned_free(void *ptr, size_t size)
+{
+#if defined __MINGW32__
+ __mingw_aligned_free(ptr);
+#elif defined _WIN32
+ _aligned_free(ptr);
+#elif defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_MEMALIGN)
+ free(ptr);
+#else
+ free(((void**)ptr)[-1]);
+#endif
+}
+
+static inline size_t
+objspace_malloc_size(rb_objspace_t *objspace, void *ptr, size_t hint)
+{
+#ifdef HAVE_MALLOC_USABLE_SIZE
+ return malloc_usable_size(ptr);
+#else
+ return hint;
+#endif
+}
+
+enum memop_type {
+ MEMOP_TYPE_MALLOC = 0,
+ MEMOP_TYPE_FREE,
+ MEMOP_TYPE_REALLOC
+};
+
+static inline void
+atomic_sub_nounderflow(size_t *var, size_t sub)
+{
+ if (sub == 0) return;
+
+ while (1) {
+ size_t val = *var;
+ if (val < sub) sub = val;
+ if (ATOMIC_SIZE_CAS(*var, val, val-sub) == val) break;
+ }
+}
+
+static void
+objspace_malloc_gc_stress(rb_objspace_t *objspace)
+{
+ if (ruby_gc_stressful && ruby_native_thread_p()) {
+ unsigned int reason = (GPR_FLAG_IMMEDIATE_MARK | GPR_FLAG_IMMEDIATE_SWEEP |
+ GPR_FLAG_STRESS | GPR_FLAG_MALLOC);
+
+ if (gc_stress_full_mark_after_malloc_p()) {
+ reason |= GPR_FLAG_FULL_MARK;
+ }
+ garbage_collect_with_gvl(objspace, reason);
+ }
+}
+
+static inline bool
+objspace_malloc_increase_report(rb_objspace_t *objspace, void *mem, size_t new_size, size_t old_size, enum memop_type type)
+{
+ if (0) fprintf(stderr, "increase - ptr: %p, type: %s, new_size: %"PRIdSIZE", old_size: %"PRIdSIZE"\n",
+ mem,
+ type == MEMOP_TYPE_MALLOC ? "malloc" :
+ type == MEMOP_TYPE_FREE ? "free " :
+ type == MEMOP_TYPE_REALLOC ? "realloc": "error",
+ new_size, old_size);
+ return false;
+}
+
+static bool
+objspace_malloc_increase_body(rb_objspace_t *objspace, void *mem, size_t new_size, size_t old_size, enum memop_type type)
+{
+ if (new_size > old_size) {
+ ATOMIC_SIZE_ADD(malloc_increase, new_size - old_size);
+#if RGENGC_ESTIMATE_OLDMALLOC
+ ATOMIC_SIZE_ADD(objspace->rgengc.oldmalloc_increase, new_size - old_size);
+#endif
+ }
+ else {
+ atomic_sub_nounderflow(&malloc_increase, old_size - new_size);
+#if RGENGC_ESTIMATE_OLDMALLOC
+ atomic_sub_nounderflow(&objspace->rgengc.oldmalloc_increase, old_size - new_size);
+#endif
+ }
+
+ if (type == MEMOP_TYPE_MALLOC) {
+ retry:
+ if (malloc_increase > malloc_limit && ruby_native_thread_p() && !dont_gc_val()) {
+ if (ruby_thread_has_gvl_p() && is_lazy_sweeping(objspace)) {
+ gc_rest(objspace); /* gc_rest can reduce malloc_increase */
+ goto retry;
+ }
+ garbage_collect_with_gvl(objspace, GPR_FLAG_MALLOC);
+ }
+ }
+
+#if MALLOC_ALLOCATED_SIZE
+ if (new_size >= old_size) {
+ ATOMIC_SIZE_ADD(objspace->malloc_params.allocated_size, new_size - old_size);
+ }
+ else {
+ size_t dec_size = old_size - new_size;
+ size_t allocated_size = objspace->malloc_params.allocated_size;
+
+#if MALLOC_ALLOCATED_SIZE_CHECK
+ if (allocated_size < dec_size) {
+ rb_bug("objspace_malloc_increase: underflow malloc_params.allocated_size.");
+ }
+#endif
+ atomic_sub_nounderflow(&objspace->malloc_params.allocated_size, dec_size);
+ }
+
+ switch (type) {
+ case MEMOP_TYPE_MALLOC:
+ ATOMIC_SIZE_INC(objspace->malloc_params.allocations);
+ break;
+ case MEMOP_TYPE_FREE:
+ {
+ size_t allocations = objspace->malloc_params.allocations;
+ if (allocations > 0) {
+ atomic_sub_nounderflow(&objspace->malloc_params.allocations, 1);
+ }
+#if MALLOC_ALLOCATED_SIZE_CHECK
+ else {
+ GC_ASSERT(objspace->malloc_params.allocations > 0);
+ }
+#endif
+ }
+ break;
+ case MEMOP_TYPE_REALLOC: /* ignore */ break;
+ }
+#endif
+ return true;
+}
+
+#define objspace_malloc_increase(...) \
+ for (bool malloc_increase_done = objspace_malloc_increase_report(__VA_ARGS__); \
+ !malloc_increase_done; \
+ malloc_increase_done = objspace_malloc_increase_body(__VA_ARGS__))
+
+struct malloc_obj_info { /* 4 words */
+ size_t size;
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+ size_t gen;
+ const char *file;
+ size_t line;
+#endif
+};
+
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+const char *ruby_malloc_info_file;
+int ruby_malloc_info_line;
+#endif
+
+static inline size_t
+objspace_malloc_prepare(rb_objspace_t *objspace, size_t size)
+{
+ if (size == 0) size = 1;
+
+#if CALC_EXACT_MALLOC_SIZE
+ size += sizeof(struct malloc_obj_info);
+#endif
+
+ return size;
+}
+
+static bool
+malloc_during_gc_p(rb_objspace_t *objspace)
+{
+ /* malloc is not allowed during GC when we're not using multiple ractors
+ * (since ractors can run while another thread is sweeping) and when we
+ * have the GVL (since if we don't have the GVL, we'll try to acquire the
+ * GVL which will block and ensure the other thread finishes GC). */
+ return during_gc && !rb_multi_ractor_p() && ruby_thread_has_gvl_p();
+}
+
+static inline void *
+objspace_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size)
+{
+ size = objspace_malloc_size(objspace, mem, size);
+ objspace_malloc_increase(objspace, mem, size, 0, MEMOP_TYPE_MALLOC);
+
+#if CALC_EXACT_MALLOC_SIZE
+ {
+ struct malloc_obj_info *info = mem;
+ info->size = size;
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+ info->gen = objspace->profile.count;
+ info->file = ruby_malloc_info_file;
+ info->line = info->file ? ruby_malloc_info_line : 0;
+#endif
+ mem = info + 1;
+ }
+#endif
+
+ return mem;
+}
+
+#if defined(__GNUC__) && RUBY_DEBUG
+#define RB_BUG_INSTEAD_OF_RB_MEMERROR 1
+#endif
+
+#ifndef RB_BUG_INSTEAD_OF_RB_MEMERROR
+# define RB_BUG_INSTEAD_OF_RB_MEMERROR 0
+#endif
+
+#define GC_MEMERROR(...) \
+ ((RB_BUG_INSTEAD_OF_RB_MEMERROR+0) ? rb_bug("" __VA_ARGS__) : rb_memerror())
+
+#define TRY_WITH_GC(siz, expr) do { \
+ const gc_profile_record_flag gpr = \
+ GPR_FLAG_FULL_MARK | \
+ GPR_FLAG_IMMEDIATE_MARK | \
+ GPR_FLAG_IMMEDIATE_SWEEP | \
+ GPR_FLAG_MALLOC; \
+ objspace_malloc_gc_stress(objspace); \
+ \
+ if (LIKELY((expr))) { \
+ /* Success on 1st try */ \
+ } \
+ else if (!garbage_collect_with_gvl(objspace, gpr)) { \
+ /* @shyouhei thinks this doesn't happen */ \
+ GC_MEMERROR("TRY_WITH_GC: could not GC"); \
+ } \
+ else if ((expr)) { \
+ /* Success on 2nd try */ \
+ } \
+ else { \
+ GC_MEMERROR("TRY_WITH_GC: could not allocate:" \
+ "%"PRIdSIZE" bytes for %s", \
+ siz, # expr); \
+ } \
+ } while (0)
+
+static void
+check_malloc_not_in_gc(rb_objspace_t *objspace, const char *msg)
+{
+ if (UNLIKELY(malloc_during_gc_p(objspace))) {
+ dont_gc_on();
+ during_gc = false;
+ rb_bug("Cannot %s during GC", msg);
+ }
+}
+
+/* these shouldn't be called directly.
+ * objspace_* functions do not check allocation size.
+ */
+static void *
+objspace_xmalloc0(rb_objspace_t *objspace, size_t size)
+{
+ check_malloc_not_in_gc(objspace, "malloc");
+
+ void *mem;
+
+ size = objspace_malloc_prepare(objspace, size);
+ TRY_WITH_GC(size, mem = malloc(size));
+ RB_DEBUG_COUNTER_INC(heap_xmalloc);
+ return objspace_malloc_fixup(objspace, mem, size);
+}
+
+static inline size_t
+xmalloc2_size(const size_t count, const size_t elsize)
+{
+ return size_mul_or_raise(count, elsize, rb_eArgError);
+}
+
+static void *
+objspace_xrealloc(rb_objspace_t *objspace, void *ptr, size_t new_size, size_t old_size)
+{
+ check_malloc_not_in_gc(objspace, "realloc");
+
+ void *mem;
+
+ if (!ptr) return objspace_xmalloc0(objspace, new_size);
+
+ /*
+ * The behavior of realloc(ptr, 0) is implementation defined.
+ * Therefore we don't use realloc(ptr, 0) for portability reason.
+ * see http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_400.htm
+ */
+ if (new_size == 0) {
+ if ((mem = objspace_xmalloc0(objspace, 0)) != NULL) {
+ /*
+ * - OpenBSD's malloc(3) man page says that when 0 is passed, it
+ * returns a non-NULL pointer to an access-protected memory page.
+ * The returned pointer cannot be read / written at all, but
+ * still be a valid argument of free().
+ *
+ * https://man.openbsd.org/malloc.3
+ *
+ * - Linux's malloc(3) man page says that it _might_ perhaps return
+ * a non-NULL pointer when its argument is 0. That return value
+ * is safe (and is expected) to be passed to free().
+ *
+ * https://man7.org/linux/man-pages/man3/malloc.3.html
+ *
+ * - As I read the implementation jemalloc's malloc() returns fully
+ * normal 16 bytes memory region when its argument is 0.
+ *
+ * - As I read the implementation musl libc's malloc() returns
+ * fully normal 32 bytes memory region when its argument is 0.
+ *
+ * - Other malloc implementations can also return non-NULL.
+ */
+ objspace_xfree(objspace, ptr, old_size);
+ return mem;
+ }
+ else {
+ /*
+ * It is dangerous to return NULL here, because that could lead to
+ * RCE. Fallback to 1 byte instead of zero.
+ *
+ * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11932
+ */
+ new_size = 1;
+ }
+ }
+
+#if CALC_EXACT_MALLOC_SIZE
+ {
+ struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
+ new_size += sizeof(struct malloc_obj_info);
+ ptr = info;
+ old_size = info->size;
+ }
+#endif
+
+ old_size = objspace_malloc_size(objspace, ptr, old_size);
+ TRY_WITH_GC(new_size, mem = RB_GNUC_EXTENSION_BLOCK(realloc(ptr, new_size)));
+ new_size = objspace_malloc_size(objspace, mem, new_size);
+
+#if CALC_EXACT_MALLOC_SIZE
+ {
+ struct malloc_obj_info *info = mem;
+ info->size = new_size;
+ mem = info + 1;
+ }
+#endif
+
+ objspace_malloc_increase(objspace, mem, new_size, old_size, MEMOP_TYPE_REALLOC);
+
+ RB_DEBUG_COUNTER_INC(heap_xrealloc);
+ return mem;
+}
+
+#if CALC_EXACT_MALLOC_SIZE && USE_GC_MALLOC_OBJ_INFO_DETAILS
+
+#define MALLOC_INFO_GEN_SIZE 100
+#define MALLOC_INFO_SIZE_SIZE 10
+static size_t malloc_info_gen_cnt[MALLOC_INFO_GEN_SIZE];
+static size_t malloc_info_gen_size[MALLOC_INFO_GEN_SIZE];
+static size_t malloc_info_size[MALLOC_INFO_SIZE_SIZE+1];
+static st_table *malloc_info_file_table;
+
+static int
+mmalloc_info_file_i(st_data_t key, st_data_t val, st_data_t dmy)
+{
+ const char *file = (void *)key;
+ const size_t *data = (void *)val;
+
+ fprintf(stderr, "%s\t%"PRIdSIZE"\t%"PRIdSIZE"\n", file, data[0], data[1]);
+
+ return ST_CONTINUE;
+}
+
+__attribute__((destructor))
+void
+rb_malloc_info_show_results(void)
+{
+ int i;
+
+ fprintf(stderr, "* malloc_info gen statistics\n");
+ for (i=0; i<MALLOC_INFO_GEN_SIZE; i++) {
+ if (i == MALLOC_INFO_GEN_SIZE-1) {
+ fprintf(stderr, "more\t%"PRIdSIZE"\t%"PRIdSIZE"\n", malloc_info_gen_cnt[i], malloc_info_gen_size[i]);
+ }
+ else {
+ fprintf(stderr, "%d\t%"PRIdSIZE"\t%"PRIdSIZE"\n", i, malloc_info_gen_cnt[i], malloc_info_gen_size[i]);
+ }
+ }
+
+ fprintf(stderr, "* malloc_info size statistics\n");
+ for (i=0; i<MALLOC_INFO_SIZE_SIZE; i++) {
+ int s = 16 << i;
+ fprintf(stderr, "%d\t%"PRIdSIZE"\n", s, malloc_info_size[i]);
+ }
+ fprintf(stderr, "more\t%"PRIdSIZE"\n", malloc_info_size[i]);
+
+ if (malloc_info_file_table) {
+ fprintf(stderr, "* malloc_info file statistics\n");
+ st_foreach(malloc_info_file_table, mmalloc_info_file_i, 0);
+ }
+}
+#else
+void
+rb_malloc_info_show_results(void)
+{
+}
+#endif
+
+static void
+objspace_xfree(rb_objspace_t *objspace, void *ptr, size_t old_size)
+{
+ if (!ptr) {
+ /*
+ * ISO/IEC 9899 says "If ptr is a null pointer, no action occurs" since
+ * its first version. We would better follow.
+ */
+ return;
+ }
+#if CALC_EXACT_MALLOC_SIZE
+ struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
+ ptr = info;
+ old_size = info->size;
+
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+ {
+ int gen = (int)(objspace->profile.count - info->gen);
+ int gen_index = gen >= MALLOC_INFO_GEN_SIZE ? MALLOC_INFO_GEN_SIZE-1 : gen;
+ int i;
+
+ malloc_info_gen_cnt[gen_index]++;
+ malloc_info_gen_size[gen_index] += info->size;
+
+ for (i=0; i<MALLOC_INFO_SIZE_SIZE; i++) {
+ size_t s = 16 << i;
+ if (info->size <= s) {
+ malloc_info_size[i]++;
+ goto found;
+ }
+ }
+ malloc_info_size[i]++;
+ found:;
+
+ {
+ st_data_t key = (st_data_t)info->file, d;
+ size_t *data;
+
+ if (malloc_info_file_table == NULL) {
+ malloc_info_file_table = st_init_numtable_with_size(1024);
+ }
+ if (st_lookup(malloc_info_file_table, key, &d)) {
+ /* hit */
+ data = (size_t *)d;
+ }
+ else {
+ data = malloc(xmalloc2_size(2, sizeof(size_t)));
+ if (data == NULL) rb_bug("objspace_xfree: can not allocate memory");
+ data[0] = data[1] = 0;
+ st_insert(malloc_info_file_table, key, (st_data_t)data);
+ }
+ data[0] ++;
+ data[1] += info->size;
+ };
+ if (0 && gen >= 2) { /* verbose output */
+ if (info->file) {
+ fprintf(stderr, "free - size:%"PRIdSIZE", gen:%d, pos: %s:%"PRIdSIZE"\n",
+ info->size, gen, info->file, info->line);
+ }
+ else {
+ fprintf(stderr, "free - size:%"PRIdSIZE", gen:%d\n",
+ info->size, gen);
+ }
+ }
+ }
+#endif
+#endif
+ old_size = objspace_malloc_size(objspace, ptr, old_size);
+
+ objspace_malloc_increase(objspace, ptr, 0, old_size, MEMOP_TYPE_FREE) {
+ free(ptr);
+ ptr = NULL;
+ RB_DEBUG_COUNTER_INC(heap_xfree);
+ }
+}
+
+static void *
+ruby_xmalloc0(size_t size)
+{
+ return objspace_xmalloc0(&rb_objspace, size);
+}
+
+void *
+ruby_xmalloc_body(size_t size)
+{
+ if ((ssize_t)size < 0) {
+ negative_size_allocation_error("too large allocation size");
+ }
+ return ruby_xmalloc0(size);
+}
+
+void
+ruby_malloc_size_overflow(size_t count, size_t elsize)
+{
+ rb_raise(rb_eArgError,
+ "malloc: possible integer overflow (%"PRIuSIZE"*%"PRIuSIZE")",
+ count, elsize);
+}
+
+void *
+ruby_xmalloc2_body(size_t n, size_t size)
+{
+ return objspace_xmalloc0(&rb_objspace, xmalloc2_size(n, size));
+}
+
+static void *
+objspace_xcalloc(rb_objspace_t *objspace, size_t size)
+{
+ if (UNLIKELY(malloc_during_gc_p(objspace))) {
+ rb_warn("calloc during GC detected, this could cause crashes if it triggers another GC");
+#if RGENGC_CHECK_MODE || RUBY_DEBUG
+ rb_bug("Cannot calloc during GC");
+#endif
+ }
+
+ void *mem;
+
+ size = objspace_malloc_prepare(objspace, size);
+ TRY_WITH_GC(size, mem = calloc1(size));
+ return objspace_malloc_fixup(objspace, mem, size);
+}
+
+void *
+ruby_xcalloc_body(size_t n, size_t size)
+{
+ return objspace_xcalloc(&rb_objspace, xmalloc2_size(n, size));
+}
+
+#ifdef ruby_sized_xrealloc
+#undef ruby_sized_xrealloc
+#endif
+void *
+ruby_sized_xrealloc(void *ptr, size_t new_size, size_t old_size)
+{
+ if ((ssize_t)new_size < 0) {
+ negative_size_allocation_error("too large allocation size");
+ }
+
+ return objspace_xrealloc(&rb_objspace, ptr, new_size, old_size);
+}
+
+void *
+ruby_xrealloc_body(void *ptr, size_t new_size)
+{
+ return ruby_sized_xrealloc(ptr, new_size, 0);
+}
+
+#ifdef ruby_sized_xrealloc2
+#undef ruby_sized_xrealloc2
+#endif
+void *
+ruby_sized_xrealloc2(void *ptr, size_t n, size_t size, size_t old_n)
+{
+ size_t len = xmalloc2_size(n, size);
+ return objspace_xrealloc(&rb_objspace, ptr, len, old_n * size);
+}
+
+void *
+ruby_xrealloc2_body(void *ptr, size_t n, size_t size)
+{
+ return ruby_sized_xrealloc2(ptr, n, size, 0);
+}
+
+#ifdef ruby_sized_xfree
+#undef ruby_sized_xfree
+#endif
+void
+ruby_sized_xfree(void *x, size_t size)
+{
+ if (LIKELY(x)) {
+ /* It's possible for a C extension's pthread destructor function set by pthread_key_create
+ * to be called after ruby_vm_destruct and attempt to free memory. Fall back to mimfree in
+ * that case. */
+ if (LIKELY(GET_VM())) {
+ objspace_xfree(&rb_objspace, x, size);
+ }
+ else {
+ ruby_mimfree(x);
+ }
+ }
+}
+
+void
+ruby_xfree(void *x)
+{
+ ruby_sized_xfree(x, 0);
+}
+
+void *
+rb_xmalloc_mul_add(size_t x, size_t y, size_t z) /* x * y + z */
+{
+ size_t w = size_mul_add_or_raise(x, y, z, rb_eArgError);
+ return ruby_xmalloc(w);
+}
+
+void *
+rb_xcalloc_mul_add(size_t x, size_t y, size_t z) /* x * y + z */
+{
+ size_t w = size_mul_add_or_raise(x, y, z, rb_eArgError);
+ return ruby_xcalloc(w, 1);
+}
+
+void *
+rb_xrealloc_mul_add(const void *p, size_t x, size_t y, size_t z) /* x * y + z */
+{
+ size_t w = size_mul_add_or_raise(x, y, z, rb_eArgError);
+ return ruby_xrealloc((void *)p, w);
+}
+
+void *
+rb_xmalloc_mul_add_mul(size_t x, size_t y, size_t z, size_t w) /* x * y + z * w */
+{
+ size_t u = size_mul_add_mul_or_raise(x, y, z, w, rb_eArgError);
+ return ruby_xmalloc(u);
+}
+
+void *
+rb_xcalloc_mul_add_mul(size_t x, size_t y, size_t z, size_t w) /* x * y + z * w */
+{
+ size_t u = size_mul_add_mul_or_raise(x, y, z, w, rb_eArgError);
+ return ruby_xcalloc(u, 1);
+}
+
+/* Mimic ruby_xmalloc, but need not rb_objspace.
+ * should return pointer suitable for ruby_xfree
+ */
+void *
+ruby_mimmalloc(size_t size)
+{
+ void *mem;
+#if CALC_EXACT_MALLOC_SIZE
+ size += sizeof(struct malloc_obj_info);
+#endif
+ mem = malloc(size);
+#if CALC_EXACT_MALLOC_SIZE
+ if (!mem) {
+ return NULL;
+ }
+ else
+ /* set 0 for consistency of allocated_size/allocations */
+ {
+ struct malloc_obj_info *info = mem;
+ info->size = 0;
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+ info->gen = 0;
+ info->file = NULL;
+ info->line = 0;
+#endif
+ mem = info + 1;
+ }
+#endif
+ return mem;
+}
+
+void
+ruby_mimfree(void *ptr)
+{
+#if CALC_EXACT_MALLOC_SIZE
+ struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
+ ptr = info;
+#endif
+ free(ptr);
+}
+
+void *
+rb_alloc_tmp_buffer_with_count(volatile VALUE *store, size_t size, size_t cnt)
+{
+ void *ptr;
+ VALUE imemo;
+ rb_imemo_tmpbuf_t *tmpbuf;
+
+ /* Keep the order; allocate an empty imemo first then xmalloc, to
+ * get rid of potential memory leak */
+ imemo = rb_imemo_tmpbuf_auto_free_maybe_mark_buffer(NULL, 0);
+ *store = imemo;
+ ptr = ruby_xmalloc0(size);
+ tmpbuf = (rb_imemo_tmpbuf_t *)imemo;
+ tmpbuf->ptr = ptr;
+ tmpbuf->cnt = cnt;
+ return ptr;
+}
+
+void *
+rb_alloc_tmp_buffer(volatile VALUE *store, long len)
+{
+ long cnt;
+
+ if (len < 0 || (cnt = (long)roomof(len, sizeof(VALUE))) < 0) {
+ rb_raise(rb_eArgError, "negative buffer size (or size too big)");
+ }
+
+ return rb_alloc_tmp_buffer_with_count(store, len, cnt);
+}
+
+void
+rb_free_tmp_buffer(volatile VALUE *store)
+{
+ rb_imemo_tmpbuf_t *s = (rb_imemo_tmpbuf_t*)ATOMIC_VALUE_EXCHANGE(*store, 0);
+ if (s) {
+ void *ptr = ATOMIC_PTR_EXCHANGE(s->ptr, 0);
+ s->cnt = 0;
+ ruby_xfree(ptr);
+ }
+}
+
+#if MALLOC_ALLOCATED_SIZE
+/*
+ * call-seq:
+ * GC.malloc_allocated_size -> Integer
+ *
+ * Returns the size of memory allocated by malloc().
+ *
+ * Only available if ruby was built with +CALC_EXACT_MALLOC_SIZE+.
+ */
+
+static VALUE
+gc_malloc_allocated_size(VALUE self)
+{
+ return UINT2NUM(rb_objspace.malloc_params.allocated_size);
+}
+
+/*
+ * call-seq:
+ * GC.malloc_allocations -> Integer
+ *
+ * Returns the number of malloc() allocations.
+ *
+ * Only available if ruby was built with +CALC_EXACT_MALLOC_SIZE+.
+ */
+
+static VALUE
+gc_malloc_allocations(VALUE self)
+{
+ return UINT2NUM(rb_objspace.malloc_params.allocations);
+}
+#endif
+
+void
+rb_gc_adjust_memory_usage(ssize_t diff)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ if (diff > 0) {
+ objspace_malloc_increase(objspace, 0, diff, 0, MEMOP_TYPE_REALLOC);
+ }
+ else if (diff < 0) {
+ objspace_malloc_increase(objspace, 0, 0, -diff, MEMOP_TYPE_REALLOC);
+ }
+}
+
+/*
+ ------------------------------ WeakMap ------------------------------
+*/
+
+struct weakmap {
+ st_table *obj2wmap; /* obj -> [ref,...] */
+ st_table *wmap2obj; /* ref -> obj */
+ VALUE final;
+};
+
+#define WMAP_DELETE_DEAD_OBJECT_IN_MARK 0
+
+#if WMAP_DELETE_DEAD_OBJECT_IN_MARK
+static int
+wmap_mark_map(st_data_t key, st_data_t val, st_data_t arg)
+{
+ rb_objspace_t *objspace = (rb_objspace_t *)arg;
+ VALUE obj = (VALUE)val;
+ if (!is_live_object(objspace, obj)) return ST_DELETE;
+ return ST_CONTINUE;
+}
+#endif
+
+static int
+wmap_replace_ref(st_data_t *key, st_data_t *value, st_data_t _argp, int existing)
+{
+ *key = rb_gc_location((VALUE)*key);
+
+ VALUE *values = (VALUE *)*value;
+ VALUE size = values[0];
+
+ for (VALUE index = 1; index <= size; index++) {
+ values[index] = rb_gc_location(values[index]);
+ }
+
+ return ST_CONTINUE;
+}
+
+static int
+wmap_foreach_replace(st_data_t key, st_data_t value, st_data_t _argp, int error)
+{
+ if (rb_gc_location((VALUE)key) != (VALUE)key) {
+ return ST_REPLACE;
+ }
+
+ VALUE *values = (VALUE *)value;
+ VALUE size = values[0];
+
+ for (VALUE index = 1; index <= size; index++) {
+ VALUE val = values[index];
+ if (rb_gc_location(val) != val) {
+ return ST_REPLACE;
+ }
+ }
+
+ return ST_CONTINUE;
+}
+
+static void
+wmap_compact(void *ptr)
+{
+ struct weakmap *w = ptr;
+ if (w->wmap2obj) rb_gc_update_tbl_refs(w->wmap2obj);
+ if (w->obj2wmap) st_foreach_with_replace(w->obj2wmap, wmap_foreach_replace, wmap_replace_ref, (st_data_t)NULL);
+ w->final = rb_gc_location(w->final);
+}
+
+static void
+wmap_mark(void *ptr)
+{
+ struct weakmap *w = ptr;
+#if WMAP_DELETE_DEAD_OBJECT_IN_MARK
+ if (w->obj2wmap) st_foreach(w->obj2wmap, wmap_mark_map, (st_data_t)&rb_objspace);
+#endif
+ rb_gc_mark_movable(w->final);
+}
+
+static int
+wmap_free_map(st_data_t key, st_data_t val, st_data_t arg)
+{
+ VALUE *ptr = (VALUE *)val;
+ ruby_sized_xfree(ptr, (ptr[0] + 1) * sizeof(VALUE));
+ return ST_CONTINUE;
+}
+
+static void
+wmap_free(void *ptr)
+{
+ struct weakmap *w = ptr;
+ st_foreach(w->obj2wmap, wmap_free_map, 0);
+ st_free_table(w->obj2wmap);
+ st_free_table(w->wmap2obj);
+ xfree(w);
+}
+
+static int
+wmap_memsize_map(st_data_t key, st_data_t val, st_data_t arg)
+{
+ VALUE *ptr = (VALUE *)val;
+ *(size_t *)arg += (ptr[0] + 1) * sizeof(VALUE);
+ return ST_CONTINUE;
+}
+
+static size_t
+wmap_memsize(const void *ptr)
+{
+ size_t size;
+ const struct weakmap *w = ptr;
+ size = sizeof(*w);
+ size += st_memsize(w->obj2wmap);
+ size += st_memsize(w->wmap2obj);
+ st_foreach(w->obj2wmap, wmap_memsize_map, (st_data_t)&size);
+ return size;
+}
+
+static const rb_data_type_t weakmap_type = {
+ "weakmap",
+ {
+ wmap_mark,
+ wmap_free,
+ wmap_memsize,
+ wmap_compact,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+};
+
+static VALUE wmap_finalize(RB_BLOCK_CALL_FUNC_ARGLIST(objid, self));
+
+static VALUE
+wmap_allocate(VALUE klass)
+{
+ struct weakmap *w;
+ VALUE obj = TypedData_Make_Struct(klass, struct weakmap, &weakmap_type, w);
+ w->obj2wmap = rb_init_identtable();
+ w->wmap2obj = rb_init_identtable();
+ w->final = rb_func_lambda_new(wmap_finalize, obj, 1, 1);
+ return obj;
+}
+
+static int
+wmap_live_p(rb_objspace_t *objspace, VALUE obj)
+{
+ if (SPECIAL_CONST_P(obj)) return TRUE;
+ /* If is_pointer_to_heap returns false, the page could be in the tomb heap
+ * or have already been freed. */
+ if (!is_pointer_to_heap(objspace, (void *)obj)) return FALSE;
+
+ void *poisoned = asan_unpoison_object_temporary(obj);
+
+ enum ruby_value_type t = BUILTIN_TYPE(obj);
+ int ret = (!(t == T_NONE || t >= T_FIXNUM || t == T_ICLASS) &&
+ is_live_object(objspace, obj));
+
+ if (poisoned) {
+ asan_poison_object(obj);
+ }
+
+ return ret;
+}
+
+static int
+wmap_remove_inverse_ref(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
+{
+ if (!existing) return ST_STOP;
+
+ VALUE old_ref = (VALUE)arg;
+
+ VALUE *values = (VALUE *)*val;
+ VALUE size = values[0];
+
+ if (size == 1) {
+ // fast path, we only had one backref
+ RUBY_ASSERT(values[1] == old_ref);
+ ruby_sized_xfree(values, 2 * sizeof(VALUE));
+ return ST_DELETE;
+ }
+
+ bool found = false;
+ VALUE index = 1;
+ for (; index <= size; index++) {
+ if (values[index] == old_ref) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) return ST_STOP;
+
+ if (size > index) {
+ MEMMOVE(&values[index], &values[index + 1], VALUE, size - index);
+ }
+
+ size -= 1;
+ values[0] = size;
+ SIZED_REALLOC_N(values, VALUE, size + 1, size + 2);
+ *val = (st_data_t)values;
+ return ST_CONTINUE;
+}
+
+/* :nodoc: */
+static VALUE
+wmap_finalize(RB_BLOCK_CALL_FUNC_ARGLIST(objid, self))
+{
+ st_data_t orig, wmap, data;
+ VALUE obj, *rids, i, size;
+ struct weakmap *w;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ /* Get reference from object id. */
+ if (UNDEF_P(obj = id2ref_obj_tbl(&rb_objspace, objid))) {
+ rb_bug("wmap_finalize: objid is not found.");
+ }
+
+ /* obj is original referenced object and/or weak reference. */
+ orig = (st_data_t)obj;
+ if (st_delete(w->obj2wmap, &orig, &data)) {
+ rids = (VALUE *)data;
+ size = *rids++;
+ for (i = 0; i < size; ++i) {
+ wmap = (st_data_t)rids[i];
+ st_delete(w->wmap2obj, &wmap, NULL);
+ }
+ ruby_sized_xfree((VALUE *)data, (size + 1) * sizeof(VALUE));
+ }
+
+ wmap = (st_data_t)obj;
+ if (st_delete(w->wmap2obj, &wmap, &orig)) {
+ wmap = (st_data_t)obj;
+ st_update(w->obj2wmap, orig, wmap_remove_inverse_ref, wmap);
+ }
+ return self;
+}
+
+struct wmap_iter_arg {
+ rb_objspace_t *objspace;
+ VALUE value;
+};
+
+static VALUE
+wmap_inspect_append(rb_objspace_t *objspace, VALUE str, VALUE obj)
+{
+ if (SPECIAL_CONST_P(obj)) {
+ return rb_str_append(str, rb_inspect(obj));
+ }
+ else if (wmap_live_p(objspace, obj)) {
+ return rb_str_append(str, rb_any_to_s(obj));
+ }
+ else {
+ return rb_str_catf(str, "#<collected:%p>", (void*)obj);
+ }
+}
+
+static int
+wmap_inspect_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ struct wmap_iter_arg *argp = (struct wmap_iter_arg *)arg;
+ rb_objspace_t *objspace = argp->objspace;
+ VALUE str = argp->value;
+ VALUE k = (VALUE)key, v = (VALUE)val;
+
+ if (RSTRING_PTR(str)[0] == '#') {
+ rb_str_cat2(str, ", ");
+ }
+ else {
+ rb_str_cat2(str, ": ");
+ RSTRING_PTR(str)[0] = '#';
+ }
+ wmap_inspect_append(objspace, str, k);
+ rb_str_cat2(str, " => ");
+ wmap_inspect_append(objspace, str, v);
+
+ return ST_CONTINUE;
+}
+
+static VALUE
+wmap_inspect(VALUE self)
+{
+ VALUE str;
+ VALUE c = rb_class_name(CLASS_OF(self));
+ struct weakmap *w;
+ struct wmap_iter_arg args;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ str = rb_sprintf("-<%"PRIsVALUE":%p", c, (void *)self);
+ if (w->wmap2obj) {
+ args.objspace = &rb_objspace;
+ args.value = str;
+ st_foreach(w->wmap2obj, wmap_inspect_i, (st_data_t)&args);
+ }
+ RSTRING_PTR(str)[0] = '#';
+ rb_str_cat2(str, ">");
+ return str;
+}
+
+static inline bool
+wmap_live_entry_p(rb_objspace_t *objspace, st_data_t key, st_data_t val)
+{
+ return wmap_live_p(objspace, (VALUE)key) && wmap_live_p(objspace, (VALUE)val);
+}
+
+static int
+wmap_each_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ rb_objspace_t *objspace = (rb_objspace_t *)arg;
+
+ if (wmap_live_entry_p(objspace, key, val)) {
+ rb_yield_values(2, (VALUE)key, (VALUE)val);
+ return ST_CONTINUE;
+ }
+ else {
+ return ST_DELETE;
+ }
+}
+
+/* Iterates over keys and objects in a weakly referenced object */
+static VALUE
+wmap_each(VALUE self)
+{
+ struct weakmap *w;
+ rb_objspace_t *objspace = &rb_objspace;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ st_foreach(w->wmap2obj, wmap_each_i, (st_data_t)objspace);
+ return self;
+}
+
+static int
+wmap_each_key_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ rb_objspace_t *objspace = (rb_objspace_t *)arg;
+
+ if (wmap_live_entry_p(objspace, key, val)) {
+ rb_yield((VALUE)key);
+ return ST_CONTINUE;
+ }
+ else {
+ return ST_DELETE;
+ }
+}
+
+/* Iterates over keys and objects in a weakly referenced object */
+static VALUE
+wmap_each_key(VALUE self)
+{
+ struct weakmap *w;
+ rb_objspace_t *objspace = &rb_objspace;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ st_foreach(w->wmap2obj, wmap_each_key_i, (st_data_t)objspace);
+ return self;
+}
+
+static int
+wmap_each_value_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ rb_objspace_t *objspace = (rb_objspace_t *)arg;
+
+ if (wmap_live_entry_p(objspace, key, val)) {
+ rb_yield((VALUE)val);
+ return ST_CONTINUE;
+ }
+ else {
+ return ST_DELETE;
+ }
+}
+
+/* Iterates over keys and objects in a weakly referenced object */
+static VALUE
+wmap_each_value(VALUE self)
+{
+ struct weakmap *w;
+ rb_objspace_t *objspace = &rb_objspace;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ st_foreach(w->wmap2obj, wmap_each_value_i, (st_data_t)objspace);
+ return self;
+}
+
+static int
+wmap_keys_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ struct wmap_iter_arg *argp = (struct wmap_iter_arg *)arg;
+ rb_objspace_t *objspace = argp->objspace;
+ VALUE ary = argp->value;
+
+ if (wmap_live_entry_p(objspace, key, val)) {
+ rb_ary_push(ary, (VALUE)key);
+ return ST_CONTINUE;
+ }
+ else {
+ return ST_DELETE;
+ }
+}
+
+/* Iterates over keys and objects in a weakly referenced object */
+static VALUE
+wmap_keys(VALUE self)
+{
+ struct weakmap *w;
+ struct wmap_iter_arg args;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ args.objspace = &rb_objspace;
+ args.value = rb_ary_new();
+ st_foreach(w->wmap2obj, wmap_keys_i, (st_data_t)&args);
+ return args.value;
+}
+
+static int
+wmap_values_i(st_data_t key, st_data_t val, st_data_t arg)
+{
+ struct wmap_iter_arg *argp = (struct wmap_iter_arg *)arg;
+ rb_objspace_t *objspace = argp->objspace;
+ VALUE ary = argp->value;
+
+ if (wmap_live_entry_p(objspace, key, val)) {
+ rb_ary_push(ary, (VALUE)val);
+ return ST_CONTINUE;
+ }
+ else {
+ return ST_DELETE;
+ }
+}
+
+/* Iterates over values and objects in a weakly referenced object */
+static VALUE
+wmap_values(VALUE self)
+{
+ struct weakmap *w;
+ struct wmap_iter_arg args;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ args.objspace = &rb_objspace;
+ args.value = rb_ary_new();
+ st_foreach(w->wmap2obj, wmap_values_i, (st_data_t)&args);
+ return args.value;
+}
+
+static int
+wmap_aset_update(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
+{
+ VALUE size, *ptr, *optr;
+ if (existing) {
+ size = (ptr = optr = (VALUE *)*val)[0];
+
+ for (VALUE index = 1; index <= size; index++) {
+ if (ptr[index] == (VALUE)arg) {
+ // The reference was already registered.
+ return ST_STOP;
+ }
+ }
+
+ ++size;
+ SIZED_REALLOC_N(ptr, VALUE, size + 1, size);
+ }
+ else {
+ optr = 0;
+ size = 1;
+ ptr = ruby_xmalloc0(2 * sizeof(VALUE));
+ }
+ ptr[0] = size;
+ ptr[size] = (VALUE)arg;
+ if (ptr == optr) return ST_STOP;
+ *val = (st_data_t)ptr;
+ return ST_CONTINUE;
+}
+
+struct wmap_aset_replace_args {
+ VALUE new_value;
+ VALUE old_value;
+};
+
+static int
+wmap_aset_replace_value(st_data_t *key, st_data_t *val, st_data_t _args, int existing)
+{
+ struct wmap_aset_replace_args *args = (struct wmap_aset_replace_args *)_args;
+
+ if (existing) {
+ args->old_value = *val;
+ }
+ *val = (st_data_t)args->new_value;
+ return ST_CONTINUE;
+}
+
+/* Creates a weak reference from the given key to the given value */
+static VALUE
+wmap_aset(VALUE self, VALUE key, VALUE value)
+{
+ struct weakmap *w;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ if (FL_ABLE(value)) {
+ define_final0(value, w->final);
+ }
+ if (FL_ABLE(key)) {
+ define_final0(key, w->final);
+ }
+
+ struct wmap_aset_replace_args aset_args = {
+ .new_value = value,
+ .old_value = Qundef,
+ };
+ st_update(w->wmap2obj, (st_data_t)key, wmap_aset_replace_value, (st_data_t)&aset_args);
+
+ // If the value is unchanged, we have nothing to do.
+ if (value != aset_args.old_value) {
+ if (!UNDEF_P(aset_args.old_value) && FL_ABLE(aset_args.old_value)) {
+ // That key existed and had an inverse reference, we need to clear the outdated inverse reference.
+ st_update(w->obj2wmap, (st_data_t)aset_args.old_value, wmap_remove_inverse_ref, key);
+ }
+
+ if (FL_ABLE(value)) {
+ // If the value has no finalizer, we don't need to keep the inverse reference
+ st_update(w->obj2wmap, (st_data_t)value, wmap_aset_update, key);
+ }
+ }
+
+ return nonspecial_obj_id(value);
+}
+
+/* Retrieves a weakly referenced object with the given key */
+static VALUE
+wmap_lookup(VALUE self, VALUE key)
+{
+ st_data_t data;
+ VALUE obj;
+ struct weakmap *w;
+ rb_objspace_t *objspace = &rb_objspace;
+ GC_ASSERT(wmap_live_p(objspace, key));
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ if (!st_lookup(w->wmap2obj, (st_data_t)key, &data)) return Qundef;
+ obj = (VALUE)data;
+ if (!wmap_live_p(objspace, obj)) return Qundef;
+ return obj;
+}
+
+/* Retrieves a weakly referenced object with the given key */
+static VALUE
+wmap_aref(VALUE self, VALUE key)
+{
+ VALUE obj = wmap_lookup(self, key);
+ return !UNDEF_P(obj) ? obj : Qnil;
+}
+
+/* Returns +true+ if +key+ is registered */
+static VALUE
+wmap_has_key(VALUE self, VALUE key)
+{
+ return RBOOL(!UNDEF_P(wmap_lookup(self, key)));
+}
+
+/* Returns the number of referenced objects */
+static VALUE
+wmap_size(VALUE self)
+{
+ struct weakmap *w;
+ st_index_t n;
+
+ TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
+ n = w->wmap2obj->num_entries;
+#if SIZEOF_ST_INDEX_T <= SIZEOF_LONG
+ return ULONG2NUM(n);
+#else
+ return ULL2NUM(n);
+#endif
+}
+
+/*
+ ------------------------------ GC profiler ------------------------------
+*/
+
+#define GC_PROFILE_RECORD_DEFAULT_SIZE 100
+
+static bool
+current_process_time(struct timespec *ts)
+{
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
+ {
+ static int try_clock_gettime = 1;
+ if (try_clock_gettime && clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ts) == 0) {
+ return true;
+ }
+ else {
+ try_clock_gettime = 0;
+ }
+ }
+#endif
+
+#ifdef RUSAGE_SELF
+ {
+ struct rusage usage;
+ struct timeval time;
+ if (getrusage(RUSAGE_SELF, &usage) == 0) {
+ time = usage.ru_utime;
+ ts->tv_sec = time.tv_sec;
+ ts->tv_nsec = (int32_t)time.tv_usec * 1000;
+ return true;
+ }
+ }
+#endif
+
+#ifdef _WIN32
+ {
+ FILETIME creation_time, exit_time, kernel_time, user_time;
+ ULARGE_INTEGER ui;
+
+ if (GetProcessTimes(GetCurrentProcess(),
+ &creation_time, &exit_time, &kernel_time, &user_time) != 0) {
+ memcpy(&ui, &user_time, sizeof(FILETIME));
+#define PER100NSEC (uint64_t)(1000 * 1000 * 10)
+ ts->tv_nsec = (long)(ui.QuadPart % PER100NSEC);
+ ts->tv_sec = (time_t)(ui.QuadPart / PER100NSEC);
+ return true;
+ }
+ }
+#endif
+
+ return false;
+}
+
+static double
+getrusage_time(void)
+{
+ struct timespec ts;
+ if (current_process_time(&ts)) {
+ return ts.tv_sec + ts.tv_nsec * 1e-9;
+ }
+ else {
+ return 0.0;
+ }
+}
+
+
+static inline void
+gc_prof_setup_new_record(rb_objspace_t *objspace, unsigned int reason)
+{
+ if (objspace->profile.run) {
+ size_t index = objspace->profile.next_index;
+ gc_profile_record *record;
+
+ /* create new record */
+ objspace->profile.next_index++;
+
+ if (!objspace->profile.records) {
+ objspace->profile.size = GC_PROFILE_RECORD_DEFAULT_SIZE;
+ objspace->profile.records = malloc(xmalloc2_size(sizeof(gc_profile_record), objspace->profile.size));
+ }
+ if (index >= objspace->profile.size) {
+ void *ptr;
+ objspace->profile.size += 1000;
+ ptr = realloc(objspace->profile.records, xmalloc2_size(sizeof(gc_profile_record), objspace->profile.size));
+ if (!ptr) rb_memerror();
+ objspace->profile.records = ptr;
+ }
+ if (!objspace->profile.records) {
+ rb_bug("gc_profile malloc or realloc miss");
+ }
+ record = objspace->profile.current_record = &objspace->profile.records[objspace->profile.next_index - 1];
+ MEMZERO(record, gc_profile_record, 1);
+
+ /* setup before-GC parameter */
+ record->flags = reason | (ruby_gc_stressful ? GPR_FLAG_STRESS : 0);
+#if MALLOC_ALLOCATED_SIZE
+ record->allocated_size = malloc_allocated_size;
+#endif
+#if GC_PROFILE_MORE_DETAIL && GC_PROFILE_DETAIL_MEMORY
+#ifdef RUSAGE_SELF
+ {
+ struct rusage usage;
+ if (getrusage(RUSAGE_SELF, &usage) == 0) {
+ record->maxrss = usage.ru_maxrss;
+ record->minflt = usage.ru_minflt;
+ record->majflt = usage.ru_majflt;
+ }
+ }
+#endif
+#endif
+ }
+}
+
+static inline void
+gc_prof_timer_start(rb_objspace_t *objspace)
+{
+ if (gc_prof_enabled(objspace)) {
+ gc_profile_record *record = gc_prof_record(objspace);
+#if GC_PROFILE_MORE_DETAIL
+ record->prepare_time = objspace->profile.prepare_time;
+#endif
+ record->gc_time = 0;
+ record->gc_invoke_time = getrusage_time();
+ }
+}
+
+static double
+elapsed_time_from(double time)
+{
+ double now = getrusage_time();
+ if (now > time) {
+ return now - time;
+ }
+ else {
+ return 0;
+ }
+}
+
+static inline void
+gc_prof_timer_stop(rb_objspace_t *objspace)
+{
+ if (gc_prof_enabled(objspace)) {
+ gc_profile_record *record = gc_prof_record(objspace);
+ record->gc_time = elapsed_time_from(record->gc_invoke_time);
+ record->gc_invoke_time -= objspace->profile.invoke_time;
+ }
+}
+
+#define RUBY_DTRACE_GC_HOOK(name) \
+ do {if (RUBY_DTRACE_GC_##name##_ENABLED()) RUBY_DTRACE_GC_##name();} while (0)
+static inline void
+gc_prof_mark_timer_start(rb_objspace_t *objspace)
+{
+ RUBY_DTRACE_GC_HOOK(MARK_BEGIN);
+#if GC_PROFILE_MORE_DETAIL
+ if (gc_prof_enabled(objspace)) {
+ gc_prof_record(objspace)->gc_mark_time = getrusage_time();
+ }
+#endif
+}
+
+static inline void
+gc_prof_mark_timer_stop(rb_objspace_t *objspace)
+{
+ RUBY_DTRACE_GC_HOOK(MARK_END);
+#if GC_PROFILE_MORE_DETAIL
+ if (gc_prof_enabled(objspace)) {
+ gc_profile_record *record = gc_prof_record(objspace);
+ record->gc_mark_time = elapsed_time_from(record->gc_mark_time);
+ }
+#endif
+}
+
+static inline void
+gc_prof_sweep_timer_start(rb_objspace_t *objspace)
+{
+ RUBY_DTRACE_GC_HOOK(SWEEP_BEGIN);
+ if (gc_prof_enabled(objspace)) {
+ gc_profile_record *record = gc_prof_record(objspace);
+
+ if (record->gc_time > 0 || GC_PROFILE_MORE_DETAIL) {
+ objspace->profile.gc_sweep_start_time = getrusage_time();
+ }
+ }
+}
+
+static inline void
+gc_prof_sweep_timer_stop(rb_objspace_t *objspace)
+{
+ RUBY_DTRACE_GC_HOOK(SWEEP_END);
+
+ if (gc_prof_enabled(objspace)) {
+ double sweep_time;
+ gc_profile_record *record = gc_prof_record(objspace);
+
+ if (record->gc_time > 0) {
+ sweep_time = elapsed_time_from(objspace->profile.gc_sweep_start_time);
+ /* need to accumulate GC time for lazy sweep after gc() */
+ record->gc_time += sweep_time;
+ }
+ else if (GC_PROFILE_MORE_DETAIL) {
+ sweep_time = elapsed_time_from(objspace->profile.gc_sweep_start_time);
+ }
+
+#if GC_PROFILE_MORE_DETAIL
+ record->gc_sweep_time += sweep_time;
+ if (heap_pages_deferred_final) record->flags |= GPR_FLAG_HAVE_FINALIZE;
+#endif
+ if (heap_pages_deferred_final) objspace->profile.latest_gc_info |= GPR_FLAG_HAVE_FINALIZE;
+ }
+}
+
+static inline void
+gc_prof_set_malloc_info(rb_objspace_t *objspace)
+{
+#if GC_PROFILE_MORE_DETAIL
+ if (gc_prof_enabled(objspace)) {
+ gc_profile_record *record = gc_prof_record(objspace);
+ record->allocate_increase = malloc_increase;
+ record->allocate_limit = malloc_limit;
+ }
+#endif
+}
+
+static inline void
+gc_prof_set_heap_info(rb_objspace_t *objspace)
+{
+ if (gc_prof_enabled(objspace)) {
+ gc_profile_record *record = gc_prof_record(objspace);
+ size_t live = objspace->profile.total_allocated_objects_at_gc_start - objspace->profile.total_freed_objects;
+ size_t total = objspace->profile.heap_used_at_gc_start * HEAP_PAGE_OBJ_LIMIT;
+
+#if GC_PROFILE_MORE_DETAIL
+ record->heap_use_pages = objspace->profile.heap_used_at_gc_start;
+ record->heap_live_objects = live;
+ record->heap_free_objects = total - live;
+#endif
+
+ record->heap_total_objects = total;
+ record->heap_use_size = live * sizeof(RVALUE);
+ record->heap_total_size = total * sizeof(RVALUE);
+ }
+}
+
+/*
+ * call-seq:
+ * GC::Profiler.clear -> nil
+ *
+ * Clears the \GC profiler data.
+ *
+ */
+
+static VALUE
+gc_profile_clear(VALUE _)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ void *p = objspace->profile.records;
+ objspace->profile.records = NULL;
+ objspace->profile.size = 0;
+ objspace->profile.next_index = 0;
+ objspace->profile.current_record = 0;
+ if (p) {
+ free(p);
+ }
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * GC::Profiler.raw_data -> [Hash, ...]
+ *
+ * Returns an Array of individual raw profile data Hashes ordered
+ * from earliest to latest by +:GC_INVOKE_TIME+.
+ *
+ * For example:
+ *
+ * [
+ * {
+ * :GC_TIME=>1.3000000000000858e-05,
+ * :GC_INVOKE_TIME=>0.010634999999999999,
+ * :HEAP_USE_SIZE=>289640,
+ * :HEAP_TOTAL_SIZE=>588960,
+ * :HEAP_TOTAL_OBJECTS=>14724,
+ * :GC_IS_MARKED=>false
+ * },
+ * # ...
+ * ]
+ *
+ * The keys mean:
+ *
+ * +:GC_TIME+::
+ * Time elapsed in seconds for this GC run
+ * +:GC_INVOKE_TIME+::
+ * Time elapsed in seconds from startup to when the GC was invoked
+ * +:HEAP_USE_SIZE+::
+ * Total bytes of heap used
+ * +:HEAP_TOTAL_SIZE+::
+ * Total size of heap in bytes
+ * +:HEAP_TOTAL_OBJECTS+::
+ * Total number of objects
+ * +:GC_IS_MARKED+::
+ * Returns +true+ if the GC is in mark phase
+ *
+ * If ruby was built with +GC_PROFILE_MORE_DETAIL+, you will also have access
+ * to the following hash keys:
+ *
+ * +:GC_MARK_TIME+::
+ * +:GC_SWEEP_TIME+::
+ * +:ALLOCATE_INCREASE+::
+ * +:ALLOCATE_LIMIT+::
+ * +:HEAP_USE_PAGES+::
+ * +:HEAP_LIVE_OBJECTS+::
+ * +:HEAP_FREE_OBJECTS+::
+ * +:HAVE_FINALIZE+::
+ *
+ */
+
+static VALUE
+gc_profile_record_get(VALUE _)
+{
+ VALUE prof;
+ VALUE gc_profile = rb_ary_new();
+ size_t i;
+ rb_objspace_t *objspace = (&rb_objspace);
+
+ if (!objspace->profile.run) {
+ return Qnil;
+ }
+
+ for (i =0; i < objspace->profile.next_index; i++) {
+ gc_profile_record *record = &objspace->profile.records[i];
+
+ prof = rb_hash_new();
+ rb_hash_aset(prof, ID2SYM(rb_intern("GC_FLAGS")), gc_info_decode(0, rb_hash_new(), record->flags));
+ rb_hash_aset(prof, ID2SYM(rb_intern("GC_TIME")), DBL2NUM(record->gc_time));
+ rb_hash_aset(prof, ID2SYM(rb_intern("GC_INVOKE_TIME")), DBL2NUM(record->gc_invoke_time));
+ rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SIZE")), SIZET2NUM(record->heap_use_size));
+ rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")), SIZET2NUM(record->heap_total_size));
+ rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")), SIZET2NUM(record->heap_total_objects));
+ rb_hash_aset(prof, ID2SYM(rb_intern("MOVED_OBJECTS")), SIZET2NUM(record->moved_objects));
+ rb_hash_aset(prof, ID2SYM(rb_intern("GC_IS_MARKED")), Qtrue);
+#if GC_PROFILE_MORE_DETAIL
+ rb_hash_aset(prof, ID2SYM(rb_intern("GC_MARK_TIME")), DBL2NUM(record->gc_mark_time));
+ rb_hash_aset(prof, ID2SYM(rb_intern("GC_SWEEP_TIME")), DBL2NUM(record->gc_sweep_time));
+ rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_INCREASE")), SIZET2NUM(record->allocate_increase));
+ rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_LIMIT")), SIZET2NUM(record->allocate_limit));
+ rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_PAGES")), SIZET2NUM(record->heap_use_pages));
+ rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_LIVE_OBJECTS")), SIZET2NUM(record->heap_live_objects));
+ rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_FREE_OBJECTS")), SIZET2NUM(record->heap_free_objects));
+
+ rb_hash_aset(prof, ID2SYM(rb_intern("REMOVING_OBJECTS")), SIZET2NUM(record->removing_objects));
+ rb_hash_aset(prof, ID2SYM(rb_intern("EMPTY_OBJECTS")), SIZET2NUM(record->empty_objects));
+
+ rb_hash_aset(prof, ID2SYM(rb_intern("HAVE_FINALIZE")), RBOOL(record->flags & GPR_FLAG_HAVE_FINALIZE));
+#endif
+
+#if RGENGC_PROFILE > 0
+ rb_hash_aset(prof, ID2SYM(rb_intern("OLD_OBJECTS")), SIZET2NUM(record->old_objects));
+ rb_hash_aset(prof, ID2SYM(rb_intern("REMEMBERED_NORMAL_OBJECTS")), SIZET2NUM(record->remembered_normal_objects));
+ rb_hash_aset(prof, ID2SYM(rb_intern("REMEMBERED_SHADY_OBJECTS")), SIZET2NUM(record->remembered_shady_objects));
+#endif
+ rb_ary_push(gc_profile, prof);
+ }
+
+ return gc_profile;
+}
+
+#if GC_PROFILE_MORE_DETAIL
+#define MAJOR_REASON_MAX 0x10
+
+static char *
+gc_profile_dump_major_reason(unsigned int flags, char *buff)
+{
+ unsigned int reason = flags & GPR_FLAG_MAJOR_MASK;
+ int i = 0;
+
+ if (reason == GPR_FLAG_NONE) {
+ buff[0] = '-';
+ buff[1] = 0;
+ }
+ else {
+#define C(x, s) \
+ if (reason & GPR_FLAG_MAJOR_BY_##x) { \
+ buff[i++] = #x[0]; \
+ if (i >= MAJOR_REASON_MAX) rb_bug("gc_profile_dump_major_reason: overflow"); \
+ buff[i] = 0; \
+ }
+ C(NOFREE, N);
+ C(OLDGEN, O);
+ C(SHADY, S);
+#if RGENGC_ESTIMATE_OLDMALLOC
+ C(OLDMALLOC, M);
+#endif
+#undef C
+ }
+ return buff;
+}
+#endif
+
+static void
+gc_profile_dump_on(VALUE out, VALUE (*append)(VALUE, VALUE))
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ size_t count = objspace->profile.next_index;
+#ifdef MAJOR_REASON_MAX
+ char reason_str[MAJOR_REASON_MAX];
+#endif
+
+ if (objspace->profile.run && count /* > 1 */) {
+ size_t i;
+ const gc_profile_record *record;
+
+ append(out, rb_sprintf("GC %"PRIuSIZE" invokes.\n", objspace->profile.count));
+ append(out, rb_str_new_cstr("Index Invoke Time(sec) Use Size(byte) Total Size(byte) Total Object GC Time(ms)\n"));
+
+ for (i = 0; i < count; i++) {
+ record = &objspace->profile.records[i];
+ append(out, rb_sprintf("%5"PRIuSIZE" %19.3f %20"PRIuSIZE" %20"PRIuSIZE" %20"PRIuSIZE" %30.20f\n",
+ i+1, record->gc_invoke_time, record->heap_use_size,
+ record->heap_total_size, record->heap_total_objects, record->gc_time*1000));
+ }
+
+#if GC_PROFILE_MORE_DETAIL
+ const char *str = "\n\n" \
+ "More detail.\n" \
+ "Prepare Time = Previously GC's rest sweep time\n"
+ "Index Flags Allocate Inc. Allocate Limit"
+#if CALC_EXACT_MALLOC_SIZE
+ " Allocated Size"
+#endif
+ " Use Page Mark Time(ms) Sweep Time(ms) Prepare Time(ms) LivingObj FreeObj RemovedObj EmptyObj"
+#if RGENGC_PROFILE
+ " OldgenObj RemNormObj RemShadObj"
+#endif
+#if GC_PROFILE_DETAIL_MEMORY
+ " MaxRSS(KB) MinorFLT MajorFLT"
+#endif
+ "\n";
+ append(out, rb_str_new_cstr(str));
+
+ for (i = 0; i < count; i++) {
+ record = &objspace->profile.records[i];
+ append(out, rb_sprintf("%5"PRIuSIZE" %4s/%c/%6s%c %13"PRIuSIZE" %15"PRIuSIZE
+#if CALC_EXACT_MALLOC_SIZE
+ " %15"PRIuSIZE
+#endif
+ " %9"PRIuSIZE" %17.12f %17.12f %17.12f %10"PRIuSIZE" %10"PRIuSIZE" %10"PRIuSIZE" %10"PRIuSIZE
+#if RGENGC_PROFILE
+ "%10"PRIuSIZE" %10"PRIuSIZE" %10"PRIuSIZE
+#endif
+#if GC_PROFILE_DETAIL_MEMORY
+ "%11ld %8ld %8ld"
+#endif
+
+ "\n",
+ i+1,
+ gc_profile_dump_major_reason(record->flags, reason_str),
+ (record->flags & GPR_FLAG_HAVE_FINALIZE) ? 'F' : '.',
+ (record->flags & GPR_FLAG_NEWOBJ) ? "NEWOBJ" :
+ (record->flags & GPR_FLAG_MALLOC) ? "MALLOC" :
+ (record->flags & GPR_FLAG_METHOD) ? "METHOD" :
+ (record->flags & GPR_FLAG_CAPI) ? "CAPI__" : "??????",
+ (record->flags & GPR_FLAG_STRESS) ? '!' : ' ',
+ record->allocate_increase, record->allocate_limit,
+#if CALC_EXACT_MALLOC_SIZE
+ record->allocated_size,
+#endif
+ record->heap_use_pages,
+ record->gc_mark_time*1000,
+ record->gc_sweep_time*1000,
+ record->prepare_time*1000,
+
+ record->heap_live_objects,
+ record->heap_free_objects,
+ record->removing_objects,
+ record->empty_objects
+#if RGENGC_PROFILE
+ ,
+ record->old_objects,
+ record->remembered_normal_objects,
+ record->remembered_shady_objects
+#endif
+#if GC_PROFILE_DETAIL_MEMORY
+ ,
+ record->maxrss / 1024,
+ record->minflt,
+ record->majflt
+#endif
+
+ ));
+ }
+#endif
+ }
+}
+
+/*
+ * call-seq:
+ * GC::Profiler.result -> String
+ *
+ * Returns a profile data report such as:
+ *
+ * GC 1 invokes.
+ * Index Invoke Time(sec) Use Size(byte) Total Size(byte) Total Object GC time(ms)
+ * 1 0.012 159240 212940 10647 0.00000000000001530000
+ */
+
+static VALUE
+gc_profile_result(VALUE _)
+{
+ VALUE str = rb_str_buf_new(0);
+ gc_profile_dump_on(str, rb_str_buf_append);
+ return str;
+}
+
+/*
+ * call-seq:
+ * GC::Profiler.report
+ * GC::Profiler.report(io)
+ *
+ * Writes the GC::Profiler.result to <tt>$stdout</tt> or the given IO object.
+ *
+ */
+
+static VALUE
+gc_profile_report(int argc, VALUE *argv, VALUE self)
+{
+ VALUE out;
+
+ out = (!rb_check_arity(argc, 0, 1) ? rb_stdout : argv[0]);
+ gc_profile_dump_on(out, rb_io_write);
+
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * GC::Profiler.total_time -> float
+ *
+ * The total time used for garbage collection in seconds
+ */
+
+static VALUE
+gc_profile_total_time(VALUE self)
+{
+ double time = 0;
+ rb_objspace_t *objspace = &rb_objspace;
+
+ if (objspace->profile.run && objspace->profile.next_index > 0) {
+ size_t i;
+ size_t count = objspace->profile.next_index;
+
+ for (i = 0; i < count; i++) {
+ time += objspace->profile.records[i].gc_time;
+ }
+ }
+ return DBL2NUM(time);
+}
+
+/*
+ * call-seq:
+ * GC::Profiler.enabled? -> true or false
+ *
+ * The current status of \GC profile mode.
+ */
+
+static VALUE
+gc_profile_enable_get(VALUE self)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ return RBOOL(objspace->profile.run);
+}
+
+/*
+ * call-seq:
+ * GC::Profiler.enable -> nil
+ *
+ * Starts the \GC profiler.
+ *
+ */
+
+static VALUE
+gc_profile_enable(VALUE _)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ objspace->profile.run = TRUE;
+ objspace->profile.current_record = 0;
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * GC::Profiler.disable -> nil
+ *
+ * Stops the \GC profiler.
+ *
+ */
+
+static VALUE
+gc_profile_disable(VALUE _)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+
+ objspace->profile.run = FALSE;
+ objspace->profile.current_record = 0;
+ return Qnil;
}
/*
@@ -3681,6 +14121,7 @@ str_len_no_raise(VALUE str)
memcpy(buff + pos, (s), rb_strlen_lit(s) + 1); \
} \
} while (0)
+#define TF(c) ((c) != 0 ? "true" : "false")
#define C(c, s) ((c) != 0 ? (s) : " ")
static size_t
@@ -3699,25 +14140,24 @@ rb_raw_obj_info_common(char *const buff, const size_t buff_size, const VALUE obj
}
}
else {
- // const int age = RVALUE_AGE_GET(obj);
-
- if (rb_gc_impl_pointer_to_heap_p(rb_gc_get_objspace(), (void *)obj)) {
- // TODO: fixme
- // APPEND_F("%p [%d%s%s%s%s%s%s] %s ",
- // (void *)obj, age,
- // C(RVALUE_UNCOLLECTIBLE_BITMAP(obj), "L"),
- // C(RVALUE_MARK_BITMAP(obj), "M"),
- // C(RVALUE_PIN_BITMAP(obj), "P"),
- // C(RVALUE_MARKING_BITMAP(obj), "R"),
- // C(RVALUE_WB_UNPROTECTED_BITMAP(obj), "U"),
- // C(rb_objspace_garbage_object_p(obj), "G"),
- // obj_type_name(obj));
+ const int age = RVALUE_FLAGS_AGE(RBASIC(obj)->flags);
+
+ if (is_pointer_to_heap(&rb_objspace, (void *)obj)) {
+ APPEND_F("%p [%d%s%s%s%s%s%s] %s ",
+ (void *)obj, age,
+ C(RVALUE_UNCOLLECTIBLE_BITMAP(obj), "L"),
+ C(RVALUE_MARK_BITMAP(obj), "M"),
+ C(RVALUE_PIN_BITMAP(obj), "P"),
+ C(RVALUE_MARKING_BITMAP(obj), "R"),
+ C(RVALUE_WB_UNPROTECTED_BITMAP(obj), "U"),
+ C(rb_objspace_garbage_object_p(obj), "G"),
+ obj_type_name(obj));
}
else {
/* fake */
- // APPEND_F("%p [%dXXXX] %s",
- // (void *)obj, age,
- // obj_type_name(obj));
+ APPEND_F("%p [%dXXXX] %s",
+ (void *)obj, age,
+ obj_type_name(obj));
}
if (internal_object_p(obj)) {
@@ -3732,14 +14172,16 @@ rb_raw_obj_info_common(char *const buff, const size_t buff_size, const VALUE obj
APPEND_F("(%s)", RSTRING_PTR(class_path));
}
}
+
+#if GC_DEBUG
+ APPEND_F("@%s:%d", RANY(obj)->file, RANY(obj)->line);
+#endif
}
end:
return pos;
}
-const char *rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj);
-
static size_t
rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALUE obj, size_t pos)
{
@@ -3762,12 +14204,13 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
RARRAY_LEN(obj));
}
else {
- APPEND_F("[%s%s] len: %ld, capa:%ld ptr:%p",
+ APPEND_F("[%s%s%s] len: %ld, capa:%ld ptr:%p",
C(ARY_EMBED_P(obj), "E"),
C(ARY_SHARED_P(obj), "S"),
+ C(RARRAY_TRANSIENT_P(obj), "T"),
RARRAY_LEN(obj),
ARY_EMBED_P(obj) ? -1L : RARRAY(obj)->as.heap.aux.capa,
- (void *)RARRAY_CONST_PTR(obj));
+ (void *)RARRAY_CONST_PTR_TRANSIENT(obj));
}
break;
case T_STRING: {
@@ -3794,12 +14237,13 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
break;
}
case T_MOVED: {
- APPEND_F("-> %p", (void*)rb_gc_impl_location(rb_gc_get_objspace(), obj));
+ APPEND_F("-> %p", (void*)rb_gc_location(obj));
break;
}
case T_HASH: {
- APPEND_F("[%c] %"PRIdSIZE,
+ APPEND_F("[%c%c] %"PRIdSIZE,
RHASH_AR_TABLE_P(obj) ? 'A' : 'S',
+ RHASH_TRANSIENT_P(obj) ? 'T' : ' ',
RHASH_SIZE(obj));
break;
}
@@ -3811,7 +14255,7 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
APPEND_F("%s", RSTRING_PTR(class_path));
}
else {
- APPEND_S("(anon)");
+ APPEND_S("(annon)");
}
break;
}
@@ -3825,20 +14269,14 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
}
case T_OBJECT:
{
- if (rb_shape_obj_too_complex(obj)) {
- size_t hash_len = rb_st_table_size(ROBJECT_IV_HASH(obj));
- APPEND_F("(too_complex) len:%zu", hash_len);
+ uint32_t len = ROBJECT_IV_CAPACITY(obj);
+
+ if (RANY(obj)->as.basic.flags & ROBJECT_EMBED) {
+ APPEND_F("(embed) len:%d", len);
}
else {
- uint32_t len = ROBJECT_IV_CAPACITY(obj);
-
- if (RBASIC(obj)->flags & ROBJECT_EMBED) {
- APPEND_F("(embed) len:%d", len);
- }
- else {
- VALUE *ptr = ROBJECT_IVPTR(obj);
- APPEND_F("len:%d ptr:%p", len, (void *)ptr);
- }
+ VALUE *ptr = ROBJECT_IVPTR(obj);
+ APPEND_F("len:%d ptr:%p", len, (void *)ptr);
}
}
break;
@@ -3871,7 +14309,7 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
switch (imemo_type(obj)) {
case imemo_ment:
{
- const rb_method_entry_t *me = (const rb_method_entry_t *)obj;
+ const rb_method_entry_t *me = &RANY(obj)->as.imemo.ment;
APPEND_F(":%s (%s%s%s%s) type:%s aliased:%d owner:%p defined_class:%p",
rb_id2name(me->called_id),
@@ -3941,14 +14379,9 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU
return pos;
}
+#undef TF
#undef C
-#define asan_unpoisoning_object(obj) \
- for (void *poisoned = asan_unpoison_object_temporary(obj), \
- *unpoisoning = &poisoned; /* flag to loop just once */ \
- unpoisoning; \
- unpoisoning = asan_poison_object_restore(obj, poisoned))
-
const char *
rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj)
{
@@ -3977,7 +14410,7 @@ static rb_atomic_t
atomic_inc_wraparound(rb_atomic_t *var, const rb_atomic_t maxval)
{
rb_atomic_t oldval = RUBY_ATOMIC_FETCH_ADD(*var, 1);
- if (RB_UNLIKELY(oldval >= maxval - 1)) { // wraparound *var
+ if (UNLIKELY(oldval >= maxval - 1)) { // wraparound *var
const rb_atomic_t newval = oldval + 1;
RUBY_ATOMIC_CAS(*var, newval, newval % maxval);
oldval %= maxval;
@@ -4000,327 +14433,125 @@ obj_info(VALUE obj)
}
#endif
-/*
- ------------------------ Extended allocator ------------------------
-*/
-
-struct gc_raise_tag {
- VALUE exc;
- const char *fmt;
- va_list *ap;
-};
-
-static void *
-gc_vraise(void *ptr)
-{
- struct gc_raise_tag *argv = ptr;
- rb_vraise(argv->exc, argv->fmt, *argv->ap);
- UNREACHABLE_RETURN(NULL);
-}
-
-static void
-gc_raise(VALUE exc, const char *fmt, ...)
+MJIT_FUNC_EXPORTED const char *
+rb_obj_info(VALUE obj)
{
- va_list ap;
- va_start(ap, fmt);
- struct gc_raise_tag argv = {
- exc, fmt, &ap,
- };
-
- if (ruby_thread_has_gvl_p()) {
- gc_vraise(&argv);
- UNREACHABLE;
- }
- else if (ruby_native_thread_p()) {
- rb_thread_call_with_gvl(gc_vraise, &argv);
- UNREACHABLE;
- }
- else {
- /* Not in a ruby thread */
- fprintf(stderr, "%s", "[FATAL] ");
- vfprintf(stderr, fmt, ap);
- }
-
- va_end(ap);
- abort();
+ return obj_info(obj);
}
-NORETURN(static void negative_size_allocation_error(const char *));
-static void
-negative_size_allocation_error(const char *msg)
+void
+rb_obj_info_dump(VALUE obj)
{
- gc_raise(rb_eNoMemError, "%s", msg);
+ char buff[0x100];
+ fprintf(stderr, "rb_obj_info_dump: %s\n", rb_raw_obj_info(buff, 0x100, obj));
}
-static void *
-ruby_memerror_body(void *dummy)
+MJIT_FUNC_EXPORTED void
+rb_obj_info_dump_loc(VALUE obj, const char *file, int line, const char *func)
{
- rb_memerror();
- return 0;
+ char buff[0x100];
+ fprintf(stderr, "<OBJ_INFO:%s@%s:%d> %s\n", func, file, line, rb_raw_obj_info(buff, 0x100, obj));
}
-NORETURN(static void ruby_memerror(void));
-RBIMPL_ATTR_MAYBE_UNUSED()
-static void
-ruby_memerror(void)
-{
- if (ruby_thread_has_gvl_p()) {
- rb_memerror();
- }
- else {
- if (ruby_native_thread_p()) {
- rb_thread_call_with_gvl(ruby_memerror_body, 0);
- }
- else {
- /* no ruby thread */
- fprintf(stderr, "[FATAL] failed to allocate memory\n");
- }
- }
- exit(EXIT_FAILURE);
-}
+#if GC_DEBUG
void
-rb_memerror(void)
+rb_gcdebug_print_obj_condition(VALUE obj)
{
- rb_execution_context_t *ec = GET_EC();
- VALUE exc = GET_VM()->special_exceptions[ruby_error_nomemory];
+ rb_objspace_t *objspace = &rb_objspace;
- if (!exc ||
- rb_ec_raised_p(ec, RAISED_NOMEMORY)) {
- fprintf(stderr, "[FATAL] failed to allocate memory\n");
- exit(EXIT_FAILURE);
+ fprintf(stderr, "created at: %s:%d\n", RANY(obj)->file, RANY(obj)->line);
+
+ if (BUILTIN_TYPE(obj) == T_MOVED) {
+ fprintf(stderr, "moved?: true\n");
}
- if (rb_ec_raised_p(ec, RAISED_NOMEMORY)) {
- rb_ec_raised_clear(ec);
+ else {
+ fprintf(stderr, "moved?: false\n");
+ }
+ if (is_pointer_to_heap(objspace, (void *)obj)) {
+ fprintf(stderr, "pointer to heap?: true\n");
}
else {
- rb_ec_raised_set(ec, RAISED_NOMEMORY);
- exc = ruby_vm_special_exception_copy(exc);
+ fprintf(stderr, "pointer to heap?: false\n");
+ return;
}
- ec->errinfo = exc;
- EC_JUMP_TAG(ec, TAG_RAISE);
-}
-void
-rb_malloc_info_show_results(void)
-{
-}
+ fprintf(stderr, "marked? : %s\n", MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj) ? "true" : "false");
+ fprintf(stderr, "pinned? : %s\n", MARKED_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj) ? "true" : "false");
+ fprintf(stderr, "age? : %d\n", RVALUE_AGE(obj));
+ fprintf(stderr, "old? : %s\n", RVALUE_OLD_P(obj) ? "true" : "false");
+ fprintf(stderr, "WB-protected?: %s\n", RVALUE_WB_UNPROTECTED(obj) ? "false" : "true");
+ fprintf(stderr, "remembered? : %s\n", RVALUE_REMEMBERED(obj) ? "true" : "false");
-void *
-ruby_xmalloc(size_t size)
-{
- if ((ssize_t)size < 0) {
- negative_size_allocation_error("too large allocation size");
+ if (is_lazy_sweeping(objspace)) {
+ fprintf(stderr, "lazy sweeping?: true\n");
+ fprintf(stderr, "swept?: %s\n", is_swept_object(objspace, obj) ? "done" : "not yet");
}
-
- return rb_gc_impl_malloc(rb_gc_get_objspace(), size);
-}
-
-void
-ruby_malloc_size_overflow(size_t count, size_t elsize)
-{
- rb_raise(rb_eArgError,
- "malloc: possible integer overflow (%"PRIuSIZE"*%"PRIuSIZE")",
- count, elsize);
-}
-
-void *
-ruby_xmalloc2(size_t n, size_t size)
-{
- return rb_gc_impl_malloc(rb_gc_get_objspace(), xmalloc2_size(n, size));
-}
-
-void *
-ruby_xcalloc(size_t n, size_t size)
-{
- return rb_gc_impl_calloc(rb_gc_get_objspace(), xmalloc2_size(n, size));
-}
-
-#ifdef ruby_sized_xrealloc
-#undef ruby_sized_xrealloc
-#endif
-void *
-ruby_sized_xrealloc(void *ptr, size_t new_size, size_t old_size)
-{
- if ((ssize_t)new_size < 0) {
- negative_size_allocation_error("too large allocation size");
+ else {
+ fprintf(stderr, "lazy sweeping?: false\n");
}
-
- return rb_gc_impl_realloc(rb_gc_get_objspace(), ptr, new_size, old_size);
}
-void *
-ruby_xrealloc(void *ptr, size_t new_size)
-{
- return ruby_sized_xrealloc(ptr, new_size, 0);
-}
-
-#ifdef ruby_sized_xrealloc2
-#undef ruby_sized_xrealloc2
-#endif
-void *
-ruby_sized_xrealloc2(void *ptr, size_t n, size_t size, size_t old_n)
-{
- size_t len = xmalloc2_size(n, size);
- return rb_gc_impl_realloc(rb_gc_get_objspace(), ptr, len, old_n * size);
-}
-
-void *
-ruby_xrealloc2(void *ptr, size_t n, size_t size)
-{
- return ruby_sized_xrealloc2(ptr, n, size, 0);
-}
-
-#ifdef ruby_sized_xfree
-#undef ruby_sized_xfree
-#endif
-void
-ruby_sized_xfree(void *x, size_t size)
+static VALUE
+gcdebug_sentinel(RB_BLOCK_CALL_FUNC_ARGLIST(obj, name))
{
- if (LIKELY(x)) {
- /* It's possible for a C extension's pthread destructor function set by pthread_key_create
- * to be called after ruby_vm_destruct and attempt to free memory. Fall back to mimfree in
- * that case. */
- if (LIKELY(GET_VM())) {
- rb_gc_impl_free(rb_gc_get_objspace(), x, size);
- }
- else {
- ruby_mimfree(x);
- }
- }
+ fprintf(stderr, "WARNING: object %s(%p) is inadvertently collected\n", (char *)name, (void *)obj);
+ return Qnil;
}
void
-ruby_xfree(void *x)
-{
- ruby_sized_xfree(x, 0);
-}
-
-void *
-rb_xmalloc_mul_add(size_t x, size_t y, size_t z) /* x * y + z */
+rb_gcdebug_sentinel(VALUE obj, const char *name)
{
- size_t w = size_mul_add_or_raise(x, y, z, rb_eArgError);
- return ruby_xmalloc(w);
+ rb_define_finalizer(obj, rb_proc_new(gcdebug_sentinel, (VALUE)name));
}
-void *
-rb_xcalloc_mul_add(size_t x, size_t y, size_t z) /* x * y + z */
-{
- size_t w = size_mul_add_or_raise(x, y, z, rb_eArgError);
- return ruby_xcalloc(w, 1);
-}
+#endif /* GC_DEBUG */
-void *
-rb_xrealloc_mul_add(const void *p, size_t x, size_t y, size_t z) /* x * y + z */
+#if GC_DEBUG_STRESS_TO_CLASS
+/*
+ * call-seq:
+ * GC.add_stress_to_class(class[, ...])
+ *
+ * Raises NoMemoryError when allocating an instance of the given classes.
+ *
+ */
+static VALUE
+rb_gcdebug_add_stress_to_class(int argc, VALUE *argv, VALUE self)
{
- size_t w = size_mul_add_or_raise(x, y, z, rb_eArgError);
- return ruby_xrealloc((void *)p, w);
-}
+ rb_objspace_t *objspace = &rb_objspace;
-void *
-rb_xmalloc_mul_add_mul(size_t x, size_t y, size_t z, size_t w) /* x * y + z * w */
-{
- size_t u = size_mul_add_mul_or_raise(x, y, z, w, rb_eArgError);
- return ruby_xmalloc(u);
-}
-
-void *
-rb_xcalloc_mul_add_mul(size_t x, size_t y, size_t z, size_t w) /* x * y + z * w */
-{
- size_t u = size_mul_add_mul_or_raise(x, y, z, w, rb_eArgError);
- return ruby_xcalloc(u, 1);
+ if (!stress_to_class) {
+ stress_to_class = rb_ary_hidden_new(argc);
+ }
+ rb_ary_cat(stress_to_class, argv, argc);
+ return self;
}
-/* Mimic ruby_xmalloc, but need not rb_objspace.
- * should return pointer suitable for ruby_xfree
+/*
+ * call-seq:
+ * GC.remove_stress_to_class(class[, ...])
+ *
+ * No longer raises NoMemoryError when allocating an instance of the
+ * given classes.
+ *
*/
-void *
-ruby_mimmalloc(size_t size)
+static VALUE
+rb_gcdebug_remove_stress_to_class(int argc, VALUE *argv, VALUE self)
{
- void *mem;
-#if CALC_EXACT_MALLOC_SIZE
- size += sizeof(struct malloc_obj_info);
-#endif
- mem = malloc(size);
-#if CALC_EXACT_MALLOC_SIZE
- if (!mem) {
- return NULL;
- }
- else
- /* set 0 for consistency of allocated_size/allocations */
- {
- struct malloc_obj_info *info = mem;
- info->size = 0;
- mem = info + 1;
- }
-#endif
- return mem;
-}
+ rb_objspace_t *objspace = &rb_objspace;
+ int i;
-void *
-ruby_mimcalloc(size_t num, size_t size)
-{
- void *mem;
-#if CALC_EXACT_MALLOC_SIZE
- struct rbimpl_size_mul_overflow_tag t = rbimpl_size_mul_overflow(num, size);
- if (UNLIKELY(t.left)) {
- return NULL;
- }
- size = t.right + sizeof(struct malloc_obj_info);
- mem = calloc1(size);
- if (!mem) {
- return NULL;
- }
- else
- /* set 0 for consistency of allocated_size/allocations */
- {
- struct malloc_obj_info *info = mem;
- info->size = 0;
- mem = info + 1;
+ if (stress_to_class) {
+ for (i = 0; i < argc; ++i) {
+ rb_ary_delete_same(stress_to_class, argv[i]);
+ }
+ if (RARRAY_LEN(stress_to_class) == 0) {
+ stress_to_class = 0;
+ }
}
-#else
- mem = calloc(num, size);
-#endif
- return mem;
+ return Qnil;
}
-
-void
-ruby_mimfree(void *ptr)
-{
-#if CALC_EXACT_MALLOC_SIZE
- struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
- ptr = info;
#endif
- free(ptr);
-}
-
-void
-rb_gc_adjust_memory_usage(ssize_t diff)
-{
- unless_objspace(objspace) { return; }
-
- rb_gc_impl_adjust_memory_usage(objspace, diff);
-}
-
-const char *
-rb_obj_info(VALUE obj)
-{
- return obj_info(obj);
-}
-
-void
-rb_obj_info_dump(VALUE obj)
-{
- char buff[0x100];
- fprintf(stderr, "rb_obj_info_dump: %s\n", rb_raw_obj_info(buff, 0x100, obj));
-}
-
-void
-rb_obj_info_dump_loc(VALUE obj, const char *file, int line, const char *func)
-{
- char buff[0x100];
- fprintf(stderr, "<OBJ_INFO:%s@%s:%d> %s\n", func, file, line, rb_raw_obj_info(buff, 0x100, obj));
-}
/*
* Document-module: ObjectSpace
@@ -4330,9 +14561,10 @@ rb_obj_info_dump_loc(VALUE obj, const char *file, int line, const char *func)
* traverse all living objects with an iterator.
*
* ObjectSpace also provides support for object finalizers, procs that will be
- * called after a specific object was destroyed by garbage collection. See
- * the documentation for +ObjectSpace.define_finalizer+ for important
- * information on how to use this method correctly.
+ * called when a specific object is about to be destroyed by garbage
+ * collection. See the documentation for
+ * <code>ObjectSpace.define_finalizer</code> for important information on
+ * how to use this method correctly.
*
* a = "A"
* b = "B"
@@ -4349,6 +14581,16 @@ rb_obj_info_dump_loc(VALUE obj, const char *file, int line, const char *func)
* Finalizer one on 537763480
*/
+/*
+ * Document-class: ObjectSpace::WeakMap
+ *
+ * An ObjectSpace::WeakMap object holds references to
+ * any objects, but those objects can get garbage collected.
+ *
+ * This class is mostly used internally by WeakRef, please use
+ * +lib/weakref.rb+ for the public interface.
+ */
+
/* Document-class: GC::Profiler
*
* The GC profiler provides access to information on GC runs including time,
@@ -4368,16 +14610,58 @@ rb_obj_info_dump_loc(VALUE obj, const char *file, int line, const char *func)
*/
#include "gc.rbinc"
+/*
+ * call-seq:
+ * GC.using_rvargc? -> true or false
+ *
+ * Returns true if using experimental feature Variable Width Allocation, false
+ * otherwise.
+ */
+static VALUE
+gc_using_rvargc_p(VALUE mod)
+{
+#if USE_RVARGC
+ return Qtrue;
+#else
+ return Qfalse;
+#endif
+}
void
Init_GC(void)
{
#undef rb_intern
- malloc_offset = gc_compute_malloc_offset();
+ VALUE rb_mObjSpace;
+ VALUE rb_mProfiler;
+ VALUE gc_constants;
rb_mGC = rb_define_module("GC");
- VALUE rb_mObjSpace = rb_define_module("ObjectSpace");
+ gc_constants = rb_hash_new();
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("DEBUG")), RBOOL(GC_DEBUG));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("BASE_SLOT_SIZE")), SIZET2NUM(BASE_SLOT_SIZE - RVALUE_OVERHEAD));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OVERHEAD")), SIZET2NUM(RVALUE_OVERHEAD));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_SIZE")), SIZET2NUM(sizeof(RVALUE)));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_PAGE_OBJ_LIMIT")), SIZET2NUM(HEAP_PAGE_OBJ_LIMIT));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_PAGE_BITMAP_SIZE")), SIZET2NUM(HEAP_PAGE_BITMAP_SIZE));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_PAGE_SIZE")), SIZET2NUM(HEAP_PAGE_SIZE));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("SIZE_POOL_COUNT")), LONG2FIX(SIZE_POOL_COUNT));
+ rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVARGC_MAX_ALLOCATE_SIZE")), LONG2FIX(size_pool_slot_size(SIZE_POOL_COUNT - 1)));
+ OBJ_FREEZE(gc_constants);
+ /* internal constants */
+ rb_define_const(rb_mGC, "INTERNAL_CONSTANTS", gc_constants);
+
+ rb_mProfiler = rb_define_module_under(rb_mGC, "Profiler");
+ rb_define_singleton_method(rb_mProfiler, "enabled?", gc_profile_enable_get, 0);
+ rb_define_singleton_method(rb_mProfiler, "enable", gc_profile_enable, 0);
+ rb_define_singleton_method(rb_mProfiler, "raw_data", gc_profile_record_get, 0);
+ rb_define_singleton_method(rb_mProfiler, "disable", gc_profile_disable, 0);
+ rb_define_singleton_method(rb_mProfiler, "clear", gc_profile_clear, 0);
+ rb_define_singleton_method(rb_mProfiler, "result", gc_profile_result, 0);
+ rb_define_singleton_method(rb_mProfiler, "report", gc_profile_report, -1);
+ rb_define_singleton_method(rb_mProfiler, "total_time", gc_profile_total_time, 0);
+
+ rb_mObjSpace = rb_define_module("ObjectSpace");
rb_define_module_function(rb_mObjSpace, "each_object", os_each_obj, -1);
@@ -4393,5 +14677,141 @@ Init_GC(void)
rb_define_module_function(rb_mObjSpace, "count_objects", count_objects, -1);
- rb_gc_impl_init();
+ {
+ VALUE rb_cWeakMap = rb_define_class_under(rb_mObjSpace, "WeakMap", rb_cObject);
+ rb_define_alloc_func(rb_cWeakMap, wmap_allocate);
+ rb_define_method(rb_cWeakMap, "[]=", wmap_aset, 2);
+ rb_define_method(rb_cWeakMap, "[]", wmap_aref, 1);
+ rb_define_method(rb_cWeakMap, "include?", wmap_has_key, 1);
+ rb_define_method(rb_cWeakMap, "member?", wmap_has_key, 1);
+ rb_define_method(rb_cWeakMap, "key?", wmap_has_key, 1);
+ rb_define_method(rb_cWeakMap, "inspect", wmap_inspect, 0);
+ rb_define_method(rb_cWeakMap, "each", wmap_each, 0);
+ rb_define_method(rb_cWeakMap, "each_pair", wmap_each, 0);
+ rb_define_method(rb_cWeakMap, "each_key", wmap_each_key, 0);
+ rb_define_method(rb_cWeakMap, "each_value", wmap_each_value, 0);
+ rb_define_method(rb_cWeakMap, "keys", wmap_keys, 0);
+ rb_define_method(rb_cWeakMap, "values", wmap_values, 0);
+ rb_define_method(rb_cWeakMap, "size", wmap_size, 0);
+ rb_define_method(rb_cWeakMap, "length", wmap_size, 0);
+ rb_include_module(rb_cWeakMap, rb_mEnumerable);
+ }
+
+ /* internal methods */
+ rb_define_singleton_method(rb_mGC, "verify_internal_consistency", gc_verify_internal_consistency_m, 0);
+ rb_define_singleton_method(rb_mGC, "verify_transient_heap_internal_consistency", gc_verify_transient_heap_internal_consistency, 0);
+#if MALLOC_ALLOCATED_SIZE
+ rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0);
+ rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0);
+#endif
+
+ rb_define_singleton_method(rb_mGC, "using_rvargc?", gc_using_rvargc_p, 0);
+
+ if (GC_COMPACTION_SUPPORTED) {
+ rb_define_singleton_method(rb_mGC, "compact", gc_compact, 0);
+ rb_define_singleton_method(rb_mGC, "auto_compact", gc_get_auto_compact, 0);
+ rb_define_singleton_method(rb_mGC, "auto_compact=", gc_set_auto_compact, 1);
+ rb_define_singleton_method(rb_mGC, "latest_compact_info", gc_compact_stats, 0);
+ }
+ else {
+ rb_define_singleton_method(rb_mGC, "compact", rb_f_notimplement, 0);
+ rb_define_singleton_method(rb_mGC, "auto_compact", rb_f_notimplement, 0);
+ rb_define_singleton_method(rb_mGC, "auto_compact=", rb_f_notimplement, 1);
+ rb_define_singleton_method(rb_mGC, "latest_compact_info", rb_f_notimplement, 0);
+ /* When !GC_COMPACTION_SUPPORTED, this method is not defined in gc.rb */
+ rb_define_singleton_method(rb_mGC, "verify_compaction_references", rb_f_notimplement, -1);
+ }
+
+#if GC_DEBUG_STRESS_TO_CLASS
+ rb_define_singleton_method(rb_mGC, "add_stress_to_class", rb_gcdebug_add_stress_to_class, -1);
+ rb_define_singleton_method(rb_mGC, "remove_stress_to_class", rb_gcdebug_remove_stress_to_class, -1);
+#endif
+
+ {
+ VALUE opts;
+ /* \GC build options */
+ rb_define_const(rb_mGC, "OPTS", opts = rb_ary_new());
+#define OPT(o) if (o) rb_ary_push(opts, rb_fstring_lit(#o))
+ OPT(GC_DEBUG);
+ OPT(USE_RGENGC);
+ OPT(RGENGC_DEBUG);
+ OPT(RGENGC_CHECK_MODE);
+ OPT(RGENGC_PROFILE);
+ OPT(RGENGC_ESTIMATE_OLDMALLOC);
+ OPT(GC_PROFILE_MORE_DETAIL);
+ OPT(GC_ENABLE_LAZY_SWEEP);
+ OPT(CALC_EXACT_MALLOC_SIZE);
+ OPT(MALLOC_ALLOCATED_SIZE);
+ OPT(MALLOC_ALLOCATED_SIZE_CHECK);
+ OPT(GC_PROFILE_DETAIL_MEMORY);
+ OPT(GC_COMPACTION_SUPPORTED);
+#undef OPT
+ OBJ_FREEZE(opts);
+ }
+}
+
+#ifdef ruby_xmalloc
+#undef ruby_xmalloc
+#endif
+#ifdef ruby_xmalloc2
+#undef ruby_xmalloc2
+#endif
+#ifdef ruby_xcalloc
+#undef ruby_xcalloc
+#endif
+#ifdef ruby_xrealloc
+#undef ruby_xrealloc
+#endif
+#ifdef ruby_xrealloc2
+#undef ruby_xrealloc2
+#endif
+
+void *
+ruby_xmalloc(size_t size)
+{
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+ ruby_malloc_info_file = __FILE__;
+ ruby_malloc_info_line = __LINE__;
+#endif
+ return ruby_xmalloc_body(size);
+}
+
+void *
+ruby_xmalloc2(size_t n, size_t size)
+{
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+ ruby_malloc_info_file = __FILE__;
+ ruby_malloc_info_line = __LINE__;
+#endif
+ return ruby_xmalloc2_body(n, size);
+}
+
+void *
+ruby_xcalloc(size_t n, size_t size)
+{
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+ ruby_malloc_info_file = __FILE__;
+ ruby_malloc_info_line = __LINE__;
+#endif
+ return ruby_xcalloc_body(n, size);
+}
+
+void *
+ruby_xrealloc(void *ptr, size_t new_size)
+{
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+ ruby_malloc_info_file = __FILE__;
+ ruby_malloc_info_line = __LINE__;
+#endif
+ return ruby_xrealloc_body(ptr, new_size);
+}
+
+void *
+ruby_xrealloc2(void *ptr, size_t n, size_t new_size)
+{
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+ ruby_malloc_info_file = __FILE__;
+ ruby_malloc_info_line = __LINE__;
+#endif
+ return ruby_xrealloc2_body(ptr, n, new_size);
}
diff --git a/gc.h b/gc.h
new file mode 100644
index 0000000000..23218c1a9e
--- /dev/null
+++ b/gc.h
@@ -0,0 +1,147 @@
+#ifndef RUBY_GC_H
+#define RUBY_GC_H 1
+#include "ruby/ruby.h"
+
+#if defined(__x86_64__) && !defined(_ILP32) && defined(__GNUC__)
+#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movq\t%%rsp, %0" : "=r" (*(p)))
+#elif defined(__i386) && defined(__GNUC__)
+#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movl\t%%esp, %0" : "=r" (*(p)))
+#elif (defined(__powerpc__) || defined(__powerpc64__)) && defined(__GNUC__) && !defined(_AIX) && !defined(__APPLE__) // Not Apple is NEEDED to unbreak ppc64 build on Darwin. Don't ask.
+#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr\t%0, %%r1" : "=r" (*(p)))
+#elif (defined(__powerpc__) || defined(__powerpc64__)) && defined(__GNUC__) && defined(_AIX)
+#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr %0,1" : "=r" (*(p)))
+#elif defined(__POWERPC__) && defined(__APPLE__) // Darwin ppc and ppc64
+#define SET_MACHINE_STACK_END(p) __asm__ volatile("mr %0, r1" : "=r" (*(p)))
+#elif defined(__aarch64__) && defined(__GNUC__)
+#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mov\t%0, sp" : "=r" (*(p)))
+#else
+NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p));
+#define SET_MACHINE_STACK_END(p) rb_gc_set_stack_end(p)
+#define USE_CONSERVATIVE_STACK_END
+#endif
+
+#define RB_GC_SAVE_MACHINE_CONTEXT(th) \
+ do { \
+ FLUSH_REGISTER_WINDOWS; \
+ setjmp((th)->ec->machine.regs); \
+ SET_MACHINE_STACK_END(&(th)->ec->machine.stack_end); \
+ } while (0)
+
+/* for GC debug */
+
+#ifndef RUBY_MARK_FREE_DEBUG
+#define RUBY_MARK_FREE_DEBUG 0
+#endif
+
+#if RUBY_MARK_FREE_DEBUG
+extern int ruby_gc_debug_indent;
+
+static inline void
+rb_gc_debug_indent(void)
+{
+ ruby_debug_printf("%*s", ruby_gc_debug_indent, "");
+}
+
+static inline void
+rb_gc_debug_body(const char *mode, const char *msg, int st, void *ptr)
+{
+ if (st == 0) {
+ ruby_gc_debug_indent--;
+ }
+ rb_gc_debug_indent();
+ ruby_debug_printf("%s: %s %s (%p)\n", mode, st ? "->" : "<-", msg, ptr);
+
+ if (st) {
+ ruby_gc_debug_indent++;
+ }
+
+ fflush(stdout);
+}
+
+#define RUBY_MARK_ENTER(msg) rb_gc_debug_body("mark", (msg), 1, ptr)
+#define RUBY_MARK_LEAVE(msg) rb_gc_debug_body("mark", (msg), 0, ptr)
+#define RUBY_FREE_ENTER(msg) rb_gc_debug_body("free", (msg), 1, ptr)
+#define RUBY_FREE_LEAVE(msg) rb_gc_debug_body("free", (msg), 0, ptr)
+#define RUBY_GC_INFO rb_gc_debug_indent(), ruby_debug_printf
+
+#else
+#define RUBY_MARK_ENTER(msg)
+#define RUBY_MARK_LEAVE(msg)
+#define RUBY_FREE_ENTER(msg)
+#define RUBY_FREE_LEAVE(msg)
+#define RUBY_GC_INFO if(0)printf
+#endif
+
+#define RUBY_MARK_MOVABLE_UNLESS_NULL(ptr) do { \
+ VALUE markobj = (ptr); \
+ if (RTEST(markobj)) {rb_gc_mark_movable(markobj);} \
+} while (0)
+#define RUBY_MARK_UNLESS_NULL(ptr) do { \
+ VALUE markobj = (ptr); \
+ if (RTEST(markobj)) {rb_gc_mark(markobj);} \
+} while (0)
+#define RUBY_FREE_UNLESS_NULL(ptr) if(ptr){ruby_xfree(ptr);(ptr)=NULL;}
+
+#if STACK_GROW_DIRECTION > 0
+# define STACK_UPPER(x, a, b) (a)
+#elif STACK_GROW_DIRECTION < 0
+# define STACK_UPPER(x, a, b) (b)
+#else
+RUBY_EXTERN int ruby_stack_grow_direction;
+int ruby_get_stack_grow_direction(volatile VALUE *addr);
+# define stack_growup_p(x) ( \
+ (ruby_stack_grow_direction ? \
+ ruby_stack_grow_direction : \
+ ruby_get_stack_grow_direction(x)) > 0)
+# define STACK_UPPER(x, a, b) (stack_growup_p(x) ? (a) : (b))
+#endif
+
+/*
+ STACK_GROW_DIR_DETECTION is used with STACK_DIR_UPPER.
+
+ On most normal systems, stacks grow from high address to lower address. In
+ this case, STACK_DIR_UPPER(a, b) will return (b), but on exotic systems where
+ the stack grows UP (from low address to high address), it will return (a).
+*/
+
+#if STACK_GROW_DIRECTION
+#define STACK_GROW_DIR_DETECTION
+#define STACK_DIR_UPPER(a,b) STACK_UPPER(0, (a), (b))
+#else
+#define STACK_GROW_DIR_DETECTION VALUE stack_grow_dir_detection
+#define STACK_DIR_UPPER(a,b) STACK_UPPER(&stack_grow_dir_detection, (a), (b))
+#endif
+#define IS_STACK_DIR_UPPER() STACK_DIR_UPPER(1,0)
+
+const char *rb_obj_info(VALUE obj);
+const char *rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj);
+
+struct rb_thread_struct;
+
+size_t rb_size_pool_slot_size(unsigned char pool_id);
+
+RUBY_SYMBOL_EXPORT_BEGIN
+
+/* exports for objspace module */
+size_t rb_objspace_data_type_memsize(VALUE obj);
+void rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data);
+void rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *data);
+int rb_objspace_markable_object_p(VALUE obj);
+int rb_objspace_internal_object_p(VALUE obj);
+int rb_objspace_marked_object_p(VALUE obj);
+
+void rb_objspace_each_objects(
+ int (*callback)(void *start, void *end, size_t stride, void *data),
+ void *data);
+
+void rb_objspace_each_objects_without_setup(
+ int (*callback)(void *, void *, size_t, void *),
+ void *data);
+
+size_t rb_gc_obj_slot_size(VALUE obj);
+
+VALUE rb_gc_disable_no_rest(void);
+
+RUBY_SYMBOL_EXPORT_END
+
+#endif /* RUBY_GC_H */
diff --git a/gc.rb b/gc.rb
index 2a75e166ce..57aeeb9131 100644
--- a/gc.rb
+++ b/gc.rb
@@ -1,6 +1,6 @@
# for gc.c
-# The \GC module provides an interface to Ruby's mark and
+# The GC module provides an interface to Ruby's mark and
# sweep garbage collection mechanism.
#
# Some of the underlying methods are also available via the ObjectSpace
@@ -10,36 +10,30 @@
# GC::Profiler.
module GC
- # Initiates garbage collection, even if manually disabled.
- #
- # The +full_mark+ keyword argument determines whether or not to perform a
- # major garbage collection cycle. When set to +true+, a major garbage
- # collection cycle is ran, meaning all objects are marked. When set to
- # +false+, a minor garbage collection cycle is ran, meaning only young
- # objects are marked.
- #
- # The +immediate_mark+ keyword argument determines whether or not to perform
- # incremental marking. When set to +true+, marking is completed during the
- # call to this method. When set to +false+, marking is performed in steps
- # that is interleaved with future Ruby code execution, so marking might not
- # be completed during this method call. Note that if +full_mark+ is +false+
- # then marking will always be immediate, regardless of the value of
- # +immediate_mark+.
- #
- # The +immediate_sweep+ keyword argument determines whether or not to defer
- # sweeping (using lazy sweep). When set to +false+, sweeping is performed in
- # steps that is interleaved with future Ruby code execution, so sweeping might
- # not be completed during this method call. When set to +true+, sweeping is
- # completed during the call to this method.
- #
- # Note: These keyword arguments are implementation and version dependent. They
- # are not guaranteed to be future-compatible, and may be ignored if the
- # underlying implementation does not support them.
+ # call-seq:
+ # GC.start -> nil
+ # ObjectSpace.garbage_collect -> nil
+ # include GC; garbage_collect -> nil
+ # GC.start(full_mark: true, immediate_sweep: true) -> nil
+ # ObjectSpace.garbage_collect(full_mark: true, immediate_sweep: true) -> nil
+ # include GC; garbage_collect(full_mark: true, immediate_sweep: true) -> nil
+ #
+ # Initiates garbage collection, even if manually disabled.
+ #
+ # This method is defined with keyword arguments that default to true:
+ #
+ # def GC.start(full_mark: true, immediate_sweep: true); end
+ #
+ # Use full_mark: false to perform a minor \GC.
+ # Use immediate_sweep: false to defer sweeping (use lazy sweep).
+ #
+ # Note: These keyword arguments are implementation and version dependent. They
+ # are not guaranteed to be future-compatible, and may be ignored if the
+ # underlying implementation does not support them.
def self.start full_mark: true, immediate_mark: true, immediate_sweep: true
Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
end
- # Alias of GC.start
def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true
Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
end
@@ -124,14 +118,14 @@ module GC
# [time]
# The total time spent in garbage collections (in milliseconds)
# [heap_allocated_pages]
- # The total number of +:heap_eden_pages+ + +:heap_tomb_pages+
+ # The total number of `:heap_eden_pages` + `:heap_tomb_pages`
# [heap_sorted_length]
# The number of pages that can fit into the buffer that holds references to
# all pages
# [heap_allocatable_pages]
# The total number of pages the application could allocate without additional \GC
# [heap_available_slots]
- # The total number of slots in all +:heap_allocated_pages+
+ # The total number of slots in all `:heap_allocated_pages`
# [heap_live_slots]
# The total number of slots which contain live objects
# [heap_free_slots]
@@ -155,7 +149,7 @@ module GC
# [malloc_increase_bytes]
# Amount of memory allocated on the heap for objects. Decreased by any \GC
# [malloc_increase_bytes_limit]
- # When +:malloc_increase_bytes+ crosses this limit, \GC is triggered
+ # When `:malloc_increase_bytes` crosses this limit, \GC is triggered
# [minor_gc_count]
# The total number of minor garbage collections run since process start
# [major_gc_count]
@@ -170,16 +164,16 @@ module GC
# [remembered_wb_unprotected_objects]
# The total number of objects without write barriers
# [remembered_wb_unprotected_objects_limit]
- # When +:remembered_wb_unprotected_objects+ crosses this limit,
+ # When `:remembered_wb_unprotected_objects` crosses this limit,
# major \GC is triggered
# [old_objects]
# Number of live, old objects which have survived at least 3 garbage collections
# [old_objects_limit]
- # When +:old_objects+ crosses this limit, major \GC is triggered
+ # When `:old_objects` crosses this limit, major \GC is triggered
# [oldmalloc_increase_bytes]
# Amount of memory allocated on the heap for objects. Decreased by major \GC
# [oldmalloc_increase_bytes_limit]
- # When +:old_malloc_increase_bytes+ crosses this limit, major \GC is triggered
+ # When `:old_malloc_increase_bytes` crosses this limit, major \GC is triggered
#
# If the optional argument, hash, is given,
# it is overwritten and returned.
@@ -197,18 +191,19 @@ module GC
# GC.stat_heap(heap_name, hash) -> Hash
# GC.stat_heap(heap_name, :key) -> Numeric
#
- # Returns information for heaps in the \GC.
+ # Returns information for memory pools in the \GC.
#
# If the first optional argument, +heap_name+, is passed in and not +nil+, it
- # returns a +Hash+ containing information about the particular heap.
- # Otherwise, it will return a +Hash+ with heap names as keys and
- # a +Hash+ containing information about the heap as values.
+ # returns a +Hash+ containing information about the particular memory pool.
+ # Otherwise, it will return a +Hash+ with memory pool names as keys and
+ # a +Hash+ containing information about the memory pool as values.
#
# If the second optional argument, +hash_or_key+, is given as +Hash+, it will
# be overwritten and returned. This is intended to avoid the probe effect.
#
# If both optional arguments are passed in and the second optional argument is
- # a symbol, it will return a +Numeric+ of the value for the particular heap.
+ # a symbol, it will return a +Numeric+ of the value for the particular memory
+ # pool.
#
# On CRuby, +heap_name+ is of the type +Integer+ but may be of type +String+
# on other implementations.
@@ -219,120 +214,42 @@ module GC
# If the optional argument, hash, is given, it is overwritten and returned.
#
# This method is only expected to work on CRuby.
- #
- # The hash includes the following keys about the internal information in
- # the \GC:
- #
- # [slot_size]
- # The slot size of the heap in bytes.
- # [heap_allocatable_pages]
- # The number of pages that can be allocated without triggering a new
- # garbage collection cycle.
- # [heap_eden_pages]
- # The number of pages in the eden heap.
- # [heap_eden_slots]
- # The total number of slots in all of the pages in the eden heap.
- # [heap_tomb_pages]
- # The number of pages in the tomb heap. The tomb heap only contains pages
- # that do not have any live objects.
- # [heap_tomb_slots]
- # The total number of slots in all of the pages in the tomb heap.
- # [total_allocated_pages]
- # The total number of pages that have been allocated in the heap.
- # [total_freed_pages]
- # The total number of pages that have been freed and released back to the
- # system in the heap.
- # [force_major_gc_count]
- # The number of times major garbage collection cycles this heap has forced
- # to start due to running out of free slots.
- # [force_incremental_marking_finish_count]
- # The number of times this heap has forced incremental marking to complete
- # due to running out of pooled slots.
- #
def self.stat_heap heap_name = nil, hash_or_key = nil
Primitive.gc_stat_heap heap_name, hash_or_key
end
# call-seq:
- # GC.config -> hash
- # GC.config(hash) -> hash
- #
- # Sets or gets information about the current \GC config.
- #
- # Configuration parameters are \GC implementation specific and may change
- # without notice.
- #
- # This method can be called without parameters to retrieve the current config.
- #
- # This method can also be called with a +Hash+ argument to assign values to
- # valid config keys. Config keys missing from the passed +Hash+ will be left
- # unmodified.
- #
- # If a key/value pair is passed to this function that does not correspond to
- # a valid config key for the \GC implementation being used, no config will be
- # updated, the key will be present in the returned Hash, and it's value will
- # be +nil+. This is to facilitate easy migration between \GC implementations.
- #
- # In both call-seqs the return value of <code>GC.config</code> will be a +Hash+
- # containing the most recent full configuration. ie. All keys and values
- # defined by the specific \GC implementation being used. In the case of a
- # config update, the return value will include the new values being updated.
- #
- # This method is only expected to work on CRuby.
- #
- # Valid config keys for Ruby's default \GC implementation are:
- #
- # [rgengc_allow_full_mark]
- # Control whether the \GC is allowed to run a full mark (young & old objects).
- #
- # When +true+ \GC interleaves major and minor collections. This is default. \GC
- # will function as intended.
- #
- # When +false+, the \GC will never trigger a full marking cycle unless
- # explicitly requested by user code. Instead only a minor mark will run -
- # only young objects will be marked. When the heap space is exhausted, new
- # pages will be allocated immediately instead of running a full mark.
- #
- # A flag will be set to notify that a full mark has been
- # requested. This flag is accessible using
- # <code>GC.latest_gc_info(:needs_major_by)</code>
- #
- # The user can trigger a major collection at any time using
- # <code>GC.start(full_mark: true)</code>
- #
- # When +false+. Young to Old object promotion is disabled. For performance
- # reasons it is recommended to warmup an application using +Process.warmup+
- # before setting this parameter to +false+.
- def self.config hash = nil
- return Primitive.gc_config_get unless hash
-
- Primitive.gc_config_set hash
- end
-
- # call-seq:
# GC.latest_gc_info -> hash
# GC.latest_gc_info(hash) -> hash
- # GC.latest_gc_info(key) -> value
+ # GC.latest_gc_info(:major_by) -> :malloc
#
# Returns information about the most recent garbage collection.
#
- # If the argument +hash+ is given and is a Hash object,
+ # If the optional argument, hash, is given,
# it is overwritten and returned.
# This is intended to avoid probe effect.
- #
- # If the argument +key+ is given and is a Symbol object,
- # it returns the value associated with the key.
- # This is equivalent to <tt>GC.latest_gc_info[key]</tt>.
def self.latest_gc_info hash_or_key = nil
- if hash_or_key == nil
- hash_or_key = {}
- elsif Primitive.cexpr!("RBOOL(!SYMBOL_P(hash_or_key) && !RB_TYPE_P(hash_or_key, T_HASH))")
- raise TypeError, "non-hash or symbol given"
- end
+ Primitive.gc_latest_gc_info hash_or_key
+ end
- Primitive.cstmt! %{
- return rb_gc_latest_gc_info(hash_or_key);
- }
+ if respond_to?(:compact)
+ # call-seq:
+ # GC.verify_compaction_references(toward: nil, double_heap: false) -> hash
+ #
+ # Verify compaction reference consistency.
+ #
+ # This method is implementation specific. During compaction, objects that
+ # were moved are replaced with T_MOVED objects. No object should have a
+ # reference to a T_MOVED object after compaction.
+ #
+ # This function expands the heap to ensure room to move all objects,
+ # compacts the heap to make sure everything moves, updates all references,
+ # then performs a full \GC. If any object contains a reference to a T_MOVED
+ # object, that object should be pushed on the mark stack, and will
+ # make a SEGV.
+ def self.verify_compaction_references(toward: nil, double_heap: false, expand_heap: false)
+ Primitive.gc_verify_compaction_references(double_heap, expand_heap, toward == :empty)
+ end
end
# call-seq:
@@ -343,7 +260,7 @@ module GC
# Note that \GC time measurement can cause some performance overhead.
def self.measure_total_time=(flag)
Primitive.cstmt! %{
- rb_gc_impl_set_measure_total_time(rb_gc_get_objspace(), flag);
+ rb_objspace.flags.measure_gc = RTEST(flag) ? TRUE : FALSE;
return flag;
}
end
@@ -355,7 +272,7 @@ module GC
# Note that measurement can affect the application performance.
def self.measure_total_time
Primitive.cexpr! %{
- RBOOL(rb_gc_impl_get_measure_total_time(rb_gc_get_objspace()))
+ RBOOL(rb_objspace.flags.measure_gc)
}
end
@@ -365,13 +282,12 @@ module GC
# Return measured \GC total time in nano seconds.
def self.total_time
Primitive.cexpr! %{
- ULL2NUM(rb_gc_impl_get_total_time(rb_gc_get_objspace()))
+ ULL2NUM(rb_objspace.profile.total_time_ns)
}
end
end
module ObjectSpace
- # Alias of GC.start
def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true
Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
end
diff --git a/gc/default.c b/gc/default.c
deleted file mode 100644
index 237f822fb5..0000000000
--- a/gc/default.c
+++ /dev/null
@@ -1,9424 +0,0 @@
-#include "ruby/internal/config.h"
-
-#include <signal.h>
-
-#ifndef _WIN32
-# include <sys/mman.h>
-# include <unistd.h>
-#endif
-
-#if !defined(PAGE_SIZE) && defined(HAVE_SYS_USER_H)
-/* LIST_HEAD conflicts with sys/queue.h on macOS */
-# include <sys/user.h>
-#endif
-
-#include "internal/hash.h"
-
-#include "ruby/ruby.h"
-#include "ruby/atomic.h"
-#include "ruby/debug.h"
-#include "ruby/thread.h"
-#include "ruby/util.h"
-#include "ruby/vm.h"
-#include "ruby/internal/encoding/string.h"
-#include "ccan/list/list.h"
-#include "darray.h"
-#include "gc/gc.h"
-#include "gc/gc_impl.h"
-
-#ifndef BUILDING_SHARED_GC
-# include "probes.h"
-#endif
-
-#include "debug_counter.h"
-#include "internal/sanitizers.h"
-
-/* MALLOC_HEADERS_BEGIN */
-#ifndef HAVE_MALLOC_USABLE_SIZE
-# ifdef _WIN32
-# define HAVE_MALLOC_USABLE_SIZE
-# define malloc_usable_size(a) _msize(a)
-# elif defined HAVE_MALLOC_SIZE
-# define HAVE_MALLOC_USABLE_SIZE
-# define malloc_usable_size(a) malloc_size(a)
-# endif
-#endif
-
-#ifdef HAVE_MALLOC_USABLE_SIZE
-# ifdef RUBY_ALTERNATIVE_MALLOC_HEADER
-/* Alternative malloc header is included in ruby/missing.h */
-# elif defined(HAVE_MALLOC_H)
-# include <malloc.h>
-# elif defined(HAVE_MALLOC_NP_H)
-# include <malloc_np.h>
-# elif defined(HAVE_MALLOC_MALLOC_H)
-# include <malloc/malloc.h>
-# endif
-#endif
-
-#ifdef HAVE_MALLOC_TRIM
-# include <malloc.h>
-
-# ifdef __EMSCRIPTEN__
-/* malloc_trim is defined in emscripten/emmalloc.h on emscripten. */
-# include <emscripten/emmalloc.h>
-# endif
-#endif
-
-#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS
-# include <mach/task.h>
-# include <mach/mach_init.h>
-# include <mach/mach_port.h>
-#endif
-
-#ifndef VM_CHECK_MODE
-# define VM_CHECK_MODE RUBY_DEBUG
-#endif
-
-// From ractor_core.h
-#ifndef RACTOR_CHECK_MODE
-# define RACTOR_CHECK_MODE (VM_CHECK_MODE || RUBY_DEBUG) && (SIZEOF_UINT64_T == SIZEOF_VALUE)
-#endif
-
-#ifndef RUBY_DEBUG_LOG
-# define RUBY_DEBUG_LOG(...)
-#endif
-
-#ifndef GC_HEAP_INIT_SLOTS
-#define GC_HEAP_INIT_SLOTS 10000
-#endif
-#ifndef GC_HEAP_FREE_SLOTS
-#define GC_HEAP_FREE_SLOTS 4096
-#endif
-#ifndef GC_HEAP_GROWTH_FACTOR
-#define GC_HEAP_GROWTH_FACTOR 1.8
-#endif
-#ifndef GC_HEAP_GROWTH_MAX_SLOTS
-#define GC_HEAP_GROWTH_MAX_SLOTS 0 /* 0 is disable */
-#endif
-#ifndef GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO
-# define GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO 0.01
-#endif
-#ifndef GC_HEAP_OLDOBJECT_LIMIT_FACTOR
-#define GC_HEAP_OLDOBJECT_LIMIT_FACTOR 2.0
-#endif
-
-#ifndef GC_HEAP_FREE_SLOTS_MIN_RATIO
-#define GC_HEAP_FREE_SLOTS_MIN_RATIO 0.20
-#endif
-#ifndef GC_HEAP_FREE_SLOTS_GOAL_RATIO
-#define GC_HEAP_FREE_SLOTS_GOAL_RATIO 0.40
-#endif
-#ifndef GC_HEAP_FREE_SLOTS_MAX_RATIO
-#define GC_HEAP_FREE_SLOTS_MAX_RATIO 0.65
-#endif
-
-#ifndef GC_MALLOC_LIMIT_MIN
-#define GC_MALLOC_LIMIT_MIN (16 * 1024 * 1024 /* 16MB */)
-#endif
-#ifndef GC_MALLOC_LIMIT_MAX
-#define GC_MALLOC_LIMIT_MAX (32 * 1024 * 1024 /* 32MB */)
-#endif
-#ifndef GC_MALLOC_LIMIT_GROWTH_FACTOR
-#define GC_MALLOC_LIMIT_GROWTH_FACTOR 1.4
-#endif
-
-#ifndef GC_OLDMALLOC_LIMIT_MIN
-#define GC_OLDMALLOC_LIMIT_MIN (16 * 1024 * 1024 /* 16MB */)
-#endif
-#ifndef GC_OLDMALLOC_LIMIT_GROWTH_FACTOR
-#define GC_OLDMALLOC_LIMIT_GROWTH_FACTOR 1.2
-#endif
-#ifndef GC_OLDMALLOC_LIMIT_MAX
-#define GC_OLDMALLOC_LIMIT_MAX (128 * 1024 * 1024 /* 128MB */)
-#endif
-
-#ifndef GC_CAN_COMPILE_COMPACTION
-#if defined(__wasi__) /* WebAssembly doesn't support signals */
-# define GC_CAN_COMPILE_COMPACTION 0
-#else
-# define GC_CAN_COMPILE_COMPACTION 1
-#endif
-#endif
-
-#ifndef PRINT_ENTER_EXIT_TICK
-# define PRINT_ENTER_EXIT_TICK 0
-#endif
-#ifndef PRINT_ROOT_TICKS
-#define PRINT_ROOT_TICKS 0
-#endif
-
-#define USE_TICK_T (PRINT_ENTER_EXIT_TICK || PRINT_ROOT_TICKS)
-
-#ifndef HEAP_COUNT
-# define HEAP_COUNT 5
-#endif
-
-typedef struct ractor_newobj_heap_cache {
- struct free_slot *freelist;
- struct heap_page *using_page;
-} rb_ractor_newobj_heap_cache_t;
-
-typedef struct ractor_newobj_cache {
- size_t incremental_mark_step_allocated_slots;
- rb_ractor_newobj_heap_cache_t heap_caches[HEAP_COUNT];
-} rb_ractor_newobj_cache_t;
-
-typedef struct {
- size_t heap_init_slots[HEAP_COUNT];
- size_t heap_free_slots;
- double growth_factor;
- size_t growth_max_slots;
-
- double heap_free_slots_min_ratio;
- double heap_free_slots_goal_ratio;
- double heap_free_slots_max_ratio;
- double uncollectible_wb_unprotected_objects_limit_ratio;
- double oldobject_limit_factor;
-
- size_t malloc_limit_min;
- size_t malloc_limit_max;
- double malloc_limit_growth_factor;
-
- size_t oldmalloc_limit_min;
- size_t oldmalloc_limit_max;
- double oldmalloc_limit_growth_factor;
-} ruby_gc_params_t;
-
-static ruby_gc_params_t gc_params = {
- { GC_HEAP_INIT_SLOTS },
- GC_HEAP_FREE_SLOTS,
- GC_HEAP_GROWTH_FACTOR,
- GC_HEAP_GROWTH_MAX_SLOTS,
-
- GC_HEAP_FREE_SLOTS_MIN_RATIO,
- GC_HEAP_FREE_SLOTS_GOAL_RATIO,
- GC_HEAP_FREE_SLOTS_MAX_RATIO,
- GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO,
- GC_HEAP_OLDOBJECT_LIMIT_FACTOR,
-
- GC_MALLOC_LIMIT_MIN,
- GC_MALLOC_LIMIT_MAX,
- GC_MALLOC_LIMIT_GROWTH_FACTOR,
-
- GC_OLDMALLOC_LIMIT_MIN,
- GC_OLDMALLOC_LIMIT_MAX,
- GC_OLDMALLOC_LIMIT_GROWTH_FACTOR,
-};
-
-/* GC_DEBUG:
- * enable to embed GC debugging information.
- */
-#ifndef GC_DEBUG
-#define GC_DEBUG 0
-#endif
-
-/* RGENGC_DEBUG:
- * 1: basic information
- * 2: remember set operation
- * 3: mark
- * 4:
- * 5: sweep
- */
-#ifndef RGENGC_DEBUG
-#ifdef RUBY_DEVEL
-#define RGENGC_DEBUG -1
-#else
-#define RGENGC_DEBUG 0
-#endif
-#endif
-#if RGENGC_DEBUG < 0 && !defined(_MSC_VER)
-# define RGENGC_DEBUG_ENABLED(level) (-(RGENGC_DEBUG) >= (level) && ruby_rgengc_debug >= (level))
-#elif defined(HAVE_VA_ARGS_MACRO)
-# define RGENGC_DEBUG_ENABLED(level) ((RGENGC_DEBUG) >= (level))
-#else
-# define RGENGC_DEBUG_ENABLED(level) 0
-#endif
-int ruby_rgengc_debug;
-
-/* RGENGC_PROFILE
- * 0: disable RGenGC profiling
- * 1: enable profiling for basic information
- * 2: enable profiling for each types
- */
-#ifndef RGENGC_PROFILE
-# define RGENGC_PROFILE 0
-#endif
-
-/* RGENGC_ESTIMATE_OLDMALLOC
- * Enable/disable to estimate increase size of malloc'ed size by old objects.
- * If estimation exceeds threshold, then will invoke full GC.
- * 0: disable estimation.
- * 1: enable estimation.
- */
-#ifndef RGENGC_ESTIMATE_OLDMALLOC
-# define RGENGC_ESTIMATE_OLDMALLOC 1
-#endif
-
-/* RGENGC_FORCE_MAJOR_GC
- * Force major/full GC if this macro is not 0.
- */
-#ifndef RGENGC_FORCE_MAJOR_GC
-# define RGENGC_FORCE_MAJOR_GC 0
-#endif
-
-#ifndef GC_PROFILE_MORE_DETAIL
-# define GC_PROFILE_MORE_DETAIL 0
-#endif
-#ifndef GC_PROFILE_DETAIL_MEMORY
-# define GC_PROFILE_DETAIL_MEMORY 0
-#endif
-#ifndef GC_ENABLE_LAZY_SWEEP
-# define GC_ENABLE_LAZY_SWEEP 1
-#endif
-#ifndef CALC_EXACT_MALLOC_SIZE
-# define CALC_EXACT_MALLOC_SIZE 0
-#endif
-#if defined(HAVE_MALLOC_USABLE_SIZE) || CALC_EXACT_MALLOC_SIZE > 0
-# ifndef MALLOC_ALLOCATED_SIZE
-# define MALLOC_ALLOCATED_SIZE 0
-# endif
-#else
-# define MALLOC_ALLOCATED_SIZE 0
-#endif
-#ifndef MALLOC_ALLOCATED_SIZE_CHECK
-# define MALLOC_ALLOCATED_SIZE_CHECK 0
-#endif
-
-#ifndef GC_DEBUG_STRESS_TO_CLASS
-# define GC_DEBUG_STRESS_TO_CLASS RUBY_DEBUG
-#endif
-
-typedef enum {
- GPR_FLAG_NONE = 0x000,
- /* major reason */
- GPR_FLAG_MAJOR_BY_NOFREE = 0x001,
- GPR_FLAG_MAJOR_BY_OLDGEN = 0x002,
- GPR_FLAG_MAJOR_BY_SHADY = 0x004,
- GPR_FLAG_MAJOR_BY_FORCE = 0x008,
-#if RGENGC_ESTIMATE_OLDMALLOC
- GPR_FLAG_MAJOR_BY_OLDMALLOC = 0x020,
-#endif
- GPR_FLAG_MAJOR_MASK = 0x0ff,
-
- /* gc reason */
- GPR_FLAG_NEWOBJ = 0x100,
- GPR_FLAG_MALLOC = 0x200,
- GPR_FLAG_METHOD = 0x400,
- GPR_FLAG_CAPI = 0x800,
- GPR_FLAG_STRESS = 0x1000,
-
- /* others */
- GPR_FLAG_IMMEDIATE_SWEEP = 0x2000,
- GPR_FLAG_HAVE_FINALIZE = 0x4000,
- GPR_FLAG_IMMEDIATE_MARK = 0x8000,
- GPR_FLAG_FULL_MARK = 0x10000,
- GPR_FLAG_COMPACT = 0x20000,
-
- GPR_DEFAULT_REASON =
- (GPR_FLAG_FULL_MARK | GPR_FLAG_IMMEDIATE_MARK |
- GPR_FLAG_IMMEDIATE_SWEEP | GPR_FLAG_CAPI),
-} gc_profile_record_flag;
-
-typedef struct gc_profile_record {
- unsigned int flags;
-
- double gc_time;
- double gc_invoke_time;
-
- size_t heap_total_objects;
- size_t heap_use_size;
- size_t heap_total_size;
- size_t moved_objects;
-
-#if GC_PROFILE_MORE_DETAIL
- double gc_mark_time;
- double gc_sweep_time;
-
- size_t heap_use_pages;
- size_t heap_live_objects;
- size_t heap_free_objects;
-
- size_t allocate_increase;
- size_t allocate_limit;
-
- double prepare_time;
- size_t removing_objects;
- size_t empty_objects;
-#if GC_PROFILE_DETAIL_MEMORY
- long maxrss;
- long minflt;
- long majflt;
-#endif
-#endif
-#if MALLOC_ALLOCATED_SIZE
- size_t allocated_size;
-#endif
-
-#if RGENGC_PROFILE > 0
- size_t old_objects;
- size_t remembered_normal_objects;
- size_t remembered_shady_objects;
-#endif
-} gc_profile_record;
-
-struct RMoved {
- VALUE flags;
- VALUE dummy;
- VALUE destination;
- uint32_t original_shape_id;
-};
-
-#define RMOVED(obj) ((struct RMoved *)(obj))
-
-typedef uintptr_t bits_t;
-enum {
- BITS_SIZE = sizeof(bits_t),
- BITS_BITLENGTH = ( BITS_SIZE * CHAR_BIT )
-};
-
-struct heap_page_header {
- struct heap_page *page;
-};
-
-struct heap_page_body {
- struct heap_page_header header;
- /* char gap[]; */
- /* RVALUE values[]; */
-};
-
-#define STACK_CHUNK_SIZE 500
-
-typedef struct stack_chunk {
- VALUE data[STACK_CHUNK_SIZE];
- struct stack_chunk *next;
-} stack_chunk_t;
-
-typedef struct mark_stack {
- stack_chunk_t *chunk;
- stack_chunk_t *cache;
- int index;
- int limit;
- size_t cache_size;
- size_t unused_cache_size;
-} mark_stack_t;
-
-typedef int (*gc_compact_compare_func)(const void *l, const void *r, void *d);
-
-typedef struct rb_heap_struct {
- short slot_size;
-
- /* Basic statistics */
- size_t total_allocated_pages;
- size_t force_major_gc_count;
- size_t force_incremental_marking_finish_count;
- size_t total_allocated_objects;
- size_t total_freed_objects;
- size_t final_slots_count;
-
- /* Sweeping statistics */
- size_t freed_slots;
- size_t empty_slots;
-
- struct heap_page *free_pages;
- struct ccan_list_head pages;
- struct heap_page *sweeping_page; /* iterator for .pages */
- struct heap_page *compact_cursor;
- uintptr_t compact_cursor_index;
- struct heap_page *pooled_pages;
- size_t total_pages; /* total page count in a heap */
- size_t total_slots; /* total slot count (about total_pages * HEAP_PAGE_OBJ_LIMIT) */
-
-} rb_heap_t;
-
-enum {
- gc_stress_no_major,
- gc_stress_no_immediate_sweep,
- gc_stress_full_mark_after_malloc,
- gc_stress_max
-};
-
-enum gc_mode {
- gc_mode_none,
- gc_mode_marking,
- gc_mode_sweeping,
- gc_mode_compacting,
-};
-
-typedef struct rb_objspace {
- struct {
- size_t limit;
- size_t increase;
-#if MALLOC_ALLOCATED_SIZE
- size_t allocated_size;
- size_t allocations;
-#endif
- } malloc_params;
-
- struct rb_gc_config {
- bool full_mark;
- } gc_config;
-
- struct {
- unsigned int mode : 2;
- unsigned int immediate_sweep : 1;
- unsigned int dont_gc : 1;
- unsigned int dont_incremental : 1;
- unsigned int during_gc : 1;
- unsigned int during_compacting : 1;
- unsigned int during_reference_updating : 1;
- unsigned int gc_stressful: 1;
- unsigned int has_newobj_hook: 1;
- unsigned int during_minor_gc : 1;
- unsigned int during_incremental_marking : 1;
- unsigned int measure_gc : 1;
- } flags;
-
- rb_event_flag_t hook_events;
- unsigned long long next_object_id;
-
- rb_heap_t heaps[HEAP_COUNT];
- size_t empty_pages_count;
- struct heap_page *empty_pages;
-
- struct {
- rb_atomic_t finalizing;
- } atomic_flags;
-
- mark_stack_t mark_stack;
- size_t marked_slots;
-
- struct {
- rb_darray(struct heap_page *) sorted;
-
- size_t allocated_pages;
- size_t freed_pages;
- uintptr_t range[2];
- size_t freeable_pages;
-
- size_t allocatable_slots;
-
- /* final */
- VALUE deferred_final;
- } heap_pages;
-
- st_table *finalizer_table;
-
- struct {
- int run;
- unsigned int latest_gc_info;
- gc_profile_record *records;
- gc_profile_record *current_record;
- size_t next_index;
- size_t size;
-
-#if GC_PROFILE_MORE_DETAIL
- double prepare_time;
-#endif
- double invoke_time;
-
- size_t minor_gc_count;
- size_t major_gc_count;
- size_t compact_count;
- size_t read_barrier_faults;
-#if RGENGC_PROFILE > 0
- size_t total_generated_normal_object_count;
- size_t total_generated_shady_object_count;
- size_t total_shade_operation_count;
- size_t total_promoted_count;
- size_t total_remembered_normal_object_count;
- size_t total_remembered_shady_object_count;
-
-#if RGENGC_PROFILE >= 2
- size_t generated_normal_object_count_types[RUBY_T_MASK];
- size_t generated_shady_object_count_types[RUBY_T_MASK];
- size_t shade_operation_count_types[RUBY_T_MASK];
- size_t promoted_types[RUBY_T_MASK];
- size_t remembered_normal_object_count_types[RUBY_T_MASK];
- size_t remembered_shady_object_count_types[RUBY_T_MASK];
-#endif
-#endif /* RGENGC_PROFILE */
-
- /* temporary profiling space */
- double gc_sweep_start_time;
- size_t total_allocated_objects_at_gc_start;
- size_t heap_used_at_gc_start;
-
- /* basic statistics */
- size_t count;
- unsigned long long marking_time_ns;
- struct timespec marking_start_time;
- unsigned long long sweeping_time_ns;
- struct timespec sweeping_start_time;
-
- /* Weak references */
- size_t weak_references_count;
- size_t retained_weak_references_count;
- } profile;
-
- VALUE gc_stress_mode;
-
- struct {
- VALUE parent_object;
- int need_major_gc;
- size_t last_major_gc;
- size_t uncollectible_wb_unprotected_objects;
- size_t uncollectible_wb_unprotected_objects_limit;
- size_t old_objects;
- size_t old_objects_limit;
-
-#if RGENGC_ESTIMATE_OLDMALLOC
- size_t oldmalloc_increase;
- size_t oldmalloc_increase_limit;
-#endif
-
-#if RGENGC_CHECK_MODE >= 2
- struct st_table *allrefs_table;
- size_t error_count;
-#endif
- } rgengc;
-
- struct {
- size_t considered_count_table[T_MASK];
- size_t moved_count_table[T_MASK];
- size_t moved_up_count_table[T_MASK];
- size_t moved_down_count_table[T_MASK];
- size_t total_moved;
-
- /* This function will be used, if set, to sort the heap prior to compaction */
- gc_compact_compare_func compare_func;
- } rcompactor;
-
- struct {
- size_t pooled_slots;
- size_t step_slots;
- } rincgc;
-
- st_table *id_to_obj_tbl;
- st_table *obj_to_id_tbl;
-
-#if GC_DEBUG_STRESS_TO_CLASS
- VALUE stress_to_class;
-#endif
-
- rb_darray(VALUE *) weak_references;
- rb_postponed_job_handle_t finalize_deferred_pjob;
-
- unsigned long live_ractor_cache_count;
-} rb_objspace_t;
-
-#ifndef HEAP_PAGE_ALIGN_LOG
-/* default tiny heap size: 64KiB */
-#define HEAP_PAGE_ALIGN_LOG 16
-#endif
-
-#if RACTOR_CHECK_MODE || GC_DEBUG
-struct rvalue_overhead {
-# if RACTOR_CHECK_MODE
- uint32_t _ractor_belonging_id;
-# endif
-# if GC_DEBUG
- const char *file;
- int line;
-# endif
-};
-
-// Make sure that RVALUE_OVERHEAD aligns to sizeof(VALUE)
-# define RVALUE_OVERHEAD (sizeof(struct { \
- union { \
- struct rvalue_overhead overhead; \
- VALUE value; \
- }; \
-}))
-size_t rb_gc_impl_obj_slot_size(VALUE obj);
-# define GET_RVALUE_OVERHEAD(obj) ((struct rvalue_overhead *)((uintptr_t)obj + rb_gc_impl_obj_slot_size(obj)))
-#else
-# define RVALUE_OVERHEAD 0
-#endif
-
-#define BASE_SLOT_SIZE (sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX]) + RVALUE_OVERHEAD)
-
-#ifndef MAX
-# define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-#ifndef MIN
-# define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-#define roomof(x, y) (((x) + (y) - 1) / (y))
-#define CEILDIV(i, mod) roomof(i, mod)
-enum {
- HEAP_PAGE_ALIGN = (1UL << HEAP_PAGE_ALIGN_LOG),
- HEAP_PAGE_ALIGN_MASK = (~(~0UL << HEAP_PAGE_ALIGN_LOG)),
- HEAP_PAGE_SIZE = HEAP_PAGE_ALIGN,
- HEAP_PAGE_OBJ_LIMIT = (unsigned int)((HEAP_PAGE_SIZE - sizeof(struct heap_page_header)) / BASE_SLOT_SIZE),
- HEAP_PAGE_BITMAP_LIMIT = CEILDIV(CEILDIV(HEAP_PAGE_SIZE, BASE_SLOT_SIZE), BITS_BITLENGTH),
- HEAP_PAGE_BITMAP_SIZE = (BITS_SIZE * HEAP_PAGE_BITMAP_LIMIT),
-};
-#define HEAP_PAGE_ALIGN (1 << HEAP_PAGE_ALIGN_LOG)
-#define HEAP_PAGE_SIZE HEAP_PAGE_ALIGN
-
-#if !defined(INCREMENTAL_MARK_STEP_ALLOCATIONS)
-# define INCREMENTAL_MARK_STEP_ALLOCATIONS 500
-#endif
-
-#undef INIT_HEAP_PAGE_ALLOC_USE_MMAP
-/* Must define either HEAP_PAGE_ALLOC_USE_MMAP or
- * INIT_HEAP_PAGE_ALLOC_USE_MMAP. */
-
-#ifndef HAVE_MMAP
-/* We can't use mmap of course, if it is not available. */
-static const bool HEAP_PAGE_ALLOC_USE_MMAP = false;
-
-#elif defined(__wasm__)
-/* wasmtime does not have proper support for mmap.
- * See https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-rationale.md#why-no-mmap-and-friends
- */
-static const bool HEAP_PAGE_ALLOC_USE_MMAP = false;
-
-#elif HAVE_CONST_PAGE_SIZE
-/* If we have the PAGE_SIZE and it is a constant, then we can directly use it. */
-static const bool HEAP_PAGE_ALLOC_USE_MMAP = (PAGE_SIZE <= HEAP_PAGE_SIZE);
-
-#elif defined(PAGE_MAX_SIZE) && (PAGE_MAX_SIZE <= HEAP_PAGE_SIZE)
-/* If we can use the maximum page size. */
-static const bool HEAP_PAGE_ALLOC_USE_MMAP = true;
-
-#elif defined(PAGE_SIZE)
-/* If the PAGE_SIZE macro can be used dynamically. */
-# define INIT_HEAP_PAGE_ALLOC_USE_MMAP (PAGE_SIZE <= HEAP_PAGE_SIZE)
-
-#elif defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
-/* If we can use sysconf to determine the page size. */
-# define INIT_HEAP_PAGE_ALLOC_USE_MMAP (sysconf(_SC_PAGE_SIZE) <= HEAP_PAGE_SIZE)
-
-#else
-/* Otherwise we can't determine the system page size, so don't use mmap. */
-static const bool HEAP_PAGE_ALLOC_USE_MMAP = false;
-#endif
-
-#ifdef INIT_HEAP_PAGE_ALLOC_USE_MMAP
-/* We can determine the system page size at runtime. */
-# define HEAP_PAGE_ALLOC_USE_MMAP (heap_page_alloc_use_mmap != false)
-
-static bool heap_page_alloc_use_mmap;
-#endif
-
-#define RVALUE_AGE_BIT_COUNT 2
-#define RVALUE_AGE_BIT_MASK (((bits_t)1 << RVALUE_AGE_BIT_COUNT) - 1)
-#define RVALUE_OLD_AGE 3
-
-struct free_slot {
- VALUE flags; /* always 0 for freed obj */
- struct free_slot *next;
-};
-
-struct heap_page {
- unsigned short slot_size;
- unsigned short total_slots;
- unsigned short free_slots;
- unsigned short final_slots;
- unsigned short pinned_slots;
- struct {
- unsigned int before_sweep : 1;
- unsigned int has_remembered_objects : 1;
- unsigned int has_uncollectible_wb_unprotected_objects : 1;
- } flags;
-
- rb_heap_t *heap;
-
- struct heap_page *free_next;
- struct heap_page_body *body;
- uintptr_t start;
- struct free_slot *freelist;
- struct ccan_list_node page_node;
-
- bits_t wb_unprotected_bits[HEAP_PAGE_BITMAP_LIMIT];
- /* the following three bitmaps are cleared at the beginning of full GC */
- bits_t mark_bits[HEAP_PAGE_BITMAP_LIMIT];
- bits_t uncollectible_bits[HEAP_PAGE_BITMAP_LIMIT];
- bits_t marking_bits[HEAP_PAGE_BITMAP_LIMIT];
-
- bits_t remembered_bits[HEAP_PAGE_BITMAP_LIMIT];
-
- /* If set, the object is not movable */
- bits_t pinned_bits[HEAP_PAGE_BITMAP_LIMIT];
- bits_t age_bits[HEAP_PAGE_BITMAP_LIMIT * RVALUE_AGE_BIT_COUNT];
-};
-
-/*
- * When asan is enabled, this will prohibit writing to the freelist until it is unlocked
- */
-static void
-asan_lock_freelist(struct heap_page *page)
-{
- asan_poison_memory_region(&page->freelist, sizeof(struct free_list *));
-}
-
-/*
- * When asan is enabled, this will enable the ability to write to the freelist
- */
-static void
-asan_unlock_freelist(struct heap_page *page)
-{
- asan_unpoison_memory_region(&page->freelist, sizeof(struct free_list *), false);
-}
-
-static inline bool
-heap_page_in_global_empty_pages_pool(rb_objspace_t *objspace, struct heap_page *page)
-{
- if (page->total_slots == 0) {
- GC_ASSERT(page->start == 0);
- GC_ASSERT(page->slot_size == 0);
- GC_ASSERT(page->heap == NULL);
- GC_ASSERT(page->free_slots == 0);
- asan_unpoisoning_memory_region(&page->freelist, sizeof(&page->freelist)) {
- GC_ASSERT(page->freelist == NULL);
- }
-
- return true;
- }
- else {
- GC_ASSERT(page->start != 0);
- GC_ASSERT(page->slot_size != 0);
- GC_ASSERT(page->heap != NULL);
-
- return false;
- }
-}
-
-#define GET_PAGE_BODY(x) ((struct heap_page_body *)((bits_t)(x) & ~(HEAP_PAGE_ALIGN_MASK)))
-#define GET_PAGE_HEADER(x) (&GET_PAGE_BODY(x)->header)
-#define GET_HEAP_PAGE(x) (GET_PAGE_HEADER(x)->page)
-
-#define NUM_IN_PAGE(p) (((bits_t)(p) & HEAP_PAGE_ALIGN_MASK) / BASE_SLOT_SIZE)
-#define BITMAP_INDEX(p) (NUM_IN_PAGE(p) / BITS_BITLENGTH )
-#define BITMAP_OFFSET(p) (NUM_IN_PAGE(p) & (BITS_BITLENGTH-1))
-#define BITMAP_BIT(p) ((bits_t)1 << BITMAP_OFFSET(p))
-
-/* Bitmap Operations */
-#define MARKED_IN_BITMAP(bits, p) ((bits)[BITMAP_INDEX(p)] & BITMAP_BIT(p))
-#define MARK_IN_BITMAP(bits, p) ((bits)[BITMAP_INDEX(p)] = (bits)[BITMAP_INDEX(p)] | BITMAP_BIT(p))
-#define CLEAR_IN_BITMAP(bits, p) ((bits)[BITMAP_INDEX(p)] = (bits)[BITMAP_INDEX(p)] & ~BITMAP_BIT(p))
-
-/* getting bitmap */
-#define GET_HEAP_MARK_BITS(x) (&GET_HEAP_PAGE(x)->mark_bits[0])
-#define GET_HEAP_PINNED_BITS(x) (&GET_HEAP_PAGE(x)->pinned_bits[0])
-#define GET_HEAP_UNCOLLECTIBLE_BITS(x) (&GET_HEAP_PAGE(x)->uncollectible_bits[0])
-#define GET_HEAP_WB_UNPROTECTED_BITS(x) (&GET_HEAP_PAGE(x)->wb_unprotected_bits[0])
-#define GET_HEAP_MARKING_BITS(x) (&GET_HEAP_PAGE(x)->marking_bits[0])
-
-#define GC_SWEEP_PAGES_FREEABLE_PER_STEP 3
-
-#define RVALUE_AGE_BITMAP_INDEX(n) (NUM_IN_PAGE(n) / (BITS_BITLENGTH / RVALUE_AGE_BIT_COUNT))
-#define RVALUE_AGE_BITMAP_OFFSET(n) ((NUM_IN_PAGE(n) % (BITS_BITLENGTH / RVALUE_AGE_BIT_COUNT)) * RVALUE_AGE_BIT_COUNT)
-
-static int
-RVALUE_AGE_GET(VALUE obj)
-{
- bits_t *age_bits = GET_HEAP_PAGE(obj)->age_bits;
- return (int)(age_bits[RVALUE_AGE_BITMAP_INDEX(obj)] >> RVALUE_AGE_BITMAP_OFFSET(obj)) & RVALUE_AGE_BIT_MASK;
-}
-
-static void
-RVALUE_AGE_SET(VALUE obj, int age)
-{
- RUBY_ASSERT(age <= RVALUE_OLD_AGE);
- bits_t *age_bits = GET_HEAP_PAGE(obj)->age_bits;
- // clear the bits
- age_bits[RVALUE_AGE_BITMAP_INDEX(obj)] &= ~(RVALUE_AGE_BIT_MASK << (RVALUE_AGE_BITMAP_OFFSET(obj)));
- // shift the correct value in
- age_bits[RVALUE_AGE_BITMAP_INDEX(obj)] |= ((bits_t)age << RVALUE_AGE_BITMAP_OFFSET(obj));
- if (age == RVALUE_OLD_AGE) {
- RB_FL_SET_RAW(obj, RUBY_FL_PROMOTED);
- }
- else {
- RB_FL_UNSET_RAW(obj, RUBY_FL_PROMOTED);
- }
-}
-
-#define malloc_limit objspace->malloc_params.limit
-#define malloc_increase objspace->malloc_params.increase
-#define malloc_allocated_size objspace->malloc_params.allocated_size
-#define heap_pages_lomem objspace->heap_pages.range[0]
-#define heap_pages_himem objspace->heap_pages.range[1]
-#define heap_pages_freeable_pages objspace->heap_pages.freeable_pages
-#define heap_pages_deferred_final objspace->heap_pages.deferred_final
-#define heaps objspace->heaps
-#define during_gc objspace->flags.during_gc
-#define finalizing objspace->atomic_flags.finalizing
-#define finalizer_table objspace->finalizer_table
-#define ruby_gc_stressful objspace->flags.gc_stressful
-#define ruby_gc_stress_mode objspace->gc_stress_mode
-#if GC_DEBUG_STRESS_TO_CLASS
-#define stress_to_class objspace->stress_to_class
-#define set_stress_to_class(c) (stress_to_class = (c))
-#else
-#define stress_to_class (objspace, 0)
-#define set_stress_to_class(c) (objspace, (c))
-#endif
-
-#if 0
-#define dont_gc_on() (fprintf(stderr, "dont_gc_on@%s:%d\n", __FILE__, __LINE__), objspace->flags.dont_gc = 1)
-#define dont_gc_off() (fprintf(stderr, "dont_gc_off@%s:%d\n", __FILE__, __LINE__), objspace->flags.dont_gc = 0)
-#define dont_gc_set(b) (fprintf(stderr, "dont_gc_set(%d)@%s:%d\n", __FILE__, __LINE__), objspace->flags.dont_gc = (int)(b))
-#define dont_gc_val() (objspace->flags.dont_gc)
-#else
-#define dont_gc_on() (objspace->flags.dont_gc = 1)
-#define dont_gc_off() (objspace->flags.dont_gc = 0)
-#define dont_gc_set(b) (objspace->flags.dont_gc = (int)(b))
-#define dont_gc_val() (objspace->flags.dont_gc)
-#endif
-
-#define gc_config_full_mark_set(b) (objspace->gc_config.full_mark = (int)(b))
-#define gc_config_full_mark_val (objspace->gc_config.full_mark)
-
-#ifndef DURING_GC_COULD_MALLOC_REGION_START
-# define DURING_GC_COULD_MALLOC_REGION_START() \
- assert(rb_during_gc()); \
- bool _prev_enabled = rb_gc_impl_gc_enabled_p(objspace); \
- rb_gc_impl_gc_disable(objspace, false)
-#endif
-
-#ifndef DURING_GC_COULD_MALLOC_REGION_END
-# define DURING_GC_COULD_MALLOC_REGION_END() \
- if (_prev_enabled) rb_gc_impl_gc_enable(objspace)
-#endif
-
-static inline enum gc_mode
-gc_mode_verify(enum gc_mode mode)
-{
-#if RGENGC_CHECK_MODE > 0
- switch (mode) {
- case gc_mode_none:
- case gc_mode_marking:
- case gc_mode_sweeping:
- case gc_mode_compacting:
- break;
- default:
- rb_bug("gc_mode_verify: unreachable (%d)", (int)mode);
- }
-#endif
- return mode;
-}
-
-static inline bool
-has_sweeping_pages(rb_objspace_t *objspace)
-{
- for (int i = 0; i < HEAP_COUNT; i++) {
- if ((&heaps[i])->sweeping_page) {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-static inline size_t
-heap_eden_total_pages(rb_objspace_t *objspace)
-{
- size_t count = 0;
- for (int i = 0; i < HEAP_COUNT; i++) {
- count += (&heaps[i])->total_pages;
- }
- return count;
-}
-
-static inline size_t
-total_allocated_objects(rb_objspace_t *objspace)
-{
- size_t count = 0;
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- count += heap->total_allocated_objects;
- }
- return count;
-}
-
-static inline size_t
-total_freed_objects(rb_objspace_t *objspace)
-{
- size_t count = 0;
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- count += heap->total_freed_objects;
- }
- return count;
-}
-
-static inline size_t
-total_final_slots_count(rb_objspace_t *objspace)
-{
- size_t count = 0;
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- count += heap->final_slots_count;
- }
- return count;
-}
-
-#define gc_mode(objspace) gc_mode_verify((enum gc_mode)(objspace)->flags.mode)
-#define gc_mode_set(objspace, m) ((objspace)->flags.mode = (unsigned int)gc_mode_verify(m))
-#define gc_needs_major_flags objspace->rgengc.need_major_gc
-
-#define is_marking(objspace) (gc_mode(objspace) == gc_mode_marking)
-#define is_sweeping(objspace) (gc_mode(objspace) == gc_mode_sweeping)
-#define is_full_marking(objspace) ((objspace)->flags.during_minor_gc == FALSE)
-#define is_incremental_marking(objspace) ((objspace)->flags.during_incremental_marking != FALSE)
-#define will_be_incremental_marking(objspace) ((objspace)->rgengc.need_major_gc != GPR_FLAG_NONE)
-#define GC_INCREMENTAL_SWEEP_SLOT_COUNT 2048
-#define GC_INCREMENTAL_SWEEP_POOL_SLOT_COUNT 1024
-#define is_lazy_sweeping(objspace) (GC_ENABLE_LAZY_SWEEP && has_sweeping_pages(objspace))
-
-#if SIZEOF_LONG == SIZEOF_VOIDP
-# define obj_id_to_ref(objid) ((objid) ^ FIXNUM_FLAG) /* unset FIXNUM_FLAG */
-#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
-# define obj_id_to_ref(objid) (FIXNUM_P(objid) ? \
- ((objid) ^ FIXNUM_FLAG) : (NUM2PTR(objid) << 1))
-#else
-# error not supported
-#endif
-
-struct RZombie {
- struct RBasic basic;
- VALUE next;
- void (*dfree)(void *);
- void *data;
-};
-
-#define RZOMBIE(o) ((struct RZombie *)(o))
-
-int ruby_disable_gc = 0;
-int ruby_enable_autocompact = 0;
-#if RGENGC_CHECK_MODE
-gc_compact_compare_func ruby_autocompact_compare_func;
-#endif
-
-static void init_mark_stack(mark_stack_t *stack);
-static int garbage_collect(rb_objspace_t *, unsigned int reason);
-
-static int gc_start(rb_objspace_t *objspace, unsigned int reason);
-static void gc_rest(rb_objspace_t *objspace);
-
-enum gc_enter_event {
- gc_enter_event_start,
- gc_enter_event_continue,
- gc_enter_event_rest,
- gc_enter_event_finalizer,
-};
-
-static inline void gc_enter(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_lev);
-static inline void gc_exit(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_lev);
-static void gc_marking_enter(rb_objspace_t *objspace);
-static void gc_marking_exit(rb_objspace_t *objspace);
-static void gc_sweeping_enter(rb_objspace_t *objspace);
-static void gc_sweeping_exit(rb_objspace_t *objspace);
-static bool gc_marks_continue(rb_objspace_t *objspace, rb_heap_t *heap);
-
-static void gc_sweep(rb_objspace_t *objspace);
-static void gc_sweep_finish_heap(rb_objspace_t *objspace, rb_heap_t *heap);
-static void gc_sweep_continue(rb_objspace_t *objspace, rb_heap_t *heap);
-
-static inline void gc_mark(rb_objspace_t *objspace, VALUE ptr);
-static inline void gc_pin(rb_objspace_t *objspace, VALUE ptr);
-static inline void gc_mark_and_pin(rb_objspace_t *objspace, VALUE ptr);
-
-static int gc_mark_stacked_objects_incremental(rb_objspace_t *, size_t count);
-NO_SANITIZE("memory", static inline bool is_pointer_to_heap(rb_objspace_t *objspace, const void *ptr));
-
-static void gc_verify_internal_consistency(void *objspace_ptr);
-
-static double getrusage_time(void);
-static inline void gc_prof_setup_new_record(rb_objspace_t *objspace, unsigned int reason);
-static inline void gc_prof_timer_start(rb_objspace_t *);
-static inline void gc_prof_timer_stop(rb_objspace_t *);
-static inline void gc_prof_mark_timer_start(rb_objspace_t *);
-static inline void gc_prof_mark_timer_stop(rb_objspace_t *);
-static inline void gc_prof_sweep_timer_start(rb_objspace_t *);
-static inline void gc_prof_sweep_timer_stop(rb_objspace_t *);
-static inline void gc_prof_set_malloc_info(rb_objspace_t *);
-static inline void gc_prof_set_heap_info(rb_objspace_t *);
-
-#define gc_prof_record(objspace) (objspace)->profile.current_record
-#define gc_prof_enabled(objspace) ((objspace)->profile.run && (objspace)->profile.current_record)
-
-#ifdef HAVE_VA_ARGS_MACRO
-# define gc_report(level, objspace, ...) \
- if (!RGENGC_DEBUG_ENABLED(level)) {} else gc_report_body(level, objspace, __VA_ARGS__)
-#else
-# define gc_report if (!RGENGC_DEBUG_ENABLED(0)) {} else gc_report_body
-#endif
-PRINTF_ARGS(static void gc_report_body(int level, rb_objspace_t *objspace, const char *fmt, ...), 3, 4);
-
-static void gc_finalize_deferred(void *dmy);
-
-#if USE_TICK_T
-
-/* the following code is only for internal tuning. */
-
-/* Source code to use RDTSC is quoted and modified from
- * https://www.mcs.anl.gov/~kazutomo/rdtsc.html
- * written by Kazutomo Yoshii <kazutomo@mcs.anl.gov>
- */
-
-#if defined(__GNUC__) && defined(__i386__)
-typedef unsigned long long tick_t;
-#define PRItick "llu"
-static inline tick_t
-tick(void)
-{
- unsigned long long int x;
- __asm__ __volatile__ ("rdtsc" : "=A" (x));
- return x;
-}
-
-#elif defined(__GNUC__) && defined(__x86_64__)
-typedef unsigned long long tick_t;
-#define PRItick "llu"
-
-static __inline__ tick_t
-tick(void)
-{
- unsigned long hi, lo;
- __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
- return ((unsigned long long)lo)|( ((unsigned long long)hi)<<32);
-}
-
-#elif defined(__powerpc64__) && (GCC_VERSION_SINCE(4,8,0) || defined(__clang__))
-typedef unsigned long long tick_t;
-#define PRItick "llu"
-
-static __inline__ tick_t
-tick(void)
-{
- unsigned long long val = __builtin_ppc_get_timebase();
- return val;
-}
-
-/* Implementation for macOS PPC by @nobu
- * See: https://github.com/ruby/ruby/pull/5975#discussion_r890045558
- */
-#elif defined(__POWERPC__) && defined(__APPLE__)
-typedef unsigned long long tick_t;
-#define PRItick "llu"
-
-static __inline__ tick_t
-tick(void)
-{
- unsigned long int upper, lower, tmp;
- # define mftbu(r) __asm__ volatile("mftbu %0" : "=r"(r))
- # define mftb(r) __asm__ volatile("mftb %0" : "=r"(r))
- do {
- mftbu(upper);
- mftb(lower);
- mftbu(tmp);
- } while (tmp != upper);
- return ((tick_t)upper << 32) | lower;
-}
-
-#elif defined(__aarch64__) && defined(__GNUC__)
-typedef unsigned long tick_t;
-#define PRItick "lu"
-
-static __inline__ tick_t
-tick(void)
-{
- unsigned long val;
- __asm__ __volatile__ ("mrs %0, cntvct_el0" : "=r" (val));
- return val;
-}
-
-
-#elif defined(_WIN32) && defined(_MSC_VER)
-#include <intrin.h>
-typedef unsigned __int64 tick_t;
-#define PRItick "llu"
-
-static inline tick_t
-tick(void)
-{
- return __rdtsc();
-}
-
-#else /* use clock */
-typedef clock_t tick_t;
-#define PRItick "llu"
-
-static inline tick_t
-tick(void)
-{
- return clock();
-}
-#endif /* TSC */
-#else /* USE_TICK_T */
-#define MEASURE_LINE(expr) expr
-#endif /* USE_TICK_T */
-
-static inline VALUE check_rvalue_consistency(rb_objspace_t *objspace, const VALUE obj);
-
-#define RVALUE_MARKED_BITMAP(obj) MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), (obj))
-#define RVALUE_WB_UNPROTECTED_BITMAP(obj) MARKED_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), (obj))
-#define RVALUE_MARKING_BITMAP(obj) MARKED_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), (obj))
-#define RVALUE_UNCOLLECTIBLE_BITMAP(obj) MARKED_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS(obj), (obj))
-#define RVALUE_PINNED_BITMAP(obj) MARKED_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), (obj))
-
-static inline int
-RVALUE_MARKED(rb_objspace_t *objspace, VALUE obj)
-{
- check_rvalue_consistency(objspace, obj);
- return RVALUE_MARKED_BITMAP(obj) != 0;
-}
-
-static inline int
-RVALUE_PINNED(rb_objspace_t *objspace, VALUE obj)
-{
- check_rvalue_consistency(objspace, obj);
- return RVALUE_PINNED_BITMAP(obj) != 0;
-}
-
-static inline int
-RVALUE_WB_UNPROTECTED(rb_objspace_t *objspace, VALUE obj)
-{
- check_rvalue_consistency(objspace, obj);
- return RVALUE_WB_UNPROTECTED_BITMAP(obj) != 0;
-}
-
-static inline int
-RVALUE_MARKING(rb_objspace_t *objspace, VALUE obj)
-{
- check_rvalue_consistency(objspace, obj);
- return RVALUE_MARKING_BITMAP(obj) != 0;
-}
-
-static inline int
-RVALUE_REMEMBERED(rb_objspace_t *objspace, VALUE obj)
-{
- check_rvalue_consistency(objspace, obj);
- return MARKED_IN_BITMAP(GET_HEAP_PAGE(obj)->remembered_bits, obj) != 0;
-}
-
-static inline int
-RVALUE_UNCOLLECTIBLE(rb_objspace_t *objspace, VALUE obj)
-{
- check_rvalue_consistency(objspace, obj);
- return RVALUE_UNCOLLECTIBLE_BITMAP(obj) != 0;
-}
-
-#define RVALUE_PAGE_WB_UNPROTECTED(page, obj) MARKED_IN_BITMAP((page)->wb_unprotected_bits, (obj))
-#define RVALUE_PAGE_UNCOLLECTIBLE(page, obj) MARKED_IN_BITMAP((page)->uncollectible_bits, (obj))
-#define RVALUE_PAGE_MARKING(page, obj) MARKED_IN_BITMAP((page)->marking_bits, (obj))
-
-static int rgengc_remember(rb_objspace_t *objspace, VALUE obj);
-static void rgengc_mark_and_rememberset_clear(rb_objspace_t *objspace, rb_heap_t *heap);
-static void rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap);
-
-static int
-check_rvalue_consistency_force(rb_objspace_t *objspace, const VALUE obj, int terminate)
-{
- int err = 0;
-
- int lev = rb_gc_vm_lock_no_barrier();
- {
- if (SPECIAL_CONST_P(obj)) {
- fprintf(stderr, "check_rvalue_consistency: %p is a special const.\n", (void *)obj);
- err++;
- }
- else if (!is_pointer_to_heap(objspace, (void *)obj)) {
- struct heap_page *empty_page = objspace->empty_pages;
- while (empty_page) {
- if ((uintptr_t)empty_page->body <= (uintptr_t)obj &&
- (uintptr_t)obj < (uintptr_t)empty_page->body + HEAP_PAGE_SIZE) {
- GC_ASSERT(heap_page_in_global_empty_pages_pool(objspace, empty_page));
- fprintf(stderr, "check_rvalue_consistency: %p is in an empty page (%p).\n",
- (void *)obj, (void *)empty_page);
- err++;
- goto skip;
- }
- }
- fprintf(stderr, "check_rvalue_consistency: %p is not a Ruby object.\n", (void *)obj);
- err++;
- skip:
- ;
- }
- else {
- const int wb_unprotected_bit = RVALUE_WB_UNPROTECTED_BITMAP(obj) != 0;
- const int uncollectible_bit = RVALUE_UNCOLLECTIBLE_BITMAP(obj) != 0;
- const int mark_bit = RVALUE_MARKED_BITMAP(obj) != 0;
- const int marking_bit = RVALUE_MARKING_BITMAP(obj) != 0;
- const int remembered_bit = MARKED_IN_BITMAP(GET_HEAP_PAGE(obj)->remembered_bits, obj) != 0;
- const int age = RVALUE_AGE_GET((VALUE)obj);
-
- if (heap_page_in_global_empty_pages_pool(objspace, GET_HEAP_PAGE(obj))) {
- fprintf(stderr, "check_rvalue_consistency: %s is in tomb page.\n", rb_obj_info(obj));
- err++;
- }
- if (BUILTIN_TYPE(obj) == T_NONE) {
- fprintf(stderr, "check_rvalue_consistency: %s is T_NONE.\n", rb_obj_info(obj));
- err++;
- }
- if (BUILTIN_TYPE(obj) == T_ZOMBIE) {
- fprintf(stderr, "check_rvalue_consistency: %s is T_ZOMBIE.\n", rb_obj_info(obj));
- err++;
- }
-
- if (BUILTIN_TYPE(obj) != T_DATA) {
- rb_obj_memsize_of((VALUE)obj);
- }
-
- /* check generation
- *
- * OLD == age == 3 && old-bitmap && mark-bit (except incremental marking)
- */
- if (age > 0 && wb_unprotected_bit) {
- fprintf(stderr, "check_rvalue_consistency: %s is not WB protected, but age is %d > 0.\n", rb_obj_info(obj), age);
- err++;
- }
-
- if (!is_marking(objspace) && uncollectible_bit && !mark_bit) {
- fprintf(stderr, "check_rvalue_consistency: %s is uncollectible, but is not marked while !gc.\n", rb_obj_info(obj));
- err++;
- }
-
- if (!is_full_marking(objspace)) {
- if (uncollectible_bit && age != RVALUE_OLD_AGE && !wb_unprotected_bit) {
- fprintf(stderr, "check_rvalue_consistency: %s is uncollectible, but not old (age: %d) and not WB unprotected.\n",
- rb_obj_info(obj), age);
- err++;
- }
- if (remembered_bit && age != RVALUE_OLD_AGE) {
- fprintf(stderr, "check_rvalue_consistency: %s is remembered, but not old (age: %d).\n",
- rb_obj_info(obj), age);
- err++;
- }
- }
-
- /*
- * check coloring
- *
- * marking:false marking:true
- * marked:false white *invalid*
- * marked:true black grey
- */
- if (is_incremental_marking(objspace) && marking_bit) {
- if (!is_marking(objspace) && !mark_bit) {
- fprintf(stderr, "check_rvalue_consistency: %s is marking, but not marked.\n", rb_obj_info(obj));
- err++;
- }
- }
- }
- }
- rb_gc_vm_unlock_no_barrier(lev);
-
- if (err > 0 && terminate) {
- rb_bug("check_rvalue_consistency_force: there is %d errors.", err);
- }
- return err;
-}
-
-#if RGENGC_CHECK_MODE == 0
-static inline VALUE
-check_rvalue_consistency(rb_objspace_t *objspace, const VALUE obj)
-{
- return obj;
-}
-#else
-static VALUE
-check_rvalue_consistency(rb_objspace_t *objspace, const VALUE obj)
-{
- check_rvalue_consistency_force(objspace, obj, TRUE);
- return obj;
-}
-#endif
-
-static inline bool
-gc_object_moved_p(rb_objspace_t *objspace, VALUE obj)
-{
- if (RB_SPECIAL_CONST_P(obj)) {
- return FALSE;
- }
- else {
- int ret;
- asan_unpoisoning_object(obj) {
- ret = BUILTIN_TYPE(obj) == T_MOVED;
- }
- return ret;
- }
-}
-
-static inline int
-RVALUE_OLD_P(rb_objspace_t *objspace, VALUE obj)
-{
- GC_ASSERT(!RB_SPECIAL_CONST_P(obj));
- check_rvalue_consistency(objspace, obj);
- // Because this will only ever be called on GC controlled objects,
- // we can use the faster _RAW function here
- return RB_OBJ_PROMOTED_RAW(obj);
-}
-
-static inline void
-RVALUE_PAGE_OLD_UNCOLLECTIBLE_SET(rb_objspace_t *objspace, struct heap_page *page, VALUE obj)
-{
- MARK_IN_BITMAP(&page->uncollectible_bits[0], obj);
- objspace->rgengc.old_objects++;
-
-#if RGENGC_PROFILE >= 2
- objspace->profile.total_promoted_count++;
- objspace->profile.promoted_types[BUILTIN_TYPE(obj)]++;
-#endif
-}
-
-static inline void
-RVALUE_OLD_UNCOLLECTIBLE_SET(rb_objspace_t *objspace, VALUE obj)
-{
- RB_DEBUG_COUNTER_INC(obj_promote);
- RVALUE_PAGE_OLD_UNCOLLECTIBLE_SET(objspace, GET_HEAP_PAGE(obj), obj);
-}
-
-/* set age to age+1 */
-static inline void
-RVALUE_AGE_INC(rb_objspace_t *objspace, VALUE obj)
-{
- int age = RVALUE_AGE_GET((VALUE)obj);
-
- if (RGENGC_CHECK_MODE && age == RVALUE_OLD_AGE) {
- rb_bug("RVALUE_AGE_INC: can not increment age of OLD object %s.", rb_obj_info(obj));
- }
-
- age++;
- RVALUE_AGE_SET(obj, age);
-
- if (age == RVALUE_OLD_AGE) {
- RVALUE_OLD_UNCOLLECTIBLE_SET(objspace, obj);
- }
-
- check_rvalue_consistency(objspace, obj);
-}
-
-static inline void
-RVALUE_AGE_SET_CANDIDATE(rb_objspace_t *objspace, VALUE obj)
-{
- check_rvalue_consistency(objspace, obj);
- GC_ASSERT(!RVALUE_OLD_P(objspace, obj));
- RVALUE_AGE_SET(obj, RVALUE_OLD_AGE - 1);
- check_rvalue_consistency(objspace, obj);
-}
-
-static inline void
-RVALUE_AGE_RESET(VALUE obj)
-{
- RVALUE_AGE_SET(obj, 0);
-}
-
-static inline void
-RVALUE_DEMOTE(rb_objspace_t *objspace, VALUE obj)
-{
- check_rvalue_consistency(objspace, obj);
- GC_ASSERT(RVALUE_OLD_P(objspace, obj));
-
- if (!is_incremental_marking(objspace) && RVALUE_REMEMBERED(objspace, obj)) {
- CLEAR_IN_BITMAP(GET_HEAP_PAGE(obj)->remembered_bits, obj);
- }
-
- CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS(obj), obj);
- RVALUE_AGE_RESET(obj);
-
- if (RVALUE_MARKED(objspace, obj)) {
- objspace->rgengc.old_objects--;
- }
-
- check_rvalue_consistency(objspace, obj);
-}
-
-static inline int
-RVALUE_BLACK_P(rb_objspace_t *objspace, VALUE obj)
-{
- return RVALUE_MARKED(objspace, obj) && !RVALUE_MARKING(objspace, obj);
-}
-
-static inline int
-RVALUE_WHITE_P(rb_objspace_t *objspace, VALUE obj)
-{
- return !RVALUE_MARKED(objspace, obj);
-}
-
-bool
-rb_gc_impl_gc_enabled_p(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
- return !dont_gc_val();
-}
-
-void
-rb_gc_impl_gc_enable(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- dont_gc_off();
-}
-
-void
-rb_gc_impl_gc_disable(void *objspace_ptr, bool finish_current_gc)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- if (finish_current_gc) {
- gc_rest(objspace);
- }
-
- dont_gc_on();
-}
-
-/*
- --------------------------- ObjectSpace -----------------------------
-*/
-
-static inline void *
-calloc1(size_t n)
-{
- return calloc(1, n);
-}
-
-void
-rb_gc_impl_set_event_hook(void *objspace_ptr, const rb_event_flag_t event)
-{
- rb_objspace_t *objspace = objspace_ptr;
- objspace->hook_events = event & RUBY_INTERNAL_EVENT_OBJSPACE_MASK;
- objspace->flags.has_newobj_hook = !!(objspace->hook_events & RUBY_INTERNAL_EVENT_NEWOBJ);
-}
-
-unsigned long long
-rb_gc_impl_get_total_time(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- unsigned long long marking_time = objspace->profile.marking_time_ns;
- unsigned long long sweeping_time = objspace->profile.sweeping_time_ns;
-
- return marking_time + sweeping_time;
-}
-
-void
-rb_gc_impl_set_measure_total_time(void *objspace_ptr, VALUE flag)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- objspace->flags.measure_gc = RTEST(flag) ? TRUE : FALSE;
-}
-
-bool
-rb_gc_impl_get_measure_total_time(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- return objspace->flags.measure_gc;
-}
-
-static size_t
-minimum_slots_for_heap(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- size_t heap_idx = heap - heaps;
- return gc_params.heap_init_slots[heap_idx];
-}
-
-static int
-object_id_cmp(st_data_t x, st_data_t y)
-{
- if (RB_TYPE_P(x, T_BIGNUM)) {
- return !rb_big_eql(x, y);
- }
- else {
- return x != y;
- }
-}
-
-static st_index_t
-object_id_hash(st_data_t n)
-{
- return FIX2LONG(rb_hash((VALUE)n));
-}
-
-#define OBJ_ID_INCREMENT (RUBY_IMMEDIATE_MASK + 1)
-#define OBJ_ID_INITIAL (OBJ_ID_INCREMENT)
-
-static const struct st_hash_type object_id_hash_type = {
- object_id_cmp,
- object_id_hash,
-};
-
-/* garbage objects will be collected soon. */
-bool
-rb_gc_impl_garbage_object_p(void *objspace_ptr, VALUE ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- bool dead = false;
-
- asan_unpoisoning_object(ptr) {
- switch (BUILTIN_TYPE(ptr)) {
- case T_NONE:
- case T_MOVED:
- case T_ZOMBIE:
- dead = true;
- break;
- default:
- break;
- }
- }
-
- if (dead) return true;
- return is_lazy_sweeping(objspace) && GET_HEAP_PAGE(ptr)->flags.before_sweep &&
- !RVALUE_MARKED(objspace, ptr);
-}
-
-VALUE
-rb_gc_impl_object_id_to_ref(void *objspace_ptr, VALUE object_id)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- VALUE obj;
- if (st_lookup(objspace->id_to_obj_tbl, object_id, &obj) &&
- !rb_gc_impl_garbage_object_p(objspace, obj)) {
- return obj;
- }
-
- if (rb_funcall(object_id, rb_intern(">="), 1, ULL2NUM(objspace->next_object_id))) {
- rb_raise(rb_eRangeError, "%+"PRIsVALUE" is not id value", rb_funcall(object_id, rb_intern("to_s"), 1, INT2FIX(10)));
- }
- else {
- rb_raise(rb_eRangeError, "%+"PRIsVALUE" is recycled object", rb_funcall(object_id, rb_intern("to_s"), 1, INT2FIX(10)));
- }
-}
-
-VALUE
-rb_gc_impl_object_id(void *objspace_ptr, VALUE obj)
-{
- VALUE id;
- rb_objspace_t *objspace = objspace_ptr;
-
- unsigned int lev = rb_gc_vm_lock();
- if (FL_TEST(obj, FL_SEEN_OBJ_ID)) {
- st_data_t val;
- if (st_lookup(objspace->obj_to_id_tbl, (st_data_t)obj, &val)) {
- id = (VALUE)val;
- }
- else {
- rb_bug("rb_gc_impl_object_id: FL_SEEN_OBJ_ID flag set but not found in table");
- }
- }
- else {
- GC_ASSERT(!st_lookup(objspace->obj_to_id_tbl, (st_data_t)obj, NULL));
-
- id = ULL2NUM(objspace->next_object_id);
- objspace->next_object_id += OBJ_ID_INCREMENT;
-
- st_insert(objspace->obj_to_id_tbl, (st_data_t)obj, (st_data_t)id);
- st_insert(objspace->id_to_obj_tbl, (st_data_t)id, (st_data_t)obj);
- FL_SET(obj, FL_SEEN_OBJ_ID);
- }
- rb_gc_vm_unlock(lev);
-
- return id;
-}
-
-static void free_stack_chunks(mark_stack_t *);
-static void mark_stack_free_cache(mark_stack_t *);
-static void heap_page_free(rb_objspace_t *objspace, struct heap_page *page);
-
-static inline void
-heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj)
-{
- asan_unpoison_object(obj, false);
-
- asan_unlock_freelist(page);
-
- struct free_slot *slot = (struct free_slot *)obj;
- slot->flags = 0;
- slot->next = page->freelist;
- page->freelist = slot;
- asan_lock_freelist(page);
-
- RVALUE_AGE_RESET(obj);
-
- if (RGENGC_CHECK_MODE &&
- /* obj should belong to page */
- !(page->start <= (uintptr_t)obj &&
- (uintptr_t)obj < ((uintptr_t)page->start + (page->total_slots * page->slot_size)) &&
- obj % BASE_SLOT_SIZE == 0)) {
- rb_bug("heap_page_add_freeobj: %p is not rvalue.", (void *)obj);
- }
-
- asan_poison_object(obj);
- gc_report(3, objspace, "heap_page_add_freeobj: add %p to freelist\n", (void *)obj);
-}
-
-static void
-heap_allocatable_slots_expand(rb_objspace_t *objspace,
- rb_heap_t *heap, size_t free_slots, size_t total_slots)
-{
- double goal_ratio = gc_params.heap_free_slots_goal_ratio;
- size_t target_total_slots;
-
- if (goal_ratio == 0.0) {
- target_total_slots = (size_t)(total_slots * gc_params.growth_factor);
- }
- else if (total_slots == 0) {
- target_total_slots = minimum_slots_for_heap(objspace, heap);
- }
- else {
- /* Find `f' where free_slots = f * total_slots * goal_ratio
- * => f = (total_slots - free_slots) / ((1 - goal_ratio) * total_slots)
- */
- double f = (double)(total_slots - free_slots) / ((1 - goal_ratio) * total_slots);
-
- if (f > gc_params.growth_factor) f = gc_params.growth_factor;
- if (f < 1.0) f = 1.1;
-
- target_total_slots = (size_t)(f * total_slots);
-
- if (0) {
- fprintf(stderr,
- "free_slots(%8"PRIuSIZE")/total_slots(%8"PRIuSIZE")=%1.2f,"
- " G(%1.2f), f(%1.2f),"
- " total_slots(%8"PRIuSIZE") => target_total_slots(%8"PRIuSIZE")\n",
- free_slots, total_slots, free_slots/(double)total_slots,
- goal_ratio, f, total_slots, target_total_slots);
- }
- }
-
- if (gc_params.growth_max_slots > 0) {
- size_t max_total_slots = (size_t)(total_slots + gc_params.growth_max_slots);
- if (target_total_slots > max_total_slots) target_total_slots = max_total_slots;
- }
-
- size_t extend_slot_count = target_total_slots - total_slots;
- /* Extend by at least 1 page. */
- if (extend_slot_count == 0) extend_slot_count = 1;
-
- objspace->heap_pages.allocatable_slots += extend_slot_count;
-}
-
-static inline void
-heap_add_freepage(rb_heap_t *heap, struct heap_page *page)
-{
- asan_unlock_freelist(page);
- GC_ASSERT(page->free_slots != 0);
- GC_ASSERT(page->freelist != NULL);
-
- page->free_next = heap->free_pages;
- heap->free_pages = page;
-
- RUBY_DEBUG_LOG("page:%p freelist:%p", (void *)page, (void *)page->freelist);
-
- asan_lock_freelist(page);
-}
-
-static inline void
-heap_add_poolpage(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
-{
- asan_unlock_freelist(page);
- GC_ASSERT(page->free_slots != 0);
- GC_ASSERT(page->freelist != NULL);
-
- page->free_next = heap->pooled_pages;
- heap->pooled_pages = page;
- objspace->rincgc.pooled_slots += page->free_slots;
-
- asan_lock_freelist(page);
-}
-
-static void
-heap_unlink_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
-{
- ccan_list_del(&page->page_node);
- heap->total_pages--;
- heap->total_slots -= page->total_slots;
-}
-
-static void
-gc_aligned_free(void *ptr, size_t size)
-{
-#if defined __MINGW32__
- __mingw_aligned_free(ptr);
-#elif defined _WIN32
- _aligned_free(ptr);
-#elif defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_MEMALIGN)
- free(ptr);
-#else
- free(((void**)ptr)[-1]);
-#endif
-}
-
-static void
-heap_page_body_free(struct heap_page_body *page_body)
-{
- GC_ASSERT((uintptr_t)page_body % HEAP_PAGE_ALIGN == 0);
-
- if (HEAP_PAGE_ALLOC_USE_MMAP) {
-#ifdef HAVE_MMAP
- GC_ASSERT(HEAP_PAGE_SIZE % sysconf(_SC_PAGE_SIZE) == 0);
- if (munmap(page_body, HEAP_PAGE_SIZE)) {
- rb_bug("heap_page_body_free: munmap failed");
- }
-#endif
- }
- else {
- gc_aligned_free(page_body, HEAP_PAGE_SIZE);
- }
-}
-
-static void
-heap_page_free(rb_objspace_t *objspace, struct heap_page *page)
-{
- objspace->heap_pages.freed_pages++;
- heap_page_body_free(page->body);
- free(page);
-}
-
-static void
-heap_pages_free_unused_pages(rb_objspace_t *objspace)
-{
- size_t pages_to_keep_count =
- // Get number of pages estimated for the smallest size pool
- CEILDIV(objspace->heap_pages.allocatable_slots, HEAP_PAGE_OBJ_LIMIT) *
- // Estimate the average slot size multiple
- (1 << (HEAP_COUNT / 2));
-
- if (objspace->empty_pages != NULL && objspace->empty_pages_count > pages_to_keep_count) {
- GC_ASSERT(objspace->empty_pages_count > 0);
- objspace->empty_pages = NULL;
- objspace->empty_pages_count = 0;
-
- size_t i, j;
- for (i = j = 0; i < rb_darray_size(objspace->heap_pages.sorted); i++) {
- struct heap_page *page = rb_darray_get(objspace->heap_pages.sorted, i);
-
- if (heap_page_in_global_empty_pages_pool(objspace, page) && pages_to_keep_count == 0) {
- heap_page_free(objspace, page);
- }
- else {
- if (heap_page_in_global_empty_pages_pool(objspace, page) && pages_to_keep_count > 0) {
- page->free_next = objspace->empty_pages;
- objspace->empty_pages = page;
- objspace->empty_pages_count++;
- pages_to_keep_count--;
- }
-
- if (i != j) {
- rb_darray_set(objspace->heap_pages.sorted, j, page);
- }
- j++;
- }
- }
-
- rb_darray_pop(objspace->heap_pages.sorted, i - j);
- GC_ASSERT(rb_darray_size(objspace->heap_pages.sorted) == j);
-
- struct heap_page *hipage = rb_darray_get(objspace->heap_pages.sorted, rb_darray_size(objspace->heap_pages.sorted) - 1);
- uintptr_t himem = (uintptr_t)hipage->body + HEAP_PAGE_SIZE;
- GC_ASSERT(himem <= heap_pages_himem);
- heap_pages_himem = himem;
-
- struct heap_page *lopage = rb_darray_get(objspace->heap_pages.sorted, 0);
- uintptr_t lomem = (uintptr_t)lopage->body + sizeof(struct heap_page_header);
- GC_ASSERT(lomem >= heap_pages_lomem);
- heap_pages_lomem = lomem;
- }
-}
-
-static void *
-gc_aligned_malloc(size_t alignment, size_t size)
-{
- /* alignment must be a power of 2 */
- GC_ASSERT(((alignment - 1) & alignment) == 0);
- GC_ASSERT(alignment % sizeof(void*) == 0);
-
- void *res;
-
-#if defined __MINGW32__
- res = __mingw_aligned_malloc(size, alignment);
-#elif defined _WIN32
- void *_aligned_malloc(size_t, size_t);
- res = _aligned_malloc(size, alignment);
-#elif defined(HAVE_POSIX_MEMALIGN)
- if (posix_memalign(&res, alignment, size) != 0) {
- return NULL;
- }
-#elif defined(HAVE_MEMALIGN)
- res = memalign(alignment, size);
-#else
- char* aligned;
- res = malloc(alignment + size + sizeof(void*));
- aligned = (char*)res + alignment + sizeof(void*);
- aligned -= ((VALUE)aligned & (alignment - 1));
- ((void**)aligned)[-1] = res;
- res = (void*)aligned;
-#endif
-
- GC_ASSERT((uintptr_t)res % alignment == 0);
-
- return res;
-}
-
-static struct heap_page_body *
-heap_page_body_allocate(void)
-{
- struct heap_page_body *page_body;
-
- if (HEAP_PAGE_ALLOC_USE_MMAP) {
-#ifdef HAVE_MMAP
- GC_ASSERT(HEAP_PAGE_ALIGN % sysconf(_SC_PAGE_SIZE) == 0);
-
- char *ptr = mmap(NULL, HEAP_PAGE_ALIGN + HEAP_PAGE_SIZE,
- PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (ptr == MAP_FAILED) {
- return NULL;
- }
-
- char *aligned = ptr + HEAP_PAGE_ALIGN;
- aligned -= ((VALUE)aligned & (HEAP_PAGE_ALIGN - 1));
- GC_ASSERT(aligned > ptr);
- GC_ASSERT(aligned <= ptr + HEAP_PAGE_ALIGN);
-
- size_t start_out_of_range_size = aligned - ptr;
- GC_ASSERT(start_out_of_range_size % sysconf(_SC_PAGE_SIZE) == 0);
- if (start_out_of_range_size > 0) {
- if (munmap(ptr, start_out_of_range_size)) {
- rb_bug("heap_page_body_allocate: munmap failed for start");
- }
- }
-
- size_t end_out_of_range_size = HEAP_PAGE_ALIGN - start_out_of_range_size;
- GC_ASSERT(end_out_of_range_size % sysconf(_SC_PAGE_SIZE) == 0);
- if (end_out_of_range_size > 0) {
- if (munmap(aligned + HEAP_PAGE_SIZE, end_out_of_range_size)) {
- rb_bug("heap_page_body_allocate: munmap failed for end");
- }
- }
-
- page_body = (struct heap_page_body *)aligned;
-#endif
- }
- else {
- page_body = gc_aligned_malloc(HEAP_PAGE_ALIGN, HEAP_PAGE_SIZE);
- }
-
- GC_ASSERT((uintptr_t)page_body % HEAP_PAGE_ALIGN == 0);
-
- return page_body;
-}
-
-static struct heap_page *
-heap_page_resurrect(rb_objspace_t *objspace)
-{
- struct heap_page *page = NULL;
- if (objspace->empty_pages != NULL) {
- GC_ASSERT(objspace->empty_pages_count > 0);
- objspace->empty_pages_count--;
- page = objspace->empty_pages;
- objspace->empty_pages = page->free_next;
- }
-
- return page;
-}
-
-static struct heap_page *
-heap_page_allocate(rb_objspace_t *objspace)
-{
- struct heap_page_body *page_body = heap_page_body_allocate();
- if (page_body == 0) {
- rb_memerror();
- }
-
- struct heap_page *page = calloc1(sizeof(struct heap_page));
- if (page == 0) {
- heap_page_body_free(page_body);
- rb_memerror();
- }
-
- uintptr_t start = (uintptr_t)page_body + sizeof(struct heap_page_header);
- uintptr_t end = (uintptr_t)page_body + HEAP_PAGE_SIZE;
-
- size_t lo = 0;
- size_t hi = rb_darray_size(objspace->heap_pages.sorted);
- while (lo < hi) {
- struct heap_page *mid_page;
-
- size_t mid = (lo + hi) / 2;
- mid_page = rb_darray_get(objspace->heap_pages.sorted, mid);
- if ((uintptr_t)mid_page->start < start) {
- lo = mid + 1;
- }
- else if ((uintptr_t)mid_page->start > start) {
- hi = mid;
- }
- else {
- rb_bug("same heap page is allocated: %p at %"PRIuVALUE, (void *)page_body, (VALUE)mid);
- }
- }
-
- rb_darray_insert(&objspace->heap_pages.sorted, hi, page);
-
- if (heap_pages_lomem == 0 || heap_pages_lomem > start) heap_pages_lomem = start;
- if (heap_pages_himem < end) heap_pages_himem = end;
-
- page->body = page_body;
- page_body->header.page = page;
-
- objspace->heap_pages.allocated_pages++;
-
- return page;
-}
-
-static void
-heap_add_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
-{
- /* Adding to eden heap during incremental sweeping is forbidden */
- GC_ASSERT(!heap->sweeping_page);
- GC_ASSERT(heap_page_in_global_empty_pages_pool(objspace, page));
-
- /* adjust obj_limit (object number available in this page) */
- uintptr_t start = (uintptr_t)page->body + sizeof(struct heap_page_header);
- if (start % BASE_SLOT_SIZE != 0) {
- int delta = BASE_SLOT_SIZE - (start % BASE_SLOT_SIZE);
- start = start + delta;
- GC_ASSERT(NUM_IN_PAGE(start) == 0 || NUM_IN_PAGE(start) == 1);
-
- /* Find a num in page that is evenly divisible by `stride`.
- * This is to ensure that objects are aligned with bit planes.
- * In other words, ensure there are an even number of objects
- * per bit plane. */
- if (NUM_IN_PAGE(start) == 1) {
- start += heap->slot_size - BASE_SLOT_SIZE;
- }
-
- GC_ASSERT(NUM_IN_PAGE(start) * BASE_SLOT_SIZE % heap->slot_size == 0);
- }
-
- int slot_count = (int)((HEAP_PAGE_SIZE - (start - (uintptr_t)page->body))/heap->slot_size);
-
- page->start = start;
- page->total_slots = slot_count;
- page->slot_size = heap->slot_size;
- page->heap = heap;
-
- asan_unlock_freelist(page);
- page->freelist = NULL;
- asan_unpoison_memory_region(page->body, HEAP_PAGE_SIZE, false);
- for (VALUE p = (VALUE)start; p < start + (slot_count * heap->slot_size); p += heap->slot_size) {
- heap_page_add_freeobj(objspace, page, p);
- }
- asan_lock_freelist(page);
-
- page->free_slots = slot_count;
-
- heap->total_allocated_pages++;
-
- ccan_list_add_tail(&heap->pages, &page->page_node);
- heap->total_pages++;
- heap->total_slots += page->total_slots;
-}
-
-static int
-heap_page_allocate_and_initialize(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- if (objspace->heap_pages.allocatable_slots > 0) {
- gc_report(1, objspace, "heap_page_allocate_and_initialize: rb_darray_size(objspace->heap_pages.sorted): %"PRIdSIZE", "
- "allocatable_slots: %"PRIdSIZE", heap->total_pages: %"PRIdSIZE"\n",
- rb_darray_size(objspace->heap_pages.sorted), objspace->heap_pages.allocatable_slots, heap->total_pages);
-
- struct heap_page *page = heap_page_resurrect(objspace);
- if (page == NULL) {
- page = heap_page_allocate(objspace);
- }
- heap_add_page(objspace, heap, page);
- heap_add_freepage(heap, page);
-
- if (objspace->heap_pages.allocatable_slots > (size_t)page->total_slots) {
- objspace->heap_pages.allocatable_slots -= page->total_slots;
- }
- else {
- objspace->heap_pages.allocatable_slots = 0;
- }
-
- return true;
- }
-
- return false;
-}
-
-static void
-heap_page_allocate_and_initialize_force(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- size_t prev_allocatable_slots = objspace->heap_pages.allocatable_slots;
- // Set allocatable slots to 1 to force a page to be created.
- objspace->heap_pages.allocatable_slots = 1;
- heap_page_allocate_and_initialize(objspace, heap);
- GC_ASSERT(heap->free_pages != NULL);
- objspace->heap_pages.allocatable_slots = prev_allocatable_slots;
-}
-
-static void
-gc_continue(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- unsigned int lock_lev;
- gc_enter(objspace, gc_enter_event_continue, &lock_lev);
-
- /* Continue marking if in incremental marking. */
- if (is_incremental_marking(objspace)) {
- if (gc_marks_continue(objspace, heap)) {
- gc_sweep(objspace);
- }
- }
-
- /* Continue sweeping if in lazy sweeping or the previous incremental
- * marking finished and did not yield a free page. */
- if (heap->free_pages == NULL && is_lazy_sweeping(objspace)) {
- gc_sweep_continue(objspace, heap);
- }
-
- gc_exit(objspace, gc_enter_event_continue, &lock_lev);
-}
-
-static void
-heap_prepare(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- GC_ASSERT(heap->free_pages == NULL);
-
- if (heap->total_slots < gc_params.heap_init_slots[heap - heaps] &&
- heap->sweeping_page == NULL) {
- heap_page_allocate_and_initialize_force(objspace, heap);
- GC_ASSERT(heap->free_pages != NULL);
- return;
- }
-
- /* Continue incremental marking or lazy sweeping, if in any of those steps. */
- gc_continue(objspace, heap);
-
- if (heap->free_pages == NULL) {
- heap_page_allocate_and_initialize(objspace, heap);
- }
-
- /* If we still don't have a free page and not allowed to create a new page,
- * we should start a new GC cycle. */
- if (heap->free_pages == NULL) {
- if (gc_start(objspace, GPR_FLAG_NEWOBJ) == FALSE) {
- rb_memerror();
- }
- else {
- if (objspace->heap_pages.allocatable_slots == 0 && !gc_config_full_mark_val) {
- heap_allocatable_slots_expand(objspace, heap,
- heap->freed_slots + heap->empty_slots,
- heap->total_slots);
- GC_ASSERT(objspace->heap_pages.allocatable_slots > 0);
- }
- /* Do steps of incremental marking or lazy sweeping if the GC run permits. */
- gc_continue(objspace, heap);
-
- /* If we're not incremental marking (e.g. a minor GC) or finished
- * sweeping and still don't have a free page, then
- * gc_sweep_finish_heap should allow us to create a new page. */
- if (heap->free_pages == NULL && !heap_page_allocate_and_initialize(objspace, heap)) {
- if (gc_needs_major_flags == GPR_FLAG_NONE) {
- rb_bug("cannot create a new page after GC");
- }
- else { // Major GC is required, which will allow us to create new page
- if (gc_start(objspace, GPR_FLAG_NEWOBJ) == FALSE) {
- rb_memerror();
- }
- else {
- /* Do steps of incremental marking or lazy sweeping. */
- gc_continue(objspace, heap);
-
- if (heap->free_pages == NULL &&
- !heap_page_allocate_and_initialize(objspace, heap)) {
- rb_bug("cannot create a new page after major GC");
- }
- }
- }
- }
- }
- }
-
- GC_ASSERT(heap->free_pages != NULL);
-}
-
-static inline VALUE
-newobj_fill(VALUE obj, VALUE v1, VALUE v2, VALUE v3)
-{
- VALUE *p = (VALUE *)obj;
- p[2] = v1;
- p[3] = v2;
- p[4] = v3;
- return obj;
-}
-
-#if GC_DEBUG
-static inline const char*
-rb_gc_impl_source_location_cstr(int *ptr)
-{
- /* We could directly refer `rb_source_location_cstr()` before, but not any
- * longer. We have to heavy lift using our debugging API. */
- if (! ptr) {
- return NULL;
- }
- else if (! (*ptr = rb_sourceline())) {
- return NULL;
- }
- else {
- return rb_sourcefile();
- }
-}
-#endif
-
-static inline VALUE
-newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace, VALUE obj)
-{
-#if !__has_feature(memory_sanitizer)
- GC_ASSERT(BUILTIN_TYPE(obj) == T_NONE);
- GC_ASSERT((flags & FL_WB_PROTECTED) == 0);
-#endif
- RBASIC(obj)->flags = flags;
- *((VALUE *)&RBASIC(obj)->klass) = klass;
-
- int t = flags & RUBY_T_MASK;
- if (t == T_CLASS || t == T_MODULE || t == T_ICLASS) {
- RVALUE_AGE_SET_CANDIDATE(objspace, obj);
- }
-
-#if RACTOR_CHECK_MODE
- void rb_ractor_setup_belonging(VALUE obj);
- rb_ractor_setup_belonging(obj);
-#endif
-
-#if RGENGC_CHECK_MODE
- newobj_fill(obj, 0, 0, 0);
-
- int lev = rb_gc_vm_lock_no_barrier();
- {
- check_rvalue_consistency(objspace, obj);
-
- GC_ASSERT(RVALUE_MARKED(objspace, obj) == FALSE);
- GC_ASSERT(RVALUE_MARKING(objspace, obj) == FALSE);
- GC_ASSERT(RVALUE_OLD_P(objspace, obj) == FALSE);
- GC_ASSERT(RVALUE_WB_UNPROTECTED(objspace, obj) == FALSE);
-
- if (RVALUE_REMEMBERED(objspace, obj)) rb_bug("newobj: %s is remembered.", rb_obj_info(obj));
- }
- rb_gc_vm_unlock_no_barrier(lev);
-#endif
-
- if (RB_UNLIKELY(wb_protected == FALSE)) {
- MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), obj);
- }
-
-#if RGENGC_PROFILE
- if (wb_protected) {
- objspace->profile.total_generated_normal_object_count++;
-#if RGENGC_PROFILE >= 2
- objspace->profile.generated_normal_object_count_types[BUILTIN_TYPE(obj)]++;
-#endif
- }
- else {
- objspace->profile.total_generated_shady_object_count++;
-#if RGENGC_PROFILE >= 2
- objspace->profile.generated_shady_object_count_types[BUILTIN_TYPE(obj)]++;
-#endif
- }
-#endif
-
-#if GC_DEBUG
- GET_RVALUE_OVERHEAD(obj)->file = rb_gc_impl_source_location_cstr(&GET_RVALUE_OVERHEAD(obj)->line);
- GC_ASSERT(!SPECIAL_CONST_P(obj)); /* check alignment */
-#endif
-
- gc_report(5, objspace, "newobj: %s\n", rb_obj_info(obj));
-
- RUBY_DEBUG_LOG("obj:%p (%s)", (void *)obj, rb_obj_info(obj));
- return obj;
-}
-
-size_t
-rb_gc_impl_obj_slot_size(VALUE obj)
-{
- return GET_HEAP_PAGE(obj)->slot_size - RVALUE_OVERHEAD;
-}
-
-static inline size_t
-heap_slot_size(unsigned char pool_id)
-{
- GC_ASSERT(pool_id < HEAP_COUNT);
-
- size_t slot_size = (1 << pool_id) * BASE_SLOT_SIZE;
-
-#if RGENGC_CHECK_MODE
- rb_objspace_t *objspace = rb_gc_get_objspace();
- GC_ASSERT(heaps[pool_id].slot_size == (short)slot_size);
-#endif
-
- slot_size -= RVALUE_OVERHEAD;
-
- return slot_size;
-}
-
-bool
-rb_gc_impl_size_allocatable_p(size_t size)
-{
- return size <= heap_slot_size(HEAP_COUNT - 1);
-}
-
-static inline VALUE
-ractor_cache_allocate_slot(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache,
- size_t heap_idx)
-{
- rb_ractor_newobj_heap_cache_t *heap_cache = &cache->heap_caches[heap_idx];
- struct free_slot *p = heap_cache->freelist;
-
- if (RB_UNLIKELY(is_incremental_marking(objspace))) {
- // Not allowed to allocate without running an incremental marking step
- if (cache->incremental_mark_step_allocated_slots >= INCREMENTAL_MARK_STEP_ALLOCATIONS) {
- return Qfalse;
- }
-
- if (p) {
- cache->incremental_mark_step_allocated_slots++;
- }
- }
-
- if (RB_LIKELY(p)) {
- VALUE obj = (VALUE)p;
- MAYBE_UNUSED(const size_t) stride = heap_slot_size(heap_idx);
- heap_cache->freelist = p->next;
- asan_unpoison_memory_region(p, stride, true);
-#if RGENGC_CHECK_MODE
- GC_ASSERT(rb_gc_impl_obj_slot_size(obj) == stride);
- // zero clear
- MEMZERO((char *)obj, char, stride);
-#endif
- return obj;
- }
- else {
- return Qfalse;
- }
-}
-
-static struct heap_page *
-heap_next_free_page(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- struct heap_page *page;
-
- if (heap->free_pages == NULL) {
- heap_prepare(objspace, heap);
- }
-
- page = heap->free_pages;
- heap->free_pages = page->free_next;
-
- GC_ASSERT(page->free_slots != 0);
-
- asan_unlock_freelist(page);
-
- return page;
-}
-
-static inline void
-ractor_cache_set_page(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, size_t heap_idx,
- struct heap_page *page)
-{
- gc_report(3, objspace, "ractor_set_cache: Using page %p\n", (void *)page->body);
-
- rb_ractor_newobj_heap_cache_t *heap_cache = &cache->heap_caches[heap_idx];
-
- GC_ASSERT(heap_cache->freelist == NULL);
- GC_ASSERT(page->free_slots != 0);
- GC_ASSERT(page->freelist != NULL);
-
- heap_cache->using_page = page;
- heap_cache->freelist = page->freelist;
- page->free_slots = 0;
- page->freelist = NULL;
-
- asan_unpoison_object((VALUE)heap_cache->freelist, false);
- GC_ASSERT(RB_TYPE_P((VALUE)heap_cache->freelist, T_NONE));
- asan_poison_object((VALUE)heap_cache->freelist);
-}
-
-static inline size_t
-heap_idx_for_size(size_t size)
-{
- size += RVALUE_OVERHEAD;
-
- size_t slot_count = CEILDIV(size, BASE_SLOT_SIZE);
-
- /* heap_idx is ceil(log2(slot_count)) */
- size_t heap_idx = 64 - nlz_int64(slot_count - 1);
-
- if (heap_idx >= HEAP_COUNT) {
- rb_bug("heap_idx_for_size: allocation size too large "
- "(size=%"PRIuSIZE"u, heap_idx=%"PRIuSIZE"u)", size, heap_idx);
- }
-
-#if RGENGC_CHECK_MODE
- rb_objspace_t *objspace = rb_gc_get_objspace();
- GC_ASSERT(size <= (size_t)heaps[heap_idx].slot_size);
- if (heap_idx > 0) GC_ASSERT(size > (size_t)heaps[heap_idx - 1].slot_size);
-#endif
-
- return heap_idx;
-}
-
-size_t
-rb_gc_impl_heap_id_for_size(void *objspace_ptr, size_t size)
-{
- return heap_idx_for_size(size);
-}
-
-
-static size_t heap_sizes[HEAP_COUNT + 1] = { 0 };
-
-size_t *
-rb_gc_impl_heap_sizes(void *objspace_ptr)
-{
- if (heap_sizes[0] == 0) {
- for (unsigned char i = 0; i < HEAP_COUNT; i++) {
- heap_sizes[i] = heap_slot_size(i);
- }
- }
-
- return heap_sizes;
-}
-
-NOINLINE(static VALUE newobj_cache_miss(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, size_t heap_idx, bool vm_locked));
-
-static VALUE
-newobj_cache_miss(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, size_t heap_idx, bool vm_locked)
-{
- rb_heap_t *heap = &heaps[heap_idx];
- VALUE obj = Qfalse;
-
- unsigned int lev = 0;
- bool unlock_vm = false;
-
- if (!vm_locked) {
- lev = rb_gc_cr_lock();
- vm_locked = true;
- unlock_vm = true;
- }
-
- {
- if (is_incremental_marking(objspace)) {
- gc_continue(objspace, heap);
- cache->incremental_mark_step_allocated_slots = 0;
-
- // Retry allocation after resetting incremental_mark_step_allocated_slots
- obj = ractor_cache_allocate_slot(objspace, cache, heap_idx);
- }
-
- if (obj == Qfalse) {
- // Get next free page (possibly running GC)
- struct heap_page *page = heap_next_free_page(objspace, heap);
- ractor_cache_set_page(objspace, cache, heap_idx, page);
-
- // Retry allocation after moving to new page
- obj = ractor_cache_allocate_slot(objspace, cache, heap_idx);
- }
- }
-
- if (unlock_vm) {
- rb_gc_cr_unlock(lev);
- }
-
- if (RB_UNLIKELY(obj == Qfalse)) {
- rb_memerror();
- }
- return obj;
-}
-
-static VALUE
-newobj_alloc(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, size_t heap_idx, bool vm_locked)
-{
- VALUE obj = ractor_cache_allocate_slot(objspace, cache, heap_idx);
-
- if (RB_UNLIKELY(obj == Qfalse)) {
- obj = newobj_cache_miss(objspace, cache, heap_idx, vm_locked);
- }
-
- rb_heap_t *heap = &heaps[heap_idx];
- heap->total_allocated_objects++;
- GC_ASSERT(rb_gc_multi_ractor_p() ||
- heap->total_slots >=
- (heap->total_allocated_objects - heap->total_freed_objects - heap->final_slots_count));
-
- return obj;
-}
-
-ALWAYS_INLINE(static VALUE newobj_slowpath(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, int wb_protected, size_t heap_idx));
-
-static inline VALUE
-newobj_slowpath(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, int wb_protected, size_t heap_idx)
-{
- VALUE obj;
- unsigned int lev;
-
- lev = rb_gc_cr_lock();
- {
- if (RB_UNLIKELY(during_gc || ruby_gc_stressful)) {
- if (during_gc) {
- dont_gc_on();
- during_gc = 0;
- rb_bug("object allocation during garbage collection phase");
- }
-
- if (ruby_gc_stressful) {
- if (!garbage_collect(objspace, GPR_FLAG_NEWOBJ)) {
- rb_memerror();
- }
- }
- }
-
- obj = newobj_alloc(objspace, cache, heap_idx, true);
- newobj_init(klass, flags, wb_protected, objspace, obj);
- }
- rb_gc_cr_unlock(lev);
-
- return obj;
-}
-
-NOINLINE(static VALUE newobj_slowpath_wb_protected(VALUE klass, VALUE flags,
- rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, size_t heap_idx));
-NOINLINE(static VALUE newobj_slowpath_wb_unprotected(VALUE klass, VALUE flags,
- rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, size_t heap_idx));
-
-static VALUE
-newobj_slowpath_wb_protected(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, size_t heap_idx)
-{
- return newobj_slowpath(klass, flags, objspace, cache, TRUE, heap_idx);
-}
-
-static VALUE
-newobj_slowpath_wb_unprotected(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, size_t heap_idx)
-{
- return newobj_slowpath(klass, flags, objspace, cache, FALSE, heap_idx);
-}
-
-VALUE
-rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, bool wb_protected, size_t alloc_size)
-{
- VALUE obj;
- rb_objspace_t *objspace = objspace_ptr;
-
- RB_DEBUG_COUNTER_INC(obj_newobj);
- (void)RB_DEBUG_COUNTER_INC_IF(obj_newobj_wb_unprotected, !wb_protected);
-
- if (RB_UNLIKELY(stress_to_class)) {
- long cnt = RARRAY_LEN(stress_to_class);
- for (long i = 0; i < cnt; i++) {
- if (klass == RARRAY_AREF(stress_to_class, i)) rb_memerror();
- }
- }
-
- size_t heap_idx = heap_idx_for_size(alloc_size);
-
- rb_ractor_newobj_cache_t *cache = (rb_ractor_newobj_cache_t *)cache_ptr;
-
- if (!RB_UNLIKELY(during_gc || ruby_gc_stressful) &&
- wb_protected) {
- obj = newobj_alloc(objspace, cache, heap_idx, false);
- newobj_init(klass, flags, wb_protected, objspace, obj);
- }
- else {
- RB_DEBUG_COUNTER_INC(obj_newobj_slowpath);
-
- obj = wb_protected ?
- newobj_slowpath_wb_protected(klass, flags, objspace, cache, heap_idx) :
- newobj_slowpath_wb_unprotected(klass, flags, objspace, cache, heap_idx);
- }
-
- return newobj_fill(obj, v1, v2, v3);
-}
-
-static int
-ptr_in_page_body_p(const void *ptr, const void *memb)
-{
- struct heap_page *page = *(struct heap_page **)memb;
- uintptr_t p_body = (uintptr_t)page->body;
-
- if ((uintptr_t)ptr >= p_body) {
- return (uintptr_t)ptr < (p_body + HEAP_PAGE_SIZE) ? 0 : 1;
- }
- else {
- return -1;
- }
-}
-
-PUREFUNC(static inline struct heap_page *heap_page_for_ptr(rb_objspace_t *objspace, uintptr_t ptr);)
-static inline struct heap_page *
-heap_page_for_ptr(rb_objspace_t *objspace, uintptr_t ptr)
-{
- struct heap_page **res;
-
- if (ptr < (uintptr_t)heap_pages_lomem ||
- ptr > (uintptr_t)heap_pages_himem) {
- return NULL;
- }
-
- res = bsearch((void *)ptr, rb_darray_ref(objspace->heap_pages.sorted, 0),
- rb_darray_size(objspace->heap_pages.sorted), sizeof(struct heap_page *),
- ptr_in_page_body_p);
-
- if (res) {
- return *res;
- }
- else {
- return NULL;
- }
-}
-
-PUREFUNC(static inline bool is_pointer_to_heap(rb_objspace_t *objspace, const void *ptr);)
-static inline bool
-is_pointer_to_heap(rb_objspace_t *objspace, const void *ptr)
-{
- register uintptr_t p = (uintptr_t)ptr;
- register struct heap_page *page;
-
- RB_DEBUG_COUNTER_INC(gc_isptr_trial);
-
- if (p < heap_pages_lomem || p > heap_pages_himem) return FALSE;
- RB_DEBUG_COUNTER_INC(gc_isptr_range);
-
- if (p % BASE_SLOT_SIZE != 0) return FALSE;
- RB_DEBUG_COUNTER_INC(gc_isptr_align);
-
- page = heap_page_for_ptr(objspace, (uintptr_t)ptr);
- if (page) {
- RB_DEBUG_COUNTER_INC(gc_isptr_maybe);
- if (heap_page_in_global_empty_pages_pool(objspace, page)) {
- return FALSE;
- }
- else {
- if (p < page->start) return FALSE;
- if (p >= page->start + (page->total_slots * page->slot_size)) return FALSE;
- if ((NUM_IN_PAGE(p) * BASE_SLOT_SIZE) % page->slot_size != 0) return FALSE;
-
- return TRUE;
- }
- }
- return FALSE;
-}
-
-bool
-rb_gc_impl_pointer_to_heap_p(void *objspace_ptr, const void *ptr)
-{
- return is_pointer_to_heap(objspace_ptr, ptr);
-}
-
-#define ZOMBIE_OBJ_KEPT_FLAGS (FL_SEEN_OBJ_ID | FL_FINALIZE)
-
-void
-rb_gc_impl_make_zombie(void *objspace_ptr, VALUE obj, void (*dfree)(void *), void *data)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- struct RZombie *zombie = RZOMBIE(obj);
- zombie->basic.flags = T_ZOMBIE | (zombie->basic.flags & ZOMBIE_OBJ_KEPT_FLAGS);
- zombie->dfree = dfree;
- zombie->data = data;
- VALUE prev, next = heap_pages_deferred_final;
- do {
- zombie->next = prev = next;
- next = RUBY_ATOMIC_VALUE_CAS(heap_pages_deferred_final, prev, obj);
- } while (next != prev);
-
- struct heap_page *page = GET_HEAP_PAGE(obj);
- page->final_slots++;
- page->heap->final_slots_count++;
-}
-
-static void
-obj_free_object_id(rb_objspace_t *objspace, VALUE obj)
-{
- st_data_t o = (st_data_t)obj, id;
-
- GC_ASSERT(BUILTIN_TYPE(obj) == T_NONE || FL_TEST(obj, FL_SEEN_OBJ_ID));
- FL_UNSET(obj, FL_SEEN_OBJ_ID);
-
- if (st_delete(objspace->obj_to_id_tbl, &o, &id)) {
- GC_ASSERT(id);
- st_delete(objspace->id_to_obj_tbl, &id, NULL);
- }
- else {
- rb_bug("Object ID seen, but not in mapping table: %s", rb_obj_info(obj));
- }
-}
-
-typedef int each_obj_callback(void *, void *, size_t, void *);
-typedef int each_page_callback(struct heap_page *, void *);
-
-struct each_obj_data {
- rb_objspace_t *objspace;
- bool reenable_incremental;
-
- each_obj_callback *each_obj_callback;
- each_page_callback *each_page_callback;
- void *data;
-
- struct heap_page **pages[HEAP_COUNT];
- size_t pages_counts[HEAP_COUNT];
-};
-
-static VALUE
-objspace_each_objects_ensure(VALUE arg)
-{
- struct each_obj_data *data = (struct each_obj_data *)arg;
- rb_objspace_t *objspace = data->objspace;
-
- /* Reenable incremental GC */
- if (data->reenable_incremental) {
- objspace->flags.dont_incremental = FALSE;
- }
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- struct heap_page **pages = data->pages[i];
- free(pages);
- }
-
- return Qnil;
-}
-
-static VALUE
-objspace_each_objects_try(VALUE arg)
-{
- struct each_obj_data *data = (struct each_obj_data *)arg;
- rb_objspace_t *objspace = data->objspace;
-
- /* Copy pages from all heaps to their respective buffers. */
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- size_t size = heap->total_pages * sizeof(struct heap_page *);
-
- struct heap_page **pages = malloc(size);
- if (!pages) rb_memerror();
-
- /* Set up pages buffer by iterating over all pages in the current eden
- * heap. This will be a snapshot of the state of the heap before we
- * call the callback over each page that exists in this buffer. Thus it
- * is safe for the callback to allocate objects without possibly entering
- * an infinite loop. */
- struct heap_page *page = 0;
- size_t pages_count = 0;
- ccan_list_for_each(&heap->pages, page, page_node) {
- pages[pages_count] = page;
- pages_count++;
- }
- data->pages[i] = pages;
- data->pages_counts[i] = pages_count;
- GC_ASSERT(pages_count == heap->total_pages);
- }
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- size_t pages_count = data->pages_counts[i];
- struct heap_page **pages = data->pages[i];
-
- struct heap_page *page = ccan_list_top(&heap->pages, struct heap_page, page_node);
- for (size_t i = 0; i < pages_count; i++) {
- /* If we have reached the end of the linked list then there are no
- * more pages, so break. */
- if (page == NULL) break;
-
- /* If this page does not match the one in the buffer, then move to
- * the next page in the buffer. */
- if (pages[i] != page) continue;
-
- uintptr_t pstart = (uintptr_t)page->start;
- uintptr_t pend = pstart + (page->total_slots * heap->slot_size);
-
- if (data->each_obj_callback &&
- (*data->each_obj_callback)((void *)pstart, (void *)pend, heap->slot_size, data->data)) {
- break;
- }
- if (data->each_page_callback &&
- (*data->each_page_callback)(page, data->data)) {
- break;
- }
-
- page = ccan_list_next(&heap->pages, page, page_node);
- }
- }
-
- return Qnil;
-}
-
-static void
-objspace_each_exec(bool protected, struct each_obj_data *each_obj_data)
-{
- /* Disable incremental GC */
- rb_objspace_t *objspace = each_obj_data->objspace;
- bool reenable_incremental = FALSE;
- if (protected) {
- reenable_incremental = !objspace->flags.dont_incremental;
-
- gc_rest(objspace);
- objspace->flags.dont_incremental = TRUE;
- }
-
- each_obj_data->reenable_incremental = reenable_incremental;
- memset(&each_obj_data->pages, 0, sizeof(each_obj_data->pages));
- memset(&each_obj_data->pages_counts, 0, sizeof(each_obj_data->pages_counts));
- rb_ensure(objspace_each_objects_try, (VALUE)each_obj_data,
- objspace_each_objects_ensure, (VALUE)each_obj_data);
-}
-
-static void
-objspace_each_objects(rb_objspace_t *objspace, each_obj_callback *callback, void *data, bool protected)
-{
- struct each_obj_data each_obj_data = {
- .objspace = objspace,
- .each_obj_callback = callback,
- .each_page_callback = NULL,
- .data = data,
- };
- objspace_each_exec(protected, &each_obj_data);
-}
-
-void
-rb_gc_impl_each_objects(void *objspace_ptr, each_obj_callback *callback, void *data)
-{
- objspace_each_objects(objspace_ptr, callback, data, TRUE);
-}
-
-#if GC_CAN_COMPILE_COMPACTION
-static void
-objspace_each_pages(rb_objspace_t *objspace, each_page_callback *callback, void *data, bool protected)
-{
- struct each_obj_data each_obj_data = {
- .objspace = objspace,
- .each_obj_callback = NULL,
- .each_page_callback = callback,
- .data = data,
- };
- objspace_each_exec(protected, &each_obj_data);
-}
-#endif
-
-VALUE
-rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
-{
- rb_objspace_t *objspace = objspace_ptr;
- VALUE table;
- st_data_t data;
-
- GC_ASSERT(!OBJ_FROZEN(obj));
-
- RBASIC(obj)->flags |= FL_FINALIZE;
-
- if (st_lookup(finalizer_table, obj, &data)) {
- table = (VALUE)data;
-
- /* avoid duplicate block, table is usually small */
- {
- long len = RARRAY_LEN(table);
- long i;
-
- for (i = 0; i < len; i++) {
- VALUE recv = RARRAY_AREF(table, i);
- if (rb_equal(recv, block)) {
- return recv;
- }
- }
- }
-
- rb_ary_push(table, block);
- }
- else {
- table = rb_ary_new3(1, block);
- rb_obj_hide(table);
- st_add_direct(finalizer_table, obj, table);
- }
-
- return block;
-}
-
-void
-rb_gc_impl_undefine_finalizer(void *objspace_ptr, VALUE obj)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- GC_ASSERT(!OBJ_FROZEN(obj));
-
- st_data_t data = obj;
- st_delete(finalizer_table, &data, 0);
- FL_UNSET(obj, FL_FINALIZE);
-}
-
-void
-rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj)
-{
- rb_objspace_t *objspace = objspace_ptr;
- VALUE table;
- st_data_t data;
-
- if (!FL_TEST(obj, FL_FINALIZE)) return;
-
- if (RB_LIKELY(st_lookup(finalizer_table, obj, &data))) {
- table = (VALUE)data;
- st_insert(finalizer_table, dest, table);
- FL_SET(dest, FL_FINALIZE);
- }
- else {
- rb_bug("rb_gc_copy_finalizer: FL_FINALIZE set but not found in finalizer_table: %s", rb_obj_info(obj));
- }
-}
-
-static VALUE
-get_object_id_in_finalizer(rb_objspace_t *objspace, VALUE obj)
-{
- if (FL_TEST(obj, FL_SEEN_OBJ_ID)) {
- return rb_gc_impl_object_id(objspace, obj);
- }
- else {
- VALUE id = ULL2NUM(objspace->next_object_id);
- objspace->next_object_id += OBJ_ID_INCREMENT;
- return id;
- }
-}
-
-static VALUE
-get_final(long i, void *data)
-{
- VALUE table = (VALUE)data;
-
- return RARRAY_AREF(table, i);
-}
-
-static void
-run_final(rb_objspace_t *objspace, VALUE zombie)
-{
- if (RZOMBIE(zombie)->dfree) {
- RZOMBIE(zombie)->dfree(RZOMBIE(zombie)->data);
- }
-
- st_data_t key = (st_data_t)zombie;
- if (FL_TEST_RAW(zombie, FL_FINALIZE)) {
- FL_UNSET(zombie, FL_FINALIZE);
- st_data_t table;
- if (st_delete(finalizer_table, &key, &table)) {
- rb_gc_run_obj_finalizer(get_object_id_in_finalizer(objspace, zombie), RARRAY_LEN(table), get_final, (void *)table);
- }
- else {
- rb_bug("FL_FINALIZE flag is set, but finalizers are not found");
- }
- }
- else {
- GC_ASSERT(!st_lookup(finalizer_table, key, NULL));
- }
-}
-
-static void
-finalize_list(rb_objspace_t *objspace, VALUE zombie)
-{
- while (zombie) {
- VALUE next_zombie;
- struct heap_page *page;
- asan_unpoison_object(zombie, false);
- next_zombie = RZOMBIE(zombie)->next;
- page = GET_HEAP_PAGE(zombie);
-
- run_final(objspace, zombie);
-
- int lev = rb_gc_vm_lock();
- {
- GC_ASSERT(BUILTIN_TYPE(zombie) == T_ZOMBIE);
- if (FL_TEST(zombie, FL_SEEN_OBJ_ID)) {
- obj_free_object_id(objspace, zombie);
- }
-
- GC_ASSERT(page->heap->final_slots_count > 0);
- GC_ASSERT(page->final_slots > 0);
-
- page->heap->final_slots_count--;
- page->final_slots--;
- page->free_slots++;
- heap_page_add_freeobj(objspace, page, zombie);
- page->heap->total_freed_objects++;
- }
- rb_gc_vm_unlock(lev);
-
- zombie = next_zombie;
- }
-}
-
-static void
-finalize_deferred_heap_pages(rb_objspace_t *objspace)
-{
- VALUE zombie;
- while ((zombie = RUBY_ATOMIC_VALUE_EXCHANGE(heap_pages_deferred_final, 0)) != 0) {
- finalize_list(objspace, zombie);
- }
-}
-
-static void
-finalize_deferred(rb_objspace_t *objspace)
-{
- rb_gc_set_pending_interrupt();
- finalize_deferred_heap_pages(objspace);
- rb_gc_unset_pending_interrupt();
-}
-
-static void
-gc_finalize_deferred(void *dmy)
-{
- rb_objspace_t *objspace = dmy;
- if (RUBY_ATOMIC_EXCHANGE(finalizing, 1)) return;
-
- finalize_deferred(objspace);
- RUBY_ATOMIC_SET(finalizing, 0);
-}
-
-static void
-gc_finalize_deferred_register(rb_objspace_t *objspace)
-{
- /* will enqueue a call to gc_finalize_deferred */
- rb_postponed_job_trigger(objspace->finalize_deferred_pjob);
-}
-
-static int pop_mark_stack(mark_stack_t *stack, VALUE *data);
-
-static void
-gc_abort(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- if (is_incremental_marking(objspace)) {
- /* Remove all objects from the mark stack. */
- VALUE obj;
- while (pop_mark_stack(&objspace->mark_stack, &obj));
-
- objspace->flags.during_incremental_marking = FALSE;
- }
-
- if (is_lazy_sweeping(objspace)) {
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
-
- heap->sweeping_page = NULL;
- struct heap_page *page = NULL;
-
- ccan_list_for_each(&heap->pages, page, page_node) {
- page->flags.before_sweep = false;
- }
- }
- }
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- rgengc_mark_and_rememberset_clear(objspace, heap);
- }
-
- gc_mode_set(objspace, gc_mode_none);
-}
-
-void
-rb_gc_impl_shutdown_free_objects(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- for (size_t i = 0; i < rb_darray_size(objspace->heap_pages.sorted); i++) {
- struct heap_page *page = rb_darray_get(objspace->heap_pages.sorted, i);
- short stride = page->slot_size;
-
- uintptr_t p = (uintptr_t)page->start;
- uintptr_t pend = p + page->total_slots * stride;
- for (; p < pend; p += stride) {
- VALUE vp = (VALUE)p;
- asan_unpoisoning_object(vp) {
- if (RB_BUILTIN_TYPE(vp) != T_NONE) {
- rb_gc_obj_free(objspace, vp);
- }
- }
- }
- }
-}
-
-static int
-rb_gc_impl_shutdown_call_finalizer_i(st_data_t key, st_data_t val, st_data_t data)
-{
- rb_objspace_t *objspace = (rb_objspace_t *)data;
- VALUE obj = (VALUE)key;
- VALUE table = (VALUE)val;
-
- GC_ASSERT(RB_FL_TEST(obj, FL_FINALIZE));
- GC_ASSERT(RB_BUILTIN_TYPE(val) == T_ARRAY);
-
- rb_gc_run_obj_finalizer(rb_gc_impl_object_id(objspace, obj), RARRAY_LEN(table), get_final, (void *)table);
-
- FL_UNSET(obj, FL_FINALIZE);
-
- return ST_DELETE;
-}
-
-void
-rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
-#if RGENGC_CHECK_MODE >= 2
- gc_verify_internal_consistency(objspace);
-#endif
-
- /* prohibit incremental GC */
- objspace->flags.dont_incremental = 1;
-
- if (RUBY_ATOMIC_EXCHANGE(finalizing, 1)) {
- /* Abort incremental marking and lazy sweeping to speed up shutdown. */
- gc_abort(objspace);
- dont_gc_on();
- return;
- }
-
- while (finalizer_table->num_entries) {
- st_foreach(finalizer_table, rb_gc_impl_shutdown_call_finalizer_i, (st_data_t)objspace);
- }
-
- /* run finalizers */
- finalize_deferred(objspace);
- GC_ASSERT(heap_pages_deferred_final == 0);
-
- /* Abort incremental marking and lazy sweeping to speed up shutdown. */
- gc_abort(objspace);
-
- /* prohibit GC because force T_DATA finalizers can break an object graph consistency */
- dont_gc_on();
-
- /* running data/file finalizers are part of garbage collection */
- unsigned int lock_lev;
- gc_enter(objspace, gc_enter_event_finalizer, &lock_lev);
-
- /* run data/file object's finalizers */
- for (size_t i = 0; i < rb_darray_size(objspace->heap_pages.sorted); i++) {
- struct heap_page *page = rb_darray_get(objspace->heap_pages.sorted, i);
- short stride = page->slot_size;
-
- uintptr_t p = (uintptr_t)page->start;
- uintptr_t pend = p + page->total_slots * stride;
- for (; p < pend; p += stride) {
- VALUE vp = (VALUE)p;
- asan_unpoisoning_object(vp) {
- if (rb_gc_shutdown_call_finalizer_p(vp)) {
- rb_gc_obj_free(objspace, vp);
- }
- }
- }
- }
-
- gc_exit(objspace, gc_enter_event_finalizer, &lock_lev);
-
- finalize_deferred_heap_pages(objspace);
-
- st_free_table(finalizer_table);
- finalizer_table = 0;
- RUBY_ATOMIC_SET(finalizing, 0);
-}
-
-void
-rb_gc_impl_each_object(void *objspace_ptr, void (*func)(VALUE obj, void *data), void *data)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- for (size_t i = 0; i < rb_darray_size(objspace->heap_pages.sorted); i++) {
- struct heap_page *page = rb_darray_get(objspace->heap_pages.sorted, i);
- short stride = page->slot_size;
-
- uintptr_t p = (uintptr_t)page->start;
- uintptr_t pend = p + page->total_slots * stride;
- for (; p < pend; p += stride) {
- VALUE obj = (VALUE)p;
-
- asan_unpoisoning_object(obj) {
- func(obj, data);
- }
- }
- }
-}
-
-/*
- ------------------------ Garbage Collection ------------------------
-*/
-
-/* Sweeping */
-
-static size_t
-objspace_available_slots(rb_objspace_t *objspace)
-{
- size_t total_slots = 0;
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- total_slots += heap->total_slots;
- }
- return total_slots;
-}
-
-static size_t
-objspace_live_slots(rb_objspace_t *objspace)
-{
- return total_allocated_objects(objspace) - total_freed_objects(objspace) - total_final_slots_count(objspace);
-}
-
-static size_t
-objspace_free_slots(rb_objspace_t *objspace)
-{
- return objspace_available_slots(objspace) - objspace_live_slots(objspace) - total_final_slots_count(objspace);
-}
-
-static void
-gc_setup_mark_bits(struct heap_page *page)
-{
- /* copy oldgen bitmap to mark bitmap */
- memcpy(&page->mark_bits[0], &page->uncollectible_bits[0], HEAP_PAGE_BITMAP_SIZE);
-}
-
-static int gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj);
-static VALUE gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, size_t slot_size);
-
-#if defined(_WIN32)
-enum {HEAP_PAGE_LOCK = PAGE_NOACCESS, HEAP_PAGE_UNLOCK = PAGE_READWRITE};
-
-static BOOL
-protect_page_body(struct heap_page_body *body, DWORD protect)
-{
- DWORD old_protect;
- return VirtualProtect(body, HEAP_PAGE_SIZE, protect, &old_protect) != 0;
-}
-#else
-enum {HEAP_PAGE_LOCK = PROT_NONE, HEAP_PAGE_UNLOCK = PROT_READ | PROT_WRITE};
-#define protect_page_body(body, protect) !mprotect((body), HEAP_PAGE_SIZE, (protect))
-#endif
-
-static void
-lock_page_body(rb_objspace_t *objspace, struct heap_page_body *body)
-{
- if (!protect_page_body(body, HEAP_PAGE_LOCK)) {
- rb_bug("Couldn't protect page %p, errno: %s", (void *)body, strerror(errno));
- }
- else {
- gc_report(5, objspace, "Protecting page in move %p\n", (void *)body);
- }
-}
-
-static void
-unlock_page_body(rb_objspace_t *objspace, struct heap_page_body *body)
-{
- if (!protect_page_body(body, HEAP_PAGE_UNLOCK)) {
- rb_bug("Couldn't unprotect page %p, errno: %s", (void *)body, strerror(errno));
- }
- else {
- gc_report(5, objspace, "Unprotecting page in move %p\n", (void *)body);
- }
-}
-
-static bool
-try_move(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *free_page, VALUE src)
-{
- GC_ASSERT(gc_is_moveable_obj(objspace, src));
-
- struct heap_page *src_page = GET_HEAP_PAGE(src);
- if (!free_page) {
- return false;
- }
-
- /* We should return true if either src is successfully moved, or src is
- * unmoveable. A false return will cause the sweeping cursor to be
- * incremented to the next page, and src will attempt to move again */
- GC_ASSERT(RVALUE_MARKED(objspace, src));
-
- asan_unlock_freelist(free_page);
- VALUE dest = (VALUE)free_page->freelist;
- asan_lock_freelist(free_page);
- asan_unpoison_object(dest, false);
- if (!dest) {
- /* if we can't get something from the freelist then the page must be
- * full */
- return false;
- }
- asan_unlock_freelist(free_page);
- free_page->freelist = ((struct free_slot *)dest)->next;
- asan_lock_freelist(free_page);
-
- GC_ASSERT(RB_BUILTIN_TYPE(dest) == T_NONE);
-
- if (src_page->slot_size > free_page->slot_size) {
- objspace->rcompactor.moved_down_count_table[BUILTIN_TYPE(src)]++;
- }
- else if (free_page->slot_size > src_page->slot_size) {
- objspace->rcompactor.moved_up_count_table[BUILTIN_TYPE(src)]++;
- }
- objspace->rcompactor.moved_count_table[BUILTIN_TYPE(src)]++;
- objspace->rcompactor.total_moved++;
-
- gc_move(objspace, src, dest, src_page->slot_size, free_page->slot_size);
- gc_pin(objspace, src);
- free_page->free_slots--;
-
- return true;
-}
-
-static void
-gc_unprotect_pages(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- struct heap_page *cursor = heap->compact_cursor;
-
- while (cursor) {
- unlock_page_body(objspace, cursor->body);
- cursor = ccan_list_next(&heap->pages, cursor, page_node);
- }
-}
-
-static void gc_update_references(rb_objspace_t *objspace);
-#if GC_CAN_COMPILE_COMPACTION
-static void invalidate_moved_page(rb_objspace_t *objspace, struct heap_page *page);
-#endif
-
-#if defined(__MINGW32__) || defined(_WIN32)
-# define GC_COMPACTION_SUPPORTED 1
-#else
-/* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for
- * the read barrier, so we must disable compaction. */
-# define GC_COMPACTION_SUPPORTED (GC_CAN_COMPILE_COMPACTION && HEAP_PAGE_ALLOC_USE_MMAP)
-#endif
-
-#if GC_CAN_COMPILE_COMPACTION
-static void
-read_barrier_handler(uintptr_t original_address)
-{
- VALUE obj;
- rb_objspace_t *objspace = (rb_objspace_t *)rb_gc_get_objspace();
-
- /* Calculate address aligned to slots. */
- uintptr_t address = original_address - (original_address % BASE_SLOT_SIZE);
-
- obj = (VALUE)address;
-
- struct heap_page_body *page_body = GET_PAGE_BODY(obj);
-
- /* If the page_body is NULL, then mprotect cannot handle it and will crash
- * with "Cannot allocate memory". */
- if (page_body == NULL) {
- rb_bug("read_barrier_handler: segmentation fault at %p", (void *)original_address);
- }
-
- int lev = rb_gc_vm_lock();
- {
- unlock_page_body(objspace, page_body);
-
- objspace->profile.read_barrier_faults++;
-
- invalidate_moved_page(objspace, GET_HEAP_PAGE(obj));
- }
- rb_gc_vm_unlock(lev);
-}
-#endif
-
-#if !GC_CAN_COMPILE_COMPACTION
-static void
-uninstall_handlers(void)
-{
- /* no-op */
-}
-
-static void
-install_handlers(void)
-{
- /* no-op */
-}
-#elif defined(_WIN32)
-static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
-typedef void (*signal_handler)(int);
-static signal_handler old_sigsegv_handler;
-
-static LONG WINAPI
-read_barrier_signal(EXCEPTION_POINTERS *info)
-{
- /* EXCEPTION_ACCESS_VIOLATION is what's raised by access to protected pages */
- if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
- /* > The second array element specifies the virtual address of the inaccessible data.
- * https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record
- *
- * Use this address to invalidate the page */
- read_barrier_handler((uintptr_t)info->ExceptionRecord->ExceptionInformation[1]);
- return EXCEPTION_CONTINUE_EXECUTION;
- }
- else {
- return EXCEPTION_CONTINUE_SEARCH;
- }
-}
-
-static void
-uninstall_handlers(void)
-{
- signal(SIGSEGV, old_sigsegv_handler);
- SetUnhandledExceptionFilter(old_handler);
-}
-
-static void
-install_handlers(void)
-{
- /* Remove SEGV handler so that the Unhandled Exception Filter handles it */
- old_sigsegv_handler = signal(SIGSEGV, NULL);
- /* Unhandled Exception Filter has access to the violation address similar
- * to si_addr from sigaction */
- old_handler = SetUnhandledExceptionFilter(read_barrier_signal);
-}
-#else
-static struct sigaction old_sigbus_handler;
-static struct sigaction old_sigsegv_handler;
-
-#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS
-static exception_mask_t old_exception_masks[32];
-static mach_port_t old_exception_ports[32];
-static exception_behavior_t old_exception_behaviors[32];
-static thread_state_flavor_t old_exception_flavors[32];
-static mach_msg_type_number_t old_exception_count;
-
-static void
-disable_mach_bad_access_exc(void)
-{
- old_exception_count = sizeof(old_exception_masks) / sizeof(old_exception_masks[0]);
- task_swap_exception_ports(
- mach_task_self(), EXC_MASK_BAD_ACCESS,
- MACH_PORT_NULL, EXCEPTION_DEFAULT, 0,
- old_exception_masks, &old_exception_count,
- old_exception_ports, old_exception_behaviors, old_exception_flavors
- );
-}
-
-static void
-restore_mach_bad_access_exc(void)
-{
- for (mach_msg_type_number_t i = 0; i < old_exception_count; i++) {
- task_set_exception_ports(
- mach_task_self(),
- old_exception_masks[i], old_exception_ports[i],
- old_exception_behaviors[i], old_exception_flavors[i]
- );
- }
-}
-#endif
-
-static void
-read_barrier_signal(int sig, siginfo_t *info, void *data)
-{
- // setup SEGV/BUS handlers for errors
- struct sigaction prev_sigbus, prev_sigsegv;
- sigaction(SIGBUS, &old_sigbus_handler, &prev_sigbus);
- sigaction(SIGSEGV, &old_sigsegv_handler, &prev_sigsegv);
-
- // enable SIGBUS/SEGV
- sigset_t set, prev_set;
- sigemptyset(&set);
- sigaddset(&set, SIGBUS);
- sigaddset(&set, SIGSEGV);
- sigprocmask(SIG_UNBLOCK, &set, &prev_set);
-#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS
- disable_mach_bad_access_exc();
-#endif
- // run handler
- read_barrier_handler((uintptr_t)info->si_addr);
-
- // reset SEGV/BUS handlers
-#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS
- restore_mach_bad_access_exc();
-#endif
- sigaction(SIGBUS, &prev_sigbus, NULL);
- sigaction(SIGSEGV, &prev_sigsegv, NULL);
- sigprocmask(SIG_SETMASK, &prev_set, NULL);
-}
-
-static void
-uninstall_handlers(void)
-{
-#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS
- restore_mach_bad_access_exc();
-#endif
- sigaction(SIGBUS, &old_sigbus_handler, NULL);
- sigaction(SIGSEGV, &old_sigsegv_handler, NULL);
-}
-
-static void
-install_handlers(void)
-{
- struct sigaction action;
- memset(&action, 0, sizeof(struct sigaction));
- sigemptyset(&action.sa_mask);
- action.sa_sigaction = read_barrier_signal;
- action.sa_flags = SA_SIGINFO | SA_ONSTACK;
-
- sigaction(SIGBUS, &action, &old_sigbus_handler);
- sigaction(SIGSEGV, &action, &old_sigsegv_handler);
-#ifdef HAVE_MACH_TASK_EXCEPTION_PORTS
- disable_mach_bad_access_exc();
-#endif
-}
-#endif
-
-static void
-gc_compact_finish(rb_objspace_t *objspace)
-{
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- gc_unprotect_pages(objspace, heap);
- }
-
- uninstall_handlers();
-
- gc_update_references(objspace);
- objspace->profile.compact_count++;
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- heap->compact_cursor = NULL;
- heap->free_pages = NULL;
- heap->compact_cursor_index = 0;
- }
-
- if (gc_prof_enabled(objspace)) {
- gc_profile_record *record = gc_prof_record(objspace);
- record->moved_objects = objspace->rcompactor.total_moved - record->moved_objects;
- }
- objspace->flags.during_compacting = FALSE;
-}
-
-struct gc_sweep_context {
- struct heap_page *page;
- int final_slots;
- int freed_slots;
- int empty_slots;
-};
-
-static inline void
-gc_sweep_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bitset, struct gc_sweep_context *ctx)
-{
- struct heap_page *sweep_page = ctx->page;
- short slot_size = sweep_page->slot_size;
- short slot_bits = slot_size / BASE_SLOT_SIZE;
- GC_ASSERT(slot_bits > 0);
-
- do {
- VALUE vp = (VALUE)p;
- GC_ASSERT(vp % BASE_SLOT_SIZE == 0);
-
- asan_unpoison_object(vp, false);
- if (bitset & 1) {
- switch (BUILTIN_TYPE(vp)) {
- default: /* majority case */
- gc_report(2, objspace, "page_sweep: free %p\n", (void *)p);
-#if RGENGC_CHECK_MODE
- if (!is_full_marking(objspace)) {
- if (RVALUE_OLD_P(objspace, vp)) rb_bug("page_sweep: %p - old while minor GC.", (void *)p);
- if (RVALUE_REMEMBERED(objspace, vp)) rb_bug("page_sweep: %p - remembered.", (void *)p);
- }
-#endif
-
- if (RVALUE_WB_UNPROTECTED(objspace, vp)) CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(vp), vp);
-
-#if RGENGC_CHECK_MODE
-#define CHECK(x) if (x(objspace, vp) != FALSE) rb_bug("obj_free: " #x "(%s) != FALSE", rb_obj_info(vp))
- CHECK(RVALUE_WB_UNPROTECTED);
- CHECK(RVALUE_MARKED);
- CHECK(RVALUE_MARKING);
- CHECK(RVALUE_UNCOLLECTIBLE);
-#undef CHECK
-#endif
-
- rb_gc_event_hook(vp, RUBY_INTERNAL_EVENT_FREEOBJ);
-
- bool has_object_id = FL_TEST(vp, FL_SEEN_OBJ_ID);
- if (rb_gc_obj_free(objspace, vp)) {
- if (has_object_id) {
- obj_free_object_id(objspace, vp);
- }
- // always add free slots back to the swept pages freelist,
- // so that if we're compacting, we can re-use the slots
- (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, BASE_SLOT_SIZE);
- heap_page_add_freeobj(objspace, sweep_page, vp);
- gc_report(3, objspace, "page_sweep: %s is added to freelist\n", rb_obj_info(vp));
- ctx->freed_slots++;
- }
- else {
- ctx->final_slots++;
- }
- break;
-
- case T_MOVED:
- if (objspace->flags.during_compacting) {
- /* The sweep cursor shouldn't have made it to any
- * T_MOVED slots while the compact flag is enabled.
- * The sweep cursor and compact cursor move in
- * opposite directions, and when they meet references will
- * get updated and "during_compacting" should get disabled */
- rb_bug("T_MOVED shouldn't be seen until compaction is finished");
- }
- gc_report(3, objspace, "page_sweep: %s is added to freelist\n", rb_obj_info(vp));
- ctx->empty_slots++;
- heap_page_add_freeobj(objspace, sweep_page, vp);
- break;
- case T_ZOMBIE:
- /* already counted */
- break;
- case T_NONE:
- ctx->empty_slots++; /* already freed */
- break;
- }
- }
- p += slot_size;
- bitset >>= slot_bits;
- } while (bitset);
-}
-
-static inline void
-gc_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct gc_sweep_context *ctx)
-{
- struct heap_page *sweep_page = ctx->page;
- GC_ASSERT(sweep_page->heap == heap);
-
- uintptr_t p;
- bits_t *bits, bitset;
-
- gc_report(2, objspace, "page_sweep: start.\n");
-
-#if RGENGC_CHECK_MODE
- if (!objspace->flags.immediate_sweep) {
- GC_ASSERT(sweep_page->flags.before_sweep == TRUE);
- }
-#endif
- sweep_page->flags.before_sweep = FALSE;
- sweep_page->free_slots = 0;
-
- p = (uintptr_t)sweep_page->start;
- bits = sweep_page->mark_bits;
-
- int page_rvalue_count = sweep_page->total_slots * (sweep_page->slot_size / BASE_SLOT_SIZE);
- int out_of_range_bits = (NUM_IN_PAGE(p) + page_rvalue_count) % BITS_BITLENGTH;
- if (out_of_range_bits != 0) { // sizeof(RVALUE) == 64
- bits[BITMAP_INDEX(p) + page_rvalue_count / BITS_BITLENGTH] |= ~(((bits_t)1 << out_of_range_bits) - 1);
- }
-
- /* The last bitmap plane may not be used if the last plane does not
- * have enough space for the slot_size. In that case, the last plane must
- * be skipped since none of the bits will be set. */
- int bitmap_plane_count = CEILDIV(NUM_IN_PAGE(p) + page_rvalue_count, BITS_BITLENGTH);
- GC_ASSERT(bitmap_plane_count == HEAP_PAGE_BITMAP_LIMIT - 1 ||
- bitmap_plane_count == HEAP_PAGE_BITMAP_LIMIT);
-
- // Skip out of range slots at the head of the page
- bitset = ~bits[0];
- bitset >>= NUM_IN_PAGE(p);
- if (bitset) {
- gc_sweep_plane(objspace, heap, p, bitset, ctx);
- }
- p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
-
- for (int i = 1; i < bitmap_plane_count; i++) {
- bitset = ~bits[i];
- if (bitset) {
- gc_sweep_plane(objspace, heap, p, bitset, ctx);
- }
- p += BITS_BITLENGTH * BASE_SLOT_SIZE;
- }
-
- if (!heap->compact_cursor) {
- gc_setup_mark_bits(sweep_page);
- }
-
-#if GC_PROFILE_MORE_DETAIL
- if (gc_prof_enabled(objspace)) {
- gc_profile_record *record = gc_prof_record(objspace);
- record->removing_objects += ctx->final_slots + ctx->freed_slots;
- record->empty_objects += ctx->empty_slots;
- }
-#endif
- if (0) fprintf(stderr, "gc_sweep_page(%"PRIdSIZE"): total_slots: %d, freed_slots: %d, empty_slots: %d, final_slots: %d\n",
- rb_gc_count(),
- sweep_page->total_slots,
- ctx->freed_slots, ctx->empty_slots, ctx->final_slots);
-
- sweep_page->free_slots += ctx->freed_slots + ctx->empty_slots;
- sweep_page->heap->total_freed_objects += ctx->freed_slots;
-
- if (heap_pages_deferred_final && !finalizing) {
- gc_finalize_deferred_register(objspace);
- }
-
-#if RGENGC_CHECK_MODE
- short freelist_len = 0;
- asan_unlock_freelist(sweep_page);
- struct free_slot *ptr = sweep_page->freelist;
- while (ptr) {
- freelist_len++;
- ptr = ptr->next;
- }
- asan_lock_freelist(sweep_page);
- if (freelist_len != sweep_page->free_slots) {
- rb_bug("inconsistent freelist length: expected %d but was %d", sweep_page->free_slots, freelist_len);
- }
-#endif
-
- gc_report(2, objspace, "page_sweep: end.\n");
-}
-
-static const char *
-gc_mode_name(enum gc_mode mode)
-{
- switch (mode) {
- case gc_mode_none: return "none";
- case gc_mode_marking: return "marking";
- case gc_mode_sweeping: return "sweeping";
- case gc_mode_compacting: return "compacting";
- default: rb_bug("gc_mode_name: unknown mode: %d", (int)mode);
- }
-}
-
-static void
-gc_mode_transition(rb_objspace_t *objspace, enum gc_mode mode)
-{
-#if RGENGC_CHECK_MODE
- enum gc_mode prev_mode = gc_mode(objspace);
- switch (prev_mode) {
- case gc_mode_none: GC_ASSERT(mode == gc_mode_marking); break;
- case gc_mode_marking: GC_ASSERT(mode == gc_mode_sweeping); break;
- case gc_mode_sweeping: GC_ASSERT(mode == gc_mode_none || mode == gc_mode_compacting); break;
- case gc_mode_compacting: GC_ASSERT(mode == gc_mode_none); break;
- }
-#endif
- if (0) fprintf(stderr, "gc_mode_transition: %s->%s\n", gc_mode_name(gc_mode(objspace)), gc_mode_name(mode));
- gc_mode_set(objspace, mode);
-}
-
-static void
-heap_page_freelist_append(struct heap_page *page, struct free_slot *freelist)
-{
- if (freelist) {
- asan_unlock_freelist(page);
- if (page->freelist) {
- struct free_slot *p = page->freelist;
- asan_unpoison_object((VALUE)p, false);
- while (p->next) {
- struct free_slot *prev = p;
- p = p->next;
- asan_poison_object((VALUE)prev);
- asan_unpoison_object((VALUE)p, false);
- }
- p->next = freelist;
- asan_poison_object((VALUE)p);
- }
- else {
- page->freelist = freelist;
- }
- asan_lock_freelist(page);
- }
-}
-
-static void
-gc_sweep_start_heap(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- heap->sweeping_page = ccan_list_top(&heap->pages, struct heap_page, page_node);
- heap->free_pages = NULL;
- heap->pooled_pages = NULL;
- if (!objspace->flags.immediate_sweep) {
- struct heap_page *page = NULL;
-
- ccan_list_for_each(&heap->pages, page, page_node) {
- page->flags.before_sweep = TRUE;
- }
- }
-}
-
-#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 4
-__attribute__((noinline))
-#endif
-
-#if GC_CAN_COMPILE_COMPACTION
-static void gc_sort_heap_by_compare_func(rb_objspace_t *objspace, gc_compact_compare_func compare_func);
-static int compare_pinned_slots(const void *left, const void *right, void *d);
-#endif
-
-static void
-gc_ractor_newobj_cache_clear(void *c, void *data)
-{
- rb_ractor_newobj_cache_t *newobj_cache = c;
-
- newobj_cache->incremental_mark_step_allocated_slots = 0;
-
- for (size_t heap_idx = 0; heap_idx < HEAP_COUNT; heap_idx++) {
- rb_ractor_newobj_heap_cache_t *cache = &newobj_cache->heap_caches[heap_idx];
-
- struct heap_page *page = cache->using_page;
- struct free_slot *freelist = cache->freelist;
- RUBY_DEBUG_LOG("ractor using_page:%p freelist:%p", (void *)page, (void *)freelist);
-
- heap_page_freelist_append(page, freelist);
-
- cache->using_page = NULL;
- cache->freelist = NULL;
- }
-}
-
-static void
-gc_sweep_start(rb_objspace_t *objspace)
-{
- gc_mode_transition(objspace, gc_mode_sweeping);
- objspace->rincgc.pooled_slots = 0;
- objspace->heap_pages.allocatable_slots = 0;
-
-#if GC_CAN_COMPILE_COMPACTION
- if (objspace->flags.during_compacting) {
- gc_sort_heap_by_compare_func(
- objspace,
- objspace->rcompactor.compare_func ? objspace->rcompactor.compare_func : compare_pinned_slots
- );
- }
-#endif
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- gc_sweep_start_heap(objspace, heap);
-
- /* We should call gc_sweep_finish_heap for size pools with no pages. */
- if (heap->sweeping_page == NULL) {
- GC_ASSERT(heap->total_pages == 0);
- GC_ASSERT(heap->total_slots == 0);
- gc_sweep_finish_heap(objspace, heap);
- }
- }
-
- rb_gc_ractor_newobj_cache_foreach(gc_ractor_newobj_cache_clear, NULL);
-}
-
-static void
-gc_sweep_finish_heap(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- size_t total_slots = heap->total_slots;
- size_t swept_slots = heap->freed_slots + heap->empty_slots;
-
- size_t init_slots = gc_params.heap_init_slots[heap - heaps];
- size_t min_free_slots = (size_t)(MAX(total_slots, init_slots) * gc_params.heap_free_slots_min_ratio);
-
- if (swept_slots < min_free_slots &&
- /* The heap is a growth heap if it freed more slots than had empty slots. */
- (heap->empty_slots == 0 || heap->freed_slots > heap->empty_slots)) {
- /* If we don't have enough slots and we have pages on the tomb heap, move
- * pages from the tomb heap to the eden heap. This may prevent page
- * creation thrashing (frequently allocating and deallocting pages) and
- * GC thrashing (running GC more frequently than required). */
- struct heap_page *resurrected_page;
- while (swept_slots < min_free_slots &&
- (resurrected_page = heap_page_resurrect(objspace))) {
- heap_add_page(objspace, heap, resurrected_page);
- heap_add_freepage(heap, resurrected_page);
-
- swept_slots += resurrected_page->free_slots;
- }
-
- if (swept_slots < min_free_slots) {
- /* Grow this heap if we are in a major GC or if we haven't run at least
- * RVALUE_OLD_AGE minor GC since the last major GC. */
- if (is_full_marking(objspace) ||
- objspace->profile.count - objspace->rgengc.last_major_gc < RVALUE_OLD_AGE) {
- heap_allocatable_slots_expand(objspace, heap, swept_slots, heap->total_slots);
- }
- else {
- gc_needs_major_flags |= GPR_FLAG_MAJOR_BY_NOFREE;
- heap->force_major_gc_count++;
- }
- }
- }
-}
-
-static void
-gc_sweep_finish(rb_objspace_t *objspace)
-{
- gc_report(1, objspace, "gc_sweep_finish\n");
-
- gc_prof_set_heap_info(objspace);
- heap_pages_free_unused_pages(objspace);
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
-
- heap->freed_slots = 0;
- heap->empty_slots = 0;
-
- if (!will_be_incremental_marking(objspace)) {
- struct heap_page *end_page = heap->free_pages;
- if (end_page) {
- while (end_page->free_next) end_page = end_page->free_next;
- end_page->free_next = heap->pooled_pages;
- }
- else {
- heap->free_pages = heap->pooled_pages;
- }
- heap->pooled_pages = NULL;
- objspace->rincgc.pooled_slots = 0;
- }
- }
-
- rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_END_SWEEP);
- gc_mode_transition(objspace, gc_mode_none);
-
-#if RGENGC_CHECK_MODE >= 2
- gc_verify_internal_consistency(objspace);
-#endif
-}
-
-static int
-gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- struct heap_page *sweep_page = heap->sweeping_page;
- int unlink_limit = GC_SWEEP_PAGES_FREEABLE_PER_STEP;
- int swept_slots = 0;
- int pooled_slots = 0;
-
- if (sweep_page == NULL) return FALSE;
-
-#if GC_ENABLE_LAZY_SWEEP
- gc_prof_sweep_timer_start(objspace);
-#endif
-
- do {
- RUBY_DEBUG_LOG("sweep_page:%p", (void *)sweep_page);
-
- struct gc_sweep_context ctx = {
- .page = sweep_page,
- .final_slots = 0,
- .freed_slots = 0,
- .empty_slots = 0,
- };
- gc_sweep_page(objspace, heap, &ctx);
- int free_slots = ctx.freed_slots + ctx.empty_slots;
-
- heap->sweeping_page = ccan_list_next(&heap->pages, sweep_page, page_node);
-
- if (free_slots == sweep_page->total_slots &&
- heap_pages_freeable_pages > 0 &&
- unlink_limit > 0) {
- heap_pages_freeable_pages--;
- unlink_limit--;
- /* There are no living objects, so move this page to the global empty pages. */
- heap_unlink_page(objspace, heap, sweep_page);
-
- sweep_page->start = 0;
- sweep_page->total_slots = 0;
- sweep_page->slot_size = 0;
- sweep_page->heap = NULL;
- sweep_page->free_slots = 0;
-
- asan_unlock_freelist(sweep_page);
- sweep_page->freelist = NULL;
- asan_lock_freelist(sweep_page);
-
- asan_poison_memory_region(sweep_page->body, HEAP_PAGE_SIZE);
-
- objspace->empty_pages_count++;
- sweep_page->free_next = objspace->empty_pages;
- objspace->empty_pages = sweep_page;
- }
- else if (free_slots > 0) {
- heap->freed_slots += ctx.freed_slots;
- heap->empty_slots += ctx.empty_slots;
-
- if (pooled_slots < GC_INCREMENTAL_SWEEP_POOL_SLOT_COUNT) {
- heap_add_poolpage(objspace, heap, sweep_page);
- pooled_slots += free_slots;
- }
- else {
- heap_add_freepage(heap, sweep_page);
- swept_slots += free_slots;
- if (swept_slots > GC_INCREMENTAL_SWEEP_SLOT_COUNT) {
- break;
- }
- }
- }
- else {
- sweep_page->free_next = NULL;
- }
- } while ((sweep_page = heap->sweeping_page));
-
- if (!heap->sweeping_page) {
- gc_sweep_finish_heap(objspace, heap);
-
- if (!has_sweeping_pages(objspace)) {
- gc_sweep_finish(objspace);
- }
- }
-
-#if GC_ENABLE_LAZY_SWEEP
- gc_prof_sweep_timer_stop(objspace);
-#endif
-
- return heap->free_pages != NULL;
-}
-
-static void
-gc_sweep_rest(rb_objspace_t *objspace)
-{
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
-
- while (heap->sweeping_page) {
- gc_sweep_step(objspace, heap);
- }
- }
-}
-
-static void
-gc_sweep_continue(rb_objspace_t *objspace, rb_heap_t *sweep_heap)
-{
- GC_ASSERT(dont_gc_val() == FALSE || objspace->profile.latest_gc_info & GPR_FLAG_METHOD);
- if (!GC_ENABLE_LAZY_SWEEP) return;
-
- gc_sweeping_enter(objspace);
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- if (!gc_sweep_step(objspace, heap)) {
- /* sweep_heap requires a free slot but sweeping did not yield any
- * and we cannot allocate a new page. */
- if (heap == sweep_heap && objspace->heap_pages.allocatable_slots == 0) {
- /* Not allowed to create a new page so finish sweeping. */
- gc_sweep_rest(objspace);
- break;
- }
- }
- }
-
- gc_sweeping_exit(objspace);
-}
-
-VALUE
-rb_gc_impl_location(void *objspace_ptr, VALUE value)
-{
- VALUE destination;
-
- if (!SPECIAL_CONST_P(value)) {
- asan_unpoisoning_object(value) {
- if (BUILTIN_TYPE(value) == T_MOVED) {
- destination = (VALUE)RMOVED(value)->destination;
- GC_ASSERT(BUILTIN_TYPE(destination) != T_NONE);
- }
- else {
- destination = value;
- }
- }
- }
- else {
- destination = value;
- }
-
- return destination;
-}
-
-#if GC_CAN_COMPILE_COMPACTION
-static void
-invalidate_moved_plane(rb_objspace_t *objspace, struct heap_page *page, uintptr_t p, bits_t bitset)
-{
- if (bitset) {
- do {
- if (bitset & 1) {
- VALUE forwarding_object = (VALUE)p;
- VALUE object;
-
- if (BUILTIN_TYPE(forwarding_object) == T_MOVED) {
- GC_ASSERT(RVALUE_PINNED(objspace, forwarding_object));
- GC_ASSERT(!RVALUE_MARKED(objspace, forwarding_object));
-
- CLEAR_IN_BITMAP(GET_HEAP_PINNED_BITS(forwarding_object), forwarding_object);
-
- object = rb_gc_impl_location(objspace, forwarding_object);
-
- uint32_t original_shape_id = 0;
- if (RB_TYPE_P(object, T_OBJECT)) {
- original_shape_id = RMOVED(forwarding_object)->original_shape_id;
- }
-
- gc_move(objspace, object, forwarding_object, GET_HEAP_PAGE(object)->slot_size, page->slot_size);
- /* forwarding_object is now our actual object, and "object"
- * is the free slot for the original page */
-
- if (original_shape_id) {
- rb_gc_set_shape(forwarding_object, original_shape_id);
- }
-
- struct heap_page *orig_page = GET_HEAP_PAGE(object);
- orig_page->free_slots++;
- heap_page_add_freeobj(objspace, orig_page, object);
-
- GC_ASSERT(RVALUE_MARKED(objspace, forwarding_object));
- GC_ASSERT(BUILTIN_TYPE(forwarding_object) != T_MOVED);
- GC_ASSERT(BUILTIN_TYPE(forwarding_object) != T_NONE);
- }
- }
- p += BASE_SLOT_SIZE;
- bitset >>= 1;
- } while (bitset);
- }
-}
-
-static void
-invalidate_moved_page(rb_objspace_t *objspace, struct heap_page *page)
-{
- int i;
- bits_t *mark_bits, *pin_bits;
- bits_t bitset;
-
- mark_bits = page->mark_bits;
- pin_bits = page->pinned_bits;
-
- uintptr_t p = page->start;
-
- // Skip out of range slots at the head of the page
- bitset = pin_bits[0] & ~mark_bits[0];
- bitset >>= NUM_IN_PAGE(p);
- invalidate_moved_plane(objspace, page, p, bitset);
- p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
-
- for (i=1; i < HEAP_PAGE_BITMAP_LIMIT; i++) {
- /* Moved objects are pinned but never marked. We reuse the pin bits
- * to indicate there is a moved object in this slot. */
- bitset = pin_bits[i] & ~mark_bits[i];
-
- invalidate_moved_plane(objspace, page, p, bitset);
- p += BITS_BITLENGTH * BASE_SLOT_SIZE;
- }
-}
-#endif
-
-static void
-gc_compact_start(rb_objspace_t *objspace)
-{
- struct heap_page *page = NULL;
- gc_mode_transition(objspace, gc_mode_compacting);
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- ccan_list_for_each(&heap->pages, page, page_node) {
- page->flags.before_sweep = TRUE;
- }
-
- heap->compact_cursor = ccan_list_tail(&heap->pages, struct heap_page, page_node);
- heap->compact_cursor_index = 0;
- }
-
- if (gc_prof_enabled(objspace)) {
- gc_profile_record *record = gc_prof_record(objspace);
- record->moved_objects = objspace->rcompactor.total_moved;
- }
-
- memset(objspace->rcompactor.considered_count_table, 0, T_MASK * sizeof(size_t));
- memset(objspace->rcompactor.moved_count_table, 0, T_MASK * sizeof(size_t));
- memset(objspace->rcompactor.moved_up_count_table, 0, T_MASK * sizeof(size_t));
- memset(objspace->rcompactor.moved_down_count_table, 0, T_MASK * sizeof(size_t));
-
- /* Set up read barrier for pages containing MOVED objects */
- install_handlers();
-}
-
-static void gc_sweep_compact(rb_objspace_t *objspace);
-
-static void
-gc_sweep(rb_objspace_t *objspace)
-{
- gc_sweeping_enter(objspace);
-
- const unsigned int immediate_sweep = objspace->flags.immediate_sweep;
-
- gc_report(1, objspace, "gc_sweep: immediate: %d\n", immediate_sweep);
-
- gc_sweep_start(objspace);
- if (objspace->flags.during_compacting) {
- gc_sweep_compact(objspace);
- }
-
- if (immediate_sweep) {
-#if !GC_ENABLE_LAZY_SWEEP
- gc_prof_sweep_timer_start(objspace);
-#endif
- gc_sweep_rest(objspace);
-#if !GC_ENABLE_LAZY_SWEEP
- gc_prof_sweep_timer_stop(objspace);
-#endif
- }
- else {
-
- /* Sweep every size pool. */
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- gc_sweep_step(objspace, heap);
- }
- }
-
- gc_sweeping_exit(objspace);
-}
-
-/* Marking - Marking stack */
-
-static stack_chunk_t *
-stack_chunk_alloc(void)
-{
- stack_chunk_t *res;
-
- res = malloc(sizeof(stack_chunk_t));
- if (!res)
- rb_memerror();
-
- return res;
-}
-
-static inline int
-is_mark_stack_empty(mark_stack_t *stack)
-{
- return stack->chunk == NULL;
-}
-
-static size_t
-mark_stack_size(mark_stack_t *stack)
-{
- size_t size = stack->index;
- stack_chunk_t *chunk = stack->chunk ? stack->chunk->next : NULL;
-
- while (chunk) {
- size += stack->limit;
- chunk = chunk->next;
- }
- return size;
-}
-
-static void
-add_stack_chunk_cache(mark_stack_t *stack, stack_chunk_t *chunk)
-{
- chunk->next = stack->cache;
- stack->cache = chunk;
- stack->cache_size++;
-}
-
-static void
-shrink_stack_chunk_cache(mark_stack_t *stack)
-{
- stack_chunk_t *chunk;
-
- if (stack->unused_cache_size > (stack->cache_size/2)) {
- chunk = stack->cache;
- stack->cache = stack->cache->next;
- stack->cache_size--;
- free(chunk);
- }
- stack->unused_cache_size = stack->cache_size;
-}
-
-static void
-push_mark_stack_chunk(mark_stack_t *stack)
-{
- stack_chunk_t *next;
-
- GC_ASSERT(stack->index == stack->limit);
-
- if (stack->cache_size > 0) {
- next = stack->cache;
- stack->cache = stack->cache->next;
- stack->cache_size--;
- if (stack->unused_cache_size > stack->cache_size)
- stack->unused_cache_size = stack->cache_size;
- }
- else {
- next = stack_chunk_alloc();
- }
- next->next = stack->chunk;
- stack->chunk = next;
- stack->index = 0;
-}
-
-static void
-pop_mark_stack_chunk(mark_stack_t *stack)
-{
- stack_chunk_t *prev;
-
- prev = stack->chunk->next;
- GC_ASSERT(stack->index == 0);
- add_stack_chunk_cache(stack, stack->chunk);
- stack->chunk = prev;
- stack->index = stack->limit;
-}
-
-static void
-mark_stack_chunk_list_free(stack_chunk_t *chunk)
-{
- stack_chunk_t *next = NULL;
-
- while (chunk != NULL) {
- next = chunk->next;
- free(chunk);
- chunk = next;
- }
-}
-
-static void
-free_stack_chunks(mark_stack_t *stack)
-{
- mark_stack_chunk_list_free(stack->chunk);
-}
-
-static void
-mark_stack_free_cache(mark_stack_t *stack)
-{
- mark_stack_chunk_list_free(stack->cache);
- stack->cache_size = 0;
- stack->unused_cache_size = 0;
-}
-
-static void
-push_mark_stack(mark_stack_t *stack, VALUE obj)
-{
- switch (BUILTIN_TYPE(obj)) {
- case T_OBJECT:
- case T_CLASS:
- case T_MODULE:
- case T_FLOAT:
- case T_STRING:
- case T_REGEXP:
- case T_ARRAY:
- case T_HASH:
- case T_STRUCT:
- case T_BIGNUM:
- case T_FILE:
- case T_DATA:
- case T_MATCH:
- case T_COMPLEX:
- case T_RATIONAL:
- case T_TRUE:
- case T_FALSE:
- case T_SYMBOL:
- case T_IMEMO:
- case T_ICLASS:
- if (stack->index == stack->limit) {
- push_mark_stack_chunk(stack);
- }
- stack->chunk->data[stack->index++] = obj;
- return;
-
- case T_NONE:
- case T_NIL:
- case T_FIXNUM:
- case T_MOVED:
- case T_ZOMBIE:
- case T_UNDEF:
- case T_MASK:
- rb_bug("push_mark_stack() called for broken object");
- break;
-
- case T_NODE:
- rb_bug("push_mark_stack: unexpected T_NODE object");
- break;
- }
-
- rb_bug("rb_gc_mark(): unknown data type 0x%x(%p) %s",
- BUILTIN_TYPE(obj), (void *)obj,
- is_pointer_to_heap((rb_objspace_t *)rb_gc_get_objspace(), (void *)obj) ? "corrupted object" : "non object");
-}
-
-static int
-pop_mark_stack(mark_stack_t *stack, VALUE *data)
-{
- if (is_mark_stack_empty(stack)) {
- return FALSE;
- }
- if (stack->index == 1) {
- *data = stack->chunk->data[--stack->index];
- pop_mark_stack_chunk(stack);
- }
- else {
- *data = stack->chunk->data[--stack->index];
- }
- return TRUE;
-}
-
-static void
-init_mark_stack(mark_stack_t *stack)
-{
- int i;
-
- MEMZERO(stack, mark_stack_t, 1);
- stack->index = stack->limit = STACK_CHUNK_SIZE;
-
- for (i=0; i < 4; i++) {
- add_stack_chunk_cache(stack, stack_chunk_alloc());
- }
- stack->unused_cache_size = stack->cache_size;
-}
-
-/* Marking */
-
-static void
-rgengc_check_relation(rb_objspace_t *objspace, VALUE obj)
-{
- const VALUE old_parent = objspace->rgengc.parent_object;
-
- if (old_parent) { /* parent object is old */
- if (RVALUE_WB_UNPROTECTED(objspace, obj) || !RVALUE_OLD_P(objspace, obj)) {
- rgengc_remember(objspace, old_parent);
- }
- }
-
- GC_ASSERT(old_parent == objspace->rgengc.parent_object);
-}
-
-static inline int
-gc_mark_set(rb_objspace_t *objspace, VALUE obj)
-{
- if (RVALUE_MARKED(objspace, obj)) return 0;
- MARK_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj);
- return 1;
-}
-
-static void
-gc_aging(rb_objspace_t *objspace, VALUE obj)
-{
- /* Disable aging if Major GC's are disabled. This will prevent longish lived
- * objects filling up the heap at the expense of marking many more objects.
- *
- * We should always pre-warm our process when disabling majors, by running
- * GC manually several times so that most objects likely to become oldgen
- * are already oldgen.
- */
- if(!gc_config_full_mark_val)
- return;
-
- struct heap_page *page = GET_HEAP_PAGE(obj);
-
- GC_ASSERT(RVALUE_MARKING(objspace, obj) == FALSE);
- check_rvalue_consistency(objspace, obj);
-
- if (!RVALUE_PAGE_WB_UNPROTECTED(page, obj)) {
- if (!RVALUE_OLD_P(objspace, obj)) {
- gc_report(3, objspace, "gc_aging: YOUNG: %s\n", rb_obj_info(obj));
- RVALUE_AGE_INC(objspace, obj);
- }
- else if (is_full_marking(objspace)) {
- GC_ASSERT(RVALUE_PAGE_UNCOLLECTIBLE(page, obj) == FALSE);
- RVALUE_PAGE_OLD_UNCOLLECTIBLE_SET(objspace, page, obj);
- }
- }
- check_rvalue_consistency(objspace, obj);
-
- objspace->marked_slots++;
-}
-
-static void
-gc_grey(rb_objspace_t *objspace, VALUE obj)
-{
-#if RGENGC_CHECK_MODE
- if (RVALUE_MARKED(objspace, obj) == FALSE) rb_bug("gc_grey: %s is not marked.", rb_obj_info(obj));
- if (RVALUE_MARKING(objspace, obj) == TRUE) rb_bug("gc_grey: %s is marking/remembered.", rb_obj_info(obj));
-#endif
-
- if (is_incremental_marking(objspace)) {
- MARK_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), obj);
- }
-
- push_mark_stack(&objspace->mark_stack, obj);
-}
-
-static void
-gc_mark(rb_objspace_t *objspace, VALUE obj)
-{
- GC_ASSERT(during_gc);
-
- rgengc_check_relation(objspace, obj);
- if (!gc_mark_set(objspace, obj)) return; /* already marked */
-
- if (0) { // for debug GC marking miss
- if (objspace->rgengc.parent_object) {
- RUBY_DEBUG_LOG("%p (%s) parent:%p (%s)",
- (void *)obj, obj_type_name(obj),
- (void *)objspace->rgengc.parent_object, obj_type_name(objspace->rgengc.parent_object));
- }
- else {
- RUBY_DEBUG_LOG("%p (%s)", (void *)obj, obj_type_name(obj));
- }
- }
-
- if (RB_UNLIKELY(RB_TYPE_P(obj, T_NONE))) {
- rb_obj_info_dump(obj);
- rb_bug("try to mark T_NONE object"); /* check here will help debugging */
- }
-
- gc_aging(objspace, obj);
- gc_grey(objspace, obj);
-}
-
-static inline void
-gc_pin(rb_objspace_t *objspace, VALUE obj)
-{
- GC_ASSERT(!SPECIAL_CONST_P(obj));
- if (RB_UNLIKELY(objspace->flags.during_compacting)) {
- if (RB_LIKELY(during_gc)) {
- if (!RVALUE_PINNED(objspace, obj)) {
- GC_ASSERT(GET_HEAP_PAGE(obj)->pinned_slots <= GET_HEAP_PAGE(obj)->total_slots);
- GET_HEAP_PAGE(obj)->pinned_slots++;
- MARK_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj);
- }
- }
- }
-}
-
-static inline void
-gc_mark_and_pin(rb_objspace_t *objspace, VALUE obj)
-{
- gc_pin(objspace, obj);
- gc_mark(objspace, obj);
-}
-
-void
-rb_gc_impl_mark_and_move(void *objspace_ptr, VALUE *ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- if (RB_UNLIKELY(objspace->flags.during_reference_updating)) {
- GC_ASSERT(objspace->flags.during_compacting);
- GC_ASSERT(during_gc);
-
- *ptr = rb_gc_impl_location(objspace, *ptr);
- }
- else {
- gc_mark(objspace, *ptr);
- }
-}
-
-void
-rb_gc_impl_mark(void *objspace_ptr, VALUE obj)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- gc_mark(objspace, obj);
-}
-
-void
-rb_gc_impl_mark_and_pin(void *objspace_ptr, VALUE obj)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- gc_mark_and_pin(objspace, obj);
-}
-
-void
-rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- (void)VALGRIND_MAKE_MEM_DEFINED(&obj, sizeof(obj));
-
- if (is_pointer_to_heap(objspace, (void *)obj)) {
- asan_unpoisoning_object(obj) {
- /* Garbage can live on the stack, so do not mark or pin */
- switch (BUILTIN_TYPE(obj)) {
- case T_ZOMBIE:
- case T_NONE:
- break;
- default:
- gc_mark_and_pin(objspace, obj);
- break;
- }
- }
- }
-}
-
-void
-rb_gc_impl_mark_weak(void *objspace_ptr, VALUE *ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- GC_ASSERT(objspace->rgengc.parent_object == 0 || FL_TEST(objspace->rgengc.parent_object, FL_WB_PROTECTED));
-
- VALUE obj = *ptr;
-
- if (RB_UNLIKELY(RB_TYPE_P(obj, T_NONE))) {
- rb_obj_info_dump(obj);
- rb_bug("try to mark T_NONE object");
- }
-
- /* If we are in a minor GC and the other object is old, then obj should
- * already be marked and cannot be reclaimed in this GC cycle so we don't
- * need to add it to the weak refences list. */
- if (!is_full_marking(objspace) && RVALUE_OLD_P(objspace, obj)) {
- GC_ASSERT(RVALUE_MARKED(objspace, obj));
- GC_ASSERT(!objspace->flags.during_compacting);
-
- return;
- }
-
- rgengc_check_relation(objspace, obj);
-
- DURING_GC_COULD_MALLOC_REGION_START();
- {
- rb_darray_append(&objspace->weak_references, ptr);
- }
- DURING_GC_COULD_MALLOC_REGION_END();
-
- objspace->profile.weak_references_count++;
-}
-
-void
-rb_gc_impl_remove_weak(void *objspace_ptr, VALUE parent_obj, VALUE *ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- /* If we're not incremental marking, then the state of the objects can't
- * change so we don't need to do anything. */
- if (!is_incremental_marking(objspace)) return;
- /* If parent_obj has not been marked, then ptr has not yet been marked
- * weak, so we don't need to do anything. */
- if (!RVALUE_MARKED(objspace, parent_obj)) return;
-
- VALUE **ptr_ptr;
- rb_darray_foreach(objspace->weak_references, i, ptr_ptr) {
- if (*ptr_ptr == ptr) {
- *ptr_ptr = NULL;
- break;
- }
- }
-}
-
-static int
-pin_value(st_data_t key, st_data_t value, st_data_t data)
-{
- rb_gc_impl_mark_and_pin((void *)data, (VALUE)value);
-
- return ST_CONTINUE;
-}
-
-static void
-mark_roots(rb_objspace_t *objspace, const char **categoryp)
-{
-#define MARK_CHECKPOINT(category) do { \
- if (categoryp) *categoryp = category; \
-} while (0)
-
- MARK_CHECKPOINT("objspace");
- objspace->rgengc.parent_object = Qfalse;
-
- if (finalizer_table != NULL) {
- st_foreach(finalizer_table, pin_value, (st_data_t)objspace);
- }
-
- st_foreach(objspace->obj_to_id_tbl, gc_mark_tbl_no_pin_i, (st_data_t)objspace);
-
- if (stress_to_class) rb_gc_mark(stress_to_class);
-
- rb_gc_mark_roots(objspace, categoryp);
-}
-
-static inline void
-gc_mark_set_parent(rb_objspace_t *objspace, VALUE obj)
-{
- if (RVALUE_OLD_P(objspace, obj)) {
- objspace->rgengc.parent_object = obj;
- }
- else {
- objspace->rgengc.parent_object = Qfalse;
- }
-}
-
-static void
-gc_mark_children(rb_objspace_t *objspace, VALUE obj)
-{
- gc_mark_set_parent(objspace, obj);
- rb_gc_mark_children(objspace, obj);
-}
-
-/**
- * incremental: 0 -> not incremental (do all)
- * incremental: n -> mark at most `n' objects
- */
-static inline int
-gc_mark_stacked_objects(rb_objspace_t *objspace, int incremental, size_t count)
-{
- mark_stack_t *mstack = &objspace->mark_stack;
- VALUE obj;
- size_t marked_slots_at_the_beginning = objspace->marked_slots;
- size_t popped_count = 0;
-
- while (pop_mark_stack(mstack, &obj)) {
- if (obj == Qundef) continue; /* skip */
-
- if (RGENGC_CHECK_MODE && !RVALUE_MARKED(objspace, obj)) {
- rb_bug("gc_mark_stacked_objects: %s is not marked.", rb_obj_info(obj));
- }
- gc_mark_children(objspace, obj);
-
- if (incremental) {
- if (RGENGC_CHECK_MODE && !RVALUE_MARKING(objspace, obj)) {
- rb_bug("gc_mark_stacked_objects: incremental, but marking bit is 0");
- }
- CLEAR_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), obj);
- popped_count++;
-
- if (popped_count + (objspace->marked_slots - marked_slots_at_the_beginning) > count) {
- break;
- }
- }
- else {
- /* just ignore marking bits */
- }
- }
-
- if (RGENGC_CHECK_MODE >= 3) gc_verify_internal_consistency(objspace);
-
- if (is_mark_stack_empty(mstack)) {
- shrink_stack_chunk_cache(mstack);
- return TRUE;
- }
- else {
- return FALSE;
- }
-}
-
-static int
-gc_mark_stacked_objects_incremental(rb_objspace_t *objspace, size_t count)
-{
- return gc_mark_stacked_objects(objspace, TRUE, count);
-}
-
-static int
-gc_mark_stacked_objects_all(rb_objspace_t *objspace)
-{
- return gc_mark_stacked_objects(objspace, FALSE, 0);
-}
-
-#if RGENGC_CHECK_MODE >= 4
-
-#define MAKE_ROOTSIG(obj) (((VALUE)(obj) << 1) | 0x01)
-#define IS_ROOTSIG(obj) ((VALUE)(obj) & 0x01)
-#define GET_ROOTSIG(obj) ((const char *)((VALUE)(obj) >> 1))
-
-struct reflist {
- VALUE *list;
- int pos;
- int size;
-};
-
-static struct reflist *
-reflist_create(VALUE obj)
-{
- struct reflist *refs = xmalloc(sizeof(struct reflist));
- refs->size = 1;
- refs->list = ALLOC_N(VALUE, refs->size);
- refs->list[0] = obj;
- refs->pos = 1;
- return refs;
-}
-
-static void
-reflist_destruct(struct reflist *refs)
-{
- xfree(refs->list);
- xfree(refs);
-}
-
-static void
-reflist_add(struct reflist *refs, VALUE obj)
-{
- if (refs->pos == refs->size) {
- refs->size *= 2;
- SIZED_REALLOC_N(refs->list, VALUE, refs->size, refs->size/2);
- }
-
- refs->list[refs->pos++] = obj;
-}
-
-static void
-reflist_dump(struct reflist *refs)
-{
- int i;
- for (i=0; i<refs->pos; i++) {
- VALUE obj = refs->list[i];
- if (IS_ROOTSIG(obj)) { /* root */
- fprintf(stderr, "<root@%s>", GET_ROOTSIG(obj));
- }
- else {
- fprintf(stderr, "<%s>", rb_obj_info(obj));
- }
- if (i+1 < refs->pos) fprintf(stderr, ", ");
- }
-}
-
-static int
-reflist_referred_from_machine_context(struct reflist *refs)
-{
- int i;
- for (i=0; i<refs->pos; i++) {
- VALUE obj = refs->list[i];
- if (IS_ROOTSIG(obj) && strcmp(GET_ROOTSIG(obj), "machine_context") == 0) return 1;
- }
- return 0;
-}
-
-struct allrefs {
- rb_objspace_t *objspace;
- /* a -> obj1
- * b -> obj1
- * c -> obj1
- * c -> obj2
- * d -> obj3
- * #=> {obj1 => [a, b, c], obj2 => [c, d]}
- */
- struct st_table *references;
- const char *category;
- VALUE root_obj;
- mark_stack_t mark_stack;
-};
-
-static int
-allrefs_add(struct allrefs *data, VALUE obj)
-{
- struct reflist *refs;
- st_data_t r;
-
- if (st_lookup(data->references, obj, &r)) {
- refs = (struct reflist *)r;
- reflist_add(refs, data->root_obj);
- return 0;
- }
- else {
- refs = reflist_create(data->root_obj);
- st_insert(data->references, obj, (st_data_t)refs);
- return 1;
- }
-}
-
-static void
-allrefs_i(VALUE obj, void *ptr)
-{
- struct allrefs *data = (struct allrefs *)ptr;
-
- if (allrefs_add(data, obj)) {
- push_mark_stack(&data->mark_stack, obj);
- }
-}
-
-static void
-allrefs_roots_i(VALUE obj, void *ptr)
-{
- struct allrefs *data = (struct allrefs *)ptr;
- if (strlen(data->category) == 0) rb_bug("!!!");
- data->root_obj = MAKE_ROOTSIG(data->category);
-
- if (allrefs_add(data, obj)) {
- push_mark_stack(&data->mark_stack, obj);
- }
-}
-#define PUSH_MARK_FUNC_DATA(v) do { \
- struct gc_mark_func_data_struct *prev_mark_func_data = GET_VM()->gc.mark_func_data; \
- GET_VM()->gc.mark_func_data = (v);
-
-#define POP_MARK_FUNC_DATA() GET_VM()->gc.mark_func_data = prev_mark_func_data;} while (0)
-
-static st_table *
-objspace_allrefs(rb_objspace_t *objspace)
-{
- struct allrefs data;
- struct gc_mark_func_data_struct mfd;
- VALUE obj;
- int prev_dont_gc = dont_gc_val();
- dont_gc_on();
-
- data.objspace = objspace;
- data.references = st_init_numtable();
- init_mark_stack(&data.mark_stack);
-
- mfd.mark_func = allrefs_roots_i;
- mfd.data = &data;
-
- /* traverse root objects */
- PUSH_MARK_FUNC_DATA(&mfd);
- GET_VM()->gc.mark_func_data = &mfd;
- mark_roots(objspace, &data.category);
- POP_MARK_FUNC_DATA();
-
- /* traverse rest objects reachable from root objects */
- while (pop_mark_stack(&data.mark_stack, &obj)) {
- rb_objspace_reachable_objects_from(data.root_obj = obj, allrefs_i, &data);
- }
- free_stack_chunks(&data.mark_stack);
-
- dont_gc_set(prev_dont_gc);
- return data.references;
-}
-
-static int
-objspace_allrefs_destruct_i(st_data_t key, st_data_t value, st_data_t ptr)
-{
- struct reflist *refs = (struct reflist *)value;
- reflist_destruct(refs);
- return ST_CONTINUE;
-}
-
-static void
-objspace_allrefs_destruct(struct st_table *refs)
-{
- st_foreach(refs, objspace_allrefs_destruct_i, 0);
- st_free_table(refs);
-}
-
-#if RGENGC_CHECK_MODE >= 5
-static int
-allrefs_dump_i(st_data_t k, st_data_t v, st_data_t ptr)
-{
- VALUE obj = (VALUE)k;
- struct reflist *refs = (struct reflist *)v;
- fprintf(stderr, "[allrefs_dump_i] %s <- ", rb_obj_info(obj));
- reflist_dump(refs);
- fprintf(stderr, "\n");
- return ST_CONTINUE;
-}
-
-static void
-allrefs_dump(rb_objspace_t *objspace)
-{
- VALUE size = objspace->rgengc.allrefs_table->num_entries;
- fprintf(stderr, "[all refs] (size: %"PRIuVALUE")\n", size);
- st_foreach(objspace->rgengc.allrefs_table, allrefs_dump_i, 0);
-}
-#endif
-
-static int
-gc_check_after_marks_i(st_data_t k, st_data_t v, st_data_t ptr)
-{
- VALUE obj = k;
- struct reflist *refs = (struct reflist *)v;
- rb_objspace_t *objspace = (rb_objspace_t *)ptr;
-
- /* object should be marked or oldgen */
- if (!RVALUE_MARKED(objspace, obj)) {
- fprintf(stderr, "gc_check_after_marks_i: %s is not marked and not oldgen.\n", rb_obj_info(obj));
- fprintf(stderr, "gc_check_after_marks_i: %p is referred from ", (void *)obj);
- reflist_dump(refs);
-
- if (reflist_referred_from_machine_context(refs)) {
- fprintf(stderr, " (marked from machine stack).\n");
- /* marked from machine context can be false positive */
- }
- else {
- objspace->rgengc.error_count++;
- fprintf(stderr, "\n");
- }
- }
- return ST_CONTINUE;
-}
-
-static void
-gc_marks_check(rb_objspace_t *objspace, st_foreach_callback_func *checker_func, const char *checker_name)
-{
- size_t saved_malloc_increase = objspace->malloc_params.increase;
-#if RGENGC_ESTIMATE_OLDMALLOC
- size_t saved_oldmalloc_increase = objspace->rgengc.oldmalloc_increase;
-#endif
- VALUE already_disabled = rb_objspace_gc_disable(objspace);
-
- objspace->rgengc.allrefs_table = objspace_allrefs(objspace);
-
- if (checker_func) {
- st_foreach(objspace->rgengc.allrefs_table, checker_func, (st_data_t)objspace);
- }
-
- if (objspace->rgengc.error_count > 0) {
-#if RGENGC_CHECK_MODE >= 5
- allrefs_dump(objspace);
-#endif
- if (checker_name) rb_bug("%s: GC has problem.", checker_name);
- }
-
- objspace_allrefs_destruct(objspace->rgengc.allrefs_table);
- objspace->rgengc.allrefs_table = 0;
-
- if (already_disabled == Qfalse) rb_objspace_gc_enable(objspace);
- objspace->malloc_params.increase = saved_malloc_increase;
-#if RGENGC_ESTIMATE_OLDMALLOC
- objspace->rgengc.oldmalloc_increase = saved_oldmalloc_increase;
-#endif
-}
-#endif /* RGENGC_CHECK_MODE >= 4 */
-
-struct verify_internal_consistency_struct {
- rb_objspace_t *objspace;
- int err_count;
- size_t live_object_count;
- size_t zombie_object_count;
-
- VALUE parent;
- size_t old_object_count;
- size_t remembered_shady_count;
-};
-
-static void
-check_generation_i(const VALUE child, void *ptr)
-{
- struct verify_internal_consistency_struct *data = (struct verify_internal_consistency_struct *)ptr;
- const VALUE parent = data->parent;
-
- if (RGENGC_CHECK_MODE) GC_ASSERT(RVALUE_OLD_P(data->objspace, parent));
-
- if (!RVALUE_OLD_P(data->objspace, child)) {
- if (!RVALUE_REMEMBERED(data->objspace, parent) &&
- !RVALUE_REMEMBERED(data->objspace, child) &&
- !RVALUE_UNCOLLECTIBLE(data->objspace, child)) {
- fprintf(stderr, "verify_internal_consistency_reachable_i: WB miss (O->Y) %s -> %s\n", rb_obj_info(parent), rb_obj_info(child));
- data->err_count++;
- }
- }
-}
-
-static void
-check_color_i(const VALUE child, void *ptr)
-{
- struct verify_internal_consistency_struct *data = (struct verify_internal_consistency_struct *)ptr;
- const VALUE parent = data->parent;
-
- if (!RVALUE_WB_UNPROTECTED(data->objspace, parent) && RVALUE_WHITE_P(data->objspace, child)) {
- fprintf(stderr, "verify_internal_consistency_reachable_i: WB miss (B->W) - %s -> %s\n",
- rb_obj_info(parent), rb_obj_info(child));
- data->err_count++;
- }
-}
-
-static void
-check_children_i(const VALUE child, void *ptr)
-{
- struct verify_internal_consistency_struct *data = (struct verify_internal_consistency_struct *)ptr;
- if (check_rvalue_consistency_force(data->objspace, child, FALSE) != 0) {
- fprintf(stderr, "check_children_i: %s has error (referenced from %s)",
- rb_obj_info(child), rb_obj_info(data->parent));
-
- data->err_count++;
- }
-}
-
-static int
-verify_internal_consistency_i(void *page_start, void *page_end, size_t stride,
- struct verify_internal_consistency_struct *data)
-{
- VALUE obj;
- rb_objspace_t *objspace = data->objspace;
-
- for (obj = (VALUE)page_start; obj != (VALUE)page_end; obj += stride) {
- asan_unpoisoning_object(obj) {
- if (!rb_gc_impl_garbage_object_p(objspace, obj)) {
- /* count objects */
- data->live_object_count++;
- data->parent = obj;
-
- /* Normally, we don't expect T_MOVED objects to be in the heap.
- * But they can stay alive on the stack, */
- if (!gc_object_moved_p(objspace, obj)) {
- /* moved slots don't have children */
- rb_objspace_reachable_objects_from(obj, check_children_i, (void *)data);
- }
-
- /* check health of children */
- if (RVALUE_OLD_P(objspace, obj)) data->old_object_count++;
- if (RVALUE_WB_UNPROTECTED(objspace, obj) && RVALUE_UNCOLLECTIBLE(objspace, obj)) data->remembered_shady_count++;
-
- if (!is_marking(objspace) && RVALUE_OLD_P(objspace, obj)) {
- /* reachable objects from an oldgen object should be old or (young with remember) */
- data->parent = obj;
- rb_objspace_reachable_objects_from(obj, check_generation_i, (void *)data);
- }
-
- if (is_incremental_marking(objspace)) {
- if (RVALUE_BLACK_P(objspace, obj)) {
- /* reachable objects from black objects should be black or grey objects */
- data->parent = obj;
- rb_objspace_reachable_objects_from(obj, check_color_i, (void *)data);
- }
- }
- }
- else {
- if (BUILTIN_TYPE(obj) == T_ZOMBIE) {
- data->zombie_object_count++;
-
- if ((RBASIC(obj)->flags & ~ZOMBIE_OBJ_KEPT_FLAGS) != T_ZOMBIE) {
- fprintf(stderr, "verify_internal_consistency_i: T_ZOMBIE has extra flags set: %s\n",
- rb_obj_info(obj));
- data->err_count++;
- }
-
- if (!!FL_TEST(obj, FL_FINALIZE) != !!st_is_member(finalizer_table, obj)) {
- fprintf(stderr, "verify_internal_consistency_i: FL_FINALIZE %s but %s finalizer_table: %s\n",
- FL_TEST(obj, FL_FINALIZE) ? "set" : "not set", st_is_member(finalizer_table, obj) ? "in" : "not in",
- rb_obj_info(obj));
- data->err_count++;
- }
- }
- }
- }
- }
-
- return 0;
-}
-
-static int
-gc_verify_heap_page(rb_objspace_t *objspace, struct heap_page *page, VALUE obj)
-{
- unsigned int has_remembered_shady = FALSE;
- unsigned int has_remembered_old = FALSE;
- int remembered_old_objects = 0;
- int free_objects = 0;
- int zombie_objects = 0;
-
- short slot_size = page->slot_size;
- uintptr_t start = (uintptr_t)page->start;
- uintptr_t end = start + page->total_slots * slot_size;
-
- for (uintptr_t ptr = start; ptr < end; ptr += slot_size) {
- VALUE val = (VALUE)ptr;
- asan_unpoisoning_object(val) {
- enum ruby_value_type type = BUILTIN_TYPE(val);
-
- if (type == T_NONE) free_objects++;
- if (type == T_ZOMBIE) zombie_objects++;
- if (RVALUE_PAGE_UNCOLLECTIBLE(page, val) && RVALUE_PAGE_WB_UNPROTECTED(page, val)) {
- has_remembered_shady = TRUE;
- }
- if (RVALUE_PAGE_MARKING(page, val)) {
- has_remembered_old = TRUE;
- remembered_old_objects++;
- }
- }
- }
-
- if (!is_incremental_marking(objspace) &&
- page->flags.has_remembered_objects == FALSE && has_remembered_old == TRUE) {
-
- for (uintptr_t ptr = start; ptr < end; ptr += slot_size) {
- VALUE val = (VALUE)ptr;
- if (RVALUE_PAGE_MARKING(page, val)) {
- fprintf(stderr, "marking -> %s\n", rb_obj_info(val));
- }
- }
- rb_bug("page %p's has_remembered_objects should be false, but there are remembered old objects (%d). %s",
- (void *)page, remembered_old_objects, obj ? rb_obj_info(obj) : "");
- }
-
- if (page->flags.has_uncollectible_wb_unprotected_objects == FALSE && has_remembered_shady == TRUE) {
- rb_bug("page %p's has_remembered_shady should be false, but there are remembered shady objects. %s",
- (void *)page, obj ? rb_obj_info(obj) : "");
- }
-
- if (0) {
- /* free_slots may not equal to free_objects */
- if (page->free_slots != free_objects) {
- rb_bug("page %p's free_slots should be %d, but %d", (void *)page, page->free_slots, free_objects);
- }
- }
- if (page->final_slots != zombie_objects) {
- rb_bug("page %p's final_slots should be %d, but %d", (void *)page, page->final_slots, zombie_objects);
- }
-
- return remembered_old_objects;
-}
-
-static int
-gc_verify_heap_pages_(rb_objspace_t *objspace, struct ccan_list_head *head)
-{
- int remembered_old_objects = 0;
- struct heap_page *page = 0;
-
- ccan_list_for_each(head, page, page_node) {
- asan_unlock_freelist(page);
- struct free_slot *p = page->freelist;
- while (p) {
- VALUE vp = (VALUE)p;
- VALUE prev = vp;
- asan_unpoison_object(vp, false);
- if (BUILTIN_TYPE(vp) != T_NONE) {
- fprintf(stderr, "freelist slot expected to be T_NONE but was: %s\n", rb_obj_info(vp));
- }
- p = p->next;
- asan_poison_object(prev);
- }
- asan_lock_freelist(page);
-
- if (page->flags.has_remembered_objects == FALSE) {
- remembered_old_objects += gc_verify_heap_page(objspace, page, Qfalse);
- }
- }
-
- return remembered_old_objects;
-}
-
-static int
-gc_verify_heap_pages(rb_objspace_t *objspace)
-{
- int remembered_old_objects = 0;
- for (int i = 0; i < HEAP_COUNT; i++) {
- remembered_old_objects += gc_verify_heap_pages_(objspace, &((&heaps[i])->pages));
- }
- return remembered_old_objects;
-}
-
-static void
-gc_verify_internal_consistency_(rb_objspace_t *objspace)
-{
- struct verify_internal_consistency_struct data = {0};
-
- data.objspace = objspace;
- gc_report(5, objspace, "gc_verify_internal_consistency: start\n");
-
- /* check relations */
- for (size_t i = 0; i < rb_darray_size(objspace->heap_pages.sorted); i++) {
- struct heap_page *page = rb_darray_get(objspace->heap_pages.sorted, i);
- short slot_size = page->slot_size;
-
- uintptr_t start = (uintptr_t)page->start;
- uintptr_t end = start + page->total_slots * slot_size;
-
- verify_internal_consistency_i((void *)start, (void *)end, slot_size, &data);
- }
-
- if (data.err_count != 0) {
-#if RGENGC_CHECK_MODE >= 5
- objspace->rgengc.error_count = data.err_count;
- gc_marks_check(objspace, NULL, NULL);
- allrefs_dump(objspace);
-#endif
- rb_bug("gc_verify_internal_consistency: found internal inconsistency.");
- }
-
- /* check heap_page status */
- gc_verify_heap_pages(objspace);
-
- /* check counters */
-
- if (!is_lazy_sweeping(objspace) &&
- !finalizing &&
- !rb_gc_multi_ractor_p()) {
- if (objspace_live_slots(objspace) != data.live_object_count) {
- fprintf(stderr, "heap_pages_final_slots: %"PRIdSIZE", total_freed_objects: %"PRIdSIZE"\n",
- total_final_slots_count(objspace), total_freed_objects(objspace));
- rb_bug("inconsistent live slot number: expect %"PRIuSIZE", but %"PRIuSIZE".",
- objspace_live_slots(objspace), data.live_object_count);
- }
- }
-
- if (!is_marking(objspace)) {
- if (objspace->rgengc.old_objects != data.old_object_count) {
- rb_bug("inconsistent old slot number: expect %"PRIuSIZE", but %"PRIuSIZE".",
- objspace->rgengc.old_objects, data.old_object_count);
- }
- if (objspace->rgengc.uncollectible_wb_unprotected_objects != data.remembered_shady_count) {
- rb_bug("inconsistent number of wb unprotected objects: expect %"PRIuSIZE", but %"PRIuSIZE".",
- objspace->rgengc.uncollectible_wb_unprotected_objects, data.remembered_shady_count);
- }
- }
-
- if (!finalizing) {
- size_t list_count = 0;
-
- {
- VALUE z = heap_pages_deferred_final;
- while (z) {
- list_count++;
- z = RZOMBIE(z)->next;
- }
- }
-
- if (total_final_slots_count(objspace) != data.zombie_object_count ||
- total_final_slots_count(objspace) != list_count) {
-
- rb_bug("inconsistent finalizing object count:\n"
- " expect %"PRIuSIZE"\n"
- " but %"PRIuSIZE" zombies\n"
- " heap_pages_deferred_final list has %"PRIuSIZE" items.",
- total_final_slots_count(objspace),
- data.zombie_object_count,
- list_count);
- }
- }
-
- gc_report(5, objspace, "gc_verify_internal_consistency: OK\n");
-}
-
-static void
-gc_verify_internal_consistency(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- unsigned int lev = rb_gc_vm_lock();
- {
- rb_gc_vm_barrier(); // stop other ractors
-
- unsigned int prev_during_gc = during_gc;
- during_gc = FALSE; // stop gc here
- {
- gc_verify_internal_consistency_(objspace);
- }
- during_gc = prev_during_gc;
- }
- rb_gc_vm_unlock(lev);
-}
-
-static void
-heap_move_pooled_pages_to_free_pages(rb_heap_t *heap)
-{
- if (heap->pooled_pages) {
- if (heap->free_pages) {
- struct heap_page *free_pages_tail = heap->free_pages;
- while (free_pages_tail->free_next) {
- free_pages_tail = free_pages_tail->free_next;
- }
- free_pages_tail->free_next = heap->pooled_pages;
- }
- else {
- heap->free_pages = heap->pooled_pages;
- }
-
- heap->pooled_pages = NULL;
- }
-}
-
-static int
-gc_remember_unprotected(rb_objspace_t *objspace, VALUE obj)
-{
- struct heap_page *page = GET_HEAP_PAGE(obj);
- bits_t *uncollectible_bits = &page->uncollectible_bits[0];
-
- if (!MARKED_IN_BITMAP(uncollectible_bits, obj)) {
- page->flags.has_uncollectible_wb_unprotected_objects = TRUE;
- MARK_IN_BITMAP(uncollectible_bits, obj);
- objspace->rgengc.uncollectible_wb_unprotected_objects++;
-
-#if RGENGC_PROFILE > 0
- objspace->profile.total_remembered_shady_object_count++;
-#if RGENGC_PROFILE >= 2
- objspace->profile.remembered_shady_object_count_types[BUILTIN_TYPE(obj)]++;
-#endif
-#endif
- return TRUE;
- }
- else {
- return FALSE;
- }
-}
-
-static inline void
-gc_marks_wb_unprotected_objects_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bits)
-{
- if (bits) {
- do {
- if (bits & 1) {
- gc_report(2, objspace, "gc_marks_wb_unprotected_objects: marked shady: %s\n", rb_obj_info((VALUE)p));
- GC_ASSERT(RVALUE_WB_UNPROTECTED(objspace, (VALUE)p));
- GC_ASSERT(RVALUE_MARKED(objspace, (VALUE)p));
- gc_mark_children(objspace, (VALUE)p);
- }
- p += BASE_SLOT_SIZE;
- bits >>= 1;
- } while (bits);
- }
-}
-
-static void
-gc_marks_wb_unprotected_objects(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- struct heap_page *page = 0;
-
- ccan_list_for_each(&heap->pages, page, page_node) {
- bits_t *mark_bits = page->mark_bits;
- bits_t *wbun_bits = page->wb_unprotected_bits;
- uintptr_t p = page->start;
- size_t j;
-
- bits_t bits = mark_bits[0] & wbun_bits[0];
- bits >>= NUM_IN_PAGE(p);
- gc_marks_wb_unprotected_objects_plane(objspace, p, bits);
- p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
-
- for (j=1; j<HEAP_PAGE_BITMAP_LIMIT; j++) {
- bits_t bits = mark_bits[j] & wbun_bits[j];
-
- gc_marks_wb_unprotected_objects_plane(objspace, p, bits);
- p += BITS_BITLENGTH * BASE_SLOT_SIZE;
- }
- }
-
- gc_mark_stacked_objects_all(objspace);
-}
-
-static void
-gc_update_weak_references(rb_objspace_t *objspace)
-{
- size_t retained_weak_references_count = 0;
- VALUE **ptr_ptr;
- rb_darray_foreach(objspace->weak_references, i, ptr_ptr) {
- if (!*ptr_ptr) continue;
-
- VALUE obj = **ptr_ptr;
-
- if (RB_SPECIAL_CONST_P(obj)) continue;
-
- if (!RVALUE_MARKED(objspace, obj)) {
- **ptr_ptr = Qundef;
- }
- else {
- retained_weak_references_count++;
- }
- }
-
- objspace->profile.retained_weak_references_count = retained_weak_references_count;
-
- rb_darray_clear(objspace->weak_references);
- DURING_GC_COULD_MALLOC_REGION_START();
- {
- rb_darray_resize_capa(&objspace->weak_references, retained_weak_references_count);
- }
- DURING_GC_COULD_MALLOC_REGION_END();
-}
-
-static void
-gc_marks_finish(rb_objspace_t *objspace)
-{
- /* finish incremental GC */
- if (is_incremental_marking(objspace)) {
- if (RGENGC_CHECK_MODE && is_mark_stack_empty(&objspace->mark_stack) == 0) {
- rb_bug("gc_marks_finish: mark stack is not empty (%"PRIdSIZE").",
- mark_stack_size(&objspace->mark_stack));
- }
-
- mark_roots(objspace, NULL);
- while (gc_mark_stacked_objects_incremental(objspace, INT_MAX) == false);
-
-#if RGENGC_CHECK_MODE >= 2
- if (gc_verify_heap_pages(objspace) != 0) {
- rb_bug("gc_marks_finish (incremental): there are remembered old objects.");
- }
-#endif
-
- objspace->flags.during_incremental_marking = FALSE;
- /* check children of all marked wb-unprotected objects */
- for (int i = 0; i < HEAP_COUNT; i++) {
- gc_marks_wb_unprotected_objects(objspace, &heaps[i]);
- }
- }
-
- gc_update_weak_references(objspace);
-
-#if RGENGC_CHECK_MODE >= 2
- gc_verify_internal_consistency(objspace);
-#endif
-
-#if RGENGC_CHECK_MODE >= 4
- during_gc = FALSE;
- gc_marks_check(objspace, gc_check_after_marks_i, "after_marks");
- during_gc = TRUE;
-#endif
-
- {
- const unsigned long r_mul = objspace->live_ractor_cache_count > 8 ? 8 : objspace->live_ractor_cache_count; // upto 8
-
- size_t total_slots = objspace_available_slots(objspace);
- size_t sweep_slots = total_slots - objspace->marked_slots; /* will be swept slots */
- size_t max_free_slots = (size_t)(total_slots * gc_params.heap_free_slots_max_ratio);
- size_t min_free_slots = (size_t)(total_slots * gc_params.heap_free_slots_min_ratio);
- if (min_free_slots < gc_params.heap_free_slots * r_mul) {
- min_free_slots = gc_params.heap_free_slots * r_mul;
- }
-
- int full_marking = is_full_marking(objspace);
-
- GC_ASSERT(objspace_available_slots(objspace) >= objspace->marked_slots);
-
- /* Setup freeable slots. */
- size_t total_init_slots = 0;
- for (int i = 0; i < HEAP_COUNT; i++) {
- total_init_slots += gc_params.heap_init_slots[i] * r_mul;
- }
-
- if (max_free_slots < total_init_slots) {
- max_free_slots = total_init_slots;
- }
-
- if (sweep_slots > max_free_slots) {
- heap_pages_freeable_pages = (sweep_slots - max_free_slots) / HEAP_PAGE_OBJ_LIMIT;
- }
- else {
- heap_pages_freeable_pages = 0;
- }
-
- if (objspace->heap_pages.allocatable_slots == 0 && sweep_slots < min_free_slots) {
- if (!full_marking) {
- if (objspace->profile.count - objspace->rgengc.last_major_gc < RVALUE_OLD_AGE) {
- full_marking = TRUE;
- }
- else {
- gc_report(1, objspace, "gc_marks_finish: next is full GC!!)\n");
- gc_needs_major_flags |= GPR_FLAG_MAJOR_BY_NOFREE;
- }
- }
- }
-
- if (full_marking) {
- /* See the comment about RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR */
- const double r = gc_params.oldobject_limit_factor;
- objspace->rgengc.uncollectible_wb_unprotected_objects_limit = MAX(
- (size_t)(objspace->rgengc.uncollectible_wb_unprotected_objects * r),
- (size_t)(objspace->rgengc.old_objects * gc_params.uncollectible_wb_unprotected_objects_limit_ratio)
- );
- objspace->rgengc.old_objects_limit = (size_t)(objspace->rgengc.old_objects * r);
- }
-
- if (objspace->rgengc.uncollectible_wb_unprotected_objects > objspace->rgengc.uncollectible_wb_unprotected_objects_limit) {
- gc_needs_major_flags |= GPR_FLAG_MAJOR_BY_SHADY;
- }
- if (objspace->rgengc.old_objects > objspace->rgengc.old_objects_limit) {
- gc_needs_major_flags |= GPR_FLAG_MAJOR_BY_OLDGEN;
- }
- if (RGENGC_FORCE_MAJOR_GC) {
- gc_needs_major_flags = GPR_FLAG_MAJOR_BY_FORCE;
- }
-
- gc_report(1, objspace, "gc_marks_finish (marks %"PRIdSIZE" objects, "
- "old %"PRIdSIZE" objects, total %"PRIdSIZE" slots, "
- "sweep %"PRIdSIZE" slots, allocatable %"PRIdSIZE" slots, next GC: %s)\n",
- objspace->marked_slots, objspace->rgengc.old_objects, objspace_available_slots(objspace), sweep_slots, objspace->heap_pages.allocatable_slots,
- gc_needs_major_flags ? "major" : "minor");
- }
-
- // TODO: refactor so we don't need to call this
- rb_ractor_finish_marking();
-
- rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_END_MARK);
-}
-
-static bool
-gc_compact_heap_cursors_met_p(rb_heap_t *heap)
-{
- return heap->sweeping_page == heap->compact_cursor;
-}
-
-
-static rb_heap_t *
-gc_compact_destination_pool(rb_objspace_t *objspace, rb_heap_t *src_pool, VALUE obj)
-{
- size_t obj_size = rb_gc_obj_optimal_size(obj);
- if (obj_size == 0) {
- return src_pool;
- }
-
- size_t idx = 0;
- if (rb_gc_impl_size_allocatable_p(obj_size)) {
- idx = heap_idx_for_size(obj_size);
- }
-
- return &heaps[idx];
-}
-
-static bool
-gc_compact_move(rb_objspace_t *objspace, rb_heap_t *heap, VALUE src)
-{
- GC_ASSERT(BUILTIN_TYPE(src) != T_MOVED);
- GC_ASSERT(gc_is_moveable_obj(objspace, src));
-
- rb_heap_t *dest_pool = gc_compact_destination_pool(objspace, heap, src);
- uint32_t orig_shape = 0;
- uint32_t new_shape = 0;
-
- if (gc_compact_heap_cursors_met_p(dest_pool)) {
- return dest_pool != heap;
- }
-
- if (RB_TYPE_P(src, T_OBJECT)) {
- orig_shape = rb_gc_get_shape(src);
-
- if (dest_pool != heap) {
- new_shape = rb_gc_rebuild_shape(src, dest_pool - heaps);
-
- if (new_shape == 0) {
- dest_pool = heap;
- }
- }
- }
-
- while (!try_move(objspace, dest_pool, dest_pool->free_pages, src)) {
- struct gc_sweep_context ctx = {
- .page = dest_pool->sweeping_page,
- .final_slots = 0,
- .freed_slots = 0,
- .empty_slots = 0,
- };
-
- /* The page of src could be partially compacted, so it may contain
- * T_MOVED. Sweeping a page may read objects on this page, so we
- * need to lock the page. */
- lock_page_body(objspace, GET_PAGE_BODY(src));
- gc_sweep_page(objspace, dest_pool, &ctx);
- unlock_page_body(objspace, GET_PAGE_BODY(src));
-
- if (dest_pool->sweeping_page->free_slots > 0) {
- heap_add_freepage(dest_pool, dest_pool->sweeping_page);
- }
-
- dest_pool->sweeping_page = ccan_list_next(&dest_pool->pages, dest_pool->sweeping_page, page_node);
- if (gc_compact_heap_cursors_met_p(dest_pool)) {
- return dest_pool != heap;
- }
- }
-
- if (orig_shape != 0) {
- if (new_shape != 0) {
- VALUE dest = rb_gc_impl_location(objspace, src);
- rb_gc_set_shape(dest, new_shape);
- }
- RMOVED(src)->original_shape_id = orig_shape;
- }
-
- return true;
-}
-
-static bool
-gc_compact_plane(rb_objspace_t *objspace, rb_heap_t *heap, uintptr_t p, bits_t bitset, struct heap_page *page)
-{
- short slot_size = page->slot_size;
- short slot_bits = slot_size / BASE_SLOT_SIZE;
- GC_ASSERT(slot_bits > 0);
-
- do {
- VALUE vp = (VALUE)p;
- GC_ASSERT(vp % BASE_SLOT_SIZE == 0);
-
- if (bitset & 1) {
- objspace->rcompactor.considered_count_table[BUILTIN_TYPE(vp)]++;
-
- if (gc_is_moveable_obj(objspace, vp)) {
- if (!gc_compact_move(objspace, heap, vp)) {
- //the cursors met. bubble up
- return false;
- }
- }
- }
- p += slot_size;
- bitset >>= slot_bits;
- } while (bitset);
-
- return true;
-}
-
-// Iterate up all the objects in page, moving them to where they want to go
-static bool
-gc_compact_page(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page)
-{
- GC_ASSERT(page == heap->compact_cursor);
-
- bits_t *mark_bits, *pin_bits;
- bits_t bitset;
- uintptr_t p = page->start;
-
- mark_bits = page->mark_bits;
- pin_bits = page->pinned_bits;
-
- // objects that can be moved are marked and not pinned
- bitset = (mark_bits[0] & ~pin_bits[0]);
- bitset >>= NUM_IN_PAGE(p);
- if (bitset) {
- if (!gc_compact_plane(objspace, heap, (uintptr_t)p, bitset, page))
- return false;
- }
- p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
-
- for (int j = 1; j < HEAP_PAGE_BITMAP_LIMIT; j++) {
- bitset = (mark_bits[j] & ~pin_bits[j]);
- if (bitset) {
- if (!gc_compact_plane(objspace, heap, (uintptr_t)p, bitset, page))
- return false;
- }
- p += BITS_BITLENGTH * BASE_SLOT_SIZE;
- }
-
- return true;
-}
-
-static bool
-gc_compact_all_compacted_p(rb_objspace_t *objspace)
-{
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
-
- if (heap->total_pages > 0 &&
- !gc_compact_heap_cursors_met_p(heap)) {
- return false;
- }
- }
-
- return true;
-}
-
-static void
-gc_sweep_compact(rb_objspace_t *objspace)
-{
- gc_compact_start(objspace);
-#if RGENGC_CHECK_MODE >= 2
- gc_verify_internal_consistency(objspace);
-#endif
-
- while (!gc_compact_all_compacted_p(objspace)) {
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
-
- if (gc_compact_heap_cursors_met_p(heap)) {
- continue;
- }
-
- struct heap_page *start_page = heap->compact_cursor;
-
- if (!gc_compact_page(objspace, heap, start_page)) {
- lock_page_body(objspace, start_page->body);
-
- continue;
- }
-
- // If we get here, we've finished moving all objects on the compact_cursor page
- // So we can lock it and move the cursor on to the next one.
- lock_page_body(objspace, start_page->body);
- heap->compact_cursor = ccan_list_prev(&heap->pages, heap->compact_cursor, page_node);
- }
- }
-
- gc_compact_finish(objspace);
-
-#if RGENGC_CHECK_MODE >= 2
- gc_verify_internal_consistency(objspace);
-#endif
-}
-
-static void
-gc_marks_rest(rb_objspace_t *objspace)
-{
- gc_report(1, objspace, "gc_marks_rest\n");
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- (&heaps[i])->pooled_pages = NULL;
- }
-
- if (is_incremental_marking(objspace)) {
- while (gc_mark_stacked_objects_incremental(objspace, INT_MAX) == FALSE);
- }
- else {
- gc_mark_stacked_objects_all(objspace);
- }
-
- gc_marks_finish(objspace);
-}
-
-static bool
-gc_marks_step(rb_objspace_t *objspace, size_t slots)
-{
- bool marking_finished = false;
-
- GC_ASSERT(is_marking(objspace));
- if (gc_mark_stacked_objects_incremental(objspace, slots)) {
- gc_marks_finish(objspace);
-
- marking_finished = true;
- }
-
- return marking_finished;
-}
-
-static bool
-gc_marks_continue(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- GC_ASSERT(dont_gc_val() == FALSE || objspace->profile.latest_gc_info & GPR_FLAG_METHOD);
- bool marking_finished = true;
-
- gc_marking_enter(objspace);
-
- if (heap->free_pages) {
- gc_report(2, objspace, "gc_marks_continue: has pooled pages");
-
- marking_finished = gc_marks_step(objspace, objspace->rincgc.step_slots);
- }
- else {
- gc_report(2, objspace, "gc_marks_continue: no more pooled pages (stack depth: %"PRIdSIZE").\n",
- mark_stack_size(&objspace->mark_stack));
- heap->force_incremental_marking_finish_count++;
- gc_marks_rest(objspace);
- }
-
- gc_marking_exit(objspace);
-
- return marking_finished;
-}
-
-static void
-gc_marks_start(rb_objspace_t *objspace, int full_mark)
-{
- /* start marking */
- gc_report(1, objspace, "gc_marks_start: (%s)\n", full_mark ? "full" : "minor");
- gc_mode_transition(objspace, gc_mode_marking);
-
- if (full_mark) {
- size_t incremental_marking_steps = (objspace->rincgc.pooled_slots / INCREMENTAL_MARK_STEP_ALLOCATIONS) + 1;
- objspace->rincgc.step_slots = (objspace->marked_slots * 2) / incremental_marking_steps;
-
- if (0) fprintf(stderr, "objspace->marked_slots: %"PRIdSIZE", "
- "objspace->rincgc.pooled_page_num: %"PRIdSIZE", "
- "objspace->rincgc.step_slots: %"PRIdSIZE", \n",
- objspace->marked_slots, objspace->rincgc.pooled_slots, objspace->rincgc.step_slots);
- objspace->flags.during_minor_gc = FALSE;
- if (ruby_enable_autocompact) {
- objspace->flags.during_compacting |= TRUE;
- }
- objspace->profile.major_gc_count++;
- objspace->rgengc.uncollectible_wb_unprotected_objects = 0;
- objspace->rgengc.old_objects = 0;
- objspace->rgengc.last_major_gc = objspace->profile.count;
- objspace->marked_slots = 0;
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- rgengc_mark_and_rememberset_clear(objspace, heap);
- heap_move_pooled_pages_to_free_pages(heap);
-
- if (objspace->flags.during_compacting) {
- struct heap_page *page = NULL;
-
- ccan_list_for_each(&heap->pages, page, page_node) {
- page->pinned_slots = 0;
- }
- }
- }
- }
- else {
- objspace->flags.during_minor_gc = TRUE;
- objspace->marked_slots =
- objspace->rgengc.old_objects + objspace->rgengc.uncollectible_wb_unprotected_objects; /* uncollectible objects are marked already */
- objspace->profile.minor_gc_count++;
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- rgengc_rememberset_mark(objspace, &heaps[i]);
- }
- }
-
- mark_roots(objspace, NULL);
-
- gc_report(1, objspace, "gc_marks_start: (%s) end, stack in %"PRIdSIZE"\n",
- full_mark ? "full" : "minor", mark_stack_size(&objspace->mark_stack));
-}
-
-static bool
-gc_marks(rb_objspace_t *objspace, int full_mark)
-{
- gc_prof_mark_timer_start(objspace);
- gc_marking_enter(objspace);
-
- bool marking_finished = false;
-
- /* setup marking */
-
- gc_marks_start(objspace, full_mark);
- if (!is_incremental_marking(objspace)) {
- gc_marks_rest(objspace);
- marking_finished = true;
- }
-
-#if RGENGC_PROFILE > 0
- if (gc_prof_record(objspace)) {
- gc_profile_record *record = gc_prof_record(objspace);
- record->old_objects = objspace->rgengc.old_objects;
- }
-#endif
-
- gc_marking_exit(objspace);
- gc_prof_mark_timer_stop(objspace);
-
- return marking_finished;
-}
-
-/* RGENGC */
-
-static void
-gc_report_body(int level, rb_objspace_t *objspace, const char *fmt, ...)
-{
- if (level <= RGENGC_DEBUG) {
- char buf[1024];
- FILE *out = stderr;
- va_list args;
- const char *status = " ";
-
- if (during_gc) {
- status = is_full_marking(objspace) ? "+" : "-";
- }
- else {
- if (is_lazy_sweeping(objspace)) {
- status = "S";
- }
- if (is_incremental_marking(objspace)) {
- status = "M";
- }
- }
-
- va_start(args, fmt);
- vsnprintf(buf, 1024, fmt, args);
- va_end(args);
-
- fprintf(out, "%s|", status);
- fputs(buf, out);
- }
-}
-
-/* bit operations */
-
-static int
-rgengc_remembersetbits_set(rb_objspace_t *objspace, VALUE obj)
-{
- struct heap_page *page = GET_HEAP_PAGE(obj);
- bits_t *bits = &page->remembered_bits[0];
-
- if (MARKED_IN_BITMAP(bits, obj)) {
- return FALSE;
- }
- else {
- page->flags.has_remembered_objects = TRUE;
- MARK_IN_BITMAP(bits, obj);
- return TRUE;
- }
-}
-
-/* wb, etc */
-
-/* return FALSE if already remembered */
-static int
-rgengc_remember(rb_objspace_t *objspace, VALUE obj)
-{
- gc_report(6, objspace, "rgengc_remember: %s %s\n", rb_obj_info(obj),
- RVALUE_REMEMBERED(objspace, obj) ? "was already remembered" : "is remembered now");
-
- check_rvalue_consistency(objspace, obj);
-
- if (RGENGC_CHECK_MODE) {
- if (RVALUE_WB_UNPROTECTED(objspace, obj)) rb_bug("rgengc_remember: %s is not wb protected.", rb_obj_info(obj));
- }
-
-#if RGENGC_PROFILE > 0
- if (!RVALUE_REMEMBERED(objspace, obj)) {
- if (RVALUE_WB_UNPROTECTED(objspace, obj) == 0) {
- objspace->profile.total_remembered_normal_object_count++;
-#if RGENGC_PROFILE >= 2
- objspace->profile.remembered_normal_object_count_types[BUILTIN_TYPE(obj)]++;
-#endif
- }
- }
-#endif /* RGENGC_PROFILE > 0 */
-
- return rgengc_remembersetbits_set(objspace, obj);
-}
-
-#ifndef PROFILE_REMEMBERSET_MARK
-#define PROFILE_REMEMBERSET_MARK 0
-#endif
-
-static inline void
-rgengc_rememberset_mark_plane(rb_objspace_t *objspace, uintptr_t p, bits_t bitset)
-{
- if (bitset) {
- do {
- if (bitset & 1) {
- VALUE obj = (VALUE)p;
- gc_report(2, objspace, "rgengc_rememberset_mark: mark %s\n", rb_obj_info(obj));
- GC_ASSERT(RVALUE_UNCOLLECTIBLE(objspace, obj));
- GC_ASSERT(RVALUE_OLD_P(objspace, obj) || RVALUE_WB_UNPROTECTED(objspace, obj));
-
- gc_mark_children(objspace, obj);
- }
- p += BASE_SLOT_SIZE;
- bitset >>= 1;
- } while (bitset);
- }
-}
-
-static void
-rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- size_t j;
- struct heap_page *page = 0;
-#if PROFILE_REMEMBERSET_MARK
- int has_old = 0, has_shady = 0, has_both = 0, skip = 0;
-#endif
- gc_report(1, objspace, "rgengc_rememberset_mark: start\n");
-
- ccan_list_for_each(&heap->pages, page, page_node) {
- if (page->flags.has_remembered_objects | page->flags.has_uncollectible_wb_unprotected_objects) {
- uintptr_t p = page->start;
- bits_t bitset, bits[HEAP_PAGE_BITMAP_LIMIT];
- bits_t *remembered_bits = page->remembered_bits;
- bits_t *uncollectible_bits = page->uncollectible_bits;
- bits_t *wb_unprotected_bits = page->wb_unprotected_bits;
-#if PROFILE_REMEMBERSET_MARK
- if (page->flags.has_remembered_objects && page->flags.has_uncollectible_wb_unprotected_objects) has_both++;
- else if (page->flags.has_remembered_objects) has_old++;
- else if (page->flags.has_uncollectible_wb_unprotected_objects) has_shady++;
-#endif
- for (j=0; j<HEAP_PAGE_BITMAP_LIMIT; j++) {
- bits[j] = remembered_bits[j] | (uncollectible_bits[j] & wb_unprotected_bits[j]);
- remembered_bits[j] = 0;
- }
- page->flags.has_remembered_objects = FALSE;
-
- bitset = bits[0];
- bitset >>= NUM_IN_PAGE(p);
- rgengc_rememberset_mark_plane(objspace, p, bitset);
- p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
-
- for (j=1; j < HEAP_PAGE_BITMAP_LIMIT; j++) {
- bitset = bits[j];
- rgengc_rememberset_mark_plane(objspace, p, bitset);
- p += BITS_BITLENGTH * BASE_SLOT_SIZE;
- }
- }
-#if PROFILE_REMEMBERSET_MARK
- else {
- skip++;
- }
-#endif
- }
-
-#if PROFILE_REMEMBERSET_MARK
- fprintf(stderr, "%d\t%d\t%d\t%d\n", has_both, has_old, has_shady, skip);
-#endif
- gc_report(1, objspace, "rgengc_rememberset_mark: finished\n");
-}
-
-static void
-rgengc_mark_and_rememberset_clear(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- struct heap_page *page = 0;
-
- ccan_list_for_each(&heap->pages, page, page_node) {
- memset(&page->mark_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
- memset(&page->uncollectible_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
- memset(&page->marking_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
- memset(&page->remembered_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
- memset(&page->pinned_bits[0], 0, HEAP_PAGE_BITMAP_SIZE);
- page->flags.has_uncollectible_wb_unprotected_objects = FALSE;
- page->flags.has_remembered_objects = FALSE;
- }
-}
-
-/* RGENGC: APIs */
-
-NOINLINE(static void gc_writebarrier_generational(VALUE a, VALUE b, rb_objspace_t *objspace));
-
-static void
-gc_writebarrier_generational(VALUE a, VALUE b, rb_objspace_t *objspace)
-{
- if (RGENGC_CHECK_MODE) {
- if (!RVALUE_OLD_P(objspace, a)) rb_bug("gc_writebarrier_generational: %s is not an old object.", rb_obj_info(a));
- if ( RVALUE_OLD_P(objspace, b)) rb_bug("gc_writebarrier_generational: %s is an old object.", rb_obj_info(b));
- if (is_incremental_marking(objspace)) rb_bug("gc_writebarrier_generational: called while incremental marking: %s -> %s", rb_obj_info(a), rb_obj_info(b));
- }
-
- /* mark `a' and remember (default behavior) */
- if (!RVALUE_REMEMBERED(objspace, a)) {
- int lev = rb_gc_vm_lock_no_barrier();
- {
- rgengc_remember(objspace, a);
- }
- rb_gc_vm_unlock_no_barrier(lev);
-
- gc_report(1, objspace, "gc_writebarrier_generational: %s (remembered) -> %s\n", rb_obj_info(a), rb_obj_info(b));
- }
-
- check_rvalue_consistency(objspace, a);
- check_rvalue_consistency(objspace, b);
-}
-
-static void
-gc_mark_from(rb_objspace_t *objspace, VALUE obj, VALUE parent)
-{
- gc_mark_set_parent(objspace, parent);
- rgengc_check_relation(objspace, obj);
- if (gc_mark_set(objspace, obj) == FALSE) return;
- gc_aging(objspace, obj);
- gc_grey(objspace, obj);
-}
-
-NOINLINE(static void gc_writebarrier_incremental(VALUE a, VALUE b, rb_objspace_t *objspace));
-
-static void
-gc_writebarrier_incremental(VALUE a, VALUE b, rb_objspace_t *objspace)
-{
- gc_report(2, objspace, "gc_writebarrier_incremental: [LG] %p -> %s\n", (void *)a, rb_obj_info(b));
-
- if (RVALUE_BLACK_P(objspace, a)) {
- if (RVALUE_WHITE_P(objspace, b)) {
- if (!RVALUE_WB_UNPROTECTED(objspace, a)) {
- gc_report(2, objspace, "gc_writebarrier_incremental: [IN] %p -> %s\n", (void *)a, rb_obj_info(b));
- gc_mark_from(objspace, b, a);
- }
- }
- else if (RVALUE_OLD_P(objspace, a) && !RVALUE_OLD_P(objspace, b)) {
- rgengc_remember(objspace, a);
- }
-
- if (RB_UNLIKELY(objspace->flags.during_compacting)) {
- MARK_IN_BITMAP(GET_HEAP_PINNED_BITS(b), b);
- }
- }
-}
-
-void
-rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- if (RGENGC_CHECK_MODE) {
- if (SPECIAL_CONST_P(a)) rb_bug("rb_gc_writebarrier: a is special const: %"PRIxVALUE, a);
- if (SPECIAL_CONST_P(b)) rb_bug("rb_gc_writebarrier: b is special const: %"PRIxVALUE, b);
- }
-
- GC_ASSERT(RB_BUILTIN_TYPE(a) != T_NONE);
- GC_ASSERT(RB_BUILTIN_TYPE(a) != T_MOVED);
- GC_ASSERT(RB_BUILTIN_TYPE(a) != T_ZOMBIE);
- GC_ASSERT(RB_BUILTIN_TYPE(b) != T_NONE);
- GC_ASSERT(RB_BUILTIN_TYPE(b) != T_MOVED);
- GC_ASSERT(RB_BUILTIN_TYPE(b) != T_ZOMBIE);
-
- retry:
- if (!is_incremental_marking(objspace)) {
- if (!RVALUE_OLD_P(objspace, a) || RVALUE_OLD_P(objspace, b)) {
- // do nothing
- }
- else {
- gc_writebarrier_generational(a, b, objspace);
- }
- }
- else {
- bool retry = false;
- /* slow path */
- int lev = rb_gc_vm_lock_no_barrier();
- {
- if (is_incremental_marking(objspace)) {
- gc_writebarrier_incremental(a, b, objspace);
- }
- else {
- retry = true;
- }
- }
- rb_gc_vm_unlock_no_barrier(lev);
-
- if (retry) goto retry;
- }
- return;
-}
-
-void
-rb_gc_impl_writebarrier_unprotect(void *objspace_ptr, VALUE obj)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- if (RVALUE_WB_UNPROTECTED(objspace, obj)) {
- return;
- }
- else {
- gc_report(2, objspace, "rb_gc_writebarrier_unprotect: %s %s\n", rb_obj_info(obj),
- RVALUE_REMEMBERED(objspace, obj) ? " (already remembered)" : "");
-
- unsigned int lev = rb_gc_vm_lock_no_barrier();
- {
- if (RVALUE_OLD_P(objspace, obj)) {
- gc_report(1, objspace, "rb_gc_writebarrier_unprotect: %s\n", rb_obj_info(obj));
- RVALUE_DEMOTE(objspace, obj);
- gc_mark_set(objspace, obj);
- gc_remember_unprotected(objspace, obj);
-
-#if RGENGC_PROFILE
- objspace->profile.total_shade_operation_count++;
-#if RGENGC_PROFILE >= 2
- objspace->profile.shade_operation_count_types[BUILTIN_TYPE(obj)]++;
-#endif /* RGENGC_PROFILE >= 2 */
-#endif /* RGENGC_PROFILE */
- }
- else {
- RVALUE_AGE_RESET(obj);
- }
-
- RB_DEBUG_COUNTER_INC(obj_wb_unprotect);
- MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), obj);
- }
- rb_gc_vm_unlock_no_barrier(lev);
- }
-}
-
-void
-rb_gc_impl_copy_attributes(void *objspace_ptr, VALUE dest, VALUE obj)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- if (RVALUE_WB_UNPROTECTED(objspace, obj)) {
- rb_gc_writebarrier_unprotect(dest);
- }
- rb_gc_copy_finalizer(dest, obj);
-}
-
-void
-rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- gc_report(1, objspace, "rb_gc_writebarrier_remember: %s\n", rb_obj_info(obj));
-
- if (is_incremental_marking(objspace)) {
- if (RVALUE_BLACK_P(objspace, obj)) {
- gc_grey(objspace, obj);
- }
- }
- else {
- if (RVALUE_OLD_P(objspace, obj)) {
- rgengc_remember(objspace, obj);
- }
- }
-}
-
-// TODO: rearchitect this function to work for a generic GC
-size_t
-rb_gc_impl_obj_flags(void *objspace_ptr, VALUE obj, ID* flags, size_t max)
-{
- rb_objspace_t *objspace = objspace_ptr;
- size_t n = 0;
- static ID ID_marked;
- static ID ID_wb_protected, ID_old, ID_marking, ID_uncollectible, ID_pinned;
-
- if (!ID_marked) {
-#define I(s) ID_##s = rb_intern(#s);
- I(marked);
- I(wb_protected);
- I(old);
- I(marking);
- I(uncollectible);
- I(pinned);
-#undef I
- }
-
- if (RVALUE_WB_UNPROTECTED(objspace, obj) == 0 && n < max) flags[n++] = ID_wb_protected;
- if (RVALUE_OLD_P(objspace, obj) && n < max) flags[n++] = ID_old;
- if (RVALUE_UNCOLLECTIBLE(objspace, obj) && n < max) flags[n++] = ID_uncollectible;
- if (RVALUE_MARKING(objspace, obj) && n < max) flags[n++] = ID_marking;
- if (RVALUE_MARKED(objspace, obj) && n < max) flags[n++] = ID_marked;
- if (RVALUE_PINNED(objspace, obj) && n < max) flags[n++] = ID_pinned;
- return n;
-}
-
-void *
-rb_gc_impl_ractor_cache_alloc(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- objspace->live_ractor_cache_count++;
-
- return calloc1(sizeof(rb_ractor_newobj_cache_t));
-}
-
-void
-rb_gc_impl_ractor_cache_free(void *objspace_ptr, void *cache)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- objspace->live_ractor_cache_count--;
-
- gc_ractor_newobj_cache_clear(cache, NULL);
- free(cache);
-}
-
-static void
-heap_ready_to_gc(rb_objspace_t *objspace, rb_heap_t *heap)
-{
- if (!heap->free_pages) {
- if (!heap_page_allocate_and_initialize(objspace, heap)) {
- objspace->heap_pages.allocatable_slots = 1;
- heap_page_allocate_and_initialize(objspace, heap);
- }
- }
-}
-
-static int
-ready_to_gc(rb_objspace_t *objspace)
-{
- if (dont_gc_val() || during_gc || ruby_disable_gc) {
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- heap_ready_to_gc(objspace, heap);
- }
- return FALSE;
- }
- else {
- return TRUE;
- }
-}
-
-static void
-gc_reset_malloc_info(rb_objspace_t *objspace, bool full_mark)
-{
- gc_prof_set_malloc_info(objspace);
- {
- size_t inc = RUBY_ATOMIC_SIZE_EXCHANGE(malloc_increase, 0);
- size_t old_limit = malloc_limit;
-
- if (inc > malloc_limit) {
- malloc_limit = (size_t)(inc * gc_params.malloc_limit_growth_factor);
- if (malloc_limit > gc_params.malloc_limit_max) {
- malloc_limit = gc_params.malloc_limit_max;
- }
- }
- else {
- malloc_limit = (size_t)(malloc_limit * 0.98); /* magic number */
- if (malloc_limit < gc_params.malloc_limit_min) {
- malloc_limit = gc_params.malloc_limit_min;
- }
- }
-
- if (0) {
- if (old_limit != malloc_limit) {
- fprintf(stderr, "[%"PRIuSIZE"] malloc_limit: %"PRIuSIZE" -> %"PRIuSIZE"\n",
- rb_gc_count(), old_limit, malloc_limit);
- }
- else {
- fprintf(stderr, "[%"PRIuSIZE"] malloc_limit: not changed (%"PRIuSIZE")\n",
- rb_gc_count(), malloc_limit);
- }
- }
- }
-
- /* reset oldmalloc info */
-#if RGENGC_ESTIMATE_OLDMALLOC
- if (!full_mark) {
- if (objspace->rgengc.oldmalloc_increase > objspace->rgengc.oldmalloc_increase_limit) {
- gc_needs_major_flags |= GPR_FLAG_MAJOR_BY_OLDMALLOC;
- objspace->rgengc.oldmalloc_increase_limit =
- (size_t)(objspace->rgengc.oldmalloc_increase_limit * gc_params.oldmalloc_limit_growth_factor);
-
- if (objspace->rgengc.oldmalloc_increase_limit > gc_params.oldmalloc_limit_max) {
- objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_max;
- }
- }
-
- if (0) fprintf(stderr, "%"PRIdSIZE"\t%d\t%"PRIuSIZE"\t%"PRIuSIZE"\t%"PRIdSIZE"\n",
- rb_gc_count(),
- gc_needs_major_flags,
- objspace->rgengc.oldmalloc_increase,
- objspace->rgengc.oldmalloc_increase_limit,
- gc_params.oldmalloc_limit_max);
- }
- else {
- /* major GC */
- objspace->rgengc.oldmalloc_increase = 0;
-
- if ((objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_BY_OLDMALLOC) == 0) {
- objspace->rgengc.oldmalloc_increase_limit =
- (size_t)(objspace->rgengc.oldmalloc_increase_limit / ((gc_params.oldmalloc_limit_growth_factor - 1)/10 + 1));
- if (objspace->rgengc.oldmalloc_increase_limit < gc_params.oldmalloc_limit_min) {
- objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_min;
- }
- }
- }
-#endif
-}
-
-static int
-garbage_collect(rb_objspace_t *objspace, unsigned int reason)
-{
- int ret;
-
- int lev = rb_gc_vm_lock();
- {
-#if GC_PROFILE_MORE_DETAIL
- objspace->profile.prepare_time = getrusage_time();
-#endif
-
- gc_rest(objspace);
-
-#if GC_PROFILE_MORE_DETAIL
- objspace->profile.prepare_time = getrusage_time() - objspace->profile.prepare_time;
-#endif
-
- ret = gc_start(objspace, reason);
- }
- rb_gc_vm_unlock(lev);
-
- return ret;
-}
-
-static int
-gc_start(rb_objspace_t *objspace, unsigned int reason)
-{
- unsigned int do_full_mark = !!(reason & GPR_FLAG_FULL_MARK);
-
- /* reason may be clobbered, later, so keep set immediate_sweep here */
- objspace->flags.immediate_sweep = !!(reason & GPR_FLAG_IMMEDIATE_SWEEP);
-
- if (!rb_darray_size(objspace->heap_pages.sorted)) return TRUE; /* heap is not ready */
- if (!(reason & GPR_FLAG_METHOD) && !ready_to_gc(objspace)) return TRUE; /* GC is not allowed */
-
- GC_ASSERT(gc_mode(objspace) == gc_mode_none);
- GC_ASSERT(!is_lazy_sweeping(objspace));
- GC_ASSERT(!is_incremental_marking(objspace));
-
- unsigned int lock_lev;
- gc_enter(objspace, gc_enter_event_start, &lock_lev);
-
-#if RGENGC_CHECK_MODE >= 2
- gc_verify_internal_consistency(objspace);
-#endif
-
- if (ruby_gc_stressful) {
- int flag = FIXNUM_P(ruby_gc_stress_mode) ? FIX2INT(ruby_gc_stress_mode) : 0;
-
- if ((flag & (1 << gc_stress_no_major)) == 0) {
- do_full_mark = TRUE;
- }
-
- objspace->flags.immediate_sweep = !(flag & (1<<gc_stress_no_immediate_sweep));
- }
-
- if (gc_needs_major_flags) {
- reason |= gc_needs_major_flags;
- do_full_mark = TRUE;
- }
- else if (RGENGC_FORCE_MAJOR_GC) {
- reason = GPR_FLAG_MAJOR_BY_FORCE;
- do_full_mark = TRUE;
- }
-
- /* if major gc has been disabled, never do a full mark */
- if (!gc_config_full_mark_val) {
- do_full_mark = FALSE;
- }
- gc_needs_major_flags = GPR_FLAG_NONE;
-
- if (do_full_mark && (reason & GPR_FLAG_MAJOR_MASK) == 0) {
- reason |= GPR_FLAG_MAJOR_BY_FORCE; /* GC by CAPI, METHOD, and so on. */
- }
-
- if (objspace->flags.dont_incremental ||
- reason & GPR_FLAG_IMMEDIATE_MARK ||
- ruby_gc_stressful) {
- objspace->flags.during_incremental_marking = FALSE;
- }
- else {
- objspace->flags.during_incremental_marking = do_full_mark;
- }
-
- /* Explicitly enable compaction (GC.compact) */
- if (do_full_mark && ruby_enable_autocompact) {
- objspace->flags.during_compacting = TRUE;
-#if RGENGC_CHECK_MODE
- objspace->rcompactor.compare_func = ruby_autocompact_compare_func;
-#endif
- }
- else {
- objspace->flags.during_compacting = !!(reason & GPR_FLAG_COMPACT);
- }
-
- if (!GC_ENABLE_LAZY_SWEEP || objspace->flags.dont_incremental) {
- objspace->flags.immediate_sweep = TRUE;
- }
-
- if (objspace->flags.immediate_sweep) reason |= GPR_FLAG_IMMEDIATE_SWEEP;
-
- gc_report(1, objspace, "gc_start(reason: %x) => %u, %d, %d\n",
- reason,
- do_full_mark, !is_incremental_marking(objspace), objspace->flags.immediate_sweep);
-
-#if USE_DEBUG_COUNTER
- RB_DEBUG_COUNTER_INC(gc_count);
-
- if (reason & GPR_FLAG_MAJOR_MASK) {
- (void)RB_DEBUG_COUNTER_INC_IF(gc_major_nofree, reason & GPR_FLAG_MAJOR_BY_NOFREE);
- (void)RB_DEBUG_COUNTER_INC_IF(gc_major_oldgen, reason & GPR_FLAG_MAJOR_BY_OLDGEN);
- (void)RB_DEBUG_COUNTER_INC_IF(gc_major_shady, reason & GPR_FLAG_MAJOR_BY_SHADY);
- (void)RB_DEBUG_COUNTER_INC_IF(gc_major_force, reason & GPR_FLAG_MAJOR_BY_FORCE);
-#if RGENGC_ESTIMATE_OLDMALLOC
- (void)RB_DEBUG_COUNTER_INC_IF(gc_major_oldmalloc, reason & GPR_FLAG_MAJOR_BY_OLDMALLOC);
-#endif
- }
- else {
- (void)RB_DEBUG_COUNTER_INC_IF(gc_minor_newobj, reason & GPR_FLAG_NEWOBJ);
- (void)RB_DEBUG_COUNTER_INC_IF(gc_minor_malloc, reason & GPR_FLAG_MALLOC);
- (void)RB_DEBUG_COUNTER_INC_IF(gc_minor_method, reason & GPR_FLAG_METHOD);
- (void)RB_DEBUG_COUNTER_INC_IF(gc_minor_capi, reason & GPR_FLAG_CAPI);
- (void)RB_DEBUG_COUNTER_INC_IF(gc_minor_stress, reason & GPR_FLAG_STRESS);
- }
-#endif
-
- objspace->profile.count++;
- objspace->profile.latest_gc_info = reason;
- objspace->profile.total_allocated_objects_at_gc_start = total_allocated_objects(objspace);
- objspace->profile.heap_used_at_gc_start = rb_darray_size(objspace->heap_pages.sorted);
- objspace->profile.weak_references_count = 0;
- objspace->profile.retained_weak_references_count = 0;
- gc_prof_setup_new_record(objspace, reason);
- gc_reset_malloc_info(objspace, do_full_mark);
-
- rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_START);
-
- GC_ASSERT(during_gc);
-
- gc_prof_timer_start(objspace);
- {
- if (gc_marks(objspace, do_full_mark)) {
- gc_sweep(objspace);
- }
- }
- gc_prof_timer_stop(objspace);
-
- gc_exit(objspace, gc_enter_event_start, &lock_lev);
- return TRUE;
-}
-
-static void
-gc_rest(rb_objspace_t *objspace)
-{
- if (is_incremental_marking(objspace) || is_lazy_sweeping(objspace)) {
- unsigned int lock_lev;
- gc_enter(objspace, gc_enter_event_rest, &lock_lev);
-
- if (RGENGC_CHECK_MODE >= 2) gc_verify_internal_consistency(objspace);
-
- if (is_incremental_marking(objspace)) {
- gc_marking_enter(objspace);
- gc_marks_rest(objspace);
- gc_marking_exit(objspace);
-
- gc_sweep(objspace);
- }
-
- if (is_lazy_sweeping(objspace)) {
- gc_sweeping_enter(objspace);
- gc_sweep_rest(objspace);
- gc_sweeping_exit(objspace);
- }
-
- gc_exit(objspace, gc_enter_event_rest, &lock_lev);
- }
-}
-
-struct objspace_and_reason {
- rb_objspace_t *objspace;
- unsigned int reason;
-};
-
-static void
-gc_current_status_fill(rb_objspace_t *objspace, char *buff)
-{
- int i = 0;
- if (is_marking(objspace)) {
- buff[i++] = 'M';
- if (is_full_marking(objspace)) buff[i++] = 'F';
- if (is_incremental_marking(objspace)) buff[i++] = 'I';
- }
- else if (is_sweeping(objspace)) {
- buff[i++] = 'S';
- if (is_lazy_sweeping(objspace)) buff[i++] = 'L';
- }
- else {
- buff[i++] = 'N';
- }
- buff[i] = '\0';
-}
-
-static const char *
-gc_current_status(rb_objspace_t *objspace)
-{
- static char buff[0x10];
- gc_current_status_fill(objspace, buff);
- return buff;
-}
-
-#if PRINT_ENTER_EXIT_TICK
-
-static tick_t last_exit_tick;
-static tick_t enter_tick;
-static int enter_count = 0;
-static char last_gc_status[0x10];
-
-static inline void
-gc_record(rb_objspace_t *objspace, int direction, const char *event)
-{
- if (direction == 0) { /* enter */
- enter_count++;
- enter_tick = tick();
- gc_current_status_fill(objspace, last_gc_status);
- }
- else { /* exit */
- tick_t exit_tick = tick();
- char current_gc_status[0x10];
- gc_current_status_fill(objspace, current_gc_status);
-#if 1
- /* [last mutator time] [gc time] [event] */
- fprintf(stderr, "%"PRItick"\t%"PRItick"\t%s\t[%s->%s|%c]\n",
- enter_tick - last_exit_tick,
- exit_tick - enter_tick,
- event,
- last_gc_status, current_gc_status,
- (objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_MASK) ? '+' : '-');
- last_exit_tick = exit_tick;
-#else
- /* [enter_tick] [gc time] [event] */
- fprintf(stderr, "%"PRItick"\t%"PRItick"\t%s\t[%s->%s|%c]\n",
- enter_tick,
- exit_tick - enter_tick,
- event,
- last_gc_status, current_gc_status,
- (objspace->profile.latest_gc_info & GPR_FLAG_MAJOR_MASK) ? '+' : '-');
-#endif
- }
-}
-#else /* PRINT_ENTER_EXIT_TICK */
-static inline void
-gc_record(rb_objspace_t *objspace, int direction, const char *event)
-{
- /* null */
-}
-#endif /* PRINT_ENTER_EXIT_TICK */
-
-static const char *
-gc_enter_event_cstr(enum gc_enter_event event)
-{
- switch (event) {
- case gc_enter_event_start: return "start";
- case gc_enter_event_continue: return "continue";
- case gc_enter_event_rest: return "rest";
- case gc_enter_event_finalizer: return "finalizer";
- }
- return NULL;
-}
-
-static void
-gc_enter_count(enum gc_enter_event event)
-{
- switch (event) {
- case gc_enter_event_start: RB_DEBUG_COUNTER_INC(gc_enter_start); break;
- case gc_enter_event_continue: RB_DEBUG_COUNTER_INC(gc_enter_continue); break;
- case gc_enter_event_rest: RB_DEBUG_COUNTER_INC(gc_enter_rest); break;
- case gc_enter_event_finalizer: RB_DEBUG_COUNTER_INC(gc_enter_finalizer); break;
- }
-}
-
-static bool current_process_time(struct timespec *ts);
-
-static void
-gc_clock_start(struct timespec *ts)
-{
- if (!current_process_time(ts)) {
- ts->tv_sec = 0;
- ts->tv_nsec = 0;
- }
-}
-
-static unsigned long long
-gc_clock_end(struct timespec *ts)
-{
- struct timespec end_time;
-
- if ((ts->tv_sec > 0 || ts->tv_nsec > 0) &&
- current_process_time(&end_time) &&
- end_time.tv_sec >= ts->tv_sec) {
- return (unsigned long long)(end_time.tv_sec - ts->tv_sec) * (1000 * 1000 * 1000) +
- (end_time.tv_nsec - ts->tv_nsec);
- }
-
- return 0;
-}
-
-static inline void
-gc_enter(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_lev)
-{
- *lock_lev = rb_gc_vm_lock();
-
- switch (event) {
- case gc_enter_event_rest:
- if (!is_marking(objspace)) break;
- // fall through
- case gc_enter_event_start:
- case gc_enter_event_continue:
- // stop other ractors
- rb_gc_vm_barrier();
- break;
- default:
- break;
- }
-
- gc_enter_count(event);
- if (RB_UNLIKELY(during_gc != 0)) rb_bug("during_gc != 0");
- if (RGENGC_CHECK_MODE >= 3) gc_verify_internal_consistency(objspace);
-
- during_gc = TRUE;
- RUBY_DEBUG_LOG("%s (%s)",gc_enter_event_cstr(event), gc_current_status(objspace));
- gc_report(1, objspace, "gc_enter: %s [%s]\n", gc_enter_event_cstr(event), gc_current_status(objspace));
- gc_record(objspace, 0, gc_enter_event_cstr(event));
-
- rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_ENTER);
-}
-
-static inline void
-gc_exit(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_lev)
-{
- GC_ASSERT(during_gc != 0);
-
- rb_gc_event_hook(0, RUBY_INTERNAL_EVENT_GC_EXIT);
-
- gc_record(objspace, 1, gc_enter_event_cstr(event));
- RUBY_DEBUG_LOG("%s (%s)", gc_enter_event_cstr(event), gc_current_status(objspace));
- gc_report(1, objspace, "gc_exit: %s [%s]\n", gc_enter_event_cstr(event), gc_current_status(objspace));
- during_gc = FALSE;
-
- rb_gc_vm_unlock(*lock_lev);
-}
-
-#ifndef MEASURE_GC
-#define MEASURE_GC (objspace->flags.measure_gc)
-#endif
-
-static void
-gc_marking_enter(rb_objspace_t *objspace)
-{
- GC_ASSERT(during_gc != 0);
-
- if (MEASURE_GC) {
- gc_clock_start(&objspace->profile.marking_start_time);
- }
-}
-
-static void
-gc_marking_exit(rb_objspace_t *objspace)
-{
- GC_ASSERT(during_gc != 0);
-
- if (MEASURE_GC) {
- objspace->profile.marking_time_ns += gc_clock_end(&objspace->profile.marking_start_time);
- }
-}
-
-static void
-gc_sweeping_enter(rb_objspace_t *objspace)
-{
- GC_ASSERT(during_gc != 0);
-
- if (MEASURE_GC) {
- gc_clock_start(&objspace->profile.sweeping_start_time);
- }
-}
-
-static void
-gc_sweeping_exit(rb_objspace_t *objspace)
-{
- GC_ASSERT(during_gc != 0);
-
- if (MEASURE_GC) {
- objspace->profile.sweeping_time_ns += gc_clock_end(&objspace->profile.sweeping_start_time);
- }
-}
-
-static void *
-gc_with_gvl(void *ptr)
-{
- struct objspace_and_reason *oar = (struct objspace_and_reason *)ptr;
- return (void *)(VALUE)garbage_collect(oar->objspace, oar->reason);
-}
-
-int ruby_thread_has_gvl_p(void);
-
-static int
-garbage_collect_with_gvl(rb_objspace_t *objspace, unsigned int reason)
-{
- if (dont_gc_val()) return TRUE;
- if (ruby_thread_has_gvl_p()) {
- return garbage_collect(objspace, reason);
- }
- else {
- if (ruby_native_thread_p()) {
- struct objspace_and_reason oar;
- oar.objspace = objspace;
- oar.reason = reason;
- return (int)(VALUE)rb_thread_call_with_gvl(gc_with_gvl, (void *)&oar);
- }
- else {
- /* no ruby thread */
- fprintf(stderr, "[FATAL] failed to allocate memory\n");
- exit(EXIT_FAILURE);
- }
- }
-}
-
-static int
-gc_set_candidate_object_i(void *vstart, void *vend, size_t stride, void *data)
-{
- rb_objspace_t *objspace = (rb_objspace_t *)data;
-
- VALUE v = (VALUE)vstart;
- for (; v != (VALUE)vend; v += stride) {
- asan_unpoisoning_object(v) {
- switch (BUILTIN_TYPE(v)) {
- case T_NONE:
- case T_ZOMBIE:
- break;
- case T_STRING:
- // precompute the string coderange. This both save time for when it will be
- // eventually needed, and avoid mutating heap pages after a potential fork.
- rb_enc_str_coderange(v);
- // fall through
- default:
- if (!RVALUE_OLD_P(objspace, v) && !RVALUE_WB_UNPROTECTED(objspace, v)) {
- RVALUE_AGE_SET_CANDIDATE(objspace, v);
- }
- }
- }
- }
-
- return 0;
-}
-
-void
-rb_gc_impl_start(void *objspace_ptr, bool full_mark, bool immediate_mark, bool immediate_sweep, bool compact)
-{
- rb_objspace_t *objspace = objspace_ptr;
- unsigned int reason = (GPR_FLAG_FULL_MARK |
- GPR_FLAG_IMMEDIATE_MARK |
- GPR_FLAG_IMMEDIATE_SWEEP |
- GPR_FLAG_METHOD);
-
- int full_marking_p = gc_config_full_mark_val;
- gc_config_full_mark_set(TRUE);
-
- /* For now, compact implies full mark / sweep, so ignore other flags */
- if (compact) {
- GC_ASSERT(GC_COMPACTION_SUPPORTED);
-
- reason |= GPR_FLAG_COMPACT;
- }
- else {
- if (!full_mark) reason &= ~GPR_FLAG_FULL_MARK;
- if (!immediate_mark) reason &= ~GPR_FLAG_IMMEDIATE_MARK;
- if (!immediate_sweep) reason &= ~GPR_FLAG_IMMEDIATE_SWEEP;
- }
-
- garbage_collect(objspace, reason);
- gc_finalize_deferred(objspace);
-
- gc_config_full_mark_set(full_marking_p);
-}
-
-void
-rb_gc_impl_prepare_heap(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- size_t orig_total_slots = objspace_available_slots(objspace);
- size_t orig_allocatable_slots = objspace->heap_pages.allocatable_slots;
-
- rb_gc_impl_each_objects(objspace, gc_set_candidate_object_i, objspace_ptr);
-
- double orig_max_free_slots = gc_params.heap_free_slots_max_ratio;
- /* Ensure that all empty pages are moved onto empty_pages. */
- gc_params.heap_free_slots_max_ratio = 0.0;
- rb_gc_impl_start(objspace, true, true, true, true);
- gc_params.heap_free_slots_max_ratio = orig_max_free_slots;
-
- objspace->heap_pages.allocatable_slots = 0;
- heap_pages_free_unused_pages(objspace_ptr);
- GC_ASSERT(objspace->empty_pages_count == 0);
- objspace->heap_pages.allocatable_slots = orig_allocatable_slots;
-
- size_t total_slots = objspace_available_slots(objspace);
- if (orig_total_slots > total_slots) {
- objspace->heap_pages.allocatable_slots += orig_total_slots - total_slots;
- }
-
-#if defined(HAVE_MALLOC_TRIM) && !defined(RUBY_ALTERNATIVE_MALLOC_HEADER)
- malloc_trim(0);
-#endif
-}
-
-static int
-gc_is_moveable_obj(rb_objspace_t *objspace, VALUE obj)
-{
- GC_ASSERT(!SPECIAL_CONST_P(obj));
-
- switch (BUILTIN_TYPE(obj)) {
- case T_NONE:
- case T_MOVED:
- case T_ZOMBIE:
- return FALSE;
- case T_SYMBOL:
- // TODO: restore original behavior
- // if (RSYMBOL(obj)->id & ~ID_SCOPE_MASK) {
- // return FALSE;
- // }
- return false;
- /* fall through */
- case T_STRING:
- case T_OBJECT:
- case T_FLOAT:
- case T_IMEMO:
- case T_ARRAY:
- case T_BIGNUM:
- case T_ICLASS:
- case T_MODULE:
- case T_REGEXP:
- case T_DATA:
- case T_MATCH:
- case T_STRUCT:
- case T_HASH:
- case T_FILE:
- case T_COMPLEX:
- case T_RATIONAL:
- case T_NODE:
- case T_CLASS:
- if (FL_TEST(obj, FL_FINALIZE)) {
- /* The finalizer table is a numtable. It looks up objects by address.
- * We can't mark the keys in the finalizer table because that would
- * prevent the objects from being collected. This check prevents
- * objects that are keys in the finalizer table from being moved
- * without directly pinning them. */
- GC_ASSERT(st_is_member(finalizer_table, obj));
-
- return FALSE;
- }
- GC_ASSERT(RVALUE_MARKED(objspace, obj));
- GC_ASSERT(!RVALUE_PINNED(objspace, obj));
-
- return TRUE;
-
- default:
- rb_bug("gc_is_moveable_obj: unreachable (%d)", (int)BUILTIN_TYPE(obj));
- break;
- }
-
- return FALSE;
-}
-
-void rb_mv_generic_ivar(VALUE src, VALUE dst);
-
-static VALUE
-gc_move(rb_objspace_t *objspace, VALUE src, VALUE dest, size_t src_slot_size, size_t slot_size)
-{
- int marked;
- int wb_unprotected;
- int uncollectible;
- int age;
-
- gc_report(4, objspace, "Moving object: %p -> %p\n", (void *)src, (void *)dest);
-
- GC_ASSERT(BUILTIN_TYPE(src) != T_NONE);
- GC_ASSERT(!MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(dest), dest));
-
- GC_ASSERT(!RVALUE_MARKING(objspace, src));
-
- /* Save off bits for current object. */
- marked = RVALUE_MARKED(objspace, src);
- wb_unprotected = RVALUE_WB_UNPROTECTED(objspace, src);
- uncollectible = RVALUE_UNCOLLECTIBLE(objspace, src);
- bool remembered = RVALUE_REMEMBERED(objspace, src);
- age = RVALUE_AGE_GET(src);
-
- /* Clear bits for eventual T_MOVED */
- CLEAR_IN_BITMAP(GET_HEAP_MARK_BITS(src), src);
- CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(src), src);
- CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS(src), src);
- CLEAR_IN_BITMAP(GET_HEAP_PAGE(src)->remembered_bits, src);
-
- if (FL_TEST(src, FL_EXIVAR)) {
- /* Resizing the st table could cause a malloc */
- DURING_GC_COULD_MALLOC_REGION_START();
- {
- rb_mv_generic_ivar(src, dest);
- }
- DURING_GC_COULD_MALLOC_REGION_END();
- }
-
- if (FL_TEST(src, FL_SEEN_OBJ_ID)) {
- /* If the source object's object_id has been seen, we need to update
- * the object to object id mapping. */
- st_data_t srcid = (st_data_t)src, id;
-
- gc_report(4, objspace, "Moving object with seen id: %p -> %p\n", (void *)src, (void *)dest);
- /* Resizing the st table could cause a malloc */
- DURING_GC_COULD_MALLOC_REGION_START();
- {
- if (!st_delete(objspace->obj_to_id_tbl, &srcid, &id)) {
- rb_bug("gc_move: object ID seen, but not in mapping table: %s", rb_obj_info((VALUE)src));
- }
-
- st_insert(objspace->obj_to_id_tbl, (st_data_t)dest, id);
- }
- DURING_GC_COULD_MALLOC_REGION_END();
- }
- else {
- GC_ASSERT(!st_lookup(objspace->obj_to_id_tbl, (st_data_t)src, NULL));
- }
-
- /* Move the object */
- memcpy((void *)dest, (void *)src, MIN(src_slot_size, slot_size));
-
- if (RVALUE_OVERHEAD > 0) {
- void *dest_overhead = (void *)(((uintptr_t)dest) + slot_size - RVALUE_OVERHEAD);
- void *src_overhead = (void *)(((uintptr_t)src) + src_slot_size - RVALUE_OVERHEAD);
-
- memcpy(dest_overhead, src_overhead, RVALUE_OVERHEAD);
- }
-
- memset((void *)src, 0, src_slot_size);
- RVALUE_AGE_RESET(src);
-
- /* Set bits for object in new location */
- if (remembered) {
- MARK_IN_BITMAP(GET_HEAP_PAGE(dest)->remembered_bits, dest);
- }
- else {
- CLEAR_IN_BITMAP(GET_HEAP_PAGE(dest)->remembered_bits, dest);
- }
-
- if (marked) {
- MARK_IN_BITMAP(GET_HEAP_MARK_BITS(dest), dest);
- }
- else {
- CLEAR_IN_BITMAP(GET_HEAP_MARK_BITS(dest), dest);
- }
-
- if (wb_unprotected) {
- MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(dest), dest);
- }
- else {
- CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(dest), dest);
- }
-
- if (uncollectible) {
- MARK_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS(dest), dest);
- }
- else {
- CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS(dest), dest);
- }
-
- RVALUE_AGE_SET(dest, age);
- /* Assign forwarding address */
- RMOVED(src)->flags = T_MOVED;
- RMOVED(src)->dummy = Qundef;
- RMOVED(src)->destination = dest;
- GC_ASSERT(BUILTIN_TYPE(dest) != T_NONE);
-
- GET_HEAP_PAGE(src)->heap->total_freed_objects++;
- GET_HEAP_PAGE(dest)->heap->total_allocated_objects++;
-
- return src;
-}
-
-#if GC_CAN_COMPILE_COMPACTION
-static int
-compare_pinned_slots(const void *left, const void *right, void *dummy)
-{
- struct heap_page *left_page;
- struct heap_page *right_page;
-
- left_page = *(struct heap_page * const *)left;
- right_page = *(struct heap_page * const *)right;
-
- return left_page->pinned_slots - right_page->pinned_slots;
-}
-
-static int
-compare_free_slots(const void *left, const void *right, void *dummy)
-{
- struct heap_page *left_page;
- struct heap_page *right_page;
-
- left_page = *(struct heap_page * const *)left;
- right_page = *(struct heap_page * const *)right;
-
- return left_page->free_slots - right_page->free_slots;
-}
-
-static void
-gc_sort_heap_by_compare_func(rb_objspace_t *objspace, gc_compact_compare_func compare_func)
-{
- for (int j = 0; j < HEAP_COUNT; j++) {
- rb_heap_t *heap = &heaps[j];
-
- size_t total_pages = heap->total_pages;
- size_t size = rb_size_mul_or_raise(total_pages, sizeof(struct heap_page *), rb_eRuntimeError);
- struct heap_page *page = 0, **page_list = malloc(size);
- size_t i = 0;
-
- heap->free_pages = NULL;
- ccan_list_for_each(&heap->pages, page, page_node) {
- page_list[i++] = page;
- GC_ASSERT(page);
- }
-
- GC_ASSERT((size_t)i == total_pages);
-
- /* Sort the heap so "filled pages" are first. `heap_add_page` adds to the
- * head of the list, so empty pages will end up at the start of the heap */
- ruby_qsort(page_list, total_pages, sizeof(struct heap_page *), compare_func, NULL);
-
- /* Reset the eden heap */
- ccan_list_head_init(&heap->pages);
-
- for (i = 0; i < total_pages; i++) {
- ccan_list_add(&heap->pages, &page_list[i]->page_node);
- if (page_list[i]->free_slots != 0) {
- heap_add_freepage(heap, page_list[i]);
- }
- }
-
- free(page_list);
- }
-}
-#endif
-
-bool
-rb_gc_impl_object_moved_p(void *objspace_ptr, VALUE obj)
-{
- return gc_object_moved_p(objspace_ptr, obj);
-}
-
-static int
-gc_ref_update(void *vstart, void *vend, size_t stride, rb_objspace_t *objspace, struct heap_page *page)
-{
- VALUE v = (VALUE)vstart;
- asan_unlock_freelist(page);
- asan_lock_freelist(page);
- page->flags.has_uncollectible_wb_unprotected_objects = FALSE;
- page->flags.has_remembered_objects = FALSE;
-
- /* For each object on the page */
- for (; v != (VALUE)vend; v += stride) {
- asan_unpoisoning_object(v) {
- switch (BUILTIN_TYPE(v)) {
- case T_NONE:
- case T_MOVED:
- case T_ZOMBIE:
- break;
- default:
- if (RVALUE_WB_UNPROTECTED(objspace, v)) {
- page->flags.has_uncollectible_wb_unprotected_objects = TRUE;
- }
- if (RVALUE_REMEMBERED(objspace, v)) {
- page->flags.has_remembered_objects = TRUE;
- }
- if (page->flags.before_sweep) {
- if (RVALUE_MARKED(objspace, v)) {
- rb_gc_update_object_references(objspace, v);
- }
- }
- else {
- rb_gc_update_object_references(objspace, v);
- }
- }
- }
- }
-
- return 0;
-}
-
-static void
-gc_update_references(rb_objspace_t *objspace)
-{
- objspace->flags.during_reference_updating = true;
-
- struct heap_page *page = NULL;
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- bool should_set_mark_bits = TRUE;
- rb_heap_t *heap = &heaps[i];
-
- ccan_list_for_each(&heap->pages, page, page_node) {
- uintptr_t start = (uintptr_t)page->start;
- uintptr_t end = start + (page->total_slots * heap->slot_size);
-
- gc_ref_update((void *)start, (void *)end, heap->slot_size, objspace, page);
- if (page == heap->sweeping_page) {
- should_set_mark_bits = FALSE;
- }
- if (should_set_mark_bits) {
- gc_setup_mark_bits(page);
- }
- }
- }
- gc_ref_update_table_values_only(objspace->obj_to_id_tbl);
- gc_update_table_refs(objspace->id_to_obj_tbl);
- gc_update_table_refs(finalizer_table);
-
- rb_gc_update_vm_references((void *)objspace);
-
- objspace->flags.during_reference_updating = false;
-}
-
-#if GC_CAN_COMPILE_COMPACTION
-static void
-root_obj_check_moved_i(const char *category, VALUE obj, void *data)
-{
- rb_objspace_t *objspace = data;
-
- if (gc_object_moved_p(objspace, obj)) {
- rb_bug("ROOT %s points to MOVED: %p -> %s", category, (void *)obj, rb_obj_info(rb_gc_impl_location(objspace, obj)));
- }
-}
-
-static void
-reachable_object_check_moved_i(VALUE ref, void *data)
-{
- VALUE parent = (VALUE)data;
- if (gc_object_moved_p(rb_gc_get_objspace(), ref)) {
- rb_bug("Object %s points to MOVED: %p -> %s", rb_obj_info(parent), (void *)ref, rb_obj_info(rb_gc_impl_location(rb_gc_get_objspace(), ref)));
- }
-}
-
-static int
-heap_check_moved_i(void *vstart, void *vend, size_t stride, void *data)
-{
- rb_objspace_t *objspace = data;
-
- VALUE v = (VALUE)vstart;
- for (; v != (VALUE)vend; v += stride) {
- if (gc_object_moved_p(objspace, v)) {
- /* Moved object still on the heap, something may have a reference. */
- }
- else {
- asan_unpoisoning_object(v) {
- switch (BUILTIN_TYPE(v)) {
- case T_NONE:
- case T_ZOMBIE:
- break;
- default:
- if (!rb_gc_impl_garbage_object_p(objspace, v)) {
- rb_objspace_reachable_objects_from(v, reachable_object_check_moved_i, (void *)v);
- }
- }
- }
- }
- }
-
- return 0;
-}
-#endif
-
-bool
-rb_gc_impl_during_gc_p(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- return during_gc;
-}
-
-#if RGENGC_PROFILE >= 2
-
-static const char*
-type_name(int type, VALUE obj)
-{
- switch ((enum ruby_value_type)type) {
- case RUBY_T_NONE: return "T_NONE";
- case RUBY_T_OBJECT: return "T_OBJECT";
- case RUBY_T_CLASS: return "T_CLASS";
- case RUBY_T_MODULE: return "T_MODULE";
- case RUBY_T_FLOAT: return "T_FLOAT";
- case RUBY_T_STRING: return "T_STRING";
- case RUBY_T_REGEXP: return "T_REGEXP";
- case RUBY_T_ARRAY: return "T_ARRAY";
- case RUBY_T_HASH: return "T_HASH";
- case RUBY_T_STRUCT: return "T_STRUCT";
- case RUBY_T_BIGNUM: return "T_BIGNUM";
- case RUBY_T_FILE: return "T_FILE";
- case RUBY_T_DATA: return "T_DATA";
- case RUBY_T_MATCH: return "T_MATCH";
- case RUBY_T_COMPLEX: return "T_COMPLEX";
- case RUBY_T_RATIONAL: return "T_RATIONAL";
- case RUBY_T_NIL: return "T_NIL";
- case RUBY_T_TRUE: return "T_TRUE";
- case RUBY_T_FALSE: return "T_FALSE";
- case RUBY_T_SYMBOL: return "T_SYMBOL";
- case RUBY_T_FIXNUM: return "T_FIXNUM";
- case RUBY_T_UNDEF: return "T_UNDEF";
- case RUBY_T_IMEMO: return "T_IMEMO";
- case RUBY_T_NODE: return "T_NODE";
- case RUBY_T_ICLASS: return "T_ICLASS";
- case RUBY_T_ZOMBIE: return "T_ZOMBIE";
- case RUBY_T_MOVED: return "T_MOVED";
- default: return "unknown";
- }
-}
-
-static void
-gc_count_add_each_types(VALUE hash, const char *name, const size_t *types)
-{
- VALUE result = rb_hash_new_with_size(T_MASK);
- int i;
- for (i=0; i<T_MASK; i++) {
- const char *type = type_name(i, 0);
- rb_hash_aset(result, ID2SYM(rb_intern(type)), SIZET2NUM(types[i]));
- }
- rb_hash_aset(hash, ID2SYM(rb_intern(name)), result);
-}
-#endif
-
-size_t
-rb_gc_impl_gc_count(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- return objspace->profile.count;
-}
-
-static VALUE
-gc_info_decode(rb_objspace_t *objspace, const VALUE hash_or_key, const unsigned int orig_flags)
-{
- static VALUE sym_major_by = Qnil, sym_gc_by, sym_immediate_sweep, sym_have_finalizer, sym_state, sym_need_major_by;
- static VALUE sym_nofree, sym_oldgen, sym_shady, sym_force, sym_stress;
-#if RGENGC_ESTIMATE_OLDMALLOC
- static VALUE sym_oldmalloc;
-#endif
- static VALUE sym_newobj, sym_malloc, sym_method, sym_capi;
- static VALUE sym_none, sym_marking, sym_sweeping;
- static VALUE sym_weak_references_count, sym_retained_weak_references_count;
- VALUE hash = Qnil, key = Qnil;
- VALUE major_by, need_major_by;
- unsigned int flags = orig_flags ? orig_flags : objspace->profile.latest_gc_info;
-
- if (SYMBOL_P(hash_or_key)) {
- key = hash_or_key;
- }
- else if (RB_TYPE_P(hash_or_key, T_HASH)) {
- hash = hash_or_key;
- }
- else {
- rb_raise(rb_eTypeError, "non-hash or symbol given");
- }
-
- if (NIL_P(sym_major_by)) {
-#define S(s) sym_##s = ID2SYM(rb_intern_const(#s))
- S(major_by);
- S(gc_by);
- S(immediate_sweep);
- S(have_finalizer);
- S(state);
- S(need_major_by);
-
- S(stress);
- S(nofree);
- S(oldgen);
- S(shady);
- S(force);
-#if RGENGC_ESTIMATE_OLDMALLOC
- S(oldmalloc);
-#endif
- S(newobj);
- S(malloc);
- S(method);
- S(capi);
-
- S(none);
- S(marking);
- S(sweeping);
-
- S(weak_references_count);
- S(retained_weak_references_count);
-#undef S
- }
-
-#define SET(name, attr) \
- if (key == sym_##name) \
- return (attr); \
- else if (hash != Qnil) \
- rb_hash_aset(hash, sym_##name, (attr));
-
- major_by =
- (flags & GPR_FLAG_MAJOR_BY_NOFREE) ? sym_nofree :
- (flags & GPR_FLAG_MAJOR_BY_OLDGEN) ? sym_oldgen :
- (flags & GPR_FLAG_MAJOR_BY_SHADY) ? sym_shady :
- (flags & GPR_FLAG_MAJOR_BY_FORCE) ? sym_force :
-#if RGENGC_ESTIMATE_OLDMALLOC
- (flags & GPR_FLAG_MAJOR_BY_OLDMALLOC) ? sym_oldmalloc :
-#endif
- Qnil;
- SET(major_by, major_by);
-
- if (orig_flags == 0) { /* set need_major_by only if flags not set explicitly */
- unsigned int need_major_flags = gc_needs_major_flags;
- need_major_by =
- (need_major_flags & GPR_FLAG_MAJOR_BY_NOFREE) ? sym_nofree :
- (need_major_flags & GPR_FLAG_MAJOR_BY_OLDGEN) ? sym_oldgen :
- (need_major_flags & GPR_FLAG_MAJOR_BY_SHADY) ? sym_shady :
- (need_major_flags & GPR_FLAG_MAJOR_BY_FORCE) ? sym_force :
-#if RGENGC_ESTIMATE_OLDMALLOC
- (need_major_flags & GPR_FLAG_MAJOR_BY_OLDMALLOC) ? sym_oldmalloc :
-#endif
- Qnil;
- SET(need_major_by, need_major_by);
- }
-
- SET(gc_by,
- (flags & GPR_FLAG_NEWOBJ) ? sym_newobj :
- (flags & GPR_FLAG_MALLOC) ? sym_malloc :
- (flags & GPR_FLAG_METHOD) ? sym_method :
- (flags & GPR_FLAG_CAPI) ? sym_capi :
- (flags & GPR_FLAG_STRESS) ? sym_stress :
- Qnil
- );
-
- SET(have_finalizer, (flags & GPR_FLAG_HAVE_FINALIZE) ? Qtrue : Qfalse);
- SET(immediate_sweep, (flags & GPR_FLAG_IMMEDIATE_SWEEP) ? Qtrue : Qfalse);
-
- if (orig_flags == 0) {
- SET(state, gc_mode(objspace) == gc_mode_none ? sym_none :
- gc_mode(objspace) == gc_mode_marking ? sym_marking : sym_sweeping);
- }
-
- SET(weak_references_count, LONG2FIX(objspace->profile.weak_references_count));
- SET(retained_weak_references_count, LONG2FIX(objspace->profile.retained_weak_references_count));
-#undef SET
-
- if (!NIL_P(key)) {/* matched key should return above */
- rb_raise(rb_eArgError, "unknown key: %"PRIsVALUE, rb_sym2str(key));
- }
-
- return hash;
-}
-
-VALUE
-rb_gc_impl_latest_gc_info(void *objspace_ptr, VALUE key)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- return gc_info_decode(objspace, key, 0);
-}
-
-
-enum gc_stat_sym {
- gc_stat_sym_count,
- gc_stat_sym_time,
- gc_stat_sym_marking_time,
- gc_stat_sym_sweeping_time,
- gc_stat_sym_heap_allocated_pages,
- gc_stat_sym_heap_empty_pages,
- gc_stat_sym_heap_allocatable_slots,
- gc_stat_sym_heap_available_slots,
- gc_stat_sym_heap_live_slots,
- gc_stat_sym_heap_free_slots,
- gc_stat_sym_heap_final_slots,
- gc_stat_sym_heap_marked_slots,
- gc_stat_sym_heap_eden_pages,
- gc_stat_sym_total_allocated_pages,
- gc_stat_sym_total_freed_pages,
- gc_stat_sym_total_allocated_objects,
- gc_stat_sym_total_freed_objects,
- gc_stat_sym_malloc_increase_bytes,
- gc_stat_sym_malloc_increase_bytes_limit,
- gc_stat_sym_minor_gc_count,
- gc_stat_sym_major_gc_count,
- gc_stat_sym_compact_count,
- gc_stat_sym_read_barrier_faults,
- gc_stat_sym_total_moved_objects,
- gc_stat_sym_remembered_wb_unprotected_objects,
- gc_stat_sym_remembered_wb_unprotected_objects_limit,
- gc_stat_sym_old_objects,
- gc_stat_sym_old_objects_limit,
-#if RGENGC_ESTIMATE_OLDMALLOC
- gc_stat_sym_oldmalloc_increase_bytes,
- gc_stat_sym_oldmalloc_increase_bytes_limit,
-#endif
- gc_stat_sym_weak_references_count,
-#if RGENGC_PROFILE
- gc_stat_sym_total_generated_normal_object_count,
- gc_stat_sym_total_generated_shady_object_count,
- gc_stat_sym_total_shade_operation_count,
- gc_stat_sym_total_promoted_count,
- gc_stat_sym_total_remembered_normal_object_count,
- gc_stat_sym_total_remembered_shady_object_count,
-#endif
- gc_stat_sym_last
-};
-
-static VALUE gc_stat_symbols[gc_stat_sym_last];
-
-static void
-setup_gc_stat_symbols(void)
-{
- if (gc_stat_symbols[0] == 0) {
-#define S(s) gc_stat_symbols[gc_stat_sym_##s] = ID2SYM(rb_intern_const(#s))
- S(count);
- S(time);
- S(marking_time),
- S(sweeping_time),
- S(heap_allocated_pages);
- S(heap_empty_pages);
- S(heap_allocatable_slots);
- S(heap_available_slots);
- S(heap_live_slots);
- S(heap_free_slots);
- S(heap_final_slots);
- S(heap_marked_slots);
- S(heap_eden_pages);
- S(total_allocated_pages);
- S(total_freed_pages);
- S(total_allocated_objects);
- S(total_freed_objects);
- S(malloc_increase_bytes);
- S(malloc_increase_bytes_limit);
- S(minor_gc_count);
- S(major_gc_count);
- S(compact_count);
- S(read_barrier_faults);
- S(total_moved_objects);
- S(remembered_wb_unprotected_objects);
- S(remembered_wb_unprotected_objects_limit);
- S(old_objects);
- S(old_objects_limit);
-#if RGENGC_ESTIMATE_OLDMALLOC
- S(oldmalloc_increase_bytes);
- S(oldmalloc_increase_bytes_limit);
-#endif
- S(weak_references_count);
-#if RGENGC_PROFILE
- S(total_generated_normal_object_count);
- S(total_generated_shady_object_count);
- S(total_shade_operation_count);
- S(total_promoted_count);
- S(total_remembered_normal_object_count);
- S(total_remembered_shady_object_count);
-#endif /* RGENGC_PROFILE */
-#undef S
- }
-}
-
-static uint64_t
-ns_to_ms(uint64_t ns)
-{
- return ns / (1000 * 1000);
-}
-
-size_t
-rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym)
-{
- rb_objspace_t *objspace = objspace_ptr;
- VALUE hash = Qnil, key = Qnil;
-
- setup_gc_stat_symbols();
-
- if (RB_TYPE_P(hash_or_sym, T_HASH)) {
- hash = hash_or_sym;
- }
- else if (SYMBOL_P(hash_or_sym)) {
- key = hash_or_sym;
- }
- else {
- rb_raise(rb_eTypeError, "non-hash or symbol given");
- }
-
-#define SET(name, attr) \
- if (key == gc_stat_symbols[gc_stat_sym_##name]) \
- return attr; \
- else if (hash != Qnil) \
- rb_hash_aset(hash, gc_stat_symbols[gc_stat_sym_##name], SIZET2NUM(attr));
-
- SET(count, objspace->profile.count);
- SET(time, (size_t)ns_to_ms(objspace->profile.marking_time_ns + objspace->profile.sweeping_time_ns)); // TODO: UINT64T2NUM
- SET(marking_time, (size_t)ns_to_ms(objspace->profile.marking_time_ns));
- SET(sweeping_time, (size_t)ns_to_ms(objspace->profile.sweeping_time_ns));
-
- /* implementation dependent counters */
- SET(heap_allocated_pages, rb_darray_size(objspace->heap_pages.sorted));
- SET(heap_empty_pages, objspace->empty_pages_count)
- SET(heap_allocatable_slots, objspace->heap_pages.allocatable_slots);
- SET(heap_available_slots, objspace_available_slots(objspace));
- SET(heap_live_slots, objspace_live_slots(objspace));
- SET(heap_free_slots, objspace_free_slots(objspace));
- SET(heap_final_slots, total_final_slots_count(objspace));
- SET(heap_marked_slots, objspace->marked_slots);
- SET(heap_eden_pages, heap_eden_total_pages(objspace));
- SET(total_allocated_pages, objspace->heap_pages.allocated_pages);
- SET(total_freed_pages, objspace->heap_pages.freed_pages);
- SET(total_allocated_objects, total_allocated_objects(objspace));
- SET(total_freed_objects, total_freed_objects(objspace));
- SET(malloc_increase_bytes, malloc_increase);
- SET(malloc_increase_bytes_limit, malloc_limit);
- SET(minor_gc_count, objspace->profile.minor_gc_count);
- SET(major_gc_count, objspace->profile.major_gc_count);
- SET(compact_count, objspace->profile.compact_count);
- SET(read_barrier_faults, objspace->profile.read_barrier_faults);
- SET(total_moved_objects, objspace->rcompactor.total_moved);
- SET(remembered_wb_unprotected_objects, objspace->rgengc.uncollectible_wb_unprotected_objects);
- SET(remembered_wb_unprotected_objects_limit, objspace->rgengc.uncollectible_wb_unprotected_objects_limit);
- SET(old_objects, objspace->rgengc.old_objects);
- SET(old_objects_limit, objspace->rgengc.old_objects_limit);
-#if RGENGC_ESTIMATE_OLDMALLOC
- SET(oldmalloc_increase_bytes, objspace->rgengc.oldmalloc_increase);
- SET(oldmalloc_increase_bytes_limit, objspace->rgengc.oldmalloc_increase_limit);
-#endif
-
-#if RGENGC_PROFILE
- SET(total_generated_normal_object_count, objspace->profile.total_generated_normal_object_count);
- SET(total_generated_shady_object_count, objspace->profile.total_generated_shady_object_count);
- SET(total_shade_operation_count, objspace->profile.total_shade_operation_count);
- SET(total_promoted_count, objspace->profile.total_promoted_count);
- SET(total_remembered_normal_object_count, objspace->profile.total_remembered_normal_object_count);
- SET(total_remembered_shady_object_count, objspace->profile.total_remembered_shady_object_count);
-#endif /* RGENGC_PROFILE */
-#undef SET
-
- if (!NIL_P(key)) { /* matched key should return above */
- rb_raise(rb_eArgError, "unknown key: %"PRIsVALUE, rb_sym2str(key));
- }
-
-#if defined(RGENGC_PROFILE) && RGENGC_PROFILE >= 2
- if (hash != Qnil) {
- gc_count_add_each_types(hash, "generated_normal_object_count_types", objspace->profile.generated_normal_object_count_types);
- gc_count_add_each_types(hash, "generated_shady_object_count_types", objspace->profile.generated_shady_object_count_types);
- gc_count_add_each_types(hash, "shade_operation_count_types", objspace->profile.shade_operation_count_types);
- gc_count_add_each_types(hash, "promoted_types", objspace->profile.promoted_types);
- gc_count_add_each_types(hash, "remembered_normal_object_count_types", objspace->profile.remembered_normal_object_count_types);
- gc_count_add_each_types(hash, "remembered_shady_object_count_types", objspace->profile.remembered_shady_object_count_types);
- }
-#endif
-
- return 0;
-}
-
-enum gc_stat_heap_sym {
- gc_stat_heap_sym_slot_size,
- gc_stat_heap_sym_heap_eden_pages,
- gc_stat_heap_sym_heap_eden_slots,
- gc_stat_heap_sym_total_allocated_pages,
- gc_stat_heap_sym_force_major_gc_count,
- gc_stat_heap_sym_force_incremental_marking_finish_count,
- gc_stat_heap_sym_total_allocated_objects,
- gc_stat_heap_sym_total_freed_objects,
- gc_stat_heap_sym_last
-};
-
-static VALUE gc_stat_heap_symbols[gc_stat_heap_sym_last];
-
-static void
-setup_gc_stat_heap_symbols(void)
-{
- if (gc_stat_heap_symbols[0] == 0) {
-#define S(s) gc_stat_heap_symbols[gc_stat_heap_sym_##s] = ID2SYM(rb_intern_const(#s))
- S(slot_size);
- S(heap_eden_pages);
- S(heap_eden_slots);
- S(total_allocated_pages);
- S(force_major_gc_count);
- S(force_incremental_marking_finish_count);
- S(total_allocated_objects);
- S(total_freed_objects);
-#undef S
- }
-}
-
-static size_t
-stat_one_heap(rb_heap_t *heap, VALUE hash, VALUE key)
-{
-#define SET(name, attr) \
- if (key == gc_stat_heap_symbols[gc_stat_heap_sym_##name]) \
- return attr; \
- else if (hash != Qnil) \
- rb_hash_aset(hash, gc_stat_heap_symbols[gc_stat_heap_sym_##name], SIZET2NUM(attr));
-
- SET(slot_size, heap->slot_size);
- SET(heap_eden_pages, heap->total_pages);
- SET(heap_eden_slots, heap->total_slots);
- SET(total_allocated_pages, heap->total_allocated_pages);
- SET(force_major_gc_count, heap->force_major_gc_count);
- SET(force_incremental_marking_finish_count, heap->force_incremental_marking_finish_count);
- SET(total_allocated_objects, heap->total_allocated_objects);
- SET(total_freed_objects, heap->total_freed_objects);
-#undef SET
-
- if (!NIL_P(key)) { /* matched key should return above */
- rb_raise(rb_eArgError, "unknown key: %"PRIsVALUE, rb_sym2str(key));
- }
-
- return 0;
-}
-
-size_t
-rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- setup_gc_stat_heap_symbols();
-
- if (NIL_P(heap_name)) {
- if (!RB_TYPE_P(hash_or_sym, T_HASH)) {
- rb_raise(rb_eTypeError, "non-hash given");
- }
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- VALUE hash = rb_hash_aref(hash_or_sym, INT2FIX(i));
- if (NIL_P(hash)) {
- hash = rb_hash_new();
- rb_hash_aset(hash_or_sym, INT2FIX(i), hash);
- }
-
- stat_one_heap(&heaps[i], hash, Qnil);
- }
- }
- else if (FIXNUM_P(heap_name)) {
- int heap_idx = FIX2INT(heap_name);
-
- if (heap_idx < 0 || heap_idx >= HEAP_COUNT) {
- rb_raise(rb_eArgError, "size pool index out of range");
- }
-
- if (SYMBOL_P(hash_or_sym)) {
- return stat_one_heap(&heaps[heap_idx], Qnil, hash_or_sym);
- }
- else if (RB_TYPE_P(hash_or_sym, T_HASH)) {
- return stat_one_heap(&heaps[heap_idx], hash_or_sym, Qnil);
- }
- else {
- rb_raise(rb_eTypeError, "non-hash or symbol given");
- }
- }
- else {
- rb_raise(rb_eTypeError, "heap_name must be nil or an Integer");
- }
-
- return 0;
-}
-
-/* I could include internal.h for this, but doing so undefines some Array macros
- * necessary for initialising objects, and I don't want to include all the array
- * headers to get them back
- * TODO: Investigate why RARRAY_AREF gets undefined in internal.h
- */
-#ifndef RBOOL
-#define RBOOL(v) (v ? Qtrue : Qfalse)
-#endif
-
-VALUE
-rb_gc_impl_config_get(void *objspace_ptr)
-{
-#define sym(name) ID2SYM(rb_intern_const(name))
- rb_objspace_t *objspace = objspace_ptr;
- VALUE hash = rb_hash_new();
-
- rb_hash_aset(hash, sym("rgengc_allow_full_mark"), RBOOL(gc_config_full_mark_val));
-
- return hash;
-}
-
-static int
-gc_config_set_key(st_data_t key, st_data_t value, st_data_t data)
-{
- rb_objspace_t *objspace = (rb_objspace_t *)data;
- if (rb_sym2id(key) == rb_intern("rgengc_allow_full_mark")) {
- gc_rest(objspace);
- gc_config_full_mark_set(RTEST(value));
- }
- return ST_CONTINUE;
-}
-
-VALUE
-rb_gc_impl_config_set(void *objspace_ptr, VALUE hash)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- if(!RB_TYPE_P(hash, T_HASH)) {
- rb_raise(rb_eArgError, "expected keyword arguments");
- }
-
- rb_hash_stlike_foreach(hash, gc_config_set_key, (st_data_t)objspace);
- return rb_gc_impl_config_get(objspace_ptr);
-}
-
-VALUE
-rb_gc_impl_stress_get(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
- return ruby_gc_stress_mode;
-}
-
-void
-rb_gc_impl_stress_set(void *objspace_ptr, VALUE flag)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- objspace->flags.gc_stressful = RTEST(flag);
- objspace->gc_stress_mode = flag;
-}
-
-static int
-get_envparam_size(const char *name, size_t *default_value, size_t lower_bound)
-{
- const char *ptr = getenv(name);
- ssize_t val;
-
- if (ptr != NULL && *ptr) {
- size_t unit = 0;
- char *end;
-#if SIZEOF_SIZE_T == SIZEOF_LONG_LONG
- val = strtoll(ptr, &end, 0);
-#else
- val = strtol(ptr, &end, 0);
-#endif
- switch (*end) {
- case 'k': case 'K':
- unit = 1024;
- ++end;
- break;
- case 'm': case 'M':
- unit = 1024*1024;
- ++end;
- break;
- case 'g': case 'G':
- unit = 1024*1024*1024;
- ++end;
- break;
- }
- while (*end && isspace((unsigned char)*end)) end++;
- if (*end) {
- if (RTEST(ruby_verbose)) fprintf(stderr, "invalid string for %s: %s\n", name, ptr);
- return 0;
- }
- if (unit > 0) {
- if (val < -(ssize_t)(SIZE_MAX / 2 / unit) || (ssize_t)(SIZE_MAX / 2 / unit) < val) {
- if (RTEST(ruby_verbose)) fprintf(stderr, "%s=%s is ignored because it overflows\n", name, ptr);
- return 0;
- }
- val *= unit;
- }
- if (val > 0 && (size_t)val > lower_bound) {
- if (RTEST(ruby_verbose)) {
- fprintf(stderr, "%s=%"PRIdSIZE" (default value: %"PRIuSIZE")\n", name, val, *default_value);
- }
- *default_value = (size_t)val;
- return 1;
- }
- else {
- if (RTEST(ruby_verbose)) {
- fprintf(stderr, "%s=%"PRIdSIZE" (default value: %"PRIuSIZE") is ignored because it must be greater than %"PRIuSIZE".\n",
- name, val, *default_value, lower_bound);
- }
- return 0;
- }
- }
- return 0;
-}
-
-static int
-get_envparam_double(const char *name, double *default_value, double lower_bound, double upper_bound, int accept_zero)
-{
- const char *ptr = getenv(name);
- double val;
-
- if (ptr != NULL && *ptr) {
- char *end;
- val = strtod(ptr, &end);
- if (!*ptr || *end) {
- if (RTEST(ruby_verbose)) fprintf(stderr, "invalid string for %s: %s\n", name, ptr);
- return 0;
- }
-
- if (accept_zero && val == 0.0) {
- goto accept;
- }
- else if (val <= lower_bound) {
- if (RTEST(ruby_verbose)) {
- fprintf(stderr, "%s=%f (default value: %f) is ignored because it must be greater than %f.\n",
- name, val, *default_value, lower_bound);
- }
- }
- else if (upper_bound != 0.0 && /* ignore upper_bound if it is 0.0 */
- val > upper_bound) {
- if (RTEST(ruby_verbose)) {
- fprintf(stderr, "%s=%f (default value: %f) is ignored because it must be lower than %f.\n",
- name, val, *default_value, upper_bound);
- }
- }
- else {
- goto accept;
- }
- }
- return 0;
-
- accept:
- if (RTEST(ruby_verbose)) fprintf(stderr, "%s=%f (default value: %f)\n", name, val, *default_value);
- *default_value = val;
- return 1;
-}
-
-/*
- * GC tuning environment variables
- *
- * * RUBY_GC_HEAP_FREE_SLOTS
- * - Prepare at least this amount of slots after GC.
- * - Allocate slots if there are not enough slots.
- * * RUBY_GC_HEAP_GROWTH_FACTOR (new from 2.1)
- * - Allocate slots by this factor.
- * - (next slots number) = (current slots number) * (this factor)
- * * RUBY_GC_HEAP_GROWTH_MAX_SLOTS (new from 2.1)
- * - Allocation rate is limited to this number of slots.
- * * RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO (new from 2.4)
- * - Allocate additional pages when the number of free slots is
- * lower than the value (total_slots * (this ratio)).
- * * RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO (new from 2.4)
- * - Allocate slots to satisfy this formula:
- * free_slots = total_slots * goal_ratio
- * - In other words, prepare (total_slots * goal_ratio) free slots.
- * - if this value is 0.0, then use RUBY_GC_HEAP_GROWTH_FACTOR directly.
- * * RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO (new from 2.4)
- * - Allow to free pages when the number of free slots is
- * greater than the value (total_slots * (this ratio)).
- * * RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR (new from 2.1.1)
- * - Do full GC when the number of old objects is more than R * N
- * where R is this factor and
- * N is the number of old objects just after last full GC.
- *
- * * obsolete
- * * RUBY_FREE_MIN -> RUBY_GC_HEAP_FREE_SLOTS (from 2.1)
- * * RUBY_HEAP_MIN_SLOTS -> RUBY_GC_HEAP_INIT_SLOTS (from 2.1)
- *
- * * RUBY_GC_MALLOC_LIMIT
- * * RUBY_GC_MALLOC_LIMIT_MAX (new from 2.1)
- * * RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR (new from 2.1)
- *
- * * RUBY_GC_OLDMALLOC_LIMIT (new from 2.1)
- * * RUBY_GC_OLDMALLOC_LIMIT_MAX (new from 2.1)
- * * RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR (new from 2.1)
- */
-
-void
-rb_gc_impl_set_params(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
- /* RUBY_GC_HEAP_FREE_SLOTS */
- if (get_envparam_size("RUBY_GC_HEAP_FREE_SLOTS", &gc_params.heap_free_slots, 0)) {
- /* ok */
- }
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- char env_key[sizeof("RUBY_GC_HEAP_" "_INIT_SLOTS") + DECIMAL_SIZE_OF_BITS(sizeof(int) * CHAR_BIT)];
- snprintf(env_key, sizeof(env_key), "RUBY_GC_HEAP_%d_INIT_SLOTS", i);
-
- get_envparam_size(env_key, &gc_params.heap_init_slots[i], 0);
- }
-
- get_envparam_double("RUBY_GC_HEAP_GROWTH_FACTOR", &gc_params.growth_factor, 1.0, 0.0, FALSE);
- get_envparam_size ("RUBY_GC_HEAP_GROWTH_MAX_SLOTS", &gc_params.growth_max_slots, 0);
- get_envparam_double("RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO", &gc_params.heap_free_slots_min_ratio,
- 0.0, 1.0, FALSE);
- get_envparam_double("RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO", &gc_params.heap_free_slots_max_ratio,
- gc_params.heap_free_slots_min_ratio, 1.0, FALSE);
- get_envparam_double("RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO", &gc_params.heap_free_slots_goal_ratio,
- gc_params.heap_free_slots_min_ratio, gc_params.heap_free_slots_max_ratio, TRUE);
- get_envparam_double("RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR", &gc_params.oldobject_limit_factor, 0.0, 0.0, TRUE);
- get_envparam_double("RUBY_GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO", &gc_params.uncollectible_wb_unprotected_objects_limit_ratio, 0.0, 0.0, TRUE);
-
- if (get_envparam_size("RUBY_GC_MALLOC_LIMIT", &gc_params.malloc_limit_min, 0)) {
- malloc_limit = gc_params.malloc_limit_min;
- }
- get_envparam_size ("RUBY_GC_MALLOC_LIMIT_MAX", &gc_params.malloc_limit_max, 0);
- if (!gc_params.malloc_limit_max) { /* ignore max-check if 0 */
- gc_params.malloc_limit_max = SIZE_MAX;
- }
- get_envparam_double("RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR", &gc_params.malloc_limit_growth_factor, 1.0, 0.0, FALSE);
-
-#if RGENGC_ESTIMATE_OLDMALLOC
- if (get_envparam_size("RUBY_GC_OLDMALLOC_LIMIT", &gc_params.oldmalloc_limit_min, 0)) {
- objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_min;
- }
- get_envparam_size ("RUBY_GC_OLDMALLOC_LIMIT_MAX", &gc_params.oldmalloc_limit_max, 0);
- get_envparam_double("RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR", &gc_params.oldmalloc_limit_growth_factor, 1.0, 0.0, FALSE);
-#endif
-}
-
-static inline size_t
-objspace_malloc_size(rb_objspace_t *objspace, void *ptr, size_t hint)
-{
-#ifdef HAVE_MALLOC_USABLE_SIZE
- return malloc_usable_size(ptr);
-#else
- return hint;
-#endif
-}
-
-enum memop_type {
- MEMOP_TYPE_MALLOC = 0,
- MEMOP_TYPE_FREE,
- MEMOP_TYPE_REALLOC
-};
-
-static inline void
-atomic_sub_nounderflow(size_t *var, size_t sub)
-{
- if (sub == 0) return;
-
- while (1) {
- size_t val = *var;
- if (val < sub) sub = val;
- if (RUBY_ATOMIC_SIZE_CAS(*var, val, val-sub) == val) break;
- }
-}
-
-#define gc_stress_full_mark_after_malloc_p() \
- (FIXNUM_P(ruby_gc_stress_mode) && (FIX2LONG(ruby_gc_stress_mode) & (1<<gc_stress_full_mark_after_malloc)))
-
-static void
-objspace_malloc_gc_stress(rb_objspace_t *objspace)
-{
- if (ruby_gc_stressful && ruby_native_thread_p()) {
- unsigned int reason = (GPR_FLAG_IMMEDIATE_MARK | GPR_FLAG_IMMEDIATE_SWEEP |
- GPR_FLAG_STRESS | GPR_FLAG_MALLOC);
-
- if (gc_stress_full_mark_after_malloc_p()) {
- reason |= GPR_FLAG_FULL_MARK;
- }
- garbage_collect_with_gvl(objspace, reason);
- }
-}
-
-static inline bool
-objspace_malloc_increase_report(rb_objspace_t *objspace, void *mem, size_t new_size, size_t old_size, enum memop_type type)
-{
- if (0) fprintf(stderr, "increase - ptr: %p, type: %s, new_size: %"PRIdSIZE", old_size: %"PRIdSIZE"\n",
- mem,
- type == MEMOP_TYPE_MALLOC ? "malloc" :
- type == MEMOP_TYPE_FREE ? "free " :
- type == MEMOP_TYPE_REALLOC ? "realloc": "error",
- new_size, old_size);
- return false;
-}
-
-static bool
-objspace_malloc_increase_body(rb_objspace_t *objspace, void *mem, size_t new_size, size_t old_size, enum memop_type type)
-{
- if (new_size > old_size) {
- RUBY_ATOMIC_SIZE_ADD(malloc_increase, new_size - old_size);
-#if RGENGC_ESTIMATE_OLDMALLOC
- RUBY_ATOMIC_SIZE_ADD(objspace->rgengc.oldmalloc_increase, new_size - old_size);
-#endif
- }
- else {
- atomic_sub_nounderflow(&malloc_increase, old_size - new_size);
-#if RGENGC_ESTIMATE_OLDMALLOC
- atomic_sub_nounderflow(&objspace->rgengc.oldmalloc_increase, old_size - new_size);
-#endif
- }
-
- if (type == MEMOP_TYPE_MALLOC) {
- retry:
- if (malloc_increase > malloc_limit && ruby_native_thread_p() && !dont_gc_val()) {
- if (ruby_thread_has_gvl_p() && is_lazy_sweeping(objspace)) {
- gc_rest(objspace); /* gc_rest can reduce malloc_increase */
- goto retry;
- }
- garbage_collect_with_gvl(objspace, GPR_FLAG_MALLOC);
- }
- }
-
-#if MALLOC_ALLOCATED_SIZE
- if (new_size >= old_size) {
- RUBY_ATOMIC_SIZE_ADD(objspace->malloc_params.allocated_size, new_size - old_size);
- }
- else {
- size_t dec_size = old_size - new_size;
- size_t allocated_size = objspace->malloc_params.allocated_size;
-
-#if MALLOC_ALLOCATED_SIZE_CHECK
- if (allocated_size < dec_size) {
- rb_bug("objspace_malloc_increase: underflow malloc_params.allocated_size.");
- }
-#endif
- atomic_sub_nounderflow(&objspace->malloc_params.allocated_size, dec_size);
- }
-
- switch (type) {
- case MEMOP_TYPE_MALLOC:
- RUBY_ATOMIC_SIZE_INC(objspace->malloc_params.allocations);
- break;
- case MEMOP_TYPE_FREE:
- {
- size_t allocations = objspace->malloc_params.allocations;
- if (allocations > 0) {
- atomic_sub_nounderflow(&objspace->malloc_params.allocations, 1);
- }
-#if MALLOC_ALLOCATED_SIZE_CHECK
- else {
- GC_ASSERT(objspace->malloc_params.allocations > 0);
- }
-#endif
- }
- break;
- case MEMOP_TYPE_REALLOC: /* ignore */ break;
- }
-#endif
- return true;
-}
-
-#define objspace_malloc_increase(...) \
- for (bool malloc_increase_done = objspace_malloc_increase_report(__VA_ARGS__); \
- !malloc_increase_done; \
- malloc_increase_done = objspace_malloc_increase_body(__VA_ARGS__))
-
-struct malloc_obj_info { /* 4 words */
- size_t size;
-};
-
-static inline size_t
-objspace_malloc_prepare(rb_objspace_t *objspace, size_t size)
-{
- if (size == 0) size = 1;
-
-#if CALC_EXACT_MALLOC_SIZE
- size += sizeof(struct malloc_obj_info);
-#endif
-
- return size;
-}
-
-static bool
-malloc_during_gc_p(rb_objspace_t *objspace)
-{
- /* malloc is not allowed during GC when we're not using multiple ractors
- * (since ractors can run while another thread is sweeping) and when we
- * have the GVL (since if we don't have the GVL, we'll try to acquire the
- * GVL which will block and ensure the other thread finishes GC). */
- return during_gc && !dont_gc_val() && !rb_gc_multi_ractor_p() && ruby_thread_has_gvl_p();
-}
-
-static inline void *
-objspace_malloc_fixup(rb_objspace_t *objspace, void *mem, size_t size)
-{
- size = objspace_malloc_size(objspace, mem, size);
- objspace_malloc_increase(objspace, mem, size, 0, MEMOP_TYPE_MALLOC) {}
-
-#if CALC_EXACT_MALLOC_SIZE
- {
- struct malloc_obj_info *info = mem;
- info->size = size;
- mem = info + 1;
- }
-#endif
-
- return mem;
-}
-
-#if defined(__GNUC__) && RUBY_DEBUG
-#define RB_BUG_INSTEAD_OF_RB_MEMERROR 1
-#endif
-
-#ifndef RB_BUG_INSTEAD_OF_RB_MEMERROR
-# define RB_BUG_INSTEAD_OF_RB_MEMERROR 0
-#endif
-
-#define GC_MEMERROR(...) \
- ((RB_BUG_INSTEAD_OF_RB_MEMERROR+0) ? rb_bug("" __VA_ARGS__) : rb_memerror())
-
-#define TRY_WITH_GC(siz, expr) do { \
- const gc_profile_record_flag gpr = \
- GPR_FLAG_FULL_MARK | \
- GPR_FLAG_IMMEDIATE_MARK | \
- GPR_FLAG_IMMEDIATE_SWEEP | \
- GPR_FLAG_MALLOC; \
- objspace_malloc_gc_stress(objspace); \
- \
- if (RB_LIKELY((expr))) { \
- /* Success on 1st try */ \
- } \
- else if (!garbage_collect_with_gvl(objspace, gpr)) { \
- /* @shyouhei thinks this doesn't happen */ \
- GC_MEMERROR("TRY_WITH_GC: could not GC"); \
- } \
- else if ((expr)) { \
- /* Success on 2nd try */ \
- } \
- else { \
- GC_MEMERROR("TRY_WITH_GC: could not allocate:" \
- "%"PRIdSIZE" bytes for %s", \
- siz, # expr); \
- } \
- } while (0)
-
-static void
-check_malloc_not_in_gc(rb_objspace_t *objspace, const char *msg)
-{
- if (RB_UNLIKELY(malloc_during_gc_p(objspace))) {
- dont_gc_on();
- during_gc = false;
- rb_bug("Cannot %s during GC", msg);
- }
-}
-
-void
-rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- if (!ptr) {
- /*
- * ISO/IEC 9899 says "If ptr is a null pointer, no action occurs" since
- * its first version. We would better follow.
- */
- return;
- }
-#if CALC_EXACT_MALLOC_SIZE
- struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
- ptr = info;
- old_size = info->size;
-#endif
- old_size = objspace_malloc_size(objspace, ptr, old_size);
-
- objspace_malloc_increase(objspace, ptr, 0, old_size, MEMOP_TYPE_FREE) {
- free(ptr);
- ptr = NULL;
- RB_DEBUG_COUNTER_INC(heap_xfree);
- }
-}
-
-void *
-rb_gc_impl_malloc(void *objspace_ptr, size_t size)
-{
- rb_objspace_t *objspace = objspace_ptr;
- check_malloc_not_in_gc(objspace, "malloc");
-
- void *mem;
-
- size = objspace_malloc_prepare(objspace, size);
- TRY_WITH_GC(size, mem = malloc(size));
- RB_DEBUG_COUNTER_INC(heap_xmalloc);
- return objspace_malloc_fixup(objspace, mem, size);
-}
-
-void *
-rb_gc_impl_calloc(void *objspace_ptr, size_t size)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- if (RB_UNLIKELY(malloc_during_gc_p(objspace))) {
- rb_warn("calloc during GC detected, this could cause crashes if it triggers another GC");
-#if RGENGC_CHECK_MODE || RUBY_DEBUG
- rb_bug("Cannot calloc during GC");
-#endif
- }
-
- void *mem;
-
- size = objspace_malloc_prepare(objspace, size);
- TRY_WITH_GC(size, mem = calloc1(size));
- return objspace_malloc_fixup(objspace, mem, size);
-}
-
-void *
-rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- check_malloc_not_in_gc(objspace, "realloc");
-
- void *mem;
-
- if (!ptr) return rb_gc_impl_malloc(objspace, new_size);
-
- /*
- * The behavior of realloc(ptr, 0) is implementation defined.
- * Therefore we don't use realloc(ptr, 0) for portability reason.
- * see http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_400.htm
- */
- if (new_size == 0) {
- if ((mem = rb_gc_impl_malloc(objspace, 0)) != NULL) {
- /*
- * - OpenBSD's malloc(3) man page says that when 0 is passed, it
- * returns a non-NULL pointer to an access-protected memory page.
- * The returned pointer cannot be read / written at all, but
- * still be a valid argument of free().
- *
- * https://man.openbsd.org/malloc.3
- *
- * - Linux's malloc(3) man page says that it _might_ perhaps return
- * a non-NULL pointer when its argument is 0. That return value
- * is safe (and is expected) to be passed to free().
- *
- * https://man7.org/linux/man-pages/man3/malloc.3.html
- *
- * - As I read the implementation jemalloc's malloc() returns fully
- * normal 16 bytes memory region when its argument is 0.
- *
- * - As I read the implementation musl libc's malloc() returns
- * fully normal 32 bytes memory region when its argument is 0.
- *
- * - Other malloc implementations can also return non-NULL.
- */
- rb_gc_impl_free(objspace, ptr, old_size);
- return mem;
- }
- else {
- /*
- * It is dangerous to return NULL here, because that could lead to
- * RCE. Fallback to 1 byte instead of zero.
- *
- * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11932
- */
- new_size = 1;
- }
- }
-
-#if CALC_EXACT_MALLOC_SIZE
- {
- struct malloc_obj_info *info = (struct malloc_obj_info *)ptr - 1;
- new_size += sizeof(struct malloc_obj_info);
- ptr = info;
- old_size = info->size;
- }
-#endif
-
- old_size = objspace_malloc_size(objspace, ptr, old_size);
- TRY_WITH_GC(new_size, mem = RB_GNUC_EXTENSION_BLOCK(realloc(ptr, new_size)));
- new_size = objspace_malloc_size(objspace, mem, new_size);
-
-#if CALC_EXACT_MALLOC_SIZE
- {
- struct malloc_obj_info *info = mem;
- info->size = new_size;
- mem = info + 1;
- }
-#endif
-
- objspace_malloc_increase(objspace, mem, new_size, old_size, MEMOP_TYPE_REALLOC);
-
- RB_DEBUG_COUNTER_INC(heap_xrealloc);
- return mem;
-}
-
-void
-rb_gc_impl_adjust_memory_usage(void *objspace_ptr, ssize_t diff)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- if (diff > 0) {
- objspace_malloc_increase(objspace, 0, diff, 0, MEMOP_TYPE_REALLOC);
- }
- else if (diff < 0) {
- objspace_malloc_increase(objspace, 0, 0, -diff, MEMOP_TYPE_REALLOC);
- }
-}
-
-// TODO: move GC profiler stuff back into gc.c
-/*
- ------------------------------ GC profiler ------------------------------
-*/
-
-#define GC_PROFILE_RECORD_DEFAULT_SIZE 100
-
-static bool
-current_process_time(struct timespec *ts)
-{
-#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
- {
- static int try_clock_gettime = 1;
- if (try_clock_gettime && clock_gettime(CLOCK_PROCESS_CPUTIME_ID, ts) == 0) {
- return true;
- }
- else {
- try_clock_gettime = 0;
- }
- }
-#endif
-
-#ifdef RUSAGE_SELF
- {
- struct rusage usage;
- struct timeval time;
- if (getrusage(RUSAGE_SELF, &usage) == 0) {
- time = usage.ru_utime;
- ts->tv_sec = time.tv_sec;
- ts->tv_nsec = (int32_t)time.tv_usec * 1000;
- return true;
- }
- }
-#endif
-
-#ifdef _WIN32
- {
- FILETIME creation_time, exit_time, kernel_time, user_time;
- ULARGE_INTEGER ui;
-
- if (GetProcessTimes(GetCurrentProcess(),
- &creation_time, &exit_time, &kernel_time, &user_time) != 0) {
- memcpy(&ui, &user_time, sizeof(FILETIME));
-#define PER100NSEC (uint64_t)(1000 * 1000 * 10)
- ts->tv_nsec = (long)(ui.QuadPart % PER100NSEC);
- ts->tv_sec = (time_t)(ui.QuadPart / PER100NSEC);
- return true;
- }
- }
-#endif
-
- return false;
-}
-
-static double
-getrusage_time(void)
-{
- struct timespec ts;
- if (current_process_time(&ts)) {
- return ts.tv_sec + ts.tv_nsec * 1e-9;
- }
- else {
- return 0.0;
- }
-}
-
-
-static inline void
-gc_prof_setup_new_record(rb_objspace_t *objspace, unsigned int reason)
-{
- if (objspace->profile.run) {
- size_t index = objspace->profile.next_index;
- gc_profile_record *record;
-
- /* create new record */
- objspace->profile.next_index++;
-
- if (!objspace->profile.records) {
- objspace->profile.size = GC_PROFILE_RECORD_DEFAULT_SIZE;
- objspace->profile.records = malloc(xmalloc2_size(sizeof(gc_profile_record), objspace->profile.size));
- }
- if (index >= objspace->profile.size) {
- void *ptr;
- objspace->profile.size += 1000;
- ptr = realloc(objspace->profile.records, xmalloc2_size(sizeof(gc_profile_record), objspace->profile.size));
- if (!ptr) rb_memerror();
- objspace->profile.records = ptr;
- }
- if (!objspace->profile.records) {
- rb_bug("gc_profile malloc or realloc miss");
- }
- record = objspace->profile.current_record = &objspace->profile.records[objspace->profile.next_index - 1];
- MEMZERO(record, gc_profile_record, 1);
-
- /* setup before-GC parameter */
- record->flags = reason | (ruby_gc_stressful ? GPR_FLAG_STRESS : 0);
-#if MALLOC_ALLOCATED_SIZE
- record->allocated_size = malloc_allocated_size;
-#endif
-#if GC_PROFILE_MORE_DETAIL && GC_PROFILE_DETAIL_MEMORY
-#ifdef RUSAGE_SELF
- {
- struct rusage usage;
- if (getrusage(RUSAGE_SELF, &usage) == 0) {
- record->maxrss = usage.ru_maxrss;
- record->minflt = usage.ru_minflt;
- record->majflt = usage.ru_majflt;
- }
- }
-#endif
-#endif
- }
-}
-
-static inline void
-gc_prof_timer_start(rb_objspace_t *objspace)
-{
- if (gc_prof_enabled(objspace)) {
- gc_profile_record *record = gc_prof_record(objspace);
-#if GC_PROFILE_MORE_DETAIL
- record->prepare_time = objspace->profile.prepare_time;
-#endif
- record->gc_time = 0;
- record->gc_invoke_time = getrusage_time();
- }
-}
-
-static double
-elapsed_time_from(double time)
-{
- double now = getrusage_time();
- if (now > time) {
- return now - time;
- }
- else {
- return 0;
- }
-}
-
-static inline void
-gc_prof_timer_stop(rb_objspace_t *objspace)
-{
- if (gc_prof_enabled(objspace)) {
- gc_profile_record *record = gc_prof_record(objspace);
- record->gc_time = elapsed_time_from(record->gc_invoke_time);
- record->gc_invoke_time -= objspace->profile.invoke_time;
- }
-}
-
-#ifdef BUILDING_SHARED_GC
-# define RUBY_DTRACE_GC_HOOK(name)
-#else
-# define RUBY_DTRACE_GC_HOOK(name) \
- do {if (RUBY_DTRACE_GC_##name##_ENABLED()) RUBY_DTRACE_GC_##name();} while (0)
-#endif
-
-static inline void
-gc_prof_mark_timer_start(rb_objspace_t *objspace)
-{
- RUBY_DTRACE_GC_HOOK(MARK_BEGIN);
-#if GC_PROFILE_MORE_DETAIL
- if (gc_prof_enabled(objspace)) {
- gc_prof_record(objspace)->gc_mark_time = getrusage_time();
- }
-#endif
-}
-
-static inline void
-gc_prof_mark_timer_stop(rb_objspace_t *objspace)
-{
- RUBY_DTRACE_GC_HOOK(MARK_END);
-#if GC_PROFILE_MORE_DETAIL
- if (gc_prof_enabled(objspace)) {
- gc_profile_record *record = gc_prof_record(objspace);
- record->gc_mark_time = elapsed_time_from(record->gc_mark_time);
- }
-#endif
-}
-
-static inline void
-gc_prof_sweep_timer_start(rb_objspace_t *objspace)
-{
- RUBY_DTRACE_GC_HOOK(SWEEP_BEGIN);
- if (gc_prof_enabled(objspace)) {
- gc_profile_record *record = gc_prof_record(objspace);
-
- if (record->gc_time > 0 || GC_PROFILE_MORE_DETAIL) {
- objspace->profile.gc_sweep_start_time = getrusage_time();
- }
- }
-}
-
-static inline void
-gc_prof_sweep_timer_stop(rb_objspace_t *objspace)
-{
- RUBY_DTRACE_GC_HOOK(SWEEP_END);
-
- if (gc_prof_enabled(objspace)) {
- double sweep_time;
- gc_profile_record *record = gc_prof_record(objspace);
-
- if (record->gc_time > 0) {
- sweep_time = elapsed_time_from(objspace->profile.gc_sweep_start_time);
- /* need to accumulate GC time for lazy sweep after gc() */
- record->gc_time += sweep_time;
- }
- else if (GC_PROFILE_MORE_DETAIL) {
- sweep_time = elapsed_time_from(objspace->profile.gc_sweep_start_time);
- }
-
-#if GC_PROFILE_MORE_DETAIL
- record->gc_sweep_time += sweep_time;
- if (heap_pages_deferred_final) record->flags |= GPR_FLAG_HAVE_FINALIZE;
-#endif
- if (heap_pages_deferred_final) objspace->profile.latest_gc_info |= GPR_FLAG_HAVE_FINALIZE;
- }
-}
-
-static inline void
-gc_prof_set_malloc_info(rb_objspace_t *objspace)
-{
-#if GC_PROFILE_MORE_DETAIL
- if (gc_prof_enabled(objspace)) {
- gc_profile_record *record = gc_prof_record(objspace);
- record->allocate_increase = malloc_increase;
- record->allocate_limit = malloc_limit;
- }
-#endif
-}
-
-static inline void
-gc_prof_set_heap_info(rb_objspace_t *objspace)
-{
- if (gc_prof_enabled(objspace)) {
- gc_profile_record *record = gc_prof_record(objspace);
- size_t live = objspace->profile.total_allocated_objects_at_gc_start - total_freed_objects(objspace);
- size_t total = objspace->profile.heap_used_at_gc_start * HEAP_PAGE_OBJ_LIMIT;
-
-#if GC_PROFILE_MORE_DETAIL
- record->heap_use_pages = objspace->profile.heap_used_at_gc_start;
- record->heap_live_objects = live;
- record->heap_free_objects = total - live;
-#endif
-
- record->heap_total_objects = total;
- record->heap_use_size = live * BASE_SLOT_SIZE;
- record->heap_total_size = total * BASE_SLOT_SIZE;
- }
-}
-
-/*
- * call-seq:
- * GC::Profiler.clear -> nil
- *
- * Clears the \GC profiler data.
- *
- */
-
-static VALUE
-gc_profile_clear(VALUE _)
-{
- rb_objspace_t *objspace = rb_gc_get_objspace();
- void *p = objspace->profile.records;
- objspace->profile.records = NULL;
- objspace->profile.size = 0;
- objspace->profile.next_index = 0;
- objspace->profile.current_record = 0;
- free(p);
- return Qnil;
-}
-
-/*
- * call-seq:
- * GC::Profiler.raw_data -> [Hash, ...]
- *
- * Returns an Array of individual raw profile data Hashes ordered
- * from earliest to latest by +:GC_INVOKE_TIME+.
- *
- * For example:
- *
- * [
- * {
- * :GC_TIME=>1.3000000000000858e-05,
- * :GC_INVOKE_TIME=>0.010634999999999999,
- * :HEAP_USE_SIZE=>289640,
- * :HEAP_TOTAL_SIZE=>588960,
- * :HEAP_TOTAL_OBJECTS=>14724,
- * :GC_IS_MARKED=>false
- * },
- * # ...
- * ]
- *
- * The keys mean:
- *
- * +:GC_TIME+::
- * Time elapsed in seconds for this GC run
- * +:GC_INVOKE_TIME+::
- * Time elapsed in seconds from startup to when the GC was invoked
- * +:HEAP_USE_SIZE+::
- * Total bytes of heap used
- * +:HEAP_TOTAL_SIZE+::
- * Total size of heap in bytes
- * +:HEAP_TOTAL_OBJECTS+::
- * Total number of objects
- * +:GC_IS_MARKED+::
- * Returns +true+ if the GC is in mark phase
- *
- * If ruby was built with +GC_PROFILE_MORE_DETAIL+, you will also have access
- * to the following hash keys:
- *
- * +:GC_MARK_TIME+::
- * +:GC_SWEEP_TIME+::
- * +:ALLOCATE_INCREASE+::
- * +:ALLOCATE_LIMIT+::
- * +:HEAP_USE_PAGES+::
- * +:HEAP_LIVE_OBJECTS+::
- * +:HEAP_FREE_OBJECTS+::
- * +:HAVE_FINALIZE+::
- *
- */
-
-static VALUE
-gc_profile_record_get(VALUE _)
-{
- VALUE prof;
- VALUE gc_profile = rb_ary_new();
- size_t i;
- rb_objspace_t *objspace = rb_gc_get_objspace();
-
- if (!objspace->profile.run) {
- return Qnil;
- }
-
- for (i =0; i < objspace->profile.next_index; i++) {
- gc_profile_record *record = &objspace->profile.records[i];
-
- prof = rb_hash_new();
- rb_hash_aset(prof, ID2SYM(rb_intern("GC_FLAGS")), gc_info_decode(objspace, rb_hash_new(), record->flags));
- rb_hash_aset(prof, ID2SYM(rb_intern("GC_TIME")), DBL2NUM(record->gc_time));
- rb_hash_aset(prof, ID2SYM(rb_intern("GC_INVOKE_TIME")), DBL2NUM(record->gc_invoke_time));
- rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SIZE")), SIZET2NUM(record->heap_use_size));
- rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")), SIZET2NUM(record->heap_total_size));
- rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")), SIZET2NUM(record->heap_total_objects));
- rb_hash_aset(prof, ID2SYM(rb_intern("MOVED_OBJECTS")), SIZET2NUM(record->moved_objects));
- rb_hash_aset(prof, ID2SYM(rb_intern("GC_IS_MARKED")), Qtrue);
-#if GC_PROFILE_MORE_DETAIL
- rb_hash_aset(prof, ID2SYM(rb_intern("GC_MARK_TIME")), DBL2NUM(record->gc_mark_time));
- rb_hash_aset(prof, ID2SYM(rb_intern("GC_SWEEP_TIME")), DBL2NUM(record->gc_sweep_time));
- rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_INCREASE")), SIZET2NUM(record->allocate_increase));
- rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_LIMIT")), SIZET2NUM(record->allocate_limit));
- rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_PAGES")), SIZET2NUM(record->heap_use_pages));
- rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_LIVE_OBJECTS")), SIZET2NUM(record->heap_live_objects));
- rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_FREE_OBJECTS")), SIZET2NUM(record->heap_free_objects));
-
- rb_hash_aset(prof, ID2SYM(rb_intern("REMOVING_OBJECTS")), SIZET2NUM(record->removing_objects));
- rb_hash_aset(prof, ID2SYM(rb_intern("EMPTY_OBJECTS")), SIZET2NUM(record->empty_objects));
-
- rb_hash_aset(prof, ID2SYM(rb_intern("HAVE_FINALIZE")), (record->flags & GPR_FLAG_HAVE_FINALIZE) ? Qtrue : Qfalse);
-#endif
-
-#if RGENGC_PROFILE > 0
- rb_hash_aset(prof, ID2SYM(rb_intern("OLD_OBJECTS")), SIZET2NUM(record->old_objects));
- rb_hash_aset(prof, ID2SYM(rb_intern("REMEMBERED_NORMAL_OBJECTS")), SIZET2NUM(record->remembered_normal_objects));
- rb_hash_aset(prof, ID2SYM(rb_intern("REMEMBERED_SHADY_OBJECTS")), SIZET2NUM(record->remembered_shady_objects));
-#endif
- rb_ary_push(gc_profile, prof);
- }
-
- return gc_profile;
-}
-
-#if GC_PROFILE_MORE_DETAIL
-#define MAJOR_REASON_MAX 0x10
-
-static char *
-gc_profile_dump_major_reason(unsigned int flags, char *buff)
-{
- unsigned int reason = flags & GPR_FLAG_MAJOR_MASK;
- int i = 0;
-
- if (reason == GPR_FLAG_NONE) {
- buff[0] = '-';
- buff[1] = 0;
- }
- else {
-#define C(x, s) \
- if (reason & GPR_FLAG_MAJOR_BY_##x) { \
- buff[i++] = #x[0]; \
- if (i >= MAJOR_REASON_MAX) rb_bug("gc_profile_dump_major_reason: overflow"); \
- buff[i] = 0; \
- }
- C(NOFREE, N);
- C(OLDGEN, O);
- C(SHADY, S);
-#if RGENGC_ESTIMATE_OLDMALLOC
- C(OLDMALLOC, M);
-#endif
-#undef C
- }
- return buff;
-}
-#endif
-
-
-
-static void
-gc_profile_dump_on(VALUE out, VALUE (*append)(VALUE, VALUE))
-{
- rb_objspace_t *objspace = rb_gc_get_objspace();
- size_t count = objspace->profile.next_index;
-#ifdef MAJOR_REASON_MAX
- char reason_str[MAJOR_REASON_MAX];
-#endif
-
- if (objspace->profile.run && count /* > 1 */) {
- size_t i;
- const gc_profile_record *record;
-
- append(out, rb_sprintf("GC %"PRIuSIZE" invokes.\n", objspace->profile.count));
- append(out, rb_str_new_cstr("Index Invoke Time(sec) Use Size(byte) Total Size(byte) Total Object GC Time(ms)\n"));
-
- for (i = 0; i < count; i++) {
- record = &objspace->profile.records[i];
- append(out, rb_sprintf("%5"PRIuSIZE" %19.3f %20"PRIuSIZE" %20"PRIuSIZE" %20"PRIuSIZE" %30.20f\n",
- i+1, record->gc_invoke_time, record->heap_use_size,
- record->heap_total_size, record->heap_total_objects, record->gc_time*1000));
- }
-
-#if GC_PROFILE_MORE_DETAIL
- const char *str = "\n\n" \
- "More detail.\n" \
- "Prepare Time = Previously GC's rest sweep time\n"
- "Index Flags Allocate Inc. Allocate Limit"
-#if CALC_EXACT_MALLOC_SIZE
- " Allocated Size"
-#endif
- " Use Page Mark Time(ms) Sweep Time(ms) Prepare Time(ms) LivingObj FreeObj RemovedObj EmptyObj"
-#if RGENGC_PROFILE
- " OldgenObj RemNormObj RemShadObj"
-#endif
-#if GC_PROFILE_DETAIL_MEMORY
- " MaxRSS(KB) MinorFLT MajorFLT"
-#endif
- "\n";
- append(out, rb_str_new_cstr(str));
-
- for (i = 0; i < count; i++) {
- record = &objspace->profile.records[i];
- append(out, rb_sprintf("%5"PRIuSIZE" %4s/%c/%6s%c %13"PRIuSIZE" %15"PRIuSIZE
-#if CALC_EXACT_MALLOC_SIZE
- " %15"PRIuSIZE
-#endif
- " %9"PRIuSIZE" %17.12f %17.12f %17.12f %10"PRIuSIZE" %10"PRIuSIZE" %10"PRIuSIZE" %10"PRIuSIZE
-#if RGENGC_PROFILE
- "%10"PRIuSIZE" %10"PRIuSIZE" %10"PRIuSIZE
-#endif
-#if GC_PROFILE_DETAIL_MEMORY
- "%11ld %8ld %8ld"
-#endif
-
- "\n",
- i+1,
- gc_profile_dump_major_reason(record->flags, reason_str),
- (record->flags & GPR_FLAG_HAVE_FINALIZE) ? 'F' : '.',
- (record->flags & GPR_FLAG_NEWOBJ) ? "NEWOBJ" :
- (record->flags & GPR_FLAG_MALLOC) ? "MALLOC" :
- (record->flags & GPR_FLAG_METHOD) ? "METHOD" :
- (record->flags & GPR_FLAG_CAPI) ? "CAPI__" : "??????",
- (record->flags & GPR_FLAG_STRESS) ? '!' : ' ',
- record->allocate_increase, record->allocate_limit,
-#if CALC_EXACT_MALLOC_SIZE
- record->allocated_size,
-#endif
- record->heap_use_pages,
- record->gc_mark_time*1000,
- record->gc_sweep_time*1000,
- record->prepare_time*1000,
-
- record->heap_live_objects,
- record->heap_free_objects,
- record->removing_objects,
- record->empty_objects
-#if RGENGC_PROFILE
- ,
- record->old_objects,
- record->remembered_normal_objects,
- record->remembered_shady_objects
-#endif
-#if GC_PROFILE_DETAIL_MEMORY
- ,
- record->maxrss / 1024,
- record->minflt,
- record->majflt
-#endif
-
- ));
- }
-#endif
- }
-}
-
-/*
- * call-seq:
- * GC::Profiler.result -> String
- *
- * Returns a profile data report such as:
- *
- * GC 1 invokes.
- * Index Invoke Time(sec) Use Size(byte) Total Size(byte) Total Object GC time(ms)
- * 1 0.012 159240 212940 10647 0.00000000000001530000
- */
-
-static VALUE
-gc_profile_result(VALUE _)
-{
- VALUE str = rb_str_buf_new(0);
- gc_profile_dump_on(str, rb_str_buf_append);
- return str;
-}
-
-/*
- * call-seq:
- * GC::Profiler.report
- * GC::Profiler.report(io)
- *
- * Writes the GC::Profiler.result to <tt>$stdout</tt> or the given IO object.
- *
- */
-
-static VALUE
-gc_profile_report(int argc, VALUE *argv, VALUE self)
-{
- VALUE out;
-
- out = (!rb_check_arity(argc, 0, 1) ? rb_stdout : argv[0]);
- gc_profile_dump_on(out, rb_io_write);
-
- return Qnil;
-}
-
-/*
- * call-seq:
- * GC::Profiler.total_time -> float
- *
- * The total time used for garbage collection in seconds
- */
-
-static VALUE
-gc_profile_total_time(VALUE self)
-{
- double time = 0;
- rb_objspace_t *objspace = rb_gc_get_objspace();
-
- if (objspace->profile.run && objspace->profile.next_index > 0) {
- size_t i;
- size_t count = objspace->profile.next_index;
-
- for (i = 0; i < count; i++) {
- time += objspace->profile.records[i].gc_time;
- }
- }
- return DBL2NUM(time);
-}
-
-/*
- * call-seq:
- * GC::Profiler.enabled? -> true or false
- *
- * The current status of \GC profile mode.
- */
-
-static VALUE
-gc_profile_enable_get(VALUE self)
-{
- rb_objspace_t *objspace = rb_gc_get_objspace();
- return objspace->profile.run ? Qtrue : Qfalse;
-}
-
-/*
- * call-seq:
- * GC::Profiler.enable -> nil
- *
- * Starts the \GC profiler.
- *
- */
-
-static VALUE
-gc_profile_enable(VALUE _)
-{
- rb_objspace_t *objspace = rb_gc_get_objspace();
- objspace->profile.run = TRUE;
- objspace->profile.current_record = 0;
- return Qnil;
-}
-
-/*
- * call-seq:
- * GC::Profiler.disable -> nil
- *
- * Stops the \GC profiler.
- *
- */
-
-static VALUE
-gc_profile_disable(VALUE _)
-{
- rb_objspace_t *objspace = rb_gc_get_objspace();
-
- objspace->profile.run = FALSE;
- objspace->profile.current_record = 0;
- return Qnil;
-}
-
-/*
- * call-seq:
- * GC.verify_internal_consistency -> nil
- *
- * Verify internal consistency.
- *
- * This method is implementation specific.
- * Now this method checks generational consistency
- * if RGenGC is supported.
- */
-static VALUE
-gc_verify_internal_consistency_m(VALUE dummy)
-{
- gc_verify_internal_consistency(rb_gc_get_objspace());
- return Qnil;
-}
-
-#if GC_CAN_COMPILE_COMPACTION
-/*
- * call-seq:
- * GC.auto_compact = flag
- *
- * Updates automatic compaction mode.
- *
- * When enabled, the compactor will execute on every major collection.
- *
- * Enabling compaction will degrade performance on major collections.
- */
-static VALUE
-gc_set_auto_compact(VALUE _, VALUE v)
-{
- GC_ASSERT(GC_COMPACTION_SUPPORTED);
-
- ruby_enable_autocompact = RTEST(v);
-
-#if RGENGC_CHECK_MODE
- ruby_autocompact_compare_func = NULL;
-
- if (SYMBOL_P(v)) {
- ID id = RB_SYM2ID(v);
- if (id == rb_intern("empty")) {
- ruby_autocompact_compare_func = compare_free_slots;
- }
- }
-#endif
-
- return v;
-}
-#else
-# define gc_set_auto_compact rb_f_notimplement
-#endif
-
-#if GC_CAN_COMPILE_COMPACTION
-/*
- * call-seq:
- * GC.auto_compact -> true or false
- *
- * Returns whether or not automatic compaction has been enabled.
- */
-static VALUE
-gc_get_auto_compact(VALUE _)
-{
- return ruby_enable_autocompact ? Qtrue : Qfalse;
-}
-#else
-# define gc_get_auto_compact rb_f_notimplement
-#endif
-
-#if GC_CAN_COMPILE_COMPACTION
-/*
- * call-seq:
- * GC.latest_compact_info -> hash
- *
- * Returns information about object moved in the most recent \GC compaction.
- *
- * The returned +hash+ contains the following keys:
- *
- * [considered]
- * Hash containing the type of the object as the key and the number of
- * objects of that type that were considered for movement.
- * [moved]
- * Hash containing the type of the object as the key and the number of
- * objects of that type that were actually moved.
- * [moved_up]
- * Hash containing the type of the object as the key and the number of
- * objects of that type that were increased in size.
- * [moved_down]
- * Hash containing the type of the object as the key and the number of
- * objects of that type that were decreased in size.
- *
- * Some objects can't be moved (due to pinning) so these numbers can be used to
- * calculate compaction efficiency.
- */
-static VALUE
-gc_compact_stats(VALUE self)
-{
- rb_objspace_t *objspace = rb_gc_get_objspace();
- VALUE h = rb_hash_new();
- VALUE considered = rb_hash_new();
- VALUE moved = rb_hash_new();
- VALUE moved_up = rb_hash_new();
- VALUE moved_down = rb_hash_new();
-
- for (size_t i = 0; i < T_MASK; i++) {
- if (objspace->rcompactor.considered_count_table[i]) {
- rb_hash_aset(considered, type_sym(i), SIZET2NUM(objspace->rcompactor.considered_count_table[i]));
- }
-
- if (objspace->rcompactor.moved_count_table[i]) {
- rb_hash_aset(moved, type_sym(i), SIZET2NUM(objspace->rcompactor.moved_count_table[i]));
- }
-
- if (objspace->rcompactor.moved_up_count_table[i]) {
- rb_hash_aset(moved_up, type_sym(i), SIZET2NUM(objspace->rcompactor.moved_up_count_table[i]));
- }
-
- if (objspace->rcompactor.moved_down_count_table[i]) {
- rb_hash_aset(moved_down, type_sym(i), SIZET2NUM(objspace->rcompactor.moved_down_count_table[i]));
- }
- }
-
- rb_hash_aset(h, ID2SYM(rb_intern("considered")), considered);
- rb_hash_aset(h, ID2SYM(rb_intern("moved")), moved);
- rb_hash_aset(h, ID2SYM(rb_intern("moved_up")), moved_up);
- rb_hash_aset(h, ID2SYM(rb_intern("moved_down")), moved_down);
-
- return h;
-}
-#else
-# define gc_compact_stats rb_f_notimplement
-#endif
-
-#if GC_CAN_COMPILE_COMPACTION
-/*
- * call-seq:
- * GC.compact -> hash
- *
- * This function compacts objects together in Ruby's heap. It eliminates
- * unused space (or fragmentation) in the heap by moving objects in to that
- * unused space.
- *
- * The returned +hash+ contains statistics about the objects that were moved;
- * see GC.latest_compact_info.
- *
- * This method is only expected to work on CRuby.
- *
- * To test whether \GC compaction is supported, use the idiom:
- *
- * GC.respond_to?(:compact)
- */
-static VALUE
-gc_compact(VALUE self)
-{
- rb_objspace_t *objspace = rb_gc_get_objspace();
- int full_marking_p = gc_config_full_mark_val;
- gc_config_full_mark_set(TRUE);
-
- /* Run GC with compaction enabled */
- rb_gc_impl_start(rb_gc_get_objspace(), true, true, true, true);
- gc_config_full_mark_set(full_marking_p);
-
- return gc_compact_stats(self);
-}
-#else
-# define gc_compact rb_f_notimplement
-#endif
-
-#if GC_CAN_COMPILE_COMPACTION
-struct desired_compaction_pages_i_data {
- rb_objspace_t *objspace;
- size_t required_slots[HEAP_COUNT];
-};
-
-static int
-desired_compaction_pages_i(struct heap_page *page, void *data)
-{
- struct desired_compaction_pages_i_data *tdata = data;
- rb_objspace_t *objspace = tdata->objspace;
- VALUE vstart = (VALUE)page->start;
- VALUE vend = vstart + (VALUE)(page->total_slots * page->heap->slot_size);
-
-
- for (VALUE v = vstart; v != vend; v += page->heap->slot_size) {
- asan_unpoisoning_object(v) {
- /* skip T_NONEs; they won't be moved */
- if (BUILTIN_TYPE(v) != T_NONE) {
- rb_heap_t *dest_pool = gc_compact_destination_pool(objspace, page->heap, v);
- size_t dest_pool_idx = dest_pool - heaps;
- tdata->required_slots[dest_pool_idx]++;
- }
- }
- }
-
- return 0;
-}
-
-/* call-seq:
- * GC.verify_compaction_references(toward: nil, double_heap: false) -> hash
- *
- * Verify compaction reference consistency.
- *
- * This method is implementation specific. During compaction, objects that
- * were moved are replaced with T_MOVED objects. No object should have a
- * reference to a T_MOVED object after compaction.
- *
- * This function expands the heap to ensure room to move all objects,
- * compacts the heap to make sure everything moves, updates all references,
- * then performs a full \GC. If any object contains a reference to a T_MOVED
- * object, that object should be pushed on the mark stack, and will
- * make a SEGV.
- */
-static VALUE
-gc_verify_compaction_references(int argc, VALUE* argv, VALUE self)
-{
- static ID keywords[3] = {0};
- if (!keywords[0]) {
- keywords[0] = rb_intern("toward");
- keywords[1] = rb_intern("double_heap");
- keywords[2] = rb_intern("expand_heap");
- }
-
- VALUE options;
- rb_scan_args_kw(rb_keyword_given_p(), argc, argv, ":", &options);
-
- VALUE arguments[3] = { Qnil, Qfalse, Qfalse };
- int kwarg_count = rb_get_kwargs(options, keywords, 0, 3, arguments);
- bool toward_empty = kwarg_count > 0 && SYMBOL_P(arguments[0]) && SYM2ID(arguments[0]) == rb_intern("empty");
- bool expand_heap = (kwarg_count > 1 && RTEST(arguments[1])) || (kwarg_count > 2 && RTEST(arguments[2]));
-
- rb_objspace_t *objspace = rb_gc_get_objspace();
-
- /* Clear the heap. */
- rb_gc_impl_start(objspace, true, true, true, false);
-
- unsigned int lev = rb_gc_vm_lock();
- {
- gc_rest(objspace);
-
- /* if both double_heap and expand_heap are set, expand_heap takes precedence */
- if (expand_heap) {
- struct desired_compaction_pages_i_data desired_compaction = {
- .objspace = objspace,
- .required_slots = {0},
- };
- /* Work out how many objects want to be in each size pool, taking account of moves */
- objspace_each_pages(objspace, desired_compaction_pages_i, &desired_compaction, TRUE);
-
- /* Find out which pool has the most pages */
- size_t max_existing_pages = 0;
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- max_existing_pages = MAX(max_existing_pages, heap->total_pages);
- }
-
- /* Add pages to each size pool so that compaction is guaranteed to move every object */
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
-
- size_t pages_to_add = 0;
- /*
- * Step 1: Make sure every pool has the same number of pages, by adding empty pages
- * to smaller pools. This is required to make sure the compact cursor can advance
- * through all of the pools in `gc_sweep_compact` without hitting the "sweep &
- * compact cursors met" condition on some pools before fully compacting others
- */
- pages_to_add += max_existing_pages - heap->total_pages;
- /*
- * Step 2: Now add additional free pages to each size pool sufficient to hold all objects
- * that want to be in that size pool, whether moved into it or moved within it
- */
- objspace->heap_pages.allocatable_slots = desired_compaction.required_slots[i];
- while (objspace->heap_pages.allocatable_slots > 0) {
- heap_page_allocate_and_initialize(objspace, heap);
- }
- /*
- * Step 3: Add two more pages so that the compact & sweep cursors will meet _after_ all objects
- * have been moved, and not on the last iteration of the `gc_sweep_compact` loop
- */
- pages_to_add += 2;
-
- for (; pages_to_add > 0; pages_to_add--) {
- heap_page_allocate_and_initialize_force(objspace, heap);
- }
- }
- }
-
- if (toward_empty) {
- objspace->rcompactor.compare_func = compare_free_slots;
- }
- }
- rb_gc_vm_unlock(lev);
-
- rb_gc_impl_start(rb_gc_get_objspace(), true, true, true, true);
-
- rb_objspace_reachable_objects_from_root(root_obj_check_moved_i, objspace);
- objspace_each_objects(objspace, heap_check_moved_i, objspace, TRUE);
-
- objspace->rcompactor.compare_func = NULL;
-
- return gc_compact_stats(self);
-}
-#else
-# define gc_verify_compaction_references rb_f_notimplement
-#endif
-
-void
-rb_gc_impl_objspace_free(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- if (is_lazy_sweeping(objspace))
- rb_bug("lazy sweeping underway when freeing object space");
-
- free(objspace->profile.records);
- objspace->profile.records = NULL;
-
- for (size_t i = 0; i < rb_darray_size(objspace->heap_pages.sorted); i++) {
- heap_page_free(objspace, rb_darray_get(objspace->heap_pages.sorted, i));
- }
- rb_darray_free(objspace->heap_pages.sorted);
- heap_pages_lomem = 0;
- heap_pages_himem = 0;
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
- heap->total_pages = 0;
- heap->total_slots = 0;
- }
-
- st_free_table(objspace->id_to_obj_tbl);
- st_free_table(objspace->obj_to_id_tbl);
-
- free_stack_chunks(&objspace->mark_stack);
- mark_stack_free_cache(&objspace->mark_stack);
-
- rb_darray_free(objspace->weak_references);
-
- free(objspace);
-}
-
-#if MALLOC_ALLOCATED_SIZE
-/*
- * call-seq:
- * GC.malloc_allocated_size -> Integer
- *
- * Returns the size of memory allocated by malloc().
- *
- * Only available if ruby was built with +CALC_EXACT_MALLOC_SIZE+.
- */
-
-static VALUE
-gc_malloc_allocated_size(VALUE self)
-{
- return UINT2NUM(rb_objspace.malloc_params.allocated_size);
-}
-
-/*
- * call-seq:
- * GC.malloc_allocations -> Integer
- *
- * Returns the number of malloc() allocations.
- *
- * Only available if ruby was built with +CALC_EXACT_MALLOC_SIZE+.
- */
-
-static VALUE
-gc_malloc_allocations(VALUE self)
-{
- return UINT2NUM(rb_objspace.malloc_params.allocations);
-}
-#endif
-
-void *
-rb_gc_impl_objspace_alloc(void)
-{
- rb_objspace_t *objspace = calloc1(sizeof(rb_objspace_t));
-
- return objspace;
-}
-
-void
-rb_gc_impl_objspace_init(void *objspace_ptr)
-{
- rb_objspace_t *objspace = objspace_ptr;
-
- gc_config_full_mark_set(TRUE);
-
- objspace->flags.measure_gc = true;
- malloc_limit = gc_params.malloc_limit_min;
- objspace->finalize_deferred_pjob = rb_postponed_job_preregister(0, gc_finalize_deferred, objspace);
- if (objspace->finalize_deferred_pjob == POSTPONED_JOB_HANDLE_INVALID) {
- rb_bug("Could not preregister postponed job for GC");
- }
-
- for (int i = 0; i < HEAP_COUNT; i++) {
- rb_heap_t *heap = &heaps[i];
-
- heap->slot_size = (1 << i) * BASE_SLOT_SIZE;
-
- ccan_list_head_init(&heap->pages);
- }
-
- rb_darray_make(&objspace->heap_pages.sorted, 0);
- rb_darray_make(&objspace->weak_references, 0);
-
- // TODO: debug why on Windows Ruby crashes on boot when GC is on.
-#ifdef _WIN32
- dont_gc_on();
-#endif
-
-#if defined(INIT_HEAP_PAGE_ALLOC_USE_MMAP)
- /* Need to determine if we can use mmap at runtime. */
- heap_page_alloc_use_mmap = INIT_HEAP_PAGE_ALLOC_USE_MMAP;
-#endif
- objspace->next_object_id = OBJ_ID_INITIAL;
- objspace->id_to_obj_tbl = st_init_table(&object_id_hash_type);
- objspace->obj_to_id_tbl = st_init_numtable();
-#if RGENGC_ESTIMATE_OLDMALLOC
- objspace->rgengc.oldmalloc_increase_limit = gc_params.oldmalloc_limit_min;
-#endif
- /* Set size pools allocatable pages. */
- for (int i = 0; i < HEAP_COUNT; i++) {
- /* Set the default value of heap_init_slots. */
- gc_params.heap_init_slots[i] = GC_HEAP_INIT_SLOTS;
- }
-
- init_mark_stack(&objspace->mark_stack);
-
- objspace->profile.invoke_time = getrusage_time();
- finalizer_table = st_init_numtable();
-}
-
-void
-rb_gc_impl_init(void)
-{
- VALUE gc_constants = rb_hash_new();
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("DEBUG")), GC_DEBUG ? Qtrue : Qfalse);
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("BASE_SLOT_SIZE")), SIZET2NUM(BASE_SLOT_SIZE - RVALUE_OVERHEAD));
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OVERHEAD")), SIZET2NUM(RVALUE_OVERHEAD));
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_PAGE_OBJ_LIMIT")), SIZET2NUM(HEAP_PAGE_OBJ_LIMIT));
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_PAGE_BITMAP_SIZE")), SIZET2NUM(HEAP_PAGE_BITMAP_SIZE));
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_PAGE_SIZE")), SIZET2NUM(HEAP_PAGE_SIZE));
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("HEAP_COUNT")), LONG2FIX(HEAP_COUNT));
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVARGC_MAX_ALLOCATE_SIZE")), LONG2FIX(heap_slot_size(HEAP_COUNT - 1)));
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_OLD_AGE")), LONG2FIX(RVALUE_OLD_AGE));
- if (RB_BUG_INSTEAD_OF_RB_MEMERROR+0) {
- rb_hash_aset(gc_constants, ID2SYM(rb_intern("RB_BUG_INSTEAD_OF_RB_MEMERROR")), Qtrue);
- }
- OBJ_FREEZE(gc_constants);
- /* Internal constants in the garbage collector. */
- rb_define_const(rb_mGC, "INTERNAL_CONSTANTS", gc_constants);
-
- if (GC_COMPACTION_SUPPORTED) {
- rb_define_singleton_method(rb_mGC, "compact", gc_compact, 0);
- rb_define_singleton_method(rb_mGC, "auto_compact", gc_get_auto_compact, 0);
- rb_define_singleton_method(rb_mGC, "auto_compact=", gc_set_auto_compact, 1);
- rb_define_singleton_method(rb_mGC, "latest_compact_info", gc_compact_stats, 0);
- rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1);
- }
- else {
- rb_define_singleton_method(rb_mGC, "compact", rb_f_notimplement, 0);
- rb_define_singleton_method(rb_mGC, "auto_compact", rb_f_notimplement, 0);
- rb_define_singleton_method(rb_mGC, "auto_compact=", rb_f_notimplement, 1);
- rb_define_singleton_method(rb_mGC, "latest_compact_info", rb_f_notimplement, 0);
- rb_define_singleton_method(rb_mGC, "verify_compaction_references", rb_f_notimplement, -1);
- }
-
- /* internal methods */
- rb_define_singleton_method(rb_mGC, "verify_internal_consistency", gc_verify_internal_consistency_m, 0);
-
-#if MALLOC_ALLOCATED_SIZE
- rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0);
- rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0);
-#endif
-
- VALUE rb_mProfiler = rb_define_module_under(rb_mGC, "Profiler");
- rb_define_singleton_method(rb_mProfiler, "enabled?", gc_profile_enable_get, 0);
- rb_define_singleton_method(rb_mProfiler, "enable", gc_profile_enable, 0);
- rb_define_singleton_method(rb_mProfiler, "raw_data", gc_profile_record_get, 0);
- rb_define_singleton_method(rb_mProfiler, "disable", gc_profile_disable, 0);
- rb_define_singleton_method(rb_mProfiler, "clear", gc_profile_clear, 0);
- rb_define_singleton_method(rb_mProfiler, "result", gc_profile_result, 0);
- rb_define_singleton_method(rb_mProfiler, "report", gc_profile_report, -1);
- rb_define_singleton_method(rb_mProfiler, "total_time", gc_profile_total_time, 0);
-
- {
- VALUE opts;
- /* \GC build options */
- rb_define_const(rb_mGC, "OPTS", opts = rb_ary_new());
-#define OPT(o) if (o) rb_ary_push(opts, rb_interned_str(#o, sizeof(#o) - 1))
- OPT(GC_DEBUG);
- OPT(USE_RGENGC);
- OPT(RGENGC_DEBUG);
- OPT(RGENGC_CHECK_MODE);
- OPT(RGENGC_PROFILE);
- OPT(RGENGC_ESTIMATE_OLDMALLOC);
- OPT(GC_PROFILE_MORE_DETAIL);
- OPT(GC_ENABLE_LAZY_SWEEP);
- OPT(CALC_EXACT_MALLOC_SIZE);
- OPT(MALLOC_ALLOCATED_SIZE);
- OPT(MALLOC_ALLOCATED_SIZE_CHECK);
- OPT(GC_PROFILE_DETAIL_MEMORY);
- OPT(GC_COMPACTION_SUPPORTED);
-#undef OPT
- OBJ_FREEZE(opts);
- }
-}
diff --git a/gc/gc.h b/gc/gc.h
deleted file mode 100644
index b4da013c1a..0000000000
--- a/gc/gc.h
+++ /dev/null
@@ -1,185 +0,0 @@
-#ifndef GC_GC_H
-#define GC_GC_H
-/**
- * @author Ruby developers <ruby-core@ruby-lang.org>
- * @copyright This file is a part of the programming language Ruby.
- * Permission is hereby granted, to either redistribute and/or
- * modify this file, provided that the conditions mentioned in the
- * file COPYING are met. Consult the file for details.
- * @brief Private header for the default GC and other GC implementations
- * first introduced for [Feature #20470].
- */
-#include "ruby/ruby.h"
-
-RUBY_SYMBOL_EXPORT_BEGIN
-unsigned int rb_gc_vm_lock(void);
-void rb_gc_vm_unlock(unsigned int lev);
-unsigned int rb_gc_cr_lock(void);
-void rb_gc_cr_unlock(unsigned int lev);
-unsigned int rb_gc_vm_lock_no_barrier(void);
-void rb_gc_vm_unlock_no_barrier(unsigned int lev);
-void rb_gc_vm_barrier(void);
-size_t rb_gc_obj_optimal_size(VALUE obj);
-void rb_gc_mark_children(void *objspace, VALUE obj);
-void rb_gc_update_object_references(void *objspace, VALUE obj);
-void rb_gc_update_vm_references(void *objspace);
-void rb_gc_event_hook(VALUE obj, rb_event_flag_t event);
-void *rb_gc_get_objspace(void);
-size_t rb_size_mul_or_raise(size_t x, size_t y, VALUE exc);
-void rb_gc_run_obj_finalizer(VALUE objid, long count, VALUE (*callback)(long i, void *data), void *data);
-void rb_gc_set_pending_interrupt(void);
-void rb_gc_unset_pending_interrupt(void);
-bool rb_gc_obj_free(void *objspace, VALUE obj);
-void rb_gc_mark_roots(void *objspace, const char **categoryp);
-void rb_gc_ractor_newobj_cache_foreach(void (*func)(void *cache, void *data), void *data);
-bool rb_gc_multi_ractor_p(void);
-void rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *passing_data);
-void rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data);
-void rb_obj_info_dump(VALUE obj);
-const char *rb_obj_info(VALUE obj);
-bool rb_gc_shutdown_call_finalizer_p(VALUE obj);
-uint32_t rb_gc_get_shape(VALUE obj);
-void rb_gc_set_shape(VALUE obj, uint32_t shape_id);
-uint32_t rb_gc_rebuild_shape(VALUE obj, size_t heap_id);
-size_t rb_obj_memsize_of(VALUE obj);
-RUBY_SYMBOL_EXPORT_END
-
-void rb_ractor_finish_marking(void);
-
-// -------------------Private section begin------------------------
-// Functions in this section are private to the default GC and gc.c
-
-/* RGENGC_CHECK_MODE
- * 0: disable all assertions
- * 1: enable assertions (to debug RGenGC)
- * 2: enable internal consistency check at each GC (for debugging)
- * 3: enable internal consistency check at each GC steps (for debugging)
- * 4: enable liveness check
- * 5: show all references
- */
-#ifndef RGENGC_CHECK_MODE
-# define RGENGC_CHECK_MODE 0
-#endif
-
-#ifndef GC_ASSERT
-# define GC_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(RGENGC_CHECK_MODE > 0, expr, #expr)
-#endif
-
-static int
-hash_foreach_replace_value(st_data_t key, st_data_t value, st_data_t argp, int error)
-{
- if (rb_gc_location((VALUE)value) != (VALUE)value) {
- return ST_REPLACE;
- }
- return ST_CONTINUE;
-}
-
-static int
-hash_replace_ref_value(st_data_t *key, st_data_t *value, st_data_t argp, int existing)
-{
- *value = rb_gc_location((VALUE)*value);
-
- return ST_CONTINUE;
-}
-
-static void
-gc_ref_update_table_values_only(st_table *tbl)
-{
- if (!tbl || tbl->num_entries == 0) return;
-
- if (st_foreach_with_replace(tbl, hash_foreach_replace_value, hash_replace_ref_value, 0)) {
- rb_raise(rb_eRuntimeError, "hash modified during iteration");
- }
-}
-
-static int
-gc_mark_tbl_no_pin_i(st_data_t key, st_data_t value, st_data_t data)
-{
- rb_gc_mark_movable((VALUE)value);
-
- return ST_CONTINUE;
-}
-
-static int
-hash_foreach_replace(st_data_t key, st_data_t value, st_data_t argp, int error)
-{
- if (rb_gc_location((VALUE)key) != (VALUE)key) {
- return ST_REPLACE;
- }
-
- if (rb_gc_location((VALUE)value) != (VALUE)value) {
- return ST_REPLACE;
- }
-
- return ST_CONTINUE;
-}
-
-static int
-hash_replace_ref(st_data_t *key, st_data_t *value, st_data_t argp, int existing)
-{
- if (rb_gc_location((VALUE)*key) != (VALUE)*key) {
- *key = rb_gc_location((VALUE)*key);
- }
-
- if (rb_gc_location((VALUE)*value) != (VALUE)*value) {
- *value = rb_gc_location((VALUE)*value);
- }
-
- return ST_CONTINUE;
-}
-
-static void
-gc_update_table_refs(st_table *tbl)
-{
- if (!tbl || tbl->num_entries == 0) return;
-
- if (st_foreach_with_replace(tbl, hash_foreach_replace, hash_replace_ref, 0)) {
- rb_raise(rb_eRuntimeError, "hash modified during iteration");
- }
-}
-
-static inline size_t
-xmalloc2_size(const size_t count, const size_t elsize)
-{
- return rb_size_mul_or_raise(count, elsize, rb_eArgError);
-}
-
-static VALUE
-type_sym(size_t type)
-{
- switch (type) {
-#define COUNT_TYPE(t) case (t): return ID2SYM(rb_intern(#t)); break;
- COUNT_TYPE(T_NONE);
- COUNT_TYPE(T_OBJECT);
- COUNT_TYPE(T_CLASS);
- COUNT_TYPE(T_MODULE);
- COUNT_TYPE(T_FLOAT);
- COUNT_TYPE(T_STRING);
- COUNT_TYPE(T_REGEXP);
- COUNT_TYPE(T_ARRAY);
- COUNT_TYPE(T_HASH);
- COUNT_TYPE(T_STRUCT);
- COUNT_TYPE(T_BIGNUM);
- COUNT_TYPE(T_FILE);
- COUNT_TYPE(T_DATA);
- COUNT_TYPE(T_MATCH);
- COUNT_TYPE(T_COMPLEX);
- COUNT_TYPE(T_RATIONAL);
- COUNT_TYPE(T_NIL);
- COUNT_TYPE(T_TRUE);
- COUNT_TYPE(T_FALSE);
- COUNT_TYPE(T_SYMBOL);
- COUNT_TYPE(T_FIXNUM);
- COUNT_TYPE(T_IMEMO);
- COUNT_TYPE(T_UNDEF);
- COUNT_TYPE(T_NODE);
- COUNT_TYPE(T_ICLASS);
- COUNT_TYPE(T_ZOMBIE);
- COUNT_TYPE(T_MOVED);
-#undef COUNT_TYPE
- default: return SIZET2NUM(type); break;
- }
-}
-// -------------------Private section end------------------------
-
-#endif
diff --git a/gc/gc_impl.h b/gc/gc_impl.h
deleted file mode 100644
index 045fce6c66..0000000000
--- a/gc/gc_impl.h
+++ /dev/null
@@ -1,103 +0,0 @@
-#ifndef GC_GC_IMPL_H
-#define GC_GC_IMPL_H
-/**
- * @author Ruby developers <ruby-core@ruby-lang.org>
- * @copyright This file is a part of the programming language Ruby.
- * Permission is hereby granted, to either redistribute and/or
- * modify this file, provided that the conditions mentioned in the
- * file COPYING are met. Consult the file for details.
- * @brief Header for GC implementations introduced in [Feature #20470].
- */
-#include "ruby/ruby.h"
-
-// `GC_IMPL_FN` is an implementation detail of `!USE_SHARED_GC` builds
-// to have the default GC in the same translation unit as gc.c for
-// the sake of optimizer visibility. It expands to nothing unless
-// you're the default GC.
-//
-// For the default GC, do not copy-paste this when implementing
-// these functions. This takes advantage of internal linkage winning
-// when appearing first. See C99 6.2.2p4.
-#ifdef RB_AMALGAMATED_DEFAULT_GC
-# define GC_IMPL_FN static
-#else
-# define GC_IMPL_FN
-#endif
-
-// Bootup
-GC_IMPL_FN void *rb_gc_impl_objspace_alloc(void);
-GC_IMPL_FN void rb_gc_impl_objspace_init(void *objspace_ptr);
-GC_IMPL_FN void rb_gc_impl_objspace_free(void *objspace_ptr);
-GC_IMPL_FN void *rb_gc_impl_ractor_cache_alloc(void *objspace_ptr);
-GC_IMPL_FN void rb_gc_impl_ractor_cache_free(void *objspace_ptr, void *cache);
-GC_IMPL_FN void rb_gc_impl_set_params(void *objspace_ptr);
-GC_IMPL_FN void rb_gc_impl_init(void);
-GC_IMPL_FN size_t *rb_gc_impl_heap_sizes(void *objspace_ptr);
-// Shutdown
-GC_IMPL_FN void rb_gc_impl_shutdown_free_objects(void *objspace_ptr);
-// GC
-GC_IMPL_FN void rb_gc_impl_start(void *objspace_ptr, bool full_mark, bool immediate_mark, bool immediate_sweep, bool compact);
-GC_IMPL_FN bool rb_gc_impl_during_gc_p(void *objspace_ptr);
-GC_IMPL_FN void rb_gc_impl_prepare_heap(void *objspace_ptr);
-GC_IMPL_FN void rb_gc_impl_gc_enable(void *objspace_ptr);
-GC_IMPL_FN void rb_gc_impl_gc_disable(void *objspace_ptr, bool finish_current_gc);
-GC_IMPL_FN bool rb_gc_impl_gc_enabled_p(void *objspace_ptr);
-GC_IMPL_FN void rb_gc_impl_stress_set(void *objspace_ptr, VALUE flag);
-GC_IMPL_FN VALUE rb_gc_impl_stress_get(void *objspace_ptr);
-GC_IMPL_FN VALUE rb_gc_impl_config_get(void *objspace_ptr);
-GC_IMPL_FN VALUE rb_gc_impl_config_set(void *objspace_ptr, VALUE hash);
-// Object allocation
-GC_IMPL_FN VALUE rb_gc_impl_new_obj(void *objspace_ptr, void *cache_ptr, VALUE klass, VALUE flags, VALUE v1, VALUE v2, VALUE v3, bool wb_protected, size_t alloc_size);
-GC_IMPL_FN size_t rb_gc_impl_obj_slot_size(VALUE obj);
-GC_IMPL_FN size_t rb_gc_impl_heap_id_for_size(void *objspace_ptr, size_t size);
-GC_IMPL_FN bool rb_gc_impl_size_allocatable_p(size_t size);
-// Malloc
-GC_IMPL_FN void *rb_gc_impl_malloc(void *objspace_ptr, size_t size);
-GC_IMPL_FN void *rb_gc_impl_calloc(void *objspace_ptr, size_t size);
-GC_IMPL_FN void *rb_gc_impl_realloc(void *objspace_ptr, void *ptr, size_t new_size, size_t old_size);
-GC_IMPL_FN void rb_gc_impl_free(void *objspace_ptr, void *ptr, size_t old_size);
-GC_IMPL_FN void rb_gc_impl_adjust_memory_usage(void *objspace_ptr, ssize_t diff);
-// Marking
-GC_IMPL_FN void rb_gc_impl_mark(void *objspace_ptr, VALUE obj);
-GC_IMPL_FN void rb_gc_impl_mark_and_move(void *objspace_ptr, VALUE *ptr);
-GC_IMPL_FN void rb_gc_impl_mark_and_pin(void *objspace_ptr, VALUE obj);
-GC_IMPL_FN void rb_gc_impl_mark_maybe(void *objspace_ptr, VALUE obj);
-GC_IMPL_FN void rb_gc_impl_mark_weak(void *objspace_ptr, VALUE *ptr);
-GC_IMPL_FN void rb_gc_impl_remove_weak(void *objspace_ptr, VALUE parent_obj, VALUE *ptr);
-// Compaction
-GC_IMPL_FN bool rb_gc_impl_object_moved_p(void *objspace_ptr, VALUE obj);
-GC_IMPL_FN VALUE rb_gc_impl_location(void *objspace_ptr, VALUE value);
-// Write barriers
-GC_IMPL_FN void rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b);
-GC_IMPL_FN void rb_gc_impl_writebarrier_unprotect(void *objspace_ptr, VALUE obj);
-GC_IMPL_FN void rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj);
-// Heap walking
-GC_IMPL_FN void rb_gc_impl_each_objects(void *objspace_ptr, int (*callback)(void *, void *, size_t, void *), void *data);
-GC_IMPL_FN void rb_gc_impl_each_object(void *objspace_ptr, void (*func)(VALUE obj, void *data), void *data);
-// Finalizers
-GC_IMPL_FN void rb_gc_impl_make_zombie(void *objspace_ptr, VALUE obj, void (*dfree)(void *), void *data);
-GC_IMPL_FN VALUE rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block);
-GC_IMPL_FN void rb_gc_impl_undefine_finalizer(void *objspace_ptr, VALUE obj);
-GC_IMPL_FN void rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj);
-GC_IMPL_FN void rb_gc_impl_shutdown_call_finalizer(void *objspace_ptr);
-// Object ID
-GC_IMPL_FN VALUE rb_gc_impl_object_id(void *objspace_ptr, VALUE obj);
-GC_IMPL_FN VALUE rb_gc_impl_object_id_to_ref(void *objspace_ptr, VALUE object_id);
-// Statistics
-GC_IMPL_FN void rb_gc_impl_set_measure_total_time(void *objspace_ptr, VALUE flag);
-GC_IMPL_FN bool rb_gc_impl_get_measure_total_time(void *objspace_ptr);
-GC_IMPL_FN unsigned long long rb_gc_impl_get_total_time(void *objspace_ptr);
-GC_IMPL_FN size_t rb_gc_impl_gc_count(void *objspace_ptr);
-GC_IMPL_FN VALUE rb_gc_impl_latest_gc_info(void *objspace_ptr, VALUE key);
-GC_IMPL_FN size_t rb_gc_impl_stat(void *objspace_ptr, VALUE hash_or_sym);
-GC_IMPL_FN size_t rb_gc_impl_stat_heap(void *objspace_ptr, VALUE heap_name, VALUE hash_or_sym);
-// Miscellaneous
-GC_IMPL_FN size_t rb_gc_impl_obj_flags(void *objspace_ptr, VALUE obj, ID* flags, size_t max);
-GC_IMPL_FN bool rb_gc_impl_pointer_to_heap_p(void *objspace_ptr, const void *ptr);
-GC_IMPL_FN bool rb_gc_impl_garbage_object_p(void *objspace_ptr, VALUE obj);
-GC_IMPL_FN void rb_gc_impl_set_event_hook(void *objspace_ptr, const rb_event_flag_t event);
-GC_IMPL_FN void rb_gc_impl_copy_attributes(void *objspace_ptr, VALUE dest, VALUE obj);
-
-#undef GC_IMPL_FN
-
-#endif
diff --git a/gem_prelude.rb b/gem_prelude.rb
index bcd2560fab..f382021ca3 100644
--- a/gem_prelude.rb
+++ b/gem_prelude.rb
@@ -4,8 +4,6 @@ rescue LoadError => e
raise unless e.path == 'rubygems'
warn "`RubyGems' were not loaded."
-else
- require 'bundled_gems'
end if defined?(Gem)
begin
diff --git a/gems/bundled_gems b/gems/bundled_gems
index 0e88f06f21..d37d869d41 100644
--- a/gems/bundled_gems
+++ b/gems/bundled_gems
@@ -1,37 +1,16 @@
-# gem-name version repository-url [revision]
-#
-# - gem-name: gem name to bundle
-# - version: released version to bundle
-# - repository-url: URL from where clone for test
-# - revision: revision in repository-url to test
-# if `revision` is not given, "v"+`version` or `version` will be used.
-
-minitest 5.25.1 https://github.com/minitest/minitest
-power_assert 2.0.4 https://github.com/ruby/power_assert
-rake 13.2.1 https://github.com/ruby/rake
-test-unit 3.6.2 https://github.com/test-unit/test-unit
-rexml 3.3.8 https://github.com/ruby/rexml
-rss 0.3.1 https://github.com/ruby/rss
-net-ftp 0.3.8 https://github.com/ruby/net-ftp
-net-imap 0.4.16 https://github.com/ruby/net-imap
-net-pop 0.1.2 https://github.com/ruby/net-pop
-net-smtp 0.5.0 https://github.com/ruby/net-smtp
-matrix 0.4.2 https://github.com/ruby/matrix
-prime 0.1.2 https://github.com/ruby/prime
-rbs 3.6.1 https://github.com/ruby/rbs
-typeprof 0.21.11 https://github.com/ruby/typeprof 167263ca3a634b61df0445f1a6b3e259a5d47f94
-debug 1.9.2 https://github.com/ruby/debug 9c4279598e9e0376657b3813bf76a206f1f97beb
-racc 1.8.1 https://github.com/ruby/racc
-mutex_m 0.2.0 https://github.com/ruby/mutex_m
-getoptlong 0.2.1 https://github.com/ruby/getoptlong
-base64 0.2.0 https://github.com/ruby/base64
-bigdecimal 3.1.8 https://github.com/ruby/bigdecimal
-observer 0.1.2 https://github.com/ruby/observer
-abbrev 0.1.2 https://github.com/ruby/abbrev
-resolv-replace 0.1.1 https://github.com/ruby/resolv-replace
-rinda 0.2.0 https://github.com/ruby/rinda
-drb 2.2.1 https://github.com/ruby/drb
-nkf 0.2.0 https://github.com/ruby/nkf
-syslog 0.1.2 https://github.com/ruby/syslog
-csv 3.3.0 https://github.com/ruby/csv
-repl_type_completor 0.1.7 https://github.com/ruby/repl_type_completor
+# gem-name version-to-bundle repository-url [optional-commit-hash-to-test-or-defaults-to-v-version]
+minitest 5.25.1 https://github.com/seattlerb/minitest
+power_assert 2.0.3 https://github.com/ruby/power_assert
+rake 13.0.6 https://github.com/ruby/rake
+test-unit 3.5.7 https://github.com/test-unit/test-unit
+rexml 3.3.9 https://github.com/ruby/rexml
+rss 0.3.1 https://github.com/ruby/rss
+net-ftp 0.2.1 https://github.com/ruby/net-ftp
+net-imap 0.3.9 https://github.com/ruby/net-imap
+net-pop 0.1.2 https://github.com/ruby/net-pop
+net-smtp 0.3.4 https://github.com/ruby/net-smtp
+matrix 0.4.2 https://github.com/ruby/matrix
+prime 0.1.2 https://github.com/ruby/prime
+rbs 2.8.2 https://github.com/ruby/rbs
+typeprof 0.21.3 https://github.com/ruby/typeprof
+debug 1.7.1 https://github.com/ruby/debug
diff --git a/goruby.c b/goruby.c
index 3ca96bfda0..5d45277207 100644
--- a/goruby.c
+++ b/goruby.c
@@ -1,4 +1,4 @@
-static void Init_golf_prelude(void);
+static void Init_golf(void);
static void *goruby_options(int argc, char **argv);
static int goruby_run_node(void *arg);
#define ruby_options goruby_options
@@ -17,13 +17,14 @@ static int goruby_run_node(void *arg);
RUBY_EXTERN void *ruby_options(int argc, char **argv);
RUBY_EXTERN int ruby_run_node(void*);
+RUBY_EXTERN void ruby_init_ext(const char *name, void (*init)(void));
-#include "golf_prelude.rbbin"
+#include "golf_prelude.c"
static VALUE
init_golf(VALUE arg)
{
- Init_golf_prelude();
+ Init_golf();
rb_provide("golf.so");
return arg;
}
@@ -60,8 +61,7 @@ int
goruby_run_node(void *arg)
{
int state;
- if (ruby_executable_node(arg, NULL) &&
- NIL_P(rb_protect(init_golf, Qtrue, &state))) {
+ if (NIL_P(rb_protect(init_golf, Qtrue, &state))) {
return state == EXIT_SUCCESS ? EXIT_FAILURE : state;
}
return ruby_run_node(arg);
diff --git a/hash.c b/hash.c
index d48c763cd2..d2dce30624 100644
--- a/hash.c
+++ b/hash.c
@@ -35,7 +35,6 @@
#include "internal/hash.h"
#include "internal/object.h"
#include "internal/proc.h"
-#include "internal/st.h"
#include "internal/symbol.h"
#include "internal/thread.h"
#include "internal/time.h"
@@ -45,34 +44,17 @@
#include "ruby/util.h"
#include "ruby_assert.h"
#include "symbol.h"
+#include "transient_heap.h"
#include "ruby/thread_native.h"
#include "ruby/ractor.h"
#include "vm_sync.h"
-#include "builtin.h"
-
-/* Flags of RHash
- *
- * 1: RHASH_PASS_AS_KEYWORDS
- * The hash is flagged as Ruby 2 keywords hash.
- * 2: RHASH_PROC_DEFAULT
- * The hash has a default proc (rather than a default value).
- * 3: RHASH_ST_TABLE_FLAG
- * The hash uses a ST table (rather than an AR table).
- * 4-7: RHASH_AR_TABLE_SIZE_MASK
- * The size of the AR table.
- * 8-11: RHASH_AR_TABLE_BOUND_MASK
- * The bounds of the AR table.
- * 13-19: RHASH_LEV_MASK
- * The iterational level of the hash. Used to prevent modifications
- * to the hash during iteration.
- */
#ifndef HASH_DEBUG
#define HASH_DEBUG 0
#endif
#if HASH_DEBUG
-#include "internal/gc.h"
+#include "gc.h"
#endif
#define SET_DEFAULT(hash, ifnone) ( \
@@ -103,7 +85,6 @@ static VALUE rb_hash_s_try_convert(VALUE, VALUE);
* 2. Insert WBs
*/
-/* :nodoc: */
VALUE
rb_hash_freeze(VALUE hash)
{
@@ -111,7 +92,6 @@ rb_hash_freeze(VALUE hash)
}
VALUE rb_cHash;
-VALUE rb_cHash_empty_frozen;
static VALUE envtbl;
static ID id_hash, id_flatten_bang;
@@ -126,7 +106,7 @@ rb_hash_set_ifnone(VALUE hash, VALUE ifnone)
return hash;
}
-int
+static int
rb_any_cmp(VALUE a, VALUE b)
{
if (a == b) return 0;
@@ -213,26 +193,10 @@ any_hash(VALUE a, st_index_t (*other_func)(VALUE))
return (long)hnum;
}
-VALUE rb_obj_hash(VALUE obj);
-VALUE rb_vm_call0(rb_execution_context_t *ec, VALUE recv, ID id, int argc, const VALUE *argv, const rb_callable_method_entry_t *cme, int kw_splat);
-
static st_index_t
obj_any_hash(VALUE obj)
{
- VALUE hval = Qundef;
- VALUE klass = CLASS_OF(obj);
- if (klass) {
- const rb_callable_method_entry_t *cme = rb_callable_method_entry(klass, id_hash);
- if (cme && METHOD_ENTRY_BASIC(cme)) {
- // Optimize away the frame push overhead if it's the default Kernel#hash
- if (cme->def->type == VM_METHOD_TYPE_CFUNC && cme->def->body.cfunc.func == (rb_cfunc_t)rb_obj_hash) {
- hval = rb_obj_hash(obj);
- }
- else if (RBASIC_CLASS(cme->defined_class) == rb_mKernel) {
- hval = rb_vm_call0(GET_EC(), obj, id_hash, 0, 0, cme, 0);
- }
- }
- }
+ VALUE hval = rb_check_funcall_basic_kw(obj, id_hash, rb_mKernel, 0, 0, 0);
if (UNDEF_P(hval)) {
hval = rb_exec_recursive_outer_mid(hash_recursive, obj, 0, id_hash);
@@ -404,10 +368,12 @@ typedef st_index_t st_hash_t;
/*
* RHASH_AR_TABLE_P(h):
- * RHASH_AR_TABLE points to ar_table.
+ * * as.ar == NULL or
+ * as.ar points ar_table.
+ * * as.ar is allocated by transient heap or xmalloc.
*
* !RHASH_AR_TABLE_P(h):
- * RHASH_ST_TABLE points st_table.
+ * * as.st points st_table.
*/
#define RHASH_AR_TABLE_MAX_BOUND RHASH_AR_TABLE_MAX_SIZE
@@ -415,6 +381,22 @@ typedef st_index_t st_hash_t;
#define RHASH_AR_TABLE_REF(hash, n) (&RHASH_AR_TABLE(hash)->pairs[n])
#define RHASH_AR_CLEARED_HINT 0xff
+typedef struct ar_table_pair_struct {
+ VALUE key;
+ VALUE val;
+} ar_table_pair;
+
+typedef struct ar_table_struct {
+ /* 64bit CPU: 8B * 2 * 8 = 128B */
+ ar_table_pair pairs[RHASH_AR_TABLE_MAX_SIZE];
+} ar_table;
+
+size_t
+rb_hash_ar_table_size(void)
+{
+ return sizeof(ar_table);
+}
+
static inline st_hash_t
ar_do_hash(st_data_t key)
{
@@ -430,13 +412,13 @@ ar_do_hash_hint(st_hash_t hash_value)
static inline ar_hint_t
ar_hint(VALUE hash, unsigned int index)
{
- return RHASH_AR_TABLE(hash)->ar_hint.ary[index];
+ return RHASH(hash)->ar_hint.ary[index];
}
static inline void
ar_hint_set_hint(VALUE hash, unsigned int index, ar_hint_t hint)
{
- RHASH_AR_TABLE(hash)->ar_hint.ary[index] = hint;
+ RHASH(hash)->ar_hint.ary[index] = hint;
}
static inline void
@@ -484,20 +466,14 @@ ar_set_entry(VALUE hash, unsigned int index, st_data_t key, st_data_t val, st_ha
((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \
(RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT)))
+#define RHASH_AR_TABLE_BOUND(h) (HASH_ASSERT(RHASH_AR_TABLE_P(h)), \
+ RHASH_AR_TABLE_BOUND_RAW(h))
+
#define RHASH_ST_TABLE_SET(h, s) rb_hash_st_table_set(h, s)
#define RHASH_TYPE(hash) (RHASH_AR_TABLE_P(hash) ? &objhash : RHASH_ST_TABLE(hash)->type)
#define HASH_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(HASH_DEBUG, expr, #expr)
-static inline unsigned int
-RHASH_AR_TABLE_BOUND(VALUE h)
-{
- HASH_ASSERT(RHASH_AR_TABLE_P(h));
- const unsigned int bound = RHASH_AR_TABLE_BOUND_RAW(h);
- HASH_ASSERT(bound <= RHASH_AR_TABLE_MAX_SIZE);
- return bound;
-}
-
#if HASH_DEBUG
#define hash_verify(hash) hash_verify_(hash, __FILE__, __LINE__)
@@ -507,10 +483,10 @@ rb_hash_dump(VALUE hash)
rb_obj_info_dump(hash);
if (RHASH_AR_TABLE_P(hash)) {
- unsigned i, bound = RHASH_AR_TABLE_BOUND(hash);
+ unsigned i, n = 0, bound = RHASH_AR_TABLE_BOUND(hash);
fprintf(stderr, " size:%u bound:%u\n",
- RHASH_AR_TABLE_SIZE(hash), bound);
+ RHASH_AR_TABLE_SIZE(hash), RHASH_AR_TABLE_BOUND(hash));
for (i=0; i<bound; i++) {
st_data_t k, v;
@@ -524,6 +500,7 @@ rb_hash_dump(VALUE hash)
rb_raw_obj_info(b1, 0x100, k),
rb_raw_obj_info(b2, 0x100, v),
ar_hint(hash, i));
+ n++;
}
else {
fprintf(stderr, " %d empty\n", i);
@@ -561,6 +538,13 @@ hash_verify_(VALUE hash, const char *file, int line)
HASH_ASSERT(RHASH_AR_TABLE_BOUND_RAW(hash) == 0);
}
+#if USE_TRANSIENT_HEAP
+ if (RHASH_TRANSIENT_P(hash)) {
+ volatile st_data_t MAYBE_UNUSED(key) = RHASH_AR_TABLE_REF(hash, 0)->key; /* read */
+ HASH_ASSERT(RHASH_AR_TABLE(hash) != NULL);
+ HASH_ASSERT(rb_transient_heap_managed_ptr_p(RHASH_AR_TABLE(hash)));
+ }
+#endif
return hash;
}
@@ -569,30 +553,69 @@ hash_verify_(VALUE hash, const char *file, int line)
#endif
static inline int
+RHASH_TABLE_NULL_P(VALUE hash)
+{
+ if (RHASH(hash)->as.ar == NULL) {
+ HASH_ASSERT(RHASH_AR_TABLE_P(hash));
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+static inline int
RHASH_TABLE_EMPTY_P(VALUE hash)
{
return RHASH_SIZE(hash) == 0;
}
-#define RHASH_SET_ST_FLAG(h) FL_SET_RAW(h, RHASH_ST_TABLE_FLAG)
-#define RHASH_UNSET_ST_FLAG(h) FL_UNSET_RAW(h, RHASH_ST_TABLE_FLAG)
+int
+rb_hash_ar_table_p(VALUE hash)
+{
+ if (FL_TEST_RAW((hash), RHASH_ST_TABLE_FLAG)) {
+ HASH_ASSERT(RHASH(hash)->as.st != NULL);
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+}
-static void
-hash_st_table_init(VALUE hash, const struct st_hash_type *type, st_index_t size)
+ar_table *
+rb_hash_ar_table(VALUE hash)
+{
+ HASH_ASSERT(RHASH_AR_TABLE_P(hash));
+ return RHASH(hash)->as.ar;
+}
+
+st_table *
+rb_hash_st_table(VALUE hash)
{
- st_init_existing_table_with_size(RHASH_ST_TABLE(hash), type, size);
- RHASH_SET_ST_FLAG(hash);
+ HASH_ASSERT(!RHASH_AR_TABLE_P(hash));
+ return RHASH(hash)->as.st;
}
void
rb_hash_st_table_set(VALUE hash, st_table *st)
{
HASH_ASSERT(st != NULL);
- RHASH_SET_ST_FLAG(hash);
+ FL_SET_RAW((hash), RHASH_ST_TABLE_FLAG);
+ RHASH(hash)->as.st = st;
+}
- *RHASH_ST_TABLE(hash) = *st;
+static void
+hash_ar_table_set(VALUE hash, ar_table *ar)
+{
+ HASH_ASSERT(RHASH_AR_TABLE_P(hash));
+ HASH_ASSERT((RHASH_TRANSIENT_P(hash) && ar == NULL) ? FALSE : TRUE);
+ RHASH(hash)->as.ar = ar;
+ hash_verify(hash);
}
+#define RHASH_SET_ST_FLAG(h) FL_SET_RAW(h, RHASH_ST_TABLE_FLAG)
+#define RHASH_UNSET_ST_FLAG(h) FL_UNSET_RAW(h, RHASH_ST_TABLE_FLAG)
+
static inline void
RHASH_AR_TABLE_BOUND_SET(VALUE h, st_index_t n)
{
@@ -647,7 +670,27 @@ RHASH_AR_TABLE_CLEAR(VALUE h)
RBASIC(h)->flags &= ~RHASH_AR_TABLE_SIZE_MASK;
RBASIC(h)->flags &= ~RHASH_AR_TABLE_BOUND_MASK;
- memset(RHASH_AR_TABLE(h), 0, sizeof(ar_table));
+ hash_ar_table_set(h, NULL);
+}
+
+static ar_table*
+ar_alloc_table(VALUE hash)
+{
+ ar_table *tab = (ar_table*)rb_transient_heap_alloc(hash, sizeof(ar_table));
+
+ if (tab != NULL) {
+ RHASH_SET_TRANSIENT_FLAG(hash);
+ }
+ else {
+ RHASH_UNSET_TRANSIENT_FLAG(hash);
+ tab = (ar_table*)ruby_xmalloc(sizeof(ar_table));
+ }
+
+ RHASH_AR_TABLE_SIZE_SET(hash, 0);
+ RHASH_AR_TABLE_BOUND_SET(hash, 0);
+ hash_ar_table_set(hash, tab);
+
+ return tab;
}
NOINLINE(static int ar_equal(VALUE x, VALUE y));
@@ -662,7 +705,7 @@ static unsigned
ar_find_entry_hint(VALUE hash, ar_hint_t hint, st_data_t key)
{
unsigned i, bound = RHASH_AR_TABLE_BOUND(hash);
- const ar_hint_t *hints = RHASH_AR_TABLE(hash)->ar_hint.ary;
+ const ar_hint_t *hints = RHASH(hash)->ar_hint.ary;
/* if table is NULL, then bound also should be 0 */
@@ -709,12 +752,22 @@ ar_find_entry(VALUE hash, st_hash_t hash_value, st_data_t key)
}
static inline void
-hash_ar_free_and_clear_table(VALUE hash)
+ar_free_and_clear_table(VALUE hash)
{
- RHASH_AR_TABLE_CLEAR(hash);
+ ar_table *tab = RHASH_AR_TABLE(hash);
+ if (tab) {
+ if (RHASH_TRANSIENT_P(hash)) {
+ RHASH_UNSET_TRANSIENT_FLAG(hash);
+ }
+ else {
+ ruby_xfree(RHASH_AR_TABLE(hash));
+ }
+ RHASH_AR_TABLE_CLEAR(hash);
+ }
HASH_ASSERT(RHASH_AR_TABLE_SIZE(hash) == 0);
HASH_ASSERT(RHASH_AR_TABLE_BOUND(hash) == 0);
+ HASH_ASSERT(RHASH_TRANSIENT_P(hash) == 0);
}
void rb_st_add_direct_with_hash(st_table *tab, st_data_t key, st_data_t value, st_hash_t hash); // st.c
@@ -748,13 +801,18 @@ ar_each_key(ar_table *ar, int max, enum ar_each_key_type type, st_data_t *dst_ke
return 0;
}
+
+
static st_table *
ar_force_convert_table(VALUE hash, const char *file, int line)
{
+ st_table *new_tab;
+
if (RHASH_ST_TABLE_P(hash)) {
return RHASH_ST_TABLE(hash);
}
- else {
+
+ if (RHASH_AR_TABLE(hash)) {
ar_table *ar = RHASH_AR_TABLE(hash);
st_hash_t hashes[RHASH_AR_TABLE_MAX_SIZE];
unsigned int bound, size;
@@ -777,15 +835,27 @@ ar_force_convert_table(VALUE hash, const char *file, int line)
if (UNLIKELY(ar_each_key(ar, bound, ar_each_key_cmp, keys, NULL, NULL))) continue;
} while (0);
+
// make st
- st_table tab;
- st_table *new_tab = &tab;
- st_init_existing_table_with_size(new_tab, &objhash, size);
+ new_tab = st_init_table_with_size(&objhash, size);
ar_each_key(ar, bound, ar_each_key_insert, NULL, new_tab, hashes);
- hash_ar_free_and_clear_table(hash);
- RHASH_ST_TABLE_SET(hash, new_tab);
- return RHASH_ST_TABLE(hash);
+ ar_free_and_clear_table(hash);
+ }
+ else {
+ new_tab = st_init_table(&objhash);
+ }
+ RHASH_ST_TABLE_SET(hash, new_tab);
+
+ return new_tab;
+}
+
+static ar_table *
+hash_ar_table(VALUE hash)
+{
+ if (RHASH_TABLE_NULL_P(hash)) {
+ ar_alloc_table(hash);
}
+ return RHASH_AR_TABLE(hash);
}
static int
@@ -838,6 +908,7 @@ ar_add_direct_with_hash(VALUE hash, st_data_t key, st_data_t val, st_hash_t hash
else {
if (UNLIKELY(bin >= RHASH_AR_TABLE_MAX_BOUND)) {
bin = ar_compact_table(hash);
+ hash_ar_table(hash);
}
HASH_ASSERT(bin < RHASH_AR_TABLE_MAX_BOUND);
@@ -848,14 +919,6 @@ ar_add_direct_with_hash(VALUE hash, st_data_t key, st_data_t val, st_hash_t hash
}
}
-static void
-ensure_ar_table(VALUE hash)
-{
- if (!RHASH_AR_TABLE_P(hash)) {
- rb_raise(rb_eRuntimeError, "hash representation was changed during iteration");
- }
-}
-
static int
ar_general_foreach(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg)
{
@@ -866,10 +929,7 @@ ar_general_foreach(VALUE hash, st_foreach_check_callback_func *func, st_update_c
if (ar_cleared_entry(hash, i)) continue;
ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i);
- st_data_t key = (st_data_t)pair->key;
- st_data_t val = (st_data_t)pair->val;
- enum st_retval retval = (*func)(key, val, arg, 0);
- ensure_ar_table(hash);
+ enum st_retval retval = (*func)(pair->key, pair->val, arg, 0);
/* pair may be not valid here because of theap */
switch (retval) {
@@ -880,12 +940,14 @@ ar_general_foreach(VALUE hash, st_foreach_check_callback_func *func, st_update_c
return 0;
case ST_REPLACE:
if (replace) {
+ VALUE key = pair->key;
+ VALUE val = pair->val;
retval = (*replace)(&key, &val, arg, TRUE);
// TODO: pair should be same as pair before.
- pair = RHASH_AR_TABLE_REF(hash, i);
- pair->key = (VALUE)key;
- pair->val = (VALUE)val;
+ ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i);
+ pair->key = key;
+ pair->val = val;
}
break;
case ST_DELETE:
@@ -942,7 +1004,6 @@ ar_foreach_check(VALUE hash, st_foreach_check_callback_func *func, st_data_t arg
hint = ar_hint(hash, i);
retval = (*func)(key, pair->val, arg, 0);
- ensure_ar_table(hash);
hash_verify(hash);
switch (retval) {
@@ -992,6 +1053,7 @@ ar_update(VALUE hash, st_data_t key,
existing = (bin != RHASH_AR_TABLE_MAX_BOUND) ? TRUE : FALSE;
}
else {
+ hash_ar_table(hash); /* allocate ltbl if needed */
existing = FALSE;
}
@@ -1003,7 +1065,6 @@ ar_update(VALUE hash, st_data_t key,
old_key = key;
retval = (*func)(&key, &value, arg, existing);
/* pair can be invalid here because of theap */
- ensure_ar_table(hash);
switch (retval) {
case ST_CONTINUE:
@@ -1041,6 +1102,8 @@ ar_insert(VALUE hash, st_data_t key, st_data_t value)
return -1;
}
+ hash_ar_table(hash); /* prepare ltbl */
+
bin = ar_find_entry(hash, hash_value, key);
if (bin == RHASH_AR_TABLE_MAX_BOUND) {
if (RHASH_AR_TABLE_SIZE(hash) >= RHASH_AR_TABLE_MAX_SIZE) {
@@ -1048,6 +1111,7 @@ ar_insert(VALUE hash, st_data_t key, st_data_t value)
}
else if (bin >= RHASH_AR_TABLE_MAX_BOUND) {
bin = ar_compact_table(hash);
+ hash_ar_table(hash);
}
HASH_ASSERT(bin < RHASH_AR_TABLE_MAX_BOUND);
@@ -1182,16 +1246,44 @@ static ar_table*
ar_copy(VALUE hash1, VALUE hash2)
{
ar_table *old_tab = RHASH_AR_TABLE(hash2);
- ar_table *new_tab = RHASH_AR_TABLE(hash1);
- *new_tab = *old_tab;
- RHASH_AR_TABLE(hash1)->ar_hint.word = RHASH_AR_TABLE(hash2)->ar_hint.word;
- RHASH_AR_TABLE_BOUND_SET(hash1, RHASH_AR_TABLE_BOUND(hash2));
- RHASH_AR_TABLE_SIZE_SET(hash1, RHASH_AR_TABLE_SIZE(hash2));
+ if (old_tab != NULL) {
+ ar_table *new_tab = RHASH_AR_TABLE(hash1);
+ if (new_tab == NULL) {
+ new_tab = (ar_table*) rb_transient_heap_alloc(hash1, sizeof(ar_table));
+ if (new_tab != NULL) {
+ RHASH_SET_TRANSIENT_FLAG(hash1);
+ }
+ else {
+ RHASH_UNSET_TRANSIENT_FLAG(hash1);
+ new_tab = (ar_table*)ruby_xmalloc(sizeof(ar_table));
+ }
+ }
+ *new_tab = *old_tab;
+ RHASH(hash1)->ar_hint.word = RHASH(hash2)->ar_hint.word;
+ RHASH_AR_TABLE_BOUND_SET(hash1, RHASH_AR_TABLE_BOUND(hash2));
+ RHASH_AR_TABLE_SIZE_SET(hash1, RHASH_AR_TABLE_SIZE(hash2));
+ hash_ar_table_set(hash1, new_tab);
- rb_gc_writebarrier_remember(hash1);
+ rb_gc_writebarrier_remember(hash1);
+ return new_tab;
+ }
+ else {
+ RHASH_AR_TABLE_BOUND_SET(hash1, RHASH_AR_TABLE_BOUND(hash2));
+ RHASH_AR_TABLE_SIZE_SET(hash1, RHASH_AR_TABLE_SIZE(hash2));
- return new_tab;
+ if (RHASH_TRANSIENT_P(hash1)) {
+ RHASH_UNSET_TRANSIENT_FLAG(hash1);
+ }
+ else if (RHASH_AR_TABLE(hash1)) {
+ ruby_xfree(RHASH_AR_TABLE(hash1));
+ }
+
+ hash_ar_table_set(hash1, NULL);
+
+ rb_gc_writebarrier_remember(hash1);
+ return old_tab;
+ }
}
static void
@@ -1207,32 +1299,32 @@ ar_clear(VALUE hash)
}
}
-static void
-hash_st_free(VALUE hash)
-{
- HASH_ASSERT(RHASH_ST_TABLE_P(hash));
-
- st_table *tab = RHASH_ST_TABLE(hash);
-
- xfree(tab->bins);
- xfree(tab->entries);
-}
-
-static void
-hash_st_free_and_clear_table(VALUE hash)
-{
- hash_st_free(hash);
-
- RHASH_ST_CLEAR(hash);
-}
-
+#if USE_TRANSIENT_HEAP
void
-rb_hash_free(VALUE hash)
+rb_hash_transient_heap_evacuate(VALUE hash, int promote)
{
- if (RHASH_ST_TABLE_P(hash)) {
- hash_st_free(hash);
+ if (RHASH_TRANSIENT_P(hash)) {
+ ar_table *new_tab;
+ ar_table *old_tab = RHASH_AR_TABLE(hash);
+
+ if (UNLIKELY(old_tab == NULL)) {
+ return;
+ }
+ HASH_ASSERT(old_tab != NULL);
+ if (! promote) {
+ new_tab = rb_transient_heap_alloc(hash, sizeof(ar_table));
+ if (new_tab == NULL) promote = true;
+ }
+ if (promote) {
+ new_tab = ruby_xmalloc(sizeof(ar_table));
+ RHASH_UNSET_TRANSIENT_FLAG(hash);
+ }
+ *new_tab = *old_tab;
+ hash_ar_table_set(hash, new_tab);
}
+ hash_verify(hash);
}
+#endif
typedef int st_foreach_func(st_data_t, st_data_t, st_data_t);
@@ -1322,79 +1414,85 @@ hash_foreach_iter(st_data_t key, st_data_t value, st_data_t argp, int error)
return hash_iter_status_check(status);
}
-static unsigned long
+static int
iter_lev_in_ivar(VALUE hash)
{
VALUE levval = rb_ivar_get(hash, id_hash_iter_lev);
HASH_ASSERT(FIXNUM_P(levval));
- long lev = FIX2LONG(levval);
- HASH_ASSERT(lev >= 0);
- return (unsigned long)lev;
+ return FIX2INT(levval);
}
void rb_ivar_set_internal(VALUE obj, ID id, VALUE val);
static void
-iter_lev_in_ivar_set(VALUE hash, unsigned long lev)
+iter_lev_in_ivar_set(VALUE hash, int lev)
{
- HASH_ASSERT(lev >= RHASH_LEV_MAX);
- HASH_ASSERT(POSFIXABLE(lev)); /* POSFIXABLE means fitting to long */
- rb_ivar_set_internal(hash, id_hash_iter_lev, LONG2FIX((long)lev));
+ rb_ivar_set_internal(hash, id_hash_iter_lev, INT2FIX(lev));
}
-static inline unsigned long
+static inline int
iter_lev_in_flags(VALUE hash)
{
- return (unsigned long)((RBASIC(hash)->flags >> RHASH_LEV_SHIFT) & RHASH_LEV_MAX);
+ unsigned int u = (unsigned int)((RBASIC(hash)->flags >> RHASH_LEV_SHIFT) & RHASH_LEV_MAX);
+ return (int)u;
}
static inline void
-iter_lev_in_flags_set(VALUE hash, unsigned long lev)
+iter_lev_in_flags_set(VALUE hash, int lev)
{
- HASH_ASSERT(lev <= RHASH_LEV_MAX);
RBASIC(hash)->flags = ((RBASIC(hash)->flags & ~RHASH_LEV_MASK) | ((VALUE)lev << RHASH_LEV_SHIFT));
}
-static inline bool
-hash_iterating_p(VALUE hash)
+static int
+RHASH_ITER_LEV(VALUE hash)
{
- return iter_lev_in_flags(hash) > 0;
+ int lev = iter_lev_in_flags(hash);
+
+ if (lev == RHASH_LEV_MAX) {
+ return iter_lev_in_ivar(hash);
+ }
+ else {
+ return lev;
+ }
}
static void
hash_iter_lev_inc(VALUE hash)
{
- unsigned long lev = iter_lev_in_flags(hash);
+ int lev = iter_lev_in_flags(hash);
if (lev == RHASH_LEV_MAX) {
- lev = iter_lev_in_ivar(hash) + 1;
- if (!POSFIXABLE(lev)) { /* paranoiac check */
- rb_raise(rb_eRuntimeError, "too much nested iterations");
- }
+ lev = iter_lev_in_ivar(hash);
+ iter_lev_in_ivar_set(hash, lev+1);
}
else {
lev += 1;
iter_lev_in_flags_set(hash, lev);
- if (lev < RHASH_LEV_MAX) return;
+ if (lev == RHASH_LEV_MAX) {
+ iter_lev_in_ivar_set(hash, lev);
+ }
}
- iter_lev_in_ivar_set(hash, lev);
}
static void
hash_iter_lev_dec(VALUE hash)
{
- unsigned long lev = iter_lev_in_flags(hash);
+ int lev = iter_lev_in_flags(hash);
if (lev == RHASH_LEV_MAX) {
lev = iter_lev_in_ivar(hash);
- if (lev > RHASH_LEV_MAX) {
- iter_lev_in_ivar_set(hash, lev-1);
- return;
- }
- rb_attr_delete(hash, id_hash_iter_lev);
+ HASH_ASSERT(lev > 0);
+ iter_lev_in_ivar_set(hash, lev-1);
}
- else if (lev == 0) {
- rb_raise(rb_eRuntimeError, "iteration level underflow");
+ else {
+ HASH_ASSERT(lev > 0);
+ iter_lev_in_flags_set(hash, lev - 1);
}
- iter_lev_in_flags_set(hash, lev - 1);
+}
+
+static VALUE
+hash_foreach_ensure_rollback(VALUE hash)
+{
+ hash_iter_lev_inc(hash);
+ return 0;
}
static VALUE
@@ -1470,18 +1568,16 @@ void rb_st_compact_table(st_table *tab);
static void
compact_after_delete(VALUE hash)
{
- if (!hash_iterating_p(hash) && RHASH_ST_TABLE_P(hash)) {
+ if (RHASH_ITER_LEV(hash) == 0 && RHASH_ST_TABLE_P(hash)) {
rb_st_compact_table(RHASH_ST_TABLE(hash));
}
}
static VALUE
-hash_alloc_flags(VALUE klass, VALUE flags, VALUE ifnone, bool st)
+hash_alloc_flags(VALUE klass, VALUE flags, VALUE ifnone)
{
const VALUE wb = (RGENGC_WB_PROTECTED_HASH ? FL_WB_PROTECTED : 0);
- const size_t size = sizeof(struct RHash) + (st ? sizeof(st_table) : sizeof(ar_table));
-
- NEWOBJ_OF(hash, struct RHash, klass, T_HASH | wb | flags, size, 0);
+ NEWOBJ_OF(hash, struct RHash, klass, T_HASH | wb | flags);
RHASH_SET_IFNONE((VALUE)hash, ifnone);
@@ -1491,8 +1587,7 @@ hash_alloc_flags(VALUE klass, VALUE flags, VALUE ifnone, bool st)
static VALUE
hash_alloc(VALUE klass)
{
- /* Allocate to be able to fit both st_table and ar_table. */
- return hash_alloc_flags(klass, 0, Qnil, sizeof(st_table) > sizeof(ar_table));
+ return hash_alloc_flags(klass, 0, Qnil);
}
static VALUE
@@ -1518,16 +1613,19 @@ copy_compare_by_id(VALUE hash, VALUE basis)
return hash;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_hash_new_with_size(st_index_t size)
{
- bool st = size > RHASH_AR_TABLE_MAX_SIZE;
- VALUE ret = hash_alloc_flags(rb_cHash, 0, Qnil, st);
-
- if (st) {
- hash_st_table_init(ret, &objhash, size);
+ VALUE ret = rb_hash_new();
+ if (size == 0) {
+ /* do nothing */
+ }
+ else if (size <= RHASH_AR_TABLE_MAX_SIZE) {
+ ar_alloc_table(ret);
+ }
+ else {
+ RHASH_ST_TABLE_SET(ret, st_init_table_with_size(&objhash, size));
}
-
return ret;
}
@@ -1540,32 +1638,11 @@ rb_hash_new_capa(long capa)
static VALUE
hash_copy(VALUE ret, VALUE hash)
{
- if (RHASH_AR_TABLE_P(hash)) {
- if (RHASH_AR_TABLE_P(ret)) {
+ if (!RHASH_EMPTY_P(hash)) {
+ if (RHASH_AR_TABLE_P(hash))
ar_copy(ret, hash);
- }
- else {
- st_table *tab = RHASH_ST_TABLE(ret);
- st_init_existing_table_with_size(tab, &objhash, RHASH_AR_TABLE_SIZE(hash));
-
- int bound = RHASH_AR_TABLE_BOUND(hash);
- for (int i = 0; i < bound; i++) {
- if (ar_cleared_entry(hash, i)) continue;
-
- ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i);
- st_add_direct(tab, pair->key, pair->val);
- RB_OBJ_WRITTEN(ret, Qundef, pair->key);
- RB_OBJ_WRITTEN(ret, Qundef, pair->val);
- }
- }
- }
- else {
- HASH_ASSERT(sizeof(st_table) <= sizeof(ar_table));
-
- RHASH_SET_ST_FLAG(ret);
- st_replace(RHASH_ST_TABLE(ret), RHASH_ST_TABLE(hash));
-
- rb_gc_writebarrier_remember(ret);
+ else if (RHASH_ST_TABLE_P(hash))
+ RHASH_ST_TABLE_SET(ret, st_copy(RHASH_ST_TABLE(hash)));
}
return ret;
}
@@ -1573,21 +1650,13 @@ hash_copy(VALUE ret, VALUE hash)
static VALUE
hash_dup_with_compare_by_id(VALUE hash)
{
- VALUE dup = hash_alloc_flags(rb_cHash, 0, Qnil, RHASH_ST_TABLE_P(hash));
- if (RHASH_ST_TABLE_P(hash)) {
- RHASH_SET_ST_FLAG(dup);
- }
- else {
- RHASH_UNSET_ST_FLAG(dup);
- }
-
- return hash_copy(dup, hash);
+ return hash_copy(copy_compare_by_id(rb_hash_new(), hash), hash);
}
static VALUE
hash_dup(VALUE hash, VALUE klass, VALUE flags)
{
- return hash_copy(hash_alloc_flags(klass, flags, RHASH_IFNONE(hash), !RHASH_EMPTY_P(hash) && RHASH_ST_TABLE_P(hash)),
+ return hash_copy(hash_alloc_flags(klass, flags, RHASH_IFNONE(hash)),
hash);
}
@@ -1602,7 +1671,7 @@ rb_hash_dup(VALUE hash)
return ret;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_hash_resurrect(VALUE hash)
{
VALUE ret = hash_dup(hash, rb_cHash, 0);
@@ -1615,7 +1684,7 @@ rb_hash_modify_check(VALUE hash)
rb_check_frozen(hash);
}
-struct st_table *
+MJIT_FUNC_EXPORTED struct st_table *
rb_hash_tbl_raw(VALUE hash, const char *file, int line)
{
return ar_force_convert_table(hash, file, line);
@@ -1733,14 +1802,14 @@ tbl_update(VALUE hash, VALUE key, tbl_update_func func, st_data_t optional_arg)
return ret;
}
-#define UPDATE_CALLBACK(iter_p, func) ((iter_p) ? func##_noinsert : func##_insert)
+#define UPDATE_CALLBACK(iter_lev, func) ((iter_lev) > 0 ? func##_noinsert : func##_insert)
-#define RHASH_UPDATE_ITER(h, iter_p, key, func, a) do { \
- tbl_update((h), (key), UPDATE_CALLBACK(iter_p, func), (st_data_t)(a)); \
+#define RHASH_UPDATE_ITER(h, iter_lev, key, func, a) do { \
+ tbl_update((h), (key), UPDATE_CALLBACK((iter_lev), func), (st_data_t)(a)); \
} while (0)
#define RHASH_UPDATE(hash, key, func, arg) \
- RHASH_UPDATE_ITER(hash, hash_iterating_p(hash), key, func, arg)
+ RHASH_UPDATE_ITER(hash, RHASH_ITER_LEV(hash), key, func, arg)
static void
set_proc_default(VALUE hash, VALUE proc)
@@ -1758,36 +1827,57 @@ set_proc_default(VALUE hash, VALUE proc)
RHASH_SET_IFNONE(hash, proc);
}
+/*
+ * call-seq:
+ * Hash.new(default_value = nil) -> new_hash
+ * Hash.new {|hash, key| ... } -> new_hash
+ *
+ * Returns a new empty \Hash object.
+ *
+ * The initial default value and initial default proc for the new hash
+ * depend on which form above was used. See {Default Values}[rdoc-ref:Hash@Default+Values].
+ *
+ * If neither an argument nor a block given,
+ * initializes both the default value and the default proc to <tt>nil</tt>:
+ * h = Hash.new
+ * h.default # => nil
+ * h.default_proc # => nil
+ *
+ * If argument <tt>default_value</tt> given but no block given,
+ * initializes the default value to the given <tt>default_value</tt>
+ * and the default proc to <tt>nil</tt>:
+ * h = Hash.new(false)
+ * h.default # => false
+ * h.default_proc # => nil
+ *
+ * If a block given but no argument, stores the block as the default proc
+ * and sets the default value to <tt>nil</tt>:
+ * h = Hash.new {|hash, key| "Default value for #{key}" }
+ * h.default # => nil
+ * h.default_proc.class # => Proc
+ * h[:nosuch] # => "Default value for nosuch"
+ */
+
static VALUE
-rb_hash_init(rb_execution_context_t *ec, VALUE hash, VALUE capa_value, VALUE ifnone_unset, VALUE ifnone, VALUE block)
+rb_hash_initialize(int argc, VALUE *argv, VALUE hash)
{
- rb_hash_modify(hash);
-
- if (capa_value != INT2FIX(0)) {
- long capa = NUM2LONG(capa_value);
- if (capa > 0 && RHASH_SIZE(hash) == 0 && RHASH_AR_TABLE_P(hash)) {
- hash_st_table_init(hash, &objhash, capa);
- }
- }
+ VALUE ifnone;
- if (!NIL_P(block)) {
- if (ifnone_unset != Qtrue) {
- rb_check_arity(1, 0, 0);
- }
- else {
- SET_PROC_DEFAULT(hash, block);
- }
+ rb_hash_modify(hash);
+ if (rb_block_given_p()) {
+ rb_check_arity(argc, 0, 0);
+ ifnone = rb_block_proc();
+ SET_PROC_DEFAULT(hash, ifnone);
}
else {
- RHASH_SET_IFNONE(hash, ifnone_unset == Qtrue ? Qnil : ifnone);
+ rb_check_arity(argc, 0, 1);
+ ifnone = argc == 0 ? Qnil : argv[0];
+ RHASH_SET_IFNONE(hash, ifnone);
}
- hash_verify(hash);
return hash;
}
-static VALUE rb_hash_to_a(VALUE hash);
-
/*
* call-seq:
* Hash[] -> new_empty_hash
@@ -1795,26 +1885,26 @@ static VALUE rb_hash_to_a(VALUE hash);
* Hash[ [*2_element_arrays] ] -> new_hash
* Hash[*objects] -> new_hash
*
- * Returns a new +Hash+ object populated with the given objects, if any.
+ * Returns a new \Hash object populated with the given objects, if any.
* See Hash::new.
*
- * With no argument, returns a new empty +Hash+.
+ * With no argument, returns a new empty \Hash.
*
- * When the single given argument is a +Hash+, returns a new +Hash+
- * populated with the entries from the given +Hash+, excluding the
+ * When the single given argument is a \Hash, returns a new \Hash
+ * populated with the entries from the given \Hash, excluding the
* default value or proc.
*
* h = {foo: 0, bar: 1, baz: 2}
* Hash[h] # => {:foo=>0, :bar=>1, :baz=>2}
*
- * When the single given argument is an Array of 2-element Arrays,
- * returns a new +Hash+ object wherein each 2-element array forms a
+ * When the single given argument is an \Array of 2-element Arrays,
+ * returns a new \Hash object wherein each 2-element array forms a
* key-value entry:
*
* Hash[ [ [:foo, 0], [:bar, 1] ] ] # => {:foo=>0, :bar=>1}
*
* When the argument count is an even number;
- * returns a new +Hash+ object wherein each successive pair of arguments
+ * returns a new \Hash object wherein each successive pair of arguments
* has become a key-value entry:
*
* Hash[:foo, 0, :bar, 1] # => {:foo=>0, :bar=>1}
@@ -1831,23 +1921,12 @@ rb_hash_s_create(int argc, VALUE *argv, VALUE klass)
if (argc == 1) {
tmp = rb_hash_s_try_convert(Qnil, argv[0]);
if (!NIL_P(tmp)) {
- if (!RHASH_EMPTY_P(tmp) && rb_hash_compare_by_id_p(tmp)) {
- /* hash_copy for non-empty hash will copy compare_by_identity
- flag, but we don't want it copied. Work around by
- converting hash to flattened array and using that. */
- tmp = rb_hash_to_a(tmp);
- }
- else {
- hash = hash_alloc(klass);
- if (!RHASH_EMPTY_P(tmp))
- hash_copy(hash, tmp);
- return hash;
- }
- }
- else {
- tmp = rb_check_array_type(argv[0]);
+ hash = hash_alloc(klass);
+ hash_copy(hash, tmp);
+ return hash;
}
+ tmp = rb_check_array_type(argv[0]);
if (!NIL_P(tmp)) {
long i;
@@ -1885,7 +1964,7 @@ rb_hash_s_create(int argc, VALUE *argv, VALUE klass)
return hash;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_to_hash_type(VALUE hash)
{
return rb_convert_type_with_id(hash, T_HASH, "Hash", idTo_hash);
@@ -1902,14 +1981,14 @@ rb_check_hash_type(VALUE hash)
* call-seq:
* Hash.try_convert(obj) -> obj, new_hash, or nil
*
- * If +obj+ is a +Hash+ object, returns +obj+.
+ * If +obj+ is a \Hash object, returns +obj+.
*
* Otherwise if +obj+ responds to <tt>:to_hash</tt>,
* calls <tt>obj.to_hash</tt> and returns the result.
*
* Returns +nil+ if +obj+ does not respond to <tt>:to_hash</tt>
*
- * Raises an exception unless <tt>obj.to_hash</tt> returns a +Hash+ object.
+ * Raises an exception unless <tt>obj.to_hash</tt> returns a \Hash object.
*/
static VALUE
rb_hash_s_try_convert(VALUE dummy, VALUE hash)
@@ -1958,12 +2037,9 @@ static VALUE
rb_hash_s_ruby2_keywords_hash(VALUE dummy, VALUE hash)
{
Check_Type(hash, T_HASH);
- VALUE tmp = rb_hash_dup(hash);
- if (RHASH_EMPTY_P(hash) && rb_hash_compare_by_id_p(hash)) {
- rb_hash_compare_by_id(tmp);
- }
- RHASH(tmp)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
- return tmp;
+ hash = rb_hash_dup(hash);
+ RHASH(hash)->basic.flags |= RHASH_PASS_AS_KEYWORDS;
+ return hash;
}
struct rehash_arg {
@@ -2001,27 +2077,25 @@ rb_hash_rehash(VALUE hash)
VALUE tmp;
st_table *tbl;
- if (hash_iterating_p(hash)) {
+ if (RHASH_ITER_LEV(hash) > 0) {
rb_raise(rb_eRuntimeError, "rehash during iteration");
}
rb_hash_modify_check(hash);
if (RHASH_AR_TABLE_P(hash)) {
tmp = hash_alloc(0);
+ ar_alloc_table(tmp);
rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
-
- hash_ar_free_and_clear_table(hash);
+ ar_free_and_clear_table(hash);
ar_copy(hash, tmp);
+ ar_free_and_clear_table(tmp);
}
else if (RHASH_ST_TABLE_P(hash)) {
st_table *old_tab = RHASH_ST_TABLE(hash);
tmp = hash_alloc(0);
-
- hash_st_table_init(tmp, old_tab->type, old_tab->num_entries);
- tbl = RHASH_ST_TABLE(tmp);
-
+ tbl = st_init_table_with_size(old_tab->type, old_tab->num_entries);
+ RHASH_ST_TABLE_SET(tmp, tbl);
rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
-
- hash_st_free(hash);
+ st_free_table(old_tab);
RHASH_ST_TABLE_SET(hash, tbl);
RHASH_ST_CLEAR(tmp);
}
@@ -2073,15 +2147,11 @@ hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval)
return ar_lookup(hash, key, pval);
}
else {
- extern st_index_t rb_iseq_cdhash_hash(VALUE);
- RUBY_ASSERT(RHASH_ST_TABLE(hash)->type->hash == rb_any_hash ||
- RHASH_ST_TABLE(hash)->type->hash == rb_ident_hash ||
- RHASH_ST_TABLE(hash)->type->hash == rb_iseq_cdhash_hash);
return st_lookup(RHASH_ST_TABLE(hash), key, pval);
}
}
-int
+MJIT_FUNC_EXPORTED int
rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval)
{
return hash_stlike_lookup(hash, key, pval);
@@ -2278,7 +2348,7 @@ rb_hash_default_proc(VALUE hash)
* call-seq:
* hash.default_proc = proc -> proc
*
- * Sets the default proc for +self+ to +proc+
+ * Sets the default proc for +self+ to +proc+:
* (see {Default Values}[rdoc-ref:Hash@Default+Values]):
* h = {}
* h.default_proc # => nil
@@ -2331,7 +2401,7 @@ key_i(VALUE key, VALUE value, VALUE arg)
* h.key(0) # => :foo
* h.key(2) # => :bar
*
- * Returns +nil+ if no such value is found.
+ * Returns +nil+ if so such value is found.
*/
static VALUE
@@ -2464,7 +2534,7 @@ shift_i_safe(VALUE key, VALUE value, VALUE arg)
*
* Removes the first hash entry
* (see {Entry Order}[rdoc-ref:Hash@Entry+Order]);
- * returns a 2-element Array containing the removed key and value:
+ * returns a 2-element \Array containing the removed key and value:
* h = {foo: 0, bar: 1, baz: 2}
* h.shift # => [:foo, 0]
* h # => {:bar=>1, :baz=>2}
@@ -2480,7 +2550,7 @@ rb_hash_shift(VALUE hash)
rb_hash_modify_check(hash);
if (RHASH_AR_TABLE_P(hash)) {
var.key = Qundef;
- if (!hash_iterating_p(hash)) {
+ if (RHASH_ITER_LEV(hash) == 0) {
if (ar_shift(hash, &var.key, &var.val)) {
return rb_assoc_new(var.key, var.val);
}
@@ -2495,7 +2565,7 @@ rb_hash_shift(VALUE hash)
}
if (RHASH_ST_TABLE_P(hash)) {
var.key = Qundef;
- if (!hash_iterating_p(hash)) {
+ if (RHASH_ITER_LEV(hash) == 0) {
if (st_shift(RHASH_ST_TABLE(hash), &var.key, &var.val)) {
return rb_assoc_new(var.key, var.val);
}
@@ -2538,7 +2608,7 @@ hash_enum_size(VALUE hash, VALUE args, VALUE eobj)
* h = {foo: 0, bar: 1, baz: 2}
* h.delete_if {|key, value| value > 0 } # => {:foo=>0}
*
- * If no block given, returns a new Enumerator:
+ * If no block given, returns a new \Enumerator:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.delete_if # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:delete_if>
* e.each { |key, value| value > 0 } # => {:foo=>0}
@@ -2568,7 +2638,7 @@ rb_hash_delete_if(VALUE hash)
*
* Returns +nil+ if no entries are removed.
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.reject! # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:reject!>
* e.each {|key, value| key.start_with?('b') } # => {:foo=>0}
@@ -2593,13 +2663,13 @@ rb_hash_reject_bang(VALUE hash)
* hash.reject {|key, value| ... } -> new_hash
* hash.reject -> new_enumerator
*
- * Returns a new +Hash+ object whose entries are all those
+ * Returns a new \Hash object whose entries are all those
* from +self+ for which the block returns +false+ or +nil+:
* h = {foo: 0, bar: 1, baz: 2}
* h1 = h.reject {|key, value| key.start_with?('b') }
* h1 # => {:foo=>0}
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.reject # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:reject>
* h1 = e.each {|key, value| key.start_with?('b') }
@@ -2624,7 +2694,7 @@ rb_hash_reject(VALUE hash)
* call-seq:
* hash.slice(*keys) -> new_hash
*
- * Returns a new +Hash+ object containing the entries for the given +keys+:
+ * Returns a new \Hash object containing the entries for the given +keys+:
* h = {foo: 0, bar: 1, baz: 2}
* h.slice(:baz, :foo) # => {:baz=>2, :foo=>0}
*
@@ -2656,7 +2726,7 @@ rb_hash_slice(int argc, VALUE *argv, VALUE hash)
* call-seq:
* hsh.except(*keys) -> a_hash
*
- * Returns a new +Hash+ excluding entries for the given +keys+:
+ * Returns a new \Hash excluding entries for the given +keys+:
* h = { a: 100, b: 200, c: 300 }
* h.except(:a) #=> {:b=>200, :c=>300}
*
@@ -2684,7 +2754,7 @@ rb_hash_except(int argc, VALUE *argv, VALUE hash)
* call-seq:
* hash.values_at(*keys) -> new_array
*
- * Returns a new Array containing values for the given +keys+:
+ * Returns a new \Array containing values for the given +keys+:
* h = {foo: 0, bar: 1, baz: 2}
* h.values_at(:baz, :foo) # => [2, 0]
*
@@ -2710,11 +2780,11 @@ rb_hash_values_at(int argc, VALUE *argv, VALUE hash)
* hash.fetch_values(*keys) -> new_array
* hash.fetch_values(*keys) {|key| ... } -> new_array
*
- * Returns a new Array containing the values associated with the given keys *keys:
+ * Returns a new \Array containing the values associated with the given keys *keys:
* h = {foo: 0, bar: 1, baz: 2}
* h.fetch_values(:baz, :foo) # => [2, 0]
*
- * Returns a new empty Array if no arguments given.
+ * Returns a new empty \Array if no arguments given.
*
* When a block is given, calls the block with each missing key,
* treating the block's return value as the value for that key:
@@ -2752,11 +2822,13 @@ keep_if_i(VALUE key, VALUE value, VALUE hash)
* hash.select {|key, value| ... } -> new_hash
* hash.select -> new_enumerator
*
- * Returns a new +Hash+ object whose entries are those for which the block returns a truthy value:
+ * Hash#filter is an alias for Hash#select.
+ *
+ * Returns a new \Hash object whose entries are those for which the block returns a truthy value:
* h = {foo: 0, bar: 1, baz: 2}
* h.select {|key, value| value < 2 } # => {:foo=>0, :bar=>1}
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.select # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:select>
* e.each {|key, value| value < 2 } # => {:foo=>0, :bar=>1}
@@ -2781,13 +2853,15 @@ rb_hash_select(VALUE hash)
* hash.select! {|key, value| ... } -> self or nil
* hash.select! -> new_enumerator
*
+ * Hash#filter! is an alias for Hash#select!.
+ *
* Returns +self+, whose entries are those for which the block returns a truthy value:
* h = {foo: 0, bar: 1, baz: 2}
* h.select! {|key, value| value < 2 } => {:foo=>0, :bar=>1}
*
* Returns +nil+ if no entries were removed.
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.select! # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:select!>
* e.each { |key, value| value < 2 } # => {:foo=>0, :bar=>1}
@@ -2818,7 +2892,7 @@ rb_hash_select_bang(VALUE hash)
* h = {foo: 0, bar: 1, baz: 2}
* h.keep_if { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2}
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.keep_if # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:keep_if>
* e.each { |key, value| key.start_with?('b') } # => {:bar=>1, :baz=>2}
@@ -2853,7 +2927,7 @@ rb_hash_clear(VALUE hash)
{
rb_hash_modify_check(hash);
- if (hash_iterating_p(hash)) {
+ if (RHASH_ITER_LEV(hash) > 0) {
rb_hash_foreach(hash, clear_i, 0);
}
else if (RHASH_AR_TABLE_P(hash)) {
@@ -2902,6 +2976,8 @@ NOINSERT_UPDATE_CALLBACK(hash_aset_str)
* hash[key] = value -> value
* hash.store(key, value)
*
+ * Hash#store is an alias for Hash#[]=.
+
* Associates the given +value+ with the given +key+; returns +value+.
*
* If the given +key+ exists, replaces its value with the given +value+;
@@ -2924,15 +3000,20 @@ NOINSERT_UPDATE_CALLBACK(hash_aset_str)
VALUE
rb_hash_aset(VALUE hash, VALUE key, VALUE val)
{
- bool iter_p = hash_iterating_p(hash);
+ int iter_lev = RHASH_ITER_LEV(hash);
rb_hash_modify(hash);
+ if (RHASH_TABLE_NULL_P(hash)) {
+ if (iter_lev > 0) no_new_key();
+ ar_alloc_table(hash);
+ }
+
if (!RHASH_STRING_KEY_P(hash, key)) {
- RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset, val);
+ RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset, val);
}
else {
- RHASH_UPDATE_ITER(hash, iter_p, key, hash_aset_str, val);
+ RHASH_UPDATE_ITER(hash, iter_lev, key, hash_aset_str, val);
}
return val;
}
@@ -2952,7 +3033,7 @@ rb_hash_replace(VALUE hash, VALUE hash2)
{
rb_hash_modify_check(hash);
if (hash == hash2) return hash;
- if (hash_iterating_p(hash)) {
+ if (RHASH_ITER_LEV(hash) > 0) {
rb_raise(rb_eRuntimeError, "can't replace hash during iteration");
}
hash2 = to_hash(hash2);
@@ -2960,13 +3041,19 @@ rb_hash_replace(VALUE hash, VALUE hash2)
COPY_DEFAULT(hash, hash2);
if (RHASH_AR_TABLE_P(hash)) {
- hash_ar_free_and_clear_table(hash);
+ ar_free_and_clear_table(hash);
}
else {
- hash_st_free_and_clear_table(hash);
+ st_free_table(RHASH_ST_TABLE(hash));
+ RHASH_ST_CLEAR(hash);
}
-
hash_copy(hash, hash2);
+ if (RHASH_EMPTY_P(hash2) && RHASH_ST_TABLE_P(hash2)) {
+ /* ident hash */
+ RHASH_ST_TABLE_SET(hash, st_init_table_with_size(RHASH_TYPE(hash2), 0));
+ }
+
+ rb_gc_writebarrier_remember(hash);
return hash;
}
@@ -2977,9 +3064,9 @@ rb_hash_replace(VALUE hash, VALUE hash2)
* hash.size -> integer
*
* Returns the count of entries in +self+:
- *
* {foo: 0, bar: 1, baz: 2}.length # => 3
*
+ * Hash#length is an alias for Hash#size.
*/
VALUE
@@ -3003,7 +3090,7 @@ rb_hash_size_num(VALUE hash)
* {foo: 0, bar: 1, baz: 2}.empty? # => false
*/
-VALUE
+static VALUE
rb_hash_empty_p(VALUE hash)
{
return RBOOL(RHASH_EMPTY_P(hash));
@@ -3029,7 +3116,7 @@ each_value_i(VALUE key, VALUE value, VALUE _)
* 1
* 2
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.each_value # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_value>
* h1 = e.each {|value| puts value }
@@ -3068,7 +3155,7 @@ each_key_i(VALUE key, VALUE value, VALUE _)
* bar
* baz
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.each_key # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_key>
* h1 = e.each {|key| puts key }
@@ -3110,6 +3197,8 @@ each_pair_i_fast(VALUE key, VALUE value, VALUE _)
* hash.each -> new_enumerator
* hash.each_pair -> new_enumerator
*
+ * Hash#each is an alias for Hash#each_pair.
+
* Calls the given block with each key-value pair; returns +self+:
* h = {foo: 0, bar: 1, baz: 2}
* h.each_pair {|key, value| puts "#{key}: #{value}"} # => {:foo=>0, :bar=>1, :baz=>2}
@@ -3118,7 +3207,7 @@ each_pair_i_fast(VALUE key, VALUE value, VALUE _)
* bar: 1
* baz: 2
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.each_pair # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:each_pair>
* h1 = e.each {|key, value| puts "#{key}: #{value}"}
@@ -3177,7 +3266,7 @@ transform_keys_i(VALUE key, VALUE value, VALUE result)
* hash.transform_keys(hash2) {|other_key| ...} -> new_hash
* hash.transform_keys -> new_enumerator
*
- * Returns a new +Hash+ object; each entry has:
+ * Returns a new \Hash object; each entry has:
* * A key provided by the block.
* * The value from +self+.
*
@@ -3201,7 +3290,7 @@ transform_keys_i(VALUE key, VALUE value, VALUE result)
* h1 = h.transform_keys {|key| :bat }
* h1 # => {:bat=>2}
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.transform_keys # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:transform_keys>
* h1 = e.each { |key| key.to_s }
@@ -3317,7 +3406,7 @@ transform_values_foreach_replace(st_data_t *key, st_data_t *value, st_data_t arg
* hash.transform_values {|value| ... } -> new_hash
* hash.transform_values -> new_enumerator
*
- * Returns a new +Hash+ object; each entry has:
+ * Returns a new \Hash object; each entry has:
* * A key from +self+.
* * A value provided by the block.
*
@@ -3326,7 +3415,7 @@ transform_values_foreach_replace(st_data_t *key, st_data_t *value, st_data_t arg
* h1 = h.transform_values {|value| value * 100}
* h1 # => {:foo=>0, :bar=>100, :baz=>200}
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.transform_values # => #<Enumerator: {:foo=>0, :bar=>1, :baz=>2}:transform_values>
* h1 = e.each { |value| value * 100}
@@ -3358,7 +3447,7 @@ rb_hash_transform_values(VALUE hash)
* h = {foo: 0, bar: 1, baz: 2}
* h.transform_values! {|value| value * 100} # => {:foo=>0, :bar=>100, :baz=>200}
*
- * Returns a new Enumerator if no block given:
+ * Returns a new \Enumerator if no block given:
* h = {foo: 0, bar: 1, baz: 2}
* e = h.transform_values! # => #<Enumerator: {:foo=>0, :bar=>100, :baz=>200}:transform_values!>
* h1 = e.each {|value| value * 100}
@@ -3388,8 +3477,8 @@ to_a_i(VALUE key, VALUE value, VALUE ary)
* call-seq:
* hash.to_a -> new_array
*
- * Returns a new Array of 2-element Array objects;
- * each nested Array contains a key-value pair from +self+:
+ * Returns a new \Array of 2-element \Array objects;
+ * each nested \Array contains a key-value pair from +self+:
* h = {foo: 0, bar: 1, baz: 2}
* h.to_a # => [[:foo, 0], [:bar, 1], [:baz, 2]]
*/
@@ -3405,65 +3494,20 @@ rb_hash_to_a(VALUE hash)
return ary;
}
-static bool
-symbol_key_needs_quote(VALUE str)
-{
- long len = RSTRING_LEN(str);
- if (len == 0 || !rb_str_symname_p(str)) return true;
- const char *s = RSTRING_PTR(str);
- char first = s[0];
- if (first == '@' || first == '$' || first == '!') return true;
- if (!at_char_boundary(s, s + len - 1, RSTRING_END(str), rb_enc_get(str))) return false;
- switch (s[len - 1]) {
- case '+':
- case '-':
- case '*':
- case '/':
- case '`':
- case '%':
- case '^':
- case '&':
- case '|':
- case ']':
- case '<':
- case '=':
- case '>':
- case '~':
- case '@':
- return true;
- default:
- return false;
- }
-}
-
static int
inspect_i(VALUE key, VALUE value, VALUE str)
{
VALUE str2;
- bool is_symbol = SYMBOL_P(key);
- bool quote = false;
- if (is_symbol) {
- str2 = rb_sym2str(key);
- quote = symbol_key_needs_quote(str2);
- }
- else {
- str2 = rb_inspect(key);
- }
+ str2 = rb_inspect(key);
if (RSTRING_LEN(str) > 1) {
rb_str_buf_cat_ascii(str, ", ");
}
else {
rb_enc_copy(str, str2);
}
- if (quote) {
- rb_str_buf_append(str, rb_str_inspect(str2));
- }
- else {
- rb_str_buf_append(str, str2);
- }
-
- rb_str_buf_cat_ascii(str, is_symbol ? ": " : " => ");
+ rb_str_buf_append(str, str2);
+ rb_str_buf_cat_ascii(str, "=>");
str2 = rb_inspect(value);
rb_str_buf_append(str, str2);
@@ -3487,11 +3531,11 @@ inspect_hash(VALUE hash, VALUE dummy, int recur)
* call-seq:
* hash.inspect -> new_string
*
- * Returns a new String containing the hash entries:
-
+ * Returns a new \String containing the hash entries:
* h = {foo: 0, bar: 1, baz: 2}
* h.inspect # => "{:foo=>0, :bar=>1, :baz=>2}"
*
+ * Hash#to_s is an alias for Hash#inspect.
*/
static VALUE
@@ -3552,15 +3596,15 @@ rb_hash_to_h_block(VALUE hash)
* hash.to_h -> self or new_hash
* hash.to_h {|key, value| ... } -> new_hash
*
- * For an instance of +Hash+, returns +self+.
+ * For an instance of \Hash, returns +self+.
*
- * For a subclass of +Hash+, returns a new +Hash+
+ * For a subclass of \Hash, returns a new \Hash
* containing the content of +self+.
*
- * When a block is given, returns a new +Hash+ object
+ * When a block is given, returns a new \Hash object
* whose content is based on the block;
- * the block should return a 2-element Array object
- * specifying the key-value pair to be included in the returned Array:
+ * the block should return a 2-element \Array object
+ * specifying the key-value pair to be included in the returned \Array:
* h = {foo: 0, bar: 1, baz: 2}
* h1 = h.to_h {|key, value| [value, key] }
* h1 # => {0=>:foo, 1=>:bar, 2=>:baz}
@@ -3590,12 +3634,12 @@ keys_i(VALUE key, VALUE value, VALUE ary)
* call-seq:
* hash.keys -> new_array
*
- * Returns a new Array containing all keys in +self+:
+ * Returns a new \Array containing all keys in +self+:
* h = {foo: 0, bar: 1, baz: 2}
* h.keys # => [:foo, :bar, :baz]
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_hash_keys(VALUE hash)
{
st_index_t size = RHASH_SIZE(hash);
@@ -3604,7 +3648,7 @@ rb_hash_keys(VALUE hash)
if (size == 0) return keys;
if (ST_DATA_COMPATIBLE_P(VALUE)) {
- RARRAY_PTR_USE(keys, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(keys, ptr, {
if (RHASH_AR_TABLE_P(hash)) {
size = ar_keys(hash, ptr, size);
}
@@ -3634,7 +3678,7 @@ values_i(VALUE key, VALUE value, VALUE ary)
* call-seq:
* hash.values -> new_array
*
- * Returns a new Array containing all values in +self+:
+ * Returns a new \Array containing all values in +self+:
* h = {foo: 0, bar: 1, baz: 2}
* h.values # => [0, 1, 2]
*/
@@ -3651,14 +3695,14 @@ rb_hash_values(VALUE hash)
if (ST_DATA_COMPATIBLE_P(VALUE)) {
if (RHASH_AR_TABLE_P(hash)) {
rb_gc_writebarrier_remember(values);
- RARRAY_PTR_USE(values, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(values, ptr, {
size = ar_values(hash, ptr, size);
});
}
else if (RHASH_ST_TABLE_P(hash)) {
st_table *table = RHASH_ST_TABLE(hash);
rb_gc_writebarrier_remember(values);
- RARRAY_PTR_USE(values, ptr, {
+ RARRAY_PTR_USE_TRANSIENT(values, ptr, {
size = st_values(table, ptr, size);
});
}
@@ -3678,11 +3722,13 @@ rb_hash_values(VALUE hash)
* hash.has_key?(key) -> true or false
* hash.key?(key) -> true or false
* hash.member?(key) -> true or false
+
+ * Methods #has_key?, #key?, and #member? are aliases for \#include?.
*
* Returns +true+ if +key+ is a key in +self+, otherwise +false+.
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_hash_has_key(VALUE hash, VALUE key)
{
return RBOOL(hash_stlike_lookup(hash, key, NULL));
@@ -3705,6 +3751,8 @@ rb_hash_search_value(VALUE key, VALUE value, VALUE arg)
* hash.has_value?(value) -> true or false
* hash.value?(value) -> true or false
*
+ * Method #value? is an alias for \#has_value?.
+ *
* Returns +true+ if +value+ is a value in +self+, otherwise +false+.
*/
@@ -3805,7 +3853,7 @@ hash_equal(VALUE hash1, VALUE hash2, int eql)
* hash == object -> true or false
*
* Returns +true+ if all of the following are true:
- * * +object+ is a +Hash+ object.
+ * * +object+ is a \Hash object.
* * +hash+ and +object+ have the same keys (regardless of order).
* * For each key +key+, <tt>hash[key] == object[key]</tt>.
*
@@ -3827,15 +3875,16 @@ rb_hash_equal(VALUE hash1, VALUE hash2)
/*
* call-seq:
- * hash.eql?(object) -> true or false
+ * hash.eql? object -> true or false
*
* Returns +true+ if all of the following are true:
- * * +object+ is a +Hash+ object.
+ * * +object+ is a \Hash object.
* * +hash+ and +object+ have the same keys (regardless of order).
- * * For each key +key+, <tt>h[key].eql?(object[key])</tt>.
+ * * For each key +key+, <tt>h[key] eql? object[key]</tt>.
*
* Otherwise, returns +false+.
*
+ * Equal:
* h1 = {foo: 0, bar: 1, baz: 2}
* h2 = {foo: 0, bar: 1, baz: 2}
* h1.eql? h2 # => true
@@ -3865,10 +3914,10 @@ hash_i(VALUE key, VALUE val, VALUE arg)
* call-seq:
* hash.hash -> an_integer
*
- * Returns the Integer hash-code for the hash.
+ * Returns the \Integer hash-code for the hash.
*
- * Two +Hash+ objects have the same hash-code if their content is the same
- * (regardless of order):
+ * Two \Hash objects have the same hash-code if their content is the same
+ * (regardless or order):
* h1 = {foo: 0, bar: 1, baz: 2}
* h2 = {baz: 2, bar: 1, foo: 0}
* h2.hash == h1.hash # => true
@@ -3899,7 +3948,7 @@ rb_hash_invert_i(VALUE key, VALUE value, VALUE hash)
* call-seq:
* hash.invert -> new_hash
*
- * Returns a new +Hash+ object with the each key-value pair inverted:
+ * Returns a new \Hash object with the each key-value pair inverted:
* h = {foo: 0, bar: 1, baz: 2}
* h1 = h.invert
* h1 # => {0=>:foo, 1=>:bar, 2=>:baz}
@@ -3958,7 +4007,9 @@ rb_hash_update_block_i(VALUE key, VALUE value, VALUE hash)
*
* Merges each of +other_hashes+ into +self+; returns +self+.
*
- * Each argument in +other_hashes+ must be a +Hash+.
+ * Each argument in +other_hashes+ must be a \Hash.
+ *
+ * \Method #update is an alias for \#merge!.
*
* With arguments and no block:
* * Returns +self+, after the given hashes are merged into it.
@@ -4072,16 +4123,16 @@ rb_hash_update_by(VALUE hash1, VALUE hash2, rb_hash_update_func *func)
* hash.merge(*other_hashes) -> new_hash
* hash.merge(*other_hashes) { |key, old_value, new_value| ... } -> new_hash
*
- * Returns the new +Hash+ formed by merging each of +other_hashes+
+ * Returns the new \Hash formed by merging each of +other_hashes+
* into a copy of +self+.
*
- * Each argument in +other_hashes+ must be a +Hash+.
+ * Each argument in +other_hashes+ must be a \Hash.
*
* ---
*
* With arguments and no block:
- * * Returns the new +Hash+ object formed by merging each successive
- * +Hash+ in +other_hashes+ into +self+.
+ * * Returns the new \Hash object formed by merging each successive
+ * \Hash in +other_hashes+ into +self+.
* * Each new-key entry is added at the end.
* * Each duplicate-key entry's value overwrites the previous value.
*
@@ -4092,7 +4143,7 @@ rb_hash_update_by(VALUE hash1, VALUE hash2, rb_hash_update_func *func)
* h.merge(h1, h2) # => {:foo=>0, :bar=>4, :baz=>2, :bat=>6, :bam=>5}
*
* With arguments and a block:
- * * Returns a new +Hash+ object that is the merge of +self+ and each given hash.
+ * * Returns a new \Hash object that is the merge of +self+ and each given hash.
* * The given hashes are merged left to right.
* * Each new-key entry is added at the end.
* * For each duplicate key:
@@ -4129,17 +4180,24 @@ assoc_cmp(VALUE a, VALUE b)
return !RTEST(rb_equal(a, b));
}
-struct assoc_arg {
- st_table *tbl;
- st_data_t key;
+static VALUE
+lookup2_call(VALUE arg)
+{
+ VALUE *args = (VALUE *)arg;
+ return rb_hash_lookup2(args[0], args[1], Qundef);
+}
+
+struct reset_hash_type_arg {
+ VALUE hash;
+ const struct st_hash_type *orighash;
};
static VALUE
-assoc_lookup(VALUE arg)
+reset_hash_type(VALUE arg)
{
- struct assoc_arg *p = (struct assoc_arg*)arg;
- st_data_t data;
- if (st_lookup(p->tbl, p->key, &data)) return (VALUE)data;
+ struct reset_hash_type_arg *p = (struct reset_hash_type_arg *)arg;
+ HASH_ASSERT(RHASH_ST_TABLE_P(p->hash));
+ RHASH_ST_TABLE(p->hash)->type = p->orighash;
return Qundef;
}
@@ -4159,7 +4217,7 @@ assoc_i(VALUE key, VALUE val, VALUE arg)
* call-seq:
* hash.assoc(key) -> new_array or nil
*
- * If the given +key+ is found, returns a 2-element Array containing that key and its value:
+ * If the given +key+ is found, returns a 2-element \Array containing that key and its value:
* h = {foo: 0, bar: 1, baz: 2}
* h.assoc(:bar) # => [:bar, 1]
*
@@ -4169,30 +4227,30 @@ assoc_i(VALUE key, VALUE val, VALUE arg)
static VALUE
rb_hash_assoc(VALUE hash, VALUE key)
{
+ st_table *table;
+ const struct st_hash_type *orighash;
VALUE args[2];
if (RHASH_EMPTY_P(hash)) return Qnil;
- if (RHASH_ST_TABLE_P(hash) && !RHASH_IDENTHASH_P(hash)) {
- VALUE value = Qundef;
- st_table assoctable = *RHASH_ST_TABLE(hash);
- assoctable.type = &(struct st_hash_type){
- .compare = assoc_cmp,
- .hash = assoctable.type->hash,
- };
- VALUE arg = (VALUE)&(struct assoc_arg){
- .tbl = &assoctable,
- .key = (st_data_t)key,
- };
-
- if (RB_OBJ_FROZEN(hash)) {
- value = assoc_lookup(arg);
- }
- else {
- hash_iter_lev_inc(hash);
- value = rb_ensure(assoc_lookup, arg, hash_foreach_ensure, hash);
- }
- hash_verify(hash);
+ ar_force_convert_table(hash, __FILE__, __LINE__);
+ HASH_ASSERT(RHASH_ST_TABLE_P(hash));
+ table = RHASH_ST_TABLE(hash);
+ orighash = table->type;
+
+ if (!RHASH_IDENTHASH_P(hash)) {
+ VALUE value;
+ struct reset_hash_type_arg ensure_arg;
+ struct st_hash_type assochash;
+
+ assochash.compare = assoc_cmp;
+ assochash.hash = orighash->hash;
+ table->type = &assochash;
+ args[0] = hash;
+ args[1] = key;
+ ensure_arg.hash = hash;
+ ensure_arg.orighash = orighash;
+ value = rb_ensure(lookup2_call, (VALUE)&args, reset_hash_type, (VALUE)&ensure_arg);
if (!UNDEF_P(value)) return rb_assoc_new(key, value);
}
@@ -4218,7 +4276,7 @@ rassoc_i(VALUE key, VALUE val, VALUE arg)
* call-seq:
* hash.rassoc(value) -> new_array or nil
*
- * Returns a new 2-element Array consisting of the key and value
+ * Returns a new 2-element \Array consisting of the key and value
* of the first-found entry whose value is <tt>==</tt> to value
* (see {Entry Order}[rdoc-ref:Hash@Entry+Order]):
* h = {foo: 0, bar: 1, baz: 1}
@@ -4255,7 +4313,7 @@ flatten_i(VALUE key, VALUE val, VALUE ary)
* hash.flatten -> new_array
* hash.flatten(level) -> new_array
*
- * Returns a new Array object that is a 1-dimensional flattening of +self+.
+ * Returns a new \Array object that is a 1-dimensional flattening of +self+.
*
* ---
*
@@ -4263,7 +4321,7 @@ flatten_i(VALUE key, VALUE val, VALUE ary)
* h = {foo: 0, bar: [:bat, 3], baz: 2}
* h.flatten # => [:foo, 0, :bar, [:bat, 3], :baz, 2]
*
- * Takes the depth of recursive flattening from Integer argument +level+:
+ * Takes the depth of recursive flattening from \Integer argument +level+:
* h = {foo: 0, bar: [:bat, [:baz, [:bat, ]]]}
* h.flatten(1) # => [:foo, 0, :bar, [:bat, [:baz, [:bat]]]]
* h.flatten(2) # => [:foo, 0, :bar, :bat, [:baz, [:bat]]]
@@ -4323,6 +4381,15 @@ delete_if_nil(VALUE key, VALUE value, VALUE hash)
return ST_CONTINUE;
}
+static int
+set_if_not_nil(VALUE key, VALUE value, VALUE hash)
+{
+ if (!NIL_P(value)) {
+ rb_hash_aset(hash, key, value);
+ }
+ return ST_CONTINUE;
+}
+
/*
* call-seq:
* hash.compact -> new_hash
@@ -4336,13 +4403,9 @@ delete_if_nil(VALUE key, VALUE value, VALUE hash)
static VALUE
rb_hash_compact(VALUE hash)
{
- VALUE result = rb_hash_dup(hash);
+ VALUE result = rb_hash_new();
if (!RHASH_EMPTY_P(hash)) {
- rb_hash_foreach(result, delete_if_nil, result);
- compact_after_delete(result);
- }
- else if (rb_hash_compare_by_id_p(hash)) {
- result = rb_hash_compare_by_id(result);
+ rb_hash_foreach(hash, set_if_not_nil, result);
}
return result;
}
@@ -4372,6 +4435,8 @@ rb_hash_compact_bang(VALUE hash)
return Qnil;
}
+static st_table *rb_init_identtable_with_size(st_index_t size);
+
/*
* call-seq:
* hash.compare_by_identity -> self
@@ -4409,33 +4474,16 @@ rb_hash_compare_by_id(VALUE hash)
if (rb_hash_compare_by_id_p(hash)) return hash;
rb_hash_modify_check(hash);
- if (hash_iterating_p(hash)) {
- rb_raise(rb_eRuntimeError, "compare_by_identity during iteration");
- }
-
- if (RHASH_TABLE_EMPTY_P(hash)) {
- // Fast path: There's nothing to rehash, so we don't need a `tmp` table.
- // We're most likely an AR table, so this will need an allocation.
- ar_force_convert_table(hash, __FILE__, __LINE__);
- HASH_ASSERT(RHASH_ST_TABLE_P(hash));
-
- RHASH_ST_TABLE(hash)->type = &identhash;
- }
- else {
- // Slow path: Need to rehash the members of `self` into a new
- // `tmp` table using the new `identhash` compare/hash functions.
- tmp = hash_alloc(0);
- hash_st_table_init(tmp, &identhash, RHASH_SIZE(hash));
- identtable = RHASH_ST_TABLE(tmp);
-
- rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
- rb_hash_free(hash);
+ ar_force_convert_table(hash, __FILE__, __LINE__);
+ HASH_ASSERT(RHASH_ST_TABLE_P(hash));
- // We know for sure `identtable` is an st table,
- // so we can skip `ar_force_convert_table` here.
- RHASH_ST_TABLE_SET(hash, identtable);
- RHASH_ST_CLEAR(tmp);
- }
+ tmp = hash_alloc(0);
+ identtable = rb_init_identtable_with_size(RHASH_SIZE(hash));
+ RHASH_ST_TABLE_SET(tmp, identtable);
+ rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tmp);
+ st_free_table(RHASH_ST_TABLE(hash));
+ RHASH_ST_TABLE_SET(hash, identtable);
+ RHASH_ST_CLEAR(tmp);
return hash;
}
@@ -4447,7 +4495,7 @@ rb_hash_compare_by_id(VALUE hash)
* Returns +true+ if #compare_by_identity has been called, +false+ otherwise.
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_hash_compare_by_id_p(VALUE hash)
{
return RBOOL(RHASH_IDENTHASH_P(hash));
@@ -4457,7 +4505,7 @@ VALUE
rb_ident_hash_new(void)
{
VALUE hash = rb_hash_new();
- hash_st_table_init(hash, &identhash, 0);
+ RHASH_ST_TABLE_SET(hash, st_init_table(&identhash));
return hash;
}
@@ -4465,7 +4513,7 @@ VALUE
rb_ident_hash_new_with_size(st_index_t size)
{
VALUE hash = rb_hash_new();
- hash_st_table_init(hash, &identhash, size);
+ RHASH_ST_TABLE_SET(hash, st_init_table_with_size(&identhash, size));
return hash;
}
@@ -4475,6 +4523,12 @@ rb_init_identtable(void)
return st_init_table(&identhash);
}
+static st_table *
+rb_init_identtable_with_size(st_index_t size)
+{
+ return st_init_table_with_size(&identhash, size);
+}
+
static int
any_p_i(VALUE key, VALUE value, VALUE arg)
{
@@ -4517,9 +4571,6 @@ any_p_i_pattern(VALUE key, VALUE value, VALUE arg)
* Returns +true+ if any element satisfies a given criterion;
* +false+ otherwise.
*
- * If +self+ has no element, returns +false+ and argument or block
- * are not used.
- *
* With no argument and no block,
* returns +true+ if +self+ is non-empty; +false+ if empty.
*
@@ -4538,8 +4589,6 @@ any_p_i_pattern(VALUE key, VALUE value, VALUE arg)
* h = {foo: 0, bar: 1, baz: 2}
* h.any? {|key, value| value < 3 } # => true
* h.any? {|key, value| value > 3 } # => false
- *
- * Related: Enumerable#any?
*/
static VALUE
@@ -4717,7 +4766,7 @@ hash_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(key, hash))
* call-seq:
* hash.to_proc -> proc
*
- * Returns a Proc object that maps a key to its value:
+ * Returns a \Proc object that maps a key to its value:
* h = {foo: 0, bar: 1, baz: 2}
* proc = h.to_proc
* proc.class # => Proc
@@ -4731,7 +4780,6 @@ rb_hash_to_proc(VALUE hash)
return rb_func_lambda_new(hash_proc_call, hash, 1, 1);
}
-/* :nodoc: */
static VALUE
rb_hash_deconstruct_keys(VALUE hash, VALUE keys)
{
@@ -4762,13 +4810,14 @@ rb_hash_add_new_element(VALUE hash, VALUE key, VALUE val)
args[1] = val;
if (RHASH_AR_TABLE_P(hash)) {
+ hash_ar_table(hash);
+
ret = ar_update(hash, (st_data_t)key, add_new_i, (st_data_t)args);
if (ret != -1) {
return ret;
}
ar_force_convert_table(hash, __FILE__, __LINE__);
}
-
tbl = RHASH_TBL_RAW(hash);
return st_update(tbl, (st_data_t)key, add_new_i, (st_data_t)args);
@@ -4801,6 +4850,15 @@ rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
if (argc > 0) {
st_index_t size = argc / 2;
+ if (RHASH_TABLE_NULL_P(hash)) {
+ if (size <= RHASH_AR_TABLE_MAX_SIZE) {
+ hash_ar_table(hash);
+ }
+ else {
+ RHASH_TBL_RAW(hash);
+ }
+ }
+
if (RHASH_AR_TABLE_P(hash) &&
(RHASH_AR_TABLE_SIZE(hash) + size <= RHASH_AR_TABLE_MAX_SIZE)) {
ar_bulk_insert(hash, argc, argv);
@@ -4903,7 +4961,9 @@ has_env_with_lock(const char *name)
static const char TZ_ENV[] = "TZ";
static void *
-get_env_cstr(VALUE str, const char *name)
+get_env_cstr(
+ VALUE str,
+ const char *name)
{
char *var;
rb_encoding *enc = rb_enc_get(str);
@@ -4925,7 +4985,7 @@ static inline const char *
env_name(volatile VALUE *s)
{
const char *name;
- StringValue(*s);
+ SafeStringValue(*s);
get_env_ptr(name, *s);
return name;
}
@@ -4935,7 +4995,7 @@ env_name(volatile VALUE *s)
static VALUE env_aset(VALUE nm, VALUE val);
static void
-reset_by_modified_env(const char *nam)
+reset_by_modified_env(const char *nam, const char *val)
{
/*
* ENV['TZ'] = nil has a special meaning.
@@ -4944,7 +5004,7 @@ reset_by_modified_env(const char *nam)
* This hack might works only on Linux glibc.
*/
if (ENVMATCH(nam, TZ_ENV)) {
- ruby_reset_timezone();
+ ruby_reset_timezone(val);
}
}
@@ -4952,7 +5012,7 @@ static VALUE
env_delete(VALUE name)
{
const char *nam = env_name(name);
- reset_by_modified_env(nam);
+ reset_by_modified_env(nam, NULL);
VALUE val = getenv_with_lock(nam);
if (!NIL_P(val)) {
@@ -5098,6 +5158,44 @@ envix(const char *nam)
}
#endif
+#if defined(_WIN32)
+static size_t
+getenvsize(const WCHAR* p)
+{
+ const WCHAR* porg = p;
+ while (*p++) p += lstrlenW(p) + 1;
+ return p - porg + 1;
+}
+
+static size_t
+getenvblocksize(void)
+{
+#ifdef _MAX_ENV
+ return _MAX_ENV;
+#else
+ return 32767;
+#endif
+}
+
+static int
+check_envsize(size_t n)
+{
+ if (_WIN32_WINNT < 0x0600 && rb_w32_osver() < 6) {
+ /* https://msdn.microsoft.com/en-us/library/windows/desktop/ms682653(v=vs.85).aspx */
+ /* Windows Server 2003 and Windows XP: The maximum size of the
+ * environment block for the process is 32,767 characters. */
+ WCHAR* p = GetEnvironmentStringsW();
+ if (!p) return -1; /* never happen */
+ n += getenvsize(p);
+ FreeEnvironmentStringsW(p);
+ if (n >= getenvblocksize()) {
+ return -1;
+ }
+ }
+ return 0;
+}
+#endif
+
#if defined(_WIN32) || \
(defined(__sun) && !(defined(HAVE_SETENV) && defined(HAVE_UNSETENV)))
@@ -5123,6 +5221,9 @@ void
ruby_setenv(const char *name, const char *value)
{
#if defined(_WIN32)
+# if defined(MINGW_HAS_SECURE_API) || RUBY_MSVCRT_VERSION >= 80
+# define HAVE__WPUTENV_S 1
+# endif
VALUE buf;
WCHAR *wname;
WCHAR *wvalue = 0;
@@ -5133,23 +5234,34 @@ ruby_setenv(const char *name, const char *value)
if (value) {
int len2;
len2 = MultiByteToWideChar(CP_UTF8, 0, value, -1, NULL, 0);
+ if (check_envsize((size_t)len + len2)) { /* len and len2 include '\0' */
+ goto fail; /* 2 for '=' & '\0' */
+ }
wname = ALLOCV_N(WCHAR, buf, len + len2);
wvalue = wname + len;
MultiByteToWideChar(CP_UTF8, 0, name, -1, wname, len);
MultiByteToWideChar(CP_UTF8, 0, value, -1, wvalue, len2);
+#ifndef HAVE__WPUTENV_S
+ wname[len-1] = L'=';
+#endif
}
else {
wname = ALLOCV_N(WCHAR, buf, len + 1);
MultiByteToWideChar(CP_UTF8, 0, name, -1, wname, len);
wvalue = wname + len;
*wvalue = L'\0';
+#ifndef HAVE__WPUTENV_S
+ wname[len-1] = L'=';
+#endif
}
ENV_LOCK();
{
- /* Use _wputenv_s() instead of SetEnvironmentVariableW() to make sure
- * special variables like "TZ" are interpret by libc. */
+#ifndef HAVE__WPUTENV_S
+ failed = _wputenv(wname);
+#else
failed = _wputenv_s(wname, wvalue);
+#endif
}
ENV_UNLOCK();
@@ -5158,7 +5270,7 @@ ruby_setenv(const char *name, const char *value)
* variable from the system area. */
if (!value || !*value) {
/* putenv() doesn't handle empty value */
- if (!SetEnvironmentVariableW(wname, value ? wvalue : NULL) &&
+ if (!SetEnvironmentVariable(name, value) &&
GetLastError() != ERROR_ENVVAR_NOT_FOUND) goto fail;
}
if (failed) {
@@ -5174,7 +5286,7 @@ ruby_setenv(const char *name, const char *value)
}
ENV_UNLOCK();
- if (ret) rb_sys_fail_sprintf("setenv(%s)", name);
+ if (ret) rb_sys_fail_str(rb_sprintf("setenv(%s)", name));
}
else {
#ifdef VOID_UNSETENV
@@ -5191,7 +5303,7 @@ ruby_setenv(const char *name, const char *value)
}
ENV_UNLOCK();
- if (ret) rb_sys_fail_sprintf("unsetenv(%s)", name);
+ if (ret) rb_sys_fail_str(rb_sprintf("unsetenv(%s)", name));
#endif
}
#elif defined __sun
@@ -5208,7 +5320,7 @@ ruby_setenv(const char *name, const char *value)
mem_size = len + strlen(value) + 2;
mem_ptr = malloc(mem_size);
if (mem_ptr == NULL)
- rb_sys_fail_sprintf("malloc(%"PRIuSIZE")", mem_size);
+ rb_sys_fail_str(rb_sprintf("malloc(%"PRIuSIZE")", mem_size));
snprintf(mem_ptr, mem_size, "%s=%s", name, value);
}
@@ -5234,7 +5346,7 @@ ruby_setenv(const char *name, const char *value)
if (ret) {
free(mem_ptr);
- rb_sys_fail_sprintf("putenv(%s)", name);
+ rb_sys_fail_str(rb_sprintf("putenv(%s)", name));
}
}
#else /* WIN32 */
@@ -5298,6 +5410,8 @@ ruby_unsetenv(const char *name)
* ENV[name] = value -> value
* ENV.store(name, value) -> value
*
+ * ENV.store is an alias for ENV.[]=.
+ *
* Creates, updates, or deletes the named environment variable, returning the value.
* Both +name+ and +value+ may be instances of String.
* See {Valid Names and Values}[rdoc-ref:ENV@Valid+Names+and+Values].
@@ -5350,15 +5464,15 @@ env_aset(VALUE nm, VALUE val)
env_delete(nm);
return Qnil;
}
- StringValue(nm);
- StringValue(val);
+ SafeStringValue(nm);
+ SafeStringValue(val);
/* nm can be modified in `val.to_str`, don't get `name` before
* check for `val` */
get_env_ptr(name, nm);
get_env_ptr(value, val);
ruby_setenv(name, value);
- reset_by_modified_env(name);
+ reset_by_modified_env(name, value);
return val;
}
@@ -5538,7 +5652,7 @@ env_each_value(VALUE ehash)
* ENV.each_pair { |name, value| block } -> ENV
* ENV.each_pair -> an_enumerator
*
- * Yields each environment variable name and its value as a 2-element Array:
+ * Yields each environment variable name and its value as a 2-element \Array:
* h = {}
* ENV.each_pair { |name, value| h[name] = value } # => ENV
* h # => {"bar"=>"1", "foo"=>"0"}
@@ -5674,7 +5788,7 @@ env_delete_if(VALUE ehash)
* Returns +nil+ in the Array for each name that is not an ENV name:
* ENV.values_at('foo', 'bat', 'bar', 'bam') # => ["0", nil, "1", nil]
*
- * Returns an empty Array if no names given.
+ * Returns an empty \Array if no names given.
*
* Raises an exception if any name is invalid.
* See {Invalid Names and Values}[rdoc-ref:ENV@Invalid+Names+and+Values].
@@ -5699,6 +5813,8 @@ env_values_at(int argc, VALUE *argv, VALUE _)
* ENV.filter { |name, value| block } -> hash of name/value pairs
* ENV.filter -> an_enumerator
*
+ * ENV.filter is an alias for ENV.select.
+ *
* Yields each environment variable name and its value as a 2-element Array,
* returning a Hash of the names and values for which the block returns a truthy value:
* ENV.replace('foo' => '0', 'bar' => '1', 'baz' => '2')
@@ -5742,6 +5858,8 @@ env_select(VALUE ehash)
* ENV.filter! { |name, value| block } -> ENV or nil
* ENV.filter! -> an_enumerator
*
+ * ENV.filter! is an alias for ENV.select!.
+ *
* Yields each environment variable name and its value as a 2-element Array,
* deleting each entry for which the block returns +false+ or +nil+,
* and returning ENV if any deletions made, or +nil+ otherwise:
@@ -5909,24 +6027,23 @@ env_to_s(VALUE _)
static VALUE
env_inspect(VALUE _)
{
- VALUE i;
VALUE str = rb_str_buf_new2("{");
+ rb_encoding *enc = env_encoding();
ENV_LOCK();
{
char **env = GET_ENVIRON(environ);
while (*env) {
- char *s = strchr(*env, '=');
+ const char *s = strchr(*env, '=');
if (env != environ) {
rb_str_buf_cat2(str, ", ");
}
if (s) {
- rb_str_buf_cat2(str, "\"");
- rb_str_buf_cat(str, *env, s-*env);
- rb_str_buf_cat2(str, "\"=>");
- i = rb_inspect(rb_str_new2(s+1));
- rb_str_buf_append(str, i);
+ rb_str_buf_append(str, rb_str_inspect(env_enc_str_new(*env, s-*env, enc)));
+ rb_str_buf_cat2(str, "=>");
+ s++;
+ rb_str_buf_append(str, rb_str_inspect(env_enc_str_new(s, strlen(s), enc)));
}
env++;
}
@@ -6052,6 +6169,8 @@ env_empty_p(VALUE _)
* ENV.member?(name) -> true or false
* ENV.key?(name) -> true or false
*
+ * ENV.has_key?, ENV.member?, and ENV.key? are aliases for ENV.include?.
+ *
* Returns +true+ if there is an environment variable with the given +name+:
* ENV.replace('foo' => '0', 'bar' => '1')
* ENV.include?('foo') # => true
@@ -6214,7 +6333,7 @@ env_rassoc(VALUE dmy, VALUE obj)
static VALUE
env_key(VALUE dmy, VALUE value)
{
- StringValue(value);
+ SafeStringValue(value);
VALUE str = Qnil;
ENV_LOCK();
@@ -6532,6 +6651,8 @@ env_update_block_i(VALUE key, VALUE val, VALUE _)
* ENV.merge!(*hashes) -> ENV
* ENV.merge!(*hashes) { |name, env_val, hash_val| block } -> ENV
*
+ * ENV.update is an alias for ENV.merge!.
+ *
* Adds to ENV each key/value pair in the given +hash+; returns ENV:
* ENV.replace('foo' => '0', 'bar' => '1')
* ENV.merge!('baz' => '2', 'bat' => '3') # => {"bar"=>"1", "bat"=>"3", "baz"=>"2", "foo"=>"0"}
@@ -6621,27 +6742,27 @@ static const rb_data_type_t env_data_type = {
};
/*
- * A +Hash+ maps each of its unique keys to a specific value.
+ * A \Hash maps each of its unique keys to a specific value.
*
- * A +Hash+ has certain similarities to an Array, but:
- * - An Array index is always an Integer.
- * - A +Hash+ key can be (almost) any object.
+ * A \Hash has certain similarities to an \Array, but:
+ * - An \Array index is always an \Integer.
+ * - A \Hash key can be (almost) any object.
*
- * === +Hash+ \Data Syntax
+ * === \Hash \Data Syntax
*
- * The older syntax for +Hash+ data uses the "hash rocket," <tt>=></tt>:
+ * The older syntax for \Hash data uses the "hash rocket," <tt>=></tt>:
*
* h = {:foo => 0, :bar => 1, :baz => 2}
* h # => {:foo=>0, :bar=>1, :baz=>2}
*
- * Alternatively, but only for a +Hash+ key that's a Symbol,
+ * Alternatively, but only for a \Hash key that's a \Symbol,
* you can use a newer JSON-style syntax,
- * where each bareword becomes a Symbol:
+ * where each bareword becomes a \Symbol:
*
* h = {foo: 0, bar: 1, baz: 2}
* h # => {:foo=>0, :bar=>1, :baz=>2}
*
- * You can also use a String in place of a bareword:
+ * You can also use a \String in place of a bareword:
*
* h = {'foo': 0, 'bar': 1, 'baz': 2}
* h # => {:foo=>0, :bar=>1, :baz=>2}
@@ -6657,7 +6778,7 @@ static const rb_data_type_t env_data_type = {
* # Raises SyntaxError (syntax error, unexpected ':', expecting =>):
* h = {0: 'zero'}
*
- * +Hash+ value can be omitted, meaning that value will be fetched from the context
+ * Hash value can be omitted, meaning that value will be fetched from the context
* by the name of the key:
*
* x = 0
@@ -6667,24 +6788,24 @@ static const rb_data_type_t env_data_type = {
*
* === Common Uses
*
- * You can use a +Hash+ to give names to objects:
+ * You can use a \Hash to give names to objects:
*
* person = {name: 'Matz', language: 'Ruby'}
* person # => {:name=>"Matz", :language=>"Ruby"}
*
- * You can use a +Hash+ to give names to method arguments:
+ * You can use a \Hash to give names to method arguments:
*
* def some_method(hash)
* p hash
* end
* some_method({foo: 0, bar: 1, baz: 2}) # => {:foo=>0, :bar=>1, :baz=>2}
*
- * Note: when the last argument in a method call is a +Hash+,
+ * Note: when the last argument in a method call is a \Hash,
* the curly braces may be omitted:
*
* some_method(foo: 0, bar: 1, baz: 2) # => {:foo=>0, :bar=>1, :baz=>2}
*
- * You can use a +Hash+ to initialize an object:
+ * You can use a \Hash to initialize an object:
*
* class Dev
* attr_accessor :name, :language
@@ -6696,9 +6817,9 @@ static const rb_data_type_t env_data_type = {
* matz = Dev.new(name: 'Matz', language: 'Ruby')
* matz # => #<Dev: @name="Matz", @language="Ruby">
*
- * === Creating a +Hash+
+ * === Creating a \Hash
*
- * You can create a +Hash+ object explicitly with:
+ * You can create a \Hash object explicitly with:
*
* - A {hash literal}[rdoc-ref:syntax/literals.rdoc@Hash+Literals].
*
@@ -6706,47 +6827,47 @@ static const rb_data_type_t env_data_type = {
*
* - \Method #Hash.
*
- * You can create a +Hash+ by calling method Hash.new.
+ * You can create a \Hash by calling method Hash.new.
*
- * Create an empty +Hash+:
+ * Create an empty Hash:
*
* h = Hash.new
* h # => {}
* h.class # => Hash
*
- * You can create a +Hash+ by calling method Hash.[].
+ * You can create a \Hash by calling method Hash.[].
*
- * Create an empty +Hash+:
+ * Create an empty Hash:
*
* h = Hash[]
* h # => {}
*
- * Create a +Hash+ with initial entries:
+ * Create a \Hash with initial entries:
*
* h = Hash[foo: 0, bar: 1, baz: 2]
* h # => {:foo=>0, :bar=>1, :baz=>2}
*
- * You can create a +Hash+ by using its literal form (curly braces).
+ * You can create a \Hash by using its literal form (curly braces).
*
- * Create an empty +Hash+:
+ * Create an empty \Hash:
*
* h = {}
* h # => {}
*
- * Create a +Hash+ with initial entries:
+ * Create a \Hash with initial entries:
*
* h = {foo: 0, bar: 1, baz: 2}
* h # => {:foo=>0, :bar=>1, :baz=>2}
*
*
- * === +Hash+ Value Basics
+ * === \Hash Value Basics
*
- * The simplest way to retrieve a +Hash+ value (instance method #[]):
+ * The simplest way to retrieve a \Hash value (instance method #[]):
*
* h = {foo: 0, bar: 1, baz: 2}
* h[:foo] # => 0
*
- * The simplest way to create or update a +Hash+ value (instance method #[]=):
+ * The simplest way to create or update a \Hash value (instance method #[]=):
*
* h = {foo: 0, bar: 1, baz: 2}
* h[:bat] = 3 # => 3
@@ -6754,7 +6875,7 @@ static const rb_data_type_t env_data_type = {
* h[:foo] = 4 # => 4
* h # => {:foo=>4, :bar=>1, :baz=>2, :bat=>3}
*
- * The simplest way to delete a +Hash+ entry (instance method #delete):
+ * The simplest way to delete a \Hash entry (instance method #delete):
*
* h = {foo: 0, bar: 1, baz: 2}
* h.delete(:bar) # => 1
@@ -6762,13 +6883,13 @@ static const rb_data_type_t env_data_type = {
*
* === Entry Order
*
- * A +Hash+ object presents its entries in the order of their creation. This is seen in:
+ * A \Hash object presents its entries in the order of their creation. This is seen in:
*
* - Iterative methods such as <tt>each</tt>, <tt>each_key</tt>, <tt>each_pair</tt>, <tt>each_value</tt>.
* - Other order-sensitive methods such as <tt>shift</tt>, <tt>keys</tt>, <tt>values</tt>.
- * - The String returned by method <tt>inspect</tt>.
+ * - The \String returned by method <tt>inspect</tt>.
*
- * A new +Hash+ has its initial ordering per the given entries:
+ * A new \Hash has its initial ordering per the given entries:
*
* h = Hash[foo: 0, bar: 1]
* h # => {:foo=>0, :bar=>1}
@@ -6789,18 +6910,18 @@ static const rb_data_type_t env_data_type = {
* h[:foo] = 5
* h # => {:bar=>1, :baz=>3, :foo=>5}
*
- * === +Hash+ Keys
+ * === \Hash Keys
*
- * ==== +Hash+ Key Equivalence
+ * ==== \Hash Key Equivalence
*
* Two objects are treated as the same \hash key when their <code>hash</code> value
* is identical and the two objects are <code>eql?</code> to each other.
*
- * ==== Modifying an Active +Hash+ Key
+ * ==== Modifying an Active \Hash Key
*
- * Modifying a +Hash+ key while it is in use damages the hash's index.
+ * Modifying a \Hash key while it is in use damages the hash's index.
*
- * This +Hash+ has keys that are Arrays:
+ * This \Hash has keys that are Arrays:
*
* a0 = [ :foo, :bar ]
* a1 = [ :baz, :bat ]
@@ -6814,7 +6935,7 @@ static const rb_data_type_t env_data_type = {
* a0[0] = :bam
* a0.hash # => 1069447059
*
- * And damages the +Hash+ index:
+ * And damages the \Hash index:
*
* h.include?(a0) # => false
* h[a0] # => nil
@@ -6825,9 +6946,9 @@ static const rb_data_type_t env_data_type = {
* h.include?(a0) # => true
* h[a0] # => 0
*
- * A String key is always safe.
- * That's because an unfrozen String
- * passed as a key will be replaced by a duplicated and frozen String:
+ * A \String key is always safe.
+ * That's because an unfrozen \String
+ * passed as a key will be replaced by a duplicated and frozen \String:
*
* s = 'foo'
* s.frozen? # => false
@@ -6835,15 +6956,15 @@ static const rb_data_type_t env_data_type = {
* first_key = h.keys.first
* first_key.frozen? # => true
*
- * ==== User-Defined +Hash+ Keys
+ * ==== User-Defined \Hash Keys
*
- * To be usable as a +Hash+ key, objects must implement the methods <code>hash</code> and <code>eql?</code>.
- * Note: this requirement does not apply if the +Hash+ uses #compare_by_identity since comparison will then
+ * To be useable as a \Hash key, objects must implement the methods <code>hash</code> and <code>eql?</code>.
+ * Note: this requirement does not apply if the \Hash uses #compare_by_identity since comparison will then
* rely on the keys' object id instead of <code>hash</code> and <code>eql?</code>.
*
- * Object defines basic implementation for <code>hash</code> and <code>eq?</code> that makes each object
+ * \Object defines basic implementation for <code>hash</code> and <code>eq?</code> that makes each object
* a distinct key. Typically, user-defined classes will want to override these methods to provide meaningful
- * behavior, or for example inherit Struct that has useful definitions for these.
+ * behavior, or for example inherit \Struct that has useful definitions for these.
*
* A typical implementation of <code>hash</code> is based on the
* object's data while <code>eql?</code> is usually aliased to the overridden
@@ -6866,7 +6987,7 @@ static const rb_data_type_t env_data_type = {
* alias eql? ==
*
* def hash
- * [self.class, @author, @title].hash
+ * @author.hash ^ @title.hash # XOR
* end
* end
*
@@ -6924,9 +7045,9 @@ static const rb_data_type_t env_data_type = {
*
* To use a mutable object as default, it is recommended to use a default proc
*
- * ==== Default Proc
+ * ==== Default \Proc
*
- * When the default proc for a +Hash+ is set (i.e., not +nil+),
+ * When the default proc for a \Hash is set (i.e., not +nil+),
* the default value returned by method #[] is determined by the default proc alone.
*
* You can retrieve the default proc with method #default_proc:
@@ -6944,7 +7065,7 @@ static const rb_data_type_t env_data_type = {
*
* When the default proc is set (i.e., not +nil+)
* and method #[] is called with with a non-existent key,
- * #[] calls the default proc with both the +Hash+ object itself and the missing key,
+ * #[] calls the default proc with both the \Hash object itself and the missing key,
* then returns the proc's return value:
*
* h = Hash.new { |hash, key| "Default value for #{key}" }
@@ -6964,19 +7085,15 @@ static const rb_data_type_t env_data_type = {
*
* Note that setting the default proc will clear the default value and vice versa.
*
- * Be aware that a default proc that modifies the hash is not thread-safe in the
- * sense that multiple threads can call into the default proc concurrently for the
- * same key.
- *
* === What's Here
*
- * First, what's elsewhere. \Class +Hash+:
+ * First, what's elsewhere. \Class \Hash:
*
* - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
* - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
* which provides dozens of additional methods.
*
- * Here, class +Hash+ provides methods that are useful for:
+ * Here, class \Hash provides methods that are useful for:
*
* - {Creating a Hash}[rdoc-ref:Hash@Methods+for+Creating+a+Hash]
* - {Setting Hash State}[rdoc-ref:Hash@Methods+for+Setting+Hash+State]
@@ -6990,15 +7107,15 @@ static const rb_data_type_t env_data_type = {
* - {Transforming Keys and Values}[rdoc-ref:Hash@Methods+for+Transforming+Keys+and+Values]
* - {And more....}[rdoc-ref:Hash@Other+Methods]
*
- * \Class +Hash+ also includes methods from module Enumerable.
+ * \Class \Hash also includes methods from module Enumerable.
*
- * ==== Methods for Creating a +Hash+
+ * ==== Methods for Creating a \Hash
*
* - ::[]: Returns a new hash populated with given objects.
* - ::new: Returns a new empty hash.
* - ::try_convert: Returns a new hash created from a given object.
*
- * ==== Methods for Setting +Hash+ State
+ * ==== Methods for Setting \Hash State
*
* - #compare_by_identity: Sets +self+ to consider only identity in comparing keys.
* - #default=: Sets the default to a given value.
@@ -7014,9 +7131,10 @@ static const rb_data_type_t env_data_type = {
* - #empty?: Returns whether there are no entries.
* - #eql?: Returns whether a given object is equal to +self+.
* - #hash: Returns the integer hash code.
- * - #has_value? (aliased as #value?): Returns whether a given object is a value in +self+.
- * - #include? (aliased as #has_key?, #member?, #key?): Returns whether a given object is a key in +self+.
- * - #size (aliased as #length): Returns the count of entries.
+ * - #has_value?: Returns whether a given object is a value in +self+.
+ * - #include?, #has_key?, #member?, #key?: Returns whether a given object is a key in +self+.
+ * - #length, #size: Returns the count of entries.
+ * - #value?: Returns whether a given object is a value in +self+.
*
* ==== Methods for Comparing
*
@@ -7024,7 +7142,7 @@ static const rb_data_type_t env_data_type = {
* - #<=: Returns whether +self+ is a subset of a given object.
* - #==: Returns whether a given object is equal to +self+.
* - #>: Returns whether +self+ is a proper superset of a given object
- * - #>=: Returns whether +self+ is a superset of a given object.
+ * - #>=: Returns whether +self+ is a proper superset of a given object.
*
* ==== Methods for Fetching
*
@@ -7037,16 +7155,16 @@ static const rb_data_type_t env_data_type = {
* - #key: Returns the key for the first-found entry with a given value.
* - #keys: Returns an array containing all keys in +self+.
* - #rassoc: Returns a 2-element array consisting of the key and value
- * of the first-found entry having a given value.
+ of the first-found entry having a given value.
* - #values: Returns an array containing all values in +self+/
* - #values_at: Returns an array containing values for given keys.
*
* ==== Methods for Assigning
*
- * - #[]= (aliased as #store): Associates a given key with a given value.
+ * - #[]=, #store: Associates a given key with a given value.
* - #merge: Returns the hash formed by merging each given hash into a copy of +self+.
- * - #update (aliased as #merge!): Merges each given hash into +self+.
- * - #replace (aliased as #initialize_copy): Replaces the entire contents of +self+ with the contents of a given hash.
+ * - #merge!, #update: Merges each given hash into +self+.
+ * - #replace: Replaces the entire contents of +self+ with the contents of a given hash.
*
* ==== Methods for Deleting
*
@@ -7056,7 +7174,7 @@ static const rb_data_type_t env_data_type = {
* - #compact!: Removes all +nil+-valued entries from +self+.
* - #delete: Removes the entry for a given key.
* - #delete_if: Removes entries selected by a given block.
- * - #select! (aliased as #filter!): Keep only those entries selected by a given block.
+ * - #filter!, #select!: Keep only those entries selected by a given block.
* - #keep_if: Keep only those entries selected by a given block.
* - #reject!: Removes entries selected by a given block.
* - #shift: Removes and returns the first entry.
@@ -7065,22 +7183,22 @@ static const rb_data_type_t env_data_type = {
*
* - #compact: Returns a copy of +self+ with all +nil+-valued entries removed.
* - #except: Returns a copy of +self+ with entries removed for specified keys.
- * - #select (aliased as #filter): Returns a copy of +self+ with only those entries selected by a given block.
+ * - #filter, #select: Returns a copy of +self+ with only those entries selected by a given block.
* - #reject: Returns a copy of +self+ with entries removed as specified by a given block.
* - #slice: Returns a hash containing the entries for given keys.
*
* ==== Methods for Iterating
- * - #each_pair (aliased as #each): Calls a given block with each key-value pair.
+ * - #each, #each_pair: Calls a given block with each key-value pair.
* - #each_key: Calls a given block with each key.
* - #each_value: Calls a given block with each value.
*
* ==== Methods for Converting
*
- * - #inspect (aliased as #to_s): Returns a new String containing the hash entries.
+ * - #inspect, #to_s: Returns a new String containing the hash entries.
* - #to_a: Returns a new array of 2-element arrays;
* each nested array contains a key-value pair from +self+.
- * - #to_h: Returns +self+ if a +Hash+;
- * if a subclass of +Hash+, returns a +Hash+ containing the entries from +self+.
+ * - #to_h: Returns +self+ if a \Hash;
+ * if a subclass of \Hash, returns a \Hash containing the entries from +self+.
* - #to_hash: Returns +self+.
* - #to_proc: Returns a proc that maps a given key to its value.
*
@@ -7111,9 +7229,9 @@ Init_Hash(void)
rb_define_alloc_func(rb_cHash, empty_hash_alloc);
rb_define_singleton_method(rb_cHash, "[]", rb_hash_s_create, -1);
rb_define_singleton_method(rb_cHash, "try_convert", rb_hash_s_try_convert, 1);
+ rb_define_method(rb_cHash, "initialize", rb_hash_initialize, -1);
rb_define_method(rb_cHash, "initialize_copy", rb_hash_replace, 1);
rb_define_method(rb_cHash, "rehash", rb_hash_rehash, 0);
- rb_define_method(rb_cHash, "freeze", rb_hash_freeze, 0);
rb_define_method(rb_cHash, "to_hash", rb_hash_to_hash, 0);
rb_define_method(rb_cHash, "to_h", rb_hash_to_h, 0);
@@ -7200,20 +7318,17 @@ Init_Hash(void)
rb_define_singleton_method(rb_cHash, "ruby2_keywords_hash?", rb_hash_s_ruby2_keywords_hash_p, 1);
rb_define_singleton_method(rb_cHash, "ruby2_keywords_hash", rb_hash_s_ruby2_keywords_hash, 1);
- rb_cHash_empty_frozen = rb_hash_freeze(rb_hash_new());
- rb_vm_register_global_object(rb_cHash_empty_frozen);
-
/* Document-class: ENV
*
- * +ENV+ is a hash-like accessor for environment variables.
+ * ENV is a hash-like accessor for environment variables.
*
* === Interaction with the Operating System
*
- * The +ENV+ object interacts with the operating system's environment variables:
+ * The ENV object interacts with the operating system's environment variables:
*
- * - When you get the value for a name in +ENV+, the value is retrieved from among the current environment variables.
- * - When you create or set a name-value pair in +ENV+, the name and value are immediately set in the environment variables.
- * - When you delete a name-value pair in +ENV+, it is immediately deleted from the environment variables.
+ * - When you get the value for a name in ENV, the value is retrieved from among the current environment variables.
+ * - When you create or set a name-value pair in ENV, the name and value are immediately set in the environment variables.
+ * - When you delete a name-value pair in ENV, it is immediately deleted from the environment variables.
*
* === Names and Values
*
@@ -7263,33 +7378,33 @@ Init_Hash(void)
*
* === About Ordering
*
- * +ENV+ enumerates its name/value pairs in the order found
+ * ENV enumerates its name/value pairs in the order found
* in the operating system's environment variables.
- * Therefore the ordering of +ENV+ content is OS-dependent, and may be indeterminate.
+ * Therefore the ordering of ENV content is OS-dependent, and may be indeterminate.
*
* This will be seen in:
- * - A Hash returned by an +ENV+ method.
- * - An Enumerator returned by an +ENV+ method.
+ * - A Hash returned by an ENV method.
+ * - An Enumerator returned by an ENV method.
* - An Array returned by ENV.keys, ENV.values, or ENV.to_a.
* - The String returned by ENV.inspect.
* - The Array returned by ENV.shift.
* - The name returned by ENV.key.
*
* === About the Examples
- * Some methods in +ENV+ return +ENV+ itself. Typically, there are many environment variables.
- * It's not useful to display a large +ENV+ in the examples here,
- * so most example snippets begin by resetting the contents of +ENV+:
- * - ENV.replace replaces +ENV+ with a new collection of entries.
- * - ENV.clear empties +ENV+.
+ * Some methods in ENV return ENV itself. Typically, there are many environment variables.
+ * It's not useful to display a large ENV in the examples here,
+ * so most example snippets begin by resetting the contents of ENV:
+ * - ENV.replace replaces ENV with a new collection of entries.
+ * - ENV.clear empties ENV.
*
- * === What's Here
+ * == What's Here
*
- * First, what's elsewhere. \Class +ENV+:
+ * First, what's elsewhere. \Class \ENV:
*
* - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
* - Extends {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
*
- * Here, class +ENV+ provides methods that are useful for:
+ * Here, class \ENV provides methods that are useful for:
*
* - {Querying}[rdoc-ref:ENV@Methods+for+Querying]
* - {Assigning}[rdoc-ref:ENV@Methods+for+Assigning]
@@ -7298,26 +7413,26 @@ Init_Hash(void)
* - {Converting}[rdoc-ref:ENV@Methods+for+Converting]
* - {And more ....}[rdoc-ref:ENV@More+Methods]
*
- * ==== Methods for Querying
+ * === Methods for Querying
*
* - ::[]: Returns the value for the given environment variable name if it exists:
- * - ::empty?: Returns whether +ENV+ is empty.
- * - ::has_value?, ::value?: Returns whether the given value is in +ENV+.
+ * - ::empty?: Returns whether \ENV is empty.
+ * - ::has_value?, ::value?: Returns whether the given value is in \ENV.
* - ::include?, ::has_key?, ::key?, ::member?: Returns whether the given name
- is in +ENV+.
+ is in \ENV.
* - ::key: Returns the name of the first entry with the given value.
* - ::size, ::length: Returns the number of entries.
* - ::value?: Returns whether any entry has the given value.
*
- * ==== Methods for Assigning
+ * === Methods for Assigning
*
* - ::[]=, ::store: Creates, updates, or deletes the named environment variable.
- * - ::clear: Removes every environment variable; returns +ENV+:
- * - ::update, ::merge!: Adds to +ENV+ each key/value pair in the given hash.
- * - ::replace: Replaces the entire content of the +ENV+
+ * - ::clear: Removes every environment variable; returns \ENV:
+ * - ::update, ::merge!: Adds to \ENV each key/value pair in the given hash.
+ * - ::replace: Replaces the entire content of the \ENV
* with the name/value pairs in the given hash.
*
- * ==== Methods for Deleting
+ * === Methods for Deleting
*
* - ::delete: Deletes the named environment variable name if it exists.
* - ::delete_if: Deletes entries selected by the block.
@@ -7326,22 +7441,22 @@ Init_Hash(void)
* - ::select!, ::filter!: Deletes entries selected by the block.
* - ::shift: Removes and returns the first entry.
*
- * ==== Methods for Iterating
+ * === Methods for Iterating
*
* - ::each, ::each_pair: Calls the block with each name/value pair.
* - ::each_key: Calls the block with each name.
* - ::each_value: Calls the block with each value.
*
- * ==== Methods for Converting
+ * === Methods for Converting
*
* - ::assoc: Returns a 2-element array containing the name and value
* of the named environment variable if it exists:
- * - ::clone: Returns +ENV+ (and issues a warning).
+ * - ::clone: Returns \ENV (and issues a warning).
* - ::except: Returns a hash of all name/value pairs except those given.
* - ::fetch: Returns the value for the given name.
- * - ::inspect: Returns the contents of +ENV+ as a string.
- * - ::invert: Returns a hash whose keys are the +ENV+ values,
- and whose values are the corresponding +ENV+ names.
+ * - ::inspect: Returns the contents of \ENV as a string.
+ * - ::invert: Returns a hash whose keys are the ENV values,
+ and whose values are the corresponding ENV names.
* - ::keys: Returns an array of all names.
* - ::rassoc: Returns the name and value of the first found entry
* that has the given value.
@@ -7355,11 +7470,11 @@ Init_Hash(void)
* - ::values: Returns all values as an array.
* - ::values_at: Returns an array of the values for the given name.
*
- * ==== More Methods
+ * === More Methods
*
* - ::dup: Raises an exception.
* - ::freeze: Raises an exception.
- * - ::rehash: Returns +nil+, without modifying +ENV+.
+ * - ::rehash: Returns +nil+, without modifying \ENV.
*
*/
@@ -7430,13 +7545,14 @@ Init_Hash(void)
rb_undef_method(envtbl_class, "initialize_dup");
/*
- * +ENV+ is a Hash-like accessor for environment variables.
+ * ENV is a Hash-like accessor for environment variables.
*
* See ENV (the class) for more details.
*/
rb_define_global_const("ENV", envtbl);
+ /* for callcc */
+ ruby_register_rollback_func_for_ensure(hash_foreach_ensure, hash_foreach_ensure_rollback);
+
HASH_ASSERT(sizeof(ar_hint_t) * RHASH_AR_TABLE_MAX_SIZE == sizeof(VALUE));
}
-
-#include "hash.rbinc"
diff --git a/hash.rb b/hash.rb
deleted file mode 100644
index 08edb745a4..0000000000
--- a/hash.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-class Hash
- # call-seq:
- # Hash.new(default_value = nil) -> new_hash
- # Hash.new(default_value = nil, capacity: size) -> new_hash
- # Hash.new {|hash, key| ... } -> new_hash
- # Hash.new(capacity: size) {|hash, key| ... } -> new_hash
- #
- # Returns a new empty +Hash+ object.
- #
- # The initial default value and initial default proc for the new hash
- # depend on which form above was used. See {Default Values}[rdoc-ref:Hash@Default+Values].
- #
- # If neither an argument nor a block is given,
- # initializes both the default value and the default proc to <tt>nil</tt>:
- # h = Hash.new
- # h.default # => nil
- # h.default_proc # => nil
- #
- # If argument <tt>default_value</tt> is given but no block is given,
- # initializes the default value to the given <tt>default_value</tt>
- # and the default proc to <tt>nil</tt>:
- # h = Hash.new(false)
- # h.default # => false
- # h.default_proc # => nil
- #
- # If a block is given but no <tt>default_value</tt>, stores the block as the default proc
- # and sets the default value to <tt>nil</tt>:
- # h = Hash.new {|hash, key| "Default value for #{key}" }
- # h.default # => nil
- # h.default_proc.class # => Proc
- # h[:nosuch] # => "Default value for nosuch"
- #
- # If both a block and a <tt>default_value</tt> are given, raises an +ArgumentError+
- #
- # If the optional keyword argument +capacity+ is given, the hash will be allocated
- # with enough capacity to accommodate this many keys without having to be resized.
- def initialize(ifnone = (ifnone_unset = true), capacity: 0, &block)
- Primitive.rb_hash_init(capacity, ifnone_unset, ifnone, block)
- end
-end
diff --git a/hrtime.h b/hrtime.h
index 2ca7b0c088..7ed4e6b04c 100644
--- a/hrtime.h
+++ b/hrtime.h
@@ -6,8 +6,6 @@
# include <sys/time.h>
#endif
-#include "internal/compilers.h"
-
/*
* Hi-res monotonic clock. It is currently nsec resolution, which has over
* 500 years of range (with an unsigned 64-bit integer). Developers
@@ -63,11 +61,7 @@ rb_hrtime_mul(rb_hrtime_t a, rb_hrtime_t b)
{
rb_hrtime_t c;
-#ifdef ckd_mul
- if (ckd_mul(&c, a, b))
- return RB_HRTIME_MAX;
-
-#elif __has_builtin(__builtin_mul_overflow)
+#ifdef HAVE_BUILTIN___BUILTIN_MUL_OVERFLOW
if (__builtin_mul_overflow(a, b, &c))
return RB_HRTIME_MAX;
#else
@@ -87,11 +81,7 @@ rb_hrtime_add(rb_hrtime_t a, rb_hrtime_t b)
{
rb_hrtime_t c;
-#ifdef ckd_add
- if (ckd_add(&c, a, b))
- return RB_HRTIME_MAX;
-
-#elif __has_builtin(__builtin_add_overflow)
+#ifdef HAVE_BUILTIN___BUILTIN_ADD_OVERFLOW
if (__builtin_add_overflow(a, b, &c))
return RB_HRTIME_MAX;
#else
diff --git a/id_table.c b/id_table.c
index 6bb067d09a..a9a041b955 100644
--- a/id_table.c
+++ b/id_table.c
@@ -92,7 +92,7 @@ rb_id_table_init(struct rb_id_table *tbl, int capa)
return tbl;
}
-struct rb_id_table *
+MJIT_FUNC_EXPORTED struct rb_id_table *
rb_id_table_create(size_t capa)
{
struct rb_id_table *tbl = ALLOC(struct rb_id_table);
@@ -150,7 +150,7 @@ hash_table_raw_insert(struct rb_id_table *tbl, id_key_t key, VALUE val)
int mask = tbl->capa - 1;
int ix = key & mask;
int d = 1;
- RUBY_ASSERT(key != 0);
+ assert(key != 0);
while (ITEM_KEY_ISSET(tbl, ix)) {
ITEM_SET_COLLIDED(tbl, ix);
ix = (ix + d) & mask;
@@ -223,7 +223,7 @@ hash_table_show(struct rb_id_table *tbl)
}
#endif
-int
+MJIT_FUNC_EXPORTED int
rb_id_table_lookup(struct rb_id_table *tbl, ID id, VALUE *valp)
{
id_key_t key = id2key(id);
@@ -253,7 +253,7 @@ rb_id_table_insert_key(struct rb_id_table *tbl, const id_key_t key, const VALUE
return TRUE;
}
-int
+MJIT_FUNC_EXPORTED int
rb_id_table_insert(struct rb_id_table *tbl, ID id, VALUE val)
{
return rb_id_table_insert_key(tbl, id2key(id), val);
@@ -276,7 +276,7 @@ rb_id_table_foreach(struct rb_id_table *tbl, rb_id_table_foreach_func_t *func, v
if (ITEM_KEY_ISSET(tbl, i)) {
const id_key_t key = ITEM_GET_KEY(tbl, i);
enum rb_id_table_iterator_result ret = (*func)(key2id(key), tbl->items[i].val, data);
- RUBY_ASSERT(key != 0);
+ assert(key != 0);
if (ret == ID_TABLE_DELETE)
hash_delete_index(tbl, i);
diff --git a/imemo.c b/imemo.c
deleted file mode 100644
index ac094eb931..0000000000
--- a/imemo.c
+++ /dev/null
@@ -1,597 +0,0 @@
-
-#include "constant.h"
-#include "id_table.h"
-#include "internal.h"
-#include "internal/imemo.h"
-#include "vm_callinfo.h"
-
-size_t rb_iseq_memsize(const rb_iseq_t *iseq);
-void rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating);
-void rb_iseq_free(const rb_iseq_t *iseq);
-
-const char *
-rb_imemo_name(enum imemo_type type)
-{
- // put no default case to get a warning if an imemo type is missing
- switch (type) {
-#define IMEMO_NAME(x) case imemo_##x: return #x;
- IMEMO_NAME(ast);
- IMEMO_NAME(callcache);
- IMEMO_NAME(callinfo);
- IMEMO_NAME(constcache);
- IMEMO_NAME(cref);
- IMEMO_NAME(env);
- IMEMO_NAME(ifunc);
- IMEMO_NAME(iseq);
- IMEMO_NAME(memo);
- IMEMO_NAME(ment);
- IMEMO_NAME(parser_strterm);
- IMEMO_NAME(svar);
- IMEMO_NAME(throw_data);
- IMEMO_NAME(tmpbuf);
-#undef IMEMO_NAME
- default:
- rb_bug("unreachable");
- }
-}
-
-/* =========================================================================
- * allocation
- * ========================================================================= */
-
-VALUE
-rb_imemo_new(enum imemo_type type, VALUE v0)
-{
- size_t size = RVALUE_SIZE;
- VALUE flags = T_IMEMO | FL_WB_PROTECTED | (type << FL_USHIFT);
- NEWOBJ_OF(obj, void, v0, flags, size, 0);
-
- return (VALUE)obj;
-}
-
-static rb_imemo_tmpbuf_t *
-rb_imemo_tmpbuf_new(void)
-{
- size_t size = sizeof(struct rb_imemo_tmpbuf_struct);
- VALUE flags = T_IMEMO | (imemo_tmpbuf << FL_USHIFT);
- NEWOBJ_OF(obj, struct rb_imemo_tmpbuf_struct, 0, flags, size, 0);
-
- return obj;
-}
-
-void *
-rb_alloc_tmp_buffer_with_count(volatile VALUE *store, size_t size, size_t cnt)
-{
- void *ptr;
- rb_imemo_tmpbuf_t *tmpbuf;
-
- /* Keep the order; allocate an empty imemo first then xmalloc, to
- * get rid of potential memory leak */
- tmpbuf = rb_imemo_tmpbuf_new();
- *store = (VALUE)tmpbuf;
- ptr = ruby_xmalloc(size);
- tmpbuf->ptr = ptr;
- tmpbuf->cnt = cnt;
-
- return ptr;
-}
-
-void *
-rb_alloc_tmp_buffer(volatile VALUE *store, long len)
-{
- long cnt;
-
- if (len < 0 || (cnt = (long)roomof(len, sizeof(VALUE))) < 0) {
- rb_raise(rb_eArgError, "negative buffer size (or size too big)");
- }
-
- return rb_alloc_tmp_buffer_with_count(store, len, cnt);
-}
-
-void
-rb_free_tmp_buffer(volatile VALUE *store)
-{
- rb_imemo_tmpbuf_t *s = (rb_imemo_tmpbuf_t*)ATOMIC_VALUE_EXCHANGE(*store, 0);
- if (s) {
- void *ptr = ATOMIC_PTR_EXCHANGE(s->ptr, 0);
- s->cnt = 0;
- ruby_xfree(ptr);
- }
-}
-
-rb_imemo_tmpbuf_t *
-rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt)
-{
- rb_imemo_tmpbuf_t *tmpbuf = rb_imemo_tmpbuf_new();
- tmpbuf->ptr = buf;
- tmpbuf->next = old_heap;
- tmpbuf->cnt = cnt;
-
- return tmpbuf;
-}
-
-#if IMEMO_DEBUG
-VALUE
-rb_imemo_new_debug(enum imemo_type type, VALUE v0, const char *file, int line)
-{
- VALUE memo = rb_imemo_new(type, v0);
- fprintf(stderr, "memo %p (type: %d) @ %s:%d\n", (void *)memo, imemo_type(memo), file, line);
- return memo;
-}
-#endif
-
-/* =========================================================================
- * memsize
- * ========================================================================= */
-
-size_t
-rb_imemo_memsize(VALUE obj)
-{
- size_t size = 0;
- switch (imemo_type(obj)) {
- case imemo_ast:
- rb_bug("imemo_ast is obsolete");
-
- break;
- case imemo_callcache:
- break;
- case imemo_callinfo:
- break;
- case imemo_constcache:
- break;
- case imemo_cref:
- break;
- case imemo_env:
- size += ((rb_env_t *)obj)->env_size * sizeof(VALUE);
-
- break;
- case imemo_ifunc:
- break;
- case imemo_iseq:
- size += rb_iseq_memsize((rb_iseq_t *)obj);
-
- break;
- case imemo_memo:
- break;
- case imemo_ment:
- size += sizeof(((rb_method_entry_t *)obj)->def);
-
- break;
- case imemo_parser_strterm:
- break;
- case imemo_svar:
- break;
- case imemo_throw_data:
- break;
- case imemo_tmpbuf:
- size += ((rb_imemo_tmpbuf_t *)obj)->cnt * sizeof(VALUE);
-
- break;
- default:
- rb_bug("unreachable");
- }
-
- return size;
-}
-
-/* =========================================================================
- * mark
- * ========================================================================= */
-
-static enum rb_id_table_iterator_result
-cc_table_mark_i(VALUE ccs_ptr, void *data)
-{
- struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
- VM_ASSERT(vm_ccs_p(ccs));
-#if VM_CHECK_MODE > 0
- VALUE klass = (VALUE)data;
-
- VALUE lookup_val;
- VM_ASSERT(rb_id_table_lookup(RCLASS_CC_TBL(klass), ccs->cme->called_id, &lookup_val));
- VM_ASSERT(lookup_val == ccs_ptr);
-#endif
-
- if (METHOD_ENTRY_INVALIDATED(ccs->cme)) {
- rb_vm_ccs_free(ccs);
- return ID_TABLE_DELETE;
- }
- else {
- rb_gc_mark_movable((VALUE)ccs->cme);
-
- for (int i=0; i<ccs->len; i++) {
- VM_ASSERT(klass == ccs->entries[i].cc->klass);
- VM_ASSERT(vm_cc_check_cme(ccs->entries[i].cc, ccs->cme));
-
- rb_gc_mark_movable((VALUE)ccs->entries[i].cc);
- }
- return ID_TABLE_CONTINUE;
- }
-}
-
-void
-rb_cc_table_mark(VALUE klass)
-{
- struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
- if (cc_tbl) {
- rb_id_table_foreach_values(cc_tbl, cc_table_mark_i, (void *)klass);
- }
-}
-
-static bool
-moved_or_living_object_strictly_p(VALUE obj)
-{
- return obj && (!rb_objspace_garbage_object_p(obj) || BUILTIN_TYPE(obj) == T_MOVED);
-}
-
-static void
-mark_and_move_method_entry(rb_method_entry_t *ment, bool reference_updating)
-{
- rb_method_definition_t *def = ment->def;
-
- rb_gc_mark_and_move(&ment->owner);
- rb_gc_mark_and_move(&ment->defined_class);
-
- if (def) {
- switch (def->type) {
- case VM_METHOD_TYPE_ISEQ:
- if (def->body.iseq.iseqptr) {
- rb_gc_mark_and_move_ptr(&def->body.iseq.iseqptr);
- }
- rb_gc_mark_and_move_ptr(&def->body.iseq.cref);
-
- if (!reference_updating) {
- if (def->iseq_overload && ment->defined_class) {
- // it can be a key of "overloaded_cme" table
- // so it should be pinned.
- rb_gc_mark((VALUE)ment);
- }
- }
- break;
- case VM_METHOD_TYPE_ATTRSET:
- case VM_METHOD_TYPE_IVAR:
- rb_gc_mark_and_move(&def->body.attr.location);
- break;
- case VM_METHOD_TYPE_BMETHOD:
- rb_gc_mark_and_move(&def->body.bmethod.proc);
- if (!reference_updating) {
- if (def->body.bmethod.hooks) rb_hook_list_mark(def->body.bmethod.hooks);
- }
- break;
- case VM_METHOD_TYPE_ALIAS:
- rb_gc_mark_and_move_ptr(&def->body.alias.original_me);
- return;
- case VM_METHOD_TYPE_REFINED:
- rb_gc_mark_and_move_ptr(&def->body.refined.orig_me);
- break;
- case VM_METHOD_TYPE_CFUNC:
- case VM_METHOD_TYPE_ZSUPER:
- case VM_METHOD_TYPE_MISSING:
- case VM_METHOD_TYPE_OPTIMIZED:
- case VM_METHOD_TYPE_UNDEF:
- case VM_METHOD_TYPE_NOTIMPLEMENTED:
- break;
- }
- }
-}
-
-void
-rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
-{
- switch (imemo_type(obj)) {
- case imemo_ast:
- rb_bug("imemo_ast is obsolete");
-
- break;
- case imemo_callcache: {
- /* cc is callcache.
- *
- * cc->klass (klass) should not be marked because if the klass is
- * free'ed, the cc->klass will be cleared by `vm_cc_invalidate()`.
- *
- * cc->cme (cme) should not be marked because if cc is invalidated
- * when cme is free'ed.
- * - klass marks cme if klass uses cme.
- * - caller classe's ccs->cme marks cc->cme.
- * - if cc is invalidated (klass doesn't refer the cc),
- * cc is invalidated by `vm_cc_invalidate()` and cc->cme is
- * not be accessed.
- * - On the multi-Ractors, cme will be collected with global GC
- * so that it is safe if GC is not interleaving while accessing
- * cc and cme.
- * - However, cc_type_super and cc_type_refinement are not chained
- * from ccs so cc->cme should be marked; the cme might be
- * reachable only through cc in these cases.
- */
- struct rb_callcache *cc = (struct rb_callcache *)obj;
- if (reference_updating) {
- if (!cc->klass) {
- // already invalidated
- }
- else {
- if (moved_or_living_object_strictly_p(cc->klass) &&
- moved_or_living_object_strictly_p((VALUE)cc->cme_)) {
- *((VALUE *)&cc->klass) = rb_gc_location(cc->klass);
- *((struct rb_callable_method_entry_struct **)&cc->cme_) =
- (struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)cc->cme_);
- }
- else {
- vm_cc_invalidate(cc);
- }
- }
- }
- else {
- if (vm_cc_super_p(cc) || vm_cc_refinement_p(cc)) {
- rb_gc_mark_movable((VALUE)cc->cme_);
- rb_gc_mark_movable((VALUE)cc->klass);
- }
- }
-
- break;
- }
- case imemo_callinfo:
- break;
- case imemo_constcache: {
- struct iseq_inline_constant_cache_entry *ice = (struct iseq_inline_constant_cache_entry *)obj;
-
- rb_gc_mark_and_move(&ice->value);
-
- break;
- }
- case imemo_cref: {
- rb_cref_t *cref = (rb_cref_t *)obj;
-
- rb_gc_mark_and_move(&cref->klass_or_self);
- rb_gc_mark_and_move_ptr(&cref->next);
- rb_gc_mark_and_move(&cref->refinements);
-
- break;
- }
- case imemo_env: {
- rb_env_t *env = (rb_env_t *)obj;
-
- if (LIKELY(env->ep)) {
- // just after newobj() can be NULL here.
- RUBY_ASSERT(rb_gc_location(env->ep[VM_ENV_DATA_INDEX_ENV]) == rb_gc_location(obj));
- RUBY_ASSERT(reference_updating || VM_ENV_ESCAPED_P(env->ep));
-
- for (unsigned int i = 0; i < env->env_size; i++) {
- rb_gc_mark_and_move((VALUE *)&env->env[i]);
- }
-
- rb_gc_mark_and_move_ptr(&env->iseq);
-
- if (reference_updating) {
- ((VALUE *)env->ep)[VM_ENV_DATA_INDEX_ENV] = rb_gc_location(env->ep[VM_ENV_DATA_INDEX_ENV]);
- }
- else {
- if (!VM_ENV_FLAGS(env->ep, VM_ENV_FLAG_WB_REQUIRED)) {
- VM_ENV_FLAGS_SET(env->ep, VM_ENV_FLAG_WB_REQUIRED);
- }
- rb_gc_mark_movable( (VALUE)rb_vm_env_prev_env(env));
- }
- }
-
- break;
- }
- case imemo_ifunc: {
- struct vm_ifunc *ifunc = (struct vm_ifunc *)obj;
-
- if (!reference_updating) {
- rb_gc_mark_maybe((VALUE)ifunc->data);
- }
-
- break;
- }
- case imemo_iseq:
- rb_iseq_mark_and_move((rb_iseq_t *)obj, reference_updating);
- break;
- case imemo_memo: {
- struct MEMO *memo = (struct MEMO *)obj;
-
- rb_gc_mark_and_move((VALUE *)&memo->v1);
- rb_gc_mark_and_move((VALUE *)&memo->v2);
- if (!reference_updating) {
- rb_gc_mark_maybe(memo->u3.value);
- }
-
- break;
- }
- case imemo_ment:
- mark_and_move_method_entry((rb_method_entry_t *)obj, reference_updating);
- break;
- case imemo_parser_strterm:
- break;
- case imemo_svar: {
- struct vm_svar *svar = (struct vm_svar *)obj;
-
- rb_gc_mark_and_move((VALUE *)&svar->cref_or_me);
- rb_gc_mark_and_move((VALUE *)&svar->lastline);
- rb_gc_mark_and_move((VALUE *)&svar->backref);
- rb_gc_mark_and_move((VALUE *)&svar->others);
-
- break;
- }
- case imemo_throw_data: {
- struct vm_throw_data *throw_data = (struct vm_throw_data *)obj;
-
- rb_gc_mark_and_move((VALUE *)&throw_data->throw_obj);
-
- break;
- }
- case imemo_tmpbuf: {
- const rb_imemo_tmpbuf_t *m = (const rb_imemo_tmpbuf_t *)obj;
-
- if (!reference_updating) {
- do {
- rb_gc_mark_locations(m->ptr, m->ptr + m->cnt);
- } while ((m = m->next) != NULL);
- }
-
- break;
- }
- default:
- rb_bug("unreachable");
- }
-}
-
-/* =========================================================================
- * free
- * ========================================================================= */
-
-static enum rb_id_table_iterator_result
-free_const_entry_i(VALUE value, void *data)
-{
- rb_const_entry_t *ce = (rb_const_entry_t *)value;
- xfree(ce);
- return ID_TABLE_CONTINUE;
-}
-
-void
-rb_free_const_table(struct rb_id_table *tbl)
-{
- rb_id_table_foreach_values(tbl, free_const_entry_i, 0);
- rb_id_table_free(tbl);
-}
-
-// alive: if false, target pointers can be freed already.
-static void
-vm_ccs_free(struct rb_class_cc_entries *ccs, int alive, VALUE klass)
-{
- if (ccs->entries) {
- for (int i=0; i<ccs->len; i++) {
- const struct rb_callcache *cc = ccs->entries[i].cc;
- if (!alive) {
- void *ptr = asan_unpoison_object_temporary((VALUE)cc);
- // ccs can be free'ed.
- if (!rb_objspace_garbage_object_p((VALUE)cc) &&
- IMEMO_TYPE_P(cc, imemo_callcache) &&
- cc->klass == klass) {
- // OK. maybe target cc.
- }
- else {
- if (ptr) {
- asan_poison_object((VALUE)cc);
- }
- continue;
- }
- if (ptr) {
- asan_poison_object((VALUE)cc);
- }
- }
-
- VM_ASSERT(!vm_cc_super_p(cc) && !vm_cc_refinement_p(cc));
- vm_cc_invalidate(cc);
- }
- ruby_xfree(ccs->entries);
- }
- ruby_xfree(ccs);
-}
-
-void
-rb_vm_ccs_free(struct rb_class_cc_entries *ccs)
-{
- RB_DEBUG_COUNTER_INC(ccs_free);
- vm_ccs_free(ccs, true, Qundef);
-}
-
-static enum rb_id_table_iterator_result
-cc_table_free_i(VALUE ccs_ptr, void *data)
-{
- struct rb_class_cc_entries *ccs = (struct rb_class_cc_entries *)ccs_ptr;
- VALUE klass = (VALUE)data;
- VM_ASSERT(vm_ccs_p(ccs));
-
- vm_ccs_free(ccs, false, klass);
-
- return ID_TABLE_CONTINUE;
-}
-
-void
-rb_cc_table_free(VALUE klass)
-{
- struct rb_id_table *cc_tbl = RCLASS_CC_TBL(klass);
-
- if (cc_tbl) {
- rb_id_table_foreach_values(cc_tbl, cc_table_free_i, (void *)klass);
- rb_id_table_free(cc_tbl);
- }
-}
-
-void
-rb_imemo_free(VALUE obj)
-{
- switch (imemo_type(obj)) {
- case imemo_ast:
- rb_bug("imemo_ast is obsolete");
-
- break;
- case imemo_callcache:
- RB_DEBUG_COUNTER_INC(obj_imemo_callcache);
-
- break;
- case imemo_callinfo:{
- const struct rb_callinfo *ci = ((const struct rb_callinfo *)obj);
-
- rb_vm_ci_free(ci);
- if (ci->kwarg) {
- ((struct rb_callinfo_kwarg *)ci->kwarg)->references--;
- if (ci->kwarg->references == 0) xfree((void *)ci->kwarg);
- }
- RB_DEBUG_COUNTER_INC(obj_imemo_callinfo);
-
- break;
- }
- case imemo_constcache:
- RB_DEBUG_COUNTER_INC(obj_imemo_constcache);
-
- break;
- case imemo_cref:
- RB_DEBUG_COUNTER_INC(obj_imemo_cref);
-
- break;
- case imemo_env: {
- rb_env_t *env = (rb_env_t *)obj;
-
- RUBY_ASSERT(VM_ENV_ESCAPED_P(env->ep));
- xfree((VALUE *)env->env);
- RB_DEBUG_COUNTER_INC(obj_imemo_env);
-
- break;
- }
- case imemo_ifunc:
- RB_DEBUG_COUNTER_INC(obj_imemo_ifunc);
- break;
- case imemo_iseq:
- rb_iseq_free((rb_iseq_t *)obj);
- RB_DEBUG_COUNTER_INC(obj_imemo_iseq);
-
- break;
- case imemo_memo:
- RB_DEBUG_COUNTER_INC(obj_imemo_memo);
-
- break;
- case imemo_ment:
- rb_free_method_entry((rb_method_entry_t *)obj);
- RB_DEBUG_COUNTER_INC(obj_imemo_ment);
-
- break;
- case imemo_parser_strterm:
- RB_DEBUG_COUNTER_INC(obj_imemo_parser_strterm);
-
- break;
- case imemo_svar:
- RB_DEBUG_COUNTER_INC(obj_imemo_svar);
- break;
- case imemo_throw_data:
- RB_DEBUG_COUNTER_INC(obj_imemo_throw_data);
-
- break;
- case imemo_tmpbuf:
- xfree(((rb_imemo_tmpbuf_t *)obj)->ptr);
- RB_DEBUG_COUNTER_INC(obj_imemo_tmpbuf);
-
- break;
- default:
- rb_bug("unreachable");
- }
-}
diff --git a/include/ruby/assert.h b/include/ruby/assert.h
index acc5e5bbfc..0c052363bc 100644
--- a/include/ruby/assert.h
+++ b/include/ruby/assert.h
@@ -22,7 +22,6 @@
*/
#include "ruby/internal/assume.h"
#include "ruby/internal/attr/cold.h"
-#include "ruby/internal/attr/format.h"
#include "ruby/internal/attr/noreturn.h"
#include "ruby/internal/cast.h"
#include "ruby/internal/dllexport.h"
@@ -133,11 +132,6 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
RBIMPL_ATTR_NORETURN()
RBIMPL_ATTR_COLD()
void rb_assert_failure(const char *file, int line, const char *name, const char *expr);
-
-RBIMPL_ATTR_NORETURN()
-RBIMPL_ATTR_COLD()
-RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 5, 6)
-void rb_assert_failure_detail(const char *file, int line, const char *name, const char *expr, const char *fmt, ...);
RBIMPL_SYMBOL_EXPORT_END()
#ifdef RUBY_FUNCTION_NAME_STRING
@@ -153,28 +147,8 @@ RBIMPL_SYMBOL_EXPORT_END()
*
* @param mesg The message to display.
*/
-#if defined(HAVE___VA_OPT__)
-# if RBIMPL_HAS_WARNING("-Wgnu-zero-variadic-macro-arguments")
-/* __VA_OPT__ is to be used for the zero variadic macro arguments
- * cases. */
-RBIMPL_WARNING_IGNORED(-Wgnu-zero-variadic-macro-arguments)
-# endif
-# define RBIMPL_VA_OPT_ARGS(...) __VA_OPT__(,) __VA_ARGS__
-
-# define RUBY_ASSERT_FAIL(mesg, ...) \
- rb_assert_failure##__VA_OPT__(_detail)( \
- __FILE__, __LINE__, RBIMPL_ASSERT_FUNC, mesg RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
-#elif !defined(__cplusplus)
-# define RBIMPL_VA_OPT_ARGS(...)
-
-# define RUBY_ASSERT_FAIL(mesg, ...) \
+#define RUBY_ASSERT_FAIL(mesg) \
rb_assert_failure(__FILE__, __LINE__, RBIMPL_ASSERT_FUNC, mesg)
-#else
-# undef RBIMPL_VA_OPT_ARGS
-
-# define RUBY_ASSERT_FAIL(mesg) \
- rb_assert_failure(__FILE__, __LINE__, RBIMPL_ASSERT_FUNC, mesg)
-#endif
/**
* Asserts that the expression is truthy. If not aborts with the message.
@@ -182,25 +156,15 @@ RBIMPL_WARNING_IGNORED(-Wgnu-zero-variadic-macro-arguments)
* @param expr What supposedly evaluates to true.
* @param mesg The message to display on failure.
*/
-#if defined(RBIMPL_VA_OPT_ARGS)
-# define RUBY_ASSERT_MESG(expr, ...) \
- (RB_LIKELY(expr) ? RBIMPL_ASSERT_NOTHING : RUBY_ASSERT_FAIL(__VA_ARGS__))
-#else
-# define RUBY_ASSERT_MESG(expr, mesg) \
+#define RUBY_ASSERT_MESG(expr, mesg) \
(RB_LIKELY(expr) ? RBIMPL_ASSERT_NOTHING : RUBY_ASSERT_FAIL(mesg))
-#endif
/**
* A variant of #RUBY_ASSERT that does not interface with #RUBY_DEBUG.
*
* @copydetails #RUBY_ASSERT
*/
-#if defined(RBIMPL_VA_OPT_ARGS)
-# define RUBY_ASSERT_ALWAYS(expr, ...) \
- RUBY_ASSERT_MESG(expr, #expr RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
-#else
-# define RUBY_ASSERT_ALWAYS(expr) RUBY_ASSERT_MESG((expr), #expr)
-#endif
+#define RUBY_ASSERT_ALWAYS(expr) RUBY_ASSERT_MESG((expr), #expr)
/**
* Asserts that the given expression is truthy if and only if #RUBY_DEBUG is truthy.
@@ -208,18 +172,9 @@ RBIMPL_WARNING_IGNORED(-Wgnu-zero-variadic-macro-arguments)
* @param expr What supposedly evaluates to true.
*/
#if RUBY_DEBUG
-# if defined(RBIMPL_VA_OPT_ARGS)
-# define RUBY_ASSERT(expr, ...) \
- RUBY_ASSERT_MESG((expr), #expr RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
-# else
-# define RUBY_ASSERT(expr) RUBY_ASSERT_MESG((expr), #expr)
-# endif
+# define RUBY_ASSERT(expr) RUBY_ASSERT_MESG((expr), #expr)
#else
-# if defined(RBIMPL_VA_OPT_ARGS)
-# define RUBY_ASSERT(/* expr, */...) RBIMPL_ASSERT_NOTHING
-# else
-# define RUBY_ASSERT(expr) RBIMPL_ASSERT_NOTHING
-# endif
+# define RUBY_ASSERT(expr) RBIMPL_ASSERT_NOTHING
#endif
/**
@@ -232,18 +187,9 @@ RBIMPL_WARNING_IGNORED(-Wgnu-zero-variadic-macro-arguments)
/* Currently `RUBY_DEBUG == ! defined(NDEBUG)` is always true. There is no
* difference any longer between this one and `RUBY_ASSERT`. */
#if defined(NDEBUG)
-# if defined(RBIMPL_VA_OPT_ARGS)
-# define RUBY_ASSERT_NDEBUG(/* expr, */...) RBIMPL_ASSERT_NOTHING
-# else
-# define RUBY_ASSERT_NDEBUG(expr) RBIMPL_ASSERT_NOTHING
-# endif
+# define RUBY_ASSERT_NDEBUG(expr) RBIMPL_ASSERT_NOTHING
#else
-# if defined(RBIMPL_VA_OPT_ARGS)
-# define RUBY_ASSERT_NDEBUG(expr, ...) \
- RUBY_ASSERT_MESG((expr), #expr RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
-# else
-# define RUBY_ASSERT_NDEBUG(expr) RUBY_ASSERT_MESG((expr), #expr)
-# endif
+# define RUBY_ASSERT_NDEBUG(expr) RUBY_ASSERT_MESG((expr), #expr)
#endif
/**
@@ -251,20 +197,10 @@ RBIMPL_WARNING_IGNORED(-Wgnu-zero-variadic-macro-arguments)
* @param mesg The message to display on failure.
*/
#if RUBY_DEBUG
-# if defined(RBIMPL_VA_OPT_ARGS)
-# define RUBY_ASSERT_MESG_WHEN(cond, /* expr, */...) \
- RUBY_ASSERT_MESG(__VA_ARGS__)
-# else
-# define RUBY_ASSERT_MESG_WHEN(cond, expr, mesg) RUBY_ASSERT_MESG((expr), (mesg))
-# endif
+# define RUBY_ASSERT_MESG_WHEN(cond, expr, mesg) RUBY_ASSERT_MESG((expr), (mesg))
#else
-# if defined(RBIMPL_VA_OPT_ARGS)
-# define RUBY_ASSERT_MESG_WHEN(cond, expr, ...) \
- ((cond) ? RUBY_ASSERT_MESG((expr), __VA_ARGS__) : RBIMPL_ASSERT_NOTHING)
-# else
-# define RUBY_ASSERT_MESG_WHEN(cond, expr, mesg) \
+# define RUBY_ASSERT_MESG_WHEN(cond, expr, mesg) \
((cond) ? RUBY_ASSERT_MESG((expr), (mesg)) : RBIMPL_ASSERT_NOTHING)
-# endif
#endif
/**
@@ -274,23 +210,7 @@ RBIMPL_WARNING_IGNORED(-Wgnu-zero-variadic-macro-arguments)
* @param cond Extra condition that shall hold for assertion to take effect.
* @param expr What supposedly evaluates to true.
*/
-#if defined(RBIMPL_VA_OPT_ARGS)
-# define RUBY_ASSERT_WHEN(cond, expr, ...) \
- RUBY_ASSERT_MESG_WHEN(cond, expr, #expr RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
-#else
-# define RUBY_ASSERT_WHEN(cond, expr) RUBY_ASSERT_MESG_WHEN((cond), (expr), #expr)
-#endif
-
-/**
- * A variant of #RUBY_ASSERT that asserts when either #RUBY_DEBUG or built-in
- * type of `obj` is `type`.
- *
- * @param obj Object to check its built-in typue.
- * @param type Built-in type constant, T_ARRAY, T_STRING, etc.
- */
-#define RUBY_ASSERT_BUILTIN_TYPE(obj, type) \
- RUBY_ASSERT(RB_TYPE_P(obj, type), \
- "Actual type is %s", rb_builtin_type_name(BUILTIN_TYPE(obj)))
+#define RUBY_ASSERT_WHEN(cond, expr) RUBY_ASSERT_MESG_WHEN((cond), (expr), #expr)
/**
* This is either #RUBY_ASSERT or #RBIMPL_ASSUME, depending on #RUBY_DEBUG.
@@ -298,19 +218,17 @@ RBIMPL_WARNING_IGNORED(-Wgnu-zero-variadic-macro-arguments)
* @copydetails #RUBY_ASSERT
*/
#if RUBY_DEBUG
-# define RBIMPL_ASSERT_OR_ASSUME RUBY_ASSERT_ALWAYS
-#elif ! defined(RBIMPL_VA_OPT_ARGS)
-# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSUME(expr)
+# define RBIMPL_ASSERT_OR_ASSUME(expr) RUBY_ASSERT_ALWAYS(expr)
#elif RBIMPL_COMPILER_BEFORE(Clang, 7, 0, 0)
# /* See commit 67d259c5dccd31fe49d417fec169977712ffdf10 */
-# define RBIMPL_ASSERT_OR_ASSUME(...) RBIMPL_ASSERT_NOTHING
+# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSERT_NOTHING
#elif defined(RUBY_ASSERT_NOASSUME)
# /* See commit d300a734414ef6de7e8eb563b7cc4389c455ed08 */
-# define RBIMPL_ASSERT_OR_ASSUME(...) RBIMPL_ASSERT_NOTHING
+# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSERT_NOTHING
#elif ! defined(RBIMPL_HAVE___ASSUME)
-# define RBIMPL_ASSERT_OR_ASSUME(...) RBIMPL_ASSERT_NOTHING
+# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSERT_NOTHING
#else
-# define RBIMPL_ASSERT_OR_ASSUME(expr, ...) RBIMPL_ASSUME(expr)
+# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSUME(expr)
#endif
#endif /* RUBY_ASSERT_H */
diff --git a/include/ruby/atomic.h b/include/ruby/atomic.h
index d786df20c9..3eb80fbf7d 100644
--- a/include/ruby/atomic.h
+++ b/include/ruby/atomic.h
@@ -139,15 +139,6 @@ typedef unsigned int rb_atomic_t;
rbimpl_atomic_cas(&(var), (oldval), (newval))
/**
- * Atomic load. This loads `var` with an atomic intrinsic and returns
- * its value.
- *
- * @param var A variable of ::rb_atomic_t
- * @return What was stored in `var`j
- */
-#define RUBY_ATOMIC_LOAD(var) rbimpl_atomic_load(&(var))
-
-/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except for the return type.
*
* @param var A variable of ::rb_atomic_t.
@@ -289,17 +280,6 @@ typedef unsigned int rb_atomic_t;
RBIMPL_CAST(rbimpl_atomic_ptr_exchange((void **)&(var), (void *)val))
/**
- * Identical to #RUBY_ATOMIC_LOAD, except it expects its arguments are `void*`.
- * There are cases where ::rb_atomic_t is 32bit while `void*` is 64bit. This
- * should be used for size related operations to support such platforms.
- *
- * @param var A variable of `void*`
- * @return The value of `var` (without tearing)
- */
-#define RUBY_ATOMIC_PTR_LOAD(var) \
- RBIMPL_CAST(rbimpl_atomic_ptr_load((void **)&var))
-
-/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `void*`.
* There are cases where ::rb_atomic_t is 32bit while `void*` is 64bit. This
* should be used for size related operations to support such platforms.
@@ -311,7 +291,7 @@ typedef unsigned int rb_atomic_t;
* @retval otherwise Something else is at `var`; not updated.
*/
#define RUBY_ATOMIC_PTR_CAS(var, oldval, newval) \
- RBIMPL_CAST(rbimpl_atomic_ptr_cas((void **)&(var), (void *)(oldval), (void *)(newval)))
+ RBIMPL_CAST(rbimpl_atomic_ptr_cas((void **)&(var), (oldval), (newval)))
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
@@ -424,7 +404,7 @@ rbimpl_atomic_size_add(volatile size_t *ptr, size_t val)
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_add_and_fetch(ptr, val);
-#elif defined(_WIN64)
+#elif defined(_WIN32) && defined(_M_AMD64)
/* Ditto for `InterlockeExchangedAdd`. */
InterlockedExchangeAdd64(ptr, val);
@@ -476,15 +456,13 @@ rbimpl_atomic_size_inc(volatile size_t *ptr)
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
rbimpl_atomic_size_add(ptr, 1);
-#elif defined(_WIN64)
+#elif defined(_WIN32) && defined(_M_AMD64)
InterlockedIncrement64(ptr);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
atomic_inc_ulong(ptr);
#else
- RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
-
rbimpl_atomic_size_add(ptr, 1);
#endif
@@ -560,7 +538,7 @@ rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val)
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_sub_and_fetch(ptr, val);
-#elif defined(_WIN64)
+#elif defined(_WIN32) && defined(_M_AMD64)
const ssize_t neg = -1;
InterlockedExchangeAdd64(ptr, neg * val);
@@ -612,15 +590,13 @@ rbimpl_atomic_size_dec(volatile size_t *ptr)
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
rbimpl_atomic_size_sub(ptr, 1);
-#elif defined(_WIN64)
+#elif defined(_WIN32) && defined(_M_AMD64)
InterlockedDecrement64(ptr);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
atomic_dec_ulong(ptr);
#else
- RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
-
rbimpl_atomic_size_sub(ptr, 1);
#endif
@@ -712,7 +688,7 @@ rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val)
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_lock_test_and_set(ptr, val);
-#elif defined(_WIN64)
+#elif defined(_WIN32) && defined(_M_AMD64)
return InterlockedExchange64(ptr, val);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
@@ -773,21 +749,6 @@ rbimpl_atomic_value_exchange(volatile VALUE *ptr, VALUE val)
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
-static inline rb_atomic_t
-rbimpl_atomic_load(volatile rb_atomic_t *ptr)
-{
-#if 0
-
-#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
-#else
- return rbimpl_atomic_fetch_add(ptr, 0);
-#endif
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_NOALIAS()
-RBIMPL_ATTR_NONNULL((1))
static inline void
rbimpl_atomic_set(volatile rb_atomic_t *ptr, rb_atomic_t val)
{
@@ -862,7 +823,7 @@ rbimpl_atomic_size_cas(volatile size_t *ptr, size_t oldval, size_t newval)
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_val_compare_and_swap(ptr, oldval, newval);
-#elif defined(_WIN64)
+#elif defined(_WIN32) && defined(_M_AMD64)
return InterlockedCompareExchange64(ptr, newval, oldval);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
@@ -914,22 +875,6 @@ rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval)
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
-static inline void *
-rbimpl_atomic_ptr_load(void **ptr)
-{
-#if 0
-
-#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
-#else
- void *val = *ptr;
- return rbimpl_atomic_ptr_cas(ptr, val, val);
-#endif
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_NOALIAS()
-RBIMPL_ATTR_NONNULL((1))
static inline VALUE
rbimpl_atomic_value_cas(volatile VALUE *ptr, VALUE oldval, VALUE newval)
{
diff --git a/include/ruby/backward/2/attributes.h b/include/ruby/backward/2/attributes.h
index 916d9e9d5b..73acfc9dc0 100644
--- a/include/ruby/backward/2/attributes.h
+++ b/include/ruby/backward/2/attributes.h
@@ -39,7 +39,6 @@
#include "ruby/internal/attr/noinline.h"
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/attr/noreturn.h"
-#include "ruby/internal/attr/packed_struct.h"
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/attr/restrict.h"
#include "ruby/internal/attr/returns_nonnull.h"
@@ -81,8 +80,10 @@
#undef NOINLINE
#define NOINLINE(x) RBIMPL_ATTR_NOINLINE() x
-#undef ALWAYS_INLINE
-#define ALWAYS_INLINE(x) RBIMPL_ATTR_FORCEINLINE() x
+#ifndef MJIT_HEADER
+# undef ALWAYS_INLINE
+# define ALWAYS_INLINE(x) RBIMPL_ATTR_FORCEINLINE() x
+#endif
#undef ERRORFUNC
#define ERRORFUNC(mesg, x) RBIMPL_ATTR_ERROR(mesg) x
@@ -146,14 +147,17 @@
#define NORETURN(x) RBIMPL_ATTR_NORETURN() x
#define NORETURN_STYLE_NEW
-#undef PACKED_STRUCT
-#define PACKED_STRUCT(x) \
- RBIMPL_ATTR_PACKED_STRUCT_BEGIN() x RBIMPL_ATTR_PACKED_STRUCT_END()
+#ifndef PACKED_STRUCT
+# define PACKED_STRUCT(x) x
+#endif
-#undef PACKED_STRUCT_UNALIGNED
-#define PACKED_STRUCT_UNALIGNED(x) \
- RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN() x \
- RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END()
+#ifndef PACKED_STRUCT_UNALIGNED
+# if UNALIGNED_WORD_ACCESS
+# define PACKED_STRUCT_UNALIGNED(x) PACKED_STRUCT(x)
+# else
+# define PACKED_STRUCT_UNALIGNED(x) x
+# endif
+#endif
#undef RB_UNUSED_VAR
#define RB_UNUSED_VAR(x) x RBIMPL_ATTR_MAYBE_UNUSED()
diff --git a/include/ruby/debug.h b/include/ruby/debug.h
index f7c8e6ca8d..f95acdb17e 100644
--- a/include/ruby/debug.h
+++ b/include/ruby/debug.h
@@ -10,7 +10,6 @@
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
*/
-#include "ruby/internal/attr/deprecated.h"
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/attr/returns_nonnull.h"
#include "ruby/internal/dllexport.h"
@@ -52,25 +51,6 @@ RBIMPL_ATTR_NONNULL((3))
int rb_profile_frames(int start, int limit, VALUE *buff, int *lines);
/**
- * Queries mysterious "frame"s of the given range.
- *
- * A per-thread version of rb_profile_frames().
- * Arguments and return values are the same with rb_profile_frames() with the
- * exception of the first argument _thread_, which accepts the Thread to be
- * profiled/queried.
- *
- * @param[in] thread The Ruby Thread to be profiled.
- * @param[in] start Start position (0 means the topmost).
- * @param[in] limit Number objects of `buff`.
- * @param[out] buff Return buffer.
- * @param[out] lines Return buffer.
- * @return Number of objects filled into `buff`.
- * @post `buff` is filled with backtrace pointers.
- * @post `lines` is filled with `__LINE__` of each backtraces.
- */
-int rb_profile_thread_frames(VALUE thread, int start, int limit, VALUE *buff, int *lines);
-
-/**
* Queries the path of the passed backtrace.
*
* @param[in] frame What rb_profile_frames() returned.
@@ -616,157 +596,48 @@ VALUE rb_tracearg_object(rb_trace_arg_t *trace_arg);
/*
* Postponed Job API
- *
- * This API is designed to be called from contexts where it is not safe to run Ruby
- * code (e.g. because they do not hold the GVL or because GC is in progress), and
- * defer a callback to run in a context where it _is_ safe. The primary intended
- * users of this API is for sampling profilers like the "stackprof" gem; these work
- * by scheduling the periodic delivery of a SIGPROF signal, and inside the C-level
- * signal handler, deferring a job to collect a Ruby backtrace when it is next safe
- * to do so.
- *
- * Ruby maintains a small, fixed-size postponed job table. An extension using this
- * API should first call `rb_postponed_job_preregister` to register a callback
- * function in this table and obtain a handle of type `rb_postponed_job_handle_t`
- * to it. Subsequently, the callback can be triggered by calling
- * `rb_postponed_job_trigger` with that handle, or the `data` associated with the
- * callback function can be changed by calling `rb_postponed_job_preregister` again.
- *
- * Because the postponed job table is quite small (it only has 32 entries on most
- * common systems), extensions should generally only preregister one or two `func`
- * values.
- *
- * Historically, this API provided two functions `rb_postponed_job_register` and
- * `rb_postponed_job_register_one`, which claimed to be fully async-signal-safe and
- * would call back the provided `func` and `data` at an appropriate time. However,
- * these functions were subject to race conditions which could cause crashes when
- * racing with Ruby's internal use of them. These two functions are still present,
- * but are marked as deprecated and have slightly changed semantics:
- *
- * * rb_postponed_job_register now works like rb_postponed_job_register_one i.e.
- * `func` will only be executed at most one time each time Ruby checks for
- * interrupts, no matter how many times it is registered
- * * They are also called with the last `data` to be registered, not the first
- * (which is how rb_postponed_job_register_one previously worked)
+ * rb_postponed_job_register and rb_postponed_job_register_one are
+ * async-signal-safe and used via SIGPROF by the "stackprof" RubyGem
*/
-
/**
* Type of postponed jobs.
*
- * @param[in,out] arg What was passed to `rb_postponed_job_preregister`
+ * @param[in,out] arg What was passed to rb_postponed_job_register().
*/
typedef void (*rb_postponed_job_func_t)(void *arg);
/**
- * The type of a handle returned from `rb_postponed_job_preregister` and
- * passed to `rb_postponed_job_trigger`
- */
-typedef unsigned int rb_postponed_job_handle_t;
-#define POSTPONED_JOB_HANDLE_INVALID ((rb_postponed_job_handle_t)UINT_MAX)
-
-/**
- * Pre-registers a func in Ruby's postponed job preregistration table,
- * returning an opaque handle which can be used to trigger the job later. Generally,
- * this function will be called during the initialization routine of an extension.
+ * Registers a postponed job.
*
- * The returned handle can be used later to call `rb_postponed_job_trigger`. This will
- * cause Ruby to call back into the registered `func` with `data` at a later time, in
- * a context where the GVL is held and it is safe to perform Ruby allocations.
+ * There are situations when running a ruby program is not possible. For
+ * instance when a program is in a signal handler; for another instance when
+ * the GC is busy. On such situations however, there might be needs to do
+ * something. We cannot but defer such operations until we are 100% sure it is
+ * safe to execute them. This mechanism is called postponed jobs. This
+ * function registers a new one. The registered job would eventually gets
+ * executed.
*
- * If the given `func` was already pre-registered, this function will overwrite the
- * stored data with the newly passed data, and return the same handle instance as
- * was previously returned.
- *
- * If this function is called concurrently with the same `func`, then the stored data
- * could be the value from either call (but will definitely be one of them).
- *
- * If this function is called to update the data concurrently with a call to
- * `rb_postponed_job_trigger` on the same handle, it's undefined whether `func` will
- * be called with the old data or the new data.
- *
- * Although the current implementation of this function is in fact async-signal-safe and
- * has defined semantics when called concurrently on the same `func`, a future Ruby
- * version might require that this method be called under the GVL; thus, programs which
- * aim to be forward-compatible should call this method whilst holding the GVL.
- *
- * @param[in] flags Unused and ignored
- * @param[in] func The function to be pre-registered
- * @param[in] data The data to be pre-registered
- * @retval POSTPONED_JOB_HANDLE_INVALID The job table is full; this registration
- * did not succeed and no further registration will do so for
- * the lifetime of the program.
- * @retval otherwise A handle which can be passed to `rb_postponed_job_trigger`
- */
-rb_postponed_job_handle_t rb_postponed_job_preregister(unsigned int flags, rb_postponed_job_func_t func, void *data);
-
-/**
- * Triggers a pre-registered job registered with rb_postponed_job_preregister,
- * scheduling it for execution the next time the Ruby VM checks for interrupts.
- * The context in which the job is called in holds the GVL and is safe to perform
- * Ruby allocations within (i.e. it is not during GC).
- *
- * This method is async-signal-safe and can be called from any thread, at any
- * time, including in signal handlers.
- *
- * If this method is called multiple times, Ruby will coalesce this into only
- * one call to the job the next time it checks for interrupts.
- *
- * @params[in] h A handle returned from rb_postponed_job_preregister
- */
-void rb_postponed_job_trigger(rb_postponed_job_handle_t h);
-
-/**
- * Schedules the given `func` to be called with `data` when Ruby next checks for
- * interrupts. If this function is called multiple times in between Ruby checking
- * for interrupts, then `func` will be called only once with the `data` value from
- * the first call to this function.
- *
- * Like `rb_postponed_job_trigger`, the context in which the job is called
- * holds the GVL and can allocate Ruby objects.
- *
- * This method essentially has the same semantics as:
- *
- * ```
- * rb_postponed_job_trigger(rb_postponed_job_preregister(func, data));
- * ```
- *
- * @note Previous versions of Ruby promised that the (`func`, `data`) pairs would
- * be executed as many times as they were registered with this function; in
- * reality this was always subject to race conditions and this function no
- * longer provides this guarantee. Instead, multiple calls to this function
- * can be coalesced into a single execution of the passed `func`, with the
- * most recent `data` registered at that time passed in.
- *
- * @deprecated This interface implies that arbitrarily many `func`'s can be enqueued
- * over the lifetime of the program, whilst in reality the registration
- * slots for postponed jobs are a finite resource. This is made clearer
- * by the `rb_postponed_job_preregister` and `rb_postponed_job_trigger`
- * functions, and a future version of Ruby might delete this function.
- *
- * @param[in] flags Unused and ignored.
+ * @param[in] flags (Unused) reserved for future extensions.
* @param[in] func Job body.
* @param[in,out] data Passed as-is to `func`.
- * @retval 0 Postponed job registration table is full. Failed.
- * @retval 1 Registration succeeded.
- * @post The passed job will run on the next interrupt check.
+ * @retval 0 Postponed job buffer is full. Failed.
+ * @retval otherwise Opaque return value.
+ * @post The passed job is postponed.
*/
- RBIMPL_ATTR_DEPRECATED(("use rb_postponed_job_preregister and rb_postponed_job_trigger"))
int rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data);
/**
- * Identical to `rb_postponed_job_register`
- *
- * @deprecated This is deprecated for the same reason as `rb_postponed_job_register`
+ * Identical to rb_postponed_job_register_one(), except it additionally checks
+ * for duplicated registration. In case the passed job is already in the
+ * postponed job buffer this function does nothing.
*
- * @param[in] flags Unused and ignored.
+ * @param[in] flags (Unused) reserved for future extensions.
* @param[in] func Job body.
* @param[in,out] data Passed as-is to `func`.
- * @retval 0 Postponed job registration table is full. Failed.
- * @retval 1 Registration succeeded.
- * @post The passed job will run on the next interrupt check.
+ * @retval 0 Postponed job buffer is full. Failed.
+ * @retval otherwise Opaque return value.
*/
- RBIMPL_ATTR_DEPRECATED(("use rb_postponed_job_preregister and rb_postponed_job_trigger"))
int rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void *data);
/** @} */
diff --git a/include/ruby/fiber/scheduler.h b/include/ruby/fiber/scheduler.h
index 8f3d383330..250b39b6df 100644
--- a/include/ruby/fiber/scheduler.h
+++ b/include/ruby/fiber/scheduler.h
@@ -97,7 +97,7 @@ VALUE rb_fiber_scheduler_get(void);
* current thread will call scheduler's `#close` method on finalisation
* (allowing the scheduler to properly manage all non-finished fibers).
* `scheduler` can be an object of any class corresponding to
- * `Fiber::Scheduler` interface. Its implementation is up to the user.
+ * `Fiber::SchedulerInterface`. Its implementation is up to the user.
*
* @param[in] scheduler The scheduler to set.
* @exception rb_eArgError `scheduler` does not conform the interface.
@@ -267,10 +267,10 @@ VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv);
* Non-blocking read from the passed IO.
*
* @param[in] scheduler Target scheduler.
- * @param[in] io An io object to read from.
- * @param[in] buffer The buffer to read to.
- * @param[in] length The minimum number of bytes to read.
- * @param[in] offset The offset in the buffer to read from.
+ * @param[out] io An io object to read from.
+ * @param[out] buffer Return buffer.
+ * @param[in] length Requested number of bytes to read.
+ * @param[in] offset The offset in the buffer to read to.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_read`.
* @return otherwise What `scheduler.io_read` returns `[-errno, size]`.
*/
@@ -280,9 +280,9 @@ VALUE rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t
* Non-blocking write to the passed IO.
*
* @param[in] scheduler Target scheduler.
- * @param[in] io An io object to write to.
- * @param[in] buffer The buffer to write from.
- * @param[in] length The minimum number of bytes to write.
+ * @param[out] io An io object to write to.
+ * @param[in] buffer What to write.
+ * @param[in] length Number of bytes to write.
* @param[in] offset The offset in the buffer to write from.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_write`.
* @return otherwise What `scheduler.io_write` returns `[-errno, size]`.
@@ -293,10 +293,10 @@ VALUE rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_
* Non-blocking read from the passed IO at the specified offset.
*
* @param[in] scheduler Target scheduler.
- * @param[in] io An io object to read from.
- * @param[in] from The offset to read from.
- * @param[in] buffer The buffer to read to.
- * @param[in] length The minimum number of bytes to read.
+ * @param[out] io An io object to read from.
+ * @param[in] from The offset in the given IO to read the data from.
+ * @param[out] buffer The buffer to read the data to.
+ * @param[in] length Requested number of bytes to read.
* @param[in] offset The offset in the buffer to read to.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_read`.
* @return otherwise What `scheduler.io_read` returns.
@@ -307,10 +307,10 @@ VALUE rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALU
* Non-blocking write to the passed IO at the specified offset.
*
* @param[in] scheduler Target scheduler.
- * @param[in] io An io object to write to.
- * @param[in] from The offset to write to.
- * @param[in] buffer The buffer to write from.
- * @param[in] length The minimum number of bytes to write.
+ * @param[out] io An io object to write to.
+ * @param[in] from The offset in the given IO to write the data to.
+ * @param[in] buffer The buffer to write the data from.
+ * @param[in] length Number of bytes to write.
* @param[in] offset The offset in the buffer to write from.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_write`.
* @return otherwise What `scheduler.io_write` returns.
@@ -321,55 +321,27 @@ VALUE rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, rb_off_t from, VAL
* Non-blocking read from the passed IO using a native buffer.
*
* @param[in] scheduler Target scheduler.
- * @param[in] io An io object to read from.
- * @param[in] base The memory to read to.
- * @param[in] size Size of the memory.
- * @param[in] length The minimum number of bytes to read.
+ * @param[out] io An io object to read from.
+ * @param[out] buffer Return buffer.
+ * @param[in] size Size of the return buffer.
+ * @param[in] length Requested number of bytes to read.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_read`.
* @return otherwise What `scheduler.io_read` returns.
*/
-VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length);
+VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *buffer, size_t size, size_t length);
/**
* Non-blocking write to the passed IO using a native buffer.
*
* @param[in] scheduler Target scheduler.
- * @param[in] io An io object to write to.
- * @param[in] base The memory to write from.
- * @param[in] size Size of the memory.
- * @param[in] length The minimum number of bytes to write.
- * @retval RUBY_Qundef `scheduler` doesn't have `#io_write`.
- * @return otherwise What `scheduler.io_write` returns.
- */
-VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length);
-
-/**
- * Non-blocking pread from the passed IO using a native buffer.
- *
- * @param[in] scheduler Target scheduler.
- * @param[in] io An io object to read from.
- * @param[in] from The offset to read from.
- * @param[in] base The memory to read to.
- * @param[in] size Size of the memory.
- * @param[in] length The minimum number of bytes to read.
- * @retval RUBY_Qundef `scheduler` doesn't have `#io_read`.
- * @return otherwise What `scheduler.io_read` returns.
- */
-VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length);
-
-/**
- * Non-blocking pwrite to the passed IO using a native buffer.
- *
- * @param[in] scheduler Target scheduler.
- * @param[in] io An io object to write to.
- * @param[in] from The offset to write from.
- * @param[in] base The memory to write from.
- * @param[in] size Size of the memory.
- * @param[in] length The minimum number of bytes to write.
+ * @param[out] io An io object to write to.
+ * @param[in] buffer What to write.
+ * @param[in] size Size of the buffer.
+ * @param[in] length Number of bytes to write.
* @retval RUBY_Qundef `scheduler` doesn't have `#io_write`.
* @return otherwise What `scheduler.io_write` returns.
*/
-VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length);
+VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *buffer, size_t size, size_t length);
/**
* Non-blocking close the given IO.
diff --git a/include/ruby/intern.h b/include/ruby/intern.h
index 48e4cd546e..2480e2e703 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -36,6 +36,7 @@
#include "ruby/internal/intern/error.h"
#include "ruby/internal/intern/eval.h"
#include "ruby/internal/intern/file.h"
+#include "ruby/internal/intern/gc.h"
#include "ruby/internal/intern/hash.h"
#include "ruby/internal/intern/io.h"
#include "ruby/internal/intern/load.h"
diff --git a/include/ruby/internal/abi.h b/include/ruby/internal/abi.h
index e735a67564..44111a0055 100644
--- a/include/ruby/internal/abi.h
+++ b/include/ruby/internal/abi.h
@@ -24,7 +24,7 @@
* In released versions of Ruby, this number is not defined since teeny
* versions of Ruby should guarantee ABI compatibility.
*/
-#define RUBY_ABI_VERSION 0
+#define RUBY_ABI_VERSION 3
/* Windows does not support weak symbols so ruby_abi_version will not exist
* in the shared library. */
@@ -33,7 +33,7 @@
#endif
#endif /* RUBY_ABI_VERSION */
-#if defined(RUBY_DLN_CHECK_ABI) && !defined(RUBY_EXPORT)
+#ifdef RUBY_DLN_CHECK_ABI
# ifdef __cplusplus
extern "C" {
diff --git a/include/ruby/internal/anyargs.h b/include/ruby/internal/anyargs.h
index e3e1b6166d..e4c6d155cc 100644
--- a/include/ruby/internal/anyargs.h
+++ b/include/ruby/internal/anyargs.h
@@ -84,12 +84,15 @@
#elif defined(_WIN32) || defined(__CYGWIN__)
# /* Skip due to [Bug #16134] */
+# define RBIMPL_CAST_FN_PTR 1
#elif ! RBIMPL_HAS_ATTRIBUTE(transparent_union)
# /* :TODO: improve here, please find a way to support. */
+# define RBIMPL_CAST_FN_PTR 1
#elif ! defined(HAVE_VA_ARGS_MACRO)
# /* :TODO: improve here, please find a way to support. */
+# define RBIMPL_CAST_FN_PTR 1
#else
# /** @cond INTERNAL_MACRO */
@@ -348,6 +351,25 @@ RBIMPL_ANYARGS_DECL(rb_define_method, VALUE, const char *)
#endif /* __cplusplus */
+#if defined(RBIMPL_CAST_FN_PTR) && !defined(__cplusplus)
+/* In C23, K&R style prototypes are gone and so `void foo(ANYARGS)` became
+ * equivalent to `void foo(void)` unlike in earlier versions. This is a problem
+ * for rb_define_* functions since that makes all valid functions one can pass
+ * trip -Wincompatible-pointer-types, which we treat as errors. This is mostly
+ * not a problem for the __builtin_choose_expr path, but outside of that we
+ * need to add a cast for compatibility.
+ */
+#define rb_define_method(klass, mid, func, arity) rb_define_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_method_id(klass, mid, func, arity) rb_define_method_id((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_singleton_method(obj, mid, func, arity) rb_define_singleton_method((obj), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_protected_method(klass, mid, func, arity) rb_define_protected_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_private_method(klass, mid, func, arity) rb_define_private_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_module_function(mod, mid, func, arity) rb_define_module_function((mod), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_global_function(mid, func, arity) rb_define_global_function((mid), (VALUE (*)(ANYARGS))(func), (arity))
+
+#undef RBIMPL_CAST_FN_PTR
+#endif /* defined(RBIMPL_CAST_FN_PTR) && !defined(__cplusplus) */
+
/**
* This macro is to properly cast a function parameter of *_define_method
* family. It has been around since 1.x era so you can maximise backwards
diff --git a/include/ruby/internal/arithmetic/long.h b/include/ruby/internal/arithmetic/long.h
index 6c00dbceb7..6b8fd8ffc3 100644
--- a/include/ruby/internal/arithmetic/long.h
+++ b/include/ruby/internal/arithmetic/long.h
@@ -114,11 +114,11 @@ RB_INT2FIX(long i)
/* :NOTE: VALUE can be wider than long. As j being unsigned, 2j+1 is fully
* defined. Also it can be compiled into a single LEA instruction. */
- const unsigned long j = RBIMPL_CAST((unsigned long)i);
+ const unsigned long j = i;
const unsigned long k = (j << 1) + RUBY_FIXNUM_FLAG;
- const long l = RBIMPL_CAST((long)k);
+ const long l = k;
const SIGNED_VALUE m = l; /* Sign extend */
- const VALUE n = RBIMPL_CAST((VALUE)m);
+ const VALUE n = m;
RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(n));
return n;
@@ -166,7 +166,7 @@ rbimpl_fix2long_by_idiv(VALUE x)
/* :NOTE: VALUE can be wider than long. (x-1)/2 never overflows because
* RB_FIXNUM_P(x) holds. Also it has no portability issue like y>>1
* below. */
- const SIGNED_VALUE y = RBIMPL_CAST((SIGNED_VALUE)(x - RUBY_FIXNUM_FLAG));
+ const SIGNED_VALUE y = x - RUBY_FIXNUM_FLAG;
const SIGNED_VALUE z = y / 2;
const long w = RBIMPL_CAST((long)z);
@@ -193,7 +193,7 @@ rbimpl_fix2long_by_shift(VALUE x)
/* :NOTE: VALUE can be wider than long. If right shift is arithmetic, this
* is noticeably faster than above. */
- const SIGNED_VALUE y = RBIMPL_CAST((SIGNED_VALUE)x);
+ const SIGNED_VALUE y = x;
const SIGNED_VALUE z = y >> 1;
const long w = RBIMPL_CAST((long)z);
@@ -252,7 +252,7 @@ static inline unsigned long
rb_fix2ulong(VALUE x)
{
RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(x));
- return RBIMPL_CAST((unsigned long)rb_fix2long(x));
+ return rb_fix2long(x);
}
/**
@@ -323,7 +323,7 @@ static inline VALUE
rb_ulong2num_inline(unsigned long v)
{
if (RB_POSFIXABLE(v))
- return RB_LONG2FIX(RBIMPL_CAST((long)v));
+ return RB_LONG2FIX(v);
else
return rb_uint2big(v);
}
diff --git a/include/ruby/internal/arithmetic/long_long.h b/include/ruby/internal/arithmetic/long_long.h
index aab455c830..65dec8729d 100644
--- a/include/ruby/internal/arithmetic/long_long.h
+++ b/include/ruby/internal/arithmetic/long_long.h
@@ -127,7 +127,7 @@ static inline unsigned LONG_LONG
rb_num2ull_inline(VALUE x)
{
if (RB_FIXNUM_P(x))
- return RBIMPL_CAST((unsigned LONG_LONG)RB_FIX2LONG(x));
+ return RB_FIX2LONG(x);
else
return rb_num2ull(x);
}
diff --git a/include/ruby/internal/arithmetic/st_data_t.h b/include/ruby/internal/arithmetic/st_data_t.h
index 91776b3fce..3bff4ffc0b 100644
--- a/include/ruby/internal/arithmetic/st_data_t.h
+++ b/include/ruby/internal/arithmetic/st_data_t.h
@@ -58,7 +58,7 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline VALUE
RB_ST2FIX(st_data_t i)
{
- SIGNED_VALUE x = RBIMPL_CAST((SIGNED_VALUE)i);
+ SIGNED_VALUE x = i;
if (x >= 0) {
x &= RUBY_FIXNUM_MAX;
@@ -69,7 +69,7 @@ RB_ST2FIX(st_data_t i)
RBIMPL_ASSERT_OR_ASSUME(RB_FIXABLE(x));
unsigned long y = RBIMPL_CAST((unsigned long)x);
- return RB_LONG2FIX(RBIMPL_CAST((long)y));
+ return RB_LONG2FIX(y);
}
#endif /* RBIMPL_ARITHMETIC_ST_DATA_T_H */
diff --git a/include/ruby/internal/attr/noexcept.h b/include/ruby/internal/attr/noexcept.h
index 7c3f92f1e7..ea3001df2a 100644
--- a/include/ruby/internal/attr/noexcept.h
+++ b/include/ruby/internal/attr/noexcept.h
@@ -54,7 +54,7 @@
* get smarter and smarter. Today they can infer if it actually throws
* or not without any annotations by humans (correct me if I'm wrong).
*
- * - When an inline function attributed `noexcept` actually _does_ throw an
+ * - When an inline function attributed `noexcepr` actually _does_ throw an
* exception: they have to call `std::terminate` then (C++ standard
* mandates so). This means exception handling routines are actually
* enforced, not omitted. This doesn't impact runtime performance (The
diff --git a/include/ruby/internal/attr/nonstring.h b/include/ruby/internal/attr/nonstring.h
new file mode 100644
index 0000000000..de26e926d4
--- /dev/null
+++ b/include/ruby/internal/attr/nonstring.h
@@ -0,0 +1,32 @@
+#ifndef RBIMPL_ATTR_NONSTRING_H /*-*-C++-*-vi:se ft=cpp:*/
+#define RBIMPL_ATTR_NONSTRING_H
+/**
+ * @file
+ * @author Ruby developers <ruby-core@ruby-lang.org>
+ * @copyright This file is a part of the programming language Ruby.
+ * Permission is hereby granted, to either redistribute and/or
+ * modify this file, provided that the conditions mentioned in the
+ * file COPYING are met. Consult the file for details.
+ * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
+ * implementation details. Don't take them as canon. They could
+ * rapidly appear then vanish. The name (path) of this header file
+ * is also an implementation detail. Do not expect it to persist
+ * at the place it is now. Developers are free to move it anywhere
+ * anytime at will.
+ * @note To ruby-core: remember that this header can be possibly
+ * recursively included from extension libraries written in C++.
+ * Do not expect for instance `__VA_ARGS__` is always available.
+ * We assume C99 for ruby itself but we don't assume languages of
+ * extension libraries. They could be written in C++98.
+ * @brief Defines #RBIMPL_ATTR_NONSTRING.
+ */
+#include "ruby/internal/has/attribute.h"
+
+/** Wraps (or simulates) `__attribute__((nonstring))` */
+#if RBIMPL_HAS_ATTRIBUTE(nonstring)
+# define RBIMPL_ATTR_NONSTRING() __attribute__((nonstring))
+#else
+# define RBIMPL_ATTR_NONSTRING() /* void */
+#endif
+
+#endif /* RBIMPL_ATTR_NONSTRING_H */
diff --git a/include/ruby/internal/attr/packed_struct.h b/include/ruby/internal/attr/packed_struct.h
deleted file mode 100644
index 0678b9acc8..0000000000
--- a/include/ruby/internal/attr/packed_struct.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef RBIMPL_ATTR_PACKED_STRUCT_H /*-*-C++-*-vi:se ft=cpp:*/
-#define RBIMPL_ATTR_PACKED_STRUCT_H
-/**
- * @file
- * @author Ruby developers <ruby-core@ruby-lang.org>
- * @copyright This file is a part of the programming language Ruby.
- * Permission is hereby granted, to either redistribute and/or
- * modify this file, provided that the conditions mentioned in the
- * file COPYING are met. Consult the file for details.
- * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
- * implementation details. Don't take them as canon. They could
- * rapidly appear then vanish. The name (path) of this header file
- * is also an implementation detail. Do not expect it to persist
- * at the place it is now. Developers are free to move it anywhere
- * anytime at will.
- * @note To ruby-core: remember that this header can be possibly
- * recursively included from extension libraries written in C++.
- * Do not expect for instance `__VA_ARGS__` is always available.
- * We assume C99 for ruby itself but we don't assume languages of
- * extension libraries. They could be written in C++98.
- * @brief Defines #RBIMPL_ATTR_PACKED_STRUCT_BEGIN,
- * #RBIMPL_ATTR_PACKED_STRUCT_END,
- * #RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN, and
- * #RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END.
- */
-#include "ruby/internal/config.h"
-
-#ifndef RBIMPL_ATTR_PACKED_STRUCT_BEGIN
-# define RBIMPL_ATTR_PACKED_STRUCT_BEGIN() /* void */
-#endif
-#ifndef RBIMPL_ATTR_PACKED_STRUCT_END
-# define RBIMPL_ATTR_PACKED_STRUCT_END() /* void */
-#endif
-
-#if UNALIGNED_WORD_ACCESS
-# define RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN() RBIMPL_ATTR_PACKED_STRUCT_BEGIN()
-# define RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END() RBIMPL_ATTR_PACKED_STRUCT_END()
-#else
-# define RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN() /* void */
-# define RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END() /* void */
-#endif
-
-#endif
diff --git a/include/ruby/internal/config.h b/include/ruby/internal/config.h
index da070f0979..aa63376d7c 100644
--- a/include/ruby/internal/config.h
+++ b/include/ruby/internal/config.h
@@ -148,4 +148,8 @@
# undef RBIMPL_TEST3
#endif /* HAVE_VA_ARGS_MACRO */
+#ifndef USE_RVARGC
+# define USE_RVARGC 1
+#endif
+
#endif /* RBIMPL_CONFIG_H */
diff --git a/include/ruby/internal/core/rarray.h b/include/ruby/internal/core/rarray.h
index 90690fe794..c3bb40be25 100644
--- a/include/ruby/internal/core/rarray.h
+++ b/include/ruby/internal/core/rarray.h
@@ -29,13 +29,25 @@
#include "ruby/internal/core/rbasic.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/fl_type.h"
-#include "ruby/internal/gc.h"
+#include "ruby/internal/rgengc.h"
#include "ruby/internal/stdbool.h"
#include "ruby/internal/value.h"
#include "ruby/internal/value_type.h"
#include "ruby/assert.h"
/**
+ * @private
+ * @warning Do not touch this macro.
+ * @warning It is an implementation detail.
+ * @warning The value of this macro must match for ruby itself and all
+ * extension libraries, otherwise serious memory corruption shall
+ * occur.
+ */
+#ifndef USE_TRANSIENT_HEAP
+# define USE_TRANSIENT_HEAP 1
+#endif
+
+/**
* Convenient casting macro.
*
* @param obj An object, which is in fact an ::RArray.
@@ -47,9 +59,15 @@
#define RARRAY_EMBED_LEN_MASK RARRAY_EMBED_LEN_MASK
#define RARRAY_EMBED_LEN_MAX RARRAY_EMBED_LEN_MAX
#define RARRAY_EMBED_LEN_SHIFT RARRAY_EMBED_LEN_SHIFT
+#if USE_TRANSIENT_HEAP
+# define RARRAY_TRANSIENT_FLAG RARRAY_TRANSIENT_FLAG
+#else
+# define RARRAY_TRANSIENT_FLAG 0
+#endif
/** @endcond */
#define RARRAY_LEN rb_array_len /**< @alias{rb_array_len} */
#define RARRAY_CONST_PTR rb_array_const_ptr /**< @alias{rb_array_const_ptr} */
+#define RARRAY_CONST_PTR_TRANSIENT rb_array_const_ptr_transient /**< @alias{rb_array_const_ptr_transient} */
/** @cond INTERNAL_MACRO */
#if defined(__fcc__) || defined(__fcc_version) || \
@@ -62,6 +80,7 @@
#define RARRAY_EMBED_LEN RARRAY_EMBED_LEN
#define RARRAY_LENINT RARRAY_LENINT
+#define RARRAY_TRANSIENT_P RARRAY_TRANSIENT_P
#define RARRAY_ASET RARRAY_ASET
#define RARRAY_PTR RARRAY_PTR
/** @endcond */
@@ -111,8 +130,30 @@ enum ruby_rarray_flags {
* 3rd parties must not be aware that there even is more than one way to
* store array elements. It was a bad idea to expose this to them.
*/
+#if USE_RVARGC
RARRAY_EMBED_LEN_MASK = RUBY_FL_USER9 | RUBY_FL_USER8 | RUBY_FL_USER7 | RUBY_FL_USER6 |
RUBY_FL_USER5 | RUBY_FL_USER4 | RUBY_FL_USER3
+#else
+ RARRAY_EMBED_LEN_MASK = RUBY_FL_USER4 | RUBY_FL_USER3
+#endif
+
+#if USE_TRANSIENT_HEAP
+ ,
+
+ /**
+ * This flag has something to do with an array's "transiency". A transient
+ * array is an array of young generation (of generational GC), who stores
+ * its elements inside of dedicated memory pages called a transient heap.
+ * Not every young generation share that storage scheme, but elder
+ * generations must no join.
+ *
+ * @internal
+ *
+ * 3rd parties must not be aware that there even is more than one way to
+ * store array elements. It was a bad idea to expose this to them.
+ */
+ RARRAY_TRANSIENT_FLAG = RUBY_FL_USER13
+#endif
};
/**
@@ -122,6 +163,13 @@ enum ruby_rarray_flags {
enum ruby_rarray_consts {
/** Where ::RARRAY_EMBED_LEN_MASK resides. */
RARRAY_EMBED_LEN_SHIFT = RUBY_FL_USHIFT + 3
+
+#if !USE_RVARGC
+ ,
+
+ /** Max possible number elements that can be embedded. */
+ RARRAY_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(VALUE)
+#endif
};
/** Ruby's array. */
@@ -180,12 +228,16 @@ struct RArray {
* to store its elements. In this case the length is encoded into the
* flags.
*/
+#if USE_RVARGC
/* This is a length 1 array because:
* 1. GCC has a bug that does not optimize C flexible array members
* (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452)
* 2. Zero length arrays are not supported by all compilers
*/
const VALUE ary[1];
+#else
+ const VALUE ary[RARRAY_EMBED_LEN_MAX];
+#endif
} as;
};
@@ -212,6 +264,16 @@ VALUE *rb_ary_ptr_use_start(VALUE ary);
*/
void rb_ary_ptr_use_end(VALUE a);
+#if USE_TRANSIENT_HEAP
+/**
+ * Destructively converts an array of transient backend into ordinal one.
+ *
+ * @param[out] a An object of ::RArray.
+ * @pre `a` must be a transient array.
+ * @post `a` gets out of transient heap, destructively.
+ */
+void rb_ary_detransient(VALUE a);
+#endif
RBIMPL_SYMBOL_EXPORT_END()
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
@@ -284,6 +346,33 @@ RARRAY_LENINT(VALUE ary)
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+/**
+ * Queries if the array is a transient array.
+ *
+ * @param[in] ary Array in question.
+ * @retval true Yes it is.
+ * @retval false No it isn't.
+ * @pre `ary` must be an instance of ::RArray.
+ *
+ * @internal
+ *
+ * @shyouhei doesn't understand the benefit of this function called from
+ * extension libraries.
+ */
+static inline bool
+RARRAY_TRANSIENT_P(VALUE ary)
+{
+ RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY);
+
+#if USE_TRANSIENT_HEAP
+ return RB_FL_ANY_RAW(ary, RARRAY_TRANSIENT_FLAG);
+#else
+ return false;
+#endif
+}
+
+RBIMPL_ATTR_PURE_UNLESS_DEBUG()
/**
* @private
*
@@ -294,7 +383,7 @@ RBIMPL_ATTR_PURE_UNLESS_DEBUG()
* @return Its backend storage.
*/
static inline const VALUE *
-rb_array_const_ptr(VALUE a)
+rb_array_const_ptr_transient(VALUE a)
{
RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY);
@@ -306,21 +395,102 @@ rb_array_const_ptr(VALUE a)
}
}
+#if ! USE_TRANSIENT_HEAP
+RBIMPL_ATTR_PURE_UNLESS_DEBUG()
+#endif
+/**
+ * @private
+ *
+ * This is an implementation detail of RARRAY_PTR(). People do not use it
+ * directly.
+ *
+ * @param[in] a An object of ::RArray.
+ * @return Its backend storage.
+ * @post `a` is not a transient array.
+ */
+static inline const VALUE *
+rb_array_const_ptr(VALUE a)
+{
+ RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY);
+
+#if USE_TRANSIENT_HEAP
+ if (RARRAY_TRANSIENT_P(a)) {
+ rb_ary_detransient(a);
+ }
+#endif
+ return rb_array_const_ptr_transient(a);
+}
+
+/**
+ * @private
+ *
+ * This is an implementation detail of #RARRAY_PTR_USE. People do not use it
+ * directly.
+ *
+ * @param[in] a An object of ::RArray.
+ * @param[in] allow_transient Whether `a` can be transient or not.
+ * @return Its backend storage.
+ * @post `a` is not a transient array unless `allow_transient`.
+ */
+static inline VALUE *
+rb_array_ptr_use_start(VALUE a,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ int allow_transient)
+{
+ RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY);
+
+#if USE_TRANSIENT_HEAP
+ if (!allow_transient) {
+ if (RARRAY_TRANSIENT_P(a)) {
+ rb_ary_detransient(a);
+ }
+ }
+#endif
+
+ return rb_ary_ptr_use_start(a);
+}
+
+/**
+ * @private
+ *
+ * This is an implementation detail of #RARRAY_PTR_USE. People do not use it
+ * directly.
+ *
+ * @param[in] a An object of ::RArray.
+ * @param[in] allow_transient Whether `a` can be transient or not.
+ */
+static inline void
+rb_array_ptr_use_end(VALUE a,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ int allow_transient)
+{
+ RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY);
+ rb_ary_ptr_use_end(a);
+}
+
/**
* @private
*
* This is an implementation detail of #RARRAY_PTR_USE. People do not use it
* directly.
*/
-#define RBIMPL_RARRAY_STMT(ary, var, expr) do { \
+#define RBIMPL_RARRAY_STMT(flag, ary, var, expr) do { \
RBIMPL_ASSERT_TYPE((ary), RUBY_T_ARRAY); \
const VALUE rbimpl_ary = (ary); \
- VALUE *var = rb_ary_ptr_use_start(rbimpl_ary); \
+ VALUE *var = rb_array_ptr_use_start(rbimpl_ary, (flag)); \
expr; \
- rb_ary_ptr_use_end(rbimpl_ary); \
+ rb_array_ptr_use_end(rbimpl_ary, (flag)); \
} while (0)
/**
+ * @private
+ *
+ * This is an implementation detail of #RARRAY_PTR_USE. People do not use it
+ * directly.
+ */
+#define RARRAY_PTR_USE_END(a) rb_array_ptr_use_end(a, 0)
+
+/**
* Declares a section of code where raw pointers are used. In case you need to
* touch the raw C array instead of polite CAPIs, then that operation shall be
* wrapped using this macro.
@@ -346,11 +516,21 @@ rb_array_const_ptr(VALUE a)
* them use it... Maybe some transition path can be implemented later.
*/
#define RARRAY_PTR_USE(ary, ptr_name, expr) \
- RBIMPL_RARRAY_STMT(ary, ptr_name, expr)
+ RBIMPL_RARRAY_STMT(0, ary, ptr_name, expr)
+
+/**
+ * Identical to #RARRAY_PTR_USE, except the pointer can be a transient one.
+ *
+ * @param ary An object of ::RArray.
+ * @param ptr_name A variable name which points the C array in `expr`.
+ * @param expr The expression that touches `ptr_name`.
+ */
+#define RARRAY_PTR_USE_TRANSIENT(ary, ptr_name, expr) \
+ RBIMPL_RARRAY_STMT(1, ary, ptr_name, expr)
/**
* Wild use of a C pointer. This function accesses the backend storage
- * directly. This is slower than #RARRAY_PTR_USE. It exercises
+ * directly. This is slower than #RARRAY_PTR_USE_TRANSIENT. It exercises
* extra manoeuvres to protect our generational GC. Use of this function is
* considered archaic. Use a modern way instead.
*
@@ -385,7 +565,7 @@ RARRAY_PTR(VALUE ary)
static inline void
RARRAY_ASET(VALUE ary, long i, VALUE v)
{
- RARRAY_PTR_USE(ary, ptr,
+ RARRAY_PTR_USE_TRANSIENT(ary, ptr,
RB_OBJ_WRITE(ary, &ptr[i], v));
}
@@ -400,6 +580,6 @@ RARRAY_ASET(VALUE ary, long i, VALUE v)
* remains as it is due to that. If we could warn such usages we can set a
* transition path, but currently no way is found to do so.
*/
-#define RARRAY_AREF(a, i) RARRAY_CONST_PTR(a)[i]
+#define RARRAY_AREF(a, i) RARRAY_CONST_PTR_TRANSIENT(a)[i]
#endif /* RBIMPL_RARRAY_H */
diff --git a/include/ruby/internal/core/rbasic.h b/include/ruby/internal/core/rbasic.h
index a1477e2600..4617f743a7 100644
--- a/include/ruby/internal/core/rbasic.h
+++ b/include/ruby/internal/core/rbasic.h
@@ -56,20 +56,22 @@ enum ruby_rvalue_flags {
};
/**
- * Ruby object's base components. All Ruby objects have them in common.
+ * Ruby's object's, base components. Every single ruby objects have them in
+ * common.
*/
struct
RUBY_ALIGNAS(SIZEOF_VALUE)
RBasic {
/**
- * Per-object flags. Each Ruby object has its own characteristics apart
- * from its class. For instance, whether an object is frozen or not is not
- * controlled by its class. This is where such properties are stored.
+ * Per-object flags. Each ruby objects have their own characteristics
+ * apart from their classes. For instance whether an object is frozen or
+ * not is not controlled by its class. This is where such properties are
+ * stored.
*
* @see enum ::ruby_fl_type
*
- * @note This is ::VALUE rather than an enum for alignment purposes. Back
+ * @note This is ::VALUE rather than an enum for alignment purpose. Back
* in the 1990s there were no such thing like `_Alignas` in C.
*/
VALUE flags;
@@ -77,10 +79,10 @@ RBasic {
/**
* Class of an object. Every object has its class. Also, everything is an
* object in Ruby. This means classes are also objects. Classes have
- * their own classes, classes of classes have their classes too, and it
- * recursively continues forever.
+ * their own classes, classes of classes have their classes, too ... and
+ * it recursively continues forever.
*
- * Also note the `const` qualifier. In Ruby, an object cannot "change" its
+ * Also note the `const` qualifier. In ruby an object cannot "change" its
* class.
*/
const VALUE klass;
diff --git a/include/ruby/internal/core/rdata.h b/include/ruby/internal/core/rdata.h
index e4c146a716..43ab3c01e7 100644
--- a/include/ruby/internal/core/rdata.h
+++ b/include/ruby/internal/core/rdata.h
@@ -37,8 +37,12 @@
#include "ruby/defines.h"
/** @cond INTERNAL_MACRO */
-#ifndef RUBY_UNTYPED_DATA_WARNING
-#define RUBY_UNTYPED_DATA_WARNING 1
+#ifdef RUBY_UNTYPED_DATA_WARNING
+# /* Take that. */
+#elif defined(RUBY_EXPORT)
+# define RUBY_UNTYPED_DATA_WARNING 1
+#else
+# define RUBY_UNTYPED_DATA_WARNING 0
#endif
#define RBIMPL_DATA_FUNC(f) RBIMPL_CAST((void (*)(void *))(f))
@@ -327,6 +331,15 @@ rb_data_object_get_warning(VALUE obj)
return rb_data_object_get(obj);
}
+#if defined(HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR_CONSTANT_P)
+# define rb_data_object_wrap_warning(klass, ptr, mark, free) \
+ RB_GNUC_EXTENSION( \
+ __builtin_choose_expr( \
+ __builtin_constant_p(klass) && !(klass), \
+ rb_data_object_wrap(klass, ptr, mark, free), \
+ (rb_data_object_wrap_warning)(klass, ptr, mark, free)))
+#endif
+
/**
* This is an implementation detail of #Data_Make_Struct. People don't use it
* directly.
diff --git a/include/ruby/internal/core/rfile.h b/include/ruby/internal/core/rfile.h
index a0eb8cb833..f8dddde9e5 100644
--- a/include/ruby/internal/core/rfile.h
+++ b/include/ruby/internal/core/rfile.h
@@ -25,7 +25,7 @@
/* rb_io_t is in ruby/io.h. The header file has historically not been included
* into ruby/ruby.h. We follow that tradition. */
-struct rb_io;
+struct rb_io_t;
/**
* Ruby's File and IO. Ruby's IO are not just file descriptors. They have
@@ -38,7 +38,7 @@ struct RFile {
struct RBasic basic;
/** IO's specific fields. */
- struct rb_io *fptr;
+ struct rb_io_t *fptr;
};
/**
diff --git a/include/ruby/internal/core/rhash.h b/include/ruby/internal/core/rhash.h
index 897c570794..61d2c15d87 100644
--- a/include/ruby/internal/core/rhash.h
+++ b/include/ruby/internal/core/rhash.h
@@ -54,6 +54,19 @@
*
* @internal
*
+ * Declaration of rb_hash_iter_lev() is at include/ruby/backward.h.
+ */
+#define RHASH_ITER_LEV(h) rb_hash_iter_lev(h)
+
+/**
+ * @private
+ *
+ * @deprecated This macro once was a thing in the old days, but makes no sense
+ * any longer today. Exists here for backwards compatibility
+ * only. You can safely forget about it.
+ *
+ * @internal
+ *
* Declaration of rb_hash_ifnone() is at include/ruby/backward.h.
*/
#define RHASH_IFNONE(h) rb_hash_ifnone(h)
diff --git a/include/ruby/internal/core/rmatch.h b/include/ruby/internal/core/rmatch.h
index a528c2999e..2d2fd897f5 100644
--- a/include/ruby/internal/core/rmatch.h
+++ b/include/ruby/internal/core/rmatch.h
@@ -68,7 +68,7 @@ struct rmatch_offset {
};
/** Represents a match. */
-struct rb_matchext_struct {
+struct rmatch {
/**
* "Registers" of a match. This is a quasi-opaque struct that holds
* execution result of a match. Roughly resembles `&~`.
@@ -82,8 +82,6 @@ struct rb_matchext_struct {
int char_offset_num_allocated;
};
-typedef struct rb_matchext_struct rb_matchext_t;
-
/**
* Regular expression execution context. When a regular expression "matches"
* to a string, it generates capture groups etc. This struct holds that info.
@@ -104,13 +102,16 @@ struct RMatch {
VALUE str;
/**
+ * The result of this match.
+ */
+ struct rmatch *rmatch;
+
+ /**
* The expression of this match.
*/
VALUE regexp; /* RRegexp */
};
-#define RMATCH_EXT(m) ((rb_matchext_t *)((char *)(m) + sizeof(struct RMatch)))
-
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
@@ -138,7 +139,8 @@ static inline struct re_registers *
RMATCH_REGS(VALUE match)
{
RBIMPL_ASSERT_TYPE(match, RUBY_T_MATCH);
- return &RMATCH_EXT(match)->regs;
+ RBIMPL_ASSERT_OR_ASSUME(RMATCH(match)->rmatch != NULL);
+ return &RMATCH(match)->rmatch->regs;
}
#endif /* RBIMPL_RMATCH_H */
diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h
index c2bcae6306..b1c2e1b0a9 100644
--- a/include/ruby/internal/core/robject.h
+++ b/include/ruby/internal/core/robject.h
@@ -74,6 +74,17 @@ enum ruby_robject_flags {
ROBJECT_EMBED = RUBY_FL_USER1
};
+#if !USE_RVARGC
+/**
+ * This is an enum because GDB wants it (rather than a macro). People need not
+ * bother.
+ */
+enum ruby_robject_consts {
+ /** Max possible number of instance variables that can be embedded. */
+ ROBJECT_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(VALUE)
+};
+#endif
+
struct st_table;
/**
@@ -107,6 +118,7 @@ struct RObject {
struct rb_id_table *iv_index_tbl;
} heap;
+#if USE_RVARGC
/* Embedded instance variables. When an object is small enough, it
* uses this area to store the instance variables.
*
@@ -116,9 +128,23 @@ struct RObject {
* 2. Zero length arrays are not supported by all compilers
*/
VALUE ary[1];
+#else
+ /**
+ * Embedded instance variables. When an object is small enough, it
+ * uses this area to store the instance variables.
+ */
+ VALUE ary[ROBJECT_EMBED_LEN_MAX];
+#endif
} as;
};
+/* Offsets for YJIT */
+#ifndef __cplusplus
+static const int32_t ROBJECT_OFFSET_AS_HEAP_IVPTR = offsetof(struct RObject, as.heap.ivptr);
+static const int32_t ROBJECT_OFFSET_AS_HEAP_IV_INDEX_TBL = offsetof(struct RObject, as.heap.iv_index_tbl);
+static const int32_t ROBJECT_OFFSET_AS_ARY = offsetof(struct RObject, as.ary);
+#endif
+
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
diff --git a/include/ruby/internal/core/rstring.h b/include/ruby/internal/core/rstring.h
index 0bca74e688..e394ab7dca 100644
--- a/include/ruby/internal/core/rstring.h
+++ b/include/ruby/internal/core/rstring.h
@@ -42,7 +42,13 @@
/** @cond INTERNAL_MACRO */
#define RSTRING_NOEMBED RSTRING_NOEMBED
+#if !USE_RVARGC
+#define RSTRING_EMBED_LEN_MASK RSTRING_EMBED_LEN_MASK
+#define RSTRING_EMBED_LEN_SHIFT RSTRING_EMBED_LEN_SHIFT
+#define RSTRING_EMBED_LEN_MAX RSTRING_EMBED_LEN_MAX
+#endif
#define RSTRING_FSTR RSTRING_FSTR
+#define RSTRING_EMBED_LEN RSTRING_EMBED_LEN
#define RSTRING_LEN RSTRING_LEN
#define RSTRING_LENINT RSTRING_LENINT
#define RSTRING_PTR RSTRING_PTR
@@ -156,6 +162,21 @@ enum ruby_rstring_flags {
*/
RSTRING_NOEMBED = RUBY_FL_USER1,
+#if !USE_RVARGC
+ /**
+ * When a string employs embedded strategy (see ::RSTRING_NOEMBED), these
+ * bits are used to store the number of bytes actually filled into
+ * ::RString::ary.
+ *
+ * @internal
+ *
+ * 3rd parties must not be aware that there even is more than one way to
+ * store a string. Might better be hidden.
+ */
+ RSTRING_EMBED_LEN_MASK = RUBY_FL_USER2 | RUBY_FL_USER3 | RUBY_FL_USER4 |
+ RUBY_FL_USER5 | RUBY_FL_USER6,
+#endif
+
/* Actually, string encodings are also encoded into the flags, using
* remaining bits.*/
@@ -181,6 +202,20 @@ enum ruby_rstring_flags {
RSTRING_FSTR = RUBY_FL_USER17
};
+#if !USE_RVARGC
+/**
+ * This is an enum because GDB wants it (rather than a macro). People need not
+ * bother.
+ */
+enum ruby_rstring_consts {
+ /** Where ::RSTRING_EMBED_LEN_MASK resides. */
+ RSTRING_EMBED_LEN_SHIFT = RUBY_FL_USHIFT + 2,
+
+ /** Max possible number of characters that can be embedded. */
+ RSTRING_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(char) - 1
+};
+#endif
+
/**
* Ruby's String. A string in ruby conceptually has these information:
*
@@ -198,13 +233,6 @@ struct RString {
/** Basic part, including flags and class. */
struct RBasic basic;
- /**
- * Length of the string, not including terminating NUL character.
- *
- * @note This is in bytes.
- */
- long len;
-
/** String's specific fields. */
union {
@@ -213,6 +241,14 @@ struct RString {
* pattern.
*/
struct {
+
+ /**
+ * Length of the string, not including terminating NUL character.
+ *
+ * @note This is in bytes.
+ */
+ long len;
+
/**
* Pointer to the contents of the string. In the old days each
* string had dedicated memory regions. That is no longer true
@@ -243,12 +279,24 @@ struct RString {
/** Embedded contents. */
struct {
+#if USE_RVARGC
+ long len;
/* This is a length 1 array because:
* 1. GCC has a bug that does not optimize C flexible array members
* (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452)
* 2. Zero length arrays are not supported by all compilers
*/
char ary[1];
+#else
+ /**
+ * When a string is short enough, it uses this area to store the
+ * contents themselves. This was impractical in the 20th century,
+ * but these days 64 bit machines can typically hold 24 bytes here.
+ * Could be sufficiently large. In this case the length is encoded
+ * into the flags.
+ */
+ char ary[RSTRING_EMBED_LEN_MAX + 1];
+#endif
} embed;
} as;
};
@@ -361,12 +409,31 @@ RBIMPL_ATTR_ARTIFICIAL()
*
* @param[in] str String in question.
* @return Its length, in bytes.
- * @pre `str` must be an instance of ::RString.
+ * @pre `str` must be an instance of ::RString, and must has its
+ * ::RSTRING_NOEMBED flag off.
+ *
+ * @internal
+ *
+ * This was a macro before. It was inevitable to be public, since macros are
+ * global constructs. But should it be forever? Now that it is a function,
+ * @shyouhei thinks it could just be eliminated, hidden into implementation
+ * details.
*/
static inline long
-RSTRING_LEN(VALUE str)
+RSTRING_EMBED_LEN(VALUE str)
{
- return RSTRING(str)->len;
+ RBIMPL_ASSERT_TYPE(str, RUBY_T_STRING);
+ RBIMPL_ASSERT_OR_ASSUME(! RB_FL_ANY_RAW(str, RSTRING_NOEMBED));
+
+#if USE_RVARGC
+ long f = RSTRING(str)->as.embed.len;
+ return f;
+#else
+ VALUE f = RBASIC(str)->flags;
+ f &= RSTRING_EMBED_LEN_MASK;
+ f >>= RSTRING_EMBED_LEN_SHIFT;
+ return RBIMPL_CAST((long)f);
+#endif
}
RBIMPL_WARNING_PUSH()
@@ -396,7 +463,7 @@ rbimpl_rstring_getmem(VALUE str)
else {
/* Expecting compilers to optimize this on-stack struct away. */
struct RString retval;
- retval.len = RSTRING_LEN(str);
+ retval.as.heap.len = RSTRING_EMBED_LEN(str);
retval.as.heap.ptr = RSTRING(str)->as.embed.ary;
return retval;
}
@@ -404,6 +471,21 @@ rbimpl_rstring_getmem(VALUE str)
RBIMPL_WARNING_POP()
+RBIMPL_ATTR_PURE_UNLESS_DEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+/**
+ * Queries the length of the string.
+ *
+ * @param[in] str String in question.
+ * @return Its length, in bytes.
+ * @pre `str` must be an instance of ::RString.
+ */
+static inline long
+RSTRING_LEN(VALUE str)
+{
+ return rbimpl_rstring_getmem(str).as.heap.len;
+}
+
RBIMPL_ATTR_ARTIFICIAL()
/**
* Queries the contents pointer of the string.
@@ -417,9 +499,13 @@ RSTRING_PTR(VALUE str)
{
char *ptr = rbimpl_rstring_getmem(str).as.heap.ptr;
- if (RUBY_DEBUG && RB_UNLIKELY(! ptr)) {
+ if (RB_UNLIKELY(! ptr)) {
/* :BEWARE: @shyouhei thinks that currently, there are rooms for this
- * function to return NULL. Better check here for maximum safety.
+ * function to return NULL. In the 20th century that was a pointless
+ * concern. However struct RString can hold fake strings nowadays. It
+ * seems no check against NULL are exercised around handling of them
+ * (one of such usages is located in marshal.c, which scares
+ * @shyouhei). Better check here for maximum safety.
*
* Also, this is not rb_warn() because RSTRING_PTR() can be called
* during GC (see what obj_info() does). rb_warn() needs to allocate
@@ -443,12 +529,12 @@ RSTRING_END(VALUE str)
{
struct RString buf = rbimpl_rstring_getmem(str);
- if (RUBY_DEBUG && RB_UNLIKELY(! buf.as.heap.ptr)) {
+ if (RB_UNLIKELY(! buf.as.heap.ptr)) {
/* Ditto. */
rb_debug_rstring_null_ptr("RSTRING_END");
}
- return &buf.as.heap.ptr[buf.len];
+ return &buf.as.heap.ptr[buf.as.heap.len];
}
RBIMPL_ATTR_ARTIFICIAL()
@@ -482,7 +568,7 @@ RSTRING_LENINT(VALUE str)
__extension__ ({ \
struct RString rbimpl_str = rbimpl_rstring_getmem(str); \
(ptrvar) = rbimpl_str.as.heap.ptr; \
- (lenvar) = rbimpl_str.len; \
+ (lenvar) = rbimpl_str.as.heap.len; \
})
#else
# define RSTRING_GETMEM(str, ptrvar, lenvar) \
diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h
index 6c19576c20..bbf208867d 100644
--- a/include/ruby/internal/core/rtypeddata.h
+++ b/include/ruby/internal/core/rtypeddata.h
@@ -114,8 +114,6 @@
#define RUBY_TYPED_PROMOTED1 RUBY_TYPED_PROMOTED1
/** @endcond */
-#define TYPED_DATA_EMBEDDED 2
-
/**
* @private
*
@@ -139,8 +137,6 @@ rbimpl_typeddata_flags {
*/
RUBY_TYPED_FREE_IMMEDIATELY = 1,
- RUBY_TYPED_EMBEDDABLE = 2,
-
/**
* This flag has something to do with Ractor. Multiple Ractors run without
* protecting each other. Sharing an object among Ractors is basically
@@ -177,16 +173,10 @@ rbimpl_typeddata_flags {
RUBY_TYPED_WB_PROTECTED = RUBY_FL_WB_PROTECTED, /* THIS FLAG DEPENDS ON Ruby version */
/**
- * This flag no longer in use
+ * This flag is mysterious. It seems nobody is currently using it. The
+ * intention of this flag is also unclear. We need further investigations.
*/
- RUBY_TYPED_UNUSED = RUBY_FL_UNUSED6,
-
- /**
- * This flag determines whether marking and compaction should be carried out
- * using the dmark/dcompact callback functions or whether we should mark
- * declaratively using a list of references defined inside the data struct we're wrapping
- */
- RUBY_TYPED_DECL_MARKING = RUBY_FL_USER2
+ RUBY_TYPED_PROMOTED1 = RUBY_FL_PROMOTED1 /* THIS FLAG DEPENDS ON Ruby version */
};
/**
@@ -357,14 +347,16 @@ struct RTypedData {
* data. This roughly resembles a Ruby level class (apart from method
* definition etc.)
*/
- const rb_data_type_t *const type;
+ const rb_data_type_t *type;
/**
* This has to be always 1.
*
* @internal
+ *
+ * Why, then, this is not a const ::VALUE?
*/
- const VALUE typed_flag;
+ VALUE typed_flag;
/** Pointer to the actual C level struct that you want to wrap. */
void *data;
@@ -464,7 +456,7 @@ RBIMPL_SYMBOL_EXPORT_END()
*/
#define TypedData_Make_Struct0(result, klass, type, size, data_type, sval) \
VALUE result = rb_data_typed_object_zalloc(klass, size, data_type); \
- (sval) = (type *)RTYPEDDATA_GET_DATA(result); \
+ (sval) = RBIMPL_CAST((type *)RTYPEDDATA_DATA(result)); \
RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval))
/**
@@ -515,36 +507,6 @@ RBIMPL_SYMBOL_EXPORT_END()
#define TypedData_Get_Struct(obj,type,data_type,sval) \
((sval) = RBIMPL_CAST((type *)rb_check_typeddata((obj), (data_type))))
-static inline bool
-RTYPEDDATA_EMBEDDED_P(VALUE obj)
-{
-#if RUBY_DEBUG
- if (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) {
- Check_Type(obj, RUBY_T_DATA);
- RBIMPL_UNREACHABLE_RETURN(false);
- }
-#endif
-
- return RTYPEDDATA(obj)->typed_flag & TYPED_DATA_EMBEDDED;
-}
-
-static inline void *
-RTYPEDDATA_GET_DATA(VALUE obj)
-{
-#if RUBY_DEBUG
- if (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) {
- Check_Type(obj, RUBY_T_DATA);
- RBIMPL_UNREACHABLE_RETURN(false);
- }
-#endif
-
- /* We reuse the data pointer in embedded TypedData. We can't use offsetof
- * since RTypedData a non-POD type in C++. */
- const size_t embedded_typed_data_size = sizeof(struct RTypedData) - sizeof(void *);
-
- return RTYPEDDATA_EMBEDDED_P(obj) ? (char *)obj + embedded_typed_data_size : RTYPEDDATA(obj)->data;
-}
-
RBIMPL_ATTR_PURE()
RBIMPL_ATTR_ARTIFICIAL()
/**
@@ -561,8 +523,7 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline bool
rbimpl_rtypeddata_p(VALUE obj)
{
- VALUE typed_flag = RTYPEDDATA(obj)->typed_flag;
- return typed_flag != 0 && typed_flag <= 3;
+ return RTYPEDDATA(obj)->typed_flag == 1;
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
diff --git a/include/ruby/internal/dllexport.h b/include/ruby/internal/dllexport.h
index 71026e7100..08a262209d 100644
--- a/include/ruby/internal/dllexport.h
+++ b/include/ruby/internal/dllexport.h
@@ -37,7 +37,9 @@
* ```
*/
#undef RUBY_EXTERN
-#if defined(RUBY_EXPORT)
+#if defined(MJIT_HEADER) && defined(_WIN32)
+# define RUBY_EXTERN extern __declspec(dllimport)
+#elif defined(RUBY_EXPORT)
# define RUBY_EXTERN extern
#elif defined(_WIN32)
# define RUBY_EXTERN extern __declspec(dllimport)
@@ -57,6 +59,36 @@
# define RUBY_FUNC_EXPORTED /* void */
#endif
+/**
+ * @cond INTERNAL_MACRO
+ *
+ * These MJIT related macros are placed here because translate_mjit_header can
+ * need them. Extension libraries should not touch.
+ */
+
+/* These macros are used for functions which are exported only for MJIT
+ and NOT ensured to be exported in future versions. */
+
+#if ! defined(MJIT_HEADER)
+# define MJIT_FUNC_EXPORTED RUBY_FUNC_EXPORTED
+#elif ! RBIMPL_COMPILER_IS(MSVC)
+# define MJIT_FUNC_EXPORTED RUBY_FUNC_EXPORTED
+#else
+# define MJIT_FUNC_EXPORTED static
+#endif
+
+#define MJIT_SYMBOL_EXPORT_BEGIN RUBY_SYMBOL_EXPORT_BEGIN
+#define MJIT_SYMBOL_EXPORT_END RUBY_SYMBOL_EXPORT_END
+
+/* On mswin, MJIT header transformation can't be used since cl.exe can't output
+ preprocessed output preserving macros. So this `MJIT_STATIC` is needed
+ to force non-static function to static on MJIT header to avoid symbol conflict. */
+#ifdef MJIT_HEADER
+# define MJIT_STATIC static
+#else
+# define MJIT_STATIC
+#endif
+
/** @endcond */
/** Shortcut macro equivalent to `RUBY_SYMBOL_EXPORT_BEGIN extern "C" {`.
diff --git a/include/ruby/internal/encoding/encoding.h b/include/ruby/internal/encoding/encoding.h
index a58f9f2b15..4748ca806b 100644
--- a/include/ruby/internal/encoding/encoding.h
+++ b/include/ruby/internal/encoding/encoding.h
@@ -28,7 +28,6 @@
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/attr/returns_nonnull.h"
#include "ruby/internal/dllexport.h"
-#include "ruby/internal/encoding/coderange.h"
#include "ruby/internal/value.h"
#include "ruby/internal/core/rbasic.h"
#include "ruby/internal/fl_type.h"
@@ -80,7 +79,7 @@ enum ruby_encoding_consts {
static inline void
RB_ENCODING_SET_INLINED(VALUE obj, int encindex)
{
- VALUE f = /* upcast */ RBIMPL_CAST((VALUE)encindex);
+ VALUE f = /* upcast */ encindex;
f <<= RUBY_ENCODING_SHIFT;
RB_FL_UNSET_RAW(obj, RUBY_ENCODING_MASK);
@@ -140,6 +139,23 @@ RBIMPL_ATTR_NOALIAS()
int rb_char_to_option_kcode(int c, int *option, int *kcode);
/**
+ * Creates a new encoding, using the passed one as a template.
+ *
+ * @param[in] name Name of the creating encoding.
+ * @param[in] src Template.
+ * @exception rb_eArgError Duplicated or malformed `name`.
+ * @return Replicated new encoding's index.
+ * @post Encoding named `name` is created as a copy of `src`, whose index
+ * is the return value.
+ *
+ * @internal
+ *
+ * `name` can be `NULL`, but that just raises an exception. OTOH it seems no
+ * sanity check is done against `src`...?
+ */
+int rb_enc_replicate(const char *name, rb_encoding *src);
+
+/**
* Creates a new "dummy" encoding. Roughly speaking, an encoding is dummy when
* it is stateful. Notable example of dummy encoding are those defined in
* ISO/IEC 2022
diff --git a/include/ruby/internal/encoding/string.h b/include/ruby/internal/encoding/string.h
index 2cfa91c01e..6ed7ca1c90 100644
--- a/include/ruby/internal/encoding/string.h
+++ b/include/ruby/internal/encoding/string.h
@@ -30,7 +30,7 @@
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
- * Identical to rb_str_new(), except it additionally takes an encoding.
+ * Identical to rb_enc_str_new(), except it additionally takes an encoding.
*
* @param[in] ptr A memory region of `len` bytes length.
* @param[in] len Length of `ptr`, in bytes, not including the
@@ -307,13 +307,13 @@ RBIMPL_ATTR_NONNULL(())
/**
* Looks for the passed string in the passed buffer.
*
- * @param[in] x Query string.
+ * @param[in] x Buffer that potentially includes `y`.
* @param[in] m Number of bytes of `x`.
- * @param[in] y Buffer that potentially includes `x`.
+ * @param[in] y Query string.
* @param[in] n Number of bytes of `y`.
* @param[in] enc Encoding of both `x` and `y`.
* @retval -1 Not found.
- * @retval otherwise Found index in `y`.
+ * @retval otherwise Found index in `x`.
* @note This API can match at a non-character-boundary.
*/
long rb_memsearch(const void *x, long m, const void *y, long n, rb_encoding *enc);
diff --git a/include/ruby/internal/error.h b/include/ruby/internal/error.h
index cd37f4461a..49e2276cb9 100644
--- a/include/ruby/internal/error.h
+++ b/include/ruby/internal/error.h
@@ -50,19 +50,7 @@ typedef enum {
/** Warning is for experimental features. */
RB_WARN_CATEGORY_EXPERIMENTAL,
- /** Warning is for performance issues (not enabled by -w). */
- RB_WARN_CATEGORY_PERFORMANCE,
-
- RB_WARN_CATEGORY_DEFAULT_BITS = (
- (1U << RB_WARN_CATEGORY_DEPRECATED) |
- (1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
- 0),
-
- RB_WARN_CATEGORY_ALL_BITS = (
- (1U << RB_WARN_CATEGORY_DEPRECATED) |
- (1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
- (1U << RB_WARN_CATEGORY_PERFORMANCE) |
- 0)
+ RB_WARN_CATEGORY_ALL_BITS = 0x6 /* no RB_WARN_CATEGORY_NONE bit */
} rb_warning_category_t;
/** for rb_readwrite_sys_fail first argument */
@@ -481,7 +469,7 @@ VALUE *rb_ruby_debug_ptr(void);
*/
#define ruby_debug (*rb_ruby_debug_ptr())
-/* reports if $VERBOSE is true */
+/* reports if `-W' specified */
RBIMPL_ATTR_NONNULL((1))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
/**
@@ -496,8 +484,7 @@ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
* default, the method just emits its passed contents to ::rb_stderr using
* rb_io_write().
*
- * @note This function is affected by the value of $VERBOSE, it does
- * nothing unless $VERBOSE is true.
+ * @note This function is affected by the `-W` flag.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
*
* @internal
@@ -522,7 +509,7 @@ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
* Issues a compile-time warning that happens at `__file__:__line__`. Purpose
* of this function being exposed to CAPI is unclear.
*
- * @note This function is affected by the value of $VERBOSE.
+ * @note This function is affected by the `-W` flag.
* @param[in] file The path corresponding to Ruby level `__FILE__`.
* @param[in] line The number corresponding to Ruby level `__LINE__`.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
@@ -535,20 +522,19 @@ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
* Identical to rb_sys_fail(), except it does not raise an exception to render
* a warning instead.
*
- * @note This function is affected by the value of $VERBOSE.
+ * @note This function is affected by the `-W` flag.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
*/
void rb_sys_warning(const char *fmt, ...);
-/* reports if $VERBOSE is not nil (so if it is true or false) */
+/* reports always */
RBIMPL_ATTR_COLD()
RBIMPL_ATTR_NONNULL((1))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
/**
- * Identical to rb_warning(), except it reports unless $VERBOSE is nil.
+ * Identical to rb_warning(), except it reports always regardless of runtime
+ * `-W` flag.
*
- * @note This function is affected by the value of $VERBOSE, it does
- * nothing if $VERBOSE is nil.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
*/
void rb_warn(const char *fmt, ...);
@@ -557,7 +543,8 @@ RBIMPL_ATTR_COLD()
RBIMPL_ATTR_NONNULL((2))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
/**
- * Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
+ * Identical to rb_category_warning(), except it reports always regardless of
+ * runtime `-W` flag.
*
* @param[in] cat Category e.g. deprecated.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
@@ -567,7 +554,8 @@ void rb_category_warn(rb_warning_category_t cat, const char *fmt, ...);
RBIMPL_ATTR_NONNULL((1, 3))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
/**
- * Identical to rb_compile_warning(), except it reports unless $VERBOSE is nil.
+ * Identical to rb_compile_warning(), except it reports always regardless of
+ * runtime `-W` flag.
*
* @param[in] file The path corresponding to Ruby level `__FILE__`.
* @param[in] line The number corresponding to Ruby level `__LINE__`.
diff --git a/include/ruby/internal/event.h b/include/ruby/internal/event.h
index 1d194ed618..04b137a193 100644
--- a/include/ruby/internal/event.h
+++ b/include/ruby/internal/event.h
@@ -23,10 +23,6 @@
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-
/* These macros are not enums because they are wider than int.*/
/**
@@ -58,7 +54,6 @@
#define RUBY_EVENT_THREAD_END 0x0800 /**< Encountered an end of a thread. */
#define RUBY_EVENT_FIBER_SWITCH 0x1000 /**< Encountered a `Fiber#yield`. */
#define RUBY_EVENT_SCRIPT_COMPILED 0x2000 /**< Encountered an `eval`. */
-#define RUBY_EVENT_RESCUE 0x4000 /**< Encountered a `rescue` statement. */
#define RUBY_EVENT_TRACEPOINT_ALL 0xffff /**< Bitmask of extended events. */
/** @} */
diff --git a/include/ruby/internal/fl_type.h b/include/ruby/internal/fl_type.h
index 2a8bdccd46..7383426b23 100644
--- a/include/ruby/internal/fl_type.h
+++ b/include/ruby/internal/fl_type.h
@@ -57,7 +57,8 @@
#define FL_SINGLETON RBIMPL_CAST((VALUE)RUBY_FL_SINGLETON) /**< @old{RUBY_FL_SINGLETON} */
#define FL_WB_PROTECTED RBIMPL_CAST((VALUE)RUBY_FL_WB_PROTECTED) /**< @old{RUBY_FL_WB_PROTECTED} */
-#define FL_PROMOTED RBIMPL_CAST((VALUE)RUBY_FL_PROMOTED) /**< @old{RUBY_FL_PROMOTED} */
+#define FL_PROMOTED0 RBIMPL_CAST((VALUE)RUBY_FL_PROMOTED0) /**< @old{RUBY_FL_PROMOTED0} */
+#define FL_PROMOTED1 RBIMPL_CAST((VALUE)RUBY_FL_PROMOTED1) /**< @old{RUBY_FL_PROMOTED1} */
#define FL_FINALIZE RBIMPL_CAST((VALUE)RUBY_FL_FINALIZE) /**< @old{RUBY_FL_FINALIZE} */
#define FL_TAINT RBIMPL_CAST((VALUE)RUBY_FL_TAINT) /**< @old{RUBY_FL_TAINT} */
#define FL_SHAREABLE RBIMPL_CAST((VALUE)RUBY_FL_SHAREABLE) /**< @old{RUBY_FL_SHAREABLE} */
@@ -110,6 +111,13 @@
#define RB_OBJ_FREEZE_RAW RB_OBJ_FREEZE_RAW
#define RB_OBJ_FROZEN RB_OBJ_FROZEN
#define RB_OBJ_FROZEN_RAW RB_OBJ_FROZEN_RAW
+#define RB_OBJ_INFECT RB_OBJ_INFECT
+#define RB_OBJ_INFECT_RAW RB_OBJ_INFECT_RAW
+#define RB_OBJ_TAINT RB_OBJ_TAINT
+#define RB_OBJ_TAINTABLE RB_OBJ_TAINTABLE
+#define RB_OBJ_TAINTED RB_OBJ_TAINTED
+#define RB_OBJ_TAINTED_RAW RB_OBJ_TAINTED_RAW
+#define RB_OBJ_TAINT_RAW RB_OBJ_TAINT_RAW
#define RB_OBJ_UNTRUST RB_OBJ_TAINT
#define RB_OBJ_UNTRUSTED RB_OBJ_TAINTED
/** @endcond */
@@ -199,15 +207,12 @@ ruby_fl_type {
RUBY_FL_WB_PROTECTED = (1<<5),
/**
- * Ruby objects are "generational". There are young objects & old objects.
- * Young objects are prone to die & monitored relatively extensively by the
- * garbage collector. Old objects tend to live longer & are monitored less
- * frequently. When an object survives a GC, its age is incremented. When
- * age is equal to RVALUE_OLD_AGE, the object becomes Old. This flag is set
- * when an object becomes old, and is used by the write barrier to check if
- * an old object should be considered for marking more frequently - as old
- * objects that have references added between major GCs need to be remarked
- * to prevent the referred object being mistakenly swept.
+ * This flag has something to do with our garbage collector. These days
+ * ruby objects are "generational". There are those who are young and
+ * those who are old. Young objects are prone to die; monitored relatively
+ * extensively by the garbage collector. OTOH old objects tend to live
+ * longer. They are relatively rarely considered. This flag is set when a
+ * object experienced promotion i.e. survived a garbage collection.
*
* @internal
*
@@ -215,14 +220,41 @@ ruby_fl_type {
* 3rd parties. It must be an implementation detail that they should never
* know. Might better be hidden.
*/
- RUBY_FL_PROMOTED = (1<<5),
+ RUBY_FL_PROMOTED0 = (1<<5),
/**
- * This flag is no longer in use
+ * This flag has something to do with our garbage collector. These days
+ * ruby objects are "generational". There are those who are young and
+ * those who are old. Young objects are prone to die; monitored relatively
+ * extensively by the garbage collector. OTOH old objects tend to live
+ * longer. They are relatively rarely considered. This flag is set when a
+ * object experienced two promotions i.e. survived garbage collections
+ * twice.
*
* @internal
+ *
+ * But honestly, @shyouhei doesn't think this flag should be visible from
+ * 3rd parties. It must be an implementation detail that they should never
+ * know. Might better be hidden.
+ */
+ RUBY_FL_PROMOTED1 = (1<<6),
+
+ /**
+ * This flag has something to do with our garbage collector. These days
+ * ruby objects are "generational". There are those who are young and
+ * those who are old. Young objects are prone to die; monitored relatively
+ * extensively by the garbage collector. OTOH old objects tend to live
+ * longer. They are relatively rarely considered. This flag is set when a
+ * object experienced promotions i.e. survived more than one garbage
+ * collections.
+ *
+ * @internal
+ *
+ * But honestly, @shyouhei doesn't think this flag should be visible from
+ * 3rd parties. It must be an implementation detail that they should never
+ * know. Might better be hidden.
*/
- RUBY_FL_UNUSED6 = (1<<6),
+ RUBY_FL_PROMOTED = RUBY_FL_PROMOTED0 | RUBY_FL_PROMOTED1,
/**
* This flag has something to do with finalisers. A ruby object can have
@@ -251,7 +283,7 @@ ruby_fl_type {
# pragma deprecated(RUBY_FL_TAINT)
#endif
- = 0,
+ = (1<<8),
/**
* This flag has something to do with Ractor. Multiple Ractors run without
@@ -278,7 +310,7 @@ ruby_fl_type {
# pragma deprecated(RUBY_FL_UNTRUSTED)
#endif
- = 0,
+ = (1<<8),
/**
* This flag has something to do with object IDs. Unlike in the old days,
@@ -395,7 +427,7 @@ ruby_fl_type {
* 3rd parties. It must be an implementation detail that they should never
* know. Might better be hidden.
*/
- RUBY_FL_SINGLETON = RUBY_FL_USER1,
+ RUBY_FL_SINGLETON = RUBY_FL_USER0,
};
enum {
@@ -457,7 +489,7 @@ RB_FL_ABLE(VALUE obj)
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_FL_TEST(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_TEST(). 3rd parties need not use
* this. Just always use RB_FL_TEST().
*
* @param[in] obj Object in question.
@@ -505,7 +537,7 @@ RB_FL_TEST(VALUE obj, VALUE flags)
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_FL_ANY(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_ANY(). 3rd parties need not use
* this. Just always use RB_FL_ANY().
*
* @param[in] obj Object in question.
@@ -539,7 +571,7 @@ RB_FL_ANY(VALUE obj, VALUE flags)
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_FL_ALL(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_ALL(). 3rd parties need not use
* this. Just always use RB_FL_ALL().
*
* @param[in] obj Object in question.
@@ -575,7 +607,7 @@ RBIMPL_ATTR_ARTIFICIAL()
/**
* @private
*
- * This is an implementation detail of RB_FL_SET(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_SET(). 3rd parties need not use
* this. Just always use RB_FL_SET().
*
* @param[out] obj Object in question.
@@ -595,7 +627,7 @@ rbimpl_fl_set_raw_raw(struct RBasic *obj, VALUE flags)
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_FL_SET(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_SET(). 3rd parties need not use
* this. Just always use RB_FL_SET().
*
* @param[out] obj Object in question.
@@ -635,7 +667,7 @@ RBIMPL_ATTR_ARTIFICIAL()
/**
* @private
*
- * This is an implementation detail of RB_FL_UNSET(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_UNSET(). 3rd parties need not use
* this. Just always use RB_FL_UNSET().
*
* @param[out] obj Object in question.
@@ -655,7 +687,7 @@ rbimpl_fl_unset_raw_raw(struct RBasic *obj, VALUE flags)
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_FL_UNSET(). 3rd parties need not use
+ * This is an implenentation detail of RB_FL_UNSET(). 3rd parties need not use
* this. Just always use RB_FL_UNSET().
*
* @param[out] obj Object in question.
@@ -690,7 +722,7 @@ RBIMPL_ATTR_ARTIFICIAL()
/**
* @private
*
- * This is an implementation detail of RB_FL_REVERSE(). 3rd parties need not
+ * This is an implenentation detail of RB_FL_REVERSE(). 3rd parties need not
* use this. Just always use RB_FL_REVERSE().
*
* @param[out] obj Object in question.
@@ -710,7 +742,7 @@ rbimpl_fl_reverse_raw_raw(struct RBasic *obj, VALUE flags)
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_FL_REVERSE(). 3rd parties need not
+ * This is an implenentation detail of RB_FL_REVERSE(). 3rd parties need not
* use this. Just always use RB_FL_REVERSE().
*
* @param[out] obj Object in question.
@@ -755,7 +787,6 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline bool
RB_OBJ_TAINTABLE(VALUE obj)
{
- (void)obj;
return false;
}
@@ -773,7 +804,6 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline VALUE
RB_OBJ_TAINTED_RAW(VALUE obj)
{
- (void)obj;
return false;
}
@@ -791,7 +821,6 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline bool
RB_OBJ_TAINTED(VALUE obj)
{
- (void)obj;
return false;
}
@@ -807,7 +836,6 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline void
RB_OBJ_TAINT_RAW(VALUE obj)
{
- (void)obj;
return;
}
@@ -823,7 +851,6 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline void
RB_OBJ_TAINT(VALUE obj)
{
- (void)obj;
return;
}
@@ -840,8 +867,6 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline void
RB_OBJ_INFECT_RAW(VALUE dst, VALUE src)
{
- (void)dst;
- (void)src;
return;
}
@@ -858,15 +883,13 @@ RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
static inline void
RB_OBJ_INFECT(VALUE dst, VALUE src)
{
- (void)dst;
- (void)src;
return;
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_OBJ_FROZEN(). 3rd parties need not
+ * This is an implenentation detail of RB_OBJ_FROZEN(). 3rd parties need not
* use this. Just always use RB_OBJ_FROZEN().
*
* @param[in] obj Object in question.
@@ -905,21 +928,9 @@ RB_OBJ_FROZEN(VALUE obj)
}
}
-RUBY_SYMBOL_EXPORT_BEGIN
-/**
- * Prevents further modifications to the given object. ::rb_eFrozenError shall
- * be raised if modification is attempted.
- *
- * @param[out] x Object in question.
- * @exception rb_eNoMemError Failed to allocate memory for the frozen
- * representation of the object.
- */
-void rb_obj_freeze_inline(VALUE obj);
-RUBY_SYMBOL_EXPORT_END
-
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implementation detail of RB_OBJ_FREEZE(). 3rd parties need not
+ * This is an implenentation detail of RB_OBJ_FREEZE(). 3rd parties need not
* use this. Just always use RB_OBJ_FREEZE().
*
* @param[out] obj Object in question.
@@ -927,7 +938,11 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline void
RB_OBJ_FREEZE_RAW(VALUE obj)
{
- rb_obj_freeze_inline(obj);
+ RB_FL_SET_RAW(obj, RUBY_FL_FREEZE);
}
+RUBY_SYMBOL_EXPORT_BEGIN
+void rb_obj_freeze_inline(VALUE obj);
+RUBY_SYMBOL_EXPORT_END
+
#endif /* RBIMPL_FL_TYPE_H */
diff --git a/include/ruby/internal/gc.h b/include/ruby/internal/gc.h
index 462f416af2..054e4b0f9c 100644
--- a/include/ruby/internal/gc.h
+++ b/include/ruby/internal/gc.h
@@ -20,369 +20,11 @@
* extension libraries. They could be written in C++98.
* @brief Registering values to the GC.
*/
-#include "ruby/internal/config.h"
-
-#ifdef STDC_HEADERS
-# include <stddef.h> /* size_t */
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h> /* ssize_t */
-#endif
-
-#include "ruby/assert.h"
-#include "ruby/internal/attr/cold.h"
-#include "ruby/internal/attr/nonnull.h"
-#include "ruby/internal/attr/noreturn.h"
-#include "ruby/internal/attr/artificial.h"
-#include "ruby/internal/attr/maybe_unused.h"
-#include "ruby/internal/attr/pure.h"
#include "ruby/internal/dllexport.h"
-#include "ruby/internal/special_consts.h"
-#include "ruby/internal/stdbool.h"
#include "ruby/internal/value.h"
RBIMPL_SYMBOL_EXPORT_BEGIN()
-#define RUBY_REF_EDGE(s, p) offsetof(s, p)
-#define RUBY_REFS_LIST_PTR(l) (RUBY_DATA_FUNC)(l)
-#define RUBY_REF_END SIZE_MAX
-#define RUBY_REFERENCES(t) static const size_t t[]
-#define RUBY_REFERENCES_START(t) RUBY_REFERENCES(t) = {
-#define RUBY_REFERENCES_END RUBY_REF_END, };
-
-/* gc.c */
-
-RBIMPL_ATTR_COLD()
-RBIMPL_ATTR_NORETURN()
-/**
- * Triggers out-of-memory error. If possible it raises ::rb_eNoMemError. But
- * because we are running out of memory that is not always doable. This
- * function tries hard to show something, but ultimately can die silently.
- *
- * @exception rb_eNoMemError Raises it if possible.
- */
-void rb_memerror(void);
-
-RBIMPL_ATTR_PURE()
-/**
- * Queries if the GC is busy.
- *
- * @retval 0 It isn't.
- * @retval 1 It is.
- */
-int rb_during_gc(void);
-
-RBIMPL_ATTR_NONNULL((1))
-/**
- * Marks objects between the two pointers. This is one of the GC utility
- * functions that you can call when you design your own
- * ::rb_data_type_struct::dmark.
- *
- * @pre Continuous memory region from `start` to `end` shall be fully
- * addressable.
- * @param[out] start Pointer to an array of objects.
- * @param[out] end Pointer that terminates the array of objects.
- * @post Objects from `start` (included) to `end` (excluded) are marked.
- *
- * @internal
- *
- * `end` can be NULL... But that just results in no-op.
- */
-void rb_gc_mark_locations(const VALUE *start, const VALUE *end);
-
-/**
- * Identical to rb_mark_hash(), except it marks only values of the table and
- * leave their associated keys unmarked. This is one of the GC utility
- * functions that you can call when you design your own
- * ::rb_data_type_struct::dmark.
- *
- * @warning Of course it can break GC. Leave it unused if unsure.
- * @param[in] tbl A table to mark.
- * @post Values stored in `tbl` are marked.
- */
-void rb_mark_tbl(struct st_table *tbl);
-
-/**
- * Identical to rb_mark_tbl(), except it marks objects using
- * rb_gc_mark_movable(). This is one of the GC utility functions that you can
- * call when you design your own ::rb_data_type_struct::dmark.
- *
- * @warning Of course it can break GC. Leave it unused if unsure.
- * @param[in] tbl A table to mark.
- * @post Values stored in `tbl` are marked.
- */
-void rb_mark_tbl_no_pin(struct st_table *tbl);
-
-/**
- * Identical to rb_mark_hash(), except it marks only keys of the table and
- * leave their associated values unmarked. This is one of the GC utility
- * functions that you can call when you design your own
- * ::rb_data_type_struct::dmark.
- *
- * @warning Of course it can break GC. Leave it unused if unsure.
- * @param[in] tbl A table to mark.
- * @post Keys stored in `tbl` are marked.
- */
-void rb_mark_set(struct st_table *tbl);
-
-/**
- * Marks keys and values associated inside of the given table. This is one of
- * the GC utility functions that you can call when you design your own
- * ::rb_data_type_struct::dmark.
- *
- * @param[in] tbl A table to mark.
- * @post Objects stored in `tbl` are marked.
- */
-void rb_mark_hash(struct st_table *tbl);
-
-/**
- * Updates references inside of tables. After you marked values using
- * rb_mark_tbl_no_pin(), the objects inside of the table could of course be
- * moved. This function is to fixup those references. You can call this from
- * your ::rb_data_type_struct::dcompact.
- *
- * @param[out] ptr A table that potentially includes moved references.
- * @post Moved references, if any, are corrected.
- */
-void rb_gc_update_tbl_refs(st_table *ptr);
-
-/**
- * Identical to rb_gc_mark(), except it allows the passed value be a
- * non-object. For instance pointers to different type of memory regions are
- * allowed here. Such values are silently ignored. This is one of the GC
- * utility functions that you can call when you design your own
- * ::rb_data_type_struct::dmark.
- *
- * @param[out] obj A possible object.
- * @post `obj` is marked, if possible.
- */
-void rb_gc_mark_maybe(VALUE obj);
-
-/**
- * Marks an object. This is one of the GC utility functions that you can call
- * when you design your own ::rb_data_type_struct::dmark.
- *
- * @param[out] obj Arbitrary Ruby object.
- * @post `obj` is marked.
- */
-void rb_gc_mark(VALUE obj);
-
-/**
- * Maybe this is the only function provided for C extensions to control the
- * pinning of objects, so let us describe it in detail. These days Ruby's GC
- * is copying. As far as an object's physical address is guaranteed unused, it
- * can move around the object space. Our GC engine rearranges these objects
- * after it reclaims unreachable objects from our object space, so that the
- * space is compact (improves memory locality). This is called the
- * "compaction" phase, and works well most of the time... as far as there are
- * no C extensions. C extensions complicate the scenario because Ruby core
- * cannot detect any use of the physical address of an object inside of C
- * functions. In order to prevent memory corruptions, objects observable from
- * C extensions are "pinned"; they stick to where they are born until they die,
- * just in case any C extensions touch their raw pointers. This variant of
- * scheme is called "Mostly-Copying" garbage collector. Authors of C
- * extensions, however, can extremely carefully write them to become
- * compaction-aware. To do so avoid referring to a Ruby object from inside of
- * your struct in the first place. But if that is not possible, use this
- * function from your ::rb_data_type_struct::dmark then. This way objects
- * marked using it are considered movable. If you chose this way you have to
- * manually fix up locations of such moved pointers using rb_gc_location().
- *
- * @see Bartlett, Joel F., "Compacting Garbage Collection with Ambiguous
- * Roots", ACM SIGPLAN Lisp Pointers Volume 1 Issue 6 pp. 3-12,
- * April-May-June, 1988. https://doi.org/10.1145/1317224.1317225
- *
- * @param[in] obj Object that is movable.
- * @post Values stored in `tbl` are marked.
- */
-void rb_gc_mark_movable(VALUE obj);
-
-/**
- * Finds a new "location" of an object. An object can be moved on compaction.
- * This function projects its new abode, or just returns the passed object if
- * not moved. This is one of the GC utility functions that you can call when
- * you design your own ::rb_data_type_struct::dcompact.
- *
- * @param[in] obj An object, possibly already moved to somewhere else.
- * @return An object, which holds the current contents of former `obj`.
- */
-VALUE rb_gc_location(VALUE obj);
-
-/**
- * Triggers a GC process. This was the only GC entry point that we had at the
- * beginning. Over time our GC evolved. Now what this function does is just a
- * very simplified variation of the entire GC algorithms. A series of
- * procedures kicked by this API is called a "full" GC.
- *
- * - It immediately scans the entire object space to sort the dead.
- * - It immediately reclaims any single dead bodies to reuse later.
- *
- * It is worth noting that the procedures above do not include evaluations of
- * finalisers. They run later.
- *
- * @internal
- *
- * Finalisers are deferred until we can handle interrupts. See
- * `rb_postponed_job_flush` in vm_trace.c.
- *
- * Of course there are GC that are not "full". For instance this one and the
- * GC which runs when we are running out of memory are different. See
- * `gc_profile_record_flag` defined in gc.c for the kinds of GC.
- *
- * In spite of the name this is not what everything that a GC can trigger. As
- * of writing it seems this function does not trigger compaction. But this
- * might change in future.
- */
-void rb_gc(void);
-
-/**
- * Copy&paste an object's finaliser to another. This is one of the GC utility
- * functions that you can call when you design your own `initialize_copy`,
- * `initialize_dup`, `initialize_clone`.
- *
- * @param[out] dst Destination object.
- * @param[in] src Source object.
- * @post `dst` and `src` share the same finaliser.
- *
- * @internal
- *
- * But isn't it easier for you to call super, and let `Object#initialize_copy`
- * call this function instead?
- */
-void rb_gc_copy_finalizer(VALUE dst, VALUE src);
-
-/**
- * (Re-) enables GC. This makes sense only after you called rb_gc_disable().
- *
- * @retval RUBY_Qtrue GC was disabled before.
- * @retval RUBY_Qfalse GC was enabled before.
- * @post GC is enabled.
- *
- * @internal
- *
- * This is one of such exceptional functions that does not raise both Ruby
- * exceptions and C++ exceptions.
- */
-VALUE rb_gc_enable(void);
-
-/**
- * Disables GC. This prevents automatic GC runs when the process is running
- * out of memory. Such situations shall result in rb_memerror(). However this
- * does not prevent users from manually invoking rb_gc(). That should work.
- * People abused this by disabling GC at the beginning of an event loop,
- * process events without GC overheads, then manually force reclaiming garbage
- * at the bottom of the loop. However because our GC is now much smarter than
- * just calling rb_gc(), this technique is proven to be sub-optimal these days.
- * It is believed that there is currently practically no needs of this
- * function.
- *
- * @retval RUBY_Qtrue GC was disabled before.
- * @retval RUBY_Qfalse GC was enabled before.
- * @post GC is disabled.
- */
-VALUE rb_gc_disable(void);
-
-/**
- * Identical to rb_gc(), except the return value.
- *
- * @return Always returns ::RUBY_Qnil.
- */
-VALUE rb_gc_start(void);
-
-/**
- * Assigns a finaliser for an object. Each objects can have objects (typically
- * blocks) that run immediately after that object dies. They are called
- * finalisers of an object. This function associates a finaliser object with a
- * target object.
- *
- * @note Note that finalisers run _after_ the object they finalise dies. You
- * cannot for instance call its methods.
- * @note If your finaliser references the object it finalises that object
- * loses any chance to become a garbage; effectively leaks memory until
- * the end of the process.
- *
- * @param[in] obj Target to finalise.
- * @param[in] block Something `call`able.
- * @exception rb_eRuntimeError Somehow `obj` cannot have finalisers.
- * @exception rb_eFrozenError `obj` is frozen.
- * @exception rb_eArgError `block` doesn't respond to `call`.
- * @return The passed `block`.
- * @post `block` runs after `obj` dies.
- */
-VALUE rb_define_finalizer(VALUE obj, VALUE block);
-
-/**
- * Modifies the object so that it has no finalisers at all. This function is
- * mainly provided for symmetry. No practical usages can be thought of.
- *
- * @param[out] obj Object to clear its finalisers.
- * @exception rb_eFrozenError `obj` is frozen.
- * @return The passed `obj`.
- * @post `obj` has no finalisers.
- * @note There is no way to undefine a specific part of many finalisers
- * that `obj` could have. All you can do is to clear them all.
- */
-VALUE rb_undefine_finalizer(VALUE obj);
-
-/**
- * Identical to rb_gc_stat(), with "count" parameter.
- *
- * @return Lifetime total number of runs of GC.
- */
-size_t rb_gc_count(void);
-
-/**
- * Obtains various GC related profiles. The parameter can be either a Symbol
- * or a Hash. If a Hash is passed, it is filled with everything currently
- * available. If a Symbol is passed just that portion is returned.
- *
- * Possible variations of keys you can pass here change from version to
- * version. You can get the list of known keys by passing an empty hash and
- * let it be filled.
- *
- * @param[in,out] key_or_buf A Symbol, or a Hash.
- * @exception rb_eTypeError Neither Symbol nor Hash.
- * @exception rb_eFrozenError Frozen hash is passed.
- * @return In case a Hash is passed it returns 0. Otherwise the
- * profile value associated with the given key is returned.
- * @post In case a Hash is passed it is filled with values.
- */
-size_t rb_gc_stat(VALUE key_or_buf);
-
-/**
- * Obtains various info regarding the most recent GC run. This includes for
- * instance the reason of the GC. The parameter can be either a Symbol or a
- * Hash. If a Hash is passed, it is filled with everything currently
- * available. If a Symbol is passed just that portion is returned.
- *
- * Possible variations of keys you can pass here change from version to
- * version. You can get the list of known keys by passing an empty hash and
- * let it be filled.
- *
- * @param[in,out] key_or_buf A Symbol, or a Hash.
- * @exception rb_eTypeError Neither Symbol nor Hash.
- * @exception rb_eFrozenError Frozen hash is passed.
- * @return In case a Hash is passed it returns that hash. Otherwise
- * the profile value associated with the given key is returned.
- * @post In case a Hash is passed it is filled with values.
- */
-VALUE rb_gc_latest_gc_info(VALUE key_or_buf);
-
-/**
- * Informs that there are external memory usages. Our GC runs when we are
- * running out of memory. The amount of memory, however, can increase/decrease
- * behind-the-scene. For instance DLLs can allocate memories using `mmap(2)`
- * etc, which are opaque to us. Registering such external allocations using
- * this function enables proper detection of how much memories an object used
- * as a whole. That will trigger GCs more often than it would otherwise. You
- * can also pass negative numbers here, to indicate that such external
- * allocations are gone.
- *
- * @param[in] diff Amount of memory increased(+)/decreased(-).
- */
-void rb_gc_adjust_memory_usage(ssize_t diff);
-
/**
* Inform the garbage collector that the global or static variable pointed by
* `valptr` stores a live Ruby object that should not be moved. Note that
@@ -417,413 +59,4 @@ void rb_gc_register_mark_object(VALUE object);
RBIMPL_SYMBOL_EXPORT_END()
-/**
- * @private
- *
- * @deprecated This macro once was a thing in the old days, but makes no sense
- * any longer today. Exists here for backwards compatibility
- * only. You can safely forget about it.
- */
-#undef USE_RGENGC
-#define USE_RGENGC 1
-
-/**
- * @deprecated This macro seems broken. Setting this to anything other than
- * zero just doesn't compile. We need to KonMari.
- */
-#ifndef USE_RGENGC_LOGGING_WB_UNPROTECT
-# define USE_RGENGC_LOGGING_WB_UNPROTECT 0
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RArray. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_ARRAY
-# define RGENGC_WB_PROTECTED_ARRAY 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RHash. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_HASH
-# define RGENGC_WB_PROTECTED_HASH 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RStruct. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_STRUCT
-# define RGENGC_WB_PROTECTED_STRUCT 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RString. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_STRING
-# define RGENGC_WB_PROTECTED_STRING 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RObject. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_OBJECT
-# define RGENGC_WB_PROTECTED_OBJECT 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RRegexp. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_REGEXP
-# define RGENGC_WB_PROTECTED_REGEXP 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RMatch. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_MATCH
-# define RGENGC_WB_PROTECTED_MATCH 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RClass. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_CLASS
-# define RGENGC_WB_PROTECTED_CLASS 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RFloat. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_FLOAT
-# define RGENGC_WB_PROTECTED_FLOAT 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RComplex. It has to be set at the time ruby itself compiles.
- * Makes no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_COMPLEX
-# define RGENGC_WB_PROTECTED_COMPLEX 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RRational. It has to be set at the time ruby itself compiles.
- * Makes no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_RATIONAL
-# define RGENGC_WB_PROTECTED_RATIONAL 1
-#endif
-
-/**
- * @private
- *
- * This is a compile-time flag to enable/disable write barrier for
- * struct ::RBignum. It has to be set at the time ruby itself compiles. Makes
- * no sense for 3rd parties.
- */
-#ifndef RGENGC_WB_PROTECTED_BIGNUM
-# define RGENGC_WB_PROTECTED_BIGNUM 1
-#endif
-
-/**
- * @private
- *
- * @deprecated This macro once was a thing in the old days, but makes no sense
- * any longer today. Exists here for backwards compatibility
- * only. You can safely forget about it.
- *
- * @internal
- *
- * @shyouhei doesn't think anybody uses this right now.
- */
-#ifndef RGENGC_WB_PROTECTED_NODE_CREF
-# define RGENGC_WB_PROTECTED_NODE_CREF 1
-#endif
-
-/**
- * @defgroup rgengc Write barrier (WB) interfaces:
- *
- * @note The following core interfaces can be changed in the future. Please
- * catch up if you want to insert WB into C-extensions correctly.
- *
- * @{
- */
-
-/**
- * Declaration of a "back" pointer. This is a write barrier for new reference
- * from "old" generation to "young" generation. It writes `young` into
- * `*slot`, which is a pointer inside of `old`.
- *
- * @param[in] old An old object.
- * @param[in] slot A pointer inside of `old`.
- * @param[out] young A young object.
- */
-#define RB_OBJ_WRITE(old, slot, young) \
- RBIMPL_CAST(rb_obj_write((VALUE)(old), (VALUE *)(slot), (VALUE)(young), __FILE__, __LINE__))
-
-/**
- * Identical to #RB_OBJ_WRITE(), except it doesn't write any values, but only a
- * WB declaration. `oldv` is replaced value with `b` (not used in current
- * Ruby).
- *
- * @param[in] old An old object.
- * @param[in] oldv An object previously stored inside of `old`.
- * @param[out] young A young object.
- */
-#define RB_OBJ_WRITTEN(old, oldv, young) \
- RBIMPL_CAST(rb_obj_written((VALUE)(old), (VALUE)(oldv), (VALUE)(young), __FILE__, __LINE__))
-/** @} */
-
-#define OBJ_PROMOTED_RAW RB_OBJ_PROMOTED_RAW /**< @old{RB_OBJ_PROMOTED_RAW} */
-#define OBJ_PROMOTED RB_OBJ_PROMOTED /**< @old{RB_OBJ_PROMOTED} */
-#define OBJ_WB_UNPROTECT RB_OBJ_WB_UNPROTECT /**< @old{RB_OBJ_WB_UNPROTECT} */
-
-/**
- * Asserts that the passed object is not fenced by write barriers. Objects of
- * such property do not contribute to generational GCs. They are scanned
- * always.
- *
- * @param[out] x An object that would not be protected by the barrier.
- */
-#define RB_OBJ_WB_UNPROTECT(x) rb_obj_wb_unprotect(x, __FILE__, __LINE__)
-
-/**
- * Identical to #RB_OBJ_WB_UNPROTECT(), except it can also assert that the
- * given object is of given type.
- *
- * @param[in] type One of `ARRAY`, `STRING`, etc.
- * @param[out] obj An object of `type` that would not be protected.
- *
- * @internal
- *
- * @shyouhei doesn't understand why this has to be visible from extensions.
- */
-#define RB_OBJ_WB_UNPROTECT_FOR(type, obj) \
- (RGENGC_WB_PROTECTED_##type ? OBJ_WB_UNPROTECT(obj) : obj)
-
-/**
- * @private
- *
- * This is an implementation detail of rb_obj_wb_unprotect(). People don't use
- * it directly.
- */
-#define RGENGC_LOGGING_WB_UNPROTECT rb_gc_unprotect_logging
-
-/** @cond INTERNAL_MACRO */
-#define RB_OBJ_PROMOTED_RAW RB_OBJ_PROMOTED_RAW
-#define RB_OBJ_PROMOTED RB_OBJ_PROMOTED
-/** @endcond */
-
-RBIMPL_SYMBOL_EXPORT_BEGIN()
-/**
- * This is the implementation of #RB_OBJ_WRITE(). People don't use it
- * directly.
- *
- * @param[in] old An object that points to `young`.
- * @param[out] young An object that is referenced from `old`.
- */
-void rb_gc_writebarrier(VALUE old, VALUE young);
-
-/**
- * This is the implementation of #RB_OBJ_WB_UNPROTECT(). People don't use it
- * directly.
- *
- * @param[out] obj An object that does not participate in WB.
- */
-void rb_gc_writebarrier_unprotect(VALUE obj);
-
-#if USE_RGENGC_LOGGING_WB_UNPROTECT
-/**
- * @private
- *
- * This is the implementation of #RGENGC_LOGGING_WB_UNPROTECT(). People
- * don't use it directly.
- *
- * @param[in] objptr Don't know why this is a pointer to void but in
- * reality this is a pointer to an object that is about
- * to be un-protected.
- * @param[in] filename Pass C's `__FILE__` here.
- * @param[in] line Pass C's `__LINE__` here.
- */
-void rb_gc_unprotect_logging(void *objptr, const char *filename, int line);
-#endif
-
-RBIMPL_SYMBOL_EXPORT_END()
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
- * This is the implementation of #RB_OBJ_PROMOTED(). People don't use it
- * directly.
- *
- * @param[in] obj An object to query.
- * @retval true The object is "promoted".
- * @retval false The object is young. Have not experienced GC at all.
- */
-static inline bool
-RB_OBJ_PROMOTED_RAW(VALUE obj)
-{
- RBIMPL_ASSERT_OR_ASSUME(RB_FL_ABLE(obj));
- return RB_FL_ANY_RAW(obj, RUBY_FL_PROMOTED);
-}
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
- * Tests if the object is "promoted" -- that is, whether the object experienced
- * one or more GC marks.
- *
- * @param[in] obj An object to query.
- * @retval true The object is "promoted".
- * @retval false The object is young. Have not experienced GC at all.
- * @note Hello, is anyone actively calling this function? @shyouhei have
- * never seen any actual usages outside of the GC implementation
- * itself.
- */
-static inline bool
-RB_OBJ_PROMOTED(VALUE obj)
-{
- if (! RB_FL_ABLE(obj)) {
- return false;
- }
- else {
- return RB_OBJ_PROMOTED_RAW(obj);
- }
-}
-
-/**
- * This is the implementation of #RB_OBJ_WB_UNPROTECT(). People don't use it
- * directly.
- *
- * @param[out] x An object that does not participate in WB.
- * @param[in] filename C's `__FILE__` of the caller function.
- * @param[in] line C's `__LINE__` of the caller function.
- * @return x
- */
-static inline VALUE
-rb_obj_wb_unprotect(
- VALUE x,
- RBIMPL_ATTR_MAYBE_UNUSED()
- const char *filename,
- RBIMPL_ATTR_MAYBE_UNUSED()
- int line)
-{
-#if USE_RGENGC_LOGGING_WB_UNPROTECT
- RGENGC_LOGGING_WB_UNPROTECT(RBIMPL_CAST((void *)x), filename, line);
-#endif
- rb_gc_writebarrier_unprotect(x);
- return x;
-}
-
-/**
- * @private
- *
- * This is the implementation of #RB_OBJ_WRITTEN(). People don't use it
- * directly.
- *
- * @param[in] a An old object.
- * @param[in] oldv An object previously stored inside of `old`.
- * @param[out] b A young object.
- * @param[in] filename C's `__FILE__` of the caller function.
- * @param[in] line C's `__LINE__` of the caller function.
- * @return a
- */
-static inline VALUE
-rb_obj_written(
- VALUE a,
- RBIMPL_ATTR_MAYBE_UNUSED()
- VALUE oldv,
- VALUE b,
- RBIMPL_ATTR_MAYBE_UNUSED()
- const char *filename,
- RBIMPL_ATTR_MAYBE_UNUSED()
- int line)
-{
-#if USE_RGENGC_LOGGING_WB_UNPROTECT
- RGENGC_LOGGING_OBJ_WRITTEN(a, oldv, b, filename, line);
-#endif
-
- if (!RB_SPECIAL_CONST_P(b)) {
- rb_gc_writebarrier(a, b);
- }
-
- return a;
-}
-
-/**
- * @private
- *
- * This is the implementation of #RB_OBJ_WRITE(). People don't use it
- * directly.
- *
- * @param[in] a An old object.
- * @param[in] slot A pointer inside of `old`.
- * @param[out] b A young object.
- * @param[in] filename C's `__FILE__` of the caller function.
- * @param[in] line C's `__LINE__` of the caller function.
- * @return a
- */
-static inline VALUE
-rb_obj_write(
- VALUE a, VALUE *slot, VALUE b,
- RBIMPL_ATTR_MAYBE_UNUSED()
- const char *filename,
- RBIMPL_ATTR_MAYBE_UNUSED()
- int line)
-{
-#ifdef RGENGC_LOGGING_WRITE
- RGENGC_LOGGING_WRITE(a, slot, b, filename, line);
-#endif
-
- *slot = b;
-
- rb_obj_written(a, RUBY_Qundef /* ignore `oldv' now */, b, filename, line);
- return a;
-}
-
-RBIMPL_ATTR_DEPRECATED(("Will be removed soon"))
-static inline void rb_gc_force_recycle(VALUE obj){}
-
#endif /* RBIMPL_GC_H */
diff --git a/include/ruby/internal/globals.h b/include/ruby/internal/globals.h
index 60d8e5309a..5a414fc472 100644
--- a/include/ruby/internal/globals.h
+++ b/include/ruby/internal/globals.h
@@ -94,7 +94,7 @@ RUBY_EXTERN VALUE rb_cRegexp; /**< `Regexp` class. */
RUBY_EXTERN VALUE rb_cStat; /**< `File::Stat` class. */
RUBY_EXTERN VALUE rb_cString; /**< `String` class. */
RUBY_EXTERN VALUE rb_cStruct; /**< `Struct` class. */
-RUBY_EXTERN VALUE rb_cSymbol; /**< `Symbol` class. */
+RUBY_EXTERN VALUE rb_cSymbol; /**< `Sumbol` class. */
RUBY_EXTERN VALUE rb_cThread; /**< `Thread` class. */
RUBY_EXTERN VALUE rb_cTime; /**< `Time` class. */
RUBY_EXTERN VALUE rb_cTrueClass; /**< `TrueClass` class. */
diff --git a/include/ruby/internal/has/c_attribute.h b/include/ruby/internal/has/c_attribute.h
index 69b0f402cd..c5c48867bf 100644
--- a/include/ruby/internal/has/c_attribute.h
+++ b/include/ruby/internal/has/c_attribute.h
@@ -21,23 +21,11 @@
* @brief Defines #RBIMPL_HAS_C_ATTRIBUTE.
*/
-#include "ruby/internal/has/extension.h"
-#include "ruby/internal/has/warning.h"
-
/** Wraps (or simulates) `__has_c_attribute`. */
#if defined(__cplusplus)
# /* Makes no sense. */
# define RBIMPL_HAS_C_ATTRIBUTE(_) 0
-#elif RBIMPL_HAS_EXTENSION(c_attributes)
-# /* Hmm. It seems Clang 17 has this macro defined even when -std=c99 mode,
-# * _and_ fails to compile complaining that attributes are C2X feature. We
-# * need to work around this nonsense. */
-# define RBIMPL_HAS_C_ATTRIBUTE(_) __has_c_attribute(_)
-
-#elif RBIMPL_HAS_WARNING("-Wc2x-extensions")
-# define RBIMPL_HAS_C_ATTRIBUTE(_) 0
-
#elif defined(__has_c_attribute)
# define RBIMPL_HAS_C_ATTRIBUTE(_) __has_c_attribute(_)
diff --git a/include/ruby/internal/intern/array.h b/include/ruby/internal/intern/array.h
index b2cc6b132d..2262c6f0c6 100644
--- a/include/ruby/internal/intern/array.h
+++ b/include/ruby/internal/intern/array.h
@@ -144,13 +144,7 @@ void rb_ary_free(VALUE ary);
*/
void rb_ary_modify(VALUE ary);
-/**
- * Freeze an array, preventing further modifications. The underlying buffer may
- * be shrunk before freezing to conserve memory.
- *
- * @param[out] obj Object assumed to be an array to freeze.
- * @see RB_OBJ_FREEZE()
- */
+/** @alias{rb_obj_freeze} */
VALUE rb_ary_freeze(VALUE obj);
RBIMPL_ATTR_PURE()
@@ -193,7 +187,7 @@ VALUE rb_ary_shared_with_p(VALUE lhs, VALUE rhs);
* : (int i) -> T?
* | (int beg, int len) -> ::Array[T]?
* | (Range[int] r) -> ::Array[T]?
- * | (ArithmeticSequence as) -> ::Array[T]? # This also raises RangeError.
+ * | (ArithmeticSequence as) -> ::Array[T]? # This also raises RagneError.
* end
* ```
*/
diff --git a/include/ruby/internal/intern/bignum.h b/include/ruby/internal/intern/bignum.h
index c27f77a1fb..43d68018de 100644
--- a/include/ruby/internal/intern/bignum.h
+++ b/include/ruby/internal/intern/bignum.h
@@ -51,7 +51,7 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
VALUE rb_big_new(size_t len, int sign);
/**
- * Queries if the passed bignum instance is a "bigzero". What is a bigzero?
+ * Queries if the passed bignum instance is a "bigzro". What is a bigzero?
* Well, bignums are for very big integers, but can also represent tiny ones
* like -1, 0, 1. Bigzero are instances of bignums whose values are zero.
* Knowing if a bignum is bigzero can be handy on occasions, like for instance
@@ -793,7 +793,7 @@ size_t rb_absint_size(VALUE val, int *nlz_bits_ret);
* @exception rb_eTypeError `val` doesn't respond to `#to_int`.
* @retval (size_t)-1 Overflowed.
* @retval otherwise
- * `((val_numbits * CHAR_BIT + word_numbits - 1) / word_numbits)`,
+ `((val_numbits * CHAR_BIT + word_numbits - 1) / word_numbits)`,
* where val_numbits is the number of bits of `abs(val)`.
* @post If `nlz_bits_ret` is not `NULL` and there is no overflow,
* `(return_value * word_numbits - val_numbits)` is stored in
diff --git a/include/ruby/internal/intern/class.h b/include/ruby/internal/intern/class.h
index 357af5d176..0fb2d001bc 100644
--- a/include/ruby/internal/intern/class.h
+++ b/include/ruby/internal/intern/class.h
@@ -88,8 +88,8 @@ VALUE rb_define_class_id(ID id, VALUE super);
* @post `outer::id` refers the returned class.
* @note If a class named `id` is already defined and its superclass is
* `super`, the function just returns the defined class.
- * @note The GC does not collect nor move classes returned by this
- * function. They are immortal.
+ * @note The compaction GC does not move classes returned by this
+ * function.
*/
VALUE rb_define_class_id_under(VALUE outer, ID id, VALUE super);
@@ -127,8 +127,8 @@ VALUE rb_define_module_id(ID id);
* constant is not a module.
* @return The created module.
* @post `outer::id` refers the returned module.
- * @note The GC does not collect nor move classes returned by this
- * function. They are immortal.
+ * @note The compaction GC does not move classes returned by this
+ * function.
*/
VALUE rb_define_module_id_under(VALUE outer, ID id);
diff --git a/include/ruby/internal/intern/error.h b/include/ruby/internal/intern/error.h
index b1e2c130b9..9c153cbac5 100644
--- a/include/ruby/internal/intern/error.h
+++ b/include/ruby/internal/intern/error.h
@@ -235,9 +235,7 @@ RBIMPL_ATTR_NORETURN()
* @param[in] max Maximum allowed `argc`.
* @exception rb_eArgError Always.
*/
-void rb_error_arity(int argc, int min, int max);
-
-void rb_str_modify(VALUE str);
+MJIT_STATIC void rb_error_arity(int argc, int min, int max);
RBIMPL_SYMBOL_EXPORT_END()
@@ -246,7 +244,12 @@ RBIMPL_SYMBOL_EXPORT_END()
*
* Does anyone use this? Remain not deleted for compatibility.
*/
-#define rb_check_frozen_internal rb_check_frozen
+#define rb_check_frozen_internal(obj) do { \
+ VALUE frozen_obj = (obj); \
+ if (RB_UNLIKELY(RB_OBJ_FROZEN(frozen_obj))) { \
+ rb_error_frozen_object(frozen_obj); \
+ } \
+ } while (0)
/** @alias{rb_check_frozen} */
static inline void
@@ -255,16 +258,9 @@ rb_check_frozen_inline(VALUE obj)
if (RB_UNLIKELY(RB_OBJ_FROZEN(obj))) {
rb_error_frozen_object(obj);
}
-
- /* ref: internal CHILLED_STRING_P()
- This is an implementation detail subject to change. */
- if (RB_UNLIKELY(RB_TYPE_P(obj, T_STRING) && FL_TEST_RAW(obj, RUBY_FL_USER3))) {
- rb_str_modify(obj);
- }
}
-/* rb_check_frozen() is available as a symbol, but have
- * the inline version take priority for native consumers. */
+/** @alias{rb_check_frozen} */
#define rb_check_frozen rb_check_frozen_inline
/**
diff --git a/include/ruby/internal/intern/gc.h b/include/ruby/internal/intern/gc.h
new file mode 100644
index 0000000000..2ee1d257db
--- /dev/null
+++ b/include/ruby/internal/intern/gc.h
@@ -0,0 +1,392 @@
+#ifndef RBIMPL_INTERN_GC_H /*-*-C++-*-vi:se ft=cpp:*/
+#define RBIMPL_INTERN_GC_H
+/**
+ * @file
+ * @author Ruby developers <ruby-core@ruby-lang.org>
+ * @copyright This file is a part of the programming language Ruby.
+ * Permission is hereby granted, to either redistribute and/or
+ * modify this file, provided that the conditions mentioned in the
+ * file COPYING are met. Consult the file for details.
+ * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
+ * implementation details. Don't take them as canon. They could
+ * rapidly appear then vanish. The name (path) of this header file
+ * is also an implementation detail. Do not expect it to persist
+ * at the place it is now. Developers are free to move it anywhere
+ * anytime at will.
+ * @note To ruby-core: remember that this header can be possibly
+ * recursively included from extension libraries written in C++.
+ * Do not expect for instance `__VA_ARGS__` is always available.
+ * We assume C99 for ruby itself but we don't assume languages of
+ * extension libraries. They could be written in C++98.
+ * @brief Public APIs related to ::rb_mGC.
+ */
+#include "ruby/internal/config.h"
+
+#ifdef STDC_HEADERS
+# include <stddef.h> /* size_t */
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h> /* ssize_t */
+#endif
+
+#include "ruby/internal/attr/cold.h"
+#include "ruby/internal/attr/noreturn.h"
+#include "ruby/internal/attr/nonnull.h"
+#include "ruby/internal/attr/pure.h"
+#include "ruby/internal/dllexport.h"
+#include "ruby/internal/value.h"
+
+RBIMPL_SYMBOL_EXPORT_BEGIN()
+
+/* gc.c */
+
+RBIMPL_ATTR_COLD()
+RBIMPL_ATTR_NORETURN()
+/**
+ * Triggers out-of-memory error. If possible it raises ::rb_eNoMemError. But
+ * because we are running out of memory that is not always doable. This
+ * function tries hard to show something, but ultimately can die silently.
+ *
+ * @exception rb_eNoMemError Raises it if possible.
+ */
+void rb_memerror(void);
+
+RBIMPL_ATTR_PURE()
+/**
+ * Queries if the GC is busy.
+ *
+ * @retval 0 It isn't.
+ * @retval 1 It is.
+ */
+int rb_during_gc(void);
+
+RBIMPL_ATTR_NONNULL((1))
+/**
+ * Marks objects between the two pointers. This is one of the GC utility
+ * functions that you can call when you design your own
+ * ::rb_data_type_struct::dmark.
+ *
+ * @pre Continuous memory region from `start` to `end` shall be fully
+ * addressable.
+ * @param[out] start Pointer to an array of objects.
+ * @param[out] end Pointer that terminates the array of objects.
+ * @post Objects from `start` (included) to `end` (excluded) are marked.
+ *
+ * @internal
+ *
+ * `end` can be NULL... But that just results in no-op.
+ */
+void rb_gc_mark_locations(const VALUE *start, const VALUE *end);
+
+/**
+ * Identical to rb_mark_hash(), except it marks only values of the table and
+ * leave their associated keys unmarked. This is one of the GC utility
+ * functions that you can call when you design your own
+ * ::rb_data_type_struct::dmark.
+ *
+ * @warning Of course it can break GC. Leave it unused if unsure.
+ * @param[in] tbl A table to mark.
+ * @post Values stored in `tbl` are marked.
+ */
+void rb_mark_tbl(struct st_table *tbl);
+
+/**
+ * Identical to rb_mark_tbl(), except it marks objects using
+ * rb_gc_mark_movable(). This is one of the GC utility functions that you can
+ * call when you design your own ::rb_data_type_struct::dmark.
+ *
+ * @warning Of course it can break GC. Leave it unused if unsure.
+ * @param[in] tbl A table to mark.
+ * @post Values stored in `tbl` are marked.
+ */
+void rb_mark_tbl_no_pin(struct st_table *tbl);
+
+/**
+ * Identical to rb_mark_hash(), except it marks only keys of the table and
+ * leave their associated values unmarked. This is one of the GC utility
+ * functions that you can call when you design your own
+ * ::rb_data_type_struct::dmark.
+ *
+ * @warning Of course it can break GC. Leave it unused if unsure.
+ * @param[in] tbl A table to mark.
+ * @post Keys stored in `tbl` are marked.
+ */
+void rb_mark_set(struct st_table *tbl);
+
+/**
+ * Marks keys and values associated inside of the given table. This is one of
+ * the GC utility functions that you can call when you design your own
+ * ::rb_data_type_struct::dmark.
+ *
+ * @param[in] tbl A table to mark.
+ * @post Objects stored in `tbl` are marked.
+ */
+void rb_mark_hash(struct st_table *tbl);
+
+/**
+ * Updates references inside of tables. After you marked values using
+ * rb_mark_tbl_no_pin(), the objects inside of the table could of course be
+ * moved. This function is to fixup those references. You can call this from
+ * your ::rb_data_type_struct::dcompact.
+ *
+ * @param[out] ptr A table that potentially includes moved references.
+ * @post Moved references, if any, are corrected.
+ */
+void rb_gc_update_tbl_refs(st_table *ptr);
+
+/**
+ * Identical to rb_gc_mark(), except it allows the passed value be a
+ * non-object. For instance pointers to different type of memory regions are
+ * allowed here. Such values are silently ignored. This is one of the GC
+ * utility functions that you can call when you design your own
+ * ::rb_data_type_struct::dmark.
+ *
+ * @param[out] obj A possible object.
+ * @post `obj` is marked, if possible.
+ */
+void rb_gc_mark_maybe(VALUE obj);
+
+/**
+ * Marks an object. This is one of the GC utility functions that you can call
+ * when you design your own ::rb_data_type_struct::dmark.
+ *
+ * @param[out] obj Arbitrary Ruby object.
+ * @post `obj` is marked.
+ */
+void rb_gc_mark(VALUE obj);
+
+/**
+ * Maybe this is the only function provided for C extensions to control the
+ * pinning of objects, so let us describe it in detail. These days Ruby's GC
+ * is copying. As far as an object's physical address is guaranteed unused, it
+ * can move around the object space. Our GC engine rearranges these objects
+ * after it reclaims unreachable objects from our object space, so that the
+ * space is compact (improves memory locality). This is called the
+ * "compaction" phase, and works well most of the time... as far as there are
+ * no C extensions. C extensions complicate the scenario because Ruby core
+ * cannot detect any use of the physical address of an object inside of C
+ * functions. In order to prevent memory corruptions, objects observable from
+ * C extensions are "pinned"; they stick to where they are born until they die,
+ * just in case any C extensions touch their raw pointers. This variant of
+ * scheme is called "Mostly-Copying" garbage collector. Authors of C
+ * extensions, however, can extremely carefully write them to become
+ * compaction-aware. To do so avoid referring to a Ruby object from inside of
+ * your struct in the first place. But if that is not possible, use this
+ * function from your ::rb_data_type_struct::dmark then. This way objects
+ * marked using it are considered movable. If you chose this way you have to
+ * manually fix up locations of such moved pointers using rb_gc_location().
+ *
+ * @see Bartlett, Joel F., "Compacting Garbage Collection with Ambiguous
+ * Roots", ACM SIGPLAN Lisp Pointers Volume 1 Issue 6 pp. 3-12,
+ * April-May-June, 1988. https://doi.org/10.1145/1317224.1317225
+ *
+ * @param[in] obj Object that is movable.
+ * @post Values stored in `tbl` are marked.
+ */
+void rb_gc_mark_movable(VALUE obj);
+
+/**
+ * Finds a new "location" of an object. An object can be moved on compaction.
+ * This function projects its new abode, or just returns the passed object if
+ * not moved. This is one of the GC utility functions that you can call when
+ * you design your own ::rb_data_type_struct::dcompact.
+ *
+ * @param[in] obj An object, possibly already moved to somewhere else.
+ * @return An object, which holds the current contents of former `obj`.
+ */
+VALUE rb_gc_location(VALUE obj);
+
+/**
+ * Asserts that the passed object is no longer needed. Such objects are
+ * reclaimed sooner or later so this function is not mandatory. But sometimes
+ * you can know from your application knowledge that an object is surely dead
+ * at some point. Calling this as a hint can be a polite way.
+ *
+ * @param[out] obj Object, dead.
+ * @pre `obj` have never been passed to this function before.
+ * @post `obj` could be invalidated.
+ * @warning It is a failure to pass an object multiple times to this
+ * function.
+ * @deprecated This is now a no-op function.
+ */
+RBIMPL_ATTR_DEPRECATED(("this is now a no-op function"))
+void rb_gc_force_recycle(VALUE obj);
+
+/**
+ * Triggers a GC process. This was the only GC entry point that we had at the
+ * beginning. Over time our GC evolved. Now what this function does is just a
+ * very simplified variation of the entire GC algorithms. A series of
+ * procedures kicked by this API is called a "full" GC.
+ *
+ * - It immediately scans the entire object space to sort the dead.
+ * - It immediately reclaims any single dead bodies to reuse later.
+ *
+ * It is worth noting that the procedures above do not include evaluations of
+ * finalisers. They run later.
+ *
+ * @internal
+ *
+ * Finalisers are deferred until we can handle interrupts. See
+ * `rb_postponed_job_flush` in vm_trace.c.
+ *
+ * Of course there are GC that are not "full". For instance this one and the
+ * GC which runs when we are running out of memory are different. See
+ * `gc_profile_record_flag` defined in gc.c for the kinds of GC.
+ *
+ * In spite of the name this is not what everything that a GC can trigger. As
+ * of writing it seems this function does not trigger compaction. But this
+ * might change in future.
+ */
+void rb_gc(void);
+
+/**
+ * Copy&paste an object's finaliser to another. This is one of the GC utility
+ * functions that you can call when you design your own `initialize_copy`,
+ * `initialize_dup`, `initialize_clone`.
+ *
+ * @param[out] dst Destination object.
+ * @param[in] src Source object.
+ * @post `dst` and `src` share the same finaliser.
+ *
+ * @internal
+ *
+ * But isn't it easier for you to call super, and let `Object#initialize_copy`
+ * call this function instead?
+ */
+void rb_gc_copy_finalizer(VALUE dst, VALUE src);
+
+/**
+ * (Re-) enables GC. This makes sense only after you called rb_gc_disable().
+ *
+ * @retval RUBY_Qtrue GC was disabled before.
+ * @retval RUBY_Qfalse GC was enabled before.
+ * @post GC is enabled.
+ *
+ * @internal
+ *
+ * This is one of such exceptional functions that does not raise both Ruby
+ * exceptions and C++ exceptions.
+ */
+VALUE rb_gc_enable(void);
+
+/**
+ * Disables GC. This prevents automatic GC runs when the process is running
+ * out of memory. Such situations shall result in rb_memerror(). However this
+ * does not prevent users from manually invoking rb_gc(). That should work.
+ * People abused this by disabling GC at the beginning of an event loop,
+ * process events without GC overheads, then manually force reclaiming garbage
+ * at the bottom of the loop. However because our GC is now much smarter than
+ * just calling rb_gc(), this technique is proven to be sub-optimal these days.
+ * It is believed that there is currently practically no needs of this
+ * function.
+ *
+ * @retval RUBY_Qtrue GC was disabled before.
+ * @retval RUBY_Qfalse GC was enabled before.
+ * @post GC is disabled.
+ */
+VALUE rb_gc_disable(void);
+
+/**
+ * Identical to rb_gc(), except the return value.
+ *
+ * @return Always returns ::RUBY_Qnil.
+ */
+VALUE rb_gc_start(void);
+
+/**
+ * Assigns a finaliser for an object. Each objects can have objects (typically
+ * blocks) that run immediately after that object dies. They are called
+ * finalisers of an object. This function associates a finaliser object with a
+ * target object.
+ *
+ * @note Note that finalisers run _after_ the object they finalise dies. You
+ * cannot for instance call its methods.
+ * @note If your finaliser references the object it finalises that object
+ * loses any chance to become a garbage; effectively leaks memory until
+ * the end of the process.
+ *
+ * @param[in] obj Target to finalise.
+ * @param[in] block Something `call`able.
+ * @exception rb_eRuntimeError Somehow `obj` cannot have finalisers.
+ * @exception rb_eFrozenError `obj` is frozen.
+ * @exception rb_eArgError `block` doesn't respond to `call`.
+ * @return The passed `block`.
+ * @post `block` runs after `obj` dies.
+ */
+VALUE rb_define_finalizer(VALUE obj, VALUE block);
+
+/**
+ * Modifies the object so that it has no finalisers at all. This function is
+ * mainly provided for symmetry. No practical usages can be thought of.
+ *
+ * @param[out] obj Object to clear its finalisers.
+ * @exception rb_eFrozenError `obj` is frozen.
+ * @return The passed `obj`.
+ * @post `obj` has no finalisers.
+ * @note There is no way to undefine a specific part of many finalisers
+ * that `obj` could have. All you can do is to clear them all.
+ */
+VALUE rb_undefine_finalizer(VALUE obj);
+
+/**
+ * Identical to rb_gc_stat(), with "count" parameter.
+ *
+ * @return Lifetime total number of runs of GC.
+ */
+size_t rb_gc_count(void);
+
+/**
+ * Obtains various GC related profiles. The parameter can be either a Symbol
+ * or a Hash. If a Hash is passed, it is filled with everything currently
+ * available. If a Symbol is passed just that portion is returned.
+ *
+ * Possible variations of keys you can pass here change from version to
+ * version. You can get the list of known keys by passing an empty hash and
+ * let it be filled.
+ *
+ * @param[in,out] key_or_buf A Symbol, or a Hash.
+ * @exception rb_eTypeError Neither Symbol nor Hash.
+ * @exception rb_eFrozenError Frozen hash is passed.
+ * @return In case a Hash is passed it returns 0. Otherwise the
+ * profile value associated with the given key is returned.
+ * @post In case a Hash is passed it is filled with values.
+ */
+size_t rb_gc_stat(VALUE key_or_buf);
+
+/**
+ * Obtains various info regarding the most recent GC run. This includes for
+ * instance the reason of the GC. The parameter can be either a Symbol or a
+ * Hash. If a Hash is passed, it is filled with everything currently
+ * available. If a Symbol is passed just that portion is returned.
+ *
+ * Possible variations of keys you can pass here change from version to
+ * version. You can get the list of known keys by passing an empty hash and
+ * let it be filled.
+ *
+ * @param[in,out] key_or_buf A Symbol, or a Hash.
+ * @exception rb_eTypeError Neither Symbol nor Hash.
+ * @exception rb_eFrozenError Frozen hash is passed.
+ * @return In case a Hash is passed it returns that hash. Otherwise
+ * the profile value associated with the given key is returned.
+ * @post In case a Hash is passed it is filled with values.
+ */
+VALUE rb_gc_latest_gc_info(VALUE key_or_buf);
+
+/**
+ * Informs that there are external memory usages. Our GC runs when we are
+ * running out of memory. The amount of memory, however, can increase/decrease
+ * behind-the-scene. For instance DLLs can allocate memories using `mmap(2)`
+ * etc, which are opaque to us. Registering such external allocations using
+ * this function enables proper detection of how much memories an object used
+ * as a whole. That will trigger GCs more often than it would otherwise. You
+ * can also pass negative numbers here, to indicate that such external
+ * allocations are gone.
+ *
+ * @param[in] diff Amount of memory increased(+)/decreased(-).
+ */
+void rb_gc_adjust_memory_usage(ssize_t diff);
+
+RBIMPL_SYMBOL_EXPORT_END()
+
+#endif /* RBIMPL_INTERN_GC_H */
diff --git a/include/ruby/internal/intern/io.h b/include/ruby/internal/intern/io.h
index b9eb258cc1..02c249723e 100644
--- a/include/ruby/internal/intern/io.h
+++ b/include/ruby/internal/intern/io.h
@@ -385,7 +385,7 @@ VALUE rb_io_puts(int argc, const VALUE *argv, VALUE io);
* @param[in] fd Target file descriptor.
* @param[in] flags Flags, e.g. `O_CREAT|O_EXCL`
* @param[in] path The path of the file that backs `fd`, for diagnostics.
- * @return An allocated instance of ::rb_cIO with the autoclose flag set.
+ * @return An allocated instance of ::rb_cIO.
* @note Leave `path` NULL if you don't know.
*/
VALUE rb_io_fdopen(int fd, int flags, const char *path);
diff --git a/include/ruby/internal/intern/load.h b/include/ruby/internal/intern/load.h
index 9ceb98c2e4..288a16c2ec 100644
--- a/include/ruby/internal/intern/load.h
+++ b/include/ruby/internal/intern/load.h
@@ -177,43 +177,6 @@ VALUE rb_f_require(VALUE self, VALUE feature);
VALUE rb_require_string(VALUE feature);
/**
- * Resolves and returns a symbol of a function in the native extension
- * specified by the feature and symbol names. Extensions will use this function
- * to access the symbols provided by other native extensions.
- *
- * @param[in] feature Name of a feature, e.g. `"json"`.
- * @param[in] symbol Name of a symbol defined by the feature.
- * @return The resolved symbol of a function, defined and externed by the
- * specified feature. It may be NULL if the feature is not loaded,
- * the feature is not extension, or the symbol is not found.
- */
-void *rb_ext_resolve_symbol(const char *feature, const char *symbol);
-
-/**
- * This macro is to provide backwards compatibility. It provides a way to
- * define function prototypes and resolving function symbols in a safe way.
- *
- * ```CXX
- * // prototypes
- * #ifdef HAVE_RB_EXT_RESOLVE_SYMBOL
- * VALUE *(*other_extension_func)(VALUE,VALUE);
- * #else
- * VALUE other_extension_func(VALUE);
- * #endif
- *
- * // in Init_xxx()
- * #ifdef HAVE_RB_EXT_RESOLVE_SYMBOL
- * other_extension_func = \
- * (VALUE(*)(VALUE,VALUE))rb_ext_resolve_symbol(fname, sym_name);
- * if (other_extension_func == NULL) {
- * // raise your own error
- * }
- * #endif
- * ```
- */
-#define HAVE_RB_EXT_RESOLVE_SYMBOL 1
-
-/**
* @name extension configuration
* @{
*/
diff --git a/include/ruby/internal/intern/object.h b/include/ruby/internal/intern/object.h
index 9daad7d046..b9ffa57c06 100644
--- a/include/ruby/internal/intern/object.h
+++ b/include/ruby/internal/intern/object.h
@@ -151,12 +151,13 @@ VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass);
* @return An allocated, not yet initialised instance of `klass`.
* @note It calls the allocator defined by rb_define_alloc_func(). You
* cannot use this function to define an allocator. Use
- * TypedData_Make_Struct or others, instead.
+ * rb_newobj_of(), #TypedData_Make_Struct or others, instead.
* @note Usually prefer rb_class_new_instance() to rb_obj_alloc() and
* rb_obj_call_init().
* @see rb_class_new_instance()
* @see rb_obj_call_init()
* @see rb_define_alloc_func()
+ * @see rb_newobj_of()
* @see #TypedData_Make_Struct
*/
VALUE rb_obj_alloc(VALUE klass);
diff --git a/include/ruby/internal/intern/process.h b/include/ruby/internal/intern/process.h
index cfa5e13162..7a7b24ed4b 100644
--- a/include/ruby/internal/intern/process.h
+++ b/include/ruby/internal/intern/process.h
@@ -31,15 +31,6 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
/* process.c */
/**
- * Wait for the specified process to terminate, reap it, and return its status.
- *
- * @param[in] pid The process ID to wait for.
- * @param[in] flags The flags to pass to waitpid(2).
- * @return VALUE An instance of Process::Status.
- */
-VALUE rb_process_status_wait(rb_pid_t pid, int flags);
-
-/**
* Sets the "last status", or the `$?`.
*
* @param[in] status The termination status, as defined in `waitpid(3posix)`.
@@ -256,7 +247,7 @@ rb_pid_t rb_spawn_err(int argc, const VALUE *argv, char *errbuf, size_t buflen);
*
* @internal
*
- * This function might or might not exist depending on `./configure` result.
+ * This function might or might not exist depending on `./confiugre` result.
* It must be a portability hell. Better not use.
*/
VALUE rb_proc_times(VALUE _);
diff --git a/include/ruby/internal/intern/re.h b/include/ruby/internal/intern/re.h
index 4dd58b469b..31f5593275 100644
--- a/include/ruby/internal/intern/re.h
+++ b/include/ruby/internal/intern/re.h
@@ -87,6 +87,11 @@ void rb_match_busy(VALUE md);
* @retval RUBY_Qfalse There is a `n`-th capture and is empty.
* @retval RUBY_Qtrue There is a `n`-th capture that has something.
*
+ * @internal
+ *
+ * @shyouhei wonders: why there are both rb_reg_match_defined() and
+ * rb_match_nth_defined, which are largely the same things, but do not share
+ * their implementations at all?
*/
VALUE rb_reg_nth_defined(int n, VALUE md);
diff --git a/include/ruby/internal/intern/select.h b/include/ruby/internal/intern/select.h
index 6ba84c6e63..fabc287cd1 100644
--- a/include/ruby/internal/intern/select.h
+++ b/include/ruby/internal/intern/select.h
@@ -76,7 +76,7 @@ struct timeval;
*
* Although any file descriptors are possible here, it makes completely no
* sense to pass a descriptor that is not `O_NONBLOCK`. If you want to know
- * the reason for this limitation in detail, you might find this thread super
+ * the reason for this limitatuon in detail, you might find this thread super
* interesting: https://lkml.org/lkml/2004/10/6/117
*/
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout);
diff --git a/include/ruby/internal/intern/signal.h b/include/ruby/internal/intern/signal.h
index 4773788651..84f7558404 100644
--- a/include/ruby/internal/intern/signal.h
+++ b/include/ruby/internal/intern/signal.h
@@ -97,7 +97,7 @@ RBIMPL_ATTR_NONNULL(())
* - Case #11: When signo and PID are both negative, the behaviour of this
* function depends on how `killpg(3)` works. On Linux, it seems such
* attempt is strictly prohibited and `Errno::EINVAL` is raised. But on
- * macOS, it seems it tries to send the signal actually to the process
+ * macOS, it seems it tries to to send the signal actually to the process
* group.
*
* @note Above description is in fact different from how `kill(2)` works.
@@ -113,6 +113,12 @@ RBIMPL_ATTR_NONNULL(())
*/
VALUE rb_f_kill(int argc, const VALUE *argv);
+/* This must be private, @shyouhei guesses. */
+#ifdef POSIX_SIGNAL
+#define posix_signal ruby_posix_signal
+void (*posix_signal(int, void (*)(int)))(int);
+#endif
+
RBIMPL_ATTR_PURE()
/**
* Queries the name of the signal. It returns for instance `"KILL"` for
diff --git a/include/ruby/internal/intern/string.h b/include/ruby/internal/intern/string.h
index 37dee45527..3083125e56 100644
--- a/include/ruby/internal/intern/string.h
+++ b/include/ruby/internal/intern/string.h
@@ -412,7 +412,7 @@ VALUE rb_utf8_str_new_static(const char *ptr, long len);
/**
* Identical to rb_interned_str(), except it takes a Ruby's string instead of
- * C's. It can also be seen as a routine identical to rb_str_new_shared(),
+ * C's. It can also be seen as a routine identical to to rb_str_new_shared(),
* except it returns an infamous "f"string.
*
* @param[in] str An object of ::RString.
@@ -454,7 +454,7 @@ VALUE rb_interned_str(const char *ptr, long len);
RBIMPL_ATTR_NONNULL(())
/**
* Identical to rb_interned_str(), except it assumes the passed pointer is a
- * pointer to a C's string. It can also be seen as a routine identical to
+ * pointer to a C's string. It can also be seen as a routine identical to to
* rb_str_to_interned_str(), except it takes a C's string instead of Ruby's.
* Or it can also be seen as a routine identical to rb_str_new_cstr(), except
* it returns an infamous "f"string.
diff --git a/include/ruby/internal/intern/struct.h b/include/ruby/internal/intern/struct.h
index 16b3fad4e0..312cf444e2 100644
--- a/include/ruby/internal/intern/struct.h
+++ b/include/ruby/internal/intern/struct.h
@@ -46,16 +46,14 @@ VALUE rb_struct_new(VALUE klass, ...);
*
* @param[in] name Name of the class.
* @param[in] ... Arbitrary number of `const char*`, terminated by
- * NULL. Each of which are the name of fields.
+ * zero. Each of which are the name of fields.
* @exception rb_eNameError `name` is not a constant name.
* @exception rb_eTypeError `name` is already taken.
- * @exception rb_eArgError Duplicated field name.
+ * @exception rb_eArgError Duplicated field name.
* @return The defined class.
* @post Global toplevel constant `name` is defined.
* @note `name` is allowed to be a null pointer. This function creates
* an anonymous struct class then.
- * @note The GC does not collect nor move classes returned by this
- * function. They are immortal.
*
* @internal
*
@@ -72,16 +70,14 @@ RBIMPL_ATTR_NONNULL((2))
* @param[out] space Namespace that the defining class shall reside.
* @param[in] name Name of the class.
* @param[in] ... Arbitrary number of `const char*`, terminated by
- * NULL. Each of which are the name of fields.
+ * zero. Each of which are the name of fields.
* @exception rb_eNameError `name` is not a constant name.
* @exception rb_eTypeError `name` is already taken.
- * @exception rb_eArgError Duplicated field name.
+ * @exception rb_eArgError Duplicated field name.
* @return The defined class.
* @post `name` is a constant under `space`.
* @note In contrast to rb_struct_define(), it doesn't make any sense to
* pass a null pointer to this function.
- * @note The GC does not collect nor move classes returned by this
- * function. They are immortal.
*/
VALUE rb_struct_define_under(VALUE space, const char *name, ...);
@@ -168,10 +164,10 @@ VALUE rb_struct_alloc_noinit(VALUE klass);
* @param[in] super Superclass of the defining class.
* @param[in] func Must be 0 for extension libraries.
* @param[in] ... Arbitrary number of `const char*`, terminated by
- * NULL. Each of which are the name of fields.
+ * zero. Each of which are the name of fields.
* @exception rb_eNameError `name` is not a constant name.
* @exception rb_eTypeError `name` is already taken.
- * @exception rb_eArgError Duplicated field name.
+ * @exception rb_eArgError Duplicated field name.
* @return The defined class.
* @post Global toplevel constant `name` is defined.
* @note `name` is allowed to be a null pointer. This function creates
@@ -191,35 +187,17 @@ RBIMPL_ATTR_NONNULL((2))
* @param[in] super Superclass of the defining class.
* @param[in] alloc Must be 0 for extension libraries.
* @param[in] ... Arbitrary number of `const char*`, terminated by
- * NULL. Each of which are the name of fields.
+ * zero. Each of which are the name of fields.
* @exception rb_eNameError `class_name` is not a constant name.
* @exception rb_eTypeError `class_name` is already taken.
- * @exception rb_eArgError Duplicated field name.
+ * @exception rb_eArgError Duplicated field name.
* @return The defined class.
* @post `class_name` is a constant under `outer`.
* @note In contrast to rb_struct_define_without_accessor(), it doesn't
* make any sense to pass a null name.
- * @note The GC does not collect nor move classes returned by this
- * function. They are immortal.
*/
VALUE rb_struct_define_without_accessor_under(VALUE outer, const char *class_name, VALUE super, rb_alloc_func_t alloc, ...);
-/**
- * Defines an anonymous data class.
- *
- * @endinternal
- *
- * @param[in] super Superclass of the defining class. Must be a
- * descendant of ::rb_cData, or 0 as ::rb_cData.
- * @param[in] ... Arbitrary number of `const char*`, terminated by
- * NULL. Each of which are the name of fields.
- * @exception rb_eArgError Duplicated field name.
- * @return The defined class.
- * @note The GC does not collect nor move classes returned by this
- * function. They are immortal.
- */
-VALUE rb_data_define(VALUE super, ...);
-
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_INTERN_STRUCT_H */
diff --git a/include/ruby/internal/intern/vm.h b/include/ruby/internal/intern/vm.h
index 29e0c7f534..76af796b54 100644
--- a/include/ruby/internal/intern/vm.h
+++ b/include/ruby/internal/intern/vm.h
@@ -229,7 +229,8 @@ void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func);
* restrict creation of an instance of a class. For example it rarely makes
* sense for a DB adaptor class to allow programmers creating DB row objects
* without querying the DB itself. You can kill sporadic creation of such
- * objects then, by nullifying the allocator function using this API.
+ * objects then, by nullifying the allocator function using this API. Your
+ * object shall be allocated using #RB_NEWOBJ_OF() directly.
*
* @param[out] klass The class to modify.
* @pre `klass` must be an instance of Class.
diff --git a/include/ruby/internal/interpreter.h b/include/ruby/internal/interpreter.h
index a10e7ad2d8..662d39c0ec 100644
--- a/include/ruby/internal/interpreter.h
+++ b/include/ruby/internal/interpreter.h
@@ -141,7 +141,7 @@ void ruby_show_copyright(void);
*
* @param[in] addr A pointer somewhere on the stack, near its bottom.
*/
-void ruby_init_stack(void *addr);
+void ruby_init_stack(volatile VALUE *addr);
/**
* Initializes the VM and builtin libraries.
diff --git a/include/ruby/internal/memory.h b/include/ruby/internal/memory.h
index 64e850c65e..6884db195d 100644
--- a/include/ruby/internal/memory.h
+++ b/include/ruby/internal/memory.h
@@ -38,7 +38,7 @@
# include <alloca.h>
#endif
-#if defined(_MSC_VER) && defined(_M_AMD64)
+#if defined(_MSC_VER) && defined(_WIN64)
# include <intrin.h>
# pragma intrinsic(_umul128)
#endif
@@ -56,14 +56,13 @@
#include "ruby/internal/has/builtin.h"
#include "ruby/internal/stdalign.h"
#include "ruby/internal/stdbool.h"
-#include "ruby/internal/stdckdint.h"
#include "ruby/internal/xmalloc.h"
#include "ruby/backward/2/limits.h"
#include "ruby/backward/2/long_long.h"
#include "ruby/backward/2/assume.h"
#include "ruby/defines.h"
-/** @cond INTERNAL_MACRO */
+/** @cond INTENAL_MACRO */
/* Make alloca work the best possible way. */
#if defined(alloca)
@@ -568,10 +567,7 @@ rbimpl_size_mul_overflow(size_t x, size_t y)
{
struct rbimpl_size_mul_overflow_tag ret = { false, 0, };
-#if defined(ckd_mul)
- ret.left = ckd_mul(&ret.right, x, y);
-
-#elif RBIMPL_HAS_BUILTIN(__builtin_mul_overflow)
+#if RBIMPL_HAS_BUILTIN(__builtin_mul_overflow)
ret.left = __builtin_mul_overflow(x, y, &ret.right);
#elif defined(DSIZE_T)
@@ -643,7 +639,7 @@ rbimpl_size_mul_or_raise(size_t x, size_t y)
static inline void *
rb_alloc_tmp_buffer2(volatile VALUE *store, long count, size_t elsize)
{
- const size_t total_size = rbimpl_size_mul_or_raise(RBIMPL_CAST((size_t)count), elsize);
+ const size_t total_size = rbimpl_size_mul_or_raise(count, elsize);
const size_t cnt = (total_size + sizeof(VALUE) - 1) / sizeof(VALUE);
return rb_alloc_tmp_buffer_with_count(store, total_size, cnt);
}
diff --git a/include/ruby/internal/module.h b/include/ruby/internal/module.h
index 97b0b2b8b0..d678dd2102 100644
--- a/include/ruby/internal/module.h
+++ b/include/ruby/internal/module.h
@@ -56,8 +56,8 @@ RBIMPL_ATTR_NONNULL(())
* @post Top-level constant named `name` refers the returned class.
* @note If a class named `name` is already defined and its superclass is
* `super`, the function just returns the defined class.
- * @note The GC does not collect nor move classes returned by this
- * function. They are immortal.
+ * @note The compaction GC does not move classes returned by this
+ * function.
*
* @internal
*
@@ -75,8 +75,8 @@ RBIMPL_ATTR_NONNULL(())
* constant is not a module.
* @return The created module.
* @post Top-level constant named `name` refers the returned module.
- * @note The GC does not collect nor move modules returned by this
- * function. They are immortal.
+ * @note The compaction GC does not move classes returned by this
+ * function.
*
* @internal
*
@@ -103,8 +103,8 @@ RBIMPL_ATTR_NONNULL(())
* @post `outer::name` refers the returned class.
* @note If a class named `name` is already defined and its superclass
* is `super`, the function just returns the defined class.
- * @note The GC does not collect nor move classes returned by this
- * function. They are immortal.
+ * @note The compaction GC does not move classes returned by this
+ * function.
*/
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super);
@@ -118,8 +118,8 @@ RBIMPL_ATTR_NONNULL(())
* the constant is not a class.
* @return The created module.
* @post `outer::name` refers the returned module.
- * @note The GC does not collect nor move modules returned by this
- * function. They are immortal.
+ * @note The compaction GC does not move classes returned by this
+ * function.
*/
VALUE rb_define_module_under(VALUE outer, const char *name);
diff --git a/include/ruby/internal/newobj.h b/include/ruby/internal/newobj.h
index 6eee2fa5fa..a8a5557a25 100644
--- a/include/ruby/internal/newobj.h
+++ b/include/ruby/internal/newobj.h
@@ -29,14 +29,63 @@
#include "ruby/internal/value.h"
#include "ruby/assert.h"
+/**
+ * Declares, allocates, then assigns a new object to the given variable.
+ *
+ * @param obj Variable name.
+ * @param type Variable type.
+ * @exception rb_eNoMemError No space left.
+ * @return An allocated object, not initialised.
+ * @note Modern programs tend to use #NEWOBJ_OF instead.
+ *
+ * @internal
+ *
+ * :FIXME: Should we deprecate it?
+ */
+#define RB_NEWOBJ(obj,type) type *(obj) = RBIMPL_CAST((type *)rb_newobj())
+
+/**
+ * Identical to #RB_NEWOBJ, except it also accepts the allocating object's
+ * class and flags.
+ *
+ * @param obj Variable name.
+ * @param type Variable type.
+ * @param klass Object's class.
+ * @param flags Object's flags.
+ * @exception rb_eNoMemError No space left.
+ * @return An allocated object, filled with the arguments.
+ */
+#define RB_NEWOBJ_OF(obj,type,klass,flags) type *(obj) = RBIMPL_CAST((type *)rb_newobj_of(klass, flags))
+
+#define NEWOBJ RB_NEWOBJ /**< @old{RB_NEWOBJ} */
+#define NEWOBJ_OF RB_NEWOBJ_OF /**< @old{RB_NEWOBJ_OF} */
#define OBJSETUP rb_obj_setup /**< @old{rb_obj_setup} */
#define CLONESETUP rb_clone_setup /**< @old{rb_clone_setup} */
#define DUPSETUP rb_dup_setup /**< @old{rb_dup_setup} */
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
+ * This is the implementation detail of #RB_NEWOBJ.
+ *
+ * @exception rb_eNoMemError No space left.
+ * @return An allocated object, not initialised.
+ */
+VALUE rb_newobj(void);
+
+/**
+ * This is the implementation detail of #RB_NEWOBJ_OF.
+ *
+ * @param klass Object's class.
+ * @param flags Object's flags.
+ * @exception rb_eNoMemError No space left.
+ * @return An allocated object, filled with the arguments.
+ */
+VALUE rb_newobj_of(VALUE klass, VALUE flags);
+
+/**
* Fills common fields in the object.
*
+ * @note Prefer rb_newobj_of() to this function.
* @param[in,out] obj A Ruby object to be set up.
* @param[in] klass `obj` will belong to this class.
* @param[in] type One of ::ruby_value_type.
@@ -123,8 +172,6 @@ RBIMPL_ATTR_DEPRECATED(("This is no longer how Object#clone works."))
static inline void
rb_clone_setup(VALUE clone, VALUE obj)
{
- (void)clone;
- (void)obj;
return;
}
@@ -142,8 +189,6 @@ RBIMPL_ATTR_DEPRECATED(("This is no longer how Object#dup works."))
static inline void
rb_dup_setup(VALUE dup, VALUE obj)
{
- (void)dup;
- (void)obj;
return;
}
diff --git a/include/ruby/internal/rgengc.h b/include/ruby/internal/rgengc.h
new file mode 100644
index 0000000000..7ea04442f6
--- /dev/null
+++ b/include/ruby/internal/rgengc.h
@@ -0,0 +1,443 @@
+#ifndef RBIMPL_RGENGC_H /*-*-C++-*-vi:se ft=cpp:*/
+#define RBIMPL_RGENGC_H
+/**
+ * @file
+ * @author Ruby developers <ruby-core@ruby-lang.org>
+ * @copyright This file is a part of the programming language Ruby.
+ * Permission is hereby granted, to either redistribute and/or
+ * modify this file, provided that the conditions mentioned in the
+ * file COPYING are met. Consult the file for details.
+ * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
+ * implementation details. Don't take them as canon. They could
+ * rapidly appear then vanish. The name (path) of this header file
+ * is also an implementation detail. Do not expect it to persist
+ * at the place it is now. Developers are free to move it anywhere
+ * anytime at will.
+ * @note To ruby-core: remember that this header can be possibly
+ * recursively included from extension libraries written in C++.
+ * Do not expect for instance `__VA_ARGS__` is always available.
+ * We assume C99 for ruby itself but we don't assume languages of
+ * extension libraries. They could be written in C++98.
+ * @brief RGENGC write-barrier APIs.
+ * @see Sasada, K., "Gradual write-barrier insertion into a Ruby
+ * interpreter", in proceedings of the 2019 ACM SIGPLAN
+ * International Symposium on Memory Management (ISMM 2019), pp
+ * 115-121, 2019. https://doi.org/10.1145/3315573.3329986
+ */
+#include "ruby/internal/attr/artificial.h"
+#include "ruby/internal/attr/maybe_unused.h"
+#include "ruby/internal/attr/pure.h"
+#include "ruby/internal/dllexport.h"
+#include "ruby/internal/special_consts.h"
+#include "ruby/internal/stdbool.h"
+#include "ruby/internal/value.h"
+#include "ruby/assert.h"
+
+/**
+ * @private
+ *
+ * @deprecated This macro once was a thing in the old days, but makes no sense
+ * any longer today. Exists here for backwards compatibility
+ * only. You can safely forget about it.
+ */
+#undef USE_RGENGC
+#define USE_RGENGC 1
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable incremental GC feature. It
+ * has to be set at the time ruby itself compiles. Makes no sense for 3rd
+ * parties. It is safe for them to set this though; that just doesn't change
+ * anything.
+ */
+#ifndef USE_RINCGC
+# define USE_RINCGC 1
+#endif
+
+/**
+ * @deprecated This macro seems broken. Setting this to anything other than
+ * zero just doesn't compile. We need to KonMari.
+ */
+#ifndef USE_RGENGC_LOGGING_WB_UNPROTECT
+# define USE_RGENGC_LOGGING_WB_UNPROTECT 0
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RArray. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_ARRAY
+# define RGENGC_WB_PROTECTED_ARRAY 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RHash. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_HASH
+# define RGENGC_WB_PROTECTED_HASH 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RStruct. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_STRUCT
+# define RGENGC_WB_PROTECTED_STRUCT 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RString. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_STRING
+# define RGENGC_WB_PROTECTED_STRING 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RObject. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_OBJECT
+# define RGENGC_WB_PROTECTED_OBJECT 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RRegexp. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_REGEXP
+# define RGENGC_WB_PROTECTED_REGEXP 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RClass. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_CLASS
+# define RGENGC_WB_PROTECTED_CLASS 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RFloat. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_FLOAT
+# define RGENGC_WB_PROTECTED_FLOAT 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RComplex. It has to be set at the time ruby itself compiles.
+ * Makes no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_COMPLEX
+# define RGENGC_WB_PROTECTED_COMPLEX 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RRational. It has to be set at the time ruby itself compiles.
+ * Makes no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_RATIONAL
+# define RGENGC_WB_PROTECTED_RATIONAL 1
+#endif
+
+/**
+ * @private
+ *
+ * This is a compile-time flag to enable/disable write barrier for
+ * struct ::RBignum. It has to be set at the time ruby itself compiles. Makes
+ * no sense for 3rd parties.
+ */
+#ifndef RGENGC_WB_PROTECTED_BIGNUM
+# define RGENGC_WB_PROTECTED_BIGNUM 1
+#endif
+
+/**
+ * @private
+ *
+ * @deprecated This macro once was a thing in the old days, but makes no sense
+ * any longer today. Exists here for backwards compatibility
+ * only. You can safely forget about it.
+ *
+ * @internal
+ *
+ * @shyouhei doesn't think anybody uses this right now.
+ */
+#ifndef RGENGC_WB_PROTECTED_NODE_CREF
+# define RGENGC_WB_PROTECTED_NODE_CREF 1
+#endif
+
+/**
+ * @defgroup rgengc Write barrier (WB) interfaces:
+ *
+ * @note The following core interfaces can be changed in the future. Please
+ * catch up if you want to insert WB into C-extensions correctly.
+ *
+ * @{
+ */
+
+/**
+ * Declaration of a "back" pointer. This is a write barrier for new reference
+ * from "old" generation to "young" generation. It writes `young` into
+ * `*slot`, which is a pointer inside of `old`.
+ *
+ * @param[in] old An old object.
+ * @param[in] slot A pointer inside of `old`.
+ * @param[out] young A young object.
+ */
+#define RB_OBJ_WRITE(old, slot, young) \
+ RBIMPL_CAST(rb_obj_write((VALUE)(old), (VALUE *)(slot), (VALUE)(young), __FILE__, __LINE__))
+
+/**
+ * Identical to #RB_OBJ_WRITE(), except it doesn't write any values, but only a
+ * WB declaration. `oldv` is replaced value with `b` (not used in current
+ * Ruby).
+ *
+ * @param[in] old An old object.
+ * @param[in] oldv An object previously stored inside of `old`.
+ * @param[out] young A young object.
+ */
+#define RB_OBJ_WRITTEN(old, oldv, young) \
+ RBIMPL_CAST(rb_obj_written((VALUE)(old), (VALUE)(oldv), (VALUE)(young), __FILE__, __LINE__))
+/** @} */
+
+#define OBJ_PROMOTED_RAW RB_OBJ_PROMOTED_RAW /**< @old{RB_OBJ_PROMOTED_RAW} */
+#define OBJ_PROMOTED RB_OBJ_PROMOTED /**< @old{RB_OBJ_PROMOTED} */
+#define OBJ_WB_UNPROTECT RB_OBJ_WB_UNPROTECT /**< @old{RB_OBJ_WB_UNPROTECT} */
+
+/**
+ * Asserts that the passed object is not fenced by write barriers. Objects of
+ * such property do not contribute to generational GCs. They are scanned
+ * always.
+ *
+ * @param[out] x An object that would not be protected by the barrier.
+ */
+#define RB_OBJ_WB_UNPROTECT(x) rb_obj_wb_unprotect(x, __FILE__, __LINE__)
+
+/**
+ * Identical to #RB_OBJ_WB_UNPROTECT(), except it can also assert that the
+ * given object is of given type.
+ *
+ * @param[in] type One of `ARRAY`, `STRING`, etc.
+ * @param[out] obj An object of `type` that would not be protected.
+ *
+ * @internal
+ *
+ * @shyouhei doesn't understand why this has to be visible from extensions.
+ */
+#define RB_OBJ_WB_UNPROTECT_FOR(type, obj) \
+ (RGENGC_WB_PROTECTED_##type ? OBJ_WB_UNPROTECT(obj) : obj)
+
+/**
+ * @private
+ *
+ * This is an implementation detail of rb_obj_wb_unprotect(). People don't use
+ * it directly.
+ */
+#define RGENGC_LOGGING_WB_UNPROTECT rb_gc_unprotect_logging
+
+/** @cond INTERNAL_MACRO */
+#define RB_OBJ_PROMOTED_RAW RB_OBJ_PROMOTED_RAW
+#define RB_OBJ_PROMOTED RB_OBJ_PROMOTED
+/** @endcond */
+
+RBIMPL_SYMBOL_EXPORT_BEGIN()
+/**
+ * This is the implementation of #RB_OBJ_WRITE(). People don't use it
+ * directly.
+ *
+ * @param[in] old An object that points to `young`.
+ * @param[out] young An object that is referenced from `old`.
+ */
+void rb_gc_writebarrier(VALUE old, VALUE young);
+
+/**
+ * This is the implementation of #RB_OBJ_WB_UNPROTECT(). People don't use it
+ * directly.
+ *
+ * @param[out] obj An object that does not participate in WB.
+ */
+void rb_gc_writebarrier_unprotect(VALUE obj);
+
+#if USE_RGENGC_LOGGING_WB_UNPROTECT
+/**
+ * @private
+ *
+ * This is the implementation of #RGENGC_LOGGING_WB_UNPROTECT(). People
+ * don't use it directly.
+ *
+ * @param[in] objptr Don't know why this is a pointer to void but in
+ * reality this is a pointer to an object that is about
+ * to be un-protected.
+ * @param[in] filename Pass C's `__FILE__` here.
+ * @param[in] line Pass C's `__LINE__` here.
+ */
+void rb_gc_unprotect_logging(void *objptr, const char *filename, int line);
+#endif
+
+RBIMPL_SYMBOL_EXPORT_END()
+
+RBIMPL_ATTR_PURE_UNLESS_DEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+/**
+ * This is the implementation of #RB_OBJ_PROMOTED(). People don't use it
+ * directly.
+ *
+ * @param[in] obj An object to query.
+ * @retval true The object is "promoted".
+ * @retval false The object is young. Have not experienced GC at all.
+ */
+static inline bool
+RB_OBJ_PROMOTED_RAW(VALUE obj)
+{
+ RBIMPL_ASSERT_OR_ASSUME(RB_FL_ABLE(obj));
+ return RB_FL_ANY_RAW(obj, RUBY_FL_PROMOTED);
+}
+
+RBIMPL_ATTR_PURE_UNLESS_DEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+/**
+ * Tests if the object is "promoted" -- that is, whether the object experienced
+ * one or more GC marks.
+ *
+ * @param[in] obj An object to query.
+ * @retval true The object is "promoted".
+ * @retval false The object is young. Have not experienced GC at all.
+ * @note Hello, is anyone actively calling this function? @shyouhei have
+ * never seen any actual usages outside of the GC implementation
+ * itself.
+ */
+static inline bool
+RB_OBJ_PROMOTED(VALUE obj)
+{
+ if (! RB_FL_ABLE(obj)) {
+ return false;
+ }
+ else {
+ return RB_OBJ_PROMOTED_RAW(obj);
+ }
+}
+
+/**
+ * This is the implementation of #RB_OBJ_WB_UNPROTECT(). People don't use it
+ * directly.
+ *
+ * @param[out] x An object that does not participate in WB.
+ * @param[in] filename C's `__FILE__` of the caller function.
+ * @param[in] line C's `__LINE__` of the caller function.
+ * @return x
+ */
+static inline VALUE
+rb_obj_wb_unprotect(
+ VALUE x,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ const char *filename,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ int line)
+{
+#if USE_RGENGC_LOGGING_WB_UNPROTECT
+ RGENGC_LOGGING_WB_UNPROTECT(RBIMPL_CAST((void *)x), filename, line);
+#endif
+ rb_gc_writebarrier_unprotect(x);
+ return x;
+}
+
+/**
+ * @private
+ *
+ * This is the implementation of #RB_OBJ_WRITTEN(). People don't use it
+ * directly.
+ *
+ * @param[in] a An old object.
+ * @param[in] oldv An object previously stored inside of `old`.
+ * @param[out] b A young object.
+ * @param[in] filename C's `__FILE__` of the caller function.
+ * @param[in] line C's `__LINE__` of the caller function.
+ * @return a
+ */
+static inline VALUE
+rb_obj_written(
+ VALUE a,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ VALUE oldv,
+ VALUE b,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ const char *filename,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ int line)
+{
+#if USE_RGENGC_LOGGING_WB_UNPROTECT
+ RGENGC_LOGGING_OBJ_WRITTEN(a, oldv, b, filename, line);
+#endif
+
+ if (!RB_SPECIAL_CONST_P(b)) {
+ rb_gc_writebarrier(a, b);
+ }
+
+ return a;
+}
+
+/**
+ * @private
+ *
+ * This is the implementation of #RB_OBJ_WRITE(). People don't use it
+ * directly.
+ *
+ * @param[in] a An old object.
+ * @param[in] slot A pointer inside of `old`.
+ * @param[out] b A young object.
+ * @param[in] filename C's `__FILE__` of the caller function.
+ * @param[in] line C's `__LINE__` of the caller function.
+ * @return a
+ */
+static inline VALUE
+rb_obj_write(
+ VALUE a, VALUE *slot, VALUE b,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ const char *filename,
+ RBIMPL_ATTR_MAYBE_UNUSED()
+ int line)
+{
+#ifdef RGENGC_LOGGING_WRITE
+ RGENGC_LOGGING_WRITE(a, slot, b, filename, line);
+#endif
+
+ *slot = b;
+
+ rb_obj_written(a, RUBY_Qundef /* ignore `oldv' now */, b, filename, line);
+ return a;
+}
+
+#endif /* RBIMPL_RGENGC_H */
diff --git a/include/ruby/internal/scan_args.h b/include/ruby/internal/scan_args.h
index 2dbc1ee7bc..1ed2bf6368 100644
--- a/include/ruby/internal/scan_args.h
+++ b/include/ruby/internal/scan_args.h
@@ -75,7 +75,7 @@
* Pass keywords if current method is called with keywords, useful for argument
* delegation
*/
-#define RB_PASS_CALLED_KEYWORDS !!rb_keyword_given_p()
+#define RB_PASS_CALLED_KEYWORDS rb_keyword_given_p()
/** @} */
diff --git a/include/ruby/internal/special_consts.h b/include/ruby/internal/special_consts.h
index 05d1087c88..dc0a6b41d6 100644
--- a/include/ruby/internal/special_consts.h
+++ b/include/ruby/internal/special_consts.h
@@ -156,7 +156,7 @@ RB_TEST(VALUE obj)
*
* RTEST(v) can be 0 if and only if (v == Qfalse || v == Qnil).
*/
- return obj & RBIMPL_CAST((VALUE)~RUBY_Qnil);
+ return obj & ~RUBY_Qnil;
}
RBIMPL_ATTR_CONST()
@@ -226,7 +226,7 @@ RB_NIL_OR_UNDEF_P(VALUE obj)
*
* NIL_OR_UNDEF_P(v) can be true only when v is Qundef or Qnil.
*/
- const VALUE mask = RBIMPL_CAST((VALUE)~(RUBY_Qundef ^ RUBY_Qnil));
+ const VALUE mask = ~(RUBY_Qundef ^ RUBY_Qnil);
const VALUE common_bits = RUBY_Qundef & RUBY_Qnil;
return (obj & mask) == common_bits;
}
@@ -346,7 +346,7 @@ RBIMPL_ATTR_CONSTEXPR(CXX11)
static inline VALUE
rb_special_const_p(VALUE obj)
{
- return (unsigned int)RB_SPECIAL_CONST_P(obj) * RUBY_Qtrue;
+ return RB_SPECIAL_CONST_P(obj) * RUBY_Qtrue;
}
/**
diff --git a/include/ruby/internal/static_assert.h b/include/ruby/internal/static_assert.h
index b9ff6646e7..594c2b2917 100644
--- a/include/ruby/internal/static_assert.h
+++ b/include/ruby/internal/static_assert.h
@@ -71,7 +71,7 @@
#else
# define RBIMPL_STATIC_ASSERT(name, expr) \
- MAYBE_UNUSED(typedef int static_assert_ ## name ## _check[1 - 2 * !(expr)])
+ typedef int static_assert_ ## name ## _check[1 - 2 * !(expr)]
#endif
#endif /* RBIMPL_STATIC_ASSERT_H */
diff --git a/include/ruby/internal/stdckdint.h b/include/ruby/internal/stdckdint.h
deleted file mode 100644
index e5b5b8b751..0000000000
--- a/include/ruby/internal/stdckdint.h
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef RBIMPL_STDCKDINT_H /*-*-C++-*-vi:se ft=cpp:*/
-#define RBIMPL_STDCKDINT_H
-/**
- * @author Ruby developers <ruby-core@ruby-lang.org>
- * @copyright This file is a part of the programming language Ruby.
- * Permission is hereby granted, to either redistribute and/or
- * modify this file, provided that the conditions mentioned in the
- * file COPYING are met. Consult the file for details.
- * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
- * implementation details. Don't take them as canon. They could
- * rapidly appear then vanish. The name (path) of this header file
- * is also an implementation detail. Do not expect it to persist
- * at the place it is now. Developers are free to move it anywhere
- * anytime at will.
- * @note To ruby-core: remember that this header can be possibly
- * recursively included from extension libraries written in C++.
- * Do not expect for instance `__VA_ARGS__` is always available.
- * We assume C99 for ruby itself but we don't assume languages of
- * extension libraries. They could be written in C++98.
- * @brief C23 shim for <stdckdint.h>
- */
-#include "ruby/internal/config.h"
-#include "ruby/internal/cast.h"
-#include "ruby/internal/has/builtin.h"
-#include "ruby/internal/stdbool.h"
-
-#ifdef __has_include
-# if __has_include(<stdckdint.h>)
-# /* Conforming C23 situation; e.g. recent clang */
-# define RBIMPL_HAVE_STDCKDINT_H
-# endif
-#endif
-
-#ifdef HAVE_STDCKDINT_H
-# /* Some OSes (most notably FreeBSD) have this file. */
-# define RBIMPL_HAVE_STDCKDINT_H
-#endif
-
-#ifdef __cplusplus
-# /* It seems OS/Compiler provided stdckdint.h tend not support C++ yet.
-# * Situations could improve someday but in a meantime let us work around.
-# */
-# undef RBIMPL_HAVE_STDCKDINT_H
-#endif
-
-#ifdef RBIMPL_HAVE_STDCKDINT_H
-# /* Take that. */
-# include <stdckdint.h>
-
-#elif RBIMPL_HAS_BUILTIN(__builtin_add_overflow)
-# define ckd_add(x, y, z) RBIMPL_CAST((bool)__builtin_add_overflow((y), (z), (x)))
-# define ckd_sub(x, y, z) RBIMPL_CAST((bool)__builtin_sub_overflow((y), (z), (x)))
-# define ckd_mul(x, y, z) RBIMPL_CAST((bool)__builtin_mul_overflow((y), (z), (x)))
-# define __STDC_VERSION_STDCKDINT_H__ 202311L
-
-#/* elif defined(__cplusplus) */
-#/* :TODO: if we assume C++11 we can use `<type_traits>` to implement them. */
-
-#else
-# /* intentionally leave them undefined */
-# /* to make `#ifdef ckd_add` etc. work as intended. */
-# undef ckd_add
-# undef ckd_sub
-# undef ckd_mul
-# undef __STDC_VERSION_STDCKDINT_H__
-#endif
-
-#endif /* RBIMPL_STDCKDINT_H */
diff --git a/include/ruby/internal/value_type.h b/include/ruby/internal/value_type.h
index aedd0abe4b..977f60a009 100644
--- a/include/ruby/internal/value_type.h
+++ b/include/ruby/internal/value_type.h
@@ -96,11 +96,10 @@
#define RB_TYPE_P RB_TYPE_P
#define Check_Type Check_Type
-#ifdef RBIMPL_VA_OPT_ARGS
-# define RBIMPL_ASSERT_TYPE(v, t) \
- RBIMPL_ASSERT_OR_ASSUME(RB_TYPE_P(v, t), "actual type: %d", rb_type(v))
+#if !RUBY_DEBUG
+# define RBIMPL_ASSERT_TYPE(v, t) RBIMPL_ASSERT_OR_ASSUME(RB_TYPE_P((v), (t)))
#else
-# define RBIMPL_ASSERT_TYPE(v, t) RBIMPL_ASSERT_OR_ASSUME(RB_TYPE_P(v, t))
+# define RBIMPL_ASSERT_TYPE Check_Type
#endif
/** @endcond */
@@ -444,7 +443,7 @@ Check_Type(VALUE v, enum ruby_value_type t)
}
unexpected_type:
- rb_unexpected_type(v, RBIMPL_CAST((int)t));
+ rb_unexpected_type(v, t);
}
#endif /* RBIMPL_VALUE_TYPE_H */
diff --git a/include/ruby/internal/xmalloc.h b/include/ruby/internal/xmalloc.h
index 132bc478ce..57552e4e7d 100644
--- a/include/ruby/internal/xmalloc.h
+++ b/include/ruby/internal/xmalloc.h
@@ -283,6 +283,110 @@ void ruby_xfree(void *ptr)
RBIMPL_ATTR_NOEXCEPT(free(ptr))
;
+#if USE_GC_MALLOC_OBJ_INFO_DETAILS
+# define ruby_xmalloc(s1) ruby_xmalloc_with_location(s1, __FILE__, __LINE__)
+# define ruby_xmalloc2(s1, s2) ruby_xmalloc2_with_location(s1, s2, __FILE__, __LINE__)
+# define ruby_xcalloc(s1, s2) ruby_xcalloc_with_location(s1, s2, __FILE__, __LINE__)
+# define ruby_xrealloc(ptr, s1) ruby_xrealloc_with_location(ptr, s1, __FILE__, __LINE__)
+# define ruby_xrealloc2(ptr, s1, s2) ruby_xrealloc2_with_location(ptr, s1, s2, __FILE__, __LINE__)
+
+RBIMPL_ATTR_NODISCARD()
+RBIMPL_ATTR_RESTRICT()
+RBIMPL_ATTR_RETURNS_NONNULL()
+RBIMPL_ATTR_ALLOC_SIZE((1))
+void *ruby_xmalloc_body(size_t size)
+RBIMPL_ATTR_NOEXCEPT(malloc(size))
+;
+
+RBIMPL_ATTR_NODISCARD()
+RBIMPL_ATTR_RESTRICT()
+RBIMPL_ATTR_RETURNS_NONNULL()
+RBIMPL_ATTR_ALLOC_SIZE((1,2))
+void *ruby_xmalloc2_body(size_t nelems, size_t elemsiz)
+RBIMPL_ATTR_NOEXCEPT(malloc(nelems * elemsiz))
+;
+
+RBIMPL_ATTR_NODISCARD()
+RBIMPL_ATTR_RESTRICT()
+RBIMPL_ATTR_RETURNS_NONNULL()
+RBIMPL_ATTR_ALLOC_SIZE((1,2))
+void *ruby_xcalloc_body(size_t nelems, size_t elemsiz)
+RBIMPL_ATTR_NOEXCEPT(calloc(nelems, elemsiz))
+;
+
+RBIMPL_ATTR_NODISCARD()
+RBIMPL_ATTR_RETURNS_NONNULL()
+RBIMPL_ATTR_ALLOC_SIZE((2))
+void *ruby_xrealloc_body(void *ptr, size_t newsiz)
+RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newsiz))
+;
+
+RBIMPL_ATTR_NODISCARD()
+RBIMPL_ATTR_RETURNS_NONNULL()
+RBIMPL_ATTR_ALLOC_SIZE((2,3))
+void *ruby_xrealloc2_body(void *ptr, size_t newelems, size_t newsiz)
+RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newelems * newsiz))
+;
+
+RUBY_EXTERN const char *ruby_malloc_info_file;
+RUBY_EXTERN int ruby_malloc_info_line;
+
+static inline void *
+ruby_xmalloc_with_location(size_t s, const char *file, int line)
+{
+ void *ptr;
+ ruby_malloc_info_file = file;
+ ruby_malloc_info_line = line;
+ ptr = ruby_xmalloc_body(s);
+ ruby_malloc_info_file = NULL;
+ return ptr;
+}
+
+static inline void *
+ruby_xmalloc2_with_location(size_t s1, size_t s2, const char *file, int line)
+{
+ void *ptr;
+ ruby_malloc_info_file = file;
+ ruby_malloc_info_line = line;
+ ptr = ruby_xmalloc2_body(s1, s2);
+ ruby_malloc_info_file = NULL;
+ return ptr;
+}
+
+static inline void *
+ruby_xcalloc_with_location(size_t s1, size_t s2, const char *file, int line)
+{
+ void *ptr;
+ ruby_malloc_info_file = file;
+ ruby_malloc_info_line = line;
+ ptr = ruby_xcalloc_body(s1, s2);
+ ruby_malloc_info_file = NULL;
+ return ptr;
+}
+
+static inline void *
+ruby_xrealloc_with_location(void *ptr, size_t s, const char *file, int line)
+{
+ void *rptr;
+ ruby_malloc_info_file = file;
+ ruby_malloc_info_line = line;
+ rptr = ruby_xrealloc_body(ptr, s);
+ ruby_malloc_info_file = NULL;
+ return rptr;
+}
+
+static inline void *
+ruby_xrealloc2_with_location(void *ptr, size_t s1, size_t s2, const char *file, int line)
+{
+ void *rptr;
+ ruby_malloc_info_file = file;
+ ruby_malloc_info_line = line;
+ rptr = ruby_xrealloc2_body(ptr, s1, s2);
+ ruby_malloc_info_file = NULL;
+ return rptr;
+}
+#endif
+
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_XMALLOC_H */
diff --git a/include/ruby/io.h b/include/ruby/io.h
index d2fd3ed317..88029b1bb9 100644
--- a/include/ruby/io.h
+++ b/include/ruby/io.h
@@ -49,11 +49,11 @@
/** @endcond */
#include "ruby/internal/attr/const.h"
-#include "ruby/internal/attr/packed_struct.h"
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/attr/noreturn.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"
+#include "ruby/backward/2/attributes.h" /* PACKED_STRUCT_UNALIGNED */
// IO#wait, IO#wait_readable, IO#wait_writable, IO#wait_priority are defined by this implementation.
#define RUBY_IO_WAIT_METHODS
@@ -78,20 +78,17 @@ RUBY_EXTERN VALUE rb_eIOTimeoutError;
*
* This is visible from extension libraries because `io/wait` wants it.
*/
-enum rb_io_event {
+typedef enum {
RUBY_IO_READABLE = RB_WAITFD_IN, /**< `IO::READABLE` */
RUBY_IO_WRITABLE = RB_WAITFD_OUT, /**< `IO::WRITABLE` */
RUBY_IO_PRIORITY = RB_WAITFD_PRI, /**< `IO::PRIORITY` */
-};
-
-typedef enum rb_io_event rb_io_event_t;
+} rb_io_event_t;
/**
* IO buffers. This is an implementation detail of ::rb_io_t::wbuf and
* ::rb_io_t::rbuf. People don't manipulate it directly.
*/
-RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN()
-struct rb_io_internal_buffer {
+PACKED_STRUCT_UNALIGNED(struct rb_io_buffer_t {
/** Pointer to the underlying memory region, of at least `capa` bytes. */
char *ptr; /* off + len <= capa */
@@ -104,10 +101,10 @@ struct rb_io_internal_buffer {
/** Designed capacity of the buffer. */
int capa;
-} RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END();
+});
/** @alias{rb_io_buffer_t} */
-typedef struct rb_io_internal_buffer rb_io_buffer_t;
+typedef struct rb_io_buffer_t rb_io_buffer_t;
/** Decomposed encoding flags (e.g. `"enc:enc2""`). */
/*
@@ -116,7 +113,7 @@ typedef struct rb_io_internal_buffer rb_io_buffer_t;
* e1 NULL force_encoding(e1) convert str.encoding to e1
* e1 e2 convert from e2 to e1 convert str.encoding to e2
*/
-struct rb_io_encoding {
+struct rb_io_enc_t {
/** Internal encoding. */
rb_encoding *enc;
/** External encoding. */
@@ -137,51 +134,40 @@ struct rb_io_encoding {
VALUE ecopts;
};
-#ifndef HAVE_RB_IO_T
-#define HAVE_RB_IO_T 1
/** Ruby's IO, metadata and buffers. */
-struct rb_io {
+typedef struct rb_io_t {
+
/** The IO's Ruby level counterpart. */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
VALUE self;
/** stdio ptr for read/write, if available. */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
FILE *stdio_file;
/** file descriptor. */
- RBIMPL_ATTR_DEPRECATED(("rb_io_descriptor"))
int fd;
/** mode flags: FMODE_XXXs */
- RBIMPL_ATTR_DEPRECATED(("rb_io_mode"))
int mode;
/** child's pid (for pipes) */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
rb_pid_t pid;
/** number of lines read */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
int lineno;
/** pathname for file */
- RBIMPL_ATTR_DEPRECATED(("rb_io_path"))
VALUE pathv;
/** finalize proc */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
- void (*finalize)(struct rb_io*,int);
+ void (*finalize)(struct rb_io_t*,int);
/** Write buffer. */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
rb_io_buffer_t wbuf;
/**
* (Byte) read buffer. Note also that there is a field called
* ::rb_io_t::cbuf, which also concerns read IO.
*/
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
rb_io_buffer_t rbuf;
/**
@@ -189,25 +175,20 @@ struct rb_io {
*
* @see rb_io_set_write_io()
*/
- RBIMPL_ATTR_DEPRECATED(("rb_io_get_write_io"))
VALUE tied_io_for_writing;
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
- struct rb_io_encoding encs; /**< Decomposed encoding flags. */
+ struct rb_io_enc_t encs; /**< Decomposed encoding flags. */
/** Encoding converter used when reading from this IO. */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
rb_econv_t *readconv;
/**
* rb_io_ungetc() destination. This buffer is read before checking
* ::rb_io_t::rbuf
*/
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
rb_io_buffer_t cbuf;
/** Encoding converter used when writing to this IO. */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
rb_econv_t *writeconv;
/**
@@ -216,25 +197,21 @@ struct rb_io {
* conversion from encoding X to encoding Y does not exist, Ruby finds an
* encoding Z that bridges the two, so that X to Z to Y conversion happens.
*/
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
VALUE writeconv_asciicompat;
/** Whether ::rb_io_t::writeconv is already set up. */
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
int writeconv_initialized;
/**
* Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before
* initialising ::rb_io_t::writeconv.
*/
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
int writeconv_pre_ecflags;
/**
* Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising
* ::rb_io_t::writeconv.
*/
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
VALUE writeconv_pre_ecopts;
/**
@@ -244,21 +221,25 @@ struct rb_io {
*
* This of course doesn't help inter-process IO interleaves, though.
*/
- RBIMPL_ATTR_DEPRECATED(("with no replacement"))
VALUE write_lock;
/**
* The timeout associated with this IO when performing blocking operations.
*/
- RBIMPL_ATTR_DEPRECATED(("rb_io_timeout/rb_io_set_timeout"))
VALUE timeout;
-};
-#endif
-
-typedef struct rb_io rb_io_t;
+} rb_io_t;
/** @alias{rb_io_enc_t} */
-typedef struct rb_io_encoding rb_io_enc_t;
+typedef struct rb_io_enc_t rb_io_enc_t;
+
+/**
+ * @private
+ *
+ * @deprecated This macro once was a thing in the old days, but makes no sense
+ * any longer today. Exists here for backwards compatibility
+ * only. You can safely forget about it.
+ */
+#define HAVE_RB_IO_T 1
/**
* @name Possible flags for ::rb_io_t::mode
@@ -349,16 +330,7 @@ typedef struct rb_io_encoding rb_io_enc_t;
* Setting this one and #FMODE_BINMODE at the same time is a contradiction.
*/
#define FMODE_TEXTMODE 0x00001000
-/**
- * This flag means that an IO object is wrapping an "external" file descriptor,
- * which is owned by something outside the Ruby interpreter (usually a C extension).
- * Ruby will not close this file when the IO object is garbage collected.
- * If this flag is set, then IO#autoclose? is false, and vice-versa.
- *
- * This flag was previously called FMODE_PREP internally.
- */
-#define FMODE_EXTERNAL 0x00010000
-
+/* #define FMODE_PREP 0x00010000 */
/* #define FMODE_SIGNAL_ON_EPIPE 0x00020000 */
/**
@@ -373,18 +345,6 @@ typedef struct rb_io_encoding rb_io_enc_t;
/** @} */
/**
- * Allocate a new IO object, with the given file descriptor.
- */
-VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding);
-
-/**
- * Returns whether or not the underlying IO is closed.
- *
- * @return Whether the underlying IO is closed.
- */
-VALUE rb_io_closed_p(VALUE io);
-
-/**
* Queries the underlying IO pointer.
*
* @param[in] obj An IO object.
@@ -454,14 +414,14 @@ rb_io_t *rb_io_make_open_file(VALUE obj);
* like this:
*
* ```CXX
- * typedef struct rb_io {
+ * typedef struct rb_io_t {
* FILE *f; // stdio ptr for read/write
* FILE *f2; // additional ptr for rw pipes
* int mode; // mode flags
* int pid; // child's pid (for pipes)
* int lineno; // number of lines read
* char *path; // pathname for file
- * void (*finalize) _((struct rb_io*,int)); // finalize proc
+ * void (*finalize) _((struct rb_io_t*,int)); // finalize proc
* } rb_io_t;
*```
*
@@ -743,12 +703,6 @@ VALUE rb_io_set_write_io(VALUE io, VALUE w);
void rb_io_set_nonblock(rb_io_t *fptr);
/**
- * Returns the path for the given IO.
- *
- */
-VALUE rb_io_path(VALUE io);
-
-/**
* Returns an integer representing the numeric file descriptor for
* <em>io</em>.
*
@@ -758,12 +712,6 @@ VALUE rb_io_path(VALUE io);
int rb_io_descriptor(VALUE io);
/**
- * Get the mode of the IO.
- *
- */
-int rb_io_mode(VALUE io);
-
-/**
* This function breaks down the option hash that `IO#initialize` takes into
* components. This is an implementation detail of rb_io_extract_modeenc()
* today. People prefer that API instead.
@@ -964,9 +912,6 @@ VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout);
* }
* ```
*
- * On timeout, ::RUBY_Qfalse is returned. Unless you are specifically handling
- * the timeouts, you should typically raise ::rb_eIOTimeoutError in this case.
- *
* @param[in] error System errno.
* @param[in] io An IO object to wait.
* @param[in] events An integer set of interests.
@@ -975,19 +920,19 @@ VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout);
* @exception rb_eRangeError `timeout` is out of range.
* @exception rb_eSystemCallError `select(2)` failed for some reason.
* @retval RUBY_Qfalse Operation timed out.
- * @retval RUBY_Qnil Operation failed for some other reason (errno).
* @retval Otherwise Actual events reached.
*
+ * @internal
+ *
+ * This function to return ::RUBY_Qfalse on timeout could be unintended. It
+ * seems timeout feature has some rough edge.
*/
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout);
/**
* Blocks until the passed IO is ready for reading, if that makes sense for the
- * passed errno. This is a special case of rb_io_maybe_wait() that is
- * only concerned with reading and handles the timeout.
- *
- * If you do not want the default timeout handling, consider using
- * ::rb_io_maybe_wait directly.
+ * passed errno. This is a special case of rb_io_maybe_wait() that only
+ * concerns for reading.
*
* @param[in] error System errno.
* @param[in] io An IO object to wait.
@@ -995,18 +940,15 @@ VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout);
* @exception rb_eIOError `io` is not open.
* @exception rb_eRangeError `timeout` is out of range.
* @exception rb_eSystemCallError `select(2)` failed for some reason.
- * @exception rb_eIOTimeoutError The wait operation timed out.
+ * @retval 0 Operation timed out.
* @retval Otherwise Always returns ::RUBY_IO_READABLE.
*/
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout);
/**
* Blocks until the passed IO is ready for writing, if that makes sense for the
- * passed errno. This is a special case of rb_io_maybe_wait() that is
- * only concerned with writing, and handles the timeout.
- *
- * If you do not want the default timeout handling, consider using
- * ::rb_io_maybe_wait directly.
+ * passed errno. This is a special case of rb_io_maybe_wait() that only
+ * concernsfor writing.
*
* @param[in] error System errno.
* @param[in] io An IO object to wait.
@@ -1014,7 +956,7 @@ int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout);
* @exception rb_eIOError `io` is not open.
* @exception rb_eRangeError `timeout` is out of range.
* @exception rb_eSystemCallError `select(2)` failed for some reason.
- * @exception rb_eIOTimeoutError The wait operation timed out.
+ * @retval 0 Operation timed out.
* @retval Otherwise Always returns ::RUBY_IO_WRITABLE.
*/
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout);
diff --git a/include/ruby/io/buffer.h b/include/ruby/io/buffer.h
index e4d98bf051..e4b855d8e7 100644
--- a/include/ruby/io/buffer.h
+++ b/include/ruby/io/buffer.h
@@ -23,18 +23,10 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
#define RUBY_IO_BUFFER_VERSION 2
-// The `IO::Buffer` class.
RUBY_EXTERN VALUE rb_cIOBuffer;
-
-// The operating system page size.
RUBY_EXTERN size_t RUBY_IO_BUFFER_PAGE_SIZE;
-
-// The default buffer size, usually a (small) multiple of the page size.
-// Can be overridden by the RUBY_IO_BUFFER_DEFAULT_SIZE environment variable.
RUBY_EXTERN size_t RUBY_IO_BUFFER_DEFAULT_SIZE;
-// Represents the internal state of the buffer.
-// More than one flag can be set at a time.
enum rb_io_buffer_flags {
// The memory in the buffer is owned by someone else.
// More specifically, it means that someone else owns the buffer and we shouldn't try to resize it.
@@ -57,15 +49,10 @@ enum rb_io_buffer_flags {
RB_IO_BUFFER_PRIVATE = 64,
// The buffer is read-only and cannot be modified.
- RB_IO_BUFFER_READONLY = 128,
-
- // The buffer is backed by a file.
- RB_IO_BUFFER_FILE = 256,
+ RB_IO_BUFFER_READONLY = 128
};
-// Represents the endian of the data types.
enum rb_io_buffer_endian {
- // The least significant units are put first.
RB_IO_BUFFER_LITTLE_ENDIAN = 4,
RB_IO_BUFFER_BIG_ENDIAN = 8,
@@ -84,14 +71,9 @@ VALUE rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer
VALUE rb_io_buffer_lock(VALUE self);
VALUE rb_io_buffer_unlock(VALUE self);
int rb_io_buffer_try_unlock(VALUE self);
-
VALUE rb_io_buffer_free(VALUE self);
-VALUE rb_io_buffer_free_locked(VALUE self);
-// Access the internal buffer and flags. Validates the pointers.
-// The points may not remain valid if the source buffer is manipulated.
-// Consider using rb_io_buffer_lock if needed.
-enum rb_io_buffer_flags rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size);
+int rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size);
void rb_io_buffer_get_bytes_for_reading(VALUE self, const void **base, size_t *size);
void rb_io_buffer_get_bytes_for_writing(VALUE self, void **base, size_t *size);
diff --git a/include/ruby/memory_view.h b/include/ruby/memory_view.h
index 42309d5afc..1ddca2d46f 100644
--- a/include/ruby/memory_view.h
+++ b/include/ruby/memory_view.h
@@ -47,10 +47,10 @@ typedef struct {
char format;
/** :FIXME: what is a "native" size is unclear. */
- bool native_size_p;
+ unsigned native_size_p: 1;
/** Endian of the component */
- bool little_endian_p;
+ unsigned little_endian_p: 1;
/** The component's offset. */
size_t offset;
diff --git a/include/ruby/onigmo.h b/include/ruby/onigmo.h
index db290cd47a..8d7c601703 100644
--- a/include/ruby/onigmo.h
+++ b/include/ruby/onigmo.h
@@ -636,7 +636,6 @@ ONIG_EXTERN const OnigSyntaxType* OnigDefaultSyntax;
#define ONIGERR_PARSE_DEPTH_LIMIT_OVER -16
#define ONIGERR_DEFAULT_ENCODING_IS_NOT_SET -21
#define ONIGERR_SPECIFIED_ENCODING_CANT_CONVERT_TO_WIDE_CHAR -22
-#define ONIGERR_TIMEOUT -23
/* general error */
#define ONIGERR_INVALID_ARGUMENT -30
/* syntax error */
@@ -745,6 +744,8 @@ typedef struct {
typedef struct {
int lower;
int upper;
+ long base_num;
+ long inner_num;
} OnigRepeatRange;
typedef void (*OnigWarnFunc)(const char* s);
@@ -845,8 +846,6 @@ void onig_free(OnigRegex);
ONIG_EXTERN
void onig_free_body(OnigRegex);
ONIG_EXTERN
-int onig_reg_copy(OnigRegex* reg, OnigRegex orig_reg);
-ONIG_EXTERN
OnigPosition onig_scan(OnigRegex reg, const OnigUChar* str, const OnigUChar* end, OnigRegion* region, OnigOptionType option, int (*scan_callback)(OnigPosition, OnigPosition, OnigRegion*, void*), void* callback_arg);
ONIG_EXTERN
OnigPosition onig_search(OnigRegex, const OnigUChar* str, const OnigUChar* end, const OnigUChar* start, const OnigUChar* range, OnigRegion* region, OnigOptionType option);
diff --git a/include/ruby/random.h b/include/ruby/random.h
index f3df0d96fb..39bdb6f3e3 100644
--- a/include/ruby/random.h
+++ b/include/ruby/random.h
@@ -11,7 +11,7 @@
*
* This is a set of APIs to roll your own subclass of ::rb_cRandom. An
* illustrative example of such PRNG can be found at
- * `ext/-test-/random/loop.c`.
+ * `ext/-test-/ramdom/loop.c`.
*/
#include "ruby/ruby.h"
diff --git a/include/ruby/re.h b/include/ruby/re.h
index f86d6f26cf..3892d6e7f2 100644
--- a/include/ruby/re.h
+++ b/include/ruby/re.h
@@ -18,7 +18,6 @@
#include <stdio.h>
-#include "ruby/onigmo.h"
#include "ruby/regex.h"
#include "ruby/internal/core/rmatch.h"
#include "ruby/internal/dllexport.h"
@@ -127,30 +126,6 @@ VALUE rb_reg_quote(VALUE str);
regex_t *rb_reg_prepare_re(VALUE re, VALUE str);
/**
- * Runs a regular expression match using function `match`. Performs preparation,
- * error handling, and memory cleanup.
- *
- * @param[in] re Target regular expression.
- * @param[in] str What `re` is about to run on.
- * @param[in] match The function to run to match `str` against `re`.
- * @param[in] args Pointer to arguments to pass into `match`.
- * @param[out] regs Registers on a successful match.
- * @exception rb_eArgError `re` does not fit for `str`.
- * @exception rb_eEncCompatError `re` and `str` are incompatible.
- * @exception rb_eRegexpError `re` is malformed.
- * @return Match position on a successful match, `ONIG_MISMATCH` otherwise.
- *
- * @internal
- *
- * The type `regex_t *` is defined in `<ruby/onigmo.h>`, _and_
- * _conflicts_ with POSIX's `<regex.h>`. We can no longer save the situation
- * at this point. Just don't mix the two.
- */
-OnigPosition rb_reg_onig_match(VALUE re, VALUE str,
- OnigPosition (*match)(regex_t *reg, VALUE str, struct re_registers *regs, void *args),
- void *args, struct re_registers *regs);
-
-/**
* Duplicates a match data. This is roughly the same as `onig_region_copy()`,
* except it tries to GC when there is not enough memory.
*
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index 035f02c70b..444940ca3a 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -43,6 +43,7 @@
#include "ruby/internal/method.h"
#include "ruby/internal/module.h"
#include "ruby/internal/newobj.h"
+#include "ruby/internal/rgengc.h"
#include "ruby/internal/scan_args.h"
#include "ruby/internal/special_consts.h"
#include "ruby/internal/symbol.h"
@@ -97,10 +98,8 @@ VALUE rb_get_path(VALUE obj);
VALUE rb_get_path_no_checksafe(VALUE);
/**
- * This macro actually does the same thing as #FilePathValue now. The "String"
- * part indicates that this is for when a string is treated like a pathname,
- * rather than the actual pathname on the file systems. For examples:
- * `Dir.fnmatch?`, `File.join`, `File.basename`, etc.
+ * @deprecated This macro is an alias of #FilePathValue now. The part that did
+ * "String" was deleted. It remains here because of no harm.
*/
#define FilePathStringValue(v) ((v) = rb_get_path(v))
@@ -272,124 +271,6 @@ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 0)
*/
int ruby_vsnprintf(char *str, size_t n, char const *fmt, va_list ap);
-#include <errno.h>
-
-/**
- * @name Errno handling routines for userland threads
- * @note POSIX chapter 2 section 3 states that for each thread of a process,
- * the value of `errno` shall not be affected by function calls or
- * assignments to `errno` by other threads.
- *
- * Soooo this `#define errno` below seems like a noob mistake at first sight.
- * If you look at its actual implementation, the functions are just adding one
- * level of indirection. It doesn't make any sense sorry? But yes! @ko1 told
- * @shyouhei that this is inevitable.
- *
- * The ultimate reason is because Ruby now has N:M threads implemented.
- * Threads of that sort change their context in user land. A function can be
- * "transferred" between threads in middle of their executions. Let us for
- * instance consider:
- *
- * ```cxx
- * void foo()
- * {
- * auto i = errno;
- * close(0);
- * errno = i;
- * }
- * ```
- *
- * This function (if ran under our Ractor) could change its running thread at
- * the `close` function. But the two `errno` invocations are different! Look
- * how the source code above is compiled by clang 17 with `-O3` flag @ Linux:
- *
- * ```
- * foo(int): # @foo(int)
- * push rbp
- * push r14
- * push rbx
- * mov ebx, edi
- * call __errno_location@PLT
- * mov r14, rax
- * mov ebp, dword ptr [rax]
- * mov edi, ebx
- * call close@PLT
- * mov dword ptr [r14], ebp
- * pop rbx
- * pop r14
- * pop rbp
- * ret
- * ```
- *
- * Notice how `__errno_location@PLT` is `call`-ed only once. The compiler
- * assumes that the location of `errno` does not change during a function call.
- * Sadly this is no longer true for us. The `close@PLT` now changes threads,
- * which should also change where `errno` is stored.
- *
- * With the `#define errno` below the compilation result changes to this:
- *
- * ```
- * foo(int): # @foo(int)
- * push rbp
- * push rbx
- * push rax
- * mov ebx, edi
- * call rb_errno_ptr()@PLT
- * mov ebp, dword ptr [rax]
- * mov edi, ebx
- * call close@PLT
- * call rb_errno_ptr()@PLT
- * mov dword ptr [rax], ebp
- * add rsp, 8
- * pop rbx
- * pop rbp
- * ret
- * ```
- *
- * Which fixes the problem.
- */
-
-/**
- * Identical to system `errno`.
- *
- * @return The last set `errno` number.
- */
-int rb_errno(void);
-
-/**
- * Set the errno.
- *
- * @param err New `errno`.
- * @post `errno` is now set to `err`.
- */
-void rb_errno_set(int err);
-
-/**
- * The location of `errno`
- *
- * @return The (thread-specific) location of `errno`.
- */
-int *rb_errno_ptr(void);
-
-/**
- * Not sure if it is necessary for extension libraries but this is where the
- * "bare" errno is located.
- *
- * @return The location of `errno`.
- */
-static inline int *
-rb_orig_errno_ptr(void)
-{
- return &errno;
-}
-
-#define rb_orig_errno errno /**< System-provided original `errno`. */
-#undef errno
-#define errno (*rb_errno_ptr()) /**< Ractor-aware version of `errno`. */
-
-/** @} */
-
-
/** @cond INTERNAL_MACRO */
#if RBIMPL_HAS_WARNING("-Wgnu-zero-variadic-macro-arguments")
# /* Skip it; clang -pedantic doesn't like the following */
diff --git a/include/ruby/thread.h b/include/ruby/thread.h
index 337f477fd0..0b5b1ca0f3 100644
--- a/include/ruby/thread.h
+++ b/include/ruby/thread.h
@@ -190,59 +190,14 @@ void *rb_nogvl(void *(*func)(void *), void *data1,
*/
#define RUBY_CALL_WO_GVL_FLAG_SKIP_CHECK_INTS_
-/**
- * Declare the current Ruby thread should acquire a dedicated
- * native thread on M:N thread scheduler.
- *
- * If a C extension (or a library which the extension relies on) should
- * keep to run on a native thread (e.g. using thread-local-storage),
- * this function allocates a dedicated native thread for the thread.
- *
- * @return `false` if the thread already running on a dedicated native
- * thread. Otherwise `true`.
- */
-bool rb_thread_lock_native_thread(void);
-
-/**
- * Triggered when a new thread is started.
- *
- * @note The callback will be called *without* the GVL held.
- */
-#define RUBY_INTERNAL_THREAD_EVENT_STARTED 1 << 0
-
-/**
-* Triggered when a thread attempt to acquire the GVL.
-*
-* @note The callback will be called *without* the GVL held.
-*/
+#define RUBY_INTERNAL_THREAD_EVENT_STARTED 1 << 0 /** thread started */
#define RUBY_INTERNAL_THREAD_EVENT_READY 1 << 1 /** acquiring GVL */
-
-/**
- * Triggered when a thread successfully acquired the GVL.
- *
- * @note The callback will be called *with* the GVL held.
- */
#define RUBY_INTERNAL_THREAD_EVENT_RESUMED 1 << 2 /** acquired GVL */
-
-/**
- * Triggered when a thread released the GVL.
- *
- * @note The callback will be called *without* the GVL held.
- */
#define RUBY_INTERNAL_THREAD_EVENT_SUSPENDED 1 << 3 /** released GVL */
-
-/**
- * Triggered when a thread exits.
- *
- * @note The callback will be called *without* the GVL held.
- */
#define RUBY_INTERNAL_THREAD_EVENT_EXITED 1 << 4 /** thread terminated */
-
#define RUBY_INTERNAL_THREAD_EVENT_MASK 0xff /** All Thread events */
-typedef struct rb_internal_thread_event_data {
- VALUE thread;
-} rb_internal_thread_event_data_t;
+typedef void rb_internal_thread_event_data_t; // for future extension.
typedef void (*rb_internal_thread_event_callback)(rb_event_flag_t event,
const rb_internal_thread_event_data_t *event_data,
@@ -256,12 +211,7 @@ typedef struct rb_internal_thread_event_hook rb_internal_thread_event_hook_t;
* @param[in] events A set of events that `func` should run.
* @param[in] data Passed as-is to `func`.
* @return An opaque pointer to the hook, to unregister it later.
- * @note This functionality is a noop on Windows and WebAssembly.
- * @note The callback will be called without the GVL held, except for the
- * RESUMED event.
- * @note Callbacks are not guaranteed to be executed on the native threads
- * that corresponds to the Ruby thread. To identify which Ruby thread
- * the event refers to, you must use `event_data->thread`.
+ * @note This functionality is a noop on Windows.
* @warning This function MUST not be called from a thread event callback.
*/
rb_internal_thread_event_hook_t *rb_internal_thread_add_event_hook(
@@ -273,53 +223,13 @@ rb_internal_thread_event_hook_t *rb_internal_thread_add_event_hook(
* Unregister the passed hook.
*
* @param[in] hook. The hook to unregister.
- * @return Whether the hook was found and unregistered.
- * @note This functionality is a noop on Windows and WebAssembly.
+ * @return Wether the hook was found and unregistered.
+ * @note This functionality is a noop on Windows.
* @warning This function MUST not be called from a thread event callback.
*/
bool rb_internal_thread_remove_event_hook(
rb_internal_thread_event_hook_t * hook);
-
-typedef int rb_internal_thread_specific_key_t;
-#define RB_INTERNAL_THREAD_SPECIFIC_KEY_MAX 8
-/**
- * Create a key to store thread specific data.
- *
- * These APIs are designed for tools using
- * rb_internal_thread_event_hook APIs.
- *
- * Note that only `RB_INTERNAL_THREAD_SPECIFIC_KEY_MAX` keys
- * can be created. raises `ThreadError` if exceeded.
- *
- * Usage:
- * // at initialize time:
- * int tool_key; // gvar
- * Init_tool() {
- * tool_key = rb_internal_thread_specific_key_create();
- * }
- *
- * // at any timing:
- * rb_internal_thread_specific_set(thread, tool_key, per_thread_data);
- * ...
- * per_thread_data = rb_internal_thread_specific_get(thread, tool_key);
- */
-rb_internal_thread_specific_key_t rb_internal_thread_specific_key_create(void);
-
-/**
- * Get thread and tool specific data.
- *
- * This function is async signal safe and thread safe.
- */
-void *rb_internal_thread_specific_get(VALUE thread_val, rb_internal_thread_specific_key_t key);
-
-/**
- * Set thread and tool specific data.
- *
- * This function is async signal safe and thread safe.
- */
-void rb_internal_thread_specific_set(VALUE thread_val, rb_internal_thread_specific_key_t key, void *data);
-
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RUBY_THREAD_H */
diff --git a/include/ruby/thread_native.h b/include/ruby/thread_native.h
index 8217a67514..c23b15e133 100644
--- a/include/ruby/thread_native.h
+++ b/include/ruby/thread_native.h
@@ -28,11 +28,6 @@ typedef union rb_thread_lock_union {
CRITICAL_SECTION crit;
} rb_nativethread_lock_t;
-struct rb_thread_cond_struct {
- struct cond_event_entry *next;
- struct cond_event_entry *prev;
-};
-
typedef struct rb_thread_cond_struct rb_nativethread_cond_t;
#elif defined(HAVE_PTHREAD_H)
diff --git a/include/ruby/util.h b/include/ruby/util.h
index 12e69c4b80..e8727a3200 100644
--- a/include/ruby/util.h
+++ b/include/ruby/util.h
@@ -33,20 +33,9 @@
RBIMPL_SYMBOL_EXPORT_BEGIN()
-/** an approximation of ceil(n * log10(2)), up to 1,048,576 (1<<20)
- * without overflow within 32-bit calculation
- */
+/** an approximation of ceil(n * log10(2)), up to 65536 at least */
#define DECIMAL_SIZE_OF_BITS(n) (((n) * 3010 + 9998) / 9999)
-/** an approximation of decimal representation size for n-bytes */
-#define DECIMAL_SIZE_OF_BYTES(n) DECIMAL_SIZE_OF_BITS((n) * CHAR_BIT)
-
-/**
- * An approximation of decimal representation size. `expr` may be a
- * type name
- */
-#define DECIMAL_SIZE_OF(expr) DECIMAL_SIZE_OF_BYTES(sizeof(expr))
-
/**
* Character to number mapping like `'a'` -> `10`, `'b'` -> `11` etc. For
* punctuation etc., the value is -1. "36" terminology comes from the fact
diff --git a/include/ruby/version.h b/include/ruby/version.h
index e9113177de..18b3abc8d7 100644
--- a/include/ruby/version.h
+++ b/include/ruby/version.h
@@ -67,7 +67,7 @@
* Minor version. As of writing this version changes annually. Greater
* version doesn't mean "better"; they just mean years passed.
*/
-#define RUBY_API_VERSION_MINOR 4
+#define RUBY_API_VERSION_MINOR 2
/**
* Teeny version. This digit is kind of reserved these days. Kept 0 for the
diff --git a/include/ruby/vm.h b/include/ruby/vm.h
index 8779780952..3458c28be7 100644
--- a/include/ruby/vm.h
+++ b/include/ruby/vm.h
@@ -49,13 +49,6 @@ int ruby_vm_destruct(ruby_vm_t *vm);
*/
void ruby_vm_at_exit(void(*func)(ruby_vm_t *));
-/**
- * Returns whether the Ruby VM will free all memory at shutdown.
- *
- * @return true if free-at-exit is enabled, false otherwise.
- */
-bool ruby_free_at_exit_p(void);
-
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RUBY_VM_H */
diff --git a/include/ruby/win32.h b/include/ruby/win32.h
index 27a3467606..18de3a17d8 100644
--- a/include/ruby/win32.h
+++ b/include/ruby/win32.h
@@ -35,7 +35,6 @@ extern "C++" { /* template without extern "C++" */
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
-#include <mswsock.h>
#if !defined(_MSC_VER) || _MSC_VER >= 1400
#include <iphlpapi.h>
#endif
@@ -126,8 +125,15 @@ typedef unsigned int uintptr_t;
#define O_SHARE_DELETE 0x20000000 /* for rb_w32_open(), rb_w32_wopen() */
typedef int clockid_t;
+#if defined(__MINGW32__)
+#undef CLOCK_PROCESS_CPUTIME_ID
+#undef CLOCK_THREAD_CPUTIME_ID
+#undef CLOCK_REALTIME_COARSE
+#endif
+#if defined(HAVE_CLOCK_GETTIME) && !defined(CLOCK_REALTIME)
#define CLOCK_REALTIME 0
#define CLOCK_MONOTONIC 1
+#endif
#undef utime
#undef lseek
@@ -148,10 +154,8 @@ typedef int clockid_t;
#define open rb_w32_uopen
#define close(h) rb_w32_close(h)
#define fclose(f) rb_w32_fclose(f)
-#define read(f, b, s) rb_w32_read(f, b, s)
-#define write(f, b, s) rb_w32_write(f, b, s)
-#define pread(f, b, s, o) rb_w32_pread(f, b, s, o)
-#define pwrite(f, b, s, o) rb_w32_pwrite(f, b, s, o)
+#define read(f, b, s) rb_w32_read(f, b, s)
+#define write(f, b, s) rb_w32_write(f, b, s)
#define getpid() rb_w32_getpid()
#undef HAVE_GETPPID
#define HAVE_GETPPID 1
@@ -719,8 +723,6 @@ int rb_w32_fclose(FILE*);
int rb_w32_pipe(int[2]);
ssize_t rb_w32_read(int, void *, size_t);
ssize_t rb_w32_write(int, const void *, size_t);
-ssize_t rb_w32_pread(int, void *, size_t, rb_off_t offset);
-ssize_t rb_w32_pwrite(int, const void *, size_t, rb_off_t offset);
rb_off_t rb_w32_lseek(int, rb_off_t, int);
int rb_w32_uutime(const char *, const struct utimbuf *);
int rb_w32_uutimes(const char *, const struct timeval *);
diff --git a/inits.c b/inits.c
index ef0805d2ee..e809b56cc9 100644
--- a/inits.c
+++ b/inits.c
@@ -22,6 +22,11 @@ rb_call_inits(void)
{
CALL(default_shapes);
CALL(Thread_Mutex);
+#if USE_TRANSIENT_HEAP
+ CALL(TransientHeap);
+#endif
+ CALL(vm_postponed_job);
+ CALL(Method);
CALL(RandomSeedCore);
CALL(encodings);
CALL(sym);
@@ -51,18 +56,17 @@ rb_call_inits(void)
CALL(Dir);
CALL(Time);
CALL(Random);
+ CALL(signal);
CALL(load);
CALL(Proc);
CALL(Binding);
CALL(Math);
CALL(GC);
- CALL(WeakMap);
CALL(Enumerator);
CALL(Ractor);
CALL(VM);
CALL(ISeq);
CALL(Thread);
- CALL(signal);
CALL(Fiber_Scheduler);
CALL(process);
CALL(Cont);
@@ -73,8 +77,8 @@ rb_call_inits(void)
CALL(vm_trace);
CALL(vm_stack_canary);
CALL(ast);
+ CALL(gc_stress);
CALL(shape);
- CALL(Prism);
// enable builtin loading
CALL(builtin);
@@ -94,7 +98,6 @@ rb_call_builtin_inits(void)
BUILTIN(pack);
BUILTIN(warning);
BUILTIN(array);
- BUILTIN(hash);
BUILTIN(kernel);
BUILTIN(symbol);
BUILTIN(timev);
@@ -102,9 +105,9 @@ rb_call_builtin_inits(void)
BUILTIN(yjit);
BUILTIN(nilclass);
BUILTIN(marshal);
-#if USE_RJIT
- BUILTIN(rjit_c);
- BUILTIN(rjit);
+#if USE_MJIT
+ BUILTIN(mjit);
+ BUILTIN(mjit_c);
#endif
Init_builtin_prelude();
}
diff --git a/insns.def b/insns.def
index 99ea95f584..9f5ee7095a 100644
--- a/insns.def
+++ b/insns.def
@@ -222,7 +222,7 @@ setinstancevariable
(ID id, IVC ic)
(VALUE val)
()
-// attr bool leaf = false; /* has rb_check_frozen() */
+// attr bool leaf = false; /* has rb_check_frozen_internal() */
{
vm_setinstancevariable(GET_ISEQ(), GET_SELF(), id, val, ic);
}
@@ -260,7 +260,20 @@ opt_getconstant_path
(VALUE val)
// attr bool leaf = false; /* may autoload or raise */
{
- val = rb_vm_opt_getconstant_path(ec, GET_CFP(), ic);
+ const ID *segments = ic->segments;
+ struct iseq_inline_constant_cache_entry *ice = ic->entry;
+ if (ice && vm_ic_hit_p(ice, GET_EP())) {
+ val = ice->value;
+
+ VM_ASSERT(val == vm_get_ev_const_chain(ec, segments));
+ } else {
+ ruby_vm_constant_cache_misses++;
+ val = vm_get_ev_const_chain(ec, segments);
+ vm_ic_track_const_chain(GET_CFP(), ic, segments);
+ // Because leaf=false, we need to undo the PC increment to get the address to this instruction
+ // INSN_ATTR(width) == 2
+ vm_ic_update(GET_ISEQ(), ic, val, GET_EP(), GET_PC() - 2);
+ }
}
/* Get constant variable id. If klass is Qnil and allow_nil is Qtrue, constants
@@ -375,17 +388,7 @@ putstring
()
(VALUE val)
{
- val = rb_ec_str_resurrect(ec, str, false);
-}
-
-/* put chilled string val. string will be copied but frozen in the future. */
-DEFINE_INSN
-putchilledstring
-(VALUE str)
-()
-(VALUE val)
-{
- val = rb_ec_str_resurrect(ec, str, true);
+ val = rb_ec_str_resurrect(ec, str);
}
/* put concatenate strings */
@@ -452,17 +455,23 @@ newarray
val = rb_ec_ary_new_from_values(ec, num, STACK_ADDR_FROM_TOP(num));
}
-/* push hash onto array unless the hash is empty (as empty keyword
- splats should be ignored).
+/* put new array initialized with num values on the stack. There
+ should be at least one element on the stack, and the top element
+ should be a hash. If the top element is empty, it is not
+ included in the array.
*/
DEFINE_INSN
-pushtoarraykwsplat
-()
-(VALUE ary, VALUE hash)
-(VALUE ary)
+newarraykwsplat
+(rb_num_t num)
+(...)
+(VALUE val)
+// attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
{
- if (!RHASH_EMPTY_P(hash)) {
- rb_ary_push(ary, hash);
+ if (RHASH_EMPTY_P(*STACK_ADDR_FROM_TOP(1))) {
+ val = rb_ary_new4(num-1, STACK_ADDR_FROM_TOP(num));
+ }
+ else {
+ val = rb_ary_new4(num, STACK_ADDR_FROM_TOP(num));
}
}
@@ -502,16 +511,13 @@ expandarray
(rb_num_t num, rb_num_t flag)
(..., VALUE ary)
(...)
-// attr bool handles_sp = true;
// attr bool leaf = false; /* has rb_check_array_type() */
// attr rb_snum_t sp_inc = (rb_snum_t)num - 1 + (flag & 1 ? 1 : 0);
{
- vm_expandarray(GET_CFP(), ary, num, (int)flag);
+ vm_expandarray(GET_SP(), ary, num, (int)flag);
}
-/* concat two arrays, without modifying first array.
- * attempts to convert both objects to arrays using to_a.
- */
+/* concat two arrays */
DEFINE_INSN
concatarray
()
@@ -522,32 +528,6 @@ concatarray
ary = vm_concat_array(ary1, ary2);
}
-/* concat second array to first array.
- * first argument must already be an array.
- * attempts to convert second object to array using to_a.
- */
-DEFINE_INSN
-concattoarray
-()
-(VALUE ary1, VALUE ary2)
-(VALUE ary)
-// attr bool leaf = false; /* has rb_check_array_type() */
-{
- ary = vm_concat_to_array(ary1, ary2);
-}
-
-/* push given number of objects to array directly before. */
-DEFINE_INSN
-pushtoarray
-(rb_num_t num)
-(...)
-(VALUE val)
-// attr rb_snum_t sp_inc = -(rb_snum_t)num;
-{
- const VALUE *objp = STACK_ADDR_FROM_TOP(num);
- val = rb_ary_cat(*(objp-1), objp, num);
-}
-
/* call to_a on array ary to splat */
DEFINE_INSN
splatarray
@@ -559,22 +539,6 @@ splatarray
obj = vm_splat_array(flag, ary);
}
-/* call to_hash on hash to keyword splat before converting block */
-DEFINE_INSN
-splatkw
-()
-(VALUE hash, VALUE block)
-(VALUE obj, VALUE block)
-// attr bool leaf = false; /* has rb_to_hash_type() */
-{
- if (NIL_P(hash)) {
- obj = Qnil;
- }
- else {
- obj = rb_to_hash_type(hash);
- }
-}
-
/* put new Hash from n elements. n must be an even number. */
DEFINE_INSN
newhash
@@ -737,20 +701,6 @@ defined
}
}
-/* defined?(@foo) */
-DEFINE_INSN
-definedivar
-(ID id, IVC ic, VALUE pushval)
-()
-(VALUE val)
-// attr bool leaf = false;
-{
- val = Qnil;
- if (!UNDEF_P(vm_getivar(GET_SELF(), id, GET_ISEQ(), ic, NULL, FALSE, Qundef))) {
- val = pushval;
- }
-}
-
/* check `target' matches `pattern'.
`flag & VM_CHECKMATCH_TYPE_MASK' describe how to check pattern.
VM_CHECKMATCH_TYPE_WHEN: ignore target and check pattern is truthy.
@@ -849,36 +799,8 @@ send
{
VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, false);
val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
- JIT_EXEC(ec, val);
-
- if (UNDEF_P(val)) {
- RESTORE_REGS();
- NEXT_INSN();
- }
-}
-
-/* invoke forward method. */
-DEFINE_INSN
-sendforward
-(CALL_DATA cd, ISEQ blockiseq)
-(...)
-(VALUE val)
-// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
-// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
-{
- struct rb_forwarding_call_data adjusted_cd;
- struct rb_callinfo adjusted_ci;
-
- VALUE bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), cd, blockiseq, 0, &adjusted_cd, &adjusted_ci);
-
- val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_method);
- JIT_EXEC(ec, val);
- if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) {
- RB_OBJ_WRITE(GET_ISEQ(), &cd->cc, adjusted_cd.cd.cc);
- }
-
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
RESTORE_REGS();
NEXT_INSN();
}
@@ -896,9 +818,8 @@ opt_send_without_block
{
VALUE bh = VM_BLOCK_HANDLER_NONE;
val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_method);
- JIT_EXEC(ec, val);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
RESTORE_REGS();
NEXT_INSN();
}
@@ -914,37 +835,7 @@ objtostring
{
val = vm_objtostring(GET_ISEQ(), recv, cd);
- if (UNDEF_P(val)) {
- CALL_SIMPLE_METHOD();
- }
-}
-
-DEFINE_INSN
-opt_ary_freeze
-(VALUE ary, CALL_DATA cd)
-()
-(VALUE val)
-{
- val = vm_opt_ary_freeze(ary, BOP_FREEZE, idFreeze);
-
- if (UNDEF_P(val)) {
- RUBY_DTRACE_CREATE_HOOK(ARRAY, RARRAY_LEN(ary));
- PUSH(rb_ary_resurrect(ary));
- CALL_SIMPLE_METHOD();
- }
-}
-
-DEFINE_INSN
-opt_hash_freeze
-(VALUE hash, CALL_DATA cd)
-()
-(VALUE val)
-{
- val = vm_opt_hash_freeze(hash, BOP_FREEZE, idFreeze);
-
- if (UNDEF_P(val)) {
- RUBY_DTRACE_CREATE_HOOK(HASH, RHASH_SIZE(hash) << 1);
- PUSH(rb_hash_resurrect(hash));
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -957,7 +848,7 @@ opt_str_freeze
{
val = vm_opt_str_freeze(str, BOP_FREEZE, idFreeze);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
PUSH(rb_str_resurrect(str));
CALL_SIMPLE_METHOD();
}
@@ -972,7 +863,7 @@ opt_nil_p
{
val = vm_opt_nil_p(GET_ISEQ(), cd, recv);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -985,15 +876,15 @@ opt_str_uminus
{
val = vm_opt_str_freeze(str, BOP_UMINUS, idUMinus);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
PUSH(rb_str_resurrect(str));
CALL_SIMPLE_METHOD();
}
}
DEFINE_INSN
-opt_newarray_send
-(rb_num_t num, rb_num_t method)
+opt_newarray_max
+(rb_num_t num)
(...)
(VALUE val)
/* This instruction typically has no funcalls. But it compares array
@@ -1002,70 +893,35 @@ opt_newarray_send
* cannot but mark it being not leaf. */
// attr bool leaf = false; /* has rb_funcall() */
// attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
-// attr rb_snum_t comptime_sp_inc = 1 - (rb_snum_t)num;
-{
- switch(method) {
- case VM_OPT_NEWARRAY_SEND_HASH:
- val = vm_opt_newarray_hash(ec, num, STACK_ADDR_FROM_TOP(num));
- break;
- case VM_OPT_NEWARRAY_SEND_MIN:
- val = vm_opt_newarray_min(ec, num, STACK_ADDR_FROM_TOP(num));
- break;
- case VM_OPT_NEWARRAY_SEND_MAX:
- val = vm_opt_newarray_max(ec, num, STACK_ADDR_FROM_TOP(num));
- break;
- case VM_OPT_NEWARRAY_SEND_PACK:
- val = vm_opt_newarray_pack_buffer(ec, (long)num-1, STACK_ADDR_FROM_TOP(num), TOPN(0), Qundef);
- break;
- case VM_OPT_NEWARRAY_SEND_PACK_BUFFER:
- val = vm_opt_newarray_pack_buffer(ec, (long)num-2, STACK_ADDR_FROM_TOP(num), TOPN(1), TOPN(0));
- break;
- default:
- rb_bug("unreachable");
- }
+{
+ val = vm_opt_newarray_max(ec, num, STACK_ADDR_FROM_TOP(num));
}
-/* super(args) # args.size => num */
DEFINE_INSN
-invokesuper
-(CALL_DATA cd, ISEQ blockiseq)
+opt_newarray_min
+(rb_num_t num)
(...)
(VALUE val)
-// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
-// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
+/* Same discussion as opt_newarray_max. */
+// attr bool leaf = false; /* has rb_funcall() */
+// attr rb_snum_t sp_inc = 1 - (rb_snum_t)num;
{
- VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, true);
- val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_super);
- JIT_EXEC(ec, val);
-
- if (UNDEF_P(val)) {
- RESTORE_REGS();
- NEXT_INSN();
- }
+ val = vm_opt_newarray_min(ec, num, STACK_ADDR_FROM_TOP(num));
}
/* super(args) # args.size => num */
DEFINE_INSN
-invokesuperforward
+invokesuper
(CALL_DATA cd, ISEQ blockiseq)
(...)
(VALUE val)
// attr rb_snum_t sp_inc = sp_inc_of_sendish(cd->ci);
// attr rb_snum_t comptime_sp_inc = sp_inc_of_sendish(ci);
{
- struct rb_forwarding_call_data adjusted_cd;
- struct rb_callinfo adjusted_ci;
-
- VALUE bh = vm_caller_setup_fwd_args(GET_EC(), GET_CFP(), cd, blockiseq, 1, &adjusted_cd, &adjusted_ci);
-
- val = vm_sendish(ec, GET_CFP(), &adjusted_cd.cd, bh, mexp_search_super);
- JIT_EXEC(ec, val);
-
- if (cd->cc != adjusted_cd.cd.cc && vm_cc_markable(adjusted_cd.cd.cc)) {
- RB_OBJ_WRITE(GET_ISEQ(), &cd->cc, adjusted_cd.cd.cc);
- }
+ VALUE bh = vm_caller_setup_arg_block(ec, GET_CFP(), cd->ci, blockiseq, true);
+ val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_super);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
RESTORE_REGS();
NEXT_INSN();
}
@@ -1083,9 +939,8 @@ invokeblock
{
VALUE bh = VM_BLOCK_HANDLER_NONE;
val = vm_sendish(ec, GET_CFP(), cd, bh, mexp_search_invokeblock);
- JIT_EXEC(ec, val);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
RESTORE_REGS();
NEXT_INSN();
}
@@ -1243,7 +1098,7 @@ opt_plus
{
val = vm_opt_plus(recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1257,7 +1112,7 @@ opt_minus
{
val = vm_opt_minus(recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1271,7 +1126,7 @@ opt_mult
{
val = vm_opt_mult(recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1288,7 +1143,7 @@ opt_div
{
val = vm_opt_div(recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1304,7 +1159,7 @@ opt_mod
{
val = vm_opt_mod(recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1318,7 +1173,7 @@ opt_eq
{
val = opt_equality(GET_ISEQ(), recv, obj, cd);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1332,7 +1187,7 @@ opt_neq
{
val = vm_opt_neq(GET_ISEQ(), cd, cd_eq, recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1346,7 +1201,7 @@ opt_lt
{
val = vm_opt_lt(recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1360,7 +1215,7 @@ opt_le
{
val = vm_opt_le(recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1374,7 +1229,7 @@ opt_gt
{
val = vm_opt_gt(recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1388,7 +1243,7 @@ opt_ge
{
val = vm_opt_ge(recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1406,7 +1261,7 @@ opt_ltlt
{
val = vm_opt_ltlt(recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1420,7 +1275,7 @@ opt_and
{
val = vm_opt_and(recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1434,7 +1289,7 @@ opt_or
{
val = vm_opt_or(recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1453,7 +1308,7 @@ opt_aref
{
val = vm_opt_aref(recv, obj);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1470,7 +1325,7 @@ opt_aset
{
val = vm_opt_aset(recv, obj, set);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1486,12 +1341,14 @@ opt_aset_with
{
VALUE tmp = vm_opt_aset_with(recv, key, val);
- if (!UNDEF_P(tmp)) {
+ if (tmp != Qundef) {
val = tmp;
}
else {
+#ifndef MJIT_HEADER
TOPN(0) = rb_str_resurrect(key);
PUSH(val);
+#endif
CALL_SIMPLE_METHOD();
}
}
@@ -1507,8 +1364,10 @@ opt_aref_with
{
val = vm_opt_aref_with(recv, key);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
+#ifndef MJIT_HEADER
PUSH(rb_str_resurrect(key));
+#endif
CALL_SIMPLE_METHOD();
}
}
@@ -1522,7 +1381,7 @@ opt_length
{
val = vm_opt_length(recv, BOP_LENGTH);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1536,7 +1395,7 @@ opt_size
{
val = vm_opt_length(recv, BOP_SIZE);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1550,7 +1409,7 @@ opt_empty_p
{
val = vm_opt_empty_p(recv);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1564,7 +1423,7 @@ opt_succ
{
val = vm_opt_succ(recv);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1578,7 +1437,7 @@ opt_not
{
val = vm_opt_not(GET_ISEQ(), cd, recv);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
@@ -1593,11 +1452,32 @@ opt_regexpmatch2
{
val = vm_opt_regexpmatch2(obj2, obj1);
- if (UNDEF_P(val)) {
+ if (val == Qundef) {
CALL_SIMPLE_METHOD();
}
}
+/* call native compiled method */
+DEFINE_INSN_IF(SUPPORT_CALL_C_FUNCTION)
+opt_call_c_function
+(rb_insn_func_t funcptr)
+()
+()
+// attr bool leaf = false; /* anything can happen inside */
+// attr bool handles_sp = true;
+{
+ reg_cfp = (funcptr)(ec, reg_cfp);
+
+ if (reg_cfp == 0) {
+ VALUE err = ec->errinfo;
+ ec->errinfo = Qnil;
+ THROW_EXCEPTION(err);
+ }
+
+ RESTORE_REGS();
+ NEXT_INSN();
+}
+
/* call specific function with args */
DEFINE_INSN
invokebuiltin
diff --git a/internal.h b/internal.h
index 4fb99d1c08..b63af50616 100644
--- a/internal.h
+++ b/internal.h
@@ -40,6 +40,11 @@
#undef RClass
#undef RCLASS_SUPER
+/* internal/gc.h */
+#undef NEWOBJ_OF
+#undef RB_NEWOBJ_OF
+#undef RB_OBJ_WRITE
+
/* internal/hash.h */
#undef RHASH_IFNONE
#undef RHASH_SIZE
diff --git a/internal/array.h b/internal/array.h
index 398676df4a..a0d16dec3f 100644
--- a/internal/array.h
+++ b/internal/array.h
@@ -23,7 +23,6 @@
#define RARRAY_PTR_IN_USE_FLAG FL_USER14
/* array.c */
-VALUE rb_ary_hash_values(long len, const VALUE *elements);
VALUE rb_ary_last(int, const VALUE *, VALUE);
void rb_ary_set_len(VALUE, long);
void rb_ary_delete_same(VALUE, VALUE);
@@ -37,11 +36,13 @@ size_t rb_ary_size_as_embedded(VALUE ary);
void rb_ary_make_embedded(VALUE ary);
bool rb_ary_embeddable_p(VALUE ary);
VALUE rb_ary_diff(VALUE ary1, VALUE ary2);
-RUBY_EXTERN VALUE rb_cArray_empty_frozen;
static inline VALUE rb_ary_entry_internal(VALUE ary, long offset);
static inline bool ARY_PTR_USING_P(VALUE ary);
+static inline void RARY_TRANSIENT_SET(VALUE ary);
+static inline void RARY_TRANSIENT_UNSET(VALUE ary);
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_ary_tmp_new_from_values(VALUE, long, const VALUE *);
VALUE rb_check_to_array(VALUE ary);
VALUE rb_ary_behead(VALUE, long);
@@ -49,13 +50,14 @@ VALUE rb_ary_aref1(VALUE ary, VALUE i);
struct rb_execution_context_struct;
VALUE rb_ec_ary_new_from_values(struct rb_execution_context_struct *ec, long n, const VALUE *elts);
+MJIT_SYMBOL_EXPORT_END
// YJIT needs this function to never allocate and never raise
static inline VALUE
rb_ary_entry_internal(VALUE ary, long offset)
{
long len = RARRAY_LEN(ary);
- const VALUE *ptr = RARRAY_CONST_PTR(ary);
+ const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary);
if (len == 0) return Qnil;
if (offset < 0) {
offset += len;
@@ -117,6 +119,22 @@ ARY_SHARED_ROOT_REFCNT(VALUE ary)
return RARRAY(ary)->as.heap.aux.capa;
}
+static inline void
+RARY_TRANSIENT_SET(VALUE ary)
+{
+#if USE_TRANSIENT_HEAP
+ FL_SET_RAW(ary, RARRAY_TRANSIENT_FLAG);
+#endif
+}
+
+static inline void
+RARY_TRANSIENT_UNSET(VALUE ary)
+{
+#if USE_TRANSIENT_HEAP
+ FL_UNSET_RAW(ary, RARRAY_TRANSIENT_FLAG);
+#endif
+}
+
#undef rb_ary_new_from_args
#if RBIMPL_HAS_WARNING("-Wgnu-zero-variadic-macro-arguments")
# /* Skip it; clang -pedantic doesn't like the following */
@@ -137,16 +155,9 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline VALUE
RARRAY_AREF(VALUE ary, long i)
{
- VALUE val;
RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY);
- RBIMPL_WARNING_PUSH();
-#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 13
- RBIMPL_WARNING_IGNORED(-Warray-bounds);
-#endif
- val = RARRAY_CONST_PTR(ary)[i];
- RBIMPL_WARNING_POP();
- return val;
+ return RARRAY_CONST_PTR_TRANSIENT(ary)[i];
}
#endif /* INTERNAL_ARRAY_H */
diff --git a/internal/basic_operators.h b/internal/basic_operators.h
index 4732a65403..2cd9f50073 100644
--- a/internal/basic_operators.h
+++ b/internal/basic_operators.h
@@ -31,18 +31,18 @@ enum ruby_basic_operators {
BOP_UMINUS,
BOP_MAX,
BOP_MIN,
- BOP_HASH,
BOP_CALL,
BOP_AND,
BOP_OR,
BOP_CMP,
BOP_DEFAULT,
- BOP_PACK,
BOP_LAST_
};
+MJIT_SYMBOL_EXPORT_BEGIN
RUBY_EXTERN short ruby_vm_redefined_flag[BOP_LAST_];
+MJIT_SYMBOL_EXPORT_END
/* optimize insn */
#define INTEGER_REDEFINED_OP_FLAG (1 << 0)
diff --git a/internal/bignum.h b/internal/bignum.h
index db8d3aee83..5cd35ede8a 100644
--- a/internal/bignum.h
+++ b/internal/bignum.h
@@ -163,9 +163,11 @@ VALUE rb_str2big_gmp(VALUE arg, int base, int badcheck);
VALUE rb_int_parse_cstr(const char *str, ssize_t len, char **endp, size_t *ndigits, int base, int flags);
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
#if defined(HAVE_INT128_T)
VALUE rb_int128t2big(int128_t n);
#endif
+MJIT_SYMBOL_EXPORT_END
/* sign: positive:1, negative:0 */
static inline bool
diff --git a/internal/bits.h b/internal/bits.h
index 1fe98fa430..2602ff7a31 100644
--- a/internal/bits.h
+++ b/internal/bits.h
@@ -34,7 +34,8 @@
# include <stdlib.h> /* for _byteswap_uint64 */
#endif
-#if defined(HAVE_X86INTRIN_H)
+#if defined(HAVE_X86INTRIN_H) && ! defined(MJIT_HEADER)
+# /* Rule out MJIT_HEADER, which does not interface well with <immintrin.h> */
# include <x86intrin.h> /* for _lzcnt_u64 */
#elif MSC_VERSION_SINCE(1310)
# include <intrin.h> /* for the following intrinsics */
@@ -118,16 +119,12 @@
MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
#endif
-#if defined(MUL_OVERFLOW_P) && defined(USE___BUILTIN_MUL_OVERFLOW_LONG_LONG)
-# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_P(a, b)
-#else
-# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX)
-#endif
-
#ifdef MUL_OVERFLOW_P
+# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_P(a, b)
# define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_P(a, b)
# define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_P(a, b)
#else
+# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX)
# define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
# define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX)
#endif
@@ -238,7 +235,7 @@ nlz_int32(uint32_t x)
* safety. */
return (unsigned int)__lzcnt(x);
-#elif defined(__x86_64__) && defined(__LZCNT__)
+#elif defined(__x86_64__) && defined(__LZCNT__) && ! defined(MJIT_HEADER)
return (unsigned int)_lzcnt_u32(x);
#elif MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
@@ -267,7 +264,7 @@ nlz_int64(uint64_t x)
#if defined(_MSC_VER) && defined(__AVX2__)
return (unsigned int)__lzcnt64(x);
-#elif defined(__x86_64__) && defined(__LZCNT__)
+#elif defined(__x86_64__) && defined(__LZCNT__) && ! defined(MJIT_HEADER)
return (unsigned int)_lzcnt_u64(x);
#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
@@ -398,9 +395,9 @@ rb_popcount32(uint32_t x)
#else
x = (x & 0x55555555) + (x >> 1 & 0x55555555);
x = (x & 0x33333333) + (x >> 2 & 0x33333333);
- x = (x & 0x07070707) + (x >> 4 & 0x07070707);
- x = (x & 0x000f000f) + (x >> 8 & 0x000f000f);
- x = (x & 0x0000001f) + (x >>16 & 0x0000001f);
+ x = (x & 0x0f0f0f0f) + (x >> 4 & 0x0f0f0f0f);
+ x = (x & 0x001f001f) + (x >> 8 & 0x001f001f);
+ x = (x & 0x0000003f) + (x >>16 & 0x0000003f);
return (unsigned int)x;
#endif
@@ -428,9 +425,9 @@ rb_popcount64(uint64_t x)
x = (x & 0x5555555555555555) + (x >> 1 & 0x5555555555555555);
x = (x & 0x3333333333333333) + (x >> 2 & 0x3333333333333333);
x = (x & 0x0707070707070707) + (x >> 4 & 0x0707070707070707);
- x = (x & 0x000f000f000f000f) + (x >> 8 & 0x000f000f000f000f);
- x = (x & 0x0000001f0000001f) + (x >>16 & 0x0000001f0000001f);
- x = (x & 0x000000000000003f) + (x >>32 & 0x000000000000003f);
+ x = (x & 0x001f001f001f001f) + (x >> 8 & 0x001f001f001f001f);
+ x = (x & 0x0000003f0000003f) + (x >>16 & 0x0000003f0000003f);
+ x = (x & 0x000000000000007f) + (x >>32 & 0x000000000000007f);
return (unsigned int)x;
#endif
@@ -453,7 +450,7 @@ rb_popcount_intptr(uintptr_t x)
static inline int
ntz_int32(uint32_t x)
{
-#if defined(__x86_64__) && defined(__BMI__)
+#if defined(__x86_64__) && defined(__BMI__) && ! defined(MJIT_HEADER)
return (unsigned)_tzcnt_u32(x);
#elif MSC_VERSION_SINCE(1400)
@@ -475,7 +472,7 @@ ntz_int32(uint32_t x)
static inline int
ntz_int64(uint64_t x)
{
-#if defined(__x86_64__) && defined(__BMI__)
+#if defined(__x86_64__) && defined(__BMI__) && ! defined(MJIT_HEADER)
return (unsigned)_tzcnt_u64(x);
#elif defined(_WIN64) && MSC_VERSION_SINCE(1400)
diff --git a/internal/class.h b/internal/class.h
index f94434b938..63917e867f 100644
--- a/internal/class.h
+++ b/internal/class.h
@@ -8,18 +8,15 @@
* file COPYING are met. Consult the file for details.
* @brief Internal header for Class.
*/
-#include "id.h"
#include "id_table.h" /* for struct rb_id_table */
+#include "internal/gc.h" /* for RB_OBJ_WRITE */
#include "internal/serial.h" /* for rb_serial_t */
-#include "internal/static_assert.h"
-#include "internal/variable.h" /* for rb_class_ivar_set */
#include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/intern.h" /* for rb_alloc_func_t */
#include "ruby/ruby.h" /* for struct RBasic */
#include "shape.h"
#include "ruby_assert.h"
#include "vm_core.h"
-#include "vm_sync.h"
#include "method.h" /* for rb_cref_t */
#ifdef RCLASS_SUPER
@@ -31,7 +28,6 @@ struct rb_subclass_entry {
struct rb_subclass_entry *next;
struct rb_subclass_entry *prev;
};
-typedef struct rb_subclass_entry rb_subclass_entry_t;
struct rb_cvar_class_tbl_entry {
uint32_t index;
@@ -44,7 +40,7 @@ struct rb_classext_struct {
VALUE *iv_ptr;
struct rb_id_table *const_tbl;
struct rb_id_table *callable_m_tbl;
- struct rb_id_table *cc_tbl; /* ID -> [[ci1, cc1], [ci2, cc2] ...] */
+ struct rb_id_table *cc_tbl; /* ID -> [[ci, cc1], cc2, ...] */
struct rb_id_table *cvc_tbl;
size_t superclass_depth;
VALUE *superclasses;
@@ -58,40 +54,32 @@ struct rb_classext_struct {
struct rb_subclass_entry *module_subclass_entry;
const VALUE origin_;
const VALUE refined_class;
- union {
- struct {
- rb_alloc_func_t allocator;
- } class;
- struct {
- VALUE attached_object;
- } singleton_class;
- } as;
+ rb_alloc_func_t allocator;
const VALUE includer;
- attr_index_t max_iv_count;
- unsigned char variation_count;
- bool permanent_classpath : 1;
- bool cloned : 1;
- VALUE classpath;
+ uint32_t max_iv_count;
+ uint32_t variation_count;
+#if !SHAPE_IN_BASIC_FLAGS
+ shape_id_t shape_id;
+#endif
};
-typedef struct rb_classext_struct rb_classext_t;
-
-STATIC_ASSERT(shape_max_variations, SHAPE_MAX_VARIATIONS < (1 << (sizeof(((rb_classext_t *)0)->variation_count) * CHAR_BIT)));
struct RClass {
struct RBasic basic;
VALUE super;
struct rb_id_table *m_tbl;
+#if SIZE_POOL_COUNT == 1
+ struct rb_classext_struct *ptr;
+#endif
};
-// Assert that classes can be embedded in heaps[2] (which has 160B slot size)
-STATIC_ASSERT(sizeof_rb_classext_t, sizeof(struct RClass) + sizeof(rb_classext_t) <= 4 * RVALUE_SIZE);
-
-struct RClass_and_rb_classext_t {
- struct RClass rclass;
- rb_classext_t classext;
-};
+typedef struct rb_subclass_entry rb_subclass_entry_t;
+typedef struct rb_classext_struct rb_classext_t;
-#define RCLASS_EXT(c) (&((struct RClass_and_rb_classext_t*)(c))->classext)
+#if RCLASS_EXT_EMBEDDED
+# define RCLASS_EXT(c) ((rb_classext_t *)((char *)(c) + sizeof(struct RClass)))
+#else
+# define RCLASS_EXT(c) (RCLASS(c)->ptr)
+#endif
#define RCLASS_CONST_TBL(c) (RCLASS_EXT(c)->const_tbl)
#define RCLASS_M_TBL(c) (RCLASS(c)->m_tbl)
#define RCLASS_IVPTR(c) (RCLASS_EXT(c)->iv_ptr)
@@ -103,61 +91,16 @@ struct RClass_and_rb_classext_t {
#define RCLASS_INCLUDER(c) (RCLASS_EXT(c)->includer)
#define RCLASS_SUBCLASS_ENTRY(c) (RCLASS_EXT(c)->subclass_entry)
#define RCLASS_MODULE_SUBCLASS_ENTRY(c) (RCLASS_EXT(c)->module_subclass_entry)
+#define RCLASS_ALLOCATOR(c) (RCLASS_EXT(c)->allocator)
#define RCLASS_SUBCLASSES(c) (RCLASS_EXT(c)->subclasses)
#define RCLASS_SUPERCLASS_DEPTH(c) (RCLASS_EXT(c)->superclass_depth)
#define RCLASS_SUPERCLASSES(c) (RCLASS_EXT(c)->superclasses)
-#define RCLASS_ATTACHED_OBJECT(c) (RCLASS_EXT(c)->as.singleton_class.attached_object)
-#define RCLASS_IS_ROOT FL_USER0
#define RICLASS_IS_ORIGIN FL_USER0
+#define RCLASS_CLONED FL_USER1
#define RCLASS_SUPERCLASSES_INCLUDE_SELF FL_USER2
#define RICLASS_ORIGIN_SHARED_MTBL FL_USER3
-static inline st_table *
-RCLASS_IV_HASH(VALUE obj)
-{
- RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
- return (st_table *)RCLASS_IVPTR(obj);
-}
-
-static inline void
-RCLASS_SET_IV_HASH(VALUE obj, const st_table *tbl)
-{
- RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
- RCLASS_IVPTR(obj) = (VALUE *)tbl;
-}
-
-static inline uint32_t
-RCLASS_IV_COUNT(VALUE obj)
-{
- RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
- if (rb_shape_obj_too_complex(obj)) {
- uint32_t count;
-
- // "Too complex" classes could have their IV hash mutated in
- // parallel, so lets lock around getting the hash size.
- RB_VM_LOCK_ENTER();
- {
- count = (uint32_t)rb_st_table_size(RCLASS_IV_HASH(obj));
- }
- RB_VM_LOCK_LEAVE();
-
- return count;
- }
- else {
- return rb_shape_get_shape_by_id(RCLASS_SHAPE_ID(obj))->next_iv_index;
- }
-}
-
-static inline void
-RCLASS_SET_M_TBL(VALUE klass, struct rb_id_table *table)
-{
- RUBY_ASSERT(!RB_OBJ_PROMOTED(klass));
- RCLASS_M_TBL(klass) = table;
-}
-
/* class.c */
void rb_class_subclass_add(VALUE super, VALUE klass);
void rb_class_remove_from_super_subclasses(VALUE);
@@ -193,30 +136,10 @@ static inline VALUE RCLASS_SUPER(VALUE klass);
static inline VALUE RCLASS_SET_SUPER(VALUE klass, VALUE super);
static inline void RCLASS_SET_INCLUDER(VALUE iclass, VALUE klass);
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_class_inherited(VALUE, VALUE);
VALUE rb_keyword_error_new(const char *, VALUE);
-
-static inline bool
-RCLASS_SINGLETON_P(VALUE klass)
-{
- return RB_TYPE_P(klass, T_CLASS) && FL_TEST_RAW(klass, FL_SINGLETON);
-}
-
-static inline rb_alloc_func_t
-RCLASS_ALLOCATOR(VALUE klass)
-{
- if (RCLASS_SINGLETON_P(klass)) {
- return 0;
- }
- return RCLASS_EXT(klass)->as.class.allocator;
-}
-
-static inline void
-RCLASS_SET_ALLOCATOR(VALUE klass, rb_alloc_func_t allocator)
-{
- assert(!RCLASS_SINGLETON_P(klass));
- RCLASS_EXT(klass)->as.class.allocator = allocator;
-}
+MJIT_SYMBOL_EXPORT_END
static inline void
RCLASS_SET_ORIGIN(VALUE klass, VALUE origin)
@@ -261,23 +184,4 @@ RCLASS_SET_SUPER(VALUE klass, VALUE super)
return super;
}
-static inline void
-RCLASS_SET_CLASSPATH(VALUE klass, VALUE classpath, bool permanent)
-{
- assert(BUILTIN_TYPE(klass) == T_CLASS || BUILTIN_TYPE(klass) == T_MODULE);
- assert(classpath == 0 || BUILTIN_TYPE(classpath) == T_STRING);
-
- RB_OBJ_WRITE(klass, &(RCLASS_EXT(klass)->classpath), classpath);
- RCLASS_EXT(klass)->permanent_classpath = permanent;
-}
-
-static inline VALUE
-RCLASS_SET_ATTACHED_OBJECT(VALUE klass, VALUE attached_object)
-{
- assert(RCLASS_SINGLETON_P(klass));
-
- RB_OBJ_WRITE(klass, &RCLASS_EXT(klass)->as.singleton_class.attached_object, attached_object);
- return attached_object;
-}
-
#endif /* INTERNAL_CLASS_H */
diff --git a/internal/cmdlineopt.h b/internal/cmdlineopt.h
index e79b993345..bf52f1214b 100644
--- a/internal/cmdlineopt.h
+++ b/internal/cmdlineopt.h
@@ -1,7 +1,7 @@
#ifndef INTERNAL_CMDLINEOPT_H /*-*-C-*-vi:se ft=c:*/
#define INTERNAL_CMDLINEOPT_H
-#include "rjit.h"
+#include "mjit.h"
#include "yjit.h"
typedef struct {
@@ -23,15 +23,11 @@ typedef struct ruby_cmdline_options {
ruby_features_t features;
ruby_features_t warn;
unsigned int dump;
- long backtrace_length_limit;
-#if USE_RJIT
- struct rb_rjit_options rjit;
+#if USE_MJIT
+ struct mjit_options mjit;
#endif
- const char *crash_report;
-
- signed int sflag: 2;
- unsigned int xflag: 1;
+ int sflag, xflag;
unsigned int warning: 1;
unsigned int verbose: 1;
unsigned int do_loop: 1;
diff --git a/internal/compile.h b/internal/compile.h
index 2ece5396f6..d32c2233c9 100644
--- a/internal/compile.h
+++ b/internal/compile.h
@@ -17,7 +17,6 @@ struct rb_iseq_struct; /* in vm_core.h */
/* compile.c */
int rb_dvar_defined(ID, const struct rb_iseq_struct *);
int rb_local_defined(ID, const struct rb_iseq_struct *);
-int rb_insn_len(VALUE insn);
const char *rb_insns_name(int i);
VALUE rb_insns_name_array(void);
int rb_iseq_cdhash_cmp(VALUE val, VALUE lit);
@@ -28,7 +27,9 @@ int rb_vm_insn_addr2insn(const void *);
int rb_vm_insn_decode(const VALUE encoded);
extern bool ruby_vm_keep_script_lines;
+MJIT_SYMBOL_EXPORT_BEGIN
/* iseq.c (export) */
rb_event_flag_t rb_iseq_event_flags(const struct rb_iseq_struct *iseq, size_t pos);
+MJIT_SYMBOL_EXPORT_END
#endif /* INTERNAL_COMPILE_H */
diff --git a/internal/cont.h b/internal/cont.h
index 3c2528a02a..c3b091668a 100644
--- a/internal/cont.h
+++ b/internal/cont.h
@@ -22,9 +22,6 @@ void rb_jit_cont_init(void);
void rb_jit_cont_each_iseq(rb_iseq_callback callback, void *data);
void rb_jit_cont_finish(void);
-/* vm.c */
-void rb_free_shared_fiber_pool(void);
-
// Copy locals from the current execution to the specified fiber.
VALUE rb_fiber_inherit_storage(struct rb_execution_context_struct *ec, struct rb_fiber_struct *fiber);
diff --git a/internal/encoding.h b/internal/encoding.h
index fe9ea10ec4..a3b81bd388 100644
--- a/internal/encoding.h
+++ b/internal/encoding.h
@@ -18,7 +18,6 @@
/* encoding.c */
ID rb_id_encoding(void);
-const char * rb_enc_inspect_name(rb_encoding *enc);
rb_encoding *rb_enc_get_from_index(int index);
rb_encoding *rb_enc_check_str(VALUE str1, VALUE str2);
int rb_encdb_replicate(const char *alias, const char *orig);
@@ -30,7 +29,4 @@ void rb_enc_set_base(const char *name, const char *orig);
int rb_enc_set_dummy(int index);
PUREFUNC(int rb_data_is_encoding(VALUE obj));
-/* vm.c */
-void rb_free_global_enc_table(void);
-
#endif /* INTERNAL_ENCODING_H */
diff --git a/internal/error.h b/internal/error.h
index 7a4daca6b3..11601858f4 100644
--- a/internal/error.h
+++ b/internal/error.h
@@ -29,37 +29,15 @@
#define rb_raise_static(e, m) \
rb_raise_cstr_i((e), rb_str_new_static((m), rb_strlen_lit(m)))
#ifdef RUBY_FUNCTION_NAME_STRING
+# define rb_sys_fail_path(path) rb_sys_fail_path_in(RUBY_FUNCTION_NAME_STRING, path)
# define rb_syserr_fail_path(err, path) rb_syserr_fail_path_in(RUBY_FUNCTION_NAME_STRING, (err), (path))
# define rb_syserr_new_path(err, path) rb_syserr_new_path_in(RUBY_FUNCTION_NAME_STRING, (err), (path))
#else
+# define rb_sys_fail_path(path) rb_sys_fail_str(path)
# define rb_syserr_fail_path(err, path) rb_syserr_fail_str((err), (path))
# define rb_syserr_new_path(err, path) rb_syserr_new_str((err), (path))
#endif
-#define rb_sys_fail(mesg) \
-do { \
- int errno_to_fail = errno; \
- rb_syserr_fail(errno_to_fail, (mesg)); \
-} while (0)
-
-#define rb_sys_fail_str(mesg) \
-do { \
- int errno_to_fail = errno; \
- rb_syserr_fail_str(errno_to_fail, (mesg)); \
-} while (0)
-
-#define rb_sys_fail_path(path) \
-do { \
- int errno_to_fail = errno; \
- rb_syserr_fail_path(errno_to_fail, (path)); \
-} while (0)
-
-#define rb_sys_fail_sprintf(...) \
-do { \
- int errno_to_fail = errno; \
- rb_syserr_fail_str(errno_to_fail, rb_sprintf("" __VA_ARGS__)); \
-} while (0)
-
/* error.c */
extern long rb_backtrace_length_limit;
extern VALUE rb_eEAGAIN;
@@ -142,8 +120,6 @@ VALUE rb_syntax_error_append(VALUE, VALUE, int, int, rb_encoding*, const char*,
PRINTF_ARGS(void rb_enc_warn(rb_encoding *enc, const char *fmt, ...), 2, 3);
PRINTF_ARGS(void rb_sys_enc_warning(rb_encoding *enc, const char *fmt, ...), 2, 3);
PRINTF_ARGS(void rb_syserr_enc_warning(int err, rb_encoding *enc, const char *fmt, ...), 3, 4);
-PRINTF_ARGS(void rb_enc_compile_warning(rb_encoding *enc, const char *file, int line, const char *fmt, ...), 4, 5);
-PRINTF_ARGS(void rb_enc_compile_warn(rb_encoding *enc, const char *file, int line, const char *fmt, ...), 4, 5);
rb_warning_category_t rb_warning_category_from_name(VALUE category);
bool rb_warning_category_enabled_p(rb_warning_category_t category);
VALUE rb_name_err_new(VALUE mesg, VALUE recv, VALUE method);
@@ -171,9 +147,6 @@ VALUE rb_syserr_new_path_in(const char *func_name, int n, VALUE path);
#endif
RUBY_SYMBOL_EXPORT_END
-/* vm.c */
-void rb_free_warning(void);
-
static inline void
rb_raise_cstr_i(VALUE etype, VALUE mesg)
{
diff --git a/internal/gc.h b/internal/gc.h
index 0f48916ee8..e54a5dce9d 100644
--- a/internal/gc.h
+++ b/internal/gc.h
@@ -14,119 +14,35 @@
#include "internal/compilers.h" /* for __has_attribute */
#include "ruby/ruby.h" /* for rb_event_flag_t */
-#include "vm_core.h" /* for GET_EC() */
-#ifndef USE_SHARED_GC
-# define USE_SHARED_GC 0
-#endif
-
-#if defined(__x86_64__) && !defined(_ILP32) && defined(__GNUC__)
-#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movq\t%%rsp, %0" : "=r" (*(p)))
-#elif defined(__i386) && defined(__GNUC__)
-#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movl\t%%esp, %0" : "=r" (*(p)))
-#elif (defined(__powerpc__) || defined(__powerpc64__)) && defined(__GNUC__) && !defined(_AIX) && !defined(__APPLE__) // Not Apple is NEEDED to unbreak ppc64 build on Darwin. Don't ask.
-#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr\t%0, %%r1" : "=r" (*(p)))
-#elif (defined(__powerpc__) || defined(__powerpc64__)) && defined(__GNUC__) && defined(_AIX)
-#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr %0,1" : "=r" (*(p)))
-#elif defined(__POWERPC__) && defined(__APPLE__) // Darwin ppc and ppc64
-#define SET_MACHINE_STACK_END(p) __asm__ volatile("mr %0, r1" : "=r" (*(p)))
-#elif defined(__aarch64__) && defined(__GNUC__)
-#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mov\t%0, sp" : "=r" (*(p)))
-#else
-NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p));
-#define SET_MACHINE_STACK_END(p) rb_gc_set_stack_end(p)
-#define USE_CONSERVATIVE_STACK_END
-#endif
-
-/* for GC debug */
-
-#ifndef RUBY_MARK_FREE_DEBUG
-#define RUBY_MARK_FREE_DEBUG 0
-#endif
-
-#if RUBY_MARK_FREE_DEBUG
-extern int ruby_gc_debug_indent;
-
-static inline void
-rb_gc_debug_indent(void)
-{
- ruby_debug_printf("%*s", ruby_gc_debug_indent, "");
-}
-
-static inline void
-rb_gc_debug_body(const char *mode, const char *msg, int st, void *ptr)
-{
- if (st == 0) {
- ruby_gc_debug_indent--;
- }
- rb_gc_debug_indent();
- ruby_debug_printf("%s: %s %s (%p)\n", mode, st ? "->" : "<-", msg, ptr);
-
- if (st) {
- ruby_gc_debug_indent++;
- }
-
- fflush(stdout);
-}
-
-#define RUBY_MARK_ENTER(msg) rb_gc_debug_body("mark", (msg), 1, ptr)
-#define RUBY_MARK_LEAVE(msg) rb_gc_debug_body("mark", (msg), 0, ptr)
-#define RUBY_FREE_ENTER(msg) rb_gc_debug_body("free", (msg), 1, ptr)
-#define RUBY_FREE_LEAVE(msg) rb_gc_debug_body("free", (msg), 0, ptr)
-#define RUBY_GC_INFO rb_gc_debug_indent(), ruby_debug_printf
-
-#else
-#define RUBY_MARK_ENTER(msg)
-#define RUBY_MARK_LEAVE(msg)
-#define RUBY_FREE_ENTER(msg)
-#define RUBY_FREE_LEAVE(msg)
-#define RUBY_GC_INFO if(0)printf
-#endif
-
-#define RUBY_FREE_UNLESS_NULL(ptr) if(ptr){ruby_xfree(ptr);(ptr)=NULL;}
+struct rb_execution_context_struct; /* in vm_core.h */
+struct rb_objspace; /* in vm_core.h */
-#if STACK_GROW_DIRECTION > 0
-# define STACK_UPPER(x, a, b) (a)
-#elif STACK_GROW_DIRECTION < 0
-# define STACK_UPPER(x, a, b) (b)
-#else
-RUBY_EXTERN int ruby_stack_grow_direction;
-int ruby_get_stack_grow_direction(volatile VALUE *addr);
-# define stack_growup_p(x) ( \
- (ruby_stack_grow_direction ? \
- ruby_stack_grow_direction : \
- ruby_get_stack_grow_direction(x)) > 0)
-# define STACK_UPPER(x, a, b) (stack_growup_p(x) ? (a) : (b))
+#ifdef NEWOBJ_OF
+# undef NEWOBJ_OF
+# undef RB_NEWOBJ_OF
+# undef RB_OBJ_WRITE
#endif
-/*
- STACK_GROW_DIR_DETECTION is used with STACK_DIR_UPPER.
-
- On most normal systems, stacks grow from high address to lower address. In
- this case, STACK_DIR_UPPER(a, b) will return (b), but on exotic systems where
- the stack grows UP (from low address to high address), it will return (a).
-*/
+#define RVALUE_SIZE (sizeof(struct RBasic) + sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX]))
-#if STACK_GROW_DIRECTION
-#define STACK_GROW_DIR_DETECTION
-#define STACK_DIR_UPPER(a,b) STACK_UPPER(0, (a), (b))
-#else
-#define STACK_GROW_DIR_DETECTION VALUE stack_grow_dir_detection
-#define STACK_DIR_UPPER(a,b) STACK_UPPER(&stack_grow_dir_detection, (a), (b))
-#endif
-#define IS_STACK_DIR_UPPER() STACK_DIR_UPPER(1,0)
+#define RB_RVARGC_NEWOBJ_OF(var, T, c, f, s) \
+ T *(var) = (T *)(((f) & FL_WB_PROTECTED) ? \
+ rb_wb_protected_newobj_of((c), (f) & ~FL_WB_PROTECTED, s) : \
+ rb_wb_unprotected_newobj_of((c), (f), s))
-const char *rb_obj_info(VALUE obj);
-const char *rb_raw_obj_info(char *const buff, const size_t buff_size, VALUE obj);
+#define RB_RVARGC_EC_NEWOBJ_OF(ec, var, T, c, f, s) \
+ T *(var) = (T *)(((f) & FL_WB_PROTECTED) ? \
+ rb_ec_wb_protected_newobj_of((ec), (c), (f) & ~FL_WB_PROTECTED, s) : \
+ rb_wb_unprotected_newobj_of((c), (f), s))
-struct rb_execution_context_struct; /* in vm_core.h */
-struct rb_objspace; /* in vm_core.h */
+/* optimized version of NEWOBJ() */
+#define RB_NEWOBJ_OF(var, T, c, f) RB_RVARGC_NEWOBJ_OF(var, T, c, f, RVALUE_SIZE)
-#define NEWOBJ_OF(var, T, c, f, s, ec) \
- T *(var) = (T *)(((f) & FL_WB_PROTECTED) ? \
- rb_wb_protected_newobj_of((ec ? ec : GET_EC()), (c), (f) & ~FL_WB_PROTECTED, s) : \
- rb_wb_unprotected_newobj_of((c), (f), s))
+#define RB_EC_NEWOBJ_OF(ec, var, T, c, f) RB_RVARGC_EC_NEWOBJ_OF(ec, var, T, c, f, RVALUE_SIZE)
+#define NEWOBJ_OF(var, T, c, f) RB_NEWOBJ_OF((var), T, (c), (f))
+#define RVARGC_NEWOBJ_OF(var, T, c, f, s) RB_RVARGC_NEWOBJ_OF((var), T, (c), (f), (s))
#define RB_OBJ_GC_FLAGS_MAX 6 /* used in ext/objspace */
#ifndef USE_UNALIGNED_MEMBER_ACCESS
@@ -144,50 +60,49 @@ struct rb_objspace; /* in vm_core.h */
COMPILER_WARNING_POP; \
unaligned_member_access_result; \
})
-
-# define UNALIGNED_MEMBER_PTR(ptr, mem) __extension__({ \
- COMPILER_WARNING_PUSH; \
- COMPILER_WARNING_IGNORED(-Waddress-of-packed-member); \
- const volatile void *unaligned_member_ptr_result = &(ptr)->mem; \
- COMPILER_WARNING_POP; \
- (__typeof__((ptr)->mem) *)unaligned_member_ptr_result; \
-})
#endif
-#ifndef UNALIGNED_MEMBER_PTR
-# define UNALIGNED_MEMBER_PTR(ptr, mem) UNALIGNED_MEMBER_ACCESS(&(ptr)->mem)
+#define UNALIGNED_MEMBER_PTR(ptr, mem) UNALIGNED_MEMBER_ACCESS(&(ptr)->mem)
+#define RB_OBJ_WRITE(a, slot, b) \
+ rb_obj_write((VALUE)(a), UNALIGNED_MEMBER_ACCESS((VALUE *)(slot)), \
+ (VALUE)(b), __FILE__, __LINE__)
+
+// We use SIZE_POOL_COUNT number of shape IDs for transitions out of different size pools
+// The next available shapd ID will be the SPECIAL_CONST_SHAPE_ID
+#if USE_RVARGC && (SIZEOF_UINT64_T == SIZEOF_VALUE)
+# define SIZE_POOL_COUNT 5
+#else
+# define SIZE_POOL_COUNT 1
#endif
-#define RB_OBJ_WRITE_UNALIGNED(old, slot, young) do { \
- VALUE *_slot = UNALIGNED_MEMBER_ACCESS(slot); \
- RB_OBJ_WRITE(old, _slot, young); \
-} while (0)
+#define RCLASS_EXT_EMBEDDED (SIZE_POOL_COUNT > 1)
-/* Used in places that could malloc during, which can cause the GC to run. We
- * need to temporarily disable the GC to allow the malloc to happen.
- * Allocating memory during GC is a bad idea, so use this only when absolutely
- * necessary. */
-#define DURING_GC_COULD_MALLOC_REGION_START() \
- assert(rb_during_gc()); \
- VALUE _already_disabled = rb_gc_disable_no_rest()
+typedef struct ractor_newobj_size_pool_cache {
+ struct RVALUE *freelist;
+ struct heap_page *using_page;
+} rb_ractor_newobj_size_pool_cache_t;
-#define DURING_GC_COULD_MALLOC_REGION_END() \
- if (_already_disabled == Qfalse) rb_gc_enable()
+typedef struct ractor_newobj_cache {
+ size_t incremental_mark_step_allocated_slots;
+ rb_ractor_newobj_size_pool_cache_t size_pool_caches[SIZE_POOL_COUNT];
+} rb_ractor_newobj_cache_t;
/* gc.c */
+extern VALUE *ruby_initial_gc_stress_ptr;
extern int ruby_disable_gc;
RUBY_ATTR_MALLOC void *ruby_mimmalloc(size_t size);
-RUBY_ATTR_MALLOC void *ruby_mimcalloc(size_t num, size_t size);
void ruby_mimfree(void *ptr);
-void rb_gc_prepare_heap(void);
void rb_objspace_set_event_hook(const rb_event_flag_t event);
-VALUE rb_objspace_gc_enable(void *objspace);
-VALUE rb_objspace_gc_disable(void *objspace);
+VALUE rb_objspace_gc_enable(struct rb_objspace *);
+VALUE rb_objspace_gc_disable(struct rb_objspace *);
void ruby_gc_set_params(void);
-void rb_gc_copy_attributes(VALUE dest, VALUE obj);
+void rb_copy_wb_protected_attribute(VALUE dest, VALUE obj);
+#if __has_attribute(alloc_align)
+__attribute__((__alloc_align__(1)))
+#endif
+RUBY_ATTR_MALLOC void *rb_aligned_malloc(size_t, size_t) RUBY_ATTR_ALLOC_SIZE((2));
size_t rb_size_mul_or_raise(size_t, size_t, VALUE); /* used in compile.c */
size_t rb_size_mul_add_or_raise(size_t, size_t, size_t, VALUE); /* used in iseq.h */
-size_t rb_malloc_grow_capa(size_t current_capacity, size_t type_size);
RUBY_ATTR_MALLOC void *rb_xmalloc_mul_add(size_t, size_t, size_t);
RUBY_ATTR_MALLOC void *rb_xcalloc_mul_add(size_t, size_t, size_t);
void *rb_xrealloc_mul_add(const void *, size_t, size_t, size_t);
@@ -196,66 +111,33 @@ RUBY_ATTR_MALLOC void *rb_xcalloc_mul_add_mul(size_t, size_t, size_t, size_t);
static inline void *ruby_sized_xrealloc_inlined(void *ptr, size_t new_size, size_t old_size) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2));
static inline void *ruby_sized_xrealloc2_inlined(void *ptr, size_t new_count, size_t elemsiz, size_t old_count) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2, 3));
static inline void ruby_sized_xfree_inlined(void *ptr, size_t size);
-
-void *rb_gc_ractor_cache_alloc(void);
-void rb_gc_ractor_cache_free(void *cache);
-
+VALUE rb_class_allocate_instance(VALUE klass);
+void rb_gc_ractor_newobj_cache_clear(rb_ractor_newobj_cache_t *newobj_cache);
+size_t rb_gc_obj_slot_size(VALUE obj);
bool rb_gc_size_allocatable_p(size_t size);
-size_t *rb_gc_heap_sizes(void);
-size_t rb_gc_heap_id_for_size(size_t size);
-
-void rb_gc_mark_and_move(VALUE *ptr);
-
-void rb_gc_mark_weak(VALUE *ptr);
-void rb_gc_remove_weak(VALUE parent_obj, VALUE *ptr);
-
-void rb_gc_ref_update_table_values_only(st_table *tbl);
-
-void rb_gc_initial_stress_set(VALUE flag);
-
-#define rb_gc_mark_and_move_ptr(ptr) do { \
- VALUE _obj = (VALUE)*(ptr); \
- rb_gc_mark_and_move(&_obj); \
- if (_obj != (VALUE)*(ptr)) *(ptr) = (void *)_obj; \
-} while (0)
-
-RUBY_SYMBOL_EXPORT_BEGIN
-/* exports for objspace module */
-void rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data);
-void rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *data);
-int rb_objspace_internal_object_p(VALUE obj);
int rb_objspace_garbage_object_p(VALUE obj);
-void rb_objspace_each_objects(
- int (*callback)(void *start, void *end, size_t stride, void *data),
- void *data);
-
-size_t rb_gc_obj_slot_size(VALUE obj);
-
-VALUE rb_gc_disable_no_rest(void);
-
-
+RUBY_SYMBOL_EXPORT_BEGIN
/* gc.c (export) */
const char *rb_objspace_data_type_name(VALUE obj);
-VALUE rb_wb_protected_newobj_of(struct rb_execution_context_struct *, VALUE, VALUE, size_t);
+VALUE rb_wb_protected_newobj_of(VALUE, VALUE, size_t);
VALUE rb_wb_unprotected_newobj_of(VALUE, VALUE, size_t);
+VALUE rb_ec_wb_protected_newobj_of(struct rb_execution_context_struct *ec, VALUE klass, VALUE flags, size_t);
size_t rb_obj_memsize_of(VALUE);
+void rb_gc_verify_internal_consistency(void);
size_t rb_obj_gc_flags(VALUE, ID[], size_t);
void rb_gc_mark_values(long n, const VALUE *values);
void rb_gc_mark_vm_stack_values(long n, const VALUE *values);
-void rb_gc_update_values(long n, VALUE *values);
void *ruby_sized_xrealloc(void *ptr, size_t new_size, size_t old_size) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2));
void *ruby_sized_xrealloc2(void *ptr, size_t new_count, size_t element_size, size_t old_count) RUBY_ATTR_RETURNS_NONNULL RUBY_ATTR_ALLOC_SIZE((2, 3));
void ruby_sized_xfree(void *x, size_t size);
-
-#if USE_SHARED_GC
-void ruby_load_external_gc_from_argv(int argc, char **argv);
-#endif
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
int rb_ec_stack_check(struct rb_execution_context_struct *ec);
void rb_gc_writebarrier_remember(VALUE obj);
const char *rb_obj_info(VALUE obj);
+MJIT_SYMBOL_EXPORT_END
#if defined(HAVE_MALLOC_USABLE_SIZE) || defined(HAVE_MALLOC_SIZE) || defined(_WIN32)
@@ -279,12 +161,6 @@ ruby_sized_xfree_inlined(void *ptr, size_t size)
# define SIZED_REALLOC_N(x, y, z, w) REALLOC_N(x, y, z)
-static inline void *
-ruby_sized_realloc_n(void *ptr, size_t new_count, size_t element_size, size_t old_count)
-{
- return ruby_xrealloc2(ptr, new_count, element_size);
-}
-
#else
static inline void *
@@ -308,12 +184,6 @@ ruby_sized_xfree_inlined(void *ptr, size_t size)
# define SIZED_REALLOC_N(v, T, m, n) \
((v) = (T *)ruby_sized_xrealloc2((void *)(v), (m), sizeof(T), (n)))
-static inline void *
-ruby_sized_realloc_n(void *ptr, size_t new_count, size_t element_size, size_t old_count)
-{
- return ruby_sized_xrealloc2(ptr, new_count, element_size, old_count);
-}
-
#endif /* HAVE_MALLOC_USABLE_SIZE */
#define ruby_sized_xrealloc ruby_sized_xrealloc_inlined
diff --git a/internal/hash.h b/internal/hash.h
index d66b5b2d04..64832c9610 100644
--- a/internal/hash.h
+++ b/internal/hash.h
@@ -28,6 +28,10 @@ enum ruby_rhash_flags {
RHASH_AR_TABLE_BOUND_MASK = (FL_USER8|FL_USER9|FL_USER10|FL_USER11), /* FL 8..11 */
RHASH_AR_TABLE_BOUND_SHIFT = (FL_USHIFT+8),
+#if USE_TRANSIENT_HEAP
+ RHASH_TRANSIENT_FLAG = FL_USER12, /* FL 12 */
+#endif
+
// we can not put it in "enum" because it can exceed "int" range.
#define RHASH_LEV_MASK (FL_USER13 | FL_USER14 | FL_USER15 | /* FL 13..19 */ \
FL_USER16 | FL_USER17 | FL_USER18 | FL_USER19)
@@ -36,23 +40,17 @@ enum ruby_rhash_flags {
RHASH_LEV_MAX = 127, /* 7 bits */
};
-typedef struct ar_table_pair_struct {
- VALUE key;
- VALUE val;
-} ar_table_pair;
-
-typedef struct ar_table_struct {
+struct RHash {
+ struct RBasic basic;
+ union {
+ st_table *st;
+ struct ar_table_struct *ar; /* possibly 0 */
+ } as;
+ const VALUE ifnone;
union {
ar_hint_t ary[RHASH_AR_TABLE_MAX_SIZE];
VALUE word;
} ar_hint;
- /* 64bit CPU: 8B * 2 * 8 = 128B */
- ar_table_pair pairs[RHASH_AR_TABLE_MAX_SIZE];
-} ar_table;
-
-struct RHash {
- struct RBasic basic;
- const VALUE ifnone;
};
#define RHASH(obj) ((struct RHash *)(obj))
@@ -76,7 +74,6 @@ VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc);
long rb_dbl_long_hash(double d);
st_table *rb_init_identtable(void);
st_index_t rb_any_hash(VALUE a);
-int rb_any_cmp(VALUE a, VALUE b);
VALUE rb_to_hash_type(VALUE obj);
VALUE rb_hash_key_str(VALUE);
VALUE rb_hash_values(VALUE hash);
@@ -86,9 +83,8 @@ VALUE rb_hash_set_pair(VALUE hash, VALUE pair);
int rb_hash_stlike_delete(VALUE hash, st_data_t *pkey, st_data_t *pval);
int rb_hash_stlike_foreach_with_replace(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg);
int rb_hash_stlike_update(VALUE hash, st_data_t key, st_update_callback_func *func, st_data_t arg);
+extern st_table *rb_hash_st_table(VALUE hash);
VALUE rb_ident_hash_new_with_size(st_index_t size);
-void rb_hash_free(VALUE hash);
-RUBY_EXTERN VALUE rb_cHash_empty_frozen;
static inline unsigned RHASH_AR_TABLE_SIZE_RAW(VALUE h);
static inline VALUE RHASH_IFNONE(VALUE h);
@@ -100,6 +96,9 @@ static inline struct ar_table_struct *RHASH_AR_TABLE(VALUE h);
static inline st_table *RHASH_ST_TABLE(VALUE h);
static inline size_t RHASH_ST_SIZE(VALUE h);
static inline void RHASH_ST_CLEAR(VALUE h);
+static inline bool RHASH_TRANSIENT_P(VALUE h);
+static inline void RHASH_SET_TRANSIENT_FLAG(VALUE h);
+static inline void RHASH_UNSET_TRANSIENT_FLAG(VALUE h);
RUBY_SYMBOL_EXPORT_BEGIN
/* hash.c (export) */
@@ -108,6 +107,7 @@ VALUE rb_ident_hash_new(void);
int rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg);
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_hash_new_with_size(st_index_t size);
VALUE rb_hash_resurrect(VALUE hash);
int rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval);
@@ -117,29 +117,54 @@ VALUE rb_hash_compare_by_id_p(VALUE hash);
st_table *rb_hash_tbl_raw(VALUE hash, const char *file, int line);
#define RHASH_TBL_RAW(h) rb_hash_tbl_raw(h, __FILE__, __LINE__)
+MJIT_SYMBOL_EXPORT_END
VALUE rb_hash_compare_by_id(VALUE hash);
+#if 0 /* for debug */
+
+static inline bool
+RHASH_AR_TABLE_P(VALUE h)
+{
+ extern int rb_hash_ar_table_p(VALUE hash);
+ return rb_hash_ar_table_p(h)
+}
+
+static inline struct ar_table_struct *
+RHASH_AR_TABLE(VALUE h)
+{
+ extern struct ar_table_struct *rb_hash_ar_table(VALUE hash);
+ return rb_hash_ar_table(h)
+}
+
+static inline st_table *
+RHASH_ST_TABLE(VALUE h)
+{
+ return rb_hash_st_table(h)
+}
+
+#else
+
static inline bool
RHASH_AR_TABLE_P(VALUE h)
{
return ! FL_TEST_RAW(h, RHASH_ST_TABLE_FLAG);
}
-RBIMPL_ATTR_RETURNS_NONNULL()
static inline struct ar_table_struct *
RHASH_AR_TABLE(VALUE h)
{
- return (struct ar_table_struct *)((uintptr_t)h + sizeof(struct RHash));
+ return RHASH(h)->as.ar;
}
-RBIMPL_ATTR_RETURNS_NONNULL()
static inline st_table *
RHASH_ST_TABLE(VALUE h)
{
- return (st_table *)((uintptr_t)h + sizeof(struct RHash));
+ return RHASH(h)->as.st;
}
+#endif
+
static inline VALUE
RHASH_IFNONE(VALUE h)
{
@@ -178,7 +203,8 @@ RHASH_ST_SIZE(VALUE h)
static inline void
RHASH_ST_CLEAR(VALUE h)
{
- memset(RHASH_ST_TABLE(h), 0, sizeof(st_table));
+ FL_UNSET_RAW(h, RHASH_ST_TABLE_FLAG);
+ RHASH(h)->as.ar = NULL;
}
static inline unsigned
@@ -189,4 +215,30 @@ RHASH_AR_TABLE_SIZE_RAW(VALUE h)
return (unsigned)ret;
}
+static inline bool
+RHASH_TRANSIENT_P(VALUE h)
+{
+#if USE_TRANSIENT_HEAP
+ return FL_TEST_RAW(h, RHASH_TRANSIENT_FLAG);
+#else
+ return false;
+#endif
+}
+
+static inline void
+RHASH_SET_TRANSIENT_FLAG(VALUE h)
+{
+#if USE_TRANSIENT_HEAP
+ FL_SET_RAW(h, RHASH_TRANSIENT_FLAG);
+#endif
+}
+
+static inline void
+RHASH_UNSET_TRANSIENT_FLAG(VALUE h)
+{
+#if USE_TRANSIENT_HEAP
+ FL_UNSET_RAW(h, RHASH_TRANSIENT_FLAG);
+#endif
+}
+
#endif /* INTERNAL_HASH_H */
diff --git a/internal/imemo.h b/internal/imemo.h
index 7420909a14..91b524e0a6 100644
--- a/internal/imemo.h
+++ b/internal/imemo.h
@@ -11,6 +11,7 @@
#include "ruby/internal/config.h"
#include <stddef.h> /* for size_t */
#include "internal/array.h" /* for rb_ary_hidden_new_fill */
+#include "internal/gc.h" /* for RB_OBJ_WRITE */
#include "ruby/internal/stdbool.h" /* for bool */
#include "ruby/ruby.h" /* for rb_block_call_func_t */
@@ -39,7 +40,7 @@ enum imemo_type {
imemo_ment = 6,
imemo_iseq = 7,
imemo_tmpbuf = 8,
- imemo_ast = 9, // Obsolete due to the universal parser
+ imemo_ast = 9,
imemo_parser_strterm = 10,
imemo_callinfo = 11,
imemo_callcache = 12,
@@ -82,12 +83,11 @@ struct vm_ifunc_argc {
/*! IFUNC (Internal FUNCtion) */
struct vm_ifunc {
VALUE flags;
- VALUE *svar_lep;
+ VALUE reserved;
rb_block_call_func_t func;
const void *data;
struct vm_ifunc_argc argc;
};
-#define IFUNC_YIELD_OPTIMIZABLE IMEMO_FL_USER0
struct rb_imemo_tmpbuf_struct {
VALUE flags;
@@ -114,12 +114,11 @@ struct MEMO {
} u3;
};
-#define IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0)))
-
/* ment is in method.h */
#define THROW_DATA_P(err) imemo_throw_data_p((VALUE)err)
#define MEMO_CAST(m) ((struct MEMO *)(m))
+#define MEMO_NEW(a, b, c) ((struct MEMO *)rb_imemo_new(imemo_memo, (VALUE)(a), (VALUE)(b), (VALUE)(c), 0))
#define MEMO_FOR(type, value) ((type *)RARRAY_PTR(value))
#define NEW_MEMO_FOR(type, value) \
((value) = rb_ary_hidden_new_fill(type_roomof(type, VALUE)), MEMO_FOR(type, value))
@@ -128,11 +127,10 @@ struct MEMO {
rb_ary_set_len((value), offsetof(type, member) / sizeof(VALUE)), \
MEMO_FOR(type, value))
-#ifndef RUBY_RUBYPARSER_H
typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t;
-#endif
rb_imemo_tmpbuf_t *rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt);
struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc);
+void rb_strterm_mark(VALUE obj);
static inline enum imemo_type imemo_type(VALUE imemo);
static inline int imemo_type_p(VALUE imemo, enum imemo_type imemo_type);
static inline bool imemo_throw_data_p(VALUE imemo);
@@ -144,33 +142,16 @@ static inline VALUE rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(VALUE
static inline void MEMO_V1_SET(struct MEMO *m, VALUE v);
static inline void MEMO_V2_SET(struct MEMO *m, VALUE v);
-size_t rb_imemo_memsize(VALUE obj);
-void rb_cc_table_mark(VALUE klass);
-void rb_imemo_mark_and_move(VALUE obj, bool reference_updating);
-void rb_cc_table_free(VALUE klass);
-void rb_imemo_free(VALUE obj);
-
RUBY_SYMBOL_EXPORT_BEGIN
#if IMEMO_DEBUG
-VALUE rb_imemo_new_debug(enum imemo_type type, VALUE v0, const char *file, int line);
+VALUE rb_imemo_new_debug(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0, const char *file, int line);
#define rb_imemo_new(type, v1, v2, v3, v0) rb_imemo_new_debug(type, v1, v2, v3, v0, __FILE__, __LINE__)
#else
-VALUE rb_imemo_new(enum imemo_type type, VALUE v0);
+VALUE rb_imemo_new(enum imemo_type type, VALUE v1, VALUE v2, VALUE v3, VALUE v0);
#endif
const char *rb_imemo_name(enum imemo_type type);
RUBY_SYMBOL_EXPORT_END
-static inline struct MEMO *
-MEMO_NEW(VALUE a, VALUE b, VALUE c)
-{
- struct MEMO *memo = IMEMO_NEW(struct MEMO, imemo_memo, 0);
- *((VALUE *)&memo->v1) = a;
- *((VALUE *)&memo->v2) = b;
- *((VALUE *)&memo->u3.value) = c;
-
- return memo;
-}
-
static inline enum imemo_type
imemo_type(VALUE imemo)
{
@@ -192,7 +173,7 @@ imemo_type_p(VALUE imemo, enum imemo_type imemo_type)
}
}
-#define IMEMO_TYPE_P(v, t) imemo_type_p((VALUE)(v), t)
+#define IMEMO_TYPE_P(v, t) imemo_type_p((VALUE)v, t)
static inline bool
imemo_throw_data_p(VALUE imemo)
@@ -209,7 +190,7 @@ rb_vm_ifunc_proc_new(rb_block_call_func_t func, const void *data)
static inline VALUE
rb_imemo_tmpbuf_auto_free_pointer(void)
{
- return rb_imemo_new(imemo_tmpbuf, 0);
+ return rb_imemo_new(imemo_tmpbuf, 0, 0, 0, 0);
}
static inline void *
@@ -234,7 +215,7 @@ rb_imemo_tmpbuf_auto_free_pointer_new_from_an_RString(VALUE str)
void *dst;
size_t len;
- StringValue(str);
+ SafeStringValue(str);
/* create tmpbuf to keep the pointer before xmalloc */
imemo = rb_imemo_tmpbuf_auto_free_pointer();
tmpbuf = (rb_imemo_tmpbuf_t *)imemo;
diff --git a/internal/inits.h b/internal/inits.h
index 03de289dd4..03e180f77b 100644
--- a/internal/inits.h
+++ b/internal/inits.h
@@ -19,6 +19,9 @@ void Init_ext(void);
/* file.c */
void Init_File(void);
+/* gc.c */
+void Init_heap(void);
+
/* localeinit.c */
int Init_enc_set_filesystem_encoding(void);
diff --git a/internal/io.h b/internal/io.h
index c207ca38bf..b5f15499d7 100644
--- a/internal/io.h
+++ b/internal/io.h
@@ -9,110 +9,8 @@
* @brief Internal header for IO.
*/
#include "ruby/ruby.h" /* for VALUE */
-
-#define HAVE_RB_IO_T
-struct rb_io;
-
#include "ruby/io.h" /* for rb_io_t */
-#define IO_WITHOUT_GVL(func, arg) rb_thread_call_without_gvl(func, arg, RUBY_UBF_IO, 0)
-#define IO_WITHOUT_GVL_INT(func, arg) (int)(VALUE)IO_WITHOUT_GVL(func, arg)
-
-/** Ruby's IO, metadata and buffers. */
-struct rb_io {
-
- /** The IO's Ruby level counterpart. */
- VALUE self;
-
- /** stdio ptr for read/write, if available. */
- FILE *stdio_file;
-
- /** file descriptor. */
- int fd;
-
- /** mode flags: FMODE_XXXs */
- int mode;
-
- /** child's pid (for pipes) */
- rb_pid_t pid;
-
- /** number of lines read */
- int lineno;
-
- /** pathname for file */
- VALUE pathv;
-
- /** finalize proc */
- void (*finalize)(struct rb_io*,int);
-
- /** Write buffer. */
- rb_io_buffer_t wbuf;
-
- /**
- * (Byte) read buffer. Note also that there is a field called
- * ::rb_io_t::cbuf, which also concerns read IO.
- */
- rb_io_buffer_t rbuf;
-
- /**
- * Duplex IO object, if set.
- *
- * @see rb_io_set_write_io()
- */
- VALUE tied_io_for_writing;
-
- struct rb_io_encoding encs; /**< Decomposed encoding flags. */
-
- /** Encoding converter used when reading from this IO. */
- rb_econv_t *readconv;
-
- /**
- * rb_io_ungetc() destination. This buffer is read before checking
- * ::rb_io_t::rbuf
- */
- rb_io_buffer_t cbuf;
-
- /** Encoding converter used when writing to this IO. */
- rb_econv_t *writeconv;
-
- /**
- * This is, when set, an instance of ::rb_cString which holds the "common"
- * encoding. Write conversion can convert strings twice... In case
- * conversion from encoding X to encoding Y does not exist, Ruby finds an
- * encoding Z that bridges the two, so that X to Z to Y conversion happens.
- */
- VALUE writeconv_asciicompat;
-
- /** Whether ::rb_io_t::writeconv is already set up. */
- int writeconv_initialized;
-
- /**
- * Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before
- * initialising ::rb_io_t::writeconv.
- */
- int writeconv_pre_ecflags;
-
- /**
- * Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising
- * ::rb_io_t::writeconv.
- */
- VALUE writeconv_pre_ecopts;
-
- /**
- * This is a Ruby level mutex. It avoids multiple threads to write to an
- * IO at once; helps for instance rb_io_puts() to ensure newlines right
- * next to its arguments.
- *
- * This of course doesn't help inter-process IO interleaves, though.
- */
- VALUE write_lock;
-
- /**
- * The timeout associated with this IO when performing blocking operations.
- */
- VALUE timeout;
-};
-
/* io.c */
void ruby_set_inplace_mode(const char *);
void rb_stdio_set_default_encoding(void);
@@ -135,9 +33,6 @@ RUBY_SYMBOL_EXPORT_BEGIN
void rb_maygvl_fd_fix_cloexec(int fd);
int rb_gc_for_fd(int err);
void rb_write_error_str(VALUE mesg);
-
-VALUE rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events);
-VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument);
RUBY_SYMBOL_EXPORT_END
#endif /* INTERNAL_IO_H */
diff --git a/internal/missing.h b/internal/missing.h
index 6ca508c8f9..c0992a151a 100644
--- a/internal/missing.h
+++ b/internal/missing.h
@@ -13,7 +13,6 @@
/* missing/setproctitle.c */
#ifndef HAVE_SETPROCTITLE
extern void ruby_init_setproctitle(int argc, char *argv[]);
-extern void ruby_free_proctitle(void);
#endif
#endif /* INTERNAL_MISSING_H */
diff --git a/internal/numeric.h b/internal/numeric.h
index 6406cfc2fa..89bc54b307 100644
--- a/internal/numeric.h
+++ b/internal/numeric.h
@@ -86,7 +86,6 @@ VALUE rb_int_equal(VALUE x, VALUE y);
VALUE rb_int_divmod(VALUE x, VALUE y);
VALUE rb_int_and(VALUE x, VALUE y);
VALUE rb_int_lshift(VALUE x, VALUE y);
-VALUE rb_int_rshift(VALUE x, VALUE y);
VALUE rb_int_div(VALUE x, VALUE y);
int rb_int_positive_p(VALUE num);
int rb_int_negative_p(VALUE num);
@@ -112,6 +111,7 @@ RUBY_SYMBOL_EXPORT_BEGIN
/* numeric.c (export) */
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_flo_div_flo(VALUE x, VALUE y);
double ruby_float_mod(double x, double y);
VALUE rb_float_equal(VALUE x, VALUE y);
@@ -125,6 +125,7 @@ VALUE rb_int_abs(VALUE num);
VALUE rb_int_bit_length(VALUE num);
VALUE rb_int_uminus(VALUE num);
VALUE rb_int_comp(VALUE num);
+MJIT_SYMBOL_EXPORT_END
static inline bool
INT_POSITIVE_P(VALUE num)
@@ -159,7 +160,7 @@ rb_num_compare_with_zero(VALUE num, ID mid)
{
VALUE zero = INT2FIX(0);
VALUE r = rb_check_funcall(num, mid, 1, &zero);
- if (RB_UNDEF_P(r)) {
+ if (r == Qundef) {
rb_cmperr(num, zero);
}
return r;
diff --git a/internal/object.h b/internal/object.h
index 92ad37fdc8..7b54e13dd2 100644
--- a/internal/object.h
+++ b/internal/object.h
@@ -11,14 +11,10 @@
#include "ruby/ruby.h" /* for VALUE */
/* object.c */
-size_t rb_obj_embedded_size(uint32_t numiv);
-VALUE rb_class_allocate_instance(VALUE klass);
VALUE rb_class_search_ancestor(VALUE klass, VALUE super);
NORETURN(void rb_undefined_alloc(VALUE klass));
double rb_num_to_dbl(VALUE val);
VALUE rb_obj_dig(int argc, VALUE *argv, VALUE self, VALUE notfound);
-VALUE rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze);
-VALUE rb_obj_dup_setup(VALUE obj, VALUE dup);
VALUE rb_immutable_obj_clone(int, VALUE *, VALUE);
VALUE rb_check_convert_type_with_id(VALUE,int,const char*,ID);
int rb_bool_expected(VALUE, const char *, int raise);
@@ -31,6 +27,7 @@ RUBY_SYMBOL_EXPORT_BEGIN
int rb_opts_exception_p(VALUE opts, int default_value);
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
CONSTFUNC(VALUE rb_obj_equal(VALUE obj1, VALUE obj2));
CONSTFUNC(VALUE rb_obj_not(VALUE obj));
VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2);
@@ -39,6 +36,7 @@ VALUE rb_false(VALUE obj);
VALUE rb_convert_type_with_id(VALUE v, int t, const char* nam, ID mid);
VALUE rb_obj_size(VALUE self, VALUE args, VALUE obj);
VALUE rb_get_freeze_opt(int argc, VALUE *argv);
+MJIT_SYMBOL_EXPORT_END
static inline void
RBASIC_SET_CLASS_RAW(VALUE obj, VALUE klass)
diff --git a/internal/parse.h b/internal/parse.h
index de42acbed9..f242c384ad 100644
--- a/internal/parse.h
+++ b/internal/parse.h
@@ -8,122 +8,18 @@
* file COPYING are met. Consult the file for details.
* @brief Internal header for the parser.
*/
-#include <limits.h>
-#include "rubyparser.h"
-#include "internal/static_assert.h"
-
-// The default parser to use for Ruby code.
-typedef enum {
- RB_DEFAULT_PARSER_PARSE_Y,
- RB_DEFAULT_PARSER_PRISM,
-} ruby_default_parser_enum;
-
-ruby_default_parser_enum rb_ruby_default_parser(void);
-void rb_ruby_default_parser_set(ruby_default_parser_enum parser);
-
-#define rb_ruby_prism_p() (rb_ruby_default_parser() == RB_DEFAULT_PARSER_PRISM)
-
-#ifdef UNIVERSAL_PARSER
-#define rb_encoding const void
-#endif
-
+#include "ruby/ruby.h" /* for VALUE */
struct rb_iseq_struct; /* in vm_core.h */
-/* structs for managing terminator of string literal and heredocment */
-typedef struct rb_strterm_literal_struct {
- long nest;
- int func; /* STR_FUNC_* (e.g., STR_FUNC_ESCAPE and STR_FUNC_EXPAND) */
- int paren; /* '(' of `%q(...)` */
- int term; /* ')' of `%q(...)` */
-} rb_strterm_literal_t;
-
-typedef struct rb_strterm_heredoc_struct {
- rb_parser_string_t *lastline; /* the string of line that contains `<<"END"` */
- long offset; /* the column of END in `<<"END"` */
- int sourceline; /* lineno of the line that contains `<<"END"` */
- unsigned length; /* the length of END in `<<"END"` */
- uint8_t quote;
- uint8_t func;
-} rb_strterm_heredoc_t;
-
-#define HERETERM_LENGTH_MAX UINT_MAX
-
-typedef struct rb_strterm_struct {
- bool heredoc;
- union {
- rb_strterm_literal_t literal;
- rb_strterm_heredoc_t heredoc;
- } u;
-} rb_strterm_t;
-
/* parse.y */
-void rb_ruby_parser_mark(void *ptr);
-size_t rb_ruby_parser_memsize(const void *ptr);
-
-void rb_ruby_parser_set_options(rb_parser_t *p, int print, int loop, int chomp, int split);
-rb_parser_t *rb_ruby_parser_set_context(rb_parser_t *p, const struct rb_iseq_struct *base, int main);
-void rb_ruby_parser_set_script_lines(rb_parser_t *p);
-void rb_ruby_parser_error_tolerant(rb_parser_t *p);
-void rb_ruby_parser_keep_tokens(rb_parser_t *p);
-typedef rb_parser_string_t*(rb_parser_lex_gets_func)(struct parser_params*, rb_parser_input_data, int);
-rb_ast_t *rb_parser_compile(rb_parser_t *p, rb_parser_lex_gets_func *gets, VALUE fname, rb_parser_input_data input, int line);
+VALUE rb_parser_set_yydebug(VALUE, VALUE);
+void *rb_parser_load_file(VALUE parser, VALUE name);
+void rb_parser_keep_script_lines(VALUE vparser);
+void rb_parser_error_tolerant(VALUE vparser);
+void rb_parser_keep_tokens(VALUE vparser);
RUBY_SYMBOL_EXPORT_BEGIN
-
-rb_encoding *rb_ruby_parser_encoding(rb_parser_t *p);
-int rb_ruby_parser_end_seen_p(rb_parser_t *p);
-int rb_ruby_parser_set_yydebug(rb_parser_t *p, int flag);
-rb_parser_string_t *rb_str_to_parser_string(rb_parser_t *p, VALUE str);
-void rb_parser_string_free(rb_parser_t *p, rb_parser_string_t *str);
-
-int rb_parser_dvar_defined_ref(struct parser_params*, ID, ID**);
-ID rb_parser_internal_id(struct parser_params*);
-int rb_parser_reg_fragment_check(struct parser_params*, rb_parser_string_t*, int);
-int rb_reg_named_capture_assign_iter_impl(struct parser_params *p, const char *s, long len, rb_encoding *enc, NODE **succ_block, const rb_code_location_t *loc);
-int rb_parser_local_defined(struct parser_params *p, ID id, const struct rb_iseq_struct *iseq);
-
+VALUE rb_parser_set_context(VALUE, const struct rb_iseq_struct *, int);
RUBY_SYMBOL_EXPORT_END
-#ifndef UNIVERSAL_PARSER
-rb_parser_t *rb_ruby_parser_allocate(void);
-rb_parser_t *rb_ruby_parser_new(void);
-#endif
-
-#ifdef RIPPER
-void ripper_parser_mark(void *ptr);
-void ripper_parser_free(void *ptr);
-size_t ripper_parser_memsize(const void *ptr);
-void ripper_error(struct parser_params *p);
-VALUE ripper_value(struct parser_params *p);
-int rb_ruby_parser_get_yydebug(rb_parser_t *p);
-void rb_ruby_parser_set_value(rb_parser_t *p, VALUE value);
-int rb_ruby_parser_error_p(rb_parser_t *p);
-VALUE rb_ruby_parser_debug_output(rb_parser_t *p);
-void rb_ruby_parser_set_debug_output(rb_parser_t *p, VALUE output);
-VALUE rb_ruby_parser_parsing_thread(rb_parser_t *p);
-void rb_ruby_parser_set_parsing_thread(rb_parser_t *p, VALUE parsing_thread);
-void rb_ruby_parser_ripper_initialize(rb_parser_t *p, rb_parser_lex_gets_func *gets, rb_parser_input_data input, VALUE sourcefile_string, const char *sourcefile, int sourceline);
-VALUE rb_ruby_parser_result(rb_parser_t *p);
-rb_encoding *rb_ruby_parser_enc(rb_parser_t *p);
-VALUE rb_ruby_parser_ruby_sourcefile_string(rb_parser_t *p);
-int rb_ruby_parser_ruby_sourceline(rb_parser_t *p);
-int rb_ruby_parser_lex_state(rb_parser_t *p);
-void rb_ruby_ripper_parse0(rb_parser_t *p);
-int rb_ruby_ripper_dedent_string(rb_parser_t *p, rb_parser_string_t *string, int width);
-int rb_ruby_ripper_initialized_p(rb_parser_t *p);
-void rb_ruby_ripper_parser_initialize(rb_parser_t *p);
-long rb_ruby_ripper_column(rb_parser_t *p);
-long rb_ruby_ripper_token_len(rb_parser_t *p);
-rb_parser_string_t *rb_ruby_ripper_lex_lastline(rb_parser_t *p);
-VALUE rb_ruby_ripper_lex_state_name(struct parser_params *p, int state);
-#ifdef UNIVERSAL_PARSER
-rb_parser_t *rb_ripper_parser_params_allocate(const rb_parser_config_t *config);
-#endif
-struct parser_params *rb_ruby_ripper_parser_allocate(void);
-#endif
-
-#ifdef UNIVERSAL_PARSER
-#undef rb_encoding
-#endif
-
#endif /* INTERNAL_PARSE_H */
diff --git a/internal/proc.h b/internal/proc.h
index c75f15b283..2416c31e14 100644
--- a/internal/proc.h
+++ b/internal/proc.h
@@ -22,9 +22,11 @@ int rb_block_min_max_arity(int *max);
VALUE rb_block_to_s(VALUE self, const struct rb_block *block, const char *additional_info);
VALUE rb_callable_receiver(VALUE);
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_func_proc_new(rb_block_call_func_t func, VALUE val);
VALUE rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_argc);
VALUE rb_iseq_location(const struct rb_iseq_struct *iseq);
VALUE rb_sym_to_proc(VALUE sym);
+MJIT_SYMBOL_EXPORT_END
#endif /* INTERNAL_PROC_H */
diff --git a/internal/process.h b/internal/process.h
index fd4994cb4b..ceadfdcbbb 100644
--- a/internal/process.h
+++ b/internal/process.h
@@ -20,8 +20,8 @@
#endif
#include "ruby/ruby.h" /* for VALUE */
-#include "internal/compilers.h" /* for __has_warning */
#include "internal/imemo.h" /* for RB_IMEMO_TMPBUF_PTR */
+#include "internal/warnings.h" /* for COMPILER_WARNING_PUSH */
#define RB_MAX_GROUPS (65536)
@@ -121,4 +121,17 @@ ARGVSTR2ARGC(VALUE argv_str)
return i - 1;
}
+#ifdef HAVE_WORKING_FORK
+COMPILER_WARNING_PUSH
+#if __has_warning("-Wdeprecated-declarations") || RBIMPL_COMPILER_IS(GCC)
+COMPILER_WARNING_IGNORED(-Wdeprecated-declarations)
+#endif
+static inline rb_pid_t
+rb_fork(void)
+{
+ return fork();
+}
+COMPILER_WARNING_POP
+#endif
+
#endif /* INTERNAL_PROCESS_H */
diff --git a/internal/random.h b/internal/random.h
index 127b908e16..231e2d5d7e 100644
--- a/internal/random.h
+++ b/internal/random.h
@@ -12,6 +12,5 @@
/* random.c */
int ruby_fill_random_bytes(void *, size_t, int);
-void rb_free_default_rand_key(void);
#endif /* INTERNAL_RANDOM_H */
diff --git a/internal/range.h b/internal/range.h
index 2394937bf8..8daba0ecab 100644
--- a/internal/range.h
+++ b/internal/range.h
@@ -24,13 +24,13 @@ RANGE_BEG(VALUE r)
static inline VALUE
RANGE_END(VALUE r)
{
- return RSTRUCT_GET(r, 1);
+ return RSTRUCT(r)->as.ary[1];
}
static inline VALUE
RANGE_EXCL(VALUE r)
{
- return RSTRUCT_GET(r, 2);
+ return RSTRUCT(r)->as.ary[2];
}
VALUE
diff --git a/internal/rational.h b/internal/rational.h
index f11fab4583..61ddbf089a 100644
--- a/internal/rational.h
+++ b/internal/rational.h
@@ -10,6 +10,7 @@
*/
#include "ruby/internal/config.h" /* for HAVE_LIBGMP */
#include "ruby/ruby.h" /* for struct RBasic */
+#include "internal/gc.h" /* for RB_OBJ_WRITE */
#include "internal/numeric.h" /* for INT_POSITIVE_P */
#include "ruby_assert.h" /* for assert */
diff --git a/internal/re.h b/internal/re.h
index 3e20114665..8b31b3d8a5 100644
--- a/internal/re.h
+++ b/internal/re.h
@@ -22,7 +22,9 @@ VALUE rb_reg_equal(VALUE re1, VALUE re2);
void rb_backref_set_string(VALUE string, long pos, long len);
void rb_match_unbusy(VALUE);
int rb_match_count(VALUE match);
+int rb_match_nth_defined(int nth, VALUE match);
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_reg_new_ary(VALUE ary, int options);
-VALUE rb_reg_last_defined(VALUE match);
+MJIT_SYMBOL_EXPORT_END
#endif /* INTERNAL_RE_H */
diff --git a/internal/ruby_parser.h b/internal/ruby_parser.h
deleted file mode 100644
index 8e306d18de..0000000000
--- a/internal/ruby_parser.h
+++ /dev/null
@@ -1,102 +0,0 @@
-#ifndef INTERNAL_RUBY_PARSE_H
-#define INTERNAL_RUBY_PARSE_H
-
-#include "internal.h"
-#include "internal/bignum.h"
-#include "internal/compilers.h"
-#include "internal/complex.h"
-#include "internal/parse.h"
-#include "internal/rational.h"
-#include "rubyparser.h"
-#include "vm.h"
-
-struct lex_pointer_string {
- VALUE str;
- long ptr;
-};
-
-RUBY_SYMBOL_EXPORT_BEGIN
-#ifdef UNIVERSAL_PARSER
-const rb_parser_config_t *rb_ruby_parser_config(void);
-rb_parser_t *rb_parser_params_new(void);
-#endif
-VALUE rb_parser_set_context(VALUE, const struct rb_iseq_struct *, int);
-VALUE rb_parser_new(void);
-VALUE rb_parser_compile_string_path(VALUE vparser, VALUE fname, VALUE src, int line);
-VALUE rb_str_new_parser_string(rb_parser_string_t *str);
-VALUE rb_str_new_mutable_parser_string(rb_parser_string_t *str);
-rb_parser_string_t *rb_parser_lex_get_str(struct parser_params *p, struct lex_pointer_string *ptr_str);
-
-VALUE rb_node_str_string_val(const NODE *);
-VALUE rb_node_sym_string_val(const NODE *);
-VALUE rb_node_dstr_string_val(const NODE *);
-VALUE rb_node_regx_string_val(const NODE *);
-VALUE rb_node_dregx_string_val(const NODE *);
-VALUE rb_node_line_lineno_val(const NODE *);
-VALUE rb_node_file_path_val(const NODE *);
-VALUE rb_node_encoding_val(const NODE *);
-
-VALUE rb_node_integer_literal_val(const NODE *);
-VALUE rb_node_float_literal_val(const NODE *);
-VALUE rb_node_rational_literal_val(const NODE *);
-VALUE rb_node_imaginary_literal_val(const NODE *);
-RUBY_SYMBOL_EXPORT_END
-
-VALUE rb_parser_end_seen_p(VALUE);
-VALUE rb_parser_encoding(VALUE);
-VALUE rb_parser_set_yydebug(VALUE, VALUE);
-VALUE rb_parser_build_script_lines_from(rb_parser_ary_t *script_lines);
-void rb_parser_set_options(VALUE, int, int, int, int);
-VALUE rb_parser_load_file(VALUE parser, VALUE name);
-void rb_parser_set_script_lines(VALUE vparser);
-void rb_parser_error_tolerant(VALUE vparser);
-void rb_parser_keep_tokens(VALUE vparser);
-
-VALUE rb_parser_compile_string(VALUE, const char*, VALUE, int);
-VALUE rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE input, int line);
-VALUE rb_parser_compile_generic(VALUE vparser, rb_parser_lex_gets_func *lex_gets, VALUE fname, VALUE input, int line);
-VALUE rb_parser_compile_array(VALUE vparser, VALUE fname, VALUE array, int start);
-
-enum lex_state_bits {
- EXPR_BEG_bit, /* ignore newline, +/- is a sign. */
- EXPR_END_bit, /* newline significant, +/- is an operator. */
- EXPR_ENDARG_bit, /* ditto, and unbound braces. */
- EXPR_ENDFN_bit, /* ditto, and unbound braces. */
- EXPR_ARG_bit, /* newline significant, +/- is an operator. */
- EXPR_CMDARG_bit, /* newline significant, +/- is an operator. */
- EXPR_MID_bit, /* newline significant, +/- is an operator. */
- EXPR_FNAME_bit, /* ignore newline, no reserved words. */
- EXPR_DOT_bit, /* right after `.', `&.' or `::', no reserved words. */
- EXPR_CLASS_bit, /* immediate after `class', no here document. */
- EXPR_LABEL_bit, /* flag bit, label is allowed. */
- EXPR_LABELED_bit, /* flag bit, just after a label. */
- EXPR_FITEM_bit, /* symbol literal as FNAME. */
- EXPR_MAX_STATE
-};
-/* examine combinations */
-enum lex_state_e {
-#define DEF_EXPR(n) EXPR_##n = (1 << EXPR_##n##_bit)
- DEF_EXPR(BEG),
- DEF_EXPR(END),
- DEF_EXPR(ENDARG),
- DEF_EXPR(ENDFN),
- DEF_EXPR(ARG),
- DEF_EXPR(CMDARG),
- DEF_EXPR(MID),
- DEF_EXPR(FNAME),
- DEF_EXPR(DOT),
- DEF_EXPR(CLASS),
- DEF_EXPR(LABEL),
- DEF_EXPR(LABELED),
- DEF_EXPR(FITEM),
- EXPR_VALUE = EXPR_BEG,
- EXPR_BEG_ANY = (EXPR_BEG | EXPR_MID | EXPR_CLASS),
- EXPR_ARG_ANY = (EXPR_ARG | EXPR_CMDARG),
- EXPR_END_ANY = (EXPR_END | EXPR_ENDARG | EXPR_ENDFN),
- EXPR_NONE = 0
-};
-
-VALUE rb_ruby_ast_new(const NODE *const root);
-rb_ast_t *rb_ruby_ast_data_get(VALUE ast_value);
-
-#endif /* INTERNAL_RUBY_PARSE_H */
diff --git a/internal/sanitizers.h b/internal/sanitizers.h
index 94f4e4165a..6e2d81137f 100644
--- a/internal/sanitizers.h
+++ b/internal/sanitizers.h
@@ -16,15 +16,11 @@
#endif
#ifdef HAVE_SANITIZER_ASAN_INTERFACE_H
-# if __has_feature(address_sanitizer)
-# define RUBY_ASAN_ENABLED
-# include <sanitizer/asan_interface.h>
-# endif
+# include <sanitizer/asan_interface.h>
#endif
#ifdef HAVE_SANITIZER_MSAN_INTERFACE_H
# if __has_feature(memory_sanitizer)
-# define RUBY_MSAN_ENABLED
# include <sanitizer/msan_interface.h>
# endif
#endif
@@ -33,10 +29,10 @@
#include "ruby/ruby.h" /* for VALUE */
#if 0
-#elif defined(RUBY_ASAN_ENABLED) && defined(RUBY_MSAN_ENABLED)
+#elif __has_feature(memory_sanitizer) && __has_feature(address_sanitizer)
# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
__attribute__((__no_sanitize__("memory, address"), __noinline__)) x
-#elif defined(RUBY_ASAN_ENABLED)
+#elif __has_feature(address_sanitizer)
# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(x) \
__attribute__((__no_sanitize__("address"), __noinline__)) x
#elif defined(NO_SANITIZE_ADDRESS)
@@ -64,15 +60,13 @@
# define NO_SANITIZE(x, y) y
#endif
-#ifndef RUBY_ASAN_ENABLED
+#if !__has_feature(address_sanitizer)
# define __asan_poison_memory_region(x, y)
# define __asan_unpoison_memory_region(x, y)
# define __asan_region_is_poisoned(x, y) 0
-# define __asan_get_current_fake_stack() NULL
-# define __asan_addr_is_in_fake_stack(fake_stack, slot, start, end) NULL
#endif
-#ifndef RUBY_MSAN_ENABLED
+#if !__has_feature(memory_sanitizer)
# define __msan_allocated_memory(x, y) ((void)(x), (void)(y))
# define __msan_poison(x, y) ((void)(x), (void)(y))
# define __msan_unpoison(x, y) ((void)(x), (void)(y))
@@ -95,7 +89,9 @@
# define VALGRIND_MAKE_MEM_UNDEFINED(p, n) 0
#endif
-/**
+#ifndef MJIT_HEADER
+
+/*!
* This function asserts that a (continuous) memory region from ptr to size
* being "poisoned". Both read / write access to such memory region are
* prohibited until properly unpoisoned. The region must be previously
@@ -105,8 +101,8 @@
* region to reuse later: poison when you keep it unused, and unpoison when you
* reuse.
*
- * @param[in] ptr pointer to the beginning of the memory region to poison.
- * @param[in] size the length of the memory region to poison.
+ * \param[in] ptr pointer to the beginning of the memory region to poison.
+ * \param[in] size the length of the memory region to poison.
*/
static inline void
asan_poison_memory_region(const volatile void *ptr, size_t size)
@@ -115,10 +111,10 @@ asan_poison_memory_region(const volatile void *ptr, size_t size)
__asan_poison_memory_region(ptr, size);
}
-/**
+/*!
* This is a variant of asan_poison_memory_region that takes a VALUE.
*
- * @param[in] obj target object.
+ * \param[in] obj target object.
*/
static inline void
asan_poison_object(VALUE obj)
@@ -127,20 +123,20 @@ asan_poison_object(VALUE obj)
asan_poison_memory_region(ptr, SIZEOF_VALUE);
}
-#ifdef RUBY_ASAN_ENABLED
+#if !__has_feature(address_sanitizer)
+#define asan_poison_object_if(ptr, obj) ((void)(ptr), (void)(obj))
+#else
#define asan_poison_object_if(ptr, obj) do { \
if (ptr) asan_poison_object(obj); \
} while (0)
-#else
-#define asan_poison_object_if(ptr, obj) ((void)(ptr), (void)(obj))
#endif
-/**
+/*!
* This function predicates if the given object is fully addressable or not.
*
- * @param[in] obj target object.
- * @retval 0 the given object is fully addressable.
- * @retval otherwise pointer to first such byte who is poisoned.
+ * \param[in] obj target object.
+ * \retval 0 the given object is fully addressable.
+ * \retval otherwise pointer to first such byte who is poisoned.
*/
static inline void *
asan_poisoned_object_p(VALUE obj)
@@ -149,7 +145,7 @@ asan_poisoned_object_p(VALUE obj)
return __asan_region_is_poisoned(ptr, SIZEOF_VALUE);
}
-/**
+/*!
* This function asserts that a (formally poisoned) memory region from ptr to
* size is now addressable. Write access to such memory region gets allowed.
* However read access might or might not be possible depending on situations,
@@ -160,9 +156,9 @@ asan_poisoned_object_p(VALUE obj)
* the other hand, that memory region is fully defined and can be read
* immediately.
*
- * @param[in] ptr pointer to the beginning of the memory region to unpoison.
- * @param[in] size the length of the memory region.
- * @param[in] malloc_p if the memory region is like a malloc's return value or not.
+ * \param[in] ptr pointer to the beginning of the memory region to unpoison.
+ * \param[in] size the length of the memory region.
+ * \param[in] malloc_p if the memory region is like a malloc's return value or not.
*/
static inline void
asan_unpoison_memory_region(const volatile void *ptr, size_t size, bool malloc_p)
@@ -176,11 +172,11 @@ asan_unpoison_memory_region(const volatile void *ptr, size_t size, bool malloc_p
}
}
-/**
+/*!
* This is a variant of asan_unpoison_memory_region that takes a VALUE.
*
- * @param[in] obj target object.
- * @param[in] malloc_p if the memory region is like a malloc's return value or not.
+ * \param[in] obj target object.
+ * \param[in] malloc_p if the memory region is like a malloc's return value or not.
*/
static inline void
asan_unpoison_object(VALUE obj, bool newobj_p)
@@ -189,138 +185,6 @@ asan_unpoison_object(VALUE obj, bool newobj_p)
asan_unpoison_memory_region(ptr, SIZEOF_VALUE, newobj_p);
}
-static inline void *
-asan_unpoison_object_temporary(VALUE obj)
-{
- void *ptr = asan_poisoned_object_p(obj);
- asan_unpoison_object(obj, false);
- return ptr;
-}
-
-static inline void *
-asan_poison_object_restore(VALUE obj, void *ptr)
-{
- if (ptr) {
- asan_poison_object(obj);
- }
- return NULL;
-}
-
-#define asan_unpoisoning_object(obj) \
- for (void *poisoned = asan_unpoison_object_temporary(obj), \
- *unpoisoning = &poisoned; /* flag to loop just once */ \
- unpoisoning; \
- unpoisoning = asan_poison_object_restore(obj, poisoned))
-
-
-static inline void *
-asan_unpoison_memory_region_temporary(void *ptr, size_t len)
-{
- void *poisoned_ptr = __asan_region_is_poisoned(ptr, len);
- asan_unpoison_memory_region(ptr, len, false);
- return poisoned_ptr;
-}
-
-static inline void *
-asan_poison_memory_region_restore(void *ptr, size_t len, void *poisoned_ptr)
-{
- if (poisoned_ptr) {
- asan_poison_memory_region(ptr, len);
- }
- return NULL;
-}
-
-#define asan_unpoisoning_memory_region(ptr, len) \
- for (void *poisoned = asan_unpoison_memory_region_temporary(ptr, len), \
- *unpoisoning = &poisoned; /* flag to loop just once */ \
- unpoisoning; \
- unpoisoning = asan_poison_memory_region_restore(ptr, len, poisoned))
-
-/**
- * Checks if the given pointer is on an ASAN fake stack. If so, it returns the
- * address this variable has on the real frame; if not, it returns the origin
- * address unmodified.
- *
- * n.b. - _dereferencing_ the returned address is meaningless and should not
- * be done; even though ASAN reserves space for the variable in both the real and
- * fake stacks, the _value_ of that variable is only in the fake stack.
- *
- * n.b. - this only works for addresses passed in from local variables on the same
- * thread, because the ASAN fake stacks are threadlocal.
- *
- * @param[in] slot the address of some local variable
- * @retval a pointer to something from that frame on the _real_ machine stack
- */
-static inline void *
-asan_get_real_stack_addr(void* slot)
-{
- VALUE *addr;
- addr = __asan_addr_is_in_fake_stack(__asan_get_current_fake_stack(), slot, NULL, NULL);
- return addr ? addr : slot;
-}
-
-/**
- * Gets the current thread's fake stack handle, which can be passed into get_fake_stack_extents
- *
- * @retval An opaque value which can be passed to asan_get_fake_stack_extents
- */
-static inline void *
-asan_get_thread_fake_stack_handle(void)
-{
- return __asan_get_current_fake_stack();
-}
-
-/**
- * Checks if the given VALUE _actually_ represents a pointer to an ASAN fake stack.
- *
- * If the given slot _is_ actually a reference to an ASAN fake stack, and that fake stack
- * contains the real values for the passed-in range of machine stack addresses, returns true
- * and the range of the fake stack through the outparams.
- *
- * Otherwise, returns false, and sets the outparams to NULL.
- *
- * Note that this function expects "start" to be > "end" on downward-growing stack architectures;
- *
- * @param[in] thread_fake_stack_handle The asan fake stack reference for the thread we're scanning
- * @param[in] slot The value on the machine stack we want to inspect
- * @param[in] machine_stack_start The extents of the real machine stack on which slot lives
- * @param[in] machine_stack_end The extents of the real machine stack on which slot lives
- * @param[out] fake_stack_start_out The extents of the fake stack which contains real VALUEs
- * @param[out] fake_stack_end_out The extents of the fake stack which contains real VALUEs
- * @return Whether slot is a pointer to a fake stack for the given machine stack range
-*/
-
-static inline bool
-asan_get_fake_stack_extents(void *thread_fake_stack_handle, VALUE slot,
- void *machine_stack_start, void *machine_stack_end,
- void **fake_stack_start_out, void **fake_stack_end_out)
-{
- /* the ifdef is needed here to suppress a warning about fake_frame_{start/end} being
- uninitialized if __asan_addr_is_in_fake_stack is an empty macro */
-#ifdef RUBY_ASAN_ENABLED
- void *fake_frame_start;
- void *fake_frame_end;
- void *real_stack_frame = __asan_addr_is_in_fake_stack(
- thread_fake_stack_handle, (void *)slot, &fake_frame_start, &fake_frame_end
- );
- if (real_stack_frame) {
- bool in_range;
-#if STACK_GROW_DIRECTION < 0
- in_range = machine_stack_start >= real_stack_frame && real_stack_frame >= machine_stack_end;
-#else
- in_range = machine_stack_start <= real_stack_frame && real_stack_frame <= machine_stack_end;
-#endif
- if (in_range) {
- *fake_stack_start_out = fake_frame_start;
- *fake_stack_end_out = fake_frame_end;
- return true;
- }
- }
-#endif
- *fake_stack_start_out = 0;
- *fake_stack_end_out = 0;
- return false;
-}
-
+#endif /* MJIT_HEADER */
#endif /* INTERNAL_SANITIZERS_H */
diff --git a/internal/signal.h b/internal/signal.h
index 2363bf412c..86fb54e949 100644
--- a/internal/signal.h
+++ b/internal/signal.h
@@ -13,12 +13,9 @@
extern int ruby_enable_coredump;
int rb_get_next_signal(void);
-#ifdef POSIX_SIGNAL
-void (*ruby_posix_signal(int, void (*)(int)))(int);
-#endif
-
RUBY_SYMBOL_EXPORT_BEGIN
/* signal.c (export) */
+int rb_grantpt(int fd);
RUBY_SYMBOL_EXPORT_END
#endif /* INTERNAL_SIGNAL_H */
diff --git a/internal/st.h b/internal/st.h
deleted file mode 100644
index a26b224505..0000000000
--- a/internal/st.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef INTERNAL_ST_H
-#define INTERNAL_ST_H
-
-#include "include/ruby/st.h"
-
-st_table *rb_st_replace(st_table *new_tab, st_table *old_tab);
-#define st_replace rb_st_replace
-st_table *rb_st_init_existing_table_with_size(st_table *tab, const struct st_hash_type *type, st_index_t size);
-#define st_init_existing_table_with_size rb_st_init_existing_table_with_size
-
-#endif
diff --git a/internal/string.h b/internal/string.h
index 10879bd1d9..12edbff2b1 100644
--- a/internal/string.h
+++ b/internal/string.h
@@ -17,11 +17,6 @@
#define STR_NOEMBED FL_USER1
#define STR_SHARED FL_USER2 /* = ELTS_SHARED */
-#define STR_CHILLED FL_USER3
-
-enum ruby_rstring_private_flags {
- RSTRING_CHILLED = STR_CHILLED,
-};
#ifdef rb_fstring_cstr
# undef rb_fstring_cstr
@@ -50,13 +45,6 @@ void rb_str_make_independent(VALUE str);
int rb_enc_str_coderange_scan(VALUE str, rb_encoding *enc);
int rb_ascii8bit_appendable_encoding_index(rb_encoding *enc, unsigned int code);
VALUE rb_str_include(VALUE str, VALUE arg);
-VALUE rb_str_byte_substr(VALUE str, VALUE beg, VALUE len);
-VALUE rb_str_tmp_frozen_no_embed_acquire(VALUE str);
-void rb_str_make_embedded(VALUE);
-VALUE rb_str_upto_each(VALUE, VALUE, int, int (*each)(VALUE, VALUE), VALUE);
-size_t rb_str_size_as_embedded(VALUE);
-bool rb_str_reembeddable_p(VALUE);
-VALUE rb_str_upto_endless_each(VALUE, int (*each)(VALUE, VALUE), VALUE);
static inline bool STR_EMBED_P(VALUE str);
static inline bool STR_SHARED_P(VALUE str);
@@ -71,8 +59,15 @@ RUBY_SYMBOL_EXPORT_BEGIN
VALUE rb_str_tmp_frozen_acquire(VALUE str);
void rb_str_tmp_frozen_release(VALUE str, VALUE tmp);
VALUE rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb_encoding *enc);
+VALUE rb_str_upto_each(VALUE, VALUE, int, int (*each)(VALUE, VALUE), VALUE);
+VALUE rb_str_upto_endless_each(VALUE, int (*each)(VALUE, VALUE), VALUE);
+void rb_str_make_embedded(VALUE);
+size_t rb_str_size_as_embedded(VALUE);
+bool rb_str_reembeddable_p(VALUE);
+void rb_str_update_shared_ary(VALUE str, VALUE old_root, VALUE new_root);
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_fstring_new(const char *ptr, long len);
VALUE rb_obj_as_string_result(VALUE str, VALUE obj);
VALUE rb_str_opt_plus(VALUE x, VALUE y);
@@ -80,10 +75,10 @@ VALUE rb_str_concat_literals(size_t num, const VALUE *strary);
VALUE rb_str_eql(VALUE str1, VALUE str2);
VALUE rb_id_quote_unprintable(ID);
VALUE rb_sym_proc_call(ID mid, int argc, const VALUE *argv, int kw_splat, VALUE passed_proc);
-VALUE rb_enc_literal_str(const char *ptr, long len, rb_encoding *enc);
struct rb_execution_context_struct;
-VALUE rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str, bool chilled);
+VALUE rb_ec_str_resurrect(struct rb_execution_context_struct *ec, VALUE str);
+MJIT_SYMBOL_EXPORT_END
#define rb_fstring_lit(str) rb_fstring_new((str), rb_strlen_lit(str))
#define rb_fstring_literal(str) rb_fstring_lit(str)
@@ -115,25 +110,6 @@ STR_SHARED_P(VALUE str)
}
static inline bool
-CHILLED_STRING_P(VALUE obj)
-{
- return RB_TYPE_P(obj, T_STRING) && FL_TEST_RAW(obj, STR_CHILLED);
-}
-
-static inline void
-CHILLED_STRING_MUTATED(VALUE str)
-{
- FL_UNSET_RAW(str, STR_CHILLED);
- rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "literal string will be frozen in the future");
-}
-
-static inline void
-STR_CHILL_RAW(VALUE str)
-{
- FL_SET_RAW(str, STR_CHILLED);
-}
-
-static inline bool
is_ascii_string(VALUE str)
{
return rb_enc_str_coderange(str) == ENC_CODERANGE_7BIT;
@@ -145,21 +121,6 @@ is_broken_string(VALUE str)
return rb_enc_str_coderange(str) == ENC_CODERANGE_BROKEN;
}
-static inline bool
-at_char_boundary(const char *s, const char *p, const char *e, rb_encoding *enc)
-{
- return rb_enc_left_char_head(s, p, e, enc) == p;
-}
-
-static inline bool
-at_char_right_boundary(const char *s, const char *p, const char *e, rb_encoding *enc)
-{
- RUBY_ASSERT(s <= p);
- RUBY_ASSERT(p <= e);
-
- return rb_enc_right_char_head(s, p, e, enc) == p;
-}
-
/* expect tail call optimization */
// YJIT needs this function to never allocate and never raise
static inline VALUE
diff --git a/internal/struct.h b/internal/struct.h
index 6da5bad10a..8acc00ec3c 100644
--- a/internal/struct.h
+++ b/internal/struct.h
@@ -9,12 +9,14 @@
* @brief Internal header for Struct.
*/
#include "ruby/internal/stdbool.h" /* for bool */
+#include "internal/gc.h" /* for RB_OBJ_WRITE */
#include "ruby/ruby.h" /* for struct RBasic */
enum {
- RSTRUCT_EMBED_LEN_MASK = RUBY_FL_USER7 | RUBY_FL_USER6 | RUBY_FL_USER5 | RUBY_FL_USER4 |
- RUBY_FL_USER3 | RUBY_FL_USER2 | RUBY_FL_USER1,
+ RSTRUCT_EMBED_LEN_MAX = RVALUE_EMBED_LEN_MAX,
+ RSTRUCT_EMBED_LEN_MASK = (RUBY_FL_USER2|RUBY_FL_USER1),
RSTRUCT_EMBED_LEN_SHIFT = (RUBY_FL_USHIFT+1),
+ RSTRUCT_TRANSIENT_FLAG = FL_USER3,
};
struct RStruct {
@@ -24,12 +26,7 @@ struct RStruct {
long len;
const VALUE *ptr;
} heap;
- /* This is a length 1 array because:
- * 1. GCC has a bug that does not optimize C flexible array members
- * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452)
- * 2. Zero length arrays are not supported by all compilers
- */
- const VALUE ary[1];
+ const VALUE ary[RSTRUCT_EMBED_LEN_MAX];
} as;
};
@@ -60,6 +57,9 @@ VALUE rb_struct_init_copy(VALUE copy, VALUE s);
VALUE rb_struct_lookup(VALUE s, VALUE idx);
VALUE rb_struct_s_keyword_init(VALUE klass);
static inline const VALUE *rb_struct_const_heap_ptr(VALUE st);
+static inline bool RSTRUCT_TRANSIENT_P(VALUE st);
+static inline void RSTRUCT_TRANSIENT_SET(VALUE st);
+static inline void RSTRUCT_TRANSIENT_UNSET(VALUE st);
static inline long RSTRUCT_EMBED_LEN(VALUE st);
static inline long RSTRUCT_LEN(VALUE st);
static inline int RSTRUCT_LENINT(VALUE st);
@@ -67,6 +67,32 @@ static inline const VALUE *RSTRUCT_CONST_PTR(VALUE st);
static inline void RSTRUCT_SET(VALUE st, long k, VALUE v);
static inline VALUE RSTRUCT_GET(VALUE st, long k);
+static inline bool
+RSTRUCT_TRANSIENT_P(VALUE st)
+{
+#if USE_TRANSIENT_HEAP
+ return FL_TEST_RAW(st, RSTRUCT_TRANSIENT_FLAG);
+#else
+ return false;
+#endif
+}
+
+static inline void
+RSTRUCT_TRANSIENT_SET(VALUE st)
+{
+#if USE_TRANSIENT_HEAP
+ FL_SET_RAW(st, RSTRUCT_TRANSIENT_FLAG);
+#endif
+}
+
+static inline void
+RSTRUCT_TRANSIENT_UNSET(VALUE st)
+{
+#if USE_TRANSIENT_HEAP
+ FL_UNSET_RAW(st, RSTRUCT_TRANSIENT_FLAG);
+#endif
+}
+
static inline long
RSTRUCT_EMBED_LEN(VALUE st)
{
@@ -120,7 +146,7 @@ RSTRUCT_GET(VALUE st, long k)
static inline const VALUE *
rb_struct_const_heap_ptr(VALUE st)
{
- assert(!FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK));
+ /* TODO: check embed on debug mode */
return RSTRUCT(st)->as.heap.ptr;
}
diff --git a/internal/symbol.h b/internal/symbol.h
index e7730cb70f..30c81ea004 100644
--- a/internal/symbol.h
+++ b/internal/symbol.h
@@ -32,9 +32,6 @@ ID rb_make_temporary_id(size_t n);
void rb_gc_free_dsymbol(VALUE);
int rb_static_id_valid_p(ID id);
-/* vm.c */
-void rb_free_static_symid_str(void);
-
#if __has_builtin(__builtin_constant_p)
#define rb_sym_intern_ascii_cstr(ptr) \
(__builtin_constant_p(ptr) ? \
diff --git a/internal/thread.h b/internal/thread.h
index e079ebb22b..c3e54de683 100644
--- a/internal/thread.h
+++ b/internal/thread.h
@@ -10,17 +10,9 @@
*/
#include "ruby/ruby.h" /* for VALUE */
#include "ruby/intern.h" /* for rb_blocking_function_t */
-#include "ccan/list/list.h" /* for list in rb_io_close_wait_list */
struct rb_thread_struct; /* in vm_core.h */
-#define RB_VM_SAVE_MACHINE_CONTEXT(th) \
- do { \
- FLUSH_REGISTER_WINDOWS; \
- setjmp((th)->ec->machine.regs); \
- SET_MACHINE_STACK_END(&(th)->ec->machine.stack_end); \
- } while (0)
-
/* thread.c */
#define COVERAGE_INDEX_LINES 0
#define COVERAGE_INDEX_BRANCHES 1
@@ -30,10 +22,6 @@ struct rb_thread_struct; /* in vm_core.h */
#define COVERAGE_TARGET_ONESHOT_LINES 8
#define COVERAGE_TARGET_EVAL 16
-#define RUBY_FATAL_THREAD_KILLED INT2FIX(0)
-#define RUBY_FATAL_THREAD_TERMINATED INT2FIX(1)
-#define RUBY_FATAL_FIBER_KILLED RB_INT2FIX(2)
-
VALUE rb_obj_is_mutex(VALUE obj);
VALUE rb_suppress_tracing(VALUE (*func)(VALUE), VALUE arg);
void rb_thread_execute_interrupts(VALUE th);
@@ -46,40 +34,23 @@ VALUE rb_thread_shield_wait(VALUE self);
VALUE rb_thread_shield_release(VALUE self);
VALUE rb_thread_shield_destroy(VALUE self);
int rb_thread_to_be_killed(VALUE thread);
-void rb_thread_acquire_fork_lock(void);
-void rb_thread_release_fork_lock(void);
-void rb_thread_reset_fork_lock(void);
void rb_mutex_allow_trap(VALUE self, int val);
VALUE rb_uninterruptible(VALUE (*b_proc)(VALUE), VALUE data);
VALUE rb_mutex_owned_p(VALUE self);
VALUE rb_exec_recursive_outer_mid(VALUE (*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h, ID mid);
-void ruby_mn_threads_params(void);
int rb_thread_wait_for_single_fd(int fd, int events, struct timeval * timeout);
-struct rb_io_close_wait_list {
- struct ccan_list_head pending_fd_users;
- VALUE closing_thread;
- VALUE closing_fiber;
- VALUE wakeup_mutex;
-};
-int rb_notify_fd_close(int fd, struct rb_io_close_wait_list *busy);
-void rb_notify_fd_close_wait(struct rb_io_close_wait_list *busy);
-
RUBY_SYMBOL_EXPORT_BEGIN
-
-void *rb_thread_prevent_fork(void *(*func)(void *), void *data); /* for ext/socket/raddrinfo.c */
-
/* Temporary. This API will be removed (renamed). */
VALUE rb_thread_io_blocking_region(rb_blocking_function_t *func, void *data1, int fd);
-VALUE rb_thread_io_blocking_call(rb_blocking_function_t *func, void *data1, int fd, int events);
/* thread.c (export) */
int ruby_thread_has_gvl_p(void); /* for ext/fiddle/closure.c */
-
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
int rb_threadptr_execute_interrupts(struct rb_thread_struct *th, int blocking_timing);
-bool rb_thread_mn_schedulable(VALUE thread);
+MJIT_SYMBOL_EXPORT_END
#endif /* INTERNAL_THREAD_H */
diff --git a/internal/time.h b/internal/time.h
index a3bf0587ec..e21b3574f6 100644
--- a/internal/time.h
+++ b/internal/time.h
@@ -28,7 +28,10 @@ struct timeval rb_time_timeval(VALUE);
RUBY_SYMBOL_EXPORT_BEGIN
/* time.c (export) */
void ruby_reset_leap_second_info(void);
-void ruby_reset_timezone(void);
+#ifdef RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY
+RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY()
+#endif
+void ruby_reset_timezone(const char *);
RUBY_SYMBOL_EXPORT_END
#endif /* INTERNAL_TIME_H */
diff --git a/internal/transcode.h b/internal/transcode.h
index ce4f2341be..9922332ea9 100644
--- a/internal/transcode.h
+++ b/internal/transcode.h
@@ -17,7 +17,4 @@
extern VALUE rb_cEncodingConverter;
size_t rb_econv_memsize(rb_econv_t *);
-/* vm.c */
-void rb_free_transcoder_table(void);
-
#endif /* INTERNAL_TRANSCODE_H */
diff --git a/internal/variable.h b/internal/variable.h
index b2a30c7c58..6dec6a6759 100644
--- a/internal/variable.h
+++ b/internal/variable.h
@@ -15,6 +15,10 @@
#include "ruby/ruby.h" /* for VALUE */
#include "shape.h" /* for rb_shape_t */
+/* global variable */
+
+#define ROBJECT_TRANSIENT_FLAG FL_USER2
+
/* variable.c */
void rb_gc_mark_global_tbl(void);
void rb_gc_update_global_tbl(void);
@@ -28,45 +32,59 @@ rb_gvar_getter_t *rb_gvar_getter_function_of(ID);
rb_gvar_setter_t *rb_gvar_setter_function_of(ID);
void rb_gvar_readonly_setter(VALUE v, ID id, VALUE *_);
void rb_gvar_ractor_local(const char *name);
-
-/**
- * Sets the name of a module.
- *
- * Non-permanently named classes can have a temporary name assigned (or
- * cleared). In that case the name will be used for `#inspect` and `#to_s`, and
- * nested classes/modules will be named with the temporary name as a prefix.
- *
- * After the module is assigned to a constant, the temporary name will be
- * discarded, and the name will be computed based on the nesting.
- *
- * @param[in] mod An instance of ::rb_cModule.
- * @param[in] name An instance of ::rb_cString.
- * @retval mod
- */
-VALUE rb_mod_set_temporary_name(VALUE, VALUE);
+static inline bool ROBJ_TRANSIENT_P(VALUE obj);
+static inline void ROBJ_TRANSIENT_SET(VALUE obj);
+static inline void ROBJ_TRANSIENT_UNSET(VALUE obj);
struct gen_ivtbl;
int rb_gen_ivtbl_get(VALUE obj, ID id, struct gen_ivtbl **ivtbl);
-void rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table);
-void rb_obj_convert_to_too_complex(VALUE obj, st_table *table);
-void rb_evict_ivars_to_hash(VALUE obj);
+int rb_obj_evacuate_ivs_to_hash_table(ID key, VALUE val, st_data_t arg);
RUBY_SYMBOL_EXPORT_BEGIN
/* variable.c (export) */
-void rb_mark_generic_ivar(VALUE obj);
-void rb_ref_update_generic_ivar(VALUE);
+void rb_mark_generic_ivar(VALUE);
void rb_mv_generic_ivar(VALUE src, VALUE dst);
VALUE rb_const_missing(VALUE klass, VALUE name);
int rb_class_ivar_set(VALUE klass, ID vid, VALUE value);
void rb_iv_tbl_copy(VALUE dst, VALUE src);
RUBY_SYMBOL_EXPORT_END
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_ivar_lookup(VALUE obj, ID id, VALUE undef);
VALUE rb_gvar_get(ID);
VALUE rb_gvar_set(ID, VALUE);
VALUE rb_gvar_defined(ID);
void rb_const_warn_if_deprecated(const rb_const_entry_t *, VALUE, ID);
+rb_shape_t * rb_grow_iv_list(VALUE obj);
void rb_ensure_iv_list_size(VALUE obj, uint32_t len, uint32_t newsize);
+struct gen_ivtbl *rb_ensure_generic_iv_list_size(VALUE obj, rb_shape_t *shape, uint32_t newsize);
attr_index_t rb_obj_ivar_set(VALUE obj, ID id, VALUE val);
+MJIT_SYMBOL_EXPORT_END
+
+static inline bool
+ROBJ_TRANSIENT_P(VALUE obj)
+{
+#if USE_TRANSIENT_HEAP
+ return FL_TEST_RAW(obj, ROBJECT_TRANSIENT_FLAG);
+#else
+ return false;
+#endif
+}
+
+static inline void
+ROBJ_TRANSIENT_SET(VALUE obj)
+{
+#if USE_TRANSIENT_HEAP
+ FL_SET_RAW(obj, ROBJECT_TRANSIENT_FLAG);
+#endif
+}
+
+static inline void
+ROBJ_TRANSIENT_UNSET(VALUE obj)
+{
+#if USE_TRANSIENT_HEAP
+ FL_UNSET_RAW(obj, ROBJECT_TRANSIENT_FLAG);
+#endif
+}
#endif /* INTERNAL_VARIABLE_H */
diff --git a/internal/vm.h b/internal/vm.h
index 380742165d..cf245c6579 100644
--- a/internal/vm.h
+++ b/internal/vm.h
@@ -45,25 +45,29 @@ VALUE rb_vm_push_frame_fname(struct rb_execution_context_struct *ec, VALUE fname
/* vm.c */
VALUE rb_obj_is_thread(VALUE obj);
void rb_vm_mark(void *ptr);
-void rb_vm_register_global_object(VALUE obj);
void rb_vm_each_stack_value(void *ptr, void (*cb)(VALUE, void*), void *ctx);
PUREFUNC(VALUE rb_vm_top_self(void));
const void **rb_vm_get_insns_address_table(void);
VALUE rb_source_location(int *pline);
const char *rb_source_location_cstr(int *pline);
-void rb_vm_pop_cfunc_frame(void);
+MJIT_STATIC void rb_vm_pop_cfunc_frame(void);
+int rb_vm_add_root_module(VALUE module);
void rb_vm_check_redefinition_by_prepend(VALUE klass);
int rb_vm_check_optimizable_mid(VALUE mid);
VALUE rb_yield_refine_block(VALUE refinement, VALUE refinements);
-VALUE ruby_vm_special_exception_copy(VALUE);
+MJIT_STATIC VALUE ruby_vm_special_exception_copy(VALUE);
PUREFUNC(st_table *rb_vm_fstring_table(void));
-void rb_lastline_set_up(VALUE val, unsigned int up);
+MJIT_SYMBOL_EXPORT_BEGIN
+VALUE vm_exec(struct rb_execution_context_struct *, bool); /* used in JIT-ed code */
+MJIT_SYMBOL_EXPORT_END
/* vm_eval.c */
VALUE rb_current_realfilepath(void);
VALUE rb_check_block_call(VALUE, ID, int, const VALUE *, rb_block_call_func_t, VALUE);
typedef void rb_check_funcall_hook(int, VALUE, ID, int, const VALUE *, VALUE);
+VALUE rb_check_funcall_with_hook(VALUE recv, ID mid, int argc, const VALUE *argv,
+ rb_check_funcall_hook *hook, VALUE arg);
VALUE rb_check_funcall_with_hook_kw(VALUE recv, ID mid, int argc, const VALUE *argv,
rb_check_funcall_hook *hook, VALUE arg, int kw_splat);
const char *rb_type_str(enum ruby_value_type type);
@@ -75,34 +79,26 @@ VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv,
rb_block_call_func_t bl_proc, int min_argc, int max_argc,
VALUE data2);
void rb_check_stack_overflow(void);
-#define RB_BLOCK_NO_USE_PACKED_ARGS 2
-VALUE rb_block_call2(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t bl_proc, VALUE data2, long flags);
-
-#if USE_YJIT
-/* vm_exec.c */
-extern uint64_t rb_vm_insns_count;
-#endif
-
-extern bool rb_free_at_exit;
-
-/* miniinit.c and builtin.c */
-void rb_free_loaded_builtin_table(void);
/* vm_insnhelper.c */
VALUE rb_equal_opt(VALUE obj1, VALUE obj2);
VALUE rb_eql_opt(VALUE obj1, VALUE obj2);
struct rb_iseq_struct;
+MJIT_SYMBOL_EXPORT_BEGIN
const struct rb_callcache *rb_vm_search_method_slowpath(const struct rb_callinfo *ci, VALUE klass);
+MJIT_SYMBOL_EXPORT_END
/* vm_method.c */
struct rb_execution_context_struct;
+MJIT_SYMBOL_EXPORT_BEGIN
int rb_ec_obj_respond_to(struct rb_execution_context_struct *ec, VALUE obj, ID id, int priv);
+MJIT_SYMBOL_EXPORT_END
void rb_clear_constant_cache(void);
/* vm_dump.c */
-void rb_print_backtrace(FILE *);
+void rb_print_backtrace(void);
/* vm_backtrace.c */
VALUE rb_vm_thread_backtrace(int argc, const VALUE *argv, VALUE thval);
@@ -110,18 +106,19 @@ VALUE rb_vm_thread_backtrace_locations(int argc, const VALUE *argv, VALUE thval)
VALUE rb_vm_backtrace(int argc, const VALUE * argv, struct rb_execution_context_struct * ec);
VALUE rb_vm_backtrace_locations(int argc, const VALUE * argv, struct rb_execution_context_struct * ec);
VALUE rb_make_backtrace(void);
-void rb_backtrace_print_as_bugreport(FILE*);
+void rb_backtrace_print_as_bugreport(void);
int rb_backtrace_p(VALUE obj);
VALUE rb_backtrace_to_str_ary(VALUE obj);
VALUE rb_backtrace_to_location_ary(VALUE obj);
-VALUE rb_location_ary_to_backtrace(VALUE ary);
void rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output);
int rb_frame_info_p(VALUE obj);
int rb_get_node_id_from_frame_info(VALUE obj);
const struct rb_iseq_struct *rb_get_iseq_from_frame_info(VALUE obj);
+MJIT_SYMBOL_EXPORT_BEGIN
VALUE rb_ec_backtrace_object(const struct rb_execution_context_struct *ec);
void rb_backtrace_use_iseq_first_lineno_for_last_location(VALUE self);
+MJIT_SYMBOL_EXPORT_END
#define RUBY_DTRACE_CREATE_HOOK(name, arg) \
RUBY_DTRACE_HOOK(name##_CREATE, arg)
diff --git a/io.c b/io.c
index b26f71056f..99ec59da29 100644
--- a/io.c
+++ b/io.c
@@ -16,6 +16,11 @@
#include "ruby/fiber/scheduler.h"
#include "ruby/io/buffer.h"
+#ifdef _WIN32
+# include "ruby/ruby.h"
+# include "ruby/io.h"
+#endif
+
#include <ctype.h>
#include <errno.h>
#include <stddef.h>
@@ -104,16 +109,6 @@
#ifdef HAVE_COPYFILE_H
# include <copyfile.h>
-
-# ifndef COPYFILE_STATE_COPIED
-/*
- * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
- * COPYFILE_STATE_COPIED. Since the only use of the former here
- * requires the latter, we disable the former when the latter is undefined.
- */
-# undef HAVE_FCOPYFILE
-# endif
-
#endif
#include "ruby/internal/stdbool.h"
@@ -122,7 +117,6 @@
#include "encindex.h"
#include "id.h"
#include "internal.h"
-#include "internal/class.h"
#include "internal/encoding.h"
#include "internal/error.h"
#include "internal/inits.h"
@@ -181,7 +175,6 @@ off_t __syscall(quad_t number, ...);
#define open rb_w32_uopen
#undef rename
#define rename(f, t) rb_w32_urename((f), (t))
-#include "win32/file.h"
#endif
VALUE rb_cIO;
@@ -222,24 +215,13 @@ static VALUE sym_HOLE;
static VALUE prep_io(int fd, int fmode, VALUE klass, const char *path);
-VALUE
-rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
-{
- return rb_thread_io_blocking_call(function, argument, io->fd, events);
-}
-
-VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
-{
- return rb_io_blocking_region_wait(io, function, argument, 0);
-}
-
struct argf {
VALUE filename, current_file;
long last_lineno; /* $. */
long lineno;
VALUE argv;
VALUE inplace;
- struct rb_io_encoding encs;
+ struct rb_io_enc_t encs;
int8_t init_p, next_p, binmode;
};
@@ -543,6 +525,7 @@ rb_cloexec_fcntl_dupfd(int fd, int minfd)
static int io_fflush(rb_io_t *);
static rb_io_t *flush_before_seek(rb_io_t *fptr);
+#define FMODE_PREP (1<<16)
#define FMODE_SIGNAL_ON_EPIPE (1<<17)
#define fptr_signal_on_epipe(fptr) \
@@ -555,12 +538,10 @@ static rb_io_t *flush_before_seek(rb_io_t *fptr);
extern ID ruby_static_id_signo;
-NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
+NORETURN(static void raise_on_write(rb_io_t *fptr, int e, VALUE errinfo));
static void
-rb_sys_fail_on_write(rb_io_t *fptr)
+raise_on_write(rb_io_t *fptr, int e, VALUE errinfo)
{
- int e = errno;
- VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
#if defined EPIPE
if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
const VALUE sig =
@@ -574,6 +555,12 @@ rb_sys_fail_on_write(rb_io_t *fptr)
rb_exc_raise(errinfo);
}
+#define rb_sys_fail_on_write(fptr) \
+ do { \
+ int e = errno; \
+ raise_on_write(fptr, e, rb_syserr_new_path(e, (fptr)->pathv)); \
+ } while (0)
+
#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
@@ -865,12 +852,9 @@ rb_io_timeout(VALUE self)
* timeout = duration -> duration
* timeout = nil -> nil
*
- * Sets the internal timeout to the specified duration or nil. The timeout
+ * Set the internal timeout to the specified duration or nil. The timeout
* applies to all blocking operations where possible.
*
- * When the operation performs longer than the timeout set, IO::TimeoutError
- * is raised.
- *
* This affects the following methods (but is not limited to): #gets, #puts,
* #read, #write, #wait_readable and #wait_writable. This also affects
* blocking socket operations like Socket#accept and Socket#connect.
@@ -1082,24 +1066,20 @@ rb_gc_for_fd(int err)
return 0;
}
-/* try `expr` upto twice while it returns false and `errno`
- * is to GC. Each `errno`s are available as `first_errno` and
- * `retried_errno` respectively */
-#define TRY_WITH_GC(expr) \
- for (int first_errno, retried_errno = 0, retried = 0; \
- (!retried && \
- !(expr) && \
- (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
- (retried_errno = errno, 1)); \
- (void)retried_errno, retried = 1)
-
static int
ruby_dup(int orig)
{
- int fd = -1;
+ int fd;
- TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
- rb_syserr_fail(first_errno, 0);
+ fd = rb_cloexec_dup(orig);
+ if (fd < 0) {
+ int e = errno;
+ if (rb_gc_for_fd(e)) {
+ fd = rb_cloexec_dup(orig);
+ }
+ if (fd < 0) {
+ rb_syserr_fail(e, 0);
+ }
}
rb_update_max_fd(fd);
return fd;
@@ -1108,7 +1088,7 @@ ruby_dup(int orig)
static VALUE
io_alloc(VALUE klass)
{
- NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
+ NEWOBJ_OF(io, struct RFile, klass, T_FILE);
io->fptr = 0;
@@ -1164,11 +1144,6 @@ static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval
static inline int
io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
{
- if (!timeout && rb_thread_mn_schedulable(thread)) {
- RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
- return -1;
- }
-
int ready = nogvl_wait_for(thread, fptr, events, timeout);
if (ready > 0) {
@@ -1309,7 +1284,7 @@ rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
iis.timeout = &timeout_storage;
}
- return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
+ return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fptr->fd);
}
static ssize_t
@@ -1342,7 +1317,7 @@ rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
iis.timeout = &timeout_storage;
}
- return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
+ return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fptr->fd);
}
#ifdef HAVE_WRITEV
@@ -1379,7 +1354,7 @@ rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
iis.timeout = &timeout_storage;
}
- return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
+ return (ssize_t)rb_thread_io_blocking_region(internal_writev_func, &iis, fptr->fd);
}
#endif
@@ -1409,7 +1384,7 @@ static VALUE
io_flush_buffer_async(VALUE arg)
{
rb_io_t *fptr = (rb_io_t *)arg;
- return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
+ return rb_thread_io_blocking_region(io_flush_buffer_sync, fptr, fptr->fd);
}
static inline int
@@ -1485,7 +1460,7 @@ rb_io_wait(VALUE io, VALUE events, VALUE timeout)
static VALUE
io_from_fd(int fd)
{
- return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
+ return prep_io(fd, FMODE_PREP, rb_cIO, NULL);
}
static int
@@ -1634,7 +1609,7 @@ rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
default:
// Non-specific error, no event is ready:
- return Qnil;
+ return Qfalse;
}
}
@@ -1646,11 +1621,9 @@ rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
if (RTEST(result)) {
return RB_NUM2INT(result);
}
- else if (result == RUBY_Qfalse) {
- rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
+ else {
+ return 0;
}
-
- return 0;
}
int
@@ -1661,11 +1634,9 @@ rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
if (RTEST(result)) {
return RB_NUM2INT(result);
}
- else if (result == RUBY_Qfalse) {
- rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
+ else {
+ return 0;
}
-
- return 0;
}
static void
@@ -1726,6 +1697,7 @@ make_writeconv(rb_io_t *fptr)
/* writing functions */
struct binwrite_arg {
rb_io_t *fptr;
+ VALUE str;
const char *ptr;
long length;
};
@@ -1862,7 +1834,7 @@ io_allocate_write_buffer(rb_io_t *fptr, int sync)
static inline int
io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
{
- // If the requested operation was synchronous and the output mode is synchronous or a TTY:
+ // If the requested operation was synchronous and the output mode is synchronus or a TTY:
if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
return 1;
@@ -1875,7 +1847,7 @@ io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
}
static long
-io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
+io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
{
if (len <= 0) return len;
@@ -1888,6 +1860,7 @@ io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
struct binwrite_arg arg;
arg.fptr = fptr;
+ arg.str = str;
arg.ptr = ptr;
arg.length = len;
@@ -1995,9 +1968,9 @@ io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
if (converted)
OBJ_FREEZE(str);
- tmp = rb_str_tmp_frozen_no_embed_acquire(str);
+ tmp = rb_str_tmp_frozen_acquire(str);
RSTRING_GETMEM(tmp, ptr, len);
- n = io_binwrite(ptr, len, fptr, nosync);
+ n = io_binwrite(tmp, ptr, len, fptr, nosync);
rb_str_tmp_frozen_release(str, tmp);
return n;
@@ -2010,7 +1983,7 @@ rb_io_bufwrite(VALUE io, const void *buf, size_t size)
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
- return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
+ return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
}
static VALUE
@@ -2302,7 +2275,7 @@ rb_io_writev(VALUE io, int argc, const VALUE *argv)
if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
VALUE klass = CLASS_OF(io);
- char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
+ char sep = FL_TEST(klass, FL_SINGLETON) ? (klass = io, '.') : '#';
rb_category_warning(
RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
" which accepts just one argument",
@@ -2414,6 +2387,9 @@ rb_io_flush(VALUE io)
* f.close
*
* Related: IO#pos=, IO#seek.
+ *
+ * IO#pos is an alias for IO#tell.
+ *
*/
static VALUE
@@ -2681,6 +2657,9 @@ io_fillbuf(rb_io_t *fptr)
* Note that this method reads data to the input byte buffer. So
* IO#sysread may not behave as you intend with IO#eof?, unless you
* call IO#rewind first (which is not available for some streams).
+ *
+ * IO#eof? is an alias for IO#eof.
+ *
*/
VALUE
@@ -2696,7 +2675,7 @@ rb_io_eof(VALUE io)
READ_CHECK(fptr);
#if RUBY_CRLF_ENVIRONMENT
if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
- return RBOOL(eof(fptr->fd));
+ return RBOOL(eof(fptr->fd));;
}
#endif
return RBOOL(io_fillbuf(fptr) < 0);
@@ -2799,10 +2778,8 @@ rb_io_fsync(VALUE io)
if (io_fflush(fptr) < 0)
rb_sys_fail_on_write(fptr);
-
- if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
+ if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
rb_sys_fail_path(fptr->pathv);
-
return INT2FIX(0);
}
#else
@@ -2851,7 +2828,7 @@ rb_io_fdatasync(VALUE io)
if (io_fflush(fptr) < 0)
rb_sys_fail_on_write(fptr);
- if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
+ if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
return INT2FIX(0);
/* fall back */
@@ -2873,6 +2850,8 @@ rb_io_fdatasync(VALUE io)
* File.open('t.txt').fileno # => 10
* f.close
*
+ * IO#to_i is an alias for IO#fileno.
+ *
*/
static VALUE
@@ -2895,23 +2874,8 @@ rb_io_descriptor(VALUE io)
return fptr->fd;
}
else {
- VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
- if (!UNDEF_P(fileno)) {
- return RB_NUM2INT(fileno);
- }
+ return RB_NUM2INT(rb_funcall(io, id_fileno, 0));
}
-
- rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
-
- UNREACHABLE_RETURN(-1);
-}
-
-int
-rb_io_mode(VALUE io)
-{
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- return fptr->mode;
}
/*
@@ -2960,7 +2924,7 @@ rb_io_pid(VALUE io)
* File.open("testfile") {|f| f.path} # => "testfile"
*/
-VALUE
+static VALUE
rb_io_path(VALUE io)
{
rb_io_t *fptr = RFILE(io)->fptr;
@@ -3301,10 +3265,9 @@ io_setstrbuf(VALUE *str, long len)
}
else {
VALUE s = StringValue(*str);
- rb_str_modify(s);
-
long clen = RSTRING_LEN(s);
if (clen >= len) {
+ rb_str_modify(s);
return FALSE;
}
len -= clen;
@@ -3435,12 +3398,7 @@ io_read_memory_call(VALUE arg)
}
}
- if (iis->nonblock) {
- return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
- }
- else {
- return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
- }
+ return rb_thread_io_blocking_region(internal_read_func, iis, iis->fptr->fd);
}
static long
@@ -3847,8 +3805,33 @@ rscheck(const char *rsptr, long rslen, VALUE rs)
rb_raise(rb_eRuntimeError, "rs modified");
}
+static const char *
+search_delim(const char *p, long len, int delim, rb_encoding *enc)
+{
+ if (rb_enc_mbminlen(enc) == 1) {
+ p = memchr(p, delim, len);
+ if (p) return p + 1;
+ }
+ else {
+ const char *end = p + len;
+ while (p < end) {
+ int r = rb_enc_precise_mbclen(p, end, enc);
+ if (!MBCLEN_CHARFOUND_P(r)) {
+ p += rb_enc_mbminlen(enc);
+ continue;
+ }
+ int n = MBCLEN_CHARFOUND_LEN(r);
+ if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
+ return p + n;
+ }
+ p += n;
+ }
+ }
+ return NULL;
+}
+
static int
-appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
+appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
{
VALUE str = *strp;
long limit = *lp;
@@ -3863,9 +3846,9 @@ appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
p = READ_CHAR_PENDING_PTR(fptr);
if (0 < limit && limit < searchlen)
searchlen = (int)limit;
- e = memchr(p, delim, searchlen);
+ e = search_delim(p, searchlen, delim, enc);
if (e) {
- int len = (int)(e-p+1);
+ int len = (int)(e-p);
if (NIL_P(str))
*strp = str = rb_str_new(p, len);
else
@@ -3905,8 +3888,8 @@ appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
long last;
if (limit > 0 && pending > limit) pending = limit;
- e = memchr(p, delim, pending);
- if (e) pending = e - p + 1;
+ e = search_delim(p, pending, delim, enc);
+ if (e) pending = e - p;
if (!NIL_P(str)) {
last = RSTRING_LEN(str);
rb_str_resize(str, last + pending);
@@ -4166,16 +4149,26 @@ rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
rsptr = RSTRING_PTR(rs);
rslen = RSTRING_LEN(rs);
}
+ newline = '\n';
+ }
+ else if (rb_enc_mbminlen(enc) == 1) {
+ rsptr = RSTRING_PTR(rs);
+ newline = (unsigned char)rsptr[rslen - 1];
}
else {
+ rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
rsptr = RSTRING_PTR(rs);
+ const char *e = rsptr + rslen;
+ const char *last = rb_enc_prev_char(rsptr, e, e, enc);
+ int n;
+ newline = rb_enc_codepoint_len(last, e, &n, enc);
+ if (last + n != e) rb_raise(rb_eArgError, "broken separator");
}
- newline = (unsigned char)rsptr[rslen - 1];
- chomp_cr = chomp && rslen == 1 && newline == '\n';
+ chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
}
/* MS - Optimization */
- while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
+ while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
const char *s, *p, *pp, *e;
if (c == newline) {
@@ -4183,7 +4176,8 @@ rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
s = RSTRING_PTR(str);
e = RSTRING_END(str);
p = e - rslen;
- if (!at_char_boundary(s, p, e, enc)) continue;
+ pp = rb_enc_left_char_head(s, p, e, enc);
+ if (pp != p) continue;
if (!rspara) rscheck(rsptr, rslen, rs);
if (memcmp(p, rsptr, rslen) == 0) {
if (chomp) {
@@ -4196,8 +4190,8 @@ rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
if (limit == 0) {
s = RSTRING_PTR(str);
p = RSTRING_END(str);
- pp = rb_enc_left_char_head(s, p-1, p, enc);
- if (extra_limit &&
+ pp = rb_enc_prev_char(s, p, p, enc);
+ if (extra_limit && pp &&
MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
/* relax the limit while incomplete character.
* extra_limit limits the relax length */
@@ -4324,8 +4318,11 @@ rb_io_gets_internal(VALUE io)
* File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
*
* With arguments +sep+ and +limit+ given,
- * combines the two behaviors
- * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
+ * combines the two behaviors:
+ *
+ * - Returns the next line as determined by line separator +sep+,
+ * or +nil+ if none.
+ * - But returns no more bytes than are allowed by the limit.
*
* Optional keyword argument +chomp+ specifies whether line separators
* are to be omitted:
@@ -4392,28 +4389,22 @@ rb_io_set_lineno(VALUE io, VALUE lineno)
return lineno;
}
-/* :nodoc: */
+/*
+ * call-seq:
+ * readline(sep = $/, chomp: false) -> string
+ * readline(limit, chomp: false) -> string
+ * readline(sep, limit, chomp: false) -> string
+ *
+ * Reads a line as with IO#gets, but raises EOFError if already at end-of-stream.
+ *
+ * Optional keyword argument +chomp+ specifies whether line separators
+ * are to be omitted.
+ */
+
static VALUE
-io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
+rb_io_readline(int argc, VALUE *argv, VALUE io)
{
- if (NIL_P(lim)) {
- // If sep is specified, but it's not a string and not nil, then assume
- // it's the limit (it should be an integer)
- if (!NIL_P(sep) && NIL_P(rb_check_string_type(sep))) {
- // If the user has specified a non-nil / non-string value
- // for the separator, we assume it's the limit and set the
- // separator to default: rb_rs.
- lim = sep;
- sep = rb_rs;
- }
- }
-
- if (!NIL_P(sep)) {
- StringValue(sep);
- }
-
- VALUE line = rb_io_getline_1(sep, NIL_P(lim) ? -1L : NUM2LONG(lim), RTEST(chomp), io);
- rb_lastline_set_up(line, 1);
+ VALUE line = rb_io_gets_m(argc, argv, io);
if (NIL_P(line)) {
rb_eof_error();
@@ -4474,8 +4465,10 @@ static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
* f.close
*
* With arguments +sep+ and +limit+ given,
- * combines the two behaviors
- * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
+ * combines the two behaviors:
+ *
+ * - Returns lines as determined by line separator +sep+.
+ * - But returns no more bytes in a line than are allowed by the limit.
*
* Optional keyword argument +chomp+ specifies whether line separators
* are to be omitted:
@@ -4595,8 +4588,10 @@ io_readlines(const struct getline_arg *arg, VALUE io)
* "ne\n"
*
* With arguments +sep+ and +limit+ given,
- * combines the two behaviors
- * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
+ * combines the two behaviors:
+ *
+ * - Calls with the next line as determined by line separator +sep+.
+ * - But returns no more bytes than are allowed by the limit.
*
* Optional keyword argument +chomp+ specifies whether line separators
* are to be omitted:
@@ -4614,6 +4609,9 @@ io_readlines(const struct getline_arg *arg, VALUE io)
* "Fifth line"
*
* Returns an Enumerator if no block is given.
+ *
+ * IO#each is an alias for IO#each_line.
+ *
*/
static VALUE
@@ -5134,7 +5132,7 @@ rb_io_ungetbyte(VALUE io, VALUE b)
b = rb_str_new((const char *)&c, 1);
break;
default:
- StringValue(b);
+ SafeStringValue(b);
}
io_ungetbyte(b, fptr);
return Qnil;
@@ -5196,7 +5194,7 @@ rb_io_ungetc(VALUE io, VALUE c)
c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
}
else {
- StringValue(c);
+ SafeStringValue(c);
}
if (NEED_READCONV(fptr)) {
SET_BINARY_MODE(fptr);
@@ -5237,6 +5235,8 @@ rb_io_ungetc(VALUE io, VALUE c)
* f = File.new('/dev/tty').isatty #=> true
* f.close
*
+ * IO#tty? is an alias for IO#isatty.
+ *
*/
static VALUE
@@ -5297,7 +5297,7 @@ rb_io_close_on_exec_p(VALUE io)
*
* Sets a close-on-exec flag.
*
- * f = File.open(File::NULL)
+ * f = open("/dev/null")
* f.close_on_exec = true
* system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
* f.closed? #=> false
@@ -5348,7 +5348,7 @@ rb_io_set_close_on_exec(VALUE io, VALUE arg)
#define rb_io_set_close_on_exec rb_f_notimplement
#endif
-#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
+#define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
static VALUE
@@ -5442,7 +5442,7 @@ maygvl_close(int fd, int keepgvl)
* close() may block for certain file types (NFS, SO_LINGER sockets,
* inotify), so let other threads run.
*/
- return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
+ return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
}
static void*
@@ -5459,7 +5459,7 @@ maygvl_fclose(FILE *file, int keepgvl)
if (keepgvl)
return fclose(file);
- return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
+ return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
}
static void free_io_buffer(rb_io_buffer_t *buf);
@@ -5467,7 +5467,7 @@ static void clear_codeconv(rb_io_t *fptr);
static void
fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
- struct rb_io_close_wait_list *busy)
+ struct ccan_list_head *busy)
{
VALUE error = Qnil;
int fd = fptr->fd;
@@ -5498,7 +5498,7 @@ fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
int done = 0;
- if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
+ if (IS_PREP_STDIO(fptr) || fd <= 2) {
// Need to keep FILE objects of stdin, stdout and stderr, so we are done:
done = 1;
}
@@ -5510,7 +5510,7 @@ fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
// Ensure waiting_fd users do not hit EBADF.
if (busy) {
// Wait for them to exit before we call close().
- rb_notify_fd_close_wait(busy);
+ do rb_thread_schedule(); while (!ccan_list_empty(busy));
}
// Disable for now.
@@ -5612,9 +5612,12 @@ clear_codeconv(rb_io_t *fptr)
clear_writeconv(fptr);
}
-static void
-rb_io_fptr_cleanup_all(rb_io_t *fptr)
+void
+rb_io_fptr_finalize_internal(void *ptr)
{
+ rb_io_t *fptr = ptr;
+
+ if (!ptr) return;
fptr->pathv = Qnil;
if (0 <= fptr->fd)
rb_io_fptr_cleanup(fptr, TRUE);
@@ -5622,14 +5625,7 @@ rb_io_fptr_cleanup_all(rb_io_t *fptr)
free_io_buffer(&fptr->rbuf);
free_io_buffer(&fptr->wbuf);
clear_codeconv(fptr);
-}
-
-void
-rb_io_fptr_finalize_internal(void *ptr)
-{
- if (!ptr) return;
- rb_io_fptr_cleanup_all(ptr);
- free(ptr);
+ free(fptr);
}
#undef rb_io_fptr_finalize
@@ -5646,7 +5642,7 @@ rb_io_fptr_finalize(rb_io_t *fptr)
}
#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
-size_t
+RUBY_FUNC_EXPORTED size_t
rb_io_memsize(const rb_io_t *fptr)
{
size_t size = sizeof(rb_io_t);
@@ -5665,14 +5661,16 @@ rb_io_memsize(const rb_io_t *fptr)
# define KEEPGVL FALSE
#endif
+int rb_notify_fd_close(int fd, struct ccan_list_head *);
static rb_io_t *
io_close_fptr(VALUE io)
{
rb_io_t *fptr;
VALUE write_io;
rb_io_t *write_fptr;
- struct rb_io_close_wait_list busy;
+ struct ccan_list_head busy;
+ ccan_list_head_init(&busy);
write_io = GetWriteIO(io);
if (io != write_io) {
write_fptr = RFILE(write_io)->fptr;
@@ -5726,9 +5724,6 @@ rb_io_close(VALUE io)
* If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
* (child exit status).
*
- * It is not an error to close an IO object that has already been closed.
- * It just returns nil.
- *
* Example:
*
* IO.popen('ruby', 'r+') do |pipe|
@@ -5812,8 +5807,10 @@ io_close(VALUE io)
*
* Related: IO#close_read, IO#close_write, IO#close.
*/
-VALUE
-rb_io_closed_p(VALUE io)
+
+
+static VALUE
+rb_io_closed(VALUE io)
{
rb_io_t *fptr;
VALUE write_io;
@@ -6111,37 +6108,28 @@ rb_io_sysread(int argc, VALUE *argv, VALUE io)
return str;
}
+#if defined(HAVE_PREAD) || defined(HAVE_PWRITE)
struct prdwr_internal_arg {
- struct rb_io *io;
int fd;
void *buf;
size_t count;
rb_off_t offset;
};
+#endif /* HAVE_PREAD || HAVE_PWRITE */
+#if defined(HAVE_PREAD)
static VALUE
-internal_pread_func(void *_arg)
+internal_pread_func(void *arg)
{
- struct prdwr_internal_arg *arg = _arg;
-
- return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
+ struct prdwr_internal_arg *p = arg;
+ return (VALUE)pread(p->fd, p->buf, p->count, p->offset);
}
static VALUE
-pread_internal_call(VALUE _arg)
+pread_internal_call(VALUE arg)
{
- struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
-
- VALUE scheduler = rb_fiber_scheduler_current();
- if (scheduler != Qnil) {
- VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
-
- if (!UNDEF_P(result)) {
- return rb_fiber_scheduler_io_result_apply(result);
- }
- }
-
- return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
+ struct prdwr_internal_arg *p = (struct prdwr_internal_arg *)arg;
+ return rb_thread_io_blocking_region(internal_pread_func, p, p->fd);
}
/*
@@ -6192,7 +6180,6 @@ rb_io_pread(int argc, VALUE *argv, VALUE io)
GetOpenFile(io, fptr);
rb_io_check_byte_readable(fptr);
- arg.io = fptr;
arg.fd = fptr->fd;
rb_io_check_closed(fptr);
@@ -6209,21 +6196,15 @@ rb_io_pread(int argc, VALUE *argv, VALUE io)
return str;
}
+#else
+# define rb_io_pread rb_f_notimplement
+#endif /* HAVE_PREAD */
+#if defined(HAVE_PWRITE)
static VALUE
-internal_pwrite_func(void *_arg)
+internal_pwrite_func(void *ptr)
{
- struct prdwr_internal_arg *arg = _arg;
-
- VALUE scheduler = rb_fiber_scheduler_current();
- if (scheduler != Qnil) {
- VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
-
- if (!UNDEF_P(result)) {
- return rb_fiber_scheduler_io_result_apply(result);
- }
- }
-
+ struct prdwr_internal_arg *arg = ptr;
return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
}
@@ -6269,20 +6250,21 @@ rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
io = GetWriteIO(io);
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
-
- arg.io = fptr;
arg.fd = fptr->fd;
tmp = rb_str_tmp_frozen_acquire(str);
arg.buf = RSTRING_PTR(tmp);
arg.count = (size_t)RSTRING_LEN(tmp);
- n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
+ n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->fd);
if (n < 0) rb_sys_fail_path(fptr->pathv);
rb_str_tmp_frozen_release(str, tmp);
return SSIZET2NUM(n);
}
+#else
+# define rb_io_pwrite rb_f_notimplement
+#endif /* HAVE_PWRITE */
VALUE
rb_io_binmode(VALUE io)
@@ -6767,6 +6749,8 @@ rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2
return extracted;
}
+typedef struct rb_io_enc_t convconfig_t;
+
static void
validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
{
@@ -6825,7 +6809,7 @@ extract_binmode(VALUE opthash, int *fmode)
void
rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
- int *oflags_p, int *fmode_p, struct rb_io_encoding *convconfig_p)
+ int *oflags_p, int *fmode_p, convconfig_t *convconfig_p)
{
VALUE vmode;
int oflags, fmode;
@@ -6853,7 +6837,7 @@ rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
else {
const char *p;
- StringValue(vmode);
+ SafeStringValue(vmode);
p = StringValueCStr(vmode);
fmode = rb_io_modestr_fmode(p);
oflags = rb_io_fmode_oflags(fmode);
@@ -6987,9 +6971,7 @@ static inline int
rb_sysopen_internal(struct sysopen_struct *data)
{
int fd;
- do {
- fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
- } while (fd < 0 && errno == EINTR);
+ fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
if (0 <= fd)
rb_update_max_fd(fd);
return fd;
@@ -6998,7 +6980,7 @@ rb_sysopen_internal(struct sysopen_struct *data)
static int
rb_sysopen(VALUE fname, int oflags, mode_t perm)
{
- int fd = -1;
+ int fd;
struct sysopen_struct data;
data.fname = rb_str_encode_ospath(fname);
@@ -7006,14 +6988,21 @@ rb_sysopen(VALUE fname, int oflags, mode_t perm)
data.oflags = oflags;
data.perm = perm;
- TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
- rb_syserr_fail_path(first_errno, fname);
+ fd = rb_sysopen_internal(&data);
+ if (fd < 0) {
+ int e = errno;
+ if (rb_gc_for_fd(e)) {
+ fd = rb_sysopen_internal(&data);
+ }
+ if (fd < 0) {
+ rb_syserr_fail_path(e, fname);
+ }
}
return fd;
}
-static inline FILE *
-fdopen_internal(int fd, const char *modestr)
+FILE *
+rb_fdopen(int fd, const char *modestr)
{
FILE *file;
@@ -7022,22 +7011,26 @@ fdopen_internal(int fd, const char *modestr)
#endif
file = fdopen(fd, modestr);
if (!file) {
+ int e = errno;
+#if defined(__sun)
+ if (e == 0) {
+ rb_gc();
+ errno = 0;
+ file = fdopen(fd, modestr);
+ }
+ else
+#endif
+ if (rb_gc_for_fd(e)) {
+ file = fdopen(fd, modestr);
+ }
+ if (!file) {
#ifdef _WIN32
- if (errno == 0) errno = EINVAL;
+ if (e == 0) e = EINVAL;
#elif defined(__sun)
- if (errno == 0) errno = EMFILE;
+ if (e == 0) e = EMFILE;
#endif
- }
- return file;
-}
-
-FILE *
-rb_fdopen(int fd, const char *modestr)
-{
- FILE *file = 0;
-
- TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
- rb_syserr_fail(first_errno, 0);
+ rb_syserr_fail(e, 0);
+ }
}
/* xxx: should be _IONBF? A buffer in FILE may have trouble. */
@@ -7144,11 +7137,11 @@ io_set_encoding_by_bom(VALUE io)
static VALUE
rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode,
- const struct rb_io_encoding *convconfig, mode_t perm)
+ const convconfig_t *convconfig, mode_t perm)
{
VALUE pathv;
rb_io_t *fptr;
- struct rb_io_encoding cc;
+ convconfig_t cc;
if (!convconfig) {
/* Set to default encodings */
rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
@@ -7182,11 +7175,13 @@ rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
{
int fmode = rb_io_modestr_fmode(modestr);
const char *p = strchr(modestr, ':');
- struct rb_io_encoding convconfig;
+ convconfig_t convconfig;
if (p) {
parse_mode_enc(p+1, rb_usascii_encoding(),
&convconfig.enc, &convconfig.enc2, &fmode);
+ convconfig.ecflags = 0;
+ convconfig.ecopts = Qnil;
}
else {
rb_encoding *e;
@@ -7194,19 +7189,10 @@ rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
+ convconfig.ecflags = 0;
+ convconfig.ecopts = Qnil;
}
- convconfig.ecflags = (fmode & FMODE_READABLE) ?
- MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
- 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
-#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
- convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
- MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
- 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
-#endif
- SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
- convconfig.ecopts = Qnil;
-
return rb_file_open_generic(io, filename,
rb_io_fmode_oflags(fmode),
fmode,
@@ -7297,7 +7283,7 @@ static void
fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
{
#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
- void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
+ void (*const old_finalize)(struct rb_io_t*,int) = fptr->finalize;
if (old_finalize == orig->finalize) return;
#endif
@@ -7335,7 +7321,12 @@ int
rb_pipe(int *pipes)
{
int ret;
- TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
+ ret = rb_cloexec_pipe(pipes);
+ if (ret < 0) {
+ if (rb_gc_for_fd(errno)) {
+ ret = rb_cloexec_pipe(pipes);
+ }
+ }
if (ret == 0) {
rb_update_max_fd(pipes[0]);
rb_update_max_fd(pipes[1]);
@@ -7497,7 +7488,7 @@ char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
#ifndef __EMSCRIPTEN__
static VALUE
pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
- const struct rb_io_encoding *convconfig)
+ const convconfig_t *convconfig)
{
struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
@@ -7726,7 +7717,7 @@ pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
#else
static VALUE
pipe_open(VALUE execarg_obj, const char *modestr, int fmode,
- const struct rb_io_encoding *convconfig)
+ const convconfig_t *convconfig)
{
rb_raise(rb_eNotImpError, "popen() is not available");
}
@@ -7748,7 +7739,7 @@ is_popen_fork(VALUE prog)
static VALUE
pipe_open_s(VALUE prog, const char *modestr, int fmode,
- const struct rb_io_encoding *convconfig)
+ const convconfig_t *convconfig)
{
int argc = 1;
VALUE *argv = &prog;
@@ -7957,7 +7948,7 @@ rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
const char *modestr;
VALUE tmp, execarg_obj = Qnil;
int oflags, fmode;
- struct rb_io_encoding convconfig;
+ convconfig_t convconfig;
tmp = rb_check_array_type(pname);
if (!NIL_P(tmp)) {
@@ -7971,7 +7962,7 @@ rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
RB_GC_GUARD(tmp);
}
else {
- StringValue(pname);
+ SafeStringValue(pname);
execarg_obj = Qnil;
if (!is_popen_fork(pname))
execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
@@ -7994,7 +7985,7 @@ popen_finish(VALUE port, VALUE klass)
if (NIL_P(port)) {
/* child */
if (rb_block_given_p()) {
- rb_yield(Qnil);
+ rb_protect(rb_yield, Qnil, NULL);
rb_io_flush(rb_ractor_stdout());
rb_io_flush(rb_ractor_stderr());
_exit(0);
@@ -8008,72 +7999,37 @@ popen_finish(VALUE port, VALUE klass)
return port;
}
-#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
-struct popen_writer_arg {
- char *const *argv;
- struct popen_arg popen;
-};
-
-static int
-exec_popen_writer(void *arg, char *errmsg, size_t buflen)
+static void
+rb_scan_open_args(int argc, const VALUE *argv,
+ VALUE *fname_p, int *oflags_p, int *fmode_p,
+ convconfig_t *convconfig_p, mode_t *perm_p)
{
- struct popen_writer_arg *pw = arg;
- pw->popen.modef = FMODE_WRITABLE;
- popen_redirect(&pw->popen);
- execv(pw->argv[0], pw->argv);
- strlcpy(errmsg, strerror(errno), buflen);
- return -1;
-}
-#endif
+ VALUE opt, fname, vmode, vperm;
+ int oflags, fmode;
+ mode_t perm;
-FILE *
-ruby_popen_writer(char *const *argv, rb_pid_t *pid)
-{
-#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
-# ifdef HAVE_WORKING_FORK
- struct popen_writer_arg pw;
- int *const write_pair = pw.popen.pair;
-# else
- int write_pair[2];
-# endif
+ argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
+ FilePathValue(fname);
- int result = rb_cloexec_pipe(write_pair);
- *pid = -1;
- if (result == 0) {
-# ifdef HAVE_WORKING_FORK
- pw.argv = argv;
- int status;
- char errmsg[80] = {'\0'};
- *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
-# else
- *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
- const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
-# endif
- close(write_pair[0]);
- if (*pid < 0) {
- close(write_pair[1]);
- fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
- }
- else {
- return fdopen(write_pair[1], "w");
- }
- }
-#endif
- return NULL;
+ rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
+
+ perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
+
+ *fname_p = fname;
+ *oflags_p = oflags;
+ *fmode_p = fmode;
+ *perm_p = perm;
}
static VALUE
-rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
+rb_open_file(int argc, const VALUE *argv, VALUE io)
{
- struct rb_io_encoding convconfig;
+ VALUE fname;
int oflags, fmode;
+ convconfig_t convconfig;
mode_t perm;
- FilePathValue(fname);
-
- rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
- perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
-
+ rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
return io;
@@ -8086,11 +8042,11 @@ rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
* File.open(path, mode = 'r', perm = 0666, **opts) -> file
* File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
*
- * Creates a new File object, via File.new with the given arguments.
+ * Creates a new \File object, via File.new with the given arguments.
*
- * With no block given, returns the File object.
+ * With no block given, returns the \File object.
*
- * With a block given, calls the block with the File object
+ * With a block given, calls the block with the \File object
* and returns the block's value.
*
*/
@@ -8157,7 +8113,7 @@ rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
oflags = NUM2INT(intmode);
else {
- StringValue(vmode);
+ SafeStringValue(vmode);
oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
}
if (NIL_P(vperm)) perm = 0666;
@@ -8188,10 +8144,20 @@ check_pipe_command(VALUE filename_or_command)
* open(path, mode = 'r', perm = 0666, **opts) -> io or nil
* open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
*
- * Creates an IO object connected to the given file.
+ * Creates an IO object connected to the given stream, file, or subprocess.
*
- * This method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
+ * Required string argument +path+ determines which of the following occurs:
+ *
+ * - The file at the specified +path+ is opened.
+ * - The process forks.
+ * - A subprocess is created.
+ *
+ * Each of these is detailed below.
+ *
+ * <b>File Opened</b>
+
+ * If +path+ does _not_ start with a pipe character (<tt>'|'</tt>),
+ * a file stream is opened with <tt>File.open(path, mode, perm, **opts)</tt>.
*
* With no block given, file stream is returned:
*
@@ -8208,6 +8174,67 @@ check_pipe_command(VALUE filename_or_command)
*
* See File.open for details.
*
+ * <b>Process Forked</b>
+ *
+ * If +path+ is the 2-character string <tt>'|-'</tt>, the process forks
+ * and the child process is connected to the parent.
+ *
+ * With no block given:
+ *
+ * io = open('|-')
+ * if io
+ * $stderr.puts "In parent, child pid is #{io.pid}."
+ * else
+ * $stderr.puts "In child, pid is #{$$}."
+ * end
+ *
+ * Output:
+ *
+ * In parent, child pid is 27903.
+ * In child, pid is 27903.
+ *
+ * With a block given:
+ *
+ * open('|-') do |io|
+ * if io
+ * $stderr.puts "In parent, child pid is #{io.pid}."
+ * else
+ * $stderr.puts "In child, pid is #{$$}."
+ * end
+ * end
+ *
+ * Output:
+ *
+ * In parent, child pid is 28427.
+ * In child, pid is 28427.
+ *
+ * <b>Subprocess Created</b>
+ *
+ * If +path+ is <tt>'|command'</tt> (<tt>'command' != '-'</tt>),
+ * a new subprocess runs the command; its open stream is returned.
+ * Note that the command may be processed by shell if it contains
+ * shell metacharacters.
+ *
+ * With no block given:
+ *
+ * io = open('|echo "Hi!"') # => #<IO:fd 12>
+ * print io.gets
+ * io.close
+ *
+ * Output:
+ *
+ * "Hi!"
+ *
+ * With a block given, calls the block with the stream, then closes the stream:
+ *
+ * open('|echo "Hi!"') do |io|
+ * print io.gets
+ * end
+ *
+ * Output:
+ *
+ * "Hi!"
+ *
*/
static VALUE
@@ -8230,8 +8257,6 @@ rb_f_open(int argc, VALUE *argv, VALUE _)
else {
VALUE cmd = check_pipe_command(tmp);
if (!NIL_P(cmd)) {
- // TODO: when removed in 4.0, update command_injection.rdoc
- rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
argv[0] = cmd;
return rb_io_s_popen(argc, argv, rb_cIO);
}
@@ -8249,13 +8274,13 @@ rb_f_open(int argc, VALUE *argv, VALUE _)
return rb_io_s_open(argc, argv, rb_cFile);
}
-static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const struct rb_io_encoding *, mode_t);
+static VALUE rb_io_open_generic(VALUE, VALUE, int, int, const convconfig_t *, mode_t);
static VALUE
rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
{
int oflags, fmode;
- struct rb_io_encoding convconfig;
+ convconfig_t convconfig;
mode_t perm;
rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
@@ -8265,12 +8290,10 @@ rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
static VALUE
rb_io_open_generic(VALUE klass, VALUE filename, int oflags, int fmode,
- const struct rb_io_encoding *convconfig, mode_t perm)
+ const convconfig_t *convconfig, mode_t perm)
{
VALUE cmd;
if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
- // TODO: when removed in 4.0, update command_injection.rdoc
- rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
}
else {
@@ -8291,7 +8314,7 @@ io_reopen(VALUE io, VALUE nfile)
GetOpenFile(nfile, orig);
if (fptr == orig) return io;
- if (RUBY_IO_EXTERNAL_P(fptr)) {
+ if (IS_PREP_STDIO(fptr)) {
if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
(fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
(fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
@@ -8317,17 +8340,17 @@ io_reopen(VALUE io, VALUE nfile)
}
/* copy rb_io_t structure */
- fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
+ fptr->mode = orig->mode | (fptr->mode & FMODE_PREP);
fptr->pid = orig->pid;
fptr->lineno = orig->lineno;
if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
- else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
+ else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil;
fptr_copy_finalizer(fptr, orig);
fd = fptr->fd;
fd2 = orig->fd;
if (fd != fd2) {
- if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
+ if (IS_PREP_STDIO(fptr) || fd <= 2 || !fptr->stdio_file) {
/* need to keep FILE objects of stdin, stdout and stderr */
if (rb_cloexec_dup2(fd2, fd) < 0)
rb_sys_fail_path(orig->pathv);
@@ -8432,10 +8455,10 @@ rb_io_reopen(int argc, VALUE *argv, VALUE file)
if (!NIL_P(nmode) || !NIL_P(opt)) {
int fmode;
- struct rb_io_encoding convconfig;
+ convconfig_t convconfig;
rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
- if (RUBY_IO_EXTERNAL_P(fptr) &&
+ if (IS_PREP_STDIO(fptr) &&
((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
(fptr->mode & FMODE_READWRITE)) {
rb_raise(rb_eArgError,
@@ -8514,7 +8537,7 @@ rb_io_init_copy(VALUE dest, VALUE io)
rb_io_flush(io);
/* copy rb_io_t structure */
- fptr->mode = orig->mode & ~FMODE_EXTERNAL;
+ fptr->mode = orig->mode & ~FMODE_PREP;
fptr->encs = orig->encs;
fptr->pid = orig->pid;
fptr->lineno = orig->lineno;
@@ -8617,7 +8640,7 @@ deprecated_str_setter(VALUE val, ID id, VALUE *var)
{
rb_str_setter(val, id, &val);
if (!NIL_P(val)) {
- rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
+ rb_warn_deprecated("`%s'", NULL, rb_id2name(id));
}
*var = val;
}
@@ -8878,9 +8901,9 @@ io_puts_ary(VALUE ary, VALUE out, int recur)
*
* Treatment for each object:
*
- * - String: writes the string.
+ * - \String: writes the string.
* - Neither string nor array: writes <tt>object.to_s</tt>.
- * - Array: writes each element of the array; arrays may be nested.
+ * - \Array: writes each element of the array; arrays may be nested.
*
* To keep these examples brief, we define this helper method:
*
@@ -9036,10 +9059,6 @@ rb_p_result(int argc, const VALUE *argv)
* 0..4
* [0..4, 0..4, 0..4]
*
- * Kernel#p is designed for debugging purposes.
- * Ruby implementations may define Kernel#p to be uninterruptible
- * in whole or in part.
- * On CRuby, Kernel#p's writing of data is uninterruptible.
*/
static VALUE
@@ -9193,94 +9212,26 @@ stderr_getter(ID id, VALUE *ptr)
}
static VALUE
-allocate_and_open_new_file(VALUE klass)
-{
- VALUE self = io_alloc(klass);
- rb_io_make_open_file(self);
- return self;
-}
-
-VALUE
-rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
-{
- int state;
- VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
- if (state) {
- /* if we raised an exception allocating an IO object, but the caller
- intended to transfer ownership of this FD to us, close the fd before
- raising the exception. Otherwise, we would leak a FD - the caller
- expects GC to close the file, but we never got around to assigning
- it to a rb_io. */
- if (!(mode & FMODE_EXTERNAL)) {
- maygvl_close(descriptor, 0);
- }
- rb_jump_tag(state);
- }
-
-
- rb_io_t *io = RFILE(self)->fptr;
- io->self = self;
- io->fd = descriptor;
- io->mode = mode;
-
- /* At this point, Ruby fully owns the descriptor, and will close it when
- the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
- in the rest of this method. */
-
- if (NIL_P(path)) {
- io->pathv = Qnil;
- }
- else {
- StringValue(path);
- io->pathv = rb_str_new_frozen(path);
- }
-
- io->timeout = timeout;
-
- if (encoding) {
- io->encs = *encoding;
- }
-
- rb_update_max_fd(descriptor);
-
- return self;
-}
-
-static VALUE
prep_io(int fd, int fmode, VALUE klass, const char *path)
{
- VALUE path_value = Qnil;
- rb_encoding *e;
- struct rb_io_encoding convconfig;
-
- if (path) {
- path_value = rb_obj_freeze(rb_str_new_cstr(path));
- }
-
- e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
- rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
- convconfig.ecflags = (fmode & FMODE_READABLE) ?
- MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
- 0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
-#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
- convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
- MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
- 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
-#endif
- SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
- convconfig.ecopts = Qnil;
-
- VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
- rb_io_t*io = RFILE(self)->fptr;
+ rb_io_t *fp;
+ VALUE io = io_alloc(klass);
- if (!io_check_tty(io)) {
+ MakeOpenFile(io, fp);
+ fp->self = io;
+ fp->fd = fd;
+ fp->mode = fmode;
+ fp->timeout = Qnil;
+ if (!io_check_tty(fp)) {
#ifdef __CYGWIN__
- io->mode |= FMODE_BINMODE;
+ fp->mode |= FMODE_BINMODE;
setmode(fd, O_BINARY);
#endif
}
+ if (path) fp->pathv = rb_obj_freeze(rb_str_new_cstr(path));
+ rb_update_max_fd(fd);
- return self;
+ return io;
}
VALUE
@@ -9296,7 +9247,7 @@ static VALUE
prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
{
rb_io_t *fptr;
- VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
+ VALUE io = prep_io(fileno(f), fmode|FMODE_PREP|DEFAULT_TEXTMODE, klass, path);
GetOpenFile(io, fptr);
fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
@@ -9340,7 +9291,7 @@ rb_io_stdio_file(rb_io_t *fptr)
}
static inline void
-rb_io_buffer_init(struct rb_io_internal_buffer *buf)
+rb_io_buffer_init(rb_io_buffer_t *buf)
{
buf->ptr = NULL;
buf->off = 0;
@@ -9396,8 +9347,6 @@ rb_io_make_open_file(VALUE obj)
return fp;
}
-static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
-
/*
* call-seq:
* IO.new(fd, mode = 'r', **opts) -> io
@@ -9443,24 +9392,18 @@ static VALUE
rb_io_initialize(int argc, VALUE *argv, VALUE io)
{
VALUE fnum, vmode;
- VALUE opt;
-
- rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
- return io_initialize(io, fnum, vmode, opt);
-}
-
-static VALUE
-io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
-{
rb_io_t *fp;
int fd, fmode, oflags = O_RDONLY;
- struct rb_io_encoding convconfig;
+ convconfig_t convconfig;
+ VALUE opt;
#if defined(HAVE_FCNTL) && defined(F_GETFL)
int ofmode;
#else
struct stat st;
#endif
+
+ argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
fd = NUM2INT(fnum);
@@ -9488,7 +9431,7 @@ io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
if (!NIL_P(opt)) {
if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
- fmode |= FMODE_EXTERNAL;
+ fmode |= FMODE_PREP;
}
path = rb_hash_aref(opt, RB_ID2SYM(idPath));
@@ -9567,9 +9510,9 @@ rb_io_set_encoding_by_bom(VALUE io)
* File.new(path, mode = 'r', perm = 0666, **opts) -> file
*
* Opens the file at the given +path+ according to the given +mode+;
- * creates and returns a new File object for that file.
+ * creates and returns a new \File object for that file.
*
- * The new File object is buffered mode (or non-sync mode), unless
+ * The new \File object is buffered mode (or non-sync mode), unless
* +filename+ is a tty.
* See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
*
@@ -9609,16 +9552,17 @@ rb_file_initialize(int argc, VALUE *argv, VALUE io)
if (RFILE(io)->fptr) {
rb_raise(rb_eRuntimeError, "reinitializing File");
}
- VALUE fname, vmode, vperm, opt;
- int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
- if (posargc < 3) { /* perm is File only */
- VALUE fd = rb_check_to_int(fname);
+ if (0 < argc && argc < 3) {
+ VALUE fd = rb_check_to_int(argv[0]);
if (!NIL_P(fd)) {
- return io_initialize(io, fd, vmode, opt);
+ argv[0] = fd;
+ return rb_io_initialize(argc, argv, io);
}
}
- return rb_open_file(io, fname, vmode, vperm, opt);
+ rb_open_file(argc, argv, io);
+
+ return io;
}
/* :nodoc: */
@@ -9656,7 +9600,7 @@ rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
* ios.autoclose? -> true or false
*
* Returns +true+ if the underlying file descriptor of _ios_ will be
- * closed at its finalization or at calling #close, otherwise +false+.
+ * closed automatically at its finalization, otherwise +false+.
*/
static VALUE
@@ -9664,7 +9608,7 @@ rb_io_autoclose_p(VALUE io)
{
rb_io_t *fptr = RFILE(io)->fptr;
rb_io_check_closed(fptr);
- return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
+ return RBOOL(!(fptr->mode & FMODE_PREP));
}
/*
@@ -9673,14 +9617,14 @@ rb_io_autoclose_p(VALUE io)
*
* Sets auto-close flag.
*
- * f = File.open(File::NULL)
- * IO.for_fd(f.fileno).close
- * f.gets # raises Errno::EBADF
+ * f = open("/dev/null")
+ * IO.for_fd(f.fileno)
+ * # ...
+ * f.gets # may cause Errno::EBADF
*
- * f = File.open(File::NULL)
- * g = IO.for_fd(f.fileno)
- * g.autoclose = false
- * g.close
+ * f = open("/dev/null")
+ * IO.for_fd(f.fileno).autoclose = false
+ * # ...
* f.gets # won't cause Errno::EBADF
*/
@@ -9690,9 +9634,9 @@ rb_io_set_autoclose(VALUE io, VALUE autoclose)
rb_io_t *fptr;
GetOpenFile(io, fptr);
if (!RTEST(autoclose))
- fptr->mode |= FMODE_EXTERNAL;
+ fptr->mode |= FMODE_PREP;
else
- fptr->mode &= ~FMODE_EXTERNAL;
+ fptr->mode &= ~FMODE_PREP;
return autoclose;
}
@@ -9825,7 +9769,7 @@ wait_mode_sym(VALUE mode)
rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
}
-static inline enum rb_io_event
+static inline rb_io_event_t
io_event_from_value(VALUE value)
{
int events = RB_NUM2INT(value);
@@ -9856,7 +9800,7 @@ static VALUE
io_wait(int argc, VALUE *argv, VALUE io)
{
VALUE timeout = Qundef;
- enum rb_io_event events = 0;
+ rb_io_event_t events = 0;
int return_io = 0;
// The documented signature for this method is actually incorrect.
@@ -10485,9 +10429,8 @@ static VALUE argf_readlines(int, VALUE *, VALUE);
* $cat t.txt | ruby -e "p readlines 12"
* ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
*
- * With arguments +sep+ and +limit+ given,
- * combines the two behaviors
- * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
+ * With arguments +sep+ and +limit+ given, combines the two behaviors;
+ * see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit].
*
* Optional keyword argument +chomp+ specifies whether line separators
* are to be omitted:
@@ -10511,21 +10454,19 @@ rb_f_readlines(int argc, VALUE *argv, VALUE recv)
/*
* call-seq:
- * ARGF.readlines(sep = $/, chomp: false) -> array
- * ARGF.readlines(limit, chomp: false) -> array
- * ARGF.readlines(sep, limit, chomp: false) -> array
+ * ARGF.readlines(sep = $/) -> array
+ * ARGF.readlines(limit) -> array
+ * ARGF.readlines(sep, limit) -> array
*
- * ARGF.to_a(sep = $/, chomp: false) -> array
- * ARGF.to_a(limit, chomp: false) -> array
- * ARGF.to_a(sep, limit, chomp: false) -> array
+ * ARGF.to_a(sep = $/) -> array
+ * ARGF.to_a(limit) -> array
+ * ARGF.to_a(sep, limit) -> array
*
* Reads each file in ARGF in its entirety, returning an Array containing
* lines from the files. Lines are assumed to be separated by _sep_.
*
* lines = ARGF.readlines
* lines[0] #=> "This is line one\n"
- *
- * See +IO.readlines+ for a full description of all options.
*/
static VALUE
argf_readlines(int argc, VALUE *argv, VALUE argf)
@@ -10579,7 +10520,7 @@ rb_f_backquote(VALUE obj, VALUE str)
VALUE result;
rb_io_t *fptr;
- StringValue(str);
+ SafeStringValue(str);
rb_last_status_clear();
port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
if (NIL_P(port)) return rb_str_new(0,0);
@@ -10587,7 +10528,8 @@ rb_f_backquote(VALUE obj, VALUE str)
GetOpenFile(port, fptr);
result = read_all(fptr, remain_size(fptr), Qnil);
rb_io_close(port);
- rb_io_fptr_cleanup_all(fptr);
+ RFILE(port)->fptr = NULL;
+ rb_io_fptr_finalize(fptr);
RB_GC_GUARD(port);
return result;
@@ -10822,7 +10764,7 @@ do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
ias.offset = offset;
ias.len = len;
- rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
+ rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
if (rv && rv != ENOSYS) {
/* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
it returns the error code. */
@@ -10926,8 +10868,7 @@ rb_io_advise(int argc, VALUE *argv, VALUE io)
* Each of the arguments +read_ios+, +write_ios+, and +error_ios+
* is an array of IO objects.
*
- * Argument +timeout+ is a numeric value (such as integer or float) timeout
- * interval in seconds.
+ * Argument +timeout+ is an integer timeout interval in seconds.
*
* The method monitors the \IO objects given in all three arrays,
* waiting for some to be ready;
@@ -11115,16 +11056,16 @@ nogvl_ioctl(void *ptr)
}
static int
-do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
+do_ioctl(int fd, ioctl_req_t cmd, long narg)
{
int retval;
struct ioctl_arg arg;
- arg.fd = io->fd;
+ arg.fd = fd;
arg.cmd = cmd;
arg.narg = narg;
- retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
+ retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
return retval;
}
@@ -11387,7 +11328,7 @@ rb_ioctl(VALUE io, VALUE req, VALUE arg)
narg = setup_narg(cmd, &arg, ioctl_narg_len);
GetOpenFile(io, fptr);
- retval = do_ioctl(fptr, cmd, narg);
+ retval = do_ioctl(fptr->fd, cmd, narg);
return finish_narg(retval, arg, fptr);
}
@@ -11441,16 +11382,16 @@ nogvl_fcntl(void *ptr)
}
static int
-do_fcntl(struct rb_io *io, int cmd, long narg)
+do_fcntl(int fd, int cmd, long narg)
{
int retval;
struct fcntl_arg arg;
- arg.fd = io->fd;
+ arg.fd = fd;
arg.cmd = cmd;
arg.narg = narg;
- retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
+ retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
if (retval != -1) {
switch (cmd) {
#if defined(F_DUPFD)
@@ -11476,7 +11417,7 @@ rb_fcntl(VALUE io, VALUE req, VALUE arg)
narg = setup_narg(cmd, &arg, fcntl_narg_len);
GetOpenFile(io, fptr);
- retval = do_fcntl(fptr, cmd, narg);
+ retval = do_fcntl(fptr->fd, cmd, narg);
return finish_narg(retval, arg, fptr);
}
@@ -11489,7 +11430,7 @@ rb_fcntl(VALUE io, VALUE req, VALUE arg)
* a file-oriented I/O stream. Arguments and results are platform
* dependent.
*
- * If +argument+ is a number, its value is passed directly;
+ * If +argument is a number, its value is passed directly;
* if it is a string, it is interpreted as a binary sequence of bytes.
* (Array#pack might be a useful way to build this string.)
*
@@ -11586,7 +11527,7 @@ rb_f_syscall(int argc, VALUE *argv, VALUE _)
VALUE v = rb_check_string_type(argv[i]);
if (!NIL_P(v)) {
- StringValue(v);
+ SafeStringValue(v);
rb_str_modify(v);
arg[i] = (VALUE)StringValueCStr(v);
}
@@ -11677,11 +11618,6 @@ io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
enc2 = NULL;
}
}
- if (enc2 == rb_ascii8bit_encoding()) {
- /* If external is ASCII-8BIT, no transcoding */
- enc = enc2;
- enc2 = NULL;
- }
SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
}
@@ -11742,9 +11678,9 @@ pipe_pair_close(VALUE rw)
* IO.pipe(**opts) -> [read_io, write_io]
* IO.pipe(enc, **opts) -> [read_io, write_io]
* IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
- * IO.pipe(**opts) {|read_io, write_io| ...} -> object
- * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
- * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
+ * IO.pipe(**opts) {|read_io, write_io] ...} -> object
+ * IO.pipe(enc, **opts) {|read_io, write_io] ...} -> object
+ * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io] ...} -> object
*
* Creates a pair of pipe endpoints, +read_io+ and +write_io+,
* connected to each other.
@@ -11955,6 +11891,9 @@ io_s_foreach(VALUE v)
* IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
* IO.foreach(path, limit, **opts) {|line| block } -> nil
* IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
+ * IO.foreach(command, sep = $/, **opts) {|line| block } -> nil
+ * IO.foreach(command, limit, **opts) {|line| block } -> nil
+ * IO.foreach(command, sep, limit, **opts) {|line| block } -> nil
* IO.foreach(...) -> an_enumerator
*
* Calls the block with each successive line read from the stream.
@@ -11963,7 +11902,16 @@ io_s_foreach(VALUE v)
* this method has potential security vulnerabilities if called with untrusted input;
* see {Command Injection}[rdoc-ref:command_injection.rdoc].
*
- * The first argument must be a string that is the path to a file.
+ * The first argument must be a string that is one of the following:
+ *
+ * - Path: if +self+ is a subclass of \IO (\File, for example),
+ * or if the string _does_ _not_ start with the pipe character (<tt>'|'</tt>),
+ * the string is the path to a file.
+ * - Command: if +self+ is the class \IO,
+ * and if the string starts with the pipe character,
+ * the rest of the string is a command to be executed as a subprocess.
+ * This usage has potential security vulnerabilities if called with untrusted input;
+ * see {Command Injection}[rdoc-ref:command_injection.rdoc].
*
* With only argument +path+ given, parses lines from the file at the given +path+,
* as determined by the default line separator,
@@ -11999,7 +11947,7 @@ io_s_foreach(VALUE v)
*
* With argument +limit+ given, parses lines as determined by the default
* line separator and the given line-length limit
- * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
+ * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
*
* File.foreach('t.txt', 7) {|line| p line }
*
@@ -12015,15 +11963,16 @@ io_s_foreach(VALUE v)
* "Fourth l"
* "line\n"
*
- * With arguments +sep+ and +limit+ given,
- * combines the two behaviors
- * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
+ * With arguments +sep+ and +limit+ given,
+ * parses lines as determined by the given
+ * line separator and the given line-length limit
+ * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
*
* Optional keyword arguments +opts+ specify:
*
* - {Open Options}[rdoc-ref:IO@Open+Options].
* - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
- * - {Line Options}[rdoc-ref:IO@Line+IO].
+ * - {Line Options}[rdoc-ref:IO@Line+Options].
*
* Returns an Enumerator if no block is given.
*
@@ -12056,6 +12005,9 @@ io_s_readlines(VALUE v)
/*
* call-seq:
+ * IO.readlines(command, sep = $/, **opts) -> array
+ * IO.readlines(command, limit, **opts) -> array
+ * IO.readlines(command, sep, limit, **opts) -> array
* IO.readlines(path, sep = $/, **opts) -> array
* IO.readlines(path, limit, **opts) -> array
* IO.readlines(path, sep, limit, **opts) -> array
@@ -12066,7 +12018,19 @@ io_s_readlines(VALUE v)
* this method has potential security vulnerabilities if called with untrusted input;
* see {Command Injection}[rdoc-ref:command_injection.rdoc].
*
- * The first argument must be a string that is the path to a file.
+ * The first argument must be a string;
+ * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
+ *
+ * - If so (and if +self+ is \IO),
+ * the rest of the string is a command to be executed as a subprocess.
+ * - Otherwise, the string is the path to a file.
+ *
+ * With only argument +command+ given, executes the command in a shell,
+ * parses its $stdout into lines, as determined by the default line separator,
+ * and returns those lines in an array:
+ *
+ * IO.readlines('| cat t.txt')
+ * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
*
* With only argument +path+ given, parses lines from the file at the given +path+,
* as determined by the default line separator,
@@ -12075,6 +12039,8 @@ io_s_readlines(VALUE v)
* IO.readlines('t.txt')
* # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
*
+ * For both forms, command and path, the remaining arguments are the same.
+ *
* With argument +sep+ given, parses lines as determined by that line separator
* (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
*
@@ -12090,20 +12056,21 @@ io_s_readlines(VALUE v)
*
* With argument +limit+ given, parses lines as determined by the default
* line separator and the given line-length limit
- * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
+ * (see {Line Limit}[rdoc-ref:IO@Line+Limit]):
*
* IO.readlines('t.txt', 7)
* # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
*
- * With arguments +sep+ and +limit+ given,
- * combines the two behaviors
- * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
+ * With arguments +sep+ and +limit+ given,
+ * parses lines as determined by the given
+ * line separator and the given line-length limit
+ * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]):
*
* Optional keyword arguments +opts+ specify:
*
* - {Open Options}[rdoc-ref:IO@Open+Options].
* - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
- * - {Line Options}[rdoc-ref:IO@Line+IO].
+ * - {Line Options}[rdoc-ref:IO@Line+Options].
*
*/
@@ -12146,6 +12113,7 @@ seek_before_access(VALUE argp)
/*
* call-seq:
+ * IO.read(command, length = nil, offset = 0, **opts) -> string or nil
* IO.read(path, length = nil, offset = 0, **opts) -> string or nil
*
* Opens the stream, reads and returns some or all of its content,
@@ -12155,7 +12123,18 @@ seek_before_access(VALUE argp)
* this method has potential security vulnerabilities if called with untrusted input;
* see {Command Injection}[rdoc-ref:command_injection.rdoc].
*
- * The first argument must be a string that is the path to a file.
+ * The first argument must be a string;
+ * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
+ *
+ * - If so (and if +self+ is \IO),
+ * the rest of the string is a command to be executed as a subprocess.
+ * - Otherwise, the string is the path to a file.
+ *
+ * With only argument +command+ given, executes the command in a shell,
+ * returns its entire $stdout:
+ *
+ * IO.read('| cat t.txt')
+ * # => "First line\nSecond line\n\nThird line\nFourth line\n"
*
* With only argument +path+ given, reads in text mode and returns the entire content
* of the file at the given path:
@@ -12167,6 +12146,8 @@ seek_before_access(VALUE argp)
* unread when encountering certain special bytes. Consider using
* IO.binread if all bytes in the file should be read.
*
+ * For both forms, command and path, the remaining arguments are the same.
+ *
* With argument +length+, returns +length+ bytes if available:
*
* IO.read('t.txt', 7) # => "First l"
@@ -12190,13 +12171,9 @@ static VALUE
rb_io_s_read(int argc, VALUE *argv, VALUE io)
{
VALUE opt, offset;
- long off;
struct foreach_arg arg;
argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
- if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
- rb_raise(rb_eArgError, "negative offset %ld given", off);
- }
open_key_args(io, argc, argv, opt, &arg);
if (NIL_P(arg.io)) return Qnil;
if (!NIL_P(offset)) {
@@ -12217,6 +12194,7 @@ rb_io_s_read(int argc, VALUE *argv, VALUE io)
/*
* call-seq:
+ * IO.binread(command, length = nil, offset = 0) -> string or nil
* IO.binread(path, length = nil, offset = 0) -> string or nil
*
* Behaves like IO.read, except that the stream is opened in binary mode
@@ -12240,7 +12218,7 @@ rb_io_s_binread(int argc, VALUE *argv, VALUE io)
|O_BINARY
#endif
};
- struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
+ convconfig_t convconfig = {NULL, NULL, 0, Qnil};
rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
FilePathValue(argv[0]);
@@ -12321,6 +12299,7 @@ io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
/*
* call-seq:
+ * IO.write(command, data, **opts) -> integer
* IO.write(path, data, offset = 0, **opts) -> integer
*
* Opens the stream, writes the given +data+ to it,
@@ -12330,9 +12309,25 @@ io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
* this method has potential security vulnerabilities if called with untrusted input;
* see {Command Injection}[rdoc-ref:command_injection.rdoc].
*
- * The first argument must be a string that is the path to a file.
+ * The first argument must be a string;
+ * its meaning depends on whether it starts with the pipe character (<tt>'|'</tt>):
+ *
+ * - If so (and if +self+ is \IO),
+ * the rest of the string is a command to be executed as a subprocess.
+ * - Otherwise, the string is the path to a file.
+ *
+ * With argument +command+ given, executes the command in a shell,
+ * passes +data+ through standard input, writes its output to $stdout,
+ * and returns the length of the given +data+:
+ *
+ * IO.write('| cat', 'Hello World!') # => 12
+ *
+ * Output:
+ *
+ * Hello World!
*
- * With only argument +path+ given, writes the given +data+ to the file at that path:
+ * With argument +path+ given, writes the given +data+ to the file
+ * at that path:
*
* IO.write('t.tmp', 'abc') # => 3
* File.read('t.tmp') # => "abc"
@@ -12371,6 +12366,7 @@ rb_io_s_write(int argc, VALUE *argv, VALUE io)
/*
* call-seq:
+ * IO.binwrite(command, string, offset = 0) -> integer
* IO.binwrite(path, string, offset = 0) -> integer
*
* Behaves like IO.write, except that the stream is opened in binary mode
@@ -12927,7 +12923,12 @@ maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf,
ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
}
else {
+#ifdef HAVE_PREAD
ss = pread(stp->src_fptr->fd, buf, len, offset);
+#else
+ stp->notimp = "pread";
+ return -1;
+#endif
}
if (ss == 0) {
return 0;
@@ -13094,6 +13095,7 @@ copy_stream_fallback_body(VALUE arg)
while (1) {
long numwrote;
long l;
+ rb_str_make_independent(buf);
if (stp->copy_length < (rb_off_t)0) {
l = buflen;
}
@@ -13247,7 +13249,7 @@ copy_stream_body(VALUE arg)
rb_str_resize(str,len);
read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
if (stp->dst_fptr) { /* IO or filename */
- if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
+ if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
rb_sys_fail_on_write(stp->dst_fptr);
}
else /* others such as StringIO */
@@ -13269,7 +13271,7 @@ copy_stream_body(VALUE arg)
return copy_stream_fallback(stp);
}
- IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
+ rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
return Qnil;
}
@@ -13437,12 +13439,10 @@ rb_io_internal_encoding(VALUE io)
*
* See {Encodings}[rdoc-ref:File@Encodings].
*
- * Argument +ext_enc+, if given, must be an Encoding object
- * or a String with the encoding name;
+ * Argument +ext_enc+, if given, must be an Encoding object;
* it is assigned as the encoding for the stream.
*
- * Argument +int_enc+, if given, must be an Encoding object
- * or a String with the encoding name;
+ * Argument +int_enc+, if given, must be an Encoding object;
* it is assigned as the encoding for the internal string.
*
* Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
@@ -13450,10 +13450,6 @@ rb_io_internal_encoding(VALUE io)
* corresponding Encoding objects are assigned as the external
* and internal encodings for the stream.
*
- * If the external encoding of a string is binary/ASCII-8BIT,
- * the internal encoding of the string is set to nil, since no
- * transcoding is needed.
- *
* Optional keyword arguments +enc_opts+ specify
* {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
*
@@ -14461,7 +14457,7 @@ argf_closed(VALUE argf)
{
next_argv();
ARGF_FORWARD(0, 0);
- return rb_io_closed_p(ARGF.current_file);
+ return rb_io_closed(ARGF.current_file);
}
/*
@@ -14596,14 +14592,14 @@ argf_write_io(VALUE argf)
/*
* call-seq:
- * ARGF.write(*objects) -> integer
+ * ARGF.write(string) -> integer
*
- * Writes each of the given +objects+ if inplace mode.
+ * Writes _string_ if inplace mode.
*/
static VALUE
-argf_write(int argc, VALUE *argv, VALUE argf)
+argf_write(VALUE argf, VALUE str)
{
- return rb_io_writev(argf_write_io(argf), argc, argv);
+ return rb_io_write(argf_write_io(argf), str);
}
void
@@ -14709,253 +14705,42 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
/*
* Document-class: ARGF
*
- * == \ARGF and +ARGV+
- *
- * The \ARGF object works with the array at global variable +ARGV+
- * to make <tt>$stdin</tt> and file streams available in the Ruby program:
- *
- * - **ARGV** may be thought of as the <b>argument vector</b> array.
+ * ARGF is a stream designed for use in scripts that process files given as
+ * command-line arguments or passed in via STDIN.
*
- * Initially, it contains the command-line arguments and options
- * that are passed to the Ruby program;
- * the program can modify that array as it likes.
+ * The arguments passed to your script are stored in the +ARGV+ Array, one
+ * argument per element. ARGF assumes that any arguments that aren't
+ * filenames have been removed from +ARGV+. For example:
*
- * - **ARGF** may be thought of as the <b>argument files</b> object.
+ * $ ruby argf.rb --verbose file1 file2
*
- * It can access file streams and/or the <tt>$stdin</tt> stream,
- * based on what it finds in +ARGV+.
- * This provides a convenient way for the command line
- * to specify streams for a Ruby program to read.
+ * ARGV #=> ["--verbose", "file1", "file2"]
+ * option = ARGV.shift #=> "--verbose"
+ * ARGV #=> ["file1", "file2"]
*
- * == Reading
+ * You can now use ARGF to work with a concatenation of each of these named
+ * files. For instance, ARGF.read will return the contents of _file1_
+ * followed by the contents of _file2_.
*
- * \ARGF may read from _source_ streams,
- * which at any particular time are determined by the content of +ARGV+.
+ * After a file in +ARGV+ has been read ARGF removes it from the Array.
+ * Thus, after all files have been read +ARGV+ will be empty.
*
- * === Simplest Case
+ * You can manipulate +ARGV+ yourself to control what ARGF operates on. If
+ * you remove a file from +ARGV+, it is ignored by ARGF; if you add files to
+ * +ARGV+, they are treated as if they were named on the command line. For
+ * example:
*
- * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
- * the source is <tt>$stdin</tt>:
+ * ARGV.replace ["file1"]
+ * ARGF.readlines # Returns the contents of file1 as an Array
+ * ARGV #=> []
+ * ARGV.replace ["file2", "file3"]
+ * ARGF.read # Returns the contents of file2 and file3
*
- * - \File +t.rb+:
- *
- * p ['ARGV', ARGV]
- * p ['ARGF.read', ARGF.read]
- *
- * - Commands and outputs
- * (see below for the content of files +foo.txt+ and +bar.txt+):
- *
- * $ echo "Open the pod bay doors, Hal." | ruby t.rb
- * ["ARGV", []]
- * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
- *
- * $ cat foo.txt bar.txt | ruby t.rb
- * ["ARGV", []]
- * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
- *
- * === About the Examples
- *
- * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
- *
- * $ cat foo.txt
- * Foo 0
- * Foo 1
- * $ cat bar.txt
- * Bar 0
- * Bar 1
- * Bar 2
- * Bar 3
- *
- * === Sources in +ARGV+
- *
- * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
- * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
- * the sources are found in +ARGV+.
- *
- * \ARGF assumes that each element in array +ARGV+ is a potential source,
- * and is one of:
- *
- * - The string path to a file that may be opened as a stream.
- * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
- *
- * Each element that is _not_ one of these
- * should be removed from +ARGV+ before \ARGF accesses that source.
- *
- * In the following example:
- *
- * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
- * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
- *
- * Example:
- *
- * - \File +t.rb+:
- *
- * # Print arguments (and options, if any) found on command line.
- * p ['ARGV', ARGV]
- *
- * - Command and output:
- *
- * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
- * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
- *
- * \ARGF's stream access considers the elements of +ARGV+, left to right:
- *
- * - \File +t.rb+:
- *
- * p "ARGV: #{ARGV}"
- * p "Line: #{ARGF.read}" # Read everything from all specified streams.
- *
- * - Command and output:
- *
- * $ ruby t.rb foo.txt bar.txt
- * "ARGV: [\"foo.txt\", \"bar.txt\"]"
- * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
- *
- * Because the value at +ARGV+ is an ordinary array,
- * you can manipulate it to control which sources \ARGF considers:
- *
- * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
- * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
- *
- * Each element in +ARGV+ is removed when its corresponding source is accessed;
- * when all sources have been accessed, the array is empty:
- *
- * - \File +t.rb+:
- *
- * until ARGV.empty? && ARGF.eof?
- * p "ARGV: #{ARGV}"
- * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
- * end
- *
- * - Command and output:
- *
- * $ ruby t.rb foo.txt bar.txt
- * "ARGV: [\"foo.txt\", \"bar.txt\"]"
- * "Line: Foo 0\n"
- * "ARGV: [\"bar.txt\"]"
- * "Line: Foo 1\n"
- * "ARGV: [\"bar.txt\"]"
- * "Line: Bar 0\n"
- * "ARGV: []"
- * "Line: Bar 1\n"
- * "ARGV: []"
- * "Line: Bar 2\n"
- * "ARGV: []"
- * "Line: Bar 3\n"
- *
- * ==== Filepaths in +ARGV+
- *
- * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
- *
- * This program prints what it reads from files at the paths specified
- * on the command line:
- *
- * - \File +t.rb+:
- *
- * p ['ARGV', ARGV]
- * # Read and print all content from the specified sources.
- * p ['ARGF.read', ARGF.read]
- *
- * - Command and output:
- *
- * $ ruby t.rb foo.txt bar.txt
- * ["ARGV", [foo.txt, bar.txt]
- * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
- *
- * ==== Specifying <tt>$stdin</tt> in +ARGV+
- *
- * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
- *
- * - \File +t.rb+:
- *
- * p ['ARGV', ARGV]
- * p ['ARGF.read', ARGF.read]
- *
- * - Command and output:
- *
- * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
- * ["ARGV", ["-"]]
- * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
- *
- * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
- * (exception:
- * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
- *
- * - Command and output:
- *
- * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
- * "ARGV: [\"foo.txt\", \"bar.txt\"]"
- * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
- *
- * ==== Mixtures and Repetitions in +ARGV+
- *
- * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
- * and character <tt>'-'</tt>, including repetitions.
- *
- * ==== Modifications to +ARGV+
- *
- * The running Ruby program may make any modifications to the +ARGV+ array;
- * the current value of +ARGV+ affects \ARGF reading.
- *
- * ==== Empty +ARGV+
- *
- * For an empty +ARGV+, an \ARGF read method either returns +nil+
- * or raises an exception, depending on the specific method.
- *
- * === More Read Methods
- *
- * As seen above, method ARGF#read reads the content of all sources
- * into a single string.
- * Other \ARGF methods provide other ways to access that content;
- * these include:
- *
- * - Byte access: #each_byte, #getbyte, #readbyte.
- * - Character access: #each_char, #getc, #readchar.
- * - Codepoint access: #each_codepoint.
- * - Line access: #each_line, #gets, #readline, #readlines.
- * - Source access: #read, #read_nonblock, #readpartial.
- *
- * === About \Enumerable
- *
- * \ARGF includes module Enumerable.
- * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
- *
- * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
- * _not_ from +ARGV+;
- * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
- * not an array of the strings from +ARGV+:
- *
- * - \File +t.rb+:
- *
- * p ['ARGV', ARGV]
- * p ['ARGF.entries', ARGF.entries]
- *
- * - Command and output:
- *
- * $ ruby t.rb foo.txt bar.txt
- * ["ARGV", ["foo.txt", "bar.txt"]]
- * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
- *
- * == Writing
- *
- * If <i>inplace mode</i> is in effect,
- * \ARGF may write to target streams,
- * which at any particular time are determined by the content of ARGV.
- *
- * Methods about inplace mode:
- *
- * - #inplace_mode
- * - #inplace_mode=
- * - #to_write_io
- *
- * Methods for writing:
- *
- * - #print
- * - #printf
- * - #putc
- * - #puts
- * - #write
+ * If +ARGV+ is empty, ARGF acts as if it contained STDIN, i.e. the data
+ * piped to your script. For example:
*
+ * $ echo "glark" | ruby -e 'p ARGF.read'
+ * "glark\n"
*/
/*
@@ -14973,7 +14758,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* ARGF is not itself a subclass of \IO.
*
* \Class StringIO provides an IO-like stream that handles a String.
- * StringIO is not itself a subclass of \IO.
+ * \StringIO is not itself a subclass of \IO.
*
* Important objects based on \IO include:
*
@@ -14991,7 +14776,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* - Kernel#open: Returns a new \IO object connected to a given source:
* stream, file, or subprocess.
*
- * Like a File stream, an \IO stream has:
+ * Like a \File stream, an \IO stream has:
*
* - A read/write mode, which may be read-only, write-only, or read/write;
* see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
@@ -15027,7 +14812,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* that determine how a new stream is to be opened:
*
* - +:mode+: Stream mode.
- * - +:flags+: Integer file open flags;
+ * - +:flags+: \Integer file open flags;
* If +mode+ is also given, the two are bitwise-ORed.
* - +:external_encoding+: External encoding for the stream.
* - +:internal_encoding+: Internal encoding for the stream.
@@ -15042,7 +14827,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* #path method.
*
* Also available are the options offered in String#encode,
- * which may control conversion between external and internal encoding.
+ * which may control conversion between external internal encoding.
*
* == Basic \IO
*
@@ -15107,64 +14892,56 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
*
* == Line \IO
*
- * \Class \IO supports line-oriented
- * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
- *
- * === Line Input
- *
- * \Class \IO supports line-oriented input for
- * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
+ * You can read an \IO stream line-by-line using these methods:
*
- * ==== \File Line Input
- *
- * You can read lines from a file using these methods:
- *
- * - IO.foreach: Reads each line and passes it to the given block.
- * - IO.readlines: Reads and returns all lines in an array.
+ * - IO#each_line: Reads each remaining line, passing it to the given block.
+ * - IO#gets: Returns the next line.
+ * - IO#readline: Like #gets, but raises an exception at end-of-stream.
+ * - IO#readlines: Returns all remaining lines in an array.
*
- * For each of these methods:
+ * Each of these reader methods accepts:
*
- * - You can specify {open options}[rdoc-ref:IO@Open+Options].
- * - Line parsing depends on the effective <i>line separator</i>;
+ * - An optional line separator, +sep+;
* see {Line Separator}[rdoc-ref:IO@Line+Separator].
- * - The length of each returned line depends on the effective <i>line limit</i>;
+ * - An optional line-size limit, +limit+;
* see {Line Limit}[rdoc-ref:IO@Line+Limit].
*
- * ==== Stream Line Input
+ * For each of these reader methods, reading may begin mid-line,
+ * depending on the stream's position;
+ * see {Position}[rdoc-ref:IO@Position]:
+ *
+ * f = File.new('t.txt')
+ * f.pos = 27
+ * f.each_line {|line| p line }
+ * f.close
*
- * You can read lines from an \IO stream using these methods:
+ * Output:
*
- * - IO#each_line: Reads each remaining line, passing it to the given block.
- * - IO#gets: Returns the next line.
- * - IO#readline: Like #gets, but raises an exception at end-of-stream.
- * - IO#readlines: Returns all remaining lines in an array.
+ * "rth line\n"
+ * "Fifth line\n"
*
- * For each of these methods:
+ * You can write to an \IO stream line-by-line using this method:
*
- * - Reading may begin mid-line,
- * depending on the stream's _position_;
- * see {Position}[rdoc-ref:IO@Position].
- * - Line parsing depends on the effective <i>line separator</i>;
- * see {Line Separator}[rdoc-ref:IO@Line+Separator].
- * - The length of each returned line depends on the effective <i>line limit</i>;
- * see {Line Limit}[rdoc-ref:IO@Line+Limit].
+ * - IO#puts: Writes objects to the stream.
*
- * ===== Line Separator
+ * === Line Separator
*
- * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
- * the string that determines what is considered a line;
- * it is sometimes called the <i>input record separator</i>.
+ * Each of these methods uses a <i>line separator</i>,
+ * which is the string that delimits lines:
*
- * The default line separator is taken from global variable <tt>$/</tt>,
- * whose initial value is <tt>"\n"</tt>.
+ * - IO.foreach.
+ * - IO.readlines.
+ * - IO#each_line.
+ * - IO#gets.
+ * - IO#readline.
+ * - IO#readlines.
*
- * Generally, the line to be read next is all data
- * from the current {position}[rdoc-ref:IO@Position]
- * to the next line separator
- * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
+ * The default line separator is the given by the global variable <tt>$/</tt>,
+ * whose value is by default <tt>"\n"</tt>.
+ * The line to be read next is all data from the current position
+ * to the next line separator:
*
* f = File.new('t.txt')
- * # Method gets with no sep argument returns the next line, according to $/.
* f.gets # => "First line\n"
* f.gets # => "Second line\n"
* f.gets # => "\n"
@@ -15172,7 +14949,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* f.gets # => "Fifth line\n"
* f.close
*
- * You can use a different line separator by passing argument +sep+:
+ * You can specify a different line separator:
*
* f = File.new('t.txt')
* f.gets('l') # => "First l"
@@ -15181,27 +14958,15 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* f.gets # => "e\n"
* f.close
*
- * Or by setting global variable <tt>$/</tt>:
+ * There are two special line separators:
*
- * f = File.new('t.txt')
- * $/ = 'l'
- * f.gets # => "First l"
- * f.gets # => "ine\nSecond l"
- * f.gets # => "ine\n\nFourth l"
- * f.close
- *
- * ===== Special Line Separator Values
- *
- * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
- * accepts two special values for parameter +sep+:
- *
- * - +nil+: The entire stream is to be read ("slurped") into a single string:
+ * - +nil+: The entire stream is read into a single string:
*
* f = File.new('t.txt')
* f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
* f.close
*
- * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
+ * - <tt>''</tt> (the empty string): The next "paragraph" is read
* (paragraphs being separated by two consecutive line separators):
*
* f = File.new('t.txt')
@@ -15209,18 +14974,23 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* f.gets('') # => "Fourth line\nFifth line\n"
* f.close
*
- * ===== Line Limit
+ * === Line Limit
*
- * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
- * uses an integer <i>line limit</i>,
- * which restricts the number of bytes that may be returned.
- * (A multi-byte character will not be split, and so a returned line may be slightly longer
- * than the limit).
+ * Each of these methods uses a <i>line limit</i>,
+ * which specifies that the number of bytes returned may not be (much) longer
+ * than the given +limit+;
*
- * The default limit value is <tt>-1</tt>;
- * any negative limit value means that there is no limit.
+ * - IO.foreach.
+ * - IO.readlines.
+ * - IO#each_line.
+ * - IO#gets.
+ * - IO#readline.
+ * - IO#readlines.
*
- * If there is no limit, the line is determined only by +sep+.
+ * A multi-byte character will not be split, and so a line may be slightly longer
+ * than the given limit.
+ *
+ * If +limit+ is not given, the line is determined only by +sep+.
*
* # Text with 1-byte characters.
* File.open('t.txt') {|f| f.gets(1) } # => "F"
@@ -15238,21 +15008,24 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* File.open('t.rus') {|f| f.gets(3).size } # => 2
* File.open('t.rus') {|f| f.gets(4).size } # => 2
*
- * ===== Line Separator and Line Limit
+ * === Line Separator and Line Limit
*
- * With arguments +sep+ and +limit+ given, combines the two behaviors:
+ * With arguments +sep+ and +limit+ given,
+ * combines the two behaviors:
*
* - Returns the next line as determined by line separator +sep+.
- * - But returns no more bytes than are allowed by the limit +limit+.
+ * - But returns no more bytes than are allowed by the limit.
*
* Example:
*
* File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
* File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
*
- * ===== Line Number
+ * === Line Number
*
- * A readable \IO stream has a non-negative integer <i>line number</i>:
+ * A readable \IO stream has a non-negative integer <i>line number</i>.
+ *
+ * The relevant methods:
*
* - IO#lineno: Returns the line number.
* - IO#lineno=: Resets and returns the line number.
@@ -15260,7 +15033,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* Unless modified by a call to method IO#lineno=,
* the line number is the number of lines read
* by certain line-oriented methods,
- * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
+ * according to the given line separator +sep+:
*
* - IO.foreach: Increments the line number on each call to the block.
* - IO#each_line: Increments the line number on each call to the block.
@@ -15329,7 +15102,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* # => 41
* f.close
*
- * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
+ * - When a stream is read, <tt>#.</tt> is set to the line number for that stream:
*
* f0 = File.new('t.txt')
* f1 = File.new('t.dat')
@@ -15350,12 +15123,6 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
* $. # => 5
* f.close
*
- * === Line Output
- *
- * You can write to an \IO stream line-by-line using this method:
- *
- * - IO#puts: Writes objects to the stream.
- *
* == Character \IO
*
* You can process an \IO stream character-by-character using these methods:
@@ -15584,14 +15351,10 @@ Init_IO(void)
rb_cIO = rb_define_class("IO", rb_cObject);
rb_include_module(rb_cIO, rb_mEnumerable);
- /* Can be raised by IO operations when IO#timeout= is set. */
rb_eIOTimeoutError = rb_define_class_under(rb_cIO, "TimeoutError", rb_eIOError);
- /* Readable event mask for IO#wait. */
rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
- /* Writable event mask for IO#wait. */
rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
- /* Priority event mask for IO#wait. */
rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
/* exception to wait for reading. see IO.select. */
@@ -15654,7 +15417,7 @@ Init_IO(void)
rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
- rb_vm_register_global_object(rb_default_rs);
+ rb_gc_register_mark_object(rb_default_rs);
rb_rs = rb_default_rs;
rb_output_rs = Qnil;
rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_str_setter);
@@ -15705,6 +15468,7 @@ Init_IO(void)
rb_define_method(rb_cIO, "read", io_read, -1);
rb_define_method(rb_cIO, "write", io_write_m, -1);
rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
+ rb_define_method(rb_cIO, "readline", rb_io_readline, -1);
rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
@@ -15739,7 +15503,7 @@ Init_IO(void)
rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
- rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
+ rb_define_method(rb_cIO, "closed?", rb_io_closed, 0);
rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
@@ -15848,7 +15612,7 @@ Init_IO(void)
rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
- rb_define_method(rb_cARGF, "write", argf_write, -1);
+ rb_define_method(rb_cARGF, "write", argf_write, 1);
rb_define_method(rb_cARGF, "print", rb_io_print, -1);
rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
diff --git a/io.rb b/io.rb
index 549c5e62bd..40873ea4fd 100644
--- a/io.rb
+++ b/io.rb
@@ -120,17 +120,4 @@ class IO
def write_nonblock(buf, exception: true)
Primitive.io_write_nonblock(buf, exception)
end
-
- # call-seq:
- # readline(sep = $/, chomp: false) -> string
- # readline(limit, chomp: false) -> string
- # readline(sep, limit, chomp: false) -> string
- #
- # Reads a line as with IO#gets, but raises EOFError if already at end-of-stream.
- #
- # Optional keyword argument +chomp+ specifies whether line separators
- # are to be omitted.
- def readline(sep = $/, limit = nil, chomp: false)
- Primitive.io_readline(sep, limit, chomp)
- end
end
diff --git a/io_buffer.c b/io_buffer.c
index 51ddde8c29..87b51c0b8c 100644
--- a/io_buffer.c
+++ b/io_buffer.c
@@ -6,6 +6,7 @@
**********************************************************************/
+#include "ruby/io.h"
#include "ruby/io/buffer.h"
#include "ruby/fiber/scheduler.h"
@@ -15,7 +16,7 @@
#include "internal/error.h"
#include "internal/numeric.h"
#include "internal/string.h"
-#include "internal/io.h"
+#include "internal/thread.h"
VALUE rb_cIOBuffer;
VALUE rb_eIOBufferLockedError;
@@ -33,18 +34,6 @@ size_t RUBY_IO_BUFFER_DEFAULT_SIZE;
#include <sys/mman.h>
#endif
-enum {
- RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH = 16,
-
- RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE = 256,
- RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH = 16,
-
- // This is used to validate the flags given by the user.
- RB_IO_BUFFER_FLAGS_MASK = RB_IO_BUFFER_EXTERNAL | RB_IO_BUFFER_INTERNAL | RB_IO_BUFFER_MAPPED | RB_IO_BUFFER_SHARED | RB_IO_BUFFER_LOCKED | RB_IO_BUFFER_PRIVATE | RB_IO_BUFFER_READONLY,
-
- RB_IO_BUFFER_DEBUG = 0,
-};
-
struct rb_io_buffer {
void *base;
size_t size;
@@ -102,9 +91,11 @@ io_buffer_map_file(struct rb_io_buffer *buffer, int descriptor, size_t size, rb_
access = FILE_MAP_WRITE;
}
+ HANDLE mapping = CreateFileMapping(file, NULL, protect, 0, 0, NULL);
+ if (!mapping) rb_sys_fail("io_buffer_map_descriptor:CreateFileMapping");
+
if (flags & RB_IO_BUFFER_PRIVATE) {
- protect = PAGE_WRITECOPY;
- access = FILE_MAP_COPY;
+ access |= FILE_MAP_COPY;
buffer->flags |= RB_IO_BUFFER_PRIVATE;
}
else {
@@ -113,10 +104,6 @@ io_buffer_map_file(struct rb_io_buffer *buffer, int descriptor, size_t size, rb_
buffer->flags |= RB_IO_BUFFER_SHARED;
}
- HANDLE mapping = CreateFileMapping(file, NULL, protect, 0, 0, NULL);
- if (RB_IO_BUFFER_DEBUG) fprintf(stderr, "io_buffer_map_file:CreateFileMapping -> %p\n", mapping);
- if (!mapping) rb_sys_fail("io_buffer_map_descriptor:CreateFileMapping");
-
void *base = MapViewOfFile(mapping, access, (DWORD)(offset >> 32), (DWORD)(offset & 0xFFFFFFFF), size);
if (!base) {
@@ -137,7 +124,6 @@ io_buffer_map_file(struct rb_io_buffer *buffer, int descriptor, size_t size, rb_
if (flags & RB_IO_BUFFER_PRIVATE) {
buffer->flags |= RB_IO_BUFFER_PRIVATE;
- access |= MAP_PRIVATE;
}
else {
// This buffer refers to external buffer.
@@ -157,7 +143,16 @@ io_buffer_map_file(struct rb_io_buffer *buffer, int descriptor, size_t size, rb_
buffer->size = size;
buffer->flags |= RB_IO_BUFFER_MAPPED;
- buffer->flags |= RB_IO_BUFFER_FILE;
+}
+
+static inline void
+io_buffer_unmap(void* base, size_t size)
+{
+#ifdef _WIN32
+ VirtualFree(base, 0, MEM_RELEASE);
+#else
+ munmap(base, size);
+#endif
}
static void
@@ -188,7 +183,7 @@ io_buffer_zero(struct rb_io_buffer *buffer)
}
static void
-io_buffer_initialize(VALUE self, struct rb_io_buffer *buffer, void *base, size_t size, enum rb_io_buffer_flags flags, VALUE source)
+io_buffer_initialize(struct rb_io_buffer *buffer, void *base, size_t size, enum rb_io_buffer_flags flags, VALUE source)
{
if (base) {
// If we are provided a pointer, we use it.
@@ -214,14 +209,10 @@ io_buffer_initialize(VALUE self, struct rb_io_buffer *buffer, void *base, size_t
buffer->base = base;
buffer->size = size;
buffer->flags = flags;
- RB_OBJ_WRITE(self, &buffer->source, source);
-
-#if defined(_WIN32)
- buffer->mapping = NULL;
-#endif
+ buffer->source = source;
}
-static void
+static int
io_buffer_free(struct rb_io_buffer *buffer)
{
if (buffer->base) {
@@ -230,16 +221,7 @@ io_buffer_free(struct rb_io_buffer *buffer)
}
if (buffer->flags & RB_IO_BUFFER_MAPPED) {
-#ifdef _WIN32
- if (buffer->flags & RB_IO_BUFFER_FILE) {
- UnmapViewOfFile(buffer->base);
- }
- else {
- VirtualFree(buffer->base, 0, MEM_RELEASE);
- }
-#else
- munmap(buffer->base, buffer->size);
-#endif
+ io_buffer_unmap(buffer->base, buffer->size);
}
// Previously we had this, but we found out due to the way GC works, we
@@ -250,20 +232,20 @@ io_buffer_free(struct rb_io_buffer *buffer)
buffer->base = NULL;
+#if defined(_WIN32)
+ if (buffer->mapping) {
+ CloseHandle(buffer->mapping);
+ buffer->mapping = NULL;
+ }
+#endif
buffer->size = 0;
buffer->flags = 0;
buffer->source = Qnil;
- }
-#if defined(_WIN32)
- if (buffer->mapping) {
- if (RB_IO_BUFFER_DEBUG) fprintf(stderr, "io_buffer_free:CloseHandle -> %p\n", buffer->mapping);
- if (!CloseHandle(buffer->mapping)) {
- fprintf(stderr, "io_buffer_free:GetLastError -> %lu\n", GetLastError());
- }
- buffer->mapping = NULL;
+ return 1;
}
-#endif
+
+ return 0;
}
void
@@ -279,6 +261,8 @@ rb_io_buffer_type_free(void *_buffer)
struct rb_io_buffer *buffer = _buffer;
io_buffer_free(buffer);
+
+ free(buffer);
}
size_t
@@ -302,23 +286,10 @@ static const rb_data_type_t rb_io_buffer_type = {
.dsize = rb_io_buffer_type_size,
},
.data = NULL,
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
};
-static inline enum rb_io_buffer_flags
-io_buffer_extract_flags(VALUE argument)
-{
- if (rb_int_negative_p(argument)) {
- rb_raise(rb_eArgError, "Flags can't be negative!");
- }
-
- enum rb_io_buffer_flags flags = RB_NUM2UINT(argument);
-
- // We deliberately ignore unknown flags. Any future flags which are exposed this way should be safe to ignore.
- return flags & RB_IO_BUFFER_FLAGS_MASK;
-}
-
-// Extract an offset argument, which must be a non-negative integer.
+// Extract an offset argument, which must be a positive integer.
static inline size_t
io_buffer_extract_offset(VALUE argument)
{
@@ -329,7 +300,7 @@ io_buffer_extract_offset(VALUE argument)
return NUM2SIZET(argument);
}
-// Extract a length argument, which must be a non-negative integer.
+// Extract a length argument, which must be a positive integer.
// Length is generally considered a mutable property of an object and
// semantically should be considered a subset of "size" as a concept.
static inline size_t
@@ -342,7 +313,7 @@ io_buffer_extract_length(VALUE argument)
return NUM2SIZET(argument);
}
-// Extract a size argument, which must be a non-negative integer.
+// Extract a size argument, which must be a positive integer.
// Size is generally considered an immutable property of an object.
static inline size_t
io_buffer_extract_size(VALUE argument)
@@ -354,24 +325,6 @@ io_buffer_extract_size(VALUE argument)
return NUM2SIZET(argument);
}
-// Extract a width argument, which must be a non-negative integer, and must be
-// at least the given minimum.
-static inline size_t
-io_buffer_extract_width(VALUE argument, size_t minimum)
-{
- if (rb_int_negative_p(argument)) {
- rb_raise(rb_eArgError, "Width can't be negative!");
- }
-
- size_t width = NUM2SIZET(argument);
-
- if (width < minimum) {
- rb_raise(rb_eArgError, "Width must be at least %" PRIuSIZE "!", minimum);
- }
-
- return width;
-}
-
// Compute the default length for a buffer, given an offset into that buffer.
// The default length is the size of the buffer minus the offset. The offset
// must be less than the size of the buffer otherwise the length will be
@@ -398,7 +351,7 @@ io_buffer_extract_length_offset(VALUE self, int argc, VALUE argv[], size_t *leng
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
- if (argc >= 2 && !NIL_P(argv[1])) {
+ if (argc >= 2) {
*offset = io_buffer_extract_offset(argv[1]);
}
else {
@@ -416,28 +369,22 @@ io_buffer_extract_length_offset(VALUE self, int argc, VALUE argv[], size_t *leng
}
// Extract the optional offset and length arguments, returning the buffer.
-// Similar to `io_buffer_extract_length_offset` but with the order of arguments
-// reversed.
-//
-// After much consideration, I decided to accept both forms.
-// The `(offset, length)` order is more natural when referring about data,
-// while the `(length, offset)` order is more natural when referring to
-// read/write operations. In many cases, with the latter form, `offset`
-// is usually not supplied.
+// Similar to `io_buffer_extract_length_offset` but with the order of
+// arguments reversed.
static inline struct rb_io_buffer *
io_buffer_extract_offset_length(VALUE self, int argc, VALUE argv[], size_t *offset, size_t *length)
{
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
- if (argc >= 1 && !NIL_P(argv[0])) {
+ if (argc >= 1) {
*offset = io_buffer_extract_offset(argv[0]);
}
else {
*offset = 0;
}
- if (argc >= 2 && !NIL_P(argv[1])) {
+ if (argc >= 2) {
*length = io_buffer_extract_length(argv[1]);
}
else {
@@ -473,7 +420,7 @@ static VALUE io_buffer_for_make_instance(VALUE klass, VALUE string, enum rb_io_b
if (!(flags & RB_IO_BUFFER_READONLY))
rb_str_modify(string);
- io_buffer_initialize(instance, buffer, RSTRING_PTR(string), RSTRING_LEN(string), flags, string);
+ io_buffer_initialize(buffer, RSTRING_PTR(string), RSTRING_LEN(string), flags, string);
return instance;
}
@@ -516,11 +463,11 @@ io_buffer_for_yield_instance_ensure(VALUE _arguments)
* IO::Buffer.for(string) -> readonly io_buffer
* IO::Buffer.for(string) {|io_buffer| ... read/write io_buffer ...}
*
- * Creates a zero-copy IO::Buffer from the given string's memory. Without a
- * block a frozen internal copy of the string is created efficiently and used
- * as the buffer source. When a block is provided, the buffer is associated
- * directly with the string's internal buffer and updating the buffer will
- * update the string.
+ * Creates a IO::Buffer from the given string's memory. Without a block a
+ * frozen internal copy of the string is created efficiently and used as the
+ * buffer source. When a block is provided, the buffer is associated directly
+ * with the string's internal buffer and updating the buffer will update the
+ * string.
*
* Until #free is invoked on the buffer, either explicitly or via the garbage
* collector, the source string will be locked and cannot be modified.
@@ -571,35 +518,6 @@ rb_io_buffer_type_for(VALUE klass, VALUE string)
}
}
-/*
- * call-seq:
- * IO::Buffer.string(length) {|io_buffer| ... read/write io_buffer ...} -> string
- *
- * Creates a new string of the given length and yields a zero-copy IO::Buffer
- * instance to the block which uses the string as a source. The block is
- * expected to write to the buffer and the string will be returned.
- *
- * IO::Buffer.string(4) do |buffer|
- * buffer.set_string("Ruby")
- * end
- * # => "Ruby"
- */
-VALUE
-rb_io_buffer_type_string(VALUE klass, VALUE length)
-{
- VALUE string = rb_str_new(NULL, RB_NUM2LONG(length));
-
- struct io_buffer_for_yield_instance_arguments arguments = {
- .klass = klass,
- .string = string,
- .instance = Qnil,
- };
-
- rb_ensure(io_buffer_for_yield_instance, (VALUE)&arguments, io_buffer_for_yield_instance_ensure, (VALUE)&arguments);
-
- return string;
-}
-
VALUE
rb_io_buffer_new(void *base, size_t size, enum rb_io_buffer_flags flags)
{
@@ -608,7 +526,7 @@ rb_io_buffer_new(void *base, size_t size, enum rb_io_buffer_flags flags)
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(instance, struct rb_io_buffer, &rb_io_buffer_type, buffer);
- io_buffer_initialize(instance, buffer, base, size, flags, Qnil);
+ io_buffer_initialize(buffer, base, size, flags, Qnil);
return instance;
}
@@ -642,6 +560,8 @@ rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer_flags
* mapping, you need to open a file in read-write mode, and explicitly pass
* +flags+ argument without IO::Buffer::IMMUTABLE.
*
+ * Example:
+ *
* File.write('test.txt', 'test')
*
* buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::READONLY)
@@ -704,7 +624,7 @@ io_buffer_map(int argc, VALUE *argv, VALUE klass)
enum rb_io_buffer_flags flags = 0;
if (argc >= 4) {
- flags = io_buffer_extract_flags(argv[3]);
+ flags = RB_NUM2UINT(argv[3]);
}
return rb_io_buffer_map(io, size, offset, flags);
@@ -732,6 +652,8 @@ io_flags_for_size(size_t size)
* on Windows). The behavior can be forced by passing IO::Buffer::MAPPED
* as a second parameter.
*
+ * Examples
+ *
* buffer = IO::Buffer.new(4)
* # =>
* # #<IO::Buffer 0x000055b34497ea10+4 INTERNAL>
@@ -765,13 +687,13 @@ rb_io_buffer_initialize(int argc, VALUE *argv, VALUE self)
enum rb_io_buffer_flags flags = 0;
if (argc >= 2) {
- flags = io_buffer_extract_flags(argv[1]);
+ flags = RB_NUM2UINT(argv[1]);
}
else {
flags |= io_flags_for_size(size);
}
- io_buffer_initialize(self, buffer, NULL, size, flags, Qnil);
+ io_buffer_initialize(buffer, NULL, size, flags, Qnil);
return self;
}
@@ -817,83 +739,6 @@ io_buffer_validate(struct rb_io_buffer *buffer)
}
}
-enum rb_io_buffer_flags
-rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size)
-{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
- if (io_buffer_validate(buffer)) {
- if (buffer->base) {
- *base = buffer->base;
- *size = buffer->size;
-
- return buffer->flags;
- }
- }
-
- *base = NULL;
- *size = 0;
-
- return 0;
-}
-
-// Internal function for accessing bytes for writing, wil
-static inline void
-io_buffer_get_bytes_for_writing(struct rb_io_buffer *buffer, void **base, size_t *size)
-{
- if (buffer->flags & RB_IO_BUFFER_READONLY ||
- (!NIL_P(buffer->source) && OBJ_FROZEN(buffer->source))) {
- rb_raise(rb_eIOBufferAccessError, "Buffer is not writable!");
- }
-
- if (!io_buffer_validate(buffer)) {
- rb_raise(rb_eIOBufferInvalidatedError, "Buffer is invalid!");
- }
-
- if (buffer->base) {
- *base = buffer->base;
- *size = buffer->size;
- } else {
- *base = NULL;
- *size = 0;
- }
-}
-
-void
-rb_io_buffer_get_bytes_for_writing(VALUE self, void **base, size_t *size)
-{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
- io_buffer_get_bytes_for_writing(buffer, base, size);
-}
-
-static void
-io_buffer_get_bytes_for_reading(struct rb_io_buffer *buffer, const void **base, size_t *size)
-{
- if (!io_buffer_validate(buffer)) {
- rb_raise(rb_eIOBufferInvalidatedError, "Buffer has been invalidated!");
- }
-
- if (buffer->base) {
- *base = buffer->base;
- *size = buffer->size;
- } else {
- *base = NULL;
- *size = 0;
- }
-}
-
-void
-rb_io_buffer_get_bytes_for_reading(VALUE self, const void **base, size_t *size)
-{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
- io_buffer_get_bytes_for_reading(buffer, base, size);
-}
-
/*
* call-seq: to_s -> string
*
@@ -930,10 +775,6 @@ rb_io_buffer_to_s(VALUE self)
rb_str_cat2(result, " MAPPED");
}
- if (buffer->flags & RB_IO_BUFFER_FILE) {
- rb_str_cat2(result, " FILE");
- }
-
if (buffer->flags & RB_IO_BUFFER_SHARED) {
rb_str_cat2(result, " SHARED");
}
@@ -942,10 +783,6 @@ rb_io_buffer_to_s(VALUE self)
rb_str_cat2(result, " LOCKED");
}
- if (buffer->flags & RB_IO_BUFFER_PRIVATE) {
- rb_str_cat2(result, " PRIVATE");
- }
-
if (buffer->flags & RB_IO_BUFFER_READONLY) {
rb_str_cat2(result, " READONLY");
}
@@ -961,38 +798,13 @@ rb_io_buffer_to_s(VALUE self)
return rb_str_cat2(result, ">");
}
-// Compute the output size of a hexdump of the given width (bytes per line), total size, and whether it is the first line in the output.
-// This is used to preallocate the output string.
-inline static size_t
-io_buffer_hexdump_output_size(size_t width, size_t size, int first)
-{
- // The preview on the right hand side is 1:1:
- size_t total = size;
-
- size_t whole_lines = (size / width);
- size_t partial_line = (size % width) ? 1 : 0;
-
- // For each line:
- // 1 byte 10 bytes 1 byte width*3 bytes 1 byte size bytes
- // (newline) (address) (space) (hexdump ) (space) (preview)
- total += (whole_lines + partial_line) * (1 + 10 + width*3 + 1 + 1);
-
- // If the hexdump is the first line, one less newline will be emitted:
- if (size && first) total -= 1;
-
- return total;
-}
-
-// Append a hexdump of the given width (bytes per line), base address, size, and whether it is the first line in the output.
-// If the hexdump is not the first line, it will prepend a newline if there is any output at all.
-// If formatting here is adjusted, please update io_buffer_hexdump_output_size accordingly.
static VALUE
-io_buffer_hexdump(VALUE string, size_t width, const char *base, size_t length, size_t offset, int first)
+io_buffer_hexdump(VALUE string, size_t width, char *base, size_t size, int first)
{
char *text = alloca(width+1);
text[width] = '\0';
- for (; offset < length; offset += width) {
+ for (size_t offset = 0; offset < size; offset += width) {
memset(text, '\0', width);
if (first) {
rb_str_catf(string, "0x%08" PRIxSIZE " ", offset);
@@ -1003,7 +815,7 @@ io_buffer_hexdump(VALUE string, size_t width, const char *base, size_t length, s
}
for (size_t i = 0; i < width; i += 1) {
- if (offset+i < length) {
+ if (offset+i < size) {
unsigned char value = ((unsigned char*)base)[offset+i];
if (value < 127 && isprint(value)) {
@@ -1026,18 +838,23 @@ io_buffer_hexdump(VALUE string, size_t width, const char *base, size_t length, s
return string;
}
-/*
- * call-seq: inspect -> string
- *
- * Inspect the buffer and report useful information about it's internal state.
- * Only a limited portion of the buffer will be displayed in a hexdump style
- * format.
- *
- * buffer = IO::Buffer.for("Hello World")
- * puts buffer.inspect
- * # #<IO::Buffer 0x000000010198ccd8+11 EXTERNAL READONLY SLICE>
- * # 0x00000000 48 65 6c 6c 6f 20 57 6f 72 6c 64 Hello World
- */
+static VALUE
+rb_io_buffer_hexdump(VALUE self)
+{
+ struct rb_io_buffer *buffer = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+
+ VALUE result = Qnil;
+
+ if (io_buffer_validate(buffer) && buffer->base) {
+ result = rb_str_buf_new(buffer->size*3 + (buffer->size/16)*12 + 1);
+
+ io_buffer_hexdump(result, 16, buffer->base, buffer->size, 1);
+ }
+
+ return result;
+}
+
VALUE
rb_io_buffer_inspect(VALUE self)
{
@@ -1047,19 +864,9 @@ rb_io_buffer_inspect(VALUE self)
VALUE result = rb_io_buffer_to_s(self);
if (io_buffer_validate(buffer)) {
- // Limit the maximum size generated by inspect:
- size_t size = buffer->size;
- int clamped = 0;
-
- if (size > RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE) {
- size = RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE;
- clamped = 1;
- }
-
- io_buffer_hexdump(result, RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH, buffer->base, size, 0, 0);
-
- if (clamped) {
- rb_str_catf(result, "\n(and %" PRIuSIZE " more bytes not printed)", buffer->size - size);
+ // Limit the maximum size generated by inspect.
+ if (buffer->size <= 256) {
+ io_buffer_hexdump(result, 16, buffer->base, buffer->size, 0);
}
}
@@ -1086,8 +893,8 @@ rb_io_buffer_size(VALUE self)
*
* Returns whether the buffer buffer is accessible.
*
- * A buffer becomes invalid if it is a slice of another buffer (or string)
- * which has been freed or re-allocated at a different address.
+ * A buffer becomes invalid if it is a slice of another buffer which has been
+ * freed.
*/
static VALUE
rb_io_buffer_valid_p(VALUE self)
@@ -1101,16 +908,8 @@ rb_io_buffer_valid_p(VALUE self)
/*
* call-seq: null? -> true or false
*
- * If the buffer was freed with #free, transferred with #transfer, or was
- * never allocated in the first place.
- *
- * buffer = IO::Buffer.new(0)
- * buffer.null? #=> true
- *
- * buffer = IO::Buffer.new(4)
- * buffer.null? #=> false
- * buffer.free
- * buffer.null? #=> true
+ * If the buffer was freed with #free or was never allocated in the first
+ * place.
*/
static VALUE
rb_io_buffer_null_p(VALUE self)
@@ -1210,22 +1009,6 @@ rb_io_buffer_mapped_p(VALUE self)
* If the buffer is _shared_, meaning it references memory that can be shared
* with other processes (and thus might change without being modified
* locally).
- *
- * # Create a test file:
- * File.write('test.txt', 'test')
- *
- * # Create a shared mapping from the given file, the file must be opened in
- * # read-write mode unless we also specify IO::Buffer::READONLY:
- * buffer = IO::Buffer.map(File.open('test.txt', 'r+'), nil, 0)
- * # => #<IO::Buffer 0x00007f1bffd5e000+4 EXTERNAL MAPPED SHARED>
- *
- * # Write to the buffer, which will modify the mapped file:
- * buffer.set_string('b', 0)
- * # => 1
- *
- * # The file itself is modified:
- * File.read('test.txt')
- * # => "best"
*/
static VALUE
rb_io_buffer_shared_p(VALUE self)
@@ -1246,6 +1029,8 @@ rb_io_buffer_shared_p(VALUE self)
* Locking is not thread safe, but is a semantic used to ensure buffers don't
* move while being used by a system call.
*
+ * Example:
+ *
* buffer.locked do
* buffer.write(io) # theoretical system call interface
* end
@@ -1259,37 +1044,6 @@ rb_io_buffer_locked_p(VALUE self)
return RBOOL(buffer->flags & RB_IO_BUFFER_LOCKED);
}
-/* call-seq: private? -> true or false
- *
- * If the buffer is _private_, meaning modifications to the buffer will not
- * be replicated to the underlying file mapping.
- *
- * # Create a test file:
- * File.write('test.txt', 'test')
- *
- * # Create a private mapping from the given file. Note that the file here
- * # is opened in read-only mode, but it doesn't matter due to the private
- * # mapping:
- * buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::PRIVATE)
- * # => #<IO::Buffer 0x00007fce63f11000+4 MAPPED PRIVATE>
- *
- * # Write to the buffer (invoking CoW of the underlying file buffer):
- * buffer.set_string('b', 0)
- * # => 1
- *
- * # The file itself is not modified:
- * File.read('test.txt')
- * # => "test"
- */
-static VALUE
-rb_io_buffer_private_p(VALUE self)
-{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
- return RBOOL(buffer->flags & RB_IO_BUFFER_PRIVATE);
-}
-
int
rb_io_buffer_readonly_p(VALUE self)
{
@@ -1383,6 +1137,8 @@ rb_io_buffer_try_unlock(VALUE self)
* non-blocking system calls. You can only share a buffer between threads with
* appropriate synchronisation techniques.
*
+ * Example:
+ *
* buffer = IO::Buffer.new(4)
* buffer.locked? #=> false
*
@@ -1430,6 +1186,8 @@ rb_io_buffer_locked(VALUE self)
*
* You can resize a freed buffer to re-allocate it.
*
+ * Example:
+ *
* buffer = IO::Buffer.for('test')
* buffer.free
* # => #<IO::Buffer 0x0000000000000000+0 NULL>
@@ -1458,17 +1216,6 @@ rb_io_buffer_free(VALUE self)
return self;
}
-VALUE rb_io_buffer_free_locked(VALUE self)
-{
- struct rb_io_buffer *buffer = NULL;
- TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
-
- io_buffer_unlock(buffer);
- io_buffer_free(buffer);
-
- return self;
-}
-
// Validate that access to the buffer is within bounds, assuming you want to
// access length bytes from the specified offset.
static inline void
@@ -1480,49 +1227,6 @@ io_buffer_validate_range(struct rb_io_buffer *buffer, size_t offset, size_t leng
}
}
-/*
- * call-seq: hexdump([offset, [length, [width]]]) -> string
- *
- * Returns a human-readable string representation of the buffer. The exact
- * format is subject to change.
- *
- * buffer = IO::Buffer.for("Hello World")
- * puts buffer.hexdump
- * # 0x00000000 48 65 6c 6c 6f 20 57 6f 72 6c 64 Hello World
- *
- * As buffers are usually fairly big, you may want to limit the output by
- * specifying the offset and length:
- *
- * puts buffer.hexdump(6, 5)
- * # 0x00000006 57 6f 72 6c 64 World
- */
-static VALUE
-rb_io_buffer_hexdump(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 3);
-
- size_t offset, length;
- struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
-
- size_t width = RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH;
- if (argc >= 3) {
- width = io_buffer_extract_width(argv[2], 1);
- }
-
- // This may raise an exception if the offset/length is invalid:
- io_buffer_validate_range(buffer, offset, length);
-
- VALUE result = Qnil;
-
- if (io_buffer_validate(buffer) && buffer->base) {
- result = rb_str_buf_new(io_buffer_hexdump_output_size(width, length, 1));
-
- io_buffer_hexdump(result, width, buffer->base, offset+length, offset, 1);
- }
-
- return result;
-}
-
static VALUE
rb_io_buffer_slice(struct rb_io_buffer *buffer, VALUE self, size_t offset, size_t length)
{
@@ -1537,12 +1241,10 @@ rb_io_buffer_slice(struct rb_io_buffer *buffer, VALUE self, size_t offset, size_
slice->size = length;
// The source should be the root buffer:
- if (buffer->source != Qnil) {
- RB_OBJ_WRITE(instance, &slice->source, buffer->source);
- }
- else {
- RB_OBJ_WRITE(instance, &slice->source, self);
- }
+ if (buffer->source != Qnil)
+ slice->source = buffer->source;
+ else
+ slice->source = self;
return instance;
}
@@ -1566,8 +1268,10 @@ rb_io_buffer_slice(struct rb_io_buffer *buffer, VALUE self, size_t offset, size_
* Raises RuntimeError if the <tt>offset+length</tt> is out of the current
* buffer's bounds.
*
+ * Example:
+ *
* string = 'test'
- * buffer = IO::Buffer.for(string).dup
+ * buffer = IO::Buffer.for(string)
*
* slice = buffer.slice
* # =>
@@ -1594,8 +1298,12 @@ rb_io_buffer_slice(struct rb_io_buffer *buffer, VALUE self, size_t offset, size_
* # it is also visible at position 1 of the original buffer
* buffer
* # =>
- * # #<IO::Buffer 0x00007fc3d31e2d80+4 INTERNAL>
+ * # #<IO::Buffer 0x00007fc3d31e2d80+4 SLICE>
* # 0x00000000 74 6f 73 74 tost
+ *
+ * # ...and original string
+ * string
+ * # => tost
*/
static VALUE
io_buffer_slice(int argc, VALUE *argv, VALUE self)
@@ -1608,11 +1316,90 @@ io_buffer_slice(int argc, VALUE *argv, VALUE self)
return rb_io_buffer_slice(buffer, self, offset, length);
}
+int
+rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size)
+{
+ struct rb_io_buffer *buffer = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+
+ if (io_buffer_validate(buffer)) {
+ if (buffer->base) {
+ *base = buffer->base;
+ *size = buffer->size;
+
+ return buffer->flags;
+ }
+ }
+
+ *base = NULL;
+ *size = 0;
+
+ return 0;
+}
+
+static inline void
+io_buffer_get_bytes_for_writing(struct rb_io_buffer *buffer, void **base, size_t *size)
+{
+ if (buffer->flags & RB_IO_BUFFER_READONLY ||
+ (!NIL_P(buffer->source) && OBJ_FROZEN(buffer->source))) {
+ rb_raise(rb_eIOBufferAccessError, "Buffer is not writable!");
+ }
+
+ if (!io_buffer_validate(buffer)) {
+ rb_raise(rb_eIOBufferInvalidatedError, "Buffer is invalid!");
+ }
+
+ if (buffer->base) {
+ *base = buffer->base;
+ *size = buffer->size;
+
+ return;
+ }
+
+ rb_raise(rb_eIOBufferAllocationError, "The buffer is not allocated!");
+}
+
+void
+rb_io_buffer_get_bytes_for_writing(VALUE self, void **base, size_t *size)
+{
+ struct rb_io_buffer *buffer = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+
+ io_buffer_get_bytes_for_writing(buffer, base, size);
+}
+
+static void
+io_buffer_get_bytes_for_reading(struct rb_io_buffer *buffer, const void **base, size_t *size)
+{
+ if (!io_buffer_validate(buffer)) {
+ rb_raise(rb_eIOBufferInvalidatedError, "Buffer has been invalidated!");
+ }
+
+ if (buffer->base) {
+ *base = buffer->base;
+ *size = buffer->size;
+
+ return;
+ }
+
+ rb_raise(rb_eIOBufferAllocationError, "The buffer is not allocated!");
+}
+
+void
+rb_io_buffer_get_bytes_for_reading(VALUE self, const void **base, size_t *size)
+{
+ struct rb_io_buffer *buffer = NULL;
+ TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
+
+ io_buffer_get_bytes_for_reading(buffer, base, size);
+}
+
/*
* call-seq: transfer -> new_io_buffer
*
- * Transfers ownership of the underlying memory to a new buffer, causing the
- * current buffer to become uninitialized.
+ * Transfers ownership to a new buffer, deallocating the current one.
+ *
+ * Example:
*
* buffer = IO::Buffer.new('test')
* other = buffer.transfer
@@ -1655,11 +1442,11 @@ io_buffer_resize_clear(struct rb_io_buffer *buffer, void* base, size_t size)
}
static void
-io_buffer_resize_copy(VALUE self, struct rb_io_buffer *buffer, size_t size)
+io_buffer_resize_copy(struct rb_io_buffer *buffer, size_t size)
{
// Slow path:
struct rb_io_buffer resized;
- io_buffer_initialize(self, &resized, NULL, size, io_flags_for_size(size), Qnil);
+ io_buffer_initialize(&resized, NULL, size, io_flags_for_size(size), Qnil);
if (buffer->base) {
size_t preserve = buffer->size;
@@ -1684,7 +1471,7 @@ rb_io_buffer_resize(VALUE self, size_t size)
}
if (buffer->base == NULL) {
- io_buffer_initialize(self, buffer, NULL, size, io_flags_for_size(size), Qnil);
+ io_buffer_initialize(buffer, NULL, size, io_flags_for_size(size), Qnil);
return;
}
@@ -1729,7 +1516,7 @@ rb_io_buffer_resize(VALUE self, size_t size)
return;
}
- io_buffer_resize_copy(self, buffer, size);
+ io_buffer_resize_copy(buffer, size);
}
/*
@@ -1924,6 +1711,8 @@ io_buffer_buffer_type_size(ID buffer_type)
*
* Returns the size of the given buffer type(s) in bytes.
*
+ * Example:
+ *
* IO::Buffer.size_of(:u32) # => 4
* IO::Buffer.size_of([:u32, :u32]) # => 8
*/
@@ -2002,6 +1791,8 @@ rb_io_buffer_get_value(const void* base, size_t size, ID buffer_type, size_t *of
* in the buffer. For example, a +:u32+ buffer type is a 32-bit unsigned
* integer in little-endian format.
*
+ * Example:
+ *
* string = [1.5].pack('f')
* # => "\x00\x00\xC0?"
* IO::Buffer.for(string).get_value(:f32, 0)
@@ -2025,6 +1816,8 @@ io_buffer_get_value(VALUE self, VALUE type, VALUE _offset)
* Similar to #get_value, except that it can handle multiple buffer types and
* returns an array of values.
*
+ * Example:
+ *
* string = [1.5, 2.5].pack('ff')
* IO::Buffer.for(string).get_values([:f32, :f32], 0)
* # => [1.5, 2.5]
@@ -2097,6 +1890,8 @@ io_buffer_extract_offset_count(ID buffer_type, size_t size, int argc, VALUE *arg
*
* If +count+ is given, only +count+ values will be yielded.
*
+ * Example:
+ *
* IO::Buffer.for("Hello World").each(:U8, 2, 2) do |offset, value|
* puts "#{offset}: #{value}"
* end
@@ -2140,6 +1935,8 @@ io_buffer_each(int argc, VALUE *argv, VALUE self)
*
* If +count+ is given, only +count+ values will be returned.
*
+ * Example:
+ *
* IO::Buffer.for("Hello World").values(:U8, 2, 2)
* # => [108, 108]
*/
@@ -2181,6 +1978,8 @@ io_buffer_values(int argc, VALUE *argv, VALUE self)
*
* If +count+ is given, only +count+ bytes will be yielded.
*
+ * Example:
+ *
* IO::Buffer.for("Hello World").each_byte(2, 2) do |offset, byte|
* puts "#{offset}: #{byte}"
* end
@@ -2290,6 +2089,8 @@ io_buffer_set_value(VALUE self, VALUE type, VALUE _offset, VALUE value)
* should be an array of symbols as described in #get_value. +values+ should
* be an array of values to write.
*
+ * Example:
+ *
* buffer = IO::Buffer.new(8)
* buffer.set_values([:U8, :U16], 0, [1, 2])
* buffer
@@ -2410,7 +2211,7 @@ rb_io_buffer_initialize_copy(VALUE self, VALUE source)
rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
- io_buffer_initialize(self, buffer, NULL, source_size, io_flags_for_size(source_size), Qnil);
+ io_buffer_initialize(buffer, NULL, source_size, io_flags_for_size(source_size), Qnil);
return io_buffer_copy_from(buffer, source_base, source_size, 0, NULL);
}
@@ -2419,8 +2220,8 @@ rb_io_buffer_initialize_copy(VALUE self, VALUE source)
* call-seq:
* copy(source, [offset, [length, [source_offset]]]) -> size
*
- * Efficiently copy from a source IO::Buffer into the buffer, at +offset+
- * using +memcpy+. For copying String instances, see #set_string.
+ * Efficiently copy buffer from a source IO::Buffer into the buffer,
+ * at +offset+ using +memcpy+. For copying String instances, see #set_string.
*
* buffer = IO::Buffer.new(32)
* # =>
@@ -2438,14 +2239,13 @@ rb_io_buffer_initialize_copy(VALUE self, VALUE source)
*
* #copy can be used to put buffer into strings associated with buffer:
*
- * string = "data: "
- * # => "data: "
- * buffer = IO::Buffer.for(string) do |buffer|
- * buffer.copy(IO::Buffer.for("test"), 5)
- * end
+ * string= "buffer: "
+ * # => "buffer: "
+ * buffer = IO::Buffer.for(string)
+ * buffer.copy(IO::Buffer.for("test"), 5)
* # => 4
* string
- * # => "data:test"
+ * # => "buffer:test"
*
* Attempt to copy into a read-only buffer will fail:
*
@@ -2529,8 +2329,8 @@ io_buffer_get_string(int argc, VALUE *argv, VALUE self)
/*
* call-seq: set_string(string, [offset, [length, [source_offset]]]) -> size
*
- * Efficiently copy from a source String into the buffer, at +offset+ using
- * +memcpy+.
+ * Efficiently copy buffer from a source String into the buffer,
+ * at +offset+ using +memcpy+.
*
* buf = IO::Buffer.new(8)
* # =>
@@ -2586,29 +2386,29 @@ rb_io_buffer_clear(VALUE self, uint8_t value, size_t offset, size_t length)
* Fill buffer with +value+, starting with +offset+ and going for +length+
* bytes.
*
- * buffer = IO::Buffer.for('test').dup
+ * buffer = IO::Buffer.for('test')
* # =>
- * # <IO::Buffer 0x00007fca40087c38+4 INTERNAL>
+ * # <IO::Buffer 0x00007fca40087c38+4 SLICE>
* # 0x00000000 74 65 73 74 test
*
* buffer.clear
* # =>
- * # <IO::Buffer 0x00007fca40087c38+4 INTERNAL>
+ * # <IO::Buffer 0x00007fca40087c38+4 SLICE>
* # 0x00000000 00 00 00 00 ....
*
* buf.clear(1) # fill with 1
* # =>
- * # <IO::Buffer 0x00007fca40087c38+4 INTERNAL>
+ * # <IO::Buffer 0x00007fca40087c38+4 SLICE>
* # 0x00000000 01 01 01 01 ....
*
* buffer.clear(2, 1, 2) # fill with 2, starting from offset 1, for 2 bytes
* # =>
- * # <IO::Buffer 0x00007fca40087c38+4 INTERNAL>
+ * # <IO::Buffer 0x00007fca40087c38+4 SLICE>
* # 0x00000000 01 02 02 01 ....
*
* buffer.clear(2, 1) # fill with 2, starting from offset 1
* # =>
- * # <IO::Buffer 0x00007fca40087c38+4 INTERNAL>
+ * # <IO::Buffer 0x00007fca40087c38+4 SLICE>
* # 0x00000000 01 02 02 02 ....
*/
static VALUE
@@ -2655,10 +2455,10 @@ io_buffer_default_size(size_t page_size)
}
struct io_buffer_blocking_region_argument {
- struct rb_io *io;
struct rb_io_buffer *buffer;
rb_blocking_function_t *function;
void *data;
+ int descriptor;
};
static VALUE
@@ -2666,7 +2466,7 @@ io_buffer_blocking_region_begin(VALUE _argument)
{
struct io_buffer_blocking_region_argument *argument = (void*)_argument;
- return rb_io_blocking_region(argument->io, argument->function, argument->data);
+ return rb_thread_io_blocking_region(argument->function, argument->data, argument->descriptor);
}
static VALUE
@@ -2680,17 +2480,13 @@ io_buffer_blocking_region_ensure(VALUE _argument)
}
static VALUE
-io_buffer_blocking_region(VALUE io, struct rb_io_buffer *buffer, rb_blocking_function_t *function, void *data)
+io_buffer_blocking_region(struct rb_io_buffer *buffer, rb_blocking_function_t *function, void *data, int descriptor)
{
- io = rb_io_get_io(io);
- struct rb_io *ioptr;
- RB_IO_POINTER(io, ioptr);
-
struct io_buffer_blocking_region_argument argument = {
- .io = ioptr,
.buffer = buffer,
.function = function,
.data = data,
+ .descriptor = descriptor,
};
// If the buffer is already locked, we can skip the ensure (unlock):
@@ -2706,12 +2502,13 @@ io_buffer_blocking_region(VALUE io, struct rb_io_buffer *buffer, rb_blocking_fun
}
struct io_buffer_read_internal_argument {
- // The file descriptor to read from:
int descriptor;
+
// The base pointer to read from:
char *base;
// The size of the buffer:
size_t size;
+
// The minimum number of bytes to read:
size_t length;
};
@@ -2777,7 +2574,7 @@ rb_io_buffer_read(VALUE self, VALUE io, size_t length, size_t offset)
.length = length,
};
- return io_buffer_blocking_region(io, buffer, io_buffer_read_internal, &argument);
+ return io_buffer_blocking_region(buffer, io_buffer_read_internal, &argument, descriptor);
}
/*
@@ -2820,45 +2617,35 @@ io_buffer_read(int argc, VALUE *argv, VALUE self)
}
struct io_buffer_pread_internal_argument {
- // The file descriptor to read from:
int descriptor;
- // The base pointer to read from:
- char *base;
- // The size of the buffer:
+ void *base;
size_t size;
- // The minimum number of bytes to read:
- size_t length;
- // The offset to read from:
off_t offset;
};
static VALUE
io_buffer_pread_internal(void *_argument)
{
- size_t total = 0;
struct io_buffer_pread_internal_argument *argument = _argument;
- while (true) {
- ssize_t result = pread(argument->descriptor, argument->base, argument->size, argument->offset);
+#if defined(HAVE_PREAD)
+ ssize_t result = pread(argument->descriptor, argument->base, argument->size, argument->offset);
+#else
+ // This emulation is not thread safe.
+ rb_off_t offset = lseek(argument->descriptor, 0, SEEK_CUR);
+ if (offset == (rb_off_t)-1)
+ return rb_fiber_scheduler_io_result(-1, errno);
- if (result < 0) {
- return rb_fiber_scheduler_io_result(result, errno);
- }
- else if (result == 0) {
- return rb_fiber_scheduler_io_result(total, 0);
- }
- else {
- total += result;
+ if (lseek(argument->descriptor, argument->offset, SEEK_SET) == (rb_off_t)-1)
+ return rb_fiber_scheduler_io_result(-1, errno);
- if (total >= argument->length) {
- return rb_fiber_scheduler_io_result(total, 0);
- }
+ ssize_t result = read(argument->descriptor, argument->base, argument->size);
- argument->base = argument->base + result;
- argument->size = argument->size - result;
- argument->offset = argument->offset + result;
- }
- }
+ if (lseek(argument->descriptor, offset, SEEK_SET) == (rb_off_t)-1)
+ return rb_fiber_scheduler_io_result(-1, errno);
+#endif
+
+ return rb_fiber_scheduler_io_result(result, errno);
}
VALUE
@@ -2884,34 +2671,32 @@ rb_io_buffer_pread(VALUE self, VALUE io, rb_off_t from, size_t length, size_t of
size_t size;
io_buffer_get_bytes_for_writing(buffer, &base, &size);
- base = (unsigned char*)base + offset;
- size = size - offset;
-
struct io_buffer_pread_internal_argument argument = {
.descriptor = descriptor,
- .base = base,
- .size = size,
- .length = length,
+
+ // Move the base pointer to the offset:
+ .base = (unsigned char*)base + offset,
+
+ // And the size to the length of buffer we want to read:
+ .size = length,
+
+ // From the offset in the file we want to read from:
.offset = from,
};
- return io_buffer_blocking_region(io, buffer, io_buffer_pread_internal, &argument);
+ return io_buffer_blocking_region(buffer, io_buffer_pread_internal, &argument, descriptor);
}
/*
- * call-seq: pread(io, from, [length, [offset]]) -> read length or -errno
+ * call-seq: pread(io, from, length, [offset]) -> read length or -errno
*
- * Read at least +length+ bytes from the +io+ starting at the specified +from+
- * position, into the buffer starting at +offset+. If an error occurs,
- * return <tt>-errno</tt>.
+ * Read at most +length+ bytes from +io+ into the buffer, starting at
+ * +from+, and put it in buffer starting from specified +offset+.
+ * If an error occurs, return <tt>-errno</tt>.
*
- * If +length+ is not given or +nil+, it defaults to the size of the buffer
- * minus the offset, i.e. the entire buffer.
+ * If +offset+ is not given, put it at the beginning of the buffer.
*
- * If +length+ is zero, exactly one <tt>pread</tt> operation will occur.
- *
- * If +offset+ is not given, it defaults to zero, i.e. the beginning of the
- * buffer.
+ * Example:
*
* IO::Buffer.for('test') do |buffer|
* p buffer
@@ -2943,12 +2728,13 @@ io_buffer_pread(int argc, VALUE *argv, VALUE self)
}
struct io_buffer_write_internal_argument {
- // The file descriptor to write to:
int descriptor;
+
// The base pointer to write from:
const char *base;
// The size of the buffer:
size_t size;
+
// The minimum length to write:
size_t length;
};
@@ -3014,7 +2800,7 @@ rb_io_buffer_write(VALUE self, VALUE io, size_t length, size_t offset)
.length = length,
};
- return io_buffer_blocking_region(io, buffer, io_buffer_write_internal, &argument);
+ return io_buffer_blocking_region(buffer, io_buffer_write_internal, &argument, descriptor);
}
/*
@@ -3048,46 +2834,37 @@ io_buffer_write(int argc, VALUE *argv, VALUE self)
return rb_io_buffer_write(self, io, length, offset);
}
+
struct io_buffer_pwrite_internal_argument {
- // The file descriptor to write to:
int descriptor;
- // The base pointer to write from:
- const char *base;
- // The size of the buffer:
+ const void *base;
size_t size;
- // The minimum length to write:
- size_t length;
- // The offset to write to:
off_t offset;
};
static VALUE
io_buffer_pwrite_internal(void *_argument)
{
- size_t total = 0;
struct io_buffer_pwrite_internal_argument *argument = _argument;
- while (true) {
- ssize_t result = pwrite(argument->descriptor, argument->base, argument->size, argument->offset);
+#if defined(HAVE_PWRITE)
+ ssize_t result = pwrite(argument->descriptor, argument->base, argument->size, argument->offset);
+#else
+ // This emulation is not thread safe.
+ rb_off_t offset = lseek(argument->descriptor, 0, SEEK_CUR);
+ if (offset == (rb_off_t)-1)
+ return rb_fiber_scheduler_io_result(-1, errno);
- if (result < 0) {
- return rb_fiber_scheduler_io_result(result, errno);
- }
- else if (result == 0) {
- return rb_fiber_scheduler_io_result(total, 0);
- }
- else {
- total += result;
+ if (lseek(argument->descriptor, argument->offset, SEEK_SET) == (rb_off_t)-1)
+ return rb_fiber_scheduler_io_result(-1, errno);
- if (total >= argument->length) {
- return rb_fiber_scheduler_io_result(total, 0);
- }
+ ssize_t result = write(argument->descriptor, argument->base, argument->size);
- argument->base = argument->base + result;
- argument->size = argument->size - result;
- argument->offset = argument->offset + result;
- }
- }
+ if (lseek(argument->descriptor, offset, SEEK_SET) == (rb_off_t)-1)
+ return rb_fiber_scheduler_io_result(-1, errno);
+#endif
+
+ return rb_fiber_scheduler_io_result(result, errno);
}
VALUE
@@ -3113,45 +2890,31 @@ rb_io_buffer_pwrite(VALUE self, VALUE io, rb_off_t from, size_t length, size_t o
size_t size;
io_buffer_get_bytes_for_reading(buffer, &base, &size);
- base = (unsigned char*)base + offset;
- size = size - offset;
-
struct io_buffer_pwrite_internal_argument argument = {
.descriptor = descriptor,
// Move the base pointer to the offset:
- .base = base,
+ .base = (unsigned char *)base + offset,
// And the size to the length of buffer we want to read:
- .size = size,
-
- // And the length of the buffer we want to write:
- .length = length,
+ .size = length,
// And the offset in the file we want to write from:
.offset = from,
};
- return io_buffer_blocking_region(io, buffer, io_buffer_pwrite_internal, &argument);
+ return io_buffer_blocking_region(buffer, io_buffer_pwrite_internal, &argument, descriptor);
}
/*
- * call-seq: pwrite(io, from, [length, [offset]]) -> written length or -errno
- *
- * Write at least +length+ bytes from the buffer starting at +offset+, into
- * the +io+ starting at the specified +from+ position. If an error occurs,
- * return <tt>-errno</tt>.
- *
- * If +length+ is not given or +nil+, it defaults to the size of the buffer
- * minus the offset, i.e. the entire buffer.
- *
- * If +length+ is zero, exactly one <tt>pwrite</tt> operation will occur.
+ * call-seq: pwrite(io, from, length, [offset]) -> written length or -errno
*
- * If +offset+ is not given, it defaults to zero, i.e. the beginning of the
- * buffer.
+ * Writes +length+ bytes from buffer into +io+, starting at
+ * +offset+ in the buffer. If an error occurs, return <tt>-errno</tt>.
*
- * If the +from+ position is beyond the end of the file, the gap will be
- * filled with null (0 value) bytes.
+ * If +offset+ is not given, the bytes are taken from the beginning of the
+ * buffer. If the +offset+ is given and is beyond the end of the file, the
+ * gap will be filled with null (0 value) bytes.
*
* out = File.open('output.txt', File::RDWR) # open for read/write, no truncation
* IO::Buffer.for('1234567').pwrite(out, 2, 3, 1)
@@ -3533,28 +3296,24 @@ io_buffer_not_inplace(VALUE self)
/*
* Document-class: IO::Buffer
*
- * IO::Buffer is a efficient zero-copy buffer for input/output. There are
- * typical use cases:
+ * IO::Buffer is a low-level efficient buffer for input/output. There are three
+ * ways of using buffer:
*
* * Create an empty buffer with ::new, fill it with buffer using #copy or
- * #set_value, #set_string, get buffer with #get_string or write it directly
- * to some file with #write.
+ * #set_value, #set_string, get buffer with #get_string;
* * Create a buffer mapped to some string with ::for, then it could be used
* both for reading with #get_string or #get_value, and writing (writing will
- * change the source string, too).
+ * change the source string, too);
* * Create a buffer mapped to some file with ::map, then it could be used for
* reading and writing the underlying file.
- * * Create a string of a fixed size with ::string, then #read into it, or
- * modify it using #set_value.
*
* Interaction with string and file memory is performed by efficient low-level
* C mechanisms like `memcpy`.
*
* The class is meant to be an utility for implementing more high-level mechanisms
- * like Fiber::Scheduler#io_read and Fiber::Scheduler#io_write and parsing binary
- * protocols.
+ * like Fiber::SchedulerInterface#io_read and Fiber::SchedulerInterface#io_write.
*
- * == Examples of Usage
+ * <b>Examples of usage:</b>
*
* Empty buffer:
*
@@ -3573,28 +3332,30 @@ io_buffer_not_inplace(VALUE self)
*
* \Buffer from string:
*
- * string = 'data'
- * IO::Buffer.for(string) do |buffer|
- * buffer
- * # =>
- * # #<IO::Buffer 0x00007f3f02be9b18+4 SLICE>
- * # 0x00000000 64 61 74 61 data
- *
- * buffer.get_string(2) # read content starting from offset 2
- * # => "ta"
- * buffer.set_string('---', 1) # write content, starting from offset 1
- * # => 3
- * buffer
- * # =>
- * # #<IO::Buffer 0x00007f3f02be9b18+4 SLICE>
- * # 0x00000000 64 2d 2d 2d d---
- * string # original string changed, too
- * # => "d---"
- * end
+ * string = 'buffer'
+ * buffer = IO::Buffer.for(string)
+ * # =>
+ * # #<IO::Buffer 0x00007f3f02be9b18+4 SLICE>
+ * # ...
+ * buffer
+ * # =>
+ * # #<IO::Buffer 0x00007f3f02be9b18+4 SLICE>
+ * # 0x00000000 64 61 74 61 buffer
+ *
+ * buffer.get_string(2) # read content starting from offset 2
+ * # => "ta"
+ * buffer.set_string('---', 1) # write content, starting from offset 1
+ * # => 3
+ * buffer
+ * # =>
+ * # #<IO::Buffer 0x00007f3f02be9b18+4 SLICE>
+ * # 0x00000000 64 2d 2d 2d d---
+ * string # original string changed, too
+ * # => "d---"
*
* \Buffer from file:
*
- * File.write('test.txt', 'test data')
+ * File.write('test.txt', 'test buffer')
* # => 9
* buffer = IO::Buffer.map(File.open('test.txt'))
* # =>
@@ -3611,35 +3372,22 @@ io_buffer_not_inplace(VALUE self)
* buffer.set_string('---', 1)
* # => 3 -- bytes written
* File.read('test.txt')
- * # => "t--- data"
+ * # => "t--- buffer"
*
- * <b>The class is experimental and the interface is subject to change, this
- * is especially true of file mappings which may be removed entirely in
- * the future.</b>
+ * <b>The class is experimental and the interface is subject to change.</b>
*/
void
Init_IO_Buffer(void)
{
rb_cIOBuffer = rb_define_class_under(rb_cIO, "Buffer", rb_cObject);
-
- /* Raised when an operation would resize or re-allocate a locked buffer. */
rb_eIOBufferLockedError = rb_define_class_under(rb_cIOBuffer, "LockedError", rb_eRuntimeError);
-
- /* Raised when the buffer cannot be allocated for some reason, or you try to use a buffer that's not allocated. */
rb_eIOBufferAllocationError = rb_define_class_under(rb_cIOBuffer, "AllocationError", rb_eRuntimeError);
-
- /* Raised when you try to write to a read-only buffer, or resize an external buffer. */
rb_eIOBufferAccessError = rb_define_class_under(rb_cIOBuffer, "AccessError", rb_eRuntimeError);
-
- /* Raised if you try to access a buffer slice which no longer references a valid memory range of the underlying source. */
rb_eIOBufferInvalidatedError = rb_define_class_under(rb_cIOBuffer, "InvalidatedError", rb_eRuntimeError);
-
- /* Raised if the mask given to a binary operation is invalid, e.g. zero length or overlaps the target buffer. */
rb_eIOBufferMaskError = rb_define_class_under(rb_cIOBuffer, "MaskError", rb_eArgError);
rb_define_alloc_func(rb_cIOBuffer, rb_io_buffer_type_allocate);
rb_define_singleton_method(rb_cIOBuffer, "for", rb_io_buffer_type_for, 1);
- rb_define_singleton_method(rb_cIOBuffer, "string", rb_io_buffer_type_string, 1);
#ifdef _WIN32
SYSTEM_INFO info;
@@ -3651,57 +3399,37 @@ Init_IO_Buffer(void)
RUBY_IO_BUFFER_DEFAULT_SIZE = io_buffer_default_size(RUBY_IO_BUFFER_PAGE_SIZE);
- /* The operating system page size. Used for efficient page-aligned memory allocations. */
+ // Efficient sizing of mapped buffers:
rb_define_const(rb_cIOBuffer, "PAGE_SIZE", SIZET2NUM(RUBY_IO_BUFFER_PAGE_SIZE));
-
- /* The default buffer size, typically a (small) multiple of the PAGE_SIZE.
- Can be explicitly specified by setting the RUBY_IO_BUFFER_DEFAULT_SIZE
- environment variable. */
rb_define_const(rb_cIOBuffer, "DEFAULT_SIZE", SIZET2NUM(RUBY_IO_BUFFER_DEFAULT_SIZE));
rb_define_singleton_method(rb_cIOBuffer, "map", io_buffer_map, -1);
+ // General use:
rb_define_method(rb_cIOBuffer, "initialize", rb_io_buffer_initialize, -1);
rb_define_method(rb_cIOBuffer, "initialize_copy", rb_io_buffer_initialize_copy, 1);
rb_define_method(rb_cIOBuffer, "inspect", rb_io_buffer_inspect, 0);
- rb_define_method(rb_cIOBuffer, "hexdump", rb_io_buffer_hexdump, -1);
+ rb_define_method(rb_cIOBuffer, "hexdump", rb_io_buffer_hexdump, 0);
rb_define_method(rb_cIOBuffer, "to_s", rb_io_buffer_to_s, 0);
rb_define_method(rb_cIOBuffer, "size", rb_io_buffer_size, 0);
rb_define_method(rb_cIOBuffer, "valid?", rb_io_buffer_valid_p, 0);
+ // Ownership:
rb_define_method(rb_cIOBuffer, "transfer", rb_io_buffer_transfer, 0);
- /* Indicates that the memory in the buffer is owned by someone else. See #external? for more details. */
+ // Flags:
rb_define_const(rb_cIOBuffer, "EXTERNAL", RB_INT2NUM(RB_IO_BUFFER_EXTERNAL));
-
- /* Indicates that the memory in the buffer is owned by the buffer. See #internal? for more details. */
rb_define_const(rb_cIOBuffer, "INTERNAL", RB_INT2NUM(RB_IO_BUFFER_INTERNAL));
-
- /* Indicates that the memory in the buffer is mapped by the operating system. See #mapped? for more details. */
rb_define_const(rb_cIOBuffer, "MAPPED", RB_INT2NUM(RB_IO_BUFFER_MAPPED));
-
- /* Indicates that the memory in the buffer is also mapped such that it can be shared with other processes. See #shared? for more details. */
rb_define_const(rb_cIOBuffer, "SHARED", RB_INT2NUM(RB_IO_BUFFER_SHARED));
-
- /* Indicates that the memory in the buffer is locked and cannot be resized or freed. See #locked? and #locked for more details. */
rb_define_const(rb_cIOBuffer, "LOCKED", RB_INT2NUM(RB_IO_BUFFER_LOCKED));
-
- /* Indicates that the memory in the buffer is mapped privately and changes won't be replicated to the underlying file. See #private? for more details. */
rb_define_const(rb_cIOBuffer, "PRIVATE", RB_INT2NUM(RB_IO_BUFFER_PRIVATE));
-
- /* Indicates that the memory in the buffer is read only, and attempts to modify it will fail. See #readonly? for more details.*/
rb_define_const(rb_cIOBuffer, "READONLY", RB_INT2NUM(RB_IO_BUFFER_READONLY));
- /* Refers to little endian byte order, where the least significant byte is stored first. See #get_value for more details. */
+ // Endian:
rb_define_const(rb_cIOBuffer, "LITTLE_ENDIAN", RB_INT2NUM(RB_IO_BUFFER_LITTLE_ENDIAN));
-
- /* Refers to big endian byte order, where the most significant byte is stored first. See #get_value for more details. */
rb_define_const(rb_cIOBuffer, "BIG_ENDIAN", RB_INT2NUM(RB_IO_BUFFER_BIG_ENDIAN));
-
- /* Refers to the byte order of the host machine. See #get_value for more details. */
rb_define_const(rb_cIOBuffer, "HOST_ENDIAN", RB_INT2NUM(RB_IO_BUFFER_HOST_ENDIAN));
-
- /* Refers to network byte order, which is the same as big endian. See #get_value for more details. */
rb_define_const(rb_cIOBuffer, "NETWORK_ENDIAN", RB_INT2NUM(RB_IO_BUFFER_NETWORK_ENDIAN));
rb_define_method(rb_cIOBuffer, "null?", rb_io_buffer_null_p, 0);
@@ -3711,7 +3439,6 @@ Init_IO_Buffer(void)
rb_define_method(rb_cIOBuffer, "mapped?", rb_io_buffer_mapped_p, 0);
rb_define_method(rb_cIOBuffer, "shared?", rb_io_buffer_shared_p, 0);
rb_define_method(rb_cIOBuffer, "locked?", rb_io_buffer_locked_p, 0);
- rb_define_method(rb_cIOBuffer, "private?", rb_io_buffer_private_p, 0);
rb_define_method(rb_cIOBuffer, "readonly?", io_buffer_readonly_p, 0);
// Locking to prevent changes while using pointer:
diff --git a/iseq.c b/iseq.c
index a60228c8e5..d17ce486c5 100644
--- a/iseq.c
+++ b/iseq.c
@@ -19,6 +19,7 @@
#endif
#include "eval_intern.h"
+#include "gc.h"
#include "id_table.h"
#include "internal.h"
#include "internal/bits.h"
@@ -26,16 +27,14 @@
#include "internal/compile.h"
#include "internal/error.h"
#include "internal/file.h"
-#include "internal/gc.h"
#include "internal/hash.h"
-#include "internal/io.h"
-#include "internal/ruby_parser.h"
+#include "internal/parse.h"
#include "internal/sanitizers.h"
#include "internal/symbol.h"
#include "internal/thread.h"
#include "internal/variable.h"
#include "iseq.h"
-#include "rjit.h"
+#include "mjit.h"
#include "ruby/util.h"
#include "vm_core.h"
#include "vm_callinfo.h"
@@ -114,7 +113,9 @@ remove_from_constant_cache(ID id, IC ic)
st_table *ics = (st_table *)lookup_result;
st_delete(ics, &ic_data, NULL);
- if (ics->num_entries == 0) {
+ if (ics->num_entries == 0 &&
+ // See comment in vm_track_constant_cache on why we need this check
+ id != vm->inserting_constant_cache_id) {
rb_id_table_delete(vm->constant_cache, id);
st_free_table(ics);
}
@@ -165,24 +166,23 @@ rb_iseq_free(const rb_iseq_t *iseq)
if (iseq && ISEQ_BODY(iseq)) {
iseq_clear_ic_references(iseq);
struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
- rb_rjit_free_iseq(iseq); /* Notify RJIT */
+ mjit_free_iseq(iseq); /* Notify MJIT */
#if USE_YJIT
- rb_yjit_iseq_free(iseq);
- if (FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED)) {
- RUBY_ASSERT(rb_yjit_live_iseq_count > 0);
- rb_yjit_live_iseq_count--;
- }
+ rb_yjit_iseq_free(body->yjit_payload);
#endif
ruby_xfree((void *)body->iseq_encoded);
ruby_xfree((void *)body->insns_info.body);
- ruby_xfree((void *)body->insns_info.positions);
+ if (body->insns_info.positions) ruby_xfree((void *)body->insns_info.positions);
#if VM_INSN_INFO_TABLE_IMPL == 2
- ruby_xfree(body->insns_info.succ_index_table);
+ if (body->insns_info.succ_index_table) ruby_xfree(body->insns_info.succ_index_table);
#endif
if (LIKELY(body->local_table != rb_iseq_shared_exc_local_tbl))
ruby_xfree((void *)body->local_table);
ruby_xfree((void *)body->is_entries);
- ruby_xfree(body->call_data);
+
+ if (body->call_data) {
+ ruby_xfree(body->call_data);
+ }
ruby_xfree((void *)body->catch_table);
ruby_xfree((void *)body->param.opt_table);
if (ISEQ_MBITS_BUFLEN(body->iseq_size) > 1 && body->mark_bits.list) {
@@ -194,9 +194,7 @@ rb_iseq_free(const rb_iseq_t *iseq)
if (body->param.keyword != NULL) {
if (body->param.keyword->table != &body->local_table[body->param.keyword->bits_start - body->param.keyword->num])
ruby_xfree((void *)body->param.keyword->table);
- if (body->param.keyword->default_values) {
- ruby_xfree((void *)body->param.keyword->default_values);
- }
+ ruby_xfree((void *)body->param.keyword->default_values);
ruby_xfree((void *)body->param.keyword);
}
compile_data_free(ISEQ_COMPILE_DATA(iseq));
@@ -214,7 +212,7 @@ rb_iseq_free(const rb_iseq_t *iseq)
typedef VALUE iseq_value_itr_t(void *ctx, VALUE obj);
static inline void
-iseq_scan_bits(unsigned int page, iseq_bits_t bits, VALUE *code, VALUE *original_iseq)
+iseq_scan_bits(unsigned int page, iseq_bits_t bits, VALUE *code, iseq_value_itr_t *func, void *data)
{
unsigned int offset;
unsigned int page_offset = (page * ISEQ_MBITS_BITLENGTH);
@@ -222,17 +220,20 @@ iseq_scan_bits(unsigned int page, iseq_bits_t bits, VALUE *code, VALUE *original
while (bits) {
offset = ntz_intptr(bits);
VALUE op = code[page_offset + offset];
- rb_gc_mark_and_move(&code[page_offset + offset]);
- VALUE newop = code[page_offset + offset];
- if (original_iseq && newop != op) {
- original_iseq[page_offset + offset] = newop;
+ VALUE newop = func(data, op);
+ if (newop != op) {
+ code[page_offset + offset] = newop;
+ if (data) {
+ VALUE *original_iseq = (VALUE *)data;
+ original_iseq[page_offset + offset] = newop;
+ }
}
bits &= bits - 1; // Reset Lowest Set Bit (BLSR)
}
}
static void
-rb_iseq_mark_and_move_each_value(const rb_iseq_t *iseq, VALUE *original_iseq)
+rb_iseq_each_value(const rb_iseq_t *iseq, iseq_value_itr_t * func, void *data)
{
unsigned int size;
VALUE *code;
@@ -253,7 +254,10 @@ rb_iseq_mark_and_move_each_value(const rb_iseq_t *iseq, VALUE *original_iseq)
if (icvarc->entry) {
RUBY_ASSERT(!RB_TYPE_P(icvarc->entry->class_value, T_NONE));
- rb_gc_mark_and_move(&icvarc->entry->class_value);
+ VALUE nv = func(data, icvarc->entry->class_value);
+ if (icvarc->entry->class_value != nv) {
+ icvarc->entry->class_value = nv;
+ }
}
}
@@ -261,7 +265,10 @@ rb_iseq_mark_and_move_each_value(const rb_iseq_t *iseq, VALUE *original_iseq)
for (unsigned int i = 0; i < body->ise_size; i++, is_entries++) {
union iseq_inline_storage_entry *const is = (union iseq_inline_storage_entry *)is_entries;
if (is->once.value) {
- rb_gc_mark_and_move(&is->once.value);
+ VALUE nv = func(data, is->once.value);
+ if (is->once.value != nv) {
+ is->once.value = nv;
+ }
}
}
@@ -269,7 +276,10 @@ rb_iseq_mark_and_move_each_value(const rb_iseq_t *iseq, VALUE *original_iseq)
for (unsigned int i = 0; i < body->ic_size; i++, is_entries++) {
IC ic = (IC)is_entries;
if (ic->entry) {
- rb_gc_mark_and_move_ptr(&ic->entry);
+ VALUE nv = func(data, (VALUE)ic->entry);
+ if ((VALUE)ic->entry != nv) {
+ ic->entry = (void *)nv;
+ }
}
}
}
@@ -277,147 +287,197 @@ rb_iseq_mark_and_move_each_value(const rb_iseq_t *iseq, VALUE *original_iseq)
// Embedded VALUEs
if (body->mark_bits.list) {
if (ISEQ_MBITS_BUFLEN(size) == 1) {
- iseq_scan_bits(0, body->mark_bits.single, code, original_iseq);
+ iseq_scan_bits(0, body->mark_bits.single, code, func, data);
}
else {
if (body->mark_bits.list) {
for (unsigned int i = 0; i < ISEQ_MBITS_BUFLEN(size); i++) {
iseq_bits_t bits = body->mark_bits.list[i];
- iseq_scan_bits(i, bits, code, original_iseq);
+ iseq_scan_bits(i, bits, code, func, data);
}
}
}
}
}
-static bool
-cc_is_active(const struct rb_callcache *cc, bool reference_updating)
+static VALUE
+update_each_insn_value(void *ctx, VALUE obj)
{
- if (cc) {
- if (cc == rb_vm_empty_cc() || rb_vm_empty_cc_for_super()) {
- return false;
- }
+ return rb_gc_location(obj);
+}
- if (reference_updating) {
- cc = (const struct rb_callcache *)rb_gc_location((VALUE)cc);
+void
+rb_iseq_update_references(rb_iseq_t *iseq)
+{
+ if (ISEQ_BODY(iseq)) {
+ struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
+
+ body->variable.coverage = rb_gc_location(body->variable.coverage);
+ body->variable.pc2branchindex = rb_gc_location(body->variable.pc2branchindex);
+ body->variable.script_lines = rb_gc_location(body->variable.script_lines);
+ body->location.label = rb_gc_location(body->location.label);
+ body->location.base_label = rb_gc_location(body->location.base_label);
+ body->location.pathobj = rb_gc_location(body->location.pathobj);
+ if (body->local_iseq) {
+ body->local_iseq = (struct rb_iseq_struct *)rb_gc_location((VALUE)body->local_iseq);
+ }
+ if (body->parent_iseq) {
+ body->parent_iseq = (struct rb_iseq_struct *)rb_gc_location((VALUE)body->parent_iseq);
+ }
+ if (body->mandatory_only_iseq) {
+ body->mandatory_only_iseq = (struct rb_iseq_struct *)rb_gc_location((VALUE)body->mandatory_only_iseq);
+ }
+ if (body->call_data) {
+ for (unsigned int i=0; i<body->ci_size; i++) {
+ struct rb_call_data *cds = body->call_data;
+ if (!SPECIAL_CONST_P((VALUE)cds[i].ci)) {
+ cds[i].ci = (struct rb_callinfo *)rb_gc_location((VALUE)cds[i].ci);
+ }
+ cds[i].cc = (struct rb_callcache *)rb_gc_location((VALUE)cds[i].cc);
+ }
}
+ VALUE *original_iseq = ISEQ_ORIGINAL_ISEQ(iseq);
+ rb_iseq_each_value(iseq, update_each_insn_value, (void *)original_iseq);
- if (vm_cc_markable(cc)) {
- if (cc->klass) { // cc is not invalidated
- const struct rb_callable_method_entry_struct *cme = vm_cc_cme(cc);
- if (reference_updating) {
- cme = (const struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)cme);
+ if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
+ int i, j;
+
+ i = body->param.keyword->required_num;
+
+ for (j = 0; i < body->param.keyword->num; i++, j++) {
+ VALUE obj = body->param.keyword->default_values[j];
+ if (!UNDEF_P(obj)) {
+ body->param.keyword->default_values[j] = rb_gc_location(obj);
}
- if (!METHOD_ENTRY_INVALIDATED(cme)) {
- return true;
+ }
+ }
+
+ if (body->catch_table) {
+ struct iseq_catch_table *table = body->catch_table;
+ unsigned int i;
+ for (i = 0; i < table->size; i++) {
+ struct iseq_catch_table_entry *entry;
+ entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
+ if (entry->iseq) {
+ entry->iseq = (rb_iseq_t *)rb_gc_location((VALUE)entry->iseq);
}
}
}
+#if USE_MJIT
+ mjit_update_references(iseq);
+#endif
+#if USE_YJIT
+ rb_yjit_iseq_update_references(body->yjit_payload);
+#endif
}
- return false;
+}
+
+static VALUE
+each_insn_value(void *ctx, VALUE obj)
+{
+ rb_gc_mark_movable(obj);
+ return obj;
}
void
-rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating)
+rb_iseq_mark(const rb_iseq_t *iseq)
{
RUBY_MARK_ENTER("iseq");
- rb_gc_mark_and_move(&iseq->wrapper);
+ RUBY_MARK_UNLESS_NULL(iseq->wrapper);
if (ISEQ_BODY(iseq)) {
- struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
+ const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
- rb_iseq_mark_and_move_each_value(iseq, reference_updating ? ISEQ_ORIGINAL_ISEQ(iseq) : NULL);
+ rb_iseq_each_value(iseq, each_insn_value, NULL);
- rb_gc_mark_and_move(&body->variable.coverage);
- rb_gc_mark_and_move(&body->variable.pc2branchindex);
- rb_gc_mark_and_move(&body->variable.script_lines);
- rb_gc_mark_and_move(&body->location.label);
- rb_gc_mark_and_move(&body->location.base_label);
- rb_gc_mark_and_move(&body->location.pathobj);
- if (body->local_iseq) rb_gc_mark_and_move_ptr(&body->local_iseq);
- if (body->parent_iseq) rb_gc_mark_and_move_ptr(&body->parent_iseq);
- if (body->mandatory_only_iseq) rb_gc_mark_and_move_ptr(&body->mandatory_only_iseq);
+ rb_gc_mark_movable(body->variable.coverage);
+ rb_gc_mark_movable(body->variable.pc2branchindex);
+ rb_gc_mark_movable(body->variable.script_lines);
+ rb_gc_mark_movable(body->location.label);
+ rb_gc_mark_movable(body->location.base_label);
+ rb_gc_mark_movable(body->location.pathobj);
+ RUBY_MARK_MOVABLE_UNLESS_NULL((VALUE)body->mandatory_only_iseq);
+ RUBY_MARK_MOVABLE_UNLESS_NULL((VALUE)body->parent_iseq);
if (body->call_data) {
- for (unsigned int i = 0; i < body->ci_size; i++) {
- struct rb_call_data *cds = body->call_data;
-
- if (cds[i].ci) rb_gc_mark_and_move_ptr(&cds[i].ci);
+ struct rb_call_data *cds = (struct rb_call_data *)body->call_data;
+ for (unsigned int i=0; i<body->ci_size; i++) {
+ const struct rb_callinfo *ci = cds[i].ci;
+ const struct rb_callcache *cc = cds[i].cc;
- if (cc_is_active(cds[i].cc, reference_updating)) {
- rb_gc_mark_and_move_ptr(&cds[i].cc);
+ if (vm_ci_markable(ci)) {
+ rb_gc_mark_movable((VALUE)ci);
}
- else if (cds[i].cc != rb_vm_empty_cc()) {
- cds[i].cc = rb_vm_empty_cc();
+
+ if (cc) {
+ VM_ASSERT((cc->flags & VM_CALLCACHE_ON_STACK) == 0);
+
+ if (vm_cc_markable(cc)) {
+ if (!vm_cc_invalidated_p(cc)) {
+ rb_gc_mark_movable((VALUE)cc);
+ }
+ else {
+ cds[i].cc = rb_vm_empty_cc();
+ }
+ }
}
}
}
- if (body->param.flags.has_kw && body->param.keyword != NULL) {
+ if (body->param.flags.has_kw && ISEQ_COMPILE_DATA(iseq) == NULL) {
const struct rb_iseq_param_keyword *const keyword = body->param.keyword;
+ int i, j;
+
+ i = keyword->required_num;
- if (keyword->default_values != NULL) {
- for (int j = 0, i = keyword->required_num; i < keyword->num; i++, j++) {
- rb_gc_mark_and_move(&keyword->default_values[j]);
+ for (j = 0; i < keyword->num; i++, j++) {
+ VALUE obj = keyword->default_values[j];
+ if (!SPECIAL_CONST_P(obj)) {
+ rb_gc_mark_movable(obj);
}
}
}
if (body->catch_table) {
- struct iseq_catch_table *table = body->catch_table;
-
- for (unsigned int i = 0; i < table->size; i++) {
- struct iseq_catch_table_entry *entry;
+ const struct iseq_catch_table *table = body->catch_table;
+ unsigned int i;
+ for (i = 0; i < table->size; i++) {
+ const struct iseq_catch_table_entry *entry;
entry = UNALIGNED_MEMBER_PTR(table, entries[i]);
if (entry->iseq) {
- rb_gc_mark_and_move_ptr(&entry->iseq);
+ rb_gc_mark_movable((VALUE)entry->iseq);
}
}
}
- if (reference_updating) {
-#if USE_RJIT
- rb_rjit_iseq_update_references(body);
-#endif
-#if USE_YJIT
- rb_yjit_iseq_update_references(iseq);
-#endif
- }
- else {
-#if USE_RJIT
- rb_rjit_iseq_mark(body->rjit_blocks);
+#if USE_MJIT
+ mjit_mark_cc_entries(body);
#endif
#if USE_YJIT
- rb_yjit_iseq_mark(body->yjit_payload);
+ rb_yjit_iseq_mark(body->yjit_payload);
#endif
- }
}
if (FL_TEST_RAW((VALUE)iseq, ISEQ_NOT_LOADED_YET)) {
- rb_gc_mark_and_move(&iseq->aux.loader.obj);
+ rb_gc_mark(iseq->aux.loader.obj);
}
else if (FL_TEST_RAW((VALUE)iseq, ISEQ_USE_COMPILE_DATA)) {
const struct iseq_compile_data *const compile_data = ISEQ_COMPILE_DATA(iseq);
- if (!reference_updating) {
- /* The operands in each instruction needs to be pinned because
- * if auto-compaction runs in iseq_set_sequence, then the objects
- * could exist on the generated_iseq buffer, which would not be
- * reference updated which can lead to T_MOVED (and subsequently
- * T_NONE) objects on the iseq. */
- rb_iseq_mark_and_pin_insn_storage(compile_data->insn.storage_head);
- }
+ rb_iseq_mark_insn_storage(compile_data->insn.storage_head);
- rb_gc_mark_and_move((VALUE *)&compile_data->err_info);
- rb_gc_mark_and_move((VALUE *)&compile_data->catch_table_ary);
+ RUBY_MARK_UNLESS_NULL(compile_data->err_info);
+ if (RTEST(compile_data->catch_table_ary)) {
+ rb_gc_mark(compile_data->catch_table_ary);
+ }
+ VM_ASSERT(compile_data != NULL);
}
else {
/* executable */
VM_ASSERT(ISEQ_EXECUTABLE_P(iseq));
-
if (iseq->aux.exec.local_hooks) {
- rb_hook_list_mark_and_update(iseq->aux.exec.local_hooks);
+ rb_hook_list_mark(iseq->aux.exec.local_hooks);
}
}
@@ -525,7 +585,7 @@ rb_iseq_pathobj_new(VALUE path, VALUE realpath)
else {
if (!NIL_P(realpath)) realpath = rb_fstring(realpath);
pathobj = rb_ary_new_from_args(2, rb_fstring(path), realpath);
- rb_ary_freeze(pathobj);
+ rb_obj_freeze(pathobj);
}
return pathobj;
}
@@ -537,6 +597,19 @@ rb_iseq_pathobj_set(const rb_iseq_t *iseq, VALUE path, VALUE realpath)
rb_iseq_pathobj_new(path, realpath));
}
+// Make a dummy iseq for a dummy frame that exposes a path for profilers to inspect
+rb_iseq_t *
+rb_iseq_alloc_with_dummy_path(VALUE fname)
+{
+ rb_iseq_t *dummy_iseq = iseq_alloc();
+
+ ISEQ_BODY(dummy_iseq)->type = ISEQ_TYPE_TOP;
+ RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.pathobj, fname);
+ RB_OBJ_WRITE(dummy_iseq, &ISEQ_BODY(dummy_iseq)->location.label, fname);
+
+ return dummy_iseq;
+}
+
static rb_iseq_location_t *
iseq_location_setup(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_code_location_t *code_location, const int node_id)
{
@@ -546,11 +619,6 @@ iseq_location_setup(rb_iseq_t *iseq, VALUE name, VALUE path, VALUE realpath, int
RB_OBJ_WRITE(iseq, &loc->label, name);
RB_OBJ_WRITE(iseq, &loc->base_label, name);
loc->first_lineno = first_lineno;
-
- if (ISEQ_BODY(iseq)->local_iseq == iseq && strcmp(RSTRING_PTR(name), "initialize") == 0) {
- ISEQ_BODY(iseq)->param.flags.use_block = 1;
- }
-
if (code_location) {
loc->node_id = node_id;
loc->code_location = *code_location;
@@ -733,26 +801,19 @@ finish_iseq_build(rb_iseq_t *iseq)
}
static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
- .inline_const_cache = OPT_INLINE_CONST_CACHE,
- .peephole_optimization = OPT_PEEPHOLE_OPTIMIZATION,
- .tailcall_optimization = OPT_TAILCALL_OPTIMIZATION,
- .specialized_instruction = OPT_SPECIALISED_INSTRUCTION,
- .operands_unification = OPT_OPERANDS_UNIFICATION,
- .instructions_unification = OPT_INSTRUCTIONS_UNIFICATION,
- .frozen_string_literal = OPT_FROZEN_STRING_LITERAL,
- .debug_frozen_string_literal = OPT_DEBUG_FROZEN_STRING_LITERAL,
- .coverage_enabled = TRUE,
+ OPT_INLINE_CONST_CACHE, /* int inline_const_cache; */
+ OPT_PEEPHOLE_OPTIMIZATION, /* int peephole_optimization; */
+ OPT_TAILCALL_OPTIMIZATION, /* int tailcall_optimization */
+ OPT_SPECIALISED_INSTRUCTION, /* int specialized_instruction; */
+ OPT_OPERANDS_UNIFICATION, /* int operands_unification; */
+ OPT_INSTRUCTIONS_UNIFICATION, /* int instructions_unification; */
+ OPT_STACK_CACHING, /* int stack_caching; */
+ OPT_FROZEN_STRING_LITERAL,
+ OPT_DEBUG_FROZEN_STRING_LITERAL,
+ TRUE, /* coverage_enabled */
};
-static const rb_compile_option_t COMPILE_OPTION_FALSE = {
- .frozen_string_literal = -1, // unspecified
-};
-
-int
-rb_iseq_opt_frozen_string_literal(void)
-{
- return COMPILE_OPTION_DEFAULT.frozen_string_literal;
-}
+static const rb_compile_option_t COMPILE_OPTION_FALSE = {0};
static void
set_compile_option_from_hash(rb_compile_option_t *option, VALUE opt)
@@ -763,7 +824,7 @@ set_compile_option_from_hash(rb_compile_option_t *option, VALUE opt)
else if (flag == Qfalse) { (o)->mem = 0; } \
}
#define SET_COMPILE_OPTION_NUM(o, h, mem) \
- { VALUE num = rb_hash_aref((h), ID2SYM(rb_intern(#mem))); \
+ { VALUE num = rb_hash_aref(opt, ID2SYM(rb_intern(#mem))); \
if (!NIL_P(num)) (o)->mem = NUM2INT(num); \
}
SET_COMPILE_OPTION(option, opt, inline_const_cache);
@@ -772,6 +833,7 @@ set_compile_option_from_hash(rb_compile_option_t *option, VALUE opt)
SET_COMPILE_OPTION(option, opt, specialized_instruction);
SET_COMPILE_OPTION(option, opt, operands_unification);
SET_COMPILE_OPTION(option, opt, instructions_unification);
+ SET_COMPILE_OPTION(option, opt, stack_caching);
SET_COMPILE_OPTION(option, opt, frozen_string_literal);
SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
SET_COMPILE_OPTION(option, opt, coverage_enabled);
@@ -780,17 +842,11 @@ set_compile_option_from_hash(rb_compile_option_t *option, VALUE opt)
#undef SET_COMPILE_OPTION_NUM
}
-static rb_compile_option_t *
-set_compile_option_from_ast(rb_compile_option_t *option, const rb_ast_body_t *ast)
+static void
+rb_iseq_make_compile_option(rb_compile_option_t *option, VALUE opt)
{
-#define SET_COMPILE_OPTION(o, a, mem) \
- ((a)->mem < 0 ? 0 : ((o)->mem = (a)->mem > 0))
- SET_COMPILE_OPTION(option, ast, coverage_enabled);
-#undef SET_COMPILE_OPTION
- if (ast->frozen_string_literal >= 0) {
- option->frozen_string_literal = ast->frozen_string_literal;
- }
- return option;
+ Check_Type(opt, T_HASH);
+ set_compile_option_from_hash(option, opt);
}
static void
@@ -831,36 +887,43 @@ make_compile_option_value(rb_compile_option_t *option)
SET_COMPILE_OPTION(option, opt, specialized_instruction);
SET_COMPILE_OPTION(option, opt, operands_unification);
SET_COMPILE_OPTION(option, opt, instructions_unification);
+ SET_COMPILE_OPTION(option, opt, stack_caching);
+ SET_COMPILE_OPTION(option, opt, frozen_string_literal);
SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
SET_COMPILE_OPTION(option, opt, coverage_enabled);
SET_COMPILE_OPTION_NUM(option, opt, debug_level);
}
#undef SET_COMPILE_OPTION
#undef SET_COMPILE_OPTION_NUM
- VALUE frozen_string_literal = option->frozen_string_literal == -1 ? Qnil : RBOOL(option->frozen_string_literal);
- rb_hash_aset(opt, ID2SYM(rb_intern("frozen_string_literal")), frozen_string_literal);
return opt;
}
rb_iseq_t *
-rb_iseq_new(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath,
+rb_iseq_new(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath,
const rb_iseq_t *parent, enum rb_iseq_type type)
{
- return rb_iseq_new_with_opt(ast_value, name, path, realpath, 0, parent,
- 0, type, &COMPILE_OPTION_DEFAULT,
- Qnil);
+ return rb_iseq_new_with_opt(ast, name, path, realpath, 0, parent,
+ 0, type, &COMPILE_OPTION_DEFAULT);
}
static int
-ast_line_count(const VALUE ast_value)
+ast_line_count(const rb_ast_body_t *ast)
{
- rb_ast_t *ast = rb_ruby_ast_data_get(ast_value);
- return ast->body.line_count;
+ if (ast->script_lines == Qfalse) {
+ // this occurs when failed to parse the source code with a syntax error
+ return 0;
+ }
+ if (RB_TYPE_P(ast->script_lines, T_ARRAY)){
+ return (int)RARRAY_LEN(ast->script_lines);
+ }
+ return FIX2INT(ast->script_lines);
}
static VALUE
-iseq_setup_coverage(VALUE coverages, VALUE path, int line_count)
+iseq_setup_coverage(VALUE coverages, VALUE path, const rb_ast_body_t *ast, int line_offset)
{
+ int line_count = line_offset + ast_line_count(ast);
+
if (line_count >= 0) {
int len = (rb_get_coverage_mode() & COVERAGE_TARGET_ONESHOT_LINES) ? 0 : line_count;
@@ -874,89 +937,45 @@ iseq_setup_coverage(VALUE coverages, VALUE path, int line_count)
}
static inline void
-iseq_new_setup_coverage(VALUE path, int line_count)
+iseq_new_setup_coverage(VALUE path, const rb_ast_body_t *ast, int line_offset)
{
VALUE coverages = rb_get_coverages();
if (RTEST(coverages)) {
- iseq_setup_coverage(coverages, path, line_count);
+ iseq_setup_coverage(coverages, path, ast, 0);
}
}
rb_iseq_t *
-rb_iseq_new_top(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent)
+rb_iseq_new_top(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent)
{
- iseq_new_setup_coverage(path, ast_line_count(ast_value));
+ iseq_new_setup_coverage(path, ast, 0);
- return rb_iseq_new_with_opt(ast_value, name, path, realpath, 0, parent, 0,
- ISEQ_TYPE_TOP, &COMPILE_OPTION_DEFAULT,
- Qnil);
-}
-
-/**
- * The main entry-point into the prism compiler when a file is required.
- */
-rb_iseq_t *
-pm_iseq_new_top(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent)
-{
- iseq_new_setup_coverage(path, (int) (node->parser->newline_list.size - 1));
-
- return pm_iseq_new_with_opt(node, name, path, realpath, 0, parent, 0,
+ return rb_iseq_new_with_opt(ast, name, path, realpath, 0, parent, 0,
ISEQ_TYPE_TOP, &COMPILE_OPTION_DEFAULT);
}
rb_iseq_t *
-rb_iseq_new_main(const VALUE ast_value, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt)
-{
- iseq_new_setup_coverage(path, ast_line_count(ast_value));
-
- return rb_iseq_new_with_opt(ast_value, rb_fstring_lit("<main>"),
- path, realpath, 0,
- parent, 0, ISEQ_TYPE_MAIN, opt ? &COMPILE_OPTION_DEFAULT : &COMPILE_OPTION_FALSE,
- Qnil);
-}
-
-/**
- * The main entry-point into the prism compiler when a file is executed as the
- * main file in the program.
- */
-rb_iseq_t *
-pm_iseq_new_main(pm_scope_node_t *node, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt)
+rb_iseq_new_main(const rb_ast_body_t *ast, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt)
{
- iseq_new_setup_coverage(path, (int) (node->parser->newline_list.size - 1));
+ iseq_new_setup_coverage(path, ast, 0);
- return pm_iseq_new_with_opt(node, rb_fstring_lit("<main>"),
+ return rb_iseq_new_with_opt(ast, rb_fstring_lit("<main>"),
path, realpath, 0,
parent, 0, ISEQ_TYPE_MAIN, opt ? &COMPILE_OPTION_DEFAULT : &COMPILE_OPTION_FALSE);
}
rb_iseq_t *
-rb_iseq_new_eval(const VALUE ast_value, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth)
-{
- if (rb_get_coverage_mode() & COVERAGE_TARGET_EVAL) {
- VALUE coverages = rb_get_coverages();
- if (RTEST(coverages) && RTEST(path) && !RTEST(rb_hash_has_key(coverages, path))) {
- iseq_setup_coverage(coverages, path, ast_line_count(ast_value) + first_lineno - 1);
- }
- }
-
- return rb_iseq_new_with_opt(ast_value, name, path, realpath, first_lineno,
- parent, isolated_depth, ISEQ_TYPE_EVAL, &COMPILE_OPTION_DEFAULT,
- Qnil);
-}
-
-rb_iseq_t *
-pm_iseq_new_eval(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath,
- int first_lineno, const rb_iseq_t *parent, int isolated_depth)
+rb_iseq_new_eval(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth)
{
if (rb_get_coverage_mode() & COVERAGE_TARGET_EVAL) {
VALUE coverages = rb_get_coverages();
if (RTEST(coverages) && RTEST(path) && !RTEST(rb_hash_has_key(coverages, path))) {
- iseq_setup_coverage(coverages, path, ((int) (node->parser->newline_list.size - 1)) + first_lineno - 1);
+ iseq_setup_coverage(coverages, path, ast, first_lineno - 1);
}
}
- return pm_iseq_new_with_opt(node, name, path, realpath, first_lineno,
+ return rb_iseq_new_with_opt(ast, name, path, realpath, first_lineno,
parent, isolated_depth, ISEQ_TYPE_EVAL, &COMPILE_OPTION_DEFAULT);
}
@@ -975,87 +994,37 @@ iseq_translate(rb_iseq_t *iseq)
}
rb_iseq_t *
-rb_iseq_new_with_opt(VALUE ast_value, VALUE name, VALUE path, VALUE realpath,
+rb_iseq_new_with_opt(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath,
int first_lineno, const rb_iseq_t *parent, int isolated_depth,
- enum rb_iseq_type type, const rb_compile_option_t *option,
- VALUE script_lines)
+ enum rb_iseq_type type, const rb_compile_option_t *option)
{
- rb_ast_t *ast = rb_ruby_ast_data_get(ast_value);
- rb_ast_body_t *body = ast ? &ast->body : NULL;
- const NODE *node = body ? body->root : 0;
+ const NODE *node = ast ? ast->root : 0;
/* TODO: argument check */
rb_iseq_t *iseq = iseq_alloc();
rb_compile_option_t new_opt;
- if (!option) option = &COMPILE_OPTION_DEFAULT;
- if (body) {
+ if (option) {
new_opt = *option;
- option = set_compile_option_from_ast(&new_opt, body);
}
-
- if (!NIL_P(script_lines)) {
- // noop
+ else {
+ new_opt = COMPILE_OPTION_DEFAULT;
}
- else if (body && body->script_lines) {
- script_lines = rb_parser_build_script_lines_from(body->script_lines);
+ if (ast && ast->compile_option) rb_iseq_make_compile_option(&new_opt, ast->compile_option);
+
+ VALUE script_lines = Qnil;
+
+ if (ast && !FIXNUM_P(ast->script_lines) && ast->script_lines) {
+ script_lines = ast->script_lines;
}
else if (parent) {
script_lines = ISEQ_BODY(parent)->variable.script_lines;
}
prepare_iseq_build(iseq, name, path, realpath, first_lineno, node ? &node->nd_loc : NULL, node ? nd_node_id(node) : -1,
- parent, isolated_depth, type, script_lines, option);
+ parent, isolated_depth, type, script_lines, &new_opt);
rb_iseq_compile_node(iseq, node);
finish_iseq_build(iseq);
- RB_GC_GUARD(ast_value);
-
- return iseq_translate(iseq);
-}
-
-/**
- * This is a step in the prism compiler that is called once all of the various
- * options have been established. It is called from one of the pm_iseq_new_*
- * functions or from the RubyVM::InstructionSequence APIs. It is responsible for
- * allocating the instruction sequence, calling into the compiler, and returning
- * the built instruction sequence.
- *
- * Importantly, this is also the function where the compiler is re-entered to
- * compile child instruction sequences. A child instruction sequence is always
- * compiled using a scope node, which is why we cast it explicitly to that here
- * in the parameters (as opposed to accepting a generic pm_node_t *).
- */
-rb_iseq_t *
-pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath,
- int first_lineno, const rb_iseq_t *parent, int isolated_depth,
- enum rb_iseq_type type, const rb_compile_option_t *option)
-{
- rb_iseq_t *iseq = iseq_alloc();
- ISEQ_BODY(iseq)->prism = true;
-
- rb_compile_option_t next_option;
- if (!option) option = &COMPILE_OPTION_DEFAULT;
-
- next_option = *option;
- next_option.coverage_enabled = node->coverage_enabled < 0 ? 0 : node->coverage_enabled > 0;
- option = &next_option;
-
- pm_location_t *location = &node->base.location;
- int32_t start_line = node->parser->start_line;
-
- pm_line_column_t start = pm_newline_list_line_column(&node->parser->newline_list, location->start, start_line);
- pm_line_column_t end = pm_newline_list_line_column(&node->parser->newline_list, location->end, start_line);
-
- rb_code_location_t code_location = (rb_code_location_t) {
- .beg_pos = { .lineno = (int) start.line, .column = (int) start.column },
- .end_pos = { .lineno = (int) end.line, .column = (int) end.column }
- };
-
- prepare_iseq_build(iseq, name, path, realpath, first_lineno, &code_location, -1,
- parent, isolated_depth, type, node->script_lines == NULL ? Qnil : *node->script_lines, option);
-
- pm_iseq_compile_node(iseq, node);
- finish_iseq_build(iseq);
return iseq_translate(iseq);
}
@@ -1181,10 +1150,6 @@ iseq_load(VALUE data, const rb_iseq_t *parent, VALUE opt)
tmp_loc.end_pos.column = NUM2INT(rb_ary_entry(code_location, 3));
}
- if (SYM2ID(rb_hash_aref(misc, ID2SYM(rb_intern("parser")))) == rb_intern("prism")) {
- ISEQ_BODY(iseq)->prism = true;
- }
-
make_compile_option(&option, opt);
option.peephole_optimization = FALSE; /* because peephole optimization can modify original iseq */
prepare_iseq_build(iseq, name, path, realpath, first_lineno, &tmp_loc, NUM2INT(node_id),
@@ -1224,10 +1189,9 @@ rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
#else
# define INITIALIZED /* volatile */
#endif
- VALUE (*parse)(VALUE vparser, VALUE fname, VALUE file, int start);
+ rb_ast_t *(*parse)(VALUE vparser, VALUE fname, VALUE file, int start);
int ln;
- VALUE INITIALIZED ast_value;
- rb_ast_t *ast;
+ rb_ast_t *INITIALIZED ast;
VALUE name = rb_fstring_lit("<compiled>");
/* safe results first */
@@ -1243,87 +1207,26 @@ rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, V
}
{
const VALUE parser = rb_parser_new();
- const rb_iseq_t *outer_scope = rb_iseq_new(Qnil, name, name, Qnil, 0, ISEQ_TYPE_TOP);
+ const rb_iseq_t *outer_scope = rb_iseq_new(NULL, name, name, Qnil, 0, ISEQ_TYPE_TOP);
VALUE outer_scope_v = (VALUE)outer_scope;
rb_parser_set_context(parser, outer_scope, FALSE);
- if (ruby_vm_keep_script_lines) rb_parser_set_script_lines(parser);
RB_GC_GUARD(outer_scope_v);
- ast_value = (*parse)(parser, file, src, ln);
+ ast = (*parse)(parser, file, src, ln);
}
- ast = rb_ruby_ast_data_get(ast_value);
-
- if (!ast || !ast->body.root) {
+ if (!ast->body.root) {
rb_ast_dispose(ast);
rb_exc_raise(GET_EC()->errinfo);
}
else {
- iseq = rb_iseq_new_with_opt(ast_value, name, file, realpath, ln,
- NULL, 0, ISEQ_TYPE_TOP, &option,
- Qnil);
+ iseq = rb_iseq_new_with_opt(&ast->body, name, file, realpath, ln,
+ NULL, 0, ISEQ_TYPE_TOP, &option);
rb_ast_dispose(ast);
}
return iseq;
}
-static rb_iseq_t *
-pm_iseq_compile_with_option(VALUE src, VALUE file, VALUE realpath, VALUE line, VALUE opt)
-{
- rb_iseq_t *iseq = NULL;
- rb_compile_option_t option;
- int ln;
- VALUE name = rb_fstring_lit("<compiled>");
-
- /* safe results first */
- make_compile_option(&option, opt);
- ln = NUM2INT(line);
- StringValueCStr(file);
-
- pm_parse_result_t result = { 0 };
- pm_options_line_set(&result.options, NUM2INT(line));
- pm_options_scopes_init(&result.options, 1);
- result.node.coverage_enabled = 1;
-
- switch (option.frozen_string_literal) {
- case ISEQ_FROZEN_STRING_LITERAL_UNSET:
- break;
- case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
- pm_options_frozen_string_literal_set(&result.options, false);
- break;
- case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
- pm_options_frozen_string_literal_set(&result.options, true);
- break;
- default:
- rb_bug("pm_iseq_compile_with_option: invalid frozen_string_literal=%d", option.frozen_string_literal);
- break;
- }
-
- VALUE script_lines;
- VALUE error;
-
- if (RB_TYPE_P(src, T_FILE)) {
- VALUE filepath = rb_io_path(src);
- error = pm_load_parse_file(&result, filepath, ruby_vm_keep_script_lines ? &script_lines : NULL);
- RB_GC_GUARD(filepath);
- }
- else {
- src = StringValue(src);
- error = pm_parse_string(&result, src, file, ruby_vm_keep_script_lines ? &script_lines : NULL);
- }
-
- if (error == Qnil) {
- iseq = pm_iseq_new_with_opt(&result.node, name, file, realpath, ln, NULL, 0, ISEQ_TYPE_TOP, &option);
- pm_parse_result_free(&result);
- }
- else {
- pm_parse_result_free(&result);
- rb_exc_raise(error);
- }
-
- return iseq;
-}
-
VALUE
rb_iseq_path(const rb_iseq_t *iseq)
{
@@ -1432,30 +1335,18 @@ rb_iseq_remove_coverage_all(void)
static void
iseqw_mark(void *ptr)
{
- rb_gc_mark_movable(*(VALUE *)ptr);
+ rb_gc_mark((VALUE)ptr);
}
static size_t
iseqw_memsize(const void *ptr)
{
- return rb_iseq_memsize(*(const rb_iseq_t **)ptr);
-}
-
-static void
-iseqw_ref_update(void *ptr)
-{
- VALUE *vptr = ptr;
- *vptr = rb_gc_location(*vptr);
+ return rb_iseq_memsize((const rb_iseq_t *)ptr);
}
static const rb_data_type_t iseqw_data_type = {
"T_IMEMO/iseq",
- {
- iseqw_mark,
- RUBY_TYPED_DEFAULT_FREE,
- iseqw_memsize,
- iseqw_ref_update,
- },
+ {iseqw_mark, NULL, iseqw_memsize,},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
};
@@ -1463,16 +1354,14 @@ static VALUE
iseqw_new(const rb_iseq_t *iseq)
{
if (iseq->wrapper) {
- if (*(const rb_iseq_t **)rb_check_typeddata(iseq->wrapper, &iseqw_data_type) != iseq) {
- rb_raise(rb_eTypeError, "wrong iseq wrapper: %" PRIsVALUE " for %p",
- iseq->wrapper, (void *)iseq);
- }
return iseq->wrapper;
}
else {
- rb_iseq_t **ptr;
- VALUE obj = TypedData_Make_Struct(rb_cISeq, rb_iseq_t *, &iseqw_data_type, ptr);
- RB_OBJ_WRITE(obj, ptr, iseq);
+ union { const rb_iseq_t *in; void *out; } deconst;
+ VALUE obj;
+ deconst.in = iseq;
+ obj = TypedData_Wrap_Struct(rb_cISeq, &iseqw_data_type, deconst.out);
+ RB_OBJ_WRITTEN(obj, Qundef, iseq);
/* cache a wrapper object */
RB_OBJ_WRITE((VALUE)iseq, &iseq->wrapper, obj);
@@ -1488,51 +1377,13 @@ rb_iseqw_new(const rb_iseq_t *iseq)
return iseqw_new(iseq);
}
-/**
- * Accept the options given to InstructionSequence.compile and
- * InstructionSequence.compile_prism and share the logic for creating the
- * instruction sequence.
- */
-static VALUE
-iseqw_s_compile_parser(int argc, VALUE *argv, VALUE self, bool prism)
-{
- VALUE src, file = Qnil, path = Qnil, line = Qnil, opt = Qnil;
- int i;
-
- i = rb_scan_args(argc, argv, "1*:", &src, NULL, &opt);
- if (i > 4+NIL_P(opt)) rb_error_arity(argc, 1, 5);
- switch (i) {
- case 5: opt = argv[--i];
- case 4: line = argv[--i];
- case 3: path = argv[--i];
- case 2: file = argv[--i];
- }
-
- if (NIL_P(file)) file = rb_fstring_lit("<compiled>");
- if (NIL_P(path)) path = file;
- if (NIL_P(line)) line = INT2FIX(1);
-
- Check_Type(path, T_STRING);
- Check_Type(file, T_STRING);
-
- rb_iseq_t *iseq;
- if (prism) {
- iseq = pm_iseq_compile_with_option(src, file, path, line, opt);
- }
- else {
- iseq = rb_iseq_compile_with_option(src, file, path, line, opt);
- }
-
- return iseqw_new(iseq);
-}
-
/*
* call-seq:
* InstructionSequence.compile(source[, file[, path[, line[, options]]]]) -> iseq
* InstructionSequence.new(source[, file[, path[, line[, options]]]]) -> iseq
*
- * Takes +source+, which can be a string of Ruby code, or an open +File+ object.
- * that contains Ruby source code.
+ * Takes +source+, a String of Ruby code and compiles it to an
+ * InstructionSequence.
*
* Optionally takes +file+, +path+, and +line+ which describe the file path,
* real path and first line number of the ruby code in +source+ which are
@@ -1554,10 +1405,6 @@ iseqw_s_compile_parser(int argc, VALUE *argv, VALUE self, bool prism)
* RubyVM::InstructionSequence.compile(File.read(path), path, File.expand_path(path))
* #=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
*
- * file = File.open("test.rb")
- * RubyVM::InstructionSequence.compile(file)
- * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>
- *
* path = File.expand_path("test.rb")
* RubyVM::InstructionSequence.compile(File.read(path), path, path)
* #=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
@@ -1566,91 +1413,26 @@ iseqw_s_compile_parser(int argc, VALUE *argv, VALUE self, bool prism)
static VALUE
iseqw_s_compile(int argc, VALUE *argv, VALUE self)
{
- return iseqw_s_compile_parser(argc, argv, self, rb_ruby_prism_p());
-}
+ VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
+ int i;
-/*
- * call-seq:
- * InstructionSequence.compile_parsey(source[, file[, path[, line[, options]]]]) -> iseq
- *
- * Takes +source+, which can be a string of Ruby code, or an open +File+ object.
- * that contains Ruby source code. It parses and compiles using parse.y.
- *
- * Optionally takes +file+, +path+, and +line+ which describe the file path,
- * real path and first line number of the ruby code in +source+ which are
- * metadata attached to the returned +iseq+.
- *
- * +file+ is used for `__FILE__` and exception backtrace. +path+ is used for
- * +require_relative+ base. It is recommended these should be the same full
- * path.
- *
- * +options+, which can be +true+, +false+ or a +Hash+, is used to
- * modify the default behavior of the Ruby iseq compiler.
- *
- * For details regarding valid compile options see ::compile_option=.
- *
- * RubyVM::InstructionSequence.compile_parsey("a = 1 + 2")
- * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
- *
- * path = "test.rb"
- * RubyVM::InstructionSequence.compile_parsey(File.read(path), path, File.expand_path(path))
- * #=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
- *
- * file = File.open("test.rb")
- * RubyVM::InstructionSequence.compile_parsey(file)
- * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>
- *
- * path = File.expand_path("test.rb")
- * RubyVM::InstructionSequence.compile_parsey(File.read(path), path, path)
- * #=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
- *
- */
-static VALUE
-iseqw_s_compile_parsey(int argc, VALUE *argv, VALUE self)
-{
- return iseqw_s_compile_parser(argc, argv, self, false);
-}
+ i = rb_scan_args(argc, argv, "1*:", &src, NULL, &opt);
+ if (i > 4+NIL_P(opt)) rb_error_arity(argc, 1, 5);
+ switch (i) {
+ case 5: opt = argv[--i];
+ case 4: line = argv[--i];
+ case 3: path = argv[--i];
+ case 2: file = argv[--i];
+ }
-/*
- * call-seq:
- * InstructionSequence.compile_prism(source[, file[, path[, line[, options]]]]) -> iseq
- *
- * Takes +source+, which can be a string of Ruby code, or an open +File+ object.
- * that contains Ruby source code. It parses and compiles using prism.
- *
- * Optionally takes +file+, +path+, and +line+ which describe the file path,
- * real path and first line number of the ruby code in +source+ which are
- * metadata attached to the returned +iseq+.
- *
- * +file+ is used for `__FILE__` and exception backtrace. +path+ is used for
- * +require_relative+ base. It is recommended these should be the same full
- * path.
- *
- * +options+, which can be +true+, +false+ or a +Hash+, is used to
- * modify the default behavior of the Ruby iseq compiler.
- *
- * For details regarding valid compile options see ::compile_option=.
- *
- * RubyVM::InstructionSequence.compile_prism("a = 1 + 2")
- * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>>
- *
- * path = "test.rb"
- * RubyVM::InstructionSequence.compile_prism(File.read(path), path, File.expand_path(path))
- * #=> <RubyVM::InstructionSequence:<compiled>@test.rb:1>
- *
- * file = File.open("test.rb")
- * RubyVM::InstructionSequence.compile_prism(file)
- * #=> <RubyVM::InstructionSequence:<compiled>@<compiled>:1>
- *
- * path = File.expand_path("test.rb")
- * RubyVM::InstructionSequence.compile_prism(File.read(path), path, path)
- * #=> <RubyVM::InstructionSequence:<compiled>@/absolute/path/to/test.rb:1>
- *
- */
-static VALUE
-iseqw_s_compile_prism(int argc, VALUE *argv, VALUE self)
-{
- return iseqw_s_compile_parser(argc, argv, self, true);
+ if (NIL_P(file)) file = rb_fstring_lit("<compiled>");
+ if (NIL_P(path)) path = file;
+ if (NIL_P(line)) line = INT2FIX(1);
+
+ Check_Type(path, T_STRING);
+ Check_Type(file, T_STRING);
+
+ return iseqw_new(rb_iseq_compile_with_option(src, file, path, line, opt));
}
/*
@@ -1679,7 +1461,6 @@ iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
VALUE file, opt = Qnil;
VALUE parser, f, exc = Qnil, ret;
rb_ast_t *ast;
- VALUE ast_value;
rb_compile_option_t option;
int i;
@@ -1698,8 +1479,7 @@ iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
parser = rb_parser_new();
rb_parser_set_context(parser, NULL, FALSE);
- ast_value = rb_parser_load_file(parser, file);
- ast = rb_ruby_ast_data_get(ast_value);
+ ast = (rb_ast_t *)rb_parser_load_file(parser, file);
if (!ast->body.root) exc = GET_EC()->errinfo;
rb_io_close(f);
@@ -1710,11 +1490,10 @@ iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
make_compile_option(&option, opt);
- ret = iseqw_new(rb_iseq_new_with_opt(ast_value, rb_fstring_lit("<main>"),
+ ret = iseqw_new(rb_iseq_new_with_opt(&ast->body, rb_fstring_lit("<main>"),
file,
rb_realpath_internal(Qnil, file, 1),
- 1, NULL, 0, ISEQ_TYPE_TOP, &option,
- Qnil));
+ 1, NULL, 0, ISEQ_TYPE_TOP, &option));
rb_ast_dispose(ast);
rb_vm_pop_frame(ec);
@@ -1724,71 +1503,6 @@ iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
/*
* call-seq:
- * InstructionSequence.compile_file_prism(file[, options]) -> iseq
- *
- * Takes +file+, a String with the location of a Ruby source file, reads,
- * parses and compiles the file, and returns +iseq+, the compiled
- * InstructionSequence with source location metadata set. It parses and
- * compiles using prism.
- *
- * Optionally takes +options+, which can be +true+, +false+ or a +Hash+, to
- * modify the default behavior of the Ruby iseq compiler.
- *
- * For details regarding valid compile options see ::compile_option=.
- *
- * # /tmp/hello.rb
- * puts "Hello, world!"
- *
- * # elsewhere
- * RubyVM::InstructionSequence.compile_file_prism("/tmp/hello.rb")
- * #=> <RubyVM::InstructionSequence:<main>@/tmp/hello.rb>
- */
-static VALUE
-iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self)
-{
- VALUE file, opt = Qnil, ret;
- rb_compile_option_t option;
- int i;
-
- i = rb_scan_args(argc, argv, "1*:", &file, NULL, &opt);
- if (i > 1+NIL_P(opt)) rb_error_arity(argc, 1, 2);
- switch (i) {
- case 2: opt = argv[--i];
- }
- FilePathValue(file);
- file = rb_fstring(file); /* rb_io_t->pathv gets frozen anyways */
-
- rb_execution_context_t *ec = GET_EC();
- VALUE v = rb_vm_push_frame_fname(ec, file);
-
- pm_parse_result_t result = { 0 };
- result.options.line = 1;
- result.node.coverage_enabled = 1;
-
- VALUE script_lines;
- VALUE error = pm_load_parse_file(&result, file, ruby_vm_keep_script_lines ? &script_lines : NULL);
-
- if (error == Qnil) {
- make_compile_option(&option, opt);
-
- ret = iseqw_new(pm_iseq_new_with_opt(&result.node, rb_fstring_lit("<main>"),
- file,
- rb_realpath_internal(Qnil, file, 1),
- 1, NULL, 0, ISEQ_TYPE_TOP, &option));
- pm_parse_result_free(&result);
- rb_vm_pop_frame(ec);
- RB_GC_GUARD(v);
- return ret;
- } else {
- pm_parse_result_free(&result);
- rb_vm_pop_frame(ec);
- RB_GC_GUARD(v);
- rb_exc_raise(error);
- }
-}
-
-/*
- * call-seq:
* InstructionSequence.compile_option = options
*
* Sets the default values for various optimizations in the Ruby iseq
@@ -1809,6 +1523,7 @@ iseqw_s_compile_file_prism(int argc, VALUE *argv, VALUE self)
* * +:operands_unification+
* * +:peephole_optimization+
* * +:specialized_instruction+
+ * * +:stack_caching+
* * +:tailcall_optimization+
*
* Additionally, +:debug_level+ can be set to an integer.
@@ -1843,9 +1558,7 @@ iseqw_s_compile_option_get(VALUE self)
static const rb_iseq_t *
iseqw_check(VALUE iseqw)
{
- rb_iseq_t **iseq_ptr;
- TypedData_Get_Struct(iseqw, rb_iseq_t *, &iseqw_data_type, iseq_ptr);
- rb_iseq_t *iseq = *iseq_ptr;
+ rb_iseq_t *iseq = DATA_PTR(iseqw);
if (!ISEQ_BODY(iseq)) {
rb_ibf_load_iseq_complete(iseq);
@@ -1874,7 +1587,11 @@ rb_iseqw_to_iseq(VALUE iseqw)
static VALUE
iseqw_eval(VALUE self)
{
- return rb_iseq_eval(iseqw_check(self));
+ const rb_iseq_t *iseq = iseqw_check(self);
+ if (0 == ISEQ_BODY(iseq)->iseq_size) {
+ rb_raise(rb_eTypeError, "attempt to evaluate dummy InstructionSequence");
+ }
+ return rb_iseq_eval(iseq);
}
/*
@@ -2296,7 +2013,7 @@ rb_iseq_node_id(const rb_iseq_t *iseq, size_t pos)
}
#endif
-rb_event_flag_t
+MJIT_FUNC_EXPORTED rb_event_flag_t
rb_iseq_event_flags(const rb_iseq_t *iseq, size_t pos)
{
const struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
@@ -2338,7 +2055,7 @@ local_var_name(const rb_iseq_t *diseq, VALUE level, VALUE op)
if (!name) {
name = rb_str_new_cstr("?");
}
- else if (!rb_is_local_id(lid)) {
+ else if (!rb_str_symname_p(name)) {
name = rb_str_inspect(name);
}
else {
@@ -2488,18 +2205,17 @@ rb_insn_operand_intern(const rb_iseq_t *iseq,
VALUE flags = rb_ary_new();
# define CALL_FLAG(n) if (vm_ci_flag(ci) & VM_CALL_##n) rb_ary_push(flags, rb_str_new2(#n))
CALL_FLAG(ARGS_SPLAT);
- CALL_FLAG(ARGS_SPLAT_MUT);
CALL_FLAG(ARGS_BLOCKARG);
CALL_FLAG(FCALL);
CALL_FLAG(VCALL);
CALL_FLAG(ARGS_SIMPLE);
+ CALL_FLAG(BLOCKISEQ);
CALL_FLAG(TAILCALL);
CALL_FLAG(SUPER);
CALL_FLAG(ZSUPER);
CALL_FLAG(KWARG);
CALL_FLAG(KW_SPLAT);
CALL_FLAG(KW_SPLAT_MUT);
- CALL_FLAG(FORWARDING);
CALL_FLAG(OPT_SEND); /* maybe not reachable */
rb_ary_push(ary, rb_ary_join(flags, rb_str_new2("|")));
}
@@ -2597,7 +2313,7 @@ rb_iseq_disasm_insn(VALUE ret, const VALUE *code, size_t pos,
{
rb_event_flag_t events = rb_iseq_event_flags(iseq, pos);
if (events) {
- str = rb_str_catf(str, "[%s%s%s%s%s%s%s%s%s%s%s%s]",
+ str = rb_str_catf(str, "[%s%s%s%s%s%s%s%s%s%s%s]",
events & RUBY_EVENT_LINE ? "Li" : "",
events & RUBY_EVENT_CLASS ? "Cl" : "",
events & RUBY_EVENT_END ? "En" : "",
@@ -2607,7 +2323,6 @@ rb_iseq_disasm_insn(VALUE ret, const VALUE *code, size_t pos,
events & RUBY_EVENT_C_RETURN ? "Cr" : "",
events & RUBY_EVENT_B_CALL ? "Bc" : "",
events & RUBY_EVENT_B_RETURN ? "Br" : "",
- events & RUBY_EVENT_RESCUE ? "Rs" : "",
events & RUBY_EVENT_COVERAGE_LINE ? "Cli" : "",
events & RUBY_EVENT_COVERAGE_BRANCH ? "Cbr" : "");
}
@@ -2697,19 +2412,11 @@ rb_iseq_disasm_recursive(const rb_iseq_t *iseq, VALUE indent)
rb_str_cat2(str, "== disasm: ");
rb_str_append(str, iseq_inspect(iseq));
+ rb_str_catf(str, " (catch: %s)", body->catch_except_p ? "true" : "false");
if ((l = RSTRING_LEN(str) - indent_len) < header_minlen) {
rb_str_modify_expand(str, header_minlen - l);
memset(RSTRING_END(str), '=', header_minlen - l);
}
- if (iseq->body->builtin_attrs) {
-#define disasm_builtin_attr(str, iseq, attr) \
- if (iseq->body->builtin_attrs & BUILTIN_ATTR_ ## attr) { \
- rb_str_cat2(str, " " #attr); \
- }
- disasm_builtin_attr(str, iseq, LEAF);
- disasm_builtin_attr(str, iseq, SINGLE_NOARG_LEAF);
- disasm_builtin_attr(str, iseq, INLINE_BLOCK);
- }
rb_str_cat2(str, "\n");
/* show catch table information */
@@ -2782,11 +2489,11 @@ rb_iseq_disasm_recursive(const rb_iseq_t *iseq, VALUE indent)
}
snprintf(argi, sizeof(argi), "%s%s%s%s%s%s", /* arg, opts, rest, post, kwrest, block */
- (body->param.lead_num > li) ? (body->param.flags.ambiguous_param0 ? "AmbiguousArg" : "Arg") : "",
+ body->param.lead_num > li ? "Arg" : "",
opti,
- (body->param.flags.has_rest && body->param.rest_start == li) ? (body->param.flags.anon_rest ? "AnonRest" : "Rest") : "",
+ (body->param.flags.has_rest && body->param.rest_start == li) ? "Rest" : "",
(body->param.flags.has_post && body->param.post_start <= li && li < body->param.post_start + body->param.post_num) ? "Post" : "",
- (body->param.flags.has_kwrest && keyword->rest_start == li) ? (body->param.flags.anon_kwrest ? "AnonKwrest" : "Kwrest") : "",
+ (body->param.flags.has_kwrest && keyword->rest_start == li) ? "Kwrest" : "",
(body->param.flags.has_block && body->param.block_start == li) ? "Block" : "");
rb_str_cat(str, indent_str, indent_len);
@@ -2961,7 +2668,6 @@ push_event_info(const rb_iseq_t *iseq, rb_event_flag_t events, int line, VALUE a
C(RUBY_EVENT_END, "end", INT2FIX(line));
C(RUBY_EVENT_RETURN, "return", INT2FIX(line));
C(RUBY_EVENT_B_RETURN, "b_return", INT2FIX(line));
- C(RUBY_EVENT_RESCUE, "rescue", INT2FIX(line));
#undef C
}
@@ -3105,6 +2811,17 @@ iseqw_s_disasm(VALUE klass, VALUE body)
return NIL_P(iseqw) ? Qnil : rb_iseq_disasm(iseqw_check(iseqw));
}
+const char *
+ruby_node_name(int node)
+{
+ switch (node) {
+#include "node_name.inc"
+ default:
+ rb_bug("unknown node: %d", node);
+ return 0;
+ }
+}
+
static VALUE
register_label(struct st_table *table, unsigned long idx)
{
@@ -3282,7 +2999,6 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
}
if (iseq_body->param.flags.has_kwrest) rb_hash_aset(params, ID2SYM(rb_intern("kwrest")), INT2FIX(keyword->rest_start));
if (iseq_body->param.flags.ambiguous_param0) rb_hash_aset(params, ID2SYM(rb_intern("ambiguous_param0")), Qtrue);
- if (iseq_body->param.flags.use_block) rb_hash_aset(params, ID2SYM(rb_intern("use_block")), Qtrue);
}
/* body */
@@ -3480,7 +3196,6 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
CHECK_EVENT(RUBY_EVENT_RETURN);
CHECK_EVENT(RUBY_EVENT_B_CALL);
CHECK_EVENT(RUBY_EVENT_B_RETURN);
- CHECK_EVENT(RUBY_EVENT_RESCUE);
#undef CHECK_EVENT
prev_insn_info = info;
}
@@ -3504,7 +3219,6 @@ iseq_data_to_ary(const rb_iseq_t *iseq)
#ifdef USE_ISEQ_NODE_ID
rb_hash_aset(misc, ID2SYM(rb_intern("node_ids")), node_ids);
#endif
- rb_hash_aset(misc, ID2SYM(rb_intern("parser")), iseq_body->prism ? ID2SYM(rb_intern("prism")) : ID2SYM(rb_intern("parse.y")));
/*
* [:magic, :major_version, :minor_version, :format_type, :misc,
@@ -3546,17 +3260,6 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
CONST_ID(req, "req");
CONST_ID(opt, "opt");
-
- if (body->param.flags.forwardable) {
- // [[:rest, :*], [:keyrest, :**], [:block, :&]]
- CONST_ID(rest, "rest");
- CONST_ID(keyrest, "keyrest");
- CONST_ID(block, "block");
- rb_ary_push(args, rb_ary_new_from_args(2, ID2SYM(rest), ID2SYM(idMULT)));
- rb_ary_push(args, rb_ary_new_from_args(2, ID2SYM(keyrest), ID2SYM(idPow)));
- rb_ary_push(args, rb_ary_new_from_args(2, ID2SYM(block), ID2SYM(idAnd)));
- }
-
if (is_proc) {
for (i = 0; i < body->param.lead_num; i++) {
PARAM_TYPE(opt);
@@ -3681,19 +3384,13 @@ typedef struct insn_data_struct {
static insn_data_t insn_data[VM_INSTRUCTION_SIZE/2];
void
-rb_free_encoded_insn_data(void)
-{
- st_free_table(encoded_insn_data);
-}
-
-void
rb_vm_encoded_insn_data_table_init(void)
{
#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
const void * const *table = rb_vm_get_insns_address_table();
#define INSN_CODE(insn) ((VALUE)table[insn])
#else
-#define INSN_CODE(insn) (insn)
+#define INSN_CODE(insn) ((VALUE)(insn))
#endif
st_data_t insn;
encoded_insn_data = st_init_numtable_with_size(VM_INSTRUCTION_SIZE / 2);
@@ -3958,32 +3655,9 @@ rb_iseq_trace_set(const rb_iseq_t *iseq, rb_event_flag_t turnon_events)
}
}
+bool rb_vm_call_ivar_attrset_p(const vm_call_handler ch);
void rb_vm_cc_general(const struct rb_callcache *cc);
-static bool
-clear_attr_cc(VALUE v)
-{
- if (imemo_type_p(v, imemo_callcache) && vm_cc_ivar_p((const struct rb_callcache *)v)) {
- rb_vm_cc_general((struct rb_callcache *)v);
- return true;
- }
- else {
- return false;
- }
-}
-
-static bool
-clear_bf_cc(VALUE v)
-{
- if (imemo_type_p(v, imemo_callcache) && vm_cc_bf_p((const struct rb_callcache *)v)) {
- rb_vm_cc_general((struct rb_callcache *)v);
- return true;
- }
- else {
- return false;
- }
-}
-
static int
clear_attr_ccs_i(void *vstart, void *vend, size_t stride, void *data)
{
@@ -3991,35 +3665,20 @@ clear_attr_ccs_i(void *vstart, void *vend, size_t stride, void *data)
for (; v != (VALUE)vend; v += stride) {
void *ptr = asan_poisoned_object_p(v);
asan_unpoison_object(v, false);
- clear_attr_cc(v);
- asan_poison_object_if(ptr, v);
- }
- return 0;
-}
-void
-rb_clear_attr_ccs(void)
-{
- rb_objspace_each_objects(clear_attr_ccs_i, NULL);
-}
+ if (imemo_type_p(v, imemo_callcache) && rb_vm_call_ivar_attrset_p(((const struct rb_callcache *)v)->call_)) {
+ rb_vm_cc_general((struct rb_callcache *)v);
+ }
-static int
-clear_bf_ccs_i(void *vstart, void *vend, size_t stride, void *data)
-{
- VALUE v = (VALUE)vstart;
- for (; v != (VALUE)vend; v += stride) {
- void *ptr = asan_poisoned_object_p(v);
- asan_unpoison_object(v, false);
- clear_bf_cc(v);
asan_poison_object_if(ptr, v);
}
return 0;
}
void
-rb_clear_bf_ccs(void)
+rb_clear_attr_ccs(void)
{
- rb_objspace_each_objects(clear_bf_ccs_i, NULL);
+ rb_objspace_each_objects(clear_attr_ccs_i, NULL);
}
static int
@@ -4035,9 +3694,8 @@ trace_set_i(void *vstart, void *vend, size_t stride, void *data)
if (rb_obj_is_iseq(v)) {
rb_iseq_trace_set(rb_iseq_check((rb_iseq_t *)v), turnon_events);
}
- else if (clear_attr_cc(v)) {
- }
- else if (clear_bf_cc(v)) {
+ else if (imemo_type_p(v, imemo_callcache) && rb_vm_call_ivar_attrset_p(((const struct rb_callcache *)v)->call_)) {
+ rb_vm_cc_general((struct rb_callcache *)v);
}
asan_poison_object_if(ptr, v);
@@ -4252,7 +3910,7 @@ succ_index_lookup(const struct succ_index_table *sd, int x)
* call-seq:
* iseq.script_lines -> array or nil
*
- * It returns recorded script lines if it is available.
+ * It returns recorded script lines if it is availalble.
* The script lines are not limited to the iseq range, but
* are entire lines of the source file.
*
@@ -4325,9 +3983,6 @@ Init_ISeq(void)
(void)iseq_s_load;
rb_define_singleton_method(rb_cISeq, "compile", iseqw_s_compile, -1);
- rb_define_singleton_method(rb_cISeq, "compile_parsey", iseqw_s_compile_parsey, -1);
- rb_define_singleton_method(rb_cISeq, "compile_prism", iseqw_s_compile_prism, -1);
- rb_define_singleton_method(rb_cISeq, "compile_file_prism", iseqw_s_compile_file_prism, -1);
rb_define_singleton_method(rb_cISeq, "new", iseqw_s_compile, -1);
rb_define_singleton_method(rb_cISeq, "compile_file", iseqw_s_compile_file, -1);
rb_define_singleton_method(rb_cISeq, "compile_option", iseqw_s_compile_option_get, 0);
diff --git a/iseq.h b/iseq.h
index a0b59c441f..2f83e7336d 100644
--- a/iseq.h
+++ b/iseq.h
@@ -11,9 +11,7 @@
**********************************************************************/
#include "internal/gc.h"
-#include "shape.h"
#include "vm_core.h"
-#include "prism_compile.h"
RUBY_EXTERN const int ruby_api_version[];
#define ISEQ_MAJOR_VERSION ((unsigned int)ruby_api_version[0])
@@ -47,10 +45,6 @@ extern const ID rb_iseq_shared_exc_local_tbl[];
#define ISEQ_FLIP_CNT(iseq) ISEQ_BODY(iseq)->variable.flip_count
-#define ISEQ_FROZEN_STRING_LITERAL_ENABLED 1
-#define ISEQ_FROZEN_STRING_LITERAL_DISABLED 0
-#define ISEQ_FROZEN_STRING_LITERAL_UNSET -1
-
static inline rb_snum_t
ISEQ_FLIP_CNT_INCREMENT(const rb_iseq_t *iseq)
{
@@ -70,7 +64,9 @@ ISEQ_ORIGINAL_ISEQ_CLEAR(const rb_iseq_t *iseq)
{
void *ptr = ISEQ_BODY(iseq)->variable.original_iseq;
ISEQ_BODY(iseq)->variable.original_iseq = NULL;
- ruby_xfree(ptr);
+ if (ptr) {
+ ruby_xfree(ptr);
+ }
}
static inline VALUE *
@@ -86,10 +82,9 @@ ISEQ_ORIGINAL_ISEQ_ALLOC(const rb_iseq_t *iseq, long size)
RUBY_EVENT_CALL | \
RUBY_EVENT_RETURN| \
RUBY_EVENT_C_CALL| \
- RUBY_EVENT_C_RETURN | \
- RUBY_EVENT_B_CALL | \
- RUBY_EVENT_B_RETURN | \
- RUBY_EVENT_RESCUE | \
+ RUBY_EVENT_C_RETURN| \
+ RUBY_EVENT_B_CALL| \
+ RUBY_EVENT_B_RETURN| \
RUBY_EVENT_COVERAGE_LINE| \
RUBY_EVENT_COVERAGE_BRANCH)
@@ -119,6 +114,7 @@ struct iseq_compile_data {
struct iseq_compile_data_storage *storage_current;
} insn;
bool in_rescue;
+ bool in_masgn;
int loopval_popped; /* used by NODE_BREAK */
int last_line;
int label_no;
@@ -130,7 +126,6 @@ struct iseq_compile_data {
struct rb_id_table *ivar_cache_table;
const struct rb_builtin_function *builtin_function_table;
const NODE *root_node;
- bool catch_except_p; // If a frame of this ISeq may catch exception, set true.
#if OPT_SUPPORT_JOKE
st_table *labels_table;
#endif
@@ -164,7 +159,7 @@ ISEQ_COMPILE_DATA_CLEAR(rb_iseq_t *iseq)
static inline rb_iseq_t *
iseq_imemo_alloc(void)
{
- return IMEMO_NEW(rb_iseq_t, imemo_iseq, 0);
+ return (rb_iseq_t *)rb_imemo_new(imemo_iseq, 0, 0, 0, 0);
}
VALUE rb_iseq_ibf_dump(const rb_iseq_t *iseq, VALUE opt);
@@ -176,7 +171,6 @@ void rb_iseq_init_trace(rb_iseq_t *iseq);
int rb_iseq_add_local_tracepoint_recursively(const rb_iseq_t *iseq, rb_event_flag_t turnon_events, VALUE tpval, unsigned int target_line, bool target_bmethod);
int rb_iseq_remove_local_tracepoint_recursively(const rb_iseq_t *iseq, VALUE tpval);
const rb_iseq_t *rb_iseq_load_iseq(VALUE fname);
-int rb_iseq_opt_frozen_string_literal(void);
#if VM_INSN_INFO_TABLE_IMPL == 2
unsigned int *rb_iseq_insns_info_decode_positions(const struct rb_iseq_constant_body *body);
@@ -193,7 +187,7 @@ VALUE *rb_iseq_original_iseq(const rb_iseq_t *iseq);
void rb_iseq_build_from_ary(rb_iseq_t *iseq, VALUE misc,
VALUE locals, VALUE args,
VALUE exception, VALUE body);
-void rb_iseq_mark_and_pin_insn_storage(struct iseq_compile_data_storage *arena);
+void rb_iseq_mark_insn_storage(struct iseq_compile_data_storage *arena);
VALUE rb_iseq_load(VALUE data, VALUE parent, VALUE opt);
VALUE rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc);
@@ -231,7 +225,8 @@ struct rb_compile_option_struct {
unsigned int specialized_instruction: 1;
unsigned int operands_unification: 1;
unsigned int instructions_unification: 1;
- signed int frozen_string_literal: 2; /* -1: not specified, 0: false, 1: true */
+ unsigned int stack_caching: 1;
+ unsigned int frozen_string_literal: 1;
unsigned int debug_frozen_string_literal: 1;
unsigned int coverage_enabled: 1;
int debug_level;
@@ -276,11 +271,10 @@ struct iseq_catch_table_entry {
unsigned int sp;
};
-RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN()
-struct iseq_catch_table {
+PACKED_STRUCT_UNALIGNED(struct iseq_catch_table {
unsigned int size;
struct iseq_catch_table_entry entries[FLEX_ARY_LEN];
-} RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END();
+});
static inline int
iseq_catch_table_bytes(int n)
@@ -331,10 +325,6 @@ VALUE rb_iseq_defined_string(enum defined_type type);
/* vm.c */
VALUE rb_iseq_local_variables(const rb_iseq_t *iseq);
-attr_index_t rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq);
-
-void rb_free_encoded_insn_data(void);
-
RUBY_SYMBOL_EXPORT_END
#endif /* RUBY_ISEQ_H */
diff --git a/kernel.rb b/kernel.rb
index 07878e82dc..9cc58bc1d9 100644
--- a/kernel.rb
+++ b/kernel.rb
@@ -16,7 +16,7 @@ module Kernel
#++
#
def class
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_obj_class(self)'
end
@@ -58,14 +58,14 @@ module Kernel
# a.freeze #=> ["a", "b", "c"]
# a.frozen? #=> true
#--
- # Determines if the object is frozen. Equivalent to `Object#frozen?` in Ruby.
- # @param[in] obj the object to be determines
- # @retval Qtrue if frozen
- # @retval Qfalse if not frozen
+ # Determines if the object is frozen. Equivalent to \c Object\#frozen? in Ruby.
+ # \param[in] obj the object to be determines
+ # \retval Qtrue if frozen
+ # \retval Qfalse if not frozen
#++
#
def frozen?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_obj_frozen_p(self)'
end
@@ -87,7 +87,6 @@ module Kernel
#++
#
def tap
- Primitive.attr! :inline_block
yield(self)
self
end
@@ -105,9 +104,9 @@ module Kernel
# require 'open-uri'
# require 'json'
#
- # construct_url(arguments)
- # .then {|url| URI(url).read }
- # .then {|response| JSON.parse(response) }
+ # construct_url(arguments).
+ # then {|url| URI(url).read }.
+ # then {|response| JSON.parse(response) }
#
# When called without block, the method returns +Enumerator+,
# which can be used, for example, for conditional
@@ -119,59 +118,38 @@ module Kernel
# 2.then.detect(&:odd?) # => nil
#
def then
- Primitive.attr! :inline_block
- unless defined?(yield)
+ unless Primitive.block_given_p
return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, rb_obj_size)'
end
yield(self)
end
- alias yield_self then
-
- module_function
-
- # call-seq:
- # loop { block }
- # loop -> an_enumerator
- #
- # Repeatedly executes the block.
- #
- # If no block is given, an enumerator is returned instead.
- #
- # loop do
- # print "Input: "
- # line = gets
- # break if !line or line =~ /^q/i
- # # ...
- # end
- #
- # StopIteration raised in the block breaks the loop. In this case,
- # loop returns the "result" value stored in the exception.
- #
- # enum = Enumerator.new { |y|
- # y << "one"
- # y << "two"
- # :ok
- # }
- #
- # result = loop {
- # puts enum.next
- # } #=> :ok
- def loop
- Primitive.attr! :inline_block
- unless defined?(yield)
- return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, rb_f_loop_size)'
- end
-
- begin
- while true
- yield
- end
- rescue StopIteration => e
- e.result
+ #
+ # call-seq:
+ # obj.yield_self {|x| block } -> an_object
+ #
+ # Yields self to the block and returns the result of the block.
+ #
+ # "my string".yield_self {|s| s.upcase } #=> "MY STRING"
+ #
+ # Good usage for +then+ is value piping in method chains:
+ #
+ # require 'open-uri'
+ # require 'json'
+ #
+ # construct_url(arguments).
+ # then {|url| URI(url).read }.
+ # then {|response| JSON.parse(response) }
+ #
+ def yield_self
+ unless Primitive.block_given_p
+ return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, rb_obj_size)'
end
+ yield(self)
end
+ module_function
+
#
# call-seq:
# Float(arg, exception: true) -> float or nil
@@ -197,97 +175,4 @@ module Kernel
Primitive.rb_f_float(arg, exception)
end
end
-
- # call-seq:
- # Integer(object, base = 0, exception: true) -> integer or nil
- #
- # Returns an integer converted from +object+.
- #
- # Tries to convert +object+ to an integer
- # using +to_int+ first and +to_i+ second;
- # see below for exceptions.
- #
- # With a non-zero +base+, +object+ must be a string or convertible
- # to a string.
- #
- # ==== numeric objects
- #
- # With integer argument +object+ given, returns +object+:
- #
- # Integer(1) # => 1
- # Integer(-1) # => -1
- #
- # With floating-point argument +object+ given,
- # returns +object+ truncated to an integer:
- #
- # Integer(1.9) # => 1 # Rounds toward zero.
- # Integer(-1.9) # => -1 # Rounds toward zero.
- #
- # ==== string objects
- #
- # With string argument +object+ and zero +base+ given,
- # returns +object+ converted to an integer in base 10:
- #
- # Integer('100') # => 100
- # Integer('-100') # => -100
- #
- # With +base+ zero, string +object+ may contain leading characters
- # to specify the actual base (radix indicator):
- #
- # Integer('0100') # => 64 # Leading '0' specifies base 8.
- # Integer('0b100') # => 4 # Leading '0b', specifies base 2.
- # Integer('0x100') # => 256 # Leading '0x' specifies base 16.
- #
- # With a positive +base+ (in range 2..36) given, returns +object+
- # converted to an integer in the given base:
- #
- # Integer('100', 2) # => 4
- # Integer('100', 8) # => 64
- # Integer('-100', 16) # => -256
- #
- # With a negative +base+ (in range -36..-2) given, returns +object+
- # converted to an integer in the radix indicator if exists or
- # +-base+:
- #
- # Integer('0x100', -2) # => 256
- # Integer('100', -2) # => 4
- # Integer('0b100', -8) # => 4
- # Integer('100', -8) # => 64
- # Integer('0o100', -10) # => 64
- # Integer('100', -10) # => 100
- #
- # +base+ -1 is equal the -10 case.
- #
- # When converting strings, surrounding whitespace and embedded underscores
- # are allowed and ignored:
- #
- # Integer(' 100 ') # => 100
- # Integer('-1_0_0', 16) # => -256
- #
- # ==== other classes
- #
- # Examples with +object+ of various other classes:
- #
- # Integer(Rational(9, 10)) # => 0 # Rounds toward zero.
- # Integer(Complex(2, 0)) # => 2 # Imaginary part must be zero.
- # Integer(Time.now) # => 1650974042
- #
- # ==== keywords
- #
- # With optional keyword argument +exception+ given as +true+ (the default):
- #
- # - Raises TypeError if +object+ does not respond to +to_int+ or +to_i+.
- # - Raises TypeError if +object+ is +nil+.
- # - Raise ArgumentError if +object+ is an invalid string.
- #
- # With +exception+ given as +false+, an exception of any kind is suppressed
- # and +nil+ is returned.
-
- def Integer(arg, base = 0, exception: true)
- if Primitive.mandatory_only?
- Primitive.rb_f_integer1(arg)
- else
- Primitive.rb_f_integer(arg, base, exception);
- end
- end
end
diff --git a/lex.c.blt b/lex.c.blt
index de0719b014..85727ed00f 100644
--- a/lex.c.blt
+++ b/lex.c.blt
@@ -1,5 +1,5 @@
/* ANSI-C code produced by gperf version 3.1 */
-/* Command-line: gperf -C -L ANSI-C -P -p -j1 -i 1 -g -o -t -N rb_reserved_word -k'1,3,$' defs/keywords */
+/* Command-line: gperf -C -P -p -j1 -i 1 -g -o -t -N rb_reserved_word -k'1,3,$' defs/keywords */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@@ -28,6 +28,7 @@
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
#endif
+#define gperf_offsetof(s, n) (short)offsetof(struct s##_t, s##_str##n)
#line 1 "defs/keywords"
struct kwtable {short name, id[2], state;};
@@ -195,88 +196,88 @@ rb_reserved_word (register const char *str, register size_t len)
{
{-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
#line 19 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str8, {keyword_break, keyword_break}, EXPR_MID},
+ {gperf_offsetof(stringpool, 8), {keyword_break, keyword_break}, EXPR_MID},
#line 25 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str9, {keyword_else, keyword_else}, EXPR_BEG},
+ {gperf_offsetof(stringpool, 9), {keyword_else, keyword_else}, EXPR_BEG},
#line 35 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str10, {keyword_nil, keyword_nil}, EXPR_END},
+ {gperf_offsetof(stringpool, 10), {keyword_nil, keyword_nil}, EXPR_END},
#line 28 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str11, {keyword_ensure, keyword_ensure}, EXPR_BEG},
+ {gperf_offsetof(stringpool, 11), {keyword_ensure, keyword_ensure}, EXPR_BEG},
#line 27 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str12, {keyword_end, keyword_end}, EXPR_END},
+ {gperf_offsetof(stringpool, 12), {keyword_end, keyword_end}, EXPR_END},
#line 44 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str13, {keyword_then, keyword_then}, EXPR_BEG},
+ {gperf_offsetof(stringpool, 13), {keyword_then, keyword_then}, EXPR_BEG},
#line 36 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str14, {keyword_not, keyword_not}, EXPR_ARG},
+ {gperf_offsetof(stringpool, 14), {keyword_not, keyword_not}, EXPR_ARG},
#line 29 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str15, {keyword_false, keyword_false}, EXPR_END},
+ {gperf_offsetof(stringpool, 15), {keyword_false, keyword_false}, EXPR_END},
#line 42 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str16, {keyword_self, keyword_self}, EXPR_END},
+ {gperf_offsetof(stringpool, 16), {keyword_self, keyword_self}, EXPR_END},
#line 26 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str17, {keyword_elsif, keyword_elsif}, EXPR_VALUE},
+ {gperf_offsetof(stringpool, 17), {keyword_elsif, keyword_elsif}, EXPR_VALUE},
#line 39 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str18, {keyword_rescue, modifier_rescue}, EXPR_MID},
+ {gperf_offsetof(stringpool, 18), {keyword_rescue, modifier_rescue}, EXPR_MID},
#line 45 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str19, {keyword_true, keyword_true}, EXPR_END},
+ {gperf_offsetof(stringpool, 19), {keyword_true, keyword_true}, EXPR_END},
#line 48 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str20, {keyword_until, modifier_until}, EXPR_VALUE},
+ {gperf_offsetof(stringpool, 20), {keyword_until, modifier_until}, EXPR_VALUE},
#line 47 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str21, {keyword_unless, modifier_unless}, EXPR_VALUE},
+ {gperf_offsetof(stringpool, 21), {keyword_unless, modifier_unless}, EXPR_VALUE},
#line 41 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str22, {keyword_return, keyword_return}, EXPR_MID},
+ {gperf_offsetof(stringpool, 22), {keyword_return, keyword_return}, EXPR_MID},
#line 22 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str23, {keyword_def, keyword_def}, EXPR_FNAME},
+ {gperf_offsetof(stringpool, 23), {keyword_def, keyword_def}, EXPR_FNAME},
#line 17 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str24, {keyword_and, keyword_and}, EXPR_VALUE},
+ {gperf_offsetof(stringpool, 24), {keyword_and, keyword_and}, EXPR_VALUE},
#line 24 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str25, {keyword_do, keyword_do}, EXPR_BEG},
+ {gperf_offsetof(stringpool, 25), {keyword_do, keyword_do}, EXPR_BEG},
#line 51 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str26, {keyword_yield, keyword_yield}, EXPR_ARG},
+ {gperf_offsetof(stringpool, 26), {keyword_yield, keyword_yield}, EXPR_ARG},
#line 30 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str27, {keyword_for, keyword_for}, EXPR_VALUE},
+ {gperf_offsetof(stringpool, 27), {keyword_for, keyword_for}, EXPR_VALUE},
#line 46 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str28, {keyword_undef, keyword_undef}, EXPR_FNAME|EXPR_FITEM},
+ {gperf_offsetof(stringpool, 28), {keyword_undef, keyword_undef}, EXPR_FNAME|EXPR_FITEM},
#line 37 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str29, {keyword_or, keyword_or}, EXPR_VALUE},
+ {gperf_offsetof(stringpool, 29), {keyword_or, keyword_or}, EXPR_VALUE},
#line 32 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str30, {keyword_in, keyword_in}, EXPR_VALUE},
+ {gperf_offsetof(stringpool, 30), {keyword_in, keyword_in}, EXPR_VALUE},
#line 49 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str31, {keyword_when, keyword_when}, EXPR_VALUE},
+ {gperf_offsetof(stringpool, 31), {keyword_when, keyword_when}, EXPR_VALUE},
#line 40 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str32, {keyword_retry, keyword_retry}, EXPR_END},
+ {gperf_offsetof(stringpool, 32), {keyword_retry, keyword_retry}, EXPR_END},
#line 31 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str33, {keyword_if, modifier_if}, EXPR_VALUE},
+ {gperf_offsetof(stringpool, 33), {keyword_if, modifier_if}, EXPR_VALUE},
#line 20 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str34, {keyword_case, keyword_case}, EXPR_VALUE},
+ {gperf_offsetof(stringpool, 34), {keyword_case, keyword_case}, EXPR_VALUE},
#line 38 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str35, {keyword_redo, keyword_redo}, EXPR_END},
+ {gperf_offsetof(stringpool, 35), {keyword_redo, keyword_redo}, EXPR_END},
#line 34 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str36, {keyword_next, keyword_next}, EXPR_MID},
+ {gperf_offsetof(stringpool, 36), {keyword_next, keyword_next}, EXPR_MID},
#line 43 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str37, {keyword_super, keyword_super}, EXPR_ARG},
+ {gperf_offsetof(stringpool, 37), {keyword_super, keyword_super}, EXPR_ARG},
#line 33 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str38, {keyword_module, keyword_module}, EXPR_VALUE},
+ {gperf_offsetof(stringpool, 38), {keyword_module, keyword_module}, EXPR_VALUE},
#line 18 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str39, {keyword_begin, keyword_begin}, EXPR_BEG},
+ {gperf_offsetof(stringpool, 39), {keyword_begin, keyword_begin}, EXPR_BEG},
#line 12 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str40, {keyword__LINE__, keyword__LINE__}, EXPR_END},
+ {gperf_offsetof(stringpool, 40), {keyword__LINE__, keyword__LINE__}, EXPR_END},
#line 13 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str41, {keyword__FILE__, keyword__FILE__}, EXPR_END},
+ {gperf_offsetof(stringpool, 41), {keyword__FILE__, keyword__FILE__}, EXPR_END},
#line 11 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str42, {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END},
+ {gperf_offsetof(stringpool, 42), {keyword__ENCODING__, keyword__ENCODING__}, EXPR_END},
#line 15 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str43, {keyword_END, keyword_END}, EXPR_END},
+ {gperf_offsetof(stringpool, 43), {keyword_END, keyword_END}, EXPR_END},
#line 16 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str44, {keyword_alias, keyword_alias}, EXPR_FNAME|EXPR_FITEM},
+ {gperf_offsetof(stringpool, 44), {keyword_alias, keyword_alias}, EXPR_FNAME|EXPR_FITEM},
#line 14 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str45, {keyword_BEGIN, keyword_BEGIN}, EXPR_END},
+ {gperf_offsetof(stringpool, 45), {keyword_BEGIN, keyword_BEGIN}, EXPR_END},
#line 23 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str46, {keyword_defined, keyword_defined}, EXPR_ARG},
+ {gperf_offsetof(stringpool, 46), {keyword_defined, keyword_defined}, EXPR_ARG},
#line 21 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str47, {keyword_class, keyword_class}, EXPR_CLASS},
+ {gperf_offsetof(stringpool, 47), {keyword_class, keyword_class}, EXPR_CLASS},
{-1}, {-1},
#line 50 "defs/keywords"
- {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str50, {keyword_while, modifier_while}, EXPR_VALUE}
+ {gperf_offsetof(stringpool, 50), {keyword_while, modifier_while}, EXPR_VALUE}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
diff --git a/lib/English.gemspec b/lib/English.gemspec
index 5f4eb420c2..a08542bcda 100644
--- a/lib/English.gemspec
+++ b/lib/English.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = "english"
- spec.version = "0.8.0"
+ spec.version = "0.7.2"
spec.authors = ["Yukihiro Matsumoto"]
spec.email = ["matz@ruby-lang.org"]
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.require_paths = ["lib"]
end
diff --git a/lib/English.rb b/lib/English.rb
index 03fe721991..ec90ff10cd 100644
--- a/lib/English.rb
+++ b/lib/English.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
# Include the English library file in a Ruby script, and you can
-# reference the global variables such as <code>$_</code> using less
+# reference the global variables such as <tt>$_</tt> using less
# cryptic names, listed below.
#
# Without 'English':
@@ -39,6 +39,7 @@
# $PROCESS_ID:: $$
# $CHILD_STATUS:: $?
# $LAST_MATCH_INFO:: $~
+# $IGNORECASE:: $=
# $ARGV:: $*
# $MATCH:: $&
# $PREMATCH:: $`
@@ -55,73 +56,87 @@ alias $ERROR_INFO $!
alias $ERROR_POSITION $@
# The default separator pattern used by String#split. May be set from
-# the command line using the <code>-F</code> flag.
+# the command line using the <tt>-F</tt> flag.
alias $FS $;
+
+# The default separator pattern used by String#split. May be set from
+# the command line using the <tt>-F</tt> flag.
alias $FIELD_SEPARATOR $;
# The separator string output between the parameters to methods such
# as Kernel#print and Array#join. Defaults to +nil+, which adds no
# text.
+alias $OFS $,
# The separator string output between the parameters to methods such
# as Kernel#print and Array#join. Defaults to +nil+, which adds no
# text.
-alias $OFS $,
alias $OUTPUT_FIELD_SEPARATOR $,
# The input record separator (newline by default). This is the value
# that routines such as Kernel#gets use to determine record
# boundaries. If set to +nil+, +gets+ will read the entire file.
alias $RS $/
+
+# The input record separator (newline by default). This is the value
+# that routines such as Kernel#gets use to determine record
+# boundaries. If set to +nil+, +gets+ will read the entire file.
alias $INPUT_RECORD_SEPARATOR $/
# The string appended to the output of every call to methods such as
# Kernel#print and IO#write. The default value is +nil+.
alias $ORS $\
+
+# The string appended to the output of every call to methods such as
+# Kernel#print and IO#write. The default value is +nil+.
alias $OUTPUT_RECORD_SEPARATOR $\
# The number of the last line read from the current input file.
-alias $NR $.
alias $INPUT_LINE_NUMBER $.
+# The number of the last line read from the current input file.
+alias $NR $.
+
# The last line read by Kernel#gets or
# Kernel#readline. Many string-related functions in the
-# Kernel module operate on <code>$_</code> by default. The variable is
+# Kernel module operate on <tt>$_</tt> by default. The variable is
# local to the current scope. Thread local.
alias $LAST_READ_LINE $_
# The destination of output for Kernel#print
# and Kernel#printf. The default value is
-# <code>$stdout</code>.
+# <tt>$stdout</tt>.
alias $DEFAULT_OUTPUT $>
# An object that provides access to the concatenation
# of the contents of all the files
-# given as command-line arguments, or <code>$stdin</code>
+# given as command-line arguments, or <tt>$stdin</tt>
# (in the case where there are no
-# arguments). <code>$<</code> supports methods similar to a
+# arguments). <tt>$<</tt> supports methods similar to a
# File object:
# +inmode+, +close+,
-# <code>closed?</code>, +each+,
-# <code>each_byte</code>, <code>each_line</code>,
-# +eof+, <code>eof?</code>, +file+,
+# <tt>closed?</tt>, +each+,
+# <tt>each_byte</tt>, <tt>each_line</tt>,
+# +eof+, <tt>eof?</tt>, +file+,
# +filename+, +fileno+,
# +getc+, +gets+, +lineno+,
-# <code>lineno=</code>, +path+,
-# +pos+, <code>pos=</code>,
+# <tt>lineno=</tt>, +path+,
+# +pos+, <tt>pos=</tt>,
# +read+, +readchar+,
# +readline+, +readlines+,
# +rewind+, +seek+, +skip+,
-# +tell+, <code>to_a</code>, <code>to_i</code>,
-# <code>to_io</code>, <code>to_s</code>, along with the
+# +tell+, <tt>to_a</tt>, <tt>to_i</tt>,
+# <tt>to_io</tt>, <tt>to_s</tt>, along with the
# methods in Enumerable. The method +file+
# returns a File object for the file currently
-# being read. This may change as <code>$<</code> reads
+# being read. This may change as <tt>$<</tt> reads
# through the files on the command line. Read only.
alias $DEFAULT_INPUT $<
# The process number of the program being executed. Read only.
alias $PID $$
+
+# The process number of the program being executed. Read only.
alias $PROCESS_ID $$
# The exit status of the last child process to terminate. Read
@@ -129,13 +144,16 @@ alias $PROCESS_ID $$
alias $CHILD_STATUS $?
# A +MatchData+ object that encapsulates the results of a successful
-# pattern match. The variables <code>$&</code>, <code>$`</code>, <code>$'</code>,
-# and <code>$1</code> to <code>$9</code> are all derived from
-# <code>$~</code>. Assigning to <code>$~</code> changes the values of these
+# pattern match. The variables <tt>$&</tt>, <tt>$`</tt>, <tt>$'</tt>,
+# and <tt>$1</tt> to <tt>$9</tt> are all derived from
+# <tt>$~</tt>. Assigning to <tt>$~</tt> changes the values of these
# derived variables. This variable is local to the current
# scope.
alias $LAST_MATCH_INFO $~
+# This variable is no longer effective. Deprecated.
+alias $IGNORECASE $=
+
# An array of strings containing the command-line
# options from the invocation of the program. Options
# used by the Ruby interpreter will have been
@@ -158,7 +176,7 @@ alias $PREMATCH $`
alias $POSTMATCH $'
# The contents of the highest-numbered group matched in the last
-# successful pattern match. Thus, in <code>"cat" =~ /(c|a)(t|z)/</code>,
-# <code>$+</code> will be set to "t". This variable is local to the
+# successful pattern match. Thus, in <tt>"cat" =~ /(c|a)(t|z)/</tt>,
+# <tt>$+</tt> will be set to "t". This variable is local to the
# current scope. Read only.
alias $LAST_PAREN_MATCH $+
diff --git a/lib/abbrev.gemspec b/lib/abbrev.gemspec
new file mode 100644
index 0000000000..c28b960c8c
--- /dev/null
+++ b/lib/abbrev.gemspec
@@ -0,0 +1,22 @@
+Gem::Specification.new do |spec|
+ spec.name = "abbrev"
+ spec.version = "0.1.1"
+ spec.authors = ["Akinori MUSHA"]
+ spec.email = ["knu@idaemons.org"]
+
+ spec.summary = %q{Calculates a set of unique abbreviations for a given set of strings}
+ spec.description = %q{Calculates a set of unique abbreviations for a given set of strings}
+ spec.homepage = "https://github.com/ruby/abbrev"
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = []
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/abbrev.rb b/lib/abbrev.rb
new file mode 100644
index 0000000000..2af01d2eae
--- /dev/null
+++ b/lib/abbrev.rb
@@ -0,0 +1,132 @@
+# frozen_string_literal: true
+#--
+# Copyright (c) 2001,2003 Akinori MUSHA <knu@iDaemons.org>
+#
+# All rights reserved. You can redistribute and/or modify it under
+# the same terms as Ruby.
+#
+# $Idaemons: /home/cvs/rb/abbrev.rb,v 1.2 2001/05/30 09:37:45 knu Exp $
+# $RoughId: abbrev.rb,v 1.4 2003/10/14 19:45:42 knu Exp $
+# $Id$
+#++
+
+##
+# Calculates the set of unambiguous abbreviations for a given set of strings.
+#
+# require 'abbrev'
+# require 'pp'
+#
+# pp Abbrev.abbrev(['ruby'])
+# #=> {"ruby"=>"ruby", "rub"=>"ruby", "ru"=>"ruby", "r"=>"ruby"}
+#
+# pp Abbrev.abbrev(%w{ ruby rules })
+#
+# _Generates:_
+# { "ruby" => "ruby",
+# "rub" => "ruby",
+# "rules" => "rules",
+# "rule" => "rules",
+# "rul" => "rules" }
+#
+# It also provides an array core extension, Array#abbrev.
+#
+# pp %w{ summer winter }.abbrev
+#
+# _Generates:_
+# { "summer" => "summer",
+# "summe" => "summer",
+# "summ" => "summer",
+# "sum" => "summer",
+# "su" => "summer",
+# "s" => "summer",
+# "winter" => "winter",
+# "winte" => "winter",
+# "wint" => "winter",
+# "win" => "winter",
+# "wi" => "winter",
+# "w" => "winter" }
+
+module Abbrev
+
+ # Given a set of strings, calculate the set of unambiguous abbreviations for
+ # those strings, and return a hash where the keys are all the possible
+ # abbreviations and the values are the full strings.
+ #
+ # Thus, given +words+ is "car" and "cone", the keys pointing to "car" would
+ # be "ca" and "car", while those pointing to "cone" would be "co", "con", and
+ # "cone".
+ #
+ # require 'abbrev'
+ #
+ # Abbrev.abbrev(%w{ car cone })
+ # #=> {"ca"=>"car", "con"=>"cone", "co"=>"cone", "car"=>"car", "cone"=>"cone"}
+ #
+ # The optional +pattern+ parameter is a pattern or a string. Only input
+ # strings that match the pattern or start with the string are included in the
+ # output hash.
+ #
+ # Abbrev.abbrev(%w{car box cone crab}, /b/)
+ # #=> {"box"=>"box", "bo"=>"box", "b"=>"box", "crab" => "crab"}
+ #
+ # Abbrev.abbrev(%w{car box cone}, 'ca')
+ # #=> {"car"=>"car", "ca"=>"car"}
+ def abbrev(words, pattern = nil)
+ table = {}
+ seen = Hash.new(0)
+
+ if pattern.is_a?(String)
+ pattern = /\A#{Regexp.quote(pattern)}/ # regard as a prefix
+ end
+
+ words.each do |word|
+ next if word.empty?
+ word.size.downto(1) { |len|
+ abbrev = word[0...len]
+
+ next if pattern && pattern !~ abbrev
+
+ case seen[abbrev] += 1
+ when 1
+ table[abbrev] = word
+ when 2
+ table.delete(abbrev)
+ else
+ break
+ end
+ }
+ end
+
+ words.each do |word|
+ next if pattern && pattern !~ word
+
+ table[word] = word
+ end
+
+ table
+ end
+
+ module_function :abbrev
+end
+
+class Array
+ # Calculates the set of unambiguous abbreviations for the strings in +self+.
+ #
+ # require 'abbrev'
+ # %w{ car cone }.abbrev
+ # #=> {"car"=>"car", "ca"=>"car", "cone"=>"cone", "con"=>"cone", "co"=>"cone"}
+ #
+ # The optional +pattern+ parameter is a pattern or a string. Only input
+ # strings that match the pattern or start with the string are included in the
+ # output hash.
+ #
+ # %w{ fast boat day }.abbrev(/^.a/)
+ # #=> {"fast"=>"fast", "fas"=>"fast", "fa"=>"fast", "day"=>"day", "da"=>"day"}
+ #
+ # Abbrev.abbrev(%w{car box cone}, "ca")
+ # #=> {"car"=>"car", "ca"=>"car"}
+ #
+ # See also Abbrev.abbrev
+ def abbrev(pattern = nil)
+ Abbrev::abbrev(self, pattern)
+ end
+end
diff --git a/lib/base64.gemspec b/lib/base64.gemspec
new file mode 100644
index 0000000000..daa0b7fa14
--- /dev/null
+++ b/lib/base64.gemspec
@@ -0,0 +1,20 @@
+Gem::Specification.new do |spec|
+ spec.name = "base64"
+ spec.version = "0.1.1"
+ spec.authors = ["Yusuke Endoh"]
+ spec.email = ["mame@ruby-lang.org"]
+
+ spec.summary = %q{Support for encoding and decoding binary data using a Base64 representation.}
+ spec.description = %q{Support for encoding and decoding binary data using a Base64 representation.}
+ spec.homepage = "https://github.com/ruby/base64"
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ spec.files = ["README.md", "LICENSE.txt", "lib/base64.rb"]
+ spec.bindir = "exe"
+ spec.executables = []
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/base64.rb b/lib/base64.rb
new file mode 100644
index 0000000000..693aa1f519
--- /dev/null
+++ b/lib/base64.rb
@@ -0,0 +1,110 @@
+# frozen_string_literal: true
+#
+# = base64.rb: methods for base64-encoding and -decoding strings
+#
+
+# The Base64 module provides for the encoding (#encode64, #strict_encode64,
+# #urlsafe_encode64) and decoding (#decode64, #strict_decode64,
+# #urlsafe_decode64) of binary data using a Base64 representation.
+#
+# == Example
+#
+# A simple encoding and decoding.
+#
+# require "base64"
+#
+# enc = Base64.encode64('Send reinforcements')
+# # -> "U2VuZCByZWluZm9yY2VtZW50cw==\n"
+# plain = Base64.decode64(enc)
+# # -> "Send reinforcements"
+#
+# The purpose of using base64 to encode data is that it translates any
+# binary data into purely printable characters.
+
+module Base64
+ module_function
+
+ # Returns the Base64-encoded version of +bin+.
+ # This method complies with RFC 2045.
+ # Line feeds are added to every 60 encoded characters.
+ #
+ # require 'base64'
+ # Base64.encode64("Now is the time for all good coders\nto learn Ruby")
+ #
+ # <i>Generates:</i>
+ #
+ # Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g
+ # UnVieQ==
+ def encode64(bin)
+ [bin].pack("m")
+ end
+
+ # Returns the Base64-decoded version of +str+.
+ # This method complies with RFC 2045.
+ # Characters outside the base alphabet are ignored.
+ #
+ # require 'base64'
+ # str = 'VGhpcyBpcyBsaW5lIG9uZQpUaGlzIG' +
+ # 'lzIGxpbmUgdHdvClRoaXMgaXMgbGlu' +
+ # 'ZSB0aHJlZQpBbmQgc28gb24uLi4K'
+ # puts Base64.decode64(str)
+ #
+ # <i>Generates:</i>
+ #
+ # This is line one
+ # This is line two
+ # This is line three
+ # And so on...
+ def decode64(str)
+ str.unpack1("m")
+ end
+
+ # Returns the Base64-encoded version of +bin+.
+ # This method complies with RFC 4648.
+ # No line feeds are added.
+ def strict_encode64(bin)
+ [bin].pack("m0")
+ end
+
+ # Returns the Base64-decoded version of +str+.
+ # This method complies with RFC 4648.
+ # ArgumentError is raised if +str+ is incorrectly padded or contains
+ # non-alphabet characters. Note that CR or LF are also rejected.
+ def strict_decode64(str)
+ str.unpack1("m0")
+ end
+
+ # Returns the Base64-encoded version of +bin+.
+ # This method complies with ``Base 64 Encoding with URL and Filename Safe
+ # Alphabet'' in RFC 4648.
+ # The alphabet uses '-' instead of '+' and '_' instead of '/'.
+ # Note that the result can still contain '='.
+ # You can remove the padding by setting +padding+ as false.
+ def urlsafe_encode64(bin, padding: true)
+ str = strict_encode64(bin)
+ str.chomp!("==") or str.chomp!("=") unless padding
+ str.tr!("+/", "-_")
+ str
+ end
+
+ # Returns the Base64-decoded version of +str+.
+ # This method complies with ``Base 64 Encoding with URL and Filename Safe
+ # Alphabet'' in RFC 4648.
+ # The alphabet uses '-' instead of '+' and '_' instead of '/'.
+ #
+ # The padding character is optional.
+ # This method accepts both correctly-padded and unpadded input.
+ # Note that it still rejects incorrectly-padded input.
+ def urlsafe_decode64(str)
+ # NOTE: RFC 4648 does say nothing about unpadded input, but says that
+ # "the excess pad characters MAY also be ignored", so it is inferred that
+ # unpadded input is also acceptable.
+ if !str.end_with?("=") && str.length % 4 != 0
+ str = str.ljust((str.length + 3) & ~3, "=")
+ str.tr!("-_", "+/")
+ else
+ str = str.tr("-_", "+/")
+ end
+ strict_decode64(str)
+ end
+end
diff --git a/lib/benchmark.gemspec b/lib/benchmark.gemspec
deleted file mode 100644
index 35deff8d18..0000000000
--- a/lib/benchmark.gemspec
+++ /dev/null
@@ -1,32 +0,0 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{a performance benchmarking library}
- spec.description = spec.summary
- spec.homepage = "https://github.com/ruby/benchmark"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.required_ruby_version = ">= 2.1.0"
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
-
- # Specify which files should be added to the gem when it is released.
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.bindir = "exe"
- spec.executables = []
- spec.require_paths = ["lib"]
-end
diff --git a/lib/benchmark.rb b/lib/benchmark.rb
index 5072bdc2f3..79c782e262 100644
--- a/lib/benchmark.rb
+++ b/lib/benchmark.rb
@@ -121,8 +121,6 @@
module Benchmark
- VERSION = "0.3.0"
-
BENCHMARK_VERSION = "2002-04-25" # :nodoc:
# Invokes the block with a Benchmark::Report object, which
@@ -307,10 +305,6 @@ module Benchmark
#
# Returns the elapsed real time used to execute the given block.
- # The unit of time is seconds.
- #
- # Benchmark.realtime { "a" * 1_000_000_000 }
- # #=> 0.5098029999935534
#
def realtime # :yield:
r0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
diff --git a/lib/benchmark/benchmark.gemspec b/lib/benchmark/benchmark.gemspec
new file mode 100644
index 0000000000..58b47d95e1
--- /dev/null
+++ b/lib/benchmark/benchmark.gemspec
@@ -0,0 +1,29 @@
+begin
+ require_relative "lib/benchmark/version"
+rescue LoadError # Fallback to load version file in ruby core repository
+ require_relative "version"
+end
+
+Gem::Specification.new do |spec|
+ spec.name = "benchmark"
+ spec.version = Benchmark::VERSION
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{a performance benchmarking library}
+ spec.description = spec.summary
+ spec.homepage = "https://github.com/ruby/benchmark"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = []
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/benchmark/version.rb b/lib/benchmark/version.rb
new file mode 100644
index 0000000000..645966fd80
--- /dev/null
+++ b/lib/benchmark/version.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+module Benchmark
+ VERSION = "0.2.1"
+end
diff --git a/lib/bundled_gems.rb b/lib/bundled_gems.rb
deleted file mode 100644
index 38057cf6c5..0000000000
--- a/lib/bundled_gems.rb
+++ /dev/null
@@ -1,273 +0,0 @@
-# -*- frozen-string-literal: true -*-
-
-# :stopdoc:
-
-module Gem::BUNDLED_GEMS
- SINCE = {
- "matrix" => "3.1.0",
- "net-ftp" => "3.1.0",
- "net-imap" => "3.1.0",
- "net-pop" => "3.1.0",
- "net-smtp" => "3.1.0",
- "prime" => "3.1.0",
- "racc" => "3.3.0",
- "abbrev" => "3.4.0",
- "base64" => "3.4.0",
- "bigdecimal" => "3.4.0",
- "csv" => "3.4.0",
- "drb" => "3.4.0",
- "getoptlong" => "3.4.0",
- "mutex_m" => "3.4.0",
- "nkf" => "3.4.0",
- "observer" => "3.4.0",
- "resolv-replace" => "3.4.0",
- "rinda" => "3.4.0",
- "syslog" => "3.4.0",
- "ostruct" => "3.5.0",
- "pstore" => "3.5.0",
- "rdoc" => "3.5.0",
- "win32ole" => "3.5.0",
- "fiddle" => "3.5.0",
- "logger" => "3.5.0",
- "benchmark" => "3.5.0",
- "irb" => "3.5.0",
- "reline" => "3.5.0",
- # "readline" => "3.5.0", # This is wrapper for reline. We don't warn for this.
- }.freeze
-
- SINCE_FAST_PATH = SINCE.transform_keys { |g| g.sub(/\A.*\-/, "") }.freeze
-
- EXACT = {
- "kconv" => "nkf",
- }.freeze
-
- PREFIXED = {
- "bigdecimal" => true,
- "csv" => true,
- "drb" => true,
- "rinda" => true,
- "syslog" => true,
- }.freeze
-
- OPTIONAL = {
- "fiddle" => true,
- }.freeze
-
- WARNED = {} # unfrozen
-
- conf = ::RbConfig::CONFIG
- LIBDIR = (conf["rubylibdir"] + "/").freeze
- ARCHDIR = (conf["rubyarchdir"] + "/").freeze
- dlext = [conf["DLEXT"], "so"].uniq
- DLEXT = /\.#{Regexp.union(dlext)}\z/
- LIBEXT = /\.#{Regexp.union("rb", *dlext)}\z/
-
- def self.replace_require(specs)
- return if [::Kernel.singleton_class, ::Kernel].any? {|klass| klass.respond_to?(:no_warning_require) }
-
- spec_names = specs.to_a.each_with_object({}) {|spec, h| h[spec.name] = true }
-
- [::Kernel.singleton_class, ::Kernel].each do |kernel_class|
- kernel_class.send(:alias_method, :no_warning_require, :require)
- kernel_class.send(:define_method, :require) do |name|
-
- message = ::Gem::BUNDLED_GEMS.warning?(name, specs: spec_names)
- begin
- result = kernel_class.send(:no_warning_require, name)
- rescue LoadError => e
- result = e
- end
-
- # Don't warn if the gem is optional dependency and not found in the Bundler environment.
- if !(result.is_a?(LoadError) && OPTIONAL[name]) && message
- if ::Gem::BUNDLED_GEMS.uplevel > 0
- Kernel.warn message, uplevel: ::Gem::BUNDLED_GEMS.uplevel
- else
- Kernel.warn message
- end
- end
-
- if result.is_a?(LoadError)
- raise result
- else
- result
- end
- end
-
- if kernel_class == ::Kernel
- kernel_class.send(:private, :require)
- else
- kernel_class.send(:public, :require)
- end
- end
- end
-
- def self.uplevel
- frame_count = 0
- frames_to_skip = 3
- uplevel = 0
- require_found = false
- Thread.each_caller_location do |cl|
- frame_count += 1
- if frames_to_skip >= 1
- frames_to_skip -= 1
- next
- end
- uplevel += 1
- if require_found
- if cl.base_label != "require"
- return uplevel
- end
- else
- if cl.base_label == "require"
- require_found = true
- end
- end
- # Don't show script name when bundle exec and call ruby script directly.
- if cl.path.end_with?("bundle")
- frame_count = 0
- break
- end
- end
- require_found ? 1 : frame_count - 1
- end
-
- def self.find_gem(path)
- if !path
- return
- elsif path.start_with?(ARCHDIR)
- n = path.delete_prefix(ARCHDIR).sub(DLEXT, "")
- elsif path.start_with?(LIBDIR)
- n = path.delete_prefix(LIBDIR).chomp(".rb")
- else
- return
- end
- (EXACT[n] || !!SINCE[n]) or PREFIXED[n = n[%r[\A[^/]+(?=/)]]] && n
- end
-
- def self.warning?(name, specs: nil)
- # name can be a feature name or a file path with String or Pathname
- feature = File.path(name)
-
- # irb already has reline as a dependency on gemspec, so we don't want to warn about it.
- # We should update this with a more general solution when we have another case.
- # ex: Gem.loaded_specs[called_gem].dependencies.any? {|d| d.name == feature }
- return false if feature.start_with?("reline") && caller_locations(2, 1)[0].to_s.include?("irb")
-
- # The actual checks needed to properly identify the gem being required
- # are costly (see [Bug #20641]), so we first do a much cheaper check
- # to exclude the vast majority of candidates.
- if feature.include?("/")
- # If requiring $LIBDIR/mutex_m.rb, we check SINCE_FAST_PATH["mutex_m"]
- # We'll fail to warn requires for files that are not the entry point
- # of the gem, e.g. require "logger/formatter.rb" won't warn.
- # But that's acceptable because this warning is best effort,
- # and in the overwhelming majority of cases logger.rb will end
- # up required.
- return unless SINCE_FAST_PATH[File.basename(feature, ".*")]
- else
- return unless SINCE_FAST_PATH[feature]
- end
-
- # bootsnap expands `require "csv"` to `require "#{LIBDIR}/csv.rb"`,
- # and `require "syslog"` to `require "#{ARCHDIR}/syslog.so"`.
- name = feature.delete_prefix(ARCHDIR)
- name.delete_prefix!(LIBDIR)
- name.tr!("/", "-")
- name.sub!(LIBEXT, "")
- return if specs.include?(name)
- _t, path = $:.resolve_feature_path(feature)
- if gem = find_gem(path)
- return if specs.include?(gem)
- caller = caller_locations(3, 3)&.find {|c| c&.absolute_path}
- return if find_gem(caller&.absolute_path)
- elsif SINCE[name] && !path
- gem = true
- else
- return
- end
-
- return if WARNED[name]
- WARNED[name] = true
- if gem == true
- gem = name
- "#{feature} was loaded from the standard library, but"
- elsif gem
- return if WARNED[gem]
- WARNED[gem] = true
- "#{feature} is found in #{gem}, which"
- else
- return
- end + build_message(gem)
- end
-
- def self.build_message(gem)
- msg = " #{RUBY_VERSION < SINCE[gem] ? "will no longer be" : "is not"} part of the default gems starting from Ruby #{SINCE[gem]}."
-
- if defined?(Bundler)
- msg += "\nYou can add #{gem} to your Gemfile or gemspec to silence this warning."
-
- # We detect the gem name from caller_locations. First we walk until we find `require`
- # then take the first frame that's not from `require`.
- #
- # Additionally, we need to skip Bootsnap and Zeitwerk if present, these
- # gems decorate Kernel#require, so they are not really the ones issuing
- # the require call users should be warned about. Those are upwards.
- frames_to_skip = 3
- location = nil
- require_found = false
- Thread.each_caller_location do |cl|
- if frames_to_skip >= 1
- frames_to_skip -= 1
- next
- end
-
- if require_found
- if cl.base_label != "require"
- location = cl.path
- break
- end
- else
- if cl.base_label == "require"
- require_found = true
- end
- end
- end
-
- if location && File.file?(location) && !location.start_with?(Gem::BUNDLED_GEMS::LIBDIR)
- caller_gem = nil
- Gem.path.each do |path|
- if location =~ %r{#{path}/gems/([\w\-\.]+)}
- caller_gem = $1
- break
- end
- end
- if caller_gem
- msg += "\nAlso please contact the author of #{caller_gem} to request adding #{gem} into its gemspec."
- end
- end
- else
- msg += " Install #{gem} from RubyGems."
- end
-
- msg
- end
-
- freeze
-end
-
-# for RubyGems without Bundler environment.
-# If loading library is not part of the default gems and the bundled gems, warn it.
-class LoadError
- def message
- return super unless path
-
- name = path.tr("/", "-")
- if !defined?(Bundler) && Gem::BUNDLED_GEMS::SINCE[name] && !Gem::BUNDLED_GEMS::WARNED[name]
- warn name + Gem::BUNDLED_GEMS.build_message(name), uplevel: Gem::BUNDLED_GEMS.uplevel
- end
- super
- end
-end
-
-# :startdoc:
diff --git a/lib/bundler.rb b/lib/bundler.rb
index a195405fd9..f83268e9cd 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -17,7 +17,7 @@ require_relative "bundler/build_metadata"
# Bundler provides a consistent environment for Ruby projects by
# tracking and installing the exact gems and versions that are needed.
#
-# Bundler is a part of Ruby's standard library.
+# Since Ruby 2.6, Bundler is a part of Ruby's standard library.
#
# Bundler is used by creating _gemfiles_ listing all the project dependencies
# and (optionally) their versions and then using
@@ -39,10 +39,6 @@ module Bundler
environment_preserver.replace_with_backup
SUDO_MUTEX = Thread::Mutex.new
- autoload :Checksum, File.expand_path("bundler/checksum", __dir__)
- autoload :CLI, File.expand_path("bundler/cli", __dir__)
- autoload :CIDetector, File.expand_path("bundler/ci_detector", __dir__)
- autoload :CompactIndexClient, File.expand_path("bundler/compact_index_client", __dir__)
autoload :Definition, File.expand_path("bundler/definition", __dir__)
autoload :Dependency, File.expand_path("bundler/dependency", __dir__)
autoload :Deprecate, File.expand_path("bundler/deprecate", __dir__)
@@ -102,7 +98,9 @@ module Bundler
end
def create_bundle_path
- mkdir_p(bundle_path) unless bundle_path.exist?
+ SharedHelpers.filesystem_access(bundle_path.to_s) do |p|
+ mkdir_p(p)
+ end unless bundle_path.exist?
@bundle_path = bundle_path.realpath
rescue Errno::EEXIST
@@ -119,7 +117,7 @@ module Bundler
@bin_path ||= begin
path = settings[:bin] || "bin"
path = Pathname.new(path).expand_path(root).expand_path
- mkdir_p(path)
+ SharedHelpers.filesystem_access(path) {|p| FileUtils.mkdir_p(p) }
path
end
end
@@ -167,29 +165,6 @@ module Bundler
end
end
- def auto_switch
- self_manager.restart_with_locked_bundler_if_needed
- end
-
- # Automatically install dependencies if Bundler.settings[:auto_install] exists.
- # This is set through config cmd `bundle config set --global auto_install 1`.
- #
- # Note that this method `nil`s out the global Definition object, so it
- # should be called first, before you instantiate anything like an
- # `Installer` that'll keep a reference to the old one instead.
- def auto_install
- return unless settings[:auto_install]
-
- begin
- definition.specs
- rescue GemNotFound, GitError
- ui.info "Automatically installing missing gems."
- reset!
- CLI::Install.new({}).run
- reset!
- end
- end
-
# Setups Bundler environment (see Bundler.setup) if it is not already set,
# and loads all gems from groups specified. Unlike ::setup, can be called
# multiple times with different groups (if they were allowed by setup).
@@ -209,7 +184,6 @@ module Bundler
# Bundler.require(:test) # requires second_gem
#
def require(*groups)
- load_plugins
setup(*groups).require(*groups)
end
@@ -218,7 +192,7 @@ module Bundler
end
def environment
- SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load", print_caller_location: true
+ SharedHelpers.major_deprecation 2, "Bundler.environment has been removed in favor of Bundler.load", :print_caller_location => true
load
end
@@ -226,13 +200,12 @@ module Bundler
#
# @param unlock [Hash, Boolean, nil] Gems that have been requested
# to be updated or true if all gems should be updated
- # @param lockfile [Pathname] Path to Gemfile.lock
# @return [Bundler::Definition]
- def definition(unlock = nil, lockfile = default_lockfile)
+ def definition(unlock = nil)
@definition = nil if unlock
@definition ||= begin
configure
- Definition.build(default_gemfile, lockfile, unlock)
+ Definition.build(default_gemfile, default_lockfile, unlock)
end
end
@@ -357,12 +330,20 @@ module Bundler
def rm_rf(path)
FileUtils.remove_entry_secure(path) if path && File.exist?(path)
+ rescue ArgumentError
+ message = <<EOF
+It is a security vulnerability to allow your home directory to be world-writable, and bundler cannot continue.
+You should probably consider fixing this issue by running `chmod o-w ~` on *nix.
+Please refer to https://ruby-doc.org/stdlib-3.1.2/libdoc/fileutils/rdoc/FileUtils.html#method-c-remove_entry_secure for details.
+EOF
+ File.world_writable?(path) ? Bundler.ui.warn(message) : raise
+ raise PathError, "Please fix the world-writable issue with your #{path} directory"
end
def settings
@settings ||= Settings.new(app_config_path)
rescue GemfileNotFound
- @settings = Settings.new
+ @settings = Settings.new(Pathname.new(".bundle").expand_path)
end
# @return [Hash] Environment present before Bundler was activated
@@ -372,24 +353,40 @@ module Bundler
# @deprecated Use `unbundled_env` instead
def clean_env
- message =
+ Bundler::SharedHelpers.major_deprecation(
+ 2,
"`Bundler.clean_env` has been deprecated in favor of `Bundler.unbundled_env`. " \
- "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`"
- removed_message =
- "`Bundler.clean_env` has been removed in favor of `Bundler.unbundled_env`. " \
- "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`"
- Bundler::SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true)
+ "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`",
+ :print_caller_location => true
+ )
+
unbundled_env
end
# @return [Hash] Environment with all bundler-related variables removed
def unbundled_env
- unbundle_env(original_env)
- end
+ env = original_env
+
+ if env.key?("BUNDLER_ORIG_MANPATH")
+ env["MANPATH"] = env["BUNDLER_ORIG_MANPATH"]
+ end
+
+ env.delete_if {|k, _| k[0, 7] == "BUNDLE_" }
+
+ if env.key?("RUBYOPT")
+ rubyopt = env["RUBYOPT"].split(" ")
+ rubyopt.delete("-r#{File.expand_path("bundler/setup", __dir__)}")
+ rubyopt.delete("-rbundler/setup")
+ env["RUBYOPT"] = rubyopt.join(" ")
+ end
- # Remove all bundler-related variables from ENV
- def unbundle_env!
- ENV.replace(unbundle_env(ENV))
+ if env.key?("RUBYLIB")
+ rubylib = env["RUBYLIB"].split(File::PATH_SEPARATOR)
+ rubylib.delete(__dir__)
+ env["RUBYLIB"] = rubylib.join(File::PATH_SEPARATOR)
+ end
+
+ env
end
# Run block with environment present before Bundler was activated
@@ -399,13 +396,13 @@ module Bundler
# @deprecated Use `with_unbundled_env` instead
def with_clean_env
- message =
+ Bundler::SharedHelpers.major_deprecation(
+ 2,
"`Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. " \
- "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`"
- removed_message =
- "`Bundler.with_clean_env` has been removed in favor of `Bundler.with_unbundled_env`. " \
- "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`"
- Bundler::SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true)
+ "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`",
+ :print_caller_location => true
+ )
+
with_env(unbundled_env) { yield }
end
@@ -421,13 +418,13 @@ module Bundler
# @deprecated Use `unbundled_system` instead
def clean_system(*args)
- message =
+ Bundler::SharedHelpers.major_deprecation(
+ 2,
"`Bundler.clean_system` has been deprecated in favor of `Bundler.unbundled_system`. " \
- "If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system`"
- removed_message =
- "`Bundler.clean_system` has been removed in favor of `Bundler.unbundled_system`. " \
- "If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system`"
- Bundler::SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true)
+ "If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system`",
+ :print_caller_location => true
+ )
+
with_env(unbundled_env) { Kernel.system(*args) }
end
@@ -443,13 +440,13 @@ module Bundler
# @deprecated Use `unbundled_exec` instead
def clean_exec(*args)
- message =
+ Bundler::SharedHelpers.major_deprecation(
+ 2,
"`Bundler.clean_exec` has been deprecated in favor of `Bundler.unbundled_exec`. " \
- "If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec`"
- removed_message =
- "`Bundler.clean_exec` has been removed in favor of `Bundler.unbundled_exec`. " \
- "If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec`"
- Bundler::SharedHelpers.major_deprecation(2, message, removed_message: removed_message, print_caller_location: true)
+ "If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec`",
+ :print_caller_location => true
+ )
+
with_env(unbundled_env) { Kernel.exec(*args) }
end
@@ -492,7 +489,7 @@ module Bundler
configured_bundle_path.use_system_gems?
end
- def mkdir_p(path)
+ def mkdir_p(path, options = {})
SharedHelpers.filesystem_access(path, :write) do |p|
FileUtils.mkdir_p(p)
end
@@ -518,16 +515,7 @@ module Bundler
end
def safe_load_marshal(data)
- if Gem.respond_to?(:load_safe_marshal)
- Gem.load_safe_marshal
- begin
- Gem::SafeMarshal.safe_load(data)
- rescue Gem::SafeMarshal::Reader::Error, Gem::SafeMarshal::Visitors::ToRuby::Error => e
- raise MarshalError, "#{e.class}: #{e.message}"
- end
- else
- load_marshal(data, marshal_proc: SafeMarshal.proc)
- end
+ load_marshal(data, :marshal_proc => SafeMarshal.proc)
end
def load_gemspec(file, validate = false)
@@ -570,23 +558,6 @@ module Bundler
@feature_flag ||= FeatureFlag.new(VERSION)
end
- def load_plugins(definition = Bundler.definition)
- return if defined?(@load_plugins_ran)
-
- Bundler.rubygems.load_plugins
-
- requested_path_gems = definition.requested_specs.select {|s| s.source.is_a?(Source::Path) }
- path_plugin_files = requested_path_gems.map do |spec|
- spec.matches_for_glob("rubygems_plugin#{Bundler.rubygems.suffix_pattern}")
- rescue TypeError
- error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
- raise Gem::InvalidSpecificationException, error_message
- end.flatten
- Bundler.rubygems.load_plugin_files(path_plugin_files)
- Bundler.rubygems.load_env_plugins
- @load_plugins_ran = true
- end
-
def reset!
reset_paths!
Plugin.reset!
@@ -635,30 +606,6 @@ module Bundler
private
- def unbundle_env(env)
- if env.key?("BUNDLER_ORIG_MANPATH")
- env["MANPATH"] = env["BUNDLER_ORIG_MANPATH"]
- end
-
- env.delete_if {|k, _| k[0, 7] == "BUNDLE_" }
- env.delete("BUNDLER_SETUP")
-
- if env.key?("RUBYOPT")
- rubyopt = env["RUBYOPT"].split(" ")
- rubyopt.delete("-r#{File.expand_path("bundler/setup", __dir__)}")
- rubyopt.delete("-rbundler/setup")
- env["RUBYOPT"] = rubyopt.join(" ")
- end
-
- if env.key?("RUBYLIB")
- rubylib = env["RUBYLIB"].split(File::PATH_SEPARATOR)
- rubylib.delete(__dir__)
- env["RUBYLIB"] = rubylib.join(File::PATH_SEPARATOR)
- end
-
- env
- end
-
def load_marshal(data, marshal_proc: nil)
Marshal.load(data, marshal_proc)
rescue TypeError => e
@@ -678,7 +625,7 @@ module Bundler
rescue ScriptError, StandardError => e
msg = "There was an error while loading `#{path.basename}`: #{e.message}"
- raise GemspecError, Dsl::DSLError.new(msg, path.to_s, e.backtrace, contents)
+ raise GemspecError, Dsl::DSLError.new(msg, path, e.backtrace, contents)
end
def configure_gem_path
diff --git a/lib/bundler/build_metadata.rb b/lib/bundler/build_metadata.rb
index 5d2a8b53bb..8bffb2fae7 100644
--- a/lib/bundler/build_metadata.rb
+++ b/lib/bundler/build_metadata.rb
@@ -29,7 +29,7 @@ module Bundler
# commit instance variable then we can't determine its commits SHA.
git_dir = File.expand_path("../../../.git", __dir__)
if File.directory?(git_dir)
- return @git_commit_sha = IO.popen(%w[git rev-parse --short HEAD], { chdir: git_dir }, &:read).strip.freeze
+ return @git_commit_sha = Dir.chdir(git_dir) { `git rev-parse --short HEAD`.strip.freeze }
end
@git_commit_sha ||= "unknown"
diff --git a/lib/bundler/bundler.gemspec b/lib/bundler/bundler.gemspec
index 88411f295d..da50b46225 100644
--- a/lib/bundler/bundler.gemspec
+++ b/lib/bundler/bundler.gemspec
@@ -29,17 +29,15 @@ Gem::Specification.new do |s|
"source_code_uri" => "https://github.com/rubygems/rubygems/tree/master/bundler",
}
- s.required_ruby_version = ">= 3.1.0"
-
- # It should match the RubyGems version shipped with `required_ruby_version` above
- s.required_rubygems_version = ">= 3.3.3"
+ s.required_ruby_version = ">= 2.6.0"
+ s.required_rubygems_version = ">= 3.0.1"
s.files = Dir.glob("lib/bundler{.rb,/**/*}", File::FNM_DOTMATCH).reject {|f| File.directory?(f) }
# include the gemspec itself because warbler breaks w/o it
s.files += %w[lib/bundler/bundler.gemspec]
- s.bindir = "exe"
+ s.bindir = "libexec"
s.executables = %w[bundle bundler]
s.require_paths = ["lib"]
end
diff --git a/lib/bundler/capistrano.rb b/lib/bundler/capistrano.rb
index 705840143f..1f3712d48e 100644
--- a/lib/bundler/capistrano.rb
+++ b/lib/bundler/capistrano.rb
@@ -17,6 +17,6 @@ end
Capistrano::Configuration.instance(:must_exist).load do
before "deploy:finalize_update", "bundle:install"
- Bundler::Deployment.define_task(self, :task, except: { no_release: true })
+ Bundler::Deployment.define_task(self, :task, :except => { :no_release => true })
set :rake, lambda { "#{fetch(:bundle_cmd, "bundle")} exec rake" }
end
diff --git a/lib/bundler/checksum.rb b/lib/bundler/checksum.rb
deleted file mode 100644
index 60ba93417c..0000000000
--- a/lib/bundler/checksum.rb
+++ /dev/null
@@ -1,254 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- class Checksum
- ALGO_SEPARATOR = "="
- DEFAULT_ALGORITHM = "sha256"
- private_constant :DEFAULT_ALGORITHM
- DEFAULT_BLOCK_SIZE = 16_384
- private_constant :DEFAULT_BLOCK_SIZE
-
- class << self
- def from_gem_package(gem_package, algo = DEFAULT_ALGORITHM)
- return if Bundler.settings[:disable_checksum_validation]
- return unless source = gem_package.instance_variable_get(:@gem)
- return unless source.respond_to?(:with_read_io)
-
- source.with_read_io do |io|
- from_gem(io, source.path)
- ensure
- io.rewind
- end
- end
-
- def from_gem(io, pathname, algo = DEFAULT_ALGORITHM)
- digest = Bundler::SharedHelpers.digest(algo.upcase).new
- buf = String.new(capacity: DEFAULT_BLOCK_SIZE)
- digest << io.readpartial(DEFAULT_BLOCK_SIZE, buf) until io.eof?
- Checksum.new(algo, digest.hexdigest!, Source.new(:gem, pathname))
- end
-
- def from_api(digest, source_uri, algo = DEFAULT_ALGORITHM)
- return if Bundler.settings[:disable_checksum_validation]
-
- Checksum.new(algo, to_hexdigest(digest, algo), Source.new(:api, source_uri))
- end
-
- def from_lock(lock_checksum, lockfile_location)
- algo, digest = lock_checksum.strip.split(ALGO_SEPARATOR, 2)
- Checksum.new(algo, to_hexdigest(digest, algo), Source.new(:lock, lockfile_location))
- end
-
- def to_hexdigest(digest, algo = DEFAULT_ALGORITHM)
- return digest unless algo == DEFAULT_ALGORITHM
- return digest if digest.match?(/\A[0-9a-f]{64}\z/i)
-
- if digest.match?(%r{\A[-0-9a-z_+/]{43}={0,2}\z}i)
- digest = digest.tr("-_", "+/") # fix urlsafe base64
- digest.unpack1("m0").unpack1("H*")
- else
- raise ArgumentError, "#{digest.inspect} is not a valid SHA256 hex or base64 digest"
- end
- end
- end
-
- attr_reader :algo, :digest, :sources
-
- def initialize(algo, digest, source)
- @algo = algo
- @digest = digest
- @sources = [source]
- end
-
- def ==(other)
- match?(other) && other.sources == sources
- end
-
- alias_method :eql?, :==
-
- def same_source?(other)
- sources.include?(other.sources.first)
- end
-
- def match?(other)
- other.is_a?(self.class) && other.digest == digest && other.algo == algo
- end
-
- def hash
- digest.hash
- end
-
- def to_s
- "#{to_lock} (from #{sources.first}#{", ..." if sources.size > 1})"
- end
-
- def to_lock
- "#{algo}#{ALGO_SEPARATOR}#{digest}"
- end
-
- def merge!(other)
- return nil unless match?(other)
-
- @sources.concat(other.sources).uniq!
- self
- end
-
- def formatted_sources
- sources.join("\n and ").concat("\n")
- end
-
- def removable?
- sources.all?(&:removable?)
- end
-
- def removal_instructions
- msg = +""
- i = 1
- sources.each do |source|
- msg << " #{i}. #{source.removal}\n"
- i += 1
- end
- msg << " #{i}. run `bundle install`\n"
- end
-
- def inspect
- abbr = "#{algo}#{ALGO_SEPARATOR}#{digest[0, 8]}"
- from = "from #{sources.join(" and ")}"
- "#<#{self.class}:#{object_id} #{abbr} #{from}>"
- end
-
- class Source
- attr_reader :type, :location
-
- def initialize(type, location)
- @type = type
- @location = location
- end
-
- def removable?
- type == :lock || type == :gem
- end
-
- def ==(other)
- other.is_a?(self.class) && other.type == type && other.location == location
- end
-
- # phrased so that the usual string format is grammatically correct
- # rake (10.3.2) sha256=abc123 from #{to_s}
- def to_s
- case type
- when :lock
- "the lockfile CHECKSUMS at #{location}"
- when :gem
- "the gem at #{location}"
- when :api
- "the API at #{location}"
- else
- "#{location} (#{type})"
- end
- end
-
- # A full sentence describing how to remove the checksum
- def removal
- case type
- when :lock
- "remove the matching checksum in #{location}"
- when :gem
- "remove the gem at #{location}"
- when :api
- "checksums from #{location} cannot be locally modified, you may need to update your sources"
- else
- "remove #{location} (#{type})"
- end
- end
- end
-
- class Store
- attr_reader :store
- protected :store
-
- def initialize
- @store = {}
- @store_mutex = Mutex.new
- end
-
- def inspect
- "#<#{self.class}:#{object_id} size=#{store.size}>"
- end
-
- # Replace when the new checksum is from the same source.
- # The primary purpose is registering checksums from gems where there are
- # duplicates of the same gem (according to full_name) in the index.
- #
- # In particular, this is when 2 gems have two similar platforms, e.g.
- # "darwin20" and "darwin-20", both of which resolve to darwin-20.
- # In the Index, the later gem replaces the former, so we do that here.
- #
- # However, if the new checksum is from a different source, we register like normal.
- # This ensures a mismatch error where there are multiple top level sources
- # that contain the same gem with different checksums.
- def replace(spec, checksum)
- return unless checksum
-
- lock_name = spec.name_tuple.lock_name
- @store_mutex.synchronize do
- existing = fetch_checksum(lock_name, checksum.algo)
- if !existing || existing.same_source?(checksum)
- store_checksum(lock_name, checksum)
- else
- merge_checksum(lock_name, checksum, existing)
- end
- end
- end
-
- def register(spec, checksum)
- return unless checksum
-
- register_checksum(spec.name_tuple.lock_name, checksum)
- end
-
- def merge!(other)
- other.store.each do |lock_name, checksums|
- checksums.each do |_algo, checksum|
- register_checksum(lock_name, checksum)
- end
- end
- end
-
- def to_lock(spec)
- lock_name = spec.name_tuple.lock_name
- checksums = @store[lock_name]
- if checksums
- "#{lock_name} #{checksums.values.map(&:to_lock).sort.join(",")}"
- else
- lock_name
- end
- end
-
- private
-
- def register_checksum(lock_name, checksum)
- @store_mutex.synchronize do
- existing = fetch_checksum(lock_name, checksum.algo)
- if existing
- merge_checksum(lock_name, checksum, existing)
- else
- store_checksum(lock_name, checksum)
- end
- end
- end
-
- def merge_checksum(lock_name, checksum, existing)
- existing.merge!(checksum) || raise(ChecksumMismatchError.new(lock_name, existing, checksum))
- end
-
- def store_checksum(lock_name, checksum)
- (@store[lock_name] ||= {})[checksum.algo] = checksum
- end
-
- def fetch_checksum(lock_name, algo)
- @store[lock_name]&.fetch(algo, nil)
- end
- end
- end
-end
diff --git a/lib/bundler/ci_detector.rb b/lib/bundler/ci_detector.rb
deleted file mode 100644
index e5fedbdea8..0000000000
--- a/lib/bundler/ci_detector.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- module CIDetector
- # NOTE: Any changes made here will need to be made to both lib/rubygems/ci_detector.rb and
- # bundler/lib/bundler/ci_detector.rb (which are enforced duplicates).
- # TODO: Drop that duplication once bundler drops support for RubyGems 3.4
- #
- # ## Recognized CI providers, their signifiers, and the relevant docs ##
- #
- # Travis CI - CI, TRAVIS https://docs.travis-ci.com/user/environment-variables/#default-environment-variables
- # Cirrus CI - CI, CIRRUS_CI https://cirrus-ci.org/guide/writing-tasks/#environment-variables
- # Circle CI - CI, CIRCLECI https://circleci.com/docs/variables/#built-in-environment-variables
- # Gitlab CI - CI, GITLAB_CI https://docs.gitlab.com/ee/ci/variables/
- # AppVeyor - CI, APPVEYOR https://www.appveyor.com/docs/environment-variables/
- # CodeShip - CI_NAME https://docs.cloudbees.com/docs/cloudbees-codeship/latest/pro-builds-and-configuration/environment-variables#_default_environment_variables
- # dsari - CI, DSARI https://github.com/rfinnie/dsari#running
- # Jenkins - BUILD_NUMBER https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables
- # TeamCity - TEAMCITY_VERSION https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Predefined+Server+Build+Parameters
- # Appflow - CI_BUILD_ID https://ionic.io/docs/appflow/automation/environments#predefined-environments
- # TaskCluster - TASKCLUSTER_ROOT_URL https://docs.taskcluster.net/docs/manual/design/env-vars
- # Semaphore - CI, SEMAPHORE https://docs.semaphoreci.com/ci-cd-environment/environment-variables/
- # BuildKite - CI, BUILDKITE https://buildkite.com/docs/pipelines/environment-variables
- # GoCD - GO_SERVER_URL https://docs.gocd.org/current/faq/dev_use_current_revision_in_build.html
- # GH Actions - CI, GITHUB_ACTIONS https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
- #
- # ### Some "standard" ENVs that multiple providers may set ###
- #
- # * CI - this is set by _most_ (but not all) CI providers now; it's approaching a standard.
- # * CI_NAME - Not as frequently used, but some providers set this to specify their own name
-
- # Any of these being set is a reasonably reliable indicator that we are
- # executing in a CI environment.
- ENV_INDICATORS = [
- "CI",
- "CI_NAME",
- "CONTINUOUS_INTEGRATION",
- "BUILD_NUMBER",
- "CI_APP_ID",
- "CI_BUILD_ID",
- "CI_BUILD_NUMBER",
- "RUN_ID",
- "TASKCLUSTER_ROOT_URL",
- ].freeze
-
- # For each CI, this env suffices to indicate that we're on _that_ CI's
- # containers. (A few of them only supply a CI_NAME variable, which is also
- # nice). And if they set "CI" but we can't tell which one they are, we also
- # want to know that - a bare "ci" without another token tells us as much.
- ENV_DESCRIPTORS = {
- "TRAVIS" => "travis",
- "CIRCLECI" => "circle",
- "CIRRUS_CI" => "cirrus",
- "DSARI" => "dsari",
- "SEMAPHORE" => "semaphore",
- "JENKINS_URL" => "jenkins",
- "BUILDKITE" => "buildkite",
- "GO_SERVER_URL" => "go",
- "GITLAB_CI" => "gitlab",
- "GITHUB_ACTIONS" => "github",
- "TASKCLUSTER_ROOT_URL" => "taskcluster",
- "CI" => "ci",
- }.freeze
-
- def self.ci?
- ENV_INDICATORS.any? {|var| ENV.include?(var) }
- end
-
- def self.ci_strings
- matching_names = ENV_DESCRIPTORS.select {|env, _| ENV[env] }.values
- matching_names << ENV["CI_NAME"].downcase if ENV["CI_NAME"]
- matching_names.reject(&:empty?).sort.uniq
- end
- end
-end
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb
index 013ffcdeed..a3eb494db2 100644
--- a/lib/bundler/cli.rb
+++ b/lib/bundler/cli.rb
@@ -5,7 +5,6 @@ require_relative "vendored_thor"
module Bundler
class CLI < Thor
require_relative "cli/common"
- require_relative "cli/install"
package_name "Bundler"
@@ -65,12 +64,12 @@ module Bundler
Bundler.reset_settings_and_root!
end
- Bundler.auto_switch
+ Bundler.self_manager.restart_with_locked_bundler_if_needed
Bundler.settings.set_command_option_if_given :retry, options[:retry]
current_cmd = args.last[:current_command].name
- Bundler.auto_install if AUTO_INSTALL_CMDS.include?(current_cmd)
+ auto_install if AUTO_INSTALL_CMDS.include?(current_cmd)
rescue UnknownArgumentError => e
raise InvalidOption, e.message
ensure
@@ -81,10 +80,10 @@ module Bundler
unprinted_warnings.each {|w| Bundler.ui.warn(w) }
end
- check_unknown_options!(except: [:config, :exec])
+ check_unknown_options!(:except => [:config, :exec])
stop_on_unknown_option! :exec
- desc "cli_help", "Prints a summary of bundler commands", hide: true
+ desc "cli_help", "Prints a summary of bundler commands", :hide => true
def cli_help
version
Bundler.ui.info "\n"
@@ -100,23 +99,21 @@ module Bundler
shell.say "Bundler commands:\n\n"
shell.say " Primary commands:\n"
- shell.print_table(primary_commands, indent: 4, truncate: true)
+ shell.print_table(primary_commands, :indent => 4, :truncate => true)
shell.say
shell.say " Utilities:\n"
- shell.print_table(utilities, indent: 4, truncate: true)
+ shell.print_table(utilities, :indent => 4, :truncate => true)
shell.say
self.class.send(:class_options_help, shell)
end
default_task(Bundler.feature_flag.default_cli_command)
- class_option "no-color", type: :boolean, desc: "Disable colorization in output"
- class_option "retry", type: :numeric, aliases: "-r", banner: "NUM",
- desc: "Specify the number of times you wish to attempt network commands"
- class_option "verbose", type: :boolean, desc: "Enable verbose output mode", aliases: "-V"
+ class_option "no-color", :type => :boolean, :desc => "Disable colorization in output"
+ class_option "retry", :type => :numeric, :aliases => "-r", :banner => "NUM",
+ :desc => "Specify the number of times you wish to attempt network commands"
+ class_option "verbose", :type => :boolean, :desc => "Enable verbose output mode", :aliases => "-V"
def help(cli = nil)
- cli = self.class.all_aliases[cli] if self.class.all_aliases[cli]
-
case cli
when "gemfile" then command = "gemfile"
when nil then command = "bundle"
@@ -130,8 +127,8 @@ module Bundler
if man_pages.include?(command)
man_page = man_pages[command]
- if Bundler.which("man") && !man_path.match?(%r{^file:/.+!/META-INF/jruby.home/.+})
- Kernel.exec("man", man_page)
+ if Bundler.which("man") && man_path !~ %r{^file:/.+!/META-INF/jruby.home/.+}
+ Kernel.exec "man #{man_page}"
else
puts File.read("#{man_path}/#{File.basename(man_page)}.ronn")
end
@@ -158,8 +155,8 @@ module Bundler
Gemfile to a gem with a gemspec, the --gemspec option will automatically add each
dependency listed in the gemspec file to the newly created Gemfile.
D
- method_option "gemspec", type: :string, banner: "Use the specified .gemspec to create the Gemfile"
- method_option "gemfile", type: :string, banner: "Use the specified name for the gemfile instead of 'Gemfile'"
+ method_option "gemspec", :type => :string, :banner => "Use the specified .gemspec to create the Gemfile"
+ method_option "gemfile", :type => :string, :banner => "Use the specified name for the gemfile instead of 'Gemfile'"
def init
require_relative "cli/init"
Init.new(options.dup).run
@@ -171,9 +168,12 @@ module Bundler
all gems are found, Bundler prints a success message and exits with a status of 0.
If not, the first missing gem is listed and Bundler exits status 1.
D
- method_option "dry-run", type: :boolean, default: false, banner: "Lock the Gemfile"
- method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile"
- method_option "path", type: :string, banner: "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
+ method_option "dry-run", :type => :boolean, :default => false, :banner =>
+ "Lock the Gemfile"
+ method_option "gemfile", :type => :string, :banner =>
+ "Use the specified gemfile instead of Gemfile"
+ method_option "path", :type => :string, :banner =>
+ "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
def check
remembered_flag_deprecation("path")
@@ -187,14 +187,10 @@ module Bundler
long_desc <<-D
Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid. If the gem is not found, Bundler prints a error message and if gem could not be removed due to any reason Bundler will display a warning.
D
- method_option "install", type: :boolean, banner: "Runs 'bundle install' after removing the gems from the Gemfile"
+ method_option "install", :type => :boolean, :banner =>
+ "Runs 'bundle install' after removing the gems from the Gemfile"
def remove(*gems)
- if ARGV.include?("--install")
- message = "The `--install` flag has been deprecated. `bundle install` is triggered by default."
- removed_message = "The `--install` flag has been removed. `bundle install` is triggered by default."
- SharedHelpers.major_deprecation(2, message, removed_message: removed_message)
- end
-
+ SharedHelpers.major_deprecation(2, "The `--install` flag has been deprecated. `bundle install` is triggered by default.") if ARGV.include?("--install")
require_relative "cli/remove"
Remove.new(gems, options).run
end
@@ -210,42 +206,58 @@ module Bundler
If the bundle has already been installed, bundler will tell you so and then exit.
D
- method_option "binstubs", type: :string, lazy_default: "bin", banner: "Generate bin stubs for bundled gems to ./bin"
- method_option "clean", type: :boolean, banner: "Run bundle clean automatically after install"
- method_option "deployment", type: :boolean, banner: "Install using defaults tuned for deployment environments"
- method_option "frozen", type: :boolean, banner: "Do not allow the Gemfile.lock to be updated after this install"
- method_option "full-index", type: :boolean, banner: "Fall back to using the single-file index of all gems"
- method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile"
- method_option "jobs", aliases: "-j", type: :numeric, banner: "Specify the number of jobs to run in parallel"
- method_option "local", type: :boolean, banner: "Do not attempt to fetch gems remotely and use the gem cache instead"
- method_option "prefer-local", type: :boolean, banner: "Only attempt to fetch gems remotely if not present locally, even if newer versions are available remotely"
- method_option "no-cache", type: :boolean, banner: "Don't update the existing gem cache."
- method_option "redownload", type: :boolean, aliases: "--force", banner: "Force downloading every gem."
- method_option "no-prune", type: :boolean, banner: "Don't remove stale gems from the cache."
- method_option "path", type: :string, banner: "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
- method_option "quiet", type: :boolean, banner: "Only output warnings and errors."
- method_option "shebang", type: :string, banner: "Specify a different shebang executable name than the default (usually 'ruby')"
- method_option "standalone", type: :array, lazy_default: [], banner: "Make a bundle that can work without the Bundler runtime"
- method_option "system", type: :boolean, banner: "Install to the system location ($BUNDLE_PATH or $GEM_HOME) even if the bundle was previously installed somewhere else for this application"
- method_option "trust-policy", alias: "P", type: :string, banner: "Gem trust policy (like gem install -P). Must be one of " +
- Bundler.rubygems.security_policy_keys.join("|")
- method_option "target-rbconfig", type: :string, banner: "rbconfig.rb for the deployment target platform"
-
- method_option "without", type: :array, banner: "Exclude gems that are part of the specified named group."
- method_option "with", type: :array, banner: "Include gems that are part of the specified named group."
+ method_option "binstubs", :type => :string, :lazy_default => "bin", :banner =>
+ "Generate bin stubs for bundled gems to ./bin"
+ method_option "clean", :type => :boolean, :banner =>
+ "Run bundle clean automatically after install"
+ method_option "deployment", :type => :boolean, :banner =>
+ "Install using defaults tuned for deployment environments"
+ method_option "frozen", :type => :boolean, :banner =>
+ "Do not allow the Gemfile.lock to be updated after this install"
+ method_option "full-index", :type => :boolean, :banner =>
+ "Fall back to using the single-file index of all gems"
+ method_option "gemfile", :type => :string, :banner =>
+ "Use the specified gemfile instead of Gemfile"
+ method_option "jobs", :aliases => "-j", :type => :numeric, :banner =>
+ "Specify the number of jobs to run in parallel"
+ method_option "local", :type => :boolean, :banner =>
+ "Do not attempt to fetch gems remotely and use the gem cache instead"
+ method_option "prefer-local", :type => :boolean, :banner =>
+ "Only attempt to fetch gems remotely if not present locally, even if newer versions are available remotely"
+ method_option "no-cache", :type => :boolean, :banner =>
+ "Don't update the existing gem cache."
+ method_option "redownload", :type => :boolean, :aliases => "--force", :banner =>
+ "Force downloading every gem."
+ method_option "no-prune", :type => :boolean, :banner =>
+ "Don't remove stale gems from the cache."
+ method_option "path", :type => :string, :banner =>
+ "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
+ method_option "quiet", :type => :boolean, :banner =>
+ "Only output warnings and errors."
+ method_option "shebang", :type => :string, :banner =>
+ "Specify a different shebang executable name than the default (usually 'ruby')"
+ method_option "standalone", :type => :array, :lazy_default => [], :banner =>
+ "Make a bundle that can work without the Bundler runtime"
+ method_option "system", :type => :boolean, :banner =>
+ "Install to the system location ($BUNDLE_PATH or $GEM_HOME) even if the bundle was previously installed somewhere else for this application"
+ method_option "trust-policy", :alias => "P", :type => :string, :banner =>
+ "Gem trust policy (like gem install -P). Must be one of " +
+ Bundler.rubygems.security_policy_keys.join("|")
+ method_option "without", :type => :array, :banner =>
+ "Exclude gems that are part of the specified named group."
+ method_option "with", :type => :array, :banner =>
+ "Include gems that are part of the specified named group."
def install
SharedHelpers.major_deprecation(2, "The `--force` option has been renamed to `--redownload`") if ARGV.include?("--force")
- %w[clean deployment frozen no-prune path shebang without with].each do |option|
+ %w[clean deployment frozen no-prune path shebang system without with].each do |option|
remembered_flag_deprecation(option)
end
- print_remembered_flag_deprecation("--system", "path.system", "true") if ARGV.include?("--system")
-
remembered_negative_flag_deprecation("no-deployment")
require_relative "cli/install"
- Bundler.settings.temporary(no_install: false) do
+ Bundler.settings.temporary(:no_install => false) do
Install.new(options.dup).run
end
end
@@ -258,27 +270,44 @@ module Bundler
update when you have changed the Gemfile, or if you want to get the newest
possible versions of the gems in the bundle.
D
- method_option "full-index", type: :boolean, banner: "Fall back to using the single-file index of all gems"
- method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile"
- method_option "group", aliases: "-g", type: :array, banner: "Update a specific group"
- method_option "jobs", aliases: "-j", type: :numeric, banner: "Specify the number of jobs to run in parallel"
- method_option "local", type: :boolean, banner: "Do not attempt to fetch gems remotely and use the gem cache instead"
- method_option "quiet", type: :boolean, banner: "Only output warnings and errors."
- method_option "source", type: :array, banner: "Update a specific source (and all gems associated with it)"
- method_option "redownload", type: :boolean, aliases: "--force", banner: "Force downloading every gem."
- method_option "ruby", type: :boolean, banner: "Update ruby specified in Gemfile.lock"
- method_option "bundler", type: :string, lazy_default: "> 0.a", banner: "Update the locked version of bundler"
- method_option "patch", type: :boolean, banner: "Prefer updating only to next patch version"
- method_option "minor", type: :boolean, banner: "Prefer updating only to next minor version"
- method_option "major", type: :boolean, banner: "Prefer updating to next major version (default)"
- method_option "pre", type: :boolean, banner: "Always choose the highest allowed version when updating gems, regardless of prerelease status"
- method_option "strict", type: :boolean, banner: "Do not allow any gem to be updated past latest --patch | --minor | --major"
- method_option "conservative", type: :boolean, banner: "Use bundle install conservative update behavior and do not allow shared dependencies to be updated."
- method_option "all", type: :boolean, banner: "Update everything."
+ method_option "full-index", :type => :boolean, :banner =>
+ "Fall back to using the single-file index of all gems"
+ method_option "gemfile", :type => :string, :banner =>
+ "Use the specified gemfile instead of Gemfile"
+ method_option "group", :aliases => "-g", :type => :array, :banner =>
+ "Update a specific group"
+ method_option "jobs", :aliases => "-j", :type => :numeric, :banner =>
+ "Specify the number of jobs to run in parallel"
+ method_option "local", :type => :boolean, :banner =>
+ "Do not attempt to fetch gems remotely and use the gem cache instead"
+ method_option "quiet", :type => :boolean, :banner =>
+ "Only output warnings and errors."
+ method_option "source", :type => :array, :banner =>
+ "Update a specific source (and all gems associated with it)"
+ method_option "redownload", :type => :boolean, :aliases => "--force", :banner =>
+ "Force downloading every gem."
+ method_option "ruby", :type => :boolean, :banner =>
+ "Update ruby specified in Gemfile.lock"
+ method_option "bundler", :type => :string, :lazy_default => "> 0.a", :banner =>
+ "Update the locked version of bundler"
+ method_option "patch", :type => :boolean, :banner =>
+ "Prefer updating only to next patch version"
+ method_option "minor", :type => :boolean, :banner =>
+ "Prefer updating only to next minor version"
+ method_option "major", :type => :boolean, :banner =>
+ "Prefer updating to next major version (default)"
+ method_option "pre", :type => :boolean, :banner =>
+ "Always choose the highest allowed version when updating gems, regardless of prerelease status"
+ method_option "strict", :type => :boolean, :banner =>
+ "Do not allow any gem to be updated past latest --patch | --minor | --major"
+ method_option "conservative", :type => :boolean, :banner =>
+ "Use bundle install conservative update behavior and do not allow shared dependencies to be updated."
+ method_option "all", :type => :boolean, :banner =>
+ "Update everything."
def update(*gems)
SharedHelpers.major_deprecation(2, "The `--force` option has been renamed to `--redownload`") if ARGV.include?("--force")
require_relative "cli/update"
- Bundler.settings.temporary(no_install: false) do
+ Bundler.settings.temporary(:no_install => false) do
Update.new(options, gems).run
end
end
@@ -288,25 +317,21 @@ module Bundler
Show lists the names and versions of all gems that are required by your Gemfile.
Calling show with [GEM] will list the exact location of that gem on your machine.
D
- method_option "paths", type: :boolean,
- banner: "List the paths of all gems that are required by your Gemfile."
- method_option "outdated", type: :boolean,
- banner: "Show verbose output including whether gems are outdated."
+ method_option "paths", :type => :boolean,
+ :banner => "List the paths of all gems that are required by your Gemfile."
+ method_option "outdated", :type => :boolean,
+ :banner => "Show verbose output including whether gems are outdated."
def show(gem_name = nil)
- if ARGV.include?("--outdated")
- message = "the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement"
- removed_message = "the `--outdated` flag to `bundle show` was undocumented and has been removed without replacement"
- SharedHelpers.major_deprecation(2, message, removed_message: removed_message)
- end
+ SharedHelpers.major_deprecation(2, "the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement") if ARGV.include?("--outdated")
require_relative "cli/show"
Show.new(options, gem_name).run
end
desc "list", "List all gems in the bundle"
- method_option "name-only", type: :boolean, banner: "print only the gem names"
- method_option "only-group", type: :array, default: [], banner: "print gems from a given set of groups"
- method_option "without-group", type: :array, default: [], banner: "print all gems except from a given set of groups"
- method_option "paths", type: :boolean, banner: "print the path to each gem in the bundle"
+ method_option "name-only", :type => :boolean, :banner => "print only the gem names"
+ method_option "only-group", :type => :array, :default => [], :banner => "print gems from a given set of groups"
+ method_option "without-group", :type => :array, :default => [], :banner => "print all gems except from a given set of groups"
+ method_option "paths", :type => :boolean, :banner => "print the path to each gem in the bundle"
def list
require_relative "cli/list"
List.new(options).run
@@ -315,8 +340,8 @@ module Bundler
map aliases_for("list")
desc "info GEM [OPTIONS]", "Show information for the given gem"
- method_option "path", type: :boolean, banner: "Print full path to gem"
- method_option "version", type: :boolean, banner: "Print gem version"
+ method_option "path", :type => :boolean, :banner => "Print full path to gem"
+ method_option "version", :type => :boolean, :banner => "Print gem version"
def info(gem_name)
require_relative "cli/info"
Info.new(options, gem_name).run
@@ -328,12 +353,18 @@ module Bundler
or the --binstubs directory if one has been set. Calling binstubs with [GEM [GEM]]
will create binstubs for all given gems.
D
- method_option "force", type: :boolean, default: false, banner: "Overwrite existing binstubs if they exist"
- method_option "path", type: :string, lazy_default: "bin", banner: "Binstub destination directory (default bin)"
- method_option "shebang", type: :string, banner: "Specify a different shebang executable name than the default (usually 'ruby')"
- method_option "standalone", type: :boolean, banner: "Make binstubs that can work without the Bundler runtime"
- method_option "all", type: :boolean, banner: "Install binstubs for all gems"
- method_option "all-platforms", type: :boolean, default: false, banner: "Install binstubs for all platforms"
+ method_option "force", :type => :boolean, :default => false, :banner =>
+ "Overwrite existing binstubs if they exist"
+ method_option "path", :type => :string, :lazy_default => "bin", :banner =>
+ "Binstub destination directory (default bin)"
+ method_option "shebang", :type => :string, :banner =>
+ "Specify a different shebang executable name than the default (usually 'ruby')"
+ method_option "standalone", :type => :boolean, :banner =>
+ "Make binstubs that can work without the Bundler runtime"
+ method_option "all", :type => :boolean, :banner =>
+ "Install binstubs for all gems"
+ method_option "all-platforms", :type => :boolean, :default => false, :banner =>
+ "Install binstubs for all platforms"
def binstubs(*gems)
require_relative "cli/binstubs"
Binstubs.new(options, gems).run
@@ -343,19 +374,19 @@ module Bundler
long_desc <<-D
Adds the specified gem to Gemfile (if valid) and run 'bundle install' in one step.
D
- method_option "version", aliases: "-v", type: :string
- method_option "group", aliases: "-g", type: :string
- method_option "source", aliases: "-s", type: :string
- method_option "require", aliases: "-r", type: :string, banner: "Adds require path to gem. Provide false, or a path as a string."
- method_option "path", type: :string
- method_option "git", type: :string
- method_option "github", type: :string
- method_option "branch", type: :string
- method_option "ref", type: :string
- method_option "glob", type: :string, banner: "The location of a dependency's .gemspec, expanded within Ruby (single quotes recommended)"
- method_option "skip-install", type: :boolean, banner: "Adds gem to the Gemfile but does not install it"
- method_option "optimistic", type: :boolean, banner: "Adds optimistic declaration of version to gem"
- method_option "strict", type: :boolean, banner: "Adds strict declaration of version to gem"
+ method_option "version", :aliases => "-v", :type => :string
+ method_option "group", :aliases => "-g", :type => :string
+ method_option "source", :aliases => "-s", :type => :string
+ method_option "require", :aliases => "-r", :type => :string, :banner => "Adds require path to gem. Provide false, or a path as a string."
+ method_option "path", :type => :string
+ method_option "git", :type => :string
+ method_option "github", :type => :string
+ method_option "branch", :type => :string
+ method_option "ref", :type => :string
+ method_option "skip-install", :type => :boolean, :banner =>
+ "Adds gem to the Gemfile but does not install it"
+ method_option "optimistic", :type => :boolean, :banner => "Adds optimistic declaration of version to gem"
+ method_option "strict", :type => :boolean, :banner => "Adds strict declaration of version to gem"
def add(*gems)
require_relative "cli/add"
Add.new(options.dup, gems).run
@@ -371,45 +402,54 @@ module Bundler
For more information on patch level options (--major, --minor, --patch,
--strict) see documentation on the same options on the update command.
D
- method_option "group", type: :string, banner: "List gems from a specific group"
- method_option "groups", type: :boolean, banner: "List gems organized by groups"
- method_option "local", type: :boolean, banner: "Do not attempt to fetch gems remotely and use the gem cache instead"
- method_option "pre", type: :boolean, banner: "Check for newer pre-release gems"
- method_option "source", type: :array, banner: "Check against a specific source"
- method_option "filter-strict", type: :boolean, aliases: "--strict", banner: "Only list newer versions allowed by your Gemfile requirements"
- method_option "update-strict", type: :boolean, banner: "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major"
- method_option "minor", type: :boolean, banner: "Prefer updating only to next minor version"
- method_option "major", type: :boolean, banner: "Prefer updating to next major version (default)"
- method_option "patch", type: :boolean, banner: "Prefer updating only to next patch version"
- method_option "filter-major", type: :boolean, banner: "Only list major newer versions"
- method_option "filter-minor", type: :boolean, banner: "Only list minor newer versions"
- method_option "filter-patch", type: :boolean, banner: "Only list patch newer versions"
- method_option "parseable", aliases: "--porcelain", type: :boolean, banner: "Use minimal formatting for more parseable output"
- method_option "only-explicit", type: :boolean, banner: "Only list gems specified in your Gemfile, not their dependencies"
+ method_option "group", :type => :string, :banner => "List gems from a specific group"
+ method_option "groups", :type => :boolean, :banner => "List gems organized by groups"
+ method_option "local", :type => :boolean, :banner =>
+ "Do not attempt to fetch gems remotely and use the gem cache instead"
+ method_option "pre", :type => :boolean, :banner => "Check for newer pre-release gems"
+ method_option "source", :type => :array, :banner => "Check against a specific source"
+ method_option "filter-strict", :type => :boolean, :aliases => "--strict", :banner =>
+ "Only list newer versions allowed by your Gemfile requirements"
+ method_option "update-strict", :type => :boolean, :banner =>
+ "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major"
+ method_option "minor", :type => :boolean, :banner => "Prefer updating only to next minor version"
+ method_option "major", :type => :boolean, :banner => "Prefer updating to next major version (default)"
+ method_option "patch", :type => :boolean, :banner => "Prefer updating only to next patch version"
+ method_option "filter-major", :type => :boolean, :banner => "Only list major newer versions"
+ method_option "filter-minor", :type => :boolean, :banner => "Only list minor newer versions"
+ method_option "filter-patch", :type => :boolean, :banner => "Only list patch newer versions"
+ method_option "parseable", :aliases => "--porcelain", :type => :boolean, :banner =>
+ "Use minimal formatting for more parseable output"
+ method_option "only-explicit", :type => :boolean, :banner =>
+ "Only list gems specified in your Gemfile, not their dependencies"
def outdated(*gems)
require_relative "cli/outdated"
Outdated.new(options, gems).run
end
desc "fund [OPTIONS]", "Lists information about gems seeking funding assistance"
- method_option "group", aliases: "-g", type: :array, banner: "Fetch funding information for a specific group"
+ method_option "group", :aliases => "-g", :type => :array, :banner =>
+ "Fetch funding information for a specific group"
def fund
require_relative "cli/fund"
Fund.new(options).run
end
desc "cache [OPTIONS]", "Locks and then caches all of the gems into vendor/cache"
- method_option "all", type: :boolean,
- default: Bundler.feature_flag.cache_all?,
- banner: "Include all sources (including path and git)."
- method_option "all-platforms", type: :boolean, banner: "Include gems for all platforms present in the lockfile, not only the current one"
- method_option "cache-path", type: :string, banner: "Specify a different cache path than the default (vendor/cache)."
- method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile"
- method_option "no-install", type: :boolean, banner: "Don't install the gems, only update the cache."
- method_option "no-prune", type: :boolean, banner: "Don't remove stale gems from the cache."
- method_option "path", type: :string, banner: "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
- method_option "quiet", type: :boolean, banner: "Only output warnings and errors."
- method_option "frozen", type: :boolean, banner: "Do not allow the Gemfile.lock to be updated after this bundle cache operation's install"
+ method_option "all", :type => :boolean,
+ :default => Bundler.feature_flag.cache_all?,
+ :banner => "Include all sources (including path and git)."
+ method_option "all-platforms", :type => :boolean, :banner => "Include gems for all platforms present in the lockfile, not only the current one"
+ method_option "cache-path", :type => :string, :banner =>
+ "Specify a different cache path than the default (vendor/cache)."
+ method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile"
+ method_option "no-install", :type => :boolean, :banner => "Don't install the gems, only update the cache."
+ method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache."
+ method_option "path", :type => :string, :banner =>
+ "Specify a different path than the system default ($BUNDLE_PATH or $GEM_HOME).#{" Bundler will remember this value for future installs on this machine" unless Bundler.feature_flag.forget_cli_options?}"
+ method_option "quiet", :type => :boolean, :banner => "Only output warnings and errors."
+ method_option "frozen", :type => :boolean, :banner =>
+ "Do not allow the Gemfile.lock to be updated after this bundle cache operation's install"
long_desc <<-D
The cache command will copy the .gem files for every gem in the bundle into the
directory ./vendor/cache. If you then check that directory into your source
@@ -417,20 +457,17 @@ module Bundler
bundle without having to download any additional gems.
D
def cache
- print_remembered_flag_deprecation("--all", "cache_all", "true") if ARGV.include?("--all")
-
- if ARGV.include?("--path")
- message =
- "The `--path` flag is deprecated because its semantics are unclear. " \
- "Use `bundle config cache_path` to configure the path of your cache of gems, " \
- "and `bundle config path` to configure the path where your gems are installed, " \
- "and stop using this flag"
- removed_message =
- "The `--path` flag has been removed because its semantics were unclear. " \
- "Use `bundle config cache_path` to configure the path of your cache of gems, " \
- "and `bundle config path` to configure the path where your gems are installed."
- SharedHelpers.major_deprecation 2, message, removed_message: removed_message
- end
+ SharedHelpers.major_deprecation 2,
+ "The `--all` flag is deprecated because it relies on being " \
+ "remembered across bundler invocations, which bundler will no longer " \
+ "do in future versions. Instead please use `bundle config set cache_all true`, " \
+ "and stop using this flag" if ARGV.include?("--all")
+
+ SharedHelpers.major_deprecation 2,
+ "The `--path` flag is deprecated because its semantics are unclear. " \
+ "Use `bundle config cache_path` to configure the path of your cache of gems, " \
+ "and `bundle config path` to configure the path where your gems are installed, " \
+ "and stop using this flag" if ARGV.include?("--path")
require_relative "cli/cache"
Cache.new(options).run
@@ -439,8 +476,8 @@ module Bundler
map aliases_for("cache")
desc "exec [OPTIONS]", "Run the command in context of the bundle"
- method_option :keep_file_descriptors, type: :boolean, default: true
- method_option :gemfile, type: :string, required: false
+ method_option :keep_file_descriptors, :type => :boolean, :default => true
+ method_option :gemfile, :type => :string, :required => false
long_desc <<-D
Exec runs a command, providing it access to the gems in the bundle. While using
bundle exec you can require and call the bundled gems as if they were installed
@@ -448,9 +485,7 @@ module Bundler
D
def exec(*args)
if ARGV.include?("--no-keep-file-descriptors")
- message = "The `--no-keep-file-descriptors` has been deprecated. `bundle exec` no longer mess with your file descriptors. Close them in the exec'd script if you need to"
- removed_message = "The `--no-keep-file-descriptors` has been removed. `bundle exec` no longer mess with your file descriptors. Close them in the exec'd script if you need to"
- SharedHelpers.major_deprecation(2, message, removed_message: removed_message)
+ SharedHelpers.major_deprecation(2, "The `--no-keep-file-descriptors` has been deprecated. `bundle exec` no longer mess with your file descriptors. Close them in the exec'd script if you need to")
end
require_relative "cli/exec"
@@ -475,7 +510,7 @@ module Bundler
subcommand "config", Config
desc "open GEM", "Opens the source directory of the given bundled gem"
- method_option "path", type: :string, lazy_default: "", banner: "Open relative path of the gem source."
+ method_option "path", :type => :string, :lazy_default => "", :banner => "Open relative path of the gem source."
def open(name)
require_relative "cli/open"
Open.new(options, name).run
@@ -520,17 +555,17 @@ module Bundler
end
unless Bundler.feature_flag.bundler_3_mode?
- desc "viz [OPTIONS]", "Generates a visual dependency graph", hide: true
+ desc "viz [OPTIONS]", "Generates a visual dependency graph", :hide => true
long_desc <<-D
Viz generates a PNG file of the current Gemfile as a dependency graph.
Viz requires the ruby-graphviz gem (and its dependencies).
The associated gems must also be installed via 'bundle install'.
D
- method_option :file, type: :string, default: "gem_graph", aliases: "-f", desc: "The name to use for the generated file. see format option"
- method_option :format, type: :string, default: "png", aliases: "-F", desc: "This is output format option. Supported format is png, jpg, svg, dot ..."
- method_option :requirements, type: :boolean, default: false, aliases: "-R", desc: "Set to show the version of each required dependency."
- method_option :version, type: :boolean, default: false, aliases: "-v", desc: "Set to show each gem version."
- method_option :without, type: :array, default: [], aliases: "-W", banner: "GROUP[ GROUP...]", desc: "Exclude gems that are part of the specified named group."
+ method_option :file, :type => :string, :default => "gem_graph", :aliases => "-f", :desc => "The name to use for the generated file. see format option"
+ method_option :format, :type => :string, :default => "png", :aliases => "-F", :desc => "This is output format option. Supported format is png, jpg, svg, dot ..."
+ method_option :requirements, :type => :boolean, :default => false, :aliases => "-R", :desc => "Set to show the version of each required dependency."
+ method_option :version, :type => :boolean, :default => false, :aliases => "-v", :desc => "Set to show each gem version."
+ method_option :without, :type => :array, :default => [], :aliases => "-W", :banner => "GROUP[ GROUP...]", :desc => "Exclude gems that are part of the specified named group."
def viz
SharedHelpers.major_deprecation 2, "The `viz` command has been renamed to `graph` and moved to a plugin. See https://github.com/rubygems/bundler-graph"
require_relative "cli/viz"
@@ -541,26 +576,23 @@ module Bundler
old_gem = instance_method(:gem)
desc "gem NAME [OPTIONS]", "Creates a skeleton for creating a rubygem"
- method_option :exe, type: :boolean, default: false, aliases: ["--bin", "-b"], desc: "Generate a binary executable for your library."
- method_option :coc, type: :boolean, desc: "Generate a code of conduct file. Set a default with `bundle config set --global gem.coc true`."
- method_option :edit, type: :string, aliases: "-e", required: false, banner: "EDITOR",
- lazy_default: [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? },
- desc: "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)"
- method_option :ext, type: :string, desc: "Generate the boilerplate for C extension code.", enum: EXTENSIONS
- method_option :git, type: :boolean, default: true, desc: "Initialize a git repo inside your library."
- method_option :mit, type: :boolean, desc: "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`."
- method_option :rubocop, type: :boolean, desc: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`."
- method_option :changelog, type: :boolean, desc: "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`."
- method_option :test, type: :string, lazy_default: Bundler.settings["gem.test"] || "", aliases: "-t", banner: "Use the specified test framework for your library",
- enum: %w[rspec minitest test-unit],
- desc: "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`."
- method_option :ci, type: :string, lazy_default: Bundler.settings["gem.ci"] || "",
- enum: %w[github gitlab circle],
- desc: "Generate CI configuration, either GitHub Actions, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|gitlab|circle)`"
- method_option :linter, type: :string, lazy_default: Bundler.settings["gem.linter"] || "",
- enum: %w[rubocop standard],
- desc: "Add a linter and code formatter, either RuboCop or Standard. Set a default with `bundle config set --global gem.linter (rubocop|standard)`"
- method_option :github_username, type: :string, default: Bundler.settings["gem.github_username"], banner: "Set your username on GitHub", desc: "Fill in GitHub username on README so that you don't have to do it manually. Set a default with `bundle config set --global gem.github_username <your_username>`."
+ method_option :exe, :type => :boolean, :default => false, :aliases => ["--bin", "-b"], :desc => "Generate a binary executable for your library."
+ method_option :coc, :type => :boolean, :desc => "Generate a code of conduct file. Set a default with `bundle config set --global gem.coc true`."
+ method_option :edit, :type => :string, :aliases => "-e", :required => false, :banner => "EDITOR",
+ :lazy_default => [ENV["BUNDLER_EDITOR"], ENV["VISUAL"], ENV["EDITOR"]].find {|e| !e.nil? && !e.empty? },
+ :desc => "Open generated gemspec in the specified editor (defaults to $EDITOR or $BUNDLER_EDITOR)"
+ method_option :ext, :type => :string, :desc => "Generate the boilerplate for C extension code.", :enum => EXTENSIONS
+ method_option :git, :type => :boolean, :default => true, :desc => "Initialize a git repo inside your library."
+ method_option :mit, :type => :boolean, :desc => "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`."
+ method_option :rubocop, :type => :boolean, :desc => "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`."
+ method_option :changelog, :type => :boolean, :desc => "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`."
+ method_option :test, :type => :string, :lazy_default => Bundler.settings["gem.test"] || "", :aliases => "-t", :banner => "Use the specified test framework for your library",
+ :desc => "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`."
+ method_option :ci, :type => :string, :lazy_default => Bundler.settings["gem.ci"] || "",
+ :desc => "Generate CI configuration, either GitHub Actions, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|gitlab|circle)`"
+ method_option :linter, :type => :string, :lazy_default => Bundler.settings["gem.linter"] || "",
+ :desc => "Add a linter and code formatter, either RuboCop or Standard. Set a default with `bundle config set --global gem.linter (rubocop|standard)`"
+ method_option :github_username, :type => :string, :default => Bundler.settings["gem.github_username"], :banner => "Set your username on GitHub", :desc => "Fill in GitHub username on README so that you don't have to do it manually. Set a default with `bundle config set --global gem.github_username <your_username>`."
def gem(name)
end
@@ -591,24 +623,29 @@ module Bundler
File.expand_path("templates", __dir__)
end
- desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory", hide: true
- method_option "dry-run", type: :boolean, default: false, banner: "Only print out changes, do not clean gems"
- method_option "force", type: :boolean, default: false, banner: "Forces cleaning up unused gems even if Bundler is configured to use globally installed gems. As a consequence, removes all system gems except for the ones in the current application."
+ desc "clean [OPTIONS]", "Cleans up unused gems in your bundler directory", :hide => true
+ method_option "dry-run", :type => :boolean, :default => false, :banner =>
+ "Only print out changes, do not clean gems"
+ method_option "force", :type => :boolean, :default => false, :banner =>
+ "Forces cleaning up unused gems even if Bundler is configured to use globally installed gems. As a consequence, removes all system gems except for the ones in the current application."
def clean
require_relative "cli/clean"
Clean.new(options.dup).run
end
desc "platform [OPTIONS]", "Displays platform compatibility information"
- method_option "ruby", type: :boolean, default: false, banner: "only display ruby related platform information"
+ method_option "ruby", :type => :boolean, :default => false, :banner =>
+ "only display ruby related platform information"
def platform
require_relative "cli/platform"
Platform.new(options).run
end
- desc "inject GEM VERSION", "Add the named gem, with version requirements, to the resolved Gemfile", hide: true
- method_option "source", type: :string, banner: "Install gem from the given source"
- method_option "group", type: :string, banner: "Install gem into a bundler group"
+ desc "inject GEM VERSION", "Add the named gem, with version requirements, to the resolved Gemfile", :hide => true
+ method_option "source", :type => :string, :banner =>
+ "Install gem from the given source"
+ method_option "group", :type => :string, :banner =>
+ "Install gem into a bundler group"
def inject(name, version)
SharedHelpers.major_deprecation 2, "The `inject` command has been replaced by the `add` command"
require_relative "cli/inject"
@@ -616,21 +653,36 @@ module Bundler
end
desc "lock", "Creates a lockfile without installing"
- method_option "update", type: :array, lazy_default: true, banner: "ignore the existing lockfile, update all gems by default, or update list of given gems"
- method_option "local", type: :boolean, default: false, banner: "do not attempt to fetch remote gemspecs and use the local gem cache only"
- method_option "print", type: :boolean, default: false, banner: "print the lockfile to STDOUT instead of writing to the file system"
- method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile"
- method_option "lockfile", type: :string, default: nil, banner: "the path the lockfile should be written to"
- method_option "full-index", type: :boolean, default: false, banner: "Fall back to using the single-file index of all gems"
- method_option "add-platform", type: :array, default: [], banner: "Add a new platform to the lockfile"
- method_option "remove-platform", type: :array, default: [], banner: "Remove a platform from the lockfile"
- method_option "patch", type: :boolean, banner: "If updating, prefer updating only to next patch version"
- method_option "minor", type: :boolean, banner: "If updating, prefer updating only to next minor version"
- method_option "major", type: :boolean, banner: "If updating, prefer updating to next major version (default)"
- method_option "pre", type: :boolean, banner: "If updating, always choose the highest allowed version, regardless of prerelease status"
- method_option "strict", type: :boolean, banner: "If updating, do not allow any gem to be updated past latest --patch | --minor | --major"
- method_option "conservative", type: :boolean, banner: "If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated"
- method_option "bundler", type: :string, lazy_default: "> 0.a", banner: "Update the locked version of bundler"
+ method_option "update", :type => :array, :lazy_default => true, :banner =>
+ "ignore the existing lockfile, update all gems by default, or update list of given gems"
+ method_option "local", :type => :boolean, :default => false, :banner =>
+ "do not attempt to fetch remote gemspecs and use the local gem cache only"
+ method_option "print", :type => :boolean, :default => false, :banner =>
+ "print the lockfile to STDOUT instead of writing to the file system"
+ method_option "gemfile", :type => :string, :banner =>
+ "Use the specified gemfile instead of Gemfile"
+ method_option "lockfile", :type => :string, :default => nil, :banner =>
+ "the path the lockfile should be written to"
+ method_option "full-index", :type => :boolean, :default => false, :banner =>
+ "Fall back to using the single-file index of all gems"
+ method_option "add-platform", :type => :array, :default => [], :banner =>
+ "Add a new platform to the lockfile"
+ method_option "remove-platform", :type => :array, :default => [], :banner =>
+ "Remove a platform from the lockfile"
+ method_option "patch", :type => :boolean, :banner =>
+ "If updating, prefer updating only to next patch version"
+ method_option "minor", :type => :boolean, :banner =>
+ "If updating, prefer updating only to next minor version"
+ method_option "major", :type => :boolean, :banner =>
+ "If updating, prefer updating to next major version (default)"
+ method_option "pre", :type => :boolean, :banner =>
+ "If updating, always choose the highest allowed version, regardless of prerelease status"
+ method_option "strict", :type => :boolean, :banner =>
+ "If updating, do not allow any gem to be updated past latest --patch | --minor | --major"
+ method_option "conservative", :type => :boolean, :banner =>
+ "If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated"
+ method_option "bundler", :type => :string, :lazy_default => "> 0.a", :banner =>
+ "Update the locked version of bundler"
def lock
require_relative "cli/lock"
Lock.new(options).run
@@ -647,8 +699,10 @@ module Bundler
missing dependencies are detected, Bundler prints them and exits status 1.
Otherwise, Bundler prints a success message and exits with a status of 0.
D
- method_option "gemfile", type: :string, banner: "Use the specified gemfile instead of Gemfile"
- method_option "quiet", type: :boolean, banner: "Only output warnings and errors."
+ method_option "gemfile", :type => :string, :banner =>
+ "Use the specified gemfile instead of Gemfile"
+ method_option "quiet", :type => :boolean, :banner =>
+ "Only output warnings and errors."
def doctor
require_relative "cli/doctor"
Doctor.new(options).run
@@ -668,9 +722,7 @@ module Bundler
D
def pristine(*gems)
require_relative "cli/pristine"
- Bundler.settings.temporary(no_install: false) do
- Pristine.new(gems).run
- end
+ Pristine.new(gems).run
end
if Bundler.feature_flag.plugins?
@@ -691,6 +743,7 @@ module Bundler
exec_used = args.index {|a| exec_commands.include? a }
command = args.find {|a| bundler_commands.include? a }
+ command = all_aliases[command] if all_aliases[command]
if exec_used && help_used
if exec_used + help_used == 1
@@ -711,16 +764,14 @@ module Bundler
# when deprecated version of `--ext` is called
# print out deprecation warning and pretend `--ext=c` was provided
if deprecated_ext_value?(arguments)
- message = "Extensions can now be generated using C or Rust, so `--ext` with no arguments has been deprecated. Please select a language, e.g. `--ext=rust` to generate a Rust extension. This gem will now be generated as if `--ext=c` was used."
- removed_message = "Extensions can now be generated using C or Rust, so `--ext` with no arguments has been removed. Please select a language, e.g. `--ext=rust` to generate a Rust extension."
- SharedHelpers.major_deprecation 2, message, removed_message: removed_message
+ SharedHelpers.major_deprecation 2, "Extensions can now be generated using C or Rust, so `--ext` with no arguments has been deprecated. Please select a language, e.g. `--ext=rust` to generate a Rust extension. This gem will now be generated as if `--ext=c` was used."
arguments[arguments.index("--ext")] = "--ext=c"
end
end
def self.deprecated_ext_value?(arguments)
index = arguments.index("--ext")
- next_argument = arguments[index + 1]
+ next_argument = arguments[index+1]
# it is ok when --ext is followed with valid extension value
# for example `bundle gem hello --ext c`
@@ -743,6 +794,26 @@ module Bundler
private
+ # Automatically invoke `bundle install` and resume if
+ # Bundler.settings[:auto_install] exists. This is set through config cmd
+ # `bundle config set --global auto_install 1`.
+ #
+ # Note that this method `nil`s out the global Definition object, so it
+ # should be called first, before you instantiate anything like an
+ # `Installer` that'll keep a reference to the old one instead.
+ def auto_install
+ return unless Bundler.settings[:auto_install]
+
+ begin
+ Bundler.definition.specs
+ rescue GemNotFound
+ Bundler.ui.info "Automatically installing missing gems."
+ Bundler.reset!
+ invoke :install, []
+ Bundler.reset!
+ end
+ end
+
def current_command
_, _, config = @_initializer
config[:current_command]
@@ -772,10 +843,13 @@ module Bundler
return unless SharedHelpers.md5_available?
- require_relative "vendored_uri"
- remote = Source::Rubygems::Remote.new(Gem::URI("https://rubygems.org"))
- cache_path = Bundler.user_cache.join("compact_index", remote.cache_slug)
- latest = Bundler::CompactIndexClient.new(cache_path).latest_version("bundler")
+ latest = Fetcher::CompactIndex.
+ new(nil, Source::Rubygems::Remote.new(Bundler::URI("https://rubygems.org")), nil).
+ send(:compact_index_client).
+ instance_variable_get(:@cache).
+ dependencies("bundler").
+ map {|d| Gem::Version.new(d.first) }.
+ max
return unless latest
current = Gem::Version.new(VERSION)
@@ -809,23 +883,12 @@ module Bundler
value = options[name]
value = value.join(" ").to_s if option.type == :array
- value = "'#{value}'" unless option.type == :boolean
- print_remembered_flag_deprecation(flag_name, name.tr("-", "_"), value)
- end
-
- def print_remembered_flag_deprecation(flag_name, option_name, option_value)
- message =
+ Bundler::SharedHelpers.major_deprecation 2,
"The `#{flag_name}` flag is deprecated because it relies on being " \
"remembered across bundler invocations, which bundler will no longer " \
- "do in future versions. Instead please use `bundle config set #{option_name} " \
- "#{option_value}`, and stop using this flag"
- removed_message =
- "The `#{flag_name}` flag has been removed because it relied on being " \
- "remembered across bundler invocations, which bundler will no longer " \
- "do. Instead please use `bundle config set #{option_name} " \
- "#{option_value}`, and stop using this flag"
- Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message
+ "do in future versions. Instead please use `bundle config set --local #{name.tr("-", "_")} " \
+ "'#{value}'`, and stop using this flag"
end
end
end
diff --git a/lib/bundler/cli/add.rb b/lib/bundler/cli/add.rb
index 2b300e1783..08fa6547fb 100644
--- a/lib/bundler/cli/add.rb
+++ b/lib/bundler/cli/add.rb
@@ -28,13 +28,13 @@ module Bundler
dependencies = gems.map {|g| Bundler::Dependency.new(g, version, options) }
Injector.inject(dependencies,
- conservative_versioning: options[:version].nil?, # Perform conservative versioning only when version is not specified
- optimistic: options[:optimistic],
- strict: options[:strict])
+ :conservative_versioning => options[:version].nil?, # Perform conservative versioning only when version is not specified
+ :optimistic => options[:optimistic],
+ :strict => options[:strict])
end
def validate_options!
- raise InvalidOption, "You cannot specify `--strict` and `--optimistic` at the same time." if options[:strict] && options[:optimistic]
+ raise InvalidOption, "You can not specify `--strict` and `--optimistic` at the same time." if options[:strict] && options[:optimistic]
# raise error when no gems are specified
raise InvalidOption, "Please specify gems to add." if gems.empty?
diff --git a/lib/bundler/cli/binstubs.rb b/lib/bundler/cli/binstubs.rb
index 8ce138df96..fc2fad47a5 100644
--- a/lib/bundler/cli/binstubs.rb
+++ b/lib/bundler/cli/binstubs.rb
@@ -17,9 +17,9 @@ module Bundler
installer = Installer.new(Bundler.root, Bundler.definition)
installer_opts = {
- force: options[:force],
- binstubs_cmd: true,
- all_platforms: options["all-platforms"],
+ :force => options[:force],
+ :binstubs_cmd => true,
+ :all_platforms => options["all-platforms"],
}
if options[:all]
@@ -45,7 +45,7 @@ module Bundler
next
end
- Bundler.settings.temporary(path: Bundler.settings[:path] || Bundler.root) do
+ Bundler.settings.temporary(:path => (Bundler.settings[:path] || Bundler.root)) do
installer.generate_standalone_bundler_executable_stubs(spec, installer_opts)
end
else
diff --git a/lib/bundler/cli/cache.rb b/lib/bundler/cli/cache.rb
index 2e63a16ec3..c8698ed7e3 100644
--- a/lib/bundler/cli/cache.rb
+++ b/lib/bundler/cli/cache.rb
@@ -19,7 +19,7 @@ module Bundler
# TODO: move cache contents here now that all bundles are locked
custom_path = Bundler.settings[:path] if options[:path]
- Bundler.settings.temporary(cache_all_platforms: options["all-platforms"]) do
+ Bundler.settings.temporary(:cache_all_platforms => options["all-platforms"]) do
Bundler.load.cache(custom_path)
end
end
diff --git a/lib/bundler/cli/check.rb b/lib/bundler/cli/check.rb
index 2adf59d5d5..cc1f37f0c3 100644
--- a/lib/bundler/cli/check.rb
+++ b/lib/bundler/cli/check.rb
@@ -17,7 +17,7 @@ module Bundler
begin
definition.resolve_only_locally!
not_installed = definition.missing_specs
- rescue GemNotFound, GitError, SolveFailure
+ rescue GemNotFound, SolveFailure
Bundler.ui.error "Bundler can't satisfy your Gemfile's dependencies."
Bundler.ui.warn "Install missing gems with `bundle install`."
exit 1
@@ -29,10 +29,10 @@ module Bundler
Bundler.ui.warn "Install missing gems with `bundle install`"
exit 1
elsif !Bundler.default_lockfile.file? && Bundler.frozen_bundle?
- Bundler.ui.error "This bundle has been frozen, but there is no #{SharedHelpers.relative_lockfile_path} present"
+ Bundler.ui.error "This bundle has been frozen, but there is no #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} present"
exit 1
else
- Bundler.load.lock(preserve_unknown_sections: true) unless options[:"dry-run"]
+ Bundler.load.lock(:preserve_unknown_sections => true) unless options[:"dry-run"]
Bundler.ui.info "The Gemfile's dependencies are satisfied"
end
end
diff --git a/lib/bundler/cli/common.rb b/lib/bundler/cli/common.rb
index 7ef6deb2cf..d654406f65 100644
--- a/lib/bundler/cli/common.rb
+++ b/lib/bundler/cli/common.rb
@@ -54,12 +54,9 @@ module Bundler
Bundler.definition.specs.each do |spec|
return spec if spec.name == name
- specs << spec if regexp && spec.name.match?(regexp)
+ specs << spec if regexp && spec.name =~ regexp
end
- default_spec = default_gem_spec(name)
- specs << default_spec if default_spec
-
case specs.count
when 0
dep_in_other_group = Bundler.definition.current_dependencies.find {|dep|dep.name == name }
@@ -78,11 +75,6 @@ module Bundler
raise GemNotFound, gem_not_found_message(name, Bundler.definition.dependencies)
end
- def self.default_gem_spec(name)
- gem_spec = Gem::Specification.find_all_by_name(name).last
- gem_spec if gem_spec&.default_gem?
- end
-
def self.ask_for_spec_from(specs)
specs.each_with_index do |spec, index|
Bundler.ui.info "#{index.succ} : #{spec.name}", true
diff --git a/lib/bundler/cli/config.rb b/lib/bundler/cli/config.rb
index 77b502fe60..e1222c75dd 100644
--- a/lib/bundler/cli/config.rb
+++ b/lib/bundler/cli/config.rb
@@ -2,17 +2,17 @@
module Bundler
class CLI::Config < Thor
- class_option :parseable, type: :boolean, banner: "Use minimal formatting for more parseable output"
+ class_option :parseable, :type => :boolean, :banner => "Use minimal formatting for more parseable output"
def self.scope_options
- method_option :global, type: :boolean, banner: "Only change the global config"
- method_option :local, type: :boolean, banner: "Only change the local config"
+ method_option :global, :type => :boolean, :banner => "Only change the global config"
+ method_option :local, :type => :boolean, :banner => "Only change the local config"
end
private_class_method :scope_options
- desc "base NAME [VALUE]", "The Bundler 1 config interface", hide: true
+ desc "base NAME [VALUE]", "The Bundler 1 config interface", :hide => true
scope_options
- method_option :delete, type: :boolean, banner: "delete"
+ method_option :delete, :type => :boolean, :banner => "delete"
def base(name = nil, *value)
new_args =
if ARGV.size == 1
@@ -25,9 +25,8 @@ module Bundler
["config", "get", ARGV[1]]
end
- message = "Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle #{new_args.join(" ")}` instead."
- removed_message = "Using the `config` command without a subcommand [list, get, set, unset] is has been removed. Use `bundle #{new_args.join(" ")}` instead."
- SharedHelpers.major_deprecation 3, message, removed_message: removed_message
+ SharedHelpers.major_deprecation 3,
+ "Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle #{new_args.join(" ")}` instead."
Base.new(options, name, value, self).run
end
diff --git a/lib/bundler/cli/console.rb b/lib/bundler/cli/console.rb
index 840cf14fd7..1eb8ea8254 100644
--- a/lib/bundler/cli/console.rb
+++ b/lib/bundler/cli/console.rb
@@ -9,9 +9,8 @@ module Bundler
end
def run
- message = "bundle console will be replaced by `bin/console` generated by `bundle gem <name>`"
- removed_message = "bundle console has been replaced by `bin/console` generated by `bundle gem <name>`"
- Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message
+ Bundler::SharedHelpers.major_deprecation 2, "bundle console will be replaced " \
+ "by `bin/console` generated by `bundle gem <name>`"
group ? Bundler.require(:default, *group.split(" ").map!(&:to_sym)) : Bundler.require
ARGV.clear
diff --git a/lib/bundler/cli/doctor.rb b/lib/bundler/cli/doctor.rb
index 1f6fc93c16..e299a5a8c2 100644
--- a/lib/bundler/cli/doctor.rb
+++ b/lib/bundler/cli/doctor.rb
@@ -6,8 +6,8 @@ require "fiddle"
module Bundler
class CLI::Doctor
- DARWIN_REGEX = /\s+(.+) \(compatibility /
- LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/
+ DARWIN_REGEX = /\s+(.+) \(compatibility /.freeze
+ LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/.freeze
attr_reader :options
diff --git a/lib/bundler/cli/exec.rb b/lib/bundler/cli/exec.rb
index f81cd5d2c4..42b602a055 100644
--- a/lib/bundler/cli/exec.rb
+++ b/lib/bundler/cli/exec.rb
@@ -12,7 +12,7 @@ module Bundler
@options = options
@cmd = args.shift
@args = args
- @args << { close_others: !options.keep_file_descriptors? } unless Bundler.current_ruby.jruby?
+ @args << { :close_others => !options.keep_file_descriptors? } unless Bundler.current_ruby.jruby?
end
def run
diff --git a/lib/bundler/cli/fund.rb b/lib/bundler/cli/fund.rb
index ad7f31f3d6..52db5aef68 100644
--- a/lib/bundler/cli/fund.rb
+++ b/lib/bundler/cli/fund.rb
@@ -16,7 +16,7 @@ module Bundler
deps = if groups.any?
Bundler.definition.dependencies_for(groups)
else
- Bundler.definition.requested_dependencies
+ Bundler.definition.current_dependencies
end
fund_info = deps.each_with_object([]) do |dep, arr|
diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb
index 22bcf0e47a..7f1200f4a0 100644
--- a/lib/bundler/cli/gem.rb
+++ b/lib/bundler/cli/gem.rb
@@ -11,7 +11,7 @@ module Bundler
class CLI::Gem
TEST_FRAMEWORK_VERSIONS = {
"rspec" => "3.0",
- "minitest" => "5.16",
+ "minitest" => "5.0",
"test-unit" => "3.0",
}.freeze
@@ -32,6 +32,7 @@ module Bundler
validate_ext_name if @extension
validate_rust_builder_rubygems_version if @extension == "rust"
+ travis_removal_info
end
def run
@@ -58,28 +59,28 @@ module Bundler
end
config = {
- name: name,
- underscored_name: underscored_name,
- namespaced_path: namespaced_path,
- makefile_path: "#{underscored_name}/#{underscored_name}",
- constant_name: constant_name,
- constant_array: constant_array,
- author: git_author_name.empty? ? "TODO: Write your name" : git_author_name,
- email: git_user_email.empty? ? "TODO: Write your email address" : git_user_email,
- test: options[:test],
- ext: extension,
- exe: options[:exe],
- bundler_version: bundler_dependency_version,
- git: use_git,
- github_username: github_username.empty? ? "[USERNAME]" : github_username,
- required_ruby_version: required_ruby_version,
- rust_builder_required_rubygems_version: rust_builder_required_rubygems_version,
- minitest_constant_name: minitest_constant_name,
+ :name => name,
+ :underscored_name => underscored_name,
+ :namespaced_path => namespaced_path,
+ :makefile_path => "#{underscored_name}/#{underscored_name}",
+ :constant_name => constant_name,
+ :constant_array => constant_array,
+ :author => git_author_name.empty? ? "TODO: Write your name" : git_author_name,
+ :email => git_user_email.empty? ? "TODO: Write your email address" : git_user_email,
+ :test => options[:test],
+ :ext => extension,
+ :exe => options[:exe],
+ :bundler_version => bundler_dependency_version,
+ :git => use_git,
+ :github_username => github_username.empty? ? "[USERNAME]" : github_username,
+ :required_ruby_version => required_ruby_version,
+ :rust_builder_required_rubygems_version => rust_builder_required_rubygems_version,
+ :minitest_constant_name => minitest_constant_name,
}
ensure_safe_gem_name(name, constant_array)
templates = {
- "Gemfile.tt" => Bundler.preferred_gemfile_name,
+ "#{Bundler.preferred_gemfile_name}.tt" => Bundler.preferred_gemfile_name,
"lib/newgem.rb.tt" => "lib/#{namespaced_path}.rb",
"lib/newgem/version.rb.tt" => "lib/#{namespaced_path}/version.rb",
"sig/newgem.rbs.tt" => "sig/#{namespaced_path}.rbs",
@@ -136,13 +137,10 @@ module Bundler
case config[:ci]
when "github"
templates.merge!("github/workflows/main.yml.tt" => ".github/workflows/main.yml")
- config[:ci_config_path] = ".github "
when "gitlab"
templates.merge!("gitlab-ci.yml.tt" => ".gitlab-ci.yml")
- config[:ci_config_path] = ".gitlab-ci.yml "
when "circle"
templates.merge!("circleci/config.yml.tt" => ".circleci/config.yml")
- config[:ci_config_path] = ".circleci "
end
if ask_and_set(:mit, "Do you want to license your code permissively under the MIT license?",
@@ -191,10 +189,7 @@ module Bundler
templates.merge!("standard.yml.tt" => ".standard.yml")
end
- if config[:exe]
- templates.merge!("exe/newgem.tt" => "exe/#{name}")
- executables.push("exe/#{name}")
- end
+ templates.merge!("exe/newgem.tt" => "exe/#{name}") if config[:exe]
if extension == "c"
templates.merge!(
@@ -238,7 +233,9 @@ module Bundler
end
if use_git
- IO.popen(%w[git add .], { chdir: target }, &:read)
+ Dir.chdir(target) do
+ `git add .`
+ end
end
# Open gemspec in editor
@@ -278,7 +275,6 @@ module Bundler
end
def ask_and_set_test_framework
- return if skip?(:test)
test_framework = options[:test] || Bundler.settings["gem.test"]
if test_framework.to_s.empty?
@@ -304,10 +300,6 @@ module Bundler
test_framework
end
- def skip?(option)
- options.key?(option) && options[option].nil?
- end
-
def hint_text(setting)
if Bundler.settings["gem.#{setting}"] == false
"Your choice will only be applied to this gem."
@@ -318,7 +310,6 @@ module Bundler
end
def ask_and_set_ci
- return if skip?(:ci)
ci_template = options[:ci] || Bundler.settings["gem.ci"]
if ci_template.to_s.empty?
@@ -350,7 +341,6 @@ module Bundler
end
def ask_and_set_linter
- return if skip?(:linter)
linter_template = options[:linter] || Bundler.settings["gem.linter"]
linter_template = deprecated_rubocop_option if linter_template.nil?
@@ -358,7 +348,7 @@ module Bundler
Bundler.ui.confirm "Do you want to add a code linter and formatter to your gem? " \
"Supported Linters:\n" \
"* RuboCop: https://rubocop.org\n" \
- "* Standard: https://github.com/standardrb/standard\n" \
+ "* Standard: https://github.com/testdouble/standard\n" \
"\n"
Bundler.ui.info hint_text("linter")
@@ -389,20 +379,15 @@ module Bundler
def deprecated_rubocop_option
if !options[:rubocop].nil?
if options[:rubocop]
- Bundler::SharedHelpers.major_deprecation 2,
- "--rubocop is deprecated, use --linter=rubocop",
- removed_message: "--rubocop has been removed, use --linter=rubocop"
+ Bundler::SharedHelpers.major_deprecation 2, "--rubocop is deprecated, use --linter=rubocop"
"rubocop"
else
- Bundler::SharedHelpers.major_deprecation 2,
- "--no-rubocop is deprecated, use --linter",
- removed_message: "--no-rubocop has been removed, use --linter"
+ Bundler::SharedHelpers.major_deprecation 2, "--no-rubocop is deprecated, use --linter"
false
end
elsif !Bundler.settings["gem.rubocop"].nil?
Bundler::SharedHelpers.major_deprecation 2,
- "config gem.rubocop is deprecated; we've updated your config to use gem.linter instead",
- removed_message: "config gem.rubocop has been removed; we've updated your config to use gem.linter instead"
+ "config gem.rubocop is deprecated; we've updated your config to use gem.linter instead"
Bundler.settings["gem.rubocop"] ? "rubocop" : false
end
end
@@ -446,7 +431,7 @@ module Bundler
end
def required_ruby_version
- "3.1.0"
+ "2.6.0"
end
def rubocop_version
@@ -457,6 +442,19 @@ module Bundler
"1.3"
end
+ # TODO: remove at next minor release
+ def travis_removal_info
+ if options[:ci] == "travis"
+ Bundler.ui.error "Support for Travis CI was removed from gem skeleton generator."
+ exit 1
+ end
+
+ if Bundler.settings["gem.ci"] == "travis"
+ Bundler.ui.error "Support for Travis CI was removed from gem skeleton generator, but it is present in bundle config. Please configure another provider using `bundle config set gem.ci SERVICE` (where SERVICE is one of github/gitlab/circle) or unset configuration using `bundle config unset gem.ci`."
+ exit 1
+ end
+ end
+
def validate_rust_builder_rubygems_version
if Gem::Version.new(rust_builder_required_rubygems_version) > Gem.rubygems_version
Bundler.ui.error "Your RubyGems version (#{Gem.rubygems_version}) is too old to build Rust extension. Please update your RubyGems using `gem update --system` or any other way and try again."
diff --git a/lib/bundler/cli/info.rb b/lib/bundler/cli/info.rb
index 8f34956aca..36c7a58f12 100644
--- a/lib/bundler/cli/info.rb
+++ b/lib/bundler/cli/info.rb
@@ -25,8 +25,19 @@ module Bundler
private
- def spec_for_gem(name)
- Bundler::CLI::Common.select_spec(name, :regex_match)
+ def spec_for_gem(gem_name)
+ spec = Bundler.definition.specs.find {|s| s.name == gem_name }
+ spec || default_gem_spec(gem_name) || Bundler::CLI::Common.select_spec(gem_name, :regex_match)
+ end
+
+ def default_gem_spec(gem_name)
+ return unless Gem::Specification.respond_to?(:find_all_by_name)
+ gem_spec = Gem::Specification.find_all_by_name(gem_name).last
+ return gem_spec if gem_spec&.default_gem?
+ end
+
+ def spec_not_found(gem_name)
+ raise GemNotFound, Bundler::CLI::Common.gem_not_found_message(gem_name, Bundler.definition.dependencies)
end
def print_gem_version(spec)
diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb
index b0b354cf10..c71bcf159f 100644
--- a/lib/bundler/cli/install.rb
+++ b/lib/bundler/cli/install.rb
@@ -12,33 +12,24 @@ module Bundler
warn_if_root
- if options[:local]
- Bundler.self_manager.restart_with_locked_bundler_if_needed
- else
- Bundler.self_manager.install_locked_bundler_and_restart_with_it_if_needed
- end
+ Bundler.self_manager.install_locked_bundler_and_restart_with_it_if_needed
- Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Gem.freebsd_platform?
+ Bundler::SharedHelpers.set_env "RB_USER_INSTALL", "1" if Bundler::FREEBSD
# Disable color in deployment mode
Bundler.ui.shell = Thor::Shell::Basic.new if options[:deployment]
- if target_rbconfig_path = options[:"target-rbconfig"]
- Bundler.rubygems.set_target_rbconfig(target_rbconfig_path)
- end
-
check_for_options_conflicts
check_trust_policy
if options[:deployment] || options[:frozen] || Bundler.frozen_bundle?
unless Bundler.default_lockfile.exist?
- flag = "--deployment flag" if options[:deployment]
- flag ||= "--frozen flag" if options[:frozen]
- flag ||= "deployment setting" if Bundler.settings[:deployment]
- flag ||= "frozen setting" if Bundler.settings[:frozen]
- raise ProductionError, "The #{flag} requires a lockfile. Please make " \
- "sure you have checked your #{SharedHelpers.relative_lockfile_path} into version control " \
+ flag = "--deployment flag" if options[:deployment]
+ flag ||= "--frozen flag" if options[:frozen]
+ flag ||= "deployment setting"
+ raise ProductionError, "The #{flag} requires a #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}. Please make " \
+ "sure you have checked your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} into version control " \
"before deploying."
end
@@ -60,8 +51,7 @@ module Bundler
if options["binstubs"]
Bundler::SharedHelpers.major_deprecation 2,
- "The --binstubs option will be removed in favor of `bundle binstubs --all`",
- removed_message: "The --binstubs option have been removed in favor of `bundle binstubs --all`"
+ "The --binstubs option will be removed in favor of `bundle binstubs --all`"
end
Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins?
@@ -71,7 +61,7 @@ module Bundler
installer = Installer.install(Bundler.root, definition, options)
- Bundler.settings.temporary(cache_all_platforms: options[:local] ? false : Bundler.settings[:cache_all_platforms]) do
+ Bundler.settings.temporary(:cache_all_platforms => options[:local] ? false : Bundler.settings[:cache_all_platforms]) do
Bundler.load.cache(nil, options[:local]) if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.frozen_bundle?
end
@@ -105,7 +95,7 @@ module Bundler
def warn_if_root
return if Bundler.settings[:silence_root_warning] || Gem.win_platform? || !Process.uid.zero?
Bundler.ui.warn "Don't run Bundler as root. Installing your bundle as root " \
- "will break this application for all non-root users on this machine.", wrap: true
+ "will break this application for all non-root users on this machine.", :wrap => true
end
def dependencies_count_for(definition)
@@ -158,7 +148,7 @@ module Bundler
Bundler.settings.set_command_option_if_given :path, options[:path]
if options["standalone"] && Bundler.settings[:path].nil? && !options["local"]
- Bundler.settings.temporary(path_relative_to_cwd: false) do
+ Bundler.settings.temporary(:path_relative_to_cwd => false) do
Bundler.settings.set_command_option :path, "bundle"
end
end
diff --git a/lib/bundler/cli/issue.rb b/lib/bundler/cli/issue.rb
index 5f2924c4bd..b891ecb1d2 100644
--- a/lib/bundler/cli/issue.rb
+++ b/lib/bundler/cli/issue.rb
@@ -5,7 +5,7 @@ require "rbconfig"
module Bundler
class CLI::Issue
def run
- Bundler.ui.info <<~EOS
+ Bundler.ui.info <<-EOS.gsub(/^ {8}/, "")
Did you find an issue with Bundler? Before filing a new issue,
be sure to check out these resources:
diff --git a/lib/bundler/cli/lock.rb b/lib/bundler/cli/lock.rb
index 3f204bdc45..cb3ed27138 100644
--- a/lib/bundler/cli/lock.rb
+++ b/lib/bundler/cli/lock.rb
@@ -15,8 +15,8 @@ module Bundler
end
print = options[:print]
- previous_output_stream = Bundler.ui.output_stream
- Bundler.ui.output_stream = :stderr if print
+ previous_ui_level = Bundler.ui.level
+ Bundler.ui.level = "silent" if print
Bundler::Fetcher.disable_endpoint = options["full-index"]
@@ -26,49 +26,45 @@ module Bundler
if update.is_a?(Array) # unlocking specific gems
Bundler::CLI::Common.ensure_all_gems_in_lockfile!(update)
- update = { gems: update, conservative: conservative }
+ update = { :gems => update, :conservative => conservative }
elsif update && conservative
- update = { conservative: conservative }
+ update = { :conservative => conservative }
elsif update && bundler
- update = { bundler: bundler }
+ update = { :bundler => bundler }
end
+ definition = Bundler.definition(update)
- file = options[:lockfile]
- file = file ? Pathname.new(file).expand_path : Bundler.default_lockfile
+ Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) if options[:update]
- Bundler.settings.temporary(frozen: false) do
- definition = Bundler.definition(update, file)
-
- Bundler::CLI::Common.configure_gem_version_promoter(definition, options) if options[:update]
-
- options["remove-platform"].each do |platform|
- definition.remove_platform(platform)
- end
+ options["remove-platform"].each do |platform|
+ definition.remove_platform(platform)
+ end
- options["add-platform"].each do |platform_string|
- platform = Gem::Platform.new(platform_string)
- if platform.to_s == "unknown"
- Bundler.ui.error "The platform `#{platform_string}` is unknown to RubyGems and can't be added to the lockfile."
- exit 1
- end
- definition.add_platform(platform)
+ options["add-platform"].each do |platform_string|
+ platform = Gem::Platform.new(platform_string)
+ if platform.to_s == "unknown"
+ Bundler.ui.warn "The platform `#{platform_string}` is unknown to RubyGems " \
+ "and adding it will likely lead to resolution errors"
end
+ definition.add_platform(platform)
+ end
- if definition.platforms.empty?
- raise InvalidOption, "Removing all platforms from the bundle is not allowed"
- end
+ if definition.platforms.empty?
+ raise InvalidOption, "Removing all platforms from the bundle is not allowed"
+ end
- definition.resolve_remotely! unless options[:local]
+ definition.resolve_remotely! unless options[:local]
- if print
- puts definition.to_lock
- else
- puts "Writing lockfile to #{file}"
- definition.lock
- end
+ if print
+ puts definition.to_lock
+ else
+ file = options[:lockfile]
+ file = file ? File.expand_path(file) : Bundler.default_lockfile
+ puts "Writing lockfile to #{file}"
+ definition.lock(file)
end
- Bundler.ui.output_stream = previous_output_stream
+ Bundler.ui.level = previous_ui_level
end
end
end
diff --git a/lib/bundler/cli/open.rb b/lib/bundler/cli/open.rb
index f24693b843..8522ec92d6 100644
--- a/lib/bundler/cli/open.rb
+++ b/lib/bundler/cli/open.rb
@@ -18,11 +18,13 @@ module Bundler
Bundler.ui.info "Unable to open #{name} because it's a default gem, so the directory it would normally be installed to does not exist."
else
root_path = spec.full_gem_path
- require "shellwords"
- command = Shellwords.split(editor) << File.join([root_path, path].compact)
- Bundler.with_original_env do
- system(*command, { chdir: root_path })
- end || Bundler.ui.info("Could not run '#{command.join(" ")}'")
+ Dir.chdir(root_path) do
+ require "shellwords"
+ command = Shellwords.split(editor) << File.join([root_path, path].compact)
+ Bundler.with_original_env do
+ system(*command)
+ end || Bundler.ui.info("Could not run '#{command.join(" ")}'")
+ end
end
end
end
diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb
index 75fcdca641..68c701aefb 100644
--- a/lib/bundler/cli/outdated.rb
+++ b/lib/bundler/cli/outdated.rb
@@ -41,12 +41,12 @@ module Bundler
# We're doing a full update
Bundler.definition(true)
else
- Bundler.definition(gems: gems, sources: sources)
+ Bundler.definition(:gems => gems, :sources => sources)
end
Bundler::CLI::Common.configure_gem_version_promoter(
Bundler.definition,
- options.merge(strict: @strict)
+ options.merge(:strict => @strict)
)
definition_resolution = proc do
@@ -54,7 +54,7 @@ module Bundler
end
if options[:parseable]
- Bundler.ui.progress(&definition_resolution)
+ Bundler.ui.silence(&definition_resolution)
else
definition_resolution.call
end
@@ -90,33 +90,35 @@ module Bundler
end
outdated_gems << {
- active_spec: active_spec,
- current_spec: current_spec,
- dependency: dependency,
- groups: groups,
+ :active_spec => active_spec,
+ :current_spec => current_spec,
+ :dependency => dependency,
+ :groups => groups,
}
end
- relevant_outdated_gems = if options_include_groups
- outdated_gems.group_by {|g| g[:groups] }.sort.flat_map do |groups, gems|
- contains_group = groups.split(", ").include?(options[:group])
- next unless options[:groups] || contains_group
-
- gems
- end.compact
- else
- outdated_gems
- end
-
- if relevant_outdated_gems.empty?
+ if outdated_gems.empty?
unless options[:parseable]
Bundler.ui.info(nothing_outdated_message)
end
else
- if options[:parseable]
- print_gems(relevant_outdated_gems)
+ if options_include_groups
+ relevant_outdated_gems = outdated_gems.group_by {|g| g[:groups] }.sort.flat_map do |groups, gems|
+ contains_group = groups.split(", ").include?(options[:group])
+ next unless options[:groups] || contains_group
+
+ gems
+ end.compact
+
+ if options[:parseable]
+ print_gems(relevant_outdated_gems)
+ else
+ print_gems_table(relevant_outdated_gems)
+ end
+ elsif options[:parseable]
+ print_gems(outdated_gems)
else
- print_gems_table(relevant_outdated_gems)
+ print_gems_table(outdated_gems)
end
exit 1
diff --git a/lib/bundler/cli/plugin.rb b/lib/bundler/cli/plugin.rb
index fd61ef0d95..fe3f4412fa 100644
--- a/lib/bundler/cli/plugin.rb
+++ b/lib/bundler/cli/plugin.rb
@@ -5,15 +5,20 @@ module Bundler
class CLI::Plugin < Thor
desc "install PLUGINS", "Install the plugin from the source"
long_desc <<-D
- Install plugins either from the rubygems source provided (with --source option), from a git source provided with --git, or a local path provided with --path. If no sources are provided, it uses Gem.sources
+ Install plugins either from the rubygems source provided (with --source option) or from a git source provided with --git (for remote repos) or --local_git (for local repos). If no sources are provided, it uses Gem.sources
D
- method_option "source", type: :string, default: nil, banner: "URL of the RubyGems source to fetch the plugin from"
- method_option "version", type: :string, default: nil, banner: "The version of the plugin to fetch"
- method_option "git", type: :string, default: nil, banner: "URL of the git repo to fetch from"
- method_option "local_git", type: :string, default: nil, banner: "Path of the local git repo to fetch from (deprecated)"
- method_option "branch", type: :string, default: nil, banner: "The git branch to checkout"
- method_option "ref", type: :string, default: nil, banner: "The git revision to check out"
- method_option "path", type: :string, default: nil, banner: "Path of a local gem to directly use"
+ method_option "source", :type => :string, :default => nil, :banner =>
+ "URL of the RubyGems source to fetch the plugin from"
+ method_option "version", :type => :string, :default => nil, :banner =>
+ "The version of the plugin to fetch"
+ method_option "git", :type => :string, :default => nil, :banner =>
+ "URL of the git repo to fetch from"
+ method_option "local_git", :type => :string, :default => nil, :banner =>
+ "Path of the local git repo to fetch from"
+ method_option "branch", :type => :string, :default => nil, :banner =>
+ "The git branch to checkout"
+ method_option "ref", :type => :string, :default => nil, :banner =>
+ "The git revision to check out"
def install(*plugins)
Bundler::Plugin.install(plugins, options)
end
@@ -22,7 +27,8 @@ module Bundler
long_desc <<-D
Uninstall given list of plugins. To uninstall all the plugins, use -all option.
D
- method_option "all", type: :boolean, default: nil, banner: "Uninstall all the installed plugins. If no plugin is installed, then it does nothing."
+ method_option "all", :type => :boolean, :default => nil, :banner =>
+ "Uninstall all the installed plugins. If no plugin is installed, then it does nothing."
def uninstall(*plugins)
Bundler::Plugin.uninstall(plugins, options)
end
diff --git a/lib/bundler/cli/pristine.rb b/lib/bundler/cli/pristine.rb
index e0d7452c44..d6654f8053 100644
--- a/lib/bundler/cli/pristine.rb
+++ b/lib/bundler/cli/pristine.rb
@@ -12,48 +12,40 @@ module Bundler
definition.validate_runtime!
installer = Bundler::Installer.new(Bundler.root, definition)
- ProcessLock.lock do
- installed_specs = definition.specs.reject do |spec|
- next if spec.name == "bundler" # Source::Rubygems doesn't install bundler
- next if !@gems.empty? && !@gems.include?(spec.name)
-
- gem_name = "#{spec.name} (#{spec.version}#{spec.git_version})"
- gem_name += " (#{spec.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY
-
- case source = spec.source
- when Source::Rubygems
- cached_gem = spec.cache_file
- unless File.exist?(cached_gem)
- Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.")
- next
- end
-
- FileUtils.rm_rf spec.full_gem_path
- when Source::Git
- if source.local?
- Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is locally overridden.")
- next
- end
-
- source.remote!
- if extension_cache_path = source.extension_cache_path(spec)
- FileUtils.rm_rf extension_cache_path
- end
- FileUtils.rm_rf spec.extension_dir
- FileUtils.rm_rf spec.full_gem_path
- else
- Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.")
+ Bundler.load.specs.each do |spec|
+ next if spec.name == "bundler" # Source::Rubygems doesn't install bundler
+ next if !@gems.empty? && !@gems.include?(spec.name)
+
+ gem_name = "#{spec.name} (#{spec.version}#{spec.git_version})"
+ gem_name += " (#{spec.platform})" if !spec.platform.nil? && spec.platform != Gem::Platform::RUBY
+
+ case source = spec.source
+ when Source::Rubygems
+ cached_gem = spec.cache_file
+ unless File.exist?(cached_gem)
+ Bundler.ui.error("Failed to pristine #{gem_name}. Cached gem #{cached_gem} does not exist.")
next
end
- true
- end.map(&:name)
+ FileUtils.rm_rf spec.full_gem_path
+ when Source::Git
+ if source.local?
+ Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is locally overridden.")
+ next
+ end
- jobs = installer.send(:installation_parallelization, {})
- pristine_count = definition.specs.count - installed_specs.count
- # allow a pristining a single gem to skip the parallel worker
- jobs = [jobs, pristine_count].min
- ParallelInstaller.call(installer, definition.specs, jobs, false, true, skip: installed_specs)
+ source.remote!
+ if extension_cache_path = source.extension_cache_path(spec)
+ FileUtils.rm_rf extension_cache_path
+ end
+ FileUtils.rm_rf spec.extension_dir
+ FileUtils.rm_rf spec.full_gem_path
+ else
+ Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.")
+ next
+ end
+
+ Bundler::GemInstaller.new(spec, installer, false, 0, true).install_from_spec
end
end
end
diff --git a/lib/bundler/cli/show.rb b/lib/bundler/cli/show.rb
index 59b0af42e1..2df13db1fa 100644
--- a/lib/bundler/cli/show.rb
+++ b/lib/bundler/cli/show.rb
@@ -40,8 +40,8 @@ module Bundler
desc = " * #{s.name} (#{s.version}#{s.git_version})"
if @verbose
latest = latest_specs.find {|l| l.name == s.name }
- Bundler.ui.info <<~END
- #{desc.lstrip}
+ Bundler.ui.info <<-END.gsub(/^ +/, "")
+ #{desc}
\tSummary: #{s.summary || "No description available."}
\tHomepage: #{s.homepage || "No website available."}
\tStatus: #{outdated?(s, latest) ? "Outdated - #{s.version} < #{latest.version}" : "Up to date"}
diff --git a/lib/bundler/cli/update.rb b/lib/bundler/cli/update.rb
index 985e8db051..b49182655b 100644
--- a/lib/bundler/cli/update.rb
+++ b/lib/bundler/cli/update.rb
@@ -35,7 +35,7 @@ module Bundler
if full_update
if conservative
- Bundler.definition(conservative: conservative)
+ Bundler.definition(:conservative => conservative)
else
Bundler.definition(true)
end
@@ -51,9 +51,9 @@ module Bundler
gems.concat(deps.map(&:name))
end
- Bundler.definition(gems: gems, sources: sources, ruby: options[:ruby],
- conservative: conservative,
- bundler: update_bundler)
+ Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby],
+ :conservative => conservative,
+ :bundler => update_bundler)
end
Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options)
@@ -63,7 +63,6 @@ module Bundler
opts = options.dup
opts["update"] = true
opts["local"] = options[:local]
- opts["force"] = options[:redownload]
Bundler.settings.set_command_option_if_given :jobs, opts["jobs"]
@@ -71,7 +70,7 @@ module Bundler
if locked_gems = Bundler.definition.locked_gems
previous_locked_info = locked_gems.specs.reduce({}) do |h, s|
- h[s.name] = { spec: s, version: s.version, source: s.source.identifier }
+ h[s.name] = { :spec => s, :version => s.version, :source => s.source.identifier }
h
end
end
diff --git a/lib/bundler/compact_index_client.rb b/lib/bundler/compact_index_client.rb
index a4f5bb1638..127a50e810 100644
--- a/lib/bundler/compact_index_client.rb
+++ b/lib/bundler/compact_index_client.rb
@@ -4,44 +4,8 @@ require "pathname"
require "set"
module Bundler
- # The CompactIndexClient is responsible for fetching and parsing the compact index.
- #
- # The compact index is a set of caching optimized files that are used to fetch gem information.
- # The files are:
- # - names: a list of all gem names
- # - versions: a list of all gem versions
- # - info/[gem]: a list of all versions of a gem
- #
- # The client is instantiated with:
- # - `directory`: the root directory where the cache files are stored.
- # - `fetcher`: (optional) an object that responds to #call(uri_path, headers) and returns an http response.
- # If the `fetcher` is not provided, the client will only read cached files from disk.
- #
- # The client is organized into:
- # - `Updater`: updates the cached files on disk using the fetcher.
- # - `Cache`: calls the updater, caches files, read and return them from disk
- # - `Parser`: parses the compact index file data
- # - `CacheFile`: a concurrency safe file reader/writer that verifies checksums
- #
- # The client is intended to optimize memory usage and performance.
- # It is called 100s or 1000s of times, parsing files with hundreds of thousands of lines.
- # It may be called concurrently without global interpreter lock in some Rubies.
- # As a result, some methods may look more complex than necessary to save memory or time.
class CompactIndexClient
- # NOTE: MD5 is here not because we expect a server to respond with it, but
- # because we use it to generate the etag on first request during the upgrade
- # to the compact index client that uses opaque etags saved to files.
- # Remove once 2.5.0 has been out for a while.
- SUPPORTED_DIGESTS = { "sha-256" => :SHA256, "md5" => :MD5 }.freeze
DEBUG_MUTEX = Thread::Mutex.new
-
- # info returns an Array of INFO Arrays. Each INFO Array has the following indices:
- INFO_NAME = 0
- INFO_VERSION = 1
- INFO_PLATFORM = 2
- INFO_DEPS = 3
- INFO_REQS = 4
-
def self.debug
return unless ENV["DEBUG_COMPACT_INDEX"]
DEBUG_MUTEX.synchronize { warn("[#{self}] #{yield}") }
@@ -50,48 +14,106 @@ module Bundler
class Error < StandardError; end
require_relative "compact_index_client/cache"
- require_relative "compact_index_client/cache_file"
- require_relative "compact_index_client/parser"
require_relative "compact_index_client/updater"
- def initialize(directory, fetcher = nil)
- @cache = Cache.new(directory, fetcher)
- @parser = Parser.new(@cache)
+ attr_reader :directory
+
+ def initialize(directory, fetcher)
+ @directory = Pathname.new(directory)
+ @updater = Updater.new(fetcher)
+ @cache = Cache.new(@directory)
+ @endpoints = Set.new
+ @info_checksums_by_name = {}
+ @parsed_checksums = false
+ @mutex = Thread::Mutex.new
+ end
+
+ def execution_mode=(block)
+ Bundler::CompactIndexClient.debug { "execution_mode=" }
+ @endpoints = Set.new
+
+ @execution_mode = block
+ end
+
+ # @return [Lambda] A lambda that takes an array of inputs and a block, and
+ # maps the inputs with the block in parallel.
+ #
+ def execution_mode
+ @execution_mode || sequentially
+ end
+
+ def sequential_execution_mode!
+ self.execution_mode = sequentially
+ end
+
+ def sequentially
+ @sequentially ||= lambda do |inputs, &blk|
+ inputs.map(&blk)
+ end
end
def names
- Bundler::CompactIndexClient.debug { "names" }
- @parser.names
+ Bundler::CompactIndexClient.debug { "/names" }
+ update(@cache.names_path, "names")
+ @cache.names
end
def versions
- Bundler::CompactIndexClient.debug { "versions" }
- @parser.versions
+ Bundler::CompactIndexClient.debug { "/versions" }
+ update(@cache.versions_path, "versions")
+ versions, @info_checksums_by_name = @cache.versions
+ versions
end
def dependencies(names)
Bundler::CompactIndexClient.debug { "dependencies(#{names})" }
- names.map {|name| info(name) }
+ execution_mode.call(names) do |name|
+ update_info(name)
+ @cache.dependencies(name).map {|d| d.unshift(name) }
+ end.flatten(1)
end
- def info(name)
- Bundler::CompactIndexClient.debug { "info(#{name})" }
- @parser.info(name)
+ def update_and_parse_checksums!
+ Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" }
+ return @info_checksums_by_name if @parsed_checksums
+ update(@cache.versions_path, "versions")
+ @info_checksums_by_name = @cache.checksums
+ @parsed_checksums = true
+ end
+
+ private
+
+ def update(local_path, remote_path)
+ Bundler::CompactIndexClient.debug { "update(#{local_path}, #{remote_path})" }
+ unless synchronize { @endpoints.add?(remote_path) }
+ Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" }
+ return
+ end
+ @updater.update(local_path, url(remote_path))
end
- def latest_version(name)
- Bundler::CompactIndexClient.debug { "latest_version(#{name})" }
- @parser.info(name).map {|d| Gem::Version.new(d[INFO_VERSION]) }.max
+ def update_info(name)
+ Bundler::CompactIndexClient.debug { "update_info(#{name})" }
+ path = @cache.info_path(name)
+ checksum = @updater.checksum_for_file(path)
+ unless existing = @info_checksums_by_name[name]
+ Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since it is missing from versions" }
+ return
+ end
+ if checksum == existing
+ Bundler::CompactIndexClient.debug { "skipping updating info for #{name} since the versions checksum matches the local checksum" }
+ return
+ end
+ Bundler::CompactIndexClient.debug { "updating info for #{name} since the versions checksum #{existing} != the local checksum #{checksum}" }
+ update(path, "info/#{name}")
end
- def available?
- Bundler::CompactIndexClient.debug { "available?" }
- @parser.available?
+ def url(path)
+ path
end
- def reset!
- Bundler::CompactIndexClient.debug { "reset!" }
- @cache.reset!
+ def synchronize
+ @mutex.synchronize { yield }
end
end
end
diff --git a/lib/bundler/compact_index_client/cache.rb b/lib/bundler/compact_index_client/cache.rb
index bedd7f8028..0b43581c11 100644
--- a/lib/bundler/compact_index_client/cache.rb
+++ b/lib/bundler/compact_index_client/cache.rb
@@ -7,89 +7,94 @@ module Bundler
class Cache
attr_reader :directory
- def initialize(directory, fetcher = nil)
+ def initialize(directory)
@directory = Pathname.new(directory).expand_path
- @updater = Updater.new(fetcher) if fetcher
- @mutex = Thread::Mutex.new
- @endpoints = Set.new
-
- @info_root = mkdir("info")
- @special_characters_info_root = mkdir("info-special-characters")
- @info_etag_root = mkdir("info-etags")
+ info_roots.each do |dir|
+ SharedHelpers.filesystem_access(dir) do
+ FileUtils.mkdir_p(dir)
+ end
+ end
end
def names
- fetch("names", names_path, names_etag_path)
+ lines(names_path)
end
- def versions
- fetch("versions", versions_path, versions_etag_path)
+ def names_path
+ directory.join("names")
end
- def info(name, remote_checksum = nil)
- path = info_path(name)
-
- if remote_checksum && remote_checksum != SharedHelpers.checksum_for_file(path, :MD5)
- fetch("info/#{name}", path, info_etag_path(name))
- else
- Bundler::CompactIndexClient.debug { "update skipped info/#{name} (#{remote_checksum ? "versions index checksum is nil" : "versions index checksum matches local"})" }
- read(path)
+ def versions
+ versions_by_name = Hash.new {|hash, key| hash[key] = [] }
+ info_checksums_by_name = {}
+
+ lines(versions_path).each do |line|
+ name, versions_string, info_checksum = line.split(" ", 3)
+ info_checksums_by_name[name] = info_checksum || ""
+ versions_string.split(",").each do |version|
+ if version.start_with?("-")
+ version = version[1..-1].split("-", 2).unshift(name)
+ versions_by_name[name].delete(version)
+ else
+ version = version.split("-", 2).unshift(name)
+ versions_by_name[name] << version
+ end
+ end
end
- end
- def reset!
- @mutex.synchronize { @endpoints.clear }
+ [versions_by_name, info_checksums_by_name]
end
- private
+ def versions_path
+ directory.join("versions")
+ end
- def names_path = directory.join("names")
- def names_etag_path = directory.join("names.etag")
- def versions_path = directory.join("versions")
- def versions_etag_path = directory.join("versions.etag")
+ def checksums
+ checksums = {}
- def info_path(name)
- name = name.to_s
- # TODO: converge this into the info_root by hashing all filenames like info_etag_path
- if /[^a-z0-9_-]/.match?(name)
- name += "-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}"
- @special_characters_info_root.join(name)
- else
- @info_root.join(name)
+ lines(versions_path).each do |line|
+ name, _, checksum = line.split(" ", 3)
+ checksums[name] = checksum
end
- end
- def info_etag_path(name)
- name = name.to_s
- @info_etag_root.join("#{name}-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}")
+ checksums
end
- def mkdir(name)
- directory.join(name).tap do |dir|
- SharedHelpers.filesystem_access(dir) do
- FileUtils.mkdir_p(dir)
- end
+ def dependencies(name)
+ lines(info_path(name)).map do |line|
+ parse_gem(line)
end
end
- def fetch(remote_path, path, etag_path)
- if already_fetched?(remote_path)
- Bundler::CompactIndexClient.debug { "already fetched #{remote_path}" }
+ def info_path(name)
+ name = name.to_s
+ if /[^a-z0-9_-]/.match?(name)
+ name += "-#{SharedHelpers.digest(:MD5).hexdigest(name).downcase}"
+ info_roots.last.join(name)
else
- Bundler::CompactIndexClient.debug { "fetching #{remote_path}" }
- @updater&.update(remote_path, path, etag_path)
+ info_roots.first.join(name)
end
+ end
+
+ private
- read(path)
+ def lines(path)
+ return [] unless path.file?
+ lines = SharedHelpers.filesystem_access(path, :read, &:read).split("\n")
+ header = lines.index("---")
+ header ? lines[header + 1..-1] : lines
end
- def already_fetched?(remote_path)
- @mutex.synchronize { !@endpoints.add?(remote_path) }
+ def parse_gem(line)
+ @dependency_parser ||= GemParser.new
+ @dependency_parser.parse(line)
end
- def read(path)
- return unless path.file?
- SharedHelpers.filesystem_access(path, :read, &:read)
+ def info_roots
+ [
+ directory.join("info"),
+ directory.join("info-special-characters"),
+ ]
end
end
end
diff --git a/lib/bundler/compact_index_client/cache_file.rb b/lib/bundler/compact_index_client/cache_file.rb
deleted file mode 100644
index 299d683438..0000000000
--- a/lib/bundler/compact_index_client/cache_file.rb
+++ /dev/null
@@ -1,148 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../vendored_fileutils"
-require "rubygems/package"
-
-module Bundler
- class CompactIndexClient
- # write cache files in a way that is robust to concurrent modifications
- # if digests are given, the checksums will be verified
- class CacheFile
- DEFAULT_FILE_MODE = 0o644
- private_constant :DEFAULT_FILE_MODE
-
- class Error < RuntimeError; end
- class ClosedError < Error; end
-
- class DigestMismatchError < Error
- def initialize(digests, expected_digests)
- super "Calculated checksums #{digests.inspect} did not match expected #{expected_digests.inspect}."
- end
- end
-
- # Initialize with a copy of the original file, then yield the instance.
- def self.copy(path, &block)
- new(path) do |file|
- file.initialize_digests
-
- SharedHelpers.filesystem_access(path, :read) do
- path.open("rb") do |s|
- file.open {|f| IO.copy_stream(s, f) }
- end
- end
-
- yield file
- end
- end
-
- # Write data to a temp file, then replace the original file with it verifying the digests if given.
- def self.write(path, data, digests = nil)
- return unless data
- new(path) do |file|
- file.digests = digests
- file.write(data)
- end
- end
-
- attr_reader :original_path, :path
-
- def initialize(original_path, &block)
- @original_path = original_path
- @perm = original_path.file? ? original_path.stat.mode : DEFAULT_FILE_MODE
- @path = original_path.sub(/$/, ".#{$$}.tmp")
- return unless block_given?
- begin
- yield self
- ensure
- close
- end
- end
-
- def size
- path.size
- end
-
- # initialize the digests using CompactIndexClient::SUPPORTED_DIGESTS, or a subset based on keys.
- def initialize_digests(keys = nil)
- @digests = keys ? SUPPORTED_DIGESTS.slice(*keys) : SUPPORTED_DIGESTS.dup
- @digests.transform_values! {|algo_class| SharedHelpers.digest(algo_class).new }
- end
-
- # reset the digests so they don't contain any previously read data
- def reset_digests
- @digests&.each_value(&:reset)
- end
-
- # set the digests that will be verified at the end
- def digests=(expected_digests)
- @expected_digests = expected_digests
-
- if @expected_digests.nil?
- @digests = nil
- elsif @digests
- @digests = @digests.slice(*@expected_digests.keys)
- else
- initialize_digests(@expected_digests.keys)
- end
- end
-
- def digests?
- @digests&.any?
- end
-
- # Open the temp file for writing, reusing original permissions, yielding the IO object.
- def open(write_mode = "wb", perm = @perm, &block)
- raise ClosedError, "Cannot reopen closed file" if @closed
- SharedHelpers.filesystem_access(path, :write) do
- path.open(write_mode, perm) do |f|
- yield digests? ? Gem::Package::DigestIO.new(f, @digests) : f
- end
- end
- end
-
- # Returns false without appending when no digests since appending is too error prone to do without digests.
- def append(data)
- return false unless digests?
- open("a") {|f| f.write data }
- verify && commit
- end
-
- def write(data)
- reset_digests
- open {|f| f.write data }
- commit!
- end
-
- def commit!
- verify || raise(DigestMismatchError.new(@base64digests, @expected_digests))
- commit
- end
-
- # Verify the digests, returning true on match, false on mismatch.
- def verify
- return true unless @expected_digests && digests?
- @base64digests = @digests.transform_values!(&:base64digest)
- @digests = nil
- @base64digests.all? {|algo, digest| @expected_digests[algo] == digest }
- end
-
- # Replace the original file with the temp file without verifying digests.
- # The file is permanently closed.
- def commit
- raise ClosedError, "Cannot commit closed file" if @closed
- SharedHelpers.filesystem_access(original_path, :write) do
- FileUtils.mv(path, original_path)
- end
- @closed = true
- end
-
- # Remove the temp file without replacing the original file.
- # The file is permanently closed.
- def close
- return if @closed
- FileUtils.remove_file(path) if @path&.file?
- @closed = true
- end
- end
- end
-end
diff --git a/lib/bundler/compact_index_client/gem_parser.rb b/lib/bundler/compact_index_client/gem_parser.rb
index 60a1817607..e7bf4c6001 100644
--- a/lib/bundler/compact_index_client/gem_parser.rb
+++ b/lib/bundler/compact_index_client/gem_parser.rb
@@ -6,15 +6,12 @@ module Bundler
GemParser = Gem::Resolver::APISet::GemParser
else
class GemParser
- EMPTY_ARRAY = [].freeze
- private_constant :EMPTY_ARRAY
-
def parse(line)
version_and_platform, rest = line.split(" ", 2)
version, platform = version_and_platform.split("-", 2)
- dependencies, requirements = rest.split("|", 2).map! {|s| s.split(",") } if rest
- dependencies = dependencies ? dependencies.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
- requirements = requirements ? requirements.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
+ dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest
+ dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : []
+ requirements = requirements ? requirements.map {|d| parse_dependency(d) } : []
[version, platform, dependencies, requirements]
end
@@ -23,7 +20,6 @@ module Bundler
def parse_dependency(string)
dependency = string.split(":")
dependency[-1] = dependency[-1].split("&") if dependency.size > 1
- dependency[0] = -dependency[0]
dependency
end
end
diff --git a/lib/bundler/compact_index_client/parser.rb b/lib/bundler/compact_index_client/parser.rb
deleted file mode 100644
index 3276abdd68..0000000000
--- a/lib/bundler/compact_index_client/parser.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- class CompactIndexClient
- class Parser
- # `compact_index` - an object responding to #names, #versions, #info(name, checksum),
- # returning the file contents as a string
- def initialize(compact_index)
- @compact_index = compact_index
- @info_checksums = nil
- @versions_by_name = nil
- @available = nil
- @gem_parser = nil
- end
-
- def names
- lines(@compact_index.names)
- end
-
- def versions
- @versions_by_name ||= Hash.new {|hash, key| hash[key] = [] }
- @info_checksums = {}
-
- lines(@compact_index.versions).each do |line|
- name, versions_string, checksum = line.split(" ", 3)
- @info_checksums[name] = checksum || ""
- versions_string.split(",") do |version|
- delete = version.delete_prefix!("-")
- version = version.split("-", 2).unshift(name)
- if delete
- @versions_by_name[name].delete(version)
- else
- @versions_by_name[name] << version
- end
- end
- end
-
- @versions_by_name
- end
-
- def info(name)
- data = @compact_index.info(name, info_checksums[name])
- lines(data).map {|line| gem_parser.parse(line).unshift(name) }
- end
-
- def available?
- return @available unless @available.nil?
- @available = !info_checksums.empty?
- end
-
- private
-
- def info_checksums
- @info_checksums ||= lines(@compact_index.versions).each_with_object({}) do |line, checksums|
- parse_version_checksum(line, checksums)
- end
- end
-
- def lines(data)
- return [] if data.nil? || data.empty?
- lines = data.split("\n")
- header = lines.index("---")
- header ? lines[header + 1..-1] : lines
- end
-
- def gem_parser
- @gem_parser ||= GemParser.new
- end
-
- # This is mostly the same as `split(" ", 3)` but it avoids allocating extra objects.
- # This method gets called at least once for every gem when parsing versions.
- def parse_version_checksum(line, checksums)
- return unless (name_end = line.index(" ")) # Artifactory bug causes blank lines in artifactor index files
- return unless (checksum_start = line.index(" ", name_end + 1) + 1)
- checksum_end = line.size - checksum_start
-
- line.freeze # allows slicing into the string to not allocate a copy of the line
- name = line[0, name_end]
- checksum = line[checksum_start, checksum_end]
- checksums[name.freeze] = checksum # freeze name since it is used as a hash key
- end
- end
- end
-end
diff --git a/lib/bundler/compact_index_client/updater.rb b/lib/bundler/compact_index_client/updater.rb
index 88c7146900..0f7bf9bb50 100644
--- a/lib/bundler/compact_index_client/updater.rb
+++ b/lib/bundler/compact_index_client/updater.rb
@@ -1,11 +1,20 @@
# frozen_string_literal: true
+require_relative "../vendored_fileutils"
+
module Bundler
class CompactIndexClient
class Updater
- class MismatchedChecksumError < Error
- def initialize(path, message)
- super "The checksum of /#{path} does not match the checksum provided by the server! Something is wrong. #{message}"
+ class MisMatchedChecksumError < Error
+ def initialize(path, server_checksum, local_checksum)
+ @path = path
+ @server_checksum = server_checksum
+ @local_checksum = local_checksum
+ end
+
+ def message
+ "The checksum of /#{@path} does not match the checksum provided by the server! Something is wrong " \
+ "(local checksum is #{@local_checksum.inspect}, was expecting #{@server_checksum.inspect})."
end
end
@@ -13,91 +22,95 @@ module Bundler
@fetcher = fetcher
end
- def update(remote_path, local_path, etag_path)
- append(remote_path, local_path, etag_path) || replace(remote_path, local_path, etag_path)
- rescue CacheFile::DigestMismatchError => e
- raise MismatchedChecksumError.new(remote_path, e.message)
- rescue Zlib::GzipFile::Error
- raise Bundler::HTTPError
- end
+ def update(local_path, remote_path, retrying = nil)
+ headers = {}
- private
+ local_temp_path = local_path.sub(/$/, ".#{$$}")
+ local_temp_path = local_temp_path.sub(/$/, ".retrying") if retrying
+ local_temp_path = local_temp_path.sub(/$/, ".tmp")
+
+ # first try to fetch any new bytes on the existing file
+ if retrying.nil? && local_path.file?
+ copy_file local_path, local_temp_path
+
+ headers["If-None-Match"] = etag_for(local_temp_path)
+ headers["Range"] =
+ if local_temp_path.size.nonzero?
+ # Subtract a byte to ensure the range won't be empty.
+ # Avoids 416 (Range Not Satisfiable) responses.
+ "bytes=#{local_temp_path.size - 1}-"
+ else
+ "bytes=#{local_temp_path.size}-"
+ end
+ end
- def append(remote_path, local_path, etag_path)
- return false unless local_path.file? && local_path.size.nonzero?
+ response = @fetcher.call(remote_path, headers)
+ return nil if response.is_a?(Net::HTTPNotModified)
- CacheFile.copy(local_path) do |file|
- etag = etag_path.read.tap(&:chomp!) if etag_path.file?
+ content = response.body
- # Subtract a byte to ensure the range won't be empty.
- # Avoids 416 (Range Not Satisfiable) responses.
- response = @fetcher.call(remote_path, request_headers(etag, file.size - 1))
- break true if response.is_a?(Gem::Net::HTTPNotModified)
+ etag = (response["ETag"] || "").gsub(%r{\AW/}, "")
+ correct_response = SharedHelpers.filesystem_access(local_temp_path) do
+ if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero?
+ local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) }
- file.digests = parse_digests(response)
- # server may ignore Range and return the full response
- if response.is_a?(Gem::Net::HTTPPartialContent)
- break false unless file.append(response.body.byteslice(1..-1))
+ etag_for(local_temp_path) == etag
else
- file.write(response.body)
+ local_temp_path.open("wb") {|f| f << content }
+
+ etag.length.zero? || etag_for(local_temp_path) == etag
end
- CacheFile.write(etag_path, etag_from_response(response))
- true
end
- end
- # request without range header to get the full file or a 304 Not Modified
- def replace(remote_path, local_path, etag_path)
- etag = etag_path.read.tap(&:chomp!) if etag_path.file?
- response = @fetcher.call(remote_path, request_headers(etag))
- return true if response.is_a?(Gem::Net::HTTPNotModified)
- CacheFile.write(local_path, response.body, parse_digests(response))
- CacheFile.write(etag_path, etag_from_response(response))
- end
+ if correct_response
+ SharedHelpers.filesystem_access(local_path) do
+ FileUtils.mv(local_temp_path, local_path)
+ end
+ return nil
+ end
- def request_headers(etag, range_start = nil)
- headers = {}
- headers["Range"] = "bytes=#{range_start}-" if range_start
- headers["If-None-Match"] = %("#{etag}") if etag
- headers
+ if retrying
+ raise MisMatchedChecksumError.new(remote_path, etag, etag_for(local_temp_path))
+ end
+
+ update(local_path, remote_path, :retrying)
+ rescue Zlib::GzipFile::Error
+ raise Bundler::HTTPError
+ ensure
+ FileUtils.remove_file(local_temp_path) if File.exist?(local_temp_path)
end
- def etag_for_request(etag_path)
- etag_path.read.tap(&:chomp!) if etag_path.file?
+ def etag_for(path)
+ sum = checksum_for_file(path)
+ sum ? %("#{sum}") : nil
end
- def etag_from_response(response)
- return unless response["ETag"]
- etag = response["ETag"].delete_prefix("W/")
- return if etag.delete_prefix!('"') && !etag.delete_suffix!('"')
- etag
+ def slice_body(body, range)
+ body.byteslice(range)
end
- # Unwraps and returns a Hash of digest algorithms and base64 values
- # according to RFC 8941 Structured Field Values for HTTP.
- # https://www.rfc-editor.org/rfc/rfc8941#name-parsing-a-byte-sequence
- # Ignores unsupported algorithms.
- def parse_digests(response)
- return unless header = response["Repr-Digest"] || response["Digest"]
- digests = {}
- header.split(",") do |param|
- algorithm, value = param.split("=", 2)
- algorithm.strip!
- algorithm.downcase!
- next unless SUPPORTED_DIGESTS.key?(algorithm)
- next unless value = byte_sequence(value)
- digests[algorithm] = value
+ def checksum_for_file(path)
+ return nil unless path.file?
+ # This must use File.read instead of Digest.file().hexdigest
+ # because we need to preserve \n line endings on windows when calculating
+ # the checksum
+ SharedHelpers.filesystem_access(path, :read) do
+ SharedHelpers.digest(:MD5).hexdigest(File.read(path))
end
- digests.empty? ? nil : digests
end
- # Unwrap surrounding colons (byte sequence)
- # The wrapping characters must be matched or we return nil.
- # Also handles quotes because right now rubygems.org sends them.
- def byte_sequence(value)
- return if value.delete_prefix!(":") && !value.delete_suffix!(":")
- return if value.delete_prefix!('"') && !value.delete_suffix!('"')
- value
+ private
+
+ def copy_file(source, dest)
+ SharedHelpers.filesystem_access(source, :read) do
+ File.open(source, "r") do |s|
+ SharedHelpers.filesystem_access(dest, :write) do
+ File.open(dest, "wb", s.stat.mode) do |f|
+ IO.copy_stream(s, f)
+ end
+ end
+ end
+ end
end
end
end
diff --git a/lib/bundler/constants.rb b/lib/bundler/constants.rb
index 9564771e78..8dd8a53815 100644
--- a/lib/bundler/constants.rb
+++ b/lib/bundler/constants.rb
@@ -1,14 +1,7 @@
# frozen_string_literal: true
-require "rbconfig"
-
module Bundler
WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/
- deprecate_constant :WINDOWS
-
FREEBSD = RbConfig::CONFIG["host_os"].to_s.include?("bsd")
- deprecate_constant :FREEBSD
-
- NULL = File::NULL
- deprecate_constant :NULL
+ NULL = WINDOWS ? "NUL" : "/dev/null"
end
diff --git a/lib/bundler/current_ruby.rb b/lib/bundler/current_ruby.rb
index 93e0c401c0..f009b07ad7 100644
--- a/lib/bundler/current_ruby.rb
+++ b/lib/bundler/current_ruby.rb
@@ -43,7 +43,7 @@ module Bundler
].freeze
def ruby?
- return true if Bundler::GemHelpers.generic_local_platform_is_ruby?
+ return true if Bundler::GemHelpers.generic_local_platform == Gem::Platform::RUBY
!windows? && (RUBY_ENGINE == "ruby" || RUBY_ENGINE == "rbx" || RUBY_ENGINE == "maglev" || RUBY_ENGINE == "truffleruby")
end
@@ -71,10 +71,26 @@ module Bundler
def windows?
Gem.win_platform?
end
- alias_method :mswin?, :windows?
- alias_method :mswin64?, :windows?
- alias_method :mingw?, :windows?
- alias_method :x64_mingw?, :windows?
+
+ def mswin?
+ # For backwards compatibility
+ windows?
+
+ # TODO: This should correctly be:
+ # windows? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin32" && Bundler.local_platform.cpu == "x86"
+ end
+
+ def mswin64?
+ windows? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mswin64" && Bundler.local_platform.cpu == "x64"
+ end
+
+ def mingw?
+ windows? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os == "mingw32" && Bundler.local_platform.cpu != "x64"
+ end
+
+ def x64_mingw?
+ Gem.win_platform? && Bundler.local_platform != Gem::Platform::RUBY && Bundler.local_platform.os.start_with?("mingw") && Bundler.local_platform.cpu == "x64"
+ end
(KNOWN_MINOR_VERSIONS + KNOWN_MAJOR_VERSIONS).each do |version|
trimmed_version = version.tr(".", "")
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index bb6eb11e4e..564530a98c 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -18,8 +18,7 @@ module Bundler
:platforms,
:ruby_version,
:lockfile,
- :gemfiles,
- :locked_checksums
+ :gemfiles
)
# Given a gemfile and lockfile creates a Bundler definition
@@ -69,6 +68,7 @@ module Bundler
@sources = sources
@unlock = unlock
@optional_groups = optional_groups
+ @remote = false
@prefer_local = false
@specs = nil
@ruby_version = ruby_version
@@ -81,22 +81,20 @@ module Bundler
@resolved_bundler_version = nil
@locked_ruby_version = nil
- @new_platforms = []
+ @new_platform = nil
@removed_platform = nil
- if lockfile_exists?
+ if lockfile && File.exist?(lockfile)
@lockfile_contents = Bundler.read_file(lockfile)
@locked_gems = LockfileParser.new(@lockfile_contents)
@locked_platforms = @locked_gems.platforms
@platforms = @locked_platforms.dup
@locked_bundler_version = @locked_gems.bundler_version
@locked_ruby_version = @locked_gems.ruby_version
- @originally_locked_deps = @locked_gems.dependencies
@originally_locked_specs = SpecSet.new(@locked_gems.specs)
- @locked_checksums = @locked_gems.checksums
if unlock != true
- @locked_deps = @originally_locked_deps
+ @locked_deps = @locked_gems.dependencies
@locked_specs = @originally_locked_specs
@locked_sources = @locked_gems.sources
else
@@ -111,11 +109,9 @@ module Bundler
@locked_gems = nil
@locked_deps = {}
@locked_specs = SpecSet.new([])
- @originally_locked_deps = {}
@originally_locked_specs = @locked_specs
@locked_sources = []
@locked_platforms = []
- @locked_checksums = Bundler.feature_flag.bundler_3_mode?
end
locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
@@ -131,31 +127,29 @@ module Bundler
@sources.merged_gem_lockfile_sections!(locked_gem_sources.first)
end
- @sources_to_unlock = @unlock.delete(:sources) || []
+ @unlock[:sources] ||= []
@unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object
@ruby_version.diff(locked_ruby_version_object)
end
@unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
- @current_platform_missing = add_current_platform unless Bundler.frozen_bundle?
+ add_current_platform unless Bundler.frozen_bundle?
converge_path_sources_to_gemspec_sources
@path_changes = converge_paths
@source_changes = converge_sources
- @explicit_unlocks = @unlock.delete(:gems) || []
-
if @unlock[:conservative]
- @gems_to_unlock = @explicit_unlocks.any? ? @explicit_unlocks : @dependencies.map(&:name)
+ @unlock[:gems] ||= @dependencies.map(&:name)
else
- eager_unlock = @explicit_unlocks.map {|name| Dependency.new(name, ">= 0") }
- @gems_to_unlock = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq
+ eager_unlock = (@unlock[:gems] || []).map {|name| Dependency.new(name, ">= 0") }
+ @unlock[:gems] = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq
end
@dependency_changes = converge_dependencies
@local_changes = converge_locals
- check_lockfile
+ @missing_lockfile_dep = check_missing_lockfile_dep
end
def gem_version_promoter
@@ -163,24 +157,37 @@ module Bundler
end
def resolve_only_locally!
+ @remote = false
sources.local_only!
resolve
end
def resolve_with_cache!
- sources.local!
sources.cached!
resolve
end
def resolve_remotely!
- sources.cached!
+ @remote = true
sources.remote!
resolve
end
- def prefer_local!
- @prefer_local = true
+ def resolution_mode=(options)
+ if options["local"]
+ @remote = false
+ else
+ @remote = true
+ @prefer_local = options["prefer-local"]
+ end
+ end
+
+ def setup_sources_for_resolve
+ if @remote == false
+ sources.cached!
+ else
+ sources.remote!
+ end
end
# For given dependency list returns a SpecSet with Gemspec of all the required
@@ -214,8 +221,8 @@ module Bundler
@resolve = nil
@resolver = nil
@resolution_packages = nil
- @source_requirements = nil
@specs = nil
+ @gem_version_promoter = nil
Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})"
true
@@ -238,9 +245,8 @@ module Bundler
end
def filter_relevant(dependencies)
- platforms_array = [generic_local_platform].freeze
dependencies.select do |d|
- d.should_include? && !d.gem_platforms(platforms_array).empty?
+ d.should_include? && !d.gem_platforms([generic_local_platform]).empty?
end
end
@@ -264,11 +270,9 @@ module Bundler
def dependencies_for(groups)
groups.map!(&:to_sym)
- deps = current_dependencies # always returns a new array
- deps.select! do |d|
- d.groups.intersect?(groups)
+ current_dependencies.reject do |d|
+ (d.groups & groups).empty?
end
- deps
end
# Resolve all the dependencies specified in Gemfile. It ensures that
@@ -293,12 +297,7 @@ module Bundler
end
end
else
- if lockfile_exists?
- Bundler.ui.debug "Found changes from the lockfile, re-resolving dependencies because #{change_reason}"
- else
- Bundler.ui.debug "Resolving dependencies because there's no lockfile"
- end
-
+ Bundler.ui.debug "Found changes from the lockfile, re-resolving dependencies because #{change_reason}"
start_resolution
end
end
@@ -311,26 +310,34 @@ module Bundler
dependencies.map(&:groups).flatten.uniq
end
- def lock(file_or_preserve_unknown_sections = false, preserve_unknown_sections_or_unused = false)
- if [true, false, nil].include?(file_or_preserve_unknown_sections)
- target_lockfile = lockfile
- preserve_unknown_sections = file_or_preserve_unknown_sections
- else
- target_lockfile = file_or_preserve_unknown_sections
- preserve_unknown_sections = preserve_unknown_sections_or_unused
+ def lock(file, preserve_unknown_sections = false)
+ return if Definition.no_lock
- suggestion = if target_lockfile == lockfile
- "To fix this warning, remove it from the `Definition#lock` call."
- else
- "Instead, instantiate a new definition passing `#{target_lockfile}`, and call `lock` without a file argument on that definition"
- end
+ contents = to_lock
- msg = "`Definition#lock` was passed a target file argument. #{suggestion}"
+ # Convert to \r\n if the existing lock has them
+ # i.e., Windows with `git config core.autocrlf=true`
+ contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match?("\r\n")
+
+ if @locked_bundler_version
+ locked_major = @locked_bundler_version.segments.first
+ current_major = bundler_version_to_lock.segments.first
- Bundler::SharedHelpers.major_deprecation 2, msg
+ updating_major = locked_major < current_major
end
- write_lock(target_lockfile, preserve_unknown_sections)
+ preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
+
+ return if file && File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
+
+ if Bundler.frozen_bundle?
+ Bundler.ui.error "Cannot write a changed lockfile while frozen."
+ return
+ end
+
+ SharedHelpers.filesystem_access(file) do |p|
+ File.open(p, "wb") {|f| f.puts(contents) }
+ end
end
def locked_ruby_version
@@ -364,10 +371,6 @@ module Bundler
end
def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
- return unless Bundler.frozen_bundle?
-
- raise ProductionError, "Frozen mode is set, but there's no lockfile" unless lockfile_exists?
-
added = []
deleted = []
changed = []
@@ -396,19 +399,19 @@ module Bundler
changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`"
end
- reason = nothing_changed? ? "some dependencies were deleted from your gemfile" : change_reason
+ reason = change_reason
msg = String.new
msg << "#{reason.capitalize.strip}, but the lockfile can't be updated because frozen mode is set"
msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any?
msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any?
- msg << "\n\nRun `bundle install` elsewhere and add the updated #{SharedHelpers.relative_gemfile_path} to version control.\n"
+ msg << "\n\nRun `bundle install` elsewhere and add the updated #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} to version control.\n"
unless explicit_flag
suggested_command = unless Bundler.settings.locations("frozen").keys.include?(:env)
"bundle config set frozen false"
end
- msg << "If this is a development machine, remove the #{SharedHelpers.relative_lockfile_path} " \
+ msg << "If this is a development machine, remove the #{Bundler.default_gemfile.relative_path_from(SharedHelpers.pwd)} " \
"freeze by running `#{suggested_command}`." if suggested_command
end
@@ -449,15 +452,13 @@ module Bundler
return if current_platform_locked?
raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \
- "but your local platform is #{local_platform}. " \
- "Add the current platform to the lockfile with\n`bundle lock --add-platform #{local_platform}` and try again."
+ "but your local platform is #{Bundler.local_platform}. " \
+ "Add the current platform to the lockfile with\n`bundle lock --add-platform #{Bundler.local_platform}` and try again."
end
def add_platform(platform)
- return if @platforms.include?(platform)
-
- @new_platforms << platform
- @platforms << platform
+ @new_platform ||= !@platforms.include?(platform)
+ @platforms |= [platform]
end
def remove_platform(platform)
@@ -473,19 +474,11 @@ module Bundler
end
end
- def nothing_changed?
- return false unless lockfile_exists?
+ attr_reader :sources
+ private :sources
- !@source_changes &&
- !@dependency_changes &&
- !@current_platform_missing &&
- @new_platforms.empty? &&
- !@path_changes &&
- !@local_changes &&
- !@missing_lockfile_dep &&
- !@unlocking_bundler &&
- !@locked_spec_with_missing_deps &&
- !@locked_spec_with_invalid_deps
+ def nothing_changed?
+ !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@missing_lockfile_dep && !@unlocking_bundler
end
def no_resolve_needed?
@@ -496,54 +489,8 @@ module Bundler
@unlocking
end
- attr_writer :source_requirements
-
private
- attr_reader :sources
-
- def should_add_extra_platforms?
- !lockfile_exists? && generic_local_platform_is_ruby? && !Bundler.settings[:force_ruby_platform]
- end
-
- def lockfile_exists?
- lockfile && File.exist?(lockfile)
- end
-
- def write_lock(file, preserve_unknown_sections)
- return if Definition.no_lock || file.nil?
-
- contents = to_lock
-
- # Convert to \r\n if the existing lock has them
- # i.e., Windows with `git config core.autocrlf=true`
- contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match?("\r\n")
-
- if @locked_bundler_version
- locked_major = @locked_bundler_version.segments.first
- current_major = bundler_version_to_lock.segments.first
-
- updating_major = locked_major < current_major
- end
-
- preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
-
- if File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
- return if Bundler.frozen_bundle?
- SharedHelpers.filesystem_access(file) { FileUtils.touch(file) }
- return
- end
-
- if Bundler.frozen_bundle?
- Bundler.ui.error "Cannot write a changed lockfile while frozen."
- return
- end
-
- SharedHelpers.filesystem_access(file) do |p|
- File.open(p, "wb") {|f| f.puts(contents) }
- end
- end
-
def resolver
@resolver ||= Resolver.new(resolution_packages, gem_version_promoter)
end
@@ -554,7 +501,7 @@ module Bundler
def dependencies_with_bundler
return dependencies unless @unlocking_bundler
- return dependencies if dependencies.any? {|d| d.name == "bundler" }
+ return dependencies if dependencies.map(&:name).include?("bundler")
[Dependency.new("bundler", @unlocking_bundler)] + dependencies
end
@@ -562,11 +509,9 @@ module Bundler
def resolution_packages
@resolution_packages ||= begin
last_resolve = converge_locked_specs
- remove_invalid_platforms!
- packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @gems_to_unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local)
- packages = additional_base_requirements_to_prevent_downgrades(packages, last_resolve)
- packages = additional_base_requirements_to_force_updates(packages)
- packages
+ remove_ruby_from_platforms_if_necessary!(current_dependencies)
+ packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, :locked_specs => @originally_locked_specs, :unlock => @unlock[:gems], :prerelease => gem_version_promoter.pre?)
+ additional_base_requirements_for_resolve(packages, last_resolve)
end
end
@@ -581,7 +526,7 @@ module Bundler
if missing_specs.any?
missing_specs.each do |s|
locked_gem = @locked_specs[s.name].last
- next if locked_gem.nil? || locked_gem.version != s.version || sources.local_mode?
+ next if locked_gem.nil? || locked_gem.version != s.version || !@remote
raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \
"no longer be found in that source. That means the author of #{locked_gem} has removed it. " \
"You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \
@@ -600,7 +545,7 @@ module Bundler
break if incomplete_specs.empty?
Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies")
- sources.remote!
+ setup_sources_for_resolve
resolution_packages.delete(incomplete_specs)
@resolve = start_resolution
specs = resolve.materialize(dependencies)
@@ -622,80 +567,69 @@ module Bundler
end
def start_resolution
- local_platform_needed_for_resolvability = @most_specific_non_local_locked_ruby_platform && !@platforms.include?(local_platform)
- @platforms << local_platform if local_platform_needed_for_resolvability
- add_platform(Gem::Platform::RUBY) if RUBY_ENGINE == "truffleruby"
-
- result = SpecSet.new(resolver.start)
+ result = resolver.start
@resolved_bundler_version = result.find {|spec| spec.name == "bundler" }&.version
- if @most_specific_non_local_locked_ruby_platform
- if spec_set_incomplete_for_platform?(result, @most_specific_non_local_locked_ruby_platform)
- @platforms.delete(@most_specific_non_local_locked_ruby_platform)
- elsif local_platform_needed_for_resolvability
- @platforms.delete(local_platform)
- end
- end
-
- @platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms?
-
- SpecSet.new(result.for(dependencies, false, @platforms))
+ SpecSet.new(SpecSet.new(result).for(dependencies, false, @platforms))
end
def precompute_source_requirements_for_indirect_dependencies?
sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source?
end
- def current_platform_locked?
- @platforms.any? do |bundle_platform|
- MatchPlatform.platforms_match?(bundle_platform, local_platform)
+ def pin_locally_available_names(source_requirements)
+ source_requirements.each_with_object({}) do |(name, original_source), new_source_requirements|
+ local_source = original_source.dup
+ local_source.local_only!
+
+ new_source_requirements[name] = if local_source.specs.search(name).any?
+ local_source
+ else
+ original_source
+ end
end
end
- def add_current_platform
- return if @platforms.include?(local_platform)
+ def current_ruby_platform_locked?
+ return false unless generic_local_platform == Gem::Platform::RUBY
+ return false if Bundler.settings[:force_ruby_platform] && !@platforms.include?(Gem::Platform::RUBY)
- @most_specific_non_local_locked_ruby_platform = find_most_specific_locked_ruby_platform
- return if @most_specific_non_local_locked_ruby_platform
+ current_platform_locked?
+ end
- @platforms << local_platform
- true
+ def current_platform_locked?
+ @platforms.any? do |bundle_platform|
+ MatchPlatform.platforms_match?(bundle_platform, Bundler.local_platform)
+ end
end
- def find_most_specific_locked_ruby_platform
- return unless generic_local_platform_is_ruby? && current_platform_locked?
+ def add_current_platform
+ return if current_ruby_platform_locked?
- most_specific_locked_platform
+ add_platform(local_platform)
end
def change_reason
if unlocking?
- unlock_targets = if @gems_to_unlock.any?
- ["gems", @gems_to_unlock]
- elsif @sources_to_unlock.any?
- ["sources", @sources_to_unlock]
- end
-
- unlock_reason = if unlock_targets
- "#{unlock_targets.first}: (#{unlock_targets.last.join(", ")})"
- else
- @unlock[:ruby] ? "ruby" : ""
- end
-
+ unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v|
+ if v == true
+ k.to_s
+ else
+ v = Array(v)
+ "#{k}: (#{v.join(", ")})"
+ end
+ end.join(", ")
return "bundler is unlocking #{unlock_reason}"
end
[
[@source_changes, "the list of sources changed"],
[@dependency_changes, "the dependencies in your gemfile changed"],
- [@current_platform_missing, "your lockfile does not include the current platform"],
- [@new_platforms.any?, "you added a new platform to your gemfile"],
+ [@new_platform, "you added a new platform to your gemfile"],
[@path_changes, "the gemspecs for path gems changed"],
[@local_changes, "the gemspecs for git local gems changed"],
[@missing_lockfile_dep, "your lock file is missing \"#{@missing_lockfile_dep}\""],
[@unlocking_bundler, "an update to the version of Bundler itself was requested"],
- [@locked_spec_with_missing_deps, "your lock file includes \"#{@locked_spec_with_missing_deps}\" but not some of its dependencies"],
- [@locked_spec_with_invalid_deps, "your lockfile does not satisfy dependencies of \"#{@locked_spec_with_invalid_deps}\""],
].select(&:first).map(&:last).join(", ")
end
@@ -722,7 +656,8 @@ module Bundler
locked_index = Index.new
locked_index.use(@locked_specs.select {|s| source.can_lock?(s) })
- !locked_index.subset?(source.specs)
+ # order here matters, since Index#== is checking source.specs.include?(locked_index)
+ locked_index != source.specs
rescue PathError, GitError => e
Bundler.ui.debug "Assuming that #{source} has not changed since fetching its specs errored (#{e})"
false
@@ -738,7 +673,7 @@ module Bundler
spec = @dependencies.find {|s| s.name == k }
source = spec&.source
if source&.respond_to?(:local_override!)
- source.unlock! if @gems_to_unlock.include?(spec.name)
+ source.unlock! if @unlock[:gems].include?(spec.name)
locals << [source, source.local_override!(v)]
end
end
@@ -746,40 +681,27 @@ module Bundler
sources_with_changes = locals.select do |source, changed|
changed || specs_changed?(source)
end.map(&:first)
- !sources_with_changes.each {|source| @sources_to_unlock << source.name }.empty?
+ !sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty?
end
- def check_lockfile
- @missing_lockfile_dep = nil
-
- @locked_spec_with_invalid_deps = nil
- @locked_spec_with_missing_deps = nil
+ def check_missing_lockfile_dep
+ all_locked_specs = @locked_specs.map(&:name) << "bundler"
- missing = []
- invalid = []
-
- @locked_specs.each do |s|
- validation = @locked_specs.validate_deps(s)
-
- missing << s if validation == :missing
- invalid << s if validation == :invalid
+ missing = @locked_specs.select do |s|
+ s.dependencies.any? {|dep| !all_locked_specs.include?(dep.name) }
end
if missing.any?
@locked_specs.delete(missing)
- @locked_spec_with_missing_deps = missing.first.name
- elsif !@dependency_changes
- @missing_lockfile_dep = current_dependencies.find do |d|
- @locked_specs[d.name].empty? && d.name != "bundler"
- end&.name
+ return missing.first.name
end
- if invalid.any?
- @locked_specs.delete(invalid)
+ return if @dependency_changes
- @locked_spec_with_invalid_deps = invalid.first.name
- end
+ current_dependencies.find do |d|
+ @locked_specs[d.name].empty? && d.name != "bundler"
+ end&.name
end
def converge_paths
@@ -813,17 +735,12 @@ module Bundler
changes = sources.replace_sources!(@locked_sources)
sources.all_sources.each do |source|
- # has to be done separately, because we want to keep the locked checksum
- # store for a source, even when doing a full update
- if @locked_checksums && @locked_gems && locked_source = @locked_gems.sources.find {|s| s == source && !s.equal?(source) }
- source.checksum_store.merge!(locked_source.checksum_store)
- end
# If the source is unlockable and the current command allows an unlock of
# the source (for example, you are doing a `bundle update <foo>` of a git-pinned
# gem), unlock it. For git sources, this means to unlock the revision, which
# will cause the `ref` used to be the most recent for the branch (or master) if
# an explicit `ref` is not used.
- if source.respond_to?(:unlock!) && @sources_to_unlock.include?(source.name)
+ if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name)
source.unlock!
changes = true
end
@@ -840,7 +757,9 @@ module Bundler
dep.source = sources.get(dep.source)
end
- unless locked_dep = @originally_locked_deps[dep.name]
+ next if unlocking?
+
+ unless locked_dep = @locked_deps[dep.name]
changes = true
next
end
@@ -867,7 +786,7 @@ module Bundler
def converge_locked_specs
converged = converge_specs(@locked_specs)
- resolve = SpecSet.new(converged.reject {|s| @gems_to_unlock.include?(s.name) })
+ resolve = SpecSet.new(converged.reject {|s| @unlock[:gems].include?(s.name) })
diff = nil
@@ -900,7 +819,7 @@ module Bundler
@specs_that_changed_sources << s if gemfile_source != lockfile_source
deps << dep if !dep.source || lockfile_source.include?(dep.source)
- @gems_to_unlock << name if lockfile_source.include?(dep.source) && lockfile_source != gemfile_source
+ @unlock[:gems] << name if lockfile_source.include?(dep.source) && lockfile_source != gemfile_source
# Replace the locked dependency's source with the equivalent source from the Gemfile
s.source = gemfile_source
@@ -909,7 +828,7 @@ module Bundler
s.source = default_source unless sources.get(lockfile_source)
end
- next if @sources_to_unlock.include?(s.source.name)
+ next if @unlock[:sources].include?(s.source.name)
# Path sources have special logic
if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec)
@@ -931,12 +850,12 @@ module Bundler
else
# If the spec is no longer in the path source, unlock it. This
# commonly happens if the version changed in the gemspec
- @gems_to_unlock << name
+ @unlock[:gems] << name
end
end
if dep.nil? && requested_dependencies.find {|d| name == d.name }
- @gems_to_unlock << s.name
+ @unlock[:gems] << s.name
else
converged << s
end
@@ -947,26 +866,23 @@ module Bundler
def metadata_dependencies
@metadata_dependencies ||= [
- Dependency.new("Ruby\0", Bundler::RubyVersion.system.gem_version),
+ Dependency.new("Ruby\0", Gem.ruby_version),
Dependency.new("RubyGems\0", Gem::VERSION),
]
end
def source_requirements
- @source_requirements ||= find_source_requirements
- end
-
- def find_source_requirements
# Record the specs available in each gem's source, so that those
# specs will be available later when the resolver knows where to
# look for that gemspec (or its dependencies)
source_requirements = if precompute_source_requirements_for_indirect_dependencies?
all_requirements = source_map.all_requirements
- { default: default_source }.merge(all_requirements)
+ all_requirements = pin_locally_available_names(all_requirements) if @prefer_local
+ { :default => default_source }.merge(all_requirements)
else
- { default: Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements)
+ { :default => Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements)
end
- source_requirements.merge!(source_map.locked_requirements) if nothing_changed?
+ source_requirements.merge!(source_map.locked_requirements) unless @remote
metadata_dependencies.each do |dep|
source_requirements[dep.name] = sources.metadata_source
end
@@ -1016,7 +932,7 @@ module Bundler
current == proposed
end
- def additional_base_requirements_to_prevent_downgrades(resolution_packages, last_resolve)
+ def additional_base_requirements_for_resolve(resolution_packages, last_resolve)
return resolution_packages unless @locked_gems && !sources.expired_sources?(@locked_gems.sources)
converge_specs(@originally_locked_specs - last_resolve).each do |locked_spec|
next if locked_spec.source.is_a?(Source::Path)
@@ -1025,44 +941,17 @@ module Bundler
resolution_packages
end
- def additional_base_requirements_to_force_updates(resolution_packages)
- return resolution_packages if @explicit_unlocks.empty?
- full_update = dup_for_full_unlock.resolve
- @explicit_unlocks.each do |name|
- version = full_update[name].first&.version
- resolution_packages.base_requirements[name] = Gem::Requirement.new("= #{version}") if version
- end
- resolution_packages
- end
-
- def dup_for_full_unlock
- unlocked_definition = self.class.new(@lockfile, @dependencies, @sources, true, @ruby_version, @optional_groups, @gemfiles)
- unlocked_definition.source_requirements = source_requirements
- unlocked_definition.gem_version_promoter.tap do |gvp|
- gvp.level = gem_version_promoter.level
- gvp.strict = gem_version_promoter.strict
- gvp.pre = gem_version_promoter.pre
- end
- unlocked_definition
- end
-
- def remove_invalid_platforms!
- return if Bundler.frozen_bundle?
-
- platforms.reverse_each do |platform|
- next if local_platform == platform ||
- @new_platforms.include?(platform) ||
+ def remove_ruby_from_platforms_if_necessary!(dependencies)
+ return if Bundler.frozen_bundle? ||
+ Bundler.local_platform == Gem::Platform::RUBY ||
+ !platforms.include?(Gem::Platform::RUBY) ||
+ (@new_platform && platforms.last == Gem::Platform::RUBY) ||
@path_changes ||
@dependency_changes ||
- @locked_spec_with_invalid_deps ||
- !spec_set_incomplete_for_platform?(@originally_locked_specs, platform)
-
- remove_platform(platform)
- end
- end
+ !@originally_locked_specs.incomplete_ruby_specs?(dependencies)
- def spec_set_incomplete_for_platform?(spec_set, platform)
- spec_set.incomplete_for_platform?(current_dependencies, platform)
+ remove_platform(Gem::Platform::RUBY)
+ add_current_platform
end
def source_map
diff --git a/lib/bundler/dependency.rb b/lib/bundler/dependency.rb
index 2a4f72fe55..5f17943629 100644
--- a/lib/bundler/dependency.rb
+++ b/lib/bundler/dependency.rb
@@ -7,21 +7,20 @@ require_relative "rubygems_ext"
module Bundler
class Dependency < Gem::Dependency
attr_reader :autorequire
- attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref, :glob
+ attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref
- ALL_RUBY_VERSIONS = (18..27).to_a.concat((30..34).to_a).freeze
+ ALL_RUBY_VERSIONS = ((18..27).to_a + (30..33).to_a).freeze
PLATFORM_MAP = {
- ruby: [Gem::Platform::RUBY, ALL_RUBY_VERSIONS],
- mri: [Gem::Platform::RUBY, ALL_RUBY_VERSIONS],
- rbx: [Gem::Platform::RUBY],
- truffleruby: [Gem::Platform::RUBY],
- jruby: [Gem::Platform::JAVA, [18, 19]],
- windows: [Gem::Platform::WINDOWS, ALL_RUBY_VERSIONS],
- # deprecated
- mswin: [Gem::Platform::MSWIN, ALL_RUBY_VERSIONS],
- mswin64: [Gem::Platform::MSWIN64, ALL_RUBY_VERSIONS - [18]],
- mingw: [Gem::Platform::MINGW, ALL_RUBY_VERSIONS],
- x64_mingw: [Gem::Platform::X64_MINGW, ALL_RUBY_VERSIONS - [18, 19]],
+ :ruby => [Gem::Platform::RUBY, ALL_RUBY_VERSIONS],
+ :mri => [Gem::Platform::RUBY, ALL_RUBY_VERSIONS],
+ :rbx => [Gem::Platform::RUBY],
+ :truffleruby => [Gem::Platform::RUBY],
+ :jruby => [Gem::Platform::JAVA, [18, 19]],
+ :windows => [Gem::Platform::WINDOWS, ALL_RUBY_VERSIONS],
+ :mswin => [Gem::Platform::MSWIN, ALL_RUBY_VERSIONS],
+ :mswin64 => [Gem::Platform::MSWIN64, ALL_RUBY_VERSIONS - [18]],
+ :mingw => [Gem::Platform::MINGW, ALL_RUBY_VERSIONS],
+ :x64_mingw => [Gem::Platform::X64_MINGW, ALL_RUBY_VERSIONS - [18, 19]],
}.each_with_object({}) do |(platform, spec), hash|
hash[platform] = spec[0]
spec[1]&.each {|version| hash[:"#{platform}_#{version}"] = spec[0] }
@@ -39,7 +38,6 @@ module Bundler
@github = options["github"]
@branch = options["branch"]
@ref = options["ref"]
- @glob = options["glob"]
@platforms = Array(options["platforms"])
@env = options["env"]
@should_include = options.fetch("should_include", true)
@@ -49,13 +47,10 @@ module Bundler
@autorequire = Array(options["require"] || []) if options.key?("require")
end
- RUBY_PLATFORM_ARRAY = [Gem::Platform::RUBY].freeze
- private_constant :RUBY_PLATFORM_ARRAY
-
# Returns the platforms this dependency is valid for, in the same order as
# passed in the `valid_platforms` parameter
def gem_platforms(valid_platforms)
- return RUBY_PLATFORM_ARRAY if force_ruby_platform
+ return [Gem::Platform::RUBY] if force_ruby_platform
return valid_platforms if @platforms.empty?
valid_platforms.select {|p| expanded_platforms.include?(GemHelpers.generic(p)) }
@@ -69,10 +64,6 @@ module Bundler
@should_include && current_env? && current_platform?
end
- def gemspec_dev_dep?
- type == :development
- end
-
def current_env?
return true unless @env
if @env.is_a?(Hash)
diff --git a/lib/bundler/digest.rb b/lib/bundler/digest.rb
index 2c6d971f1b..f11f5edd38 100644
--- a/lib/bundler/digest.rb
+++ b/lib/bundler/digest.rb
@@ -26,7 +26,7 @@ module Bundler
end
a, b, c, d, e = *words
(16..79).each do |i|
- w[i] = SHA1_MASK & rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1)
+ w[i] = SHA1_MASK & rotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1)
end
0.upto(79) do |i|
case i
@@ -50,7 +50,7 @@ module Bundler
words.map!.with_index {|word, index| SHA1_MASK & (word + mutated[index]) }
end
- words.pack("N*").unpack1("H*")
+ words.pack("N*").unpack("H*").first
end
private
diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb
index aad8759652..03c80a408c 100644
--- a/lib/bundler/dsl.rb
+++ b/lib/bundler/dsl.rb
@@ -18,10 +18,9 @@ module Bundler
VALID_KEYS = %w[group groups git path glob name branch ref tag require submodules
platform platforms type source install_if gemfile force_ruby_platform].freeze
- GITHUB_PULL_REQUEST_URL = %r{\Ahttps://github\.com/([A-Za-z0-9_\-\.]+/[A-Za-z0-9_\-\.]+)/pull/(\d+)\z}
- GITLAB_MERGE_REQUEST_URL = %r{\Ahttps://gitlab\.com/([A-Za-z0-9_\-\./]+)/-/merge_requests/(\d+)\z}
+ GITHUB_PULL_REQUEST_URL = %r{\Ahttps://github\.com/([A-Za-z0-9_\-\.]+/[A-Za-z0-9_\-\.]+)/pull/(\d+)\z}.freeze
- attr_reader :gemspecs, :gemfile
+ attr_reader :gemspecs
attr_accessor :dependencies
def initialize
@@ -42,20 +41,20 @@ module Bundler
end
def eval_gemfile(gemfile, contents = nil)
- with_gemfile(gemfile) do |current_gemfile|
- contents ||= Bundler.read_file(current_gemfile)
- instance_eval(contents, current_gemfile, 1)
- rescue GemfileEvalError => e
- message = "There was an error evaluating `#{File.basename current_gemfile}`: #{e.message}"
- raise DSLError.new(message, current_gemfile, e.backtrace, contents)
- rescue GemfileError, InvalidArgumentError, InvalidOption, DeprecatedError, ScriptError => e
- message = "There was an error parsing `#{File.basename current_gemfile}`: #{e.message}"
- raise DSLError.new(message, current_gemfile, e.backtrace, contents)
- rescue StandardError => e
- raise unless e.backtrace_locations.first.path == current_gemfile
- message = "There was an error parsing `#{File.basename current_gemfile}`: #{e.message}"
- raise DSLError.new(message, current_gemfile, e.backtrace, contents)
- end
+ expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile&.parent)
+ original_gemfile = @gemfile
+ @gemfile = expanded_gemfile_path
+ @gemfiles << expanded_gemfile_path
+ contents ||= Bundler.read_file(@gemfile.to_s)
+ instance_eval(contents.dup.tap {|x| x.untaint if RUBY_VERSION < "2.7" }, gemfile.to_s, 1)
+ rescue Exception => e # rubocop:disable Lint/RescueException
+ message = "There was an error " \
+ "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \
+ "`#{File.basename gemfile.to_s}`: #{e.message}"
+
+ raise DSLError.new(message, gemfile, e.backtrace, contents)
+ ensure
+ @gemfile = original_gemfile
end
def gemspec(opts = nil)
@@ -77,11 +76,11 @@ module Bundler
@gemspecs << spec
- gem spec.name, name: spec.name, path: path, glob: glob
+ gem spec.name, :name => spec.name, :path => path, :glob => glob
group(development_group) do
spec.development_dependencies.each do |dep|
- gem dep.name, *(dep.requirement.as_list + [type: :development])
+ gem dep.name, *(dep.requirement.as_list + [:type => :development])
end
end
when 0
@@ -103,51 +102,39 @@ module Bundler
# if there's already a dependency with this name we try to prefer one
if current = @dependencies.find {|d| d.name == dep.name }
- if current.requirement != dep.requirement
- current_requirement_open = current.requirements_list.include?(">= 0")
+ deleted_dep = @dependencies.delete(current) if current.type == :development
- gemspec_dep = [dep, current].find(&:gemspec_dev_dep?)
- if gemspec_dep
- gemfile_dep = [dep, current].find(&:runtime?)
+ unless deleted_dep
+ if current.requirement != dep.requirement
+ return if dep.type == :development
- unless current_requirement_open
- Bundler.ui.warn "A gemspec development dependency (#{gemspec_dep.name}, #{gemspec_dep.requirement}) is being overridden by a Gemfile dependency (#{gemfile_dep.name}, #{gemfile_dep.requirement}).\n" \
- "This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement\n"
- end
- else
update_prompt = ""
if File.basename(@gemfile) == Injector::INJECTED_GEMS
- if dep.requirements_list.include?(">= 0") && !current_requirement_open
+ if dep.requirements_list.include?(">= 0") && !current.requirements_list.include?(">= 0")
update_prompt = ". Gem already added"
else
update_prompt = ". If you want to update the gem version, run `bundle update #{current.name}`"
- update_prompt += ". You may also need to change the version requirement specified in the Gemfile if it's too restrictive." unless current_requirement_open
+ update_prompt += ". You may also need to change the version requirement specified in the Gemfile if it's too restrictive." unless current.requirements_list.include?(">= 0")
end
end
raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \
- "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" \
- "#{update_prompt}"
+ "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" \
+ "#{update_prompt}"
+ elsif current.source != dep.source
+ return if dep.type == :development
+ raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
+ "You specified that #{dep.name} (#{dep.requirement}) should come from " \
+ "#{current.source || "an unspecified source"} and #{dep.source}\n"
+ else
+ Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \
+ "You should probably keep only one of them.\n" \
+ "Remove any duplicate entries and specify the gem only once.\n" \
+ "While it's not a problem now, it could cause errors if you change the version of one of them later."
end
end
-
- # Always prefer the dependency from the Gemfile
- if current.gemspec_dev_dep?
- @dependencies.delete(current)
- elsif dep.gemspec_dev_dep?
- return
- elsif current.source != dep.source
- raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
- "You specified that #{dep.name} (#{dep.requirement}) should come from " \
- "#{current.source || "an unspecified source"} and #{dep.source}\n"
- else
- Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \
- "You should probably keep only one of them.\n" \
- "Remove any duplicate entries and specify the gem only once.\n" \
- "While it's not a problem now, it could cause errors if you change the version of one of them later."
- end
end
@dependencies << dep
@@ -219,7 +206,7 @@ module Bundler
end
def github(repo, options = {})
- raise InvalidArgumentError, "GitHub sources require a block" unless block_given?
+ raise ArgumentError, "GitHub sources require a block" unless block_given?
github_uri = @git_sources["github"].call(repo)
git_options = normalize_hash(options).merge("uri" => github_uri)
git_source = @sources.add_git_source(git_options)
@@ -285,16 +272,6 @@ module Bundler
private
- def with_gemfile(gemfile)
- expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile&.parent)
- original_gemfile = @gemfile
- @gemfile = expanded_gemfile_path
- @gemfiles << expanded_gemfile_path
- yield @gemfile.to_s
- ensure
- @gemfile = original_gemfile
- end
-
def add_git_sources
git_source(:github) do |repo_name|
if repo_name =~ GITHUB_PULL_REQUEST_URL
@@ -319,20 +296,6 @@ module Bundler
repo_name ||= user_name
"https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git"
end
-
- git_source(:gitlab) do |repo_name|
- if repo_name =~ GITLAB_MERGE_REQUEST_URL
- {
- "git" => "https://gitlab.com/#{$1}.git",
- "branch" => nil,
- "ref" => "refs/merge-requests/#{$2}/head",
- "tag" => nil,
- }
- else
- repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
- "https://gitlab.com/#{repo_name}.git"
- end
- end
end
def with_source(source)
@@ -434,11 +397,13 @@ module Bundler
end
def validate_keys(command, opts, valid_keys)
- if opts["branch"] && !(opts["git"] || opts["github"] || (opts.keys & @git_sources.keys.map(&:to_s)).any?)
+ invalid_keys = opts.keys - valid_keys
+
+ git_source = opts.keys & @git_sources.keys.map(&:to_s)
+ if opts["branch"] && !(opts["git"] || opts["github"] || git_source.any?)
raise GemfileError, %(The `branch` option for `#{command}` is not allowed. Only gems with a git source can specify a branch)
end
- invalid_keys = opts.keys - valid_keys
return true unless invalid_keys.any?
message = String.new
@@ -457,13 +422,9 @@ module Bundler
def normalize_source(source)
case source
when :gemcutter, :rubygems, :rubyforge
- message =
- "The source :#{source} is deprecated because HTTP requests are insecure.\n" \
- "Please change your source to 'https://rubygems.org' if possible, or 'http://rubygems.org' if not."
- removed_message =
- "The source :#{source} is disallowed because HTTP requests are insecure.\n" \
- "Please change your source to 'https://rubygems.org' if possible, or 'http://rubygems.org' if not."
- Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message
+ Bundler::SharedHelpers.major_deprecation 2, "The source :#{source} is deprecated because HTTP " \
+ "requests are insecure.\nPlease change your source to 'https://" \
+ "rubygems.org' if possible, or 'http://rubygems.org' if not."
"http://rubygems.org"
when String
source
@@ -508,17 +469,10 @@ module Bundler
"should come from that source"
raise GemfileEvalError, msg
else
- message =
- "Your Gemfile contains multiple global sources. " \
+ Bundler::SharedHelpers.major_deprecation 2, "Your Gemfile contains multiple global sources. " \
"Using `source` more than once without a block is a security risk, and " \
"may result in installing unexpected gems. To resolve this warning, use " \
"a block to indicate which gems should come from the secondary source."
- removed_message =
- "Your Gemfile contains multiple global sources. " \
- "Using `source` more than once without a block is a security risk, and " \
- "may result in installing unexpected gems. To resolve this error, use " \
- "a block to indicate which gems should come from the secondary source."
- Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message
end
end
@@ -587,7 +541,7 @@ module Bundler
return m unless backtrace && dsl_path && contents
- trace_line = backtrace.find {|l| l.include?(dsl_path) } || trace_line
+ trace_line = backtrace.find {|l| l.include?(dsl_path.to_s) } || trace_line
return m unless trace_line
line_numer = trace_line.split(":")[1].to_i - 1
return m unless line_numer
@@ -613,7 +567,7 @@ module Bundler
def parse_line_number_from_description
description = self.description
- if dsl_path && description =~ /((#{Regexp.quote File.expand_path(dsl_path)}|#{Regexp.quote dsl_path}):\d+)/
+ if dsl_path && description =~ /((#{Regexp.quote File.expand_path(dsl_path)}|#{Regexp.quote dsl_path.to_s}):\d+)/
trace_line = Regexp.last_match[1]
description = description.sub(/\n.*\n(\.\.\.)? *\^~+$/, "").sub(/#{Regexp.quote trace_line}:\s*/, "").sub("\n", " - ")
end
diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb
index 201818cc33..863544b1f9 100644
--- a/lib/bundler/endpoint_specification.rb
+++ b/lib/bundler/endpoint_specification.rb
@@ -92,20 +92,9 @@ module Bundler
end
end
- # needed for `bundle fund`
- def metadata
- if @remote_specification
- @remote_specification.metadata
- elsif _local_specification
- _local_specification.metadata
- else
- super
- end
- end
-
def _local_specification
return unless @loaded_from && File.exist?(local_specification_path)
- eval(File.read(local_specification_path), nil, local_specification_path).tap do |spec|
+ eval(File.read(local_specification_path)).tap do |spec|
spec.loaded_from = @loaded_from
end
end
@@ -136,11 +125,7 @@ module Bundler
next unless v
case k.to_s
when "checksum"
- begin
- @checksum = Checksum.from_api(v.last, @spec_fetcher.uri)
- rescue ArgumentError => e
- raise ArgumentError, "Invalid checksum for #{full_name}: #{e.message}"
- end
+ @checksum = v.last
when "rubygems"
@required_rubygems_version = Gem::Requirement.new(v)
when "ruby"
diff --git a/lib/bundler/env.rb b/lib/bundler/env.rb
index 074bef6edc..7b1152930e 100644
--- a/lib/bundler/env.rb
+++ b/lib/bundler/env.rb
@@ -40,11 +40,11 @@ module Bundler
out << "\n## Gemfile\n"
gemfiles.each do |gemfile|
- out << "\n### #{SharedHelpers.relative_path_to(gemfile)}\n\n"
+ out << "\n### #{Pathname.new(gemfile).relative_path_from(SharedHelpers.pwd)}\n\n"
out << "```ruby\n" << read_file(gemfile).chomp << "\n```\n"
end
- out << "\n### #{SharedHelpers.relative_path_to(Bundler.default_lockfile)}\n\n"
+ out << "\n### #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}\n\n"
out << "```\n" << read_file(Bundler.default_lockfile).chomp << "\n```\n"
end
@@ -69,7 +69,9 @@ module Bundler
end
def self.ruby_version
- "#{RUBY_VERSION}p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{Gem::Platform.local}]"
+ str = String.new(RUBY_VERSION)
+ str << "p#{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
+ str << " (#{RUBY_RELEASE_DATE} revision #{RUBY_REVISION}) [#{Gem::Platform.local}]"
end
def self.git_version
@@ -120,7 +122,7 @@ module Bundler
specs = Bundler.rubygems.find_name(name)
out << [" #{name}", "(#{specs.map(&:version).join(",")})"] unless specs.empty?
end
- if (exe = caller_locations.last.absolute_path)&.match? %r{(exe|bin)/bundler?\z}
+ if (exe = caller.last.split(":").first)&.match? %r{(exe|bin)/bundler?\z}
shebang = File.read(exe).lines.first
shebang.sub!(/^#!\s*/, "")
unless shebang.start_with?(Gem.ruby, "/usr/bin/env ruby")
diff --git a/lib/bundler/environment_preserver.rb b/lib/bundler/environment_preserver.rb
index 444ab6fd37..57013f5d50 100644
--- a/lib/bundler/environment_preserver.rb
+++ b/lib/bundler/environment_preserver.rb
@@ -19,7 +19,14 @@ module Bundler
BUNDLER_PREFIX = "BUNDLER_ORIG_"
def self.from_env
- new(ENV.to_hash, BUNDLER_KEYS)
+ new(env_to_hash(ENV), BUNDLER_KEYS)
+ end
+
+ def self.env_to_hash(env)
+ to_hash = env.to_hash
+ return to_hash unless Gem.win_platform?
+
+ to_hash.each_with_object({}) {|(k,v), a| a[k.upcase] = v }
end
# @param env [Hash]
@@ -32,7 +39,18 @@ module Bundler
# Replaces `ENV` with the bundler environment variables backed up
def replace_with_backup
- ENV.replace(backup)
+ unless Gem.win_platform?
+ ENV.replace(backup)
+ return
+ end
+
+ # Fallback logic for Windows below to workaround
+ # https://bugs.ruby-lang.org/issues/16798. Can be dropped once all
+ # supported rubies include the fix for that.
+
+ ENV.clear
+
+ backup.each {|k, v| ENV[k] = v }
end
# @return [Hash]
@@ -40,9 +58,9 @@ module Bundler
env = @original.clone
@keys.each do |key|
value = env[key]
- if !value.nil?
+ if !value.nil? && !value.empty?
env[@prefix + key] ||= value
- else
+ elsif value.nil?
env[@prefix + key] ||= INTENTIONALLY_NIL
end
end
@@ -54,7 +72,7 @@ module Bundler
env = @original.clone
@keys.each do |key|
value_original = env[@prefix + key]
- next if value_original.nil?
+ next if value_original.nil? || value_original.empty?
if value_original == INTENTIONALLY_NIL
env.delete(key)
else
diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb
index a0ce739ad7..5839fc6a73 100644
--- a/lib/bundler/errors.rb
+++ b/lib/bundler/errors.rb
@@ -52,49 +52,6 @@ module Bundler
class GemfileEvalError < GemfileError; end
class MarshalError < StandardError; end
- class ChecksumMismatchError < SecurityError
- def initialize(lock_name, existing, checksum)
- @lock_name = lock_name
- @existing = existing
- @checksum = checksum
- end
-
- def message
- <<~MESSAGE
- Bundler found mismatched checksums. This is a potential security risk.
- #{@lock_name} #{@existing.to_lock}
- from #{@existing.sources.join("\n and ")}
- #{@lock_name} #{@checksum.to_lock}
- from #{@checksum.sources.join("\n and ")}
-
- #{mismatch_resolution_instructions}
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- MESSAGE
- end
-
- def mismatch_resolution_instructions
- removable, remote = [@existing, @checksum].partition(&:removable?)
- case removable.size
- when 0
- msg = +"Mismatched checksums each have an authoritative source:\n"
- msg << " 1. #{@existing.sources.reject(&:removable?).map(&:to_s).join(" and ")}\n"
- msg << " 2. #{@checksum.sources.reject(&:removable?).map(&:to_s).join(" and ")}\n"
- msg << "You may need to alter your Gemfile sources to resolve this issue.\n"
- when 1
- msg = +"If you trust #{remote.first.sources.first}, to resolve this issue you can:\n"
- msg << removable.first.removal_instructions
- when 2
- msg = +"To resolve this issue you can either:\n"
- msg << @checksum.removal_instructions
- msg << "or if you are sure that the new checksum from #{@checksum.sources.first} is correct:\n"
- msg << @existing.removal_instructions
- end
- end
-
- status_code(37)
- end
-
class PermissionError < BundlerError
def initialize(path, permission_type = :write)
@path = path
@@ -215,35 +172,4 @@ module Bundler
status_code(36)
end
-
- class InsecureInstallPathError < BundlerError
- def initialize(name, path)
- @name = name
- @path = path
- end
-
- def message
- "Bundler cannot reinstall #{@name} because there's a previous installation of it at #{@path} that is unsafe to remove.\n" \
- "The parent of #{@path} is world-writable and does not have the sticky bit set, making it insecure to remove due to potential vulnerabilities.\n" \
- "Please change the permissions of #{File.dirname(@path)} or choose a different install path."
- end
-
- status_code(38)
- end
-
- class CorruptBundlerInstallError < BundlerError
- def initialize(loaded_spec)
- @loaded_spec = loaded_spec
- end
-
- def message
- "The running version of Bundler (#{Bundler::VERSION}) does not match the version of the specification installed for it (#{@loaded_spec.version}). " \
- "This can be caused by reinstalling Ruby without removing previous installation, leaving around an upgraded default version of Bundler. " \
- "Reinstalling Ruby from scratch should fix the problem."
- end
-
- status_code(39)
- end
-
- class InvalidArgumentError < BundlerError; status_code(40); end
end
diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb
index 14721623f9..2119799f68 100644
--- a/lib/bundler/fetcher.rb
+++ b/lib/bundler/fetcher.rb
@@ -1,15 +1,14 @@
# frozen_string_literal: true
require_relative "vendored_persistent"
-require_relative "vendored_timeout"
require "cgi"
-require_relative "vendored_securerandom"
+require "securerandom"
require "zlib"
+require "rubygems/request"
module Bundler
# Handles all the fetching with the rubygems server
class Fetcher
- autoload :Base, File.expand_path("fetcher/base", __dir__)
autoload :CompactIndex, File.expand_path("fetcher/compact_index", __dir__)
autoload :Downloader, File.expand_path("fetcher/downloader", __dir__)
autoload :Dependency, File.expand_path("fetcher/dependency", __dir__)
@@ -81,9 +80,9 @@ module Bundler
:HTTPRequestURITooLong, :HTTPUnauthorized, :HTTPUnprocessableEntity,
:HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze
FAIL_ERRORS = begin
- fail_errors = [AuthenticationRequiredError, BadAuthenticationError, AuthenticationForbiddenError, FallbackError, SecurityError]
+ fail_errors = [AuthenticationRequiredError, BadAuthenticationError, AuthenticationForbiddenError, FallbackError]
fail_errors << Gem::Requirement::BadRequirementError
- fail_errors.concat(NET_ERRORS.map {|e| Gem::Net.const_get(e) })
+ fail_errors.concat(NET_ERRORS.map {|e| Net.const_get(e) })
end.freeze
class << self
@@ -95,7 +94,6 @@ module Bundler
self.max_retries = Bundler.settings[:retry] # How many retries for the API call
def initialize(remote)
- @cis = nil
@remote = remote
Socket.do_not_reverse_lookup = true
@@ -111,17 +109,15 @@ module Bundler
spec -= [nil, "ruby", ""]
spec_file_name = "#{spec.join "-"}.gemspec"
- uri = Gem::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz")
- spec = if uri.scheme == "file"
- path = Gem::Util.correct_for_windows_path(uri.path)
+ uri = Bundler::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz")
+ if uri.scheme == "file"
+ path = Bundler.rubygems.correct_for_windows_path(uri.path)
Bundler.safe_load_marshal Bundler.rubygems.inflate(Gem.read_binary(path))
elsif cached_spec_path = gemspec_cached_path(spec_file_name)
Bundler.load_gemspec(cached_spec_path)
else
Bundler.safe_load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body)
end
- raise MarshalError, "is #{spec.inspect}" unless spec.is_a?(Gem::Specification)
- spec
rescue MarshalError
raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \
"Your network or your gem server is probably having issues right now."
@@ -138,11 +134,20 @@ module Bundler
def specs(gem_names, source)
index = Bundler::Index.new
- fetch_specs(gem_names).each do |name, version, platform, dependencies, metadata|
+ if Bundler::Fetcher.disable_endpoint
+ @use_api = false
+ specs = fetchers.last.specs(gem_names)
+ else
+ specs = []
+ @fetchers = fetchers.drop_while do |f|
+ !f.available? || (f.api_fetcher? && !gem_names) || !specs = f.specs(gem_names)
+ end
+ @use_api = false if fetchers.none?(&:api_fetcher?)
+ end
+
+ specs.each do |name, version, platform, dependencies, metadata|
spec = if dependencies
- EndpointSpecification.new(name, version, platform, self, dependencies, metadata).tap do |es|
- source.checksum_store.replace(es, es.checksum)
- end
+ EndpointSpecification.new(name, version, platform, self, dependencies, metadata)
else
RemoteSpecification.new(name, version, platform, self)
end
@@ -153,10 +158,22 @@ module Bundler
index
rescue CertificateFailureError
- Bundler.ui.info "" if gem_names && api_fetcher? # newline after dots
+ Bundler.ui.info "" if gem_names && use_api # newline after dots
raise
end
+ def use_api
+ return @use_api if defined?(@use_api)
+
+ fetchers.shift until fetchers.first.available?
+
+ @use_api = if remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint
+ false
+ else
+ fetchers.first.api_fetcher?
+ end
+ end
+
def user_agent
@user_agent ||= begin
ruby = Bundler::RubyVersion.system
@@ -182,7 +199,7 @@ module Bundler
agent << " ci/#{cis.join(",")}" if cis.any?
# add a random ID so we can consolidate runs server-side
- agent << " " << Gem::SecureRandom.hex(8)
+ agent << " " << SecureRandom.hex(8)
# add any user agent strings set in the config
extra_ua = Bundler.settings[:user_agent]
@@ -192,6 +209,10 @@ module Bundler
end
end
+ def fetchers
+ @fetchers ||= FETCHERS.map {|f| f.new(downloader, @remote, uri) }
+ end
+
def http_proxy
return unless uri = connection.proxy_uri
uri.to_s
@@ -201,49 +222,25 @@ module Bundler
"#<#{self.class}:0x#{object_id} uri=#{uri}>"
end
- def api_fetcher?
- fetchers.first.api_fetcher?
- end
-
- def gem_remote_fetcher
- @gem_remote_fetcher ||= begin
- require_relative "fetcher/gem_remote_fetcher"
- fetcher = GemRemoteFetcher.new Gem.configuration[:http_proxy]
- fetcher.headers["User-Agent"] = user_agent
- fetcher.headers["X-Gemfile-Source"] = @remote.original_uri.to_s if @remote.original_uri
- fetcher
- end
- end
-
private
- def available_fetchers
- if Bundler::Fetcher.disable_endpoint
- [Index]
- elsif remote_uri.scheme == "file"
- Bundler.ui.debug("Using a local server, bundler won't use the CompactIndex API")
- [Index]
- else
- [CompactIndex, Dependency, Index]
- end
- end
-
- def fetchers
- @fetchers ||= available_fetchers.map {|f| f.new(downloader, @remote, uri, gem_remote_fetcher) }.drop_while {|f| !f.available? }
- end
-
- def fetch_specs(gem_names)
- fetchers.reject!(&:api_fetcher?) unless gem_names
- fetchers.reject! do |f|
- specs = f.specs(gem_names)
- return specs if specs
- true
- end
- []
- end
+ FETCHERS = [CompactIndex, Dependency, Index].freeze
def cis
- @cis ||= Bundler::CIDetector.ci_strings
+ env_cis = {
+ "TRAVIS" => "travis",
+ "CIRCLECI" => "circle",
+ "SEMAPHORE" => "semaphore",
+ "JENKINS_URL" => "jenkins",
+ "BUILDBOX" => "buildbox",
+ "GO_SERVER_URL" => "go",
+ "SNAP_CI" => "snap",
+ "GITLAB_CI" => "gitlab",
+ "GITHUB_ACTIONS" => "github",
+ "CI_NAME" => ENV["CI_NAME"],
+ "CI" => "ci",
+ }
+ env_cis.find_all {|env, _| ENV[env] }.map {|_, ci| ci }
end
def connection
@@ -253,9 +250,9 @@ module Bundler
Bundler.settings[:ssl_client_cert]
raise SSLError if needs_ssl && !defined?(OpenSSL::SSL)
- con = Gem::Net::HTTP::Persistent.new name: "bundler", proxy: :ENV
+ con = PersistentHTTP.new :name => "bundler", :proxy => :ENV
if gem_proxy = Gem.configuration[:http_proxy]
- con.proxy = Gem::URI.parse(gem_proxy) if gem_proxy != :no_proxy
+ con.proxy = Bundler::URI.parse(gem_proxy) if gem_proxy != :no_proxy
end
if remote_uri.scheme == "https"
@@ -288,10 +285,10 @@ module Bundler
end
HTTP_ERRORS = [
- Gem::Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH,
+ Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH,
Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN,
- Gem::Net::HTTPBadResponse, Gem::Net::HTTPHeaderSyntaxError, Gem::Net::ProtocolError,
- Gem::Net::HTTP::Persistent::Error, Zlib::BufError, Errno::EHOSTUNREACH
+ Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError,
+ PersistentHTTP::Error, Zlib::BufError, Errno::EHOSTUNREACH
].freeze
def bundler_cert_store
@@ -307,7 +304,6 @@ module Bundler
end
else
store.set_default_paths
- require "rubygems/request"
Gem::Request.get_cert_files.each {|c| store.add_file c }
end
store
diff --git a/lib/bundler/fetcher/base.rb b/lib/bundler/fetcher/base.rb
index cfec2f8e94..62cc75add8 100644
--- a/lib/bundler/fetcher/base.rb
+++ b/lib/bundler/fetcher/base.rb
@@ -6,14 +6,12 @@ module Bundler
attr_reader :downloader
attr_reader :display_uri
attr_reader :remote
- attr_reader :gem_remote_fetcher
- def initialize(downloader, remote, display_uri, gem_remote_fetcher)
+ def initialize(downloader, remote, display_uri)
raise "Abstract class" if self.class == Base
@downloader = downloader
@remote = remote
@display_uri = display_uri
- @gem_remote_fetcher = gem_remote_fetcher
end
def remote_uri
@@ -40,9 +38,9 @@ module Bundler
private
- def log_specs(&block)
+ def log_specs(debug_msg)
if Bundler.ui.debug?
- Bundler.ui.debug yield
+ Bundler.ui.debug debug_msg
else
Bundler.ui.info ".", false
end
diff --git a/lib/bundler/fetcher/compact_index.rb b/lib/bundler/fetcher/compact_index.rb
index 6c82d57011..8d30dec471 100644
--- a/lib/bundler/fetcher/compact_index.rb
+++ b/lib/bundler/fetcher/compact_index.rb
@@ -4,14 +4,16 @@ require_relative "base"
require_relative "../worker"
module Bundler
+ autoload :CompactIndexClient, File.expand_path("../compact_index_client", __dir__)
+
class Fetcher
class CompactIndex < Base
def self.compact_index_request(method_name)
method = instance_method(method_name)
undef_method(method_name)
define_method(method_name) do |*args, &blk|
- method.bind_call(self, *args, &blk)
- rescue NetworkDownError, CompactIndexClient::Updater::MismatchedChecksumError => e
+ method.bind(self).call(*args, &blk)
+ rescue NetworkDownError, CompactIndexClient::Updater::MisMatchedChecksumError => e
raise HTTPError, e.message
rescue AuthenticationRequiredError, BadAuthenticationError
# Fail since we got a 401 from the server.
@@ -33,9 +35,16 @@ module Bundler
remaining_gems = gem_names.dup
until remaining_gems.empty?
- log_specs { "Looking up gems #{remaining_gems.inspect}" }
- deps = fetch_gem_infos(remaining_gems).flatten(1)
- next_gems = deps.flat_map {|d| d[CompactIndexClient::INFO_DEPS].flat_map(&:first) }.uniq
+ log_specs "Looking up gems #{remaining_gems.inspect}"
+
+ deps = begin
+ parallel_compact_index_client.dependencies(remaining_gems)
+ rescue TooManyRequestsError
+ @bundle_worker&.stop
+ @bundle_worker = nil # reset it. Not sure if necessary
+ serial_compact_index_client.dependencies(remaining_gems)
+ end
+ next_gems = deps.map {|d| d[3].map(&:first).flatten(1) }.flatten(1).uniq
deps.each {|dep| gem_info << dep }
complete_gems.concat(deps.map(&:first)).uniq!
remaining_gems = next_gems - complete_gems
@@ -51,9 +60,13 @@ module Bundler
Bundler.ui.debug("FIPS mode is enabled, bundler can't use the CompactIndex API")
return nil
end
+ if fetch_uri.scheme == "file"
+ Bundler.ui.debug("Using a local server, bundler won't use the CompactIndex API")
+ return false
+ end
# Read info file checksums out of /versions, so we can know if gems are up to date
- compact_index_client.available?
- rescue CompactIndexClient::Updater::MismatchedChecksumError => e
+ compact_index_client.update_and_parse_checksums!
+ rescue CompactIndexClient::Updater::MisMatchedChecksumError => e
Bundler.ui.debug(e.message)
nil
end
@@ -72,20 +85,20 @@ module Bundler
end
end
- def fetch_gem_infos(names)
- in_parallel(names) {|name| compact_index_client.info(name) }
- rescue TooManyRequestsError # rubygems.org is rate limiting us, slow down.
- @bundle_worker&.stop
- @bundle_worker = nil # reset it. Not sure if necessary
- compact_index_client.reset!
- names.map {|name| compact_index_client.info(name) }
+ def parallel_compact_index_client
+ compact_index_client.execution_mode = lambda do |inputs, &blk|
+ func = lambda {|object, _index| blk.call(object) }
+ worker = bundle_worker(func)
+ inputs.each {|input| worker.enq(input) }
+ inputs.map { worker.deq }
+ end
+
+ compact_index_client
end
- def in_parallel(inputs, &blk)
- func = lambda {|object, _index| blk.call(object) }
- worker = bundle_worker(func)
- inputs.each {|input| worker.enq(input) }
- inputs.map { worker.deq }
+ def serial_compact_index_client
+ compact_index_client.sequential_execution_mode!
+ compact_index_client
end
def bundle_worker(func = nil)
@@ -112,7 +125,7 @@ module Bundler
rescue NetworkDownError => e
raise unless Bundler.feature_flag.allow_offline_install? && headers["If-None-Match"]
ui.warn "Using the cached data for the new index because of a network error: #{e}"
- Gem::Net::HTTPNotModified.new(nil, nil, nil)
+ Net::HTTPNotModified.new(nil, nil, nil)
end
end
end
diff --git a/lib/bundler/fetcher/dependency.rb b/lib/bundler/fetcher/dependency.rb
index 0b807c9a4b..18b606abb6 100644
--- a/lib/bundler/fetcher/dependency.rb
+++ b/lib/bundler/fetcher/dependency.rb
@@ -24,7 +24,7 @@ module Bundler
def specs(gem_names, full_dependency_list = [], last_spec_list = [])
query_list = gem_names.uniq - full_dependency_list
- log_specs { "Query List: #{query_list.inspect}" }
+ log_specs "Query List: #{query_list.inspect}"
return last_spec_list if query_list.empty?
diff --git a/lib/bundler/fetcher/downloader.rb b/lib/bundler/fetcher/downloader.rb
index 868b39b959..3062899e0e 100644
--- a/lib/bundler/fetcher/downloader.rb
+++ b/lib/bundler/fetcher/downloader.rb
@@ -20,35 +20,33 @@ module Bundler
Bundler.ui.debug("HTTP #{response.code} #{response.message} #{filtered_uri}")
case response
- when Gem::Net::HTTPSuccess, Gem::Net::HTTPNotModified
+ when Net::HTTPSuccess, Net::HTTPNotModified
response
- when Gem::Net::HTTPRedirection
- new_uri = Gem::URI.parse(response["location"])
+ when Net::HTTPRedirection
+ new_uri = Bundler::URI.parse(response["location"])
if new_uri.host == uri.host
new_uri.user = uri.user
new_uri.password = uri.password
end
fetch(new_uri, headers, counter + 1)
- when Gem::Net::HTTPRequestedRangeNotSatisfiable
+ when Net::HTTPRequestedRangeNotSatisfiable
new_headers = headers.dup
new_headers.delete("Range")
new_headers["Accept-Encoding"] = "gzip"
fetch(uri, new_headers)
- when Gem::Net::HTTPRequestEntityTooLarge
+ when Net::HTTPRequestEntityTooLarge
raise FallbackError, response.body
- when Gem::Net::HTTPTooManyRequests
+ when Net::HTTPTooManyRequests
raise TooManyRequestsError, response.body
- when Gem::Net::HTTPUnauthorized
+ when Net::HTTPUnauthorized
raise BadAuthenticationError, uri.host if uri.userinfo
raise AuthenticationRequiredError, uri.host
- when Gem::Net::HTTPForbidden
+ when Net::HTTPForbidden
raise AuthenticationForbiddenError, uri.host
- when Gem::Net::HTTPNotFound
- raise FallbackError, "Gem::Net::HTTPNotFound: #{filtered_uri}"
+ when Net::HTTPNotFound
+ raise FallbackError, "Net::HTTPNotFound: #{filtered_uri}"
else
- message = "Gem::#{response.class.name.gsub(/\AGem::/, "")}"
- message += ": #{response.body}" unless response.body.empty?
- raise HTTPError, message
+ raise HTTPError, "#{response.class}#{": #{response.body}" unless response.body.empty?}"
end
end
@@ -58,7 +56,7 @@ module Bundler
filtered_uri = URICredentialsFilter.credential_filtered_uri(uri)
Bundler.ui.debug "HTTP GET #{filtered_uri}"
- req = Gem::Net::HTTP::Get.new uri.request_uri, headers
+ req = Net::HTTP::Get.new uri.request_uri, headers
if uri.user
user = CGI.unescape(uri.user)
password = uri.password ? CGI.unescape(uri.password) : nil
diff --git a/lib/bundler/fetcher/gem_remote_fetcher.rb b/lib/bundler/fetcher/gem_remote_fetcher.rb
deleted file mode 100644
index 3fc7b68263..0000000000
--- a/lib/bundler/fetcher/gem_remote_fetcher.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-require "rubygems/remote_fetcher"
-
-module Bundler
- class Fetcher
- class GemRemoteFetcher < Gem::RemoteFetcher
- def request(*args)
- super do |req|
- req.delete("User-Agent") if headers["User-Agent"]
- yield req if block_given?
- end
- end
- end
- end
-end
diff --git a/lib/bundler/fetcher/index.rb b/lib/bundler/fetcher/index.rb
index 6e37e1e5d1..c623647f01 100644
--- a/lib/bundler/fetcher/index.rb
+++ b/lib/bundler/fetcher/index.rb
@@ -6,7 +6,7 @@ module Bundler
class Fetcher
class Index < Base
def specs(_gem_names)
- Bundler.rubygems.fetch_all_remote_specs(remote, gem_remote_fetcher)
+ Bundler.rubygems.fetch_all_remote_specs(remote)
rescue Gem::RemoteFetcher::FetchError => e
case e.message
when /certificate verify failed/
diff --git a/lib/bundler/force_platform.rb b/lib/bundler/force_platform.rb
index 7af33218cb..249a24ecd1 100644
--- a/lib/bundler/force_platform.rb
+++ b/lib/bundler/force_platform.rb
@@ -2,6 +2,8 @@
module Bundler
module ForcePlatform
+ private
+
# The `:force_ruby_platform` value used by dependencies for resolution, and
# by locked specifications for materialization is `false` by default, except
# for TruffleRuby. TruffleRuby generally needs to force the RUBY platform
diff --git a/lib/bundler/friendly_errors.rb b/lib/bundler/friendly_errors.rb
index e61ed64450..39afe8a071 100644
--- a/lib/bundler/friendly_errors.rb
+++ b/lib/bundler/friendly_errors.rb
@@ -32,7 +32,7 @@ module Bundler
if Bundler.ui.debug?
Bundler.ui.trace error
else
- Bundler.ui.error error.message, wrap: true
+ Bundler.ui.error error.message, :wrap => true
end
when Thor::Error
Bundler.ui.error error.message
@@ -40,7 +40,7 @@ module Bundler
Bundler.ui.error "\nQuitting..."
Bundler.ui.trace error
when Gem::InvalidSpecificationException
- Bundler.ui.error error.message, wrap: true
+ Bundler.ui.error error.message, :wrap => true
when SystemExit
when *[defined?(Java::JavaLang::OutOfMemoryError) && Java::JavaLang::OutOfMemoryError].compact
Bundler.ui.error "\nYour JVM has run out of memory, and Bundler cannot continue. " \
@@ -61,7 +61,7 @@ module Bundler
end
def request_issue_report_for(e)
- Bundler.ui.error <<~EOS, nil, nil
+ Bundler.ui.error <<-EOS.gsub(/^ {8}/, ""), nil, nil
--- ERROR REPORT TEMPLATE -------------------------------------------------------
```
@@ -75,7 +75,7 @@ module Bundler
Bundler.ui.error "Unfortunately, an unexpected error occurred, and Bundler cannot continue."
- Bundler.ui.error <<~EOS, nil, :yellow
+ Bundler.ui.error <<-EOS.gsub(/^ {8}/, ""), nil, :yellow
First, try this link to see if there are any existing issue reports for this error:
#{issues_url(e)}
@@ -93,7 +93,7 @@ module Bundler
end
def serialized_exception_for(e)
- <<~EOS
+ <<-EOS.gsub(/^ {8}/, "")
#{e.class}: #{e.message}
#{e.backtrace&.join("\n ")&.chomp}
EOS
diff --git a/lib/bundler/gem_helper.rb b/lib/bundler/gem_helper.rb
index 5ce0ef6280..dcf759cded 100644
--- a/lib/bundler/gem_helper.rb
+++ b/lib/bundler/gem_helper.rb
@@ -47,7 +47,7 @@ module Bundler
built_gem_path = build_gem
end
- desc "Generate SHA512 checksum of #{name}-#{version}.gem into the checksums directory."
+ desc "Generate SHA512 checksum if #{name}-#{version}.gem into the checksums directory."
task "build:checksum" => "build" do
build_checksum(built_gem_path)
end
@@ -215,7 +215,7 @@ module Bundler
def sh_with_status(cmd, &block)
Bundler.ui.debug(cmd)
SharedHelpers.chdir(base) do
- outbuf = IO.popen(cmd, err: [:child, :out], &:read)
+ outbuf = IO.popen(cmd, :err => [:child, :out], &:read)
status = $?
block&.call(outbuf) if status.success?
[outbuf, status]
diff --git a/lib/bundler/gem_helpers.rb b/lib/bundler/gem_helpers.rb
index 70ccceb491..2e6d788f9c 100644
--- a/lib/bundler/gem_helpers.rb
+++ b/lib/bundler/gem_helpers.rb
@@ -34,11 +34,6 @@ module Bundler
end
module_function :local_platform
- def generic_local_platform_is_ruby?
- generic_local_platform == Gem::Platform::RUBY
- end
- module_function :generic_local_platform_is_ruby?
-
def platform_specificity_match(spec_platform, user_platform)
spec_platform = Gem::Platform.new(spec_platform)
@@ -46,27 +41,13 @@ module Bundler
end
module_function :platform_specificity_match
- def select_best_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
- matching = if force_ruby
- specs.select {|spec| spec.match_platform(Gem::Platform::RUBY) && spec.force_ruby_platform! }
- else
- specs.select {|spec| spec.match_platform(platform) }
- end
-
- if prefer_locked
- locked_originally = matching.select {|spec| spec.is_a?(LazySpecification) }
- return locked_originally if locked_originally.any?
- end
+ def select_best_platform_match(specs, platform)
+ matching = specs.select {|spec| spec.match_platform(platform) }
sort_best_platform_match(matching, platform)
end
module_function :select_best_platform_match
- def select_best_local_platform_match(specs, force_ruby: false)
- select_best_platform_match(specs, local_platform, force_ruby: force_ruby).map(&:materialize_for_installation).compact
- end
- module_function :select_best_local_platform_match
-
def sort_best_platform_match(matching, platform)
exact = matching.select {|spec| spec.platform == platform }
return exact if exact.any?
@@ -126,6 +107,8 @@ module Bundler
def same_deps(spec, exemplary_spec)
same_runtime_deps = spec.dependencies.sort == exemplary_spec.dependencies.sort
+ return same_runtime_deps unless spec.is_a?(Gem::Specification) && exemplary_spec.is_a?(Gem::Specification)
+
same_metadata_deps = spec.required_ruby_version == exemplary_spec.required_ruby_version && spec.required_rubygems_version == exemplary_spec.required_rubygems_version
same_runtime_deps && same_metadata_deps
end
diff --git a/lib/bundler/gem_version_promoter.rb b/lib/bundler/gem_version_promoter.rb
index ecc65b4956..d281f46eeb 100644
--- a/lib/bundler/gem_version_promoter.rb
+++ b/lib/bundler/gem_version_promoter.rb
@@ -45,37 +45,17 @@ module Bundler
# Given a Resolver::Package and an Array of Specifications of available
# versions for a gem, this method will return the Array of Specifications
- # sorted in an order to give preference to the current level (:major, :minor
- # or :patch) when resolution is deciding what versions best resolve all
- # dependencies in the bundle.
+ # sorted (and possibly truncated if strict is true) in an order to give
+ # preference to the current level (:major, :minor or :patch) when resolution
+ # is deciding what versions best resolve all dependencies in the bundle.
# @param package [Resolver::Package] The package being resolved.
# @param specs [Specification] An array of Specifications for the package.
- # @return [Specification] A new instance of the Specification Array sorted.
+ # @return [Specification] A new instance of the Specification Array sorted and
+ # possibly filtered.
def sort_versions(package, specs)
- locked_version = package.locked_version
-
- result = specs.sort do |a, b|
- unless package.prerelease_specified? || pre?
- a_pre = a.prerelease?
- b_pre = b.prerelease?
+ specs = filter_dep_specs(specs, package) if strict
- next 1 if a_pre && !b_pre
- next -1 if b_pre && !a_pre
- end
-
- if major? || locked_version.nil?
- b <=> a
- elsif either_version_older_than_locked?(a, b, locked_version)
- b <=> a
- elsif segments_do_not_match?(a, b, :major)
- a <=> b
- elsif !minor? && segments_do_not_match?(a, b, :minor)
- a <=> b
- else
- b <=> a
- end
- end
- post_sort(result, package.unlock?, locked_version)
+ sort_dep_specs(specs, package)
end
# @return [bool] Convenience method for testing value of level variable.
@@ -93,18 +73,9 @@ module Bundler
pre == true
end
- # Given a Resolver::Package and an Array of Specifications of available
- # versions for a gem, this method will truncate the Array if strict
- # is true. That means filtering out downgrades from the version currently
- # locked, and filtering out upgrades that go past the selected level (major,
- # minor, or patch).
- # @param package [Resolver::Package] The package being resolved.
- # @param specs [Specification] An array of Specifications for the package.
- # @return [Specification] A new instance of the Specification Array
- # truncated.
- def filter_versions(package, specs)
- return specs unless strict
+ private
+ def filter_dep_specs(specs, package)
locked_version = package.locked_version
return specs if locked_version.nil? || major?
@@ -118,10 +89,35 @@ module Bundler
end
end
- private
+ def sort_dep_specs(specs, package)
+ locked_version = package.locked_version
+
+ result = specs.sort do |a, b|
+ unless package.prerelease_specified? || pre?
+ a_pre = a.prerelease?
+ b_pre = b.prerelease?
+
+ next -1 if a_pre && !b_pre
+ next 1 if b_pre && !a_pre
+ end
+
+ if major?
+ a <=> b
+ elsif either_version_older_than_locked?(a, b, locked_version)
+ a <=> b
+ elsif segments_do_not_match?(a, b, :major)
+ b <=> a
+ elsif !minor? && segments_do_not_match?(a, b, :minor)
+ b <=> a
+ else
+ a <=> b
+ end
+ end
+ post_sort(result, package.unlock?, locked_version)
+ end
def either_version_older_than_locked?(a, b, locked_version)
- a.version < locked_version || b.version < locked_version
+ locked_version && (a.version < locked_version || b.version < locked_version)
end
def segments_do_not_match?(a, b, level)
@@ -137,13 +133,13 @@ module Bundler
if unlock || locked_version.nil?
result
else
- move_version_to_beginning(result, locked_version)
+ move_version_to_end(result, locked_version)
end
end
- def move_version_to_beginning(result, version)
+ def move_version_to_end(result, version)
move, keep = result.partition {|s| s.version.to_s == version.to_s }
- move.concat(keep)
+ keep.concat(move)
end
end
end
diff --git a/lib/bundler/graph.rb b/lib/bundler/graph.rb
index b22b17a453..3c008e63e3 100644
--- a/lib/bundler/graph.rb
+++ b/lib/bundler/graph.rb
@@ -84,7 +84,7 @@ module Bundler
else
raise ArgumentError, "2nd argument is invalid"
end
- label.nil? ? {} : { label: label }
+ label.nil? ? {} : { :label => label }
end
def spec_for_dependency(dependency)
@@ -103,7 +103,7 @@ module Bundler
end
def g
- @g ||= ::GraphViz.digraph(@graph_name, concentrate: true, normalize: true, nodesep: 0.55) do |g|
+ @g ||= ::GraphViz.digraph(@graph_name, :concentrate => true, :normalize => true, :nodesep => 0.55) do |g|
g.edge[:weight] = 2
g.edge[:fontname] = g.node[:fontname] = "Arial, Helvetica, SansSerif"
g.edge[:fontsize] = 12
@@ -114,10 +114,10 @@ module Bundler
@groups.each do |group|
g.add_nodes(
group, {
- style: "filled",
- fillcolor: "#B9B9D5",
- shape: "box3d",
- fontsize: 16,
+ :style => "filled",
+ :fillcolor => "#B9B9D5",
+ :shape => "box3d",
+ :fontsize => 16,
}.merge(@node_options[group])
)
end
@@ -125,8 +125,8 @@ module Bundler
@relations.each do |parent, children|
children.each do |child|
if @groups.include?(parent)
- g.add_nodes(child, { style: "filled", fillcolor: "#B9B9D5" }.merge(@node_options[child]))
- g.add_edges(parent, child, { constraint: false }.merge(@edge_options["#{parent}_#{child}"]))
+ g.add_nodes(child, { :style => "filled", :fillcolor => "#B9B9D5" }.merge(@node_options[child]))
+ g.add_edges(parent, child, { :constraint => false }.merge(@edge_options["#{parent}_#{child}"]))
else
g.add_nodes(child, @node_options[child])
g.add_edges(parent, child, @edge_options["#{parent}_#{child}"])
@@ -135,7 +135,7 @@ module Bundler
end
if @output_format.to_s == "debug"
- $stdout.puts g.output none: String
+ $stdout.puts g.output :none => String
Bundler.ui.info "debugging bundle viz..."
else
begin
diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb
index df46facc88..b8c599f63a 100644
--- a/lib/bundler/index.rb
+++ b/lib/bundler/index.rb
@@ -10,8 +10,8 @@ module Bundler
i
end
- attr_reader :specs, :duplicates, :sources
- protected :specs, :duplicates
+ attr_reader :specs, :all_specs, :sources
+ protected :specs, :all_specs
RUBY = "ruby"
NULL = "\0"
@@ -19,21 +19,21 @@ module Bundler
def initialize
@sources = []
@cache = {}
- @specs = {}
- @duplicates = {}
+ @specs = Hash.new {|h, k| h[k] = {} }
+ @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH }
end
def initialize_copy(o)
@sources = o.sources.dup
@cache = {}
- @specs = {}
- @duplicates = {}
+ @specs = Hash.new {|h, k| h[k] = {} }
+ @all_specs = Hash.new {|h, k| h[k] = EMPTY_SEARCH }
o.specs.each do |name, hash|
@specs[name] = hash.dup
end
- o.duplicates.each do |name, array|
- @duplicates[name] = array.dup
+ o.all_specs.each do |name, array|
+ @all_specs[name] = array.dup
end
end
@@ -46,11 +46,12 @@ module Bundler
true
end
- def search_all(name, &blk)
- return enum_for(:search_all, name) unless blk
- specs_by_name(name).each(&blk)
- @duplicates[name]&.each(&blk)
- @sources.each {|source| source.search_all(name, &blk) }
+ def search_all(name)
+ all_matches = local_search(name) + @all_specs[name]
+ @sources.each do |source|
+ all_matches.concat(source.search_all(name))
+ end
+ all_matches
end
# Search this index's specs, and any source indexes that this index knows
@@ -60,14 +61,11 @@ module Bundler
return results unless @sources.any?
@sources.each do |source|
- results = safe_concat(results, source.search(query))
+ results.concat(source.search(query))
end
- results.uniq!(&:full_name) unless results.empty? # avoid modifying frozen EMPTY_SEARCH
- results
+ results.uniq(&:full_name)
end
- alias_method :[], :search
-
def local_search(query)
case query
when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query)
@@ -78,10 +76,12 @@ module Bundler
end
end
- def add(spec)
- (@specs[spec.name] ||= {}).store(spec.full_name, spec)
+ alias_method :[], :search
+
+ def <<(spec)
+ @specs[spec.name][spec.full_name] = spec
+ spec
end
- alias_method :<<, :add
def each(&blk)
return enum_for(:each) unless blk
@@ -115,25 +115,15 @@ module Bundler
names.uniq
end
- # Combines indexes proritizing existing specs, like `Hash#reverse_merge!`
- # Duplicate specs found in `other` are stored in `@duplicates`.
- def use(other)
+ def use(other, override_dupes = false)
return unless other
- other.each do |spec|
- exist?(spec) ? add_duplicate(spec) : add(spec)
- end
- self
- end
-
- # Combines indexes proritizing specs from `other`, like `Hash#merge!`
- # Duplicate specs found in `self` are saved in `@duplicates`.
- def merge!(other)
- return unless other
- other.each do |spec|
- if existing = find_by_spec(spec)
- add_duplicate(existing)
+ other.each do |s|
+ if (dupes = search_by_spec(s)) && !dupes.empty?
+ # safe to << since it's a new array when it has contents
+ @all_specs[s.name] = dupes << s
+ next unless override_dupes
end
- add spec
+ self << s
end
self
end
@@ -145,7 +135,8 @@ module Bundler
end
# Whether all the specs in self are in other
- def subset?(other)
+ # TODO: rename to #include?
+ def ==(other)
all? do |spec|
other_spec = other[spec].first
other_spec && dependencies_eql?(spec, other_spec) && spec.source == other_spec.source
@@ -166,40 +157,19 @@ module Bundler
private
- def safe_concat(a, b)
- return a if b.empty?
- return b if a.empty?
- a.concat(b)
- end
-
- def add_duplicate(spec)
- (@duplicates[spec.name] ||= []) << spec
- end
-
def specs_by_name_and_version(name, version)
- results = @specs[name]&.values
- return EMPTY_SEARCH unless results
- results.select! {|spec| spec.version == version }
- results
+ specs_by_name(name).select {|spec| spec.version == version }
end
def specs_by_name(name)
- @specs[name]&.values || EMPTY_SEARCH
+ @specs[name].values
end
EMPTY_SEARCH = [].freeze
def search_by_spec(spec)
- spec = find_by_spec(spec)
+ spec = @specs[spec.name][spec.full_name]
spec ? [spec] : EMPTY_SEARCH
end
-
- def find_by_spec(spec)
- @specs[spec.name]&.fetch(spec.full_name, nil)
- end
-
- def exist?(spec)
- @specs[spec.name]&.key?(spec.full_name)
- end
end
end
diff --git a/lib/bundler/injector.rb b/lib/bundler/injector.rb
index c7e93c9ee0..cb644a7f69 100644
--- a/lib/bundler/injector.rb
+++ b/lib/bundler/injector.rb
@@ -23,10 +23,13 @@ module Bundler
# @param [Pathname] lockfile_path The lockfile in which to inject the new dependency.
# @return [Array]
def inject(gemfile_path, lockfile_path)
- Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true)
+ if Bundler.frozen_bundle?
+ # ensure the lock and Gemfile are synced
+ Bundler.definition.ensure_equivalent_gemfile_and_lockfile(true)
+ end
# temporarily unfreeze
- Bundler.settings.temporary(deployment: false, frozen: false) do
+ Bundler.settings.temporary(:deployment => false, :frozen => false) do
# evaluate the Gemfile we have now
builder = Dsl.new
builder.eval_gemfile(gemfile_path)
@@ -47,7 +50,7 @@ module Bundler
append_to(gemfile_path, build_gem_lines(@options[:conservative_versioning])) if @deps.any?
# since we resolved successfully, write out the lockfile
- @definition.lock
+ @definition.lock(Bundler.default_lockfile)
# invalidate the cached Bundler.definition
Bundler.reset_paths!
@@ -83,7 +86,7 @@ module Bundler
segments = version.segments
seg_end_index = version >= Gem::Version.new("1.0") ? 1 : 2
- prerelease_suffix = version.to_s.delete_prefix(version.release.to_s) if version.prerelease?
+ prerelease_suffix = version.to_s.gsub(version.release.to_s, "") if version.prerelease?
"#{version_prefix}#{segments[0..seg_end_index].join(".")}#{prerelease_suffix}"
end
@@ -117,10 +120,9 @@ module Bundler
github = ", :github => \"#{d.github}\"" unless d.github.nil?
branch = ", :branch => \"#{d.branch}\"" unless d.branch.nil?
ref = ", :ref => \"#{d.ref}\"" unless d.ref.nil?
- glob = ", :glob => \"#{d.glob}\"" unless d.glob.nil?
require_path = ", :require => #{convert_autorequire(d.autorequire)}" unless d.autorequire.nil?
- %(gem #{name}#{requirement}#{group}#{source}#{path}#{git}#{github}#{branch}#{ref}#{glob}#{require_path})
+ %(gem #{name}#{requirement}#{group}#{source}#{path}#{git}#{github}#{branch}#{ref}#{require_path})
end.join("\n")
end
diff --git a/lib/bundler/inline.rb b/lib/bundler/inline.rb
index ca17d0233e..5c184f67a1 100644
--- a/lib/bundler/inline.rb
+++ b/lib/bundler/inline.rb
@@ -39,56 +39,35 @@ def gemfile(install = false, options = {}, &gemfile)
Bundler.ui = ui
raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty?
- old_gemfile = ENV["BUNDLE_GEMFILE"]
-
- Bundler.unbundle_env!
-
- begin
+ Bundler.with_unbundled_env do
Bundler.instance_variable_set(:@bundle_path, Pathname.new(Gem.dir))
Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile"
Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins?
builder = Bundler::Dsl.new
builder.instance_eval(&gemfile)
+ builder.check_primary_source_safety
- Bundler.settings.temporary(deployment: false, frozen: false) do
+ Bundler.settings.temporary(:deployment => false, :frozen => false) do
definition = builder.to_definition(nil, true)
+ def definition.lock(*); end
definition.validate_runtime!
if install || definition.missing_specs?
- Bundler.settings.temporary(inline: true, no_install: false) do
- installer = Bundler::Installer.install(Bundler.root, definition, system: true)
+ Bundler.settings.temporary(:inline => true, :no_install => false) do
+ installer = Bundler::Installer.install(Bundler.root, definition, :system => true)
installer.post_install_messages.each do |name, message|
Bundler.ui.info "Post-install message from #{name}:\n#{message}"
end
end
end
- begin
- runtime = Bundler::Runtime.new(nil, definition).setup
- rescue Gem::LoadError => e
- name = e.name
- version = e.requirement.requirements.first[1]
- activated_version = Gem.loaded_specs[name].version
-
- Bundler.ui.info \
- "The #{name} gem was resolved to #{version}, but #{activated_version} was activated by Bundler while installing it, causing a conflict. " \
- "Bundler will now retry resolving with #{activated_version} instead."
-
- builder.dependencies.delete_if {|d| d.name == name }
- builder.instance_eval { gem name, activated_version }
- definition = builder.to_definition(nil, true)
-
- retry
- end
-
- runtime.require
- end
- ensure
- if old_gemfile
- ENV["BUNDLE_GEMFILE"] = old_gemfile
- else
- ENV["BUNDLE_GEMFILE"] = ""
+ runtime = Bundler::Runtime.new(nil, definition)
+ runtime.setup.require
end
end
+
+ if ENV["BUNDLE_GEMFILE"].nil?
+ ENV["BUNDLE_GEMFILE"] = ""
+ end
end
diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb
index b65546a10a..59b6a6ad22 100644
--- a/lib/bundler/installer.rb
+++ b/lib/bundler/installer.rb
@@ -69,7 +69,9 @@ module Bundler
Bundler.create_bundle_path
ProcessLock.lock do
- @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment])
+ if Bundler.frozen_bundle?
+ @definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment])
+ end
if @definition.dependencies.empty?
Bundler.ui.warn "The Gemfile specifies no dependencies"
@@ -79,7 +81,7 @@ module Bundler
if resolve_if_needed(options)
ensure_specs_are_compatible!
- Bundler.load_plugins(@definition)
+ load_plugins
options.delete(:jobs)
else
options[:jobs] = 1 # to avoid the overhead of Bundler::Worker
@@ -134,12 +136,12 @@ module Bundler
mode = Gem.win_platform? ? "wb:UTF-8" : "w"
require "erb"
- content = ERB.new(template, trim_mode: "-").result(binding)
+ content = ERB.new(template, :trim_mode => "-").result(binding)
- File.write(binstub_path, content, mode: mode, perm: 0o777 & ~File.umask)
+ File.write(binstub_path, content, :mode => mode, :perm => 0o777 & ~File.umask)
if Gem.win_platform? || options[:all_platforms]
prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n"
- File.write("#{binstub_path}.cmd", prefix + content, mode: mode)
+ File.write("#{binstub_path}.cmd", prefix + content, :mode => mode)
end
end
@@ -177,12 +179,12 @@ module Bundler
mode = Gem.win_platform? ? "wb:UTF-8" : "w"
require "erb"
- content = ERB.new(template, trim_mode: "-").result(binding)
+ content = ERB.new(template, :trim_mode => "-").result(binding)
- File.write("#{bin_path}/#{executable}", content, mode: mode, perm: 0o755)
+ File.write("#{bin_path}/#{executable}", content, :mode => mode, :perm => 0o755)
if Gem.win_platform? || options[:all_platforms]
prefix = "@ruby -x \"%~f0\" %*\n@exit /b %ERRORLEVEL%\n\n"
- File.write("#{bin_path}/#{executable}.cmd", prefix + content, mode: mode)
+ File.write("#{bin_path}/#{executable}.cmd", prefix + content, :mode => mode)
end
end
end
@@ -194,14 +196,9 @@ module Bundler
# that said, it's a rare situation (other than rake), and parallel
# installation is SO MUCH FASTER. so we let people opt in.
def install(options)
- standalone = options[:standalone]
- force = options[:force]
- local = options[:local]
+ force = options["force"]
jobs = installation_parallelization(options)
- spec_installations = ParallelInstaller.call(self, @definition.specs, jobs, standalone, force, local: local)
- spec_installations.each do |installation|
- post_install_messages[installation.name] = installation.post_install_message if installation.has_post_install_message?
- end
+ install_in_parallel jobs, options[:standalone], force
end
def installation_parallelization(options)
@@ -216,6 +213,20 @@ module Bundler
Bundler.settings.processor_count
end
+ def load_plugins
+ Bundler.rubygems.load_plugins
+
+ requested_path_gems = @definition.requested_specs.select {|s| s.source.is_a?(Source::Path) }
+ path_plugin_files = requested_path_gems.map do |spec|
+ Bundler.rubygems.spec_matches_for_glob(spec, "rubygems_plugin#{Bundler.rubygems.suffix_pattern}")
+ rescue TypeError
+ error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
+ raise Gem::InvalidSpecificationException, error_message
+ end.flatten
+ Bundler.rubygems.load_plugin_files(path_plugin_files)
+ Bundler.rubygems.load_env_plugins
+ end
+
def ensure_specs_are_compatible!
@definition.specs.each do |spec|
unless spec.matches_current_ruby?
@@ -229,21 +240,28 @@ module Bundler
end
end
+ def install_in_parallel(size, standalone, force = false)
+ spec_installations = ParallelInstaller.call(self, @definition.specs, size, standalone, force)
+ spec_installations.each do |installation|
+ post_install_messages[installation.name] = installation.post_install_message if installation.has_post_install_message?
+ end
+ end
+
# returns whether or not a re-resolve was needed
def resolve_if_needed(options)
- @definition.prefer_local! if options[:"prefer-local"]
-
- if options[:local] || (@definition.no_resolve_needed? && !@definition.missing_specs?)
- @definition.resolve_with_cache!
- false
- else
- @definition.resolve_remotely!
- true
+ @definition.resolution_mode = options
+
+ if !@definition.unlocking? && !options["force"] && !Bundler.settings[:inline] && Bundler.default_lockfile.file?
+ return false if @definition.nothing_changed? && !@definition.missing_specs?
end
+
+ @definition.setup_sources_for_resolve
+
+ true
end
- def lock
- @definition.lock
+ def lock(opts = {})
+ @definition.lock(Bundler.default_lockfile, opts[:preserve_unknown_sections])
end
end
end
diff --git a/lib/bundler/installer/gem_installer.rb b/lib/bundler/installer/gem_installer.rb
index 1da91857bd..9a013eea4d 100644
--- a/lib/bundler/installer/gem_installer.rb
+++ b/lib/bundler/installer/gem_installer.rb
@@ -2,28 +2,27 @@
module Bundler
class GemInstaller
- attr_reader :spec, :standalone, :worker, :force, :local, :installer
+ attr_reader :spec, :standalone, :worker, :force, :installer
- def initialize(spec, installer, standalone = false, worker = 0, force = false, local = false)
+ def initialize(spec, installer, standalone = false, worker = 0, force = false)
@spec = spec
@installer = installer
@standalone = standalone
@worker = worker
@force = force
- @local = local
end
def install_from_spec
post_install_message = install
Bundler.ui.debug "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}"
generate_executable_stubs
- [true, post_install_message]
- rescue Bundler::InstallHookError, Bundler::SecurityError, Bundler::APIResponseMismatchError, Bundler::InsecureInstallPathError
+ return true, post_install_message
+ rescue Bundler::InstallHookError, Bundler::SecurityError, Bundler::APIResponseMismatchError
raise
rescue Errno::ENOSPC
- [false, out_of_space_message]
- rescue Bundler::BundlerError, Gem::InstallError => e
- [false, specific_failure_message(e)]
+ return false, out_of_space_message
+ rescue Bundler::BundlerError, Gem::InstallError, Bundler::APIResponseInvalidDependenciesError => e
+ return false, specific_failure_message(e)
end
private
@@ -54,10 +53,10 @@ module Bundler
def install
spec.source.install(
spec,
- force: force,
- local: local,
- build_args: Array(spec_settings),
- previous_spec: previous_spec,
+ :force => force,
+ :ensure_builtin_gems_cached => standalone,
+ :build_args => Array(spec_settings),
+ :previous_spec => previous_spec,
)
end
@@ -78,7 +77,7 @@ module Bundler
if Bundler.settings[:bin] && standalone
installer.generate_standalone_bundler_executable_stubs(spec)
elsif Bundler.settings[:bin]
- installer.generate_bundler_executable_stubs(spec, force: true)
+ installer.generate_bundler_executable_stubs(spec, :force => true)
end
end
end
diff --git a/lib/bundler/installer/parallel_installer.rb b/lib/bundler/installer/parallel_installer.rb
index d10e5ec924..83a381f592 100644
--- a/lib/bundler/installer/parallel_installer.rb
+++ b/lib/bundler/installer/parallel_installer.rb
@@ -42,7 +42,8 @@ module Bundler
# Checks installed dependencies against spec's dependencies to make
# sure needed dependencies have been installed.
- def dependencies_installed?(installed_specs)
+ def dependencies_installed?(all_specs)
+ installed_specs = all_specs.select(&:installed?).map(&:name)
dependencies.all? {|d| installed_specs.include? d.name }
end
@@ -62,24 +63,20 @@ module Bundler
end
end
- def self.call(*args, **kwargs)
- new(*args, **kwargs).call
+ def self.call(*args)
+ new(*args).call
end
attr_reader :size
- def initialize(installer, all_specs, size, standalone, force, local: false, skip: nil)
+ def initialize(installer, all_specs, size, standalone, force)
@installer = installer
@size = size
@standalone = standalone
@force = force
- @local = local
@specs = all_specs.map {|s| SpecInstallation.new(s) }
- @specs.each do |spec_install|
- spec_install.state = :installed if skip.include?(spec_install.name)
- end if skip
@spec_set = all_specs
- @rake = @specs.find {|s| s.name == "rake" unless s.installed? }
+ @rake = @specs.find {|s| s.name == "rake" }
end
def call
@@ -94,12 +91,38 @@ module Bundler
install_serially
end
+ check_for_unmet_dependencies
+
handle_error if failed_specs.any?
@specs
ensure
worker_pool&.stop
end
+ def check_for_unmet_dependencies
+ unmet_dependencies = @specs.map do |s|
+ [
+ s,
+ s.dependencies.reject {|dep| @specs.any? {|spec| dep.matches_spec?(spec.spec) } },
+ ]
+ end.reject {|a| a.last.empty? }
+ return if unmet_dependencies.empty?
+
+ warning = []
+ warning << "Your lockfile doesn't include a valid resolution."
+ warning << "You can fix this by regenerating your lockfile or manually editing the bad locked gems to a version that satisfies all dependencies."
+ warning << "The unmet dependencies are:"
+
+ unmet_dependencies.each do |spec, unmet_spec_dependencies|
+ unmet_spec_dependencies.each do |unmet_spec_dependency|
+ found = @specs.find {|s| s.name == unmet_spec_dependency.name && !unmet_spec_dependency.matches_spec?(s.spec) }
+ warning << "* #{unmet_spec_dependency}, dependency of #{spec.full_name}, unsatisfied by #{found.full_name}"
+ end
+ end
+
+ Bundler.ui.warn(warning.join("\n"))
+ end
+
private
def failed_specs
@@ -128,7 +151,7 @@ module Bundler
def do_install(spec_install, worker_num)
Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL, spec_install)
gem_installer = Bundler::GemInstaller.new(
- spec_install.spec, @installer, @standalone, worker_num, @force, @local
+ spec_install.spec, @installer, @standalone, worker_num, @force
)
success, message = gem_installer.install_from_spec
if success
@@ -186,14 +209,8 @@ module Bundler
# previously installed specifications. We continue until all specs
# are installed.
def enqueue_specs
- installed_specs = {}
- @specs.each do |spec|
- next unless spec.installed?
- installed_specs[spec.name] = true
- end
-
- @specs.each do |spec|
- if spec.ready_to_enqueue? && spec.dependencies_installed?(installed_specs)
+ @specs.select(&:ready_to_enqueue?).each do |spec|
+ if spec.dependencies_installed? @specs
spec.state = :enqueued
worker_pool.enq spec
end
diff --git a/lib/bundler/installer/standalone.rb b/lib/bundler/installer/standalone.rb
index cf5993448c..2a8c9a432d 100644
--- a/lib/bundler/installer/standalone.rb
+++ b/lib/bundler/installer/standalone.rb
@@ -12,7 +12,6 @@ module Bundler
end
File.open File.join(bundler_path, "setup.rb"), "w" do |file|
file.puts "require 'rbconfig'"
- file.puts prevent_gem_activation
file.puts define_path_helpers
file.puts reverse_rubygems_kernel_mixin
paths.each do |path|
@@ -56,21 +55,11 @@ module Bundler
if spec.source.instance_of?(Source::Path) && spec.source.path.absolute?
full_path
else
- SharedHelpers.relative_path_to(full_path, from: Bundler.root.join(bundler_path))
+ Pathname.new(full_path).relative_path_from(Bundler.root.join(bundler_path)).to_s
end
- end
-
- def prevent_gem_activation
- <<~'END'
- module Kernel
- remove_method(:gem) if private_method_defined?(:gem)
-
- def gem(*)
- end
-
- private :gem
- end
- END
+ rescue TypeError
+ error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
+ raise Gem::InvalidSpecificationException.new(error_message)
end
def define_path_helpers
@@ -98,7 +87,8 @@ module Bundler
if Gem.respond_to?(:discover_gems_on_require=)
Gem.discover_gems_on_require = false
else
- [::Kernel.singleton_class, ::Kernel].each do |k|
+ kernel = (class << ::Kernel; self; end)
+ [kernel, ::Kernel].each do |k|
if k.private_method_defined?(:gem_original_require)
private_require = k.private_method_defined?(:require)
k.send(:remove_method, :require)
diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb
index 8669e021c2..c9b161dc0e 100644
--- a/lib/bundler/lazy_specification.rb
+++ b/lib/bundler/lazy_specification.rb
@@ -4,29 +4,16 @@ require_relative "force_platform"
module Bundler
class LazySpecification
- include MatchMetadata
include MatchPlatform
include ForcePlatform
- attr_reader :name, :version, :platform
- attr_accessor :source, :remote, :force_ruby_platform, :dependencies, :required_ruby_version, :required_rubygems_version
-
- alias_method :runtime_dependencies, :dependencies
-
- def self.from_spec(s)
- lazy_spec = new(s.name, s.version, s.platform, s.source)
- lazy_spec.dependencies = s.dependencies
- lazy_spec.required_ruby_version = s.required_ruby_version
- lazy_spec.required_rubygems_version = s.required_rubygems_version
- lazy_spec
- end
+ attr_reader :name, :version, :dependencies, :platform
+ attr_accessor :source, :remote, :force_ruby_platform
def initialize(name, version, platform, source = nil)
@name = name
@version = version
@dependencies = []
- @required_ruby_version = Gem::Requirement.default
- @required_rubygems_version = Gem::Requirement.default
@platform = platform || Gem::Platform::RUBY
@source = source
@force_ruby_platform = default_force_ruby_platform
@@ -40,14 +27,6 @@ module Bundler
end
end
- def lock_name
- @lock_name ||= name_tuple.lock_name
- end
-
- def name_tuple
- Gem::NameTuple.new(@name, @version, @platform)
- end
-
def ==(other)
full_name == other.full_name
end
@@ -82,7 +61,12 @@ module Bundler
def to_lock
out = String.new
- out << " #{lock_name}\n"
+
+ if platform == Gem::Platform::RUBY
+ out << " #{name} (#{version})\n"
+ else
+ out << " #{name} (#{version}-#{platform})\n"
+ end
dependencies.sort_by(&:to_s).uniq.each do |dep|
next if dep.type == :development
@@ -105,7 +89,7 @@ module Bundler
installable_candidates = GemHelpers.select_best_platform_match(matching_specs, target_platform)
- specification = __materialize__(installable_candidates, fallback_to_non_installable: false)
+ specification = __materialize__(installable_candidates, :fallback_to_non_installable => false)
return specification unless specification.nil?
if target_platform != platform
@@ -125,7 +109,9 @@ module Bundler
# bad gem.
def __materialize__(candidates, fallback_to_non_installable: Bundler.frozen_bundle?)
search = candidates.reverse.find do |spec|
- spec.is_a?(StubSpecification) || spec.matches_current_metadata?
+ spec.is_a?(StubSpecification) ||
+ (spec.matches_current_ruby? &&
+ spec.matches_current_rubygems?)
end
if search.nil? && fallback_to_non_installable
search = candidates.last
@@ -136,7 +122,11 @@ module Bundler
end
def to_s
- lock_name
+ @to_s ||= if platform == Gem::Platform::RUBY
+ "#{name} (#{version})"
+ else
+ "#{name} (#{version}-#{platform})"
+ end
end
def git_version
@@ -144,10 +134,6 @@ module Bundler
" #{source.revision[0..6]}"
end
- def force_ruby_platform!
- @force_ruby_platform = true
- end
-
private
def use_exact_resolved_specifications?
diff --git a/lib/bundler/lockfile_generator.rb b/lib/bundler/lockfile_generator.rb
index a646d00ee1..f7ba51b3e6 100644
--- a/lib/bundler/lockfile_generator.rb
+++ b/lib/bundler/lockfile_generator.rb
@@ -19,7 +19,6 @@ module Bundler
add_sources
add_platforms
add_dependencies
- add_checksums
add_locked_ruby_version
add_bundled_with
@@ -66,14 +65,6 @@ module Bundler
end
end
- def add_checksums
- return unless definition.locked_checksums
- checksums = definition.resolve.map do |spec|
- spec.source.checksum_store.to_lock(spec)
- end
- add_section("CHECKSUMS", checksums)
- end
-
def add_locked_ruby_version
return unless locked_ruby_version = definition.locked_ruby_version
add_section("RUBY VERSION", locked_ruby_version.to_s)
diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb
index 8a15e356c4..7360a36752 100644
--- a/lib/bundler/lockfile_parser.rb
+++ b/lib/bundler/lockfile_parser.rb
@@ -2,41 +2,10 @@
module Bundler
class LockfileParser
- class Position
- attr_reader :line, :column
- def initialize(line, column)
- @line = line
- @column = column
- end
-
- def advance!(string)
- lines = string.count("\n")
- if lines > 0
- @line += lines
- @column = string.length - string.rindex("\n")
- else
- @column += string.length
- end
- end
-
- def to_s
- "#{line}:#{column}"
- end
- end
-
- attr_reader(
- :sources,
- :dependencies,
- :specs,
- :platforms,
- :bundler_version,
- :ruby_version,
- :checksums,
- )
+ attr_reader :sources, :dependencies, :specs, :platforms, :bundler_version, :ruby_version
BUNDLED = "BUNDLED WITH"
DEPENDENCIES = "DEPENDENCIES"
- CHECKSUMS = "CHECKSUMS"
PLATFORMS = "PLATFORMS"
RUBY = "RUBY VERSION"
GIT = "GIT"
@@ -44,7 +13,7 @@ module Bundler
PATH = "PATH"
PLUGIN = "PLUGIN SOURCE"
SPECS = " specs:"
- OPTIONS = /^ ([a-z]+): (.*)$/i
+ OPTIONS = /^ ([a-z]+): (.*)$/i.freeze
SOURCE = [GIT, GEM, PATH, PLUGIN].freeze
SECTIONS_BY_VERSION_INTRODUCED = {
@@ -52,18 +21,15 @@ module Bundler
Gem::Version.create("1.10") => [BUNDLED].freeze,
Gem::Version.create("1.12") => [RUBY].freeze,
Gem::Version.create("1.13") => [PLUGIN].freeze,
- Gem::Version.create("2.5.0") => [CHECKSUMS].freeze,
}.freeze
- KNOWN_SECTIONS = SECTIONS_BY_VERSION_INTRODUCED.values.flatten!.freeze
+ KNOWN_SECTIONS = SECTIONS_BY_VERSION_INTRODUCED.values.flatten.freeze
ENVIRONMENT_VERSION_SECTIONS = [BUNDLED, RUBY].freeze
deprecate_constant(:ENVIRONMENT_VERSION_SECTIONS)
def self.sections_in_lockfile(lockfile_contents)
- sections = lockfile_contents.scan(/^\w[\w ]*$/)
- sections.uniq!
- sections
+ lockfile_contents.scan(/^\w[\w ]*$/).uniq
end
def self.unknown_sections_in_lockfile(lockfile_contents)
@@ -72,7 +38,7 @@ module Bundler
def self.sections_to_ignore(base_version = nil)
base_version &&= base_version.release
- base_version ||= Gem::Version.create("1.0")
+ base_version ||= Gem::Version.create("1.0".dup)
attributes = []
SECTIONS_BY_VERSION_INTRODUCED.each do |version, introduced|
next if version <= base_version
@@ -95,53 +61,37 @@ module Bundler
@platforms = []
@sources = []
@dependencies = {}
- @parse_method = nil
+ @state = nil
@specs = {}
- @lockfile_path = begin
- SharedHelpers.relative_lockfile_path
- rescue GemfileNotFound
- "Gemfile.lock"
- end
- @pos = Position.new(1, 1)
if lockfile.match?(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/)
- raise LockfileError, "Your #{@lockfile_path} contains merge conflicts.\n" \
- "Run `git checkout HEAD -- #{@lockfile_path}` first to get a clean lock."
+ raise LockfileError, "Your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} contains merge conflicts.\n" \
+ "Run `git checkout HEAD -- #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` first to get a clean lock."
end
- lockfile.split(/((?:\r?\n)+)/) do |line|
- # split alternates between the line and the following whitespace
- next @pos.advance!(line) if line.match?(/^\s*$/)
-
+ lockfile.split(/(?:\r?\n)+/).each do |line|
if SOURCE.include?(line)
- @parse_method = :parse_source
+ @state = :source
parse_source(line)
elsif line == DEPENDENCIES
- @parse_method = :parse_dependency
- elsif line == CHECKSUMS
- # This is a temporary solution to make this feature disabled by default
- # for all gemfiles that don't already explicitly include the feature.
- @checksums = true
- @parse_method = :parse_checksum
+ @state = :dependency
elsif line == PLATFORMS
- @parse_method = :parse_platform
+ @state = :platform
elsif line == RUBY
- @parse_method = :parse_ruby
+ @state = :ruby
elsif line == BUNDLED
- @parse_method = :parse_bundled_with
+ @state = :bundled_with
elsif /^[^\s]/.match?(line)
- @parse_method = nil
- elsif @parse_method
- send(@parse_method, line)
+ @state = nil
+ elsif @state
+ send("parse_#{@state}", line)
end
- @pos.advance!(line)
end
- @specs = @specs.values.sort_by!(&:full_name)
+ @specs = @specs.values.sort_by(&:full_name)
rescue ArgumentError => e
Bundler.ui.debug(e)
- raise LockfileError, "Your lockfile is unreadable. Run `rm #{@lockfile_path}` " \
- "and then `bundle install` to generate a new lockfile. The error occurred while " \
- "evaluating #{@lockfile_path}:#{@pos}"
+ raise LockfileError, "Your lockfile is unreadable. Run `rm #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` " \
+ "and then `bundle install` to generate a new lockfile."
end
def may_include_redundant_platform_specific_gems?
@@ -160,9 +110,21 @@ module Bundler
def parse_source(line)
case line
when SPECS
- return unless TYPES.key?(@type)
- @current_source = TYPES[@type].from_lock(@opts)
- @sources << @current_source
+ case @type
+ when PATH
+ @current_source = TYPES[@type].from_lock(@opts)
+ @sources << @current_source
+ when GIT
+ @current_source = TYPES[@type].from_lock(@opts)
+ @sources << @current_source
+ when GEM
+ @opts["remotes"] = Array(@opts.delete("remote")).reverse
+ @current_source = TYPES[@type].from_lock(@opts)
+ @sources << @current_source
+ when PLUGIN
+ @current_source = Plugin.source_from_lock(@opts)
+ @sources << @current_source
+ end
when OPTIONS
value = $2
value = true if value == "true"
@@ -192,19 +154,18 @@ module Bundler
(?:#{space}\(([^-]*) # Space, followed by version
(?:-(.*))?\))? # Optional platform
(!)? # Optional pinned marker
- (?:#{space}([^ ]+))? # Optional checksum
$ # Line end
- /xo
+ /xo.freeze
def parse_dependency(line)
return unless line =~ NAME_VERSION
spaces = $1
return unless spaces.size == 2
- name = -$2
+ name = $2
version = $3
pinned = $5
- version = version.split(",").each(&:strip!) if version
+ version = version.split(",").map(&:strip) if version
dep = Bundler::Dependency.new(name, version)
@@ -225,65 +186,40 @@ module Bundler
@dependencies[dep.name] = dep
end
- def parse_checksum(line)
+ def parse_spec(line)
return unless line =~ NAME_VERSION
-
spaces = $1
- return unless spaces.size == 2
- checksums = $6
- return unless checksums
name = $2
version = $3
platform = $4
- version = Gem::Version.new(version)
- platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
- full_name = Gem::NameTuple.new(name, version, platform).full_name
- return unless spec = @specs[full_name]
-
- checksums.split(",") do |lock_checksum|
- column = line.index(lock_checksum) + 1
- checksum = Checksum.from_lock(lock_checksum, "#{@lockfile_path}:#{@pos.line}:#{column}")
- spec.source.checksum_store.register(spec, checksum)
- end
- end
-
- def parse_spec(line)
- return unless line =~ NAME_VERSION
- spaces = $1
- name = -$2
- version = $3
-
if spaces.size == 4
- # only load platform for non-dependency (spec) line
- platform = $4
-
version = Gem::Version.new(version)
platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
- @current_spec = LazySpecification.new(name, version, platform, @current_source)
+ @current_spec = LazySpecification.new(name, version, platform)
+ @current_spec.source = @current_source
@current_source.add_dependency_names(name)
@specs[@current_spec.full_name] = @current_spec
elsif spaces.size == 6
- version = version.split(",").each(&:strip!) if version
+ version = version.split(",").map(&:strip) if version
dep = Gem::Dependency.new(name, version)
@current_spec.dependencies << dep
end
end
def parse_platform(line)
- @platforms << Gem::Platform.new($1.strip) if line =~ /^ (.*)$/
+ @platforms << Gem::Platform.new($1) if line =~ /^ (.*)$/
end
def parse_bundled_with(line)
- line.strip!
+ line = line.strip
return unless Gem::Version.correct?(line)
@bundler_version = Gem::Version.create(line)
end
def parse_ruby(line)
- line.strip!
- @ruby_version = line
+ @ruby_version = line.strip
end
end
end
diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1
index dae05bd945..8549855b0d 100644
--- a/lib/bundler/man/bundle-add.1
+++ b/lib/bundler/man/bundle-add.1
@@ -1,70 +1,82 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-ADD" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-ADD" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install
+.
.SH "SYNOPSIS"
-\fBbundle add\fR \fIGEM_NAME\fR [\-\-group=GROUP] [\-\-version=VERSION] [\-\-source=SOURCE] [\-\-path=PATH] [\-\-git=GIT|\-\-github=GITHUB] [\-\-branch=BRANCH] [\-\-ref=REF] [\-\-skip\-install] [\-\-strict|\-\-optimistic]
+\fBbundle add\fR \fIGEM_NAME\fR [\-\-group=GROUP] [\-\-version=VERSION] [\-\-source=SOURCE] [\-\-path=PATH] [\-\-git=GIT] [\-\-github=GITHUB] [\-\-branch=BRANCH] [\-\-ref=REF] [\-\-skip\-install] [\-\-strict] [\-\-optimistic]
+.
.SH "DESCRIPTION"
-Adds the named gem to the [\fBGemfile(5)\fR][Gemfile(5)] and run \fBbundle install\fR\. \fBbundle install\fR can be avoided by using the flag \fB\-\-skip\-install\fR\.
+Adds the named gem to the Gemfile and run \fBbundle install\fR\. \fBbundle install\fR can be avoided by using the flag \fB\-\-skip\-install\fR\.
+.
+.P
+Example:
+.
+.P
+bundle add rails
+.
+.P
+bundle add rails \-\-version "< 3\.0, > 1\.1"
+.
+.P
+bundle add rails \-\-version "~> 5\.0\.0" \-\-source "https://gems\.example\.com" \-\-group "development"
+.
+.P
+bundle add rails \-\-skip\-install
+.
+.P
+bundle add rails \-\-group "development, test"
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-version\fR, \fB\-v\fR
Specify version requirements(s) for the added gem\.
+.
.TP
\fB\-\-group\fR, \fB\-g\fR
Specify the group(s) for the added gem\. Multiple groups should be separated by commas\.
+.
.TP
\fB\-\-source\fR, \fB\-s\fR
Specify the source for the added gem\.
+.
.TP
\fB\-\-require\fR, \fB\-r\fR
Adds require path to gem\. Provide false, or a path as a string\.
+.
.TP
\fB\-\-path\fR
Specify the file system path for the added gem\.
+.
.TP
\fB\-\-git\fR
Specify the git source for the added gem\.
+.
.TP
\fB\-\-github\fR
Specify the github source for the added gem\.
+.
.TP
\fB\-\-branch\fR
Specify the git branch for the added gem\.
+.
.TP
\fB\-\-ref\fR
Specify the git ref for the added gem\.
+.
.TP
\fB\-\-skip\-install\fR
Adds the gem to the Gemfile but does not install it\.
+.
.TP
\fB\-\-optimistic\fR
Adds optimistic declaration of version\.
+.
.TP
\fB\-\-strict\fR
Adds strict declaration of version\.
-.SH "EXAMPLES"
-.IP "1." 4
-You can add the \fBrails\fR gem to the Gemfile without any version restriction\. The source of the gem will be the global source\.
-.IP
-\fBbundle add rails\fR
-.IP "2." 4
-You can add the \fBrails\fR gem with version greater than 1\.1 (not including 1\.1) and less than 3\.0\.
-.IP
-\fBbundle add rails \-\-version "> 1\.1, < 3\.0"\fR
-.IP "3." 4
-You can use the \fBhttps://gems\.example\.com\fR custom source and assign the gem to a group\.
-.IP
-\fBbundle add rails \-\-version "~> 5\.0\.0" \-\-source "https://gems\.example\.com" \-\-group "development"\fR
-.IP "4." 4
-The following adds the \fBgem\fR entry to the Gemfile without installing the gem\. You can install gems later via \fBbundle install\fR\.
-.IP
-\fBbundle add rails \-\-skip\-install\fR
-.IP "5." 4
-You can assign the gem to more than one group\.
-.IP
-\fBbundle add rails \-\-group "development, test"\fR
-.IP "" 0
-.SH "SEE ALSO"
-Gemfile(5) \fIhttps://bundler\.io/man/gemfile\.5\.html\fR, bundle\-remove(1) \fIbundle\-remove\.1\.html\fR
+
diff --git a/lib/bundler/man/bundle-add.1.ronn b/lib/bundler/man/bundle-add.1.ronn
index 8b38c7a248..37c92e5fcd 100644
--- a/lib/bundler/man/bundle-add.1.ronn
+++ b/lib/bundler/man/bundle-add.1.ronn
@@ -1,19 +1,26 @@
bundle-add(1) -- Add gem to the Gemfile and run bundle install
-==============================================================
+================================================================
## SYNOPSIS
-`bundle add` <GEM_NAME> [--group=GROUP] [--version=VERSION] [--source=SOURCE]
- [--path=PATH] [--git=GIT|--github=GITHUB] [--branch=BRANCH] [--ref=REF]
- [--skip-install] [--strict|--optimistic]
+`bundle add` <GEM_NAME> [--group=GROUP] [--version=VERSION] [--source=SOURCE] [--path=PATH] [--git=GIT] [--github=GITHUB] [--branch=BRANCH] [--ref=REF] [--skip-install] [--strict] [--optimistic]
## DESCRIPTION
+Adds the named gem to the Gemfile and run `bundle install`. `bundle install` can be avoided by using the flag `--skip-install`.
-Adds the named gem to the [`Gemfile(5)`][Gemfile(5)] and run `bundle install`.
-`bundle install` can be avoided by using the flag `--skip-install`.
+Example:
-## OPTIONS
+bundle add rails
+
+bundle add rails --version "< 3.0, > 1.1"
+
+bundle add rails --version "~> 5.0.0" --source "https://gems.example.com" --group "development"
+
+bundle add rails --skip-install
+
+bundle add rails --group "development, test"
+## OPTIONS
* `--version`, `-v`:
Specify version requirements(s) for the added gem.
@@ -49,33 +56,3 @@ Adds the named gem to the [`Gemfile(5)`][Gemfile(5)] and run `bundle install`.
* `--strict`:
Adds strict declaration of version.
-
-## EXAMPLES
-
-1. You can add the `rails` gem to the Gemfile without any version restriction.
- The source of the gem will be the global source.
-
- `bundle add rails`
-
-2. You can add the `rails` gem with version greater than 1.1 (not including 1.1) and less than 3.0.
-
- `bundle add rails --version "> 1.1, < 3.0"`
-
-3. You can use the `https://gems.example.com` custom source and assign the gem
- to a group.
-
- `bundle add rails --version "~> 5.0.0" --source "https://gems.example.com" --group "development"`
-
-4. The following adds the `gem` entry to the Gemfile without installing the
- gem. You can install gems later via `bundle install`.
-
- `bundle add rails --skip-install`
-
-5. You can assign the gem to more than one group.
-
- `bundle add rails --group "development, test"`
-
-## SEE ALSO
-
-[Gemfile(5)](https://bundler.io/man/gemfile.5.html),
-[bundle-remove(1)](bundle-remove.1.html)
diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1
index 56c9966e75..40c338916a 100644
--- a/lib/bundler/man/bundle-binstubs.1
+++ b/lib/bundler/man/bundle-binstubs.1
@@ -1,29 +1,41 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-BINSTUBS" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-BINSTUBS" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-binstubs\fR \- Install the binstubs of the listed gems
+.
.SH "SYNOPSIS"
\fBbundle binstubs\fR \fIGEM_NAME\fR [\-\-force] [\-\-path PATH] [\-\-standalone]
+.
.SH "DESCRIPTION"
Binstubs are scripts that wrap around executables\. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it into \fBbin/\fR\. Binstubs are a shortcut\-or alternative\- to always using \fBbundle exec\fR\. This gives you a file that can be run directly, and one that will always run the correct gem version used by the application\.
+.
.P
For example, if you run \fBbundle binstubs rspec\-core\fR, Bundler will create the file \fBbin/rspec\fR\. That file will contain enough code to load Bundler, tell it to load the bundled gems, and then run rspec\.
+.
.P
This command generates binstubs for executables in \fBGEM_NAME\fR\. Binstubs are put into \fBbin\fR, or the \fB\-\-path\fR directory if one has been set\. Calling binstubs with [GEM [GEM]] will create binstubs for all given gems\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-force\fR
Overwrite existing binstubs if they exist\.
+.
.TP
\fB\-\-path\fR
The location to install the specified binstubs to\. This defaults to \fBbin\fR\.
+.
.TP
\fB\-\-standalone\fR
Makes binstubs that can work without depending on Rubygems or Bundler at runtime\.
+.
.TP
\fB\-\-shebang\fR
-Specify a different shebang executable name than the default (default 'ruby')
+Specify a different shebang executable name than the default (default \'ruby\')
+.
.TP
\fB\-\-all\fR
Create binstubs for all gems in the bundle\.
diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1
index d634eef203..69b1e1e3dd 100644
--- a/lib/bundler/man/bundle-cache.1
+++ b/lib/bundler/man/bundle-cache.1
@@ -1,40 +1,61 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CACHE" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-CACHE" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application
+.
.SH "SYNOPSIS"
\fBbundle cache\fR
+.
.P
alias: \fBpackage\fR, \fBpack\fR
+.
.SH "DESCRIPTION"
Copy all of the \fB\.gem\fR files needed to run the application into the \fBvendor/cache\fR directory\. In the future, when running \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR, use the gems in the cache in preference to the ones on \fBrubygems\.org\fR\.
+.
.SH "GIT AND PATH GEMS"
The \fBbundle cache\fR command can also package \fB:git\fR and \fB:path\fR dependencies besides \.gem files\. This needs to be explicitly enabled via the \fB\-\-all\fR option\. Once used, the \fB\-\-all\fR option will be remembered\.
+.
.SH "SUPPORT FOR MULTIPLE PLATFORMS"
When using gems that have different packages for different platforms, Bundler supports caching of gems for other platforms where the Gemfile has been resolved (i\.e\. present in the lockfile) in \fBvendor/cache\fR\. This needs to be enabled via the \fB\-\-all\-platforms\fR option\. This setting will be remembered in your local bundler configuration\.
+.
.SH "REMOTE FETCHING"
By default, if you run \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR after running bundle cache(1) \fIbundle\-cache\.1\.html\fR, bundler will still connect to \fBrubygems\.org\fR to check whether a platform\-specific gem exists for any of the gems in \fBvendor/cache\fR\.
+.
.P
For instance, consider this Gemfile(5):
+.
.IP "" 4
+.
.nf
+
source "https://rubygems\.org"
gem "nokogiri"
+.
.fi
+.
.IP "" 0
+.
.P
If you run \fBbundle cache\fR under C Ruby, bundler will retrieve the version of \fBnokogiri\fR for the \fB"ruby"\fR platform\. If you deploy to JRuby and run \fBbundle install\fR, bundler is forced to check to see whether a \fB"java"\fR platformed \fBnokogiri\fR exists\.
+.
.P
Even though the \fBnokogiri\fR gem for the Ruby platform is \fItechnically\fR acceptable on JRuby, it has a C extension that does not run on JRuby\. As a result, bundler will, by default, still connect to \fBrubygems\.org\fR to check whether it has a version of one of your gems more specific to your platform\.
+.
.P
This problem is also not limited to the \fB"java"\fR platform\. A similar (common) problem can happen when developing on Windows and deploying to Linux, or even when developing on OSX and deploying to Linux\.
+.
.P
If you know for sure that the gems packaged in \fBvendor/cache\fR are appropriate for the platform you are on, you can run \fBbundle install \-\-local\fR to skip checking for more appropriate gems, and use the ones in \fBvendor/cache\fR\.
+.
.P
One way to be sure that you have the right platformed versions of all your gems is to run \fBbundle cache\fR on an identical machine and check in the gems\. For instance, you can run \fBbundle cache\fR on an identical staging box during your staging process, and check in the \fBvendor/cache\fR before deploying to production\.
+.
.P
By default, bundle cache(1) \fIbundle\-cache\.1\.html\fR fetches and also installs the gems to the default location\. To package the dependencies to \fBvendor/cache\fR without installing them to the local install location, you can run \fBbundle cache \-\-no\-install\fR\.
+.
.SH "HISTORY"
In Bundler 2\.1, \fBcache\fR took in the functionalities of \fBpackage\fR and now \fBpackage\fR and \fBpack\fR are aliases of \fBcache\fR\.
diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1
index e15a41e4fd..748a37e7d1 100644
--- a/lib/bundler/man/bundle-check.1
+++ b/lib/bundler/man/bundle-check.1
@@ -1,23 +1,30 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CHECK" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-CHECK" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems
+.
.SH "SYNOPSIS"
\fBbundle check\fR [\-\-dry\-run] [\-\-gemfile=FILE] [\-\-path=PATH]
+.
.SH "DESCRIPTION"
\fBcheck\fR searches the local machine for each of the gems requested in the Gemfile\. If all gems are found, Bundler prints a success message and exits with a status of 0\.
+.
.P
If not, the first missing gem is listed and Bundler exits status 1\.
-.P
-If the lockfile needs to be updated then it will be resolved using the gems installed on the local machine, if they satisfy the requirements\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-dry\-run\fR
Locks the [\fBGemfile(5)\fR][Gemfile(5)] before running the command\.
+.
.TP
\fB\-\-gemfile\fR
Use the specified gemfile instead of the [\fBGemfile(5)\fR][Gemfile(5)]\.
+.
.TP
\fB\-\-path\fR
Specify a different path than the system default (\fB$BUNDLE_PATH\fR or \fB$GEM_HOME\fR)\. Bundler will remember this value for future installs on this machine\.
diff --git a/lib/bundler/man/bundle-check.1.ronn b/lib/bundler/man/bundle-check.1.ronn
index eb3ff1daf9..f2846b8ff2 100644
--- a/lib/bundler/man/bundle-check.1.ronn
+++ b/lib/bundler/man/bundle-check.1.ronn
@@ -15,9 +15,6 @@ a status of 0.
If not, the first missing gem is listed and Bundler exits status 1.
-If the lockfile needs to be updated then it will be resolved using the gems
-installed on the local machine, if they satisfy the requirements.
-
## OPTIONS
* `--dry-run`:
diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1
index aa5ccf7594..af8f13cd89 100644
--- a/lib/bundler/man/bundle-clean.1
+++ b/lib/bundler/man/bundle-clean.1
@@ -1,16 +1,23 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CLEAN" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-CLEAN" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory
+.
.SH "SYNOPSIS"
\fBbundle clean\fR [\-\-dry\-run] [\-\-force]
+.
.SH "DESCRIPTION"
This command will remove all unused gems in your bundler directory\. This is useful when you have made many changes to your gem dependencies\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-dry\-run\fR
Print the changes, but do not clean the unused gems\.
+.
.TP
\fB\-\-force\fR
Forces cleaning up unused gems even if Bundler is configured to use globally installed gems\. As a consequence, removes all system gems except for the ones in the current application\.
diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1
index 47104fb5c6..4442f33105 100644
--- a/lib/bundler/man/bundle-config.1
+++ b/lib/bundler/man/bundle-config.1
@@ -1,319 +1,512 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CONFIG" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-CONFIG" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-config\fR \- Set bundler configuration options
+.
.SH "SYNOPSIS"
\fBbundle config\fR list
+.
.br
\fBbundle config\fR [get] NAME
+.
.br
\fBbundle config\fR [set] NAME VALUE
+.
.br
\fBbundle config\fR unset NAME
+.
.SH "DESCRIPTION"
-This command allows you to interact with Bundler's configuration system\.
+This command allows you to interact with Bundler\'s configuration system\.
+.
.P
Bundler loads configuration settings in this order:
+.
.IP "1." 4
Local config (\fB<project_root>/\.bundle/config\fR or \fB$BUNDLE_APP_CONFIG/config\fR)
+.
.IP "2." 4
Environmental variables (\fBENV\fR)
+.
.IP "3." 4
Global config (\fB~/\.bundle/config\fR)
+.
.IP "4." 4
Bundler default config
+.
.IP "" 0
+.
.P
Executing \fBbundle config list\fR will print a list of all bundler configuration for the current bundle, and where that configuration was set\.
+.
.P
Executing \fBbundle config get <name>\fR will print the value of that configuration setting, and where it was set\.
+.
.P
Executing \fBbundle config set <name> <value>\fR defaults to setting \fBlocal\fR configuration if executing from within a local application, otherwise it will set \fBglobal\fR configuration\. See \fB\-\-local\fR and \fB\-\-global\fR options below\.
+.
.P
Executing \fBbundle config set \-\-local <name> <value>\fR will set that configuration in the directory for the local application\. The configuration will be stored in \fB<project_root>/\.bundle/config\fR\. If \fBBUNDLE_APP_CONFIG\fR is set, the configuration will be stored in \fB$BUNDLE_APP_CONFIG/config\fR\.
+.
.P
Executing \fBbundle config set \-\-global <name> <value>\fR will set that configuration to the value specified for all bundles executed as the current user\. The configuration will be stored in \fB~/\.bundle/config\fR\. If \fIname\fR already is set, \fIname\fR will be overridden and user will be warned\.
+.
.P
Executing \fBbundle config unset <name>\fR will delete the configuration in both local and global sources\.
+.
.P
Executing \fBbundle config unset \-\-global <name>\fR will delete the configuration only from the user configuration\.
+.
.P
Executing \fBbundle config unset \-\-local <name>\fR will delete the configuration only from the local application\.
+.
.P
Executing bundle with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\.
+.
.SH "REMEMBERING OPTIONS"
-Flags passed to \fBbundle install\fR or the Bundler runtime, such as \fB\-\-path foo\fR or \fB\-\-without production\fR, are remembered between commands and saved to your local application's configuration (normally, \fB\./\.bundle/config\fR)\.
+Flags passed to \fBbundle install\fR or the Bundler runtime, such as \fB\-\-path foo\fR or \fB\-\-without production\fR, are remembered between commands and saved to your local application\'s configuration (normally, \fB\./\.bundle/config\fR)\.
+.
.P
-However, this will be changed in bundler 3, so it's better not to rely on this behavior\. If these options must be remembered, it's better to set them using \fBbundle config\fR (e\.g\., \fBbundle config set \-\-local path foo\fR)\.
+However, this will be changed in bundler 3, so it\'s better not to rely on this behavior\. If these options must be remembered, it\'s better to set them using \fBbundle config\fR (e\.g\., \fBbundle config set \-\-local path foo\fR)\.
+.
.P
The options that can be configured are:
+.
.TP
\fBbin\fR
-Creates a directory (defaults to \fB~/bin\fR) and place any executables from the gem there\. These executables run in Bundler's context\. If used, you might add this directory to your environment's \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\.
+Creates a directory (defaults to \fB~/bin\fR) and place any executables from the gem there\. These executables run in Bundler\'s context\. If used, you might add this directory to your environment\'s \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\.
+.
.TP
\fBdeployment\fR
-In deployment mode, Bundler will 'roll\-out' the bundle for \fBproduction\fR use\. Please check carefully if you want to have this option enabled in \fBdevelopment\fR or \fBtest\fR environments\.
+In deployment mode, Bundler will \'roll\-out\' the bundle for \fBproduction\fR use\. Please check carefully if you want to have this option enabled in \fBdevelopment\fR or \fBtest\fR environments\.
+.
.TP
\fBonly\fR
A space\-separated list of groups to install only gems of the specified groups\.
+.
.TP
\fBpath\fR
-The location to install the specified gems to\. This defaults to Rubygems' setting\. Bundler shares this location with Rubygems, \fBgem install \|\.\|\.\|\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \|\.\|\.\|\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\.
+The location to install the specified gems to\. This defaults to Rubygems\' setting\. Bundler shares this location with Rubygems, \fBgem install \.\.\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \.\.\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\.
+.
.TP
\fBwithout\fR
A space\-separated list of groups referencing gems to skip during installation\.
+.
.TP
\fBwith\fR
A space\-separated list of \fBoptional\fR groups referencing gems to include during installation\.
+.
.SH "BUILD OPTIONS"
You can use \fBbundle config\fR to give Bundler the flags to pass to the gem installer every time bundler tries to install a particular gem\.
+.
.P
A very common example, the \fBmysql\fR gem, requires Snow Leopard users to pass configuration flags to \fBgem install\fR to specify where to find the \fBmysql_config\fR executable\.
+.
.IP "" 4
+.
.nf
+
gem install mysql \-\- \-\-with\-mysql\-config=/usr/local/mysql/bin/mysql_config
+.
.fi
+.
.IP "" 0
+.
.P
Since the specific location of that executable can change from machine to machine, you can specify these flags on a per\-machine basis\.
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global build\.mysql \-\-with\-mysql\-config=/usr/local/mysql/bin/mysql_config
+.
.fi
+.
.IP "" 0
+.
.P
After running this command, every time bundler needs to install the \fBmysql\fR gem, it will pass along the flags you specified\.
+.
.SH "CONFIGURATION KEYS"
Configuration keys in bundler have two forms: the canonical form and the environment variable form\.
+.
.P
-For instance, passing the \fB\-\-without\fR flag to bundle install(1) \fIbundle\-install\.1\.html\fR prevents Bundler from installing certain groups specified in the Gemfile(5)\. Bundler persists this value in \fBapp/\.bundle/config\fR so that calls to \fBBundler\.setup\fR do not try to find gems from the \fBGemfile\fR that you didn't install\. Additionally, subsequent calls to bundle install(1) \fIbundle\-install\.1\.html\fR remember this setting and skip those groups\.
+For instance, passing the \fB\-\-without\fR flag to bundle install(1) \fIbundle\-install\.1\.html\fR prevents Bundler from installing certain groups specified in the Gemfile(5)\. Bundler persists this value in \fBapp/\.bundle/config\fR so that calls to \fBBundler\.setup\fR do not try to find gems from the \fBGemfile\fR that you didn\'t install\. Additionally, subsequent calls to bundle install(1) \fIbundle\-install\.1\.html\fR remember this setting and skip those groups\.
+.
.P
The canonical form of this configuration is \fB"without"\fR\. To convert the canonical form to the environment variable form, capitalize it, and prepend \fBBUNDLE_\fR\. The environment variable form of \fB"without"\fR is \fBBUNDLE_WITHOUT\fR\.
+.
.P
Any periods in the configuration keys must be replaced with two underscores when setting it via environment variables\. The configuration key \fBlocal\.rack\fR becomes the environment variable \fBBUNDLE_LOCAL__RACK\fR\.
+.
.SH "LIST OF AVAILABLE KEYS"
The following is a list of all configuration keys and their purpose\. You can learn more about their operation in bundle install(1) \fIbundle\-install\.1\.html\fR\.
+.
+.IP "\(bu" 4
+\fBallow_deployment_source_credential_changes\fR (\fBBUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES\fR): When in deployment mode, allow changing the credentials to a gem\'s source\. Ex: \fBhttps://some\.host\.com/gems/path/\fR \-> \fBhttps://user_name:password@some\.host\.com/gems/path\fR
+.
.IP "\(bu" 4
\fBallow_offline_install\fR (\fBBUNDLE_ALLOW_OFFLINE_INSTALL\fR): Allow Bundler to use cached data when installing without network access\.
+.
.IP "\(bu" 4
\fBauto_clean_without_path\fR (\fBBUNDLE_AUTO_CLEAN_WITHOUT_PATH\fR): Automatically run \fBbundle clean\fR after installing when an explicit \fBpath\fR has not been set and Bundler is not installing into the system gems\.
+.
.IP "\(bu" 4
\fBauto_install\fR (\fBBUNDLE_AUTO_INSTALL\fR): Automatically run \fBbundle install\fR when gems are missing\.
+.
.IP "\(bu" 4
\fBbin\fR (\fBBUNDLE_BIN\fR): Install executables from gems in the bundle to the specified directory\. Defaults to \fBfalse\fR\.
+.
.IP "\(bu" 4
\fBcache_all\fR (\fBBUNDLE_CACHE_ALL\fR): Cache all gems, including path and git gems\. This needs to be explicitly configured on bundler 1 and bundler 2, but will be the default on bundler 3\.
+.
.IP "\(bu" 4
\fBcache_all_platforms\fR (\fBBUNDLE_CACHE_ALL_PLATFORMS\fR): Cache gems for all platforms\.
+.
.IP "\(bu" 4
\fBcache_path\fR (\fBBUNDLE_CACHE_PATH\fR): The directory that bundler will place cached gems in when running \fBbundle package\fR, and that bundler will look in when installing gems\. Defaults to \fBvendor/cache\fR\.
+.
.IP "\(bu" 4
\fBclean\fR (\fBBUNDLE_CLEAN\fR): Whether Bundler should run \fBbundle clean\fR automatically after \fBbundle install\fR\.
+.
.IP "\(bu" 4
\fBconsole\fR (\fBBUNDLE_CONSOLE\fR): The console that \fBbundle console\fR starts\. Defaults to \fBirb\fR\.
+.
.IP "\(bu" 4
\fBdefault_install_uses_path\fR (\fBBUNDLE_DEFAULT_INSTALL_USES_PATH\fR): Whether a \fBbundle install\fR without an explicit \fB\-\-path\fR argument defaults to installing gems in \fB\.bundle\fR\.
+.
.IP "\(bu" 4
\fBdeployment\fR (\fBBUNDLE_DEPLOYMENT\fR): Disallow changes to the \fBGemfile\fR\. When the \fBGemfile\fR is changed and the lockfile has not been updated, running Bundler commands will be blocked\.
+.
.IP "\(bu" 4
\fBdisable_checksum_validation\fR (\fBBUNDLE_DISABLE_CHECKSUM_VALIDATION\fR): Allow installing gems even if they do not match the checksum provided by RubyGems\.
+.
.IP "\(bu" 4
\fBdisable_exec_load\fR (\fBBUNDLE_DISABLE_EXEC_LOAD\fR): Stop Bundler from using \fBload\fR to launch an executable in\-process in \fBbundle exec\fR\.
+.
.IP "\(bu" 4
\fBdisable_local_branch_check\fR (\fBBUNDLE_DISABLE_LOCAL_BRANCH_CHECK\fR): Allow Bundler to use a local git override without a branch specified in the Gemfile\.
+.
.IP "\(bu" 4
\fBdisable_local_revision_check\fR (\fBBUNDLE_DISABLE_LOCAL_REVISION_CHECK\fR): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository\.
+.
.IP "\(bu" 4
-\fBdisable_shared_gems\fR (\fBBUNDLE_DISABLE_SHARED_GEMS\fR): Stop Bundler from accessing gems installed to RubyGems' normal location\.
+\fBdisable_shared_gems\fR (\fBBUNDLE_DISABLE_SHARED_GEMS\fR): Stop Bundler from accessing gems installed to RubyGems\' normal location\.
+.
.IP "\(bu" 4
\fBdisable_version_check\fR (\fBBUNDLE_DISABLE_VERSION_CHECK\fR): Stop Bundler from checking if a newer Bundler version is available on rubygems\.org\.
+.
.IP "\(bu" 4
-\fBforce_ruby_platform\fR (\fBBUNDLE_FORCE_RUBY_PLATFORM\fR): Ignore the current machine's platform and install only \fBruby\fR platform gems\. As a result, gems with native extensions will be compiled from source\.
+\fBforce_ruby_platform\fR (\fBBUNDLE_FORCE_RUBY_PLATFORM\fR): Ignore the current machine\'s platform and install only \fBruby\fR platform gems\. As a result, gems with native extensions will be compiled from source\.
+.
.IP "\(bu" 4
\fBfrozen\fR (\fBBUNDLE_FROZEN\fR): Disallow changes to the \fBGemfile\fR\. When the \fBGemfile\fR is changed and the lockfile has not been updated, running Bundler commands will be blocked\. Defaults to \fBtrue\fR when \fB\-\-deployment\fR is used\.
+.
.IP "\(bu" 4
\fBgem\.github_username\fR (\fBBUNDLE_GEM__GITHUB_USERNAME\fR): Sets a GitHub username or organization to be used in \fBREADME\fR file when you create a new gem via \fBbundle gem\fR command\. It can be overridden by passing an explicit \fB\-\-github\-username\fR flag to \fBbundle gem\fR\.
+.
.IP "\(bu" 4
\fBgem\.push_key\fR (\fBBUNDLE_GEM__PUSH_KEY\fR): Sets the \fB\-\-key\fR parameter for \fBgem push\fR when using the \fBrake release\fR command with a private gemstash server\.
+.
.IP "\(bu" 4
\fBgemfile\fR (\fBBUNDLE_GEMFILE\fR): The name of the file that bundler should use as the \fBGemfile\fR\. This location of this file also sets the root of the project, which is used to resolve relative paths in the \fBGemfile\fR, among other things\. By default, bundler will search up from the current working directory until it finds a \fBGemfile\fR\.
+.
.IP "\(bu" 4
\fBglobal_gem_cache\fR (\fBBUNDLE_GLOBAL_GEM_CACHE\fR): Whether Bundler should cache all gems globally, rather than locally to the installing Ruby installation\.
+.
.IP "\(bu" 4
\fBignore_funding_requests\fR (\fBBUNDLE_IGNORE_FUNDING_REQUESTS\fR): When set, no funding requests will be printed\.
+.
.IP "\(bu" 4
\fBignore_messages\fR (\fBBUNDLE_IGNORE_MESSAGES\fR): When set, no post install messages will be printed\. To silence a single gem, use dot notation like \fBignore_messages\.httparty true\fR\.
+.
.IP "\(bu" 4
\fBinit_gems_rb\fR (\fBBUNDLE_INIT_GEMS_RB\fR): Generate a \fBgems\.rb\fR instead of a \fBGemfile\fR when running \fBbundle init\fR\.
+.
.IP "\(bu" 4
\fBjobs\fR (\fBBUNDLE_JOBS\fR): The number of gems Bundler can install in parallel\. Defaults to the number of available processors\.
+.
.IP "\(bu" 4
\fBno_install\fR (\fBBUNDLE_NO_INSTALL\fR): Whether \fBbundle package\fR should skip installing gems\.
+.
.IP "\(bu" 4
\fBno_prune\fR (\fBBUNDLE_NO_PRUNE\fR): Whether Bundler should leave outdated gems unpruned when caching\.
+.
.IP "\(bu" 4
\fBonly\fR (\fBBUNDLE_ONLY\fR): A space\-separated list of groups to install only gems of the specified groups\.
+.
.IP "\(bu" 4
\fBpath\fR (\fBBUNDLE_PATH\fR): The location on disk where all gems in your bundle will be located regardless of \fB$GEM_HOME\fR or \fB$GEM_PATH\fR values\. Bundle gems not found in this location will be installed by \fBbundle install\fR\. Defaults to \fBGem\.dir\fR\. When \-\-deployment is used, defaults to vendor/bundle\.
+.
.IP "\(bu" 4
\fBpath\.system\fR (\fBBUNDLE_PATH__SYSTEM\fR): Whether Bundler will install gems into the default system path (\fBGem\.dir\fR)\.
+.
.IP "\(bu" 4
\fBpath_relative_to_cwd\fR (\fBBUNDLE_PATH_RELATIVE_TO_CWD\fR) Makes \fB\-\-path\fR relative to the CWD instead of the \fBGemfile\fR\.
+.
.IP "\(bu" 4
-\fBplugins\fR (\fBBUNDLE_PLUGINS\fR): Enable Bundler's experimental plugin system\.
+\fBplugins\fR (\fBBUNDLE_PLUGINS\fR): Enable Bundler\'s experimental plugin system\.
+.
.IP "\(bu" 4
\fBprefer_patch\fR (BUNDLE_PREFER_PATCH): Prefer updating only to next patch version during updates\. Makes \fBbundle update\fR calls equivalent to \fBbundler update \-\-patch\fR\.
+.
.IP "\(bu" 4
\fBprint_only_version_number\fR (\fBBUNDLE_PRINT_ONLY_VERSION_NUMBER\fR): Print only version number from \fBbundler \-\-version\fR\.
+.
.IP "\(bu" 4
\fBredirect\fR (\fBBUNDLE_REDIRECT\fR): The number of redirects allowed for network requests\. Defaults to \fB5\fR\.
+.
.IP "\(bu" 4
\fBretry\fR (\fBBUNDLE_RETRY\fR): The number of times to retry failed network requests\. Defaults to \fB3\fR\.
+.
.IP "\(bu" 4
\fBsetup_makes_kernel_gem_public\fR (\fBBUNDLE_SETUP_MAKES_KERNEL_GEM_PUBLIC\fR): Have \fBBundler\.setup\fR make the \fBKernel#gem\fR method public, even though RubyGems declares it as private\.
+.
.IP "\(bu" 4
\fBshebang\fR (\fBBUNDLE_SHEBANG\fR): The program name that should be invoked for generated binstubs\. Defaults to the ruby install name used to generate the binstub\.
+.
.IP "\(bu" 4
\fBsilence_deprecations\fR (\fBBUNDLE_SILENCE_DEPRECATIONS\fR): Whether Bundler should silence deprecation warnings for behavior that will be changed in the next major version\.
+.
.IP "\(bu" 4
\fBsilence_root_warning\fR (\fBBUNDLE_SILENCE_ROOT_WARNING\fR): Silence the warning Bundler prints when installing gems as root\.
+.
.IP "\(bu" 4
\fBssl_ca_cert\fR (\fBBUNDLE_SSL_CA_CERT\fR): Path to a designated CA certificate file or folder containing multiple certificates for trusted CAs in PEM format\.
+.
.IP "\(bu" 4
\fBssl_client_cert\fR (\fBBUNDLE_SSL_CLIENT_CERT\fR): Path to a designated file containing a X\.509 client certificate and key in PEM format\.
+.
.IP "\(bu" 4
\fBssl_verify_mode\fR (\fBBUNDLE_SSL_VERIFY_MODE\fR): The SSL verification mode Bundler uses when making HTTPS requests\. Defaults to verify peer\.
+.
.IP "\(bu" 4
\fBsystem_bindir\fR (\fBBUNDLE_SYSTEM_BINDIR\fR): The location where RubyGems installs binstubs\. Defaults to \fBGem\.bindir\fR\.
+.
.IP "\(bu" 4
\fBtimeout\fR (\fBBUNDLE_TIMEOUT\fR): The seconds allowed before timing out for network requests\. Defaults to \fB10\fR\.
+.
.IP "\(bu" 4
\fBupdate_requires_all_flag\fR (\fBBUNDLE_UPDATE_REQUIRES_ALL_FLAG\fR): Require passing \fB\-\-all\fR to \fBbundle update\fR when everything should be updated, and disallow passing no options to \fBbundle update\fR\.
+.
.IP "\(bu" 4
\fBuser_agent\fR (\fBBUNDLE_USER_AGENT\fR): The custom user agent fragment Bundler includes in API requests\.
-.IP "\(bu" 4
-\fBversion\fR (\fBBUNDLE_VERSION\fR): The version of Bundler to use when running under Bundler environment\. Defaults to \fBlockfile\fR\. You can also specify \fBsystem\fR or \fBx\.y\.z\fR\. \fBlockfile\fR will use the Bundler version specified in the \fBGemfile\.lock\fR, \fBsystem\fR will use the system version of Bundler, and \fBx\.y\.z\fR will use the specified version of Bundler\.
+.
.IP "\(bu" 4
\fBwith\fR (\fBBUNDLE_WITH\fR): A \fB:\fR\-separated list of groups whose gems bundler should install\.
+.
.IP "\(bu" 4
\fBwithout\fR (\fBBUNDLE_WITHOUT\fR): A \fB:\fR\-separated list of groups whose gems bundler should not install\.
+.
.IP "" 0
+.
.P
In general, you should set these settings per\-application by using the applicable flag to the bundle install(1) \fIbundle\-install\.1\.html\fR or bundle cache(1) \fIbundle\-cache\.1\.html\fR command\.
+.
.P
You can set them globally either via environment variables or \fBbundle config\fR, whichever is preferable for your setup\. If you use both, environment variables will take preference over global settings\.
+.
.SH "LOCAL GIT REPOS"
Bundler also allows you to work against a git repository locally instead of using the remote version\. This can be achieved by setting up a local override:
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-local local\.GEM_NAME /path/to/local/git/repository
+.
.fi
+.
.IP "" 0
+.
.P
For example, in order to use a local Rack repository, a developer could call:
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-local local\.rack ~/Work/git/rack
+.
.fi
+.
.IP "" 0
+.
.P
-Now instead of checking out the remote git repository, the local override will be used\. Similar to a path source, every time the local git repository change, changes will be automatically picked up by Bundler\. This means a commit in the local git repo will update the revision in the \fBGemfile\.lock\fR to the local git repo revision\. This requires the same attention as git submodules\. Before pushing to the remote, you need to ensure the local override was pushed, otherwise you may point to a commit that only exists in your local machine\. You'll also need to CGI escape your usernames and passwords as well\.
+Now instead of checking out the remote git repository, the local override will be used\. Similar to a path source, every time the local git repository change, changes will be automatically picked up by Bundler\. This means a commit in the local git repo will update the revision in the \fBGemfile\.lock\fR to the local git repo revision\. This requires the same attention as git submodules\. Before pushing to the remote, you need to ensure the local override was pushed, otherwise you may point to a commit that only exists in your local machine\. You\'ll also need to CGI escape your usernames and passwords as well\.
+.
.P
-Bundler does many checks to ensure a developer won't work with invalid references\. Particularly, we force a developer to specify a branch in the \fBGemfile\fR in order to use this feature\. If the branch specified in the \fBGemfile\fR and the current branch in the local git repository do not match, Bundler will abort\. This ensures that a developer is always working against the correct branches, and prevents accidental locking to a different branch\.
+Bundler does many checks to ensure a developer won\'t work with invalid references\. Particularly, we force a developer to specify a branch in the \fBGemfile\fR in order to use this feature\. If the branch specified in the \fBGemfile\fR and the current branch in the local git repository do not match, Bundler will abort\. This ensures that a developer is always working against the correct branches, and prevents accidental locking to a different branch\.
+.
.P
Finally, Bundler also ensures that the current revision in the \fBGemfile\.lock\fR exists in the local git repository\. By doing this, Bundler forces you to fetch the latest changes in the remotes\.
+.
.SH "MIRRORS OF GEM SOURCES"
Bundler supports overriding gem sources with mirrors\. This allows you to configure rubygems\.org as the gem source in your Gemfile while still using your mirror to fetch gems\.
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global mirror\.SOURCE_URL MIRROR_URL
+.
.fi
+.
.IP "" 0
+.
.P
For example, to use a mirror of https://rubygems\.org hosted at https://example\.org:
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global mirror\.https://rubygems\.org https://example\.org
+.
.fi
+.
.IP "" 0
+.
.P
Each mirror also provides a fallback timeout setting\. If the mirror does not respond within the fallback timeout, Bundler will try to use the original server instead of the mirror\.
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global mirror\.SOURCE_URL\.fallback_timeout TIMEOUT
+.
.fi
+.
.IP "" 0
+.
.P
For example, to fall back to rubygems\.org after 3 seconds:
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global mirror\.https://rubygems\.org\.fallback_timeout 3
+.
.fi
+.
.IP "" 0
+.
.P
The default fallback timeout is 0\.1 seconds, but the setting can currently only accept whole seconds (for example, 1, 15, or 30)\.
+.
.SH "CREDENTIALS FOR GEM SOURCES"
Bundler allows you to configure credentials for any gem source, which allows you to avoid putting secrets into your Gemfile\.
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global SOURCE_HOSTNAME USERNAME:PASSWORD
+.
.fi
+.
.IP "" 0
+.
.P
For example, to save the credentials of user \fBclaudette\fR for the gem source at \fBgems\.longerous\.com\fR, you would run:
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global gems\.longerous\.com claudette:s00pers3krit
+.
.fi
+.
.IP "" 0
+.
.P
Or you can set the credentials as an environment variable like this:
+.
.IP "" 4
+.
.nf
+
export BUNDLE_GEMS__LONGEROUS__COM="claudette:s00pers3krit"
+.
.fi
+.
.IP "" 0
+.
.P
For gems with a git source with HTTP(S) URL you can specify credentials like so:
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-global https://github\.com/rubygems/rubygems\.git username:password
+.
.fi
+.
.IP "" 0
+.
.P
Or you can set the credentials as an environment variable like so:
+.
.IP "" 4
+.
.nf
+
export BUNDLE_GITHUB__COM=username:password
+.
.fi
+.
.IP "" 0
+.
.P
This is especially useful for private repositories on hosts such as GitHub, where you can use personal OAuth tokens:
+.
.IP "" 4
+.
.nf
+
export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x\-oauth\-basic
+.
.fi
+.
.IP "" 0
+.
.P
Note that any configured credentials will be redacted by informative commands such as \fBbundle config list\fR or \fBbundle config get\fR, unless you use the \fB\-\-parseable\fR flag\. This is to avoid unintentionally leaking credentials when copy\-pasting bundler output\.
+.
.P
Also note that to guarantee a sane mapping between valid environment variable names and valid host names, bundler makes the following transformations:
+.
.IP "\(bu" 4
-Any \fB\-\fR characters in a host name are mapped to a triple underscore (\fB___\fR) in the corresponding environment variable\.
+Any \fB\-\fR characters in a host name are mapped to a triple dash (\fB___\fR) in the corresponding environment variable\.
+.
.IP "\(bu" 4
-Any \fB\.\fR characters in a host name are mapped to a double underscore (\fB__\fR) in the corresponding environment variable\.
+Any \fB\.\fR characters in a host name are mapped to a double dash (\fB__\fR) in the corresponding environment variable\.
+.
.IP "" 0
+.
.P
-This means that if you have a gem server named \fBmy\.gem\-host\.com\fR, you'll need to use the \fBBUNDLE_MY__GEM___HOST__COM\fR variable to configure credentials for it through ENV\.
+This means that if you have a gem server named \fBmy\.gem\-host\.com\fR, you\'ll need to use the \fBBUNDLE_MY__GEM___HOST__COM\fR variable to configure credentials for it through ENV\.
+.
.SH "CONFIGURE BUNDLER DIRECTORIES"
-Bundler's home, cache and plugin directories and config file can be configured through environment variables\. The default location for Bundler's home directory is \fB~/\.bundle\fR, which all directories inherit from by default\. The following outlines the available environment variables and their default values
+Bundler\'s home, config, cache and plugin directories are able to be configured through environment variables\. The default location for Bundler\'s home directory is \fB~/\.bundle\fR, which all directories inherit from by default\. The following outlines the available environment variables and their default values
+.
.IP "" 4
+.
.nf
+
BUNDLE_USER_HOME : $HOME/\.bundle
BUNDLE_USER_CACHE : $BUNDLE_USER_HOME/cache
BUNDLE_USER_CONFIG : $BUNDLE_USER_HOME/config
BUNDLE_USER_PLUGIN : $BUNDLE_USER_HOME/plugin
+.
.fi
+.
.IP "" 0
diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn
index 1a0ec2a5dc..adc273ec62 100644
--- a/lib/bundler/man/bundle-config.1.ronn
+++ b/lib/bundler/man/bundle-config.1.ronn
@@ -137,6 +137,9 @@ the environment variable `BUNDLE_LOCAL__RACK`.
The following is a list of all configuration keys and their purpose. You can
learn more about their operation in [bundle install(1)](bundle-install.1.html).
+* `allow_deployment_source_credential_changes` (`BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES`):
+ When in deployment mode, allow changing the credentials to a gem's source.
+ Ex: `https://some.host.com/gems/path/` -> `https://user_name:password@some.host.com/gems/path`
* `allow_offline_install` (`BUNDLE_ALLOW_OFFLINE_INSTALL`):
Allow Bundler to use cached data when installing without network access.
* `auto_clean_without_path` (`BUNDLE_AUTO_CLEAN_WITHOUT_PATH`):
@@ -271,12 +274,6 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
and disallow passing no options to `bundle update`.
* `user_agent` (`BUNDLE_USER_AGENT`):
The custom user agent fragment Bundler includes in API requests.
-* `version` (`BUNDLE_VERSION`):
- The version of Bundler to use when running under Bundler environment.
- Defaults to `lockfile`. You can also specify `system` or `x.y.z`.
- `lockfile` will use the Bundler version specified in the `Gemfile.lock`,
- `system` will use the system version of Bundler, and `x.y.z` will use
- the specified version of Bundler.
* `with` (`BUNDLE_WITH`):
A `:`-separated list of groups whose gems bundler should install.
* `without` (`BUNDLE_WITHOUT`):
@@ -385,10 +382,10 @@ copy-pasting bundler output.
Also note that to guarantee a sane mapping between valid environment variable
names and valid host names, bundler makes the following transformations:
-* Any `-` characters in a host name are mapped to a triple underscore (`___`) in the
+* Any `-` characters in a host name are mapped to a triple dash (`___`) in the
corresponding environment variable.
-* Any `.` characters in a host name are mapped to a double underscore (`__`) in the
+* Any `.` characters in a host name are mapped to a double dash (`__`) in the
corresponding environment variable.
This means that if you have a gem server named `my.gem-host.com`, you'll need to
@@ -397,7 +394,7 @@ through ENV.
## CONFIGURE BUNDLER DIRECTORIES
-Bundler's home, cache and plugin directories and config file can be configured
+Bundler's home, config, cache and plugin directories are able to be configured
through environment variables. The default location for Bundler's home directory is
`~/.bundle`, which all directories inherit from by default. The following
outlines the available environment variables and their default values
diff --git a/lib/bundler/man/bundle-console.1 b/lib/bundler/man/bundle-console.1
index f2b2ddaed0..24fff46cec 100644
--- a/lib/bundler/man/bundle-console.1
+++ b/lib/bundler/man/bundle-console.1
@@ -1,35 +1,53 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-CONSOLE" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-CONSOLE" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-console\fR \- Deprecated way to open an IRB session with the bundle pre\-loaded
+.
.SH "SYNOPSIS"
\fBbundle console\fR [GROUP]
+.
.SH "DESCRIPTION"
Starts an interactive Ruby console session in the context of the current bundle\.
+.
.P
If no \fBGROUP\fR is specified, all gems in the \fBdefault\fR group in the Gemfile(5) \fIhttps://bundler\.io/man/gemfile\.5\.html\fR are preliminarily loaded\.
+.
.P
If \fBGROUP\fR is specified, all gems in the given group in the Gemfile in addition to the gems in \fBdefault\fR group are loaded\. Even if the given group does not exist in the Gemfile, IRB console starts without any warning or error\.
+.
.P
The environment variable \fBBUNDLE_CONSOLE\fR or \fBbundle config set console\fR can be used to change the shell from the following:
+.
.IP "\(bu" 4
\fBirb\fR (default)
+.
.IP "\(bu" 4
\fBpry\fR (https://github\.com/pry/pry)
+.
.IP "\(bu" 4
\fBripl\fR (https://github\.com/cldwalker/ripl)
+.
.IP "" 0
+.
.P
\fBbundle console\fR uses irb by default\. An alternative Pry or Ripl can be used with \fBbundle console\fR by adjusting the \fBconsole\fR Bundler setting\. Also make sure that \fBpry\fR or \fBripl\fR is in your Gemfile\.
+.
.SH "EXAMPLE"
+.
.nf
+
$ bundle config set console pry
$ bundle console
-Resolving dependencies\|\.\|\.\|\.
+Resolving dependencies\.\.\.
[1] pry(main)>
+.
.fi
+.
.SH "NOTES"
This command was deprecated in Bundler 2\.1 and will be removed in 3\.0\. Use \fBbin/console\fR script, which can be generated by \fBbundle gem <NAME>\fR\.
+.
.SH "SEE ALSO"
Gemfile(5) \fIhttps://bundler\.io/man/gemfile\.5\.html\fR
diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1
index f225d0cd79..57da8216cb 100644
--- a/lib/bundler/man/bundle-doctor.1
+++ b/lib/bundler/man/bundle-doctor.1
@@ -1,30 +1,44 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-DOCTOR" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-DOCTOR" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-doctor\fR \- Checks the bundle for common problems
+.
.SH "SYNOPSIS"
\fBbundle doctor\fR [\-\-quiet] [\-\-gemfile=GEMFILE]
+.
.SH "DESCRIPTION"
Checks your Gemfile and gem environment for common problems\. If issues are detected, Bundler prints them and exits status 1\. Otherwise, Bundler prints a success message and exits status 0\.
+.
.P
Examples of common problems caught by bundle\-doctor include:
+.
.IP "\(bu" 4
Invalid Bundler settings
+.
.IP "\(bu" 4
Mismatched Ruby versions
+.
.IP "\(bu" 4
Mismatched platforms
+.
.IP "\(bu" 4
Uninstalled gems
+.
.IP "\(bu" 4
Missing dependencies
+.
.IP "" 0
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-quiet\fR
Only output warnings and errors\.
+.
.TP
\fB\-\-gemfile=<gemfile>\fR
-The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project's root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\.
+The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project\'s root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\.
diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1
index e16b7bc747..852788db7a 100644
--- a/lib/bundler/man/bundle-exec.1
+++ b/lib/bundler/man/bundle-exec.1
@@ -1,104 +1,165 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-EXEC" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-EXEC" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-exec\fR \- Execute a command in the context of the bundle
+.
.SH "SYNOPSIS"
\fBbundle exec\fR [\-\-keep\-file\-descriptors] \fIcommand\fR
+.
.SH "DESCRIPTION"
This command executes the command, making all gems specified in the [\fBGemfile(5)\fR][Gemfile(5)] available to \fBrequire\fR in Ruby programs\.
+.
.P
Essentially, if you would normally have run something like \fBrspec spec/my_spec\.rb\fR, and you want to use the gems specified in the [\fBGemfile(5)\fR][Gemfile(5)] and installed via bundle install(1) \fIbundle\-install\.1\.html\fR, you should run \fBbundle exec rspec spec/my_spec\.rb\fR\.
+.
.P
-Note that \fBbundle exec\fR does not require that an executable is available on your shell's \fB$PATH\fR\.
+Note that \fBbundle exec\fR does not require that an executable is available on your shell\'s \fB$PATH\fR\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-keep\-file\-descriptors\fR
-Passes all file descriptors to the new processes\. Default is true from bundler version 2\.2\.26\. Setting it to false is now deprecated\.
+Exec in Ruby 2\.0 began discarding non\-standard file descriptors\. When this flag is passed, exec will revert to the 1\.9 behaviour of passing all file descriptors to the new process\.
+.
.SH "BUNDLE INSTALL \-\-BINSTUBS"
If you use the \fB\-\-binstubs\fR flag in bundle install(1) \fIbundle\-install\.1\.html\fR, Bundler will automatically create a directory (which defaults to \fBapp_root/bin\fR) containing all of the executables available from gems in the bundle\.
+.
.P
After using \fB\-\-binstubs\fR, \fBbin/rspec spec/my_spec\.rb\fR is identical to \fBbundle exec rspec spec/my_spec\.rb\fR\.
+.
.SH "ENVIRONMENT MODIFICATIONS"
\fBbundle exec\fR makes a number of changes to the shell environment, then executes the command you specify in full\.
+.
.IP "\(bu" 4
-make sure that it's still possible to shell out to \fBbundle\fR from inside a command invoked by \fBbundle exec\fR (using \fB$BUNDLE_BIN_PATH\fR)
+make sure that it\'s still possible to shell out to \fBbundle\fR from inside a command invoked by \fBbundle exec\fR (using \fB$BUNDLE_BIN_PATH\fR)
+.
.IP "\(bu" 4
put the directory containing executables (like \fBrails\fR, \fBrspec\fR, \fBrackup\fR) for your bundle on \fB$PATH\fR
+.
.IP "\(bu" 4
make sure that if bundler is invoked in the subshell, it uses the same \fBGemfile\fR (by setting \fBBUNDLE_GEMFILE\fR)
+.
.IP "\(bu" 4
add \fB\-rbundler/setup\fR to \fB$RUBYOPT\fR, which makes sure that Ruby programs invoked in the subshell can see the gems in the bundle
+.
.IP "" 0
+.
.P
It also modifies Rubygems:
+.
.IP "\(bu" 4
disallow loading additional gems not in the bundle
+.
.IP "\(bu" 4
-modify the \fBgem\fR method to be a no\-op if a gem matching the requirements is in the bundle, and to raise a \fBGem::LoadError\fR if it's not
+modify the \fBgem\fR method to be a no\-op if a gem matching the requirements is in the bundle, and to raise a \fBGem::LoadError\fR if it\'s not
+.
.IP "\(bu" 4
Define \fBGem\.refresh\fR to be a no\-op, since the source index is always frozen when using bundler, and to prevent gems from the system leaking into the environment
+.
.IP "\(bu" 4
Override \fBGem\.bin_path\fR to use the gems in the bundle, making system executables work
+.
.IP "\(bu" 4
Add all gems in the bundle into Gem\.loaded_specs
+.
.IP "" 0
+.
.P
-Finally, \fBbundle exec\fR also implicitly modifies \fBGemfile\.lock\fR if the lockfile and the Gemfile do not match\. Bundler needs the Gemfile to determine things such as a gem's groups, \fBautorequire\fR, and platforms, etc\., and that information isn't stored in the lockfile\. The Gemfile and lockfile must be synced in order to \fBbundle exec\fR successfully, so \fBbundle exec\fR updates the lockfile beforehand\.
+Finally, \fBbundle exec\fR also implicitly modifies \fBGemfile\.lock\fR if the lockfile and the Gemfile do not match\. Bundler needs the Gemfile to determine things such as a gem\'s groups, \fBautorequire\fR, and platforms, etc\., and that information isn\'t stored in the lockfile\. The Gemfile and lockfile must be synced in order to \fBbundle exec\fR successfully, so \fBbundle exec\fR updates the lockfile beforehand\.
+.
.SS "Loading"
By default, when attempting to \fBbundle exec\fR to a file with a ruby shebang, Bundler will \fBKernel\.load\fR that file instead of using \fBKernel\.exec\fR\. For the vast majority of cases, this is a performance improvement\. In a rare few cases, this could cause some subtle side\-effects (such as dependence on the exact contents of \fB$0\fR or \fB__FILE__\fR) and the optimization can be disabled by enabling the \fBdisable_exec_load\fR setting\.
+.
.SS "Shelling out"
-Any Ruby code that opens a subshell (like \fBsystem\fR, backticks, or \fB%x{}\fR) will automatically use the current Bundler environment\. If you need to shell out to a Ruby command that is not part of your current bundle, use the \fBwith_unbundled_env\fR method with a block\. Any subshells created inside the block will be given the environment present before Bundler was activated\. For example, Homebrew commands run Ruby, but don't work inside a bundle:
+Any Ruby code that opens a subshell (like \fBsystem\fR, backticks, or \fB%x{}\fR) will automatically use the current Bundler environment\. If you need to shell out to a Ruby command that is not part of your current bundle, use the \fBwith_unbundled_env\fR method with a block\. Any subshells created inside the block will be given the environment present before Bundler was activated\. For example, Homebrew commands run Ruby, but don\'t work inside a bundle:
+.
.IP "" 4
+.
.nf
+
Bundler\.with_unbundled_env do
`brew install wget`
end
+.
.fi
+.
.IP "" 0
+.
.P
Using \fBwith_unbundled_env\fR is also necessary if you are shelling out to a different bundle\. Any Bundler commands run in a subshell will inherit the current Gemfile, so commands that need to run in the context of a different bundle also need to use \fBwith_unbundled_env\fR\.
+.
.IP "" 4
+.
.nf
+
Bundler\.with_unbundled_env do
Dir\.chdir "/other/bundler/project" do
`bundle exec \./script`
end
end
+.
.fi
+.
.IP "" 0
+.
.P
Bundler provides convenience helpers that wrap \fBsystem\fR and \fBexec\fR, and they can be used like this:
+.
.IP "" 4
+.
.nf
-Bundler\.clean_system('brew install wget')
-Bundler\.clean_exec('brew install wget')
+
+Bundler\.clean_system(\'brew install wget\')
+Bundler\.clean_exec(\'brew install wget\')
+.
.fi
+.
.IP "" 0
+.
.SH "RUBYGEMS PLUGINS"
At present, the Rubygems plugin system requires all files named \fBrubygems_plugin\.rb\fR on the load path of \fIany\fR installed gem when any Ruby code requires \fBrubygems\.rb\fR\. This includes executables installed into the system, like \fBrails\fR, \fBrackup\fR, and \fBrspec\fR\.
+.
.P
Since Rubygems plugins can contain arbitrary Ruby code, they commonly end up activating themselves or their dependencies\.
+.
.P
For instance, the \fBgemcutter 0\.5\fR gem depended on \fBjson_pure\fR\. If you had that version of gemcutter installed (even if you \fIalso\fR had a newer version without this problem), Rubygems would activate \fBgemcutter 0\.5\fR and \fBjson_pure <latest>\fR\.
+.
.P
If your Gemfile(5) also contained \fBjson_pure\fR (or a gem with a dependency on \fBjson_pure\fR), the latest version on your system might conflict with the version in your Gemfile(5), or the snapshot version in your \fBGemfile\.lock\fR\.
+.
.P
If this happens, bundler will say:
+.
.IP "" 4
+.
.nf
+
You have already activated json_pure 1\.4\.6 but your Gemfile
requires json_pure 1\.4\.3\. Consider using bundle exec\.
+.
.fi
+.
.IP "" 0
+.
.P
In this situation, you almost certainly want to remove the underlying gem with the problematic gem plugin\. In general, the authors of these plugins (in this case, the \fBgemcutter\fR gem) have released newer versions that are more careful in their plugins\.
+.
.P
You can find a list of all the gems containing gem plugins by running
+.
.IP "" 4
+.
.nf
-ruby \-e "puts Gem\.find_files('rubygems_plugin\.rb')"
+
+ruby \-e "puts Gem\.find_files(\'rubygems_plugin\.rb\')"
+.
.fi
+.
.IP "" 0
+.
.P
-At the very least, you should remove all but the newest version of each gem plugin, and also remove all gem plugins that you aren't using (\fBgem uninstall gem_name\fR)\.
+At the very least, you should remove all but the newest version of each gem plugin, and also remove all gem plugins that you aren\'t using (\fBgem uninstall gem_name\fR)\.
diff --git a/lib/bundler/man/bundle-exec.1.ronn b/lib/bundler/man/bundle-exec.1.ronn
index 9d5b559f26..05948095e2 100644
--- a/lib/bundler/man/bundle-exec.1.ronn
+++ b/lib/bundler/man/bundle-exec.1.ronn
@@ -21,8 +21,9 @@ available on your shell's `$PATH`.
## OPTIONS
* `--keep-file-descriptors`:
- Passes all file descriptors to the new processes. Default is true from
- bundler version 2.2.26. Setting it to false is now deprecated.
+ Exec in Ruby 2.0 began discarding non-standard file descriptors. When this
+ flag is passed, exec will revert to the 1.9 behaviour of passing all file
+ descriptors to the new process.
## BUNDLE INSTALL --BINSTUBS
diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1
index e6e58cd409..8339b727ce 100644
--- a/lib/bundler/man/bundle-gem.1
+++ b/lib/bundler/man/bundle-gem.1
@@ -1,75 +1,105 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-GEM" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-GEM" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem
+.
.SH "SYNOPSIS"
\fBbundle gem\fR \fIGEM_NAME\fR \fIOPTIONS\fR
+.
.SH "DESCRIPTION"
Generates a directory named \fBGEM_NAME\fR with a \fBRakefile\fR, \fBGEM_NAME\.gemspec\fR, and other supporting files and directories that can be used to develop a rubygem with that name\.
+.
.P
Run \fBrake \-T\fR in the resulting project for a list of Rake tasks that can be used to test and publish the gem to rubygems\.org\.
+.
.P
-The generated project skeleton can be customized with OPTIONS, as explained below\. Note that these options can also be specified via Bundler's global configuration file using the following names:
+The generated project skeleton can be customized with OPTIONS, as explained below\. Note that these options can also be specified via Bundler\'s global configuration file using the following names:
+.
.IP "\(bu" 4
\fBgem\.coc\fR
+.
.IP "\(bu" 4
\fBgem\.mit\fR
+.
.IP "\(bu" 4
\fBgem\.test\fR
+.
.IP "" 0
+.
.SH "OPTIONS"
+.
.IP "\(bu" 4
\fB\-\-exe\fR or \fB\-b\fR or \fB\-\-bin\fR: Specify that Bundler should create a binary executable (as \fBexe/GEM_NAME\fR) in the generated rubygem project\. This binary will also be added to the \fBGEM_NAME\.gemspec\fR manifest\. This behavior is disabled by default\.
+.
.IP "\(bu" 4
\fB\-\-no\-exe\fR: Do not create a binary (overrides \fB\-\-exe\fR specified in the global config)\.
+.
.IP "\(bu" 4
-\fB\-\-coc\fR: Add a \fBCODE_OF_CONDUCT\.md\fR file to the root of the generated project\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\.
+\fB\-\-coc\fR: Add a \fBCODE_OF_CONDUCT\.md\fR file to the root of the generated project\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\.
+.
.IP "\(bu" 4
\fB\-\-no\-coc\fR: Do not create a \fBCODE_OF_CONDUCT\.md\fR (overrides \fB\-\-coc\fR specified in the global config)\.
+.
.IP "\(bu" 4
\fB\-\-ext=c\fR, \fB\-\-ext=rust\fR Add boilerplate for C or Rust (currently magnus \fIhttps://docs\.rs/magnus\fR based) extension code to the generated project\. This behavior is disabled by default\.
+.
.IP "\(bu" 4
\fB\-\-no\-ext\fR: Do not add extension code (overrides \fB\-\-ext\fR specified in the global config)\.
+.
.IP "\(bu" 4
-\fB\-\-mit\fR: Add an MIT license to a \fBLICENSE\.txt\fR file in the root of the generated project\. Your name from the global git config is used for the copyright statement\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\.
+\fB\-\-mit\fR: Add an MIT license to a \fBLICENSE\.txt\fR file in the root of the generated project\. Your name from the global git config is used for the copyright statement\. If this option is unspecified, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\.
+.
.IP "\(bu" 4
\fB\-\-no\-mit\fR: Do not create a \fBLICENSE\.txt\fR (overrides \fB\-\-mit\fR specified in the global config)\.
+.
.IP "\(bu" 4
\fB\-t\fR, \fB\-\-test=minitest\fR, \fB\-\-test=rspec\fR, \fB\-\-test=test\-unit\fR: Specify the test framework that Bundler should use when generating the project\. Acceptable values are \fBminitest\fR, \fBrspec\fR and \fBtest\-unit\fR\. The \fBGEM_NAME\.gemspec\fR will be configured and a skeleton test/spec directory will be created based on this option\. Given no option is specified:
+.
.IP
-When Bundler is configured to generate tests, this defaults to Bundler's global config setting \fBgem\.test\fR\.
+When Bundler is configured to generate tests, this defaults to Bundler\'s global config setting \fBgem\.test\fR\.
+.
.IP
When Bundler is configured to not generate tests, an interactive prompt will be displayed and the answer will be used for the current rubygem project\.
+.
.IP
-When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\.
-.IP "\(bu" 4
-\fB\-\-no\-test\fR: Do not use a test framework (overrides \fB\-\-test\fR specified in the global config)\.
+When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\.
+.
.IP "\(bu" 4
\fB\-\-ci\fR, \fB\-\-ci=github\fR, \fB\-\-ci=gitlab\fR, \fB\-\-ci=circle\fR: Specify the continuous integration service that Bundler should use when generating the project\. Acceptable values are \fBgithub\fR, \fBgitlab\fR and \fBcircle\fR\. A configuration file will be generated in the project directory\. Given no option is specified:
+.
.IP
-When Bundler is configured to generate CI files, this defaults to Bundler's global config setting \fBgem\.ci\fR\.
+When Bundler is configured to generate CI files, this defaults to Bundler\'s global config setting \fBgem\.ci\fR\.
+.
.IP
When Bundler is configured to not generate CI files, an interactive prompt will be displayed and the answer will be used for the current rubygem project\.
+.
.IP
-When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\.
-.IP "\(bu" 4
-\fB\-\-no\-ci\fR: Do not use a continuous integration service (overrides \fB\-\-ci\fR specified in the global config)\.
+When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\.
+.
.IP "\(bu" 4
-\fB\-\-linter\fR, \fB\-\-linter=rubocop\fR, \fB\-\-linter=standard\fR: Specify the linter and code formatter that Bundler should add to the project's development dependencies\. Acceptable values are \fBrubocop\fR and \fBstandard\fR\. A configuration file will be generated in the project directory\. Given no option is specified:
+\fB\-\-linter\fR, \fB\-\-linter=rubocop\fR, \fB\-\-linter=standard\fR: Specify the linter and code formatter that Bundler should add to the project\'s development dependencies\. Acceptable values are \fBrubocop\fR and \fBstandard\fR\. A configuration file will be generated in the project directory\. Given no option is specified:
+.
.IP
-When Bundler is configured to add a linter, this defaults to Bundler's global config setting \fBgem\.linter\fR\.
+When Bundler is configured to add a linter, this defaults to Bundler\'s global config setting \fBgem\.linter\fR\.
+.
.IP
When Bundler is configured not to add a linter, an interactive prompt will be displayed and the answer will be used for the current rubygem project\.
+.
.IP
-When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler's global config for future \fBbundle gem\fR use\.
-.IP "\(bu" 4
-\fB\-\-no\-linter\fR: Do not add a linter (overrides \fB\-\-linter\fR specified in the global config)\.
+When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\.
+.
.IP "\(bu" 4
\fB\-e\fR, \fB\-\-edit[=EDITOR]\fR: Open the resulting GEM_NAME\.gemspec in EDITOR, or the default editor if not specified\. The default is \fB$BUNDLER_EDITOR\fR, \fB$VISUAL\fR, or \fB$EDITOR\fR\.
+.
.IP "" 0
+.
.SH "SEE ALSO"
+.
.IP "\(bu" 4
bundle config(1) \fIbundle\-config\.1\.html\fR
+.
.IP "" 0
diff --git a/lib/bundler/man/bundle-gem.1.ronn b/lib/bundler/man/bundle-gem.1.ronn
index 2d71d8dabe..46fa2f179f 100644
--- a/lib/bundler/man/bundle-gem.1.ronn
+++ b/lib/bundler/man/bundle-gem.1.ronn
@@ -76,10 +76,6 @@ configuration file using the following names:
the answer will be saved in Bundler's global config for future `bundle gem`
use.
-* `--no-test`:
- Do not use a test framework (overrides `--test` specified in the global
- config).
-
* `--ci`, `--ci=github`, `--ci=gitlab`, `--ci=circle`:
Specify the continuous integration service that Bundler should use when
generating the project. Acceptable values are `github`, `gitlab`
@@ -96,10 +92,6 @@ configuration file using the following names:
the answer will be saved in Bundler's global config for future `bundle gem`
use.
-* `--no-ci`:
- Do not use a continuous integration service (overrides `--ci` specified in
- the global config).
-
* `--linter`, `--linter=rubocop`, `--linter=standard`:
Specify the linter and code formatter that Bundler should add to the
project's development dependencies. Acceptable values are `rubocop` and
@@ -116,9 +108,6 @@ configuration file using the following names:
the answer will be saved in Bundler's global config for future `bundle gem`
use.
-* `--no-linter`:
- Do not add a linter (overrides `--linter` specified in the global config).
-
* `-e`, `--edit[=EDITOR]`:
Open the resulting GEM_NAME.gemspec in EDITOR, or the default editor if not
specified. The default is `$BUNDLER_EDITOR`, `$VISUAL`, or `$EDITOR`.
diff --git a/lib/bundler/man/bundle-help.1 b/lib/bundler/man/bundle-help.1
index d7a05f824e..9787c2d49f 100644
--- a/lib/bundler/man/bundle-help.1
+++ b/lib/bundler/man/bundle-help.1
@@ -1,9 +1,13 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-HELP" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-HELP" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-help\fR \- Displays detailed help for each subcommand
+.
.SH "SYNOPSIS"
\fBbundle help\fR [COMMAND]
+.
.SH "DESCRIPTION"
Displays detailed help for the given subcommand\. You can specify a single \fBCOMMAND\fR at the same time\. When \fBCOMMAND\fR is omitted, help for \fBhelp\fR command will be displayed\.
diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1
index 6b401a57f4..2cced71520 100644
--- a/lib/bundler/man/bundle-info.1
+++ b/lib/bundler/man/bundle-info.1
@@ -1,13 +1,19 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-INFO" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-INFO" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-info\fR \- Show information for the given gem in your bundle
+.
.SH "SYNOPSIS"
\fBbundle info\fR [GEM_NAME] [\-\-path]
+.
.SH "DESCRIPTION"
Given a gem name present in your bundle, print the basic information about it such as homepage, version, path and summary\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-path\fR
Print the path of the given gem
diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1
index f2e444c7c2..c7a9a155b5 100644
--- a/lib/bundler/man/bundle-init.1
+++ b/lib/bundler/man/bundle-init.1
@@ -1,20 +1,29 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-INIT" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-INIT" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-init\fR \- Generates a Gemfile into the current working directory
+.
.SH "SYNOPSIS"
\fBbundle init\fR [\-\-gemspec=FILE]
+.
.SH "DESCRIPTION"
Init generates a default [\fBGemfile(5)\fR][Gemfile(5)] in the current working directory\. When adding a [\fBGemfile(5)\fR][Gemfile(5)] to a gem with a gemspec, the \fB\-\-gemspec\fR option will automatically add each dependency listed in the gemspec file to the newly created [\fBGemfile(5)\fR][Gemfile(5)]\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-gemspec\fR
Use the specified \.gemspec to create the [\fBGemfile(5)\fR][Gemfile(5)]
+.
.TP
\fB\-\-gemfile\fR
Use the specified name for the gemfile instead of \fBGemfile\fR
+.
.SH "FILES"
Included in the default [\fBGemfile(5)\fR][Gemfile(5)] generated is the line \fB# frozen_string_literal: true\fR\. This is a magic comment supported for the first time in Ruby 2\.3\. The presence of this line results in all string literals in the file being implicitly frozen\.
+.
.SH "SEE ALSO"
Gemfile(5) \fIhttps://bundler\.io/man/gemfile\.5\.html\fR
diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1
index 8eb3633837..9e25c29085 100644
--- a/lib/bundler/man/bundle-inject.1
+++ b/lib/bundler/man/bundle-inject.1
@@ -1,23 +1,36 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-INJECT" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-INJECT" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile
+.
.SH "SYNOPSIS"
\fBbundle inject\fR [GEM] [VERSION]
+.
.SH "DESCRIPTION"
Adds the named gem(s) with their version requirements to the resolved [\fBGemfile(5)\fR][Gemfile(5)]\.
+.
.P
-This command will add the gem to both your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock if it isn't listed yet\.
+This command will add the gem to both your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock if it isn\'t listed yet\.
+.
.P
Example:
+.
.IP "" 4
+.
.nf
+
bundle install
-bundle inject 'rack' '> 0'
+bundle inject \'rack\' \'> 0\'
+.
.fi
+.
.IP "" 0
+.
.P
-This will inject the 'rack' gem with a version greater than 0 in your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock\.
+This will inject the \'rack\' gem with a version greater than 0 in your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock\.
+.
.P
The \fBbundle inject\fR command was deprecated in Bundler 2\.1 and will be removed in Bundler 3\.0\.
diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1
index 7539d18f81..337683af06 100644
--- a/lib/bundler/man/bundle-install.1
+++ b/lib/bundler/man/bundle-install.1
@@ -1,215 +1,313 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-INSTALL" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-INSTALL" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-install\fR \- Install the dependencies specified in your Gemfile
+.
.SH "SYNOPSIS"
-\fBbundle install\fR [\-\-binstubs[=DIRECTORY]] [\-\-clean] [\-\-deployment] [\-\-frozen] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-local] [\-\-no\-cache] [\-\-no\-prune] [\-\-path PATH] [\-\-prefer\-local] [\-\-quiet] [\-\-redownload] [\-\-retry=NUMBER] [\-\-shebang] [\-\-standalone[=GROUP[ GROUP\|\.\|\.\|\.]]] [\-\-system] [\-\-trust\-policy=POLICY] [\-\-with=GROUP[ GROUP\|\.\|\.\|\.]] [\-\-without=GROUP[ GROUP\|\.\|\.\|\.]]
+\fBbundle install\fR [\-\-binstubs[=DIRECTORY]] [\-\-clean] [\-\-deployment] [\-\-frozen] [\-\-full\-index] [\-\-gemfile=GEMFILE] [\-\-jobs=NUMBER] [\-\-local] [\-\-no\-cache] [\-\-no\-prune] [\-\-path PATH] [\-\-quiet] [\-\-redownload] [\-\-retry=NUMBER] [\-\-shebang] [\-\-standalone[=GROUP[ GROUP\.\.\.]]] [\-\-system] [\-\-trust\-policy=POLICY] [\-\-with=GROUP[ GROUP\.\.\.]] [\-\-without=GROUP[ GROUP\.\.\.]]
+.
.SH "DESCRIPTION"
Install the gems specified in your Gemfile(5)\. If this is the first time you run bundle install (and a \fBGemfile\.lock\fR does not exist), Bundler will fetch all remote sources, resolve dependencies and install all needed gems\.
+.
.P
If a \fBGemfile\.lock\fR does exist, and you have not updated your Gemfile(5), Bundler will fetch all remote sources, but use the dependencies specified in the \fBGemfile\.lock\fR instead of resolving dependencies\.
+.
.P
If a \fBGemfile\.lock\fR does exist, and you have updated your Gemfile(5), Bundler will use the dependencies in the \fBGemfile\.lock\fR for all gems that you did not update, but will re\-resolve the dependencies of gems that you did update\. You can find more information about this update process below under \fICONSERVATIVE UPDATING\fR\.
+.
.SH "OPTIONS"
The \fB\-\-clean\fR, \fB\-\-deployment\fR, \fB\-\-frozen\fR, \fB\-\-no\-prune\fR, \fB\-\-path\fR, \fB\-\-shebang\fR, \fB\-\-system\fR, \fB\-\-without\fR and \fB\-\-with\fR options are deprecated because they only make sense if they are applied to every subsequent \fBbundle install\fR run automatically and that requires \fBbundler\fR to silently remember them\. Since \fBbundler\fR will no longer remember CLI flags in future versions, \fBbundle config\fR (see bundle\-config(1)) should be used to apply them permanently\.
+.
.TP
\fB\-\-binstubs[=<directory>]\fR
Binstubs are scripts that wrap around executables\. Bundler creates a small Ruby file (a binstub) that loads Bundler, runs the command, and puts it in \fBbin/\fR\. This lets you link the binstub inside of an application to the exact gem version the application needs\.
+.
.IP
-Creates a directory (defaults to \fB~/bin\fR) and places any executables from the gem there\. These executables run in Bundler's context\. If used, you might add this directory to your environment's \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\.
+Creates a directory (defaults to \fB~/bin\fR) and places any executables from the gem there\. These executables run in Bundler\'s context\. If used, you might add this directory to your environment\'s \fBPATH\fR variable\. For instance, if the \fBrails\fR gem comes with a \fBrails\fR executable, this flag will create a \fBbin/rails\fR executable that ensures that all referred dependencies will be resolved using the bundled gems\.
+.
.TP
\fB\-\-clean\fR
-On finishing the installation Bundler is going to remove any gems not present in the current Gemfile(5)\. Don't worry, gems currently in use will not be removed\.
+On finishing the installation Bundler is going to remove any gems not present in the current Gemfile(5)\. Don\'t worry, gems currently in use will not be removed\.
+.
.IP
This option is deprecated in favor of the \fBclean\fR setting\.
+.
.TP
\fB\-\-deployment\fR
-In \fIdeployment mode\fR, Bundler will 'roll\-out' the bundle for production or CI use\. Please check carefully if you want to have this option enabled in your development environment\.
+In \fIdeployment mode\fR, Bundler will \'roll\-out\' the bundle for production or CI use\. Please check carefully if you want to have this option enabled in your development environment\.
+.
.IP
This option is deprecated in favor of the \fBdeployment\fR setting\.
+.
.TP
\fB\-\-redownload\fR
Force download every gem, even if the required versions are already available locally\.
+.
.TP
\fB\-\-frozen\fR
Do not allow the Gemfile\.lock to be updated after this install\. Exits non\-zero if there are going to be changes to the Gemfile\.lock\.
+.
.IP
This option is deprecated in favor of the \fBfrozen\fR setting\.
+.
.TP
\fB\-\-full\-index\fR
-Bundler will not call Rubygems' API endpoint (default) but download and cache a (currently big) index file of all gems\. Performance can be improved for large bundles that seldom change by enabling this option\.
+Bundler will not call Rubygems\' API endpoint (default) but download and cache a (currently big) index file of all gems\. Performance can be improved for large bundles that seldom change by enabling this option\.
+.
.TP
\fB\-\-gemfile=<gemfile>\fR
-The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project's root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\.
+The location of the Gemfile(5) which Bundler should use\. This defaults to a Gemfile(5) in the current working directory\. In general, Bundler will assume that the location of the Gemfile(5) is also the project\'s root and will try to find \fBGemfile\.lock\fR and \fBvendor/cache\fR relative to this location\.
+.
.TP
\fB\-\-jobs=[<number>]\fR, \fB\-j[<number>]\fR
The maximum number of parallel download and install jobs\. The default is the number of available processors\.
+.
.TP
\fB\-\-local\fR
-Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems' cache or in \fBvendor/cache\fR\. Note that if an appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\.
+Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems\' cache or in \fBvendor/cache\fR\. Note that if an appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\.
+.
.TP
\fB\-\-prefer\-local\fR
-Force using locally installed gems, or gems already present in Rubygems' cache or in \fBvendor/cache\fR, when resolving, even if newer versions are available remotely\. Only attempt to connect to \fBrubygems\.org\fR for gems that are not present locally\.
+Force using locally installed gems, or gems already present in Rubygems\' cache or in \fBvendor/cache\fR, when resolving, even if newer versions are available remotely\. Only attempt to connect to \fBrubygems\.org\fR for gems that are not present locally\.
+.
.TP
\fB\-\-no\-cache\fR
Do not update the cache in \fBvendor/cache\fR with the newly bundled gems\. This does not remove any gems in the cache but keeps the newly bundled gems from being cached during the install\.
+.
.TP
\fB\-\-no\-prune\fR
-Don't remove stale gems from the cache when the installation finishes\.
+Don\'t remove stale gems from the cache when the installation finishes\.
+.
.IP
This option is deprecated in favor of the \fBno_prune\fR setting\.
+.
.TP
\fB\-\-path=<path>\fR
-The location to install the specified gems to\. This defaults to Rubygems' setting\. Bundler shares this location with Rubygems, \fBgem install \|\.\|\.\|\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \|\.\|\.\|\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\.
+The location to install the specified gems to\. This defaults to Rubygems\' setting\. Bundler shares this location with Rubygems, \fBgem install \.\.\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \.\.\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\.
+.
.IP
This option is deprecated in favor of the \fBpath\fR setting\.
+.
.TP
\fB\-\-quiet\fR
Do not print progress information to the standard output\. Instead, Bundler will exit using a status code (\fB$?\fR)\.
+.
.TP
\fB\-\-retry=[<number>]\fR
Retry failed network or git requests for \fInumber\fR times\.
+.
.TP
\fB\-\-shebang=<ruby\-executable>\fR
Uses the specified ruby executable (usually \fBruby\fR) to execute the scripts created with \fB\-\-binstubs\fR\. In addition, if you use \fB\-\-binstubs\fR together with \fB\-\-shebang jruby\fR these executables will be changed to execute \fBjruby\fR instead\.
+.
.IP
This option is deprecated in favor of the \fBshebang\fR setting\.
+.
.TP
\fB\-\-standalone[=<list>]\fR
-Makes a bundle that can work without depending on Rubygems or Bundler at runtime\. A space separated list of groups to install has to be specified\. Bundler creates a directory named \fBbundle\fR and installs the bundle there\. It also generates a \fBbundle/bundler/setup\.rb\fR file to replace Bundler's own setup in the manner required\. Using this option implicitly sets \fBpath\fR, which is a [remembered option][REMEMBERED OPTIONS]\.
+Makes a bundle that can work without depending on Rubygems or Bundler at runtime\. A space separated list of groups to install has to be specified\. Bundler creates a directory named \fBbundle\fR and installs the bundle there\. It also generates a \fBbundle/bundler/setup\.rb\fR file to replace Bundler\'s own setup in the manner required\. Using this option implicitly sets \fBpath\fR, which is a [remembered option][REMEMBERED OPTIONS]\.
+.
.TP
\fB\-\-system\fR
-Installs the gems specified in the bundle to the system's Rubygems location\. This overrides any previous configuration of \fB\-\-path\fR\.
+Installs the gems specified in the bundle to the system\'s Rubygems location\. This overrides any previous configuration of \fB\-\-path\fR\.
+.
.IP
This option is deprecated in favor of the \fBsystem\fR setting\.
+.
.TP
\fB\-\-trust\-policy=[<policy>]\fR
Apply the Rubygems security policy \fIpolicy\fR, where policy is one of \fBHighSecurity\fR, \fBMediumSecurity\fR, \fBLowSecurity\fR, \fBAlmostNoSecurity\fR, or \fBNoSecurity\fR\. For more details, please see the Rubygems signing documentation linked below in \fISEE ALSO\fR\.
+.
.TP
\fB\-\-with=<list>\fR
A space\-separated list of groups referencing gems to install\. If an optional group is given it is installed\. If a group is given that is in the remembered list of groups given to \-\-without, it is removed from that list\.
+.
.IP
This option is deprecated in favor of the \fBwith\fR setting\.
+.
.TP
\fB\-\-without=<list>\fR
A space\-separated list of groups referencing gems to skip during installation\. If a group is given that is in the remembered list of groups given to \-\-with, it is removed from that list\.
+.
.IP
This option is deprecated in favor of the \fBwithout\fR setting\.
+.
.SH "DEPLOYMENT MODE"
-Bundler's defaults are optimized for development\. To switch to defaults optimized for deployment and for CI, use the \fB\-\-deployment\fR flag\. Do not activate deployment mode on development machines, as it will cause an error when the Gemfile(5) is modified\.
+Bundler\'s defaults are optimized for development\. To switch to defaults optimized for deployment and for CI, use the \fB\-\-deployment\fR flag\. Do not activate deployment mode on development machines, as it will cause an error when the Gemfile(5) is modified\.
+.
.IP "1." 4
A \fBGemfile\.lock\fR is required\.
+.
.IP
To ensure that the same versions of the gems you developed with and tested with are also used in deployments, a \fBGemfile\.lock\fR is required\.
+.
.IP
This is mainly to ensure that you remember to check your \fBGemfile\.lock\fR into version control\.
+.
.IP "2." 4
The \fBGemfile\.lock\fR must be up to date
+.
.IP
In development, you can modify your Gemfile(5) and re\-run \fBbundle install\fR to \fIconservatively update\fR your \fBGemfile\.lock\fR snapshot\.
+.
.IP
In deployment, your \fBGemfile\.lock\fR should be up\-to\-date with changes made in your Gemfile(5)\.
+.
.IP "3." 4
Gems are installed to \fBvendor/bundle\fR not your default system location
+.
.IP
-In development, it's convenient to share the gems used in your application with other applications and other scripts that run on the system\.
+In development, it\'s convenient to share the gems used in your application with other applications and other scripts that run on the system\.
+.
.IP
In deployment, isolation is a more important default\. In addition, the user deploying the application may not have permission to install gems to the system, or the web server may not have permission to read them\.
+.
.IP
As a result, \fBbundle install \-\-deployment\fR installs gems to the \fBvendor/bundle\fR directory in the application\. This may be overridden using the \fB\-\-path\fR option\.
+.
.IP "" 0
+.
.SH "INSTALLING GROUPS"
By default, \fBbundle install\fR will install all gems in all groups in your Gemfile(5), except those declared for a different platform\.
+.
.P
However, you can explicitly tell Bundler to skip installing certain groups with the \fB\-\-without\fR option\. This option takes a space\-separated list of groups\.
+.
.P
While the \fB\-\-without\fR option will skip \fIinstalling\fR the gems in the specified groups, it will still \fIdownload\fR those gems and use them to resolve the dependencies of every gem in your Gemfile(5)\.
+.
.P
This is so that installing a different set of groups on another machine (such as a production server) will not change the gems and versions that you have already developed and tested against\.
+.
.P
\fBBundler offers a rock\-solid guarantee that the third\-party code you are running in development and testing is also the third\-party code you are running in production\. You can choose to exclude some of that code in different environments, but you will never be caught flat\-footed by different versions of third\-party code being used in different environments\.\fR
+.
.P
For a simple illustration, consider the following Gemfile(5):
+.
.IP "" 4
+.
.nf
-source 'https://rubygems\.org'
-gem 'sinatra'
+source \'https://rubygems\.org\'
+
+gem \'sinatra\'
group :production do
- gem 'rack\-perftools\-profiler'
+ gem \'rack\-perftools\-profiler\'
end
+.
.fi
+.
.IP "" 0
+.
.P
In this case, \fBsinatra\fR depends on any version of Rack (\fB>= 1\.0\fR), while \fBrack\-perftools\-profiler\fR depends on 1\.x (\fB~> 1\.0\fR)\.
+.
.P
When you run \fBbundle install \-\-without production\fR in development, we look at the dependencies of \fBrack\-perftools\-profiler\fR as well\. That way, you do not spend all your time developing against Rack 2\.0, using new APIs unavailable in Rack 1\.x, only to have Bundler switch to Rack 1\.2 when the \fBproduction\fR group \fIis\fR used\.
+.
.P
This should not cause any problems in practice, because we do not attempt to \fBinstall\fR the gems in the excluded groups, and only evaluate as part of the dependency resolution process\.
+.
.P
This also means that you cannot include different versions of the same gem in different groups, because doing so would result in different sets of dependencies used in development and production\. Because of the vagaries of the dependency resolution process, this usually affects more than the gems you list in your Gemfile(5), and can (surprisingly) radically change the gems you are using\.
+.
.SH "THE GEMFILE\.LOCK"
When you run \fBbundle install\fR, Bundler will persist the full names and versions of all gems that you used (including dependencies of the gems specified in the Gemfile(5)) into a file called \fBGemfile\.lock\fR\.
+.
.P
Bundler uses this file in all subsequent calls to \fBbundle install\fR, which guarantees that you always use the same exact code, even as your application moves across machines\.
+.
.P
Because of the way dependency resolution works, even a seemingly small change (for instance, an update to a point\-release of a dependency of a gem in your Gemfile(5)) can result in radically different gems being needed to satisfy all dependencies\.
+.
.P
As a result, you \fBSHOULD\fR check your \fBGemfile\.lock\fR into version control, in both applications and gems\. If you do not, every machine that checks out your repository (including your production server) will resolve all dependencies again, which will result in different versions of third\-party code being used if \fBany\fR of the gems in the Gemfile(5) or any of their dependencies have been updated\.
+.
.P
When Bundler first shipped, the \fBGemfile\.lock\fR was included in the \fB\.gitignore\fR file included with generated gems\. Over time, however, it became clear that this practice forces the pain of broken dependencies onto new contributors, while leaving existing contributors potentially unaware of the problem\. Since \fBbundle install\fR is usually the first step towards a contribution, the pain of broken dependencies would discourage new contributors from contributing\. As a result, we have revised our guidance for gem authors to now recommend checking in the lock for gems\.
+.
.SH "CONSERVATIVE UPDATING"
When you make a change to the Gemfile(5) and then run \fBbundle install\fR, Bundler will update only the gems that you modified\.
+.
.P
In other words, if a gem that you \fBdid not modify\fR worked before you called \fBbundle install\fR, it will continue to use the exact same versions of all dependencies as it used before the update\.
+.
.P
-Let's take a look at an example\. Here's your original Gemfile(5):
+Let\'s take a look at an example\. Here\'s your original Gemfile(5):
+.
.IP "" 4
+.
.nf
-source 'https://rubygems\.org'
-gem 'actionpack', '2\.3\.8'
-gem 'activemerchant'
+source \'https://rubygems\.org\'
+
+gem \'actionpack\', \'2\.3\.8\'
+gem \'activemerchant\'
+.
.fi
+.
.IP "" 0
+.
.P
In this case, both \fBactionpack\fR and \fBactivemerchant\fR depend on \fBactivesupport\fR\. The \fBactionpack\fR gem depends on \fBactivesupport 2\.3\.8\fR and \fBrack ~> 1\.1\.0\fR, while the \fBactivemerchant\fR gem depends on \fBactivesupport >= 2\.3\.2\fR, \fBbraintree >= 2\.0\.0\fR, and \fBbuilder >= 2\.0\.0\fR\.
+.
.P
When the dependencies are first resolved, Bundler will select \fBactivesupport 2\.3\.8\fR, which satisfies the requirements of both gems in your Gemfile(5)\.
+.
.P
Next, you modify your Gemfile(5) to:
+.
.IP "" 4
+.
.nf
-source 'https://rubygems\.org'
-gem 'actionpack', '3\.0\.0\.rc'
-gem 'activemerchant'
+source \'https://rubygems\.org\'
+
+gem \'actionpack\', \'3\.0\.0\.rc\'
+gem \'activemerchant\'
+.
.fi
+.
.IP "" 0
+.
.P
The \fBactionpack 3\.0\.0\.rc\fR gem has a number of new dependencies, and updates the \fBactivesupport\fR dependency to \fB= 3\.0\.0\.rc\fR and the \fBrack\fR dependency to \fB~> 1\.2\.1\fR\.
+.
.P
When you run \fBbundle install\fR, Bundler notices that you changed the \fBactionpack\fR gem, but not the \fBactivemerchant\fR gem\. It evaluates the gems currently being used to satisfy its requirements:
+.
.TP
\fBactivesupport 2\.3\.8\fR
also used to satisfy a dependency in \fBactivemerchant\fR, which is not being updated
+.
.TP
\fBrack ~> 1\.1\.0\fR
not currently being used to satisfy another dependency
+.
.P
Because you did not explicitly ask to update \fBactivemerchant\fR, you would not expect it to suddenly stop working after updating \fBactionpack\fR\. However, satisfying the new \fBactivesupport 3\.0\.0\.rc\fR dependency of actionpack requires updating one of its dependencies\.
+.
.P
Even though \fBactivemerchant\fR declares a very loose dependency that theoretically matches \fBactivesupport 3\.0\.0\.rc\fR, Bundler treats gems in your Gemfile(5) that have not changed as an atomic unit together with their dependencies\. In this case, the \fBactivemerchant\fR dependency is treated as \fBactivemerchant 1\.7\.1 + activesupport 2\.3\.8\fR, so \fBbundle install\fR will report that it cannot update \fBactionpack\fR\.
+.
.P
To explicitly update \fBactionpack\fR, including its dependencies which other gems in the Gemfile(5) still depend on, run \fBbundle update actionpack\fR (see \fBbundle update(1)\fR)\.
+.
.P
\fBSummary\fR: In general, after making a change to the Gemfile(5) , you should first try to run \fBbundle install\fR, which will guarantee that no other gem in the Gemfile(5) is impacted by the change\. If that does not work, run bundle update(1) \fIbundle\-update\.1\.html\fR\.
+.
.SH "SEE ALSO"
+.
.IP "\(bu" 4
-Gem install docs \fIhttps://guides\.rubygems\.org/rubygems\-basics/#installing\-gems\fR
+Gem install docs \fIhttp://guides\.rubygems\.org/rubygems\-basics/#installing\-gems\fR
+.
.IP "\(bu" 4
-Rubygems signing docs \fIhttps://guides\.rubygems\.org/security/\fR
+Rubygems signing docs \fIhttp://guides\.rubygems\.org/security/\fR
+.
.IP "" 0
diff --git a/lib/bundler/man/bundle-install.1.ronn b/lib/bundler/man/bundle-install.1.ronn
index ed8169de05..be9ed0f974 100644
--- a/lib/bundler/man/bundle-install.1.ronn
+++ b/lib/bundler/man/bundle-install.1.ronn
@@ -14,7 +14,6 @@ bundle-install(1) -- Install the dependencies specified in your Gemfile
[--no-cache]
[--no-prune]
[--path PATH]
- [--prefer-local]
[--quiet]
[--redownload]
[--retry=NUMBER]
@@ -379,5 +378,5 @@ does not work, run [bundle update(1)](bundle-update.1.html).
## SEE ALSO
-* [Gem install docs](https://guides.rubygems.org/rubygems-basics/#installing-gems)
-* [Rubygems signing docs](https://guides.rubygems.org/security/)
+* [Gem install docs](http://guides.rubygems.org/rubygems-basics/#installing-gems)
+* [Rubygems signing docs](http://guides.rubygems.org/security/)
diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1
index 5cbb1c3cfe..1680e6007a 100644
--- a/lib/bundler/man/bundle-list.1
+++ b/lib/bundler/man/bundle-list.1
@@ -1,34 +1,49 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-LIST" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-LIST" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-list\fR \- List all the gems in the bundle
+.
.SH "SYNOPSIS"
-\fBbundle list\fR [\-\-name\-only] [\-\-paths] [\-\-without\-group=GROUP[ GROUP\|\.\|\.\|\.]] [\-\-only\-group=GROUP[ GROUP\|\.\|\.\|\.]]
+\fBbundle list\fR [\-\-name\-only] [\-\-paths] [\-\-without\-group=GROUP[ GROUP\.\.\.]] [\-\-only\-group=GROUP[ GROUP\.\.\.]]
+.
.SH "DESCRIPTION"
Prints a list of all the gems in the bundle including their version\.
+.
.P
Example:
+.
.P
bundle list \-\-name\-only
+.
.P
bundle list \-\-paths
+.
.P
bundle list \-\-without\-group test
+.
.P
bundle list \-\-only\-group dev
+.
.P
bundle list \-\-only\-group dev test \-\-paths
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-name\-only\fR
Print only the name of each gem\.
+.
.TP
\fB\-\-paths\fR
Print the path to each gem in the bundle\.
+.
.TP
\fB\-\-without\-group=<list>\fR
A space\-separated list of groups of gems to skip during printing\.
+.
.TP
\fB\-\-only\-group=<list>\fR
A space\-separated list of groups of gems to print\.
diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1
index 5f0d43a9aa..8722c44b3d 100644
--- a/lib/bundler/man/bundle-lock.1
+++ b/lib/bundler/man/bundle-lock.1
@@ -1,60 +1,84 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-LOCK" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-LOCK" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-lock\fR \- Creates / Updates a lockfile without installing
+.
.SH "SYNOPSIS"
\fBbundle lock\fR [\-\-update] [\-\-local] [\-\-print] [\-\-lockfile=PATH] [\-\-full\-index] [\-\-add\-platform] [\-\-remove\-platform] [\-\-patch] [\-\-minor] [\-\-major] [\-\-strict] [\-\-conservative]
+.
.SH "DESCRIPTION"
Lock the gems specified in Gemfile\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-update=<*gems>\fR
Ignores the existing lockfile\. Resolve then updates lockfile\. Taking a list of gems or updating all gems if no list is given\.
+.
.TP
\fB\-\-local\fR
-Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems' cache or in \fBvendor/cache\fR\. Note that if a appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\.
+Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems\' cache or in \fBvendor/cache\fR\. Note that if a appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\.
+.
.TP
\fB\-\-print\fR
Prints the lockfile to STDOUT instead of writing to the file system\.
+.
.TP
\fB\-\-lockfile=<path>\fR
The path where the lockfile should be written to\.
+.
.TP
\fB\-\-full\-index\fR
Fall back to using the single\-file index of all gems\.
+.
.TP
\fB\-\-add\-platform\fR
Add a new platform to the lockfile, re\-resolving for the addition of that platform\.
+.
.TP
\fB\-\-remove\-platform\fR
Remove a platform from the lockfile\.
+.
.TP
\fB\-\-patch\fR
If updating, prefer updating only to next patch version\.
+.
.TP
\fB\-\-minor\fR
If updating, prefer updating only to next minor version\.
+.
.TP
\fB\-\-major\fR
If updating, prefer updating to next major version (default)\.
+.
.TP
\fB\-\-strict\fR
If updating, do not allow any gem to be updated past latest \-\-patch | \-\-minor | \-\-major\.
+.
.TP
\fB\-\-conservative\fR
If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated\.
+.
.SH "UPDATING ALL GEMS"
If you run \fBbundle lock\fR with \fB\-\-update\fR option without list of gems, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\.
+.
.SH "UPDATING A LIST OF GEMS"
Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\.
+.
.P
For instance, you only want to update \fBnokogiri\fR, run \fBbundle lock \-\-update nokogiri\fR\.
+.
.P
Bundler will update \fBnokogiri\fR and any of its dependencies, but leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\.
+.
.SH "SUPPORTING OTHER PLATFORMS"
-If you want your bundle to support platforms other than the one you're running locally, you can run \fBbundle lock \-\-add\-platform PLATFORM\fR to add PLATFORM to the lockfile, force bundler to re\-resolve and consider the new platform when picking gems, all without needing to have a machine that matches PLATFORM handy to install those platform\-specific gems on\.
+If you want your bundle to support platforms other than the one you\'re running locally, you can run \fBbundle lock \-\-add\-platform PLATFORM\fR to add PLATFORM to the lockfile, force bundler to re\-resolve and consider the new platform when picking gems, all without needing to have a machine that matches PLATFORM handy to install those platform\-specific gems on\.
+.
.P
For a full explanation of gem platforms, see \fBgem help platform\fR\.
+.
.SH "PATCH LEVEL OPTIONS"
See bundle update(1) \fIbundle\-update\.1\.html\fR for details\.
diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1
index fb5ff1fee7..3513f0d09b 100644
--- a/lib/bundler/man/bundle-open.1
+++ b/lib/bundler/man/bundle-open.1
@@ -1,31 +1,51 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-OPEN" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-OPEN" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-open\fR \- Opens the source directory for a gem in your bundle
+.
.SH "SYNOPSIS"
\fBbundle open\fR [GEM] [\-\-path=PATH]
+.
.SH "DESCRIPTION"
Opens the source directory of the provided GEM in your editor\.
+.
.P
For this to work the \fBEDITOR\fR or \fBBUNDLER_EDITOR\fR environment variable has to be set\.
+.
.P
Example:
+.
.IP "" 4
+.
.nf
-bundle open 'rack'
+
+bundle open \'rack\'
+.
.fi
+.
.IP "" 0
+.
.P
-Will open the source directory for the 'rack' gem in your bundle\.
+Will open the source directory for the \'rack\' gem in your bundle\.
+.
.IP "" 4
+.
.nf
-bundle open 'rack' \-\-path 'README\.md'
+
+bundle open \'rack\' \-\-path \'README\.md\'
+.
.fi
+.
.IP "" 0
+.
.P
-Will open the README\.md file of the 'rack' gem source in your bundle\.
+Will open the README\.md file of the \'rack\' gem source in your bundle\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-path\fR
Specify GEM source relative path to open\.
diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1
index ea3005dd87..129ff00f58 100644
--- a/lib/bundler/man/bundle-outdated.1
+++ b/lib/bundler/man/bundle-outdated.1
@@ -1,100 +1,152 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-OUTDATED" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-OUTDATED" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-outdated\fR \- List installed gems with newer versions available
+.
.SH "SYNOPSIS"
\fBbundle outdated\fR [GEM] [\-\-local] [\-\-pre] [\-\-source] [\-\-strict] [\-\-parseable | \-\-porcelain] [\-\-group=GROUP] [\-\-groups] [\-\-patch|\-\-minor|\-\-major] [\-\-filter\-major] [\-\-filter\-minor] [\-\-filter\-patch] [\-\-only\-explicit]
+.
.SH "DESCRIPTION"
Outdated lists the names and versions of gems that have a newer version available in the given source\. Calling outdated with [GEM [GEM]] will only check for newer versions of the given gems\. Prerelease gems are ignored by default\. If your gems are up to date, Bundler will exit with a status of 0\. Otherwise, it will exit 1\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-local\fR
Do not attempt to fetch gems remotely and use the gem cache instead\.
+.
.TP
\fB\-\-pre\fR
Check for newer pre\-release gems\.
+.
.TP
\fB\-\-source\fR
Check against a specific source\.
+.
.TP
\fB\-\-strict\fR
Only list newer versions allowed by your Gemfile requirements, also respecting conservative update flags (\-\-patch, \-\-minor, \-\-major)\.
+.
.TP
\fB\-\-parseable\fR, \fB\-\-porcelain\fR
Use minimal formatting for more parseable output\.
+.
.TP
\fB\-\-group\fR
List gems from a specific group\.
+.
.TP
\fB\-\-groups\fR
List gems organized by groups\.
+.
.TP
\fB\-\-minor\fR
Prefer updating only to next minor version\.
+.
.TP
\fB\-\-major\fR
Prefer updating to next major version (default)\.
+.
.TP
\fB\-\-patch\fR
Prefer updating only to next patch version\.
+.
.TP
\fB\-\-filter\-major\fR
Only list major newer versions\.
+.
.TP
\fB\-\-filter\-minor\fR
Only list minor newer versions\.
+.
.TP
\fB\-\-filter\-patch\fR
Only list patch newer versions\.
+.
.TP
\fB\-\-only\-explicit\fR
Only list gems specified in your Gemfile, not their dependencies\.
+.
.SH "PATCH LEVEL OPTIONS"
See bundle update(1) \fIbundle\-update\.1\.html\fR for details\.
+.
.SH "FILTERING OUTPUT"
The 3 filtering options do not affect the resolution of versions, merely what versions are shown in the output\.
+.
.P
If the regular output shows the following:
+.
.IP "" 4
+.
.nf
+
* Gem Current Latest Requested Groups
* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test
* hashie 1\.2\.0 3\.4\.6 = 1\.2\.0 default
* headless 2\.2\.3 2\.3\.1 = 2\.2\.3 test
+.
.fi
+.
.IP "" 0
+.
.P
\fB\-\-filter\-major\fR would only show:
+.
.IP "" 4
+.
.nf
+
* Gem Current Latest Requested Groups
* hashie 1\.2\.0 3\.4\.6 = 1\.2\.0 default
+.
.fi
+.
.IP "" 0
+.
.P
\fB\-\-filter\-minor\fR would only show:
+.
.IP "" 4
+.
.nf
+
* Gem Current Latest Requested Groups
* headless 2\.2\.3 2\.3\.1 = 2\.2\.3 test
+.
.fi
+.
.IP "" 0
+.
.P
\fB\-\-filter\-patch\fR would only show:
+.
.IP "" 4
+.
.nf
+
* Gem Current Latest Requested Groups
* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test
+.
.fi
+.
.IP "" 0
+.
.P
Filter options can be combined\. \fB\-\-filter\-minor\fR and \fB\-\-filter\-patch\fR would show:
+.
.IP "" 4
+.
.nf
+
* Gem Current Latest Requested Groups
* faker 1\.6\.5 1\.6\.6 ~> 1\.4 development, test
+.
.fi
+.
.IP "" 0
+.
.P
Combining all three \fBfilter\fR options would be the same result as providing none of them\.
diff --git a/lib/bundler/man/bundle-outdated.1.ronn b/lib/bundler/man/bundle-outdated.1.ronn
index 4ac65d0532..27bf21ab9d 100644
--- a/lib/bundler/man/bundle-outdated.1.ronn
+++ b/lib/bundler/man/bundle-outdated.1.ronn
@@ -102,5 +102,4 @@ Filter options can be combined. `--filter-minor` and `--filter-patch` would show
* Gem Current Latest Requested Groups
* faker 1.6.5 1.6.6 ~> 1.4 development, test
-
Combining all three `filter` options would be the same result as providing none of them.
diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1
index c3058175fc..5021c46b4c 100644
--- a/lib/bundler/man/bundle-platform.1
+++ b/lib/bundler/man/bundle-platform.1
@@ -1,27 +1,41 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-PLATFORM" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-PLATFORM" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-platform\fR \- Displays platform compatibility information
+.
.SH "SYNOPSIS"
\fBbundle platform\fR [\-\-ruby]
+.
.SH "DESCRIPTION"
\fBplatform\fR displays information from your Gemfile, Gemfile\.lock, and Ruby VM about your platform\.
+.
.P
For instance, using this Gemfile(5):
+.
.IP "" 4
+.
.nf
+
source "https://rubygems\.org"
ruby "3\.1\.2"
gem "rack"
+.
.fi
+.
.IP "" 0
+.
.P
If you run \fBbundle platform\fR on Ruby 3\.1\.2, it displays the following output:
+.
.IP "" 4
+.
.nf
+
Your platform is: x86_64\-linux
Your app has gems that work on these platforms:
@@ -34,16 +48,24 @@ Your Gemfile specifies a Ruby version requirement:
* ruby 3\.1\.2
Your current platform satisfies the Ruby version requirement\.
+.
.fi
+.
.IP "" 0
+.
.P
-\fBplatform\fR lists all the platforms in your \fBGemfile\.lock\fR as well as the \fBruby\fR directive if applicable from your Gemfile(5)\. It also lets you know if the \fBruby\fR directive requirement has been met\. If \fBruby\fR directive doesn't match the running Ruby VM, it tells you what part does not\.
+\fBplatform\fR lists all the platforms in your \fBGemfile\.lock\fR as well as the \fBruby\fR directive if applicable from your Gemfile(5)\. It also lets you know if the \fBruby\fR directive requirement has been met\. If \fBruby\fR directive doesn\'t match the running Ruby VM, it tells you what part does not\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-ruby\fR
-It will display the ruby directive information, so you don't have to parse it from the Gemfile(5)\.
+It will display the ruby directive information, so you don\'t have to parse it from the Gemfile(5)\.
+.
.SH "SEE ALSO"
+.
.IP "\(bu" 4
bundle\-lock(1) \fIbundle\-lock\.1\.html\fR
+.
.IP "" 0
diff --git a/lib/bundler/man/bundle-plugin.1 b/lib/bundler/man/bundle-plugin.1
index 34437d9973..ec30e1d0fd 100644
--- a/lib/bundler/man/bundle-plugin.1
+++ b/lib/bundler/man/bundle-plugin.1
@@ -1,58 +1,81 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-PLUGIN" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-PLUGIN" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-plugin\fR \- Manage Bundler plugins
+.
.SH "SYNOPSIS"
-\fBbundle plugin\fR install PLUGINS [\-\-source=\fISOURCE\fR] [\-\-version=\fIversion\fR] [\-\-git=\fIgit\-url\fR] [\-\-branch=\fIbranch\fR|\-\-ref=\fIrev\fR] [\-\-path=\fIpath\fR]
+\fBbundle plugin\fR install PLUGINS [\-\-source=\fISOURCE\fR] [\-\-version=\fIversion\fR] [\-\-git|\-\-local_git=\fIgit\-url\fR] [\-\-branch=\fIbranch\fR|\-\-ref=\fIrev\fR]
+.
.br
\fBbundle plugin\fR uninstall PLUGINS
+.
.br
\fBbundle plugin\fR list
+.
.br
\fBbundle plugin\fR help [COMMAND]
+.
.SH "DESCRIPTION"
You can install, uninstall, and list plugin(s) with this command to extend functionalities of Bundler\.
+.
.SH "SUB\-COMMANDS"
+.
.SS "install"
Install the given plugin(s)\.
-.TP
-\fBbundle plugin install bundler\-graph\fR
-Install bundler\-graph gem from globally configured sources (defaults to RubyGems\.org)\. The global source, specified in source in Gemfile is ignored\.
-.TP
-\fBbundle plugin install bundler\-graph \-\-source https://example\.com\fR
-Install bundler\-graph gem from example\.com\. The global source, specified in source in Gemfile is not considered\.
-.TP
-\fBbundle plugin install bundler\-graph \-\-version 0\.2\.1\fR
-You can specify the version of the gem via \fB\-\-version\fR\.
-.TP
-\fBbundle plugin install bundler\-graph \-\-git https://github\.com/rubygems/bundler\-graph\fR
-Install bundler\-graph gem from Git repository\. You can use standard Git URLs like:
-.IP
+.
+.IP "\(bu" 4
+\fBbundle plugin install bundler\-graph\fR: Install bundler\-graph gem from RubyGems\.org\. The global source, specified in source in Gemfile is ignored\.
+.
+.IP "\(bu" 4
+\fBbundle plugin install bundler\-graph \-\-source https://example\.com\fR: Install bundler\-graph gem from example\.com\. The global source, specified in source in Gemfile is not considered\.
+.
+.IP "\(bu" 4
+\fBbundle plugin install bundler\-graph \-\-version 0\.2\.1\fR: You can specify the version of the gem via \fB\-\-version\fR\.
+.
+.IP "\(bu" 4
+\fBbundle plugin install bundler\-graph \-\-git https://github\.com/rubygems/bundler\-graph\fR: Install bundler\-graph gem from Git repository\. \fB\-\-git\fR can be replaced with \fB\-\-local\-git\fR\. You cannot use both \fB\-\-git\fR and \fB\-\-local\-git\fR\. You can use standard Git URLs like:
+.
+.IP "\(bu" 4
\fBssh://[user@]host\.xz[:port]/path/to/repo\.git\fR
-.br
+.
+.IP "\(bu" 4
\fBhttp[s]://host\.xz[:port]/path/to/repo\.git\fR
-.br
+.
+.IP "\(bu" 4
\fB/path/to/repo\fR
-.br
+.
+.IP "\(bu" 4
\fBfile:///path/to/repo\fR
+.
+.IP "" 0
+.
.IP
-When you specify \fB\-\-git\fR, you can use \fB\-\-branch\fR or \fB\-\-ref\fR to specify any branch, tag, or commit hash (revision) to use\.
-.TP
-\fBbundle plugin install bundler\-graph \-\-path \.\./bundler\-graph\fR
-Install bundler\-graph gem from a local path\.
+When you specify \fB\-\-git\fR/\fB\-\-local\-git\fR, you can use \fB\-\-branch\fR or \fB\-\-ref\fR to specify any branch, tag, or commit hash (revision) to use\. When you specify both, only the latter is used\.
+.
+.IP "" 0
+.
.SS "uninstall"
Uninstall the plugin(s) specified in PLUGINS\.
+.
.SS "list"
List the installed plugins and available commands\.
+.
.P
No options\.
+.
.SS "help"
Describe subcommands or one specific subcommand\.
+.
.P
No options\.
+.
.SH "SEE ALSO"
+.
.IP "\(bu" 4
How to write a Bundler plugin \fIhttps://bundler\.io/guides/bundler_plugins\.html\fR
+.
.IP "" 0
diff --git a/lib/bundler/man/bundle-plugin.1.ronn b/lib/bundler/man/bundle-plugin.1.ronn
index b0a34660ea..4f234eeba7 100644
--- a/lib/bundler/man/bundle-plugin.1.ronn
+++ b/lib/bundler/man/bundle-plugin.1.ronn
@@ -4,8 +4,7 @@ bundle-plugin(1) -- Manage Bundler plugins
## SYNOPSIS
`bundle plugin` install PLUGINS [--source=<SOURCE>] [--version=<version>]
- [--git=<git-url>] [--branch=<branch>|--ref=<rev>]
- [--path=<path>]<br>
+ [--git|--local_git=<git-url>] [--branch=<branch>|--ref=<rev>]<br>
`bundle plugin` uninstall PLUGINS<br>
`bundle plugin` list<br>
`bundle plugin` help [COMMAND]
@@ -21,7 +20,7 @@ You can install, uninstall, and list plugin(s) with this command to extend funct
Install the given plugin(s).
* `bundle plugin install bundler-graph`:
- Install bundler-graph gem from globally configured sources (defaults to RubyGems.org). The global source, specified in source in Gemfile is ignored.
+ Install bundler-graph gem from RubyGems.org. The global source, specified in source in Gemfile is ignored.
* `bundle plugin install bundler-graph --source https://example.com`:
Install bundler-graph gem from example.com. The global source, specified in source in Gemfile is not considered.
@@ -30,17 +29,14 @@ Install the given plugin(s).
You can specify the version of the gem via `--version`.
* `bundle plugin install bundler-graph --git https://github.com/rubygems/bundler-graph`:
- Install bundler-graph gem from Git repository. You can use standard Git URLs like:
+ Install bundler-graph gem from Git repository. `--git` can be replaced with `--local-git`. You cannot use both `--git` and `--local-git`. You can use standard Git URLs like:
- `ssh://[user@]host.xz[:port]/path/to/repo.git`<br>
- `http[s]://host.xz[:port]/path/to/repo.git`<br>
- `/path/to/repo`<br>
- `file:///path/to/repo`
+ * `ssh://[user@]host.xz[:port]/path/to/repo.git`
+ * `http[s]://host.xz[:port]/path/to/repo.git`
+ * `/path/to/repo`
+ * `file:///path/to/repo`
- When you specify `--git`, you can use `--branch` or `--ref` to specify any branch, tag, or commit hash (revision) to use.
-
-* `bundle plugin install bundler-graph --path ../bundler-graph`:
- Install bundler-graph gem from a local path.
+ When you specify `--git`/`--local-git`, you can use `--branch` or `--ref` to specify any branch, tag, or commit hash (revision) to use. When you specify both, only the latter is used.
### uninstall
diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1
index 103c6f68ae..af81c48d2b 100644
--- a/lib/bundler/man/bundle-pristine.1
+++ b/lib/bundler/man/bundle-pristine.1
@@ -1,23 +1,34 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-PRISTINE" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-PRISTINE" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-pristine\fR \- Restores installed gems to their pristine condition
+.
.SH "SYNOPSIS"
\fBbundle pristine\fR
+.
.SH "DESCRIPTION"
\fBpristine\fR restores the installed gems in the bundle to their pristine condition using the local gem cache from RubyGems\. For git gems, a forced checkout will be performed\.
+.
.P
-For further explanation, \fBbundle pristine\fR ignores unpacked files on disk\. In other words, this command utilizes the local \fB\.gem\fR cache or the gem's git repository as if one were installing from scratch\.
+For further explanation, \fBbundle pristine\fR ignores unpacked files on disk\. In other words, this command utilizes the local \fB\.gem\fR cache or the gem\'s git repository as if one were installing from scratch\.
+.
.P
-Note: the Bundler gem cannot be restored to its original state with \fBpristine\fR\. One also cannot use \fBbundle pristine\fR on gems with a 'path' option in the Gemfile, because bundler has no original copy it can restore from\.
+Note: the Bundler gem cannot be restored to its original state with \fBpristine\fR\. One also cannot use \fBbundle pristine\fR on gems with a \'path\' option in the Gemfile, because bundler has no original copy it can restore from\.
+.
.P
When is it practical to use \fBbundle pristine\fR?
+.
.P
It comes in handy when a developer is debugging a gem\. \fBbundle pristine\fR is a great way to get rid of experimental changes to a gem that one may not want\.
+.
.P
Why use \fBbundle pristine\fR over \fBgem pristine \-\-all\fR?
+.
.P
Both commands are very similar\. For context: \fBbundle pristine\fR, without arguments, cleans all gems from the lockfile\. Meanwhile, \fBgem pristine \-\-all\fR cleans all installed gems for that Ruby version\.
+.
.P
If a developer forgets which gems in their project they might have been debugging, the Rubygems \fBgem pristine [GEMNAME]\fR command may be inconvenient\. One can avoid waiting for \fBgem pristine \-\-all\fR, and instead run \fBbundle pristine\fR\.
diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1
index 4a2ed4eb13..d86cf134bd 100644
--- a/lib/bundler/man/bundle-remove.1
+++ b/lib/bundler/man/bundle-remove.1
@@ -1,21 +1,31 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-REMOVE" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-REMOVE" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-remove\fR \- Removes gems from the Gemfile
+.
.SH "SYNOPSIS"
-\fBbundle remove [GEM [GEM \|\.\|\.\|\.]] [\-\-install]\fR
+\fBbundle remove [GEM [GEM \.\.\.]] [\-\-install]\fR
+.
.SH "DESCRIPTION"
Removes the given gems from the Gemfile while ensuring that the resulting Gemfile is still valid\. If a gem cannot be removed, a warning is printed\. If a gem is already absent from the Gemfile, and error is raised\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-install\fR
Runs \fBbundle install\fR after the given gems have been removed from the Gemfile, which ensures that both the lockfile and the installed gems on disk are also updated to remove the given gem(s)\.
+.
.P
Example:
+.
.P
bundle remove rails
+.
.P
bundle remove rails rack
+.
.P
bundle remove rails rack \-\-install
diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1
index dfbb439218..aa91176bf2 100644
--- a/lib/bundler/man/bundle-show.1
+++ b/lib/bundler/man/bundle-show.1
@@ -1,15 +1,22 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-SHOW" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-SHOW" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem
+.
.SH "SYNOPSIS"
\fBbundle show\fR [GEM] [\-\-paths]
+.
.SH "DESCRIPTION"
Without the [GEM] option, \fBshow\fR will print a list of the names and versions of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by name\.
+.
.P
Calling show with [GEM] will list the exact location of that gem on your machine\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-paths\fR
List the paths of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by gem name\.
diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1
index 5eb9514f03..e4e10ad23b 100644
--- a/lib/bundler/man/bundle-update.1
+++ b/lib/bundler/man/bundle-update.1
@@ -1,81 +1,114 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-UPDATE" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-UPDATE" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-update\fR \- Update your gems to the latest available versions
+.
.SH "SYNOPSIS"
\fBbundle update\fR \fI*gems\fR [\-\-all] [\-\-group=NAME] [\-\-source=NAME] [\-\-local] [\-\-ruby] [\-\-bundler[=VERSION]] [\-\-full\-index] [\-\-jobs=JOBS] [\-\-quiet] [\-\-patch|\-\-minor|\-\-major] [\-\-redownload] [\-\-strict] [\-\-conservative]
+.
.SH "DESCRIPTION"
Update the gems specified (all gems, if \fB\-\-all\fR flag is used), ignoring the previously installed gems specified in the \fBGemfile\.lock\fR\. In general, you should use bundle install(1) \fIbundle\-install\.1\.html\fR to install the same exact gems and versions across machines\.
+.
.P
You would use \fBbundle update\fR to explicitly update the version of a gem\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-all\fR
Update all gems specified in Gemfile\.
+.
.TP
\fB\-\-group=<name>\fR, \fB\-g=[<name>]\fR
Only update the gems in the specified group\. For instance, you can update all gems in the development group with \fBbundle update \-\-group development\fR\. You can also call \fBbundle update rails \-\-group test\fR to update the rails gem and all gems in the test group, for example\.
+.
.TP
\fB\-\-source=<name>\fR
The name of a \fB:git\fR or \fB:path\fR source used in the Gemfile(5)\. For instance, with a \fB:git\fR source of \fBhttp://github\.com/rails/rails\.git\fR, you would call \fBbundle update \-\-source rails\fR
+.
.TP
\fB\-\-local\fR
Do not attempt to fetch gems remotely and use the gem cache instead\.
+.
.TP
\fB\-\-ruby\fR
Update the locked version of Ruby to the current version of Ruby\.
+.
.TP
\fB\-\-bundler\fR
Update the locked version of bundler to the invoked bundler version\.
+.
.TP
\fB\-\-full\-index\fR
Fall back to using the single\-file index of all gems\.
+.
.TP
\fB\-\-jobs=[<number>]\fR, \fB\-j[<number>]\fR
Specify the number of jobs to run in parallel\. The default is the number of available processors\.
+.
.TP
\fB\-\-retry=[<number>]\fR
Retry failed network or git requests for \fInumber\fR times\.
+.
.TP
\fB\-\-quiet\fR
Only output warnings and errors\.
+.
.TP
\fB\-\-redownload\fR
Force downloading every gem\.
+.
.TP
\fB\-\-patch\fR
Prefer updating only to next patch version\.
+.
.TP
\fB\-\-minor\fR
Prefer updating only to next minor version\.
+.
.TP
\fB\-\-major\fR
Prefer updating to next major version (default)\.
+.
.TP
\fB\-\-strict\fR
Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\.
+.
.TP
\fB\-\-conservative\fR
Use bundle install conservative update behavior and do not allow indirect dependencies to be updated\.
+.
.SH "UPDATING ALL GEMS"
If you run \fBbundle update \-\-all\fR, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\.
+.
.P
Consider the following Gemfile(5):
+.
.IP "" 4
+.
.nf
+
source "https://rubygems\.org"
gem "rails", "3\.0\.0\.rc"
gem "nokogiri"
+.
.fi
+.
.IP "" 0
+.
.P
When you run bundle install(1) \fIbundle\-install\.1\.html\fR the first time, bundler will resolve all of the dependencies, all the way down, and install what you need:
+.
.IP "" 4
+.
.nf
-Fetching gem metadata from https://rubygems\.org/\|\.\|\.\|\.\|\.\|\.\|\.\|\.\|\.\|\.
-Resolving dependencies\|\.\|\.\|\.
+
+Fetching gem metadata from https://rubygems\.org/\.\.\.\.\.\.\.\.\.
+Resolving dependencies\.\.\.
Installing builder 2\.1\.2
Installing abstract 1\.0\.0
Installing rack 1\.2\.8
@@ -105,36 +138,55 @@ Installing nokogiri 1\.6\.5
Bundle complete! 2 Gemfile dependencies, 26 gems total\.
Use `bundle show [gemname]` to see where a bundled gem is installed\.
+.
.fi
+.
.IP "" 0
+.
.P
As you can see, even though you have two gems in the Gemfile(5), your application needs 26 different gems in order to run\. Bundler remembers the exact versions it installed in \fBGemfile\.lock\fR\. The next time you run bundle install(1) \fIbundle\-install\.1\.html\fR, bundler skips the dependency resolution and installs the same gems as it installed last time\.
+.
.P
-After checking in the \fBGemfile\.lock\fR into version control and cloning it on another machine, running bundle install(1) \fIbundle\-install\.1\.html\fR will \fIstill\fR install the gems that you installed last time\. You don't need to worry that a new release of \fBerubis\fR or \fBmail\fR changes the gems you use\.
+After checking in the \fBGemfile\.lock\fR into version control and cloning it on another machine, running bundle install(1) \fIbundle\-install\.1\.html\fR will \fIstill\fR install the gems that you installed last time\. You don\'t need to worry that a new release of \fBerubis\fR or \fBmail\fR changes the gems you use\.
+.
.P
However, from time to time, you might want to update the gems you are using to the newest versions that still match the gems in your Gemfile(5)\.
+.
.P
To do this, run \fBbundle update \-\-all\fR, which will ignore the \fBGemfile\.lock\fR, and resolve all the dependencies again\. Keep in mind that this process can result in a significantly different set of the 25 gems, based on the requirements of new gems that the gem authors released since the last time you ran \fBbundle update \-\-all\fR\.
+.
.SH "UPDATING A LIST OF GEMS"
Sometimes, you want to update a single gem in the Gemfile(5), and leave the rest of the gems that you specified locked to the versions in the \fBGemfile\.lock\fR\.
+.
.P
For instance, in the scenario above, imagine that \fBnokogiri\fR releases version \fB1\.4\.4\fR, and you want to update it \fIwithout\fR updating Rails and all of its dependencies\. To do this, run \fBbundle update nokogiri\fR\.
+.
.P
Bundler will update \fBnokogiri\fR and any of its dependencies, but leave alone Rails and its dependencies\.
+.
.SH "OVERLAPPING DEPENDENCIES"
Sometimes, multiple gems declared in your Gemfile(5) are satisfied by the same second\-level dependency\. For instance, consider the case of \fBthin\fR and \fBrack\-perftools\-profiler\fR\.
+.
.IP "" 4
+.
.nf
+
source "https://rubygems\.org"
gem "thin"
gem "rack\-perftools\-profiler"
+.
.fi
+.
.IP "" 0
+.
.P
The \fBthin\fR gem depends on \fBrack >= 1\.0\fR, while \fBrack\-perftools\-profiler\fR depends on \fBrack ~> 1\.0\fR\. If you run bundle install, you get:
+.
.IP "" 4
+.
.nf
+
Fetching source index for https://rubygems\.org/
Installing daemons (1\.1\.0)
Installing eventmachine (0\.12\.10) with native extensions
@@ -144,132 +196,199 @@ Installing rack (1\.2\.1)
Installing rack\-perftools_profiler (0\.0\.2)
Installing thin (1\.2\.7) with native extensions
Using bundler (1\.0\.0\.rc\.3)
+.
.fi
+.
.IP "" 0
+.
.P
-In this case, the two gems have their own set of dependencies, but they share \fBrack\fR in common\. If you run \fBbundle update thin\fR, bundler will update \fBdaemons\fR, \fBeventmachine\fR and \fBrack\fR, which are dependencies of \fBthin\fR, but not \fBopen4\fR or \fBperftools\.rb\fR, which are dependencies of \fBrack\-perftools_profiler\fR\. Note that \fBbundle update thin\fR will update \fBrack\fR even though it's \fIalso\fR a dependency of \fBrack\-perftools_profiler\fR\.
+In this case, the two gems have their own set of dependencies, but they share \fBrack\fR in common\. If you run \fBbundle update thin\fR, bundler will update \fBdaemons\fR, \fBeventmachine\fR and \fBrack\fR, which are dependencies of \fBthin\fR, but not \fBopen4\fR or \fBperftools\.rb\fR, which are dependencies of \fBrack\-perftools_profiler\fR\. Note that \fBbundle update thin\fR will update \fBrack\fR even though it\'s \fIalso\fR a dependency of \fBrack\-perftools_profiler\fR\.
+.
.P
In short, by default, when you update a gem using \fBbundle update\fR, bundler will update all dependencies of that gem, including those that are also dependencies of another gem\.
+.
.P
To prevent updating indirect dependencies, prior to version 1\.14 the only option was the \fBCONSERVATIVE UPDATING\fR behavior in bundle install(1) \fIbundle\-install\.1\.html\fR:
+.
.P
In this scenario, updating the \fBthin\fR version manually in the Gemfile(5), and then running bundle install(1) \fIbundle\-install\.1\.html\fR will only update \fBdaemons\fR and \fBeventmachine\fR, but not \fBrack\fR\. For more information, see the \fBCONSERVATIVE UPDATING\fR section of bundle install(1) \fIbundle\-install\.1\.html\fR\.
+.
.P
Starting with 1\.14, specifying the \fB\-\-conservative\fR option will also prevent indirect dependencies from being updated\.
+.
.SH "PATCH LEVEL OPTIONS"
Version 1\.14 introduced 4 patch\-level options that will influence how gem versions are resolved\. One of the following options can be used: \fB\-\-patch\fR, \fB\-\-minor\fR or \fB\-\-major\fR\. \fB\-\-strict\fR can be added to further influence resolution\.
+.
.TP
\fB\-\-patch\fR
Prefer updating only to next patch version\.
+.
.TP
\fB\-\-minor\fR
Prefer updating only to next minor version\.
+.
.TP
\fB\-\-major\fR
Prefer updating to next major version (default)\.
+.
.TP
\fB\-\-strict\fR
Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\.
+.
.P
-When Bundler is resolving what versions to use to satisfy declared requirements in the Gemfile or in parent gems, it looks up all available versions, filters out any versions that don't satisfy the requirement, and then, by default, sorts them from newest to oldest, considering them in that order\.
+When Bundler is resolving what versions to use to satisfy declared requirements in the Gemfile or in parent gems, it looks up all available versions, filters out any versions that don\'t satisfy the requirement, and then, by default, sorts them from newest to oldest, considering them in that order\.
+.
.P
Providing one of the patch level options (e\.g\. \fB\-\-patch\fR) changes the sort order of the satisfying versions, causing Bundler to consider the latest \fB\-\-patch\fR or \fB\-\-minor\fR version available before other versions\. Note that versions outside the stated patch level could still be resolved to if necessary to find a suitable dependency graph\.
+.
.P
-For example, if gem 'foo' is locked at 1\.0\.2, with no gem requirement defined in the Gemfile, and versions 1\.0\.3, 1\.0\.4, 1\.1\.0, 1\.1\.1, 2\.0\.0 all exist, the default order of preference by default (\fB\-\-major\fR) will be "2\.0\.0, 1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\.
+For example, if gem \'foo\' is locked at 1\.0\.2, with no gem requirement defined in the Gemfile, and versions 1\.0\.3, 1\.0\.4, 1\.1\.0, 1\.1\.1, 2\.0\.0 all exist, the default order of preference by default (\fB\-\-major\fR) will be "2\.0\.0, 1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\.
+.
.P
If the \fB\-\-patch\fR option is used, the order of preference will change to "1\.0\.4, 1\.0\.3, 1\.0\.2, 1\.1\.1, 1\.1\.0, 2\.0\.0"\.
+.
.P
If the \fB\-\-minor\fR option is used, the order of preference will change to "1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2, 2\.0\.0"\.
+.
.P
Combining the \fB\-\-strict\fR option with any of the patch level options will remove any versions beyond the scope of the patch level option, to ensure that no gem is updated that far\.
+.
.P
To continue the previous example, if both \fB\-\-patch\fR and \fB\-\-strict\fR options are used, the available versions for resolution would be "1\.0\.4, 1\.0\.3, 1\.0\.2"\. If \fB\-\-minor\fR and \fB\-\-strict\fR are used, it would be "1\.1\.1, 1\.1\.0, 1\.0\.4, 1\.0\.3, 1\.0\.2"\.
+.
.P
-Gem requirements as defined in the Gemfile will still be the first determining factor for what versions are available\. If the gem requirement for \fBfoo\fR in the Gemfile is '~> 1\.0', that will accomplish the same thing as providing the \fB\-\-minor\fR and \fB\-\-strict\fR options\.
+Gem requirements as defined in the Gemfile will still be the first determining factor for what versions are available\. If the gem requirement for \fBfoo\fR in the Gemfile is \'~> 1\.0\', that will accomplish the same thing as providing the \fB\-\-minor\fR and \fB\-\-strict\fR options\.
+.
.SH "PATCH LEVEL EXAMPLES"
Given the following gem specifications:
+.
.IP "" 4
+.
.nf
+
foo 1\.4\.3, requires: ~> bar 2\.0
foo 1\.4\.4, requires: ~> bar 2\.0
foo 1\.4\.5, requires: ~> bar 2\.1
foo 1\.5\.0, requires: ~> bar 2\.1
foo 1\.5\.1, requires: ~> bar 3\.0
bar with versions 2\.0\.3, 2\.0\.4, 2\.1\.0, 2\.1\.1, 3\.0\.0
+.
.fi
+.
.IP "" 0
+.
.P
Gemfile:
+.
.IP "" 4
+.
.nf
-gem 'foo'
+
+gem \'foo\'
+.
.fi
+.
.IP "" 0
+.
.P
Gemfile\.lock:
+.
.IP "" 4
+.
.nf
+
foo (1\.4\.3)
bar (~> 2\.0)
bar (2\.0\.3)
+.
.fi
+.
.IP "" 0
+.
.P
Cases:
+.
.IP "" 4
+.
.nf
+
# Command Line Result
\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
-1 bundle update \-\-patch 'foo 1\.4\.5', 'bar 2\.1\.1'
-2 bundle update \-\-patch foo 'foo 1\.4\.5', 'bar 2\.1\.1'
-3 bundle update \-\-minor 'foo 1\.5\.1', 'bar 3\.0\.0'
-4 bundle update \-\-minor \-\-strict 'foo 1\.5\.0', 'bar 2\.1\.1'
-5 bundle update \-\-patch \-\-strict 'foo 1\.4\.4', 'bar 2\.0\.4'
+1 bundle update \-\-patch \'foo 1\.4\.5\', \'bar 2\.1\.1\'
+2 bundle update \-\-patch foo \'foo 1\.4\.5\', \'bar 2\.1\.1\'
+3 bundle update \-\-minor \'foo 1\.5\.1\', \'bar 3\.0\.0\'
+4 bundle update \-\-minor \-\-strict \'foo 1\.5\.0\', \'bar 2\.1\.1\'
+5 bundle update \-\-patch \-\-strict \'foo 1\.4\.4\', \'bar 2\.0\.4\'
+.
.fi
+.
.IP "" 0
+.
.P
In case 1, bar is upgraded to 2\.1\.1, a minor version increase, because the dependency from foo 1\.4\.5 required it\.
+.
.P
-In case 2, only foo is requested to be unlocked, but bar is also allowed to move because it's not a declared dependency in the Gemfile\.
+In case 2, only foo is requested to be unlocked, but bar is also allowed to move because it\'s not a declared dependency in the Gemfile\.
+.
.P
In case 3, bar goes up a whole major release, because a minor increase is preferred now for foo, and when it goes to 1\.5\.1, it requires 3\.0\.0 of bar\.
+.
.P
-In case 4, foo is preferred up to a minor version, but 1\.5\.1 won't work because the \-\-strict flag removes bar 3\.0\.0 from consideration since it's a major increment\.
+In case 4, foo is preferred up to a minor version, but 1\.5\.1 won\'t work because the \-\-strict flag removes bar 3\.0\.0 from consideration since it\'s a major increment\.
+.
.P
In case 5, both foo and bar have any minor or major increments removed from consideration because of the \-\-strict flag, so the most they can move is up to 1\.4\.4 and 2\.0\.4\.
+.
.SH "RECOMMENDED WORKFLOW"
In general, when working with an application managed with bundler, you should use the following workflow:
+.
.IP "\(bu" 4
After you create your Gemfile(5) for the first time, run
+.
.IP
$ bundle install
+.
.IP "\(bu" 4
Check the resulting \fBGemfile\.lock\fR into version control
+.
.IP
$ git add Gemfile\.lock
+.
.IP "\(bu" 4
When checking out this repository on another development machine, run
+.
.IP
$ bundle install
+.
.IP "\(bu" 4
When checking out this repository on a deployment machine, run
+.
.IP
$ bundle install \-\-deployment
+.
.IP "\(bu" 4
After changing the Gemfile(5) to reflect a new or update dependency, run
+.
.IP
$ bundle install
+.
.IP "\(bu" 4
Make sure to check the updated \fBGemfile\.lock\fR into version control
+.
.IP
$ git add Gemfile\.lock
+.
.IP "\(bu" 4
If bundle install(1) \fIbundle\-install\.1\.html\fR reports a conflict, manually update the specific gems that you changed in the Gemfile(5)
+.
.IP
$ bundle update rails thin
+.
.IP "\(bu" 4
If you want to update all the gems to the latest possible versions that still match the gems listed in the Gemfile(5), run
+.
.IP
$ bundle update \-\-all
+.
.IP "" 0
diff --git a/lib/bundler/man/bundle-version.1 b/lib/bundler/man/bundle-version.1
index a29858181a..5e3ed44600 100644
--- a/lib/bundler/man/bundle-version.1
+++ b/lib/bundler/man/bundle-version.1
@@ -1,22 +1,35 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-VERSION" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-VERSION" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-version\fR \- Prints Bundler version information
+.
.SH "SYNOPSIS"
\fBbundle version\fR
+.
.SH "DESCRIPTION"
Prints Bundler version information\.
+.
.SH "OPTIONS"
No options\.
+.
.SH "EXAMPLE"
Print the version of Bundler with build date and commit hash of the in the Git source\.
+.
.IP "" 4
+.
.nf
+
bundle version
+.
.fi
+.
.IP "" 0
+.
.P
shows \fBBundler version 2\.3\.21 (2022\-08\-24 commit d54be5fdd8)\fR for example\.
+.
.P
cf\. \fBbundle \-\-version\fR shows \fBBundler version 2\.3\.21\fR\.
diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1
index 9609e098dd..d5330ec754 100644
--- a/lib/bundler/man/bundle-viz.1
+++ b/lib/bundler/man/bundle-viz.1
@@ -1,29 +1,41 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE\-VIZ" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE\-VIZ" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile
+.
.SH "SYNOPSIS"
\fBbundle viz\fR [\-\-file=FILE] [\-\-format=FORMAT] [\-\-requirements] [\-\-version] [\-\-without=GROUP GROUP]
+.
.SH "DESCRIPTION"
\fBviz\fR generates a PNG file of the current \fBGemfile(5)\fR as a dependency graph\. \fBviz\fR requires the ruby\-graphviz gem (and its dependencies)\.
+.
.P
The associated gems must also be installed via \fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR\.
+.
.P
\fBviz\fR command was deprecated in Bundler 2\.2\. Use bundler\-graph plugin \fIhttps://github\.com/rubygems/bundler\-graph\fR instead\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-file\fR, \fB\-f\fR
The name to use for the generated file\. See \fB\-\-format\fR option
+.
.TP
\fB\-\-format\fR, \fB\-F\fR
-This is output format option\. Supported format is png, jpg, svg, dot \|\.\|\.\|\.
+This is output format option\. Supported format is png, jpg, svg, dot \.\.\.
+.
.TP
\fB\-\-requirements\fR, \fB\-R\fR
Set to show the version of each required dependency\.
+.
.TP
\fB\-\-version\fR, \fB\-v\fR
Set to show each gem version\.
+.
.TP
\fB\-\-without\fR, \fB\-W\fR
Exclude gems that are part of the specified named group\.
diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1
index d84d788748..99c65a72b5 100644
--- a/lib/bundler/man/bundle.1
+++ b/lib/bundler/man/bundle.1
@@ -1,102 +1,141 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "BUNDLE" "1" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "BUNDLE" "1" "August 2023" "" ""
+.
.SH "NAME"
\fBbundle\fR \- Ruby Dependency Management
+.
.SH "SYNOPSIS"
\fBbundle\fR COMMAND [\-\-no\-color] [\-\-verbose] [ARGS]
+.
.SH "DESCRIPTION"
-Bundler manages an \fBapplication's dependencies\fR through its entire life across many machines systematically and repeatably\.
+Bundler manages an \fBapplication\'s dependencies\fR through its entire life across many machines systematically and repeatably\.
+.
.P
See the bundler website \fIhttps://bundler\.io\fR for information on getting started, and Gemfile(5) for more information on the \fBGemfile\fR format\.
+.
.SH "OPTIONS"
+.
.TP
\fB\-\-no\-color\fR
Print all output without color
+.
.TP
\fB\-\-retry\fR, \fB\-r\fR
Specify the number of times you wish to attempt network commands
+.
.TP
\fB\-\-verbose\fR, \fB\-V\fR
Print out additional logging information
+.
.SH "BUNDLE COMMANDS"
We divide \fBbundle\fR subcommands into primary commands and utilities:
+.
.SH "PRIMARY COMMANDS"
+.
.TP
\fBbundle install(1)\fR \fIbundle\-install\.1\.html\fR
Install the gems specified by the \fBGemfile\fR or \fBGemfile\.lock\fR
+.
.TP
\fBbundle update(1)\fR \fIbundle\-update\.1\.html\fR
Update dependencies to their latest versions
+.
.TP
\fBbundle cache(1)\fR \fIbundle\-cache\.1\.html\fR
Package the \.gem files required by your application into the \fBvendor/cache\fR directory (aliases: \fBbundle package\fR, \fBbundle pack\fR)
+.
.TP
\fBbundle exec(1)\fR \fIbundle\-exec\.1\.html\fR
Execute a script in the current bundle
+.
.TP
\fBbundle config(1)\fR \fIbundle\-config\.1\.html\fR
Specify and read configuration options for Bundler
+.
.TP
\fBbundle help(1)\fR \fIbundle\-help\.1\.html\fR
Display detailed help for each subcommand
+.
.SH "UTILITIES"
+.
.TP
\fBbundle add(1)\fR \fIbundle\-add\.1\.html\fR
Add the named gem to the Gemfile and run \fBbundle install\fR
+.
.TP
\fBbundle binstubs(1)\fR \fIbundle\-binstubs\.1\.html\fR
Generate binstubs for executables in a gem
+.
.TP
\fBbundle check(1)\fR \fIbundle\-check\.1\.html\fR
Determine whether the requirements for your application are installed and available to Bundler
+.
.TP
\fBbundle show(1)\fR \fIbundle\-show\.1\.html\fR
Show the source location of a particular gem in the bundle
+.
.TP
\fBbundle outdated(1)\fR \fIbundle\-outdated\.1\.html\fR
Show all of the outdated gems in the current bundle
+.
.TP
\fBbundle console(1)\fR (deprecated)
Start an IRB session in the current bundle
+.
.TP
\fBbundle open(1)\fR \fIbundle\-open\.1\.html\fR
Open an installed gem in the editor
+.
.TP
\fBbundle lock(1)\fR \fIbundle\-lock\.1\.html\fR
Generate a lockfile for your dependencies
+.
.TP
\fBbundle viz(1)\fR \fIbundle\-viz\.1\.html\fR (deprecated)
Generate a visual representation of your dependencies
+.
.TP
\fBbundle init(1)\fR \fIbundle\-init\.1\.html\fR
Generate a simple \fBGemfile\fR, placed in the current directory
+.
.TP
\fBbundle gem(1)\fR \fIbundle\-gem\.1\.html\fR
Create a simple gem, suitable for development with Bundler
+.
.TP
\fBbundle platform(1)\fR \fIbundle\-platform\.1\.html\fR
Display platform compatibility information
+.
.TP
\fBbundle clean(1)\fR \fIbundle\-clean\.1\.html\fR
Clean up unused gems in your Bundler directory
+.
.TP
\fBbundle doctor(1)\fR \fIbundle\-doctor\.1\.html\fR
Display warnings about common problems
+.
.TP
\fBbundle remove(1)\fR \fIbundle\-remove\.1\.html\fR
Removes gems from the Gemfile
+.
.TP
\fBbundle plugin(1)\fR \fIbundle\-plugin\.1\.html\fR
Manage Bundler plugins
+.
.TP
\fBbundle version(1)\fR \fIbundle\-version\.1\.html\fR
Prints Bundler version information
+.
.SH "PLUGINS"
-When running a command that isn't listed in PRIMARY COMMANDS or UTILITIES, Bundler will try to find an executable on your path named \fBbundler\-<command>\fR and execute it, passing down any extra arguments to it\.
+When running a command that isn\'t listed in PRIMARY COMMANDS or UTILITIES, Bundler will try to find an executable on your path named \fBbundler\-<command>\fR and execute it, passing down any extra arguments to it\.
+.
.SH "OBSOLETE"
These commands are obsolete and should no longer be used:
+.
.IP "\(bu" 4
\fBbundle inject(1)\fR
+.
.IP "" 0
diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5
index f24a1c540d..352fa0f545 100644
--- a/lib/bundler/man/gemfile.5
+++ b/lib/bundler/man/gemfile.5
@@ -1,143 +1,228 @@
-.\" generated with nRonn/v0.11.1
-.\" https://github.com/n-ronn/nronn/tree/0.11.1
-.TH "GEMFILE" "5" "September 2024" ""
+.\" generated with Ronn/v0.7.3
+.\" http://github.com/rtomayko/ronn/tree/0.7.3
+.
+.TH "GEMFILE" "5" "August 2023" "" ""
+.
.SH "NAME"
\fBGemfile\fR \- A format for describing gem dependencies for Ruby programs
+.
.SH "SYNOPSIS"
A \fBGemfile\fR describes the gem dependencies required to execute associated Ruby code\.
+.
.P
Place the \fBGemfile\fR in the root of the directory containing the associated code\. For instance, in a Rails application, place the \fBGemfile\fR in the same directory as the \fBRakefile\fR\.
+.
.SH "SYNTAX"
A \fBGemfile\fR is evaluated as Ruby code, in a context which makes available a number of methods used to describe the gem requirements\.
+.
.SH "GLOBAL SOURCE"
At the top of the \fBGemfile\fR, add a single line for the \fBRubyGems\fR source that contains the gems listed in the \fBGemfile\fR\.
+.
.IP "" 4
+.
.nf
+
source "https://rubygems\.org"
+.
.fi
+.
.IP "" 0
+.
.P
You can add only one global source\. In Bundler 1\.13, adding multiple global sources was deprecated\. The \fBsource\fR \fBMUST\fR be a valid RubyGems repository\.
+.
.P
To use more than one source of RubyGems, you should use \fI\fBsource\fR block\fR\.
+.
.P
A source is checked for gems following the heuristics described in \fISOURCE PRIORITY\fR\.
+.
.P
\fBNote about a behavior of the feature deprecated in Bundler 1\.13\fR: If a gem is found in more than one global source, Bundler will print a warning after installing the gem indicating which source was used, and listing the other sources where the gem is available\. A specific source can be selected for gems that need to use a non\-standard repository, suppressing this warning, by using the \fI\fB:source\fR option\fR or \fBsource\fR block\.
+.
.SS "CREDENTIALS"
Some gem sources require a username and password\. Use bundle config(1) \fIbundle\-config\.1\.html\fR to set the username and password for any of the sources that need it\. The command must be run once on each computer that will install the Gemfile, but this keeps the credentials from being stored in plain text in version control\.
+.
.IP "" 4
+.
.nf
+
bundle config gems\.example\.com user:password
+.
.fi
+.
.IP "" 0
+.
.P
For some sources, like a company Gemfury account, it may be easier to include the credentials in the Gemfile as part of the source URL\.
+.
.IP "" 4
+.
.nf
+
source "https://user:password@gems\.example\.com"
+.
.fi
+.
.IP "" 0
+.
.P
Credentials in the source URL will take precedence over credentials set using \fBconfig\fR\.
+.
.SH "RUBY"
If your application requires a specific Ruby version or engine, specify your requirements using the \fBruby\fR method, with the following arguments\. All parameters are \fBOPTIONAL\fR unless otherwise specified\.
+.
.SS "VERSION (required)"
The version of Ruby that your application requires\. If your application requires an alternate Ruby engine, such as JRuby, TruffleRuby, etc\., this should be the Ruby version that the engine is compatible with\.
+.
.IP "" 4
+.
.nf
+
ruby "3\.1\.2"
+.
.fi
+.
.IP "" 0
+.
.P
If you wish to derive your Ruby version from a version file (ie \.ruby\-version), you can use the \fBfile\fR option instead\.
+.
.IP "" 4
+.
.nf
+
ruby file: "\.ruby\-version"
+.
.fi
+.
.IP "" 0
-.P
-The version file should conform to any of the following formats:
-.IP "\(bu" 4
-\fB3\.1\.2\fR (\.ruby\-version)
-.IP "\(bu" 4
-\fBruby 3\.1\.2\fR (\.tool\-versions, read: https://asdf\-vm\.com/manage/configuration\.html#tool\-versions)
-.IP "" 0
+.
.SS "ENGINE"
Each application \fImay\fR specify a Ruby engine\. If an engine is specified, an engine version \fImust\fR also be specified\.
+.
.P
-What exactly is an Engine?
+What exactly is an Engine? \- A Ruby engine is an implementation of the Ruby language\.
+.
.IP "\(bu" 4
-A Ruby engine is an implementation of the Ruby language\.
+For background: the reference or original implementation of the Ruby programming language is called Matz\'s Ruby Interpreter \fIhttps://en\.wikipedia\.org/wiki/Ruby_MRI\fR, or MRI for short\. This is named after Ruby creator Yukihiro Matsumoto, also known as Matz\. MRI is also known as CRuby, because it is written in C\. MRI is the most widely used Ruby engine\.
+.
.IP "\(bu" 4
-For background: the reference or original implementation of the Ruby programming language is called Matz's Ruby Interpreter \fIhttps://en\.wikipedia\.org/wiki/Ruby_MRI\fR, or MRI for short\. This is named after Ruby creator Yukihiro Matsumoto, also known as Matz\. MRI is also known as CRuby, because it is written in C\. MRI is the most widely used Ruby engine\.
-.IP "\(bu" 4
-Other implementations \fIhttps://www\.ruby\-lang\.org/en/about/\fR of Ruby exist\. Some of the more well\-known implementations include JRuby \fIhttps://www\.jruby\.org/\fR and TruffleRuby \fIhttps://www\.graalvm\.org/ruby/\fR\. Rubinius is an alternative implementation of Ruby written in Ruby\. JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine\. TruffleRuby is a Ruby implementation on the GraalVM, a language toolkit built on the JVM\.
+Other implementations \fIhttps://www\.ruby\-lang\.org/en/about/\fR of Ruby exist\. Some of the more well\-known implementations include JRuby \fIhttp://jruby\.org/\fR and TruffleRuby \fIhttps://www\.graalvm\.org/ruby/\fR\. Rubinius is an alternative implementation of Ruby written in Ruby\. JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine\. TruffleRuby is a Ruby implementation on the GraalVM, a language toolkit built on the JVM\.
+.
.IP "" 0
+.
.SS "ENGINE VERSION"
Each application \fImay\fR specify a Ruby engine version\. If an engine version is specified, an engine \fImust\fR also be specified\. If the engine is "ruby" the engine version specified \fImust\fR match the Ruby version\.
+.
.IP "" 4
+.
.nf
+
ruby "2\.6\.8", engine: "jruby", engine_version: "9\.3\.8\.0"
+.
.fi
+.
.IP "" 0
+.
.SS "PATCHLEVEL"
Each application \fImay\fR specify a Ruby patchlevel\. Specifying the patchlevel has been meaningless since Ruby 2\.1\.0 was released as the patchlevel is now uniquely determined by a combination of major, minor, and teeny version numbers\.
+.
.P
This option was implemented in Bundler 1\.4\.0 for Ruby 2\.0 or earlier\.
+.
.IP "" 4
+.
.nf
+
ruby "3\.1\.2", patchlevel: "20"
+.
.fi
+.
.IP "" 0
+.
.SH "GEMS"
Specify gem requirements using the \fBgem\fR method, with the following arguments\. All parameters are \fBOPTIONAL\fR unless otherwise specified\.
+.
.SS "NAME (required)"
For each gem requirement, list a single \fIgem\fR line\.
+.
.IP "" 4
+.
.nf
+
gem "nokogiri"
+.
.fi
+.
.IP "" 0
+.
.SS "VERSION"
Each \fIgem\fR \fBMAY\fR have one or more version specifiers\.
+.
.IP "" 4
+.
.nf
+
gem "nokogiri", ">= 1\.4\.2"
gem "RedCloth", ">= 4\.1\.0", "< 4\.2\.0"
+.
.fi
+.
.IP "" 0
+.
.SS "REQUIRE AS"
Each \fIgem\fR \fBMAY\fR specify files that should be used when autorequiring via \fBBundler\.require\fR\. You may pass an array with multiple files or \fBtrue\fR if the file you want \fBrequired\fR has the same name as \fIgem\fR or \fBfalse\fR to prevent any file from being autorequired\.
+.
.IP "" 4
+.
.nf
+
gem "redis", require: ["redis/connection/hiredis", "redis"]
gem "webmock", require: false
gem "byebug", require: true
+.
.fi
+.
.IP "" 0
+.
.P
The argument defaults to the name of the gem\. For example, these are identical:
+.
.IP "" 4
+.
.nf
+
gem "nokogiri"
gem "nokogiri", require: "nokogiri"
gem "nokogiri", require: true
+.
.fi
+.
.IP "" 0
+.
.SS "GROUPS"
Each \fIgem\fR \fBMAY\fR specify membership in one or more groups\. Any \fIgem\fR that does not specify membership in any group is placed in the \fBdefault\fR group\.
+.
.IP "" 4
+.
.nf
+
gem "rspec", group: :test
gem "wirble", groups: [:development, :test]
+.
.fi
+.
.IP "" 0
+.
.P
The Bundler runtime allows its two main methods, \fBBundler\.setup\fR and \fBBundler\.require\fR, to limit their impact to particular groups\.
+.
.IP "" 4
+.
.nf
-# setup adds gems to Ruby's load path
+
+# setup adds gems to Ruby\'s load path
Bundler\.setup # defaults to all groups
require "bundler/setup" # same as Bundler\.setup
Bundler\.setup(:default) # only set up the _default_ group
@@ -149,271 +234,429 @@ Bundler\.require # defaults to the _default_ group
Bundler\.require(:default) # identical
Bundler\.require(:default, :test) # requires the _default_ and _test_ groups
Bundler\.require(:test) # requires the _test_ group
+.
.fi
+.
.IP "" 0
+.
.P
The Bundler CLI allows you to specify a list of groups whose gems \fBbundle install\fR should not install with the \fBwithout\fR configuration\.
+.
.P
To specify multiple groups to ignore, specify a list of groups separated by spaces\.
+.
.IP "" 4
+.
.nf
+
bundle config set \-\-local without test
bundle config set \-\-local without development test
+.
.fi
+.
.IP "" 0
+.
.P
Also, calling \fBBundler\.setup\fR with no parameters, or calling \fBrequire "bundler/setup"\fR will setup all groups except for the ones you excluded via \fB\-\-without\fR (since they are not available)\.
+.
.P
Note that on \fBbundle install\fR, bundler downloads and evaluates all gems, in order to create a single canonical list of all of the required gems and their dependencies\. This means that you cannot list different versions of the same gems in different groups\. For more details, see Understanding Bundler \fIhttps://bundler\.io/rationale\.html\fR\.
+.
.SS "PLATFORMS"
If a gem should only be used in a particular platform or set of platforms, you can specify them\. Platforms are essentially identical to groups, except that you do not need to use the \fB\-\-without\fR install\-time flag to exclude groups of gems for other platforms\.
+.
.P
There are a number of \fBGemfile\fR platforms:
+.
.TP
\fBruby\fR
C Ruby (MRI), Rubinius, or TruffleRuby, but not Windows
+.
.TP
\fBmri\fR
C Ruby (MRI) only, but not Windows
+.
.TP
\fBwindows\fR
Windows C Ruby (MRI), including RubyInstaller 32\-bit and 64\-bit versions
+.
.TP
\fBmswin\fR
Windows C Ruby (MRI), including RubyInstaller 32\-bit versions
+.
.TP
\fBmswin64\fR
Windows C Ruby (MRI), including RubyInstaller 64\-bit versions
+.
.TP
\fBrbx\fR
Rubinius
+.
.TP
\fBjruby\fR
JRuby
+.
.TP
\fBtruffleruby\fR
TruffleRuby
+.
.P
On platforms \fBruby\fR, \fBmri\fR, \fBmswin\fR, \fBmswin64\fR, and \fBwindows\fR, you may additionally specify a version by appending the major and minor version numbers without a delimiter\. For example, to specify that a gem should only be used on platform \fBruby\fR version 3\.1, use:
+.
.IP "" 4
+.
.nf
+
ruby_31
+.
.fi
+.
.IP "" 0
+.
.P
As with groups (above), you may specify one or more platforms:
+.
.IP "" 4
+.
.nf
+
gem "weakling", platforms: :jruby
gem "ruby\-debug", platforms: :mri_31
gem "nokogiri", platforms: [:windows_31, :jruby]
+.
.fi
+.
.IP "" 0
+.
.P
All operations involving groups (\fBbundle install\fR \fIbundle\-install\.1\.html\fR, \fBBundler\.setup\fR, \fBBundler\.require\fR) behave exactly the same as if any groups not matching the current platform were explicitly excluded\.
-.P
-The following platform values are deprecated and should be replaced with \fBwindows\fR:
-.IP "\(bu" 4
-\fBmswin\fR, \fBmswin64\fR, \fBmingw32\fR, \fBx64_mingw\fR
-.IP "" 0
-.P
-Note that, while unfortunately using the same terminology, the values of this option are different from the values that \fBbundle lock \-\-add\-platform\fR can take\. The values of this option are more closer to "Ruby Implementation" while the values that \fBbundle lock \-\-add\-platform\fR understands are more related to OS and architecture of the different systems where your lockfile will be used\.
+.
.SS "FORCE_RUBY_PLATFORM"
If you always want the pure ruby variant of a gem to be chosen over platform specific variants, you can use the \fBforce_ruby_platform\fR option:
+.
.IP "" 4
+.
.nf
+
gem "ffi", force_ruby_platform: true
+.
.fi
+.
.IP "" 0
+.
.P
This can be handy (assuming the pure ruby variant works fine) when:
+.
.IP "\(bu" 4
-You're having issues with the platform specific variant\.
+You\'re having issues with the platform specific variant\.
+.
.IP "\(bu" 4
The platform specific variant does not yet support a newer ruby (and thus has a \fBrequired_ruby_version\fR upper bound), but you still want your Gemfile{\.lock} files to resolve under that ruby\.
+.
.IP "" 0
+.
.SS "SOURCE"
-You can select an alternate RubyGems repository for a gem using the ':source' option\.
+You can select an alternate RubyGems repository for a gem using the \':source\' option\.
+.
.IP "" 4
+.
.nf
+
gem "some_internal_gem", source: "https://gems\.example\.com"
+.
.fi
+.
.IP "" 0
+.
.P
This forces the gem to be loaded from this source and ignores the global source declared at the top level of the file\. If the gem does not exist in this source, it will not be installed\.
+.
.P
Bundler will search for child dependencies of this gem by first looking in the source selected for the parent, but if they are not found there, it will fall back on the global source\.
+.
.P
\fBNote about a behavior of the feature deprecated in Bundler 1\.13\fR: Selecting a specific source repository this way also suppresses the ambiguous gem warning described above in \fIGLOBAL SOURCE\fR\.
+.
.P
Using the \fB:source\fR option for an individual gem will also make that source available as a possible global source for any other gems which do not specify explicit sources\. Thus, when adding gems with explicit sources, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources\.
+.
.SS "GIT"
If necessary, you can specify that a gem is located at a particular git repository using the \fB:git\fR parameter\. The repository can be accessed via several protocols:
+.
.TP
\fBHTTP(S)\fR
gem "rails", git: "https://github\.com/rails/rails\.git"
+.
.TP
\fBSSH\fR
gem "rails", git: "git@github\.com:rails/rails\.git"
+.
.TP
\fBgit\fR
gem "rails", git: "git://github\.com/rails/rails\.git"
+.
.P
If using SSH, the user that you use to run \fBbundle install\fR \fBMUST\fR have the appropriate keys available in their \fB$HOME/\.ssh\fR\.
+.
.P
\fBNOTE\fR: \fBhttp://\fR and \fBgit://\fR URLs should be avoided if at all possible\. These protocols are unauthenticated, so a man\-in\-the\-middle attacker can deliver malicious code and compromise your system\. HTTPS and SSH are strongly preferred\.
+.
.P
The \fBgroup\fR, \fBplatforms\fR, and \fBrequire\fR options are available and behave exactly the same as they would for a normal gem\.
+.
.P
A git repository \fBSHOULD\fR have at least one file, at the root of the directory containing the gem, with the extension \fB\.gemspec\fR\. This file \fBMUST\fR contain a valid gem specification, as expected by the \fBgem build\fR command\.
+.
.P
If a git repository does not have a \fB\.gemspec\fR, bundler will attempt to create one, but it will not contain any dependencies, executables, or C extension compilation instructions\. As a result, it may fail to properly integrate into your application\.
+.
.P
If a git repository does have a \fB\.gemspec\fR for the gem you attached it to, a version specifier, if provided, means that the git repository is only valid if the \fB\.gemspec\fR specifies a version matching the version specifier\. If not, bundler will print a warning\.
+.
.IP "" 4
+.
.nf
+
gem "rails", "2\.3\.8", git: "https://github\.com/rails/rails\.git"
# bundle install will fail, because the \.gemspec in the rails
-# repository's master branch specifies version 3\.0\.0
+# repository\'s master branch specifies version 3\.0\.0
+.
.fi
+.
.IP "" 0
+.
.P
If a git repository does \fBnot\fR have a \fB\.gemspec\fR for the gem you attached it to, a version specifier \fBMUST\fR be provided\. Bundler will use this version in the simple \fB\.gemspec\fR it creates\.
+.
.P
Git repositories support a number of additional options\.
+.
.TP
\fBbranch\fR, \fBtag\fR, and \fBref\fR
You \fBMUST\fR only specify at most one of these options\. The default is \fBbranch: "master"\fR\. For example:
+.
.IP
gem "rails", git: "https://github\.com/rails/rails\.git", branch: "5\-0\-stable"
+.
.IP
gem "rails", git: "https://github\.com/rails/rails\.git", tag: "v5\.0\.0"
+.
.IP
gem "rails", git: "https://github\.com/rails/rails\.git", ref: "4aded"
+.
.TP
\fBsubmodules\fR
For reference, a git submodule \fIhttps://git\-scm\.com/book/en/v2/Git\-Tools\-Submodules\fR lets you have another git repository within a subfolder of your repository\. Specify \fBsubmodules: true\fR to cause bundler to expand any submodules included in the git repository
+.
.P
If a git repository contains multiple \fB\.gemspecs\fR, each \fB\.gemspec\fR represents a gem located at the same place in the file system as the \fB\.gemspec\fR\.
+.
.IP "" 4
+.
.nf
+
|~rails [git root]
| |\-rails\.gemspec [rails gem located here]
|~actionpack
| |\-actionpack\.gemspec [actionpack gem located here]
|~activesupport
| |\-activesupport\.gemspec [activesupport gem located here]
-|\|\.\|\.\|\.
+|\.\.\.
+.
.fi
+.
.IP "" 0
+.
.P
To install a gem located in a git repository, bundler changes to the directory containing the gemspec, runs \fBgem build name\.gemspec\fR and then installs the resulting gem\. The \fBgem build\fR command, which comes standard with Rubygems, evaluates the \fB\.gemspec\fR in the context of the directory in which it is located\.
+.
.SS "GIT SOURCE"
-A custom git source can be defined via the \fBgit_source\fR method\. Provide the source's name as an argument, and a block which receives a single argument and interpolates it into a string to return the full repo address:
+A custom git source can be defined via the \fBgit_source\fR method\. Provide the source\'s name as an argument, and a block which receives a single argument and interpolates it into a string to return the full repo address:
+.
.IP "" 4
+.
.nf
+
git_source(:stash){ |repo_name| "https://stash\.corp\.acme\.pl/#{repo_name}\.git" }
-gem 'rails', stash: 'forks/rails'
+gem \'rails\', stash: \'forks/rails\'
+.
.fi
+.
.IP "" 0
+.
.P
In addition, if you wish to choose a specific branch:
+.
.IP "" 4
+.
.nf
+
gem "rails", stash: "forks/rails", branch: "branch_name"
+.
.fi
+.
.IP "" 0
+.
.SS "GITHUB"
\fBNOTE\fR: This shorthand should be avoided until Bundler 2\.0, since it currently expands to an insecure \fBgit://\fR URL\. This allows a man\-in\-the\-middle attacker to compromise your system\.
+.
.P
If the git repository you want to use is hosted on GitHub and is public, you can use the :github shorthand to specify the github username and repository name (without the trailing "\.git"), separated by a slash\. If both the username and repository name are the same, you can omit one\.
+.
.IP "" 4
+.
.nf
+
gem "rails", github: "rails/rails"
gem "rails", github: "rails"
+.
.fi
+.
.IP "" 0
+.
.P
Are both equivalent to
+.
.IP "" 4
+.
.nf
+
gem "rails", git: "https://github\.com/rails/rails\.git"
+.
.fi
+.
.IP "" 0
+.
.P
Since the \fBgithub\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\.
+.
.P
You can also directly pass a pull request URL:
+.
.IP "" 4
+.
.nf
+
gem "rails", github: "https://github\.com/rails/rails/pull/43753"
+.
.fi
+.
.IP "" 0
+.
.P
Which is equivalent to:
+.
.IP "" 4
+.
.nf
+
gem "rails", github: "rails/rails", branch: "refs/pull/43753/head"
+.
.fi
+.
.IP "" 0
+.
.SS "GIST"
If the git repository you want to use is hosted as a GitHub Gist and is public, you can use the :gist shorthand to specify the gist identifier (without the trailing "\.git")\.
+.
.IP "" 4
+.
.nf
+
gem "the_hatch", gist: "4815162342"
+.
.fi
+.
.IP "" 0
+.
.P
Is equivalent to:
+.
.IP "" 4
+.
.nf
+
gem "the_hatch", git: "https://gist\.github\.com/4815162342\.git"
+.
.fi
+.
.IP "" 0
+.
.P
Since the \fBgist\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\.
+.
.SS "BITBUCKET"
If the git repository you want to use is hosted on Bitbucket and is public, you can use the :bitbucket shorthand to specify the bitbucket username and repository name (without the trailing "\.git"), separated by a slash\. If both the username and repository name are the same, you can omit one\.
+.
.IP "" 4
+.
.nf
+
gem "rails", bitbucket: "rails/rails"
gem "rails", bitbucket: "rails"
+.
.fi
+.
.IP "" 0
+.
.P
Are both equivalent to
+.
.IP "" 4
+.
.nf
+
gem "rails", git: "https://rails@bitbucket\.org/rails/rails\.git"
+.
.fi
+.
.IP "" 0
+.
.P
Since the \fBbitbucket\fR method is a specialization of \fBgit_source\fR, it accepts a \fB:branch\fR named argument\.
+.
.SS "PATH"
You can specify that a gem is located in a particular location on the file system\. Relative paths are resolved relative to the directory containing the \fBGemfile\fR\.
+.
.P
Similar to the semantics of the \fB:git\fR option, the \fB:path\fR option requires that the directory in question either contains a \fB\.gemspec\fR for the gem, or that you specify an explicit version that bundler should use\.
+.
.P
Unlike \fB:git\fR, bundler does not compile C extensions for gems specified as paths\.
+.
.IP "" 4
+.
.nf
+
gem "rails", path: "vendor/rails"
+.
.fi
+.
.IP "" 0
+.
.P
-If you would like to use multiple local gems directly from the filesystem, you can set a global \fBpath\fR option to the path containing the gem's files\. This will automatically load gemspec files from subdirectories\.
+If you would like to use multiple local gems directly from the filesystem, you can set a global \fBpath\fR option to the path containing the gem\'s files\. This will automatically load gemspec files from subdirectories\.
+.
.IP "" 4
+.
.nf
-path 'components' do
- gem 'admin_ui'
- gem 'public_ui'
+
+path \'components\' do
+ gem \'admin_ui\'
+ gem \'public_ui\'
end
+.
.fi
+.
.IP "" 0
+.
.SH "BLOCK FORM OF SOURCE, GIT, PATH, GROUP and PLATFORMS"
The \fB:source\fR, \fB:git\fR, \fB:path\fR, \fB:group\fR, and \fB:platforms\fR options may be applied to a group of gems by using block form\.
+.
.IP "" 4
+.
.nf
+
source "https://gems\.example\.com" do
gem "some_internal_gem"
gem "another_internal_gem"
@@ -433,40 +676,61 @@ group :development, optional: true do
gem "wirble"
gem "faker"
end
+.
.fi
+.
.IP "" 0
+.
.P
In the case of the group block form the :optional option can be given to prevent a group from being installed unless listed in the \fB\-\-with\fR option given to the \fBbundle install\fR command\.
+.
.P
In the case of the \fBgit\fR block form, the \fB:ref\fR, \fB:branch\fR, \fB:tag\fR, and \fB:submodules\fR options may be passed to the \fBgit\fR method, and all gems in the block will inherit those options\.
+.
.P
The presence of a \fBsource\fR block in a Gemfile also makes that source available as a possible global source for any other gems which do not specify explicit sources\. Thus, when defining source blocks, it is recommended that you also ensure all other gems in the Gemfile are using explicit sources, either via source blocks or \fB:source\fR directives on individual gems\.
+.
.SH "INSTALL_IF"
The \fBinstall_if\fR method allows gems to be installed based on a proc or lambda\. This is especially useful for optional gems that can only be used if certain software is installed or some other conditions are met\.
+.
.IP "" 4
+.
.nf
+
install_if \-> { RUBY_PLATFORM =~ /darwin/ } do
gem "pasteboard"
end
+.
.fi
+.
.IP "" 0
+.
.SH "GEMSPEC"
-The \fB\.gemspec\fR \fIhttps://guides\.rubygems\.org/specification\-reference/\fR file is where you provide metadata about your gem to Rubygems\. Some required Gemspec attributes include the name, description, and homepage of your gem\. This is also where you specify the dependencies your gem needs to run\.
+The \fB\.gemspec\fR \fIhttp://guides\.rubygems\.org/specification\-reference/\fR file is where you provide metadata about your gem to Rubygems\. Some required Gemspec attributes include the name, description, and homepage of your gem\. This is also where you specify the dependencies your gem needs to run\.
+.
.P
If you wish to use Bundler to help install dependencies for a gem while it is being developed, use the \fBgemspec\fR method to pull in the dependencies listed in the \fB\.gemspec\fR file\.
+.
.P
-The \fBgemspec\fR method adds any runtime dependencies as gem requirements in the default group\. It also adds development dependencies as gem requirements in the \fBdevelopment\fR group\. Finally, it adds a gem requirement on your project (\fBpath: '\.'\fR)\. In conjunction with \fBBundler\.setup\fR, this allows you to require project files in your test code as you would if the project were installed as a gem; you need not manipulate the load path manually or require project files via relative paths\.
+The \fBgemspec\fR method adds any runtime dependencies as gem requirements in the default group\. It also adds development dependencies as gem requirements in the \fBdevelopment\fR group\. Finally, it adds a gem requirement on your project (\fBpath: \'\.\'\fR)\. In conjunction with \fBBundler\.setup\fR, this allows you to require project files in your test code as you would if the project were installed as a gem; you need not manipulate the load path manually or require project files via relative paths\.
+.
.P
The \fBgemspec\fR method supports optional \fB:path\fR, \fB:glob\fR, \fB:name\fR, and \fB:development_group\fR options, which control where bundler looks for the \fB\.gemspec\fR, the glob it uses to look for the gemspec (defaults to: \fB{,*,*/*}\.gemspec\fR), what named \fB\.gemspec\fR it uses (if more than one is present), and which group development dependencies are included in\.
+.
.P
When a \fBgemspec\fR dependency encounters version conflicts during resolution, the local version under development will always be selected \-\- even if there are remote versions that better match other requirements for the \fBgemspec\fR gem\.
+.
.SH "SOURCE PRIORITY"
When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order:
+.
.IP "1." 4
The source explicitly attached to the gem (using \fB:source\fR, \fB:path\fR, or \fB:git\fR)
+.
.IP "2." 4
For implicit gems (dependencies of explicit gems), any source, git, or path repository declared on the parent\. This results in bundler prioritizing the ActiveSupport gem from the Rails git repository over ones from \fBrubygems\.org\fR
+.
.IP "3." 4
If neither of the above conditions are met, the global source will be used\. If multiple global sources are specified, they will be prioritized from last to first, but this is deprecated since Bundler 1\.13, so Bundler prints a warning and will abort with an error in the future\.
+.
.IP "" 0
diff --git a/lib/bundler/man/gemfile.5.ronn b/lib/bundler/man/gemfile.5.ronn
index 802549737e..6749c33f59 100644
--- a/lib/bundler/man/gemfile.5.ronn
+++ b/lib/bundler/man/gemfile.5.ronn
@@ -74,11 +74,6 @@ you can use the `file` option instead.
ruby file: ".ruby-version"
-The version file should conform to any of the following formats:
-
- - `3.1.2` (.ruby-version)
- - `ruby 3.1.2` (.tool-versions, read: https://asdf-vm.com/manage/configuration.html#tool-versions)
-
### ENGINE
Each application _may_ specify a Ruby engine. If an engine is specified, an
@@ -96,7 +91,7 @@ What exactly is an Engine?
- [Other implementations](https://www.ruby-lang.org/en/about/) of Ruby exist.
Some of the more well-known implementations include
- [JRuby](https://www.jruby.org/) and [TruffleRuby](https://www.graalvm.org/ruby/).
+ [JRuby](http://jruby.org/) and [TruffleRuby](https://www.graalvm.org/ruby/).
Rubinius is an alternative implementation of Ruby written in Ruby.
JRuby is an implementation of Ruby on the JVM, short for Java Virtual Machine.
TruffleRuby is a Ruby implementation on the GraalVM, a language toolkit built on the JVM.
@@ -238,16 +233,6 @@ All operations involving groups ([`bundle install`](bundle-install.1.html), `Bun
`Bundler.require`) behave exactly the same as if any groups not
matching the current platform were explicitly excluded.
-The following platform values are deprecated and should be replaced with `windows`:
-
- * `mswin`, `mswin64`, `mingw32`, `x64_mingw`
-
-Note that, while unfortunately using the same terminology, the values of this
-option are different from the values that `bundle lock --add-platform` can take.
-The values of this option are more closer to "Ruby Implementation" while the
-values that `bundle lock --add-platform` understands are more related to OS and
-architecture of the different systems where your lockfile will be used.
-
### FORCE_RUBY_PLATFORM
If you always want the pure ruby variant of a gem to be chosen over platform
@@ -515,7 +500,7 @@ software is installed or some other conditions are met.
## GEMSPEC
-The [`.gemspec`](https://guides.rubygems.org/specification-reference/) file is where
+The [`.gemspec`](http://guides.rubygems.org/specification-reference/) file is where
you provide metadata about your gem to Rubygems. Some required Gemspec
attributes include the name, description, and homepage of your gem. This is
also where you specify the dependencies your gem needs to run.
diff --git a/lib/bundler/match_metadata.rb b/lib/bundler/match_metadata.rb
index f6cc27df32..499036ca93 100644
--- a/lib/bundler/match_metadata.rb
+++ b/lib/bundler/match_metadata.rb
@@ -2,10 +2,6 @@
module Bundler
module MatchMetadata
- def matches_current_metadata?
- matches_current_ruby? && matches_current_rubygems?
- end
-
def matches_current_ruby?
@required_ruby_version.satisfied_by?(Gem.ruby_version)
end
diff --git a/lib/bundler/match_platform.rb b/lib/bundler/match_platform.rb
index ece9fb8679..7f7e8227f9 100644
--- a/lib/bundler/match_platform.rb
+++ b/lib/bundler/match_platform.rb
@@ -12,7 +12,7 @@ module Bundler
def self.platforms_match?(gemspec_platform, local_platform)
return true if gemspec_platform.nil?
- return true if gemspec_platform == Gem::Platform::RUBY
+ return true if Gem::Platform::RUBY == gemspec_platform
return true if local_platform == gemspec_platform
gemspec_platform = Gem::Platform.new(gemspec_platform)
return true if gemspec_platform === local_platform
diff --git a/lib/bundler/mirror.rb b/lib/bundler/mirror.rb
index 494a6d6aef..9d437a0951 100644
--- a/lib/bundler/mirror.rb
+++ b/lib/bundler/mirror.rb
@@ -47,7 +47,7 @@ module Bundler
def fetch_valid_mirror_for(uri)
downcased = uri.to_s.downcase
- mirror = @mirrors[downcased] || @mirrors[Gem::URI(downcased).host] || Mirror.new(uri)
+ mirror = @mirrors[downcased] || @mirrors[Bundler::URI(downcased).host] || Mirror.new(uri)
mirror.validate!(@prober)
mirror = Mirror.new(uri) unless mirror.valid?
mirror
@@ -74,7 +74,7 @@ module Bundler
@uri = if uri.nil?
nil
else
- Gem::URI(uri.to_s)
+ Bundler::URI(uri.to_s)
end
@valid = nil
end
@@ -126,7 +126,7 @@ module Bundler
if uri == "all"
@all = true
else
- @uri = Gem::URI(uri).absolute? ? Settings.normalize_uri(uri) : uri
+ @uri = Bundler::URI(uri).absolute? ? Settings.normalize_uri(uri) : uri
end
@value = value
end
diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb
index 588fa79be8..f3caff8963 100644
--- a/lib/bundler/plugin.rb
+++ b/lib/bundler/plugin.rb
@@ -62,8 +62,7 @@ module Bundler
if names.any?
names.each do |name|
if index.installed?(name)
- path = index.plugin_path(name).to_s
- Bundler.rm_rf(path) if index.installed_in_plugin_root?(name)
+ Bundler.rm_rf(index.plugin_path(name))
index.unregister_plugin(name)
Bundler.ui.info "Uninstalled plugin #{name}"
else
@@ -101,7 +100,7 @@ module Bundler
# @param [Pathname] gemfile path
# @param [Proc] block that can be evaluated for (inline) Gemfile
def gemfile_install(gemfile = nil, &inline)
- Bundler.settings.temporary(frozen: false, deployment: false) do
+ Bundler.settings.temporary(:frozen => false, :deployment => false) do
builder = DSL.new
if block_given?
builder.instance_eval(&inline)
@@ -198,7 +197,7 @@ module Bundler
# @param [Hash] The options that are present in the lock file
# @return [API::Source] the instance of the class that handles the source
# type passed in locked_opts
- def from_lock(locked_opts)
+ def source_from_lock(locked_opts)
src = source(locked_opts["type"])
src.new(locked_opts.merge("uri" => locked_opts["remote"]))
@@ -228,7 +227,7 @@ module Bundler
plugins = index.hook_plugins(event)
return unless plugins.any?
- plugins.each {|name| load_plugin(name) }
+ (plugins - @loaded_plugin_names).each {|name| load_plugin(name) }
@hooks_by_event[event].each {|blk| blk.call(*args, &arg_blk) }
end
@@ -240,11 +239,6 @@ module Bundler
Index.new.installed?(plugin)
end
- # @return [true, false] whether the plugin is loaded
- def loaded?(plugin)
- @loaded_plugin_names.include?(plugin)
- end
-
# Post installation processing and registering with index
#
# @param [Array<String>] plugins list to be installed
@@ -307,7 +301,7 @@ module Bundler
@hooks_by_event = Hash.new {|h, k| h[k] = [] }
load_paths = spec.load_paths
- Gem.add_to_load_path(*load_paths)
+ Bundler.rubygems.add_to_load_path(load_paths)
path = Pathname.new spec.full_gem_path
begin
@@ -335,14 +329,13 @@ module Bundler
# @param [String] name of the plugin
def load_plugin(name)
return unless name && !name.empty?
- return if loaded?(name)
# Need to ensure before this that plugin root where the rest of gems
# are installed to be on load path to support plugin deps. Currently not
# done to avoid conflicts
path = index.plugin_path(name)
- Gem.add_to_load_path(*index.load_paths(name))
+ Bundler.rubygems.add_to_load_path(index.load_paths(name))
load path.join(PLUGIN_FILE_NAME)
diff --git a/lib/bundler/plugin/api/source.rb b/lib/bundler/plugin/api/source.rb
index 690f379389..67c45bd204 100644
--- a/lib/bundler/plugin/api/source.rb
+++ b/lib/bundler/plugin/api/source.rb
@@ -39,7 +39,7 @@ module Bundler
# is present to be compatible with `Definition` and is used by
# rubygems source.
module Source
- attr_reader :uri, :options, :name, :checksum_store
+ attr_reader :uri, :options, :name
attr_accessor :dependency_names
def initialize(opts)
@@ -48,7 +48,6 @@ module Bundler
@uri = opts["uri"]
@type = opts["type"]
@name = opts["name"] || "#{@type} at #{@uri}"
- @checksum_store = Checksum::Store.new
end
# This is used by the default `spec` method to constructs the
@@ -96,7 +95,7 @@ module Bundler
#
# Note: Do not override if you don't know what you are doing.
def post_install(spec, disable_exts = false)
- opts = { env_shebang: false, disable_extensions: disable_exts }
+ opts = { :env_shebang => false, :disable_extensions => disable_exts }
installer = Bundler::Source::Path::Installer.new(spec, opts)
installer.post_install
end
@@ -107,7 +106,7 @@ module Bundler
def install_path
@install_path ||=
begin
- base_name = File.basename(Gem::URI.parse(uri).normalize.path)
+ base_name = File.basename(Bundler::URI.parse(uri).normalize.path)
gem_install_dir.join("#{base_name}-#{uri_hash[0..11]}")
end
@@ -131,7 +130,7 @@ module Bundler
Bundler::Index.build do |index|
files.each do |file|
next unless spec = Bundler.load_gemspec(file)
- spec.installed_by_version = Gem::VERSION
+ Bundler.rubygems.set_installed_by_version(spec)
spec.source = self
Bundler.rubygems.validate(spec)
@@ -176,7 +175,7 @@ module Bundler
#
# This is used by `app_cache_path`
def app_cache_dirname
- base_name = File.basename(Gem::URI.parse(uri).normalize.path)
+ base_name = File.basename(Bundler::URI.parse(uri).normalize.path)
"#{base_name}-#{uri_hash}"
end
@@ -196,7 +195,6 @@ module Bundler
FileUtils.rm_rf(new_cache_path)
FileUtils.cp_r(install_path, new_cache_path)
- FileUtils.rm_rf(app_cache_path.join(".git"))
FileUtils.touch(app_cache_path.join(".bundlecache"))
end
diff --git a/lib/bundler/plugin/events.rb b/lib/bundler/plugin/events.rb
index 29c05098ae..bc037d1af5 100644
--- a/lib/bundler/plugin/events.rb
+++ b/lib/bundler/plugin/events.rb
@@ -56,30 +56,6 @@ module Bundler
# Includes an Array of Bundler::Dependency objects
# GEM_AFTER_INSTALL_ALL = "after-install-all"
define :GEM_AFTER_INSTALL_ALL, "after-install-all"
-
- # @!parse
- # A hook called before each individual gem is required
- # Includes a Bundler::Dependency.
- # GEM_BEFORE_REQUIRE = "before-require"
- define :GEM_BEFORE_REQUIRE, "before-require"
-
- # @!parse
- # A hook called after each individual gem is required
- # Includes a Bundler::Dependency.
- # GEM_AFTER_REQUIRE = "after-require"
- define :GEM_AFTER_REQUIRE, "after-require"
-
- # @!parse
- # A hook called before any gems require
- # Includes an Array of Bundler::Dependency objects.
- # GEM_BEFORE_REQUIRE_ALL = "before-require-all"
- define :GEM_BEFORE_REQUIRE_ALL, "before-require-all"
-
- # @!parse
- # A hook called after all gems required
- # Includes an Array of Bundler::Dependency objects.
- # GEM_AFTER_REQUIRE_ALL = "after-require-all"
- define :GEM_AFTER_REQUIRE_ALL, "after-require-all"
end
end
end
diff --git a/lib/bundler/plugin/index.rb b/lib/bundler/plugin/index.rb
index c2ab8f90da..a2d5eaa38a 100644
--- a/lib/bundler/plugin/index.rb
+++ b/lib/bundler/plugin/index.rb
@@ -136,14 +136,6 @@ module Bundler
@hooks[event] || []
end
- # This plugin is installed inside the .bundle/plugin directory,
- # and thus is managed solely by Bundler
- def installed_in_plugin_root?(name)
- return false unless (path = installed?(name))
-
- path.start_with?("#{Plugin.root}/")
- end
-
private
# Reads the index file from the directory and initializes the instance
diff --git a/lib/bundler/plugin/installer.rb b/lib/bundler/plugin/installer.rb
index 4f60862bb4..c9ff12ce4b 100644
--- a/lib/bundler/plugin/installer.rb
+++ b/lib/bundler/plugin/installer.rb
@@ -10,7 +10,6 @@ module Bundler
class Installer
autoload :Rubygems, File.expand_path("installer/rubygems", __dir__)
autoload :Git, File.expand_path("installer/git", __dir__)
- autoload :Path, File.expand_path("installer/path", __dir__)
def install(names, options)
check_sources_consistency!(options)
@@ -19,8 +18,8 @@ module Bundler
if options[:git]
install_git(names, version, options)
- elsif options[:path]
- install_path(names, version, options[:path])
+ elsif options[:local_git]
+ install_local_git(names, version, options)
else
sources = options[:source] || Gem.sources
install_rubygems(names, version, sources)
@@ -46,40 +45,20 @@ module Bundler
if options.key?(:git) && options.key?(:local_git)
raise InvalidOption, "Remote and local plugin git sources can't be both specified"
end
-
- # back-compat; local_git is an alias for git
- if options.key?(:local_git)
- Bundler::SharedHelpers.major_deprecation(2, "--local_git is deprecated, use --git")
- options[:git] = options.delete(:local_git)
- end
-
- if (options.keys & [:source, :git, :path]).length > 1
- raise InvalidOption, "Only one of --source, --git, or --path may be specified"
- end
-
- if (options.key?(:branch) || options.key?(:ref)) && !options.key?(:git)
- raise InvalidOption, "--#{options.key?(:branch) ? "branch" : "ref"} can only be used with git sources"
- end
-
- if options.key?(:branch) && options.key?(:ref)
- raise InvalidOption, "--branch and --ref can't be both specified"
- end
end
def install_git(names, version, options)
- source_list = SourceList.new
- source = source_list.add_git_source({ "uri" => options[:git],
- "branch" => options[:branch],
- "ref" => options[:ref] })
+ uri = options.delete(:git)
+ options["uri"] = uri
- install_all_sources(names, version, source_list, source)
+ install_all_sources(names, version, options, options[:source])
end
- def install_path(names, version, path)
- source_list = SourceList.new
- source = source_list.add_path_source({ "path" => path, "root_path" => SharedHelpers.pwd })
+ def install_local_git(names, version, options)
+ uri = options.delete(:local_git)
+ options["uri"] = uri
- install_all_sources(names, version, source_list, source)
+ install_all_sources(names, version, options, options[:source])
end
# Installs the plugin from rubygems source and returns the path where the
@@ -91,19 +70,20 @@ module Bundler
#
# @return [Hash] map of names to the specs of plugins installed
def install_rubygems(names, version, sources)
- source_list = SourceList.new
+ install_all_sources(names, version, nil, sources)
+ end
- Array(sources).each {|remote| source_list.add_global_rubygems_remote(remote) }
+ def install_all_sources(names, version, git_source_options, rubygems_source)
+ source_list = SourceList.new
- install_all_sources(names, version, source_list)
- end
+ source_list.add_git_source(git_source_options) if git_source_options
+ Array(rubygems_source).each {|remote| source_list.add_global_rubygems_remote(remote) } if rubygems_source
- def install_all_sources(names, version, source_list, source = nil)
- deps = names.map {|name| Dependency.new(name, version, { "source" => source }) }
+ deps = names.map {|name| Dependency.new name, version }
Bundler.configure_gem_home_and_path(Plugin.root)
- Bundler.settings.temporary(deployment: false, frozen: false) do
+ Bundler.settings.temporary(:deployment => false, :frozen => false) do
definition = Definition.new(nil, deps, source_list, true)
install_definition(definition)
diff --git a/lib/bundler/plugin/installer/path.rb b/lib/bundler/plugin/installer/path.rb
deleted file mode 100644
index 58a8fa7426..0000000000
--- a/lib/bundler/plugin/installer/path.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module Bundler
- module Plugin
- class Installer
- class Path < Bundler::Source::Path
- def root
- SharedHelpers.in_bundle? ? Bundler.root : Plugin.root
- end
-
- def generate_bin(spec, disable_extensions = false)
- # Need to find a way without code duplication
- # For now, we can ignore this
- end
- end
- end
- end
-end
diff --git a/lib/bundler/plugin/source_list.rb b/lib/bundler/plugin/source_list.rb
index 746996de55..547661cf2f 100644
--- a/lib/bundler/plugin/source_list.rb
+++ b/lib/bundler/plugin/source_list.rb
@@ -9,10 +9,6 @@ module Bundler
add_source_to_list Plugin::Installer::Git.new(options), git_sources
end
- def add_path_source(options = {})
- add_source_to_list Plugin::Installer::Path.new(options), path_sources
- end
-
def add_rubygems_source(options = {})
add_source_to_list Plugin::Installer::Rubygems.new(options), @rubygems_sources
end
@@ -21,6 +17,10 @@ module Bundler
path_sources + git_sources + rubygems_sources + [metadata_source]
end
+ def default_source
+ git_sources.first || global_rubygems_source
+ end
+
private
def rubygems_aggregate_class
diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb
index 9d237f3fa0..f626a3218e 100644
--- a/lib/bundler/remote_specification.rb
+++ b/lib/bundler/remote_specification.rb
@@ -88,10 +88,6 @@ module Bundler
end
end
- def runtime_dependencies
- dependencies.select(&:runtime?)
- end
-
def git_version
return unless loaded_from && source.is_a?(Bundler::Source::Git)
" #{source.revision[0..6]}"
diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb
index a38b6974f8..2ad35bc931 100644
--- a/lib/bundler/resolver.rb
+++ b/lib/bundler/resolver.rb
@@ -29,7 +29,7 @@ module Bundler
Bundler.ui.info "Resolving dependencies...", true
- solve_versions(root: root, logger: logger)
+ solve_versions(:root => root, :logger => logger)
end
def setup_solver
@@ -37,39 +37,31 @@ module Bundler
root_version = Resolver::Candidate.new(0)
@all_specs = Hash.new do |specs, name|
- source = source_for(name)
- matches = source.specs.search(name)
-
- # Don't bother to check for circular deps when no dependency API are
- # available, since it's too slow to be usable. That edge case won't work
- # but resolution other than that should work fine and reasonably fast.
- if source.respond_to?(:dependency_api_available?) && source.dependency_api_available?
- matches = filter_invalid_self_dependencies(matches, name)
- end
-
- specs[name] = matches.sort_by {|s| [s.version, s.platform.to_s] }
- end
-
- @all_versions = Hash.new do |candidates, package|
- candidates[package] = all_versions_for(package)
+ specs[name] = source_for(name).specs.search(name).reject do |s|
+ s.dependencies.any? {|d| d.name == name && !d.requirement.satisfied_by?(s.version) } # ignore versions that depend on themselves incorrectly
+ end.sort_by {|s| [s.version, s.platform.to_s] }
end
@sorted_versions = Hash.new do |candidates, package|
- candidates[package] = filtered_versions_for(package).sort
+ candidates[package] = if package.root?
+ [root_version]
+ else
+ all_versions_for(package).sort
+ end
end
- @sorted_versions[root] = [root_version]
-
root_dependencies = prepare_dependencies(@requirements, @packages)
@cached_dependencies = Hash.new do |dependencies, package|
- dependencies[package] = Hash.new do |versions, version|
- versions[version] = to_dependency_hash(version.dependencies.reject {|d| d.name == package.name }, @packages)
+ dependencies[package] = if package.root?
+ { root_version => root_dependencies }
+ else
+ Hash.new do |versions, version|
+ versions[version] = to_dependency_hash(version.dependencies.reject {|d| d.name == package.name }, @packages)
+ end
end
end
- @cached_dependencies[root] = { root_version => root_dependencies }
-
logger = Bundler::UI::Shell.new
logger.level = debug? ? "debug" : "warn"
@@ -77,16 +69,15 @@ module Bundler
end
def solve_versions(root:, logger:)
- solver = PubGrub::VersionSolver.new(source: self, root: root, logger: logger)
+ solver = PubGrub::VersionSolver.new(:source => self, :root => root, :logger => logger)
result = solver.solve
- resolved_specs = result.map {|package, version| version.to_specs(package) }.flatten
- resolved_specs |= @base.specs_compatible_with(SpecSet.new(resolved_specs))
+ result.map {|package, version| version.to_specs(package) }.flatten.uniq
rescue PubGrub::SolveFailure => e
incompatibility = e.incompatibility
- names_to_unlock, names_to_allow_prereleases_for, names_to_allow_remote_specs_for, extended_explanation = find_names_to_relax(incompatibility)
+ names_to_unlock, names_to_allow_prereleases_for, extended_explanation = find_names_to_relax(incompatibility)
- names_to_relax = names_to_unlock + names_to_allow_prereleases_for + names_to_allow_remote_specs_for
+ names_to_relax = names_to_unlock + names_to_allow_prereleases_for
if names_to_relax.any?
if names_to_unlock.any?
@@ -96,17 +87,11 @@ module Bundler
end
if names_to_allow_prereleases_for.any?
- Bundler.ui.debug "Found conflicts with dependencies with prereleases. Will retry considering prereleases for #{names_to_allow_prereleases_for.join(", ")}...", true
+ Bundler.ui.debug "Found conflicts with dependencies with prereleases. Will retrying considering prereleases for #{names_to_allow_prereleases_for.join(", ")}...", true
@base.include_prereleases(names_to_allow_prereleases_for)
end
- if names_to_allow_remote_specs_for.any?
- Bundler.ui.debug "Found conflicts with local versions of #{names_to_allow_remote_specs_for.join(", ")}. Will retry considering remote versions...", true
-
- @base.include_remote_specs(names_to_allow_remote_specs_for)
- end
-
root, logger = setup_solver
Bundler.ui.debug "Retrying resolution...", true
@@ -126,7 +111,6 @@ module Bundler
def find_names_to_relax(incompatibility)
names_to_unlock = []
names_to_allow_prereleases_for = []
- names_to_allow_remote_specs_for = []
extended_explanation = nil
while incompatibility.conflict?
@@ -139,10 +123,8 @@ module Bundler
if base_requirements[name]
names_to_unlock << name
- elsif package.ignores_prereleases? && @all_specs[name].any? {|s| s.version.prerelease? }
+ elsif package.ignores_prereleases?
names_to_allow_prereleases_for << name
- elsif package.prefer_local? && @all_specs[name].any? {|s| !s.is_a?(StubSpecification) }
- names_to_allow_remote_specs_for << name
end
no_versions_incompat = [cause.incompatibility, cause.satisfier].find {|incompat| incompat.cause.is_a?(PubGrub::Incompatibility::NoVersions) }
@@ -152,7 +134,7 @@ module Bundler
end
end
- [names_to_unlock.uniq, names_to_allow_prereleases_for.uniq, names_to_allow_remote_specs_for.uniq, extended_explanation]
+ [names_to_unlock.uniq, names_to_allow_prereleases_for.uniq, extended_explanation]
end
def parse_dependency(package, dependency)
@@ -162,19 +144,13 @@ module Bundler
requirement_to_range(dependency)
end
- PubGrub::VersionConstraint.new(package, range: range)
+ PubGrub::VersionConstraint.new(package, :range => range)
end
def versions_for(package, range=VersionRange.any)
- versions = select_sorted_versions(package, range)
+ versions = range.select_versions(@sorted_versions[package])
- # Conditional avoids (among other things) calling
- # sort_versions_by_preferred with the root package
- if versions.size > 1
- sort_versions_by_preferred(package, versions)
- else
- versions
- end
+ sort_versions(package, versions)
end
def no_versions_incompatibility_for(package, unsatisfied_term)
@@ -197,7 +173,7 @@ module Bundler
extended_explanation = other_specs_matching_message(specs_matching_other_platforms, label) if specs_matching_other_platforms.any?
end
- Incompatibility.new([unsatisfied_term], cause: cause, custom_explanation: custom_explanation, extended_explanation: extended_explanation)
+ Incompatibility.new([unsatisfied_term], :cause => cause, :custom_explanation => custom_explanation, :extended_explanation => extended_explanation)
end
def debug?
@@ -236,9 +212,9 @@ module Bundler
sorted_versions[high]
end
- range = PubGrub::VersionRange.new(min: low, max: high, include_min: true)
+ range = PubGrub::VersionRange.new(:min => low, :max => high, :include_min => true)
- self_constraint = PubGrub::VersionConstraint.new(package, range: range)
+ self_constraint = PubGrub::VersionConstraint.new(package, :range => range)
dep_term = PubGrub::Term.new(dep_constraint, false)
self_term = PubGrub::Term.new(self_constraint, true)
@@ -247,13 +223,13 @@ module Bundler
"current #{dep_package} version is #{dep_constraint.constraint_string}"
end
- PubGrub::Incompatibility.new([self_term, dep_term], cause: :dependency, custom_explanation: custom_explanation)
+ PubGrub::Incompatibility.new([self_term, dep_term], :cause => :dependency, :custom_explanation => custom_explanation)
end
end
def all_versions_for(package)
name = package.name
- results = (@base[name] + filter_specs(@all_specs[name], package)).uniq {|spec| [spec.version.hash, spec.platform] }
+ results = (@base[name] + filter_prereleases(@all_specs[name], package)).uniq {|spec| [spec.version.hash, spec.platform] }
if name == "bundler" && !bundler_pinned_to_current_version?
bundler_spec = Gem.loaded_specs["bundler"]
@@ -263,41 +239,21 @@ module Bundler
locked_requirement = base_requirements[name]
results = filter_matching_specs(results, locked_requirement) if locked_requirement
- results.group_by(&:version).reduce([]) do |groups, (version, specs)|
- platform_specs = package.platform_specs(specs)
-
- # If package is a top-level dependency,
- # candidate is only valid if there are matching versions for all resolution platforms.
- #
- # If package is not a top-level deependency,
- # then it's not necessary that it has matching versions for all platforms, since it may have been introduced only as
- # a dependency for a platform specific variant, so it will only need to have a valid version for that platform.
- #
- if package.top_level?
- next groups if platform_specs.any?(&:empty?)
- else
- next groups if platform_specs.all?(&:empty?)
- end
+ versions = results.group_by(&:version).reduce([]) do |groups, (version, specs)|
+ platform_specs = package.platforms.flat_map {|platform| select_best_platform_match(specs, platform) }
+ next groups if platform_specs.empty?
ruby_specs = select_best_platform_match(specs, Gem::Platform::RUBY)
- ruby_group = Resolver::SpecGroup.new(ruby_specs)
+ groups << Resolver::Candidate.new(version, :specs => ruby_specs) if ruby_specs.any?
- unless ruby_group.empty?
- platform_specs.each do |specs|
- ruby_group.merge(Resolver::SpecGroup.new(specs))
- end
+ next groups if platform_specs == ruby_specs || package.force_ruby_platform?
- groups << Resolver::Candidate.new(version, group: ruby_group, priority: -1)
- next groups if package.force_ruby_platform?
- end
-
- platform_group = Resolver::SpecGroup.new(platform_specs.flatten.uniq)
- next groups if platform_group == ruby_group
-
- groups << Resolver::Candidate.new(version, group: platform_group, priority: 1)
+ groups << Resolver::Candidate.new(version, :specs => platform_specs)
groups
end
+
+ sort_versions(package, versions)
end
def source_for(name)
@@ -331,21 +287,15 @@ module Bundler
end
specs_matching_requirement = filter_matching_specs(specs, package.dependency.requirement)
- not_found_message = if specs_matching_requirement.any?
+ if specs_matching_requirement.any?
specs = specs_matching_requirement
matching_part = requirement_label
platforms = package.platforms
-
- if platforms.size == 1
- "Could not find gem '#{requirement_label}' with platform '#{platforms.first}'"
- else
- "Could not find gems matching '#{requirement_label}' valid for all resolution platforms (#{platforms.join(", ")})"
- end
- else
- "Could not find gem '#{requirement_label}'"
+ platform_label = platforms.size == 1 ? "platform '#{platforms.first}" : "platforms '#{platforms.join("', '")}"
+ requirement_label = "#{requirement_label}' with #{platform_label}"
end
- message = String.new("#{not_found_message} in #{source}#{cache_message}.\n")
+ message = String.new("Could not find gem '#{requirement_label}' in #{source}#{cache_message}.\n")
if specs.any?
message << "\n#{other_specs_matching_message(specs, matching_part)}"
@@ -356,56 +306,28 @@ module Bundler
private
- def filtered_versions_for(package)
- @gem_version_promoter.filter_versions(package, @all_versions[package])
- end
-
- def raise_all_versions_filtered_out!(package)
- level = @gem_version_promoter.level
- name = package.name
- locked_version = package.locked_version
- requirement = package.dependency
-
- raise GemNotFound,
- "#{name} is locked to #{locked_version}, while Gemfile is requesting #{requirement}. " \
- "--strict --#{level} was specified, but there are no #{level} level upgrades from #{locked_version} satisfying #{requirement}, so version solving has failed"
- end
-
def filter_matching_specs(specs, requirements)
Array(requirements).flat_map do |requirement|
specs.select {| spec| requirement_satisfied_by?(requirement, spec) }
end
end
- def filter_specs(specs, package)
- filter_remote_specs(filter_prereleases(specs, package), package)
- end
-
def filter_prereleases(specs, package)
return specs unless package.ignores_prereleases? && specs.size > 1
specs.reject {|s| s.version.prerelease? }
end
- def filter_remote_specs(specs, package)
- return specs unless package.prefer_local?
-
- specs.select {|s| s.is_a?(StubSpecification) }
- end
-
- # Ignore versions that depend on themselves incorrectly
- def filter_invalid_self_dependencies(specs, name)
- specs.reject do |s|
- s.dependencies.any? {|d| d.name == name && !d.requirement.satisfied_by?(s.version) }
- end
- end
-
def requirement_satisfied_by?(requirement, spec)
requirement.satisfied_by?(spec.version) || spec.source.is_a?(Source::Gemspec)
end
- def sort_versions_by_preferred(package, versions)
- @gem_version_promoter.sort_versions(package, versions)
+ def sort_versions(package, versions)
+ if versions.size > 1
+ @gem_version_promoter.sort_versions(package, versions).reverse
+ else
+ versions
+ end
end
def repository_for(package)
@@ -422,22 +344,12 @@ module Bundler
next [dep_package, dep_constraint] if name == "bundler"
- dep_range = dep_constraint.range
- versions = select_sorted_versions(dep_package, dep_range)
- if versions.empty?
- if dep_package.ignores_prereleases? || dep_package.prefer_local?
- @all_versions.delete(dep_package)
- @sorted_versions.delete(dep_package)
- end
- dep_package.consider_prereleases! if dep_package.ignores_prereleases?
- dep_package.consider_remote_versions! if dep_package.prefer_local?
- versions = select_sorted_versions(dep_package, dep_range)
+ versions = versions_for(dep_package, dep_constraint.range)
+ if versions.empty? && dep_package.ignores_prereleases?
+ @sorted_versions.delete(dep_package)
+ dep_package.consider_prereleases!
+ versions = versions_for(dep_package, dep_constraint.range)
end
-
- if versions.empty? && select_all_versions(dep_package, dep_range).any?
- raise_all_versions_filtered_out!(dep_package)
- end
-
next [dep_package, dep_constraint] unless versions.empty?
next unless dep_package.current_platform?
@@ -446,14 +358,6 @@ module Bundler
end.compact.to_h
end
- def select_sorted_versions(package, range)
- range.select_versions(@sorted_versions[package])
- end
-
- def select_all_versions(package, range)
- range.select_versions(@all_versions[package])
- end
-
def other_specs_matching_message(specs, requirement)
message = String.new("The source contains the following gems matching '#{requirement}':\n")
message << specs.map {|s| " * #{s.full_name}" }.join("\n")
@@ -462,26 +366,26 @@ module Bundler
def requirement_to_range(requirement)
ranges = requirement.requirements.map do |(op, version)|
- ver = Resolver::Candidate.new(version, priority: -1)
- platform_ver = Resolver::Candidate.new(version, priority: 1)
+ ver = Resolver::Candidate.new(version).generic!
+ platform_ver = Resolver::Candidate.new(version).platform_specific!
case op
when "~>"
name = "~> #{ver}"
bump = Resolver::Candidate.new(version.bump.to_s + ".A")
- PubGrub::VersionRange.new(name: name, min: ver, max: bump, include_min: true)
+ PubGrub::VersionRange.new(:name => name, :min => ver, :max => bump, :include_min => true)
when ">"
- PubGrub::VersionRange.new(min: platform_ver)
+ PubGrub::VersionRange.new(:min => platform_ver)
when ">="
- PubGrub::VersionRange.new(min: ver, include_min: true)
+ PubGrub::VersionRange.new(:min => ver, :include_min => true)
when "<"
- PubGrub::VersionRange.new(max: ver)
+ PubGrub::VersionRange.new(:max => ver)
when "<="
- PubGrub::VersionRange.new(max: platform_ver, include_max: true)
+ PubGrub::VersionRange.new(:max => platform_ver, :include_max => true)
when "="
- PubGrub::VersionRange.new(min: ver, max: platform_ver, include_min: true, include_max: true)
+ PubGrub::VersionRange.new(:min => ver, :max => platform_ver, :include_min => true, :include_max => true)
when "!="
- PubGrub::VersionRange.new(min: ver, max: platform_ver, include_min: true, include_max: true).invert
+ PubGrub::VersionRange.new(:min => ver, :max => platform_ver, :include_min => true, :include_max => true).invert
else
raise "bad version specifier: #{op}"
end
diff --git a/lib/bundler/resolver/base.rb b/lib/bundler/resolver/base.rb
index 3f2436672a..e5c3763c3f 100644
--- a/lib/bundler/resolver/base.rb
+++ b/lib/bundler/resolver/base.rb
@@ -24,16 +24,12 @@ module Bundler
name = dep.name
- @packages[name] = Package.new(name, dep_platforms, **options.merge(dependency: dep))
+ @packages[name] = Package.new(name, dep_platforms, **options.merge(:dependency => dep))
dep
end.compact
end
- def specs_compatible_with(result)
- @base.specs_compatible_with(result)
- end
-
def [](name)
@base[name]
end
@@ -72,12 +68,6 @@ module Bundler
end
end
- def include_remote_specs(names)
- names.each do |name|
- get_package(name).consider_remote_versions!
- end
- end
-
private
def indirect_pins(names)
diff --git a/lib/bundler/resolver/candidate.rb b/lib/bundler/resolver/candidate.rb
index f593fc5d61..e695ef08ee 100644
--- a/lib/bundler/resolver/candidate.rb
+++ b/lib/bundler/resolver/candidate.rb
@@ -15,7 +15,7 @@ module Bundler
# considered separately.
#
# Some candidates may also keep some information explicitly about the
- # package they refer to. These candidates are referred to as "canonical" and
+ # package the refer to. These candidates are referred to as "canonical" and
# are used when materializing resolution results back into RubyGems
# specifications that can be installed, written to lock files, and so on.
#
@@ -24,10 +24,10 @@ module Bundler
attr_reader :version
- def initialize(version, group: nil, priority: -1)
- @spec_group = group || SpecGroup.new([])
+ def initialize(version, specs: [])
+ @spec_group = Resolver::SpecGroup.new(specs)
@version = Gem::Version.new(version)
- @priority = priority
+ @ruby_only = specs.map(&:platform).uniq == [Gem::Platform::RUBY]
end
def dependencies
@@ -40,6 +40,18 @@ module Bundler
@spec_group.to_specs(package.force_ruby_platform?)
end
+ def generic!
+ @ruby_only = true
+
+ self
+ end
+
+ def platform_specific!
+ @ruby_only = false
+
+ self
+ end
+
def prerelease?
@version.prerelease?
end
@@ -49,7 +61,7 @@ module Bundler
end
def sort_obj
- [@version, @priority]
+ [@version, @ruby_only ? -1 : 1]
end
def <=>(other)
diff --git a/lib/bundler/resolver/incompatibility.rb b/lib/bundler/resolver/incompatibility.rb
index 4ac1b2e1ea..c61151fbeb 100644
--- a/lib/bundler/resolver/incompatibility.rb
+++ b/lib/bundler/resolver/incompatibility.rb
@@ -8,7 +8,7 @@ module Bundler
def initialize(terms, cause:, custom_explanation: nil, extended_explanation: nil)
@extended_explanation = extended_explanation
- super(terms, cause: cause, custom_explanation: custom_explanation)
+ super(terms, :cause => cause, :custom_explanation => custom_explanation)
end
end
end
diff --git a/lib/bundler/resolver/package.rb b/lib/bundler/resolver/package.rb
index 5aecc12d05..7499a75006 100644
--- a/lib/bundler/resolver/package.rb
+++ b/lib/bundler/resolver/package.rb
@@ -15,19 +15,13 @@ module Bundler
class Package
attr_reader :name, :platforms, :dependency, :locked_version
- def initialize(name, platforms, locked_specs:, unlock:, prerelease: false, prefer_local: false, dependency: nil)
+ def initialize(name, platforms, locked_specs:, unlock:, prerelease: false, dependency: nil)
@name = name
@platforms = platforms
@locked_version = locked_specs[name].first&.version
@unlock = unlock
@dependency = dependency || Dependency.new(name, @locked_version)
- @top_level = !dependency.nil?
@prerelease = @dependency.prerelease? || @locked_version&.prerelease? || prerelease ? :consider_first : :ignore
- @prefer_local = prefer_local
- end
-
- def platform_specs(specs)
- platforms.map {|platform| GemHelpers.select_best_platform_match(specs, platform, prefer_locked: !unlock?) }
end
def to_s
@@ -38,10 +32,6 @@ module Bundler
false
end
- def top_level?
- @top_level
- end
-
def meta?
@name.end_with?("\0")
end
@@ -70,14 +60,6 @@ module Bundler
@prerelease = :consider_last
end
- def prefer_local?
- @prefer_local
- end
-
- def consider_remote_versions!
- @prefer_local = false
- end
-
def force_ruby_platform?
@dependency.force_ruby_platform
end
diff --git a/lib/bundler/resolver/spec_group.rb b/lib/bundler/resolver/spec_group.rb
index f950df6eda..b44c19a73f 100644
--- a/lib/bundler/resolver/spec_group.rb
+++ b/lib/bundler/resolver/spec_group.rb
@@ -3,8 +3,6 @@
module Bundler
class Resolver
class SpecGroup
- attr_reader :specs
-
def initialize(specs)
@specs = specs
end
@@ -27,8 +25,9 @@ module Bundler
def to_specs(force_ruby_platform)
@specs.map do |s|
- lazy_spec = LazySpecification.from_spec(s)
+ lazy_spec = LazySpecification.new(name, version, s.platform, source)
lazy_spec.force_ruby_platform = force_ruby_platform
+ lazy_spec.dependencies.replace s.dependencies
lazy_spec
end
end
@@ -40,33 +39,17 @@ module Bundler
def dependencies
@dependencies ||= @specs.map do |spec|
__dependencies(spec) + metadata_dependencies(spec)
- end.flatten.uniq.sort
- end
-
- def ==(other)
- sorted_spec_names == other.sorted_spec_names
- end
-
- def merge(other)
- return false unless equivalent?(other)
-
- @specs |= other.specs
-
- true
+ end.flatten.uniq
end
protected
def sorted_spec_names
- @specs.map(&:full_name).sort
+ @sorted_spec_names ||= @specs.map(&:full_name).sort
end
private
- def equivalent?(other)
- name == other.name && version == other.version && source == other.source && dependencies == other.dependencies
- end
-
def exemplary_spec
@specs.first
end
@@ -81,6 +64,8 @@ module Bundler
end
def metadata_dependencies(spec)
+ return [] if spec.is_a?(LazySpecification)
+
[
metadata_dependency("Ruby", spec.required_ruby_version),
metadata_dependency("RubyGems", spec.required_rubygems_version),
diff --git a/lib/bundler/retry.rb b/lib/bundler/retry.rb
index 090cb7e2ca..2415ade200 100644
--- a/lib/bundler/retry.rb
+++ b/lib/bundler/retry.rb
@@ -50,13 +50,13 @@ module Bundler
end
return true unless name
Bundler.ui.info "" unless Bundler.ui.debug? # Add new line in case dots preceded this
- Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}", true
+ Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}", Bundler.ui.debug?
end
def keep_trying?
return true if current_run.zero?
return false if last_attempt?
- true if @failed
+ return true if @failed
end
def last_attempt?
diff --git a/lib/bundler/ruby_dsl.rb b/lib/bundler/ruby_dsl.rb
index fb4b79c4df..d054969e8d 100644
--- a/lib/bundler/ruby_dsl.rb
+++ b/lib/bundler/ruby_dsl.rb
@@ -3,51 +3,22 @@
module Bundler
module RubyDsl
def ruby(*ruby_version)
- options = ruby_version.pop if ruby_version.last.is_a?(Hash)
+ options = ruby_version.last.is_a?(Hash) ? ruby_version.pop : {}
ruby_version.flatten!
- if options
- patchlevel = options[:patchlevel]
- engine = options[:engine]
- engine_version = options[:engine_version]
+ raise GemfileError, "Please define :engine_version" if options[:engine] && options[:engine_version].nil?
+ raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil?
- raise GemfileError, "Please define :engine_version" if engine && engine_version.nil?
- raise GemfileError, "Please define :engine" if engine_version && engine.nil?
-
- if options[:file]
- raise GemfileError, "Do not pass version argument when using :file option" unless ruby_version.empty?
- ruby_version << normalize_ruby_file(options[:file])
- end
-
- if engine == "ruby" && engine_version && ruby_version != Array(engine_version)
- raise GemfileEvalError, "ruby_version must match the :engine_version for MRI"
- end
+ if options[:file]
+ raise GemfileError, "Cannot specify version when using the file option" if ruby_version.any?
+ ruby_version << Bundler.read_file(options[:file]).strip
end
- @ruby_version = RubyVersion.new(ruby_version, patchlevel, engine, engine_version)
- end
-
- # Support the various file formats found in .ruby-version files.
- #
- # 3.2.2
- # ruby-3.2.2
- #
- # Also supports .tool-versions files for asdf. Lines not starting with "ruby" are ignored.
- #
- # ruby 2.5.1 # comment is ignored
- # ruby 2.5.1# close comment and extra spaces doesn't confuse
- #
- # Intentionally does not support `3.2.1@gemset` since rvm recommends using .ruby-gemset instead
- #
- # Loads the file relative to the dirname of the Gemfile itself.
- def normalize_ruby_file(filename)
- file_content = Bundler.read_file(gemfile.dirname.join(filename))
- # match "ruby-3.2.2" or "ruby 3.2.2" capturing version string up to the first space or comment
- if /^ruby(-|\s+)([^\s#]+)/.match(file_content)
- $2
- else
- file_content.strip
+ if options[:engine] == "ruby" && options[:engine_version] &&
+ ruby_version != Array(options[:engine_version])
+ raise GemfileEvalError, "ruby_version must match the :engine_version for MRI"
end
+ @ruby_version = RubyVersion.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version])
end
end
end
diff --git a/lib/bundler/ruby_version.rb b/lib/bundler/ruby_version.rb
index 0ed5cbc6ca..b5396abb6e 100644
--- a/lib/bundler/ruby_version.rb
+++ b/lib/bundler/ruby_version.rb
@@ -23,13 +23,7 @@ module Bundler
# specified must match the version.
@versions = Array(versions).map do |v|
- normalized_v = normalize_version(v)
-
- unless Gem::Requirement::PATTERN.match?(normalized_v)
- raise InvalidArgumentError, "#{v} is not a valid requirement on the Ruby version"
- end
-
- op, v = Gem::Requirement.parse(normalized_v)
+ op, v = Gem::Requirement.parse(v)
op == "=" ? v.to_s : "#{op} #{v}"
end
@@ -55,7 +49,7 @@ module Bundler
(\d+\.\d+\.\d+(?:\.\S+)?) # ruby version
(?:p(-?\d+))? # optional patchlevel
(?:\s\((\S+)\s(.+)\))? # optional engine info
- /xo
+ /xo.freeze
# Returns a RubyVersion from the given string.
# @param [String] the version string to match.
@@ -118,13 +112,6 @@ module Bundler
private
- # Ruby's official preview version format uses a `-`: Example: 3.3.0-preview2
- # However, RubyGems recognizes preview version format with a `.`: Example: 3.3.0.preview2
- # Returns version string after replacing `-` with `.`
- def normalize_version(version)
- version.tr("-", ".")
- end
-
def matches?(requirements, version)
# Handles RUBY_PATCHLEVEL of -1 for instances like ruby-head
return requirements == version if requirements.to_s == "-1" || version.to_s == "-1"
diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb
index 67f830d4f3..8981612706 100644
--- a/lib/bundler/rubygems_ext.rb
+++ b/lib/bundler/rubygems_ext.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
-require "rubygems" unless defined?(Gem)
+require "pathname"
+
+require "rubygems/specification"
# We can't let `Gem::Source` be autoloaded in the `Gem::Specification#source`
# redefinition below, so we need to load it upfront. The reason is that if
@@ -13,6 +15,10 @@ require "rubygems" unless defined?(Gem)
# `Gem::Source` from the redefined `Gem::Specification#source`.
require "rubygems/source"
+require_relative "match_metadata"
+require_relative "force_platform"
+require_relative "match_platform"
+
# Cherry-pick fixes to `Gem.ruby_version` to be useful for modern Bundler
# versions and ignore patchlevels
# (https://github.com/rubygems/rubygems/pull/5472,
@@ -23,60 +29,7 @@ unless Gem.ruby_version.to_s == RUBY_VERSION || RUBY_PATCHLEVEL == -1
end
module Gem
- # Can be removed once RubyGems 3.5.11 support is dropped
- unless Gem.respond_to?(:freebsd_platform?)
- def self.freebsd_platform?
- RbConfig::CONFIG["host_os"].to_s.include?("bsd")
- end
- end
-
- # Can be removed once RubyGems 3.5.18 support is dropped
- unless Gem.respond_to?(:open_file_with_lock)
- class << self
- remove_method :open_file_with_flock if Gem.respond_to?(:open_file_with_flock)
-
- def open_file_with_flock(path, &block)
- mode = IO::RDONLY | IO::APPEND | IO::CREAT | IO::BINARY
- mode |= IO::SHARE_DELETE if IO.const_defined?(:SHARE_DELETE)
-
- File.open(path, mode) do |io|
- begin
- io.flock(File::LOCK_EX)
- rescue Errno::ENOSYS, Errno::ENOTSUP
- rescue Errno::ENOLCK # NFS
- raise unless Thread.main == Thread.current
- end
- yield io
- end
- end
-
- def open_file_with_lock(path, &block)
- file_lock = "#{path}.lock"
- open_file_with_flock(file_lock, &block)
- ensure
- FileUtils.rm_f file_lock
- end
- end
- end
-
- require "rubygems/specification"
-
- # Can be removed once RubyGems 3.5.14 support is dropped
- VALIDATES_FOR_RESOLUTION = Specification.new.respond_to?(:validate_for_resolution).freeze
-
- # Can be removed once RubyGems 3.3.15 support is dropped
- FLATTENS_REQUIRED_PATHS = Specification.new.respond_to?(:flatten_require_paths).freeze
-
class Specification
- # Can be removed once RubyGems 3.5.15 support is dropped
- correct_array_attributes = @@default_value.select {|_k,v| v.is_a?(Array) }.keys
- unless @@array_attributes == correct_array_attributes
- @@array_attributes = correct_array_attributes # rubocop:disable Style/ClassVars
- end
-
- require_relative "match_metadata"
- require_relative "match_platform"
-
include ::Bundler::MatchMetadata
include ::Bundler::MatchPlatform
@@ -93,7 +46,7 @@ module Gem
def full_gem_path
if source.respond_to?(:root)
- File.expand_path(File.dirname(loaded_from), source.root)
+ Pathname.new(loaded_from).dirname.expand_path(source.root).to_s.tap {|x| x.untaint if RUBY_VERSION < "2.7" }
else
rg_full_gem_path
end
@@ -123,6 +76,11 @@ module Gem
end
end
+ remove_method :gem_dir if instance_methods(false).include?(:gem_dir)
+ def gem_dir
+ full_gem_path
+ end
+
unless const_defined?(:LATEST_RUBY_WITHOUT_PATCH_VERSIONS)
LATEST_RUBY_WITHOUT_PATCH_VERSIONS = Gem::Version.new("2.1")
@@ -159,39 +117,23 @@ module Gem
gemfile
end
- def nondevelopment_dependencies
- dependencies - development_dependencies
- end
+ # Backfill missing YAML require when not defined. Fixed since 3.1.0.pre1.
+ module YamlBackfiller
+ def to_yaml(opts = {})
+ Gem.load_yaml unless defined?(::YAML)
- def deleted_gem?
- !default_gem? && !File.directory?(full_gem_path)
- end
-
- unless VALIDATES_FOR_RESOLUTION
- def validate_for_resolution
- SpecificationPolicy.new(self).validate_for_resolution
+ super(opts)
end
end
- unless FLATTENS_REQUIRED_PATHS
- def flatten_require_paths
- return unless raw_require_paths.first.is_a?(Array)
-
- warn "#{name} #{version} includes a gemspec with `require_paths` set to an array of arrays. Newer versions of this gem might've already fixed this"
- raw_require_paths.flatten!
- end
+ prepend YamlBackfiller
- class << self
- module RequirePathFlattener
- def from_yaml(input)
- spec = super(input)
- spec.flatten_require_paths
- spec
- end
- end
+ def nondevelopment_dependencies
+ dependencies - development_dependencies
+ end
- prepend RequirePathFlattener
- end
+ def deleted_gem?
+ !default_gem? && !File.directory?(full_gem_path)
end
private
@@ -213,47 +155,29 @@ module Gem
end
end
- unless VALIDATES_FOR_RESOLUTION
- class SpecificationPolicy
- def validate_for_resolution
- validate_required!
- end
- end
- end
-
- module BetterPermissionError
- def data
- super
- rescue Errno::EACCES
- raise Bundler::PermissionError.new(loaded_from, :read)
- end
- end
-
- require "rubygems/stub_specification"
-
- class StubSpecification
- prepend BetterPermissionError
- end
-
class Dependency
- require_relative "force_platform"
-
include ::Bundler::ForcePlatform
- attr_reader :force_ruby_platform
-
attr_accessor :source, :groups
alias_method :eql?, :==
- unless method_defined?(:encode_with, false)
- def encode_with(coder)
- [:@name, :@requirement, :@type, :@prerelease, :@version_requirements].each do |ivar|
- coder[ivar.to_s.sub(/^@/, "")] = instance_variable_get(ivar)
- end
+ def force_ruby_platform
+ return @force_ruby_platform if defined?(@force_ruby_platform) && !@force_ruby_platform.nil?
+
+ @force_ruby_platform = default_force_ruby_platform
+ end
+
+ def encode_with(coder)
+ to_yaml_properties.each do |ivar|
+ coder[ivar.to_s.sub(/^@/, "")] = instance_variable_get(ivar)
end
end
+ def to_yaml_properties
+ instance_variables.reject {|p| ["@source", "@groups"].include?(p.to_s) }
+ end
+
def to_lock
out = String.new(" #{name}")
unless requirement.none?
@@ -264,6 +188,53 @@ module Gem
end
end
+ # comparison is done order independently since rubygems 3.2.0.rc.2
+ unless Gem::Requirement.new("> 1", "< 2") == Gem::Requirement.new("< 2", "> 1")
+ class Requirement
+ module OrderIndependentComparison
+ def ==(other)
+ return unless Gem::Requirement === other
+
+ if _requirements_sorted? && other._requirements_sorted?
+ super
+ else
+ _with_sorted_requirements == other._with_sorted_requirements
+ end
+ end
+
+ protected
+
+ def _requirements_sorted?
+ return @_requirements_sorted if defined?(@_requirements_sorted)
+ strings = as_list
+ @_requirements_sorted = strings == strings.sort
+ end
+
+ def _with_sorted_requirements
+ @_with_sorted_requirements ||= _requirements_sorted? ? self : self.class.new(as_list.sort)
+ end
+ end
+
+ prepend OrderIndependentComparison
+ end
+ end
+
+ if Gem::Requirement.new("~> 2.0").hash == Gem::Requirement.new("~> 2.0.0").hash
+ class Requirement
+ module CorrectHashForLambdaOperator
+ def hash
+ if requirements.any? {|r| r.first == "~>" }
+ requirements.map {|r| r.first == "~>" ? [r[0], r[1].to_s] : r }.sort.hash
+ else
+ super
+ end
+ end
+ end
+
+ prepend CorrectHashForLambdaOperator
+ end
+ end
+
require "rubygems/platform"
class Platform
@@ -289,7 +260,7 @@ module Gem
# cpu
([nil,"universal"].include?(@cpu) || [nil, "universal"].include?(other.cpu) || @cpu == other.cpu ||
- (@cpu == "arm" && other.cpu.start_with?("armv"))) &&
+ (@cpu == "arm" && other.cpu.start_with?("arm"))) &&
# os
@os == other.os &&
@@ -349,7 +320,7 @@ module Gem
end
# On universal Rubies, resolve the "universal" arch to the real CPU arch, without changing the extension directory.
- class BasicSpecification
+ class Specification
if /^universal\.(?<arch>.*?)-/ =~ (CROSS_COMPILING || RUBY_PLATFORM)
local_platform = Platform.local
if local_platform.cpu == "universal"
@@ -362,54 +333,23 @@ module Gem
end
def extensions_dir
- @extensions_dir ||=
- Gem.default_ext_dir_for(base_dir) || File.join(base_dir, "extensions", ORIGINAL_LOCAL_PLATFORM, Gem.extension_api_version)
+ Gem.default_ext_dir_for(base_dir) ||
+ File.join(base_dir, "extensions", ORIGINAL_LOCAL_PLATFORM,
+ Gem.extension_api_version)
end
end
end
end
- require "rubygems/name_tuple"
-
- class NameTuple
- # Versions of RubyGems before about 3.5.0 don't to_s the platform.
- unless Gem::NameTuple.new("a", Gem::Version.new("1"), Gem::Platform.new("x86_64-linux")).platform.is_a?(String)
- alias_method :initialize_with_platform, :initialize
+ require "rubygems/util"
- def initialize(name, version, platform=Gem::Platform::RUBY)
- if Gem::Platform === platform
- initialize_with_platform(name, version, platform.to_s)
- else
- initialize_with_platform(name, version, platform)
- end
- end
+ Util.singleton_class.module_eval do
+ if Util.singleton_methods.include?(:glob_files_in_dir) # since 3.0.0.beta.2
+ remove_method :glob_files_in_dir
end
- def lock_name
- if platform == Gem::Platform::RUBY
- "#{name} (#{version})"
- else
- "#{name} (#{version}-#{platform})"
- end
- end
- end
-
- unless Gem.rubygems_version >= Gem::Version.new("3.5.19")
- class Resolver::ActivationRequest
- remove_method :installed?
-
- def installed?
- case @spec
- when Gem::Resolver::VendorSpecification then
- true
- else
- this_spec = full_spec
-
- Gem::Specification.any? do |s|
- s == this_spec && s.base_dir == this_spec.base_dir
- end
- end
- end
+ def glob_files_in_dir(glob, base_path)
+ Dir.glob(glob, :base => base_path).map! {|f| File.expand_path(f, base_path) }
end
end
end
diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb
index 65fdf16072..38035a00ac 100644
--- a/lib/bundler/rubygems_gem_installer.rb
+++ b/lib/bundler/rubygems_gem_installer.rb
@@ -20,7 +20,7 @@ module Bundler
strict_rm_rf spec.extension_dir
SharedHelpers.filesystem_access(gem_dir, :create) do
- FileUtils.mkdir_p gem_dir, mode: 0o755
+ FileUtils.mkdir_p gem_dir, :mode => 0o755
end
extract_files
@@ -29,10 +29,7 @@ module Bundler
write_build_info_file
run_post_build_hooks
- SharedHelpers.filesystem_access(bin_dir, :write) do
- generate_bin
- end
-
+ generate_bin
generate_plugins
write_spec
@@ -48,24 +45,6 @@ module Bundler
spec
end
- if Bundler.rubygems.provides?("< 3.5")
- def pre_install_checks
- super
- rescue Gem::FilePermissionError
- # Ignore permission checks in RubyGems. Instead, go on, and try to write
- # for real. We properly handle permission errors when they happen.
- nil
- end
- end
-
- def ensure_writable_dir(dir)
- super
- rescue Gem::FilePermissionError
- # Ignore permission checks in RubyGems. Instead, go on, and try to write
- # for real. We properly handle permission errors when they happen.
- nil
- end
-
def generate_plugins
return unless Gem::Installer.instance_methods(false).include?(:generate_plugins)
@@ -81,24 +60,8 @@ module Bundler
end
end
- if Bundler.rubygems.provides?("< 3.5.19")
- def generate_bin_script(filename, bindir)
- bin_script_path = File.join bindir, formatted_program_filename(filename)
-
- Gem.open_file_with_lock(bin_script_path) do
- require "fileutils"
- FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers
-
- File.open(bin_script_path, "wb", 0o755) do |file|
- file.write app_script_text(filename)
- file.chmod(options[:prog_mode] || 0o755)
- end
- end
-
- verbose bin_script_path
-
- generate_windows_script filename, bindir
- end
+ def pre_install_checks
+ super && validate_bundler_checksum(options[:bundler_expected_checksum])
end
def build_extensions
@@ -135,35 +98,74 @@ module Bundler
end
end
- def gem_checksum
- Checksum.from_gem_package(@package)
- end
-
private
def prepare_extension_build(extension_dir)
SharedHelpers.filesystem_access(extension_dir, :create) do
FileUtils.mkdir_p extension_dir
end
+ require "shellwords" unless Bundler.rubygems.provides?(">= 3.2.25")
end
def strict_rm_rf(dir)
- return unless File.exist?(dir)
- return if Dir.empty?(dir)
+ Bundler.rm_rf dir
+ rescue StandardError => e
+ raise unless File.exist?(dir)
+
+ raise DirectoryRemovalError.new(e, "Could not delete previous installation of `#{dir}`")
+ end
- parent = File.dirname(dir)
- parent_st = File.stat(parent)
+ def validate_bundler_checksum(checksum)
+ return true if Bundler.settings[:disable_checksum_validation]
+ return true unless checksum
+ return true unless source = @package.instance_variable_get(:@gem)
+ return true unless source.respond_to?(:with_read_io)
+ digest = source.with_read_io do |io|
+ digest = SharedHelpers.digest(:SHA256).new
+ digest << io.read(16_384) until io.eof?
+ io.rewind
+ send(checksum_type(checksum), digest)
+ end
+ unless digest == checksum
+ raise SecurityError, <<-MESSAGE
+ Bundler cannot continue installing #{spec.name} (#{spec.version}).
+ The checksum for the downloaded `#{spec.full_name}.gem` does not match \
+ the checksum given by the server. This means the contents of the downloaded \
+ gem is different from what was uploaded to the server, and could be a potential security issue.
+
+ To resolve this issue:
+ 1. delete the downloaded gem located at: `#{spec.gem_dir}/#{spec.full_name}.gem`
+ 2. run `bundle install`
+
+ If you wish to continue installing the downloaded gem, and are certain it does not pose a \
+ security issue despite the mismatching checksum, do the following:
+ 1. run `bundle config set --local disable_checksum_validation true` to turn off checksum verification
+ 2. run `bundle install`
+
+ (More info: The expected SHA256 checksum was #{checksum.inspect}, but the \
+ checksum for the downloaded gem was #{digest.inspect}.)
+ MESSAGE
+ end
+ true
+ end
- if parent_st.world_writable? && !parent_st.sticky?
- raise InsecureInstallPathError.new(spec.full_name, dir)
+ def checksum_type(checksum)
+ case checksum.length
+ when 64 then :hexdigest!
+ when 44 then :base64digest!
+ else raise InstallError, "The given checksum for #{spec.full_name} (#{checksum.inspect}) is not a valid SHA256 hexdigest nor base64digest"
end
+ end
- begin
- FileUtils.remove_entry_secure(dir)
- rescue StandardError => e
- raise unless File.exist?(dir)
+ def hexdigest!(digest)
+ digest.hexdigest!
+ end
- raise DirectoryRemovalError.new(e, "Could not delete previous installation of `#{dir}`")
+ def base64digest!(digest)
+ if digest.respond_to?(:base64digest!)
+ digest.base64digest!
+ else
+ [digest.digest!].pack("m0")
end
end
end
diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb
index e77704aa0a..d8b7886af7 100644
--- a/lib/bundler/rubygems_integration.rb
+++ b/lib/bundler/rubygems_integration.rb
@@ -4,12 +4,17 @@ require "rubygems" unless defined?(Gem)
module Bundler
class RubygemsIntegration
- require "monitor"
+ if defined?(Gem::Ext::Builder::CHDIR_MONITOR)
+ EXT_LOCK = Gem::Ext::Builder::CHDIR_MONITOR
+ else
+ require "monitor"
- EXT_LOCK = Monitor.new
+ EXT_LOCK = Monitor.new
+ end
def initialize
@replaced_methods = {}
+ backport_ext_builder_monitor
end
def version
@@ -20,6 +25,10 @@ module Bundler
Gem::Requirement.new(req_str).satisfied_by?(version)
end
+ def supports_bundler_trampolining?
+ provides?(">= 3.3.0.a")
+ end
+
def build_args
require "rubygems/command"
Gem::Command.build_args
@@ -30,14 +39,22 @@ module Bundler
Gem::Command.build_args = args
end
- def set_target_rbconfig(path)
- Gem.set_target_rbconfig(path)
- end
-
def loaded_specs(name)
Gem.loaded_specs[name]
end
+ def add_to_load_path(paths)
+ return Gem.add_to_load_path(*paths) if Gem.respond_to?(:add_to_load_path)
+
+ if insert_index = Gem.load_path_insert_index
+ # Gem directories must come after -I and ENV['RUBYLIB']
+ $LOAD_PATH.insert(insert_index, *paths)
+ else
+ # We are probably testing in core, -I and RUBYLIB don't apply
+ $LOAD_PATH.unshift(*paths)
+ end
+ end
+
def mark_loaded(spec)
if spec.respond_to?(:activated=)
current = Gem.loaded_specs[spec.name]
@@ -48,7 +65,7 @@ module Bundler
end
def validate(spec)
- Bundler.ui.silence { spec.validate_for_resolution }
+ Bundler.ui.silence { spec.validate(false) }
rescue Gem::InvalidSpecificationException => e
error_message = "The gemspec at #{spec.loaded_from} is not valid. Please fix this gemspec.\n" \
"The validation error was '#{e.message}'\n"
@@ -57,6 +74,11 @@ module Bundler
nil
end
+ def set_installed_by_version(spec, installed_by_version = Gem::VERSION)
+ return unless spec.respond_to?(:installed_by_version=)
+ spec.installed_by_version = Gem::Version.create(installed_by_version)
+ end
+
def spec_missing_extensions?(spec, default = true)
return spec.missing_extensions? if spec.respond_to?(:missing_extensions?)
@@ -66,6 +88,14 @@ module Bundler
default
end
+ def spec_matches_for_glob(spec, glob)
+ return spec.matches_for_glob(glob) if spec.respond_to?(:matches_for_glob)
+
+ spec.load_paths.map do |lp|
+ Dir["#{lp}/#{glob}#{suffix_pattern}"]
+ end.flatten(1)
+ end
+
def stub_set_spec(stub, spec)
stub.instance_variable_set(:@spec, spec)
end
@@ -86,6 +116,16 @@ module Bundler
Gem::Util.inflate(obj)
end
+ def correct_for_windows_path(path)
+ if Gem::Util.respond_to?(:correct_for_windows_path)
+ Gem::Util.correct_for_windows_path(path)
+ elsif path[0].chr == "/" && path[1].chr =~ /[a-z]/i && path[2].chr == ":"
+ path[1..-1]
+ else
+ path
+ end
+ end
+
def gem_dir
Gem.dir
end
@@ -121,7 +161,7 @@ module Bundler
def spec_cache_dirs
@spec_cache_dirs ||= begin
dirs = gem_path.map {|dir| File.join(dir, "specifications") }
- dirs << Gem.spec_cache_dir
+ dirs << Gem.spec_cache_dir if Gem.respond_to?(:spec_cache_dir) # Not in RubyGems 2.0.3 or earlier
dirs.uniq.select {|dir| File.directory? dir }
end
end
@@ -144,15 +184,15 @@ module Bundler
end
def load_plugins
- Gem.load_plugins
+ Gem.load_plugins if Gem.respond_to?(:load_plugins)
end
- def load_plugin_files(plugin_files)
- Gem.load_plugin_files(plugin_files)
+ def load_plugin_files(files)
+ Gem.load_plugin_files(files) if Gem.respond_to?(:load_plugin_files)
end
def load_env_plugins
- Gem.load_env_plugins
+ Gem.load_env_plugins if Gem.respond_to?(:load_env_plugins)
end
def ui=(obj)
@@ -190,7 +230,8 @@ module Bundler
if Gem.respond_to?(:discover_gems_on_require=)
Gem.discover_gems_on_require = false
else
- [::Kernel.singleton_class, ::Kernel].each do |k|
+ kernel = (class << ::Kernel; self; end)
+ [kernel, ::Kernel].each do |k|
if k.private_method_defined?(:gem_original_require)
redefine_method(k, :require, k.instance_method(:gem_original_require))
end
@@ -199,11 +240,14 @@ module Bundler
end
def replace_gem(specs, specs_by_name)
+ reverse_rubygems_kernel_mixin
+
executables = nil
- [::Kernel.singleton_class, ::Kernel].each do |kernel_class|
+ kernel = (class << ::Kernel; self; end)
+ [kernel, ::Kernel].each do |kernel_class|
redefine_method(kernel_class, :gem) do |dep, *reqs|
- if executables&.include?(File.basename(caller_locations(1, 1).first.path))
+ if executables&.include?(File.basename(caller.first.split(":").first))
break
end
@@ -314,14 +358,6 @@ module Bundler
def replace_entrypoints(specs)
specs_by_name = add_default_gems_to(specs)
- reverse_rubygems_kernel_mixin
- begin
- # bundled_gems only provide with Ruby 3.3 or later
- require "bundled_gems"
- rescue LoadError
- else
- Gem::BUNDLED_GEMS.replace_require(specs) if Gem::BUNDLED_GEMS.respond_to?(:replace_require)
- end
replace_gem(specs, specs_by_name)
stub_rubygems(specs)
replace_bin_path(specs_by_name)
@@ -352,7 +388,11 @@ module Bundler
@replaced_methods.each do |(sym, klass), method|
redefine_method(klass, sym, method)
end
- post_reset_hooks.reject! {|proc| proc.binding.source_location[0] == __FILE__ }
+ if Binding.public_method_defined?(:source_location)
+ post_reset_hooks.reject! {|proc| proc.binding.source_location[0] == __FILE__ }
+ else
+ post_reset_hooks.reject! {|proc| proc.binding.eval("__FILE__") == __FILE__ }
+ end
@replaced_methods.clear
end
@@ -407,28 +447,30 @@ module Bundler
Gem::Specification.all = specs
end
- def fetch_specs(remote, name, fetcher)
+ def fetch_specs(remote, name)
require "rubygems/remote_fetcher"
path = remote.uri.to_s + "#{name}.#{Gem.marshal_version}.gz"
+ fetcher = gem_remote_fetcher
+ fetcher.headers = { "X-Gemfile-Source" => remote.original_uri.to_s } if remote.original_uri
string = fetcher.fetch_path(path)
- specs = Bundler.safe_load_marshal(string)
- raise MarshalError, "Specs #{name} from #{remote} is expected to be an Array but was unexpected class #{specs.class}" unless specs.is_a?(Array)
- specs
+ Bundler.safe_load_marshal(string)
rescue Gem::RemoteFetcher::FetchError
# it's okay for prerelease to fail
raise unless name == "prerelease_specs"
end
- def fetch_all_remote_specs(remote, gem_remote_fetcher)
- specs = fetch_specs(remote, "specs", gem_remote_fetcher)
- pres = fetch_specs(remote, "prerelease_specs", gem_remote_fetcher) || []
+ def fetch_all_remote_specs(remote)
+ specs = fetch_specs(remote, "specs")
+ pres = fetch_specs(remote, "prerelease_specs") || []
specs.concat(pres)
end
- def download_gem(spec, uri, cache_dir, fetcher)
+ def download_gem(spec, uri, cache_dir)
require "rubygems/remote_fetcher"
uri = Bundler.settings.mirror_for(uri)
+ fetcher = gem_remote_fetcher
+ fetcher.headers = { "X-Gemfile-Source" => spec.remote.original_uri.to_s } if spec.remote.original_uri
Bundler::Retry.new("download gem from #{uri}").attempts do
gem_file_name = spec.file_name
local_gem_path = File.join cache_dir, gem_file_name
@@ -436,6 +478,7 @@ module Bundler
begin
remote_gem_path = uri + "gems/#{gem_file_name}"
+ remote_gem_path = remote_gem_path.to_s if provides?("< 3.2.0.rc.1")
SharedHelpers.filesystem_access(local_gem_path) do
fetcher.cache_update_path remote_gem_path, local_gem_path
@@ -454,6 +497,12 @@ module Bundler
raise Bundler::HTTPError, "Could not download gem from #{uri} due to underlying error <#{e.message}>"
end
+ def gem_remote_fetcher
+ require "rubygems/remote_fetcher"
+ proxy = Gem.configuration[:http_proxy]
+ Gem::RemoteFetcher.new(proxy)
+ end
+
def build(spec, skip_validation = false)
require "rubygems/package"
Gem::Package.build(spec, skip_validation)
@@ -464,22 +513,27 @@ module Bundler
end
def all_specs
- SharedHelpers.major_deprecation 2, "Bundler.rubygems.all_specs has been removed in favor of Bundler.rubygems.installed_specs"
-
Gem::Specification.stubs.map do |stub|
StubSpecification.from_stub(stub)
end
end
- def installed_specs
- Gem::Specification.stubs.reject(&:default_gem?).map do |stub|
- StubSpecification.from_stub(stub)
- end
- end
+ def backport_ext_builder_monitor
+ # So we can avoid requiring "rubygems/ext" in its entirety
+ Gem.module_eval <<-RUBY, __FILE__, __LINE__ + 1
+ module Ext
+ end
+ RUBY
- def default_specs
- Gem::Specification.default_stubs.map do |stub|
- StubSpecification.from_stub(stub)
+ require "rubygems/ext/builder"
+
+ Gem::Ext::Builder.class_eval do
+ unless const_defined?(:CHDIR_MONITOR)
+ const_set(:CHDIR_MONITOR, EXT_LOCK)
+ end
+
+ remove_const(:CHDIR_MUTEX) if const_defined?(:CHDIR_MUTEX)
+ const_set(:CHDIR_MUTEX, const_get(:CHDIR_MONITOR))
end
end
@@ -491,8 +545,14 @@ module Bundler
Gem::Specification.stubs_for(name).map(&:to_spec)
end
- def default_stubs
- Gem::Specification.default_stubs("*.gemspec")
+ if Gem::Specification.respond_to?(:default_stubs)
+ def default_stubs
+ Gem::Specification.default_stubs("*.gemspec")
+ end
+ else
+ def default_stubs
+ Gem::Specification.send(:default_stubs, "*.gemspec")
+ end
end
end
diff --git a/lib/bundler/runtime.rb b/lib/bundler/runtime.rb
index 9792a81962..95cf78dd41 100644
--- a/lib/bundler/runtime.rb
+++ b/lib/bundler/runtime.rb
@@ -10,7 +10,7 @@ module Bundler
end
def setup(*groups)
- @definition.ensure_equivalent_gemfile_and_lockfile
+ @definition.ensure_equivalent_gemfile_and_lockfile if Bundler.frozen_bundle?
# Has to happen first
clean_load_path
@@ -28,11 +28,11 @@ module Bundler
spec.load_paths.reject {|path| $LOAD_PATH.include?(path) }
end.reverse.flatten
- Gem.add_to_load_path(*load_paths)
+ Bundler.rubygems.add_to_load_path(load_paths)
setup_manpath
- lock(preserve_unknown_sections: true)
+ lock(:preserve_unknown_sections => true)
self
end
@@ -41,17 +41,12 @@ module Bundler
groups.map!(&:to_sym)
groups = [:default] if groups.empty?
- dependencies = @definition.dependencies.select do |dep|
- # Select the dependency if it is in any of the requested groups, and
- # for the current platform, and matches the gem constraints.
- (dep.groups & groups).any? && dep.should_include?
- end
-
- Plugin.hook(Plugin::Events::GEM_BEFORE_REQUIRE_ALL, dependencies)
+ @definition.dependencies.each do |dep|
+ # Skip the dependency if it is not in any of the requested groups, or
+ # not for the current platform, or doesn't match the gem constraints.
+ next unless (dep.groups & groups).any? && dep.should_include?
- dependencies.each do |dep|
required_file = nil
- Plugin.hook(Plugin::Events::GEM_BEFORE_REQUIRE, dep)
begin
# Loop through all the specified autorequires for the
@@ -81,13 +76,7 @@ module Bundler
end
end
end
-
- Plugin.hook(Plugin::Events::GEM_AFTER_REQUIRE, dep)
end
-
- Plugin.hook(Plugin::Events::GEM_AFTER_REQUIRE_ALL, dependencies)
-
- dependencies
end
def self.definition_method(meth)
@@ -106,7 +95,7 @@ module Bundler
def lock(opts = {})
return if @definition.no_resolve_needed?
- @definition.lock(opts[:preserve_unknown_sections])
+ @definition.lock(Bundler.default_lockfile, opts[:preserve_unknown_sections])
end
alias_method :gems, :specs
@@ -139,6 +128,11 @@ module Bundler
spec.source.cache(spec, custom_path) if spec.source.respond_to?(:cache)
end
+ Dir[cache_path.join("*/.git")].each do |git_dir|
+ FileUtils.rm_rf(git_dir)
+ FileUtils.touch(File.expand_path("../.bundlecache", git_dir))
+ end
+
prune_cache(cache_path) unless Bundler.settings[:no_prune]
end
diff --git a/lib/bundler/self_manager.rb b/lib/bundler/self_manager.rb
index 6ab41b99f7..827f3f9222 100644
--- a/lib/bundler/self_manager.rb
+++ b/lib/bundler/self_manager.rb
@@ -9,23 +9,17 @@ module Bundler
def restart_with_locked_bundler_if_needed
return unless needs_switching? && installed?
- restart_with(restart_version)
+ restart_with(lockfile_version)
end
def install_locked_bundler_and_restart_with_it_if_needed
return unless needs_switching?
- if restart_version == lockfile_version
- Bundler.ui.info \
- "Bundler #{current_version} is running, but your lockfile was generated with #{lockfile_version}. " \
- "Installing Bundler #{lockfile_version} and restarting using that version."
- else
- Bundler.ui.info \
- "Bundler #{current_version} is running, but your configuration was #{restart_version}. " \
- "Installing Bundler #{restart_version} and restarting using that version."
- end
+ Bundler.ui.info \
+ "Bundler #{current_version} is running, but your lockfile was generated with #{lockfile_version}. " \
+ "Installing Bundler #{lockfile_version} and restarting using that version."
- install_and_restart_with(restart_version)
+ install_and_restart_with(lockfile_version)
end
def update_bundler_and_restart_with_it_if_needed(target)
@@ -70,23 +64,8 @@ module Bundler
configured_gem_home = ENV["GEM_HOME"]
configured_gem_path = ENV["GEM_PATH"]
- # Bundler specs need some stuff to be required before Bundler starts
- # running, for example, for faking the compact index API. However, these
- # flags are lost when we reexec to a different version of Bundler. In the
- # future, we may be able to properly reconstruct the original Ruby
- # invocation (see https://bugs.ruby-lang.org/issues/6648), but for now
- # there's no way to do it, so we need to be explicit about how to re-exec.
- # This may be a feature end users request at some point, but maybe by that
- # time, we have builtin tools to do. So for now, we use an undocumented
- # ENV variable only for our specs.
- bundler_spec_original_cmd = ENV["BUNDLER_SPEC_ORIGINAL_CMD"]
- if bundler_spec_original_cmd
- require "shellwords"
- cmd = [*Shellwords.shellsplit(bundler_spec_original_cmd), *ARGV]
- else
- cmd = [$PROGRAM_NAME, *ARGV]
- cmd.unshift(Gem.ruby) unless File.executable?($PROGRAM_NAME)
- end
+ cmd = [$PROGRAM_NAME, *ARGV]
+ cmd.unshift(Gem.ruby) unless File.executable?($PROGRAM_NAME)
Bundler.with_original_env do
Kernel.exec(
@@ -98,15 +77,14 @@ module Bundler
def needs_switching?
autoswitching_applies? &&
- Bundler.settings[:version] != "system" &&
- released?(restart_version) &&
- !running?(restart_version) &&
+ released?(lockfile_version) &&
+ !running?(lockfile_version) &&
!updating?
end
def autoswitching_applies?
ENV["BUNDLER_VERSION"].nil? &&
- ruby_can_restart_with_same_arguments? &&
+ Bundler.rubygems.supports_bundler_trampolining? &&
SharedHelpers.in_bundle? &&
lockfile_version
end
@@ -136,7 +114,7 @@ module Bundler
source = Bundler::Source::Rubygems.new("remotes" => "https://rubygems.org")
source.remote!
source.add_dependency_names("bundler")
- source.specs.select(&:matches_current_metadata?)
+ source.specs
end
end
@@ -166,10 +144,6 @@ module Bundler
!version.to_s.end_with?(".dev")
end
- def ruby_can_restart_with_same_arguments?
- $PROGRAM_NAME != "-e"
- end
-
def updating?
"update".start_with?(ARGV.first || " ") && ARGV[1..-1].any? {|a| a.start_with?("--bundler") }
end
@@ -177,7 +151,7 @@ module Bundler
def installed?
Bundler.configure
- Bundler.rubygems.find_bundler(restart_version.to_s)
+ Bundler.rubygems.find_bundler(lockfile_version.to_s)
end
def current_version
@@ -189,17 +163,6 @@ module Bundler
parsed_version = Bundler::LockfileParser.bundled_with
@lockfile_version = parsed_version ? Gem::Version.new(parsed_version) : nil
- rescue ArgumentError
- @lockfile_version = nil
- end
-
- def restart_version
- return @restart_version if defined?(@restart_version)
- # BUNDLE_VERSION=x.y.z
- @restart_version = Gem::Version.new(Bundler.settings[:version])
- rescue ArgumentError
- # BUNDLE_VERSION=lockfile
- @restart_version = lockfile_version
end
end
end
diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb
index 878747a53b..0af2236a45 100644
--- a/lib/bundler/settings.rb
+++ b/lib/bundler/settings.rb
@@ -7,6 +7,7 @@ module Bundler
autoload :Validator, File.expand_path("settings/validator", __dir__)
BOOL_KEYS = %w[
+ allow_deployment_source_credential_changes
allow_offline_install
auto_clean_without_path
auto_install
@@ -45,20 +46,6 @@ module Bundler
update_requires_all_flag
].freeze
- REMEMBERED_KEYS = %w[
- bin
- cache_all
- clean
- deployment
- frozen
- no_prune
- path
- shebang
- path.system
- without
- with
- ].freeze
-
NUMBER_KEYS = %w[
jobs
redirect
@@ -87,7 +74,6 @@ module Bundler
shebang
system_bindir
trust-policy
- version
].freeze
DEFAULT_CONFIG = {
@@ -97,39 +83,25 @@ module Bundler
"BUNDLE_REDIRECT" => 5,
"BUNDLE_RETRY" => 3,
"BUNDLE_TIMEOUT" => 10,
- "BUNDLE_VERSION" => "lockfile",
}.freeze
def initialize(root = nil)
@root = root
@local_config = load_config(local_config_file)
- @local_root = root || Pathname.new(".bundle").expand_path
-
- @env_config = ENV.to_h
- @env_config.select! {|key, _value| key.start_with?("BUNDLE_") }
- @env_config.delete("BUNDLE_")
-
+ @env_config = ENV.to_h.select {|key, _value| key =~ /\ABUNDLE_.+/ }
@global_config = load_config(global_config_file)
@temporary = {}
-
- @key_cache = {}
end
def [](name)
key = key_for(name)
-
- value = nil
- configs.each do |_, config|
- value = config[key]
- next if value.nil?
- break
- end
+ value = configs.values.map {|config| config[key] }.compact.first
converted_value(value, name)
end
def set_command_option(key, value)
- if !is_remembered(key) || Bundler.feature_flag.forget_cli_options?
+ if Bundler.feature_flag.forget_cli_options?
temporary(key => value)
value
else
@@ -143,7 +115,7 @@ module Bundler
end
def set_local(key, value)
- local_config_file = @local_root.join("config")
+ local_config_file || raise(GemfileNotFound, "Could not locate Gemfile")
set_key(key, value, @local_config, local_config_file)
end
@@ -166,22 +138,17 @@ module Bundler
end
def all
- keys = @temporary.keys.union(@global_config.keys, @local_config.keys, @env_config.keys)
+ keys = @temporary.keys | @global_config.keys | @local_config.keys | @env_config.keys
- keys.map! do |key|
- key = key.delete_prefix("BUNDLE_")
- key.gsub!("___", "-")
- key.gsub!("__", ".")
- key.downcase!
- key
- end.sort!
- keys
+ keys.map do |key|
+ key.sub(/^BUNDLE_/, "").gsub(/___/, "-").gsub(/__/, ".").downcase
+ end.sort
end
def local_overrides
repos = {}
all.each do |k|
- repos[k.delete_prefix("local.")] = self[k] if k.start_with?("local.")
+ repos[$'] = self[k] if k =~ /^local\./
end
repos
end
@@ -189,7 +156,7 @@ module Bundler
def mirror_for(uri)
if uri.is_a?(String)
require_relative "vendored_uri"
- uri = Gem::URI(uri)
+ uri = Bundler::URI(uri)
end
gem_mirrors.for(uri.to_s).uri
@@ -328,18 +295,18 @@ module Bundler
end
def key_for(key)
- @key_cache[key] ||= self.class.key_for(key)
+ self.class.key_for(key)
end
private
def configs
- @configs ||= {
- temporary: @temporary,
- local: @local_config,
- env: @env_config,
- global: @global_config,
- default: DEFAULT_CONFIG,
+ {
+ :temporary => @temporary,
+ :local => @local_config,
+ :env => @env_config,
+ :global => @global_config,
+ :default => DEFAULT_CONFIG,
}
end
@@ -360,20 +327,16 @@ module Bundler
end
def is_bool(name)
- name = self.class.key_to_s(name)
- BOOL_KEYS.include?(name) || BOOL_KEYS.include?(parent_setting_for(name))
+ BOOL_KEYS.include?(name.to_s) || BOOL_KEYS.include?(parent_setting_for(name.to_s))
end
def is_string(name)
- name = self.class.key_to_s(name)
- STRING_KEYS.include?(name) || name.start_with?("local.") || name.start_with?("mirror.") || name.start_with?("build.")
+ STRING_KEYS.include?(name.to_s) || name.to_s.start_with?("local.") || name.to_s.start_with?("mirror.") || name.to_s.start_with?("build.")
end
def to_bool(value)
case value
- when String
- value.match?(/\A(false|f|no|n|0|)\z/i) ? false : true
- when nil, false
+ when nil, /\A(false|f|no|n|0|)\z/i, false
false
else
true
@@ -381,15 +344,11 @@ module Bundler
end
def is_num(key)
- NUMBER_KEYS.include?(self.class.key_to_s(key))
+ NUMBER_KEYS.include?(key.to_s)
end
def is_array(key)
- ARRAY_KEYS.include?(self.class.key_to_s(key))
- end
-
- def is_remembered(key)
- REMEMBERED_KEYS.include?(self.class.key_to_s(key))
+ ARRAY_KEYS.include?(key.to_s)
end
def is_credential(key)
@@ -412,7 +371,7 @@ module Bundler
end
def set_key(raw_key, value, hash, file)
- raw_key = self.class.key_to_s(raw_key)
+ raw_key = raw_key.to_s
value = array_to_s(value) if is_array(raw_key)
key = key_for(raw_key)
@@ -427,13 +386,12 @@ module Bundler
return unless file
SharedHelpers.filesystem_access(file) do |p|
FileUtils.mkdir_p(p.dirname)
- p.open("w") {|f| f.write(serializer_class.dump(hash)) }
+ require_relative "yaml_serializer"
+ p.open("w") {|f| f.write(YAMLSerializer.dump(hash)) }
end
end
def converted_value(value, key)
- key = self.class.key_to_s(key)
-
if is_array(key)
to_array(value)
elsif value.nil?
@@ -491,57 +449,41 @@ module Bundler
SharedHelpers.filesystem_access(config_file, :read) do |file|
valid_file = file.exist? && !file.size.zero?
return {} unless valid_file
- serializer_class.load(file.read).inject({}) do |config, (k, v)|
- k = k.dup
- k << "/" if /https?:/i.match?(k) && !k.end_with?("/", "__#{FALLBACK_TIMEOUT_URI_OPTION.upcase}")
- k.gsub!(".", "__")
-
- unless k.start_with?("#")
- if k.include?("-")
- Bundler.ui.warn "Your #{file} config includes `#{k}`, which contains the dash character (`-`).\n" \
- "This is deprecated, because configuration through `ENV` should be possible, but `ENV` keys cannot include dashes.\n" \
- "Please edit #{file} and replace any dashes in configuration keys with a triple underscore (`___`)."
-
- # string hash keys are frozen
- k = k.gsub("-", "___")
- end
-
- config[k] = v
+ require_relative "yaml_serializer"
+ YAMLSerializer.load(file.read).inject({}) do |config, (k, v)|
+ new_k = k
+
+ if k.include?("-")
+ Bundler.ui.warn "Your #{file} config includes `#{k}`, which contains the dash character (`-`).\n" \
+ "This is deprecated, because configuration through `ENV` should be possible, but `ENV` keys cannot include dashes.\n" \
+ "Please edit #{file} and replace any dashes in configuration keys with a triple underscore (`___`)."
+
+ new_k = k.gsub("-", "___")
end
+ config[new_k] = v
config
end
end
end
- def serializer_class
- require "rubygems/yaml_serializer"
- Gem::YAMLSerializer
- rescue LoadError
- # TODO: Remove this when RubyGems 3.4 is EOL
- require_relative "yaml_serializer"
- YAMLSerializer
- end
-
- FALLBACK_TIMEOUT_URI_OPTION = "fallback_timeout"
+ PER_URI_OPTIONS = %w[
+ fallback_timeout
+ ].freeze
NORMALIZE_URI_OPTIONS_PATTERN =
/
\A
(\w+\.)? # optional prefix key
(https?.*?) # URI
- (\.#{FALLBACK_TIMEOUT_URI_OPTION})? # optional suffix key
+ (\.#{Regexp.union(PER_URI_OPTIONS)})? # optional suffix key
\z
- /ix
+ /ix.freeze
def self.key_for(key)
- key = key_to_s(key)
- key = normalize_uri(key) if key.start_with?("http", "mirror.http")
- key = key.gsub(".", "__")
- key.gsub!("-", "___")
- key.upcase!
-
- key.gsub(/\A([ #]*)/, '\1BUNDLE_')
+ key = normalize_uri(key).to_s if key.is_a?(String) && key.start_with?("http", "mirror.http")
+ key = key.to_s.gsub(".", "__").gsub("-", "___").upcase
+ "BUNDLE_#{key}"
end
# TODO: duplicates Rubygems#normalize_uri
@@ -555,40 +497,11 @@ module Bundler
end
uri = URINormalizer.normalize_suffix(uri)
require_relative "vendored_uri"
- uri = Gem::URI(uri)
+ uri = Bundler::URI(uri)
unless uri.absolute?
raise ArgumentError, format("Gem sources must be absolute. You provided '%s'.", uri)
end
"#{prefix}#{uri}#{suffix}"
end
-
- # This is a hot method, so avoid respond_to? checks on every invocation
- if :read.respond_to?(:name)
- def self.key_to_s(key)
- case key
- when String
- key
- when Symbol
- key.name
- when Gem::URI::HTTP
- key.to_s
- else
- raise ArgumentError, "Invalid key: #{key.inspect}"
- end
- end
- else
- def self.key_to_s(key)
- case key
- when String
- key
- when Symbol
- key.to_s
- when Gem::URI::HTTP
- key.to_s
- else
- raise ArgumentError, "Invalid key: #{key.inspect}"
- end
- end
- end
end
end
diff --git a/lib/bundler/setup.rb b/lib/bundler/setup.rb
index 5a0fd8e0e3..801fd5312a 100644
--- a/lib/bundler/setup.rb
+++ b/lib/bundler/setup.rb
@@ -5,12 +5,6 @@ require_relative "shared_helpers"
if Bundler::SharedHelpers.in_bundle?
require_relative "../bundler"
- # autoswitch to locked Bundler version if available
- Bundler.auto_switch
-
- # try to auto_install first before we get to the `Bundler.ui.silence`, so user knows what is happening
- Bundler.auto_install
-
if STDOUT.tty? || ENV["BUNDLER_FORCE_TTY"]
begin
Bundler.ui.silence { Bundler.setup }
@@ -18,10 +12,7 @@ if Bundler::SharedHelpers.in_bundle?
Bundler.ui.error e.message
Bundler.ui.warn e.backtrace.join("\n") if ENV["DEBUG"]
if e.is_a?(Bundler::GemNotFound)
- default_bundle = Gem.bin_path("bundler", "bundle")
- current_bundle = Bundler::SharedHelpers.bundle_bin_path
- suggested_bundle = default_bundle == current_bundle ? "bundle" : current_bundle
- suggested_cmd = "#{suggested_bundle} install"
+ suggested_cmd = "bundle install"
original_gemfile = Bundler.original_env["BUNDLE_GEMFILE"]
suggested_cmd += " --gemfile #{original_gemfile}" if original_gemfile
Bundler.ui.warn "Run `#{suggested_cmd}` to install missing gems."
diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb
index e55632b89f..d1d4e1d07a 100644
--- a/lib/bundler/shared_helpers.rb
+++ b/lib/bundler/shared_helpers.rb
@@ -1,27 +1,25 @@
# frozen_string_literal: true
+require "pathname"
+require "rbconfig"
+
require_relative "version"
+require_relative "constants"
require_relative "rubygems_integration"
require_relative "current_ruby"
-autoload :Pathname, "pathname"
-
module Bundler
- autoload :WINDOWS, File.expand_path("constants", __dir__)
- autoload :FREEBSD, File.expand_path("constants", __dir__)
- autoload :NULL, File.expand_path("constants", __dir__)
-
module SharedHelpers
def root
gemfile = find_gemfile
raise GemfileNotFound, "Could not locate Gemfile" unless gemfile
- Pathname.new(gemfile).expand_path.parent
+ Pathname.new(gemfile).tap {|x| x.untaint if RUBY_VERSION < "2.7" }.expand_path.parent
end
def default_gemfile
gemfile = find_gemfile
raise GemfileNotFound, "Could not locate Gemfile" unless gemfile
- Pathname.new(gemfile).expand_path
+ Pathname.new(gemfile).tap {|x| x.untaint if RUBY_VERSION < "2.7" }.expand_path
end
def default_lockfile
@@ -30,7 +28,7 @@ module Bundler
case gemfile.basename.to_s
when "gems.rb" then Pathname.new(gemfile.sub(/.rb$/, ".locked"))
else Pathname.new("#{gemfile}.lock")
- end
+ end.tap {|x| x.untaint if RUBY_VERSION < "2.7" }
end
def default_bundle_dir
@@ -102,7 +100,7 @@ module Bundler
#
# @see {Bundler::PermissionError}
def filesystem_access(path, action = :write, &block)
- yield(path.dup)
+ yield(path.dup.tap {|x| x.untaint if RUBY_VERSION < "2.7" })
rescue Errno::EACCES
raise PermissionError.new(path, action)
rescue Errno::EAGAIN
@@ -119,18 +117,16 @@ module Bundler
raise GenericSystemCallError.new(e, "There was an error accessing `#{path}`.")
end
- def major_deprecation(major_version, message, removed_message: nil, print_caller_location: false)
+ def major_deprecation(major_version, message, print_caller_location: false)
if print_caller_location
caller_location = caller_locations(2, 2).first
- suffix = " (called at #{caller_location.path}:#{caller_location.lineno})"
- message += suffix
- removed_message += suffix if removed_message
+ message = "#{message} (called at #{caller_location.path}:#{caller_location.lineno})"
end
bundler_major_version = Bundler.bundler_major_version
if bundler_major_version > major_version
require_relative "errors"
- raise DeprecatedError, "[REMOVED] #{removed_message || message}"
+ raise DeprecatedError, "[REMOVED] #{message}"
end
return unless bundler_major_version >= major_version && prints_major_deprecations?
@@ -197,40 +193,10 @@ module Bundler
Digest(name)
end
- def checksum_for_file(path, digest)
- return unless path.file?
- # This must use File.read instead of Digest.file().hexdigest
- # because we need to preserve \n line endings on windows when calculating
- # the checksum
- SharedHelpers.filesystem_access(path, :read) do
- File.open(path, "rb") do |f|
- digest = SharedHelpers.digest(digest).new
- buf = String.new(capacity: 16_384, encoding: Encoding::BINARY)
- digest << buf while f.read(16_384, buf)
- digest.hexdigest
- end
- end
- end
-
def write_to_gemfile(gemfile_path, contents)
filesystem_access(gemfile_path) {|g| File.open(g, "w") {|file| file.puts contents } }
end
- def relative_gemfile_path
- relative_path_to(Bundler.default_gemfile)
- end
-
- def relative_lockfile_path
- relative_path_to(Bundler.default_lockfile)
- end
-
- def relative_path_to(destination, from: pwd)
- Pathname.new(destination).relative_path_from(from).to_s
- rescue ArgumentError
- # on Windows, if source and destination are on different drivers, there's no relative path from one to the other
- destination
- end
-
private
def validate_bundle_path
@@ -269,7 +235,7 @@ module Bundler
def search_up(*names)
previous = nil
- current = File.expand_path(SharedHelpers.pwd)
+ current = File.expand_path(SharedHelpers.pwd).tap {|x| x.untaint if RUBY_VERSION < "2.7" }
until !File.directory?(current) || current == previous
if ENV["BUNDLER_SPEC_RUN"]
@@ -306,13 +272,6 @@ module Bundler
public :set_env
def set_bundle_variables
- Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", bundle_bin_path
- Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", find_gemfile.to_s
- Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION
- Bundler::SharedHelpers.set_env "BUNDLER_SETUP", File.expand_path("setup", __dir__)
- end
-
- def bundle_bin_path
# bundler exe & lib folders have same root folder, typical gem installation
exe_file = File.expand_path("../../exe/bundle", __dir__)
@@ -322,9 +281,11 @@ module Bundler
# bundler is a default gem, exe path is separate
exe_file = Bundler.rubygems.bin_path("bundler", "bundle", VERSION) unless File.exist?(exe_file)
- exe_file
+ Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", exe_file
+ Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", find_gemfile.to_s
+ Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION
+ Bundler::SharedHelpers.set_env "BUNDLER_SETUP", File.expand_path("setup", __dir__) unless RUBY_VERSION < "2.7"
end
- public :bundle_bin_path
def set_path
validate_bundle_path
@@ -336,7 +297,7 @@ module Bundler
def set_rubyopt
rubyopt = [ENV["RUBYOPT"]].compact
setup_require = "-r#{File.expand_path("setup", __dir__)}"
- return if !rubyopt.empty? && rubyopt.first.include?(setup_require)
+ return if !rubyopt.empty? && rubyopt.first =~ /#{setup_require}/
rubyopt.unshift setup_require
Bundler::SharedHelpers.set_env "RUBYOPT", rubyopt.join(" ")
end
diff --git a/lib/bundler/source.rb b/lib/bundler/source.rb
index 115dbd1378..f7f5ea7865 100644
--- a/lib/bundler/source.rb
+++ b/lib/bundler/source.rb
@@ -11,8 +11,6 @@ module Bundler
attr_accessor :dependency_names
- attr_reader :checksum_store
-
def unmet_deps
specs.unmet_dependency_names
end
diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb
index 3b934adbb2..adbce5fce4 100644
--- a/lib/bundler/source/git.rb
+++ b/lib/bundler/source/git.rb
@@ -11,7 +11,6 @@ module Bundler
def initialize(options)
@options = options
- @checksum_store = Checksum::Store.new
@glob = options["glob"] || DEFAULT_GLOB
@allow_cached = false
@@ -20,7 +19,7 @@ module Bundler
# Stringify options that could be set as symbols
%w[ref branch tag revision].each {|k| options[k] = options[k].to_s if options[k] }
- @uri = URINormalizer.normalize_suffix(options["uri"] || "", trailing_slash: false)
+ @uri = URINormalizer.normalize_suffix(options["uri"] || "", :trailing_slash => false)
@safe_uri = URICredentialsFilter.credential_filtered_uri(@uri)
@branch = options["branch"]
@ref = options["ref"] || options["branch"] || options["tag"]
@@ -32,20 +31,6 @@ module Bundler
@local = false
end
- def remote!
- return if @allow_remote
-
- @local_specs = nil
- @allow_remote = true
- end
-
- def cached!
- return if @allow_cached
-
- @local_specs = nil
- @allow_cached = true
- end
-
def self.from_lock(options)
new(options.merge("uri" => options.delete("remote")))
end
@@ -70,13 +55,13 @@ module Bundler
end
def hash
- [self.class, uri, ref, branch, name, glob, submodules].hash
+ [self.class, uri, ref, branch, name, version, glob, submodules].hash
end
def eql?(other)
other.is_a?(Git) && uri == other.uri && ref == other.ref &&
branch == other.branch && name == other.name &&
- glob == other.glob &&
+ version == other.version && glob == other.glob &&
submodules == other.submodules
end
@@ -164,8 +149,7 @@ module Bundler
"does not exist. Run `bundle config unset local.#{override_for(original_path)}` to remove the local override"
end
- @local = true
- set_paths!(path)
+ set_local!(path)
# Create a new git proxy without the cached revision
# so the Gemfile.lock always picks up the new revision.
@@ -188,13 +172,13 @@ module Bundler
end
def specs(*)
- set_up_app_cache!(app_cache_path) if use_app_cache?
+ set_local!(app_cache_path) if has_app_cache? && !local?
if requires_checkout? && !@copied
- FileUtils.rm_rf(app_cache_path) if use_app_cache? && git_proxy.not_a_repository?
-
fetch
- checkout
+ git_proxy.copy_to(install_path, submodules)
+ serialize_gemspecs_in(install_path)
+ @copied = true
end
local_specs
@@ -207,10 +191,13 @@ module Bundler
print_using_message "Using #{version_message(spec, options[:previous_spec])} from #{self}"
if (requires_checkout? && !@copied) || force
- checkout
+ Bundler.ui.debug " * Checking out revision: #{ref}"
+ git_proxy.copy_to(install_path, submodules)
+ serialize_gemspecs_in(install_path)
+ @copied = true
end
- generate_bin_options = { disable_extensions: !Bundler.rubygems.spec_missing_extensions?(spec), build_args: options[:build_args] }
+ generate_bin_options = { :disable_extensions => !Bundler.rubygems.spec_missing_extensions?(spec), :build_args => options[:build_args] }
generate_bin(spec, generate_bin_options)
requires_checkout? ? spec.post_install_message : nil
@@ -219,14 +206,12 @@ module Bundler
def cache(spec, custom_path = nil)
app_cache_path = app_cache_path(custom_path)
return unless Bundler.feature_flag.cache_all?
- return if install_path == app_cache_path
- return if cache_path == app_cache_path
+ return if path == app_cache_path
cached!
FileUtils.rm_rf(app_cache_path)
git_proxy.checkout if requires_checkout?
- FileUtils.cp_r("#{cache_path}/.", app_cache_path)
- FileUtils.touch(app_cache_path.join(".bundlecache"))
- FileUtils.rm_rf(Dir.glob(app_cache_path.join("hooks/*.sample")))
+ git_proxy.copy_to(app_cache_path, @submodules)
+ serialize_gemspecs_in(app_cache_path)
end
def load_spec_files
@@ -270,13 +255,6 @@ module Bundler
private
- def checkout
- Bundler.ui.debug " * Checking out revision: #{ref}"
- git_proxy.copy_to(install_path, submodules)
- serialize_gemspecs_in(install_path)
- @copied = true
- end
-
def humanized_ref
if local?
path
@@ -299,40 +277,22 @@ module Bundler
# The gemspecs we cache should already be evaluated.
spec = Bundler.load_gemspec(spec_path)
next unless spec
- spec.installed_by_version = Gem::VERSION
+ Bundler.rubygems.set_installed_by_version(spec)
Bundler.rubygems.validate(spec)
File.open(spec_path, "wb") {|file| file.write(spec.to_ruby) }
end
end
- def set_paths!(path)
- set_cache_path!(path)
- set_install_path!(path)
- end
-
- def set_cache_path!(path)
- @git_proxy = nil
- @cache_path = path
- end
-
- def set_install_path!(path)
- @local_specs = nil
- @install_path = path
- end
-
- def set_up_app_cache!(path)
- FileUtils.mkdir_p(path.join("refs"))
- set_cache_path!(path)
+ def set_local!(path)
+ @local = true
+ @local_specs = @git_proxy = nil
+ @cache_path = @install_path = path
end
def has_app_cache?
cached_revision && super
end
- def use_app_cache?
- has_app_cache? && !local?
- end
-
def requires_checkout?
allow_git_ops? && !local? && !cached_revision_checked_out?
end
@@ -365,7 +325,7 @@ module Bundler
if %r{^\w+://(\w+@)?}.match?(uri)
# Downcase the domain component of the URI
# and strip off a trailing slash, if one is present
- input = Gem::URI.parse(uri).normalize.to_s.sub(%r{/$}, "")
+ input = Bundler::URI.parse(uri).normalize.to_s.sub(%r{/$}, "")
else
# If there is no URI scheme, assume it is an ssh/git URI
input = uri
@@ -398,12 +358,9 @@ module Bundler
def validate_spec(_spec); end
def load_gemspec(file)
- dirname = Pathname.new(file).dirname
- SharedHelpers.chdir(dirname.to_s) do
- stub = Gem::StubSpecification.gemspec_stub(file, install_path.parent, install_path.parent)
- stub.full_gem_path = dirname.expand_path(root).to_s
- StubSpecification.from_stub(stub)
- end
+ stub = Gem::StubSpecification.gemspec_stub(file, install_path.parent, install_path.parent)
+ stub.full_gem_path = Pathname.new(file).dirname.expand_path(root).to_s.tap {|x| x.untaint if RUBY_VERSION < "2.7" }
+ StubSpecification.from_stub(stub)
end
def git_scope
diff --git a/lib/bundler/source/git/git_proxy.rb b/lib/bundler/source/git/git_proxy.rb
index 744235bc04..fdb738e52e 100644
--- a/lib/bundler/source/git/git_proxy.rb
+++ b/lib/bundler/source/git/git_proxy.rb
@@ -43,13 +43,6 @@ module Bundler
end
end
- class AmbiguousGitReference < GitError
- def initialize(options)
- msg = "Specification of branch or ref with tag is ambiguous. You specified #{options.inspect}"
- super msg
- end
- end
-
# The GitProxy is responsible to interact with git repositories.
# All actions required by the Git source is encapsulated in this
# object.
@@ -60,15 +53,10 @@ module Bundler
def initialize(path, uri, options = {}, revision = nil, git = nil)
@path = path
@uri = uri
- @tag = options["tag"]
@branch = options["branch"]
+ @tag = options["tag"]
@ref = options["ref"]
- if @tag
- raise AmbiguousGitReference.new(options) if @branch || @ref
- @explicit_ref = @tag
- else
- @explicit_ref = @ref || @branch
- end
+ @explicit_ref = branch || tag || ref
@revision = revision
@git = git
@commit_ref = nil
@@ -80,20 +68,14 @@ module Bundler
def current_branch
@current_branch ||= with_path do
- git_local("rev-parse", "--abbrev-ref", "HEAD", dir: path).strip
+ git_local("rev-parse", "--abbrev-ref", "HEAD", :dir => path).strip
end
end
- def not_a_repository?
- _, status = git_null("rev-parse", "--resolve-git-dir", path.to_s, dir: path)
-
- !status.success?
- end
-
def contains?(commit)
allowed_with_path do
- result, status = git_null("branch", "--contains", commit, dir: path)
- status.success? && result.match?(/^\* (.*)$/)
+ result, status = git_null("branch", "--contains", commit, :dir => path)
+ status.success? && result =~ /^\* (.*)$/
end
end
@@ -136,20 +118,15 @@ module Bundler
end
end
- ref = @commit_ref || (locked_to_full_sha? && @revision)
- if ref
- git "config", "uploadpack.allowAnySHA1InWant", "true", dir: path.to_s if @commit_ref.nil? && needs_allow_any_sha1_in_want?
+ git "fetch", "--force", "--quiet", *extra_fetch_args, :dir => destination if @commit_ref
- git "fetch", "--force", "--quiet", *extra_fetch_args(ref), dir: destination
- end
-
- git "reset", "--hard", @revision, dir: destination
+ git "reset", "--hard", @revision, :dir => destination
if submodules
- git_retry "submodule", "update", "--init", "--recursive", dir: destination
+ git_retry "submodule", "update", "--init", "--recursive", :dir => destination
elsif Gem::Version.create(version) >= Gem::Version.create("2.9.0")
inner_command = "git -C $toplevel submodule deinit --force $sm_path"
- git_retry "submodule", "foreach", "--quiet", inner_command, dir: destination
+ git_retry "submodule", "foreach", "--quiet", inner_command, :dir => destination
end
end
@@ -185,17 +162,10 @@ module Bundler
_, err, status = capture(command, nil)
return extra_ref if status.success?
- if err.include?("Could not find remote branch")
+ if err.include?("Could not find remote branch") || # git up to 2.49
+ err.include?("Remote branch #{branch_option} not found") # git 2.49 or higher
raise MissingGitRevisionError.new(command_with_no_credentials, nil, explicit_ref, credential_filtered_uri)
else
- idx = command.index("--depth")
- if idx
- command.delete_at(idx)
- command.delete_at(idx)
- command_with_no_credentials = check_allowed(command)
-
- err += "Retrying without --depth argument."
- end
raise GitCommandError.new(command_with_no_credentials, path, err)
end
end
@@ -262,50 +232,42 @@ module Bundler
end
def not_pinned?
- branch || tag || ref.nil?
+ branch_option || ref.nil?
end
def pinned_to_full_sha?
- full_sha_revision?(ref)
- end
-
- def locked_to_full_sha?
- full_sha_revision?(@revision)
- end
-
- def full_sha_revision?(ref)
- ref&.match?(/\A\h{40}\z/)
+ ref =~ /\A\h{40}\z/
end
def git_null(*command, dir: nil)
check_allowed(command)
- capture(command, dir, ignore_err: true)
+ capture(command, dir, :ignore_err => true)
end
def git_retry(*command, dir: nil)
command_with_no_credentials = check_allowed(command)
Bundler::Retry.new("`#{command_with_no_credentials}` at #{dir || SharedHelpers.pwd}").attempts do
- git(*command, dir: dir)
+ git(*command, :dir => dir)
end
end
def git(*command, dir: nil)
- run_command(*command, dir: dir) do |unredacted_command|
+ run_command(*command, :dir => dir) do |unredacted_command|
check_allowed(unredacted_command)
end
end
def git_local(*command, dir: nil)
- run_command(*command, dir: dir) do |unredacted_command|
+ run_command(*command, :dir => dir) do |unredacted_command|
redact_and_check_presence(unredacted_command)
end
end
def has_revision_cached?
return unless @revision && path.exist?
- git("cat-file", "-e", @revision, dir: path)
+ git("cat-file", "-e", @revision, :dir => path)
true
rescue GitError
false
@@ -328,16 +290,18 @@ module Bundler
end
def verify(reference)
- git("rev-parse", "--verify", reference, dir: path).strip
+ git("rev-parse", "--verify", reference, :dir => path).strip
end
# Adds credentials to the URI
def configured_uri
if /https?:/.match?(uri)
- remote = Gem::URI(uri)
+ remote = Bundler::URI(uri)
config_auth = Bundler.settings[remote.to_s] || Bundler.settings[remote.host]
remote.userinfo ||= config_auth
remote.to_s
+ elsif File.exist?(uri)
+ "file://#{uri}"
else
uri.to_s
end
@@ -410,7 +374,7 @@ module Bundler
if Bundler.feature_flag.bundler_3_mode? || supports_minus_c?
["git", "-C", dir.to_s, *cmd]
else
- ["git", *cmd, { chdir: dir.to_s }]
+ ["git", *cmd, { :chdir => dir.to_s }]
end
end
@@ -426,7 +390,7 @@ module Bundler
# anyways.
return args if @revision
- args += ["--branch", branch || tag] if branch || tag
+ args += ["--branch", branch_option] if branch_option
args
end
@@ -436,12 +400,16 @@ module Bundler
["--depth", depth.to_s]
end
- def extra_fetch_args(ref)
+ def extra_fetch_args
extra_args = [path.to_s, *depth_args]
- extra_args.push(ref)
+ extra_args.push(@commit_ref)
extra_args
end
+ def branch_option
+ branch || tag
+ end
+
def full_clone?
depth.nil?
end
@@ -450,10 +418,6 @@ module Bundler
@supports_minus_c ||= Gem::Version.new(version) >= Gem::Version.new("1.8.5")
end
- def needs_allow_any_sha1_in_want?
- @needs_allow_any_sha1_in_want ||= Gem::Version.new(version) <= Gem::Version.new("2.13.7")
- end
-
def supports_fetching_unreachable_refs?
@supports_fetching_unreachable_refs ||= Gem::Version.new(version) >= Gem::Version.new("2.5.0")
end
diff --git a/lib/bundler/source/metadata.rb b/lib/bundler/source/metadata.rb
index 6b05e17727..593da6d1a7 100644
--- a/lib/bundler/source/metadata.rb
+++ b/lib/bundler/source/metadata.rb
@@ -5,29 +5,27 @@ module Bundler
class Metadata < Source
def specs
@specs ||= Index.build do |idx|
- idx << Gem::Specification.new("Ruby\0", Bundler::RubyVersion.system.gem_version)
+ idx << Gem::Specification.new("Ruby\0", Gem.ruby_version)
idx << Gem::Specification.new("RubyGems\0", Gem::VERSION) do |s|
s.required_rubygems_version = Gem::Requirement.default
end
- if local_spec = Gem.loaded_specs["bundler"]
- raise CorruptBundlerInstallError.new(local_spec) if local_spec.version.to_s != Bundler::VERSION
+ idx << Gem::Specification.new do |s|
+ s.name = "bundler"
+ s.version = VERSION
+ s.license = "MIT"
+ s.platform = Gem::Platform::RUBY
+ s.authors = ["bundler team"]
+ s.bindir = "exe"
+ s.homepage = "https://bundler.io"
+ s.summary = "The best way to manage your application's dependencies"
+ s.executables = %w[bundle]
+ # can't point to the actual gemspec or else the require paths will be wrong
+ s.loaded_from = __dir__
+ end
+ if local_spec = Bundler.rubygems.find_bundler(VERSION)
idx << local_spec
- else
- idx << Gem::Specification.new do |s|
- s.name = "bundler"
- s.version = VERSION
- s.license = "MIT"
- s.platform = Gem::Platform::RUBY
- s.authors = ["bundler team"]
- s.bindir = "exe"
- s.homepage = "https://bundler.io"
- s.summary = "The best way to manage your application's dependencies"
- s.executables = %w[bundle]
- # can't point to the actual gemspec or else the require paths will be wrong
- s.loaded_from = __dir__
- end
end
idx.each {|s| s.source = self }
diff --git a/lib/bundler/source/path.rb b/lib/bundler/source/path.rb
index d4c530e922..bdfcf8274a 100644
--- a/lib/bundler/source/path.rb
+++ b/lib/bundler/source/path.rb
@@ -14,10 +14,12 @@ module Bundler
DEFAULT_GLOB = "{,*,*/*}.gemspec"
def initialize(options)
- @checksum_store = Checksum::Store.new
@options = options.dup
@glob = options["glob"] || DEFAULT_GLOB
+ @allow_cached = false
+ @allow_remote = false
+
@root_path = options["root_path"] || root
if options["path"]
@@ -38,6 +40,16 @@ module Bundler
@original_path = @path
end
+ def remote!
+ @local_specs = nil
+ @allow_remote = true
+ end
+
+ def cached!
+ @local_specs = nil
+ @allow_cached = true
+ end
+
def self.from_lock(options)
new(options.merge("path" => options.delete("remote")))
end
@@ -53,8 +65,6 @@ module Bundler
"source at `#{@path}`"
end
- alias_method :to_gemfile, :path
-
def hash
[self.class, expanded_path, version].hash
end
@@ -75,7 +85,7 @@ module Bundler
using_message = "Using #{version_message(spec, options[:previous_spec])} from #{self}"
using_message += " and installing its executables" unless spec.executables.empty?
print_using_message using_message
- generate_bin(spec, disable_extensions: true)
+ generate_bin(spec, :disable_extensions => true)
nil # no post-install message
end
@@ -150,7 +160,7 @@ module Bundler
def load_gemspec(file)
return unless spec = Bundler.load_gemspec(file)
- spec.installed_by_version = Gem::VERSION
+ Bundler.rubygems.set_installed_by_version(spec)
spec
end
@@ -215,7 +225,7 @@ module Bundler
# Some gem authors put absolute paths in their gemspec
# and we have to save them from themselves
spec.files = spec.files.map do |path|
- next path unless /\A#{Pathname::SEPARATOR_PAT}/o.match?(path)
+ next path unless /\A#{Pathname::SEPARATOR_PAT}/.match?(path)
next if File.directory?(path)
begin
Pathname.new(path).relative_path_from(gem_dir).to_s
@@ -226,10 +236,10 @@ module Bundler
installer = Path::Installer.new(
spec,
- env_shebang: false,
- disable_extensions: options[:disable_extensions],
- build_args: options[:build_args],
- bundler_extension_cache_path: extension_cache_path(spec)
+ :env_shebang => false,
+ :disable_extensions => options[:disable_extensions],
+ :build_args => options[:build_args],
+ :bundler_extension_cache_path => extension_cache_path(spec)
)
installer.post_install
rescue Gem::InvalidSpecificationException => e
diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb
index 3b6ef8bd58..af57acbbc2 100644
--- a/lib/bundler/source/rubygems.rb
+++ b/lib/bundler/source/rubygems.rb
@@ -10,7 +10,7 @@ module Bundler
# Ask for X gems per API request
API_REQUEST_SIZE = 50
- attr_accessor :remotes
+ attr_reader :remotes
def initialize(options = {})
@options = options
@@ -19,11 +19,8 @@ module Bundler
@allow_remote = false
@allow_cached = false
@allow_local = options["allow_local"] || false
- @checksum_store = Checksum::Store.new
Array(options["remotes"]).reverse_each {|r| add_remote(r) }
-
- @lockfile_remotes = @remotes if options["from_lockfile"]
end
def caches
@@ -52,11 +49,10 @@ module Bundler
end
def cached!
- return unless File.exist?(cache_path)
-
return if @allow_cached
@specs = nil
+ @allow_local = true
@allow_cached = true
end
@@ -92,14 +88,13 @@ module Bundler
end
def self.from_lock(options)
- options["remotes"] = Array(options.delete("remote")).reverse
- new(options.merge("from_lockfile" => true))
+ new(options)
end
def to_lock
out = String.new("GEM\n")
- lockfile_remotes.reverse_each do |remote|
- out << " remote: #{remote}\n"
+ remotes.reverse_each do |remote|
+ out << " remote: #{suppress_configured_credentials remote}\n"
end
out << " specs:\n"
end
@@ -133,22 +128,25 @@ module Bundler
def specs
@specs ||= begin
# remote_specs usually generates a way larger Index than the other
- # sources, and large_idx.merge! small_idx is way faster than
- # small_idx.merge! large_idx.
- index = @allow_remote ? remote_specs.dup : Index.new
- index.merge!(cached_specs) if @allow_cached
- index.merge!(installed_specs) if @allow_local
-
- # complete with default specs, only if not already available in the
- # index through remote, cached, or installed specs
- index.use(default_specs) if @allow_local
-
- index
+ # sources, and large_idx.use small_idx is way faster than
+ # small_idx.use large_idx.
+ idx = @allow_remote ? remote_specs.dup : Index.new
+ idx.use(cached_specs, :override_dupes) if @allow_cached || @allow_remote
+ idx.use(installed_specs, :override_dupes) if @allow_local
+ idx
end
end
def install(spec, options = {})
- if (spec.default_gem? && !cached_built_in_gem(spec, local: options[:local])) || (installed?(spec) && !options[:force])
+ force = options[:force]
+ ensure_builtin_gems_cached = options[:ensure_builtin_gems_cached]
+
+ if ensure_builtin_gems_cached && spec.default_gem? && !cached_path(spec)
+ cached_built_in_gem(spec) unless spec.remote
+ force = true
+ end
+
+ if installed?(spec) && !force
print_using_message "Using #{version_message(spec, options[:previous_spec])}"
return nil # no post-install message
end
@@ -171,14 +169,15 @@ module Bundler
installer = Bundler::RubyGemsGemInstaller.at(
path,
- security_policy: Bundler.rubygems.security_policies[Bundler.settings["trust-policy"]],
- install_dir: install_path.to_s,
- bin_dir: bin_path.to_s,
- ignore_dependencies: true,
- wrappers: true,
- env_shebang: true,
- build_args: options[:build_args],
- bundler_extension_cache_path: extension_cache_path(spec)
+ :security_policy => Bundler.rubygems.security_policies[Bundler.settings["trust-policy"]],
+ :install_dir => install_path.to_s,
+ :bin_dir => bin_path.to_s,
+ :ignore_dependencies => true,
+ :wrappers => true,
+ :env_shebang => true,
+ :build_args => options[:build_args],
+ :bundler_expected_checksum => spec.respond_to?(:checksum) && spec.checksum,
+ :bundler_extension_cache_path => extension_cache_path(spec)
)
if spec.remote
@@ -196,8 +195,6 @@ module Bundler
spec.__swap__(s)
end
- spec.source.checksum_store.register(spec, installer.gem_checksum)
-
message = "Installing #{version_message(spec, options[:previous_spec])}"
message += " with native extensions" if spec.extensions.any?
Bundler.ui.confirm message
@@ -206,7 +203,6 @@ module Bundler
spec.full_gem_path = installed_spec.full_gem_path
spec.loaded_from = installed_spec.loaded_from
- spec.base_dir = installed_spec.base_dir
spec.post_install_message
end
@@ -222,13 +218,12 @@ module Bundler
raise InstallError, e.message
end
- def cached_built_in_gem(spec, local: false)
- cached_path = cached_gem(spec)
- if cached_path.nil? && !local
+ def cached_built_in_gem(spec)
+ cached_path = cached_path(spec)
+ if cached_path.nil?
remote_spec = remote_specs.search(spec).first
if remote_spec
cached_path = fetch_gem(remote_spec)
- spec.remote = remote_spec.remote
else
Bundler.ui.warn "#{spec.full_name} is built in to Ruby, and can't be cached because your Gemfile doesn't have any sources that contain it."
end
@@ -242,7 +237,7 @@ module Bundler
end
def spec_names
- if dependency_api_available?
+ if @allow_remote && dependency_api_available?
remote_specs.spec_names
else
[]
@@ -250,25 +245,22 @@ module Bundler
end
def unmet_deps
- if dependency_api_available?
+ if @allow_remote && dependency_api_available?
remote_specs.unmet_dependency_names
else
[]
end
end
- def remote_fetchers
- @remote_fetchers ||= remotes.to_h do |uri|
- remote = Source::Rubygems::Remote.new(uri)
- [remote, Bundler::Fetcher.new(remote)]
- end.freeze
- end
-
def fetchers
- @fetchers ||= remote_fetchers.values.freeze
+ @fetchers ||= remotes.map do |uri|
+ remote = Source::Rubygems::Remote.new(uri)
+ Bundler::Fetcher.new(remote)
+ end
end
def double_check_for(unmet_dependency_names)
+ return unless @allow_remote
return unless dependency_api_available?
unmet_dependency_names = unmet_dependency_names.call
@@ -283,9 +275,7 @@ module Bundler
Bundler.ui.debug "Double checking for #{unmet_dependency_names || "all specs (due to the size of the request)"} in #{self}"
- fetch_names(api_fetchers, unmet_dependency_names, remote_specs)
-
- specs.use remote_specs
+ fetch_names(api_fetchers, unmet_dependency_names, specs, false)
end
def dependency_names_to_double_check
@@ -314,7 +304,11 @@ module Bundler
end
def credless_remotes
- remotes.map(&method(:remove_auth))
+ if Bundler.settings[:allow_deployment_source_credential_changes]
+ remotes.map(&method(:remove_auth))
+ else
+ remotes.map(&method(:suppress_configured_credentials))
+ end
end
def remotes_for_spec(spec)
@@ -325,6 +319,14 @@ module Bundler
end
def cached_gem(spec)
+ if spec.default_gem?
+ cached_built_in_gem(spec)
+ else
+ cached_path(spec)
+ end
+ end
+
+ def cached_path(spec)
global_cache_path = download_cache_path(spec)
caches << global_cache_path if global_cache_path
@@ -339,12 +341,21 @@ module Bundler
def normalize_uri(uri)
uri = URINormalizer.normalize_suffix(uri.to_s)
require_relative "../vendored_uri"
- uri = Gem::URI(uri)
+ uri = Bundler::URI(uri)
raise ArgumentError, "The source must be an absolute URI. For example:\n" \
- "source 'https://rubygems.org'" if !uri.absolute? || (uri.is_a?(Gem::URI::HTTP) && uri.host.nil?)
+ "source 'https://rubygems.org'" if !uri.absolute? || (uri.is_a?(Bundler::URI::HTTP) && uri.host.nil?)
uri
end
+ def suppress_configured_credentials(remote)
+ remote_nouser = remove_auth(remote)
+ if remote.userinfo && remote.userinfo == Bundler.settings[remote_nouser]
+ remote_nouser
+ else
+ remote
+ end
+ end
+
def remove_auth(remote)
if remote.user || remote.password
remote.dup.tap {|uri| uri.user = uri.password = nil }.to_s
@@ -355,7 +366,7 @@ module Bundler
def installed_specs
@installed_specs ||= Index.build do |idx|
- Bundler.rubygems.installed_specs.reverse_each do |spec|
+ Bundler.rubygems.all_specs.reverse_each do |spec|
spec.source = self
if Bundler.rubygems.spec_missing_extensions?(spec, false)
Bundler.ui.debug "Source #{self} is ignoring #{spec} because it is missing extensions"
@@ -366,18 +377,9 @@ module Bundler
end
end
- def default_specs
- @default_specs ||= Index.build do |idx|
- Bundler.rubygems.default_specs.each do |spec|
- spec.source = self
- idx << spec
- end
- end
- end
-
def cached_specs
@cached_specs ||= begin
- idx = Index.new
+ idx = @allow_local ? installed_specs.dup : Index.new
Dir["#{cache_path}/*.gem"].each do |gemfile|
s ||= Bundler.rubygems.spec_from_gem(gemfile)
@@ -390,30 +392,35 @@ module Bundler
end
def api_fetchers
- fetchers.select(&:api_fetcher?)
+ fetchers.select {|f| f.use_api && f.fetchers.first.api_fetcher? }
end
def remote_specs
@remote_specs ||= Index.build do |idx|
index_fetchers = fetchers - api_fetchers
- if index_fetchers.empty?
- fetch_names(api_fetchers, dependency_names, idx)
- else
- fetch_names(fetchers, nil, idx)
- end
+ # gather lists from non-api sites
+ fetch_names(index_fetchers, nil, idx, false)
+
+ # legacy multi-remote sources need special logic to figure out
+ # dependency names and that logic can be very costly if one remote
+ # uses the dependency API but others don't. So use full indexes
+ # consistently in that particular case.
+ allow_api = !multiple_remotes?
+
+ fetch_names(api_fetchers, allow_api && dependency_names, idx, false)
end
end
- def fetch_names(fetchers, dependency_names, index)
+ def fetch_names(fetchers, dependency_names, index, override_dupes)
fetchers.each do |f|
if dependency_names
Bundler.ui.info "Fetching gem metadata from #{URICredentialsFilter.credential_filtered_uri(f.uri)}", Bundler.ui.debug?
- index.use f.specs_with_retry(dependency_names, self)
+ index.use f.specs_with_retry(dependency_names, self), override_dupes
Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over
else
Bundler.ui.info "Fetching source index from #{URICredentialsFilter.credential_filtered_uri(f.uri)}"
- index.use f.specs_with_retry(nil, self)
+ index.use f.specs_with_retry(nil, self), override_dupes
end
end
end
@@ -459,10 +466,6 @@ module Bundler
private
- def lockfile_remotes
- @lockfile_remotes || credless_remotes
- end
-
# Checks if the requested spec exists in the global cache. If it does,
# we copy it to the download path, and if it does not, we download it.
#
@@ -478,8 +481,7 @@ module Bundler
def download_gem(spec, download_cache_path, previous_spec = nil)
uri = spec.remote.uri
Bundler.ui.confirm("Fetching #{version_message(spec, previous_spec)}")
- gem_remote_fetcher = remote_fetchers.fetch(spec.remote).gem_remote_fetcher
- Bundler.rubygems.download_gem(spec, uri, download_cache_path, gem_remote_fetcher)
+ Bundler.rubygems.download_gem(spec, uri, download_cache_path)
end
# Returns the global cache path of the calling Rubygems::Source object.
diff --git a/lib/bundler/source/rubygems/remote.rb b/lib/bundler/source/rubygems/remote.rb
index 9c5c06de24..82c850ffbb 100644
--- a/lib/bundler/source/rubygems/remote.rb
+++ b/lib/bundler/source/rubygems/remote.rb
@@ -48,7 +48,7 @@ module Bundler
end
uri
- rescue Gem::URI::InvalidComponentError
+ rescue Bundler::URI::InvalidComponentError
error_message = "Please CGI escape your usernames and passwords before " \
"setting them for authentication."
raise HTTPError.new(error_message)
diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb
index 5f9dd68f17..4419695b7f 100644
--- a/lib/bundler/source_list.rb
+++ b/lib/bundler/source_list.rb
@@ -22,7 +22,6 @@ module Bundler
@metadata_source = Source::Metadata.new
@merged_gem_lockfile_sections = false
- @local_mode = true
end
def merged_gem_lockfile_sections?
@@ -74,10 +73,6 @@ module Bundler
global_rubygems_source
end
- def local_mode?
- @local_mode
- end
-
def default_source
global_path_source || global_rubygems_source
end
@@ -145,17 +140,11 @@ module Bundler
all_sources.each(&:local_only!)
end
- def local!
- all_sources.each(&:local!)
- end
-
def cached!
all_sources.each(&:cached!)
end
def remote!
- @local_mode = false
-
all_sources.each(&:remote!)
end
@@ -168,11 +157,7 @@ module Bundler
end
def map_sources(replacement_sources)
- rubygems = @rubygems_sources.map do |source|
- replace_rubygems_source(replacement_sources, source) || source
- end
-
- git, plugin = [@git_sources, @plugin_sources].map do |sources|
+ rubygems, git, plugin = [@rubygems_sources, @git_sources, @plugin_sources].map do |sources|
sources.map do |source|
replacement_sources.find {|s| s == source } || source
end
@@ -186,22 +171,13 @@ module Bundler
end
def global_replacement_source(replacement_sources)
- replacement_source = replace_rubygems_source(replacement_sources, global_rubygems_source)
+ replacement_source = replacement_sources.find {|s| s == global_rubygems_source }
return global_rubygems_source unless replacement_source
replacement_source.local!
replacement_source
end
- def replace_rubygems_source(replacement_sources, gemfile_source)
- replacement_source = replacement_sources.find {|s| s == gemfile_source }
- return unless replacement_source
-
- # locked sources never include credentials so always prefer remotes from the gemfile
- replacement_source.remotes = gemfile_source.remotes
- replacement_source
- end
-
def different_sources?(lock_sources, replacement_sources)
!equivalent_sources?(lock_sources, replacement_sources)
end
diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb
index 96c36c2dec..21630e3a3e 100644
--- a/lib/bundler/spec_set.rb
+++ b/lib/bundler/spec_set.rb
@@ -37,7 +37,7 @@ module Bundler
specs_for_dep.first.dependencies.each do |d|
next if d.type == :development
- incomplete = true if d.name != "bundler" && lookup[d.name].nil?
+ incomplete = true if d.name != "bundler" && lookup[d.name].empty?
deps << [d, dep[1]]
end
else
@@ -45,58 +45,28 @@ module Bundler
end
if incomplete && check
- @incomplete_specs += lookup[name] || [LazySpecification.new(name, nil, nil)]
+ @incomplete_specs += lookup[name].any? ? lookup[name] : [LazySpecification.new(name, nil, nil)]
end
end
specs.uniq
end
- def add_extra_platforms!(platforms)
- return platforms.concat([Gem::Platform::RUBY]).uniq if @specs.empty?
-
- new_platforms = all_platforms.select do |platform|
- next if platforms.include?(platform)
- next unless GemHelpers.generic(platform) == Gem::Platform::RUBY
-
- complete_platform(platform)
- end
- return platforms if new_platforms.empty?
-
- platforms.concat(new_platforms)
-
- less_specific_platform = new_platforms.find {|platform| platform != Gem::Platform::RUBY && Bundler.local_platform === platform && platform === Bundler.local_platform }
- platforms.delete(Bundler.local_platform) if less_specific_platform
-
- platforms
- end
-
- def validate_deps(s)
- s.runtime_dependencies.each do |dep|
- next if dep.name == "bundler"
-
- return :missing unless names.include?(dep.name)
- return :invalid if none? {|spec| dep.matches_spec?(spec) }
- end
-
- :valid
- end
-
def [](key)
key = key.name if key.respond_to?(:name)
- lookup[key]&.reverse || []
+ lookup[key].reverse
end
def []=(key, value)
@specs << value
-
- reset!
+ @lookup = nil
+ @sorted = nil
end
def delete(specs)
- Array(specs).each {|spec| @specs.delete(spec) }
-
- reset!
+ specs.each {|spec| @specs.delete(spec) }
+ @lookup = nil
+ @sorted = nil
end
def sort!
@@ -130,12 +100,12 @@ module Bundler
end
end
- def incomplete_for_platform?(deps, platform)
+ def incomplete_ruby_specs?(deps)
return false if @specs.empty?
@incomplete_specs = []
- self.for(deps, true, [platform])
+ self.for(deps, true, [Gem::Platform::RUBY])
@incomplete_specs.any?
end
@@ -144,6 +114,16 @@ module Bundler
@specs.select {|s| s.is_a?(LazySpecification) }
end
+ def merge(set)
+ arr = sorted.dup
+ set.each do |set_spec|
+ full_name = set_spec.full_name
+ next if arr.any? {|spec| spec.full_name == full_name }
+ arr << set_spec
+ end
+ SpecSet.new(arr)
+ end
+
def -(other)
SpecSet.new(to_a - other.to_a)
end
@@ -152,20 +132,14 @@ module Bundler
@specs.detect {|spec| spec.name == name && spec.match_platform(platform) }
end
- def specs_compatible_with(other)
- select do |spec|
- other.valid?(spec)
- end
- end
-
def delete_by_name(name)
@specs.reject! {|spec| spec.name == name }
-
- reset!
+ @lookup = nil
+ @sorted = nil
end
def what_required(spec)
- unless req = find {|s| s.runtime_dependencies.any? {|d| d.name == spec.name } }
+ unless req = find {|s| s.dependencies.any? {|d| d.type == :runtime && d.name == spec.name } }
return [spec]
end
what_required(req) << spec
@@ -191,56 +165,8 @@ module Bundler
sorted.each(&b)
end
- def names
- lookup.keys
- end
-
- def valid?(s)
- s.matches_current_metadata? && valid_dependencies?(s)
- end
-
private
- def reset!
- @sorted = nil
- @lookup = nil
- end
-
- def complete_platform(platform)
- new_specs = []
-
- valid_platform = lookup.all? do |_, specs|
- spec = specs.first
- matching_specs = spec.source.specs.search([spec.name, spec.version])
- platform_spec = GemHelpers.select_best_platform_match(matching_specs, platform).find do |s|
- valid?(s)
- end
-
- if platform_spec
- new_specs << LazySpecification.from_spec(platform_spec) unless specs.include?(platform_spec)
- true
- else
- false
- end
- end
-
- if valid_platform && new_specs.any?
- @specs.concat(new_specs)
-
- reset!
- end
-
- valid_platform
- end
-
- def all_platforms
- @specs.flat_map {|spec| spec.source.specs.search([spec.name, spec.version]).map(&:platform) }.uniq
- end
-
- def valid_dependencies?(s)
- validate_deps(s) == :valid
- end
-
def sorted
rake = @specs.find {|s| s.name == "rake" }
begin
@@ -259,9 +185,8 @@ module Bundler
def lookup
@lookup ||= begin
- lookup = {}
+ lookup = Hash.new {|h, k| h[k] = [] }
@specs.each do |s|
- lookup[s.name] ||= []
lookup[s.name] << s
end
lookup
@@ -275,23 +200,16 @@ module Bundler
def specs_for_dependency(dep, platform)
specs_for_name = lookup[dep.name]
- return [] unless specs_for_name
-
- if platform
- GemHelpers.select_best_platform_match(specs_for_name, platform, force_ruby: dep.force_ruby_platform)
- else
- GemHelpers.select_best_local_platform_match(specs_for_name, force_ruby: dep.force_ruby_platform || dep.default_force_ruby_platform)
- end
+ target_platform = dep.force_ruby_platform ? Gem::Platform::RUBY : (platform || Bundler.local_platform)
+ matching_specs = GemHelpers.select_best_platform_match(specs_for_name, target_platform)
+ matching_specs.map!(&:materialize_for_installation).compact! if platform.nil?
+ matching_specs
end
def tsort_each_child(s)
s.dependencies.sort_by(&:name).each do |d|
next if d.type == :development
-
- specs_for_name = lookup[d.name]
- next unless specs_for_name
-
- specs_for_name.each {|s2| yield s2 }
+ lookup[d.name].each {|s2| yield s2 }
end
end
end
diff --git a/lib/bundler/stub_specification.rb b/lib/bundler/stub_specification.rb
index dc5d38580a..88a4257fa4 100644
--- a/lib/bundler/stub_specification.rb
+++ b/lib/bundler/stub_specification.rb
@@ -9,7 +9,6 @@ module Bundler
spec
end
- attr_reader :checksum
attr_accessor :stub, :ignored
def source=(source)
@@ -17,8 +16,7 @@ module Bundler
# Stub has no concept of source, which means that extension_dir may be wrong
# This is the case for git-based gems. So, instead manually assign the extension dir
return unless source.respond_to?(:extension_dir_name)
- unique_extension_dir = [source.extension_dir_name, File.basename(full_gem_path)].uniq.join("-")
- path = File.join(stub.extensions_dir, unique_extension_dir)
+ path = File.join(stub.extensions_dir, source.extension_dir_name)
stub.extension_dir = File.expand_path(path)
end
@@ -45,8 +43,8 @@ module Bundler
true
end
- def activated?
- stub.activated?
+ def activated
+ stub.activated
end
def activated=(activated)
@@ -58,7 +56,7 @@ module Bundler
end
def gem_build_complete_path
- stub.gem_build_complete_path
+ File.join(extension_dir, "gem.build_complete")
end
def default_gem?
@@ -77,14 +75,6 @@ module Bundler
stub.full_require_paths
end
- def require_paths
- stub.require_paths
- end
-
- def base_dir=(path)
- stub.base_dir = path
- end
-
def load_paths
full_require_paths
end
@@ -118,7 +108,6 @@ module Bundler
end
rs.source = source
- rs.base_dir = stub.base_dir
rs
end
diff --git a/lib/bundler/templates/Executable.bundler b/lib/bundler/templates/Executable.bundler
index caa2021701..e290fe91eb 100644
--- a/lib/bundler/templates/Executable.bundler
+++ b/lib/bundler/templates/Executable.bundler
@@ -27,7 +27,7 @@ m = Module.new do
bundler_version = nil
update_index = nil
ARGV.each_with_index do |a, i|
- if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN)
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
bundler_version = a
end
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
diff --git a/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt b/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
index 67fe8cee79..175b821a62 100644
--- a/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
+++ b/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt
@@ -2,131 +2,83 @@
## Our Pledge
-We as members, contributors, and leaders pledge to make participation in our
-community a harassment-free experience for everyone, regardless of age, body
-size, visible or invisible disability, ethnicity, sex characteristics, gender
-identity and expression, level of experience, education, socio-economic status,
-nationality, personal appearance, race, caste, color, religion, or sexual
-identity and orientation.
+We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
-We pledge to act and interact in ways that contribute to an open, welcoming,
-diverse, inclusive, and healthy community.
+We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
## Our Standards
-Examples of behavior that contributes to a positive environment for our
-community include:
+Examples of behavior that contributes to a positive environment for our community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
-* Accepting responsibility and apologizing to those affected by our mistakes,
- and learning from the experience
-* Focusing on what is best not just for us as individuals, but for the overall
- community
+* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
-* The use of sexualized language or imagery, and sexual attention or advances of
- any kind
+* The use of sexualized language or imagery, and sexual attention or
+ advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
-* Publishing others' private information, such as a physical or email address,
- without their explicit permission
+* Publishing others' private information, such as a physical or email
+ address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
-Community leaders are responsible for clarifying and enforcing our standards of
-acceptable behavior and will take appropriate and fair corrective action in
-response to any behavior that they deem inappropriate, threatening, offensive,
-or harmful.
+Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
-Community leaders have the right and responsibility to remove, edit, or reject
-comments, commits, code, wiki edits, issues, and other contributions that are
-not aligned to this Code of Conduct, and will communicate reasons for moderation
-decisions when appropriate.
+Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
## Scope
-This Code of Conduct applies within all community spaces, and also applies when
-an individual is officially representing the community in public spaces.
-Examples of representing our community include using an official email address,
-posting via an official social media account, or acting as an appointed
-representative at an online or offline event.
+This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
## Enforcement
-Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported to the community leaders responsible for enforcement at
-[INSERT CONTACT METHOD].
-All complaints will be reviewed and investigated promptly and fairly.
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at <%= config[:email] %>. All complaints will be reviewed and investigated promptly and fairly.
-All community leaders are obligated to respect the privacy and security of the
-reporter of any incident.
+All community leaders are obligated to respect the privacy and security of the reporter of any incident.
## Enforcement Guidelines
-Community leaders will follow these Community Impact Guidelines in determining
-the consequences for any action they deem in violation of this Code of Conduct:
+Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
-**Community Impact**: Use of inappropriate language or other behavior deemed
-unprofessional or unwelcome in the community.
+**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
-**Consequence**: A private, written warning from community leaders, providing
-clarity around the nature of the violation and an explanation of why the
-behavior was inappropriate. A public apology may be requested.
+**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
### 2. Warning
-**Community Impact**: A violation through a single incident or series of
-actions.
+**Community Impact**: A violation through a single incident or series of actions.
-**Consequence**: A warning with consequences for continued behavior. No
-interaction with the people involved, including unsolicited interaction with
-those enforcing the Code of Conduct, for a specified period of time. This
-includes avoiding interactions in community spaces as well as external channels
-like social media. Violating these terms may lead to a temporary or permanent
-ban.
+**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
### 3. Temporary Ban
-**Community Impact**: A serious violation of community standards, including
-sustained inappropriate behavior.
+**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
-**Consequence**: A temporary ban from any sort of interaction or public
-communication with the community for a specified period of time. No public or
-private interaction with the people involved, including unsolicited interaction
-with those enforcing the Code of Conduct, is allowed during this period.
-Violating these terms may lead to a permanent ban.
+**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
-**Community Impact**: Demonstrating a pattern of violation of community
-standards, including sustained inappropriate behavior, harassment of an
-individual, or aggression toward or disparagement of classes of individuals.
+**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
-**Consequence**: A permanent ban from any sort of public interaction within the
-community.
+**Consequence**: A permanent ban from any sort of public interaction within the community.
## Attribution
-This Code of Conduct is adapted from the [Contributor Covenant][homepage],
-version 2.1, available at
-[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,
+available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
-Community Impact Guidelines were inspired by
-[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
-
-For answers to common questions about this code of conduct, see the FAQ at
-[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
-[https://www.contributor-covenant.org/translations][translations].
+Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
-[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
-[Mozilla CoC]: https://github.com/mozilla/diversity
-[FAQ]: https://www.contributor-covenant.org/faq
-[translations]: https://www.contributor-covenant.org/translations
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
diff --git a/lib/bundler/templates/newgem/README.md.tt b/lib/bundler/templates/newgem/README.md.tt
index f9c97d5c7e..20eaac8a62 100644
--- a/lib/bundler/templates/newgem/README.md.tt
+++ b/lib/bundler/templates/newgem/README.md.tt
@@ -6,19 +6,15 @@ Welcome to your new gem! In this directory, you'll find the files you need to be
## Installation
-TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
+TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
Install the gem and add to the application's Gemfile by executing:
-```bash
-bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
-```
+ $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
If bundler is not being used to manage dependencies, install the gem by executing:
-```bash
-gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
-```
+ $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
## Usage
diff --git a/lib/bundler/templates/newgem/Rakefile.tt b/lib/bundler/templates/newgem/Rakefile.tt
index 172183d4b4..b5a5c4e392 100644
--- a/lib/bundler/templates/newgem/Rakefile.tt
+++ b/lib/bundler/templates/newgem/Rakefile.tt
@@ -4,9 +4,13 @@ require "bundler/gem_tasks"
<% default_task_names = [config[:test_task]].compact -%>
<% case config[:test] -%>
<% when "minitest" -%>
-require "minitest/test_task"
+require "rake/testtask"
-Minitest::TestTask.create
+Rake::TestTask.new(:test) do |t|
+ t.libs << "test"
+ t.libs << "lib"
+ t.test_files = FileList["test/**/test_*.rb"]
+end
<% when "test-unit" -%>
require "rake/testtask"
@@ -42,9 +46,7 @@ require "rb_sys/extensiontask"
task build: :compile
-GEMSPEC = Gem::Specification.load("<%= config[:underscored_name] %>.gemspec")
-
-RbSys::ExtensionTask.new(<%= config[:name].inspect %>, GEMSPEC) do |ext|
+RbSys::ExtensionTask.new(<%= config[:name].inspect %>) do |ext|
ext.lib_dir = "lib/<%= config[:namespaced_path] %>"
end
<% else -%>
@@ -52,9 +54,7 @@ require "rake/extensiontask"
task build: :compile
-GEMSPEC = Gem::Specification.load("<%= config[:underscored_name] %>.gemspec")
-
-Rake::ExtensionTask.new("<%= config[:underscored_name] %>", GEMSPEC) do |ext|
+Rake::ExtensionTask.new("<%= config[:underscored_name] %>") do |ext|
ext.lib_dir = "lib/<%= config[:namespaced_path] %>"
end
<% end -%>
diff --git a/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt b/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt
index 0ebce0e4a0..c64385486e 100644
--- a/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt
+++ b/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt
@@ -12,4 +12,4 @@ publish = false
crate-type = ["cdylib"]
[dependencies]
-magnus = { version = "0.6.2" }
+magnus = { version = "0.6" }
diff --git a/lib/bundler/templates/newgem/github/workflows/main.yml.tt b/lib/bundler/templates/newgem/github/workflows/main.yml.tt
index 32b39558d8..be58dd8156 100644
--- a/lib/bundler/templates/newgem/github/workflows/main.yml.tt
+++ b/lib/bundler/templates/newgem/github/workflows/main.yml.tt
@@ -17,7 +17,7 @@ jobs:
- '<%= RUBY_VERSION %>'
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v3
<%- if config[:ext] == 'rust' -%>
- name: Set up Ruby & Rust
uses: oxidize-rb/actions/setup-ruby-and-rust@v1
diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt
index 6e88f4dab1..bb76680379 100644
--- a/lib/bundler/templates/newgem/newgem.gemspec.tt
+++ b/lib/bundler/templates/newgem/newgem.gemspec.tt
@@ -27,11 +27,10 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- gemspec = File.basename(__FILE__)
- spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls|
- ls.readlines("\x0", chomp: true).reject do |f|
- (f == gemspec) ||
- f.start_with?(*%w[bin/ test/ spec/ features/ .git <%= config[:ci_config_path] %>appveyor Gemfile])
+ spec.files = Dir.chdir(__dir__) do
+ `git ls-files -z`.split("\x0").reject do |f|
+ (File.expand_path(f) == __FILE__) ||
+ f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
end
end
spec.bindir = "exe"
diff --git a/lib/bundler/templates/newgem/rubocop.yml.tt b/lib/bundler/templates/newgem/rubocop.yml.tt
index 3d1c4ee7b2..9ecec78807 100644
--- a/lib/bundler/templates/newgem/rubocop.yml.tt
+++ b/lib/bundler/templates/newgem/rubocop.yml.tt
@@ -2,7 +2,12 @@ AllCops:
TargetRubyVersion: <%= ::Gem::Version.new(config[:required_ruby_version]).segments[0..1].join(".") %>
Style/StringLiterals:
+ Enabled: true
EnforcedStyle: double_quotes
Style/StringLiteralsInInterpolation:
+ Enabled: true
EnforcedStyle: double_quotes
+
+Layout/LineLength:
+ Max: 120
diff --git a/lib/bundler/templates/newgem/standard.yml.tt b/lib/bundler/templates/newgem/standard.yml.tt
index a0696cd2e9..934b0b2c37 100644
--- a/lib/bundler/templates/newgem/standard.yml.tt
+++ b/lib/bundler/templates/newgem/standard.yml.tt
@@ -1,3 +1,3 @@
# For available configuration options, see:
-# https://github.com/standardrb/standard
+# https://github.com/testdouble/standard
ruby_version: <%= ::Gem::Version.new(config[:required_ruby_version]).segments[0..1].join(".") %>
diff --git a/lib/bundler/ui/shell.rb b/lib/bundler/ui/shell.rb
index 6df1512a5b..4139585c47 100644
--- a/lib/bundler/ui/shell.rb
+++ b/lib/bundler/ui/shell.rb
@@ -6,17 +6,14 @@ module Bundler
module UI
class Shell
LEVELS = %w[silent error warn confirm info debug].freeze
- OUTPUT_STREAMS = [:stdout, :stderr].freeze
attr_writer :shell
- attr_reader :output_stream
def initialize(options = {})
Thor::Base.shell = options["no-color"] ? Thor::Shell::Basic : nil
@shell = Thor::Base.shell.new
@level = ENV["DEBUG"] ? "debug" : "info"
@warning_history = []
- @output_stream = :stdout
end
def add_color(string, *color)
@@ -87,7 +84,7 @@ module Bundler
@shell.yes?(msg)
end
- def no?(msg)
+ def no?
@shell.no?(msg)
end
@@ -104,11 +101,6 @@ module Bundler
index <= LEVELS.index(@level)
end
- def output_stream=(symbol)
- raise ArgumentError unless OUTPUT_STREAMS.include?(symbol)
- @output_stream = symbol
- end
-
def trace(e, newline = nil, force = false)
return unless debug? || force
msg = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n ")}"
@@ -119,10 +111,6 @@ module Bundler
with_level("silent", &blk)
end
- def progress(&blk)
- with_output_stream(:stderr, &blk)
- end
-
def unprinted_warnings
[]
end
@@ -131,8 +119,6 @@ module Bundler
# valimism
def tell_me(msg, color = nil, newline = nil)
- return tell_err(msg, color, newline) if output_stream == :stderr
-
msg = word_wrap(msg) if newline.is_a?(Hash) && newline[:wrap]
if newline.nil?
@shell.say(msg, color)
@@ -144,7 +130,7 @@ module Bundler
def tell_err(message, color = nil, newline = nil)
return if @shell.send(:stderr).closed?
- newline = !message.to_s.match?(/( |\t)\Z/) if newline.nil?
+ newline ||= message.to_s !~ /( |\t)\Z/
message = word_wrap(message) if newline.is_a?(Hash) && newline[:wrap]
color = nil if color && !$stderr.tty?
@@ -161,7 +147,7 @@ module Bundler
spaces ? text.gsub(/#{spaces}/, "") : text
end
- def word_wrap(text, line_width = Thor::Terminal.terminal_width)
+ def word_wrap(text, line_width = @shell.terminal_width)
strip_leading_spaces(text).split("\n").collect do |line|
line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line
end * "\n"
@@ -174,14 +160,6 @@ module Bundler
ensure
@level = original
end
-
- def with_output_stream(symbol)
- original = output_stream
- self.output_stream = symbol
- yield
- ensure
- @output_stream = original
- end
end
end
end
diff --git a/lib/bundler/ui/silent.rb b/lib/bundler/ui/silent.rb
index 83d31d4b55..fa3292bdc9 100644
--- a/lib/bundler/ui/silent.rb
+++ b/lib/bundler/ui/silent.rb
@@ -53,13 +53,6 @@ module Bundler
false
end
- def output_stream=(_symbol)
- end
-
- def output_stream
- nil
- end
-
def ask(message)
end
@@ -67,7 +60,7 @@ module Bundler
raise "Cannot ask yes? with a silent shell"
end
- def no?(msg)
+ def no?
raise "Cannot ask no? with a silent shell"
end
@@ -84,10 +77,6 @@ module Bundler
yield
end
- def progress
- yield
- end
-
def unprinted_warnings
@warnings
end
diff --git a/lib/bundler/uri_credentials_filter.rb b/lib/bundler/uri_credentials_filter.rb
index a83f5304e2..ccfaf0bc5d 100644
--- a/lib/bundler/uri_credentials_filter.rb
+++ b/lib/bundler/uri_credentials_filter.rb
@@ -11,7 +11,7 @@ module Bundler
return uri if File.exist?(uri)
require_relative "vendored_uri"
- uri = Gem::URI(uri)
+ uri = Bundler::URI(uri)
end
if uri.userinfo
@@ -25,7 +25,7 @@ module Bundler
end
return uri.to_s if uri_to_anonymize.is_a?(String)
uri
- rescue Gem::URI::InvalidURIError # uri is not canonical uri scheme
+ rescue Bundler::URI::InvalidURIError # uri is not canonical uri scheme
uri
end
diff --git a/lib/bundler/vendor/connection_pool/lib/connection_pool.rb b/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
index 317088a866..455319efe3 100644
--- a/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
+++ b/lib/bundler/vendor/connection_pool/lib/connection_pool.rb
@@ -1,4 +1,4 @@
-require_relative "../../../vendored_timeout"
+require "timeout"
require_relative "connection_pool/version"
class Bundler::ConnectionPool
@@ -6,7 +6,7 @@ class Bundler::ConnectionPool
class PoolShuttingDownError < ::Bundler::ConnectionPool::Error; end
- class TimeoutError < ::Gem::Timeout::Error; end
+ class TimeoutError < ::Timeout::Error; end
end
# Generic connection pool class for sharing a limited number of objects or network connections
@@ -36,57 +36,14 @@ end
# Accepts the following options:
# - :size - number of connections to pool, defaults to 5
# - :timeout - amount of time to wait for a connection if none currently available, defaults to 5 seconds
-# - :auto_reload_after_fork - automatically drop all connections after fork, defaults to true
#
class Bundler::ConnectionPool
- DEFAULTS = {size: 5, timeout: 5, auto_reload_after_fork: true}
+ DEFAULTS = {size: 5, timeout: 5}
def self.wrap(options, &block)
Wrapper.new(options, &block)
end
- if Process.respond_to?(:fork)
- INSTANCES = ObjectSpace::WeakMap.new
- private_constant :INSTANCES
-
- def self.after_fork
- INSTANCES.values.each do |pool|
- next unless pool.auto_reload_after_fork
-
- # We're on after fork, so we know all other threads are dead.
- # All we need to do is to ensure the main thread doesn't have a
- # checked out connection
- pool.checkin(force: true)
- pool.reload do |connection|
- # Unfortunately we don't know what method to call to close the connection,
- # so we try the most common one.
- connection.close if connection.respond_to?(:close)
- end
- end
- nil
- end
-
- if ::Process.respond_to?(:_fork) # MRI 3.1+
- module ForkTracker
- def _fork
- pid = super
- if pid == 0
- Bundler::ConnectionPool.after_fork
- end
- pid
- end
- end
- Process.singleton_class.prepend(ForkTracker)
- end
- else
- INSTANCES = nil
- private_constant :INSTANCES
-
- def self.after_fork
- # noop
- end
- end
-
def initialize(options = {}, &block)
raise ArgumentError, "Connection pool requires a block" unless block
@@ -94,12 +51,10 @@ class Bundler::ConnectionPool
@size = Integer(options.fetch(:size))
@timeout = options.fetch(:timeout)
- @auto_reload_after_fork = options.fetch(:auto_reload_after_fork)
@available = TimedStack.new(@size, &block)
@key = :"pool-#{@available.object_id}"
@key_count = :"pool-#{@available.object_id}-count"
- INSTANCES[self] = self if INSTANCES
end
def with(options = {})
@@ -126,16 +81,16 @@ class Bundler::ConnectionPool
end
end
- def checkin(force: false)
+ def checkin
if ::Thread.current[@key]
- if ::Thread.current[@key_count] == 1 || force
+ if ::Thread.current[@key_count] == 1
@available.push(::Thread.current[@key])
::Thread.current[@key] = nil
::Thread.current[@key_count] = nil
else
::Thread.current[@key_count] -= 1
end
- elsif !force
+ else
raise Bundler::ConnectionPool::Error, "no connections are checked out"
end
@@ -162,8 +117,6 @@ class Bundler::ConnectionPool
# Size of this connection pool
attr_reader :size
- # Automatically drop all connections after fork
- attr_reader :auto_reload_after_fork
# Number of pool entries available for checkout at this instant.
def available
diff --git a/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb b/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb
index 384d6fc977..56ebf69902 100644
--- a/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb
+++ b/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb
@@ -1,3 +1,3 @@
class Bundler::ConnectionPool
- VERSION = "2.4.1"
+ VERSION = "2.3.0"
end
diff --git a/lib/bundler/vendor/fileutils/lib/fileutils.rb b/lib/bundler/vendor/fileutils/lib/fileutils.rb
index 6db19caf6f..211311c069 100644
--- a/lib/bundler/vendor/fileutils/lib/fileutils.rb
+++ b/lib/bundler/vendor/fileutils/lib/fileutils.rb
@@ -180,7 +180,7 @@ end
# - {CVE-2004-0452}[https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452].
#
module Bundler::FileUtils
- VERSION = "1.7.2"
+ VERSION = "1.7.0"
def self.private_module_function(name) #:nodoc:
module_function name
@@ -192,6 +192,8 @@ module Bundler::FileUtils
#
# Bundler::FileUtils.pwd # => "/rdoc/fileutils"
#
+ # Bundler::FileUtils.getwd is an alias for Bundler::FileUtils.pwd.
+ #
# Related: Bundler::FileUtils.cd.
#
def pwd
@@ -233,6 +235,8 @@ module Bundler::FileUtils
# cd ..
# cd fileutils
#
+ # Bundler::FileUtils.chdir is an alias for Bundler::FileUtils.cd.
+ #
# Related: Bundler::FileUtils.pwd.
#
def cd(dir, verbose: nil, &block) # :yield: dir
@@ -511,6 +515,8 @@ module Bundler::FileUtils
# Raises an exception if +dest+ is the path to an existing file
# and keyword argument +force+ is not +true+.
#
+ # Bundler::FileUtils#link is an alias for Bundler::FileUtils#ln.
+ #
# Related: Bundler::FileUtils.link_entry (has different options).
#
def ln(src, dest, force: nil, noop: nil, verbose: nil)
@@ -701,6 +707,8 @@ module Bundler::FileUtils
# ln -sf src2.txt dest2.txt
# ln -s srcdir3/src0.txt srcdir3/src1.txt destdir3
#
+ # Bundler::FileUtils.symlink is an alias for Bundler::FileUtils.ln_s.
+ #
# Related: Bundler::FileUtils.ln_sf.
#
def ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil)
@@ -868,6 +876,8 @@ module Bundler::FileUtils
#
# Raises an exception if +src+ is a directory.
#
+ # Bundler::FileUtils.copy is an alias for Bundler::FileUtils.cp.
+ #
# Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
def cp(src, dest, preserve: nil, noop: nil, verbose: nil)
@@ -1154,6 +1164,8 @@ module Bundler::FileUtils
# mv src0 dest0
# mv src1.txt src1 dest1
#
+ # Bundler::FileUtils.move is an alias for Bundler::FileUtils.mv.
+ #
def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
return if noop
@@ -1211,6 +1223,8 @@ module Bundler::FileUtils
#
# rm src0.dat src0.txt
#
+ # Bundler::FileUtils.remove is an alias for Bundler::FileUtils.rm.
+ #
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm(list, force: nil, noop: nil, verbose: nil)
@@ -1236,6 +1250,8 @@ module Bundler::FileUtils
#
# See Bundler::FileUtils.rm for keyword arguments.
#
+ # Bundler::FileUtils.safe_unlink is an alias for Bundler::FileUtils.rm_f.
+ #
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm_f(list, noop: nil, verbose: nil)
@@ -1323,6 +1339,8 @@ module Bundler::FileUtils
#
# See Bundler::FileUtils.rm_r for keyword arguments.
#
+ # Bundler::FileUtils.rmtree is an alias for Bundler::FileUtils.rm_rf.
+ #
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm_rf(list, noop: nil, verbose: nil, secure: nil)
@@ -1624,13 +1642,7 @@ module Bundler::FileUtils
st = File.stat(s)
unless File.exist?(d) and compare_file(s, d)
remove_file d, true
- if d.end_with?('/')
- mkdir_p d
- copy_file s, d + File.basename(s)
- else
- mkdir_p File.expand_path('..', d)
- copy_file s, d
- end
+ copy_file s, d
File.utime st.atime, st.mtime, d if preserve
File.chmod fu_mode(mode, st), d if mode
File.chown uid, gid, d if uid or gid
diff --git a/lib/bundler/vendor/net-http-persistent/.document b/lib/bundler/vendor/net-http-persistent/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/bundler/vendor/net-http-persistent/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb
index c15b346330..a4e1c5a750 100644
--- a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb
+++ b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb
@@ -1,14 +1,14 @@
-require_relative '../../../../../vendored_net_http'
-require_relative '../../../../../vendored_uri'
+require 'net/http'
+require_relative '../../../../uri/lib/uri'
require 'cgi' # for escaping
require_relative '../../../../connection_pool/lib/connection_pool'
autoload :OpenSSL, 'openssl'
##
-# Persistent connections for Gem::Net::HTTP
+# Persistent connections for Net::HTTP
#
-# Gem::Net::HTTP::Persistent maintains persistent connections across all the
+# Bundler::Persistent::Net::HTTP::Persistent maintains persistent connections across all the
# servers you wish to talk to. For each host:port you communicate with a
# single persistent connection is created.
#
@@ -22,34 +22,34 @@ autoload :OpenSSL, 'openssl'
#
# require 'bundler/vendor/net-http-persistent/lib/net/http/persistent'
#
-# uri = Gem::URI 'http://example.com/awesome/web/service'
+# uri = Bundler::URI 'http://example.com/awesome/web/service'
#
-# http = Gem::Net::HTTP::Persistent.new
+# http = Bundler::Persistent::Net::HTTP::Persistent.new
#
# # perform a GET
# response = http.request uri
#
# # or
#
-# get = Gem::Net::HTTP::Get.new uri.request_uri
+# get = Net::HTTP::Get.new uri.request_uri
# response = http.request get
#
# # create a POST
# post_uri = uri + 'create'
-# post = Gem::Net::HTTP::Post.new post_uri.path
+# post = Net::HTTP::Post.new post_uri.path
# post.set_form_data 'some' => 'cool data'
#
-# # perform the POST, the Gem::URI is always required
+# # perform the POST, the Bundler::URI is always required
# response http.request post_uri, post
#
# Note that for GET, HEAD and other requests that do not have a body you want
-# to use Gem::URI#request_uri not Gem::URI#path. The request_uri contains the query
+# to use Bundler::URI#request_uri not Bundler::URI#path. The request_uri contains the query
# params which are sent in the body for other requests.
#
# == TLS/SSL
#
# TLS connections are automatically created depending upon the scheme of the
-# Gem::URI. TLS connections are automatically verified against the default
+# Bundler::URI. TLS connections are automatically verified against the default
# certificate store for your computer. You can override this by changing
# verify_mode or by specifying an alternate cert_store.
#
@@ -72,7 +72,7 @@ autoload :OpenSSL, 'openssl'
# == Proxies
#
# A proxy can be set through #proxy= or at initialization time by providing a
-# second argument to ::new. The proxy may be the Gem::URI of the proxy server or
+# second argument to ::new. The proxy may be the Bundler::URI of the proxy server or
# <code>:ENV</code> which will consult environment variables.
#
# See #proxy= and #proxy_from_env for details.
@@ -92,7 +92,7 @@ autoload :OpenSSL, 'openssl'
#
# === Segregation
#
-# Each Gem::Net::HTTP::Persistent instance has its own pool of connections. There
+# Each Bundler::Persistent::Net::HTTP::Persistent instance has its own pool of connections. There
# is no sharing with other instances (as was true in earlier versions).
#
# === Idle Timeout
@@ -131,7 +131,7 @@ autoload :OpenSSL, 'openssl'
#
# === Connection Termination
#
-# If you are done using the Gem::Net::HTTP::Persistent instance you may shut down
+# If you are done using the Bundler::Persistent::Net::HTTP::Persistent instance you may shut down
# all the connections in the current thread with #shutdown. This is not
# recommended for normal use, it should only be used when it will be several
# minutes before you make another HTTP request.
@@ -141,7 +141,7 @@ autoload :OpenSSL, 'openssl'
# Ruby will automatically garbage collect and shutdown your HTTP connections
# when the thread terminates.
-class Gem::Net::HTTP::Persistent
+class Bundler::Persistent::Net::HTTP::Persistent
##
# The beginning of Time
@@ -172,12 +172,12 @@ class Gem::Net::HTTP::Persistent
end
##
- # The version of Gem::Net::HTTP::Persistent you are using
+ # The version of Bundler::Persistent::Net::HTTP::Persistent you are using
- VERSION = '4.0.2'
+ VERSION = '4.0.1'
##
- # Error class for errors raised by Gem::Net::HTTP::Persistent. Various
+ # Error class for errors raised by Bundler::Persistent::Net::HTTP::Persistent. Various
# SystemCallErrors are re-raised with a human-readable message under this
# class.
@@ -197,10 +197,10 @@ class Gem::Net::HTTP::Persistent
# NOTE: This may not work on ruby > 1.9.
def self.detect_idle_timeout uri, max = 10
- uri = Gem::URI uri unless Gem::URI::Generic === uri
+ uri = Bundler::URI uri unless Bundler::URI::Generic === uri
uri += '/'
- req = Gem::Net::HTTP::Head.new uri.request_uri
+ req = Net::HTTP::Head.new uri.request_uri
http = new 'net-http-persistent detect_idle_timeout'
@@ -214,7 +214,7 @@ class Gem::Net::HTTP::Persistent
$stderr.puts "HEAD #{uri} => #{response.code}" if $DEBUG
- unless Gem::Net::HTTPOK === response then
+ unless Net::HTTPOK === response then
raise Error, "bad response code #{response.code} detecting idle timeout"
end
@@ -238,7 +238,7 @@ class Gem::Net::HTTP::Persistent
attr_reader :certificate
##
- # For Gem::Net::HTTP parity
+ # For Net::HTTP parity
alias cert certificate
@@ -266,7 +266,7 @@ class Gem::Net::HTTP::Persistent
attr_reader :ciphers
##
- # Sends debug_output to this IO via Gem::Net::HTTP#set_debug_output.
+ # Sends debug_output to this IO via Net::HTTP#set_debug_output.
#
# Never use this method in production code, it causes a serious security
# hole.
@@ -279,7 +279,7 @@ class Gem::Net::HTTP::Persistent
attr_reader :generation # :nodoc:
##
- # Headers that are added to every request using Gem::Net::HTTP#add_field
+ # Headers that are added to every request using Net::HTTP#add_field
attr_reader :headers
@@ -304,7 +304,7 @@ class Gem::Net::HTTP::Persistent
##
# Number of retries to perform if a request fails.
#
- # See also #max_retries=, Gem::Net::HTTP#max_retries=.
+ # See also #max_retries=, Net::HTTP#max_retries=.
attr_reader :max_retries
@@ -325,12 +325,12 @@ class Gem::Net::HTTP::Persistent
attr_reader :name
##
- # Seconds to wait until a connection is opened. See Gem::Net::HTTP#open_timeout
+ # Seconds to wait until a connection is opened. See Net::HTTP#open_timeout
attr_accessor :open_timeout
##
- # Headers that are added to every request using Gem::Net::HTTP#[]=
+ # Headers that are added to every request using Net::HTTP#[]=
attr_reader :override_headers
@@ -340,7 +340,7 @@ class Gem::Net::HTTP::Persistent
attr_reader :private_key
##
- # For Gem::Net::HTTP parity
+ # For Net::HTTP parity
alias key private_key
@@ -360,12 +360,12 @@ class Gem::Net::HTTP::Persistent
attr_reader :pool # :nodoc:
##
- # Seconds to wait until reading one block. See Gem::Net::HTTP#read_timeout
+ # Seconds to wait until reading one block. See Net::HTTP#read_timeout
attr_accessor :read_timeout
##
- # Seconds to wait until writing one block. See Gem::Net::HTTP#write_timeout
+ # Seconds to wait until writing one block. See Net::HTTP#write_timeout
attr_accessor :write_timeout
@@ -450,18 +450,18 @@ class Gem::Net::HTTP::Persistent
attr_reader :verify_mode
##
- # Creates a new Gem::Net::HTTP::Persistent.
+ # Creates a new Bundler::Persistent::Net::HTTP::Persistent.
#
# Set a +name+ for fun. Your library name should be good enough, but this
# otherwise has no purpose.
#
- # +proxy+ may be set to a Gem::URI::HTTP or :ENV to pick up proxy options from
+ # +proxy+ may be set to a Bundler::URI::HTTP or :ENV to pick up proxy options from
# the environment. See proxy_from_env for details.
#
- # In order to use a Gem::URI for the proxy you may need to do some extra work
- # beyond Gem::URI parsing if the proxy requires a password:
+ # In order to use a Bundler::URI for the proxy you may need to do some extra work
+ # beyond Bundler::URI parsing if the proxy requires a password:
#
- # proxy = Gem::URI 'http://proxy.example'
+ # proxy = Bundler::URI 'http://proxy.example'
# proxy.user = 'AzureDiamond'
# proxy.password = 'hunter2'
#
@@ -492,8 +492,8 @@ class Gem::Net::HTTP::Persistent
@socket_options << [Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1] if
Socket.const_defined? :TCP_NODELAY
- @pool = Gem::Net::HTTP::Persistent::Pool.new size: pool_size do |http_args|
- Gem::Net::HTTP::Persistent::Connection.new Gem::Net::HTTP, http_args, @ssl_generation
+ @pool = Bundler::Persistent::Net::HTTP::Persistent::Pool.new size: pool_size do |http_args|
+ Bundler::Persistent::Net::HTTP::Persistent::Connection.new Net::HTTP, http_args, @ssl_generation
end
@certificate = nil
@@ -510,7 +510,7 @@ class Gem::Net::HTTP::Persistent
@verify_mode = nil
@cert_store = nil
- @generation = 0 # incremented when proxy Gem::URI changes
+ @generation = 0 # incremented when proxy Bundler::URI changes
if HAVE_OPENSSL then
@verify_mode = OpenSSL::SSL::VERIFY_PEER
@@ -529,7 +529,7 @@ class Gem::Net::HTTP::Persistent
reconnect_ssl
end
- # For Gem::Net::HTTP parity
+ # For Net::HTTP parity
alias cert= certificate=
##
@@ -648,7 +648,7 @@ class Gem::Net::HTTP::Persistent
end
##
- # Starts the Gem::Net::HTTP +connection+
+ # Starts the Net::HTTP +connection+
def start http
http.set_debug_output @debug_output if @debug_output
@@ -666,7 +666,7 @@ class Gem::Net::HTTP::Persistent
end
##
- # Finishes the Gem::Net::HTTP +connection+
+ # Finishes the Net::HTTP +connection+
def finish connection
connection.finish
@@ -716,16 +716,16 @@ class Gem::Net::HTTP::Persistent
reconnect_ssl
end
- # For Gem::Net::HTTP parity
+ # For Net::HTTP parity
alias key= private_key=
##
- # Sets the proxy server. The +proxy+ may be the Gem::URI of the proxy server,
+ # Sets the proxy server. The +proxy+ may be the Bundler::URI of the proxy server,
# the symbol +:ENV+ which will read the proxy from the environment or nil to
# disable use of a proxy. See #proxy_from_env for details on setting the
# proxy from the environment.
#
- # If the proxy Gem::URI is set after requests have been made, the next request
+ # If the proxy Bundler::URI is set after requests have been made, the next request
# will shut-down and re-open all connections.
#
# The +no_proxy+ query parameter can be used to specify hosts which shouldn't
@@ -736,9 +736,9 @@ class Gem::Net::HTTP::Persistent
def proxy= proxy
@proxy_uri = case proxy
when :ENV then proxy_from_env
- when Gem::URI::HTTP then proxy
+ when Bundler::URI::HTTP then proxy
when nil then # ignore
- else raise ArgumentError, 'proxy must be :ENV or a Gem::URI::HTTP'
+ else raise ArgumentError, 'proxy must be :ENV or a Bundler::URI::HTTP'
end
@no_proxy.clear
@@ -763,13 +763,13 @@ class Gem::Net::HTTP::Persistent
end
##
- # Creates a Gem::URI for an HTTP proxy server from ENV variables.
+ # Creates a Bundler::URI for an HTTP proxy server from ENV variables.
#
# If +HTTP_PROXY+ is set a proxy will be returned.
#
- # If +HTTP_PROXY_USER+ or +HTTP_PROXY_PASS+ are set the Gem::URI is given the
+ # If +HTTP_PROXY_USER+ or +HTTP_PROXY_PASS+ are set the Bundler::URI is given the
# indicated user and password unless HTTP_PROXY contains either of these in
- # the Gem::URI.
+ # the Bundler::URI.
#
# The +NO_PROXY+ ENV variable can be used to specify hosts which shouldn't
# be reached via proxy; if set it should be a comma separated list of
@@ -785,7 +785,7 @@ class Gem::Net::HTTP::Persistent
return nil if env_proxy.nil? or env_proxy.empty?
- uri = Gem::URI normalize_uri env_proxy
+ uri = Bundler::URI normalize_uri env_proxy
env_no_proxy = ENV['no_proxy'] || ENV['NO_PROXY']
@@ -835,7 +835,7 @@ class Gem::Net::HTTP::Persistent
end
##
- # Finishes then restarts the Gem::Net::HTTP +connection+
+ # Finishes then restarts the Net::HTTP +connection+
def reset connection
http = connection.http
@@ -854,16 +854,16 @@ class Gem::Net::HTTP::Persistent
end
##
- # Makes a request on +uri+. If +req+ is nil a Gem::Net::HTTP::Get is performed
+ # Makes a request on +uri+. If +req+ is nil a Net::HTTP::Get is performed
# against +uri+.
#
- # If a block is passed #request behaves like Gem::Net::HTTP#request (the body of
+ # If a block is passed #request behaves like Net::HTTP#request (the body of
# the response will not have been read).
#
- # +req+ must be a Gem::Net::HTTPGenericRequest subclass (see Gem::Net::HTTP for a list).
+ # +req+ must be a Net::HTTPGenericRequest subclass (see Net::HTTP for a list).
def request uri, req = nil, &block
- uri = Gem::URI uri
+ uri = Bundler::URI uri
req = request_setup req || uri
response = nil
@@ -896,14 +896,14 @@ class Gem::Net::HTTP::Persistent
end
##
- # Creates a GET request if +req_or_uri+ is a Gem::URI and adds headers to the
+ # Creates a GET request if +req_or_uri+ is a Bundler::URI and adds headers to the
# request.
#
# Returns the request.
def request_setup req_or_uri # :nodoc:
req = if req_or_uri.respond_to? 'request_uri' then
- Gem::Net::HTTP::Get.new req_or_uri.request_uri
+ Net::HTTP::Get.new req_or_uri.request_uri
else
req_or_uri
end
diff --git a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb
index 8b9ab5cc78..a57a5d1352 100644
--- a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb
+++ b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb
@@ -1,8 +1,8 @@
##
-# A Gem::Net::HTTP connection wrapper that holds extra information for managing the
+# A Net::HTTP connection wrapper that holds extra information for managing the
# connection's lifetime.
-class Gem::Net::HTTP::Persistent::Connection # :nodoc:
+class Bundler::Persistent::Net::HTTP::Persistent::Connection # :nodoc:
attr_accessor :http
@@ -25,10 +25,9 @@ class Gem::Net::HTTP::Persistent::Connection # :nodoc:
ensure
reset
end
- alias_method :close, :finish
def reset
- @last_use = Gem::Net::HTTP::Persistent::EPOCH
+ @last_use = Bundler::Persistent::Net::HTTP::Persistent::EPOCH
@requests = 0
end
diff --git a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb
index 04a1e754bf..9dfa6ffdb1 100644
--- a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb
+++ b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb
@@ -1,4 +1,4 @@
-class Gem::Net::HTTP::Persistent::Pool < Bundler::ConnectionPool # :nodoc:
+class Bundler::Persistent::Net::HTTP::Persistent::Pool < Bundler::ConnectionPool # :nodoc:
attr_reader :available # :nodoc:
attr_reader :key # :nodoc:
@@ -6,37 +6,25 @@ class Gem::Net::HTTP::Persistent::Pool < Bundler::ConnectionPool # :nodoc:
def initialize(options = {}, &block)
super
- @available = Gem::Net::HTTP::Persistent::TimedStackMulti.new(@size, &block)
+ @available = Bundler::Persistent::Net::HTTP::Persistent::TimedStackMulti.new(@size, &block)
@key = "current-#{@available.object_id}"
end
def checkin net_http_args
- if net_http_args.is_a?(Hash) && net_http_args.size == 1 && net_http_args[:force]
- # Bundler::ConnectionPool 2.4+ calls `checkin(force: true)` after fork.
- # When this happens, we should remove all connections from Thread.current
- if stacks = Thread.current[@key]
- stacks.each do |http_args, connections|
- connections.each do |conn|
- @available.push conn, connection_args: http_args
- end
- connections.clear
- end
- end
- else
- stack = Thread.current[@key][net_http_args] ||= []
+ stack = Thread.current[@key][net_http_args] ||= []
- raise Bundler::ConnectionPool::Error, 'no connections are checked out' if
- stack.empty?
+ raise Bundler::ConnectionPool::Error, 'no connections are checked out' if
+ stack.empty?
- conn = stack.pop
+ conn = stack.pop
- if stack.empty?
- @available.push conn, connection_args: net_http_args
+ if stack.empty?
+ @available.push conn, connection_args: net_http_args
- Thread.current[@key].delete(net_http_args)
- Thread.current[@key] = nil if Thread.current[@key].empty?
- end
+ Thread.current[@key].delete(net_http_args)
+ Thread.current[@key] = nil if Thread.current[@key].empty?
end
+
nil
end
diff --git a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb
index 214804fcd9..2da881c554 100644
--- a/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb
+++ b/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb
@@ -1,4 +1,4 @@
-class Gem::Net::HTTP::Persistent::TimedStackMulti < Bundler::ConnectionPool::TimedStack # :nodoc:
+class Bundler::Persistent::Net::HTTP::Persistent::TimedStackMulti < Bundler::ConnectionPool::TimedStack # :nodoc:
##
# Returns a new hash that has arrays for keys
diff --git a/lib/bundler/vendor/pub_grub/.document b/lib/bundler/vendor/pub_grub/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/bundler/vendor/pub_grub/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb b/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb
index 36ab06254d..4bf61461b2 100644
--- a/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb
+++ b/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb
@@ -1,5 +1,4 @@
require_relative 'package'
-require_relative 'rubygems'
require_relative 'version_constraint'
require_relative 'incompatibility'
require_relative 'basic_package_source'
diff --git a/lib/bundler/vendor/securerandom/.document b/lib/bundler/vendor/securerandom/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/bundler/vendor/securerandom/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/bundler/vendor/securerandom/lib/random/formatter.rb b/lib/bundler/vendor/securerandom/lib/random/formatter.rb
deleted file mode 100644
index e429709789..0000000000
--- a/lib/bundler/vendor/securerandom/lib/random/formatter.rb
+++ /dev/null
@@ -1,373 +0,0 @@
-# -*- coding: us-ascii -*-
-# frozen_string_literal: true
-
-# == \Random number formatter.
-#
-# Formats generated random numbers in many manners. When <tt>'random/formatter'</tt>
-# is required, several methods are added to empty core module <tt>Bundler::Random::Formatter</tt>,
-# making them available as Random's instance and module methods.
-#
-# Standard library Bundler::SecureRandom is also extended with the module, and the methods
-# described below are available as a module methods in it.
-#
-# === Examples
-#
-# Generate random hexadecimal strings:
-#
-# require 'bundler/vendor/securerandom/lib/random/formatter'
-#
-# prng = Random.new
-# prng.hex(10) #=> "52750b30ffbc7de3b362"
-# prng.hex(10) #=> "92b15d6c8dc4beb5f559"
-# prng.hex(13) #=> "39b290146bea6ce975c37cfc23"
-# # or just
-# Random.hex #=> "1aed0c631e41be7f77365415541052ee"
-#
-# Generate random base64 strings:
-#
-# prng.base64(10) #=> "EcmTPZwWRAozdA=="
-# prng.base64(10) #=> "KO1nIU+p9DKxGg=="
-# prng.base64(12) #=> "7kJSM/MzBJI+75j8"
-# Random.base64(4) #=> "bsQ3fQ=="
-#
-# Generate random binary strings:
-#
-# prng.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
-# prng.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
-# Random.random_bytes(6) #=> "\xA1\xE6Lr\xC43"
-#
-# Generate alphanumeric strings:
-#
-# prng.alphanumeric(10) #=> "S8baxMJnPl"
-# prng.alphanumeric(10) #=> "aOxAg8BAJe"
-# Random.alphanumeric #=> "TmP9OsJHJLtaZYhP"
-#
-# Generate UUIDs:
-#
-# prng.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
-# prng.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
-# Random.uuid #=> "f14e0271-de96-45cc-8911-8910292a42cd"
-#
-# All methods are available in the standard library Bundler::SecureRandom, too:
-#
-# Bundler::SecureRandom.hex #=> "05b45376a30c67238eb93b16499e50cf"
-
-module Bundler::Random::Formatter
-
- # Generate a random binary string.
- #
- # The argument _n_ specifies the length of the result string.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in future.
- #
- # The result may contain any byte: "\x00" - "\xff".
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # Random.random_bytes #=> "\xD8\\\xE0\xF4\r\xB2\xFC*WM\xFF\x83\x18\xF45\xB6"
- # # or
- # prng = Random.new
- # prng.random_bytes #=> "m\xDC\xFC/\a\x00Uf\xB2\xB2P\xBD\xFF6S\x97"
- def random_bytes(n=nil)
- n = n ? n.to_int : 16
- gen_random(n)
- end
-
- # Generate a random hexadecimal string.
- #
- # The argument _n_ specifies the length, in bytes, of the random number to be generated.
- # The length of the resulting hexadecimal string is twice of _n_.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in the future.
- #
- # The result may contain 0-9 and a-f.
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # Random.hex #=> "eb693ec8252cd630102fd0d0fb7c3485"
- # # or
- # prng = Random.new
- # prng.hex #=> "91dc3bfb4de5b11d029d376634589b61"
- def hex(n=nil)
- random_bytes(n).unpack1("H*")
- end
-
- # Generate a random base64 string.
- #
- # The argument _n_ specifies the length, in bytes, of the random number
- # to be generated. The length of the result string is about 4/3 of _n_.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in the future.
- #
- # The result may contain A-Z, a-z, 0-9, "+", "/" and "=".
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # Random.base64 #=> "/2BuBuLf3+WfSKyQbRcc/A=="
- # # or
- # prng = Random.new
- # prng.base64 #=> "6BbW0pxO0YENxn38HMUbcQ=="
- #
- # See RFC 3548 for the definition of base64.
- def base64(n=nil)
- [random_bytes(n)].pack("m0")
- end
-
- # Generate a random URL-safe base64 string.
- #
- # The argument _n_ specifies the length, in bytes, of the random number
- # to be generated. The length of the result string is about 4/3 of _n_.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in the future.
- #
- # The boolean argument _padding_ specifies the padding.
- # If it is false or nil, padding is not generated.
- # Otherwise padding is generated.
- # By default, padding is not generated because "=" may be used as a URL delimiter.
- #
- # The result may contain A-Z, a-z, 0-9, "-" and "_".
- # "=" is also used if _padding_ is true.
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # Random.urlsafe_base64 #=> "b4GOKm4pOYU_-BOXcrUGDg"
- # # or
- # prng = Random.new
- # prng.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
- #
- # prng.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="
- # prng.urlsafe_base64(nil, true) #=> "-M8rLhr7JEpJlqFGUMmOxg=="
- #
- # See RFC 3548 for the definition of URL-safe base64.
- def urlsafe_base64(n=nil, padding=false)
- s = [random_bytes(n)].pack("m0")
- s.tr!("+/", "-_")
- s.delete!("=") unless padding
- s
- end
-
- # Generate a random v4 UUID (Universally Unique IDentifier).
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # Random.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
- # Random.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
- # # or
- # prng = Random.new
- # prng.uuid #=> "62936e70-1815-439b-bf89-8492855a7e6b"
- #
- # The version 4 UUID is purely random (except the version).
- # It doesn't contain meaningful information such as MAC addresses, timestamps, etc.
- #
- # The result contains 122 random bits (15.25 random bytes).
- #
- # See RFC4122[https://datatracker.ietf.org/doc/html/rfc4122] for details of UUID.
- #
- def uuid
- ary = random_bytes(16).unpack("NnnnnN")
- ary[2] = (ary[2] & 0x0fff) | 0x4000
- ary[3] = (ary[3] & 0x3fff) | 0x8000
- "%08x-%04x-%04x-%04x-%04x%08x" % ary
- end
-
- alias uuid_v4 uuid
-
- # Generate a random v7 UUID (Universally Unique IDentifier).
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # Random.uuid_v7 # => "0188d4c3-1311-7f96-85c7-242a7aa58f1e"
- # Random.uuid_v7 # => "0188d4c3-16fe-744f-86af-38fa04c62bb5"
- # Random.uuid_v7 # => "0188d4c3-1af8-764f-b049-c204ce0afa23"
- # Random.uuid_v7 # => "0188d4c3-1e74-7085-b14f-ef6415dc6f31"
- # # |<--sorted-->| |<----- random ---->|
- #
- # # or
- # prng = Random.new
- # prng.uuid_v7 # => "0188ca51-5e72-7950-a11d-def7ff977c98"
- #
- # The version 7 UUID starts with the least significant 48 bits of a 64 bit
- # Unix timestamp (milliseconds since the epoch) and fills the remaining bits
- # with random data, excluding the version and variant bits.
- #
- # This allows version 7 UUIDs to be sorted by creation time. Time ordered
- # UUIDs can be used for better database index locality of newly inserted
- # records, which may have a significant performance benefit compared to random
- # data inserts.
- #
- # The result contains 74 random bits (9.25 random bytes).
- #
- # Note that this method cannot be made reproducable because its output
- # includes not only random bits but also timestamp.
- #
- # See draft-ietf-uuidrev-rfc4122bis[https://datatracker.ietf.org/doc/draft-ietf-uuidrev-rfc4122bis/]
- # for details of UUIDv7.
- #
- # ==== Monotonicity
- #
- # UUIDv7 has millisecond precision by default, so multiple UUIDs created
- # within the same millisecond are not issued in monotonically increasing
- # order. To create UUIDs that are time-ordered with sub-millisecond
- # precision, up to 12 bits of additional timestamp may added with
- # +extra_timestamp_bits+. The extra timestamp precision comes at the expense
- # of random bits. Setting <tt>extra_timestamp_bits: 12</tt> provides ~244ns
- # of precision, but only 62 random bits (7.75 random bytes).
- #
- # prng = Random.new
- # Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 12) }
- # # =>
- # ["0188d4c7-13da-74f9-8b53-22a786ffdd5a",
- # "0188d4c7-13da-753b-83a5-7fb9b2afaeea",
- # "0188d4c7-13da-754a-88ea-ac0baeedd8db",
- # "0188d4c7-13da-7557-83e1-7cad9cda0d8d"]
- # # |<--- sorted --->| |<-- random --->|
- #
- # Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 8) }
- # # =>
- # ["0188d4c7-3333-7a95-850a-de6edb858f7e",
- # "0188d4c7-3333-7ae8-842e-bc3a8b7d0cf9", # <- out of order
- # "0188d4c7-3333-7ae2-995a-9f135dc44ead", # <- out of order
- # "0188d4c7-3333-7af9-87c3-8f612edac82e"]
- # # |<--- sorted -->||<---- random --->|
- #
- # Any rollbacks of the system clock will break monotonicity. UUIDv7 is based
- # on UTC, which excludes leap seconds and can rollback the clock. To avoid
- # this, the system clock can synchronize with an NTP server configured to use
- # a "leap smear" approach. NTP or PTP will also be needed to synchronize
- # across distributed nodes.
- #
- # Counters and other mechanisms for stronger guarantees of monotonicity are
- # not implemented. Applications with stricter requirements should follow
- # {Section 6.2}[https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-07.html#monotonicity_counters]
- # of the specification.
- #
- def uuid_v7(extra_timestamp_bits: 0)
- case (extra_timestamp_bits = Integer(extra_timestamp_bits))
- when 0 # min timestamp precision
- ms = Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
- rand = random_bytes(10)
- rand.setbyte(0, rand.getbyte(0) & 0x0f | 0x70) # version
- rand.setbyte(2, rand.getbyte(2) & 0x3f | 0x80) # variant
- "%08x-%04x-%s" % [
- (ms & 0x0000_ffff_ffff_0000) >> 16,
- (ms & 0x0000_0000_0000_ffff),
- rand.unpack("H4H4H12").join("-")
- ]
-
- when 12 # max timestamp precision
- ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
- .divmod(1_000_000)
- extra_bits = ns * 4096 / 1_000_000
- rand = random_bytes(8)
- rand.setbyte(0, rand.getbyte(0) & 0x3f | 0x80) # variant
- "%08x-%04x-7%03x-%s" % [
- (ms & 0x0000_ffff_ffff_0000) >> 16,
- (ms & 0x0000_0000_0000_ffff),
- extra_bits,
- rand.unpack("H4H12").join("-")
- ]
-
- when (0..12) # the generic version is slower than the special cases above
- rand_a, rand_b1, rand_b2, rand_b3 = random_bytes(10).unpack("nnnN")
- rand_mask_bits = 12 - extra_timestamp_bits
- ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
- .divmod(1_000_000)
- "%08x-%04x-%04x-%04x-%04x%08x" % [
- (ms & 0x0000_ffff_ffff_0000) >> 16,
- (ms & 0x0000_0000_0000_ffff),
- 0x7000 |
- ((ns * (1 << extra_timestamp_bits) / 1_000_000) << rand_mask_bits) |
- rand_a & ((1 << rand_mask_bits) - 1),
- 0x8000 | (rand_b1 & 0x3fff),
- rand_b2,
- rand_b3
- ]
-
- else
- raise ArgumentError, "extra_timestamp_bits must be in 0..12"
- end
- end
-
- # Internal interface to Random; Generate random data _n_ bytes.
- private def gen_random(n)
- self.bytes(n)
- end
-
- # Generate a string that randomly draws from a
- # source array of characters.
- #
- # The argument _source_ specifies the array of characters from which
- # to generate the string.
- # The argument _n_ specifies the length, in characters, of the string to be
- # generated.
- #
- # The result may contain whatever characters are in the source array.
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # prng.choose([*'l'..'r'], 16) #=> "lmrqpoonmmlqlron"
- # prng.choose([*'0'..'9'], 5) #=> "27309"
- private def choose(source, n)
- size = source.size
- m = 1
- limit = size
- while limit * size <= 0x100000000
- limit *= size
- m += 1
- end
- result = ''.dup
- while m <= n
- rs = random_number(limit)
- is = rs.digits(size)
- (m-is.length).times { is << 0 }
- result << source.values_at(*is).join('')
- n -= m
- end
- if 0 < n
- rs = random_number(limit)
- is = rs.digits(size)
- if is.length < n
- (n-is.length).times { is << 0 }
- else
- is.pop while n < is.length
- end
- result.concat source.values_at(*is).join('')
- end
- result
- end
-
- # The default character list for #alphanumeric.
- ALPHANUMERIC = [*'A'..'Z', *'a'..'z', *'0'..'9']
-
- # Generate a random alphanumeric string.
- #
- # The argument _n_ specifies the length, in characters, of the alphanumeric
- # string to be generated.
- # The argument _chars_ specifies the character list which the result is
- # consist of.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in the future.
- #
- # The result may contain A-Z, a-z and 0-9, unless _chars_ is specified.
- #
- # require 'bundler/vendor/securerandom/lib/random/formatter'
- #
- # Random.alphanumeric #=> "2BuBuLf3WfSKyQbR"
- # # or
- # prng = Random.new
- # prng.alphanumeric(10) #=> "i6K93NdqiH"
- #
- # Random.alphanumeric(4, chars: [*"0".."9"]) #=> "2952"
- # # or
- # prng = Random.new
- # prng.alphanumeric(10, chars: [*"!".."/"]) #=> ",.,++%/''."
- def alphanumeric(n = nil, chars: ALPHANUMERIC)
- n = 16 if n.nil?
- choose(chars, n)
- end
-end
diff --git a/lib/bundler/vendor/securerandom/lib/securerandom.rb b/lib/bundler/vendor/securerandom/lib/securerandom.rb
deleted file mode 100644
index e797054468..0000000000
--- a/lib/bundler/vendor/securerandom/lib/securerandom.rb
+++ /dev/null
@@ -1,96 +0,0 @@
-# -*- coding: us-ascii -*-
-# frozen_string_literal: true
-
-require_relative 'random/formatter'
-
-# == Secure random number generator interface.
-#
-# This library is an interface to secure random number generators which are
-# suitable for generating session keys in HTTP cookies, etc.
-#
-# You can use this library in your application by requiring it:
-#
-# require 'bundler/vendor/securerandom/lib/securerandom'
-#
-# It supports the following secure random number generators:
-#
-# * openssl
-# * /dev/urandom
-# * Win32
-#
-# Bundler::SecureRandom is extended by the Bundler::Random::Formatter module which
-# defines the following methods:
-#
-# * alphanumeric
-# * base64
-# * choose
-# * gen_random
-# * hex
-# * rand
-# * random_bytes
-# * random_number
-# * urlsafe_base64
-# * uuid
-#
-# These methods are usable as class methods of Bundler::SecureRandom such as
-# +Bundler::SecureRandom.hex+.
-#
-# If a secure random number generator is not available,
-# +NotImplementedError+ is raised.
-
-module Bundler::SecureRandom
-
- # The version
- VERSION = "0.3.1"
-
- class << self
- # Returns a random binary string containing +size+ bytes.
- #
- # See Random.bytes
- def bytes(n)
- return gen_random(n)
- end
-
- private
-
- # :stopdoc:
-
- # Implementation using OpenSSL
- def gen_random_openssl(n)
- return OpenSSL::Random.random_bytes(n)
- end
-
- # Implementation using system random device
- def gen_random_urandom(n)
- ret = Random.urandom(n)
- unless ret
- raise NotImplementedError, "No random device"
- end
- unless ret.length == n
- raise NotImplementedError, "Unexpected partial read from random device: only #{ret.length} for #{n} bytes"
- end
- ret
- end
-
- begin
- # Check if Random.urandom is available
- Random.urandom(1)
- alias gen_random gen_random_urandom
- rescue RuntimeError
- begin
- require 'openssl'
- rescue NoMethodError
- raise NotImplementedError, "No random device"
- else
- alias gen_random gen_random_openssl
- end
- end
-
- # :startdoc:
-
- # Generate random data bytes for Bundler::Random::Formatter
- public :gen_random
- end
-end
-
-Bundler::SecureRandom.extend(Bundler::Random::Formatter)
diff --git a/lib/bundler/vendor/thor/.document b/lib/bundler/vendor/thor/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/bundler/vendor/thor/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/bundler/vendor/thor/lib/thor.rb b/lib/bundler/vendor/thor/lib/thor.rb
index 627722164f..0794dbb522 100644
--- a/lib/bundler/vendor/thor/lib/thor.rb
+++ b/lib/bundler/vendor/thor/lib/thor.rb
@@ -65,15 +65,8 @@ class Bundler::Thor
# Defines the long description of the next command.
#
- # Long description is by default indented, line-wrapped and repeated whitespace merged.
- # In order to print long description verbatim, with indentation and spacing exactly
- # as found in the code, use the +wrap+ option
- #
- # long_desc 'your very long description', wrap: false
- #
# ==== Parameters
# long description<String>
- # options<Hash>
#
def long_desc(long_description, options = {})
if options[:for]
@@ -81,7 +74,6 @@ class Bundler::Thor
command.long_description = long_description if long_description
else
@long_desc = long_description
- @long_desc_wrap = options[:wrap] != false
end
end
@@ -141,7 +133,7 @@ class Bundler::Thor
# # magic
# end
#
- # method_option :foo, :for => :previous_command
+ # method_option :foo => :bar, :for => :previous_command
#
# def next_command
# # magic
@@ -161,9 +153,6 @@ class Bundler::Thor
# :hide - If you want to hide this option from the help.
#
def method_option(name, options = {})
- unless [ Symbol, String ].any? { |klass| name.is_a?(klass) }
- raise ArgumentError, "Expected a Symbol or String, got #{name.inspect}"
- end
scope = if options[:for]
find_and_refresh_command(options[:for]).options
else
@@ -174,81 +163,6 @@ class Bundler::Thor
end
alias_method :option, :method_option
- # Adds and declares option group for exclusive options in the
- # block and arguments. You can declare options as the outside of the block.
- #
- # If :for is given as option, it allows you to change the options from
- # a previous defined command.
- #
- # ==== Parameters
- # Array[Bundler::Thor::Option.name]
- # options<Hash>:: :for is applied for previous defined command.
- #
- # ==== Examples
- #
- # exclusive do
- # option :one
- # option :two
- # end
- #
- # Or
- #
- # option :one
- # option :two
- # exclusive :one, :two
- #
- # If you give "--one" and "--two" at the same time ExclusiveArgumentsError
- # will be raised.
- #
- def method_exclusive(*args, &block)
- register_options_relation_for(:method_options,
- :method_exclusive_option_names, *args, &block)
- end
- alias_method :exclusive, :method_exclusive
-
- # Adds and declares option group for required at least one of options in the
- # block of arguments. You can declare options as the outside of the block.
- #
- # If :for is given as option, it allows you to change the options from
- # a previous defined command.
- #
- # ==== Parameters
- # Array[Bundler::Thor::Option.name]
- # options<Hash>:: :for is applied for previous defined command.
- #
- # ==== Examples
- #
- # at_least_one do
- # option :one
- # option :two
- # end
- #
- # Or
- #
- # option :one
- # option :two
- # at_least_one :one, :two
- #
- # If you do not give "--one" and "--two" AtLeastOneRequiredArgumentError
- # will be raised.
- #
- # You can use at_least_one and exclusive at the same time.
- #
- # exclusive do
- # at_least_one do
- # option :one
- # option :two
- # end
- # end
- #
- # Then it is required either only one of "--one" or "--two".
- #
- def method_at_least_one(*args, &block)
- register_options_relation_for(:method_options,
- :method_at_least_one_option_names, *args, &block)
- end
- alias_method :at_least_one, :method_at_least_one
-
# Prints help information for the given command.
#
# ==== Parameters
@@ -264,16 +178,9 @@ class Bundler::Thor
shell.say " #{banner(command).split("\n").join("\n ")}"
shell.say
class_options_help(shell, nil => command.options.values)
- print_exclusive_options(shell, command)
- print_at_least_one_required_options(shell, command)
-
if command.long_description
shell.say "Description:"
- if command.wrap_long_description
- shell.print_wrapped(command.long_description, indent: 2)
- else
- shell.say command.long_description
- end
+ shell.print_wrapped(command.long_description, :indent => 2)
else
shell.say command.description
end
@@ -290,7 +197,7 @@ class Bundler::Thor
Bundler::Thor::Util.thor_classes_in(self).each do |klass|
list += klass.printable_commands(false)
end
- sort_commands!(list)
+ list.sort! { |a, b| a[0] <=> b[0] }
if defined?(@package_name) && @package_name
shell.say "#{@package_name} commands:"
@@ -298,11 +205,9 @@ class Bundler::Thor
shell.say "Commands:"
end
- shell.print_table(list, indent: 2, truncate: true)
+ shell.print_table(list, :indent => 2, :truncate => true)
shell.say
class_options_help(shell)
- print_exclusive_options(shell)
- print_at_least_one_required_options(shell)
end
# Returns commands ready to be printed.
@@ -333,7 +238,7 @@ class Bundler::Thor
define_method(subcommand) do |*args|
args, opts = Bundler::Thor::Arguments.split(args)
- invoke_args = [args, opts, {invoked_via_subcommand: true, class_options: options}]
+ invoke_args = [args, opts, {:invoked_via_subcommand => true, :class_options => options}]
invoke_args.unshift "help" if opts.delete("--help") || opts.delete("-h")
invoke subcommand_class, *invoke_args
end
@@ -441,24 +346,6 @@ class Bundler::Thor
protected
- # Returns this class exclusive options array set.
- #
- # ==== Returns
- # Array[Array[Bundler::Thor::Option.name]]
- #
- def method_exclusive_option_names #:nodoc:
- @method_exclusive_option_names ||= []
- end
-
- # Returns this class at least one of required options array set.
- #
- # ==== Returns
- # Array[Array[Bundler::Thor::Option.name]]
- #
- def method_at_least_one_option_names #:nodoc:
- @method_at_least_one_option_names ||= []
- end
-
def stop_on_unknown_option #:nodoc:
@stop_on_unknown_option ||= []
end
@@ -468,30 +355,8 @@ class Bundler::Thor
@disable_required_check ||= [:help]
end
- def print_exclusive_options(shell, command = nil) # :nodoc:
- opts = []
- opts = command.method_exclusive_option_names unless command.nil?
- opts += class_exclusive_option_names
- unless opts.empty?
- shell.say "Exclusive Options:"
- shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 )
- shell.say
- end
- end
-
- def print_at_least_one_required_options(shell, command = nil) # :nodoc:
- opts = []
- opts = command.method_at_least_one_option_names unless command.nil?
- opts += class_at_least_one_option_names
- unless opts.empty?
- shell.say "Required At Least One:"
- shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 )
- shell.say
- end
- end
-
# The method responsible for dispatching given the args.
- def dispatch(meth, given_args, given_opts, config) #:nodoc:
+ def dispatch(meth, given_args, given_opts, config) #:nodoc: # rubocop:disable MethodLength
meth ||= retrieve_command_name(given_args)
command = all_commands[normalize_command_name(meth)]
@@ -550,16 +415,12 @@ class Bundler::Thor
@usage ||= nil
@desc ||= nil
@long_desc ||= nil
- @long_desc_wrap ||= nil
@hide ||= nil
if @usage && @desc
base_class = @hide ? Bundler::Thor::HiddenCommand : Bundler::Thor::Command
- relations = {exclusive_option_names: method_exclusive_option_names,
- at_least_one_option_names: method_at_least_one_option_names}
- commands[meth] = base_class.new(meth, @desc, @long_desc, @long_desc_wrap, @usage, method_options, relations)
- @usage, @desc, @long_desc, @long_desc_wrap, @method_options, @hide = nil
- @method_exclusive_option_names, @method_at_least_one_option_names = nil
+ commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
+ @usage, @desc, @long_desc, @method_options, @hide = nil
true
elsif all_commands[meth] || meth == "method_missing"
true
@@ -634,14 +495,6 @@ class Bundler::Thor
"
end
alias_method :subtask_help, :subcommand_help
-
- # Sort the commands, lexicographically by default.
- #
- # Can be overridden in the subclass to change the display order of the
- # commands.
- def sort_commands!(list)
- list.sort! { |a, b| a[0] <=> b[0] }
- end
end
include Bundler::Thor::Base
diff --git a/lib/bundler/vendor/thor/lib/thor/actions.rb b/lib/bundler/vendor/thor/lib/thor/actions.rb
index ca58182691..de9b3b4c86 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions.rb
@@ -46,17 +46,17 @@ class Bundler::Thor
# Add runtime options that help actions execution.
#
def add_runtime_options!
- class_option :force, type: :boolean, aliases: "-f", group: :runtime,
- desc: "Overwrite files that already exist"
+ class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
+ :desc => "Overwrite files that already exist"
- class_option :pretend, type: :boolean, aliases: "-p", group: :runtime,
- desc: "Run but do not make any changes"
+ class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
+ :desc => "Run but do not make any changes"
- class_option :quiet, type: :boolean, aliases: "-q", group: :runtime,
- desc: "Suppress status output"
+ class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
+ :desc => "Suppress status output"
- class_option :skip, type: :boolean, aliases: "-s", group: :runtime,
- desc: "Skip files that already exist"
+ class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
+ :desc => "Skip files that already exist"
end
end
@@ -113,9 +113,9 @@ class Bundler::Thor
#
def relative_to_original_destination_root(path, remove_dot = true)
root = @destination_stack[0]
- if path.start_with?(root) && [File::SEPARATOR, File::ALT_SEPARATOR, nil, ""].include?(path[root.size..root.size])
+ if path.start_with?(root) && [File::SEPARATOR, File::ALT_SEPARATOR, nil, ''].include?(path[root.size..root.size])
path = path.dup
- path[0...root.size] = "."
+ path[0...root.size] = '.'
remove_dot ? (path[2..-1] || "") : path
else
path
@@ -175,7 +175,7 @@ class Bundler::Thor
shell.padding += 1 if verbose
@destination_stack.push File.expand_path(dir, destination_root)
- # If the directory doesn't exist and we're not pretending
+ # If the directory doesnt exist and we're not pretending
if !File.exist?(destination_root) && !pretend
require "fileutils"
FileUtils.mkdir_p(destination_root)
@@ -225,7 +225,7 @@ class Bundler::Thor
require "open-uri"
URI.open(path, "Accept" => "application/x-thor-template", &:read)
else
- File.open(path, &:read)
+ open(path, &:read)
end
instance_eval(contents, path)
@@ -284,7 +284,7 @@ class Bundler::Thor
#
def run_ruby_script(command, config = {})
return unless behavior == :invoke
- run command, config.merge(with: Bundler::Thor::Util.ruby_command)
+ run command, config.merge(:with => Bundler::Thor::Util.ruby_command)
end
# Run a thor command. A hash of options can be given and it's converted to
@@ -315,7 +315,7 @@ class Bundler::Thor
args.push Bundler::Thor::Options.to_switches(config)
command = args.join(" ").strip
- run command, with: :thor, verbose: verbose, pretend: pretend, capture: capture
+ run command, :with => :thor, :verbose => verbose, :pretend => pretend, :capture => capture
end
protected
@@ -323,7 +323,7 @@ class Bundler::Thor
# Allow current root to be shared between invocations.
#
def _shared_configuration #:nodoc:
- super.merge!(destination_root: destination_root)
+ super.merge!(:destination_root => destination_root)
end
def _cleanup_options_and_set(options, key) #:nodoc:
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb b/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb
index 6724835b01..330fc08cae 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb
@@ -43,8 +43,7 @@ class Bundler::Thor
# Boolean:: true if it is identical, false otherwise.
#
def identical?
- # binread uses ASCII-8BIT, so to avoid false negatives, the string must use the same
- exists? && File.binread(destination) == String.new(render).force_encoding("ASCII-8BIT")
+ exists? && File.binread(destination) == render
end
# Holds the content to be added to the file.
@@ -61,7 +60,7 @@ class Bundler::Thor
invoke_with_conflict_check do
require "fileutils"
FileUtils.mkdir_p(File.dirname(destination))
- File.open(destination, "wb", config[:perm]) { |f| f.write render }
+ File.open(destination, "wb") { |f| f.write render }
end
given_destination
end
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/directory.rb b/lib/bundler/vendor/thor/lib/thor/actions/directory.rb
index 2f9687c0a5..d37327a139 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions/directory.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions/directory.rb
@@ -58,7 +58,7 @@ class Bundler::Thor
def initialize(base, source, destination = nil, config = {}, &block)
@source = File.expand_path(Dir[Util.escape_globs(base.find_in_source_paths(source.to_s))].first)
@block = block
- super(base, destination, {recursive: true}.merge(config))
+ super(base, destination, {:recursive => true}.merge(config))
end
def invoke!
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb b/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb
index c0bca78525..284d92c19a 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb
@@ -33,7 +33,7 @@ class Bundler::Thor
#
def initialize(base, destination, config = {})
@base = base
- @config = {verbose: true}.merge(config)
+ @config = {:verbose => true}.merge(config)
self.destination = destination
end
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb b/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb
index 80a0255996..bf2a737c84 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb
@@ -66,15 +66,12 @@ class Bundler::Thor
# ==== Parameters
# source<String>:: the address of the given content.
# destination<String>:: the relative path to the destination root.
- # config<Hash>:: give :verbose => false to not log the status, and
- # :http_headers => <Hash> to add headers to an http request.
+ # config<Hash>:: give :verbose => false to not log the status.
#
# ==== Examples
#
# get "http://gist.github.com/103208", "doc/README"
#
- # get "http://gist.github.com/103208", "doc/README", :http_headers => {"Content-Type" => "application/json"}
- #
# get "http://gist.github.com/103208" do |content|
# content.split("\n").first
# end
@@ -85,10 +82,10 @@ class Bundler::Thor
render = if source =~ %r{^https?\://}
require "open-uri"
- URI.send(:open, source, config.fetch(:http_headers, {})) { |input| input.binmode.read }
+ URI.send(:open, source) { |input| input.binmode.read }
else
source = File.expand_path(find_in_source_paths(source.to_s))
- File.open(source) { |input| input.binmode.read }
+ open(source) { |input| input.binmode.read }
end
destination ||= if block_given?
@@ -123,7 +120,12 @@ class Bundler::Thor
context = config.delete(:context) || instance_eval("binding")
create_file destination, nil, config do
- capturable_erb = CapturableERB.new(::File.binread(source), trim_mode: "-", eoutvar: "@output_buffer")
+ match = ERB.version.match(/(\d+\.\d+\.\d+)/)
+ capturable_erb = if match && match[1] >= "2.2.0" # Ruby 2.6+
+ CapturableERB.new(::File.binread(source), :trim_mode => "-", :eoutvar => "@output_buffer")
+ else
+ CapturableERB.new(::File.binread(source), nil, "-", "@output_buffer")
+ end
content = capturable_erb.tap do |erb|
erb.filename = source
end.result(context)
@@ -250,7 +252,7 @@ class Bundler::Thor
# flag<Regexp|String>:: the regexp or string to be replaced
# replacement<String>:: the replacement, can be also given as a block
# config<Hash>:: give :verbose => false to not log the status, and
- # :force => true, to force the replacement regardless of runner behavior.
+ # :force => true, to force the replacement regardles of runner behavior.
#
# ==== Example
#
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb b/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb
index 70526e615f..bf013307f1 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb
@@ -21,7 +21,7 @@ class Bundler::Thor
# gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
# end
#
- WARNINGS = {unchanged_no_flag: "File unchanged! Either the supplied flag value not found or the content has already been inserted!"}
+ WARNINGS = { unchanged_no_flag: 'File unchanged! The supplied flag value not found!' }
def insert_into_file(destination, *args, &block)
data = block_given? ? block : args.shift
@@ -37,7 +37,7 @@ class Bundler::Thor
attr_reader :replacement, :flag, :behavior
def initialize(base, destination, data, config)
- super(base, destination, {verbose: true}.merge(config))
+ super(base, destination, {:verbose => true}.merge(config))
@behavior, @flag = if @config.key?(:after)
[:after, @config.delete(:after)]
@@ -59,8 +59,6 @@ class Bundler::Thor
if exists?
if replace!(/#{flag}/, content, config[:force])
say_status(:invoke)
- elsif replacement_present?
- say_status(:unchanged, color: :blue)
else
say_status(:unchanged, warning: WARNINGS[:unchanged_no_flag], color: :red)
end
@@ -98,8 +96,6 @@ class Bundler::Thor
end
elsif warning
warning
- elsif behavior == :unchanged
- :unchanged
else
:subtract
end
@@ -107,18 +103,11 @@ class Bundler::Thor
super(status, (color || config[:verbose]))
end
- def content
- @content ||= File.read(destination)
- end
-
- def replacement_present?
- content.include?(replacement)
- end
-
# Adds the content to the file.
#
def replace!(regexp, string, force)
- if force || !replacement_present?
+ content = File.read(destination)
+ if force || !content.include?(replacement)
success = content.gsub!(regexp, string)
File.open(destination, "wb") { |file| file.write(content) } unless pretend?
diff --git a/lib/bundler/vendor/thor/lib/thor/base.rb b/lib/bundler/vendor/thor/lib/thor/base.rb
index b156899c1e..8487f9590a 100644
--- a/lib/bundler/vendor/thor/lib/thor/base.rb
+++ b/lib/bundler/vendor/thor/lib/thor/base.rb
@@ -24,9 +24,9 @@ class Bundler::Thor
class << self
def deprecation_warning(message) #:nodoc:
- unless ENV["THOR_SILENCE_DEPRECATION"]
+ unless ENV['THOR_SILENCE_DEPRECATION']
warn "Deprecation warning: #{message}\n" +
- "You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION."
+ 'You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.'
end
end
end
@@ -60,7 +60,6 @@ class Bundler::Thor
command_options = config.delete(:command_options) # hook for start
parse_options = parse_options.merge(command_options) if command_options
-
if local_options.is_a?(Array)
array_options = local_options
hash_options = {}
@@ -74,24 +73,9 @@ class Bundler::Thor
# Let Bundler::Thor::Options parse the options first, so it can remove
# declared options from the array. This will leave us with
# a list of arguments that weren't declared.
- current_command = config[:current_command]
- stop_on_unknown = self.class.stop_on_unknown_option? current_command
-
- # Give a relation of options.
- # After parsing, Bundler::Thor::Options check whether right relations are kept
- relations = if current_command.nil?
- {exclusive_option_names: [], at_least_one_option_names: []}
- else
- current_command.options_relation
- end
-
- self.class.class_exclusive_option_names.map { |n| relations[:exclusive_option_names] << n }
- self.class.class_at_least_one_option_names.map { |n| relations[:at_least_one_option_names] << n }
-
- disable_required_check = self.class.disable_required_check? current_command
-
- opts = Bundler::Thor::Options.new(parse_options, hash_options, stop_on_unknown, disable_required_check, relations)
-
+ stop_on_unknown = self.class.stop_on_unknown_option? config[:current_command]
+ disable_required_check = self.class.disable_required_check? config[:current_command]
+ opts = Bundler::Thor::Options.new(parse_options, hash_options, stop_on_unknown, disable_required_check)
self.options = opts.parse(array_options)
self.options = config[:class_options].merge(options) if config[:class_options]
@@ -326,92 +310,9 @@ class Bundler::Thor
# :hide:: -- If you want to hide this option from the help.
#
def class_option(name, options = {})
- unless [ Symbol, String ].any? { |klass| name.is_a?(klass) }
- raise ArgumentError, "Expected a Symbol or String, got #{name.inspect}"
- end
build_option(name, options, class_options)
end
- # Adds and declares option group for exclusive options in the
- # block and arguments. You can declare options as the outside of the block.
- #
- # ==== Parameters
- # Array[Bundler::Thor::Option.name]
- #
- # ==== Examples
- #
- # class_exclusive do
- # class_option :one
- # class_option :two
- # end
- #
- # Or
- #
- # class_option :one
- # class_option :two
- # class_exclusive :one, :two
- #
- # If you give "--one" and "--two" at the same time ExclusiveArgumentsError
- # will be raised.
- #
- def class_exclusive(*args, &block)
- register_options_relation_for(:class_options,
- :class_exclusive_option_names, *args, &block)
- end
-
- # Adds and declares option group for required at least one of options in the
- # block and arguments. You can declare options as the outside of the block.
- #
- # ==== Examples
- #
- # class_at_least_one do
- # class_option :one
- # class_option :two
- # end
- #
- # Or
- #
- # class_option :one
- # class_option :two
- # class_at_least_one :one, :two
- #
- # If you do not give "--one" and "--two" AtLeastOneRequiredArgumentError
- # will be raised.
- #
- # You can use class_at_least_one and class_exclusive at the same time.
- #
- # class_exclusive do
- # class_at_least_one do
- # class_option :one
- # class_option :two
- # end
- # end
- #
- # Then it is required either only one of "--one" or "--two".
- #
- def class_at_least_one(*args, &block)
- register_options_relation_for(:class_options,
- :class_at_least_one_option_names, *args, &block)
- end
-
- # Returns this class exclusive options array set, looking up in the ancestors chain.
- #
- # ==== Returns
- # Array[Array[Bundler::Thor::Option.name]]
- #
- def class_exclusive_option_names
- @class_exclusive_option_names ||= from_superclass(:class_exclusive_option_names, [])
- end
-
- # Returns this class at least one of required options array set, looking up in the ancestors chain.
- #
- # ==== Returns
- # Array[Array[Bundler::Thor::Option.name]]
- #
- def class_at_least_one_option_names
- @class_at_least_one_option_names ||= from_superclass(:class_at_least_one_option_names, [])
- end
-
# Removes a previous defined argument. If :undefine is given, undefine
# accessors as well.
#
@@ -605,7 +506,7 @@ class Bundler::Thor
#
def public_command(*names)
names.each do |name|
- class_eval "def #{name}(*); super end", __FILE__, __LINE__
+ class_eval "def #{name}(*); super end"
end
end
alias_method :public_task, :public_command
@@ -657,19 +558,20 @@ class Bundler::Thor
return if options.empty?
list = []
- padding = options.map { |o| o.aliases_for_usage.size }.max.to_i
+ padding = options.map { |o| o.aliases.size }.max.to_i * 4
+
options.each do |option|
next if option.hide
item = [option.usage(padding)]
item.push(option.description ? "# #{option.description}" : "")
list << item
- list << ["", "# Default: #{option.print_default}"] if option.show_default?
- list << ["", "# Possible values: #{option.enum_to_s}"] if option.enum
+ list << ["", "# Default: #{option.default}"] if option.show_default?
+ list << ["", "# Possible values: #{option.enum.join(', ')}"] if option.enum
end
shell.say(group_name ? "#{group_name} options:" : "Options:")
- shell.print_table(list, indent: 2)
+ shell.print_table(list, :indent => 2)
shell.say ""
end
@@ -686,7 +588,7 @@ class Bundler::Thor
# options<Hash>:: Described in both class_option and method_option.
# scope<Hash>:: Options hash that is being built up
def build_option(name, options, scope) #:nodoc:
- scope[name] = Bundler::Thor::Option.new(name, {check_default_type: check_default_type}.merge!(options))
+ scope[name] = Bundler::Thor::Option.new(name, {:check_default_type => check_default_type}.merge!(options))
end
# Receives a hash of options, parse them and add to the scope. This is a
@@ -708,7 +610,7 @@ class Bundler::Thor
def find_and_refresh_command(name) #:nodoc:
if commands[name.to_s]
commands[name.to_s]
- elsif command = all_commands[name.to_s] # rubocop:disable Lint/AssignmentInCondition
+ elsif command = all_commands[name.to_s] # rubocop:disable AssignmentInCondition
commands[name.to_s] = command.clone
else
raise ArgumentError, "You supplied :for => #{name.inspect}, but the command #{name.inspect} could not be found."
@@ -716,7 +618,7 @@ class Bundler::Thor
end
alias_method :find_and_refresh_task, :find_and_refresh_command
- # Every time someone inherits from a Bundler::Thor class, register the klass
+ # Everytime someone inherits from a Bundler::Thor class, register the klass
# and file into baseclass.
def inherited(klass)
super(klass)
@@ -792,34 +694,6 @@ class Bundler::Thor
def dispatch(command, given_args, given_opts, config) #:nodoc:
raise NotImplementedError
end
-
- # Register a relation of options for target(method_option/class_option)
- # by args and block.
- def register_options_relation_for(target, relation, *args, &block) # :nodoc:
- opt = args.pop if args.last.is_a? Hash
- opt ||= {}
- names = args.map{ |arg| arg.to_s }
- names += built_option_names(target, opt, &block) if block_given?
- command_scope_member(relation, opt) << names
- end
-
- # Get target(method_options or class_options) options
- # of before and after by block evaluation.
- def built_option_names(target, opt = {}, &block) # :nodoc:
- before = command_scope_member(target, opt).map{ |k,v| v.name }
- instance_eval(&block)
- after = command_scope_member(target, opt).map{ |k,v| v.name }
- after - before
- end
-
- # Get command scope member by name.
- def command_scope_member(name, options = {}) # :nodoc:
- if options[:for]
- find_and_refresh_command(options[:for]).send(name)
- else
- send(name)
- end
- end
end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/command.rb b/lib/bundler/vendor/thor/lib/thor/command.rb
index 68c8fffedb..040c971c0c 100644
--- a/lib/bundler/vendor/thor/lib/thor/command.rb
+++ b/lib/bundler/vendor/thor/lib/thor/command.rb
@@ -1,15 +1,14 @@
class Bundler::Thor
- class Command < Struct.new(:name, :description, :long_description, :wrap_long_description, :usage, :options, :options_relation, :ancestor_name)
+ class Command < Struct.new(:name, :description, :long_description, :usage, :options, :ancestor_name)
FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/
- def initialize(name, description, long_description, wrap_long_description, usage, options = nil, options_relation = nil)
- super(name.to_s, description, long_description, wrap_long_description, usage, options || {}, options_relation || {})
+ def initialize(name, description, long_description, usage, options = nil)
+ super(name.to_s, description, long_description, usage, options || {})
end
def initialize_copy(other) #:nodoc:
super(other)
self.options = other.options.dup if other.options
- self.options_relation = other.options_relation.dup if other.options_relation
end
def hidden?
@@ -63,14 +62,6 @@ class Bundler::Thor
end.join("\n")
end
- def method_exclusive_option_names #:nodoc:
- self.options_relation[:exclusive_option_names] || []
- end
-
- def method_at_least_one_option_names #:nodoc:
- self.options_relation[:at_least_one_option_names] || []
- end
-
protected
# Add usage with required arguments
@@ -136,7 +127,7 @@ class Bundler::Thor
# A dynamic command that handles method missing scenarios.
class DynamicCommand < Command
def initialize(name, options = nil)
- super(name.to_s, "A dynamically-generated command", name.to_s, nil, name.to_s, options)
+ super(name.to_s, "A dynamically-generated command", name.to_s, name.to_s, options)
end
def run(instance, args = [])
diff --git a/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb b/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb
index b16a98f782..3c4483e5dd 100644
--- a/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb
+++ b/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb
@@ -38,10 +38,6 @@ class Bundler::Thor
super(convert_key(key), *args)
end
- def slice(*keys)
- super(*keys.map{ |key| convert_key(key) })
- end
-
def key?(key)
super(convert_key(key))
end
diff --git a/lib/bundler/vendor/thor/lib/thor/error.rb b/lib/bundler/vendor/thor/lib/thor/error.rb
index 928646e501..03f2ce85bb 100644
--- a/lib/bundler/vendor/thor/lib/thor/error.rb
+++ b/lib/bundler/vendor/thor/lib/thor/error.rb
@@ -1,15 +1,18 @@
class Bundler::Thor
Correctable = if defined?(DidYouMean::SpellChecker) && defined?(DidYouMean::Correctable) # rubocop:disable Naming/ConstantName
- Module.new do
- def to_s
- super + DidYouMean.formatter.message_for(corrections)
- end
-
- def corrections
- @corrections ||= self.class.const_get(:SpellChecker).new(self).corrections
- end
- end
- end
+ # In order to support versions of Ruby that don't have keyword
+ # arguments, we need our own spell checker class that doesn't take key
+ # words. Even though this code wouldn't be hit because of the check
+ # above, it's still necessary because the interpreter would otherwise be
+ # unable to parse the file.
+ class NoKwargSpellChecker < DidYouMean::SpellChecker # :nodoc:
+ def initialize(dictionary)
+ @dictionary = dictionary
+ end
+ end
+
+ DidYouMean::Correctable
+ end
# Bundler::Thor::Error is raised when it's caused by wrong usage of thor classes. Those
# errors have their backtrace suppressed and are nicely shown to the user.
@@ -34,7 +37,7 @@ class Bundler::Thor
end
def spell_checker
- DidYouMean::SpellChecker.new(dictionary: error.all_commands)
+ NoKwargSpellChecker.new(error.all_commands)
end
end
@@ -76,7 +79,7 @@ class Bundler::Thor
end
def spell_checker
- @spell_checker ||= DidYouMean::SpellChecker.new(dictionary: error.switches)
+ @spell_checker ||= NoKwargSpellChecker.new(error.switches)
end
end
@@ -98,9 +101,15 @@ class Bundler::Thor
class MalformattedArgumentError < InvocationError
end
- class ExclusiveArgumentError < InvocationError
- end
-
- class AtLeastOneRequiredArgumentError < InvocationError
+ if Correctable
+ if DidYouMean.respond_to?(:correct_error)
+ DidYouMean.correct_error(Bundler::Thor::UndefinedCommandError, UndefinedCommandError::SpellChecker)
+ DidYouMean.correct_error(Bundler::Thor::UnknownArgumentError, UnknownArgumentError::SpellChecker)
+ else
+ DidYouMean::SPELL_CHECKERS.merge!(
+ 'Bundler::Thor::UndefinedCommandError' => UndefinedCommandError::SpellChecker,
+ 'Bundler::Thor::UnknownArgumentError' => UnknownArgumentError::SpellChecker
+ )
+ end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/group.rb b/lib/bundler/vendor/thor/lib/thor/group.rb
index 7ea11e8f93..7861d05345 100644
--- a/lib/bundler/vendor/thor/lib/thor/group.rb
+++ b/lib/bundler/vendor/thor/lib/thor/group.rb
@@ -169,7 +169,7 @@ class Bundler::Thor::Group
# options are added to group_options hash. Options that already exists
# in base_options are not added twice.
#
- def get_options_from_invocations(group_options, base_options) #:nodoc:
+ def get_options_from_invocations(group_options, base_options) #:nodoc: # rubocop:disable MethodLength
invocations.each do |name, from_option|
value = if from_option
option = class_options[name]
diff --git a/lib/bundler/vendor/thor/lib/thor/invocation.rb b/lib/bundler/vendor/thor/lib/thor/invocation.rb
index 5ce74710ba..248a466f8e 100644
--- a/lib/bundler/vendor/thor/lib/thor/invocation.rb
+++ b/lib/bundler/vendor/thor/lib/thor/invocation.rb
@@ -143,7 +143,7 @@ class Bundler::Thor
# Configuration values that are shared between invocations.
def _shared_configuration #:nodoc:
- {invocations: @_invocations}
+ {:invocations => @_invocations}
end
# This method simply retrieves the class and command to be invoked.
diff --git a/lib/bundler/vendor/thor/lib/thor/nested_context.rb b/lib/bundler/vendor/thor/lib/thor/nested_context.rb
index 7d60cb1c12..fd36b9d43f 100644
--- a/lib/bundler/vendor/thor/lib/thor/nested_context.rb
+++ b/lib/bundler/vendor/thor/lib/thor/nested_context.rb
@@ -13,10 +13,10 @@ class Bundler::Thor
end
def entered?
- @depth.positive?
+ @depth > 0
end
- private
+ private
def push
@depth += 1
diff --git a/lib/bundler/vendor/thor/lib/thor/parser/argument.rb b/lib/bundler/vendor/thor/lib/thor/parser/argument.rb
index b9e94e4669..dfe7398583 100644
--- a/lib/bundler/vendor/thor/lib/thor/parser/argument.rb
+++ b/lib/bundler/vendor/thor/lib/thor/parser/argument.rb
@@ -24,17 +24,6 @@ class Bundler::Thor
validate! # Trigger specific validations
end
- def print_default
- if @type == :array and @default.is_a?(Array)
- @default.map { |x|
- p = x.gsub('"','\\"')
- "\"#{p}\""
- }.join(" ")
- else
- @default
- end
- end
-
def usage
required? ? banner : "[#{banner}]"
end
@@ -52,19 +41,11 @@ class Bundler::Thor
end
end
- def enum_to_s
- if enum.respond_to? :join
- enum.join(", ")
- else
- "#{enum.first}..#{enum.last}"
- end
- end
-
protected
def validate!
raise ArgumentError, "An argument cannot be required and have default value." if required? && !default.nil?
- raise ArgumentError, "An argument cannot have an enum other than an enumerable." if @enum && !@enum.is_a?(Enumerable)
+ raise ArgumentError, "An argument cannot have an enum other than an array." if @enum && !@enum.is_a?(Array)
end
def valid_type?(type)
diff --git a/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb b/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb
index b6f9c9a37a..3a5d82cf29 100644
--- a/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb
+++ b/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb
@@ -1,5 +1,5 @@
class Bundler::Thor
- class Arguments #:nodoc:
+ class Arguments #:nodoc: # rubocop:disable ClassLength
NUMERIC = /[-+]?(\d*\.\d+|\d+)/
# Receives an array of args and returns two arrays, one with arguments
@@ -30,7 +30,11 @@ class Bundler::Thor
arguments.each do |argument|
if !argument.default.nil?
- @assigns[argument.human_name] = argument.default.dup
+ begin
+ @assigns[argument.human_name] = argument.default.dup
+ rescue TypeError # Compatibility shim for un-dup-able Fixnum in Ruby < 2.4
+ @assigns[argument.human_name] = argument.default
+ end
elsif argument.required?
@non_assigned_required << argument
end
@@ -117,18 +121,8 @@ class Bundler::Thor
#
def parse_array(name)
return shift if peek.is_a?(Array)
-
array = []
-
- while current_is_value?
- value = shift
-
- if !value.empty?
- validate_enum_value!(name, value, "Expected all values of '%s' to be one of %s; got %s")
- end
-
- array << value
- end
+ array << shift while current_is_value?
array
end
@@ -144,9 +138,11 @@ class Bundler::Thor
end
value = $&.index(".") ? shift.to_f : shift.to_i
-
- validate_enum_value!(name, value, "Expected '%s' to be one of %s; got %s")
-
+ if @switches.is_a?(Hash) && switch = @switches[name]
+ if switch.enum && !switch.enum.include?(value)
+ raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}"
+ end
+ end
value
end
@@ -160,27 +156,15 @@ class Bundler::Thor
nil
else
value = shift
-
- validate_enum_value!(name, value, "Expected '%s' to be one of %s; got %s")
-
+ if @switches.is_a?(Hash) && switch = @switches[name]
+ if switch.enum && !switch.enum.include?(value)
+ raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}"
+ end
+ end
value
end
end
- # Raises an error if the switch is an enum and the values aren't included on it.
- #
- def validate_enum_value!(name, value, message)
- return unless @switches.is_a?(Hash)
-
- switch = @switches[name]
-
- return unless switch
-
- if switch.enum && !switch.enum.include?(value)
- raise MalformattedArgumentError, message % [name, switch.enum_to_s, value]
- end
- end
-
# Raises an error if @non_assigned_required array is not empty.
#
def check_requirement!
diff --git a/lib/bundler/vendor/thor/lib/thor/parser/option.rb b/lib/bundler/vendor/thor/lib/thor/parser/option.rb
index c6af4e1e87..5a5af6f888 100644
--- a/lib/bundler/vendor/thor/lib/thor/parser/option.rb
+++ b/lib/bundler/vendor/thor/lib/thor/parser/option.rb
@@ -11,7 +11,7 @@ class Bundler::Thor
super
@lazy_default = options[:lazy_default]
@group = options[:group].to_s.capitalize if options[:group]
- @aliases = normalize_aliases(options[:aliases])
+ @aliases = Array(options[:aliases])
@hide = options[:hide]
end
@@ -58,7 +58,7 @@ class Bundler::Thor
default = nil
if VALID_TYPES.include?(value)
value
- elsif required = (value == :required) # rubocop:disable Lint/AssignmentInCondition
+ elsif required = (value == :required) # rubocop:disable AssignmentInCondition
:string
end
when TrueClass, FalseClass
@@ -69,7 +69,7 @@ class Bundler::Thor
value.class.name.downcase.to_sym
end
- new(name.to_s, required: required, type: type, default: default, aliases: aliases)
+ new(name.to_s, :required => required, :type => type, :default => default, :aliases => aliases)
end
def switch_name
@@ -90,26 +90,13 @@ class Bundler::Thor
sample = "[#{sample}]".dup unless required?
if boolean?
- sample << ", [#{dasherize('no-' + human_name)}]" unless (name == "force") || name.match(/\Ano[\-_]/)
+ sample << ", [#{dasherize('no-' + human_name)}]" unless (name == "force") || name.start_with?("no-")
end
- aliases_for_usage.ljust(padding) + sample
- end
-
- def aliases_for_usage
if aliases.empty?
- ""
- else
- "#{aliases.join(', ')}, "
- end
- end
-
- def show_default?
- case default
- when TrueClass, FalseClass
- true
+ (" " * padding) << sample
else
- super
+ "#{aliases.join(', ')}, #{sample}"
end
end
@@ -151,8 +138,8 @@ class Bundler::Thor
raise ArgumentError, err
elsif @check_default_type == nil
Bundler::Thor.deprecation_warning "#{err}.\n" +
- "This will be rejected in the future unless you explicitly pass the options `check_default_type: false`" +
- " or call `allow_incompatible_default_type!` in your code"
+ 'This will be rejected in the future unless you explicitly pass the options `check_default_type: false`' +
+ ' or call `allow_incompatible_default_type!` in your code'
end
end
end
@@ -168,11 +155,5 @@ class Bundler::Thor
def dasherize(str)
(str.length > 1 ? "--" : "-") + str.tr("_", "-")
end
-
- private
-
- def normalize_aliases(aliases)
- Array(aliases).map { |short| short.to_s.sub(/^(?!\-)/, "-") }
- end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/parser/options.rb b/lib/bundler/vendor/thor/lib/thor/parser/options.rb
index 978e76b132..5bd97aba6f 100644
--- a/lib/bundler/vendor/thor/lib/thor/parser/options.rb
+++ b/lib/bundler/vendor/thor/lib/thor/parser/options.rb
@@ -1,5 +1,5 @@
class Bundler::Thor
- class Options < Arguments #:nodoc:
+ class Options < Arguments #:nodoc: # rubocop:disable ClassLength
LONG_RE = /^(--\w+(?:-\w+)*)$/
SHORT_RE = /^(-[a-z])$/i
EQ_RE = /^(--\w+(?:-\w+)*|-[a-z])=(.*)$/i
@@ -29,10 +29,8 @@ class Bundler::Thor
#
# If +stop_on_unknown+ is true, #parse will stop as soon as it encounters
# an unknown option or a regular argument.
- def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false, relations = {})
+ def initialize(hash_options = {}, defaults = {}, stop_on_unknown = false, disable_required_check = false)
@stop_on_unknown = stop_on_unknown
- @exclusives = (relations[:exclusive_option_names] || []).select{|array| !array.empty?}
- @at_least_ones = (relations[:at_least_one_option_names] || []).select{|array| !array.empty?}
@disable_required_check = disable_required_check
options = hash_options.values
super(options)
@@ -52,7 +50,8 @@ class Bundler::Thor
options.each do |option|
@switches[option.switch_name] = option
- option.aliases.each do |name|
+ option.aliases.each do |short|
+ name = short.to_s.sub(/^(?!\-)/, "-")
@shorts[name] ||= option.switch_name
end
end
@@ -86,7 +85,7 @@ class Bundler::Thor
super(arg)
end
- def parse(args) # rubocop:disable Metrics/MethodLength
+ def parse(args) # rubocop:disable MethodLength
@pile = args.dup
@is_treated_as_value = false
@parsing_options = true
@@ -133,38 +132,12 @@ class Bundler::Thor
end
check_requirement! unless @disable_required_check
- check_exclusive!
- check_at_least_one!
assigns = Bundler::Thor::CoreExt::HashWithIndifferentAccess.new(@assigns)
assigns.freeze
assigns
end
- def check_exclusive!
- opts = @assigns.keys
- # When option A and B are exclusive, if A and B are given at the same time,
- # the diffrence of argument array size will decrease.
- found = @exclusives.find{ |ex| (ex - opts).size < ex.size - 1 }
- if found
- names = names_to_switch_names(found & opts).map{|n| "'#{n}'"}
- class_name = self.class.name.split("::").last.downcase
- fail ExclusiveArgumentError, "Found exclusive #{class_name} #{names.join(", ")}"
- end
- end
-
- def check_at_least_one!
- opts = @assigns.keys
- # When at least one is required of the options A and B,
- # if the both options were not given, none? would be true.
- found = @at_least_ones.find{ |one_reqs| one_reqs.none?{ |o| opts.include? o} }
- if found
- names = names_to_switch_names(found).map{|n| "'#{n}'"}
- class_name = self.class.name.split("::").last.downcase
- fail AtLeastOneRequiredArgumentError, "Not found at least one of required #{class_name} #{names.join(", ")}"
- end
- end
-
def check_unknown!
to_check = @stopped_parsing_after_extra_index ? @extra[0...@stopped_parsing_after_extra_index] : @extra
@@ -175,17 +148,6 @@ class Bundler::Thor
protected
- # Option names changes to swith name or human name
- def names_to_switch_names(names = [])
- @switches.map do |_, o|
- if names.include? o.name
- o.respond_to?(:switch_name) ? o.switch_name : o.human_name
- else
- nil
- end
- end.compact
- end
-
def assign_result!(option, result)
if option.repeatable && option.type == :hash
(@assigns[option.human_name] ||= {}).merge!(result)
@@ -232,7 +194,7 @@ class Bundler::Thor
end
def switch_option(arg)
- if match = no_or_skip?(arg) # rubocop:disable Lint/AssignmentInCondition
+ if match = no_or_skip?(arg) # rubocop:disable AssignmentInCondition
@switches[arg] || @switches["--#{match}"]
else
@switches[arg]
diff --git a/lib/bundler/vendor/thor/lib/thor/rake_compat.rb b/lib/bundler/vendor/thor/lib/thor/rake_compat.rb
index c6a4653fc1..f8f86372cc 100644
--- a/lib/bundler/vendor/thor/lib/thor/rake_compat.rb
+++ b/lib/bundler/vendor/thor/lib/thor/rake_compat.rb
@@ -41,7 +41,7 @@ instance_eval do
def task(*)
task = super
- if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable Lint/AssignmentInCondition
+ if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition
non_namespaced_name = task.name.split(":").last
description = non_namespaced_name
@@ -59,7 +59,7 @@ instance_eval do
end
def namespace(name)
- if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable Lint/AssignmentInCondition
+ if klass = Bundler::Thor::RakeCompat.rake_classes.last # rubocop:disable AssignmentInCondition
const_name = Bundler::Thor::Util.camel_case(name.to_s).to_sym
klass.const_set(const_name, Class.new(Bundler::Thor))
new_klass = klass.const_get(const_name)
diff --git a/lib/bundler/vendor/thor/lib/thor/runner.rb b/lib/bundler/vendor/thor/lib/thor/runner.rb
index c7cc873131..54c5525093 100644
--- a/lib/bundler/vendor/thor/lib/thor/runner.rb
+++ b/lib/bundler/vendor/thor/lib/thor/runner.rb
@@ -2,10 +2,12 @@ require_relative "../thor"
require_relative "group"
require "yaml"
-require "digest/sha2"
+require "digest/md5"
require "pathname"
-class Bundler::Thor::Runner < Bundler::Thor #:nodoc:
+class Bundler::Thor::Runner < Bundler::Thor #:nodoc: # rubocop:disable ClassLength
+ autoload :OpenURI, "open-uri"
+
map "-T" => :list, "-i" => :install, "-u" => :update, "-v" => :version
def self.banner(command, all = false, subcommand = false)
@@ -23,7 +25,7 @@ class Bundler::Thor::Runner < Bundler::Thor #:nodoc:
initialize_thorfiles(meth)
klass, command = Bundler::Thor::Util.find_class_and_command_by_namespace(meth)
self.class.handle_no_command_error(command, false) if klass.nil?
- klass.start(["-h", command].compact, shell: shell)
+ klass.start(["-h", command].compact, :shell => shell)
else
super
end
@@ -38,42 +40,30 @@ class Bundler::Thor::Runner < Bundler::Thor #:nodoc:
klass, command = Bundler::Thor::Util.find_class_and_command_by_namespace(meth)
self.class.handle_no_command_error(command, false) if klass.nil?
args.unshift(command) if command
- klass.start(args, shell: shell)
+ klass.start(args, :shell => shell)
end
desc "install NAME", "Install an optionally named Bundler::Thor file into your system commands"
- method_options as: :string, relative: :boolean, force: :boolean
- def install(name) # rubocop:disable Metrics/MethodLength
+ method_options :as => :string, :relative => :boolean, :force => :boolean
+ def install(name) # rubocop:disable MethodLength
initialize_thorfiles
- is_uri = name =~ %r{^https?\://}
-
- if is_uri
- base = name
- package = :file
- require "open-uri"
- begin
- contents = URI.open(name, &:read)
- rescue OpenURI::HTTPError
- raise Error, "Error opening URI '#{name}'"
- end
- else
- # If a directory name is provided as the argument, look for a 'main.thor'
- # command in said directory.
- begin
- if File.directory?(File.expand_path(name))
- base = File.join(name, "main.thor")
- package = :directory
- contents = File.open(base, &:read)
- else
- base = name
- package = :file
- require "open-uri"
- contents = URI.open(name, &:read)
- end
- rescue Errno::ENOENT
- raise Error, "Error opening file '#{name}'"
+ # If a directory name is provided as the argument, look for a 'main.thor'
+ # command in said directory.
+ begin
+ if File.directory?(File.expand_path(name))
+ base = File.join(name, "main.thor")
+ package = :directory
+ contents = open(base, &:read)
+ else
+ base = name
+ package = :file
+ contents = open(name, &:read)
end
+ rescue OpenURI::HTTPError
+ raise Error, "Error opening URI '#{name}'"
+ rescue Errno::ENOENT
+ raise Error, "Error opening file '#{name}'"
end
say "Your Thorfile contains:"
@@ -94,16 +84,16 @@ class Bundler::Thor::Runner < Bundler::Thor #:nodoc:
as = basename if as.empty?
end
- location = if options[:relative] || is_uri
+ location = if options[:relative] || name =~ %r{^https?://}
name
else
File.expand_path(name)
end
thor_yaml[as] = {
- filename: Digest::SHA256.hexdigest(name + as),
- location: location,
- namespaces: Bundler::Thor::Util.namespaces_in_content(contents, base)
+ :filename => Digest::MD5.hexdigest(name + as),
+ :location => location,
+ :namespaces => Bundler::Thor::Util.namespaces_in_content(contents, base)
}
save_yaml(thor_yaml)
@@ -164,14 +154,14 @@ class Bundler::Thor::Runner < Bundler::Thor #:nodoc:
end
desc "installed", "List the installed Bundler::Thor modules and commands"
- method_options internal: :boolean
+ method_options :internal => :boolean
def installed
initialize_thorfiles(nil, true)
display_klasses(true, options["internal"])
end
desc "list [SEARCH]", "List the available thor commands (--substring means .*SEARCH)"
- method_options substring: :boolean, group: :string, all: :boolean, debug: :boolean
+ method_options :substring => :boolean, :group => :string, :all => :boolean, :debug => :boolean
def list(search = "")
initialize_thorfiles
@@ -313,7 +303,7 @@ private
say shell.set_color(namespace, :blue, true)
say "-" * namespace.size
- print_table(list, truncate: true)
+ print_table(list, :truncate => true)
say
end
alias_method :display_tasks, :display_commands
diff --git a/lib/bundler/vendor/thor/lib/thor/shell.rb b/lib/bundler/vendor/thor/lib/thor/shell.rb
index 265f3ba046..a4137d1bde 100644
--- a/lib/bundler/vendor/thor/lib/thor/shell.rb
+++ b/lib/bundler/vendor/thor/lib/thor/shell.rb
@@ -75,7 +75,7 @@ class Bundler::Thor
# Allow shell to be shared between invocations.
#
def _shared_configuration #:nodoc:
- super.merge!(shell: shell)
+ super.merge!(:shell => shell)
end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/basic.rb b/lib/bundler/vendor/thor/lib/thor/shell/basic.rb
index dc3179e5f3..ef97d52ae7 100644
--- a/lib/bundler/vendor/thor/lib/thor/shell/basic.rb
+++ b/lib/bundler/vendor/thor/lib/thor/shell/basic.rb
@@ -1,10 +1,8 @@
-require_relative "column_printer"
-require_relative "table_printer"
-require_relative "wrapped_printer"
-
class Bundler::Thor
module Shell
class Basic
+ DEFAULT_TERMINAL_WIDTH = 80
+
attr_accessor :base
attr_reader :padding
@@ -147,14 +145,14 @@ class Bundler::Thor
# "yes".
#
def yes?(statement, color = nil)
- !!(ask(statement, color, add_to_history: false) =~ is?(:yes))
+ !!(ask(statement, color, :add_to_history => false) =~ is?(:yes))
end
# Make a question the to user and returns true if the user replies "n" or
# "no".
#
def no?(statement, color = nil)
- !!(ask(statement, color, add_to_history: false) =~ is?(:no))
+ !!(ask(statement, color, :add_to_history => false) =~ is?(:no))
end
# Prints values in columns
@@ -163,8 +161,16 @@ class Bundler::Thor
# Array[String, String, ...]
#
def print_in_columns(array)
- printer = ColumnPrinter.new(stdout)
- printer.print(array)
+ return if array.empty?
+ colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2
+ array.each_with_index do |value, index|
+ # Don't output trailing spaces when printing the last column
+ if ((((index + 1) % (terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
+ stdout.puts value
+ else
+ stdout.printf("%-#{colwidth}s", value)
+ end
+ end
end
# Prints a table.
@@ -175,11 +181,58 @@ class Bundler::Thor
# ==== Options
# indent<Integer>:: Indent the first column by indent value.
# colwidth<Integer>:: Force the first column to colwidth spaces wide.
- # borders<Boolean>:: Adds ascii borders.
#
- def print_table(array, options = {}) # rubocop:disable Metrics/MethodLength
- printer = TablePrinter.new(stdout, options)
- printer.print(array)
+ def print_table(array, options = {}) # rubocop:disable MethodLength
+ return if array.empty?
+
+ formats = []
+ indent = options[:indent].to_i
+ colwidth = options[:colwidth]
+ options[:truncate] = terminal_width if options[:truncate] == true
+
+ formats << "%-#{colwidth + 2}s".dup if colwidth
+ start = colwidth ? 1 : 0
+
+ colcount = array.max { |a, b| a.size <=> b.size }.size
+
+ maximas = []
+
+ start.upto(colcount - 1) do |index|
+ maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
+ maximas << maxima
+ formats << if index == colcount - 1
+ # Don't output 2 trailing spaces when printing the last column
+ "%-s".dup
+ else
+ "%-#{maxima + 2}s".dup
+ end
+ end
+
+ formats[0] = formats[0].insert(0, " " * indent)
+ formats << "%s"
+
+ array.each do |row|
+ sentence = "".dup
+
+ row.each_with_index do |column, index|
+ maxima = maximas[index]
+
+ f = if column.is_a?(Numeric)
+ if index == row.size - 1
+ # Don't output 2 trailing spaces when printing the last column
+ "%#{maxima}s"
+ else
+ "%#{maxima}s "
+ end
+ else
+ formats[index]
+ end
+ sentence << f % column.to_s
+ end
+
+ sentence = truncate(sentence, options[:truncate]) if options[:truncate]
+ stdout.puts sentence
+ end
end
# Prints a long string, word-wrapping the text to the current width of the
@@ -192,8 +245,33 @@ class Bundler::Thor
# indent<Integer>:: Indent each line of the printed paragraph by indent value.
#
def print_wrapped(message, options = {})
- printer = WrappedPrinter.new(stdout, options)
- printer.print(message)
+ indent = options[:indent] || 0
+ width = terminal_width - indent
+ paras = message.split("\n\n")
+
+ paras.map! do |unwrapped|
+ words = unwrapped.split(" ")
+ counter = words.first.length
+ words.inject do |memo, word|
+ word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
+ counter = 0 if word.include? "\n"
+ if (counter + word.length + 1) < width
+ memo = "#{memo} #{word}"
+ counter += (word.length + 1)
+ else
+ memo = "#{memo}\n#{word}"
+ counter = word.length
+ end
+ memo
+ end
+ end.compact!
+
+ paras.each do |para|
+ para.split("\n").each do |line|
+ stdout.puts line.insert(0, " " * indent)
+ end
+ stdout.puts unless para == paras.last
+ end
end
# Deals with file collision and returns true if the file should be
@@ -211,7 +289,7 @@ class Bundler::Thor
loop do
answer = ask(
%[Overwrite #{destination}? (enter "h" for help) #{options}],
- add_to_history: false
+ :add_to_history => false
)
case answer
@@ -238,11 +316,24 @@ class Bundler::Thor
say "Please specify merge tool to `THOR_MERGE` env."
else
- say file_collision_help(block_given?)
+ say file_collision_help
end
end
end
+ # This code was copied from Rake, available under MIT-LICENSE
+ # Copyright (c) 2003, 2004 Jim Weirich
+ def terminal_width
+ result = if ENV["THOR_COLUMNS"]
+ ENV["THOR_COLUMNS"].to_i
+ else
+ unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
+ end
+ result < 10 ? DEFAULT_TERMINAL_WIDTH : result
+ rescue
+ DEFAULT_TERMINAL_WIDTH
+ end
+
# Called if something goes wrong during the execution. This is used by Bundler::Thor
# internally and should not be used inside your scripts. If something went
# wrong, you can always raise an exception. If you raise a Bundler::Thor::Error, it
@@ -293,21 +384,16 @@ class Bundler::Thor
end
end
- def file_collision_help(block_given) #:nodoc:
- help = <<-HELP
+ def file_collision_help #:nodoc:
+ <<-HELP
Y - yes, overwrite
n - no, do not overwrite
a - all, overwrite this and all others
q - quit, abort
- h - help, show this help
- HELP
- if block_given
- help << <<-HELP
d - diff, show the differences between the old and the new
+ h - help, show this help
m - merge, run merge tool
- HELP
- end
- help
+ HELP
end
def show_diff(destination, content) #:nodoc:
@@ -325,8 +411,46 @@ class Bundler::Thor
mute? || (base && base.options[:quiet])
end
+ # Calculate the dynamic width of the terminal
+ def dynamic_width
+ @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
+ end
+
+ def dynamic_width_stty
+ `stty size 2>/dev/null`.split[1].to_i
+ end
+
+ def dynamic_width_tput
+ `tput cols 2>/dev/null`.to_i
+ end
+
def unix?
- Terminal.unix?
+ RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris)/i
+ end
+
+ def truncate(string, width)
+ as_unicode do
+ chars = string.chars.to_a
+ if chars.length <= width
+ chars.join
+ else
+ chars[0, width - 3].join + "..."
+ end
+ end
+ end
+
+ if "".respond_to?(:encode)
+ def as_unicode
+ yield
+ end
+ else
+ def as_unicode
+ old = $KCODE
+ $KCODE = "U"
+ yield
+ ensure
+ $KCODE = old
+ end
end
def ask_simply(statement, color, options)
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/color.rb b/lib/bundler/vendor/thor/lib/thor/shell/color.rb
index 5d708fadca..dc167ed3cc 100644
--- a/lib/bundler/vendor/thor/lib/thor/shell/color.rb
+++ b/lib/bundler/vendor/thor/lib/thor/shell/color.rb
@@ -105,7 +105,52 @@ class Bundler::Thor
end
def are_colors_disabled?
- !ENV["NO_COLOR"].nil? && !ENV["NO_COLOR"].empty?
+ !ENV['NO_COLOR'].nil?
+ end
+
+ # Overwrite show_diff to show diff with colors if Diff::LCS is
+ # available.
+ #
+ def show_diff(destination, content) #:nodoc:
+ if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
+ actual = File.binread(destination).to_s.split("\n")
+ content = content.to_s.split("\n")
+
+ Diff::LCS.sdiff(actual, content).each do |diff|
+ output_diff_line(diff)
+ end
+ else
+ super
+ end
+ end
+
+ def output_diff_line(diff) #:nodoc:
+ case diff.action
+ when "-"
+ say "- #{diff.old_element.chomp}", :red, true
+ when "+"
+ say "+ #{diff.new_element.chomp}", :green, true
+ when "!"
+ say "- #{diff.old_element.chomp}", :red, true
+ say "+ #{diff.new_element.chomp}", :green, true
+ else
+ say " #{diff.old_element.chomp}", nil, true
+ end
+ end
+
+ # Check if Diff::LCS is loaded. If it is, use it to create pretty output
+ # for diff.
+ #
+ def diff_lcs_loaded? #:nodoc:
+ return true if defined?(Diff::LCS)
+ return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
+
+ @diff_lcs_loaded = begin
+ require "diff/lcs"
+ true
+ rescue LoadError
+ false
+ end
end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb b/lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb
deleted file mode 100644
index 56a9e6181b..0000000000
--- a/lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative "terminal"
-
-class Bundler::Thor
- module Shell
- class ColumnPrinter
- attr_reader :stdout, :options
-
- def initialize(stdout, options = {})
- @stdout = stdout
- @options = options
- @indent = options[:indent].to_i
- end
-
- def print(array)
- return if array.empty?
- colwidth = (array.map { |el| el.to_s.size }.max || 0) + 2
- array.each_with_index do |value, index|
- # Don't output trailing spaces when printing the last column
- if ((((index + 1) % (Terminal.terminal_width / colwidth))).zero? && !index.zero?) || index + 1 == array.length
- stdout.puts value
- else
- stdout.printf("%-#{colwidth}s", value)
- end
- end
- end
- end
- end
-end
-
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/html.rb b/lib/bundler/vendor/thor/lib/thor/shell/html.rb
index 0277b882b7..77a6d13a23 100644
--- a/lib/bundler/vendor/thor/lib/thor/shell/html.rb
+++ b/lib/bundler/vendor/thor/lib/thor/shell/html.rb
@@ -76,6 +76,51 @@ class Bundler::Thor
def can_display_colors?
true
end
+
+ # Overwrite show_diff to show diff with colors if Diff::LCS is
+ # available.
+ #
+ def show_diff(destination, content) #:nodoc:
+ if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
+ actual = File.binread(destination).to_s.split("\n")
+ content = content.to_s.split("\n")
+
+ Diff::LCS.sdiff(actual, content).each do |diff|
+ output_diff_line(diff)
+ end
+ else
+ super
+ end
+ end
+
+ def output_diff_line(diff) #:nodoc:
+ case diff.action
+ when "-"
+ say "- #{diff.old_element.chomp}", :red, true
+ when "+"
+ say "+ #{diff.new_element.chomp}", :green, true
+ when "!"
+ say "- #{diff.old_element.chomp}", :red, true
+ say "+ #{diff.new_element.chomp}", :green, true
+ else
+ say " #{diff.old_element.chomp}", nil, true
+ end
+ end
+
+ # Check if Diff::LCS is loaded. If it is, use it to create pretty output
+ # for diff.
+ #
+ def diff_lcs_loaded? #:nodoc:
+ return true if defined?(Diff::LCS)
+ return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
+
+ @diff_lcs_loaded = begin
+ require "diff/lcs"
+ true
+ rescue LoadError
+ false
+ end
+ end
end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb b/lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb
deleted file mode 100644
index 525f9ce5bb..0000000000
--- a/lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb
+++ /dev/null
@@ -1,134 +0,0 @@
-require_relative "column_printer"
-require_relative "terminal"
-
-class Bundler::Thor
- module Shell
- class TablePrinter < ColumnPrinter
- BORDER_SEPARATOR = :separator
-
- def initialize(stdout, options = {})
- super
- @formats = []
- @maximas = []
- @colwidth = options[:colwidth]
- @truncate = options[:truncate] == true ? Terminal.terminal_width : options[:truncate]
- @padding = 1
- end
-
- def print(array)
- return if array.empty?
-
- prepare(array)
-
- print_border_separator if options[:borders]
-
- array.each do |row|
- if options[:borders] && row == BORDER_SEPARATOR
- print_border_separator
- next
- end
-
- sentence = "".dup
-
- row.each_with_index do |column, index|
- sentence << format_cell(column, row.size, index)
- end
-
- sentence = truncate(sentence)
- sentence << "|" if options[:borders]
- stdout.puts indentation + sentence
-
- end
- print_border_separator if options[:borders]
- end
-
- private
-
- def prepare(array)
- array = array.reject{|row| row == BORDER_SEPARATOR }
-
- @formats << "%-#{@colwidth + 2}s".dup if @colwidth
- start = @colwidth ? 1 : 0
-
- colcount = array.max { |a, b| a.size <=> b.size }.size
-
- start.upto(colcount - 1) do |index|
- maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
-
- @maximas << maxima
- @formats << if options[:borders]
- "%-#{maxima}s".dup
- elsif index == colcount - 1
- # Don't output 2 trailing spaces when printing the last column
- "%-s".dup
- else
- "%-#{maxima + 2}s".dup
- end
- end
-
- @formats << "%s"
- end
-
- def format_cell(column, row_size, index)
- maxima = @maximas[index]
-
- f = if column.is_a?(Numeric)
- if options[:borders]
- # With borders we handle padding separately
- "%#{maxima}s"
- elsif index == row_size - 1
- # Don't output 2 trailing spaces when printing the last column
- "%#{maxima}s"
- else
- "%#{maxima}s "
- end
- else
- @formats[index]
- end
-
- cell = "".dup
- cell << "|" + " " * @padding if options[:borders]
- cell << f % column.to_s
- cell << " " * @padding if options[:borders]
- cell
- end
-
- def print_border_separator
- separator = @maximas.map do |maxima|
- "+" + "-" * (maxima + 2 * @padding)
- end
- stdout.puts indentation + separator.join + "+"
- end
-
- def truncate(string)
- return string unless @truncate
- as_unicode do
- chars = string.chars.to_a
- if chars.length <= @truncate
- chars.join
- else
- chars[0, @truncate - 3 - @indent].join + "..."
- end
- end
- end
-
- def indentation
- " " * @indent
- end
-
- if "".respond_to?(:encode)
- def as_unicode
- yield
- end
- else
- def as_unicode
- old = $KCODE # rubocop:disable Style/GlobalVars
- $KCODE = "U" # rubocop:disable Style/GlobalVars
- yield
- ensure
- $KCODE = old # rubocop:disable Style/GlobalVars
- end
- end
- end
- end
-end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/terminal.rb b/lib/bundler/vendor/thor/lib/thor/shell/terminal.rb
deleted file mode 100644
index 2c60684308..0000000000
--- a/lib/bundler/vendor/thor/lib/thor/shell/terminal.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-class Bundler::Thor
- module Shell
- module Terminal
- DEFAULT_TERMINAL_WIDTH = 80
-
- class << self
- # This code was copied from Rake, available under MIT-LICENSE
- # Copyright (c) 2003, 2004 Jim Weirich
- def terminal_width
- result = if ENV["THOR_COLUMNS"]
- ENV["THOR_COLUMNS"].to_i
- else
- unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
- end
- result < 10 ? DEFAULT_TERMINAL_WIDTH : result
- rescue
- DEFAULT_TERMINAL_WIDTH
- end
-
- def unix?
- RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris)/i
- end
-
- private
-
- # Calculate the dynamic width of the terminal
- def dynamic_width
- @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
- end
-
- def dynamic_width_stty
- `stty size 2>/dev/null`.split[1].to_i
- end
-
- def dynamic_width_tput
- `tput cols 2>/dev/null`.to_i
- end
-
- end
- end
- end
-end
diff --git a/lib/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb b/lib/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb
deleted file mode 100644
index ba88e952db..0000000000
--- a/lib/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative "column_printer"
-require_relative "terminal"
-
-class Bundler::Thor
- module Shell
- class WrappedPrinter < ColumnPrinter
- def print(message)
- width = Terminal.terminal_width - @indent
- paras = message.split("\n\n")
-
- paras.map! do |unwrapped|
- words = unwrapped.split(" ")
- counter = words.first.length
- words.inject do |memo, word|
- word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
- counter = 0 if word.include? "\n"
- if (counter + word.length + 1) < width
- memo = "#{memo} #{word}"
- counter += (word.length + 1)
- else
- memo = "#{memo}\n#{word}"
- counter = word.length
- end
- memo
- end
- end.compact!
-
- paras.each do |para|
- para.split("\n").each do |line|
- stdout.puts line.insert(0, " " * @indent)
- end
- stdout.puts unless para == paras.last
- end
- end
- end
- end
-end
-
diff --git a/lib/bundler/vendor/thor/lib/thor/util.rb b/lib/bundler/vendor/thor/lib/thor/util.rb
index 68916daf2e..d2572a4249 100644
--- a/lib/bundler/vendor/thor/lib/thor/util.rb
+++ b/lib/bundler/vendor/thor/lib/thor/util.rb
@@ -90,7 +90,7 @@ class Bundler::Thor
def snake_case(str)
return str.downcase if str =~ /^[A-Z_]+$/
str.gsub(/\B[A-Z]/, '_\&').squeeze("_") =~ /_*(.*)/
- Regexp.last_match(-1).downcase
+ $+.downcase
end
# Receives a string and convert it to camel case. camel_case returns CamelCase.
@@ -130,10 +130,9 @@ class Bundler::Thor
#
def find_class_and_command_by_namespace(namespace, fallback = true)
if namespace.include?(":") # look for a namespaced command
- *pieces, command = namespace.split(":")
- namespace = pieces.join(":")
- namespace = "default" if namespace.empty?
- klass = Bundler::Thor::Base.subclasses.detect { |thor| thor.namespace == namespace && thor.commands.keys.include?(command) }
+ pieces = namespace.split(":")
+ command = pieces.pop
+ klass = Bundler::Thor::Util.find_by_namespace(pieces.join(":"))
end
unless klass # look for a Bundler::Thor::Group with the right name
klass = Bundler::Thor::Util.find_by_namespace(namespace)
@@ -151,7 +150,7 @@ class Bundler::Thor
# inside the sandbox to avoid namespacing conflicts.
#
def load_thorfile(path, content = nil, debug = false)
- content ||= File.read(path)
+ content ||= File.binread(path)
begin
Bundler::Thor::Sandbox.class_eval(content, path)
@@ -190,7 +189,7 @@ class Bundler::Thor
# Returns the root where thor files are located, depending on the OS.
#
def thor_root
- File.join(user_home, ".thor").tr("\\", "/")
+ File.join(user_home, ".thor").tr('\\', "/")
end
# Returns the files in the thor root. On Windows thor_root will be something
@@ -237,7 +236,7 @@ class Bundler::Thor
# symlink points to 'ruby_install_name'
ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby
end
- rescue NotImplementedError # rubocop:disable Lint/HandleExceptions
+ rescue NotImplementedError # rubocop:disable HandleExceptions
# just ignore on windows
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/version.rb b/lib/bundler/vendor/thor/lib/thor/version.rb
index 1fb00017ed..48a4788b3b 100644
--- a/lib/bundler/vendor/thor/lib/thor/version.rb
+++ b/lib/bundler/vendor/thor/lib/thor/version.rb
@@ -1,3 +1,3 @@
class Bundler::Thor
- VERSION = "1.3.0"
+ VERSION = "1.2.1"
end
diff --git a/lib/bundler/vendor/tsort/.document b/lib/bundler/vendor/tsort/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/bundler/vendor/tsort/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/bundler/vendor/tsort/lib/tsort.rb b/lib/bundler/vendor/tsort/lib/tsort.rb
index cf8731f760..4a0e1a4e25 100644
--- a/lib/bundler/vendor/tsort/lib/tsort.rb
+++ b/lib/bundler/vendor/tsort/lib/tsort.rb
@@ -122,9 +122,6 @@
#
module Bundler::TSort
-
- VERSION = "0.2.0"
-
class Cyclic < StandardError
end
diff --git a/lib/bundler/vendor/uri/.document b/lib/bundler/vendor/uri/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/bundler/vendor/uri/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/bundler/vendor/uri/lib/uri/common.rb b/lib/bundler/vendor/uri/lib/uri/common.rb
index 93f4f226ad..914a4c7581 100644
--- a/lib/bundler/vendor/uri/lib/uri/common.rb
+++ b/lib/bundler/vendor/uri/lib/uri/common.rb
@@ -68,32 +68,16 @@ module Bundler::URI
end
private_constant :Schemes
- # Registers the given +klass+ as the class to be instantiated
- # when parsing a \Bundler::URI with the given +scheme+:
#
- # Bundler::URI.register_scheme('MS_SEARCH', Bundler::URI::Generic) # => Bundler::URI::Generic
- # Bundler::URI.scheme_list['MS_SEARCH'] # => Bundler::URI::Generic
+ # Register the given +klass+ to be instantiated when parsing URLs with the given +scheme+.
+ # Note that currently only schemes which after .upcase are valid constant names
+ # can be registered (no -/+/. allowed).
#
- # Note that after calling String#upcase on +scheme+, it must be a valid
- # constant name.
def self.register_scheme(scheme, klass)
Schemes.const_set(scheme.to_s.upcase, klass)
end
- # Returns a hash of the defined schemes:
- #
- # Bundler::URI.scheme_list
- # # =>
- # {"MAILTO"=>Bundler::URI::MailTo,
- # "LDAPS"=>Bundler::URI::LDAPS,
- # "WS"=>Bundler::URI::WS,
- # "HTTP"=>Bundler::URI::HTTP,
- # "HTTPS"=>Bundler::URI::HTTPS,
- # "LDAP"=>Bundler::URI::LDAP,
- # "FILE"=>Bundler::URI::File,
- # "FTP"=>Bundler::URI::FTP}
- #
- # Related: Bundler::URI.register_scheme.
+ # Returns a Hash of the defined schemes.
def self.scheme_list
Schemes.constants.map { |name|
[name.to_s.upcase, Schemes.const_get(name)]
@@ -104,21 +88,9 @@ module Bundler::URI
private_constant :INITIAL_SCHEMES
Ractor.make_shareable(INITIAL_SCHEMES) if defined?(Ractor)
- # Returns a new object constructed from the given +scheme+, +arguments+,
- # and +default+:
- #
- # - The new object is an instance of <tt>Bundler::URI.scheme_list[scheme.upcase]</tt>.
- # - The object is initialized by calling the class initializer
- # using +scheme+ and +arguments+.
- # See Bundler::URI::Generic.new.
- #
- # Examples:
#
- # values = ['john.doe', 'www.example.com', '123', nil, '/forum/questions/', nil, 'tag=networking&order=newest', 'top']
- # Bundler::URI.for('https', *values)
- # # => #<Bundler::URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- # Bundler::URI.for('foo', *values, default: Bundler::URI::HTTP)
- # # => #<Bundler::URI::HTTP foo://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
+ # Construct a Bundler::URI instance, using the scheme to detect the appropriate class
+ # from +Bundler::URI.scheme_list+.
#
def self.for(scheme, *arguments, default: Generic)
const_name = scheme.to_s.upcase
@@ -149,49 +121,95 @@ module Bundler::URI
#
class BadURIError < Error; end
- # Returns a 9-element array representing the parts of the \Bundler::URI
- # formed from the string +uri+;
- # each array element is a string or +nil+:
- #
- # names = %w[scheme userinfo host port registry path opaque query fragment]
- # values = Bundler::URI.split('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # names.zip(values)
- # # =>
- # [["scheme", "https"],
- # ["userinfo", "john.doe"],
- # ["host", "www.example.com"],
- # ["port", "123"],
- # ["registry", nil],
- # ["path", "/forum/questions/"],
- # ["opaque", nil],
- # ["query", "tag=networking&order=newest"],
- # ["fragment", "top"]]
+ #
+ # == Synopsis
+ #
+ # Bundler::URI::split(uri)
+ #
+ # == Args
+ #
+ # +uri+::
+ # String with Bundler::URI.
+ #
+ # == Description
+ #
+ # Splits the string on following parts and returns array with result:
+ #
+ # * Scheme
+ # * Userinfo
+ # * Host
+ # * Port
+ # * Registry
+ # * Path
+ # * Opaque
+ # * Query
+ # * Fragment
+ #
+ # == Usage
+ #
+ # require 'bundler/vendor/uri/lib/uri'
+ #
+ # Bundler::URI.split("http://www.ruby-lang.org/")
+ # # => ["http", nil, "www.ruby-lang.org", nil, nil, "/", nil, nil, nil]
#
def self.split(uri)
RFC3986_PARSER.split(uri)
end
- # Returns a new \Bundler::URI object constructed from the given string +uri+:
#
- # Bundler::URI.parse('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # # => #<Bundler::URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- # Bundler::URI.parse('http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # # => #<Bundler::URI::HTTP http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
+ # == Synopsis
+ #
+ # Bundler::URI::parse(uri_str)
+ #
+ # == Args
+ #
+ # +uri_str+::
+ # String with Bundler::URI.
+ #
+ # == Description
+ #
+ # Creates one of the Bundler::URI's subclasses instance from the string.
+ #
+ # == Raises
+ #
+ # Bundler::URI::InvalidURIError::
+ # Raised if Bundler::URI given is not a correct one.
#
- # It's recommended to first ::escape string +uri+
- # if it may contain invalid Bundler::URI characters.
+ # == Usage
+ #
+ # require 'bundler/vendor/uri/lib/uri'
+ #
+ # uri = Bundler::URI.parse("http://www.ruby-lang.org/")
+ # # => #<Bundler::URI::HTTP http://www.ruby-lang.org/>
+ # uri.scheme
+ # # => "http"
+ # uri.host
+ # # => "www.ruby-lang.org"
+ #
+ # It's recommended to first ::escape the provided +uri_str+ if there are any
+ # invalid Bundler::URI characters.
#
def self.parse(uri)
RFC3986_PARSER.parse(uri)
end
- # Merges the given Bundler::URI strings +str+
- # per {RFC 2396}[https://www.rfc-editor.org/rfc/rfc2396.html].
#
- # Each string in +str+ is converted to an
- # {RFC3986 Bundler::URI}[https://www.rfc-editor.org/rfc/rfc3986.html] before being merged.
+ # == Synopsis
+ #
+ # Bundler::URI::join(str[, str, ...])
#
- # Examples:
+ # == Args
+ #
+ # +str+::
+ # String(s) to work with, will be converted to RFC3986 URIs before merging.
+ #
+ # == Description
+ #
+ # Joins URIs.
+ #
+ # == Usage
+ #
+ # require 'bundler/vendor/uri/lib/uri'
#
# Bundler::URI.join("http://example.com/","main.rbx")
# # => #<Bundler::URI::HTTP http://example.com/main.rbx>
@@ -236,7 +254,7 @@ module Bundler::URI
# Bundler::URI.extract("text here http://foo.example.org/bla and here mailto:test@example.com and here also.")
# # => ["http://foo.example.com/bla", "mailto:test@example.com"]
#
- def self.extract(str, schemes = nil, &block) # :nodoc:
+ def self.extract(str, schemes = nil, &block)
warn "Bundler::URI.extract is obsolete", uplevel: 1 if $VERBOSE
DEFAULT_PARSER.extract(str, schemes, &block)
end
@@ -273,7 +291,7 @@ module Bundler::URI
# p $&
# end
#
- def self.regexp(schemes = nil)# :nodoc:
+ def self.regexp(schemes = nil)
warn "Bundler::URI.regexp is obsolete", uplevel: 1 if $VERBOSE
DEFAULT_PARSER.make_regexp(schemes)
end
@@ -296,86 +314,40 @@ module Bundler::URI
TBLDECWWWCOMP_['+'] = ' '
TBLDECWWWCOMP_.freeze
- # Returns a URL-encoded string derived from the given string +str+.
- #
- # The returned string:
- #
- # - Preserves:
- #
- # - Characters <tt>'*'</tt>, <tt>'.'</tt>, <tt>'-'</tt>, and <tt>'_'</tt>.
- # - Character in ranges <tt>'a'..'z'</tt>, <tt>'A'..'Z'</tt>,
- # and <tt>'0'..'9'</tt>.
- #
- # Example:
+ # Encodes given +str+ to URL-encoded form data.
#
- # Bundler::URI.encode_www_form_component('*.-_azAZ09')
- # # => "*.-_azAZ09"
+ # This method doesn't convert *, -, ., 0-9, A-Z, _, a-z, but does convert SP
+ # (ASCII space) to + and converts others to %XX.
#
- # - Converts:
+ # If +enc+ is given, convert +str+ to the encoding before percent encoding.
#
- # - Character <tt>' '</tt> to character <tt>'+'</tt>.
- # - Any other character to "percent notation";
- # the percent notation for character <i>c</i> is <tt>'%%%X' % c.ord</tt>.
+ # This is an implementation of
+ # https://www.w3.org/TR/2013/CR-html5-20130806/forms.html#url-encoded-form-data.
#
- # Example:
- #
- # Bundler::URI.encode_www_form_component('Here are some punctuation characters: ,;?:')
- # # => "Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A"
- #
- # Encoding:
- #
- # - If +str+ has encoding Encoding::ASCII_8BIT, argument +enc+ is ignored.
- # - Otherwise +str+ is converted first to Encoding::UTF_8
- # (with suitable character replacements),
- # and then to encoding +enc+.
- #
- # In either case, the returned string has forced encoding Encoding::US_ASCII.
- #
- # Related: Bundler::URI.encode_uri_component (encodes <tt>' '</tt> as <tt>'%20'</tt>).
+ # See Bundler::URI.decode_www_form_component, Bundler::URI.encode_www_form.
def self.encode_www_form_component(str, enc=nil)
_encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_, str, enc)
end
- # Returns a string decoded from the given \URL-encoded string +str+.
- #
- # The given string is first encoded as Encoding::ASCII-8BIT (using String#b),
- # then decoded (as below), and finally force-encoded to the given encoding +enc+.
- #
- # The returned string:
- #
- # - Preserves:
- #
- # - Characters <tt>'*'</tt>, <tt>'.'</tt>, <tt>'-'</tt>, and <tt>'_'</tt>.
- # - Character in ranges <tt>'a'..'z'</tt>, <tt>'A'..'Z'</tt>,
- # and <tt>'0'..'9'</tt>.
- #
- # Example:
- #
- # Bundler::URI.decode_www_form_component('*.-_azAZ09')
- # # => "*.-_azAZ09"
- #
- # - Converts:
- #
- # - Character <tt>'+'</tt> to character <tt>' '</tt>.
- # - Each "percent notation" to an ASCII character.
+ # Decodes given +str+ of URL-encoded form data.
#
- # Example:
+ # This decodes + to SP.
#
- # Bundler::URI.decode_www_form_component('Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A')
- # # => "Here are some punctuation characters: ,;?:"
- #
- # Related: Bundler::URI.decode_uri_component (preserves <tt>'+'</tt>).
+ # See Bundler::URI.encode_www_form_component, Bundler::URI.decode_www_form.
def self.decode_www_form_component(str, enc=Encoding::UTF_8)
_decode_uri_component(/\+|%\h\h/, str, enc)
end
- # Like Bundler::URI.encode_www_form_component, except that <tt>' '</tt> (space)
- # is encoded as <tt>'%20'</tt> (instead of <tt>'+'</tt>).
+ # Encodes +str+ using URL encoding
+ #
+ # This encodes SP to %20 instead of +.
def self.encode_uri_component(str, enc=nil)
_encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCURICOMP_, str, enc)
end
- # Like Bundler::URI.decode_www_form_component, except that <tt>'+'</tt> is preserved.
+ # Decodes given +str+ of URL-encoded data.
+ #
+ # This does not decode + to SP.
def self.decode_uri_component(str, enc=Encoding::UTF_8)
_decode_uri_component(/%\h\h/, str, enc)
end
@@ -400,104 +372,33 @@ module Bundler::URI
end
private_class_method :_decode_uri_component
- # Returns a URL-encoded string derived from the given
- # {Enumerable}[rdoc-ref:Enumerable@Enumerable+in+Ruby+Classes]
- # +enum+.
- #
- # The result is suitable for use as form data
- # for an \HTTP request whose <tt>Content-Type</tt> is
- # <tt>'application/x-www-form-urlencoded'</tt>.
- #
- # The returned string consists of the elements of +enum+,
- # each converted to one or more URL-encoded strings,
- # and all joined with character <tt>'&'</tt>.
- #
- # Simple examples:
- #
- # Bundler::URI.encode_www_form([['foo', 0], ['bar', 1], ['baz', 2]])
- # # => "foo=0&bar=1&baz=2"
- # Bundler::URI.encode_www_form({foo: 0, bar: 1, baz: 2})
- # # => "foo=0&bar=1&baz=2"
- #
- # The returned string is formed using method Bundler::URI.encode_www_form_component,
- # which converts certain characters:
- #
- # Bundler::URI.encode_www_form('f#o': '/', 'b-r': '$', 'b z': '@')
- # # => "f%23o=%2F&b-r=%24&b+z=%40"
- #
- # When +enum+ is Array-like, each element +ele+ is converted to a field:
- #
- # - If +ele+ is an array of two or more elements,
- # the field is formed from its first two elements
- # (and any additional elements are ignored):
- #
- # name = Bundler::URI.encode_www_form_component(ele[0], enc)
- # value = Bundler::URI.encode_www_form_component(ele[1], enc)
- # "#{name}=#{value}"
+ # Generates URL-encoded form data from given +enum+.
#
- # Examples:
+ # This generates application/x-www-form-urlencoded data defined in HTML5
+ # from given an Enumerable object.
#
- # Bundler::URI.encode_www_form([%w[foo bar], %w[baz bat bah]])
- # # => "foo=bar&baz=bat"
- # Bundler::URI.encode_www_form([['foo', 0], ['bar', :baz, 'bat']])
- # # => "foo=0&bar=baz"
+ # This internally uses Bundler::URI.encode_www_form_component(str).
#
- # - If +ele+ is an array of one element,
- # the field is formed from <tt>ele[0]</tt>:
+ # This method doesn't convert the encoding of given items, so convert them
+ # before calling this method if you want to send data as other than original
+ # encoding or mixed encoding data. (Strings which are encoded in an HTML5
+ # ASCII incompatible encoding are converted to UTF-8.)
#
- # Bundler::URI.encode_www_form_component(ele[0])
+ # This method doesn't handle files. When you send a file, use
+ # multipart/form-data.
#
- # Example:
+ # This refers https://url.spec.whatwg.org/#concept-urlencoded-serializer
#
- # Bundler::URI.encode_www_form([['foo'], [:bar], [0]])
- # # => "foo&bar&0"
- #
- # - Otherwise the field is formed from +ele+:
- #
- # Bundler::URI.encode_www_form_component(ele)
- #
- # Example:
- #
- # Bundler::URI.encode_www_form(['foo', :bar, 0])
- # # => "foo&bar&0"
- #
- # The elements of an Array-like +enum+ may be mixture:
- #
- # Bundler::URI.encode_www_form([['foo', 0], ['bar', 1, 2], ['baz'], :bat])
- # # => "foo=0&bar=1&baz&bat"
- #
- # When +enum+ is Hash-like,
- # each +key+/+value+ pair is converted to one or more fields:
- #
- # - If +value+ is
- # {Array-convertible}[rdoc-ref:implicit_conversion.rdoc@Array-Convertible+Objects],
- # each element +ele+ in +value+ is paired with +key+ to form a field:
- #
- # name = Bundler::URI.encode_www_form_component(key, enc)
- # value = Bundler::URI.encode_www_form_component(ele, enc)
- # "#{name}=#{value}"
- #
- # Example:
- #
- # Bundler::URI.encode_www_form({foo: [:bar, 1], baz: [:bat, :bam, 2]})
- # # => "foo=bar&foo=1&baz=bat&baz=bam&baz=2"
- #
- # - Otherwise, +key+ and +value+ are paired to form a field:
- #
- # name = Bundler::URI.encode_www_form_component(key, enc)
- # value = Bundler::URI.encode_www_form_component(value, enc)
- # "#{name}=#{value}"
- #
- # Example:
- #
- # Bundler::URI.encode_www_form({foo: 0, bar: 1, baz: 2})
- # # => "foo=0&bar=1&baz=2"
- #
- # The elements of a Hash-like +enum+ may be mixture:
- #
- # Bundler::URI.encode_www_form({foo: [0, 1], bar: 2})
- # # => "foo=0&foo=1&bar=2"
+ # Bundler::URI.encode_www_form([["q", "ruby"], ["lang", "en"]])
+ # #=> "q=ruby&lang=en"
+ # Bundler::URI.encode_www_form("q" => "ruby", "lang" => "en")
+ # #=> "q=ruby&lang=en"
+ # Bundler::URI.encode_www_form("q" => ["ruby", "perl"], "lang" => "en")
+ # #=> "q=ruby&q=perl&lang=en"
+ # Bundler::URI.encode_www_form([["q", "ruby"], ["q", "perl"], ["lang", "en"]])
+ # #=> "q=ruby&q=perl&lang=en"
#
+ # See Bundler::URI.encode_www_form_component, Bundler::URI.decode_www_form.
def self.encode_www_form(enum, enc=nil)
enum.map do |k,v|
if v.nil?
@@ -518,39 +419,22 @@ module Bundler::URI
end.join('&')
end
- # Returns name/value pairs derived from the given string +str+,
- # which must be an ASCII string.
- #
- # The method may be used to decode the body of Net::HTTPResponse object +res+
- # for which <tt>res['Content-Type']</tt> is <tt>'application/x-www-form-urlencoded'</tt>.
- #
- # The returned data is an array of 2-element subarrays;
- # each subarray is a name/value pair (both are strings).
- # Each returned string has encoding +enc+,
- # and has had invalid characters removed via
- # {String#scrub}[rdoc-ref:String#scrub].
+ # Decodes URL-encoded form data from given +str+.
#
- # A simple example:
+ # This decodes application/x-www-form-urlencoded data
+ # and returns an array of key-value arrays.
#
- # Bundler::URI.decode_www_form('foo=0&bar=1&baz')
- # # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
+ # This refers http://url.spec.whatwg.org/#concept-urlencoded-parser,
+ # so this supports only &-separator, and doesn't support ;-separator.
#
- # The returned strings have certain conversions,
- # similar to those performed in Bundler::URI.decode_www_form_component:
- #
- # Bundler::URI.decode_www_form('f%23o=%2F&b-r=%24&b+z=%40')
- # # => [["f#o", "/"], ["b-r", "$"], ["b z", "@"]]
- #
- # The given string may contain consecutive separators:
- #
- # Bundler::URI.decode_www_form('foo=0&&bar=1&&baz=2')
- # # => [["foo", "0"], ["", ""], ["bar", "1"], ["", ""], ["baz", "2"]]
- #
- # A different separator may be specified:
- #
- # Bundler::URI.decode_www_form('foo=0--bar=1--baz', separator: '--')
- # # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
+ # ary = Bundler::URI.decode_www_form("a=1&a=2&b=3")
+ # ary #=> [['a', '1'], ['a', '2'], ['b', '3']]
+ # ary.assoc('a').last #=> '1'
+ # ary.assoc('b').last #=> '3'
+ # ary.rassoc('a').last #=> '2'
+ # Hash[ary] #=> {"a"=>"2", "b"=>"3"}
#
+ # See Bundler::URI.decode_www_form_component, Bundler::URI.encode_www_form.
def self.decode_www_form(str, enc=Encoding::UTF_8, separator: '&', use__charset_: false, isindex: false)
raise ArgumentError, "the input of #{self.name}.#{__method__} must be ASCII only string" unless str.ascii_only?
ary = []
@@ -829,15 +713,7 @@ end # module Bundler::URI
module Bundler
#
- # Returns a \Bundler::URI object derived from the given +uri+,
- # which may be a \Bundler::URI string or an existing \Bundler::URI object:
- #
- # # Returns a new Bundler::URI.
- # uri = Bundler::URI('http://github.com/ruby/ruby')
- # # => #<Bundler::URI::HTTP http://github.com/ruby/ruby>
- # # Returns the given Bundler::URI.
- # Bundler::URI(uri)
- # # => #<Bundler::URI::HTTP http://github.com/ruby/ruby>
+ # Returns +uri+ converted to an Bundler::URI object.
#
def URI(uri)
if uri.is_a?(Bundler::URI::Generic)
diff --git a/lib/bundler/vendor/uri/lib/uri/generic.rb b/lib/bundler/vendor/uri/lib/uri/generic.rb
index 762c425ac1..9ae6915826 100644
--- a/lib/bundler/vendor/uri/lib/uri/generic.rb
+++ b/lib/bundler/vendor/uri/lib/uri/generic.rb
@@ -1376,7 +1376,6 @@ module Bundler::URI
end
str
end
- alias to_str to_s
#
# Compares two URIs.
diff --git a/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb b/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb
index 4c9882f595..a85511c146 100644
--- a/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb
+++ b/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb
@@ -1,73 +1,9 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
module Bundler::URI
class RFC3986_Parser # :nodoc:
# Bundler::URI defined in RFC3986
- HOST = %r[
- (?<IP-literal>\[(?:
- (?<IPv6address>
- (?:\h{1,4}:){6}
- (?<ls32>\h{1,4}:\h{1,4}
- | (?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)
- \.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>)
- )
- | ::(?:\h{1,4}:){5}\g<ls32>
- | \h{1,4}?::(?:\h{1,4}:){4}\g<ls32>
- | (?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>
- | (?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>
- | (?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>
- | (?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>
- | (?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}
- | (?:(?:\h{1,4}:){,6}\h{1,4})?::
- )
- | (?<IPvFuture>v\h++\.[!$&-.0-9:;=A-Z_a-z~]++)
- )\])
- | \g<IPv4address>
- | (?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*+)
- ]x
-
- USERINFO = /(?:%\h\h|[!$&-.0-9:;=A-Z_a-z~])*+/
-
- SCHEME = %r[[A-Za-z][+\-.0-9A-Za-z]*+].source
- SEG = %r[(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/])].source
- SEG_NC = %r[(?:%\h\h|[!$&-.0-9;=@A-Z_a-z~])].source
- FRAGMENT = %r[(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/?])*+].source
-
- RFC3986_URI = %r[\A
- (?<seg>#{SEG}){0}
- (?<Bundler::URI>
- (?<scheme>#{SCHEME}):
- (?<hier-part>//
- (?<authority>
- (?:(?<userinfo>#{USERINFO.source})@)?
- (?<host>#{HOST.source.delete(" \n")})
- (?::(?<port>\d*+))?
- )
- (?<path-abempty>(?:/\g<seg>*+)?)
- | (?<path-absolute>/((?!/)\g<seg>++)?)
- | (?<path-rootless>(?!/)\g<seg>++)
- | (?<path-empty>)
- )
- (?:\?(?<query>[^\#]*+))?
- (?:\#(?<fragment>#{FRAGMENT}))?
- )\z]x
-
- RFC3986_relative_ref = %r[\A
- (?<seg>#{SEG}){0}
- (?<relative-ref>
- (?<relative-part>//
- (?<authority>
- (?:(?<userinfo>#{USERINFO.source})@)?
- (?<host>#{HOST.source.delete(" \n")}(?<!/))?
- (?::(?<port>\d*+))?
- )
- (?<path-abempty>(?:/\g<seg>*+)?)
- | (?<path-absolute>/\g<seg>*+)
- | (?<path-noscheme>#{SEG_NC}++(?:/\g<seg>*+)?)
- | (?<path-empty>)
- )
- (?:\?(?<query>[^#]*+))?
- (?:\#(?<fragment>#{FRAGMENT}))?
- )\z]x
+ RFC3986_URI = /\A(?<Bundler::URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*+):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*+)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h++\.[!$&-.0-;=A-Z_a-z~]++))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*+))(?::(?<port>\d*+))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*+))*+)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])++)(?:\/\g<segment>)*+)?)|(?<path-rootless>\g<segment-nz>(?:\/\g<segment>)*+)|(?<path-empty>))(?:\?(?<query>[^#]*+))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*+))?)\z/
+ RFC3986_relative_ref = /\A(?<relative-ref>(?<relative-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*+)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h++\.[!$&-.0-;=A-Z_a-z~]++))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])++))?(?::(?<port>\d*+))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*+))*+)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])++)(?:\/\g<segment>)*+)?)|(?<path-noscheme>(?<segment-nz-nc>(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])++)(?:\/\g<segment>)*+)|(?<path-empty>))(?:\?(?<query>[^#]*+))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*+))?)\z/
attr_reader :regexp
def initialize
@@ -83,9 +19,9 @@ module Bundler::URI
uri.ascii_only? or
raise InvalidURIError, "Bundler::URI must be ascii only #{uri.dump}"
if m = RFC3986_URI.match(uri)
- query = m["query"]
- scheme = m["scheme"]
- opaque = m["path-rootless"]
+ query = m["query".freeze]
+ scheme = m["scheme".freeze]
+ opaque = m["path-rootless".freeze]
if opaque
opaque << "?#{query}" if query
[ scheme,
@@ -96,35 +32,35 @@ module Bundler::URI
nil, # path
opaque,
nil, # query
- m["fragment"]
+ m["fragment".freeze]
]
else # normal
[ scheme,
- m["userinfo"],
- m["host"],
- m["port"],
+ m["userinfo".freeze],
+ m["host".freeze],
+ m["port".freeze],
nil, # registry
- (m["path-abempty"] ||
- m["path-absolute"] ||
- m["path-empty"]),
+ (m["path-abempty".freeze] ||
+ m["path-absolute".freeze] ||
+ m["path-empty".freeze]),
nil, # opaque
query,
- m["fragment"]
+ m["fragment".freeze]
]
end
elsif m = RFC3986_relative_ref.match(uri)
[ nil, # scheme
- m["userinfo"],
- m["host"],
- m["port"],
+ m["userinfo".freeze],
+ m["host".freeze],
+ m["port".freeze],
nil, # registry,
- (m["path-abempty"] ||
- m["path-absolute"] ||
- m["path-noscheme"] ||
- m["path-empty"]),
+ (m["path-abempty".freeze] ||
+ m["path-absolute".freeze] ||
+ m["path-noscheme".freeze] ||
+ m["path-empty".freeze]),
nil, # opaque
- m["query"],
- m["fragment"]
+ m["query".freeze],
+ m["fragment".freeze]
]
else
raise InvalidURIError, "bad Bundler::URI(is not Bundler::URI?): #{uri.inspect}"
@@ -156,14 +92,14 @@ module Bundler::URI
def default_regexp # :nodoc:
{
- SCHEME: %r[\A#{SCHEME}\z]o,
- USERINFO: %r[\A#{USERINFO}\z]o,
- HOST: %r[\A#{HOST}\z]o,
- ABS_PATH: %r[\A/#{SEG}*+\z]o,
- REL_PATH: %r[\A(?!/)#{SEG}++\z]o,
- QUERY: %r[\A(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/?])*+\z],
- FRAGMENT: %r[\A#{FRAGMENT}\z]o,
- OPAQUE: %r[\A(?:[^/].*)?\z],
+ SCHEME: /\A[A-Za-z][A-Za-z0-9+\-.]*\z/,
+ USERINFO: /\A(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*\z/,
+ HOST: /\A(?:(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{,4}::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*))\z/,
+ ABS_PATH: /\A\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/,
+ REL_PATH: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/,
+ QUERY: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/,
+ FRAGMENT: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/,
+ OPAQUE: /\A(?:[^\/].*)?\z/,
PORT: /\A[\x09\x0a\x0c\x0d ]*+\d*[\x09\x0a\x0c\x0d ]*\z/,
}
end
diff --git a/lib/bundler/vendor/uri/lib/uri/version.rb b/lib/bundler/vendor/uri/lib/uri/version.rb
index 1fa1c7c09a..84b08eee30 100644
--- a/lib/bundler/vendor/uri/lib/uri/version.rb
+++ b/lib/bundler/vendor/uri/lib/uri/version.rb
@@ -1,6 +1,6 @@
module Bundler::URI
# :stopdoc:
- VERSION_CODE = '001300'.freeze
+ VERSION_CODE = '001202'.freeze
VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
# :startdoc:
end
diff --git a/lib/bundler/vendored_net_http.rb b/lib/bundler/vendored_net_http.rb
deleted file mode 100644
index 8ff2ccd1fe..0000000000
--- a/lib/bundler/vendored_net_http.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-# This defined? guard can be removed once RubyGems 3.4 support is dropped.
-#
-# Bundler specs load this code from `spec/support/vendored_net_http.rb` to avoid
-# activating the Bundler gem too early. Without this guard, we get redefinition
-# warnings once Bundler is actually activated and
-# `lib/bundler/vendored_net_http.rb` is required. This is not an issue in
-# RubyGems versions including `rubygems/vendored_net_http` since `require` takes
-# care of avoiding the double load.
-#
-unless defined?(Gem::Net)
- begin
- require "rubygems/vendored_net_http"
- rescue LoadError
- begin
- require "rubygems/net/http"
- rescue LoadError
- require "net/http"
- Gem::Net = Net
- end
- end
-end
diff --git a/lib/bundler/vendored_persistent.rb b/lib/bundler/vendored_persistent.rb
index ab985c267f..e29f27cdfd 100644
--- a/lib/bundler/vendored_persistent.rb
+++ b/lib/bundler/vendored_persistent.rb
@@ -9,3 +9,7 @@ module Bundler
end
end
require_relative "vendor/net-http-persistent/lib/net/http/persistent"
+
+module Bundler
+ PersistentHTTP = Persistent::Net::HTTP::Persistent
+end
diff --git a/lib/bundler/vendored_securerandom.rb b/lib/bundler/vendored_securerandom.rb
deleted file mode 100644
index 6c15f4a2b2..0000000000
--- a/lib/bundler/vendored_securerandom.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-# Use RubyGems vendored copy when available. Otherwise fallback to Bundler
-# vendored copy. The vendored copy in Bundler can be removed once support for
-# RubyGems 3.5.18 is dropped.
-
-begin
- require "rubygems/vendored_securerandom"
-rescue LoadError
- module Bundler::Random; end
- require_relative "vendor/securerandom/lib/securerandom"
- Gem::SecureRandom = Bundler::SecureRandom
- Gem::Random = Bundler::Random
-end
diff --git a/lib/bundler/vendored_timeout.rb b/lib/bundler/vendored_timeout.rb
deleted file mode 100644
index 9b2507c0cc..0000000000
--- a/lib/bundler/vendored_timeout.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-begin
- require "rubygems/vendored_timeout"
-rescue LoadError
- begin
- require "rubygems/timeout"
- rescue LoadError
- require "timeout"
- Gem::Timeout = Timeout
- end
-end
diff --git a/lib/bundler/vendored_uri.rb b/lib/bundler/vendored_uri.rb
index 2efddc65f9..905e8158e8 100644
--- a/lib/bundler/vendored_uri.rb
+++ b/lib/bundler/vendored_uri.rb
@@ -1,21 +1,4 @@
# frozen_string_literal: true
module Bundler; end
-
-# Use RubyGems vendored copy when available. Otherwise fallback to Bundler
-# vendored copy. The vendored copy in Bundler can be removed once support for
-# RubyGems 3.5 is dropped.
-
-begin
- require "rubygems/vendor/uri/lib/uri"
-rescue LoadError
- require_relative "vendor/uri/lib/uri"
- Gem::URI = Bundler::URI
-
- module Gem
- def URI(uri) # rubocop:disable Naming/MethodName
- Bundler::URI(uri)
- end
- module_function :URI
- end
-end
+require_relative "vendor/uri/lib/uri"
diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb
index f2f6236cda..8ef7be935b 100644
--- a/lib/bundler/version.rb
+++ b/lib/bundler/version.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: false
module Bundler
- VERSION = "2.6.0.dev".freeze
+ VERSION = "2.4.19".freeze
def self.bundler_major_version
@bundler_major_version ||= VERSION.split(".").first.to_i
diff --git a/lib/bundler/vlad.rb b/lib/bundler/vlad.rb
index 6179d0e4eb..538e8c3e74 100644
--- a/lib/bundler/vlad.rb
+++ b/lib/bundler/vlad.rb
@@ -13,5 +13,5 @@ require_relative "deployment"
include Rake::DSL if defined? Rake::DSL
namespace :vlad do
- Bundler::Deployment.define_task(Rake::RemoteTask, :remote_task, roles: :app)
+ Bundler::Deployment.define_task(Rake::RemoteTask, :remote_task, :roles => :app)
end
diff --git a/lib/bundler/yaml_serializer.rb b/lib/bundler/yaml_serializer.rb
index ab1eb6dbcf..d5ecbd4aef 100644
--- a/lib/bundler/yaml_serializer.rb
+++ b/lib/bundler/yaml_serializer.rb
@@ -17,11 +17,7 @@ module Bundler
if v.is_a?(Hash)
yaml << dump_hash(v).gsub(/^(?!$)/, " ") # indent all non-empty lines
elsif v.is_a?(Array) # Expected to be array of strings
- if v.empty?
- yaml << " []\n"
- else
- yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n"
- end
+ yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n"
else
yaml << " " << v.to_s.gsub(/\s+/, " ").inspect << "\n"
end
@@ -36,31 +32,30 @@ module Bundler
(.*) # value
\1 # matching closing quote
$
- /xo
+ /xo.freeze
HASH_REGEX = /
^
([ ]*) # indentations
- ([^#]+) # key excludes comment char '#'
+ (.+) # key
(?::(?=(?:\s|$))) # : (without the lookahead the #key includes this when : is present in value)
[ ]?
(['"]?) # optional opening quote
(.*) # value
\3 # matching closing quote
$
- /xo
+ /xo.freeze
def load(str)
res = {}
stack = [res]
last_hash = nil
last_empty_key = nil
- str.split(/\r?\n/) do |line|
+ str.split(/\r?\n/).each do |line|
if match = HASH_REGEX.match(line)
indent, key, quote, val = match.captures
- val = strip_comment(val)
-
- depth = indent.size / 2
+ key = convert_to_backward_compatible_key(key)
+ depth = indent.scan(/ /).length
if quote.empty? && val.empty?
new_hash = {}
stack[depth][key] = new_hash
@@ -68,13 +63,10 @@ module Bundler
last_empty_key = key
last_hash = stack[depth]
else
- val = [] if val == "[]" # empty array
stack[depth][key] = val
end
elsif match = ARRAY_REGEX.match(line)
_, val = match.captures
- val = strip_comment(val)
-
last_hash[last_empty_key] = [] unless last_hash[last_empty_key].is_a?(Array)
last_hash[last_empty_key].push(val)
@@ -83,16 +75,15 @@ module Bundler
res
end
- def strip_comment(val)
- if val.include?("#") && !val.start_with?("#")
- val.split("#", 2).first.strip
- else
- val
- end
+ # for settings' keys
+ def convert_to_backward_compatible_key(key)
+ key = "#{key}/" if key =~ /https?:/i && key !~ %r{/\Z}
+ key = key.gsub(".", "__") if key.include?(".")
+ key
end
class << self
- private :dump_hash
+ private :dump_hash, :convert_to_backward_compatible_key
end
end
end
diff --git a/lib/cgi.rb b/lib/cgi.rb
index 7af85e7fc8..7dc3a64941 100644
--- a/lib/cgi.rb
+++ b/lib/cgi.rb
@@ -288,7 +288,7 @@
#
class CGI
- VERSION = "0.4.1"
+ VERSION = "0.3.7"
end
require 'cgi/core'
diff --git a/lib/cgi/cookie.rb b/lib/cgi/cookie.rb
index 9498e2f9fa..1c4ef6a600 100644
--- a/lib/cgi/cookie.rb
+++ b/lib/cgi/cookie.rb
@@ -190,9 +190,10 @@ class CGI
values ||= ""
values = values.split('&').collect{|v| CGI.unescape(v,@@accept_charset) }
if cookies.has_key?(name)
- values = cookies[name].value + values
+ cookies[name].concat(values)
+ else
+ cookies[name] = Cookie.new(name, *values)
end
- cookies[name] = Cookie.new(name, *values)
end
cookies
diff --git a/lib/cgi/session.rb b/lib/cgi/session.rb
index aab60869bb..70c7ebca42 100644
--- a/lib/cgi/session.rb
+++ b/lib/cgi/session.rb
@@ -279,7 +279,7 @@ class CGI
# fields are surrounded by a <fieldset> tag in HTML 4 generation, which
# is _not_ invisible on many browsers; you may wish to disable the
# use of fieldsets with code similar to the following
- # (see https://blade.ruby-lang.org/ruby-list/37805)
+ # (see http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/37805)
#
# cgi = CGI.new("html4")
# class << cgi
diff --git a/lib/cgi/util.rb b/lib/cgi/util.rb
index 4986e544e0..ce77a0ccd5 100644
--- a/lib/cgi/util.rb
+++ b/lib/cgi/util.rb
@@ -36,7 +36,7 @@ module CGI::Util
# URL-encode a string following RFC 3986
# Space characters (+" "+) are encoded with (+"%20"+)
- # url_encoded_string = CGI.escapeURIComponent("'Stop!' said Fred")
+ # url_encoded_string = CGI.escape("'Stop!' said Fred")
# # => "%27Stop%21%27%20said%20Fred"
def escapeURIComponent(string)
encoding = string.encoding
@@ -46,10 +46,9 @@ module CGI::Util
end
buffer.force_encoding(encoding)
end
- alias escape_uri_component escapeURIComponent
# URL-decode a string following RFC 3986 with encoding(optional).
- # string = CGI.unescapeURIComponent("%27Stop%21%27+said%20Fred")
+ # string = CGI.unescape("%27Stop%21%27+said%20Fred")
# # => "'Stop!'+said Fred"
def unescapeURIComponent(string, encoding = @@accept_charset)
str = string.b
@@ -60,8 +59,6 @@ module CGI::Util
str.valid_encoding? ? str : str.force_encoding(string.encoding)
end
- alias unescape_uri_component unescapeURIComponent
-
# The set of special characters and their escaped values
TABLE_FOR_ESCAPE_HTML__ = {
"'" => '&#39;',
@@ -93,12 +90,9 @@ module CGI::Util
end
end
- # TruffleRuby runs the pure-Ruby variant faster, do not use the C extension there
- unless RUBY_ENGINE == 'truffleruby'
- begin
- require 'cgi/escape'
- rescue LoadError
- end
+ begin
+ require 'cgi/escape'
+ rescue LoadError
end
# Unescape a string that has been HTML-escaped
@@ -184,7 +178,7 @@ module CGI::Util
def escapeElement(string, *elements)
elements = elements[0] if elements[0].kind_of?(Array)
unless elements.empty?
- string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/i) do
+ string.gsub(/<\/?(?:#{elements.join("|")})\b[^<>]*+>?/im) do
CGI.escapeHTML($&)
end
else
@@ -204,7 +198,7 @@ module CGI::Util
def unescapeElement(string, *elements)
elements = elements[0] if elements[0].kind_of?(Array)
unless elements.empty?
- string.gsub(/&lt;\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?&gt;/i) do
+ string.gsub(/&lt;\/?(?:#{elements.join("|")})\b(?>[^&]+|&(?![gl]t;)\w+;)*(?:&gt;)?/im) do
unescapeHTML($&)
end
else
diff --git a/lib/csv.rb b/lib/csv.rb
new file mode 100644
index 0000000000..0307033941
--- /dev/null
+++ b/lib/csv.rb
@@ -0,0 +1,2881 @@
+# encoding: US-ASCII
+# frozen_string_literal: true
+# = csv.rb -- CSV Reading and Writing
+#
+# Created by James Edward Gray II on 2005-10-31.
+#
+# See CSV for documentation.
+#
+# == Description
+#
+# Welcome to the new and improved CSV.
+#
+# This version of the CSV library began its life as FasterCSV. FasterCSV was
+# intended as a replacement to Ruby's then standard CSV library. It was
+# designed to address concerns users of that library had and it had three
+# primary goals:
+#
+# 1. Be significantly faster than CSV while remaining a pure Ruby library.
+# 2. Use a smaller and easier to maintain code base. (FasterCSV eventually
+# grew larger, was also but considerably richer in features. The parsing
+# core remains quite small.)
+# 3. Improve on the CSV interface.
+#
+# Obviously, the last one is subjective. I did try to defer to the original
+# interface whenever I didn't have a compelling reason to change it though, so
+# hopefully this won't be too radically different.
+#
+# We must have met our goals because FasterCSV was renamed to CSV and replaced
+# the original library as of Ruby 1.9. If you are migrating code from 1.8 or
+# earlier, you may have to change your code to comply with the new interface.
+#
+# == What's the Different From the Old CSV?
+#
+# I'm sure I'll miss something, but I'll try to mention most of the major
+# differences I am aware of, to help others quickly get up to speed:
+#
+# === \CSV Parsing
+#
+# * This parser is m17n aware. See CSV for full details.
+# * This library has a stricter parser and will throw MalformedCSVErrors on
+# problematic data.
+# * This library has a less liberal idea of a line ending than CSV. What you
+# set as the <tt>:row_sep</tt> is law. It can auto-detect your line endings
+# though.
+# * The old library returned empty lines as <tt>[nil]</tt>. This library calls
+# them <tt>[]</tt>.
+# * This library has a much faster parser.
+#
+# === Interface
+#
+# * CSV now uses keyword parameters to set options.
+# * CSV no longer has generate_row() or parse_row().
+# * The old CSV's Reader and Writer classes have been dropped.
+# * CSV::open() is now more like Ruby's open().
+# * CSV objects now support most standard IO methods.
+# * CSV now has a new() method used to wrap objects like String and IO for
+# reading and writing.
+# * CSV::generate() is different from the old method.
+# * CSV no longer supports partial reads. It works line-by-line.
+# * CSV no longer allows the instance methods to override the separators for
+# performance reasons. They must be set in the constructor.
+#
+# If you use this library and find yourself missing any functionality I have
+# trimmed, please {let me know}[mailto:james@grayproductions.net].
+#
+# == Documentation
+#
+# See CSV for documentation.
+#
+# == What is CSV, really?
+#
+# CSV maintains a pretty strict definition of CSV taken directly from
+# {the RFC}[http://www.ietf.org/rfc/rfc4180.txt]. I relax the rules in only one
+# place and that is to make using this library easier. CSV will parse all valid
+# CSV.
+#
+# What you don't want to do is to feed CSV invalid data. Because of the way the
+# CSV format works, it's common for a parser to need to read until the end of
+# the file to be sure a field is invalid. This consumes a lot of time and memory.
+#
+# Luckily, when working with invalid CSV, Ruby's built-in methods will almost
+# always be superior in every way. For example, parsing non-quoted fields is as
+# easy as:
+#
+# data.split(",")
+#
+# == Questions and/or Comments
+#
+# Feel free to email {James Edward Gray II}[mailto:james@grayproductions.net]
+# with any questions.
+
+require "forwardable"
+require "date"
+require "stringio"
+
+require_relative "csv/fields_converter"
+require_relative "csv/input_record_separator"
+require_relative "csv/parser"
+require_relative "csv/row"
+require_relative "csv/table"
+require_relative "csv/writer"
+
+# == \CSV
+#
+# === In a Hurry?
+#
+# If you are familiar with \CSV data and have a particular task in mind,
+# you may want to go directly to the:
+# - {Recipes for CSV}[doc/csv/recipes/recipes_rdoc.html].
+#
+# Otherwise, read on here, about the API: classes, methods, and constants.
+#
+# === \CSV Data
+#
+# \CSV (comma-separated values) data is a text representation of a table:
+# - A _row_ _separator_ delimits table rows.
+# A common row separator is the newline character <tt>"\n"</tt>.
+# - A _column_ _separator_ delimits fields in a row.
+# A common column separator is the comma character <tt>","</tt>.
+#
+# This \CSV \String, with row separator <tt>"\n"</tt>
+# and column separator <tt>","</tt>,
+# has three rows and two columns:
+# "foo,0\nbar,1\nbaz,2\n"
+#
+# Despite the name \CSV, a \CSV representation can use different separators.
+#
+# For more about tables, see the Wikipedia article
+# "{Table (information)}[https://en.wikipedia.org/wiki/Table_(information)]",
+# especially its section
+# "{Simple table}[https://en.wikipedia.org/wiki/Table_(information)#Simple_table]"
+#
+# == \Class \CSV
+#
+# Class \CSV provides methods for:
+# - Parsing \CSV data from a \String object, a \File (via its file path), or an \IO object.
+# - Generating \CSV data to a \String object.
+#
+# To make \CSV available:
+# require 'csv'
+#
+# All examples here assume that this has been done.
+#
+# == Keeping It Simple
+#
+# A \CSV object has dozens of instance methods that offer fine-grained control
+# of parsing and generating \CSV data.
+# For many needs, though, simpler approaches will do.
+#
+# This section summarizes the singleton methods in \CSV
+# that allow you to parse and generate without explicitly
+# creating \CSV objects.
+# For details, follow the links.
+#
+# === Simple Parsing
+#
+# Parsing methods commonly return either of:
+# - An \Array of Arrays of Strings:
+# - The outer \Array is the entire "table".
+# - Each inner \Array is a row.
+# - Each \String is a field.
+# - A CSV::Table object. For details, see
+# {\CSV with Headers}[#class-CSV-label-CSV+with+Headers].
+#
+# ==== Parsing a \String
+#
+# The input to be parsed can be a string:
+# string = "foo,0\nbar,1\nbaz,2\n"
+#
+# \Method CSV.parse returns the entire \CSV data:
+# CSV.parse(string) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+#
+# \Method CSV.parse_line returns only the first row:
+# CSV.parse_line(string) # => ["foo", "0"]
+#
+# \CSV extends class \String with instance method String#parse_csv,
+# which also returns only the first row:
+# string.parse_csv # => ["foo", "0"]
+#
+# ==== Parsing Via a \File Path
+#
+# The input to be parsed can be in a file:
+# string = "foo,0\nbar,1\nbaz,2\n"
+# path = 't.csv'
+# File.write(path, string)
+#
+# \Method CSV.read returns the entire \CSV data:
+# CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+#
+# \Method CSV.foreach iterates, passing each row to the given block:
+# CSV.foreach(path) do |row|
+# p row
+# end
+# Output:
+# ["foo", "0"]
+# ["bar", "1"]
+# ["baz", "2"]
+#
+# \Method CSV.table returns the entire \CSV data as a CSV::Table object:
+# CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:3>
+#
+# ==== Parsing from an Open \IO Stream
+#
+# The input to be parsed can be in an open \IO stream:
+#
+# \Method CSV.read returns the entire \CSV data:
+# File.open(path) do |file|
+# CSV.read(file)
+# end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+#
+# As does method CSV.parse:
+# File.open(path) do |file|
+# CSV.parse(file)
+# end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+#
+# \Method CSV.parse_line returns only the first row:
+# File.open(path) do |file|
+# CSV.parse_line(file)
+# end # => ["foo", "0"]
+#
+# \Method CSV.foreach iterates, passing each row to the given block:
+# File.open(path) do |file|
+# CSV.foreach(file) do |row|
+# p row
+# end
+# end
+# Output:
+# ["foo", "0"]
+# ["bar", "1"]
+# ["baz", "2"]
+#
+# \Method CSV.table returns the entire \CSV data as a CSV::Table object:
+# File.open(path) do |file|
+# CSV.table(file)
+# end # => #<CSV::Table mode:col_or_row row_count:3>
+#
+# === Simple Generating
+#
+# \Method CSV.generate returns a \String;
+# this example uses method CSV#<< to append the rows
+# that are to be generated:
+# output_string = CSV.generate do |csv|
+# csv << ['foo', 0]
+# csv << ['bar', 1]
+# csv << ['baz', 2]
+# end
+# output_string # => "foo,0\nbar,1\nbaz,2\n"
+#
+# \Method CSV.generate_line returns a \String containing the single row
+# constructed from an \Array:
+# CSV.generate_line(['foo', '0']) # => "foo,0\n"
+#
+# \CSV extends class \Array with instance method <tt>Array#to_csv</tt>,
+# which forms an \Array into a \String:
+# ['foo', '0'].to_csv # => "foo,0\n"
+#
+# === "Filtering" \CSV
+#
+# \Method CSV.filter provides a Unix-style filter for \CSV data.
+# The input data is processed to form the output data:
+# in_string = "foo,0\nbar,1\nbaz,2\n"
+# out_string = ''
+# CSV.filter(in_string, out_string) do |row|
+# row[0] = row[0].upcase
+# row[1] *= 4
+# end
+# out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
+#
+# == \CSV Objects
+#
+# There are three ways to create a \CSV object:
+# - \Method CSV.new returns a new \CSV object.
+# - \Method CSV.instance returns a new or cached \CSV object.
+# - \Method \CSV() also returns a new or cached \CSV object.
+#
+# === Instance Methods
+#
+# \CSV has three groups of instance methods:
+# - Its own internally defined instance methods.
+# - Methods included by module Enumerable.
+# - Methods delegated to class IO. See below.
+#
+# ==== Delegated Methods
+#
+# For convenience, a CSV object will delegate to many methods in class IO.
+# (A few have wrapper "guard code" in \CSV.) You may call:
+# * IO#binmode
+# * #binmode?
+# * IO#close
+# * IO#close_read
+# * IO#close_write
+# * IO#closed?
+# * #eof
+# * #eof?
+# * IO#external_encoding
+# * IO#fcntl
+# * IO#fileno
+# * #flock
+# * IO#flush
+# * IO#fsync
+# * IO#internal_encoding
+# * #ioctl
+# * IO#isatty
+# * #path
+# * IO#pid
+# * IO#pos
+# * IO#pos=
+# * IO#reopen
+# * #rewind
+# * IO#seek
+# * #stat
+# * IO#string
+# * IO#sync
+# * IO#sync=
+# * IO#tell
+# * #to_i
+# * #to_io
+# * IO#truncate
+# * IO#tty?
+#
+# === Options
+#
+# The default values for options are:
+# DEFAULT_OPTIONS = {
+# # For both parsing and generating.
+# col_sep: ",",
+# row_sep: :auto,
+# quote_char: '"',
+# # For parsing.
+# field_size_limit: nil,
+# converters: nil,
+# unconverted_fields: nil,
+# headers: false,
+# return_headers: false,
+# header_converters: nil,
+# skip_blanks: false,
+# skip_lines: nil,
+# liberal_parsing: false,
+# nil_value: nil,
+# empty_value: "",
+# strip: false,
+# # For generating.
+# write_headers: nil,
+# quote_empty: true,
+# force_quotes: false,
+# write_converters: nil,
+# write_nil_value: nil,
+# write_empty_value: "",
+# }
+#
+# ==== Options for Parsing
+#
+# Options for parsing, described in detail below, include:
+# - +row_sep+: Specifies the row separator; used to delimit rows.
+# - +col_sep+: Specifies the column separator; used to delimit fields.
+# - +quote_char+: Specifies the quote character; used to quote fields.
+# - +field_size_limit+: Specifies the maximum field size + 1 allowed.
+# Deprecated since 3.2.3. Use +max_field_size+ instead.
+# - +max_field_size+: Specifies the maximum field size allowed.
+# - +converters+: Specifies the field converters to be used.
+# - +unconverted_fields+: Specifies whether unconverted fields are to be available.
+# - +headers+: Specifies whether data contains headers,
+# or specifies the headers themselves.
+# - +return_headers+: Specifies whether headers are to be returned.
+# - +header_converters+: Specifies the header converters to be used.
+# - +skip_blanks+: Specifies whether blanks lines are to be ignored.
+# - +skip_lines+: Specifies how comments lines are to be recognized.
+# - +strip+: Specifies whether leading and trailing whitespace are to be
+# stripped from fields. This must be compatible with +col_sep+; if it is not,
+# then an +ArgumentError+ exception will be raised.
+# - +liberal_parsing+: Specifies whether \CSV should attempt to parse
+# non-compliant data.
+# - +nil_value+: Specifies the object that is to be substituted for each null (no-text) field.
+# - +empty_value+: Specifies the object that is to be substituted for each empty field.
+#
+# :include: ../doc/csv/options/common/row_sep.rdoc
+#
+# :include: ../doc/csv/options/common/col_sep.rdoc
+#
+# :include: ../doc/csv/options/common/quote_char.rdoc
+#
+# :include: ../doc/csv/options/parsing/field_size_limit.rdoc
+#
+# :include: ../doc/csv/options/parsing/converters.rdoc
+#
+# :include: ../doc/csv/options/parsing/unconverted_fields.rdoc
+#
+# :include: ../doc/csv/options/parsing/headers.rdoc
+#
+# :include: ../doc/csv/options/parsing/return_headers.rdoc
+#
+# :include: ../doc/csv/options/parsing/header_converters.rdoc
+#
+# :include: ../doc/csv/options/parsing/skip_blanks.rdoc
+#
+# :include: ../doc/csv/options/parsing/skip_lines.rdoc
+#
+# :include: ../doc/csv/options/parsing/strip.rdoc
+#
+# :include: ../doc/csv/options/parsing/liberal_parsing.rdoc
+#
+# :include: ../doc/csv/options/parsing/nil_value.rdoc
+#
+# :include: ../doc/csv/options/parsing/empty_value.rdoc
+#
+# ==== Options for Generating
+#
+# Options for generating, described in detail below, include:
+# - +row_sep+: Specifies the row separator; used to delimit rows.
+# - +col_sep+: Specifies the column separator; used to delimit fields.
+# - +quote_char+: Specifies the quote character; used to quote fields.
+# - +write_headers+: Specifies whether headers are to be written.
+# - +force_quotes+: Specifies whether each output field is to be quoted.
+# - +quote_empty+: Specifies whether each empty output field is to be quoted.
+# - +write_converters+: Specifies the field converters to be used in writing.
+# - +write_nil_value+: Specifies the object that is to be substituted for each +nil+-valued field.
+# - +write_empty_value+: Specifies the object that is to be substituted for each empty field.
+#
+# :include: ../doc/csv/options/common/row_sep.rdoc
+#
+# :include: ../doc/csv/options/common/col_sep.rdoc
+#
+# :include: ../doc/csv/options/common/quote_char.rdoc
+#
+# :include: ../doc/csv/options/generating/write_headers.rdoc
+#
+# :include: ../doc/csv/options/generating/force_quotes.rdoc
+#
+# :include: ../doc/csv/options/generating/quote_empty.rdoc
+#
+# :include: ../doc/csv/options/generating/write_converters.rdoc
+#
+# :include: ../doc/csv/options/generating/write_nil_value.rdoc
+#
+# :include: ../doc/csv/options/generating/write_empty_value.rdoc
+#
+# === \CSV with Headers
+#
+# CSV allows to specify column names of CSV file, whether they are in data, or
+# provided separately. If headers are specified, reading methods return an instance
+# of CSV::Table, consisting of CSV::Row.
+#
+# # Headers are part of data
+# data = CSV.parse(<<~ROWS, headers: true)
+# Name,Department,Salary
+# Bob,Engineering,1000
+# Jane,Sales,2000
+# John,Management,5000
+# ROWS
+#
+# data.class #=> CSV::Table
+# data.first #=> #<CSV::Row "Name":"Bob" "Department":"Engineering" "Salary":"1000">
+# data.first.to_h #=> {"Name"=>"Bob", "Department"=>"Engineering", "Salary"=>"1000"}
+#
+# # Headers provided by developer
+# data = CSV.parse('Bob,Engineering,1000', headers: %i[name department salary])
+# data.first #=> #<CSV::Row name:"Bob" department:"Engineering" salary:"1000">
+#
+# === \Converters
+#
+# By default, each value (field or header) parsed by \CSV is formed into a \String.
+# You can use a _field_ _converter_ or _header_ _converter_
+# to intercept and modify the parsed values:
+# - See {Field Converters}[#class-CSV-label-Field+Converters].
+# - See {Header Converters}[#class-CSV-label-Header+Converters].
+#
+# Also by default, each value to be written during generation is written 'as-is'.
+# You can use a _write_ _converter_ to modify values before writing.
+# - See {Write Converters}[#class-CSV-label-Write+Converters].
+#
+# ==== Specifying \Converters
+#
+# You can specify converters for parsing or generating in the +options+
+# argument to various \CSV methods:
+# - Option +converters+ for converting parsed field values.
+# - Option +header_converters+ for converting parsed header values.
+# - Option +write_converters+ for converting values to be written (generated).
+#
+# There are three forms for specifying converters:
+# - A converter proc: executable code to be used for conversion.
+# - A converter name: the name of a stored converter.
+# - A converter list: an array of converter procs, converter names, and converter lists.
+#
+# ===== Converter Procs
+#
+# This converter proc, +strip_converter+, accepts a value +field+
+# and returns <tt>field.strip</tt>:
+# strip_converter = proc {|field| field.strip }
+# In this call to <tt>CSV.parse</tt>,
+# the keyword argument <tt>converters: string_converter</tt>
+# specifies that:
+# - \Proc +string_converter+ is to be called for each parsed field.
+# - The converter's return value is to replace the +field+ value.
+# Example:
+# string = " foo , 0 \n bar , 1 \n baz , 2 \n"
+# array = CSV.parse(string, converters: strip_converter)
+# array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+#
+# A converter proc can receive a second argument, +field_info+,
+# that contains details about the field.
+# This modified +strip_converter+ displays its arguments:
+# strip_converter = proc do |field, field_info|
+# p [field, field_info]
+# field.strip
+# end
+# string = " foo , 0 \n bar , 1 \n baz , 2 \n"
+# array = CSV.parse(string, converters: strip_converter)
+# array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+# Output:
+# [" foo ", #<struct CSV::FieldInfo index=0, line=1, header=nil>]
+# [" 0 ", #<struct CSV::FieldInfo index=1, line=1, header=nil>]
+# [" bar ", #<struct CSV::FieldInfo index=0, line=2, header=nil>]
+# [" 1 ", #<struct CSV::FieldInfo index=1, line=2, header=nil>]
+# [" baz ", #<struct CSV::FieldInfo index=0, line=3, header=nil>]
+# [" 2 ", #<struct CSV::FieldInfo index=1, line=3, header=nil>]
+# Each CSV::FieldInfo object shows:
+# - The 0-based field index.
+# - The 1-based line index.
+# - The field header, if any.
+#
+# ===== Stored \Converters
+#
+# A converter may be given a name and stored in a structure where
+# the parsing methods can find it by name.
+#
+# The storage structure for field converters is the \Hash CSV::Converters.
+# It has several built-in converter procs:
+# - <tt>:integer</tt>: converts each \String-embedded integer into a true \Integer.
+# - <tt>:float</tt>: converts each \String-embedded float into a true \Float.
+# - <tt>:date</tt>: converts each \String-embedded date into a true \Date.
+# - <tt>:date_time</tt>: converts each \String-embedded date-time into a true \DateTime
+# .
+# This example creates a converter proc, then stores it:
+# strip_converter = proc {|field| field.strip }
+# CSV::Converters[:strip] = strip_converter
+# Then the parsing method call can refer to the converter
+# by its name, <tt>:strip</tt>:
+# string = " foo , 0 \n bar , 1 \n baz , 2 \n"
+# array = CSV.parse(string, converters: :strip)
+# array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+#
+# The storage structure for header converters is the \Hash CSV::HeaderConverters,
+# which works in the same way.
+# It also has built-in converter procs:
+# - <tt>:downcase</tt>: Downcases each header.
+# - <tt>:symbol</tt>: Converts each header to a \Symbol.
+#
+# There is no such storage structure for write headers.
+#
+# In order for the parsing methods to access stored converters in non-main-Ractors, the
+# storage structure must be made shareable first.
+# Therefore, <tt>Ractor.make_shareable(CSV::Converters)</tt> and
+# <tt>Ractor.make_shareable(CSV::HeaderConverters)</tt> must be called before the creation
+# of Ractors that use the converters stored in these structures. (Since making the storage
+# structures shareable involves freezing them, any custom converters that are to be used
+# must be added first.)
+#
+# ===== Converter Lists
+#
+# A _converter_ _list_ is an \Array that may include any assortment of:
+# - Converter procs.
+# - Names of stored converters.
+# - Nested converter lists.
+#
+# Examples:
+# numeric_converters = [:integer, :float]
+# date_converters = [:date, :date_time]
+# [numeric_converters, strip_converter]
+# [strip_converter, date_converters, :float]
+#
+# Like a converter proc, a converter list may be named and stored in either
+# \CSV::Converters or CSV::HeaderConverters:
+# CSV::Converters[:custom] = [strip_converter, date_converters, :float]
+# CSV::HeaderConverters[:custom] = [:downcase, :symbol]
+#
+# There are two built-in converter lists:
+# CSV::Converters[:numeric] # => [:integer, :float]
+# CSV::Converters[:all] # => [:date_time, :numeric]
+#
+# ==== Field \Converters
+#
+# With no conversion, all parsed fields in all rows become Strings:
+# string = "foo,0\nbar,1\nbaz,2\n"
+# ary = CSV.parse(string)
+# ary # => # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+#
+# When you specify a field converter, each parsed field is passed to the converter;
+# its return value becomes the stored value for the field.
+# A converter might, for example, convert an integer embedded in a \String
+# into a true \Integer.
+# (In fact, that's what built-in field converter +:integer+ does.)
+#
+# There are three ways to use field \converters.
+#
+# - Using option {converters}[#class-CSV-label-Option+converters] with a parsing method:
+# ary = CSV.parse(string, converters: :integer)
+# ary # => [0, 1, 2] # => [["foo", 0], ["bar", 1], ["baz", 2]]
+# - Using option {converters}[#class-CSV-label-Option+converters] with a new \CSV instance:
+# csv = CSV.new(string, converters: :integer)
+# # Field converters in effect:
+# csv.converters # => [:integer]
+# csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
+# - Using method #convert to add a field converter to a \CSV instance:
+# csv = CSV.new(string)
+# # Add a converter.
+# csv.convert(:integer)
+# csv.converters # => [:integer]
+# csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
+#
+# Installing a field converter does not affect already-read rows:
+# csv = CSV.new(string)
+# csv.shift # => ["foo", "0"]
+# # Add a converter.
+# csv.convert(:integer)
+# csv.converters # => [:integer]
+# csv.read # => [["bar", 1], ["baz", 2]]
+#
+# There are additional built-in \converters, and custom \converters are also supported.
+#
+# ===== Built-In Field \Converters
+#
+# The built-in field converters are in \Hash CSV::Converters:
+# - Each key is a field converter name.
+# - Each value is one of:
+# - A \Proc field converter.
+# - An \Array of field converter names.
+#
+# Display:
+# CSV::Converters.each_pair do |name, value|
+# if value.kind_of?(Proc)
+# p [name, value.class]
+# else
+# p [name, value]
+# end
+# end
+# Output:
+# [:integer, Proc]
+# [:float, Proc]
+# [:numeric, [:integer, :float]]
+# [:date, Proc]
+# [:date_time, Proc]
+# [:all, [:date_time, :numeric]]
+#
+# Each of these converters transcodes values to UTF-8 before attempting conversion.
+# If a value cannot be transcoded to UTF-8 the conversion will
+# fail and the value will remain unconverted.
+#
+# Converter +:integer+ converts each field that Integer() accepts:
+# data = '0,1,2,x'
+# # Without the converter
+# csv = CSV.parse_line(data)
+# csv # => ["0", "1", "2", "x"]
+# # With the converter
+# csv = CSV.parse_line(data, converters: :integer)
+# csv # => [0, 1, 2, "x"]
+#
+# Converter +:float+ converts each field that Float() accepts:
+# data = '1.0,3.14159,x'
+# # Without the converter
+# csv = CSV.parse_line(data)
+# csv # => ["1.0", "3.14159", "x"]
+# # With the converter
+# csv = CSV.parse_line(data, converters: :float)
+# csv # => [1.0, 3.14159, "x"]
+#
+# Converter +:numeric+ converts with both +:integer+ and +:float+..
+#
+# Converter +:date+ converts each field that Date::parse accepts:
+# data = '2001-02-03,x'
+# # Without the converter
+# csv = CSV.parse_line(data)
+# csv # => ["2001-02-03", "x"]
+# # With the converter
+# csv = CSV.parse_line(data, converters: :date)
+# csv # => [#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>, "x"]
+#
+# Converter +:date_time+ converts each field that DateTime::parse accepts:
+# data = '2020-05-07T14:59:00-05:00,x'
+# # Without the converter
+# csv = CSV.parse_line(data)
+# csv # => ["2020-05-07T14:59:00-05:00", "x"]
+# # With the converter
+# csv = CSV.parse_line(data, converters: :date_time)
+# csv # => [#<DateTime: 2020-05-07T14:59:00-05:00 ((2458977j,71940s,0n),-18000s,2299161j)>, "x"]
+#
+# Converter +:numeric+ converts with both +:date_time+ and +:numeric+..
+#
+# As seen above, method #convert adds \converters to a \CSV instance,
+# and method #converters returns an \Array of the \converters in effect:
+# csv = CSV.new('0,1,2')
+# csv.converters # => []
+# csv.convert(:integer)
+# csv.converters # => [:integer]
+# csv.convert(:date)
+# csv.converters # => [:integer, :date]
+#
+# ===== Custom Field \Converters
+#
+# You can define a custom field converter:
+# strip_converter = proc {|field| field.strip }
+# string = " foo , 0 \n bar , 1 \n baz , 2 \n"
+# array = CSV.parse(string, converters: strip_converter)
+# array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+# You can register the converter in \Converters \Hash,
+# which allows you to refer to it by name:
+# CSV::Converters[:strip] = strip_converter
+# string = " foo , 0 \n bar , 1 \n baz , 2 \n"
+# array = CSV.parse(string, converters: :strip)
+# array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+#
+# ==== Header \Converters
+#
+# Header converters operate only on headers (and not on other rows).
+#
+# There are three ways to use header \converters;
+# these examples use built-in header converter +:downcase+,
+# which downcases each parsed header.
+#
+# - Option +header_converters+ with a singleton parsing method:
+# string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
+# tbl = CSV.parse(string, headers: true, header_converters: :downcase)
+# tbl.class # => CSV::Table
+# tbl.headers # => ["name", "count"]
+#
+# - Option +header_converters+ with a new \CSV instance:
+# csv = CSV.new(string, header_converters: :downcase)
+# # Header converters in effect:
+# csv.header_converters # => [:downcase]
+# tbl = CSV.parse(string, headers: true)
+# tbl.headers # => ["Name", "Count"]
+#
+# - Method #header_convert adds a header converter to a \CSV instance:
+# csv = CSV.new(string)
+# # Add a header converter.
+# csv.header_convert(:downcase)
+# csv.header_converters # => [:downcase]
+# tbl = CSV.parse(string, headers: true)
+# tbl.headers # => ["Name", "Count"]
+#
+# ===== Built-In Header \Converters
+#
+# The built-in header \converters are in \Hash CSV::HeaderConverters.
+# The keys there are the names of the \converters:
+# CSV::HeaderConverters.keys # => [:downcase, :symbol]
+#
+# Converter +:downcase+ converts each header by downcasing it:
+# string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
+# tbl = CSV.parse(string, headers: true, header_converters: :downcase)
+# tbl.class # => CSV::Table
+# tbl.headers # => ["name", "count"]
+#
+# Converter +:symbol+ converts each header by making it into a \Symbol:
+# string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
+# tbl = CSV.parse(string, headers: true, header_converters: :symbol)
+# tbl.headers # => [:name, :count]
+# Details:
+# - Strips leading and trailing whitespace.
+# - Downcases the header.
+# - Replaces embedded spaces with underscores.
+# - Removes non-word characters.
+# - Makes the string into a \Symbol.
+#
+# ===== Custom Header \Converters
+#
+# You can define a custom header converter:
+# upcase_converter = proc {|header| header.upcase }
+# string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+# table = CSV.parse(string, headers: true, header_converters: upcase_converter)
+# table # => #<CSV::Table mode:col_or_row row_count:4>
+# table.headers # => ["NAME", "VALUE"]
+# You can register the converter in \HeaderConverters \Hash,
+# which allows you to refer to it by name:
+# CSV::HeaderConverters[:upcase] = upcase_converter
+# table = CSV.parse(string, headers: true, header_converters: :upcase)
+# table # => #<CSV::Table mode:col_or_row row_count:4>
+# table.headers # => ["NAME", "VALUE"]
+#
+# ===== Write \Converters
+#
+# When you specify a write converter for generating \CSV,
+# each field to be written is passed to the converter;
+# its return value becomes the new value for the field.
+# A converter might, for example, strip whitespace from a field.
+#
+# Using no write converter (all fields unmodified):
+# output_string = CSV.generate do |csv|
+# csv << [' foo ', 0]
+# csv << [' bar ', 1]
+# csv << [' baz ', 2]
+# end
+# output_string # => " foo ,0\n bar ,1\n baz ,2\n"
+# Using option +write_converters+ with two custom write converters:
+# strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field }
+# upcase_converter = proc {|field| field.respond_to?(:upcase) ? field.upcase : field }
+# write_converters = [strip_converter, upcase_converter]
+# output_string = CSV.generate(write_converters: write_converters) do |csv|
+# csv << [' foo ', 0]
+# csv << [' bar ', 1]
+# csv << [' baz ', 2]
+# end
+# output_string # => "FOO,0\nBAR,1\nBAZ,2\n"
+#
+# === Character Encodings (M17n or Multilingualization)
+#
+# This new CSV parser is m17n savvy. The parser works in the Encoding of the IO
+# or String object being read from or written to. Your data is never transcoded
+# (unless you ask Ruby to transcode it for you) and will literally be parsed in
+# the Encoding it is in. Thus CSV will return Arrays or Rows of Strings in the
+# Encoding of your data. This is accomplished by transcoding the parser itself
+# into your Encoding.
+#
+# Some transcoding must take place, of course, to accomplish this multiencoding
+# support. For example, <tt>:col_sep</tt>, <tt>:row_sep</tt>, and
+# <tt>:quote_char</tt> must be transcoded to match your data. Hopefully this
+# makes the entire process feel transparent, since CSV's defaults should just
+# magically work for your data. However, you can set these values manually in
+# the target Encoding to avoid the translation.
+#
+# It's also important to note that while all of CSV's core parser is now
+# Encoding agnostic, some features are not. For example, the built-in
+# converters will try to transcode data to UTF-8 before making conversions.
+# Again, you can provide custom converters that are aware of your Encodings to
+# avoid this translation. It's just too hard for me to support native
+# conversions in all of Ruby's Encodings.
+#
+# Anyway, the practical side of this is simple: make sure IO and String objects
+# passed into CSV have the proper Encoding set and everything should just work.
+# CSV methods that allow you to open IO objects (CSV::foreach(), CSV::open(),
+# CSV::read(), and CSV::readlines()) do allow you to specify the Encoding.
+#
+# One minor exception comes when generating CSV into a String with an Encoding
+# that is not ASCII compatible. There's no existing data for CSV to use to
+# prepare itself and thus you will probably need to manually specify the desired
+# Encoding for most of those cases. It will try to guess using the fields in a
+# row of output though, when using CSV::generate_line() or Array#to_csv().
+#
+# I try to point out any other Encoding issues in the documentation of methods
+# as they come up.
+#
+# This has been tested to the best of my ability with all non-"dummy" Encodings
+# Ruby ships with. However, it is brave new code and may have some bugs.
+# Please feel free to {report}[mailto:james@grayproductions.net] any issues you
+# find with it.
+#
+class CSV
+
+ # The error thrown when the parser encounters illegal CSV formatting.
+ class MalformedCSVError < RuntimeError
+ attr_reader :line_number
+ alias_method :lineno, :line_number
+ def initialize(message, line_number)
+ @line_number = line_number
+ super("#{message} in line #{line_number}.")
+ end
+ end
+
+ #
+ # A FieldInfo Struct contains details about a field's position in the data
+ # source it was read from. CSV will pass this Struct to some blocks that make
+ # decisions based on field structure. See CSV.convert_fields() for an
+ # example.
+ #
+ # <b><tt>index</tt></b>:: The zero-based index of the field in its row.
+ # <b><tt>line</tt></b>:: The line of the data source this row is from.
+ # <b><tt>header</tt></b>:: The header for the column, when available.
+ # <b><tt>quoted?</tt></b>:: True or false, whether the original value is quoted or not.
+ #
+ FieldInfo = Struct.new(:index, :line, :header, :quoted?)
+
+ # A Regexp used to find and convert some common Date formats.
+ DateMatcher = / \A(?: (\w+,?\s+)?\w+\s+\d{1,2},?\s+\d{2,4} |
+ \d{4}-\d{2}-\d{2} )\z /x
+ # A Regexp used to find and convert some common DateTime formats.
+ DateTimeMatcher =
+ / \A(?: (\w+,?\s+)?\w+\s+\d{1,2}\s+\d{1,2}:\d{1,2}:\d{1,2},?\s+\d{2,4} |
+ # ISO-8601 and RFC-3339 (space instead of T) recognized by DateTime.parse
+ \d{4}-\d{2}-\d{2}
+ (?:[T\s]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?(?:[+-]\d{2}(?::\d{2})|Z)?)?)?
+ )\z /x
+
+ # The encoding used by all converters.
+ ConverterEncoding = Encoding.find("UTF-8")
+
+ # A \Hash containing the names and \Procs for the built-in field converters.
+ # See {Built-In Field Converters}[#class-CSV-label-Built-In+Field+Converters].
+ #
+ # This \Hash is intentionally left unfrozen, and may be extended with
+ # custom field converters.
+ # See {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters].
+ Converters = {
+ integer: lambda { |f|
+ Integer(f.encode(ConverterEncoding)) rescue f
+ },
+ float: lambda { |f|
+ Float(f.encode(ConverterEncoding)) rescue f
+ },
+ numeric: [:integer, :float],
+ date: lambda { |f|
+ begin
+ e = f.encode(ConverterEncoding)
+ e.match?(DateMatcher) ? Date.parse(e) : f
+ rescue # encoding conversion or date parse errors
+ f
+ end
+ },
+ date_time: lambda { |f|
+ begin
+ e = f.encode(ConverterEncoding)
+ e.match?(DateTimeMatcher) ? DateTime.parse(e) : f
+ rescue # encoding conversion or date parse errors
+ f
+ end
+ },
+ all: [:date_time, :numeric],
+ }
+
+ # A \Hash containing the names and \Procs for the built-in header converters.
+ # See {Built-In Header Converters}[#class-CSV-label-Built-In+Header+Converters].
+ #
+ # This \Hash is intentionally left unfrozen, and may be extended with
+ # custom field converters.
+ # See {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters].
+ HeaderConverters = {
+ downcase: lambda { |h| h.encode(ConverterEncoding).downcase },
+ symbol: lambda { |h|
+ h.encode(ConverterEncoding).downcase.gsub(/[^\s\w]+/, "").strip.
+ gsub(/\s+/, "_").to_sym
+ },
+ symbol_raw: lambda { |h| h.encode(ConverterEncoding).to_sym }
+ }
+
+ # Default values for method options.
+ DEFAULT_OPTIONS = {
+ # For both parsing and generating.
+ col_sep: ",",
+ row_sep: :auto,
+ quote_char: '"',
+ # For parsing.
+ field_size_limit: nil,
+ max_field_size: nil,
+ converters: nil,
+ unconverted_fields: nil,
+ headers: false,
+ return_headers: false,
+ header_converters: nil,
+ skip_blanks: false,
+ skip_lines: nil,
+ liberal_parsing: false,
+ nil_value: nil,
+ empty_value: "",
+ strip: false,
+ # For generating.
+ write_headers: nil,
+ quote_empty: true,
+ force_quotes: false,
+ write_converters: nil,
+ write_nil_value: nil,
+ write_empty_value: "",
+ }.freeze
+
+ class << self
+ # :call-seq:
+ # instance(string, **options)
+ # instance(io = $stdout, **options)
+ # instance(string, **options) {|csv| ... }
+ # instance(io = $stdout, **options) {|csv| ... }
+ #
+ # Creates or retrieves cached \CSV objects.
+ # For arguments and options, see CSV.new.
+ #
+ # This API is not Ractor-safe.
+ #
+ # ---
+ #
+ # With no block given, returns a \CSV object.
+ #
+ # The first call to +instance+ creates and caches a \CSV object:
+ # s0 = 's0'
+ # csv0 = CSV.instance(s0)
+ # csv0.class # => CSV
+ #
+ # Subsequent calls to +instance+ with that _same_ +string+ or +io+
+ # retrieve that same cached object:
+ # csv1 = CSV.instance(s0)
+ # csv1.class # => CSV
+ # csv1.equal?(csv0) # => true # Same CSV object
+ #
+ # A subsequent call to +instance+ with a _different_ +string+ or +io+
+ # creates and caches a _different_ \CSV object.
+ # s1 = 's1'
+ # csv2 = CSV.instance(s1)
+ # csv2.equal?(csv0) # => false # Different CSV object
+ #
+ # All the cached objects remains available:
+ # csv3 = CSV.instance(s0)
+ # csv3.equal?(csv0) # true # Same CSV object
+ # csv4 = CSV.instance(s1)
+ # csv4.equal?(csv2) # true # Same CSV object
+ #
+ # ---
+ #
+ # When a block is given, calls the block with the created or retrieved
+ # \CSV object; returns the block's return value:
+ # CSV.instance(s0) {|csv| :foo } # => :foo
+ def instance(data = $stdout, **options)
+ # create a _signature_ for this method call, data object and options
+ sig = [data.object_id] +
+ options.values_at(*DEFAULT_OPTIONS.keys)
+
+ # fetch or create the instance for this signature
+ @@instances ||= Hash.new
+ instance = (@@instances[sig] ||= new(data, **options))
+
+ if block_given?
+ yield instance # run block, if given, returning result
+ else
+ instance # or return the instance
+ end
+ end
+
+ # :call-seq:
+ # filter(in_string_or_io, **options) {|row| ... } -> array_of_arrays or csv_table
+ # filter(in_string_or_io, out_string_or_io, **options) {|row| ... } -> array_of_arrays or csv_table
+ # filter(**options) {|row| ... } -> array_of_arrays or csv_table
+ #
+ # - Parses \CSV from a source (\String, \IO stream, or ARGF).
+ # - Calls the given block with each parsed row:
+ # - Without headers, each row is an \Array.
+ # - With headers, each row is a CSV::Row.
+ # - Generates \CSV to an output (\String, \IO stream, or STDOUT).
+ # - Returns the parsed source:
+ # - Without headers, an \Array of \Arrays.
+ # - With headers, a CSV::Table.
+ #
+ # When +in_string_or_io+ is given, but not +out_string_or_io+,
+ # parses from the given +in_string_or_io+
+ # and generates to STDOUT.
+ #
+ # \String input without headers:
+ #
+ # in_string = "foo,0\nbar,1\nbaz,2"
+ # CSV.filter(in_string) do |row|
+ # row[0].upcase!
+ # row[1] = - row[1].to_i
+ # end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
+ #
+ # Output (to STDOUT):
+ #
+ # FOO,0
+ # BAR,-1
+ # BAZ,-2
+ #
+ # \String input with headers:
+ #
+ # in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2"
+ # CSV.filter(in_string, headers: true) do |row|
+ # row[0].upcase!
+ # row[1] = - row[1].to_i
+ # end # => #<CSV::Table mode:col_or_row row_count:4>
+ #
+ # Output (to STDOUT):
+ #
+ # Name,Value
+ # FOO,0
+ # BAR,-1
+ # BAZ,-2
+ #
+ # \IO stream input without headers:
+ #
+ # File.write('t.csv', "foo,0\nbar,1\nbaz,2")
+ # File.open('t.csv') do |in_io|
+ # CSV.filter(in_io) do |row|
+ # row[0].upcase!
+ # row[1] = - row[1].to_i
+ # end
+ # end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
+ #
+ # Output (to STDOUT):
+ #
+ # FOO,0
+ # BAR,-1
+ # BAZ,-2
+ #
+ # \IO stream input with headers:
+ #
+ # File.write('t.csv', "Name,Value\nfoo,0\nbar,1\nbaz,2")
+ # File.open('t.csv') do |in_io|
+ # CSV.filter(in_io, headers: true) do |row|
+ # row[0].upcase!
+ # row[1] = - row[1].to_i
+ # end
+ # end # => #<CSV::Table mode:col_or_row row_count:4>
+ #
+ # Output (to STDOUT):
+ #
+ # Name,Value
+ # FOO,0
+ # BAR,-1
+ # BAZ,-2
+ #
+ # When both +in_string_or_io+ and +out_string_or_io+ are given,
+ # parses from +in_string_or_io+ and generates to +out_string_or_io+.
+ #
+ # \String output without headers:
+ #
+ # in_string = "foo,0\nbar,1\nbaz,2"
+ # out_string = ''
+ # CSV.filter(in_string, out_string) do |row|
+ # row[0].upcase!
+ # row[1] = - row[1].to_i
+ # end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
+ # out_string # => "FOO,0\nBAR,-1\nBAZ,-2\n"
+ #
+ # \String output with headers:
+ #
+ # in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2"
+ # out_string = ''
+ # CSV.filter(in_string, out_string, headers: true) do |row|
+ # row[0].upcase!
+ # row[1] = - row[1].to_i
+ # end # => #<CSV::Table mode:col_or_row row_count:4>
+ # out_string # => "Name,Value\nFOO,0\nBAR,-1\nBAZ,-2\n"
+ #
+ # \IO stream output without headers:
+ #
+ # in_string = "foo,0\nbar,1\nbaz,2"
+ # File.open('t.csv', 'w') do |out_io|
+ # CSV.filter(in_string, out_io) do |row|
+ # row[0].upcase!
+ # row[1] = - row[1].to_i
+ # end
+ # end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
+ # File.read('t.csv') # => "FOO,0\nBAR,-1\nBAZ,-2\n"
+ #
+ # \IO stream output with headers:
+ #
+ # in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2"
+ # File.open('t.csv', 'w') do |out_io|
+ # CSV.filter(in_string, out_io, headers: true) do |row|
+ # row[0].upcase!
+ # row[1] = - row[1].to_i
+ # end
+ # end # => #<CSV::Table mode:col_or_row row_count:4>
+ # File.read('t.csv') # => "Name,Value\nFOO,0\nBAR,-1\nBAZ,-2\n"
+ #
+ # When neither +in_string_or_io+ nor +out_string_or_io+ given,
+ # parses from {ARGF}[rdoc-ref:ARGF]
+ # and generates to STDOUT.
+ #
+ # Without headers:
+ #
+ # # Put Ruby code into a file.
+ # ruby = <<-EOT
+ # require 'csv'
+ # CSV.filter do |row|
+ # row[0].upcase!
+ # row[1] = - row[1].to_i
+ # end
+ # EOT
+ # File.write('t.rb', ruby)
+ # # Put some CSV into a file.
+ # File.write('t.csv', "foo,0\nbar,1\nbaz,2")
+ # # Run the Ruby code with CSV filename as argument.
+ # system(Gem.ruby, "t.rb", "t.csv")
+ #
+ # Output (to STDOUT):
+ #
+ # FOO,0
+ # BAR,-1
+ # BAZ,-2
+ #
+ # With headers:
+ #
+ # # Put Ruby code into a file.
+ # ruby = <<-EOT
+ # require 'csv'
+ # CSV.filter(headers: true) do |row|
+ # row[0].upcase!
+ # row[1] = - row[1].to_i
+ # end
+ # EOT
+ # File.write('t.rb', ruby)
+ # # Put some CSV into a file.
+ # File.write('t.csv', "Name,Value\nfoo,0\nbar,1\nbaz,2")
+ # # Run the Ruby code with CSV filename as argument.
+ # system(Gem.ruby, "t.rb", "t.csv")
+ #
+ # Output (to STDOUT):
+ #
+ # Name,Value
+ # FOO,0
+ # BAR,-1
+ # BAZ,-2
+ #
+ # Arguments:
+ #
+ # * Argument +in_string_or_io+ must be a \String or an \IO stream.
+ # * Argument +out_string_or_io+ must be a \String or an \IO stream.
+ # * Arguments <tt>**options</tt> must be keyword options.
+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
+ def filter(input=nil, output=nil, **options)
+ # parse options for input, output, or both
+ in_options, out_options = Hash.new, {row_sep: InputRecordSeparator.value}
+ options.each do |key, value|
+ case key
+ when /\Ain(?:put)?_(.+)\Z/
+ in_options[$1.to_sym] = value
+ when /\Aout(?:put)?_(.+)\Z/
+ out_options[$1.to_sym] = value
+ else
+ in_options[key] = value
+ out_options[key] = value
+ end
+ end
+
+ # build input and output wrappers
+ input = new(input || ARGF, **in_options)
+ output = new(output || $stdout, **out_options)
+
+ # process headers
+ need_manual_header_output =
+ (in_options[:headers] and
+ out_options[:headers] == true and
+ out_options[:write_headers])
+ if need_manual_header_output
+ first_row = input.shift
+ if first_row
+ if first_row.is_a?(Row)
+ headers = first_row.headers
+ yield headers
+ output << headers
+ end
+ yield first_row
+ output << first_row
+ end
+ end
+
+ # read, yield, write
+ input.each do |row|
+ yield row
+ output << row
+ end
+ end
+
+ #
+ # :call-seq:
+ # foreach(path_or_io, mode='r', **options) {|row| ... )
+ # foreach(path_or_io, mode='r', **options) -> new_enumerator
+ #
+ # Calls the block with each row read from source +path_or_io+.
+ #
+ # \Path input without headers:
+ #
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # in_path = 't.csv'
+ # File.write(in_path, string)
+ # CSV.foreach(in_path) {|row| p row }
+ #
+ # Output:
+ #
+ # ["foo", "0"]
+ # ["bar", "1"]
+ # ["baz", "2"]
+ #
+ # \Path input with headers:
+ #
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # in_path = 't.csv'
+ # File.write(in_path, string)
+ # CSV.foreach(in_path, headers: true) {|row| p row }
+ #
+ # Output:
+ #
+ # <CSV::Row "Name":"foo" "Value":"0">
+ # <CSV::Row "Name":"bar" "Value":"1">
+ # <CSV::Row "Name":"baz" "Value":"2">
+ #
+ # \IO stream input without headers:
+ #
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ # File.open('t.csv') do |in_io|
+ # CSV.foreach(in_io) {|row| p row }
+ # end
+ #
+ # Output:
+ #
+ # ["foo", "0"]
+ # ["bar", "1"]
+ # ["baz", "2"]
+ #
+ # \IO stream input with headers:
+ #
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ # File.open('t.csv') do |in_io|
+ # CSV.foreach(in_io, headers: true) {|row| p row }
+ # end
+ #
+ # Output:
+ #
+ # <CSV::Row "Name":"foo" "Value":"0">
+ # <CSV::Row "Name":"bar" "Value":"1">
+ # <CSV::Row "Name":"baz" "Value":"2">
+ #
+ # With no block given, returns an \Enumerator:
+ #
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ # CSV.foreach(path) # => #<Enumerator: CSV:foreach("t.csv", "r")>
+ #
+ # Arguments:
+ # * Argument +path_or_io+ must be a file path or an \IO stream.
+ # * Argument +mode+, if given, must be a \File mode
+ # See {Open Mode}[https://ruby-doc.org/core/IO.html#method-c-new-label-Open+Mode].
+ # * Arguments <tt>**options</tt> must be keyword options.
+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
+ # * This method optionally accepts an additional <tt>:encoding</tt> option
+ # that you can use to specify the Encoding of the data read from +path+ or +io+.
+ # You must provide this unless your data is in the encoding
+ # given by <tt>Encoding::default_external</tt>.
+ # Parsing will use this to determine how to parse the data.
+ # You may provide a second Encoding to
+ # have the data transcoded as it is read. For example,
+ # encoding: 'UTF-32BE:UTF-8'
+ # would read +UTF-32BE+ data from the file
+ # but transcode it to +UTF-8+ before parsing.
+ def foreach(path, mode="r", **options, &block)
+ return to_enum(__method__, path, mode, **options) unless block_given?
+ open(path, mode, **options) do |csv|
+ csv.each(&block)
+ end
+ end
+
+ #
+ # :call-seq:
+ # generate(csv_string, **options) {|csv| ... }
+ # generate(**options) {|csv| ... }
+ #
+ # * Argument +csv_string+, if given, must be a \String object;
+ # defaults to a new empty \String.
+ # * Arguments +options+, if given, should be generating options.
+ # See {Options for Generating}[#class-CSV-label-Options+for+Generating].
+ #
+ # ---
+ #
+ # Creates a new \CSV object via <tt>CSV.new(csv_string, **options)</tt>;
+ # calls the block with the \CSV object, which the block may modify;
+ # returns the \String generated from the \CSV object.
+ #
+ # Note that a passed \String *is* modified by this method.
+ # Pass <tt>csv_string</tt>.dup if the \String must be preserved.
+ #
+ # This method has one additional option: <tt>:encoding</tt>,
+ # which sets the base Encoding for the output if no no +str+ is specified.
+ # CSV needs this hint if you plan to output non-ASCII compatible data.
+ #
+ # ---
+ #
+ # Add lines:
+ # input_string = "foo,0\nbar,1\nbaz,2\n"
+ # output_string = CSV.generate(input_string) do |csv|
+ # csv << ['bat', 3]
+ # csv << ['bam', 4]
+ # end
+ # output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
+ # input_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
+ # output_string.equal?(input_string) # => true # Same string, modified
+ #
+ # Add lines into new string, preserving old string:
+ # input_string = "foo,0\nbar,1\nbaz,2\n"
+ # output_string = CSV.generate(input_string.dup) do |csv|
+ # csv << ['bat', 3]
+ # csv << ['bam', 4]
+ # end
+ # output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
+ # input_string # => "foo,0\nbar,1\nbaz,2\n"
+ # output_string.equal?(input_string) # => false # Different strings
+ #
+ # Create lines from nothing:
+ # output_string = CSV.generate do |csv|
+ # csv << ['foo', 0]
+ # csv << ['bar', 1]
+ # csv << ['baz', 2]
+ # end
+ # output_string # => "foo,0\nbar,1\nbaz,2\n"
+ #
+ # ---
+ #
+ # Raises an exception if +csv_string+ is not a \String object:
+ # # Raises TypeError (no implicit conversion of Integer into String)
+ # CSV.generate(0)
+ #
+ def generate(str=nil, **options)
+ encoding = options[:encoding]
+ # add a default empty String, if none was given
+ if str
+ str = StringIO.new(str)
+ str.seek(0, IO::SEEK_END)
+ str.set_encoding(encoding) if encoding
+ else
+ str = +""
+ str.force_encoding(encoding) if encoding
+ end
+ csv = new(str, **options) # wrap
+ yield csv # yield for appending
+ csv.string # return final String
+ end
+
+ # :call-seq:
+ # CSV.generate_line(ary)
+ # CSV.generate_line(ary, **options)
+ #
+ # Returns the \String created by generating \CSV from +ary+
+ # using the specified +options+.
+ #
+ # Argument +ary+ must be an \Array.
+ #
+ # Special options:
+ # * Option <tt>:row_sep</tt> defaults to <tt>"\n"> on Ruby 3.0 or later
+ # and <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>) otherwise.:
+ # $INPUT_RECORD_SEPARATOR # => "\n"
+ # * This method accepts an additional option, <tt>:encoding</tt>, which sets the base
+ # Encoding for the output. This method will try to guess your Encoding from
+ # the first non-+nil+ field in +row+, if possible, but you may need to use
+ # this parameter as a backup plan.
+ #
+ # For other +options+,
+ # see {Options for Generating}[#class-CSV-label-Options+for+Generating].
+ #
+ # ---
+ #
+ # Returns the \String generated from an \Array:
+ # CSV.generate_line(['foo', '0']) # => "foo,0\n"
+ #
+ # ---
+ #
+ # Raises an exception if +ary+ is not an \Array:
+ # # Raises NoMethodError (undefined method `find' for :foo:Symbol)
+ # CSV.generate_line(:foo)
+ #
+ def generate_line(row, **options)
+ options = {row_sep: InputRecordSeparator.value}.merge(options)
+ str = +""
+ if options[:encoding]
+ str.force_encoding(options[:encoding])
+ else
+ fallback_encoding = nil
+ output_encoding = nil
+ row.each do |field|
+ next unless field.is_a?(String)
+ fallback_encoding ||= field.encoding
+ next if field.ascii_only?
+ output_encoding = field.encoding
+ break
+ end
+ output_encoding ||= fallback_encoding
+ if output_encoding
+ str.force_encoding(output_encoding)
+ end
+ end
+ (new(str, **options) << row).string
+ end
+
+ # :call-seq:
+ # CSV.generate_lines(rows)
+ # CSV.generate_lines(rows, **options)
+ #
+ # Returns the \String created by generating \CSV from
+ # using the specified +options+.
+ #
+ # Argument +rows+ must be an \Array of row. Row is \Array of \String or \CSV::Row.
+ #
+ # Special options:
+ # * Option <tt>:row_sep</tt> defaults to <tt>"\n"</tt> on Ruby 3.0 or later
+ # and <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>) otherwise.:
+ # $INPUT_RECORD_SEPARATOR # => "\n"
+ # * This method accepts an additional option, <tt>:encoding</tt>, which sets the base
+ # Encoding for the output. This method will try to guess your Encoding from
+ # the first non-+nil+ field in +row+, if possible, but you may need to use
+ # this parameter as a backup plan.
+ #
+ # For other +options+,
+ # see {Options for Generating}[#class-CSV-label-Options+for+Generating].
+ #
+ # ---
+ #
+ # Returns the \String generated from an
+ # CSV.generate_lines([['foo', '0'], ['bar', '1'], ['baz', '2']]) # => "foo,0\nbar,1\nbaz,2\n"
+ #
+ # ---
+ #
+ # Raises an exception
+ # # Raises NoMethodError (undefined method `each' for :foo:Symbol)
+ # CSV.generate_lines(:foo)
+ #
+ def generate_lines(rows, **options)
+ self.generate(**options) do |csv|
+ rows.each do |row|
+ csv << row
+ end
+ end
+ end
+
+ #
+ # :call-seq:
+ # open(file_path, mode = "rb", **options ) -> new_csv
+ # open(io, mode = "rb", **options ) -> new_csv
+ # open(file_path, mode = "rb", **options ) { |csv| ... } -> object
+ # open(io, mode = "rb", **options ) { |csv| ... } -> object
+ #
+ # possible options elements:
+ # keyword form:
+ # :invalid => nil # raise error on invalid byte sequence (default)
+ # :invalid => :replace # replace invalid byte sequence
+ # :undef => :replace # replace undefined conversion
+ # :replace => string # replacement string ("?" or "\uFFFD" if not specified)
+ #
+ # * Argument +path+, if given, must be the path to a file.
+ # :include: ../doc/csv/arguments/io.rdoc
+ # * Argument +mode+, if given, must be a \File mode
+ # See {Open Mode}[IO.html#method-c-new-label-Open+Mode].
+ # * Arguments <tt>**options</tt> must be keyword options.
+ # See {Options for Generating}[#class-CSV-label-Options+for+Generating].
+ # * This method optionally accepts an additional <tt>:encoding</tt> option
+ # that you can use to specify the Encoding of the data read from +path+ or +io+.
+ # You must provide this unless your data is in the encoding
+ # given by <tt>Encoding::default_external</tt>.
+ # Parsing will use this to determine how to parse the data.
+ # You may provide a second Encoding to
+ # have the data transcoded as it is read. For example,
+ # encoding: 'UTF-32BE:UTF-8'
+ # would read +UTF-32BE+ data from the file
+ # but transcode it to +UTF-8+ before parsing.
+ #
+ # ---
+ #
+ # These examples assume prior execution of:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ #
+ # ---
+ #
+ # With no block given, returns a new \CSV object.
+ #
+ # Create a \CSV object using a file path:
+ # csv = CSV.open(path)
+ # csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
+ #
+ # Create a \CSV object using an open \File:
+ # csv = CSV.open(File.open(path))
+ # csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
+ #
+ # ---
+ #
+ # With a block given, calls the block with the created \CSV object;
+ # returns the block's return value:
+ #
+ # Using a file path:
+ # csv = CSV.open(path) {|csv| p csv}
+ # csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
+ # Output:
+ # #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
+ #
+ # Using an open \File:
+ # csv = CSV.open(File.open(path)) {|csv| p csv}
+ # csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
+ # Output:
+ # #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
+ #
+ # ---
+ #
+ # Raises an exception if the argument is not a \String object or \IO object:
+ # # Raises TypeError (no implicit conversion of Symbol into String)
+ # CSV.open(:foo)
+ def open(filename, mode="r", **options)
+ # wrap a File opened with the remaining +args+ with no newline
+ # decorator
+ file_opts = options.dup
+ unless file_opts.key?(:newline)
+ file_opts[:universal_newline] ||= false
+ end
+ options.delete(:invalid)
+ options.delete(:undef)
+ options.delete(:replace)
+ options.delete_if {|k, _| /newline\z/.match?(k)}
+
+ begin
+ f = File.open(filename, mode, **file_opts)
+ rescue ArgumentError => e
+ raise unless /needs binmode/.match?(e.message) and mode == "r"
+ mode = "rb"
+ file_opts = {encoding: Encoding.default_external}.merge(file_opts)
+ retry
+ end
+ begin
+ csv = new(f, **options)
+ rescue Exception
+ f.close
+ raise
+ end
+
+ # handle blocks like Ruby's open(), not like the CSV library
+ if block_given?
+ begin
+ yield csv
+ ensure
+ csv.close
+ end
+ else
+ csv
+ end
+ end
+
+ #
+ # :call-seq:
+ # parse(string) -> array_of_arrays
+ # parse(io) -> array_of_arrays
+ # parse(string, headers: ..., **options) -> csv_table
+ # parse(io, headers: ..., **options) -> csv_table
+ # parse(string, **options) {|row| ... }
+ # parse(io, **options) {|row| ... }
+ #
+ # Parses +string+ or +io+ using the specified +options+.
+ #
+ # - Argument +string+ should be a \String object;
+ # it will be put into a new StringIO object positioned at the beginning.
+ # :include: ../doc/csv/arguments/io.rdoc
+ # - Argument +options+: see {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
+ #
+ # ====== Without Option +headers+
+ #
+ # Without {option +headers+}[#class-CSV-label-Option+headers] case.
+ #
+ # These examples assume prior execution of:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ #
+ # ---
+ #
+ # With no block given, returns an \Array of Arrays formed from the source.
+ #
+ # Parse a \String:
+ # a_of_a = CSV.parse(string)
+ # a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+ #
+ # Parse an open \File:
+ # a_of_a = File.open(path) do |file|
+ # CSV.parse(file)
+ # end
+ # a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+ #
+ # ---
+ #
+ # With a block given, calls the block with each parsed row:
+ #
+ # Parse a \String:
+ # CSV.parse(string) {|row| p row }
+ #
+ # Output:
+ # ["foo", "0"]
+ # ["bar", "1"]
+ # ["baz", "2"]
+ #
+ # Parse an open \File:
+ # File.open(path) do |file|
+ # CSV.parse(file) {|row| p row }
+ # end
+ #
+ # Output:
+ # ["foo", "0"]
+ # ["bar", "1"]
+ # ["baz", "2"]
+ #
+ # ====== With Option +headers+
+ #
+ # With {option +headers+}[#class-CSV-label-Option+headers] case.
+ #
+ # These examples assume prior execution of:
+ # string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ #
+ # ---
+ #
+ # With no block given, returns a CSV::Table object formed from the source.
+ #
+ # Parse a \String:
+ # csv_table = CSV.parse(string, headers: ['Name', 'Count'])
+ # csv_table # => #<CSV::Table mode:col_or_row row_count:5>
+ #
+ # Parse an open \File:
+ # csv_table = File.open(path) do |file|
+ # CSV.parse(file, headers: ['Name', 'Count'])
+ # end
+ # csv_table # => #<CSV::Table mode:col_or_row row_count:4>
+ #
+ # ---
+ #
+ # With a block given, calls the block with each parsed row,
+ # which has been formed into a CSV::Row object:
+ #
+ # Parse a \String:
+ # CSV.parse(string, headers: ['Name', 'Count']) {|row| p row }
+ #
+ # Output:
+ # # <CSV::Row "Name":"foo" "Count":"0">
+ # # <CSV::Row "Name":"bar" "Count":"1">
+ # # <CSV::Row "Name":"baz" "Count":"2">
+ #
+ # Parse an open \File:
+ # File.open(path) do |file|
+ # CSV.parse(file, headers: ['Name', 'Count']) {|row| p row }
+ # end
+ #
+ # Output:
+ # # <CSV::Row "Name":"foo" "Count":"0">
+ # # <CSV::Row "Name":"bar" "Count":"1">
+ # # <CSV::Row "Name":"baz" "Count":"2">
+ #
+ # ---
+ #
+ # Raises an exception if the argument is not a \String object or \IO object:
+ # # Raises NoMethodError (undefined method `close' for :foo:Symbol)
+ # CSV.parse(:foo)
+ def parse(str, **options, &block)
+ csv = new(str, **options)
+
+ return csv.each(&block) if block_given?
+
+ # slurp contents, if no block is given
+ begin
+ csv.read
+ ensure
+ csv.close
+ end
+ end
+
+ # :call-seq:
+ # CSV.parse_line(string) -> new_array or nil
+ # CSV.parse_line(io) -> new_array or nil
+ # CSV.parse_line(string, **options) -> new_array or nil
+ # CSV.parse_line(io, **options) -> new_array or nil
+ # CSV.parse_line(string, headers: true, **options) -> csv_row or nil
+ # CSV.parse_line(io, headers: true, **options) -> csv_row or nil
+ #
+ # Returns the data created by parsing the first line of +string+ or +io+
+ # using the specified +options+.
+ #
+ # - Argument +string+ should be a \String object;
+ # it will be put into a new StringIO object positioned at the beginning.
+ # :include: ../doc/csv/arguments/io.rdoc
+ # - Argument +options+: see {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
+ #
+ # ====== Without Option +headers+
+ #
+ # Without option +headers+, returns the first row as a new \Array.
+ #
+ # These examples assume prior execution of:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ #
+ # Parse the first line from a \String object:
+ # CSV.parse_line(string) # => ["foo", "0"]
+ #
+ # Parse the first line from a File object:
+ # File.open(path) do |file|
+ # CSV.parse_line(file) # => ["foo", "0"]
+ # end # => ["foo", "0"]
+ #
+ # Returns +nil+ if the argument is an empty \String:
+ # CSV.parse_line('') # => nil
+ #
+ # ====== With Option +headers+
+ #
+ # With {option +headers+}[#class-CSV-label-Option+headers],
+ # returns the first row as a CSV::Row object.
+ #
+ # These examples assume prior execution of:
+ # string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ #
+ # Parse the first line from a \String object:
+ # CSV.parse_line(string, headers: true) # => #<CSV::Row "Name":"foo" "Count":"0">
+ #
+ # Parse the first line from a File object:
+ # File.open(path) do |file|
+ # CSV.parse_line(file, headers: true)
+ # end # => #<CSV::Row "Name":"foo" "Count":"0">
+ #
+ # ---
+ #
+ # Raises an exception if the argument is +nil+:
+ # # Raises ArgumentError (Cannot parse nil as CSV):
+ # CSV.parse_line(nil)
+ #
+ def parse_line(line, **options)
+ new(line, **options).each.first
+ end
+
+ #
+ # :call-seq:
+ # read(source, **options) -> array_of_arrays
+ # read(source, headers: true, **options) -> csv_table
+ #
+ # Opens the given +source+ with the given +options+ (see CSV.open),
+ # reads the source (see CSV#read), and returns the result,
+ # which will be either an \Array of Arrays or a CSV::Table.
+ #
+ # Without headers:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ # CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+ #
+ # With headers:
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ # CSV.read(path, headers: true) # => #<CSV::Table mode:col_or_row row_count:4>
+ def read(path, **options)
+ open(path, **options) { |csv| csv.read }
+ end
+
+ # :call-seq:
+ # CSV.readlines(source, **options)
+ #
+ # Alias for CSV.read.
+ def readlines(path, **options)
+ read(path, **options)
+ end
+
+ # :call-seq:
+ # CSV.table(source, **options)
+ #
+ # Calls CSV.read with +source+, +options+, and certain default options:
+ # - +headers+: +true+
+ # - +converters+: +:numeric+
+ # - +header_converters+: +:symbol+
+ #
+ # Returns a CSV::Table object.
+ #
+ # Example:
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ # CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:4>
+ def table(path, **options)
+ default_options = {
+ headers: true,
+ converters: :numeric,
+ header_converters: :symbol,
+ }
+ options = default_options.merge(options)
+ read(path, **options)
+ end
+ end
+
+ # :call-seq:
+ # CSV.new(string)
+ # CSV.new(io)
+ # CSV.new(string, **options)
+ # CSV.new(io, **options)
+ #
+ # Returns the new \CSV object created using +string+ or +io+
+ # and the specified +options+.
+ #
+ # - Argument +string+ should be a \String object;
+ # it will be put into a new StringIO object positioned at the beginning.
+ # :include: ../doc/csv/arguments/io.rdoc
+ # - Argument +options+: See:
+ # * {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
+ # * {Options for Generating}[#class-CSV-label-Options+for+Generating]
+ # For performance reasons, the options cannot be overridden
+ # in a \CSV object, so those specified here will endure.
+ #
+ # In addition to the \CSV instance methods, several \IO methods are delegated.
+ # See {Delegated Methods}[#class-CSV-label-Delegated+Methods].
+ #
+ # ---
+ #
+ # Create a \CSV object from a \String object:
+ # csv = CSV.new('foo,0')
+ # csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
+ #
+ # Create a \CSV object from a \File object:
+ # File.write('t.csv', 'foo,0')
+ # csv = CSV.new(File.open('t.csv'))
+ # csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
+ #
+ # ---
+ #
+ # Raises an exception if the argument is +nil+:
+ # # Raises ArgumentError (Cannot parse nil as CSV):
+ # CSV.new(nil)
+ #
+ def initialize(data,
+ col_sep: ",",
+ row_sep: :auto,
+ quote_char: '"',
+ field_size_limit: nil,
+ max_field_size: nil,
+ converters: nil,
+ unconverted_fields: nil,
+ headers: false,
+ return_headers: false,
+ write_headers: nil,
+ header_converters: nil,
+ skip_blanks: false,
+ force_quotes: false,
+ skip_lines: nil,
+ liberal_parsing: false,
+ internal_encoding: nil,
+ external_encoding: nil,
+ encoding: nil,
+ nil_value: nil,
+ empty_value: "",
+ strip: false,
+ quote_empty: true,
+ write_converters: nil,
+ write_nil_value: nil,
+ write_empty_value: "")
+ raise ArgumentError.new("Cannot parse nil as CSV") if data.nil?
+
+ if data.is_a?(String)
+ if encoding
+ if encoding.is_a?(String)
+ data_external_encoding, data_internal_encoding = encoding.split(":", 2)
+ if data_internal_encoding
+ data = data.encode(data_internal_encoding, data_external_encoding)
+ else
+ data = data.dup.force_encoding(data_external_encoding)
+ end
+ else
+ data = data.dup.force_encoding(encoding)
+ end
+ end
+ @io = StringIO.new(data)
+ else
+ @io = data
+ end
+ @encoding = determine_encoding(encoding, internal_encoding)
+
+ @base_fields_converter_options = {
+ nil_value: nil_value,
+ empty_value: empty_value,
+ }
+ @write_fields_converter_options = {
+ nil_value: write_nil_value,
+ empty_value: write_empty_value,
+ }
+ @initial_converters = converters
+ @initial_header_converters = header_converters
+ @initial_write_converters = write_converters
+
+ if max_field_size.nil? and field_size_limit
+ max_field_size = field_size_limit - 1
+ end
+ @parser_options = {
+ column_separator: col_sep,
+ row_separator: row_sep,
+ quote_character: quote_char,
+ max_field_size: max_field_size,
+ unconverted_fields: unconverted_fields,
+ headers: headers,
+ return_headers: return_headers,
+ skip_blanks: skip_blanks,
+ skip_lines: skip_lines,
+ liberal_parsing: liberal_parsing,
+ encoding: @encoding,
+ nil_value: nil_value,
+ empty_value: empty_value,
+ strip: strip,
+ }
+ @parser = nil
+ @parser_enumerator = nil
+ @eof_error = nil
+
+ @writer_options = {
+ encoding: @encoding,
+ force_encoding: (not encoding.nil?),
+ force_quotes: force_quotes,
+ headers: headers,
+ write_headers: write_headers,
+ column_separator: col_sep,
+ row_separator: row_sep,
+ quote_character: quote_char,
+ quote_empty: quote_empty,
+ }
+
+ @writer = nil
+ writer if @writer_options[:write_headers]
+ end
+
+ # :call-seq:
+ # csv.col_sep -> string
+ #
+ # Returns the encoded column separator; used for parsing and writing;
+ # see {Option +col_sep+}[#class-CSV-label-Option+col_sep]:
+ # CSV.new('').col_sep # => ","
+ def col_sep
+ parser.column_separator
+ end
+
+ # :call-seq:
+ # csv.row_sep -> string
+ #
+ # Returns the encoded row separator; used for parsing and writing;
+ # see {Option +row_sep+}[#class-CSV-label-Option+row_sep]:
+ # CSV.new('').row_sep # => "\n"
+ def row_sep
+ parser.row_separator
+ end
+
+ # :call-seq:
+ # csv.quote_char -> character
+ #
+ # Returns the encoded quote character; used for parsing and writing;
+ # see {Option +quote_char+}[#class-CSV-label-Option+quote_char]:
+ # CSV.new('').quote_char # => "\""
+ def quote_char
+ parser.quote_character
+ end
+
+ # :call-seq:
+ # csv.field_size_limit -> integer or nil
+ #
+ # Returns the limit for field size; used for parsing;
+ # see {Option +field_size_limit+}[#class-CSV-label-Option+field_size_limit]:
+ # CSV.new('').field_size_limit # => nil
+ #
+ # Deprecated since 3.2.3. Use +max_field_size+ instead.
+ def field_size_limit
+ parser.field_size_limit
+ end
+
+ # :call-seq:
+ # csv.max_field_size -> integer or nil
+ #
+ # Returns the limit for field size; used for parsing;
+ # see {Option +max_field_size+}[#class-CSV-label-Option+max_field_size]:
+ # CSV.new('').max_field_size # => nil
+ #
+ # Since 3.2.3.
+ def max_field_size
+ parser.max_field_size
+ end
+
+ # :call-seq:
+ # csv.skip_lines -> regexp or nil
+ #
+ # Returns the \Regexp used to identify comment lines; used for parsing;
+ # see {Option +skip_lines+}[#class-CSV-label-Option+skip_lines]:
+ # CSV.new('').skip_lines # => nil
+ def skip_lines
+ parser.skip_lines
+ end
+
+ # :call-seq:
+ # csv.converters -> array
+ #
+ # Returns an \Array containing field converters;
+ # see {Field Converters}[#class-CSV-label-Field+Converters]:
+ # csv = CSV.new('')
+ # csv.converters # => []
+ # csv.convert(:integer)
+ # csv.converters # => [:integer]
+ # csv.convert(proc {|x| x.to_s })
+ # csv.converters
+ #
+ # Notes that you need to call
+ # +Ractor.make_shareable(CSV::Converters)+ on the main Ractor to use
+ # this method.
+ def converters
+ parser_fields_converter.map do |converter|
+ name = Converters.rassoc(converter)
+ name ? name.first : converter
+ end
+ end
+
+ # :call-seq:
+ # csv.unconverted_fields? -> object
+ #
+ # Returns the value that determines whether unconverted fields are to be
+ # available; used for parsing;
+ # see {Option +unconverted_fields+}[#class-CSV-label-Option+unconverted_fields]:
+ # CSV.new('').unconverted_fields? # => nil
+ def unconverted_fields?
+ parser.unconverted_fields?
+ end
+
+ # :call-seq:
+ # csv.headers -> object
+ #
+ # Returns the value that determines whether headers are used; used for parsing;
+ # see {Option +headers+}[#class-CSV-label-Option+headers]:
+ # CSV.new('').headers # => nil
+ def headers
+ if @writer
+ @writer.headers
+ else
+ parsed_headers = parser.headers
+ return parsed_headers if parsed_headers
+ raw_headers = @parser_options[:headers]
+ raw_headers = nil if raw_headers == false
+ raw_headers
+ end
+ end
+
+ # :call-seq:
+ # csv.return_headers? -> true or false
+ #
+ # Returns the value that determines whether headers are to be returned; used for parsing;
+ # see {Option +return_headers+}[#class-CSV-label-Option+return_headers]:
+ # CSV.new('').return_headers? # => false
+ def return_headers?
+ parser.return_headers?
+ end
+
+ # :call-seq:
+ # csv.write_headers? -> true or false
+ #
+ # Returns the value that determines whether headers are to be written; used for generating;
+ # see {Option +write_headers+}[#class-CSV-label-Option+write_headers]:
+ # CSV.new('').write_headers? # => nil
+ def write_headers?
+ @writer_options[:write_headers]
+ end
+
+ # :call-seq:
+ # csv.header_converters -> array
+ #
+ # Returns an \Array containing header converters; used for parsing;
+ # see {Header Converters}[#class-CSV-label-Header+Converters]:
+ # CSV.new('').header_converters # => []
+ #
+ # Notes that you need to call
+ # +Ractor.make_shareable(CSV::HeaderConverters)+ on the main Ractor
+ # to use this method.
+ def header_converters
+ header_fields_converter.map do |converter|
+ name = HeaderConverters.rassoc(converter)
+ name ? name.first : converter
+ end
+ end
+
+ # :call-seq:
+ # csv.skip_blanks? -> true or false
+ #
+ # Returns the value that determines whether blank lines are to be ignored; used for parsing;
+ # see {Option +skip_blanks+}[#class-CSV-label-Option+skip_blanks]:
+ # CSV.new('').skip_blanks? # => false
+ def skip_blanks?
+ parser.skip_blanks?
+ end
+
+ # :call-seq:
+ # csv.force_quotes? -> true or false
+ #
+ # Returns the value that determines whether all output fields are to be quoted;
+ # used for generating;
+ # see {Option +force_quotes+}[#class-CSV-label-Option+force_quotes]:
+ # CSV.new('').force_quotes? # => false
+ def force_quotes?
+ @writer_options[:force_quotes]
+ end
+
+ # :call-seq:
+ # csv.liberal_parsing? -> true or false
+ #
+ # Returns the value that determines whether illegal input is to be handled; used for parsing;
+ # see {Option +liberal_parsing+}[#class-CSV-label-Option+liberal_parsing]:
+ # CSV.new('').liberal_parsing? # => false
+ def liberal_parsing?
+ parser.liberal_parsing?
+ end
+
+ # :call-seq:
+ # csv.encoding -> encoding
+ #
+ # Returns the encoding used for parsing and generating;
+ # see {Character Encodings (M17n or Multilingualization)}[#class-CSV-label-Character+Encodings+-28M17n+or+Multilingualization-29]:
+ # CSV.new('').encoding # => #<Encoding:UTF-8>
+ attr_reader :encoding
+
+ # :call-seq:
+ # csv.line_no -> integer
+ #
+ # Returns the count of the rows parsed or generated.
+ #
+ # Parsing:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ # CSV.open(path) do |csv|
+ # csv.each do |row|
+ # p [csv.lineno, row]
+ # end
+ # end
+ # Output:
+ # [1, ["foo", "0"]]
+ # [2, ["bar", "1"]]
+ # [3, ["baz", "2"]]
+ #
+ # Generating:
+ # CSV.generate do |csv|
+ # p csv.lineno; csv << ['foo', 0]
+ # p csv.lineno; csv << ['bar', 1]
+ # p csv.lineno; csv << ['baz', 2]
+ # end
+ # Output:
+ # 0
+ # 1
+ # 2
+ def lineno
+ if @writer
+ @writer.lineno
+ else
+ parser.lineno
+ end
+ end
+
+ # :call-seq:
+ # csv.line -> array
+ #
+ # Returns the line most recently read:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ # CSV.open(path) do |csv|
+ # csv.each do |row|
+ # p [csv.lineno, csv.line]
+ # end
+ # end
+ # Output:
+ # [1, "foo,0\n"]
+ # [2, "bar,1\n"]
+ # [3, "baz,2\n"]
+ def line
+ parser.line
+ end
+
+ ### IO and StringIO Delegation ###
+
+ extend Forwardable
+ def_delegators :@io, :binmode, :close, :close_read, :close_write,
+ :closed?, :external_encoding, :fcntl,
+ :fileno, :flush, :fsync, :internal_encoding,
+ :isatty, :pid, :pos, :pos=, :reopen,
+ :seek, :string, :sync, :sync=, :tell,
+ :truncate, :tty?
+
+ def binmode?
+ if @io.respond_to?(:binmode?)
+ @io.binmode?
+ else
+ false
+ end
+ end
+
+ def flock(*args)
+ raise NotImplementedError unless @io.respond_to?(:flock)
+ @io.flock(*args)
+ end
+
+ def ioctl(*args)
+ raise NotImplementedError unless @io.respond_to?(:ioctl)
+ @io.ioctl(*args)
+ end
+
+ def path
+ @io.path if @io.respond_to?(:path)
+ end
+
+ def stat(*args)
+ raise NotImplementedError unless @io.respond_to?(:stat)
+ @io.stat(*args)
+ end
+
+ def to_i
+ raise NotImplementedError unless @io.respond_to?(:to_i)
+ @io.to_i
+ end
+
+ def to_io
+ @io.respond_to?(:to_io) ? @io.to_io : @io
+ end
+
+ def eof?
+ return false if @eof_error
+ begin
+ parser_enumerator.peek
+ false
+ rescue MalformedCSVError => error
+ @eof_error = error
+ false
+ rescue StopIteration
+ true
+ end
+ end
+ alias_method :eof, :eof?
+
+ # Rewinds the underlying IO object and resets CSV's lineno() counter.
+ def rewind
+ @parser = nil
+ @parser_enumerator = nil
+ @eof_error = nil
+ @writer.rewind if @writer
+ @io.rewind
+ end
+
+ ### End Delegation ###
+
+ # :call-seq:
+ # csv << row -> self
+ #
+ # Appends a row to +self+.
+ #
+ # - Argument +row+ must be an \Array object or a CSV::Row object.
+ # - The output stream must be open for writing.
+ #
+ # ---
+ #
+ # Append Arrays:
+ # CSV.generate do |csv|
+ # csv << ['foo', 0]
+ # csv << ['bar', 1]
+ # csv << ['baz', 2]
+ # end # => "foo,0\nbar,1\nbaz,2\n"
+ #
+ # Append CSV::Rows:
+ # headers = []
+ # CSV.generate do |csv|
+ # csv << CSV::Row.new(headers, ['foo', 0])
+ # csv << CSV::Row.new(headers, ['bar', 1])
+ # csv << CSV::Row.new(headers, ['baz', 2])
+ # end # => "foo,0\nbar,1\nbaz,2\n"
+ #
+ # Headers in CSV::Row objects are not appended:
+ # headers = ['Name', 'Count']
+ # CSV.generate do |csv|
+ # csv << CSV::Row.new(headers, ['foo', 0])
+ # csv << CSV::Row.new(headers, ['bar', 1])
+ # csv << CSV::Row.new(headers, ['baz', 2])
+ # end # => "foo,0\nbar,1\nbaz,2\n"
+ #
+ # ---
+ #
+ # Raises an exception if +row+ is not an \Array or \CSV::Row:
+ # CSV.generate do |csv|
+ # # Raises NoMethodError (undefined method `collect' for :foo:Symbol)
+ # csv << :foo
+ # end
+ #
+ # Raises an exception if the output stream is not opened for writing:
+ # path = 't.csv'
+ # File.write(path, '')
+ # File.open(path) do |file|
+ # CSV.open(file) do |csv|
+ # # Raises IOError (not opened for writing)
+ # csv << ['foo', 0]
+ # end
+ # end
+ def <<(row)
+ writer << row
+ self
+ end
+ alias_method :add_row, :<<
+ alias_method :puts, :<<
+
+ # :call-seq:
+ # convert(converter_name) -> array_of_procs
+ # convert {|field, field_info| ... } -> array_of_procs
+ #
+ # - With no block, installs a field converter (a \Proc).
+ # - With a block, defines and installs a custom field converter.
+ # - Returns the \Array of installed field converters.
+ #
+ # - Argument +converter_name+, if given, should be the name
+ # of an existing field converter.
+ #
+ # See {Field Converters}[#class-CSV-label-Field+Converters].
+ # ---
+ #
+ # With no block, installs a field converter:
+ # csv = CSV.new('')
+ # csv.convert(:integer)
+ # csv.convert(:float)
+ # csv.convert(:date)
+ # csv.converters # => [:integer, :float, :date]
+ #
+ # ---
+ #
+ # The block, if given, is called for each field:
+ # - Argument +field+ is the field value.
+ # - Argument +field_info+ is a CSV::FieldInfo object
+ # containing details about the field.
+ #
+ # The examples here assume the prior execution of:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ #
+ # Example giving a block:
+ # csv = CSV.open(path)
+ # csv.convert {|field, field_info| p [field, field_info]; field.upcase }
+ # csv.read # => [["FOO", "0"], ["BAR", "1"], ["BAZ", "2"]]
+ #
+ # Output:
+ # ["foo", #<struct CSV::FieldInfo index=0, line=1, header=nil>]
+ # ["0", #<struct CSV::FieldInfo index=1, line=1, header=nil>]
+ # ["bar", #<struct CSV::FieldInfo index=0, line=2, header=nil>]
+ # ["1", #<struct CSV::FieldInfo index=1, line=2, header=nil>]
+ # ["baz", #<struct CSV::FieldInfo index=0, line=3, header=nil>]
+ # ["2", #<struct CSV::FieldInfo index=1, line=3, header=nil>]
+ #
+ # The block need not return a \String object:
+ # csv = CSV.open(path)
+ # csv.convert {|field, field_info| field.to_sym }
+ # csv.read # => [[:foo, :"0"], [:bar, :"1"], [:baz, :"2"]]
+ #
+ # If +converter_name+ is given, the block is not called:
+ # csv = CSV.open(path)
+ # csv.convert(:integer) {|field, field_info| fail 'Cannot happen' }
+ # csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
+ #
+ # ---
+ #
+ # Raises a parse-time exception if +converter_name+ is not the name of a built-in
+ # field converter:
+ # csv = CSV.open(path)
+ # csv.convert(:nosuch) => [nil]
+ # # Raises NoMethodError (undefined method `arity' for nil:NilClass)
+ # csv.read
+ def convert(name = nil, &converter)
+ parser_fields_converter.add_converter(name, &converter)
+ end
+
+ # :call-seq:
+ # header_convert(converter_name) -> array_of_procs
+ # header_convert {|header, field_info| ... } -> array_of_procs
+ #
+ # - With no block, installs a header converter (a \Proc).
+ # - With a block, defines and installs a custom header converter.
+ # - Returns the \Array of installed header converters.
+ #
+ # - Argument +converter_name+, if given, should be the name
+ # of an existing header converter.
+ #
+ # See {Header Converters}[#class-CSV-label-Header+Converters].
+ # ---
+ #
+ # With no block, installs a header converter:
+ # csv = CSV.new('')
+ # csv.header_convert(:symbol)
+ # csv.header_convert(:downcase)
+ # csv.header_converters # => [:symbol, :downcase]
+ #
+ # ---
+ #
+ # The block, if given, is called for each header:
+ # - Argument +header+ is the header value.
+ # - Argument +field_info+ is a CSV::FieldInfo object
+ # containing details about the header.
+ #
+ # The examples here assume the prior execution of:
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ #
+ # Example giving a block:
+ # csv = CSV.open(path, headers: true)
+ # csv.header_convert {|header, field_info| p [header, field_info]; header.upcase }
+ # table = csv.read
+ # table # => #<CSV::Table mode:col_or_row row_count:4>
+ # table.headers # => ["NAME", "VALUE"]
+ #
+ # Output:
+ # ["Name", #<struct CSV::FieldInfo index=0, line=1, header=nil>]
+ # ["Value", #<struct CSV::FieldInfo index=1, line=1, header=nil>]
+
+ # The block need not return a \String object:
+ # csv = CSV.open(path, headers: true)
+ # csv.header_convert {|header, field_info| header.to_sym }
+ # table = csv.read
+ # table.headers # => [:Name, :Value]
+ #
+ # If +converter_name+ is given, the block is not called:
+ # csv = CSV.open(path, headers: true)
+ # csv.header_convert(:downcase) {|header, field_info| fail 'Cannot happen' }
+ # table = csv.read
+ # table.headers # => ["name", "value"]
+ # ---
+ #
+ # Raises a parse-time exception if +converter_name+ is not the name of a built-in
+ # field converter:
+ # csv = CSV.open(path, headers: true)
+ # csv.header_convert(:nosuch)
+ # # Raises NoMethodError (undefined method `arity' for nil:NilClass)
+ # csv.read
+ def header_convert(name = nil, &converter)
+ header_fields_converter.add_converter(name, &converter)
+ end
+
+ include Enumerable
+
+ # :call-seq:
+ # csv.each -> enumerator
+ # csv.each {|row| ...}
+ #
+ # Calls the block with each successive row.
+ # The data source must be opened for reading.
+ #
+ # Without headers:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # csv = CSV.new(string)
+ # csv.each do |row|
+ # p row
+ # end
+ # Output:
+ # ["foo", "0"]
+ # ["bar", "1"]
+ # ["baz", "2"]
+ #
+ # With headers:
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # csv = CSV.new(string, headers: true)
+ # csv.each do |row|
+ # p row
+ # end
+ # Output:
+ # <CSV::Row "Name":"foo" "Value":"0">
+ # <CSV::Row "Name":"bar" "Value":"1">
+ # <CSV::Row "Name":"baz" "Value":"2">
+ #
+ # ---
+ #
+ # Raises an exception if the source is not opened for reading:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # csv = CSV.new(string)
+ # csv.close
+ # # Raises IOError (not opened for reading)
+ # csv.each do |row|
+ # p row
+ # end
+ def each(&block)
+ return to_enum(__method__) unless block_given?
+ begin
+ while true
+ yield(parser_enumerator.next)
+ end
+ rescue StopIteration
+ end
+ end
+
+ # :call-seq:
+ # csv.read -> array or csv_table
+ #
+ # Forms the remaining rows from +self+ into:
+ # - A CSV::Table object, if headers are in use.
+ # - An \Array of Arrays, otherwise.
+ #
+ # The data source must be opened for reading.
+ #
+ # Without headers:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ # csv = CSV.open(path)
+ # csv.read # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+ #
+ # With headers:
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # path = 't.csv'
+ # File.write(path, string)
+ # csv = CSV.open(path, headers: true)
+ # csv.read # => #<CSV::Table mode:col_or_row row_count:4>
+ #
+ # ---
+ #
+ # Raises an exception if the source is not opened for reading:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # csv = CSV.new(string)
+ # csv.close
+ # # Raises IOError (not opened for reading)
+ # csv.read
+ def read
+ rows = to_a
+ if parser.use_headers?
+ Table.new(rows, headers: parser.headers)
+ else
+ rows
+ end
+ end
+ alias_method :readlines, :read
+
+ # :call-seq:
+ # csv.header_row? -> true or false
+ #
+ # Returns +true+ if the next row to be read is a header row\;
+ # +false+ otherwise.
+ #
+ # Without headers:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # csv = CSV.new(string)
+ # csv.header_row? # => false
+ #
+ # With headers:
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # csv = CSV.new(string, headers: true)
+ # csv.header_row? # => true
+ # csv.shift # => #<CSV::Row "Name":"foo" "Value":"0">
+ # csv.header_row? # => false
+ #
+ # ---
+ #
+ # Raises an exception if the source is not opened for reading:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # csv = CSV.new(string)
+ # csv.close
+ # # Raises IOError (not opened for reading)
+ # csv.header_row?
+ def header_row?
+ parser.header_row?
+ end
+
+ # :call-seq:
+ # csv.shift -> array, csv_row, or nil
+ #
+ # Returns the next row of data as:
+ # - An \Array if no headers are used.
+ # - A CSV::Row object if headers are used.
+ #
+ # The data source must be opened for reading.
+ #
+ # Without headers:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # csv = CSV.new(string)
+ # csv.shift # => ["foo", "0"]
+ # csv.shift # => ["bar", "1"]
+ # csv.shift # => ["baz", "2"]
+ # csv.shift # => nil
+ #
+ # With headers:
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # csv = CSV.new(string, headers: true)
+ # csv.shift # => #<CSV::Row "Name":"foo" "Value":"0">
+ # csv.shift # => #<CSV::Row "Name":"bar" "Value":"1">
+ # csv.shift # => #<CSV::Row "Name":"baz" "Value":"2">
+ # csv.shift # => nil
+ #
+ # ---
+ #
+ # Raises an exception if the source is not opened for reading:
+ # string = "foo,0\nbar,1\nbaz,2\n"
+ # csv = CSV.new(string)
+ # csv.close
+ # # Raises IOError (not opened for reading)
+ # csv.shift
+ def shift
+ if @eof_error
+ eof_error, @eof_error = @eof_error, nil
+ raise eof_error
+ end
+ begin
+ parser_enumerator.next
+ rescue StopIteration
+ nil
+ end
+ end
+ alias_method :gets, :shift
+ alias_method :readline, :shift
+
+ # :call-seq:
+ # csv.inspect -> string
+ #
+ # Returns a \String showing certain properties of +self+:
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # csv = CSV.new(string, headers: true)
+ # s = csv.inspect
+ # s # => "#<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:\",\" row_sep:\"\\n\" quote_char:\"\\\"\" headers:true>"
+ def inspect
+ str = ["#<", self.class.to_s, " io_type:"]
+ # show type of wrapped IO
+ if @io == $stdout then str << "$stdout"
+ elsif @io == $stdin then str << "$stdin"
+ elsif @io == $stderr then str << "$stderr"
+ else str << @io.class.to_s
+ end
+ # show IO.path(), if available
+ if @io.respond_to?(:path) and (p = @io.path)
+ str << " io_path:" << p.inspect
+ end
+ # show encoding
+ str << " encoding:" << @encoding.name
+ # show other attributes
+ ["lineno", "col_sep", "row_sep", "quote_char"].each do |attr_name|
+ if a = __send__(attr_name)
+ str << " " << attr_name << ":" << a.inspect
+ end
+ end
+ ["skip_blanks", "liberal_parsing"].each do |attr_name|
+ if a = __send__("#{attr_name}?")
+ str << " " << attr_name << ":" << a.inspect
+ end
+ end
+ _headers = headers
+ str << " headers:" << _headers.inspect if _headers
+ str << ">"
+ begin
+ str.join('')
+ rescue # any encoding error
+ str.map do |s|
+ e = Encoding::Converter.asciicompat_encoding(s.encoding)
+ e ? s.encode(e) : s.force_encoding("ASCII-8BIT")
+ end.join('')
+ end
+ end
+
+ private
+
+ def determine_encoding(encoding, internal_encoding)
+ # honor the IO encoding if we can, otherwise default to ASCII-8BIT
+ io_encoding = raw_encoding
+ return io_encoding if io_encoding
+
+ return Encoding.find(internal_encoding) if internal_encoding
+
+ if encoding
+ encoding, = encoding.split(":", 2) if encoding.is_a?(String)
+ return Encoding.find(encoding)
+ end
+
+ Encoding.default_internal || Encoding.default_external
+ end
+
+ def normalize_converters(converters)
+ converters ||= []
+ unless converters.is_a?(Array)
+ converters = [converters]
+ end
+ converters.collect do |converter|
+ case converter
+ when Proc # custom code block
+ [nil, converter]
+ else # by name
+ [converter, nil]
+ end
+ end
+ end
+
+ #
+ # Processes +fields+ with <tt>@converters</tt>, or <tt>@header_converters</tt>
+ # if +headers+ is passed as +true+, returning the converted field set. Any
+ # converter that changes the field into something other than a String halts
+ # the pipeline of conversion for that field. This is primarily an efficiency
+ # shortcut.
+ #
+ def convert_fields(fields, headers = false)
+ if headers
+ header_fields_converter.convert(fields, nil, 0)
+ else
+ parser_fields_converter.convert(fields, @headers, lineno)
+ end
+ end
+
+ #
+ # Returns the encoding of the internal IO object.
+ #
+ def raw_encoding
+ if @io.respond_to? :internal_encoding
+ @io.internal_encoding || @io.external_encoding
+ elsif @io.respond_to? :encoding
+ @io.encoding
+ else
+ nil
+ end
+ end
+
+ def parser_fields_converter
+ @parser_fields_converter ||= build_parser_fields_converter
+ end
+
+ def build_parser_fields_converter
+ specific_options = {
+ builtin_converters_name: :Converters,
+ }
+ options = @base_fields_converter_options.merge(specific_options)
+ build_fields_converter(@initial_converters, options)
+ end
+
+ def header_fields_converter
+ @header_fields_converter ||= build_header_fields_converter
+ end
+
+ def build_header_fields_converter
+ specific_options = {
+ builtin_converters_name: :HeaderConverters,
+ accept_nil: true,
+ }
+ options = @base_fields_converter_options.merge(specific_options)
+ build_fields_converter(@initial_header_converters, options)
+ end
+
+ def writer_fields_converter
+ @writer_fields_converter ||= build_writer_fields_converter
+ end
+
+ def build_writer_fields_converter
+ build_fields_converter(@initial_write_converters,
+ @write_fields_converter_options)
+ end
+
+ def build_fields_converter(initial_converters, options)
+ fields_converter = FieldsConverter.new(options)
+ normalize_converters(initial_converters).each do |name, converter|
+ fields_converter.add_converter(name, &converter)
+ end
+ fields_converter
+ end
+
+ def parser
+ @parser ||= Parser.new(@io, parser_options)
+ end
+
+ def parser_options
+ @parser_options.merge(header_fields_converter: header_fields_converter,
+ fields_converter: parser_fields_converter)
+ end
+
+ def parser_enumerator
+ @parser_enumerator ||= parser.parse
+ end
+
+ def writer
+ @writer ||= Writer.new(@io, writer_options)
+ end
+
+ def writer_options
+ @writer_options.merge(header_fields_converter: header_fields_converter,
+ fields_converter: writer_fields_converter)
+ end
+end
+
+# Passes +args+ to CSV::instance.
+#
+# CSV("CSV,data").read
+# #=> [["CSV", "data"]]
+#
+# If a block is given, the instance is passed the block and the return value
+# becomes the return value of the block.
+#
+# CSV("CSV,data") { |c|
+# c.read.any? { |a| a.include?("data") }
+# } #=> true
+#
+# CSV("CSV,data") { |c|
+# c.read.any? { |a| a.include?("zombies") }
+# } #=> false
+#
+# CSV options may also be given.
+#
+# io = StringIO.new
+# CSV(io, col_sep: ";") { |csv| csv << ["a", "b", "c"] }
+#
+# This API is not Ractor-safe.
+#
+def CSV(*args, **options, &block)
+ CSV.instance(*args, **options, &block)
+end
+
+require_relative "csv/version"
+require_relative "csv/core_ext/array"
+require_relative "csv/core_ext/string"
diff --git a/lib/csv/core_ext/array.rb b/lib/csv/core_ext/array.rb
new file mode 100644
index 0000000000..8beb06b082
--- /dev/null
+++ b/lib/csv/core_ext/array.rb
@@ -0,0 +1,9 @@
+class Array # :nodoc:
+ # Equivalent to CSV::generate_line(self, options)
+ #
+ # ["CSV", "data"].to_csv
+ # #=> "CSV,data\n"
+ def to_csv(**options)
+ CSV.generate_line(self, **options)
+ end
+end
diff --git a/lib/csv/core_ext/string.rb b/lib/csv/core_ext/string.rb
new file mode 100644
index 0000000000..9b1d31c2a4
--- /dev/null
+++ b/lib/csv/core_ext/string.rb
@@ -0,0 +1,9 @@
+class String # :nodoc:
+ # Equivalent to CSV::parse_line(self, options)
+ #
+ # "CSV,data".parse_csv
+ # #=> ["CSV", "data"]
+ def parse_csv(**options)
+ CSV.parse_line(self, **options)
+ end
+end
diff --git a/lib/csv/csv.gemspec b/lib/csv/csv.gemspec
new file mode 100644
index 0000000000..11c5b0f2a6
--- /dev/null
+++ b/lib/csv/csv.gemspec
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+begin
+ require_relative "lib/csv/version"
+rescue LoadError
+ # for Ruby core repository
+ require_relative "version"
+end
+
+Gem::Specification.new do |spec|
+ spec.name = "csv"
+ spec.version = CSV::VERSION
+ spec.authors = ["James Edward Gray II", "Kouhei Sutou"]
+ spec.email = [nil, "kou@cozmixng.org"]
+
+ spec.summary = "CSV Reading and Writing"
+ spec.description = "The CSV library provides a complete interface to CSV files and data. It offers tools to enable you to read and write to and from Strings or IO objects, as needed."
+ spec.homepage = "https://github.com/ruby/csv"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ lib_path = "lib"
+ spec.require_paths = [lib_path]
+ files = []
+ lib_dir = File.join(__dir__, lib_path)
+ if File.exist?(lib_dir)
+ Dir.chdir(lib_dir) do
+ Dir.glob("**/*.rb").each do |file|
+ files << "lib/#{file}"
+ end
+ end
+ end
+ doc_dir = File.join(__dir__, "doc")
+ if File.exist?(doc_dir)
+ Dir.chdir(doc_dir) do
+ Dir.glob("**/*.rdoc").each do |rdoc_file|
+ files << "doc/#{rdoc_file}"
+ end
+ end
+ end
+ spec.files = files
+ spec.rdoc_options.concat(["--main", "README.md"])
+ rdoc_files = [
+ "LICENSE.txt",
+ "NEWS.md",
+ "README.md",
+ ]
+ recipes_dir = File.join(doc_dir, "csv", "recipes")
+ if File.exist?(recipes_dir)
+ Dir.chdir(recipes_dir) do
+ Dir.glob("**/*.rdoc").each do |recipe_file|
+ rdoc_files << "doc/csv/recipes/#{recipe_file}"
+ end
+ end
+ end
+ spec.extra_rdoc_files = rdoc_files
+
+ spec.required_ruby_version = ">= 2.5.0"
+
+ # spec.add_dependency "stringio", ">= 0.1.3"
+ spec.add_development_dependency "bundler"
+ spec.add_development_dependency "rake"
+ spec.add_development_dependency "benchmark_driver"
+ spec.add_development_dependency "test-unit", ">= 3.4.8"
+end
diff --git a/lib/csv/delete_suffix.rb b/lib/csv/delete_suffix.rb
new file mode 100644
index 0000000000..d457718997
--- /dev/null
+++ b/lib/csv/delete_suffix.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+# This provides String#delete_suffix? for Ruby 2.4.
+unless String.method_defined?(:delete_suffix)
+ class CSV
+ module DeleteSuffix
+ refine String do
+ def delete_suffix(suffix)
+ if end_with?(suffix)
+ self[0...-suffix.size]
+ else
+ self
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/csv/fields_converter.rb b/lib/csv/fields_converter.rb
new file mode 100644
index 0000000000..d15977d379
--- /dev/null
+++ b/lib/csv/fields_converter.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+class CSV
+ # Note: Don't use this class directly. This is an internal class.
+ class FieldsConverter
+ include Enumerable
+ #
+ # A CSV::FieldsConverter is a data structure for storing the
+ # fields converter properties to be passed as a parameter
+ # when parsing a new file (e.g. CSV::Parser.new(@io, parser_options))
+ #
+
+ def initialize(options={})
+ @converters = []
+ @nil_value = options[:nil_value]
+ @empty_value = options[:empty_value]
+ @empty_value_is_empty_string = (@empty_value == "")
+ @accept_nil = options[:accept_nil]
+ @builtin_converters_name = options[:builtin_converters_name]
+ @need_static_convert = need_static_convert?
+ end
+
+ def add_converter(name=nil, &converter)
+ if name.nil? # custom converter
+ @converters << converter
+ else # named converter
+ combo = builtin_converters[name]
+ case combo
+ when Array # combo converter
+ combo.each do |sub_name|
+ add_converter(sub_name)
+ end
+ else # individual named converter
+ @converters << combo
+ end
+ end
+ end
+
+ def each(&block)
+ @converters.each(&block)
+ end
+
+ def empty?
+ @converters.empty?
+ end
+
+ def convert(fields, headers, lineno, quoted_fields)
+ return fields unless need_convert?
+
+ fields.collect.with_index do |field, index|
+ if field.nil?
+ field = @nil_value
+ elsif field.is_a?(String) and field.empty?
+ field = @empty_value unless @empty_value_is_empty_string
+ end
+ @converters.each do |converter|
+ break if field.nil? and @accept_nil
+ if converter.arity == 1 # straight field converter
+ field = converter[field]
+ else # FieldInfo converter
+ if headers
+ header = headers[index]
+ else
+ header = nil
+ end
+ quoted = quoted_fields[index]
+ field = converter[field, FieldInfo.new(index, lineno, header, quoted)]
+ end
+ break unless field.is_a?(String) # short-circuit pipeline for speed
+ end
+ field # final state of each field, converted or original
+ end
+ end
+
+ private
+ def need_static_convert?
+ not (@nil_value.nil? and @empty_value_is_empty_string)
+ end
+
+ def need_convert?
+ @need_static_convert or
+ (not @converters.empty?)
+ end
+
+ def builtin_converters
+ @builtin_converters ||= ::CSV.const_get(@builtin_converters_name)
+ end
+ end
+end
diff --git a/lib/csv/input_record_separator.rb b/lib/csv/input_record_separator.rb
new file mode 100644
index 0000000000..7a99343c0c
--- /dev/null
+++ b/lib/csv/input_record_separator.rb
@@ -0,0 +1,18 @@
+require "English"
+require "stringio"
+
+class CSV
+ module InputRecordSeparator
+ class << self
+ if RUBY_VERSION >= "3.0.0"
+ def value
+ "\n"
+ end
+ else
+ def value
+ $INPUT_RECORD_SEPARATOR
+ end
+ end
+ end
+ end
+end
diff --git a/lib/csv/match_p.rb b/lib/csv/match_p.rb
new file mode 100644
index 0000000000..775559a3eb
--- /dev/null
+++ b/lib/csv/match_p.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+# This provides String#match? and Regexp#match? for Ruby 2.3.
+unless String.method_defined?(:match?)
+ class CSV
+ module MatchP
+ refine String do
+ def match?(pattern)
+ self =~ pattern
+ end
+ end
+
+ refine Regexp do
+ def match?(string)
+ self =~ string
+ end
+ end
+ end
+ end
+end
diff --git a/lib/csv/parser.rb b/lib/csv/parser.rb
new file mode 100644
index 0000000000..afb3131cd5
--- /dev/null
+++ b/lib/csv/parser.rb
@@ -0,0 +1,1289 @@
+# frozen_string_literal: true
+
+require "strscan"
+
+require_relative "input_record_separator"
+require_relative "row"
+require_relative "table"
+
+class CSV
+ # Note: Don't use this class directly. This is an internal class.
+ class Parser
+ #
+ # A CSV::Parser is m17n aware. The parser works in the Encoding of the IO
+ # or String object being read from or written to. Your data is never transcoded
+ # (unless you ask Ruby to transcode it for you) and will literally be parsed in
+ # the Encoding it is in. Thus CSV will return Arrays or Rows of Strings in the
+ # Encoding of your data. This is accomplished by transcoding the parser itself
+ # into your Encoding.
+ #
+
+ # Raised when encoding is invalid.
+ class InvalidEncoding < StandardError
+ end
+
+ # Raised when unexpected case is happen.
+ class UnexpectedError < StandardError
+ end
+
+ #
+ # CSV::Scanner receives a CSV output, scans it and return the content.
+ # It also controls the life cycle of the object with its methods +keep_start+,
+ # +keep_end+, +keep_back+, +keep_drop+.
+ #
+ # Uses StringScanner (the official strscan gem). Strscan provides lexical
+ # scanning operations on a String. We inherit its object and take advantage
+ # on the methods. For more information, please visit:
+ # https://ruby-doc.org/stdlib-2.6.1/libdoc/strscan/rdoc/StringScanner.html
+ #
+ class Scanner < StringScanner
+ alias_method :scan_all, :scan
+
+ def initialize(*args)
+ super
+ @keeps = []
+ end
+
+ def each_line(row_separator)
+ position = pos
+ rest.each_line(row_separator) do |line|
+ position += line.bytesize
+ self.pos = position
+ yield(line)
+ end
+ end
+
+ def keep_start
+ @keeps.push(pos)
+ end
+
+ def keep_end
+ start = @keeps.pop
+ string.byteslice(start, pos - start)
+ end
+
+ def keep_back
+ self.pos = @keeps.pop
+ end
+
+ def keep_drop
+ @keeps.pop
+ end
+ end
+
+ #
+ # CSV::InputsScanner receives IO inputs, encoding and the chunk_size.
+ # It also controls the life cycle of the object with its methods +keep_start+,
+ # +keep_end+, +keep_back+, +keep_drop+.
+ #
+ # CSV::InputsScanner.scan() tries to match with pattern at the current position.
+ # If there's a match, the scanner advances the "scan pointer" and returns the matched string.
+ # Otherwise, the scanner returns nil.
+ #
+ # CSV::InputsScanner.rest() returns the "rest" of the string (i.e. everything after the scan pointer).
+ # If there is no more data (eos? = true), it returns "".
+ #
+ class InputsScanner
+ def initialize(inputs, encoding, row_separator, chunk_size: 8192)
+ @inputs = inputs.dup
+ @encoding = encoding
+ @row_separator = row_separator
+ @chunk_size = chunk_size
+ @last_scanner = @inputs.empty?
+ @keeps = []
+ read_chunk
+ end
+
+ def each_line(row_separator)
+ return enum_for(__method__, row_separator) unless block_given?
+ buffer = nil
+ input = @scanner.rest
+ position = @scanner.pos
+ offset = 0
+ n_row_separator_chars = row_separator.size
+ # trace(__method__, :start, line, input)
+ while true
+ input.each_line(row_separator) do |line|
+ @scanner.pos += line.bytesize
+ if buffer
+ if n_row_separator_chars == 2 and
+ buffer.end_with?(row_separator[0]) and
+ line.start_with?(row_separator[1])
+ buffer << line[0]
+ line = line[1..-1]
+ position += buffer.bytesize + offset
+ @scanner.pos = position
+ offset = 0
+ yield(buffer)
+ buffer = nil
+ next if line.empty?
+ else
+ buffer << line
+ line = buffer
+ buffer = nil
+ end
+ end
+ if line.end_with?(row_separator)
+ position += line.bytesize + offset
+ @scanner.pos = position
+ offset = 0
+ yield(line)
+ else
+ buffer = line
+ end
+ end
+ break unless read_chunk
+ input = @scanner.rest
+ position = @scanner.pos
+ offset = -buffer.bytesize if buffer
+ end
+ yield(buffer) if buffer
+ end
+
+ def scan(pattern)
+ # trace(__method__, pattern, :start)
+ value = @scanner.scan(pattern)
+ # trace(__method__, pattern, :done, :last, value) if @last_scanner
+ return value if @last_scanner
+
+ read_chunk if value and @scanner.eos?
+ # trace(__method__, pattern, :done, value)
+ value
+ end
+
+ def scan_all(pattern)
+ # trace(__method__, pattern, :start)
+ value = @scanner.scan(pattern)
+ # trace(__method__, pattern, :done, :last, value) if @last_scanner
+ return value if @last_scanner
+
+ return nil if value.nil?
+ while @scanner.eos? and read_chunk and (sub_value = @scanner.scan(pattern))
+ # trace(__method__, pattern, :sub, sub_value)
+ value << sub_value
+ end
+ # trace(__method__, pattern, :done, value)
+ value
+ end
+
+ def eos?
+ @scanner.eos?
+ end
+
+ def keep_start
+ # trace(__method__, :start)
+ adjust_last_keep
+ @keeps.push([@scanner, @scanner.pos, nil])
+ # trace(__method__, :done)
+ end
+
+ def keep_end
+ # trace(__method__, :start)
+ scanner, start, buffer = @keeps.pop
+ if scanner == @scanner
+ keep = @scanner.string.byteslice(start, @scanner.pos - start)
+ else
+ keep = @scanner.string.byteslice(0, @scanner.pos)
+ end
+ if buffer
+ buffer << keep
+ keep = buffer
+ end
+ # trace(__method__, :done, keep)
+ keep
+ end
+
+ def keep_back
+ # trace(__method__, :start)
+ scanner, start, buffer = @keeps.pop
+ if buffer
+ # trace(__method__, :rescan, start, buffer)
+ string = @scanner.string
+ if scanner == @scanner
+ keep = string.byteslice(start, string.bytesize - start)
+ else
+ keep = string
+ end
+ if keep and not keep.empty?
+ @inputs.unshift(StringIO.new(keep))
+ @last_scanner = false
+ end
+ @scanner = StringScanner.new(buffer)
+ else
+ if @scanner != scanner
+ message = "scanners are different but no buffer: "
+ message += "#{@scanner.inspect}(#{@scanner.object_id}): "
+ message += "#{scanner.inspect}(#{scanner.object_id})"
+ raise UnexpectedError, message
+ end
+ # trace(__method__, :repos, start, buffer)
+ @scanner.pos = start
+ end
+ read_chunk if @scanner.eos?
+ end
+
+ def keep_drop
+ _, _, buffer = @keeps.pop
+ # trace(__method__, :done, :empty) unless buffer
+ return unless buffer
+
+ last_keep = @keeps.last
+ # trace(__method__, :done, :no_last_keep) unless last_keep
+ return unless last_keep
+
+ if last_keep[2]
+ last_keep[2] << buffer
+ else
+ last_keep[2] = buffer
+ end
+ # trace(__method__, :done)
+ end
+
+ def rest
+ @scanner.rest
+ end
+
+ def check(pattern)
+ @scanner.check(pattern)
+ end
+
+ private
+ def trace(*args)
+ pp([*args, @scanner, @scanner&.string, @scanner&.pos, @keeps])
+ end
+
+ def adjust_last_keep
+ # trace(__method__, :start)
+
+ keep = @keeps.last
+ # trace(__method__, :done, :empty) if keep.nil?
+ return if keep.nil?
+
+ scanner, start, buffer = keep
+ string = @scanner.string
+ if @scanner != scanner
+ start = 0
+ end
+ if start == 0 and @scanner.eos?
+ keep_data = string
+ else
+ keep_data = string.byteslice(start, @scanner.pos - start)
+ end
+ if keep_data
+ if buffer
+ buffer << keep_data
+ else
+ keep[2] = keep_data.dup
+ end
+ end
+
+ # trace(__method__, :done)
+ end
+
+ def read_chunk
+ return false if @last_scanner
+
+ adjust_last_keep
+
+ input = @inputs.first
+ case input
+ when StringIO
+ string = input.read
+ raise InvalidEncoding unless string.valid_encoding?
+ # trace(__method__, :stringio, string)
+ @scanner = StringScanner.new(string)
+ @inputs.shift
+ @last_scanner = @inputs.empty?
+ true
+ else
+ chunk = input.gets(@row_separator, @chunk_size)
+ if chunk
+ raise InvalidEncoding unless chunk.valid_encoding?
+ # trace(__method__, :chunk, chunk)
+ @scanner = StringScanner.new(chunk)
+ if input.respond_to?(:eof?) and input.eof?
+ @inputs.shift
+ @last_scanner = @inputs.empty?
+ end
+ true
+ else
+ # trace(__method__, :no_chunk)
+ @scanner = StringScanner.new("".encode(@encoding))
+ @inputs.shift
+ @last_scanner = @inputs.empty?
+ if @last_scanner
+ false
+ else
+ read_chunk
+ end
+ end
+ end
+ end
+ end
+
+ def initialize(input, options)
+ @input = input
+ @options = options
+ @samples = []
+
+ prepare
+ end
+
+ def column_separator
+ @column_separator
+ end
+
+ def row_separator
+ @row_separator
+ end
+
+ def quote_character
+ @quote_character
+ end
+
+ def field_size_limit
+ @max_field_size&.succ
+ end
+
+ def max_field_size
+ @max_field_size
+ end
+
+ def skip_lines
+ @skip_lines
+ end
+
+ def unconverted_fields?
+ @unconverted_fields
+ end
+
+ def headers
+ @headers
+ end
+
+ def header_row?
+ @use_headers and @headers.nil?
+ end
+
+ def return_headers?
+ @return_headers
+ end
+
+ def skip_blanks?
+ @skip_blanks
+ end
+
+ def liberal_parsing?
+ @liberal_parsing
+ end
+
+ def lineno
+ @lineno
+ end
+
+ def line
+ last_line
+ end
+
+ def parse(&block)
+ return to_enum(__method__) unless block_given?
+
+ if @return_headers and @headers and @raw_headers
+ headers = Row.new(@headers, @raw_headers, true)
+ if @unconverted_fields
+ headers = add_unconverted_fields(headers, [])
+ end
+ yield headers
+ end
+
+ begin
+ @scanner ||= build_scanner
+ if quote_character.nil?
+ parse_no_quote(&block)
+ elsif @need_robust_parsing
+ parse_quotable_robust(&block)
+ else
+ parse_quotable_loose(&block)
+ end
+ rescue InvalidEncoding
+ if @scanner
+ ignore_broken_line
+ lineno = @lineno
+ else
+ lineno = @lineno + 1
+ end
+ message = "Invalid byte sequence in #{@encoding}"
+ raise MalformedCSVError.new(message, lineno)
+ rescue UnexpectedError => error
+ if @scanner
+ ignore_broken_line
+ lineno = @lineno
+ else
+ lineno = @lineno + 1
+ end
+ message = "This should not be happen: #{error.message}: "
+ message += "Please report this to https://github.com/ruby/csv/issues"
+ raise MalformedCSVError.new(message, lineno)
+ end
+ end
+
+ def use_headers?
+ @use_headers
+ end
+
+ private
+ # A set of tasks to prepare the file in order to parse it
+ def prepare
+ prepare_variable
+ prepare_quote_character
+ prepare_backslash
+ prepare_skip_lines
+ prepare_strip
+ prepare_separators
+ validate_strip_and_col_sep_options
+ prepare_quoted
+ prepare_unquoted
+ prepare_line
+ prepare_header
+ prepare_parser
+ end
+
+ def prepare_variable
+ @need_robust_parsing = false
+ @encoding = @options[:encoding]
+ liberal_parsing = @options[:liberal_parsing]
+ if liberal_parsing
+ @liberal_parsing = true
+ if liberal_parsing.is_a?(Hash)
+ @double_quote_outside_quote =
+ liberal_parsing[:double_quote_outside_quote]
+ @backslash_quote = liberal_parsing[:backslash_quote]
+ else
+ @double_quote_outside_quote = false
+ @backslash_quote = false
+ end
+ @need_robust_parsing = true
+ else
+ @liberal_parsing = false
+ @backslash_quote = false
+ end
+ @unconverted_fields = @options[:unconverted_fields]
+ @max_field_size = @options[:max_field_size]
+ @skip_blanks = @options[:skip_blanks]
+ @fields_converter = @options[:fields_converter]
+ @header_fields_converter = @options[:header_fields_converter]
+ end
+
+ def prepare_quote_character
+ @quote_character = @options[:quote_character]
+ if @quote_character.nil?
+ @escaped_quote_character = nil
+ @escaped_quote = nil
+ else
+ @quote_character = @quote_character.to_s.encode(@encoding)
+ if @quote_character.length != 1
+ message = ":quote_char has to be nil or a single character String"
+ raise ArgumentError, message
+ end
+ @double_quote_character = @quote_character * 2
+ @escaped_quote_character = Regexp.escape(@quote_character)
+ @escaped_quote = Regexp.new(@escaped_quote_character)
+ end
+ end
+
+ def prepare_backslash
+ return unless @backslash_quote
+
+ @backslash_character = "\\".encode(@encoding)
+
+ @escaped_backslash_character = Regexp.escape(@backslash_character)
+ @escaped_backslash = Regexp.new(@escaped_backslash_character)
+ if @quote_character.nil?
+ @backslash_quote_character = nil
+ else
+ @backslash_quote_character =
+ @backslash_character + @escaped_quote_character
+ end
+ end
+
+ def prepare_skip_lines
+ skip_lines = @options[:skip_lines]
+ case skip_lines
+ when String
+ @skip_lines = skip_lines.encode(@encoding)
+ when Regexp, nil
+ @skip_lines = skip_lines
+ else
+ unless skip_lines.respond_to?(:match)
+ message =
+ ":skip_lines has to respond to \#match: #{skip_lines.inspect}"
+ raise ArgumentError, message
+ end
+ @skip_lines = skip_lines
+ end
+ end
+
+ def prepare_strip
+ @strip = @options[:strip]
+ @escaped_strip = nil
+ @strip_value = nil
+ @rstrip_value = nil
+ if @strip.is_a?(String)
+ case @strip.length
+ when 0
+ raise ArgumentError, ":strip must not be an empty String"
+ when 1
+ # ok
+ else
+ raise ArgumentError, ":strip doesn't support 2 or more characters yet"
+ end
+ @strip = @strip.encode(@encoding)
+ @escaped_strip = Regexp.escape(@strip)
+ if @quote_character
+ @strip_value = Regexp.new(@escaped_strip +
+ "+".encode(@encoding))
+ @rstrip_value = Regexp.new(@escaped_strip +
+ "+\\z".encode(@encoding))
+ end
+ @need_robust_parsing = true
+ elsif @strip
+ strip_values = " \t\f\v"
+ @escaped_strip = strip_values.encode(@encoding)
+ if @quote_character
+ @strip_value = Regexp.new("[#{strip_values}]+".encode(@encoding))
+ @rstrip_value = Regexp.new("[#{strip_values}]+\\z".encode(@encoding))
+ end
+ @need_robust_parsing = true
+ end
+ end
+
+ begin
+ StringScanner.new("x").scan("x")
+ rescue TypeError
+ STRING_SCANNER_SCAN_ACCEPT_STRING = false
+ else
+ STRING_SCANNER_SCAN_ACCEPT_STRING = true
+ end
+
+ def prepare_separators
+ column_separator = @options[:column_separator]
+ @column_separator = column_separator.to_s.encode(@encoding)
+ if @column_separator.size < 1
+ message = ":col_sep must be 1 or more characters: "
+ message += column_separator.inspect
+ raise ArgumentError, message
+ end
+ @row_separator =
+ resolve_row_separator(@options[:row_separator]).encode(@encoding)
+
+ @escaped_column_separator = Regexp.escape(@column_separator)
+ @escaped_first_column_separator = Regexp.escape(@column_separator[0])
+ if @column_separator.size > 1
+ @column_end = Regexp.new(@escaped_column_separator)
+ @column_ends = @column_separator.each_char.collect do |char|
+ Regexp.new(Regexp.escape(char))
+ end
+ @first_column_separators = Regexp.new(@escaped_first_column_separator +
+ "+".encode(@encoding))
+ else
+ if STRING_SCANNER_SCAN_ACCEPT_STRING
+ @column_end = @column_separator
+ else
+ @column_end = Regexp.new(@escaped_column_separator)
+ end
+ @column_ends = nil
+ @first_column_separators = nil
+ end
+
+ escaped_row_separator = Regexp.escape(@row_separator)
+ @row_end = Regexp.new(escaped_row_separator)
+ if @row_separator.size > 1
+ @row_ends = @row_separator.each_char.collect do |char|
+ Regexp.new(Regexp.escape(char))
+ end
+ else
+ @row_ends = nil
+ end
+
+ @cr = "\r".encode(@encoding)
+ @lf = "\n".encode(@encoding)
+ @line_end = Regexp.new("\r\n|\n|\r".encode(@encoding))
+ @not_line_end = Regexp.new("[^\r\n]+".encode(@encoding))
+ end
+
+ # This method verifies that there are no (obvious) ambiguities with the
+ # provided +col_sep+ and +strip+ parsing options. For example, if +col_sep+
+ # and +strip+ were both equal to +\t+, then there would be no clear way to
+ # parse the input.
+ def validate_strip_and_col_sep_options
+ return unless @strip
+
+ if @strip.is_a?(String)
+ if @column_separator.start_with?(@strip) || @column_separator.end_with?(@strip)
+ raise ArgumentError,
+ "The provided strip (#{@escaped_strip}) and " \
+ "col_sep (#{@escaped_column_separator}) options are incompatible."
+ end
+ else
+ if Regexp.new("\\A[#{@escaped_strip}]|[#{@escaped_strip}]\\z").match?(@column_separator)
+ raise ArgumentError,
+ "The provided strip (true) and " \
+ "col_sep (#{@escaped_column_separator}) options are incompatible."
+ end
+ end
+ end
+
+ def prepare_quoted
+ if @quote_character
+ @quotes = Regexp.new(@escaped_quote_character +
+ "+".encode(@encoding))
+ no_quoted_values = @escaped_quote_character.dup
+ if @backslash_quote
+ no_quoted_values << @escaped_backslash_character
+ end
+ @quoted_value = Regexp.new("[^".encode(@encoding) +
+ no_quoted_values +
+ "]+".encode(@encoding))
+ end
+ if @escaped_strip
+ @split_column_separator = Regexp.new(@escaped_strip +
+ "*".encode(@encoding) +
+ @escaped_column_separator +
+ @escaped_strip +
+ "*".encode(@encoding))
+ else
+ if @column_separator == " ".encode(@encoding)
+ @split_column_separator = Regexp.new(@escaped_column_separator)
+ else
+ @split_column_separator = @column_separator
+ end
+ end
+ end
+
+ def prepare_unquoted
+ return if @quote_character.nil?
+
+ no_unquoted_values = "\r\n".encode(@encoding)
+ no_unquoted_values << @escaped_first_column_separator
+ unless @liberal_parsing
+ no_unquoted_values << @escaped_quote_character
+ end
+ @unquoted_value = Regexp.new("[^".encode(@encoding) +
+ no_unquoted_values +
+ "]+".encode(@encoding))
+ end
+
+ def resolve_row_separator(separator)
+ if separator == :auto
+ cr = "\r".encode(@encoding)
+ lf = "\n".encode(@encoding)
+ if @input.is_a?(StringIO)
+ pos = @input.pos
+ separator = detect_row_separator(@input.read, cr, lf)
+ @input.seek(pos)
+ elsif @input.respond_to?(:gets)
+ if @input.is_a?(File)
+ chunk_size = 32 * 1024
+ else
+ chunk_size = 1024
+ end
+ begin
+ while separator == :auto
+ #
+ # if we run out of data, it's probably a single line
+ # (ensure will set default value)
+ #
+ break unless sample = @input.gets(nil, chunk_size)
+
+ # extend sample if we're unsure of the line ending
+ if sample.end_with?(cr)
+ sample << (@input.gets(nil, 1) || "")
+ end
+
+ @samples << sample
+
+ separator = detect_row_separator(sample, cr, lf)
+ end
+ rescue IOError
+ # do nothing: ensure will set default
+ end
+ end
+ separator = InputRecordSeparator.value if separator == :auto
+ end
+ separator.to_s.encode(@encoding)
+ end
+
+ def detect_row_separator(sample, cr, lf)
+ lf_index = sample.index(lf)
+ if lf_index
+ cr_index = sample[0, lf_index].index(cr)
+ else
+ cr_index = sample.index(cr)
+ end
+ if cr_index and lf_index
+ if cr_index + 1 == lf_index
+ cr + lf
+ elsif cr_index < lf_index
+ cr
+ else
+ lf
+ end
+ elsif cr_index
+ cr
+ elsif lf_index
+ lf
+ else
+ :auto
+ end
+ end
+
+ def prepare_line
+ @lineno = 0
+ @last_line = nil
+ @scanner = nil
+ end
+
+ def last_line
+ if @scanner
+ @last_line ||= @scanner.keep_end
+ else
+ @last_line
+ end
+ end
+
+ def prepare_header
+ @return_headers = @options[:return_headers]
+
+ headers = @options[:headers]
+ case headers
+ when Array
+ @raw_headers = headers
+ quoted_fields = [false] * @raw_headers.size
+ @use_headers = true
+ when String
+ @raw_headers, quoted_fields = parse_headers(headers)
+ @use_headers = true
+ when nil, false
+ @raw_headers = nil
+ @use_headers = false
+ else
+ @raw_headers = nil
+ @use_headers = true
+ end
+ if @raw_headers
+ @headers = adjust_headers(@raw_headers, quoted_fields)
+ else
+ @headers = nil
+ end
+ end
+
+ def parse_headers(row)
+ quoted_fields = []
+ converter = lambda do |field, info|
+ quoted_fields << info.quoted?
+ field
+ end
+ headers = CSV.parse_line(row,
+ col_sep: @column_separator,
+ row_sep: @row_separator,
+ quote_char: @quote_character,
+ converters: [converter])
+ [headers, quoted_fields]
+ end
+
+ def adjust_headers(headers, quoted_fields)
+ adjusted_headers = @header_fields_converter.convert(headers, nil, @lineno, quoted_fields)
+ adjusted_headers.each {|h| h.freeze if h.is_a? String}
+ adjusted_headers
+ end
+
+ def prepare_parser
+ @may_quoted = may_quoted?
+ end
+
+ def may_quoted?
+ return false if @quote_character.nil?
+
+ if @input.is_a?(StringIO)
+ pos = @input.pos
+ sample = @input.read
+ @input.seek(pos)
+ else
+ return false if @samples.empty?
+ sample = @samples.first
+ end
+ sample[0, 128].index(@quote_character)
+ end
+
+ class UnoptimizedStringIO # :nodoc:
+ def initialize(string)
+ @io = StringIO.new(string, "rb:#{string.encoding}")
+ end
+
+ def gets(*args)
+ @io.gets(*args)
+ end
+
+ def each_line(*args, &block)
+ @io.each_line(*args, &block)
+ end
+
+ def eof?
+ @io.eof?
+ end
+ end
+
+ SCANNER_TEST = (ENV["CSV_PARSER_SCANNER_TEST"] == "yes")
+ if SCANNER_TEST
+ SCANNER_TEST_CHUNK_SIZE_NAME = "CSV_PARSER_SCANNER_TEST_CHUNK_SIZE"
+ SCANNER_TEST_CHUNK_SIZE_VALUE = ENV[SCANNER_TEST_CHUNK_SIZE_NAME]
+ def build_scanner
+ inputs = @samples.collect do |sample|
+ UnoptimizedStringIO.new(sample)
+ end
+ if @input.is_a?(StringIO)
+ inputs << UnoptimizedStringIO.new(@input.read)
+ else
+ inputs << @input
+ end
+ begin
+ chunk_size_value = ENV[SCANNER_TEST_CHUNK_SIZE_NAME]
+ rescue # Ractor::IsolationError
+ # Ractor on Ruby 3.0 can't read ENV value.
+ chunk_size_value = SCANNER_TEST_CHUNK_SIZE_VALUE
+ end
+ chunk_size = Integer((chunk_size_value || "1"), 10)
+ InputsScanner.new(inputs,
+ @encoding,
+ @row_separator,
+ chunk_size: chunk_size)
+ end
+ else
+ def build_scanner
+ string = nil
+ if @samples.empty? and @input.is_a?(StringIO)
+ string = @input.read
+ elsif @samples.size == 1 and
+ @input != ARGF and
+ @input.respond_to?(:eof?) and
+ @input.eof?
+ string = @samples[0]
+ end
+ if string
+ unless string.valid_encoding?
+ index = string.lines(@row_separator).index do |line|
+ !line.valid_encoding?
+ end
+ if index
+ message = "Invalid byte sequence in #{@encoding}"
+ raise MalformedCSVError.new(message, @lineno + index + 1)
+ end
+ end
+ Scanner.new(string)
+ else
+ inputs = @samples.collect do |sample|
+ StringIO.new(sample)
+ end
+ inputs << @input
+ InputsScanner.new(inputs, @encoding, @row_separator)
+ end
+ end
+ end
+
+ def skip_needless_lines
+ return unless @skip_lines
+
+ until @scanner.eos?
+ @scanner.keep_start
+ line = @scanner.scan_all(@not_line_end) || "".encode(@encoding)
+ line << @row_separator if parse_row_end
+ if skip_line?(line)
+ @lineno += 1
+ @scanner.keep_drop
+ else
+ @scanner.keep_back
+ return
+ end
+ end
+ end
+
+ def skip_line?(line)
+ line = line.delete_suffix(@row_separator)
+ case @skip_lines
+ when String
+ line.include?(@skip_lines)
+ when Regexp
+ @skip_lines.match?(line)
+ else
+ @skip_lines.match(line)
+ end
+ end
+
+ def validate_field_size(field)
+ return unless @max_field_size
+ return if field.size <= @max_field_size
+ ignore_broken_line
+ message = "Field size exceeded: #{field.size} > #{@max_field_size}"
+ raise MalformedCSVError.new(message, @lineno)
+ end
+
+ def parse_no_quote(&block)
+ @scanner.each_line(@row_separator) do |line|
+ next if @skip_lines and skip_line?(line)
+ original_line = line
+ line = line.delete_suffix(@row_separator)
+
+ if line.empty?
+ next if @skip_blanks
+ row = []
+ quoted_fields = []
+ else
+ line = strip_value(line)
+ row = line.split(@split_column_separator, -1)
+ quoted_fields = [false] * row.size
+ if @max_field_size
+ row.each do |column|
+ validate_field_size(column)
+ end
+ end
+ n_columns = row.size
+ i = 0
+ while i < n_columns
+ row[i] = nil if row[i].empty?
+ i += 1
+ end
+ end
+ @last_line = original_line
+ emit_row(row, quoted_fields, &block)
+ end
+ end
+
+ def parse_quotable_loose(&block)
+ @scanner.keep_start
+ @scanner.each_line(@row_separator) do |line|
+ if @skip_lines and skip_line?(line)
+ @scanner.keep_drop
+ @scanner.keep_start
+ next
+ end
+ original_line = line
+ line = line.delete_suffix(@row_separator)
+
+ if line.empty?
+ if @skip_blanks
+ @scanner.keep_drop
+ @scanner.keep_start
+ next
+ end
+ row = []
+ quoted_fields = []
+ elsif line.include?(@cr) or line.include?(@lf)
+ @scanner.keep_back
+ @need_robust_parsing = true
+ return parse_quotable_robust(&block)
+ else
+ row = line.split(@split_column_separator, -1)
+ quoted_fields = []
+ n_columns = row.size
+ i = 0
+ while i < n_columns
+ column = row[i]
+ if column.empty?
+ quoted_fields << false
+ row[i] = nil
+ else
+ n_quotes = column.count(@quote_character)
+ if n_quotes.zero?
+ quoted_fields << false
+ # no quote
+ elsif n_quotes == 2 and
+ column.start_with?(@quote_character) and
+ column.end_with?(@quote_character)
+ quoted_fields << true
+ row[i] = column[1..-2]
+ else
+ @scanner.keep_back
+ @need_robust_parsing = true
+ return parse_quotable_robust(&block)
+ end
+ validate_field_size(row[i])
+ end
+ i += 1
+ end
+ end
+ @scanner.keep_drop
+ @scanner.keep_start
+ @last_line = original_line
+ emit_row(row, quoted_fields, &block)
+ end
+ @scanner.keep_drop
+ end
+
+ def parse_quotable_robust(&block)
+ row = []
+ quoted_fields = []
+ skip_needless_lines
+ start_row
+ while true
+ @quoted_column_value = false
+ @unquoted_column_value = false
+ @scanner.scan_all(@strip_value) if @strip_value
+ value = parse_column_value
+ if value
+ @scanner.scan_all(@strip_value) if @strip_value
+ validate_field_size(value)
+ end
+ if parse_column_end
+ row << value
+ quoted_fields << @quoted_column_value
+ elsif parse_row_end
+ if row.empty? and value.nil?
+ emit_row([], [], &block) unless @skip_blanks
+ else
+ row << value
+ quoted_fields << @quoted_column_value
+ emit_row(row, quoted_fields, &block)
+ row = []
+ quoted_fields = []
+ end
+ skip_needless_lines
+ start_row
+ elsif @scanner.eos?
+ break if row.empty? and value.nil?
+ row << value
+ quoted_fields << @quoted_column_value
+ emit_row(row, quoted_fields, &block)
+ break
+ else
+ if @quoted_column_value
+ if liberal_parsing? and (new_line = @scanner.check(@line_end))
+ message =
+ "Illegal end-of-line sequence outside of a quoted field " +
+ "<#{new_line.inspect}>"
+ else
+ message = "Any value after quoted field isn't allowed"
+ end
+ ignore_broken_line
+ raise MalformedCSVError.new(message, @lineno)
+ elsif @unquoted_column_value and
+ (new_line = @scanner.scan(@line_end))
+ ignore_broken_line
+ message = "Unquoted fields do not allow new line " +
+ "<#{new_line.inspect}>"
+ raise MalformedCSVError.new(message, @lineno)
+ elsif @scanner.rest.start_with?(@quote_character)
+ ignore_broken_line
+ message = "Illegal quoting"
+ raise MalformedCSVError.new(message, @lineno)
+ elsif (new_line = @scanner.scan(@line_end))
+ ignore_broken_line
+ message = "New line must be <#{@row_separator.inspect}> " +
+ "not <#{new_line.inspect}>"
+ raise MalformedCSVError.new(message, @lineno)
+ else
+ ignore_broken_line
+ raise MalformedCSVError.new("TODO: Meaningful message",
+ @lineno)
+ end
+ end
+ end
+ end
+
+ def parse_column_value
+ if @liberal_parsing
+ quoted_value = parse_quoted_column_value
+ if quoted_value
+ @scanner.scan_all(@strip_value) if @strip_value
+ unquoted_value = parse_unquoted_column_value
+ if unquoted_value
+ if @double_quote_outside_quote
+ unquoted_value = unquoted_value.gsub(@quote_character * 2,
+ @quote_character)
+ if quoted_value.empty? # %Q{""...} case
+ return @quote_character + unquoted_value
+ end
+ end
+ @quote_character + quoted_value + @quote_character + unquoted_value
+ else
+ quoted_value
+ end
+ else
+ parse_unquoted_column_value
+ end
+ elsif @may_quoted
+ parse_quoted_column_value ||
+ parse_unquoted_column_value
+ else
+ parse_unquoted_column_value ||
+ parse_quoted_column_value
+ end
+ end
+
+ def parse_unquoted_column_value
+ value = @scanner.scan_all(@unquoted_value)
+ return nil unless value
+
+ @unquoted_column_value = true
+ if @first_column_separators
+ while true
+ @scanner.keep_start
+ is_column_end = @column_ends.all? do |column_end|
+ @scanner.scan(column_end)
+ end
+ @scanner.keep_back
+ break if is_column_end
+ sub_separator = @scanner.scan_all(@first_column_separators)
+ break if sub_separator.nil?
+ value << sub_separator
+ sub_value = @scanner.scan_all(@unquoted_value)
+ break if sub_value.nil?
+ value << sub_value
+ end
+ end
+ value.gsub!(@backslash_quote_character, @quote_character) if @backslash_quote
+ if @rstrip_value
+ value.gsub!(@rstrip_value, "")
+ end
+ value
+ end
+
+ def parse_quoted_column_value
+ quotes = @scanner.scan_all(@quotes)
+ return nil unless quotes
+
+ @quoted_column_value = true
+ n_quotes = quotes.size
+ if (n_quotes % 2).zero?
+ quotes[0, (n_quotes - 2) / 2]
+ else
+ value = quotes[0, n_quotes / 2]
+ while true
+ quoted_value = @scanner.scan_all(@quoted_value)
+ value << quoted_value if quoted_value
+ if @backslash_quote
+ if @scanner.scan(@escaped_backslash)
+ if @scanner.scan(@escaped_quote)
+ value << @quote_character
+ else
+ value << @backslash_character
+ end
+ next
+ end
+ end
+
+ quotes = @scanner.scan_all(@quotes)
+ unless quotes
+ ignore_broken_line
+ message = "Unclosed quoted field"
+ raise MalformedCSVError.new(message, @lineno)
+ end
+ n_quotes = quotes.size
+ if n_quotes == 1
+ break
+ else
+ value << quotes[0, n_quotes / 2]
+ break if (n_quotes % 2) == 1
+ end
+ end
+ value
+ end
+ end
+
+ def parse_column_end
+ return true if @scanner.scan(@column_end)
+ return false unless @column_ends
+
+ @scanner.keep_start
+ if @column_ends.all? {|column_end| @scanner.scan(column_end)}
+ @scanner.keep_drop
+ true
+ else
+ @scanner.keep_back
+ false
+ end
+ end
+
+ def parse_row_end
+ return true if @scanner.scan(@row_end)
+ return false unless @row_ends
+ @scanner.keep_start
+ if @row_ends.all? {|row_end| @scanner.scan(row_end)}
+ @scanner.keep_drop
+ true
+ else
+ @scanner.keep_back
+ false
+ end
+ end
+
+ def strip_value(value)
+ return value unless @strip
+ return value if value.nil?
+
+ case @strip
+ when String
+ while value.delete_prefix!(@strip)
+ # do nothing
+ end
+ while value.delete_suffix!(@strip)
+ # do nothing
+ end
+ else
+ value.strip!
+ end
+ value
+ end
+
+ def ignore_broken_line
+ @scanner.scan_all(@not_line_end)
+ @scanner.scan_all(@line_end)
+ @lineno += 1
+ end
+
+ def start_row
+ if @last_line
+ @last_line = nil
+ else
+ @scanner.keep_drop
+ end
+ @scanner.keep_start
+ end
+
+ def emit_row(row, quoted_fields, &block)
+ @lineno += 1
+
+ raw_row = row
+ if @use_headers
+ if @headers.nil?
+ @headers = adjust_headers(row, quoted_fields)
+ return unless @return_headers
+ row = Row.new(@headers, row, true)
+ else
+ row = Row.new(@headers,
+ @fields_converter.convert(raw_row, @headers, @lineno, quoted_fields))
+ end
+ else
+ # convert fields, if needed...
+ row = @fields_converter.convert(raw_row, nil, @lineno, quoted_fields)
+ end
+
+ # inject unconverted fields and accessor, if requested...
+ if @unconverted_fields and not row.respond_to?(:unconverted_fields)
+ add_unconverted_fields(row, raw_row)
+ end
+
+ yield(row)
+ end
+
+ # This method injects an instance variable <tt>unconverted_fields</tt> into
+ # +row+ and an accessor method for +row+ called unconverted_fields(). The
+ # variable is set to the contents of +fields+.
+ def add_unconverted_fields(row, fields)
+ class << row
+ attr_reader :unconverted_fields
+ end
+ row.instance_variable_set(:@unconverted_fields, fields)
+ row
+ end
+ end
+end
diff --git a/lib/csv/row.rb b/lib/csv/row.rb
new file mode 100644
index 0000000000..86323f7d0a
--- /dev/null
+++ b/lib/csv/row.rb
@@ -0,0 +1,757 @@
+# frozen_string_literal: true
+
+require "forwardable"
+
+class CSV
+ # = \CSV::Row
+ # A \CSV::Row instance represents a \CSV table row.
+ # (see {class CSV}[../CSV.html]).
+ #
+ # The instance may have:
+ # - Fields: each is an object, not necessarily a \String.
+ # - Headers: each serves a key, and also need not be a \String.
+ #
+ # === Instance Methods
+ #
+ # \CSV::Row has three groups of instance methods:
+ # - Its own internally defined instance methods.
+ # - Methods included by module Enumerable.
+ # - Methods delegated to class Array.:
+ # * Array#empty?
+ # * Array#length
+ # * Array#size
+ #
+ # == Creating a \CSV::Row Instance
+ #
+ # Commonly, a new \CSV::Row instance is created by parsing \CSV source
+ # that has headers:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.each {|row| p row }
+ # Output:
+ # #<CSV::Row "Name":"foo" "Value":"0">
+ # #<CSV::Row "Name":"bar" "Value":"1">
+ # #<CSV::Row "Name":"baz" "Value":"2">
+ #
+ # You can also create a row directly. See ::new.
+ #
+ # == Headers
+ #
+ # Like a \CSV::Table, a \CSV::Row has headers.
+ #
+ # A \CSV::Row that was created by parsing \CSV source
+ # inherits its headers from the table:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table.first
+ # row.headers # => ["Name", "Value"]
+ #
+ # You can also create a new row with headers;
+ # like the keys in a \Hash, the headers need not be Strings:
+ # row = CSV::Row.new([:name, :value], ['foo', 0])
+ # row.headers # => [:name, :value]
+ #
+ # The new row retains its headers even if added to a table
+ # that has headers:
+ # table << row # => #<CSV::Table mode:col_or_row row_count:5>
+ # row.headers # => [:name, :value]
+ # row[:name] # => "foo"
+ # row['Name'] # => nil
+ #
+ #
+ #
+ # == Accessing Fields
+ #
+ # You may access a field in a \CSV::Row with either its \Integer index
+ # (\Array-style) or its header (\Hash-style).
+ #
+ # Fetch a field using method #[]:
+ # row = CSV::Row.new(['Name', 'Value'], ['foo', 0])
+ # row[1] # => 0
+ # row['Value'] # => 0
+ #
+ # Set a field using method #[]=:
+ # row = CSV::Row.new(['Name', 'Value'], ['foo', 0])
+ # row # => #<CSV::Row "Name":"foo" "Value":0>
+ # row[0] = 'bar'
+ # row['Value'] = 1
+ # row # => #<CSV::Row "Name":"bar" "Value":1>
+ #
+ class Row
+ # :call-seq:
+ # CSV::Row.new(headers, fields, header_row = false) -> csv_row
+ #
+ # Returns the new \CSV::Row instance constructed from
+ # arguments +headers+ and +fields+; both should be Arrays;
+ # note that the fields need not be Strings:
+ # row = CSV::Row.new(['Name', 'Value'], ['foo', 0])
+ # row # => #<CSV::Row "Name":"foo" "Value":0>
+ #
+ # If the \Array lengths are different, the shorter is +nil+-filled:
+ # row = CSV::Row.new(['Name', 'Value', 'Date', 'Size'], ['foo', 0])
+ # row # => #<CSV::Row "Name":"foo" "Value":0 "Date":nil "Size":nil>
+ #
+ # Each \CSV::Row object is either a <i>field row</i> or a <i>header row</i>;
+ # by default, a new row is a field row; for the row created above:
+ # row.field_row? # => true
+ # row.header_row? # => false
+ #
+ # If the optional argument +header_row+ is given as +true+,
+ # the created row is a header row:
+ # row = CSV::Row.new(['Name', 'Value'], ['foo', 0], header_row = true)
+ # row # => #<CSV::Row "Name":"foo" "Value":0>
+ # row.field_row? # => false
+ # row.header_row? # => true
+ def initialize(headers, fields, header_row = false)
+ @header_row = header_row
+ headers.each { |h| h.freeze if h.is_a? String }
+
+ # handle extra headers or fields
+ @row = if headers.size >= fields.size
+ headers.zip(fields)
+ else
+ fields.zip(headers).each(&:reverse!)
+ end
+ end
+
+ # Internal data format used to compare equality.
+ attr_reader :row
+ protected :row
+
+ ### Array Delegation ###
+
+ extend Forwardable
+ def_delegators :@row, :empty?, :length, :size
+
+ # :call-seq:
+ # row.initialize_copy(other_row) -> self
+ #
+ # Calls superclass method.
+ def initialize_copy(other)
+ super_return_value = super
+ @row = @row.collect(&:dup)
+ super_return_value
+ end
+
+ # :call-seq:
+ # row.header_row? -> true or false
+ #
+ # Returns +true+ if this is a header row, +false+ otherwise.
+ def header_row?
+ @header_row
+ end
+
+ # :call-seq:
+ # row.field_row? -> true or false
+ #
+ # Returns +true+ if this is a field row, +false+ otherwise.
+ def field_row?
+ not header_row?
+ end
+
+ # :call-seq:
+ # row.headers -> array_of_headers
+ #
+ # Returns the headers for this row:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table.first
+ # row.headers # => ["Name", "Value"]
+ def headers
+ @row.map(&:first)
+ end
+
+ # :call-seq:
+ # field(index) -> value
+ # field(header) -> value
+ # field(header, offset) -> value
+ #
+ # Returns the field value for the given +index+ or +header+.
+ #
+ # ---
+ #
+ # Fetch field value by \Integer index:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.field(0) # => "foo"
+ # row.field(1) # => "bar"
+ #
+ # Counts backward from the last column if +index+ is negative:
+ # row.field(-1) # => "0"
+ # row.field(-2) # => "foo"
+ #
+ # Returns +nil+ if +index+ is out of range:
+ # row.field(2) # => nil
+ # row.field(-3) # => nil
+ #
+ # ---
+ #
+ # Fetch field value by header (first found):
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.field('Name') # => "Foo"
+ #
+ # Fetch field value by header, ignoring +offset+ leading fields:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.field('Name', 2) # => "Baz"
+ #
+ # Returns +nil+ if the header does not exist.
+ def field(header_or_index, minimum_index = 0)
+ # locate the pair
+ finder = (header_or_index.is_a?(Integer) || header_or_index.is_a?(Range)) ? :[] : :assoc
+ pair = @row[minimum_index..-1].public_send(finder, header_or_index)
+
+ # return the field if we have a pair
+ if pair.nil?
+ nil
+ else
+ header_or_index.is_a?(Range) ? pair.map(&:last) : pair.last
+ end
+ end
+ alias_method :[], :field
+
+ #
+ # :call-seq:
+ # fetch(header) -> value
+ # fetch(header, default) -> value
+ # fetch(header) {|row| ... } -> value
+ #
+ # Returns the field value as specified by +header+.
+ #
+ # ---
+ #
+ # With the single argument +header+, returns the field value
+ # for that header (first found):
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.fetch('Name') # => "Foo"
+ #
+ # Raises exception +KeyError+ if the header does not exist.
+ #
+ # ---
+ #
+ # With arguments +header+ and +default+ given,
+ # returns the field value for the header (first found)
+ # if the header exists, otherwise returns +default+:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.fetch('Name', '') # => "Foo"
+ # row.fetch(:nosuch, '') # => ""
+ #
+ # ---
+ #
+ # With argument +header+ and a block given,
+ # returns the field value for the header (first found)
+ # if the header exists; otherwise calls the block
+ # and returns its return value:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.fetch('Name') {|header| fail 'Cannot happen' } # => "Foo"
+ # row.fetch(:nosuch) {|header| "Header '#{header} not found'" } # => "Header 'nosuch not found'"
+ def fetch(header, *varargs)
+ raise ArgumentError, "Too many arguments" if varargs.length > 1
+ pair = @row.assoc(header)
+ if pair
+ pair.last
+ else
+ if block_given?
+ yield header
+ elsif varargs.empty?
+ raise KeyError, "key not found: #{header}"
+ else
+ varargs.first
+ end
+ end
+ end
+
+ # :call-seq:
+ # row.has_key?(header) -> true or false
+ #
+ # Returns +true+ if there is a field with the given +header+,
+ # +false+ otherwise.
+ def has_key?(header)
+ !!@row.assoc(header)
+ end
+ alias_method :include?, :has_key?
+ alias_method :key?, :has_key?
+ alias_method :member?, :has_key?
+ alias_method :header?, :has_key?
+
+ #
+ # :call-seq:
+ # row[index] = value -> value
+ # row[header, offset] = value -> value
+ # row[header] = value -> value
+ #
+ # Assigns the field value for the given +index+ or +header+;
+ # returns +value+.
+ #
+ # ---
+ #
+ # Assign field value by \Integer index:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row[0] = 'Bat'
+ # row[1] = 3
+ # row # => #<CSV::Row "Name":"Bat" "Value":3>
+ #
+ # Counts backward from the last column if +index+ is negative:
+ # row[-1] = 4
+ # row[-2] = 'Bam'
+ # row # => #<CSV::Row "Name":"Bam" "Value":4>
+ #
+ # Extends the row with <tt>nil:nil</tt> if positive +index+ is not in the row:
+ # row[4] = 5
+ # row # => #<CSV::Row "Name":"bad" "Value":4 nil:nil nil:nil nil:5>
+ #
+ # Raises IndexError if negative +index+ is too small (too far from zero).
+ #
+ # ---
+ #
+ # Assign field value by header (first found):
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row['Name'] = 'Bat'
+ # row # => #<CSV::Row "Name":"Bat" "Name":"Bar" "Name":"Baz">
+ #
+ # Assign field value by header, ignoring +offset+ leading fields:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row['Name', 2] = 4
+ # row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":4>
+ #
+ # Append new field by (new) header:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row['New'] = 6
+ # row# => #<CSV::Row "Name":"foo" "Value":"0" "New":6>
+ def []=(*args)
+ value = args.pop
+
+ if args.first.is_a? Integer
+ if @row[args.first].nil? # extending past the end with index
+ @row[args.first] = [nil, value]
+ @row.map! { |pair| pair.nil? ? [nil, nil] : pair }
+ else # normal index assignment
+ @row[args.first][1] = value
+ end
+ else
+ index = index(*args)
+ if index.nil? # appending a field
+ self << [args.first, value]
+ else # normal header assignment
+ @row[index][1] = value
+ end
+ end
+ end
+
+ #
+ # :call-seq:
+ # row << [header, value] -> self
+ # row << hash -> self
+ # row << value -> self
+ #
+ # Adds a field to +self+; returns +self+:
+ #
+ # If the argument is a 2-element \Array <tt>[header, value]</tt>,
+ # a field is added with the given +header+ and +value+:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row << ['NAME', 'Bat']
+ # row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz" "NAME":"Bat">
+ #
+ # If the argument is a \Hash, each <tt>key-value</tt> pair is added
+ # as a field with header +key+ and value +value+.
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row << {NAME: 'Bat', name: 'Bam'}
+ # row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz" NAME:"Bat" name:"Bam">
+ #
+ # Otherwise, the given +value+ is added as a field with no header.
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row << 'Bag'
+ # row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz" nil:"Bag">
+ def <<(arg)
+ if arg.is_a?(Array) and arg.size == 2 # appending a header and name
+ @row << arg
+ elsif arg.is_a?(Hash) # append header and name pairs
+ arg.each { |pair| @row << pair }
+ else # append field value
+ @row << [nil, arg]
+ end
+
+ self # for chaining
+ end
+
+ # :call-seq:
+ # row.push(*values) -> self
+ #
+ # Appends each of the given +values+ to +self+ as a field; returns +self+:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.push('Bat', 'Bam')
+ # row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz" nil:"Bat" nil:"Bam">
+ def push(*args)
+ args.each { |arg| self << arg }
+
+ self # for chaining
+ end
+
+ #
+ # :call-seq:
+ # delete(index) -> [header, value] or nil
+ # delete(header) -> [header, value] or empty_array
+ # delete(header, offset) -> [header, value] or empty_array
+ #
+ # Removes a specified field from +self+; returns the 2-element \Array
+ # <tt>[header, value]</tt> if the field exists.
+ #
+ # If an \Integer argument +index+ is given,
+ # removes and returns the field at offset +index+,
+ # or returns +nil+ if the field does not exist:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.delete(1) # => ["Name", "Bar"]
+ # row.delete(50) # => nil
+ #
+ # Otherwise, if the single argument +header+ is given,
+ # removes and returns the first-found field with the given header,
+ # of returns a new empty \Array if the field does not exist:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.delete('Name') # => ["Name", "Foo"]
+ # row.delete('NAME') # => []
+ #
+ # If argument +header+ and \Integer argument +offset+ are given,
+ # removes and returns the first-found field with the given header
+ # whose +index+ is at least as large as +offset+:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.delete('Name', 1) # => ["Name", "Bar"]
+ # row.delete('NAME', 1) # => []
+ def delete(header_or_index, minimum_index = 0)
+ if header_or_index.is_a? Integer # by index
+ @row.delete_at(header_or_index)
+ elsif i = index(header_or_index, minimum_index) # by header
+ @row.delete_at(i)
+ else
+ [ ]
+ end
+ end
+
+ # :call-seq:
+ # row.delete_if {|header, value| ... } -> self
+ #
+ # Removes fields from +self+ as selected by the block; returns +self+.
+ #
+ # Removes each field for which the block returns a truthy value:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.delete_if {|header, value| value.start_with?('B') } # => true
+ # row # => #<CSV::Row "Name":"Foo">
+ # row.delete_if {|header, value| header.start_with?('B') } # => false
+ #
+ # If no block is given, returns a new Enumerator:
+ # row.delete_if # => #<Enumerator: #<CSV::Row "Name":"Foo">:delete_if>
+ def delete_if(&block)
+ return enum_for(__method__) { size } unless block_given?
+
+ @row.delete_if(&block)
+
+ self # for chaining
+ end
+
+ # :call-seq:
+ # self.fields(*specifiers) -> array_of_fields
+ #
+ # Returns field values per the given +specifiers+, which may be any mixture of:
+ # - \Integer index.
+ # - \Range of \Integer indexes.
+ # - 2-element \Array containing a header and offset.
+ # - Header.
+ # - \Range of headers.
+ #
+ # For +specifier+ in one of the first four cases above,
+ # returns the result of <tt>self.field(specifier)</tt>; see #field.
+ #
+ # Although there may be any number of +specifiers+,
+ # the examples here will illustrate one at a time.
+ #
+ # When the specifier is an \Integer +index+,
+ # returns <tt>self.field(index)</tt>L
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.fields(1) # => ["Bar"]
+ #
+ # When the specifier is a \Range of \Integers +range+,
+ # returns <tt>self.field(range)</tt>:
+ # row.fields(1..2) # => ["Bar", "Baz"]
+ #
+ # When the specifier is a 2-element \Array +array+,
+ # returns <tt>self.field(array)</tt>L
+ # row.fields('Name', 1) # => ["Foo", "Bar"]
+ #
+ # When the specifier is a header +header+,
+ # returns <tt>self.field(header)</tt>L
+ # row.fields('Name') # => ["Foo"]
+ #
+ # When the specifier is a \Range of headers +range+,
+ # forms a new \Range +new_range+ from the indexes of
+ # <tt>range.start</tt> and <tt>range.end</tt>,
+ # and returns <tt>self.field(new_range)</tt>:
+ # source = "Name,NAME,name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.fields('Name'..'NAME') # => ["Foo", "Bar"]
+ #
+ # Returns all fields if no argument given:
+ # row.fields # => ["Foo", "Bar", "Baz"]
+ def fields(*headers_and_or_indices)
+ if headers_and_or_indices.empty? # return all fields--no arguments
+ @row.map(&:last)
+ else # or work like values_at()
+ all = []
+ headers_and_or_indices.each do |h_or_i|
+ if h_or_i.is_a? Range
+ index_begin = h_or_i.begin.is_a?(Integer) ? h_or_i.begin :
+ index(h_or_i.begin)
+ index_end = h_or_i.end.is_a?(Integer) ? h_or_i.end :
+ index(h_or_i.end)
+ new_range = h_or_i.exclude_end? ? (index_begin...index_end) :
+ (index_begin..index_end)
+ all.concat(fields.values_at(new_range))
+ else
+ all << field(*Array(h_or_i))
+ end
+ end
+ return all
+ end
+ end
+ alias_method :values_at, :fields
+
+ # :call-seq:
+ # index(header) -> index
+ # index(header, offset) -> index
+ #
+ # Returns the index for the given header, if it exists;
+ # otherwise returns +nil+.
+ #
+ # With the single argument +header+, returns the index
+ # of the first-found field with the given +header+:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.index('Name') # => 0
+ # row.index('NAME') # => nil
+ #
+ # With arguments +header+ and +offset+,
+ # returns the index of the first-found field with given +header+,
+ # but ignoring the first +offset+ fields:
+ # row.index('Name', 1) # => 1
+ # row.index('Name', 3) # => nil
+ def index(header, minimum_index = 0)
+ # find the pair
+ index = headers[minimum_index..-1].index(header)
+ # return the index at the right offset, if we found one
+ index.nil? ? nil : index + minimum_index
+ end
+
+ # :call-seq:
+ # row.field?(value) -> true or false
+ #
+ # Returns +true+ if +value+ is a field in this row, +false+ otherwise:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.field?('Bar') # => true
+ # row.field?('BAR') # => false
+ def field?(data)
+ fields.include? data
+ end
+
+ include Enumerable
+
+ # :call-seq:
+ # row.each {|header, value| ... } -> self
+ #
+ # Calls the block with each header-value pair; returns +self+:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.each {|header, value| p [header, value] }
+ # Output:
+ # ["Name", "Foo"]
+ # ["Name", "Bar"]
+ # ["Name", "Baz"]
+ #
+ # If no block is given, returns a new Enumerator:
+ # row.each # => #<Enumerator: #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz">:each>
+ def each(&block)
+ return enum_for(__method__) { size } unless block_given?
+
+ @row.each(&block)
+
+ self # for chaining
+ end
+
+ alias_method :each_pair, :each
+
+ # :call-seq:
+ # row == other -> true or false
+ #
+ # Returns +true+ if +other+ is a /CSV::Row that has the same
+ # fields (headers and values) in the same order as +self+;
+ # otherwise returns +false+:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # other_row = table[0]
+ # row == other_row # => true
+ # other_row = table[1]
+ # row == other_row # => false
+ def ==(other)
+ return @row == other.row if other.is_a? CSV::Row
+ @row == other
+ end
+
+ # :call-seq:
+ # row.to_h -> hash
+ #
+ # Returns the new \Hash formed by adding each header-value pair in +self+
+ # as a key-value pair in the \Hash.
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.to_h # => {"Name"=>"foo", "Value"=>"0"}
+ #
+ # Header order is preserved, but repeated headers are ignored:
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.to_h # => {"Name"=>"Foo"}
+ def to_h
+ hash = {}
+ each do |key, _value|
+ hash[key] = self[key] unless hash.key?(key)
+ end
+ hash
+ end
+ alias_method :to_hash, :to_h
+
+ # :call-seq:
+ # row.deconstruct_keys(keys) -> hash
+ #
+ # Returns the new \Hash suitable for pattern matching containing only the
+ # keys specified as an argument.
+ def deconstruct_keys(keys)
+ if keys.nil?
+ to_h
+ else
+ keys.to_h { |key| [key, self[key]] }
+ end
+ end
+
+ alias_method :to_ary, :to_a
+
+ # :call-seq:
+ # row.deconstruct -> array
+ #
+ # Returns the new \Array suitable for pattern matching containing the values
+ # of the row.
+ def deconstruct
+ fields
+ end
+
+ # :call-seq:
+ # row.to_csv -> csv_string
+ #
+ # Returns the row as a \CSV String. Headers are not included:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.to_csv # => "foo,0\n"
+ def to_csv(**options)
+ fields.to_csv(**options)
+ end
+ alias_method :to_s, :to_csv
+
+ # :call-seq:
+ # row.dig(index_or_header, *identifiers) -> object
+ #
+ # Finds and returns the object in nested object that is specified
+ # by +index_or_header+ and +specifiers+.
+ #
+ # The nested objects may be instances of various classes.
+ # See {Dig Methods}[rdoc-ref:dig_methods.rdoc].
+ #
+ # Examples:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.dig(1) # => "0"
+ # row.dig('Value') # => "0"
+ # row.dig(5) # => nil
+ def dig(index_or_header, *indexes)
+ value = field(index_or_header)
+ if value.nil?
+ nil
+ elsif indexes.empty?
+ value
+ else
+ unless value.respond_to?(:dig)
+ raise TypeError, "#{value.class} does not have \#dig method"
+ end
+ value.dig(*indexes)
+ end
+ end
+
+ # :call-seq:
+ # row.inspect -> string
+ #
+ # Returns an ASCII-compatible \String showing:
+ # - Class \CSV::Row.
+ # - Header-value pairs.
+ # Example:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # row = table[0]
+ # row.inspect # => "#<CSV::Row \"Name\":\"foo\" \"Value\":\"0\">"
+ def inspect
+ str = ["#<", self.class.to_s]
+ each do |header, field|
+ str << " " << (header.is_a?(Symbol) ? header.to_s : header.inspect) <<
+ ":" << field.inspect
+ end
+ str << ">"
+ begin
+ str.join('')
+ rescue # any encoding error
+ str.map do |s|
+ e = Encoding::Converter.asciicompat_encoding(s.encoding)
+ e ? s.encode(e) : s.force_encoding("ASCII-8BIT")
+ end.join('')
+ end
+ end
+ end
+end
diff --git a/lib/csv/table.rb b/lib/csv/table.rb
new file mode 100644
index 0000000000..fb19f5453f
--- /dev/null
+++ b/lib/csv/table.rb
@@ -0,0 +1,1055 @@
+# frozen_string_literal: true
+
+require "forwardable"
+
+class CSV
+ # = \CSV::Table
+ # A \CSV::Table instance represents \CSV data.
+ # (see {class CSV}[../CSV.html]).
+ #
+ # The instance may have:
+ # - Rows: each is a Table::Row object.
+ # - Headers: names for the columns.
+ #
+ # === Instance Methods
+ #
+ # \CSV::Table has three groups of instance methods:
+ # - Its own internally defined instance methods.
+ # - Methods included by module Enumerable.
+ # - Methods delegated to class Array.:
+ # * Array#empty?
+ # * Array#length
+ # * Array#size
+ #
+ # == Creating a \CSV::Table Instance
+ #
+ # Commonly, a new \CSV::Table instance is created by parsing \CSV source
+ # using headers:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.class # => CSV::Table
+ #
+ # You can also create an instance directly. See ::new.
+ #
+ # == Headers
+ #
+ # If a table has headers, the headers serve as labels for the columns of data.
+ # Each header serves as the label for its column.
+ #
+ # The headers for a \CSV::Table object are stored as an \Array of Strings.
+ #
+ # Commonly, headers are defined in the first row of \CSV source:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.headers # => ["Name", "Value"]
+ #
+ # If no headers are defined, the \Array is empty:
+ # table = CSV::Table.new([])
+ # table.headers # => []
+ #
+ # == Access Modes
+ #
+ # \CSV::Table provides three modes for accessing table data:
+ # - \Row mode.
+ # - Column mode.
+ # - Mixed mode (the default for a new table).
+ #
+ # The access mode for a\CSV::Table instance affects the behavior
+ # of some of its instance methods:
+ # - #[]
+ # - #[]=
+ # - #delete
+ # - #delete_if
+ # - #each
+ # - #values_at
+ #
+ # === \Row Mode
+ #
+ # Set a table to row mode with method #by_row!:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
+ #
+ # Specify a single row by an \Integer index:
+ # # Get a row.
+ # table[1] # => #<CSV::Row "Name":"bar" "Value":"1">
+ # # Set a row, then get it.
+ # table[1] = CSV::Row.new(['Name', 'Value'], ['bam', 3])
+ # table[1] # => #<CSV::Row "Name":"bam" "Value":3>
+ #
+ # Specify a sequence of rows by a \Range:
+ # # Get rows.
+ # table[1..2] # => [#<CSV::Row "Name":"bam" "Value":3>, #<CSV::Row "Name":"baz" "Value":"2">]
+ # # Set rows, then get them.
+ # table[1..2] = [
+ # CSV::Row.new(['Name', 'Value'], ['bat', 4]),
+ # CSV::Row.new(['Name', 'Value'], ['bad', 5]),
+ # ]
+ # table[1..2] # => [["Name", #<CSV::Row "Name":"bat" "Value":4>], ["Value", #<CSV::Row "Name":"bad" "Value":5>]]
+ #
+ # === Column Mode
+ #
+ # Set a table to column mode with method #by_col!:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.by_col! # => #<CSV::Table mode:col row_count:4>
+ #
+ # Specify a column by an \Integer index:
+ # # Get a column.
+ # table[0]
+ # # Set a column, then get it.
+ # table[0] = ['FOO', 'BAR', 'BAZ']
+ # table[0] # => ["FOO", "BAR", "BAZ"]
+ #
+ # Specify a column by its \String header:
+ # # Get a column.
+ # table['Name'] # => ["FOO", "BAR", "BAZ"]
+ # # Set a column, then get it.
+ # table['Name'] = ['Foo', 'Bar', 'Baz']
+ # table['Name'] # => ["Foo", "Bar", "Baz"]
+ #
+ # === Mixed Mode
+ #
+ # In mixed mode, you can refer to either rows or columns:
+ # - An \Integer index refers to a row.
+ # - A \Range index refers to multiple rows.
+ # - A \String index refers to a column.
+ #
+ # Set a table to mixed mode with method #by_col_or_row!:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>
+ #
+ # Specify a single row by an \Integer index:
+ # # Get a row.
+ # table[1] # => #<CSV::Row "Name":"bar" "Value":"1">
+ # # Set a row, then get it.
+ # table[1] = CSV::Row.new(['Name', 'Value'], ['bam', 3])
+ # table[1] # => #<CSV::Row "Name":"bam" "Value":3>
+ #
+ # Specify a sequence of rows by a \Range:
+ # # Get rows.
+ # table[1..2] # => [#<CSV::Row "Name":"bam" "Value":3>, #<CSV::Row "Name":"baz" "Value":"2">]
+ # # Set rows, then get them.
+ # table[1] = CSV::Row.new(['Name', 'Value'], ['bat', 4])
+ # table[2] = CSV::Row.new(['Name', 'Value'], ['bad', 5])
+ # table[1..2] # => [["Name", #<CSV::Row "Name":"bat" "Value":4>], ["Value", #<CSV::Row "Name":"bad" "Value":5>]]
+ #
+ # Specify a column by its \String header:
+ # # Get a column.
+ # table['Name'] # => ["foo", "bat", "bad"]
+ # # Set a column, then get it.
+ # table['Name'] = ['Foo', 'Bar', 'Baz']
+ # table['Name'] # => ["Foo", "Bar", "Baz"]
+ class Table
+ # :call-seq:
+ # CSV::Table.new(array_of_rows, headers = nil) -> csv_table
+ #
+ # Returns a new \CSV::Table object.
+ #
+ # - Argument +array_of_rows+ must be an \Array of CSV::Row objects.
+ # - Argument +headers+, if given, may be an \Array of Strings.
+ #
+ # ---
+ #
+ # Create an empty \CSV::Table object:
+ # table = CSV::Table.new([])
+ # table # => #<CSV::Table mode:col_or_row row_count:1>
+ #
+ # Create a non-empty \CSV::Table object:
+ # rows = [
+ # CSV::Row.new([], []),
+ # CSV::Row.new([], []),
+ # CSV::Row.new([], []),
+ # ]
+ # table = CSV::Table.new(rows)
+ # table # => #<CSV::Table mode:col_or_row row_count:4>
+ #
+ # ---
+ #
+ # If argument +headers+ is an \Array of Strings,
+ # those Strings become the table's headers:
+ # table = CSV::Table.new([], headers: ['Name', 'Age'])
+ # table.headers # => ["Name", "Age"]
+ #
+ # If argument +headers+ is not given and the table has rows,
+ # the headers are taken from the first row:
+ # rows = [
+ # CSV::Row.new(['Foo', 'Bar'], []),
+ # CSV::Row.new(['foo', 'bar'], []),
+ # CSV::Row.new(['FOO', 'BAR'], []),
+ # ]
+ # table = CSV::Table.new(rows)
+ # table.headers # => ["Foo", "Bar"]
+ #
+ # If argument +headers+ is not given and the table is empty (has no rows),
+ # the headers are also empty:
+ # table = CSV::Table.new([])
+ # table.headers # => []
+ #
+ # ---
+ #
+ # Raises an exception if argument +array_of_rows+ is not an \Array object:
+ # # Raises NoMethodError (undefined method `first' for :foo:Symbol):
+ # CSV::Table.new(:foo)
+ #
+ # Raises an exception if an element of +array_of_rows+ is not a \CSV::Table object:
+ # # Raises NoMethodError (undefined method `headers' for :foo:Symbol):
+ # CSV::Table.new([:foo])
+ def initialize(array_of_rows, headers: nil)
+ @table = array_of_rows
+ @headers = headers
+ unless @headers
+ if @table.empty?
+ @headers = []
+ else
+ @headers = @table.first.headers
+ end
+ end
+
+ @mode = :col_or_row
+ end
+
+ # The current access mode for indexing and iteration.
+ attr_reader :mode
+
+ # Internal data format used to compare equality.
+ attr_reader :table
+ protected :table
+
+ ### Array Delegation ###
+
+ extend Forwardable
+ def_delegators :@table, :empty?, :length, :size
+
+ # :call-seq:
+ # table.by_col -> table_dup
+ #
+ # Returns a duplicate of +self+, in column mode
+ # (see {Column Mode}[#class-CSV::Table-label-Column+Mode]):
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.mode # => :col_or_row
+ # dup_table = table.by_col
+ # dup_table.mode # => :col
+ # dup_table.equal?(table) # => false # It's a dup
+ #
+ # This may be used to chain method calls without changing the mode
+ # (but also will affect performance and memory usage):
+ # dup_table.by_col['Name']
+ #
+ # Also note that changes to the duplicate table will not affect the original.
+ def by_col
+ self.class.new(@table.dup).by_col!
+ end
+
+ # :call-seq:
+ # table.by_col! -> self
+ #
+ # Sets the mode for +self+ to column mode
+ # (see {Column Mode}[#class-CSV::Table-label-Column+Mode]); returns +self+:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.mode # => :col_or_row
+ # table1 = table.by_col!
+ # table.mode # => :col
+ # table1.equal?(table) # => true # Returned self
+ def by_col!
+ @mode = :col
+
+ self
+ end
+
+ # :call-seq:
+ # table.by_col_or_row -> table_dup
+ #
+ # Returns a duplicate of +self+, in mixed mode
+ # (see {Mixed Mode}[#class-CSV::Table-label-Mixed+Mode]):
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true).by_col!
+ # table.mode # => :col
+ # dup_table = table.by_col_or_row
+ # dup_table.mode # => :col_or_row
+ # dup_table.equal?(table) # => false # It's a dup
+ #
+ # This may be used to chain method calls without changing the mode
+ # (but also will affect performance and memory usage):
+ # dup_table.by_col_or_row['Name']
+ #
+ # Also note that changes to the duplicate table will not affect the original.
+ def by_col_or_row
+ self.class.new(@table.dup).by_col_or_row!
+ end
+
+ # :call-seq:
+ # table.by_col_or_row! -> self
+ #
+ # Sets the mode for +self+ to mixed mode
+ # (see {Mixed Mode}[#class-CSV::Table-label-Mixed+Mode]); returns +self+:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true).by_col!
+ # table.mode # => :col
+ # table1 = table.by_col_or_row!
+ # table.mode # => :col_or_row
+ # table1.equal?(table) # => true # Returned self
+ def by_col_or_row!
+ @mode = :col_or_row
+
+ self
+ end
+
+ # :call-seq:
+ # table.by_row -> table_dup
+ #
+ # Returns a duplicate of +self+, in row mode
+ # (see {Row Mode}[#class-CSV::Table-label-Row+Mode]):
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.mode # => :col_or_row
+ # dup_table = table.by_row
+ # dup_table.mode # => :row
+ # dup_table.equal?(table) # => false # It's a dup
+ #
+ # This may be used to chain method calls without changing the mode
+ # (but also will affect performance and memory usage):
+ # dup_table.by_row[1]
+ #
+ # Also note that changes to the duplicate table will not affect the original.
+ def by_row
+ self.class.new(@table.dup).by_row!
+ end
+
+ # :call-seq:
+ # table.by_row! -> self
+ #
+ # Sets the mode for +self+ to row mode
+ # (see {Row Mode}[#class-CSV::Table-label-Row+Mode]); returns +self+:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.mode # => :col_or_row
+ # table1 = table.by_row!
+ # table.mode # => :row
+ # table1.equal?(table) # => true # Returned self
+ def by_row!
+ @mode = :row
+
+ self
+ end
+
+ # :call-seq:
+ # table.headers -> array_of_headers
+ #
+ # Returns a new \Array containing the \String headers for the table.
+ #
+ # If the table is not empty, returns the headers from the first row:
+ # rows = [
+ # CSV::Row.new(['Foo', 'Bar'], []),
+ # CSV::Row.new(['FOO', 'BAR'], []),
+ # CSV::Row.new(['foo', 'bar'], []),
+ # ]
+ # table = CSV::Table.new(rows)
+ # table.headers # => ["Foo", "Bar"]
+ # table.delete(0)
+ # table.headers # => ["FOO", "BAR"]
+ # table.delete(0)
+ # table.headers # => ["foo", "bar"]
+ #
+ # If the table is empty, returns a copy of the headers in the table itself:
+ # table.delete(0)
+ # table.headers # => ["Foo", "Bar"]
+ def headers
+ if @table.empty?
+ @headers.dup
+ else
+ @table.first.headers
+ end
+ end
+
+ # :call-seq:
+ # table[n] -> row or column_data
+ # table[range] -> array_of_rows or array_of_column_data
+ # table[header] -> array_of_column_data
+ #
+ # Returns data from the table; does not modify the table.
+ #
+ # ---
+ #
+ # Fetch a \Row by Its \Integer Index::
+ # - Form: <tt>table[n]</tt>, +n+ an integer.
+ # - Access mode: <tt>:row</tt> or <tt>:col_or_row</tt>.
+ # - Return value: _nth_ row of the table, if that row exists;
+ # otherwise +nil+.
+ #
+ # Returns the _nth_ row of the table if that row exists:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
+ # table[1] # => #<CSV::Row "Name":"bar" "Value":"1">
+ # table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>
+ # table[1] # => #<CSV::Row "Name":"bar" "Value":"1">
+ #
+ # Counts backward from the last row if +n+ is negative:
+ # table[-1] # => #<CSV::Row "Name":"baz" "Value":"2">
+ #
+ # Returns +nil+ if +n+ is too large or too small:
+ # table[4] # => nil
+ # table[-4] # => nil
+ #
+ # Raises an exception if the access mode is <tt>:row</tt>
+ # and +n+ is not an \Integer:
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
+ # # Raises TypeError (no implicit conversion of String into Integer):
+ # table['Name']
+ #
+ # ---
+ #
+ # Fetch a Column by Its \Integer Index::
+ # - Form: <tt>table[n]</tt>, +n+ an \Integer.
+ # - Access mode: <tt>:col</tt>.
+ # - Return value: _nth_ column of the table, if that column exists;
+ # otherwise an \Array of +nil+ fields of length <tt>self.size</tt>.
+ #
+ # Returns the _nth_ column of the table if that column exists:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.by_col! # => #<CSV::Table mode:col row_count:4>
+ # table[1] # => ["0", "1", "2"]
+ #
+ # Counts backward from the last column if +n+ is negative:
+ # table[-2] # => ["foo", "bar", "baz"]
+ #
+ # Returns an \Array of +nil+ fields if +n+ is too large or too small:
+ # table[4] # => [nil, nil, nil]
+ # table[-4] # => [nil, nil, nil]
+ #
+ # ---
+ #
+ # Fetch Rows by \Range::
+ # - Form: <tt>table[range]</tt>, +range+ a \Range object.
+ # - Access mode: <tt>:row</tt> or <tt>:col_or_row</tt>.
+ # - Return value: rows from the table, beginning at row <tt>range.start</tt>,
+ # if those rows exists.
+ #
+ # Returns rows from the table, beginning at row <tt>range.first</tt>,
+ # if those rows exist:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
+ # rows = table[1..2] # => #<CSV::Row "Name":"bar" "Value":"1">
+ # rows # => [#<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]
+ # table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>
+ # rows = table[1..2] # => #<CSV::Row "Name":"bar" "Value":"1">
+ # rows # => [#<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]
+ #
+ # If there are too few rows, returns all from <tt>range.start</tt> to the end:
+ # rows = table[1..50] # => #<CSV::Row "Name":"bar" "Value":"1">
+ # rows # => [#<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]
+ #
+ # Special case: if <tt>range.start == table.size</tt>, returns an empty \Array:
+ # table[table.size..50] # => []
+ #
+ # If <tt>range.end</tt> is negative, calculates the ending index from the end:
+ # rows = table[0..-1]
+ # rows # => [#<CSV::Row "Name":"foo" "Value":"0">, #<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]
+ #
+ # If <tt>range.start</tt> is negative, calculates the starting index from the end:
+ # rows = table[-1..2]
+ # rows # => [#<CSV::Row "Name":"baz" "Value":"2">]
+ #
+ # If <tt>range.start</tt> is larger than <tt>table.size</tt>, returns +nil+:
+ # table[4..4] # => nil
+ #
+ # ---
+ #
+ # Fetch Columns by \Range::
+ # - Form: <tt>table[range]</tt>, +range+ a \Range object.
+ # - Access mode: <tt>:col</tt>.
+ # - Return value: column data from the table, beginning at column <tt>range.start</tt>,
+ # if those columns exist.
+ #
+ # Returns column values from the table, if the column exists;
+ # the values are arranged by row:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.by_col!
+ # table[0..1] # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+ #
+ # Special case: if <tt>range.start == headers.size</tt>,
+ # returns an \Array (size: <tt>table.size</tt>) of empty \Arrays:
+ # table[table.headers.size..50] # => [[], [], []]
+ #
+ # If <tt>range.end</tt> is negative, calculates the ending index from the end:
+ # table[0..-1] # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+ #
+ # If <tt>range.start</tt> is negative, calculates the starting index from the end:
+ # table[-2..2] # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
+ #
+ # If <tt>range.start</tt> is larger than <tt>table.size</tt>,
+ # returns an \Array of +nil+ values:
+ # table[4..4] # => [nil, nil, nil]
+ #
+ # ---
+ #
+ # Fetch a Column by Its \String Header::
+ # - Form: <tt>table[header]</tt>, +header+ a \String header.
+ # - Access mode: <tt>:col</tt> or <tt>:col_or_row</tt>
+ # - Return value: column data from the table, if that +header+ exists.
+ #
+ # Returns column values from the table, if the column exists:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.by_col! # => #<CSV::Table mode:col row_count:4>
+ # table['Name'] # => ["foo", "bar", "baz"]
+ # table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>
+ # col = table['Name']
+ # col # => ["foo", "bar", "baz"]
+ #
+ # Modifying the returned column values does not modify the table:
+ # col[0] = 'bat'
+ # col # => ["bat", "bar", "baz"]
+ # table['Name'] # => ["foo", "bar", "baz"]
+ #
+ # Returns an \Array of +nil+ values if there is no such column:
+ # table['Nosuch'] # => [nil, nil, nil]
+ def [](index_or_header)
+ if @mode == :row or # by index
+ (@mode == :col_or_row and (index_or_header.is_a?(Integer) or index_or_header.is_a?(Range)))
+ @table[index_or_header]
+ else # by header
+ @table.map { |row| row[index_or_header] }
+ end
+ end
+
+ # :call-seq:
+ # table[n] = row -> row
+ # table[n] = field_or_array_of_fields -> field_or_array_of_fields
+ # table[header] = field_or_array_of_fields -> field_or_array_of_fields
+ #
+ # Puts data onto the table.
+ #
+ # ---
+ #
+ # Set a \Row by Its \Integer Index::
+ # - Form: <tt>table[n] = row</tt>, +n+ an \Integer,
+ # +row+ a \CSV::Row instance or an \Array of fields.
+ # - Access mode: <tt>:row</tt> or <tt>:col_or_row</tt>.
+ # - Return value: +row+.
+ #
+ # If the row exists, it is replaced:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # new_row = CSV::Row.new(['Name', 'Value'], ['bat', 3])
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
+ # return_value = table[0] = new_row
+ # return_value.equal?(new_row) # => true # Returned the row
+ # table[0].to_h # => {"Name"=>"bat", "Value"=>3}
+ #
+ # With access mode <tt>:col_or_row</tt>:
+ # table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>
+ # table[0] = CSV::Row.new(['Name', 'Value'], ['bam', 4])
+ # table[0].to_h # => {"Name"=>"bam", "Value"=>4}
+ #
+ # With an \Array instead of a \CSV::Row, inherits headers from the table:
+ # array = ['bad', 5]
+ # return_value = table[0] = array
+ # return_value.equal?(array) # => true # Returned the array
+ # table[0].to_h # => {"Name"=>"bad", "Value"=>5}
+ #
+ # If the row does not exist, extends the table by adding rows:
+ # assigns rows with +nil+ as needed:
+ # table.size # => 3
+ # table[5] = ['bag', 6]
+ # table.size # => 6
+ # table[3] # => nil
+ # table[4]# => nil
+ # table[5].to_h # => {"Name"=>"bag", "Value"=>6}
+ #
+ # Note that the +nil+ rows are actually +nil+, not a row of +nil+ fields.
+ #
+ # ---
+ #
+ # Set a Column by Its \Integer Index::
+ # - Form: <tt>table[n] = array_of_fields</tt>, +n+ an \Integer,
+ # +array_of_fields+ an \Array of \String fields.
+ # - Access mode: <tt>:col</tt>.
+ # - Return value: +array_of_fields+.
+ #
+ # If the column exists, it is replaced:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # new_col = [3, 4, 5]
+ # table.by_col! # => #<CSV::Table mode:col row_count:4>
+ # return_value = table[1] = new_col
+ # return_value.equal?(new_col) # => true # Returned the column
+ # table[1] # => [3, 4, 5]
+ # # The rows, as revised:
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
+ # table[0].to_h # => {"Name"=>"foo", "Value"=>3}
+ # table[1].to_h # => {"Name"=>"bar", "Value"=>4}
+ # table[2].to_h # => {"Name"=>"baz", "Value"=>5}
+ # table.by_col! # => #<CSV::Table mode:col row_count:4>
+ #
+ # If there are too few values, fills with +nil+ values:
+ # table[1] = [0]
+ # table[1] # => [0, nil, nil]
+ #
+ # If there are too many values, ignores the extra values:
+ # table[1] = [0, 1, 2, 3, 4]
+ # table[1] # => [0, 1, 2]
+ #
+ # If a single value is given, replaces all fields in the column with that value:
+ # table[1] = 'bat'
+ # table[1] # => ["bat", "bat", "bat"]
+ #
+ # ---
+ #
+ # Set a Column by Its \String Header::
+ # - Form: <tt>table[header] = field_or_array_of_fields</tt>,
+ # +header+ a \String header, +field_or_array_of_fields+ a field value
+ # or an \Array of \String fields.
+ # - Access mode: <tt>:col</tt> or <tt>:col_or_row</tt>.
+ # - Return value: +field_or_array_of_fields+.
+ #
+ # If the column exists, it is replaced:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # new_col = [3, 4, 5]
+ # table.by_col! # => #<CSV::Table mode:col row_count:4>
+ # return_value = table['Value'] = new_col
+ # return_value.equal?(new_col) # => true # Returned the column
+ # table['Value'] # => [3, 4, 5]
+ # # The rows, as revised:
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
+ # table[0].to_h # => {"Name"=>"foo", "Value"=>3}
+ # table[1].to_h # => {"Name"=>"bar", "Value"=>4}
+ # table[2].to_h # => {"Name"=>"baz", "Value"=>5}
+ # table.by_col! # => #<CSV::Table mode:col row_count:4>
+ #
+ # If there are too few values, fills with +nil+ values:
+ # table['Value'] = [0]
+ # table['Value'] # => [0, nil, nil]
+ #
+ # If there are too many values, ignores the extra values:
+ # table['Value'] = [0, 1, 2, 3, 4]
+ # table['Value'] # => [0, 1, 2]
+ #
+ # If the column does not exist, extends the table by adding columns:
+ # table['Note'] = ['x', 'y', 'z']
+ # table['Note'] # => ["x", "y", "z"]
+ # # The rows, as revised:
+ # table.by_row!
+ # table[0].to_h # => {"Name"=>"foo", "Value"=>0, "Note"=>"x"}
+ # table[1].to_h # => {"Name"=>"bar", "Value"=>1, "Note"=>"y"}
+ # table[2].to_h # => {"Name"=>"baz", "Value"=>2, "Note"=>"z"}
+ # table.by_col!
+ #
+ # If a single value is given, replaces all fields in the column with that value:
+ # table['Value'] = 'bat'
+ # table['Value'] # => ["bat", "bat", "bat"]
+ def []=(index_or_header, value)
+ if @mode == :row or # by index
+ (@mode == :col_or_row and index_or_header.is_a? Integer)
+ if value.is_a? Array
+ @table[index_or_header] = Row.new(headers, value)
+ else
+ @table[index_or_header] = value
+ end
+ else # set column
+ unless index_or_header.is_a? Integer
+ index = @headers.index(index_or_header) || @headers.size
+ @headers[index] = index_or_header
+ end
+ if value.is_a? Array # multiple values
+ @table.each_with_index do |row, i|
+ if row.header_row?
+ row[index_or_header] = index_or_header
+ else
+ row[index_or_header] = value[i]
+ end
+ end
+ else # repeated value
+ @table.each do |row|
+ if row.header_row?
+ row[index_or_header] = index_or_header
+ else
+ row[index_or_header] = value
+ end
+ end
+ end
+ end
+ end
+
+ # :call-seq:
+ # table.values_at(*indexes) -> array_of_rows
+ # table.values_at(*headers) -> array_of_columns_data
+ #
+ # If the access mode is <tt>:row</tt> or <tt>:col_or_row</tt>,
+ # and each argument is either an \Integer or a \Range,
+ # returns rows.
+ # Otherwise, returns columns data.
+ #
+ # In either case, the returned values are in the order
+ # specified by the arguments. Arguments may be repeated.
+ #
+ # ---
+ #
+ # Returns rows as an \Array of \CSV::Row objects.
+ #
+ # No argument:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.values_at # => []
+ #
+ # One index:
+ # values = table.values_at(0)
+ # values # => [#<CSV::Row "Name":"foo" "Value":"0">]
+ #
+ # Two indexes:
+ # values = table.values_at(2, 0)
+ # values # => [#<CSV::Row "Name":"baz" "Value":"2">, #<CSV::Row "Name":"foo" "Value":"0">]
+ #
+ # One \Range:
+ # values = table.values_at(1..2)
+ # values # => [#<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]
+ #
+ # \Ranges and indexes:
+ # values = table.values_at(0..1, 1..2, 0, 2)
+ # pp values
+ # Output:
+ # [#<CSV::Row "Name":"foo" "Value":"0">,
+ # #<CSV::Row "Name":"bar" "Value":"1">,
+ # #<CSV::Row "Name":"bar" "Value":"1">,
+ # #<CSV::Row "Name":"baz" "Value":"2">,
+ # #<CSV::Row "Name":"foo" "Value":"0">,
+ # #<CSV::Row "Name":"baz" "Value":"2">]
+ #
+ # ---
+ #
+ # Returns columns data as row Arrays,
+ # each consisting of the specified columns data for that row:
+ # values = table.values_at('Name')
+ # values # => [["foo"], ["bar"], ["baz"]]
+ # values = table.values_at('Value', 'Name')
+ # values # => [["0", "foo"], ["1", "bar"], ["2", "baz"]]
+ def values_at(*indices_or_headers)
+ if @mode == :row or # by indices
+ ( @mode == :col_or_row and indices_or_headers.all? do |index|
+ index.is_a?(Integer) or
+ ( index.is_a?(Range) and
+ index.first.is_a?(Integer) and
+ index.last.is_a?(Integer) )
+ end )
+ @table.values_at(*indices_or_headers)
+ else # by headers
+ @table.map { |row| row.values_at(*indices_or_headers) }
+ end
+ end
+
+ # :call-seq:
+ # table << row_or_array -> self
+ #
+ # If +row_or_array+ is a \CSV::Row object,
+ # it is appended to the table:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table << CSV::Row.new(table.headers, ['bat', 3])
+ # table[3] # => #<CSV::Row "Name":"bat" "Value":3>
+ #
+ # If +row_or_array+ is an \Array, it is used to create a new
+ # \CSV::Row object which is then appended to the table:
+ # table << ['bam', 4]
+ # table[4] # => #<CSV::Row "Name":"bam" "Value":4>
+ def <<(row_or_array)
+ if row_or_array.is_a? Array # append Array
+ @table << Row.new(headers, row_or_array)
+ else # append Row
+ @table << row_or_array
+ end
+
+ self # for chaining
+ end
+
+ #
+ # :call-seq:
+ # table.push(*rows_or_arrays) -> self
+ #
+ # A shortcut for appending multiple rows. Equivalent to:
+ # rows.each {|row| self << row }
+ #
+ # Each argument may be either a \CSV::Row object or an \Array:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # rows = [
+ # CSV::Row.new(table.headers, ['bat', 3]),
+ # ['bam', 4]
+ # ]
+ # table.push(*rows)
+ # table[3..4] # => [#<CSV::Row "Name":"bat" "Value":3>, #<CSV::Row "Name":"bam" "Value":4>]
+ def push(*rows)
+ rows.each { |row| self << row }
+
+ self # for chaining
+ end
+
+ # :call-seq:
+ # table.delete(*indexes) -> deleted_values
+ # table.delete(*headers) -> deleted_values
+ #
+ # If the access mode is <tt>:row</tt> or <tt>:col_or_row</tt>,
+ # and each argument is either an \Integer or a \Range,
+ # returns deleted rows.
+ # Otherwise, returns deleted columns data.
+ #
+ # In either case, the returned values are in the order
+ # specified by the arguments. Arguments may be repeated.
+ #
+ # ---
+ #
+ # Returns rows as an \Array of \CSV::Row objects.
+ #
+ # One index:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # deleted_values = table.delete(0)
+ # deleted_values # => [#<CSV::Row "Name":"foo" "Value":"0">]
+ #
+ # Two indexes:
+ # table = CSV.parse(source, headers: true)
+ # deleted_values = table.delete(2, 0)
+ # deleted_values # => [#<CSV::Row "Name":"baz" "Value":"2">, #<CSV::Row "Name":"foo" "Value":"0">]
+ #
+ # ---
+ #
+ # Returns columns data as column Arrays.
+ #
+ # One header:
+ # table = CSV.parse(source, headers: true)
+ # deleted_values = table.delete('Name')
+ # deleted_values # => ["foo", "bar", "baz"]
+ #
+ # Two headers:
+ # table = CSV.parse(source, headers: true)
+ # deleted_values = table.delete('Value', 'Name')
+ # deleted_values # => [["0", "1", "2"], ["foo", "bar", "baz"]]
+ def delete(*indexes_or_headers)
+ if indexes_or_headers.empty?
+ raise ArgumentError, "wrong number of arguments (given 0, expected 1+)"
+ end
+ deleted_values = indexes_or_headers.map do |index_or_header|
+ if @mode == :row or # by index
+ (@mode == :col_or_row and index_or_header.is_a? Integer)
+ @table.delete_at(index_or_header)
+ else # by header
+ if index_or_header.is_a? Integer
+ @headers.delete_at(index_or_header)
+ else
+ @headers.delete(index_or_header)
+ end
+ @table.map { |row| row.delete(index_or_header).last }
+ end
+ end
+ if indexes_or_headers.size == 1
+ deleted_values[0]
+ else
+ deleted_values
+ end
+ end
+
+ # :call-seq:
+ # table.delete_if {|row_or_column| ... } -> self
+ #
+ # Removes rows or columns for which the block returns a truthy value;
+ # returns +self+.
+ #
+ # Removes rows when the access mode is <tt>:row</tt> or <tt>:col_or_row</tt>;
+ # calls the block with each \CSV::Row object:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
+ # table.size # => 3
+ # table.delete_if {|row| row['Name'].start_with?('b') }
+ # table.size # => 1
+ #
+ # Removes columns when the access mode is <tt>:col</tt>;
+ # calls the block with each column as a 2-element array
+ # containing the header and an \Array of column fields:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.by_col! # => #<CSV::Table mode:col row_count:4>
+ # table.headers.size # => 2
+ # table.delete_if {|column_data| column_data[1].include?('2') }
+ # table.headers.size # => 1
+ #
+ # Returns a new \Enumerator if no block is given:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.delete_if # => #<Enumerator: #<CSV::Table mode:col_or_row row_count:4>:delete_if>
+ def delete_if(&block)
+ return enum_for(__method__) { @mode == :row or @mode == :col_or_row ? size : headers.size } unless block_given?
+
+ if @mode == :row or @mode == :col_or_row # by index
+ @table.delete_if(&block)
+ else # by header
+ headers.each do |header|
+ delete(header) if yield([header, self[header]])
+ end
+ end
+
+ self # for chaining
+ end
+
+ include Enumerable
+
+ # :call-seq:
+ # table.each {|row_or_column| ... ) -> self
+ #
+ # Calls the block with each row or column; returns +self+.
+ #
+ # When the access mode is <tt>:row</tt> or <tt>:col_or_row</tt>,
+ # calls the block with each \CSV::Row object:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
+ # table.each {|row| p row }
+ # Output:
+ # #<CSV::Row "Name":"foo" "Value":"0">
+ # #<CSV::Row "Name":"bar" "Value":"1">
+ # #<CSV::Row "Name":"baz" "Value":"2">
+ #
+ # When the access mode is <tt>:col</tt>,
+ # calls the block with each column as a 2-element array
+ # containing the header and an \Array of column fields:
+ # table.by_col! # => #<CSV::Table mode:col row_count:4>
+ # table.each {|column_data| p column_data }
+ # Output:
+ # ["Name", ["foo", "bar", "baz"]]
+ # ["Value", ["0", "1", "2"]]
+ #
+ # Returns a new \Enumerator if no block is given:
+ # table.each # => #<Enumerator: #<CSV::Table mode:col row_count:4>:each>
+ def each(&block)
+ return enum_for(__method__) { @mode == :col ? headers.size : size } unless block_given?
+
+ if @mode == :col
+ headers.each.with_index do |header, i|
+ yield([header, @table.map {|row| row[header, i]}])
+ end
+ else
+ @table.each(&block)
+ end
+
+ self # for chaining
+ end
+
+ # :call-seq:
+ # table == other_table -> true or false
+ #
+ # Returns +true+ if all each row of +self+ <tt>==</tt>
+ # the corresponding row of +other_table+, otherwise, +false+.
+ #
+ # The access mode does no affect the result.
+ #
+ # Equal tables:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # other_table = CSV.parse(source, headers: true)
+ # table == other_table # => true
+ #
+ # Different row count:
+ # other_table.delete(2)
+ # table == other_table # => false
+ #
+ # Different last row:
+ # other_table << ['bat', 3]
+ # table == other_table # => false
+ def ==(other)
+ return @table == other.table if other.is_a? CSV::Table
+ @table == other
+ end
+
+ # :call-seq:
+ # table.to_a -> array_of_arrays
+ #
+ # Returns the table as an \Array of \Arrays;
+ # the headers are in the first row:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.to_a # => [["Name", "Value"], ["foo", "0"], ["bar", "1"], ["baz", "2"]]
+ def to_a
+ array = [headers]
+ @table.each do |row|
+ array.push(row.fields) unless row.header_row?
+ end
+
+ array
+ end
+
+ # :call-seq:
+ # table.to_csv(**options) -> csv_string
+ #
+ # Returns the table as \CSV string.
+ # See {Options for Generating}[../CSV.html#class-CSV-label-Options+for+Generating].
+ #
+ # Defaults option +write_headers+ to +true+:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.to_csv # => "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ #
+ # Omits the headers if option +write_headers+ is given as +false+
+ # (see {Option +write_headers+}[../CSV.html#class-CSV-label-Option+write_headers]):
+ # table.to_csv(write_headers: false) # => "foo,0\nbar,1\nbaz,2\n"
+ #
+ # Limit rows if option +limit+ is given like +2+:
+ # table.to_csv(limit: 2) # => "Name,Value\nfoo,0\nbar,1\n"
+ def to_csv(write_headers: true, limit: nil, **options)
+ array = write_headers ? [headers.to_csv(**options)] : []
+ limit ||= @table.size
+ limit = @table.size + 1 + limit if limit < 0
+ limit = 0 if limit < 0
+ @table.first(limit).each do |row|
+ array.push(row.fields.to_csv(**options)) unless row.header_row?
+ end
+
+ array.join("")
+ end
+ alias_method :to_s, :to_csv
+
+ #
+ # Extracts the nested value specified by the sequence of +index+ or +header+ objects by calling dig at each step,
+ # returning nil if any intermediate step is nil.
+ #
+ def dig(index_or_header, *index_or_headers)
+ value = self[index_or_header]
+ if value.nil?
+ nil
+ elsif index_or_headers.empty?
+ value
+ else
+ unless value.respond_to?(:dig)
+ raise TypeError, "#{value.class} does not have \#dig method"
+ end
+ value.dig(*index_or_headers)
+ end
+ end
+
+ # :call-seq:
+ # table.inspect => string
+ #
+ # Returns a <tt>US-ASCII</tt>-encoded \String showing table:
+ # - Class: <tt>CSV::Table</tt>.
+ # - Access mode: <tt>:row</tt>, <tt>:col</tt>, or <tt>:col_or_row</tt>.
+ # - Size: Row count, including the header row.
+ #
+ # Example:
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
+ # table = CSV.parse(source, headers: true)
+ # table.inspect # => "#<CSV::Table mode:col_or_row row_count:4>\nName,Value\nfoo,0\nbar,1\nbaz,2\n"
+ #
+ def inspect
+ inspected = +"#<#{self.class} mode:#{@mode} row_count:#{to_a.size}>"
+ summary = to_csv(limit: 5)
+ inspected << "\n" << summary if summary.encoding.ascii_compatible?
+ inspected
+ end
+ end
+end
diff --git a/lib/csv/version.rb b/lib/csv/version.rb
new file mode 100644
index 0000000000..e05d63d801
--- /dev/null
+++ b/lib/csv/version.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+class CSV
+ # The version of the installed library.
+ VERSION = "3.2.6"
+end
diff --git a/lib/csv/writer.rb b/lib/csv/writer.rb
new file mode 100644
index 0000000000..030a295bc9
--- /dev/null
+++ b/lib/csv/writer.rb
@@ -0,0 +1,210 @@
+# frozen_string_literal: true
+
+require_relative "input_record_separator"
+require_relative "row"
+
+class CSV
+ # Note: Don't use this class directly. This is an internal class.
+ class Writer
+ #
+ # A CSV::Writer receives an output, prepares the header, format and output.
+ # It allows us to write new rows in the object and rewind it.
+ #
+ attr_reader :lineno
+ attr_reader :headers
+
+ def initialize(output, options)
+ @output = output
+ @options = options
+ @lineno = 0
+ @fields_converter = nil
+ prepare
+ if @options[:write_headers] and @headers
+ self << @headers
+ end
+ @fields_converter = @options[:fields_converter]
+ end
+
+ #
+ # Adds a new row
+ #
+ def <<(row)
+ case row
+ when Row
+ row = row.fields
+ when Hash
+ row = @headers.collect {|header| row[header]}
+ end
+
+ @headers ||= row if @use_headers
+ @lineno += 1
+
+ if @fields_converter
+ quoted_fields = [false] * row.size
+ row = @fields_converter.convert(row, nil, lineno, quoted_fields)
+ end
+
+ i = -1
+ converted_row = row.collect do |field|
+ i += 1
+ quote(field, i)
+ end
+ line = converted_row.join(@column_separator) + @row_separator
+ if @output_encoding
+ line = line.encode(@output_encoding)
+ end
+ @output << line
+
+ self
+ end
+
+ #
+ # Winds back to the beginning
+ #
+ def rewind
+ @lineno = 0
+ @headers = nil if @options[:headers].nil?
+ end
+
+ private
+ def prepare
+ @encoding = @options[:encoding]
+
+ prepare_header
+ prepare_format
+ prepare_output
+ end
+
+ def prepare_header
+ headers = @options[:headers]
+ case headers
+ when Array
+ @headers = headers
+ @use_headers = true
+ when String
+ @headers = CSV.parse_line(headers,
+ col_sep: @options[:column_separator],
+ row_sep: @options[:row_separator],
+ quote_char: @options[:quote_character])
+ @use_headers = true
+ when true
+ @headers = nil
+ @use_headers = true
+ else
+ @headers = nil
+ @use_headers = false
+ end
+ return unless @headers
+
+ converter = @options[:header_fields_converter]
+ @headers = converter.convert(@headers, nil, 0, [])
+ @headers.each do |header|
+ header.freeze if header.is_a?(String)
+ end
+ end
+
+ def prepare_force_quotes_fields(force_quotes)
+ @force_quotes_fields = {}
+ force_quotes.each do |name_or_index|
+ case name_or_index
+ when Integer
+ index = name_or_index
+ @force_quotes_fields[index] = true
+ when String, Symbol
+ name = name_or_index.to_s
+ if @headers.nil?
+ message = ":headers is required when you use field name " +
+ "in :force_quotes: " +
+ "#{name_or_index.inspect}: #{force_quotes.inspect}"
+ raise ArgumentError, message
+ end
+ index = @headers.index(name)
+ next if index.nil?
+ @force_quotes_fields[index] = true
+ else
+ message = ":force_quotes element must be " +
+ "field index or field name: " +
+ "#{name_or_index.inspect}: #{force_quotes.inspect}"
+ raise ArgumentError, message
+ end
+ end
+ end
+
+ def prepare_format
+ @column_separator = @options[:column_separator].to_s.encode(@encoding)
+ row_separator = @options[:row_separator]
+ if row_separator == :auto
+ @row_separator = InputRecordSeparator.value.encode(@encoding)
+ else
+ @row_separator = row_separator.to_s.encode(@encoding)
+ end
+ @quote_character = @options[:quote_character]
+ force_quotes = @options[:force_quotes]
+ if force_quotes.is_a?(Array)
+ prepare_force_quotes_fields(force_quotes)
+ @force_quotes = false
+ elsif force_quotes
+ @force_quotes_fields = nil
+ @force_quotes = true
+ else
+ @force_quotes_fields = nil
+ @force_quotes = false
+ end
+ unless @force_quotes
+ @quotable_pattern =
+ Regexp.new("[\r\n".encode(@encoding) +
+ Regexp.escape(@column_separator) +
+ Regexp.escape(@quote_character.encode(@encoding)) +
+ "]".encode(@encoding))
+ end
+ @quote_empty = @options.fetch(:quote_empty, true)
+ end
+
+ def prepare_output
+ @output_encoding = nil
+ return unless @output.is_a?(StringIO)
+
+ output_encoding = @output.internal_encoding || @output.external_encoding
+ if @encoding != output_encoding
+ if @options[:force_encoding]
+ @output_encoding = output_encoding
+ else
+ compatible_encoding = Encoding.compatible?(@encoding, output_encoding)
+ if compatible_encoding
+ @output.set_encoding(compatible_encoding)
+ @output.seek(0, IO::SEEK_END)
+ end
+ end
+ end
+ end
+
+ def quote_field(field)
+ field = String(field)
+ encoded_quote_character = @quote_character.encode(field.encoding)
+ encoded_quote_character +
+ field.gsub(encoded_quote_character,
+ encoded_quote_character * 2) +
+ encoded_quote_character
+ end
+
+ def quote(field, i)
+ if @force_quotes
+ quote_field(field)
+ elsif @force_quotes_fields and @force_quotes_fields[i]
+ quote_field(field)
+ else
+ if field.nil? # represent +nil+ fields as empty unquoted fields
+ ""
+ else
+ field = String(field) # Stringify fields
+ # represent empty fields as empty quoted fields
+ if (@quote_empty and field.empty?) or (field.valid_encoding? and @quotable_pattern.match?(field))
+ quote_field(field)
+ else
+ field # unquoted field
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/delegate.gemspec b/lib/delegate.gemspec
deleted file mode 100644
index 6c3feac74b..0000000000
--- a/lib/delegate.gemspec
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{Provides three abilities to delegate method calls to an object.}
- spec.description = %q{Provides three abilities to delegate method calls to an object.}
- spec.homepage = "https://github.com/ruby/delegate"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
-
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.require_paths = ["lib"]
- spec.required_ruby_version = '>= 2.7'
-end
diff --git a/lib/delegate.rb b/lib/delegate.rb
index 1ea4fb985b..387a5f063d 100644
--- a/lib/delegate.rb
+++ b/lib/delegate.rb
@@ -39,7 +39,7 @@
# Be advised, RDoc will not detect delegated methods.
#
class Delegator < BasicObject
- VERSION = "0.3.1"
+ VERSION = "0.3.0"
kernel = ::Kernel.dup
kernel.class_eval do
@@ -186,7 +186,7 @@ class Delegator < BasicObject
# method calls are being delegated to.
#
def __getobj__
- __raise__ ::NotImplementedError, "need to define '__getobj__'"
+ __raise__ ::NotImplementedError, "need to define `__getobj__'"
end
#
@@ -194,7 +194,7 @@ class Delegator < BasicObject
# to _obj_.
#
def __setobj__(obj)
- __raise__ ::NotImplementedError, "need to define '__setobj__'"
+ __raise__ ::NotImplementedError, "need to define `__setobj__'"
end
#
diff --git a/lib/delegate/delegate.gemspec b/lib/delegate/delegate.gemspec
new file mode 100644
index 0000000000..1cfacfeb2f
--- /dev/null
+++ b/lib/delegate/delegate.gemspec
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{Provides three abilities to delegate method calls to an object.}
+ spec.description = %q{Provides three abilities to delegate method calls to an object.}
+ spec.homepage = "https://github.com/ruby/delegate"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.require_paths = ["lib"]
+ spec.required_ruby_version = '>= 2.7'
+end
diff --git a/lib/did_you_mean.rb b/lib/did_you_mean.rb
index e177665099..2df238da06 100644
--- a/lib/did_you_mean.rb
+++ b/lib/did_you_mean.rb
@@ -113,7 +113,7 @@ module DidYouMean
correct_error LoadError, RequirePathChecker if RUBY_VERSION >= '2.8.0'
correct_error NoMatchingPatternKeyError, PatternKeyNameChecker if defined?(::NoMatchingPatternKeyError)
- # TODO: Remove on the 3.4 development start:
+ # TODO: Remove on 3.3:
class DeprecatedMapping # :nodoc:
def []=(key, value)
warn "Calling `DidYouMean::SPELL_CHECKERS[#{key.to_s}] = #{value.to_s}' has been deprecated. " \
@@ -132,7 +132,7 @@ module DidYouMean
end
end
- # TODO: Remove on the 3.4 development start:
+ # TODO: Remove on 3.3:
SPELL_CHECKERS = DeprecatedMapping.new
deprecate_constant :SPELL_CHECKERS
private_constant :DeprecatedMapping
diff --git a/lib/did_you_mean/did_you_mean.gemspec b/lib/did_you_mean/did_you_mean.gemspec
index be4ac76b4b..8fe5723129 100644
--- a/lib/did_you_mean/did_you_mean.gemspec
+++ b/lib/did_you_mean/did_you_mean.gemspec
@@ -22,4 +22,6 @@ Gem::Specification.new do |spec|
spec.require_paths = ["lib"]
spec.required_ruby_version = '>= 2.5.0'
+
+ spec.add_development_dependency "rake"
end
diff --git a/lib/did_you_mean/jaro_winkler.rb b/lib/did_you_mean/jaro_winkler.rb
index 9a3e57f6d7..56db130af4 100644
--- a/lib/did_you_mean/jaro_winkler.rb
+++ b/lib/did_you_mean/jaro_winkler.rb
@@ -8,7 +8,8 @@ module DidYouMean
m = 0.0
t = 0.0
- range = length2 > 3 ? length2 / 2 - 1 : 0
+ range = (length2 / 2).floor - 1
+ range = 0 if range < 0
flags1 = 0
flags2 = 0
@@ -71,8 +72,10 @@ module DidYouMean
codepoints2 = str2.codepoints
prefix_bonus = 0
+ i = 0
str1.each_codepoint do |char1|
- char1 == codepoints2[prefix_bonus] && prefix_bonus < 4 ? prefix_bonus += 1 : break
+ char1 == codepoints2[i] && i < 4 ? prefix_bonus += 1 : break
+ i += 1
end
jaro_distance + (prefix_bonus * WEIGHT * (1 - jaro_distance))
diff --git a/lib/did_you_mean/spell_checkers/key_error_checker.rb b/lib/did_you_mean/spell_checkers/key_error_checker.rb
index 955bff1be6..be4bea7789 100644
--- a/lib/did_you_mean/spell_checkers/key_error_checker.rb
+++ b/lib/did_you_mean/spell_checkers/key_error_checker.rb
@@ -14,15 +14,7 @@ module DidYouMean
private
def exact_matches
- @exact_matches ||= @keys.select { |word| @key == word.to_s }.map { |obj| format_object(obj) }
- end
-
- def format_object(symbol_or_object)
- if symbol_or_object.is_a?(Symbol)
- ":#{symbol_or_object}"
- else
- symbol_or_object.to_s
- end
+ @exact_matches ||= @keys.select { |word| @key == word.to_s }.map(&:inspect)
end
end
end
diff --git a/lib/did_you_mean/spell_checkers/pattern_key_name_checker.rb b/lib/did_you_mean/spell_checkers/pattern_key_name_checker.rb
index 622d4dee25..ed263c8f93 100644
--- a/lib/did_you_mean/spell_checkers/pattern_key_name_checker.rb
+++ b/lib/did_you_mean/spell_checkers/pattern_key_name_checker.rb
@@ -14,15 +14,7 @@ module DidYouMean
private
def exact_matches
- @exact_matches ||= @keys.select { |word| @key == word.to_s }.map { |obj| format_object(obj) }
- end
-
- def format_object(symbol_or_object)
- if symbol_or_object.is_a?(Symbol)
- ":#{symbol_or_object}"
- else
- symbol_or_object.to_s
- end
+ @exact_matches ||= @keys.select { |word| @key == word.to_s }.map(&:inspect)
end
end
end
diff --git a/lib/drb.rb b/lib/drb.rb
new file mode 100644
index 0000000000..2bb4716fa2
--- /dev/null
+++ b/lib/drb.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: false
+require 'drb/drb'
+
diff --git a/lib/drb/acl.rb b/lib/drb/acl.rb
new file mode 100644
index 0000000000..b004656f09
--- /dev/null
+++ b/lib/drb/acl.rb
@@ -0,0 +1,239 @@
+# frozen_string_literal: false
+# Copyright (c) 2000,2002,2003 Masatoshi SEKI
+#
+# acl.rb is copyrighted free software by Masatoshi SEKI.
+# You can redistribute it and/or modify it under the same terms as Ruby.
+
+require 'ipaddr'
+
+##
+# Simple Access Control Lists.
+#
+# Access control lists are composed of "allow" and "deny" halves to control
+# access. Use "all" or "*" to match any address. To match a specific address
+# use any address or address mask that IPAddr can understand.
+#
+# Example:
+#
+# list = %w[
+# deny all
+# allow 192.168.1.1
+# allow ::ffff:192.168.1.2
+# allow 192.168.1.3
+# ]
+#
+# # From Socket#peeraddr, see also ACL#allow_socket?
+# addr = ["AF_INET", 10, "lc630", "192.168.1.3"]
+#
+# acl = ACL.new
+# p acl.allow_addr?(addr) # => true
+#
+# acl = ACL.new(list, ACL::DENY_ALLOW)
+# p acl.allow_addr?(addr) # => true
+
+class ACL
+
+ ##
+ # The current version of ACL
+
+ VERSION=["2.0.0"]
+
+ ##
+ # An entry in an ACL
+
+ class ACLEntry
+
+ ##
+ # Creates a new entry using +str+.
+ #
+ # +str+ may be "*" or "all" to match any address, an IP address string
+ # to match a specific address, an IP address mask per IPAddr, or one
+ # containing "*" to match part of an IPv4 address.
+ #
+ # IPAddr::InvalidPrefixError may be raised when an IP network
+ # address with an invalid netmask/prefix is given.
+
+ def initialize(str)
+ if str == '*' or str == 'all'
+ @pat = [:all]
+ elsif str.include?('*')
+ @pat = [:name, dot_pat(str)]
+ else
+ begin
+ @pat = [:ip, IPAddr.new(str)]
+ rescue IPAddr::InvalidPrefixError
+ # In this case, `str` shouldn't be a host name pattern
+ # because it contains a slash.
+ raise
+ rescue ArgumentError
+ @pat = [:name, dot_pat(str)]
+ end
+ end
+ end
+
+ private
+
+ ##
+ # Creates a regular expression to match IPv4 addresses
+
+ def dot_pat_str(str)
+ list = str.split('.').collect { |s|
+ (s == '*') ? '.+' : s
+ }
+ list.join("\\.")
+ end
+
+ private
+
+ ##
+ # Creates a Regexp to match an address.
+
+ def dot_pat(str)
+ /\A#{dot_pat_str(str)}\z/
+ end
+
+ public
+
+ ##
+ # Matches +addr+ against this entry.
+
+ def match(addr)
+ case @pat[0]
+ when :all
+ true
+ when :ip
+ begin
+ ipaddr = IPAddr.new(addr[3])
+ ipaddr = ipaddr.ipv4_mapped if @pat[1].ipv6? && ipaddr.ipv4?
+ rescue ArgumentError
+ return false
+ end
+ (@pat[1].include?(ipaddr)) ? true : false
+ when :name
+ (@pat[1] =~ addr[2]) ? true : false
+ else
+ false
+ end
+ end
+ end
+
+ ##
+ # A list of ACLEntry objects. Used to implement the allow and deny halves
+ # of an ACL
+
+ class ACLList
+
+ ##
+ # Creates an empty ACLList
+
+ def initialize
+ @list = []
+ end
+
+ public
+
+ ##
+ # Matches +addr+ against each ACLEntry in this list.
+
+ def match(addr)
+ @list.each do |e|
+ return true if e.match(addr)
+ end
+ false
+ end
+
+ public
+
+ ##
+ # Adds +str+ as an ACLEntry in this list
+
+ def add(str)
+ @list.push(ACLEntry.new(str))
+ end
+
+ end
+
+ ##
+ # Default to deny
+
+ DENY_ALLOW = 0
+
+ ##
+ # Default to allow
+
+ ALLOW_DENY = 1
+
+ ##
+ # Creates a new ACL from +list+ with an evaluation +order+ of DENY_ALLOW or
+ # ALLOW_DENY.
+ #
+ # An ACL +list+ is an Array of "allow" or "deny" and an address or address
+ # mask or "all" or "*" to match any address:
+ #
+ # %w[
+ # deny all
+ # allow 192.0.2.2
+ # allow 192.0.2.128/26
+ # ]
+
+ def initialize(list=nil, order = DENY_ALLOW)
+ @order = order
+ @deny = ACLList.new
+ @allow = ACLList.new
+ install_list(list) if list
+ end
+
+ public
+
+ ##
+ # Allow connections from Socket +soc+?
+
+ def allow_socket?(soc)
+ allow_addr?(soc.peeraddr)
+ end
+
+ public
+
+ ##
+ # Allow connections from addrinfo +addr+? It must be formatted like
+ # Socket#peeraddr:
+ #
+ # ["AF_INET", 10, "lc630", "192.0.2.1"]
+
+ def allow_addr?(addr)
+ case @order
+ when DENY_ALLOW
+ return true if @allow.match(addr)
+ return false if @deny.match(addr)
+ return true
+ when ALLOW_DENY
+ return false if @deny.match(addr)
+ return true if @allow.match(addr)
+ return false
+ else
+ false
+ end
+ end
+
+ public
+
+ ##
+ # Adds +list+ of ACL entries to this ACL.
+
+ def install_list(list)
+ i = 0
+ while i < list.size
+ permission, domain = list.slice(i,2)
+ case permission.downcase
+ when 'allow'
+ @allow.add(domain)
+ when 'deny'
+ @deny.add(domain)
+ else
+ raise "Invalid ACL entry #{list}"
+ end
+ i += 2
+ end
+ end
+
+end
diff --git a/lib/drb/drb.gemspec b/lib/drb/drb.gemspec
new file mode 100644
index 0000000000..c9d7e40a51
--- /dev/null
+++ b/lib/drb/drb.gemspec
@@ -0,0 +1,43 @@
+begin
+ require_relative "lib/drb/version"
+rescue LoadError # Fallback to load version file in ruby core repository
+ require_relative "version"
+end
+
+Gem::Specification.new do |spec|
+ spec.name = "drb"
+ spec.version = DRb::VERSION
+ spec.authors = ["Masatoshi SEKI"]
+ spec.email = ["seki@ruby-lang.org"]
+
+ spec.summary = %q{Distributed object system for Ruby}
+ spec.description = %q{Distributed object system for Ruby}
+ spec.homepage = "https://github.com/ruby/drb"
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ spec.files = %w[
+ LICENSE.txt
+ drb.gemspec
+ lib/drb.rb
+ lib/drb/acl.rb
+ lib/drb/drb.rb
+ lib/drb/eq.rb
+ lib/drb/extserv.rb
+ lib/drb/extservm.rb
+ lib/drb/gw.rb
+ lib/drb/invokemethod.rb
+ lib/drb/observer.rb
+ lib/drb/ssl.rb
+ lib/drb/timeridconv.rb
+ lib/drb/unix.rb
+ lib/drb/version.rb
+ lib/drb/weakidconv.rb
+ ]
+ spec.require_paths = ["lib"]
+
+ spec.add_dependency "ruby2_keywords"
+end
diff --git a/lib/drb/drb.rb b/lib/drb/drb.rb
new file mode 100644
index 0000000000..23181bb834
--- /dev/null
+++ b/lib/drb/drb.rb
@@ -0,0 +1,1942 @@
+# frozen_string_literal: false
+#
+# = drb/drb.rb
+#
+# Distributed Ruby: _dRuby_ version 2.0.4
+#
+# Copyright (c) 1999-2003 Masatoshi SEKI. You can redistribute it and/or
+# modify it under the same terms as Ruby.
+#
+# Author:: Masatoshi SEKI
+#
+# Documentation:: William Webber (william@williamwebber.com)
+#
+# == Overview
+#
+# dRuby is a distributed object system for Ruby. It allows an object in one
+# Ruby process to invoke methods on an object in another Ruby process on the
+# same or a different machine.
+#
+# The Ruby standard library contains the core classes of the dRuby package.
+# However, the full package also includes access control lists and the
+# Rinda tuple-space distributed task management system, as well as a
+# large number of samples. The full dRuby package can be downloaded from
+# the dRuby home page (see *References*).
+#
+# For an introduction and examples of usage see the documentation to the
+# DRb module.
+#
+# == References
+#
+# [http://www2a.biglobe.ne.jp/~seki/ruby/druby.html]
+# The dRuby home page, in Japanese. Contains the full dRuby package
+# and links to other Japanese-language sources.
+#
+# [http://www2a.biglobe.ne.jp/~seki/ruby/druby.en.html]
+# The English version of the dRuby home page.
+#
+# [http://pragprog.com/book/sidruby/the-druby-book]
+# The dRuby Book: Distributed and Parallel Computing with Ruby
+# by Masatoshi Seki and Makoto Inoue
+#
+# [http://www.ruby-doc.org/docs/ProgrammingRuby/html/ospace.html]
+# The chapter from *Programming* *Ruby* by Dave Thomas and Andy Hunt
+# which discusses dRuby.
+#
+# [http://www.clio.ne.jp/home/web-i31s/Flotuard/Ruby/PRC2K_seki/dRuby.en.html]
+# Translation of presentation on Ruby by Masatoshi Seki.
+
+require 'socket'
+require 'io/wait'
+require 'monitor'
+require_relative 'eq'
+
+#
+# == Overview
+#
+# dRuby is a distributed object system for Ruby. It is written in
+# pure Ruby and uses its own protocol. No add-in services are needed
+# beyond those provided by the Ruby runtime, such as TCP sockets. It
+# does not rely on or interoperate with other distributed object
+# systems such as CORBA, RMI, or .NET.
+#
+# dRuby allows methods to be called in one Ruby process upon a Ruby
+# object located in another Ruby process, even on another machine.
+# References to objects can be passed between processes. Method
+# arguments and return values are dumped and loaded in marshalled
+# format. All of this is done transparently to both the caller of the
+# remote method and the object that it is called upon.
+#
+# An object in a remote process is locally represented by a
+# DRb::DRbObject instance. This acts as a sort of proxy for the
+# remote object. Methods called upon this DRbObject instance are
+# forwarded to its remote object. This is arranged dynamically at run
+# time. There are no statically declared interfaces for remote
+# objects, such as CORBA's IDL.
+#
+# dRuby calls made into a process are handled by a DRb::DRbServer
+# instance within that process. This reconstitutes the method call,
+# invokes it upon the specified local object, and returns the value to
+# the remote caller. Any object can receive calls over dRuby. There
+# is no need to implement a special interface, or mixin special
+# functionality. Nor, in the general case, does an object need to
+# explicitly register itself with a DRbServer in order to receive
+# dRuby calls.
+#
+# One process wishing to make dRuby calls upon another process must
+# somehow obtain an initial reference to an object in the remote
+# process by some means other than as the return value of a remote
+# method call, as there is initially no remote object reference it can
+# invoke a method upon. This is done by attaching to the server by
+# URI. Each DRbServer binds itself to a URI such as
+# 'druby://example.com:8787'. A DRbServer can have an object attached
+# to it that acts as the server's *front* *object*. A DRbObject can
+# be explicitly created from the server's URI. This DRbObject's
+# remote object will be the server's front object. This front object
+# can then return references to other Ruby objects in the DRbServer's
+# process.
+#
+# Method calls made over dRuby behave largely the same as normal Ruby
+# method calls made within a process. Method calls with blocks are
+# supported, as are raising exceptions. In addition to a method's
+# standard errors, a dRuby call may also raise one of the
+# dRuby-specific errors, all of which are subclasses of DRb::DRbError.
+#
+# Any type of object can be passed as an argument to a dRuby call or
+# returned as its return value. By default, such objects are dumped
+# or marshalled at the local end, then loaded or unmarshalled at the
+# remote end. The remote end therefore receives a copy of the local
+# object, not a distributed reference to it; methods invoked upon this
+# copy are executed entirely in the remote process, not passed on to
+# the local original. This has semantics similar to pass-by-value.
+#
+# However, if an object cannot be marshalled, a dRuby reference to it
+# is passed or returned instead. This will turn up at the remote end
+# as a DRbObject instance. All methods invoked upon this remote proxy
+# are forwarded to the local object, as described in the discussion of
+# DRbObjects. This has semantics similar to the normal Ruby
+# pass-by-reference.
+#
+# The easiest way to signal that we want an otherwise marshallable
+# object to be passed or returned as a DRbObject reference, rather
+# than marshalled and sent as a copy, is to include the
+# DRb::DRbUndumped mixin module.
+#
+# dRuby supports calling remote methods with blocks. As blocks (or
+# rather the Proc objects that represent them) are not marshallable,
+# the block executes in the local, not the remote, context. Each
+# value yielded to the block is passed from the remote object to the
+# local block, then the value returned by each block invocation is
+# passed back to the remote execution context to be collected, before
+# the collected values are finally returned to the local context as
+# the return value of the method invocation.
+#
+# == Examples of usage
+#
+# For more dRuby samples, see the +samples+ directory in the full
+# dRuby distribution.
+#
+# === dRuby in client/server mode
+#
+# This illustrates setting up a simple client-server drb
+# system. Run the server and client code in different terminals,
+# starting the server code first.
+#
+# ==== Server code
+#
+# require 'drb/drb'
+#
+# # The URI for the server to connect to
+# URI="druby://localhost:8787"
+#
+# class TimeServer
+#
+# def get_current_time
+# return Time.now
+# end
+#
+# end
+#
+# # The object that handles requests on the server
+# FRONT_OBJECT=TimeServer.new
+#
+# DRb.start_service(URI, FRONT_OBJECT)
+# # Wait for the drb server thread to finish before exiting.
+# DRb.thread.join
+#
+# ==== Client code
+#
+# require 'drb/drb'
+#
+# # The URI to connect to
+# SERVER_URI="druby://localhost:8787"
+#
+# # Start a local DRbServer to handle callbacks.
+# #
+# # Not necessary for this small example, but will be required
+# # as soon as we pass a non-marshallable object as an argument
+# # to a dRuby call.
+# #
+# # Note: this must be called at least once per process to take any effect.
+# # This is particularly important if your application forks.
+# DRb.start_service
+#
+# timeserver = DRbObject.new_with_uri(SERVER_URI)
+# puts timeserver.get_current_time
+#
+# === Remote objects under dRuby
+#
+# This example illustrates returning a reference to an object
+# from a dRuby call. The Logger instances live in the server
+# process. References to them are returned to the client process,
+# where methods can be invoked upon them. These methods are
+# executed in the server process.
+#
+# ==== Server code
+#
+# require 'drb/drb'
+#
+# URI="druby://localhost:8787"
+#
+# class Logger
+#
+# # Make dRuby send Logger instances as dRuby references,
+# # not copies.
+# include DRb::DRbUndumped
+#
+# def initialize(n, fname)
+# @name = n
+# @filename = fname
+# end
+#
+# def log(message)
+# File.open(@filename, "a") do |f|
+# f.puts("#{Time.now}: #{@name}: #{message}")
+# end
+# end
+#
+# end
+#
+# # We have a central object for creating and retrieving loggers.
+# # This retains a local reference to all loggers created. This
+# # is so an existing logger can be looked up by name, but also
+# # to prevent loggers from being garbage collected. A dRuby
+# # reference to an object is not sufficient to prevent it being
+# # garbage collected!
+# class LoggerFactory
+#
+# def initialize(bdir)
+# @basedir = bdir
+# @loggers = {}
+# end
+#
+# def get_logger(name)
+# if !@loggers.has_key? name
+# # make the filename safe, then declare it to be so
+# fname = name.gsub(/[.\/\\\:]/, "_")
+# @loggers[name] = Logger.new(name, @basedir + "/" + fname)
+# end
+# return @loggers[name]
+# end
+#
+# end
+#
+# FRONT_OBJECT=LoggerFactory.new("/tmp/dlog")
+#
+# DRb.start_service(URI, FRONT_OBJECT)
+# DRb.thread.join
+#
+# ==== Client code
+#
+# require 'drb/drb'
+#
+# SERVER_URI="druby://localhost:8787"
+#
+# DRb.start_service
+#
+# log_service=DRbObject.new_with_uri(SERVER_URI)
+#
+# ["loga", "logb", "logc"].each do |logname|
+#
+# logger=log_service.get_logger(logname)
+#
+# logger.log("Hello, world!")
+# logger.log("Goodbye, world!")
+# logger.log("=== EOT ===")
+#
+# end
+#
+# == Security
+#
+# As with all network services, security needs to be considered when
+# using dRuby. By allowing external access to a Ruby object, you are
+# not only allowing outside clients to call the methods you have
+# defined for that object, but by default to execute arbitrary Ruby
+# code on your server. Consider the following:
+#
+# # !!! UNSAFE CODE !!!
+# ro = DRbObject::new_with_uri("druby://your.server.com:8989")
+# class << ro
+# undef :instance_eval # force call to be passed to remote object
+# end
+# ro.instance_eval("`rm -rf *`")
+#
+# The dangers posed by instance_eval and friends are such that a
+# DRbServer should only be used when clients are trusted.
+#
+# A DRbServer can be configured with an access control list to
+# selectively allow or deny access from specified IP addresses. The
+# main druby distribution provides the ACL class for this purpose. In
+# general, this mechanism should only be used alongside, rather than
+# as a replacement for, a good firewall.
+#
+# == dRuby internals
+#
+# dRuby is implemented using three main components: a remote method
+# call marshaller/unmarshaller; a transport protocol; and an
+# ID-to-object mapper. The latter two can be directly, and the first
+# indirectly, replaced, in order to provide different behaviour and
+# capabilities.
+#
+# Marshalling and unmarshalling of remote method calls is performed by
+# a DRb::DRbMessage instance. This uses the Marshal module to dump
+# the method call before sending it over the transport layer, then
+# reconstitute it at the other end. There is normally no need to
+# replace this component, and no direct way is provided to do so.
+# However, it is possible to implement an alternative marshalling
+# scheme as part of an implementation of the transport layer.
+#
+# The transport layer is responsible for opening client and server
+# network connections and forwarding dRuby request across them.
+# Normally, it uses DRb::DRbMessage internally to manage marshalling
+# and unmarshalling. The transport layer is managed by
+# DRb::DRbProtocol. Multiple protocols can be installed in
+# DRbProtocol at the one time; selection between them is determined by
+# the scheme of a dRuby URI. The default transport protocol is
+# selected by the scheme 'druby:', and implemented by
+# DRb::DRbTCPSocket. This uses plain TCP/IP sockets for
+# communication. An alternative protocol, using UNIX domain sockets,
+# is implemented by DRb::DRbUNIXSocket in the file drb/unix.rb, and
+# selected by the scheme 'drbunix:'. A sample implementation over
+# HTTP can be found in the samples accompanying the main dRuby
+# distribution.
+#
+# The ID-to-object mapping component maps dRuby object ids to the
+# objects they refer to, and vice versa. The implementation to use
+# can be specified as part of a DRb::DRbServer's configuration. The
+# default implementation is provided by DRb::DRbIdConv. It uses an
+# object's ObjectSpace id as its dRuby id. This means that the dRuby
+# reference to that object only remains meaningful for the lifetime of
+# the object's process and the lifetime of the object within that
+# process. A modified implementation is provided by DRb::TimerIdConv
+# in the file drb/timeridconv.rb. This implementation retains a local
+# reference to all objects exported over dRuby for a configurable
+# period of time (defaulting to ten minutes), to prevent them being
+# garbage-collected within this time. Another sample implementation
+# is provided in sample/name.rb in the main dRuby distribution. This
+# allows objects to specify their own id or "name". A dRuby reference
+# can be made persistent across processes by having each process
+# register an object using the same dRuby name.
+#
+module DRb
+
+ # Superclass of all errors raised in the DRb module.
+ class DRbError < RuntimeError; end
+
+ # Error raised when an error occurs on the underlying communication
+ # protocol.
+ class DRbConnError < DRbError; end
+
+ # Class responsible for converting between an object and its id.
+ #
+ # This, the default implementation, uses an object's local ObjectSpace
+ # __id__ as its id. This means that an object's identification over
+ # drb remains valid only while that object instance remains alive
+ # within the server runtime.
+ #
+ # For alternative mechanisms, see DRb::TimerIdConv in drb/timeridconv.rb
+ # and DRbNameIdConv in sample/name.rb in the full drb distribution.
+ class DRbIdConv
+
+ # Convert an object reference id to an object.
+ #
+ # This implementation looks up the reference id in the local object
+ # space and returns the object it refers to.
+ def to_obj(ref)
+ ObjectSpace._id2ref(ref)
+ end
+
+ # Convert an object into a reference id.
+ #
+ # This implementation returns the object's __id__ in the local
+ # object space.
+ def to_id(obj)
+ case obj
+ when Object
+ obj.nil? ? nil : obj.__id__
+ when BasicObject
+ obj.__id__
+ end
+ end
+ end
+
+ # Mixin module making an object undumpable or unmarshallable.
+ #
+ # If an object which includes this module is returned by method
+ # called over drb, then the object remains in the server space
+ # and a reference to the object is returned, rather than the
+ # object being marshalled and moved into the client space.
+ module DRbUndumped
+ def _dump(dummy) # :nodoc:
+ raise TypeError, 'can\'t dump'
+ end
+ end
+
+ # Error raised by the DRb module when an attempt is made to refer to
+ # the context's current drb server but the context does not have one.
+ # See #current_server.
+ class DRbServerNotFound < DRbError; end
+
+ # Error raised by the DRbProtocol module when it cannot find any
+ # protocol implementation support the scheme specified in a URI.
+ class DRbBadURI < DRbError; end
+
+ # Error raised by a dRuby protocol when it doesn't support the
+ # scheme specified in a URI. See DRb::DRbProtocol.
+ class DRbBadScheme < DRbError; end
+
+ # An exception wrapping a DRb::DRbUnknown object
+ class DRbUnknownError < DRbError
+
+ # Create a new DRbUnknownError for the DRb::DRbUnknown object +unknown+
+ def initialize(unknown)
+ @unknown = unknown
+ super(unknown.name)
+ end
+
+ # Get the wrapped DRb::DRbUnknown object.
+ attr_reader :unknown
+
+ def self._load(s) # :nodoc:
+ Marshal::load(s)
+ end
+
+ def _dump(lv) # :nodoc:
+ Marshal::dump(@unknown)
+ end
+ end
+
+ # An exception wrapping an error object
+ class DRbRemoteError < DRbError
+
+ # Creates a new remote error that wraps the Exception +error+
+ def initialize(error)
+ @reason = error.class.to_s
+ super("#{error.message} (#{error.class})")
+ set_backtrace(error.backtrace)
+ end
+
+ # the class of the error, as a string.
+ attr_reader :reason
+ end
+
+ # Class wrapping a marshalled object whose type is unknown locally.
+ #
+ # If an object is returned by a method invoked over drb, but the
+ # class of the object is unknown in the client namespace, or
+ # the object is a constant unknown in the client namespace, then
+ # the still-marshalled object is returned wrapped in a DRbUnknown instance.
+ #
+ # If this object is passed as an argument to a method invoked over
+ # drb, then the wrapped object is passed instead.
+ #
+ # The class or constant name of the object can be read from the
+ # +name+ attribute. The marshalled object is held in the +buf+
+ # attribute.
+ class DRbUnknown
+
+ # Create a new DRbUnknown object.
+ #
+ # +buf+ is a string containing a marshalled object that could not
+ # be unmarshalled. +err+ is the error message that was raised
+ # when the unmarshalling failed. It is used to determine the
+ # name of the unmarshalled object.
+ def initialize(err, buf)
+ case err.to_s
+ when /uninitialized constant (\S+)/
+ @name = $1
+ when /undefined class\/module (\S+)/
+ @name = $1
+ else
+ @name = nil
+ end
+ @buf = buf
+ end
+
+ # The name of the unknown thing.
+ #
+ # Class name for unknown objects; variable name for unknown
+ # constants.
+ attr_reader :name
+
+ # Buffer contained the marshalled, unknown object.
+ attr_reader :buf
+
+ def self._load(s) # :nodoc:
+ begin
+ Marshal::load(s)
+ rescue NameError, ArgumentError
+ DRbUnknown.new($!, s)
+ end
+ end
+
+ def _dump(lv) # :nodoc:
+ @buf
+ end
+
+ # Attempt to load the wrapped marshalled object again.
+ #
+ # If the class of the object is now known locally, the object
+ # will be unmarshalled and returned. Otherwise, a new
+ # but identical DRbUnknown object will be returned.
+ def reload
+ self.class._load(@buf)
+ end
+
+ # Create a DRbUnknownError exception containing this object.
+ def exception
+ DRbUnknownError.new(self)
+ end
+ end
+
+ # An Array wrapper that can be sent to another server via DRb.
+ #
+ # All entries in the array will be dumped or be references that point to
+ # the local server.
+
+ class DRbArray
+
+ # Creates a new DRbArray that either dumps or wraps all the items in the
+ # Array +ary+ so they can be loaded by a remote DRb server.
+
+ def initialize(ary)
+ @ary = ary.collect { |obj|
+ if obj.kind_of? DRbUndumped
+ DRbObject.new(obj)
+ else
+ begin
+ Marshal.dump(obj)
+ obj
+ rescue
+ DRbObject.new(obj)
+ end
+ end
+ }
+ end
+
+ def self._load(s) # :nodoc:
+ Marshal::load(s)
+ end
+
+ def _dump(lv) # :nodoc:
+ Marshal.dump(@ary)
+ end
+ end
+
+ # Handler for sending and receiving drb messages.
+ #
+ # This takes care of the low-level marshalling and unmarshalling
+ # of drb requests and responses sent over the wire between server
+ # and client. This relieves the implementor of a new drb
+ # protocol layer with having to deal with these details.
+ #
+ # The user does not have to directly deal with this object in
+ # normal use.
+ class DRbMessage
+ def initialize(config) # :nodoc:
+ @load_limit = config[:load_limit]
+ @argc_limit = config[:argc_limit]
+ end
+
+ def dump(obj, error=false) # :nodoc:
+ case obj
+ when DRbUndumped
+ obj = make_proxy(obj, error)
+ when Object
+ # nothing
+ else
+ obj = make_proxy(obj, error)
+ end
+ begin
+ str = Marshal::dump(obj)
+ rescue
+ str = Marshal::dump(make_proxy(obj, error))
+ end
+ [str.size].pack('N') + str
+ end
+
+ def load(soc) # :nodoc:
+ begin
+ sz = soc.read(4) # sizeof (N)
+ rescue
+ raise(DRbConnError, $!.message, $!.backtrace)
+ end
+ raise(DRbConnError, 'connection closed') if sz.nil?
+ raise(DRbConnError, 'premature header') if sz.size < 4
+ sz = sz.unpack('N')[0]
+ raise(DRbConnError, "too large packet #{sz}") if @load_limit < sz
+ begin
+ str = soc.read(sz)
+ rescue
+ raise(DRbConnError, $!.message, $!.backtrace)
+ end
+ raise(DRbConnError, 'connection closed') if str.nil?
+ raise(DRbConnError, 'premature marshal format(can\'t read)') if str.size < sz
+ DRb.mutex.synchronize do
+ begin
+ Marshal::load(str)
+ rescue NameError, ArgumentError
+ DRbUnknown.new($!, str)
+ end
+ end
+ end
+
+ def send_request(stream, ref, msg_id, arg, b) # :nodoc:
+ ary = []
+ ary.push(dump(ref.__drbref))
+ ary.push(dump(msg_id.id2name))
+ ary.push(dump(arg.length))
+ arg.each do |e|
+ ary.push(dump(e))
+ end
+ ary.push(dump(b))
+ stream.write(ary.join(''))
+ rescue
+ raise(DRbConnError, $!.message, $!.backtrace)
+ end
+
+ def recv_request(stream) # :nodoc:
+ ref = load(stream)
+ ro = DRb.to_obj(ref)
+ msg = load(stream)
+ argc = load(stream)
+ raise(DRbConnError, "too many arguments") if @argc_limit < argc
+ argv = Array.new(argc, nil)
+ argc.times do |n|
+ argv[n] = load(stream)
+ end
+ block = load(stream)
+ return ro, msg, argv, block
+ end
+
+ def send_reply(stream, succ, result) # :nodoc:
+ stream.write(dump(succ) + dump(result, !succ))
+ rescue
+ raise(DRbConnError, $!.message, $!.backtrace)
+ end
+
+ def recv_reply(stream) # :nodoc:
+ succ = load(stream)
+ result = load(stream)
+ [succ, result]
+ end
+
+ private
+ def make_proxy(obj, error=false) # :nodoc:
+ if error
+ DRbRemoteError.new(obj)
+ else
+ DRbObject.new(obj)
+ end
+ end
+ end
+
+ # Module managing the underlying network protocol(s) used by drb.
+ #
+ # By default, drb uses the DRbTCPSocket protocol. Other protocols
+ # can be defined. A protocol must define the following class methods:
+ #
+ # [open(uri, config)] Open a client connection to the server at +uri+,
+ # using configuration +config+. Return a protocol
+ # instance for this connection.
+ # [open_server(uri, config)] Open a server listening at +uri+,
+ # using configuration +config+. Return a
+ # protocol instance for this listener.
+ # [uri_option(uri, config)] Take a URI, possibly containing an option
+ # component (e.g. a trailing '?param=val'),
+ # and return a [uri, option] tuple.
+ #
+ # All of these methods should raise a DRbBadScheme error if the URI
+ # does not identify the protocol they support (e.g. "druby:" for
+ # the standard Ruby protocol). This is how the DRbProtocol module,
+ # given a URI, determines which protocol implementation serves that
+ # protocol.
+ #
+ # The protocol instance returned by #open_server must have the
+ # following methods:
+ #
+ # [accept] Accept a new connection to the server. Returns a protocol
+ # instance capable of communicating with the client.
+ # [close] Close the server connection.
+ # [uri] Get the URI for this server.
+ #
+ # The protocol instance returned by #open must have the following methods:
+ #
+ # [send_request (ref, msg_id, arg, b)]
+ # Send a request to +ref+ with the given message id and arguments.
+ # This is most easily implemented by calling DRbMessage.send_request,
+ # providing a stream that sits on top of the current protocol.
+ # [recv_reply]
+ # Receive a reply from the server and return it as a [success-boolean,
+ # reply-value] pair. This is most easily implemented by calling
+ # DRb.recv_reply, providing a stream that sits on top of the
+ # current protocol.
+ # [alive?]
+ # Is this connection still alive?
+ # [close]
+ # Close this connection.
+ #
+ # The protocol instance returned by #open_server().accept() must have
+ # the following methods:
+ #
+ # [recv_request]
+ # Receive a request from the client and return a [object, message,
+ # args, block] tuple. This is most easily implemented by calling
+ # DRbMessage.recv_request, providing a stream that sits on top of
+ # the current protocol.
+ # [send_reply(succ, result)]
+ # Send a reply to the client. This is most easily implemented
+ # by calling DRbMessage.send_reply, providing a stream that sits
+ # on top of the current protocol.
+ # [close]
+ # Close this connection.
+ #
+ # A new protocol is registered with the DRbProtocol module using
+ # the add_protocol method.
+ #
+ # For examples of other protocols, see DRbUNIXSocket in drb/unix.rb,
+ # and HTTP0 in sample/http0.rb and sample/http0serv.rb in the full
+ # drb distribution.
+ module DRbProtocol
+
+ # Add a new protocol to the DRbProtocol module.
+ def add_protocol(prot)
+ @protocol.push(prot)
+ end
+ module_function :add_protocol
+
+ # Open a client connection to +uri+ with the configuration +config+.
+ #
+ # The DRbProtocol module asks each registered protocol in turn to
+ # try to open the URI. Each protocol signals that it does not handle that
+ # URI by raising a DRbBadScheme error. If no protocol recognises the
+ # URI, then a DRbBadURI error is raised. If a protocol accepts the
+ # URI, but an error occurs in opening it, a DRbConnError is raised.
+ def open(uri, config, first=true)
+ @protocol.each do |prot|
+ begin
+ return prot.open(uri, config)
+ rescue DRbBadScheme
+ rescue DRbConnError
+ raise($!)
+ rescue
+ raise(DRbConnError, "#{uri} - #{$!.inspect}")
+ end
+ end
+ if first && (config[:auto_load] != false)
+ auto_load(uri)
+ return open(uri, config, false)
+ end
+ raise DRbBadURI, 'can\'t parse uri:' + uri
+ end
+ module_function :open
+
+ # Open a server listening for connections at +uri+ with
+ # configuration +config+.
+ #
+ # The DRbProtocol module asks each registered protocol in turn to
+ # try to open a server at the URI. Each protocol signals that it does
+ # not handle that URI by raising a DRbBadScheme error. If no protocol
+ # recognises the URI, then a DRbBadURI error is raised. If a protocol
+ # accepts the URI, but an error occurs in opening it, the underlying
+ # error is passed on to the caller.
+ def open_server(uri, config, first=true)
+ @protocol.each do |prot|
+ begin
+ return prot.open_server(uri, config)
+ rescue DRbBadScheme
+ end
+ end
+ if first && (config[:auto_load] != false)
+ auto_load(uri)
+ return open_server(uri, config, false)
+ end
+ raise DRbBadURI, 'can\'t parse uri:' + uri
+ end
+ module_function :open_server
+
+ # Parse +uri+ into a [uri, option] pair.
+ #
+ # The DRbProtocol module asks each registered protocol in turn to
+ # try to parse the URI. Each protocol signals that it does not handle that
+ # URI by raising a DRbBadScheme error. If no protocol recognises the
+ # URI, then a DRbBadURI error is raised.
+ def uri_option(uri, config, first=true)
+ @protocol.each do |prot|
+ begin
+ uri, opt = prot.uri_option(uri, config)
+ # opt = nil if opt == ''
+ return uri, opt
+ rescue DRbBadScheme
+ end
+ end
+ if first && (config[:auto_load] != false)
+ auto_load(uri)
+ return uri_option(uri, config, false)
+ end
+ raise DRbBadURI, 'can\'t parse uri:' + uri
+ end
+ module_function :uri_option
+
+ def auto_load(uri) # :nodoc:
+ if /\Adrb([a-z0-9]+):/ =~ uri
+ require("drb/#{$1}") rescue nil
+ end
+ end
+ module_function :auto_load
+ end
+
+ # The default drb protocol which communicates over a TCP socket.
+ #
+ # The DRb TCP protocol URI looks like:
+ # <code>druby://<host>:<port>?<option></code>. The option is optional.
+
+ class DRbTCPSocket
+ # :stopdoc:
+ private
+ def self.parse_uri(uri)
+ if /\Adruby:\/\/(.*?):(\d+)(\?(.*))?\z/ =~ uri
+ host = $1
+ port = $2.to_i
+ option = $4
+ [host, port, option]
+ else
+ raise(DRbBadScheme, uri) unless uri.start_with?('druby:')
+ raise(DRbBadURI, 'can\'t parse uri:' + uri)
+ end
+ end
+
+ public
+
+ # Open a client connection to +uri+ (DRb URI string) using configuration
+ # +config+.
+ #
+ # This can raise DRb::DRbBadScheme or DRb::DRbBadURI if +uri+ is not for a
+ # recognized protocol. See DRb::DRbServer.new for information on built-in
+ # URI protocols.
+ def self.open(uri, config)
+ host, port, = parse_uri(uri)
+ soc = TCPSocket.open(host, port)
+ self.new(uri, soc, config)
+ end
+
+ # Returns the hostname of this server
+ def self.getservername
+ host = Socket::gethostname
+ begin
+ Socket::getaddrinfo(host, nil,
+ Socket::AF_UNSPEC,
+ Socket::SOCK_STREAM,
+ 0,
+ Socket::AI_PASSIVE)[0][3]
+ rescue
+ 'localhost'
+ end
+ end
+
+ # For the families available for +host+, returns a TCPServer on +port+.
+ # If +port+ is 0 the first available port is used. IPv4 servers are
+ # preferred over IPv6 servers.
+ def self.open_server_inaddr_any(host, port)
+ infos = Socket::getaddrinfo(host, nil,
+ Socket::AF_UNSPEC,
+ Socket::SOCK_STREAM,
+ 0,
+ Socket::AI_PASSIVE)
+ families = Hash[*infos.collect { |af, *_| af }.uniq.zip([]).flatten]
+ return TCPServer.open('0.0.0.0', port) if families.has_key?('AF_INET')
+ return TCPServer.open('::', port) if families.has_key?('AF_INET6')
+ return TCPServer.open(port)
+ # :stopdoc:
+ end
+
+ # Open a server listening for connections at +uri+ using
+ # configuration +config+.
+ def self.open_server(uri, config)
+ uri = 'druby://:0' unless uri
+ host, port, _ = parse_uri(uri)
+ config = {:tcp_original_host => host}.update(config)
+ if host.size == 0
+ host = getservername
+ soc = open_server_inaddr_any(host, port)
+ else
+ soc = TCPServer.open(host, port)
+ end
+ port = soc.addr[1] if port == 0
+ config[:tcp_port] = port
+ uri = "druby://#{host}:#{port}"
+ self.new(uri, soc, config)
+ end
+
+ # Parse +uri+ into a [uri, option] pair.
+ def self.uri_option(uri, config)
+ host, port, option = parse_uri(uri)
+ return "druby://#{host}:#{port}", option
+ end
+
+ # Create a new DRbTCPSocket instance.
+ #
+ # +uri+ is the URI we are connected to.
+ # +soc+ is the tcp socket we are bound to. +config+ is our
+ # configuration.
+ def initialize(uri, soc, config={})
+ @uri = uri
+ @socket = soc
+ @config = config
+ @acl = config[:tcp_acl]
+ @msg = DRbMessage.new(config)
+ set_sockopt(@socket)
+ @shutdown_pipe_r, @shutdown_pipe_w = IO.pipe
+ end
+
+ # Get the URI that we are connected to.
+ attr_reader :uri
+
+ # Get the address of our TCP peer (the other end of the socket
+ # we are bound to.
+ def peeraddr
+ @socket.peeraddr
+ end
+
+ # Get the socket.
+ def stream; @socket; end
+
+ # On the client side, send a request to the server.
+ def send_request(ref, msg_id, arg, b)
+ @msg.send_request(stream, ref, msg_id, arg, b)
+ end
+
+ # On the server side, receive a request from the client.
+ def recv_request
+ @msg.recv_request(stream)
+ end
+
+ # On the server side, send a reply to the client.
+ def send_reply(succ, result)
+ @msg.send_reply(stream, succ, result)
+ end
+
+ # On the client side, receive a reply from the server.
+ def recv_reply
+ @msg.recv_reply(stream)
+ end
+
+ public
+
+ # Close the connection.
+ #
+ # If this is an instance returned by #open_server, then this stops
+ # listening for new connections altogether. If this is an instance
+ # returned by #open or by #accept, then it closes this particular
+ # client-server session.
+ def close
+ shutdown
+ if @socket
+ @socket.close
+ @socket = nil
+ end
+ close_shutdown_pipe
+ end
+
+ def close_shutdown_pipe
+ @shutdown_pipe_w.close
+ @shutdown_pipe_r.close
+ end
+ private :close_shutdown_pipe
+
+ # On the server side, for an instance returned by #open_server,
+ # accept a client connection and return a new instance to handle
+ # the server's side of this client-server session.
+ def accept
+ while true
+ s = accept_or_shutdown
+ return nil unless s
+ break if (@acl ? @acl.allow_socket?(s) : true)
+ s.close
+ end
+ if @config[:tcp_original_host].to_s.size == 0
+ uri = "druby://#{s.addr[3]}:#{@config[:tcp_port]}"
+ else
+ uri = @uri
+ end
+ self.class.new(uri, s, @config)
+ end
+
+ def accept_or_shutdown
+ readables, = IO.select([@socket, @shutdown_pipe_r])
+ if readables.include? @shutdown_pipe_r
+ return nil
+ end
+ @socket.accept
+ end
+ private :accept_or_shutdown
+
+ # Graceful shutdown
+ def shutdown
+ @shutdown_pipe_w.close
+ end
+
+ # Check to see if this connection is alive.
+ def alive?
+ return false unless @socket
+ if @socket.to_io.wait_readable(0)
+ close
+ return false
+ end
+ true
+ end
+
+ def set_sockopt(soc) # :nodoc:
+ soc.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
+ rescue IOError, Errno::ECONNRESET, Errno::EINVAL
+ # closed/shutdown socket, ignore error
+ end
+ end
+
+ module DRbProtocol
+ @protocol = [DRbTCPSocket] # default
+ end
+
+ class DRbURIOption # :nodoc: I don't understand the purpose of this class...
+ def initialize(option)
+ @option = option.to_s
+ end
+ attr_reader :option
+ def to_s; @option; end
+
+ def ==(other)
+ return false unless DRbURIOption === other
+ @option == other.option
+ end
+
+ def hash
+ @option.hash
+ end
+
+ alias eql? ==
+ end
+
+ # Object wrapping a reference to a remote drb object.
+ #
+ # Method calls on this object are relayed to the remote
+ # object that this object is a stub for.
+ class DRbObject
+
+ # Unmarshall a marshalled DRbObject.
+ #
+ # If the referenced object is located within the local server, then
+ # the object itself is returned. Otherwise, a new DRbObject is
+ # created to act as a stub for the remote referenced object.
+ def self._load(s)
+ uri, ref = Marshal.load(s)
+
+ if DRb.here?(uri)
+ obj = DRb.to_obj(ref)
+ return obj
+ end
+
+ self.new_with(uri, ref)
+ end
+
+ # Creates a DRb::DRbObject given the reference information to the remote
+ # host +uri+ and object +ref+.
+
+ def self.new_with(uri, ref)
+ it = self.allocate
+ it.instance_variable_set(:@uri, uri)
+ it.instance_variable_set(:@ref, ref)
+ it
+ end
+
+ # Create a new DRbObject from a URI alone.
+ def self.new_with_uri(uri)
+ self.new(nil, uri)
+ end
+
+ # Marshall this object.
+ #
+ # The URI and ref of the object are marshalled.
+ def _dump(lv)
+ Marshal.dump([@uri, @ref])
+ end
+
+ # Create a new remote object stub.
+ #
+ # +obj+ is the (local) object we want to create a stub for. Normally
+ # this is +nil+. +uri+ is the URI of the remote object that this
+ # will be a stub for.
+ def initialize(obj, uri=nil)
+ @uri = nil
+ @ref = nil
+ case obj
+ when Object
+ is_nil = obj.nil?
+ when BasicObject
+ is_nil = false
+ end
+
+ if is_nil
+ return if uri.nil?
+ @uri, option = DRbProtocol.uri_option(uri, DRb.config)
+ @ref = DRbURIOption.new(option) unless option.nil?
+ else
+ @uri = uri ? uri : (DRb.uri rescue nil)
+ @ref = obj ? DRb.to_id(obj) : nil
+ end
+ end
+
+ # Get the URI of the remote object.
+ def __drburi
+ @uri
+ end
+
+ # Get the reference of the object, if local.
+ def __drbref
+ @ref
+ end
+
+ undef :to_s
+ undef :to_a if respond_to?(:to_a)
+
+ # Routes respond_to? to the referenced remote object.
+ def respond_to?(msg_id, priv=false)
+ case msg_id
+ when :_dump
+ true
+ when :marshal_dump
+ false
+ else
+ method_missing(:respond_to?, msg_id, priv)
+ end
+ end
+
+ # Routes method calls to the referenced remote object.
+ ruby2_keywords def method_missing(msg_id, *a, &b)
+ if DRb.here?(@uri)
+ obj = DRb.to_obj(@ref)
+ DRb.current_server.check_insecure_method(obj, msg_id)
+ return obj.__send__(msg_id, *a, &b)
+ end
+
+ succ, result = self.class.with_friend(@uri) do
+ DRbConn.open(@uri) do |conn|
+ conn.send_message(self, msg_id, a, b)
+ end
+ end
+
+ if succ
+ return result
+ elsif DRbUnknown === result
+ raise result
+ else
+ bt = self.class.prepare_backtrace(@uri, result)
+ result.set_backtrace(bt + caller)
+ raise result
+ end
+ end
+
+ # Given the +uri+ of another host executes the block provided.
+ def self.with_friend(uri) # :nodoc:
+ friend = DRb.fetch_server(uri)
+ return yield() unless friend
+
+ save = Thread.current['DRb']
+ Thread.current['DRb'] = { 'server' => friend }
+ return yield
+ ensure
+ Thread.current['DRb'] = save if friend
+ end
+
+ # Returns a modified backtrace from +result+ with the +uri+ where each call
+ # in the backtrace came from.
+ def self.prepare_backtrace(uri, result) # :nodoc:
+ prefix = "(#{uri}) "
+ bt = []
+ result.backtrace.each do |x|
+ break if /`__send__'$/ =~ x
+ if /\A\(druby:\/\// =~ x
+ bt.push(x)
+ else
+ bt.push(prefix + x)
+ end
+ end
+ bt
+ end
+
+ def pretty_print(q) # :nodoc:
+ q.pp_object(self)
+ end
+
+ def pretty_print_cycle(q) # :nodoc:
+ q.object_address_group(self) {
+ q.breakable
+ q.text '...'
+ }
+ end
+ end
+
+ class ThreadObject
+ include MonitorMixin
+
+ def initialize(&blk)
+ super()
+ @wait_ev = new_cond
+ @req_ev = new_cond
+ @res_ev = new_cond
+ @status = :wait
+ @req = nil
+ @res = nil
+ @thread = Thread.new(self, &blk)
+ end
+
+ def alive?
+ @thread.alive?
+ end
+
+ def kill
+ @thread.kill
+ @thread.join
+ end
+
+ def method_missing(msg, *arg, &blk)
+ synchronize do
+ @wait_ev.wait_until { @status == :wait }
+ @req = [msg] + arg
+ @status = :req
+ @req_ev.broadcast
+ @res_ev.wait_until { @status == :res }
+ value = @res
+ @req = @res = nil
+ @status = :wait
+ @wait_ev.broadcast
+ return value
+ end
+ end
+
+ def _execute()
+ synchronize do
+ @req_ev.wait_until { @status == :req }
+ @res = yield(@req)
+ @status = :res
+ @res_ev.signal
+ end
+ end
+ end
+
+ # Class handling the connection between a DRbObject and the
+ # server the real object lives on.
+ #
+ # This class maintains a pool of connections, to reduce the
+ # overhead of starting and closing down connections for each
+ # method call.
+ #
+ # This class is used internally by DRbObject. The user does
+ # not normally need to deal with it directly.
+ class DRbConn
+ POOL_SIZE = 16 # :nodoc:
+
+ def self.make_pool
+ ThreadObject.new do |queue|
+ pool = []
+ while true
+ queue._execute do |message|
+ case(message[0])
+ when :take then
+ remote_uri = message[1]
+ conn = nil
+ new_pool = []
+ pool.each do |c|
+ if conn.nil? and c.uri == remote_uri
+ conn = c if c.alive?
+ else
+ new_pool.push c
+ end
+ end
+ pool = new_pool
+ conn
+ when :store then
+ conn = message[1]
+ pool.unshift(conn)
+ pool.pop.close while pool.size > POOL_SIZE
+ conn
+ else
+ nil
+ end
+ end
+ end
+ end
+ end
+ @pool_proxy = nil
+
+ def self.stop_pool
+ @pool_proxy&.kill
+ @pool_proxy = nil
+ end
+
+ def self.open(remote_uri) # :nodoc:
+ begin
+ @pool_proxy = make_pool unless @pool_proxy&.alive?
+
+ conn = @pool_proxy.take(remote_uri)
+ conn = self.new(remote_uri) unless conn
+ succ, result = yield(conn)
+ return succ, result
+
+ ensure
+ if conn
+ if succ
+ @pool_proxy.store(conn)
+ else
+ conn.close
+ end
+ end
+ end
+ end
+
+ def initialize(remote_uri) # :nodoc:
+ @uri = remote_uri
+ @protocol = DRbProtocol.open(remote_uri, DRb.config)
+ end
+ attr_reader :uri # :nodoc:
+
+ def send_message(ref, msg_id, arg, block) # :nodoc:
+ @protocol.send_request(ref, msg_id, arg, block)
+ @protocol.recv_reply
+ end
+
+ def close # :nodoc:
+ @protocol.close
+ @protocol = nil
+ end
+
+ def alive? # :nodoc:
+ return false unless @protocol
+ @protocol.alive?
+ end
+ end
+
+ # Class representing a drb server instance.
+ #
+ # A DRbServer must be running in the local process before any incoming
+ # dRuby calls can be accepted, or any local objects can be passed as
+ # dRuby references to remote processes, even if those local objects are
+ # never actually called remotely. You do not need to start a DRbServer
+ # in the local process if you are only making outgoing dRuby calls
+ # passing marshalled parameters.
+ #
+ # Unless multiple servers are being used, the local DRbServer is normally
+ # started by calling DRb.start_service.
+ class DRbServer
+ @@acl = nil
+ @@idconv = DRbIdConv.new
+ @@secondary_server = nil
+ @@argc_limit = 256
+ @@load_limit = 0xffffffff
+ @@verbose = false
+
+ # Set the default value for the :argc_limit option.
+ #
+ # See #new(). The initial default value is 256.
+ def self.default_argc_limit(argc)
+ @@argc_limit = argc
+ end
+
+ # Set the default value for the :load_limit option.
+ #
+ # See #new(). The initial default value is 25 MB.
+ def self.default_load_limit(sz)
+ @@load_limit = sz
+ end
+
+ # Set the default access control list to +acl+. The default ACL is +nil+.
+ #
+ # See also DRb::ACL and #new()
+ def self.default_acl(acl)
+ @@acl = acl
+ end
+
+ # Set the default value for the :id_conv option.
+ #
+ # See #new(). The initial default value is a DRbIdConv instance.
+ def self.default_id_conv(idconv)
+ @@idconv = idconv
+ end
+
+ # Set the default value of the :verbose option.
+ #
+ # See #new(). The initial default value is false.
+ def self.verbose=(on)
+ @@verbose = on
+ end
+
+ # Get the default value of the :verbose option.
+ def self.verbose
+ @@verbose
+ end
+
+ def self.make_config(hash={}) # :nodoc:
+ default_config = {
+ :idconv => @@idconv,
+ :verbose => @@verbose,
+ :tcp_acl => @@acl,
+ :load_limit => @@load_limit,
+ :argc_limit => @@argc_limit,
+ }
+ default_config.update(hash)
+ end
+
+ # Create a new DRbServer instance.
+ #
+ # +uri+ is the URI to bind to. This is normally of the form
+ # 'druby://<hostname>:<port>' where <hostname> is a hostname of
+ # the local machine. If nil, then the system's default hostname
+ # will be bound to, on a port selected by the system; these value
+ # can be retrieved from the +uri+ attribute. 'druby:' specifies
+ # the default dRuby transport protocol: another protocol, such
+ # as 'drbunix:', can be specified instead.
+ #
+ # +front+ is the front object for the server, that is, the object
+ # to which remote method calls on the server will be passed. If
+ # nil, then the server will not accept remote method calls.
+ #
+ # If +config_or_acl+ is a hash, it is the configuration to
+ # use for this server. The following options are recognised:
+ #
+ # :idconv :: an id-to-object conversion object. This defaults
+ # to an instance of the class DRb::DRbIdConv.
+ # :verbose :: if true, all unsuccessful remote calls on objects
+ # in the server will be logged to $stdout. false
+ # by default.
+ # :tcp_acl :: the access control list for this server. See
+ # the ACL class from the main dRuby distribution.
+ # :load_limit :: the maximum message size in bytes accepted by
+ # the server. Defaults to 25 MB (26214400).
+ # :argc_limit :: the maximum number of arguments to a remote
+ # method accepted by the server. Defaults to
+ # 256.
+ # The default values of these options can be modified on
+ # a class-wide basis by the class methods #default_argc_limit,
+ # #default_load_limit, #default_acl, #default_id_conv,
+ # and #verbose=
+ #
+ # If +config_or_acl+ is not a hash, but is not nil, it is
+ # assumed to be the access control list for this server.
+ # See the :tcp_acl option for more details.
+ #
+ # If no other server is currently set as the primary server,
+ # this will become the primary server.
+ #
+ # The server will immediately start running in its own thread.
+ def initialize(uri=nil, front=nil, config_or_acl=nil)
+ if Hash === config_or_acl
+ config = config_or_acl.dup
+ else
+ acl = config_or_acl || @@acl
+ config = {
+ :tcp_acl => acl
+ }
+ end
+
+ @config = self.class.make_config(config)
+
+ @protocol = DRbProtocol.open_server(uri, @config)
+ @uri = @protocol.uri
+ @exported_uri = [@uri]
+
+ @front = front
+ @idconv = @config[:idconv]
+
+ @grp = ThreadGroup.new
+ @thread = run
+
+ DRb.regist_server(self)
+ end
+
+ # The URI of this DRbServer.
+ attr_reader :uri
+
+ # The main thread of this DRbServer.
+ #
+ # This is the thread that listens for and accepts connections
+ # from clients, not that handles each client's request-response
+ # session.
+ attr_reader :thread
+
+ # The front object of the DRbServer.
+ #
+ # This object receives remote method calls made on the server's
+ # URI alone, with an object id.
+ attr_reader :front
+
+ # The configuration of this DRbServer
+ attr_reader :config
+
+ # Set whether to operate in verbose mode.
+ #
+ # In verbose mode, failed calls are logged to stdout.
+ def verbose=(v); @config[:verbose]=v; end
+
+ # Get whether the server is in verbose mode.
+ #
+ # In verbose mode, failed calls are logged to stdout.
+ def verbose; @config[:verbose]; end
+
+ # Is this server alive?
+ def alive?
+ @thread.alive?
+ end
+
+ # Is +uri+ the URI for this server?
+ def here?(uri)
+ @exported_uri.include?(uri)
+ end
+
+ # Stop this server.
+ def stop_service
+ DRb.remove_server(self)
+ if Thread.current['DRb'] && Thread.current['DRb']['server'] == self
+ Thread.current['DRb']['stop_service'] = true
+ else
+ shutdown
+ end
+ end
+
+ # Convert a dRuby reference to the local object it refers to.
+ def to_obj(ref)
+ return front if ref.nil?
+ return front[ref.to_s] if DRbURIOption === ref
+ @idconv.to_obj(ref)
+ end
+
+ # Convert a local object to a dRuby reference.
+ def to_id(obj)
+ return nil if obj.__id__ == front.__id__
+ @idconv.to_id(obj)
+ end
+
+ private
+
+ def shutdown
+ current = Thread.current
+ if @protocol.respond_to? :shutdown
+ @protocol.shutdown
+ else
+ [@thread, *@grp.list].each { |thread|
+ thread.kill unless thread == current # xxx: Thread#kill
+ }
+ end
+ @thread.join unless @thread == current
+ end
+
+ ##
+ # Starts the DRb main loop in a new thread.
+
+ def run
+ Thread.start do
+ begin
+ while main_loop
+ end
+ ensure
+ @protocol.close if @protocol
+ end
+ end
+ end
+
+ # List of insecure methods.
+ #
+ # These methods are not callable via dRuby.
+ INSECURE_METHOD = [
+ :__send__
+ ]
+
+ # Has a method been included in the list of insecure methods?
+ def insecure_method?(msg_id)
+ INSECURE_METHOD.include?(msg_id)
+ end
+
+ # Coerce an object to a string, providing our own representation if
+ # to_s is not defined for the object.
+ def any_to_s(obj)
+ "#{obj}:#{obj.class}"
+ rescue
+ Kernel.instance_method(:to_s).bind_call(obj)
+ end
+
+ # Check that a method is callable via dRuby.
+ #
+ # +obj+ is the object we want to invoke the method on. +msg_id+ is the
+ # method name, as a Symbol.
+ #
+ # If the method is an insecure method (see #insecure_method?) a
+ # SecurityError is thrown. If the method is private or undefined,
+ # a NameError is thrown.
+ def check_insecure_method(obj, msg_id)
+ return true if Proc === obj && msg_id == :__drb_yield
+ raise(ArgumentError, "#{any_to_s(msg_id)} is not a symbol") unless Symbol == msg_id.class
+ raise(SecurityError, "insecure method `#{msg_id}'") if insecure_method?(msg_id)
+
+ case obj
+ when Object
+ if obj.private_methods.include?(msg_id)
+ desc = any_to_s(obj)
+ raise NoMethodError, "private method `#{msg_id}' called for #{desc}"
+ elsif obj.protected_methods.include?(msg_id)
+ desc = any_to_s(obj)
+ raise NoMethodError, "protected method `#{msg_id}' called for #{desc}"
+ else
+ true
+ end
+ else
+ if Kernel.instance_method(:private_methods).bind(obj).call.include?(msg_id)
+ desc = any_to_s(obj)
+ raise NoMethodError, "private method `#{msg_id}' called for #{desc}"
+ elsif Kernel.instance_method(:protected_methods).bind(obj).call.include?(msg_id)
+ desc = any_to_s(obj)
+ raise NoMethodError, "protected method `#{msg_id}' called for #{desc}"
+ else
+ true
+ end
+ end
+ end
+ public :check_insecure_method
+
+ class InvokeMethod # :nodoc:
+ def initialize(drb_server, client)
+ @drb_server = drb_server
+ @client = client
+ end
+
+ def perform
+ begin
+ setup_message
+ ensure
+ @result = nil
+ @succ = false
+ end
+
+ if @block
+ @result = perform_with_block
+ else
+ @result = perform_without_block
+ end
+ @succ = true
+ case @result
+ when Array
+ if @msg_id == :to_ary
+ @result = DRbArray.new(@result)
+ end
+ end
+ return @succ, @result
+ rescue NoMemoryError, SystemExit, SystemStackError, SecurityError
+ raise
+ rescue Exception
+ @result = $!
+ return @succ, @result
+ end
+
+ private
+ def init_with_client
+ obj, msg, argv, block = @client.recv_request
+ @obj = obj
+ @msg_id = msg.intern
+ @argv = argv
+ @block = block
+ end
+
+ def check_insecure_method
+ @drb_server.check_insecure_method(@obj, @msg_id)
+ end
+
+ def setup_message
+ init_with_client
+ check_insecure_method
+ end
+
+ def perform_without_block
+ if Proc === @obj && @msg_id == :__drb_yield
+ if @argv.size == 1
+ ary = @argv
+ else
+ ary = [@argv]
+ end
+ ary.collect(&@obj)[0]
+ else
+ @obj.__send__(@msg_id, *@argv)
+ end
+ end
+
+ end
+
+ require_relative 'invokemethod'
+ class InvokeMethod
+ include InvokeMethod18Mixin
+ end
+
+ def error_print(exception)
+ exception.backtrace.inject(true) do |first, x|
+ if first
+ $stderr.puts "#{x}: #{exception} (#{exception.class})"
+ else
+ $stderr.puts "\tfrom #{x}"
+ end
+ false
+ end
+ end
+
+ # The main loop performed by a DRbServer's internal thread.
+ #
+ # Accepts a connection from a client, and starts up its own
+ # thread to handle it. This thread loops, receiving requests
+ # from the client, invoking them on a local object, and
+ # returning responses, until the client closes the connection
+ # or a local method call fails.
+ def main_loop
+ client0 = @protocol.accept
+ return nil if !client0
+ Thread.start(client0) do |client|
+ @grp.add Thread.current
+ Thread.current['DRb'] = { 'client' => client ,
+ 'server' => self }
+ DRb.mutex.synchronize do
+ client_uri = client.uri
+ @exported_uri << client_uri unless @exported_uri.include?(client_uri)
+ end
+ _last_invoke_method = nil
+ loop do
+ begin
+ succ = false
+ invoke_method = InvokeMethod.new(self, client)
+ succ, result = invoke_method.perform
+ error_print(result) if !succ && verbose
+ unless DRbConnError === result && result.message == 'connection closed'
+ client.send_reply(succ, result)
+ end
+ rescue Exception => e
+ error_print(e) if verbose
+ ensure
+ _last_invoke_method = invoke_method
+ client.close unless succ
+ if Thread.current['DRb']['stop_service']
+ shutdown
+ break
+ end
+ break unless succ
+ end
+ end
+ end
+ end
+ end
+
+ @primary_server = nil
+
+ # Start a dRuby server locally.
+ #
+ # The new dRuby server will become the primary server, even
+ # if another server is currently the primary server.
+ #
+ # +uri+ is the URI for the server to bind to. If nil,
+ # the server will bind to random port on the default local host
+ # name and use the default dRuby protocol.
+ #
+ # +front+ is the server's front object. This may be nil.
+ #
+ # +config+ is the configuration for the new server. This may
+ # be nil.
+ #
+ # See DRbServer::new.
+ def start_service(uri=nil, front=nil, config=nil)
+ @primary_server = DRbServer.new(uri, front, config)
+ end
+ module_function :start_service
+
+ # The primary local dRuby server.
+ #
+ # This is the server created by the #start_service call.
+ attr_accessor :primary_server
+ module_function :primary_server=, :primary_server
+
+ # Get the 'current' server.
+ #
+ # In the context of execution taking place within the main
+ # thread of a dRuby server (typically, as a result of a remote
+ # call on the server or one of its objects), the current
+ # server is that server. Otherwise, the current server is
+ # the primary server.
+ #
+ # If the above rule fails to find a server, a DRbServerNotFound
+ # error is raised.
+ def current_server
+ drb = Thread.current['DRb']
+ server = (drb && drb['server']) ? drb['server'] : @primary_server
+ raise DRbServerNotFound unless server
+ return server
+ end
+ module_function :current_server
+
+ # Stop the local dRuby server.
+ #
+ # This operates on the primary server. If there is no primary
+ # server currently running, it is a noop.
+ def stop_service
+ @primary_server.stop_service if @primary_server
+ @primary_server = nil
+ end
+ module_function :stop_service
+
+ # Get the URI defining the local dRuby space.
+ #
+ # This is the URI of the current server. See #current_server.
+ def uri
+ drb = Thread.current['DRb']
+ client = (drb && drb['client'])
+ if client
+ uri = client.uri
+ return uri if uri
+ end
+ current_server.uri
+ end
+ module_function :uri
+
+ # Is +uri+ the URI for the current local server?
+ def here?(uri)
+ current_server.here?(uri) rescue false
+ # (current_server.uri rescue nil) == uri
+ end
+ module_function :here?
+
+ # Get the configuration of the current server.
+ #
+ # If there is no current server, this returns the default configuration.
+ # See #current_server and DRbServer::make_config.
+ def config
+ current_server.config
+ rescue
+ DRbServer.make_config
+ end
+ module_function :config
+
+ # Get the front object of the current server.
+ #
+ # This raises a DRbServerNotFound error if there is no current server.
+ # See #current_server.
+ def front
+ current_server.front
+ end
+ module_function :front
+
+ # Convert a reference into an object using the current server.
+ #
+ # This raises a DRbServerNotFound error if there is no current server.
+ # See #current_server.
+ def to_obj(ref)
+ current_server.to_obj(ref)
+ end
+
+ # Get a reference id for an object using the current server.
+ #
+ # This raises a DRbServerNotFound error if there is no current server.
+ # See #current_server.
+ def to_id(obj)
+ current_server.to_id(obj)
+ end
+ module_function :to_id
+ module_function :to_obj
+
+ # Get the thread of the primary server.
+ #
+ # This returns nil if there is no primary server. See #primary_server.
+ def thread
+ @primary_server ? @primary_server.thread : nil
+ end
+ module_function :thread
+
+ # Set the default id conversion object.
+ #
+ # This is expected to be an instance such as DRb::DRbIdConv that responds to
+ # #to_id and #to_obj that can convert objects to and from DRb references.
+ #
+ # See DRbServer#default_id_conv.
+ def install_id_conv(idconv)
+ DRbServer.default_id_conv(idconv)
+ end
+ module_function :install_id_conv
+
+ # Set the default ACL to +acl+.
+ #
+ # See DRb::DRbServer.default_acl.
+ def install_acl(acl)
+ DRbServer.default_acl(acl)
+ end
+ module_function :install_acl
+
+ @mutex = Thread::Mutex.new
+ def mutex # :nodoc:
+ @mutex
+ end
+ module_function :mutex
+
+ @server = {}
+ # Registers +server+ with DRb.
+ #
+ # This is called when a new DRb::DRbServer is created.
+ #
+ # If there is no primary server then +server+ becomes the primary server.
+ #
+ # Example:
+ #
+ # require 'drb'
+ #
+ # s = DRb::DRbServer.new # automatically calls regist_server
+ # DRb.fetch_server s.uri #=> #<DRb::DRbServer:0x...>
+ def regist_server(server)
+ @server[server.uri] = server
+ mutex.synchronize do
+ @primary_server = server unless @primary_server
+ end
+ end
+ module_function :regist_server
+
+ # Removes +server+ from the list of registered servers.
+ def remove_server(server)
+ @server.delete(server.uri)
+ mutex.synchronize do
+ if @primary_server == server
+ @primary_server = nil
+ end
+ end
+ end
+ module_function :remove_server
+
+ # Retrieves the server with the given +uri+.
+ #
+ # See also regist_server and remove_server.
+ def fetch_server(uri)
+ @server[uri]
+ end
+ module_function :fetch_server
+end
+
+# :stopdoc:
+DRbObject = DRb::DRbObject
+DRbUndumped = DRb::DRbUndumped
+DRbIdConv = DRb::DRbIdConv
diff --git a/lib/drb/eq.rb b/lib/drb/eq.rb
new file mode 100644
index 0000000000..15ca5cae42
--- /dev/null
+++ b/lib/drb/eq.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: false
+module DRb
+ class DRbObject # :nodoc:
+ def ==(other)
+ return false unless DRbObject === other
+ (@ref == other.__drbref) && (@uri == other.__drburi)
+ end
+
+ def hash
+ [@uri, @ref].hash
+ end
+
+ alias eql? ==
+ end
+end
diff --git a/lib/drb/extserv.rb b/lib/drb/extserv.rb
new file mode 100644
index 0000000000..9523fe84e3
--- /dev/null
+++ b/lib/drb/extserv.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: false
+=begin
+ external service
+ Copyright (c) 2000,2002 Masatoshi SEKI
+=end
+
+require_relative 'drb'
+require 'monitor'
+
+module DRb
+ class ExtServ
+ include MonitorMixin
+ include DRbUndumped
+
+ def initialize(there, name, server=nil)
+ super()
+ @server = server || DRb::primary_server
+ @name = name
+ ro = DRbObject.new(nil, there)
+ synchronize do
+ @invoker = ro.register(name, DRbObject.new(self, @server.uri))
+ end
+ end
+ attr_reader :server
+
+ def front
+ DRbObject.new(nil, @server.uri)
+ end
+
+ def stop_service
+ synchronize do
+ @invoker.unregister(@name)
+ server = @server
+ @server = nil
+ server.stop_service
+ true
+ end
+ end
+
+ def alive?
+ @server ? @server.alive? : false
+ end
+ end
+end
diff --git a/lib/drb/extservm.rb b/lib/drb/extservm.rb
new file mode 100644
index 0000000000..9333a108e5
--- /dev/null
+++ b/lib/drb/extservm.rb
@@ -0,0 +1,94 @@
+# frozen_string_literal: false
+=begin
+ external service manager
+ Copyright (c) 2000 Masatoshi SEKI
+=end
+
+require_relative 'drb'
+require 'monitor'
+
+module DRb
+ class ExtServManager
+ include DRbUndumped
+ include MonitorMixin
+
+ @@command = {}
+
+ def self.command
+ @@command
+ end
+
+ def self.command=(cmd)
+ @@command = cmd
+ end
+
+ def initialize
+ super()
+ @cond = new_cond
+ @servers = {}
+ @waiting = []
+ @queue = Thread::Queue.new
+ @thread = invoke_thread
+ @uri = nil
+ end
+ attr_accessor :uri
+
+ def service(name)
+ synchronize do
+ while true
+ server = @servers[name]
+ return server if server && server.alive? # server may be `false'
+ invoke_service(name)
+ @cond.wait
+ end
+ end
+ end
+
+ def register(name, ro)
+ synchronize do
+ @servers[name] = ro
+ @cond.signal
+ end
+ self
+ end
+ alias regist register
+
+ def unregister(name)
+ synchronize do
+ @servers.delete(name)
+ end
+ end
+ alias unregist unregister
+
+ private
+ def invoke_thread
+ Thread.new do
+ while name = @queue.pop
+ invoke_service_command(name, @@command[name])
+ end
+ end
+ end
+
+ def invoke_service(name)
+ @queue.push(name)
+ end
+
+ def invoke_service_command(name, command)
+ raise "invalid command. name: #{name}" unless command
+ synchronize do
+ return if @servers.include?(name)
+ @servers[name] = false
+ end
+ uri = @uri || DRb.uri
+ if command.respond_to? :to_ary
+ command = command.to_ary + [uri, name]
+ pid = spawn(*command)
+ else
+ pid = spawn("#{command} #{uri} #{name}")
+ end
+ th = Process.detach(pid)
+ th[:drb_service] = name
+ th
+ end
+ end
+end
diff --git a/lib/drb/gw.rb b/lib/drb/gw.rb
new file mode 100644
index 0000000000..65a525476e
--- /dev/null
+++ b/lib/drb/gw.rb
@@ -0,0 +1,161 @@
+# frozen_string_literal: false
+require_relative 'drb'
+require 'monitor'
+
+module DRb
+
+ # Gateway id conversion forms a gateway between different DRb protocols or
+ # networks.
+ #
+ # The gateway needs to install this id conversion and create servers for
+ # each of the protocols or networks it will be a gateway between. It then
+ # needs to create a server that attaches to each of these networks. For
+ # example:
+ #
+ # require 'drb/drb'
+ # require 'drb/unix'
+ # require 'drb/gw'
+ #
+ # DRb.install_id_conv DRb::GWIdConv.new
+ # gw = DRb::GW.new
+ # s1 = DRb::DRbServer.new 'drbunix:/path/to/gateway', gw
+ # s2 = DRb::DRbServer.new 'druby://example:10000', gw
+ #
+ # s1.thread.join
+ # s2.thread.join
+ #
+ # Each client must register services with the gateway, for example:
+ #
+ # DRb.start_service 'drbunix:', nil # an anonymous server
+ # gw = DRbObject.new nil, 'drbunix:/path/to/gateway'
+ # gw[:unix] = some_service
+ # DRb.thread.join
+
+ class GWIdConv < DRbIdConv
+ def to_obj(ref) # :nodoc:
+ if Array === ref && ref[0] == :DRbObject
+ return DRbObject.new_with(ref[1], ref[2])
+ end
+ super(ref)
+ end
+ end
+
+ # The GW provides a synchronized store for participants in the gateway to
+ # communicate.
+
+ class GW
+ include MonitorMixin
+
+ # Creates a new GW
+
+ def initialize
+ super()
+ @hash = {}
+ end
+
+ # Retrieves +key+ from the GW
+
+ def [](key)
+ synchronize do
+ @hash[key]
+ end
+ end
+
+ # Stores value +v+ at +key+ in the GW
+
+ def []=(key, v)
+ synchronize do
+ @hash[key] = v
+ end
+ end
+ end
+
+ class DRbObject # :nodoc:
+ def self._load(s)
+ uri, ref = Marshal.load(s)
+ if DRb.uri == uri
+ return ref ? DRb.to_obj(ref) : DRb.front
+ end
+
+ self.new_with(DRb.uri, [:DRbObject, uri, ref])
+ end
+
+ def _dump(lv)
+ if DRb.uri == @uri
+ if Array === @ref && @ref[0] == :DRbObject
+ Marshal.dump([@ref[1], @ref[2]])
+ else
+ Marshal.dump([@uri, @ref]) # ??
+ end
+ else
+ Marshal.dump([DRb.uri, [:DRbObject, @uri, @ref]])
+ end
+ end
+ end
+end
+
+=begin
+DRb.install_id_conv(DRb::GWIdConv.new)
+
+front = DRb::GW.new
+
+s1 = DRb::DRbServer.new('drbunix:/tmp/gw_b_a', front)
+s2 = DRb::DRbServer.new('drbunix:/tmp/gw_b_c', front)
+
+s1.thread.join
+s2.thread.join
+=end
+
+=begin
+# foo.rb
+
+require 'drb/drb'
+
+class Foo
+ include DRbUndumped
+ def initialize(name, peer=nil)
+ @name = name
+ @peer = peer
+ end
+
+ def ping(obj)
+ puts "#{@name}: ping: #{obj.inspect}"
+ @peer.ping(self) if @peer
+ end
+end
+=end
+
+=begin
+# gw_a.rb
+require 'drb/unix'
+require 'foo'
+
+obj = Foo.new('a')
+DRb.start_service("drbunix:/tmp/gw_a", obj)
+
+robj = DRbObject.new_with_uri('drbunix:/tmp/gw_b_a')
+robj[:a] = obj
+
+DRb.thread.join
+=end
+
+=begin
+# gw_c.rb
+require 'drb/unix'
+require 'foo'
+
+foo = Foo.new('c', nil)
+
+DRb.start_service("drbunix:/tmp/gw_c", nil)
+
+robj = DRbObject.new_with_uri("drbunix:/tmp/gw_b_c")
+
+puts "c->b"
+a = robj[:a]
+sleep 2
+
+a.ping(foo)
+
+DRb.thread.join
+=end
+
diff --git a/lib/drb/invokemethod.rb b/lib/drb/invokemethod.rb
new file mode 100644
index 0000000000..0fae6d52b6
--- /dev/null
+++ b/lib/drb/invokemethod.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: false
+# for ruby-1.8.0
+
+module DRb # :nodoc: all
+ class DRbServer
+ module InvokeMethod18Mixin
+ def block_yield(x)
+ if x.size == 1 && x[0].class == Array
+ x[0] = DRbArray.new(x[0])
+ end
+ @block.call(*x)
+ end
+
+ def perform_with_block
+ @obj.__send__(@msg_id, *@argv) do |*x|
+ jump_error = nil
+ begin
+ block_value = block_yield(x)
+ rescue LocalJumpError
+ jump_error = $!
+ end
+ if jump_error
+ case jump_error.reason
+ when :break
+ break(jump_error.exit_value)
+ else
+ raise jump_error
+ end
+ end
+ block_value
+ end
+ end
+ end
+ end
+end
diff --git a/lib/drb/observer.rb b/lib/drb/observer.rb
new file mode 100644
index 0000000000..0fb7301edf
--- /dev/null
+++ b/lib/drb/observer.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: false
+require 'observer'
+
+module DRb
+ # The Observable module extended to DRb. See Observable for details.
+ module DRbObservable
+ include Observable
+
+ # Notifies observers of a change in state. See also
+ # Observable#notify_observers
+ def notify_observers(*arg)
+ if defined? @observer_state and @observer_state
+ if defined? @observer_peers
+ @observer_peers.each do |observer, method|
+ begin
+ observer.__send__(method, *arg)
+ rescue
+ delete_observer(observer)
+ end
+ end
+ end
+ @observer_state = false
+ end
+ end
+ end
+end
diff --git a/lib/drb/ssl.rb b/lib/drb/ssl.rb
new file mode 100644
index 0000000000..54ab1ef395
--- /dev/null
+++ b/lib/drb/ssl.rb
@@ -0,0 +1,344 @@
+# frozen_string_literal: false
+require 'socket'
+require 'openssl'
+require_relative 'drb'
+require 'singleton'
+
+module DRb
+
+ # The protocol for DRb over an SSL socket
+ #
+ # The URI for a DRb socket over SSL is:
+ # <code>drbssl://<host>:<port>?<option></code>. The option is optional
+ class DRbSSLSocket < DRbTCPSocket
+
+ # SSLConfig handles the needed SSL information for establishing a
+ # DRbSSLSocket connection, including generating the X509 / RSA pair.
+ #
+ # An instance of this config can be passed to DRbSSLSocket.new,
+ # DRbSSLSocket.open and DRbSSLSocket.open_server
+ #
+ # See DRb::DRbSSLSocket::SSLConfig.new for more details
+ class SSLConfig
+
+ # Default values for a SSLConfig instance.
+ #
+ # See DRb::DRbSSLSocket::SSLConfig.new for more details
+ DEFAULT = {
+ :SSLCertificate => nil,
+ :SSLPrivateKey => nil,
+ :SSLClientCA => nil,
+ :SSLCACertificatePath => nil,
+ :SSLCACertificateFile => nil,
+ :SSLTmpDhCallback => nil,
+ :SSLVerifyMode => ::OpenSSL::SSL::VERIFY_NONE,
+ :SSLVerifyDepth => nil,
+ :SSLVerifyCallback => nil, # custom verification
+ :SSLCertificateStore => nil,
+ # Must specify if you use auto generated certificate.
+ :SSLCertName => nil, # e.g. [["CN","fqdn.example.com"]]
+ :SSLCertComment => "Generated by Ruby/OpenSSL"
+ }
+
+ # Create a new DRb::DRbSSLSocket::SSLConfig instance
+ #
+ # The DRb::DRbSSLSocket will take either a +config+ Hash or an instance
+ # of SSLConfig, and will setup the certificate for its session for the
+ # configuration. If want it to generate a generic certificate, the bare
+ # minimum is to provide the :SSLCertName
+ #
+ # === Config options
+ #
+ # From +config+ Hash:
+ #
+ # :SSLCertificate ::
+ # An instance of OpenSSL::X509::Certificate. If this is not provided,
+ # then a generic X509 is generated, with a correspond :SSLPrivateKey
+ #
+ # :SSLPrivateKey ::
+ # A private key instance, like OpenSSL::PKey::RSA. This key must be
+ # the key that signed the :SSLCertificate
+ #
+ # :SSLClientCA ::
+ # An OpenSSL::X509::Certificate, or Array of certificates that will
+ # used as ClientCAs in the SSL Context
+ #
+ # :SSLCACertificatePath ::
+ # A path to the directory of CA certificates. The certificates must
+ # be in PEM format.
+ #
+ # :SSLCACertificateFile ::
+ # A path to a CA certificate file, in PEM format.
+ #
+ # :SSLTmpDhCallback ::
+ # A DH callback. See OpenSSL::SSL::SSLContext.tmp_dh_callback
+ #
+ # :SSLVerifyMode ::
+ # This is the SSL verification mode. See OpenSSL::SSL::VERIFY_* for
+ # available modes. The default is OpenSSL::SSL::VERIFY_NONE
+ #
+ # :SSLVerifyDepth ::
+ # Number of CA certificates to walk, when verifying a certificate
+ # chain.
+ #
+ # :SSLVerifyCallback ::
+ # A callback to be used for additional verification. See
+ # OpenSSL::SSL::SSLContext.verify_callback
+ #
+ # :SSLCertificateStore ::
+ # A OpenSSL::X509::Store used for verification of certificates
+ #
+ # :SSLCertName ::
+ # Issuer name for the certificate. This is required when generating
+ # the certificate (if :SSLCertificate and :SSLPrivateKey were not
+ # given). The value of this is to be an Array of pairs:
+ #
+ # [["C", "Raleigh"], ["ST","North Carolina"],
+ # ["CN","fqdn.example.com"]]
+ #
+ # See also OpenSSL::X509::Name
+ #
+ # :SSLCertComment ::
+ # A comment to be used for generating the certificate. The default is
+ # "Generated by Ruby/OpenSSL"
+ #
+ #
+ # === Example
+ #
+ # These values can be added after the fact, like a Hash.
+ #
+ # require 'drb/ssl'
+ # c = DRb::DRbSSLSocket::SSLConfig.new {}
+ # c[:SSLCertificate] =
+ # OpenSSL::X509::Certificate.new(File.read('mycert.crt'))
+ # c[:SSLPrivateKey] = OpenSSL::PKey::RSA.new(File.read('mycert.key'))
+ # c[:SSLVerifyMode] = OpenSSL::SSL::VERIFY_PEER
+ # c[:SSLCACertificatePath] = "/etc/ssl/certs/"
+ # c.setup_certificate
+ #
+ # or
+ #
+ # require 'drb/ssl'
+ # c = DRb::DRbSSLSocket::SSLConfig.new({
+ # :SSLCertName => [["CN" => DRb::DRbSSLSocket.getservername]]
+ # })
+ # c.setup_certificate
+ #
+ def initialize(config)
+ @config = config
+ @cert = config[:SSLCertificate]
+ @pkey = config[:SSLPrivateKey]
+ @ssl_ctx = nil
+ end
+
+ # A convenience method to access the values like a Hash
+ def [](key);
+ @config[key] || DEFAULT[key]
+ end
+
+ # Connect to IO +tcp+, with context of the current certificate
+ # configuration
+ def connect(tcp)
+ ssl = ::OpenSSL::SSL::SSLSocket.new(tcp, @ssl_ctx)
+ ssl.sync = true
+ ssl.connect
+ ssl
+ end
+
+ # Accept connection to IO +tcp+, with context of the current certificate
+ # configuration
+ def accept(tcp)
+ ssl = OpenSSL::SSL::SSLSocket.new(tcp, @ssl_ctx)
+ ssl.sync = true
+ ssl.accept
+ ssl
+ end
+
+ # Ensures that :SSLCertificate and :SSLPrivateKey have been provided
+ # or that a new certificate is generated with the other parameters
+ # provided.
+ def setup_certificate
+ if @cert && @pkey
+ return
+ end
+
+ rsa = OpenSSL::PKey::RSA.new(2048){|p, n|
+ next unless self[:verbose]
+ case p
+ when 0; $stderr.putc "." # BN_generate_prime
+ when 1; $stderr.putc "+" # BN_generate_prime
+ when 2; $stderr.putc "*" # searching good prime,
+ # n = #of try,
+ # but also data from BN_generate_prime
+ when 3; $stderr.putc "\n" # found good prime, n==0 - p, n==1 - q,
+ # but also data from BN_generate_prime
+ else; $stderr.putc "*" # BN_generate_prime
+ end
+ }
+
+ cert = OpenSSL::X509::Certificate.new
+ cert.version = 3
+ cert.serial = 0
+ name = OpenSSL::X509::Name.new(self[:SSLCertName])
+ cert.subject = name
+ cert.issuer = name
+ cert.not_before = Time.now
+ cert.not_after = Time.now + (365*24*60*60)
+ cert.public_key = rsa.public_key
+
+ ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
+ cert.extensions = [
+ ef.create_extension("basicConstraints","CA:FALSE"),
+ ef.create_extension("subjectKeyIdentifier", "hash") ]
+ ef.issuer_certificate = cert
+ cert.add_extension(ef.create_extension("authorityKeyIdentifier",
+ "keyid:always,issuer:always"))
+ if comment = self[:SSLCertComment]
+ cert.add_extension(ef.create_extension("nsComment", comment))
+ end
+ cert.sign(rsa, "SHA256")
+
+ @cert = cert
+ @pkey = rsa
+ end
+
+ # Establish the OpenSSL::SSL::SSLContext with the configuration
+ # parameters provided.
+ def setup_ssl_context
+ ctx = ::OpenSSL::SSL::SSLContext.new
+ ctx.cert = @cert
+ ctx.key = @pkey
+ ctx.client_ca = self[:SSLClientCA]
+ ctx.ca_path = self[:SSLCACertificatePath]
+ ctx.ca_file = self[:SSLCACertificateFile]
+ ctx.tmp_dh_callback = self[:SSLTmpDhCallback]
+ ctx.verify_mode = self[:SSLVerifyMode]
+ ctx.verify_depth = self[:SSLVerifyDepth]
+ ctx.verify_callback = self[:SSLVerifyCallback]
+ ctx.cert_store = self[:SSLCertificateStore]
+ @ssl_ctx = ctx
+ end
+ end
+
+ # Parse the dRuby +uri+ for an SSL connection.
+ #
+ # Expects drbssl://...
+ #
+ # Raises DRbBadScheme or DRbBadURI if +uri+ is not matching or malformed
+ def self.parse_uri(uri) # :nodoc:
+ if /\Adrbssl:\/\/(.*?):(\d+)(\?(.*))?\z/ =~ uri
+ host = $1
+ port = $2.to_i
+ option = $4
+ [host, port, option]
+ else
+ raise(DRbBadScheme, uri) unless uri.start_with?('drbssl:')
+ raise(DRbBadURI, 'can\'t parse uri:' + uri)
+ end
+ end
+
+ # Return an DRb::DRbSSLSocket instance as a client-side connection,
+ # with the SSL connected. This is called from DRb::start_service or while
+ # connecting to a remote object:
+ #
+ # DRb.start_service 'drbssl://localhost:0', front, config
+ #
+ # +uri+ is the URI we are connected to,
+ # <code>'drbssl://localhost:0'</code> above, +config+ is our
+ # configuration. Either a Hash or DRb::DRbSSLSocket::SSLConfig
+ def self.open(uri, config)
+ host, port, = parse_uri(uri)
+ soc = TCPSocket.open(host, port)
+ ssl_conf = SSLConfig::new(config)
+ ssl_conf.setup_ssl_context
+ ssl = ssl_conf.connect(soc)
+ self.new(uri, ssl, ssl_conf, true)
+ end
+
+ # Returns a DRb::DRbSSLSocket instance as a server-side connection, with
+ # the SSL connected. This is called from DRb::start_service or while
+ # connecting to a remote object:
+ #
+ # DRb.start_service 'drbssl://localhost:0', front, config
+ #
+ # +uri+ is the URI we are connected to,
+ # <code>'drbssl://localhost:0'</code> above, +config+ is our
+ # configuration. Either a Hash or DRb::DRbSSLSocket::SSLConfig
+ def self.open_server(uri, config)
+ uri = 'drbssl://:0' unless uri
+ host, port, = parse_uri(uri)
+ if host.size == 0
+ host = getservername
+ soc = open_server_inaddr_any(host, port)
+ else
+ soc = TCPServer.open(host, port)
+ end
+ port = soc.addr[1] if port == 0
+ @uri = "drbssl://#{host}:#{port}"
+
+ ssl_conf = SSLConfig.new(config)
+ ssl_conf.setup_certificate
+ ssl_conf.setup_ssl_context
+ self.new(@uri, soc, ssl_conf, false)
+ end
+
+ # This is a convenience method to parse +uri+ and separate out any
+ # additional options appended in the +uri+.
+ #
+ # Returns an option-less uri and the option => [uri,option]
+ #
+ # The +config+ is completely unused, so passing nil is sufficient.
+ def self.uri_option(uri, config) # :nodoc:
+ host, port, option = parse_uri(uri)
+ return "drbssl://#{host}:#{port}", option
+ end
+
+ # Create a DRb::DRbSSLSocket instance.
+ #
+ # +uri+ is the URI we are connected to.
+ # +soc+ is the tcp socket we are bound to.
+ # +config+ is our configuration. Either a Hash or SSLConfig
+ # +is_established+ is a boolean of whether +soc+ is currently established
+ #
+ # This is called automatically based on the DRb protocol.
+ def initialize(uri, soc, config, is_established)
+ @ssl = is_established ? soc : nil
+ super(uri, soc.to_io, config)
+ end
+
+ # Returns the SSL stream
+ def stream; @ssl; end # :nodoc:
+
+ # Closes the SSL stream before closing the dRuby connection.
+ def close # :nodoc:
+ if @ssl
+ @ssl.close
+ @ssl = nil
+ end
+ super
+ end
+
+ def accept # :nodoc:
+ begin
+ while true
+ soc = accept_or_shutdown
+ return nil unless soc
+ break if (@acl ? @acl.allow_socket?(soc) : true)
+ soc.close
+ end
+ begin
+ ssl = @config.accept(soc)
+ rescue Exception
+ soc.close
+ raise
+ end
+ self.class.new(uri, ssl, @config, true)
+ rescue OpenSSL::SSL::SSLError
+ warn("#{$!.message} (#{$!.class})", uplevel: 0) if @config[:verbose]
+ retry
+ end
+ end
+ end
+
+ DRbProtocol.add_protocol(DRbSSLSocket)
+end
diff --git a/lib/drb/timeridconv.rb b/lib/drb/timeridconv.rb
new file mode 100644
index 0000000000..3ead98a7f2
--- /dev/null
+++ b/lib/drb/timeridconv.rb
@@ -0,0 +1,97 @@
+# frozen_string_literal: false
+require_relative 'drb'
+require 'monitor'
+
+module DRb
+
+ # Timer id conversion keeps objects alive for a certain amount of time after
+ # their last access. The default time period is 600 seconds and can be
+ # changed upon initialization.
+ #
+ # To use TimerIdConv:
+ #
+ # DRb.install_id_conv TimerIdConv.new 60 # one minute
+
+ class TimerIdConv < DRbIdConv
+ class TimerHolder2 # :nodoc:
+ include MonitorMixin
+
+ class InvalidIndexError < RuntimeError; end
+
+ def initialize(keeping=600)
+ super()
+ @sentinel = Object.new
+ @gc = {}
+ @renew = {}
+ @keeping = keeping
+ @expires = nil
+ end
+
+ def add(obj)
+ synchronize do
+ rotate
+ key = obj.__id__
+ @renew[key] = obj
+ invoke_keeper
+ return key
+ end
+ end
+
+ def fetch(key)
+ synchronize do
+ rotate
+ obj = peek(key)
+ raise InvalidIndexError if obj == @sentinel
+ @renew[key] = obj # KeepIt
+ return obj
+ end
+ end
+
+ private
+ def peek(key)
+ return @renew.fetch(key) { @gc.fetch(key, @sentinel) }
+ end
+
+ def invoke_keeper
+ return if @expires
+ @expires = Time.now + @keeping
+ on_gc
+ end
+
+ def on_gc
+ return unless Thread.main.alive?
+ return if @expires.nil?
+ Thread.new { rotate } if @expires < Time.now
+ ObjectSpace.define_finalizer(Object.new) {on_gc}
+ end
+
+ def rotate
+ synchronize do
+ if @expires &.< Time.now
+ @gc = @renew # GCed
+ @renew = {}
+ @expires = @gc.empty? ? nil : Time.now + @keeping
+ end
+ end
+ end
+ end
+
+ # Creates a new TimerIdConv which will hold objects for +keeping+ seconds.
+ def initialize(keeping=600)
+ @holder = TimerHolder2.new(keeping)
+ end
+
+ def to_obj(ref) # :nodoc:
+ return super if ref.nil?
+ @holder.fetch(ref)
+ rescue TimerHolder2::InvalidIndexError
+ raise "invalid reference"
+ end
+
+ def to_id(obj) # :nodoc:
+ return @holder.add(obj)
+ end
+ end
+end
+
+# DRb.install_id_conv(TimerIdConv.new)
diff --git a/lib/drb/unix.rb b/lib/drb/unix.rb
new file mode 100644
index 0000000000..1629ad3bcd
--- /dev/null
+++ b/lib/drb/unix.rb
@@ -0,0 +1,118 @@
+# frozen_string_literal: false
+require 'socket'
+require_relative 'drb'
+require 'tmpdir'
+
+raise(LoadError, "UNIXServer is required") unless defined?(UNIXServer)
+
+module DRb
+
+ # Implements DRb over a UNIX socket
+ #
+ # DRb UNIX socket URIs look like <code>drbunix:<path>?<option></code>. The
+ # option is optional.
+
+ class DRbUNIXSocket < DRbTCPSocket
+ # :stopdoc:
+ def self.parse_uri(uri)
+ if /\Adrbunix:(.*?)(\?(.*))?\z/ =~ uri
+ filename = $1
+ option = $3
+ [filename, option]
+ else
+ raise(DRbBadScheme, uri) unless uri.start_with?('drbunix:')
+ raise(DRbBadURI, 'can\'t parse uri:' + uri)
+ end
+ end
+
+ def self.open(uri, config)
+ filename, = parse_uri(uri)
+ soc = UNIXSocket.open(filename)
+ self.new(uri, soc, config)
+ end
+
+ def self.open_server(uri, config)
+ filename, = parse_uri(uri)
+ if filename.size == 0
+ soc = temp_server
+ filename = soc.path
+ uri = 'drbunix:' + soc.path
+ else
+ soc = UNIXServer.open(filename)
+ end
+ owner = config[:UNIXFileOwner]
+ group = config[:UNIXFileGroup]
+ if owner || group
+ require 'etc'
+ owner = Etc.getpwnam( owner ).uid if owner
+ group = Etc.getgrnam( group ).gid if group
+ File.chown owner, group, filename
+ end
+ mode = config[:UNIXFileMode]
+ File.chmod(mode, filename) if mode
+
+ self.new(uri, soc, config, true)
+ end
+
+ def self.uri_option(uri, config)
+ filename, option = parse_uri(uri)
+ return "drbunix:#{filename}", option
+ end
+
+ def initialize(uri, soc, config={}, server_mode = false)
+ super(uri, soc, config)
+ set_sockopt(@socket)
+ @server_mode = server_mode
+ @acl = nil
+ end
+
+ # import from tempfile.rb
+ Max_try = 10
+ private
+ def self.temp_server
+ tmpdir = Dir::tmpdir
+ n = 0
+ while true
+ begin
+ tmpname = sprintf('%s/druby%d.%d', tmpdir, $$, n)
+ lock = tmpname + '.lock'
+ unless File.exist?(tmpname) or File.exist?(lock)
+ Dir.mkdir(lock)
+ break
+ end
+ rescue
+ raise "cannot generate tempfile `%s'" % tmpname if n >= Max_try
+ #sleep(1)
+ end
+ n += 1
+ end
+ soc = UNIXServer.new(tmpname)
+ Dir.rmdir(lock)
+ soc
+ end
+
+ public
+ def close
+ return unless @socket
+ shutdown # DRbProtocol#shutdown
+ path = @socket.path if @server_mode
+ @socket.close
+ File.unlink(path) if @server_mode
+ @socket = nil
+ close_shutdown_pipe
+ end
+
+ def accept
+ s = accept_or_shutdown
+ return nil unless s
+ self.class.new(nil, s, @config)
+ end
+
+ def set_sockopt(soc)
+ # no-op for now
+ end
+ end
+
+ DRbProtocol.add_protocol(DRbUNIXSocket)
+ # :startdoc:
+end
diff --git a/lib/drb/version.rb b/lib/drb/version.rb
new file mode 100644
index 0000000000..10d33445b6
--- /dev/null
+++ b/lib/drb/version.rb
@@ -0,0 +1,3 @@
+module DRb
+ VERSION = "2.1.1"
+end
diff --git a/lib/drb/weakidconv.rb b/lib/drb/weakidconv.rb
new file mode 100644
index 0000000000..ecf0bf515f
--- /dev/null
+++ b/lib/drb/weakidconv.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: false
+require_relative 'drb'
+require 'monitor'
+
+module DRb
+
+ # To use WeakIdConv:
+ #
+ # DRb.start_service(nil, nil, {:idconv => DRb::WeakIdConv.new})
+
+ class WeakIdConv < DRbIdConv
+ class WeakSet
+ include MonitorMixin
+ def initialize
+ super()
+ @immutable = {}
+ @map = ObjectSpace::WeakMap.new
+ end
+
+ def add(obj)
+ synchronize do
+ begin
+ @map[obj] = self
+ rescue ArgumentError
+ @immutable[obj.__id__] = obj
+ end
+ return obj.__id__
+ end
+ end
+
+ def fetch(ref)
+ synchronize do
+ @immutable.fetch(ref) {
+ @map.each { |key, _|
+ return key if key.__id__ == ref
+ }
+ raise RangeError.new("invalid reference")
+ }
+ end
+ end
+ end
+
+ def initialize()
+ super()
+ @weak_set = WeakSet.new
+ end
+
+ def to_obj(ref) # :nodoc:
+ return super if ref.nil?
+ @weak_set.fetch(ref)
+ end
+
+ def to_id(obj) # :nodoc:
+ return @weak_set.add(obj)
+ end
+ end
+end
+
+# DRb.install_id_conv(WeakIdConv.new)
diff --git a/lib/erb.gemspec b/lib/erb.gemspec
index 94a8fd5c3e..d973cc10de 100644
--- a/lib/erb.gemspec
+++ b/lib/erb.gemspec
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
spec.name = 'erb'
spec.version = ERB.const_get(:VERSION, false)
spec.authors = ['Masatoshi SEKI', 'Takashi Kokubun']
- spec.email = ['seki@ruby-lang.org', 'k0kubun@ruby-lang.org']
+ spec.email = ['seki@ruby-lang.org', 'takashikkbn@gmail.com']
spec.summary = %q{An easy to use but powerful templating system for Ruby.}
spec.description = %q{An easy to use but powerful templating system for Ruby.}
diff --git a/lib/erb.rb b/lib/erb.rb
index bc1615d7da..754419f819 100644
--- a/lib/erb.rb
+++ b/lib/erb.rb
@@ -307,11 +307,11 @@ class ERB
# def build
# b = binding
# # create and run templates, filling member data variables
- # ERB.new(<<~'END_PRODUCT', trim_mode: "", eoutvar: "@product").result b
+ # ERB.new(<<-'END_PRODUCT'.gsub(/^\s+/, ""), trim_mode: "", eoutvar: "@product").result b
# <%= PRODUCT[:name] %>
# <%= PRODUCT[:desc] %>
# END_PRODUCT
- # ERB.new(<<~'END_PRICE', trim_mode: "", eoutvar: "@price").result b
+ # ERB.new(<<-'END_PRICE'.gsub(/^\s+/, ""), trim_mode: "", eoutvar: "@price").result b
# <%= PRODUCT[:name] %> -- <%= PRODUCT[:cost] %>
# <%= PRODUCT[:desc] %>
# END_PRICE
diff --git a/lib/erb/compiler.rb b/lib/erb/compiler.rb
index 7096c8dcea..547d2c4c44 100644
--- a/lib/erb/compiler.rb
+++ b/lib/erb/compiler.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: true
#--
# ERB::Compiler
#
diff --git a/lib/erb/def_method.rb b/lib/erb/def_method.rb
index aee989a926..17f9c0f9fa 100644
--- a/lib/erb/def_method.rb
+++ b/lib/erb/def_method.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: true
#--
# ERB::DefMethod
#
diff --git a/lib/erb/util.rb b/lib/erb/util.rb
index 1d2a36275d..0c1e7482a8 100644
--- a/lib/erb/util.rb
+++ b/lib/erb/util.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: true
#--
# ERB::Escape
#
diff --git a/lib/erb/version.rb b/lib/erb/version.rb
index b5fe39b330..38e1b76ff4 100644
--- a/lib/erb/version.rb
+++ b/lib/erb/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
class ERB
- VERSION = '4.0.4'
+ VERSION = '4.0.2'
private_constant :VERSION
end
diff --git a/lib/error_highlight/base.rb b/lib/error_highlight/base.rb
index e2077fa5a6..062871ee16 100644
--- a/lib/error_highlight/base.rb
+++ b/lib/error_highlight/base.rb
@@ -54,20 +54,11 @@ module ErrorHighlight
return nil unless Thread::Backtrace::Location === loc
- node =
- begin
- RubyVM::AbstractSyntaxTree.of(loc, keep_script_lines: true)
- rescue RuntimeError => error
- # RubyVM::AbstractSyntaxTree.of raises an error with a message that
- # includes "prism" when the ISEQ was compiled with the prism compiler.
- # In this case, we'll try to parse again with prism instead.
- raise unless error.message.include?("prism")
- prism_find(loc)
- end
+ node = RubyVM::AbstractSyntaxTree.of(loc, keep_script_lines: true)
Spotter.new(node, **opts).spot
- when RubyVM::AbstractSyntaxTree::Node, Prism::Node
+ when RubyVM::AbstractSyntaxTree::Node
Spotter.new(obj, **opts).spot
else
@@ -81,21 +72,6 @@ module ErrorHighlight
return nil
end
- # Accepts a Thread::Backtrace::Location object and returns a Prism::Node
- # corresponding to the backtrace location in the source code.
- def self.prism_find(location)
- require "prism"
- return nil if Prism::VERSION < "1.0.0"
-
- absolute_path = location.absolute_path
- return unless absolute_path
-
- node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location)
- Prism.parse_file(absolute_path).value.breadth_first_search { |node| node.node_id == node_id }
- end
-
- private_class_method :prism_find
-
class Spotter
class NonAscii < Exception; end
private_constant :NonAscii
@@ -122,58 +98,9 @@ module ErrorHighlight
end
end
- OPT_GETCONSTANT_PATH = (RUBY_VERSION.split(".").map {|s| s.to_i } <=> [3, 2]) >= 0
- private_constant :OPT_GETCONSTANT_PATH
-
def spot
return nil unless @node
- if OPT_GETCONSTANT_PATH
- # In Ruby 3.2 or later, a nested constant access (like `Foo::Bar::Baz`)
- # is compiled to one instruction (opt_getconstant_path).
- # @node points to the node of the whole `Foo::Bar::Baz` even if `Foo`
- # or `Foo::Bar` causes NameError.
- # So we try to spot the sub-node that causes the NameError by using
- # `NameError#name`.
- case @node.type
- when :COLON2
- subnodes = []
- node = @node
- while node.type == :COLON2
- node2, const = node.children
- subnodes << node if const == @name
- node = node2
- end
- if node.type == :CONST || node.type == :COLON3
- if node.children.first == @name
- subnodes << node
- end
-
- # If we found only one sub-node whose name is equal to @name, use it
- return nil if subnodes.size != 1
- @node = subnodes.first
- else
- # Do nothing; opt_getconstant_path is used only when the const base is
- # NODE_CONST (`Foo`) or NODE_COLON3 (`::Foo`)
- end
- when :constant_path_node
- subnodes = []
- node = @node
-
- begin
- subnodes << node if node.name == @name
- end while (node = node.parent).is_a?(Prism::ConstantPathNode)
-
- if node.is_a?(Prism::ConstantReadNode) && node.name == @name
- subnodes << node
- end
-
- # If we found only one sub-node whose name is equal to @name, use it
- return nil if subnodes.size != 1
- @node = subnodes.first
- end
- end
-
case @node.type
when :CALL, :QCALL
@@ -238,48 +165,6 @@ module ErrorHighlight
when :OP_CDECL
spot_op_cdecl
-
- when :call_node
- case @point_type
- when :name
- prism_spot_call_for_name
- when :args
- prism_spot_call_for_args
- end
-
- when :local_variable_operator_write_node
- case @point_type
- when :name
- prism_spot_local_variable_operator_write_for_name
- when :args
- prism_spot_local_variable_operator_write_for_args
- end
-
- when :call_operator_write_node
- case @point_type
- when :name
- prism_spot_call_operator_write_for_name
- when :args
- prism_spot_call_operator_write_for_args
- end
-
- when :index_operator_write_node
- case @point_type
- when :name
- prism_spot_index_operator_write_for_name
- when :args
- prism_spot_index_operator_write_for_args
- end
-
- when :constant_read_node
- prism_spot_constant_read
-
- when :constant_path_node
- prism_spot_constant_path
-
- when :constant_path_operator_write_node
- prism_spot_constant_path_operator_write
-
end
if @snippet && @beg_column && @end_column && @beg_column < @end_column
@@ -623,207 +508,6 @@ module ErrorHighlight
@beg_lineno = @end_lineno = lineno
@snippet = @fetch[lineno]
end
-
- # Take a location from the prism parser and set the necessary instance
- # variables.
- def prism_location(location)
- @beg_lineno = location.start_line
- @beg_column = location.start_column
- @end_lineno = location.end_line
- @end_column = location.end_column
- @snippet = @fetch[@beg_lineno, @end_lineno]
- end
-
- # Example:
- # x.foo
- # ^^^^
- # x.foo(42)
- # ^^^^
- # x&.foo
- # ^^^^^
- # x[42]
- # ^^^^
- # x.foo = 1
- # ^^^^^^
- # x[42] = 1
- # ^^^^^^
- # x + 1
- # ^
- # +x
- # ^
- # foo(42)
- # ^^^
- # foo 42
- # ^^^
- # foo
- # ^^^
- def prism_spot_call_for_name
- # Explicitly turn off foo.() syntax because error_highlight expects this
- # to not work.
- return nil if @node.name == :call && @node.message_loc.nil?
-
- location = @node.message_loc || @node.call_operator_loc || @node.location
- location = @node.call_operator_loc.join(location) if @node.call_operator_loc&.start_line == location.start_line
-
- # If the method name ends with "=" but the message does not, then this is
- # a method call using the "attribute assignment" syntax
- # (e.g., foo.bar = 1). In this case we need to go retrieve the = sign and
- # add it to the location.
- if (name = @node.name).end_with?("=") && !@node.message.end_with?("=")
- location = location.adjoin("=")
- end
-
- prism_location(location)
-
- if !name.end_with?("=") && !name.match?(/[[:alpha:]_\[]/)
- # If the method name is an operator, then error_highlight only
- # highlights the first line.
- fetch_line(location.start_line)
- end
- end
-
- # Example:
- # x.foo(42)
- # ^^
- # x[42]
- # ^^
- # x.foo = 1
- # ^
- # x[42] = 1
- # ^^^^^^^
- # x[] = 1
- # ^^^^^
- # x + 1
- # ^
- # foo(42)
- # ^^
- # foo 42
- # ^^
- def prism_spot_call_for_args
- # Disallow highlighting arguments if there are no arguments.
- return if @node.arguments.nil?
-
- # Explicitly turn off foo.() syntax because error_highlight expects this
- # to not work.
- return nil if @node.name == :call && @node.message_loc.nil?
-
- if @node.name == :[]= && @node.opening == "[" && (@node.arguments&.arguments || []).length == 1
- prism_location(@node.opening_loc.copy(start_offset: @node.opening_loc.start_offset + 1).join(@node.arguments.location))
- else
- prism_location(@node.arguments.location)
- end
- end
-
- # Example:
- # x += 1
- # ^
- def prism_spot_local_variable_operator_write_for_name
- prism_location(@node.binary_operator_loc.chop)
- end
-
- # Example:
- # x += 1
- # ^
- def prism_spot_local_variable_operator_write_for_args
- prism_location(@node.value.location)
- end
-
- # Example:
- # x.foo += 42
- # ^^^ (for foo)
- # x.foo += 42
- # ^ (for +)
- # x.foo += 42
- # ^^^^^^^ (for foo=)
- def prism_spot_call_operator_write_for_name
- if !@name.start_with?(/[[:alpha:]_]/)
- prism_location(@node.binary_operator_loc.chop)
- else
- location = @node.message_loc
- if @node.call_operator_loc.start_line == location.start_line
- location = @node.call_operator_loc.join(location)
- end
-
- location = location.adjoin("=") if @name.end_with?("=")
- prism_location(location)
- end
- end
-
- # Example:
- # x.foo += 42
- # ^^
- def prism_spot_call_operator_write_for_args
- prism_location(@node.value.location)
- end
-
- # Example:
- # x[1] += 42
- # ^^^ (for [])
- # x[1] += 42
- # ^ (for +)
- # x[1] += 42
- # ^^^^^^ (for []=)
- def prism_spot_index_operator_write_for_name
- case @name
- when :[]
- prism_location(@node.opening_loc.join(@node.closing_loc))
- when :[]=
- prism_location(@node.opening_loc.join(@node.closing_loc).adjoin("="))
- else
- # Explicitly turn off foo[] += 1 syntax when the operator is not on
- # the same line because error_highlight expects this to not work.
- return nil if @node.binary_operator_loc.start_line != @node.opening_loc.start_line
-
- prism_location(@node.binary_operator_loc.chop)
- end
- end
-
- # Example:
- # x[1] += 42
- # ^^^^^^^^
- def prism_spot_index_operator_write_for_args
- opening_loc =
- if @node.arguments.nil?
- @node.opening_loc.copy(start_offset: @node.opening_loc.start_offset + 1)
- else
- @node.arguments.location
- end
-
- prism_location(opening_loc.join(@node.value.location))
- end
-
- # Example:
- # Foo
- # ^^^
- def prism_spot_constant_read
- prism_location(@node.location)
- end
-
- # Example:
- # Foo::Bar
- # ^^^^^
- def prism_spot_constant_path
- if @node.parent && @node.parent.location.end_line == @node.location.end_line
- fetch_line(@node.parent.location.end_line)
- prism_location(@node.delimiter_loc.join(@node.name_loc))
- else
- fetch_line(@node.location.end_line)
- location = @node.name_loc
- location = @node.delimiter_loc.join(location) if @node.delimiter_loc.end_line == location.start_line
- prism_location(location)
- end
- end
-
- # Example:
- # Foo::Bar += 1
- # ^^^^^^^^
- def prism_spot_constant_path_operator_write
- if @name == (target = @node.target).name
- prism_location(target.delimiter_loc.join(target.name_loc))
- else
- prism_location(@node.binary_operator_loc.chop)
- end
- end
end
private_constant :Spotter
diff --git a/lib/error_highlight/version.rb b/lib/error_highlight/version.rb
index 506d37fbc1..5afe5f06d6 100644
--- a/lib/error_highlight/version.rb
+++ b/lib/error_highlight/version.rb
@@ -1,3 +1,3 @@
module ErrorHighlight
- VERSION = "0.6.0"
+ VERSION = "0.5.1"
end
diff --git a/lib/fileutils.gemspec b/lib/fileutils.gemspec
index 2603d664da..76baea3039 100644
--- a/lib/fileutils.gemspec
+++ b/lib/fileutils.gemspec
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
s.description = "Several file utility methods for copying, moving, removing, etc."
s.require_path = %w{lib}
- s.files = ["COPYING", "BSDL", "README.md", "Rakefile", "fileutils.gemspec", "lib/fileutils.rb"]
+ s.files = ["LICENSE.txt", "README.md", "Rakefile", "fileutils.gemspec", "lib/fileutils.rb"]
s.required_ruby_version = ">= 2.5.0"
s.authors = ["Minero Aoki"]
diff --git a/lib/fileutils.rb b/lib/fileutils.rb
index e8cc355760..b495078f93 100644
--- a/lib/fileutils.rb
+++ b/lib/fileutils.rb
@@ -3,7 +3,7 @@
begin
require 'rbconfig'
rescue LoadError
- # for make rjit-headers
+ # for make mjit-headers
end
# Namespace for file utility methods for copying, moving, removing, etc.
@@ -180,8 +180,7 @@ end
# - {CVE-2004-0452}[https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452].
#
module FileUtils
- # The version number.
- VERSION = "1.7.2"
+ VERSION = "1.7.0"
def self.private_module_function(name) #:nodoc:
module_function name
@@ -193,6 +192,8 @@ module FileUtils
#
# FileUtils.pwd # => "/rdoc/fileutils"
#
+ # FileUtils.getwd is an alias for FileUtils.pwd.
+ #
# Related: FileUtils.cd.
#
def pwd
@@ -234,6 +235,8 @@ module FileUtils
# cd ..
# cd fileutils
#
+ # FileUtils.chdir is an alias for FileUtils.cd.
+ #
# Related: FileUtils.pwd.
#
def cd(dir, verbose: nil, &block) # :yield: dir
@@ -512,6 +515,8 @@ module FileUtils
# Raises an exception if +dest+ is the path to an existing file
# and keyword argument +force+ is not +true+.
#
+ # FileUtils#link is an alias for FileUtils#ln.
+ #
# Related: FileUtils.link_entry (has different options).
#
def ln(src, dest, force: nil, noop: nil, verbose: nil)
@@ -702,6 +707,8 @@ module FileUtils
# ln -sf src2.txt dest2.txt
# ln -s srcdir3/src0.txt srcdir3/src1.txt destdir3
#
+ # FileUtils.symlink is an alias for FileUtils.ln_s.
+ #
# Related: FileUtils.ln_sf.
#
def ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil)
@@ -869,6 +876,8 @@ module FileUtils
#
# Raises an exception if +src+ is a directory.
#
+ # FileUtils.copy is an alias for FileUtils.cp.
+ #
# Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
#
def cp(src, dest, preserve: nil, noop: nil, verbose: nil)
@@ -1155,6 +1164,8 @@ module FileUtils
# mv src0 dest0
# mv src1.txt src1 dest1
#
+ # FileUtils.move is an alias for FileUtils.mv.
+ #
def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
return if noop
@@ -1212,6 +1223,8 @@ module FileUtils
#
# rm src0.dat src0.txt
#
+ # FileUtils.remove is an alias for FileUtils.rm.
+ #
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm(list, force: nil, noop: nil, verbose: nil)
@@ -1237,6 +1250,8 @@ module FileUtils
#
# See FileUtils.rm for keyword arguments.
#
+ # FileUtils.safe_unlink is an alias for FileUtils.rm_f.
+ #
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm_f(list, noop: nil, verbose: nil)
@@ -1324,6 +1339,8 @@ module FileUtils
#
# See FileUtils.rm_r for keyword arguments.
#
+ # FileUtils.rmtree is an alias for FileUtils.rm_rf.
+ #
# Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
#
def rm_rf(list, noop: nil, verbose: nil, secure: nil)
@@ -1625,13 +1642,7 @@ module FileUtils
st = File.stat(s)
unless File.exist?(d) and compare_file(s, d)
remove_file d, true
- if d.end_with?('/')
- mkdir_p d
- copy_file s, d + File.basename(s)
- else
- mkdir_p File.expand_path('..', d)
- copy_file s, d
- end
+ copy_file s, d
File.utime st.atime, st.mtime, d if preserve
File.chmod fu_mode(mode, st), d if mode
File.chown uid, gid, d if uid or gid
@@ -1652,7 +1663,7 @@ module FileUtils
when "a"
mask | 07777
else
- raise ArgumentError, "invalid 'who' symbol in file mode: #{chr}"
+ raise ArgumentError, "invalid `who' symbol in file mode: #{chr}"
end
end
end
@@ -1706,7 +1717,7 @@ module FileUtils
copy_mask = user_mask(chr)
(current_mode & copy_mask) / (copy_mask & 0111) * (user_mask & 0111)
else
- raise ArgumentError, "invalid 'perm' symbol in file mode: #{chr}"
+ raise ArgumentError, "invalid `perm' symbol in file mode: #{chr}"
end
end
@@ -2029,22 +2040,21 @@ module FileUtils
private
- module StreamUtils_ # :nodoc:
-
+ module StreamUtils_
private
case (defined?(::RbConfig) ? ::RbConfig::CONFIG['host_os'] : ::RUBY_PLATFORM)
when /mswin|mingw/
- def fu_windows?; true end #:nodoc:
+ def fu_windows?; true end
else
- def fu_windows?; false end #:nodoc:
+ def fu_windows?; false end
end
def fu_copy_stream0(src, dest, blksize = nil) #:nodoc:
IO.copy_stream(src, dest)
end
- def fu_stream_blksize(*streams) #:nodoc:
+ def fu_stream_blksize(*streams)
streams.each do |s|
next unless s.respond_to?(:stat)
size = fu_blksize(s.stat)
@@ -2053,14 +2063,14 @@ module FileUtils
fu_default_blksize()
end
- def fu_blksize(st) #:nodoc:
+ def fu_blksize(st)
s = st.blksize
return nil unless s
return nil if s == 0
s
end
- def fu_default_blksize #:nodoc:
+ def fu_default_blksize
1024
end
end
@@ -2505,7 +2515,7 @@ module FileUtils
end
private_module_function :fu_output_message
- def fu_split_path(path) #:nodoc:
+ def fu_split_path(path)
path = File.path(path)
list = []
until (parent, base = File.split(path); parent == path or parent == ".")
@@ -2526,7 +2536,7 @@ module FileUtils
end
private_module_function :fu_relative_components_from
- def fu_clean_components(*comp) #:nodoc:
+ def fu_clean_components(*comp)
comp.shift while comp.first == "."
return comp if comp.empty?
clean = [comp.shift]
@@ -2545,11 +2555,11 @@ module FileUtils
private_module_function :fu_clean_components
if fu_windows?
- def fu_starting_path?(path) #:nodoc:
+ def fu_starting_path?(path)
path&.start_with?(%r(\w:|/))
end
else
- def fu_starting_path?(path) #:nodoc:
+ def fu_starting_path?(path)
path&.start_with?("/")
end
end
diff --git a/lib/find.gemspec b/lib/find.gemspec
index aef24a5028..3f0aadcdae 100644
--- a/lib/find.gemspec
+++ b/lib/find.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "find"
+ spec.version = "0.1.1"
spec.authors = ['Kazuki Tsujimoto']
spec.email = ['kazuki@callcc.net']
@@ -25,5 +18,7 @@ Gem::Specification.new do |spec|
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
end
diff --git a/lib/find.rb b/lib/find.rb
index 98a79cc76d..9bee99c66d 100644
--- a/lib/find.rb
+++ b/lib/find.rb
@@ -27,8 +27,6 @@
#
module Find
- VERSION = "0.2.0"
-
#
# Calls the associated block with the name of every file and directory listed
# as arguments, then recursively on their subdirectories, and so on.
diff --git a/lib/getoptlong.rb b/lib/getoptlong.rb
new file mode 100644
index 0000000000..5ae0e1497c
--- /dev/null
+++ b/lib/getoptlong.rb
@@ -0,0 +1,867 @@
+# frozen_string_literal: true
+#
+# GetoptLong for Ruby
+#
+# Copyright (C) 1998, 1999, 2000 Motoyuki Kasahara.
+#
+# You may redistribute and/or modify this library under the same license
+# terms as Ruby.
+
+# \Class \GetoptLong provides parsing both for options
+# and for regular arguments.
+#
+# Using \GetoptLong, you can define options for your program.
+# The program can then capture and respond to whatever options
+# are included in the command that executes the program.
+#
+# A simple example: file <tt>simple.rb</tt>:
+#
+# :include: ../sample/getoptlong/simple.rb
+#
+# If you are somewhat familiar with options,
+# you may want to skip to this
+# {full example}[#class-GetoptLong-label-Full+Example].
+#
+# == Options
+#
+# A \GetoptLong option has:
+#
+# - A string <em>option name</em>.
+# - Zero or more string <em>aliases</em> for the name.
+# - An <em>option type</em>.
+#
+# Options may be defined by calling singleton method GetoptLong.new,
+# which returns a new \GetoptLong object.
+# Options may then be processed by calling other methods
+# such as GetoptLong#each.
+#
+# === Option Name and Aliases
+#
+# In the array that defines an option,
+# the first element is the string option name.
+# Often the name takes the 'long' form, beginning with two hyphens.
+#
+# The option name may have any number of aliases,
+# which are defined by additional string elements.
+#
+# The name and each alias must be of one of two forms:
+#
+# - Two hyphens, followed by one or more letters.
+# - One hyphen, followed by a single letter.
+#
+# File <tt>aliases.rb</tt>:
+#
+# :include: ../sample/getoptlong/aliases.rb
+#
+# An option may be cited by its name,
+# or by any of its aliases;
+# the parsed option always reports the name, not an alias:
+#
+# $ ruby aliases.rb -a -p --xxx --aaa -x
+#
+# Output:
+#
+# ["--xxx", ""]
+# ["--xxx", ""]
+# ["--xxx", ""]
+# ["--xxx", ""]
+# ["--xxx", ""]
+#
+#
+# An option may also be cited by an abbreviation of its name or any alias,
+# as long as that abbreviation is unique among the options.
+#
+# File <tt>abbrev.rb</tt>:
+#
+# :include: ../sample/getoptlong/abbrev.rb
+#
+# Command line:
+#
+# $ ruby abbrev.rb --xxx --xx --xyz --xy
+#
+# Output:
+#
+# ["--xxx", ""]
+# ["--xxx", ""]
+# ["--xyz", ""]
+# ["--xyz", ""]
+#
+# This command line raises GetoptLong::AmbiguousOption:
+#
+# $ ruby abbrev.rb --x
+#
+# === Repetition
+#
+# An option may be cited more than once:
+#
+# $ ruby abbrev.rb --xxx --xyz --xxx --xyz
+#
+# Output:
+#
+# ["--xxx", ""]
+# ["--xyz", ""]
+# ["--xxx", ""]
+# ["--xyz", ""]
+#
+# === Treating Remaining Options as Arguments
+#
+# A option-like token that appears
+# anywhere after the token <tt>--</tt> is treated as an ordinary argument,
+# and is not processed as an option:
+#
+# $ ruby abbrev.rb --xxx --xyz -- --xxx --xyz
+#
+# Output:
+#
+# ["--xxx", ""]
+# ["--xyz", ""]
+#
+# === Option Types
+#
+# Each option definition includes an option type,
+# which controls whether the option takes an argument.
+#
+# File <tt>types.rb</tt>:
+#
+# :include: ../sample/getoptlong/types.rb
+#
+# Note that an option type has to do with the <em>option argument</em>
+# (whether it is required, optional, or forbidden),
+# not with whether the option itself is required.
+#
+# ==== Option with Required Argument
+#
+# An option of type <tt>GetoptLong::REQUIRED_ARGUMENT</tt>
+# must be followed by an argument, which is associated with that option:
+#
+# $ ruby types.rb --xxx foo
+#
+# Output:
+#
+# ["--xxx", "foo"]
+#
+# If the option is not last, its argument is whatever follows it
+# (even if the argument looks like another option):
+#
+# $ ruby types.rb --xxx --yyy
+#
+# Output:
+#
+# ["--xxx", "--yyy"]
+#
+# If the option is last, an exception is raised:
+#
+# $ ruby types.rb
+# # Raises GetoptLong::MissingArgument
+#
+# ==== Option with Optional Argument
+#
+# An option of type <tt>GetoptLong::OPTIONAL_ARGUMENT</tt>
+# may be followed by an argument, which if given is associated with that option.
+#
+# If the option is last, it does not have an argument:
+#
+# $ ruby types.rb --yyy
+#
+# Output:
+#
+# ["--yyy", ""]
+#
+# If the option is followed by another option, it does not have an argument:
+#
+# $ ruby types.rb --yyy --zzz
+#
+# Output:
+#
+# ["--yyy", ""]
+# ["--zzz", ""]
+#
+# Otherwise the option is followed by its argument, which is associated
+# with that option:
+#
+# $ ruby types.rb --yyy foo
+#
+# Output:
+#
+# ["--yyy", "foo"]
+#
+# ==== Option with No Argument
+#
+# An option of type <tt>GetoptLong::NO_ARGUMENT</tt> takes no argument:
+#
+# ruby types.rb --zzz foo
+#
+# Output:
+#
+# ["--zzz", ""]
+#
+# === ARGV
+#
+# You can process options either with method #each and a block,
+# or with method #get.
+#
+# During processing, each found option is removed, along with its argument
+# if there is one.
+# After processing, each remaining element was neither an option
+# nor the argument for an option.
+#
+# File <tt>argv.rb</tt>:
+#
+# :include: ../sample/getoptlong/argv.rb
+#
+# Command line:
+#
+# $ ruby argv.rb --xxx Foo --yyy Bar Baz --zzz Bat Bam
+#
+# Output:
+#
+# Original ARGV: ["--xxx", "Foo", "--yyy", "Bar", "Baz", "--zzz", "Bat", "Bam"]
+# ["--xxx", "Foo"]
+# ["--yyy", "Bar"]
+# ["--zzz", ""]
+# Remaining ARGV: ["Baz", "Bat", "Bam"]
+#
+# === Ordering
+#
+# There are three settings that control the way the options
+# are interpreted:
+#
+# - +PERMUTE+.
+# - +REQUIRE_ORDER+.
+# - +RETURN_IN_ORDER+.
+#
+# The initial setting for a new \GetoptLong object is +REQUIRE_ORDER+
+# if environment variable +POSIXLY_CORRECT+ is defined, +PERMUTE+ otherwise.
+#
+# ==== PERMUTE Ordering
+#
+# In the +PERMUTE+ ordering, options and other, non-option,
+# arguments may appear in any order and any mixture.
+#
+# File <tt>permute.rb</tt>:
+#
+# :include: ../sample/getoptlong/permute.rb
+#
+# Command line:
+#
+# $ ruby permute.rb Foo --zzz Bar --xxx Baz --yyy Bat Bam --xxx Bag Bah
+#
+# Output:
+#
+# Original ARGV: ["Foo", "--zzz", "Bar", "--xxx", "Baz", "--yyy", "Bat", "Bam", "--xxx", "Bag", "Bah"]
+# ["--zzz", ""]
+# ["--xxx", "Baz"]
+# ["--yyy", "Bat"]
+# ["--xxx", "Bag"]
+# Remaining ARGV: ["Foo", "Bar", "Bam", "Bah"]
+#
+# ==== REQUIRE_ORDER Ordering
+#
+# In the +REQUIRE_ORDER+ ordering, all options precede all non-options;
+# that is, each word after the first non-option word
+# is treated as a non-option word (even if it begins with a hyphen).
+#
+# File <tt>require_order.rb</tt>:
+#
+# :include: ../sample/getoptlong/require_order.rb
+#
+# Command line:
+#
+# $ ruby require_order.rb --xxx Foo Bar --xxx Baz --yyy Bat -zzz
+#
+# Output:
+#
+# Original ARGV: ["--xxx", "Foo", "Bar", "--xxx", "Baz", "--yyy", "Bat", "-zzz"]
+# ["--xxx", "Foo"]
+# Remaining ARGV: ["Bar", "--xxx", "Baz", "--yyy", "Bat", "-zzz"]
+#
+# ==== RETURN_IN_ORDER Ordering
+#
+# In the +RETURN_IN_ORDER+ ordering, every word is treated as an option.
+# A word that begins with a hyphen (or two) is treated in the usual way;
+# a word +word+ that does not so begin is treated as an option
+# whose name is an empty string, and whose value is +word+.
+#
+# File <tt>return_in_order.rb</tt>:
+#
+# :include: ../sample/getoptlong/return_in_order.rb
+#
+# Command line:
+#
+# $ ruby return_in_order.rb Foo --xxx Bar Baz --zzz Bat Bam
+#
+# Output:
+#
+# Original ARGV: ["Foo", "--xxx", "Bar", "Baz", "--zzz", "Bat", "Bam"]
+# ["", "Foo"]
+# ["--xxx", "Bar"]
+# ["", "Baz"]
+# ["--zzz", ""]
+# ["", "Bat"]
+# ["", "Bam"]
+# Remaining ARGV: []
+#
+# === Full Example
+#
+# File <tt>fibonacci.rb</tt>:
+#
+# :include: ../sample/getoptlong/fibonacci.rb
+#
+# Command line:
+#
+# $ ruby fibonacci.rb
+#
+# Output:
+#
+# Option --number is required.
+# Usage:
+#
+# -n n, --number n:
+# Compute Fibonacci number for n.
+# -v [boolean], --verbose [boolean]:
+# Show intermediate results; default is 'false'.
+# -h, --help:
+# Show this help.
+#
+# Command line:
+#
+# $ ruby fibonacci.rb --number
+#
+# Raises GetoptLong::MissingArgument:
+#
+# fibonacci.rb: option `--number' requires an argument
+#
+# Command line:
+#
+# $ ruby fibonacci.rb --number 6
+#
+# Output:
+#
+# 8
+#
+# Command line:
+#
+# $ ruby fibonacci.rb --number 6 --verbose
+#
+# Output:
+# 1
+# 2
+# 3
+# 5
+# 8
+#
+# Command line:
+#
+# $ ruby fibonacci.rb --number 6 --verbose yes
+#
+# Output:
+#
+# --verbose argument must be true or false
+# Usage:
+#
+# -n n, --number n:
+# Compute Fibonacci number for n.
+# -v [boolean], --verbose [boolean]:
+# Show intermediate results; default is 'false'.
+# -h, --help:
+# Show this help.
+#
+class GetoptLong
+ # Version.
+ VERSION = "0.2.0"
+
+ #
+ # Orderings.
+ #
+ ORDERINGS = [REQUIRE_ORDER = 0, PERMUTE = 1, RETURN_IN_ORDER = 2]
+
+ #
+ # Argument flags.
+ #
+ ARGUMENT_FLAGS = [NO_ARGUMENT = 0, REQUIRED_ARGUMENT = 1,
+ OPTIONAL_ARGUMENT = 2]
+
+ #
+ # Status codes.
+ #
+ STATUS_YET, STATUS_STARTED, STATUS_TERMINATED = 0, 1, 2
+
+ #
+ # Error types.
+ #
+ class Error < StandardError; end
+ class AmbiguousOption < Error; end
+ class NeedlessArgument < Error; end
+ class MissingArgument < Error; end
+ class InvalidOption < Error; end
+
+ #
+ # Returns a new \GetoptLong object based on the given +arguments+.
+ # See {Options}[#class-GetoptLong-label-Options].
+ #
+ # Example:
+ #
+ # :include: ../sample/getoptlong/simple.rb
+ #
+ # Raises an exception if:
+ #
+ # - Any of +arguments+ is not an array.
+ # - Any option name or alias is not a string.
+ # - Any option type is invalid.
+ #
+ def initialize(*arguments)
+ #
+ # Current ordering.
+ #
+ if ENV.include?('POSIXLY_CORRECT')
+ @ordering = REQUIRE_ORDER
+ else
+ @ordering = PERMUTE
+ end
+
+ #
+ # Hash table of option names.
+ # Keys of the table are option names, and their values are canonical
+ # names of the options.
+ #
+ @canonical_names = Hash.new
+
+ #
+ # Hash table of argument flags.
+ # Keys of the table are option names, and their values are argument
+ # flags of the options.
+ #
+ @argument_flags = Hash.new
+
+ #
+ # Whether error messages are output to $stderr.
+ #
+ @quiet = false
+
+ #
+ # Status code.
+ #
+ @status = STATUS_YET
+
+ #
+ # Error code.
+ #
+ @error = nil
+
+ #
+ # Error message.
+ #
+ @error_message = nil
+
+ #
+ # Rest of catenated short options.
+ #
+ @rest_singles = ''
+
+ #
+ # List of non-option-arguments.
+ # Append them to ARGV when option processing is terminated.
+ #
+ @non_option_arguments = Array.new
+
+ if 0 < arguments.length
+ set_options(*arguments)
+ end
+ end
+
+ # Sets the ordering; see {Ordering}[#class-GetoptLong-label-Ordering];
+ # returns the new ordering.
+ #
+ # If the given +ordering+ is +PERMUTE+ and environment variable
+ # +POSIXLY_CORRECT+ is defined, sets the ordering to +REQUIRE_ORDER+;
+ # otherwise sets the ordering to +ordering+:
+ #
+ # options = GetoptLong.new
+ # options.ordering == GetoptLong::PERMUTE # => true
+ # options.ordering = GetoptLong::RETURN_IN_ORDER
+ # options.ordering == GetoptLong::RETURN_IN_ORDER # => true
+ # ENV['POSIXLY_CORRECT'] = 'true'
+ # options.ordering = GetoptLong::PERMUTE
+ # options.ordering == GetoptLong::REQUIRE_ORDER # => true
+ #
+ # Raises an exception if +ordering+ is invalid.
+ #
+ def ordering=(ordering)
+ #
+ # The method is failed if option processing has already started.
+ #
+ if @status != STATUS_YET
+ set_error(ArgumentError, "argument error")
+ raise RuntimeError,
+ "invoke ordering=, but option processing has already started"
+ end
+
+ #
+ # Check ordering.
+ #
+ if !ORDERINGS.include?(ordering)
+ raise ArgumentError, "invalid ordering `#{ordering}'"
+ end
+ if ordering == PERMUTE && ENV.include?('POSIXLY_CORRECT')
+ @ordering = REQUIRE_ORDER
+ else
+ @ordering = ordering
+ end
+ end
+
+ #
+ # Returns the ordering setting.
+ #
+ attr_reader :ordering
+
+ #
+ # Replaces existing options with those given by +arguments+,
+ # which have the same form as the arguments to ::new;
+ # returns +self+.
+ #
+ # Raises an exception if option processing has begun.
+ #
+ def set_options(*arguments)
+ #
+ # The method is failed if option processing has already started.
+ #
+ if @status != STATUS_YET
+ raise RuntimeError,
+ "invoke set_options, but option processing has already started"
+ end
+
+ #
+ # Clear tables of option names and argument flags.
+ #
+ @canonical_names.clear
+ @argument_flags.clear
+
+ arguments.each do |arg|
+ if !arg.is_a?(Array)
+ raise ArgumentError, "the option list contains non-Array argument"
+ end
+
+ #
+ # Find an argument flag and it set to `argument_flag'.
+ #
+ argument_flag = nil
+ arg.each do |i|
+ if ARGUMENT_FLAGS.include?(i)
+ if argument_flag != nil
+ raise ArgumentError, "too many argument-flags"
+ end
+ argument_flag = i
+ end
+ end
+
+ raise ArgumentError, "no argument-flag" if argument_flag == nil
+
+ canonical_name = nil
+ arg.each do |i|
+ #
+ # Check an option name.
+ #
+ next if i == argument_flag
+ begin
+ if !i.is_a?(String) || i !~ /\A-([^-]|-.+)\z/
+ raise ArgumentError, "an invalid option `#{i}'"
+ end
+ if (@canonical_names.include?(i))
+ raise ArgumentError, "option redefined `#{i}'"
+ end
+ rescue
+ @canonical_names.clear
+ @argument_flags.clear
+ raise
+ end
+
+ #
+ # Register the option (`i') to the `@canonical_names' and
+ # `@canonical_names' Hashes.
+ #
+ if canonical_name == nil
+ canonical_name = i
+ end
+ @canonical_names[i] = canonical_name
+ @argument_flags[i] = argument_flag
+ end
+ raise ArgumentError, "no option name" if canonical_name == nil
+ end
+ return self
+ end
+
+ #
+ # Sets quiet mode and returns the given argument:
+ #
+ # - When +false+ or +nil+, error messages are written to <tt>$stdout</tt>.
+ # - Otherwise, error messages are not written.
+ #
+ attr_writer :quiet
+
+ #
+ # Returns the quiet mode setting.
+ #
+ attr_reader :quiet
+ alias quiet? quiet
+
+ #
+ # Terminate option processing;
+ # returns +nil+ if processing has already terminated;
+ # otherwise returns +self+.
+ #
+ def terminate
+ return nil if @status == STATUS_TERMINATED
+ raise RuntimeError, "an error has occurred" if @error != nil
+
+ @status = STATUS_TERMINATED
+ @non_option_arguments.reverse_each do |argument|
+ ARGV.unshift(argument)
+ end
+
+ @canonical_names = nil
+ @argument_flags = nil
+ @rest_singles = nil
+ @non_option_arguments = nil
+
+ return self
+ end
+
+ #
+ # Returns +true+ if option processing has terminated, +false+ otherwise.
+ #
+ def terminated?
+ return @status == STATUS_TERMINATED
+ end
+
+ #
+ # \Set an error (a protected method).
+ #
+ def set_error(type, message)
+ $stderr.print("#{$0}: #{message}\n") if !@quiet
+
+ @error = type
+ @error_message = message
+ @canonical_names = nil
+ @argument_flags = nil
+ @rest_singles = nil
+ @non_option_arguments = nil
+
+ raise type, message
+ end
+ protected :set_error
+
+ #
+ # Returns whether option processing has failed.
+ #
+ attr_reader :error
+ alias error? error
+
+ # Return the appropriate error message in POSIX-defined format.
+ # If no error has occurred, returns +nil+.
+ #
+ def error_message
+ return @error_message
+ end
+
+ #
+ # Returns the next option as a 2-element array containing:
+ #
+ # - The option name (the name itself, not an alias).
+ # - The option value.
+ #
+ # Returns +nil+ if there are no more options.
+ #
+ def get
+ option_name, option_argument = nil, ''
+
+ #
+ # Check status.
+ #
+ return nil if @error != nil
+ case @status
+ when STATUS_YET
+ @status = STATUS_STARTED
+ when STATUS_TERMINATED
+ return nil
+ end
+
+ #
+ # Get next option argument.
+ #
+ if 0 < @rest_singles.length
+ argument = '-' + @rest_singles
+ elsif (ARGV.length == 0)
+ terminate
+ return nil
+ elsif @ordering == PERMUTE
+ while 0 < ARGV.length && ARGV[0] !~ /\A-./
+ @non_option_arguments.push(ARGV.shift)
+ end
+ if ARGV.length == 0
+ terminate
+ return nil
+ end
+ argument = ARGV.shift
+ elsif @ordering == REQUIRE_ORDER
+ if (ARGV[0] !~ /\A-./)
+ terminate
+ return nil
+ end
+ argument = ARGV.shift
+ else
+ argument = ARGV.shift
+ end
+
+ #
+ # Check the special argument `--'.
+ # `--' indicates the end of the option list.
+ #
+ if argument == '--' && @rest_singles.length == 0
+ terminate
+ return nil
+ end
+
+ #
+ # Check for long and short options.
+ #
+ if argument =~ /\A(--[^=]+)/ && @rest_singles.length == 0
+ #
+ # This is a long style option, which start with `--'.
+ #
+ pattern = $1
+ if @canonical_names.include?(pattern)
+ option_name = pattern
+ else
+ #
+ # The option `option_name' is not registered in `@canonical_names'.
+ # It may be an abbreviated.
+ #
+ matches = []
+ @canonical_names.each_key do |key|
+ if key.index(pattern) == 0
+ option_name = key
+ matches << key
+ end
+ end
+ if 2 <= matches.length
+ set_error(AmbiguousOption, "option `#{argument}' is ambiguous between #{matches.join(', ')}")
+ elsif matches.length == 0
+ set_error(InvalidOption, "unrecognized option `#{argument}'")
+ end
+ end
+
+ #
+ # Check an argument to the option.
+ #
+ if @argument_flags[option_name] == REQUIRED_ARGUMENT
+ if argument =~ /=(.*)/m
+ option_argument = $1
+ elsif 0 < ARGV.length
+ option_argument = ARGV.shift
+ else
+ set_error(MissingArgument,
+ "option `#{argument}' requires an argument")
+ end
+ elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT
+ if argument =~ /=(.*)/m
+ option_argument = $1
+ elsif 0 < ARGV.length && ARGV[0] !~ /\A-./
+ option_argument = ARGV.shift
+ else
+ option_argument = ''
+ end
+ elsif argument =~ /=(.*)/m
+ set_error(NeedlessArgument,
+ "option `#{option_name}' doesn't allow an argument")
+ end
+
+ elsif argument =~ /\A(-(.))(.*)/m
+ #
+ # This is a short style option, which start with `-' (not `--').
+ # Short options may be catenated (e.g. `-l -g' is equivalent to
+ # `-lg').
+ #
+ option_name, ch, @rest_singles = $1, $2, $3
+
+ if @canonical_names.include?(option_name)
+ #
+ # The option `option_name' is found in `@canonical_names'.
+ # Check its argument.
+ #
+ if @argument_flags[option_name] == REQUIRED_ARGUMENT
+ if 0 < @rest_singles.length
+ option_argument = @rest_singles
+ @rest_singles = ''
+ elsif 0 < ARGV.length
+ option_argument = ARGV.shift
+ else
+ # 1003.2 specifies the format of this message.
+ set_error(MissingArgument, "option requires an argument -- #{ch}")
+ end
+ elsif @argument_flags[option_name] == OPTIONAL_ARGUMENT
+ if 0 < @rest_singles.length
+ option_argument = @rest_singles
+ @rest_singles = ''
+ elsif 0 < ARGV.length && ARGV[0] !~ /\A-./
+ option_argument = ARGV.shift
+ else
+ option_argument = ''
+ end
+ end
+ else
+ #
+ # This is an invalid option.
+ # 1003.2 specifies the format of this message.
+ #
+ if ENV.include?('POSIXLY_CORRECT')
+ set_error(InvalidOption, "invalid option -- #{ch}")
+ else
+ set_error(InvalidOption, "invalid option -- #{ch}")
+ end
+ end
+ else
+ #
+ # This is a non-option argument.
+ # Only RETURN_IN_ORDER fell into here.
+ #
+ return '', argument
+ end
+
+ return @canonical_names[option_name], option_argument
+ end
+ alias get_option get
+
+ #
+ # Calls the given block with each option;
+ # each option is a 2-element array containing:
+ #
+ # - The option name (the name itself, not an alias).
+ # - The option value.
+ #
+ # Example:
+ #
+ # :include: ../sample/getoptlong/each.rb
+ #
+ # Command line:
+ #
+ # ruby each.rb -xxx Foo -x Bar --yyy Baz -y Bat --zzz
+ #
+ # Output:
+ #
+ # Original ARGV: ["-xxx", "Foo", "-x", "Bar", "--yyy", "Baz", "-y", "Bat", "--zzz"]
+ # ["--xxx", "xx"]
+ # ["--xxx", "Bar"]
+ # ["--yyy", "Baz"]
+ # ["--yyy", "Bat"]
+ # ["--zzz", ""]
+ # Remaining ARGV: ["Foo"]
+ #
+ def each
+ loop do
+ option_name, option_argument = get_option
+ break if option_name == nil
+ yield option_name, option_argument
+ end
+ end
+ alias each_option each
+end
diff --git a/lib/getoptlong/getoptlong.gemspec b/lib/getoptlong/getoptlong.gemspec
new file mode 100644
index 0000000000..dfe087b886
--- /dev/null
+++ b/lib/getoptlong/getoptlong.gemspec
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{GetoptLong for Ruby}
+ spec.description = spec.summary
+ spec.homepage = "https://github.com/ruby/getoptlong"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/ipaddr.rb b/lib/ipaddr.rb
index dbb213c90a..7a5cf94830 100644
--- a/lib/ipaddr.rb
+++ b/lib/ipaddr.rb
@@ -40,7 +40,7 @@ require 'socket'
# p ipaddr3 #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
class IPAddr
- VERSION = "1.2.6"
+ VERSION = "1.2.5"
# 32 bit mask for IPv4
IN4MASK = 0xffffffff
@@ -52,7 +52,7 @@ class IPAddr
# Regexp _internally_ used for parsing IPv4 address.
RE_IPV4ADDRLIKE = %r{
\A
- \d+ \. \d+ \. \d+ \. \d+
+ (\d+) \. (\d+) \. (\d+) \. (\d+)
\z
}x
@@ -110,13 +110,8 @@ class IPAddr
# Convert a network byte ordered string form of an IP address into
# human readable form.
- # It expects the string to be encoded in Encoding::ASCII_8BIT (BINARY).
def self.ntop(addr)
- if addr.is_a?(String) && addr.encoding != Encoding::BINARY
- raise InvalidAddressError, "invalid encoding (given #{addr.encoding}, expected BINARY)"
- end
-
- case addr.bytesize
+ case addr.size
when 4
addr.unpack('C4').join('.')
when 16
@@ -181,7 +176,9 @@ class IPAddr
def include?(other)
other = coerce_other(other)
return false unless other.family == family
- begin_addr <= other.begin_addr && end_addr >= other.end_addr
+ range = to_range
+ other = other.to_range
+ range.begin <= other.begin && range.end >= other.end
end
alias === include?
@@ -227,12 +224,6 @@ class IPAddr
return str
end
- # Returns a string containing the IP address representation in
- # cidr notation
- def cidr
- format("%s/%s", to_s, prefix)
- end
-
# Returns a network byte ordered string form of the IP address.
def hton
case @family
@@ -258,17 +249,12 @@ class IPAddr
end
# Returns true if the ipaddr is a loopback address.
- # Loopback IPv4 addresses in the IPv4-mapped IPv6
- # address range are also considered as loopback addresses.
def loopback?
case @family
when Socket::AF_INET
- @addr & 0xff000000 == 0x7f000000 # 127.0.0.1/8
+ @addr & 0xff000000 == 0x7f000000
when Socket::AF_INET6
- @addr == 1 || # ::1
- (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
- @addr & 0xff000000 == 0x7f000000 # ::ffff:127.0.0.1/8
- ))
+ @addr == 1
else
raise AddressFamilyError, "unsupported address family"
end
@@ -277,8 +263,7 @@ class IPAddr
# Returns true if the ipaddr is a private address. IPv4 addresses
# in 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16 as defined in RFC
# 1918 and IPv6 Unique Local Addresses in fc00::/7 as defined in RFC
- # 4193 are considered private. Private IPv4 addresses in the
- # IPv4-mapped IPv6 address range are also considered private.
+ # 4193 are considered private.
def private?
case @family
when Socket::AF_INET
@@ -286,31 +271,22 @@ class IPAddr
@addr & 0xfff00000 == 0xac100000 || # 172.16.0.0/12
@addr & 0xffff0000 == 0xc0a80000 # 192.168.0.0/16
when Socket::AF_INET6
- @addr & 0xfe00_0000_0000_0000_0000_0000_0000_0000 == 0xfc00_0000_0000_0000_0000_0000_0000_0000 ||
- (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
- @addr & 0xff000000 == 0x0a000000 || # ::ffff:10.0.0.0/8
- @addr & 0xfff00000 == 0xac100000 || # ::ffff::172.16.0.0/12
- @addr & 0xffff0000 == 0xc0a80000 # ::ffff::192.168.0.0/16
- ))
+ @addr & 0xfe00_0000_0000_0000_0000_0000_0000_0000 == 0xfc00_0000_0000_0000_0000_0000_0000_0000
else
raise AddressFamilyError, "unsupported address family"
end
end
# Returns true if the ipaddr is a link-local address. IPv4
- # addresses in 169.254.0.0/16 reserved by RFC 3927 and link-local
+ # addresses in 169.254.0.0/16 reserved by RFC 3927 and Link-Local
# IPv6 Unicast Addresses in fe80::/10 reserved by RFC 4291 are
- # considered link-local. Link-local IPv4 addresses in the
- # IPv4-mapped IPv6 address range are also considered link-local.
+ # considered link-local.
def link_local?
case @family
when Socket::AF_INET
@addr & 0xffff0000 == 0xa9fe0000 # 169.254.0.0/16
when Socket::AF_INET6
- @addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000 || # fe80::/10
- (@addr & 0xffff_0000_0000 == 0xffff_0000_0000 && (
- @addr & 0xffff0000 == 0xa9fe0000 # ::ffff:169.254.0.0/16
- ))
+ @addr & 0xffc0_0000_0000_0000_0000_0000_0000_0000 == 0xfe80_0000_0000_0000_0000_0000_0000_0000
else
raise AddressFamilyError, "unsupported address family"
end
@@ -424,6 +400,17 @@ class IPAddr
# Creates a Range object for the network address.
def to_range
+ begin_addr = (@addr & @mask_addr)
+
+ case @family
+ when Socket::AF_INET
+ end_addr = (@addr | (IN4MASK ^ @mask_addr))
+ when Socket::AF_INET6
+ end_addr = (@addr | (IN6MASK ^ @mask_addr))
+ else
+ raise AddressFamilyError, "unsupported address family"
+ end
+
self.class.new(begin_addr, @family)..self.class.new(end_addr, @family)
end
@@ -452,7 +439,7 @@ class IPAddr
when Integer
mask!(prefix)
else
- raise InvalidPrefixError, "prefix must be an integer"
+ raise InvalidPrefixError, "prefix must be an integer: #{@addr}"
end
end
@@ -477,20 +464,6 @@ class IPAddr
_to_string(@mask_addr)
end
- # Returns the wildcard mask in string format e.g. 0.0.255.255
- def wildcard_mask
- case @family
- when Socket::AF_INET
- mask = IN4MASK ^ @mask_addr
- when Socket::AF_INET6
- mask = IN6MASK ^ @mask_addr
- else
- raise AddressFamilyError, "unsupported address family"
- end
-
- _to_string(mask)
- end
-
# Returns the IPv6 zone identifier, if present.
# Raises InvalidAddressError if not an IPv6 address.
def zone_id
@@ -518,21 +491,6 @@ class IPAddr
protected
- def begin_addr
- @addr & @mask_addr
- end
-
- def end_addr
- case @family
- when Socket::AF_INET
- @addr | (IN4MASK ^ @mask_addr)
- when Socket::AF_INET6
- @addr | (IN6MASK ^ @mask_addr)
- else
- raise AddressFamilyError, "unsupported address family"
- end
- end
-
# Set +@addr+, the internal stored ip address, to given +addr+. The
# parameter +addr+ is validated using the first +family+ member,
# which is +Socket::AF_INET+ or +Socket::AF_INET6+.
@@ -540,11 +498,11 @@ class IPAddr
case family[0] ? family[0] : @family
when Socket::AF_INET
if addr < 0 || addr > IN4MASK
- raise InvalidAddressError, "invalid address: #{addr}"
+ raise InvalidAddressError, "invalid address: #{@addr}"
end
when Socket::AF_INET6
if addr < 0 || addr > IN6MASK
- raise InvalidAddressError, "invalid address: #{addr}"
+ raise InvalidAddressError, "invalid address: #{@addr}"
end
else
raise AddressFamilyError, "unsupported address family"
@@ -571,12 +529,12 @@ class IPAddr
else
m = IPAddr.new(mask)
if m.family != @family
- raise InvalidPrefixError, "address family is not same"
+ raise InvalidPrefixError, "address family is not same: #{@addr}"
end
@mask_addr = m.to_i
n = @mask_addr ^ m.instance_variable_get(:@mask_addr)
unless ((n + 1) & n).zero?
- raise InvalidPrefixError, "invalid mask #{mask}"
+ raise InvalidPrefixError, "invalid mask #{mask}: #{@addr}"
end
@addr &= @mask_addr
return self
@@ -587,13 +545,13 @@ class IPAddr
case @family
when Socket::AF_INET
if prefixlen < 0 || prefixlen > 32
- raise InvalidPrefixError, "invalid length"
+ raise InvalidPrefixError, "invalid length: #{@addr}"
end
masklen = 32 - prefixlen
@mask_addr = ((IN4MASK >> masklen) << masklen)
when Socket::AF_INET6
if prefixlen < 0 || prefixlen > 128
- raise InvalidPrefixError, "invalid length"
+ raise InvalidPrefixError, "invalid length: #{@addr}"
end
masklen = 128 - prefixlen
@mask_addr = ((IN6MASK >> masklen) << masklen)
@@ -689,12 +647,12 @@ class IPAddr
when Array
octets = addr
else
- RE_IPV4ADDRLIKE.match?(addr) or return nil
- octets = addr.split('.')
+ m = RE_IPV4ADDRLIKE.match(addr) or return nil
+ octets = m.captures
end
octets.inject(0) { |i, s|
(n = s.to_i) < 256 or raise InvalidAddressError, "invalid address: #{@addr}"
- (s != '0') && s.start_with?('0') and raise InvalidAddressError, "zero-filled number in IPv4 address is ambiguous: #{@addr}"
+ s.match(/\A0./) and raise InvalidAddressError, "zero-filled number in IPv4 address is ambiguous: #{@addr}"
i << 8 | n
}
end
diff --git a/lib/irb.rb b/lib/irb.rb
index 213e231174..2db99bcd43 100644
--- a/lib/irb.rb
+++ b/lib/irb.rb
@@ -1,954 +1,484 @@
-# frozen_string_literal: true
-
-# :markup: markdown
+# frozen_string_literal: false
+#
# irb.rb - irb main module
+# $Release Version: 0.9.6 $
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-
+# --
+#
+#
+#
require "ripper"
require "reline"
require_relative "irb/init"
require_relative "irb/context"
-require_relative "irb/default_commands"
+require_relative "irb/extend-command"
require_relative "irb/ruby-lex"
-require_relative "irb/statement"
require_relative "irb/input-method"
require_relative "irb/locale"
require_relative "irb/color"
require_relative "irb/version"
require_relative "irb/easter-egg"
-require_relative "irb/debug"
-require_relative "irb/pager"
-# ## IRB
+# IRB stands for "interactive Ruby" and is a tool to interactively execute Ruby
+# expressions read from the standard input.
#
-# Module IRB ("Interactive Ruby") provides a shell-like interface that supports
-# user interaction with the Ruby interpreter.
+# The +irb+ command from your shell will start the interpreter.
#
-# It operates as a *read-eval-print loop*
-# ([REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop))
-# that:
+# == Usage
#
-# * ***Reads*** each character as you type. You can modify the IRB context to
-# change the way input works. See [Input](rdoc-ref:IRB@Input).
-# * ***Evaluates*** the code each time it has read a syntactically complete
-# passage.
-# * ***Prints*** after evaluating. You can modify the IRB context to change
-# the way output works. See [Output](rdoc-ref:IRB@Output).
+# Use of irb is easy if you know Ruby.
#
-#
-# Example:
+# When executing irb, prompts are displayed as follows. Then, enter the Ruby
+# expression. An input is executed when it is syntactically complete.
#
# $ irb
-# irb(main):001> File.basename(Dir.pwd)
-# => "irb"
-# irb(main):002> Dir.entries('.').size
-# => 25
-# irb(main):003* Dir.entries('.').select do |entry|
-# irb(main):004* entry.start_with?('R')
-# irb(main):005> end
-# => ["README.md", "Rakefile"]
-#
-# The typed input may also include [\IRB-specific
-# commands](rdoc-ref:IRB@IRB-Specific+Commands).
-#
-# As seen above, you can start IRB by using the shell command `irb`.
-#
-# You can stop an IRB session by typing command `exit`:
-#
-# irb(main):006> exit
-# $
-#
-# At that point, IRB calls any hooks found in array `IRB.conf[:AT_EXIT]`, then
-# exits.
-#
-# ## Startup
-#
-# At startup, IRB:
-#
-# 1. Interprets (as Ruby code) the content of the [configuration
-# file](rdoc-ref:IRB@Configuration+File) (if given).
-# 2. Constructs the initial session context from [hash
-# IRB.conf](rdoc-ref:IRB@Hash+IRB.conf) and from default values; the hash
-# content may have been affected by [command-line
-# options](rdoc-ref:IB@Command-Line+Options), and by direct assignments in
-# the configuration file.
-# 3. Assigns the context to variable `conf`.
-# 4. Assigns command-line arguments to variable `ARGV`.
-# 5. Prints the [prompt](rdoc-ref:IRB@Prompt+and+Return+Formats).
-# 6. Puts the content of the [initialization
-# script](rdoc-ref:IRB@Initialization+Script) onto the IRB shell, just as if
-# it were user-typed commands.
-#
-#
-# ### The Command Line
-#
-# On the command line, all options precede all arguments; the first item that is
-# not recognized as an option is treated as an argument, as are all items that
-# follow.
-#
-# #### Command-Line Options
-#
-# Many command-line options affect entries in hash `IRB.conf`, which in turn
-# affect the initial configuration of the IRB session.
-#
-# Details of the options are described in the relevant subsections below.
-#
-# A cursory list of the IRB command-line options may be seen in the [help
-# message](https://raw.githubusercontent.com/ruby/irb/master/lib/irb/lc/help-message),
-# which is also displayed if you use command-line option `--help`.
-#
-# If you are interested in a specific option, consult the
-# [index](rdoc-ref:doc/irb/indexes.md@Index+of+Command-Line+Options).
-#
-# #### Command-Line Arguments
-#
-# Command-line arguments are passed to IRB in array `ARGV`:
-#
-# $ irb --noscript Foo Bar Baz
-# irb(main):001> ARGV
-# => ["Foo", "Bar", "Baz"]
-# irb(main):002> exit
-# $
-#
-# Command-line option `--` causes everything that follows to be treated as
-# arguments, even those that look like options:
-#
-# $ irb --noscript -- --noscript -- Foo Bar Baz
-# irb(main):001> ARGV
-# => ["--noscript", "--", "Foo", "Bar", "Baz"]
-# irb(main):002> exit
-# $
-#
-# ### Configuration File
-#
-# You can initialize IRB via a *configuration file*.
-#
-# If command-line option `-f` is given, no configuration file is looked for.
-#
-# Otherwise, IRB reads and interprets a configuration file if one is available.
-#
-# The configuration file can contain any Ruby code, and can usefully include
-# user code that:
-#
-# * Can then be debugged in IRB.
-# * Configures IRB itself.
-# * Requires or loads files.
-#
-#
-# The path to the configuration file is the first found among:
-#
-# * The value of variable `$IRBRC`, if defined.
-# * The value of variable `$XDG_CONFIG_HOME/irb/irbrc`, if defined.
-# * File `$HOME/.irbrc`, if it exists.
-# * File `$HOME/.config/irb/irbrc`, if it exists.
-# * File `.irbrc` in the current directory, if it exists.
-# * File `irb.rc` in the current directory, if it exists.
-# * File `_irbrc` in the current directory, if it exists.
-# * File `$irbrc` in the current directory, if it exists.
-#
-#
-# If the search fails, there is no configuration file.
-#
-# If the search succeeds, the configuration file is read as Ruby code, and so
-# can contain any Ruby programming you like.
-#
-# Method `conf.rc?` returns `true` if a configuration file was read, `false`
-# otherwise. Hash entry `IRB.conf[:RC]` also contains that value.
-#
-# ### Hash `IRB.conf`
-#
-# The initial entries in hash `IRB.conf` are determined by:
-#
-# * Default values.
-# * Command-line options, which may override defaults.
-# * Direct assignments in the configuration file.
-#
-#
-# You can see the hash by typing `IRB.conf`.
-#
-# Details of the entries' meanings are described in the relevant subsections
-# below.
-#
-# If you are interested in a specific entry, consult the
-# [index](rdoc-ref:doc/irb/indexes.md@Index+of+IRB.conf+Entries).
-#
-# ### Notes on Initialization Precedence
-#
-# * Any conflict between an entry in hash `IRB.conf` and a command-line option
-# is resolved in favor of the hash entry.
-# * Hash `IRB.conf` affects the context only once, when the configuration file
-# is interpreted; any subsequent changes to it do not affect the context and
-# are therefore essentially meaningless.
-#
-#
-# ### Initialization Script
-#
-# By default, the first command-line argument (after any options) is the path to
-# a Ruby initialization script.
-#
-# IRB reads the initialization script and puts its content onto the IRB shell,
-# just as if it were user-typed commands.
-#
-# Command-line option `--noscript` causes the first command-line argument to be
-# treated as an ordinary argument (instead of an initialization script);
-# `--script` is the default.
-#
-# ## Input
-#
-# This section describes the features that allow you to change the way IRB input
-# works; see also [Input and Output](rdoc-ref:IRB@Input+and+Output).
-#
-# ### Input Command History
-#
-# By default, IRB stores a history of up to 1000 input commands in a file named
-# `.irb_history`. The history file will be in the same directory as the
-# [configuration file](rdoc-ref:IRB@Configuration+File) if one is found, or in
-# `~/` otherwise.
-#
-# A new IRB session creates the history file if it does not exist, and appends
-# to the file if it does exist.
-#
-# You can change the filepath by adding to your configuration file:
-# `IRB.conf[:HISTORY_FILE] = *filepath*`, where *filepath* is a string filepath.
-#
-# During the session, method `conf.history_file` returns the filepath, and
-# method `conf.history_file = *new_filepath*` copies the history to the file at
-# *new_filepath*, which becomes the history file for the session.
-#
-# You can change the number of commands saved by adding to your configuration
-# file: `IRB.conf[:SAVE_HISTORY] = *n*`, wheHISTORY_FILEre *n* is one of:
-#
-# * Positive integer: the number of commands to be saved,
-# * Zero: all commands are to be saved.
-# * `nil`: no commands are to be saved,.
-#
-#
-# During the session, you can use methods `conf.save_history` or
-# `conf.save_history=` to retrieve or change the count.
-#
-# ### Command Aliases
-#
-# By default, IRB defines several command aliases:
-#
-# irb(main):001> conf.command_aliases
-# => {:"$"=>:show_source, :"@"=>:whereami}
-#
-# You can change the initial aliases in the configuration file with:
-#
-# IRB.conf[:COMMAND_ALIASES] = {foo: :show_source, bar: :whereami}
-#
-# You can replace the current aliases at any time with configuration method
-# `conf.command_aliases=`; Because `conf.command_aliases` is a hash, you can
-# modify it.
-#
-# ### End-of-File
-#
-# By default, `IRB.conf[:IGNORE_EOF]` is `false`, which means that typing the
-# end-of-file character `Ctrl-D` causes the session to exit.
-#
-# You can reverse that behavior by adding `IRB.conf[:IGNORE_EOF] = true` to the
-# configuration file.
-#
-# During the session, method `conf.ignore_eof?` returns the setting, and method
-# `conf.ignore_eof = *boolean*` sets it.
-#
-# ### SIGINT
-#
-# By default, `IRB.conf[:IGNORE_SIGINT]` is `true`, which means that typing the
-# interrupt character `Ctrl-C` causes the session to exit.
-#
-# You can reverse that behavior by adding `IRB.conf[:IGNORE_SIGING] = false` to
-# the configuration file.
-#
-# During the session, method `conf.ignore_siging?` returns the setting, and
-# method `conf.ignore_sigint = *boolean*` sets it.
-#
-# ### Automatic Completion
-#
-# By default, IRB enables [automatic
-# completion](https://en.wikipedia.org/wiki/Autocomplete#In_command-line_interpr
-# eters):
-#
-# You can disable it by either of these:
-#
-# * Adding `IRB.conf[:USE_AUTOCOMPLETE] = false` to the configuration file.
-# * Giving command-line option `--noautocomplete` (`--autocomplete` is the
-# default).
-#
-#
-# Method `conf.use_autocomplete?` returns `true` if automatic completion is
-# enabled, `false` otherwise.
-#
-# The setting may not be changed during the session.
-#
-# ### Automatic Indentation
-#
-# By default, IRB automatically indents lines of code to show structure (e.g.,
-# it indent the contents of a block).
-#
-# The current setting is returned by the configuration method
-# `conf.auto_indent_mode`.
-#
-# The default initial setting is `true`:
-#
-# irb(main):001> conf.auto_indent_mode
-# => true
-# irb(main):002* Dir.entries('.').select do |entry|
-# irb(main):003* entry.start_with?('R')
-# irb(main):004> end
-# => ["README.md", "Rakefile"]
-#
-# You can change the initial setting in the configuration file with:
+# irb(main):001:0> 1+2
+# #=> 3
+# irb(main):002:0> class Foo
+# irb(main):003:1> def foo
+# irb(main):004:2> print 1
+# irb(main):005:2> end
+# irb(main):006:1> end
+# #=> nil
+#
+# The singleline editor module or multiline editor module can be used with irb.
+# Use of multiline editor is default if it's installed.
+#
+# == Command line options
+#
+# :include: ./irb/lc/help-message
+#
+# == Commands
+#
+# The following commands are available on IRB.
+#
+# * cwws
+# * Show the current workspace.
+# * cb, cws, chws
+# * Change the current workspace to an object.
+# * bindings, workspaces
+# * Show workspaces.
+# * pushb, pushws
+# * Push an object to the workspace stack.
+# * popb, popws
+# * Pop a workspace from the workspace stack.
+# * load
+# * Load a Ruby file.
+# * require
+# * Require a Ruby file.
+# * source
+# * Loads a given file in the current session.
+# * irb
+# * Start a child IRB.
+# * jobs
+# * List of current sessions.
+# * fg
+# * Switches to the session of the given number.
+# * kill
+# * Kills the session with the given number.
+# * help
+# * Enter the mode to look up RI documents.
+# * irb_info
+# * Show information about IRB.
+# * ls
+# * Show methods, constants, and variables.
+# -g [query] or -G [query] allows you to filter out the output.
+# * measure
+# * measure enables the mode to measure processing time. measure :off disables it.
+# * $, show_source
+# * Show the source code of a given method or constant.
+# * @, whereami
+# * Show the source code around binding.irb again.
+# * debug
+# * Start the debugger of debug.gem.
+# * break, delete, next, step, continue, finish, backtrace, info, catch
+# * Start the debugger of debug.gem and run the command on it.
+#
+# == Configuration
+#
+# IRB reads a personal initialization file when it's invoked.
+# IRB searches a file in the following order and loads the first one found.
+#
+# * <tt>$IRBRC</tt> (if <tt>$IRBRC</tt> is set)
+# * <tt>$XDG_CONFIG_HOME/irb/irbrc</tt> (if <tt>$XDG_CONFIG_HOME</tt> is set)
+# * <tt>~/.irbrc</tt>
+# * +.config/irb/irbrc+
+# * +.irbrc+
+# * +irb.rc+
+# * +_irbrc+
+# * <code>$irbrc</code>
+#
+# The following are alternatives to the command line options. To use them type
+# as follows in an +irb+ session:
+#
+# IRB.conf[:IRB_NAME]="irb"
+# IRB.conf[:INSPECT_MODE]=nil
+# IRB.conf[:IRB_RC] = nil
+# IRB.conf[:BACK_TRACE_LIMIT]=16
+# IRB.conf[:USE_LOADER] = false
+# IRB.conf[:USE_MULTILINE] = nil
+# IRB.conf[:USE_SINGLELINE] = nil
+# IRB.conf[:USE_COLORIZE] = true
+# IRB.conf[:USE_TRACER] = false
+# IRB.conf[:USE_AUTOCOMPLETE] = true
+# IRB.conf[:IGNORE_SIGINT] = true
+# IRB.conf[:IGNORE_EOF] = false
+# IRB.conf[:PROMPT_MODE] = :DEFAULT
+# IRB.conf[:PROMPT] = {...}
+#
+# === Auto indentation
+#
+# To disable auto-indent mode in irb, add the following to your +.irbrc+:
#
# IRB.conf[:AUTO_INDENT] = false
#
-# Note that the *current* setting *may not* be changed in the IRB session.
-#
-# ### Input Method
-#
-# The IRB input method determines how command input is to be read; by default,
-# the input method for a session is IRB::RelineInputMethod. Unless the
-# value of the TERM environment variable is 'dumb', in which case the
-# most simplistic input method is used.
-#
-# You can set the input method by:
-#
-# * Adding to the configuration file:
-#
-# * `IRB.conf[:USE_SINGLELINE] = true` or `IRB.conf[:USE_MULTILINE]=
-# false` sets the input method to IRB::ReadlineInputMethod.
-# * `IRB.conf[:USE_SINGLELINE] = false` or `IRB.conf[:USE_MULTILINE] =
-# true` sets the input method to IRB::RelineInputMethod.
-#
-#
-# * Giving command-line options:
-#
-# * `--singleline` or `--nomultiline` sets the input method to
-# IRB::ReadlineInputMethod.
-# * `--nosingleline` or `--multiline` sets the input method to
-# IRB::RelineInputMethod.
-# * `--nosingleline` together with `--nomultiline` sets the
-# input to IRB::StdioInputMethod.
-#
-#
-# Method `conf.use_multiline?` and its synonym `conf.use_reline` return:
-#
-# * `true` if option `--multiline` was given.
-# * `false` if option `--nomultiline` was given.
-# * `nil` if neither was given.
-#
-#
-# Method `conf.use_singleline?` and its synonym `conf.use_readline` return:
-#
-# * `true` if option `--singleline` was given.
-# * `false` if option `--nosingleline` was given.
-# * `nil` if neither was given.
-#
-#
-# ## Output
-#
-# This section describes the features that allow you to change the way IRB
-# output works; see also [Input and Output](rdoc-ref:IRB@Input+and+Output).
-#
-# ### Return-Value Printing (Echoing)
-#
-# By default, IRB prints (echoes) the values returned by all input commands.
-#
-# You can change the initial behavior and suppress all echoing by:
-#
-# * Adding to the configuration file: `IRB.conf[:ECHO] = false`. (The default
-# value for this entry is `nil`, which means the same as `true`.)
-# * Giving command-line option `--noecho`. (The default is `--echo`.)
-#
-#
-# During the session, you can change the current setting with configuration
-# method `conf.echo=` (set to `true` or `false`).
-#
-# As stated above, by default IRB prints the values returned by all input
-# commands; but IRB offers special treatment for values returned by assignment
-# statements, which may be:
-#
-# * Printed with truncation (to fit on a single line of output), which is the
-# default; an ellipsis (`...` is suffixed, to indicate the truncation):
-#
-# irb(main):001> x = 'abc' * 100
-#
-#
-# > "abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc...
-#
-# * Printed in full (regardless of the length).
-# * Suppressed (not printed at all)
-#
-#
-# You can change the initial behavior by:
+# === Autocompletion
#
-# * Adding to the configuration file: `IRB.conf[:ECHO_ON_ASSIGNMENT] = false`.
-# (The default value for this entry is `niL`, which means the same as
-# `:truncate`.)
-# * Giving command-line option `--noecho-on-assignment` or
-# `--echo-on-assignment`. (The default is `--truncate-echo-on-assignment`.)
+# To disable autocompletion for irb, add the following to your +.irbrc+:
#
+# IRB.conf[:USE_AUTOCOMPLETE] = false
#
-# During the session, you can change the current setting with configuration
-# method `conf.echo_on_assignment=` (set to `true`, `false`, or `:truncate`).
+# === History
#
-# By default, IRB formats returned values by calling method `inspect`.
+# By default, irb will store the last 1000 commands you used in
+# <code>IRB.conf[:HISTORY_FILE]</code> (<code>~/.irb_history</code> by default).
#
-# You can change the initial behavior by:
+# If you want to disable history, add the following to your +.irbrc+:
#
-# * Adding to the configuration file: `IRB.conf[:INSPECT_MODE] = false`. (The
-# default value for this entry is `true`.)
-# * Giving command-line option `--noinspect`. (The default is `--inspect`.)
+# IRB.conf[:SAVE_HISTORY] = nil
#
+# See IRB::Context#save_history= for more information.
#
-# During the session, you can change the setting using method
-# `conf.inspect_mode=`.
+# The history of _results_ of commands evaluated is not stored by default,
+# but can be turned on to be stored with this +.irbrc+ setting:
#
-# ### Multiline Output
+# IRB.conf[:EVAL_HISTORY] = <number>
#
-# By default, IRB prefixes a newline to a multiline response.
+# See IRB::Context#eval_history= and History class. The history of command
+# results is not permanently saved in any file.
#
-# You can change the initial default value by adding to the configuration file:
+# == Customizing the IRB Prompt
#
-# IRB.conf[:NEWLINE_BEFORE_MULTILINE_OUTPUT] = false
+# In order to customize the prompt, you can change the following Hash:
#
-# During a session, you can retrieve or set the value using methods
-# `conf.newline_before_multiline_output?` and
-# `conf.newline_before_multiline_output=`.
+# IRB.conf[:PROMPT]
#
-# Examples:
+# This example can be used in your +.irbrc+
#
-# irb(main):001> conf.inspect_mode = false
-# => false
-# irb(main):002> "foo\nbar"
-# =>
-# foo
-# bar
-# irb(main):003> conf.newline_before_multiline_output = false
-# => false
-# irb(main):004> "foo\nbar"
-# => foo
-# bar
-#
-# ### Evaluation History
-#
-# By default, IRB saves no history of evaluations (returned values), and the
-# related methods `conf.eval_history`, `_`, and `__` are undefined.
-#
-# You can turn on that history, and set the maximum number of evaluations to be
-# stored:
-#
-# * In the configuration file: add `IRB.conf[:EVAL_HISTORY] = *n*`. (Examples
-# below assume that we've added `IRB.conf[:EVAL_HISTORY] = 5`.)
-# * In the session (at any time): `conf.eval_history = *n*`.
-#
-#
-# If `n` is zero, all evaluation history is stored.
-#
-# Doing either of the above:
-#
-# * Sets the maximum size of the evaluation history; defines method
-# `conf.eval_history`, which returns the maximum size `n` of the evaluation
-# history:
-#
-# irb(main):001> conf.eval_history = 5
-# => 5
-# irb(main):002> conf.eval_history
-# => 5
-#
-# * Defines variable `_`, which contains the most recent evaluation, or `nil`
-# if none; same as method `conf.last_value`:
-#
-# irb(main):003> _
-# => 5
-# irb(main):004> :foo
-# => :foo
-# irb(main):005> :bar
-# => :bar
-# irb(main):006> _
-# => :bar
-# irb(main):007> _
-# => :bar
-#
-# * Defines variable `__`:
-#
-# * `__` unadorned: contains all evaluation history:
-#
-# irb(main):008> :foo
-# => :foo
-# irb(main):009> :bar
-# => :bar
-# irb(main):010> :baz
-# => :baz
-# irb(main):011> :bat
-# => :bat
-# irb(main):012> :bam
-# => :bam
-# irb(main):013> __
-# =>
-# 9 :bar
-# 10 :baz
-# 11 :bat
-# 12 :bam
-# irb(main):014> __
-# =>
-# 10 :baz
-# 11 :bat
-# 12 :bam
-# 13 ...self-history...
-#
-# Note that when the evaluation is multiline, it is displayed
-# differently.
-#
-# * `__[`*m*`]`:
-#
-# * Positive *m*: contains the evaluation for the given line number,
-# or `nil` if that line number is not in the evaluation history:
-#
-# irb(main):015> __[12]
-# => :bam
-# irb(main):016> __[1]
-# => nil
-#
-# * Negative *m*: contains the `mth`-from-end evaluation, or `nil` if
-# that evaluation is not in the evaluation history:
-#
-# irb(main):017> __[-3]
-# => :bam
-# irb(main):018> __[-13]
-# => nil
-#
-# * Zero *m*: contains `nil`:
-#
-# irb(main):019> __[0]
-# => nil
-#
-#
-#
-#
-# ### Prompt and Return Formats
-#
-# By default, IRB uses the prompt and return value formats defined in its
-# `:DEFAULT` prompt mode.
-#
-# #### The Default Prompt and Return Format
-#
-# The default prompt and return values look like this:
-#
-# irb(main):001> 1 + 1
-# => 2
-# irb(main):002> 2 + 2
-# => 4
-#
-# The prompt includes:
-#
-# * The name of the running program (`irb`); see [IRB
-# Name](rdoc-ref:IRB@IRB+Name).
-# * The name of the current session (`main`); See [IRB
-# Sessions](rdoc-ref:IRB@IRB+Sessions).
-# * A 3-digit line number (1-based).
-#
-#
-# The default prompt actually defines three formats:
-#
-# * One for most situations (as above):
-#
-# irb(main):003> Dir
-# => Dir
-#
-# * One for when the typed command is a statement continuation (adds trailing
-# asterisk):
-#
-# irb(main):004* Dir.
-#
-# * One for when the typed command is a string continuation (adds trailing
-# single-quote):
-#
-# irb(main):005' Dir.entries('.
-#
-#
-# You can see the prompt change as you type the characters in the following:
-#
-# irb(main):001* Dir.entries('.').select do |entry|
-# irb(main):002* entry.start_with?('R')
-# irb(main):003> end
-# => ["README.md", "Rakefile"]
-#
-# #### Pre-Defined Prompts
-#
-# IRB has several pre-defined prompts, stored in hash `IRB.conf[:PROMPT]`:
-#
-# irb(main):001> IRB.conf[:PROMPT].keys
-# => [:NULL, :DEFAULT, :CLASSIC, :SIMPLE, :INF_RUBY, :XMP]
-#
-# To see the full data for these, type `IRB.conf[:PROMPT]`.
-#
-# Most of these prompt definitions include specifiers that represent values like
-# the IRB name, session name, and line number; see [Prompt
-# Specifiers](rdoc-ref:IRB@Prompt+Specifiers).
-#
-# You can change the initial prompt and return format by:
-#
-# * Adding to the configuration file: `IRB.conf[:PROMPT] = *mode*` where
-# *mode* is the symbol name of a prompt mode.
-# * Giving a command-line option:
-#
-# * `--prompt *mode*`: sets the prompt mode to *mode*. where *mode* is the
-# symbol name of a prompt mode.
-# * `--simple-prompt` or `--sample-book-mode`: sets the prompt mode to
-# `:SIMPLE`.
-# * `--inf-ruby-mode`: sets the prompt mode to `:INF_RUBY` and suppresses
-# both `--multiline` and `--singleline`.
-# * `--noprompt`: suppresses prompting; does not affect echoing.
-#
-#
-#
-# You can retrieve or set the current prompt mode with methods
-#
-# `conf.prompt_mode` and `conf.prompt_mode=`.
-#
-# If you're interested in prompts and return formats other than the defaults,
-# you might experiment by trying some of the others.
-#
-# #### Custom Prompts
-#
-# You can also define custom prompts and return formats, which may be done
-# either in an IRB session or in the configuration file.
-#
-# A prompt in IRB actually defines three prompts, as seen above. For simple
-# custom data, we'll make all three the same:
-#
-# irb(main):001* IRB.conf[:PROMPT][:MY_PROMPT] = {
-# irb(main):002* PROMPT_I: ': ',
-# irb(main):003* PROMPT_C: ': ',
-# irb(main):004* PROMPT_S: ': ',
-# irb(main):005* RETURN: '=> '
-# irb(main):006> }
-# => {:PROMPT_I=>": ", :PROMPT_C=>": ", :PROMPT_S=>": ", :RETURN=>"=> "}
-#
-# If you define the custom prompt in the configuration file, you can also make
-# it the current prompt by adding:
+# IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode
+# :AUTO_INDENT => false, # disables auto-indent mode
+# :PROMPT_I => ">> ", # simple prompt
+# :PROMPT_S => nil, # prompt for continuated strings
+# :PROMPT_C => nil, # prompt for continuated statement
+# :RETURN => " ==>%s\n" # format to return value
+# }
#
# IRB.conf[:PROMPT_MODE] = :MY_PROMPT
#
-# Regardless of where it's defined, you can make it the current prompt in a
-# session:
-#
-# conf.prompt_mode = :MY_PROMPT
-#
-# You can view or modify the current prompt data with various configuration
-# methods:
-#
-# * `conf.prompt_mode`, `conf.prompt_mode=`.
-# * `conf.prompt_c`, `conf.c=`.
-# * `conf.prompt_i`, `conf.i=`.
-# * `conf.prompt_s`, `conf.s=`.
-# * `conf.return_format`, `return_format=`.
-#
-#
-# #### Prompt Specifiers
-#
-# A prompt's definition can include specifiers for which certain values are
-# substituted:
-#
-# * `%N`: the name of the running program.
-# * `%m`: the value of `self.to_s`.
-# * `%M`: the value of `self.inspect`.
-# * `%l`: an indication of the type of string; one of `"`, `'`, `/`, `]`.
-# * `%NNi`: Indentation level. NN is a 2-digit number that specifies the number
-# of digits of the indentation level (03 will result in 001).
-# * `%NNn`: Line number. NN is a 2-digit number that specifies the number
-# of digits of the line number (03 will result in 001).
-# * `%%`: Literal `%`.
-#
-#
-# ### Verbosity
-#
-# By default, IRB verbosity is disabled, which means that output is smaller
-# rather than larger.
-#
-# You can enable verbosity by:
-#
-# * Adding to the configuration file: `IRB.conf[:VERBOSE] = true` (the default
-# is `nil`).
-# * Giving command-line options `--verbose` (the default is `--noverbose`).
-#
-#
-# During a session, you can retrieve or set verbosity with methods
-# `conf.verbose` and `conf.verbose=`.
-#
-# ### Help
-#
-# Command-line option `--version` causes IRB to print its help text and exit.
-#
-# ### Version
-#
-# Command-line option `--version` causes IRB to print its version text and exit.
-#
-# ## Input and Output
-#
-# ### Color Highlighting
-#
-# By default, IRB color highlighting is enabled, and is used for both:
-#
-# * Input: As you type, IRB reads the typed characters and highlights elements
-# that it recognizes; it also highlights errors such as mismatched
-# parentheses.
-# * Output: IRB highlights syntactical elements.
-#
-#
-# You can disable color highlighting by:
-#
-# * Adding to the configuration file: `IRB.conf[:USE_COLORIZE] = false` (the
-# default value is `true`).
-# * Giving command-line option `--nocolorize`
-#
-#
-# ## Debugging
-#
-# Command-line option `-d` sets variables `$VERBOSE` and `$DEBUG` to `true`;
-# these have no effect on IRB output.
-#
-# ### Warnings
-#
-# Command-line option `-w` suppresses warnings.
-#
-# Command-line option `-W[*level*]` sets warning level;
-#
-# * 0=silence
-# * 1=medium
-# * 2=verbose
-#
-# ## Other Features
-#
-# ### Load Modules
-#
-# You can specify the names of modules that are to be required at startup.
-#
-# Array `conf.load_modules` determines the modules (if any) that are to be
-# required during session startup. The array is used only during session
-# startup, so the initial value is the only one that counts.
-#
-# The default initial value is `[]` (load no modules):
-#
-# irb(main):001> conf.load_modules
-# => []
-#
-# You can set the default initial value via:
-#
-# * Command-line option `-r`
-#
-# $ irb -r csv -r json
-# irb(main):001> conf.load_modules
-# => ["csv", "json"]
-#
-# * Hash entry `IRB.conf[:LOAD_MODULES] = *array*`:
-#
-# IRB.conf[:LOAD_MODULES] = %w[csv, json]
-#
-#
-# Note that the configuration file entry overrides the command-line options.
-#
-# ### RI Documentation Directories
-#
-# You can specify the paths to RI documentation directories that are to be
-# loaded (in addition to the default directories) at startup; see details about
-# RI by typing `ri --help`.
-#
-# Array `conf.extra_doc_dirs` determines the directories (if any) that are to be
-# loaded during session startup. The array is used only during session startup,
-# so the initial value is the only one that counts.
-#
-# The default initial value is `[]` (load no extra documentation):
-#
-# irb(main):001> conf.extra_doc_dirs
-# => []
-#
-# You can set the default initial value via:
-#
-# * Command-line option `--extra_doc_dir`
-#
-# $ irb --extra-doc-dir your_doc_dir --extra-doc-dir my_doc_dir
-# irb(main):001> conf.extra_doc_dirs
-# => ["your_doc_dir", "my_doc_dir"]
-#
-# * Hash entry `IRB.conf[:EXTRA_DOC_DIRS] = *array*`:
-#
-# IRB.conf[:EXTRA_DOC_DIRS] = %w[your_doc_dir my_doc_dir]
-#
-#
-# Note that the configuration file entry overrides the command-line options.
-#
-# ### IRB Name
-#
-# You can specify a name for IRB.
-#
-# The default initial value is `'irb'`:
-#
-# irb(main):001> conf.irb_name
-# => "irb"
-#
-# You can set the default initial value via hash entry `IRB.conf[:IRB_NAME] =
-# *string*`:
-#
-# IRB.conf[:IRB_NAME] = 'foo'
+# Or, invoke irb with the above prompt mode by:
+#
+# irb --prompt my-prompt
+#
+# Constants +PROMPT_I+, +PROMPT_S+ and +PROMPT_C+ specify the format. In the
+# prompt specification, some special strings are available:
+#
+# %N # command name which is running
+# %m # to_s of main object (self)
+# %M # inspect of main object (self)
+# %l # type of string(", ', /, ]), `]' is inner %w[...]
+# %NNi # indent level. NN is digits and means as same as printf("%NNd").
+# # It can be omitted
+# %NNn # line number.
+# %% # %
+#
+# For instance, the default prompt mode is defined as follows:
+#
+# IRB.conf[:PROMPT_MODE][:DEFAULT] = {
+# :PROMPT_I => "%N(%m):%03n:%i> ",
+# :PROMPT_N => "%N(%m):%03n:%i> ",
+# :PROMPT_S => "%N(%m):%03n:%i%l ",
+# :PROMPT_C => "%N(%m):%03n:%i* ",
+# :RETURN => "%s\n" # used to printf
+# }
+#
+# irb comes with a number of available modes:
+#
+# # :NULL:
+# # :PROMPT_I:
+# # :PROMPT_N:
+# # :PROMPT_S:
+# # :PROMPT_C:
+# # :RETURN: |
+# # %s
+# # :DEFAULT:
+# # :PROMPT_I: ! '%N(%m):%03n:%i> '
+# # :PROMPT_N: ! '%N(%m):%03n:%i> '
+# # :PROMPT_S: ! '%N(%m):%03n:%i%l '
+# # :PROMPT_C: ! '%N(%m):%03n:%i* '
+# # :RETURN: |
+# # => %s
+# # :CLASSIC:
+# # :PROMPT_I: ! '%N(%m):%03n:%i> '
+# # :PROMPT_N: ! '%N(%m):%03n:%i> '
+# # :PROMPT_S: ! '%N(%m):%03n:%i%l '
+# # :PROMPT_C: ! '%N(%m):%03n:%i* '
+# # :RETURN: |
+# # %s
+# # :SIMPLE:
+# # :PROMPT_I: ! '>> '
+# # :PROMPT_N: ! '>> '
+# # :PROMPT_S:
+# # :PROMPT_C: ! '?> '
+# # :RETURN: |
+# # => %s
+# # :INF_RUBY:
+# # :PROMPT_I: ! '%N(%m):%03n:%i> '
+# # :PROMPT_N:
+# # :PROMPT_S:
+# # :PROMPT_C:
+# # :RETURN: |
+# # %s
+# # :AUTO_INDENT: true
+# # :XMP:
+# # :PROMPT_I:
+# # :PROMPT_N:
+# # :PROMPT_S:
+# # :PROMPT_C:
+# # :RETURN: |2
+# # ==>%s
+#
+# == Restrictions
+#
+# Because irb evaluates input immediately after it is syntactically complete,
+# the results may be slightly different than directly using Ruby.
+#
+# == IRB Sessions
#
-# ### Application Name
-#
-# You can specify an application name for the IRB session.
-#
-# The default initial value is `'irb'`:
-#
-# irb(main):001> conf.ap_name
-# => "irb"
-#
-# You can set the default initial value via hash entry `IRB.conf[:AP_NAME] =
-# *string*`:
-#
-# IRB.conf[:AP_NAME] = 'my_ap_name'
-#
-# ### Configuration Monitor
-#
-# You can monitor changes to the configuration by assigning a proc to
-# `IRB.conf[:IRB_RC]` in the configuration file:
-#
-# IRB.conf[:IRB_RC] = proc {|conf| puts conf.class }
-#
-# Each time the configuration is changed, that proc is called with argument
-# `conf`:
-#
-# ### Encodings
+# IRB has a special feature, that allows you to manage many sessions at once.
#
-# Command-line option `-E *ex*[:*in*]` sets initial external (ex) and internal
-# (in) encodings.
+# You can create new sessions with Irb.irb, and get a list of current sessions
+# with the +jobs+ command in the prompt.
#
-# Command-line option `-U` sets both to UTF-8.
+# === Commands
#
-# ### Commands
+# JobManager provides commands to handle the current sessions:
#
-# Please use the `help` command to see the list of available commands.
+# jobs # List of current sessions
+# fg # Switches to the session of the given number
+# kill # Kills the session with the given number
#
-# ### IRB Sessions
+# The +exit+ command, or ::irb_exit, will quit the current session and call any
+# exit hooks with IRB.irb_at_exit.
#
-# IRB has a special feature, that allows you to manage many sessions at once.
+# A few commands for loading files within the session are also available:
#
-# You can create new sessions with Irb.irb, and get a list of current sessions
-# with the `jobs` command in the prompt.
+# +source+::
+# Loads a given file in the current session and displays the source lines,
+# see IrbLoader#source_file
+# +irb_load+::
+# Loads the given file similarly to Kernel#load, see IrbLoader#irb_load
+# +irb_require+::
+# Loads the given file similarly to Kernel#require
#
-# #### Configuration
+# === Configuration
#
# The command line options, or IRB.conf, specify the default behavior of
# Irb.irb.
#
-# On the other hand, each conf in IRB@Command-Line+Options is used to
+# On the other hand, each conf in IRB@Command+line+options is used to
# individually configure IRB.irb.
#
-# If a proc is set for `IRB.conf[:IRB_RC]`, its will be invoked after execution
+# If a proc is set for <code>IRB.conf[:IRB_RC]</code>, its will be invoked after execution
# of that proc with the context of the current session as its argument. Each
# session can be configured using this mechanism.
#
-# #### Session variables
+# === Session variables
#
# There are a few variables in every Irb session that can come in handy:
#
-# `_`
-# : The value command executed, as a local variable
-# `__`
-# : The history of evaluated commands. Available only if
-# `IRB.conf[:EVAL_HISTORY]` is not `nil` (which is the default). See also
-# IRB::Context#eval_history= and IRB::History.
-# `__[line_no]`
-# : Returns the evaluation value at the given line number, `line_no`. If
-# `line_no` is a negative, the return value `line_no` many lines before the
-# most recent return value.
-#
-#
-# ## Restrictions
-#
-# Ruby code typed into IRB behaves the same as Ruby code in a file, except that:
-#
-# * Because IRB evaluates input immediately after it is syntactically
-# complete, some results may be slightly different.
-# * Forking may not be well behaved.
-#
+# <code>_</code>::
+# The value command executed, as a local variable
+# <code>__</code>::
+# The history of evaluated commands. Available only if
+# <code>IRB.conf[:EVAL_HISTORY]</code> is not +nil+ (which is the default).
+# See also IRB::Context#eval_history= and IRB::History.
+# <code>__[line_no]</code>::
+# Returns the evaluation value at the given line number, +line_no+.
+# If +line_no+ is a negative, the return value +line_no+ many lines before
+# the most recent return value.
+#
+# === Example using IRB Sessions
+#
+# # invoke a new session
+# irb(main):001:0> irb
+# # list open sessions
+# irb.1(main):001:0> jobs
+# #0->irb on main (#<Thread:0x400fb7e4> : stop)
+# #1->irb#1 on main (#<Thread:0x40125d64> : running)
+#
+# # change the active session
+# irb.1(main):002:0> fg 0
+# # define class Foo in top-level session
+# irb(main):002:0> class Foo;end
+# # invoke a new session with the context of Foo
+# irb(main):003:0> irb Foo
+# # define Foo#foo
+# irb.2(Foo):001:0> def foo
+# irb.2(Foo):002:1> print 1
+# irb.2(Foo):003:1> end
+#
+# # change the active session
+# irb.2(Foo):004:0> fg 0
+# # list open sessions
+# irb(main):004:0> jobs
+# #0->irb on main (#<Thread:0x400fb7e4> : running)
+# #1->irb#1 on main (#<Thread:0x40125d64> : stop)
+# #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop)
+# # check if Foo#foo is available
+# irb(main):005:0> Foo.instance_methods #=> [:foo, ...]
+#
+# # change the active session
+# irb(main):006:0> fg 2
+# # define Foo#bar in the context of Foo
+# irb.2(Foo):005:0> def bar
+# irb.2(Foo):006:1> print "bar"
+# irb.2(Foo):007:1> end
+# irb.2(Foo):010:0> Foo.instance_methods #=> [:bar, :foo, ...]
+#
+# # change the active session
+# irb.2(Foo):011:0> fg 0
+# irb(main):007:0> f = Foo.new #=> #<Foo:0x4010af3c>
+# # invoke a new session with the context of f (instance of Foo)
+# irb(main):008:0> irb f
+# # list open sessions
+# irb.3(<Foo:0x4010af3c>):001:0> jobs
+# #0->irb on main (#<Thread:0x400fb7e4> : stop)
+# #1->irb#1 on main (#<Thread:0x40125d64> : stop)
+# #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop)
+# #3->irb#3 on #<Foo:0x4010af3c> (#<Thread:0x4010a1e0> : running)
+# # evaluate f.foo
+# irb.3(<Foo:0x4010af3c>):002:0> foo #=> 1 => nil
+# # evaluate f.bar
+# irb.3(<Foo:0x4010af3c>):003:0> bar #=> bar => nil
+# # kill jobs 1, 2, and 3
+# irb.3(<Foo:0x4010af3c>):004:0> kill 1, 2, 3
+# # list open sessions, should only include main session
+# irb(main):009:0> jobs
+# #0->irb on main (#<Thread:0x400fb7e4> : running)
+# # quit irb
+# irb(main):010:0> exit
module IRB
# An exception raised by IRB.irb_abort
class Abort < Exception;end
- class << self
- # The current IRB::Context of the session, see IRB.conf
- #
- # irb
- # irb(main):001:0> IRB.CurrentContext.irb_name = "foo"
- # foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo"
- def CurrentContext # :nodoc:
- conf[:MAIN_CONTEXT]
- end
+ @CONF = {}
- # Initializes IRB and creates a new Irb.irb object at the `TOPLEVEL_BINDING`
- def start(ap_path = nil)
- STDOUT.sync = true
- $0 = File::basename(ap_path, ".rb") if ap_path
- setup(ap_path)
+ # Displays current configuration.
+ #
+ # Modifying the configuration is achieved by sending a message to IRB.conf.
+ #
+ # See IRB@Configuration for more information.
+ def IRB.conf
+ @CONF
+ end
- if @CONF[:SCRIPT]
- irb = Irb.new(nil, @CONF[:SCRIPT])
- else
- irb = Irb.new
- end
- irb.run(@CONF)
- end
+ # Returns the current version of IRB, including release version and last
+ # updated date.
+ def IRB.version
+ if v = @CONF[:VERSION] then return v end
- # Quits irb
- def irb_exit(*) # :nodoc:
- throw :IRB_EXIT, false
- end
+ @CONF[:VERSION] = format("irb %s (%s)", @RELEASE_VERSION, @LAST_UPDATE_DATE)
+ end
- # Aborts then interrupts irb.
- #
- # Will raise an Abort exception, or the given `exception`.
- def irb_abort(irb, exception = Abort) # :nodoc:
- irb.context.thread.raise exception, "abort then interrupt!"
+ # The current IRB::Context of the session, see IRB.conf
+ #
+ # irb
+ # irb(main):001:0> IRB.CurrentContext.irb_name = "foo"
+ # foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo"
+ def IRB.CurrentContext
+ IRB.conf[:MAIN_CONTEXT]
+ end
+
+ # Initializes IRB and creates a new Irb.irb object at the +TOPLEVEL_BINDING+
+ def IRB.start(ap_path = nil)
+ STDOUT.sync = true
+ $0 = File::basename(ap_path, ".rb") if ap_path
+
+ IRB.setup(ap_path)
+
+ if @CONF[:SCRIPT]
+ irb = Irb.new(nil, @CONF[:SCRIPT])
+ else
+ irb = Irb.new
end
+ irb.run(@CONF)
end
- class Irb
- # Note: instance and index assignment expressions could also be written like:
- # "foo.bar=(1)" and "foo.[]=(1, bar)", when expressed that way, the former be
- # parsed as :assign and echo will be suppressed, but the latter is parsed as a
- # :method_add_arg and the output won't be suppressed
+ # Calls each event hook of <code>IRB.conf[:AT_EXIT]</code> when the current session quits.
+ def IRB.irb_at_exit
+ @CONF[:AT_EXIT].each{|hook| hook.call}
+ end
- PROMPT_MAIN_TRUNCATE_LENGTH = 32
- PROMPT_MAIN_TRUNCATE_OMISSION = '...'
- CONTROL_CHARACTERS_PATTERN = "\x00-\x1F"
+ # Quits irb
+ def IRB.irb_exit(irb, ret)
+ throw :IRB_EXIT, ret
+ end
- # Returns the current context of this irb session
- attr_reader :context
- # The lexer used by this irb session
- attr_accessor :scanner
+ # Aborts then interrupts irb.
+ #
+ # Will raise an Abort exception, or the given +exception+.
+ def IRB.irb_abort(irb, exception = Abort)
+ irb.context.thread.raise exception, "abort then interrupt!"
+ end
- attr_reader :from_binding
+ class Irb
+ ASSIGNMENT_NODE_TYPES = [
+ # Local, instance, global, class, constant, instance, and index assignment:
+ # "foo = bar",
+ # "@foo = bar",
+ # "$foo = bar",
+ # "@@foo = bar",
+ # "::Foo = bar",
+ # "a::Foo = bar",
+ # "Foo = bar"
+ # "foo.bar = 1"
+ # "foo[1] = bar"
+ :assign,
+
+ # Operation assignment:
+ # "foo += bar"
+ # "foo -= bar"
+ # "foo ||= bar"
+ # "foo &&= bar"
+ :opassign,
+
+ # Multiple assignment:
+ # "foo, bar = 1, 2
+ :massign,
+ ]
+ # Note: instance and index assignment expressions could also be written like:
+ # "foo.bar=(1)" and "foo.[]=(1, bar)", when expressed that way, the former
+ # be parsed as :assign and echo will be suppressed, but the latter is
+ # parsed as a :method_add_arg and the output won't be suppressed
# Creates a new irb session
- def initialize(workspace = nil, input_method = nil, from_binding: false)
- @from_binding = from_binding
+ def initialize(workspace = nil, input_method = nil)
@context = Context.new(self, workspace, input_method)
- @context.workspace.load_helper_methods_to_main
+ @context.main.extend ExtendCommandBundle
@signal_status = :IN_IRB
@scanner = RubyLex.new
- @line_no = 1
end
- # A hook point for `debug` command's breakpoint after :IRB_EXIT as well as its
- # clean-up
+ # A hook point for `debug` command's TracePoint after :IRB_EXIT as well as its clean-up
def debug_break
- # it means the debug integration has been activated
+ # it means the debug command is executed
if defined?(DEBUGGER__) && DEBUGGER__.respond_to?(:capture_frames_without_irb)
# after leaving this initial breakpoint, revert the capture_frames patch
DEBUGGER__.singleton_class.send(:alias_method, :capture_frames, :capture_frames_without_irb)
@@ -957,101 +487,108 @@ module IRB
end
end
- def debug_readline(binding)
- workspace = IRB::WorkSpace.new(binding)
- context.replace_workspace(workspace)
- context.workspace.load_helper_methods_to_main
- @line_no += 1
-
- # When users run:
- # 1. Debugging commands, like `step 2`
- # 2. Any input that's not irb-command, like `foo = 123`
- #
- #
- # Irb#eval_input will simply return the input, and we need to pass it to the
- # debugger.
- input = nil
- forced_exit = catch(:IRB_EXIT) do
- if IRB.conf[:SAVE_HISTORY] && context.io.support_history_saving?
- # Previous IRB session's history has been saved when `Irb#run` is exited We need
- # to make sure the saved history is not saved again by resetting the counter
- context.io.reset_history_counter
-
- begin
- input = eval_input
- ensure
- context.io.save_history
- end
- else
- input = eval_input
- end
- false
- end
-
- Kernel.exit if forced_exit
-
- if input&.include?("\n")
- @line_no += input.count("\n") - 1
- end
-
- input
- end
-
def run(conf = IRB.conf)
- in_nested_session = !!conf[:MAIN_CONTEXT]
conf[:IRB_RC].call(context) if conf[:IRB_RC]
- prev_context = conf[:MAIN_CONTEXT]
conf[:MAIN_CONTEXT] = context
- save_history = !in_nested_session && conf[:SAVE_HISTORY] && context.io.support_history_saving?
-
- if save_history
- context.io.load_history
- end
-
prev_trap = trap("SIGINT") do
signal_handle
end
begin
- if defined?(RubyVM.keep_script_lines)
- keep_script_lines_backup = RubyVM.keep_script_lines
- RubyVM.keep_script_lines = true
- end
-
- forced_exit = catch(:IRB_EXIT) do
+ catch(:IRB_EXIT) do
eval_input
end
ensure
- # Do not restore to nil. It will cause IRB crash when used with threads.
- IRB.conf[:MAIN_CONTEXT] = prev_context if prev_context
-
- RubyVM.keep_script_lines = keep_script_lines_backup if defined?(RubyVM.keep_script_lines)
trap("SIGINT", prev_trap)
conf[:AT_EXIT].each{|hook| hook.call}
-
- context.io.save_history if save_history
- Kernel.exit if forced_exit
end
end
+ # Returns the current context of this irb session
+ attr_reader :context
+ # The lexer used by this irb session
+ attr_accessor :scanner
+
# Evaluates input for this session.
def eval_input
- configure_io
+ exc = nil
+
+ @scanner.set_prompt do
+ |ltype, indent, continue, line_no|
+ if ltype
+ f = @context.prompt_s
+ elsif continue
+ f = @context.prompt_c
+ elsif indent > 0
+ f = @context.prompt_n
+ else
+ f = @context.prompt_i
+ end
+ f = "" unless f
+ if @context.prompting?
+ @context.io.prompt = p = prompt(f, ltype, indent, line_no)
+ else
+ @context.io.prompt = p = ""
+ end
+ if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent)
+ unless ltype
+ prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
+ ind = prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
+ indent * 2 - p.size
+ ind += 2 if continue
+ @context.io.prompt = p + " " * ind if ind > 0
+ end
+ end
+ @context.io.prompt
+ end
- each_top_level_statement do |statement, line_no|
- signal_status(:IN_EVAL) do
- begin
- # If the integration with debugger is activated, we return certain input if it
- # should be dealt with by debugger
- if @context.with_debugger && statement.should_be_handled_by_debugger?
- return statement.code
+ @scanner.set_input(@context.io, context: @context) do
+ signal_status(:IN_INPUT) do
+ if l = @context.io.gets
+ print l if @context.verbose?
+ else
+ if @context.ignore_eof? and @context.io.readable_after_eof?
+ l = "\n"
+ if @context.verbose?
+ printf "Use \"exit\" to leave %s\n", @context.ap_name
+ end
+ else
+ print "\n" if @context.prompting?
end
+ end
+ l
+ end
+ end
- @context.evaluate(statement, line_no)
+ @scanner.set_auto_indent(@context) if @context.auto_indent_mode
- if @context.echo? && !statement.suppresses_echo?
- if statement.is_assignment?
+ @scanner.each_top_level_statement(@context) do |line, line_no|
+ signal_status(:IN_EVAL) do
+ begin
+ line.untaint if RUBY_VERSION < '2.7'
+ if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty?
+ IRB.set_measure_callback
+ end
+ # Assignment expression check should be done before @context.evaluate to handle code like `a /2#/ if false; a = 1`
+ is_assignment = assignment_expression?(line)
+ if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty?
+ result = nil
+ last_proc = proc{ result = @context.evaluate(line, line_no, exception: exc) }
+ IRB.conf[:MEASURE_CALLBACKS].inject(last_proc) { |chain, item|
+ _name, callback, arg = item
+ proc {
+ callback.(@context, line, line_no, arg, exception: exc) do
+ chain.call
+ end
+ }
+ }.call
+ @context.set_last_value(result)
+ else
+ @context.evaluate(line, line_no, exception: exc)
+ end
+ if @context.echo?
+ if is_assignment
if @context.echo_on_assignment?
output_value(@context.echo_on_assignment? == :truncate)
end
@@ -1059,138 +596,17 @@ module IRB
output_value
end
end
+ rescue Interrupt => exc
rescue SystemExit, SignalException
raise
- rescue Interrupt, Exception => exc
- handle_exception(exc)
- @context.workspace.local_variable_set(:_, exc)
- end
- end
- end
- end
-
- def read_input(prompt)
- signal_status(:IN_INPUT) do
- @context.io.prompt = prompt
- if l = @context.io.gets
- print l if @context.verbose?
- else
- if @context.ignore_eof? and @context.io.readable_after_eof?
- l = "\n"
- if @context.verbose?
- printf "Use \"exit\" to leave %s\n", @context.ap_name
- end
- else
- print "\n" if @context.prompting?
- end
- end
- l
- end
- end
-
- def readmultiline
- prompt = generate_prompt([], false, 0)
-
- # multiline
- return read_input(prompt) if @context.io.respond_to?(:check_termination)
-
- # nomultiline
- code = +''
- line_offset = 0
- loop do
- line = read_input(prompt)
- unless line
- return code.empty? ? nil : code
- end
-
- code << line
- return code if command?(code)
-
- tokens, opens, terminated = @scanner.check_code_state(code, local_variables: @context.local_variables)
- return code if terminated
-
- line_offset += 1
- continue = @scanner.should_continue?(tokens)
- prompt = generate_prompt(opens, continue, line_offset)
- end
- end
-
- def each_top_level_statement
- loop do
- code = readmultiline
- break unless code
- yield build_statement(code), @line_no
- @line_no += code.count("\n")
- rescue RubyLex::TerminateLineInput
- end
- end
-
- def build_statement(code)
- if code.match?(/\A\n*\z/)
- return Statement::EmptyInput.new
- end
-
- code.force_encoding(@context.io.encoding)
- if (command, arg = @context.parse_command(code))
- command_class = Command.load_command(command)
- Statement::Command.new(code, command_class, arg)
- else
- is_assignment_expression = @scanner.assignment_expression?(code, local_variables: @context.local_variables)
- Statement::Expression.new(code, is_assignment_expression)
- end
- end
-
- def command?(code)
- !!@context.parse_command(code)
- end
-
- def configure_io
- if @context.io.respond_to?(:check_termination)
- @context.io.check_termination do |code|
- if Reline::IOGate.in_pasting?
- rest = @scanner.check_termination_in_prev_line(code, local_variables: @context.local_variables)
- if rest
- Reline.delete_text
- rest.bytes.reverse_each do |c|
- Reline.ungetc(c)
- end
- true
- else
- false
- end
+ rescue Exception => exc
else
- next true if command?(code)
-
- _tokens, _opens, terminated = @scanner.check_code_state(code, local_variables: @context.local_variables)
- terminated
- end
- end
- end
- if @context.io.respond_to?(:dynamic_prompt)
- @context.io.dynamic_prompt do |lines|
- tokens = RubyLex.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join, local_variables: @context.local_variables)
- line_results = IRB::NestingParser.parse_by_line(tokens)
- tokens_until_line = []
- line_results.map.with_index do |(line_tokens, _prev_opens, next_opens, _min_depth), line_num_offset|
- line_tokens.each do |token, _s|
- # Avoid appending duplicated token. Tokens that include "n" like multiline
- # tstring_content can exist in multiple lines.
- tokens_until_line << token if token != tokens_until_line.last
- end
- continue = @scanner.should_continue?(tokens_until_line)
- generate_prompt(next_opens, continue, line_num_offset)
+ exc = nil
+ next
end
- end
- end
-
- if @context.io.respond_to?(:auto_indent) and @context.auto_indent_mode
- @context.io.auto_indent do |lines, line_index, byte_pointer, is_newline|
- next nil if lines == [nil] # Workaround for exit IRB with CTRL+d
- next nil if !is_newline && lines[line_index]&.byteslice(0, byte_pointer)&.match?(/\A\s*\z/)
-
- code = lines[0..line_index].map { |l| "#{l}\n" }.join
- tokens = RubyLex.ripper_lex_without_warning(code, local_variables: @context.local_variables)
- @scanner.process_indent_level(tokens, lines, line_index, is_newline)
+ handle_exception(exc)
+ @context.workspace.local_variable_set(:_, exc)
+ exc = nil
end
end
end
@@ -1225,75 +641,60 @@ module IRB
end
def handle_exception(exc)
- if exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
+ if exc.backtrace && exc.backtrace[0] =~ /\/irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
!(SyntaxError === exc) && !(EncodingError === exc)
# The backtrace of invalid encoding hash (ex. {"\xAE": 1}) raises EncodingError without lineno.
irb_bug = true
else
irb_bug = false
- # To support backtrace filtering while utilizing Exception#full_message, we need to clone
- # the exception to avoid modifying the original exception's backtrace.
- exc = exc.clone
- filtered_backtrace = exc.backtrace.map { |l| @context.workspace.filter_backtrace(l) }.compact
- backtrace_filter = IRB.conf[:BACKTRACE_FILTER]
-
- if backtrace_filter
- if backtrace_filter.respond_to?(:call)
- filtered_backtrace = backtrace_filter.call(filtered_backtrace)
- else
- warn "IRB.conf[:BACKTRACE_FILTER] #{backtrace_filter} should respond to `call` method"
- end
- end
-
- exc.set_backtrace(filtered_backtrace)
end
- highlight = Color.colorable?
-
- order =
+ if exc.backtrace
+ order = nil
if RUBY_VERSION < '3.0.0'
- STDOUT.tty? ? :bottom : :top
+ if STDOUT.tty?
+ message = exc.full_message(order: :bottom)
+ order = :bottom
+ else
+ message = exc.full_message(order: :top)
+ order = :top
+ end
else # '3.0.0' <= RUBY_VERSION
- :top
- end
-
- message = exc.full_message(order: order, highlight: highlight)
- message = convert_invalid_byte_sequence(message, exc.message.encoding)
- message = encode_with_invalid_byte_sequence(message, IRB.conf[:LC_MESSAGES].encoding) unless message.encoding.to_s.casecmp?(IRB.conf[:LC_MESSAGES].encoding.to_s)
- message = message.gsub(/((?:^\t.+$\n)+)/) { |m|
- case order
- when :top
- lines = m.split("\n")
- when :bottom
- lines = m.split("\n").reverse
+ message = exc.full_message(order: :top)
+ order = :top
end
- unless irb_bug
- if lines.size > @context.back_trace_limit
- omit = lines.size - @context.back_trace_limit
- lines = lines[0..(@context.back_trace_limit - 1)]
- lines << "\t... %d levels..." % omit
+ message = convert_invalid_byte_sequence(message, exc.message.encoding)
+ message = encode_with_invalid_byte_sequence(message, IRB.conf[:LC_MESSAGES].encoding) unless message.encoding.to_s.casecmp?(IRB.conf[:LC_MESSAGES].encoding.to_s)
+ message = message.gsub(/((?:^\t.+$\n)+)/) { |m|
+ case order
+ when :top
+ lines = m.split("\n")
+ when :bottom
+ lines = m.split("\n").reverse
end
- end
- lines = lines.reverse if order == :bottom
- lines.map{ |l| l + "\n" }.join
- }
- # The "<top (required)>" in "(irb)" may be the top level of IRB so imitate the main object.
- message = message.gsub(/\(irb\):(?<num>\d+):in (?<open_quote>[`'])<(?<frame>top \(required\))>'/) { "(irb):#{$~[:num]}:in #{$~[:open_quote]}<main>'" }
- puts message
- puts 'Maybe IRB bug!' if irb_bug
- rescue Exception => handler_exc
- begin
- puts exc.inspect
- puts "backtraces are hidden because #{handler_exc} was raised when processing them"
- rescue Exception
- puts 'Uninspectable exception occurred'
+ unless irb_bug
+ lines = lines.map { |l| @context.workspace.filter_backtrace(l) }.compact
+ if lines.size > @context.back_trace_limit
+ omit = lines.size - @context.back_trace_limit
+ lines = lines[0..(@context.back_trace_limit - 1)]
+ lines << "\t... %d levels..." % omit
+ end
+ end
+ lines = lines.reverse if order == :bottom
+ lines.map{ |l| l + "\n" }.join
+ }
+ # The "<top (required)>" in "(irb)" may be the top level of IRB so imitate the main object.
+ message = message.gsub(/\(irb\):(?<num>\d+):in `<(?<frame>top \(required\))>'/) { "(irb):#{$~[:num]}:in `<main>'" }
+ puts message
end
+ print "Maybe IRB bug!\n" if irb_bug
end
- # Evaluates the given block using the given `path` as the Context#irb_path and
- # `name` as the Context#irb_name.
+ # Evaluates the given block using the given +path+ as the Context#irb_path
+ # and +name+ as the Context#irb_name.
#
- # Used by the irb command `source`, see IRB@IRB+Sessions for more information.
+ # Used by the irb command +source+, see IRB@IRB+Sessions for more
+ # information.
def suspend_name(path = nil, name = nil)
@context.irb_path, back_path = path, @context.irb_path if path
@context.irb_name, back_name = name, @context.irb_name if name
@@ -1305,22 +706,25 @@ module IRB
end
end
- # Evaluates the given block using the given `workspace` as the
+ # Evaluates the given block using the given +workspace+ as the
# Context#workspace.
#
- # Used by the irb command `irb_load`, see IRB@IRB+Sessions for more information.
+ # Used by the irb command +irb_load+, see IRB@IRB+Sessions for more
+ # information.
def suspend_workspace(workspace)
- current_workspace = @context.workspace
- @context.replace_workspace(workspace)
- yield
- ensure
- @context.replace_workspace current_workspace
+ @context.workspace, back_workspace = workspace, @context.workspace
+ begin
+ yield back_workspace
+ ensure
+ @context.workspace = back_workspace
+ end
end
- # Evaluates the given block using the given `input_method` as the Context#io.
+ # Evaluates the given block using the given +input_method+ as the
+ # Context#io.
#
- # Used by the irb commands `source` and `irb_load`, see IRB@IRB+Sessions for
- # more information.
+ # Used by the irb commands +source+ and +irb_load+, see IRB@IRB+Sessions
+ # for more information.
def suspend_input_method(input_method)
back_io = @context.io
@context.instance_eval{@io = input_method}
@@ -1331,6 +735,16 @@ module IRB
end
end
+ # Evaluates the given block using the given +context+ as the Context.
+ def suspend_context(context)
+ @context, back_context = context, @context
+ begin
+ yield back_context
+ ensure
+ @context = back_context
+ end
+ end
+
# Handler for the signal SIGINT, see Kernel#trap for more information.
def signal_handle
unless @context.ignore_sigint?
@@ -1353,7 +767,7 @@ module IRB
end
end
- # Evaluates the given block using the given `status`.
+ # Evaluates the given block using the given +status+.
def signal_status(status)
return yield if @signal_status == :IN_LOAD
@@ -1366,6 +780,45 @@ module IRB
end
end
+ def prompt(prompt, ltype, indent, line_no) # :nodoc:
+ p = prompt.dup
+ p.gsub!(/%([0-9]+)?([a-zA-Z])/) do
+ case $2
+ when "N"
+ @context.irb_name
+ when "m"
+ @context.main.to_s
+ when "M"
+ @context.main.inspect
+ when "l"
+ ltype
+ when "i"
+ if indent < 0
+ if $1
+ "-".rjust($1.to_i)
+ else
+ "-"
+ end
+ else
+ if $1
+ format("%" + $1 + "d", indent)
+ else
+ indent.to_s
+ end
+ end
+ when "n"
+ if $1
+ format("%" + $1 + "d", line_no)
+ else
+ line_no.to_s
+ end
+ when "%"
+ "%"
+ end
+ end
+ p
+ end
+
def output_value(omit = false) # :nodoc:
str = @context.inspect_last_value
multiline_p = str.include?("\n")
@@ -1395,16 +848,15 @@ module IRB
end
end
end
-
if multiline_p && @context.newline_before_multiline_output?
- str = "\n" + str
+ printf @context.return_format, "\n#{str}"
+ else
+ printf @context.return_format, str
end
-
- Pager.page_content(format(@context.return_format, str), retain_content: true)
end
- # Outputs the local variables to this current session, including #signal_status
- # and #context, using IRB::Locale.
+ # Outputs the local variables to this current session, including
+ # #signal_status and #context, using IRB::Locale.
def inspect
ary = []
for iv in instance_variables
@@ -1420,94 +872,60 @@ module IRB
format("#<%s: %s>", self.class, ary.join(", "))
end
- private
-
- def generate_prompt(opens, continue, line_offset)
- ltype = @scanner.ltype_from_open_tokens(opens)
- indent = @scanner.calc_indent_level(opens)
- continue = opens.any? || continue
- line_no = @line_no + line_offset
-
- if ltype
- f = @context.prompt_s
- elsif continue
- f = @context.prompt_c
- else
- f = @context.prompt_i
- end
- f = "" unless f
- if @context.prompting?
- p = format_prompt(f, ltype, indent, line_no)
- else
- p = ""
- end
- if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent)
- unless ltype
- prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i
- ind = format_prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size +
- indent * 2 - p.size
- p += " " * ind if ind > 0
- end
- end
- p
+ def assignment_expression?(line)
+ # Try to parse the line and check if the last of possibly multiple
+ # expressions is an assignment type.
+
+ # If the expression is invalid, Ripper.sexp should return nil which will
+ # result in false being returned. Any valid expression should return an
+ # s-expression where the second element of the top level array is an
+ # array of parsed expressions. The first element of each expression is the
+ # expression's type.
+ verbose, $VERBOSE = $VERBOSE, nil
+ code = "#{RubyLex.generate_local_variables_assign_code(@context.local_variables) || 'nil;'}\n#{line}"
+ # Get the last node_type of the line. drop(1) is to ignore the local_variables_assign_code part.
+ node_type = Ripper.sexp(code)&.dig(1)&.drop(1)&.dig(-1, 0)
+ ASSIGNMENT_NODE_TYPES.include?(node_type)
+ ensure
+ $VERBOSE = verbose
end
- def truncate_prompt_main(str) # :nodoc:
- str = str.tr(CONTROL_CHARACTERS_PATTERN, ' ')
- if str.size <= PROMPT_MAIN_TRUNCATE_LENGTH
- str
- else
- str[0, PROMPT_MAIN_TRUNCATE_LENGTH - PROMPT_MAIN_TRUNCATE_OMISSION.size] + PROMPT_MAIN_TRUNCATE_OMISSION
- end
- end
+ ATTR_TTY = "\e[%sm"
+ def ATTR_TTY.[](*a) self % a.join(";"); end
+ ATTR_PLAIN = ""
+ def ATTR_PLAIN.[](*) self; end
+ end
- def format_prompt(format, ltype, indent, line_no) # :nodoc:
- format.gsub(/%([0-9]+)?([a-zA-Z%])/) do
- case $2
- when "N"
- @context.irb_name
- when "m"
- main_str = @context.main.to_s rescue "!#{$!.class}"
- truncate_prompt_main(main_str)
- when "M"
- main_str = @context.main.inspect rescue "!#{$!.class}"
- truncate_prompt_main(main_str)
- when "l"
- ltype
- when "i"
- if indent < 0
- if $1
- "-".rjust($1.to_i)
- else
- "-"
- end
- else
- if $1
- format("%" + $1 + "d", indent)
- else
- indent.to_s
- end
- end
- when "n"
- if $1
- format("%" + $1 + "d", line_no)
- else
- line_no.to_s
- end
- when "%"
- "%" unless $1
- end
+ def @CONF.inspect
+ IRB.version unless self[:VERSION]
+
+ array = []
+ for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name}
+ case k
+ when :MAIN_CONTEXT, :__TMP__EHV__
+ array.push format("CONF[:%s]=...myself...", k.id2name)
+ when :PROMPT
+ s = v.collect{
+ |kk, vv|
+ ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"}
+ format(":%s=>{%s}", kk.id2name, ss.join(", "))
+ }
+ array.push format("CONF[:%s]={%s}", k.id2name, s.join(", "))
+ else
+ array.push format("CONF[:%s]=%s", k.id2name, v.inspect)
end
end
+ array.join("\n")
end
end
class Binding
- # Opens an IRB session where `binding.irb` is called which allows for
- # interactive debugging. You can call any methods or variables available in the
- # current scope, and mutate state if you need to.
+ # Opens an IRB session where +binding.irb+ is called which allows for
+ # interactive debugging. You can call any methods or variables available in
+ # the current scope, and mutate state if you need to.
+ #
#
- # Given a Ruby file called `potato.rb` containing the following code:
+ # Given a Ruby file called +potato.rb+ containing the following code:
#
# class Potato
# def initialize
@@ -1519,8 +937,8 @@ class Binding
#
# Potato.new
#
- # Running `ruby potato.rb` will open an IRB session where `binding.irb` is
- # called, and you will see the following:
+ # Running <code>ruby potato.rb</code> will open an IRB session where
+ # +binding.irb+ is called, and you will see the following:
#
# $ ruby potato.rb
#
@@ -1550,42 +968,22 @@ class Binding
# irb(#<Potato:0x00007feea1916670>):004:0> @cooked = true
# => true
#
- # You can exit the IRB session with the `exit` command. Note that exiting will
- # resume execution where `binding.irb` had paused it, as you can see from the
+ # You can exit the IRB session with the +exit+ command. Note that exiting will
+ # resume execution where +binding.irb+ had paused it, as you can see from the
# output printed to standard output in this example:
#
# irb(#<Potato:0x00007feea1916670>):005:0> exit
# Cooked potato: true
#
- # See IRB for more information.
+ #
+ # See IRB@IRB+Usage for more information.
def irb(show_code: true)
- # Setup IRB with the current file's path and no command line arguments
- IRB.setup(source_location[0], argv: []) unless IRB.initialized?
- # Create a new workspace using the current binding
+ IRB.setup(source_location[0], argv: [])
workspace = IRB::WorkSpace.new(self)
- # Print the code around the binding if show_code is true
STDOUT.print(workspace.code_around_binding) if show_code
- # Get the original IRB instance
- debugger_irb = IRB.instance_variable_get(:@debugger_irb)
-
- irb_path = File.expand_path(source_location[0])
-
- if debugger_irb
- # If we're already in a debugger session, set the workspace and irb_path for the original IRB instance
- debugger_irb.context.replace_workspace(workspace)
- debugger_irb.context.irb_path = irb_path
- # If we've started a debugger session and hit another binding.irb, we don't want
- # to start an IRB session instead, we want to resume the irb:rdbg session.
- IRB::Debug.setup(debugger_irb)
- IRB::Debug.insert_debug_break
- debugger_irb.debug_break
- else
- # If we're not in a debugger session, create a new IRB instance with the current
- # workspace
- binding_irb = IRB::Irb.new(workspace, from_binding: true)
- binding_irb.context.irb_path = irb_path
- binding_irb.run(IRB.conf)
- binding_irb.debug_break
- end
+ binding_irb = IRB::Irb.new(workspace)
+ binding_irb.context.irb_path = File.expand_path(source_location[0])
+ binding_irb.run(IRB.conf)
+ binding_irb.debug_break
end
end
diff --git a/lib/irb/cmd/backtrace.rb b/lib/irb/cmd/backtrace.rb
new file mode 100644
index 0000000000..f632894618
--- /dev/null
+++ b/lib/irb/cmd/backtrace.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Backtrace < DebugCommand
+ def self.transform_args(args)
+ args&.dump
+ end
+
+ def execute(*args)
+ super(pre_cmds: ["backtrace", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/break.rb b/lib/irb/cmd/break.rb
new file mode 100644
index 0000000000..df259a90ca
--- /dev/null
+++ b/lib/irb/cmd/break.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Break < DebugCommand
+ def self.transform_args(args)
+ args&.dump
+ end
+
+ def execute(args = nil)
+ super(pre_cmds: "break #{args}")
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/catch.rb b/lib/irb/cmd/catch.rb
new file mode 100644
index 0000000000..40b62c7533
--- /dev/null
+++ b/lib/irb/cmd/catch.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Catch < DebugCommand
+ def self.transform_args(args)
+ args&.dump
+ end
+
+ def execute(*args)
+ super(pre_cmds: ["catch", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/chws.rb b/lib/irb/cmd/chws.rb
new file mode 100644
index 0000000000..7c84ba0a4b
--- /dev/null
+++ b/lib/irb/cmd/chws.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: false
+#
+# change-ws.rb -
+# $Release Version: 0.9.6$
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+
+require_relative "nop"
+require_relative "../ext/change-ws"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+
+ class CurrentWorkingWorkspace < Nop
+ category "IRB"
+ description "Show the current workspace."
+
+ def execute(*obj)
+ irb_context.main
+ end
+ end
+
+ class ChangeWorkspace < Nop
+ category "IRB"
+ description "Change the current workspace to an object."
+
+ def execute(*obj)
+ irb_context.change_workspace(*obj)
+ irb_context.main
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/continue.rb b/lib/irb/cmd/continue.rb
new file mode 100644
index 0000000000..9136177eef
--- /dev/null
+++ b/lib/irb/cmd/continue.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Continue < DebugCommand
+ def execute(*args)
+ super(do_cmds: ["continue", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/debug.rb b/lib/irb/cmd/debug.rb
new file mode 100644
index 0000000000..7d39b9fa27
--- /dev/null
+++ b/lib/irb/cmd/debug.rb
@@ -0,0 +1,136 @@
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Debug < Nop
+ category "Debugging"
+ description "Start the debugger of debug.gem."
+
+ BINDING_IRB_FRAME_REGEXPS = [
+ '<internal:prelude>',
+ binding.method(:irb).source_location.first,
+ ].map { |file| /\A#{Regexp.escape(file)}:\d+:in `irb'\z/ }
+ IRB_DIR = File.expand_path('..', __dir__)
+
+ def execute(pre_cmds: nil, do_cmds: nil)
+ unless binding_irb?
+ puts "`debug` command is only available when IRB is started with binding.irb"
+ return
+ end
+
+ unless setup_debugger
+ puts <<~MSG
+ You need to install the debug gem before using this command.
+ If you use `bundle exec`, please add `gem "debug"` into your Gemfile.
+ MSG
+ return
+ end
+
+ options = { oneshot: true, hook_call: false }
+ if pre_cmds || do_cmds
+ options[:command] = ['irb', pre_cmds, do_cmds]
+ end
+ if DEBUGGER__::LineBreakpoint.instance_method(:initialize).parameters.include?([:key, :skip_src])
+ options[:skip_src] = true
+ end
+
+ # To make debugger commands like `next` or `continue` work without asking
+ # the user to quit IRB after that, we need to exit IRB first and then hit
+ # a TracePoint on #debug_break.
+ file, lineno = IRB::Irb.instance_method(:debug_break).source_location
+ DEBUGGER__::SESSION.add_line_breakpoint(file, lineno + 1, **options)
+ # exit current Irb#run call
+ throw :IRB_EXIT
+ end
+
+ private
+
+ def binding_irb?
+ caller.any? do |frame|
+ BINDING_IRB_FRAME_REGEXPS.any? do |regexp|
+ frame.match?(regexp)
+ end
+ end
+ end
+
+ module SkipPathHelperForIRB
+ def skip_internal_path?(path)
+ # The latter can be removed once https://github.com/ruby/debug/issues/866 is resolved
+ super || path.match?(IRB_DIR) || path.match?('<internal:prelude>')
+ end
+ end
+
+ def setup_debugger
+ unless defined?(DEBUGGER__::SESSION)
+ begin
+ require "debug/session"
+ rescue LoadError # debug.gem is not written in Gemfile
+ return false unless load_bundled_debug_gem
+ end
+ DEBUGGER__.start(nonstop: true)
+ end
+
+ unless DEBUGGER__.respond_to?(:capture_frames_without_irb)
+ DEBUGGER__.singleton_class.send(:alias_method, :capture_frames_without_irb, :capture_frames)
+
+ def DEBUGGER__.capture_frames(*args)
+ frames = capture_frames_without_irb(*args)
+ frames.reject! do |frame|
+ frame.realpath&.start_with?(IRB_DIR) || frame.path == "<internal:prelude>"
+ end
+ frames
+ end
+
+ DEBUGGER__::ThreadClient.prepend(SkipPathHelperForIRB)
+ end
+
+ true
+ end
+
+ # This is used when debug.gem is not written in Gemfile. Even if it's not
+ # installed by `bundle install`, debug.gem is installed by default because
+ # it's a bundled gem. This method tries to activate and load that.
+ def load_bundled_debug_gem
+ # Discover latest debug.gem under GEM_PATH
+ debug_gem = Gem.paths.path.flat_map { |path| Dir.glob("#{path}/gems/debug-*") }.select do |path|
+ File.basename(path).match?(/\Adebug-\d+\.\d+\.\d+(\w+)?\z/)
+ end.sort_by do |path|
+ Gem::Version.new(File.basename(path).delete_prefix('debug-'))
+ end.last
+ return false unless debug_gem
+
+ # Discover debug/debug.so under extensions for Ruby 3.2+
+ ext_name = "/debug/debug.#{RbConfig::CONFIG['DLEXT']}"
+ ext_path = Gem.paths.path.flat_map do |path|
+ Dir.glob("#{path}/extensions/**/#{File.basename(debug_gem)}#{ext_name}")
+ end.first
+
+ # Attempt to forcibly load the bundled gem
+ if ext_path
+ $LOAD_PATH << ext_path.delete_suffix(ext_name)
+ end
+ $LOAD_PATH << "#{debug_gem}/lib"
+ begin
+ require "debug/session"
+ puts "Loaded #{File.basename(debug_gem)}"
+ true
+ rescue LoadError
+ false
+ end
+ end
+ end
+
+ class DebugCommand < Debug
+ def self.category
+ "Debugging"
+ end
+
+ def self.description
+ command_name = self.name.split("::").last.downcase
+ "Start the debugger of debug.gem and run its `#{command_name}` command."
+ end
+ end
+ end
+end
diff --git a/lib/irb/cmd/delete.rb b/lib/irb/cmd/delete.rb
new file mode 100644
index 0000000000..aeb26d2572
--- /dev/null
+++ b/lib/irb/cmd/delete.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Delete < DebugCommand
+ def execute(*args)
+ super(pre_cmds: ["delete", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/edit.rb b/lib/irb/cmd/edit.rb
new file mode 100644
index 0000000000..0103891cf4
--- /dev/null
+++ b/lib/irb/cmd/edit.rb
@@ -0,0 +1,61 @@
+require 'shellwords'
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Edit < Nop
+ category "Misc"
+ description 'Open a file with the editor command defined with `ENV["EDITOR"]`.'
+
+ class << self
+ def transform_args(args)
+ # Return a string literal as is for backward compatibility
+ if args.nil? || args.empty? || string_literal?(args)
+ args
+ else # Otherwise, consider the input as a String for convenience
+ args.strip.dump
+ end
+ end
+ end
+
+ def execute(*args)
+ path = args.first
+
+ if path.nil? && (irb_path = @irb_context.irb_path)
+ path = irb_path
+ end
+
+ if !File.exist?(path)
+ require_relative "show_source"
+
+ source =
+ begin
+ ShowSource.find_source(path, @irb_context)
+ rescue NameError
+ # if user enters a path that doesn't exist, it'll cause NameError when passed here because find_source would try to evaluate it as well
+ # in this case, we should just ignore the error
+ end
+
+ if source && File.exist?(source.file)
+ path = source.file
+ else
+ puts "Can not find file: #{path}"
+ return
+ end
+ end
+
+ if editor = ENV['EDITOR']
+ puts "command: '#{editor}'"
+ puts " path: #{path}"
+ system(*Shellwords.split(editor), path)
+ else
+ puts "Can not find editor setting: ENV['EDITOR']"
+ end
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/finish.rb b/lib/irb/cmd/finish.rb
new file mode 100644
index 0000000000..29f100feb5
--- /dev/null
+++ b/lib/irb/cmd/finish.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Finish < DebugCommand
+ def execute(*args)
+ super(do_cmds: ["finish", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/fork.rb b/lib/irb/cmd/fork.rb
new file mode 100644
index 0000000000..255a670dce
--- /dev/null
+++ b/lib/irb/cmd/fork.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: false
+#
+# fork.rb -
+# $Release Version: 0.9.6 $
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Fork < Nop
+ def execute
+ pid = __send__ ExtendCommand.irb_original_method_name("fork")
+ unless pid
+ class << self
+ alias_method :exit, ExtendCommand.irb_original_method_name('exit')
+ end
+ if block_given?
+ begin
+ yield
+ ensure
+ exit
+ end
+ end
+ end
+ pid
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/help.rb b/lib/irb/cmd/help.rb
new file mode 100644
index 0000000000..2a135cdb14
--- /dev/null
+++ b/lib/irb/cmd/help.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: false
+#
+# help.rb - helper using ri
+# $Release Version: 0.9.6$
+# $Revision$
+#
+# --
+#
+#
+#
+
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Help < Nop
+ class << self
+ def transform_args(args)
+ # Return a string literal as is for backward compatibility
+ if args.empty? || string_literal?(args)
+ args
+ else # Otherwise, consider the input as a String for convenience
+ args.strip.dump
+ end
+ end
+ end
+
+ category "Context"
+ description "Enter the mode to look up RI documents."
+
+ def execute(*names)
+ require 'rdoc/ri/driver'
+ opts = RDoc::RI::Driver.process_args([])
+ IRB::ExtendCommand::Help.const_set(:Ri, RDoc::RI::Driver.new(opts))
+ rescue LoadError, SystemExit
+ IRB::ExtendCommand::Help.remove_method(:execute)
+ # raise NoMethodError in ensure
+ else
+ def execute(*names)
+ if names.empty?
+ Ri.interactive
+ return
+ end
+ names.each do |name|
+ begin
+ Ri.display_name(name.to_s)
+ rescue RDoc::RI::Error
+ puts $!.message
+ end
+ end
+ nil
+ end
+ nil
+ ensure
+ execute(*names)
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/info.rb b/lib/irb/cmd/info.rb
new file mode 100644
index 0000000000..2c0a32b34f
--- /dev/null
+++ b/lib/irb/cmd/info.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Info < DebugCommand
+ def self.transform_args(args)
+ args&.dump
+ end
+
+ def execute(*args)
+ super(pre_cmds: ["info", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/irb_info.rb b/lib/irb/cmd/irb_info.rb
new file mode 100644
index 0000000000..da11e8d40b
--- /dev/null
+++ b/lib/irb/cmd/irb_info.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: false
+
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class IrbInfo < Nop
+ category "IRB"
+ description "Show information about IRB."
+
+ def execute
+ Class.new {
+ def inspect
+ str = "Ruby version: #{RUBY_VERSION}\n"
+ str += "IRB version: #{IRB.version}\n"
+ str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
+ str += ".irbrc path: #{IRB.rc_file}\n" if File.exist?(IRB.rc_file)
+ str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
+ str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty?
+ str += "LC_ALL env: #{ENV["LC_ALL"]}\n" if ENV["LC_ALL"] && !ENV["LC_ALL"].empty?
+ str += "East Asian Ambiguous Width: #{Reline.ambiguous_width.inspect}\n"
+ if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
+ codepage = `chcp`.b.sub(/.*: (\d+)\n/, '\1')
+ str += "Code page: #{codepage}\n"
+ end
+ str
+ end
+ alias_method :to_s, :inspect
+ }.new
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/load.rb b/lib/irb/cmd/load.rb
new file mode 100644
index 0000000000..2897bbd975
--- /dev/null
+++ b/lib/irb/cmd/load.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: false
+#
+# load.rb -
+# $Release Version: 0.9.6$
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+
+require_relative "nop"
+require_relative "../ext/loader"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class LoaderCommand < Nop
+ include IrbLoader
+
+ def raise_cmd_argument_error
+ raise CommandArgumentError.new("Please specify the file name.")
+ end
+ end
+
+ class Load < LoaderCommand
+ category "IRB"
+ description "Load a Ruby file."
+
+ def execute(file_name = nil, priv = nil)
+ raise_cmd_argument_error unless file_name
+ irb_load(file_name, priv)
+ end
+ end
+
+ class Require < LoaderCommand
+ category "IRB"
+ description "Require a Ruby file."
+ def execute(file_name = nil)
+ raise_cmd_argument_error unless file_name
+
+ rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?")
+ return false if $".find{|f| f =~ rex}
+
+ case file_name
+ when /\.rb$/
+ begin
+ if irb_load(file_name)
+ $".push file_name
+ return true
+ end
+ rescue LoadError
+ end
+ when /\.(so|o|sl)$/
+ return ruby_require(file_name)
+ end
+
+ begin
+ irb_load(f = file_name + ".rb")
+ $".push f
+ return true
+ rescue LoadError
+ return ruby_require(file_name)
+ end
+ end
+ end
+
+ class Source < LoaderCommand
+ category "IRB"
+ description "Loads a given file in the current session."
+
+ def execute(file_name = nil)
+ raise_cmd_argument_error unless file_name
+
+ source_file(file_name)
+ end
+ end
+ end
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/ls.rb b/lib/irb/cmd/ls.rb
new file mode 100644
index 0000000000..b65fae2bf1
--- /dev/null
+++ b/lib/irb/cmd/ls.rb
@@ -0,0 +1,116 @@
+# frozen_string_literal: true
+
+require "reline"
+require_relative "nop"
+require_relative "../color"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Ls < Nop
+ category "Context"
+ description "Show methods, constants, and variables. `-g [query]` or `-G [query]` allows you to filter out the output."
+
+ def self.transform_args(args)
+ if match = args&.match(/\A(?<args>.+\s|)(-g|-G)\s+(?<grep>[^\s]+)\s*\n\z/)
+ args = match[:args]
+ "#{args}#{',' unless args.chomp.empty?} grep: /#{match[:grep]}/"
+ else
+ args
+ end
+ end
+
+ def execute(*arg, grep: nil)
+ o = Output.new(grep: grep)
+
+ obj = arg.empty? ? irb_context.workspace.main : arg.first
+ locals = arg.empty? ? irb_context.workspace.binding.local_variables : []
+ klass = (obj.class == Class || obj.class == Module ? obj : obj.class)
+
+ o.dump("constants", obj.constants) if obj.respond_to?(:constants)
+ dump_methods(o, klass, obj)
+ o.dump("instance variables", obj.instance_variables)
+ o.dump("class variables", klass.class_variables)
+ o.dump("locals", locals)
+ nil
+ end
+
+ def dump_methods(o, klass, obj)
+ singleton_class = begin obj.singleton_class; rescue TypeError; nil end
+ maps = class_method_map((singleton_class || klass).ancestors)
+ maps.each do |mod, methods|
+ name = mod == singleton_class ? "#{klass}.methods" : "#{mod}#methods"
+ o.dump(name, methods)
+ end
+ end
+
+ def class_method_map(classes)
+ dumped = Array.new
+ classes.reject { |mod| mod >= Object }.map do |mod|
+ methods = mod.public_instance_methods(false).select do |m|
+ dumped.push(m) unless dumped.include?(m)
+ end
+ [mod, methods]
+ end.reverse
+ end
+
+ class Output
+ MARGIN = " "
+
+ def initialize(grep: nil)
+ @grep = grep
+ @line_width = screen_width - MARGIN.length # right padding
+ end
+
+ def dump(name, strs)
+ strs = strs.grep(@grep) if @grep
+ strs = strs.sort
+ return if strs.empty?
+
+ # Attempt a single line
+ print "#{Color.colorize(name, [:BOLD, :BLUE])}: "
+ if fits_on_line?(strs, cols: strs.size, offset: "#{name}: ".length)
+ puts strs.join(MARGIN)
+ return
+ end
+ puts
+
+ # Dump with the largest # of columns that fits on a line
+ cols = strs.size
+ until fits_on_line?(strs, cols: cols, offset: MARGIN.length) || cols == 1
+ cols -= 1
+ end
+ widths = col_widths(strs, cols: cols)
+ strs.each_slice(cols) do |ss|
+ puts ss.map.with_index { |s, i| "#{MARGIN}%-#{widths[i]}s" % s }.join
+ end
+ end
+
+ private
+
+ def fits_on_line?(strs, cols:, offset: 0)
+ width = col_widths(strs, cols: cols).sum + MARGIN.length * (cols - 1)
+ width <= @line_width - offset
+ end
+
+ def col_widths(strs, cols:)
+ cols.times.map do |col|
+ (col...strs.size).step(cols).map do |i|
+ strs[i].length
+ end.max
+ end
+ end
+
+ def screen_width
+ Reline.get_screen_size.last
+ rescue Errno::EINVAL # in `winsize': Invalid argument - <STDIN>
+ 80
+ end
+ end
+ private_constant :Output
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/measure.rb b/lib/irb/cmd/measure.rb
new file mode 100644
index 0000000000..9122e2dac9
--- /dev/null
+++ b/lib/irb/cmd/measure.rb
@@ -0,0 +1,48 @@
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Measure < Nop
+ category "Misc"
+ description "`measure` enables the mode to measure processing time. `measure :off` disables it."
+
+ def initialize(*args)
+ super(*args)
+ end
+
+ def execute(type = nil, arg = nil, &block)
+ # Please check IRB.init_config in lib/irb/init.rb that sets
+ # IRB.conf[:MEASURE_PROC] to register default "measure" methods,
+ # "measure :time" (abbreviated as "measure") and "measure :stackprof".
+ case type
+ when :off
+ IRB.conf[:MEASURE] = nil
+ IRB.unset_measure_callback(arg)
+ when :list
+ IRB.conf[:MEASURE_CALLBACKS].each do |type_name, _, arg_val|
+ puts "- #{type_name}" + (arg_val ? "(#{arg_val.inspect})" : '')
+ end
+ when :on
+ IRB.conf[:MEASURE] = true
+ added = IRB.set_measure_callback(type, arg)
+ puts "#{added[0]} is added." if added
+ else
+ if block_given?
+ IRB.conf[:MEASURE] = true
+ added = IRB.set_measure_callback(&block)
+ puts "#{added[0]} is added." if added
+ else
+ IRB.conf[:MEASURE] = true
+ added = IRB.set_measure_callback(type, arg)
+ puts "#{added[0]} is added." if added
+ end
+ end
+ nil
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/next.rb b/lib/irb/cmd/next.rb
new file mode 100644
index 0000000000..d29c82e7fc
--- /dev/null
+++ b/lib/irb/cmd/next.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Next < DebugCommand
+ def execute(*args)
+ super(do_cmds: ["next", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/nop.rb b/lib/irb/cmd/nop.rb
index 9d2e3c4d47..c616c054a8 100644
--- a/lib/irb/cmd/nop.rb
+++ b/lib/irb/cmd/nop.rb
@@ -1,4 +1,71 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
+#
+# nop.rb -
+# $Release Version: 0.9.6$
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+module IRB
+ # :stopdoc:
-# This file is just a placeholder for backward-compatibility.
-# Please require 'irb' and inherit your command from `IRB::Command::Base` instead.
+ module ExtendCommand
+ class CommandArgumentError < StandardError; end
+
+ class Nop
+ class << self
+ def category(category = nil)
+ @category = category if category
+ @category
+ end
+
+ def description(description = nil)
+ @description = description if description
+ @description
+ end
+
+ private
+
+ def string_literal?(args)
+ sexp = Ripper.sexp(args)
+ sexp && sexp.size == 2 && sexp.last&.first&.first == :string_literal
+ end
+ end
+
+ if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
+ def self.execute(conf, *opts, **kwargs, &block)
+ command = new(conf)
+ command.execute(*opts, **kwargs, &block)
+ rescue CommandArgumentError => e
+ puts e.message
+ end
+ else
+ def self.execute(conf, *opts, &block)
+ command = new(conf)
+ command.execute(*opts, &block)
+ rescue CommandArgumentError => e
+ puts e.message
+ end
+ end
+
+ def initialize(conf)
+ @irb_context = conf
+ end
+
+ attr_reader :irb_context
+
+ def irb
+ @irb_context.irb
+ end
+
+ def execute(*opts)
+ #nop
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/pushws.rb b/lib/irb/cmd/pushws.rb
new file mode 100644
index 0000000000..41d2e705f1
--- /dev/null
+++ b/lib/irb/cmd/pushws.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: false
+#
+# change-ws.rb -
+# $Release Version: 0.9.6$
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+
+require_relative "nop"
+require_relative "../ext/workspaces"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Workspaces < Nop
+ category "IRB"
+ description "Show workspaces."
+
+ def execute(*obj)
+ irb_context.workspaces.collect{|ws| ws.main}
+ end
+ end
+
+ class PushWorkspace < Workspaces
+ category "IRB"
+ description "Push an object to the workspace stack."
+
+ def execute(*obj)
+ irb_context.push_workspace(*obj)
+ super
+ end
+ end
+
+ class PopWorkspace < Workspaces
+ category "IRB"
+ description "Pop a workspace from the workspace stack."
+
+ def execute(*obj)
+ irb_context.pop_workspace(*obj)
+ super
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/show_cmds.rb b/lib/irb/cmd/show_cmds.rb
new file mode 100644
index 0000000000..acced27d48
--- /dev/null
+++ b/lib/irb/cmd/show_cmds.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require "stringio"
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class ShowCmds < Nop
+ category "IRB"
+ description "List all available commands and their description."
+
+ def execute(*args)
+ commands_info = IRB::ExtendCommandBundle.all_commands_info
+ commands_grouped_by_categories = commands_info.group_by { |cmd| cmd[:category] }
+ longest_cmd_name_length = commands_info.map { |c| c[:display_name] }.max { |a, b| a.length <=> b.length }.length
+
+ output = StringIO.new
+
+ commands_grouped_by_categories.each do |category, cmds|
+ output.puts Color.colorize(category, [:BOLD])
+
+ cmds.each do |cmd|
+ output.puts " #{cmd[:display_name].to_s.ljust(longest_cmd_name_length)} #{cmd[:description]}"
+ end
+
+ output.puts
+ end
+
+ puts output.string
+
+ nil
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/show_source.rb b/lib/irb/cmd/show_source.rb
new file mode 100644
index 0000000000..ea700be4bf
--- /dev/null
+++ b/lib/irb/cmd/show_source.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+require_relative "nop"
+require_relative "../color"
+require_relative "../ruby-lex"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class ShowSource < Nop
+ category "Context"
+ description "Show the source code of a given method or constant."
+
+ class << self
+ def transform_args(args)
+ # Return a string literal as is for backward compatibility
+ if args.empty? || string_literal?(args)
+ args
+ else # Otherwise, consider the input as a String for convenience
+ args.strip.dump
+ end
+ end
+
+ def find_source(str, irb_context)
+ case str
+ when /\A[A-Z]\w*(::[A-Z]\w*)*\z/ # Const::Name
+ eval(str, irb_context.workspace.binding) # trigger autoload
+ base = irb_context.workspace.binding.receiver.yield_self { |r| r.is_a?(Module) ? r : Object }
+ file, line = base.const_source_location(str) if base.respond_to?(:const_source_location) # Ruby 2.7+
+ when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
+ owner = eval(Regexp.last_match[:owner], irb_context.workspace.binding)
+ method = Regexp.last_match[:method]
+ if owner.respond_to?(:instance_method) && owner.instance_methods.include?(method.to_sym)
+ file, line = owner.instance_method(method).source_location
+ end
+ when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/ # method, receiver.method, receiver::method
+ receiver = eval(Regexp.last_match[:receiver] || 'self', irb_context.workspace.binding)
+ method = Regexp.last_match[:method]
+ file, line = receiver.method(method).source_location if receiver.respond_to?(method)
+ end
+ if file && line
+ Source.new(file: file, first_line: line, last_line: find_end(file, line))
+ end
+ end
+
+ private
+
+ def find_end(file, first_line)
+ return first_line unless File.exist?(file)
+ lex = RubyLex.new
+ lines = File.read(file).lines[(first_line - 1)..-1]
+ tokens = RubyLex.ripper_lex_without_warning(lines.join)
+ prev_tokens = []
+
+ # chunk with line number
+ tokens.chunk { |tok| tok.pos[0] }.each do |lnum, chunk|
+ code = lines[0..lnum].join
+ prev_tokens.concat chunk
+ continue = lex.process_continue(prev_tokens)
+ code_block_open = lex.check_code_block(code, prev_tokens)
+ if !continue && !code_block_open
+ return first_line + lnum
+ end
+ end
+ first_line
+ end
+ end
+
+ def execute(str = nil)
+ unless str.is_a?(String)
+ puts "Error: Expected a string but got #{str.inspect}"
+ return
+ end
+
+ source = self.class.find_source(str, @irb_context)
+ if source && File.exist?(source.file)
+ show_source(source)
+ else
+ puts "Error: Couldn't locate a definition for #{str}"
+ end
+ nil
+ end
+
+ private
+
+ # @param [IRB::ExtendCommand::ShowSource::Source] source
+ def show_source(source)
+ puts
+ puts "#{bold("From")}: #{source.file}:#{source.first_line}"
+ puts
+ code = IRB::Color.colorize_code(File.read(source.file))
+ puts code.lines[(source.first_line - 1)...source.last_line].join
+ puts
+ end
+
+ def bold(str)
+ Color.colorize(str, [:BOLD])
+ end
+
+ Source = Struct.new(
+ :file, # @param [String] - file name
+ :first_line, # @param [String] - first line
+ :last_line, # @param [String] - last line
+ keyword_init: true,
+ )
+ private_constant :Source
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/step.rb b/lib/irb/cmd/step.rb
new file mode 100644
index 0000000000..2bc74a9d79
--- /dev/null
+++ b/lib/irb/cmd/step.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require_relative "debug"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Step < DebugCommand
+ def execute(*args)
+ super(do_cmds: ["step", *args].join(" "))
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/subirb.rb b/lib/irb/cmd/subirb.rb
new file mode 100644
index 0000000000..699b35fcb4
--- /dev/null
+++ b/lib/irb/cmd/subirb.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: false
+# multi.rb -
+# $Release Version: 0.9.6$
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class MultiIRBCommand < Nop
+ def initialize(conf)
+ super
+ extend_irb_context
+ end
+
+ private
+
+ def extend_irb_context
+ # this extension patches IRB context like IRB.CurrentContext
+ require_relative "../ext/multi-irb"
+ end
+ end
+
+ class IrbCommand < MultiIRBCommand
+ category "IRB"
+ description "Start a child IRB."
+
+ def execute(*obj)
+ IRB.irb(nil, *obj)
+ end
+ end
+
+ class Jobs < MultiIRBCommand
+ category "IRB"
+ description "List of current sessions."
+
+ def execute
+ IRB.JobManager
+ end
+ end
+
+ class Foreground < MultiIRBCommand
+ category "IRB"
+ description "Switches to the session of the given number."
+
+ def execute(key = nil)
+ raise CommandArgumentError.new("Please specify the id of target IRB job (listed in the `jobs` command).") unless key
+ IRB.JobManager.switch(key)
+ end
+ end
+
+ class Kill < MultiIRBCommand
+ category "IRB"
+ description "Kills the session with the given number."
+
+ def execute(*keys)
+ IRB.JobManager.kill(*keys)
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/cmd/whereami.rb b/lib/irb/cmd/whereami.rb
new file mode 100644
index 0000000000..8f56ba073d
--- /dev/null
+++ b/lib/irb/cmd/whereami.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require_relative "nop"
+
+module IRB
+ # :stopdoc:
+
+ module ExtendCommand
+ class Whereami < Nop
+ category "Context"
+ description "Show the source code around binding.irb again."
+
+ def execute(*)
+ code = irb_context.workspace.code_around_binding
+ if code
+ puts code
+ else
+ puts "The current context doesn't have code."
+ end
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/color.rb b/lib/irb/color.rb
index fca942b28b..6378e14856 100644
--- a/lib/irb/color.rb
+++ b/lib/irb/color.rb
@@ -9,14 +9,12 @@ module IRB # :nodoc:
BOLD = 1
UNDERLINE = 4
REVERSE = 7
- BLACK = 30
RED = 31
GREEN = 32
YELLOW = 33
BLUE = 34
MAGENTA = 35
CYAN = 36
- WHITE = 37
TOKEN_KEYWORDS = {
on_kw: ['nil', 'self', 'true', 'false', '__FILE__', '__LINE__', '__ENCODING__'],
@@ -79,12 +77,12 @@ module IRB # :nodoc:
class << self
def colorable?
- supported = $stdout.tty? && (/mswin|mingw/.match?(RUBY_PLATFORM) || (ENV.key?('TERM') && ENV['TERM'] != 'dumb'))
+ supported = $stdout.tty? && (/mswin|mingw/ =~ RUBY_PLATFORM || (ENV.key?('TERM') && ENV['TERM'] != 'dumb'))
# because ruby/debug also uses irb's color module selectively,
# irb won't be activated in that case.
if IRB.respond_to?(:conf)
- supported && !!IRB.conf.fetch(:USE_COLORIZE, true)
+ supported && IRB.conf.fetch(:USE_COLORIZE, true)
else
supported
end
@@ -199,9 +197,15 @@ module IRB # :nodoc:
end
end
- lexer.scan.each do |elem|
- next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message
- on_scan.call(elem)
+ if lexer.respond_to?(:scan) # Ruby 2.7+
+ lexer.scan.each do |elem|
+ next if allow_last_error and /meets end of file|unexpected end-of-input/ =~ elem.message
+ on_scan.call(elem)
+ end
+ else
+ lexer.parse.sort_by(&:pos).each do |elem|
+ on_scan.call(elem)
+ end
end
# yield uncolorable DATA section
yield(nil, inner_code.byteslice(byte_pos...inner_code.bytesize), nil) if byte_pos < inner_code.bytesize
@@ -238,7 +242,7 @@ module IRB # :nodoc:
case token
when :on_symbeg, :on_symbols_beg, :on_qsymbols_beg
@stack << true
- when :on_ident, :on_op, :on_const, :on_ivar, :on_cvar, :on_gvar, :on_kw, :on_backtick
+ when :on_ident, :on_op, :on_const, :on_ivar, :on_cvar, :on_gvar, :on_kw
if @stack.last # Pop only when it's Symbol
@stack.pop
return prev_state
diff --git a/lib/irb/color_printer.rb b/lib/irb/color_printer.rb
index 31644aa7f9..1127bcecb4 100644
--- a/lib/irb/color_printer.rb
+++ b/lib/irb/color_printer.rb
@@ -4,9 +4,6 @@ require_relative 'color'
module IRB
class ColorPrinter < ::PP
- METHOD_RESPOND_TO = Object.instance_method(:respond_to?)
- METHOD_INSPECT = Object.instance_method(:inspect)
-
class << self
def pp(obj, out = $>, width = screen_width)
q = ColorPrinter.new(out, width)
@@ -25,11 +22,9 @@ module IRB
end
def pp(obj)
- if String === obj
+ if obj.is_a?(String)
# Avoid calling Ruby 2.4+ String#pretty_print that splits a string by "\n"
text(obj.inspect)
- elsif !METHOD_RESPOND_TO.bind(obj).call(:inspect)
- text(METHOD_INSPECT.bind(obj).call)
else
super
end
diff --git a/lib/irb/command.rb b/lib/irb/command.rb
deleted file mode 100644
index 68a4b52727..0000000000
--- a/lib/irb/command.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-#
-# irb/command.rb - irb command
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-
-require_relative "command/base"
-
-module IRB # :nodoc:
- module Command
- @commands = {}
-
- class << self
- attr_reader :commands
-
- # Registers a command with the given name.
- # Aliasing is intentionally not supported at the moment.
- def register(name, command_class)
- @commands[name.to_sym] = [command_class, []]
- end
- end
- end
-end
diff --git a/lib/irb/command/backtrace.rb b/lib/irb/command/backtrace.rb
deleted file mode 100644
index 687bb075ac..0000000000
--- a/lib/irb/command/backtrace.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Backtrace < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "backtrace #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/base.rb b/lib/irb/command/base.rb
deleted file mode 100644
index af810ed343..0000000000
--- a/lib/irb/command/base.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-# frozen_string_literal: true
-#
-# nop.rb -
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-
-module IRB
- # :stopdoc:
-
- module Command
- class CommandArgumentError < StandardError; end
-
- class << self
- def extract_ruby_args(*args, **kwargs)
- throw :EXTRACT_RUBY_ARGS, [args, kwargs]
- end
- end
-
- class Base
- class << self
- def category(category = nil)
- @category = category if category
- @category || "No category"
- end
-
- def description(description = nil)
- @description = description if description
- @description || "No description provided."
- end
-
- def help_message(help_message = nil)
- @help_message = help_message if help_message
- @help_message
- end
-
- def execute(irb_context, arg)
- new(irb_context).execute(arg)
- rescue CommandArgumentError => e
- puts e.message
- end
-
- private
-
- def highlight(text)
- Color.colorize(text, [:BOLD, :BLUE])
- end
- end
-
- def initialize(irb_context)
- @irb_context = irb_context
- end
-
- attr_reader :irb_context
-
- def execute(arg)
- #nop
- end
- end
-
- Nop = Base
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/break.rb b/lib/irb/command/break.rb
deleted file mode 100644
index a8f81fe665..0000000000
--- a/lib/irb/command/break.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Break < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "break #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/catch.rb b/lib/irb/command/catch.rb
deleted file mode 100644
index 529dcbca5a..0000000000
--- a/lib/irb/command/catch.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Catch < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "catch #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/cd.rb b/lib/irb/command/cd.rb
deleted file mode 100644
index b83c8689ae..0000000000
--- a/lib/irb/command/cd.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- class CD < Base
- category "Workspace"
- description "Move into the given object or leave the current context."
-
- help_message(<<~HELP)
- Usage: cd ([target]|..)
-
- IRB uses a stack of workspaces to keep track of context(s), with `pushws` and `popws` commands to manipulate the stack.
- The `cd` command is an attempt to simplify the operation and will be subject to change.
-
- When given:
- - an object, cd will use that object as the new context by pushing it onto the workspace stack.
- - "..", cd will leave the current context by popping the top workspace off the stack.
- - no arguments, cd will move to the top workspace on the stack by popping off all workspaces.
-
- Examples:
-
- cd Foo
- cd Foo.new
- cd @ivar
- cd ..
- cd
- HELP
-
- def execute(arg)
- case arg
- when ".."
- irb_context.pop_workspace
- when ""
- # TODO: decide what workspace commands should be kept, and underlying APIs should look like,
- # and perhaps add a new API to clear the workspace stack.
- prev_workspace = irb_context.pop_workspace
- while prev_workspace
- prev_workspace = irb_context.pop_workspace
- end
- else
- begin
- obj = eval(arg, irb_context.workspace.binding)
- irb_context.push_workspace(obj)
- rescue StandardError => e
- warn "Error: #{e}"
- end
- end
- end
- end
- end
-end
diff --git a/lib/irb/command/chws.rb b/lib/irb/command/chws.rb
deleted file mode 100644
index ef456d0961..0000000000
--- a/lib/irb/command/chws.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-#
-# change-ws.rb -
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-require_relative "../ext/change-ws"
-
-module IRB
- # :stopdoc:
-
- module Command
-
- class CurrentWorkingWorkspace < Base
- category "Workspace"
- description "Show the current workspace."
-
- def execute(_arg)
- puts "Current workspace: #{irb_context.main}"
- end
- end
-
- class ChangeWorkspace < Base
- category "Workspace"
- description "Change the current workspace to an object."
-
- def execute(arg)
- if arg.empty?
- irb_context.change_workspace
- else
- obj = eval(arg, irb_context.workspace.binding)
- irb_context.change_workspace(obj)
- end
-
- puts "Current workspace: #{irb_context.main}"
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/context.rb b/lib/irb/command/context.rb
deleted file mode 100644
index b4fc807343..0000000000
--- a/lib/irb/command/context.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- class Context < Base
- category "IRB"
- description "Displays current configuration."
-
- def execute(_arg)
- # This command just displays the configuration.
- # Modifying the configuration is achieved by sending a message to IRB.conf.
- Pager.page_content(IRB.CurrentContext.inspect)
- end
- end
- end
-end
diff --git a/lib/irb/command/continue.rb b/lib/irb/command/continue.rb
deleted file mode 100644
index 0daa029b15..0000000000
--- a/lib/irb/command/continue.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Continue < DebugCommand
- def execute(arg)
- execute_debug_command(do_cmds: "continue #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/debug.rb b/lib/irb/command/debug.rb
deleted file mode 100644
index 3ebb57fe54..0000000000
--- a/lib/irb/command/debug.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-require_relative "../debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Debug < Base
- category "Debugging"
- description "Start the debugger of debug.gem."
-
- def execute(_arg)
- execute_debug_command
- end
-
- def execute_debug_command(pre_cmds: nil, do_cmds: nil)
- pre_cmds = pre_cmds&.rstrip
- do_cmds = do_cmds&.rstrip
-
- if irb_context.with_debugger
- # If IRB is already running with a debug session, throw the command and IRB.debug_readline will pass it to the debugger.
- if cmd = pre_cmds || do_cmds
- throw :IRB_EXIT, cmd
- else
- puts "IRB is already running with a debug session."
- return
- end
- else
- # If IRB is not running with a debug session yet, then:
- # 1. Check if the debugging command is run from a `binding.irb` call.
- # 2. If so, try setting up the debug gem.
- # 3. Insert a debug breakpoint at `Irb#debug_break` with the intended command.
- # 4. Exit the current Irb#run call via `throw :IRB_EXIT`.
- # 5. `Irb#debug_break` will be called and trigger the breakpoint, which will run the intended command.
- unless irb_context.from_binding?
- puts "Debugging commands are only available when IRB is started with binding.irb"
- return
- end
-
- if IRB.respond_to?(:JobManager)
- warn "Can't start the debugger when IRB is running in a multi-IRB session."
- return
- end
-
- unless IRB::Debug.setup(irb_context.irb)
- puts <<~MSG
- You need to install the debug gem before using this command.
- If you use `bundle exec`, please add `gem "debug"` into your Gemfile.
- MSG
- return
- end
-
- IRB::Debug.insert_debug_break(pre_cmds: pre_cmds, do_cmds: do_cmds)
-
- # exit current Irb#run call
- throw :IRB_EXIT
- end
- end
- end
-
- class DebugCommand < Debug
- class << self
- def category
- "Debugging"
- end
-
- def description
- command_name = self.name.split("::").last.downcase
- "Start the debugger of debug.gem and run its `#{command_name}` command."
- end
- end
- end
- end
-end
diff --git a/lib/irb/command/delete.rb b/lib/irb/command/delete.rb
deleted file mode 100644
index 2a57a4a3de..0000000000
--- a/lib/irb/command/delete.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Delete < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "delete #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/disable_irb.rb b/lib/irb/command/disable_irb.rb
deleted file mode 100644
index 0b00d0302b..0000000000
--- a/lib/irb/command/disable_irb.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class DisableIrb < Base
- category "IRB"
- description "Disable binding.irb."
-
- def execute(*)
- ::Binding.define_method(:irb) {}
- IRB.irb_exit
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/edit.rb b/lib/irb/command/edit.rb
deleted file mode 100644
index cb7e0c4873..0000000000
--- a/lib/irb/command/edit.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require 'shellwords'
-
-require_relative "../color"
-require_relative "../source_finder"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Edit < Base
- include RubyArgsExtractor
-
- category "Misc"
- description 'Open a file or source location.'
- help_message <<~HELP_MESSAGE
- Usage: edit [FILE or constant or method signature]
-
- Open a file in the editor specified in #{highlight('ENV["VISUAL"]')} or #{highlight('ENV["EDITOR"]')}
-
- - If no arguments are provided, IRB will attempt to open the file the current context was defined in.
- - If FILE is provided, IRB will open the file.
- - If a constant or method signature is provided, IRB will attempt to locate the source file and open it.
-
- Examples:
-
- edit
- edit foo.rb
- edit Foo
- edit Foo#bar
- HELP_MESSAGE
-
- def execute(arg)
- # Accept string literal for backward compatibility
- path = unwrap_string_literal(arg)
-
- if path.nil?
- path = @irb_context.irb_path
- elsif !File.exist?(path)
- source = SourceFinder.new(@irb_context).find_source(path)
-
- if source&.file_exist? && !source.binary_file?
- path = source.file
- end
- end
-
- unless File.exist?(path)
- puts "Can not find file: #{path}"
- return
- end
-
- if editor = (ENV['VISUAL'] || ENV['EDITOR'])
- puts "command: '#{editor}'"
- puts " path: #{path}"
- system(*Shellwords.split(editor), path)
- else
- puts "Can not find editor setting: ENV['VISUAL'] or ENV['EDITOR']"
- end
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/exit.rb b/lib/irb/command/exit.rb
deleted file mode 100644
index b4436f0343..0000000000
--- a/lib/irb/command/exit.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class Exit < Base
- category "IRB"
- description "Exit the current irb session."
-
- def execute(_arg)
- IRB.irb_exit
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/finish.rb b/lib/irb/command/finish.rb
deleted file mode 100644
index 3311a0e6e9..0000000000
--- a/lib/irb/command/finish.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Finish < DebugCommand
- def execute(arg)
- execute_debug_command(do_cmds: "finish #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/force_exit.rb b/lib/irb/command/force_exit.rb
deleted file mode 100644
index 14086aa849..0000000000
--- a/lib/irb/command/force_exit.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class ForceExit < Base
- category "IRB"
- description "Exit the current process."
-
- def execute(_arg)
- throw :IRB_EXIT, true
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/help.rb b/lib/irb/command/help.rb
deleted file mode 100644
index 12b468fefc..0000000000
--- a/lib/irb/command/help.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- class Help < Base
- category "Help"
- description "List all available commands. Use `help <command>` to get information about a specific command."
-
- def execute(command_name)
- content =
- if command_name.empty?
- help_message
- else
- if command_class = Command.load_command(command_name)
- command_class.help_message || command_class.description
- else
- "Can't find command `#{command_name}`. Please check the command name and try again.\n\n"
- end
- end
- Pager.page_content(content)
- end
-
- private
-
- def help_message
- commands_info = IRB::Command.all_commands_info
- helper_methods_info = IRB::HelperMethod.all_helper_methods_info
- commands_grouped_by_categories = commands_info.group_by { |cmd| cmd[:category] }
- commands_grouped_by_categories["Helper methods"] = helper_methods_info
-
- if irb_context.with_debugger
- # Remove the original "Debugging" category
- commands_grouped_by_categories.delete("Debugging")
- end
-
- longest_cmd_name_length = commands_info.map { |c| c[:display_name].length }.max
-
- output = StringIO.new
-
- help_cmds = commands_grouped_by_categories.delete("Help")
- no_category_cmds = commands_grouped_by_categories.delete("No category")
- aliases = irb_context.instance_variable_get(:@command_aliases).map do |alias_name, target|
- { display_name: alias_name, description: "Alias for `#{target}`" }
- end
-
- # Display help commands first
- add_category_to_output("Help", help_cmds, output, longest_cmd_name_length)
-
- # Display the rest of the commands grouped by categories
- commands_grouped_by_categories.each do |category, cmds|
- add_category_to_output(category, cmds, output, longest_cmd_name_length)
- end
-
- # Display commands without a category
- if no_category_cmds
- add_category_to_output("No category", no_category_cmds, output, longest_cmd_name_length)
- end
-
- # Display aliases
- add_category_to_output("Aliases", aliases, output, longest_cmd_name_length)
-
- # Append the debugger help at the end
- if irb_context.with_debugger
- # Add "Debugging (from debug.gem)" category as title
- add_category_to_output("Debugging (from debug.gem)", [], output, longest_cmd_name_length)
- output.puts DEBUGGER__.help
- end
-
- output.string
- end
-
- def add_category_to_output(category, cmds, output, longest_cmd_name_length)
- output.puts Color.colorize(category, [:BOLD])
-
- cmds.each do |cmd|
- output.puts " #{cmd[:display_name].to_s.ljust(longest_cmd_name_length)} #{cmd[:description]}"
- end
-
- output.puts
- end
- end
- end
-end
diff --git a/lib/irb/command/history.rb b/lib/irb/command/history.rb
deleted file mode 100644
index 90f87f9102..0000000000
--- a/lib/irb/command/history.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-require "stringio"
-
-require_relative "../pager"
-
-module IRB
- # :stopdoc:
-
- module Command
- class History < Base
- category "IRB"
- description "Shows the input history. `-g [query]` or `-G [query]` allows you to filter the output."
-
- def execute(arg)
-
- if (match = arg&.match(/(-g|-G)\s+(?<grep>.+)\s*\n\z/))
- grep = Regexp.new(match[:grep])
- end
-
- formatted_inputs = irb_context.io.class::HISTORY.each_with_index.reverse_each.filter_map do |input, index|
- next if grep && !input.match?(grep)
-
- header = "#{index}: "
-
- first_line, *other_lines = input.split("\n")
- first_line = "#{header}#{first_line}"
-
- truncated_lines = other_lines.slice!(1..) # Show 1 additional line (2 total)
- other_lines << "..." if truncated_lines&.any?
-
- other_lines.map! do |line|
- " " * header.length + line
- end
-
- [first_line, *other_lines].join("\n") + "\n"
- end
-
- Pager.page_content(formatted_inputs.join)
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/info.rb b/lib/irb/command/info.rb
deleted file mode 100644
index d08ce00a32..0000000000
--- a/lib/irb/command/info.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Info < DebugCommand
- def execute(arg)
- execute_debug_command(pre_cmds: "info #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/internal_helpers.rb b/lib/irb/command/internal_helpers.rb
deleted file mode 100644
index 249b5cdede..0000000000
--- a/lib/irb/command/internal_helpers.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- # Internal use only, for default command's backward compatibility.
- module RubyArgsExtractor # :nodoc:
- def unwrap_string_literal(str)
- return if str.empty?
-
- sexp = Ripper.sexp(str)
- if sexp && sexp.size == 2 && sexp.last&.first&.first == :string_literal
- @irb_context.workspace.binding.eval(str).to_s
- else
- str
- end
- end
-
- def ruby_args(arg)
- # Use throw and catch to handle arg that includes `;`
- # For example: "1, kw: (2; 3); 4" will be parsed to [[1], { kw: 3 }]
- catch(:EXTRACT_RUBY_ARGS) do
- @irb_context.workspace.binding.eval "IRB::Command.extract_ruby_args #{arg}"
- end || [[], {}]
- end
- end
- end
-end
diff --git a/lib/irb/command/irb_info.rb b/lib/irb/command/irb_info.rb
deleted file mode 100644
index 6d868de94c..0000000000
--- a/lib/irb/command/irb_info.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class IrbInfo < Base
- category "IRB"
- description "Show information about IRB."
-
- def execute(_arg)
- str = "Ruby version: #{RUBY_VERSION}\n"
- str += "IRB version: #{IRB.version}\n"
- str += "InputMethod: #{IRB.CurrentContext.io.inspect}\n"
- str += "Completion: #{IRB.CurrentContext.io.respond_to?(:completion_info) ? IRB.CurrentContext.io.completion_info : 'off'}\n"
- rc_files = IRB.irbrc_files
- str += ".irbrc paths: #{rc_files.join(", ")}\n" if rc_files.any?
- str += "RUBY_PLATFORM: #{RUBY_PLATFORM}\n"
- str += "LANG env: #{ENV["LANG"]}\n" if ENV["LANG"] && !ENV["LANG"].empty?
- str += "LC_ALL env: #{ENV["LC_ALL"]}\n" if ENV["LC_ALL"] && !ENV["LC_ALL"].empty?
- str += "East Asian Ambiguous Width: #{Reline.ambiguous_width.inspect}\n"
- if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
- codepage = `chcp`.b.sub(/.*: (\d+)\n/, '\1')
- str += "Code page: #{codepage}\n"
- end
- puts str
- nil
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/load.rb b/lib/irb/command/load.rb
deleted file mode 100644
index 1cd3f279d1..0000000000
--- a/lib/irb/command/load.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-# frozen_string_literal: true
-#
-# load.rb -
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-require_relative "../ext/loader"
-
-module IRB
- # :stopdoc:
-
- module Command
- class LoaderCommand < Base
- include RubyArgsExtractor
- include IrbLoader
-
- def raise_cmd_argument_error
- raise CommandArgumentError.new("Please specify the file name.")
- end
- end
-
- class Load < LoaderCommand
- category "IRB"
- description "Load a Ruby file."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(file_name = nil, priv = nil)
- raise_cmd_argument_error unless file_name
- irb_load(file_name, priv)
- end
- end
-
- class Require < LoaderCommand
- category "IRB"
- description "Require a Ruby file."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(file_name = nil)
- raise_cmd_argument_error unless file_name
-
- rex = Regexp.new("#{Regexp.quote(file_name)}(\.o|\.rb)?")
- return false if $".find{|f| f =~ rex}
-
- case file_name
- when /\.rb$/
- begin
- if irb_load(file_name)
- $".push file_name
- return true
- end
- rescue LoadError
- end
- when /\.(so|o|sl)$/
- return ruby_require(file_name)
- end
-
- begin
- irb_load(f = file_name + ".rb")
- $".push f
- return true
- rescue LoadError
- return ruby_require(file_name)
- end
- end
- end
-
- class Source < LoaderCommand
- category "IRB"
- description "Loads a given file in the current session."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(file_name = nil)
- raise_cmd_argument_error unless file_name
-
- source_file(file_name)
- end
- end
- end
- # :startdoc:
-end
diff --git a/lib/irb/command/ls.rb b/lib/irb/command/ls.rb
deleted file mode 100644
index cbd9998bc4..0000000000
--- a/lib/irb/command/ls.rb
+++ /dev/null
@@ -1,155 +0,0 @@
-# frozen_string_literal: true
-
-require "reline"
-require "stringio"
-
-require_relative "../pager"
-require_relative "../color"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Ls < Base
- include RubyArgsExtractor
-
- category "Context"
- description "Show methods, constants, and variables."
-
- help_message <<~HELP_MESSAGE
- Usage: ls [obj] [-g [query]]
-
- -g [query] Filter the output with a query.
- HELP_MESSAGE
-
- def execute(arg)
- if match = arg.match(/\A(?<target>.+\s|)(-g|-G)\s+(?<grep>.+)$/)
- if match[:target].empty?
- use_main = true
- else
- obj = @irb_context.workspace.binding.eval(match[:target])
- end
- grep = Regexp.new(match[:grep])
- else
- args, kwargs = ruby_args(arg)
- use_main = args.empty?
- obj = args.first
- grep = kwargs[:grep]
- end
-
- if use_main
- obj = irb_context.workspace.main
- locals = irb_context.workspace.binding.local_variables
- end
-
- o = Output.new(grep: grep)
-
- klass = (obj.class == Class || obj.class == Module ? obj : obj.class)
-
- o.dump("constants", obj.constants) if obj.respond_to?(:constants)
- dump_methods(o, klass, obj)
- o.dump("instance variables", obj.instance_variables)
- o.dump("class variables", klass.class_variables)
- o.dump("locals", locals) if locals
- o.print_result
- end
-
- def dump_methods(o, klass, obj)
- singleton_class = begin obj.singleton_class; rescue TypeError; nil end
- dumped_mods = Array.new
- ancestors = klass.ancestors
- ancestors = ancestors.reject { |c| c >= Object } if klass < Object
- singleton_ancestors = (singleton_class&.ancestors || []).reject { |c| c >= Class }
-
- # singleton_class' ancestors should be at the front
- maps = class_method_map(singleton_ancestors, dumped_mods) + class_method_map(ancestors, dumped_mods)
- maps.each do |mod, methods|
- name = mod == singleton_class ? "#{klass}.methods" : "#{mod}#methods"
- o.dump(name, methods)
- end
- end
-
- def class_method_map(classes, dumped_mods)
- dumped_methods = Array.new
- classes.map do |mod|
- next if dumped_mods.include? mod
-
- dumped_mods << mod
-
- methods = mod.public_instance_methods(false).select do |method|
- if dumped_methods.include? method
- false
- else
- dumped_methods << method
- true
- end
- end
-
- [mod, methods]
- end.compact
- end
-
- class Output
- MARGIN = " "
-
- def initialize(grep: nil)
- @grep = grep
- @line_width = screen_width - MARGIN.length # right padding
- @io = StringIO.new
- end
-
- def print_result
- Pager.page_content(@io.string)
- end
-
- def dump(name, strs)
- strs = strs.grep(@grep) if @grep
- strs = strs.sort
- return if strs.empty?
-
- # Attempt a single line
- @io.print "#{Color.colorize(name, [:BOLD, :BLUE])}: "
- if fits_on_line?(strs, cols: strs.size, offset: "#{name}: ".length)
- @io.puts strs.join(MARGIN)
- return
- end
- @io.puts
-
- # Dump with the largest # of columns that fits on a line
- cols = strs.size
- until fits_on_line?(strs, cols: cols, offset: MARGIN.length) || cols == 1
- cols -= 1
- end
- widths = col_widths(strs, cols: cols)
- strs.each_slice(cols) do |ss|
- @io.puts ss.map.with_index { |s, i| "#{MARGIN}%-#{widths[i]}s" % s }.join
- end
- end
-
- private
-
- def fits_on_line?(strs, cols:, offset: 0)
- width = col_widths(strs, cols: cols).sum + MARGIN.length * (cols - 1)
- width <= @line_width - offset
- end
-
- def col_widths(strs, cols:)
- cols.times.map do |col|
- (col...strs.size).step(cols).map do |i|
- strs[i].length
- end.max
- end
- end
-
- def screen_width
- Reline.get_screen_size.last
- rescue Errno::EINVAL # in `winsize': Invalid argument - <STDIN>
- 80
- end
- end
- private_constant :Output
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/measure.rb b/lib/irb/command/measure.rb
deleted file mode 100644
index f96be20de8..0000000000
--- a/lib/irb/command/measure.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-module IRB
- # :stopdoc:
-
- module Command
- class Measure < Base
- include RubyArgsExtractor
-
- category "Misc"
- description "`measure` enables the mode to measure processing time. `measure :off` disables it."
-
- def initialize(*args)
- super(*args)
- end
-
- def execute(arg)
- if arg&.match?(/^do$|^do[^\w]|^\{/)
- warn 'Configure IRB.conf[:MEASURE_PROC] to add custom measure methods.'
- return
- end
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(type = nil, arg = nil)
- # Please check IRB.init_config in lib/irb/init.rb that sets
- # IRB.conf[:MEASURE_PROC] to register default "measure" methods,
- # "measure :time" (abbreviated as "measure") and "measure :stackprof".
-
- case type
- when :off
- IRB.unset_measure_callback(arg)
- when :list
- IRB.conf[:MEASURE_CALLBACKS].each do |type_name, _, arg_val|
- puts "- #{type_name}" + (arg_val ? "(#{arg_val.inspect})" : '')
- end
- when :on
- added = IRB.set_measure_callback(arg)
- puts "#{added[0]} is added." if added
- else
- added = IRB.set_measure_callback(type, arg)
- puts "#{added[0]} is added." if added
- end
- nil
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/next.rb b/lib/irb/command/next.rb
deleted file mode 100644
index 3fc6b68d21..0000000000
--- a/lib/irb/command/next.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Next < DebugCommand
- def execute(arg)
- execute_debug_command(do_cmds: "next #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/pushws.rb b/lib/irb/command/pushws.rb
deleted file mode 100644
index b51928c650..0000000000
--- a/lib/irb/command/pushws.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-# frozen_string_literal: true
-#
-# change-ws.rb -
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-
-require_relative "../ext/workspaces"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Workspaces < Base
- category "Workspace"
- description "Show workspaces."
-
- def execute(_arg)
- inspection_resuls = irb_context.instance_variable_get(:@workspace_stack).map do |ws|
- truncated_inspect(ws.main)
- end
-
- puts "[" + inspection_resuls.join(", ") + "]"
- end
-
- private
-
- def truncated_inspect(obj)
- obj_inspection = obj.inspect
-
- if obj_inspection.size > 20
- obj_inspection = obj_inspection[0, 19] + "...>"
- end
-
- obj_inspection
- end
- end
-
- class PushWorkspace < Workspaces
- category "Workspace"
- description "Push an object to the workspace stack."
-
- def execute(arg)
- if arg.empty?
- irb_context.push_workspace
- else
- obj = eval(arg, irb_context.workspace.binding)
- irb_context.push_workspace(obj)
- end
- super
- end
- end
-
- class PopWorkspace < Workspaces
- category "Workspace"
- description "Pop a workspace from the workspace stack."
-
- def execute(_arg)
- irb_context.pop_workspace
- super
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/show_doc.rb b/lib/irb/command/show_doc.rb
deleted file mode 100644
index 8a2188e4eb..0000000000
--- a/lib/irb/command/show_doc.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Command
- class ShowDoc < Base
- include RubyArgsExtractor
-
- category "Context"
- description "Look up documentation with RI."
-
- help_message <<~HELP_MESSAGE
- Usage: show_doc [name]
-
- When name is provided, IRB will look up the documentation for the given name.
- When no name is provided, a RI session will be started.
-
- Examples:
-
- show_doc
- show_doc Array
- show_doc Array#each
-
- HELP_MESSAGE
-
- def execute(arg)
- # Accept string literal for backward compatibility
- name = unwrap_string_literal(arg)
- require 'rdoc/ri/driver'
-
- unless ShowDoc.const_defined?(:Ri)
- opts = RDoc::RI::Driver.process_args([])
- ShowDoc.const_set(:Ri, RDoc::RI::Driver.new(opts))
- end
-
- if name.nil?
- Ri.interactive
- else
- begin
- Ri.display_name(name)
- rescue RDoc::RI::Error
- puts $!.message
- end
- end
-
- nil
- rescue LoadError, SystemExit
- warn "Can't display document because `rdoc` is not installed."
- end
- end
- end
-end
diff --git a/lib/irb/command/show_source.rb b/lib/irb/command/show_source.rb
deleted file mode 100644
index f4c6f104a2..0000000000
--- a/lib/irb/command/show_source.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../source_finder"
-require_relative "../pager"
-require_relative "../color"
-
-module IRB
- module Command
- class ShowSource < Base
- include RubyArgsExtractor
-
- category "Context"
- description "Show the source code of a given method, class/module, or constant."
-
- help_message <<~HELP_MESSAGE
- Usage: show_source [target] [-s]
-
- -s Show the super method. You can stack it like `-ss` to show the super of the super, etc.
-
- Examples:
-
- show_source Foo
- show_source Foo#bar
- show_source Foo#bar -s
- show_source Foo.baz
- show_source Foo::BAR
- HELP_MESSAGE
-
- def execute(arg)
- # Accept string literal for backward compatibility
- str = unwrap_string_literal(arg)
- unless str.is_a?(String)
- puts "Error: Expected a string but got #{str.inspect}"
- return
- end
-
- str, esses = str.split(" -")
- super_level = esses ? esses.count("s") : 0
- source = SourceFinder.new(@irb_context).find_source(str, super_level)
-
- if source
- show_source(source)
- elsif super_level > 0
- puts "Error: Couldn't locate a super definition for #{str}"
- else
- puts "Error: Couldn't locate a definition for #{str}"
- end
- nil
- end
-
- private
-
- def show_source(source)
- if source.binary_file?
- content = "\n#{bold('Defined in binary file')}: #{source.file}\n\n"
- else
- code = source.colorized_content || 'Source not available'
- content = <<~CONTENT
-
- #{bold("From")}: #{source.file}:#{source.line}
-
- #{code.chomp}
-
- CONTENT
- end
- Pager.page_content(content)
- end
-
- def bold(str)
- Color.colorize(str, [:BOLD])
- end
- end
- end
-end
diff --git a/lib/irb/command/step.rb b/lib/irb/command/step.rb
deleted file mode 100644
index 29e5e35ac0..0000000000
--- a/lib/irb/command/step.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "debug"
-
-module IRB
- # :stopdoc:
-
- module Command
- class Step < DebugCommand
- def execute(arg)
- execute_debug_command(do_cmds: "step #{arg}")
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/subirb.rb b/lib/irb/command/subirb.rb
deleted file mode 100644
index 85af28c1a5..0000000000
--- a/lib/irb/command/subirb.rb
+++ /dev/null
@@ -1,123 +0,0 @@
-# frozen_string_literal: true
-#
-# multi.rb -
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-
-module IRB
- # :stopdoc:
-
- module Command
- class MultiIRBCommand < Base
- include RubyArgsExtractor
-
- private
-
- def print_deprecated_warning
- warn <<~MSG
- Multi-irb commands are deprecated and will be removed in IRB 2.0.0. Please use workspace commands instead.
- If you have any use case for multi-irb, please leave a comment at https://github.com/ruby/irb/issues/653
- MSG
- end
-
- def extend_irb_context
- # this extension patches IRB context like IRB.CurrentContext
- require_relative "../ext/multi-irb"
- end
-
- def print_debugger_warning
- warn "Multi-IRB commands are not available when the debugger is enabled."
- end
- end
-
- class IrbCommand < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
- description "Start a child IRB."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(*obj)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- extend_irb_context
- IRB.irb(nil, *obj)
- puts IRB.JobManager.inspect
- end
- end
-
- class Jobs < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
- description "List of current sessions."
-
- def execute(_arg)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- extend_irb_context
- puts IRB.JobManager.inspect
- end
- end
-
- class Foreground < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
- description "Switches to the session of the given number."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(key = nil)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- extend_irb_context
-
- raise CommandArgumentError.new("Please specify the id of target IRB job (listed in the `jobs` command).") unless key
- IRB.JobManager.switch(key)
- puts IRB.JobManager.inspect
- end
- end
-
- class Kill < MultiIRBCommand
- category "Multi-irb (DEPRECATED)"
- description "Kills the session with the given number."
-
- def execute(arg)
- args, kwargs = ruby_args(arg)
- execute_internal(*args, **kwargs)
- end
-
- def execute_internal(*keys)
- print_deprecated_warning
-
- if irb_context.with_debugger
- print_debugger_warning
- return
- end
-
- extend_irb_context
- IRB.JobManager.kill(*keys)
- puts IRB.JobManager.inspect
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/command/whereami.rb b/lib/irb/command/whereami.rb
deleted file mode 100644
index c8439f1212..0000000000
--- a/lib/irb/command/whereami.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # :stopdoc:
-
- module Command
- class Whereami < Base
- category "Context"
- description "Show the source code around binding.irb again."
-
- def execute(_arg)
- code = irb_context.workspace.code_around_binding
- if code
- puts code
- else
- puts "The current context doesn't have code."
- end
- end
- end
- end
-
- # :startdoc:
-end
diff --git a/lib/irb/completion.rb b/lib/irb/completion.rb
index 7f102dcdf4..34640e17f9 100644
--- a/lib/irb/completion.rb
+++ b/lib/irb/completion.rb
@@ -1,6 +1,8 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/completion.rb -
+# $Release Version: 0.9$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
# From Original Idea of shugo@ruby-lang.org
#
@@ -8,7 +10,30 @@
require_relative 'ruby-lex'
module IRB
- class BaseCompletor # :nodoc:
+ module InputCompletor # :nodoc:
+ using Module.new {
+ refine ::Binding do
+ def eval_methods
+ ::Kernel.instance_method(:methods).bind(eval("self")).call
+ end
+
+ def eval_private_methods
+ ::Kernel.instance_method(:private_methods).bind(eval("self")).call
+ end
+
+ def eval_instance_variables
+ ::Kernel.instance_method(:instance_variables).bind(eval("self")).call
+ end
+
+ def eval_global_variables
+ ::Kernel.instance_method(:global_variables).bind(eval("self")).call
+ end
+
+ def eval_class_constants
+ ::Module.instance_method(:constants).bind(eval("self.class")).call
+ end
+ end
+ }
# Set of reserved words used by Ruby, you should not use these for
# constants or variables
@@ -33,21 +58,21 @@ module IRB
yield
]
- HELP_COMMAND_PREPOSING = /\Ahelp\s+/
+ BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
- def completion_candidates(preposing, target, postposing, bind:)
- raise NotImplementedError
- end
-
- def doc_namespace(preposing, matched, postposing, bind:)
- raise NotImplementedError
+ def self.absolute_path?(p) # TODO Remove this method after 2.6 EOL.
+ if File.respond_to?(:absolute_path?)
+ File.absolute_path?(p)
+ else
+ File.absolute_path(p) == p
+ end
end
GEM_PATHS =
if defined?(Gem::Specification)
Gem::Specification.latest_specs(true).map { |s|
s.require_paths.map { |p|
- if File.absolute_path?(p)
+ if absolute_path?(p)
p
else
File.join(s.full_gem_path, p)
@@ -58,7 +83,7 @@ module IRB
[]
end.freeze
- def retrieve_gem_and_system_load_path
+ def self.retrieve_gem_and_system_load_path
candidates = (GEM_PATHS | $LOAD_PATH)
candidates.map do |p|
if p.respond_to?(:to_path)
@@ -69,8 +94,8 @@ module IRB
end.compact.sort
end
- def retrieve_files_to_require_from_load_path
- @files_from_load_path ||=
+ def self.retrieve_files_to_require_from_load_path
+ @@files_from_load_path ||=
(
shortest = []
rest = retrieve_gem_and_system_load_path.each_with_object([]) { |path, result|
@@ -88,84 +113,13 @@ module IRB
)
end
- def command_candidates(target)
- if !target.empty?
- IRB::Command.command_names.select { _1.start_with?(target) }
- else
- []
- end
- end
-
- def retrieve_files_to_require_relative_from_current_dir
- @files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
+ def self.retrieve_files_to_require_relative_from_current_dir
+ @@files_from_current_dir ||= Dir.glob("**/*.{rb,#{RbConfig::CONFIG['DLEXT']}}", base: '.').map { |path|
path.sub(/\.(rb|#{RbConfig::CONFIG['DLEXT']})\z/, '')
}
end
- end
-
- class TypeCompletor < BaseCompletor # :nodoc:
- def initialize(context)
- @context = context
- end
-
- def inspect
- ReplTypeCompletor.info
- end
-
- def completion_candidates(preposing, target, _postposing, bind:)
- # When completing the argument of `help` command, only commands should be candidates
- return command_candidates(target) if preposing.match?(HELP_COMMAND_PREPOSING)
-
- commands = if preposing.empty?
- command_candidates(target)
- # It doesn't make sense to propose commands with other preposing
- else
- []
- end
-
- result = ReplTypeCompletor.analyze(preposing + target, binding: bind, filename: @context.irb_path)
-
- return commands unless result
-
- commands | result.completion_candidates.map { target + _1 }
- end
-
- def doc_namespace(preposing, matched, _postposing, bind:)
- result = ReplTypeCompletor.analyze(preposing + matched, binding: bind, filename: @context.irb_path)
- result&.doc_namespace('')
- end
- end
-
- class RegexpCompletor < BaseCompletor # :nodoc:
- using Module.new {
- refine ::Binding do
- def eval_methods
- ::Kernel.instance_method(:methods).bind(eval("self")).call
- end
-
- def eval_private_methods
- ::Kernel.instance_method(:private_methods).bind(eval("self")).call
- end
-
- def eval_instance_variables
- ::Kernel.instance_method(:instance_variables).bind(eval("self")).call
- end
-
- def eval_global_variables
- ::Kernel.instance_method(:global_variables).bind(eval("self")).call
- end
-
- def eval_class_constants
- ::Module.instance_method(:constants).bind(eval("self.class")).call
- end
- end
- }
-
- def inspect
- 'RegexpCompletor'
- end
- def complete_require_path(target, preposing, postposing)
+ CompletionRequireProc = lambda { |target, preposing = nil, postposing = nil|
if target =~ /\A(['"])([^'"]+)\Z/
quote = $1
actual_target = $2
@@ -180,53 +134,44 @@ module IRB
break
end
end
- return unless tok&.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
-
- case tok.tok
- when 'require'
- retrieve_files_to_require_from_load_path.select { |path|
- path.start_with?(actual_target)
- }.map { |path|
- quote + path
- }
- when 'require_relative'
- retrieve_files_to_require_relative_from_current_dir.select { |path|
- path.start_with?(actual_target)
- }.map { |path|
- quote + path
- }
+ result = []
+ if tok && tok.event == :on_ident && tok.state == Ripper::EXPR_CMDARG
+ case tok.tok
+ when 'require'
+ result = retrieve_files_to_require_from_load_path.select { |path|
+ path.start_with?(actual_target)
+ }.map { |path|
+ quote + path
+ }
+ when 'require_relative'
+ result = retrieve_files_to_require_relative_from_current_dir.select { |path|
+ path.start_with?(actual_target)
+ }.map { |path|
+ quote + path
+ }
+ end
end
- end
+ result
+ }
- def completion_candidates(preposing, target, postposing, bind:)
- if result = complete_require_path(target, preposing, postposing)
- return result
+ CompletionProc = lambda { |target, preposing = nil, postposing = nil|
+ if preposing && postposing
+ result = CompletionRequireProc.(target, preposing, postposing)
+ unless result
+ result = retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
+ end
+ result
+ else
+ retrieve_completion_data(target).compact.map{ |i| i.encode(Encoding.default_external) }
end
+ }
- commands = command_candidates(target)
-
- # When completing the argument of `help` command, only commands should be candidates
- return commands if preposing.match?(HELP_COMMAND_PREPOSING)
-
- # It doesn't make sense to propose commands with other preposing
- commands = [] unless preposing.empty?
-
- completion_data = retrieve_completion_data(target, bind: bind, doc_namespace: false).compact.map{ |i| i.encode(Encoding.default_external) }
- commands | completion_data
- end
-
- def doc_namespace(_preposing, matched, _postposing, bind:)
- retrieve_completion_data(matched, bind: bind, doc_namespace: true)
- end
-
- def retrieve_completion_data(input, bind:, doc_namespace:)
+ def self.retrieve_completion_data(input, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false)
case input
- # this regexp only matches the closing character because of irb's Reline.completer_quote_characters setting
- # details are described in: https://github.com/ruby/irb/pull/523
- when /^(.*["'`])\.([^.]*)$/
+ when /^((["'`]).*\2)\.([^.]*)$/
# String
receiver = $1
- message = $2
+ message = $3
if doc_namespace
"String.#{message}"
@@ -235,9 +180,7 @@ module IRB
select_message(receiver, message, candidates)
end
- # this regexp only matches the closing character because of irb's Reline.completer_quote_characters setting
- # details are described in: https://github.com/ruby/irb/pull/523
- when /^(.*\/)\.([^.]*)$/
+ when /^(\/[^\/]*\/)\.([^.]*)$/
# Regexp
receiver = $1
message = $2
@@ -262,26 +205,26 @@ module IRB
end
when /^([^\}]*\})\.([^.]*)$/
- # Hash or Proc
+ # Proc or Hash
receiver = $1
message = $2
if doc_namespace
- ["Hash.#{message}", "Proc.#{message}"]
+ ["Proc.#{message}", "Hash.#{message}"]
else
- hash_candidates = Hash.instance_methods.collect{|m| m.to_s}
proc_candidates = Proc.instance_methods.collect{|m| m.to_s}
- select_message(receiver, message, hash_candidates | proc_candidates)
+ hash_candidates = Hash.instance_methods.collect{|m| m.to_s}
+ select_message(receiver, message, proc_candidates | hash_candidates)
end
- when /^(:[^:.]+)$/
+ when /^(:[^:.]*)$/
# Symbol
if doc_namespace
nil
else
sym = $1
candidates = Symbol.all_symbols.collect do |s|
- s.inspect
+ ":" + s.id2name.encode(Encoding.default_external)
rescue EncodingError
# ignore
end
@@ -296,7 +239,7 @@ module IRB
if doc_namespace
candidates.find { |i| i == receiver }
else
- candidates.grep(/^#{Regexp.quote(receiver)}/).collect{|e| "::" + e}
+ candidates.grep(/^#{receiver}/).collect{|e| "::" + e}
end
when /^([A-Z].*)::([^:.]*)$/
@@ -415,11 +358,19 @@ module IRB
else
# func1.func2
candidates = []
+ to_ignore = ignored_modules
+ ObjectSpace.each_object(Module){|m|
+ next if (to_ignore.include?(m) rescue true)
+ next unless m.respond_to?(:instance_methods) # JRuby has modules that represent java packages. They don't include many common ruby methods
+ candidates.concat m.instance_methods(false).collect{|x| x.to_s}
+ }
+ candidates.sort!
+ candidates.uniq!
end
if doc_namespace
rec_class = rec.is_a?(Module) ? rec : rec.class
- "#{rec_class.name}#{sep}#{candidates.find{ |i| i == message }}" rescue nil
+ "#{rec_class.name}#{sep}#{candidates.find{ |i| i == message }}"
else
select_message(receiver, message, candidates, sep)
end
@@ -437,19 +388,13 @@ module IRB
else
select_message(receiver, message, candidates.sort)
end
- when /^\s*$/
- # empty input
- if doc_namespace
- nil
- else
- []
- end
+
else
if doc_namespace
vars = (bind.local_variables | bind.eval_instance_variables).collect{|m| m.to_s}
perfect_match_var = vars.find{|m| m.to_s == input}
if perfect_match_var
- eval("#{perfect_match_var}.class.name", bind) rescue nil
+ eval("#{perfect_match_var}.class.name", bind)
else
candidates = (bind.eval_methods | bind.eval_private_methods | bind.local_variables | bind.eval_instance_variables | bind.eval_class_constants).collect{|m| m.to_s}
candidates |= ReservedWords
@@ -463,10 +408,44 @@ module IRB
end
end
+ PerfectMatchedProc = ->(matched, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding) {
+ begin
+ require 'rdoc'
+ rescue LoadError
+ return
+ end
+
+ RDocRIDriver ||= RDoc::RI::Driver.new
+
+ if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
+ IRB.__send__(:easter_egg)
+ return
+ end
+
+ namespace = retrieve_completion_data(matched, bind: bind, doc_namespace: true)
+ return unless namespace
+
+ if namespace.is_a?(Array)
+ out = RDoc::Markup::Document.new
+ namespace.each do |m|
+ begin
+ RDocRIDriver.add_method(out, m)
+ rescue RDoc::RI::Driver::NotFoundError
+ end
+ end
+ RDocRIDriver.display(out)
+ else
+ begin
+ RDocRIDriver.display_names([namespace])
+ rescue RDoc::RI::Driver::NotFoundError
+ end
+ end
+ }
+
# Set of available operators in Ruby
Operators = %w[% & * ** + - / < << <= <=> == === =~ > >= >> [] []= ^ ! != !~]
- def select_message(receiver, message, candidates, sep = ".")
+ def self.select_message(receiver, message, candidates, sep = ".")
candidates.grep(/^#{Regexp.quote(message)}/).collect do |e|
case e
when /^[a-zA-Z_]/
@@ -477,21 +456,30 @@ module IRB
end
end
end
- end
- module InputCompletor
- class << self
- private def regexp_completor
- @regexp_completor ||= RegexpCompletor.new
+ def self.ignored_modules
+ # We could cache the result, but this is very fast already.
+ # By using this approach, we avoid Module#name calls, which are
+ # relatively slow when there are a lot of anonymous modules defined.
+ s = {}
+
+ scanner = lambda do |m|
+ next if s.include?(m) # IRB::ExtendCommandBundle::EXCB recurses.
+ s[m] = true
+ m.constants(false).each do |c|
+ value = m.const_get(c)
+ scanner.call(value) if value.is_a?(Module)
+ end
end
- def retrieve_completion_data(input, bind: IRB.conf[:MAIN_CONTEXT].workspace.binding, doc_namespace: false)
- regexp_completor.retrieve_completion_data(input, bind: bind, doc_namespace: doc_namespace)
+ %i(IRB RubyLex).each do |sym|
+ next unless Object.const_defined?(sym)
+ scanner.call(Object.const_get(sym))
end
+
+ s.delete(IRB::Context) if defined?(IRB::Context)
+
+ s
end
- CompletionProc = ->(target, preposing = nil, postposing = nil) {
- regexp_completor.completion_candidates(preposing || '', target, postposing || '', bind: IRB.conf[:MAIN_CONTEXT].workspace.binding)
- }
end
- deprecate_constant :InputCompletor
end
diff --git a/lib/irb/context.rb b/lib/irb/context.rb
index 505bed80a1..91fbb2fcf1 100644
--- a/lib/irb/context.rb
+++ b/lib/irb/context.rb
@@ -1,9 +1,14 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/context.rb - irb context
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-
+# --
+#
+#
+#
require_relative "workspace"
require_relative "inspector"
require_relative "input-method"
@@ -13,7 +18,6 @@ module IRB
# A class that wraps the current state of the irb session, including the
# configuration of IRB.conf.
class Context
- ASSIGN_OPERATORS_REGEXP = Regexp.union(%w[= += -= *= /= %= **= &= |= &&= ||= ^= <<= >>=])
# Creates a new IRB context.
#
# The optional +input_method+ argument:
@@ -23,11 +27,10 @@ module IRB
# +other+:: uses this as InputMethod
def initialize(irb, workspace = nil, input_method = nil)
@irb = irb
- @workspace_stack = []
if workspace
- @workspace_stack << workspace
+ @workspace = workspace
else
- @workspace_stack << WorkSpace.new
+ @workspace = WorkSpace.new
end
@thread = Thread.current
@@ -63,7 +66,7 @@ module IRB
@io = nil
self.inspect_mode = IRB.conf[:INSPECT_MODE]
- self.use_tracer = IRB.conf[:USE_TRACER]
+ self.use_tracer = IRB.conf[:USE_TRACER] if IRB.conf[:USE_TRACER]
self.use_loader = IRB.conf[:USE_LOADER] if IRB.conf[:USE_LOADER]
self.eval_history = IRB.conf[:EVAL_HISTORY] if IRB.conf[:EVAL_HISTORY]
@@ -74,34 +77,33 @@ module IRB
self.prompt_mode = IRB.conf[:PROMPT_MODE]
- @irb_name = IRB.conf[:IRB_NAME]
-
- unless IRB.conf[:SINGLE_IRB] or !defined?(IRB::JobManager)
- @irb_name = @irb_name + "#" + IRB.JobManager.n_jobs.to_s
+ if IRB.conf[:SINGLE_IRB] or !defined?(IRB::JobManager)
+ @irb_name = IRB.conf[:IRB_NAME]
+ else
+ @irb_name = IRB.conf[:IRB_NAME]+"#"+IRB.JobManager.n_jobs.to_s
end
-
- self.irb_path = "(" + @irb_name + ")"
+ @irb_path = "(" + @irb_name + ")"
case input_method
when nil
@io = nil
case use_multiline?
when nil
- if term_interactive? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline?
+ if STDIN.tty? && IRB.conf[:PROMPT_MODE] != :INF_RUBY && !use_singleline?
# Both of multiline mode and singleline mode aren't specified.
- @io = RelineInputMethod.new(build_completor)
+ @io = RelineInputMethod.new
else
@io = nil
end
when false
@io = nil
when true
- @io = RelineInputMethod.new(build_completor)
+ @io = RelineInputMethod.new
end
unless @io
case use_singleline?
when nil
- if (defined?(ReadlineInputMethod) && term_interactive? &&
+ if (defined?(ReadlineInputMethod) && STDIN.tty? &&
IRB.conf[:PROMPT_MODE] != :INF_RUBY)
@io = ReadlineInputMethod.new
else
@@ -124,14 +126,16 @@ module IRB
when '-'
@io = FileInputMethod.new($stdin)
@irb_name = '-'
- self.irb_path = '-'
+ @irb_path = '-'
when String
@io = FileInputMethod.new(input_method)
@irb_name = File.basename(input_method)
- self.irb_path = input_method
+ @irb_path = input_method
else
@io = input_method
end
+ self.save_history = IRB.conf[:SAVE_HISTORY] if IRB.conf[:SAVE_HISTORY]
+
@extra_doc_dirs = IRB.conf[:EXTRA_DOC_DIRS]
@echo = IRB.conf[:ECHO]
@@ -149,106 +153,18 @@ module IRB
@newline_before_multiline_output = true
end
- @command_aliases = IRB.conf[:COMMAND_ALIASES].dup
- end
-
- private def term_interactive?
- return true if ENV['TEST_IRB_FORCE_INTERACTIVE']
- STDIN.tty? && ENV['TERM'] != 'dumb'
- end
-
- def use_tracer=(val)
- require_relative "ext/tracer" if val
- IRB.conf[:USE_TRACER] = val
- end
-
- def eval_history=(val)
- self.class.remove_method(__method__)
- require_relative "ext/eval_history"
- __send__(__method__, val)
- end
-
- def use_loader=(val)
- self.class.remove_method(__method__)
- require_relative "ext/use-loader"
- __send__(__method__, val)
- end
-
- private def build_completor
- completor_type = IRB.conf[:COMPLETOR]
-
- # Gem repl_type_completor is added to bundled gems in Ruby 3.4.
- # Use :type as default completor only in Ruby 3.4 or later.
- verbose = !!completor_type
- completor_type ||= RUBY_VERSION >= '3.4' ? :type : :regexp
-
- case completor_type
- when :regexp
- return RegexpCompletor.new
- when :type
- completor = build_type_completor(verbose: verbose)
- return completor if completor
- else
- warn "Invalid value for IRB.conf[:COMPLETOR]: #{completor_type}"
- end
- # Fallback to RegexpCompletor
- RegexpCompletor.new
- end
-
- private def build_type_completor(verbose:)
- if RUBY_ENGINE == 'truffleruby'
- # Avoid SyntaxError. truffleruby does not support endless method definition yet.
- warn 'TypeCompletor is not supported on TruffleRuby yet' if verbose
- return
- end
-
- begin
- require 'repl_type_completor'
- rescue LoadError => e
- warn "TypeCompletor requires `gem repl_type_completor`: #{e.message}" if verbose
- return
- end
-
- ReplTypeCompletor.preload_rbs
- TypeCompletor.new(self)
- end
-
- def save_history=(val)
- IRB.conf[:SAVE_HISTORY] = val
- end
-
- def save_history
- IRB.conf[:SAVE_HISTORY]
- end
-
- # A copy of the default <code>IRB.conf[:HISTORY_FILE]</code>
- def history_file
- IRB.conf[:HISTORY_FILE]
- end
-
- # Set <code>IRB.conf[:HISTORY_FILE]</code> to the given +hist+.
- def history_file=(hist)
- IRB.conf[:HISTORY_FILE] = hist
- end
-
- # Workspace in the current context.
- def workspace
- @workspace_stack.last
- end
-
- # Replace the current workspace with the given +workspace+.
- def replace_workspace(workspace)
- @workspace_stack.pop
- @workspace_stack.push(workspace)
+ @command_aliases = IRB.conf[:COMMAND_ALIASES]
end
# The top-level workspace, see WorkSpace#main
def main
- workspace.main
+ @workspace.main
end
# The toplevel workspace, see #home_workspace
attr_reader :workspace_home
+ # WorkSpace in the current context.
+ attr_accessor :workspace
# The current thread in this context.
attr_reader :thread
# The current input method.
@@ -269,27 +185,9 @@ module IRB
# Can be either name from <code>IRB.conf[:IRB_NAME]</code>, or the number of
# the current job set by JobManager, such as <code>irb#2</code>
attr_accessor :irb_name
-
- # Can be one of the following:
- # - the #irb_name surrounded by parenthesis
- # - the +input_method+ passed to Context.new
- # - the file path of the current IRB context in a binding.irb session
- attr_reader :irb_path
-
- # Sets @irb_path to the given +path+ as well as @eval_path
- # @eval_path is used for evaluating code in the context of IRB session
- # It's the same as irb_path, but with the IRB name postfix
- # This makes sure users can distinguish the methods defined in the IRB session
- # from the methods defined in the current file's context, especially with binding.irb
- def irb_path=(path)
- @irb_path = path
-
- if File.exist?(path)
- @eval_path = "#{path}(#{IRB.conf[:IRB_NAME]})"
- else
- @eval_path = path
- end
- end
+ # Can be either the #irb_name surrounded by parenthesis, or the
+ # +input_method+ passed to Context.new
+ attr_accessor :irb_path
# Whether multiline editor mode is enabled or not.
#
@@ -310,29 +208,18 @@ module IRB
attr_reader :prompt_mode
# Standard IRB prompt.
#
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
+ # See IRB@Customizing+the+IRB+Prompt for more information.
attr_accessor :prompt_i
# IRB prompt for continuated strings.
#
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
+ # See IRB@Customizing+the+IRB+Prompt for more information.
attr_accessor :prompt_s
# IRB prompt for continuated statement. (e.g. immediately after an +if+)
#
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
+ # See IRB@Customizing+the+IRB+Prompt for more information.
attr_accessor :prompt_c
-
- # TODO: Remove this when developing v2.0
- def prompt_n
- warn "IRB::Context#prompt_n is deprecated and will be removed in the next major release."
- ""
- end
-
- # TODO: Remove this when developing v2.0
- def prompt_n=(_)
- warn "IRB::Context#prompt_n= is deprecated and will be removed in the next major release."
- ""
- end
-
+ # See IRB@Customizing+the+IRB+Prompt for more information.
+ attr_accessor :prompt_n
# Can be either the default <code>IRB.conf[:AUTO_INDENT]</code>, or the
# mode set by #prompt_mode=
#
@@ -440,13 +327,13 @@ module IRB
# The default value is 16.
#
# Can also be set using the +--back-trace-limit+ command line option.
+ #
+ # See IRB@Command+line+options for more command line options.
attr_accessor :back_trace_limit
# User-defined IRB command aliases
attr_accessor :command_aliases
- attr_accessor :with_debugger
-
# Alias for #use_multiline
alias use_multiline? use_multiline
# Alias for #use_singleline
@@ -490,7 +377,9 @@ module IRB
# StdioInputMethod or RelineInputMethod or ReadlineInputMethod, see #io
# for more information.
def prompting?
- verbose? || @io.prompting?
+ verbose? || (STDIN.tty? && @io.kind_of?(StdioInputMethod) ||
+ @io.kind_of?(RelineInputMethod) ||
+ (defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod)))
end
# The return value of the last statement evaluated.
@@ -500,18 +389,19 @@ module IRB
# to #last_value.
def set_last_value(value)
@last_value = value
- workspace.local_variable_set :_, value
+ @workspace.local_variable_set :_, value
end
# Sets the +mode+ of the prompt in this context.
#
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
+ # See IRB@Customizing+the+IRB+Prompt for more information.
def prompt_mode=(mode)
@prompt_mode = mode
pconf = IRB.conf[:PROMPT][mode]
@prompt_i = pconf[:PROMPT_I]
@prompt_s = pconf[:PROMPT_S]
@prompt_c = pconf[:PROMPT_C]
+ @prompt_n = pconf[:PROMPT_N]
@return_format = pconf[:RETURN]
@return_format = "%s\n" if @return_format == nil
if ai = pconf.include?(:AUTO_INDENT)
@@ -543,6 +433,8 @@ module IRB
#
# Can also be set using the +--inspect+ and +--noinspect+ command line
# options.
+ #
+ # See IRB@Command+line+options for more command line options.
def inspect_mode=(opt)
if i = Inspector::INSPECTORS[opt]
@@ -586,94 +478,42 @@ module IRB
@inspect_mode
end
- def evaluate(statement, line_no) # :nodoc:
+ def evaluate(line, line_no, exception: nil) # :nodoc:
@line_no = line_no
-
- case statement
- when Statement::EmptyInput
- return
- when Statement::Expression
- result = evaluate_expression(statement.code, line_no)
- set_last_value(result)
- when Statement::Command
- statement.command_class.execute(self, statement.arg)
- end
-
- nil
- end
-
- def from_binding?
- @irb.from_binding
- end
-
- def evaluate_expression(code, line_no) # :nodoc:
- result = nil
- if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty?
- IRB.set_measure_callback
- end
-
- if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty?
- last_proc = proc do
- result = workspace.evaluate(code, @eval_path, line_no)
- end
- IRB.conf[:MEASURE_CALLBACKS].inject(last_proc) do |chain, item|
- _name, callback, arg = item
- proc do
- callback.(self, code, line_no, arg) do
- chain.call
- end
- end
- end.call
- else
- result = workspace.evaluate(code, @eval_path, line_no)
+ if exception
+ line_no -= 1
+ line = "begin ::Kernel.raise _; rescue _.class\n#{line}\n""end"
+ @workspace.local_variable_set(:_, exception)
end
- result
- end
-
- def parse_command(code)
- command_name, arg = code.strip.split(/\s+/, 2)
- return unless code.lines.size == 1 && command_name
- arg ||= ''
- command = command_name.to_sym
- # Command aliases are always command. example: $, @
- if (alias_name = command_aliases[command])
- return [alias_name, arg]
+ # Transform a non-identifier alias (@, $) or keywords (next, break)
+ command, args = line.split(/\s/, 2)
+ if original = command_aliases[command.to_sym]
+ line = line.gsub(/\A#{Regexp.escape(command)}/, original.to_s)
+ command = original
end
- # Assignment-like expression is not a command
- return if arg.start_with?(ASSIGN_OPERATORS_REGEXP) && !arg.start_with?(/==|=~/)
-
- # Local variable have precedence over command
- return if local_variables.include?(command)
-
- # Check visibility
- public_method = !!Kernel.instance_method(:public_method).bind_call(main, command) rescue false
- private_method = !public_method && !!Kernel.instance_method(:method).bind_call(main, command) rescue false
- if Command.execute_as_command?(command, public_method: public_method, private_method: private_method)
- [command, arg]
+ # Hook command-specific transformation
+ command_class = ExtendCommandBundle.load_command(command)
+ if command_class&.respond_to?(:transform_args)
+ line = "#{command} #{command_class.transform_args(args)}"
end
- end
- def colorize_input(input, complete:)
- if IRB.conf[:USE_COLORIZE] && IRB::Color.colorable?
- lvars = local_variables || []
- if parse_command(input)
- name, sep, arg = input.split(/(\s+)/, 2)
- arg = IRB::Color.colorize_code(arg, complete: complete, local_variables: lvars)
- "#{IRB::Color.colorize(name, [:BOLD])}\e[m#{sep}#{arg}"
- else
- IRB::Color.colorize_code(input, complete: complete, local_variables: lvars)
- end
- else
- Reline::Unicode.escape_for_print(input)
- end
+ set_last_value(@workspace.evaluate(self, line, irb_path, line_no))
end
def inspect_last_value # :nodoc:
@inspect_method.inspect_value(@last_value)
end
+ alias __exit__ exit
+ # Exits the current session, see IRB.irb_exit
+ def exit(ret = 0)
+ IRB.irb_exit(@irb, ret)
+ rescue UncaughtThrowError
+ super
+ end
+
NOPRINTING_IVARS = ["@last_value"] # :nodoc:
NO_INSPECTING_IVARS = ["@irb", "@io"] # :nodoc:
IDNAME_IVARS = ["@prompt_mode"] # :nodoc:
@@ -704,5 +544,17 @@ module IRB
def local_variables # :nodoc:
workspace.binding.local_variables
end
+
+ # Return true if it's aliased from the argument and it's not an identifier.
+ def symbol_alias?(command)
+ return nil if command.match?(/\A\w+\z/)
+ command_aliases.key?(command.to_sym)
+ end
+
+ # Return true if the command supports transforming args
+ def transform_args?(command)
+ command = command_aliases.fetch(command.to_sym, command)
+ ExtendCommandBundle.load_command(command)&.respond_to?(:transform_args)
+ end
end
end
diff --git a/lib/irb/debug.rb b/lib/irb/debug.rb
deleted file mode 100644
index cd64b77ad7..0000000000
--- a/lib/irb/debug.rb
+++ /dev/null
@@ -1,126 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- module Debug
- IRB_DIR = File.expand_path('..', __dir__)
-
- class << self
- def insert_debug_break(pre_cmds: nil, do_cmds: nil)
- options = { oneshot: true, hook_call: false }
-
- if pre_cmds || do_cmds
- options[:command] = ['irb', pre_cmds, do_cmds]
- end
- if DEBUGGER__::LineBreakpoint.instance_method(:initialize).parameters.include?([:key, :skip_src])
- options[:skip_src] = true
- end
-
- # To make debugger commands like `next` or `continue` work without asking
- # the user to quit IRB after that, we need to exit IRB first and then hit
- # a TracePoint on #debug_break.
- file, lineno = IRB::Irb.instance_method(:debug_break).source_location
- DEBUGGER__::SESSION.add_line_breakpoint(file, lineno + 1, **options)
- end
-
- def setup(irb)
- # When debug session is not started at all
- unless defined?(DEBUGGER__::SESSION)
- begin
- require "debug/session"
- rescue LoadError # debug.gem is not written in Gemfile
- return false unless load_bundled_debug_gem
- end
- DEBUGGER__::CONFIG.set_config
- configure_irb_for_debugger(irb)
-
- DEBUGGER__.initialize_session{ IRB::Debug::UI.new(irb) }
- end
-
- # When debug session was previously started but not by IRB
- if defined?(DEBUGGER__::SESSION) && !irb.context.with_debugger
- configure_irb_for_debugger(irb)
- DEBUGGER__::SESSION.reset_ui(IRB::Debug::UI.new(irb))
- end
-
- # Apply patches to debug gem so it skips IRB frames
- unless DEBUGGER__.respond_to?(:capture_frames_without_irb)
- DEBUGGER__.singleton_class.send(:alias_method, :capture_frames_without_irb, :capture_frames)
-
- def DEBUGGER__.capture_frames(*args)
- frames = capture_frames_without_irb(*args)
- frames.reject! do |frame|
- frame.realpath&.start_with?(IRB_DIR) || frame.path == "<internal:prelude>"
- end
- frames
- end
-
- DEBUGGER__::ThreadClient.prepend(SkipPathHelperForIRB)
- end
-
- if !DEBUGGER__::CONFIG[:no_hint] && irb.context.io.is_a?(RelineInputMethod)
- Reline.output_modifier_proc = proc do |input, complete:|
- unless input.strip.empty?
- cmd = input.split(/\s/, 2).first
-
- if !complete && DEBUGGER__.commands.key?(cmd)
- input = input.sub(/\n$/, " # debug command\n")
- end
- end
-
- irb.context.colorize_input(input, complete: complete)
- end
- end
-
- true
- end
-
- private
-
- def configure_irb_for_debugger(irb)
- require 'irb/debug/ui'
- IRB.instance_variable_set(:@debugger_irb, irb)
- irb.context.with_debugger = true
- irb.context.irb_name += ":rdbg"
- end
-
- module SkipPathHelperForIRB
- def skip_internal_path?(path)
- # The latter can be removed once https://github.com/ruby/debug/issues/866 is resolved
- super || path.match?(IRB_DIR) || path.match?('<internal:prelude>')
- end
- end
-
- # This is used when debug.gem is not written in Gemfile. Even if it's not
- # installed by `bundle install`, debug.gem is installed by default because
- # it's a bundled gem. This method tries to activate and load that.
- def load_bundled_debug_gem
- # Discover latest debug.gem under GEM_PATH
- debug_gem = Gem.paths.path.flat_map { |path| Dir.glob("#{path}/gems/debug-*") }.select do |path|
- File.basename(path).match?(/\Adebug-\d+\.\d+\.\d+(\w+)?\z/)
- end.sort_by do |path|
- Gem::Version.new(File.basename(path).delete_prefix('debug-'))
- end.last
- return false unless debug_gem
-
- # Discover debug/debug.so under extensions for Ruby 3.2+
- ext_name = "/debug/debug.#{RbConfig::CONFIG['DLEXT']}"
- ext_path = Gem.paths.path.flat_map do |path|
- Dir.glob("#{path}/extensions/**/#{File.basename(debug_gem)}#{ext_name}")
- end.first
-
- # Attempt to forcibly load the bundled gem
- if ext_path
- $LOAD_PATH << ext_path.delete_suffix(ext_name)
- end
- $LOAD_PATH << "#{debug_gem}/lib"
- begin
- require "debug/session"
- puts "Loaded #{File.basename(debug_gem)}"
- true
- rescue LoadError
- false
- end
- end
- end
- end
-end
diff --git a/lib/irb/debug/ui.rb b/lib/irb/debug/ui.rb
deleted file mode 100644
index 7a1cd6dd16..0000000000
--- a/lib/irb/debug/ui.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-require 'io/console/size'
-require 'debug/console'
-
-module IRB
- module Debug
- class UI < DEBUGGER__::UI_Base
- def initialize(irb)
- @irb = irb
- end
-
- def remote?
- false
- end
-
- def activate session, on_fork: false
- end
-
- def deactivate
- end
-
- def width
- if (w = IO.console_size[1]) == 0 # for tests PTY
- 80
- else
- w
- end
- end
-
- def quit n
- yield
- exit n
- end
-
- def ask prompt
- setup_interrupt do
- print prompt
- ($stdin.gets || '').strip
- end
- end
-
- def puts str = nil
- case str
- when Array
- str.each{|line|
- $stdout.puts line.chomp
- }
- when String
- str.each_line{|line|
- $stdout.puts line.chomp
- }
- when nil
- $stdout.puts
- end
- end
-
- def readline _
- setup_interrupt do
- tc = DEBUGGER__::SESSION.instance_variable_get(:@tc)
- cmd = @irb.debug_readline(tc.current_frame.eval_binding || TOPLEVEL_BINDING)
-
- case cmd
- when nil # when user types C-d
- "continue"
- else
- cmd
- end
- end
- end
-
- def setup_interrupt
- DEBUGGER__::SESSION.intercept_trap_sigint false do
- current_thread = Thread.current # should be session_server thread
-
- prev_handler = trap(:INT){
- current_thread.raise Interrupt
- }
-
- yield
- ensure
- trap(:INT, prev_handler)
- end
- end
-
- def after_fork_parent
- parent_pid = Process.pid
-
- at_exit{
- DEBUGGER__::SESSION.intercept_trap_sigint_end
- trap(:SIGINT, :IGNORE)
-
- if Process.pid == parent_pid
- # only check child process from its parent
- begin
- # wait for all child processes to keep terminal
- Process.waitpid
- rescue Errno::ESRCH, Errno::ECHILD
- end
- end
- }
- end
- end
- end
-end
diff --git a/lib/irb/default_commands.rb b/lib/irb/default_commands.rb
deleted file mode 100644
index 768fbee9d7..0000000000
--- a/lib/irb/default_commands.rb
+++ /dev/null
@@ -1,276 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "command"
-require_relative "command/internal_helpers"
-require_relative "command/backtrace"
-require_relative "command/break"
-require_relative "command/catch"
-require_relative "command/cd"
-require_relative "command/chws"
-require_relative "command/context"
-require_relative "command/continue"
-require_relative "command/debug"
-require_relative "command/delete"
-require_relative "command/disable_irb"
-require_relative "command/edit"
-require_relative "command/exit"
-require_relative "command/finish"
-require_relative "command/force_exit"
-require_relative "command/help"
-require_relative "command/history"
-require_relative "command/info"
-require_relative "command/irb_info"
-require_relative "command/load"
-require_relative "command/ls"
-require_relative "command/measure"
-require_relative "command/next"
-require_relative "command/pushws"
-require_relative "command/show_doc"
-require_relative "command/show_source"
-require_relative "command/step"
-require_relative "command/subirb"
-require_relative "command/whereami"
-
-module IRB
- module Command
- NO_OVERRIDE = 0
- OVERRIDE_PRIVATE_ONLY = 0x01
- OVERRIDE_ALL = 0x02
-
- class << self
- # This API is for IRB's internal use only and may change at any time.
- # Please do NOT use it.
- def _register_with_aliases(name, command_class, *aliases)
- @commands[name.to_sym] = [command_class, aliases]
- end
-
- def all_commands_info
- user_aliases = IRB.CurrentContext.command_aliases.each_with_object({}) do |(alias_name, target), result|
- result[target] ||= []
- result[target] << alias_name
- end
-
- commands.map do |command_name, (command_class, aliases)|
- aliases = aliases.map { |a| a.first }
-
- if additional_aliases = user_aliases[command_name]
- aliases += additional_aliases
- end
-
- display_name = aliases.shift || command_name
- {
- display_name: display_name,
- description: command_class.description,
- category: command_class.category
- }
- end
- end
-
- def command_override_policies
- @@command_override_policies ||= commands.flat_map do |cmd_name, (cmd_class, aliases)|
- [[cmd_name, OVERRIDE_ALL]] + aliases
- end.to_h
- end
-
- def execute_as_command?(name, public_method:, private_method:)
- case command_override_policies[name]
- when OVERRIDE_ALL
- true
- when OVERRIDE_PRIVATE_ONLY
- !public_method
- when NO_OVERRIDE
- !public_method && !private_method
- end
- end
-
- def command_names
- command_override_policies.keys.map(&:to_s)
- end
-
- # Convert a command name to its implementation class if such command exists
- def load_command(command)
- command = command.to_sym
- commands.each do |command_name, (command_class, aliases)|
- if command_name == command || aliases.any? { |alias_name, _| alias_name == command }
- return command_class
- end
- end
- nil
- end
- end
-
- _register_with_aliases(:irb_context, Command::Context,
- [:context, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_exit, Command::Exit,
- [:exit, OVERRIDE_PRIVATE_ONLY],
- [:quit, OVERRIDE_PRIVATE_ONLY],
- [:irb_quit, OVERRIDE_PRIVATE_ONLY]
- )
-
- _register_with_aliases(:irb_exit!, Command::ForceExit,
- [:exit!, OVERRIDE_PRIVATE_ONLY]
- )
-
- _register_with_aliases(:irb_current_working_workspace, Command::CurrentWorkingWorkspace,
- [:cwws, NO_OVERRIDE],
- [:pwws, NO_OVERRIDE],
- [:irb_print_working_workspace, OVERRIDE_ALL],
- [:irb_cwws, OVERRIDE_ALL],
- [:irb_pwws, OVERRIDE_ALL],
- [:irb_current_working_binding, OVERRIDE_ALL],
- [:irb_print_working_binding, OVERRIDE_ALL],
- [:irb_cwb, OVERRIDE_ALL],
- [:irb_pwb, OVERRIDE_ALL],
- )
-
- _register_with_aliases(:irb_change_workspace, Command::ChangeWorkspace,
- [:chws, NO_OVERRIDE],
- [:cws, NO_OVERRIDE],
- [:irb_chws, OVERRIDE_ALL],
- [:irb_cws, OVERRIDE_ALL],
- [:irb_change_binding, OVERRIDE_ALL],
- [:irb_cb, OVERRIDE_ALL],
- [:cb, NO_OVERRIDE],
- )
-
- _register_with_aliases(:irb_workspaces, Command::Workspaces,
- [:workspaces, NO_OVERRIDE],
- [:irb_bindings, OVERRIDE_ALL],
- [:bindings, NO_OVERRIDE],
- )
-
- _register_with_aliases(:irb_push_workspace, Command::PushWorkspace,
- [:pushws, NO_OVERRIDE],
- [:irb_pushws, OVERRIDE_ALL],
- [:irb_push_binding, OVERRIDE_ALL],
- [:irb_pushb, OVERRIDE_ALL],
- [:pushb, NO_OVERRIDE],
- )
-
- _register_with_aliases(:irb_pop_workspace, Command::PopWorkspace,
- [:popws, NO_OVERRIDE],
- [:irb_popws, OVERRIDE_ALL],
- [:irb_pop_binding, OVERRIDE_ALL],
- [:irb_popb, OVERRIDE_ALL],
- [:popb, NO_OVERRIDE],
- )
-
- _register_with_aliases(:irb_load, Command::Load)
- _register_with_aliases(:irb_require, Command::Require)
- _register_with_aliases(:irb_source, Command::Source,
- [:source, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb, Command::IrbCommand)
- _register_with_aliases(:irb_jobs, Command::Jobs,
- [:jobs, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_fg, Command::Foreground,
- [:fg, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_kill, Command::Kill,
- [:kill, OVERRIDE_PRIVATE_ONLY]
- )
-
- _register_with_aliases(:irb_debug, Command::Debug,
- [:debug, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_edit, Command::Edit,
- [:edit, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_break, Command::Break,
- [:break, OVERRIDE_ALL]
- )
- _register_with_aliases(:irb_catch, Command::Catch,
- [:catch, OVERRIDE_PRIVATE_ONLY]
- )
- _register_with_aliases(:irb_next, Command::Next,
- [:next, OVERRIDE_ALL]
- )
- _register_with_aliases(:irb_delete, Command::Delete,
- [:delete, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_step, Command::Step,
- [:step, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_continue, Command::Continue,
- [:continue, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_finish, Command::Finish,
- [:finish, NO_OVERRIDE]
- )
- _register_with_aliases(:irb_backtrace, Command::Backtrace,
- [:backtrace, NO_OVERRIDE],
- [:bt, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_debug_info, Command::Info,
- [:info, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_help, Command::Help,
- [:help, NO_OVERRIDE],
- [:show_cmds, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_show_doc, Command::ShowDoc,
- [:show_doc, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_info, Command::IrbInfo)
-
- _register_with_aliases(:irb_ls, Command::Ls,
- [:ls, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_measure, Command::Measure,
- [:measure, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_show_source, Command::ShowSource,
- [:show_source, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_whereami, Command::Whereami,
- [:whereami, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_history, Command::History,
- [:history, NO_OVERRIDE],
- [:hist, NO_OVERRIDE]
- )
-
- _register_with_aliases(:irb_disable_irb, Command::DisableIrb,
- [:disable_irb, NO_OVERRIDE]
- )
-
- register(:cd, Command::CD)
- end
-
- ExtendCommand = Command
-
- # For backward compatibility, we need to keep this module:
- # - As a container of helper methods
- # - As a place to register commands with the deprecated def_extend_command method
- module ExtendCommandBundle
- # For backward compatibility
- NO_OVERRIDE = Command::NO_OVERRIDE
- OVERRIDE_PRIVATE_ONLY = Command::OVERRIDE_PRIVATE_ONLY
- OVERRIDE_ALL = Command::OVERRIDE_ALL
-
- # Deprecated. Doesn't have any effect.
- @EXTEND_COMMANDS = []
-
- class << self
- # Drepcated. Use Command.regiser instead.
- def def_extend_command(cmd_name, cmd_class, _, *aliases)
- Command._register_with_aliases(cmd_name, cmd_class, *aliases)
- Command.class_variable_set(:@@command_override_policies, nil)
- end
- end
- end
-end
diff --git a/lib/irb/easter-egg.rb b/lib/irb/easter-egg.rb
index 14dc93fc9c..3e79692de9 100644
--- a/lib/irb/easter-egg.rb
+++ b/lib/irb/easter-egg.rb
@@ -98,28 +98,18 @@ module IRB
end
end
- private def easter_egg_logo(type)
- @easter_egg_logos ||= File.read(File.join(__dir__, 'ruby_logo.aa'), encoding: 'UTF-8:UTF-8')
- .split(/TYPE: ([A-Z_]+)\n/)[1..]
- .each_slice(2)
- .to_h
- @easter_egg_logos[type.to_s.upcase]
- end
-
private def easter_egg(type = nil)
- print "\e[?1049h"
type ||= [:logo, :dancing].sample
case type
when :logo
- Pager.page do |io|
- logo_type = STDOUT.external_encoding == Encoding::UTF_8 ? :unicode_large : :ascii_large
- io.write easter_egg_logo(logo_type)
- STDIN.raw { STDIN.getc } if io == STDOUT
+ File.open(File.join(__dir__, 'ruby_logo.aa')) do |f|
+ require "rdoc"
+ RDoc::RI::Driver.new.page do |io|
+ IO.copy_stream(f, io)
+ end
end
when :dancing
- STDOUT.cooked do
- interrupted = false
- prev_trap = trap("SIGINT") { interrupted = true }
+ begin
canvas = Canvas.new(Reline.get_screen_size)
Reline::IOGate.set_winch_handler do
canvas = Canvas.new(Reline.get_screen_size)
@@ -135,15 +125,12 @@ module IRB
buff[0, 20] = "\e[0mPress Ctrl+C to stop\e[31m\e[1m"
print "\e[H" + buff
sleep 0.05
- break if interrupted
end
rescue Interrupt
ensure
- trap("SIGINT", prev_trap)
+ print "\e[0m\e[?1049l"
end
end
- ensure
- print "\e[0m\e[?1049l"
end
end
end
diff --git a/lib/irb/ext/change-ws.rb b/lib/irb/ext/change-ws.rb
index 60e8afe31f..4c57e44eab 100644
--- a/lib/irb/ext/change-ws.rb
+++ b/lib/irb/ext/change-ws.rb
@@ -1,8 +1,14 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/ext/cb.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB # :nodoc:
class Context
@@ -12,7 +18,7 @@ module IRB # :nodoc:
if defined? @home_workspace
@home_workspace
else
- @home_workspace = workspace
+ @home_workspace = @workspace
end
end
@@ -25,13 +31,15 @@ module IRB # :nodoc:
# See IRB::WorkSpace.new for more information.
def change_workspace(*_main)
if _main.empty?
- replace_workspace(home_workspace)
+ @workspace = home_workspace
return main
end
- workspace = WorkSpace.new(_main[0])
- replace_workspace(workspace)
- workspace.load_helper_methods_to_main
+ @workspace = WorkSpace.new(_main[0])
+
+ if !(class<<main;ancestors;end).include?(ExtendCommandBundle)
+ main.extend ExtendCommandBundle
+ end
end
end
end
diff --git a/lib/irb/ext/eval_history.rb b/lib/irb/ext/eval_history.rb
deleted file mode 100644
index 6c21ff00ee..0000000000
--- a/lib/irb/ext/eval_history.rb
+++ /dev/null
@@ -1,149 +0,0 @@
-# frozen_string_literal: true
-#
-# history.rb -
-# by Keiju ISHITSUKA(keiju@ruby-lang.org)
-#
-
-module IRB # :nodoc:
-
- class Context
-
- NOPRINTING_IVARS.push "@eval_history_values"
-
- # See #set_last_value
- alias _set_last_value set_last_value
-
- def set_last_value(value)
- _set_last_value(value)
-
- if defined?(@eval_history) && @eval_history
- @eval_history_values.push @line_no, @last_value
- workspace.evaluate "__ = IRB.CurrentContext.instance_eval{@eval_history_values}"
- end
-
- @last_value
- end
-
- remove_method :eval_history= if method_defined?(:eval_history=)
- # The command result history limit. This method is not available until
- # #eval_history= was called with non-nil value (directly or via
- # setting <code>IRB.conf[:EVAL_HISTORY]</code> in <code>.irbrc</code>).
- attr_reader :eval_history
- # Sets command result history limit. Default value is set from
- # <code>IRB.conf[:EVAL_HISTORY]</code>.
- #
- # +no+ is an Integer or +nil+.
- #
- # Returns +no+ of history items if greater than 0.
- #
- # If +no+ is 0, the number of history items is unlimited.
- #
- # If +no+ is +nil+, execution result history isn't used (default).
- #
- # EvalHistory values are available via <code>__</code> variable, see
- # IRB::EvalHistory.
- def eval_history=(no)
- if no
- if defined?(@eval_history) && @eval_history
- @eval_history_values.size(no)
- else
- @eval_history_values = EvalHistory.new(no)
- IRB.conf[:__TMP__EHV__] = @eval_history_values
- workspace.evaluate("__ = IRB.conf[:__TMP__EHV__]")
- IRB.conf.delete(:__TMP_EHV__)
- end
- else
- @eval_history_values = nil
- end
- @eval_history = no
- end
- end
-
- # Represents history of results of previously evaluated commands.
- #
- # Available via <code>__</code> variable, only if <code>IRB.conf[:EVAL_HISTORY]</code>
- # or <code>IRB::CurrentContext().eval_history</code> is non-nil integer value
- # (by default it is +nil+).
- #
- # Example (in `irb`):
- #
- # # Initialize history
- # IRB::CurrentContext().eval_history = 10
- # # => 10
- #
- # # Perform some commands...
- # 1 + 2
- # # => 3
- # puts 'x'
- # # x
- # # => nil
- # raise RuntimeError
- # # ...error raised
- #
- # # Inspect history (format is "<item number> <evaluated value>":
- # __
- # # => 1 10
- # # 2 3
- # # 3 nil
- #
- # __[1]
- # # => 10
- #
- class EvalHistory
-
- def initialize(size = 16) # :nodoc:
- @size = size
- @contents = []
- end
-
- def size(size) # :nodoc:
- if size != 0 && size < @size
- @contents = @contents[@size - size .. @size]
- end
- @size = size
- end
-
- # Get one item of the content (both positive and negative indexes work).
- def [](idx)
- begin
- if idx >= 0
- @contents.find{|no, val| no == idx}[1]
- else
- @contents[idx][1]
- end
- rescue NameError
- nil
- end
- end
-
- def push(no, val) # :nodoc:
- @contents.push [no, val]
- @contents.shift if @size != 0 && @contents.size > @size
- end
-
- alias real_inspect inspect
-
- def inspect # :nodoc:
- if @contents.empty?
- return real_inspect
- end
-
- unless (last = @contents.pop)[1].equal?(self)
- @contents.push last
- last = nil
- end
- str = @contents.collect{|no, val|
- if val.equal?(self)
- "#{no} ...self-history..."
- else
- "#{no} #{val.inspect}"
- end
- }.join("\n")
- if str == ""
- str = "Empty."
- end
- @contents.push last if last
- str
- end
- end
-end
diff --git a/lib/irb/ext/history.rb b/lib/irb/ext/history.rb
new file mode 100644
index 0000000000..fc304c6f6c
--- /dev/null
+++ b/lib/irb/ext/history.rb
@@ -0,0 +1,155 @@
+# frozen_string_literal: false
+#
+# history.rb -
+# $Release Version: 0.9.6$
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+
+module IRB # :nodoc:
+
+ class Context
+
+ NOPRINTING_IVARS.push "@eval_history_values"
+
+ # See #set_last_value
+ alias _set_last_value set_last_value
+
+ def set_last_value(value)
+ _set_last_value(value)
+
+ if defined?(@eval_history) && @eval_history
+ @eval_history_values.push @line_no, @last_value
+ @workspace.evaluate self, "__ = IRB.CurrentContext.instance_eval{@eval_history_values}"
+ end
+
+ @last_value
+ end
+
+ remove_method :eval_history= if method_defined?(:eval_history=)
+ # The command result history limit. This method is not available until
+ # #eval_history= was called with non-nil value (directly or via
+ # setting <code>IRB.conf[:EVAL_HISTORY]</code> in <code>.irbrc</code>).
+ attr_reader :eval_history
+ # Sets command result history limit. Default value is set from
+ # <code>IRB.conf[:EVAL_HISTORY]</code>.
+ #
+ # +no+ is an Integer or +nil+.
+ #
+ # Returns +no+ of history items if greater than 0.
+ #
+ # If +no+ is 0, the number of history items is unlimited.
+ #
+ # If +no+ is +nil+, execution result history isn't used (default).
+ #
+ # History values are available via <code>__</code> variable, see
+ # IRB::History.
+ def eval_history=(no)
+ if no
+ if defined?(@eval_history) && @eval_history
+ @eval_history_values.size(no)
+ else
+ @eval_history_values = History.new(no)
+ IRB.conf[:__TMP__EHV__] = @eval_history_values
+ @workspace.evaluate(self, "__ = IRB.conf[:__TMP__EHV__]")
+ IRB.conf.delete(:__TMP_EHV__)
+ end
+ else
+ @eval_history_values = nil
+ end
+ @eval_history = no
+ end
+ end
+
+ # Represents history of results of previously evaluated commands.
+ #
+ # Available via <code>__</code> variable, only if <code>IRB.conf[:EVAL_HISTORY]</code>
+ # or <code>IRB::CurrentContext().eval_history</code> is non-nil integer value
+ # (by default it is +nil+).
+ #
+ # Example (in `irb`):
+ #
+ # # Initialize history
+ # IRB::CurrentContext().eval_history = 10
+ # # => 10
+ #
+ # # Perform some commands...
+ # 1 + 2
+ # # => 3
+ # puts 'x'
+ # # x
+ # # => nil
+ # raise RuntimeError
+ # # ...error raised
+ #
+ # # Inspect history (format is "<item number> <evaluated value>":
+ # __
+ # # => 1 10
+ # # 2 3
+ # # 3 nil
+ #
+ # __[1]
+ # # => 10
+ #
+ class History
+
+ def initialize(size = 16) # :nodoc:
+ @size = size
+ @contents = []
+ end
+
+ def size(size) # :nodoc:
+ if size != 0 && size < @size
+ @contents = @contents[@size - size .. @size]
+ end
+ @size = size
+ end
+
+ # Get one item of the content (both positive and negative indexes work).
+ def [](idx)
+ begin
+ if idx >= 0
+ @contents.find{|no, val| no == idx}[1]
+ else
+ @contents[idx][1]
+ end
+ rescue NameError
+ nil
+ end
+ end
+
+ def push(no, val) # :nodoc:
+ @contents.push [no, val]
+ @contents.shift if @size != 0 && @contents.size > @size
+ end
+
+ alias real_inspect inspect
+
+ def inspect # :nodoc:
+ if @contents.empty?
+ return real_inspect
+ end
+
+ unless (last = @contents.pop)[1].equal?(self)
+ @contents.push last
+ last = nil
+ end
+ str = @contents.collect{|no, val|
+ if val.equal?(self)
+ "#{no} ...self-history..."
+ else
+ "#{no} #{val.inspect}"
+ end
+ }.join("\n")
+ if str == ""
+ str = "Empty."
+ end
+ @contents.push last if last
+ str
+ end
+ end
+end
diff --git a/lib/irb/ext/loader.rb b/lib/irb/ext/loader.rb
index df5aaa8e5a..af028996e7 100644
--- a/lib/irb/ext/loader.rb
+++ b/lib/irb/ext/loader.rb
@@ -1,8 +1,15 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# loader.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
+
module IRB # :nodoc:
# Raised in the event of an exception in a file loaded from an Irb session
@@ -24,8 +31,31 @@ module IRB # :nodoc:
load_file(path, priv)
end
+ if File.respond_to?(:absolute_path?)
+ def absolute_path?(path)
+ File.absolute_path?(path)
+ end
+ else
+ separator =
+ if File::ALT_SEPARATOR
+ "[#{Regexp.quote(File::SEPARATOR + File::ALT_SEPARATOR)}]"
+ else
+ File::SEPARATOR
+ end
+ ABSOLUTE_PATH_PATTERN = # :nodoc:
+ case Dir.pwd
+ when /\A\w:/, /\A#{separator}{2}/
+ /\A(?:\w:|#{separator})#{separator}/
+ else
+ /\A#{separator}/
+ end
+ def absolute_path?(path)
+ ABSOLUTE_PATH_PATTERN =~ path
+ end
+ end
+
def search_file_from_ruby_path(fn) # :nodoc:
- if File.absolute_path?(fn)
+ if absolute_path?(fn)
return fn if File.exist?(fn)
return nil
end
@@ -42,7 +72,6 @@ module IRB # :nodoc:
#
# See Irb#suspend_input_method for more information.
def source_file(path)
- irb = irb_context.irb
irb.suspend_name(path, File.basename(path)) do
FileInputMethod.open(path) do |io|
irb.suspend_input_method(io) do
@@ -67,7 +96,6 @@ module IRB # :nodoc:
#
# See Irb#suspend_input_method for more information.
def load_file(path, priv = nil)
- irb = irb_context.irb
irb.suspend_name(path, File.basename(path)) do
if priv
@@ -98,13 +126,13 @@ module IRB # :nodoc:
def old # :nodoc:
back_io = @io
- back_path = irb_path
+ back_path = @irb_path
back_name = @irb_name
back_scanner = @irb.scanner
begin
@io = FileInputMethod.new(path)
@irb_name = File.basename(path)
- self.irb_path = path
+ @irb_path = path
@irb.signal_status(:IN_LOAD) do
if back_io.kind_of?(FileInputMethod)
@irb.eval_input
@@ -119,7 +147,7 @@ module IRB # :nodoc:
ensure
@io = back_io
@irb_name = back_name
- self.irb_path = back_path
+ @irb_path = back_path
@irb.scanner = back_scanner
end
end
diff --git a/lib/irb/ext/multi-irb.rb b/lib/irb/ext/multi-irb.rb
index 9f234f0cdc..e57d43a569 100644
--- a/lib/irb/ext/multi-irb.rb
+++ b/lib/irb/ext/multi-irb.rb
@@ -1,11 +1,17 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/multi-irb.rb - multiple irb module
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB
- class JobManager # :nodoc:
+ class JobManager
# Creates a new JobManager object
def initialize
@@ -166,12 +172,12 @@ module IRB
@JobManager = JobManager.new
# The current JobManager in the session
- def IRB.JobManager # :nodoc:
+ def IRB.JobManager
@JobManager
end
# The current Context in this session
- def IRB.CurrentContext # :nodoc:
+ def IRB.CurrentContext
IRB.JobManager.irb(Thread.current).context
end
@@ -179,7 +185,7 @@ module IRB
#
# The optional +file+ argument is given to Context.new, along with the
# workspace created with the remaining arguments, see WorkSpace.new
- def IRB.irb(file = nil, *main) # :nodoc:
+ def IRB.irb(file = nil, *main)
workspace = WorkSpace.new(*main)
parent_thread = Thread.current
Thread.start do
diff --git a/lib/irb/ext/save-history.rb b/lib/irb/ext/save-history.rb
new file mode 100644
index 0000000000..9e7620545a
--- /dev/null
+++ b/lib/irb/ext/save-history.rb
@@ -0,0 +1,130 @@
+# frozen_string_literal: false
+# save-history.rb -
+# $Release Version: 0.9.6$
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+
+module IRB
+ module HistorySavingAbility # :nodoc:
+ end
+
+ class Context
+ def init_save_history# :nodoc:
+ unless (class<<@io;self;end).include?(HistorySavingAbility)
+ @io.extend(HistorySavingAbility)
+ end
+ end
+
+ # A copy of the default <code>IRB.conf[:SAVE_HISTORY]</code>
+ def save_history
+ IRB.conf[:SAVE_HISTORY]
+ end
+
+ remove_method(:save_history=) if method_defined?(:save_history=)
+ # Sets <code>IRB.conf[:SAVE_HISTORY]</code> to the given +val+ and calls
+ # #init_save_history with this context.
+ #
+ # Will store the number of +val+ entries of history in the #history_file
+ #
+ # Add the following to your +.irbrc+ to change the number of history
+ # entries stored to 1000:
+ #
+ # IRB.conf[:SAVE_HISTORY] = 1000
+ def save_history=(val)
+ IRB.conf[:SAVE_HISTORY] = val
+ if val
+ main_context = IRB.conf[:MAIN_CONTEXT]
+ main_context = self unless main_context
+ main_context.init_save_history
+ end
+ end
+
+ # A copy of the default <code>IRB.conf[:HISTORY_FILE]</code>
+ def history_file
+ IRB.conf[:HISTORY_FILE]
+ end
+
+ # Set <code>IRB.conf[:HISTORY_FILE]</code> to the given +hist+.
+ def history_file=(hist)
+ IRB.conf[:HISTORY_FILE] = hist
+ end
+ end
+
+ module HistorySavingAbility # :nodoc:
+ def HistorySavingAbility.extended(obj)
+ IRB.conf[:AT_EXIT].push proc{obj.save_history}
+ obj.load_history
+ obj
+ end
+
+ def load_history
+ return unless self.class.const_defined?(:HISTORY)
+ history = self.class::HISTORY
+ if history_file = IRB.conf[:HISTORY_FILE]
+ history_file = File.expand_path(history_file)
+ end
+ history_file = IRB.rc_file("_history") unless history_file
+ if File.exist?(history_file)
+ File.open(history_file, "r:#{IRB.conf[:LC_MESSAGES].encoding}") do |f|
+ f.each { |l|
+ l = l.chomp
+ if self.class == RelineInputMethod and history.last&.end_with?("\\")
+ history.last.delete_suffix!("\\")
+ history.last << "\n" << l
+ else
+ history << l
+ end
+ }
+ end
+ @loaded_history_lines = history.size
+ @loaded_history_mtime = File.mtime(history_file)
+ end
+ end
+
+ def save_history
+ return unless self.class.const_defined?(:HISTORY)
+ history = self.class::HISTORY
+ if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) != 0
+ if history_file = IRB.conf[:HISTORY_FILE]
+ history_file = File.expand_path(history_file)
+ end
+ history_file = IRB.rc_file("_history") unless history_file
+
+ # Change the permission of a file that already exists[BUG #7694]
+ begin
+ if File.stat(history_file).mode & 066 != 0
+ File.chmod(0600, history_file)
+ end
+ rescue Errno::ENOENT
+ rescue Errno::EPERM
+ return
+ rescue
+ raise
+ end
+
+ if File.exist?(history_file) &&
+ File.mtime(history_file) != @loaded_history_mtime
+ history = history[@loaded_history_lines..-1] if @loaded_history_lines
+ append_history = true
+ end
+
+ File.open(history_file, (append_history ? 'a' : 'w'), 0o600, encoding: IRB.conf[:LC_MESSAGES]&.encoding) do |f|
+ hist = history.map{ |l| l.split("\n").join("\\\n") }
+ unless append_history
+ begin
+ hist = hist.last(num) if hist.size > num and num > 0
+ rescue RangeError # bignum too big to convert into `long'
+ # Do nothing because the bignum should be treated as inifinity
+ end
+ end
+ f.puts(hist)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/irb/ext/tracer.rb b/lib/irb/ext/tracer.rb
index fd6daa88ae..67ac4bb965 100644
--- a/lib/irb/ext/tracer.rb
+++ b/lib/irb/ext/tracer.rb
@@ -1,39 +1,84 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/lib/tracer.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-# Loading the gem "tracer" will cause it to extend IRB commands with:
-# https://github.com/ruby/tracer/blob/v0.2.2/lib/tracer/irb.rb
+# --
+#
+#
+#
begin
require "tracer"
rescue LoadError
- $stderr.puts "Tracer extension of IRB is enabled but tracer gem wasn't found."
+ $stderr.puts "Tracer extension of IRB is enabled but tracer gem doesn't found."
+ module IRB
+ TracerLoadError = true
+ class Context
+ def use_tracer=(opt)
+ # do nothing
+ end
+ end
+ end
return # This is about to disable loading below
end
module IRB
- class CallTracer < ::CallTracer
- IRB_DIR = File.expand_path('../..', __dir__)
- def skip?(tp)
- super || tp.path.match?(IRB_DIR) || tp.path.match?('<internal:prelude>')
+ # initialize tracing function
+ def IRB.initialize_tracer
+ Tracer.verbose = false
+ Tracer.add_filter {
+ |event, file, line, id, binding, *rests|
+ /^#{Regexp.quote(@CONF[:IRB_LIB_PATH])}/ !~ file and
+ File::basename(file) != "irb.rb"
+ }
+ end
+
+ class Context
+ # Whether Tracer is used when evaluating statements in this context.
+ #
+ # See +lib/tracer.rb+ for more information.
+ attr_reader :use_tracer
+ alias use_tracer? use_tracer
+
+ # Sets whether or not to use the Tracer library when evaluating statements
+ # in this context.
+ #
+ # See +lib/tracer.rb+ for more information.
+ def use_tracer=(opt)
+ if opt
+ Tracer.set_get_line_procs(@irb_path) {
+ |line_no, *rests|
+ @io.line(line_no)
+ }
+ elsif !opt && @use_tracer
+ Tracer.off
+ end
+ @use_tracer=opt
end
end
+
class WorkSpace
alias __evaluate__ evaluate
# Evaluate the context of this workspace and use the Tracer library to
# output the exact lines of code are being executed in chronological order.
#
- # See https://github.com/ruby/tracer for more information.
- def evaluate(statements, file = __FILE__, line = __LINE__)
- if IRB.conf[:USE_TRACER] == true
- CallTracer.new(colorize: Color.colorable?).start do
- __evaluate__(statements, file, line)
+ # See +lib/tracer.rb+ for more information.
+ def evaluate(context, statements, file = nil, line = nil)
+ if context.use_tracer? && file != nil && line != nil
+ Tracer.on
+ begin
+ __evaluate__(context, statements, file, line)
+ ensure
+ Tracer.off
end
else
- __evaluate__(statements, file, line)
+ __evaluate__(context, statements, file || __FILE__, line || __LINE__)
end
end
end
+
+ IRB.initialize_tracer
end
diff --git a/lib/irb/ext/use-loader.rb b/lib/irb/ext/use-loader.rb
index c8a3ea1fe8..1897bc89e0 100644
--- a/lib/irb/ext/use-loader.rb
+++ b/lib/irb/ext/use-loader.rb
@@ -1,10 +1,16 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# use-loader.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
-require_relative "../command/load"
+require_relative "../cmd/load"
require_relative "loader"
class Object
@@ -17,12 +23,12 @@ module IRB
remove_method :irb_load if method_defined?(:irb_load)
# Loads the given file similarly to Kernel#load, see IrbLoader#irb_load
def irb_load(*opts, &b)
- Command::Load.execute(irb_context, *opts, &b)
+ ExtendCommand::Load.execute(irb_context, *opts, &b)
end
remove_method :irb_require if method_defined?(:irb_require)
# Loads the given file similarly to Kernel#require
def irb_require(*opts, &b)
- Command::Require.execute(irb_context, *opts, &b)
+ ExtendCommand::Require.execute(irb_context, *opts, &b)
end
end
@@ -49,12 +55,14 @@ module IRB
if IRB.conf[:USE_LOADER] != opt
IRB.conf[:USE_LOADER] = opt
if opt
- (class<<workspace.main;self;end).instance_eval {
+ if !$".include?("irb/cmd/load")
+ end
+ (class<<@workspace.main;self;end).instance_eval {
alias_method :load, :irb_load
alias_method :require, :irb_require
}
else
- (class<<workspace.main;self;end).instance_eval {
+ (class<<@workspace.main;self;end).instance_eval {
alias_method :load, :__original__load__IRB_use_loader__
alias_method :require, :__original__require__IRB_use_loader__
}
diff --git a/lib/irb/ext/workspaces.rb b/lib/irb/ext/workspaces.rb
index da09faa83e..730b58e64d 100644
--- a/lib/irb/ext/workspaces.rb
+++ b/lib/irb/ext/workspaces.rb
@@ -1,11 +1,32 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# push-ws.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB # :nodoc:
class Context
+
+ # Size of the current WorkSpace stack
+ def irb_level
+ workspace_stack.size
+ end
+
+ # WorkSpaces in the current stack
+ def workspaces
+ if defined? @workspaces
+ @workspaces
+ else
+ @workspaces = []
+ end
+ end
+
# Creates a new workspace with the given object or binding, and appends it
# onto the current #workspaces stack.
#
@@ -13,15 +34,20 @@ module IRB # :nodoc:
# information.
def push_workspace(*_main)
if _main.empty?
- if @workspace_stack.size > 1
- # swap the top two workspaces
- previous_workspace, current_workspace = @workspace_stack.pop(2)
- @workspace_stack.push current_workspace, previous_workspace
+ if workspaces.empty?
+ print "No other workspace\n"
+ return nil
end
- else
- new_workspace = WorkSpace.new(workspace.binding, _main[0])
- @workspace_stack.push new_workspace
- new_workspace.load_helper_methods_to_main
+ ws = workspaces.pop
+ workspaces.push @workspace
+ @workspace = ws
+ return workspaces
+ end
+
+ workspaces.push @workspace
+ @workspace = WorkSpace.new(@workspace.binding, _main[0])
+ if !(class<<main;ancestors;end).include?(ExtendCommandBundle)
+ main.extend ExtendCommandBundle
end
end
@@ -30,7 +56,11 @@ module IRB # :nodoc:
#
# Also, see #push_workspace.
def pop_workspace
- @workspace_stack.pop if @workspace_stack.size > 1
+ if workspaces.empty?
+ print "workspace stack empty\n"
+ return
+ end
+ @workspace = workspaces.pop
end
end
end
diff --git a/lib/irb/extend-command.rb b/lib/irb/extend-command.rb
new file mode 100644
index 0000000000..d0829a06c4
--- /dev/null
+++ b/lib/irb/extend-command.rb
@@ -0,0 +1,433 @@
+# frozen_string_literal: false
+#
+# irb/extend-command.rb - irb extend command
+# $Release Version: 0.9.6$
+# $Revision$
+# by Keiju ISHITSUKA(keiju@ruby-lang.org)
+#
+# --
+#
+#
+#
+module IRB # :nodoc:
+ # Installs the default irb extensions command bundle.
+ module ExtendCommandBundle
+ EXCB = ExtendCommandBundle # :nodoc:
+
+ # See #install_alias_method.
+ NO_OVERRIDE = 0
+ # See #install_alias_method.
+ OVERRIDE_PRIVATE_ONLY = 0x01
+ # See #install_alias_method.
+ OVERRIDE_ALL = 0x02
+
+ # Quits the current irb context
+ #
+ # +ret+ is the optional signal or message to send to Context#exit
+ #
+ # Same as <code>IRB.CurrentContext.exit</code>.
+ def irb_exit(ret = 0)
+ irb_context.exit(ret)
+ end
+
+ # Displays current configuration.
+ #
+ # Modifying the configuration is achieved by sending a message to IRB.conf.
+ def irb_context
+ IRB.CurrentContext
+ end
+
+ @ALIASES = [
+ [:context, :irb_context, NO_OVERRIDE],
+ [:conf, :irb_context, NO_OVERRIDE],
+ [:irb_quit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
+ [:exit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
+ [:quit, :irb_exit, OVERRIDE_PRIVATE_ONLY],
+ ]
+
+
+ @EXTEND_COMMANDS = [
+ [
+ :irb_current_working_workspace, :CurrentWorkingWorkspace, "cmd/chws",
+ [:cwws, NO_OVERRIDE],
+ [:pwws, NO_OVERRIDE],
+ [:irb_print_working_workspace, OVERRIDE_ALL],
+ [:irb_cwws, OVERRIDE_ALL],
+ [:irb_pwws, OVERRIDE_ALL],
+ [:irb_current_working_binding, OVERRIDE_ALL],
+ [:irb_print_working_binding, OVERRIDE_ALL],
+ [:irb_cwb, OVERRIDE_ALL],
+ [:irb_pwb, OVERRIDE_ALL],
+ ],
+ [
+ :irb_change_workspace, :ChangeWorkspace, "cmd/chws",
+ [:chws, NO_OVERRIDE],
+ [:cws, NO_OVERRIDE],
+ [:irb_chws, OVERRIDE_ALL],
+ [:irb_cws, OVERRIDE_ALL],
+ [:irb_change_binding, OVERRIDE_ALL],
+ [:irb_cb, OVERRIDE_ALL],
+ [:cb, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_workspaces, :Workspaces, "cmd/pushws",
+ [:workspaces, NO_OVERRIDE],
+ [:irb_bindings, OVERRIDE_ALL],
+ [:bindings, NO_OVERRIDE],
+ ],
+ [
+ :irb_push_workspace, :PushWorkspace, "cmd/pushws",
+ [:pushws, NO_OVERRIDE],
+ [:irb_pushws, OVERRIDE_ALL],
+ [:irb_push_binding, OVERRIDE_ALL],
+ [:irb_pushb, OVERRIDE_ALL],
+ [:pushb, NO_OVERRIDE],
+ ],
+ [
+ :irb_pop_workspace, :PopWorkspace, "cmd/pushws",
+ [:popws, NO_OVERRIDE],
+ [:irb_popws, OVERRIDE_ALL],
+ [:irb_pop_binding, OVERRIDE_ALL],
+ [:irb_popb, OVERRIDE_ALL],
+ [:popb, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_load, :Load, "cmd/load"],
+ [
+ :irb_require, :Require, "cmd/load"],
+ [
+ :irb_source, :Source, "cmd/load",
+ [:source, NO_OVERRIDE],
+ ],
+
+ [
+ :irb, :IrbCommand, "cmd/subirb"],
+ [
+ :irb_jobs, :Jobs, "cmd/subirb",
+ [:jobs, NO_OVERRIDE],
+ ],
+ [
+ :irb_fg, :Foreground, "cmd/subirb",
+ [:fg, NO_OVERRIDE],
+ ],
+ [
+ :irb_kill, :Kill, "cmd/subirb",
+ [:kill, OVERRIDE_PRIVATE_ONLY],
+ ],
+
+ [
+ :irb_debug, :Debug, "cmd/debug",
+ [:debug, NO_OVERRIDE],
+ ],
+ [
+ :irb_edit, :Edit, "cmd/edit",
+ [:edit, NO_OVERRIDE],
+ ],
+ [
+ :irb_break, :Break, "cmd/break",
+ ],
+ [
+ :irb_catch, :Catch, "cmd/catch",
+ ],
+ [
+ :irb_next, :Next, "cmd/next"
+ ],
+ [
+ :irb_delete, :Delete, "cmd/delete",
+ [:delete, NO_OVERRIDE],
+ ],
+ [
+ :irb_step, :Step, "cmd/step",
+ [:step, NO_OVERRIDE],
+ ],
+ [
+ :irb_continue, :Continue, "cmd/continue",
+ [:continue, NO_OVERRIDE],
+ ],
+ [
+ :irb_finish, :Finish, "cmd/finish",
+ [:finish, NO_OVERRIDE],
+ ],
+ [
+ :irb_backtrace, :Backtrace, "cmd/backtrace",
+ [:backtrace, NO_OVERRIDE],
+ [:bt, NO_OVERRIDE],
+ ],
+ [
+ :irb_debug_info, :Info, "cmd/info",
+ [:info, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_help, :Help, "cmd/help",
+ [:show_doc, NO_OVERRIDE],
+ [:help, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_info, :IrbInfo, "cmd/irb_info"
+ ],
+
+ [
+ :irb_ls, :Ls, "cmd/ls",
+ [:ls, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_measure, :Measure, "cmd/measure",
+ [:measure, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_show_source, :ShowSource, "cmd/show_source",
+ [:show_source, NO_OVERRIDE],
+ ],
+
+ [
+ :irb_whereami, :Whereami, "cmd/whereami",
+ [:whereami, NO_OVERRIDE],
+ ],
+ [
+ :irb_show_cmds, :ShowCmds, "cmd/show_cmds",
+ [:show_cmds, NO_OVERRIDE],
+ ]
+ ]
+
+
+ @@commands = []
+
+ def self.all_commands_info
+ return @@commands unless @@commands.empty?
+ user_aliases = IRB.CurrentContext.command_aliases.each_with_object({}) do |(alias_name, target), result|
+ result[target] ||= []
+ result[target] << alias_name
+ end
+
+ @EXTEND_COMMANDS.each do |cmd_name, cmd_class, load_file, *aliases|
+ if !defined?(ExtendCommand) || !ExtendCommand.const_defined?(cmd_class, false)
+ require_relative load_file
+ end
+
+ klass = ExtendCommand.const_get(cmd_class, false)
+ aliases = aliases.map { |a| a.first }
+
+ if additional_aliases = user_aliases[cmd_name]
+ aliases += additional_aliases
+ end
+
+ display_name = aliases.shift || cmd_name
+ @@commands << { display_name: display_name, description: klass.description, category: klass.category }
+ end
+
+ @@commands
+ end
+
+ # Convert a command name to its implementation class if such command exists
+ def self.load_command(command)
+ command = command.to_sym
+ @EXTEND_COMMANDS.each do |cmd_name, cmd_class, load_file, *aliases|
+ next if cmd_name != command && aliases.all? { |alias_name, _| alias_name != command }
+
+ if !defined?(ExtendCommand) || !ExtendCommand.const_defined?(cmd_class, false)
+ require_relative load_file
+ end
+ return ExtendCommand.const_get(cmd_class, false)
+ end
+ nil
+ end
+
+ # Installs the default irb commands.
+ def self.install_extend_commands
+ for args in @EXTEND_COMMANDS
+ def_extend_command(*args)
+ end
+ end
+
+ # Evaluate the given +cmd_name+ on the given +cmd_class+ Class.
+ #
+ # Will also define any given +aliases+ for the method.
+ #
+ # The optional +load_file+ parameter will be required within the method
+ # definition.
+ def self.def_extend_command(cmd_name, cmd_class, load_file = nil, *aliases)
+ case cmd_class
+ when Symbol
+ cmd_class = cmd_class.id2name
+ when String
+ when Class
+ cmd_class = cmd_class.name
+ end
+
+ if load_file
+ kwargs = ", **kwargs" if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
+ line = __LINE__; eval %[
+ def #{cmd_name}(*opts#{kwargs}, &b)
+ require_relative "#{load_file}"
+ arity = ExtendCommand::#{cmd_class}.instance_method(:execute).arity
+ args = (1..(arity < 0 ? ~arity : arity)).map {|i| "arg" + i.to_s }
+ args << "*opts#{kwargs}" if arity < 0
+ args << "&block"
+ args = args.join(", ")
+ line = __LINE__; eval %[
+ unless singleton_class.class_variable_defined?(:@@#{cmd_name}_)
+ singleton_class.class_variable_set(:@@#{cmd_name}_, true)
+ def self.#{cmd_name}_(\#{args})
+ ExtendCommand::#{cmd_class}.execute(irb_context, \#{args})
+ end
+ end
+ ], nil, __FILE__, line
+ __send__ :#{cmd_name}_, *opts#{kwargs}, &b
+ end
+ ], nil, __FILE__, line
+ else
+ line = __LINE__; eval %[
+ def #{cmd_name}(*opts, &b)
+ ExtendCommand::#{cmd_class}.execute(irb_context, *opts, &b)
+ end
+ ], nil, __FILE__, line
+ end
+
+ for ali, flag in aliases
+ @ALIASES.push [ali, cmd_name, flag]
+ end
+ end
+
+ # Installs alias methods for the default irb commands, see
+ # ::install_extend_commands.
+ def install_alias_method(to, from, override = NO_OVERRIDE)
+ to = to.id2name unless to.kind_of?(String)
+ from = from.id2name unless from.kind_of?(String)
+
+ if override == OVERRIDE_ALL or
+ (override == OVERRIDE_PRIVATE_ONLY) && !respond_to?(to) or
+ (override == NO_OVERRIDE) && !respond_to?(to, true)
+ target = self
+ (class << self; self; end).instance_eval{
+ if target.respond_to?(to, true) &&
+ !target.respond_to?(EXCB.irb_original_method_name(to), true)
+ alias_method(EXCB.irb_original_method_name(to), to)
+ end
+ alias_method to, from
+ }
+ else
+ Kernel.print "irb: warn: can't alias #{to} from #{from}.\n"
+ end
+ end
+
+ def self.irb_original_method_name(method_name) # :nodoc:
+ "irb_" + method_name + "_org"
+ end
+
+ # Installs alias methods for the default irb commands on the given object
+ # using #install_alias_method.
+ def self.extend_object(obj)
+ unless (class << obj; ancestors; end).include?(EXCB)
+ super
+ for ali, com, flg in @ALIASES
+ obj.install_alias_method(ali, com, flg)
+ end
+ end
+ end
+
+ install_extend_commands
+ end
+
+ # Extends methods for the Context module
+ module ContextExtender
+ CE = ContextExtender # :nodoc:
+
+ @EXTEND_COMMANDS = [
+ [:eval_history=, "ext/history.rb"],
+ [:use_tracer=, "ext/tracer.rb"],
+ [:use_loader=, "ext/use-loader.rb"],
+ [:save_history=, "ext/save-history.rb"],
+ ]
+
+ # Installs the default context extensions as irb commands:
+ #
+ # Context#eval_history=:: +irb/ext/history.rb+
+ # Context#use_tracer=:: +irb/ext/tracer.rb+
+ # Context#use_loader=:: +irb/ext/use-loader.rb+
+ # Context#save_history=:: +irb/ext/save-history.rb+
+ def self.install_extend_commands
+ for args in @EXTEND_COMMANDS
+ def_extend_command(*args)
+ end
+ end
+
+ # Evaluate the given +command+ from the given +load_file+ on the Context
+ # module.
+ #
+ # Will also define any given +aliases+ for the method.
+ def self.def_extend_command(cmd_name, load_file, *aliases)
+ line = __LINE__; Context.module_eval %[
+ def #{cmd_name}(*opts, &b)
+ Context.module_eval {remove_method(:#{cmd_name})}
+ require_relative "#{load_file}"
+ __send__ :#{cmd_name}, *opts, &b
+ end
+ for ali in aliases
+ alias_method ali, cmd_name
+ end
+ ], __FILE__, line
+ end
+
+ CE.install_extend_commands
+ end
+
+ # A convenience module for extending Ruby methods.
+ module MethodExtender
+ # Extends the given +base_method+ with a prefix call to the given
+ # +extend_method+.
+ def def_pre_proc(base_method, extend_method)
+ base_method = base_method.to_s
+ extend_method = extend_method.to_s
+
+ alias_name = new_alias_name(base_method)
+ module_eval %[
+ alias_method alias_name, base_method
+ def #{base_method}(*opts)
+ __send__ :#{extend_method}, *opts
+ __send__ :#{alias_name}, *opts
+ end
+ ]
+ end
+
+ # Extends the given +base_method+ with a postfix call to the given
+ # +extend_method+.
+ def def_post_proc(base_method, extend_method)
+ base_method = base_method.to_s
+ extend_method = extend_method.to_s
+
+ alias_name = new_alias_name(base_method)
+ module_eval %[
+ alias_method alias_name, base_method
+ def #{base_method}(*opts)
+ __send__ :#{alias_name}, *opts
+ __send__ :#{extend_method}, *opts
+ end
+ ]
+ end
+
+ # Returns a unique method name to use as an alias for the given +name+.
+ #
+ # Usually returns <code>#{prefix}#{name}#{postfix}<num></code>, example:
+ #
+ # new_alias_name('foo') #=> __alias_of__foo__
+ # def bar; end
+ # new_alias_name('bar') #=> __alias_of__bar__2
+ def new_alias_name(name, prefix = "__alias_of__", postfix = "__")
+ base_name = "#{prefix}#{name}#{postfix}"
+ all_methods = instance_methods(true) + private_instance_methods(true)
+ same_methods = all_methods.grep(/^#{Regexp.quote(base_name)}[0-9]*$/)
+ return base_name if same_methods.empty?
+ no = same_methods.size
+ while !same_methods.include?(alias_name = base_name + no)
+ no += 1
+ end
+ alias_name
+ end
+ end
+end
diff --git a/lib/irb/frame.rb b/lib/irb/frame.rb
index 4b697c8719..de54a98f1b 100644
--- a/lib/irb/frame.rb
+++ b/lib/irb/frame.rb
@@ -1,8 +1,14 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# frame.rb -
+# $Release Version: 0.9$
+# $Revision$
# by Keiju ISHITSUKA(Nihon Rational Software Co.,Ltd)
#
+# --
+#
+#
+#
module IRB
class Frame
diff --git a/lib/irb/help.rb b/lib/irb/help.rb
index a24bc10a15..3eeaf841b0 100644
--- a/lib/irb/help.rb
+++ b/lib/irb/help.rb
@@ -1,16 +1,24 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/help.rb - print usage module
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
#
+# --
+#
+#
+#
+
+require_relative 'magic-file'
module IRB
- # Outputs the irb help message, see IRB@Command-Line+Options.
- def IRB.print_usage # :nodoc:
+ # Outputs the irb help message, see IRB@Command+line+options.
+ def IRB.print_usage
lc = IRB.conf[:LC_MESSAGES]
path = lc.find("irb/help-message")
space_line = false
- File.open(path){|f|
+ IRB::MagicFile.open(path){|f|
f.each_line do |l|
if /^\s*$/ =~ l
lc.puts l unless space_line
diff --git a/lib/irb/helper_method.rb b/lib/irb/helper_method.rb
deleted file mode 100644
index f1f6fff915..0000000000
--- a/lib/irb/helper_method.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative "helper_method/base"
-
-module IRB
- module HelperMethod
- @helper_methods = {}
-
- class << self
- attr_reader :helper_methods
-
- def register(name, helper_class)
- @helper_methods[name] = helper_class
-
- if defined?(HelpersContainer)
- HelpersContainer.install_helper_methods
- end
- end
-
- def all_helper_methods_info
- @helper_methods.map do |name, helper_class|
- { display_name: name, description: helper_class.description }
- end
- end
- end
-
- # Default helper_methods
- require_relative "helper_method/conf"
- register(:conf, HelperMethod::Conf)
- end
-end
diff --git a/lib/irb/helper_method/base.rb b/lib/irb/helper_method/base.rb
deleted file mode 100644
index a68001ed28..0000000000
--- a/lib/irb/helper_method/base.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require "singleton"
-
-module IRB
- module HelperMethod
- class Base
- include Singleton
-
- class << self
- def description(description = nil)
- @description = description if description
- @description
- end
- end
- end
- end
-end
diff --git a/lib/irb/helper_method/conf.rb b/lib/irb/helper_method/conf.rb
deleted file mode 100644
index 718ed279c0..0000000000
--- a/lib/irb/helper_method/conf.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-module IRB
- module HelperMethod
- class Conf < Base
- description "Returns the current IRB context."
-
- def execute
- IRB.CurrentContext
- end
- end
- end
-end
diff --git a/lib/irb/history.rb b/lib/irb/history.rb
deleted file mode 100644
index 685354b2d8..0000000000
--- a/lib/irb/history.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-require "pathname"
-
-module IRB
- module HistorySavingAbility # :nodoc:
- def support_history_saving?
- true
- end
-
- def reset_history_counter
- @loaded_history_lines = self.class::HISTORY.size
- end
-
- def load_history
- history = self.class::HISTORY
-
- if history_file = IRB.conf[:HISTORY_FILE]
- history_file = File.expand_path(history_file)
- end
- history_file = IRB.rc_file("_history") unless history_file
- if history_file && File.exist?(history_file)
- File.open(history_file, "r:#{IRB.conf[:LC_MESSAGES].encoding}") do |f|
- f.each { |l|
- l = l.chomp
- if self.class == RelineInputMethod and history.last&.end_with?("\\")
- history.last.delete_suffix!("\\")
- history.last << "\n" << l
- else
- history << l
- end
- }
- end
- @loaded_history_lines = history.size
- @loaded_history_mtime = File.mtime(history_file)
- end
- end
-
- def save_history
- history = self.class::HISTORY.to_a
-
- if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) != 0
- if history_file = IRB.conf[:HISTORY_FILE]
- history_file = File.expand_path(history_file)
- end
- history_file = IRB.rc_file("_history") unless history_file
-
- # When HOME and XDG_CONFIG_HOME are not available, history_file might be nil
- return unless history_file
-
- # Change the permission of a file that already exists[BUG #7694]
- begin
- if File.stat(history_file).mode & 066 != 0
- File.chmod(0600, history_file)
- end
- rescue Errno::ENOENT
- rescue Errno::EPERM
- return
- rescue
- raise
- end
-
- if File.exist?(history_file) &&
- File.mtime(history_file) != @loaded_history_mtime
- history = history[@loaded_history_lines..-1] if @loaded_history_lines
- append_history = true
- end
-
- pathname = Pathname.new(history_file)
- unless Dir.exist?(pathname.dirname)
- warn "Warning: The directory to save IRB's history file does not exist. Please double check `IRB.conf[:HISTORY_FILE]`'s value."
- return
- end
-
- File.open(history_file, (append_history ? 'a' : 'w'), 0o600, encoding: IRB.conf[:LC_MESSAGES]&.encoding) do |f|
- hist = history.map{ |l| l.scrub.split("\n").join("\\\n") }
- unless append_history
- begin
- hist = hist.last(num) if hist.size > num and num > 0
- rescue RangeError # bignum too big to convert into `long'
- # Do nothing because the bignum should be treated as infinity
- end
- end
- f.puts(hist)
- end
- end
- end
- end
-end
diff --git a/lib/irb/init.rb b/lib/irb/init.rb
index d474bd41d6..55453cc8f7 100644
--- a/lib/irb/init.rb
+++ b/lib/irb/init.rb
@@ -1,50 +1,16 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/init.rb - irb initialize module
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB # :nodoc:
- @CONF = {}
- @INITIALIZED = false
- # Displays current configuration.
- #
- # Modifying the configuration is achieved by sending a message to IRB.conf.
- #
- # See IRB@Configuration for more information.
- def IRB.conf
- @CONF
- end
-
- def @CONF.inspect
- array = []
- for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name}
- case k
- when :MAIN_CONTEXT, :__TMP__EHV__
- array.push format("CONF[:%s]=...myself...", k.id2name)
- when :PROMPT
- s = v.collect{
- |kk, vv|
- ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"}
- format(":%s=>{%s}", kk.id2name, ss.join(", "))
- }
- array.push format("CONF[:%s]={%s}", k.id2name, s.join(", "))
- else
- array.push format("CONF[:%s]=%s", k.id2name, v.inspect)
- end
- end
- array.join("\n")
- end
-
- # Returns the current version of IRB, including release version and last
- # updated date.
- def IRB.version
- format("irb %s (%s)", @RELEASE_VERSION, @LAST_UPDATE_DATE)
- end
-
- def IRB.initialized?
- !!@INITIALIZED
- end
# initialize config
def IRB.setup(ap_path, argv: ::ARGV)
@@ -52,22 +18,22 @@ module IRB # :nodoc:
IRB.init_error
IRB.parse_opts(argv: argv)
IRB.run_config
- IRB.validate_config
IRB.load_modules
unless @CONF[:PROMPT][@CONF[:PROMPT_MODE]]
fail UndefinedPromptMode, @CONF[:PROMPT_MODE]
end
- @INITIALIZED = true
end
# @CONF default setting
def IRB.init_config(ap_path)
+ # class instance variables
+ @TRACER_INITIALIZED = false
+
# default configurations
unless ap_path and @CONF[:AP_NAME]
ap_path = File.join(File.dirname(File.dirname(__FILE__)), "irb.rb")
end
- @CONF[:VERSION] = version
@CONF[:AP_NAME] = File::basename(ap_path, ".rb")
@CONF[:IRB_NAME] = "irb"
@@ -80,13 +46,11 @@ module IRB # :nodoc:
@CONF[:USE_SINGLELINE] = false unless defined?(ReadlineInputMethod)
@CONF[:USE_COLORIZE] = (nc = ENV['NO_COLOR']).nil? || nc.empty?
@CONF[:USE_AUTOCOMPLETE] = ENV.fetch("IRB_USE_AUTOCOMPLETE", "true") != "false"
- @CONF[:COMPLETOR] = ENV["IRB_COMPLETOR"]&.to_sym
@CONF[:INSPECT_MODE] = true
@CONF[:USE_TRACER] = false
@CONF[:USE_LOADER] = false
@CONF[:IGNORE_SIGINT] = true
@CONF[:IGNORE_EOF] = false
- @CONF[:USE_PAGER] = true
@CONF[:EXTRA_DOC_DIRS] = []
@CONF[:ECHO] = nil
@CONF[:ECHO_ON_ASSIGNMENT] = nil
@@ -100,30 +64,35 @@ module IRB # :nodoc:
@CONF[:PROMPT] = {
:NULL => {
:PROMPT_I => nil,
+ :PROMPT_N => nil,
:PROMPT_S => nil,
:PROMPT_C => nil,
:RETURN => "%s\n"
},
:DEFAULT => {
- :PROMPT_I => "%N(%m):%03n> ",
- :PROMPT_S => "%N(%m):%03n%l ",
- :PROMPT_C => "%N(%m):%03n* ",
+ :PROMPT_I => "%N(%m):%03n:%i> ",
+ :PROMPT_N => "%N(%m):%03n:%i> ",
+ :PROMPT_S => "%N(%m):%03n:%i%l ",
+ :PROMPT_C => "%N(%m):%03n:%i* ",
:RETURN => "=> %s\n"
},
:CLASSIC => {
:PROMPT_I => "%N(%m):%03n:%i> ",
+ :PROMPT_N => "%N(%m):%03n:%i> ",
:PROMPT_S => "%N(%m):%03n:%i%l ",
:PROMPT_C => "%N(%m):%03n:%i* ",
:RETURN => "%s\n"
},
:SIMPLE => {
:PROMPT_I => ">> ",
+ :PROMPT_N => ">> ",
:PROMPT_S => "%l> ",
:PROMPT_C => "?> ",
:RETURN => "=> %s\n"
},
:INF_RUBY => {
- :PROMPT_I => "%N(%m):%03n> ",
+ :PROMPT_I => "%N(%m):%03n:%i> ",
+ :PROMPT_N => nil,
:PROMPT_S => nil,
:PROMPT_C => nil,
:RETURN => "%s\n",
@@ -131,6 +100,7 @@ module IRB # :nodoc:
},
:XMP => {
:PROMPT_I => nil,
+ :PROMPT_N => nil,
:PROMPT_S => nil,
:PROMPT_C => nil,
:RETURN => " ==>%s\n"
@@ -193,6 +163,10 @@ module IRB # :nodoc:
# Symbol aliases
:'$' => :show_source,
:'@' => :whereami,
+ # Keyword aliases
+ :break => :irb_break,
+ :catch => :irb_catch,
+ :next => :irb_next,
}
end
@@ -219,7 +193,6 @@ module IRB # :nodoc:
added = [:TIME, IRB.conf[:MEASURE_PROC][:TIME], arg]
end
if added
- IRB.conf[:MEASURE] = true
found = IRB.conf[:MEASURE_CALLBACKS].find{ |m| m[0] == added[0] && m[2] == added[2] }
if found
# already added
@@ -240,7 +213,6 @@ module IRB # :nodoc:
type_sym = type.upcase.to_sym
IRB.conf[:MEASURE_CALLBACKS].reject!{ |t, | t == type_sym }
end
- IRB.conf[:MEASURE] = nil if IRB.conf[:MEASURE_CALLBACKS].empty?
end
def IRB.init_error
@@ -288,8 +260,6 @@ module IRB # :nodoc:
end
when "--noinspect"
@CONF[:INSPECT_MODE] = false
- when "--no-pager"
- @CONF[:USE_PAGER] = false
when "--singleline", "--readline", "--legacy"
@CONF[:USE_SINGLELINE] = true
when "--nosingleline", "--noreadline"
@@ -335,10 +305,6 @@ module IRB # :nodoc:
@CONF[:USE_AUTOCOMPLETE] = true
when "--noautocomplete"
@CONF[:USE_AUTOCOMPLETE] = false
- when "--regexp-completor"
- @CONF[:COMPLETOR] = :regexp
- when "--type-completor"
- @CONF[:COMPLETOR] = :type
when /^--prompt-mode(?:=(.+))?/, /^--prompt(?:=(.+))?/
opt = $1 || argv.shift
prompt_mode = opt.upcase.tr("-", "_").intern
@@ -393,73 +359,61 @@ module IRB # :nodoc:
$LOAD_PATH.unshift(*load_path)
end
- # Run the config file
+ # running config
def IRB.run_config
if @CONF[:RC]
- irbrc_files.each do |rc|
- load rc
- rescue StandardError, ScriptError => e
- warn "Error loading RC file '#{rc}':\n#{e.full_message(highlight: false)}"
+ begin
+ load rc_file
+ rescue LoadError, Errno::ENOENT
+ rescue # StandardError, ScriptError
+ print "load error: #{rc_file}\n"
+ print $!.class, ": ", $!, "\n"
+ for err in $@[0, $@.size - 2]
+ print "\t", err, "\n"
+ end
end
end
end
IRBRC_EXT = "rc"
-
- def IRB.rc_file(ext)
- prepare_irbrc_name_generators
-
- # When irbrc exist in default location
- if (rcgen = @existing_rc_name_generators.first)
- return rcgen.call(ext)
+ def IRB.rc_file(ext = IRBRC_EXT)
+ if !@CONF[:RC_NAME_GENERATOR]
+ rc_file_generators do |rcgen|
+ @CONF[:RC_NAME_GENERATOR] ||= rcgen
+ if File.exist?(rcgen.call(IRBRC_EXT))
+ @CONF[:RC_NAME_GENERATOR] = rcgen
+ break
+ end
+ end
end
-
- # When irbrc does not exist in default location
- rc_file_generators do |rcgen|
- return rcgen.call(ext)
+ case rc_file = @CONF[:RC_NAME_GENERATOR].call(ext)
+ when String
+ return rc_file
+ else
+ fail IllegalRCNameGenerator
end
-
- # When HOME and XDG_CONFIG_HOME are not available
- nil
end
- def IRB.irbrc_files
- prepare_irbrc_name_generators
- @irbrc_files
- end
-
- def IRB.validate_config
- conf[:IRB_NAME] = conf[:IRB_NAME].to_s
-
- irb_rc = conf[:IRB_RC]
- unless irb_rc.nil? || irb_rc.respond_to?(:call)
- raise_validation_error "IRB.conf[:IRB_RC] should be a callable object. Got #{irb_rc.inspect}."
- end
-
- back_trace_limit = conf[:BACK_TRACE_LIMIT]
- unless back_trace_limit.is_a?(Integer)
- raise_validation_error "IRB.conf[:BACK_TRACE_LIMIT] should be an integer. Got #{back_trace_limit.inspect}."
+ # enumerate possible rc-file base name generators
+ def IRB.rc_file_generators
+ if irbrc = ENV["IRBRC"]
+ yield proc{|rc| rc == "rc" ? irbrc : irbrc+rc}
end
-
- prompt = conf[:PROMPT]
- unless prompt.is_a?(Hash)
- msg = "IRB.conf[:PROMPT] should be a Hash. Got #{prompt.inspect}."
-
- if prompt.is_a?(Symbol)
- msg += " Did you mean to set `IRB.conf[:PROMPT_MODE]`?"
+ if xdg_config_home = ENV["XDG_CONFIG_HOME"]
+ irb_home = File.join(xdg_config_home, "irb")
+ if File.directory?(irb_home)
+ yield proc{|rc| irb_home + "/irb#{rc}"}
end
-
- raise_validation_error msg
end
-
- eval_history = conf[:EVAL_HISTORY]
- unless eval_history.nil? || eval_history.is_a?(Integer)
- raise_validation_error "IRB.conf[:EVAL_HISTORY] should be an integer. Got #{eval_history.inspect}."
+ if home = ENV["HOME"]
+ yield proc{|rc| home+"/.irb#{rc}"}
end
- end
-
- def IRB.raise_validation_error(msg)
- raise TypeError, msg, @irbrc_files
+ current_dir = Dir.pwd
+ yield proc{|rc| current_dir+"/.config/irb/irb#{rc}"}
+ yield proc{|rc| current_dir+"/.irb#{rc}"}
+ yield proc{|rc| current_dir+"/irb#{rc.sub(/\A_?/, '.')}"}
+ yield proc{|rc| current_dir+"/_irb#{rc}"}
+ yield proc{|rc| current_dir+"/$irb#{rc}"}
end
# loading modules
@@ -473,52 +427,10 @@ module IRB # :nodoc:
end
end
+
+ DefaultEncodings = Struct.new(:external, :internal)
class << IRB
private
-
- def prepare_irbrc_name_generators
- return if @existing_rc_name_generators
-
- @existing_rc_name_generators = []
- @irbrc_files = []
- rc_file_generators do |rcgen|
- irbrc = rcgen.call(IRBRC_EXT)
- if File.exist?(irbrc)
- @irbrc_files << irbrc
- @existing_rc_name_generators << rcgen
- end
- end
- generate_current_dir_irbrc_files.each do |irbrc|
- @irbrc_files << irbrc if File.exist?(irbrc)
- end
- @irbrc_files.uniq!
- end
-
- # enumerate possible rc-file base name generators
- def rc_file_generators
- if irbrc = ENV["IRBRC"]
- yield proc{|rc| rc == "rc" ? irbrc : irbrc+rc}
- end
- if xdg_config_home = ENV["XDG_CONFIG_HOME"]
- irb_home = File.join(xdg_config_home, "irb")
- if File.directory?(irb_home)
- yield proc{|rc| irb_home + "/irb#{rc}"}
- end
- end
- if home = ENV["HOME"]
- yield proc{|rc| home+"/.irb#{rc}"}
- if xdg_config_home.nil? || xdg_config_home.empty?
- yield proc{|rc| home+"/.config/irb/irb#{rc}"}
- end
- end
- end
-
- # possible irbrc files in current directory
- def generate_current_dir_irbrc_files
- current_dir = Dir.pwd
- %w[.irbrc irbrc _irbrc $irbrc].map { |file| "#{current_dir}/#{file}" }
- end
-
def set_encoding(extern, intern = nil, override: true)
verbose, $VERBOSE = $VERBOSE, nil
Encoding.default_external = extern unless extern.nil? || extern.empty?
diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb
index 210d3da789..9480573195 100644
--- a/lib/irb/input-method.rb
+++ b/lib/irb/input-method.rb
@@ -1,17 +1,30 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/input-method.rb - input methods used irb
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-
+# --
+#
+#
+#
+require_relative 'src_encoding'
+require_relative 'magic-file'
require_relative 'completion'
-require_relative "history"
require 'io/console'
require 'reline'
module IRB
+ STDIN_FILE_NAME = "(line)" # :nodoc:
class InputMethod
- BASIC_WORD_BREAK_CHARACTERS = " \t\n`><=;|&{("
+
+ # Creates a new input method object
+ def initialize(file = STDIN_FILE_NAME)
+ @file_name = file
+ end
+ # The file name of this input method, usually given during initialization.
+ attr_reader :file_name
# The irb prompt associated with this input method
attr_accessor :prompt
@@ -20,7 +33,7 @@ module IRB
#
# See IO#gets for more information.
def gets
- fail NotImplementedError
+ fail NotImplementedError, "gets"
end
public :gets
@@ -40,14 +53,6 @@ module IRB
false
end
- def support_history_saving?
- false
- end
-
- def prompting?
- false
- end
-
# For debug message
def inspect
'Abstract InputMethod'
@@ -57,6 +62,7 @@ module IRB
class StdioInputMethod < InputMethod
# Creates a new input method object
def initialize
+ super
@line_no = 0
@line = []
@stdin = IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
@@ -67,7 +73,6 @@ module IRB
#
# See IO#gets for more information.
def gets
- puts if @stdout.tty? # workaround for debug compatibility test
print @prompt
line = @stdin.gets
@line[@line_no += 1] = line
@@ -96,10 +101,6 @@ module IRB
true
end
- def prompting?
- STDIN.tty?
- end
-
# Returns the current line number for #io.
#
# #line counts the number of times #gets is called.
@@ -135,9 +136,12 @@ module IRB
# Creates a new input method object
def initialize(file)
- @io = file.is_a?(IO) ? file : File.open(file)
+ super
+ @io = file.is_a?(IO) ? file : IRB::MagicFile.open(file)
@external_encoding = @io.external_encoding
end
+ # The file name of this input method, usually given during initialization.
+ attr_reader :file_name
# Whether the end of this input method has been reached, returns +true+ if
# there is no more data to read.
@@ -170,121 +174,138 @@ module IRB
end
end
- class ReadlineInputMethod < StdioInputMethod
- class << self
- def initialize_readline
+ begin
+ class ReadlineInputMethod < InputMethod
+ def self.initialize_readline
require "readline"
rescue LoadError
else
include ::Readline
end
- end
- include HistorySavingAbility
+ # Creates a new input method object using Readline
+ def initialize
+ self.class.initialize_readline
+ if Readline.respond_to?(:encoding_system_needs)
+ IRB.__send__(:set_encoding, Readline.encoding_system_needs.name, override: false)
+ end
+ super
- # Creates a new input method object using Readline
- def initialize
- self.class.initialize_readline
- if Readline.respond_to?(:encoding_system_needs)
- IRB.__send__(:set_encoding, Readline.encoding_system_needs.name, override: false)
- end
+ @line_no = 0
+ @line = []
+ @eof = false
- super
+ @stdin = IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
+ @stdout = IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
- @eof = false
- @completor = RegexpCompletor.new
+ if Readline.respond_to?("basic_word_break_characters=")
+ Readline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS
+ end
+ Readline.completion_append_character = nil
+ Readline.completion_proc = IRB::InputCompletor::CompletionProc
+ end
- if Readline.respond_to?("basic_word_break_characters=")
- Readline.basic_word_break_characters = BASIC_WORD_BREAK_CHARACTERS
+ # Reads the next line from this input method.
+ #
+ # See IO#gets for more information.
+ def gets
+ Readline.input = @stdin
+ Readline.output = @stdout
+ if l = readline(@prompt, false)
+ HISTORY.push(l) if !l.empty?
+ @line[@line_no += 1] = l + "\n"
+ else
+ @eof = true
+ l
+ end
end
- Readline.completion_append_character = nil
- Readline.completion_proc = ->(target) {
- bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
- @completor.completion_candidates('', target, '', bind: bind)
- }
- end
- def completion_info
- 'RegexpCompletor'
- end
+ # Whether the end of this input method has been reached, returns +true+
+ # if there is no more data to read.
+ #
+ # See IO#eof? for more information.
+ def eof?
+ @eof
+ end
- # Reads the next line from this input method.
- #
- # See IO#gets for more information.
- def gets
- Readline.input = @stdin
- Readline.output = @stdout
- if l = readline(@prompt, false)
- HISTORY.push(l) if !l.empty?
- @line[@line_no += 1] = l + "\n"
- else
- @eof = true
- l
+ # Whether this input method is still readable when there is no more data to
+ # read.
+ #
+ # See IO#eof for more information.
+ def readable_after_eof?
+ true
end
- end
- # Whether the end of this input method has been reached, returns +true+
- # if there is no more data to read.
- #
- # See IO#eof? for more information.
- def eof?
- @eof
- end
+ # Returns the current line number for #io.
+ #
+ # #line counts the number of times #gets is called.
+ #
+ # See IO#lineno for more information.
+ def line(line_no)
+ @line[line_no]
+ end
- def prompting?
- true
- end
+ # The external encoding for standard input.
+ def encoding
+ @stdin.external_encoding
+ end
- # For debug message
- def inspect
- readline_impl = (defined?(Reline) && Readline == Reline) ? 'Reline' : 'ext/readline'
- str = "ReadlineInputMethod with #{readline_impl} #{Readline::VERSION}"
- inputrc_path = File.expand_path(ENV['INPUTRC'] || '~/.inputrc')
- str += " and #{inputrc_path}" if File.exist?(inputrc_path)
- str
+ # For debug message
+ def inspect
+ readline_impl = (defined?(Reline) && Readline == Reline) ? 'Reline' : 'ext/readline'
+ str = "ReadlineInputMethod with #{readline_impl} #{Readline::VERSION}"
+ inputrc_path = File.expand_path(ENV['INPUTRC'] || '~/.inputrc')
+ str += " and #{inputrc_path}" if File.exist?(inputrc_path)
+ str
+ end
end
end
- class RelineInputMethod < StdioInputMethod
- HISTORY = Reline::HISTORY
- include HistorySavingAbility
+ class RelineInputMethod < InputMethod
+ include Reline
+
# Creates a new input method object using Reline
- def initialize(completor)
+ def initialize
IRB.__send__(:set_encoding, Reline.encoding_system_needs.name, override: false)
+ super
- super()
-
+ @line_no = 0
+ @line = []
@eof = false
- @completor = completor
- Reline.basic_word_break_characters = BASIC_WORD_BREAK_CHARACTERS
+ @stdin = ::IO.open(STDIN.to_i, :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
+ @stdout = ::IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
+
+ if Reline.respond_to?("basic_word_break_characters=")
+ Reline.basic_word_break_characters = IRB::InputCompletor::BASIC_WORD_BREAK_CHARACTERS
+ end
Reline.completion_append_character = nil
Reline.completer_quote_characters = ''
- Reline.completion_proc = ->(target, preposing, postposing) {
- bind = IRB.conf[:MAIN_CONTEXT].workspace.binding
- @completion_params = [preposing, target, postposing, bind]
- @completor.completion_candidates(preposing, target, postposing, bind: bind)
- }
- Reline.output_modifier_proc = proc do |input, complete:|
- IRB.CurrentContext.colorize_input(input, complete: complete)
- end
- Reline.dig_perfect_match_proc = ->(matched) { display_document(matched) }
+ Reline.completion_proc = IRB::InputCompletor::CompletionProc
+ Reline.output_modifier_proc =
+ if IRB.conf[:USE_COLORIZE]
+ proc do |output, complete: |
+ next unless IRB::Color.colorable?
+ lvars = IRB.CurrentContext&.local_variables || []
+ IRB::Color.colorize_code(output, complete: complete, local_variables: lvars)
+ end
+ else
+ proc do |output|
+ Reline::Unicode.escape_for_print(output)
+ end
+ end
+ Reline.dig_perfect_match_proc = IRB::InputCompletor::PerfectMatchedProc
Reline.autocompletion = IRB.conf[:USE_AUTOCOMPLETE]
if IRB.conf[:USE_AUTOCOMPLETE]
begin
require 'rdoc'
- Reline.add_dialog_proc(:show_doc, show_doc_dialog_proc, Reline::DEFAULT_DIALOG_CONTEXT)
+ Reline.add_dialog_proc(:show_doc, SHOW_DOC_DIALOG, Reline::DEFAULT_DIALOG_CONTEXT)
rescue LoadError
end
end
end
- def completion_info
- autocomplete_message = Reline.autocompletion ? 'Autocomplete' : 'Tab Complete'
- "#{autocomplete_message}, #{@completor.inspect}"
- end
-
def check_termination(&block)
@check_termination_proc = block
end
@@ -297,165 +318,98 @@ module IRB
@auto_indent_proc = block
end
- def retrieve_doc_namespace(matched)
- preposing, _target, postposing, bind = @completion_params
- @completor.doc_namespace(preposing, matched, postposing, bind: bind)
- end
+ SHOW_DOC_DIALOG = ->() {
+ dialog.trap_key = nil
+ alt_d = [
+ [Reline::Key.new(nil, 0xE4, true)], # Normal Alt+d.
+ [27, 100], # Normal Alt+d when convert-meta isn't used.
+ [195, 164], # The "ä" that appears when Alt+d is pressed on xterm.
+ [226, 136, 130] # The "∂" that appears when Alt+d in pressed on iTerm2.
+ ]
- def rdoc_ri_driver
- return @rdoc_ri_driver if defined?(@rdoc_ri_driver)
-
- begin
- require 'rdoc'
- rescue LoadError
- @rdoc_ri_driver = nil
- else
- options = {}
- options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty?
- @rdoc_ri_driver = RDoc::RI::Driver.new(options)
+ if just_cursor_moving and completion_journey_data.nil?
+ return nil
end
- end
-
- def show_doc_dialog_proc
- input_method = self # self is changed in the lambda below.
- ->() {
- dialog.trap_key = nil
- alt_d = [
- [27, 100], # Normal Alt+d when convert-meta isn't used.
- # When option/alt is not configured as a meta key in terminal emulator,
- # option/alt + d will send a unicode character depend on OS keyboard setting.
- [195, 164], # "ä" in somewhere (FIXME: environment information is unknown).
- [226, 136, 130] # "∂" Alt+d on Mac keyboard.
- ]
-
- if just_cursor_moving and completion_journey_data.nil?
- return nil
- end
- cursor_pos_to_render, result, pointer, autocomplete_dialog = context.pop(4)
- return nil if result.nil? or pointer.nil? or pointer < 0
-
- name = input_method.retrieve_doc_namespace(result[pointer])
- # Use first one because document dialog does not support multiple namespaces.
- name = name.first if name.is_a?(Array)
+ cursor_pos_to_render, result, pointer, autocomplete_dialog = context.pop(4)
+ return nil if result.nil? or pointer.nil? or pointer < 0
+ name = result[pointer]
+ name = IRB::InputCompletor.retrieve_completion_data(name, doc_namespace: true)
- show_easter_egg = name&.match?(/\ARubyVM/) && !ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
+ options = {}
+ options[:extra_doc_dirs] = IRB.conf[:EXTRA_DOC_DIRS] unless IRB.conf[:EXTRA_DOC_DIRS].empty?
+ driver = RDoc::RI::Driver.new(options)
- driver = input_method.rdoc_ri_driver
-
- if key.match?(dialog.name)
- if show_easter_egg
- IRB.__send__(:easter_egg)
- else
- begin
- driver.display_names([name])
- rescue RDoc::RI::Driver::NotFoundError
- end
- end
+ if key.match?(dialog.name)
+ begin
+ driver.display_names([name])
+ rescue RDoc::RI::Driver::NotFoundError
end
+ end
+ begin
+ name = driver.expand_name(name)
+ rescue RDoc::RI::Driver::NotFoundError
+ return nil
+ rescue
+ return nil # unknown error
+ end
+ doc = nil
+ used_for_class = false
+ if not name =~ /#|\./
+ found, klasses, includes, extends = driver.classes_and_includes_and_extends_for(name)
+ if not found.empty?
+ doc = driver.class_document(name, found, klasses, includes, extends)
+ used_for_class = true
+ end
+ end
+ unless used_for_class
+ doc = RDoc::Markup::Document.new
begin
- name = driver.expand_name(name)
+ driver.add_method(doc, name)
rescue RDoc::RI::Driver::NotFoundError
- return nil
+ doc = nil
rescue
return nil # unknown error
end
- doc = nil
- used_for_class = false
- if not name =~ /#|\./
- found, klasses, includes, extends = driver.classes_and_includes_and_extends_for(name)
- if not found.empty?
- doc = driver.class_document(name, found, klasses, includes, extends)
- used_for_class = true
- end
- end
- unless used_for_class
- doc = RDoc::Markup::Document.new
- begin
- driver.add_method(doc, name)
- rescue RDoc::RI::Driver::NotFoundError
- doc = nil
- rescue
- return nil # unknown error
- end
- end
- return nil if doc.nil?
- width = 40
-
- right_x = cursor_pos_to_render.x + autocomplete_dialog.width
- if right_x + width > screen_width
- right_width = screen_width - (right_x + 1)
- left_x = autocomplete_dialog.column - width
- left_x = 0 if left_x < 0
- left_width = width > autocomplete_dialog.column ? autocomplete_dialog.column : width
- if right_width.positive? and left_width.positive?
- if right_width >= left_width
- width = right_width
- x = right_x
- else
- width = left_width
- x = left_x
- end
- elsif right_width.positive? and left_width <= 0
+ end
+ return nil if doc.nil?
+ width = 40
+
+ right_x = cursor_pos_to_render.x + autocomplete_dialog.width
+ if right_x + width > screen_width
+ right_width = screen_width - (right_x + 1)
+ left_x = autocomplete_dialog.column - width
+ left_x = 0 if left_x < 0
+ left_width = width > autocomplete_dialog.column ? autocomplete_dialog.column : width
+ if right_width.positive? and left_width.positive?
+ if right_width >= left_width
width = right_width
x = right_x
- elsif right_width <= 0 and left_width.positive?
+ else
width = left_width
x = left_x
- else # Both are negative width.
- return nil
end
- else
+ elsif right_width.positive? and left_width <= 0
+ width = right_width
x = right_x
+ elsif right_width <= 0 and left_width.positive?
+ width = left_width
+ x = left_x
+ else # Both are negative width.
+ return nil
end
- formatter = RDoc::Markup::ToAnsi.new
- formatter.width = width
- dialog.trap_key = alt_d
- mod_key = RUBY_PLATFORM.match?(/darwin/) ? "Option" : "Alt"
- if show_easter_egg
- type = STDOUT.external_encoding == Encoding::UTF_8 ? :unicode : :ascii
- contents = IRB.send(:easter_egg_logo, type).split("\n")
- message = "Press #{mod_key}+d to see more"
- contents[0][0, message.size] = message
- else
- message = "Press #{mod_key}+d to read the full document"
- contents = [message] + doc.accept(formatter).split("\n")
- end
- contents = contents.take(preferred_dialog_height)
-
- y = cursor_pos_to_render.y
- Reline::DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49')
- }
- end
-
- def display_document(matched)
- driver = rdoc_ri_driver
- return unless driver
-
- if matched =~ /\A(?:::)?RubyVM/ and not ENV['RUBY_YES_I_AM_NOT_A_NORMAL_USER']
- IRB.__send__(:easter_egg)
- return
- end
-
- namespace = retrieve_doc_namespace(matched)
- return unless namespace
-
- if namespace.is_a?(Array)
- out = RDoc::Markup::Document.new
- namespace.each do |m|
- begin
- driver.add_method(out, m)
- rescue RDoc::RI::Driver::NotFoundError
- end
- end
- driver.display(out)
else
- begin
- driver.display_names([namespace])
- rescue RDoc::RI::Driver::NotFoundError
- end
+ x = right_x
end
- end
+ formatter = RDoc::Markup::ToAnsi.new
+ formatter.width = width
+ dialog.trap_key = alt_d
+ message = 'Press Alt+d to read the full document'
+ contents = [message] + doc.accept(formatter).split("\n")
+
+ y = cursor_pos_to_render.y
+ DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49')
+ }
# Reads the next line from this input method.
#
@@ -465,8 +419,8 @@ module IRB
Reline.output = @stdout
Reline.prompt_proc = @prompt_proc
Reline.auto_indent_proc = @auto_indent_proc if @auto_indent_proc
- if l = Reline.readmultiline(@prompt, false, &@check_termination_proc)
- Reline::HISTORY.push(l) if !l.empty?
+ if l = readmultiline(@prompt, false, &@check_termination_proc)
+ HISTORY.push(l) if !l.empty?
@line[@line_no += 1] = l + "\n"
else
@eof = true
@@ -482,15 +436,37 @@ module IRB
@eof
end
- def prompting?
+ # Whether this input method is still readable when there is no more data to
+ # read.
+ #
+ # See IO#eof for more information.
+ def readable_after_eof?
true
end
+ # Returns the current line number for #io.
+ #
+ # #line counts the number of times #gets is called.
+ #
+ # See IO#lineno for more information.
+ def line(line_no)
+ @line[line_no]
+ end
+
+ # The external encoding for standard input.
+ def encoding
+ @stdin.external_encoding
+ end
+
# For debug message
def inspect
config = Reline::Config.new
str = "RelineInputMethod with Reline #{Reline::VERSION}"
- inputrc_path = File.expand_path(config.inputrc_path)
+ if config.respond_to?(:inputrc_path)
+ inputrc_path = File.expand_path(config.inputrc_path)
+ else
+ inputrc_path = File.expand_path(ENV['INPUTRC'] || '~/.inputrc')
+ end
str += " and #{inputrc_path}" if File.exist?(inputrc_path)
str
end
diff --git a/lib/irb/inspector.rb b/lib/irb/inspector.rb
index 8046744f88..d8c0ba90cf 100644
--- a/lib/irb/inspector.rb
+++ b/lib/irb/inspector.rb
@@ -1,11 +1,19 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/inspector.rb - inspect methods
+# $Release Version: 0.9.6$
+# $Revision: 1.19 $
+# $Date: 2002/06/11 07:51:31 $
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB # :nodoc:
+
# Convenience method to create a new Inspector, using the given +inspect+
# proc, and optional +init+ proc and passes them to Inspector.new
#
@@ -34,7 +42,6 @@ module IRB # :nodoc:
# irb(main):001:0> "what?" #=> omg! what?
#
class Inspector
- KERNEL_INSPECT = Object.instance_method(:inspect)
# Default inspectors available to irb, this includes:
#
# +:pp+:: Using Kernel#pretty_inspect
@@ -42,40 +49,38 @@ module IRB # :nodoc:
# +:marshal+:: Using Marshal.dump
INSPECTORS = {}
- class << self
- # Determines the inspector to use where +inspector+ is one of the keys passed
- # during inspector definition.
- def keys_with_inspector(inspector)
- INSPECTORS.select{|k, v| v == inspector}.collect{|k, v| k}
- end
+ # Determines the inspector to use where +inspector+ is one of the keys passed
+ # during inspector definition.
+ def self.keys_with_inspector(inspector)
+ INSPECTORS.select{|k,v| v == inspector}.collect{|k, v| k}
+ end
- # Example
- #
- # Inspector.def_inspector(key, init_p=nil){|v| v.inspect}
- # Inspector.def_inspector([key1,..], init_p=nil){|v| v.inspect}
- # Inspector.def_inspector(key, inspector)
- # Inspector.def_inspector([key1,...], inspector)
- def def_inspector(key, arg=nil, &block)
- if block_given?
- inspector = IRB::Inspector(block, arg)
- else
- inspector = arg
- end
+ # Example
+ #
+ # Inspector.def_inspector(key, init_p=nil){|v| v.inspect}
+ # Inspector.def_inspector([key1,..], init_p=nil){|v| v.inspect}
+ # Inspector.def_inspector(key, inspector)
+ # Inspector.def_inspector([key1,...], inspector)
+ def self.def_inspector(key, arg=nil, &block)
+ if block_given?
+ inspector = IRB::Inspector(block, arg)
+ else
+ inspector = arg
+ end
- case key
- when Array
- for k in key
- def_inspector(k, inspector)
- end
- when Symbol
- INSPECTORS[key] = inspector
- INSPECTORS[key.to_s] = inspector
- when String
- INSPECTORS[key] = inspector
- INSPECTORS[key.intern] = inspector
- else
- INSPECTORS[key] = inspector
+ case key
+ when Array
+ for k in key
+ def_inspector(k, inspector)
end
+ when Symbol
+ INSPECTORS[key] = inspector
+ INSPECTORS[key.to_s] = inspector
+ when String
+ INSPECTORS[key] = inspector
+ INSPECTORS[key.intern] = inspector
+ else
+ INSPECTORS[key] = inspector
end
end
@@ -95,17 +100,9 @@ module IRB # :nodoc:
# Proc to call when the input is evaluated and output in irb.
def inspect_value(v)
@inspect.call(v)
- rescue => e
- puts "An error occurred when inspecting the object: #{e.inspect}"
-
- begin
- puts "Result of Kernel#inspect: #{KERNEL_INSPECT.bind_call(v)}"
- ''
- rescue => e
- puts "An error occurred when running Kernel#inspect: #{e.inspect}"
- puts e.backtrace.join("\n")
- ''
- end
+ rescue
+ puts "(Object doesn't support #inspect)"
+ ''
end
end
@@ -114,7 +111,7 @@ module IRB # :nodoc:
Color.colorize_code(v.inspect, colorable: Color.colorable? && Color.inspect_colorable?(v))
}
Inspector.def_inspector([true, :pp, :pretty_inspect], proc{require_relative "color_printer"}){|v|
- IRB::ColorPrinter.pp(v, +'').chomp
+ IRB::ColorPrinter.pp(v, '').chomp
}
Inspector.def_inspector([:yaml, :YAML], proc{require "yaml"}){|v|
begin
diff --git a/lib/irb/irb.gemspec b/lib/irb/irb.gemspec
index b29002f593..c3e8a4dc58 100644
--- a/lib/irb/irb.gemspec
+++ b/lib/irb/irb.gemspec
@@ -16,11 +16,6 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/ruby/irb"
spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
- spec.metadata["documentation_uri"] = spec.homepage
- spec.metadata["changelog_uri"] = "#{spec.homepage}/releases"
-
spec.files = [
".document",
"Gemfile",
@@ -39,8 +34,7 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7")
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.6")
- spec.add_dependency "reline", ">= 0.4.2"
- spec.add_dependency "rdoc", ">= 4.0.0"
+ spec.add_dependency "reline", ">= 0.3.0"
end
diff --git a/lib/irb/lc/error.rb b/lib/irb/lc/error.rb
index ee0f047822..cb5c21cdb4 100644
--- a/lib/irb/lc/error.rb
+++ b/lib/irb/lc/error.rb
@@ -1,8 +1,14 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/lc/error.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB
# :stopdoc:
@@ -12,6 +18,11 @@ module IRB
super("Unrecognized switch: #{val}")
end
end
+ class NotImplementedError < StandardError
+ def initialize(val)
+ super("Need to define `#{val}'")
+ end
+ end
class CantReturnToNormalMode < StandardError
def initialize
super("Can't return to normal mode.")
@@ -47,6 +58,11 @@ module IRB
super("Undefined prompt mode(#{val}).")
end
end
+ class IllegalRCGenerator < StandardError
+ def initialize
+ super("Define illegal RC_NAME_GENERATOR.")
+ end
+ end
# :startdoc:
end
diff --git a/lib/irb/lc/help-message b/lib/irb/lc/help-message
index 37347306e8..5b23f4c41e 100644
--- a/lib/irb/lc/help-message
+++ b/lib/irb/lc/help-message
@@ -22,18 +22,14 @@ Usage: irb.rb [options] [programfile] [arguments]
Show truncated result on assignment (default).
--inspect Use 'inspect' for output.
--noinspect Don't use 'inspect' for output.
- --no-pager Don't use pager.
- --multiline Use multiline editor module (default).
- --nomultiline Don't use multiline editor module.
+ --multiline Use multiline editor module.
+ --nomultiline Don't use multiline editor module (default).
--singleline Use single line editor module.
--nosingleline Don't use single line editor module (default).
--colorize Use color-highlighting (default).
--nocolorize Don't use color-highlighting.
--autocomplete Use auto-completion (default).
--noautocomplete Don't use auto-completion.
- --regexp-completor
- Use regexp based completion (default).
- --type-completor Use type based completion.
--prompt prompt-mode, --prompt-mode prompt-mode
Set prompt mode. Pre-defined prompt modes are:
'default', 'classic', 'simple', 'inf-ruby', 'xmp', 'null'.
diff --git a/lib/irb/lc/ja/encoding_aliases.rb b/lib/irb/lc/ja/encoding_aliases.rb
new file mode 100644
index 0000000000..08180c3ec2
--- /dev/null
+++ b/lib/irb/lc/ja/encoding_aliases.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: false
+module IRB
+ # :stopdoc:
+
+ class Locale
+ @@legacy_encoding_alias_map = {
+ 'ujis' => Encoding::EUC_JP,
+ 'euc' => Encoding::EUC_JP
+ }.freeze
+ end
+
+ # :startdoc:
+end
diff --git a/lib/irb/lc/ja/error.rb b/lib/irb/lc/ja/error.rb
index 9e2e5b8870..5e3622cbae 100644
--- a/lib/irb/lc/ja/error.rb
+++ b/lib/irb/lc/ja/error.rb
@@ -1,8 +1,14 @@
-# frozen_string_literal: true
-#
+# -*- coding: utf-8 -*-
+# frozen_string_literal: false
# irb/lc/ja/error.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB
# :stopdoc:
@@ -12,6 +18,11 @@ module IRB
super("スイッãƒ(#{val})ãŒåˆ†ã‚Šã¾ã›ã‚“")
end
end
+ class NotImplementedError < StandardError
+ def initialize(val)
+ super("`#{val}'ã®å®šç¾©ãŒå¿…è¦ã§ã™")
+ end
+ end
class CantReturnToNormalMode < StandardError
def initialize
super("Normalãƒ¢ãƒ¼ãƒ‰ã«æˆ»ã‚Œã¾ã›ã‚“.")
@@ -47,6 +58,11 @@ module IRB
super("プロンプトモード(#{val})ã¯å®šç¾©ã•れã¦ã„ã¾ã›ã‚“.")
end
end
+ class IllegalRCGenerator < StandardError
+ def initialize
+ super("RC_NAME_GENERATORãŒæ­£ã—ã定義ã•れã¦ã„ã¾ã›ã‚“.")
+ end
+ end
# :startdoc:
end
diff --git a/lib/irb/lc/ja/help-message b/lib/irb/lc/ja/help-message
index 99f4449b3b..1c15d331ea 100644
--- a/lib/irb/lc/ja/help-message
+++ b/lib/irb/lc/ja/help-message
@@ -9,18 +9,10 @@ Usage: irb.rb [options] [programfile] [arguments]
-W[level=2] ruby -W ã¨åŒã˜.
--context-mode n æ–°ã—ã„ワークスペースを作æˆã—ãŸæ™‚ã«é–¢é€£ã™ã‚‹ Binding
オブジェクトã®ä½œæˆæ–¹æ³•ã‚’ 0 ã‹ã‚‰ 3 ã®ã„ãšã‚Œã‹ã«è¨­å®šã™ã‚‹.
- --extra-doc-dir 指定ã—ãŸãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã‚’追加ã§èª­ã¿è¾¼ã‚€.
--echo å®Ÿè¡Œçµæžœã‚’表示ã™ã‚‹(デフォルト).
--noecho å®Ÿè¡Œçµæžœã‚’表示ã—ãªã„.
- --echo-on-assignment
- ä»£å…¥çµæžœã‚’表示ã™ã‚‹.
- --noecho-on-assignment
- ä»£å…¥çµæžœã‚’表示ã—ãªã„.
- --truncate-echo-on-assignment
- truncateã•れãŸä»£å…¥çµæžœã‚’表示ã™ã‚‹(デフォルト).
--inspect çµæžœå‡ºåŠ›ã«inspectを用ã„ã‚‹.
--noinspect çµæžœå‡ºåŠ›ã«inspectを用ã„ãªã„.
- --no-pager ページャを使用ã—ãªã„.
--multiline マルãƒãƒ©ã‚¤ãƒ³ã‚¨ãƒ‡ã‚£ã‚¿ã‚’利用ã™ã‚‹.
--nomultiline マルãƒãƒ©ã‚¤ãƒ³ã‚¨ãƒ‡ã‚£ã‚¿ã‚’利用ã—ãªã„.
--singleline シングルラインエディタを利用ã™ã‚‹.
@@ -29,9 +21,6 @@ Usage: irb.rb [options] [programfile] [arguments]
--nocolorize 色付ã‘を利用ã—ãªã„.
--autocomplete オートコンプリートを利用ã™ã‚‹.
--noautocomplete オートコンプリートを利用ã—ãªã„.
- --regexp-completor
- è£œå®Œã«æ­£è¦è¡¨ç¾ã‚’利用ã™ã‚‹.
- --type-completor 補完ã«åž‹æƒ…報を利用ã™ã‚‹.
--prompt prompt-mode/--prompt-mode prompt-mode
プロンプトモードを切替ãˆã¾ã™. ç¾åœ¨å®šç¾©ã•れã¦ã„るプ
ロンプトモードã¯, default, simple, xmp, inf-rubyãŒ
@@ -42,8 +31,6 @@ Usage: irb.rb [options] [programfile] [arguments]
--sample-book-mode/--simple-prompt
éžå¸¸ã«ã‚·ãƒ³ãƒ—ルãªãƒ—ロンプトを用ã„るモードã§ã™.
--noprompt プロンプト表示を行ãªã‚ãªã„.
- --script スクリプトモード(最åˆã®å¼•数をスクリプトファイルã¨ã—ã¦æ‰±ã†ã€ãƒ‡ãƒ•ォルト)
- --noscript 引数をargvã¨ã—ã¦æ‰±ã†.
--single-irb irb 中㧠self を実行ã—ã¦å¾—られるオブジェクトをサ
ブ irb ã¨å…±æœ‰ã™ã‚‹.
--tracer コマンド実行時ã«ãƒˆãƒ¬ãƒ¼ã‚¹ã‚’行ãªã†.
diff --git a/lib/irb/locale.rb b/lib/irb/locale.rb
index 2abcc7354b..bb44b41002 100644
--- a/lib/irb/locale.rb
+++ b/lib/irb/locale.rb
@@ -1,9 +1,14 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/locale.rb - internationalization module
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-
+# --
+#
+#
+#
module IRB # :nodoc:
class Locale
@@ -15,11 +20,7 @@ module IRB # :nodoc:
]x
LOCALE_DIR = "/lc/"
- LEGACY_ENCODING_ALIAS_MAP = {
- 'ujis' => Encoding::EUC_JP,
- 'euc' => Encoding::EUC_JP
- }
-
+ @@legacy_encoding_alias_map = {}.freeze
@@loaded = []
def initialize(locale = nil)
@@ -30,11 +31,11 @@ module IRB # :nodoc:
@lang, @territory, @encoding_name, @modifier = m[:language], m[:territory], m[:codeset], m[:modifier]
if @encoding_name
- if @encoding = LEGACY_ENCODING_ALIAS_MAP[@encoding_name]
+ begin load 'irb/encoding_aliases.rb'; rescue LoadError; end
+ if @encoding = @@legacy_encoding_alias_map[@encoding_name]
warn(("%s is obsolete. use %s" % ["#{@lang}_#{@territory}.#{@encoding_name}", "#{@lang}_#{@territory}.#{@encoding.name}"]), uplevel: 1)
- else
- @encoding = Encoding.find(@encoding_name) rescue nil
end
+ @encoding = Encoding.find(@encoding_name) rescue nil
end
end
@encoding ||= (Encoding.find('locale') rescue Encoding::ASCII_8BIT)
@@ -82,19 +83,46 @@ module IRB # :nodoc:
super(*ary)
end
- def load(file)
+ def require(file, priv = nil)
+ rex = Regexp.new("lc/#{Regexp.quote(file)}\.(so|o|sl|rb)?")
+ return false if $".find{|f| f =~ rex}
+
+ case file
+ when /\.rb$/
+ begin
+ load(file, priv)
+ $".push file
+ return true
+ rescue LoadError
+ end
+ when /\.(so|o|sl)$/
+ return super
+ end
+
+ begin
+ load(f = file + ".rb")
+ $".push f #"
+ return true
+ rescue LoadError
+ return ruby_require(file)
+ end
+ end
+
+ alias toplevel_load load
+
+ def load(file, priv=nil)
found = find(file)
if found
unless @@loaded.include?(found)
@@loaded << found # cache
- Kernel.load(found)
+ return real_load(found, priv)
end
else
raise LoadError, "No such file to load -- #{file}"
end
end
- def find(file, paths = $:)
+ def find(file , paths = $:)
dir = File.dirname(file)
dir = "" if dir == "."
base = File.basename(file)
@@ -106,6 +134,16 @@ module IRB # :nodoc:
end
end
+ private
+ def real_load(path, priv)
+ src = MagicFile.open(path){|f| f.read}
+ if priv
+ eval("self", TOPLEVEL_BINDING).extend(Module.new {eval(src, nil, path)})
+ else
+ eval(src, TOPLEVEL_BINDING, path)
+ end
+ end
+
# @param paths load paths in which IRB find a localized file.
# @param dir directory
# @param file basename to be localized
diff --git a/lib/irb/magic-file.rb b/lib/irb/magic-file.rb
new file mode 100644
index 0000000000..34e06d64b3
--- /dev/null
+++ b/lib/irb/magic-file.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: false
+module IRB
+ class << (MagicFile = Object.new)
+ # see parser_magic_comment in parse.y
+ ENCODING_SPEC_RE = %r"coding\s*[=:]\s*([[:alnum:]\-_]+)"
+
+ def open(path)
+ io = File.open(path, 'rb')
+ line = io.gets
+ line = io.gets if line[0,2] == "#!"
+ encoding = detect_encoding(line)
+ internal_encoding = encoding
+ encoding ||= IRB.default_src_encoding
+ io.rewind
+ io.set_encoding(encoding, internal_encoding)
+
+ if block_given?
+ begin
+ return (yield io)
+ ensure
+ io.close
+ end
+ else
+ return io
+ end
+ end
+
+ private
+ def detect_encoding(line)
+ return unless line[0] == ?#
+ line = line[1..-1]
+ line = $1 if line[/-\*-\s*(.*?)\s*-*-$/]
+ return nil unless ENCODING_SPEC_RE =~ line
+ encoding = $1
+ return encoding.sub(/-(?:mac|dos|unix)/i, '')
+ end
+ end
+end
diff --git a/lib/irb/nesting_parser.rb b/lib/irb/nesting_parser.rb
deleted file mode 100644
index fc71d64aee..0000000000
--- a/lib/irb/nesting_parser.rb
+++ /dev/null
@@ -1,239 +0,0 @@
-# frozen_string_literal: true
-module IRB
- module NestingParser
- IGNORE_TOKENS = %i[on_sp on_ignored_nl on_comment on_embdoc_beg on_embdoc on_embdoc_end]
-
- class << self
- # Scan each token and call the given block with array of token and other information for parsing
- def scan_opens(tokens)
- opens = []
- pending_heredocs = []
- first_token_on_line = true
- tokens.each do |t|
- skip = false
- last_tok, state, args = opens.last
- case state
- when :in_alias_undef
- skip = t.event == :on_kw
- when :in_unquoted_symbol
- unless IGNORE_TOKENS.include?(t.event)
- opens.pop
- skip = true
- end
- when :in_lambda_head
- opens.pop if t.event == :on_tlambeg || (t.event == :on_kw && t.tok == 'do')
- when :in_method_head
- unless IGNORE_TOKENS.include?(t.event)
- next_args = []
- body = nil
- if args.include?(:receiver)
- case t.event
- when :on_lparen, :on_ivar, :on_gvar, :on_cvar
- # def (receiver). | def @ivar. | def $gvar. | def @@cvar.
- next_args << :dot
- when :on_kw
- case t.tok
- when 'self', 'true', 'false', 'nil'
- # def self(arg) | def self.
- next_args.push(:arg, :dot)
- else
- # def if(arg)
- skip = true
- next_args << :arg
- end
- when :on_op, :on_backtick
- # def +(arg)
- skip = true
- next_args << :arg
- when :on_ident, :on_const
- # def a(arg) | def a.
- next_args.push(:arg, :dot)
- end
- end
- if args.include?(:dot)
- # def receiver.name
- next_args << :name if t.event == :on_period || (t.event == :on_op && t.tok == '::')
- end
- if args.include?(:name)
- if %i[on_ident on_const on_op on_kw on_backtick].include?(t.event)
- # def name(arg) | def receiver.name(arg)
- next_args << :arg
- skip = true
- end
- end
- if args.include?(:arg)
- case t.event
- when :on_nl, :on_semicolon
- # def receiver.f;
- body = :normal
- when :on_lparen
- # def receiver.f()
- next_args << :eq
- else
- if t.event == :on_op && t.tok == '='
- # def receiver.f =
- body = :oneliner
- else
- # def receiver.f arg
- next_args << :arg_without_paren
- end
- end
- end
- if args.include?(:eq)
- if t.event == :on_op && t.tok == '='
- body = :oneliner
- else
- body = :normal
- end
- end
- if args.include?(:arg_without_paren)
- if %i[on_semicolon on_nl].include?(t.event)
- # def f a;
- body = :normal
- else
- # def f a, b
- next_args << :arg_without_paren
- end
- end
- if body == :oneliner
- opens.pop
- elsif body
- opens[-1] = [last_tok, nil]
- else
- opens[-1] = [last_tok, :in_method_head, next_args]
- end
- end
- when :in_for_while_until_condition
- if t.event == :on_semicolon || t.event == :on_nl || (t.event == :on_kw && t.tok == 'do')
- skip = true if t.event == :on_kw && t.tok == 'do'
- opens[-1] = [last_tok, nil]
- end
- end
-
- unless skip
- case t.event
- when :on_kw
- case t.tok
- when 'begin', 'class', 'module', 'do', 'case'
- opens << [t, nil]
- when 'end'
- opens.pop
- when 'def'
- opens << [t, :in_method_head, [:receiver, :name]]
- when 'if', 'unless'
- unless t.state.allbits?(Ripper::EXPR_LABEL)
- opens << [t, nil]
- end
- when 'while', 'until'
- unless t.state.allbits?(Ripper::EXPR_LABEL)
- opens << [t, :in_for_while_until_condition]
- end
- when 'ensure', 'rescue'
- unless t.state.allbits?(Ripper::EXPR_LABEL)
- opens.pop
- opens << [t, nil]
- end
- when 'alias'
- opens << [t, :in_alias_undef, 2]
- when 'undef'
- opens << [t, :in_alias_undef, 1]
- when 'elsif', 'else', 'when'
- opens.pop
- opens << [t, nil]
- when 'for'
- opens << [t, :in_for_while_until_condition]
- when 'in'
- if last_tok&.event == :on_kw && %w[case in].include?(last_tok.tok) && first_token_on_line
- opens.pop
- opens << [t, nil]
- end
- end
- when :on_tlambda
- opens << [t, :in_lambda_head]
- when :on_lparen, :on_lbracket, :on_lbrace, :on_tlambeg, :on_embexpr_beg, :on_embdoc_beg
- opens << [t, nil]
- when :on_rparen, :on_rbracket, :on_rbrace, :on_embexpr_end, :on_embdoc_end
- opens.pop
- when :on_heredoc_beg
- pending_heredocs << t
- when :on_heredoc_end
- opens.pop
- when :on_backtick
- opens << [t, nil] if t.state.allbits?(Ripper::EXPR_BEG)
- when :on_tstring_beg, :on_words_beg, :on_qwords_beg, :on_symbols_beg, :on_qsymbols_beg, :on_regexp_beg
- opens << [t, nil]
- when :on_tstring_end, :on_regexp_end, :on_label_end
- opens.pop
- when :on_symbeg
- if t.tok == ':'
- opens << [t, :in_unquoted_symbol]
- else
- opens << [t, nil]
- end
- end
- end
- if t.event == :on_nl || t.event == :on_semicolon
- first_token_on_line = true
- elsif t.event != :on_sp
- first_token_on_line = false
- end
- if pending_heredocs.any? && t.tok.include?("\n")
- pending_heredocs.reverse_each { |t| opens << [t, nil] }
- pending_heredocs = []
- end
- if opens.last && opens.last[1] == :in_alias_undef && !IGNORE_TOKENS.include?(t.event) && t.event != :on_heredoc_end
- tok, state, arg = opens.pop
- opens << [tok, state, arg - 1] if arg >= 1
- end
- yield t, opens if block_given?
- end
- opens.map(&:first) + pending_heredocs.reverse
- end
-
- def open_tokens(tokens)
- # scan_opens without block will return a list of open tokens at last token position
- scan_opens(tokens)
- end
-
- # Calculates token information [line_tokens, prev_opens, next_opens, min_depth] for each line.
- # Example code
- # ["hello
- # world"+(
- # First line
- # line_tokens: [[lbracket, '['], [tstring_beg, '"'], [tstring_content("hello\nworld"), "hello\n"]]
- # prev_opens: []
- # next_tokens: [lbracket, tstring_beg]
- # min_depth: 0 (minimum at beginning of line)
- # Second line
- # line_tokens: [[tstring_content("hello\nworld"), "world"], [tstring_end, '"'], [op, '+'], [lparen, '(']]
- # prev_opens: [lbracket, tstring_beg]
- # next_tokens: [lbracket, lparen]
- # min_depth: 1 (minimum just after tstring_end)
- def parse_by_line(tokens)
- line_tokens = []
- prev_opens = []
- min_depth = 0
- output = []
- last_opens = scan_opens(tokens) do |t, opens|
- depth = t == opens.last&.first ? opens.size - 1 : opens.size
- min_depth = depth if depth < min_depth
- if t.tok.include?("\n")
- t.tok.each_line do |line|
- line_tokens << [t, line]
- next if line[-1] != "\n"
- next_opens = opens.map(&:first)
- output << [line_tokens, prev_opens, next_opens, min_depth]
- prev_opens = next_opens
- min_depth = prev_opens.size
- line_tokens = []
- end
- else
- line_tokens << [t, t.tok]
- end
- end
- output << [line_tokens, prev_opens, last_opens, min_depth] if line_tokens.any?
- output
- end
- end
- end
-end
diff --git a/lib/irb/notifier.rb b/lib/irb/notifier.rb
index dc1b9ef14b..d0e413dd68 100644
--- a/lib/irb/notifier.rb
+++ b/lib/irb/notifier.rb
@@ -1,8 +1,14 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# notifier.rb - output methods used by irb
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
require_relative "output-method"
diff --git a/lib/irb/output-method.rb b/lib/irb/output-method.rb
index 69942f47a2..3fda708cb0 100644
--- a/lib/irb/output-method.rb
+++ b/lib/irb/output-method.rb
@@ -1,18 +1,30 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# output-method.rb - output methods used by irb
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
module IRB
# An abstract output class for IO in irb. This is mainly used internally by
# IRB::Notifier. You can define your own output method to use with Irb.new,
# or Context.new
class OutputMethod
+ class NotImplementedError < StandardError
+ def initialize(val)
+ super("Need to define `#{val}'")
+ end
+ end
+
# Open this method to implement your own output method, raises a
# NotImplementedError if you don't define #print in your own class.
def print(*opts)
- raise NotImplementedError
+ raise NotImplementedError, "print"
end
# Prints the given +opts+, with a newline delimiter.
diff --git a/lib/irb/pager.rb b/lib/irb/pager.rb
deleted file mode 100644
index 558318cdb8..0000000000
--- a/lib/irb/pager.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- # The implementation of this class is borrowed from RDoc's lib/rdoc/ri/driver.rb.
- # Please do NOT use this class directly outside of IRB.
- class Pager
- PAGE_COMMANDS = [ENV['RI_PAGER'], ENV['PAGER'], 'less', 'more'].compact.uniq
-
- class << self
- def page_content(content, **options)
- if content_exceeds_screen_height?(content)
- page(**options) do |io|
- io.puts content
- end
- else
- $stdout.puts content
- end
- end
-
- def page(retain_content: false)
- if should_page? && pager = setup_pager(retain_content: retain_content)
- begin
- pid = pager.pid
- yield pager
- ensure
- pager.close
- end
- else
- yield $stdout
- end
- # When user presses Ctrl-C, IRB would raise `IRB::Abort`
- # But since Pager is implemented by running paging commands like `less` in another process with `IO.popen`,
- # the `IRB::Abort` exception only interrupts IRB's execution but doesn't affect the pager
- # So to properly terminate the pager with Ctrl-C, we need to catch `IRB::Abort` and kill the pager process
- rescue IRB::Abort
- begin
- Process.kill("TERM", pid) if pid
- rescue Errno::ESRCH
- # Pager process already terminated
- end
- nil
- rescue Errno::EPIPE
- end
-
- private
-
- def should_page?
- IRB.conf[:USE_PAGER] && STDIN.tty? && (ENV.key?("TERM") && ENV["TERM"] != "dumb")
- end
-
- def content_exceeds_screen_height?(content)
- screen_height, screen_width = begin
- Reline.get_screen_size
- rescue Errno::EINVAL
- [24, 80]
- end
-
- pageable_height = screen_height - 3 # leave some space for previous and the current prompt
-
- # If the content has more lines than the pageable height
- content.lines.count > pageable_height ||
- # Or if the content is a few long lines
- pageable_height * screen_width < Reline::Unicode.calculate_width(content, true)
- end
-
- def setup_pager(retain_content:)
- require 'shellwords'
-
- PAGE_COMMANDS.each do |pager_cmd|
- cmd = Shellwords.split(pager_cmd)
- next if cmd.empty?
-
- if cmd.first == 'less'
- cmd << '-R' unless cmd.include?('-R')
- cmd << '-X' if retain_content && !cmd.include?('-X')
- end
-
- begin
- io = IO.popen(cmd, 'w')
- rescue
- next
- end
-
- if $? && $?.pid == io.pid && $?.exited? # pager didn't work
- next
- end
-
- return io
- end
-
- nil
- end
- end
- end
-end
diff --git a/lib/irb/ruby-lex.rb b/lib/irb/ruby-lex.rb
index 3abb53b4ea..85b336fbe1 100644
--- a/lib/irb/ruby-lex.rb
+++ b/lib/irb/ruby-lex.rb
@@ -1,476 +1,866 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/ruby-lex.rb - ruby lexcal analyzer
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
require "ripper"
require "jruby" if RUBY_ENGINE == "jruby"
-require_relative "nesting_parser"
-
-module IRB
- # :stopdoc:
- class RubyLex
- ASSIGNMENT_NODE_TYPES = [
- # Local, instance, global, class, constant, instance, and index assignment:
- # "foo = bar",
- # "@foo = bar",
- # "$foo = bar",
- # "@@foo = bar",
- # "::Foo = bar",
- # "a::Foo = bar",
- # "Foo = bar"
- # "foo.bar = 1"
- # "foo[1] = bar"
- :assign,
-
- # Operation assignment:
- # "foo += bar"
- # "foo -= bar"
- # "foo ||= bar"
- # "foo &&= bar"
- :opassign,
-
- # Multiple assignment:
- # "foo, bar = 1, 2
- :massign,
- ]
-
- ERROR_TOKENS = [
- :on_parse_error,
- :compile_error,
- :on_assign_error,
- :on_alias_error,
- :on_class_name_error,
- :on_param_error
- ]
-
- LTYPE_TOKENS = %i[
- on_heredoc_beg on_tstring_beg
- on_regexp_beg on_symbeg on_backtick
- on_symbols_beg on_qsymbols_beg
- on_words_beg on_qwords_beg
- ]
-
- class TerminateLineInput < StandardError
- def initialize
- super("Terminate Line Input")
+
+# :stopdoc:
+class RubyLex
+
+ class TerminateLineInput < StandardError
+ def initialize
+ super("Terminate Line Input")
+ end
+ end
+
+ def initialize
+ @exp_line_no = @line_no = 1
+ @indent = 0
+ @continue = false
+ @line = ""
+ @prompt = nil
+ end
+
+ def self.compile_with_errors_suppressed(code, line_no: 1)
+ begin
+ result = yield code, line_no
+ rescue ArgumentError
+ # Ruby can issue an error for the code if there is an
+ # incomplete magic comment for encoding in it. Force an
+ # expression with a new line before the code in this
+ # case to prevent magic comment handling. To make sure
+ # line numbers in the lexed code remain the same,
+ # decrease the line number by one.
+ code = ";\n#{code}"
+ line_no -= 1
+ result = yield code, line_no
+ end
+ result
+ end
+
+ # io functions
+ def set_input(io, p = nil, context:, &block)
+ @io = io
+ if @io.respond_to?(:check_termination)
+ @io.check_termination do |code|
+ if Reline::IOGate.in_pasting?
+ lex = RubyLex.new
+ rest = lex.check_termination_in_prev_line(code, context: context)
+ if rest
+ Reline.delete_text
+ rest.bytes.reverse_each do |c|
+ Reline.ungetc(c)
+ end
+ true
+ else
+ false
+ end
+ else
+ # Accept any single-line input for symbol aliases or commands that transform args
+ command = code.split(/\s/, 2).first
+ if context.symbol_alias?(command) || context.transform_args?(command)
+ next true
+ end
+
+ code.gsub!(/\s*\z/, '').concat("\n")
+ ltype, indent, continue, code_block_open = check_state(code, context: context)
+ if ltype or indent > 0 or continue or code_block_open
+ false
+ else
+ true
+ end
+ end
end
end
+ if @io.respond_to?(:dynamic_prompt)
+ @io.dynamic_prompt do |lines|
+ lines << '' if lines.empty?
+ result = []
+ tokens = self.class.ripper_lex_without_warning(lines.map{ |l| l + "\n" }.join, context: context)
+ code = String.new
+ partial_tokens = []
+ unprocessed_tokens = []
+ line_num_offset = 0
+ tokens.each do |t|
+ partial_tokens << t
+ unprocessed_tokens << t
+ if t.tok.include?("\n")
+ t_str = t.tok
+ t_str.each_line("\n") do |s|
+ code << s << "\n"
+ ltype, indent, continue, code_block_open = check_state(code, partial_tokens, context: context)
+ result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
+ line_num_offset += 1
+ end
+ unprocessed_tokens = []
+ else
+ code << t.tok
+ end
+ end
- class << self
- def compile_with_errors_suppressed(code, line_no: 1)
- begin
- result = yield code, line_no
- rescue ArgumentError
- # Ruby can issue an error for the code if there is an
- # incomplete magic comment for encoding in it. Force an
- # expression with a new line before the code in this
- # case to prevent magic comment handling. To make sure
- # line numbers in the lexed code remain the same,
- # decrease the line number by one.
- code = ";\n#{code}"
- line_no -= 1
- result = yield code, line_no
+ unless unprocessed_tokens.empty?
+ ltype, indent, continue, code_block_open = check_state(code, unprocessed_tokens, context: context)
+ result << @prompt.call(ltype, indent, continue || code_block_open, @line_no + line_num_offset)
end
result
end
+ end
- def generate_local_variables_assign_code(local_variables)
- "#{local_variables.join('=')}=nil;" unless local_variables.empty?
- end
+ if p.respond_to?(:call)
+ @input = p
+ elsif block_given?
+ @input = block
+ else
+ @input = Proc.new{@io.gets}
+ end
+ end
- # Some part of the code is not included in Ripper's token.
- # Example: DATA part, token after heredoc_beg when heredoc has unclosed embexpr.
- # With interpolated tokens, tokens.map(&:tok).join will be equal to code.
- def interpolate_ripper_ignored_tokens(code, tokens)
- line_positions = [0]
- code.lines.each do |line|
- line_positions << line_positions.last + line.bytesize
- end
- prev_byte_pos = 0
- interpolated = []
- prev_line = 1
- tokens.each do |t|
- line, col = t.pos
- byte_pos = line_positions[line - 1] + col
- if prev_byte_pos < byte_pos
- tok = code.byteslice(prev_byte_pos...byte_pos)
- pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
- interpolated << Ripper::Lexer::Elem.new(pos, :on_ignored_by_ripper, tok, 0)
- prev_line += tok.count("\n")
+ def set_prompt(p = nil, &block)
+ p = block if block_given?
+ if p.respond_to?(:call)
+ @prompt = p
+ else
+ @prompt = Proc.new{print p}
+ end
+ end
+
+ ERROR_TOKENS = [
+ :on_parse_error,
+ :compile_error,
+ :on_assign_error,
+ :on_alias_error,
+ :on_class_name_error,
+ :on_param_error
+ ]
+
+ def self.generate_local_variables_assign_code(local_variables)
+ "#{local_variables.join('=')}=nil;" unless local_variables.empty?
+ end
+
+ def self.ripper_lex_without_warning(code, context: nil)
+ verbose, $VERBOSE = $VERBOSE, nil
+ lvars_code = generate_local_variables_assign_code(context&.local_variables || [])
+ if lvars_code
+ code = "#{lvars_code}\n#{code}"
+ line_no = 0
+ else
+ line_no = 1
+ end
+
+ compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
+ lexer = Ripper::Lexer.new(inner_code, '-', line_no)
+ if lexer.respond_to?(:scan) # Ruby 2.7+
+ lexer.scan.each_with_object([]) do |t, tokens|
+ next if t.pos.first == 0
+ prev_tk = tokens.last
+ position_overlapped = prev_tk && t.pos[0] == prev_tk.pos[0] && t.pos[1] < prev_tk.pos[1] + prev_tk.tok.bytesize
+ if position_overlapped
+ tokens[-1] = t if ERROR_TOKENS.include?(prev_tk.event) && !ERROR_TOKENS.include?(t.event)
+ else
+ tokens << t
end
- interpolated << t
- prev_byte_pos = byte_pos + t.tok.bytesize
- prev_line += t.tok.count("\n")
end
- if prev_byte_pos < code.bytesize
- tok = code.byteslice(prev_byte_pos..)
- pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
- interpolated << Ripper::Lexer::Elem.new(pos, :on_ignored_by_ripper, tok, 0)
+ else
+ lexer.parse.reject { |it| it.pos.first == 0 }.sort_by(&:pos)
+ end
+ end
+ ensure
+ $VERBOSE = verbose
+ end
+
+ def find_prev_spaces(line_index)
+ return 0 if @tokens.size == 0
+ md = @tokens[0].tok.match(/(\A +)/)
+ prev_spaces = md.nil? ? 0 : md[1].count(' ')
+ line_count = 0
+ @tokens.each_with_index do |t, i|
+ if t.tok.include?("\n")
+ line_count += t.tok.count("\n")
+ if line_count >= line_index
+ return prev_spaces
+ end
+ if (@tokens.size - 1) > i
+ md = @tokens[i + 1].tok.match(/(\A +)/)
+ prev_spaces = md.nil? ? 0 : md[1].count(' ')
end
- interpolated
end
+ end
+ prev_spaces
+ end
- def ripper_lex_without_warning(code, local_variables: [])
- verbose, $VERBOSE = $VERBOSE, nil
- lvars_code = generate_local_variables_assign_code(local_variables)
- original_code = code
- if lvars_code
- code = "#{lvars_code}\n#{code}"
- line_no = 0
+ def set_auto_indent(context)
+ if @io.respond_to?(:auto_indent) and context.auto_indent_mode
+ @io.auto_indent do |lines, line_index, byte_pointer, is_newline|
+ if is_newline
+ @tokens = self.class.ripper_lex_without_warning(lines[0..line_index].join("\n"), context: context)
+ prev_spaces = find_prev_spaces(line_index)
+ depth_difference = check_newline_depth_difference
+ depth_difference = 0 if depth_difference < 0
+ prev_spaces + depth_difference * 2
else
- line_no = 1
+ code = line_index.zero? ? '' : lines[0..(line_index - 1)].map{ |l| l + "\n" }.join
+ last_line = lines[line_index]&.byteslice(0, byte_pointer)
+ code += last_line if last_line
+ @tokens = self.class.ripper_lex_without_warning(code, context: context)
+ check_corresponding_token_depth(lines, line_index)
end
+ end
+ end
+ end
- compile_with_errors_suppressed(code, line_no: line_no) do |inner_code, line_no|
- lexer = Ripper::Lexer.new(inner_code, '-', line_no)
- tokens = []
- lexer.scan.each do |t|
- next if t.pos.first == 0
- prev_tk = tokens.last
- position_overlapped = prev_tk && t.pos[0] == prev_tk.pos[0] && t.pos[1] < prev_tk.pos[1] + prev_tk.tok.bytesize
- if position_overlapped
- tokens[-1] = t if ERROR_TOKENS.include?(prev_tk.event) && !ERROR_TOKENS.include?(t.event)
- else
- tokens << t
+ def check_state(code, tokens = nil, context: nil)
+ tokens = self.class.ripper_lex_without_warning(code, context: context) unless tokens
+ ltype = process_literal_type(tokens)
+ indent = process_nesting_level(tokens)
+ continue = process_continue(tokens)
+ lvars_code = self.class.generate_local_variables_assign_code(context.local_variables)
+ code = "#{lvars_code}\n#{code}" if lvars_code
+ code_block_open = check_code_block(code, tokens)
+ [ltype, indent, continue, code_block_open]
+ end
+
+ def prompt
+ if @prompt
+ @prompt.call(@ltype, @indent, @continue, @line_no)
+ end
+ end
+
+ def initialize_input
+ @ltype = nil
+ @indent = 0
+ @continue = false
+ @line = ""
+ @exp_line_no = @line_no
+ @code_block_open = false
+ end
+
+ def each_top_level_statement(context)
+ initialize_input
+ catch(:TERM_INPUT) do
+ loop do
+ begin
+ prompt
+ unless l = lex(context)
+ throw :TERM_INPUT if @line == ''
+ else
+ @line_no += l.count("\n")
+ if l == "\n"
+ @exp_line_no += 1
+ next
+ end
+ @line.concat l
+ if @code_block_open or @ltype or @continue or @indent > 0
+ next
end
end
- interpolate_ripper_ignored_tokens(original_code, tokens)
+ if @line != "\n"
+ @line.force_encoding(@io.encoding)
+ yield @line, @exp_line_no
+ end
+ raise TerminateLineInput if @io.eof?
+ @line = ''
+ @exp_line_no = @line_no
+
+ @indent = 0
+ rescue TerminateLineInput
+ initialize_input
+ prompt
end
- ensure
- $VERBOSE = verbose
end
end
+ end
- def check_code_state(code, local_variables:)
- tokens = self.class.ripper_lex_without_warning(code, local_variables: local_variables)
- opens = NestingParser.open_tokens(tokens)
- [tokens, opens, code_terminated?(code, tokens, opens, local_variables: local_variables)]
+ def lex(context)
+ line = @input.call
+ if @io.respond_to?(:check_termination)
+ return line # multiline
end
+ code = @line + (line.nil? ? '' : line)
+ code.gsub!(/\s*\z/, '').concat("\n")
+ @tokens = self.class.ripper_lex_without_warning(code, context: context)
+ @ltype, @indent, @continue, @code_block_open = check_state(code, @tokens, context: context)
+ line
+ end
- def code_terminated?(code, tokens, opens, local_variables:)
- case check_code_syntax(code, local_variables: local_variables)
- when :unrecoverable_error
- true
- when :recoverable_error
- false
- when :other_error
- opens.empty? && !should_continue?(tokens)
- when :valid
- !should_continue?(tokens)
- end
+ def process_continue(tokens = @tokens)
+ # last token is always newline
+ if tokens.size >= 2 and tokens[-2].event == :on_regexp_end
+ # end of regexp literal
+ return false
+ elsif tokens.size >= 2 and tokens[-2].event == :on_semicolon
+ return false
+ elsif tokens.size >= 2 and tokens[-2].event == :on_kw and ['begin', 'else', 'ensure'].include?(tokens[-2].tok)
+ return false
+ elsif !tokens.empty? and tokens.last.tok == "\\\n"
+ return true
+ elsif tokens.size >= 1 and tokens[-1].event == :on_heredoc_end # "EOH\n"
+ return false
+ elsif tokens.size >= 2 and tokens[-2].state.anybits?(Ripper::EXPR_BEG | Ripper::EXPR_FNAME) and tokens[-2].tok !~ /\A\.\.\.?\z/
+ # end of literal except for regexp
+ # endless range at end of line is not a continue
+ return true
end
+ false
+ end
- def assignment_expression?(code, local_variables:)
- # Try to parse the code and check if the last of possibly multiple
- # expressions is an assignment type.
+ def check_code_block(code, tokens = @tokens)
+ return true if tokens.empty?
+ if tokens.last.event == :on_heredoc_beg
+ return true
+ end
- # If the expression is invalid, Ripper.sexp should return nil which will
- # result in false being returned. Any valid expression should return an
- # s-expression where the second element of the top level array is an
- # array of parsed expressions. The first element of each expression is the
- # expression's type.
+ begin # check if parser error are available
verbose, $VERBOSE = $VERBOSE, nil
- code = "#{RubyLex.generate_local_variables_assign_code(local_variables) || 'nil;'}\n#{code}"
- # Get the last node_type of the line. drop(1) is to ignore the local_variables_assign_code part.
- node_type = Ripper.sexp(code)&.dig(1)&.drop(1)&.dig(-1, 0)
- ASSIGNMENT_NODE_TYPES.include?(node_type)
+ case RUBY_ENGINE
+ when 'ruby'
+ self.class.compile_with_errors_suppressed(code) do |inner_code, line_no|
+ RubyVM::InstructionSequence.compile(inner_code, nil, nil, line_no)
+ end
+ when 'jruby'
+ JRuby.compile_ir(code)
+ else
+ catch(:valid) do
+ eval("BEGIN { throw :valid, true }\n#{code}")
+ false
+ end
+ end
+ rescue EncodingError
+ # This is for a hash with invalid encoding symbol, {"\xAE": 1}
+ rescue SyntaxError => e
+ case e.message
+ when /unterminated (?:string|regexp) meets end of file/
+ # "unterminated regexp meets end of file"
+ #
+ # example:
+ # /
+ #
+ # "unterminated string meets end of file"
+ #
+ # example:
+ # '
+ return true
+ when /syntax error, unexpected end-of-input/
+ # "syntax error, unexpected end-of-input, expecting keyword_end"
+ #
+ # example:
+ # if true
+ # hoge
+ # if false
+ # fuga
+ # end
+ return true
+ when /syntax error, unexpected keyword_end/
+ # "syntax error, unexpected keyword_end"
+ #
+ # example:
+ # if (
+ # end
+ #
+ # example:
+ # end
+ return false
+ when /syntax error, unexpected '\.'/
+ # "syntax error, unexpected '.'"
+ #
+ # example:
+ # .
+ return false
+ when /unexpected tREGEXP_BEG/
+ # "syntax error, unexpected tREGEXP_BEG, expecting keyword_do or '{' or '('"
+ #
+ # example:
+ # method / f /
+ return false
+ end
ensure
$VERBOSE = verbose
end
- def should_continue?(tokens)
- # Look at the last token and check if IRB need to continue reading next line.
- # Example code that should continue: `a\` `a +` `a.`
- # Trailing spaces, newline, comments are skipped
- return true if tokens.last&.event == :on_sp && tokens.last.tok == "\\\n"
-
- tokens.reverse_each do |token|
- case token.event
- when :on_sp, :on_nl, :on_ignored_nl, :on_comment, :on_embdoc_beg, :on_embdoc, :on_embdoc_end
- # Skip
- when :on_regexp_end, :on_heredoc_end, :on_semicolon
- # State is EXPR_BEG but should not continue
- return false
- else
- # Endless range should not continue
- return false if token.event == :on_op && token.tok.match?(/\A\.\.\.?\z/)
-
- # EXPR_DOT and most of the EXPR_BEG should continue
- return token.state.anybits?(Ripper::EXPR_BEG | Ripper::EXPR_DOT)
- end
- end
- false
+ last_lex_state = tokens.last.state
+
+ if last_lex_state.allbits?(Ripper::EXPR_BEG)
+ return false
+ elsif last_lex_state.allbits?(Ripper::EXPR_DOT)
+ return true
+ elsif last_lex_state.allbits?(Ripper::EXPR_CLASS)
+ return true
+ elsif last_lex_state.allbits?(Ripper::EXPR_FNAME)
+ return true
+ elsif last_lex_state.allbits?(Ripper::EXPR_VALUE)
+ return true
+ elsif last_lex_state.allbits?(Ripper::EXPR_ARG)
+ return false
end
- def check_code_syntax(code, local_variables:)
- lvars_code = RubyLex.generate_local_variables_assign_code(local_variables)
- code = "#{lvars_code}\n#{code}"
+ false
+ end
- begin # check if parser error are available
- verbose, $VERBOSE = $VERBOSE, nil
- case RUBY_ENGINE
- when 'ruby'
- self.class.compile_with_errors_suppressed(code) do |inner_code, line_no|
- RubyVM::InstructionSequence.compile(inner_code, nil, nil, line_no)
+ def process_nesting_level(tokens = @tokens)
+ indent = 0
+ in_oneliner_def = nil
+ tokens.each_with_index { |t, index|
+ # detecting one-liner method definition
+ if in_oneliner_def.nil?
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
+ in_oneliner_def = :ENDFN
+ end
+ else
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
+ # continuing
+ elsif t.state.allbits?(Ripper::EXPR_BEG)
+ if t.tok == '='
+ in_oneliner_def = :BODY
end
- when 'jruby'
- JRuby.compile_ir(code)
else
- catch(:valid) do
- eval("BEGIN { throw :valid, true }\n#{code}")
- false
+ if in_oneliner_def == :BODY
+ # one-liner method definition
+ indent -= 1
end
+ in_oneliner_def = nil
end
- rescue EncodingError
- # This is for a hash with invalid encoding symbol, {"\xAE": 1}
- :unrecoverable_error
- rescue SyntaxError => e
- case e.message
- when /unexpected keyword_end/
- # "syntax error, unexpected keyword_end"
- #
- # example:
- # if (
- # end
- #
- # example:
- # end
- return :unrecoverable_error
- when /unexpected '\.'/
- # "syntax error, unexpected '.'"
- #
- # example:
- # .
- return :unrecoverable_error
- when /unexpected tREGEXP_BEG/
- # "syntax error, unexpected tREGEXP_BEG, expecting keyword_do or '{' or '('"
- #
- # example:
- # method / f /
- return :unrecoverable_error
- when /unterminated (?:string|regexp) meets end of file/
- # "unterminated regexp meets end of file"
- #
- # example:
- # /
- #
- # "unterminated string meets end of file"
- #
- # example:
- # '
- return :recoverable_error
- when /unexpected end-of-input/
- # "syntax error, unexpected end-of-input, expecting keyword_end"
- #
- # example:
- # if true
- # hoge
- # if false
- # fuga
- # end
- return :recoverable_error
- else
- return :other_error
+ end
+
+ case t.event
+ when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
+ indent += 1
+ when :on_rbracket, :on_rbrace, :on_rparen
+ indent -= 1
+ when :on_kw
+ next if index > 0 and tokens[index - 1].state.allbits?(Ripper::EXPR_FNAME)
+ case t.tok
+ when 'do'
+ syntax_of_do = take_corresponding_syntax_to_kw_do(tokens, index)
+ indent += 1 if syntax_of_do == :method_calling
+ when 'def', 'case', 'for', 'begin', 'class', 'module'
+ indent += 1
+ when 'if', 'unless', 'while', 'until'
+ # postfix if/unless/while/until must be Ripper::EXPR_LABEL
+ indent += 1 unless t.state.allbits?(Ripper::EXPR_LABEL)
+ when 'end'
+ indent -= 1
end
- ensure
- $VERBOSE = verbose
end
- :valid
- end
+ # percent literals are not indented
+ }
+ indent
+ end
- def calc_indent_level(opens)
- indent_level = 0
- opens.each_with_index do |t, index|
- case t.event
- when :on_heredoc_beg
- if opens[index + 1]&.event != :on_heredoc_beg
- if t.tok.match?(/^<<[~-]/)
- indent_level += 1
- else
- indent_level = 0
- end
- end
- when :on_tstring_beg, :on_regexp_beg, :on_symbeg, :on_backtick
- # No indent: "", //, :"", ``
- # Indent: %(), %r(), %i(), %x()
- indent_level += 1 if t.tok.start_with? '%'
- when :on_embdoc_beg
- indent_level = 0
- else
- indent_level += 1 unless t.tok == 'alias' || t.tok == 'undef'
+ def is_method_calling?(tokens, index)
+ tk = tokens[index]
+ if tk.state.anybits?(Ripper::EXPR_CMDARG) and tk.event == :on_ident
+ # The target method call to pass the block with "do".
+ return true
+ elsif tk.state.anybits?(Ripper::EXPR_ARG) and tk.event == :on_ident
+ non_sp_index = tokens[0..(index - 1)].rindex{ |t| t.event != :on_sp }
+ if non_sp_index
+ prev_tk = tokens[non_sp_index]
+ if prev_tk.state.anybits?(Ripper::EXPR_DOT) and prev_tk.event == :on_period
+ # The target method call with receiver to pass the block with "do".
+ return true
end
end
- indent_level
end
+ false
+ end
- FREE_INDENT_TOKENS = %i[on_tstring_beg on_backtick on_regexp_beg on_symbeg]
-
- def free_indent_token?(token)
- FREE_INDENT_TOKENS.include?(token&.event)
+ def take_corresponding_syntax_to_kw_do(tokens, index)
+ syntax_of_do = nil
+ # Finding a syntax corresponding to "do".
+ index.downto(0) do |i|
+ tk = tokens[i]
+ # In "continue", the token isn't the corresponding syntax to "do".
+ non_sp_index = tokens[0..(i - 1)].rindex{ |t| t.event != :on_sp }
+ first_in_fomula = false
+ if non_sp_index.nil?
+ first_in_fomula = true
+ elsif [:on_ignored_nl, :on_nl, :on_comment].include?(tokens[non_sp_index].event)
+ first_in_fomula = true
+ end
+ if is_method_calling?(tokens, i)
+ syntax_of_do = :method_calling
+ break if first_in_fomula
+ elsif tk.event == :on_kw && %w{while until for}.include?(tk.tok)
+ # A loop syntax in front of "do" found.
+ #
+ # while cond do # also "until" or "for"
+ # end
+ #
+ # This "do" doesn't increment indent because the loop syntax already
+ # incremented.
+ syntax_of_do = :loop_syntax
+ break if first_in_fomula
+ end
end
+ syntax_of_do
+ end
- # Calculates the difference of pasted code's indent and indent calculated from tokens
- def indent_difference(lines, line_results, line_index)
- loop do
- _tokens, prev_opens, _next_opens, min_depth = line_results[line_index]
- open_token = prev_opens.last
- if !open_token || (open_token.event != :on_heredoc_beg && !free_indent_token?(open_token))
- # If the leading whitespace is an indent, return the difference
- indent_level = calc_indent_level(prev_opens.take(min_depth))
- calculated_indent = 2 * indent_level
- actual_indent = lines[line_index][/^ */].size
- return actual_indent - calculated_indent
- elsif open_token.event == :on_heredoc_beg && open_token.tok.match?(/^<<[^-~]/)
- return 0
- end
- # If the leading whitespace is not an indent but part of a multiline token
- # Calculate base_indent of the multiline token's beginning line
- line_index = open_token.pos[0] - 1
+ def is_the_in_correspond_to_a_for(tokens, index)
+ syntax_of_in = nil
+ # Finding a syntax corresponding to "do".
+ index.downto(0) do |i|
+ tk = tokens[i]
+ # In "continue", the token isn't the corresponding syntax to "do".
+ non_sp_index = tokens[0..(i - 1)].rindex{ |t| t.event != :on_sp }
+ first_in_fomula = false
+ if non_sp_index.nil?
+ first_in_fomula = true
+ elsif [:on_ignored_nl, :on_nl, :on_comment].include?(tokens[non_sp_index].event)
+ first_in_fomula = true
+ end
+ if tk.event == :on_kw && tk.tok == 'for'
+ # A loop syntax in front of "do" found.
+ #
+ # while cond do # also "until" or "for"
+ # end
+ #
+ # This "do" doesn't increment indent because the loop syntax already
+ # incremented.
+ syntax_of_in = :for
end
+ break if first_in_fomula
end
+ syntax_of_in
+ end
- def process_indent_level(tokens, lines, line_index, is_newline)
- line_results = NestingParser.parse_by_line(tokens)
- result = line_results[line_index]
- if result
- _tokens, prev_opens, next_opens, min_depth = result
+ def check_newline_depth_difference
+ depth_difference = 0
+ open_brace_on_line = 0
+ in_oneliner_def = nil
+ @tokens.each_with_index do |t, index|
+ # detecting one-liner method definition
+ if in_oneliner_def.nil?
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
+ in_oneliner_def = :ENDFN
+ end
else
- # When last line is empty
- prev_opens = next_opens = line_results.last[2]
- min_depth = next_opens.size
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
+ # continuing
+ elsif t.state.allbits?(Ripper::EXPR_BEG)
+ if t.tok == '='
+ in_oneliner_def = :BODY
+ end
+ else
+ if in_oneliner_def == :BODY
+ # one-liner method definition
+ depth_difference -= 1
+ end
+ in_oneliner_def = nil
+ end
end
- # To correctly indent line like `end.map do`, we use shortest open tokens on each line for indent calculation.
- # Shortest open tokens can be calculated by `opens.take(min_depth)`
- indent = 2 * calc_indent_level(prev_opens.take(min_depth))
+ case t.event
+ when :on_ignored_nl, :on_nl, :on_comment
+ if index != (@tokens.size - 1) and in_oneliner_def != :BODY
+ depth_difference = 0
+ open_brace_on_line = 0
+ end
+ next
+ when :on_sp
+ next
+ end
- preserve_indent = lines[line_index - (is_newline ? 1 : 0)][/^ */].size
+ case t.event
+ when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
+ depth_difference += 1
+ open_brace_on_line += 1
+ when :on_rbracket, :on_rbrace, :on_rparen
+ depth_difference -= 1 if open_brace_on_line > 0
+ when :on_kw
+ next if index > 0 and @tokens[index - 1].state.allbits?(Ripper::EXPR_FNAME)
+ case t.tok
+ when 'do'
+ syntax_of_do = take_corresponding_syntax_to_kw_do(@tokens, index)
+ depth_difference += 1 if syntax_of_do == :method_calling
+ when 'def', 'case', 'for', 'begin', 'class', 'module'
+ depth_difference += 1
+ when 'if', 'unless', 'while', 'until', 'rescue'
+ # postfix if/unless/while/until/rescue must be Ripper::EXPR_LABEL
+ unless t.state.allbits?(Ripper::EXPR_LABEL)
+ depth_difference += 1
+ end
+ when 'else', 'elsif', 'ensure', 'when'
+ depth_difference += 1
+ when 'in'
+ unless is_the_in_correspond_to_a_for(@tokens, index)
+ depth_difference += 1
+ end
+ when 'end'
+ depth_difference -= 1
+ end
+ end
+ end
+ depth_difference
+ end
- prev_open_token = prev_opens.last
- next_open_token = next_opens.last
+ def check_corresponding_token_depth(lines, line_index)
+ corresponding_token_depth = nil
+ is_first_spaces_of_line = true
+ is_first_printable_of_line = true
+ spaces_of_nest = []
+ spaces_at_line_head = 0
+ open_brace_on_line = 0
+ in_oneliner_def = nil
+
+ if heredoc_scope?
+ return lines[line_index][/^ */].length
+ end
- # Calculates base indent for pasted code on the line where prev_open_token is located
- # irb(main):001:1* if a # base_indent is 2, indent calculated from tokens is 0
- # irb(main):002:1* if b # base_indent is 6, indent calculated from tokens is 2
- # irb(main):003:0> c # base_indent is 6, indent calculated from tokens is 4
- if prev_open_token
- base_indent = [0, indent_difference(lines, line_results, prev_open_token.pos[0] - 1)].max
+ @tokens.each_with_index do |t, index|
+ # detecting one-liner method definition
+ if in_oneliner_def.nil?
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
+ in_oneliner_def = :ENDFN
+ end
else
- base_indent = 0
+ if t.state.allbits?(Ripper::EXPR_ENDFN)
+ # continuing
+ elsif t.state.allbits?(Ripper::EXPR_BEG)
+ if t.tok == '='
+ in_oneliner_def = :BODY
+ end
+ else
+ if in_oneliner_def == :BODY
+ # one-liner method definition
+ if is_first_printable_of_line
+ corresponding_token_depth = spaces_of_nest.pop
+ else
+ spaces_of_nest.pop
+ corresponding_token_depth = nil
+ end
+ end
+ in_oneliner_def = nil
+ end
end
- if free_indent_token?(prev_open_token)
- if is_newline && prev_open_token.pos[0] == line_index
- # First newline inside free-indent token
- base_indent + indent
- else
- # Accept any number of indent inside free-indent token
- preserve_indent
+ case t.event
+ when :on_ignored_nl, :on_nl, :on_comment
+ if in_oneliner_def != :BODY
+ corresponding_token_depth = nil
+ spaces_at_line_head = 0
+ is_first_spaces_of_line = true
+ is_first_printable_of_line = true
+ open_brace_on_line = 0
end
- elsif prev_open_token&.event == :on_embdoc_beg || next_open_token&.event == :on_embdoc_beg
- if prev_open_token&.event == next_open_token&.event
- # Accept any number of indent inside embdoc content
- preserve_indent
+ next
+ when :on_sp
+ spaces_at_line_head = t.tok.count(' ') if is_first_spaces_of_line
+ is_first_spaces_of_line = false
+ next
+ end
+
+ case t.event
+ when :on_lbracket, :on_lbrace, :on_lparen, :on_tlambeg
+ spaces_of_nest.push(spaces_at_line_head + open_brace_on_line * 2)
+ open_brace_on_line += 1
+ when :on_rbracket, :on_rbrace, :on_rparen
+ if is_first_printable_of_line
+ corresponding_token_depth = spaces_of_nest.pop
else
- # =begin or =end
- 0
+ spaces_of_nest.pop
+ corresponding_token_depth = nil
end
- elsif prev_open_token&.event == :on_heredoc_beg
- tok = prev_open_token.tok
- if prev_opens.size <= next_opens.size
- if is_newline && lines[line_index].empty? && line_results[line_index - 1][1].last != next_open_token
- # First line in heredoc
- tok.match?(/^<<[-~]/) ? base_indent + indent : indent
- elsif tok.match?(/^<<~/)
- # Accept extra indent spaces inside `<<~` heredoc
- [base_indent + indent, preserve_indent].max
+ open_brace_on_line -= 1
+ when :on_kw
+ next if index > 0 and @tokens[index - 1].state.allbits?(Ripper::EXPR_FNAME)
+ case t.tok
+ when 'do'
+ syntax_of_do = take_corresponding_syntax_to_kw_do(@tokens, index)
+ if syntax_of_do == :method_calling
+ spaces_of_nest.push(spaces_at_line_head)
+ end
+ when 'def', 'case', 'for', 'begin', 'class', 'module'
+ spaces_of_nest.push(spaces_at_line_head)
+ when 'rescue'
+ unless t.state.allbits?(Ripper::EXPR_LABEL)
+ corresponding_token_depth = spaces_of_nest.last
+ end
+ when 'if', 'unless', 'while', 'until'
+ # postfix if/unless/while/until must be Ripper::EXPR_LABEL
+ unless t.state.allbits?(Ripper::EXPR_LABEL)
+ spaces_of_nest.push(spaces_at_line_head)
+ end
+ when 'else', 'elsif', 'ensure', 'when'
+ corresponding_token_depth = spaces_of_nest.last
+ when 'in'
+ if in_keyword_case_scope?
+ corresponding_token_depth = spaces_of_nest.last
+ end
+ when 'end'
+ if is_first_printable_of_line
+ corresponding_token_depth = spaces_of_nest.pop
else
- # Accept any number of indent inside other heredoc
- preserve_indent
+ spaces_of_nest.pop
+ corresponding_token_depth = nil
end
- else
- # Heredoc close
- prev_line_indent_level = calc_indent_level(prev_opens)
- tok.match?(/^<<[~-]/) ? base_indent + 2 * (prev_line_indent_level - 1) : 0
end
- else
- base_indent + indent
end
+ is_first_spaces_of_line = false
+ is_first_printable_of_line = false
end
+ corresponding_token_depth
+ end
- def ltype_from_open_tokens(opens)
- start_token = opens.reverse_each.find do |tok|
- LTYPE_TOKENS.include?(tok.event)
- end
- return nil unless start_token
-
- case start_token&.event
+ def check_string_literal(tokens)
+ i = 0
+ start_token = []
+ end_type = []
+ pending_heredocs = []
+ while i < tokens.size
+ t = tokens[i]
+ case t.event
+ when *end_type.last
+ start_token.pop
+ end_type.pop
when :on_tstring_beg
- case start_token&.tok
- when ?" then ?"
- when /^%.$/ then ?"
- when /^%Q.$/ then ?"
- when ?' then ?'
- when /^%q.$/ then ?'
+ start_token << t
+ end_type << [:on_tstring_end, :on_label_end]
+ when :on_regexp_beg
+ start_token << t
+ end_type << :on_regexp_end
+ when :on_symbeg
+ acceptable_single_tokens = %i{on_ident on_const on_op on_cvar on_ivar on_gvar on_kw on_int on_backtick}
+ if (i + 1) < tokens.size
+ if acceptable_single_tokens.all?{ |st| tokens[i + 1].event != st }
+ start_token << t
+ end_type << :on_tstring_end
+ else
+ i += 1
+ end
+ end
+ when :on_backtick
+ if t.state.allbits?(Ripper::EXPR_BEG)
+ start_token << t
+ end_type << :on_tstring_end
end
- when :on_regexp_beg then ?/
- when :on_symbeg then ?:
- when :on_backtick then ?`
- when :on_qwords_beg then ?]
- when :on_words_beg then ?]
- when :on_qsymbols_beg then ?]
- when :on_symbols_beg then ?]
+ when :on_qwords_beg, :on_words_beg, :on_qsymbols_beg, :on_symbols_beg
+ start_token << t
+ end_type << :on_tstring_end
when :on_heredoc_beg
- start_token&.tok =~ /<<[-~]?(['"`])\w+\1/
- $1 || ?"
- else
- nil
+ pending_heredocs << t
end
+
+ if pending_heredocs.any? && t.tok.include?("\n")
+ pending_heredocs.reverse_each do |t|
+ start_token << t
+ end_type << :on_heredoc_end
+ end
+ pending_heredocs = []
+ end
+ i += 1
end
+ pending_heredocs.first || start_token.last
+ end
- def check_termination_in_prev_line(code, local_variables:)
- tokens = self.class.ripper_lex_without_warning(code, local_variables: local_variables)
- past_first_newline = false
- index = tokens.rindex do |t|
- # traverse first token before last line
- if past_first_newline
- if t.tok.include?("\n")
- true
- end
- elsif t.tok.include?("\n")
- past_first_newline = true
- false
- else
- false
+ def process_literal_type(tokens = @tokens)
+ start_token = check_string_literal(tokens)
+ return nil if start_token == ""
+
+ case start_token&.event
+ when :on_tstring_beg
+ case start_token&.tok
+ when ?" then ?"
+ when /^%.$/ then ?"
+ when /^%Q.$/ then ?"
+ when ?' then ?'
+ when /^%q.$/ then ?'
+ end
+ when :on_regexp_beg then ?/
+ when :on_symbeg then ?:
+ when :on_backtick then ?`
+ when :on_qwords_beg then ?]
+ when :on_words_beg then ?]
+ when :on_qsymbols_beg then ?]
+ when :on_symbols_beg then ?]
+ when :on_heredoc_beg
+ start_token&.tok =~ /<<[-~]?(['"`])[_a-zA-Z0-9]+\1/
+ case $1
+ when ?" then ?"
+ when ?' then ?'
+ when ?` then ?`
+ else ?"
+ end
+ else
+ nil
+ end
+ end
+
+ def check_termination_in_prev_line(code, context: nil)
+ tokens = self.class.ripper_lex_without_warning(code, context: context)
+ past_first_newline = false
+ index = tokens.rindex do |t|
+ # traverse first token before last line
+ if past_first_newline
+ if t.tok.include?("\n")
+ true
end
+ elsif t.tok.include?("\n")
+ past_first_newline = true
+ false
+ else
+ false
end
+ end
- if index
- first_token = nil
- last_line_tokens = tokens[(index + 1)..(tokens.size - 1)]
- last_line_tokens.each do |t|
- unless [:on_sp, :on_ignored_sp, :on_comment].include?(t.event)
- first_token = t
- break
- end
+ if index
+ first_token = nil
+ last_line_tokens = tokens[(index + 1)..(tokens.size - 1)]
+ last_line_tokens.each do |t|
+ unless [:on_sp, :on_ignored_sp, :on_comment].include?(t.event)
+ first_token = t
+ break
end
+ end
- if first_token && first_token.state != Ripper::EXPR_DOT
- tokens_without_last_line = tokens[0..index]
- code_without_last_line = tokens_without_last_line.map(&:tok).join
- opens_without_last_line = NestingParser.open_tokens(tokens_without_last_line)
- if code_terminated?(code_without_last_line, tokens_without_last_line, opens_without_last_line, local_variables: local_variables)
- return last_line_tokens.map(&:tok).join
- end
+ if first_token.nil?
+ return false
+ elsif first_token && first_token.state == Ripper::EXPR_DOT
+ return false
+ else
+ tokens_without_last_line = tokens[0..index]
+ ltype = process_literal_type(tokens_without_last_line)
+ indent = process_nesting_level(tokens_without_last_line)
+ continue = process_continue(tokens_without_last_line)
+ code_block_open = check_code_block(tokens_without_last_line.map(&:tok).join(''), tokens_without_last_line)
+ if ltype or indent > 0 or continue or code_block_open
+ return false
+ else
+ return last_line_tokens.map(&:tok).join('')
end
end
- false
end
+ false
end
- # :startdoc:
-end
-RubyLex = IRB::RubyLex
-Object.deprecate_constant(:RubyLex)
+ private
+
+ def heredoc_scope?
+ heredoc_tokens = @tokens.select { |t| [:on_heredoc_beg, :on_heredoc_end].include?(t.event) }
+ heredoc_tokens[-1]&.event == :on_heredoc_beg
+ end
+
+ def in_keyword_case_scope?
+ kw_tokens = @tokens.select { |t| t.event == :on_kw && ['case', 'for', 'end'].include?(t.tok) }
+ counter = 0
+ kw_tokens.reverse.each do |t|
+ if t.tok == 'case'
+ return true if counter.zero?
+ counter += 1
+ elsif t.tok == 'for'
+ counter += 1
+ elsif t.tok == 'end'
+ counter -= 1
+ end
+ end
+ false
+ end
+end
+# :startdoc:
diff --git a/lib/irb/ruby_logo.aa b/lib/irb/ruby_logo.aa
index d0143a448b..a34a3e2f28 100644
--- a/lib/irb/ruby_logo.aa
+++ b/lib/irb/ruby_logo.aa
@@ -1,118 +1,37 @@
-TYPE: ASCII_LARGE
- ,,,;;;;;;;;;;;;;;;;;;;;;;,,
- ,,,;;;;;;;;;,, ,;;;' ''';;,
- ,,;;;''' ';;;, ,,;;'' '';,
- ,;;'' ;;;;;;;;,,,,,, ';;
- ,;;'' ;;;;';;;'''';;;;;;;;;,,,;;
- ,,;'' ;;;; ';;, ''''';;,
- ,;;' ;;;' ';;, ;;
- ,;;' ,;;; '';,, ;;
- ,;;' ;;; ';;, ,;;
- ;;' ;;;' '';,, ;;;
- ,;' ;;;; ';;, ;;'
- ,;;' ,;;;;' ,,,,,,,,,,,,;;;;;
- ,;' ,;;;;;;;;;;;;;;;;;;;;'''''''';;;
- ;;' ,;;;;;;;;;,, ;;;;
- ;;' ,;;;'' ;;, ';;,, ,;;;;
- ;;' ,;;;' ;; '';;, ,;';;;
- ;;' ,;;;' ;;, '';;,, ,;',;;;
- ,;;; ,;;;' ;; '';;,, ,;' ;;;'
- ;;;; ,,;;;' ;;, ';;;' ;;;
-,;;; ,;;;;' ;; ,;;; ;;;
-;;;;; ,,;;;;;' ;;, ,;';; ;;;
-;;;;;, ,,;;;;;;;' ;; ,;;' ;;; ;;;
-;;;;;;;,,,,,,,;;;;;;;;;;;;;;,,, ;;, ,;' ;; ;;;
-;;' ;;;;;;;;;;'''' ,;';; ''';;;;,,, ;; ,;; ;; ;;;
-;; ;;;'' ;; ';; ''';;;;,,,, ;;, ,;;' ;;, ;;
-;; ;;;;, ;;' ';; ''';;;;,,;;;;' ';; ;;
-;;;;;;';, ,;; ;; '';;;;, ;;,;;
-;;; ;; ;;, ;; ;; ,;;' ';;, ;;;;;
-;; ;;; ;;, ;;' ;; ,,;'' ';;, ;;;;;
-;; ;; ;; ;; ;; ,;;' '';, ;;;;
-;;,;; ;; ;;' ;; ,;;'' ';,, ;;;'
- ;;;; ';; ,;; ;;,,;;'' ';;, ;;;
- ';;; ';; ;; ,;;;;;;;;;;;;;,,,,,,,,,,,, ';;;;;
- ';, ';,;;' ,,,;;'' '''''''';;;;;;;;;;;;;;;;;;;
- ';;,,, ;;;; ,,,,;;;;;;,,,,,;;;;;;;;;;;;;;;;;;;''''''''''''''
- ''';;;;;;;;;;;;;;'''''''''''''''
-TYPE: ASCII
- ,,,;;;;''''';;;'';,
- ,,;'' ';;,;;; ',
- ,,'' ;;'';'''';;;;;;
- ,;' ;; ',, ;
- ,;' ,;' ';, ;
- ;' ,;; ',,,;
- ,' ,;;,,,,,,,,,,,;;;;
- ;' ;;';;;; ,;;
- ;' ,;' ;; '',, ,;;;
- ;; ,;' ; '';, ,; ;'
-;; ,;;' ;; ;; ;;
-;;, ,,;;' ; ;'; ;;
-;';;,,,,;;;;;;;,,, ;; ,' ; ;;
-; ;;''' ,;'; ''';,,, ; ,;' ;;;;
-;;;;, ; '; ''';;;' ';;;
-;'; ;, ;' '; ,;' ', ;;;
-;;; ; ,; '; ,,' ',, ;;
-;;; '; ;' ';,,'' ';,;;
- '; ';,; ,,;''''''''';;;;;;,,;;;
- ';,,;;,,;;;;;;;;;;''''''''''''''
-TYPE: UNICODE_LARGE
-
- ⣀⣤⣴⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣤⣄⡀
- ⢀⣀⣤⣴⣾⣿⣿⣿⠿⣿⣿⣿⣿⣦⣀ ⢀⣤⣶⣿⠿⠛â â ˆâ ‰â ™â »â¢¿â£·â£¦â¡€
- ⢀⣠⣴⣾⡿⠿⠛⠉⠉ ⠈⠙⢿⣿⣷⣤⡀ ⣠⣴⣾⡿⠟⠉ ⠉⠻⣿⣦
- â¢€â£¤â£¶â£¿â Ÿâ ‹â  â¢¿â£¿â£¿â£¿â£¿â£¿â£¿â£§â£¤â£¤â£¤â£€â£€â£€â¡€ ⠘⢿⣷⡀
- ⢀⣠⣾⡿⠟⠉ ⢸⣿⣿⣿⠟⢿⣿⣯⡙⠛⠛⠛⠿⠿⠿⢿⣿⣿⣶⣶⣶⣦⣤⣬⣿⣧
- ⣠⣴⣿⠟⠋ ⢸⣿⣿⡿ ⠈⠻⣿⣶⣄ ⠉⠉⠉⠙⠛⢻⣿⡆
- â£ â£¾â¡¿â ›â  â£¼â£¿â£¿â ƒ ⠈⠙⢿⣷⣤⡀ ⠈⣿⡇
- ⣠⣾⡿⠋ ⢠⣿⣿⡠⠙⠻⣿⣦⣀ ⣿⡇
- ⣠⣾⡿⠋ ⢀⣿⣿⣿ ⠈⠛⢿⣷⣄⡀ ⢠⣿⡇
- ⢀⣾⡿⠋ ⢀⣾⣿⣿⠇ ⠙⠻⣿⣦⣀ ⢸⣿⡇
- â¢€â£´â£¿â Ÿâ  â¢€â£¾â£¿â£¿â¡Ÿ ⠈⠻⢿⣷⣄ ⣾⣿⠇
- ⢠⣾⡿⠃ ⣠⣿⣿⣿⣿⠃ ⣀⣀⣀⣀⣀⣀⣀⣀⣤⣤⣤⣤⣽⣿⣿⣿⣿
- ⣰⣿⠟ ⣴⣿⣿⣿⣿⣿⣶⣶⣿⣿⣿⣿⣿⠿⠿⠿⠿⠿⠿⠿⠿⠛⠛⠛⠛⠛⠛⠛⠛⣿⣿⣿
- â£¼â£¿â  â¢ â£¾â£¿â£¿â£¿â¡¿â£¿â£¿â¢¿â£·â£¦â£„ ⣼⣿⣿⣿
- ⣼⣿⠃ ⢀⣴⣿⣿⣿⠟⠋ ⢸⣿⡆⠈⠛⠿⣿⣦⣄⡀ ⣰⣿⣿⣿⡇
- ⢀⣾⣿⠃ â¢€â£´â£¿â£¿â£¿â Ÿâ  â£¿â£· ⠈⠙⠻⣿⣶⣄⡀ ⣰⣿⠟⣿⣿⡇
- ⢀⣾⣿⠇ â¢€â£´â£¿â£¿â£¿â Ÿâ  â¢¸â£¿â¡† ⠙⠻⢿⣷⣤⣀ ⣰⣿â â¢ â£¿â£¿â¡‡
- ⢠⣿⣿⡟ â¢€â£´â£¿â£¿â¡¿â ›â  â£¿â£· ⠉⠻⢿⣷⣦⣀ â£´â£¿â  â¢¸â£¿â£¿â ƒ
- ⣿⣿⣿⡇ ⣠⣴⣿⣿⡿⠋ ⢸⣿⡆ ⠈⠛⢿⣿⣿⠃ ⢸⣿⣿
-⢠⣿⣿⣿ ⢀⣴⣾⣿⣿⡿⠋ ⠈⣿⣧ ⢠⣾⣿⣿ ⢸⣿⣿
-⢸⣿⣿⣿⡇ ⣀⣴⣾⣿⣿⣿⡿⠋ ⢹⣿⡆ ⣴⣿⠟⢹⣿⡀ ⢸⣿⡿
-⢸⣿⡟⣿⣿⣄ ⣀⣤⣶⣿⣿⣿⣿⣿⡟⠉ ⠈⣿⣷ ⢠⣾⡿⠋ ⢸⣿⡇ ⣼⣿⡇
-⢸⣿⡇⢹⣿⣿⣷⣦⣤⣤⣤⣤⣤⣴⣶⣾⣿⣿⣿⣿⡿⠿⣿⣿⣿⣿⣷⣶⣤⣤⣀⡀ ⢹⣿⡆ ⢀⣴⣿⠟ ⣿⣧ ⣿⣿⡇
-⢸⣿⠃ â¢¿â£¿â£¿â£¿â£¿â£¿â£¿â¡¿â ¿â ¿â ›â ›â ‰â ‰â  â¢°â£¿â Ÿâ£¿â£·â¡€â ‰â ™â ›â ¿â¢¿â£¿â£¶â£¦â£¤â£€â¡€ ⠈⣿⣷ â£ â£¿â¡¿â  â¢¿â£¿ ⣿⣿⡇
-⢸⣿ â¢€â£¾â£¿â£¿â ‹â ‰â  â¢€â£¿â¡¿ ⠘⣿⣷⡀ ⠉⠙⠛⠿⠿⣿⣶⣦⣤⣄⣀ ⢹⣿⡄ ⣠⣾⡿⠋ ⢸⣿⡆ ⣿⣿
-⣸⣿⢀⣾⣿⣿⣿⣆ ⣸⣿⠃ ⠘⢿⣷⡀ ⠈⠉⠛⠻⠿⣿⣷⣶⣤⣌⣿⣷⣾⡿⠋ ⠘⣿⡇ ⣿⣿
-⣿⣿⣾⡿⣿⡿⠹⣿⡆ ⢠⣿⡠⠈⢿⣷⡀ ⠈⠉⠙⣻⣿⣿⣿⣀ ⣿⣷⢰⣿⣿
-⣿⣿⡿â¢â£¿â¡‡ ⢻⣿⡄ ⣾⣿ ⠈⢿⣷⡀ ⢀⣤⣾⡿⠋⠈⠻⢿⣷⣄ ⢻⣿⢸⣿⡟
-⣿⣿â â¢¸â£¿â¡‡ ⢻⣿⡄ ⢸⣿⠇ ⠈⢿⣷⡀ ⣀⣴⣿⠟⠋ ⠙⢿⣷⣤⡀ ⢸⣿⣿⣿⡇
-⣿⣿ â¢¸â£¿â  â ˆâ¢¿â£·â¡€ ⢀⣿⡟ ⠈⢿⣷⡀ â¢€â£¤â£¾â¡¿â ›â  â ™â »â£¿â£¦â¡€ ⠈⣿⣿⣿⡇
-⢸⣿⡄⣿⣿ ⠈⣿⣷⡀ ⣼⣿⠃ ⠈⢿⣷⡀ ⢀⣠⣶⣿⠟⠋ ⠈⠻⣿⣦⣄ ⣿⣿⣿⠇
-⠈⣿⣷⣿⡿ ⠘⣿⣧ ⢠⣿⡠⠈⢿⣷⣄⣤⣶⣿⠟⠋ ⠈⠛⢿⣷⣄ ⢸⣿⣿
- ⠘⣿⣿⡇ ⠘⣿⣧ ⣾⣿ ⢀⣠⣼⣿⣿⣿⣿⣿⣷⣶⣶⣶⣶⣶⣶⣤⣤⣤⣤⣤⣤⣀⣀⣀⣀⣀⣀⡀ ⠙⢿⣷⣼⣿⣿
- ⠈⠻⣿⣦⡀ ⠹⣿⣆⢸⣿⠇ â£€â£ â£´â£¾â¡¿â Ÿâ ‹â  â ‰â ‰â ‰â ‰â ‰â ‰â ›â ›â£›â£›â£›â£»â£¿â£¿â£¿â£¿â£¿â£¿â£¿â£¿â£¿â£¿â£·â£¿â£¿â£¿â¡¿
- ⠈⠻⢿⣷⣦⣄⣀⡀ ⢹⣿⣿⡟ ⢀⣀⣀⣤⣤⣶⣾⣿⣿⣿⣯⣥⣤⣤⣤⣤⣶⣶⣶⣶⣶⣶⣶⣾⣿⣿⣿⣿⠿⠿⠿⠿⠿⠿⠿⠟⠛⠛⠛⠛⠛⠛⠛⠉⠉⠉⠉⠉⠉
- ⠉⠙⠛⠿⠿⠿⣿⣿⣿⣿⠿⠿⠿⠿⠿⠿⠿⠛⠛⠛⠛⠛⠛⠛⠋⠉⠉⠉⠉⠉⠉⠉
-TYPE: UNICODE
- ⣀⣤⣴⣾⣿⣿⣿⡛⠛⠛⠛⠛⣻⣿⠿⠛⠛⠶⣤⡀
- â£€â£´â ¾â ›â ‰â  â ™â£¿â£¶â£¤â£¶â£Ÿâ£‰ ⠈⠻⣦
- ⣀⣴⠟⠋ ⢸⣿⠟⠻⣯⡙⠛⠛⠛⠶⠶⠶⢶⣽⣇
- â£ â¡¾â ‹â  â£¾â¡¿ ⠈⠛⢦⣄ ⣿
- ⣠⡾⠋ ⣰⣿⠃ ⠙⠷⣤⡀ ⣿
- ⢀⡾⠋ ⣰⣿⡠⠈⠻⣦⣄⢠⣿
- â£°â Ÿâ  â£´â£¿â£¿â£â£€â£ â£¤â£¤â£¤â£¤â£¤â£¤â£¤â£´â ¶â ¿â£¿â¡
- â£¼â  â¢€â£¾â£¿â Ÿâ£¿â ¿â£¯â£â  ⣰⣿⡇
- ⢀⣼⠋ â¢€â£´â£¿â Ÿâ  â¢¸â¡‡ ⠙⠻⢦⣄⡀ ⢠⡿⣿⡇
-â¢€â£¾â¡ â¢€â£´â£¿â Ÿâ  â£¿ ⠉⠻⢶⣄⡀⣰⡟ ⣿⠃
-â£¾â£¿â  â£ â£¶â¡¿â ‹â  â¢¹â¡‡ ⠈⣿⡠⢸⣿
-⣿⣿⡆ ⢀⣠⣴⣿⡿⠋ ⠈⣿ ⢀⡾⠋⣿ ⢸⣿
-⣿⠸⣿⣶⣤⣤⣤⣤⣶⣾⠿⠿⣿⣿⠶⣤⣤⣀⡀ ⢹⡇ â£´â Ÿâ  â£¿â¡€â¢¸â£¿
-â£¿â¢€â£¿â£Ÿâ ›â ‹â ‰â  â¢°â¡Ÿâ ¹â£§ ⠈⠉⠛⠻⠶⢦⣤⣀⡀ ⠈⣿ ⣠⡾⠃ ⢸⡇⢸⡇
-⣿⣾⣿⢿⡄ â£¿â  â ˜â£§ ⠉⠙⠛⠷⣿⣿⡋ ⠸⣇⣸⡇
-⣿⠃⣿⠈⢿⡄ ⣸⠇ ⠘⣧ ⢀⣤⠾⠋⠈⠻⣦⡀ ⣿⣿⡇
-⣿⢸⡠⠈⣷⡀ ⢠⡿ ⠘⣧⡀ â£ â¡´â Ÿâ  â ˆâ »â£¦â£€ ⢿⣿â 
-⢻⣾⡇ ⠘⣷ ⣼⠃ ⠘⣷⣠⣴⠟⠋ ⠙⢷⣄⢸⣿
- ⠻⣧⡀ ⠘⣧⣰⡠⢀⣠⣤⠶⠛⠉⠛⠛⠛⠛⠛⠛⠻⢶⣶⣶⣶⣶⣶⣤⣤⣽⣿⣿
- ⠈⠛⠷⢦⣤⣽⣿⣥⣤⣶⣶⡿⠿⠿⠶⠶⠶⠶⠾⠛⠛⠛⠛⠛⠛⠛⠋⠉⠉⠉⠉⠉⠉â 
+ -+smJYYN?mm-
+ HB"BBYT TQg NggT
+ 9Q+g Nm,T 8g NJW
+ YS+ N2NJ"Sg N?
+ BQg #( gT Nggggk J
+ 5j NJ NJ NNge
+ #Q #JJ NgT N(
+ @j bj mT J
+ Bj @/d NJ (
+ #q #(( NgT #J
+ 5d #(t mT $d
+ #q @(@J NJB;
+ @( 5d ? HHH H HQmgggggggmN qD
+ 5d #uN 2QdH E O
+ 5 5JSd Nd NJH @d j
+ Fd @J4d s NQH #d (
+ #( #o6d Nd NgH #d #d
+ 4 B&Od v NgT #d F
+ #( 9JGd NH NgUd F
+ #d #GJQ d NP $
+ #J #U+#Q N Q # j
+ j /W BQ+ BQ d NJ NJ
+ - NjJH HBIjTQggPJQgW N W k #J
+ #J b HYWgggN j s Nag d NN b #d
+ #J 5- D s Ngg N d Nd F
+ Fd BKH2 #+ s NNgg J Q J ]
+ F H @ J N y K(d P I
+ F4 E N? #d y #Q NJ E j
+ F W Nd q m Bg NxW N(H-
+ F d b @ m Hd gW vKJ
+ NJ d K d s Bg aT FDd
+ b # d N m BQ mV N>
+ e5 Nd #d NggggggQWH HHHH NJ -
+ m7 NW H N HSVO1z=?11-
+ NgTH bB kH WBHWWHBHWmQgg&gggggNNN
+ NNggggggNN
diff --git a/lib/irb/source_finder.rb b/lib/irb/source_finder.rb
deleted file mode 100644
index c515da5702..0000000000
--- a/lib/irb/source_finder.rb
+++ /dev/null
@@ -1,139 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "ruby-lex"
-
-module IRB
- class SourceFinder
- class EvaluationError < StandardError; end
-
- class Source
- attr_reader :file, :line
- def initialize(file, line, ast_source = nil)
- @file = file
- @line = line
- @ast_source = ast_source
- end
-
- def file_exist?
- File.exist?(@file)
- end
-
- def binary_file?
- # If the line is zero, it means that the target's source is probably in a binary file.
- @line.zero?
- end
-
- def file_content
- @file_content ||= File.read(@file)
- end
-
- def colorized_content
- if !binary_file? && file_exist?
- end_line = find_end
- # To correctly colorize, we need to colorize full content and extract the relevant lines.
- colored = IRB::Color.colorize_code(file_content)
- colored.lines[@line - 1...end_line].join
- elsif @ast_source
- IRB::Color.colorize_code(@ast_source)
- end
- end
-
- private
-
- def find_end
- lex = RubyLex.new
- code = file_content
- lines = code.lines[(@line - 1)..-1]
- tokens = RubyLex.ripper_lex_without_warning(lines.join)
- prev_tokens = []
-
- # chunk with line number
- tokens.chunk { |tok| tok.pos[0] }.each do |lnum, chunk|
- code = lines[0..lnum].join
- prev_tokens.concat chunk
- continue = lex.should_continue?(prev_tokens)
- syntax = lex.check_code_syntax(code, local_variables: [])
- if !continue && syntax == :valid
- return @line + lnum
- end
- end
- @line
- end
- end
-
- private_constant :Source
-
- def initialize(irb_context)
- @irb_context = irb_context
- end
-
- def find_source(signature, super_level = 0)
- case signature
- when /\A(::)?[A-Z]\w*(::[A-Z]\w*)*\z/ # ConstName, ::ConstName, ConstPath::ConstName
- eval_receiver_or_owner(signature) # trigger autoload
- *parts, name = signature.split('::', -1)
- base =
- if parts.empty? # ConstName
- find_const_owner(name)
- elsif parts == [''] # ::ConstName
- Object
- else # ConstPath::ConstName
- eval_receiver_or_owner(parts.join('::'))
- end
- file, line = base.const_source_location(name)
- when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
- owner = eval_receiver_or_owner(Regexp.last_match[:owner])
- method = Regexp.last_match[:method]
- return unless owner.respond_to?(:instance_method)
- method = method_target(owner, super_level, method, "owner")
- file, line = method&.source_location
- when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/ # method, receiver.method, receiver::method
- receiver = eval_receiver_or_owner(Regexp.last_match[:receiver] || 'self')
- method = Regexp.last_match[:method]
- return unless receiver.respond_to?(method, true)
- method = method_target(receiver, super_level, method, "receiver")
- file, line = method&.source_location
- end
- return unless file && line
-
- if File.exist?(file)
- Source.new(file, line)
- elsif method
- # Method defined with eval, probably in IRB session
- source = RubyVM::InstructionSequence.of(method)&.script_lines&.join rescue nil
- Source.new(file, line, source)
- end
- rescue EvaluationError
- nil
- end
-
- private
-
- def method_target(owner_receiver, super_level, method, type)
- case type
- when "owner"
- target_method = owner_receiver.instance_method(method)
- when "receiver"
- target_method = owner_receiver.method(method)
- end
- super_level.times do |s|
- target_method = target_method.super_method if target_method
- end
- target_method
- rescue NameError
- nil
- end
-
- def eval_receiver_or_owner(code)
- context_binding = @irb_context.workspace.binding
- eval(code, context_binding)
- rescue NameError
- raise EvaluationError
- end
-
- def find_const_owner(name)
- module_nesting = @irb_context.workspace.binding.eval('::Module.nesting')
- module_nesting.find { |mod| mod.const_defined?(name, false) } || module_nesting.find { |mod| mod.const_defined?(name) } || Object
- end
- end
-end
diff --git a/lib/irb/src_encoding.rb b/lib/irb/src_encoding.rb
new file mode 100644
index 0000000000..99aea2b43e
--- /dev/null
+++ b/lib/irb/src_encoding.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: false
+# DO NOT WRITE ANY MAGIC COMMENT HERE.
+module IRB
+ def self.default_src_encoding
+ return __ENCODING__
+ end
+end
diff --git a/lib/irb/statement.rb b/lib/irb/statement.rb
deleted file mode 100644
index 9591a40357..0000000000
--- a/lib/irb/statement.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# frozen_string_literal: true
-
-module IRB
- class Statement
- attr_reader :code
-
- def is_assignment?
- raise NotImplementedError
- end
-
- def suppresses_echo?
- raise NotImplementedError
- end
-
- def should_be_handled_by_debugger?
- raise NotImplementedError
- end
-
- class EmptyInput < Statement
- def is_assignment?
- false
- end
-
- def suppresses_echo?
- true
- end
-
- # Debugger takes empty input to repeat the last command
- def should_be_handled_by_debugger?
- true
- end
-
- def code
- ""
- end
- end
-
- class Expression < Statement
- def initialize(code, is_assignment)
- @code = code
- @is_assignment = is_assignment
- end
-
- def suppresses_echo?
- @code.match?(/;\s*\z/)
- end
-
- def should_be_handled_by_debugger?
- true
- end
-
- def is_assignment?
- @is_assignment
- end
- end
-
- class Command < Statement
- attr_reader :command_class, :arg
-
- def initialize(original_code, command_class, arg)
- @code = original_code
- @command_class = command_class
- @arg = arg
- end
-
- def is_assignment?
- false
- end
-
- def suppresses_echo?
- true
- end
-
- def should_be_handled_by_debugger?
- require_relative 'command/debug'
- IRB::Command::DebugCommand > @command_class
- end
- end
- end
-end
diff --git a/lib/irb/version.rb b/lib/irb/version.rb
index 955a3a81da..d1c0e54fdc 100644
--- a/lib/irb/version.rb
+++ b/lib/irb/version.rb
@@ -1,11 +1,17 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/version.rb - irb version definition file
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
#
+# --
+#
+#
+#
module IRB # :nodoc:
- VERSION = "1.14.1"
+ VERSION = "1.6.2"
@RELEASE_VERSION = VERSION
- @LAST_UPDATE_DATE = "2024-09-25"
+ @LAST_UPDATE_DATE = "2022-12-13"
end
diff --git a/lib/irb/workspace.rb b/lib/irb/workspace.rb
index 632b432439..e5ef52528a 100644
--- a/lib/irb/workspace.rb
+++ b/lib/irb/workspace.rb
@@ -1,13 +1,17 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/workspace-binding.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
require "delegate"
-require_relative "helper_method"
-
IRB::TOPLEVEL_BINDING = binding
module IRB # :nodoc:
class WorkSpace
@@ -92,11 +96,11 @@ EOF
IRB.conf[:__MAIN__] = @main
@main.singleton_class.class_eval do
private
+ define_method(:exit) do |*a, &b|
+ # Do nothing, will be overridden
+ end
define_method(:binding, Kernel.instance_method(:binding))
define_method(:local_variables, Kernel.instance_method(:local_variables))
- # Define empty method to avoid delegator warning, will be overridden.
- define_method(:exit) {|*a, &b| }
- define_method(:exit!) {|*a, &b| }
end
@binding = eval("IRB.conf[:__MAIN__].instance_eval('binding', __FILE__, __LINE__)", @binding, *@binding.source_location)
end
@@ -110,14 +114,8 @@ EOF
# <code>IRB.conf[:__MAIN__]</code>
attr_reader :main
- def load_helper_methods_to_main
- ancestors = class<<main;ancestors;end
- main.extend ExtendCommandBundle if !ancestors.include?(ExtendCommandBundle)
- main.extend HelpersContainer if !ancestors.include?(HelpersContainer)
- end
-
# Evaluate the given +statements+ within the context of this workspace.
- def evaluate(statements, file = __FILE__, line = __LINE__)
+ def evaluate(context, statements, file = __FILE__, line = __LINE__)
eval(statements, @binding, file, line)
end
@@ -130,8 +128,6 @@ EOF
end
# error message manipulator
- # WARN: Rails patches this method to filter its own backtrace. Be cautious when changing it.
- # See: https://github.com/rails/rails/blob/main/railties/lib/rails/commands/console/console_command.rb#L8:~:text=def,filter_backtrace
def filter_backtrace(bt)
return nil if bt =~ /\/irb\/.*\.rb/
return nil if bt =~ /\/irb\.rb/
@@ -146,7 +142,11 @@ EOF
end
def code_around_binding
- file, pos = @binding.source_location
+ if @binding.respond_to?(:source_location)
+ file, pos = @binding.source_location
+ else
+ file, pos = @binding.eval('[__FILE__, __LINE__]')
+ end
if defined?(::SCRIPT_LINES__[file]) && lines = ::SCRIPT_LINES__[file]
code = ::SCRIPT_LINES__[file].join('')
@@ -173,19 +173,8 @@ EOF
"\nFrom: #{file} @ line #{pos + 1} :\n\n#{body}#{Color.clear}\n"
end
- end
- module HelpersContainer
- class << self
- def install_helper_methods
- HelperMethod.helper_methods.each do |name, helper_method_class|
- define_method name do |*args, **opts, &block|
- helper_method_class.instance.execute(*args, **opts, &block)
- end unless method_defined?(name)
- end
- end
+ def IRB.delete_caller
end
-
- install_helper_methods
end
end
diff --git a/lib/irb/ws-for-case-2.rb b/lib/irb/ws-for-case-2.rb
index 03f42d73d9..eb173fddca 100644
--- a/lib/irb/ws-for-case-2.rb
+++ b/lib/irb/ws-for-case-2.rb
@@ -1,8 +1,14 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# irb/ws-for-case-2.rb -
+# $Release Version: 0.9.6$
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
+# --
+#
+#
+#
while true
IRB::BINDING_QUEUE.push _ = binding
diff --git a/lib/irb/xmp.rb b/lib/irb/xmp.rb
index b1bc53283e..88cbd88525 100644
--- a/lib/irb/xmp.rb
+++ b/lib/irb/xmp.rb
@@ -1,8 +1,14 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
#
# xmp.rb - irb version of gotoken xmp
+# $Release Version: 0.9$
+# $Revision$
# by Keiju ISHITSUKA(Nippon Rational Inc.)
#
+# --
+#
+#
+#
require_relative "../irb"
require_relative "frame"
@@ -44,8 +50,8 @@ class XMP
# The top-level binding or, optional +bind+ parameter will be used when
# creating the workspace. See WorkSpace.new for more information.
#
- # This uses the +:XMP+ prompt mode.
- # See {Custom Prompts}[rdoc-ref:IRB@Custom+Prompts] for more information.
+ # This uses the +:XMP+ prompt mode, see IRB@Customizing+the+IRB+Prompt for
+ # full detail.
def initialize(bind = nil)
IRB.init_config(nil)
diff --git a/lib/logger.rb b/lib/logger.rb
index 63179ec671..7e4dacc911 100644
--- a/lib/logger.rb
+++ b/lib/logger.rb
@@ -10,7 +10,6 @@
#
# A simple system for logging messages. See Logger for more documentation.
-require 'fiber'
require 'monitor'
require 'rbconfig'
@@ -265,7 +264,8 @@ require_relative 'logger/errors'
# logger.error! # => 3
# logger.fatal! # => 4
#
-# You can retrieve the log level with method #level.
+# You can retrieve the log level with method
+# {level}[Logger.html#attribute-i-level]:
#
# logger.level = Logger::ERROR
# logger.level # => 3
@@ -380,9 +380,7 @@ class Logger
include Severity
# Logging severity threshold (e.g. <tt>Logger::INFO</tt>).
- def level
- level_override[Fiber.current] || @level
- end
+ attr_reader :level
# Sets the log level; returns +severity+.
# See {Log Level}[rdoc-ref:Logger@Log+Level].
@@ -397,23 +395,24 @@ class Logger
# Logger#sev_threshold= is an alias for Logger#level=.
#
def level=(severity)
- @level = Severity.coerce(severity)
- end
-
- # Adjust the log level during the block execution for the current Fiber only
- #
- # logger.with_level(:debug) do
- # logger.debug { "Hello" }
- # end
- def with_level(severity)
- prev, level_override[Fiber.current] = level, Severity.coerce(severity)
- begin
- yield
- ensure
- if prev
- level_override[Fiber.current] = prev
+ if severity.is_a?(Integer)
+ @level = severity
+ else
+ case severity.to_s.downcase
+ when 'debug'
+ @level = DEBUG
+ when 'info'
+ @level = INFO
+ when 'warn'
+ @level = WARN
+ when 'error'
+ @level = ERROR
+ when 'fatal'
+ @level = FATAL
+ when 'unknown'
+ @level = UNKNOWN
else
- level_override.delete(Fiber.current)
+ raise ArgumentError, "invalid log level: #{severity}"
end
end
end
@@ -574,27 +573,21 @@ class Logger
# - +shift_period_suffix+: sets the format for the filename suffix
# for periodic log file rotation; default is <tt>'%Y%m%d'</tt>.
# See {Periodic Rotation}[rdoc-ref:Logger@Periodic+Rotation].
- # - +reraise_write_errors+: An array of exception classes, which will
- # be reraised if there is an error when writing to the log device.
- # The default is to swallow all exceptions raised.
#
def initialize(logdev, shift_age = 0, shift_size = 1048576, level: DEBUG,
progname: nil, formatter: nil, datetime_format: nil,
- binmode: false, shift_period_suffix: '%Y%m%d',
- reraise_write_errors: [])
+ binmode: false, shift_period_suffix: '%Y%m%d')
self.level = level
self.progname = progname
@default_formatter = Formatter.new
self.datetime_format = datetime_format
self.formatter = formatter
@logdev = nil
- @level_override = {}
if logdev && logdev != File::NULL
@logdev = LogDevice.new(logdev, shift_age: shift_age,
shift_size: shift_size,
shift_period_suffix: shift_period_suffix,
- binmode: binmode,
- reraise_write_errors: reraise_write_errors)
+ binmode: binmode)
end
end
@@ -746,11 +739,6 @@ private
SEV_LABEL[severity] || 'ANY'
end
- # Guarantee the existence of this ivar even when subclasses don't call the superclass constructor.
- def level_override
- @level_override ||= {}
- end
-
def format_message(severity, datetime, progname, msg)
(@formatter || @default_formatter).call(severity, datetime, progname, msg)
end
diff --git a/lib/logger/log_device.rb b/lib/logger/log_device.rb
index 4876adf0b7..84277a2656 100644
--- a/lib/logger/log_device.rb
+++ b/lib/logger/log_device.rb
@@ -11,10 +11,9 @@ class Logger
attr_reader :filename
include MonitorMixin
- def initialize(log = nil, shift_age: nil, shift_size: nil, shift_period_suffix: nil, binmode: false, reraise_write_errors: [])
+ def initialize(log = nil, shift_age: nil, shift_size: nil, shift_period_suffix: nil, binmode: false)
@dev = @filename = @shift_age = @shift_size = @shift_period_suffix = nil
@binmode = binmode
- @reraise_write_errors = reraise_write_errors
mon_initialize
set_dev(log)
if @filename
@@ -35,22 +34,16 @@ class Logger
if @shift_age and @dev.respond_to?(:stat)
begin
check_shift_log
- rescue *@reraise_write_errors
- raise
rescue
warn("log shifting failed. #{$!}")
end
end
begin
@dev.write(message)
- rescue *@reraise_write_errors
- raise
rescue
warn("log writing failed. #{$!}")
end
end
- rescue *@reraise_write_errors
- raise
rescue Exception => ignored
warn("log writing failed. #{ignored}")
end
diff --git a/lib/logger/logger.gemspec b/lib/logger/logger.gemspec
index 5e8232e4ab..d12db625d9 100644
--- a/lib/logger/logger.gemspec
+++ b/lib/logger/logger.gemspec
@@ -18,5 +18,9 @@ Gem::Specification.new do |spec|
spec.files = Dir.glob("lib/**/*.rb") + ["logger.gemspec"]
spec.require_paths = ["lib"]
- spec.required_ruby_version = ">= 2.5.0"
+ spec.required_ruby_version = ">= 2.3.0"
+
+ spec.add_development_dependency "bundler", ">= 0"
+ spec.add_development_dependency "rake", ">= 12.3.3"
+ spec.add_development_dependency "test-unit"
end
diff --git a/lib/logger/period.rb b/lib/logger/period.rb
index a0359defe3..0a291dbbbe 100644
--- a/lib/logger/period.rb
+++ b/lib/logger/period.rb
@@ -8,14 +8,14 @@ class Logger
def next_rotate_time(now, shift_age)
case shift_age
- when 'daily', :daily
+ when 'daily'
t = Time.mktime(now.year, now.month, now.mday) + SiD
- when 'weekly', :weekly
+ when 'weekly'
t = Time.mktime(now.year, now.month, now.mday) + SiD * (7 - now.wday)
- when 'monthly', :monthly
+ when 'monthly'
t = Time.mktime(now.year, now.month, 1) + SiD * 32
return Time.mktime(t.year, t.month, 1)
- when 'now', 'everytime', :now, :everytime
+ when 'now', 'everytime'
return now
else
raise ArgumentError, "invalid :shift_age #{shift_age.inspect}, should be daily, weekly, monthly, or everytime"
@@ -30,13 +30,13 @@ class Logger
def previous_period_end(now, shift_age)
case shift_age
- when 'daily', :daily
+ when 'daily'
t = Time.mktime(now.year, now.month, now.mday) - SiD / 2
- when 'weekly', :weekly
+ when 'weekly'
t = Time.mktime(now.year, now.month, now.mday) - (SiD * now.wday + SiD / 2)
- when 'monthly', :monthly
+ when 'monthly'
t = Time.mktime(now.year, now.month, 1) - SiD / 2
- when 'now', 'everytime', :now, :everytime
+ when 'now', 'everytime'
return now
else
raise ArgumentError, "invalid :shift_age #{shift_age.inspect}, should be daily, weekly, monthly, or everytime"
diff --git a/lib/logger/severity.rb b/lib/logger/severity.rb
index e96fb0d320..b38afb7d22 100644
--- a/lib/logger/severity.rb
+++ b/lib/logger/severity.rb
@@ -15,24 +15,5 @@ class Logger
FATAL = 4
# An unknown message that should always be logged.
UNKNOWN = 5
-
- LEVELS = {
- "debug" => DEBUG,
- "info" => INFO,
- "warn" => WARN,
- "error" => ERROR,
- "fatal" => FATAL,
- "unknown" => UNKNOWN,
- }
- private_constant :LEVELS
-
- def self.coerce(severity)
- if severity.is_a?(Integer)
- severity
- else
- key = severity.to_s.downcase
- LEVELS[key] || raise(ArgumentError, "invalid log level: #{severity}")
- end
- end
end
end
diff --git a/lib/logger/version.rb b/lib/logger/version.rb
index 2a0801be63..f85c72eed3 100644
--- a/lib/logger/version.rb
+++ b/lib/logger/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
class Logger
- VERSION = "1.6.1"
+ VERSION = "1.5.3"
end
diff --git a/lib/mkmf.rb b/lib/mkmf.rb
index d970e9a6ad..0fbc1cc2e5 100644
--- a/lib/mkmf.rb
+++ b/lib/mkmf.rb
@@ -44,23 +44,6 @@ end
# correctly compile and link the C extension to Ruby and a third-party
# library.
module MakeMakefile
-
- target_rbconfig = nil
- ARGV.delete_if do |arg|
- opt = arg.delete_prefix("--target-rbconfig=")
- unless opt == arg
- target_rbconfig = opt
- end
- end
- if target_rbconfig
- # Load the RbConfig for the target platform into this module.
- # Cross-compiling needs the same version of Ruby.
- Kernel.load target_rbconfig, self
- else
- # The RbConfig for the target platform where the built extension runs.
- RbConfig = ::RbConfig
- end
-
#### defer until this module become global-state free.
# def self.extended(obj)
# obj.init_mkmf
@@ -76,9 +59,6 @@ module MakeMakefile
# The makefile configuration using the defaults from when Ruby was built.
CONFIG = RbConfig::MAKEFILE_CONFIG
-
- ##
- # The saved original value of +LIB+ environment variable
ORIG_LIBPATH = ENV['LIB']
##
@@ -109,16 +89,26 @@ module MakeMakefile
unless defined? $configure_args
$configure_args = {}
- args = CONFIG["configure_args"].shellsplit
- if arg = ENV["CONFIGURE_ARGS"]
- args.push(*arg.shellsplit)
+ args = CONFIG["configure_args"]
+ if ENV["CONFIGURE_ARGS"]
+ args << " " << ENV["CONFIGURE_ARGS"]
end
- args.delete_if {|a| /\A--(?:top(?:src)?|src|cur)dir(?=\z|=)/ =~ a}
- for arg in args.concat(ARGV)
+ for arg in Shellwords::shellwords(args)
arg, val = arg.split('=', 2)
next unless arg
arg.tr!('_', '-')
- if arg.sub!(/\A(?!--)/, '--')
+ if arg.sub!(/^(?!--)/, '--')
+ val or next
+ arg.downcase!
+ end
+ next if /^--(?:top|topsrc|src|cur)dir$/ =~ arg
+ $configure_args[arg] = val || true
+ end
+ for arg in ARGV
+ arg, val = arg.split('=', 2)
+ next unless arg
+ arg.tr!('_', '-')
+ if arg.sub!(/^(?!--)/, '--')
val or next
arg.downcase!
end
@@ -265,16 +255,12 @@ MESSAGE
CSRCFLAG = CONFIG['CSRCFLAG']
CPPOUTFILE = config_string('CPPOUTFILE') {|str| str.sub(/\bconftest\b/, CONFTEST)}
- # :startdoc:
-
- # Removes _files_.
def rm_f(*files)
opt = (Hash === files.last ? [files.pop] : [])
FileUtils.rm_f(Dir[*files.flatten], *opt)
end
module_function :rm_f
- # Removes _files_ recursively.
def rm_rf(*files)
opt = (Hash === files.last ? [files.pop] : [])
FileUtils.rm_rf(Dir[*files.flatten], *opt)
@@ -289,8 +275,6 @@ MESSAGE
t if times.all? {|n| n <= t}
end
- # :stopdoc:
-
def split_libs(*strs)
sep = $mswin ? /\s+/ : /\s+(?=-|\z)/
strs.flat_map {|s| s.lstrip.split(sep)}
@@ -416,11 +400,6 @@ MESSAGE
env, *commands = commands if Hash === commands.first
envs.merge!(env) if env
end
-
- # disable ASAN leak reporting - conftest programs almost always don't bother
- # to free their memory.
- envs['ASAN_OPTIONS'] = "detect_leaks=0" unless ENV.key?('ASAN_OPTIONS')
-
return envs, expand[commands]
end
@@ -428,19 +407,11 @@ MESSAGE
envs.map {|e, v| "#{e}=#{v.quote}"}
end
- # :startdoc:
-
- # call-seq:
- # xsystem(command, werror: false) -> true or false
- #
- # Executes _command_ with expanding variables, and returns the exit
- # status like as Kernel#system. If _werror_ is true and the error
- # output is not empty, returns +false+. The output will logged.
- def xsystem(command, werror: false)
+ def xsystem command, opts = nil
env, command = expand_command(command)
Logging::open do
puts [env_quote(env), command.quote].join(' ')
- if werror
+ if opts and opts[:werror]
result = nil
Logging.postpone do |log|
output = IO.popen(env, command, &:read)
@@ -454,7 +425,6 @@ MESSAGE
end
end
- # Executes _command_ similarly to xsystem, but yields opened pipe.
def xpopen command, *mode, &block
env, commands = expand_command(command)
command = [env_quote(env), command].join(' ')
@@ -469,7 +439,6 @@ MESSAGE
end
end
- # Logs _src_
def log_src(src, heading="checked program was")
src = src.split(/^/)
fmt = "%#{src.size.to_s.size}d: %s"
@@ -484,15 +453,10 @@ EOM
EOM
end
- # Returns the language-dependent source file name for configuration
- # checks.
def conftest_source
CONFTEST_C
end
- # Creats temporary source file from +COMMON_HEADERS+ and _src_.
- # Yields the created source string and uses the returned string as
- # the source code, if the block is given.
def create_tmpsrc(src)
src = "#{COMMON_HEADERS}\n#{src}"
src = yield(src) if block_given?
@@ -513,8 +477,6 @@ EOM
src
end
- # :stopdoc:
-
def have_devel?
unless defined? $have_devel
$have_devel = true
@@ -523,7 +485,7 @@ EOM
$have_devel
end
- def try_do(src, command, **opts, &b)
+ def try_do(src, command, *opts, &b)
unless have_devel?
raise <<MSG
The compiler failed to generate an executable file.
@@ -532,7 +494,7 @@ MSG
end
begin
src = create_tmpsrc(src, &b)
- xsystem(command, **opts)
+ xsystem(command, *opts)
ensure
log_src(src)
end
@@ -583,28 +545,28 @@ MSG
end
def libpathflag(libpath=$DEFLIBPATH|$LIBPATH)
- libpathflags = nil
libpath.map{|x|
case x
when "$(topdir)", /\A\./
LIBPATHFLAG
else
- libpathflags ||= [LIBPATHFLAG, RPATHFLAG].grep(/\S/).join(" ")
+ LIBPATHFLAG+RPATHFLAG
end % x.quote
- }.join(" ")
- end
-
- def werror_flag(opt = nil)
- config_string("WERRORFLAG") {|flag| opt = opt && !opt.empty? ? "#{opt} #{flag}" : flag}
- opt
+ }.join
end
def with_werror(opt, opts = nil)
- opt = werror_flag(opt) if opts and (opts = opts.dup).delete(:werror)
- yield(opt, opts)
+ if opts
+ if opts[:werror] and config_string("WERRORFLAG") {|flag| opt = opt ? "#{opt} #{flag}" : flag}
+ (opts = opts.dup).delete(:werror)
+ end
+ yield(opt, opts)
+ else
+ yield(opt)
+ end
end
- def try_link0(src, opt = "", **opts, &b) # :nodoc:
+ def try_link0(src, opt="", *opts, &b) # :nodoc:
exe = CONFTEST+$EXEEXT
cmd = link_command("", opt)
if $universal
@@ -612,13 +574,13 @@ MSG
Dir.mktmpdir("mkmf_", oldtmpdir = ENV["TMPDIR"]) do |tmpdir|
begin
ENV["TMPDIR"] = tmpdir
- try_do(src, cmd, **opts, &b)
+ try_do(src, cmd, *opts, &b)
ensure
ENV["TMPDIR"] = oldtmpdir
end
end
else
- try_do(src, cmd, **opts, &b)
+ try_do(src, cmd, *opts, &b)
end and File.executable?(exe) or return nil
exe
ensure
@@ -627,32 +589,31 @@ MSG
# Returns whether or not the +src+ can be compiled as a C source and linked
# with its depending libraries successfully. +opt+ is passed to the linker
- # as options. Note that <tt>$CFLAGS</tt> and <tt>$LDFLAGS</tt> are also
- # passed to the linker.
+ # as options. Note that +$CFLAGS+ and +$LDFLAGS+ are also passed to the
+ # linker.
#
# If a block given, it is called with the source before compilation. You can
# modify the source in the block.
#
# [+src+] a String which contains a C source
# [+opt+] a String which contains linker options
- def try_link(src, opt = "", **opts, &b)
- exe = try_link0(src, opt, **opts, &b) or return false
+ def try_link(src, opt="", *opts, &b)
+ exe = try_link0(src, opt, *opts, &b) or return false
MakeMakefile.rm_f exe
true
end
# Returns whether or not the +src+ can be compiled as a C source. +opt+ is
- # passed to the C compiler as options. Note that <tt>$CFLAGS</tt> is also
- # passed to the compiler.
+ # passed to the C compiler as options. Note that +$CFLAGS+ is also passed to
+ # the compiler.
#
# If a block given, it is called with the source before compilation. You can
# modify the source in the block.
#
# [+src+] a String which contains a C source
# [+opt+] a String which contains compiler options
- def try_compile(src, opt = "", werror: nil, **opts, &b)
- opt = werror_flag(opt) if werror
- try_do(src, cc_command(opt), werror: werror, **opts, &b) and
+ def try_compile(src, opt="", *opts, &b)
+ with_werror(opt, *opts) {|_opt, *| try_do(src, cc_command(_opt), *opts, &b)} and
File.file?("#{CONFTEST}.#{$OBJEXT}")
ensure
MakeMakefile.rm_f "#{CONFTEST}*"
@@ -660,15 +621,15 @@ MSG
# Returns whether or not the +src+ can be preprocessed with the C
# preprocessor. +opt+ is passed to the preprocessor as options. Note that
- # <tt>$CFLAGS</tt> is also passed to the preprocessor.
+ # +$CFLAGS+ is also passed to the preprocessor.
#
# If a block given, it is called with the source before preprocessing. You
# can modify the source in the block.
#
# [+src+] a String which contains a C source
# [+opt+] a String which contains preprocessor options
- def try_cpp(src, opt = "", **opts, &b)
- try_do(src, cpp_command(CPPOUTFILE, opt), **opts, &b) and
+ def try_cpp(src, opt="", *opts, &b)
+ try_do(src, cpp_command(CPPOUTFILE, opt), *opts, &b) and
File.file?("#{CONFTEST}.i")
ensure
MakeMakefile.rm_f "#{CONFTEST}*"
@@ -685,14 +646,6 @@ MSG
end
end
- # :startdoc:
-
- # Sets <tt>$CPPFLAGS</tt> to _flags_ and yields. If the block returns a
- # falsy value, <tt>$CPPFLAGS</tt> is reset to its previous value, remains
- # set to _flags_ otherwise.
- #
- # [+flags+] a C preprocessor flag as a +String+
- #
def with_cppflags(flags)
cppflags = $CPPFLAGS
$CPPFLAGS = flags.dup
@@ -701,29 +654,20 @@ MSG
$CPPFLAGS = cppflags unless ret
end
- # :nodoc:
- def try_cppflags(flags, werror: true, **opts)
- try_header(MAIN_DOES_NOTHING, flags, werror: werror, **opts)
+ def try_cppflags(flags, opts = {})
+ try_header(MAIN_DOES_NOTHING, flags, {:werror => true}.update(opts))
end
- # Check whether each given C preprocessor flag is acceptable and append it
- # to <tt>$CPPFLAGS</tt> if so.
- #
- # [+flags+] a C preprocessor flag as a +String+ or an +Array+ of them
- #
- def append_cppflags(flags, **opts)
+ def append_cppflags(flags, *opts)
Array(flags).each do |flag|
if checking_for("whether #{flag} is accepted as CPPFLAGS") {
- try_cppflags(flag, **opts)
+ try_cppflags(flag, *opts)
}
$CPPFLAGS << " " << flag
end
end
end
- # Sets <tt>$CFLAGS</tt> to _flags_ and yields. If the block returns a falsy
- # value, <tt>$CFLAGS</tt> is reset to its previous value, remains set to
- # _flags_ otherwise.
def with_cflags(flags)
cflags = $CFLAGS
$CFLAGS = flags.dup
@@ -732,14 +676,10 @@ MSG
$CFLAGS = cflags unless ret
end
- # :nodoc:
- def try_cflags(flags, werror: true, **opts)
- try_compile(MAIN_DOES_NOTHING, flags, werror: werror, **opts)
+ def try_cflags(flags, opts = {})
+ try_compile(MAIN_DOES_NOTHING, flags, {:werror => true}.update(opts))
end
- # Sets <tt>$LDFLAGS</tt> to _flags_ and yields. If the block returns a
- # falsy value, <tt>$LDFLAGS</tt> is reset to its previous value, remains set
- # to _flags_ otherwise.
def with_ldflags(flags)
ldflags = $LDFLAGS
$LDFLAGS = flags.dup
@@ -748,30 +688,21 @@ MSG
$LDFLAGS = ldflags unless ret
end
- # :nodoc:
- def try_ldflags(flags, werror: $mswin, **opts)
- try_link(MAIN_DOES_NOTHING, flags, werror: werror, **opts)
+ def try_ldflags(flags, opts = {})
+ opts = {:werror => true}.update(opts) if $mswin
+ try_link(MAIN_DOES_NOTHING, flags, opts)
end
- # :startdoc:
-
- # Check whether each given linker flag is acceptable and append it to
- # <tt>$LDFLAGS</tt> if so.
- #
- # [+flags+] a linker flag as a +String+ or an +Array+ of them
- #
- def append_ldflags(flags, **opts)
+ def append_ldflags(flags, *opts)
Array(flags).each do |flag|
if checking_for("whether #{flag} is accepted as LDFLAGS") {
- try_ldflags(flag, **opts)
+ try_ldflags(flag, *opts)
}
$LDFLAGS << " " << flag
end
end
end
- # :stopdoc:
-
def try_static_assert(expr, headers = nil, opt = "", &b)
headers = cpp_include(headers)
try_compile(<<SRC, opt, &b)
@@ -907,8 +838,6 @@ int t(void) { const volatile void *volatile p; p = &(&#{var})[0]; return !p; }
SRC
end
- # :startdoc:
-
# Returns whether or not the +src+ can be preprocessed with the C
# preprocessor and matches with +pat+.
#
@@ -947,8 +876,6 @@ SRC
log_src(src)
end
- # :stopdoc:
-
# This is used internally by the have_macro? method.
def macro_defined?(macro, src, opt = "", &b)
src = src.sub(/[^\n]\z/, "\\&\n")
@@ -968,8 +895,8 @@ SRC
# * the linked file can be invoked as an executable
# * and the executable exits successfully
#
- # +opt+ is passed to the linker as options. Note that <tt>$CFLAGS</tt> and
- # <tt>$LDFLAGS</tt> are also passed to the linker.
+ # +opt+ is passed to the linker as options. Note that +$CFLAGS+ and
+ # +$LDFLAGS+ are also passed to the linker.
#
# If a block given, it is called with the source before compilation. You can
# modify the source in the block.
@@ -1041,10 +968,6 @@ SRC
format(LIBARG, lib) + " " + libs
end
- # Prints messages to $stdout, if verbose mode.
- #
- # Internal use only.
- #
def message(*s)
unless Logging.quiet and not $VERBOSE
printf(*s)
@@ -1058,11 +981,7 @@ SRC
# Internal use only.
#
def checking_for(m, fmt = nil)
- if f = caller_locations(1, 1).first.base_label and /\A\w/ =~ f
- f += ": "
- else
- f = ""
- end
+ f = caller[0][/in `([^<].*)'$/, 1] and f << ": " #` for vim #'
m = "checking #{/\Acheck/ =~ f ? '' : 'for '}#{m}... "
message "%s", m
a = r = nil
@@ -1076,10 +995,6 @@ SRC
r
end
- # Build a message for checking.
- #
- # Internal use only.
- #
def checking_message(target, place = nil, opt = nil)
[["in", place], ["with", opt]].inject("#{target}") do |msg, (pre, noun)|
if noun
@@ -1104,10 +1019,10 @@ SRC
#
# [+flags+] a C compiler flag as a +String+ or an +Array+ of them
#
- def append_cflags(flags, **opts)
+ def append_cflags(flags, *opts)
Array(flags).each do |flag|
if checking_for("whether #{flag} is accepted as CFLAGS") {
- try_cflags(flag, **opts)
+ try_cflags(flag, *opts)
}
$CFLAGS << " " << flag
end
@@ -1341,7 +1256,6 @@ SRC
end
end
- # :nodoc:
# Returns whether or not the static type +type+ is defined.
#
# See also +have_type+
@@ -1399,7 +1313,6 @@ SRC
end
end
- # :nodoc:
# Returns whether or not the constant +const+ is defined.
#
# See also +have_const+
@@ -1559,7 +1472,7 @@ SRC
u = "unsigned " if signed > 0
prelude << "extern rbcv_typedef_ foo();"
compat = UNIVERSAL_INTS.find {|t|
- try_compile([prelude, "extern #{u}#{t} foo();"].join("\n"), opts, werror: true, &b)
+ try_compile([prelude, "extern #{u}#{t} foo();"].join("\n"), opts, :werror=>true, &b)
}
end
if compat
@@ -1583,7 +1496,7 @@ SRC
# Used internally by the what_type? method to determine if +type+ is a scalar
# pointer.
def scalar_ptr_type?(type, member = nil, headers = nil, &b)
- try_compile(<<"SRC", &b)
+ try_compile(<<"SRC", &b) # pointer
#{cpp_include(headers)}
/*top*/
volatile #{type} conftestval;
@@ -1596,7 +1509,7 @@ SRC
# Used internally by the what_type? method to determine if +type+ is a scalar
# pointer.
def scalar_type?(type, member = nil, headers = nil, &b)
- try_compile(<<"SRC", &b)
+ try_compile(<<"SRC", &b) # pointer
#{cpp_include(headers)}
/*top*/
volatile #{type} conftestval;
@@ -1618,10 +1531,6 @@ SRC
end
end
- # :startdoc:
-
- # Returns a string represents the type of _type_, or _member_ of
- # _type_ if _member_ is not +nil+.
def what_type?(type, member = nil, headers = nil, &b)
m = "#{type}"
var = val = "*rbcv_var_"
@@ -1681,8 +1590,6 @@ SRC
end
end
- # :nodoc:
- #
# This method is used internally by the find_executable method.
#
# Internal use only.
@@ -1721,6 +1628,8 @@ SRC
nil
end
+ # :startdoc:
+
# Searches for the executable +bin+ on +path+. The default path is your
# +PATH+ environment variable. If that isn't defined, it will resort to
# searching /usr/local/bin, /usr/ucb, /usr/bin and /bin.
@@ -1889,8 +1798,7 @@ SRC
# application.
#
def dir_config(target, idefault=nil, ldefault=nil)
- key = [target, idefault, ldefault].compact.join("\0")
- if conf = $config_dirs[key]
+ if conf = $config_dirs[target]
return conf
end
@@ -1900,13 +1808,9 @@ SRC
end
idir = with_config(target + "-include", idefault)
- if conf = $arg_config.assoc("--with-#{target}-include")
- conf[1] ||= "${#{target}-dir}/include"
- end
+ $arg_config.last[1] ||= "${#{target}-dir}/include"
ldir = with_config(target + "-lib", ldefault)
- if conf = $arg_config.assoc("--with-#{target}-lib")
- conf[1] ||= "${#{target}-dir}/#{_libdir_basename}"
- end
+ $arg_config.last[1] ||= "${#{target}-dir}/#{_libdir_basename}"
idirs = idir ? Array === idir ? idir.dup : idir.split(File::PATH_SEPARATOR) : []
if defaults
@@ -1928,7 +1832,7 @@ SRC
end
$LIBPATH = ldirs | $LIBPATH
- $config_dirs[key] = [idir, ldir]
+ $config_dirs[target] = [idir, ldir]
end
# Returns compile/link information about an installed library in a tuple of <code>[cflags,
@@ -1951,73 +1855,66 @@ SRC
# invoked with the options and a stripped output string is returned without
# modifying any of the global values mentioned above.
def pkg_config(pkg, *options)
- fmt = "not found"
- def fmt.%(x)
- x ? x.inspect : self
- end
-
- checking_for "pkg-config for #{pkg}", fmt do
- _, ldir = dir_config(pkg)
- if ldir
- pkg_config_path = "#{ldir}/pkgconfig"
- if File.directory?(pkg_config_path)
- Logging.message("PKG_CONFIG_PATH = %s\n", pkg_config_path)
- envs = ["PKG_CONFIG_PATH"=>[pkg_config_path, ENV["PKG_CONFIG_PATH"]].compact.join(File::PATH_SEPARATOR)]
- end
+ _, ldir = dir_config(pkg)
+ if ldir
+ pkg_config_path = "#{ldir}/pkgconfig"
+ if File.directory?(pkg_config_path)
+ Logging.message("PKG_CONFIG_PATH = %s\n", pkg_config_path)
+ envs = ["PKG_CONFIG_PATH"=>[pkg_config_path, ENV["PKG_CONFIG_PATH"]].compact.join(File::PATH_SEPARATOR)]
end
- if pkgconfig = with_config("#{pkg}-config") and find_executable0(pkgconfig)
+ end
+ if pkgconfig = with_config("#{pkg}-config") and find_executable0(pkgconfig)
# if and only if package specific config command is given
- elsif ($PKGCONFIG ||=
- (pkgconfig = with_config("pkg-config") {config_string("PKG_CONFIG") || "pkg-config"}) &&
- find_executable0(pkgconfig) && pkgconfig) and
- xsystem([*envs, $PKGCONFIG, "--exists", pkg])
- # default to pkg-config command
- pkgconfig = $PKGCONFIG
- args = [pkg]
- elsif find_executable0(pkgconfig = "#{pkg}-config")
+ elsif ($PKGCONFIG ||=
+ (pkgconfig = with_config("pkg-config") {config_string("PKG_CONFIG") || "pkg-config"}) &&
+ find_executable0(pkgconfig) && pkgconfig) and
+ xsystem([*envs, $PKGCONFIG, "--exists", pkg])
+ # default to pkg-config command
+ pkgconfig = $PKGCONFIG
+ args = [pkg]
+ elsif find_executable0(pkgconfig = "#{pkg}-config")
# default to package specific config command, as a last resort.
+ else
+ pkgconfig = nil
+ end
+ if pkgconfig
+ get = proc {|opts|
+ opts = Array(opts).map { |o| "--#{o}" }
+ opts = xpopen([*envs, pkgconfig, *opts, *args], err:[:child, :out], &:read)
+ Logging.open {puts opts.each_line.map{|s|"=> #{s.inspect}"}}
+ opts.strip if $?.success?
+ }
+ end
+ orig_ldflags = $LDFLAGS
+ if get and !options.empty?
+ get[options]
+ elsif get and try_ldflags(ldflags = get['libs'])
+ if incflags = get['cflags-only-I']
+ $INCFLAGS << " " << incflags
+ cflags = get['cflags-only-other']
else
- pkgconfig = nil
- end
- if pkgconfig
- get = proc {|opts|
- opts = Array(opts).map { |o| "--#{o}" }
- opts = xpopen([*envs, pkgconfig, *opts, *args], err:[:child, :out], &:read)
- Logging.open {puts opts.each_line.map{|s|"=> #{s.inspect}"}}
- opts.strip if $?.success?
- }
+ cflags = get['cflags']
end
- orig_ldflags = $LDFLAGS
- if get and !options.empty?
- get[options]
- elsif get and try_ldflags(ldflags = get['libs'])
- if incflags = get['cflags-only-I']
- $INCFLAGS << " " << incflags
- cflags = get['cflags-only-other']
- else
- cflags = get['cflags']
- end
- libs = get['libs-only-l']
- if cflags
- $CFLAGS += " " << cflags
- $CXXFLAGS += " " << cflags
- end
- if libs
- ldflags = (Shellwords.shellwords(ldflags) - Shellwords.shellwords(libs)).quote.join(" ")
- else
- libs, ldflags = Shellwords.shellwords(ldflags).partition {|s| s =~ /-l([^ ]+)/ }.map {|l|l.quote.join(" ")}
- end
- $libs += " " << libs
-
- $LDFLAGS = [orig_ldflags, ldflags].join(' ')
- Logging::message "package configuration for %s\n", pkg
- Logging::message "incflags: %s\ncflags: %s\nldflags: %s\nlibs: %s\n\n",
- incflags, cflags, ldflags, libs
- [[incflags, cflags].join(' '), ldflags, libs]
+ libs = get['libs-only-l']
+ if cflags
+ $CFLAGS += " " << cflags
+ $CXXFLAGS += " " << cflags
+ end
+ if libs
+ ldflags = (Shellwords.shellwords(ldflags) - Shellwords.shellwords(libs)).quote.join(" ")
else
- Logging::message "package configuration for %s is not found\n", pkg
- nil
+ libs, ldflags = Shellwords.shellwords(ldflags).partition {|s| s =~ /-l([^ ]+)/ }.map {|l|l.quote.join(" ")}
end
+ $libs += " " << libs
+
+ $LDFLAGS = [orig_ldflags, ldflags].join(' ')
+ Logging::message "package configuration for %s\n", pkg
+ Logging::message "incflags: %s\ncflags: %s\nldflags: %s\nlibs: %s\n\n",
+ incflags, cflags, ldflags, libs
+ [[incflags, cflags].join(' '), ldflags, libs]
+ else
+ Logging::message "package configuration for %s is not found\n", pkg
+ nil
end
end
@@ -2067,14 +1964,14 @@ SRC
def configuration(srcdir)
mk = []
- verbose = with_config('verbose') ? "1" : (CONFIG['MKMF_VERBOSE'] || "0")
+ CONFIG['MKMF_VERBOSE'] ||= "0"
vpath = $VPATH.dup
CONFIG["hdrdir"] ||= $hdrdir
mk << %{
SHELL = /bin/sh
# V=0 quiet, V=1 verbose. other values don't work.
-V = #{verbose}
+V = #{CONFIG['MKMF_VERBOSE']}
V0 = $(V:0=)
Q1 = $(V:1=)
Q = $(Q1:0=@)
@@ -2166,9 +2063,7 @@ ARCH_FLAG = #{$ARCH_FLAG}
DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
LDSHARED = #{CONFIG['LDSHARED']}
LDSHAREDXX = #{config_string('LDSHAREDXX') || '$(LDSHARED)'}
-POSTLINK = #{config_string('POSTLINK', RbConfig::CONFIG)}
AR = #{CONFIG['AR']}
-LD = #{CONFIG['LD']}
EXEEXT = #{CONFIG['EXEEXT']}
}
@@ -2476,7 +2371,7 @@ TARGET_ENTRY = #{EXPORT_PREFIX || ''}Init_$(TARGET_NAME)
DLLIB = #{dllib}
EXTSTATIC = #{$static || ""}
STATIC_LIB = #{staticlib unless $static.nil?}
-#{!$extout && defined?($installed_list) ? %[INSTALLED_LIST = #{$installed_list}\n] : ""}
+#{!$extout && defined?($installed_list) ? "INSTALLED_LIST = #{$installed_list}\n" : ""}
TIMESTAMP_DIR = #{$extout && $extmk ? '$(extout)/.timestamp' : '.'}
" #"
# TODO: fixme
@@ -2503,7 +2398,7 @@ TARGET_SO_DIR_TIMESTAMP = #{timestamp_file(sodir, target_prefix)}
mfile.puts(conf)
mfile.print "
all: #{$extout ? "install" : target ? "$(DLLIB)" : "Makefile"}
-static: #{$extmk && !$static ? "all" : %[$(STATIC_LIB)#{$extout ? " install-rb" : ""}]}
+static: #{$extmk && !$static ? "all" : "$(STATIC_LIB)#{$extout ? " install-rb" : ""}"}
.PHONY: all install static install-so install-rb
.PHONY: clean clean-so clean-static clean-rb
" #"
@@ -2534,7 +2429,6 @@ static: #{$extmk && !$static ? "all" : %[$(STATIC_LIB)#{$extout ? " install-rb"
mfile.puts dest
mfile.print "clean-so::\n"
mfile.print "\t-$(Q)$(RM) #{fseprepl[dest]} #{fseprepl[stamp]}\n"
- mfile.print "\t-$(Q)$(RM_RF) #{fseprepl['$(CLEANLIBS)']}\n"
mfile.print "\t-$(Q)$(RMDIRS) #{fseprepl[dir]}#{$ignore_error}\n"
else
mfile.print "#{f} #{stamp}\n"
@@ -2804,7 +2698,7 @@ MESSAGE
when $mswin
$nmake = ?m if /nmake/i =~ make
end
- $ignore_error = " 2> #{File::NULL} || #{$mswin ? 'exit /b0' : 'true'}"
+ $ignore_error = $nmake ? '' : ' 2> /dev/null || true'
RbConfig::CONFIG["srcdir"] = CONFIG["srcdir"] =
$srcdir = arg_config("--srcdir", File.dirname($0))
@@ -2827,9 +2721,6 @@ MESSAGE
split = Shellwords.method(:shellwords).to_proc
- ##
- # The prefix added to exported symbols automatically
-
EXPORT_PREFIX = config_string('EXPORT_PREFIX') {|s| s.strip}
hdr = ['#include "ruby.h"' "\n"]
@@ -2859,10 +2750,6 @@ MESSAGE
# make compile rules
COMPILE_RULES = config_string('COMPILE_RULES', &split) || %w[.%s.%s:]
-
- ##
- # Substitution in rules for NMake
-
RULE_SUBST = config_string('RULE_SUBST')
##
@@ -2907,11 +2794,7 @@ MESSAGE
##
# Argument which will add a library path to the linker
- LIBPATHFLAG = config_string('LIBPATHFLAG') || '-L%s'
-
- ##
- # Argument which will add a runtime library path to the linker
-
+ LIBPATHFLAG = config_string('LIBPATHFLAG') || ' -L%s'
RPATHFLAG = config_string('RPATHFLAG') || ''
##
@@ -2923,10 +2806,6 @@ MESSAGE
# A C main function which does no work
MAIN_DOES_NOTHING = config_string('MAIN_DOES_NOTHING') || "int main(int argc, char **argv)\n{\n return !!argv[argc];\n}"
-
- ##
- # The type names for convertible_int
-
UNIVERSAL_INTS = config_string('UNIVERSAL_INTS') {|s| Shellwords.shellwords(s)} ||
%w[int short long long\ long]
@@ -2957,32 +2836,18 @@ realclean: distclean
@lang = Hash.new(self)
- ##
- # Retrieves the module for _name_ language.
def self.[](name)
@lang.fetch(name)
end
- ##
- # Defines the module for _name_ language.
def self.[]=(name, mod)
@lang[name] = mod
end
- ##
- # The language that this module is for
- LANGUAGE = -"C"
-
- self[self::LANGUAGE] = self
-
- cxx = Module.new do
- # Module for C++
-
+ self["C++"] = Module.new do
include MakeMakefile
extend self
- # :stopdoc:
-
CONFTEST_CXX = "#{CONFTEST}.#{config_string('CXX_EXT') || CXX_EXT[0]}"
TRY_LINK_CXX = config_string('TRY_LINK_CXX') ||
@@ -3012,12 +2877,7 @@ realclean: distclean
conf = link_config(ldflags, *opts)
RbConfig::expand(TRY_LINK_CXX.dup, conf)
end
-
- # :startdoc:
end
-
- cxx::LANGUAGE = -"C++"
- self[cxx::LANGUAGE] = cxx
end
# MakeMakefile::Global = #
diff --git a/lib/mutex_m.gemspec b/lib/mutex_m.gemspec
new file mode 100644
index 0000000000..f614dcd9a0
--- /dev/null
+++ b/lib/mutex_m.gemspec
@@ -0,0 +1,27 @@
+begin
+ require_relative "lib/mutex_m"
+rescue LoadError
+ # for Ruby core repository
+ require_relative "mutex_m"
+end
+
+Gem::Specification.new do |spec|
+ spec.name = "mutex_m"
+ spec.version = Mutex_m::VERSION
+ spec.authors = ["Keiju ISHITSUKA"]
+ spec.email = ["keiju@ruby-lang.org"]
+
+ spec.summary = %q{Mixin to extend objects to be handled like a Mutex.}
+ spec.description = %q{Mixin to extend objects to be handled like a Mutex.}
+ spec.homepage = "https://github.com/ruby/mutex_m"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.files = ["Gemfile", "LICENSE.txt", "README.md", "Rakefile", "lib/mutex_m.rb", "mutex_m.gemspec"]
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+
+ spec.add_development_dependency "bundler"
+ spec.add_development_dependency "rake"
+ spec.add_development_dependency "test-unit"
+end
diff --git a/lib/mutex_m.rb b/lib/mutex_m.rb
new file mode 100644
index 0000000000..17ec9924e4
--- /dev/null
+++ b/lib/mutex_m.rb
@@ -0,0 +1,118 @@
+# frozen_string_literal: false
+#
+# mutex_m.rb -
+# $Release Version: 3.0$
+# $Revision: 1.7 $
+# Original from mutex.rb
+# by Keiju ISHITSUKA(keiju@ishitsuka.com)
+# modified by matz
+# patched by akira yamada
+#
+# --
+
+# = mutex_m.rb
+#
+# When 'mutex_m' is required, any object that extends or includes Mutex_m will
+# be treated like a Mutex.
+#
+# Start by requiring the standard library Mutex_m:
+#
+# require "mutex_m.rb"
+#
+# From here you can extend an object with Mutex instance methods:
+#
+# obj = Object.new
+# obj.extend Mutex_m
+#
+# Or mixin Mutex_m into your module to your class inherit Mutex instance
+# methods --- remember to call super() in your class initialize method.
+#
+# class Foo
+# include Mutex_m
+# def initialize
+# # ...
+# super()
+# end
+# # ...
+# end
+# obj = Foo.new
+# # this obj can be handled like Mutex
+#
+module Mutex_m
+
+ VERSION = "0.1.2"
+ Ractor.make_shareable(VERSION) if defined?(Ractor)
+
+ def Mutex_m.define_aliases(cl) # :nodoc:
+ cl.module_eval %q{
+ alias locked? mu_locked?
+ alias lock mu_lock
+ alias unlock mu_unlock
+ alias try_lock mu_try_lock
+ alias synchronize mu_synchronize
+ }
+ end
+
+ def Mutex_m.append_features(cl) # :nodoc:
+ super
+ define_aliases(cl) unless cl.instance_of?(Module)
+ end
+
+ def Mutex_m.extend_object(obj) # :nodoc:
+ super
+ obj.mu_extended
+ end
+
+ def mu_extended # :nodoc:
+ unless (defined? locked? and
+ defined? lock and
+ defined? unlock and
+ defined? try_lock and
+ defined? synchronize)
+ Mutex_m.define_aliases(singleton_class)
+ end
+ mu_initialize
+ end
+
+ # See Thread::Mutex#synchronize
+ def mu_synchronize(&block)
+ @_mutex.synchronize(&block)
+ end
+
+ # See Thread::Mutex#locked?
+ def mu_locked?
+ @_mutex.locked?
+ end
+
+ # See Thread::Mutex#try_lock
+ def mu_try_lock
+ @_mutex.try_lock
+ end
+
+ # See Thread::Mutex#lock
+ def mu_lock
+ @_mutex.lock
+ end
+
+ # See Thread::Mutex#unlock
+ def mu_unlock
+ @_mutex.unlock
+ end
+
+ # See Thread::Mutex#sleep
+ def sleep(timeout = nil)
+ @_mutex.sleep(timeout)
+ end
+
+ private
+
+ def mu_initialize # :nodoc:
+ @_mutex = Thread::Mutex.new
+ end
+
+ def initialize(*args) # :nodoc:
+ mu_initialize
+ super
+ end
+ ruby2_keywords(:initialize) if respond_to?(:ruby2_keywords, true)
+end
diff --git a/lib/net/http.rb b/lib/net/http.rb
index 5cc9d2ce88..387df4b8f4 100644
--- a/lib/net/http.rb
+++ b/lib/net/http.rb
@@ -67,8 +67,6 @@ module Net #:nodoc:
# Net::HTTP.post(uri, data)
# params = {title: 'foo', body: 'bar', userId: 1}
# Net::HTTP.post_form(uri, params)
- # data = '{"title": "foo", "body": "bar", "userId": 1}'
- # Net::HTTP.put(uri, data)
#
# - If performance is important, consider using sessions, which lower request overhead.
# This {session}[rdoc-ref:Net::HTTP@Sessions] has multiple requests for
@@ -458,10 +456,6 @@ module Net #:nodoc:
#
# == What's Here
#
- # First, what's elsewhere. Class Net::HTTP:
- #
- # - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
- #
# This is a categorized summary of methods and attributes.
#
# === \Net::HTTP Objects
@@ -526,8 +520,6 @@ module Net #:nodoc:
# Sends a POST request with form data and returns a response object.
# - {::post}[rdoc-ref:Net::HTTP.post]:
# Sends a POST request with data and returns a response object.
- # - {::put}[rdoc-ref:Net::HTTP.put]:
- # Sends a PUT request with data and returns a response object.
# - {#copy}[rdoc-ref:Net::HTTP#copy]:
# Sends a COPY request and returns a response object.
# - {#delete}[rdoc-ref:Net::HTTP#delete]:
@@ -897,39 +889,6 @@ module Net #:nodoc:
}
end
- # Sends a PUT request to the server; returns a Net::HTTPResponse object.
- #
- # Argument +url+ must be a URL;
- # argument +data+ must be a string:
- #
- # _uri = uri.dup
- # _uri.path = '/posts'
- # data = '{"title": "foo", "body": "bar", "userId": 1}'
- # headers = {'content-type': 'application/json'}
- # res = Net::HTTP.put(_uri, data, headers) # => #<Net::HTTPCreated 201 Created readbody=true>
- # puts res.body
- #
- # Output:
- #
- # {
- # "title": "foo",
- # "body": "bar",
- # "userId": 1,
- # "id": 101
- # }
- #
- # Related:
- #
- # - Net::HTTP::Put: request class for \HTTP method +PUT+.
- # - Net::HTTP#put: convenience method for \HTTP method +PUT+.
- #
- def HTTP.put(url, data, header = nil)
- start(url.hostname, url.port,
- :use_ssl => url.scheme == 'https' ) {|http|
- http.put(url, data, header)
- }
- end
-
#
# \HTTP session management
#
@@ -1103,7 +1062,7 @@ module Net #:nodoc:
# For proxy-defining arguments +p_addr+ through +p_no_proxy+,
# see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
#
- def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_no_proxy = nil, p_use_ssl = nil)
+ def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_no_proxy = nil)
http = super address, port
if proxy_class? then # from Net::HTTP::Proxy()
@@ -1112,7 +1071,6 @@ module Net #:nodoc:
http.proxy_port = @proxy_port
http.proxy_user = @proxy_user
http.proxy_pass = @proxy_pass
- http.proxy_use_ssl = @proxy_use_ssl
elsif p_addr == :ENV then
http.proxy_from_env = true
else
@@ -1124,67 +1082,34 @@ module Net #:nodoc:
http.proxy_port = p_port || default_port
http.proxy_user = p_user
http.proxy_pass = p_pass
- http.proxy_use_ssl = p_use_ssl
end
http
end
- class << HTTP
- # Allows to set the default configuration that will be used
- # when creating a new connection.
- #
- # Example:
- #
- # Net::HTTP.default_configuration = {
- # read_timeout: 1,
- # write_timeout: 1
- # }
- # http = Net::HTTP.new(hostname)
- # http.open_timeout # => 60
- # http.read_timeout # => 1
- # http.write_timeout # => 1
- #
- attr_accessor :default_configuration
- end
-
# Creates a new \Net::HTTP object for the specified server address,
# without opening the TCP connection or initializing the \HTTP session.
# The +address+ should be a DNS hostname or IP address.
def initialize(address, port = nil) # :nodoc:
- defaults = {
- keep_alive_timeout: 2,
- close_on_empty_response: false,
- open_timeout: 60,
- read_timeout: 60,
- write_timeout: 60,
- continue_timeout: nil,
- max_retries: 1,
- debug_output: nil,
- response_body_encoding: false,
- ignore_eof: true
- }
- options = defaults.merge(self.class.default_configuration || {})
-
@address = address
@port = (port || HTTP.default_port)
@ipaddr = nil
@local_host = nil
@local_port = nil
@curr_http_version = HTTPVersion
- @keep_alive_timeout = options[:keep_alive_timeout]
+ @keep_alive_timeout = 2
@last_communicated = nil
- @close_on_empty_response = options[:close_on_empty_response]
+ @close_on_empty_response = false
@socket = nil
@started = false
- @open_timeout = options[:open_timeout]
- @read_timeout = options[:read_timeout]
- @write_timeout = options[:write_timeout]
- @continue_timeout = options[:continue_timeout]
- @max_retries = options[:max_retries]
- @debug_output = options[:debug_output]
- @response_body_encoding = options[:response_body_encoding]
- @ignore_eof = options[:ignore_eof]
+ @open_timeout = 60
+ @read_timeout = 60
+ @write_timeout = 60
+ @continue_timeout = nil
+ @max_retries = 1
+ @debug_output = nil
+ @response_body_encoding = false
+ @ignore_eof = true
@proxy_from_env = false
@proxy_uri = nil
@@ -1192,7 +1117,6 @@ module Net #:nodoc:
@proxy_port = nil
@proxy_user = nil
@proxy_pass = nil
- @proxy_use_ssl = nil
@use_ssl = false
@ssl_context = nil
@@ -1327,7 +1251,6 @@ module Net #:nodoc:
# Sets the proxy password;
# see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
attr_writer :proxy_pass
- attr_writer :proxy_use_ssl
# Returns the IP address for the connection.
#
@@ -1517,6 +1440,23 @@ module Net #:nodoc:
@use_ssl = flag
end
+ SSL_IVNAMES = [
+ :@ca_file,
+ :@ca_path,
+ :@cert,
+ :@cert_store,
+ :@ciphers,
+ :@extra_chain_cert,
+ :@key,
+ :@ssl_timeout,
+ :@ssl_version,
+ :@min_version,
+ :@max_version,
+ :@verify_callback,
+ :@verify_depth,
+ :@verify_mode,
+ :@verify_hostname,
+ ] # :nodoc:
SSL_ATTRIBUTES = [
:ca_file,
:ca_path,
@@ -1535,8 +1475,6 @@ module Net #:nodoc:
:verify_hostname,
] # :nodoc:
- SSL_IVNAMES = SSL_ATTRIBUTES.map { |a| "@#{a}".to_sym } # :nodoc:
-
# Sets or returns the path to a CA certification file in PEM format.
attr_accessor :ca_file
@@ -1672,13 +1610,7 @@ module Net #:nodoc:
debug "opened"
if use_ssl?
if proxy?
- if @proxy_use_ssl
- proxy_sock = OpenSSL::SSL::SSLSocket.new(s)
- ssl_socket_connect(proxy_sock, @open_timeout)
- else
- proxy_sock = s
- end
- proxy_sock = BufferedIO.new(proxy_sock, read_timeout: @read_timeout,
+ plain_sock = BufferedIO.new(s, read_timeout: @read_timeout,
write_timeout: @write_timeout,
continue_timeout: @continue_timeout,
debug_output: @debug_output)
@@ -1689,8 +1621,8 @@ module Net #:nodoc:
buf << "Proxy-Authorization: Basic #{credential}\r\n"
end
buf << "\r\n"
- proxy_sock.write(buf)
- HTTPResponse.read_new(proxy_sock).value
+ plain_sock.write(buf)
+ HTTPResponse.read_new(plain_sock).value
# assuming nothing left in buffers after successful CONNECT response
end
@@ -1798,14 +1730,13 @@ module Net #:nodoc:
@proxy_port = nil
@proxy_user = nil
@proxy_pass = nil
- @proxy_use_ssl = nil
# Creates an \HTTP proxy class which behaves like \Net::HTTP, but
# performs all access via the specified proxy.
#
# This class is obsolete. You may pass these same parameters directly to
# \Net::HTTP.new. See Net::HTTP.new for details of the arguments.
- def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_use_ssl = nil) #:nodoc:
+ def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil) #:nodoc:
return self unless p_addr
Class.new(self) {
@@ -1823,7 +1754,6 @@ module Net #:nodoc:
@proxy_user = p_user
@proxy_pass = p_pass
- @proxy_use_ssl = p_use_ssl
}
end
@@ -1848,9 +1778,6 @@ module Net #:nodoc:
# Returns the password for accessing the proxy, or +nil+ if none;
# see Net::HTTP@Proxy+Server.
attr_reader :proxy_pass
-
- # Use SSL when talking to the proxy. If Net::HTTP does not use a proxy, nil.
- attr_reader :proxy_use_ssl
end
# Returns +true+ if a proxy server is defined, +false+ otherwise;
@@ -2085,11 +2012,6 @@ module Net #:nodoc:
# http = Net::HTTP.new(hostname)
# http.put('/todos/1', data) # => #<Net::HTTPOK 200 OK readbody=true>
#
- # Related:
- #
- # - Net::HTTP::Put: request class for \HTTP method PUT.
- # - Net::HTTP.put: sends PUT request, returns response body.
- #
def put(path, data, initheader = nil)
request(Put.new(path, initheader), data)
end
@@ -2428,10 +2350,7 @@ module Net #:nodoc:
res
}
res.reading_body(@socket, req.response_body_permitted?) {
- if block_given?
- count = max_retries # Don't restart in the middle of a download
- yield res
- end
+ yield res if block_given?
}
rescue Net::OpenTimeout
raise
diff --git a/lib/net/http/header.rb b/lib/net/http/header.rb
index f6c36f1b5e..6660c8075a 100644
--- a/lib/net/http/header.rb
+++ b/lib/net/http/header.rb
@@ -491,7 +491,7 @@ module Net::HTTPHeader
alias canonical_each each_capitalized
def capitalize(name)
- name.to_s.split('-'.freeze).map {|s| s.capitalize }.join('-'.freeze)
+ name.to_s.split(/-/).map {|s| s.capitalize }.join('-')
end
private :capitalize
diff --git a/lib/net/http/requests.rb b/lib/net/http/requests.rb
index e58057adf1..5724164205 100644
--- a/lib/net/http/requests.rb
+++ b/lib/net/http/requests.rb
@@ -124,11 +124,6 @@ end
# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
#
-# Related:
-#
-# - Net::HTTP.put: sends +PUT+ request, returns response object.
-# - Net::HTTP#put: sends +PUT+ request, returns response object.
-#
class Net::HTTP::Put < Net::HTTPRequest
METHOD = 'PUT'
REQUEST_HAS_BODY = true
diff --git a/lib/net/net-protocol.gemspec b/lib/net/net-protocol.gemspec
index f9fd83f12b..c03621cb0d 100644
--- a/lib/net/net-protocol.gemspec
+++ b/lib/net/net-protocol.gemspec
@@ -21,12 +21,11 @@ Gem::Specification.new do |spec|
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
- spec.metadata["changelog_uri"] = spec.homepage + "/releases"
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.require_paths = ["lib"]
diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb
index 197ea09089..ea0752a971 100644
--- a/lib/net/protocol.rb
+++ b/lib/net/protocol.rb
@@ -26,7 +26,7 @@ require 'io/wait'
module Net # :nodoc:
class Protocol #:nodoc: internal use only
- VERSION = "0.2.2"
+ VERSION = "0.2.1"
private
def Protocol.protocol_param(name, val)
diff --git a/lib/observer.rb b/lib/observer.rb
new file mode 100644
index 0000000000..ef70e39dd8
--- /dev/null
+++ b/lib/observer.rb
@@ -0,0 +1,229 @@
+# frozen_string_literal: true
+#
+# Implementation of the _Observer_ object-oriented design pattern. The
+# following documentation is copied, with modifications, from "Programming
+# Ruby", by Hunt and Thomas; http://www.ruby-doc.org/docs/ProgrammingRuby/html/lib_patterns.html.
+#
+# See Observable for more info.
+
+# The Observer pattern (also known as publish/subscribe) provides a simple
+# mechanism for one object to inform a set of interested third-party objects
+# when its state changes.
+#
+# == Mechanism
+#
+# The notifying class mixes in the +Observable+
+# module, which provides the methods for managing the associated observer
+# objects.
+#
+# The observable object must:
+# * assert that it has +#changed+
+# * call +#notify_observers+
+#
+# An observer subscribes to updates using Observable#add_observer, which also
+# specifies the method called via #notify_observers. The default method for
+# #notify_observers is #update.
+#
+# === Example
+#
+# The following example demonstrates this nicely. A +Ticker+, when run,
+# continually receives the stock +Price+ for its <tt>@symbol</tt>. A +Warner+
+# is a general observer of the price, and two warners are demonstrated, a
+# +WarnLow+ and a +WarnHigh+, which print a warning if the price is below or
+# above their set limits, respectively.
+#
+# The +update+ callback allows the warners to run without being explicitly
+# called. The system is set up with the +Ticker+ and several observers, and the
+# observers do their duty without the top-level code having to interfere.
+#
+# Note that the contract between publisher and subscriber (observable and
+# observer) is not declared or enforced. The +Ticker+ publishes a time and a
+# price, and the warners receive that. But if you don't ensure that your
+# contracts are correct, nothing else can warn you.
+#
+# require "observer"
+#
+# class Ticker ### Periodically fetch a stock price.
+# include Observable
+#
+# def initialize(symbol)
+# @symbol = symbol
+# end
+#
+# def run
+# last_price = nil
+# loop do
+# price = Price.fetch(@symbol)
+# print "Current price: #{price}\n"
+# if price != last_price
+# changed # notify observers
+# last_price = price
+# notify_observers(Time.now, price)
+# end
+# sleep 1
+# end
+# end
+# end
+#
+# class Price ### A mock class to fetch a stock price (60 - 140).
+# def self.fetch(symbol)
+# 60 + rand(80)
+# end
+# end
+#
+# class Warner ### An abstract observer of Ticker objects.
+# def initialize(ticker, limit)
+# @limit = limit
+# ticker.add_observer(self)
+# end
+# end
+#
+# class WarnLow < Warner
+# def update(time, price) # callback for observer
+# if price < @limit
+# print "--- #{time.to_s}: Price below #@limit: #{price}\n"
+# end
+# end
+# end
+#
+# class WarnHigh < Warner
+# def update(time, price) # callback for observer
+# if price > @limit
+# print "+++ #{time.to_s}: Price above #@limit: #{price}\n"
+# end
+# end
+# end
+#
+# ticker = Ticker.new("MSFT")
+# WarnLow.new(ticker, 80)
+# WarnHigh.new(ticker, 120)
+# ticker.run
+#
+# Produces:
+#
+# Current price: 83
+# Current price: 75
+# --- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 75
+# Current price: 90
+# Current price: 134
+# +++ Sun Jun 09 00:10:25 CDT 2002: Price above 120: 134
+# Current price: 134
+# Current price: 112
+# Current price: 79
+# --- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 79
+#
+# === Usage with procs
+#
+# The +#notify_observers+ method can also be used with +proc+s by using
+# the +:call+ as +func+ parameter.
+#
+# The following example illustrates the use of a lambda:
+#
+# require 'observer'
+#
+# class Ticker
+# include Observable
+#
+# def run
+# # logic to retrieve the price (here 77.0)
+# changed
+# notify_observers(77.0)
+# end
+# end
+#
+# ticker = Ticker.new
+# warner = ->(price) { puts "New price received: #{price}" }
+# ticker.add_observer(warner, :call)
+# ticker.run
+module Observable
+ VERSION = "0.1.1"
+
+ #
+ # Add +observer+ as an observer on this object. So that it will receive
+ # notifications.
+ #
+ # +observer+:: the object that will be notified of changes.
+ # +func+:: Symbol naming the method that will be called when this Observable
+ # has changes.
+ #
+ # This method must return true for +observer.respond_to?+ and will
+ # receive <tt>*arg</tt> when #notify_observers is called, where
+ # <tt>*arg</tt> is the value passed to #notify_observers by this
+ # Observable
+ def add_observer(observer, func=:update)
+ @observer_peers = {} unless defined? @observer_peers
+ unless observer.respond_to? func
+ raise NoMethodError, "observer does not respond to `#{func}'"
+ end
+ @observer_peers[observer] = func
+ end
+
+ #
+ # Remove +observer+ as an observer on this object so that it will no longer
+ # receive notifications.
+ #
+ # +observer+:: An observer of this Observable
+ def delete_observer(observer)
+ @observer_peers.delete observer if defined? @observer_peers
+ end
+
+ #
+ # Remove all observers associated with this object.
+ #
+ def delete_observers
+ @observer_peers.clear if defined? @observer_peers
+ end
+
+ #
+ # Return the number of observers associated with this object.
+ #
+ def count_observers
+ if defined? @observer_peers
+ @observer_peers.size
+ else
+ 0
+ end
+ end
+
+ #
+ # Set the changed state of this object. Notifications will be sent only if
+ # the changed +state+ is +true+.
+ #
+ # +state+:: Boolean indicating the changed state of this Observable.
+ #
+ def changed(state=true)
+ @observer_state = state
+ end
+
+ #
+ # Returns true if this object's state has been changed since the last
+ # #notify_observers call.
+ #
+ def changed?
+ if defined? @observer_state and @observer_state
+ true
+ else
+ false
+ end
+ end
+
+ #
+ # Notify observers of a change in state *if* this object's changed state is
+ # +true+.
+ #
+ # This will invoke the method named in #add_observer, passing <tt>*arg</tt>.
+ # The changed state is then set to +false+.
+ #
+ # <tt>*arg</tt>:: Any arguments to pass to the observers.
+ def notify_observers(*arg)
+ if defined? @observer_state and @observer_state
+ if defined? @observer_peers
+ @observer_peers.each do |k, v|
+ k.__send__(v, *arg)
+ end
+ end
+ @observer_state = false
+ end
+ end
+
+end
diff --git a/lib/observer/observer.gemspec b/lib/observer/observer.gemspec
new file mode 100644
index 0000000000..46538e881a
--- /dev/null
+++ b/lib/observer/observer.gemspec
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{Implementation of the Observer object-oriented design pattern.}
+ spec.description = spec.summary
+ spec.homepage = "https://github.com/ruby/observer"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/open-uri.gemspec b/lib/open-uri.gemspec
index b6aaf35200..cad63e4d80 100644
--- a/lib/open-uri.gemspec
+++ b/lib/open-uri.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", "."].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "open-uri"
+ spec.version = "0.3.0"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
diff --git a/lib/open-uri.rb b/lib/open-uri.rb
index f2eddbcd2b..93e8cfcdb7 100644
--- a/lib/open-uri.rb
+++ b/lib/open-uri.rb
@@ -31,7 +31,6 @@ module URI
super
end
end
- singleton_class.send(:ruby2_keywords, :open) if respond_to?(:ruby2_keywords, true)
end
# OpenURI is an easy-to-use wrapper for Net::HTTP, Net::HTTPS and Net::FTP.
@@ -90,9 +89,6 @@ end
# Author:: Tanaka Akira <akr@m17n.org>
module OpenURI
-
- VERSION = "0.4.1"
-
Options = {
:proxy => true,
:proxy_http_basic_authentication => true,
@@ -108,8 +104,6 @@ module OpenURI
:ftp_active_mode => false,
:redirect => true,
:encoding => nil,
- :max_redirects => 64,
- :request_specific_fields => nil,
}
def OpenURI.check_options(options) # :nodoc:
@@ -149,11 +143,7 @@ module OpenURI
end
encoding = Encoding.find(options[:encoding])
end
- if options.has_key? :request_specific_fields
- if !(options[:request_specific_fields].is_a?(Hash) || options[:request_specific_fields].is_a?(Proc))
- raise ArgumentError, "Invalid request_specific_fields option: #{options[:request_specific_fields].inspect}"
- end
- end
+
unless mode == nil ||
mode == 'r' || mode == 'rb' ||
mode == File::RDONLY
@@ -217,20 +207,11 @@ module OpenURI
end
uri_set = {}
- max_redirects = options[:max_redirects] || Options.fetch(:max_redirects)
buf = nil
while true
- request_specific_fields = {}
- if options.has_key? :request_specific_fields
- request_specific_fields = if options[:request_specific_fields].is_a?(Hash)
- options[:request_specific_fields]
- else options[:request_specific_fields].is_a?(Proc)
- options[:request_specific_fields].call(uri)
- end
- end
redirect = catch(:open_uri_redirect) {
buf = Buffer.new
- uri.buffer_open(buf, find_proxy.call(uri), options.merge(request_specific_fields))
+ uri.buffer_open(buf, find_proxy.call(uri), options)
nil
}
if redirect
@@ -250,14 +231,9 @@ module OpenURI
options = options.dup
options.delete :http_basic_authentication
end
- if options.include?(:request_specific_fields) && options[:request_specific_fields].is_a?(Hash)
- # Send request specific headers only for the initial request.
- options.delete :request_specific_fields
- end
uri = redirect
raise "HTTP redirection loop: #{uri}" if uri_set.include? uri.to_s
uri_set[uri.to_s] = true
- raise TooManyRedirects.new("Too many redirects", buf.io) if max_redirects && uri_set.size > max_redirects
else
break
end
@@ -412,9 +388,6 @@ module OpenURI
attr_reader :uri
end
- class TooManyRedirects < HTTPError
- end
-
class Buffer # :nodoc: all
def initialize
@io = StringIO.new
@@ -763,44 +736,6 @@ module OpenURI
# Using +true+ also means that redirections between http and ftp are
# permitted.
#
- # [:max_redirects]
- # Synopsis:
- # :max_redirects=>int
- #
- # Number of HTTP redirects allowed before OpenURI::TooManyRedirects is raised.
- # The default is 64.
- #
- # [:request_specific_fields]
- # Synopsis:
- # :request_specific_fields => {}
- # :request_specific_fields => lambda {|url| ...}
- #
- # :request_specific_fields option allows specifying custom header fields that
- # are sent with the HTTP request. It can be passed as a Hash or a Proc that
- # gets evaluated on each request and returns a Hash of header fields.
- #
- # If a Hash is provided, it specifies the headers only for the initial
- # request and these headers will not be sent on redirects.
- #
- # If a Proc is provided, it will be executed for each request including
- # redirects, allowing dynamic header customization based on the request URL.
- # It is important that the Proc returns a Hash. And this Hash specifies the
- # headers to be sent with the request.
- #
- # For Example with Hash
- # URI.open("http://...",
- # request_specific_fields: {"Authorization" => "token dummy"}) {|f| ... }
- #
- # For Example with Proc:
- # URI.open("http://...",
- # request_specific_fields: lambda { |uri|
- # if uri.host == "example.com"
- # {"Authorization" => "token dummy"}
- # else
- # {}
- # end
- # }) {|f| ... }
- #
def open(*rest, &block)
OpenURI.open_uri(self, *rest, &block)
end
diff --git a/lib/open3.rb b/lib/open3.rb
index 74d00b86d9..9652b27194 100644
--- a/lib/open3.rb
+++ b/lib/open3.rb
@@ -31,189 +31,57 @@
require 'open3/version'
-# \Module \Open3 supports creating child processes
-# with access to their $stdin, $stdout, and $stderr streams.
-#
-# == What's Here
-#
-# Each of these methods executes a given command in a new process or subshell,
-# or multiple commands in new processes and/or subshells:
-#
-# - Each of these methods executes a single command in a process or subshell,
-# accepts a string for input to $stdin,
-# and returns string output from $stdout, $stderr, or both:
-#
-# - Open3.capture2: Executes the command;
-# returns the string from $stdout.
-# - Open3.capture2e: Executes the command;
-# returns the string from merged $stdout and $stderr.
-# - Open3.capture3: Executes the command;
-# returns strings from $stdout and $stderr.
-#
-# - Each of these methods executes a single command in a process or subshell,
-# and returns pipes for $stdin, $stdout, and/or $stderr:
-#
-# - Open3.popen2: Executes the command;
-# returns pipes for $stdin and $stdout.
-# - Open3.popen2e: Executes the command;
-# returns pipes for $stdin and merged $stdout and $stderr.
-# - Open3.popen3: Executes the command;
-# returns pipes for $stdin, $stdout, and $stderr.
-#
-# - Each of these methods executes one or more commands in processes and/or subshells,
-# returns pipes for the first $stdin, the last $stdout, or both:
-#
-# - Open3.pipeline_r: Returns a pipe for the last $stdout.
-# - Open3.pipeline_rw: Returns pipes for the first $stdin and the last $stdout.
-# - Open3.pipeline_w: Returns a pipe for the first $stdin.
-# - Open3.pipeline_start: Does not wait for processes to complete.
-# - Open3.pipeline: Waits for processes to complete.
-#
-# Each of the methods above accepts:
-#
-# - An optional hash of environment variable names and values;
-# see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
-# - A required string argument that is a +command_line+ or +exe_path+;
-# see {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
-# - An optional hash of execution options;
-# see {Execution Options}[rdoc-ref:Process@Execution+Options].
-#
module Open3
- # :call-seq:
- # Open3.popen3([env, ] command_line, options = {}) -> [stdin, stdout, stderr, wait_thread]
- # Open3.popen3([env, ] exe_path, *args, options = {}) -> [stdin, stdout, stderr, wait_thread]
- # Open3.popen3([env, ] command_line, options = {}) {|stdin, stdout, stderr, wait_thread| ... } -> object
- # Open3.popen3([env, ] exe_path, *args, options = {}) {|stdin, stdout, stderr, wait_thread| ... } -> object
- #
- # Basically a wrapper for
- # {Process.spawn}[rdoc-ref:Process.spawn]
- # that:
- #
- # - Creates a child process, by calling Process.spawn with the given arguments.
- # - Creates streams +stdin+, +stdout+, and +stderr+,
- # which are the standard input, standard output, and standard error streams
- # in the child process.
- # - Creates thread +wait_thread+ that waits for the child process to exit;
- # the thread has method +pid+, which returns the process ID
- # of the child process.
- #
- # With no block given, returns the array
- # <tt>[stdin, stdout, stderr, wait_thread]</tt>.
- # The caller should close each of the three returned streams.
- #
- # stdin, stdout, stderr, wait_thread = Open3.popen3('echo')
- # # => [#<IO:fd 8>, #<IO:fd 10>, #<IO:fd 12>, #<Process::Waiter:0x00007f58d5428f58 run>]
- # stdin.close
- # stdout.close
- # stderr.close
- # wait_thread.pid # => 2210481
- # wait_thread.value # => #<Process::Status: pid 2210481 exit 0>
- #
- # With a block given, calls the block with the four variables
- # (three streams and the wait thread)
- # and returns the block's return value.
- # The caller need not close the streams:
- #
- # Open3.popen3('echo') do |stdin, stdout, stderr, wait_thread|
- # p stdin
- # p stdout
- # p stderr
- # p wait_thread
- # p wait_thread.pid
- # p wait_thread.value
- # end
- #
- # Output:
- #
- # #<IO:fd 6>
- # #<IO:fd 7>
- # #<IO:fd 9>
- # #<Process::Waiter:0x00007f58d53606e8 sleep>
- # 2211047
- # #<Process::Status: pid 2211047 exit 0>
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # If the first argument is a hash, it becomes leading argument +env+
- # in the call to Process.spawn;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- #
- # If the last argument is a hash, it becomes trailing argument +options+
- # in the call to Process.spawn;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
- #
- # The single required argument is one of the following:
- #
- # - +command_line+ if it is a string,
- # and if it begins with a shell reserved word or special built-in,
- # or if it contains one or more metacharacters.
- # - +exe_path+ otherwise.
- #
- # <b>Argument +command_line+</b>
- #
- # \String argument +command_line+ is a command line to be passed to a shell;
- # it must begin with a shell reserved word, begin with a special built-in,
- # or contain meta characters:
- #
- # Open3.popen3('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word.
- # Open3.popen3('echo') {|*args| p args } # Built-in.
- # Open3.popen3('date > date.tmp') {|*args| p args } # Contains meta character.
- #
- # Output (similar for each call above):
- #
- # [#<IO:(closed)>, #<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f58d52f28c8 dead>]
+ # Open stdin, stdout, and stderr streams and start external executable.
+ # In addition, a thread to wait for the started process is created.
+ # The thread has a pid method and a thread variable :pid which is the pid of
+ # the started process.
#
- # The command line may also contain arguments and options for the command:
+ # Block form:
#
- # Open3.popen3('echo "Foo"') { |i, o, e, t| o.gets }
- # "Foo\n"
+ # Open3.popen3([env,] cmd... [, opts]) {|stdin, stdout, stderr, wait_thr|
+ # pid = wait_thr.pid # pid of the started process.
+ # ...
+ # exit_status = wait_thr.value # Process::Status object returned.
+ # }
#
- # <b>Argument +exe_path+</b>
+ # Non-block form:
#
- # Argument +exe_path+ is one of the following:
- #
- # - The string path to an executable to be called.
- # - A 2-element array containing the path to an executable
- # and the string to be used as the name of the executing process.
- #
- # Example:
- #
- # Open3.popen3('/usr/bin/date') { |i, o, e, t| o.gets }
- # # => "Wed Sep 27 02:56:44 PM CDT 2023\n"
+ # stdin, stdout, stderr, wait_thr = Open3.popen3([env,] cmd... [, opts])
+ # pid = wait_thr[:pid] # pid of the started process
+ # ...
+ # stdin.close # stdin, stdout and stderr should be closed explicitly in this form.
+ # stdout.close
+ # stderr.close
+ # exit_status = wait_thr.value # Process::Status object returned.
#
- # Ruby invokes the executable directly, with no shell and no shell expansion:
+ # The parameters env, cmd, and opts are passed to Process.spawn.
+ # A commandline string and a list of argument strings can be accepted as follows:
#
- # Open3.popen3('doesnt_exist') { |i, o, e, t| o.gets } # Raises Errno::ENOENT
+ # Open3.popen3("echo abc") {|i, o, e, t| ... }
+ # Open3.popen3("echo", "abc") {|i, o, e, t| ... }
+ # Open3.popen3(["echo", "argv0"], "abc") {|i, o, e, t| ... }
#
- # If one or more +args+ is given, each is an argument or option
- # to be passed to the executable:
+ # If the last parameter, opts, is a Hash, it is recognized as an option for Process.spawn.
#
- # Open3.popen3('echo', 'C #') { |i, o, e, t| o.gets }
- # # => "C #\n"
- # Open3.popen3('echo', 'hello', 'world') { |i, o, e, t| o.gets }
- # # => "hello world\n"
+ # Open3.popen3("pwd", :chdir=>"/") {|i,o,e,t|
+ # p o.read.chomp #=> "/"
+ # }
#
- # Take care to avoid deadlocks.
- # Output streams +stdout+ and +stderr+ have fixed-size buffers,
- # so reading extensively from one but not the other can cause a deadlock
- # when the unread buffer fills.
- # To avoid that, +stdout+ and +stderr+ should be read simultaneously
- # (using threads or IO.select).
+ # wait_thr.value waits for the termination of the process.
+ # The block form also waits for the process when it returns.
#
- # Related:
+ # Closing stdin, stdout and stderr does not wait for the process to complete.
#
- # - Open3.popen2: Makes the standard input and standard output streams
- # of the child process available as separate streams,
- # with no access to the standard error stream.
- # - Open3.popen2e: Makes the standard input and the merge
- # of the standard output and standard error streams
- # of the child process available as separate streams.
+ # You should be careful to avoid deadlocks.
+ # Since pipes are fixed length buffers,
+ # Open3.popen3("prog") {|i, o, e, t| o.read } deadlocks if
+ # the program generates too much output on stderr.
+ # You should read stdout and stderr simultaneously (using threads or IO.select).
+ # However, if you don't need stderr output, you can use Open3.popen2.
+ # If merged stdout and stderr output is not a problem, you can use Open3.popen2e.
+ # If you really need stdout and stderr output as separate strings, you can consider Open3.capture3.
#
def popen3(*cmd, &block)
if Hash === cmd.last
@@ -236,131 +104,45 @@ module Open3
end
module_function :popen3
- # :call-seq:
- # Open3.popen2([env, ] command_line, options = {}) -> [stdin, stdout, wait_thread]
- # Open3.popen2([env, ] exe_path, *args, options = {}) -> [stdin, stdout, wait_thread]
- # Open3.popen2([env, ] command_line, options = {}) {|stdin, stdout, wait_thread| ... } -> object
- # Open3.popen2([env, ] exe_path, *args, options = {}) {|stdin, stdout, wait_thread| ... } -> object
- #
- # Basically a wrapper for
- # {Process.spawn}[rdoc-ref:Process.spawn]
- # that:
- #
- # - Creates a child process, by calling Process.spawn with the given arguments.
- # - Creates streams +stdin+ and +stdout+,
- # which are the standard input and standard output streams
- # in the child process.
- # - Creates thread +wait_thread+ that waits for the child process to exit;
- # the thread has method +pid+, which returns the process ID
- # of the child process.
- #
- # With no block given, returns the array
- # <tt>[stdin, stdout, wait_thread]</tt>.
- # The caller should close each of the two returned streams.
- #
- # stdin, stdout, wait_thread = Open3.popen2('echo')
- # # => [#<IO:fd 6>, #<IO:fd 7>, #<Process::Waiter:0x00007f58d52dbe98 run>]
- # stdin.close
- # stdout.close
- # wait_thread.pid # => 2263572
- # wait_thread.value # => #<Process::Status: pid 2263572 exit 0>
- #
- # With a block given, calls the block with the three variables
- # (two streams and the wait thread)
- # and returns the block's return value.
- # The caller need not close the streams:
- #
- # Open3.popen2('echo') do |stdin, stdout, wait_thread|
- # p stdin
- # p stdout
- # p wait_thread
- # p wait_thread.pid
- # p wait_thread.value
- # end
- #
- # Output:
- #
- # #<IO:fd 6>
- # #<IO:fd 7>
- # #<Process::Waiter:0x00007f58d59a34b0 sleep>
- # 2263636
- # #<Process::Status: pid 2263636 exit 0>
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # If the first argument is a hash, it becomes leading argument +env+
- # in the call to Process.spawn;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ # Open3.popen2 is similar to Open3.popen3 except that it doesn't create a pipe for
+ # the standard error stream.
#
- # If the last argument is a hash, it becomes trailing argument +options+
- # in the call to Process.spawn;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ # Block form:
#
- # The single required argument is one of the following:
+ # Open3.popen2([env,] cmd... [, opts]) {|stdin, stdout, wait_thr|
+ # pid = wait_thr.pid # pid of the started process.
+ # ...
+ # exit_status = wait_thr.value # Process::Status object returned.
+ # }
#
- # - +command_line+ if it is a string,
- # and if it begins with a shell reserved word or special built-in,
- # or if it contains one or more metacharacters.
- # - +exe_path+ otherwise.
+ # Non-block form:
#
- # <b>Argument +command_line+</b>
- #
- # \String argument +command_line+ is a command line to be passed to a shell;
- # it must begin with a shell reserved word, begin with a special built-in,
- # or contain meta characters:
- #
- # Open3.popen2('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word.
- # Open3.popen2('echo') {|*args| p args } # Built-in.
- # Open3.popen2('date > date.tmp') {|*args| p args } # Contains meta character.
- #
- # Output (similar for each call above):
- #
- # # => [#<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f7577dfe410 dead>]
- #
- # The command line may also contain arguments and options for the command:
- #
- # Open3.popen2('echo "Foo"') { |i, o, t| o.gets }
- # "Foo\n"
- #
- # <b>Argument +exe_path+</b>
- #
- # Argument +exe_path+ is one of the following:
+ # stdin, stdout, wait_thr = Open3.popen2([env,] cmd... [, opts])
+ # ...
+ # stdin.close # stdin and stdout should be closed explicitly in this form.
+ # stdout.close
#
- # - The string path to an executable to be called.
- # - A 2-element array containing the path to an executable
- # and the string to be used as the name of the executing process.
+ # See Process.spawn for the optional hash arguments _env_ and _opts_.
#
# Example:
#
- # Open3.popen2('/usr/bin/date') { |i, o, t| o.gets }
- # # => "Thu Sep 28 09:41:06 AM CDT 2023\n"
- #
- # Ruby invokes the executable directly, with no shell and no shell expansion:
- #
- # Open3.popen2('doesnt_exist') { |i, o, t| o.gets } # Raises Errno::ENOENT
- #
- # If one or more +args+ is given, each is an argument or option
- # to be passed to the executable:
- #
- # Open3.popen2('echo', 'C #') { |i, o, t| o.gets }
- # # => "C #\n"
- # Open3.popen2('echo', 'hello', 'world') { |i, o, t| o.gets }
- # # => "hello world\n"
+ # Open3.popen2("wc -c") {|i,o,t|
+ # i.print "answer to life the universe and everything"
+ # i.close
+ # p o.gets #=> "42\n"
+ # }
#
+ # Open3.popen2("bc -q") {|i,o,t|
+ # i.puts "obase=13"
+ # i.puts "6 * 9"
+ # p o.gets #=> "42\n"
+ # }
#
- # Related:
- #
- # - Open3.popen2e: Makes the standard input and the merge
- # of the standard output and standard error streams
- # of the child process available as separate streams.
- # - Open3.popen3: Makes the standard input, standard output,
- # and standard error streams
- # of the child process available as separate streams.
+ # Open3.popen2("dc") {|i,o,t|
+ # i.print "42P"
+ # i.close
+ # p o.read #=> "*"
+ # }
#
def popen2(*cmd, &block)
if Hash === cmd.last
@@ -380,130 +162,36 @@ module Open3
end
module_function :popen2
- # :call-seq:
- # Open3.popen2e([env, ] command_line, options = {}) -> [stdin, stdout_and_stderr, wait_thread]
- # Open3.popen2e([env, ] exe_path, *args, options = {}) -> [stdin, stdout_and_stderr, wait_thread]
- # Open3.popen2e([env, ] command_line, options = {}) {|stdin, stdout_and_stderr, wait_thread| ... } -> object
- # Open3.popen2e([env, ] exe_path, *args, options = {}) {|stdin, stdout_and_stderr, wait_thread| ... } -> object
- #
- # Basically a wrapper for
- # {Process.spawn}[rdoc-ref:Process.spawn]
- # that:
- #
- # - Creates a child process, by calling Process.spawn with the given arguments.
- # - Creates streams +stdin+, +stdout_and_stderr+,
- # which are the standard input and the merge of the standard output
- # and standard error streams in the child process.
- # - Creates thread +wait_thread+ that waits for the child process to exit;
- # the thread has method +pid+, which returns the process ID
- # of the child process.
- #
- # With no block given, returns the array
- # <tt>[stdin, stdout_and_stderr, wait_thread]</tt>.
- # The caller should close each of the two returned streams.
- #
- # stdin, stdout_and_stderr, wait_thread = Open3.popen2e('echo')
- # # => [#<IO:fd 6>, #<IO:fd 7>, #<Process::Waiter:0x00007f7577da4398 run>]
- # stdin.close
- # stdout_and_stderr.close
- # wait_thread.pid # => 2274600
- # wait_thread.value # => #<Process::Status: pid 2274600 exit 0>
- #
- # With a block given, calls the block with the three variables
- # (two streams and the wait thread)
- # and returns the block's return value.
- # The caller need not close the streams:
- #
- # Open3.popen2e('echo') do |stdin, stdout_and_stderr, wait_thread|
- # p stdin
- # p stdout_and_stderr
- # p wait_thread
- # p wait_thread.pid
- # p wait_thread.value
- # end
- #
- # Output:
- #
- # #<IO:fd 6>
- # #<IO:fd 7>
- # #<Process::Waiter:0x00007f75777578c8 sleep>
- # 2274763
- # #<Process::Status: pid 2274763 exit 0>
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # If the first argument is a hash, it becomes leading argument +env+
- # in the call to Process.spawn;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- #
- # If the last argument is a hash, it becomes trailing argument +options+
- # in the call to Process.spawn;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
- #
- # The single required argument is one of the following:
- #
- # - +command_line+ if it is a string,
- # and if it begins with a shell reserved word or special built-in,
- # or if it contains one or more metacharacters.
- # - +exe_path+ otherwise.
- #
- # <b>Argument +command_line+</b>
- #
- # \String argument +command_line+ is a command line to be passed to a shell;
- # it must begin with a shell reserved word, begin with a special built-in,
- # or contain meta characters:
+ # Open3.popen2e is similar to Open3.popen3 except that it merges
+ # the standard output stream and the standard error stream.
#
- # Open3.popen2e('if true; then echo "Foo"; fi') {|*args| p args } # Shell reserved word.
- # Open3.popen2e('echo') {|*args| p args } # Built-in.
- # Open3.popen2e('date > date.tmp') {|*args| p args } # Contains meta character.
+ # Block form:
#
- # Output (similar for each call above):
+ # Open3.popen2e([env,] cmd... [, opts]) {|stdin, stdout_and_stderr, wait_thr|
+ # pid = wait_thr.pid # pid of the started process.
+ # ...
+ # exit_status = wait_thr.value # Process::Status object returned.
+ # }
#
- # # => [#<IO:(closed)>, #<IO:(closed)>, #<Process::Waiter:0x00007f7577d8a1f0 dead>]
+ # Non-block form:
#
- # The command line may also contain arguments and options for the command:
- #
- # Open3.popen2e('echo "Foo"') { |i, o_and_e, t| o_and_e.gets }
- # "Foo\n"
- #
- # <b>Argument +exe_path+</b>
- #
- # Argument +exe_path+ is one of the following:
+ # stdin, stdout_and_stderr, wait_thr = Open3.popen2e([env,] cmd... [, opts])
+ # ...
+ # stdin.close # stdin and stdout_and_stderr should be closed explicitly in this form.
+ # stdout_and_stderr.close
#
- # - The string path to an executable to be called.
- # - A 2-element array containing the path to an executable
- # and the string to be used as the name of the executing process.
+ # See Process.spawn for the optional hash arguments _env_ and _opts_.
#
# Example:
- #
- # Open3.popen2e('/usr/bin/date') { |i, o_and_e, t| o_and_e.gets }
- # # => "Thu Sep 28 01:58:45 PM CDT 2023\n"
- #
- # Ruby invokes the executable directly, with no shell and no shell expansion:
- #
- # Open3.popen2e('doesnt_exist') { |i, o_and_e, t| o_and_e.gets } # Raises Errno::ENOENT
- #
- # If one or more +args+ is given, each is an argument or option
- # to be passed to the executable:
- #
- # Open3.popen2e('echo', 'C #') { |i, o_and_e, t| o_and_e.gets }
- # # => "C #\n"
- # Open3.popen2e('echo', 'hello', 'world') { |i, o_and_e, t| o_and_e.gets }
- # # => "hello world\n"
- #
- # Related:
- #
- # - Open3.popen2: Makes the standard input and standard output streams
- # of the child process available as separate streams,
- # with no access to the standard error stream.
- # - Open3.popen3: Makes the standard input, standard output,
- # and standard error streams
- # of the child process available as separate streams.
+ # # check gcc warnings
+ # source = "foo.c"
+ # Open3.popen2e("gcc", "-Wall", source) {|i,oe,t|
+ # oe.each {|line|
+ # if /warning/ =~ line
+ # ...
+ # end
+ # }
+ # }
#
def popen2e(*cmd, &block)
if Hash === cmd.last
@@ -550,100 +238,44 @@ module Open3
private :popen_run
end
- # :call-seq:
- # Open3.capture3([env, ] command_line, options = {}) -> [stdout_s, stderr_s, status]
- # Open3.capture3([env, ] exe_path, *args, options = {}) -> [stdout_s, stderr_s, status]
- #
- # Basically a wrapper for Open3.popen3 that:
- #
- # - Creates a child process, by calling Open3.popen3 with the given arguments
- # (except for certain entries in hash +options+; see below).
- # - Returns as strings +stdout_s+ and +stderr_s+ the standard output
- # and standard error of the child process.
- # - Returns as +status+ a <tt>Process::Status</tt> object
- # that represents the exit status of the child process.
+ # Open3.capture3 captures the standard output and the standard error of a command.
#
- # Returns the array <tt>[stdout_s, stderr_s, status]</tt>:
+ # stdout_str, stderr_str, status = Open3.capture3([env,] cmd... [, opts])
#
- # stdout_s, stderr_s, status = Open3.capture3('echo "Foo"')
- # # => ["Foo\n", "", #<Process::Status: pid 2281954 exit 0>]
+ # The arguments env, cmd and opts are passed to Open3.popen3 except
+ # <code>opts[:stdin_data]</code> and <code>opts[:binmode]</code>. See Process.spawn.
#
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
+ # If <code>opts[:stdin_data]</code> is specified, it is sent to the command's standard input.
#
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
+ # If <code>opts[:binmode]</code> is true, internal pipes are set to binary mode.
#
- # If the first argument is a hash, it becomes leading argument +env+
- # in the call to Open3.popen3;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ # Examples:
#
- # If the last argument is a hash, it becomes trailing argument +options+
- # in the call to Open3.popen3;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ # # dot is a command of graphviz.
+ # graph = <<'End'
+ # digraph g {
+ # a -> b
+ # }
+ # End
+ # drawn_graph, dot_log = Open3.capture3("dot -v", :stdin_data=>graph)
#
- # The hash +options+ is given;
- # two options have local effect in method Open3.capture3:
+ # o, e, s = Open3.capture3("echo abc; sort >&2", :stdin_data=>"foo\nbar\nbaz\n")
+ # p o #=> "abc\n"
+ # p e #=> "bar\nbaz\nfoo\n"
+ # p s #=> #<Process::Status: pid 32682 exit 0>
#
- # - If entry <tt>options[:stdin_data]</tt> exists, the entry is removed
- # and its string value is sent to the command's standard input:
- #
- # Open3.capture3('tee', stdin_data: 'Foo')
- # # => ["Foo", "", #<Process::Status: pid 2319575 exit 0>]
- #
- # - If entry <tt>options[:binmode]</tt> exists, the entry is removed and
- # the internal streams are set to binary mode.
- #
- # The single required argument is one of the following:
- #
- # - +command_line+ if it is a string,
- # and if it begins with a shell reserved word or special built-in,
- # or if it contains one or more metacharacters.
- # - +exe_path+ otherwise.
- #
- # <b>Argument +command_line+</b>
- #
- # \String argument +command_line+ is a command line to be passed to a shell;
- # it must begin with a shell reserved word, begin with a special built-in,
- # or contain meta characters:
- #
- # Open3.capture3('if true; then echo "Foo"; fi') # Shell reserved word.
- # # => ["Foo\n", "", #<Process::Status: pid 2282025 exit 0>]
- # Open3.capture3('echo') # Built-in.
- # # => ["\n", "", #<Process::Status: pid 2282092 exit 0>]
- # Open3.capture3('date > date.tmp') # Contains meta character.
- # # => ["", "", #<Process::Status: pid 2282110 exit 0>]
- #
- # The command line may also contain arguments and options for the command:
- #
- # Open3.capture3('echo "Foo"')
- # # => ["Foo\n", "", #<Process::Status: pid 2282092 exit 0>]
- #
- # <b>Argument +exe_path+</b>
- #
- # Argument +exe_path+ is one of the following:
- #
- # - The string path to an executable to be called.
- # - A 2-element array containing the path to an executable
- # and the string to be used as the name of the executing process.
- #
- # Example:
- #
- # Open3.capture3('/usr/bin/date')
- # # => ["Thu Sep 28 05:03:51 PM CDT 2023\n", "", #<Process::Status: pid 2282300 exit 0>]
- #
- # Ruby invokes the executable directly, with no shell and no shell expansion:
- #
- # Open3.capture3('doesnt_exist') # Raises Errno::ENOENT
- #
- # If one or more +args+ is given, each is an argument or option
- # to be passed to the executable:
- #
- # Open3.capture3('echo', 'C #')
- # # => ["C #\n", "", #<Process::Status: pid 2282368 exit 0>]
- # Open3.capture3('echo', 'hello', 'world')
- # # => ["hello world\n", "", #<Process::Status: pid 2282372 exit 0>]
+ # # generate a thumbnail image using the convert command of ImageMagick.
+ # # However, if the image is really stored in a file,
+ # # system("convert", "-thumbnail", "80", "png:#{filename}", "png:-") is better
+ # # because of reduced memory consumption.
+ # # But if the image is stored in a DB or generated by the gnuplot Open3.capture2 example,
+ # # Open3.capture3 should be considered.
+ # #
+ # image = File.read("/usr/share/openclipart/png/animals/mammals/sheep-md-v0.1.png", :binmode=>true)
+ # thumbnail, err, s = Open3.capture3("convert -thumbnail 80 png:- png:-", :stdin_data=>image, :binmode=>true)
+ # if s.success?
+ # STDOUT.binmode; print thumbnail
+ # end
#
def capture3(*cmd)
if Hash === cmd.last
@@ -677,100 +309,34 @@ module Open3
end
module_function :capture3
- # :call-seq:
- # Open3.capture2([env, ] command_line, options = {}) -> [stdout_s, status]
- # Open3.capture2([env, ] exe_path, *args, options = {}) -> [stdout_s, status]
- #
- # Basically a wrapper for Open3.popen3 that:
- #
- # - Creates a child process, by calling Open3.popen3 with the given arguments
- # (except for certain entries in hash +options+; see below).
- # - Returns as string +stdout_s+ the standard output of the child process.
- # - Returns as +status+ a <tt>Process::Status</tt> object
- # that represents the exit status of the child process.
- #
- # Returns the array <tt>[stdout_s, status]</tt>:
- #
- # stdout_s, status = Open3.capture2('echo "Foo"')
- # # => ["Foo\n", #<Process::Status: pid 2326047 exit 0>]
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
+ # Open3.capture2 captures the standard output of a command.
#
- # If the first argument is a hash, it becomes leading argument +env+
- # in the call to Open3.popen3;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ # stdout_str, status = Open3.capture2([env,] cmd... [, opts])
#
- # If the last argument is a hash, it becomes trailing argument +options+
- # in the call to Open3.popen3;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ # The arguments env, cmd and opts are passed to Open3.popen3 except
+ # <code>opts[:stdin_data]</code> and <code>opts[:binmode]</code>. See Process.spawn.
#
- # The hash +options+ is given;
- # two options have local effect in method Open3.capture2:
+ # If <code>opts[:stdin_data]</code> is specified, it is sent to the command's standard input.
#
- # - If entry <tt>options[:stdin_data]</tt> exists, the entry is removed
- # and its string value is sent to the command's standard input:
- #
- # Open3.capture2('tee', stdin_data: 'Foo')
- #
- # # => ["Foo", #<Process::Status: pid 2326087 exit 0>]
- #
- # - If entry <tt>options[:binmode]</tt> exists, the entry is removed and
- # the internal streams are set to binary mode.
- #
- # The single required argument is one of the following:
- #
- # - +command_line+ if it is a string,
- # and if it begins with a shell reserved word or special built-in,
- # or if it contains one or more metacharacters.
- # - +exe_path+ otherwise.
- #
- # <b>Argument +command_line+</b>
- #
- # \String argument +command_line+ is a command line to be passed to a shell;
- # it must begin with a shell reserved word, begin with a special built-in,
- # or contain meta characters:
- #
- # Open3.capture2('if true; then echo "Foo"; fi') # Shell reserved word.
- # # => ["Foo\n", #<Process::Status: pid 2326131 exit 0>]
- # Open3.capture2('echo') # Built-in.
- # # => ["\n", #<Process::Status: pid 2326139 exit 0>]
- # Open3.capture2('date > date.tmp') # Contains meta character.
- # # => ["", #<Process::Status: pid 2326174 exit 0>]
- #
- # The command line may also contain arguments and options for the command:
- #
- # Open3.capture2('echo "Foo"')
- # # => ["Foo\n", #<Process::Status: pid 2326183 exit 0>]
- #
- # <b>Argument +exe_path+</b>
- #
- # Argument +exe_path+ is one of the following:
- #
- # - The string path to an executable to be called.
- # - A 2-element array containing the path to an executable
- # and the string to be used as the name of the executing process.
+ # If <code>opts[:binmode]</code> is true, internal pipes are set to binary mode.
#
# Example:
#
- # Open3.capture2('/usr/bin/date')
- # # => ["Fri Sep 29 01:00:39 PM CDT 2023\n", #<Process::Status: pid 2326222 exit 0>]
- #
- # Ruby invokes the executable directly, with no shell and no shell expansion:
- #
- # Open3.capture2('doesnt_exist') # Raises Errno::ENOENT
- #
- # If one or more +args+ is given, each is an argument or option
- # to be passed to the executable:
- #
- # Open3.capture2('echo', 'C #')
- # # => ["C #\n", #<Process::Status: pid 2326267 exit 0>]
- # Open3.capture2('echo', 'hello', 'world')
- # # => ["hello world\n", #<Process::Status: pid 2326299 exit 0>]
+ # # factor is a command for integer factorization.
+ # o, s = Open3.capture2("factor", :stdin_data=>"42")
+ # p o #=> "42: 2 3 7\n"
+ #
+ # # generate x**2 graph in png using gnuplot.
+ # gnuplot_commands = <<"End"
+ # set terminal png
+ # plot x**2, "-" with lines
+ # 1 14
+ # 2 1
+ # 3 8
+ # 4 5
+ # e
+ # End
+ # image, s = Open3.capture2("gnuplot", :stdin_data=>gnuplot_commands, :binmode=>true)
#
def capture2(*cmd)
if Hash === cmd.last
@@ -804,100 +370,21 @@ module Open3
end
module_function :capture2
- # :call-seq:
- # Open3.capture2e([env, ] command_line, options = {}) -> [stdout_and_stderr_s, status]
- # Open3.capture2e([env, ] exe_path, *args, options = {}) -> [stdout_and_stderr_s, status]
- #
- # Basically a wrapper for Open3.popen3 that:
- #
- # - Creates a child process, by calling Open3.popen3 with the given arguments
- # (except for certain entries in hash +options+; see below).
- # - Returns as string +stdout_and_stderr_s+ the merged standard output
- # and standard error of the child process.
- # - Returns as +status+ a <tt>Process::Status</tt> object
- # that represents the exit status of the child process.
- #
- # Returns the array <tt>[stdout_and_stderr_s, status]</tt>:
- #
- # stdout_and_stderr_s, status = Open3.capture2e('echo "Foo"')
- # # => ["Foo\n", #<Process::Status: pid 2371692 exit 0>]
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
- #
- # Unlike Process.spawn, this method waits for the child process to exit
- # before returning, so the caller need not do so.
- #
- # If the first argument is a hash, it becomes leading argument +env+
- # in the call to Open3.popen3;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- #
- # If the last argument is a hash, it becomes trailing argument +options+
- # in the call to Open3.popen3;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
- #
- # The hash +options+ is given;
- # two options have local effect in method Open3.capture2e:
- #
- # - If entry <tt>options[:stdin_data]</tt> exists, the entry is removed
- # and its string value is sent to the command's standard input:
+ # Open3.capture2e captures the standard output and the standard error of a command.
#
- # Open3.capture2e('tee', stdin_data: 'Foo')
- # # => ["Foo", #<Process::Status: pid 2371732 exit 0>]
+ # stdout_and_stderr_str, status = Open3.capture2e([env,] cmd... [, opts])
#
- # - If entry <tt>options[:binmode]</tt> exists, the entry is removed and
- # the internal streams are set to binary mode.
+ # The arguments env, cmd and opts are passed to Open3.popen3 except
+ # <code>opts[:stdin_data]</code> and <code>opts[:binmode]</code>. See Process.spawn.
#
- # The single required argument is one of the following:
+ # If <code>opts[:stdin_data]</code> is specified, it is sent to the command's standard input.
#
- # - +command_line+ if it is a string,
- # and if it begins with a shell reserved word or special built-in,
- # or if it contains one or more metacharacters.
- # - +exe_path+ otherwise.
- #
- # <b>Argument +command_line+</b>
- #
- # \String argument +command_line+ is a command line to be passed to a shell;
- # it must begin with a shell reserved word, begin with a special built-in,
- # or contain meta characters:
- #
- # Open3.capture2e('if true; then echo "Foo"; fi') # Shell reserved word.
- # # => ["Foo\n", #<Process::Status: pid 2371740 exit 0>]
- # Open3.capture2e('echo') # Built-in.
- # # => ["\n", #<Process::Status: pid 2371774 exit 0>]
- # Open3.capture2e('date > date.tmp') # Contains meta character.
- # # => ["", #<Process::Status: pid 2371812 exit 0>]
- #
- # The command line may also contain arguments and options for the command:
- #
- # Open3.capture2e('echo "Foo"')
- # # => ["Foo\n", #<Process::Status: pid 2326183 exit 0>]
- #
- # <b>Argument +exe_path+</b>
- #
- # Argument +exe_path+ is one of the following:
- #
- # - The string path to an executable to be called.
- # - A 2-element array containing the path to an executable
- # and the string to be used as the name of the executing process.
+ # If <code>opts[:binmode]</code> is true, internal pipes are set to binary mode.
#
# Example:
#
- # Open3.capture2e('/usr/bin/date')
- # # => ["Sat Sep 30 09:01:46 AM CDT 2023\n", #<Process::Status: pid 2371820 exit 0>]
- #
- # Ruby invokes the executable directly, with no shell and no shell expansion:
- #
- # Open3.capture2e('doesnt_exist') # Raises Errno::ENOENT
- #
- # If one or more +args+ is given, each is an argument or option
- # to be passed to the executable:
- #
- # Open3.capture2e('echo', 'C #')
- # # => ["C #\n", #<Process::Status: pid 2371856 exit 0>]
- # Open3.capture2e('echo', 'hello', 'world')
- # # => ["hello world\n", #<Process::Status: pid 2371894 exit 0>]
+ # # capture make log
+ # make_log, s = Open3.capture2e("make")
#
def capture2e(*cmd)
if Hash === cmd.last
@@ -931,86 +418,48 @@ module Open3
end
module_function :capture2e
- # :call-seq:
- # Open3.pipeline_rw([env, ] *cmds, options = {}) -> [first_stdin, last_stdout, wait_threads]
- #
- # Basically a wrapper for
- # {Process.spawn}[rdoc-ref:Process.spawn]
- # that:
- #
- # - Creates a child process for each of the given +cmds+
- # by calling Process.spawn.
- # - Pipes the +stdout+ from each child to the +stdin+ of the next child,
- # or, for the first child, from the caller's +stdin+,
- # or, for the last child, to the caller's +stdout+.
- #
- # The method does not wait for child processes to exit,
- # so the caller must do so.
- #
- # With no block given, returns a 3-element array containing:
- #
- # - The +stdin+ stream of the first child process.
- # - The +stdout+ stream of the last child process.
- # - An array of the wait threads for all of the child processes.
- #
- # Example:
- #
- # first_stdin, last_stdout, wait_threads = Open3.pipeline_rw('sort', 'cat -n')
- # # => [#<IO:fd 20>, #<IO:fd 21>, [#<Process::Waiter:0x000055e8de29ab40 sleep>, #<Process::Waiter:0x000055e8de29a690 sleep>]]
- # first_stdin.puts("foo\nbar\nbaz")
- # first_stdin.close # Send EOF to sort.
- # puts last_stdout.read
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- #
- # Output:
- #
- # 1 bar
- # 2 baz
- # 3 foo
- #
- # With a block given, calls the block with the +stdin+ stream of the first child,
- # the +stdout+ stream of the last child,
- # and an array of the wait processes:
- #
- # Open3.pipeline_rw('sort', 'cat -n') do |first_stdin, last_stdout, wait_threads|
- # first_stdin.puts "foo\nbar\nbaz"
- # first_stdin.close # send EOF to sort.
- # puts last_stdout.read
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- # end
+ # Open3.pipeline_rw starts a list of commands as a pipeline with pipes
+ # which connect to stdin of the first command and stdout of the last command.
#
- # Output:
+ # Open3.pipeline_rw(cmd1, cmd2, ... [, opts]) {|first_stdin, last_stdout, wait_threads|
+ # ...
+ # }
#
- # 1 bar
- # 2 baz
- # 3 foo
+ # first_stdin, last_stdout, wait_threads = Open3.pipeline_rw(cmd1, cmd2, ... [, opts])
+ # ...
+ # first_stdin.close
+ # last_stdout.close
#
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
#
- # If the first argument is a hash, it becomes leading argument +env+
- # in each call to Process.spawn;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ # cmd:
+ # commandline command line string which is passed to a shell
+ # [env, commandline, opts] command line string which is passed to a shell
+ # [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell)
+ # [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)
#
- # If the last argument is a hash, it becomes trailing argument +options+
- # in each call to Process.spawn;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ # Note that env and opts are optional, as for Process.spawn.
#
- # Each remaining argument in +cmds+ is one of:
+ # The options to pass to Process.spawn are constructed by merging
+ # +opts+, the last hash element of the array, and
+ # specifications for the pipes between each of the commands.
#
- # - A +command_line+: a string that begins with a shell reserved word
- # or special built-in, or contains one or more metacharacters.
- # - An +exe_path+: the string path to an executable to be called.
- # - An array containing a +command_line+ or an +exe_path+,
- # along with zero or more string arguments for the command.
- #
- # See {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
+ # Example:
#
+ # Open3.pipeline_rw("tr -dc A-Za-z", "wc -c") {|i, o, ts|
+ # i.puts "All persons more than a mile high to leave the court."
+ # i.close
+ # p o.gets #=> "42\n"
+ # }
+ #
+ # Open3.pipeline_rw("sort", "cat -n") {|stdin, stdout, wait_thrs|
+ # stdin.puts "foo"
+ # stdin.puts "bar"
+ # stdin.puts "baz"
+ # stdin.close # send EOF to sort.
+ # p stdout.read #=> " 1\tbar\n 2\tbaz\n 3\tfoo\n"
+ # }
def pipeline_rw(*cmds, &block)
if Hash === cmds.last
opts = cmds.pop.dup
@@ -1029,77 +478,43 @@ module Open3
end
module_function :pipeline_rw
- # :call-seq:
- # Open3.pipeline_r([env, ] *cmds, options = {}) -> [last_stdout, wait_threads]
+ # Open3.pipeline_r starts a list of commands as a pipeline with a pipe
+ # which connects to stdout of the last command.
#
- # Basically a wrapper for
- # {Process.spawn}[rdoc-ref:Process.spawn]
- # that:
+ # Open3.pipeline_r(cmd1, cmd2, ... [, opts]) {|last_stdout, wait_threads|
+ # ...
+ # }
#
- # - Creates a child process for each of the given +cmds+
- # by calling Process.spawn.
- # - Pipes the +stdout+ from each child to the +stdin+ of the next child,
- # or, for the last child, to the caller's +stdout+.
+ # last_stdout, wait_threads = Open3.pipeline_r(cmd1, cmd2, ... [, opts])
+ # ...
+ # last_stdout.close
#
- # The method does not wait for child processes to exit,
- # so the caller must do so.
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
#
- # With no block given, returns a 2-element array containing:
+ # cmd:
+ # commandline command line string which is passed to a shell
+ # [env, commandline, opts] command line string which is passed to a shell
+ # [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell)
+ # [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)
#
- # - The +stdout+ stream of the last child process.
- # - An array of the wait threads for all of the child processes.
+ # Note that env and opts are optional, as for Process.spawn.
#
# Example:
#
- # last_stdout, wait_threads = Open3.pipeline_r('ls', 'grep R')
- # # => [#<IO:fd 5>, [#<Process::Waiter:0x000055e8de2f9898 dead>, #<Process::Waiter:0x000055e8de2f94b0 sleep>]]
- # puts last_stdout.read
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- #
- # Output:
- #
- # Rakefile
- # README.md
- #
- # With a block given, calls the block with the +stdout+ stream
- # of the last child process,
- # and an array of the wait processes:
- #
- # Open3.pipeline_r('ls', 'grep R') do |last_stdout, wait_threads|
- # puts last_stdout.read
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- # end
- #
- # Output:
- #
- # Rakefile
- # README.md
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
- #
- # If the first argument is a hash, it becomes leading argument +env+
- # in each call to Process.spawn;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- #
- # If the last argument is a hash, it becomes trailing argument +options+
- # in each call to Process.spawn;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ # Open3.pipeline_r("zcat /var/log/apache2/access.log.*.gz",
+ # [{"LANG"=>"C"}, "grep", "GET /favicon.ico"],
+ # "logresolve") {|o, ts|
+ # o.each_line {|line|
+ # ...
+ # }
+ # }
#
- # Each remaining argument in +cmds+ is one of:
- #
- # - A +command_line+: a string that begins with a shell reserved word
- # or special built-in, or contains one or more metacharacters.
- # - An +exe_path+: the string path to an executable to be called.
- # - An array containing a +command_line+ or an +exe_path+,
- # along with zero or more string arguments for the command.
- #
- # See {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
+ # Open3.pipeline_r("yes", "head -10") {|o, ts|
+ # p o.read #=> "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"
+ # p ts[0].value #=> #<Process::Status: pid 24910 SIGPIPE (signal 13)>
+ # p ts[1].value #=> #<Process::Status: pid 24913 exit 0>
+ # }
#
def pipeline_r(*cmds, &block)
if Hash === cmds.last
@@ -1115,82 +530,33 @@ module Open3
end
module_function :pipeline_r
-
- # :call-seq:
- # Open3.pipeline_w([env, ] *cmds, options = {}) -> [first_stdin, wait_threads]
+ # Open3.pipeline_w starts a list of commands as a pipeline with a pipe
+ # which connects to stdin of the first command.
#
- # Basically a wrapper for
- # {Process.spawn}[rdoc-ref:Process.spawn]
- # that:
+ # Open3.pipeline_w(cmd1, cmd2, ... [, opts]) {|first_stdin, wait_threads|
+ # ...
+ # }
#
- # - Creates a child process for each of the given +cmds+
- # by calling Process.spawn.
- # - Pipes the +stdout+ from each child to the +stdin+ of the next child,
- # or, for the first child, pipes the caller's +stdout+ to the child's +stdin+.
+ # first_stdin, wait_threads = Open3.pipeline_w(cmd1, cmd2, ... [, opts])
+ # ...
+ # first_stdin.close
#
- # The method does not wait for child processes to exit,
- # so the caller must do so.
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
#
- # With no block given, returns a 2-element array containing:
+ # cmd:
+ # commandline command line string which is passed to a shell
+ # [env, commandline, opts] command line string which is passed to a shell
+ # [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell)
+ # [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)
#
- # - The +stdin+ stream of the first child process.
- # - An array of the wait threads for all of the child processes.
+ # Note that env and opts are optional, as for Process.spawn.
#
# Example:
#
- # first_stdin, wait_threads = Open3.pipeline_w('sort', 'cat -n')
- # # => [#<IO:fd 7>, [#<Process::Waiter:0x000055e8de928278 run>, #<Process::Waiter:0x000055e8de923e80 run>]]
- # first_stdin.puts("foo\nbar\nbaz")
- # first_stdin.close # Send EOF to sort.
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- #
- # Output:
- #
- # 1 bar
- # 2 baz
- # 3 foo
- #
- # With a block given, calls the block with the +stdin+ stream
- # of the first child process,
- # and an array of the wait processes:
- #
- # Open3.pipeline_w('sort', 'cat -n') do |first_stdin, wait_threads|
- # first_stdin.puts("foo\nbar\nbaz")
- # first_stdin.close # Send EOF to sort.
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- # end
- #
- # Output:
- #
- # 1 bar
- # 2 baz
- # 3 foo
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
- #
- # If the first argument is a hash, it becomes leading argument +env+
- # in each call to Process.spawn;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- #
- # If the last argument is a hash, it becomes trailing argument +options+
- # in each call to Process.spawn;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
- #
- # Each remaining argument in +cmds+ is one of:
- #
- # - A +command_line+: a string that begins with a shell reserved word
- # or special built-in, or contains one or more metacharacters.
- # - An +exe_path+: the string path to an executable to be called.
- # - An array containing a +command_line+ or an +exe_path+,
- # along with zero or more string arguments for the command.
- #
- # See {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
+ # Open3.pipeline_w("bzip2 -c", :out=>"/tmp/hello.bz2") {|i, ts|
+ # i.puts "hello"
+ # }
#
def pipeline_w(*cmds, &block)
if Hash === cmds.last
@@ -1207,67 +573,49 @@ module Open3
end
module_function :pipeline_w
- # :call-seq:
- # Open3.pipeline_start([env, ] *cmds, options = {}) -> [wait_threads]
- #
- # Basically a wrapper for
- # {Process.spawn}[rdoc-ref:Process.spawn]
- # that:
- #
- # - Creates a child process for each of the given +cmds+
- # by calling Process.spawn.
- # - Does not wait for child processes to exit.
- #
- # With no block given, returns an array of the wait threads
- # for all of the child processes.
- #
- # Example:
- #
- # wait_threads = Open3.pipeline_start('ls', 'grep R')
- # # => [#<Process::Waiter:0x000055e8de9d2bb0 run>, #<Process::Waiter:0x000055e8de9d2890 run>]
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- #
- # Output:
- #
- # Rakefile
- # README.md
+ # Open3.pipeline_start starts a list of commands as a pipeline.
+ # No pipes are created for stdin of the first command and
+ # stdout of the last command.
#
- # With a block given, calls the block with an array of the wait processes:
+ # Open3.pipeline_start(cmd1, cmd2, ... [, opts]) {|wait_threads|
+ # ...
+ # }
#
- # Open3.pipeline_start('ls', 'grep R') do |wait_threads|
- # wait_threads.each do |wait_thread|
- # wait_thread.join
- # end
- # end
- #
- # Output:
- #
- # Rakefile
- # README.md
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
+ # wait_threads = Open3.pipeline_start(cmd1, cmd2, ... [, opts])
+ # ...
#
- # If the first argument is a hash, it becomes leading argument +env+
- # in each call to Process.spawn;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
#
- # If the last argument is a hash, it becomes trailing argument +options+
- # in each call to Process.spawn;
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ # cmd:
+ # commandline command line string which is passed to a shell
+ # [env, commandline, opts] command line string which is passed to a shell
+ # [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell)
+ # [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)
#
- # Each remaining argument in +cmds+ is one of:
+ # Note that env and opts are optional, as for Process.spawn.
#
- # - A +command_line+: a string that begins with a shell reserved word
- # or special built-in, or contains one or more metacharacters.
- # - An +exe_path+: the string path to an executable to be called.
- # - An array containing a +command_line+ or an +exe_path+,
- # along with zero or more string arguments for the command.
+ # Example:
#
- # See {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
+ # # Run xeyes in 10 seconds.
+ # Open3.pipeline_start("xeyes") {|ts|
+ # sleep 10
+ # t = ts[0]
+ # Process.kill("TERM", t.pid)
+ # p t.value #=> #<Process::Status: pid 911 SIGTERM (signal 15)>
+ # }
+ #
+ # # Convert pdf to ps and send it to a printer.
+ # # Collect error message of pdftops and lpr.
+ # pdf_file = "paper.pdf"
+ # printer = "printer-name"
+ # err_r, err_w = IO.pipe
+ # Open3.pipeline_start(["pdftops", pdf_file, "-"],
+ # ["lpr", "-P#{printer}"],
+ # :err=>err_w) {|ts|
+ # err_w.close
+ # p err_r.read # error messages of pdftops and lpr.
+ # }
#
def pipeline_start(*cmds, &block)
if Hash === cmds.last
@@ -1285,51 +633,57 @@ module Open3
end
module_function :pipeline_start
- # :call-seq:
- # Open3.pipeline([env, ] *cmds, options = {}) -> array_of_statuses
- #
- # Basically a wrapper for
- # {Process.spawn}[rdoc-ref:Process.spawn]
- # that:
+ # Open3.pipeline starts a list of commands as a pipeline.
+ # It waits for the completion of the commands.
+ # No pipes are created for stdin of the first command and
+ # stdout of the last command.
#
- # - Creates a child process for each of the given +cmds+
- # by calling Process.spawn.
- # - Pipes the +stdout+ from each child to the +stdin+ of the next child,
- # or, for the last child, to the caller's +stdout+.
- # - Waits for the child processes to exit.
- # - Returns an array of Process::Status objects (one for each child).
+ # status_list = Open3.pipeline(cmd1, cmd2, ... [, opts])
#
- # Example:
+ # Each cmd is a string or an array.
+ # If it is an array, the elements are passed to Process.spawn.
#
- # wait_threads = Open3.pipeline('ls', 'grep R')
- # # => [#<Process::Status: pid 2139200 exit 0>, #<Process::Status: pid 2139202 exit 0>]
+ # cmd:
+ # commandline command line string which is passed to a shell
+ # [env, commandline, opts] command line string which is passed to a shell
+ # [env, cmdname, arg1, ..., opts] command name and one or more arguments (no shell)
+ # [env, [cmdname, argv0], arg1, ..., opts] command name and arguments including argv[0] (no shell)
#
- # Output:
+ # Note that env and opts are optional, as Process.spawn.
#
- # Rakefile
- # README.md
- #
- # Like Process.spawn, this method has potential security vulnerabilities
- # if called with untrusted input;
- # see {Command Injection}[rdoc-ref:command_injection.rdoc@Command+Injection].
- #
- # If the first argument is a hash, it becomes leading argument +env+
- # in each call to Process.spawn;
- # see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- #
- # If the last argument is a hash, it becomes trailing argument +options+
- # in each call to Process.spawn'
- # see {Execution Options}[rdoc-ref:Process@Execution+Options].
- #
- # Each remaining argument in +cmds+ is one of:
- #
- # - A +command_line+: a string that begins with a shell reserved word
- # or special built-in, or contains one or more metacharacters.
- # - An +exe_path+: the string path to an executable to be called.
- # - An array containing a +command_line+ or an +exe_path+,
- # along with zero or more string arguments for the command.
+ # Example:
#
- # See {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
+ # fname = "/usr/share/man/man1/ruby.1.gz"
+ # p Open3.pipeline(["zcat", fname], "nroff -man", "less")
+ # #=> [#<Process::Status: pid 11817 exit 0>,
+ # # #<Process::Status: pid 11820 exit 0>,
+ # # #<Process::Status: pid 11828 exit 0>]
+ #
+ # fname = "/usr/share/man/man1/ls.1.gz"
+ # Open3.pipeline(["zcat", fname], "nroff -man", "colcrt")
+ #
+ # # convert PDF to PS and send to a printer by lpr
+ # pdf_file = "paper.pdf"
+ # printer = "printer-name"
+ # Open3.pipeline(["pdftops", pdf_file, "-"],
+ # ["lpr", "-P#{printer}"])
+ #
+ # # count lines
+ # Open3.pipeline("sort", "uniq -c", :in=>"names.txt", :out=>"count")
+ #
+ # # cyclic pipeline
+ # r,w = IO.pipe
+ # w.print "ibase=14\n10\n"
+ # Open3.pipeline("bc", "tee /dev/tty", :in=>r, :out=>w)
+ # #=> 14
+ # # 18
+ # # 22
+ # # 30
+ # # 42
+ # # 58
+ # # 78
+ # # 106
+ # # 202
#
def pipeline(*cmds)
if Hash === cmds.last
diff --git a/lib/open3/open3.gemspec b/lib/open3/open3.gemspec
index 21980decac..a33fca7444 100644
--- a/lib/open3/open3.gemspec
+++ b/lib/open3/open3.gemspec
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/open3/version.rb b/lib/open3/version.rb
index bfcec44ccc..b6b6ee2c9c 100644
--- a/lib/open3/version.rb
+++ b/lib/open3/version.rb
@@ -1,3 +1,3 @@
module Open3
- VERSION = "0.2.1"
+ VERSION = "0.1.2"
end
diff --git a/lib/optparse.rb b/lib/optparse.rb
index 50641867f0..53a4387bd8 100644
--- a/lib/optparse.rb
+++ b/lib/optparse.rb
@@ -8,6 +8,7 @@
# See OptionParser for documentation.
#
+
#--
# == Developer Documentation (not for RDoc output)
#
@@ -47,7 +48,7 @@
#
# == OptionParser
#
-# === New to +OptionParser+?
+# === New to \OptionParser?
#
# See the {Tutorial}[optparse/tutorial.rdoc].
#
@@ -151,14 +152,14 @@
# OptionParser supports the ability to coerce command line arguments
# into objects for us.
#
-# OptionParser comes with a few ready-to-use kinds of type
+# OptionParser comes with a few ready-to-use kinds of type
# coercion. They are:
#
-# - Date -- Anything accepted by +Date.parse+ (need to require +optparse/date+)
-# - DateTime -- Anything accepted by +DateTime.parse+ (need to require +optparse/date+)
-# - Time -- Anything accepted by +Time.httpdate+ or +Time.parse+ (need to require +optparse/time+)
-# - URI -- Anything accepted by +URI.parse+ (need to require +optparse/uri+)
-# - Shellwords -- Anything accepted by +Shellwords.shellwords+ (need to require +optparse/shellwords+)
+# - Date -- Anything accepted by +Date.parse+
+# - DateTime -- Anything accepted by +DateTime.parse+
+# - Time -- Anything accepted by +Time.httpdate+ or +Time.parse+
+# - URI -- Anything accepted by +URI.parse+
+# - Shellwords -- Anything accepted by +Shellwords.shellwords+
# - String -- Any non-empty string
# - Integer -- Any integer. Will convert octal. (e.g. 124, -3, 040)
# - Float -- Any float. (e.g. 10, 3.14, -100E+13)
@@ -424,8 +425,7 @@
# If you have any questions, file a ticket at http://bugs.ruby-lang.org.
#
class OptionParser
- # The version string
- OptionParser::Version = "0.5.0"
+ OptionParser::Version = "0.3.1"
# :stopdoc:
NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
@@ -438,8 +438,6 @@ class OptionParser
# and resolved against a list of acceptable values.
#
module Completion
- # :nodoc:
-
def self.regexp(key, icase)
Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'), icase)
end
@@ -461,7 +459,7 @@ class OptionParser
candidates
end
- def candidate(key, icase = false, pat = nil, &_)
+ def candidate(key, icase = false, pat = nil)
Completion.candidate(key, icase, pat, &method(:each))
end
@@ -512,8 +510,6 @@ class OptionParser
# RequiredArgument, etc.
#
class Switch
- # :nodoc:
-
attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block
#
@@ -701,11 +697,6 @@ class OptionParser
q.object_group(self) {pretty_print_contents(q)}
end
- def omitted_argument(val) # :nodoc:
- val.pop if val.size == 3 and val.last.nil?
- val
- end
-
#
# Switch that takes no arguments.
#
@@ -719,10 +710,10 @@ class OptionParser
conv_arg(arg)
end
- def self.incompatible_argument_styles(*) # :nodoc:
+ def self.incompatible_argument_styles(*)
end
- def self.pattern # :nodoc:
+ def self.pattern
Object
end
@@ -739,7 +730,7 @@ class OptionParser
#
# Raises an exception if argument is not present.
#
- def parse(arg, argv, &_)
+ def parse(arg, argv)
unless arg
raise MissingArgument if argv.empty?
arg = argv.shift
@@ -764,7 +755,7 @@ class OptionParser
if arg
conv_arg(*parse_arg(arg, &error))
else
- omitted_argument conv_arg(arg)
+ conv_arg(arg)
end
end
@@ -783,14 +774,13 @@ class OptionParser
#
def parse(arg, argv, &error)
if !(val = arg) and (argv.empty? or /\A-./ =~ (val = argv[0]))
- return nil, block
+ return nil, block, nil
end
opt = (val = parse_arg(val, &error))[1]
val = conv_arg(*val)
if opt and !arg
argv.shift
else
- omitted_argument val
val[0] = nil
end
val
@@ -808,8 +798,6 @@ class OptionParser
# matching pattern and converter pair. Also provides summary feature.
#
class List
- # :nodoc:
-
# Map from acceptable argument types to pattern and converter pairs.
attr_reader :atype
@@ -849,7 +837,7 @@ class OptionParser
def accept(t, pat = /.*/m, &block)
if pat
pat.respond_to?(:match) or
- raise TypeError, "has no 'match'", ParseError.filter_backtrace(caller(2))
+ raise TypeError, "has no `match'", ParseError.filter_backtrace(caller(2))
else
pat = t if t.respond_to?(:match)
end
@@ -1045,31 +1033,11 @@ XXX
to << "#compdef #{name}\n"
to << COMPSYS_HEADER
visit(:compsys, {}, {}) {|o, d|
- to << %Q[ "#{o}[#{d.gsub(/[\\\"\[\]]/, '\\\\\&')}]" \\\n]
+ to << %Q[ "#{o}[#{d.gsub(/[\"\[\]]/, '\\\\\&')}]" \\\n]
}
to << " '*:file:_files' && return 0\n"
end
- def help_exit
- if STDOUT.tty? && (pager = ENV.values_at(*%w[RUBY_PAGER PAGER]).find {|e| e && !e.empty?})
- less = ENV["LESS"]
- args = [{"LESS" => "#{!less || less.empty? ? '-' : less}Fe"}, pager, "w"]
- print = proc do |f|
- f.puts help
- rescue Errno::EPIPE
- # pager terminated
- end
- if Process.respond_to?(:fork) and false
- IO.popen("-") {|f| f ? Process.exec(*args, in: f) : print.call(STDOUT)}
- # unreachable
- end
- IO.popen(*args, &print)
- else
- puts help
- end
- exit
- end
-
#
# Default options for ARGV, which never appear in option summary.
#
@@ -1081,7 +1049,8 @@ XXX
#
Officious['help'] = proc do |parser|
Switch::NoArgument.new do |arg|
- parser.help_exit
+ puts parser.help
+ exit
end
end
@@ -1115,7 +1084,7 @@ XXX
Switch::OptionalArgument.new do |pkg|
if pkg
begin
- require_relative 'optparse/version'
+ require 'optparse/version'
rescue LoadError
else
show_version(*pkg.split(/,/)) or
@@ -1160,10 +1129,6 @@ XXX
default.to_i + 1
end
end
-
- #
- # See self.inc
- #
def inc(*args)
self.class.inc(*args)
end
@@ -1202,19 +1167,11 @@ XXX
def terminate(arg = nil)
self.class.terminate(arg)
end
- #
- # See #terminate.
- #
def self.terminate(arg = nil)
throw :terminate, arg
end
@stack = [DefaultList]
- #
- # Returns the global top option list.
- #
- # Do not use directly.
- #
def self.top() DefaultList end
#
@@ -1235,9 +1192,9 @@ XXX
#
# Directs to reject specified class argument.
#
- # +type+:: Argument class specifier, any object including Class.
+ # +t+:: Argument class specifier, any object including Class.
#
- # reject(type)
+ # reject(t)
#
def reject(*args, &blk) top.reject(*args, &blk) end
#
@@ -1327,24 +1284,10 @@ XXX
end
end
- #
- # Shows warning message with the program name
- #
- # +mesg+:: Message, defaulted to +$!+.
- #
- # See Kernel#warn.
- #
def warn(mesg = $!)
super("#{program_name}: #{mesg}")
end
- #
- # Shows message with the program name then aborts.
- #
- # +mesg+:: Message, defaulted to +$!+.
- #
- # See Kernel#abort.
- #
def abort(mesg = $!)
super("#{program_name}: #{mesg}")
end
@@ -1366,9 +1309,6 @@ XXX
#
# Pushes a new List.
#
- # If a block is given, yields +self+ and returns the result of the
- # block, otherwise returns +self+.
- #
def new
@stack.push(List.new)
if block_given?
@@ -1592,12 +1532,6 @@ XXX
nolong
end
- # ----
- # Option definition phase methods
- #
- # These methods are used to define options, or to construct an
- # OptionParser instance in other words.
-
# :call-seq:
# define(*params, &block)
#
@@ -1673,13 +1607,6 @@ XXX
top.append(string, nil, nil)
end
- # ----
- # Arguments parse phase methods
- #
- # These methods parse +argv+, convert, and store the results by
- # calling handlers. As these methods do not modify +self+, +self+
- # can be frozen.
-
#
# Parses command line arguments +argv+ in order. When a block is given,
# each non-option argument is yielded. When optional +into+ keyword
@@ -1689,21 +1616,21 @@ XXX
#
# Returns the rest of +argv+ left unparsed.
#
- def order(*argv, **keywords, &nonopt)
+ def order(*argv, into: nil, &nonopt)
argv = argv[0].dup if argv.size == 1 and Array === argv[0]
- order!(argv, **keywords, &nonopt)
+ order!(argv, into: into, &nonopt)
end
#
# Same as #order, but removes switches destructively.
# Non-option arguments remain in +argv+.
#
- def order!(argv = default_argv, into: nil, **keywords, &nonopt)
+ def order!(argv = default_argv, into: nil, &nonopt)
setter = ->(name, val) {into[name.to_sym] = val} if into
- parse_in_order(argv, setter, **keywords, &nonopt)
+ parse_in_order(argv, setter, &nonopt)
end
- def parse_in_order(argv = default_argv, setter = nil, exact: require_exact, **, &nonopt) # :nodoc:
+ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
opt, arg, val, rest = nil
nonopt ||= proc {|a| throw :terminate, a}
argv.unshift(arg) if arg = catch(:terminate) {
@@ -1714,24 +1641,19 @@ XXX
opt, rest = $1, $2
opt.tr!('_', '-')
begin
- if exact
- sw, = search(:long, opt)
- else
- sw, = complete(:long, opt, true)
+ sw, = complete(:long, opt, true)
+ if require_exact && !sw.long.include?(arg)
+ throw :terminate, arg unless raise_unknown
+ raise InvalidOption, arg
end
rescue ParseError
throw :terminate, arg unless raise_unknown
raise $!.set_option(arg, true)
- else
- unless sw
- throw :terminate, arg unless raise_unknown
- raise InvalidOption, arg
- end
end
begin
opt, cb, val = sw.parse(rest, argv) {|*exc| raise(*exc)}
- val = callback!(cb, 1, val) if cb
- callback!(setter, 2, sw.switch_name, val) if setter
+ val = cb.call(val) if cb
+ setter.call(sw.switch_name, val) if setter
rescue ParseError
raise $!.set_option(arg, rest)
end
@@ -1749,7 +1671,7 @@ XXX
val = arg.delete_prefix('-')
has_arg = true
rescue InvalidOption
- raise if exact
+ raise if require_exact
# if no short options match, try completion with long
# options.
sw, = complete(:long, opt)
@@ -1769,8 +1691,8 @@ XXX
end
begin
argv.unshift(opt) if opt and (!rest or (opt = opt.sub(/\A-*/, '-')) != '-')
- val = callback!(cb, 1, val) if cb
- callback!(setter, 2, sw.switch_name, val) if setter
+ val = cb.call(val) if cb
+ setter.call(sw.switch_name, val) if setter
rescue ParseError
raise $!.set_option(arg, arg.length > 2)
end
@@ -1796,19 +1718,6 @@ XXX
end
private :parse_in_order
- # Calls callback with _val_.
- def callback!(cb, max_arity, *args) # :nodoc:
- args.compact!
-
- if (size = args.size) < max_arity and cb.to_proc.lambda?
- (arity = cb.arity) < 0 and arity = (1-arity)
- arity = max_arity if arity > max_arity
- args[arity - 1] = nil if arity > size
- end
- cb.call(*args)
- end
- private :callback!
-
#
# Parses command line arguments +argv+ in permutation mode and returns
# list of non-option arguments. When optional +into+ keyword
@@ -1816,18 +1725,18 @@ XXX
# <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
# similar object).
#
- def permute(*argv, **keywords)
+ def permute(*argv, into: nil)
argv = argv[0].dup if argv.size == 1 and Array === argv[0]
- permute!(argv, **keywords)
+ permute!(argv, into: into)
end
#
# Same as #permute, but removes switches destructively.
# Non-option arguments remain in +argv+.
#
- def permute!(argv = default_argv, **keywords)
+ def permute!(argv = default_argv, into: nil)
nonopts = []
- order!(argv, **keywords, &nonopts.method(:<<))
+ order!(argv, into: into, &nonopts.method(:<<))
argv[0, 0] = nonopts
argv
end
@@ -1839,20 +1748,20 @@ XXX
# values are stored there via <code>[]=</code> method (so it can be Hash,
# or OpenStruct, or other similar object).
#
- def parse(*argv, **keywords)
+ def parse(*argv, into: nil)
argv = argv[0].dup if argv.size == 1 and Array === argv[0]
- parse!(argv, **keywords)
+ parse!(argv, into: into)
end
#
# Same as #parse, but removes switches destructively.
# Non-option arguments remain in +argv+.
#
- def parse!(argv = default_argv, **keywords)
+ def parse!(argv = default_argv, into: nil)
if ENV.include?('POSIXLY_CORRECT')
- order!(argv, **keywords)
+ order!(argv, into: into)
else
- permute!(argv, **keywords)
+ permute!(argv, into: into)
end
end
@@ -1866,16 +1775,7 @@ XXX
# # params["bar"] = "x" # --bar x
# # params["zot"] = "z" # --zot Z
#
- # Option +symbolize_names+ (boolean) specifies whether returned Hash keys should be Symbols; defaults to +false+ (use Strings).
- #
- # params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option", symbolize_names: true)
- # # params[:a] = true # -a
- # # params[:b] = "1" # -b1
- # # params[:foo] = "1" # --foo
- # # params[:bar] = "x" # --bar x
- # # params[:zot] = "z" # --zot Z
- #
- def getopts(*args, symbolize_names: false, **keywords)
+ def getopts(*args)
argv = Array === args.first ? args.shift : default_argv
single_options, *long_options = *args
@@ -1903,15 +1803,15 @@ XXX
end
end
- parse_in_order(argv, result.method(:[]=), **keywords)
- symbolize_names ? result.transform_keys(&:to_sym) : result
+ parse_in_order(argv, result.method(:[]=))
+ result
end
#
# See #getopts.
#
- def self.getopts(*args, symbolize_names: false)
- new.getopts(*args, symbolize_names: symbolize_names)
+ def self.getopts(*args)
+ new.getopts(*args)
end
#
@@ -1972,9 +1872,6 @@ XXX
DidYouMean.formatter.message_for(all_candidates & checker.correct(opt))
end
- #
- # Return candidates for +word+.
- #
def candidate(word)
list = []
case word
@@ -2016,10 +1913,10 @@ XXX
# The optional +into+ keyword argument works exactly like that accepted in
# method #parse.
#
- def load(filename = nil, **keywords)
+ def load(filename = nil, into: nil)
unless filename
basename = File.basename($0, '.*')
- return true if load(File.expand_path(basename, '~/.options'), **keywords) rescue nil
+ return true if load(File.expand_path(basename, '~/.options'), into: into) rescue nil
basename << ".options"
return [
# XDG
@@ -2031,11 +1928,11 @@ XXX
'~/config/settings',
].any? {|dir|
next if !dir or dir.empty?
- load(File.expand_path(basename, dir), **keywords) rescue nil
+ load(File.expand_path(basename, dir), into: into) rescue nil
}
end
begin
- parse(*File.readlines(filename, chomp: true), **keywords)
+ parse(*File.readlines(filename, chomp: true), into: into)
true
rescue Errno::ENOENT, Errno::ENOTDIR
false
@@ -2048,10 +1945,10 @@ XXX
#
# +env+ defaults to the basename of the program.
#
- def environment(env = File.basename($0, '.*'), **keywords)
+ def environment(env = File.basename($0, '.*'))
env = ENV[env] || ENV[env.upcase] or return
require 'shellwords'
- parse(*Shellwords.shellwords(env), **keywords)
+ parse(*Shellwords.shellwords(env))
end
#
@@ -2217,7 +2114,6 @@ XXX
# Reason which caused the error.
Reason = 'parse error'
- # :nodoc:
def initialize(*args, additional: nil)
@additional = additional
@arg0, = args
@@ -2368,19 +2264,19 @@ XXX
# Parses +self+ destructively in order and returns +self+ containing the
# rest arguments left unparsed.
#
- def order!(**keywords, &blk) options.order!(self, **keywords, &blk) end
+ def order!(&blk) options.order!(self, &blk) end
#
# Parses +self+ destructively in permutation mode and returns +self+
# containing the rest arguments left unparsed.
#
- def permute!(**keywords) options.permute!(self, **keywords) end
+ def permute!() options.permute!(self) end
#
# Parses +self+ destructively and returns +self+ containing the
# rest arguments left unparsed.
#
- def parse!(**keywords) options.parse!(self, **keywords) end
+ def parse!() options.parse!(self) end
#
# Substitution of getopts is possible as follows. Also see
@@ -2393,8 +2289,8 @@ XXX
# rescue OptionParser::ParseError
# end
#
- def getopts(*args, symbolize_names: false, **keywords)
- options.getopts(self, *args, symbolize_names: symbolize_names, **keywords)
+ def getopts(*args)
+ options.getopts(self, *args)
end
#
@@ -2404,8 +2300,7 @@ XXX
super
obj.instance_eval {@optparse = nil}
end
-
- def initialize(*args) # :nodoc:
+ def initialize(*args)
super
@optparse = nil
end
diff --git a/lib/optparse/ac.rb b/lib/optparse/ac.rb
index 23fc740d10..0953725e46 100644
--- a/lib/optparse/ac.rb
+++ b/lib/optparse/ac.rb
@@ -1,11 +1,7 @@
# frozen_string_literal: false
require_relative '../optparse'
-#
-# autoconf-like options.
-#
class OptionParser::AC < OptionParser
- # :stopdoc:
private
def _check_ac_args(name, block)
@@ -18,7 +14,6 @@ class OptionParser::AC < OptionParser
end
ARG_CONV = proc {|val| val.nil? ? true : val}
- private_constant :ARG_CONV
def _ac_arg_enable(prefix, name, help_string, block)
_check_ac_args(name, block)
@@ -34,27 +29,16 @@ class OptionParser::AC < OptionParser
enable
end
- # :startdoc:
-
public
- # Define <tt>--enable</tt> / <tt>--disable</tt> style option
- #
- # Appears as <tt>--enable-<i>name</i></tt> in help message.
def ac_arg_enable(name, help_string, &block)
_ac_arg_enable("enable", name, help_string, block)
end
- # Define <tt>--enable</tt> / <tt>--disable</tt> style option
- #
- # Appears as <tt>--disable-<i>name</i></tt> in help message.
def ac_arg_disable(name, help_string, &block)
_ac_arg_enable("disable", name, help_string, block)
end
- # Define <tt>--with</tt> / <tt>--without</tt> style option
- #
- # Appears as <tt>--with-<i>name</i></tt> in help message.
def ac_arg_with(name, help_string, &block)
_check_ac_args(name, block)
diff --git a/lib/optparse/kwargs.rb b/lib/optparse/kwargs.rb
index 59a2f61544..992aca467e 100644
--- a/lib/optparse/kwargs.rb
+++ b/lib/optparse/kwargs.rb
@@ -7,17 +7,12 @@ class OptionParser
#
# :include: ../../doc/optparse/creates_option.rdoc
#
- # Defines options which set in to _options_ for keyword parameters
- # of _method_.
- #
- # Parameters for each keywords are given as elements of _params_.
- #
- def define_by_keywords(options, method, **params)
- method.parameters.each do |type, name|
+ def define_by_keywords(options, meth, **opts)
+ meth.parameters.each do |type, name|
case type
when :key, :keyreq
op, cl = *(type == :key ? %w"[ ]" : ["", ""])
- define("--#{name}=#{op}#{name.upcase}#{cl}", *params[name]) do |o|
+ define("--#{name}=#{op}#{name.upcase}#{cl}", *opts[name]) do |o|
options[name] = o
end
end
diff --git a/lib/optparse/optparse.gemspec b/lib/optparse/optparse.gemspec
index 1aa54aa781..a4287ddeee 100644
--- a/lib/optparse/optparse.gemspec
+++ b/lib/optparse/optparse.gemspec
@@ -22,8 +22,7 @@ Gem::Specification.new do |spec|
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
- spec.files = Dir["{doc,lib,misc}/**/{*,.document}"] +
- %w[README.md ChangeLog COPYING .document .rdoc_options]
+ spec.files = Dir["{doc,lib,misc}/**/*"] + %w[README.md ChangeLog COPYING]
spec.rdoc_options = ["--main=README.md", "--op=rdoc", "--page-dir=doc"]
spec.bindir = "exe"
spec.executables = []
diff --git a/lib/optparse/version.rb b/lib/optparse/version.rb
index b5ed695146..b869d8fe51 100644
--- a/lib/optparse/version.rb
+++ b/lib/optparse/version.rb
@@ -2,11 +2,6 @@
# OptionParser internal utility
class << OptionParser
- #
- # Shows version string in packages if Version is defined.
- #
- # +pkgs+:: package list
- #
def show_version(*pkgs)
progname = ARGV.options.program_name
result = false
@@ -52,8 +47,6 @@ class << OptionParser
result
end
- # :stopdoc:
-
def each_const(path, base = ::Object)
path.split(/::|\//).inject(base) do |klass, name|
raise NameError, path unless Module === klass
@@ -75,6 +68,4 @@ class << OptionParser
end
end
end
-
- # :startdoc:
end
diff --git a/lib/ostruct.gemspec b/lib/ostruct.gemspec
deleted file mode 100644
index 08a7aefb05..0000000000
--- a/lib/ostruct.gemspec
+++ /dev/null
@@ -1,24 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Marc-Andre Lafortune"]
- spec.email = ["ruby-core@marc-andre.ca"]
-
- spec.summary = %q{Class to build custom data structures, similar to a Hash.}
- spec.description = %q{Class to build custom data structures, similar to a Hash.}
- spec.homepage = "https://github.com/ruby/ostruct"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.required_ruby_version = ">= 2.5.0"
-
- spec.files = [".gitignore", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "lib/ostruct.rb", "ostruct.gemspec"]
- spec.require_paths = ["lib"]
-end
diff --git a/lib/ostruct.rb b/lib/ostruct.rb
index c762baa5a5..a08561d6c9 100644
--- a/lib/ostruct.rb
+++ b/lib/ostruct.rb
@@ -107,15 +107,7 @@
# For all these reasons, consider not using OpenStruct at all.
#
class OpenStruct
- VERSION = "0.6.0"
-
- HAS_PERFORMANCE_WARNINGS = begin
- Warning[:performance]
- true
- rescue NoMethodError, ArgumentError
- false
- end
- private_constant :HAS_PERFORMANCE_WARNINGS
+ VERSION = "0.5.5"
#
# Creates a new OpenStruct object. By default, the resulting OpenStruct
@@ -132,10 +124,6 @@ class OpenStruct
# data # => #<OpenStruct country="Australia", capital="Canberra">
#
def initialize(hash=nil)
- if HAS_PERFORMANCE_WARNINGS && Warning[:performance]
- warn "OpenStruct use is discouraged for performance reasons", uplevel: 1, category: :performance
- end
-
if hash
update_to_values!(hash)
else
@@ -376,7 +364,7 @@ class OpenStruct
end
@table.delete(sym) do
return yield if block
- raise! NameError.new("no field '#{sym}' in #{self}", sym)
+ raise! NameError.new("no field `#{sym}' in #{self}", sym)
end
end
diff --git a/lib/ostruct/ostruct.gemspec b/lib/ostruct/ostruct.gemspec
new file mode 100644
index 0000000000..31ecc312c3
--- /dev/null
+++ b/lib/ostruct/ostruct.gemspec
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Marc-Andre Lafortune"]
+ spec.email = ["ruby-core@marc-andre.ca"]
+
+ spec.summary = %q{Class to build custom data structures, similar to a Hash.}
+ spec.description = %q{Class to build custom data structures, similar to a Hash.}
+ spec.homepage = "https://github.com/ruby/ostruct"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+ spec.required_ruby_version = ">= 2.5.0"
+
+ spec.files = [".gitignore", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "lib/ostruct.rb", "ostruct.gemspec"]
+ spec.require_paths = ["lib"]
+
+ spec.add_development_dependency "bundler"
+ spec.add_development_dependency "rake"
+end
diff --git a/lib/pp.gemspec b/lib/pp.gemspec
index 27a92a8ce4..3f08f400c4 100644
--- a/lib/pp.gemspec
+++ b/lib/pp.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "pp"
+ spec.version = "0.4.0"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
diff --git a/lib/pp.rb b/lib/pp.rb
index ed7e89923c..81551aa116 100644
--- a/lib/pp.rb
+++ b/lib/pp.rb
@@ -46,7 +46,6 @@ require 'prettyprint'
#
# To define a customized pretty printing function for your classes,
# redefine method <code>#pretty_print(pp)</code> in the class.
-# Note that <code>require 'pp'</code> is needed before redefining <code>#pretty_print(pp)</code>.
#
# <code>#pretty_print</code> takes the +pp+ argument, which is an instance of the PP class.
# The method uses #text, #breakable, #nest, #group and #pp to print the
@@ -62,9 +61,6 @@ require 'prettyprint'
# Tanaka Akira <akr@fsij.org>
class PP < PrettyPrint
-
- VERSION = "0.5.0"
-
# Returns the usable width for +out+.
# As the width of +out+:
# 1. If +out+ is assigned to a tty device, its width is used.
@@ -93,7 +89,7 @@ class PP < PrettyPrint
#
# PP.pp returns +out+.
def PP.pp(obj, out=$>, width=width_for(out))
- q = new(out, width)
+ q = PP.new(out, width)
q.guard_inspect_key {q.pp obj}
q.flush
#$pp = q
@@ -286,42 +282,16 @@ class PP < PrettyPrint
group(1, '{', '}') {
seplist(obj, nil, :each_pair) {|k, v|
group {
- pp_hash_pair k, v
+ pp k
+ text '=>'
+ group(1) {
+ breakable ''
+ pp v
+ }
}
}
}
end
-
- if RUBY_VERSION >= '3.4.'
- # A pretty print for a pair of Hash
- def pp_hash_pair(k, v)
- if Symbol === k
- sym_s = k.inspect
- if sym_s[1].match?(/["$@!]/) || sym_s[-1].match?(/[%&*+\-\/<=>@\]^`|~]/)
- text "#{k.to_s.inspect}:"
- else
- text "#{k}:"
- end
- else
- pp k
- text ' '
- text '=>'
- end
- group(1) {
- breakable
- pp v
- }
- end
- else
- def pp_hash_pair(k, v)
- pp k
- text '=>'
- group(1) {
- breakable ''
- pp v
- }
- end
- end
end
include PPMethods
@@ -448,10 +418,8 @@ end
class Data # :nodoc:
def pretty_print(q) # :nodoc:
- class_name = PP.mcall(self, Kernel, :class).name
- class_name = " #{class_name}" if class_name
- q.group(1, "#<data#{class_name}", '>') {
- q.seplist(PP.mcall(self, Kernel, :class).members, lambda { q.text "," }) {|member|
+ q.group(1, sprintf("#<data %s", PP.mcall(self, Kernel, :class).name), '>') {
+ q.seplist(PP.mcall(self, Data, :members), lambda { q.text "," }) {|member|
q.breakable
q.text member.to_s
q.text '='
@@ -466,11 +434,11 @@ class Data # :nodoc:
def pretty_print_cycle(q) # :nodoc:
q.text sprintf("#<data %s:...>", PP.mcall(self, Kernel, :class).name)
end
-end if defined?(Data.define)
+end if "3.2" <= RUBY_VERSION
class Range # :nodoc:
def pretty_print(q) # :nodoc:
- q.pp self.begin if self.begin
+ q.pp self.begin
q.breakable ''
q.text(self.exclude_end? ? '...' : '..')
q.breakable ''
@@ -661,6 +629,10 @@ end
module Kernel
# Returns a pretty printed object as a string.
#
+ # In order to use this method you must first require the PP module:
+ #
+ # require 'pp'
+ #
# See the PP module for more information.
def pretty_inspect
PP.pp(self, ''.dup)
diff --git a/lib/prettyprint.gemspec b/lib/prettyprint.gemspec
index a18adb174b..eae2227d60 100644
--- a/lib/prettyprint.gemspec
+++ b/lib/prettyprint.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "prettyprint"
+ spec.version = "0.1.1"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
diff --git a/lib/prettyprint.rb b/lib/prettyprint.rb
index 6f50192f5d..188c2e6db0 100644
--- a/lib/prettyprint.rb
+++ b/lib/prettyprint.rb
@@ -23,18 +23,16 @@
#
# == References
# Christian Lindig, Strictly Pretty, March 2000,
-# https://lindig.github.io/papers/strictly-pretty-2000.pdf
+# http://www.st.cs.uni-sb.de/~lindig/papers/#pretty
#
# Philip Wadler, A prettier printer, March 1998,
-# https://homepages.inf.ed.ac.uk/wadler/topics/language-design.html#prettier
+# http://homepages.inf.ed.ac.uk/wadler/topics/language-design.html#prettier
#
# == Author
# Tanaka Akira <akr@fsij.org>
#
class PrettyPrint
- VERSION = "0.2.0"
-
# This is a convenience method which is same as follows:
#
# begin
diff --git a/lib/prism.rb b/lib/prism.rb
deleted file mode 100644
index 66a64e7fd0..0000000000
--- a/lib/prism.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-# frozen_string_literal: true
-
-# The Prism Ruby parser.
-#
-# "Parsing Ruby is suddenly manageable!"
-# - You, hopefully
-#
-module Prism
- # There are many files in prism that are templated to handle every node type,
- # which means the files can end up being quite large. We autoload them to make
- # our require speed faster since consuming libraries are unlikely to use all
- # of these features.
-
- autoload :BasicVisitor, "prism/visitor"
- autoload :Compiler, "prism/compiler"
- autoload :DesugarCompiler, "prism/desugar_compiler"
- autoload :Dispatcher, "prism/dispatcher"
- autoload :DotVisitor, "prism/dot_visitor"
- autoload :DSL, "prism/dsl"
- autoload :InspectVisitor, "prism/inspect_visitor"
- autoload :LexCompat, "prism/lex_compat"
- autoload :LexRipper, "prism/lex_compat"
- autoload :MutationCompiler, "prism/mutation_compiler"
- autoload :Pack, "prism/pack"
- autoload :Pattern, "prism/pattern"
- autoload :Reflection, "prism/reflection"
- autoload :Serialize, "prism/serialize"
- autoload :Translation, "prism/translation"
- autoload :Visitor, "prism/visitor"
-
- # Some of these constants are not meant to be exposed, so marking them as
- # private here.
-
- private_constant :LexCompat
- private_constant :LexRipper
-
- # :call-seq:
- # Prism::lex_compat(source, **options) -> LexCompat::Result
- #
- # Returns a parse result whose value is an array of tokens that closely
- # resembles the return value of Ripper::lex. The main difference is that the
- # `:on_sp` token is not emitted.
- #
- # For supported options, see Prism::parse.
- def self.lex_compat(source, **options)
- LexCompat.new(source, **options).result # steep:ignore
- end
-
- # :call-seq:
- # Prism::lex_ripper(source) -> Array
- #
- # This lexes with the Ripper lex. It drops any space events but otherwise
- # returns the same tokens. Raises SyntaxError if the syntax in source is
- # invalid.
- def self.lex_ripper(source)
- LexRipper.new(source).result # steep:ignore
- end
-
- # :call-seq:
- # Prism::load(source, serialized) -> ParseResult
- #
- # Load the serialized AST using the source as a reference into a tree.
- def self.load(source, serialized)
- Serialize.load(source, serialized)
- end
-end
-
-require_relative "prism/polyfill/byteindex"
-require_relative "prism/node"
-require_relative "prism/node_ext"
-require_relative "prism/parse_result"
-
-# This is a Ruby implementation of the prism parser. If we're running on CRuby
-# and we haven't explicitly set the PRISM_FFI_BACKEND environment variable, then
-# it's going to require the built library. Otherwise, it's going to require a
-# module that uses FFI to call into the library.
-if RUBY_ENGINE == "ruby" and !ENV["PRISM_FFI_BACKEND"]
- require "prism/prism"
-
- # The C extension is the default backend on CRuby.
- Prism::BACKEND = :CEXT
-else
- require_relative "prism/ffi"
-
- # The FFI backend is used on other Ruby implementations.
- Prism::BACKEND = :FFI
-end
diff --git a/lib/prism/desugar_compiler.rb b/lib/prism/desugar_compiler.rb
deleted file mode 100644
index e3b15fc3b0..0000000000
--- a/lib/prism/desugar_compiler.rb
+++ /dev/null
@@ -1,391 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- class DesugarAndWriteNode # :nodoc:
- include DSL
-
- attr_reader :node, :default_source, :read_class, :write_class, :arguments
-
- def initialize(node, default_source, read_class, write_class, **arguments)
- @node = node
- @default_source = default_source
- @read_class = read_class
- @write_class = write_class
- @arguments = arguments
- end
-
- # Desugar `x &&= y` to `x && x = y`
- def compile
- and_node(
- location: node.location,
- left: public_send(read_class, location: node.name_loc, **arguments),
- right: public_send(
- write_class,
- location: node.location,
- **arguments,
- name_loc: node.name_loc,
- value: node.value,
- operator_loc: node.operator_loc
- ),
- operator_loc: node.operator_loc
- )
- end
- end
-
- class DesugarOrWriteDefinedNode # :nodoc:
- include DSL
-
- attr_reader :node, :default_source, :read_class, :write_class, :arguments
-
- def initialize(node, default_source, read_class, write_class, **arguments)
- @node = node
- @default_source = default_source
- @read_class = read_class
- @write_class = write_class
- @arguments = arguments
- end
-
- # Desugar `x ||= y` to `defined?(x) ? x : x = y`
- def compile
- if_node(
- location: node.location,
- if_keyword_loc: node.operator_loc,
- predicate: defined_node(
- location: node.name_loc,
- value: public_send(read_class, location: node.name_loc, **arguments),
- keyword_loc: node.operator_loc
- ),
- then_keyword_loc: node.operator_loc,
- statements: statements_node(
- location: node.location,
- body: [public_send(read_class, location: node.name_loc, **arguments)]
- ),
- subsequent: else_node(
- location: node.location,
- else_keyword_loc: node.operator_loc,
- statements: statements_node(
- location: node.location,
- body: [
- public_send(
- write_class,
- location: node.location,
- **arguments,
- name_loc: node.name_loc,
- value: node.value,
- operator_loc: node.operator_loc
- )
- ]
- ),
- end_keyword_loc: node.operator_loc
- ),
- end_keyword_loc: node.operator_loc
- )
- end
- end
-
- class DesugarOperatorWriteNode # :nodoc:
- include DSL
-
- attr_reader :node, :default_source, :read_class, :write_class, :arguments
-
- def initialize(node, default_source, read_class, write_class, **arguments)
- @node = node
- @default_source = default_source
- @read_class = read_class
- @write_class = write_class
- @arguments = arguments
- end
-
- # Desugar `x += y` to `x = x + y`
- def compile
- binary_operator_loc = node.binary_operator_loc.chop
-
- public_send(
- write_class,
- location: node.location,
- **arguments,
- name_loc: node.name_loc,
- value: call_node(
- location: node.location,
- receiver: public_send(
- read_class,
- location: node.name_loc,
- **arguments
- ),
- name: binary_operator_loc.slice.to_sym,
- message_loc: binary_operator_loc,
- arguments: arguments_node(
- location: node.value.location,
- arguments: [node.value]
- )
- ),
- operator_loc: node.binary_operator_loc.copy(
- start_offset: node.binary_operator_loc.end_offset - 1,
- length: 1
- )
- )
- end
- end
-
- class DesugarOrWriteNode # :nodoc:
- include DSL
-
- attr_reader :node, :default_source, :read_class, :write_class, :arguments
-
- def initialize(node, default_source, read_class, write_class, **arguments)
- @node = node
- @default_source = default_source
- @read_class = read_class
- @write_class = write_class
- @arguments = arguments
- end
-
- # Desugar `x ||= y` to `x || x = y`
- def compile
- or_node(
- location: node.location,
- left: public_send(read_class, location: node.name_loc, **arguments),
- right: public_send(
- write_class,
- location: node.location,
- **arguments,
- name_loc: node.name_loc,
- value: node.value,
- operator_loc: node.operator_loc
- ),
- operator_loc: node.operator_loc
- )
- end
- end
-
- private_constant :DesugarAndWriteNode, :DesugarOrWriteNode, :DesugarOrWriteDefinedNode, :DesugarOperatorWriteNode
-
- class ClassVariableAndWriteNode
- def desugar # :nodoc:
- DesugarAndWriteNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
- end
- end
-
- class ClassVariableOrWriteNode
- def desugar # :nodoc:
- DesugarOrWriteDefinedNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
- end
- end
-
- class ClassVariableOperatorWriteNode
- def desugar # :nodoc:
- DesugarOperatorWriteNode.new(self, source, :class_variable_read_node, :class_variable_write_node, name: name).compile
- end
- end
-
- class ConstantAndWriteNode
- def desugar # :nodoc:
- DesugarAndWriteNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
- end
- end
-
- class ConstantOrWriteNode
- def desugar # :nodoc:
- DesugarOrWriteDefinedNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
- end
- end
-
- class ConstantOperatorWriteNode
- def desugar # :nodoc:
- DesugarOperatorWriteNode.new(self, source, :constant_read_node, :constant_write_node, name: name).compile
- end
- end
-
- class GlobalVariableAndWriteNode
- def desugar # :nodoc:
- DesugarAndWriteNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
- end
- end
-
- class GlobalVariableOrWriteNode
- def desugar # :nodoc:
- DesugarOrWriteDefinedNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
- end
- end
-
- class GlobalVariableOperatorWriteNode
- def desugar # :nodoc:
- DesugarOperatorWriteNode.new(self, source, :global_variable_read_node, :global_variable_write_node, name: name).compile
- end
- end
-
- class InstanceVariableAndWriteNode
- def desugar # :nodoc:
- DesugarAndWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
- end
- end
-
- class InstanceVariableOrWriteNode
- def desugar # :nodoc:
- DesugarOrWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
- end
- end
-
- class InstanceVariableOperatorWriteNode
- def desugar # :nodoc:
- DesugarOperatorWriteNode.new(self, source, :instance_variable_read_node, :instance_variable_write_node, name: name).compile
- end
- end
-
- class LocalVariableAndWriteNode
- def desugar # :nodoc:
- DesugarAndWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
- end
- end
-
- class LocalVariableOrWriteNode
- def desugar # :nodoc:
- DesugarOrWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
- end
- end
-
- class LocalVariableOperatorWriteNode
- def desugar # :nodoc:
- DesugarOperatorWriteNode.new(self, source, :local_variable_read_node, :local_variable_write_node, name: name, depth: depth).compile
- end
- end
-
- # DesugarCompiler is a compiler that desugars Ruby code into a more primitive
- # form. This is useful for consumers that want to deal with fewer node types.
- class DesugarCompiler < MutationCompiler
- # @@foo &&= bar
- #
- # becomes
- #
- # @@foo && @@foo = bar
- def visit_class_variable_and_write_node(node)
- node.desugar
- end
-
- # @@foo ||= bar
- #
- # becomes
- #
- # defined?(@@foo) ? @@foo : @@foo = bar
- def visit_class_variable_or_write_node(node)
- node.desugar
- end
-
- # @@foo += bar
- #
- # becomes
- #
- # @@foo = @@foo + bar
- def visit_class_variable_operator_write_node(node)
- node.desugar
- end
-
- # Foo &&= bar
- #
- # becomes
- #
- # Foo && Foo = bar
- def visit_constant_and_write_node(node)
- node.desugar
- end
-
- # Foo ||= bar
- #
- # becomes
- #
- # defined?(Foo) ? Foo : Foo = bar
- def visit_constant_or_write_node(node)
- node.desugar
- end
-
- # Foo += bar
- #
- # becomes
- #
- # Foo = Foo + bar
- def visit_constant_operator_write_node(node)
- node.desugar
- end
-
- # $foo &&= bar
- #
- # becomes
- #
- # $foo && $foo = bar
- def visit_global_variable_and_write_node(node)
- node.desugar
- end
-
- # $foo ||= bar
- #
- # becomes
- #
- # defined?($foo) ? $foo : $foo = bar
- def visit_global_variable_or_write_node(node)
- node.desugar
- end
-
- # $foo += bar
- #
- # becomes
- #
- # $foo = $foo + bar
- def visit_global_variable_operator_write_node(node)
- node.desugar
- end
-
- # @foo &&= bar
- #
- # becomes
- #
- # @foo && @foo = bar
- def visit_instance_variable_and_write_node(node)
- node.desugar
- end
-
- # @foo ||= bar
- #
- # becomes
- #
- # @foo || @foo = bar
- def visit_instance_variable_or_write_node(node)
- node.desugar
- end
-
- # @foo += bar
- #
- # becomes
- #
- # @foo = @foo + bar
- def visit_instance_variable_operator_write_node(node)
- node.desugar
- end
-
- # foo &&= bar
- #
- # becomes
- #
- # foo && foo = bar
- def visit_local_variable_and_write_node(node)
- node.desugar
- end
-
- # foo ||= bar
- #
- # becomes
- #
- # foo || foo = bar
- def visit_local_variable_or_write_node(node)
- node.desugar
- end
-
- # foo += bar
- #
- # becomes
- #
- # foo = foo + bar
- def visit_local_variable_operator_write_node(node)
- node.desugar
- end
- end
-end
diff --git a/lib/prism/ffi.rb b/lib/prism/ffi.rb
deleted file mode 100644
index 0520f7cdd2..0000000000
--- a/lib/prism/ffi.rb
+++ /dev/null
@@ -1,495 +0,0 @@
-# frozen_string_literal: true
-# typed: ignore
-
-# This file is responsible for mirroring the API provided by the C extension by
-# using FFI to call into the shared library.
-
-require "rbconfig"
-require "ffi"
-
-module Prism
- module LibRubyParser # :nodoc:
- extend FFI::Library
-
- # Define the library that we will be pulling functions from. Note that this
- # must align with the build shared library from make/rake.
- ffi_lib File.expand_path("../../build/libprism.#{RbConfig::CONFIG["SOEXT"]}", __dir__)
-
- # Convert a native C type declaration into a symbol that FFI understands.
- # For example:
- #
- # const char * -> :pointer
- # bool -> :bool
- # size_t -> :size_t
- # void -> :void
- #
- def self.resolve_type(type, callbacks)
- type = type.strip
-
- if !type.end_with?("*")
- type.delete_prefix("const ").to_sym
- else
- type = type.delete_suffix("*").rstrip
- callbacks.include?(type.to_sym) ? type.to_sym : :pointer
- end
- end
-
- # Read through the given header file and find the declaration of each of the
- # given functions. For each one, define a function with the same name and
- # signature as the C function.
- def self.load_exported_functions_from(header, *functions, callbacks)
- File.foreach(File.expand_path("../../include/#{header}", __dir__)) do |line|
- # We only want to attempt to load exported functions.
- next unless line.start_with?("PRISM_EXPORTED_FUNCTION ")
-
- # We only want to load the functions that we are interested in.
- next unless functions.any? { |function| line.include?(function) }
-
- # Parse the function declaration.
- unless /^PRISM_EXPORTED_FUNCTION (?<return_type>.+) (?<name>\w+)\((?<arg_types>.+)\);$/ =~ line
- raise "Could not parse #{line}"
- end
-
- # Delete the function from the list of functions we are looking for to
- # mark it as having been found.
- functions.delete(name)
-
- # Split up the argument types into an array, ensure we handle the case
- # where there are no arguments (by explicit void).
- arg_types = arg_types.split(",").map(&:strip)
- arg_types = [] if arg_types == %w[void]
-
- # Resolve the type of the argument by dropping the name of the argument
- # first if it is present.
- arg_types.map! { |type| resolve_type(type.sub(/\w+$/, ""), callbacks) }
-
- # Attach the function using the FFI library.
- attach_function name, arg_types, resolve_type(return_type, [])
- end
-
- # If we didn't find all of the functions, raise an error.
- raise "Could not find functions #{functions.inspect}" unless functions.empty?
- end
-
- callback :pm_parse_stream_fgets_t, [:pointer, :int, :pointer], :pointer
- enum :pm_string_init_result_t, %i[PM_STRING_INIT_SUCCESS PM_STRING_INIT_ERROR_GENERIC PM_STRING_INIT_ERROR_DIRECTORY]
-
- load_exported_functions_from(
- "prism.h",
- "pm_version",
- "pm_serialize_parse",
- "pm_serialize_parse_stream",
- "pm_serialize_parse_comments",
- "pm_serialize_lex",
- "pm_serialize_parse_lex",
- "pm_parse_success_p",
- [:pm_parse_stream_fgets_t]
- )
-
- load_exported_functions_from(
- "prism/util/pm_buffer.h",
- "pm_buffer_sizeof",
- "pm_buffer_init",
- "pm_buffer_value",
- "pm_buffer_length",
- "pm_buffer_free",
- []
- )
-
- load_exported_functions_from(
- "prism/util/pm_string.h",
- "pm_string_mapped_init",
- "pm_string_free",
- "pm_string_source",
- "pm_string_length",
- "pm_string_sizeof",
- []
- )
-
- # This object represents a pm_buffer_t. We only use it as an opaque pointer,
- # so it doesn't need to know the fields of pm_buffer_t.
- class PrismBuffer # :nodoc:
- SIZEOF = LibRubyParser.pm_buffer_sizeof
-
- attr_reader :pointer
-
- def initialize(pointer)
- @pointer = pointer
- end
-
- def value
- LibRubyParser.pm_buffer_value(pointer)
- end
-
- def length
- LibRubyParser.pm_buffer_length(pointer)
- end
-
- def read
- value.read_string(length)
- end
-
- # Initialize a new buffer and yield it to the block. The buffer will be
- # automatically freed when the block returns.
- def self.with
- FFI::MemoryPointer.new(SIZEOF) do |pointer|
- raise unless LibRubyParser.pm_buffer_init(pointer)
- return yield new(pointer)
- ensure
- LibRubyParser.pm_buffer_free(pointer)
- end
- end
- end
-
- # This object represents a pm_string_t. We only use it as an opaque pointer,
- # so it doesn't have to be an FFI::Struct.
- class PrismString # :nodoc:
- SIZEOF = LibRubyParser.pm_string_sizeof
-
- attr_reader :pointer, :length
-
- def initialize(pointer, length, from_string)
- @pointer = pointer
- @length = length
- @from_string = from_string
- end
-
- def read
- raise "should use the original String instead" if @from_string
- @pointer.read_string(@length)
- end
-
- # Yields a pm_string_t pointer to the given block.
- def self.with_string(string)
- raise TypeError unless string.is_a?(String)
-
- length = string.bytesize
- # + 1 to never get an address of 0, which pm_parser_init() asserts
- FFI::MemoryPointer.new(:char, length + 1, false) do |pointer|
- pointer.write_string(string)
- # since we have the extra byte we might as well \0-terminate
- pointer.put_char(length, 0)
- return yield new(pointer, length, true)
- end
- end
-
- # Yields a pm_string_t pointer to the given block.
- def self.with_file(filepath)
- raise TypeError unless filepath.is_a?(String)
-
- # On Windows and Mac, it's expected that filepaths will be encoded in
- # UTF-8. If they are not, we need to convert them to UTF-8 before
- # passing them into pm_string_mapped_init.
- if RbConfig::CONFIG["host_os"].match?(/bccwin|cygwin|djgpp|mingw|mswin|wince|darwin/i) &&
- (encoding = filepath.encoding) != Encoding::ASCII_8BIT && encoding != Encoding::UTF_8
- filepath = filepath.encode(Encoding::UTF_8)
- end
-
- FFI::MemoryPointer.new(SIZEOF) do |pm_string|
- case (result = LibRubyParser.pm_string_mapped_init(pm_string, filepath))
- when :PM_STRING_INIT_SUCCESS
- pointer = LibRubyParser.pm_string_source(pm_string)
- length = LibRubyParser.pm_string_length(pm_string)
- return yield new(pointer, length, false)
- when :PM_STRING_INIT_ERROR_GENERIC
- raise SystemCallError.new(filepath, FFI.errno)
- when :PM_STRING_INIT_ERROR_DIRECTORY
- raise Errno::EISDIR.new(filepath)
- else
- raise "Unknown error initializing pm_string_t: #{result.inspect}"
- end
- ensure
- LibRubyParser.pm_string_free(pm_string)
- end
- end
- end
- end
-
- # Mark the LibRubyParser module as private as it should only be called through
- # the prism module.
- private_constant :LibRubyParser
-
- # The version constant is set by reading the result of calling pm_version.
- VERSION = LibRubyParser.pm_version.read_string
-
- class << self
- # Mirror the Prism.dump API by using the serialization API.
- def dump(source, **options)
- LibRubyParser::PrismString.with_string(source) { |string| dump_common(string, options) }
- end
-
- # Mirror the Prism.dump_file API by using the serialization API.
- def dump_file(filepath, **options)
- options[:filepath] = filepath
- LibRubyParser::PrismString.with_file(filepath) { |string| dump_common(string, options) }
- end
-
- # Mirror the Prism.lex API by using the serialization API.
- def lex(code, **options)
- LibRubyParser::PrismString.with_string(code) { |string| lex_common(string, code, options) }
- end
-
- # Mirror the Prism.lex_file API by using the serialization API.
- def lex_file(filepath, **options)
- options[:filepath] = filepath
- LibRubyParser::PrismString.with_file(filepath) { |string| lex_common(string, string.read, options) }
- end
-
- # Mirror the Prism.parse API by using the serialization API.
- def parse(code, **options)
- LibRubyParser::PrismString.with_string(code) { |string| parse_common(string, code, options) }
- end
-
- # Mirror the Prism.parse_file API by using the serialization API. This uses
- # native strings instead of Ruby strings because it allows us to use mmap
- # when it is available.
- def parse_file(filepath, **options)
- options[:filepath] = filepath
- LibRubyParser::PrismString.with_file(filepath) { |string| parse_common(string, string.read, options) }
- end
-
- # Mirror the Prism.parse_stream API by using the serialization API.
- def parse_stream(stream, **options)
- LibRubyParser::PrismBuffer.with do |buffer|
- source = +""
- callback = -> (string, size, _) {
- raise "Expected size to be >= 0, got: #{size}" if size <= 0
-
- if !(line = stream.gets(size - 1)).nil?
- source << line
- string.write_string("#{line}\x00", line.bytesize + 1)
- end
- }
-
- # In the pm_serialize_parse_stream function it accepts a pointer to the
- # IO object as a void* and then passes it through to the callback as the
- # third argument, but it never touches it itself. As such, since we have
- # access to the IO object already through the closure of the lambda, we
- # can pass a null pointer here and not worry.
- LibRubyParser.pm_serialize_parse_stream(buffer.pointer, nil, callback, dump_options(options))
- Prism.load(source, buffer.read)
- end
- end
-
- # Mirror the Prism.parse_comments API by using the serialization API.
- def parse_comments(code, **options)
- LibRubyParser::PrismString.with_string(code) { |string| parse_comments_common(string, code, options) }
- end
-
- # Mirror the Prism.parse_file_comments API by using the serialization
- # API. This uses native strings instead of Ruby strings because it allows us
- # to use mmap when it is available.
- def parse_file_comments(filepath, **options)
- options[:filepath] = filepath
- LibRubyParser::PrismString.with_file(filepath) { |string| parse_comments_common(string, string.read, options) }
- end
-
- # Mirror the Prism.parse_lex API by using the serialization API.
- def parse_lex(code, **options)
- LibRubyParser::PrismString.with_string(code) { |string| parse_lex_common(string, code, options) }
- end
-
- # Mirror the Prism.parse_lex_file API by using the serialization API.
- def parse_lex_file(filepath, **options)
- options[:filepath] = filepath
- LibRubyParser::PrismString.with_file(filepath) { |string| parse_lex_common(string, string.read, options) }
- end
-
- # Mirror the Prism.parse_success? API by using the serialization API.
- def parse_success?(code, **options)
- LibRubyParser::PrismString.with_string(code) { |string| parse_file_success_common(string, options) }
- end
-
- # Mirror the Prism.parse_failure? API by using the serialization API.
- def parse_failure?(code, **options)
- !parse_success?(code, **options)
- end
-
- # Mirror the Prism.parse_file_success? API by using the serialization API.
- def parse_file_success?(filepath, **options)
- options[:filepath] = filepath
- LibRubyParser::PrismString.with_file(filepath) { |string| parse_file_success_common(string, options) }
- end
-
- # Mirror the Prism.parse_file_failure? API by using the serialization API.
- def parse_file_failure?(filepath, **options)
- !parse_file_success?(filepath, **options)
- end
-
- # Mirror the Prism.profile API by using the serialization API.
- def profile(source, **options)
- LibRubyParser::PrismString.with_string(source) do |string|
- LibRubyParser::PrismBuffer.with do |buffer|
- LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
- nil
- end
- end
- end
-
- # Mirror the Prism.profile_file API by using the serialization API.
- def profile_file(filepath, **options)
- LibRubyParser::PrismString.with_file(filepath) do |string|
- LibRubyParser::PrismBuffer.with do |buffer|
- options[:filepath] = filepath
- LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
- nil
- end
- end
- end
-
- private
-
- def dump_common(string, options) # :nodoc:
- LibRubyParser::PrismBuffer.with do |buffer|
- LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
- buffer.read
- end
- end
-
- def lex_common(string, code, options) # :nodoc:
- serialized = LibRubyParser::PrismBuffer.with do |buffer|
- LibRubyParser.pm_serialize_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
- buffer.read
- end
-
- Serialize.load_tokens(Source.for(code), serialized)
- end
-
- def parse_common(string, code, options) # :nodoc:
- serialized = dump_common(string, options)
- Prism.load(code, serialized)
- end
-
- def parse_comments_common(string, code, options) # :nodoc:
- LibRubyParser::PrismBuffer.with do |buffer|
- LibRubyParser.pm_serialize_parse_comments(buffer.pointer, string.pointer, string.length, dump_options(options))
-
- source = Source.for(code)
- loader = Serialize::Loader.new(source, buffer.read)
-
- loader.load_header
- loader.load_encoding
- loader.load_start_line
- loader.load_comments
- end
- end
-
- def parse_lex_common(string, code, options) # :nodoc:
- LibRubyParser::PrismBuffer.with do |buffer|
- LibRubyParser.pm_serialize_parse_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
-
- source = Source.for(code)
- loader = Serialize::Loader.new(source, buffer.read)
-
- tokens = loader.load_tokens
- node, comments, magic_comments, data_loc, errors, warnings = loader.load_nodes
- tokens.each { |token,| token.value.force_encoding(loader.encoding) }
-
- ParseLexResult.new([node, tokens], comments, magic_comments, data_loc, errors, warnings, source)
- end
- end
-
- def parse_file_success_common(string, options) # :nodoc:
- LibRubyParser.pm_parse_success_p(string.pointer, string.length, dump_options(options))
- end
-
- # Return the value that should be dumped for the command_line option.
- def dump_options_command_line(options)
- command_line = options.fetch(:command_line, "")
- raise ArgumentError, "command_line must be a string" unless command_line.is_a?(String)
-
- command_line.each_char.inject(0) do |value, char|
- case char
- when "a" then value | 0b000001
- when "e" then value | 0b000010
- when "l" then value | 0b000100
- when "n" then value | 0b001000
- when "p" then value | 0b010000
- when "x" then value | 0b100000
- else raise ArgumentError, "invalid command_line option: #{char}"
- end
- end
- end
-
- # Return the value that should be dumped for the version option.
- def dump_options_version(version)
- case version
- when nil, "latest"
- 0
- when /\A3\.3(\.\d+)?\z/
- 1
- when /\A3\.4(\.\d+)?\z/
- 0
- else
- raise ArgumentError, "invalid version: #{version}"
- end
- end
-
- # Convert the given options into a serialized options string.
- def dump_options(options)
- template = +""
- values = []
-
- template << "L"
- if (filepath = options[:filepath])
- values.push(filepath.bytesize, filepath.b)
- template << "A*"
- else
- values << 0
- end
-
- template << "l"
- values << options.fetch(:line, 1)
-
- template << "L"
- if (encoding = options[:encoding])
- name = encoding.is_a?(Encoding) ? encoding.name : encoding
- values.push(name.bytesize, name.b)
- template << "A*"
- else
- values << 0
- end
-
- template << "C"
- values << (options.fetch(:frozen_string_literal, false) ? 1 : 0)
-
- template << "C"
- values << dump_options_command_line(options)
-
- template << "C"
- values << dump_options_version(options[:version])
-
- template << "C"
- values << (options[:encoding] == false ? 1 : 0)
-
- template << "C"
- values << (options.fetch(:main_script, false) ? 1 : 0)
-
- template << "C"
- values << (options.fetch(:partial_script, false) ? 1 : 0)
-
- template << "L"
- if (scopes = options[:scopes])
- values << scopes.length
-
- scopes.each do |scope|
- template << "L"
- values << scope.length
-
- scope.each do |local|
- name = local.name
- template << "L"
- values << name.bytesize
-
- template << "A*"
- values << name.b
- end
- end
- else
- values << 0
- end
-
- values.pack(template)
- end
- end
-end
diff --git a/lib/prism/lex_compat.rb b/lib/prism/lex_compat.rb
deleted file mode 100644
index a83c24cb41..0000000000
--- a/lib/prism/lex_compat.rb
+++ /dev/null
@@ -1,927 +0,0 @@
-# frozen_string_literal: true
-
-require "delegate"
-require "ripper"
-
-module Prism
- # This class is responsible for lexing the source using prism and then
- # converting those tokens to be compatible with Ripper. In the vast majority
- # of cases, this is a one-to-one mapping of the token type. Everything else
- # generally lines up. However, there are a few cases that require special
- # handling.
- class LexCompat # :nodoc:
- # A result class specialized for holding tokens produced by the lexer.
- class Result < Prism::Result
- # The list of tokens that were produced by the lexer.
- attr_reader :value
-
- # Create a new lex compat result object with the given values.
- def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
- @value = value
- super(comments, magic_comments, data_loc, errors, warnings, source)
- end
-
- # Implement the hash pattern matching interface for Result.
- def deconstruct_keys(keys)
- super.merge!(value: value)
- end
- end
-
- # This is a mapping of prism token types to Ripper token types. This is a
- # many-to-one mapping because we split up our token types, whereas Ripper
- # tends to group them.
- RIPPER = {
- AMPERSAND: :on_op,
- AMPERSAND_AMPERSAND: :on_op,
- AMPERSAND_AMPERSAND_EQUAL: :on_op,
- AMPERSAND_DOT: :on_op,
- AMPERSAND_EQUAL: :on_op,
- BACK_REFERENCE: :on_backref,
- BACKTICK: :on_backtick,
- BANG: :on_op,
- BANG_EQUAL: :on_op,
- BANG_TILDE: :on_op,
- BRACE_LEFT: :on_lbrace,
- BRACE_RIGHT: :on_rbrace,
- BRACKET_LEFT: :on_lbracket,
- BRACKET_LEFT_ARRAY: :on_lbracket,
- BRACKET_LEFT_RIGHT: :on_op,
- BRACKET_LEFT_RIGHT_EQUAL: :on_op,
- BRACKET_RIGHT: :on_rbracket,
- CARET: :on_op,
- CARET_EQUAL: :on_op,
- CHARACTER_LITERAL: :on_CHAR,
- CLASS_VARIABLE: :on_cvar,
- COLON: :on_op,
- COLON_COLON: :on_op,
- COMMA: :on_comma,
- COMMENT: :on_comment,
- CONSTANT: :on_const,
- DOT: :on_period,
- DOT_DOT: :on_op,
- DOT_DOT_DOT: :on_op,
- EMBDOC_BEGIN: :on_embdoc_beg,
- EMBDOC_END: :on_embdoc_end,
- EMBDOC_LINE: :on_embdoc,
- EMBEXPR_BEGIN: :on_embexpr_beg,
- EMBEXPR_END: :on_embexpr_end,
- EMBVAR: :on_embvar,
- EOF: :on_eof,
- EQUAL: :on_op,
- EQUAL_EQUAL: :on_op,
- EQUAL_EQUAL_EQUAL: :on_op,
- EQUAL_GREATER: :on_op,
- EQUAL_TILDE: :on_op,
- FLOAT: :on_float,
- FLOAT_IMAGINARY: :on_imaginary,
- FLOAT_RATIONAL: :on_rational,
- FLOAT_RATIONAL_IMAGINARY: :on_imaginary,
- GREATER: :on_op,
- GREATER_EQUAL: :on_op,
- GREATER_GREATER: :on_op,
- GREATER_GREATER_EQUAL: :on_op,
- GLOBAL_VARIABLE: :on_gvar,
- HEREDOC_END: :on_heredoc_end,
- HEREDOC_START: :on_heredoc_beg,
- IDENTIFIER: :on_ident,
- IGNORED_NEWLINE: :on_ignored_nl,
- INTEGER: :on_int,
- INTEGER_IMAGINARY: :on_imaginary,
- INTEGER_RATIONAL: :on_rational,
- INTEGER_RATIONAL_IMAGINARY: :on_imaginary,
- INSTANCE_VARIABLE: :on_ivar,
- INVALID: :INVALID,
- KEYWORD___ENCODING__: :on_kw,
- KEYWORD___LINE__: :on_kw,
- KEYWORD___FILE__: :on_kw,
- KEYWORD_ALIAS: :on_kw,
- KEYWORD_AND: :on_kw,
- KEYWORD_BEGIN: :on_kw,
- KEYWORD_BEGIN_UPCASE: :on_kw,
- KEYWORD_BREAK: :on_kw,
- KEYWORD_CASE: :on_kw,
- KEYWORD_CLASS: :on_kw,
- KEYWORD_DEF: :on_kw,
- KEYWORD_DEFINED: :on_kw,
- KEYWORD_DO: :on_kw,
- KEYWORD_DO_LOOP: :on_kw,
- KEYWORD_ELSE: :on_kw,
- KEYWORD_ELSIF: :on_kw,
- KEYWORD_END: :on_kw,
- KEYWORD_END_UPCASE: :on_kw,
- KEYWORD_ENSURE: :on_kw,
- KEYWORD_FALSE: :on_kw,
- KEYWORD_FOR: :on_kw,
- KEYWORD_IF: :on_kw,
- KEYWORD_IF_MODIFIER: :on_kw,
- KEYWORD_IN: :on_kw,
- KEYWORD_MODULE: :on_kw,
- KEYWORD_NEXT: :on_kw,
- KEYWORD_NIL: :on_kw,
- KEYWORD_NOT: :on_kw,
- KEYWORD_OR: :on_kw,
- KEYWORD_REDO: :on_kw,
- KEYWORD_RESCUE: :on_kw,
- KEYWORD_RESCUE_MODIFIER: :on_kw,
- KEYWORD_RETRY: :on_kw,
- KEYWORD_RETURN: :on_kw,
- KEYWORD_SELF: :on_kw,
- KEYWORD_SUPER: :on_kw,
- KEYWORD_THEN: :on_kw,
- KEYWORD_TRUE: :on_kw,
- KEYWORD_UNDEF: :on_kw,
- KEYWORD_UNLESS: :on_kw,
- KEYWORD_UNLESS_MODIFIER: :on_kw,
- KEYWORD_UNTIL: :on_kw,
- KEYWORD_UNTIL_MODIFIER: :on_kw,
- KEYWORD_WHEN: :on_kw,
- KEYWORD_WHILE: :on_kw,
- KEYWORD_WHILE_MODIFIER: :on_kw,
- KEYWORD_YIELD: :on_kw,
- LABEL: :on_label,
- LABEL_END: :on_label_end,
- LAMBDA_BEGIN: :on_tlambeg,
- LESS: :on_op,
- LESS_EQUAL: :on_op,
- LESS_EQUAL_GREATER: :on_op,
- LESS_LESS: :on_op,
- LESS_LESS_EQUAL: :on_op,
- METHOD_NAME: :on_ident,
- MINUS: :on_op,
- MINUS_EQUAL: :on_op,
- MINUS_GREATER: :on_tlambda,
- NEWLINE: :on_nl,
- NUMBERED_REFERENCE: :on_backref,
- PARENTHESIS_LEFT: :on_lparen,
- PARENTHESIS_LEFT_PARENTHESES: :on_lparen,
- PARENTHESIS_RIGHT: :on_rparen,
- PERCENT: :on_op,
- PERCENT_EQUAL: :on_op,
- PERCENT_LOWER_I: :on_qsymbols_beg,
- PERCENT_LOWER_W: :on_qwords_beg,
- PERCENT_LOWER_X: :on_backtick,
- PERCENT_UPPER_I: :on_symbols_beg,
- PERCENT_UPPER_W: :on_words_beg,
- PIPE: :on_op,
- PIPE_EQUAL: :on_op,
- PIPE_PIPE: :on_op,
- PIPE_PIPE_EQUAL: :on_op,
- PLUS: :on_op,
- PLUS_EQUAL: :on_op,
- QUESTION_MARK: :on_op,
- RATIONAL_FLOAT: :on_rational,
- RATIONAL_INTEGER: :on_rational,
- REGEXP_BEGIN: :on_regexp_beg,
- REGEXP_END: :on_regexp_end,
- SEMICOLON: :on_semicolon,
- SLASH: :on_op,
- SLASH_EQUAL: :on_op,
- STAR: :on_op,
- STAR_EQUAL: :on_op,
- STAR_STAR: :on_op,
- STAR_STAR_EQUAL: :on_op,
- STRING_BEGIN: :on_tstring_beg,
- STRING_CONTENT: :on_tstring_content,
- STRING_END: :on_tstring_end,
- SYMBOL_BEGIN: :on_symbeg,
- TILDE: :on_op,
- UAMPERSAND: :on_op,
- UCOLON_COLON: :on_op,
- UDOT_DOT: :on_op,
- UDOT_DOT_DOT: :on_op,
- UMINUS: :on_op,
- UMINUS_NUM: :on_op,
- UPLUS: :on_op,
- USTAR: :on_op,
- USTAR_STAR: :on_op,
- WORDS_SEP: :on_words_sep,
- "__END__": :on___end__
- }.freeze
-
- # When we produce tokens, we produce the same arrays that Ripper does.
- # However, we add a couple of convenience methods onto them to make them a
- # little easier to work with. We delegate all other methods to the array.
- class Token < SimpleDelegator
- # @dynamic initialize, each, []
-
- # The location of the token in the source.
- def location
- self[0]
- end
-
- # The type of the token.
- def event
- self[1]
- end
-
- # The slice of the source that this token represents.
- def value
- self[2]
- end
-
- # The state of the lexer when this token was produced.
- def state
- self[3]
- end
- end
-
- # Ripper doesn't include the rest of the token in the event, so we need to
- # trim it down to just the content on the first line when comparing.
- class EndContentToken < Token
- def ==(other) # :nodoc:
- [self[0], self[1], self[2][0..self[2].index("\n")], self[3]] == other
- end
- end
-
- # Tokens where state should be ignored
- # used for :on_comment, :on_heredoc_end, :on_embexpr_end
- class IgnoreStateToken < Token
- def ==(other) # :nodoc:
- self[0...-1] == other[0...-1]
- end
- end
-
- # Ident tokens for the most part are exactly the same, except sometimes we
- # know an ident is a local when ripper doesn't (when they are introduced
- # through named captures in regular expressions). In that case we don't
- # compare the state.
- class IdentToken < Token
- def ==(other) # :nodoc:
- (self[0...-1] == other[0...-1]) && (
- (other[3] == Ripper::EXPR_LABEL | Ripper::EXPR_END) ||
- (other[3] & Ripper::EXPR_ARG_ANY != 0)
- )
- end
- end
-
- # Ignored newlines can occasionally have a LABEL state attached to them, so
- # we compare the state differently here.
- class IgnoredNewlineToken < Token
- def ==(other) # :nodoc:
- return false unless self[0...-1] == other[0...-1]
-
- if self[3] == Ripper::EXPR_ARG | Ripper::EXPR_LABELED
- other[3] & Ripper::EXPR_ARG | Ripper::EXPR_LABELED != 0
- else
- self[3] == other[3]
- end
- end
- end
-
- # If we have an identifier that follows a method name like:
- #
- # def foo bar
- #
- # then Ripper will mark bar as END|LABEL if there is a local in a parent
- # scope named bar because it hasn't pushed the local table yet. We do this
- # more accurately, so we need to allow comparing against both END and
- # END|LABEL.
- class ParamToken < Token
- def ==(other) # :nodoc:
- (self[0...-1] == other[0...-1]) && (
- (other[3] == Ripper::EXPR_END) ||
- (other[3] == Ripper::EXPR_END | Ripper::EXPR_LABEL)
- )
- end
- end
-
- # A heredoc in this case is a list of tokens that belong to the body of the
- # heredoc that should be appended onto the list of tokens when the heredoc
- # closes.
- module Heredoc # :nodoc:
- # Heredocs that are no dash or tilde heredocs are just a list of tokens.
- # We need to keep them around so that we can insert them in the correct
- # order back into the token stream and set the state of the last token to
- # the state that the heredoc was opened in.
- class PlainHeredoc # :nodoc:
- attr_reader :tokens
-
- def initialize
- @tokens = []
- end
-
- def <<(token)
- tokens << token
- end
-
- def to_a
- tokens
- end
- end
-
- # Dash heredocs are a little more complicated. They are a list of tokens
- # that need to be split on "\\\n" to mimic Ripper's behavior. We also need
- # to keep track of the state that the heredoc was opened in.
- class DashHeredoc # :nodoc:
- attr_reader :split, :tokens
-
- def initialize(split)
- @split = split
- @tokens = []
- end
-
- def <<(token)
- tokens << token
- end
-
- def to_a
- embexpr_balance = 0
-
- tokens.each_with_object([]) do |token, results| #$ Array[Token]
- case token.event
- when :on_embexpr_beg
- embexpr_balance += 1
- results << token
- when :on_embexpr_end
- embexpr_balance -= 1
- results << token
- when :on_tstring_content
- if embexpr_balance == 0
- lineno = token[0][0]
- column = token[0][1]
-
- if split
- # Split on "\\\n" to mimic Ripper's behavior. Use a lookbehind
- # to keep the delimiter in the result.
- token.value.split(/(?<=[^\\]\\\n)|(?<=[^\\]\\\r\n)/).each_with_index do |value, index|
- column = 0 if index > 0
- results << Token.new([[lineno, column], :on_tstring_content, value, token.state])
- lineno += value.count("\n")
- end
- else
- results << token
- end
- else
- results << token
- end
- else
- results << token
- end
- end
- end
- end
-
- # Heredocs that are dedenting heredocs are a little more complicated.
- # Ripper outputs on_ignored_sp tokens for the whitespace that is being
- # removed from the output. prism only modifies the node itself and keeps
- # the token the same. This simplifies prism, but makes comparing against
- # Ripper much harder because there is a length mismatch.
- #
- # Fortunately, we already have to pull out the heredoc tokens in order to
- # insert them into the stream in the correct order. As such, we can do
- # some extra manipulation on the tokens to make them match Ripper's
- # output by mirroring the dedent logic that Ripper uses.
- class DedentingHeredoc # :nodoc:
- TAB_WIDTH = 8
-
- attr_reader :tokens, :dedent_next, :dedent, :embexpr_balance
-
- def initialize
- @tokens = []
- @dedent_next = true
- @dedent = nil
- @embexpr_balance = 0
- @ended_on_newline = false
- end
-
- # As tokens are coming in, we track the minimum amount of common leading
- # whitespace on plain string content tokens. This allows us to later
- # remove that amount of whitespace from the beginning of each line.
- def <<(token)
- case token.event
- when :on_embexpr_beg, :on_heredoc_beg
- @embexpr_balance += 1
- @dedent = 0 if @dedent_next && @ended_on_newline
- when :on_embexpr_end, :on_heredoc_end
- @embexpr_balance -= 1
- when :on_tstring_content
- if embexpr_balance == 0
- line = token.value
-
- if dedent_next && !(line.strip.empty? && line.end_with?("\n"))
- leading = line[/\A(\s*)\n?/, 1]
- next_dedent = 0
-
- leading.each_char do |char|
- if char == "\t"
- next_dedent = next_dedent - (next_dedent % TAB_WIDTH) + TAB_WIDTH
- else
- next_dedent += 1
- end
- end
-
- @dedent = [dedent, next_dedent].compact.min
- @dedent_next = true
- @ended_on_newline = line.end_with?("\n")
- tokens << token
- return
- end
- end
- end
-
- @dedent_next = token.event == :on_tstring_content && embexpr_balance == 0
- @ended_on_newline = false
- tokens << token
- end
-
- def to_a
- # If every line in the heredoc is blank, we still need to split up the
- # string content token into multiple tokens.
- if dedent.nil?
- results = [] #: Array[Token]
- embexpr_balance = 0
-
- tokens.each do |token|
- case token.event
- when :on_embexpr_beg, :on_heredoc_beg
- embexpr_balance += 1
- results << token
- when :on_embexpr_end, :on_heredoc_end
- embexpr_balance -= 1
- results << token
- when :on_tstring_content
- if embexpr_balance == 0
- lineno = token[0][0]
- column = token[0][1]
-
- token.value.split(/(?<=\n)/).each_with_index do |value, index|
- column = 0 if index > 0
- results << Token.new([[lineno, column], :on_tstring_content, value, token.state])
- lineno += 1
- end
- else
- results << token
- end
- else
- results << token
- end
- end
-
- return results
- end
-
- # If the minimum common whitespace is 0, then we need to concatenate
- # string nodes together that are immediately adjacent.
- if dedent == 0
- results = [] #: Array[Token]
- embexpr_balance = 0
-
- index = 0
- max_index = tokens.length
-
- while index < max_index
- token = tokens[index]
- results << token
- index += 1
-
- case token.event
- when :on_embexpr_beg, :on_heredoc_beg
- embexpr_balance += 1
- when :on_embexpr_end, :on_heredoc_end
- embexpr_balance -= 1
- when :on_tstring_content
- if embexpr_balance == 0
- while index < max_index && tokens[index].event == :on_tstring_content && !token.value.match?(/\\\r?\n\z/)
- token.value << tokens[index].value
- index += 1
- end
- end
- end
- end
-
- return results
- end
-
- # Otherwise, we're going to run through each token in the list and
- # insert on_ignored_sp tokens for the amount of dedent that we need to
- # perform. We also need to remove the dedent from the beginning of
- # each line of plain string content tokens.
- results = [] #: Array[Token]
- dedent_next = true
- embexpr_balance = 0
-
- tokens.each do |token|
- # Notice that the structure of this conditional largely matches the
- # whitespace calculation we performed above. This is because
- # checking if the subsequent token needs to be dedented is common to
- # both the dedent calculation and the ignored_sp insertion.
- case token.event
- when :on_embexpr_beg
- embexpr_balance += 1
- results << token
- when :on_embexpr_end
- embexpr_balance -= 1
- results << token
- when :on_tstring_content
- if embexpr_balance == 0
- # Here we're going to split the string on newlines, but maintain
- # the newlines in the resulting array. We'll do that with a look
- # behind assertion.
- splits = token.value.split(/(?<=\n)/)
- index = 0
-
- while index < splits.length
- line = splits[index]
- lineno = token[0][0] + index
- column = token[0][1]
-
- # Blank lines do not count toward common leading whitespace
- # calculation and do not need to be dedented.
- if dedent_next || index > 0
- column = 0
- end
-
- # If the dedent is 0 and we're not supposed to dedent the next
- # line or this line doesn't start with whitespace, then we
- # should concatenate the rest of the string to match ripper.
- if dedent == 0 && (!dedent_next || !line.start_with?(/\s/))
- line = splits[index..].join
- index = splits.length
- end
-
- # If we are supposed to dedent this line or if this is not the
- # first line of the string and this line isn't entirely blank,
- # then we need to insert an on_ignored_sp token and remove the
- # dedent from the beginning of the line.
- if (dedent > 0) && (dedent_next || index > 0)
- deleting = 0
- deleted_chars = [] #: Array[String]
-
- # Gather up all of the characters that we're going to
- # delete, stopping when you hit a character that would put
- # you over the dedent amount.
- line.each_char.with_index do |char, i|
- case char
- when "\r"
- if line[i + 1] == "\n"
- break
- end
- when "\n"
- break
- when "\t"
- deleting = deleting - (deleting % TAB_WIDTH) + TAB_WIDTH
- else
- deleting += 1
- end
-
- break if deleting > dedent
- deleted_chars << char
- end
-
- # If we have something to delete, then delete it from the
- # string and insert an on_ignored_sp token.
- if deleted_chars.any?
- ignored = deleted_chars.join
- line.delete_prefix!(ignored)
-
- results << Token.new([[lineno, 0], :on_ignored_sp, ignored, token[3]])
- column = ignored.length
- end
- end
-
- results << Token.new([[lineno, column], token[1], line, token[3]]) unless line.empty?
- index += 1
- end
- else
- results << token
- end
- else
- results << token
- end
-
- dedent_next =
- ((token.event == :on_tstring_content) || (token.event == :on_heredoc_end)) &&
- embexpr_balance == 0
- end
-
- results
- end
- end
-
- # Here we will split between the two types of heredocs and return the
- # object that will store their tokens.
- def self.build(opening)
- case opening.value[2]
- when "~"
- DedentingHeredoc.new
- when "-"
- DashHeredoc.new(opening.value[3] != "'")
- else
- PlainHeredoc.new
- end
- end
- end
-
- private_constant :Heredoc
-
- attr_reader :source, :options
-
- def initialize(source, **options)
- @source = source
- @options = options
- end
-
- def result
- tokens = [] #: Array[LexCompat::Token]
-
- state = :default
- heredoc_stack = [[]] #: Array[Array[Heredoc::PlainHeredoc | Heredoc::DashHeredoc | Heredoc::DedentingHeredoc]]
-
- result = Prism.lex(source, **options)
- result_value = result.value
- previous_state = nil #: Ripper::Lexer::State?
- last_heredoc_end = nil #: Integer?
-
- # In previous versions of Ruby, Ripper wouldn't flush the bom before the
- # first token, so we had to have a hack in place to account for that. This
- # checks for that behavior.
- bom_flushed = Ripper.lex("\xEF\xBB\xBF# test")[0][0][1] == 0
- bom = source.byteslice(0..2) == "\xEF\xBB\xBF"
-
- result_value.each_with_index do |(token, lex_state), index|
- lineno = token.location.start_line
- column = token.location.start_column
-
- # If there's a UTF-8 byte-order mark as the start of the file, then for
- # certain tokens ripper sets the first token back by 3 bytes. It also
- # keeps the byte order mark in the first token's value. This is weird,
- # and I don't want to mirror that in our parser. So instead, we'll match
- # up the columns and values here.
- if bom && lineno == 1
- column -= 3
-
- if index == 0 && column == 0 && !bom_flushed
- flushed =
- case token.type
- when :BACK_REFERENCE, :INSTANCE_VARIABLE, :CLASS_VARIABLE,
- :GLOBAL_VARIABLE, :NUMBERED_REFERENCE, :PERCENT_LOWER_I,
- :PERCENT_LOWER_X, :PERCENT_LOWER_W, :PERCENT_UPPER_I,
- :PERCENT_UPPER_W, :STRING_BEGIN
- true
- when :REGEXP_BEGIN, :SYMBOL_BEGIN
- token.value.start_with?("%")
- else
- false
- end
-
- unless flushed
- column -= 3
- value = token.value
- value.prepend(String.new("\xEF\xBB\xBF", encoding: value.encoding))
- end
- end
- end
-
- event = RIPPER.fetch(token.type)
- value = token.value
- lex_state = Ripper::Lexer::State.new(lex_state)
-
- token =
- case event
- when :on___end__
- EndContentToken.new([[lineno, column], event, value, lex_state])
- when :on_comment
- IgnoreStateToken.new([[lineno, column], event, value, lex_state])
- when :on_heredoc_end
- # Heredoc end tokens can be emitted in an odd order, so we don't
- # want to bother comparing the state on them.
- last_heredoc_end = token.location.end_offset
- IgnoreStateToken.new([[lineno, column], event, value, lex_state])
- when :on_ident
- if lex_state == Ripper::EXPR_END
- # If we have an identifier that follows a method name like:
- #
- # def foo bar
- #
- # then Ripper will mark bar as END|LABEL if there is a local in a
- # parent scope named bar because it hasn't pushed the local table
- # yet. We do this more accurately, so we need to allow comparing
- # against both END and END|LABEL.
- ParamToken.new([[lineno, column], event, value, lex_state])
- elsif lex_state == Ripper::EXPR_END | Ripper::EXPR_LABEL
- # In the event that we're comparing identifiers, we're going to
- # allow a little divergence. Ripper doesn't account for local
- # variables introduced through named captures in regexes, and we
- # do, which accounts for this difference.
- IdentToken.new([[lineno, column], event, value, lex_state])
- else
- Token.new([[lineno, column], event, value, lex_state])
- end
- when :on_embexpr_end
- IgnoreStateToken.new([[lineno, column], event, value, lex_state])
- when :on_ignored_nl
- # Ignored newlines can occasionally have a LABEL state attached to
- # them which doesn't actually impact anything. We don't mirror that
- # state so we ignored it.
- IgnoredNewlineToken.new([[lineno, column], event, value, lex_state])
- when :on_regexp_end
- # On regex end, Ripper scans and then sets end state, so the ripper
- # lexed output is begin, when it should be end. prism sets lex state
- # correctly to end state, but we want to be able to compare against
- # Ripper's lexed state. So here, if it's a regexp end token, we
- # output the state as the previous state, solely for the sake of
- # comparison.
- previous_token = result_value[index - 1][0]
- lex_state =
- if RIPPER.fetch(previous_token.type) == :on_embexpr_end
- # If the previous token is embexpr_end, then we have to do even
- # more processing. The end of an embedded expression sets the
- # state to the state that it had at the beginning of the
- # embedded expression. So we have to go and find that state and
- # set it here.
- counter = 1
- current_index = index - 1
-
- until counter == 0
- current_index -= 1
- current_event = RIPPER.fetch(result_value[current_index][0].type)
- counter += { on_embexpr_beg: -1, on_embexpr_end: 1 }[current_event] || 0
- end
-
- Ripper::Lexer::State.new(result_value[current_index][1])
- else
- previous_state
- end
-
- Token.new([[lineno, column], event, value, lex_state])
- when :on_eof
- previous_token = result_value[index - 1][0]
-
- # If we're at the end of the file and the previous token was a
- # comment and there is still whitespace after the comment, then
- # Ripper will append a on_nl token (even though there isn't
- # necessarily a newline). We mirror that here.
- if previous_token.type == :COMMENT
- # If the comment is at the start of a heredoc: <<HEREDOC # comment
- # then the comment's end_offset is up near the heredoc_beg.
- # This is not the correct offset to use for figuring out if
- # there is trailing whitespace after the last token.
- # Use the greater offset of the two to determine the start of
- # the trailing whitespace.
- start_offset = [previous_token.location.end_offset, last_heredoc_end].compact.max
- end_offset = token.location.start_offset
-
- if start_offset < end_offset
- if bom
- start_offset += 3
- end_offset += 3
- end
-
- tokens << Token.new([[lineno, 0], :on_nl, source.byteslice(start_offset...end_offset), lex_state])
- end
- end
-
- Token.new([[lineno, column], event, value, lex_state])
- else
- Token.new([[lineno, column], event, value, lex_state])
- end
-
- previous_state = lex_state
-
- # The order in which tokens appear in our lexer is different from the
- # order that they appear in Ripper. When we hit the declaration of a
- # heredoc in prism, we skip forward and lex the rest of the content of
- # the heredoc before going back and lexing at the end of the heredoc
- # identifier.
- #
- # To match up to ripper, we keep a small state variable around here to
- # track whether we're in the middle of a heredoc or not. In this way we
- # can shuffle around the token to match Ripper's output.
- case state
- when :default
- # The default state is when there are no heredocs at all. In this
- # state we can append the token to the list of tokens and move on.
- tokens << token
-
- # If we get the declaration of a heredoc, then we open a new heredoc
- # and move into the heredoc_opened state.
- if event == :on_heredoc_beg
- state = :heredoc_opened
- heredoc_stack.last << Heredoc.build(token)
- end
- when :heredoc_opened
- # The heredoc_opened state is when we've seen the declaration of a
- # heredoc and are now lexing the body of the heredoc. In this state we
- # push tokens onto the most recently created heredoc.
- heredoc_stack.last.last << token
-
- case event
- when :on_heredoc_beg
- # If we receive a heredoc declaration while lexing the body of a
- # heredoc, this means we have nested heredocs. In this case we'll
- # push a new heredoc onto the stack and stay in the heredoc_opened
- # state since we're now lexing the body of the new heredoc.
- heredoc_stack << [Heredoc.build(token)]
- when :on_heredoc_end
- # If we receive the end of a heredoc, then we're done lexing the
- # body of the heredoc. In this case we now have a completed heredoc
- # but need to wait for the next newline to push it into the token
- # stream.
- state = :heredoc_closed
- end
- when :heredoc_closed
- if %i[on_nl on_ignored_nl on_comment].include?(event) || (event == :on_tstring_content && value.end_with?("\n"))
- if heredoc_stack.size > 1
- flushing = heredoc_stack.pop
- heredoc_stack.last.last << token
-
- flushing.each do |heredoc|
- heredoc.to_a.each do |flushed_token|
- heredoc_stack.last.last << flushed_token
- end
- end
-
- state = :heredoc_opened
- next
- end
- elsif event == :on_heredoc_beg
- tokens << token
- state = :heredoc_opened
- heredoc_stack.last << Heredoc.build(token)
- next
- elsif heredoc_stack.size > 1
- heredoc_stack[-2].last << token
- next
- end
-
- heredoc_stack.last.each do |heredoc|
- tokens.concat(heredoc.to_a)
- end
-
- heredoc_stack.last.clear
- state = :default
-
- tokens << token
- end
- end
-
- # Drop the EOF token from the list
- tokens = tokens[0...-1]
-
- # We sort by location to compare against Ripper's output
- tokens.sort_by!(&:location)
-
- Result.new(tokens, result.comments, result.magic_comments, result.data_loc, result.errors, result.warnings, Source.for(source))
- end
- end
-
- private_constant :LexCompat
-
- # This is a class that wraps the Ripper lexer to produce almost exactly the
- # same tokens.
- class LexRipper # :nodoc:
- attr_reader :source
-
- def initialize(source)
- @source = source
- end
-
- def result
- previous = [] #: [[Integer, Integer], Symbol, String, untyped] | []
- results = [] #: Array[[[Integer, Integer], Symbol, String, untyped]]
-
- lex(source).each do |token|
- case token[1]
- when :on_sp
- # skip
- when :on_tstring_content
- if previous[1] == :on_tstring_content && (token[2].start_with?("\#$") || token[2].start_with?("\#@"))
- previous[2] << token[2]
- else
- results << token
- previous = token
- end
- when :on_words_sep
- if previous[1] == :on_words_sep
- previous[2] << token[2]
- else
- results << token
- previous = token
- end
- else
- results << token
- previous = token
- end
- end
-
- results
- end
-
- private
-
- if Ripper.method(:lex).parameters.assoc(:keyrest)
- def lex(source)
- Ripper.lex(source, raise_errors: true)
- end
- else
- def lex(source)
- ripper = Ripper::Lexer.new(source)
- ripper.lex.tap do |result|
- raise SyntaxError, ripper.errors.map(&:message).join(' ;') if ripper.errors.any?
- end
- end
- end
- end
-
- private_constant :LexRipper
-end
diff --git a/lib/prism/node_ext.rb b/lib/prism/node_ext.rb
deleted file mode 100644
index 4dfcebd638..0000000000
--- a/lib/prism/node_ext.rb
+++ /dev/null
@@ -1,508 +0,0 @@
-# frozen_string_literal: true
-
-# Here we are reopening the prism module to provide methods on nodes that aren't
-# templated and are meant as convenience methods.
-module Prism
- class Node
- def deprecated(*replacements) # :nodoc:
- location = caller_locations(1, 1)
- location = location[0].label if location
- suggest = replacements.map { |replacement| "#{self.class}##{replacement}" }
-
- warn(<<~MSG, category: :deprecated)
- [deprecation]: #{self.class}##{location} is deprecated and will be \
- removed in the next major version. Use #{suggest.join("/")} instead.
- #{(caller(1, 3) || []).join("\n")}
- MSG
- end
- end
-
- module RegularExpressionOptions # :nodoc:
- # Returns a numeric value that represents the flags that were used to create
- # the regular expression.
- def options
- o = 0
- o |= Regexp::IGNORECASE if flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
- o |= Regexp::EXTENDED if flags.anybits?(RegularExpressionFlags::EXTENDED)
- o |= Regexp::MULTILINE if flags.anybits?(RegularExpressionFlags::MULTI_LINE)
- o |= Regexp::FIXEDENCODING if flags.anybits?(RegularExpressionFlags::EUC_JP | RegularExpressionFlags::WINDOWS_31J | RegularExpressionFlags::UTF_8)
- o |= Regexp::NOENCODING if flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
- o
- end
- end
-
- class InterpolatedMatchLastLineNode < Node
- include RegularExpressionOptions
- end
-
- class InterpolatedRegularExpressionNode < Node
- include RegularExpressionOptions
- end
-
- class MatchLastLineNode < Node
- include RegularExpressionOptions
- end
-
- class RegularExpressionNode < Node
- include RegularExpressionOptions
- end
-
- private_constant :RegularExpressionOptions
-
- module HeredocQuery # :nodoc:
- # Returns true if this node was represented as a heredoc in the source code.
- def heredoc?
- opening&.start_with?("<<")
- end
- end
-
- class InterpolatedStringNode < Node
- include HeredocQuery
- end
-
- class InterpolatedXStringNode < Node
- include HeredocQuery
- end
-
- class StringNode < Node
- include HeredocQuery
-
- # Occasionally it's helpful to treat a string as if it were interpolated so
- # that there's a consistent interface for working with strings.
- def to_interpolated
- InterpolatedStringNode.new(
- source,
- -1,
- location,
- frozen? ? InterpolatedStringNodeFlags::FROZEN : 0,
- opening_loc,
- [copy(location: content_loc, opening_loc: nil, closing_loc: nil)],
- closing_loc
- )
- end
- end
-
- class XStringNode < Node
- include HeredocQuery
-
- # Occasionally it's helpful to treat a string as if it were interpolated so
- # that there's a consistent interface for working with strings.
- def to_interpolated
- InterpolatedXStringNode.new(
- source,
- -1,
- location,
- flags,
- opening_loc,
- [StringNode.new(source, node_id, content_loc, 0, nil, content_loc, nil, unescaped)],
- closing_loc
- )
- end
- end
-
- private_constant :HeredocQuery
-
- class ImaginaryNode < Node
- # Returns the value of the node as a Ruby Complex.
- def value
- Complex(0, numeric.value)
- end
- end
-
- class RationalNode < Node
- # Returns the value of the node as a Ruby Rational.
- def value
- Rational(numerator, denominator)
- end
-
- # Returns the value of the node as an IntegerNode or a FloatNode. This
- # method is deprecated in favor of #value or #numerator/#denominator.
- def numeric
- deprecated("value", "numerator", "denominator")
-
- if denominator == 1
- IntegerNode.new(source, -1, location.chop, flags, numerator)
- else
- FloatNode.new(source, -1, location.chop, 0, numerator.to_f / denominator)
- end
- end
- end
-
- class ConstantReadNode < Node
- # Returns the list of parts for the full name of this constant.
- # For example: [:Foo]
- def full_name_parts
- [name]
- end
-
- # Returns the full name of this constant. For example: "Foo"
- def full_name
- name.to_s
- end
- end
-
- class ConstantWriteNode < Node
- # Returns the list of parts for the full name of this constant.
- # For example: [:Foo]
- def full_name_parts
- [name]
- end
-
- # Returns the full name of this constant. For example: "Foo"
- def full_name
- name.to_s
- end
- end
-
- class ConstantPathNode < Node
- # An error class raised when dynamic parts are found while computing a
- # constant path's full name. For example:
- # Foo::Bar::Baz -> does not raise because all parts of the constant path are
- # simple constants
- # var::Bar::Baz -> raises because the first part of the constant path is a
- # local variable
- class DynamicPartsInConstantPathError < StandardError; end
-
- # An error class raised when missing nodes are found while computing a
- # constant path's full name. For example:
- # Foo:: -> raises because the constant path is missing the last part
- class MissingNodesInConstantPathError < StandardError; end
-
- # Returns the list of parts for the full name of this constant path.
- # For example: [:Foo, :Bar]
- def full_name_parts
- parts = [] #: Array[Symbol]
- current = self #: node?
-
- while current.is_a?(ConstantPathNode)
- name = current.name
- if name.nil?
- raise MissingNodesInConstantPathError, "Constant path contains missing nodes. Cannot compute full name"
- end
-
- parts.unshift(name)
- current = current.parent
- end
-
- if !current.is_a?(ConstantReadNode) && !current.nil?
- raise DynamicPartsInConstantPathError, "Constant path contains dynamic parts. Cannot compute full name"
- end
-
- parts.unshift(current&.name || :"")
- end
-
- # Returns the full name of this constant path. For example: "Foo::Bar"
- def full_name
- full_name_parts.join("::")
- end
-
- # Previously, we had a child node on this class that contained either a
- # constant read or a missing node. To not cause a breaking change, we
- # continue to supply that API.
- def child
- deprecated("name", "name_loc")
-
- if name
- ConstantReadNode.new(source, -1, name_loc, 0, name)
- else
- MissingNode.new(source, -1, location, 0)
- end
- end
- end
-
- class ConstantPathTargetNode < Node
- # Returns the list of parts for the full name of this constant path.
- # For example: [:Foo, :Bar]
- def full_name_parts
- parts =
- case parent
- when ConstantPathNode, ConstantReadNode
- parent.full_name_parts
- when nil
- [:""]
- else
- # e.g. self::Foo, (var)::Bar = baz
- raise ConstantPathNode::DynamicPartsInConstantPathError, "Constant target path contains dynamic parts. Cannot compute full name"
- end
-
- if name.nil?
- raise ConstantPathNode::MissingNodesInConstantPathError, "Constant target path contains missing nodes. Cannot compute full name"
- end
-
- parts.push(name)
- end
-
- # Returns the full name of this constant path. For example: "Foo::Bar"
- def full_name
- full_name_parts.join("::")
- end
-
- # Previously, we had a child node on this class that contained either a
- # constant read or a missing node. To not cause a breaking change, we
- # continue to supply that API.
- def child
- deprecated("name", "name_loc")
-
- if name
- ConstantReadNode.new(source, -1, name_loc, 0, name)
- else
- MissingNode.new(source, -1, location, 0)
- end
- end
- end
-
- class ConstantTargetNode < Node
- # Returns the list of parts for the full name of this constant.
- # For example: [:Foo]
- def full_name_parts
- [name]
- end
-
- # Returns the full name of this constant. For example: "Foo"
- def full_name
- name.to_s
- end
- end
-
- class ParametersNode < Node
- # Mirrors the Method#parameters method.
- def signature
- names = [] #: Array[[Symbol, Symbol] | [Symbol]]
-
- requireds.each do |param|
- names << (param.is_a?(MultiTargetNode) ? [:req] : [:req, param.name])
- end
-
- optionals.each { |param| names << [:opt, param.name] }
-
- if rest && rest.is_a?(RestParameterNode)
- names << [:rest, rest.name || :*]
- end
-
- posts.each do |param|
- case param
- when MultiTargetNode
- names << [:req]
- when NoKeywordsParameterNode, KeywordRestParameterNode, ForwardingParameterNode
- # Invalid syntax, e.g. "def f(**nil, ...)" moves the NoKeywordsParameterNode to posts
- raise "Invalid syntax"
- else
- names << [:req, param.name]
- end
- end
-
- # Regardless of the order in which the keywords were defined, the required
- # keywords always come first followed by the optional keywords.
- keyopt = [] #: Array[OptionalKeywordParameterNode]
- keywords.each do |param|
- if param.is_a?(OptionalKeywordParameterNode)
- keyopt << param
- else
- names << [:keyreq, param.name]
- end
- end
-
- keyopt.each { |param| names << [:key, param.name] }
-
- case keyword_rest
- when ForwardingParameterNode
- names.concat([[:rest, :*], [:keyrest, :**], [:block, :&]])
- when KeywordRestParameterNode
- names << [:keyrest, keyword_rest.name || :**]
- when NoKeywordsParameterNode
- names << [:nokey]
- end
-
- names << [:block, block.name || :&] if block
- names
- end
- end
-
- class CallNode < Node
- # When a call node has the attribute_write flag set, it means that the call
- # is using the attribute write syntax. This is either a method call to []=
- # or a method call to a method that ends with =. Either way, the = sign is
- # present in the source.
- #
- # Prism returns the message_loc _without_ the = sign attached, because there
- # can be any amount of space between the message and the = sign. However,
- # sometimes you want the location of the full message including the inner
- # space and the = sign. This method provides that.
- def full_message_loc
- attribute_write? ? message_loc&.adjoin("=") : message_loc
- end
- end
-
- class CallOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class ClassVariableOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class ConstantOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class ConstantPathOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class GlobalVariableOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class IndexOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class InstanceVariableOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class LocalVariableOperatorWriteNode < Node
- # Returns the binary operator used to modify the receiver. This method is
- # deprecated in favor of #binary_operator.
- def operator
- deprecated("binary_operator")
- binary_operator
- end
-
- # Returns the location of the binary operator used to modify the receiver.
- # This method is deprecated in favor of #binary_operator_loc.
- def operator_loc
- deprecated("binary_operator_loc")
- binary_operator_loc
- end
- end
-
- class CaseMatchNode < Node
- # Returns the else clause of the case match node. This method is deprecated
- # in favor of #else_clause.
- def consequent
- deprecated("else_clause")
- else_clause
- end
- end
-
- class CaseNode < Node
- # Returns the else clause of the case node. This method is deprecated in
- # favor of #else_clause.
- def consequent
- deprecated("else_clause")
- else_clause
- end
- end
-
- class IfNode < Node
- # Returns the subsequent if/elsif/else clause of the if node. This method is
- # deprecated in favor of #subsequent.
- def consequent
- deprecated("subsequent")
- subsequent
- end
- end
-
- class RescueNode < Node
- # Returns the subsequent rescue clause of the rescue node. This method is
- # deprecated in favor of #subsequent.
- def consequent
- deprecated("subsequent")
- subsequent
- end
- end
-
- class UnlessNode < Node
- # Returns the else clause of the unless node. This method is deprecated in
- # favor of #else_clause.
- def consequent
- deprecated("else_clause")
- else_clause
- end
- end
-end
diff --git a/lib/prism/pack.rb b/lib/prism/pack.rb
deleted file mode 100644
index c0de8ab8b7..0000000000
--- a/lib/prism/pack.rb
+++ /dev/null
@@ -1,228 +0,0 @@
-# frozen_string_literal: true
-# typed: ignore
-
-module Prism
- # A parser for the pack template language.
- module Pack
- %i[
- SPACE
- COMMENT
- INTEGER
- UTF8
- BER
- FLOAT
- STRING_SPACE_PADDED
- STRING_NULL_PADDED
- STRING_NULL_TERMINATED
- STRING_MSB
- STRING_LSB
- STRING_HEX_HIGH
- STRING_HEX_LOW
- STRING_UU
- STRING_MIME
- STRING_BASE64
- STRING_FIXED
- STRING_POINTER
- MOVE
- BACK
- NULL
-
- UNSIGNED
- SIGNED
- SIGNED_NA
-
- AGNOSTIC_ENDIAN
- LITTLE_ENDIAN
- BIG_ENDIAN
- NATIVE_ENDIAN
- ENDIAN_NA
-
- SIZE_SHORT
- SIZE_INT
- SIZE_LONG
- SIZE_LONG_LONG
- SIZE_8
- SIZE_16
- SIZE_32
- SIZE_64
- SIZE_P
- SIZE_NA
-
- LENGTH_FIXED
- LENGTH_MAX
- LENGTH_RELATIVE
- LENGTH_NA
- ].each do |const|
- const_set(const, const)
- end
-
- # A directive in the pack template language.
- class Directive
- # A symbol representing the version of Ruby.
- attr_reader :version
-
- # A symbol representing whether or not we are packing or unpacking.
- attr_reader :variant
-
- # A byteslice of the source string that this directive represents.
- attr_reader :source
-
- # The type of the directive.
- attr_reader :type
-
- # The type of signedness of the directive.
- attr_reader :signed
-
- # The type of endianness of the directive.
- attr_reader :endian
-
- # The size of the directive.
- attr_reader :size
-
- # The length type of this directive (used for integers).
- attr_reader :length_type
-
- # The length of this directive (used for integers).
- attr_reader :length
-
- # Initialize a new directive with the given values.
- def initialize(version, variant, source, type, signed, endian, size, length_type, length)
- @version = version
- @variant = variant
- @source = source
- @type = type
- @signed = signed
- @endian = endian
- @size = size
- @length_type = length_type
- @length = length
- end
-
- # The descriptions of the various types of endianness.
- ENDIAN_DESCRIPTIONS = {
- AGNOSTIC_ENDIAN: "agnostic",
- LITTLE_ENDIAN: "little-endian (VAX)",
- BIG_ENDIAN: "big-endian (network)",
- NATIVE_ENDIAN: "native-endian",
- ENDIAN_NA: "n/a"
- }
-
- # The descriptions of the various types of signedness.
- SIGNED_DESCRIPTIONS = {
- UNSIGNED: "unsigned",
- SIGNED: "signed",
- SIGNED_NA: "n/a"
- }
-
- # The descriptions of the various types of sizes.
- SIZE_DESCRIPTIONS = {
- SIZE_SHORT: "short",
- SIZE_INT: "int-width",
- SIZE_LONG: "long",
- SIZE_LONG_LONG: "long long",
- SIZE_8: "8-bit",
- SIZE_16: "16-bit",
- SIZE_32: "32-bit",
- SIZE_64: "64-bit",
- SIZE_P: "pointer-width"
- }
-
- # Provide a human-readable description of the directive.
- def describe
- case type
- when SPACE
- "whitespace"
- when COMMENT
- "comment"
- when INTEGER
- if size == SIZE_8
- base = "#{SIGNED_DESCRIPTIONS[signed]} #{SIZE_DESCRIPTIONS[size]} integer"
- else
- base = "#{SIGNED_DESCRIPTIONS[signed]} #{SIZE_DESCRIPTIONS[size]} #{ENDIAN_DESCRIPTIONS[endian]} integer"
- end
- case length_type
- when LENGTH_FIXED
- if length > 1
- base + ", x#{length}"
- else
- base
- end
- when LENGTH_MAX
- base + ", as many as possible"
- else
- raise
- end
- when UTF8
- "UTF-8 character"
- when BER
- "BER-compressed integer"
- when FLOAT
- "#{SIZE_DESCRIPTIONS[size]} #{ENDIAN_DESCRIPTIONS[endian]} float"
- when STRING_SPACE_PADDED
- "arbitrary binary string (space padded)"
- when STRING_NULL_PADDED
- "arbitrary binary string (null padded, count is width)"
- when STRING_NULL_TERMINATED
- "arbitrary binary string (null padded, count is width), except that null is added with *"
- when STRING_MSB
- "bit string (MSB first)"
- when STRING_LSB
- "bit string (LSB first)"
- when STRING_HEX_HIGH
- "hex string (high nibble first)"
- when STRING_HEX_LOW
- "hex string (low nibble first)"
- when STRING_UU
- "UU-encoded string"
- when STRING_MIME
- "quoted printable, MIME encoding"
- when STRING_BASE64
- "base64 encoded string"
- when STRING_FIXED
- "pointer to a structure (fixed-length string)"
- when STRING_POINTER
- "pointer to a null-terminated string"
- when MOVE
- "move to absolute position"
- when BACK
- "back up a byte"
- when NULL
- "null byte"
- else
- raise
- end
- end
- end
-
- # The result of parsing a pack template.
- class Format
- # A list of the directives in the template.
- attr_reader :directives
-
- # The encoding of the template.
- attr_reader :encoding
-
- # Create a new Format with the given directives and encoding.
- def initialize(directives, encoding)
- @directives = directives
- @encoding = encoding
- end
-
- # Provide a human-readable description of the format.
- def describe
- source_width = directives.map { |d| d.source.inspect.length }.max
- directive_lines = directives.map do |directive|
- if directive.type == SPACE
- source = directive.source.inspect
- else
- source = directive.source
- end
- # @type var source_width: Integer
- " #{source.ljust(source_width)} #{directive.describe}"
- end
-
- (["Directives:"] + directive_lines + ["Encoding:", " #{encoding}"]).join("\n")
- end
- end
- end
-end
diff --git a/lib/prism/parse_result.rb b/lib/prism/parse_result.rb
deleted file mode 100644
index ae026b42ac..0000000000
--- a/lib/prism/parse_result.rb
+++ /dev/null
@@ -1,721 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- # This represents a source of Ruby code that has been parsed. It is used in
- # conjunction with locations to allow them to resolve line numbers and source
- # ranges.
- class Source
- # Create a new source object with the given source code. This method should
- # be used instead of `new` and it will return either a `Source` or a
- # specialized and more performant `ASCIISource` if no multibyte characters
- # are present in the source code.
- def self.for(source, start_line = 1, offsets = [])
- if source.ascii_only?
- ASCIISource.new(source, start_line, offsets)
- else
- new(source, start_line, offsets)
- end
- end
-
- # The source code that this source object represents.
- attr_reader :source
-
- # The line number where this source starts.
- attr_reader :start_line
-
- # The list of newline byte offsets in the source code.
- attr_reader :offsets
-
- # Create a new source object with the given source code.
- def initialize(source, start_line = 1, offsets = [])
- @source = source
- @start_line = start_line # set after parsing is done
- @offsets = offsets # set after parsing is done
- end
-
- # Returns the encoding of the source code, which is set by parameters to the
- # parser or by the encoding magic comment.
- def encoding
- source.encoding
- end
-
- # Returns the lines of the source code as an array of strings.
- def lines
- source.lines
- end
-
- # Perform a byteslice on the source code using the given byte offset and
- # byte length.
- def slice(byte_offset, length)
- source.byteslice(byte_offset, length) or raise
- end
-
- # Binary search through the offsets to find the line number for the given
- # byte offset.
- def line(byte_offset)
- start_line + find_line(byte_offset)
- end
-
- # Return the byte offset of the start of the line corresponding to the given
- # byte offset.
- def line_start(byte_offset)
- offsets[find_line(byte_offset)]
- end
-
- # Returns the byte offset of the end of the line corresponding to the given
- # byte offset.
- def line_end(byte_offset)
- offsets[find_line(byte_offset) + 1] || source.bytesize
- end
-
- # Return the column number for the given byte offset.
- def column(byte_offset)
- byte_offset - line_start(byte_offset)
- end
-
- # Return the character offset for the given byte offset.
- def character_offset(byte_offset)
- (source.byteslice(0, byte_offset) or raise).length
- end
-
- # Return the column number in characters for the given byte offset.
- def character_column(byte_offset)
- character_offset(byte_offset) - character_offset(line_start(byte_offset))
- end
-
- # Returns the offset from the start of the file for the given byte offset
- # counting in code units for the given encoding.
- #
- # This method is tested with UTF-8, UTF-16, and UTF-32. If there is the
- # concept of code units that differs from the number of characters in other
- # encodings, it is not captured here.
- def code_units_offset(byte_offset, encoding)
- byteslice = (source.byteslice(0, byte_offset) or raise).encode(encoding)
-
- if encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE
- byteslice.bytesize / 2
- else
- byteslice.length
- end
- end
-
- # Returns the column number in code units for the given encoding for the
- # given byte offset.
- def code_units_column(byte_offset, encoding)
- code_units_offset(byte_offset, encoding) - code_units_offset(line_start(byte_offset), encoding)
- end
-
- private
-
- # Binary search through the offsets to find the line number for the given
- # byte offset.
- def find_line(byte_offset)
- left = 0
- right = offsets.length - 1
-
- while left <= right
- mid = left + (right - left) / 2
- return mid if (offset = offsets[mid]) == byte_offset
-
- if offset < byte_offset
- left = mid + 1
- else
- right = mid - 1
- end
- end
-
- left - 1
- end
- end
-
- # Specialized version of Prism::Source for source code that includes ASCII
- # characters only. This class is used to apply performance optimizations that
- # cannot be applied to sources that include multibyte characters. Sources that
- # include multibyte characters are represented by the Prism::Source class.
- class ASCIISource < Source
- # Return the character offset for the given byte offset.
- def character_offset(byte_offset)
- byte_offset
- end
-
- # Return the column number in characters for the given byte offset.
- def character_column(byte_offset)
- byte_offset - line_start(byte_offset)
- end
-
- # Returns the offset from the start of the file for the given byte offset
- # counting in code units for the given encoding.
- #
- # This method is tested with UTF-8, UTF-16, and UTF-32. If there is the
- # concept of code units that differs from the number of characters in other
- # encodings, it is not captured here.
- def code_units_offset(byte_offset, encoding)
- byte_offset
- end
-
- # Specialized version of `code_units_column` that does not depend on
- # `code_units_offset`, which is a more expensive operation. This is
- # essentially the same as `Prism::Source#column`.
- def code_units_column(byte_offset, encoding)
- byte_offset - line_start(byte_offset)
- end
- end
-
- # This represents a location in the source.
- class Location
- # A Source object that is used to determine more information from the given
- # offset and length.
- attr_reader :source
- protected :source
-
- # The byte offset from the beginning of the source where this location
- # starts.
- attr_reader :start_offset
-
- # The length of this location in bytes.
- attr_reader :length
-
- # Create a new location object with the given source, start byte offset, and
- # byte length.
- def initialize(source, start_offset, length)
- @source = source
- @start_offset = start_offset
- @length = length
-
- # These are used to store comments that are associated with this location.
- # They are initialized to `nil` to save on memory when there are no
- # comments to be attached and/or the comment-related APIs are not used.
- @leading_comments = nil
- @trailing_comments = nil
- end
-
- # These are the comments that are associated with this location that exist
- # before the start of this location.
- def leading_comments
- @leading_comments ||= []
- end
-
- # Attach a comment to the leading comments of this location.
- def leading_comment(comment)
- leading_comments << comment
- end
-
- # These are the comments that are associated with this location that exist
- # after the end of this location.
- def trailing_comments
- @trailing_comments ||= []
- end
-
- # Attach a comment to the trailing comments of this location.
- def trailing_comment(comment)
- trailing_comments << comment
- end
-
- # Returns all comments that are associated with this location (both leading
- # and trailing comments).
- def comments
- [*@leading_comments, *@trailing_comments]
- end
-
- # Create a new location object with the given options.
- def copy(source: self.source, start_offset: self.start_offset, length: self.length)
- Location.new(source, start_offset, length)
- end
-
- # Returns a new location that is the result of chopping off the last byte.
- def chop
- copy(length: length == 0 ? length : length - 1)
- end
-
- # Returns a string representation of this location.
- def inspect
- "#<Prism::Location @start_offset=#{@start_offset} @length=#{@length} start_line=#{start_line}>"
- end
-
- # Returns all of the lines of the source code associated with this location.
- def source_lines
- source.lines
- end
-
- # The source code that this location represents.
- def slice
- source.slice(start_offset, length)
- end
-
- # The source code that this location represents starting from the beginning
- # of the line that this location starts on to the end of the line that this
- # location ends on.
- def slice_lines
- line_start = source.line_start(start_offset)
- line_end = source.line_end(end_offset)
- source.slice(line_start, line_end - line_start)
- end
-
- # The character offset from the beginning of the source where this location
- # starts.
- def start_character_offset
- source.character_offset(start_offset)
- end
-
- # The offset from the start of the file in code units of the given encoding.
- def start_code_units_offset(encoding = Encoding::UTF_16LE)
- source.code_units_offset(start_offset, encoding)
- end
-
- # The byte offset from the beginning of the source where this location ends.
- def end_offset
- start_offset + length
- end
-
- # The character offset from the beginning of the source where this location
- # ends.
- def end_character_offset
- source.character_offset(end_offset)
- end
-
- # The offset from the start of the file in code units of the given encoding.
- def end_code_units_offset(encoding = Encoding::UTF_16LE)
- source.code_units_offset(end_offset, encoding)
- end
-
- # The line number where this location starts.
- def start_line
- source.line(start_offset)
- end
-
- # The content of the line where this location starts before this location.
- def start_line_slice
- offset = source.line_start(start_offset)
- source.slice(offset, start_offset - offset)
- end
-
- # The line number where this location ends.
- def end_line
- source.line(end_offset)
- end
-
- # The column number in bytes where this location starts from the start of
- # the line.
- def start_column
- source.column(start_offset)
- end
-
- # The column number in characters where this location ends from the start of
- # the line.
- def start_character_column
- source.character_column(start_offset)
- end
-
- # The column number in code units of the given encoding where this location
- # starts from the start of the line.
- def start_code_units_column(encoding = Encoding::UTF_16LE)
- source.code_units_column(start_offset, encoding)
- end
-
- # The column number in bytes where this location ends from the start of the
- # line.
- def end_column
- source.column(end_offset)
- end
-
- # The column number in characters where this location ends from the start of
- # the line.
- def end_character_column
- source.character_column(end_offset)
- end
-
- # The column number in code units of the given encoding where this location
- # ends from the start of the line.
- def end_code_units_column(encoding = Encoding::UTF_16LE)
- source.code_units_column(end_offset, encoding)
- end
-
- # Implement the hash pattern matching interface for Location.
- def deconstruct_keys(keys)
- { start_offset: start_offset, end_offset: end_offset }
- end
-
- # Implement the pretty print interface for Location.
- def pretty_print(q)
- q.text("(#{start_line},#{start_column})-(#{end_line},#{end_column})")
- end
-
- # Returns true if the given other location is equal to this location.
- def ==(other)
- Location === other &&
- other.start_offset == start_offset &&
- other.end_offset == end_offset
- end
-
- # Returns a new location that stretches from this location to the given
- # other location. Raises an error if this location is not before the other
- # location or if they don't share the same source.
- def join(other)
- raise "Incompatible sources" if source != other.source
- raise "Incompatible locations" if start_offset > other.start_offset
-
- Location.new(source, start_offset, other.end_offset - start_offset)
- end
-
- # Join this location with the first occurrence of the string in the source
- # that occurs after this location on the same line, and return the new
- # location. This will raise an error if the string does not exist.
- def adjoin(string)
- line_suffix = source.slice(end_offset, source.line_end(end_offset) - end_offset)
-
- line_suffix_index = line_suffix.byteindex(string)
- raise "Could not find #{string}" if line_suffix_index.nil?
-
- Location.new(source, start_offset, length + line_suffix_index + string.bytesize)
- end
- end
-
- # This represents a comment that was encountered during parsing. It is the
- # base class for all comment types.
- class Comment
- # The location of this comment in the source.
- attr_reader :location
-
- # Create a new comment object with the given location.
- def initialize(location)
- @location = location
- end
-
- # Implement the hash pattern matching interface for Comment.
- def deconstruct_keys(keys)
- { location: location }
- end
-
- # Returns the content of the comment by slicing it from the source code.
- def slice
- location.slice
- end
- end
-
- # InlineComment objects are the most common. They correspond to comments in
- # the source file like this one that start with #.
- class InlineComment < Comment
- # Returns true if this comment happens on the same line as other code and
- # false if the comment is by itself.
- def trailing?
- !location.start_line_slice.strip.empty?
- end
-
- # Returns a string representation of this comment.
- def inspect
- "#<Prism::InlineComment @location=#{location.inspect}>"
- end
- end
-
- # EmbDocComment objects correspond to comments that are surrounded by =begin
- # and =end.
- class EmbDocComment < Comment
- # This can only be true for inline comments.
- def trailing?
- false
- end
-
- # Returns a string representation of this comment.
- def inspect
- "#<Prism::EmbDocComment @location=#{location.inspect}>"
- end
- end
-
- # This represents a magic comment that was encountered during parsing.
- class MagicComment
- # A Location object representing the location of the key in the source.
- attr_reader :key_loc
-
- # A Location object representing the location of the value in the source.
- attr_reader :value_loc
-
- # Create a new magic comment object with the given key and value locations.
- def initialize(key_loc, value_loc)
- @key_loc = key_loc
- @value_loc = value_loc
- end
-
- # Returns the key of the magic comment by slicing it from the source code.
- def key
- key_loc.slice
- end
-
- # Returns the value of the magic comment by slicing it from the source code.
- def value
- value_loc.slice
- end
-
- # Implement the hash pattern matching interface for MagicComment.
- def deconstruct_keys(keys)
- { key_loc: key_loc, value_loc: value_loc }
- end
-
- # Returns a string representation of this magic comment.
- def inspect
- "#<Prism::MagicComment @key=#{key.inspect} @value=#{value.inspect}>"
- end
- end
-
- # This represents an error that was encountered during parsing.
- class ParseError
- # The type of error. This is an _internal_ symbol that is used for
- # communicating with translation layers. It is not meant to be public API.
- attr_reader :type
-
- # The message associated with this error.
- attr_reader :message
-
- # A Location object representing the location of this error in the source.
- attr_reader :location
-
- # The level of this error.
- attr_reader :level
-
- # Create a new error object with the given message and location.
- def initialize(type, message, location, level)
- @type = type
- @message = message
- @location = location
- @level = level
- end
-
- # Implement the hash pattern matching interface for ParseError.
- def deconstruct_keys(keys)
- { type: type, message: message, location: location, level: level }
- end
-
- # Returns a string representation of this error.
- def inspect
- "#<Prism::ParseError @type=#{@type.inspect} @message=#{@message.inspect} @location=#{@location.inspect} @level=#{@level.inspect}>"
- end
- end
-
- # This represents a warning that was encountered during parsing.
- class ParseWarning
- # The type of warning. This is an _internal_ symbol that is used for
- # communicating with translation layers. It is not meant to be public API.
- attr_reader :type
-
- # The message associated with this warning.
- attr_reader :message
-
- # A Location object representing the location of this warning in the source.
- attr_reader :location
-
- # The level of this warning.
- attr_reader :level
-
- # Create a new warning object with the given message and location.
- def initialize(type, message, location, level)
- @type = type
- @message = message
- @location = location
- @level = level
- end
-
- # Implement the hash pattern matching interface for ParseWarning.
- def deconstruct_keys(keys)
- { type: type, message: message, location: location, level: level }
- end
-
- # Returns a string representation of this warning.
- def inspect
- "#<Prism::ParseWarning @type=#{@type.inspect} @message=#{@message.inspect} @location=#{@location.inspect} @level=#{@level.inspect}>"
- end
- end
-
- # This represents the result of a call to ::parse or ::parse_file. It contains
- # the requested structure, any comments that were encounters, and any errors
- # that were encountered.
- class Result
- # The list of comments that were encountered during parsing.
- attr_reader :comments
-
- # The list of magic comments that were encountered during parsing.
- attr_reader :magic_comments
-
- # An optional location that represents the location of the __END__ marker
- # and the rest of the content of the file. This content is loaded into the
- # DATA constant when the file being parsed is the main file being executed.
- attr_reader :data_loc
-
- # The list of errors that were generated during parsing.
- attr_reader :errors
-
- # The list of warnings that were generated during parsing.
- attr_reader :warnings
-
- # A Source instance that represents the source code that was parsed.
- attr_reader :source
-
- # Create a new result object with the given values.
- def initialize(comments, magic_comments, data_loc, errors, warnings, source)
- @comments = comments
- @magic_comments = magic_comments
- @data_loc = data_loc
- @errors = errors
- @warnings = warnings
- @source = source
- end
-
- # Implement the hash pattern matching interface for Result.
- def deconstruct_keys(keys)
- { comments: comments, magic_comments: magic_comments, data_loc: data_loc, errors: errors, warnings: warnings }
- end
-
- # Returns the encoding of the source code that was parsed.
- def encoding
- source.encoding
- end
-
- # Returns true if there were no errors during parsing and false if there
- # were.
- def success?
- errors.empty?
- end
-
- # Returns true if there were errors during parsing and false if there were
- # not.
- def failure?
- !success?
- end
- end
-
- # This is a result specific to the `parse` and `parse_file` methods.
- class ParseResult < Result
- autoload :Comments, "prism/parse_result/comments"
- autoload :Errors, "prism/parse_result/errors"
- autoload :Newlines, "prism/parse_result/newlines"
-
- private_constant :Comments
- private_constant :Errors
- private_constant :Newlines
-
- # The syntax tree that was parsed from the source code.
- attr_reader :value
-
- # Create a new parse result object with the given values.
- def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
- @value = value
- super(comments, magic_comments, data_loc, errors, warnings, source)
- end
-
- # Implement the hash pattern matching interface for ParseResult.
- def deconstruct_keys(keys)
- super.merge!(value: value)
- end
-
- # Attach the list of comments to their respective locations in the tree.
- def attach_comments!
- Comments.new(self).attach! # steep:ignore
- end
-
- # Walk the tree and mark nodes that are on a new line, loosely emulating
- # the behavior of CRuby's `:line` tracepoint event.
- def mark_newlines!
- value.accept(Newlines.new(source.offsets.size)) # steep:ignore
- end
-
- # Returns a string representation of the syntax tree with the errors
- # displayed inline.
- def errors_format
- Errors.new(self).format
- end
- end
-
- # This is a result specific to the `lex` and `lex_file` methods.
- class LexResult < Result
- # The list of tokens that were parsed from the source code.
- attr_reader :value
-
- # Create a new lex result object with the given values.
- def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
- @value = value
- super(comments, magic_comments, data_loc, errors, warnings, source)
- end
-
- # Implement the hash pattern matching interface for LexResult.
- def deconstruct_keys(keys)
- super.merge!(value: value)
- end
- end
-
- # This is a result specific to the `parse_lex` and `parse_lex_file` methods.
- class ParseLexResult < Result
- # A tuple of the syntax tree and the list of tokens that were parsed from
- # the source code.
- attr_reader :value
-
- # Create a new parse lex result object with the given values.
- def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
- @value = value
- super(comments, magic_comments, data_loc, errors, warnings, source)
- end
-
- # Implement the hash pattern matching interface for ParseLexResult.
- def deconstruct_keys(keys)
- super.merge!(value: value)
- end
- end
-
- # This represents a token from the Ruby source.
- class Token
- # The Source object that represents the source this token came from.
- attr_reader :source
- private :source
-
- # The type of token that this token is.
- attr_reader :type
-
- # A byteslice of the source that this token represents.
- attr_reader :value
-
- # Create a new token object with the given type, value, and location.
- def initialize(source, type, value, location)
- @source = source
- @type = type
- @value = value
- @location = location
- end
-
- # Implement the hash pattern matching interface for Token.
- def deconstruct_keys(keys)
- { type: type, value: value, location: location }
- end
-
- # A Location object representing the location of this token in the source.
- def location
- location = @location
- return location if location.is_a?(Location)
- @location = Location.new(source, location >> 32, location & 0xFFFFFFFF)
- end
-
- # Implement the pretty print interface for Token.
- def pretty_print(q)
- q.group do
- q.text(type.to_s)
- self.location.pretty_print(q)
- q.text("(")
- q.nest(2) do
- q.breakable("")
- q.pp(value)
- end
- q.breakable("")
- q.text(")")
- end
- end
-
- # Returns true if the given other token is equal to this token.
- def ==(other)
- Token === other &&
- other.type == type &&
- other.value == value
- end
-
- # Returns a string representation of this token.
- def inspect
- location
- super
- end
- end
-end
diff --git a/lib/prism/parse_result/comments.rb b/lib/prism/parse_result/comments.rb
deleted file mode 100644
index 22c4148b2c..0000000000
--- a/lib/prism/parse_result/comments.rb
+++ /dev/null
@@ -1,187 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- class ParseResult < Result
- # When we've parsed the source, we have both the syntax tree and the list of
- # comments that we found in the source. This class is responsible for
- # walking the tree and finding the nearest location to attach each comment.
- #
- # It does this by first finding the nearest locations to each comment.
- # Locations can either come from nodes directly or from location fields on
- # nodes. For example, a `ClassNode` has an overall location encompassing the
- # entire class, but it also has a location for the `class` keyword.
- #
- # Once the nearest locations are found, it determines which one to attach
- # to. If it's a trailing comment (a comment on the same line as other source
- # code), it will favor attaching to the nearest location that occurs before
- # the comment. Otherwise it will favor attaching to the nearest location
- # that is after the comment.
- class Comments
- # A target for attaching comments that is based on a specific node's
- # location.
- class NodeTarget # :nodoc:
- attr_reader :node
-
- def initialize(node)
- @node = node
- end
-
- def start_offset
- node.start_offset
- end
-
- def end_offset
- node.end_offset
- end
-
- def encloses?(comment)
- start_offset <= comment.location.start_offset &&
- comment.location.end_offset <= end_offset
- end
-
- def leading_comment(comment)
- node.location.leading_comment(comment)
- end
-
- def trailing_comment(comment)
- node.location.trailing_comment(comment)
- end
- end
-
- # A target for attaching comments that is based on a location field on a
- # node. For example, the `end` token of a ClassNode.
- class LocationTarget # :nodoc:
- attr_reader :location
-
- def initialize(location)
- @location = location
- end
-
- def start_offset
- location.start_offset
- end
-
- def end_offset
- location.end_offset
- end
-
- def encloses?(comment)
- false
- end
-
- def leading_comment(comment)
- location.leading_comment(comment)
- end
-
- def trailing_comment(comment)
- location.trailing_comment(comment)
- end
- end
-
- # The parse result that we are attaching comments to.
- attr_reader :parse_result
-
- # Create a new Comments object that will attach comments to the given
- # parse result.
- def initialize(parse_result)
- @parse_result = parse_result
- end
-
- # Attach the comments to their respective locations in the tree by
- # mutating the parse result.
- def attach!
- parse_result.comments.each do |comment|
- preceding, enclosing, following = nearest_targets(parse_result.value, comment)
-
- if comment.trailing?
- if preceding
- preceding.trailing_comment(comment)
- else
- (following || enclosing || NodeTarget.new(parse_result.value)).leading_comment(comment)
- end
- else
- # If a comment exists on its own line, prefer a leading comment.
- if following
- following.leading_comment(comment)
- elsif preceding
- preceding.trailing_comment(comment)
- else
- (enclosing || NodeTarget.new(parse_result.value)).leading_comment(comment)
- end
- end
- end
- end
-
- private
-
- # Responsible for finding the nearest targets to the given comment within
- # the context of the given encapsulating node.
- def nearest_targets(node, comment)
- comment_start = comment.location.start_offset
- comment_end = comment.location.end_offset
-
- targets = [] #: Array[_Target]
- node.comment_targets.map do |value|
- case value
- when StatementsNode
- targets.concat(value.body.map { |node| NodeTarget.new(node) })
- when Node
- targets << NodeTarget.new(value)
- when Location
- targets << LocationTarget.new(value)
- end
- end
-
- targets.sort_by!(&:start_offset)
- preceding = nil #: _Target?
- following = nil #: _Target?
-
- left = 0
- right = targets.length
-
- # This is a custom binary search that finds the nearest nodes to the
- # given comment. When it finds a node that completely encapsulates the
- # comment, it recurses downward into the tree.
- while left < right
- middle = (left + right) / 2
- target = targets[middle]
-
- target_start = target.start_offset
- target_end = target.end_offset
-
- if target.encloses?(comment)
- # @type var target: NodeTarget
- # The comment is completely contained by this target. Abandon the
- # binary search at this level.
- return nearest_targets(target.node, comment)
- end
-
- if target_end <= comment_start
- # This target falls completely before the comment. Because we will
- # never consider this target or any targets before it again, this
- # target must be the closest preceding target we have encountered so
- # far.
- preceding = target
- left = middle + 1
- next
- end
-
- if comment_end <= target_start
- # This target falls completely after the comment. Because we will
- # never consider this target or any targets after it again, this
- # target must be the closest following target we have encountered so
- # far.
- following = target
- right = middle
- next
- end
-
- # This should only happen if there is a bug in this parser.
- raise "Comment location overlaps with a target location"
- end
-
- [preceding, NodeTarget.new(node), following]
- end
- end
- end
-end
diff --git a/lib/prism/parse_result/errors.rb b/lib/prism/parse_result/errors.rb
deleted file mode 100644
index 847a8442fe..0000000000
--- a/lib/prism/parse_result/errors.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-# frozen_string_literal: true
-
-require "stringio"
-
-module Prism
- class ParseResult < Result
- # An object to represent the set of errors on a parse result. This object
- # can be used to format the errors in a human-readable way.
- class Errors
- # The parse result that contains the errors.
- attr_reader :parse_result
-
- # Initialize a new set of errors from the given parse result.
- def initialize(parse_result)
- @parse_result = parse_result
- end
-
- # Formats the errors in a human-readable way and return them as a string.
- def format
- error_lines = {}
- parse_result.errors.each do |error|
- location = error.location
- (location.start_line..location.end_line).each do |line|
- error_lines[line] ||= []
- error_lines[line] << error
- end
- end
-
- source_lines = parse_result.source.source.lines
- source_lines << "" if error_lines.key?(source_lines.size + 1)
-
- io = StringIO.new
- source_lines.each.with_index(1) do |line, line_number|
- io.puts(line)
-
- (error_lines.delete(line_number) || []).each do |error|
- location = error.location
-
- case line_number
- when location.start_line
- io.print(" " * location.start_column + "^")
-
- if location.start_line == location.end_line
- if location.start_column != location.end_column
- io.print("~" * (location.end_column - location.start_column - 1))
- end
-
- io.puts(" " + error.message)
- else
- io.puts("~" * (line.bytesize - location.start_column))
- end
- when location.end_line
- io.puts("~" * location.end_column + " " + error.message)
- else
- io.puts("~" * line.bytesize)
- end
- end
- end
-
- io.puts
- io.string
- end
- end
- end
-end
diff --git a/lib/prism/parse_result/newlines.rb b/lib/prism/parse_result/newlines.rb
deleted file mode 100644
index a04fa78a75..0000000000
--- a/lib/prism/parse_result/newlines.rb
+++ /dev/null
@@ -1,154 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- class ParseResult < Result
- # The :line tracepoint event gets fired whenever the Ruby VM encounters an
- # expression on a new line. The types of expressions that can trigger this
- # event are:
- #
- # * if statements
- # * unless statements
- # * nodes that are children of statements lists
- #
- # In order to keep track of the newlines, we have a list of offsets that
- # come back from the parser. We assign these offsets to the first nodes that
- # we find in the tree that are on those lines.
- #
- # Note that the logic in this file should be kept in sync with the Java
- # MarkNewlinesVisitor, since that visitor is responsible for marking the
- # newlines for JRuby/TruffleRuby.
- #
- # This file is autoloaded only when `mark_newlines!` is called, so the
- # re-opening of the various nodes in this file will only be performed in
- # that case. We do that to avoid storing the extra `@newline` instance
- # variable on every node if we don't need it.
- class Newlines < Visitor
- # Create a new Newlines visitor with the given newline offsets.
- def initialize(lines)
- # @type var lines: Integer
- @lines = Array.new(1 + lines, false)
- end
-
- # Permit block/lambda nodes to mark newlines within themselves.
- def visit_block_node(node)
- old_lines = @lines
- @lines = Array.new(old_lines.size, false)
-
- begin
- super(node)
- ensure
- @lines = old_lines
- end
- end
-
- alias_method :visit_lambda_node, :visit_block_node
-
- # Mark if/unless nodes as newlines.
- def visit_if_node(node)
- node.newline_flag!(@lines)
- super(node)
- end
-
- alias_method :visit_unless_node, :visit_if_node
-
- # Permit statements lists to mark newlines within themselves.
- def visit_statements_node(node)
- node.body.each do |child|
- child.newline_flag!(@lines)
- end
- super(node)
- end
- end
- end
-
- class Node
- def newline_flag? # :nodoc:
- @newline_flag ? true : false
- end
-
- def newline_flag!(lines) # :nodoc:
- line = location.start_line
- unless lines[line]
- lines[line] = true
- @newline_flag = true
- end
- end
- end
-
- class BeginNode < Node
- def newline_flag!(lines) # :nodoc:
- # Never mark BeginNode with a newline flag, mark children instead.
- end
- end
-
- class ParenthesesNode < Node
- def newline_flag!(lines) # :nodoc:
- # Never mark ParenthesesNode with a newline flag, mark children instead.
- end
- end
-
- class IfNode < Node
- def newline_flag!(lines) # :nodoc:
- predicate.newline_flag!(lines)
- end
- end
-
- class UnlessNode < Node
- def newline_flag!(lines) # :nodoc:
- predicate.newline_flag!(lines)
- end
- end
-
- class UntilNode < Node
- def newline_flag!(lines) # :nodoc:
- predicate.newline_flag!(lines)
- end
- end
-
- class WhileNode < Node
- def newline_flag!(lines) # :nodoc:
- predicate.newline_flag!(lines)
- end
- end
-
- class RescueModifierNode < Node
- def newline_flag!(lines) # :nodoc:
- expression.newline_flag!(lines)
- end
- end
-
- class InterpolatedMatchLastLineNode < Node
- def newline_flag!(lines) # :nodoc:
- first = parts.first
- first.newline_flag!(lines) if first
- end
- end
-
- class InterpolatedRegularExpressionNode < Node
- def newline_flag!(lines) # :nodoc:
- first = parts.first
- first.newline_flag!(lines) if first
- end
- end
-
- class InterpolatedStringNode < Node
- def newline_flag!(lines) # :nodoc:
- first = parts.first
- first.newline_flag!(lines) if first
- end
- end
-
- class InterpolatedSymbolNode < Node
- def newline_flag!(lines) # :nodoc:
- first = parts.first
- first.newline_flag!(lines) if first
- end
- end
-
- class InterpolatedXStringNode < Node
- def newline_flag!(lines) # :nodoc:
- first = parts.first
- first.newline_flag!(lines) if first
- end
- end
-end
diff --git a/lib/prism/pattern.rb b/lib/prism/pattern.rb
deleted file mode 100644
index 03fec26789..0000000000
--- a/lib/prism/pattern.rb
+++ /dev/null
@@ -1,268 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- # A pattern is an object that wraps a Ruby pattern matching expression. The
- # expression would normally be passed to an `in` clause within a `case`
- # expression or a rightward assignment expression. For example, in the
- # following snippet:
- #
- # case node
- # in ConstantPathNode[ConstantReadNode[name: :Prism], ConstantReadNode[name: :Pattern]]
- # end
- #
- # the pattern is the <tt>ConstantPathNode[...]</tt> expression.
- #
- # The pattern gets compiled into an object that responds to #call by running
- # the #compile method. This method itself will run back through Prism to
- # parse the expression into a tree, then walk the tree to generate the
- # necessary callable objects. For example, if you wanted to compile the
- # expression above into a callable, you would:
- #
- # callable = Prism::Pattern.new("ConstantPathNode[ConstantReadNode[name: :Prism], ConstantReadNode[name: :Pattern]]").compile
- # callable.call(node)
- #
- # The callable object returned by #compile is guaranteed to respond to #call
- # with a single argument, which is the node to match against. It also is
- # guaranteed to respond to #===, which means it itself can be used in a `case`
- # expression, as in:
- #
- # case node
- # when callable
- # end
- #
- # If the query given to the initializer cannot be compiled into a valid
- # matcher (either because of a syntax error or because it is using syntax we
- # do not yet support) then a Prism::Pattern::CompilationError will be
- # raised.
- class Pattern
- # Raised when the query given to a pattern is either invalid Ruby syntax or
- # is using syntax that we don't yet support.
- class CompilationError < StandardError
- # Create a new CompilationError with the given representation of the node
- # that caused the error.
- def initialize(repr)
- super(<<~ERROR)
- prism was unable to compile the pattern you provided into a usable
- expression. It failed on to understand the node represented by:
-
- #{repr}
-
- Note that not all syntax supported by Ruby's pattern matching syntax
- is also supported by prism's patterns. If you're using some syntax
- that you believe should be supported, please open an issue on
- GitHub at https://github.com/ruby/prism/issues/new.
- ERROR
- end
- end
-
- # The query that this pattern was initialized with.
- attr_reader :query
-
- # Create a new pattern with the given query. The query should be a string
- # containing a Ruby pattern matching expression.
- def initialize(query)
- @query = query
- @compiled = nil
- end
-
- # Compile the query into a callable object that can be used to match against
- # nodes.
- def compile
- result = Prism.parse("case nil\nin #{query}\nend")
-
- case_match_node = result.value.statements.body.last
- raise CompilationError, case_match_node.inspect unless case_match_node.is_a?(CaseMatchNode)
-
- in_node = case_match_node.conditions.last
- raise CompilationError, in_node.inspect unless in_node.is_a?(InNode)
-
- compile_node(in_node.pattern)
- end
-
- # Scan the given node and all of its children for nodes that match the
- # pattern. If a block is given, it will be called with each node that
- # matches the pattern. If no block is given, an enumerator will be returned
- # that will yield each node that matches the pattern.
- def scan(root)
- return to_enum(:scan, root) unless block_given?
-
- @compiled ||= compile
- queue = [root]
-
- while (node = queue.shift)
- yield node if @compiled.call(node) # steep:ignore
- queue.concat(node.compact_child_nodes)
- end
- end
-
- private
-
- # Shortcut for combining two procs into one that returns true if both return
- # true.
- def combine_and(left, right)
- ->(other) { left.call(other) && right.call(other) }
- end
-
- # Shortcut for combining two procs into one that returns true if either
- # returns true.
- def combine_or(left, right)
- ->(other) { left.call(other) || right.call(other) }
- end
-
- # Raise an error because the given node is not supported.
- def compile_error(node)
- raise CompilationError, node.inspect
- end
-
- # in [foo, bar, baz]
- def compile_array_pattern_node(node)
- compile_error(node) if !node.rest.nil? || node.posts.any?
-
- constant = node.constant
- compiled_constant = compile_node(constant) if constant
-
- preprocessed = node.requireds.map { |required| compile_node(required) }
-
- compiled_requireds = ->(other) do
- deconstructed = other.deconstruct
-
- deconstructed.length == preprocessed.length &&
- preprocessed
- .zip(deconstructed)
- .all? { |(matcher, value)| matcher.call(value) }
- end
-
- if compiled_constant
- combine_and(compiled_constant, compiled_requireds)
- else
- compiled_requireds
- end
- end
-
- # in foo | bar
- def compile_alternation_pattern_node(node)
- combine_or(compile_node(node.left), compile_node(node.right))
- end
-
- # in Prism::ConstantReadNode
- def compile_constant_path_node(node)
- parent = node.parent
-
- if parent.is_a?(ConstantReadNode) && parent.slice == "Prism"
- name = node.name
- raise CompilationError, node.inspect if name.nil?
-
- compile_constant_name(node, name)
- else
- compile_error(node)
- end
- end
-
- # in ConstantReadNode
- # in String
- def compile_constant_read_node(node)
- compile_constant_name(node, node.name)
- end
-
- # Compile a name associated with a constant.
- def compile_constant_name(node, name)
- if Prism.const_defined?(name, false)
- clazz = Prism.const_get(name)
-
- ->(other) { clazz === other }
- elsif Object.const_defined?(name, false)
- clazz = Object.const_get(name)
-
- ->(other) { clazz === other }
- else
- compile_error(node)
- end
- end
-
- # in InstanceVariableReadNode[name: Symbol]
- # in { name: Symbol }
- def compile_hash_pattern_node(node)
- compile_error(node) if node.rest
- compiled_constant = compile_node(node.constant) if node.constant
-
- preprocessed =
- node.elements.to_h do |element|
- key = element.key
- if key.is_a?(SymbolNode)
- [key.unescaped.to_sym, compile_node(element.value)]
- else
- raise CompilationError, element.inspect
- end
- end
-
- compiled_keywords = ->(other) do
- deconstructed = other.deconstruct_keys(preprocessed.keys)
-
- preprocessed.all? do |keyword, matcher|
- deconstructed.key?(keyword) && matcher.call(deconstructed[keyword])
- end
- end
-
- if compiled_constant
- combine_and(compiled_constant, compiled_keywords)
- else
- compiled_keywords
- end
- end
-
- # in nil
- def compile_nil_node(node)
- ->(attribute) { attribute.nil? }
- end
-
- # in /foo/
- def compile_regular_expression_node(node)
- regexp = Regexp.new(node.unescaped, node.closing[1..])
-
- ->(attribute) { regexp === attribute }
- end
-
- # in ""
- # in "foo"
- def compile_string_node(node)
- string = node.unescaped
-
- ->(attribute) { string === attribute }
- end
-
- # in :+
- # in :foo
- def compile_symbol_node(node)
- symbol = node.unescaped.to_sym
-
- ->(attribute) { symbol === attribute }
- end
-
- # Compile any kind of node. Dispatch out to the individual compilation
- # methods based on the type of node.
- def compile_node(node)
- case node
- when AlternationPatternNode
- compile_alternation_pattern_node(node)
- when ArrayPatternNode
- compile_array_pattern_node(node)
- when ConstantPathNode
- compile_constant_path_node(node)
- when ConstantReadNode
- compile_constant_read_node(node)
- when HashPatternNode
- compile_hash_pattern_node(node)
- when NilNode
- compile_nil_node(node)
- when RegularExpressionNode
- compile_regular_expression_node(node)
- when StringNode
- compile_string_node(node)
- when SymbolNode
- compile_symbol_node(node)
- else
- compile_error(node)
- end
- end
- end
-end
diff --git a/lib/prism/polyfill/byteindex.rb b/lib/prism/polyfill/byteindex.rb
deleted file mode 100644
index 98c6089f14..0000000000
--- a/lib/prism/polyfill/byteindex.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-# Polyfill for String#byteindex, which didn't exist until Ruby 3.2.
-if !("".respond_to?(:byteindex))
- String.include(
- Module.new {
- def byteindex(needle, offset = 0)
- charindex = index(needle, offset)
- slice(0...charindex).bytesize if charindex
- end
- }
- )
-end
diff --git a/lib/prism/polyfill/unpack1.rb b/lib/prism/polyfill/unpack1.rb
deleted file mode 100644
index 3fa9b5a0c5..0000000000
--- a/lib/prism/polyfill/unpack1.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-# Polyfill for String#unpack1 with the offset parameter. Not all Ruby engines
-# have Method#parameters implemented, so we check the arity instead if
-# necessary.
-if (unpack1 = String.instance_method(:unpack1)).respond_to?(:parameters) ? unpack1.parameters.none? { |_, name| name == :offset } : (unpack1.arity == 1)
- String.prepend(
- Module.new {
- def unpack1(format, offset: 0) # :nodoc:
- offset == 0 ? super(format) : self[offset..].unpack1(format) # steep:ignore
- end
- }
- )
-end
diff --git a/lib/prism/prism.gemspec b/lib/prism/prism.gemspec
deleted file mode 100644
index 37aa979576..0000000000
--- a/lib/prism/prism.gemspec
+++ /dev/null
@@ -1,160 +0,0 @@
-# frozen_string_literal: true
-
-Gem::Specification.new do |spec|
- spec.name = "prism"
- spec.version = "1.0.0"
- spec.authors = ["Shopify"]
- spec.email = ["ruby@shopify.com"]
-
- spec.summary = "Prism Ruby parser"
- spec.homepage = "https://github.com/ruby/prism"
- spec.license = "MIT"
-
- spec.required_ruby_version = ">= 2.7.0"
-
- spec.require_paths = ["lib"]
- spec.files = [
- "BSDmakefile",
- "CHANGELOG.md",
- "CODE_OF_CONDUCT.md",
- "CONTRIBUTING.md",
- "LICENSE.md",
- "Makefile",
- "README.md",
- "config.yml",
- "docs/build_system.md",
- "docs/configuration.md",
- "docs/cruby_compilation.md",
- "docs/design.md",
- "docs/encoding.md",
- "docs/fuzzing.md",
- "docs/heredocs.md",
- "docs/javascript.md",
- "docs/local_variable_depth.md",
- "docs/mapping.md",
- "docs/parser_translation.md",
- "docs/parsing_rules.md",
- "docs/releasing.md",
- "docs/ripper_translation.md",
- "docs/ruby_api.md",
- "docs/ruby_parser_translation.md",
- "docs/serialization.md",
- "docs/testing.md",
- "ext/prism/api_node.c",
- "ext/prism/api_pack.c",
- "ext/prism/extension.c",
- "ext/prism/extension.h",
- "include/prism.h",
- "include/prism/ast.h",
- "include/prism/defines.h",
- "include/prism/diagnostic.h",
- "include/prism/encoding.h",
- "include/prism/node.h",
- "include/prism/options.h",
- "include/prism/pack.h",
- "include/prism/parser.h",
- "include/prism/prettyprint.h",
- "include/prism/regexp.h",
- "include/prism/static_literals.h",
- "include/prism/util/pm_buffer.h",
- "include/prism/util/pm_char.h",
- "include/prism/util/pm_constant_pool.h",
- "include/prism/util/pm_integer.h",
- "include/prism/util/pm_list.h",
- "include/prism/util/pm_memchr.h",
- "include/prism/util/pm_newline_list.h",
- "include/prism/util/pm_strncasecmp.h",
- "include/prism/util/pm_string.h",
- "include/prism/util/pm_strpbrk.h",
- "include/prism/version.h",
- "lib/prism.rb",
- "lib/prism/compiler.rb",
- "lib/prism/desugar_compiler.rb",
- "lib/prism/dispatcher.rb",
- "lib/prism/dot_visitor.rb",
- "lib/prism/dsl.rb",
- "lib/prism/ffi.rb",
- "lib/prism/inspect_visitor.rb",
- "lib/prism/lex_compat.rb",
- "lib/prism/mutation_compiler.rb",
- "lib/prism/node_ext.rb",
- "lib/prism/node.rb",
- "lib/prism/pack.rb",
- "lib/prism/parse_result.rb",
- "lib/prism/parse_result/comments.rb",
- "lib/prism/parse_result/errors.rb",
- "lib/prism/parse_result/newlines.rb",
- "lib/prism/pattern.rb",
- "lib/prism/polyfill/byteindex.rb",
- "lib/prism/polyfill/unpack1.rb",
- "lib/prism/reflection.rb",
- "lib/prism/serialize.rb",
- "lib/prism/translation.rb",
- "lib/prism/translation/parser.rb",
- "lib/prism/translation/parser33.rb",
- "lib/prism/translation/parser34.rb",
- "lib/prism/translation/parser/compiler.rb",
- "lib/prism/translation/parser/lexer.rb",
- "lib/prism/translation/ripper.rb",
- "lib/prism/translation/ripper/sexp.rb",
- "lib/prism/translation/ripper/shim.rb",
- "lib/prism/translation/ruby_parser.rb",
- "lib/prism/visitor.rb",
- "prism.gemspec",
- "rbi/prism.rbi",
- "rbi/prism/compiler.rbi",
- "rbi/prism/dsl.rbi",
- "rbi/prism/inspect_visitor.rbi",
- "rbi/prism/node_ext.rbi",
- "rbi/prism/node.rbi",
- "rbi/prism/parse_result.rbi",
- "rbi/prism/reflection.rbi",
- "rbi/prism/translation/parser.rbi",
- "rbi/prism/translation/parser33.rbi",
- "rbi/prism/translation/parser34.rbi",
- "rbi/prism/translation/ripper.rbi",
- "rbi/prism/visitor.rbi",
- "sig/prism.rbs",
- "sig/prism/compiler.rbs",
- "sig/prism/dispatcher.rbs",
- "sig/prism/dot_visitor.rbs",
- "sig/prism/dsl.rbs",
- "sig/prism/inspect_visitor.rbs",
- "sig/prism/lex_compat.rbs",
- "sig/prism/mutation_compiler.rbs",
- "sig/prism/node_ext.rbs",
- "sig/prism/node.rbs",
- "sig/prism/pack.rbs",
- "sig/prism/parse_result.rbs",
- "sig/prism/pattern.rbs",
- "sig/prism/reflection.rbs",
- "sig/prism/serialize.rbs",
- "sig/prism/visitor.rbs",
- "src/diagnostic.c",
- "src/encoding.c",
- "src/node.c",
- "src/options.c",
- "src/pack.c",
- "src/prettyprint.c",
- "src/prism.c",
- "src/regexp.c",
- "src/serialize.c",
- "src/static_literals.c",
- "src/token_type.c",
- "src/util/pm_buffer.c",
- "src/util/pm_char.c",
- "src/util/pm_constant_pool.c",
- "src/util/pm_integer.c",
- "src/util/pm_list.c",
- "src/util/pm_memchr.c",
- "src/util/pm_newline_list.c",
- "src/util/pm_string.c",
- "src/util/pm_strncasecmp.c",
- "src/util/pm_strpbrk.c"
- ]
-
- spec.extensions = ["ext/prism/extconf.rb"]
- spec.metadata["allowed_push_host"] = "https://rubygems.org"
- spec.metadata["source_code_uri"] = "https://github.com/ruby/prism"
- spec.metadata["changelog_uri"] = "https://github.com/ruby/prism/blob/main/CHANGELOG.md"
-end
diff --git a/lib/prism/translation.rb b/lib/prism/translation.rb
deleted file mode 100644
index 8b75e8a3ab..0000000000
--- a/lib/prism/translation.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- # This module is responsible for converting the prism syntax tree into other
- # syntax trees.
- module Translation # steep:ignore
- autoload :Parser, "prism/translation/parser"
- autoload :Parser33, "prism/translation/parser33"
- autoload :Parser34, "prism/translation/parser34"
- autoload :Ripper, "prism/translation/ripper"
- autoload :RubyParser, "prism/translation/ruby_parser"
- end
-end
diff --git a/lib/prism/translation/parser.rb b/lib/prism/translation/parser.rb
deleted file mode 100644
index 969f2b95b0..0000000000
--- a/lib/prism/translation/parser.rb
+++ /dev/null
@@ -1,307 +0,0 @@
-# frozen_string_literal: true
-
-begin
- require "parser"
-rescue LoadError
- warn(%q{Error: Unable to load parser. Add `gem "parser"` to your Gemfile.})
- exit(1)
-end
-
-module Prism
- module Translation
- # This class is the entry-point for converting a prism syntax tree into the
- # whitequark/parser gem's syntax tree. It inherits from the base parser for
- # the parser gem, and overrides the parse* methods to parse with prism and
- # then translate.
- class Parser < ::Parser::Base
- Diagnostic = ::Parser::Diagnostic # :nodoc:
- private_constant :Diagnostic
-
- # The parser gem has a list of diagnostics with a hard-coded set of error
- # messages. We create our own diagnostic class in order to set our own
- # error messages.
- class PrismDiagnostic < Diagnostic
- # This is the cached message coming from prism.
- attr_reader :message
-
- # Initialize a new diagnostic with the given message and location.
- def initialize(message, level, reason, location)
- @message = message
- super(level, reason, {}, location, [])
- end
- end
-
- Racc_debug_parser = false # :nodoc:
-
- def version # :nodoc:
- 34
- end
-
- # The default encoding for Ruby files is UTF-8.
- def default_encoding
- Encoding::UTF_8
- end
-
- def yyerror # :nodoc:
- end
-
- # Parses a source buffer and returns the AST.
- def parse(source_buffer)
- @source_buffer = source_buffer
- source = source_buffer.source
-
- offset_cache = build_offset_cache(source)
- result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version), partial_script: true, encoding: false), offset_cache)
-
- build_ast(result.value, offset_cache)
- ensure
- @source_buffer = nil
- end
-
- # Parses a source buffer and returns the AST and the source code comments.
- def parse_with_comments(source_buffer)
- @source_buffer = source_buffer
- source = source_buffer.source
-
- offset_cache = build_offset_cache(source)
- result = unwrap(Prism.parse(source, filepath: source_buffer.name, version: convert_for_prism(version), partial_script: true, encoding: false), offset_cache)
-
- [
- build_ast(result.value, offset_cache),
- build_comments(result.comments, offset_cache)
- ]
- ensure
- @source_buffer = nil
- end
-
- # Parses a source buffer and returns the AST, the source code comments,
- # and the tokens emitted by the lexer.
- def tokenize(source_buffer, recover = false)
- @source_buffer = source_buffer
- source = source_buffer.source
-
- offset_cache = build_offset_cache(source)
- result =
- begin
- unwrap(Prism.parse_lex(source, filepath: source_buffer.name, version: convert_for_prism(version), partial_script: true, encoding: false), offset_cache)
- rescue ::Parser::SyntaxError
- raise if !recover
- end
-
- program, tokens = result.value
- ast = build_ast(program, offset_cache) if result.success?
-
- [
- ast,
- build_comments(result.comments, offset_cache),
- build_tokens(tokens, offset_cache)
- ]
- ensure
- @source_buffer = nil
- end
-
- # Since prism resolves num params for us, we don't need to support this
- # kind of logic here.
- def try_declare_numparam(node)
- node.children[0].match?(/\A_[1-9]\z/)
- end
-
- private
-
- # This is a hook to allow consumers to disable some errors if they don't
- # want them to block creating the syntax tree.
- def valid_error?(error)
- true
- end
-
- # This is a hook to allow consumers to disable some warnings if they don't
- # want them to block creating the syntax tree.
- def valid_warning?(warning)
- true
- end
-
- # Build a diagnostic from the given prism parse error.
- def error_diagnostic(error, offset_cache)
- location = error.location
- diagnostic_location = build_range(location, offset_cache)
-
- case error.type
- when :argument_block_multi
- Diagnostic.new(:error, :block_and_blockarg, {}, diagnostic_location, [])
- when :argument_formal_constant
- Diagnostic.new(:error, :argument_const, {}, diagnostic_location, [])
- when :argument_formal_class
- Diagnostic.new(:error, :argument_cvar, {}, diagnostic_location, [])
- when :argument_formal_global
- Diagnostic.new(:error, :argument_gvar, {}, diagnostic_location, [])
- when :argument_formal_ivar
- Diagnostic.new(:error, :argument_ivar, {}, diagnostic_location, [])
- when :argument_no_forwarding_amp
- Diagnostic.new(:error, :no_anonymous_blockarg, {}, diagnostic_location, [])
- when :argument_no_forwarding_star
- Diagnostic.new(:error, :no_anonymous_restarg, {}, diagnostic_location, [])
- when :argument_no_forwarding_star_star
- Diagnostic.new(:error, :no_anonymous_kwrestarg, {}, diagnostic_location, [])
- when :begin_lonely_else
- location = location.copy(length: 4)
- diagnostic_location = build_range(location, offset_cache)
- Diagnostic.new(:error, :useless_else, {}, diagnostic_location, [])
- when :class_name, :module_name
- Diagnostic.new(:error, :module_name_const, {}, diagnostic_location, [])
- when :class_in_method
- Diagnostic.new(:error, :class_in_def, {}, diagnostic_location, [])
- when :def_endless_setter
- Diagnostic.new(:error, :endless_setter, {}, diagnostic_location, [])
- when :embdoc_term
- Diagnostic.new(:error, :embedded_document, {}, diagnostic_location, [])
- when :incomplete_variable_class, :incomplete_variable_class_3_3
- location = location.copy(length: location.length + 1)
- diagnostic_location = build_range(location, offset_cache)
-
- Diagnostic.new(:error, :cvar_name, { name: location.slice }, diagnostic_location, [])
- when :incomplete_variable_instance, :incomplete_variable_instance_3_3
- location = location.copy(length: location.length + 1)
- diagnostic_location = build_range(location, offset_cache)
-
- Diagnostic.new(:error, :ivar_name, { name: location.slice }, diagnostic_location, [])
- when :invalid_variable_global, :invalid_variable_global_3_3
- Diagnostic.new(:error, :gvar_name, { name: location.slice }, diagnostic_location, [])
- when :module_in_method
- Diagnostic.new(:error, :module_in_def, {}, diagnostic_location, [])
- when :numbered_parameter_ordinary
- Diagnostic.new(:error, :ordinary_param_defined, {}, diagnostic_location, [])
- when :numbered_parameter_outer_scope
- Diagnostic.new(:error, :numparam_used_in_outer_scope, {}, diagnostic_location, [])
- when :parameter_circular
- Diagnostic.new(:error, :circular_argument_reference, { var_name: location.slice }, diagnostic_location, [])
- when :parameter_name_repeat
- Diagnostic.new(:error, :duplicate_argument, {}, diagnostic_location, [])
- when :parameter_numbered_reserved
- Diagnostic.new(:error, :reserved_for_numparam, { name: location.slice }, diagnostic_location, [])
- when :regexp_unknown_options
- Diagnostic.new(:error, :regexp_options, { options: location.slice[1..] }, diagnostic_location, [])
- when :singleton_for_literals
- Diagnostic.new(:error, :singleton_literal, {}, diagnostic_location, [])
- when :string_literal_eof
- Diagnostic.new(:error, :string_eof, {}, diagnostic_location, [])
- when :unexpected_token_ignore
- Diagnostic.new(:error, :unexpected_token, { token: location.slice }, diagnostic_location, [])
- when :write_target_in_method
- Diagnostic.new(:error, :dynamic_const, {}, diagnostic_location, [])
- else
- PrismDiagnostic.new(error.message, :error, error.type, diagnostic_location)
- end
- end
-
- # Build a diagnostic from the given prism parse warning.
- def warning_diagnostic(warning, offset_cache)
- diagnostic_location = build_range(warning.location, offset_cache)
-
- case warning.type
- when :ambiguous_first_argument_plus
- Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "+" }, diagnostic_location, [])
- when :ambiguous_first_argument_minus
- Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "-" }, diagnostic_location, [])
- when :ambiguous_prefix_ampersand
- Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "&" }, diagnostic_location, [])
- when :ambiguous_prefix_star
- Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "*" }, diagnostic_location, [])
- when :ambiguous_prefix_star_star
- Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "**" }, diagnostic_location, [])
- when :ambiguous_slash
- Diagnostic.new(:warning, :ambiguous_regexp, {}, diagnostic_location, [])
- when :dot_dot_dot_eol
- Diagnostic.new(:warning, :triple_dot_at_eol, {}, diagnostic_location, [])
- when :duplicated_hash_key
- # skip, parser does this on its own
- else
- PrismDiagnostic.new(warning.message, :warning, warning.type, diagnostic_location)
- end
- end
-
- # If there was a error generated during the parse, then raise an
- # appropriate syntax error. Otherwise return the result.
- def unwrap(result, offset_cache)
- result.errors.each do |error|
- next unless valid_error?(error)
- diagnostics.process(error_diagnostic(error, offset_cache))
- end
-
- result.warnings.each do |warning|
- next unless valid_warning?(warning)
- diagnostic = warning_diagnostic(warning, offset_cache)
- diagnostics.process(diagnostic) if diagnostic
- end
-
- result
- end
-
- # Prism deals with offsets in bytes, while the parser gem deals with
- # offsets in characters. We need to handle this conversion in order to
- # build the parser gem AST.
- #
- # If the bytesize of the source is the same as the length, then we can
- # just use the offset directly. Otherwise, we build an array where the
- # index is the byte offset and the value is the character offset.
- def build_offset_cache(source)
- if source.bytesize == source.length
- -> (offset) { offset }
- else
- offset_cache = []
- offset = 0
-
- source.each_char do |char|
- char.bytesize.times { offset_cache << offset }
- offset += 1
- end
-
- offset_cache << offset
- end
- end
-
- # Build the parser gem AST from the prism AST.
- def build_ast(program, offset_cache)
- program.accept(Compiler.new(self, offset_cache))
- end
-
- # Build the parser gem comments from the prism comments.
- def build_comments(comments, offset_cache)
- comments.map do |comment|
- ::Parser::Source::Comment.new(build_range(comment.location, offset_cache))
- end
- end
-
- # Build the parser gem tokens from the prism tokens.
- def build_tokens(tokens, offset_cache)
- Lexer.new(source_buffer, tokens, offset_cache).to_a
- end
-
- # Build a range from a prism location.
- def build_range(location, offset_cache)
- ::Parser::Source::Range.new(
- source_buffer,
- offset_cache[location.start_offset],
- offset_cache[location.end_offset]
- )
- end
-
- # Converts the version format handled by Parser to the format handled by Prism.
- def convert_for_prism(version)
- case version
- when 33
- "3.3.1"
- when 34
- "3.4.0"
- else
- "latest"
- end
- end
-
- require_relative "parser/compiler"
- require_relative "parser/lexer"
-
- private_constant :Compiler
- private_constant :Lexer
- end
- end
-end
diff --git a/lib/prism/translation/parser/compiler.rb b/lib/prism/translation/parser/compiler.rb
deleted file mode 100644
index d57b5757d7..0000000000
--- a/lib/prism/translation/parser/compiler.rb
+++ /dev/null
@@ -1,2146 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- module Translation
- class Parser
- # A visitor that knows how to convert a prism syntax tree into the
- # whitequark/parser gem's syntax tree.
- class Compiler < ::Prism::Compiler
- # Raised when the tree is malformed or there is a bug in the compiler.
- class CompilationError < StandardError
- end
-
- # The Parser::Base instance that is being used to build the AST.
- attr_reader :parser
-
- # The Parser::Builders::Default instance that is being used to build the
- # AST.
- attr_reader :builder
-
- # The Parser::Source::Buffer instance that is holding a reference to the
- # source code.
- attr_reader :source_buffer
-
- # The offset cache that is used to map between byte and character
- # offsets in the file.
- attr_reader :offset_cache
-
- # The types of values that can be forwarded in the current scope.
- attr_reader :forwarding
-
- # Whether or not the current node is in a destructure.
- attr_reader :in_destructure
-
- # Whether or not the current node is in a pattern.
- attr_reader :in_pattern
-
- # Initialize a new compiler with the given parser, offset cache, and
- # options.
- def initialize(parser, offset_cache, forwarding: [], in_destructure: false, in_pattern: false)
- @parser = parser
- @builder = parser.builder
- @source_buffer = parser.source_buffer
- @offset_cache = offset_cache
-
- @forwarding = forwarding
- @in_destructure = in_destructure
- @in_pattern = in_pattern
- end
-
- # alias foo bar
- # ^^^^^^^^^^^^^
- def visit_alias_method_node(node)
- builder.alias(token(node.keyword_loc), visit(node.new_name), visit(node.old_name))
- end
-
- # alias $foo $bar
- # ^^^^^^^^^^^^^^^
- def visit_alias_global_variable_node(node)
- builder.alias(token(node.keyword_loc), visit(node.new_name), visit(node.old_name))
- end
-
- # foo => bar | baz
- # ^^^^^^^^^
- def visit_alternation_pattern_node(node)
- builder.match_alt(visit(node.left), token(node.operator_loc), visit(node.right))
- end
-
- # a and b
- # ^^^^^^^
- def visit_and_node(node)
- builder.logical_op(:and, visit(node.left), token(node.operator_loc), visit(node.right))
- end
-
- # []
- # ^^
- def visit_array_node(node)
- builder.array(token(node.opening_loc), visit_all(node.elements), token(node.closing_loc))
- end
-
- # foo => [bar]
- # ^^^^^
- def visit_array_pattern_node(node)
- elements = [*node.requireds]
- elements << node.rest if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode)
- elements.concat(node.posts)
- visited = visit_all(elements)
-
- if node.rest.is_a?(ImplicitRestNode)
- visited[-1] = builder.match_with_trailing_comma(visited[-1], token(node.rest.location))
- end
-
- if node.constant
- if visited.empty?
- builder.const_pattern(visit(node.constant), token(node.opening_loc), builder.array_pattern(token(node.opening_loc), visited, token(node.closing_loc)), token(node.closing_loc))
- else
- builder.const_pattern(visit(node.constant), token(node.opening_loc), builder.array_pattern(nil, visited, nil), token(node.closing_loc))
- end
- else
- builder.array_pattern(token(node.opening_loc), visited, token(node.closing_loc))
- end
- end
-
- # foo(bar)
- # ^^^
- def visit_arguments_node(node)
- visit_all(node.arguments)
- end
-
- # { a: 1 }
- # ^^^^
- def visit_assoc_node(node)
- key = node.key
-
- if in_pattern
- if node.value.is_a?(ImplicitNode)
- if key.is_a?(SymbolNode)
- if key.opening.nil?
- builder.match_hash_var([key.unescaped, srange(key.location)])
- else
- builder.match_hash_var_from_str(token(key.opening_loc), [builder.string_internal([key.unescaped, srange(key.value_loc)])], token(key.closing_loc))
- end
- else
- builder.match_hash_var_from_str(token(key.opening_loc), visit_all(key.parts), token(key.closing_loc))
- end
- elsif key.opening.nil?
- builder.pair_keyword([key.unescaped, srange(key.location)], visit(node.value))
- else
- builder.pair_quoted(token(key.opening_loc), [builder.string_internal([key.unescaped, srange(key.value_loc)])], token(key.closing_loc), visit(node.value))
- end
- elsif node.value.is_a?(ImplicitNode)
- if (value = node.value.value).is_a?(LocalVariableReadNode)
- builder.pair_keyword(
- [key.unescaped, srange(key)],
- builder.ident([value.name, srange(key.value_loc)]).updated(:lvar)
- )
- else
- builder.pair_label([key.unescaped, srange(key.location)])
- end
- elsif node.operator_loc
- builder.pair(visit(key), token(node.operator_loc), visit(node.value))
- elsif key.is_a?(SymbolNode) && key.opening_loc.nil?
- builder.pair_keyword([key.unescaped, srange(key.location)], visit(node.value))
- else
- parts =
- if key.is_a?(SymbolNode)
- [builder.string_internal([key.unescaped, srange(key.value_loc)])]
- else
- visit_all(key.parts)
- end
-
- builder.pair_quoted(token(key.opening_loc), parts, token(key.closing_loc), visit(node.value))
- end
- end
-
- # def foo(**); bar(**); end
- # ^^
- #
- # { **foo }
- # ^^^^^
- def visit_assoc_splat_node(node)
- if in_pattern
- builder.match_rest(token(node.operator_loc), token(node.value&.location))
- elsif node.value.nil? && forwarding.include?(:**)
- builder.forwarded_kwrestarg(token(node.operator_loc))
- else
- builder.kwsplat(token(node.operator_loc), visit(node.value))
- end
- end
-
- # $+
- # ^^
- def visit_back_reference_read_node(node)
- builder.back_ref(token(node.location))
- end
-
- # begin end
- # ^^^^^^^^^
- def visit_begin_node(node)
- rescue_bodies = []
-
- if (rescue_clause = node.rescue_clause)
- begin
- find_start_offset = (rescue_clause.reference&.location || rescue_clause.exceptions.last&.location || rescue_clause.keyword_loc).end_offset
- find_end_offset = (rescue_clause.statements&.location&.start_offset || rescue_clause.subsequent&.location&.start_offset || (find_start_offset + 1))
-
- rescue_bodies << builder.rescue_body(
- token(rescue_clause.keyword_loc),
- rescue_clause.exceptions.any? ? builder.array(nil, visit_all(rescue_clause.exceptions), nil) : nil,
- token(rescue_clause.operator_loc),
- visit(rescue_clause.reference),
- srange_find(find_start_offset, find_end_offset, [";"]),
- visit(rescue_clause.statements)
- )
- end until (rescue_clause = rescue_clause.subsequent).nil?
- end
-
- begin_body =
- builder.begin_body(
- visit(node.statements),
- rescue_bodies,
- token(node.else_clause&.else_keyword_loc),
- visit(node.else_clause),
- token(node.ensure_clause&.ensure_keyword_loc),
- visit(node.ensure_clause&.statements)
- )
-
- if node.begin_keyword_loc
- builder.begin_keyword(token(node.begin_keyword_loc), begin_body, token(node.end_keyword_loc))
- else
- begin_body
- end
- end
-
- # foo(&bar)
- # ^^^^
- def visit_block_argument_node(node)
- builder.block_pass(token(node.operator_loc), visit(node.expression))
- end
-
- # foo { |; bar| }
- # ^^^
- def visit_block_local_variable_node(node)
- builder.shadowarg(token(node.location))
- end
-
- # A block on a keyword or method call.
- def visit_block_node(node)
- raise CompilationError, "Cannot directly compile block nodes"
- end
-
- # def foo(&bar); end
- # ^^^^
- def visit_block_parameter_node(node)
- builder.blockarg(token(node.operator_loc), token(node.name_loc))
- end
-
- # A block's parameters.
- def visit_block_parameters_node(node)
- [*visit(node.parameters)].concat(visit_all(node.locals))
- end
-
- # break
- # ^^^^^
- #
- # break foo
- # ^^^^^^^^^
- def visit_break_node(node)
- builder.keyword_cmd(:break, token(node.keyword_loc), nil, visit(node.arguments) || [], nil)
- end
-
- # foo
- # ^^^
- #
- # foo.bar
- # ^^^^^^^
- #
- # foo.bar() {}
- # ^^^^^^^^^^^^
- def visit_call_node(node)
- name = node.name
- arguments = node.arguments&.arguments || []
- block = node.block
-
- if block.is_a?(BlockArgumentNode)
- arguments = [*arguments, block]
- block = nil
- end
-
- if node.call_operator_loc.nil?
- case name
- when :-@
- case (receiver = node.receiver).type
- when :integer_node, :float_node, :rational_node, :imaginary_node
- return visit(numeric_negate(node.message_loc, receiver))
- end
- when :!
- return visit_block(builder.not_op(token(node.message_loc), token(node.opening_loc), visit(node.receiver), token(node.closing_loc)), block)
- when :=~
- if (receiver = node.receiver).is_a?(RegularExpressionNode)
- return builder.match_op(visit(receiver), token(node.message_loc), visit(node.arguments.arguments.first))
- end
- when :[]
- return visit_block(builder.index(visit(node.receiver), token(node.opening_loc), visit_all(arguments), token(node.closing_loc)), block)
- when :[]=
- if node.message != "[]=" && node.arguments && block.nil? && !node.safe_navigation?
- arguments = node.arguments.arguments[...-1]
- arguments << node.block if node.block
-
- return visit_block(
- builder.assign(
- builder.index_asgn(
- visit(node.receiver),
- token(node.opening_loc),
- visit_all(arguments),
- token(node.closing_loc),
- ),
- srange_find(node.message_loc.end_offset, node.arguments.arguments.last.location.start_offset, ["="]),
- visit(node.arguments.arguments.last)
- ),
- block
- )
- end
- end
- end
-
- message_loc = node.message_loc
- call_operator_loc = node.call_operator_loc
- call_operator = [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)] if call_operator_loc
-
- visit_block(
- if name.end_with?("=") && !message_loc.slice.end_with?("=") && node.arguments && block.nil?
- builder.assign(
- builder.attr_asgn(visit(node.receiver), call_operator, token(message_loc)),
- srange_find(message_loc.end_offset, node.arguments.location.start_offset, ["="]),
- visit(node.arguments.arguments.last)
- )
- else
- builder.call_method(
- visit(node.receiver),
- call_operator,
- message_loc ? [node.name, srange(message_loc)] : nil,
- token(node.opening_loc),
- visit_all(arguments),
- token(node.closing_loc)
- )
- end,
- block
- )
- end
-
- # foo.bar += baz
- # ^^^^^^^^^^^^^^^
- def visit_call_operator_write_node(node)
- call_operator_loc = node.call_operator_loc
-
- builder.op_assign(
- builder.call_method(
- visit(node.receiver),
- call_operator_loc.nil? ? nil : [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)],
- node.message_loc ? [node.read_name, srange(node.message_loc)] : nil,
- nil,
- [],
- nil
- ),
- [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
- visit(node.value)
- )
- end
-
- # foo.bar &&= baz
- # ^^^^^^^^^^^^^^^
- def visit_call_and_write_node(node)
- call_operator_loc = node.call_operator_loc
-
- builder.op_assign(
- builder.call_method(
- visit(node.receiver),
- call_operator_loc.nil? ? nil : [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)],
- node.message_loc ? [node.read_name, srange(node.message_loc)] : nil,
- nil,
- [],
- nil
- ),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # foo.bar ||= baz
- # ^^^^^^^^^^^^^^^
- def visit_call_or_write_node(node)
- call_operator_loc = node.call_operator_loc
-
- builder.op_assign(
- builder.call_method(
- visit(node.receiver),
- call_operator_loc.nil? ? nil : [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)],
- node.message_loc ? [node.read_name, srange(node.message_loc)] : nil,
- nil,
- [],
- nil
- ),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # foo.bar, = 1
- # ^^^^^^^
- def visit_call_target_node(node)
- call_operator_loc = node.call_operator_loc
-
- builder.attr_asgn(
- visit(node.receiver),
- call_operator_loc.nil? ? nil : [{ "." => :dot, "&." => :anddot, "::" => "::" }.fetch(call_operator_loc.slice), srange(call_operator_loc)],
- token(node.message_loc)
- )
- end
-
- # foo => bar => baz
- # ^^^^^^^^^^
- def visit_capture_pattern_node(node)
- builder.match_as(visit(node.value), token(node.operator_loc), visit(node.target))
- end
-
- # case foo; when bar; end
- # ^^^^^^^^^^^^^^^^^^^^^^^
- def visit_case_node(node)
- builder.case(
- token(node.case_keyword_loc),
- visit(node.predicate),
- visit_all(node.conditions),
- token(node.else_clause&.else_keyword_loc),
- visit(node.else_clause),
- token(node.end_keyword_loc)
- )
- end
-
- # case foo; in bar; end
- # ^^^^^^^^^^^^^^^^^^^^^
- def visit_case_match_node(node)
- builder.case_match(
- token(node.case_keyword_loc),
- visit(node.predicate),
- visit_all(node.conditions),
- token(node.else_clause&.else_keyword_loc),
- visit(node.else_clause),
- token(node.end_keyword_loc)
- )
- end
-
- # class Foo; end
- # ^^^^^^^^^^^^^^
- def visit_class_node(node)
- builder.def_class(
- token(node.class_keyword_loc),
- visit(node.constant_path),
- token(node.inheritance_operator_loc),
- visit(node.superclass),
- node.body&.accept(copy_compiler(forwarding: [])),
- token(node.end_keyword_loc)
- )
- end
-
- # @@foo
- # ^^^^^
- def visit_class_variable_read_node(node)
- builder.cvar(token(node.location))
- end
-
- # @@foo = 1
- # ^^^^^^^^^
- def visit_class_variable_write_node(node)
- builder.assign(
- builder.assignable(builder.cvar(token(node.name_loc))),
- token(node.operator_loc),
- visit(node.value)
- )
- end
-
- # @@foo += bar
- # ^^^^^^^^^^^^
- def visit_class_variable_operator_write_node(node)
- builder.op_assign(
- builder.assignable(builder.cvar(token(node.name_loc))),
- [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
- visit(node.value)
- )
- end
-
- # @@foo &&= bar
- # ^^^^^^^^^^^^^
- def visit_class_variable_and_write_node(node)
- builder.op_assign(
- builder.assignable(builder.cvar(token(node.name_loc))),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # @@foo ||= bar
- # ^^^^^^^^^^^^^
- def visit_class_variable_or_write_node(node)
- builder.op_assign(
- builder.assignable(builder.cvar(token(node.name_loc))),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # @@foo, = bar
- # ^^^^^
- def visit_class_variable_target_node(node)
- builder.assignable(builder.cvar(token(node.location)))
- end
-
- # Foo
- # ^^^
- def visit_constant_read_node(node)
- builder.const([node.name, srange(node.location)])
- end
-
- # Foo = 1
- # ^^^^^^^
- #
- # Foo, Bar = 1
- # ^^^ ^^^
- def visit_constant_write_node(node)
- builder.assign(builder.assignable(builder.const([node.name, srange(node.name_loc)])), token(node.operator_loc), visit(node.value))
- end
-
- # Foo += bar
- # ^^^^^^^^^^^
- def visit_constant_operator_write_node(node)
- builder.op_assign(
- builder.assignable(builder.const([node.name, srange(node.name_loc)])),
- [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
- visit(node.value)
- )
- end
-
- # Foo &&= bar
- # ^^^^^^^^^^^^
- def visit_constant_and_write_node(node)
- builder.op_assign(
- builder.assignable(builder.const([node.name, srange(node.name_loc)])),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # Foo ||= bar
- # ^^^^^^^^^^^^
- def visit_constant_or_write_node(node)
- builder.op_assign(
- builder.assignable(builder.const([node.name, srange(node.name_loc)])),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # Foo, = bar
- # ^^^
- def visit_constant_target_node(node)
- builder.assignable(builder.const([node.name, srange(node.location)]))
- end
-
- # Foo::Bar
- # ^^^^^^^^
- def visit_constant_path_node(node)
- if node.parent.nil?
- builder.const_global(
- token(node.delimiter_loc),
- [node.name, srange(node.name_loc)]
- )
- else
- builder.const_fetch(
- visit(node.parent),
- token(node.delimiter_loc),
- [node.name, srange(node.name_loc)]
- )
- end
- end
-
- # Foo::Bar = 1
- # ^^^^^^^^^^^^
- #
- # Foo::Foo, Bar::Bar = 1
- # ^^^^^^^^ ^^^^^^^^
- def visit_constant_path_write_node(node)
- builder.assign(
- builder.assignable(visit(node.target)),
- token(node.operator_loc),
- visit(node.value)
- )
- end
-
- # Foo::Bar += baz
- # ^^^^^^^^^^^^^^^
- def visit_constant_path_operator_write_node(node)
- builder.op_assign(
- builder.assignable(visit(node.target)),
- [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
- visit(node.value)
- )
- end
-
- # Foo::Bar &&= baz
- # ^^^^^^^^^^^^^^^^
- def visit_constant_path_and_write_node(node)
- builder.op_assign(
- builder.assignable(visit(node.target)),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # Foo::Bar ||= baz
- # ^^^^^^^^^^^^^^^^
- def visit_constant_path_or_write_node(node)
- builder.op_assign(
- builder.assignable(visit(node.target)),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # Foo::Bar, = baz
- # ^^^^^^^^
- def visit_constant_path_target_node(node)
- builder.assignable(visit_constant_path_node(node))
- end
-
- # def foo; end
- # ^^^^^^^^^^^^
- #
- # def self.foo; end
- # ^^^^^^^^^^^^^^^^^
- def visit_def_node(node)
- if node.equal_loc
- if node.receiver
- builder.def_endless_singleton(
- token(node.def_keyword_loc),
- visit(node.receiver.is_a?(ParenthesesNode) ? node.receiver.body : node.receiver),
- token(node.operator_loc),
- token(node.name_loc),
- builder.args(token(node.lparen_loc), visit(node.parameters) || [], token(node.rparen_loc), false),
- token(node.equal_loc),
- node.body&.accept(copy_compiler(forwarding: find_forwarding(node.parameters)))
- )
- else
- builder.def_endless_method(
- token(node.def_keyword_loc),
- token(node.name_loc),
- builder.args(token(node.lparen_loc), visit(node.parameters) || [], token(node.rparen_loc), false),
- token(node.equal_loc),
- node.body&.accept(copy_compiler(forwarding: find_forwarding(node.parameters)))
- )
- end
- elsif node.receiver
- builder.def_singleton(
- token(node.def_keyword_loc),
- visit(node.receiver.is_a?(ParenthesesNode) ? node.receiver.body : node.receiver),
- token(node.operator_loc),
- token(node.name_loc),
- builder.args(token(node.lparen_loc), visit(node.parameters) || [], token(node.rparen_loc), false),
- node.body&.accept(copy_compiler(forwarding: find_forwarding(node.parameters))),
- token(node.end_keyword_loc)
- )
- else
- builder.def_method(
- token(node.def_keyword_loc),
- token(node.name_loc),
- builder.args(token(node.lparen_loc), visit(node.parameters) || [], token(node.rparen_loc), false),
- node.body&.accept(copy_compiler(forwarding: find_forwarding(node.parameters))),
- token(node.end_keyword_loc)
- )
- end
- end
-
- # defined? a
- # ^^^^^^^^^^
- #
- # defined?(a)
- # ^^^^^^^^^^^
- def visit_defined_node(node)
- builder.keyword_cmd(
- :defined?,
- token(node.keyword_loc),
- token(node.lparen_loc),
- [visit(node.value)],
- token(node.rparen_loc)
- )
- end
-
- # if foo then bar else baz end
- # ^^^^^^^^^^^^
- def visit_else_node(node)
- visit(node.statements)
- end
-
- # "foo #{bar}"
- # ^^^^^^
- def visit_embedded_statements_node(node)
- builder.begin(
- token(node.opening_loc),
- visit(node.statements),
- token(node.closing_loc)
- )
- end
-
- # "foo #@bar"
- # ^^^^^
- def visit_embedded_variable_node(node)
- visit(node.variable)
- end
-
- # begin; foo; ensure; bar; end
- # ^^^^^^^^^^^^
- def visit_ensure_node(node)
- raise CompilationError, "Cannot directly compile ensure nodes"
- end
-
- # false
- # ^^^^^
- def visit_false_node(node)
- builder.false(token(node.location))
- end
-
- # foo => [*, bar, *]
- # ^^^^^^^^^^^
- def visit_find_pattern_node(node)
- elements = [node.left, *node.requireds, node.right]
-
- if node.constant
- builder.const_pattern(visit(node.constant), token(node.opening_loc), builder.find_pattern(nil, visit_all(elements), nil), token(node.closing_loc))
- else
- builder.find_pattern(token(node.opening_loc), visit_all(elements), token(node.closing_loc))
- end
- end
-
- # 1.0
- # ^^^
- def visit_float_node(node)
- visit_numeric(node, builder.float([node.value, srange(node.location)]))
- end
-
- # for foo in bar do end
- # ^^^^^^^^^^^^^^^^^^^^^
- def visit_for_node(node)
- builder.for(
- token(node.for_keyword_loc),
- visit(node.index),
- token(node.in_keyword_loc),
- visit(node.collection),
- if node.do_keyword_loc
- token(node.do_keyword_loc)
- else
- srange_find(node.collection.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset, [";"])
- end,
- visit(node.statements),
- token(node.end_keyword_loc)
- )
- end
-
- # def foo(...); bar(...); end
- # ^^^
- def visit_forwarding_arguments_node(node)
- builder.forwarded_args(token(node.location))
- end
-
- # def foo(...); end
- # ^^^
- def visit_forwarding_parameter_node(node)
- builder.forward_arg(token(node.location))
- end
-
- # super
- # ^^^^^
- #
- # super {}
- # ^^^^^^^^
- def visit_forwarding_super_node(node)
- visit_block(
- builder.keyword_cmd(
- :zsuper,
- ["super", srange_offsets(node.location.start_offset, node.location.start_offset + 5)]
- ),
- node.block
- )
- end
-
- # $foo
- # ^^^^
- def visit_global_variable_read_node(node)
- builder.gvar(token(node.location))
- end
-
- # $foo = 1
- # ^^^^^^^^
- def visit_global_variable_write_node(node)
- builder.assign(
- builder.assignable(builder.gvar(token(node.name_loc))),
- token(node.operator_loc),
- visit(node.value)
- )
- end
-
- # $foo += bar
- # ^^^^^^^^^^^
- def visit_global_variable_operator_write_node(node)
- builder.op_assign(
- builder.assignable(builder.gvar(token(node.name_loc))),
- [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
- visit(node.value)
- )
- end
-
- # $foo &&= bar
- # ^^^^^^^^^^^^
- def visit_global_variable_and_write_node(node)
- builder.op_assign(
- builder.assignable(builder.gvar(token(node.name_loc))),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # $foo ||= bar
- # ^^^^^^^^^^^^
- def visit_global_variable_or_write_node(node)
- builder.op_assign(
- builder.assignable(builder.gvar(token(node.name_loc))),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # $foo, = bar
- # ^^^^
- def visit_global_variable_target_node(node)
- builder.assignable(builder.gvar([node.slice, srange(node.location)]))
- end
-
- # {}
- # ^^
- def visit_hash_node(node)
- builder.associate(
- token(node.opening_loc),
- visit_all(node.elements),
- token(node.closing_loc)
- )
- end
-
- # foo => {}
- # ^^
- def visit_hash_pattern_node(node)
- elements = [*node.elements, *node.rest]
-
- if node.constant
- builder.const_pattern(visit(node.constant), token(node.opening_loc), builder.hash_pattern(nil, visit_all(elements), nil), token(node.closing_loc))
- else
- builder.hash_pattern(token(node.opening_loc), visit_all(elements), token(node.closing_loc))
- end
- end
-
- # if foo then bar end
- # ^^^^^^^^^^^^^^^^^^^
- #
- # bar if foo
- # ^^^^^^^^^^
- #
- # foo ? bar : baz
- # ^^^^^^^^^^^^^^^
- def visit_if_node(node)
- if !node.if_keyword_loc
- builder.ternary(
- visit(node.predicate),
- token(node.then_keyword_loc),
- visit(node.statements),
- token(node.subsequent.else_keyword_loc),
- visit(node.subsequent)
- )
- elsif node.if_keyword_loc.start_offset == node.location.start_offset
- builder.condition(
- token(node.if_keyword_loc),
- visit(node.predicate),
- if node.then_keyword_loc
- token(node.then_keyword_loc)
- else
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.subsequent&.location || node.end_keyword_loc).start_offset, [";"])
- end,
- visit(node.statements),
- case node.subsequent
- when IfNode
- token(node.subsequent.if_keyword_loc)
- when ElseNode
- token(node.subsequent.else_keyword_loc)
- end,
- visit(node.subsequent),
- if node.if_keyword != "elsif"
- token(node.end_keyword_loc)
- end
- )
- else
- builder.condition_mod(
- visit(node.statements),
- visit(node.subsequent),
- token(node.if_keyword_loc),
- visit(node.predicate)
- )
- end
- end
-
- # 1i
- # ^^
- def visit_imaginary_node(node)
- visit_numeric(node, builder.complex([Complex(0, node.numeric.value), srange(node.location)]))
- end
-
- # { foo: }
- # ^^^^
- def visit_implicit_node(node)
- raise CompilationError, "Cannot directly compile implicit nodes"
- end
-
- # foo { |bar,| }
- # ^
- def visit_implicit_rest_node(node)
- raise CompilationError, "Cannot compile implicit rest nodes"
- end
-
- # case foo; in bar; end
- # ^^^^^^^^^^^^^^^^^^^^^
- def visit_in_node(node)
- pattern = nil
- guard = nil
-
- case node.pattern
- when IfNode
- pattern = within_pattern { |compiler| node.pattern.statements.accept(compiler) }
- guard = builder.if_guard(token(node.pattern.if_keyword_loc), visit(node.pattern.predicate))
- when UnlessNode
- pattern = within_pattern { |compiler| node.pattern.statements.accept(compiler) }
- guard = builder.unless_guard(token(node.pattern.keyword_loc), visit(node.pattern.predicate))
- else
- pattern = within_pattern { |compiler| node.pattern.accept(compiler) }
- end
-
- builder.in_pattern(
- token(node.in_loc),
- pattern,
- guard,
- srange_find(node.pattern.location.end_offset, node.statements&.location&.start_offset, [";", "then"]),
- visit(node.statements)
- )
- end
-
- # foo[bar] += baz
- # ^^^^^^^^^^^^^^^
- def visit_index_operator_write_node(node)
- arguments = node.arguments&.arguments || []
- arguments << node.block if node.block
-
- builder.op_assign(
- builder.index(
- visit(node.receiver),
- token(node.opening_loc),
- visit_all(arguments),
- token(node.closing_loc)
- ),
- [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
- visit(node.value)
- )
- end
-
- # foo[bar] &&= baz
- # ^^^^^^^^^^^^^^^^
- def visit_index_and_write_node(node)
- arguments = node.arguments&.arguments || []
- arguments << node.block if node.block
-
- builder.op_assign(
- builder.index(
- visit(node.receiver),
- token(node.opening_loc),
- visit_all(arguments),
- token(node.closing_loc)
- ),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # foo[bar] ||= baz
- # ^^^^^^^^^^^^^^^^
- def visit_index_or_write_node(node)
- arguments = node.arguments&.arguments || []
- arguments << node.block if node.block
-
- builder.op_assign(
- builder.index(
- visit(node.receiver),
- token(node.opening_loc),
- visit_all(arguments),
- token(node.closing_loc)
- ),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # foo[bar], = 1
- # ^^^^^^^^
- def visit_index_target_node(node)
- builder.index_asgn(
- visit(node.receiver),
- token(node.opening_loc),
- visit_all(node.arguments.arguments),
- token(node.closing_loc),
- )
- end
-
- # @foo
- # ^^^^
- def visit_instance_variable_read_node(node)
- builder.ivar(token(node.location))
- end
-
- # @foo = 1
- # ^^^^^^^^
- def visit_instance_variable_write_node(node)
- builder.assign(
- builder.assignable(builder.ivar(token(node.name_loc))),
- token(node.operator_loc),
- visit(node.value)
- )
- end
-
- # @foo += bar
- # ^^^^^^^^^^^
- def visit_instance_variable_operator_write_node(node)
- builder.op_assign(
- builder.assignable(builder.ivar(token(node.name_loc))),
- [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
- visit(node.value)
- )
- end
-
- # @foo &&= bar
- # ^^^^^^^^^^^^
- def visit_instance_variable_and_write_node(node)
- builder.op_assign(
- builder.assignable(builder.ivar(token(node.name_loc))),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # @foo ||= bar
- # ^^^^^^^^^^^^
- def visit_instance_variable_or_write_node(node)
- builder.op_assign(
- builder.assignable(builder.ivar(token(node.name_loc))),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # @foo, = bar
- # ^^^^
- def visit_instance_variable_target_node(node)
- builder.assignable(builder.ivar(token(node.location)))
- end
-
- # 1
- # ^
- def visit_integer_node(node)
- visit_numeric(node, builder.integer([node.value, srange(node.location)]))
- end
-
- # /foo #{bar}/
- # ^^^^^^^^^^^^
- def visit_interpolated_regular_expression_node(node)
- builder.regexp_compose(
- token(node.opening_loc),
- visit_all(node.parts),
- [node.closing[0], srange_offsets(node.closing_loc.start_offset, node.closing_loc.start_offset + 1)],
- builder.regexp_options([node.closing[1..], srange_offsets(node.closing_loc.start_offset + 1, node.closing_loc.end_offset)])
- )
- end
-
- # if /foo #{bar}/ then end
- # ^^^^^^^^^^^^
- alias visit_interpolated_match_last_line_node visit_interpolated_regular_expression_node
-
- # "foo #{bar}"
- # ^^^^^^^^^^^^
- def visit_interpolated_string_node(node)
- if node.heredoc?
- return visit_heredoc(node) { |children, closing| builder.string_compose(token(node.opening_loc), children, closing) }
- end
-
- parts = if node.parts.one? { |part| part.type == :string_node }
- node.parts.flat_map do |node|
- if node.type == :string_node && node.unescaped.lines.count >= 2
- start_offset = node.content_loc.start_offset
-
- node.unescaped.lines.map do |line|
- end_offset = start_offset + line.length
- offsets = srange_offsets(start_offset, end_offset)
- start_offset = end_offset
-
- builder.string_internal([line, offsets])
- end
- else
- visit(node)
- end
- end
- else
- visit_all(node.parts)
- end
-
- builder.string_compose(
- token(node.opening_loc),
- parts,
- token(node.closing_loc)
- )
- end
-
- # :"foo #{bar}"
- # ^^^^^^^^^^^^^
- def visit_interpolated_symbol_node(node)
- builder.symbol_compose(
- token(node.opening_loc),
- visit_all(node.parts),
- token(node.closing_loc)
- )
- end
-
- # `foo #{bar}`
- # ^^^^^^^^^^^^
- def visit_interpolated_x_string_node(node)
- if node.heredoc?
- visit_heredoc(node) { |children, closing| builder.xstring_compose(token(node.opening_loc), children, closing) }
- else
- builder.xstring_compose(
- token(node.opening_loc),
- visit_all(node.parts),
- token(node.closing_loc)
- )
- end
- end
-
- # -> { it }
- # ^^
- def visit_it_local_variable_read_node(node)
- builder.ident([:it, srange(node.location)]).updated(:lvar)
- end
-
- # -> { it }
- # ^^^^^^^^^
- def visit_it_parameters_node(node)
- builder.args(nil, [], nil, false)
- end
-
- # foo(bar: baz)
- # ^^^^^^^^
- def visit_keyword_hash_node(node)
- builder.associate(nil, visit_all(node.elements), nil)
- end
-
- # def foo(**bar); end
- # ^^^^^
- #
- # def foo(**); end
- # ^^
- def visit_keyword_rest_parameter_node(node)
- builder.kwrestarg(
- token(node.operator_loc),
- node.name ? [node.name, srange(node.name_loc)] : nil
- )
- end
-
- # -> {}
- # ^^^^^
- def visit_lambda_node(node)
- parameters = node.parameters
- implicit_parameters = parameters.is_a?(NumberedParametersNode) || parameters.is_a?(ItParametersNode)
-
- builder.block(
- builder.call_lambda(token(node.operator_loc)),
- [node.opening, srange(node.opening_loc)],
- if parameters.nil?
- builder.args(nil, [], nil, false)
- elsif implicit_parameters
- visit(node.parameters)
- else
- builder.args(
- token(node.parameters.opening_loc),
- visit(node.parameters),
- token(node.parameters.closing_loc),
- false
- )
- end,
- node.body&.accept(copy_compiler(forwarding: implicit_parameters ? [] : find_forwarding(parameters&.parameters))),
- [node.closing, srange(node.closing_loc)]
- )
- end
-
- # foo
- # ^^^
- def visit_local_variable_read_node(node)
- builder.ident([node.name, srange(node.location)]).updated(:lvar)
- end
-
- # foo = 1
- # ^^^^^^^
- def visit_local_variable_write_node(node)
- builder.assign(
- builder.assignable(builder.ident(token(node.name_loc))),
- token(node.operator_loc),
- visit(node.value)
- )
- end
-
- # foo += bar
- # ^^^^^^^^^^
- def visit_local_variable_operator_write_node(node)
- builder.op_assign(
- builder.assignable(builder.ident(token(node.name_loc))),
- [node.binary_operator_loc.slice.chomp("="), srange(node.binary_operator_loc)],
- visit(node.value)
- )
- end
-
- # foo &&= bar
- # ^^^^^^^^^^^
- def visit_local_variable_and_write_node(node)
- builder.op_assign(
- builder.assignable(builder.ident(token(node.name_loc))),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # foo ||= bar
- # ^^^^^^^^^^^
- def visit_local_variable_or_write_node(node)
- builder.op_assign(
- builder.assignable(builder.ident(token(node.name_loc))),
- [node.operator_loc.slice.chomp("="), srange(node.operator_loc)],
- visit(node.value)
- )
- end
-
- # foo, = bar
- # ^^^
- def visit_local_variable_target_node(node)
- if in_pattern
- builder.assignable(builder.match_var([node.name, srange(node.location)]))
- else
- builder.assignable(builder.ident(token(node.location)))
- end
- end
-
- # foo in bar
- # ^^^^^^^^^^
- def visit_match_predicate_node(node)
- builder.match_pattern_p(
- visit(node.value),
- token(node.operator_loc),
- within_pattern { |compiler| node.pattern.accept(compiler) }
- )
- end
-
- # foo => bar
- # ^^^^^^^^^^
- def visit_match_required_node(node)
- builder.match_pattern(
- visit(node.value),
- token(node.operator_loc),
- within_pattern { |compiler| node.pattern.accept(compiler) }
- )
- end
-
- # /(?<foo>foo)/ =~ bar
- # ^^^^^^^^^^^^^^^^^^^^
- def visit_match_write_node(node)
- builder.match_op(
- visit(node.call.receiver),
- token(node.call.message_loc),
- visit(node.call.arguments.arguments.first)
- )
- end
-
- # A node that is missing from the syntax tree. This is only used in the
- # case of a syntax error. The parser gem doesn't have such a concept, so
- # we invent our own here.
- def visit_missing_node(node)
- ::AST::Node.new(:missing, [], location: ::Parser::Source::Map.new(srange(node.location)))
- end
-
- # module Foo; end
- # ^^^^^^^^^^^^^^^
- def visit_module_node(node)
- builder.def_module(
- token(node.module_keyword_loc),
- visit(node.constant_path),
- node.body&.accept(copy_compiler(forwarding: [])),
- token(node.end_keyword_loc)
- )
- end
-
- # foo, bar = baz
- # ^^^^^^^^
- def visit_multi_target_node(node)
- builder.multi_lhs(
- token(node.lparen_loc),
- visit_all(multi_target_elements(node)),
- token(node.rparen_loc)
- )
- end
-
- # foo, bar = baz
- # ^^^^^^^^^^^^^^
- def visit_multi_write_node(node)
- elements = multi_target_elements(node)
-
- if elements.length == 1 && elements.first.is_a?(MultiTargetNode)
- elements = multi_target_elements(elements.first)
- end
-
- builder.multi_assign(
- builder.multi_lhs(
- token(node.lparen_loc),
- visit_all(elements),
- token(node.rparen_loc)
- ),
- token(node.operator_loc),
- visit(node.value)
- )
- end
-
- # next
- # ^^^^
- #
- # next foo
- # ^^^^^^^^
- def visit_next_node(node)
- builder.keyword_cmd(
- :next,
- token(node.keyword_loc),
- nil,
- visit(node.arguments) || [],
- nil
- )
- end
-
- # nil
- # ^^^
- def visit_nil_node(node)
- builder.nil(token(node.location))
- end
-
- # def foo(**nil); end
- # ^^^^^
- def visit_no_keywords_parameter_node(node)
- if in_pattern
- builder.match_nil_pattern(token(node.operator_loc), token(node.keyword_loc))
- else
- builder.kwnilarg(token(node.operator_loc), token(node.keyword_loc))
- end
- end
-
- # -> { _1 + _2 }
- # ^^^^^^^^^^^^^^
- def visit_numbered_parameters_node(node)
- builder.numargs(node.maximum)
- end
-
- # $1
- # ^^
- def visit_numbered_reference_read_node(node)
- builder.nth_ref([node.number, srange(node.location)])
- end
-
- # def foo(bar: baz); end
- # ^^^^^^^^
- def visit_optional_keyword_parameter_node(node)
- builder.kwoptarg([node.name, srange(node.name_loc)], visit(node.value))
- end
-
- # def foo(bar = 1); end
- # ^^^^^^^
- def visit_optional_parameter_node(node)
- builder.optarg(token(node.name_loc), token(node.operator_loc), visit(node.value))
- end
-
- # a or b
- # ^^^^^^
- def visit_or_node(node)
- builder.logical_op(:or, visit(node.left), token(node.operator_loc), visit(node.right))
- end
-
- # def foo(bar, *baz); end
- # ^^^^^^^^^
- def visit_parameters_node(node)
- params = []
-
- if node.requireds.any?
- node.requireds.each do |required|
- params <<
- if required.is_a?(RequiredParameterNode)
- visit(required)
- else
- required.accept(copy_compiler(in_destructure: true))
- end
- end
- end
-
- params.concat(visit_all(node.optionals)) if node.optionals.any?
- params << visit(node.rest) if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode)
-
- if node.posts.any?
- node.posts.each do |post|
- params <<
- if post.is_a?(RequiredParameterNode)
- visit(post)
- else
- post.accept(copy_compiler(in_destructure: true))
- end
- end
- end
-
- params.concat(visit_all(node.keywords)) if node.keywords.any?
- params << visit(node.keyword_rest) if !node.keyword_rest.nil?
- params << visit(node.block) if !node.block.nil?
- params
- end
-
- # ()
- # ^^
- #
- # (1)
- # ^^^
- def visit_parentheses_node(node)
- builder.begin(
- token(node.opening_loc),
- visit(node.body),
- token(node.closing_loc)
- )
- end
-
- # foo => ^(bar)
- # ^^^^^^
- def visit_pinned_expression_node(node)
- expression = builder.begin(token(node.lparen_loc), visit(node.expression), token(node.rparen_loc))
- builder.pin(token(node.operator_loc), expression)
- end
-
- # foo = 1 and bar => ^foo
- # ^^^^
- def visit_pinned_variable_node(node)
- builder.pin(token(node.operator_loc), visit(node.variable))
- end
-
- # END {}
- def visit_post_execution_node(node)
- builder.postexe(
- token(node.keyword_loc),
- token(node.opening_loc),
- visit(node.statements),
- token(node.closing_loc)
- )
- end
-
- # BEGIN {}
- def visit_pre_execution_node(node)
- builder.preexe(
- token(node.keyword_loc),
- token(node.opening_loc),
- visit(node.statements),
- token(node.closing_loc)
- )
- end
-
- # The top-level program node.
- def visit_program_node(node)
- visit(node.statements)
- end
-
- # 0..5
- # ^^^^
- def visit_range_node(node)
- if node.exclude_end?
- builder.range_exclusive(
- visit(node.left),
- token(node.operator_loc),
- visit(node.right)
- )
- else
- builder.range_inclusive(
- visit(node.left),
- token(node.operator_loc),
- visit(node.right)
- )
- end
- end
-
- # if foo .. bar; end
- # ^^^^^^^^^^
- alias visit_flip_flop_node visit_range_node
-
- # 1r
- # ^^
- def visit_rational_node(node)
- visit_numeric(node, builder.rational([node.value, srange(node.location)]))
- end
-
- # redo
- # ^^^^
- def visit_redo_node(node)
- builder.keyword_cmd(:redo, token(node.location))
- end
-
- # /foo/
- # ^^^^^
- def visit_regular_expression_node(node)
- content = node.content
- parts =
- if content.include?("\n")
- offset = node.content_loc.start_offset
- content.lines.map do |line|
- builder.string_internal([line, srange_offsets(offset, offset += line.bytesize)])
- end
- else
- [builder.string_internal(token(node.content_loc))]
- end
-
- builder.regexp_compose(
- token(node.opening_loc),
- parts,
- [node.closing[0], srange_offsets(node.closing_loc.start_offset, node.closing_loc.start_offset + 1)],
- builder.regexp_options([node.closing[1..], srange_offsets(node.closing_loc.start_offset + 1, node.closing_loc.end_offset)])
- )
- end
-
- # if /foo/ then end
- # ^^^^^
- alias visit_match_last_line_node visit_regular_expression_node
-
- # def foo(bar:); end
- # ^^^^
- def visit_required_keyword_parameter_node(node)
- builder.kwarg([node.name, srange(node.name_loc)])
- end
-
- # def foo(bar); end
- # ^^^
- def visit_required_parameter_node(node)
- builder.arg(token(node.location))
- end
-
- # foo rescue bar
- # ^^^^^^^^^^^^^^
- def visit_rescue_modifier_node(node)
- builder.begin_body(
- visit(node.expression),
- [
- builder.rescue_body(
- token(node.keyword_loc),
- nil,
- nil,
- nil,
- nil,
- visit(node.rescue_expression)
- )
- ]
- )
- end
-
- # begin; rescue; end
- # ^^^^^^^
- def visit_rescue_node(node)
- raise CompilationError, "Cannot directly compile rescue nodes"
- end
-
- # def foo(*bar); end
- # ^^^^
- #
- # def foo(*); end
- # ^
- def visit_rest_parameter_node(node)
- builder.restarg(token(node.operator_loc), token(node.name_loc))
- end
-
- # retry
- # ^^^^^
- def visit_retry_node(node)
- builder.keyword_cmd(:retry, token(node.location))
- end
-
- # return
- # ^^^^^^
- #
- # return 1
- # ^^^^^^^^
- def visit_return_node(node)
- builder.keyword_cmd(
- :return,
- token(node.keyword_loc),
- nil,
- visit(node.arguments) || [],
- nil
- )
- end
-
- # self
- # ^^^^
- def visit_self_node(node)
- builder.self(token(node.location))
- end
-
- # A shareable constant.
- def visit_shareable_constant_node(node)
- visit(node.write)
- end
-
- # class << self; end
- # ^^^^^^^^^^^^^^^^^^
- def visit_singleton_class_node(node)
- builder.def_sclass(
- token(node.class_keyword_loc),
- token(node.operator_loc),
- visit(node.expression),
- node.body&.accept(copy_compiler(forwarding: [])),
- token(node.end_keyword_loc)
- )
- end
-
- # __ENCODING__
- # ^^^^^^^^^^^^
- def visit_source_encoding_node(node)
- builder.accessible(builder.__ENCODING__(token(node.location)))
- end
-
- # __FILE__
- # ^^^^^^^^
- def visit_source_file_node(node)
- builder.accessible(builder.__FILE__(token(node.location)))
- end
-
- # __LINE__
- # ^^^^^^^^
- def visit_source_line_node(node)
- builder.accessible(builder.__LINE__(token(node.location)))
- end
-
- # foo(*bar)
- # ^^^^
- #
- # def foo((bar, *baz)); end
- # ^^^^
- #
- # def foo(*); bar(*); end
- # ^
- def visit_splat_node(node)
- if node.expression.nil? && forwarding.include?(:*)
- builder.forwarded_restarg(token(node.operator_loc))
- elsif in_destructure
- builder.restarg(token(node.operator_loc), token(node.expression&.location))
- elsif in_pattern
- builder.match_rest(token(node.operator_loc), token(node.expression&.location))
- else
- builder.splat(token(node.operator_loc), visit(node.expression))
- end
- end
-
- # A list of statements.
- def visit_statements_node(node)
- builder.compstmt(visit_all(node.body))
- end
-
- # "foo"
- # ^^^^^
- def visit_string_node(node)
- if node.heredoc?
- visit_heredoc(node.to_interpolated) { |children, closing| builder.string_compose(token(node.opening_loc), children, closing) }
- elsif node.opening == "?"
- builder.character([node.unescaped, srange(node.location)])
- elsif node.opening&.start_with?("%") && node.unescaped.empty?
- builder.string_compose(token(node.opening_loc), [], token(node.closing_loc))
- else
- content_lines = node.content.lines
- unescaped_lines = node.unescaped.lines
-
- parts =
- if content_lines.length <= 1 || unescaped_lines.length <= 1
- [builder.string_internal([node.unescaped, srange(node.content_loc)])]
- elsif content_lines.length != unescaped_lines.length
- # This occurs when we have line continuations in the string. We
- # need to come back and fix this, but for now this stops the
- # code from breaking when we encounter it because of trying to
- # transpose arrays of different lengths.
- [builder.string_internal([node.unescaped, srange(node.content_loc)])]
- else
- start_offset = node.content_loc.start_offset
-
- [content_lines, unescaped_lines].transpose.map do |content_line, unescaped_line|
- end_offset = start_offset + content_line.length
- offsets = srange_offsets(start_offset, end_offset)
- start_offset = end_offset
-
- builder.string_internal([unescaped_line, offsets])
- end
- end
-
- builder.string_compose(
- token(node.opening_loc),
- parts,
- token(node.closing_loc)
- )
- end
- end
-
- # super(foo)
- # ^^^^^^^^^^
- def visit_super_node(node)
- arguments = node.arguments&.arguments || []
- block = node.block
-
- if block.is_a?(BlockArgumentNode)
- arguments = [*arguments, block]
- block = nil
- end
-
- visit_block(
- builder.keyword_cmd(
- :super,
- token(node.keyword_loc),
- token(node.lparen_loc),
- visit_all(arguments),
- token(node.rparen_loc)
- ),
- block
- )
- end
-
- # :foo
- # ^^^^
- def visit_symbol_node(node)
- if node.closing_loc.nil?
- if node.opening_loc.nil?
- builder.symbol_internal([node.unescaped, srange(node.location)])
- else
- builder.symbol([node.unescaped, srange(node.location)])
- end
- else
- parts = if node.value.lines.one?
- [builder.string_internal([node.unescaped, srange(node.value_loc)])]
- else
- start_offset = node.value_loc.start_offset
-
- node.value.lines.map do |line|
- end_offset = start_offset + line.length
- offsets = srange_offsets(start_offset, end_offset)
- start_offset = end_offset
-
- builder.string_internal([line, offsets])
- end
- end
-
- builder.symbol_compose(
- token(node.opening_loc),
- parts,
- token(node.closing_loc)
- )
- end
- end
-
- # true
- # ^^^^
- def visit_true_node(node)
- builder.true(token(node.location))
- end
-
- # undef foo
- # ^^^^^^^^^
- def visit_undef_node(node)
- builder.undef_method(token(node.keyword_loc), visit_all(node.names))
- end
-
- # unless foo; bar end
- # ^^^^^^^^^^^^^^^^^^^
- #
- # bar unless foo
- # ^^^^^^^^^^^^^^
- def visit_unless_node(node)
- if node.keyword_loc.start_offset == node.location.start_offset
- builder.condition(
- token(node.keyword_loc),
- visit(node.predicate),
- if node.then_keyword_loc
- token(node.then_keyword_loc)
- else
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.else_clause&.location || node.end_keyword_loc).start_offset, [";"])
- end,
- visit(node.else_clause),
- token(node.else_clause&.else_keyword_loc),
- visit(node.statements),
- token(node.end_keyword_loc)
- )
- else
- builder.condition_mod(
- visit(node.else_clause),
- visit(node.statements),
- token(node.keyword_loc),
- visit(node.predicate)
- )
- end
- end
-
- # until foo; bar end
- # ^^^^^^^^^^^^^^^^^^
- #
- # bar until foo
- # ^^^^^^^^^^^^^
- def visit_until_node(node)
- if node.location.start_offset == node.keyword_loc.start_offset
- builder.loop(
- :until,
- token(node.keyword_loc),
- visit(node.predicate),
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, [";", "do"]),
- visit(node.statements),
- token(node.closing_loc)
- )
- else
- builder.loop_mod(
- :until,
- visit(node.statements),
- token(node.keyword_loc),
- visit(node.predicate)
- )
- end
- end
-
- # case foo; when bar; end
- # ^^^^^^^^^^^^^
- def visit_when_node(node)
- builder.when(
- token(node.keyword_loc),
- visit_all(node.conditions),
- if node.then_keyword_loc
- token(node.then_keyword_loc)
- else
- srange_find(node.conditions.last.location.end_offset, node.statements&.location&.start_offset, [";"])
- end,
- visit(node.statements)
- )
- end
-
- # while foo; bar end
- # ^^^^^^^^^^^^^^^^^^
- #
- # bar while foo
- # ^^^^^^^^^^^^^
- def visit_while_node(node)
- if node.location.start_offset == node.keyword_loc.start_offset
- builder.loop(
- :while,
- token(node.keyword_loc),
- visit(node.predicate),
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, [";", "do"]),
- visit(node.statements),
- token(node.closing_loc)
- )
- else
- builder.loop_mod(
- :while,
- visit(node.statements),
- token(node.keyword_loc),
- visit(node.predicate)
- )
- end
- end
-
- # `foo`
- # ^^^^^
- def visit_x_string_node(node)
- if node.heredoc?
- visit_heredoc(node.to_interpolated) { |children, closing| builder.xstring_compose(token(node.opening_loc), children, closing) }
- else
- parts = if node.unescaped.lines.one?
- [builder.string_internal([node.unescaped, srange(node.content_loc)])]
- else
- start_offset = node.content_loc.start_offset
-
- node.unescaped.lines.map do |line|
- end_offset = start_offset + line.length
- offsets = srange_offsets(start_offset, end_offset)
- start_offset = end_offset
-
- builder.string_internal([line, offsets])
- end
- end
-
- builder.xstring_compose(
- token(node.opening_loc),
- parts,
- token(node.closing_loc)
- )
- end
- end
-
- # yield
- # ^^^^^
- #
- # yield 1
- # ^^^^^^^
- def visit_yield_node(node)
- builder.keyword_cmd(
- :yield,
- token(node.keyword_loc),
- token(node.lparen_loc),
- visit(node.arguments) || [],
- token(node.rparen_loc)
- )
- end
-
- private
-
- # Initialize a new compiler with the given option overrides, used to
- # visit a subtree with the given options.
- def copy_compiler(forwarding: self.forwarding, in_destructure: self.in_destructure, in_pattern: self.in_pattern)
- Compiler.new(parser, offset_cache, forwarding: forwarding, in_destructure: in_destructure, in_pattern: in_pattern)
- end
-
- # When *, **, &, or ... are used as an argument in a method call, we
- # check if they were allowed by the current context. To determine that
- # we build this lookup table.
- def find_forwarding(node)
- return [] if node.nil?
-
- forwarding = []
- forwarding << :* if node.rest.is_a?(RestParameterNode) && node.rest.name.nil?
- forwarding << :** if node.keyword_rest.is_a?(KeywordRestParameterNode) && node.keyword_rest.name.nil?
- forwarding << :& if !node.block.nil? && node.block.name.nil?
- forwarding |= [:&, :"..."] if node.keyword_rest.is_a?(ForwardingParameterNode)
-
- forwarding
- end
-
- # Returns the set of targets for a MultiTargetNode or a MultiWriteNode.
- def multi_target_elements(node)
- elements = [*node.lefts]
- elements << node.rest if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode)
- elements.concat(node.rights)
- elements
- end
-
- # Negate the value of a numeric node. This is a special case where you
- # have a negative sign on one line and then a number on the next line.
- # In normal Ruby, this will always be a method call. The parser gem,
- # however, marks this as a numeric literal. We have to massage the tree
- # here to get it into the correct form.
- def numeric_negate(message_loc, receiver)
- case receiver.type
- when :integer_node, :float_node
- receiver.copy(value: -receiver.value, location: message_loc.join(receiver.location))
- when :rational_node
- receiver.copy(numerator: -receiver.numerator, location: message_loc.join(receiver.location))
- when :imaginary_node
- receiver.copy(numeric: numeric_negate(message_loc, receiver.numeric), location: message_loc.join(receiver.location))
- end
- end
-
- # Blocks can have a special set of parameters that automatically expand
- # when given arrays if they have a single required parameter and no
- # other parameters.
- def procarg0?(parameters)
- parameters &&
- parameters.requireds.length == 1 &&
- parameters.optionals.empty? &&
- parameters.rest.nil? &&
- parameters.posts.empty? &&
- parameters.keywords.empty? &&
- parameters.keyword_rest.nil? &&
- parameters.block.nil?
- end
-
- # Locations in the parser gem AST are generated using this class. We
- # store a reference to its constant to make it slightly faster to look
- # up.
- Range = ::Parser::Source::Range
-
- # Constructs a new source range from the given start and end offsets.
- def srange(location)
- Range.new(source_buffer, offset_cache[location.start_offset], offset_cache[location.end_offset]) if location
- end
-
- # Constructs a new source range from the given start and end offsets.
- def srange_offsets(start_offset, end_offset)
- Range.new(source_buffer, offset_cache[start_offset], offset_cache[end_offset])
- end
-
- # Constructs a new source range by finding the given tokens between the
- # given start offset and end offset. If the needle is not found, it
- # returns nil. Importantly it does not search past newlines or comments.
- #
- # Note that end_offset is allowed to be nil, in which case this will
- # search until the end of the string.
- def srange_find(start_offset, end_offset, tokens)
- if (match = source_buffer.source.byteslice(start_offset...end_offset).match(/\A(\s*)(#{tokens.join("|")})/))
- _, whitespace, token = *match
- token_offset = start_offset + whitespace.bytesize
-
- [token, Range.new(source_buffer, offset_cache[token_offset], offset_cache[token_offset + token.bytesize])]
- end
- end
-
- # Transform a location into a token that the parser gem expects.
- def token(location)
- [location.slice, Range.new(source_buffer, offset_cache[location.start_offset], offset_cache[location.end_offset])] if location
- end
-
- # Visit a block node on a call.
- def visit_block(call, block)
- if block
- parameters = block.parameters
- implicit_parameters = parameters.is_a?(NumberedParametersNode) || parameters.is_a?(ItParametersNode)
-
- builder.block(
- call,
- token(block.opening_loc),
- if parameters.nil?
- builder.args(nil, [], nil, false)
- elsif implicit_parameters
- visit(parameters)
- else
- builder.args(
- token(parameters.opening_loc),
- if procarg0?(parameters.parameters)
- parameter = parameters.parameters.requireds.first
- visited = parameter.is_a?(RequiredParameterNode) ? visit(parameter) : parameter.accept(copy_compiler(in_destructure: true))
- [builder.procarg0(visited)].concat(visit_all(parameters.locals))
- else
- visit(parameters)
- end,
- token(parameters.closing_loc),
- false
- )
- end,
- block.body&.accept(copy_compiler(forwarding: implicit_parameters ? [] : find_forwarding(parameters&.parameters))),
- token(block.closing_loc)
- )
- else
- call
- end
- end
-
- # The parser gem automatically converts \r\n to \n, meaning our offsets
- # need to be adjusted to always subtract 1 from the length.
- def chomped_bytesize(line)
- chomped = line.chomp
- chomped.bytesize + (chomped == line ? 0 : 1)
- end
-
- # Visit a heredoc that can be either a string or an xstring.
- def visit_heredoc(node)
- children = Array.new
- indented = false
-
- # If this is a dedenting heredoc, then we need to insert the opening
- # content into the children as well.
- if node.opening.start_with?("<<~") && node.parts.length > 0 && !node.parts.first.is_a?(StringNode)
- location = node.parts.first.location
- location = location.copy(start_offset: location.start_offset - location.start_line_slice.bytesize)
- children << builder.string_internal(token(location))
- indented = true
- end
-
- node.parts.each do |part|
- pushing =
- if part.is_a?(StringNode) && part.unescaped.include?("\n")
- unescaped = part.unescaped.lines
- escaped = part.content.lines
-
- escaped_lengths = []
- normalized_lengths = []
-
- if node.opening.end_with?("'")
- escaped.each do |line|
- escaped_lengths << line.bytesize
- normalized_lengths << chomped_bytesize(line)
- end
- else
- escaped
- .chunk_while { |before, after| before.match?(/(?<!\\)\\\r?\n$/) }
- .each do |lines|
- escaped_lengths << lines.sum(&:bytesize)
- normalized_lengths << lines.sum { |line| chomped_bytesize(line) }
- end
- end
-
- start_offset = part.location.start_offset
-
- unescaped.map.with_index do |unescaped_line, index|
- inner_part = builder.string_internal([unescaped_line, srange_offsets(start_offset, start_offset + normalized_lengths.fetch(index, 0))])
- start_offset += escaped_lengths.fetch(index, 0)
- inner_part
- end
- else
- [visit(part)]
- end
-
- pushing.each do |child|
- if child.type == :str && child.children.last == ""
- # nothing
- elsif child.type == :str && children.last && children.last.type == :str && !children.last.children.first.end_with?("\n")
- appendee = children[-1]
-
- location = appendee.loc
- location = location.with_expression(location.expression.join(child.loc.expression))
-
- children[-1] = appendee.updated(:str, [appendee.children.first << child.children.first], location: location)
- else
- children << child
- end
- end
- end
-
- closing = node.closing
- closing_t = [closing.chomp, srange_offsets(node.closing_loc.start_offset, node.closing_loc.end_offset - (closing[/\s+$/]&.length || 0))]
- composed = yield children, closing_t
-
- composed = composed.updated(nil, children[1..-1]) if indented
- composed
- end
-
- # Visit a numeric node and account for the optional sign.
- def visit_numeric(node, value)
- if (slice = node.slice).match?(/^[+-]/)
- builder.unary_num(
- [slice[0].to_sym, srange_offsets(node.location.start_offset, node.location.start_offset + 1)],
- value
- )
- else
- value
- end
- end
-
- # Within the given block, track that we're within a pattern.
- def within_pattern
- begin
- parser.pattern_variables.push
- yield copy_compiler(in_pattern: true)
- ensure
- parser.pattern_variables.pop
- end
- end
- end
- end
- end
-end
diff --git a/lib/prism/translation/parser/lexer.rb b/lib/prism/translation/parser/lexer.rb
deleted file mode 100644
index db7dbb1c87..0000000000
--- a/lib/prism/translation/parser/lexer.rb
+++ /dev/null
@@ -1,438 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- module Translation
- class Parser
- # Accepts a list of prism tokens and converts them into the expected
- # format for the parser gem.
- class Lexer
- # The direct translating of types between the two lexers.
- TYPES = {
- # These tokens should never appear in the output of the lexer.
- EOF: nil,
- MISSING: nil,
- NOT_PROVIDED: nil,
- IGNORED_NEWLINE: nil,
- EMBDOC_END: nil,
- EMBDOC_LINE: nil,
- __END__: nil,
-
- # These tokens have more or less direct mappings.
- AMPERSAND: :tAMPER2,
- AMPERSAND_AMPERSAND: :tANDOP,
- AMPERSAND_AMPERSAND_EQUAL: :tOP_ASGN,
- AMPERSAND_DOT: :tANDDOT,
- AMPERSAND_EQUAL: :tOP_ASGN,
- BACK_REFERENCE: :tBACK_REF,
- BACKTICK: :tXSTRING_BEG,
- BANG: :tBANG,
- BANG_EQUAL: :tNEQ,
- BANG_TILDE: :tNMATCH,
- BRACE_LEFT: :tLCURLY,
- BRACE_RIGHT: :tRCURLY,
- BRACKET_LEFT: :tLBRACK2,
- BRACKET_LEFT_ARRAY: :tLBRACK,
- BRACKET_LEFT_RIGHT: :tAREF,
- BRACKET_LEFT_RIGHT_EQUAL: :tASET,
- BRACKET_RIGHT: :tRBRACK,
- CARET: :tCARET,
- CARET_EQUAL: :tOP_ASGN,
- CHARACTER_LITERAL: :tCHARACTER,
- CLASS_VARIABLE: :tCVAR,
- COLON: :tCOLON,
- COLON_COLON: :tCOLON2,
- COMMA: :tCOMMA,
- COMMENT: :tCOMMENT,
- CONSTANT: :tCONSTANT,
- DOT: :tDOT,
- DOT_DOT: :tDOT2,
- DOT_DOT_DOT: :tDOT3,
- EMBDOC_BEGIN: :tCOMMENT,
- EMBEXPR_BEGIN: :tSTRING_DBEG,
- EMBEXPR_END: :tSTRING_DEND,
- EMBVAR: :tSTRING_DVAR,
- EQUAL: :tEQL,
- EQUAL_EQUAL: :tEQ,
- EQUAL_EQUAL_EQUAL: :tEQQ,
- EQUAL_GREATER: :tASSOC,
- EQUAL_TILDE: :tMATCH,
- FLOAT: :tFLOAT,
- FLOAT_IMAGINARY: :tIMAGINARY,
- FLOAT_RATIONAL: :tRATIONAL,
- FLOAT_RATIONAL_IMAGINARY: :tIMAGINARY,
- GLOBAL_VARIABLE: :tGVAR,
- GREATER: :tGT,
- GREATER_EQUAL: :tGEQ,
- GREATER_GREATER: :tRSHFT,
- GREATER_GREATER_EQUAL: :tOP_ASGN,
- HEREDOC_START: :tSTRING_BEG,
- HEREDOC_END: :tSTRING_END,
- IDENTIFIER: :tIDENTIFIER,
- INSTANCE_VARIABLE: :tIVAR,
- INTEGER: :tINTEGER,
- INTEGER_IMAGINARY: :tIMAGINARY,
- INTEGER_RATIONAL: :tRATIONAL,
- INTEGER_RATIONAL_IMAGINARY: :tIMAGINARY,
- KEYWORD_ALIAS: :kALIAS,
- KEYWORD_AND: :kAND,
- KEYWORD_BEGIN: :kBEGIN,
- KEYWORD_BEGIN_UPCASE: :klBEGIN,
- KEYWORD_BREAK: :kBREAK,
- KEYWORD_CASE: :kCASE,
- KEYWORD_CLASS: :kCLASS,
- KEYWORD_DEF: :kDEF,
- KEYWORD_DEFINED: :kDEFINED,
- KEYWORD_DO: :kDO,
- KEYWORD_DO_LOOP: :kDO_COND,
- KEYWORD_END: :kEND,
- KEYWORD_END_UPCASE: :klEND,
- KEYWORD_ENSURE: :kENSURE,
- KEYWORD_ELSE: :kELSE,
- KEYWORD_ELSIF: :kELSIF,
- KEYWORD_FALSE: :kFALSE,
- KEYWORD_FOR: :kFOR,
- KEYWORD_IF: :kIF,
- KEYWORD_IF_MODIFIER: :kIF_MOD,
- KEYWORD_IN: :kIN,
- KEYWORD_MODULE: :kMODULE,
- KEYWORD_NEXT: :kNEXT,
- KEYWORD_NIL: :kNIL,
- KEYWORD_NOT: :kNOT,
- KEYWORD_OR: :kOR,
- KEYWORD_REDO: :kREDO,
- KEYWORD_RESCUE: :kRESCUE,
- KEYWORD_RESCUE_MODIFIER: :kRESCUE_MOD,
- KEYWORD_RETRY: :kRETRY,
- KEYWORD_RETURN: :kRETURN,
- KEYWORD_SELF: :kSELF,
- KEYWORD_SUPER: :kSUPER,
- KEYWORD_THEN: :kTHEN,
- KEYWORD_TRUE: :kTRUE,
- KEYWORD_UNDEF: :kUNDEF,
- KEYWORD_UNLESS: :kUNLESS,
- KEYWORD_UNLESS_MODIFIER: :kUNLESS_MOD,
- KEYWORD_UNTIL: :kUNTIL,
- KEYWORD_UNTIL_MODIFIER: :kUNTIL_MOD,
- KEYWORD_WHEN: :kWHEN,
- KEYWORD_WHILE: :kWHILE,
- KEYWORD_WHILE_MODIFIER: :kWHILE_MOD,
- KEYWORD_YIELD: :kYIELD,
- KEYWORD___ENCODING__: :k__ENCODING__,
- KEYWORD___FILE__: :k__FILE__,
- KEYWORD___LINE__: :k__LINE__,
- LABEL: :tLABEL,
- LABEL_END: :tLABEL_END,
- LAMBDA_BEGIN: :tLAMBEG,
- LESS: :tLT,
- LESS_EQUAL: :tLEQ,
- LESS_EQUAL_GREATER: :tCMP,
- LESS_LESS: :tLSHFT,
- LESS_LESS_EQUAL: :tOP_ASGN,
- METHOD_NAME: :tFID,
- MINUS: :tMINUS,
- MINUS_EQUAL: :tOP_ASGN,
- MINUS_GREATER: :tLAMBDA,
- NEWLINE: :tNL,
- NUMBERED_REFERENCE: :tNTH_REF,
- PARENTHESIS_LEFT: :tLPAREN2,
- PARENTHESIS_LEFT_PARENTHESES: :tLPAREN_ARG,
- PARENTHESIS_RIGHT: :tRPAREN,
- PERCENT: :tPERCENT,
- PERCENT_EQUAL: :tOP_ASGN,
- PERCENT_LOWER_I: :tQSYMBOLS_BEG,
- PERCENT_LOWER_W: :tQWORDS_BEG,
- PERCENT_UPPER_I: :tSYMBOLS_BEG,
- PERCENT_UPPER_W: :tWORDS_BEG,
- PERCENT_LOWER_X: :tXSTRING_BEG,
- PLUS: :tPLUS,
- PLUS_EQUAL: :tOP_ASGN,
- PIPE_EQUAL: :tOP_ASGN,
- PIPE: :tPIPE,
- PIPE_PIPE: :tOROP,
- PIPE_PIPE_EQUAL: :tOP_ASGN,
- QUESTION_MARK: :tEH,
- REGEXP_BEGIN: :tREGEXP_BEG,
- REGEXP_END: :tSTRING_END,
- SEMICOLON: :tSEMI,
- SLASH: :tDIVIDE,
- SLASH_EQUAL: :tOP_ASGN,
- STAR: :tSTAR2,
- STAR_EQUAL: :tOP_ASGN,
- STAR_STAR: :tPOW,
- STAR_STAR_EQUAL: :tOP_ASGN,
- STRING_BEGIN: :tSTRING_BEG,
- STRING_CONTENT: :tSTRING_CONTENT,
- STRING_END: :tSTRING_END,
- SYMBOL_BEGIN: :tSYMBEG,
- TILDE: :tTILDE,
- UAMPERSAND: :tAMPER,
- UCOLON_COLON: :tCOLON3,
- UDOT_DOT: :tBDOT2,
- UDOT_DOT_DOT: :tBDOT3,
- UMINUS: :tUMINUS,
- UMINUS_NUM: :tUNARY_NUM,
- UPLUS: :tUPLUS,
- USTAR: :tSTAR,
- USTAR_STAR: :tDSTAR,
- WORDS_SEP: :tSPACE
- }
-
- # These constants represent flags in our lex state. We really, really
- # don't want to be using them and we really, really don't want to be
- # exposing them as part of our public API. Unfortunately, we don't have
- # another way of matching the exact tokens that the parser gem expects
- # without them. We should find another way to do this, but in the
- # meantime we'll hide them from the documentation and mark them as
- # private constants.
- EXPR_BEG = 0x1 # :nodoc:
- EXPR_LABEL = 0x400 # :nodoc:
-
- # It is used to determine whether `do` is of the token type `kDO` or `kDO_LAMBDA`.
- #
- # NOTE: In edge cases like `-> (foo = -> (bar) {}) do end`, please note that `kDO` is still returned
- # instead of `kDO_LAMBDA`, which is expected: https://github.com/ruby/prism/pull/3046
- LAMBDA_TOKEN_TYPES = [:kDO_LAMBDA, :tLAMBDA, :tLAMBEG]
-
- # The `PARENTHESIS_LEFT` token in Prism is classified as either `tLPAREN` or `tLPAREN2` in the Parser gem.
- # The following token types are listed as those classified as `tLPAREN`.
- LPAREN_CONVERSION_TOKEN_TYPES = [
- :kBREAK, :kCASE, :tDIVIDE, :kFOR, :kIF, :kNEXT, :kRETURN, :kUNTIL, :kWHILE, :tAMPER, :tANDOP, :tBANG, :tCOMMA, :tDOT2, :tDOT3,
- :tEQL, :tLPAREN, :tLPAREN2, :tLSHFT, :tNL, :tOP_ASGN, :tOROP, :tPIPE, :tSEMI, :tSTRING_DBEG, :tUMINUS, :tUPLUS
- ]
-
- private_constant :TYPES, :EXPR_BEG, :EXPR_LABEL, :LAMBDA_TOKEN_TYPES, :LPAREN_CONVERSION_TOKEN_TYPES
-
- # The Parser::Source::Buffer that the tokens were lexed from.
- attr_reader :source_buffer
-
- # An array of tuples that contain prism tokens and their associated lex
- # state when they were lexed.
- attr_reader :lexed
-
- # A hash that maps offsets in bytes to offsets in characters.
- attr_reader :offset_cache
-
- # Initialize the lexer with the given source buffer, prism tokens, and
- # offset cache.
- def initialize(source_buffer, lexed, offset_cache)
- @source_buffer = source_buffer
- @lexed = lexed
- @offset_cache = offset_cache
- end
-
- Range = ::Parser::Source::Range # :nodoc:
- private_constant :Range
-
- # Convert the prism tokens into the expected format for the parser gem.
- def to_a
- tokens = []
-
- index = 0
- length = lexed.length
-
- heredoc_identifier_stack = []
-
- while index < length
- token, state = lexed[index]
- index += 1
- next if %i[IGNORED_NEWLINE __END__ EOF].include?(token.type)
-
- type = TYPES.fetch(token.type)
- value = token.value
- location = Range.new(source_buffer, offset_cache[token.location.start_offset], offset_cache[token.location.end_offset])
-
- case type
- when :kDO
- types = tokens.map(&:first)
- nearest_lambda_token_type = types.reverse.find { |type| LAMBDA_TOKEN_TYPES.include?(type) }
-
- if nearest_lambda_token_type == :tLAMBDA
- type = :kDO_LAMBDA
- end
- when :tCHARACTER
- value.delete_prefix!("?")
- when :tCOMMENT
- if token.type == :EMBDOC_BEGIN
- start_index = index
-
- while !((next_token = lexed[index][0]) && next_token.type == :EMBDOC_END) && (index < length - 1)
- value += next_token.value
- index += 1
- end
-
- if start_index != index
- value += next_token.value
- location = Range.new(source_buffer, offset_cache[token.location.start_offset], offset_cache[lexed[index][0].location.end_offset])
- index += 1
- end
- else
- value.chomp!
- location = Range.new(source_buffer, offset_cache[token.location.start_offset], offset_cache[token.location.end_offset - 1])
- end
- when :tNL
- value = nil
- when :tFLOAT
- value = parse_float(value)
- when :tIMAGINARY
- value = parse_complex(value)
- when :tINTEGER
- if value.start_with?("+")
- tokens << [:tUNARY_NUM, ["+", Range.new(source_buffer, offset_cache[token.location.start_offset], offset_cache[token.location.start_offset + 1])]]
- location = Range.new(source_buffer, offset_cache[token.location.start_offset + 1], offset_cache[token.location.end_offset])
- end
-
- value = parse_integer(value)
- when :tLABEL
- value.chomp!(":")
- when :tLABEL_END
- value.chomp!(":")
- when :tLCURLY
- type = :tLBRACE if state == EXPR_BEG | EXPR_LABEL
- when :tLPAREN2
- type = :tLPAREN if tokens.empty? || LPAREN_CONVERSION_TOKEN_TYPES.include?(tokens.dig(-1, 0))
- when :tNTH_REF
- value = parse_integer(value.delete_prefix("$"))
- when :tOP_ASGN
- value.chomp!("=")
- when :tRATIONAL
- value = parse_rational(value)
- when :tSPACE
- value = nil
- when :tSTRING_BEG
- if token.type == :HEREDOC_START
- heredoc_identifier_stack.push(value.match(/<<[-~]?["'`]?(?<heredoc_identifier>.*?)["'`]?\z/)[:heredoc_identifier])
- end
- if ["\"", "'"].include?(value) && (next_token = lexed[index][0]) && next_token.type == :STRING_END
- next_location = token.location.join(next_token.location)
- type = :tSTRING
- value = ""
- location = Range.new(source_buffer, offset_cache[next_location.start_offset], offset_cache[next_location.end_offset])
- index += 1
- elsif ["\"", "'"].include?(value) && (next_token = lexed[index][0]) && next_token.type == :STRING_CONTENT && next_token.value.lines.count <= 1 && (next_next_token = lexed[index + 1][0]) && next_next_token.type == :STRING_END
- next_location = token.location.join(next_next_token.location)
- type = :tSTRING
- value = next_token.value.gsub("\\\\", "\\")
- location = Range.new(source_buffer, offset_cache[next_location.start_offset], offset_cache[next_location.end_offset])
- index += 2
- elsif value.start_with?("<<")
- quote = value[2] == "-" || value[2] == "~" ? value[3] : value[2]
- if quote == "`"
- type = :tXSTRING_BEG
- value = "<<`"
- else
- value = "<<#{quote == "'" || quote == "\"" ? quote : "\""}"
- end
- end
- when :tSTRING_CONTENT
- unless (lines = token.value.lines).one?
- start_offset = offset_cache[token.location.start_offset]
- lines.map do |line|
- newline = line.end_with?("\r\n") ? "\r\n" : "\n"
- chomped_line = line.chomp
- if match = chomped_line.match(/(?<backslashes>\\+)\z/)
- adjustment = match[:backslashes].size / 2
- adjusted_line = chomped_line.delete_suffix("\\" * adjustment)
- if match[:backslashes].size.odd?
- adjusted_line.delete_suffix!("\\")
- adjustment += 2
- else
- adjusted_line << newline
- end
- else
- adjusted_line = line
- adjustment = 0
- end
-
- end_offset = start_offset + adjusted_line.length + adjustment
- tokens << [:tSTRING_CONTENT, [adjusted_line, Range.new(source_buffer, offset_cache[start_offset], offset_cache[end_offset])]]
- start_offset = end_offset
- end
- next
- end
- when :tSTRING_DVAR
- value = nil
- when :tSTRING_END
- if token.type == :HEREDOC_END && value.end_with?("\n")
- newline_length = value.end_with?("\r\n") ? 2 : 1
- value = heredoc_identifier_stack.pop
- location = Range.new(source_buffer, offset_cache[token.location.start_offset], offset_cache[token.location.end_offset - newline_length])
- elsif token.type == :REGEXP_END
- value = value[0]
- location = Range.new(source_buffer, offset_cache[token.location.start_offset], offset_cache[token.location.start_offset + 1])
- end
- when :tSYMBEG
- if (next_token = lexed[index][0]) && next_token.type != :STRING_CONTENT && next_token.type != :EMBEXPR_BEGIN && next_token.type != :EMBVAR && next_token.type != :STRING_END
- next_location = token.location.join(next_token.location)
- type = :tSYMBOL
- value = next_token.value
- value = { "~@" => "~", "!@" => "!" }.fetch(value, value)
- location = Range.new(source_buffer, offset_cache[next_location.start_offset], offset_cache[next_location.end_offset])
- index += 1
- end
- when :tFID
- if !tokens.empty? && tokens.dig(-1, 0) == :kDEF
- type = :tIDENTIFIER
- end
- when :tXSTRING_BEG
- if (next_token = lexed[index][0]) && next_token.type != :STRING_CONTENT && next_token.type != :STRING_END
- type = :tBACK_REF2
- end
- end
-
- tokens << [type, [value, location]]
-
- if token.type == :REGEXP_END
- tokens << [:tREGEXP_OPT, [token.value[1..], Range.new(source_buffer, offset_cache[token.location.start_offset + 1], offset_cache[token.location.end_offset])]]
- end
- end
-
- tokens
- end
-
- private
-
- # Parse an integer from the string representation.
- def parse_integer(value)
- Integer(value)
- rescue ArgumentError
- 0
- end
-
- # Parse a float from the string representation.
- def parse_float(value)
- Float(value)
- rescue ArgumentError
- 0.0
- end
-
- # Parse a complex from the string representation.
- def parse_complex(value)
- value.chomp!("i")
-
- if value.end_with?("r")
- Complex(0, parse_rational(value))
- elsif value.start_with?(/0[BbOoDdXx]/)
- Complex(0, parse_integer(value))
- else
- Complex(0, value)
- end
- rescue ArgumentError
- 0i
- end
-
- # Parse a rational from the string representation.
- def parse_rational(value)
- value.chomp!("r")
-
- if value.start_with?(/0[BbOoDdXx]/)
- Rational(parse_integer(value))
- else
- Rational(value)
- end
- rescue ArgumentError
- 0r
- end
- end
- end
- end
-end
diff --git a/lib/prism/translation/parser33.rb b/lib/prism/translation/parser33.rb
deleted file mode 100644
index b09266e06a..0000000000
--- a/lib/prism/translation/parser33.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- module Translation
- # This class is the entry-point for Ruby 3.3 of `Prism::Translation::Parser`.
- class Parser33 < Parser
- def version # :nodoc:
- 33
- end
- end
- end
-end
diff --git a/lib/prism/translation/parser34.rb b/lib/prism/translation/parser34.rb
deleted file mode 100644
index 0ead70ad3c..0000000000
--- a/lib/prism/translation/parser34.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# frozen_string_literal: true
-
-module Prism
- module Translation
- # This class is the entry-point for Ruby 3.4 of `Prism::Translation::Parser`.
- class Parser34 < Parser
- def version # :nodoc:
- 34
- end
- end
- end
-end
diff --git a/lib/prism/translation/ripper.rb b/lib/prism/translation/ripper.rb
deleted file mode 100644
index 018842715b..0000000000
--- a/lib/prism/translation/ripper.rb
+++ /dev/null
@@ -1,3448 +0,0 @@
-# frozen_string_literal: true
-
-require "ripper"
-
-module Prism
- module Translation
- # This class provides a compatibility layer between prism and Ripper. It
- # functions by parsing the entire tree first and then walking it and
- # executing each of the Ripper callbacks as it goes. To use this class, you
- # treat `Prism::Translation::Ripper` effectively as you would treat the
- # `Ripper` class.
- #
- # Note that this class will serve the most common use cases, but Ripper's
- # API is extensive and undocumented. It relies on reporting the state of the
- # parser at any given time. We do our best to replicate that here, but
- # because it is a different architecture it is not possible to perfectly
- # replicate the behavior of Ripper.
- #
- # The main known difference is that we may omit dispatching some events in
- # some cases. This impacts the following events:
- #
- # - on_assign_error
- # - on_comma
- # - on_ignored_nl
- # - on_ignored_sp
- # - on_kw
- # - on_label_end
- # - on_lbrace
- # - on_lbracket
- # - on_lparen
- # - on_nl
- # - on_op
- # - on_operator_ambiguous
- # - on_rbrace
- # - on_rbracket
- # - on_rparen
- # - on_semicolon
- # - on_sp
- # - on_symbeg
- # - on_tstring_beg
- # - on_tstring_end
- #
- class Ripper < Compiler
- # Parses the given Ruby program read from +src+.
- # +src+ must be a String or an IO or a object with a #gets method.
- def self.parse(src, filename = "(ripper)", lineno = 1)
- new(src, filename, lineno).parse
- end
-
- # Tokenizes the Ruby program and returns an array of an array,
- # which is formatted like
- # <code>[[lineno, column], type, token, state]</code>.
- # The +filename+ argument is mostly ignored.
- # By default, this method does not handle syntax errors in +src+,
- # use the +raise_errors+ keyword to raise a SyntaxError for an error in +src+.
- #
- # require "ripper"
- # require "pp"
- #
- # pp Ripper.lex("def m(a) nil end")
- # #=> [[[1, 0], :on_kw, "def", FNAME ],
- # [[1, 3], :on_sp, " ", FNAME ],
- # [[1, 4], :on_ident, "m", ENDFN ],
- # [[1, 5], :on_lparen, "(", BEG|LABEL],
- # [[1, 6], :on_ident, "a", ARG ],
- # [[1, 7], :on_rparen, ")", ENDFN ],
- # [[1, 8], :on_sp, " ", BEG ],
- # [[1, 9], :on_kw, "nil", END ],
- # [[1, 12], :on_sp, " ", END ],
- # [[1, 13], :on_kw, "end", END ]]
- #
- def self.lex(src, filename = "-", lineno = 1, raise_errors: false)
- result = Prism.lex_compat(src, filepath: filename, line: lineno)
-
- if result.failure? && raise_errors
- raise SyntaxError, result.errors.first.message
- else
- result.value
- end
- end
-
- # This contains a table of all of the parser events and their
- # corresponding arity.
- PARSER_EVENT_TABLE = {
- BEGIN: 1,
- END: 1,
- alias: 2,
- alias_error: 2,
- aref: 2,
- aref_field: 2,
- arg_ambiguous: 1,
- arg_paren: 1,
- args_add: 2,
- args_add_block: 2,
- args_add_star: 2,
- args_forward: 0,
- args_new: 0,
- array: 1,
- aryptn: 4,
- assign: 2,
- assign_error: 2,
- assoc_new: 2,
- assoc_splat: 1,
- assoclist_from_args: 1,
- bare_assoc_hash: 1,
- begin: 1,
- binary: 3,
- block_var: 2,
- blockarg: 1,
- bodystmt: 4,
- brace_block: 2,
- break: 1,
- call: 3,
- case: 2,
- class: 3,
- class_name_error: 2,
- command: 2,
- command_call: 4,
- const_path_field: 2,
- const_path_ref: 2,
- const_ref: 1,
- def: 3,
- defined: 1,
- defs: 5,
- do_block: 2,
- dot2: 2,
- dot3: 2,
- dyna_symbol: 1,
- else: 1,
- elsif: 3,
- ensure: 1,
- excessed_comma: 0,
- fcall: 1,
- field: 3,
- fndptn: 4,
- for: 3,
- hash: 1,
- heredoc_dedent: 2,
- hshptn: 3,
- if: 3,
- if_mod: 2,
- ifop: 3,
- in: 3,
- kwrest_param: 1,
- lambda: 2,
- magic_comment: 2,
- massign: 2,
- method_add_arg: 2,
- method_add_block: 2,
- mlhs_add: 2,
- mlhs_add_post: 2,
- mlhs_add_star: 2,
- mlhs_new: 0,
- mlhs_paren: 1,
- module: 2,
- mrhs_add: 2,
- mrhs_add_star: 2,
- mrhs_new: 0,
- mrhs_new_from_args: 1,
- next: 1,
- nokw_param: 1,
- opassign: 3,
- operator_ambiguous: 2,
- param_error: 2,
- params: 7,
- paren: 1,
- parse_error: 1,
- program: 1,
- qsymbols_add: 2,
- qsymbols_new: 0,
- qwords_add: 2,
- qwords_new: 0,
- redo: 0,
- regexp_add: 2,
- regexp_literal: 2,
- regexp_new: 0,
- rescue: 4,
- rescue_mod: 2,
- rest_param: 1,
- retry: 0,
- return: 1,
- return0: 0,
- sclass: 2,
- stmts_add: 2,
- stmts_new: 0,
- string_add: 2,
- string_concat: 2,
- string_content: 0,
- string_dvar: 1,
- string_embexpr: 1,
- string_literal: 1,
- super: 1,
- symbol: 1,
- symbol_literal: 1,
- symbols_add: 2,
- symbols_new: 0,
- top_const_field: 1,
- top_const_ref: 1,
- unary: 2,
- undef: 1,
- unless: 3,
- unless_mod: 2,
- until: 2,
- until_mod: 2,
- var_alias: 2,
- var_field: 1,
- var_ref: 1,
- vcall: 1,
- void_stmt: 0,
- when: 3,
- while: 2,
- while_mod: 2,
- word_add: 2,
- word_new: 0,
- words_add: 2,
- words_new: 0,
- xstring_add: 2,
- xstring_literal: 1,
- xstring_new: 0,
- yield: 1,
- yield0: 0,
- zsuper: 0
- }
-
- # This contains a table of all of the scanner events and their
- # corresponding arity.
- SCANNER_EVENT_TABLE = {
- CHAR: 1,
- __end__: 1,
- backref: 1,
- backtick: 1,
- comma: 1,
- comment: 1,
- const: 1,
- cvar: 1,
- embdoc: 1,
- embdoc_beg: 1,
- embdoc_end: 1,
- embexpr_beg: 1,
- embexpr_end: 1,
- embvar: 1,
- float: 1,
- gvar: 1,
- heredoc_beg: 1,
- heredoc_end: 1,
- ident: 1,
- ignored_nl: 1,
- imaginary: 1,
- int: 1,
- ivar: 1,
- kw: 1,
- label: 1,
- label_end: 1,
- lbrace: 1,
- lbracket: 1,
- lparen: 1,
- nl: 1,
- op: 1,
- period: 1,
- qsymbols_beg: 1,
- qwords_beg: 1,
- rational: 1,
- rbrace: 1,
- rbracket: 1,
- regexp_beg: 1,
- regexp_end: 1,
- rparen: 1,
- semicolon: 1,
- sp: 1,
- symbeg: 1,
- symbols_beg: 1,
- tlambda: 1,
- tlambeg: 1,
- tstring_beg: 1,
- tstring_content: 1,
- tstring_end: 1,
- words_beg: 1,
- words_sep: 1,
- ignored_sp: 1
- }
-
- # This array contains name of parser events.
- PARSER_EVENTS = PARSER_EVENT_TABLE.keys
-
- # This array contains name of scanner events.
- SCANNER_EVENTS = SCANNER_EVENT_TABLE.keys
-
- # This array contains name of all ripper events.
- EVENTS = PARSER_EVENTS + SCANNER_EVENTS
-
- # A list of all of the Ruby keywords.
- KEYWORDS = [
- "alias",
- "and",
- "begin",
- "BEGIN",
- "break",
- "case",
- "class",
- "def",
- "defined?",
- "do",
- "else",
- "elsif",
- "end",
- "END",
- "ensure",
- "false",
- "for",
- "if",
- "in",
- "module",
- "next",
- "nil",
- "not",
- "or",
- "redo",
- "rescue",
- "retry",
- "return",
- "self",
- "super",
- "then",
- "true",
- "undef",
- "unless",
- "until",
- "when",
- "while",
- "yield",
- "__ENCODING__",
- "__FILE__",
- "__LINE__"
- ]
-
- # A list of all of the Ruby binary operators.
- BINARY_OPERATORS = [
- :!=,
- :!~,
- :=~,
- :==,
- :===,
- :<=>,
- :>,
- :>=,
- :<,
- :<=,
- :&,
- :|,
- :^,
- :>>,
- :<<,
- :-,
- :+,
- :%,
- :/,
- :*,
- :**
- ]
-
- private_constant :KEYWORDS, :BINARY_OPERATORS
-
- # Parses +src+ and create S-exp tree.
- # Returns more readable tree rather than Ripper.sexp_raw.
- # This method is mainly for developer use.
- # The +filename+ argument is mostly ignored.
- # By default, this method does not handle syntax errors in +src+,
- # returning +nil+ in such cases. Use the +raise_errors+ keyword
- # to raise a SyntaxError for an error in +src+.
- #
- # require "ripper"
- # require "pp"
- #
- # pp Ripper.sexp("def m(a) nil end")
- # #=> [:program,
- # [[:def,
- # [:@ident, "m", [1, 4]],
- # [:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil, nil, nil, nil]],
- # [:bodystmt, [[:var_ref, [:@kw, "nil", [1, 9]]]], nil, nil, nil]]]]
- #
- def self.sexp(src, filename = "-", lineno = 1, raise_errors: false)
- builder = SexpBuilderPP.new(src, filename, lineno)
- sexp = builder.parse
- if builder.error?
- if raise_errors
- raise SyntaxError, builder.error
- end
- else
- sexp
- end
- end
-
- # Parses +src+ and create S-exp tree.
- # This method is mainly for developer use.
- # The +filename+ argument is mostly ignored.
- # By default, this method does not handle syntax errors in +src+,
- # returning +nil+ in such cases. Use the +raise_errors+ keyword
- # to raise a SyntaxError for an error in +src+.
- #
- # require "ripper"
- # require "pp"
- #
- # pp Ripper.sexp_raw("def m(a) nil end")
- # #=> [:program,
- # [:stmts_add,
- # [:stmts_new],
- # [:def,
- # [:@ident, "m", [1, 4]],
- # [:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil]],
- # [:bodystmt,
- # [:stmts_add, [:stmts_new], [:var_ref, [:@kw, "nil", [1, 9]]]],
- # nil,
- # nil,
- # nil]]]]
- #
- def self.sexp_raw(src, filename = "-", lineno = 1, raise_errors: false)
- builder = SexpBuilder.new(src, filename, lineno)
- sexp = builder.parse
- if builder.error?
- if raise_errors
- raise SyntaxError, builder.error
- end
- else
- sexp
- end
- end
-
- autoload :SexpBuilder, "prism/translation/ripper/sexp"
- autoload :SexpBuilderPP, "prism/translation/ripper/sexp"
-
- # The source that is being parsed.
- attr_reader :source
-
- # The filename of the source being parsed.
- attr_reader :filename
-
- # The current line number of the parser.
- attr_reader :lineno
-
- # The current column number of the parser.
- attr_reader :column
-
- # Create a new Translation::Ripper object with the given source.
- def initialize(source, filename = "(ripper)", lineno = 1)
- @source = source
- @filename = filename
- @lineno = lineno
- @column = 0
- @result = nil
- end
-
- ##########################################################################
- # Public interface
- ##########################################################################
-
- # True if the parser encountered an error during parsing.
- def error?
- result.failure?
- end
-
- # Parse the source and return the result.
- def parse
- result.comments.each do |comment|
- location = comment.location
- bounds(location)
-
- if comment.is_a?(InlineComment)
- on_comment(comment.slice)
- else
- offset = location.start_offset
- lines = comment.slice.lines
-
- lines.each_with_index do |line, index|
- bounds(location.copy(start_offset: offset))
-
- if index == 0
- on_embdoc_beg(line)
- elsif index == lines.size - 1
- on_embdoc_end(line)
- else
- on_embdoc(line)
- end
-
- offset += line.bytesize
- end
- end
- end
-
- result.magic_comments.each do |magic_comment|
- on_magic_comment(magic_comment.key, magic_comment.value)
- end
-
- unless result.data_loc.nil?
- on___end__(result.data_loc.slice.each_line.first)
- end
-
- result.warnings.each do |warning|
- bounds(warning.location)
-
- if warning.level == :default
- warning(warning.message)
- else
- case warning.type
- when :ambiguous_first_argument_plus
- on_arg_ambiguous("+")
- when :ambiguous_first_argument_minus
- on_arg_ambiguous("-")
- when :ambiguous_slash
- on_arg_ambiguous("/")
- else
- warn(warning.message)
- end
- end
- end
-
- if error?
- result.errors.each do |error|
- location = error.location
- bounds(location)
-
- case error.type
- when :alias_argument
- on_alias_error("can't make alias for the number variables", location.slice)
- when :argument_formal_class
- on_param_error("formal argument cannot be a class variable", location.slice)
- when :argument_format_constant
- on_param_error("formal argument cannot be a constant", location.slice)
- when :argument_formal_global
- on_param_error("formal argument cannot be a global variable", location.slice)
- when :argument_formal_ivar
- on_param_error("formal argument cannot be an instance variable", location.slice)
- when :class_name, :module_name
- on_class_name_error("class/module name must be CONSTANT", location.slice)
- else
- on_parse_error(error.message)
- end
- end
-
- nil
- else
- result.value.accept(self)
- end
- end
-
- ##########################################################################
- # Visitor methods
- ##########################################################################
-
- # alias foo bar
- # ^^^^^^^^^^^^^
- def visit_alias_method_node(node)
- new_name = visit(node.new_name)
- old_name = visit(node.old_name)
-
- bounds(node.location)
- on_alias(new_name, old_name)
- end
-
- # alias $foo $bar
- # ^^^^^^^^^^^^^^^
- def visit_alias_global_variable_node(node)
- new_name = visit_alias_global_variable_node_value(node.new_name)
- old_name = visit_alias_global_variable_node_value(node.old_name)
-
- bounds(node.location)
- on_var_alias(new_name, old_name)
- end
-
- # Visit one side of an alias global variable node.
- private def visit_alias_global_variable_node_value(node)
- bounds(node.location)
-
- case node
- when BackReferenceReadNode
- on_backref(node.slice)
- when GlobalVariableReadNode
- on_gvar(node.name.to_s)
- else
- raise
- end
- end
-
- # foo => bar | baz
- # ^^^^^^^^^
- def visit_alternation_pattern_node(node)
- left = visit_pattern_node(node.left)
- right = visit_pattern_node(node.right)
-
- bounds(node.location)
- on_binary(left, :|, right)
- end
-
- # Visit a pattern within a pattern match. This is used to bypass the
- # parenthesis node that can be used to wrap patterns.
- private def visit_pattern_node(node)
- if node.is_a?(ParenthesesNode)
- visit(node.body)
- else
- visit(node)
- end
- end
-
- # a and b
- # ^^^^^^^
- def visit_and_node(node)
- left = visit(node.left)
- right = visit(node.right)
-
- bounds(node.location)
- on_binary(left, node.operator.to_sym, right)
- end
-
- # []
- # ^^
- def visit_array_node(node)
- case (opening = node.opening)
- when /^%w/
- opening_loc = node.opening_loc
- bounds(opening_loc)
- on_qwords_beg(opening)
-
- elements = on_qwords_new
- previous = nil
-
- node.elements.each do |element|
- visit_words_sep(opening_loc, previous, element)
-
- bounds(element.location)
- elements = on_qwords_add(elements, on_tstring_content(element.content))
-
- previous = element
- end
-
- bounds(node.closing_loc)
- on_tstring_end(node.closing)
- when /^%i/
- opening_loc = node.opening_loc
- bounds(opening_loc)
- on_qsymbols_beg(opening)
-
- elements = on_qsymbols_new
- previous = nil
-
- node.elements.each do |element|
- visit_words_sep(opening_loc, previous, element)
-
- bounds(element.location)
- elements = on_qsymbols_add(elements, on_tstring_content(element.value))
-
- previous = element
- end
-
- bounds(node.closing_loc)
- on_tstring_end(node.closing)
- when /^%W/
- opening_loc = node.opening_loc
- bounds(opening_loc)
- on_words_beg(opening)
-
- elements = on_words_new
- previous = nil
-
- node.elements.each do |element|
- visit_words_sep(opening_loc, previous, element)
-
- bounds(element.location)
- elements =
- on_words_add(
- elements,
- if element.is_a?(StringNode)
- on_word_add(on_word_new, on_tstring_content(element.content))
- else
- element.parts.inject(on_word_new) do |word, part|
- word_part =
- if part.is_a?(StringNode)
- bounds(part.location)
- on_tstring_content(part.content)
- else
- visit(part)
- end
-
- on_word_add(word, word_part)
- end
- end
- )
-
- previous = element
- end
-
- bounds(node.closing_loc)
- on_tstring_end(node.closing)
- when /^%I/
- opening_loc = node.opening_loc
- bounds(opening_loc)
- on_symbols_beg(opening)
-
- elements = on_symbols_new
- previous = nil
-
- node.elements.each do |element|
- visit_words_sep(opening_loc, previous, element)
-
- bounds(element.location)
- elements =
- on_symbols_add(
- elements,
- if element.is_a?(SymbolNode)
- on_word_add(on_word_new, on_tstring_content(element.value))
- else
- element.parts.inject(on_word_new) do |word, part|
- word_part =
- if part.is_a?(StringNode)
- bounds(part.location)
- on_tstring_content(part.content)
- else
- visit(part)
- end
-
- on_word_add(word, word_part)
- end
- end
- )
-
- previous = element
- end
-
- bounds(node.closing_loc)
- on_tstring_end(node.closing)
- else
- bounds(node.opening_loc)
- on_lbracket(opening)
-
- elements = visit_arguments(node.elements) unless node.elements.empty?
-
- bounds(node.closing_loc)
- on_rbracket(node.closing)
- end
-
- bounds(node.location)
- on_array(elements)
- end
-
- # Dispatch a words_sep event that contains the space between the elements
- # of list literals.
- private def visit_words_sep(opening_loc, previous, current)
- end_offset = (previous.nil? ? opening_loc : previous.location).end_offset
- start_offset = current.location.start_offset
-
- if end_offset != start_offset
- bounds(current.location.copy(start_offset: end_offset))
- on_words_sep(source.byteslice(end_offset...start_offset))
- end
- end
-
- # Visit a list of elements, like the elements of an array or arguments.
- private def visit_arguments(elements)
- bounds(elements.first.location)
- elements.inject(on_args_new) do |args, element|
- arg = visit(element)
- bounds(element.location)
-
- case element
- when BlockArgumentNode
- on_args_add_block(args, arg)
- when SplatNode
- on_args_add_star(args, arg)
- else
- on_args_add(args, arg)
- end
- end
- end
-
- # foo => [bar]
- # ^^^^^
- def visit_array_pattern_node(node)
- constant = visit(node.constant)
- requireds = visit_all(node.requireds) if node.requireds.any?
- rest =
- if (rest_node = node.rest).is_a?(SplatNode)
- if rest_node.expression.nil?
- bounds(rest_node.location)
- on_var_field(nil)
- else
- visit(rest_node.expression)
- end
- end
-
- posts = visit_all(node.posts) if node.posts.any?
-
- bounds(node.location)
- on_aryptn(constant, requireds, rest, posts)
- end
-
- # foo(bar)
- # ^^^
- def visit_arguments_node(node)
- arguments, _ = visit_call_node_arguments(node, nil, false)
- arguments
- end
-
- # { a: 1 }
- # ^^^^
- def visit_assoc_node(node)
- key = visit(node.key)
- value = visit(node.value)
-
- bounds(node.location)
- on_assoc_new(key, value)
- end
-
- # def foo(**); bar(**); end
- # ^^
- #
- # { **foo }
- # ^^^^^
- def visit_assoc_splat_node(node)
- value = visit(node.value)
-
- bounds(node.location)
- on_assoc_splat(value)
- end
-
- # $+
- # ^^
- def visit_back_reference_read_node(node)
- bounds(node.location)
- on_backref(node.slice)
- end
-
- # begin end
- # ^^^^^^^^^
- def visit_begin_node(node)
- clauses = visit_begin_node_clauses(node.begin_keyword_loc, node, false)
-
- bounds(node.location)
- on_begin(clauses)
- end
-
- # Visit the clauses of a begin node to form an on_bodystmt call.
- private def visit_begin_node_clauses(location, node, allow_newline)
- statements =
- if node.statements.nil?
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- body = node.statements.body
- body.unshift(nil) if void_stmt?(location, node.statements.body[0].location, allow_newline)
-
- bounds(node.statements.location)
- visit_statements_node_body(body)
- end
-
- rescue_clause = visit(node.rescue_clause)
- else_clause =
- unless (else_clause_node = node.else_clause).nil?
- else_statements =
- if else_clause_node.statements.nil?
- [nil]
- else
- body = else_clause_node.statements.body
- body.unshift(nil) if void_stmt?(else_clause_node.else_keyword_loc, else_clause_node.statements.body[0].location, allow_newline)
- body
- end
-
- bounds(else_clause_node.location)
- visit_statements_node_body(else_statements)
- end
- ensure_clause = visit(node.ensure_clause)
-
- bounds(node.location)
- on_bodystmt(statements, rescue_clause, else_clause, ensure_clause)
- end
-
- # Visit the body of a structure that can have either a set of statements
- # or statements wrapped in rescue/else/ensure.
- private def visit_body_node(location, node, allow_newline = false)
- case node
- when nil
- bounds(location)
- on_bodystmt(visit_statements_node_body([nil]), nil, nil, nil)
- when StatementsNode
- body = [*node.body]
- body.unshift(nil) if void_stmt?(location, body[0].location, allow_newline)
- stmts = visit_statements_node_body(body)
-
- bounds(node.body.first.location)
- on_bodystmt(stmts, nil, nil, nil)
- when BeginNode
- visit_begin_node_clauses(location, node, allow_newline)
- else
- raise
- end
- end
-
- # foo(&bar)
- # ^^^^
- def visit_block_argument_node(node)
- visit(node.expression)
- end
-
- # foo { |; bar| }
- # ^^^
- def visit_block_local_variable_node(node)
- bounds(node.location)
- on_ident(node.name.to_s)
- end
-
- # Visit a BlockNode.
- def visit_block_node(node)
- braces = node.opening == "{"
- parameters = visit(node.parameters)
-
- body =
- case node.body
- when nil
- bounds(node.location)
- stmts = on_stmts_add(on_stmts_new, on_void_stmt)
-
- bounds(node.location)
- braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
- when StatementsNode
- stmts = node.body.body
- stmts.unshift(nil) if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false)
- stmts = visit_statements_node_body(stmts)
-
- bounds(node.body.location)
- braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
- when BeginNode
- visit_body_node(node.parameters&.location || node.opening_loc, node.body)
- else
- raise
- end
-
- if braces
- bounds(node.location)
- on_brace_block(parameters, body)
- else
- bounds(node.location)
- on_do_block(parameters, body)
- end
- end
-
- # def foo(&bar); end
- # ^^^^
- def visit_block_parameter_node(node)
- if node.name_loc.nil?
- bounds(node.location)
- on_blockarg(nil)
- else
- bounds(node.name_loc)
- name = visit_token(node.name.to_s)
-
- bounds(node.location)
- on_blockarg(name)
- end
- end
-
- # A block's parameters.
- def visit_block_parameters_node(node)
- parameters =
- if node.parameters.nil?
- on_params(nil, nil, nil, nil, nil, nil, nil)
- else
- visit(node.parameters)
- end
-
- locals =
- if node.locals.any?
- visit_all(node.locals)
- else
- false
- end
-
- bounds(node.location)
- on_block_var(parameters, locals)
- end
-
- # break
- # ^^^^^
- #
- # break foo
- # ^^^^^^^^^
- def visit_break_node(node)
- if node.arguments.nil?
- bounds(node.location)
- on_break(on_args_new)
- else
- arguments = visit(node.arguments)
-
- bounds(node.location)
- on_break(arguments)
- end
- end
-
- # foo
- # ^^^
- #
- # foo.bar
- # ^^^^^^^
- #
- # foo.bar() {}
- # ^^^^^^^^^^^^
- def visit_call_node(node)
- if node.call_operator_loc.nil?
- case node.name
- when :[]
- receiver = visit(node.receiver)
- arguments, block = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
-
- bounds(node.location)
- call = on_aref(receiver, arguments)
-
- if block.nil?
- call
- else
- bounds(node.location)
- on_method_add_block(call, block)
- end
- when :[]=
- receiver = visit(node.receiver)
-
- *arguments, last_argument = node.arguments.arguments
- arguments << node.block if !node.block.nil?
-
- arguments =
- if arguments.any?
- args = visit_arguments(arguments)
-
- if !node.block.nil?
- args
- else
- bounds(arguments.first.location)
- on_args_add_block(args, false)
- end
- end
-
- bounds(node.location)
- call = on_aref_field(receiver, arguments)
- value = visit_write_value(last_argument)
-
- bounds(last_argument.location)
- on_assign(call, value)
- when :-@, :+@, :~
- receiver = visit(node.receiver)
-
- bounds(node.location)
- on_unary(node.name, receiver)
- when :!
- receiver = visit(node.receiver)
-
- bounds(node.location)
- on_unary(node.message == "not" ? :not : :!, receiver)
- when *BINARY_OPERATORS
- receiver = visit(node.receiver)
- value = visit(node.arguments.arguments.first)
-
- bounds(node.location)
- on_binary(receiver, node.name, value)
- else
- bounds(node.message_loc)
- message = visit_token(node.message, false)
-
- if node.variable_call?
- on_vcall(message)
- else
- arguments, block = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location))
- call =
- if node.opening_loc.nil? && arguments&.any?
- bounds(node.location)
- on_command(message, arguments)
- elsif !node.opening_loc.nil?
- bounds(node.location)
- on_method_add_arg(on_fcall(message), on_arg_paren(arguments))
- else
- bounds(node.location)
- on_method_add_arg(on_fcall(message), on_args_new)
- end
-
- if block.nil?
- call
- else
- bounds(node.block.location)
- on_method_add_block(call, block)
- end
- end
- end
- else
- receiver = visit(node.receiver)
-
- bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
-
- message =
- if node.message_loc.nil?
- :call
- else
- bounds(node.message_loc)
- visit_token(node.message, false)
- end
-
- if node.name.end_with?("=") && !node.message.end_with?("=") && !node.arguments.nil? && node.block.nil?
- value = visit_write_value(node.arguments.arguments.first)
-
- bounds(node.location)
- on_assign(on_field(receiver, call_operator, message), value)
- else
- arguments, block = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location))
- call =
- if node.opening_loc.nil?
- bounds(node.location)
-
- if node.arguments.nil? && !node.block.is_a?(BlockArgumentNode)
- on_call(receiver, call_operator, message)
- else
- on_command_call(receiver, call_operator, message, arguments)
- end
- else
- bounds(node.opening_loc)
- arguments = on_arg_paren(arguments)
-
- bounds(node.location)
- on_method_add_arg(on_call(receiver, call_operator, message), arguments)
- end
-
- if block.nil?
- call
- else
- bounds(node.block.location)
- on_method_add_block(call, block)
- end
- end
- end
- end
-
- # Visit the arguments and block of a call node and return the arguments
- # and block as they should be used.
- private def visit_call_node_arguments(arguments_node, block_node, trailing_comma)
- arguments = arguments_node&.arguments || []
- block = block_node
-
- if block.is_a?(BlockArgumentNode)
- arguments << block
- block = nil
- end
-
- [
- if arguments.length == 1 && arguments.first.is_a?(ForwardingArgumentsNode)
- visit(arguments.first)
- elsif arguments.any?
- args = visit_arguments(arguments)
-
- if block_node.is_a?(BlockArgumentNode) || arguments.last.is_a?(ForwardingArgumentsNode) || command?(arguments.last) || trailing_comma
- args
- else
- bounds(arguments.first.location)
- on_args_add_block(args, false)
- end
- end,
- visit(block)
- ]
- end
-
- # Returns true if the given node is a command node.
- private def command?(node)
- node.is_a?(CallNode) &&
- node.opening_loc.nil? &&
- (!node.arguments.nil? || node.block.is_a?(BlockArgumentNode)) &&
- !BINARY_OPERATORS.include?(node.name)
- end
-
- # foo.bar += baz
- # ^^^^^^^^^^^^^^^
- def visit_call_operator_write_node(node)
- receiver = visit(node.receiver)
-
- bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
-
- bounds(node.message_loc)
- message = visit_token(node.message)
-
- bounds(node.location)
- target = on_field(receiver, call_operator, message)
-
- bounds(node.binary_operator_loc)
- operator = on_op("#{node.binary_operator}=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # foo.bar &&= baz
- # ^^^^^^^^^^^^^^^
- def visit_call_and_write_node(node)
- receiver = visit(node.receiver)
-
- bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
-
- bounds(node.message_loc)
- message = visit_token(node.message)
-
- bounds(node.location)
- target = on_field(receiver, call_operator, message)
-
- bounds(node.operator_loc)
- operator = on_op("&&=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # foo.bar ||= baz
- # ^^^^^^^^^^^^^^^
- def visit_call_or_write_node(node)
- receiver = visit(node.receiver)
-
- bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
-
- bounds(node.message_loc)
- message = visit_token(node.message)
-
- bounds(node.location)
- target = on_field(receiver, call_operator, message)
-
- bounds(node.operator_loc)
- operator = on_op("||=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # foo.bar, = 1
- # ^^^^^^^
- def visit_call_target_node(node)
- if node.call_operator == "::"
- receiver = visit(node.receiver)
-
- bounds(node.message_loc)
- message = visit_token(node.message)
-
- bounds(node.location)
- on_const_path_field(receiver, message)
- else
- receiver = visit(node.receiver)
-
- bounds(node.call_operator_loc)
- call_operator = visit_token(node.call_operator)
-
- bounds(node.message_loc)
- message = visit_token(node.message)
-
- bounds(node.location)
- on_field(receiver, call_operator, message)
- end
- end
-
- # foo => bar => baz
- # ^^^^^^^^^^
- def visit_capture_pattern_node(node)
- value = visit(node.value)
- target = visit(node.target)
-
- bounds(node.location)
- on_binary(value, :"=>", target)
- end
-
- # case foo; when bar; end
- # ^^^^^^^^^^^^^^^^^^^^^^^
- def visit_case_node(node)
- predicate = visit(node.predicate)
- clauses =
- node.conditions.reverse_each.inject(visit(node.else_clause)) do |current, condition|
- on_when(*visit(condition), current)
- end
-
- bounds(node.location)
- on_case(predicate, clauses)
- end
-
- # case foo; in bar; end
- # ^^^^^^^^^^^^^^^^^^^^^
- def visit_case_match_node(node)
- predicate = visit(node.predicate)
- clauses =
- node.conditions.reverse_each.inject(visit(node.else_clause)) do |current, condition|
- on_in(*visit(condition), current)
- end
-
- bounds(node.location)
- on_case(predicate, clauses)
- end
-
- # class Foo; end
- # ^^^^^^^^^^^^^^
- def visit_class_node(node)
- constant_path =
- if node.constant_path.is_a?(ConstantReadNode)
- bounds(node.constant_path.location)
- on_const_ref(on_const(node.constant_path.name.to_s))
- else
- visit(node.constant_path)
- end
-
- superclass = visit(node.superclass)
- bodystmt = visit_body_node(node.superclass&.location || node.constant_path.location, node.body, node.superclass.nil?)
-
- bounds(node.location)
- on_class(constant_path, superclass, bodystmt)
- end
-
- # @@foo
- # ^^^^^
- def visit_class_variable_read_node(node)
- bounds(node.location)
- on_var_ref(on_cvar(node.slice))
- end
-
- # @@foo = 1
- # ^^^^^^^^^
- #
- # @@foo, @@bar = 1
- # ^^^^^ ^^^^^
- def visit_class_variable_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_cvar(node.name.to_s))
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_assign(target, value)
- end
-
- # @@foo += bar
- # ^^^^^^^^^^^^
- def visit_class_variable_operator_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_cvar(node.name.to_s))
-
- bounds(node.binary_operator_loc)
- operator = on_op("#{node.binary_operator}=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # @@foo &&= bar
- # ^^^^^^^^^^^^^
- def visit_class_variable_and_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_cvar(node.name.to_s))
-
- bounds(node.operator_loc)
- operator = on_op("&&=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # @@foo ||= bar
- # ^^^^^^^^^^^^^
- def visit_class_variable_or_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_cvar(node.name.to_s))
-
- bounds(node.operator_loc)
- operator = on_op("||=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # @@foo, = bar
- # ^^^^^
- def visit_class_variable_target_node(node)
- bounds(node.location)
- on_var_field(on_cvar(node.name.to_s))
- end
-
- # Foo
- # ^^^
- def visit_constant_read_node(node)
- bounds(node.location)
- on_var_ref(on_const(node.name.to_s))
- end
-
- # Foo = 1
- # ^^^^^^^
- #
- # Foo, Bar = 1
- # ^^^ ^^^
- def visit_constant_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_const(node.name.to_s))
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_assign(target, value)
- end
-
- # Foo += bar
- # ^^^^^^^^^^^
- def visit_constant_operator_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_const(node.name.to_s))
-
- bounds(node.binary_operator_loc)
- operator = on_op("#{node.binary_operator}=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # Foo &&= bar
- # ^^^^^^^^^^^^
- def visit_constant_and_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_const(node.name.to_s))
-
- bounds(node.operator_loc)
- operator = on_op("&&=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # Foo ||= bar
- # ^^^^^^^^^^^^
- def visit_constant_or_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_const(node.name.to_s))
-
- bounds(node.operator_loc)
- operator = on_op("||=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # Foo, = bar
- # ^^^
- def visit_constant_target_node(node)
- bounds(node.location)
- on_var_field(on_const(node.name.to_s))
- end
-
- # Foo::Bar
- # ^^^^^^^^
- def visit_constant_path_node(node)
- if node.parent.nil?
- bounds(node.name_loc)
- child = on_const(node.name.to_s)
-
- bounds(node.location)
- on_top_const_ref(child)
- else
- parent = visit(node.parent)
-
- bounds(node.name_loc)
- child = on_const(node.name.to_s)
-
- bounds(node.location)
- on_const_path_ref(parent, child)
- end
- end
-
- # Foo::Bar = 1
- # ^^^^^^^^^^^^
- #
- # Foo::Foo, Bar::Bar = 1
- # ^^^^^^^^ ^^^^^^^^
- def visit_constant_path_write_node(node)
- target = visit_constant_path_write_node_target(node.target)
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_assign(target, value)
- end
-
- # Visit a constant path that is part of a write node.
- private def visit_constant_path_write_node_target(node)
- if node.parent.nil?
- bounds(node.name_loc)
- child = on_const(node.name.to_s)
-
- bounds(node.location)
- on_top_const_field(child)
- else
- parent = visit(node.parent)
-
- bounds(node.name_loc)
- child = on_const(node.name.to_s)
-
- bounds(node.location)
- on_const_path_field(parent, child)
- end
- end
-
- # Foo::Bar += baz
- # ^^^^^^^^^^^^^^^
- def visit_constant_path_operator_write_node(node)
- target = visit_constant_path_write_node_target(node.target)
- value = visit(node.value)
-
- bounds(node.binary_operator_loc)
- operator = on_op("#{node.binary_operator}=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # Foo::Bar &&= baz
- # ^^^^^^^^^^^^^^^^
- def visit_constant_path_and_write_node(node)
- target = visit_constant_path_write_node_target(node.target)
- value = visit(node.value)
-
- bounds(node.operator_loc)
- operator = on_op("&&=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # Foo::Bar ||= baz
- # ^^^^^^^^^^^^^^^^
- def visit_constant_path_or_write_node(node)
- target = visit_constant_path_write_node_target(node.target)
- value = visit(node.value)
-
- bounds(node.operator_loc)
- operator = on_op("||=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # Foo::Bar, = baz
- # ^^^^^^^^
- def visit_constant_path_target_node(node)
- visit_constant_path_write_node_target(node)
- end
-
- # def foo; end
- # ^^^^^^^^^^^^
- #
- # def self.foo; end
- # ^^^^^^^^^^^^^^^^^
- def visit_def_node(node)
- receiver = visit(node.receiver)
- operator =
- if !node.operator_loc.nil?
- bounds(node.operator_loc)
- visit_token(node.operator)
- end
-
- bounds(node.name_loc)
- name = visit_token(node.name_loc.slice)
-
- parameters =
- if node.parameters.nil?
- bounds(node.location)
- on_params(nil, nil, nil, nil, nil, nil, nil)
- else
- visit(node.parameters)
- end
-
- if !node.lparen_loc.nil?
- bounds(node.lparen_loc)
- parameters = on_paren(parameters)
- end
-
- bodystmt =
- if node.equal_loc.nil?
- visit_body_node(node.rparen_loc || node.end_keyword_loc, node.body)
- else
- body = visit(node.body.body.first)
-
- bounds(node.body.location)
- on_bodystmt(body, nil, nil, nil)
- end
-
- bounds(node.location)
- if receiver.nil?
- on_def(name, parameters, bodystmt)
- else
- on_defs(receiver, operator, name, parameters, bodystmt)
- end
- end
-
- # defined? a
- # ^^^^^^^^^^
- #
- # defined?(a)
- # ^^^^^^^^^^^
- def visit_defined_node(node)
- bounds(node.location)
- on_defined(visit(node.value))
- end
-
- # if foo then bar else baz end
- # ^^^^^^^^^^^^
- def visit_else_node(node)
- statements =
- if node.statements.nil?
- [nil]
- else
- body = node.statements.body
- body.unshift(nil) if void_stmt?(node.else_keyword_loc, node.statements.body[0].location, false)
- body
- end
-
- bounds(node.location)
- on_else(visit_statements_node_body(statements))
- end
-
- # "foo #{bar}"
- # ^^^^^^
- def visit_embedded_statements_node(node)
- bounds(node.opening_loc)
- on_embexpr_beg(node.opening)
-
- statements =
- if node.statements.nil?
- bounds(node.location)
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- visit(node.statements)
- end
-
- bounds(node.closing_loc)
- on_embexpr_end(node.closing)
-
- bounds(node.location)
- on_string_embexpr(statements)
- end
-
- # "foo #@bar"
- # ^^^^^
- def visit_embedded_variable_node(node)
- bounds(node.operator_loc)
- on_embvar(node.operator)
-
- variable = visit(node.variable)
-
- bounds(node.location)
- on_string_dvar(variable)
- end
-
- # Visit an EnsureNode node.
- def visit_ensure_node(node)
- statements =
- if node.statements.nil?
- [nil]
- else
- body = node.statements.body
- body.unshift(nil) if void_stmt?(node.ensure_keyword_loc, body[0].location, false)
- body
- end
-
- statements = visit_statements_node_body(statements)
-
- bounds(node.location)
- on_ensure(statements)
- end
-
- # false
- # ^^^^^
- def visit_false_node(node)
- bounds(node.location)
- on_var_ref(on_kw("false"))
- end
-
- # foo => [*, bar, *]
- # ^^^^^^^^^^^
- def visit_find_pattern_node(node)
- constant = visit(node.constant)
- left =
- if node.left.expression.nil?
- bounds(node.left.location)
- on_var_field(nil)
- else
- visit(node.left.expression)
- end
-
- requireds = visit_all(node.requireds) if node.requireds.any?
- right =
- if node.right.expression.nil?
- bounds(node.right.location)
- on_var_field(nil)
- else
- visit(node.right.expression)
- end
-
- bounds(node.location)
- on_fndptn(constant, left, requireds, right)
- end
-
- # if foo .. bar; end
- # ^^^^^^^^^^
- def visit_flip_flop_node(node)
- left = visit(node.left)
- right = visit(node.right)
-
- bounds(node.location)
- if node.exclude_end?
- on_dot3(left, right)
- else
- on_dot2(left, right)
- end
- end
-
- # 1.0
- # ^^^
- def visit_float_node(node)
- visit_number_node(node) { |text| on_float(text) }
- end
-
- # for foo in bar do end
- # ^^^^^^^^^^^^^^^^^^^^^
- def visit_for_node(node)
- index = visit(node.index)
- collection = visit(node.collection)
- statements =
- if node.statements.nil?
- bounds(node.location)
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- visit(node.statements)
- end
-
- bounds(node.location)
- on_for(index, collection, statements)
- end
-
- # def foo(...); bar(...); end
- # ^^^
- def visit_forwarding_arguments_node(node)
- bounds(node.location)
- on_args_forward
- end
-
- # def foo(...); end
- # ^^^
- def visit_forwarding_parameter_node(node)
- bounds(node.location)
- on_args_forward
- end
-
- # super
- # ^^^^^
- #
- # super {}
- # ^^^^^^^^
- def visit_forwarding_super_node(node)
- if node.block.nil?
- bounds(node.location)
- on_zsuper
- else
- block = visit(node.block)
-
- bounds(node.location)
- on_method_add_block(on_zsuper, block)
- end
- end
-
- # $foo
- # ^^^^
- def visit_global_variable_read_node(node)
- bounds(node.location)
- on_var_ref(on_gvar(node.name.to_s))
- end
-
- # $foo = 1
- # ^^^^^^^^
- #
- # $foo, $bar = 1
- # ^^^^ ^^^^
- def visit_global_variable_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_gvar(node.name.to_s))
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_assign(target, value)
- end
-
- # $foo += bar
- # ^^^^^^^^^^^
- def visit_global_variable_operator_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_gvar(node.name.to_s))
-
- bounds(node.binary_operator_loc)
- operator = on_op("#{node.binary_operator}=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # $foo &&= bar
- # ^^^^^^^^^^^^
- def visit_global_variable_and_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_gvar(node.name.to_s))
-
- bounds(node.operator_loc)
- operator = on_op("&&=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # $foo ||= bar
- # ^^^^^^^^^^^^
- def visit_global_variable_or_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_gvar(node.name.to_s))
-
- bounds(node.operator_loc)
- operator = on_op("||=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # $foo, = bar
- # ^^^^
- def visit_global_variable_target_node(node)
- bounds(node.location)
- on_var_field(on_gvar(node.name.to_s))
- end
-
- # {}
- # ^^
- def visit_hash_node(node)
- elements =
- if node.elements.any?
- args = visit_all(node.elements)
-
- bounds(node.elements.first.location)
- on_assoclist_from_args(args)
- end
-
- bounds(node.location)
- on_hash(elements)
- end
-
- # foo => {}
- # ^^
- def visit_hash_pattern_node(node)
- constant = visit(node.constant)
- elements =
- if node.elements.any? || !node.rest.nil?
- node.elements.map do |element|
- [
- if (key = element.key).opening_loc.nil?
- visit(key)
- else
- bounds(key.value_loc)
- if (value = key.value).empty?
- on_string_content
- else
- on_string_add(on_string_content, on_tstring_content(value))
- end
- end,
- visit(element.value)
- ]
- end
- end
-
- rest =
- case node.rest
- when AssocSplatNode
- visit(node.rest.value)
- when NoKeywordsParameterNode
- bounds(node.rest.location)
- on_var_field(visit(node.rest))
- end
-
- bounds(node.location)
- on_hshptn(constant, elements, rest)
- end
-
- # if foo then bar end
- # ^^^^^^^^^^^^^^^^^^^
- #
- # bar if foo
- # ^^^^^^^^^^
- #
- # foo ? bar : baz
- # ^^^^^^^^^^^^^^^
- def visit_if_node(node)
- if node.then_keyword == "?"
- predicate = visit(node.predicate)
- truthy = visit(node.statements.body.first)
- falsy = visit(node.subsequent.statements.body.first)
-
- bounds(node.location)
- on_ifop(predicate, truthy, falsy)
- elsif node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
- predicate = visit(node.predicate)
- statements =
- if node.statements.nil?
- bounds(node.location)
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- visit(node.statements)
- end
- subsequent = visit(node.subsequent)
-
- bounds(node.location)
- if node.if_keyword == "if"
- on_if(predicate, statements, subsequent)
- else
- on_elsif(predicate, statements, subsequent)
- end
- else
- statements = visit(node.statements.body.first)
- predicate = visit(node.predicate)
-
- bounds(node.location)
- on_if_mod(predicate, statements)
- end
- end
-
- # 1i
- # ^^
- def visit_imaginary_node(node)
- visit_number_node(node) { |text| on_imaginary(text) }
- end
-
- # { foo: }
- # ^^^^
- def visit_implicit_node(node)
- end
-
- # foo { |bar,| }
- # ^
- def visit_implicit_rest_node(node)
- bounds(node.location)
- on_excessed_comma
- end
-
- # case foo; in bar; end
- # ^^^^^^^^^^^^^^^^^^^^^
- def visit_in_node(node)
- # This is a special case where we're not going to call on_in directly
- # because we don't have access to the subsequent. Instead, we'll return
- # the component parts and let the parent node handle it.
- pattern = visit_pattern_node(node.pattern)
- statements =
- if node.statements.nil?
- bounds(node.location)
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- visit(node.statements)
- end
-
- [pattern, statements]
- end
-
- # foo[bar] += baz
- # ^^^^^^^^^^^^^^^
- def visit_index_operator_write_node(node)
- receiver = visit(node.receiver)
- arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
-
- bounds(node.location)
- target = on_aref_field(receiver, arguments)
-
- bounds(node.binary_operator_loc)
- operator = on_op("#{node.binary_operator}=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # foo[bar] &&= baz
- # ^^^^^^^^^^^^^^^^
- def visit_index_and_write_node(node)
- receiver = visit(node.receiver)
- arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
-
- bounds(node.location)
- target = on_aref_field(receiver, arguments)
-
- bounds(node.operator_loc)
- operator = on_op("&&=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # foo[bar] ||= baz
- # ^^^^^^^^^^^^^^^^
- def visit_index_or_write_node(node)
- receiver = visit(node.receiver)
- arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
-
- bounds(node.location)
- target = on_aref_field(receiver, arguments)
-
- bounds(node.operator_loc)
- operator = on_op("||=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # foo[bar], = 1
- # ^^^^^^^^
- def visit_index_target_node(node)
- receiver = visit(node.receiver)
- arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
-
- bounds(node.location)
- on_aref_field(receiver, arguments)
- end
-
- # @foo
- # ^^^^
- def visit_instance_variable_read_node(node)
- bounds(node.location)
- on_var_ref(on_ivar(node.name.to_s))
- end
-
- # @foo = 1
- # ^^^^^^^^
- def visit_instance_variable_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_ivar(node.name.to_s))
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_assign(target, value)
- end
-
- # @foo += bar
- # ^^^^^^^^^^^
- def visit_instance_variable_operator_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_ivar(node.name.to_s))
-
- bounds(node.binary_operator_loc)
- operator = on_op("#{node.binary_operator}=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # @foo &&= bar
- # ^^^^^^^^^^^^
- def visit_instance_variable_and_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_ivar(node.name.to_s))
-
- bounds(node.operator_loc)
- operator = on_op("&&=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # @foo ||= bar
- # ^^^^^^^^^^^^
- def visit_instance_variable_or_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_ivar(node.name.to_s))
-
- bounds(node.operator_loc)
- operator = on_op("||=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # @foo, = bar
- # ^^^^
- def visit_instance_variable_target_node(node)
- bounds(node.location)
- on_var_field(on_ivar(node.name.to_s))
- end
-
- # 1
- # ^
- def visit_integer_node(node)
- visit_number_node(node) { |text| on_int(text) }
- end
-
- # if /foo #{bar}/ then end
- # ^^^^^^^^^^^^
- def visit_interpolated_match_last_line_node(node)
- bounds(node.opening_loc)
- on_regexp_beg(node.opening)
-
- bounds(node.parts.first.location)
- parts =
- node.parts.inject(on_regexp_new) do |content, part|
- on_regexp_add(content, visit_string_content(part))
- end
-
- bounds(node.closing_loc)
- closing = on_regexp_end(node.closing)
-
- bounds(node.location)
- on_regexp_literal(parts, closing)
- end
-
- # /foo #{bar}/
- # ^^^^^^^^^^^^
- def visit_interpolated_regular_expression_node(node)
- bounds(node.opening_loc)
- on_regexp_beg(node.opening)
-
- bounds(node.parts.first.location)
- parts =
- node.parts.inject(on_regexp_new) do |content, part|
- on_regexp_add(content, visit_string_content(part))
- end
-
- bounds(node.closing_loc)
- closing = on_regexp_end(node.closing)
-
- bounds(node.location)
- on_regexp_literal(parts, closing)
- end
-
- # "foo #{bar}"
- # ^^^^^^^^^^^^
- def visit_interpolated_string_node(node)
- if node.opening&.start_with?("<<~")
- heredoc = visit_heredoc_string_node(node)
-
- bounds(node.location)
- on_string_literal(heredoc)
- elsif !node.heredoc? && node.parts.length > 1 && node.parts.any? { |part| (part.is_a?(StringNode) || part.is_a?(InterpolatedStringNode)) && !part.opening_loc.nil? }
- first, *rest = node.parts
- rest.inject(visit(first)) do |content, part|
- concat = visit(part)
-
- bounds(part.location)
- on_string_concat(content, concat)
- end
- else
- bounds(node.parts.first.location)
- parts =
- node.parts.inject(on_string_content) do |content, part|
- on_string_add(content, visit_string_content(part))
- end
-
- bounds(node.location)
- on_string_literal(parts)
- end
- end
-
- # :"foo #{bar}"
- # ^^^^^^^^^^^^^
- def visit_interpolated_symbol_node(node)
- bounds(node.parts.first.location)
- parts =
- node.parts.inject(on_string_content) do |content, part|
- on_string_add(content, visit_string_content(part))
- end
-
- bounds(node.location)
- on_dyna_symbol(parts)
- end
-
- # `foo #{bar}`
- # ^^^^^^^^^^^^
- def visit_interpolated_x_string_node(node)
- if node.opening.start_with?("<<~")
- heredoc = visit_heredoc_x_string_node(node)
-
- bounds(node.location)
- on_xstring_literal(heredoc)
- else
- bounds(node.parts.first.location)
- parts =
- node.parts.inject(on_xstring_new) do |content, part|
- on_xstring_add(content, visit_string_content(part))
- end
-
- bounds(node.location)
- on_xstring_literal(parts)
- end
- end
-
- # Visit an individual part of a string-like node.
- private def visit_string_content(part)
- if part.is_a?(StringNode)
- bounds(part.content_loc)
- on_tstring_content(part.content)
- else
- visit(part)
- end
- end
-
- # -> { it }
- # ^^
- def visit_it_local_variable_read_node(node)
- bounds(node.location)
- on_vcall(on_ident(node.slice))
- end
-
- # -> { it }
- # ^^^^^^^^^
- def visit_it_parameters_node(node)
- end
-
- # foo(bar: baz)
- # ^^^^^^^^
- def visit_keyword_hash_node(node)
- elements = visit_all(node.elements)
-
- bounds(node.location)
- on_bare_assoc_hash(elements)
- end
-
- # def foo(**bar); end
- # ^^^^^
- #
- # def foo(**); end
- # ^^
- def visit_keyword_rest_parameter_node(node)
- if node.name_loc.nil?
- bounds(node.location)
- on_kwrest_param(nil)
- else
- bounds(node.name_loc)
- name = on_ident(node.name.to_s)
-
- bounds(node.location)
- on_kwrest_param(name)
- end
- end
-
- # -> {}
- def visit_lambda_node(node)
- bounds(node.operator_loc)
- on_tlambda(node.operator)
-
- parameters =
- if node.parameters.is_a?(BlockParametersNode)
- # Ripper does not track block-locals within lambdas, so we skip
- # directly to the parameters here.
- params =
- if node.parameters.parameters.nil?
- bounds(node.location)
- on_params(nil, nil, nil, nil, nil, nil, nil)
- else
- visit(node.parameters.parameters)
- end
-
- if node.parameters.opening_loc.nil?
- params
- else
- bounds(node.parameters.opening_loc)
- on_paren(params)
- end
- else
- bounds(node.location)
- on_params(nil, nil, nil, nil, nil, nil, nil)
- end
-
- braces = node.opening == "{"
- if braces
- bounds(node.opening_loc)
- on_tlambeg(node.opening)
- end
-
- body =
- case node.body
- when nil
- bounds(node.location)
- stmts = on_stmts_add(on_stmts_new, on_void_stmt)
-
- bounds(node.location)
- braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
- when StatementsNode
- stmts = node.body.body
- stmts.unshift(nil) if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false)
- stmts = visit_statements_node_body(stmts)
-
- bounds(node.body.location)
- braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
- when BeginNode
- visit_body_node(node.opening_loc, node.body)
- else
- raise
- end
-
- bounds(node.location)
- on_lambda(parameters, body)
- end
-
- # foo
- # ^^^
- def visit_local_variable_read_node(node)
- bounds(node.location)
- on_var_ref(on_ident(node.slice))
- end
-
- # foo = 1
- # ^^^^^^^
- def visit_local_variable_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_ident(node.name_loc.slice))
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_assign(target, value)
- end
-
- # foo += bar
- # ^^^^^^^^^^
- def visit_local_variable_operator_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_ident(node.name_loc.slice))
-
- bounds(node.binary_operator_loc)
- operator = on_op("#{node.binary_operator}=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # foo &&= bar
- # ^^^^^^^^^^^
- def visit_local_variable_and_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_ident(node.name_loc.slice))
-
- bounds(node.operator_loc)
- operator = on_op("&&=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # foo ||= bar
- # ^^^^^^^^^^^
- def visit_local_variable_or_write_node(node)
- bounds(node.name_loc)
- target = on_var_field(on_ident(node.name_loc.slice))
-
- bounds(node.operator_loc)
- operator = on_op("||=")
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_opassign(target, operator, value)
- end
-
- # foo, = bar
- # ^^^
- def visit_local_variable_target_node(node)
- bounds(node.location)
- on_var_field(on_ident(node.name.to_s))
- end
-
- # if /foo/ then end
- # ^^^^^
- def visit_match_last_line_node(node)
- bounds(node.opening_loc)
- on_regexp_beg(node.opening)
-
- bounds(node.content_loc)
- tstring_content = on_tstring_content(node.content)
-
- bounds(node.closing_loc)
- closing = on_regexp_end(node.closing)
-
- on_regexp_literal(on_regexp_add(on_regexp_new, tstring_content), closing)
- end
-
- # foo in bar
- # ^^^^^^^^^^
- def visit_match_predicate_node(node)
- value = visit(node.value)
- pattern = on_in(visit_pattern_node(node.pattern), nil, nil)
-
- on_case(value, pattern)
- end
-
- # foo => bar
- # ^^^^^^^^^^
- def visit_match_required_node(node)
- value = visit(node.value)
- pattern = on_in(visit_pattern_node(node.pattern), nil, nil)
-
- on_case(value, pattern)
- end
-
- # /(?<foo>foo)/ =~ bar
- # ^^^^^^^^^^^^^^^^^^^^
- def visit_match_write_node(node)
- visit(node.call)
- end
-
- # A node that is missing from the syntax tree. This is only used in the
- # case of a syntax error.
- def visit_missing_node(node)
- raise "Cannot visit missing nodes directly."
- end
-
- # module Foo; end
- # ^^^^^^^^^^^^^^^
- def visit_module_node(node)
- constant_path =
- if node.constant_path.is_a?(ConstantReadNode)
- bounds(node.constant_path.location)
- on_const_ref(on_const(node.constant_path.name.to_s))
- else
- visit(node.constant_path)
- end
-
- bodystmt = visit_body_node(node.constant_path.location, node.body, true)
-
- bounds(node.location)
- on_module(constant_path, bodystmt)
- end
-
- # (foo, bar), bar = qux
- # ^^^^^^^^^^
- def visit_multi_target_node(node)
- bounds(node.location)
- targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, true)
-
- if node.lparen_loc.nil?
- targets
- else
- bounds(node.lparen_loc)
- on_mlhs_paren(targets)
- end
- end
-
- # Visit the targets of a multi-target node.
- private def visit_multi_target_node_targets(lefts, rest, rights, skippable)
- if skippable && lefts.length == 1 && lefts.first.is_a?(MultiTargetNode) && rest.nil? && rights.empty?
- return visit(lefts.first)
- end
-
- mlhs = on_mlhs_new
-
- lefts.each do |left|
- bounds(left.location)
- mlhs = on_mlhs_add(mlhs, visit(left))
- end
-
- case rest
- when nil
- # do nothing
- when ImplicitRestNode
- # these do not get put into the generated tree
- bounds(rest.location)
- on_excessed_comma
- else
- bounds(rest.location)
- mlhs = on_mlhs_add_star(mlhs, visit(rest))
- end
-
- if rights.any?
- bounds(rights.first.location)
- post = on_mlhs_new
-
- rights.each do |right|
- bounds(right.location)
- post = on_mlhs_add(post, visit(right))
- end
-
- mlhs = on_mlhs_add_post(mlhs, post)
- end
-
- mlhs
- end
-
- # foo, bar = baz
- # ^^^^^^^^^^^^^^
- def visit_multi_write_node(node)
- bounds(node.location)
- targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, true)
-
- unless node.lparen_loc.nil?
- bounds(node.lparen_loc)
- targets = on_mlhs_paren(targets)
- end
-
- value = visit_write_value(node.value)
-
- bounds(node.location)
- on_massign(targets, value)
- end
-
- # next
- # ^^^^
- #
- # next foo
- # ^^^^^^^^
- def visit_next_node(node)
- if node.arguments.nil?
- bounds(node.location)
- on_next(on_args_new)
- else
- arguments = visit(node.arguments)
-
- bounds(node.location)
- on_next(arguments)
- end
- end
-
- # nil
- # ^^^
- def visit_nil_node(node)
- bounds(node.location)
- on_var_ref(on_kw("nil"))
- end
-
- # def foo(**nil); end
- # ^^^^^
- def visit_no_keywords_parameter_node(node)
- bounds(node.location)
- on_nokw_param(nil)
-
- :nil
- end
-
- # -> { _1 + _2 }
- # ^^^^^^^^^^^^^^
- def visit_numbered_parameters_node(node)
- end
-
- # $1
- # ^^
- def visit_numbered_reference_read_node(node)
- bounds(node.location)
- on_backref(node.slice)
- end
-
- # def foo(bar: baz); end
- # ^^^^^^^^
- def visit_optional_keyword_parameter_node(node)
- bounds(node.name_loc)
- name = on_label("#{node.name}:")
- value = visit(node.value)
-
- [name, value]
- end
-
- # def foo(bar = 1); end
- # ^^^^^^^
- def visit_optional_parameter_node(node)
- bounds(node.name_loc)
- name = visit_token(node.name.to_s)
- value = visit(node.value)
-
- [name, value]
- end
-
- # a or b
- # ^^^^^^
- def visit_or_node(node)
- left = visit(node.left)
- right = visit(node.right)
-
- bounds(node.location)
- on_binary(left, node.operator.to_sym, right)
- end
-
- # def foo(bar, *baz); end
- # ^^^^^^^^^
- def visit_parameters_node(node)
- requireds = node.requireds.map { |required| required.is_a?(MultiTargetNode) ? visit_destructured_parameter_node(required) : visit(required) } if node.requireds.any?
- optionals = visit_all(node.optionals) if node.optionals.any?
- rest = visit(node.rest)
- posts = node.posts.map { |post| post.is_a?(MultiTargetNode) ? visit_destructured_parameter_node(post) : visit(post) } if node.posts.any?
- keywords = visit_all(node.keywords) if node.keywords.any?
- keyword_rest = visit(node.keyword_rest)
- block = visit(node.block)
-
- bounds(node.location)
- on_params(requireds, optionals, rest, posts, keywords, keyword_rest, block)
- end
-
- # Visit a destructured positional parameter node.
- private def visit_destructured_parameter_node(node)
- bounds(node.location)
- targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, false)
-
- bounds(node.lparen_loc)
- on_mlhs_paren(targets)
- end
-
- # ()
- # ^^
- #
- # (1)
- # ^^^
- def visit_parentheses_node(node)
- body =
- if node.body.nil?
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- visit(node.body)
- end
-
- bounds(node.location)
- on_paren(body)
- end
-
- # foo => ^(bar)
- # ^^^^^^
- def visit_pinned_expression_node(node)
- expression = visit(node.expression)
-
- bounds(node.location)
- on_begin(expression)
- end
-
- # foo = 1 and bar => ^foo
- # ^^^^
- def visit_pinned_variable_node(node)
- visit(node.variable)
- end
-
- # END {}
- # ^^^^^^
- def visit_post_execution_node(node)
- statements =
- if node.statements.nil?
- bounds(node.location)
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- visit(node.statements)
- end
-
- bounds(node.location)
- on_END(statements)
- end
-
- # BEGIN {}
- # ^^^^^^^^
- def visit_pre_execution_node(node)
- statements =
- if node.statements.nil?
- bounds(node.location)
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- visit(node.statements)
- end
-
- bounds(node.location)
- on_BEGIN(statements)
- end
-
- # The top-level program node.
- def visit_program_node(node)
- body = node.statements.body
- body << nil if body.empty?
- statements = visit_statements_node_body(body)
-
- bounds(node.location)
- on_program(statements)
- end
-
- # 0..5
- # ^^^^
- def visit_range_node(node)
- left = visit(node.left)
- right = visit(node.right)
-
- bounds(node.location)
- if node.exclude_end?
- on_dot3(left, right)
- else
- on_dot2(left, right)
- end
- end
-
- # 1r
- # ^^
- def visit_rational_node(node)
- visit_number_node(node) { |text| on_rational(text) }
- end
-
- # redo
- # ^^^^
- def visit_redo_node(node)
- bounds(node.location)
- on_redo
- end
-
- # /foo/
- # ^^^^^
- def visit_regular_expression_node(node)
- bounds(node.opening_loc)
- on_regexp_beg(node.opening)
-
- if node.content.empty?
- bounds(node.closing_loc)
- closing = on_regexp_end(node.closing)
-
- on_regexp_literal(on_regexp_new, closing)
- else
- bounds(node.content_loc)
- tstring_content = on_tstring_content(node.content)
-
- bounds(node.closing_loc)
- closing = on_regexp_end(node.closing)
-
- on_regexp_literal(on_regexp_add(on_regexp_new, tstring_content), closing)
- end
- end
-
- # def foo(bar:); end
- # ^^^^
- def visit_required_keyword_parameter_node(node)
- bounds(node.name_loc)
- [on_label("#{node.name}:"), false]
- end
-
- # def foo(bar); end
- # ^^^
- def visit_required_parameter_node(node)
- bounds(node.location)
- on_ident(node.name.to_s)
- end
-
- # foo rescue bar
- # ^^^^^^^^^^^^^^
- def visit_rescue_modifier_node(node)
- expression = visit_write_value(node.expression)
- rescue_expression = visit(node.rescue_expression)
-
- bounds(node.location)
- on_rescue_mod(expression, rescue_expression)
- end
-
- # begin; rescue; end
- # ^^^^^^^
- def visit_rescue_node(node)
- exceptions =
- case node.exceptions.length
- when 0
- nil
- when 1
- if (exception = node.exceptions.first).is_a?(SplatNode)
- bounds(exception.location)
- on_mrhs_add_star(on_mrhs_new, visit(exception))
- else
- [visit(node.exceptions.first)]
- end
- else
- bounds(node.location)
- length = node.exceptions.length
-
- node.exceptions.each_with_index.inject(on_args_new) do |mrhs, (exception, index)|
- arg = visit(exception)
-
- bounds(exception.location)
- mrhs = on_mrhs_new_from_args(mrhs) if index == length - 1
-
- if exception.is_a?(SplatNode)
- if index == length - 1
- on_mrhs_add_star(mrhs, arg)
- else
- on_args_add_star(mrhs, arg)
- end
- else
- if index == length - 1
- on_mrhs_add(mrhs, arg)
- else
- on_args_add(mrhs, arg)
- end
- end
- end
- end
-
- reference = visit(node.reference)
- statements =
- if node.statements.nil?
- bounds(node.location)
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- visit(node.statements)
- end
-
- subsequent = visit(node.subsequent)
-
- bounds(node.location)
- on_rescue(exceptions, reference, statements, subsequent)
- end
-
- # def foo(*bar); end
- # ^^^^
- #
- # def foo(*); end
- # ^
- def visit_rest_parameter_node(node)
- if node.name_loc.nil?
- bounds(node.location)
- on_rest_param(nil)
- else
- bounds(node.name_loc)
- on_rest_param(visit_token(node.name.to_s))
- end
- end
-
- # retry
- # ^^^^^
- def visit_retry_node(node)
- bounds(node.location)
- on_retry
- end
-
- # return
- # ^^^^^^
- #
- # return 1
- # ^^^^^^^^
- def visit_return_node(node)
- if node.arguments.nil?
- bounds(node.location)
- on_return0
- else
- arguments = visit(node.arguments)
-
- bounds(node.location)
- on_return(arguments)
- end
- end
-
- # self
- # ^^^^
- def visit_self_node(node)
- bounds(node.location)
- on_var_ref(on_kw("self"))
- end
-
- # A shareable constant.
- def visit_shareable_constant_node(node)
- visit(node.write)
- end
-
- # class << self; end
- # ^^^^^^^^^^^^^^^^^^
- def visit_singleton_class_node(node)
- expression = visit(node.expression)
- bodystmt = visit_body_node(node.body&.location || node.end_keyword_loc, node.body)
-
- bounds(node.location)
- on_sclass(expression, bodystmt)
- end
-
- # __ENCODING__
- # ^^^^^^^^^^^^
- def visit_source_encoding_node(node)
- bounds(node.location)
- on_var_ref(on_kw("__ENCODING__"))
- end
-
- # __FILE__
- # ^^^^^^^^
- def visit_source_file_node(node)
- bounds(node.location)
- on_var_ref(on_kw("__FILE__"))
- end
-
- # __LINE__
- # ^^^^^^^^
- def visit_source_line_node(node)
- bounds(node.location)
- on_var_ref(on_kw("__LINE__"))
- end
-
- # foo(*bar)
- # ^^^^
- #
- # def foo((bar, *baz)); end
- # ^^^^
- #
- # def foo(*); bar(*); end
- # ^
- def visit_splat_node(node)
- visit(node.expression)
- end
-
- # A list of statements.
- def visit_statements_node(node)
- bounds(node.location)
- visit_statements_node_body(node.body)
- end
-
- # Visit the list of statements of a statements node. We support nil
- # statements in the list. This would normally not be allowed by the
- # structure of the prism parse tree, but we manually add them here so that
- # we can mirror Ripper's void stmt.
- private def visit_statements_node_body(body)
- body.inject(on_stmts_new) do |stmts, stmt|
- on_stmts_add(stmts, stmt.nil? ? on_void_stmt : visit(stmt))
- end
- end
-
- # "foo"
- # ^^^^^
- def visit_string_node(node)
- if (content = node.content).empty?
- bounds(node.location)
- on_string_literal(on_string_content)
- elsif (opening = node.opening) == "?"
- bounds(node.location)
- on_CHAR("?#{node.content}")
- elsif opening.start_with?("<<~")
- heredoc = visit_heredoc_string_node(node.to_interpolated)
-
- bounds(node.location)
- on_string_literal(heredoc)
- else
- bounds(node.content_loc)
- tstring_content = on_tstring_content(content)
-
- bounds(node.location)
- on_string_literal(on_string_add(on_string_content, tstring_content))
- end
- end
-
- # Ripper gives back the escaped string content but strips out the common
- # leading whitespace. Prism gives back the unescaped string content and
- # a location for the escaped string content. Unfortunately these don't
- # work well together, so here we need to re-derive the common leading
- # whitespace.
- private def visit_heredoc_node_whitespace(parts)
- common_whitespace = nil
- dedent_next = true
-
- parts.each do |part|
- if part.is_a?(StringNode)
- if dedent_next && !(content = part.content).chomp.empty?
- common_whitespace = [
- common_whitespace || Float::INFINITY,
- content[/\A\s*/].each_char.inject(0) do |part_whitespace, char|
- char == "\t" ? ((part_whitespace / 8 + 1) * 8) : (part_whitespace + 1)
- end
- ].min
- end
-
- dedent_next = true
- else
- dedent_next = false
- end
- end
-
- common_whitespace || 0
- end
-
- # Visit a string that is expressed using a <<~ heredoc.
- private def visit_heredoc_node(parts, base)
- common_whitespace = visit_heredoc_node_whitespace(parts)
-
- if common_whitespace == 0
- bounds(parts.first.location)
-
- string = []
- result = base
-
- parts.each do |part|
- if part.is_a?(StringNode)
- if string.empty?
- string = [part]
- else
- string << part
- end
- else
- unless string.empty?
- bounds(string[0].location)
- result = yield result, on_tstring_content(string.map(&:content).join)
- string = []
- end
-
- result = yield result, visit(part)
- end
- end
-
- unless string.empty?
- bounds(string[0].location)
- result = yield result, on_tstring_content(string.map(&:content).join)
- end
-
- result
- else
- bounds(parts.first.location)
- result =
- parts.inject(base) do |string_content, part|
- yield string_content, visit_string_content(part)
- end
-
- bounds(parts.first.location)
- on_heredoc_dedent(result, common_whitespace)
- end
- end
-
- # Visit a heredoc node that is representing a string.
- private def visit_heredoc_string_node(node)
- bounds(node.opening_loc)
- on_heredoc_beg(node.opening)
-
- bounds(node.location)
- result =
- visit_heredoc_node(node.parts, on_string_content) do |parts, part|
- on_string_add(parts, part)
- end
-
- bounds(node.closing_loc)
- on_heredoc_end(node.closing)
-
- result
- end
-
- # Visit a heredoc node that is representing an xstring.
- private def visit_heredoc_x_string_node(node)
- bounds(node.opening_loc)
- on_heredoc_beg(node.opening)
-
- bounds(node.location)
- result =
- visit_heredoc_node(node.parts, on_xstring_new) do |parts, part|
- on_xstring_add(parts, part)
- end
-
- bounds(node.closing_loc)
- on_heredoc_end(node.closing)
-
- result
- end
-
- # super(foo)
- # ^^^^^^^^^^
- def visit_super_node(node)
- arguments, block = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.rparen_loc || node.location))
-
- if !node.lparen_loc.nil?
- bounds(node.lparen_loc)
- arguments = on_arg_paren(arguments)
- end
-
- bounds(node.location)
- call = on_super(arguments)
-
- if block.nil?
- call
- else
- bounds(node.block.location)
- on_method_add_block(call, block)
- end
- end
-
- # :foo
- # ^^^^
- def visit_symbol_node(node)
- if (opening = node.opening)&.match?(/^%s|['"]:?$/)
- bounds(node.value_loc)
- content = on_string_content
-
- if !(value = node.value).empty?
- content = on_string_add(content, on_tstring_content(value))
- end
-
- on_dyna_symbol(content)
- elsif (closing = node.closing) == ":"
- bounds(node.location)
- on_label("#{node.value}:")
- elsif opening.nil? && node.closing_loc.nil?
- bounds(node.value_loc)
- on_symbol_literal(visit_token(node.value))
- else
- bounds(node.value_loc)
- on_symbol_literal(on_symbol(visit_token(node.value)))
- end
- end
-
- # true
- # ^^^^
- def visit_true_node(node)
- bounds(node.location)
- on_var_ref(on_kw("true"))
- end
-
- # undef foo
- # ^^^^^^^^^
- def visit_undef_node(node)
- names = visit_all(node.names)
-
- bounds(node.location)
- on_undef(names)
- end
-
- # unless foo; bar end
- # ^^^^^^^^^^^^^^^^^^^
- #
- # bar unless foo
- # ^^^^^^^^^^^^^^
- def visit_unless_node(node)
- if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
- predicate = visit(node.predicate)
- statements =
- if node.statements.nil?
- bounds(node.location)
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- visit(node.statements)
- end
- else_clause = visit(node.else_clause)
-
- bounds(node.location)
- on_unless(predicate, statements, else_clause)
- else
- statements = visit(node.statements.body.first)
- predicate = visit(node.predicate)
-
- bounds(node.location)
- on_unless_mod(predicate, statements)
- end
- end
-
- # until foo; bar end
- # ^^^^^^^^^^^^^^^^^
- #
- # bar until foo
- # ^^^^^^^^^^^^^
- def visit_until_node(node)
- if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
- predicate = visit(node.predicate)
- statements =
- if node.statements.nil?
- bounds(node.location)
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- visit(node.statements)
- end
-
- bounds(node.location)
- on_until(predicate, statements)
- else
- statements = visit(node.statements.body.first)
- predicate = visit(node.predicate)
-
- bounds(node.location)
- on_until_mod(predicate, statements)
- end
- end
-
- # case foo; when bar; end
- # ^^^^^^^^^^^^^
- def visit_when_node(node)
- # This is a special case where we're not going to call on_when directly
- # because we don't have access to the subsequent. Instead, we'll return
- # the component parts and let the parent node handle it.
- conditions = visit_arguments(node.conditions)
- statements =
- if node.statements.nil?
- bounds(node.location)
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- visit(node.statements)
- end
-
- [conditions, statements]
- end
-
- # while foo; bar end
- # ^^^^^^^^^^^^^^^^^^
- #
- # bar while foo
- # ^^^^^^^^^^^^^
- def visit_while_node(node)
- if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
- predicate = visit(node.predicate)
- statements =
- if node.statements.nil?
- bounds(node.location)
- on_stmts_add(on_stmts_new, on_void_stmt)
- else
- visit(node.statements)
- end
-
- bounds(node.location)
- on_while(predicate, statements)
- else
- statements = visit(node.statements.body.first)
- predicate = visit(node.predicate)
-
- bounds(node.location)
- on_while_mod(predicate, statements)
- end
- end
-
- # `foo`
- # ^^^^^
- def visit_x_string_node(node)
- if node.unescaped.empty?
- bounds(node.location)
- on_xstring_literal(on_xstring_new)
- elsif node.opening.start_with?("<<~")
- heredoc = visit_heredoc_x_string_node(node.to_interpolated)
-
- bounds(node.location)
- on_xstring_literal(heredoc)
- else
- bounds(node.content_loc)
- content = on_tstring_content(node.content)
-
- bounds(node.location)
- on_xstring_literal(on_xstring_add(on_xstring_new, content))
- end
- end
-
- # yield
- # ^^^^^
- #
- # yield 1
- # ^^^^^^^
- def visit_yield_node(node)
- if node.arguments.nil? && node.lparen_loc.nil?
- bounds(node.location)
- on_yield0
- else
- arguments =
- if node.arguments.nil?
- bounds(node.location)
- on_args_new
- else
- visit(node.arguments)
- end
-
- unless node.lparen_loc.nil?
- bounds(node.lparen_loc)
- arguments = on_paren(arguments)
- end
-
- bounds(node.location)
- on_yield(arguments)
- end
- end
-
- private
-
- # Lazily initialize the parse result.
- def result
- @result ||= Prism.parse(source, partial_script: true)
- end
-
- ##########################################################################
- # Helpers
- ##########################################################################
-
- # Returns true if there is a comma between the two locations.
- def trailing_comma?(left, right)
- source.byteslice(left.end_offset...right.start_offset).include?(",")
- end
-
- # Returns true if there is a semicolon between the two locations.
- def void_stmt?(left, right, allow_newline)
- pattern = allow_newline ? /[;\n]/ : /;/
- source.byteslice(left.end_offset...right.start_offset).match?(pattern)
- end
-
- # Visit the string content of a particular node. This method is used to
- # split into the various token types.
- def visit_token(token, allow_keywords = true)
- case token
- when "."
- on_period(token)
- when "`"
- on_backtick(token)
- when *(allow_keywords ? KEYWORDS : [])
- on_kw(token)
- when /^_/
- on_ident(token)
- when /^[[:upper:]]\w*$/
- on_const(token)
- when /^@@/
- on_cvar(token)
- when /^@/
- on_ivar(token)
- when /^\$/
- on_gvar(token)
- when /^[[:punct:]]/
- on_op(token)
- else
- on_ident(token)
- end
- end
-
- # Visit a node that represents a number. We need to explicitly handle the
- # unary - operator.
- def visit_number_node(node)
- slice = node.slice
- location = node.location
-
- if slice[0] == "-"
- bounds(location.copy(start_offset: location.start_offset + 1))
- value = yield slice[1..-1]
-
- bounds(node.location)
- on_unary(:-@, value)
- else
- bounds(location)
- yield slice
- end
- end
-
- # Visit a node that represents a write value. This is used to handle the
- # special case of an implicit array that is generated without brackets.
- def visit_write_value(node)
- if node.is_a?(ArrayNode) && node.opening_loc.nil?
- elements = node.elements
- length = elements.length
-
- bounds(elements.first.location)
- elements.each_with_index.inject((elements.first.is_a?(SplatNode) && length == 1) ? on_mrhs_new : on_args_new) do |args, (element, index)|
- arg = visit(element)
- bounds(element.location)
-
- if index == length - 1
- if element.is_a?(SplatNode)
- mrhs = index == 0 ? args : on_mrhs_new_from_args(args)
- on_mrhs_add_star(mrhs, arg)
- else
- on_mrhs_add(on_mrhs_new_from_args(args), arg)
- end
- else
- case element
- when BlockArgumentNode
- on_args_add_block(args, arg)
- when SplatNode
- on_args_add_star(args, arg)
- else
- on_args_add(args, arg)
- end
- end
- end
- else
- visit(node)
- end
- end
-
- # This method is responsible for updating lineno and column information
- # to reflect the current node.
- #
- # This method could be drastically improved with some caching on the start
- # of every line, but for now it's good enough.
- def bounds(location)
- @lineno = location.start_line
- @column = location.start_column
- end
-
- ##########################################################################
- # Ripper interface
- ##########################################################################
-
- # :stopdoc:
- def _dispatch_0; end
- def _dispatch_1(_); end
- def _dispatch_2(_, _); end
- def _dispatch_3(_, _, _); end
- def _dispatch_4(_, _, _, _); end
- def _dispatch_5(_, _, _, _, _); end
- def _dispatch_7(_, _, _, _, _, _, _); end
- # :startdoc:
-
- #
- # Parser Events
- #
-
- PARSER_EVENT_TABLE.each do |id, arity|
- alias_method "on_#{id}", "_dispatch_#{arity}"
- end
-
- # This method is called when weak warning is produced by the parser.
- # +fmt+ and +args+ is printf style.
- def warn(fmt, *args)
- end
-
- # This method is called when strong warning is produced by the parser.
- # +fmt+ and +args+ is printf style.
- def warning(fmt, *args)
- end
-
- # This method is called when the parser found syntax error.
- def compile_error(msg)
- end
-
- #
- # Scanner Events
- #
-
- SCANNER_EVENTS.each do |id|
- alias_method "on_#{id}", :_dispatch_1
- end
-
- # This method is provided by the Ripper C extension. It is called when a
- # string needs to be dedented because of a tilde heredoc. It is expected
- # that it will modify the string in place and return the number of bytes
- # that were removed.
- def dedent_string(string, width)
- whitespace = 0
- cursor = 0
-
- while cursor < string.length && string[cursor].match?(/\s/) && whitespace < width
- if string[cursor] == "\t"
- whitespace = ((whitespace / 8 + 1) * 8)
- break if whitespace > width
- else
- whitespace += 1
- end
-
- cursor += 1
- end
-
- string.replace(string[cursor..])
- cursor
- end
- end
- end
-end
diff --git a/lib/prism/translation/ripper/sexp.rb b/lib/prism/translation/ripper/sexp.rb
deleted file mode 100644
index dc26a639a3..0000000000
--- a/lib/prism/translation/ripper/sexp.rb
+++ /dev/null
@@ -1,125 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../ripper"
-
-module Prism
- module Translation
- class Ripper
- # This class mirrors the ::Ripper::SexpBuilder subclass of ::Ripper that
- # returns the arrays of [type, *children].
- class SexpBuilder < Ripper
- # :stopdoc:
-
- attr_reader :error
-
- private
-
- def dedent_element(e, width)
- if (n = dedent_string(e[1], width)) > 0
- e[2][1] += n
- end
- e
- end
-
- def on_heredoc_dedent(val, width)
- sub = proc do |cont|
- cont.map! do |e|
- if Array === e
- case e[0]
- when :@tstring_content
- e = dedent_element(e, width)
- when /_add\z/
- e[1] = sub[e[1]]
- end
- elsif String === e
- dedent_string(e, width)
- end
- e
- end
- end
- sub[val]
- val
- end
-
- events = private_instance_methods(false).grep(/\Aon_/) {$'.to_sym}
- (PARSER_EVENTS - events).each do |event|
- module_eval(<<-End, __FILE__, __LINE__ + 1)
- def on_#{event}(*args)
- args.unshift :#{event}
- end
- End
- end
-
- SCANNER_EVENTS.each do |event|
- module_eval(<<-End, __FILE__, __LINE__ + 1)
- def on_#{event}(tok)
- [:@#{event}, tok, [lineno(), column()]]
- end
- End
- end
-
- def on_error(mesg)
- @error = mesg
- end
- remove_method :on_parse_error
- alias on_parse_error on_error
- alias compile_error on_error
-
- # :startdoc:
- end
-
- # This class mirrors the ::Ripper::SexpBuilderPP subclass of ::Ripper that
- # returns the same values as ::Ripper::SexpBuilder except with a couple of
- # niceties that flatten linked lists into arrays.
- class SexpBuilderPP < SexpBuilder
- # :stopdoc:
-
- private
-
- def on_heredoc_dedent(val, width)
- val.map! do |e|
- next e if Symbol === e and /_content\z/ =~ e
- if Array === e and e[0] == :@tstring_content
- e = dedent_element(e, width)
- elsif String === e
- dedent_string(e, width)
- end
- e
- end
- val
- end
-
- def _dispatch_event_new
- []
- end
-
- def _dispatch_event_push(list, item)
- list.push item
- list
- end
-
- def on_mlhs_paren(list)
- [:mlhs, *list]
- end
-
- def on_mlhs_add_star(list, star)
- list.push([:rest_param, star])
- end
-
- def on_mlhs_add_post(list, post)
- list.concat(post)
- end
-
- PARSER_EVENT_TABLE.each do |event, arity|
- if /_new\z/ =~ event and arity == 0
- alias_method "on_#{event}", :_dispatch_event_new
- elsif /_add\z/ =~ event
- alias_method "on_#{event}", :_dispatch_event_push
- end
- end
-
- # :startdoc:
- end
- end
- end
-end
diff --git a/lib/prism/translation/ripper/shim.rb b/lib/prism/translation/ripper/shim.rb
deleted file mode 100644
index 10e21cd16a..0000000000
--- a/lib/prism/translation/ripper/shim.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-# frozen_string_literal: true
-
-# This writes the prism ripper translation into the Ripper constant so that
-# users can transparently use Ripper without any changes.
-Ripper = Prism::Translation::Ripper
diff --git a/lib/prism/translation/ruby_parser.rb b/lib/prism/translation/ruby_parser.rb
deleted file mode 100644
index 189038d008..0000000000
--- a/lib/prism/translation/ruby_parser.rb
+++ /dev/null
@@ -1,1636 +0,0 @@
-# frozen_string_literal: true
-
-begin
- require "ruby_parser"
-rescue LoadError
- warn(%q{Error: Unable to load ruby_parser. Add `gem "ruby_parser"` to your Gemfile.})
- exit(1)
-end
-
-module Prism
- module Translation
- # This module is the entry-point for converting a prism syntax tree into the
- # seattlerb/ruby_parser gem's syntax tree.
- class RubyParser
- # A prism visitor that builds Sexp objects.
- class Compiler < ::Prism::Compiler
- # This is the name of the file that we are compiling. We set it on every
- # Sexp object that is generated, and also use it to compile __FILE__
- # nodes.
- attr_reader :file
-
- # Class variables will change their type based on if they are inside of
- # a method definition or not, so we need to track that state.
- attr_reader :in_def
-
- # Some nodes will change their representation if they are inside of a
- # pattern, so we need to track that state.
- attr_reader :in_pattern
-
- # Initialize a new compiler with the given file name.
- def initialize(file, in_def: false, in_pattern: false)
- @file = file
- @in_def = in_def
- @in_pattern = in_pattern
- end
-
- # alias foo bar
- # ^^^^^^^^^^^^^
- def visit_alias_method_node(node)
- s(node, :alias, visit(node.new_name), visit(node.old_name))
- end
-
- # alias $foo $bar
- # ^^^^^^^^^^^^^^^
- def visit_alias_global_variable_node(node)
- s(node, :valias, node.new_name.name, node.old_name.name)
- end
-
- # foo => bar | baz
- # ^^^^^^^^^
- def visit_alternation_pattern_node(node)
- s(node, :or, visit(node.left), visit(node.right))
- end
-
- # a and b
- # ^^^^^^^
- def visit_and_node(node)
- left = visit(node.left)
-
- if left[0] == :and
- # ruby_parser has the and keyword as right-associative as opposed to
- # prism which has it as left-associative. We reverse that
- # associativity here.
- nest = left
- nest = nest[2] while nest[2][0] == :and
- nest[2] = s(node, :and, nest[2], visit(node.right))
- left
- else
- s(node, :and, left, visit(node.right))
- end
- end
-
- # []
- # ^^
- def visit_array_node(node)
- if in_pattern
- s(node, :array_pat, nil).concat(visit_all(node.elements))
- else
- s(node, :array).concat(visit_all(node.elements))
- end
- end
-
- # foo => [bar]
- # ^^^^^
- def visit_array_pattern_node(node)
- if node.constant.nil? && node.requireds.empty? && node.rest.nil? && node.posts.empty?
- s(node, :array_pat)
- else
- result = s(node, :array_pat, visit_pattern_constant(node.constant)).concat(visit_all(node.requireds))
-
- case node.rest
- when SplatNode
- result << :"*#{node.rest.expression&.name}"
- when ImplicitRestNode
- result << :*
-
- # This doesn't make any sense at all, but since we're trying to
- # replicate the behavior directly, we'll copy it.
- result.line(666)
- end
-
- result.concat(visit_all(node.posts))
- end
- end
-
- # foo(bar)
- # ^^^
- def visit_arguments_node(node)
- raise "Cannot visit arguments directly"
- end
-
- # { a: 1 }
- # ^^^^
- def visit_assoc_node(node)
- [visit(node.key), visit(node.value)]
- end
-
- # def foo(**); bar(**); end
- # ^^
- #
- # { **foo }
- # ^^^^^
- def visit_assoc_splat_node(node)
- if node.value.nil?
- [s(node, :kwsplat)]
- else
- [s(node, :kwsplat, visit(node.value))]
- end
- end
-
- # $+
- # ^^
- def visit_back_reference_read_node(node)
- s(node, :back_ref, node.name.name.delete_prefix("$").to_sym)
- end
-
- # begin end
- # ^^^^^^^^^
- def visit_begin_node(node)
- result = node.statements.nil? ? s(node, :nil) : visit(node.statements)
-
- if !node.rescue_clause.nil?
- if !node.statements.nil?
- result = s(node.statements, :rescue, result, visit(node.rescue_clause))
- else
- result = s(node.rescue_clause, :rescue, visit(node.rescue_clause))
- end
-
- current = node.rescue_clause
- until (current = current.subsequent).nil?
- result << visit(current)
- end
- end
-
- if !node.else_clause&.statements.nil?
- result << visit(node.else_clause)
- end
-
- if !node.ensure_clause.nil?
- if !node.statements.nil? || !node.rescue_clause.nil? || !node.else_clause.nil?
- result = s(node.statements || node.rescue_clause || node.else_clause || node.ensure_clause, :ensure, result, visit(node.ensure_clause))
- else
- result = s(node.ensure_clause, :ensure, visit(node.ensure_clause))
- end
- end
-
- result
- end
-
- # foo(&bar)
- # ^^^^
- def visit_block_argument_node(node)
- s(node, :block_pass).tap do |result|
- result << visit(node.expression) unless node.expression.nil?
- end
- end
-
- # foo { |; bar| }
- # ^^^
- def visit_block_local_variable_node(node)
- node.name
- end
-
- # A block on a keyword or method call.
- def visit_block_node(node)
- s(node, :block_pass, visit(node.expression))
- end
-
- # def foo(&bar); end
- # ^^^^
- def visit_block_parameter_node(node)
- :"&#{node.name}"
- end
-
- # A block's parameters.
- def visit_block_parameters_node(node)
- # If this block parameters has no parameters and is using pipes, then
- # it inherits its location from its shadow locals, even if they're not
- # on the same lines as the pipes.
- shadow_loc = true
-
- result =
- if node.parameters.nil?
- s(node, :args)
- else
- shadow_loc = false
- visit(node.parameters)
- end
-
- if node.opening == "("
- result.line = node.opening_loc.start_line
- result.line_max = node.closing_loc.end_line
- shadow_loc = false
- end
-
- if node.locals.any?
- shadow = s(node, :shadow).concat(visit_all(node.locals))
- shadow.line = node.locals.first.location.start_line
- shadow.line_max = node.locals.last.location.end_line
- result << shadow
-
- if shadow_loc
- result.line = shadow.line
- result.line_max = shadow.line_max
- end
- end
-
- result
- end
-
- # break
- # ^^^^^
- #
- # break foo
- # ^^^^^^^^^
- def visit_break_node(node)
- if node.arguments.nil?
- s(node, :break)
- elsif node.arguments.arguments.length == 1
- s(node, :break, visit(node.arguments.arguments.first))
- else
- s(node, :break, s(node.arguments, :array).concat(visit_all(node.arguments.arguments)))
- end
- end
-
- # foo
- # ^^^
- #
- # foo.bar
- # ^^^^^^^
- #
- # foo.bar() {}
- # ^^^^^^^^^^^^
- def visit_call_node(node)
- case node.name
- when :!~
- return s(node, :not, visit(node.copy(name: :"=~")))
- when :=~
- if node.arguments&.arguments&.length == 1 && node.block.nil?
- case node.receiver
- when StringNode
- return s(node, :match3, visit(node.arguments.arguments.first), visit(node.receiver))
- when RegularExpressionNode, InterpolatedRegularExpressionNode
- return s(node, :match2, visit(node.receiver), visit(node.arguments.arguments.first))
- end
-
- case node.arguments.arguments.first
- when RegularExpressionNode, InterpolatedRegularExpressionNode
- return s(node, :match3, visit(node.arguments.arguments.first), visit(node.receiver))
- end
- end
- end
-
- type = node.attribute_write? ? :attrasgn : :call
- type = :"safe_#{type}" if node.safe_navigation?
-
- arguments = node.arguments&.arguments || []
- write_value = arguments.pop if type == :attrasgn
- block = node.block
-
- if block.is_a?(BlockArgumentNode)
- arguments << block
- block = nil
- end
-
- result = s(node, type, visit(node.receiver), node.name).concat(visit_all(arguments))
- result << visit_write_value(write_value) unless write_value.nil?
-
- visit_block(node, result, block)
- end
-
- # foo.bar += baz
- # ^^^^^^^^^^^^^^^
- def visit_call_operator_write_node(node)
- if op_asgn?(node)
- s(node, op_asgn_type(node, :op_asgn), visit(node.receiver), visit_write_value(node.value), node.read_name, node.binary_operator)
- else
- s(node, op_asgn_type(node, :op_asgn2), visit(node.receiver), node.write_name, node.binary_operator, visit_write_value(node.value))
- end
- end
-
- # foo.bar &&= baz
- # ^^^^^^^^^^^^^^^
- def visit_call_and_write_node(node)
- if op_asgn?(node)
- s(node, op_asgn_type(node, :op_asgn), visit(node.receiver), visit_write_value(node.value), node.read_name, :"&&")
- else
- s(node, op_asgn_type(node, :op_asgn2), visit(node.receiver), node.write_name, :"&&", visit_write_value(node.value))
- end
- end
-
- # foo.bar ||= baz
- # ^^^^^^^^^^^^^^^
- def visit_call_or_write_node(node)
- if op_asgn?(node)
- s(node, op_asgn_type(node, :op_asgn), visit(node.receiver), visit_write_value(node.value), node.read_name, :"||")
- else
- s(node, op_asgn_type(node, :op_asgn2), visit(node.receiver), node.write_name, :"||", visit_write_value(node.value))
- end
- end
-
- # Call nodes with operators following them will either be op_asgn or
- # op_asgn2 nodes. That is determined by their call operator and their
- # right-hand side.
- private def op_asgn?(node)
- node.call_operator == "::" || (node.value.is_a?(CallNode) && node.value.opening_loc.nil? && !node.value.arguments.nil?)
- end
-
- # Call nodes with operators following them can use &. as an operator,
- # which changes their type by prefixing "safe_".
- private def op_asgn_type(node, type)
- node.safe_navigation? ? :"safe_#{type}" : type
- end
-
- # foo.bar, = 1
- # ^^^^^^^
- def visit_call_target_node(node)
- s(node, :attrasgn, visit(node.receiver), node.name)
- end
-
- # foo => bar => baz
- # ^^^^^^^^^^
- def visit_capture_pattern_node(node)
- visit(node.target) << visit(node.value)
- end
-
- # case foo; when bar; end
- # ^^^^^^^^^^^^^^^^^^^^^^^
- def visit_case_node(node)
- s(node, :case, visit(node.predicate)).concat(visit_all(node.conditions)) << visit(node.else_clause)
- end
-
- # case foo; in bar; end
- # ^^^^^^^^^^^^^^^^^^^^^
- def visit_case_match_node(node)
- s(node, :case, visit(node.predicate)).concat(visit_all(node.conditions)) << visit(node.else_clause)
- end
-
- # class Foo; end
- # ^^^^^^^^^^^^^^
- def visit_class_node(node)
- name =
- if node.constant_path.is_a?(ConstantReadNode)
- node.name
- else
- visit(node.constant_path)
- end
-
- if node.body.nil?
- s(node, :class, name, visit(node.superclass))
- elsif node.body.is_a?(StatementsNode)
- compiler = copy_compiler(in_def: false)
- s(node, :class, name, visit(node.superclass)).concat(node.body.body.map { |child| child.accept(compiler) })
- else
- s(node, :class, name, visit(node.superclass), node.body.accept(copy_compiler(in_def: false)))
- end
- end
-
- # @@foo
- # ^^^^^
- def visit_class_variable_read_node(node)
- s(node, :cvar, node.name)
- end
-
- # @@foo = 1
- # ^^^^^^^^^
- #
- # @@foo, @@bar = 1
- # ^^^^^ ^^^^^
- def visit_class_variable_write_node(node)
- s(node, class_variable_write_type, node.name, visit_write_value(node.value))
- end
-
- # @@foo += bar
- # ^^^^^^^^^^^^
- def visit_class_variable_operator_write_node(node)
- s(node, class_variable_write_type, node.name, s(node, :call, s(node, :cvar, node.name), node.binary_operator, visit_write_value(node.value)))
- end
-
- # @@foo &&= bar
- # ^^^^^^^^^^^^^
- def visit_class_variable_and_write_node(node)
- s(node, :op_asgn_and, s(node, :cvar, node.name), s(node, class_variable_write_type, node.name, visit_write_value(node.value)))
- end
-
- # @@foo ||= bar
- # ^^^^^^^^^^^^^
- def visit_class_variable_or_write_node(node)
- s(node, :op_asgn_or, s(node, :cvar, node.name), s(node, class_variable_write_type, node.name, visit_write_value(node.value)))
- end
-
- # @@foo, = bar
- # ^^^^^
- def visit_class_variable_target_node(node)
- s(node, class_variable_write_type, node.name)
- end
-
- # If a class variable is written within a method definition, it has a
- # different type than everywhere else.
- private def class_variable_write_type
- in_def ? :cvasgn : :cvdecl
- end
-
- # Foo
- # ^^^
- def visit_constant_read_node(node)
- s(node, :const, node.name)
- end
-
- # Foo = 1
- # ^^^^^^^
- #
- # Foo, Bar = 1
- # ^^^ ^^^
- def visit_constant_write_node(node)
- s(node, :cdecl, node.name, visit_write_value(node.value))
- end
-
- # Foo += bar
- # ^^^^^^^^^^^
- def visit_constant_operator_write_node(node)
- s(node, :cdecl, node.name, s(node, :call, s(node, :const, node.name), node.binary_operator, visit_write_value(node.value)))
- end
-
- # Foo &&= bar
- # ^^^^^^^^^^^^
- def visit_constant_and_write_node(node)
- s(node, :op_asgn_and, s(node, :const, node.name), s(node, :cdecl, node.name, visit(node.value)))
- end
-
- # Foo ||= bar
- # ^^^^^^^^^^^^
- def visit_constant_or_write_node(node)
- s(node, :op_asgn_or, s(node, :const, node.name), s(node, :cdecl, node.name, visit(node.value)))
- end
-
- # Foo, = bar
- # ^^^
- def visit_constant_target_node(node)
- s(node, :cdecl, node.name)
- end
-
- # Foo::Bar
- # ^^^^^^^^
- def visit_constant_path_node(node)
- if node.parent.nil?
- s(node, :colon3, node.name)
- else
- s(node, :colon2, visit(node.parent), node.name)
- end
- end
-
- # Foo::Bar = 1
- # ^^^^^^^^^^^^
- #
- # Foo::Foo, Bar::Bar = 1
- # ^^^^^^^^ ^^^^^^^^
- def visit_constant_path_write_node(node)
- s(node, :cdecl, visit(node.target), visit_write_value(node.value))
- end
-
- # Foo::Bar += baz
- # ^^^^^^^^^^^^^^^
- def visit_constant_path_operator_write_node(node)
- s(node, :op_asgn, visit(node.target), node.binary_operator, visit_write_value(node.value))
- end
-
- # Foo::Bar &&= baz
- # ^^^^^^^^^^^^^^^^
- def visit_constant_path_and_write_node(node)
- s(node, :op_asgn_and, visit(node.target), visit_write_value(node.value))
- end
-
- # Foo::Bar ||= baz
- # ^^^^^^^^^^^^^^^^
- def visit_constant_path_or_write_node(node)
- s(node, :op_asgn_or, visit(node.target), visit_write_value(node.value))
- end
-
- # Foo::Bar, = baz
- # ^^^^^^^^
- def visit_constant_path_target_node(node)
- inner =
- if node.parent.nil?
- s(node, :colon3, node.name)
- else
- s(node, :colon2, visit(node.parent), node.name)
- end
-
- s(node, :const, inner)
- end
-
- # def foo; end
- # ^^^^^^^^^^^^
- #
- # def self.foo; end
- # ^^^^^^^^^^^^^^^^^
- def visit_def_node(node)
- name = node.name_loc.slice.to_sym
- result =
- if node.receiver.nil?
- s(node, :defn, name)
- else
- s(node, :defs, visit(node.receiver), name)
- end
-
- result.line(node.name_loc.start_line)
- if node.parameters.nil?
- result << s(node, :args).line(node.name_loc.start_line)
- else
- result << visit(node.parameters)
- end
-
- if node.body.nil?
- result << s(node, :nil)
- elsif node.body.is_a?(StatementsNode)
- compiler = copy_compiler(in_def: true)
- result.concat(node.body.body.map { |child| child.accept(compiler) })
- else
- result << node.body.accept(copy_compiler(in_def: true))
- end
- end
-
- # defined? a
- # ^^^^^^^^^^
- #
- # defined?(a)
- # ^^^^^^^^^^^
- def visit_defined_node(node)
- s(node, :defined, visit(node.value))
- end
-
- # if foo then bar else baz end
- # ^^^^^^^^^^^^
- def visit_else_node(node)
- visit(node.statements)
- end
-
- # "foo #{bar}"
- # ^^^^^^
- def visit_embedded_statements_node(node)
- result = s(node, :evstr)
- result << visit(node.statements) unless node.statements.nil?
- result
- end
-
- # "foo #@bar"
- # ^^^^^
- def visit_embedded_variable_node(node)
- s(node, :evstr, visit(node.variable))
- end
-
- # begin; foo; ensure; bar; end
- # ^^^^^^^^^^^^
- def visit_ensure_node(node)
- node.statements.nil? ? s(node, :nil) : visit(node.statements)
- end
-
- # false
- # ^^^^^
- def visit_false_node(node)
- s(node, :false)
- end
-
- # foo => [*, bar, *]
- # ^^^^^^^^^^^
- def visit_find_pattern_node(node)
- s(node, :find_pat, visit_pattern_constant(node.constant), :"*#{node.left.expression&.name}", *visit_all(node.requireds), :"*#{node.right.expression&.name}")
- end
-
- # if foo .. bar; end
- # ^^^^^^^^^^
- def visit_flip_flop_node(node)
- if node.left.is_a?(IntegerNode) && node.right.is_a?(IntegerNode)
- s(node, :lit, Range.new(node.left.value, node.right.value, node.exclude_end?))
- else
- s(node, node.exclude_end? ? :flip3 : :flip2, visit(node.left), visit(node.right))
- end
- end
-
- # 1.0
- # ^^^
- def visit_float_node(node)
- s(node, :lit, node.value)
- end
-
- # for foo in bar do end
- # ^^^^^^^^^^^^^^^^^^^^^
- def visit_for_node(node)
- s(node, :for, visit(node.collection), visit(node.index), visit(node.statements))
- end
-
- # def foo(...); bar(...); end
- # ^^^
- def visit_forwarding_arguments_node(node)
- s(node, :forward_args)
- end
-
- # def foo(...); end
- # ^^^
- def visit_forwarding_parameter_node(node)
- s(node, :forward_args)
- end
-
- # super
- # ^^^^^
- #
- # super {}
- # ^^^^^^^^
- def visit_forwarding_super_node(node)
- visit_block(node, s(node, :zsuper), node.block)
- end
-
- # $foo
- # ^^^^
- def visit_global_variable_read_node(node)
- s(node, :gvar, node.name)
- end
-
- # $foo = 1
- # ^^^^^^^^
- #
- # $foo, $bar = 1
- # ^^^^ ^^^^
- def visit_global_variable_write_node(node)
- s(node, :gasgn, node.name, visit_write_value(node.value))
- end
-
- # $foo += bar
- # ^^^^^^^^^^^
- def visit_global_variable_operator_write_node(node)
- s(node, :gasgn, node.name, s(node, :call, s(node, :gvar, node.name), node.binary_operator, visit(node.value)))
- end
-
- # $foo &&= bar
- # ^^^^^^^^^^^^
- def visit_global_variable_and_write_node(node)
- s(node, :op_asgn_and, s(node, :gvar, node.name), s(node, :gasgn, node.name, visit_write_value(node.value)))
- end
-
- # $foo ||= bar
- # ^^^^^^^^^^^^
- def visit_global_variable_or_write_node(node)
- s(node, :op_asgn_or, s(node, :gvar, node.name), s(node, :gasgn, node.name, visit_write_value(node.value)))
- end
-
- # $foo, = bar
- # ^^^^
- def visit_global_variable_target_node(node)
- s(node, :gasgn, node.name)
- end
-
- # {}
- # ^^
- def visit_hash_node(node)
- s(node, :hash).concat(node.elements.flat_map { |element| visit(element) })
- end
-
- # foo => {}
- # ^^
- def visit_hash_pattern_node(node)
- result = s(node, :hash_pat, visit_pattern_constant(node.constant)).concat(node.elements.flat_map { |element| visit(element) })
-
- case node.rest
- when AssocSplatNode
- result << s(node.rest, :kwrest, :"**#{node.rest.value&.name}")
- when NoKeywordsParameterNode
- result << visit(node.rest)
- end
-
- result
- end
-
- # if foo then bar end
- # ^^^^^^^^^^^^^^^^^^^
- #
- # bar if foo
- # ^^^^^^^^^^
- #
- # foo ? bar : baz
- # ^^^^^^^^^^^^^^^
- def visit_if_node(node)
- s(node, :if, visit(node.predicate), visit(node.statements), visit(node.subsequent))
- end
-
- # 1i
- def visit_imaginary_node(node)
- s(node, :lit, node.value)
- end
-
- # { foo: }
- # ^^^^
- def visit_implicit_node(node)
- end
-
- # foo { |bar,| }
- # ^
- def visit_implicit_rest_node(node)
- end
-
- # case foo; in bar; end
- # ^^^^^^^^^^^^^^^^^^^^^
- def visit_in_node(node)
- pattern =
- if node.pattern.is_a?(ConstantPathNode)
- s(node.pattern, :const, visit(node.pattern))
- else
- node.pattern.accept(copy_compiler(in_pattern: true))
- end
-
- s(node, :in, pattern).concat(node.statements.nil? ? [nil] : visit_all(node.statements.body))
- end
-
- # foo[bar] += baz
- # ^^^^^^^^^^^^^^^
- def visit_index_operator_write_node(node)
- arglist = nil
-
- if !node.arguments.nil? || !node.block.nil?
- arglist = s(node, :arglist).concat(visit_all(node.arguments&.arguments || []))
- arglist << visit(node.block) if !node.block.nil?
- end
-
- s(node, :op_asgn1, visit(node.receiver), arglist, node.binary_operator, visit_write_value(node.value))
- end
-
- # foo[bar] &&= baz
- # ^^^^^^^^^^^^^^^^
- def visit_index_and_write_node(node)
- arglist = nil
-
- if !node.arguments.nil? || !node.block.nil?
- arglist = s(node, :arglist).concat(visit_all(node.arguments&.arguments || []))
- arglist << visit(node.block) if !node.block.nil?
- end
-
- s(node, :op_asgn1, visit(node.receiver), arglist, :"&&", visit_write_value(node.value))
- end
-
- # foo[bar] ||= baz
- # ^^^^^^^^^^^^^^^^
- def visit_index_or_write_node(node)
- arglist = nil
-
- if !node.arguments.nil? || !node.block.nil?
- arglist = s(node, :arglist).concat(visit_all(node.arguments&.arguments || []))
- arglist << visit(node.block) if !node.block.nil?
- end
-
- s(node, :op_asgn1, visit(node.receiver), arglist, :"||", visit_write_value(node.value))
- end
-
- # foo[bar], = 1
- # ^^^^^^^^
- def visit_index_target_node(node)
- arguments = visit_all(node.arguments&.arguments || [])
- arguments << visit(node.block) unless node.block.nil?
-
- s(node, :attrasgn, visit(node.receiver), :[]=).concat(arguments)
- end
-
- # @foo
- # ^^^^
- def visit_instance_variable_read_node(node)
- s(node, :ivar, node.name)
- end
-
- # @foo = 1
- # ^^^^^^^^
- #
- # @foo, @bar = 1
- # ^^^^ ^^^^
- def visit_instance_variable_write_node(node)
- s(node, :iasgn, node.name, visit_write_value(node.value))
- end
-
- # @foo += bar
- # ^^^^^^^^^^^
- def visit_instance_variable_operator_write_node(node)
- s(node, :iasgn, node.name, s(node, :call, s(node, :ivar, node.name), node.binary_operator, visit_write_value(node.value)))
- end
-
- # @foo &&= bar
- # ^^^^^^^^^^^^
- def visit_instance_variable_and_write_node(node)
- s(node, :op_asgn_and, s(node, :ivar, node.name), s(node, :iasgn, node.name, visit(node.value)))
- end
-
- # @foo ||= bar
- # ^^^^^^^^^^^^
- def visit_instance_variable_or_write_node(node)
- s(node, :op_asgn_or, s(node, :ivar, node.name), s(node, :iasgn, node.name, visit(node.value)))
- end
-
- # @foo, = bar
- # ^^^^
- def visit_instance_variable_target_node(node)
- s(node, :iasgn, node.name)
- end
-
- # 1
- # ^
- def visit_integer_node(node)
- s(node, :lit, node.value)
- end
-
- # if /foo #{bar}/ then end
- # ^^^^^^^^^^^^
- def visit_interpolated_match_last_line_node(node)
- parts = visit_interpolated_parts(node.parts)
- regexp =
- if parts.length == 1
- s(node, :lit, Regexp.new(parts.first, node.options))
- else
- s(node, :dregx).concat(parts).tap do |result|
- options = node.options
- result << options if options != 0
- end
- end
-
- s(node, :match, regexp)
- end
-
- # /foo #{bar}/
- # ^^^^^^^^^^^^
- def visit_interpolated_regular_expression_node(node)
- parts = visit_interpolated_parts(node.parts)
-
- if parts.length == 1
- s(node, :lit, Regexp.new(parts.first, node.options))
- else
- s(node, :dregx).concat(parts).tap do |result|
- options = node.options
- result << options if options != 0
- end
- end
- end
-
- # "foo #{bar}"
- # ^^^^^^^^^^^^
- def visit_interpolated_string_node(node)
- parts = visit_interpolated_parts(node.parts)
- parts.length == 1 ? s(node, :str, parts.first) : s(node, :dstr).concat(parts)
- end
-
- # :"foo #{bar}"
- # ^^^^^^^^^^^^^
- def visit_interpolated_symbol_node(node)
- parts = visit_interpolated_parts(node.parts)
- parts.length == 1 ? s(node, :lit, parts.first.to_sym) : s(node, :dsym).concat(parts)
- end
-
- # `foo #{bar}`
- # ^^^^^^^^^^^^
- def visit_interpolated_x_string_node(node)
- source = node.heredoc? ? node.parts.first : node
- parts = visit_interpolated_parts(node.parts)
- parts.length == 1 ? s(source, :xstr, parts.first) : s(source, :dxstr).concat(parts)
- end
-
- # Visit the interpolated content of the string-like node.
- private def visit_interpolated_parts(parts)
- visited = []
- parts.each do |part|
- result = visit(part)
-
- if result[0] == :evstr && result[1]
- if result[1][0] == :str
- visited << result[1]
- elsif result[1][0] == :dstr
- visited.concat(result[1][1..-1])
- else
- visited << result
- end
- elsif result[0] == :dstr
- if !visited.empty? && part.parts[0].is_a?(StringNode)
- # If we are in the middle of an implicitly concatenated string,
- # we should not have a bare string as the first part. In this
- # case we need to visit just that first part and then we can
- # push the rest of the parts onto the visited array.
- result[1] = visit(part.parts[0])
- end
- visited.concat(result[1..-1])
- else
- visited << result
- end
- end
-
- state = :beginning #: :beginning | :string_content | :interpolated_content
-
- visited.each_with_object([]) do |result, results|
- case state
- when :beginning
- if result.is_a?(String)
- results << result
- state = :string_content
- elsif result.is_a?(Array) && result[0] == :str
- results << result[1]
- state = :string_content
- else
- results << ""
- results << result
- state = :interpolated_content
- end
- when :string_content
- if result.is_a?(String)
- results[0] << result
- elsif result.is_a?(Array) && result[0] == :str
- results[0] << result[1]
- else
- results << result
- state = :interpolated_content
- end
- when :interpolated_content
- if result.is_a?(Array) && result[0] == :str && results[-1][0] == :str && (results[-1].line_max == result.line)
- results[-1][1] << result[1]
- results[-1].line_max = result.line_max
- else
- results << result
- end
- end
- end
- end
-
- # -> { it }
- # ^^
- def visit_it_local_variable_read_node(node)
- s(node, :call, nil, :it)
- end
-
- # foo(bar: baz)
- # ^^^^^^^^
- def visit_keyword_hash_node(node)
- s(node, :hash).concat(node.elements.flat_map { |element| visit(element) })
- end
-
- # def foo(**bar); end
- # ^^^^^
- #
- # def foo(**); end
- # ^^
- def visit_keyword_rest_parameter_node(node)
- :"**#{node.name}"
- end
-
- # -> {}
- def visit_lambda_node(node)
- parameters =
- case node.parameters
- when nil, NumberedParametersNode
- s(node, :args)
- else
- visit(node.parameters)
- end
-
- if node.body.nil?
- s(node, :iter, s(node, :lambda), parameters)
- else
- s(node, :iter, s(node, :lambda), parameters, visit(node.body))
- end
- end
-
- # foo
- # ^^^
- def visit_local_variable_read_node(node)
- if node.name.match?(/^_\d$/)
- s(node, :call, nil, node.name)
- else
- s(node, :lvar, node.name)
- end
- end
-
- # foo = 1
- # ^^^^^^^
- #
- # foo, bar = 1
- # ^^^ ^^^
- def visit_local_variable_write_node(node)
- s(node, :lasgn, node.name, visit_write_value(node.value))
- end
-
- # foo += bar
- # ^^^^^^^^^^
- def visit_local_variable_operator_write_node(node)
- s(node, :lasgn, node.name, s(node, :call, s(node, :lvar, node.name), node.binary_operator, visit_write_value(node.value)))
- end
-
- # foo &&= bar
- # ^^^^^^^^^^^
- def visit_local_variable_and_write_node(node)
- s(node, :op_asgn_and, s(node, :lvar, node.name), s(node, :lasgn, node.name, visit_write_value(node.value)))
- end
-
- # foo ||= bar
- # ^^^^^^^^^^^
- def visit_local_variable_or_write_node(node)
- s(node, :op_asgn_or, s(node, :lvar, node.name), s(node, :lasgn, node.name, visit_write_value(node.value)))
- end
-
- # foo, = bar
- # ^^^
- def visit_local_variable_target_node(node)
- s(node, :lasgn, node.name)
- end
-
- # if /foo/ then end
- # ^^^^^
- def visit_match_last_line_node(node)
- s(node, :match, s(node, :lit, Regexp.new(node.unescaped, node.options)))
- end
-
- # foo in bar
- # ^^^^^^^^^^
- def visit_match_predicate_node(node)
- s(node, :case, visit(node.value), s(node, :in, node.pattern.accept(copy_compiler(in_pattern: true)), nil), nil)
- end
-
- # foo => bar
- # ^^^^^^^^^^
- def visit_match_required_node(node)
- s(node, :case, visit(node.value), s(node, :in, node.pattern.accept(copy_compiler(in_pattern: true)), nil), nil)
- end
-
- # /(?<foo>foo)/ =~ bar
- # ^^^^^^^^^^^^^^^^^^^^
- def visit_match_write_node(node)
- s(node, :match2, visit(node.call.receiver), visit(node.call.arguments.arguments.first))
- end
-
- # A node that is missing from the syntax tree. This is only used in the
- # case of a syntax error. The parser gem doesn't have such a concept, so
- # we invent our own here.
- def visit_missing_node(node)
- raise "Cannot visit missing node directly"
- end
-
- # module Foo; end
- # ^^^^^^^^^^^^^^^
- def visit_module_node(node)
- name =
- if node.constant_path.is_a?(ConstantReadNode)
- node.name
- else
- visit(node.constant_path)
- end
-
- if node.body.nil?
- s(node, :module, name)
- elsif node.body.is_a?(StatementsNode)
- compiler = copy_compiler(in_def: false)
- s(node, :module, name).concat(node.body.body.map { |child| child.accept(compiler) })
- else
- s(node, :module, name, node.body.accept(copy_compiler(in_def: false)))
- end
- end
-
- # foo, bar = baz
- # ^^^^^^^^
- def visit_multi_target_node(node)
- targets = [*node.lefts]
- targets << node.rest if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode)
- targets.concat(node.rights)
-
- s(node, :masgn, s(node, :array).concat(visit_all(targets)))
- end
-
- # foo, bar = baz
- # ^^^^^^^^^^^^^^
- def visit_multi_write_node(node)
- targets = [*node.lefts]
- targets << node.rest if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode)
- targets.concat(node.rights)
-
- value =
- if node.value.is_a?(ArrayNode) && node.value.opening_loc.nil?
- if node.value.elements.length == 1 && node.value.elements.first.is_a?(SplatNode)
- visit(node.value.elements.first)
- else
- visit(node.value)
- end
- else
- s(node.value, :to_ary, visit(node.value))
- end
-
- s(node, :masgn, s(node, :array).concat(visit_all(targets)), value)
- end
-
- # next
- # ^^^^
- #
- # next foo
- # ^^^^^^^^
- def visit_next_node(node)
- if node.arguments.nil?
- s(node, :next)
- elsif node.arguments.arguments.length == 1
- argument = node.arguments.arguments.first
- s(node, :next, argument.is_a?(SplatNode) ? s(node, :svalue, visit(argument)) : visit(argument))
- else
- s(node, :next, s(node, :array).concat(visit_all(node.arguments.arguments)))
- end
- end
-
- # nil
- # ^^^
- def visit_nil_node(node)
- s(node, :nil)
- end
-
- # def foo(**nil); end
- # ^^^^^
- def visit_no_keywords_parameter_node(node)
- in_pattern ? s(node, :kwrest, :"**nil") : :"**nil"
- end
-
- # -> { _1 + _2 }
- # ^^^^^^^^^^^^^^
- def visit_numbered_parameters_node(node)
- raise "Cannot visit numbered parameters directly"
- end
-
- # $1
- # ^^
- def visit_numbered_reference_read_node(node)
- s(node, :nth_ref, node.number)
- end
-
- # def foo(bar: baz); end
- # ^^^^^^^^
- def visit_optional_keyword_parameter_node(node)
- s(node, :kwarg, node.name, visit(node.value))
- end
-
- # def foo(bar = 1); end
- # ^^^^^^^
- def visit_optional_parameter_node(node)
- s(node, :lasgn, node.name, visit(node.value))
- end
-
- # a or b
- # ^^^^^^
- def visit_or_node(node)
- left = visit(node.left)
-
- if left[0] == :or
- # ruby_parser has the or keyword as right-associative as opposed to
- # prism which has it as left-associative. We reverse that
- # associativity here.
- nest = left
- nest = nest[2] while nest[2][0] == :or
- nest[2] = s(node, :or, nest[2], visit(node.right))
- left
- else
- s(node, :or, left, visit(node.right))
- end
- end
-
- # def foo(bar, *baz); end
- # ^^^^^^^^^
- def visit_parameters_node(node)
- children =
- node.compact_child_nodes.map do |element|
- if element.is_a?(MultiTargetNode)
- visit_destructured_parameter(element)
- else
- visit(element)
- end
- end
-
- s(node, :args).concat(children)
- end
-
- # def foo((bar, baz)); end
- # ^^^^^^^^^^
- private def visit_destructured_parameter(node)
- children =
- [*node.lefts, *node.rest, *node.rights].map do |child|
- case child
- when RequiredParameterNode
- visit(child)
- when MultiTargetNode
- visit_destructured_parameter(child)
- when SplatNode
- :"*#{child.expression&.name}"
- else
- raise
- end
- end
-
- s(node, :masgn).concat(children)
- end
-
- # ()
- # ^^
- #
- # (1)
- # ^^^
- def visit_parentheses_node(node)
- if node.body.nil?
- s(node, :nil)
- else
- visit(node.body)
- end
- end
-
- # foo => ^(bar)
- # ^^^^^^
- def visit_pinned_expression_node(node)
- node.expression.accept(copy_compiler(in_pattern: false))
- end
-
- # foo = 1 and bar => ^foo
- # ^^^^
- def visit_pinned_variable_node(node)
- if node.variable.is_a?(LocalVariableReadNode) && node.variable.name.match?(/^_\d$/)
- s(node, :lvar, node.variable.name)
- else
- visit(node.variable)
- end
- end
-
- # END {}
- def visit_post_execution_node(node)
- s(node, :iter, s(node, :postexe), 0, visit(node.statements))
- end
-
- # BEGIN {}
- def visit_pre_execution_node(node)
- s(node, :iter, s(node, :preexe), 0, visit(node.statements))
- end
-
- # The top-level program node.
- def visit_program_node(node)
- visit(node.statements)
- end
-
- # 0..5
- # ^^^^
- def visit_range_node(node)
- if !in_pattern && !node.left.nil? && !node.right.nil? && ([node.left.type, node.right.type] - %i[nil_node integer_node]).empty?
- left = node.left.value if node.left.is_a?(IntegerNode)
- right = node.right.value if node.right.is_a?(IntegerNode)
- s(node, :lit, Range.new(left, right, node.exclude_end?))
- else
- s(node, node.exclude_end? ? :dot3 : :dot2, visit_range_bounds_node(node.left), visit_range_bounds_node(node.right))
- end
- end
-
- # If the bounds of a range node are empty parentheses, then they do not
- # get replaced by their usual s(:nil), but instead are s(:begin).
- private def visit_range_bounds_node(node)
- if node.is_a?(ParenthesesNode) && node.body.nil?
- s(node, :begin)
- else
- visit(node)
- end
- end
-
- # 1r
- # ^^
- def visit_rational_node(node)
- s(node, :lit, node.value)
- end
-
- # redo
- # ^^^^
- def visit_redo_node(node)
- s(node, :redo)
- end
-
- # /foo/
- # ^^^^^
- def visit_regular_expression_node(node)
- s(node, :lit, Regexp.new(node.unescaped, node.options))
- end
-
- # def foo(bar:); end
- # ^^^^
- def visit_required_keyword_parameter_node(node)
- s(node, :kwarg, node.name)
- end
-
- # def foo(bar); end
- # ^^^
- def visit_required_parameter_node(node)
- node.name
- end
-
- # foo rescue bar
- # ^^^^^^^^^^^^^^
- def visit_rescue_modifier_node(node)
- s(node, :rescue, visit(node.expression), s(node.rescue_expression, :resbody, s(node.rescue_expression, :array), visit(node.rescue_expression)))
- end
-
- # begin; rescue; end
- # ^^^^^^^
- def visit_rescue_node(node)
- exceptions =
- if node.exceptions.length == 1 && node.exceptions.first.is_a?(SplatNode)
- visit(node.exceptions.first)
- else
- s(node, :array).concat(visit_all(node.exceptions))
- end
-
- if !node.reference.nil?
- exceptions << (visit(node.reference) << s(node.reference, :gvar, :"$!"))
- end
-
- s(node, :resbody, exceptions).concat(node.statements.nil? ? [nil] : visit_all(node.statements.body))
- end
-
- # def foo(*bar); end
- # ^^^^
- #
- # def foo(*); end
- # ^
- def visit_rest_parameter_node(node)
- :"*#{node.name}"
- end
-
- # retry
- # ^^^^^
- def visit_retry_node(node)
- s(node, :retry)
- end
-
- # return
- # ^^^^^^
- #
- # return 1
- # ^^^^^^^^
- def visit_return_node(node)
- if node.arguments.nil?
- s(node, :return)
- elsif node.arguments.arguments.length == 1
- argument = node.arguments.arguments.first
- s(node, :return, argument.is_a?(SplatNode) ? s(node, :svalue, visit(argument)) : visit(argument))
- else
- s(node, :return, s(node, :array).concat(visit_all(node.arguments.arguments)))
- end
- end
-
- # self
- # ^^^^
- def visit_self_node(node)
- s(node, :self)
- end
-
- # A shareable constant.
- def visit_shareable_constant_node(node)
- visit(node.write)
- end
-
- # class << self; end
- # ^^^^^^^^^^^^^^^^^^
- def visit_singleton_class_node(node)
- s(node, :sclass, visit(node.expression)).tap do |sexp|
- sexp << node.body.accept(copy_compiler(in_def: false)) unless node.body.nil?
- end
- end
-
- # __ENCODING__
- # ^^^^^^^^^^^^
- def visit_source_encoding_node(node)
- # TODO
- s(node, :colon2, s(node, :const, :Encoding), :UTF_8)
- end
-
- # __FILE__
- # ^^^^^^^^
- def visit_source_file_node(node)
- s(node, :str, node.filepath)
- end
-
- # __LINE__
- # ^^^^^^^^
- def visit_source_line_node(node)
- s(node, :lit, node.location.start_line)
- end
-
- # foo(*bar)
- # ^^^^
- #
- # def foo((bar, *baz)); end
- # ^^^^
- #
- # def foo(*); bar(*); end
- # ^
- def visit_splat_node(node)
- if node.expression.nil?
- s(node, :splat)
- else
- s(node, :splat, visit(node.expression))
- end
- end
-
- # A list of statements.
- def visit_statements_node(node)
- first, *rest = node.body
-
- if rest.empty?
- visit(first)
- else
- s(node, :block).concat(visit_all(node.body))
- end
- end
-
- # "foo"
- # ^^^^^
- def visit_string_node(node)
- unescaped = node.unescaped
-
- if node.forced_binary_encoding?
- unescaped.force_encoding(Encoding::BINARY)
- end
-
- s(node, :str, unescaped)
- end
-
- # super(foo)
- # ^^^^^^^^^^
- def visit_super_node(node)
- arguments = node.arguments&.arguments || []
- block = node.block
-
- if block.is_a?(BlockArgumentNode)
- arguments << block
- block = nil
- end
-
- visit_block(node, s(node, :super).concat(visit_all(arguments)), block)
- end
-
- # :foo
- # ^^^^
- def visit_symbol_node(node)
- node.value == "!@" ? s(node, :lit, :"!@") : s(node, :lit, node.unescaped.to_sym)
- end
-
- # true
- # ^^^^
- def visit_true_node(node)
- s(node, :true)
- end
-
- # undef foo
- # ^^^^^^^^^
- def visit_undef_node(node)
- names = node.names.map { |name| s(node, :undef, visit(name)) }
- names.length == 1 ? names.first : s(node, :block).concat(names)
- end
-
- # unless foo; bar end
- # ^^^^^^^^^^^^^^^^^^^
- #
- # bar unless foo
- # ^^^^^^^^^^^^^^
- def visit_unless_node(node)
- s(node, :if, visit(node.predicate), visit(node.else_clause), visit(node.statements))
- end
-
- # until foo; bar end
- # ^^^^^^^^^^^^^^^^^
- #
- # bar until foo
- # ^^^^^^^^^^^^^
- def visit_until_node(node)
- s(node, :until, visit(node.predicate), visit(node.statements), !node.begin_modifier?)
- end
-
- # case foo; when bar; end
- # ^^^^^^^^^^^^^
- def visit_when_node(node)
- s(node, :when, s(node, :array).concat(visit_all(node.conditions))).concat(node.statements.nil? ? [nil] : visit_all(node.statements.body))
- end
-
- # while foo; bar end
- # ^^^^^^^^^^^^^^^^^^
- #
- # bar while foo
- # ^^^^^^^^^^^^^
- def visit_while_node(node)
- s(node, :while, visit(node.predicate), visit(node.statements), !node.begin_modifier?)
- end
-
- # `foo`
- # ^^^^^
- def visit_x_string_node(node)
- result = s(node, :xstr, node.unescaped)
-
- if node.heredoc?
- result.line = node.content_loc.start_line
- result.line_max = node.content_loc.end_line
- end
-
- result
- end
-
- # yield
- # ^^^^^
- #
- # yield 1
- # ^^^^^^^
- def visit_yield_node(node)
- s(node, :yield).concat(visit_all(node.arguments&.arguments || []))
- end
-
- private
-
- # Create a new compiler with the given options.
- def copy_compiler(in_def: self.in_def, in_pattern: self.in_pattern)
- Compiler.new(file, in_def: in_def, in_pattern: in_pattern)
- end
-
- # Create a new Sexp object from the given prism node and arguments.
- def s(node, *arguments)
- result = Sexp.new(*arguments)
- result.file = file
- result.line = node.location.start_line
- result.line_max = node.location.end_line
- result
- end
-
- # Visit a block node, which will modify the AST by wrapping the given
- # visited node in an iter node.
- def visit_block(node, sexp, block)
- if block.nil?
- sexp
- else
- parameters =
- case block.parameters
- when nil, NumberedParametersNode
- 0
- else
- visit(block.parameters)
- end
-
- if block.body.nil?
- s(node, :iter, sexp, parameters)
- else
- s(node, :iter, sexp, parameters, visit(block.body))
- end
- end
- end
-
- # Pattern constants get wrapped in another layer of :const.
- def visit_pattern_constant(node)
- case node
- when nil
- # nothing
- when ConstantReadNode
- visit(node)
- else
- s(node, :const, visit(node))
- end
- end
-
- # Visit the value of a write, which will be on the right-hand side of
- # a write operator. Because implicit arrays can have splats, those could
- # potentially be wrapped in an svalue node.
- def visit_write_value(node)
- if node.is_a?(ArrayNode) && node.opening_loc.nil?
- if node.elements.length == 1 && node.elements.first.is_a?(SplatNode)
- s(node, :svalue, visit(node.elements.first))
- else
- s(node, :svalue, visit(node))
- end
- else
- visit(node)
- end
- end
- end
-
- private_constant :Compiler
-
- # Parse the given source and translate it into the seattlerb/ruby_parser
- # gem's Sexp format.
- def parse(source, filepath = "(string)")
- translate(Prism.parse(source, filepath: filepath, partial_script: true), filepath)
- end
-
- # Parse the given file and translate it into the seattlerb/ruby_parser
- # gem's Sexp format.
- def parse_file(filepath)
- translate(Prism.parse_file(filepath, partial_script: true), filepath)
- end
-
- class << self
- # Parse the given source and translate it into the seattlerb/ruby_parser
- # gem's Sexp format.
- def parse(source, filepath = "(string)")
- new.parse(source, filepath)
- end
-
- # Parse the given file and translate it into the seattlerb/ruby_parser
- # gem's Sexp format.
- def parse_file(filepath)
- new.parse_file(filepath)
- end
- end
-
- private
-
- # Translate the given parse result and filepath into the
- # seattlerb/ruby_parser gem's Sexp format.
- def translate(result, filepath)
- if result.failure?
- error = result.errors.first
- raise ::RubyParser::SyntaxError, "#{filepath}:#{error.location.start_line} :: #{error.message}"
- end
-
- result.value.accept(Compiler.new(filepath))
- end
- end
- end
-end
diff --git a/lib/pstore.gemspec b/lib/pstore.gemspec
deleted file mode 100644
index 86051d2f43..0000000000
--- a/lib/pstore.gemspec
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{Transactional File Storage for Ruby Objects}
- spec.description = spec.summary
- spec.homepage = "https://github.com/ruby/pstore"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = "https://github.com/ruby/pstore"
-
- # Specify which files should be added to the gem when it is released.
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.bindir = "exe"
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
- spec.require_paths = ["lib"]
-end
diff --git a/lib/pstore.rb b/lib/pstore.rb
index 57ecb0ef5c..72deaa1017 100644
--- a/lib/pstore.rb
+++ b/lib/pstore.rb
@@ -326,7 +326,7 @@ require "digest"
# end
#
class PStore
- VERSION = "0.1.3"
+ VERSION = "0.1.2"
RDWR_ACCESS = {mode: IO::RDWR | IO::CREAT | IO::BINARY, encoding: Encoding::ASCII_8BIT}.freeze
RD_ACCESS = {mode: IO::RDONLY | IO::BINARY, encoding: Encoding::ASCII_8BIT}.freeze
@@ -437,7 +437,7 @@ class PStore
in_transaction
unless @table.key? key
if default == PStore::Error
- raise PStore::Error, format("undefined key '%s'", key)
+ raise PStore::Error, format("undefined key `%s'", key)
else
return default
end
@@ -487,6 +487,8 @@ class PStore
# end
#
# Raises an exception if called outside a transaction block.
+ #
+ # PStore#roots is an alias for PStore#keys.
def keys
in_transaction
@table.keys
@@ -502,6 +504,8 @@ class PStore
# end
#
# Raises an exception if called outside a transaction block.
+ #
+ # PStore#root? is an alias for PStore#key?.
def key?(key)
in_transaction
@table.key? key
@@ -517,8 +521,8 @@ class PStore
end
# Exits the current transaction block, committing any changes
- # specified in the
- # {transaction block}[rdoc-ref:PStore@The+Transaction+Block].
+ # specified in the transaction block.
+ # See {Committing or Aborting}[rdoc-ref:PStore@Committing+or+Aborting].
#
# Raises an exception if called outside a transaction block.
def commit
@@ -528,8 +532,8 @@ class PStore
end
# Exits the current transaction block, discarding any changes
- # specified in the
- # {transaction block}[rdoc-ref:PStore@The+Transaction+Block].
+ # specified in the transaction block.
+ # See {Committing or Aborting}[rdoc-ref:PStore@Committing+or+Aborting].
#
# Raises an exception if called outside a transaction block.
def abort
diff --git a/lib/pstore/pstore.gemspec b/lib/pstore/pstore.gemspec
new file mode 100644
index 0000000000..8425795afe
--- /dev/null
+++ b/lib/pstore/pstore.gemspec
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{Transactional File Storage for Ruby Objects}
+ spec.description = spec.summary
+ spec.homepage = "https://github.com/ruby/pstore"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = "https://github.com/ruby/pstore"
+
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/racc.rb b/lib/racc.rb
new file mode 100644
index 0000000000..f6e4ac03a8
--- /dev/null
+++ b/lib/racc.rb
@@ -0,0 +1,6 @@
+require 'racc/compat'
+require 'racc/debugflags'
+require 'racc/grammar'
+require 'racc/state'
+require 'racc/exception'
+require 'racc/info'
diff --git a/lib/racc/compat.rb b/lib/racc/compat.rb
new file mode 100644
index 0000000000..62f4f630be
--- /dev/null
+++ b/lib/racc/compat.rb
@@ -0,0 +1,33 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+unless Object.method_defined?(:__send)
+ class Object
+ alias __send __send__
+ end
+end
+
+unless Object.method_defined?(:__send!)
+ class Object
+ alias __send! __send__
+ end
+end
+
+unless Array.method_defined?(:map!)
+ class Array
+ if Array.method_defined?(:collect!)
+ alias map! collect!
+ else
+ alias map! filter
+ end
+ end
+end
diff --git a/lib/racc/debugflags.rb b/lib/racc/debugflags.rb
new file mode 100644
index 0000000000..ee34cf2314
--- /dev/null
+++ b/lib/racc/debugflags.rb
@@ -0,0 +1,60 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+module Racc
+
+ class DebugFlags
+ def DebugFlags.parse_option_string(s)
+ parse = rule = token = state = la = prec = conf = false
+ s.split(//).each do |ch|
+ case ch
+ when 'p' then parse = true
+ when 'r' then rule = true
+ when 't' then token = true
+ when 's' then state = true
+ when 'l' then la = true
+ when 'c' then prec = true
+ when 'o' then conf = true
+ else
+ raise "unknown debug flag char: #{ch.inspect}"
+ end
+ end
+ new(parse, rule, token, state, la, prec, conf)
+ end
+
+ def initialize(parse = false, rule = false, token = false, state = false,
+ la = false, prec = false, conf = false)
+ @parse = parse
+ @rule = rule
+ @token = token
+ @state = state
+ @la = la
+ @prec = prec
+ @any = (parse || rule || token || state || la || prec)
+ @status_logging = conf
+ end
+
+ attr_reader :parse
+ attr_reader :rule
+ attr_reader :token
+ attr_reader :state
+ attr_reader :la
+ attr_reader :prec
+
+ def any?
+ @any
+ end
+
+ attr_reader :status_logging
+ end
+
+end
diff --git a/lib/racc/exception.rb b/lib/racc/exception.rb
new file mode 100644
index 0000000000..c11dc2e43e
--- /dev/null
+++ b/lib/racc/exception.rb
@@ -0,0 +1,16 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+module Racc
+ class Error < StandardError; end
+ class CompileError < Error; end
+end
diff --git a/lib/racc/grammar.rb b/lib/racc/grammar.rb
new file mode 100644
index 0000000000..01c4c3df69
--- /dev/null
+++ b/lib/racc/grammar.rb
@@ -0,0 +1,1118 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+require 'racc/compat'
+require 'racc/iset'
+require 'racc/sourcetext'
+require 'racc/logfilegenerator'
+require 'racc/exception'
+require 'forwardable'
+
+module Racc
+
+ class Grammar
+
+ def initialize(debug_flags = DebugFlags.new)
+ @symboltable = SymbolTable.new
+ @debug_symbol = debug_flags.token
+ @rules = [] # :: [Rule]
+ @start = nil
+ @n_expected_srconflicts = nil
+ @prec_table = []
+ @prec_table_closed = false
+ @closed = false
+ @states = nil
+ end
+
+ attr_reader :start
+ attr_reader :symboltable
+ attr_accessor :n_expected_srconflicts
+
+ def [](x)
+ @rules[x]
+ end
+
+ def each_rule(&block)
+ @rules.each(&block)
+ end
+
+ alias each each_rule
+
+ def each_index(&block)
+ @rules.each_index(&block)
+ end
+
+ def each_with_index(&block)
+ @rules.each_with_index(&block)
+ end
+
+ def size
+ @rules.size
+ end
+
+ def to_s
+ "<Racc::Grammar>"
+ end
+
+ extend Forwardable
+
+ def_delegator "@symboltable", :each, :each_symbol
+ def_delegator "@symboltable", :each_terminal
+ def_delegator "@symboltable", :each_nonterminal
+
+ def intern(value, dummy = false)
+ @symboltable.intern(value, dummy)
+ end
+
+ def symbols
+ @symboltable.symbols
+ end
+
+ def nonterminal_base
+ @symboltable.nt_base
+ end
+
+ def useless_nonterminal_exist?
+ n_useless_nonterminals() != 0
+ end
+
+ def n_useless_nonterminals
+ @n_useless_nonterminals ||= each_useless_nonterminal.count
+ end
+
+ def each_useless_nonterminal
+ return to_enum __method__ unless block_given?
+
+ @symboltable.each_nonterminal do |sym|
+ yield sym if sym.useless?
+ end
+ end
+
+ def useless_rule_exist?
+ n_useless_rules() != 0
+ end
+
+ def n_useless_rules
+ @n_useless_rules ||= each_useless_rule.count
+ end
+
+ def each_useless_rule
+ return to_enum __method__ unless block_given?
+
+ each do |r|
+ yield r if r.useless?
+ end
+ end
+
+ def nfa
+ (@states ||= States.new(self)).nfa
+ end
+
+ def dfa
+ (@states ||= States.new(self)).dfa
+ end
+
+ alias states dfa
+
+ def state_transition_table
+ states().state_transition_table
+ end
+
+ def parser_class
+ states = states() # cache
+ if $DEBUG
+ srcfilename = caller(1).first.slice(/\A(.*?):/, 1)
+ begin
+ write_log srcfilename + ".output"
+ rescue SystemCallError
+ end
+ report = lambda {|s| $stderr.puts "racc: #{srcfilename}: #{s}" }
+ if states.should_report_srconflict?
+ report["#{states.n_srconflicts} shift/reduce conflicts"]
+ end
+ if states.rrconflict_exist?
+ report["#{states.n_rrconflicts} reduce/reduce conflicts"]
+ end
+ g = states.grammar
+ if g.useless_nonterminal_exist?
+ report["#{g.n_useless_nonterminals} useless nonterminals"]
+ end
+ if g.useless_rule_exist?
+ report["#{g.n_useless_rules} useless rules"]
+ end
+ end
+ states.state_transition_table.parser_class
+ end
+
+ def write_log(path)
+ File.open(path, 'w') {|f|
+ LogFileGenerator.new(states()).output f
+ }
+ end
+
+ #
+ # Grammar Definition Interface
+ #
+
+ def add(rule)
+ raise ArgumentError, "rule added after the Grammar closed" if @closed
+ @rules.push rule
+ end
+
+ def added?(sym)
+ @rules.detect {|r| r.target == sym }
+ end
+
+ def start_symbol=(s)
+ raise CompileError, "start symbol set twice'" if @start
+ @start = s
+ end
+
+ def declare_precedence(assoc, syms)
+ raise CompileError, "precedence table defined twice" if @prec_table_closed
+ @prec_table.push [assoc, syms]
+ end
+
+ def end_precedence_declaration(reverse)
+ @prec_table_closed = true
+ return if @prec_table.empty?
+ table = reverse ? @prec_table.reverse : @prec_table
+ table.each_with_index do |(assoc, syms), idx|
+ syms.each do |sym|
+ sym.assoc = assoc
+ sym.precedence = idx
+ end
+ end
+ end
+
+ #
+ # Dynamic Generation Interface
+ #
+
+ def Grammar.define(&block)
+ env = DefinitionEnv.new
+ env.instance_eval(&block)
+ env.grammar
+ end
+
+ class DefinitionEnv
+ def initialize
+ @grammar = Grammar.new
+ @seqs = Hash.new(0)
+ @delayed = []
+ end
+
+ def grammar
+ flush_delayed
+ @grammar.each do |rule|
+ if rule.specified_prec
+ rule.specified_prec = @grammar.intern(rule.specified_prec)
+ end
+ end
+ @grammar.init
+ @grammar
+ end
+
+ def precedence_table(&block)
+ env = PrecedenceDefinitionEnv.new(@grammar)
+ env.instance_eval(&block)
+ @grammar.end_precedence_declaration env.reverse
+ end
+
+ def method_missing(mid, *args, &block)
+ unless mid.to_s[-1,1] == '='
+ super # raises NoMethodError
+ end
+ target = @grammar.intern(mid.to_s.chop.intern)
+ unless args.size == 1
+ raise ArgumentError, "too many arguments for #{mid} (#{args.size} for 1)"
+ end
+ _add target, args.first
+ end
+
+ def _add(target, x)
+ case x
+ when Sym
+ @delayed.each do |rule|
+ rule.replace x, target if rule.target == x
+ end
+ @grammar.symboltable.delete x
+ else
+ x.each_rule do |r|
+ r.target = target
+ @grammar.add r
+ end
+ end
+ flush_delayed
+ end
+
+ def _delayed_add(rule)
+ @delayed.push rule
+ end
+
+ def _added?(sym)
+ @grammar.added?(sym) or @delayed.detect {|r| r.target == sym }
+ end
+
+ def flush_delayed
+ return if @delayed.empty?
+ @delayed.each do |rule|
+ @grammar.add rule
+ end
+ @delayed.clear
+ end
+
+ def seq(*list, &block)
+ Rule.new(nil, list.map {|x| _intern(x) }, UserAction.proc(block))
+ end
+
+ def null(&block)
+ seq(&block)
+ end
+
+ def action(&block)
+ id = "@#{@seqs["action"] += 1}".intern
+ _delayed_add Rule.new(@grammar.intern(id), [], UserAction.proc(block))
+ id
+ end
+
+ alias _ action
+
+ def option(sym, default = nil, &block)
+ _defmetasyntax("option", _intern(sym), block) {|target|
+ seq() { default } | seq(sym)
+ }
+ end
+
+ def many(sym, &block)
+ _defmetasyntax("many", _intern(sym), block) {|target|
+ seq() { [] }\
+ | seq(target, sym) {|list, x| list.push x; list }
+ }
+ end
+
+ def many1(sym, &block)
+ _defmetasyntax("many1", _intern(sym), block) {|target|
+ seq(sym) {|x| [x] }\
+ | seq(target, sym) {|list, x| list.push x; list }
+ }
+ end
+
+ def separated_by(sep, sym, &block)
+ option(separated_by1(sep, sym), [], &block)
+ end
+
+ def separated_by1(sep, sym, &block)
+ _defmetasyntax("separated_by1", _intern(sym), block) {|target|
+ seq(sym) {|x| [x] }\
+ | seq(target, sep, sym) {|list, _, x| list.push x; list }
+ }
+ end
+
+ def _intern(x)
+ case x
+ when Symbol, String
+ @grammar.intern(x)
+ when Racc::Sym
+ x
+ else
+ raise TypeError, "wrong type #{x.class} (expected Symbol/String/Racc::Sym)"
+ end
+ end
+
+ private
+
+ def _defmetasyntax(type, id, action, &block)
+ if action
+ idbase = "#{type}@#{id}-#{@seqs[type] += 1}"
+ target = _wrap(idbase, "#{idbase}-core", action)
+ _register("#{idbase}-core", &block)
+ else
+ target = _register("#{type}@#{id}", &block)
+ end
+ @grammar.intern(target)
+ end
+
+ def _register(target_name)
+ target = target_name.intern
+ unless _added?(@grammar.intern(target))
+ yield(target).each_rule do |rule|
+ rule.target = @grammar.intern(target)
+ _delayed_add rule
+ end
+ end
+ target
+ end
+
+ def _wrap(target_name, sym, block)
+ target = target_name.intern
+ _delayed_add Rule.new(@grammar.intern(target),
+ [@grammar.intern(sym.intern)],
+ UserAction.proc(block))
+ target
+ end
+ end
+
+ class PrecedenceDefinitionEnv
+ def initialize(g)
+ @grammar = g
+ @prechigh_seen = false
+ @preclow_seen = false
+ @reverse = false
+ end
+
+ attr_reader :reverse
+
+ def higher
+ if @prechigh_seen
+ raise CompileError, "prechigh used twice"
+ end
+ @prechigh_seen = true
+ end
+
+ def lower
+ if @preclow_seen
+ raise CompileError, "preclow used twice"
+ end
+ if @prechigh_seen
+ @reverse = true
+ end
+ @preclow_seen = true
+ end
+
+ def left(*syms)
+ @grammar.declare_precedence :Left, syms.map {|s| @grammar.intern(s) }
+ end
+
+ def right(*syms)
+ @grammar.declare_precedence :Right, syms.map {|s| @grammar.intern(s) }
+ end
+
+ def nonassoc(*syms)
+ @grammar.declare_precedence :Nonassoc, syms.map {|s| @grammar.intern(s)}
+ end
+ end
+
+ #
+ # Computation
+ #
+
+ def init
+ return if @closed
+ @closed = true
+ @start ||= @rules.map {|r| r.target }.detect {|sym| not sym.dummy? }
+ raise CompileError, 'no rule in input' if @rules.empty?
+ add_start_rule
+ @rules.freeze
+ fix_ident
+ compute_hash
+ compute_heads
+ determine_terminals
+ compute_nullable_0
+ @symboltable.fix
+ compute_locate
+ @symboltable.each_nonterminal {|t| compute_expand t }
+ compute_nullable
+ compute_useless
+ end
+
+ private
+
+ def add_start_rule
+ r = Rule.new(@symboltable.dummy,
+ [@start, @symboltable.anchor, @symboltable.anchor],
+ UserAction.empty)
+ r.ident = 0
+ r.hash = 0
+ r.precedence = nil
+ @rules.unshift r
+ end
+
+ # Rule#ident
+ # LocationPointer#ident
+ def fix_ident
+ @rules.each_with_index do |rule, idx|
+ rule.ident = idx
+ end
+ end
+
+ # Rule#hash
+ def compute_hash
+ hash = 4 # size of dummy rule
+ @rules.each do |rule|
+ rule.hash = hash
+ hash += (rule.size + 1)
+ end
+ end
+
+ # Sym#heads
+ def compute_heads
+ @rules.each do |rule|
+ rule.target.heads.push rule.ptrs[0]
+ end
+ end
+
+ # Sym#terminal?
+ def determine_terminals
+ @symboltable.each do |s|
+ s.term = s.heads.empty?
+ end
+ end
+
+ # Sym#self_null?
+ def compute_nullable_0
+ @symboltable.each do |s|
+ if s.terminal?
+ s.snull = false
+ else
+ s.snull = s.heads.any? {|loc| loc.reduce? }
+ end
+ end
+ end
+
+ # Sym#locate
+ def compute_locate
+ @rules.each do |rule|
+ t = nil
+ rule.ptrs.each do |ptr|
+ unless ptr.reduce?
+ tok = ptr.dereference
+ tok.locate.push ptr
+ t = tok if tok.terminal?
+ end
+ end
+ rule.precedence = t
+ end
+ end
+
+ # Sym#expand
+ def compute_expand(t)
+ puts "expand> #{t.to_s}" if @debug_symbol
+ t.expand = _compute_expand(t, ISet.new, [])
+ puts "expand< #{t.to_s}: #{t.expand.to_s}" if @debug_symbol
+ end
+
+ def _compute_expand(t, set, lock)
+ if tmp = t.expand
+ set.update tmp
+ return set
+ end
+ tok = nil
+ set.update_a t.heads
+ t.heads.each do |ptr|
+ tok = ptr.dereference
+ if tok and tok.nonterminal?
+ unless lock[tok.ident]
+ lock[tok.ident] = true
+ _compute_expand tok, set, lock
+ end
+ end
+ end
+ set
+ end
+
+ # Sym#nullable?, Rule#nullable?
+ def compute_nullable
+ @rules.each {|r| r.null = false }
+ @symboltable.each {|t| t.null = false }
+ r = @rules.dup
+ s = @symboltable.nonterminals
+ begin
+ rs = r.size
+ ss = s.size
+ check_rules_nullable r
+ check_symbols_nullable s
+ end until rs == r.size and ss == s.size
+ end
+
+ def check_rules_nullable(rules)
+ rules.delete_if do |rule|
+ rule.null = true
+ rule.symbols.each do |t|
+ unless t.nullable?
+ rule.null = false
+ break
+ end
+ end
+ rule.nullable?
+ end
+ end
+
+ def check_symbols_nullable(symbols)
+ symbols.delete_if do |sym|
+ sym.heads.each do |ptr|
+ if ptr.rule.nullable?
+ sym.null = true
+ break
+ end
+ end
+ sym.nullable?
+ end
+ end
+
+ # Sym#useless?, Rule#useless?
+ # FIXME: what means "useless"?
+ def compute_useless
+ @symboltable.each_terminal {|sym| sym.useless = false }
+ @symboltable.each_nonterminal {|sym| sym.useless = true }
+ @rules.each {|rule| rule.useless = true }
+ r = @rules.dup
+ s = @symboltable.nonterminals
+ begin
+ rs = r.size
+ ss = s.size
+ check_rules_useless r
+ check_symbols_useless s
+ end until r.size == rs and s.size == ss
+ end
+
+ def check_rules_useless(rules)
+ rules.delete_if do |rule|
+ rule.useless = false
+ rule.symbols.each do |sym|
+ if sym.useless?
+ rule.useless = true
+ break
+ end
+ end
+ not rule.useless?
+ end
+ end
+
+ def check_symbols_useless(s)
+ s.delete_if do |t|
+ t.heads.each do |ptr|
+ unless ptr.rule.useless?
+ t.useless = false
+ break
+ end
+ end
+ not t.useless?
+ end
+ end
+
+ end # class Grammar
+
+
+ class Rule
+
+ def initialize(target, syms, act)
+ @target = target
+ @symbols = syms
+ @action = act
+ @alternatives = []
+
+ @ident = nil
+ @hash = nil
+ @ptrs = nil
+ @precedence = nil
+ @specified_prec = nil
+ @null = nil
+ @useless = nil
+ end
+
+ attr_accessor :target
+ attr_reader :symbols
+ attr_reader :action
+
+ def |(x)
+ @alternatives.push x.rule
+ self
+ end
+
+ def rule
+ self
+ end
+
+ def each_rule(&block)
+ yield self
+ @alternatives.each(&block)
+ end
+
+ attr_accessor :ident
+
+ attr_reader :hash
+ attr_reader :ptrs
+
+ def hash=(n)
+ @hash = n
+ ptrs = []
+ @symbols.each_with_index do |sym, idx|
+ ptrs.push LocationPointer.new(self, idx, sym)
+ end
+ ptrs.push LocationPointer.new(self, @symbols.size, nil)
+ @ptrs = ptrs
+ end
+
+ def precedence
+ @specified_prec || @precedence
+ end
+
+ def precedence=(sym)
+ @precedence ||= sym
+ end
+
+ def prec(sym, &block)
+ @specified_prec = sym
+ if block
+ unless @action.empty?
+ raise CompileError, 'both of rule action block and prec block given'
+ end
+ @action = UserAction.proc(block)
+ end
+ self
+ end
+
+ attr_accessor :specified_prec
+
+ def nullable?() @null end
+ def null=(n) @null = n end
+
+ def useless?() @useless end
+ def useless=(u) @useless = u end
+
+ def inspect
+ "#<Racc::Rule id=#{@ident} (#{@target})>"
+ end
+
+ def ==(other)
+ other.kind_of?(Rule) and @ident == other.ident
+ end
+
+ def [](idx)
+ @symbols[idx]
+ end
+
+ def size
+ @symbols.size
+ end
+
+ def empty?
+ @symbols.empty?
+ end
+
+ def to_s
+ "#<rule#{@ident}>"
+ end
+
+ def accept?
+ if tok = @symbols[-1]
+ tok.anchor?
+ else
+ false
+ end
+ end
+
+ def each(&block)
+ @symbols.each(&block)
+ end
+
+ def replace(src, dest)
+ @target = dest
+ @symbols = @symbols.map {|s| s == src ? dest : s }
+ end
+
+ end # class Rule
+
+
+ class UserAction
+
+ def UserAction.source_text(src)
+ new(src, nil)
+ end
+
+ def UserAction.proc(pr = nil, &block)
+ if pr and block
+ raise ArgumentError, "both of argument and block given"
+ end
+ new(nil, pr || block)
+ end
+
+ def UserAction.empty
+ new(nil, nil)
+ end
+
+ private_class_method :new
+
+ def initialize(src, proc)
+ @source = src
+ @proc = proc
+ end
+
+ attr_reader :source
+ attr_reader :proc
+
+ def source?
+ not @proc
+ end
+
+ def proc?
+ not @source
+ end
+
+ def empty?
+ not @proc and not @source
+ end
+
+ def name
+ "{action type=#{@source || @proc || 'nil'}}"
+ end
+
+ alias inspect name
+
+ end
+
+
+ class OrMark
+ def initialize(lineno)
+ @lineno = lineno
+ end
+
+ def name
+ '|'
+ end
+
+ alias inspect name
+
+ attr_reader :lineno
+ end
+
+
+ class Prec
+ def initialize(symbol, lineno)
+ @symbol = symbol
+ @lineno = lineno
+ end
+
+ def name
+ "=#{@symbol}"
+ end
+
+ alias inspect name
+
+ attr_reader :symbol
+ attr_reader :lineno
+ end
+
+
+ #
+ # A set of rule and position in it's RHS.
+ # Note that the number of pointers is more than rule's RHS array,
+ # because pointer points right edge of the final symbol when reducing.
+ #
+ class LocationPointer
+
+ def initialize(rule, i, sym)
+ @rule = rule
+ @index = i
+ @symbol = sym
+ @ident = @rule.hash + i
+ @reduce = sym.nil?
+ end
+
+ attr_reader :rule
+ attr_reader :index
+ attr_reader :symbol
+
+ alias dereference symbol
+
+ attr_reader :ident
+ alias hash ident
+ attr_reader :reduce
+ alias reduce? reduce
+
+ def to_s
+ sprintf('(%d,%d %s)',
+ @rule.ident, @index, (reduce?() ? '#' : @symbol.to_s))
+ end
+
+ alias inspect to_s
+
+ def eql?(ot)
+ @hash == ot.hash
+ end
+
+ alias == eql?
+
+ def head?
+ @index == 0
+ end
+
+ def next
+ @rule.ptrs[@index + 1] or ptr_bug!
+ end
+
+ alias increment next
+
+ def before(len)
+ @rule.ptrs[@index - len] or ptr_bug!
+ end
+
+ private
+
+ def ptr_bug!
+ raise "racc: fatal: pointer not exist: self: #{to_s}"
+ end
+
+ end # class LocationPointer
+
+
+ class SymbolTable
+
+ include Enumerable
+
+ def initialize
+ @symbols = [] # :: [Racc::Sym]
+ @cache = {} # :: {(String|Symbol) => Racc::Sym}
+ @dummy = intern(:$start, true)
+ @anchor = intern(false, true) # Symbol ID = 0
+ @error = intern(:error, false) # Symbol ID = 1
+ end
+
+ attr_reader :dummy
+ attr_reader :anchor
+ attr_reader :error
+
+ def [](id)
+ @symbols[id]
+ end
+
+ def intern(val, dummy = false)
+ @cache[val] ||=
+ begin
+ sym = Sym.new(val, dummy)
+ @symbols.push sym
+ sym
+ end
+ end
+
+ attr_reader :symbols
+ alias to_a symbols
+
+ def delete(sym)
+ @symbols.delete sym
+ @cache.delete sym.value
+ end
+
+ attr_reader :nt_base
+
+ def nt_max
+ @symbols.size
+ end
+
+ def each(&block)
+ @symbols.each(&block)
+ end
+
+ def terminals(&block)
+ @symbols[0, @nt_base]
+ end
+
+ def each_terminal(&block)
+ @terms.each(&block)
+ end
+
+ def nonterminals
+ @symbols[@nt_base, @symbols.size - @nt_base]
+ end
+
+ def each_nonterminal(&block)
+ @nterms.each(&block)
+ end
+
+ def fix
+ terms, nterms = @symbols.partition {|s| s.terminal? }
+ @symbols = terms + nterms
+ @terms = terms
+ @nterms = nterms
+ @nt_base = terms.size
+ fix_ident
+ check_terminals
+ end
+
+ private
+
+ def fix_ident
+ @symbols.each_with_index do |t, i|
+ t.ident = i
+ end
+ end
+
+ def check_terminals
+ return unless @symbols.any? {|s| s.should_terminal? }
+ @anchor.should_terminal
+ @error.should_terminal
+ each_terminal do |t|
+ t.should_terminal if t.string_symbol?
+ end
+ each do |s|
+ s.should_terminal if s.assoc
+ end
+ terminals().reject {|t| t.should_terminal? }.each do |t|
+ raise CompileError, "terminal #{t} not declared as terminal"
+ end
+ nonterminals().select {|n| n.should_terminal? }.each do |n|
+ raise CompileError, "symbol #{n} declared as terminal but is not terminal"
+ end
+ end
+
+ end # class SymbolTable
+
+
+ # Stands terminal and nonterminal symbols.
+ class Sym
+
+ def initialize(value, dummyp)
+ @ident = nil
+ @value = value
+ @dummyp = dummyp
+
+ @term = nil
+ @nterm = nil
+ @should_terminal = false
+ @precedence = nil
+ case value
+ when Symbol
+ @to_s = value.to_s
+ @serialized = value.inspect
+ @string = false
+ when String
+ @to_s = value.inspect
+ @serialized = value.dump
+ @string = true
+ when false
+ @to_s = '$end'
+ @serialized = 'false'
+ @string = false
+ when ErrorSymbolValue
+ @to_s = 'error'
+ @serialized = 'Object.new'
+ @string = false
+ else
+ raise ArgumentError, "unknown symbol value: #{value.class}"
+ end
+
+ @heads = []
+ @locate = []
+ @snull = nil
+ @null = nil
+ @expand = nil
+ @useless = nil
+ end
+
+ class << self
+ def once_writer(nm)
+ nm = nm.id2name
+ module_eval(<<-EOS)
+ def #{nm}=(v)
+ raise 'racc: fatal: @#{nm} != nil' unless @#{nm}.nil?
+ @#{nm} = v
+ end
+ EOS
+ end
+ end
+
+ once_writer :ident
+ attr_reader :ident
+
+ alias hash ident
+
+ attr_reader :value
+
+ def dummy?
+ @dummyp
+ end
+
+ def terminal?
+ @term
+ end
+
+ def nonterminal?
+ @nterm
+ end
+
+ def term=(t)
+ raise 'racc: fatal: term= called twice' unless @term.nil?
+ @term = t
+ @nterm = !t
+ end
+
+ def should_terminal
+ @should_terminal = true
+ end
+
+ def should_terminal?
+ @should_terminal
+ end
+
+ def string_symbol?
+ @string
+ end
+
+ def serialize
+ @serialized
+ end
+
+ attr_writer :serialized
+
+ attr_accessor :precedence
+ attr_accessor :assoc
+
+ def to_s
+ @to_s.dup
+ end
+
+ alias inspect to_s
+
+ def |(x)
+ rule() | x.rule
+ end
+
+ def rule
+ Rule.new(nil, [self], UserAction.empty)
+ end
+
+ #
+ # cache
+ #
+
+ attr_reader :heads
+ attr_reader :locate
+
+ def self_null?
+ @snull
+ end
+
+ once_writer :snull
+
+ def nullable?
+ @null
+ end
+
+ def null=(n)
+ @null = n
+ end
+
+ attr_reader :expand
+ once_writer :expand
+
+ def useless?
+ @useless
+ end
+
+ def useless=(f)
+ @useless = f
+ end
+
+ end # class Sym
+
+end # module Racc
diff --git a/lib/racc/grammarfileparser.rb b/lib/racc/grammarfileparser.rb
new file mode 100644
index 0000000000..c7d1207f0b
--- /dev/null
+++ b/lib/racc/grammarfileparser.rb
@@ -0,0 +1,561 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+require 'racc'
+require 'racc/compat'
+require 'racc/grammar'
+require 'racc/parserfilegenerator'
+require 'racc/sourcetext'
+require 'stringio'
+
+module Racc
+
+ grammar = Grammar.define {
+ g = self
+
+ g.class = seq(:CLASS, :cname, many(:param), :RULE, :rules, option(:END))
+
+ g.cname = seq(:rubyconst) {|name|
+ @result.params.classname = name
+ }\
+ | seq(:rubyconst, "<", :rubyconst) {|c, _, s|
+ @result.params.classname = c
+ @result.params.superclass = s
+ }
+
+ g.rubyconst = separated_by1(:colon2, :SYMBOL) {|syms|
+ syms.map {|s| s.to_s }.join('::')
+ }
+
+ g.colon2 = seq(':', ':')
+
+ g.param = seq(:CONV, many1(:convdef), :END) {|*|
+ #@grammar.end_convert_block # FIXME
+ }\
+ | seq(:PRECHIGH, many1(:precdef), :PRECLOW) {|*|
+ @grammar.end_precedence_declaration true
+ }\
+ | seq(:PRECLOW, many1(:precdef), :PRECHIGH) {|*|
+ @grammar.end_precedence_declaration false
+ }\
+ | seq(:START, :symbol) {|_, sym|
+ @grammar.start_symbol = sym
+ }\
+ | seq(:TOKEN, :symbols) {|_, syms|
+ syms.each do |s|
+ s.should_terminal
+ end
+ }\
+ | seq(:OPTION, :options) {|_, syms|
+ syms.each do |opt|
+ case opt
+ when 'result_var'
+ @result.params.result_var = true
+ when 'no_result_var'
+ @result.params.result_var = false
+ when 'omit_action_call'
+ @result.params.omit_action_call = true
+ when 'no_omit_action_call'
+ @result.params.omit_action_call = false
+ else
+ raise CompileError, "unknown option: #{opt}"
+ end
+ end
+ }\
+ | seq(:EXPECT, :DIGIT) {|_, num|
+ if @grammar.n_expected_srconflicts
+ raise CompileError, "`expect' seen twice"
+ end
+ @grammar.n_expected_srconflicts = num
+ }
+
+ g.convdef = seq(:symbol, :STRING) {|sym, code|
+ sym.serialized = code
+ }
+
+ g.precdef = seq(:LEFT, :symbols) {|_, syms|
+ @grammar.declare_precedence :Left, syms
+ }\
+ | seq(:RIGHT, :symbols) {|_, syms|
+ @grammar.declare_precedence :Right, syms
+ }\
+ | seq(:NONASSOC, :symbols) {|_, syms|
+ @grammar.declare_precedence :Nonassoc, syms
+ }
+
+ g.symbols = seq(:symbol) {|sym|
+ [sym]
+ }\
+ | seq(:symbols, :symbol) {|list, sym|
+ list.push sym
+ list
+ }\
+ | seq(:symbols, "|")
+
+ g.symbol = seq(:SYMBOL) {|sym| @grammar.intern(sym) }\
+ | seq(:STRING) {|str| @grammar.intern(str) }
+
+ g.options = many(:SYMBOL) {|syms| syms.map {|s| s.to_s } }
+
+ g.rules = option(:rules_core) {|list|
+ add_rule_block list unless list.empty?
+ nil
+ }
+
+ g.rules_core = seq(:symbol) {|sym|
+ [sym]
+ }\
+ | seq(:rules_core, :rule_item) {|list, i|
+ list.push i
+ list
+ }\
+ | seq(:rules_core, ';') {|list, *|
+ add_rule_block list unless list.empty?
+ list.clear
+ list
+ }\
+ | seq(:rules_core, ':') {|list, *|
+ next_target = list.pop
+ add_rule_block list unless list.empty?
+ [next_target]
+ }
+
+ g.rule_item = seq(:symbol)\
+ | seq("|") {|*|
+ OrMark.new(@scanner.lineno)
+ }\
+ | seq("=", :symbol) {|_, sym|
+ Prec.new(sym, @scanner.lineno)
+ }\
+ | seq(:ACTION) {|src|
+ UserAction.source_text(src)
+ }
+ }
+
+ GrammarFileParser = grammar.parser_class
+
+ if grammar.states.srconflict_exist?
+ raise 'Racc boot script fatal: S/R conflict in build'
+ end
+ if grammar.states.rrconflict_exist?
+ raise 'Racc boot script fatal: R/R conflict in build'
+ end
+
+ class GrammarFileParser # reopen
+
+ class Result
+ def initialize(grammar)
+ @grammar = grammar
+ @params = ParserFileGenerator::Params.new
+ end
+
+ attr_reader :grammar
+ attr_reader :params
+ end
+
+ def GrammarFileParser.parse_file(filename)
+ parse(File.read(filename), filename, 1)
+ end
+
+ def GrammarFileParser.parse(src, filename = '-', lineno = 1)
+ new().parse(src, filename, lineno)
+ end
+
+ def initialize(debug_flags = DebugFlags.new)
+ @yydebug = debug_flags.parse
+ end
+
+ def parse(src, filename = '-', lineno = 1)
+ @filename = filename
+ @lineno = lineno
+ @scanner = GrammarFileScanner.new(src, @filename)
+ @scanner.debug = @yydebug
+ @grammar = Grammar.new
+ @result = Result.new(@grammar)
+ @embedded_action_seq = 0
+ yyparse @scanner, :yylex
+ parse_user_code
+ @result.grammar.init
+ @result
+ end
+
+ private
+
+ def next_token
+ @scanner.scan
+ end
+
+ def on_error(tok, val, _values)
+ if val.respond_to?(:id2name)
+ v = val.id2name
+ elsif val.kind_of?(String)
+ v = val
+ else
+ v = val.inspect
+ end
+ raise CompileError, "#{location()}: unexpected token '#{v}'"
+ end
+
+ def location
+ "#{@filename}:#{@lineno - 1 + @scanner.lineno}"
+ end
+
+ def add_rule_block(list)
+ sprec = nil
+ target = list.shift
+ case target
+ when OrMark, UserAction, Prec
+ raise CompileError, "#{target.lineno}: unexpected symbol #{target.name}"
+ end
+ curr = []
+ list.each do |i|
+ case i
+ when OrMark
+ add_rule target, curr, sprec
+ curr = []
+ sprec = nil
+ when Prec
+ raise CompileError, "'=<prec>' used twice in one rule" if sprec
+ sprec = i.symbol
+ else
+ curr.push i
+ end
+ end
+ add_rule target, curr, sprec
+ end
+
+ def add_rule(target, list, sprec)
+ if list.last.kind_of?(UserAction)
+ act = list.pop
+ else
+ act = UserAction.empty
+ end
+ list.map! {|s| s.kind_of?(UserAction) ? embedded_action(s) : s }
+ rule = Rule.new(target, list, act)
+ rule.specified_prec = sprec
+ @grammar.add rule
+ end
+
+ def embedded_action(act)
+ sym = @grammar.intern("@#{@embedded_action_seq += 1}".intern, true)
+ @grammar.add Rule.new(sym, [], act)
+ sym
+ end
+
+ #
+ # User Code Block
+ #
+
+ def parse_user_code
+ line = @scanner.lineno
+ _, *blocks = *@scanner.epilogue.split(/^----/)
+ blocks.each do |block|
+ header, *body = block.lines.to_a
+ label0, paths = *header.sub(/\A-+/, '').split('=', 2)
+ label = canonical_label(label0)
+ (paths ? paths.strip.split(' ') : []).each do |path|
+ add_user_code label, SourceText.new(File.read(path), path, 1)
+ end
+ add_user_code label, SourceText.new(body.join(''), @filename, line + 1)
+ line += (1 + body.size)
+ end
+ end
+
+ USER_CODE_LABELS = {
+ 'header' => :header,
+ 'prepare' => :header, # obsolete
+ 'inner' => :inner,
+ 'footer' => :footer,
+ 'driver' => :footer # obsolete
+ }
+
+ def canonical_label(src)
+ label = src.to_s.strip.downcase.slice(/\w+/)
+ unless USER_CODE_LABELS.key?(label)
+ raise CompileError, "unknown user code type: #{label.inspect}"
+ end
+ label
+ end
+
+ def add_user_code(label, src)
+ @result.params.public_send(USER_CODE_LABELS[label]).push src
+ end
+
+ end
+
+
+ class GrammarFileScanner
+
+ def initialize(str, filename = '-')
+ @lines = str.b.split(/\n|\r\n|\r/)
+ @filename = filename
+ @lineno = -1
+ @line_head = true
+ @in_rule_blk = false
+ @in_conv_blk = false
+ @in_block = nil
+ @epilogue = ''
+ @debug = false
+ next_line
+ end
+
+ attr_reader :epilogue
+
+ def lineno
+ @lineno + 1
+ end
+
+ attr_accessor :debug
+
+ def yylex(&block)
+ unless @debug
+ yylex0(&block)
+ else
+ yylex0 do |sym, tok|
+ $stderr.printf "%7d %-10s %s\n", lineno(), sym.inspect, tok.inspect
+ yield [sym, tok]
+ end
+ end
+ end
+
+ private
+
+ def yylex0
+ begin
+ until @line.empty?
+ @line.sub!(/\A\s+/, '')
+ if /\A\#/ =~ @line
+ break
+ elsif /\A\/\*/ =~ @line
+ skip_comment
+ elsif s = reads(/\A[a-zA-Z_]\w*/)
+ yield [atom_symbol(s), s.intern]
+ elsif s = reads(/\A\d+/)
+ yield [:DIGIT, s.to_i]
+ elsif ch = reads(/\A./)
+ case ch
+ when '"', "'"
+ yield [:STRING, eval(scan_quoted(ch))]
+ when '{'
+ lineno = lineno()
+ yield [:ACTION, SourceText.new(scan_action(), @filename, lineno)]
+ else
+ if ch == '|'
+ @line_head = false
+ end
+ yield [ch, ch]
+ end
+ else
+ end
+ end
+ end while next_line()
+ yield nil
+ end
+
+ def next_line
+ @lineno += 1
+ @line = @lines[@lineno]
+ if not @line or /\A----/ =~ @line
+ @epilogue = @lines.join("\n")
+ @lines.clear
+ @line = nil
+ if @in_block
+ @lineno -= 1
+ scan_error! sprintf('unterminated %s', @in_block)
+ end
+ false
+ else
+ @line.sub!(/(?:\n|\r\n|\r)\z/, '')
+ @line_head = true
+ true
+ end
+ end
+
+ ReservedWord = {
+ 'right' => :RIGHT,
+ 'left' => :LEFT,
+ 'nonassoc' => :NONASSOC,
+ 'preclow' => :PRECLOW,
+ 'prechigh' => :PRECHIGH,
+ 'token' => :TOKEN,
+ 'convert' => :CONV,
+ 'options' => :OPTION,
+ 'start' => :START,
+ 'expect' => :EXPECT,
+ 'class' => :CLASS,
+ 'rule' => :RULE,
+ 'end' => :END
+ }
+
+ def atom_symbol(token)
+ if token == 'end'
+ symbol = :END
+ @in_conv_blk = false
+ @in_rule_blk = false
+ else
+ if @line_head and not @in_conv_blk and not @in_rule_blk
+ symbol = ReservedWord[token] || :SYMBOL
+ else
+ symbol = :SYMBOL
+ end
+ case symbol
+ when :RULE then @in_rule_blk = true
+ when :CONV then @in_conv_blk = true
+ end
+ end
+ @line_head = false
+ symbol
+ end
+
+ def skip_comment
+ @in_block = 'comment'
+ until m = /\*\//.match(@line)
+ next_line
+ end
+ @line = m.post_match
+ @in_block = nil
+ end
+
+ $raccs_print_type = false
+
+ def scan_action
+ buf = String.new
+ nest = 1
+ pre = nil
+ @in_block = 'action'
+ begin
+ pre = nil
+ if s = reads(/\A\s+/)
+ # does not set 'pre'
+ buf << s
+ end
+ until @line.empty?
+ if s = reads(/\A[^'"`{}%#\/\$]+/)
+ buf << (pre = s)
+ next
+ end
+ case ch = read(1)
+ when '{'
+ nest += 1
+ buf << (pre = ch)
+ when '}'
+ nest -= 1
+ if nest == 0
+ @in_block = nil
+ buf.sub!(/[ \t\f]+\z/, '')
+ return buf
+ end
+ buf << (pre = ch)
+ when '#' # comment
+ buf << ch << @line
+ break
+ when "'", '"', '`'
+ buf << (pre = scan_quoted(ch))
+ when '%'
+ if literal_head? pre, @line
+ # % string, regexp, array
+ buf << ch
+ case ch = read(1)
+ when /[qQx]/n
+ buf << ch << (pre = scan_quoted(read(1), '%string'))
+ when /wW/n
+ buf << ch << (pre = scan_quoted(read(1), '%array'))
+ when /s/n
+ buf << ch << (pre = scan_quoted(read(1), '%symbol'))
+ when /r/n
+ buf << ch << (pre = scan_quoted(read(1), '%regexp'))
+ when /[a-zA-Z0-9= ]/n # does not include "_"
+ scan_error! "unknown type of % literal '%#{ch}'"
+ else
+ buf << (pre = scan_quoted(ch, '%string'))
+ end
+ else
+ # operator
+ buf << '||op->' if $raccs_print_type
+ buf << (pre = ch)
+ end
+ when '/'
+ if literal_head? pre, @line
+ # regexp
+ buf << (pre = scan_quoted(ch, 'regexp'))
+ else
+ # operator
+ buf << '||op->' if $raccs_print_type
+ buf << (pre = ch)
+ end
+ when '$' # gvar
+ buf << ch << (pre = read(1))
+ else
+ raise 'racc: fatal: must not happen'
+ end
+ end
+ buf << "\n"
+ end while next_line()
+ raise 'racc: fatal: scan finished before parser finished'
+ end
+
+ def literal_head?(pre, post)
+ (!pre || /[a-zA-Z_0-9]/n !~ pre[-1,1]) &&
+ !post.empty? && /\A[\s\=]/n !~ post
+ end
+
+ def read(len)
+ s = @line[0, len]
+ @line = @line[len .. -1]
+ s
+ end
+
+ def reads(re)
+ m = re.match(@line) or return nil
+ @line = m.post_match
+ m[0]
+ end
+
+ def scan_quoted(left, tag = 'string')
+ buf = left.dup
+ buf = "||#{tag}->" + buf if $raccs_print_type
+ re = get_quoted_re(left)
+ sv, @in_block = @in_block, tag
+ begin
+ if s = reads(re)
+ buf << s
+ break
+ else
+ buf << @line
+ end
+ end while next_line()
+ @in_block = sv
+ buf << "<-#{tag}||" if $raccs_print_type
+ buf
+ end
+
+ LEFT_TO_RIGHT = {
+ '(' => ')',
+ '{' => '}',
+ '[' => ']',
+ '<' => '>'
+ }
+
+ CACHE = {}
+
+ def get_quoted_re(left)
+ term = Regexp.quote(LEFT_TO_RIGHT[left] || left)
+ CACHE[left] ||= /\A[^#{term}\\]*(?:\\.[^\\#{term}]*)*#{term}/
+ end
+
+ def scan_error!(msg)
+ raise CompileError, "#{lineno()}: #{msg}"
+ end
+
+ end
+
+end # module Racc
diff --git a/lib/racc/info.rb b/lib/racc/info.rb
new file mode 100644
index 0000000000..37bff7edba
--- /dev/null
+++ b/lib/racc/info.rb
@@ -0,0 +1,17 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+module Racc
+ VERSION = '1.6.2'
+ Version = VERSION
+ Copyright = 'Copyright (c) 1999-2006 Minero Aoki'
+end
diff --git a/lib/racc/iset.rb b/lib/racc/iset.rb
new file mode 100644
index 0000000000..339221d21b
--- /dev/null
+++ b/lib/racc/iset.rb
@@ -0,0 +1,92 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+module Racc
+
+ # An "indexed" set. All items must respond to :ident.
+ class ISet
+
+ def initialize(a = [])
+ @set = a
+ end
+
+ attr_reader :set
+
+ def add(i)
+ @set[i.ident] = i
+ end
+
+ def [](key)
+ @set[key.ident]
+ end
+
+ def []=(key, val)
+ @set[key.ident] = val
+ end
+
+ alias include? []
+ alias key? []
+
+ def update(other)
+ s = @set
+ o = other.set
+ o.each_index do |idx|
+ if t = o[idx]
+ s[idx] = t
+ end
+ end
+ end
+
+ def update_a(a)
+ s = @set
+ a.each {|i| s[i.ident] = i }
+ end
+
+ def delete(key)
+ i = @set[key.ident]
+ @set[key.ident] = nil
+ i
+ end
+
+ def each(&block)
+ @set.compact.each(&block)
+ end
+
+ def to_a
+ @set.compact
+ end
+
+ def to_s
+ "[#{@set.compact.join(' ')}]"
+ end
+
+ alias inspect to_s
+
+ def size
+ @set.nitems
+ end
+
+ def empty?
+ @set.nitems == 0
+ end
+
+ def clear
+ @set.clear
+ end
+
+ def dup
+ ISet.new(@set.dup)
+ end
+
+ end # class ISet
+
+end # module Racc
diff --git a/lib/racc/logfilegenerator.rb b/lib/racc/logfilegenerator.rb
new file mode 100644
index 0000000000..2f5aa0c8b0
--- /dev/null
+++ b/lib/racc/logfilegenerator.rb
@@ -0,0 +1,212 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+module Racc
+
+ class LogFileGenerator
+
+ def initialize(states, debug_flags = DebugFlags.new)
+ @states = states
+ @grammar = states.grammar
+ @debug_flags = debug_flags
+ end
+
+ def output(out)
+ output_conflict out; out.puts
+ output_useless out; out.puts
+ output_rule out; out.puts
+ output_token out; out.puts
+ output_state out
+ end
+
+ #
+ # Warnings
+ #
+
+ def output_conflict(out)
+ @states.each do |state|
+ if state.srconf
+ out.printf "state %d contains %d shift/reduce conflicts\n",
+ state.stateid, state.srconf.size
+ end
+ if state.rrconf
+ out.printf "state %d contains %d reduce/reduce conflicts\n",
+ state.stateid, state.rrconf.size
+ end
+ end
+ end
+
+ def output_useless(out)
+ @grammar.each do |rl|
+ if rl.useless?
+ out.printf "rule %d (%s) never reduced\n",
+ rl.ident, rl.target.to_s
+ end
+ end
+ @grammar.each_nonterminal do |t|
+ if t.useless?
+ out.printf "useless nonterminal %s\n", t.to_s
+ end
+ end
+ end
+
+ #
+ # States
+ #
+
+ def output_state(out)
+ out << "--------- State ---------\n"
+
+ showall = @debug_flags.la || @debug_flags.state
+ @states.each do |state|
+ out << "\nstate #{state.ident}\n\n"
+
+ (showall ? state.closure : state.core).each do |ptr|
+ pointer_out(out, ptr) if ptr.rule.ident != 0 or showall
+ end
+ out << "\n"
+
+ action_out out, state
+ end
+ end
+
+ def pointer_out(out, ptr)
+ buf = sprintf("%4d) %s :", ptr.rule.ident, ptr.rule.target.to_s)
+ ptr.rule.symbols.each_with_index do |tok, idx|
+ buf << ' _' if idx == ptr.index
+ buf << ' ' << tok.to_s
+ end
+ buf << ' _' if ptr.reduce?
+ out.puts buf
+ end
+
+ def action_out(f, state)
+ sr = state.srconf && state.srconf.dup
+ rr = state.rrconf && state.rrconf.dup
+ acts = state.action
+ keys = acts.keys
+ keys.sort! {|a,b| a.ident <=> b.ident }
+
+ [ Shift, Reduce, Error, Accept ].each do |klass|
+ keys.delete_if do |tok|
+ act = acts[tok]
+ if act.kind_of?(klass)
+ outact f, tok, act
+ if sr and c = sr.delete(tok)
+ outsrconf f, c
+ end
+ if rr and c = rr.delete(tok)
+ outrrconf f, c
+ end
+
+ true
+ else
+ false
+ end
+ end
+ end
+ sr.each {|tok, c| outsrconf f, c } if sr
+ rr.each {|tok, c| outrrconf f, c } if rr
+
+ act = state.defact
+ if not act.kind_of?(Error) or @debug_flags.any?
+ outact f, '$default', act
+ end
+
+ f.puts
+ state.goto_table.each do |t, st|
+ if t.nonterminal?
+ f.printf " %-12s go to state %d\n", t.to_s, st.ident
+ end
+ end
+ end
+
+ def outact(f, t, act)
+ case act
+ when Shift
+ f.printf " %-12s shift, and go to state %d\n",
+ t.to_s, act.goto_id
+ when Reduce
+ f.printf " %-12s reduce using rule %d (%s)\n",
+ t.to_s, act.ruleid, act.rule.target.to_s
+ when Accept
+ f.printf " %-12s accept\n", t.to_s
+ when Error
+ f.printf " %-12s error\n", t.to_s
+ else
+ raise "racc: fatal: wrong act for outact: act=#{act}(#{act.class})"
+ end
+ end
+
+ def outsrconf(f, confs)
+ confs.each do |c|
+ r = c.reduce
+ f.printf " %-12s [reduce using rule %d (%s)]\n",
+ c.shift.to_s, r.ident, r.target.to_s
+ end
+ end
+
+ def outrrconf(f, confs)
+ confs.each do |c|
+ r = c.low_prec
+ f.printf " %-12s [reduce using rule %d (%s)]\n",
+ c.token.to_s, r.ident, r.target.to_s
+ end
+ end
+
+ #
+ # Rules
+ #
+
+ def output_rule(out)
+ out.print "-------- Grammar --------\n\n"
+ @grammar.each do |rl|
+ if @debug_flags.any? or rl.ident != 0
+ out.printf "rule %d %s: %s\n",
+ rl.ident, rl.target.to_s, rl.symbols.join(' ')
+ end
+ end
+ end
+
+ #
+ # Tokens
+ #
+
+ def output_token(out)
+ out.print "------- Symbols -------\n\n"
+
+ out.print "**Nonterminals, with rules where they appear\n\n"
+ @grammar.each_nonterminal do |t|
+ tmp = <<SRC
+ %s (%d)
+ on right: %s
+ on left : %s
+SRC
+ out.printf tmp, t.to_s, t.ident,
+ symbol_locations(t.locate).join(' '),
+ symbol_locations(t.heads).join(' ')
+ end
+
+ out.print "\n**Terminals, with rules where they appear\n\n"
+ @grammar.each_terminal do |t|
+ out.printf " %s (%d) %s\n",
+ t.to_s, t.ident, symbol_locations(t.locate).join(' ')
+ end
+ end
+
+ def symbol_locations(locs)
+ locs.map {|loc| loc.rule.ident }.reject {|n| n == 0 }.uniq
+ end
+
+ end
+
+end # module Racc
diff --git a/lib/racc/parser-text.rb b/lib/racc/parser-text.rb
new file mode 100644
index 0000000000..0579f4ce9b
--- /dev/null
+++ b/lib/racc/parser-text.rb
@@ -0,0 +1,637 @@
+module Racc
+ PARSER_TEXT = <<'__end_of_file__'
+# frozen_string_literal: false
+#--
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+#
+# As a special exception, when this code is copied by Racc
+# into a Racc output file, you may use that output file
+# without restriction.
+#++
+
+require 'racc/info'
+
+unless defined?(NotImplementedError)
+ NotImplementedError = NotImplementError # :nodoc:
+end
+
+module Racc
+ class ParseError < StandardError; end
+end
+unless defined?(::ParseError)
+ ParseError = Racc::ParseError # :nodoc:
+end
+
+# Racc is a LALR(1) parser generator.
+# It is written in Ruby itself, and generates Ruby programs.
+#
+# == Command-line Reference
+#
+# racc [-o<var>filename</var>] [--output-file=<var>filename</var>]
+# [-e<var>rubypath</var>] [--executable=<var>rubypath</var>]
+# [-v] [--verbose]
+# [-O<var>filename</var>] [--log-file=<var>filename</var>]
+# [-g] [--debug]
+# [-E] [--embedded]
+# [-l] [--no-line-convert]
+# [-c] [--line-convert-all]
+# [-a] [--no-omit-actions]
+# [-C] [--check-only]
+# [-S] [--output-status]
+# [--version] [--copyright] [--help] <var>grammarfile</var>
+#
+# [+grammarfile+]
+# Racc grammar file. Any extension is permitted.
+# [-o+outfile+, --output-file=+outfile+]
+# A filename for output. default is <+filename+>.tab.rb
+# [-O+filename+, --log-file=+filename+]
+# Place logging output in file +filename+.
+# Default log file name is <+filename+>.output.
+# [-e+rubypath+, --executable=+rubypath+]
+# output executable file(mode 755). where +path+ is the Ruby interpreter.
+# [-v, --verbose]
+# verbose mode. create +filename+.output file, like yacc's y.output file.
+# [-g, --debug]
+# add debug code to parser class. To display debuggin information,
+# use this '-g' option and set @yydebug true in parser class.
+# [-E, --embedded]
+# Output parser which doesn't need runtime files (racc/parser.rb).
+# [-C, --check-only]
+# Check syntax of racc grammar file and quit.
+# [-S, --output-status]
+# Print messages time to time while compiling.
+# [-l, --no-line-convert]
+# turns off line number converting.
+# [-c, --line-convert-all]
+# Convert line number of actions, inner, header and footer.
+# [-a, --no-omit-actions]
+# Call all actions, even if an action is empty.
+# [--version]
+# print Racc version and quit.
+# [--copyright]
+# Print copyright and quit.
+# [--help]
+# Print usage and quit.
+#
+# == Generating Parser Using Racc
+#
+# To compile Racc grammar file, simply type:
+#
+# $ racc parse.y
+#
+# This creates Ruby script file "parse.tab.y". The -o option can change the output filename.
+#
+# == Writing A Racc Grammar File
+#
+# If you want your own parser, you have to write a grammar file.
+# A grammar file contains the name of your parser class, grammar for the parser,
+# user code, and anything else.
+# When writing a grammar file, yacc's knowledge is helpful.
+# If you have not used yacc before, Racc is not too difficult.
+#
+# Here's an example Racc grammar file.
+#
+# class Calcparser
+# rule
+# target: exp { print val[0] }
+#
+# exp: exp '+' exp
+# | exp '*' exp
+# | '(' exp ')'
+# | NUMBER
+# end
+#
+# Racc grammar files resemble yacc files.
+# But (of course), this is Ruby code.
+# yacc's $$ is the 'result', $0, $1... is
+# an array called 'val', and $-1, $-2... is an array called '_values'.
+#
+# See the {Grammar File Reference}[rdoc-ref:lib/racc/rdoc/grammar.en.rdoc] for
+# more information on grammar files.
+#
+# == Parser
+#
+# Then you must prepare the parse entry method. There are two types of
+# parse methods in Racc, Racc::Parser#do_parse and Racc::Parser#yyparse
+#
+# Racc::Parser#do_parse is simple.
+#
+# It's yyparse() of yacc, and Racc::Parser#next_token is yylex().
+# This method must returns an array like [TOKENSYMBOL, ITS_VALUE].
+# EOF is [false, false].
+# (TOKENSYMBOL is a Ruby symbol (taken from String#intern) by default.
+# If you want to change this, see the grammar reference.
+#
+# Racc::Parser#yyparse is little complicated, but useful.
+# It does not use Racc::Parser#next_token, instead it gets tokens from any iterator.
+#
+# For example, <code>yyparse(obj, :scan)</code> causes
+# calling +obj#scan+, and you can return tokens by yielding them from +obj#scan+.
+#
+# == Debugging
+#
+# When debugging, "-v" or/and the "-g" option is helpful.
+#
+# "-v" creates verbose log file (.output).
+# "-g" creates a "Verbose Parser".
+# Verbose Parser prints the internal status when parsing.
+# But it's _not_ automatic.
+# You must use -g option and set +@yydebug+ to +true+ in order to get output.
+# -g option only creates the verbose parser.
+#
+# === Racc reported syntax error.
+#
+# Isn't there too many "end"?
+# grammar of racc file is changed in v0.10.
+#
+# Racc does not use '%' mark, while yacc uses huge number of '%' marks..
+#
+# === Racc reported "XXXX conflicts".
+#
+# Try "racc -v xxxx.y".
+# It causes producing racc's internal log file, xxxx.output.
+#
+# === Generated parsers does not work correctly
+#
+# Try "racc -g xxxx.y".
+# This command let racc generate "debugging parser".
+# Then set @yydebug=true in your parser.
+# It produces a working log of your parser.
+#
+# == Re-distributing Racc runtime
+#
+# A parser, which is created by Racc, requires the Racc runtime module;
+# racc/parser.rb.
+#
+# Ruby 1.8.x comes with Racc runtime module,
+# you need NOT distribute Racc runtime files.
+#
+# If you want to include the Racc runtime module with your parser.
+# This can be done by using '-E' option:
+#
+# $ racc -E -omyparser.rb myparser.y
+#
+# This command creates myparser.rb which `includes' Racc runtime.
+# Only you must do is to distribute your parser file (myparser.rb).
+#
+# Note: parser.rb is ruby license, but your parser is not.
+# Your own parser is completely yours.
+module Racc
+
+ unless defined?(Racc_No_Extensions)
+ Racc_No_Extensions = false # :nodoc:
+ end
+
+ class Parser
+
+ Racc_Runtime_Version = ::Racc::VERSION
+ Racc_Runtime_Core_Version_R = ::Racc::VERSION
+
+ begin
+ if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
+ require 'jruby'
+ require 'racc/cparse-jruby.jar'
+ com.headius.racc.Cparse.new.load(JRuby.runtime, false)
+ else
+ require 'racc/cparse'
+ end
+
+ unless new.respond_to?(:_racc_do_parse_c, true)
+ raise LoadError, 'old cparse.so'
+ end
+ if Racc_No_Extensions
+ raise LoadError, 'selecting ruby version of racc runtime core'
+ end
+
+ Racc_Main_Parsing_Routine = :_racc_do_parse_c # :nodoc:
+ Racc_YY_Parse_Method = :_racc_yyparse_c # :nodoc:
+ Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C # :nodoc:
+ Racc_Runtime_Type = 'c' # :nodoc:
+ rescue LoadError
+ Racc_Main_Parsing_Routine = :_racc_do_parse_rb
+ Racc_YY_Parse_Method = :_racc_yyparse_rb
+ Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R
+ Racc_Runtime_Type = 'ruby'
+ end
+
+ def Parser.racc_runtime_type # :nodoc:
+ Racc_Runtime_Type
+ end
+
+ def _racc_setup
+ @yydebug = false unless self.class::Racc_debug_parser
+ @yydebug = false unless defined?(@yydebug)
+ if @yydebug
+ @racc_debug_out = $stderr unless defined?(@racc_debug_out)
+ @racc_debug_out ||= $stderr
+ end
+ arg = self.class::Racc_arg
+ arg[13] = true if arg.size < 14
+ arg
+ end
+
+ def _racc_init_sysvars
+ @racc_state = [0]
+ @racc_tstack = []
+ @racc_vstack = []
+
+ @racc_t = nil
+ @racc_val = nil
+
+ @racc_read_next = true
+
+ @racc_user_yyerror = false
+ @racc_error_status = 0
+ end
+
+ # The entry point of the parser. This method is used with #next_token.
+ # If Racc wants to get token (and its value), calls next_token.
+ #
+ # Example:
+ # def parse
+ # @q = [[1,1],
+ # [2,2],
+ # [3,3],
+ # [false, '$']]
+ # do_parse
+ # end
+ #
+ # def next_token
+ # @q.shift
+ # end
+ class_eval %{
+ def do_parse
+ #{Racc_Main_Parsing_Routine}(_racc_setup(), false)
+ end
+ }
+
+ # The method to fetch next token.
+ # If you use #do_parse method, you must implement #next_token.
+ #
+ # The format of return value is [TOKEN_SYMBOL, VALUE].
+ # +token-symbol+ is represented by Ruby's symbol by default, e.g. :IDENT
+ # for 'IDENT'. ";" (String) for ';'.
+ #
+ # The final symbol (End of file) must be false.
+ def next_token
+ raise NotImplementedError, "#{self.class}\#next_token is not defined"
+ end
+
+ def _racc_do_parse_rb(arg, in_debug)
+ action_table, action_check, action_default, action_pointer,
+ _, _, _, _,
+ _, _, token_table, * = arg
+
+ _racc_init_sysvars
+ tok = act = i = nil
+
+ catch(:racc_end_parse) {
+ while true
+ if i = action_pointer[@racc_state[-1]]
+ if @racc_read_next
+ if @racc_t != 0 # not EOF
+ tok, @racc_val = next_token()
+ unless tok # EOF
+ @racc_t = 0
+ else
+ @racc_t = (token_table[tok] or 1) # error token
+ end
+ racc_read_token(@racc_t, tok, @racc_val) if @yydebug
+ @racc_read_next = false
+ end
+ end
+ i += @racc_t
+ unless i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ else
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
+ end
+ }
+ end
+
+ # Another entry point for the parser.
+ # If you use this method, you must implement RECEIVER#METHOD_ID method.
+ #
+ # RECEIVER#METHOD_ID is a method to get next token.
+ # It must 'yield' the token, which format is [TOKEN-SYMBOL, VALUE].
+ class_eval %{
+ def yyparse(recv, mid)
+ #{Racc_YY_Parse_Method}(recv, mid, _racc_setup(), false)
+ end
+ }
+
+ def _racc_yyparse_rb(recv, mid, arg, c_debug)
+ action_table, action_check, action_default, action_pointer,
+ _, _, _, _,
+ _, _, token_table, * = arg
+
+ _racc_init_sysvars
+
+ catch(:racc_end_parse) {
+ until i = action_pointer[@racc_state[-1]]
+ while act = _racc_evalact(action_default[@racc_state[-1]], arg)
+ ;
+ end
+ end
+ recv.__send__(mid) do |tok, val|
+ unless tok
+ @racc_t = 0
+ else
+ @racc_t = (token_table[tok] or 1) # error token
+ end
+ @racc_val = val
+ @racc_read_next = false
+
+ i += @racc_t
+ unless i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
+
+ while !(i = action_pointer[@racc_state[-1]]) ||
+ ! @racc_read_next ||
+ @racc_t == 0 # $
+ unless i and i += @racc_t and
+ i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
+ end
+ end
+ }
+ end
+
+ ###
+ ### common
+ ###
+
+ def _racc_evalact(act, arg)
+ action_table, action_check, _, action_pointer,
+ _, _, _, _,
+ _, _, _, shift_n,
+ reduce_n, * = arg
+ nerr = 0 # tmp
+
+ if act > 0 and act < shift_n
+ #
+ # shift
+ #
+ if @racc_error_status > 0
+ @racc_error_status -= 1 unless @racc_t <= 1 # error token or EOF
+ end
+ @racc_vstack.push @racc_val
+ @racc_state.push act
+ @racc_read_next = true
+ if @yydebug
+ @racc_tstack.push @racc_t
+ racc_shift @racc_t, @racc_tstack, @racc_vstack
+ end
+
+ elsif act < 0 and act > -reduce_n
+ #
+ # reduce
+ #
+ code = catch(:racc_jump) {
+ @racc_state.push _racc_do_reduce(arg, act)
+ false
+ }
+ if code
+ case code
+ when 1 # yyerror
+ @racc_user_yyerror = true # user_yyerror
+ return -reduce_n
+ when 2 # yyaccept
+ return shift_n
+ else
+ raise '[Racc Bug] unknown jump code'
+ end
+ end
+
+ elsif act == shift_n
+ #
+ # accept
+ #
+ racc_accept if @yydebug
+ throw :racc_end_parse, @racc_vstack[0]
+
+ elsif act == -reduce_n
+ #
+ # error
+ #
+ case @racc_error_status
+ when 0
+ unless arg[21] # user_yyerror
+ nerr += 1
+ on_error @racc_t, @racc_val, @racc_vstack
+ end
+ when 3
+ if @racc_t == 0 # is $
+ # We're at EOF, and another error occurred immediately after
+ # attempting auto-recovery
+ throw :racc_end_parse, nil
+ end
+ @racc_read_next = true
+ end
+ @racc_user_yyerror = false
+ @racc_error_status = 3
+ while true
+ if i = action_pointer[@racc_state[-1]]
+ i += 1 # error token
+ if i >= 0 and
+ (act = action_table[i]) and
+ action_check[i] == @racc_state[-1]
+ break
+ end
+ end
+ throw :racc_end_parse, nil if @racc_state.size <= 1
+ @racc_state.pop
+ @racc_vstack.pop
+ if @yydebug
+ @racc_tstack.pop
+ racc_e_pop @racc_state, @racc_tstack, @racc_vstack
+ end
+ end
+ return act
+
+ else
+ raise "[Racc Bug] unknown action #{act.inspect}"
+ end
+
+ racc_next_state(@racc_state[-1], @racc_state) if @yydebug
+
+ nil
+ end
+
+ def _racc_do_reduce(arg, act)
+ _, _, _, _,
+ goto_table, goto_check, goto_default, goto_pointer,
+ nt_base, reduce_table, _, _,
+ _, use_result, * = arg
+
+ state = @racc_state
+ vstack = @racc_vstack
+ tstack = @racc_tstack
+
+ i = act * -3
+ len = reduce_table[i]
+ reduce_to = reduce_table[i+1]
+ method_id = reduce_table[i+2]
+ void_array = []
+
+ tmp_t = tstack[-len, len] if @yydebug
+ tmp_v = vstack[-len, len]
+ tstack[-len, len] = void_array if @yydebug
+ vstack[-len, len] = void_array
+ state[-len, len] = void_array
+
+ # tstack must be updated AFTER method call
+ if use_result
+ vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0])
+ else
+ vstack.push __send__(method_id, tmp_v, vstack)
+ end
+ tstack.push reduce_to
+
+ racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug
+
+ k1 = reduce_to - nt_base
+ if i = goto_pointer[k1]
+ i += state[-1]
+ if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1
+ return curstate
+ end
+ end
+ goto_default[k1]
+ end
+
+ # This method is called when a parse error is found.
+ #
+ # ERROR_TOKEN_ID is an internal ID of token which caused error.
+ # You can get string representation of this ID by calling
+ # #token_to_str.
+ #
+ # ERROR_VALUE is a value of error token.
+ #
+ # value_stack is a stack of symbol values.
+ # DO NOT MODIFY this object.
+ #
+ # This method raises ParseError by default.
+ #
+ # If this method returns, parsers enter "error recovering mode".
+ def on_error(t, val, vstack)
+ raise ParseError, sprintf("\nparse error on value %s (%s)",
+ val.inspect, token_to_str(t) || '?')
+ end
+
+ # Enter error recovering mode.
+ # This method does not call #on_error.
+ def yyerror
+ throw :racc_jump, 1
+ end
+
+ # Exit parser.
+ # Return value is +Symbol_Value_Stack[0]+.
+ def yyaccept
+ throw :racc_jump, 2
+ end
+
+ # Leave error recovering mode.
+ def yyerrok
+ @racc_error_status = 0
+ end
+
+ # For debugging output
+ def racc_read_token(t, tok, val)
+ @racc_debug_out.print 'read '
+ @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') '
+ @racc_debug_out.puts val.inspect
+ @racc_debug_out.puts
+ end
+
+ def racc_shift(tok, tstack, vstack)
+ @racc_debug_out.puts "shift #{racc_token2str tok}"
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
+
+ def racc_reduce(toks, sim, tstack, vstack)
+ out = @racc_debug_out
+ out.print 'reduce '
+ if toks.empty?
+ out.print ' <none>'
+ else
+ toks.each {|t| out.print ' ', racc_token2str(t) }
+ end
+ out.puts " --> #{racc_token2str(sim)}"
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
+
+ def racc_accept
+ @racc_debug_out.puts 'accept'
+ @racc_debug_out.puts
+ end
+
+ def racc_e_pop(state, tstack, vstack)
+ @racc_debug_out.puts 'error recovering mode: pop token'
+ racc_print_states state
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
+
+ def racc_next_state(curstate, state)
+ @racc_debug_out.puts "goto #{curstate}"
+ racc_print_states state
+ @racc_debug_out.puts
+ end
+
+ def racc_print_stacks(t, v)
+ out = @racc_debug_out
+ out.print ' ['
+ t.each_index do |i|
+ out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')'
+ end
+ out.puts ' ]'
+ end
+
+ def racc_print_states(s)
+ out = @racc_debug_out
+ out.print ' ['
+ s.each {|st| out.print ' ', st }
+ out.puts ' ]'
+ end
+
+ def racc_token2str(tok)
+ self.class::Racc_token_to_s_table[tok] or
+ raise "[Racc Bug] can't convert token #{tok} to string"
+ end
+
+ # Convert internal ID of token symbol to the string.
+ def token_to_str(t)
+ self.class::Racc_token_to_s_table[t]
+ end
+
+ end
+
+end
+
+__end_of_file__
+end
diff --git a/lib/racc/parser.rb b/lib/racc/parser.rb
new file mode 100644
index 0000000000..078bfef3e9
--- /dev/null
+++ b/lib/racc/parser.rb
@@ -0,0 +1,632 @@
+# frozen_string_literal: false
+#--
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+#
+# As a special exception, when this code is copied by Racc
+# into a Racc output file, you may use that output file
+# without restriction.
+#++
+
+require 'racc/info'
+
+unless defined?(NotImplementedError)
+ NotImplementedError = NotImplementError # :nodoc:
+end
+
+module Racc
+ class ParseError < StandardError; end
+end
+unless defined?(::ParseError)
+ ParseError = Racc::ParseError # :nodoc:
+end
+
+# Racc is a LALR(1) parser generator.
+# It is written in Ruby itself, and generates Ruby programs.
+#
+# == Command-line Reference
+#
+# racc [-o<var>filename</var>] [--output-file=<var>filename</var>]
+# [-e<var>rubypath</var>] [--executable=<var>rubypath</var>]
+# [-v] [--verbose]
+# [-O<var>filename</var>] [--log-file=<var>filename</var>]
+# [-g] [--debug]
+# [-E] [--embedded]
+# [-l] [--no-line-convert]
+# [-c] [--line-convert-all]
+# [-a] [--no-omit-actions]
+# [-C] [--check-only]
+# [-S] [--output-status]
+# [--version] [--copyright] [--help] <var>grammarfile</var>
+#
+# [+grammarfile+]
+# Racc grammar file. Any extension is permitted.
+# [-o+outfile+, --output-file=+outfile+]
+# A filename for output. default is <+filename+>.tab.rb
+# [-O+filename+, --log-file=+filename+]
+# Place logging output in file +filename+.
+# Default log file name is <+filename+>.output.
+# [-e+rubypath+, --executable=+rubypath+]
+# output executable file(mode 755). where +path+ is the Ruby interpreter.
+# [-v, --verbose]
+# verbose mode. create +filename+.output file, like yacc's y.output file.
+# [-g, --debug]
+# add debug code to parser class. To display debuggin information,
+# use this '-g' option and set @yydebug true in parser class.
+# [-E, --embedded]
+# Output parser which doesn't need runtime files (racc/parser.rb).
+# [-C, --check-only]
+# Check syntax of racc grammar file and quit.
+# [-S, --output-status]
+# Print messages time to time while compiling.
+# [-l, --no-line-convert]
+# turns off line number converting.
+# [-c, --line-convert-all]
+# Convert line number of actions, inner, header and footer.
+# [-a, --no-omit-actions]
+# Call all actions, even if an action is empty.
+# [--version]
+# print Racc version and quit.
+# [--copyright]
+# Print copyright and quit.
+# [--help]
+# Print usage and quit.
+#
+# == Generating Parser Using Racc
+#
+# To compile Racc grammar file, simply type:
+#
+# $ racc parse.y
+#
+# This creates Ruby script file "parse.tab.y". The -o option can change the output filename.
+#
+# == Writing A Racc Grammar File
+#
+# If you want your own parser, you have to write a grammar file.
+# A grammar file contains the name of your parser class, grammar for the parser,
+# user code, and anything else.
+# When writing a grammar file, yacc's knowledge is helpful.
+# If you have not used yacc before, Racc is not too difficult.
+#
+# Here's an example Racc grammar file.
+#
+# class Calcparser
+# rule
+# target: exp { print val[0] }
+#
+# exp: exp '+' exp
+# | exp '*' exp
+# | '(' exp ')'
+# | NUMBER
+# end
+#
+# Racc grammar files resemble yacc files.
+# But (of course), this is Ruby code.
+# yacc's $$ is the 'result', $0, $1... is
+# an array called 'val', and $-1, $-2... is an array called '_values'.
+#
+# See the {Grammar File Reference}[rdoc-ref:lib/racc/rdoc/grammar.en.rdoc] for
+# more information on grammar files.
+#
+# == Parser
+#
+# Then you must prepare the parse entry method. There are two types of
+# parse methods in Racc, Racc::Parser#do_parse and Racc::Parser#yyparse
+#
+# Racc::Parser#do_parse is simple.
+#
+# It's yyparse() of yacc, and Racc::Parser#next_token is yylex().
+# This method must returns an array like [TOKENSYMBOL, ITS_VALUE].
+# EOF is [false, false].
+# (TOKENSYMBOL is a Ruby symbol (taken from String#intern) by default.
+# If you want to change this, see the grammar reference.
+#
+# Racc::Parser#yyparse is little complicated, but useful.
+# It does not use Racc::Parser#next_token, instead it gets tokens from any iterator.
+#
+# For example, <code>yyparse(obj, :scan)</code> causes
+# calling +obj#scan+, and you can return tokens by yielding them from +obj#scan+.
+#
+# == Debugging
+#
+# When debugging, "-v" or/and the "-g" option is helpful.
+#
+# "-v" creates verbose log file (.output).
+# "-g" creates a "Verbose Parser".
+# Verbose Parser prints the internal status when parsing.
+# But it's _not_ automatic.
+# You must use -g option and set +@yydebug+ to +true+ in order to get output.
+# -g option only creates the verbose parser.
+#
+# === Racc reported syntax error.
+#
+# Isn't there too many "end"?
+# grammar of racc file is changed in v0.10.
+#
+# Racc does not use '%' mark, while yacc uses huge number of '%' marks..
+#
+# === Racc reported "XXXX conflicts".
+#
+# Try "racc -v xxxx.y".
+# It causes producing racc's internal log file, xxxx.output.
+#
+# === Generated parsers does not work correctly
+#
+# Try "racc -g xxxx.y".
+# This command let racc generate "debugging parser".
+# Then set @yydebug=true in your parser.
+# It produces a working log of your parser.
+#
+# == Re-distributing Racc runtime
+#
+# A parser, which is created by Racc, requires the Racc runtime module;
+# racc/parser.rb.
+#
+# Ruby 1.8.x comes with Racc runtime module,
+# you need NOT distribute Racc runtime files.
+#
+# If you want to include the Racc runtime module with your parser.
+# This can be done by using '-E' option:
+#
+# $ racc -E -omyparser.rb myparser.y
+#
+# This command creates myparser.rb which `includes' Racc runtime.
+# Only you must do is to distribute your parser file (myparser.rb).
+#
+# Note: parser.rb is ruby license, but your parser is not.
+# Your own parser is completely yours.
+module Racc
+
+ unless defined?(Racc_No_Extensions)
+ Racc_No_Extensions = false # :nodoc:
+ end
+
+ class Parser
+
+ Racc_Runtime_Version = ::Racc::VERSION
+ Racc_Runtime_Core_Version_R = ::Racc::VERSION
+
+ begin
+ if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
+ require 'jruby'
+ require 'racc/cparse-jruby.jar'
+ com.headius.racc.Cparse.new.load(JRuby.runtime, false)
+ else
+ require 'racc/cparse'
+ end
+
+ unless new.respond_to?(:_racc_do_parse_c, true)
+ raise LoadError, 'old cparse.so'
+ end
+ if Racc_No_Extensions
+ raise LoadError, 'selecting ruby version of racc runtime core'
+ end
+
+ Racc_Main_Parsing_Routine = :_racc_do_parse_c # :nodoc:
+ Racc_YY_Parse_Method = :_racc_yyparse_c # :nodoc:
+ Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C # :nodoc:
+ Racc_Runtime_Type = 'c' # :nodoc:
+ rescue LoadError
+ Racc_Main_Parsing_Routine = :_racc_do_parse_rb
+ Racc_YY_Parse_Method = :_racc_yyparse_rb
+ Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R
+ Racc_Runtime_Type = 'ruby'
+ end
+
+ def Parser.racc_runtime_type # :nodoc:
+ Racc_Runtime_Type
+ end
+
+ def _racc_setup
+ @yydebug = false unless self.class::Racc_debug_parser
+ @yydebug = false unless defined?(@yydebug)
+ if @yydebug
+ @racc_debug_out = $stderr unless defined?(@racc_debug_out)
+ @racc_debug_out ||= $stderr
+ end
+ arg = self.class::Racc_arg
+ arg[13] = true if arg.size < 14
+ arg
+ end
+
+ def _racc_init_sysvars
+ @racc_state = [0]
+ @racc_tstack = []
+ @racc_vstack = []
+
+ @racc_t = nil
+ @racc_val = nil
+
+ @racc_read_next = true
+
+ @racc_user_yyerror = false
+ @racc_error_status = 0
+ end
+
+ # The entry point of the parser. This method is used with #next_token.
+ # If Racc wants to get token (and its value), calls next_token.
+ #
+ # Example:
+ # def parse
+ # @q = [[1,1],
+ # [2,2],
+ # [3,3],
+ # [false, '$']]
+ # do_parse
+ # end
+ #
+ # def next_token
+ # @q.shift
+ # end
+ class_eval %{
+ def do_parse
+ #{Racc_Main_Parsing_Routine}(_racc_setup(), false)
+ end
+ }
+
+ # The method to fetch next token.
+ # If you use #do_parse method, you must implement #next_token.
+ #
+ # The format of return value is [TOKEN_SYMBOL, VALUE].
+ # +token-symbol+ is represented by Ruby's symbol by default, e.g. :IDENT
+ # for 'IDENT'. ";" (String) for ';'.
+ #
+ # The final symbol (End of file) must be false.
+ def next_token
+ raise NotImplementedError, "#{self.class}\#next_token is not defined"
+ end
+
+ def _racc_do_parse_rb(arg, in_debug)
+ action_table, action_check, action_default, action_pointer,
+ _, _, _, _,
+ _, _, token_table, * = arg
+
+ _racc_init_sysvars
+ tok = act = i = nil
+
+ catch(:racc_end_parse) {
+ while true
+ if i = action_pointer[@racc_state[-1]]
+ if @racc_read_next
+ if @racc_t != 0 # not EOF
+ tok, @racc_val = next_token()
+ unless tok # EOF
+ @racc_t = 0
+ else
+ @racc_t = (token_table[tok] or 1) # error token
+ end
+ racc_read_token(@racc_t, tok, @racc_val) if @yydebug
+ @racc_read_next = false
+ end
+ end
+ i += @racc_t
+ unless i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ else
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
+ end
+ }
+ end
+
+ # Another entry point for the parser.
+ # If you use this method, you must implement RECEIVER#METHOD_ID method.
+ #
+ # RECEIVER#METHOD_ID is a method to get next token.
+ # It must 'yield' the token, which format is [TOKEN-SYMBOL, VALUE].
+ class_eval %{
+ def yyparse(recv, mid)
+ #{Racc_YY_Parse_Method}(recv, mid, _racc_setup(), false)
+ end
+ }
+
+ def _racc_yyparse_rb(recv, mid, arg, c_debug)
+ action_table, action_check, action_default, action_pointer,
+ _, _, _, _,
+ _, _, token_table, * = arg
+
+ _racc_init_sysvars
+
+ catch(:racc_end_parse) {
+ until i = action_pointer[@racc_state[-1]]
+ while act = _racc_evalact(action_default[@racc_state[-1]], arg)
+ ;
+ end
+ end
+ recv.__send__(mid) do |tok, val|
+ unless tok
+ @racc_t = 0
+ else
+ @racc_t = (token_table[tok] or 1) # error token
+ end
+ @racc_val = val
+ @racc_read_next = false
+
+ i += @racc_t
+ unless i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
+
+ while !(i = action_pointer[@racc_state[-1]]) ||
+ ! @racc_read_next ||
+ @racc_t == 0 # $
+ unless i and i += @racc_t and
+ i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
+ end
+ end
+ }
+ end
+
+ ###
+ ### common
+ ###
+
+ def _racc_evalact(act, arg)
+ action_table, action_check, _, action_pointer,
+ _, _, _, _,
+ _, _, _, shift_n,
+ reduce_n, * = arg
+ nerr = 0 # tmp
+
+ if act > 0 and act < shift_n
+ #
+ # shift
+ #
+ if @racc_error_status > 0
+ @racc_error_status -= 1 unless @racc_t <= 1 # error token or EOF
+ end
+ @racc_vstack.push @racc_val
+ @racc_state.push act
+ @racc_read_next = true
+ if @yydebug
+ @racc_tstack.push @racc_t
+ racc_shift @racc_t, @racc_tstack, @racc_vstack
+ end
+
+ elsif act < 0 and act > -reduce_n
+ #
+ # reduce
+ #
+ code = catch(:racc_jump) {
+ @racc_state.push _racc_do_reduce(arg, act)
+ false
+ }
+ if code
+ case code
+ when 1 # yyerror
+ @racc_user_yyerror = true # user_yyerror
+ return -reduce_n
+ when 2 # yyaccept
+ return shift_n
+ else
+ raise '[Racc Bug] unknown jump code'
+ end
+ end
+
+ elsif act == shift_n
+ #
+ # accept
+ #
+ racc_accept if @yydebug
+ throw :racc_end_parse, @racc_vstack[0]
+
+ elsif act == -reduce_n
+ #
+ # error
+ #
+ case @racc_error_status
+ when 0
+ unless arg[21] # user_yyerror
+ nerr += 1
+ on_error @racc_t, @racc_val, @racc_vstack
+ end
+ when 3
+ if @racc_t == 0 # is $
+ # We're at EOF, and another error occurred immediately after
+ # attempting auto-recovery
+ throw :racc_end_parse, nil
+ end
+ @racc_read_next = true
+ end
+ @racc_user_yyerror = false
+ @racc_error_status = 3
+ while true
+ if i = action_pointer[@racc_state[-1]]
+ i += 1 # error token
+ if i >= 0 and
+ (act = action_table[i]) and
+ action_check[i] == @racc_state[-1]
+ break
+ end
+ end
+ throw :racc_end_parse, nil if @racc_state.size <= 1
+ @racc_state.pop
+ @racc_vstack.pop
+ if @yydebug
+ @racc_tstack.pop
+ racc_e_pop @racc_state, @racc_tstack, @racc_vstack
+ end
+ end
+ return act
+
+ else
+ raise "[Racc Bug] unknown action #{act.inspect}"
+ end
+
+ racc_next_state(@racc_state[-1], @racc_state) if @yydebug
+
+ nil
+ end
+
+ def _racc_do_reduce(arg, act)
+ _, _, _, _,
+ goto_table, goto_check, goto_default, goto_pointer,
+ nt_base, reduce_table, _, _,
+ _, use_result, * = arg
+
+ state = @racc_state
+ vstack = @racc_vstack
+ tstack = @racc_tstack
+
+ i = act * -3
+ len = reduce_table[i]
+ reduce_to = reduce_table[i+1]
+ method_id = reduce_table[i+2]
+ void_array = []
+
+ tmp_t = tstack[-len, len] if @yydebug
+ tmp_v = vstack[-len, len]
+ tstack[-len, len] = void_array if @yydebug
+ vstack[-len, len] = void_array
+ state[-len, len] = void_array
+
+ # tstack must be updated AFTER method call
+ if use_result
+ vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0])
+ else
+ vstack.push __send__(method_id, tmp_v, vstack)
+ end
+ tstack.push reduce_to
+
+ racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug
+
+ k1 = reduce_to - nt_base
+ if i = goto_pointer[k1]
+ i += state[-1]
+ if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1
+ return curstate
+ end
+ end
+ goto_default[k1]
+ end
+
+ # This method is called when a parse error is found.
+ #
+ # ERROR_TOKEN_ID is an internal ID of token which caused error.
+ # You can get string representation of this ID by calling
+ # #token_to_str.
+ #
+ # ERROR_VALUE is a value of error token.
+ #
+ # value_stack is a stack of symbol values.
+ # DO NOT MODIFY this object.
+ #
+ # This method raises ParseError by default.
+ #
+ # If this method returns, parsers enter "error recovering mode".
+ def on_error(t, val, vstack)
+ raise ParseError, sprintf("\nparse error on value %s (%s)",
+ val.inspect, token_to_str(t) || '?')
+ end
+
+ # Enter error recovering mode.
+ # This method does not call #on_error.
+ def yyerror
+ throw :racc_jump, 1
+ end
+
+ # Exit parser.
+ # Return value is +Symbol_Value_Stack[0]+.
+ def yyaccept
+ throw :racc_jump, 2
+ end
+
+ # Leave error recovering mode.
+ def yyerrok
+ @racc_error_status = 0
+ end
+
+ # For debugging output
+ def racc_read_token(t, tok, val)
+ @racc_debug_out.print 'read '
+ @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') '
+ @racc_debug_out.puts val.inspect
+ @racc_debug_out.puts
+ end
+
+ def racc_shift(tok, tstack, vstack)
+ @racc_debug_out.puts "shift #{racc_token2str tok}"
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
+
+ def racc_reduce(toks, sim, tstack, vstack)
+ out = @racc_debug_out
+ out.print 'reduce '
+ if toks.empty?
+ out.print ' <none>'
+ else
+ toks.each {|t| out.print ' ', racc_token2str(t) }
+ end
+ out.puts " --> #{racc_token2str(sim)}"
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
+
+ def racc_accept
+ @racc_debug_out.puts 'accept'
+ @racc_debug_out.puts
+ end
+
+ def racc_e_pop(state, tstack, vstack)
+ @racc_debug_out.puts 'error recovering mode: pop token'
+ racc_print_states state
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
+
+ def racc_next_state(curstate, state)
+ @racc_debug_out.puts "goto #{curstate}"
+ racc_print_states state
+ @racc_debug_out.puts
+ end
+
+ def racc_print_stacks(t, v)
+ out = @racc_debug_out
+ out.print ' ['
+ t.each_index do |i|
+ out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')'
+ end
+ out.puts ' ]'
+ end
+
+ def racc_print_states(s)
+ out = @racc_debug_out
+ out.print ' ['
+ s.each {|st| out.print ' ', st }
+ out.puts ' ]'
+ end
+
+ def racc_token2str(tok)
+ self.class::Racc_token_to_s_table[tok] or
+ raise "[Racc Bug] can't convert token #{tok} to string"
+ end
+
+ # Convert internal ID of token symbol to the string.
+ def token_to_str(t)
+ self.class::Racc_token_to_s_table[t]
+ end
+
+ end
+
+end
diff --git a/lib/racc/parserfilegenerator.rb b/lib/racc/parserfilegenerator.rb
new file mode 100644
index 0000000000..7131026929
--- /dev/null
+++ b/lib/racc/parserfilegenerator.rb
@@ -0,0 +1,468 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+require 'racc/compat'
+require 'racc/sourcetext'
+require 'racc/parser-text'
+require 'rbconfig'
+
+module Racc
+
+ class ParserFileGenerator
+
+ class Params
+ def self.bool_attr(name)
+ module_eval(<<-End)
+ def #{name}?
+ @#{name}
+ end
+
+ def #{name}=(b)
+ @#{name} = b
+ end
+ End
+ end
+
+ attr_accessor :filename
+ attr_accessor :classname
+ attr_accessor :superclass
+ bool_attr :omit_action_call
+ bool_attr :result_var
+ attr_accessor :header
+ attr_accessor :inner
+ attr_accessor :footer
+
+ bool_attr :debug_parser
+ bool_attr :convert_line
+ bool_attr :convert_line_all
+ bool_attr :embed_runtime
+ bool_attr :make_executable
+ attr_accessor :interpreter
+
+ def initialize
+ # Parameters derived from parser
+ self.filename = nil
+ self.classname = nil
+ self.superclass = 'Racc::Parser'
+ self.omit_action_call = true
+ self.result_var = true
+ self.header = []
+ self.inner = []
+ self.footer = []
+
+ # Parameters derived from command line options
+ self.debug_parser = false
+ self.convert_line = true
+ self.convert_line_all = false
+ self.embed_runtime = false
+ self.make_executable = false
+ self.interpreter = nil
+ end
+ end
+
+ def initialize(states, params)
+ @states = states
+ @grammar = states.grammar
+ @params = params
+ end
+
+ def generate_parser
+ string_io = StringIO.new
+
+ init_line_conversion_system
+ @f = string_io
+ parser_file
+
+ string_io.rewind
+ string_io.read
+ end
+
+ def generate_parser_file(destpath)
+ init_line_conversion_system
+ File.open(destpath, 'w') {|f|
+ @f = f
+ parser_file
+ }
+ File.chmod 0755, destpath if @params.make_executable?
+ end
+
+ private
+
+ def parser_file
+ shebang @params.interpreter if @params.make_executable?
+ notice
+ line
+ if @params.embed_runtime?
+ embed_library runtime_source()
+ else
+ require 'racc/parser.rb'
+ end
+ header
+ parser_class(@params.classname, @params.superclass) {
+ inner
+ state_transition_table
+ }
+ footer
+ end
+
+ c = ::RbConfig::CONFIG
+ RUBY_PATH = "#{c['bindir']}/#{c['ruby_install_name']}#{c['EXEEXT']}"
+
+ def shebang(path)
+ line '#!' + (path == 'ruby' ? RUBY_PATH : path)
+ end
+
+ def notice
+ line %q[#]
+ line %q[# DO NOT MODIFY!!!!]
+ line %Q[# This file is automatically generated by Racc #{Racc::Version}]
+ line %Q[# from Racc grammar file "#{@params.filename}".]
+ line %q[#]
+ end
+
+ def runtime_source
+ SourceText.new(::Racc::PARSER_TEXT, 'racc/parser.rb', 1)
+ end
+
+ def embed_library(src)
+ line %[###### #{src.filename} begin]
+ line %[unless $".index '#{src.filename}']
+ line %[$".push '#{src.filename}']
+ put src, @params.convert_line?
+ line %[end]
+ line %[###### #{src.filename} end]
+ end
+
+ def require(feature)
+ line "require '#{feature}'"
+ end
+
+ def parser_class(classname, superclass)
+ mods = classname.split('::')
+ classid = mods.pop
+ mods.each do |mod|
+ indent; line "module #{mod}"
+ cref_push mod
+ end
+ indent; line "class #{classid} < #{superclass}"
+ cref_push classid
+ yield
+ cref_pop
+ indent; line "end \# class #{classid}"
+ mods.reverse_each do |mod|
+ cref_pop
+ indent; line "end \# module #{mod}"
+ end
+ end
+
+ def header
+ @params.header.each do |src|
+ line
+ put src, @params.convert_line_all?
+ end
+ end
+
+ def inner
+ @params.inner.each do |src|
+ line
+ put src, @params.convert_line?
+ end
+ end
+
+ def footer
+ @params.footer.each do |src|
+ line
+ put src, @params.convert_line_all?
+ end
+ end
+
+ # Low Level Routines
+
+ def put(src, convert_line = false)
+ if convert_line
+ replace_location(src) {
+ @f.puts src.text
+ }
+ else
+ @f.puts src.text
+ end
+ end
+
+ def line(str = '')
+ @f.puts str
+ end
+
+ def init_line_conversion_system
+ @cref = []
+ @used_separator = {}
+ end
+
+ def cref_push(name)
+ @cref.push name
+ end
+
+ def cref_pop
+ @cref.pop
+ end
+
+ def indent
+ @f.print ' ' * @cref.size
+ end
+
+ def toplevel?
+ @cref.empty?
+ end
+
+ def replace_location(src)
+ sep = make_separator(src)
+ @f.print 'self.class.' if toplevel?
+ @f.puts "module_eval(<<'#{sep}', '#{src.filename}', #{src.lineno})"
+ yield
+ @f.puts sep
+ end
+
+ def make_separator(src)
+ sep = unique_separator(src.filename)
+ sep *= 2 while src.text.index(sep)
+ sep
+ end
+
+ def unique_separator(id)
+ sep = String.new "...end #{id}/module_eval..."
+ while @used_separator.key?(sep)
+ sep.concat sprintf('%02x', rand(255))
+ end
+ @used_separator[sep] = true
+ sep
+ end
+
+ #
+ # State Transition Table Serialization
+ #
+
+ public
+
+ def put_state_transition_table(f)
+ @f = f
+ state_transition_table
+ end
+
+ private
+
+ def state_transition_table
+ table = @states.state_transition_table
+ table.use_result_var = @params.result_var?
+ table.debug_parser = @params.debug_parser?
+
+ line "##### State transition tables begin ###"
+ line
+ integer_list 'racc_action_table', table.action_table
+ line
+ integer_list 'racc_action_check', table.action_check
+ line
+ integer_list 'racc_action_pointer', table.action_pointer
+ line
+ integer_list 'racc_action_default', table.action_default
+ line
+ integer_list 'racc_goto_table', table.goto_table
+ line
+ integer_list 'racc_goto_check', table.goto_check
+ line
+ integer_list 'racc_goto_pointer', table.goto_pointer
+ line
+ integer_list 'racc_goto_default', table.goto_default
+ line
+ i_i_sym_list 'racc_reduce_table', table.reduce_table
+ line
+ line "racc_reduce_n = #{table.reduce_n}"
+ line
+ line "racc_shift_n = #{table.shift_n}"
+ line
+ sym_int_hash 'racc_token_table', table.token_table
+ line
+ line "racc_nt_base = #{table.nt_base}"
+ line
+ line "racc_use_result_var = #{table.use_result_var}"
+ line
+ @f.print(unindent_auto(<<-End))
+ Racc_arg = [
+ racc_action_table,
+ racc_action_check,
+ racc_action_default,
+ racc_action_pointer,
+ racc_goto_table,
+ racc_goto_check,
+ racc_goto_default,
+ racc_goto_pointer,
+ racc_nt_base,
+ racc_reduce_table,
+ racc_token_table,
+ racc_shift_n,
+ racc_reduce_n,
+ racc_use_result_var ]
+ End
+ line
+ string_list 'Racc_token_to_s_table', table.token_to_s_table
+ line
+ line "Racc_debug_parser = #{table.debug_parser}"
+ line
+ line '##### State transition tables end #####'
+ actions
+ end
+
+ def integer_list(name, table)
+ sep = ''
+ line "#{name} = ["
+ table.each_slice(10) do |ns|
+ @f.print sep; sep = ",\n"
+ @f.print ns.map {|n| sprintf('%6s', n ? n.to_s : 'nil') }.join(',')
+ end
+ line ' ]'
+ end
+
+ def i_i_sym_list(name, table)
+ sep = ''
+ line "#{name} = ["
+ table.each_slice(3) do |len, target, mid|
+ @f.print sep; sep = ",\n"
+ @f.printf ' %d, %d, %s', len, target, mid.inspect
+ end
+ line " ]"
+ end
+
+ def sym_int_hash(name, h)
+ sep = "\n"
+ @f.print "#{name} = {"
+ h.to_a.sort_by {|sym, i| i }.each do |sym, i|
+ @f.print sep; sep = ",\n"
+ @f.printf " %s => %d", sym.serialize, i
+ end
+ line " }"
+ end
+
+ def string_list(name, list)
+ sep = " "
+ line "#{name} = ["
+ list.each do |s|
+ @f.print sep; sep = ",\n "
+ @f.print s.dump
+ end
+ line ' ]'
+ end
+
+ def actions
+ @grammar.each do |rule|
+ unless rule.action.source?
+ raise "racc: fatal: cannot generate parser file when any action is a Proc"
+ end
+ end
+
+ if @params.result_var?
+ decl = ', result'
+ retval = "\n result"
+ default_body = ''
+ else
+ decl = ''
+ retval = ''
+ default_body = 'val[0]'
+ end
+ @grammar.each do |rule|
+ line
+ if rule.action.empty? and @params.omit_action_call?
+ line "# reduce #{rule.ident} omitted"
+ else
+ src0 = rule.action.source || SourceText.new(default_body, __FILE__, 0)
+ if @params.convert_line?
+ src = remove_blank_lines(src0)
+ delim = make_delimiter(src.text)
+ @f.printf unindent_auto(<<-End),
+ module_eval(<<'%s', '%s', %d)
+ def _reduce_%d(val, _values%s)
+ %s%s
+ end
+ %s
+ End
+ delim, src.filename, src.lineno - 1,
+ rule.ident, decl,
+ src.text, retval,
+ delim
+ else
+ src = remove_blank_lines(src0)
+ @f.printf unindent_auto(<<-End),
+ def _reduce_%d(val, _values%s)
+ %s%s
+ end
+ End
+ rule.ident, decl,
+ src.text, retval
+ end
+ end
+ end
+ line
+ @f.printf unindent_auto(<<-'End'), decl
+ def _reduce_none(val, _values%s)
+ val[0]
+ end
+ End
+ line
+ end
+
+ def remove_blank_lines(src)
+ body = src.text.dup
+ line = src.lineno
+ while body.slice!(/\A[ \t\f]*(?:\n|\r\n|\r)/)
+ line += 1
+ end
+ SourceText.new(body, src.filename, line)
+ end
+
+ def make_delimiter(body)
+ delim = '.,.,'
+ while body.index(delim)
+ delim *= 2
+ end
+ delim
+ end
+
+ def unindent_auto(str)
+ lines = str.lines.to_a
+ n = minimum_indent(lines)
+ lines.map {|line| detab(line).sub(indent_re(n), '').rstrip + "\n" }.join('')
+ end
+
+ def minimum_indent(lines)
+ lines.map {|line| n_indent(line) }.min
+ end
+
+ def n_indent(line)
+ line.slice(/\A\s+/).size
+ end
+
+ RE_CACHE = {}
+
+ def indent_re(n)
+ RE_CACHE[n] ||= /\A {#{n}}/
+ end
+
+ def detab(str, ts = 8)
+ add = 0
+ len = nil
+ str.gsub(/\t/) {
+ len = ts - ($`.size + add) % ts
+ add += len - 1
+ ' ' * len
+ }
+ end
+
+ end
+
+end
diff --git a/lib/racc/racc.gemspec b/lib/racc/racc.gemspec
new file mode 100644
index 0000000000..1095c8f47e
--- /dev/null
+++ b/lib/racc/racc.gemspec
@@ -0,0 +1,58 @@
+# -*- encoding: utf-8 -*-
+
+begin
+ require_relative "lib/racc/info"
+rescue LoadError # Fallback to load version file in ruby core repository
+ require_relative "info"
+end
+
+Gem::Specification.new do |s|
+ s.name = "racc"
+ s.version = Racc::VERSION
+ s.summary = "Racc is a LALR(1) parser generator"
+ s.description = <<DESC
+Racc is a LALR(1) parser generator.
+ It is written in Ruby itself, and generates Ruby program.
+
+ NOTE: Ruby 1.8.x comes with Racc runtime module. You
+ can run your parsers generated by racc 1.4.x out of the
+ box.
+DESC
+ s.authors = ["Minero Aoki", "Aaron Patterson"]
+ s.email = [nil, "aaron@tenderlovemaking.com"]
+ s.homepage = "https://github.com/ruby/racc"
+ s.licenses = ["Ruby", "BSD-2-Clause"]
+ s.executables = ["racc"]
+ s.files = [
+ "COPYING", "ChangeLog", "TODO",
+ "README.ja.rdoc", "README.rdoc", "bin/racc",
+ "ext/racc/MANIFEST",
+ "ext/racc/cparse/cparse.c",
+ "ext/racc/cparse/extconf.rb",
+ "lib/racc.rb", "lib/racc/compat.rb",
+ "lib/racc/debugflags.rb", "lib/racc/exception.rb",
+ "lib/racc/grammar.rb", "lib/racc/grammarfileparser.rb",
+ "lib/racc/info.rb", "lib/racc/iset.rb",
+ "lib/racc/logfilegenerator.rb", "lib/racc/parser-text.rb",
+ "lib/racc/parser.rb", "lib/racc/parserfilegenerator.rb",
+ "lib/racc/sourcetext.rb",
+ "lib/racc/state.rb", "lib/racc/statetransitiontable.rb",
+ "lib/racc/static.rb",
+ "doc/en/NEWS.en.rdoc", "doc/en/grammar2.en.rdoc",
+ "doc/en/grammar.en.rdoc", "doc/ja/NEWS.ja.rdoc",
+ "doc/ja/command.ja.html", "doc/ja/debug.ja.rdoc",
+ "doc/ja/grammar.ja.rdoc", "doc/ja/index.ja.html",
+ "doc/ja/parser.ja.rdoc", "doc/ja/usage.ja.html",
+ ]
+ s.require_paths = ["lib"]
+ s.required_ruby_version = ">= 2.5"
+ s.rdoc_options = ["--main", "README.rdoc"]
+ s.extra_rdoc_files = ["README.ja.rdoc", "README.rdoc"]
+
+ if RUBY_PLATFORM =~ /java/
+ s.files << 'lib/racc/cparse-jruby.jar'
+ s.platform = 'java'
+ else
+ s.extensions = ["ext/racc/cparse/extconf.rb"]
+ end
+end
diff --git a/lib/racc/sourcetext.rb b/lib/racc/sourcetext.rb
new file mode 100644
index 0000000000..de52dcae9b
--- /dev/null
+++ b/lib/racc/sourcetext.rb
@@ -0,0 +1,35 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+module Racc
+
+ class SourceText
+ def initialize(text, filename, lineno)
+ @text = text
+ @filename = filename
+ @lineno = lineno
+ end
+
+ attr_reader :text
+ attr_reader :filename
+ attr_reader :lineno
+
+ def to_s
+ "#<SourceText #{location()}>"
+ end
+
+ def location
+ "#{@filename}:#{@lineno}"
+ end
+ end
+
+end
diff --git a/lib/racc/state.rb b/lib/racc/state.rb
new file mode 100644
index 0000000000..f85809fbeb
--- /dev/null
+++ b/lib/racc/state.rb
@@ -0,0 +1,972 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+require 'racc/iset'
+require 'racc/statetransitiontable'
+require 'racc/exception'
+require 'forwardable'
+
+module Racc
+
+ # A table of LALR states.
+ class States
+
+ include Enumerable
+
+ def initialize(grammar, debug_flags = DebugFlags.new)
+ @grammar = grammar
+ @symboltable = grammar.symboltable
+ @d_state = debug_flags.state
+ @d_la = debug_flags.la
+ @d_prec = debug_flags.prec
+ @states = []
+ @statecache = {}
+ @actions = ActionTable.new(@grammar, self)
+ @nfa_computed = false
+ @dfa_computed = false
+ end
+
+ attr_reader :grammar
+ attr_reader :actions
+
+ def size
+ @states.size
+ end
+
+ def inspect
+ '#<state table>'
+ end
+
+ alias to_s inspect
+
+ def [](i)
+ @states[i]
+ end
+
+ def each_state(&block)
+ @states.each(&block)
+ end
+
+ alias each each_state
+
+ def each_index(&block)
+ @states.each_index(&block)
+ end
+
+ extend Forwardable
+
+ def_delegator "@actions", :shift_n
+ def_delegator "@actions", :reduce_n
+ def_delegator "@actions", :nt_base
+
+ def should_report_srconflict?
+ srconflict_exist? and
+ (n_srconflicts() != @grammar.n_expected_srconflicts)
+ end
+
+ def srconflict_exist?
+ n_srconflicts() != 0
+ end
+
+ def n_srconflicts
+ @n_srconflicts ||= inject(0) {|sum, st| sum + st.n_srconflicts }
+ end
+
+ def rrconflict_exist?
+ n_rrconflicts() != 0
+ end
+
+ def n_rrconflicts
+ @n_rrconflicts ||= inject(0) {|sum, st| sum + st.n_rrconflicts }
+ end
+
+ def state_transition_table
+ @state_transition_table ||= StateTransitionTable.generate(self.dfa)
+ end
+
+ #
+ # NFA (Non-deterministic Finite Automaton) Computation
+ #
+
+ public
+
+ def nfa
+ return self if @nfa_computed
+ compute_nfa
+ @nfa_computed = true
+ self
+ end
+
+ private
+
+ def compute_nfa
+ @grammar.init
+ # add state 0
+ core_to_state [ @grammar[0].ptrs[0] ]
+ # generate LALR states
+ cur = 0
+ @gotos = []
+ while cur < @states.size
+ generate_states @states[cur] # state is added here
+ cur += 1
+ end
+ @actions.init
+ end
+
+ def generate_states(state)
+ puts "dstate: #{state}" if @d_state
+
+ table = {}
+ state.closure.each do |ptr|
+ if sym = ptr.dereference
+ addsym table, sym, ptr.next
+ end
+ end
+ table.each do |sym, core|
+ puts "dstate: sym=#{sym} ncore=#{core}" if @d_state
+
+ dest = core_to_state(core.to_a)
+ state.goto_table[sym] = dest
+ id = sym.nonterminal?() ? @gotos.size : nil
+ g = Goto.new(id, sym, state, dest)
+ @gotos.push g if sym.nonterminal?
+ state.gotos[sym] = g
+ puts "dstate: #{state.ident} --#{sym}--> #{dest.ident}" if @d_state
+
+ # check infinite recursion
+ if state.ident == dest.ident and state.closure.size == 1
+ raise CompileError,
+ sprintf("Infinite recursion: state %d, with rule %d",
+ state.ident, state.ptrs[0].rule.ident)
+ end
+ end
+ end
+
+ def addsym(table, sym, ptr)
+ unless s = table[sym]
+ table[sym] = s = ISet.new
+ end
+ s.add ptr
+ end
+
+ def core_to_state(core)
+ #
+ # convert CORE to a State object.
+ # If matching state does not exist, create it and add to the table.
+ #
+
+ k = fingerprint(core)
+ unless dest = @statecache[k]
+ # not registered yet
+ dest = State.new(@states.size, core)
+ @states.push dest
+
+ @statecache[k] = dest
+
+ puts "core_to_state: create state ID #{dest.ident}" if @d_state
+ else
+ if @d_state
+ puts "core_to_state: dest is cached ID #{dest.ident}"
+ puts "core_to_state: dest core #{dest.core.join(' ')}"
+ end
+ end
+
+ dest
+ end
+
+ def fingerprint(arr)
+ arr.map {|i| i.ident }.pack('L*')
+ end
+
+ #
+ # DFA (Deterministic Finite Automaton) Generation
+ #
+
+ public
+
+ def dfa
+ return self if @dfa_computed
+ nfa
+ compute_dfa
+ @dfa_computed = true
+ self
+ end
+
+ private
+
+ def compute_dfa
+ la = lookahead()
+ @states.each do |state|
+ state.la = la
+ resolve state
+ end
+ set_accept
+ @states.each do |state|
+ pack state
+ end
+ check_useless
+ end
+
+ def lookahead
+ #
+ # lookahead algorithm ver.3 -- from bison 1.26
+ #
+
+ gotos = @gotos
+ if @d_la
+ puts "\n--- goto ---"
+ gotos.each_with_index {|g, i| print i, ' '; p g }
+ end
+
+ ### initialize_LA()
+ ### set_goto_map()
+ la_rules = []
+ @states.each do |state|
+ state.check_la la_rules
+ end
+
+ ### initialize_F()
+ f = create_tmap(gotos.size)
+ reads = []
+ edge = []
+ gotos.each do |goto|
+ goto.to_state.goto_table.each do |t, st|
+ if t.terminal?
+ f[goto.ident] |= (1 << t.ident)
+ elsif t.nullable?
+ edge.push goto.to_state.gotos[t].ident
+ end
+ end
+ if edge.empty?
+ reads.push nil
+ else
+ reads.push edge
+ edge = []
+ end
+ end
+ digraph f, reads
+ if @d_la
+ puts "\n--- F1 (reads) ---"
+ print_tab gotos, reads, f
+ end
+
+ ### build_relations()
+ ### compute_FOLLOWS
+ path = nil
+ edge = []
+ lookback = Array.new(la_rules.size, nil)
+ includes = []
+ gotos.each do |goto|
+ goto.symbol.heads.each do |ptr|
+ path = record_path(goto.from_state, ptr.rule)
+ lastgoto = path.last
+ st = lastgoto ? lastgoto.to_state : goto.from_state
+ if st.conflict?
+ addrel lookback, st.rruleid(ptr.rule), goto
+ end
+ path.reverse_each do |g|
+ break if g.symbol.terminal?
+ edge.push g.ident
+ break unless g.symbol.nullable?
+ end
+ end
+ if edge.empty?
+ includes.push nil
+ else
+ includes.push edge
+ edge = []
+ end
+ end
+ includes = transpose(includes)
+ digraph f, includes
+ if @d_la
+ puts "\n--- F2 (includes) ---"
+ print_tab gotos, includes, f
+ end
+
+ ### compute_lookaheads
+ la = create_tmap(la_rules.size)
+ lookback.each_with_index do |arr, i|
+ if arr
+ arr.each do |g|
+ la[i] |= f[g.ident]
+ end
+ end
+ end
+ if @d_la
+ puts "\n--- LA (lookback) ---"
+ print_tab la_rules, lookback, la
+ end
+
+ la
+ end
+
+ def create_tmap(size)
+ Array.new(size, 0) # use Integer as bitmap
+ end
+
+ def addrel(tbl, i, item)
+ if a = tbl[i]
+ a.push item
+ else
+ tbl[i] = [item]
+ end
+ end
+
+ def record_path(begst, rule)
+ st = begst
+ path = []
+ rule.symbols.each do |t|
+ goto = st.gotos[t]
+ path.push goto
+ st = goto.to_state
+ end
+ path
+ end
+
+ def transpose(rel)
+ new = Array.new(rel.size, nil)
+ rel.each_with_index do |arr, idx|
+ if arr
+ arr.each do |i|
+ addrel new, i, idx
+ end
+ end
+ end
+ new
+ end
+
+ def digraph(map, relation)
+ n = relation.size
+ index = Array.new(n, nil)
+ vertices = []
+ @infinity = n + 2
+
+ index.each_index do |i|
+ if not index[i] and relation[i]
+ traverse i, index, vertices, map, relation
+ end
+ end
+ end
+
+ def traverse(i, index, vertices, map, relation)
+ vertices.push i
+ index[i] = height = vertices.size
+
+ if rp = relation[i]
+ rp.each do |proci|
+ unless index[proci]
+ traverse proci, index, vertices, map, relation
+ end
+ if index[i] > index[proci]
+ # circulative recursion !!!
+ index[i] = index[proci]
+ end
+ map[i] |= map[proci]
+ end
+ end
+
+ if index[i] == height
+ while true
+ proci = vertices.pop
+ index[proci] = @infinity
+ break if i == proci
+
+ map[proci] |= map[i]
+ end
+ end
+ end
+
+ # for debug
+ def print_atab(idx, tab)
+ tab.each_with_index do |i,ii|
+ printf '%-20s', idx[ii].inspect
+ p i
+ end
+ end
+
+ def print_tab(idx, rel, tab)
+ tab.each_with_index do |bin,i|
+ print i, ' ', idx[i].inspect, ' << '; p rel[i]
+ print ' '
+ each_t(@symboltable, bin) {|t| print ' ', t }
+ puts
+ end
+ end
+
+ # for debug
+ def print_tab_i(idx, rel, tab, i)
+ bin = tab[i]
+ print i, ' ', idx[i].inspect, ' << '; p rel[i]
+ print ' '
+ each_t(@symboltable, bin) {|t| print ' ', t }
+ end
+
+ # for debug
+ def printb(i)
+ each_t(@symboltable, i) do |t|
+ print t, ' '
+ end
+ puts
+ end
+
+ def each_t(tbl, set)
+ 0.upto( set.size ) do |i|
+ (0..7).each do |ii|
+ if set[idx = i * 8 + ii] == 1
+ yield tbl[idx]
+ end
+ end
+ end
+ end
+
+ #
+ # resolve
+ #
+
+ def resolve(state)
+ if state.conflict?
+ resolve_rr state, state.ritems
+ resolve_sr state, state.stokens
+ else
+ if state.rrules.empty?
+ # shift
+ state.stokens.each do |t|
+ state.action[t] = @actions.shift(state.goto_table[t])
+ end
+ else
+ # reduce
+ state.defact = @actions.reduce(state.rrules[0])
+ end
+ end
+ end
+
+ def resolve_rr(state, r)
+ r.each do |item|
+ item.each_la(@symboltable) do |t|
+ act = state.action[t]
+ if act
+ unless act.kind_of?(Reduce)
+ raise "racc: fatal: #{act.class} in action table"
+ end
+ # Cannot resolve R/R conflict (on t).
+ # Reduce with upper rule as default.
+ state.rr_conflict act.rule, item.rule, t
+ else
+ # No conflict.
+ state.action[t] = @actions.reduce(item.rule)
+ end
+ end
+ end
+ end
+
+ def resolve_sr(state, s)
+ s.each do |stok|
+ goto = state.goto_table[stok]
+ act = state.action[stok]
+
+ unless act
+ # no conflict
+ state.action[stok] = @actions.shift(goto)
+ else
+ unless act.kind_of?(Reduce)
+ puts 'DEBUG -------------------------------'
+ p stok
+ p act
+ state.action.each do |k,v|
+ print k.inspect, ' ', v.inspect, "\n"
+ end
+ raise "racc: fatal: #{act.class} in action table"
+ end
+
+ # conflict on stok
+
+ rtok = act.rule.precedence
+ case do_resolve_sr(stok, rtok)
+ when :Reduce
+ # action is already set
+
+ when :Shift
+ # overwrite
+ act.decref
+ state.action[stok] = @actions.shift(goto)
+
+ when :Error
+ act.decref
+ state.action[stok] = @actions.error
+
+ when :CantResolve
+ # shift as default
+ act.decref
+ state.action[stok] = @actions.shift(goto)
+ state.sr_conflict stok, act.rule
+ end
+ end
+ end
+ end
+
+ ASSOC = {
+ :Left => :Reduce,
+ :Right => :Shift,
+ :Nonassoc => :Error
+ }
+
+ def do_resolve_sr(stok, rtok)
+ puts "resolve_sr: s/r conflict: rtok=#{rtok}, stok=#{stok}" if @d_prec
+
+ unless rtok and rtok.precedence
+ puts "resolve_sr: no prec for #{rtok}(R)" if @d_prec
+ return :CantResolve
+ end
+ rprec = rtok.precedence
+
+ unless stok and stok.precedence
+ puts "resolve_sr: no prec for #{stok}(S)" if @d_prec
+ return :CantResolve
+ end
+ sprec = stok.precedence
+
+ ret = if rprec == sprec
+ ASSOC[rtok.assoc] or
+ raise "racc: fatal: #{rtok}.assoc is not Left/Right/Nonassoc"
+ else
+ (rprec > sprec) ? (:Reduce) : (:Shift)
+ end
+
+ puts "resolve_sr: resolved as #{ret.id2name}" if @d_prec
+ ret
+ end
+
+ #
+ # complete
+ #
+
+ def set_accept
+ anch = @symboltable.anchor
+ init_state = @states[0].goto_table[@grammar.start]
+ targ_state = init_state.action[anch].goto_state
+ acc_state = targ_state.action[anch].goto_state
+
+ acc_state.action.clear
+ acc_state.goto_table.clear
+ acc_state.defact = @actions.accept
+ end
+
+ def pack(state)
+ ### find most frequently used reduce rule
+ act = state.action
+ arr = Array.new(@grammar.size, 0)
+ act.each do |t, a|
+ arr[a.ruleid] += 1 if a.kind_of?(Reduce)
+ end
+ i = arr.max
+ s = (i > 0) ? arr.index(i) : nil
+
+ ### set & delete default action
+ if s
+ r = @actions.reduce(s)
+ if not state.defact or state.defact == r
+ act.delete_if {|t, a| a == r }
+ state.defact = r
+ end
+ else
+ state.defact ||= @actions.error
+ end
+ end
+
+ def check_useless
+ used = []
+ @actions.each_reduce do |act|
+ if not act or act.refn == 0
+ act.rule.useless = true
+ else
+ t = act.rule.target
+ used[t.ident] = t
+ end
+ end
+ @symboltable.nt_base.upto(@symboltable.nt_max - 1) do |n|
+ unless used[n]
+ @symboltable[n].useless = true
+ end
+ end
+ end
+
+ end # class StateTable
+
+
+ # A LALR state.
+ class State
+
+ def initialize(ident, core)
+ @ident = ident
+ @core = core
+ @goto_table = {}
+ @gotos = {}
+ @stokens = nil
+ @ritems = nil
+ @action = {}
+ @defact = nil
+ @rrconf = nil
+ @srconf = nil
+
+ @closure = make_closure(@core)
+ end
+
+ attr_reader :ident
+ alias stateid ident
+ alias hash ident
+
+ attr_reader :core
+ attr_reader :closure
+
+ attr_reader :goto_table
+ attr_reader :gotos
+
+ attr_reader :stokens
+ attr_reader :ritems
+ attr_reader :rrules
+
+ attr_reader :action
+ attr_accessor :defact # default action
+
+ attr_reader :rrconf
+ attr_reader :srconf
+
+ def inspect
+ "<state #{@ident}>"
+ end
+
+ alias to_s inspect
+
+ def ==(oth)
+ @ident == oth.ident
+ end
+
+ alias eql? ==
+
+ def make_closure(core)
+ set = ISet.new
+ core.each do |ptr|
+ set.add ptr
+ if t = ptr.dereference and t.nonterminal?
+ set.update_a t.expand
+ end
+ end
+ set.to_a
+ end
+
+ def check_la(la_rules)
+ @conflict = false
+ s = []
+ r = []
+ @closure.each do |ptr|
+ if t = ptr.dereference
+ if t.terminal?
+ s[t.ident] = t
+ if t.ident == 1 # $error
+ @conflict = true
+ end
+ end
+ else
+ r.push ptr.rule
+ end
+ end
+ unless r.empty?
+ if not s.empty? or r.size > 1
+ @conflict = true
+ end
+ end
+ s.compact!
+ @stokens = s
+ @rrules = r
+
+ if @conflict
+ @la_rules_i = la_rules.size
+ @la_rules = r.map {|i| i.ident }
+ la_rules.concat r
+ else
+ @la_rules_i = @la_rules = nil
+ end
+ end
+
+ def conflict?
+ @conflict
+ end
+
+ def rruleid(rule)
+ if i = @la_rules.index(rule.ident)
+ @la_rules_i + i
+ else
+ puts '/// rruleid'
+ p self
+ p rule
+ p @rrules
+ p @la_rules_i
+ raise 'racc: fatal: cannot get reduce rule id'
+ end
+ end
+
+ def la=(la)
+ return unless @conflict
+ i = @la_rules_i
+ @ritems = r = []
+ @rrules.each do |rule|
+ r.push Item.new(rule, la[i])
+ i += 1
+ end
+ end
+
+ def rr_conflict(high, low, ctok)
+ c = RRconflict.new(@ident, high, low, ctok)
+
+ @rrconf ||= {}
+ if a = @rrconf[ctok]
+ a.push c
+ else
+ @rrconf[ctok] = [c]
+ end
+ end
+
+ def sr_conflict(shift, reduce)
+ c = SRconflict.new(@ident, shift, reduce)
+
+ @srconf ||= {}
+ if a = @srconf[shift]
+ a.push c
+ else
+ @srconf[shift] = [c]
+ end
+ end
+
+ def n_srconflicts
+ @srconf ? @srconf.size : 0
+ end
+
+ def n_rrconflicts
+ @rrconf ? @rrconf.size : 0
+ end
+
+ end # class State
+
+
+ #
+ # Represents a transition on the grammar.
+ # "Real goto" means a transition by nonterminal,
+ # but this class treats also terminal's.
+ # If one is a terminal transition, .ident returns nil.
+ #
+ class Goto
+ def initialize(ident, sym, from, to)
+ @ident = ident
+ @symbol = sym
+ @from_state = from
+ @to_state = to
+ end
+
+ attr_reader :ident
+ attr_reader :symbol
+ attr_reader :from_state
+ attr_reader :to_state
+
+ def inspect
+ "(#{@from_state.ident}-#{@symbol}->#{@to_state.ident})"
+ end
+ end
+
+
+ # LALR item. A set of rule and its lookahead tokens.
+ class Item
+ def initialize(rule, la)
+ @rule = rule
+ @la = la
+ end
+
+ attr_reader :rule
+ attr_reader :la
+
+ def each_la(tbl)
+ la = @la
+ 0.upto(la.size - 1) do |i|
+ (0..7).each do |ii|
+ if la[idx = i * 8 + ii] == 1
+ yield tbl[idx]
+ end
+ end
+ end
+ end
+ end
+
+
+ # The table of LALR actions. Actions are either of
+ # Shift, Reduce, Accept and Error.
+ class ActionTable
+
+ def initialize(rt, st)
+ @grammar = rt
+ @statetable = st
+
+ @reduce = []
+ @shift = []
+ @accept = nil
+ @error = nil
+ end
+
+ def init
+ @grammar.each do |rule|
+ @reduce.push Reduce.new(rule)
+ end
+ @statetable.each do |state|
+ @shift.push Shift.new(state)
+ end
+ @accept = Accept.new
+ @error = Error.new
+ end
+
+ def reduce_n
+ @reduce.size
+ end
+
+ def reduce(i)
+ case i
+ when Rule then i = i.ident
+ when Integer then ;
+ else
+ raise "racc: fatal: wrong class #{i.class} for reduce"
+ end
+
+ r = @reduce[i] or raise "racc: fatal: reduce action #{i.inspect} not exist"
+ r.incref
+ r
+ end
+
+ def each_reduce(&block)
+ @reduce.each(&block)
+ end
+
+ def shift_n
+ @shift.size
+ end
+
+ def shift(i)
+ case i
+ when State then i = i.ident
+ when Integer then ;
+ else
+ raise "racc: fatal: wrong class #{i.class} for shift"
+ end
+
+ @shift[i] or raise "racc: fatal: shift action #{i} does not exist"
+ end
+
+ def each_shift(&block)
+ @shift.each(&block)
+ end
+
+ attr_reader :accept
+ attr_reader :error
+
+ end
+
+
+ class Shift
+ def initialize(goto)
+ @goto_state = goto
+ end
+
+ attr_reader :goto_state
+
+ def goto_id
+ @goto_state.ident
+ end
+
+ def inspect
+ "<shift #{@goto_state.ident}>"
+ end
+ end
+
+
+ class Reduce
+ def initialize(rule)
+ @rule = rule
+ @refn = 0
+ end
+
+ attr_reader :rule
+ attr_reader :refn
+
+ def ruleid
+ @rule.ident
+ end
+
+ def inspect
+ "<reduce #{@rule.ident}>"
+ end
+
+ def incref
+ @refn += 1
+ end
+
+ def decref
+ @refn -= 1
+ raise 'racc: fatal: act.refn < 0' if @refn < 0
+ end
+ end
+
+ class Accept
+ def inspect
+ "<accept>"
+ end
+ end
+
+ class Error
+ def inspect
+ "<error>"
+ end
+ end
+
+ class SRconflict
+ def initialize(sid, shift, reduce)
+ @stateid = sid
+ @shift = shift
+ @reduce = reduce
+ end
+
+ attr_reader :stateid
+ attr_reader :shift
+ attr_reader :reduce
+
+ def to_s
+ sprintf('state %d: S/R conflict rule %d reduce and shift %s',
+ @stateid, @reduce.ruleid, @shift.to_s)
+ end
+ end
+
+ class RRconflict
+ def initialize(sid, high, low, tok)
+ @stateid = sid
+ @high_prec = high
+ @low_prec = low
+ @token = tok
+ end
+
+ attr_reader :stateid
+ attr_reader :high_prec
+ attr_reader :low_prec
+ attr_reader :token
+
+ def to_s
+ sprintf('state %d: R/R conflict with rule %d and %d on %s',
+ @stateid, @high_prec.ident, @low_prec.ident, @token.to_s)
+ end
+ end
+
+end
diff --git a/lib/racc/statetransitiontable.rb b/lib/racc/statetransitiontable.rb
new file mode 100644
index 0000000000..d75fa1657a
--- /dev/null
+++ b/lib/racc/statetransitiontable.rb
@@ -0,0 +1,311 @@
+#--
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+#
+#++
+
+require 'racc/parser'
+
+module Racc
+
+ StateTransitionTable = Struct.new(:action_table,
+ :action_check,
+ :action_default,
+ :action_pointer,
+ :goto_table,
+ :goto_check,
+ :goto_default,
+ :goto_pointer,
+ :token_table,
+ :reduce_table,
+ :reduce_n,
+ :shift_n,
+ :nt_base,
+ :token_to_s_table,
+ :use_result_var,
+ :debug_parser)
+ class StateTransitionTable # reopen
+ def StateTransitionTable.generate(states)
+ StateTransitionTableGenerator.new(states).generate
+ end
+
+ def initialize(states)
+ super()
+ @states = states
+ @grammar = states.grammar
+ self.use_result_var = true
+ self.debug_parser = true
+ end
+
+ attr_reader :states
+ attr_reader :grammar
+
+ def parser_class
+ ParserClassGenerator.new(@states).generate
+ end
+
+ def token_value_table
+ h = {}
+ token_table().each do |sym, i|
+ h[sym.value] = i
+ end
+ h
+ end
+ end
+
+
+ class StateTransitionTableGenerator
+
+ def initialize(states)
+ @states = states
+ @grammar = states.grammar
+ end
+
+ def generate
+ t = StateTransitionTable.new(@states)
+ gen_action_tables t, @states
+ gen_goto_tables t, @grammar
+ t.token_table = token_table(@grammar)
+ t.reduce_table = reduce_table(@grammar)
+ t.reduce_n = @states.reduce_n
+ t.shift_n = @states.shift_n
+ t.nt_base = @grammar.nonterminal_base
+ t.token_to_s_table = @grammar.symbols.map {|sym| sym.to_s }
+ t
+ end
+
+ def reduce_table(grammar)
+ t = [0, 0, :racc_error]
+ grammar.each_with_index do |rule, idx|
+ next if idx == 0
+ t.push rule.size
+ t.push rule.target.ident
+ t.push(if rule.action.empty? # and @params.omit_action_call?
+ then :_reduce_none
+ else "_reduce_#{idx}".intern
+ end)
+ end
+ t
+ end
+
+ def token_table(grammar)
+ h = {}
+ grammar.symboltable.terminals.each do |t|
+ h[t] = t.ident
+ end
+ h
+ end
+
+ def gen_action_tables(t, states)
+ t.action_table = yytable = []
+ t.action_check = yycheck = []
+ t.action_default = yydefact = []
+ t.action_pointer = yypact = []
+ e1 = []
+ e2 = []
+ states.each do |state|
+ yydefact.push act2actid(state.defact)
+ if state.action.empty?
+ yypact.push nil
+ next
+ end
+ vector = []
+ state.action.each do |tok, act|
+ vector[tok.ident] = act2actid(act)
+ end
+ addent e1, vector, state.ident, yypact
+ end
+ set_table e1, e2, yytable, yycheck, yypact
+ end
+
+ def gen_goto_tables(t, grammar)
+ t.goto_table = yytable2 = []
+ t.goto_check = yycheck2 = []
+ t.goto_pointer = yypgoto = []
+ t.goto_default = yydefgoto = []
+ e1 = []
+ e2 = []
+ grammar.each_nonterminal do |tok|
+ tmp = []
+
+ # decide default
+ freq = Array.new(@states.size, 0)
+ @states.each do |state|
+ st = state.goto_table[tok]
+ if st
+ st = st.ident
+ freq[st] += 1
+ end
+ tmp[state.ident] = st
+ end
+ max = freq.max
+ if max > 1
+ default = freq.index(max)
+ tmp.map! {|i| default == i ? nil : i }
+ else
+ default = nil
+ end
+ yydefgoto.push default
+
+ # delete default value
+ tmp.pop until tmp.last or tmp.empty?
+ if tmp.compact.empty?
+ # only default
+ yypgoto.push nil
+ next
+ end
+
+ addent e1, tmp, (tok.ident - grammar.nonterminal_base), yypgoto
+ end
+ set_table e1, e2, yytable2, yycheck2, yypgoto
+ end
+
+ def addent(all, arr, chkval, ptr)
+ max = arr.size
+ min = nil
+ arr.each_with_index do |item, idx|
+ if item
+ min ||= idx
+ end
+ end
+ ptr.push(-7777) # mark
+ arr = arr[min...max]
+ all.push [arr, chkval, mkmapexp(arr), min, ptr.size - 1]
+ end
+
+ n = 2 ** 16
+ begin
+ Regexp.compile("a{#{n}}")
+ RE_DUP_MAX = n
+ rescue RegexpError
+ n /= 2
+ retry
+ end
+
+ def mkmapexp(arr)
+ i = ii = 0
+ as = arr.size
+ map = String.new
+ maxdup = RE_DUP_MAX
+ curr = nil
+ while i < as
+ ii = i + 1
+ if arr[i]
+ ii += 1 while ii < as and arr[ii]
+ curr = '-'
+ else
+ ii += 1 while ii < as and not arr[ii]
+ curr = '.'
+ end
+
+ offset = ii - i
+ if offset == 1
+ map << curr
+ else
+ while offset > maxdup
+ map << "#{curr}{#{maxdup}}"
+ offset -= maxdup
+ end
+ map << "#{curr}{#{offset}}" if offset > 1
+ end
+ i = ii
+ end
+ Regexp.compile(map, Regexp::NOENCODING)
+ end
+
+ def set_table(entries, dummy, tbl, chk, ptr)
+ upper = 0
+ map = '-' * 10240
+
+ # sort long to short
+ entries.sort_by!.with_index {|a,i| [-a[0].size, i] }
+
+ entries.each do |arr, chkval, expr, min, ptri|
+ if upper + arr.size > map.size
+ map << '-' * (arr.size + 1024)
+ end
+ idx = map.index(expr)
+ ptr[ptri] = idx - min
+ arr.each_with_index do |item, i|
+ if item
+ i += idx
+ tbl[i] = item
+ chk[i] = chkval
+ map[i] = ?o
+ end
+ end
+ upper = idx + arr.size
+ end
+ end
+
+ def act2actid(act)
+ case act
+ when Shift then act.goto_id
+ when Reduce then -act.ruleid
+ when Accept then @states.shift_n
+ when Error then @states.reduce_n * -1
+ else
+ raise "racc: fatal: wrong act type #{act.class} in action table"
+ end
+ end
+
+ end
+
+
+ class ParserClassGenerator
+
+ def initialize(states)
+ @states = states
+ @grammar = states.grammar
+ end
+
+ def generate
+ table = @states.state_transition_table
+ c = Class.new(::Racc::Parser)
+ c.const_set :Racc_arg, [table.action_table,
+ table.action_check,
+ table.action_default,
+ table.action_pointer,
+ table.goto_table,
+ table.goto_check,
+ table.goto_default,
+ table.goto_pointer,
+ table.nt_base,
+ table.reduce_table,
+ table.token_value_table,
+ table.shift_n,
+ table.reduce_n,
+ false]
+ c.const_set :Racc_token_to_s_table, table.token_to_s_table
+ c.const_set :Racc_debug_parser, true
+ define_actions c
+ c
+ end
+
+ private
+
+ def define_actions(c)
+ c.module_eval "def _reduce_none(vals, vstack) vals[0] end"
+ @grammar.each do |rule|
+ if rule.action.empty?
+ c.alias_method("_reduce_#{rule.ident}", :_reduce_none)
+ else
+ c.define_method("_racc_action_#{rule.ident}", &rule.action.proc)
+ c.module_eval(<<-End, __FILE__, __LINE__ + 1)
+ def _reduce_#{rule.ident}(vals, vstack)
+ _racc_action_#{rule.ident}(*vals)
+ end
+ End
+ end
+ end
+ end
+
+ end
+
+end # module Racc
diff --git a/lib/racc/static.rb b/lib/racc/static.rb
new file mode 100644
index 0000000000..bebbeb5aa6
--- /dev/null
+++ b/lib/racc/static.rb
@@ -0,0 +1,5 @@
+require 'racc'
+require 'racc/parser'
+require 'racc/grammarfileparser'
+require 'racc/parserfilegenerator'
+require 'racc/logfilegenerator'
diff --git a/lib/random/formatter.rb b/lib/random/formatter.rb
index 2b5cf718ad..4dea61c16c 100644
--- a/lib/random/formatter.rb
+++ b/lib/random/formatter.rb
@@ -165,133 +165,15 @@ module Random::Formatter
#
# The result contains 122 random bits (15.25 random bytes).
#
- # See RFC9562[https://www.rfc-editor.org/rfc/rfc9562] for details of UUIDv4.
+ # See RFC4122[https://datatracker.ietf.org/doc/html/rfc4122] for details of UUID.
#
def uuid
- ary = random_bytes(16)
- ary.setbyte(6, (ary.getbyte(6) & 0x0f) | 0x40)
- ary.setbyte(8, (ary.getbyte(8) & 0x3f) | 0x80)
- ary.unpack("H8H4H4H4H12").join(?-)
+ ary = random_bytes(16).unpack("NnnnnN")
+ ary[2] = (ary[2] & 0x0fff) | 0x4000
+ ary[3] = (ary[3] & 0x3fff) | 0x8000
+ "%08x-%04x-%04x-%04x-%04x%08x" % ary
end
- alias uuid_v4 uuid
-
- # Generate a random v7 UUID (Universally Unique IDentifier).
- #
- # require 'random/formatter'
- #
- # Random.uuid_v7 # => "0188d4c3-1311-7f96-85c7-242a7aa58f1e"
- # Random.uuid_v7 # => "0188d4c3-16fe-744f-86af-38fa04c62bb5"
- # Random.uuid_v7 # => "0188d4c3-1af8-764f-b049-c204ce0afa23"
- # Random.uuid_v7 # => "0188d4c3-1e74-7085-b14f-ef6415dc6f31"
- # # |<--sorted-->| |<----- random ---->|
- #
- # # or
- # prng = Random.new
- # prng.uuid_v7 # => "0188ca51-5e72-7950-a11d-def7ff977c98"
- #
- # The version 7 UUID starts with the least significant 48 bits of a 64 bit
- # Unix timestamp (milliseconds since the epoch) and fills the remaining bits
- # with random data, excluding the version and variant bits.
- #
- # This allows version 7 UUIDs to be sorted by creation time. Time ordered
- # UUIDs can be used for better database index locality of newly inserted
- # records, which may have a significant performance benefit compared to random
- # data inserts.
- #
- # The result contains 74 random bits (9.25 random bytes).
- #
- # Note that this method cannot be made reproducible because its output
- # includes not only random bits but also timestamp.
- #
- # See RFC9562[https://www.rfc-editor.org/rfc/rfc9562] for details of UUIDv7.
- #
- # ==== Monotonicity
- #
- # UUIDv7 has millisecond precision by default, so multiple UUIDs created
- # within the same millisecond are not issued in monotonically increasing
- # order. To create UUIDs that are time-ordered with sub-millisecond
- # precision, up to 12 bits of additional timestamp may added with
- # +extra_timestamp_bits+. The extra timestamp precision comes at the expense
- # of random bits. Setting <tt>extra_timestamp_bits: 12</tt> provides ~244ns
- # of precision, but only 62 random bits (7.75 random bytes).
- #
- # prng = Random.new
- # Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 12) }
- # # =>
- # ["0188d4c7-13da-74f9-8b53-22a786ffdd5a",
- # "0188d4c7-13da-753b-83a5-7fb9b2afaeea",
- # "0188d4c7-13da-754a-88ea-ac0baeedd8db",
- # "0188d4c7-13da-7557-83e1-7cad9cda0d8d"]
- # # |<--- sorted --->| |<-- random --->|
- #
- # Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 8) }
- # # =>
- # ["0188d4c7-3333-7a95-850a-de6edb858f7e",
- # "0188d4c7-3333-7ae8-842e-bc3a8b7d0cf9", # <- out of order
- # "0188d4c7-3333-7ae2-995a-9f135dc44ead", # <- out of order
- # "0188d4c7-3333-7af9-87c3-8f612edac82e"]
- # # |<--- sorted -->||<---- random --->|
- #
- # Any rollbacks of the system clock will break monotonicity. UUIDv7 is based
- # on UTC, which excludes leap seconds and can rollback the clock. To avoid
- # this, the system clock can synchronize with an NTP server configured to use
- # a "leap smear" approach. NTP or PTP will also be needed to synchronize
- # across distributed nodes.
- #
- # Counters and other mechanisms for stronger guarantees of monotonicity are
- # not implemented. Applications with stricter requirements should follow
- # {Section 6.2}[https://www.rfc-editor.org/rfc/rfc9562.html#name-monotonicity-and-counters]
- # of the specification.
- #
- def uuid_v7(extra_timestamp_bits: 0)
- case (extra_timestamp_bits = Integer(extra_timestamp_bits))
- when 0 # min timestamp precision
- ms = Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
- rand = random_bytes(10)
- rand.setbyte(0, rand.getbyte(0) & 0x0f | 0x70) # version
- rand.setbyte(2, rand.getbyte(2) & 0x3f | 0x80) # variant
- "%08x-%04x-%s" % [
- (ms & 0x0000_ffff_ffff_0000) >> 16,
- (ms & 0x0000_0000_0000_ffff),
- rand.unpack("H4H4H12").join("-")
- ]
-
- when 12 # max timestamp precision
- ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
- .divmod(1_000_000)
- extra_bits = ns * 4096 / 1_000_000
- rand = random_bytes(8)
- rand.setbyte(0, rand.getbyte(0) & 0x3f | 0x80) # variant
- "%08x-%04x-7%03x-%s" % [
- (ms & 0x0000_ffff_ffff_0000) >> 16,
- (ms & 0x0000_0000_0000_ffff),
- extra_bits,
- rand.unpack("H4H12").join("-")
- ]
-
- when (0..12) # the generic version is slower than the special cases above
- rand_a, rand_b1, rand_b2, rand_b3 = random_bytes(10).unpack("nnnN")
- rand_mask_bits = 12 - extra_timestamp_bits
- ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
- .divmod(1_000_000)
- "%08x-%04x-%04x-%04x-%04x%08x" % [
- (ms & 0x0000_ffff_ffff_0000) >> 16,
- (ms & 0x0000_0000_0000_ffff),
- 0x7000 |
- ((ns * (1 << extra_timestamp_bits) / 1_000_000) << rand_mask_bits) |
- rand_a & ((1 << rand_mask_bits) - 1),
- 0x8000 | (rand_b1 & 0x3fff),
- rand_b2,
- rand_b3
- ]
-
- else
- raise ArgumentError, "extra_timestamp_bits must be in 0..12"
- end
- end
-
- # Internal interface to Random; Generate random data _n_ bytes.
private def gen_random(n)
self.bytes(n)
end
@@ -339,20 +221,16 @@ module Random::Formatter
result
end
- # The default character list for #alphanumeric.
ALPHANUMERIC = [*'A'..'Z', *'a'..'z', *'0'..'9']
-
# Generate a random alphanumeric string.
#
# The argument _n_ specifies the length, in characters, of the alphanumeric
# string to be generated.
- # The argument _chars_ specifies the character list which the result is
- # consist of.
#
# If _n_ is not specified or is nil, 16 is assumed.
# It may be larger in the future.
#
- # The result may contain A-Z, a-z and 0-9, unless _chars_ is specified.
+ # The result may contain A-Z, a-z and 0-9.
#
# require 'random/formatter'
#
@@ -360,13 +238,8 @@ module Random::Formatter
# # or
# prng = Random.new
# prng.alphanumeric(10) #=> "i6K93NdqiH"
- #
- # Random.alphanumeric(4, chars: [*"0".."9"]) #=> "2952"
- # # or
- # prng = Random.new
- # prng.alphanumeric(10, chars: [*"!".."/"]) #=> ",.,++%/''."
- def alphanumeric(n = nil, chars: ALPHANUMERIC)
+ def alphanumeric(n=nil)
n = 16 if n.nil?
- choose(chars, n)
+ choose(ALPHANUMERIC, n)
end
end
diff --git a/lib/rdoc.rb b/lib/rdoc.rb
index 3821569f45..b62c22576d 100644
--- a/lib/rdoc.rb
+++ b/lib/rdoc.rb
@@ -21,7 +21,7 @@ $DEBUG_RDOC = nil
# see RDoc::Markup and refer to <tt>rdoc --help</tt> for command line usage.
#
# If you want to set the default markup format see
-# RDoc::Markup@Markup+Formats
+# RDoc::Markup@Supported+Formats
#
# If you want to store rdoc configuration in your gem (such as the default
# markup format) see RDoc::Options@Saved+Options
@@ -120,17 +120,6 @@ module RDoc
end
end
- ##
- # Searches and returns the directory for settings.
- #
- # 1. <tt>$HOME/.rdoc</tt> directory, if it exists.
- # 2. The +rdoc+ directory under the path specified by the
- # +XDG_DATA_HOME+ environment variable, if it is set.
- # 3. <tt>$HOME/.local/share/rdoc</tt> directory.
- #
- # Other than the home directory, the containing directory will be
- # created automatically.
-
def self.home
rdoc_dir = begin
File.expand_path('~/.rdoc')
@@ -140,7 +129,6 @@ module RDoc
if File.directory?(rdoc_dir)
rdoc_dir
else
- require 'fileutils'
begin
# XDG
xdg_data_home = ENV["XDG_DATA_HOME"] || File.join(File.expand_path("~"), '.local', 'share')
@@ -188,26 +176,26 @@ module RDoc
# programs: classes, modules, methods, and so on.
autoload :CodeObject, "#{__dir__}/rdoc/code_object"
- autoload :Context, "#{__dir__}/rdoc/code_object/context"
- autoload :TopLevel, "#{__dir__}/rdoc/code_object/top_level"
-
- autoload :AnonClass, "#{__dir__}/rdoc/code_object/anon_class"
- autoload :ClassModule, "#{__dir__}/rdoc/code_object/class_module"
- autoload :NormalClass, "#{__dir__}/rdoc/code_object/normal_class"
- autoload :NormalModule, "#{__dir__}/rdoc/code_object/normal_module"
- autoload :SingleClass, "#{__dir__}/rdoc/code_object/single_class"
-
- autoload :Alias, "#{__dir__}/rdoc/code_object/alias"
- autoload :AnyMethod, "#{__dir__}/rdoc/code_object/any_method"
- autoload :MethodAttr, "#{__dir__}/rdoc/code_object/method_attr"
- autoload :GhostMethod, "#{__dir__}/rdoc/code_object/ghost_method"
- autoload :MetaMethod, "#{__dir__}/rdoc/code_object/meta_method"
- autoload :Attr, "#{__dir__}/rdoc/code_object/attr"
-
- autoload :Constant, "#{__dir__}/rdoc/code_object/constant"
- autoload :Mixin, "#{__dir__}/rdoc/code_object/mixin"
- autoload :Include, "#{__dir__}/rdoc/code_object/include"
- autoload :Extend, "#{__dir__}/rdoc/code_object/extend"
- autoload :Require, "#{__dir__}/rdoc/code_object/require"
+ autoload :Context, "#{__dir__}/rdoc/context"
+ autoload :TopLevel, "#{__dir__}/rdoc/top_level"
+
+ autoload :AnonClass, "#{__dir__}/rdoc/anon_class"
+ autoload :ClassModule, "#{__dir__}/rdoc/class_module"
+ autoload :NormalClass, "#{__dir__}/rdoc/normal_class"
+ autoload :NormalModule, "#{__dir__}/rdoc/normal_module"
+ autoload :SingleClass, "#{__dir__}/rdoc/single_class"
+
+ autoload :Alias, "#{__dir__}/rdoc/alias"
+ autoload :AnyMethod, "#{__dir__}/rdoc/any_method"
+ autoload :MethodAttr, "#{__dir__}/rdoc/method_attr"
+ autoload :GhostMethod, "#{__dir__}/rdoc/ghost_method"
+ autoload :MetaMethod, "#{__dir__}/rdoc/meta_method"
+ autoload :Attr, "#{__dir__}/rdoc/attr"
+
+ autoload :Constant, "#{__dir__}/rdoc/constant"
+ autoload :Mixin, "#{__dir__}/rdoc/mixin"
+ autoload :Include, "#{__dir__}/rdoc/include"
+ autoload :Extend, "#{__dir__}/rdoc/extend"
+ autoload :Require, "#{__dir__}/rdoc/require"
end
diff --git a/lib/rdoc/alias.rb b/lib/rdoc/alias.rb
new file mode 100644
index 0000000000..858e053049
--- /dev/null
+++ b/lib/rdoc/alias.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+##
+# Represent an alias, which is an old_name/new_name pair associated with a
+# particular context
+#--
+# TODO implement Alias as a proxy to a method/attribute, inheriting from
+# MethodAttr
+
+class RDoc::Alias < RDoc::CodeObject
+
+ ##
+ # Aliased method's name
+
+ attr_reader :new_name
+
+ alias name new_name
+
+ ##
+ # Aliasee method's name
+
+ attr_reader :old_name
+
+ ##
+ # Is this an alias declared in a singleton context?
+
+ attr_accessor :singleton
+
+ ##
+ # Source file token stream
+
+ attr_reader :text
+
+ ##
+ # Creates a new Alias with a token stream of +text+ that aliases +old_name+
+ # to +new_name+, has +comment+ and is a +singleton+ context.
+
+ def initialize(text, old_name, new_name, comment, singleton = false)
+ super()
+
+ @text = text
+ @singleton = singleton
+ @old_name = old_name
+ @new_name = new_name
+ self.comment = comment
+ end
+
+ ##
+ # Order by #singleton then #new_name
+
+ def <=>(other)
+ [@singleton ? 0 : 1, new_name] <=> [other.singleton ? 0 : 1, other.new_name]
+ end
+
+ ##
+ # HTML fragment reference for this alias
+
+ def aref
+ type = singleton ? 'c' : 'i'
+ "#alias-#{type}-#{html_name}"
+ end
+
+ ##
+ # Full old name including namespace
+
+ def full_old_name
+ @full_name || "#{parent.name}#{pretty_old_name}"
+ end
+
+ ##
+ # HTML id-friendly version of +#new_name+.
+
+ def html_name
+ CGI.escape(@new_name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '')
+ end
+
+ def inspect # :nodoc:
+ parent_name = parent ? parent.name : '(unknown)'
+ "#<%s:0x%x %s.alias_method %s, %s>" % [
+ self.class, object_id,
+ parent_name, @old_name, @new_name,
+ ]
+ end
+
+ ##
+ # '::' for the alias of a singleton method/attribute, '#' for instance-level.
+
+ def name_prefix
+ singleton ? '::' : '#'
+ end
+
+ ##
+ # Old name with prefix '::' or '#'.
+
+ def pretty_old_name
+ "#{singleton ? '::' : '#'}#{@old_name}"
+ end
+
+ ##
+ # New name with prefix '::' or '#'.
+
+ def pretty_new_name
+ "#{singleton ? '::' : '#'}#{@new_name}"
+ end
+
+ alias pretty_name pretty_new_name
+
+ def to_s # :nodoc:
+ "alias: #{self.new_name} -> #{self.pretty_old_name} in: #{parent}"
+ end
+
+end
+
diff --git a/lib/rdoc/anon_class.rb b/lib/rdoc/anon_class.rb
new file mode 100644
index 0000000000..d02a38c2cf
--- /dev/null
+++ b/lib/rdoc/anon_class.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+##
+# An anonymous class like:
+#
+# c = Class.new do end
+#
+# AnonClass is currently not used.
+
+class RDoc::AnonClass < RDoc::ClassModule
+end
+
diff --git a/lib/rdoc/any_method.rb b/lib/rdoc/any_method.rb
new file mode 100644
index 0000000000..051f946a10
--- /dev/null
+++ b/lib/rdoc/any_method.rb
@@ -0,0 +1,364 @@
+# frozen_string_literal: true
+##
+# AnyMethod is the base class for objects representing methods
+
+class RDoc::AnyMethod < RDoc::MethodAttr
+
+ ##
+ # 2::
+ # RDoc 4
+ # Added calls_super
+ # Added parent name and class
+ # Added section title
+ # 3::
+ # RDoc 4.1
+ # Added is_alias_for
+
+ MARSHAL_VERSION = 3 # :nodoc:
+
+ ##
+ # Don't rename \#initialize to \::new
+
+ attr_accessor :dont_rename_initialize
+
+ ##
+ # The C function that implements this method (if it was defined in a C file)
+
+ attr_accessor :c_function
+
+ # The section title of the method (if defined in a C file via +:category:+)
+ attr_accessor :section_title
+
+ # Parameters for this method
+
+ attr_accessor :params
+
+ ##
+ # If true this method uses +super+ to call a superclass version
+
+ attr_accessor :calls_super
+
+ include RDoc::TokenStream
+
+ ##
+ # Creates a new AnyMethod with a token stream +text+ and +name+
+
+ def initialize text, name
+ super
+
+ @c_function = nil
+ @dont_rename_initialize = false
+ @token_stream = nil
+ @calls_super = false
+ @superclass_method = nil
+ end
+
+ ##
+ # Adds +an_alias+ as an alias for this method in +context+.
+
+ def add_alias an_alias, context = nil
+ method = self.class.new an_alias.text, an_alias.new_name
+
+ method.record_location an_alias.file
+ method.singleton = self.singleton
+ method.params = self.params
+ method.visibility = self.visibility
+ method.comment = an_alias.comment
+ method.is_alias_for = self
+ @aliases << method
+ context.add_method method if context
+ method
+ end
+
+ ##
+ # Prefix for +aref+ is 'method'.
+
+ def aref_prefix
+ 'method'
+ end
+
+ ##
+ # The call_seq or the param_seq with method name, if there is no call_seq.
+ #
+ # Use this for displaying a method's argument lists.
+
+ def arglists
+ if @call_seq then
+ @call_seq
+ elsif @params then
+ "#{name}#{param_seq}"
+ end
+ end
+
+ ##
+ # Different ways to call this method
+
+ def call_seq
+ unless call_seq = _call_seq
+ call_seq = is_alias_for._call_seq if is_alias_for
+ end
+
+ return unless call_seq
+
+ deduplicate_call_seq(call_seq)
+ end
+
+ ##
+ # Sets the different ways you can call this method. If an empty +call_seq+
+ # is given nil is assumed.
+ #
+ # See also #param_seq
+
+ def call_seq= call_seq
+ return if call_seq.empty?
+
+ @call_seq = call_seq
+ end
+
+ ##
+ # Loads is_alias_for from the internal name. Returns nil if the alias
+ # cannot be found.
+
+ def is_alias_for # :nodoc:
+ case @is_alias_for
+ when RDoc::MethodAttr then
+ @is_alias_for
+ when Array then
+ return nil unless @store
+
+ klass_name, singleton, method_name = @is_alias_for
+
+ return nil unless klass = @store.find_class_or_module(klass_name)
+
+ @is_alias_for = klass.find_method method_name, singleton
+ end
+ end
+
+ ##
+ # Dumps this AnyMethod for use by ri. See also #marshal_load
+
+ def marshal_dump
+ aliases = @aliases.map do |a|
+ [a.name, parse(a.comment)]
+ end
+
+ is_alias_for = [
+ @is_alias_for.parent.full_name,
+ @is_alias_for.singleton,
+ @is_alias_for.name
+ ] if @is_alias_for
+
+ [ MARSHAL_VERSION,
+ @name,
+ full_name,
+ @singleton,
+ @visibility,
+ parse(@comment),
+ @call_seq,
+ @block_params,
+ aliases,
+ @params,
+ @file.relative_name,
+ @calls_super,
+ @parent.name,
+ @parent.class,
+ @section.title,
+ is_alias_for,
+ ]
+ end
+
+ ##
+ # Loads this AnyMethod from +array+. For a loaded AnyMethod the following
+ # methods will return cached values:
+ #
+ # * #full_name
+ # * #parent_name
+
+ def marshal_load array
+ initialize_visibility
+
+ @dont_rename_initialize = nil
+ @token_stream = nil
+ @aliases = []
+ @parent = nil
+ @parent_name = nil
+ @parent_class = nil
+ @section = nil
+ @file = nil
+
+ version = array[0]
+ @name = array[1]
+ @full_name = array[2]
+ @singleton = array[3]
+ @visibility = array[4]
+ @comment = array[5]
+ @call_seq = array[6]
+ @block_params = array[7]
+ # 8 handled below
+ @params = array[9]
+ # 10 handled below
+ @calls_super = array[11]
+ @parent_name = array[12]
+ @parent_title = array[13]
+ @section_title = array[14]
+ @is_alias_for = array[15]
+
+ array[8].each do |new_name, comment|
+ add_alias RDoc::Alias.new(nil, @name, new_name, comment, @singleton)
+ end
+
+ @parent_name ||= if @full_name =~ /#/ then
+ $`
+ else
+ name = @full_name.split('::')
+ name.pop
+ name.join '::'
+ end
+
+ @file = RDoc::TopLevel.new array[10] if version > 0
+ end
+
+ ##
+ # Method name
+ #
+ # If the method has no assigned name, it extracts it from #call_seq.
+
+ def name
+ return @name if @name
+
+ @name =
+ @call_seq[/^.*?\.(\w+)/, 1] ||
+ @call_seq[/^.*?(\w+)/, 1] ||
+ @call_seq if @call_seq
+ end
+
+ ##
+ # A list of this method's method and yield parameters. +call-seq+ params
+ # are preferred over parsed method and block params.
+
+ def param_list
+ if @call_seq then
+ params = @call_seq.split("\n").last
+ params = params.sub(/.*?\((.*)\)/, '\1')
+ params = params.sub(/(\{|do)\s*\|([^|]*)\|.*/, ',\2')
+ elsif @params then
+ params = @params.sub(/\((.*)\)/, '\1')
+
+ params << ",#{@block_params}" if @block_params
+ elsif @block_params then
+ params = @block_params
+ else
+ return []
+ end
+
+ if @block_params then
+ # If this method has explicit block parameters, remove any explicit
+ # &block
+ params = params.sub(/,?\s*&\w+/, '')
+ else
+ params = params.sub(/\&(\w+)/, '\1')
+ end
+
+ params = params.gsub(/\s+/, '').split(',').reject(&:empty?)
+
+ params.map { |param| param.sub(/=.*/, '') }
+ end
+
+ ##
+ # Pretty parameter list for this method. If the method's parameters were
+ # given by +call-seq+ it is preferred over the parsed values.
+
+ def param_seq
+ if @call_seq then
+ params = @call_seq.split("\n").last
+ params = params.sub(/[^( ]+/, '')
+ params = params.sub(/(\|[^|]+\|)\s*\.\.\.\s*(end|\})/, '\1 \2')
+ elsif @params then
+ params = @params.gsub(/\s*\#.*/, '')
+ params = params.tr_s("\n ", " ")
+ params = "(#{params})" unless params[0] == ?(
+ else
+ params = ''
+ end
+
+ if @block_params then
+ # If this method has explicit block parameters, remove any explicit
+ # &block
+ params = params.sub(/,?\s*&\w+/, '')
+
+ block = @block_params.tr_s("\n ", " ")
+ if block[0] == ?(
+ block = block.sub(/^\(/, '').sub(/\)/, '')
+ end
+ params << " { |#{block}| ... }"
+ end
+
+ params
+ end
+
+ ##
+ # Sets the store for this method and its referenced code objects.
+
+ def store= store
+ super
+
+ @file = @store.add_file @file.full_name if @file
+ end
+
+ ##
+ # For methods that +super+, find the superclass method that would be called.
+
+ def superclass_method
+ return unless @calls_super
+ return @superclass_method if @superclass_method
+
+ parent.each_ancestor do |ancestor|
+ if method = ancestor.method_list.find { |m| m.name == @name } then
+ @superclass_method = method
+ break
+ end
+ end
+
+ @superclass_method
+ end
+
+ protected
+
+ ##
+ # call_seq without deduplication and alias lookup.
+
+ def _call_seq
+ @call_seq if defined?(@call_seq) && @call_seq
+ end
+
+ private
+
+ ##
+ # call_seq with alias examples information removed, if this
+ # method is an alias method.
+
+ def deduplicate_call_seq(call_seq)
+ return call_seq unless is_alias_for || !aliases.empty?
+
+ method_name = self.name
+ method_name = method_name[0, 1] if method_name =~ /\A\[/
+
+ entries = call_seq.split "\n"
+
+ ignore = aliases.map(&:name)
+ if is_alias_for
+ ignore << is_alias_for.name
+ ignore.concat is_alias_for.aliases.map(&:name)
+ end
+ ignore.map! { |n| n =~ /\A\[/ ? /\[.*\]/ : n}
+ ignore.delete(method_name)
+ ignore = Regexp.union(ignore)
+
+ matching = entries.reject do |entry|
+ entry =~ /^\w*\.?#{ignore}[$\(\s]/ or
+ entry =~ /\s#{ignore}\s/
+ end
+
+ matching.empty? ? nil : matching.join("\n")
+ end
+end
diff --git a/lib/rdoc/attr.rb b/lib/rdoc/attr.rb
new file mode 100644
index 0000000000..f780b3b976
--- /dev/null
+++ b/lib/rdoc/attr.rb
@@ -0,0 +1,176 @@
+# frozen_string_literal: true
+##
+# An attribute created by \#attr, \#attr_reader, \#attr_writer or
+# \#attr_accessor
+
+class RDoc::Attr < RDoc::MethodAttr
+
+ ##
+ # 3::
+ # RDoc 4
+ # Added parent name and class
+ # Added section title
+
+ MARSHAL_VERSION = 3 # :nodoc:
+
+ ##
+ # Is the attribute readable ('R'), writable ('W') or both ('RW')?
+
+ attr_accessor :rw
+
+ ##
+ # Creates a new Attr with body +text+, +name+, read/write status +rw+ and
+ # +comment+. +singleton+ marks this as a class attribute.
+
+ def initialize(text, name, rw, comment, singleton = false)
+ super text, name
+
+ @rw = rw
+ @singleton = singleton
+ self.comment = comment
+ end
+
+ ##
+ # Attributes are equal when their names, singleton and rw are identical
+
+ def == other
+ self.class == other.class and
+ self.name == other.name and
+ self.rw == other.rw and
+ self.singleton == other.singleton
+ end
+
+ ##
+ # Add +an_alias+ as an attribute in +context+.
+
+ def add_alias(an_alias, context)
+ new_attr = self.class.new(self.text, an_alias.new_name, self.rw,
+ self.comment, self.singleton)
+
+ new_attr.record_location an_alias.file
+ new_attr.visibility = self.visibility
+ new_attr.is_alias_for = self
+ @aliases << new_attr
+ context.add_attribute new_attr
+ new_attr
+ end
+
+ ##
+ # The #aref prefix for attributes
+
+ def aref_prefix
+ 'attribute'
+ end
+
+ ##
+ # Attributes never call super. See RDoc::AnyMethod#calls_super
+ #
+ # An RDoc::Attr can show up in the method list in some situations (see
+ # Gem::ConfigFile)
+
+ def calls_super # :nodoc:
+ false
+ end
+
+ ##
+ # Returns attr_reader, attr_writer or attr_accessor as appropriate.
+
+ def definition
+ case @rw
+ when 'RW' then 'attr_accessor'
+ when 'R' then 'attr_reader'
+ when 'W' then 'attr_writer'
+ end
+ end
+
+ def inspect # :nodoc:
+ alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
+ visibility = self.visibility
+ visibility = "forced #{visibility}" if force_documentation
+ "#<%s:0x%x %s %s (%s)%s>" % [
+ self.class, object_id,
+ full_name,
+ rw,
+ visibility,
+ alias_for,
+ ]
+ end
+
+ ##
+ # Dumps this Attr for use by ri. See also #marshal_load
+
+ def marshal_dump
+ [ MARSHAL_VERSION,
+ @name,
+ full_name,
+ @rw,
+ @visibility,
+ parse(@comment),
+ singleton,
+ @file.relative_name,
+ @parent.full_name,
+ @parent.class,
+ @section.title
+ ]
+ end
+
+ ##
+ # Loads this Attr from +array+. For a loaded Attr the following
+ # methods will return cached values:
+ #
+ # * #full_name
+ # * #parent_name
+
+ def marshal_load array
+ initialize_visibility
+
+ @aliases = []
+ @parent = nil
+ @parent_name = nil
+ @parent_class = nil
+ @section = nil
+ @file = nil
+
+ version = array[0]
+ @name = array[1]
+ @full_name = array[2]
+ @rw = array[3]
+ @visibility = array[4]
+ @comment = array[5]
+ @singleton = array[6] || false # MARSHAL_VERSION == 0
+ # 7 handled below
+ @parent_name = array[8]
+ @parent_class = array[9]
+ @section_title = array[10]
+
+ @file = RDoc::TopLevel.new array[7] if version > 1
+
+ @parent_name ||= @full_name.split('#', 2).first
+ end
+
+ def pretty_print q # :nodoc:
+ q.group 2, "[#{self.class.name} #{full_name} #{rw} #{visibility}", "]" do
+ unless comment.empty? then
+ q.breakable
+ q.text "comment:"
+ q.breakable
+ q.pp @comment
+ end
+ end
+ end
+
+ def to_s # :nodoc:
+ "#{definition} #{name} in: #{parent}"
+ end
+
+ ##
+ # Attributes do not have token streams.
+ #
+ # An RDoc::Attr can show up in the method list in some situations (see
+ # Gem::ConfigFile)
+
+ def token_stream # :nodoc:
+ end
+
+end
+
diff --git a/lib/rdoc/class_module.rb b/lib/rdoc/class_module.rb
new file mode 100644
index 0000000000..7609080fbf
--- /dev/null
+++ b/lib/rdoc/class_module.rb
@@ -0,0 +1,802 @@
+# frozen_string_literal: true
+##
+# ClassModule is the base class for objects representing either a class or a
+# module.
+
+class RDoc::ClassModule < RDoc::Context
+
+ ##
+ # 1::
+ # RDoc 3.7
+ # * Added visibility, singleton and file to attributes
+ # * Added file to constants
+ # * Added file to includes
+ # * Added file to methods
+ # 2::
+ # RDoc 3.13
+ # * Added extends
+ # 3::
+ # RDoc 4.0
+ # * Added sections
+ # * Added in_files
+ # * Added parent name
+ # * Complete Constant dump
+
+ MARSHAL_VERSION = 3 # :nodoc:
+
+ ##
+ # Constants that are aliases for this class or module
+
+ attr_accessor :constant_aliases
+
+ ##
+ # Comment and the location it came from. Use #add_comment to add comments
+
+ attr_accessor :comment_location
+
+ attr_accessor :diagram # :nodoc:
+
+ ##
+ # Class or module this constant is an alias for
+
+ attr_accessor :is_alias_for
+
+ ##
+ # Return a RDoc::ClassModule of class +class_type+ that is a copy
+ # of module +module+. Used to promote modules to classes.
+ #--
+ # TODO move to RDoc::NormalClass (I think)
+
+ def self.from_module class_type, mod
+ klass = class_type.new mod.name
+
+ mod.comment_location.each do |comment, location|
+ klass.add_comment comment, location
+ end
+
+ klass.parent = mod.parent
+ klass.section = mod.section
+ klass.viewer = mod.viewer
+
+ klass.attributes.concat mod.attributes
+ klass.method_list.concat mod.method_list
+ klass.aliases.concat mod.aliases
+ klass.external_aliases.concat mod.external_aliases
+ klass.constants.concat mod.constants
+ klass.includes.concat mod.includes
+ klass.extends.concat mod.extends
+
+ klass.methods_hash.update mod.methods_hash
+ klass.constants_hash.update mod.constants_hash
+
+ klass.current_section = mod.current_section
+ klass.in_files.concat mod.in_files
+ klass.sections.concat mod.sections
+ klass.unmatched_alias_lists = mod.unmatched_alias_lists
+ klass.current_section = mod.current_section
+ klass.visibility = mod.visibility
+
+ klass.classes_hash.update mod.classes_hash
+ klass.modules_hash.update mod.modules_hash
+ klass.metadata.update mod.metadata
+
+ klass.document_self = mod.received_nodoc ? nil : mod.document_self
+ klass.document_children = mod.document_children
+ klass.force_documentation = mod.force_documentation
+ klass.done_documenting = mod.done_documenting
+
+ # update the parent of all children
+
+ (klass.attributes +
+ klass.method_list +
+ klass.aliases +
+ klass.external_aliases +
+ klass.constants +
+ klass.includes +
+ klass.extends +
+ klass.classes +
+ klass.modules).each do |obj|
+ obj.parent = klass
+ obj.full_name = nil
+ end
+
+ klass
+ end
+
+ ##
+ # Creates a new ClassModule with +name+ with optional +superclass+
+ #
+ # This is a constructor for subclasses, and must never be called directly.
+
+ def initialize(name, superclass = nil)
+ @constant_aliases = []
+ @diagram = nil
+ @is_alias_for = nil
+ @name = name
+ @superclass = superclass
+ @comment_location = [] # [[comment, location]]
+
+ super()
+ end
+
+ ##
+ # Adds +comment+ to this ClassModule's list of comments at +location+. This
+ # method is preferred over #comment= since it allows ri data to be updated
+ # across multiple runs.
+
+ def add_comment comment, location
+ return unless document_self
+
+ original = comment
+
+ comment = case comment
+ when RDoc::Comment then
+ comment.normalize
+ else
+ normalize_comment comment
+ end
+
+ if location.parser == RDoc::Parser::C
+ @comment_location.delete_if { |(_, l)| l == location }
+ end
+
+ @comment_location << [comment, location]
+
+ self.comment = original
+ end
+
+ def add_things my_things, other_things # :nodoc:
+ other_things.each do |group, things|
+ my_things[group].each { |thing| yield false, thing } if
+ my_things.include? group
+
+ things.each do |thing|
+ yield true, thing
+ end
+ end
+ end
+
+ ##
+ # Ancestors list for this ClassModule: the list of included modules
+ # (classes will add their superclass if any).
+ #
+ # Returns the included classes or modules, not the includes
+ # themselves. The returned values are either String or
+ # RDoc::NormalModule instances (see RDoc::Include#module).
+ #
+ # The values are returned in reverse order of their inclusion,
+ # which is the order suitable for searching methods/attributes
+ # in the ancestors. The superclass, if any, comes last.
+
+ def ancestors
+ includes.map { |i| i.module }.reverse
+ end
+
+ def aref_prefix # :nodoc:
+ raise NotImplementedError, "missing aref_prefix for #{self.class}"
+ end
+
+ ##
+ # HTML fragment reference for this module or class. See
+ # RDoc::NormalClass#aref and RDoc::NormalModule#aref
+
+ def aref
+ "#{aref_prefix}-#{full_name}"
+ end
+
+ ##
+ # Ancestors of this class or module only
+
+ alias direct_ancestors ancestors
+
+ ##
+ # Clears the comment. Used by the Ruby parser.
+
+ def clear_comment
+ @comment = ''
+ end
+
+ ##
+ # This method is deprecated, use #add_comment instead.
+ #
+ # Appends +comment+ to the current comment, but separated by a rule. Works
+ # more like <tt>+=</tt>.
+
+ def comment= comment # :nodoc:
+ comment = case comment
+ when RDoc::Comment then
+ comment.normalize
+ else
+ normalize_comment comment
+ end
+
+ comment = "#{@comment.to_s}\n---\n#{comment.to_s}" unless @comment.empty?
+
+ super comment
+ end
+
+ ##
+ # Prepares this ClassModule for use by a generator.
+ #
+ # See RDoc::Store#complete
+
+ def complete min_visibility
+ update_aliases
+ remove_nodoc_children
+ update_includes
+ remove_invisible min_visibility
+ end
+
+ ##
+ # Does this ClassModule or any of its methods have document_self set?
+
+ def document_self_or_methods
+ document_self || method_list.any?{ |m| m.document_self }
+ end
+
+ ##
+ # Does this class or module have a comment with content or is
+ # #received_nodoc true?
+
+ def documented?
+ return true if @received_nodoc
+ return false if @comment_location.empty?
+ @comment_location.any? { |comment, _| not comment.empty? }
+ end
+
+ ##
+ # Iterates the ancestors of this class or module for which an
+ # RDoc::ClassModule exists.
+
+ def each_ancestor # :yields: module
+ return enum_for __method__ unless block_given?
+
+ ancestors.each do |mod|
+ next if String === mod
+ next if self == mod
+ yield mod
+ end
+ end
+
+ ##
+ # Looks for a symbol in the #ancestors. See Context#find_local_symbol.
+
+ def find_ancestor_local_symbol symbol
+ each_ancestor do |m|
+ res = m.find_local_symbol(symbol)
+ return res if res
+ end
+
+ nil
+ end
+
+ ##
+ # Finds a class or module with +name+ in this namespace or its descendants
+
+ def find_class_named name
+ return self if full_name == name
+ return self if @name == name
+
+ @classes.values.find do |klass|
+ next if klass == self
+ klass.find_class_named name
+ end
+ end
+
+ ##
+ # Return the fully qualified name of this class or module
+
+ def full_name
+ @full_name ||= if RDoc::ClassModule === parent then
+ "#{parent.full_name}::#{@name}"
+ else
+ @name
+ end
+ end
+
+ ##
+ # TODO: filter included items by #display?
+
+ def marshal_dump # :nodoc:
+ attrs = attributes.sort.map do |attr|
+ next unless attr.display?
+ [ attr.name, attr.rw,
+ attr.visibility, attr.singleton, attr.file_name,
+ ]
+ end.compact
+
+ method_types = methods_by_type.map do |type, visibilities|
+ visibilities = visibilities.map do |visibility, methods|
+ method_names = methods.map do |method|
+ next unless method.display?
+ [method.name, method.file_name]
+ end.compact
+
+ [visibility, method_names.uniq]
+ end
+
+ [type, visibilities]
+ end
+
+ [ MARSHAL_VERSION,
+ @name,
+ full_name,
+ @superclass,
+ parse(@comment_location),
+ attrs,
+ constants.select { |constant| constant.display? },
+ includes.map do |incl|
+ next unless incl.display?
+ [incl.name, parse(incl.comment), incl.file_name]
+ end.compact,
+ method_types,
+ extends.map do |ext|
+ next unless ext.display?
+ [ext.name, parse(ext.comment), ext.file_name]
+ end.compact,
+ @sections.values,
+ @in_files.map do |tl|
+ tl.relative_name
+ end,
+ parent.full_name,
+ parent.class,
+ ]
+ end
+
+ def marshal_load array # :nodoc:
+ initialize_visibility
+ initialize_methods_etc
+ @current_section = nil
+ @document_self = true
+ @done_documenting = false
+ @parent = nil
+ @temporary_section = nil
+ @visibility = nil
+ @classes = {}
+ @modules = {}
+
+ @name = array[1]
+ @full_name = array[2]
+ @superclass = array[3]
+ @comment = array[4]
+
+ @comment_location = if RDoc::Markup::Document === @comment.parts.first then
+ @comment
+ else
+ RDoc::Markup::Document.new @comment
+ end
+
+ array[5].each do |name, rw, visibility, singleton, file|
+ singleton ||= false
+ visibility ||= :public
+
+ attr = RDoc::Attr.new nil, name, rw, nil, singleton
+
+ add_attribute attr
+ attr.visibility = visibility
+ attr.record_location RDoc::TopLevel.new file
+ end
+
+ array[6].each do |constant, comment, file|
+ case constant
+ when RDoc::Constant then
+ add_constant constant
+ else
+ constant = add_constant RDoc::Constant.new(constant, nil, comment)
+ constant.record_location RDoc::TopLevel.new file
+ end
+ end
+
+ array[7].each do |name, comment, file|
+ incl = add_include RDoc::Include.new(name, comment)
+ incl.record_location RDoc::TopLevel.new file
+ end
+
+ array[8].each do |type, visibilities|
+ visibilities.each do |visibility, methods|
+ @visibility = visibility
+
+ methods.each do |name, file|
+ method = RDoc::AnyMethod.new nil, name
+ method.singleton = true if type == 'class'
+ method.record_location RDoc::TopLevel.new file
+ add_method method
+ end
+ end
+ end
+
+ array[9].each do |name, comment, file|
+ ext = add_extend RDoc::Extend.new(name, comment)
+ ext.record_location RDoc::TopLevel.new file
+ end if array[9] # Support Marshal version 1
+
+ sections = (array[10] || []).map do |section|
+ [section.title, section]
+ end
+
+ @sections = Hash[*sections.flatten]
+ @current_section = add_section nil
+
+ @in_files = []
+
+ (array[11] || []).each do |filename|
+ record_location RDoc::TopLevel.new filename
+ end
+
+ @parent_name = array[12]
+ @parent_class = array[13]
+ end
+
+ ##
+ # Merges +class_module+ into this ClassModule.
+ #
+ # The data in +class_module+ is preferred over the receiver.
+
+ def merge class_module
+ @parent = class_module.parent
+ @parent_name = class_module.parent_name
+
+ other_document = parse class_module.comment_location
+
+ if other_document then
+ document = parse @comment_location
+
+ document = document.merge other_document
+
+ @comment = @comment_location = document
+ end
+
+ cm = class_module
+ other_files = cm.in_files
+
+ merge_collections attributes, cm.attributes, other_files do |add, attr|
+ if add then
+ add_attribute attr
+ else
+ @attributes.delete attr
+ @methods_hash.delete attr.pretty_name
+ end
+ end
+
+ merge_collections constants, cm.constants, other_files do |add, const|
+ if add then
+ add_constant const
+ else
+ @constants.delete const
+ @constants_hash.delete const.name
+ end
+ end
+
+ merge_collections includes, cm.includes, other_files do |add, incl|
+ if add then
+ add_include incl
+ else
+ @includes.delete incl
+ end
+ end
+
+ @includes.uniq! # clean up
+
+ merge_collections extends, cm.extends, other_files do |add, ext|
+ if add then
+ add_extend ext
+ else
+ @extends.delete ext
+ end
+ end
+
+ @extends.uniq! # clean up
+
+ merge_collections method_list, cm.method_list, other_files do |add, meth|
+ if add then
+ add_method meth
+ else
+ @method_list.delete meth
+ @methods_hash.delete meth.pretty_name
+ end
+ end
+
+ merge_sections cm
+
+ self
+ end
+
+ ##
+ # Merges collection +mine+ with +other+ preferring other. +other_files+ is
+ # used to help determine which items should be deleted.
+ #
+ # Yields whether the item should be added or removed (true or false) and the
+ # item to be added or removed.
+ #
+ # merge_collections things, other.things, other.in_files do |add, thing|
+ # if add then
+ # # add the thing
+ # else
+ # # remove the thing
+ # end
+ # end
+
+ def merge_collections mine, other, other_files, &block # :nodoc:
+ my_things = mine. group_by { |thing| thing.file }
+ other_things = other.group_by { |thing| thing.file }
+
+ remove_things my_things, other_files, &block
+ add_things my_things, other_things, &block
+ end
+
+ ##
+ # Merges the comments in this ClassModule with the comments in the other
+ # ClassModule +cm+.
+
+ def merge_sections cm # :nodoc:
+ my_sections = sections.group_by { |section| section.title }
+ other_sections = cm.sections.group_by { |section| section.title }
+
+ other_files = cm.in_files
+
+ remove_things my_sections, other_files do |_, section|
+ @sections.delete section.title
+ end
+
+ other_sections.each do |group, sections|
+ if my_sections.include? group
+ my_sections[group].each do |my_section|
+ other_section = cm.sections_hash[group]
+
+ my_comments = my_section.comments
+ other_comments = other_section.comments
+
+ other_files = other_section.in_files
+
+ merge_collections my_comments, other_comments, other_files do |add, comment|
+ if add then
+ my_section.add_comment comment
+ else
+ my_section.remove_comment comment
+ end
+ end
+ end
+ else
+ sections.each do |section|
+ add_section group, section.comments
+ end
+ end
+ end
+ end
+
+ ##
+ # Does this object represent a module?
+
+ def module?
+ false
+ end
+
+ ##
+ # Allows overriding the initial name.
+ #
+ # Used for modules and classes that are constant aliases.
+
+ def name= new_name
+ @name = new_name
+ end
+
+ ##
+ # Parses +comment_location+ into an RDoc::Markup::Document composed of
+ # multiple RDoc::Markup::Documents with their file set.
+
+ def parse comment_location
+ case comment_location
+ when String then
+ super
+ when Array then
+ docs = comment_location.map do |comment, location|
+ doc = super comment
+ doc.file = location
+ doc
+ end
+
+ RDoc::Markup::Document.new(*docs)
+ when RDoc::Comment then
+ doc = super comment_location.text, comment_location.format
+ doc.file = comment_location.location
+ doc
+ when RDoc::Markup::Document then
+ return comment_location
+ else
+ raise ArgumentError, "unknown comment class #{comment_location.class}"
+ end
+ end
+
+ ##
+ # Path to this class or module for use with HTML generator output.
+
+ def path
+ http_url @store.rdoc.generator.class_dir
+ end
+
+ ##
+ # Name to use to generate the url:
+ # modules and classes that are aliases for another
+ # module or class return the name of the latter.
+
+ def name_for_path
+ is_alias_for ? is_alias_for.full_name : full_name
+ end
+
+ ##
+ # Returns the classes and modules that are not constants
+ # aliasing another class or module. For use by formatters
+ # only (caches its result).
+
+ def non_aliases
+ @non_aliases ||= classes_and_modules.reject { |cm| cm.is_alias_for }
+ end
+
+ ##
+ # Updates the child modules or classes of class/module +parent+ by
+ # deleting the ones that have been removed from the documentation.
+ #
+ # +parent_hash+ is either <tt>parent.modules_hash</tt> or
+ # <tt>parent.classes_hash</tt> and +all_hash+ is ::all_modules_hash or
+ # ::all_classes_hash.
+
+ def remove_nodoc_children
+ prefix = self.full_name + '::'
+
+ modules_hash.each_key do |name|
+ full_name = prefix + name
+ modules_hash.delete name unless @store.modules_hash[full_name]
+ end
+
+ classes_hash.each_key do |name|
+ full_name = prefix + name
+ classes_hash.delete name unless @store.classes_hash[full_name]
+ end
+ end
+
+ def remove_things my_things, other_files # :nodoc:
+ my_things.delete_if do |file, things|
+ next false unless other_files.include? file
+
+ things.each do |thing|
+ yield false, thing
+ end
+
+ true
+ end
+ end
+
+ ##
+ # Search record used by RDoc::Generator::JsonIndex
+
+ def search_record
+ [
+ name,
+ full_name,
+ full_name,
+ '',
+ path,
+ '',
+ snippet(@comment_location),
+ ]
+ end
+
+ ##
+ # Sets the store for this class or module and its contained code objects.
+
+ def store= store
+ super
+
+ @attributes .each do |attr| attr.store = store end
+ @constants .each do |const| const.store = store end
+ @includes .each do |incl| incl.store = store end
+ @extends .each do |ext| ext.store = store end
+ @method_list.each do |meth| meth.store = store end
+ end
+
+ ##
+ # Get the superclass of this class. Attempts to retrieve the superclass
+ # object, returns the name if it is not known.
+
+ def superclass
+ @store.find_class_named(@superclass) || @superclass
+ end
+
+ ##
+ # Set the superclass of this class to +superclass+
+
+ def superclass=(superclass)
+ raise NoMethodError, "#{full_name} is a module" if module?
+ @superclass = superclass
+ end
+
+ def to_s # :nodoc:
+ if is_alias_for then
+ "#{self.class.name} #{self.full_name} -> #{is_alias_for}"
+ else
+ super
+ end
+ end
+
+ ##
+ # 'module' or 'class'
+
+ def type
+ module? ? 'module' : 'class'
+ end
+
+ ##
+ # Updates the child modules & classes by replacing the ones that are
+ # aliases through a constant.
+ #
+ # The aliased module/class is replaced in the children and in
+ # RDoc::Store#modules_hash or RDoc::Store#classes_hash
+ # by a copy that has <tt>RDoc::ClassModule#is_alias_for</tt> set to
+ # the aliased module/class, and this copy is added to <tt>#aliases</tt>
+ # of the aliased module/class.
+ #
+ # Formatters can use the #non_aliases method to retrieve children that
+ # are not aliases, for instance to list the namespace content, since
+ # the aliased modules are included in the constants of the class/module,
+ # that are listed separately.
+
+ def update_aliases
+ constants.each do |const|
+ next unless cm = const.is_alias_for
+ cm_alias = cm.dup
+ cm_alias.name = const.name
+
+ # Don't move top-level aliases under Object, they look ugly there
+ unless RDoc::TopLevel === cm_alias.parent then
+ cm_alias.parent = self
+ cm_alias.full_name = nil # force update for new parent
+ end
+
+ cm_alias.aliases.clear
+ cm_alias.is_alias_for = cm
+
+ if cm.module? then
+ @store.modules_hash[cm_alias.full_name] = cm_alias
+ modules_hash[const.name] = cm_alias
+ else
+ @store.classes_hash[cm_alias.full_name] = cm_alias
+ classes_hash[const.name] = cm_alias
+ end
+
+ cm.aliases << cm_alias
+ end
+ end
+
+ ##
+ # Deletes from #includes those whose module has been removed from the
+ # documentation.
+ #--
+ # FIXME: includes are not reliably removed, see _possible_bug test case
+
+ def update_includes
+ includes.reject! do |include|
+ mod = include.module
+ !(String === mod) && @store.modules_hash[mod.full_name].nil?
+ end
+
+ includes.uniq!
+ end
+
+ ##
+ # Deletes from #extends those whose module has been removed from the
+ # documentation.
+ #--
+ # FIXME: like update_includes, extends are not reliably removed
+
+ def update_extends
+ extends.reject! do |ext|
+ mod = ext.module
+
+ !(String === mod) && @store.modules_hash[mod.full_name].nil?
+ end
+
+ extends.uniq!
+ end
+
+end
+
diff --git a/lib/rdoc/code_object/alias.rb b/lib/rdoc/code_object/alias.rb
deleted file mode 100644
index 92df7e448f..0000000000
--- a/lib/rdoc/code_object/alias.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-# frozen_string_literal: true
-##
-# Represent an alias, which is an old_name/new_name pair associated with a
-# particular context
-#--
-# TODO implement Alias as a proxy to a method/attribute, inheriting from
-# MethodAttr
-
-class RDoc::Alias < RDoc::CodeObject
-
- ##
- # Aliased method's name
-
- attr_reader :new_name
-
- alias name new_name
-
- ##
- # Aliasee method's name
-
- attr_reader :old_name
-
- ##
- # Is this an alias declared in a singleton context?
-
- attr_accessor :singleton
-
- ##
- # Source file token stream
-
- attr_reader :text
-
- ##
- # Creates a new Alias with a token stream of +text+ that aliases +old_name+
- # to +new_name+, has +comment+ and is a +singleton+ context.
-
- def initialize(text, old_name, new_name, comment, singleton = false)
- super()
-
- @text = text
- @singleton = singleton
- @old_name = old_name
- @new_name = new_name
- self.comment = comment
- end
-
- ##
- # Order by #singleton then #new_name
-
- def <=>(other)
- [@singleton ? 0 : 1, new_name] <=> [other.singleton ? 0 : 1, other.new_name]
- end
-
- ##
- # HTML fragment reference for this alias
-
- def aref
- type = singleton ? 'c' : 'i'
- "#alias-#{type}-#{html_name}"
- end
-
- ##
- # Full old name including namespace
-
- def full_old_name
- @full_name || "#{parent.name}#{pretty_old_name}"
- end
-
- ##
- # HTML id-friendly version of +#new_name+.
-
- def html_name
- CGI.escape(@new_name.gsub('-', '-2D')).gsub('%', '-').sub(/^-/, '')
- end
-
- def inspect # :nodoc:
- parent_name = parent ? parent.name : '(unknown)'
- "#<%s:0x%x %s.alias_method %s, %s>" % [
- self.class, object_id,
- parent_name, @old_name, @new_name,
- ]
- end
-
- ##
- # '::' for the alias of a singleton method/attribute, '#' for instance-level.
-
- def name_prefix
- singleton ? '::' : '#'
- end
-
- ##
- # Old name with prefix '::' or '#'.
-
- def pretty_old_name
- "#{singleton ? '::' : '#'}#{@old_name}"
- end
-
- ##
- # New name with prefix '::' or '#'.
-
- def pretty_new_name
- "#{singleton ? '::' : '#'}#{@new_name}"
- end
-
- alias pretty_name pretty_new_name
-
- def to_s # :nodoc:
- "alias: #{self.new_name} -> #{self.pretty_old_name} in: #{parent}"
- end
-
-end
diff --git a/lib/rdoc/code_object/anon_class.rb b/lib/rdoc/code_object/anon_class.rb
deleted file mode 100644
index 3c2f0e1877..0000000000
--- a/lib/rdoc/code_object/anon_class.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# frozen_string_literal: true
-##
-# An anonymous class like:
-#
-# c = Class.new do end
-#
-# AnonClass is currently not used.
-
-class RDoc::AnonClass < RDoc::ClassModule
-end
diff --git a/lib/rdoc/code_object/any_method.rb b/lib/rdoc/code_object/any_method.rb
deleted file mode 100644
index 465c4a4fb2..0000000000
--- a/lib/rdoc/code_object/any_method.rb
+++ /dev/null
@@ -1,379 +0,0 @@
-# frozen_string_literal: true
-##
-# AnyMethod is the base class for objects representing methods
-
-class RDoc::AnyMethod < RDoc::MethodAttr
-
- ##
- # 2::
- # RDoc 4
- # Added calls_super
- # Added parent name and class
- # Added section title
- # 3::
- # RDoc 4.1
- # Added is_alias_for
-
- MARSHAL_VERSION = 3 # :nodoc:
-
- ##
- # Don't rename \#initialize to \::new
-
- attr_accessor :dont_rename_initialize
-
- ##
- # The C function that implements this method (if it was defined in a C file)
-
- attr_accessor :c_function
-
- # The section title of the method (if defined in a C file via +:category:+)
- attr_accessor :section_title
-
- # Parameters for this method
-
- attr_accessor :params
-
- ##
- # If true this method uses +super+ to call a superclass version
-
- attr_accessor :calls_super
-
- include RDoc::TokenStream
-
- ##
- # Creates a new AnyMethod with a token stream +text+ and +name+
-
- def initialize text, name
- super
-
- @c_function = nil
- @dont_rename_initialize = false
- @token_stream = nil
- @calls_super = false
- @superclass_method = nil
- end
-
- ##
- # Adds +an_alias+ as an alias for this method in +context+.
-
- def add_alias an_alias, context = nil
- method = self.class.new an_alias.text, an_alias.new_name
-
- method.record_location an_alias.file
- method.singleton = self.singleton
- method.params = self.params
- method.visibility = self.visibility
- method.comment = an_alias.comment
- method.is_alias_for = self
- @aliases << method
- context.add_method method if context
- method
- end
-
- ##
- # Prefix for +aref+ is 'method'.
-
- def aref_prefix
- 'method'
- end
-
- ##
- # The call_seq or the param_seq with method name, if there is no call_seq.
- #
- # Use this for displaying a method's argument lists.
-
- def arglists
- if @call_seq then
- @call_seq
- elsif @params then
- "#{name}#{param_seq}"
- end
- end
-
- ##
- # Different ways to call this method
-
- def call_seq
- unless call_seq = _call_seq
- call_seq = is_alias_for._call_seq if is_alias_for
- end
-
- return unless call_seq
-
- deduplicate_call_seq(call_seq)
- end
-
- ##
- # Sets the different ways you can call this method. If an empty +call_seq+
- # is given nil is assumed.
- #
- # See also #param_seq
-
- def call_seq= call_seq
- return if call_seq.empty?
-
- @call_seq = call_seq
- end
-
- ##
- # Whether the method has a call-seq.
-
- def has_call_seq?
- !!(@call_seq || is_alias_for&._call_seq)
- end
-
- ##
- # Loads is_alias_for from the internal name. Returns nil if the alias
- # cannot be found.
-
- def is_alias_for # :nodoc:
- case @is_alias_for
- when RDoc::MethodAttr then
- @is_alias_for
- when Array then
- return nil unless @store
-
- klass_name, singleton, method_name = @is_alias_for
-
- return nil unless klass = @store.find_class_or_module(klass_name)
-
- @is_alias_for = klass.find_method method_name, singleton
- end
- end
-
- ##
- # Dumps this AnyMethod for use by ri. See also #marshal_load
-
- def marshal_dump
- aliases = @aliases.map do |a|
- [a.name, parse(a.comment)]
- end
-
- is_alias_for = [
- @is_alias_for.parent.full_name,
- @is_alias_for.singleton,
- @is_alias_for.name
- ] if @is_alias_for
-
- [ MARSHAL_VERSION,
- @name,
- full_name,
- @singleton,
- @visibility,
- parse(@comment),
- @call_seq,
- @block_params,
- aliases,
- @params,
- @file.relative_name,
- @calls_super,
- @parent.name,
- @parent.class,
- @section.title,
- is_alias_for,
- ]
- end
-
- ##
- # Loads this AnyMethod from +array+. For a loaded AnyMethod the following
- # methods will return cached values:
- #
- # * #full_name
- # * #parent_name
-
- def marshal_load array
- initialize_visibility
-
- @dont_rename_initialize = nil
- @token_stream = nil
- @aliases = []
- @parent = nil
- @parent_name = nil
- @parent_class = nil
- @section = nil
- @file = nil
-
- version = array[0]
- @name = array[1]
- @full_name = array[2]
- @singleton = array[3]
- @visibility = array[4]
- @comment = array[5]
- @call_seq = array[6]
- @block_params = array[7]
- # 8 handled below
- @params = array[9]
- # 10 handled below
- @calls_super = array[11]
- @parent_name = array[12]
- @parent_title = array[13]
- @section_title = array[14]
- @is_alias_for = array[15]
-
- array[8].each do |new_name, comment|
- add_alias RDoc::Alias.new(nil, @name, new_name, comment, @singleton)
- end
-
- @parent_name ||= if @full_name =~ /#/ then
- $`
- else
- name = @full_name.split('::')
- name.pop
- name.join '::'
- end
-
- @file = RDoc::TopLevel.new array[10] if version > 0
- end
-
- ##
- # Method name
- #
- # If the method has no assigned name, it extracts it from #call_seq.
-
- def name
- return @name if @name
-
- @name =
- @call_seq[/^.*?\.(\w+)/, 1] ||
- @call_seq[/^.*?(\w+)/, 1] ||
- @call_seq if @call_seq
- end
-
- ##
- # A list of this method's method and yield parameters. +call-seq+ params
- # are preferred over parsed method and block params.
-
- def param_list
- if @call_seq then
- params = @call_seq.split("\n").last
- params = params.sub(/.*?\((.*)\)/, '\1')
- params = params.sub(/(\{|do)\s*\|([^|]*)\|.*/, ',\2')
- elsif @params then
- params = @params.sub(/\((.*)\)/, '\1')
-
- params << ",#{@block_params}" if @block_params
- elsif @block_params then
- params = @block_params
- else
- return []
- end
-
- if @block_params then
- # If this method has explicit block parameters, remove any explicit
- # &block
- params = params.sub(/,?\s*&\w+/, '')
- else
- params = params.sub(/\&(\w+)/, '\1')
- end
-
- params = params.gsub(/\s+/, '').split(',').reject(&:empty?)
-
- params.map { |param| param.sub(/=.*/, '') }
- end
-
- ##
- # Pretty parameter list for this method. If the method's parameters were
- # given by +call-seq+ it is preferred over the parsed values.
-
- def param_seq
- if @call_seq then
- params = @call_seq.split("\n").last
- params = params.sub(/[^( ]+/, '')
- params = params.sub(/(\|[^|]+\|)\s*\.\.\.\s*(end|\})/, '\1 \2')
- elsif @params then
- params = @params.gsub(/\s*\#.*/, '')
- params = params.tr_s("\n ", " ")
- params = "(#{params})" unless params[0] == ?(
- else
- params = ''
- end
-
- if @block_params then
- # If this method has explicit block parameters, remove any explicit
- # &block
- params = params.sub(/,?\s*&\w+/, '')
-
- block = @block_params.tr_s("\n ", " ")
- if block[0] == ?(
- block = block.sub(/^\(/, '').sub(/\)/, '')
- end
- params << " { |#{block}| ... }"
- end
-
- params
- end
-
- ##
- # Whether to skip the method description, true for methods that have
- # aliases with a call-seq that doesn't include the method name.
-
- def skip_description?
- has_call_seq? && call_seq.nil? && !!(is_alias_for || !aliases.empty?)
- end
-
- ##
- # Sets the store for this method and its referenced code objects.
-
- def store= store
- super
-
- @file = @store.add_file @file.full_name if @file
- end
-
- ##
- # For methods that +super+, find the superclass method that would be called.
-
- def superclass_method
- return unless @calls_super
- return @superclass_method if @superclass_method
-
- parent.each_ancestor do |ancestor|
- if method = ancestor.method_list.find { |m| m.name == @name } then
- @superclass_method = method
- break
- end
- end
-
- @superclass_method
- end
-
- protected
-
- ##
- # call_seq without deduplication and alias lookup.
-
- def _call_seq
- @call_seq if defined?(@call_seq) && @call_seq
- end
-
- private
-
- ##
- # call_seq with alias examples information removed, if this
- # method is an alias method.
-
- def deduplicate_call_seq(call_seq)
- return call_seq unless is_alias_for || !aliases.empty?
-
- method_name = self.name
- method_name = method_name[0, 1] if method_name =~ /\A\[/
-
- entries = call_seq.split "\n"
-
- ignore = aliases.map(&:name)
- if is_alias_for
- ignore << is_alias_for.name
- ignore.concat is_alias_for.aliases.map(&:name)
- end
- ignore.map! { |n| n =~ /\A\[/ ? /\[.*\]/ : n}
- ignore.delete(method_name)
- ignore = Regexp.union(ignore)
-
- matching = entries.reject do |entry|
- entry =~ /^\w*\.?#{ignore}[$\(\s]/ or
- entry =~ /\s#{ignore}\s/
- end
-
- matching.empty? ? nil : matching.join("\n")
- end
-end
diff --git a/lib/rdoc/code_object/attr.rb b/lib/rdoc/code_object/attr.rb
deleted file mode 100644
index a403235933..0000000000
--- a/lib/rdoc/code_object/attr.rb
+++ /dev/null
@@ -1,175 +0,0 @@
-# frozen_string_literal: true
-##
-# An attribute created by \#attr, \#attr_reader, \#attr_writer or
-# \#attr_accessor
-
-class RDoc::Attr < RDoc::MethodAttr
-
- ##
- # 3::
- # RDoc 4
- # Added parent name and class
- # Added section title
-
- MARSHAL_VERSION = 3 # :nodoc:
-
- ##
- # Is the attribute readable ('R'), writable ('W') or both ('RW')?
-
- attr_accessor :rw
-
- ##
- # Creates a new Attr with body +text+, +name+, read/write status +rw+ and
- # +comment+. +singleton+ marks this as a class attribute.
-
- def initialize(text, name, rw, comment, singleton = false)
- super text, name
-
- @rw = rw
- @singleton = singleton
- self.comment = comment
- end
-
- ##
- # Attributes are equal when their names, singleton and rw are identical
-
- def == other
- self.class == other.class and
- self.name == other.name and
- self.rw == other.rw and
- self.singleton == other.singleton
- end
-
- ##
- # Add +an_alias+ as an attribute in +context+.
-
- def add_alias(an_alias, context)
- new_attr = self.class.new(self.text, an_alias.new_name, self.rw,
- self.comment, self.singleton)
-
- new_attr.record_location an_alias.file
- new_attr.visibility = self.visibility
- new_attr.is_alias_for = self
- @aliases << new_attr
- context.add_attribute new_attr
- new_attr
- end
-
- ##
- # The #aref prefix for attributes
-
- def aref_prefix
- 'attribute'
- end
-
- ##
- # Attributes never call super. See RDoc::AnyMethod#calls_super
- #
- # An RDoc::Attr can show up in the method list in some situations (see
- # Gem::ConfigFile)
-
- def calls_super # :nodoc:
- false
- end
-
- ##
- # Returns attr_reader, attr_writer or attr_accessor as appropriate.
-
- def definition
- case @rw
- when 'RW' then 'attr_accessor'
- when 'R' then 'attr_reader'
- when 'W' then 'attr_writer'
- end
- end
-
- def inspect # :nodoc:
- alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
- visibility = self.visibility
- visibility = "forced #{visibility}" if force_documentation
- "#<%s:0x%x %s %s (%s)%s>" % [
- self.class, object_id,
- full_name,
- rw,
- visibility,
- alias_for,
- ]
- end
-
- ##
- # Dumps this Attr for use by ri. See also #marshal_load
-
- def marshal_dump
- [ MARSHAL_VERSION,
- @name,
- full_name,
- @rw,
- @visibility,
- parse(@comment),
- singleton,
- @file.relative_name,
- @parent.full_name,
- @parent.class,
- @section.title
- ]
- end
-
- ##
- # Loads this Attr from +array+. For a loaded Attr the following
- # methods will return cached values:
- #
- # * #full_name
- # * #parent_name
-
- def marshal_load array
- initialize_visibility
-
- @aliases = []
- @parent = nil
- @parent_name = nil
- @parent_class = nil
- @section = nil
- @file = nil
-
- version = array[0]
- @name = array[1]
- @full_name = array[2]
- @rw = array[3]
- @visibility = array[4]
- @comment = array[5]
- @singleton = array[6] || false # MARSHAL_VERSION == 0
- # 7 handled below
- @parent_name = array[8]
- @parent_class = array[9]
- @section_title = array[10]
-
- @file = RDoc::TopLevel.new array[7] if version > 1
-
- @parent_name ||= @full_name.split('#', 2).first
- end
-
- def pretty_print q # :nodoc:
- q.group 2, "[#{self.class.name} #{full_name} #{rw} #{visibility}", "]" do
- unless comment.empty? then
- q.breakable
- q.text "comment:"
- q.breakable
- q.pp @comment
- end
- end
- end
-
- def to_s # :nodoc:
- "#{definition} #{name} in: #{parent}"
- end
-
- ##
- # Attributes do not have token streams.
- #
- # An RDoc::Attr can show up in the method list in some situations (see
- # Gem::ConfigFile)
-
- def token_stream # :nodoc:
- end
-
-end
diff --git a/lib/rdoc/code_object/class_module.rb b/lib/rdoc/code_object/class_module.rb
deleted file mode 100644
index c69e14b5e4..0000000000
--- a/lib/rdoc/code_object/class_module.rb
+++ /dev/null
@@ -1,801 +0,0 @@
-# frozen_string_literal: true
-##
-# ClassModule is the base class for objects representing either a class or a
-# module.
-
-class RDoc::ClassModule < RDoc::Context
-
- ##
- # 1::
- # RDoc 3.7
- # * Added visibility, singleton and file to attributes
- # * Added file to constants
- # * Added file to includes
- # * Added file to methods
- # 2::
- # RDoc 3.13
- # * Added extends
- # 3::
- # RDoc 4.0
- # * Added sections
- # * Added in_files
- # * Added parent name
- # * Complete Constant dump
-
- MARSHAL_VERSION = 3 # :nodoc:
-
- ##
- # Constants that are aliases for this class or module
-
- attr_accessor :constant_aliases
-
- ##
- # Comment and the location it came from. Use #add_comment to add comments
-
- attr_accessor :comment_location
-
- attr_accessor :diagram # :nodoc:
-
- ##
- # Class or module this constant is an alias for
-
- attr_accessor :is_alias_for
-
- ##
- # Return a RDoc::ClassModule of class +class_type+ that is a copy
- # of module +module+. Used to promote modules to classes.
- #--
- # TODO move to RDoc::NormalClass (I think)
-
- def self.from_module class_type, mod
- klass = class_type.new mod.name
-
- mod.comment_location.each do |comment, location|
- klass.add_comment comment, location
- end
-
- klass.parent = mod.parent
- klass.section = mod.section
- klass.viewer = mod.viewer
-
- klass.attributes.concat mod.attributes
- klass.method_list.concat mod.method_list
- klass.aliases.concat mod.aliases
- klass.external_aliases.concat mod.external_aliases
- klass.constants.concat mod.constants
- klass.includes.concat mod.includes
- klass.extends.concat mod.extends
-
- klass.methods_hash.update mod.methods_hash
- klass.constants_hash.update mod.constants_hash
-
- klass.current_section = mod.current_section
- klass.in_files.concat mod.in_files
- klass.sections.concat mod.sections
- klass.unmatched_alias_lists = mod.unmatched_alias_lists
- klass.current_section = mod.current_section
- klass.visibility = mod.visibility
-
- klass.classes_hash.update mod.classes_hash
- klass.modules_hash.update mod.modules_hash
- klass.metadata.update mod.metadata
-
- klass.document_self = mod.received_nodoc ? nil : mod.document_self
- klass.document_children = mod.document_children
- klass.force_documentation = mod.force_documentation
- klass.done_documenting = mod.done_documenting
-
- # update the parent of all children
-
- (klass.attributes +
- klass.method_list +
- klass.aliases +
- klass.external_aliases +
- klass.constants +
- klass.includes +
- klass.extends +
- klass.classes +
- klass.modules).each do |obj|
- obj.parent = klass
- obj.full_name = nil
- end
-
- klass
- end
-
- ##
- # Creates a new ClassModule with +name+ with optional +superclass+
- #
- # This is a constructor for subclasses, and must never be called directly.
-
- def initialize(name, superclass = nil)
- @constant_aliases = []
- @diagram = nil
- @is_alias_for = nil
- @name = name
- @superclass = superclass
- @comment_location = [] # [[comment, location]]
-
- super()
- end
-
- ##
- # Adds +comment+ to this ClassModule's list of comments at +location+. This
- # method is preferred over #comment= since it allows ri data to be updated
- # across multiple runs.
-
- def add_comment comment, location
- return unless document_self
-
- original = comment
-
- comment = case comment
- when RDoc::Comment then
- comment.normalize
- else
- normalize_comment comment
- end
-
- if location.parser == RDoc::Parser::C
- @comment_location.delete_if { |(_, l)| l == location }
- end
-
- @comment_location << [comment, location]
-
- self.comment = original
- end
-
- def add_things my_things, other_things # :nodoc:
- other_things.each do |group, things|
- my_things[group].each { |thing| yield false, thing } if
- my_things.include? group
-
- things.each do |thing|
- yield true, thing
- end
- end
- end
-
- ##
- # Ancestors list for this ClassModule: the list of included modules
- # (classes will add their superclass if any).
- #
- # Returns the included classes or modules, not the includes
- # themselves. The returned values are either String or
- # RDoc::NormalModule instances (see RDoc::Include#module).
- #
- # The values are returned in reverse order of their inclusion,
- # which is the order suitable for searching methods/attributes
- # in the ancestors. The superclass, if any, comes last.
-
- def ancestors
- includes.map { |i| i.module }.reverse
- end
-
- def aref_prefix # :nodoc:
- raise NotImplementedError, "missing aref_prefix for #{self.class}"
- end
-
- ##
- # HTML fragment reference for this module or class. See
- # RDoc::NormalClass#aref and RDoc::NormalModule#aref
-
- def aref
- "#{aref_prefix}-#{full_name}"
- end
-
- ##
- # Ancestors of this class or module only
-
- alias direct_ancestors ancestors
-
- ##
- # Clears the comment. Used by the Ruby parser.
-
- def clear_comment
- @comment = ''
- end
-
- ##
- # This method is deprecated, use #add_comment instead.
- #
- # Appends +comment+ to the current comment, but separated by a rule. Works
- # more like <tt>+=</tt>.
-
- def comment= comment # :nodoc:
- comment = case comment
- when RDoc::Comment then
- comment.normalize
- else
- normalize_comment comment
- end
-
- comment = "#{@comment.to_s}\n---\n#{comment.to_s}" unless @comment.empty?
-
- super comment
- end
-
- ##
- # Prepares this ClassModule for use by a generator.
- #
- # See RDoc::Store#complete
-
- def complete min_visibility
- update_aliases
- remove_nodoc_children
- update_includes
- remove_invisible min_visibility
- end
-
- ##
- # Does this ClassModule or any of its methods have document_self set?
-
- def document_self_or_methods
- document_self || method_list.any?{ |m| m.document_self }
- end
-
- ##
- # Does this class or module have a comment with content or is
- # #received_nodoc true?
-
- def documented?
- return true if @received_nodoc
- return false if @comment_location.empty?
- @comment_location.any? { |comment, _| not comment.empty? }
- end
-
- ##
- # Iterates the ancestors of this class or module for which an
- # RDoc::ClassModule exists.
-
- def each_ancestor # :yields: module
- return enum_for __method__ unless block_given?
-
- ancestors.each do |mod|
- next if String === mod
- next if self == mod
- yield mod
- end
- end
-
- ##
- # Looks for a symbol in the #ancestors. See Context#find_local_symbol.
-
- def find_ancestor_local_symbol symbol
- each_ancestor do |m|
- res = m.find_local_symbol(symbol)
- return res if res
- end
-
- nil
- end
-
- ##
- # Finds a class or module with +name+ in this namespace or its descendants
-
- def find_class_named name
- return self if full_name == name
- return self if @name == name
-
- @classes.values.find do |klass|
- next if klass == self
- klass.find_class_named name
- end
- end
-
- ##
- # Return the fully qualified name of this class or module
-
- def full_name
- @full_name ||= if RDoc::ClassModule === parent then
- "#{parent.full_name}::#{@name}"
- else
- @name
- end
- end
-
- ##
- # TODO: filter included items by #display?
-
- def marshal_dump # :nodoc:
- attrs = attributes.sort.map do |attr|
- next unless attr.display?
- [ attr.name, attr.rw,
- attr.visibility, attr.singleton, attr.file_name,
- ]
- end.compact
-
- method_types = methods_by_type.map do |type, visibilities|
- visibilities = visibilities.map do |visibility, methods|
- method_names = methods.map do |method|
- next unless method.display?
- [method.name, method.file_name]
- end.compact
-
- [visibility, method_names.uniq]
- end
-
- [type, visibilities]
- end
-
- [ MARSHAL_VERSION,
- @name,
- full_name,
- @superclass,
- parse(@comment_location),
- attrs,
- constants.select { |constant| constant.display? },
- includes.map do |incl|
- next unless incl.display?
- [incl.name, parse(incl.comment), incl.file_name]
- end.compact,
- method_types,
- extends.map do |ext|
- next unless ext.display?
- [ext.name, parse(ext.comment), ext.file_name]
- end.compact,
- @sections.values,
- @in_files.map do |tl|
- tl.relative_name
- end,
- parent.full_name,
- parent.class,
- ]
- end
-
- def marshal_load array # :nodoc:
- initialize_visibility
- initialize_methods_etc
- @current_section = nil
- @document_self = true
- @done_documenting = false
- @parent = nil
- @temporary_section = nil
- @visibility = nil
- @classes = {}
- @modules = {}
-
- @name = array[1]
- @full_name = array[2]
- @superclass = array[3]
- @comment = array[4]
-
- @comment_location = if RDoc::Markup::Document === @comment.parts.first then
- @comment
- else
- RDoc::Markup::Document.new @comment
- end
-
- array[5].each do |name, rw, visibility, singleton, file|
- singleton ||= false
- visibility ||= :public
-
- attr = RDoc::Attr.new nil, name, rw, nil, singleton
-
- add_attribute attr
- attr.visibility = visibility
- attr.record_location RDoc::TopLevel.new file
- end
-
- array[6].each do |constant, comment, file|
- case constant
- when RDoc::Constant then
- add_constant constant
- else
- constant = add_constant RDoc::Constant.new(constant, nil, comment)
- constant.record_location RDoc::TopLevel.new file
- end
- end
-
- array[7].each do |name, comment, file|
- incl = add_include RDoc::Include.new(name, comment)
- incl.record_location RDoc::TopLevel.new file
- end
-
- array[8].each do |type, visibilities|
- visibilities.each do |visibility, methods|
- @visibility = visibility
-
- methods.each do |name, file|
- method = RDoc::AnyMethod.new nil, name
- method.singleton = true if type == 'class'
- method.record_location RDoc::TopLevel.new file
- add_method method
- end
- end
- end
-
- array[9].each do |name, comment, file|
- ext = add_extend RDoc::Extend.new(name, comment)
- ext.record_location RDoc::TopLevel.new file
- end if array[9] # Support Marshal version 1
-
- sections = (array[10] || []).map do |section|
- [section.title, section]
- end
-
- @sections = Hash[*sections.flatten]
- @current_section = add_section nil
-
- @in_files = []
-
- (array[11] || []).each do |filename|
- record_location RDoc::TopLevel.new filename
- end
-
- @parent_name = array[12]
- @parent_class = array[13]
- end
-
- ##
- # Merges +class_module+ into this ClassModule.
- #
- # The data in +class_module+ is preferred over the receiver.
-
- def merge class_module
- @parent = class_module.parent
- @parent_name = class_module.parent_name
-
- other_document = parse class_module.comment_location
-
- if other_document then
- document = parse @comment_location
-
- document = document.merge other_document
-
- @comment = @comment_location = document
- end
-
- cm = class_module
- other_files = cm.in_files
-
- merge_collections attributes, cm.attributes, other_files do |add, attr|
- if add then
- add_attribute attr
- else
- @attributes.delete attr
- @methods_hash.delete attr.pretty_name
- end
- end
-
- merge_collections constants, cm.constants, other_files do |add, const|
- if add then
- add_constant const
- else
- @constants.delete const
- @constants_hash.delete const.name
- end
- end
-
- merge_collections includes, cm.includes, other_files do |add, incl|
- if add then
- add_include incl
- else
- @includes.delete incl
- end
- end
-
- @includes.uniq! # clean up
-
- merge_collections extends, cm.extends, other_files do |add, ext|
- if add then
- add_extend ext
- else
- @extends.delete ext
- end
- end
-
- @extends.uniq! # clean up
-
- merge_collections method_list, cm.method_list, other_files do |add, meth|
- if add then
- add_method meth
- else
- @method_list.delete meth
- @methods_hash.delete meth.pretty_name
- end
- end
-
- merge_sections cm
-
- self
- end
-
- ##
- # Merges collection +mine+ with +other+ preferring other. +other_files+ is
- # used to help determine which items should be deleted.
- #
- # Yields whether the item should be added or removed (true or false) and the
- # item to be added or removed.
- #
- # merge_collections things, other.things, other.in_files do |add, thing|
- # if add then
- # # add the thing
- # else
- # # remove the thing
- # end
- # end
-
- def merge_collections mine, other, other_files, &block # :nodoc:
- my_things = mine. group_by { |thing| thing.file }
- other_things = other.group_by { |thing| thing.file }
-
- remove_things my_things, other_files, &block
- add_things my_things, other_things, &block
- end
-
- ##
- # Merges the comments in this ClassModule with the comments in the other
- # ClassModule +cm+.
-
- def merge_sections cm # :nodoc:
- my_sections = sections.group_by { |section| section.title }
- other_sections = cm.sections.group_by { |section| section.title }
-
- other_files = cm.in_files
-
- remove_things my_sections, other_files do |_, section|
- @sections.delete section.title
- end
-
- other_sections.each do |group, sections|
- if my_sections.include? group
- my_sections[group].each do |my_section|
- other_section = cm.sections_hash[group]
-
- my_comments = my_section.comments
- other_comments = other_section.comments
-
- other_files = other_section.in_files
-
- merge_collections my_comments, other_comments, other_files do |add, comment|
- if add then
- my_section.add_comment comment
- else
- my_section.remove_comment comment
- end
- end
- end
- else
- sections.each do |section|
- add_section group, section.comments
- end
- end
- end
- end
-
- ##
- # Does this object represent a module?
-
- def module?
- false
- end
-
- ##
- # Allows overriding the initial name.
- #
- # Used for modules and classes that are constant aliases.
-
- def name= new_name
- @name = new_name
- end
-
- ##
- # Parses +comment_location+ into an RDoc::Markup::Document composed of
- # multiple RDoc::Markup::Documents with their file set.
-
- def parse comment_location
- case comment_location
- when String then
- super
- when Array then
- docs = comment_location.map do |comment, location|
- doc = super comment
- doc.file = location
- doc
- end
-
- RDoc::Markup::Document.new(*docs)
- when RDoc::Comment then
- doc = super comment_location.text, comment_location.format
- doc.file = comment_location.location
- doc
- when RDoc::Markup::Document then
- return comment_location
- else
- raise ArgumentError, "unknown comment class #{comment_location.class}"
- end
- end
-
- ##
- # Path to this class or module for use with HTML generator output.
-
- def path
- http_url @store.rdoc.generator.class_dir
- end
-
- ##
- # Name to use to generate the url:
- # modules and classes that are aliases for another
- # module or class return the name of the latter.
-
- def name_for_path
- is_alias_for ? is_alias_for.full_name : full_name
- end
-
- ##
- # Returns the classes and modules that are not constants
- # aliasing another class or module. For use by formatters
- # only (caches its result).
-
- def non_aliases
- @non_aliases ||= classes_and_modules.reject { |cm| cm.is_alias_for }
- end
-
- ##
- # Updates the child modules or classes of class/module +parent+ by
- # deleting the ones that have been removed from the documentation.
- #
- # +parent_hash+ is either <tt>parent.modules_hash</tt> or
- # <tt>parent.classes_hash</tt> and +all_hash+ is ::all_modules_hash or
- # ::all_classes_hash.
-
- def remove_nodoc_children
- prefix = self.full_name + '::'
-
- modules_hash.each_key do |name|
- full_name = prefix + name
- modules_hash.delete name unless @store.modules_hash[full_name]
- end
-
- classes_hash.each_key do |name|
- full_name = prefix + name
- classes_hash.delete name unless @store.classes_hash[full_name]
- end
- end
-
- def remove_things my_things, other_files # :nodoc:
- my_things.delete_if do |file, things|
- next false unless other_files.include? file
-
- things.each do |thing|
- yield false, thing
- end
-
- true
- end
- end
-
- ##
- # Search record used by RDoc::Generator::JsonIndex
-
- def search_record
- [
- name,
- full_name,
- full_name,
- '',
- path,
- '',
- snippet(@comment_location),
- ]
- end
-
- ##
- # Sets the store for this class or module and its contained code objects.
-
- def store= store
- super
-
- @attributes .each do |attr| attr.store = store end
- @constants .each do |const| const.store = store end
- @includes .each do |incl| incl.store = store end
- @extends .each do |ext| ext.store = store end
- @method_list.each do |meth| meth.store = store end
- end
-
- ##
- # Get the superclass of this class. Attempts to retrieve the superclass
- # object, returns the name if it is not known.
-
- def superclass
- @store.find_class_named(@superclass) || @superclass
- end
-
- ##
- # Set the superclass of this class to +superclass+
-
- def superclass=(superclass)
- raise NoMethodError, "#{full_name} is a module" if module?
- @superclass = superclass
- end
-
- def to_s # :nodoc:
- if is_alias_for then
- "#{self.class.name} #{self.full_name} -> #{is_alias_for}"
- else
- super
- end
- end
-
- ##
- # 'module' or 'class'
-
- def type
- module? ? 'module' : 'class'
- end
-
- ##
- # Updates the child modules & classes by replacing the ones that are
- # aliases through a constant.
- #
- # The aliased module/class is replaced in the children and in
- # RDoc::Store#modules_hash or RDoc::Store#classes_hash
- # by a copy that has <tt>RDoc::ClassModule#is_alias_for</tt> set to
- # the aliased module/class, and this copy is added to <tt>#aliases</tt>
- # of the aliased module/class.
- #
- # Formatters can use the #non_aliases method to retrieve children that
- # are not aliases, for instance to list the namespace content, since
- # the aliased modules are included in the constants of the class/module,
- # that are listed separately.
-
- def update_aliases
- constants.each do |const|
- next unless cm = const.is_alias_for
- cm_alias = cm.dup
- cm_alias.name = const.name
-
- # Don't move top-level aliases under Object, they look ugly there
- unless RDoc::TopLevel === cm_alias.parent then
- cm_alias.parent = self
- cm_alias.full_name = nil # force update for new parent
- end
-
- cm_alias.aliases.clear
- cm_alias.is_alias_for = cm
-
- if cm.module? then
- @store.modules_hash[cm_alias.full_name] = cm_alias
- modules_hash[const.name] = cm_alias
- else
- @store.classes_hash[cm_alias.full_name] = cm_alias
- classes_hash[const.name] = cm_alias
- end
-
- cm.aliases << cm_alias
- end
- end
-
- ##
- # Deletes from #includes those whose module has been removed from the
- # documentation.
- #--
- # FIXME: includes are not reliably removed, see _possible_bug test case
-
- def update_includes
- includes.reject! do |include|
- mod = include.module
- !(String === mod) && @store.modules_hash[mod.full_name].nil?
- end
-
- includes.uniq!
- end
-
- ##
- # Deletes from #extends those whose module has been removed from the
- # documentation.
- #--
- # FIXME: like update_includes, extends are not reliably removed
-
- def update_extends
- extends.reject! do |ext|
- mod = ext.module
-
- !(String === mod) && @store.modules_hash[mod.full_name].nil?
- end
-
- extends.uniq!
- end
-
-end
diff --git a/lib/rdoc/code_object/constant.rb b/lib/rdoc/code_object/constant.rb
deleted file mode 100644
index 12b8be775c..0000000000
--- a/lib/rdoc/code_object/constant.rb
+++ /dev/null
@@ -1,186 +0,0 @@
-# frozen_string_literal: true
-##
-# A constant
-
-class RDoc::Constant < RDoc::CodeObject
-
- MARSHAL_VERSION = 0 # :nodoc:
-
- ##
- # Sets the module or class this is constant is an alias for.
-
- attr_writer :is_alias_for
-
- ##
- # The constant's name
-
- attr_accessor :name
-
- ##
- # The constant's value
-
- attr_accessor :value
-
- ##
- # The constant's visibility
-
- attr_accessor :visibility
-
- ##
- # Creates a new constant with +name+, +value+ and +comment+
-
- def initialize(name, value, comment)
- super()
-
- @name = name
- @value = value
-
- @is_alias_for = nil
- @visibility = :public
-
- self.comment = comment
- end
-
- ##
- # Constants are ordered by name
-
- def <=> other
- return unless self.class === other
-
- [parent_name, name] <=> [other.parent_name, other.name]
- end
-
- ##
- # Constants are equal when their #parent and #name is the same
-
- def == other
- self.class == other.class and
- @parent == other.parent and
- @name == other.name
- end
-
- ##
- # A constant is documented if it has a comment, or is an alias
- # for a documented class or module.
-
- def documented?
- return true if super
- return false unless @is_alias_for
- case @is_alias_for
- when String then
- found = @store.find_class_or_module @is_alias_for
- return false unless found
- @is_alias_for = found
- end
- @is_alias_for.documented?
- end
-
- ##
- # Full constant name including namespace
-
- def full_name
- @full_name ||= "#{parent_name}::#{@name}"
- end
-
- ##
- # The module or class this constant is an alias for
-
- def is_alias_for
- case @is_alias_for
- when String then
- found = @store.find_class_or_module @is_alias_for
- @is_alias_for = found if found
- @is_alias_for
- else
- @is_alias_for
- end
- end
-
- def inspect # :nodoc:
- "#<%s:0x%x %s::%s>" % [
- self.class, object_id,
- parent_name, @name,
- ]
- end
-
- ##
- # Dumps this Constant for use by ri. See also #marshal_load
-
- def marshal_dump
- alias_name = case found = is_alias_for
- when RDoc::CodeObject then found.full_name
- else found
- end
-
- [ MARSHAL_VERSION,
- @name,
- full_name,
- @visibility,
- alias_name,
- parse(@comment),
- @file.relative_name,
- parent.name,
- parent.class,
- section.title,
- ]
- end
-
- ##
- # Loads this Constant from +array+. For a loaded Constant the following
- # methods will return cached values:
- #
- # * #full_name
- # * #parent_name
-
- def marshal_load array
- initialize array[1], nil, array[5]
-
- @full_name = array[2]
- @visibility = array[3] || :public
- @is_alias_for = array[4]
- # 5 handled above
- # 6 handled below
- @parent_name = array[7]
- @parent_class = array[8]
- @section_title = array[9]
-
- @file = RDoc::TopLevel.new array[6]
- end
-
- ##
- # Path to this constant for use with HTML generator output.
-
- def path
- "#{@parent.path}##{@name}"
- end
-
- def pretty_print q # :nodoc:
- q.group 2, "[#{self.class.name} #{full_name}", "]" do
- unless comment.empty? then
- q.breakable
- q.text "comment:"
- q.breakable
- q.pp @comment
- end
- end
- end
-
- ##
- # Sets the store for this class or module and its contained code objects.
-
- def store= store
- super
-
- @file = @store.add_file @file.full_name if @file
- end
-
- def to_s # :nodoc:
- parent_name = parent ? parent.full_name : '(unknown)'
- if is_alias_for
- "constant #{parent_name}::#@name -> #{is_alias_for}"
- else
- "constant #{parent_name}::#@name"
- end
- end
-
-end
diff --git a/lib/rdoc/code_object/context.rb b/lib/rdoc/code_object/context.rb
deleted file mode 100644
index c688d562c3..0000000000
--- a/lib/rdoc/code_object/context.rb
+++ /dev/null
@@ -1,1264 +0,0 @@
-# frozen_string_literal: true
-##
-# A Context is something that can hold modules, classes, methods, attributes,
-# aliases, requires, and includes. Classes, modules, and files are all
-# Contexts.
-
-class RDoc::Context < RDoc::CodeObject
-
- include Comparable
-
- ##
- # Types of methods
-
- TYPES = %w[class instance]
-
- ##
- # If a context has these titles it will be sorted in this order.
-
- TOMDOC_TITLES = [nil, 'Public', 'Internal', 'Deprecated'] # :nodoc:
- TOMDOC_TITLES_SORT = TOMDOC_TITLES.sort_by { |title| title.to_s } # :nodoc:
-
- ##
- # Class/module aliases
-
- attr_reader :aliases
-
- ##
- # All attr* methods
-
- attr_reader :attributes
-
- ##
- # Block params to be used in the next MethodAttr parsed under this context
-
- attr_accessor :block_params
-
- ##
- # Constants defined
-
- attr_reader :constants
-
- ##
- # Sets the current documentation section of documentation
-
- attr_writer :current_section
-
- ##
- # Files this context is found in
-
- attr_reader :in_files
-
- ##
- # Modules this context includes
-
- attr_reader :includes
-
- ##
- # Modules this context is extended with
-
- attr_reader :extends
-
- ##
- # Methods defined in this context
-
- attr_reader :method_list
-
- ##
- # Name of this class excluding namespace. See also full_name
-
- attr_reader :name
-
- ##
- # Files this context requires
-
- attr_reader :requires
-
- ##
- # Use this section for the next method, attribute or constant added.
-
- attr_accessor :temporary_section
-
- ##
- # Hash <tt>old_name => [aliases]</tt>, for aliases
- # that haven't (yet) been resolved to a method/attribute.
- # (Not to be confused with the aliases of the context.)
-
- attr_accessor :unmatched_alias_lists
-
- ##
- # Aliases that could not be resolved.
-
- attr_reader :external_aliases
-
- ##
- # Current visibility of this context
-
- attr_accessor :visibility
-
- ##
- # Current visibility of this line
-
- attr_writer :current_line_visibility
-
- ##
- # Hash of registered methods. Attributes are also registered here,
- # twice if they are RW.
-
- attr_reader :methods_hash
-
- ##
- # Params to be used in the next MethodAttr parsed under this context
-
- attr_accessor :params
-
- ##
- # Hash of registered constants.
-
- attr_reader :constants_hash
-
- ##
- # Creates an unnamed empty context with public current visibility
-
- def initialize
- super
-
- @in_files = []
-
- @name ||= "unknown"
- @parent = nil
- @visibility = :public
-
- @current_section = Section.new self, nil, nil
- @sections = { nil => @current_section }
- @temporary_section = nil
-
- @classes = {}
- @modules = {}
-
- initialize_methods_etc
- end
-
- ##
- # Sets the defaults for methods and so-forth
-
- def initialize_methods_etc
- @method_list = []
- @attributes = []
- @aliases = []
- @requires = []
- @includes = []
- @extends = []
- @constants = []
- @external_aliases = []
- @current_line_visibility = nil
-
- # This Hash maps a method name to a list of unmatched aliases (aliases of
- # a method not yet encountered).
- @unmatched_alias_lists = {}
-
- @methods_hash = {}
- @constants_hash = {}
-
- @params = nil
-
- @store ||= nil
- end
-
- ##
- # Contexts are sorted by full_name
-
- def <=>(other)
- return nil unless RDoc::CodeObject === other
-
- full_name <=> other.full_name
- end
-
- ##
- # Adds an item of type +klass+ with the given +name+ and +comment+ to the
- # context.
- #
- # Currently only RDoc::Extend and RDoc::Include are supported.
-
- def add klass, name, comment
- if RDoc::Extend == klass then
- ext = RDoc::Extend.new name, comment
- add_extend ext
- elsif RDoc::Include == klass then
- incl = RDoc::Include.new name, comment
- add_include incl
- else
- raise NotImplementedError, "adding a #{klass} is not implemented"
- end
- end
-
- ##
- # Adds +an_alias+ that is automatically resolved
-
- def add_alias an_alias
- return an_alias unless @document_self
-
- method_attr = find_method(an_alias.old_name, an_alias.singleton) ||
- find_attribute(an_alias.old_name, an_alias.singleton)
-
- if method_attr then
- method_attr.add_alias an_alias, self
- else
- add_to @external_aliases, an_alias
- unmatched_alias_list =
- @unmatched_alias_lists[an_alias.pretty_old_name] ||= []
- unmatched_alias_list.push an_alias
- end
-
- an_alias
- end
-
- ##
- # Adds +attribute+ if not already there. If it is (as method(s) or attribute),
- # updates the comment if it was empty.
- #
- # The attribute is registered only if it defines a new method.
- # For instance, <tt>attr_reader :foo</tt> will not be registered
- # if method +foo+ exists, but <tt>attr_accessor :foo</tt> will be registered
- # if method +foo+ exists, but <tt>foo=</tt> does not.
-
- def add_attribute attribute
- return attribute unless @document_self
-
- # mainly to check for redefinition of an attribute as a method
- # TODO find a policy for 'attr_reader :foo' + 'def foo=()'
- register = false
-
- key = nil
-
- if attribute.rw.index 'R' then
- key = attribute.pretty_name
- known = @methods_hash[key]
-
- if known then
- known.comment = attribute.comment if known.comment.empty?
- elsif registered = @methods_hash[attribute.pretty_name + '='] and
- RDoc::Attr === registered then
- registered.rw = 'RW'
- else
- @methods_hash[key] = attribute
- register = true
- end
- end
-
- if attribute.rw.index 'W' then
- key = attribute.pretty_name + '='
- known = @methods_hash[key]
-
- if known then
- known.comment = attribute.comment if known.comment.empty?
- elsif registered = @methods_hash[attribute.pretty_name] and
- RDoc::Attr === registered then
- registered.rw = 'RW'
- else
- @methods_hash[key] = attribute
- register = true
- end
- end
-
- if register then
- attribute.visibility = @visibility
- add_to @attributes, attribute
- resolve_aliases attribute
- end
-
- attribute
- end
-
- ##
- # Adds a class named +given_name+ with +superclass+.
- #
- # Both +given_name+ and +superclass+ may contain '::', and are
- # interpreted relative to the +self+ context. This allows handling correctly
- # examples like these:
- # class RDoc::Gauntlet < Gauntlet
- # module Mod
- # class Object # implies < ::Object
- # class SubObject < Object # this is _not_ ::Object
- #
- # Given <tt>class Container::Item</tt> RDoc assumes +Container+ is a module
- # unless it later sees <tt>class Container</tt>. +add_class+ automatically
- # upgrades +given_name+ to a class in this case.
-
- def add_class class_type, given_name, superclass = '::Object'
- # superclass +nil+ is passed by the C parser in the following cases:
- # - registering Object in 1.8 (correct)
- # - registering BasicObject in 1.9 (correct)
- # - registering RubyVM in 1.9 in iseq.c (incorrect: < Object in vm.c)
- #
- # If we later find a superclass for a registered class with a nil
- # superclass, we must honor it.
-
- # find the name & enclosing context
- if given_name =~ /^:+(\w+)$/ then
- full_name = $1
- enclosing = top_level
- name = full_name.split(/:+/).last
- else
- full_name = child_name given_name
-
- if full_name =~ /^(.+)::(\w+)$/ then
- name = $2
- ename = $1
- enclosing = @store.classes_hash[ename] || @store.modules_hash[ename]
- # HACK: crashes in actionpack/lib/action_view/helpers/form_helper.rb (metaprogramming)
- unless enclosing then
- # try the given name at top level (will work for the above example)
- enclosing = @store.classes_hash[given_name] ||
- @store.modules_hash[given_name]
- return enclosing if enclosing
- # not found: create the parent(s)
- names = ename.split('::')
- enclosing = self
- names.each do |n|
- enclosing = enclosing.classes_hash[n] ||
- enclosing.modules_hash[n] ||
- enclosing.add_module(RDoc::NormalModule, n)
- end
- end
- else
- name = full_name
- enclosing = self
- end
- end
-
- # fix up superclass
- if full_name == 'BasicObject' then
- superclass = nil
- elsif full_name == 'Object' then
- superclass = '::BasicObject'
- end
-
- # find the superclass full name
- if superclass then
- if superclass =~ /^:+/ then
- superclass = $' #'
- else
- if superclass =~ /^(\w+):+(.+)$/ then
- suffix = $2
- mod = find_module_named($1)
- superclass = mod.full_name + '::' + suffix if mod
- else
- mod = find_module_named(superclass)
- superclass = mod.full_name if mod
- end
- end
-
- # did we believe it was a module?
- mod = @store.modules_hash.delete superclass
-
- upgrade_to_class mod, RDoc::NormalClass, mod.parent if mod
-
- # e.g., Object < Object
- superclass = nil if superclass == full_name
- end
-
- klass = @store.classes_hash[full_name]
-
- if klass then
- # if TopLevel, it may not be registered in the classes:
- enclosing.classes_hash[name] = klass
-
- # update the superclass if needed
- if superclass then
- existing = klass.superclass
- existing = existing.full_name unless existing.is_a?(String) if existing
- if existing.nil? ||
- (existing == 'Object' && superclass != 'Object') then
- klass.superclass = superclass
- end
- end
- else
- # this is a new class
- mod = @store.modules_hash.delete full_name
-
- if mod then
- klass = upgrade_to_class mod, RDoc::NormalClass, enclosing
-
- klass.superclass = superclass unless superclass.nil?
- else
- klass = class_type.new name, superclass
-
- enclosing.add_class_or_module(klass, enclosing.classes_hash,
- @store.classes_hash)
- end
- end
-
- klass.parent = self
-
- klass
- end
-
- ##
- # Adds the class or module +mod+ to the modules or
- # classes Hash +self_hash+, and to +all_hash+ (either
- # <tt>TopLevel::modules_hash</tt> or <tt>TopLevel::classes_hash</tt>),
- # unless #done_documenting is +true+. Sets the #parent of +mod+
- # to +self+, and its #section to #current_section. Returns +mod+.
-
- def add_class_or_module mod, self_hash, all_hash
- mod.section = current_section # TODO declaring context? something is
- # wrong here...
- mod.parent = self
- mod.full_name = nil
- mod.store = @store
-
- unless @done_documenting then
- self_hash[mod.name] = mod
- # this must be done AFTER adding mod to its parent, so that the full
- # name is correct:
- all_hash[mod.full_name] = mod
- if @store.unmatched_constant_alias[mod.full_name] then
- to, file = @store.unmatched_constant_alias[mod.full_name]
- add_module_alias mod, mod.name, to, file
- end
- end
-
- mod
- end
-
- ##
- # Adds +constant+ if not already there. If it is, updates the comment,
- # value and/or is_alias_for of the known constant if they were empty/nil.
-
- def add_constant constant
- return constant unless @document_self
-
- # HACK: avoid duplicate 'PI' & 'E' in math.c (1.8.7 source code)
- # (this is a #ifdef: should be handled by the C parser)
- known = @constants_hash[constant.name]
-
- if known then
- known.comment = constant.comment if known.comment.empty?
-
- known.value = constant.value if
- known.value.nil? or known.value.strip.empty?
-
- known.is_alias_for ||= constant.is_alias_for
- else
- @constants_hash[constant.name] = constant
- add_to @constants, constant
- end
-
- constant
- end
-
- ##
- # Adds included module +include+ which should be an RDoc::Include
-
- def add_include include
- add_to @includes, include
-
- include
- end
-
- ##
- # Adds extension module +ext+ which should be an RDoc::Extend
-
- def add_extend ext
- add_to @extends, ext
-
- ext
- end
-
- ##
- # Adds +method+ if not already there. If it is (as method or attribute),
- # updates the comment if it was empty.
-
- def add_method method
- return method unless @document_self
-
- # HACK: avoid duplicate 'new' in io.c & struct.c (1.8.7 source code)
- key = method.pretty_name
- known = @methods_hash[key]
-
- if known then
- if @store then # otherwise we are loading
- known.comment = method.comment if known.comment.empty?
- previously = ", previously in #{known.file}" unless
- method.file == known.file
- @store.rdoc.options.warn \
- "Duplicate method #{known.full_name} in #{method.file}#{previously}"
- end
- else
- @methods_hash[key] = method
- if @current_line_visibility
- method.visibility, @current_line_visibility = @current_line_visibility, nil
- else
- method.visibility = @visibility
- end
- add_to @method_list, method
- resolve_aliases method
- end
-
- method
- end
-
- ##
- # Adds a module named +name+. If RDoc already knows +name+ is a class then
- # that class is returned instead. See also #add_class.
-
- def add_module(class_type, name)
- mod = @classes[name] || @modules[name]
- return mod if mod
-
- full_name = child_name name
- mod = @store.modules_hash[full_name] || class_type.new(name)
-
- add_class_or_module mod, @modules, @store.modules_hash
- end
-
- ##
- # Adds a module by +RDoc::NormalModule+ instance. See also #add_module.
-
- def add_module_by_normal_module(mod)
- add_class_or_module mod, @modules, @store.modules_hash
- end
-
- ##
- # Adds an alias from +from+ (a class or module) to +name+ which was defined
- # in +file+.
-
- def add_module_alias from, from_name, to, file
- return from if @done_documenting
-
- to_full_name = child_name to.name
-
- # if we already know this name, don't register an alias:
- # see the metaprogramming in lib/active_support/basic_object.rb,
- # where we already know BasicObject is a class when we find
- # BasicObject = BlankSlate
- return from if @store.find_class_or_module to_full_name
-
- unless from
- @store.unmatched_constant_alias[child_name(from_name)] = [to, file]
- return to
- end
-
- new_to = from.dup
- new_to.name = to.name
- new_to.full_name = nil
-
- if new_to.module? then
- @store.modules_hash[to_full_name] = new_to
- @modules[to.name] = new_to
- else
- @store.classes_hash[to_full_name] = new_to
- @classes[to.name] = new_to
- end
-
- # Registers a constant for this alias. The constant value and comment
- # will be updated later, when the Ruby parser adds the constant
- const = RDoc::Constant.new to.name, nil, new_to.comment
- const.record_location file
- const.is_alias_for = from
- add_constant const
-
- new_to
- end
-
- ##
- # Adds +require+ to this context's top level
-
- def add_require(require)
- return require unless @document_self
-
- if RDoc::TopLevel === self then
- add_to @requires, require
- else
- parent.add_require require
- end
- end
-
- ##
- # Returns a section with +title+, creating it if it doesn't already exist.
- # +comment+ will be appended to the section's comment.
- #
- # A section with a +title+ of +nil+ will return the default section.
- #
- # See also RDoc::Context::Section
-
- def add_section title, comment = nil
- if section = @sections[title] then
- section.add_comment comment if comment
- else
- section = Section.new self, title, comment
- @sections[title] = section
- end
-
- section
- end
-
- ##
- # Adds +thing+ to the collection +array+
-
- def add_to array, thing
- array << thing if @document_self
-
- thing.parent = self
- thing.store = @store if @store
- thing.section = current_section
- end
-
- ##
- # Is there any content?
- #
- # This means any of: comment, aliases, methods, attributes, external
- # aliases, require, constant.
- #
- # Includes and extends are also checked unless <tt>includes == false</tt>.
-
- def any_content(includes = true)
- @any_content ||= !(
- @comment.empty? &&
- @method_list.empty? &&
- @attributes.empty? &&
- @aliases.empty? &&
- @external_aliases.empty? &&
- @requires.empty? &&
- @constants.empty?
- )
- @any_content || (includes && !(@includes + @extends).empty? )
- end
-
- ##
- # Creates the full name for a child with +name+
-
- def child_name name
- if name =~ /^:+/
- $' #'
- elsif RDoc::TopLevel === self then
- name
- else
- "#{self.full_name}::#{name}"
- end
- end
-
- ##
- # Class attributes
-
- def class_attributes
- @class_attributes ||= attributes.select { |a| a.singleton }
- end
-
- ##
- # Class methods
-
- def class_method_list
- @class_method_list ||= method_list.select { |a| a.singleton }
- end
-
- ##
- # Array of classes in this context
-
- def classes
- @classes.values
- end
-
- ##
- # All classes and modules in this namespace
-
- def classes_and_modules
- classes + modules
- end
-
- ##
- # Hash of classes keyed by class name
-
- def classes_hash
- @classes
- end
-
- ##
- # The current documentation section that new items will be added to. If
- # temporary_section is available it will be used.
-
- def current_section
- if section = @temporary_section then
- @temporary_section = nil
- else
- section = @current_section
- end
-
- section
- end
-
- ##
- # Is part of this thing was defined in +file+?
-
- def defined_in?(file)
- @in_files.include?(file)
- end
-
- def display(method_attr) # :nodoc:
- if method_attr.is_a? RDoc::Attr
- "#{method_attr.definition} #{method_attr.pretty_name}"
- else
- "method #{method_attr.pretty_name}"
- end
- end
-
- ##
- # Iterator for ancestors for duck-typing. Does nothing. See
- # RDoc::ClassModule#each_ancestor.
- #
- # This method exists to make it easy to work with Context subclasses that
- # aren't part of RDoc.
-
- def each_ancestor(&_) # :nodoc:
- end
-
- ##
- # Iterator for attributes
-
- def each_attribute # :yields: attribute
- @attributes.each { |a| yield a }
- end
-
- ##
- # Iterator for classes and modules
-
- def each_classmodule(&block) # :yields: module
- classes_and_modules.sort.each(&block)
- end
-
- ##
- # Iterator for constants
-
- def each_constant # :yields: constant
- @constants.each {|c| yield c}
- end
-
- ##
- # Iterator for included modules
-
- def each_include # :yields: include
- @includes.each do |i| yield i end
- end
-
- ##
- # Iterator for extension modules
-
- def each_extend # :yields: extend
- @extends.each do |e| yield e end
- end
-
- ##
- # Iterator for methods
-
- def each_method # :yields: method
- return enum_for __method__ unless block_given?
-
- @method_list.sort.each { |m| yield m }
- end
-
- ##
- # Iterator for each section's contents sorted by title. The +section+, the
- # section's +constants+ and the sections +attributes+ are yielded. The
- # +constants+ and +attributes+ collections are sorted.
- #
- # To retrieve methods in a section use #methods_by_type with the optional
- # +section+ parameter.
- #
- # NOTE: Do not edit collections yielded by this method
-
- def each_section # :yields: section, constants, attributes
- return enum_for __method__ unless block_given?
-
- constants = @constants.group_by do |constant| constant.section end
- attributes = @attributes.group_by do |attribute| attribute.section end
-
- constants.default = []
- attributes.default = []
-
- sort_sections.each do |section|
- yield section, constants[section].select(&:display?).sort, attributes[section].select(&:display?).sort
- end
- end
-
- ##
- # Finds an attribute +name+ with singleton value +singleton+.
-
- def find_attribute(name, singleton)
- name = $1 if name =~ /^(.*)=$/
- @attributes.find { |a| a.name == name && a.singleton == singleton }
- end
-
- ##
- # Finds an attribute with +name+ in this context
-
- def find_attribute_named(name)
- case name
- when /\A#/ then
- find_attribute name[1..-1], false
- when /\A::/ then
- find_attribute name[2..-1], true
- else
- @attributes.find { |a| a.name == name }
- end
- end
-
- ##
- # Finds a class method with +name+ in this context
-
- def find_class_method_named(name)
- @method_list.find { |meth| meth.singleton && meth.name == name }
- end
-
- ##
- # Finds a constant with +name+ in this context
-
- def find_constant_named(name)
- @constants.find do |m|
- m.name == name || m.full_name == name
- end
- end
-
- ##
- # Find a module at a higher scope
-
- def find_enclosing_module_named(name)
- parent && parent.find_module_named(name)
- end
-
- ##
- # Finds an external alias +name+ with singleton value +singleton+.
-
- def find_external_alias(name, singleton)
- @external_aliases.find { |m| m.name == name && m.singleton == singleton }
- end
-
- ##
- # Finds an external alias with +name+ in this context
-
- def find_external_alias_named(name)
- case name
- when /\A#/ then
- find_external_alias name[1..-1], false
- when /\A::/ then
- find_external_alias name[2..-1], true
- else
- @external_aliases.find { |a| a.name == name }
- end
- end
-
- ##
- # Finds a file with +name+ in this context
-
- def find_file_named name
- @store.find_file_named name
- end
-
- ##
- # Finds an instance method with +name+ in this context
-
- def find_instance_method_named(name)
- @method_list.find { |meth| !meth.singleton && meth.name == name }
- end
-
- ##
- # Finds a method, constant, attribute, external alias, module or file
- # named +symbol+ in this context.
-
- def find_local_symbol(symbol)
- find_method_named(symbol) or
- find_constant_named(symbol) or
- find_attribute_named(symbol) or
- find_external_alias_named(symbol) or
- find_module_named(symbol) or
- find_file_named(symbol)
- end
-
- ##
- # Finds a method named +name+ with singleton value +singleton+.
-
- def find_method(name, singleton)
- @method_list.find { |m|
- if m.singleton
- m.name == name && m.singleton == singleton
- else
- m.name == name && !m.singleton && !singleton
- end
- }
- end
-
- ##
- # Finds a instance or module method with +name+ in this context
-
- def find_method_named(name)
- case name
- when /\A#/ then
- find_method name[1..-1], false
- when /\A::/ then
- find_method name[2..-1], true
- else
- @method_list.find { |meth| meth.name == name }
- end
- end
-
- ##
- # Find a module with +name+ using ruby's scoping rules
-
- def find_module_named(name)
- res = @modules[name] || @classes[name]
- return res if res
- return self if self.name == name
- find_enclosing_module_named name
- end
-
- ##
- # Look up +symbol+, first as a module, then as a local symbol.
-
- def find_symbol(symbol)
- find_symbol_module(symbol) || find_local_symbol(symbol)
- end
-
- ##
- # Look up a module named +symbol+.
-
- def find_symbol_module(symbol)
- result = nil
-
- # look for a class or module 'symbol'
- case symbol
- when /^::/ then
- result = @store.find_class_or_module symbol
- when /^(\w+):+(.+)$/
- suffix = $2
- top = $1
- searched = self
- while searched do
- mod = searched.find_module_named(top)
- break unless mod
- result = @store.find_class_or_module "#{mod.full_name}::#{suffix}"
- break if result || searched.is_a?(RDoc::TopLevel)
- searched = searched.parent
- end
- else
- searched = self
- while searched do
- result = searched.find_module_named(symbol)
- break if result || searched.is_a?(RDoc::TopLevel)
- searched = searched.parent
- end
- end
-
- result
- end
-
- ##
- # The full name for this context. This method is overridden by subclasses.
-
- def full_name
- '(unknown)'
- end
-
- ##
- # Does this context and its methods and constants all have documentation?
- #
- # (Yes, fully documented doesn't mean everything.)
-
- def fully_documented?
- documented? and
- attributes.all? { |a| a.documented? } and
- method_list.all? { |m| m.documented? } and
- constants.all? { |c| c.documented? }
- end
-
- ##
- # URL for this with a +prefix+
-
- def http_url(prefix)
- path = name_for_path
- path = path.gsub(/<<\s*(\w*)/, 'from-\1') if path =~ /<</
- path = [prefix] + path.split('::')
-
- File.join(*path.compact) + '.html'
- end
-
- ##
- # Instance attributes
-
- def instance_attributes
- @instance_attributes ||= attributes.reject { |a| a.singleton }
- end
-
- ##
- # Instance methods
-
- def instance_methods
- @instance_methods ||= method_list.reject { |a| a.singleton }
- end
-
- ##
- # Instance methods
- #--
- # TODO remove this later
-
- def instance_method_list
- warn '#instance_method_list is obsoleted, please use #instance_methods'
- @instance_methods ||= method_list.reject { |a| a.singleton }
- end
-
- ##
- # Breaks method_list into a nested hash by type (<tt>'class'</tt> or
- # <tt>'instance'</tt>) and visibility (+:public+, +:protected+, +:private+).
- #
- # If +section+ is provided only methods in that RDoc::Context::Section will
- # be returned.
-
- def methods_by_type section = nil
- methods = {}
-
- TYPES.each do |type|
- visibilities = {}
- RDoc::VISIBILITIES.each do |vis|
- visibilities[vis] = []
- end
-
- methods[type] = visibilities
- end
-
- each_method do |method|
- next if section and not method.section == section
- methods[method.type][method.visibility] << method
- end
-
- methods
- end
-
- ##
- # Yields AnyMethod and Attr entries matching the list of names in +methods+.
-
- def methods_matching(methods, singleton = false, &block)
- (@method_list + @attributes).each do |m|
- yield m if methods.include?(m.name) and m.singleton == singleton
- end
-
- each_ancestor do |parent|
- parent.methods_matching(methods, singleton, &block)
- end
- end
-
- ##
- # Array of modules in this context
-
- def modules
- @modules.values
- end
-
- ##
- # Hash of modules keyed by module name
-
- def modules_hash
- @modules
- end
-
- ##
- # Name to use to generate the url.
- # <tt>#full_name</tt> by default.
-
- def name_for_path
- full_name
- end
-
- ##
- # Changes the visibility for new methods to +visibility+
-
- def ongoing_visibility=(visibility)
- @visibility = visibility
- end
-
- ##
- # Record +top_level+ as a file +self+ is in.
-
- def record_location(top_level)
- @in_files << top_level unless @in_files.include?(top_level)
- end
-
- ##
- # Should we remove this context from the documentation?
- #
- # The answer is yes if:
- # * #received_nodoc is +true+
- # * #any_content is +false+ (not counting includes)
- # * All #includes are modules (not a string), and their module has
- # <tt>#remove_from_documentation? == true</tt>
- # * All classes and modules have <tt>#remove_from_documentation? == true</tt>
-
- def remove_from_documentation?
- @remove_from_documentation ||=
- @received_nodoc &&
- !any_content(false) &&
- @includes.all? { |i| !i.module.is_a?(String) && i.module.remove_from_documentation? } &&
- classes_and_modules.all? { |cm| cm.remove_from_documentation? }
- end
-
- ##
- # Removes methods and attributes with a visibility less than +min_visibility+.
- #--
- # TODO mark the visibility of attributes in the template (if not public?)
-
- def remove_invisible min_visibility
- return if [:private, :nodoc].include? min_visibility
- remove_invisible_in @method_list, min_visibility
- remove_invisible_in @attributes, min_visibility
- remove_invisible_in @constants, min_visibility
- end
-
- ##
- # Only called when min_visibility == :public or :private
-
- def remove_invisible_in array, min_visibility # :nodoc:
- if min_visibility == :public then
- array.reject! { |e|
- e.visibility != :public and not e.force_documentation
- }
- else
- array.reject! { |e|
- e.visibility == :private and not e.force_documentation
- }
- end
- end
-
- ##
- # Tries to resolve unmatched aliases when a method or attribute has just
- # been added.
-
- def resolve_aliases added
- # resolve any pending unmatched aliases
- key = added.pretty_name
- unmatched_alias_list = @unmatched_alias_lists[key]
- return unless unmatched_alias_list
- unmatched_alias_list.each do |unmatched_alias|
- added.add_alias unmatched_alias, self
- @external_aliases.delete unmatched_alias
- end
- @unmatched_alias_lists.delete key
- end
-
- ##
- # Returns RDoc::Context::Section objects referenced in this context for use
- # in a table of contents.
-
- def section_contents
- used_sections = {}
-
- each_method do |method|
- next unless method.display?
-
- used_sections[method.section] = true
- end
-
- # order found sections
- sections = sort_sections.select do |section|
- used_sections[section]
- end
-
- # only the default section is used
- return [] if
- sections.length == 1 and not sections.first.title
-
- sections
- end
-
- ##
- # Sections in this context
-
- def sections
- @sections.values
- end
-
- def sections_hash # :nodoc:
- @sections
- end
-
- ##
- # Sets the current section to a section with +title+. See also #add_section
-
- def set_current_section title, comment
- @current_section = add_section title, comment
- end
-
- ##
- # Given an array +methods+ of method names, set the visibility of each to
- # +visibility+
-
- def set_visibility_for(methods, visibility, singleton = false)
- methods_matching methods, singleton do |m|
- m.visibility = visibility
- end
- end
-
- ##
- # Given an array +names+ of constants, set the visibility of each constant to
- # +visibility+
-
- def set_constant_visibility_for(names, visibility)
- names.each do |name|
- constant = @constants_hash[name] or next
- constant.visibility = visibility
- end
- end
-
- ##
- # Sorts sections alphabetically (default) or in TomDoc fashion (none,
- # Public, Internal, Deprecated)
-
- def sort_sections
- titles = @sections.map { |title, _| title }
-
- if titles.length > 1 and
- TOMDOC_TITLES_SORT ==
- (titles | TOMDOC_TITLES).sort_by { |title| title.to_s } then
- @sections.values_at(*TOMDOC_TITLES).compact
- else
- @sections.sort_by { |title, _|
- title.to_s
- }.map { |_, section|
- section
- }
- end
- end
-
- def to_s # :nodoc:
- "#{self.class.name} #{self.full_name}"
- end
-
- ##
- # Return the TopLevel that owns us
- #--
- # FIXME we can be 'owned' by several TopLevel (see #record_location &
- # #in_files)
-
- def top_level
- return @top_level if defined? @top_level
- @top_level = self
- @top_level = @top_level.parent until RDoc::TopLevel === @top_level
- @top_level
- end
-
- ##
- # Upgrades NormalModule +mod+ in +enclosing+ to a +class_type+
-
- def upgrade_to_class mod, class_type, enclosing
- enclosing.modules_hash.delete mod.name
-
- klass = RDoc::ClassModule.from_module class_type, mod
- klass.store = @store
-
- # if it was there, then we keep it even if done_documenting
- @store.classes_hash[mod.full_name] = klass
- enclosing.classes_hash[mod.name] = klass
-
- klass
- end
-
- autoload :Section, "#{__dir__}/context/section"
-
-end
diff --git a/lib/rdoc/code_object/context/section.rb b/lib/rdoc/code_object/context/section.rb
deleted file mode 100644
index aecd4e0213..0000000000
--- a/lib/rdoc/code_object/context/section.rb
+++ /dev/null
@@ -1,233 +0,0 @@
-# frozen_string_literal: true
-require 'cgi/util'
-
-##
-# A section of documentation like:
-#
-# # :section: The title
-# # The body
-#
-# Sections can be referenced multiple times and will be collapsed into a
-# single section.
-
-class RDoc::Context::Section
-
- include RDoc::Text
-
- MARSHAL_VERSION = 0 # :nodoc:
-
- ##
- # Section comment
-
- attr_reader :comment
-
- ##
- # Section comments
-
- attr_reader :comments
-
- ##
- # Context this Section lives in
-
- attr_reader :parent
-
- ##
- # Section title
-
- attr_reader :title
-
- ##
- # Creates a new section with +title+ and +comment+
-
- def initialize parent, title, comment
- @parent = parent
- @title = title ? title.strip : title
-
- @comments = []
-
- add_comment comment
- end
-
- ##
- # Sections are equal when they have the same #title
-
- def == other
- self.class === other and @title == other.title
- end
-
- alias eql? ==
-
- ##
- # Adds +comment+ to this section
-
- def add_comment comment
- comment = extract_comment comment
-
- return if comment.empty?
-
- case comment
- when RDoc::Comment then
- @comments << comment
- when RDoc::Markup::Document then
- @comments.concat comment.parts
- when Array then
- @comments.concat comment
- else
- raise TypeError, "unknown comment type: #{comment.inspect}"
- end
- end
-
- ##
- # Anchor reference for linking to this section
-
- def aref
- title = @title || '[untitled]'
-
- CGI.escape(title).gsub('%', '-').sub(/^-/, '')
- end
-
- ##
- # Extracts the comment for this section from the original comment block.
- # If the first line contains :section:, strip it and use the rest.
- # Otherwise remove lines up to the line containing :section:, and look
- # for those lines again at the end and remove them. This lets us write
- #
- # # :section: The title
- # # The body
-
- def extract_comment comment
- case comment
- when Array then
- comment.map do |c|
- extract_comment c
- end
- when nil
- RDoc::Comment.new ''
- when RDoc::Comment then
- if comment.text =~ /^#[ \t]*:section:.*\n/ then
- start = $`
- rest = $'
-
- comment.text = if start.empty? then
- rest
- else
- rest.sub(/#{start.chomp}\Z/, '')
- end
- end
-
- comment
- when RDoc::Markup::Document then
- comment
- else
- raise TypeError, "unknown comment #{comment.inspect}"
- end
- end
-
- def inspect # :nodoc:
- "#<%s:0x%x %p>" % [self.class, object_id, title]
- end
-
- def hash # :nodoc:
- @title.hash
- end
-
- ##
- # The files comments in this section come from
-
- def in_files
- return [] if @comments.empty?
-
- case @comments
- when Array then
- @comments.map do |comment|
- comment.file
- end
- when RDoc::Markup::Document then
- @comment.parts.map do |document|
- document.file
- end
- else
- raise RDoc::Error, "BUG: unknown comment class #{@comments.class}"
- end
- end
-
- ##
- # Serializes this Section. The title and parsed comment are saved, but not
- # the section parent which must be restored manually.
-
- def marshal_dump
- [
- MARSHAL_VERSION,
- @title,
- parse,
- ]
- end
-
- ##
- # De-serializes this Section. The section parent must be restored manually.
-
- def marshal_load array
- @parent = nil
-
- @title = array[1]
- @comments = array[2]
- end
-
- ##
- # Parses +comment_location+ into an RDoc::Markup::Document composed of
- # multiple RDoc::Markup::Documents with their file set.
-
- def parse
- case @comments
- when String then
- super
- when Array then
- docs = @comments.map do |comment, location|
- doc = super comment
- doc.file = location if location
- doc
- end
-
- RDoc::Markup::Document.new(*docs)
- when RDoc::Comment then
- doc = super @comments.text, comments.format
- doc.file = @comments.location
- doc
- when RDoc::Markup::Document then
- return @comments
- else
- raise ArgumentError, "unknown comment class #{comments.class}"
- end
- end
-
- ##
- # The section's title, or 'Top Section' if the title is nil.
- #
- # This is used by the table of contents template so the name is silly.
-
- def plain_html
- @title || 'Top Section'
- end
-
- ##
- # Removes a comment from this section if it is from the same file as
- # +comment+
-
- def remove_comment comment
- return if @comments.empty?
-
- case @comments
- when Array then
- @comments.delete_if do |my_comment|
- my_comment.file == comment.file
- end
- when RDoc::Markup::Document then
- @comments.parts.delete_if do |document|
- document.file == comment.file.name
- end
- else
- raise RDoc::Error, "BUG: unknown comment class #{@comments.class}"
- end
- end
-
-end
diff --git a/lib/rdoc/code_object/extend.rb b/lib/rdoc/code_object/extend.rb
deleted file mode 100644
index 7d57433de6..0000000000
--- a/lib/rdoc/code_object/extend.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-##
-# A Module extension to a class with \#extend
-#
-# RDoc::Extend.new 'Enumerable', 'comment ...'
-
-class RDoc::Extend < RDoc::Mixin
-
-end
diff --git a/lib/rdoc/code_object/ghost_method.rb b/lib/rdoc/code_object/ghost_method.rb
deleted file mode 100644
index 25f951e35e..0000000000
--- a/lib/rdoc/code_object/ghost_method.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# frozen_string_literal: true
-##
-# GhostMethod represents a method referenced only by a comment
-
-class RDoc::GhostMethod < RDoc::AnyMethod
-end
diff --git a/lib/rdoc/code_object/include.rb b/lib/rdoc/code_object/include.rb
deleted file mode 100644
index c3e0d45e47..0000000000
--- a/lib/rdoc/code_object/include.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-##
-# A Module included in a class with \#include
-#
-# RDoc::Include.new 'Enumerable', 'comment ...'
-
-class RDoc::Include < RDoc::Mixin
-
-end
diff --git a/lib/rdoc/code_object/meta_method.rb b/lib/rdoc/code_object/meta_method.rb
deleted file mode 100644
index 8c95a0f78c..0000000000
--- a/lib/rdoc/code_object/meta_method.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# frozen_string_literal: true
-##
-# MetaMethod represents a meta-programmed method
-
-class RDoc::MetaMethod < RDoc::AnyMethod
-end
diff --git a/lib/rdoc/code_object/method_attr.rb b/lib/rdoc/code_object/method_attr.rb
deleted file mode 100644
index 27e6599bc1..0000000000
--- a/lib/rdoc/code_object/method_attr.rb
+++ /dev/null
@@ -1,418 +0,0 @@
-# frozen_string_literal: true
-##
-# Abstract class representing either a method or an attribute.
-
-class RDoc::MethodAttr < RDoc::CodeObject
-
- include Comparable
-
- ##
- # Name of this method/attribute.
-
- attr_accessor :name
-
- ##
- # public, protected, private
-
- attr_accessor :visibility
-
- ##
- # Is this a singleton method/attribute?
-
- attr_accessor :singleton
-
- ##
- # Source file token stream
-
- attr_reader :text
-
- ##
- # Array of other names for this method/attribute
-
- attr_reader :aliases
-
- ##
- # The method/attribute we're aliasing
-
- attr_accessor :is_alias_for
-
- #--
- # The attributes below are for AnyMethod only.
- # They are left here for the time being to
- # allow ri to operate.
- # TODO modify ri to avoid calling these on attributes.
- #++
-
- ##
- # Parameters yielded by the called block
-
- attr_reader :block_params
-
- ##
- # Parameters for this method
-
- attr_accessor :params
-
- ##
- # Different ways to call this method
-
- attr_accessor :call_seq
-
- ##
- # The call_seq or the param_seq with method name, if there is no call_seq.
-
- attr_reader :arglists
-
- ##
- # Pretty parameter list for this method
-
- attr_reader :param_seq
-
-
- ##
- # Creates a new MethodAttr from token stream +text+ and method or attribute
- # name +name+.
- #
- # Usually this is called by super from a subclass.
-
- def initialize text, name
- super()
-
- @text = text
- @name = name
-
- @aliases = []
- @is_alias_for = nil
- @parent_name = nil
- @singleton = nil
- @visibility = :public
- @see = false
-
- @arglists = nil
- @block_params = nil
- @call_seq = nil
- @param_seq = nil
- @params = nil
- end
-
- ##
- # Resets cached data for the object so it can be rebuilt by accessor methods
-
- def initialize_copy other # :nodoc:
- @full_name = nil
- end
-
- def initialize_visibility # :nodoc:
- super
- @see = nil
- end
-
- ##
- # Order by #singleton then #name
-
- def <=>(other)
- return unless other.respond_to?(:singleton) &&
- other.respond_to?(:name)
-
- [ @singleton ? 0 : 1, name] <=>
- [other.singleton ? 0 : 1, other.name]
- end
-
- def == other # :nodoc:
- equal?(other) or self.class == other.class and full_name == other.full_name
- end
-
- ##
- # A method/attribute is documented if any of the following is true:
- # - it was marked with :nodoc:;
- # - it has a comment;
- # - it is an alias for a documented method;
- # - it has a +#see+ method that is documented.
-
- def documented?
- super or
- (is_alias_for and is_alias_for.documented?) or
- (see and see.documented?)
- end
-
- ##
- # A method/attribute to look at,
- # in particular if this method/attribute has no documentation.
- #
- # It can be a method/attribute of the superclass or of an included module,
- # including the Kernel module, which is always appended to the included
- # modules.
- #
- # Returns +nil+ if there is no such method/attribute.
- # The +#is_alias_for+ method/attribute, if any, is not included.
- #
- # Templates may generate a "see also ..." if this method/attribute
- # has documentation, and "see ..." if it does not.
-
- def see
- @see = find_see if @see == false
- @see
- end
-
- ##
- # Sets the store for this class or module and its contained code objects.
-
- def store= store
- super
-
- @file = @store.add_file @file.full_name if @file
- end
-
- def find_see # :nodoc:
- return nil if singleton || is_alias_for
-
- # look for the method
- other = find_method_or_attribute name
- return other if other
-
- # if it is a setter, look for a getter
- return nil unless name =~ /[a-z_]=$/i # avoid == or ===
- return find_method_or_attribute name[0..-2]
- end
-
- def find_method_or_attribute name # :nodoc:
- return nil unless parent.respond_to? :ancestors
-
- searched = parent.ancestors
- kernel = @store.modules_hash['Kernel']
-
- searched << kernel if kernel &&
- parent != kernel && !searched.include?(kernel)
-
- searched.each do |ancestor|
- next if String === ancestor
- next if parent == ancestor
-
- other = ancestor.find_method_named('#' + name) ||
- ancestor.find_attribute_named(name)
-
- return other if other
- end
-
- nil
- end
-
- ##
- # Abstract method. Contexts in their building phase call this
- # to register a new alias for this known method/attribute.
- #
- # - creates a new AnyMethod/Attribute named <tt>an_alias.new_name</tt>;
- # - adds +self+ as an alias for the new method or attribute
- # - adds the method or attribute to #aliases
- # - adds the method or attribute to +context+.
-
- def add_alias(an_alias, context)
- raise NotImplementedError
- end
-
- ##
- # HTML fragment reference for this method
-
- def aref
- type = singleton ? 'c' : 'i'
- # % characters are not allowed in html names => dash instead
- "#{aref_prefix}-#{type}-#{html_name}"
- end
-
- ##
- # Prefix for +aref+, defined by subclasses.
-
- def aref_prefix
- raise NotImplementedError
- end
-
- ##
- # Attempts to sanitize the content passed by the Ruby parser:
- # remove outer parentheses, etc.
-
- def block_params=(value)
- # 'yield.to_s' or 'assert yield, msg'
- return @block_params = '' if value =~ /^[\.,]/
-
- # remove trailing 'if/unless ...'
- return @block_params = '' if value =~ /^(if|unless)\s/
-
- value = $1.strip if value =~ /^(.+)\s(if|unless)\s/
-
- # outer parentheses
- value = $1 if value =~ /^\s*\((.*)\)\s*$/
- value = value.strip
-
- # proc/lambda
- return @block_params = $1 if value =~ /^(proc|lambda)(\s*\{|\sdo)/
-
- # surrounding +...+ or [...]
- value = $1.strip if value =~ /^\+(.*)\+$/
- value = $1.strip if value =~ /^\[(.*)\]$/
-
- return @block_params = '' if value.empty?
-
- # global variable
- return @block_params = 'str' if value =~ /^\$[&0-9]$/
-
- # wipe out array/hash indices
- value.gsub!(/(\w)\[[^\[]+\]/, '\1')
-
- # remove @ from class/instance variables
- value.gsub!(/@@?([a-z0-9_]+)/, '\1')
-
- # method calls => method name
- value.gsub!(/([A-Z:a-z0-9_]+)\.([a-z0-9_]+)(\s*\(\s*[a-z0-9_.,\s]*\s*\)\s*)?/) do
- case $2
- when 'to_s' then $1
- when 'const_get' then 'const'
- when 'new' then
- $1.split('::').last. # ClassName => class_name
- gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
- gsub(/([a-z\d])([A-Z])/, '\1_\2').
- downcase
- else
- $2
- end
- end
-
- # class prefixes
- value.gsub!(/[A-Za-z0-9_:]+::/, '')
-
- # simple expressions
- value = $1 if value =~ /^([a-z0-9_]+)\s*[-*+\/]/
-
- @block_params = value.strip
- end
-
- ##
- # HTML id-friendly method/attribute name
-
- def html_name
- require 'cgi/util'
-
- CGI.escape(@name.gsub('-', '-2D')).gsub('%', '-').sub(/^-/, '')
- end
-
- ##
- # Full method/attribute name including namespace
-
- def full_name
- @full_name ||= "#{parent_name}#{pretty_name}"
- end
-
- def inspect # :nodoc:
- alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
- visibility = self.visibility
- visibility = "forced #{visibility}" if force_documentation
- "#<%s:0x%x %s (%s)%s>" % [
- self.class, object_id,
- full_name,
- visibility,
- alias_for,
- ]
- end
-
- ##
- # '::' for a class method/attribute, '#' for an instance method.
-
- def name_prefix
- @singleton ? '::' : '#'
- end
-
- ##
- # Name for output to HTML. For class methods the full name with a "." is
- # used like +SomeClass.method_name+. For instance methods the class name is
- # used if +context+ does not match the parent.
- #
- # This is to help prevent people from using :: to call class methods.
-
- def output_name context
- return "#{name_prefix}#{@name}" if context == parent
-
- "#{parent_name}#{@singleton ? '.' : '#'}#{@name}"
- end
-
- ##
- # Method/attribute name with class/instance indicator
-
- def pretty_name
- "#{name_prefix}#{@name}"
- end
-
- ##
- # Type of method/attribute (class or instance)
-
- def type
- singleton ? 'class' : 'instance'
- end
-
- ##
- # Path to this method for use with HTML generator output.
-
- def path
- "#{@parent.path}##{aref}"
- end
-
- ##
- # Name of our parent with special handling for un-marshaled methods
-
- def parent_name
- @parent_name || super
- end
-
- def pretty_print q # :nodoc:
- alias_for =
- if @is_alias_for.respond_to? :name then
- "alias for #{@is_alias_for.name}"
- elsif Array === @is_alias_for then
- "alias for #{@is_alias_for.last}"
- end
-
- q.group 2, "[#{self.class.name} #{full_name} #{visibility}", "]" do
- if alias_for then
- q.breakable
- q.text alias_for
- end
-
- if text then
- q.breakable
- q.text "text:"
- q.breakable
- q.pp @text
- end
-
- unless comment.empty? then
- q.breakable
- q.text "comment:"
- q.breakable
- q.pp @comment
- end
- end
- end
-
- ##
- # Used by RDoc::Generator::JsonIndex to create a record for the search
- # engine.
-
- def search_record
- [
- @name,
- full_name,
- @name,
- @parent.full_name,
- path,
- params,
- snippet(@comment),
- ]
- end
-
- def to_s # :nodoc:
- if @is_alias_for
- "#{self.class.name}: #{full_name} -> #{is_alias_for}"
- else
- "#{self.class.name}: #{full_name}"
- end
- end
-
-end
diff --git a/lib/rdoc/code_object/mixin.rb b/lib/rdoc/code_object/mixin.rb
deleted file mode 100644
index fa8faefc15..0000000000
--- a/lib/rdoc/code_object/mixin.rb
+++ /dev/null
@@ -1,120 +0,0 @@
-# frozen_string_literal: true
-##
-# A Mixin adds features from a module into another context. RDoc::Include and
-# RDoc::Extend are both mixins.
-
-class RDoc::Mixin < RDoc::CodeObject
-
- ##
- # Name of included module
-
- attr_accessor :name
-
- ##
- # Creates a new Mixin for +name+ with +comment+
-
- def initialize(name, comment)
- super()
- @name = name
- self.comment = comment
- @module = nil # cache for module if found
- end
-
- ##
- # Mixins are sorted by name
-
- def <=> other
- return unless self.class === other
-
- name <=> other.name
- end
-
- def == other # :nodoc:
- self.class === other and @name == other.name
- end
-
- alias eql? == # :nodoc:
-
- ##
- # Full name based on #module
-
- def full_name
- m = self.module
- RDoc::ClassModule === m ? m.full_name : @name
- end
-
- def hash # :nodoc:
- [@name, self.module].hash
- end
-
- def inspect # :nodoc:
- "#<%s:0x%x %s.%s %s>" % [
- self.class,
- object_id,
- parent_name, self.class.name.downcase, @name,
- ]
- end
-
- ##
- # Attempts to locate the included module object. Returns the name if not
- # known.
- #
- # The scoping rules of Ruby to resolve the name of an included module are:
- # - first look into the children of the current context;
- # - if not found, look into the children of included modules,
- # in reverse inclusion order;
- # - if still not found, go up the hierarchy of names.
- #
- # This method has <code>O(n!)</code> behavior when the module calling
- # include is referencing nonexistent modules. Avoid calling #module until
- # after all the files are parsed. This behavior is due to ruby's constant
- # lookup behavior.
- #
- # As of the beginning of October, 2011, no gem includes nonexistent modules.
-
- def module
- return @module if @module
-
- # search the current context
- return @name unless parent
- full_name = parent.child_name(@name)
- @module = @store.modules_hash[full_name]
- return @module if @module
- return @name if @name =~ /^::/
-
- # search the includes before this one, in reverse order
- searched = parent.includes.take_while { |i| i != self }.reverse
- searched.each do |i|
- inc = i.module
- next if String === inc
- full_name = inc.child_name(@name)
- @module = @store.modules_hash[full_name]
- return @module if @module
- end
-
- # go up the hierarchy of names
- up = parent.parent
- while up
- full_name = up.child_name(@name)
- @module = @store.modules_hash[full_name]
- return @module if @module
- up = up.parent
- end
-
- @name
- end
-
- ##
- # Sets the store for this class or module and its contained code objects.
-
- def store= store
- super
-
- @file = @store.add_file @file.full_name if @file
- end
-
- def to_s # :nodoc:
- "#{self.class.name.downcase} #@name in: #{parent}"
- end
-
-end
diff --git a/lib/rdoc/code_object/normal_class.rb b/lib/rdoc/code_object/normal_class.rb
deleted file mode 100644
index aa340b5d15..0000000000
--- a/lib/rdoc/code_object/normal_class.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-# frozen_string_literal: true
-##
-# A normal class, neither singleton nor anonymous
-
-class RDoc::NormalClass < RDoc::ClassModule
-
- ##
- # The ancestors of this class including modules. Unlike Module#ancestors,
- # this class is not included in the result. The result will contain both
- # RDoc::ClassModules and Strings.
-
- def ancestors
- if String === superclass then
- super << superclass
- elsif superclass then
- ancestors = super
- ancestors << superclass
- ancestors.concat superclass.ancestors
- else
- super
- end
- end
-
- def aref_prefix # :nodoc:
- 'class'
- end
-
- ##
- # The definition of this class, <tt>class MyClassName</tt>
-
- def definition
- "class #{full_name}"
- end
-
- def direct_ancestors
- superclass ? super + [superclass] : super
- end
-
- def inspect # :nodoc:
- superclass = @superclass ? " < #{@superclass}" : nil
- "<%s:0x%x class %s%s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [
- self.class, object_id,
- full_name, superclass, @includes, @extends, @attributes, @method_list, @aliases
- ]
- end
-
- def to_s # :nodoc:
- display = "#{self.class.name} #{self.full_name}"
- if superclass
- display += ' < ' + (superclass.is_a?(String) ? superclass : superclass.full_name)
- end
- display += ' -> ' + is_alias_for.to_s if is_alias_for
- display
- end
-
- def pretty_print q # :nodoc:
- superclass = @superclass ? " < #{@superclass}" : nil
-
- q.group 2, "[class #{full_name}#{superclass}", "]" do
- q.breakable
- q.text "includes:"
- q.breakable
- q.seplist @includes do |inc| q.pp inc end
-
- q.breakable
- q.text "constants:"
- q.breakable
- q.seplist @constants do |const| q.pp const end
-
- q.breakable
- q.text "attributes:"
- q.breakable
- q.seplist @attributes do |attr| q.pp attr end
-
- q.breakable
- q.text "methods:"
- q.breakable
- q.seplist @method_list do |meth| q.pp meth end
-
- q.breakable
- q.text "aliases:"
- q.breakable
- q.seplist @aliases do |aliaz| q.pp aliaz end
-
- q.breakable
- q.text "comment:"
- q.breakable
- q.pp comment
- end
- end
-
-end
diff --git a/lib/rdoc/code_object/normal_module.rb b/lib/rdoc/code_object/normal_module.rb
deleted file mode 100644
index 498ec4dde2..0000000000
--- a/lib/rdoc/code_object/normal_module.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-# frozen_string_literal: true
-##
-# A normal module, like NormalClass
-
-class RDoc::NormalModule < RDoc::ClassModule
-
- def aref_prefix # :nodoc:
- 'module'
- end
-
- def inspect # :nodoc:
- "#<%s:0x%x module %s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [
- self.class, object_id,
- full_name, @includes, @extends, @attributes, @method_list, @aliases
- ]
- end
-
- ##
- # The definition of this module, <tt>module MyModuleName</tt>
-
- def definition
- "module #{full_name}"
- end
-
- ##
- # This is a module, returns true
-
- def module?
- true
- end
-
- def pretty_print q # :nodoc:
- q.group 2, "[module #{full_name}:", "]" do
- q.breakable
- q.text "includes:"
- q.breakable
- q.seplist @includes do |inc| q.pp inc end
- q.breakable
-
- q.breakable
- q.text "constants:"
- q.breakable
- q.seplist @constants do |const| q.pp const end
-
- q.text "attributes:"
- q.breakable
- q.seplist @attributes do |attr| q.pp attr end
- q.breakable
-
- q.text "methods:"
- q.breakable
- q.seplist @method_list do |meth| q.pp meth end
- q.breakable
-
- q.text "aliases:"
- q.breakable
- q.seplist @aliases do |aliaz| q.pp aliaz end
- q.breakable
-
- q.text "comment:"
- q.breakable
- q.pp comment
- end
- end
-
- ##
- # Modules don't have one, raises NoMethodError
-
- def superclass
- raise NoMethodError, "#{full_name} is a module"
- end
-
-end
diff --git a/lib/rdoc/code_object/require.rb b/lib/rdoc/code_object/require.rb
deleted file mode 100644
index 05e26b84b0..0000000000
--- a/lib/rdoc/code_object/require.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-##
-# A file loaded by \#require
-
-class RDoc::Require < RDoc::CodeObject
-
- ##
- # Name of the required file
-
- attr_accessor :name
-
- ##
- # Creates a new Require that loads +name+ with +comment+
-
- def initialize(name, comment)
- super()
- @name = name.gsub(/'|"/, "") #'
- @top_level = nil
- self.comment = comment
- end
-
- def inspect # :nodoc:
- "#<%s:0x%x require '%s' in %s>" % [
- self.class,
- object_id,
- @name,
- parent_file_name,
- ]
- end
-
- def to_s # :nodoc:
- "require #{name} in: #{parent}"
- end
-
- ##
- # The RDoc::TopLevel corresponding to this require, or +nil+ if not found.
-
- def top_level
- @top_level ||= begin
- tl = RDoc::TopLevel.all_files_hash[name + '.rb']
-
- if tl.nil? and RDoc::TopLevel.all_files.first.full_name =~ %r(^lib/) then
- # second chance
- tl = RDoc::TopLevel.all_files_hash['lib/' + name + '.rb']
- end
-
- tl
- end
- end
-
-end
diff --git a/lib/rdoc/code_object/single_class.rb b/lib/rdoc/code_object/single_class.rb
deleted file mode 100644
index dd16529648..0000000000
--- a/lib/rdoc/code_object/single_class.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-##
-# A singleton class
-
-class RDoc::SingleClass < RDoc::ClassModule
-
- ##
- # Adds the superclass to the included modules.
-
- def ancestors
- superclass ? super + [superclass] : super
- end
-
- def aref_prefix # :nodoc:
- 'sclass'
- end
-
- ##
- # The definition of this singleton class, <tt>class << MyClassName</tt>
-
- def definition
- "class << #{full_name}"
- end
-
- def pretty_print q # :nodoc:
- q.group 2, "[class << #{full_name}", "]" do
- next
- end
- end
-end
diff --git a/lib/rdoc/code_object/top_level.rb b/lib/rdoc/code_object/top_level.rb
deleted file mode 100644
index b93e3802fc..0000000000
--- a/lib/rdoc/code_object/top_level.rb
+++ /dev/null
@@ -1,291 +0,0 @@
-# frozen_string_literal: true
-##
-# A TopLevel context is a representation of the contents of a single file
-
-class RDoc::TopLevel < RDoc::Context
-
- MARSHAL_VERSION = 0 # :nodoc:
-
- ##
- # This TopLevel's File::Stat struct
-
- attr_accessor :file_stat
-
- ##
- # Relative name of this file
-
- attr_accessor :relative_name
-
- ##
- # Absolute name of this file
-
- attr_accessor :absolute_name
-
- ##
- # All the classes or modules that were declared in
- # this file. These are assigned to either +#classes_hash+
- # or +#modules_hash+ once we know what they really are.
-
- attr_reader :classes_or_modules
-
- attr_accessor :diagram # :nodoc:
-
- ##
- # The parser class that processed this file
-
- attr_reader :parser
-
- ##
- # Creates a new TopLevel for the file at +absolute_name+. If documentation
- # is being generated outside the source dir +relative_name+ is relative to
- # the source directory.
-
- def initialize absolute_name, relative_name = absolute_name
- super()
- @name = nil
- @absolute_name = absolute_name
- @relative_name = relative_name
- @file_stat = File.stat(absolute_name) rescue nil # HACK for testing
- @diagram = nil
- @parser = nil
-
- @classes_or_modules = []
- end
-
- ##
- # Sets the parser for this toplevel context, also the store.
-
- def parser=(val)
- @parser = val
- @store.update_parser_of_file(absolute_name, val) if @store
- @parser
- end
-
- ##
- # An RDoc::TopLevel is equal to another with the same relative_name
-
- def == other
- self.class === other and @relative_name == other.relative_name
- end
-
- alias eql? ==
-
- ##
- # Adds +an_alias+ to +Object+ instead of +self+.
-
- def add_alias(an_alias)
- object_class.record_location self
- return an_alias unless @document_self
- object_class.add_alias an_alias
- end
-
- ##
- # Adds +constant+ to +Object+ instead of +self+.
-
- def add_constant constant
- object_class.record_location self
- return constant unless @document_self
- object_class.add_constant constant
- end
-
- ##
- # Adds +include+ to +Object+ instead of +self+.
-
- def add_include(include)
- object_class.record_location self
- return include unless @document_self
- object_class.add_include include
- end
-
- ##
- # Adds +method+ to +Object+ instead of +self+.
-
- def add_method(method)
- object_class.record_location self
- return method unless @document_self
- object_class.add_method method
- end
-
- ##
- # Adds class or module +mod+. Used in the building phase
- # by the Ruby parser.
-
- def add_to_classes_or_modules mod
- @classes_or_modules << mod
- end
-
- ##
- # Base name of this file
-
- def base_name
- File.basename @relative_name
- end
-
- alias name base_name
-
- ##
- # Only a TopLevel that contains text file) will be displayed. See also
- # RDoc::CodeObject#display?
-
- def display?
- text? and super
- end
-
- ##
- # See RDoc::TopLevel::find_class_or_module
- #--
- # TODO Why do we search through all classes/modules found, not just the
- # ones of this instance?
-
- def find_class_or_module name
- @store.find_class_or_module name
- end
-
- ##
- # Finds a class or module named +symbol+
-
- def find_local_symbol(symbol)
- find_class_or_module(symbol) || super
- end
-
- ##
- # Finds a module or class with +name+
-
- def find_module_named(name)
- find_class_or_module(name)
- end
-
- ##
- # Returns the relative name of this file
-
- def full_name
- @relative_name
- end
-
- ##
- # An RDoc::TopLevel has the same hash as another with the same
- # relative_name
-
- def hash
- @relative_name.hash
- end
-
- ##
- # URL for this with a +prefix+
-
- def http_url(prefix)
- path = [prefix, @relative_name.tr('.', '_')]
-
- File.join(*path.compact) + '.html'
- end
-
- def inspect # :nodoc:
- "#<%s:0x%x %p modules: %p classes: %p>" % [
- self.class, object_id,
- base_name,
- @modules.map { |n, m| m },
- @classes.map { |n, c| c }
- ]
- end
-
- ##
- # Time this file was last modified, if known
-
- def last_modified
- @file_stat ? file_stat.mtime : nil
- end
-
- ##
- # Dumps this TopLevel for use by ri. See also #marshal_load
-
- def marshal_dump
- [
- MARSHAL_VERSION,
- @relative_name,
- @parser,
- parse(@comment),
- ]
- end
-
- ##
- # Loads this TopLevel from +array+.
-
- def marshal_load array # :nodoc:
- initialize array[1]
-
- @parser = array[2]
- @comment = array[3]
-
- @file_stat = nil
- end
-
- ##
- # Returns the NormalClass "Object", creating it if not found.
- #
- # Records +self+ as a location in "Object".
-
- def object_class
- @object_class ||= begin
- oc = @store.find_class_named('Object') || add_class(RDoc::NormalClass, 'Object')
- oc.record_location self
- oc
- end
- end
-
- ##
- # Base name of this file without the extension
-
- def page_name
- basename = File.basename @relative_name
- basename =~ /\.(rb|rdoc|txt|md)$/i
-
- $` || basename
- end
-
- ##
- # Path to this file for use with HTML generator output.
-
- def path
- http_url @store.rdoc.generator.file_dir
- end
-
- def pretty_print q # :nodoc:
- q.group 2, "[#{self.class}: ", "]" do
- q.text "base name: #{base_name.inspect}"
- q.breakable
-
- items = @modules.map { |n, m| m }
- items.concat @modules.map { |n, c| c }
- q.seplist items do |mod| q.pp mod end
- end
- end
-
- ##
- # Search record used by RDoc::Generator::JsonIndex
-
- def search_record
- return unless @parser < RDoc::Parser::Text
-
- [
- page_name,
- '',
- page_name,
- '',
- path,
- '',
- snippet(@comment),
- ]
- end
-
- ##
- # Is this TopLevel from a text file instead of a source code file?
-
- def text?
- @parser and @parser.include? RDoc::Parser::Text
- end
-
- def to_s # :nodoc:
- "file #{full_name}"
- end
-
-end
diff --git a/lib/rdoc/comment.rb b/lib/rdoc/comment.rb
index 04ec226436..9e90999eac 100644
--- a/lib/rdoc/comment.rb
+++ b/lib/rdoc/comment.rb
@@ -6,8 +6,8 @@
# Each comment may have a different markup format set by #format=. By default
# 'rdoc' is used. The :markup: directive tells RDoc which format to use.
#
-# See RDoc::MarkupReference@Directive+for+Specifying+RDoc+Source+Format.
-
+# See RDoc::Markup@Other+directives for instructions on adding an alternate
+# format.
class RDoc::Comment
@@ -97,26 +97,42 @@ class RDoc::Comment
# comment. The difficulty is to make sure not to match lines starting
# with ARGF at the same indent, but that are after the first description
# paragraph.
- if /^(?<S> ((?!\n)\s)*+ (?# whitespaces except newline))
- :?call-seq:
- (?<B> \g<S>(?<N>\n|\z) (?# trailing spaces))?
- (?<seq>
- (\g<S>(?!\w)\S.*\g<N>)*
- (?>
- (?<H> \g<S>\w+ (?# ' # ARGF' in the example above))
- .*\g<N>)?
- (\g<S>\S.*\g<N> (?# other non-blank line))*+
- (\g<B>+(\k<H>.*\g<N> (?# ARGF.to_a lines))++)*+
- )
- (?m:^\s*$|\z)
- /x =~ @text
- seq = $~[:seq]
-
+ if @text =~ /^\s*:?call-seq:(.*?(?:\S).*?)^\s*$/m then
all_start, all_stop = $~.offset(0)
+ seq_start, seq_stop = $~.offset(1)
+
+ # we get the following lines that start with the leading word at the
+ # same indent, even if they have blank lines before
+ if $1 =~ /(^\s*\n)+^(\s*\w+)/m then
+ leading = $2 # ' * ARGF' in the example above
+ re = %r%
+ \A(
+ (^\s*\n)+
+ (^#{Regexp.escape leading}.*?\n)+
+ )+
+ ^\s*$
+ %xm
+
+ if @text[seq_stop..-1] =~ re then
+ all_stop = seq_stop + $~.offset(0).last
+ seq_stop = seq_stop + $~.offset(1).last
+ end
+ end
+
+ seq = @text[seq_start..seq_stop]
+ seq.gsub!(/^\s*(\S|\n)/m, '\1')
@text.slice! all_start...all_stop
- seq.gsub!(/^\s*/, '')
- method.call_seq = seq
+ method.call_seq = seq.chomp
+
+ else
+ regexp = /^\s*:?call-seq:(.*?)(^\s*$|\z)/m
+ if regexp =~ @text then
+ @text = @text.sub(regexp, '')
+ seq = $1
+ seq.gsub!(/^\s*/, '')
+ method.call_seq = seq
+ end
end
method
@@ -133,7 +149,12 @@ class RDoc::Comment
# HACK dubious
def encode! encoding
- @text = String.new @text, encoding: encoding
+ # TODO: Remove this condition after Ruby 2.2 EOL
+ if RUBY_VERSION < '2.3.0'
+ @text = @text.force_encoding encoding
+ else
+ @text = String.new @text, encoding: encoding
+ end
self
end
diff --git a/lib/rdoc/constant.rb b/lib/rdoc/constant.rb
new file mode 100644
index 0000000000..0c3d7505a1
--- /dev/null
+++ b/lib/rdoc/constant.rb
@@ -0,0 +1,187 @@
+# frozen_string_literal: true
+##
+# A constant
+
+class RDoc::Constant < RDoc::CodeObject
+
+ MARSHAL_VERSION = 0 # :nodoc:
+
+ ##
+ # Sets the module or class this is constant is an alias for.
+
+ attr_writer :is_alias_for
+
+ ##
+ # The constant's name
+
+ attr_accessor :name
+
+ ##
+ # The constant's value
+
+ attr_accessor :value
+
+ ##
+ # The constant's visibility
+
+ attr_accessor :visibility
+
+ ##
+ # Creates a new constant with +name+, +value+ and +comment+
+
+ def initialize(name, value, comment)
+ super()
+
+ @name = name
+ @value = value
+
+ @is_alias_for = nil
+ @visibility = :public
+
+ self.comment = comment
+ end
+
+ ##
+ # Constants are ordered by name
+
+ def <=> other
+ return unless self.class === other
+
+ [parent_name, name] <=> [other.parent_name, other.name]
+ end
+
+ ##
+ # Constants are equal when their #parent and #name is the same
+
+ def == other
+ self.class == other.class and
+ @parent == other.parent and
+ @name == other.name
+ end
+
+ ##
+ # A constant is documented if it has a comment, or is an alias
+ # for a documented class or module.
+
+ def documented?
+ return true if super
+ return false unless @is_alias_for
+ case @is_alias_for
+ when String then
+ found = @store.find_class_or_module @is_alias_for
+ return false unless found
+ @is_alias_for = found
+ end
+ @is_alias_for.documented?
+ end
+
+ ##
+ # Full constant name including namespace
+
+ def full_name
+ @full_name ||= "#{parent_name}::#{@name}"
+ end
+
+ ##
+ # The module or class this constant is an alias for
+
+ def is_alias_for
+ case @is_alias_for
+ when String then
+ found = @store.find_class_or_module @is_alias_for
+ @is_alias_for = found if found
+ @is_alias_for
+ else
+ @is_alias_for
+ end
+ end
+
+ def inspect # :nodoc:
+ "#<%s:0x%x %s::%s>" % [
+ self.class, object_id,
+ parent_name, @name,
+ ]
+ end
+
+ ##
+ # Dumps this Constant for use by ri. See also #marshal_load
+
+ def marshal_dump
+ alias_name = case found = is_alias_for
+ when RDoc::CodeObject then found.full_name
+ else found
+ end
+
+ [ MARSHAL_VERSION,
+ @name,
+ full_name,
+ @visibility,
+ alias_name,
+ parse(@comment),
+ @file.relative_name,
+ parent.name,
+ parent.class,
+ section.title,
+ ]
+ end
+
+ ##
+ # Loads this Constant from +array+. For a loaded Constant the following
+ # methods will return cached values:
+ #
+ # * #full_name
+ # * #parent_name
+
+ def marshal_load array
+ initialize array[1], nil, array[5]
+
+ @full_name = array[2]
+ @visibility = array[3] || :public
+ @is_alias_for = array[4]
+ # 5 handled above
+ # 6 handled below
+ @parent_name = array[7]
+ @parent_class = array[8]
+ @section_title = array[9]
+
+ @file = RDoc::TopLevel.new array[6]
+ end
+
+ ##
+ # Path to this constant for use with HTML generator output.
+
+ def path
+ "#{@parent.path}##{@name}"
+ end
+
+ def pretty_print q # :nodoc:
+ q.group 2, "[#{self.class.name} #{full_name}", "]" do
+ unless comment.empty? then
+ q.breakable
+ q.text "comment:"
+ q.breakable
+ q.pp @comment
+ end
+ end
+ end
+
+ ##
+ # Sets the store for this class or module and its contained code objects.
+
+ def store= store
+ super
+
+ @file = @store.add_file @file.full_name if @file
+ end
+
+ def to_s # :nodoc:
+ parent_name = parent ? parent.full_name : '(unknown)'
+ if is_alias_for
+ "constant #{parent_name}::#@name -> #{is_alias_for}"
+ else
+ "constant #{parent_name}::#@name"
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/context.rb b/lib/rdoc/context.rb
new file mode 100644
index 0000000000..c6edfb473c
--- /dev/null
+++ b/lib/rdoc/context.rb
@@ -0,0 +1,1264 @@
+# frozen_string_literal: true
+##
+# A Context is something that can hold modules, classes, methods, attributes,
+# aliases, requires, and includes. Classes, modules, and files are all
+# Contexts.
+
+class RDoc::Context < RDoc::CodeObject
+
+ include Comparable
+
+ ##
+ # Types of methods
+
+ TYPES = %w[class instance]
+
+ ##
+ # If a context has these titles it will be sorted in this order.
+
+ TOMDOC_TITLES = [nil, 'Public', 'Internal', 'Deprecated'] # :nodoc:
+ TOMDOC_TITLES_SORT = TOMDOC_TITLES.sort_by { |title| title.to_s } # :nodoc:
+
+ ##
+ # Class/module aliases
+
+ attr_reader :aliases
+
+ ##
+ # All attr* methods
+
+ attr_reader :attributes
+
+ ##
+ # Block params to be used in the next MethodAttr parsed under this context
+
+ attr_accessor :block_params
+
+ ##
+ # Constants defined
+
+ attr_reader :constants
+
+ ##
+ # Sets the current documentation section of documentation
+
+ attr_writer :current_section
+
+ ##
+ # Files this context is found in
+
+ attr_reader :in_files
+
+ ##
+ # Modules this context includes
+
+ attr_reader :includes
+
+ ##
+ # Modules this context is extended with
+
+ attr_reader :extends
+
+ ##
+ # Methods defined in this context
+
+ attr_reader :method_list
+
+ ##
+ # Name of this class excluding namespace. See also full_name
+
+ attr_reader :name
+
+ ##
+ # Files this context requires
+
+ attr_reader :requires
+
+ ##
+ # Use this section for the next method, attribute or constant added.
+
+ attr_accessor :temporary_section
+
+ ##
+ # Hash <tt>old_name => [aliases]</tt>, for aliases
+ # that haven't (yet) been resolved to a method/attribute.
+ # (Not to be confused with the aliases of the context.)
+
+ attr_accessor :unmatched_alias_lists
+
+ ##
+ # Aliases that could not be resolved.
+
+ attr_reader :external_aliases
+
+ ##
+ # Current visibility of this context
+
+ attr_accessor :visibility
+
+ ##
+ # Current visibility of this line
+
+ attr_writer :current_line_visibility
+
+ ##
+ # Hash of registered methods. Attributes are also registered here,
+ # twice if they are RW.
+
+ attr_reader :methods_hash
+
+ ##
+ # Params to be used in the next MethodAttr parsed under this context
+
+ attr_accessor :params
+
+ ##
+ # Hash of registered constants.
+
+ attr_reader :constants_hash
+
+ ##
+ # Creates an unnamed empty context with public current visibility
+
+ def initialize
+ super
+
+ @in_files = []
+
+ @name ||= "unknown"
+ @parent = nil
+ @visibility = :public
+
+ @current_section = Section.new self, nil, nil
+ @sections = { nil => @current_section }
+ @temporary_section = nil
+
+ @classes = {}
+ @modules = {}
+
+ initialize_methods_etc
+ end
+
+ ##
+ # Sets the defaults for methods and so-forth
+
+ def initialize_methods_etc
+ @method_list = []
+ @attributes = []
+ @aliases = []
+ @requires = []
+ @includes = []
+ @extends = []
+ @constants = []
+ @external_aliases = []
+ @current_line_visibility = nil
+
+ # This Hash maps a method name to a list of unmatched aliases (aliases of
+ # a method not yet encountered).
+ @unmatched_alias_lists = {}
+
+ @methods_hash = {}
+ @constants_hash = {}
+
+ @params = nil
+
+ @store ||= nil
+ end
+
+ ##
+ # Contexts are sorted by full_name
+
+ def <=>(other)
+ return nil unless RDoc::CodeObject === other
+
+ full_name <=> other.full_name
+ end
+
+ ##
+ # Adds an item of type +klass+ with the given +name+ and +comment+ to the
+ # context.
+ #
+ # Currently only RDoc::Extend and RDoc::Include are supported.
+
+ def add klass, name, comment
+ if RDoc::Extend == klass then
+ ext = RDoc::Extend.new name, comment
+ add_extend ext
+ elsif RDoc::Include == klass then
+ incl = RDoc::Include.new name, comment
+ add_include incl
+ else
+ raise NotImplementedError, "adding a #{klass} is not implemented"
+ end
+ end
+
+ ##
+ # Adds +an_alias+ that is automatically resolved
+
+ def add_alias an_alias
+ return an_alias unless @document_self
+
+ method_attr = find_method(an_alias.old_name, an_alias.singleton) ||
+ find_attribute(an_alias.old_name, an_alias.singleton)
+
+ if method_attr then
+ method_attr.add_alias an_alias, self
+ else
+ add_to @external_aliases, an_alias
+ unmatched_alias_list =
+ @unmatched_alias_lists[an_alias.pretty_old_name] ||= []
+ unmatched_alias_list.push an_alias
+ end
+
+ an_alias
+ end
+
+ ##
+ # Adds +attribute+ if not already there. If it is (as method(s) or attribute),
+ # updates the comment if it was empty.
+ #
+ # The attribute is registered only if it defines a new method.
+ # For instance, <tt>attr_reader :foo</tt> will not be registered
+ # if method +foo+ exists, but <tt>attr_accessor :foo</tt> will be registered
+ # if method +foo+ exists, but <tt>foo=</tt> does not.
+
+ def add_attribute attribute
+ return attribute unless @document_self
+
+ # mainly to check for redefinition of an attribute as a method
+ # TODO find a policy for 'attr_reader :foo' + 'def foo=()'
+ register = false
+
+ key = nil
+
+ if attribute.rw.index 'R' then
+ key = attribute.pretty_name
+ known = @methods_hash[key]
+
+ if known then
+ known.comment = attribute.comment if known.comment.empty?
+ elsif registered = @methods_hash[attribute.pretty_name + '='] and
+ RDoc::Attr === registered then
+ registered.rw = 'RW'
+ else
+ @methods_hash[key] = attribute
+ register = true
+ end
+ end
+
+ if attribute.rw.index 'W' then
+ key = attribute.pretty_name + '='
+ known = @methods_hash[key]
+
+ if known then
+ known.comment = attribute.comment if known.comment.empty?
+ elsif registered = @methods_hash[attribute.pretty_name] and
+ RDoc::Attr === registered then
+ registered.rw = 'RW'
+ else
+ @methods_hash[key] = attribute
+ register = true
+ end
+ end
+
+ if register then
+ attribute.visibility = @visibility
+ add_to @attributes, attribute
+ resolve_aliases attribute
+ end
+
+ attribute
+ end
+
+ ##
+ # Adds a class named +given_name+ with +superclass+.
+ #
+ # Both +given_name+ and +superclass+ may contain '::', and are
+ # interpreted relative to the +self+ context. This allows handling correctly
+ # examples like these:
+ # class RDoc::Gauntlet < Gauntlet
+ # module Mod
+ # class Object # implies < ::Object
+ # class SubObject < Object # this is _not_ ::Object
+ #
+ # Given <tt>class Container::Item</tt> RDoc assumes +Container+ is a module
+ # unless it later sees <tt>class Container</tt>. +add_class+ automatically
+ # upgrades +given_name+ to a class in this case.
+
+ def add_class class_type, given_name, superclass = '::Object'
+ # superclass +nil+ is passed by the C parser in the following cases:
+ # - registering Object in 1.8 (correct)
+ # - registering BasicObject in 1.9 (correct)
+ # - registering RubyVM in 1.9 in iseq.c (incorrect: < Object in vm.c)
+ #
+ # If we later find a superclass for a registered class with a nil
+ # superclass, we must honor it.
+
+ # find the name & enclosing context
+ if given_name =~ /^:+(\w+)$/ then
+ full_name = $1
+ enclosing = top_level
+ name = full_name.split(/:+/).last
+ else
+ full_name = child_name given_name
+
+ if full_name =~ /^(.+)::(\w+)$/ then
+ name = $2
+ ename = $1
+ enclosing = @store.classes_hash[ename] || @store.modules_hash[ename]
+ # HACK: crashes in actionpack/lib/action_view/helpers/form_helper.rb (metaprogramming)
+ unless enclosing then
+ # try the given name at top level (will work for the above example)
+ enclosing = @store.classes_hash[given_name] ||
+ @store.modules_hash[given_name]
+ return enclosing if enclosing
+ # not found: create the parent(s)
+ names = ename.split('::')
+ enclosing = self
+ names.each do |n|
+ enclosing = enclosing.classes_hash[n] ||
+ enclosing.modules_hash[n] ||
+ enclosing.add_module(RDoc::NormalModule, n)
+ end
+ end
+ else
+ name = full_name
+ enclosing = self
+ end
+ end
+
+ # fix up superclass
+ if full_name == 'BasicObject' then
+ superclass = nil
+ elsif full_name == 'Object' then
+ superclass = '::BasicObject'
+ end
+
+ # find the superclass full name
+ if superclass then
+ if superclass =~ /^:+/ then
+ superclass = $' #'
+ else
+ if superclass =~ /^(\w+):+(.+)$/ then
+ suffix = $2
+ mod = find_module_named($1)
+ superclass = mod.full_name + '::' + suffix if mod
+ else
+ mod = find_module_named(superclass)
+ superclass = mod.full_name if mod
+ end
+ end
+
+ # did we believe it was a module?
+ mod = @store.modules_hash.delete superclass
+
+ upgrade_to_class mod, RDoc::NormalClass, mod.parent if mod
+
+ # e.g., Object < Object
+ superclass = nil if superclass == full_name
+ end
+
+ klass = @store.classes_hash[full_name]
+
+ if klass then
+ # if TopLevel, it may not be registered in the classes:
+ enclosing.classes_hash[name] = klass
+
+ # update the superclass if needed
+ if superclass then
+ existing = klass.superclass
+ existing = existing.full_name unless existing.is_a?(String) if existing
+ if existing.nil? ||
+ (existing == 'Object' && superclass != 'Object') then
+ klass.superclass = superclass
+ end
+ end
+ else
+ # this is a new class
+ mod = @store.modules_hash.delete full_name
+
+ if mod then
+ klass = upgrade_to_class mod, RDoc::NormalClass, enclosing
+
+ klass.superclass = superclass unless superclass.nil?
+ else
+ klass = class_type.new name, superclass
+
+ enclosing.add_class_or_module(klass, enclosing.classes_hash,
+ @store.classes_hash)
+ end
+ end
+
+ klass.parent = self
+
+ klass
+ end
+
+ ##
+ # Adds the class or module +mod+ to the modules or
+ # classes Hash +self_hash+, and to +all_hash+ (either
+ # <tt>TopLevel::modules_hash</tt> or <tt>TopLevel::classes_hash</tt>),
+ # unless #done_documenting is +true+. Sets the #parent of +mod+
+ # to +self+, and its #section to #current_section. Returns +mod+.
+
+ def add_class_or_module mod, self_hash, all_hash
+ mod.section = current_section # TODO declaring context? something is
+ # wrong here...
+ mod.parent = self
+ mod.full_name = nil
+ mod.store = @store
+
+ unless @done_documenting then
+ self_hash[mod.name] = mod
+ # this must be done AFTER adding mod to its parent, so that the full
+ # name is correct:
+ all_hash[mod.full_name] = mod
+ if @store.unmatched_constant_alias[mod.full_name] then
+ to, file = @store.unmatched_constant_alias[mod.full_name]
+ add_module_alias mod, mod.name, to, file
+ end
+ end
+
+ mod
+ end
+
+ ##
+ # Adds +constant+ if not already there. If it is, updates the comment,
+ # value and/or is_alias_for of the known constant if they were empty/nil.
+
+ def add_constant constant
+ return constant unless @document_self
+
+ # HACK: avoid duplicate 'PI' & 'E' in math.c (1.8.7 source code)
+ # (this is a #ifdef: should be handled by the C parser)
+ known = @constants_hash[constant.name]
+
+ if known then
+ known.comment = constant.comment if known.comment.empty?
+
+ known.value = constant.value if
+ known.value.nil? or known.value.strip.empty?
+
+ known.is_alias_for ||= constant.is_alias_for
+ else
+ @constants_hash[constant.name] = constant
+ add_to @constants, constant
+ end
+
+ constant
+ end
+
+ ##
+ # Adds included module +include+ which should be an RDoc::Include
+
+ def add_include include
+ add_to @includes, include
+
+ include
+ end
+
+ ##
+ # Adds extension module +ext+ which should be an RDoc::Extend
+
+ def add_extend ext
+ add_to @extends, ext
+
+ ext
+ end
+
+ ##
+ # Adds +method+ if not already there. If it is (as method or attribute),
+ # updates the comment if it was empty.
+
+ def add_method method
+ return method unless @document_self
+
+ # HACK: avoid duplicate 'new' in io.c & struct.c (1.8.7 source code)
+ key = method.pretty_name
+ known = @methods_hash[key]
+
+ if known then
+ if @store then # otherwise we are loading
+ known.comment = method.comment if known.comment.empty?
+ previously = ", previously in #{known.file}" unless
+ method.file == known.file
+ @store.rdoc.options.warn \
+ "Duplicate method #{known.full_name} in #{method.file}#{previously}"
+ end
+ else
+ @methods_hash[key] = method
+ if @current_line_visibility
+ method.visibility, @current_line_visibility = @current_line_visibility, nil
+ else
+ method.visibility = @visibility
+ end
+ add_to @method_list, method
+ resolve_aliases method
+ end
+
+ method
+ end
+
+ ##
+ # Adds a module named +name+. If RDoc already knows +name+ is a class then
+ # that class is returned instead. See also #add_class.
+
+ def add_module(class_type, name)
+ mod = @classes[name] || @modules[name]
+ return mod if mod
+
+ full_name = child_name name
+ mod = @store.modules_hash[full_name] || class_type.new(name)
+
+ add_class_or_module mod, @modules, @store.modules_hash
+ end
+
+ ##
+ # Adds a module by +RDoc::NormalModule+ instance. See also #add_module.
+
+ def add_module_by_normal_module(mod)
+ add_class_or_module mod, @modules, @store.modules_hash
+ end
+
+ ##
+ # Adds an alias from +from+ (a class or module) to +name+ which was defined
+ # in +file+.
+
+ def add_module_alias from, from_name, to, file
+ return from if @done_documenting
+
+ to_full_name = child_name to.name
+
+ # if we already know this name, don't register an alias:
+ # see the metaprogramming in lib/active_support/basic_object.rb,
+ # where we already know BasicObject is a class when we find
+ # BasicObject = BlankSlate
+ return from if @store.find_class_or_module to_full_name
+
+ unless from
+ @store.unmatched_constant_alias[child_name(from_name)] = [to, file]
+ return to
+ end
+
+ new_to = from.dup
+ new_to.name = to.name
+ new_to.full_name = nil
+
+ if new_to.module? then
+ @store.modules_hash[to_full_name] = new_to
+ @modules[to.name] = new_to
+ else
+ @store.classes_hash[to_full_name] = new_to
+ @classes[to.name] = new_to
+ end
+
+ # Registers a constant for this alias. The constant value and comment
+ # will be updated later, when the Ruby parser adds the constant
+ const = RDoc::Constant.new to.name, nil, new_to.comment
+ const.record_location file
+ const.is_alias_for = from
+ add_constant const
+
+ new_to
+ end
+
+ ##
+ # Adds +require+ to this context's top level
+
+ def add_require(require)
+ return require unless @document_self
+
+ if RDoc::TopLevel === self then
+ add_to @requires, require
+ else
+ parent.add_require require
+ end
+ end
+
+ ##
+ # Returns a section with +title+, creating it if it doesn't already exist.
+ # +comment+ will be appended to the section's comment.
+ #
+ # A section with a +title+ of +nil+ will return the default section.
+ #
+ # See also RDoc::Context::Section
+
+ def add_section title, comment = nil
+ if section = @sections[title] then
+ section.add_comment comment if comment
+ else
+ section = Section.new self, title, comment
+ @sections[title] = section
+ end
+
+ section
+ end
+
+ ##
+ # Adds +thing+ to the collection +array+
+
+ def add_to array, thing
+ array << thing if @document_self
+
+ thing.parent = self
+ thing.store = @store if @store
+ thing.section = current_section
+ end
+
+ ##
+ # Is there any content?
+ #
+ # This means any of: comment, aliases, methods, attributes, external
+ # aliases, require, constant.
+ #
+ # Includes and extends are also checked unless <tt>includes == false</tt>.
+
+ def any_content(includes = true)
+ @any_content ||= !(
+ @comment.empty? &&
+ @method_list.empty? &&
+ @attributes.empty? &&
+ @aliases.empty? &&
+ @external_aliases.empty? &&
+ @requires.empty? &&
+ @constants.empty?
+ )
+ @any_content || (includes && !(@includes + @extends).empty? )
+ end
+
+ ##
+ # Creates the full name for a child with +name+
+
+ def child_name name
+ if name =~ /^:+/
+ $' #'
+ elsif RDoc::TopLevel === self then
+ name
+ else
+ "#{self.full_name}::#{name}"
+ end
+ end
+
+ ##
+ # Class attributes
+
+ def class_attributes
+ @class_attributes ||= attributes.select { |a| a.singleton }
+ end
+
+ ##
+ # Class methods
+
+ def class_method_list
+ @class_method_list ||= method_list.select { |a| a.singleton }
+ end
+
+ ##
+ # Array of classes in this context
+
+ def classes
+ @classes.values
+ end
+
+ ##
+ # All classes and modules in this namespace
+
+ def classes_and_modules
+ classes + modules
+ end
+
+ ##
+ # Hash of classes keyed by class name
+
+ def classes_hash
+ @classes
+ end
+
+ ##
+ # The current documentation section that new items will be added to. If
+ # temporary_section is available it will be used.
+
+ def current_section
+ if section = @temporary_section then
+ @temporary_section = nil
+ else
+ section = @current_section
+ end
+
+ section
+ end
+
+ ##
+ # Is part of this thing was defined in +file+?
+
+ def defined_in?(file)
+ @in_files.include?(file)
+ end
+
+ def display(method_attr) # :nodoc:
+ if method_attr.is_a? RDoc::Attr
+ "#{method_attr.definition} #{method_attr.pretty_name}"
+ else
+ "method #{method_attr.pretty_name}"
+ end
+ end
+
+ ##
+ # Iterator for ancestors for duck-typing. Does nothing. See
+ # RDoc::ClassModule#each_ancestor.
+ #
+ # This method exists to make it easy to work with Context subclasses that
+ # aren't part of RDoc.
+
+ def each_ancestor # :nodoc:
+ end
+
+ ##
+ # Iterator for attributes
+
+ def each_attribute # :yields: attribute
+ @attributes.each { |a| yield a }
+ end
+
+ ##
+ # Iterator for classes and modules
+
+ def each_classmodule(&block) # :yields: module
+ classes_and_modules.sort.each(&block)
+ end
+
+ ##
+ # Iterator for constants
+
+ def each_constant # :yields: constant
+ @constants.each {|c| yield c}
+ end
+
+ ##
+ # Iterator for included modules
+
+ def each_include # :yields: include
+ @includes.each do |i| yield i end
+ end
+
+ ##
+ # Iterator for extension modules
+
+ def each_extend # :yields: extend
+ @extends.each do |e| yield e end
+ end
+
+ ##
+ # Iterator for methods
+
+ def each_method # :yields: method
+ return enum_for __method__ unless block_given?
+
+ @method_list.sort.each { |m| yield m }
+ end
+
+ ##
+ # Iterator for each section's contents sorted by title. The +section+, the
+ # section's +constants+ and the sections +attributes+ are yielded. The
+ # +constants+ and +attributes+ collections are sorted.
+ #
+ # To retrieve methods in a section use #methods_by_type with the optional
+ # +section+ parameter.
+ #
+ # NOTE: Do not edit collections yielded by this method
+
+ def each_section # :yields: section, constants, attributes
+ return enum_for __method__ unless block_given?
+
+ constants = @constants.group_by do |constant| constant.section end
+ attributes = @attributes.group_by do |attribute| attribute.section end
+
+ constants.default = []
+ attributes.default = []
+
+ sort_sections.each do |section|
+ yield section, constants[section].select(&:display?).sort, attributes[section].select(&:display?).sort
+ end
+ end
+
+ ##
+ # Finds an attribute +name+ with singleton value +singleton+.
+
+ def find_attribute(name, singleton)
+ name = $1 if name =~ /^(.*)=$/
+ @attributes.find { |a| a.name == name && a.singleton == singleton }
+ end
+
+ ##
+ # Finds an attribute with +name+ in this context
+
+ def find_attribute_named(name)
+ case name
+ when /\A#/ then
+ find_attribute name[1..-1], false
+ when /\A::/ then
+ find_attribute name[2..-1], true
+ else
+ @attributes.find { |a| a.name == name }
+ end
+ end
+
+ ##
+ # Finds a class method with +name+ in this context
+
+ def find_class_method_named(name)
+ @method_list.find { |meth| meth.singleton && meth.name == name }
+ end
+
+ ##
+ # Finds a constant with +name+ in this context
+
+ def find_constant_named(name)
+ @constants.find do |m|
+ m.name == name || m.full_name == name
+ end
+ end
+
+ ##
+ # Find a module at a higher scope
+
+ def find_enclosing_module_named(name)
+ parent && parent.find_module_named(name)
+ end
+
+ ##
+ # Finds an external alias +name+ with singleton value +singleton+.
+
+ def find_external_alias(name, singleton)
+ @external_aliases.find { |m| m.name == name && m.singleton == singleton }
+ end
+
+ ##
+ # Finds an external alias with +name+ in this context
+
+ def find_external_alias_named(name)
+ case name
+ when /\A#/ then
+ find_external_alias name[1..-1], false
+ when /\A::/ then
+ find_external_alias name[2..-1], true
+ else
+ @external_aliases.find { |a| a.name == name }
+ end
+ end
+
+ ##
+ # Finds a file with +name+ in this context
+
+ def find_file_named name
+ @store.find_file_named name
+ end
+
+ ##
+ # Finds an instance method with +name+ in this context
+
+ def find_instance_method_named(name)
+ @method_list.find { |meth| !meth.singleton && meth.name == name }
+ end
+
+ ##
+ # Finds a method, constant, attribute, external alias, module or file
+ # named +symbol+ in this context.
+
+ def find_local_symbol(symbol)
+ find_method_named(symbol) or
+ find_constant_named(symbol) or
+ find_attribute_named(symbol) or
+ find_external_alias_named(symbol) or
+ find_module_named(symbol) or
+ find_file_named(symbol)
+ end
+
+ ##
+ # Finds a method named +name+ with singleton value +singleton+.
+
+ def find_method(name, singleton)
+ @method_list.find { |m|
+ if m.singleton
+ m.name == name && m.singleton == singleton
+ else
+ m.name == name && !m.singleton && !singleton
+ end
+ }
+ end
+
+ ##
+ # Finds a instance or module method with +name+ in this context
+
+ def find_method_named(name)
+ case name
+ when /\A#/ then
+ find_method name[1..-1], false
+ when /\A::/ then
+ find_method name[2..-1], true
+ else
+ @method_list.find { |meth| meth.name == name }
+ end
+ end
+
+ ##
+ # Find a module with +name+ using ruby's scoping rules
+
+ def find_module_named(name)
+ res = @modules[name] || @classes[name]
+ return res if res
+ return self if self.name == name
+ find_enclosing_module_named name
+ end
+
+ ##
+ # Look up +symbol+, first as a module, then as a local symbol.
+
+ def find_symbol(symbol)
+ find_symbol_module(symbol) || find_local_symbol(symbol)
+ end
+
+ ##
+ # Look up a module named +symbol+.
+
+ def find_symbol_module(symbol)
+ result = nil
+
+ # look for a class or module 'symbol'
+ case symbol
+ when /^::/ then
+ result = @store.find_class_or_module symbol
+ when /^(\w+):+(.+)$/
+ suffix = $2
+ top = $1
+ searched = self
+ while searched do
+ mod = searched.find_module_named(top)
+ break unless mod
+ result = @store.find_class_or_module "#{mod.full_name}::#{suffix}"
+ break if result || searched.is_a?(RDoc::TopLevel)
+ searched = searched.parent
+ end
+ else
+ searched = self
+ while searched do
+ result = searched.find_module_named(symbol)
+ break if result || searched.is_a?(RDoc::TopLevel)
+ searched = searched.parent
+ end
+ end
+
+ result
+ end
+
+ ##
+ # The full name for this context. This method is overridden by subclasses.
+
+ def full_name
+ '(unknown)'
+ end
+
+ ##
+ # Does this context and its methods and constants all have documentation?
+ #
+ # (Yes, fully documented doesn't mean everything.)
+
+ def fully_documented?
+ documented? and
+ attributes.all? { |a| a.documented? } and
+ method_list.all? { |m| m.documented? } and
+ constants.all? { |c| c.documented? }
+ end
+
+ ##
+ # URL for this with a +prefix+
+
+ def http_url(prefix)
+ path = name_for_path
+ path = path.gsub(/<<\s*(\w*)/, 'from-\1') if path =~ /<</
+ path = [prefix] + path.split('::')
+
+ File.join(*path.compact) + '.html'
+ end
+
+ ##
+ # Instance attributes
+
+ def instance_attributes
+ @instance_attributes ||= attributes.reject { |a| a.singleton }
+ end
+
+ ##
+ # Instance methods
+
+ def instance_methods
+ @instance_methods ||= method_list.reject { |a| a.singleton }
+ end
+
+ ##
+ # Instance methods
+ #--
+ # TODO remove this later
+
+ def instance_method_list
+ warn '#instance_method_list is obsoleted, please use #instance_methods'
+ @instance_methods ||= method_list.reject { |a| a.singleton }
+ end
+
+ ##
+ # Breaks method_list into a nested hash by type (<tt>'class'</tt> or
+ # <tt>'instance'</tt>) and visibility (+:public+, +:protected+, +:private+).
+ #
+ # If +section+ is provided only methods in that RDoc::Context::Section will
+ # be returned.
+
+ def methods_by_type section = nil
+ methods = {}
+
+ TYPES.each do |type|
+ visibilities = {}
+ RDoc::VISIBILITIES.each do |vis|
+ visibilities[vis] = []
+ end
+
+ methods[type] = visibilities
+ end
+
+ each_method do |method|
+ next if section and not method.section == section
+ methods[method.type][method.visibility] << method
+ end
+
+ methods
+ end
+
+ ##
+ # Yields AnyMethod and Attr entries matching the list of names in +methods+.
+
+ def methods_matching(methods, singleton = false, &block)
+ (@method_list + @attributes).each do |m|
+ yield m if methods.include?(m.name) and m.singleton == singleton
+ end
+
+ each_ancestor do |parent|
+ parent.methods_matching(methods, singleton, &block)
+ end
+ end
+
+ ##
+ # Array of modules in this context
+
+ def modules
+ @modules.values
+ end
+
+ ##
+ # Hash of modules keyed by module name
+
+ def modules_hash
+ @modules
+ end
+
+ ##
+ # Name to use to generate the url.
+ # <tt>#full_name</tt> by default.
+
+ def name_for_path
+ full_name
+ end
+
+ ##
+ # Changes the visibility for new methods to +visibility+
+
+ def ongoing_visibility=(visibility)
+ @visibility = visibility
+ end
+
+ ##
+ # Record +top_level+ as a file +self+ is in.
+
+ def record_location(top_level)
+ @in_files << top_level unless @in_files.include?(top_level)
+ end
+
+ ##
+ # Should we remove this context from the documentation?
+ #
+ # The answer is yes if:
+ # * #received_nodoc is +true+
+ # * #any_content is +false+ (not counting includes)
+ # * All #includes are modules (not a string), and their module has
+ # <tt>#remove_from_documentation? == true</tt>
+ # * All classes and modules have <tt>#remove_from_documentation? == true</tt>
+
+ def remove_from_documentation?
+ @remove_from_documentation ||=
+ @received_nodoc &&
+ !any_content(false) &&
+ @includes.all? { |i| !i.module.is_a?(String) && i.module.remove_from_documentation? } &&
+ classes_and_modules.all? { |cm| cm.remove_from_documentation? }
+ end
+
+ ##
+ # Removes methods and attributes with a visibility less than +min_visibility+.
+ #--
+ # TODO mark the visibility of attributes in the template (if not public?)
+
+ def remove_invisible min_visibility
+ return if [:private, :nodoc].include? min_visibility
+ remove_invisible_in @method_list, min_visibility
+ remove_invisible_in @attributes, min_visibility
+ remove_invisible_in @constants, min_visibility
+ end
+
+ ##
+ # Only called when min_visibility == :public or :private
+
+ def remove_invisible_in array, min_visibility # :nodoc:
+ if min_visibility == :public then
+ array.reject! { |e|
+ e.visibility != :public and not e.force_documentation
+ }
+ else
+ array.reject! { |e|
+ e.visibility == :private and not e.force_documentation
+ }
+ end
+ end
+
+ ##
+ # Tries to resolve unmatched aliases when a method or attribute has just
+ # been added.
+
+ def resolve_aliases added
+ # resolve any pending unmatched aliases
+ key = added.pretty_name
+ unmatched_alias_list = @unmatched_alias_lists[key]
+ return unless unmatched_alias_list
+ unmatched_alias_list.each do |unmatched_alias|
+ added.add_alias unmatched_alias, self
+ @external_aliases.delete unmatched_alias
+ end
+ @unmatched_alias_lists.delete key
+ end
+
+ ##
+ # Returns RDoc::Context::Section objects referenced in this context for use
+ # in a table of contents.
+
+ def section_contents
+ used_sections = {}
+
+ each_method do |method|
+ next unless method.display?
+
+ used_sections[method.section] = true
+ end
+
+ # order found sections
+ sections = sort_sections.select do |section|
+ used_sections[section]
+ end
+
+ # only the default section is used
+ return [] if
+ sections.length == 1 and not sections.first.title
+
+ sections
+ end
+
+ ##
+ # Sections in this context
+
+ def sections
+ @sections.values
+ end
+
+ def sections_hash # :nodoc:
+ @sections
+ end
+
+ ##
+ # Sets the current section to a section with +title+. See also #add_section
+
+ def set_current_section title, comment
+ @current_section = add_section title, comment
+ end
+
+ ##
+ # Given an array +methods+ of method names, set the visibility of each to
+ # +visibility+
+
+ def set_visibility_for(methods, visibility, singleton = false)
+ methods_matching methods, singleton do |m|
+ m.visibility = visibility
+ end
+ end
+
+ ##
+ # Given an array +names+ of constants, set the visibility of each constant to
+ # +visibility+
+
+ def set_constant_visibility_for(names, visibility)
+ names.each do |name|
+ constant = @constants_hash[name] or next
+ constant.visibility = visibility
+ end
+ end
+
+ ##
+ # Sorts sections alphabetically (default) or in TomDoc fashion (none,
+ # Public, Internal, Deprecated)
+
+ def sort_sections
+ titles = @sections.map { |title, _| title }
+
+ if titles.length > 1 and
+ TOMDOC_TITLES_SORT ==
+ (titles | TOMDOC_TITLES).sort_by { |title| title.to_s } then
+ @sections.values_at(*TOMDOC_TITLES).compact
+ else
+ @sections.sort_by { |title, _|
+ title.to_s
+ }.map { |_, section|
+ section
+ }
+ end
+ end
+
+ def to_s # :nodoc:
+ "#{self.class.name} #{self.full_name}"
+ end
+
+ ##
+ # Return the TopLevel that owns us
+ #--
+ # FIXME we can be 'owned' by several TopLevel (see #record_location &
+ # #in_files)
+
+ def top_level
+ return @top_level if defined? @top_level
+ @top_level = self
+ @top_level = @top_level.parent until RDoc::TopLevel === @top_level
+ @top_level
+ end
+
+ ##
+ # Upgrades NormalModule +mod+ in +enclosing+ to a +class_type+
+
+ def upgrade_to_class mod, class_type, enclosing
+ enclosing.modules_hash.delete mod.name
+
+ klass = RDoc::ClassModule.from_module class_type, mod
+ klass.store = @store
+
+ # if it was there, then we keep it even if done_documenting
+ @store.classes_hash[mod.full_name] = klass
+ enclosing.classes_hash[mod.name] = klass
+
+ klass
+ end
+
+ autoload :Section, "#{__dir__}/context/section"
+
+end
diff --git a/lib/rdoc/context/section.rb b/lib/rdoc/context/section.rb
new file mode 100644
index 0000000000..c316efe99f
--- /dev/null
+++ b/lib/rdoc/context/section.rb
@@ -0,0 +1,234 @@
+# frozen_string_literal: true
+require 'cgi/util'
+
+##
+# A section of documentation like:
+#
+# # :section: The title
+# # The body
+#
+# Sections can be referenced multiple times and will be collapsed into a
+# single section.
+
+class RDoc::Context::Section
+
+ include RDoc::Text
+
+ MARSHAL_VERSION = 0 # :nodoc:
+
+ ##
+ # Section comment
+
+ attr_reader :comment
+
+ ##
+ # Section comments
+
+ attr_reader :comments
+
+ ##
+ # Context this Section lives in
+
+ attr_reader :parent
+
+ ##
+ # Section title
+
+ attr_reader :title
+
+ ##
+ # Creates a new section with +title+ and +comment+
+
+ def initialize parent, title, comment
+ @parent = parent
+ @title = title ? title.strip : title
+
+ @comments = []
+
+ add_comment comment
+ end
+
+ ##
+ # Sections are equal when they have the same #title
+
+ def == other
+ self.class === other and @title == other.title
+ end
+
+ alias eql? ==
+
+ ##
+ # Adds +comment+ to this section
+
+ def add_comment comment
+ comment = extract_comment comment
+
+ return if comment.empty?
+
+ case comment
+ when RDoc::Comment then
+ @comments << comment
+ when RDoc::Markup::Document then
+ @comments.concat comment.parts
+ when Array then
+ @comments.concat comment
+ else
+ raise TypeError, "unknown comment type: #{comment.inspect}"
+ end
+ end
+
+ ##
+ # Anchor reference for linking to this section
+
+ def aref
+ title = @title || '[untitled]'
+
+ CGI.escape(title).gsub('%', '-').sub(/^-/, '')
+ end
+
+ ##
+ # Extracts the comment for this section from the original comment block.
+ # If the first line contains :section:, strip it and use the rest.
+ # Otherwise remove lines up to the line containing :section:, and look
+ # for those lines again at the end and remove them. This lets us write
+ #
+ # # :section: The title
+ # # The body
+
+ def extract_comment comment
+ case comment
+ when Array then
+ comment.map do |c|
+ extract_comment c
+ end
+ when nil
+ RDoc::Comment.new ''
+ when RDoc::Comment then
+ if comment.text =~ /^#[ \t]*:section:.*\n/ then
+ start = $`
+ rest = $'
+
+ comment.text = if start.empty? then
+ rest
+ else
+ rest.sub(/#{start.chomp}\Z/, '')
+ end
+ end
+
+ comment
+ when RDoc::Markup::Document then
+ comment
+ else
+ raise TypeError, "unknown comment #{comment.inspect}"
+ end
+ end
+
+ def inspect # :nodoc:
+ "#<%s:0x%x %p>" % [self.class, object_id, title]
+ end
+
+ def hash # :nodoc:
+ @title.hash
+ end
+
+ ##
+ # The files comments in this section come from
+
+ def in_files
+ return [] if @comments.empty?
+
+ case @comments
+ when Array then
+ @comments.map do |comment|
+ comment.file
+ end
+ when RDoc::Markup::Document then
+ @comment.parts.map do |document|
+ document.file
+ end
+ else
+ raise RDoc::Error, "BUG: unknown comment class #{@comments.class}"
+ end
+ end
+
+ ##
+ # Serializes this Section. The title and parsed comment are saved, but not
+ # the section parent which must be restored manually.
+
+ def marshal_dump
+ [
+ MARSHAL_VERSION,
+ @title,
+ parse,
+ ]
+ end
+
+ ##
+ # De-serializes this Section. The section parent must be restored manually.
+
+ def marshal_load array
+ @parent = nil
+
+ @title = array[1]
+ @comments = array[2]
+ end
+
+ ##
+ # Parses +comment_location+ into an RDoc::Markup::Document composed of
+ # multiple RDoc::Markup::Documents with their file set.
+
+ def parse
+ case @comments
+ when String then
+ super
+ when Array then
+ docs = @comments.map do |comment, location|
+ doc = super comment
+ doc.file = location if location
+ doc
+ end
+
+ RDoc::Markup::Document.new(*docs)
+ when RDoc::Comment then
+ doc = super @comments.text, comments.format
+ doc.file = @comments.location
+ doc
+ when RDoc::Markup::Document then
+ return @comments
+ else
+ raise ArgumentError, "unknown comment class #{comments.class}"
+ end
+ end
+
+ ##
+ # The section's title, or 'Top Section' if the title is nil.
+ #
+ # This is used by the table of contents template so the name is silly.
+
+ def plain_html
+ @title || 'Top Section'
+ end
+
+ ##
+ # Removes a comment from this section if it is from the same file as
+ # +comment+
+
+ def remove_comment comment
+ return if @comments.empty?
+
+ case @comments
+ when Array then
+ @comments.delete_if do |my_comment|
+ my_comment.file == comment.file
+ end
+ when RDoc::Markup::Document then
+ @comments.parts.delete_if do |document|
+ document.file == comment.file.name
+ end
+ else
+ raise RDoc::Error, "BUG: unknown comment class #{@comments.class}"
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/cross_reference.rb b/lib/rdoc/cross_reference.rb
index 4e011219e8..319bbc02ac 100644
--- a/lib/rdoc/cross_reference.rb
+++ b/lib/rdoc/cross_reference.rb
@@ -131,9 +131,6 @@ class RDoc::CrossReference
@seen = {}
end
- ##
- # Returns a method reference to +name+.
-
def resolve_method name
ref = nil
@@ -226,3 +223,4 @@ class RDoc::CrossReference
end
end
+
diff --git a/lib/rdoc/encoding.rb b/lib/rdoc/encoding.rb
index 67e190f782..cf60badd24 100644
--- a/lib/rdoc/encoding.rb
+++ b/lib/rdoc/encoding.rb
@@ -86,6 +86,17 @@ module RDoc::Encoding
nil
end
+ def self.remove_frozen_string_literal string
+ string =~ /\A(?:#!.*\n)?(.*\n)/
+ first_line = $1
+
+ if first_line =~ /\A# +frozen[-_]string[-_]literal[=:].+$/i
+ string = string.sub first_line, ''
+ end
+
+ string
+ end
+
##
# Detects the encoding of +string+ based on the magic comment
@@ -113,7 +124,12 @@ module RDoc::Encoding
if text.kind_of? RDoc::Comment
text.encode! encoding
else
- String.new text, encoding: encoding
+ # TODO: Remove this condition after Ruby 2.2 EOL
+ if RUBY_VERSION < '2.3.0'
+ text.force_encoding encoding
+ else
+ String.new text, encoding: encoding
+ end
end
end
diff --git a/lib/rdoc/erb_partial.rb b/lib/rdoc/erb_partial.rb
index 043d763db1..d6e3f41b7e 100644
--- a/lib/rdoc/erb_partial.rb
+++ b/lib/rdoc/erb_partial.rb
@@ -16,3 +16,4 @@ class RDoc::ERBPartial < ERB
end
end
+
diff --git a/lib/rdoc/erbio.rb b/lib/rdoc/erbio.rb
index 0f98eaedee..0d5f96e133 100644
--- a/lib/rdoc/erbio.rb
+++ b/lib/rdoc/erbio.rb
@@ -20,8 +20,12 @@ class RDoc::ERBIO < ERB
##
# Defaults +eoutvar+ to 'io', otherwise is identical to ERB's initialize
- def initialize str, trim_mode: nil, eoutvar: 'io'
- super(str, trim_mode: trim_mode, eoutvar: eoutvar)
+ def initialize str, safe_level = nil, legacy_trim_mode = nil, legacy_eoutvar = 'io', trim_mode: nil, eoutvar: 'io'
+ if RUBY_VERSION >= '2.6'
+ super(str, trim_mode: trim_mode, eoutvar: eoutvar)
+ else
+ super(str, safe_level, legacy_trim_mode, legacy_eoutvar)
+ end
end
##
@@ -35,3 +39,4 @@ class RDoc::ERBIO < ERB
end
end
+
diff --git a/lib/rdoc/extend.rb b/lib/rdoc/extend.rb
new file mode 100644
index 0000000000..e1b182902e
--- /dev/null
+++ b/lib/rdoc/extend.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+##
+# A Module extension to a class with \#extend
+#
+# RDoc::Extend.new 'Enumerable', 'comment ...'
+
+class RDoc::Extend < RDoc::Mixin
+
+end
+
diff --git a/lib/rdoc/generator/darkfish.rb b/lib/rdoc/generator/darkfish.rb
index 96bb4fb66f..60e0265e8c 100644
--- a/lib/rdoc/generator/darkfish.rb
+++ b/lib/rdoc/generator/darkfish.rb
@@ -610,7 +610,7 @@ class RDoc::Generator::Darkfish
@classes = @store.all_classes_and_modules.sort
@files = @store.all_files.sort
- @methods = @classes.flat_map { |m| m.method_list }.sort
+ @methods = @classes.map { |m| m.method_list }.flatten.sort
@modsort = get_sorted_module_list @classes
end
@@ -677,6 +677,7 @@ class RDoc::Generator::Darkfish
return body if body =~ /<html/
head_file = @template_dir + '_head.rhtml'
+ footer_file = @template_dir + '_footer.rhtml'
<<-TEMPLATE
<!DOCTYPE html>
@@ -686,6 +687,8 @@ class RDoc::Generator::Darkfish
#{head_file.read}
#{body}
+
+#{footer_file.read}
TEMPLATE
end
@@ -775,7 +778,11 @@ class RDoc::Generator::Darkfish
erbout = "_erbout_#{file_var}"
end
- template = klass.new template, trim_mode: '-', eoutvar: erbout
+ if RUBY_VERSION >= '2.6'
+ template = klass.new template, trim_mode: '-', eoutvar: erbout
+ else
+ template = klass.new template, nil, '-', erbout
+ end
@template_cache[file] = template
template
end
diff --git a/lib/rdoc/generator/json_index.rb b/lib/rdoc/generator/json_index.rb
index c454910d5c..3a1000033d 100644
--- a/lib/rdoc/generator/json_index.rb
+++ b/lib/rdoc/generator/json_index.rb
@@ -230,9 +230,9 @@ class RDoc::Generator::JsonIndex
def index_methods
debug_msg " generating method search index"
- list = @classes.uniq.flat_map do |klass|
+ list = @classes.uniq.map do |klass|
klass.method_list
- end.sort_by do |method|
+ end.flatten.sort_by do |method|
[method.name, method.parent.full_name]
end
diff --git a/lib/rdoc/generator/markup.rb b/lib/rdoc/generator/markup.rb
index 76b7d458aa..b54265717c 100644
--- a/lib/rdoc/generator/markup.rb
+++ b/lib/rdoc/generator/markup.rb
@@ -157,3 +157,4 @@ class RDoc::TopLevel
end
end
+
diff --git a/lib/rdoc/generator/pot.rb b/lib/rdoc/generator/pot.rb
index b0b7c07179..bee1133b07 100644
--- a/lib/rdoc/generator/pot.rb
+++ b/lib/rdoc/generator/pot.rb
@@ -81,7 +81,6 @@ class RDoc::Generator::POT
end
end
- # :nodoc:
def class_dir
nil
end
diff --git a/lib/rdoc/generator/pot/message_extractor.rb b/lib/rdoc/generator/pot/message_extractor.rb
index 4938858bdc..313dfd2dc7 100644
--- a/lib/rdoc/generator/pot/message_extractor.rb
+++ b/lib/rdoc/generator/pot/message_extractor.rb
@@ -29,7 +29,7 @@ class RDoc::Generator::POT::MessageExtractor
extract_text(klass.comment_location, klass.full_name)
klass.each_section do |section, constants, attributes|
- extract_text(section.title, "#{klass.full_name}: section title")
+ extract_text(section.title ,"#{klass.full_name}: section title")
section.comments.each do |comment|
extract_text(comment, "#{klass.full_name}: #{section.title}")
end
diff --git a/lib/rdoc/generator/pot/po_entry.rb b/lib/rdoc/generator/pot/po_entry.rb
index 7454b29273..3c278826f4 100644
--- a/lib/rdoc/generator/pot/po_entry.rb
+++ b/lib/rdoc/generator/pot/po_entry.rb
@@ -23,7 +23,7 @@ class RDoc::Generator::POT::POEntry
attr_reader :flags
##
- # Creates a PO entry for +msgid+. Other values can be specified by
+ # Creates a PO entry for +msgid+. Other valus can be specified by
# +options+.
def initialize msgid, options = {}
diff --git a/lib/rdoc/generator/ri.rb b/lib/rdoc/generator/ri.rb
index 1c2f018f97..0eef1d03f5 100644
--- a/lib/rdoc/generator/ri.rb
+++ b/lib/rdoc/generator/ri.rb
@@ -28,3 +28,4 @@ class RDoc::Generator::RI
end
end
+
diff --git a/lib/rdoc/generator/template/darkfish/_head.rhtml b/lib/rdoc/generator/template/darkfish/_head.rhtml
index 69649ad3b5..d5aed3e9ef 100644
--- a/lib/rdoc/generator/template/darkfish/_head.rhtml
+++ b/lib/rdoc/generator/template/darkfish/_head.rhtml
@@ -1,5 +1,4 @@
<meta charset="<%= @options.charset %>">
-<meta name="viewport" content="width=device-width, initial-scale=1" />
<title><%= h @title %></title>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml
index afc7f7b88d..9c49b31376 100644
--- a/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml
+++ b/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml
@@ -3,7 +3,7 @@
<div id="search-field-wrapper">
<input id="search-field" role="combobox" aria-label="Search"
aria-autocomplete="list" aria-controls="search-results"
- type="text" name="search" placeholder="Search (/) for a class, method, ..." spellcheck="false"
+ type="text" name="search" placeholder="Search" spellcheck="false"
title="Type to search, Up and Down to navigate, Enter to load">
</div>
diff --git a/lib/rdoc/generator/template/darkfish/_sidebar_toggle.rhtml b/lib/rdoc/generator/template/darkfish/_sidebar_toggle.rhtml
deleted file mode 100644
index ed2cbe31a0..0000000000
--- a/lib/rdoc/generator/template/darkfish/_sidebar_toggle.rhtml
+++ /dev/null
@@ -1,3 +0,0 @@
-<div id="navigation-toggle" role="button" tabindex="0" aria-label="Toggle sidebar" aria-expanded="true" aria-controls="navigation">
- <span aria-hidden="true">&#9776;</span>
-</div>
diff --git a/lib/rdoc/generator/template/darkfish/class.rhtml b/lib/rdoc/generator/template/darkfish/class.rhtml
index 6c64ba6c98..97d175dddc 100644
--- a/lib/rdoc/generator/template/darkfish/class.rhtml
+++ b/lib/rdoc/generator/template/darkfish/class.rhtml
@@ -1,20 +1,19 @@
<body id="top" role="document" class="<%= klass.type %>">
-<%= render '_sidebar_toggle.rhtml' %>
-
-<nav id="navigation" role="navigation">
+<nav role="navigation">
<div id="project-navigation">
<%= render '_sidebar_navigation.rhtml' %>
<%= render '_sidebar_search.rhtml' %>
</div>
<%= render '_sidebar_table_of_contents.rhtml' %>
- <%= render '_sidebar_sections.rhtml' %>
- <%= render '_sidebar_parent.rhtml' %>
- <%= render '_sidebar_includes.rhtml' %>
- <%= render '_sidebar_extends.rhtml' %>
- <%= render '_sidebar_methods.rhtml' %>
- <%= render '_footer.rhtml' %>
+ <div id="class-metadata">
+ <%= render '_sidebar_sections.rhtml' %>
+ <%= render '_sidebar_parent.rhtml' %>
+ <%= render '_sidebar_includes.rhtml' %>
+ <%= render '_sidebar_extends.rhtml' %>
+ <%= render '_sidebar_methods.rhtml' %>
+ </div>
</nav>
<main role="main" aria-labelledby="<%=h klass.aref %>">
@@ -113,10 +112,6 @@
<%- end -%>
</div>
<%- end -%>
- <%- elsif method.has_call_seq? then -%>
- <div class="method-heading">
- <span class="method-name"><%= h method.name %></span>
- </div>
<%- else -%>
<div class="method-heading">
<span class="method-name"><%= h method.name %></span><span
@@ -128,7 +123,6 @@
<%- end -%>
</div>
- <%- unless method.skip_description? then -%>
<div class="method-description">
<%- if method.comment then -%>
<%= method.description.strip %>
@@ -151,7 +145,6 @@
</div>
<%- end -%>
</div>
- <%- end -%>
<%- unless method.aliases.empty? then -%>
<div class="aliases">
diff --git a/lib/rdoc/generator/template/darkfish/css/rdoc.css b/lib/rdoc/generator/template/darkfish/css/rdoc.css
index 7a42e62522..1be815f503 100644
--- a/lib/rdoc/generator/template/darkfish/css/rdoc.css
+++ b/lib/rdoc/generator/template/darkfish/css/rdoc.css
@@ -9,42 +9,16 @@
/* vim: ft=css et sw=2 ts=2 sts=2 */
/* Base Green is: #6C8C22 */
-/* 1. Variables and Root Styles */
-:root {
- --sidebar-width: 300px;
- --primary-color: #2c8c5e; /* A more muted green */
- --secondary-color: #246b4b; /* A darker, muted green */
- --text-color: #333;
- --background-color: #f8f9fa;
- --code-block-background-color: #f0f4f8;
- --code-block-border-color: #d1d5da;
- --link-color: #246b4b; /* A muted teal-green color */
- --link-hover-color: #25a28a; /* A slightly brighter teal-green */
- --border-color: #e0e0e0;
- --sidebar-text-color: #2c3e50; /* Dark blue-gray for contrast */
-
- /* Font family variables */
- --font-primary: 'Lato', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;
- --font-heading: 'Helvetica Neue', Arial, sans-serif;
- --font-code: 'Source Code Pro', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
-}
-
-/* 2. Global Styles */
+.hide { display: none !important; }
+
+* { padding: 0; margin: 0; }
+
body {
- background: var(--background-color);
- font-family: var(--font-primary);
- font-weight: 400;
- color: var(--text-color);
- line-height: 1.6;
-
- /* Layout */
- display: flex;
- flex-direction: column;
- min-height: 100vh;
- margin: 0;
+ background: #fafafa;
+ font-family: Lato, sans-serif;
+ font-weight: 300;
}
-/* 3. Typography */
h1 span,
h2 span,
h3 span,
@@ -86,36 +60,25 @@ h6:target {
border-left: 10px solid #f1edba;
}
-/* 4. Links */
:link,
:visited {
- color: var(--link-color);
+ color: #6C8C22;
text-decoration: none;
- transition: color 0.3s ease;
- font-weight: 600; /* Make links bolder */
}
:link:hover,
:visited:hover {
- color: var(--link-hover-color);
- text-decoration: underline;
+ border-bottom: 1px dotted #6C8C22;
}
-/* 5. Code and Pre */
code,
pre {
- font-family: var(--font-code);
- background-color: var(--code-block-background-color);
- border: 1px solid var(--code-block-border-color);
- border-radius: 6px;
- padding: 16px;
- overflow-x: auto;
- font-size: 15px; /* Increased from 14px */
- line-height: 1.5; /* Slightly increased for better readability with larger font */
- margin: 1em 0; /* Add some vertical margin */
-}
-
-/* 6. Tables */
+ font-family: "Source Code Pro", Monaco, monospace;
+ background-color: rgba(27,31,35,0.05);
+ padding: 0em 0.2em;
+ border-radius: 0.2em;
+}
+
table {
margin: 0;
border-spacing: 0;
@@ -135,142 +98,106 @@ table tr:nth-child(even) td {
background-color: #f5f4f6;
}
-/* 7. Navigation and Sidebar */
-nav {
- font-family: var(--font-heading);
- font-size: 16px;
- border-right: 1px solid var(--border-color);
- position: fixed;
- top: 0;
- bottom: 0;
- left: 0;
- width: var(--sidebar-width);
- background: var(--background-color);
- overflow-y: auto;
- z-index: 10;
- display: flex;
- flex-direction: column;
- color: var(--sidebar-text-color);
-}
-
-nav[hidden] {
- display: none;
-}
-
-nav footer {
- padding: 1em;
- border-top: 1px solid #ccc;
-}
+/* @group Generic Classes */
-nav .nav-section {
- margin-top: 1em;
- padding: 0 1em;
+.initially-hidden {
+ display: none;
}
-nav h2 {
- margin: 0 0 0.5em;
- padding: 0.5em 0;
- font-size: 1.2em;
- color: var(--text-color);
- border-bottom: 1px solid var(--border-color);
+#search-field {
+ width: 98%;
+ background: white;
+ border: none;
+ height: 1.5em;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ text-align: left;
}
-
-nav h3,
-#table-of-contents-navigation {
- margin: 0;
- padding: 0.5em 0;
- font-size: 1em;
- color: var(--text-color);
+#search-field:focus {
+ background: #f1edba;
}
-
-nav ul,
-nav dl,
-nav p {
- padding: 0;
- list-style: none;
- margin: 0.5em 0;
+#search-field:-moz-placeholder,
+#search-field::-webkit-input-placeholder {
+ font-weight: bold;
+ color: #666;
}
-nav ul li {
- margin-bottom: 0.3em;
+.missing-docs {
+ font-size: 120%;
+ background: white url(../images/wrench_orange.png) no-repeat 4px center;
+ color: #ccc;
+ line-height: 2em;
+ border: 1px solid #d00;
+ opacity: 1;
+ padding-left: 20px;
+ text-indent: 24px;
+ letter-spacing: 3px;
+ font-weight: bold;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
}
-nav ul ul {
- padding-left: 1em;
+.target-section {
+ border: 2px solid #dcce90;
+ border-left-width: 8px;
+ padding: 0 1em;
+ background: #fff3c2;
}
-nav ul ul ul {
- padding-left: 1em;
-}
+/* @end */
-nav ul ul ul ul {
- padding-left: 1em;
+/* @group Index Page, Standalone file pages */
+.table-of-contents ul {
+ margin: 1em;
+ list-style: none;
}
-nav a {
- color: var(--link-color);
- text-decoration: none;
+.table-of-contents ul ul {
+ margin-top: 0.25em;
}
-nav a:hover {
- text-decoration: underline;
+.table-of-contents ul :link,
+.table-of-contents ul :visited {
+ font-size: 16px;
}
-#navigation-toggle {
- z-index: 1000;
- font-size: 2em;
- display: block;
- position: fixed;
- top: 10px;
- left: 20px;
- cursor: pointer;
+.table-of-contents li {
+ margin-bottom: 0.25em;
}
-#navigation-toggle[aria-expanded="true"] {
- top: 10px;
- left: 250px;
+.table-of-contents li .toc-toggle {
+ width: 16px;
+ height: 16px;
+ background: url(../images/add.png) no-repeat;
}
-nav ul li details {
- position: relative;
- padding-right: 1.5em; /* Add space for the marker on the right */
+.table-of-contents li .toc-toggle.open {
+ background: url(../images/delete.png) no-repeat;
}
-nav ul li details > summary {
- list-style: none; /* Remove the default marker */
- position: relative; /* So that the open/close triangle can position itself absolutely inside */
-}
+/* @end */
-nav ul li details > summary::after {
- content: 'â–¶'; /* Unicode right-pointing triangle */
- position: absolute;
- font-size: 0.8em;
- bottom: 0.1em;
- margin-left: 0.3em;
- transition: transform 0.2s ease;
-}
+/* @group Top-Level Structure */
-nav ul li details[open] > summary::after {
- transform: rotate(90deg); /* Rotate the triangle when open */
+nav {
+ float: left;
+ width: 260px;
+ font-family: Helvetica, sans-serif;
+ font-size: 14px;
+ border-right: 1px solid #ccc;
+ position: sticky;
+ top: 0;
+ overflow: auto;
+ height: calc(100vh - 100px); /* reduce the footer height */
}
-/* 8. Main Content */
main {
- flex: 1;
display: block;
- margin: 3em auto;
- padding: 0 2em;
- max-width: 800px;
+ margin: 0 2em 5em 260px;
+ padding-left: 20px;
+ min-width: 340px;
font-size: 16px;
- line-height: 1.6;
- color: var(--text-color);
- box-sizing: border-box;
-}
-
-@media (min-width: 1024px) {
- main {
- margin-left: var(--sidebar-width);
- }
}
main h1,
@@ -279,137 +206,131 @@ main h3,
main h4,
main h5,
main h6 {
- font-family: var(--font-heading);
+ font-family: Helvetica, sans-serif;
}
-@media (min-width: 1024px) {
- .table-of-contents main {
- margin-left: 20em;
- }
+.table-of-contents main {
+ margin-left: 2em;
}
#validator-badges {
+ clear: both;
margin: 1em 1em 2em;
font-size: smaller;
}
-/* 9. Search */
-#search-section {
- padding: 1em;
- background-color: var(--background-color);
- border-bottom: 1px solid var(--border-color);
-}
+/* @end */
-#search-field-wrapper {
- position: relative;
- display: flex;
- align-items: center;
+/* @group navigation */
+nav {
+ margin-bottom: 1em;
}
-#search-field {
- width: 100%;
- padding: 0.5em 1em 0.5em 2.5em;
- border: 1px solid var(--border-color);
- border-radius: 20px;
- font-size: 14px;
- outline: none;
- transition: border-color 0.3s ease;
- background-color: var(--background-color);
+nav .nav-section {
+ margin-top: 2em;
+ border-top: 2px solid #aaa;
+ font-size: 90%;
+ overflow: hidden;
}
-#search-field:focus {
- border-color: var(--primary-color);
+nav h2 {
+ margin: 0;
+ padding: 2px 8px 2px 8px;
+ background-color: #e8e8e8;
+ color: #555;
+ font-size: 125%;
+ text-align: center;
}
-#search-field::placeholder {
- color: var(--text-color);
- opacity: 0.6;
+nav h3,
+#table-of-contents-navigation {
+ margin: 0;
+ padding: 2px 8px 2px 8px;
+ text-align: right;
+ background-color: #e8e8e8;
+ color: #555;
}
-#search-field-wrapper::before {
- content: "\1F50D"; /* Unicode for magnifying glass */
- position: absolute;
- left: 0.75em;
- top: 50%;
- transform: translateY(-50%);
- font-size: 14px;
- color: var(--text-color);
- opacity: 0.6;
+nav ul,
+nav dl,
+nav p {
+ padding: 4px 8px 0;
+ list-style: none;
}
-/* 10. Utility Classes */
-.hide { display: none !important; }
-.initially-hidden { display: none; }
+#project-navigation .nav-section {
+ margin: 0;
+ border-top: 0;
+}
-/* 11. Media Queries */
-@media (min-width: 1024px) {
- /* Styles for larger screens */
+#home-section h2 {
+ text-align: center;
}
-/* 12. Print Styles */
-@media print {
- /* Print-specific styles */
+#table-of-contents-navigation {
+ font-size: 1.2em;
+ font-weight: bold;
+ text-align: center;
}
-/* 13. Syntax Highlighting */
-.ruby-constant { color: #0366d6; } /* Bright blue for constants */
-.ruby-keyword { color: #d73a49; } /* Red for keywords */
-.ruby-ivar { color: #e36209; } /* Orange for instance variables */
-.ruby-operator { color: #005cc5; } /* Dark blue for operators */
-.ruby-identifier { color: #24292e; } /* Dark gray for identifiers */
-.ruby-node { color: #22863a; } /* Green for interpolation */
-.ruby-comment { color: #6a737d; } /* Gray for comments */
-.ruby-regexp { color: #032f62; } /* Navy for regular expressions */
-.ruby-value { color: #005cc5; } /* Dark blue for numeric values */
-.ruby-string { color: #22863a; } /* Green for strings */
+#search-section {
+ margin-top: 0;
+ border-top: 0;
+}
-code {
- background-color: #f0f4f8; /* Match pre background */
- padding: 0.2em 0.4em;
- border-radius: 3px;
- font-size: 85%;
+#search-field-wrapper {
+ border-top: 1px solid #aaa;
+ border-bottom: 1px solid #aaa;
+ padding: 3px 8px;
+ background-color: #e8e8e8;
+ color: #555;
}
-em {
- text-decoration-color: rgba(52, 48, 64, 0.25);
- text-decoration-line: underline;
- text-decoration-style: dotted;
+ul.link-list li {
+ white-space: nowrap;
+ line-height: 1.4em;
}
-strong,
-em {
- background-color: rgba(158, 178, 255, 0.1);
+ul.link-list .type {
+ font-size: 8px;
+ text-transform: uppercase;
+ color: white;
+ background: #969696;
+ padding: 2px 4px;
+ -webkit-border-radius: 5px;
}
-/* 14. Specific Component Styles */
-.table-of-contents ul {
- margin: 1em;
- list-style: none;
+dl.note-list dt {
+ float: left;
+ margin-right: 1em;
}
-.table-of-contents ul ul {
- margin-top: 0.25em;
+.calls-super {
+ background: url(../images/arrow_up.png) no-repeat right center;
}
-.table-of-contents ul :link,
-.table-of-contents ul :visited {
- font-size: 16px;
+.nav-section details summary {
+ display: block;
}
-.table-of-contents li {
- margin-bottom: 0.25em;
+.nav-section details summary::-webkit-details-marker {
+ display: none;
}
-.table-of-contents li .toc-toggle {
- width: 16px;
- height: 16px;
- background: url(../images/add.png) no-repeat;
+.nav-section details summary:before {
+ content: "";
}
-.table-of-contents li .toc-toggle.open {
- background: url(../images/delete.png) no-repeat;
+.nav-section details summary:after {
+ content: " \25B6"; /* BLACK RIGHT-POINTING TRIANGLE */
}
+.nav-section details[open] > summary:after {
+ content: " \25BD"; /* WHITE DOWN-POINTING TRIANGLE */
+}
+
+/* @end */
+/* @group Documentation Section */
main {
color: #333;
}
@@ -432,43 +353,43 @@ main sup {
main h1[class] {
margin-top: 0;
margin-bottom: 1em;
- font-size: 2.5em;
- color: var(--primary-color);
+ font-size: 2em;
+ color: #6C8C22;
}
main h1 {
- margin: 1.5em 0 0.5em;
- font-size: 2.2em;
- color: var(--secondary-color);
+ margin: 2em 0 0.5em;
+ font-size: 1.7em;
}
main h2 {
- margin: 1.3em 0 0.5em;
- font-size: 1.8em;
- color: var(--secondary-color);
+ margin: 2em 0 0.5em;
+ font-size: 1.5em;
}
main h3 {
- margin: 1.2em 0 0.5em;
- font-size: 1.5em;
- color: var(--secondary-color);
+ margin: 2em 0 0.5em;
+ font-size: 1.2em;
}
main h4 {
- margin: 1.1em 0 0.5em;
- font-size: 1.3em;
- color: var(--secondary-color);
+ margin: 2em 0 0.5em;
+ font-size: 1.1em;
}
-main h5, main h6 {
- margin: 1em 0 0.5em;
- font-size: 1.1em;
- color: var(--secondary-color);
+main h5 {
+ margin: 2em 0 0.5em;
+ font-size: 1em;
+}
+
+main h6 {
+ margin: 2em 0 0.5em;
+ font-size: 1em;
}
main p {
- line-height: 1.5em;
- font-weight: 400;
+ margin: 0 0 0.5em;
+ line-height: 1.4em;
}
main pre {
@@ -503,8 +424,6 @@ main dl {
main dt {
margin-bottom: 0.5em;
- margin-right: 1em;
- float: left;
font-weight: bold;
}
@@ -551,7 +470,7 @@ main header h3 {
.constants-list > dl dt {
margin-bottom: 0.75em;
padding-left: 0;
- font-family: var(--font-code);
+ font-family: "Source Code Pro", Monaco, monospace;
font-size: 110%;
}
@@ -585,9 +504,6 @@ main header h3 {
/* @group Method Details */
main .method-source-code {
- /* While this is already invisible through the rule below, this will inform the browser to
- not consider source code during text searching until it is actually expanded. */
- visibility: hidden;
max-height: 0;
overflow: auto;
transition-duration: 200ms;
@@ -597,12 +513,11 @@ main .method-source-code {
}
main .method-source-code.active-menu {
- visibility: visible;
max-height: 100vh;
}
main .method-description .method-calls-super {
- color: var(--text-color);
+ color: #333;
font-weight: bold;
}
@@ -618,10 +533,10 @@ main .method-detail:target {
main .method-heading {
position: relative;
- font-family: var(--font-code);
+ font-family: "Source Code Pro", Monaco, monospace;
font-size: 110%;
font-weight: bold;
- color: var(--text-color);
+ color: #333;
}
main .method-heading :link,
main .method-heading :visited {
@@ -638,7 +553,7 @@ main .method-click-advice {
line-height: 20px;
background: url(../images/zoom.png) no-repeat right top;
}
-main .method-header:hover .method-click-advice {
+main .method-heading:hover .method-click-advice {
visibility: visible;
}
@@ -649,7 +564,7 @@ main .method-alias .method-heading {
main .method-description,
main .aliases {
margin-top: 0.75em;
- color: var(--text-color);
+ color: #333;
}
main .aliases {
@@ -673,14 +588,38 @@ main .attribute-access-type {
/* @end */
+/* @group Source Code */
+
+pre {
+ margin: 0.5em 0;
+ border: 1px dashed #999;
+ padding: 0.5em;
+ background: #262626;
+ color: white;
+ overflow: auto;
+}
+
+.ruby-constant { color: #7fffd4; background: transparent; }
+.ruby-keyword { color: #00ffff; background: transparent; }
+.ruby-ivar { color: #eedd82; background: transparent; }
+.ruby-operator { color: #00ffee; background: transparent; }
+.ruby-identifier { color: #ffdead; background: transparent; }
+.ruby-node { color: #ffa07a; background: transparent; }
+.ruby-comment { color: #dc0000; background: transparent; }
+.ruby-regexp { color: #ffa07a; background: transparent; }
+.ruby-value { color: #7fffd4; background: transparent; }
+
+/* @end */
+
+
/* @group search results */
#search-results {
- font-family: var(--font-primary);
+ font-family: Lato, sans-serif;
font-weight: 300;
}
#search-results .search-match {
- font-family: var(--font-heading);
+ font-family: Helvetica, sans-serif;
font-weight: normal;
}
@@ -716,34 +655,8 @@ main .attribute-access-type {
#search-results pre {
margin: 0.5em;
- font-family: var(--font-code);
+ font-family: "Source Code Pro", Monaco, monospace;
}
-@media (max-width: 480px) {
- nav {
- width: 100%;
- }
-
- main {
- margin: 1em auto;
- padding: 0 1em;
- max-width: 100%;
- }
-
- #navigation-toggle {
- right: 10px;
- left: auto;
- }
-
- #navigation-toggle[aria-expanded="true"] {
- left: auto;
- }
-
- table {
- display: block;
- overflow-x: auto;
- white-space: nowrap;
- }
-}
/* @end */
diff --git a/lib/rdoc/generator/template/darkfish/index.rhtml b/lib/rdoc/generator/template/darkfish/index.rhtml
index a5c0dd54da..423e225b68 100644
--- a/lib/rdoc/generator/template/darkfish/index.rhtml
+++ b/lib/rdoc/generator/template/darkfish/index.rhtml
@@ -1,16 +1,15 @@
<body id="top" role="document" class="file">
-<%= render '_sidebar_toggle.rhtml' %>
-
-<nav id="navigation" role="navigation">
+<nav role="navigation">
<div id="project-navigation">
<%= render '_sidebar_navigation.rhtml' %>
+
<%= render '_sidebar_search.rhtml' %>
</div>
- <%= render '_sidebar_pages.rhtml' %>
- <%= render '_sidebar_classes.rhtml' %>
-
- <%= render '_footer.rhtml' %>
+ <div id="project-metadata">
+ <%= render '_sidebar_pages.rhtml' %>
+ <%= render '_sidebar_classes.rhtml' %>
+ </div>
</nav>
<main role="main">
diff --git a/lib/rdoc/generator/template/darkfish/js/darkfish.js b/lib/rdoc/generator/template/darkfish/js/darkfish.js
index bea0a5f1cb..d0c9467751 100644
--- a/lib/rdoc/generator/template/darkfish/js/darkfish.js
+++ b/lib/rdoc/generator/template/darkfish/js/darkfish.js
@@ -78,37 +78,7 @@ function hookSearch() {
search.scrollIntoView = search.scrollInWindow;
};
-function hookFocus() {
- document.addEventListener("keydown", (event) => {
- if (document.activeElement.tagName === 'INPUT') {
- return;
- }
- if (event.key === "/") {
- event.preventDefault();
- document.querySelector('#search-field').focus();
- }
- });
-}
-
-function hookSidebar() {
- var navigation = document.querySelector('#navigation');
- var navigationToggle = document.querySelector('#navigation-toggle');
-
- navigationToggle.addEventListener('click', function() {
- navigation.hidden = !navigation.hidden;
- navigationToggle.ariaExpanded = navigationToggle.ariaExpanded !== 'true';
- });
-
- var isSmallViewport = window.matchMedia("(max-width: 1024px)").matches;
- if (isSmallViewport) {
- navigation.hidden = true;
- navigationToggle.ariaExpanded = false;
- }
-}
-
document.addEventListener('DOMContentLoaded', function() {
hookSourceViews();
hookSearch();
- hookFocus();
- hookSidebar();
});
diff --git a/lib/rdoc/generator/template/darkfish/js/search.js b/lib/rdoc/generator/template/darkfish/js/search.js
index d3cded1d57..58e52afecf 100644
--- a/lib/rdoc/generator/template/darkfish/js/search.js
+++ b/lib/rdoc/generator/template/darkfish/js/search.js
@@ -15,9 +15,9 @@ Search.prototype = Object.assign({}, Navigation, new function() {
this.init = function() {
var _this = this;
var observer = function(e) {
- switch(e.key) {
- case 'ArrowUp':
- case 'ArrowDown':
+ switch(e.keyCode) {
+ case 38: // Event.KEY_UP
+ case 40: // Event.KEY_DOWN
return;
}
_this.search(_this.input.value);
diff --git a/lib/rdoc/generator/template/darkfish/page.rhtml b/lib/rdoc/generator/template/darkfish/page.rhtml
index fb33eba6fd..4a6b006bb3 100644
--- a/lib/rdoc/generator/template/darkfish/page.rhtml
+++ b/lib/rdoc/generator/template/darkfish/page.rhtml
@@ -1,18 +1,18 @@
<body id="top" role="document" class="file">
-<%= render '_sidebar_toggle.rhtml' %>
-
-<nav id="navigation" role="navigation">
+<nav role="navigation">
<div id="project-navigation">
<%= render '_sidebar_navigation.rhtml' %>
<%= render '_sidebar_search.rhtml' %>
</div>
<%= render '_sidebar_table_of_contents.rhtml' %>
- <%= render '_sidebar_pages.rhtml' %>
- <%= render '_footer.rhtml' %>
+ <div id="project-metadata">
+ <%= render '_sidebar_pages.rhtml' %>
+ </div>
</nav>
<main role="main" aria-label="Page <%=h file.full_name%>">
<%= file.description %>
</main>
+
diff --git a/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml b/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml
index 098b589add..f0841572c3 100644
--- a/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml
+++ b/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml
@@ -1,16 +1,13 @@
<body role="document">
-<%= render '_sidebar_toggle.rhtml' %>
+<nav role="navigation">
+ <%= render '_sidebar_navigation.rhtml' %>
-<nav id="navigation" role="navigation">
- <div id="project-navigation">
- <%= render '_sidebar_navigation.rhtml' %>
- <%= render '_sidebar_search.rhtml' %>
- </div>
-
- <%= render '_sidebar_pages.rhtml' %>
- <%= render '_sidebar_classes.rhtml' %>
+ <%= render '_sidebar_search.rhtml' %>
- <%= render '_footer.rhtml' %>
+ <div id="project-metadata">
+ <%= render '_sidebar_pages.rhtml' %>
+ <%= render '_sidebar_classes.rhtml' %>
+ </div>
</nav>
<main role="main">
@@ -18,3 +15,4 @@
<p><%= message %>
</main>
+
diff --git a/lib/rdoc/generator/template/darkfish/servlet_root.rhtml b/lib/rdoc/generator/template/darkfish/servlet_root.rhtml
index 373e0006d9..cab3092b17 100644
--- a/lib/rdoc/generator/template/darkfish/servlet_root.rhtml
+++ b/lib/rdoc/generator/template/darkfish/servlet_root.rhtml
@@ -1,7 +1,5 @@
<body role="document">
-<%= render '_sidebar_toggle.rhtml' %>
-
-<nav id="navigation" role="navigation">
+<nav role="navigation">
<div id="project-navigation">
<div id="home-section" class="nav-section">
<h2>
@@ -12,8 +10,7 @@
<%= render '_sidebar_search.rhtml' %>
</div>
- <%= render '_sidebar_installed.rhtml' %>
- <%= render '_footer.rhtml' %>
+<%= render '_sidebar_installed.rhtml' %>
</nav>
<main role="main">
diff --git a/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml b/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml
index 2cd2207836..941ff9d630 100644
--- a/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml
+++ b/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml
@@ -1,15 +1,4 @@
<body id="top" class="table-of-contents">
-<%= render '_sidebar_toggle.rhtml' %>
-
-<nav id="navigation" role="navigation">
- <div id="project-navigation">
- <%= render '_sidebar_navigation.rhtml' %>
-
- <%= render '_sidebar_search.rhtml' %>
- </div>
-
- <%= render '_footer.rhtml' %>
-</nav>
<main role="main">
<h1 class="class"><%= h @title %></h1>
@@ -47,9 +36,8 @@
unless table.empty? then %>
<ul>
<%- table.each do |item| -%>
-<%- label = item.respond_to?(:label) ? item.label(klass) : item.aref -%>
- <li><a href="<%= klass.path %>#<%= label %>"><%= item.plain_html %></a>
-<%- end -%>
+ <li><a href="<%= klass.path %>#<%= item.aref %>"><%= item.plain_html %></a>
+<%- end -%>
</ul>
<%- end -%>
</li>
@@ -58,9 +46,9 @@
<h2 id="methods">Methods</h2>
<ul>
-<%- @store.all_classes_and_modules.flat_map do |mod|
+<%- @store.all_classes_and_modules.map do |mod|
mod.method_list
- end.sort.each do |method| %>
+ end.flatten.sort.each do |method| %>
<li class="method">
<a href="<%= method.path %>"><%= h method.pretty_name %></a>
&mdash;
diff --git a/lib/rdoc/generator/template/json_index/js/navigation.js b/lib/rdoc/generator/template/json_index/js/navigation.js
index 137e3a0038..dfad74b1ae 100644
--- a/lib/rdoc/generator/template/json_index/js/navigation.js
+++ b/lib/rdoc/generator/template/json_index/js/navigation.js
@@ -23,24 +23,24 @@ Navigation = new function() {
this.onkeydown = function(e) {
if (!this.navigationActive) return;
- switch(e.key) {
- case 'ArrowLeft':
+ switch(e.keyCode) {
+ case 37: //Event.KEY_LEFT:
if (this.moveLeft()) e.preventDefault();
break;
- case 'ArrowUp':
- if (e.key == 'ArrowUp' || e.ctrlKey) {
+ case 38: //Event.KEY_UP:
+ if (e.keyCode == 38 || e.ctrlKey) {
if (this.moveUp()) e.preventDefault();
}
break;
- case 'ArrowRight':
+ case 39: //Event.KEY_RIGHT:
if (this.moveRight()) e.preventDefault();
break;
- case 'ArrowDown':
- if (e.key == 'ArrowDown' || e.ctrlKey) {
+ case 40: //Event.KEY_DOWN:
+ if (e.keyCode == 40 || e.ctrlKey) {
if (this.moveDown()) e.preventDefault();
}
break;
- case 'Enter':
+ case 13: //Event.KEY_RETURN:
if (this.current) e.preventDefault();
this.select(this.current);
break;
diff --git a/lib/rdoc/ghost_method.rb b/lib/rdoc/ghost_method.rb
new file mode 100644
index 0000000000..2488feb9d7
--- /dev/null
+++ b/lib/rdoc/ghost_method.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+##
+# GhostMethod represents a method referenced only by a comment
+
+class RDoc::GhostMethod < RDoc::AnyMethod
+end
+
diff --git a/lib/rdoc/include.rb b/lib/rdoc/include.rb
new file mode 100644
index 0000000000..b3ad610649
--- /dev/null
+++ b/lib/rdoc/include.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+##
+# A Module included in a class with \#include
+#
+# RDoc::Include.new 'Enumerable', 'comment ...'
+
+class RDoc::Include < RDoc::Mixin
+
+end
+
diff --git a/lib/rdoc/markdown.rb b/lib/rdoc/markdown.rb
index 881d19ecb4..a0709b6352 100644
--- a/lib/rdoc/markdown.rb
+++ b/lib/rdoc/markdown.rb
@@ -6,7 +6,7 @@
# RDoc::Markdown as described by the [markdown syntax][syntax].
#
# To choose Markdown as your only default format see
-# RDoc::Options@Saved+Options for instructions on setting up a `.rdoc_options`
+# RDoc::Options@Saved+Options for instructions on setting up a `.doc_options`
# file to store your project default.
#
# ## Usage
@@ -175,7 +175,7 @@
# [dingus]: http://daringfireball.net/projects/markdown/dingus
# [GFM]: https://github.github.com/gfm/
# [pegmarkdown]: https://github.com/jgm/peg-markdown
-# [PHPE]: https://michelf.ca/projects/php-markdown/extra/#def-list
+# [PHPE]: http://michelf.com/projects/php-markdown/extra/#def-list
# [syntax]: http://daringfireball.net/projects/markdown/syntax
#--
# Last updated to jgm/peg-markdown commit 8f8fc22ef0
@@ -1158,7 +1158,7 @@ class RDoc::Markdown
return _tmp
end
- # AtxHeading = AtxStart:s @Spacechar+ AtxInline+:a (@Sp /#*/ @Sp)? @Newline { RDoc::Markup::Heading.new(s, a.join) }
+ # AtxHeading = AtxStart:s @Sp AtxInline+:a (@Sp /#*/ @Sp)? @Newline { RDoc::Markup::Heading.new(s, a.join) }
def _AtxHeading
_save = self.pos
@@ -1169,22 +1169,12 @@ class RDoc::Markdown
self.pos = _save
break
end
- _save1 = self.pos
- _tmp = _Spacechar()
- if _tmp
- while true
- _tmp = _Spacechar()
- break unless _tmp
- end
- _tmp = true
- else
- self.pos = _save1
- end
+ _tmp = _Sp()
unless _tmp
self.pos = _save
break
end
- _save2 = self.pos
+ _save1 = self.pos
_ary = []
_tmp = apply(:_AtxInline)
if _tmp
@@ -1197,37 +1187,37 @@ class RDoc::Markdown
_tmp = true
@result = _ary
else
- self.pos = _save2
+ self.pos = _save1
end
a = @result
unless _tmp
self.pos = _save
break
end
- _save3 = self.pos
+ _save2 = self.pos
- _save4 = self.pos
+ _save3 = self.pos
while true # sequence
_tmp = _Sp()
unless _tmp
- self.pos = _save4
+ self.pos = _save3
break
end
_tmp = scan(/\G(?-mix:#*)/)
unless _tmp
- self.pos = _save4
+ self.pos = _save3
break
end
_tmp = _Sp()
unless _tmp
- self.pos = _save4
+ self.pos = _save3
end
break
end # end sequence
unless _tmp
_tmp = true
- self.pos = _save3
+ self.pos = _save2
end
unless _tmp
self.pos = _save
@@ -16455,12 +16445,12 @@ class RDoc::Markdown
return _tmp
end
- # DefinitionListLabel = Inline:label @Sp @Newline { label }
+ # DefinitionListLabel = StrChunk:label @Sp @Newline { label }
def _DefinitionListLabel
_save = self.pos
while true # sequence
- _tmp = apply(:_Inline)
+ _tmp = apply(:_StrChunk)
label = @result
unless _tmp
self.pos = _save
@@ -16549,7 +16539,7 @@ class RDoc::Markdown
Rules[:_Plain] = rule_info("Plain", "Inlines:a { paragraph a }")
Rules[:_AtxInline] = rule_info("AtxInline", "!@Newline !(@Sp /\#*/ @Sp @Newline) Inline")
Rules[:_AtxStart] = rule_info("AtxStart", "< /\\\#{1,6}/ > { text.length }")
- Rules[:_AtxHeading] = rule_info("AtxHeading", "AtxStart:s @Spacechar+ AtxInline+:a (@Sp /\#*/ @Sp)? @Newline { RDoc::Markup::Heading.new(s, a.join) }")
+ Rules[:_AtxHeading] = rule_info("AtxHeading", "AtxStart:s @Sp AtxInline+:a (@Sp /\#*/ @Sp)? @Newline { RDoc::Markup::Heading.new(s, a.join) }")
Rules[:_SetextHeading] = rule_info("SetextHeading", "(SetextHeading1 | SetextHeading2)")
Rules[:_SetextBottom1] = rule_info("SetextBottom1", "/={1,}/ @Newline")
Rules[:_SetextBottom2] = rule_info("SetextBottom2", "/-{1,}/ @Newline")
@@ -16787,7 +16777,7 @@ class RDoc::Markdown
Rules[:_TableAlign] = rule_info("TableAlign", "< /:?-+:?/ > @Sp { text.start_with?(\":\") ? (text.end_with?(\":\") ? :center : :left) : (text.end_with?(\":\") ? :right : nil) }")
Rules[:_DefinitionList] = rule_info("DefinitionList", "&{ definition_lists? } DefinitionListItem+:list { RDoc::Markup::List.new :NOTE, *list.flatten }")
Rules[:_DefinitionListItem] = rule_info("DefinitionListItem", "DefinitionListLabel+:label DefinitionListDefinition+:defns { list_items = [] list_items << RDoc::Markup::ListItem.new(label, defns.shift) list_items.concat defns.map { |defn| RDoc::Markup::ListItem.new nil, defn } unless list_items.empty? list_items }")
- Rules[:_DefinitionListLabel] = rule_info("DefinitionListLabel", "Inline:label @Sp @Newline { label }")
+ Rules[:_DefinitionListLabel] = rule_info("DefinitionListLabel", "StrChunk:label @Sp @Newline { label }")
Rules[:_DefinitionListDefinition] = rule_info("DefinitionListDefinition", "@NonindentSpace \":\" @Space Inlines:a @BlankLine+ { paragraph a }")
# :startdoc:
end
diff --git a/lib/rdoc/markdown/entities.rb b/lib/rdoc/markdown/entities.rb
index 265c2eb3f3..d2cf610293 100644
--- a/lib/rdoc/markdown/entities.rb
+++ b/lib/rdoc/markdown/entities.rb
@@ -2129,3 +2129,4 @@ RDoc::Markdown::HTML_ENTITIES = {
"zwj" => [0x0200D],
"zwnj" => [0x0200C],
}
+
diff --git a/lib/rdoc/markdown/literals.rb b/lib/rdoc/markdown/literals.rb
index c5c15d3100..37659b7ae0 100644
--- a/lib/rdoc/markdown/literals.rb
+++ b/lib/rdoc/markdown/literals.rb
@@ -3,6 +3,7 @@
# :markup: markdown
##
+#--
# This set of literals is for Ruby 1.9 regular expressions and gives full
# unicode support.
#
diff --git a/lib/rdoc/markup.rb b/lib/rdoc/markup.rb
index 3c29870d8a..6e93030965 100644
--- a/lib/rdoc/markup.rb
+++ b/lib/rdoc/markup.rb
@@ -10,24 +10,19 @@
# RDoc::Markup and other markup formats do no output formatting, this is
# handled by the RDoc::Markup::Formatter subclasses.
#
-# = Markup Formats
-#
-# +RDoc+ supports these markup formats:
-#
-# - +rdoc+:
-# the +RDoc+ markup format;
-# see RDoc::MarkupReference.
-# - +markdown+:
-# The +markdown+ markup format as described in
-# the {Markdown Guide}[https://www.markdownguide.org];
-# see RDoc::Markdown.
-# - +rd+:
-# the +rd+ markup format format;
-# see RDoc::RD.
-# - +tomdoc+:
-# the TomDoc format as described in
-# {TomDoc for Ruby}[http://tomdoc.org];
-# see RDoc::TomDoc.
+# = Supported Formats
+#
+# Besides the RDoc::Markup format, the following formats are built in to RDoc:
+#
+# markdown::
+# The markdown format as described by
+# http://daringfireball.net/projects/markdown/. See RDoc::Markdown for
+# details on the parser and supported extensions.
+# rd::
+# The rdtool format. See RDoc::RD for details on the parser and format.
+# tomdoc::
+# The TomDoc format as described by http://tomdoc.org/. See RDoc::TomDoc
+# for details on the parser and supported extensions.
#
# You can choose a markup format using the following methods:
#
diff --git a/lib/rdoc/markup/attr_changer.rb b/lib/rdoc/markup/attr_changer.rb
index e5ba470bb6..4c4bc6479e 100644
--- a/lib/rdoc/markup/attr_changer.rb
+++ b/lib/rdoc/markup/attr_changer.rb
@@ -20,3 +20,4 @@ class RDoc::Markup::AttrChanger
end
end
+
diff --git a/lib/rdoc/markup/attr_span.rb b/lib/rdoc/markup/attr_span.rb
index f1fabf1c3b..20ef11cd6d 100644
--- a/lib/rdoc/markup/attr_span.rb
+++ b/lib/rdoc/markup/attr_span.rb
@@ -33,3 +33,4 @@ class RDoc::Markup::AttrSpan
end
end
+
diff --git a/lib/rdoc/markup/attribute_manager.rb b/lib/rdoc/markup/attribute_manager.rb
index ed014f255b..601e6bc189 100644
--- a/lib/rdoc/markup/attribute_manager.rb
+++ b/lib/rdoc/markup/attribute_manager.rb
@@ -1,19 +1,19 @@
# frozen_string_literal: true
-
##
# Manages changes of attributes in a block of text
-class RDoc::Markup::AttributeManager
- unless ::MatchData.method_defined?(:match_length)
- using ::Module.new {
- refine(::MatchData) {
- def match_length(nth) # :nodoc:
- b, e = offset(nth)
- e - b if b
- end
- }
+unless MatchData.method_defined?(:match_length)
+ using Module.new {
+ refine(MatchData) {
+ def match_length(nth)
+ b, e = offset(nth)
+ e - b if b
+ end
}
- end
+ }
+end
+
+class RDoc::Markup::AttributeManager
##
# The NUL character
@@ -138,7 +138,6 @@ class RDoc::Markup::AttributeManager
res
end
- # :nodoc:
def exclusive?(attr)
(attr & @exclusive_bitmap) != 0
end
@@ -156,7 +155,6 @@ class RDoc::Markup::AttributeManager
convert_attrs_word_pair_map(str, attrs, exclusive)
end
- # :nodoc:
def convert_attrs_matching_word_pairs(str, attrs, exclusive)
# first do matching ones
tags = @matching_word_pairs.select { |start, bitmap|
@@ -181,7 +179,6 @@ class RDoc::Markup::AttributeManager
str.delete!(NON_PRINTING_START + NON_PRINTING_END)
end
- # :nodoc:
def convert_attrs_word_pair_map(str, attrs, exclusive)
# then non-matching
unless @word_pair_map.empty? then
@@ -260,7 +257,7 @@ class RDoc::Markup::AttributeManager
def add_word_pair(start, stop, name, exclusive = false)
raise ArgumentError, "Word flags may not start with '<'" if
- start[0, 1] == '<'
+ start[0,1] == '<'
bitmap = @attributes.bitmap_for name
@@ -271,7 +268,7 @@ class RDoc::Markup::AttributeManager
@word_pair_map[pattern] = bitmap
end
- @protectable << start[0, 1]
+ @protectable << start[0,1]
@protectable.uniq!
@exclusive_bitmap |= bitmap if exclusive
@@ -403,3 +400,4 @@ class RDoc::Markup::AttributeManager
end
end
+
diff --git a/lib/rdoc/markup/attributes.rb b/lib/rdoc/markup/attributes.rb
index d9d18b3059..ce014ce928 100644
--- a/lib/rdoc/markup/attributes.rb
+++ b/lib/rdoc/markup/attributes.rb
@@ -68,3 +68,4 @@ class RDoc::Markup::Attributes
end
end
+
diff --git a/lib/rdoc/markup/blank_line.rb b/lib/rdoc/markup/blank_line.rb
index f63ae9479c..3129ab5e7f 100644
--- a/lib/rdoc/markup/blank_line.rb
+++ b/lib/rdoc/markup/blank_line.rb
@@ -25,3 +25,4 @@ class RDoc::Markup::BlankLine
end
end
+
diff --git a/lib/rdoc/markup/block_quote.rb b/lib/rdoc/markup/block_quote.rb
index d9fcbf213c..7a4b3e36b0 100644
--- a/lib/rdoc/markup/block_quote.rb
+++ b/lib/rdoc/markup/block_quote.rb
@@ -12,3 +12,4 @@ class RDoc::Markup::BlockQuote < RDoc::Markup::Raw
end
end
+
diff --git a/lib/rdoc/markup/document.rb b/lib/rdoc/markup/document.rb
index 94cf6a3666..f3a5de1fc3 100644
--- a/lib/rdoc/markup/document.rb
+++ b/lib/rdoc/markup/document.rb
@@ -162,3 +162,4 @@ class RDoc::Markup::Document
end
end
+
diff --git a/lib/rdoc/markup/formatter.rb b/lib/rdoc/markup/formatter.rb
index 9daffaabb8..2bac76e838 100644
--- a/lib/rdoc/markup/formatter.rb
+++ b/lib/rdoc/markup/formatter.rb
@@ -90,7 +90,7 @@ class RDoc::Markup::Formatter
def add_regexp_handling_TIDYLINK
@markup.add_regexp_handling(/(?:
- \{[^{}]*\} | # multi-word label
+ \{.*?\} | # multi-word label
\b[^\s{}]+? # single-word label
)
@@ -263,3 +263,4 @@ class RDoc::Markup::Formatter
end
end
+
diff --git a/lib/rdoc/markup/hard_break.rb b/lib/rdoc/markup/hard_break.rb
index de1819c903..046068d5c2 100644
--- a/lib/rdoc/markup/hard_break.rb
+++ b/lib/rdoc/markup/hard_break.rb
@@ -29,3 +29,4 @@ class RDoc::Markup::HardBreak
end
end
+
diff --git a/lib/rdoc/markup/heading.rb b/lib/rdoc/markup/heading.rb
index 02476e5226..93a3a52000 100644
--- a/lib/rdoc/markup/heading.rb
+++ b/lib/rdoc/markup/heading.rb
@@ -76,3 +76,4 @@ RDoc::Markup::Heading =
end
end
+
diff --git a/lib/rdoc/markup/include.rb b/lib/rdoc/markup/include.rb
index 2bf63526b2..ad7c4a9640 100644
--- a/lib/rdoc/markup/include.rb
+++ b/lib/rdoc/markup/include.rb
@@ -40,3 +40,4 @@ class RDoc::Markup::Include
end
end
+
diff --git a/lib/rdoc/markup/indented_paragraph.rb b/lib/rdoc/markup/indented_paragraph.rb
index 992cd7cf81..d42b2e52b8 100644
--- a/lib/rdoc/markup/indented_paragraph.rb
+++ b/lib/rdoc/markup/indented_paragraph.rb
@@ -45,3 +45,4 @@ class RDoc::Markup::IndentedParagraph < RDoc::Markup::Raw
end
end
+
diff --git a/lib/rdoc/markup/list.rb b/lib/rdoc/markup/list.rb
index 112b7a1a86..05c3609202 100644
--- a/lib/rdoc/markup/list.rb
+++ b/lib/rdoc/markup/list.rb
@@ -99,3 +99,4 @@ class RDoc::Markup::List
end
end
+
diff --git a/lib/rdoc/markup/list_item.rb b/lib/rdoc/markup/list_item.rb
index 0b8326a69f..d22554ee73 100644
--- a/lib/rdoc/markup/list_item.rb
+++ b/lib/rdoc/markup/list_item.rb
@@ -97,3 +97,4 @@ class RDoc::Markup::ListItem
end
end
+
diff --git a/lib/rdoc/markup/paragraph.rb b/lib/rdoc/markup/paragraph.rb
index 21dfda007a..a2e45ef009 100644
--- a/lib/rdoc/markup/paragraph.rb
+++ b/lib/rdoc/markup/paragraph.rb
@@ -26,3 +26,4 @@ class RDoc::Markup::Paragraph < RDoc::Markup::Raw
end
end
+
diff --git a/lib/rdoc/markup/parser.rb b/lib/rdoc/markup/parser.rb
index 9c77048591..0029df7e65 100644
--- a/lib/rdoc/markup/parser.rb
+++ b/lib/rdoc/markup/parser.rb
@@ -218,7 +218,7 @@ class RDoc::Markup::Parser
break if peek_token.first == :BREAK
- data << ' ' if skip :NEWLINE and /#{SPACE_SEPARATED_LETTER_CLASS}\z/o.match?(data)
+ data << ' ' if skip :NEWLINE
else
unget
break
@@ -420,8 +420,6 @@ class RDoc::Markup::Parser
# A simple wrapper of StringScanner that is aware of the current column and lineno
class MyStringScanner
- # :stopdoc:
-
def initialize(input)
@line = @column = 0
@s = StringScanner.new input
@@ -458,8 +456,6 @@ class RDoc::Markup::Parser
def [](i)
@s[i]
end
-
- #:startdoc:
end
##
diff --git a/lib/rdoc/markup/pre_process.rb b/lib/rdoc/markup/pre_process.rb
index 979f2eadae..88078c9cef 100644
--- a/lib/rdoc/markup/pre_process.rb
+++ b/lib/rdoc/markup/pre_process.rb
@@ -97,18 +97,15 @@ class RDoc::Markup::PreProcess
# RDoc::CodeObject#metadata for details.
def handle text, code_object = nil, &block
- first_line = 1
if RDoc::Comment === text then
comment = text
text = text.text
- first_line = comment.line || 1
end
# regexp helper (square brackets for optional)
# $1 $2 $3 $4 $5
# [prefix][\]:directive:[spaces][param]newline
- text = text.lines.map.with_index(first_line) do |line, num|
- next line unless line =~ /\A([ \t]*(?:#|\/?\*)?[ \t]*)(\\?):([\w-]+):([ \t]*)(.+)?(\r?\n|$)/
+ text = text.gsub(/^([ \t]*(?:#|\/?\*)?[ \t]*)(\\?):(\w+):([ \t]*)(.+)?(\r?\n|$)/) do
# skip something like ':toto::'
next $& if $4.empty? and $5 and $5[0, 1] == ':'
@@ -123,8 +120,8 @@ class RDoc::Markup::PreProcess
next "#{$1.strip}\n"
end
- handle_directive $1, $3, $5, code_object, text.encoding, num, &block
- end.join
+ handle_directive $1, $3, $5, code_object, text.encoding, &block
+ end
if comment then
comment.text = text
@@ -151,7 +148,7 @@ class RDoc::Markup::PreProcess
# When 1.8.7 support is ditched prefix can be defaulted to ''
def handle_directive prefix, directive, param, code_object = nil,
- encoding = nil, line = nil
+ encoding = nil
blankline = "#{prefix.strip}\n"
directive = directive.downcase
@@ -223,11 +220,11 @@ class RDoc::Markup::PreProcess
# remove parameter &block
code_object.params = code_object.params.sub(/,?\s*&\w+/, '') if code_object.params
- code_object.block_params = param || ''
+ code_object.block_params = param
blankline
else
- result = yield directive, param, line if block_given?
+ result = yield directive, param if block_given?
case result
when nil then
diff --git a/lib/rdoc/markup/raw.rb b/lib/rdoc/markup/raw.rb
index a7c1c210a6..85e2c8b825 100644
--- a/lib/rdoc/markup/raw.rb
+++ b/lib/rdoc/markup/raw.rb
@@ -67,3 +67,4 @@ class RDoc::Markup::Raw
end
end
+
diff --git a/lib/rdoc/markup/regexp_handling.rb b/lib/rdoc/markup/regexp_handling.rb
index c471fe73c7..6ed868c2c1 100644
--- a/lib/rdoc/markup/regexp_handling.rb
+++ b/lib/rdoc/markup/regexp_handling.rb
@@ -38,3 +38,4 @@ class RDoc::Markup::RegexpHandling
end
end
+
diff --git a/lib/rdoc/markup/rule.rb b/lib/rdoc/markup/rule.rb
index 448148d6d1..38c1dc7f56 100644
--- a/lib/rdoc/markup/rule.rb
+++ b/lib/rdoc/markup/rule.rb
@@ -18,3 +18,4 @@ class RDoc::Markup::Rule < Struct.new :weight
end
end
+
diff --git a/lib/rdoc/markup/table.rb b/lib/rdoc/markup/table.rb
index 27a20f073a..7bcb10aff3 100644
--- a/lib/rdoc/markup/table.rb
+++ b/lib/rdoc/markup/table.rb
@@ -3,21 +3,12 @@
# A section of table
class RDoc::Markup::Table
- # headers of each column
- attr_accessor :header
+ attr_accessor :header, :align, :body
- # alignments of each column
- attr_accessor :align
-
- # body texts of each column
- attr_accessor :body
-
- # Creates new instance
def initialize header, align, body
@header, @align, @body = header, align, body
end
- # :stopdoc:
def == other
self.class == other.class and
@header == other.header and
@@ -29,7 +20,7 @@ class RDoc::Markup::Table
visitor.accept_table @header, @body, @align
end
- def pretty_print q
+ def pretty_print q # :nodoc:
q.group 2, '[Table: ', ']' do
q.group 2, '[Head: ', ']' do
q.seplist @header.zip(@align) do |text, align|
diff --git a/lib/rdoc/markup/to_ansi.rb b/lib/rdoc/markup/to_ansi.rb
index c3eacab21a..6cc3b70e93 100644
--- a/lib/rdoc/markup/to_ansi.rb
+++ b/lib/rdoc/markup/to_ansi.rb
@@ -91,3 +91,4 @@ class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc
end
end
+
diff --git a/lib/rdoc/markup/to_bs.rb b/lib/rdoc/markup/to_bs.rb
index b7b73e73f7..f9b86487db 100644
--- a/lib/rdoc/markup/to_bs.rb
+++ b/lib/rdoc/markup/to_bs.rb
@@ -24,7 +24,7 @@ class RDoc::Markup::ToBs < RDoc::Markup::ToRdoc
def init_tags
add_tag :BOLD, '+b', '-b'
add_tag :EM, '+_', '-_'
- add_tag :TT, '', '' # we need in_tt information maintained
+ add_tag :TT, '' , '' # we need in_tt information maintained
end
##
@@ -41,31 +41,6 @@ class RDoc::Markup::ToBs < RDoc::Markup::ToRdoc
end
##
- # Prepares the visitor for consuming +list_item+
-
- def accept_list_item_start list_item
- type = @list_type.last
-
- case type
- when :NOTE, :LABEL then
- bullets = Array(list_item.label).map do |label|
- attributes(label).strip
- end.join "\n"
-
- bullets << ":\n" unless bullets.empty?
-
- @prefix = ' ' * @indent
- @indent += 2
- @prefix << bullets + (' ' * @indent)
- else
- bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.'
- @prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1)
- width = bullet.length + 1
- @indent += width
- end
- end
-
- ##
# Turns on or off regexp handling for +convert_string+
def annotate tag
diff --git a/lib/rdoc/markup/to_html.rb b/lib/rdoc/markup/to_html.rb
index 91cadf9d16..bf323074de 100644
--- a/lib/rdoc/markup/to_html.rb
+++ b/lib/rdoc/markup/to_html.rb
@@ -61,7 +61,6 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
#
# These methods are used by regexp handling markup added by RDoc::Markup#add_regexp_handling.
- # :nodoc:
URL_CHARACTERS_REGEXP_STR = /[A-Za-z0-9\-._~:\/\?#\[\]@!$&'\(\)*+,;%=]/.source
##
@@ -203,9 +202,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
def accept_paragraph paragraph
@res << "\n<p>"
text = paragraph.text @hard_break
- text = text.gsub(/(#{SPACE_SEPARATED_LETTER_CLASS})?\K\r?\n(?=(?(1)(#{SPACE_SEPARATED_LETTER_CLASS})?))/o) {
- defined?($2) && ' '
- }
+ text = text.gsub(/\r?\n/, ' ')
@res << to_html(text)
@res << "</p>\n"
end
@@ -433,9 +430,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
def parseable? text
verbose, $VERBOSE = $VERBOSE, nil
- catch(:valid) do
- eval("BEGIN { throw :valid, true }\n#{text}")
- end
+ eval("BEGIN {return true}\n#{text}")
rescue SyntaxError
false
ensure
@@ -450,3 +445,4 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
end
end
+
diff --git a/lib/rdoc/markup/to_html_crossref.rb b/lib/rdoc/markup/to_html_crossref.rb
index 9b5de62fd6..a9fd09df41 100644
--- a/lib/rdoc/markup/to_html_crossref.rb
+++ b/lib/rdoc/markup/to_html_crossref.rb
@@ -42,7 +42,6 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
@cross_reference = RDoc::CrossReference.new @context
end
- # :nodoc:
def init_link_notation_regexp_handlings
add_regexp_handling_RDOCLINK
@@ -63,8 +62,8 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
name = name[1..-1] unless @show_hash if name[0, 1] == '#'
- if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])?@/
- text ||= [CGI.unescape($'), (" at <code>#{$1}</code>" if $~.begin(1))].join("")
+ if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])@/
+ text ||= "#{CGI.unescape $'} at <code>#{$1}</code>"
code = false
else
text ||= name
@@ -139,37 +138,39 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
# Creates an HTML link to +name+ with the given +text+.
def link name, text, code = true
- if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])?@/
+ if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])@/
name = $1
label = $'
end
- ref = @cross_reference.resolve name, text if name
+ ref = @cross_reference.resolve name, text
case ref
when String then
ref
else
- path = ref ? ref.as_href(@from_path) : +""
+ path = ref.as_href @from_path
if code and RDoc::CodeObject === ref and !(RDoc::TopLevel === ref)
text = "<code>#{CGI.escapeHTML text}</code>"
end
- if label
- if path =~ /#/
- path << "-label-#{label}"
- elsif ref&.sections&.any? { |section| label == section.title }
- path << "##{label}"
- elsif ref.respond_to?(:aref)
+ if path =~ /#/ then
+ path << "-label-#{label}"
+ elsif ref.sections and
+ ref.sections.any? { |section| label == section.title } then
+ path << "##{label}"
+ else
+ if ref.respond_to?(:aref)
path << "##{ref.aref}-label-#{label}"
else
path << "#label-#{label}"
end
- end
+ end if label
"<a href=\"#{path}\">#{text}</a>"
end
end
end
+
diff --git a/lib/rdoc/markup/to_html_snippet.rb b/lib/rdoc/markup/to_html_snippet.rb
index f471395a3a..4eb36592b7 100644
--- a/lib/rdoc/markup/to_html_snippet.rb
+++ b/lib/rdoc/markup/to_html_snippet.rb
@@ -66,9 +66,6 @@ class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml
alias accept_rule ignore
- ##
- # Adds +paragraph+ to the output
-
def accept_paragraph paragraph
para = @in_list_entry.last || "<p>"
@@ -285,3 +282,4 @@ class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml
end
end
+
diff --git a/lib/rdoc/markup/to_joined_paragraph.rb b/lib/rdoc/markup/to_joined_paragraph.rb
index 31cbe0853c..46e07c94ad 100644
--- a/lib/rdoc/markup/to_joined_paragraph.rb
+++ b/lib/rdoc/markup/to_joined_paragraph.rb
@@ -25,9 +25,9 @@ class RDoc::Markup::ToJoinedParagraph < RDoc::Markup::Formatter
def accept_paragraph paragraph
parts = paragraph.parts.chunk do |part|
String === part
- end.flat_map do |string, chunk|
+ end.map do |string, chunk|
string ? chunk.join.rstrip : chunk
- end
+ end.flatten
paragraph.parts.replace parts
end
@@ -44,3 +44,4 @@ class RDoc::Markup::ToJoinedParagraph < RDoc::Markup::Formatter
alias accept_table ignore
end
+
diff --git a/lib/rdoc/markup/to_label.rb b/lib/rdoc/markup/to_label.rb
index cf808364e9..aa1dbcf2a1 100644
--- a/lib/rdoc/markup/to_label.rb
+++ b/lib/rdoc/markup/to_label.rb
@@ -72,3 +72,4 @@ class RDoc::Markup::ToLabel < RDoc::Markup::Formatter
alias start_accepting ignore
end
+
diff --git a/lib/rdoc/markup/to_markdown.rb b/lib/rdoc/markup/to_markdown.rb
index b915fab60b..3ee48becb0 100644
--- a/lib/rdoc/markup/to_markdown.rb
+++ b/lib/rdoc/markup/to_markdown.rb
@@ -45,6 +45,8 @@ class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc
# Finishes consumption of `list`
def accept_list_end list
+ @res << "\n"
+
super
end
@@ -58,8 +60,6 @@ class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc
when :NOTE, :LABEL then
use_prefix
- @res << "\n"
-
4
else
@list_index[-1] = @list_index.last.succ
@@ -81,11 +81,11 @@ class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc
attributes(label).strip
end.join "\n"
- bullets << "\n" unless bullets.empty?
+ bullets << "\n:"
@prefix = ' ' * @indent
@indent += 4
- @prefix << bullets << ":" << (' ' * (@indent - 1))
+ @prefix << bullets + (' ' * (@indent - 1))
else
bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.'
@prefix = (' ' * @indent) + bullet.ljust(4)
@@ -189,3 +189,4 @@ class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc
end
end
+
diff --git a/lib/rdoc/markup/to_rdoc.rb b/lib/rdoc/markup/to_rdoc.rb
index 90763ccfdb..2a9b05625c 100644
--- a/lib/rdoc/markup/to_rdoc.rb
+++ b/lib/rdoc/markup/to_rdoc.rb
@@ -145,19 +145,11 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
case type
when :NOTE, :LABEL then
- stripped_labels = Array(list_item.label).map do |label|
+ bullets = Array(list_item.label).map do |label|
attributes(label).strip
- end
-
- bullets = case type
- when :NOTE
- stripped_labels.map { |b| "#{b}::" }
- when :LABEL
- stripped_labels.map { |b| "[#{b}]" }
- end
+ end.join "\n"
- bullets = bullets.join("\n")
- bullets << "\n" unless stripped_labels.empty?
+ bullets << ":\n" unless bullets.empty?
@prefix = ' ' * @indent
@indent += 2
@@ -249,8 +241,8 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
# Adds +table+ to the output
def accept_table header, body, aligns
- widths = header.zip(*body).map do |cols|
- cols.map(&:size).max
+ widths = header.zip(body) do |h, b|
+ [h.size, b.size].max
end
aligns = aligns.map do |a|
case a
@@ -262,12 +254,12 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
:rjust
end
end
- @res << header.zip(widths, aligns).map do |h, w, a|
+ @res << header.zip(widths, aligns) do |h, w, a|
h.__send__(a, w)
end.join("|").rstrip << "\n"
@res << widths.map {|w| "-" * w }.join("|") << "\n"
body.each do |row|
- @res << row.zip(widths, aligns).map do |t, w, a|
+ @res << row.zip(widths, aligns) do |t, w, a|
t.__send__(a, w)
end.join("|").rstrip << "\n"
end
@@ -350,3 +342,4 @@ class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter
end
end
+
diff --git a/lib/rdoc/markup/to_table_of_contents.rb b/lib/rdoc/markup/to_table_of_contents.rb
index e5b8225ba3..eb8e8faa16 100644
--- a/lib/rdoc/markup/to_table_of_contents.rb
+++ b/lib/rdoc/markup/to_table_of_contents.rb
@@ -86,3 +86,4 @@ class RDoc::Markup::ToTableOfContents < RDoc::Markup::Formatter
# :startdoc:
end
+
diff --git a/lib/rdoc/markup/to_test.rb b/lib/rdoc/markup/to_test.rb
index 30113da561..61d3cffaf0 100644
--- a/lib/rdoc/markup/to_test.rb
+++ b/lib/rdoc/markup/to_test.rb
@@ -67,3 +67,4 @@ class RDoc::Markup::ToTest < RDoc::Markup::Formatter
# :startdoc:
end
+
diff --git a/lib/rdoc/markup/to_tt_only.rb b/lib/rdoc/markup/to_tt_only.rb
index 9ac14ed235..9235d33f04 100644
--- a/lib/rdoc/markup/to_tt_only.rb
+++ b/lib/rdoc/markup/to_tt_only.rb
@@ -118,3 +118,4 @@ class RDoc::Markup::ToTtOnly < RDoc::Markup::Formatter
end
end
+
diff --git a/lib/rdoc/markup/verbatim.rb b/lib/rdoc/markup/verbatim.rb
index f51c2cfa14..7f1bc29a09 100644
--- a/lib/rdoc/markup/verbatim.rb
+++ b/lib/rdoc/markup/verbatim.rb
@@ -81,3 +81,4 @@ class RDoc::Markup::Verbatim < RDoc::Markup::Raw
end
end
+
diff --git a/lib/rdoc/meta_method.rb b/lib/rdoc/meta_method.rb
new file mode 100644
index 0000000000..7927a9ce9c
--- /dev/null
+++ b/lib/rdoc/meta_method.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+##
+# MetaMethod represents a meta-programmed method
+
+class RDoc::MetaMethod < RDoc::AnyMethod
+end
+
diff --git a/lib/rdoc/method_attr.rb b/lib/rdoc/method_attr.rb
new file mode 100644
index 0000000000..aae3c47e85
--- /dev/null
+++ b/lib/rdoc/method_attr.rb
@@ -0,0 +1,419 @@
+# frozen_string_literal: true
+##
+# Abstract class representing either a method or an attribute.
+
+class RDoc::MethodAttr < RDoc::CodeObject
+
+ include Comparable
+
+ ##
+ # Name of this method/attribute.
+
+ attr_accessor :name
+
+ ##
+ # public, protected, private
+
+ attr_accessor :visibility
+
+ ##
+ # Is this a singleton method/attribute?
+
+ attr_accessor :singleton
+
+ ##
+ # Source file token stream
+
+ attr_reader :text
+
+ ##
+ # Array of other names for this method/attribute
+
+ attr_reader :aliases
+
+ ##
+ # The method/attribute we're aliasing
+
+ attr_accessor :is_alias_for
+
+ #--
+ # The attributes below are for AnyMethod only.
+ # They are left here for the time being to
+ # allow ri to operate.
+ # TODO modify ri to avoid calling these on attributes.
+ #++
+
+ ##
+ # Parameters yielded by the called block
+
+ attr_reader :block_params
+
+ ##
+ # Parameters for this method
+
+ attr_accessor :params
+
+ ##
+ # Different ways to call this method
+
+ attr_accessor :call_seq
+
+ ##
+ # The call_seq or the param_seq with method name, if there is no call_seq.
+
+ attr_reader :arglists
+
+ ##
+ # Pretty parameter list for this method
+
+ attr_reader :param_seq
+
+
+ ##
+ # Creates a new MethodAttr from token stream +text+ and method or attribute
+ # name +name+.
+ #
+ # Usually this is called by super from a subclass.
+
+ def initialize text, name
+ super()
+
+ @text = text
+ @name = name
+
+ @aliases = []
+ @is_alias_for = nil
+ @parent_name = nil
+ @singleton = nil
+ @visibility = :public
+ @see = false
+
+ @arglists = nil
+ @block_params = nil
+ @call_seq = nil
+ @param_seq = nil
+ @params = nil
+ end
+
+ ##
+ # Resets cached data for the object so it can be rebuilt by accessor methods
+
+ def initialize_copy other # :nodoc:
+ @full_name = nil
+ end
+
+ def initialize_visibility # :nodoc:
+ super
+ @see = nil
+ end
+
+ ##
+ # Order by #singleton then #name
+
+ def <=>(other)
+ return unless other.respond_to?(:singleton) &&
+ other.respond_to?(:name)
+
+ [ @singleton ? 0 : 1, name] <=>
+ [other.singleton ? 0 : 1, other.name]
+ end
+
+ def == other # :nodoc:
+ equal?(other) or self.class == other.class and full_name == other.full_name
+ end
+
+ ##
+ # A method/attribute is documented if any of the following is true:
+ # - it was marked with :nodoc:;
+ # - it has a comment;
+ # - it is an alias for a documented method;
+ # - it has a +#see+ method that is documented.
+
+ def documented?
+ super or
+ (is_alias_for and is_alias_for.documented?) or
+ (see and see.documented?)
+ end
+
+ ##
+ # A method/attribute to look at,
+ # in particular if this method/attribute has no documentation.
+ #
+ # It can be a method/attribute of the superclass or of an included module,
+ # including the Kernel module, which is always appended to the included
+ # modules.
+ #
+ # Returns +nil+ if there is no such method/attribute.
+ # The +#is_alias_for+ method/attribute, if any, is not included.
+ #
+ # Templates may generate a "see also ..." if this method/attribute
+ # has documentation, and "see ..." if it does not.
+
+ def see
+ @see = find_see if @see == false
+ @see
+ end
+
+ ##
+ # Sets the store for this class or module and its contained code objects.
+
+ def store= store
+ super
+
+ @file = @store.add_file @file.full_name if @file
+ end
+
+ def find_see # :nodoc:
+ return nil if singleton || is_alias_for
+
+ # look for the method
+ other = find_method_or_attribute name
+ return other if other
+
+ # if it is a setter, look for a getter
+ return nil unless name =~ /[a-z_]=$/i # avoid == or ===
+ return find_method_or_attribute name[0..-2]
+ end
+
+ def find_method_or_attribute name # :nodoc:
+ return nil unless parent.respond_to? :ancestors
+
+ searched = parent.ancestors
+ kernel = @store.modules_hash['Kernel']
+
+ searched << kernel if kernel &&
+ parent != kernel && !searched.include?(kernel)
+
+ searched.each do |ancestor|
+ next if String === ancestor
+ next if parent == ancestor
+
+ other = ancestor.find_method_named('#' + name) ||
+ ancestor.find_attribute_named(name)
+
+ return other if other
+ end
+
+ nil
+ end
+
+ ##
+ # Abstract method. Contexts in their building phase call this
+ # to register a new alias for this known method/attribute.
+ #
+ # - creates a new AnyMethod/Attribute named <tt>an_alias.new_name</tt>;
+ # - adds +self+ as an alias for the new method or attribute
+ # - adds the method or attribute to #aliases
+ # - adds the method or attribute to +context+.
+
+ def add_alias(an_alias, context)
+ raise NotImplementedError
+ end
+
+ ##
+ # HTML fragment reference for this method
+
+ def aref
+ type = singleton ? 'c' : 'i'
+ # % characters are not allowed in html names => dash instead
+ "#{aref_prefix}-#{type}-#{html_name}"
+ end
+
+ ##
+ # Prefix for +aref+, defined by subclasses.
+
+ def aref_prefix
+ raise NotImplementedError
+ end
+
+ ##
+ # Attempts to sanitize the content passed by the Ruby parser:
+ # remove outer parentheses, etc.
+
+ def block_params=(value)
+ # 'yield.to_s' or 'assert yield, msg'
+ return @block_params = '' if value =~ /^[\.,]/
+
+ # remove trailing 'if/unless ...'
+ return @block_params = '' if value =~ /^(if|unless)\s/
+
+ value = $1.strip if value =~ /^(.+)\s(if|unless)\s/
+
+ # outer parentheses
+ value = $1 if value =~ /^\s*\((.*)\)\s*$/
+ value = value.strip
+
+ # proc/lambda
+ return @block_params = $1 if value =~ /^(proc|lambda)(\s*\{|\sdo)/
+
+ # surrounding +...+ or [...]
+ value = $1.strip if value =~ /^\+(.*)\+$/
+ value = $1.strip if value =~ /^\[(.*)\]$/
+
+ return @block_params = '' if value.empty?
+
+ # global variable
+ return @block_params = 'str' if value =~ /^\$[&0-9]$/
+
+ # wipe out array/hash indices
+ value.gsub!(/(\w)\[[^\[]+\]/, '\1')
+
+ # remove @ from class/instance variables
+ value.gsub!(/@@?([a-z0-9_]+)/, '\1')
+
+ # method calls => method name
+ value.gsub!(/([A-Z:a-z0-9_]+)\.([a-z0-9_]+)(\s*\(\s*[a-z0-9_.,\s]*\s*\)\s*)?/) do
+ case $2
+ when 'to_s' then $1
+ when 'const_get' then 'const'
+ when 'new' then
+ $1.split('::').last. # ClassName => class_name
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
+ downcase
+ else
+ $2
+ end
+ end
+
+ # class prefixes
+ value.gsub!(/[A-Za-z0-9_:]+::/, '')
+
+ # simple expressions
+ value = $1 if value =~ /^([a-z0-9_]+)\s*[-*+\/]/
+
+ @block_params = value.strip
+ end
+
+ ##
+ # HTML id-friendly method/attribute name
+
+ def html_name
+ require 'cgi/util'
+
+ CGI.escape(@name.gsub('-', '-2D')).gsub('%','-').sub(/^-/, '')
+ end
+
+ ##
+ # Full method/attribute name including namespace
+
+ def full_name
+ @full_name ||= "#{parent_name}#{pretty_name}"
+ end
+
+ def inspect # :nodoc:
+ alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil
+ visibility = self.visibility
+ visibility = "forced #{visibility}" if force_documentation
+ "#<%s:0x%x %s (%s)%s>" % [
+ self.class, object_id,
+ full_name,
+ visibility,
+ alias_for,
+ ]
+ end
+
+ ##
+ # '::' for a class method/attribute, '#' for an instance method.
+
+ def name_prefix
+ @singleton ? '::' : '#'
+ end
+
+ ##
+ # Name for output to HTML. For class methods the full name with a "." is
+ # used like +SomeClass.method_name+. For instance methods the class name is
+ # used if +context+ does not match the parent.
+ #
+ # This is to help prevent people from using :: to call class methods.
+
+ def output_name context
+ return "#{name_prefix}#{@name}" if context == parent
+
+ "#{parent_name}#{@singleton ? '.' : '#'}#{@name}"
+ end
+
+ ##
+ # Method/attribute name with class/instance indicator
+
+ def pretty_name
+ "#{name_prefix}#{@name}"
+ end
+
+ ##
+ # Type of method/attribute (class or instance)
+
+ def type
+ singleton ? 'class' : 'instance'
+ end
+
+ ##
+ # Path to this method for use with HTML generator output.
+
+ def path
+ "#{@parent.path}##{aref}"
+ end
+
+ ##
+ # Name of our parent with special handling for un-marshaled methods
+
+ def parent_name
+ @parent_name || super
+ end
+
+ def pretty_print q # :nodoc:
+ alias_for =
+ if @is_alias_for.respond_to? :name then
+ "alias for #{@is_alias_for.name}"
+ elsif Array === @is_alias_for then
+ "alias for #{@is_alias_for.last}"
+ end
+
+ q.group 2, "[#{self.class.name} #{full_name} #{visibility}", "]" do
+ if alias_for then
+ q.breakable
+ q.text alias_for
+ end
+
+ if text then
+ q.breakable
+ q.text "text:"
+ q.breakable
+ q.pp @text
+ end
+
+ unless comment.empty? then
+ q.breakable
+ q.text "comment:"
+ q.breakable
+ q.pp @comment
+ end
+ end
+ end
+
+ ##
+ # Used by RDoc::Generator::JsonIndex to create a record for the search
+ # engine.
+
+ def search_record
+ [
+ @name,
+ full_name,
+ @name,
+ @parent.full_name,
+ path,
+ params,
+ snippet(@comment),
+ ]
+ end
+
+ def to_s # :nodoc:
+ if @is_alias_for
+ "#{self.class.name}: #{full_name} -> #{is_alias_for}"
+ else
+ "#{self.class.name}: #{full_name}"
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/mixin.rb b/lib/rdoc/mixin.rb
new file mode 100644
index 0000000000..379d7cc526
--- /dev/null
+++ b/lib/rdoc/mixin.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+##
+# A Mixin adds features from a module into another context. RDoc::Include and
+# RDoc::Extend are both mixins.
+
+class RDoc::Mixin < RDoc::CodeObject
+
+ ##
+ # Name of included module
+
+ attr_accessor :name
+
+ ##
+ # Creates a new Mixin for +name+ with +comment+
+
+ def initialize(name, comment)
+ super()
+ @name = name
+ self.comment = comment
+ @module = nil # cache for module if found
+ end
+
+ ##
+ # Mixins are sorted by name
+
+ def <=> other
+ return unless self.class === other
+
+ name <=> other.name
+ end
+
+ def == other # :nodoc:
+ self.class === other and @name == other.name
+ end
+
+ alias eql? == # :nodoc:
+
+ ##
+ # Full name based on #module
+
+ def full_name
+ m = self.module
+ RDoc::ClassModule === m ? m.full_name : @name
+ end
+
+ def hash # :nodoc:
+ [@name, self.module].hash
+ end
+
+ def inspect # :nodoc:
+ "#<%s:0x%x %s.%s %s>" % [
+ self.class,
+ object_id,
+ parent_name, self.class.name.downcase, @name,
+ ]
+ end
+
+ ##
+ # Attempts to locate the included module object. Returns the name if not
+ # known.
+ #
+ # The scoping rules of Ruby to resolve the name of an included module are:
+ # - first look into the children of the current context;
+ # - if not found, look into the children of included modules,
+ # in reverse inclusion order;
+ # - if still not found, go up the hierarchy of names.
+ #
+ # This method has <code>O(n!)</code> behavior when the module calling
+ # include is referencing nonexistent modules. Avoid calling #module until
+ # after all the files are parsed. This behavior is due to ruby's constant
+ # lookup behavior.
+ #
+ # As of the beginning of October, 2011, no gem includes nonexistent modules.
+
+ def module
+ return @module if @module
+
+ # search the current context
+ return @name unless parent
+ full_name = parent.child_name(@name)
+ @module = @store.modules_hash[full_name]
+ return @module if @module
+ return @name if @name =~ /^::/
+
+ # search the includes before this one, in reverse order
+ searched = parent.includes.take_while { |i| i != self }.reverse
+ searched.each do |i|
+ inc = i.module
+ next if String === inc
+ full_name = inc.child_name(@name)
+ @module = @store.modules_hash[full_name]
+ return @module if @module
+ end
+
+ # go up the hierarchy of names
+ up = parent.parent
+ while up
+ full_name = up.child_name(@name)
+ @module = @store.modules_hash[full_name]
+ return @module if @module
+ up = up.parent
+ end
+
+ @name
+ end
+
+ ##
+ # Sets the store for this class or module and its contained code objects.
+
+ def store= store
+ super
+
+ @file = @store.add_file @file.full_name if @file
+ end
+
+ def to_s # :nodoc:
+ "#{self.class.name.downcase} #@name in: #{parent}"
+ end
+
+end
+
diff --git a/lib/rdoc/normal_class.rb b/lib/rdoc/normal_class.rb
new file mode 100644
index 0000000000..68dfa7d4a3
--- /dev/null
+++ b/lib/rdoc/normal_class.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+##
+# A normal class, neither singleton nor anonymous
+
+class RDoc::NormalClass < RDoc::ClassModule
+
+ ##
+ # The ancestors of this class including modules. Unlike Module#ancestors,
+ # this class is not included in the result. The result will contain both
+ # RDoc::ClassModules and Strings.
+
+ def ancestors
+ if String === superclass then
+ super << superclass
+ elsif superclass then
+ ancestors = super
+ ancestors << superclass
+ ancestors.concat superclass.ancestors
+ else
+ super
+ end
+ end
+
+ def aref_prefix # :nodoc:
+ 'class'
+ end
+
+ ##
+ # The definition of this class, <tt>class MyClassName</tt>
+
+ def definition
+ "class #{full_name}"
+ end
+
+ def direct_ancestors
+ superclass ? super + [superclass] : super
+ end
+
+ def inspect # :nodoc:
+ superclass = @superclass ? " < #{@superclass}" : nil
+ "<%s:0x%x class %s%s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [
+ self.class, object_id,
+ full_name, superclass, @includes, @extends, @attributes, @method_list, @aliases
+ ]
+ end
+
+ def to_s # :nodoc:
+ display = "#{self.class.name} #{self.full_name}"
+ if superclass
+ display += ' < ' + (superclass.is_a?(String) ? superclass : superclass.full_name)
+ end
+ display += ' -> ' + is_alias_for.to_s if is_alias_for
+ display
+ end
+
+ def pretty_print q # :nodoc:
+ superclass = @superclass ? " < #{@superclass}" : nil
+
+ q.group 2, "[class #{full_name}#{superclass}", "]" do
+ q.breakable
+ q.text "includes:"
+ q.breakable
+ q.seplist @includes do |inc| q.pp inc end
+
+ q.breakable
+ q.text "constants:"
+ q.breakable
+ q.seplist @constants do |const| q.pp const end
+
+ q.breakable
+ q.text "attributes:"
+ q.breakable
+ q.seplist @attributes do |attr| q.pp attr end
+
+ q.breakable
+ q.text "methods:"
+ q.breakable
+ q.seplist @method_list do |meth| q.pp meth end
+
+ q.breakable
+ q.text "aliases:"
+ q.breakable
+ q.seplist @aliases do |aliaz| q.pp aliaz end
+
+ q.breakable
+ q.text "comment:"
+ q.breakable
+ q.pp comment
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/normal_module.rb b/lib/rdoc/normal_module.rb
new file mode 100644
index 0000000000..edf29f8f1c
--- /dev/null
+++ b/lib/rdoc/normal_module.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+##
+# A normal module, like NormalClass
+
+class RDoc::NormalModule < RDoc::ClassModule
+
+ def aref_prefix # :nodoc:
+ 'module'
+ end
+
+ def inspect # :nodoc:
+ "#<%s:0x%x module %s includes: %p extends: %p attributes: %p methods: %p aliases: %p>" % [
+ self.class, object_id,
+ full_name, @includes, @extends, @attributes, @method_list, @aliases
+ ]
+ end
+
+ ##
+ # The definition of this module, <tt>module MyModuleName</tt>
+
+ def definition
+ "module #{full_name}"
+ end
+
+ ##
+ # This is a module, returns true
+
+ def module?
+ true
+ end
+
+ def pretty_print q # :nodoc:
+ q.group 2, "[module #{full_name}:", "]" do
+ q.breakable
+ q.text "includes:"
+ q.breakable
+ q.seplist @includes do |inc| q.pp inc end
+ q.breakable
+
+ q.breakable
+ q.text "constants:"
+ q.breakable
+ q.seplist @constants do |const| q.pp const end
+
+ q.text "attributes:"
+ q.breakable
+ q.seplist @attributes do |attr| q.pp attr end
+ q.breakable
+
+ q.text "methods:"
+ q.breakable
+ q.seplist @method_list do |meth| q.pp meth end
+ q.breakable
+
+ q.text "aliases:"
+ q.breakable
+ q.seplist @aliases do |aliaz| q.pp aliaz end
+ q.breakable
+
+ q.text "comment:"
+ q.breakable
+ q.pp comment
+ end
+ end
+
+ ##
+ # Modules don't have one, raises NoMethodError
+
+ def superclass
+ raise NoMethodError, "#{full_name} is a module"
+ end
+
+end
+
diff --git a/lib/rdoc/options.rb b/lib/rdoc/options.rb
index 2631d57364..eed0f6b39b 100644
--- a/lib/rdoc/options.rb
+++ b/lib/rdoc/options.rb
@@ -105,7 +105,6 @@ class RDoc::Options
generator_name
generator_options
generators
- locale
op_dir
page_dir
option_parser
@@ -233,9 +232,9 @@ class RDoc::Options
attr_accessor :main_page
##
- # The markup format.
- # One of: +rdoc+ (the default), +markdown+, +rd+, +tomdoc+.
- # See {Markup Formats}[rdoc-ref:RDoc::Markup@Markup+Formats].
+ # The default markup format. The default is 'rdoc'. 'markdown', 'tomdoc'
+ # and 'rd' are also built-in.
+
attr_accessor :markup
##
@@ -566,10 +565,9 @@ class RDoc::Options
@op_dir ||= 'doc'
+ @rdoc_include << "." if @rdoc_include.empty?
root = @root.to_s
- if @rdoc_include.empty? || !@rdoc_include.include?(root)
- @rdoc_include << root
- end
+ @rdoc_include << root unless @rdoc_include.include?(root)
@exclude = self.exclude
@@ -683,7 +681,7 @@ Usage: #{opt.program_name} [options] [names...]
EOF
- parsers = Hash.new { |h, parser| h[parser] = [] }
+ parsers = Hash.new { |h,parser| h[parser] = [] }
RDoc::Parser.parsers.each do |regexp, parser|
parsers[parser.name.sub('RDoc::Parser::', '')] << regexp.source
diff --git a/lib/rdoc/parser.rb b/lib/rdoc/parser.rb
index 76801ba377..3bb6f5d1f2 100644
--- a/lib/rdoc/parser.rb
+++ b/lib/rdoc/parser.rb
@@ -125,11 +125,9 @@ class RDoc::Parser
return parser if ext_name.empty?
if parser == RDoc::Parser::Simple and ext_name !~ /txt|rdoc/ then
- case mode = check_modeline(file_name)
+ case check_modeline file_name
when nil, 'rdoc' then # continue
- else
- RDoc::Parser.parsers.find { |_, p| return p if mode.casecmp?(p.name[/\w+\z/]) }
- return nil
+ else return nil
end
end
@@ -166,8 +164,7 @@ class RDoc::Parser
# Finds and instantiates the correct parser for the given +file_name+ and
# +content+.
- def self.for top_level, content, options, stats
- file_name = top_level.absolute_name
+ def self.for top_level, file_name, content, options, stats
return if binary? file_name
parser = use_markup content
diff --git a/lib/rdoc/parser/c.rb b/lib/rdoc/parser/c.rb
index 4050d7aa49..5695bf1acb 100644
--- a/lib/rdoc/parser/c.rb
+++ b/lib/rdoc/parser/c.rb
@@ -440,7 +440,7 @@ class RDoc::Parser::C < RDoc::Parser
# Scans #content for rb_include_module
def do_includes
- @content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c, m|
+ @content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m|
next unless cls = @classes[c]
m = @known_classes[m] || m
@@ -575,18 +575,19 @@ class RDoc::Parser::C < RDoc::Parser
table = {}
file_content.scan(%r{
((?>/\*.*?\*/\s*)?)
- ((?:\w+\s+){0,2} VALUE\s+(\w+)
- \s*(?:\([^\)]*\))(?:[^\);]|$))
+ ((?:(?:\w+)\s+)?
+ (?:intern\s+)?VALUE\s+(\w+)
+ \s*(?:\([^)]*\))(?:[^\);]|$))
| ((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+(\w+)\s+(\w+))
| ^\s*\#\s*define\s+(\w+)\s+(\w+)
}xm) do
case
- when name = $3
- table[name] = [:func_def, $1, $2, $~.offset(2)] if !(t = table[name]) || t[0] != :func_def
- when name = $6
- table[name] = [:macro_def, $4, $5, $~.offset(5), $7] if !(t = table[name]) || t[0] == :macro_alias
- when name = $8
- table[name] ||= [:macro_alias, $9]
+ when $1
+ table[$3] = [:func_def, $1, $2, $~.offset(2)] if !table[$3] || table[$3][0] != :func_def
+ when $4
+ table[$6] = [:macro_def, $4, $5, $~.offset(5), $7] if !table[$6] || table[$6][0] == :macro_alias
+ when $8
+ table[$8] ||= [:macro_alias, $9]
end
end
table
@@ -756,27 +757,17 @@ class RDoc::Parser::C < RDoc::Parser
def gen_const_table file_content
table = {}
@content.scan(%r{
- (?<doc>(?>^\s*/\*.*?\*/\s+))
- rb_define_(?<type>\w+)\(\s*(?:\w+),\s*
- "(?<name>\w+)"\s*,
+ ((?>^\s*/\*.*?\*/\s+))
+ rb_define_(\w+)\((?:\s*(?:\w+),)?\s*
+ "(\w+)"\s*,
.*?\)\s*;
- | (?<doc>(?>^\s*/\*.*?\*/\s+))
- rb_file_(?<type>const)\(\s*
- "(?<name>\w+)"\s*,
- .*?\)\s*;
- | (?<doc>(?>^\s*/\*.*?\*/\s+))
- rb_curses_define_(?<type>const)\(\s*
- (?<name>\w+)
- \s*\)\s*;
| Document-(?:const|global|variable):\s
- (?<name>(?:\w+::)*\w+)
- \s*?\n(?<doc>(?>.*?\*/))
+ ((?:\w+::)*\w+)
+ \s*?\n((?>.*?\*/))
}mxi) do
- name, doc, type = $~.values_at(:name, :doc, :type)
- if type
- table[[type, name]] = doc
- else
- table[name] = "/*\n" + doc
+ case
+ when $1 then table[[$2, $3]] = $1
+ when $4 then table[$4] = "/*\n" + $5
end
end
table
@@ -948,13 +939,14 @@ class RDoc::Parser::C < RDoc::Parser
# "/* definition: comment */" form. The literal ':' and '\' characters
# can be escaped with a backslash.
if type.downcase == 'const' then
- if /\A(.+?)?:(?!\S)/ =~ comment.text
- new_definition, new_comment = $1, $'
+ no_match, new_definition, new_comment = comment.text.split(/(\A.*):/)
- if !new_definition # Default to literal C definition
+ if no_match and no_match.empty? then
+ if new_definition.empty? then # Default to literal C definition
new_definition = definition
else
- new_definition = new_definition.gsub(/\\([\\:])/, '\1')
+ new_definition = new_definition.gsub("\:", ":")
+ new_definition = new_definition.gsub("\\", '\\')
end
new_definition.sub!(/\A(\s+)/, '')
@@ -1225,9 +1217,6 @@ class RDoc::Parser::C < RDoc::Parser
@top_level
end
- ##
- # Creates a RDoc::Comment instance.
-
def new_comment text = nil, location = nil, language = nil
RDoc::Comment.new(text, location, language).tap do |comment|
comment.format = @markup
diff --git a/lib/rdoc/parser/changelog.rb b/lib/rdoc/parser/changelog.rb
index 12a50f8d0e..9245d49376 100644
--- a/lib/rdoc/parser/changelog.rb
+++ b/lib/rdoc/parser/changelog.rb
@@ -193,7 +193,7 @@ class RDoc::Parser::ChangeLog < RDoc::Parser
entries << [entry_name, entry_body] if entry_name
- entries.reject! do |(entry, _)|
+ entries.reject! do |(entry,_)|
entry == nil
end
@@ -216,22 +216,12 @@ class RDoc::Parser::ChangeLog < RDoc::Parser
@top_level
end
- ##
- # The extension for Git commit log
-
module Git
- ##
- # Parses auxiliary info. Currently `base-url` to expand
- # references is effective.
-
def parse_info(info)
/^\s*base-url\s*=\s*(.*\S)/ =~ info
@base_url = $1
end
- ##
- # Parses the entries in the Git commit logs
-
def parse_entries
entries = []
@@ -254,11 +244,6 @@ class RDoc::Parser::ChangeLog < RDoc::Parser
entries
end
- ##
- # Returns a list of ChangeLog entries as
- # RDoc::Parser::ChangeLog::Git::LogEntry list for the given
- # +entries+.
-
def create_entries entries
# git log entries have no strictly itemized style like the old
# style, just assume Markdown.
@@ -347,3 +332,4 @@ class RDoc::Parser::ChangeLog < RDoc::Parser
end
end
end
+
diff --git a/lib/rdoc/parser/markdown.rb b/lib/rdoc/parser/markdown.rb
index 3c316227b9..9ff478f872 100644
--- a/lib/rdoc/parser/markdown.rb
+++ b/lib/rdoc/parser/markdown.rb
@@ -20,3 +20,5 @@ class RDoc::Parser::Markdown < RDoc::Parser
end
end
+
+
diff --git a/lib/rdoc/parser/prism_ruby.rb b/lib/rdoc/parser/prism_ruby.rb
deleted file mode 100644
index 05e98ad6c4..0000000000
--- a/lib/rdoc/parser/prism_ruby.rb
+++ /dev/null
@@ -1,1026 +0,0 @@
-# frozen_string_literal: true
-
-require 'prism'
-require_relative 'ripper_state_lex'
-
-# Unlike lib/rdoc/parser/ruby.rb, this file is not based on rtags and does not contain code from
-# rtags.rb -
-# ruby-lex.rb - ruby lexcal analyzer
-# ruby-token.rb - ruby tokens
-
-# Parse and collect document from Ruby source code.
-# RDoc::Parser::PrismRuby is compatible with RDoc::Parser::Ruby and aims to replace it.
-
-class RDoc::Parser::PrismRuby < RDoc::Parser
-
- parse_files_matching(/\.rbw?$/) if ENV['RDOC_USE_PRISM_PARSER']
-
- attr_accessor :visibility
- attr_reader :container, :singleton
-
- def initialize(top_level, file_name, content, options, stats)
- super
-
- content = handle_tab_width(content)
-
- @size = 0
- @token_listeners = nil
- content = RDoc::Encoding.remove_magic_comment content
- @content = content
- @markup = @options.markup
- @track_visibility = :nodoc != @options.visibility
- @encoding = @options.encoding
-
- @module_nesting = [top_level]
- @container = top_level
- @visibility = :public
- @singleton = false
- end
-
- # Dive into another container
-
- def with_container(container, singleton: false)
- old_container = @container
- old_visibility = @visibility
- old_singleton = @singleton
- @visibility = :public
- @container = container
- @singleton = singleton
- unless singleton
- @module_nesting.push container
-
- # Need to update module parent chain to emulate Module.nesting.
- # This mechanism is inaccurate and needs to be fixed.
- container.parent = old_container
- end
- yield container
- ensure
- @container = old_container
- @visibility = old_visibility
- @singleton = old_singleton
- @module_nesting.pop unless singleton
- end
-
- # Records the location of this +container+ in the file for this parser and
- # adds it to the list of classes and modules in the file.
-
- def record_location container # :nodoc:
- case container
- when RDoc::ClassModule then
- @top_level.add_to_classes_or_modules container
- end
-
- container.record_location @top_level
- end
-
- # Scans this Ruby file for Ruby constructs
-
- def scan
- @tokens = RDoc::Parser::RipperStateLex.parse(@content)
- @lines = @content.lines
- result = Prism.parse(@content)
- @program_node = result.value
- @line_nodes = {}
- prepare_line_nodes(@program_node)
- prepare_comments(result.comments)
- return if @top_level.done_documenting
-
- @first_non_meta_comment = nil
- if (_line_no, start_line, rdoc_comment = @unprocessed_comments.first)
- @first_non_meta_comment = rdoc_comment if start_line < @program_node.location.start_line
- end
-
- @program_node.accept(RDocVisitor.new(self, @top_level, @store))
- process_comments_until(@lines.size + 1)
- end
-
- def should_document?(code_object) # :nodoc:
- return true unless @track_visibility
- return false if code_object.parent&.document_children == false
- code_object.document_self
- end
-
- # Assign AST node to a line.
- # This is used to show meta-method source code in the documentation.
-
- def prepare_line_nodes(node) # :nodoc:
- case node
- when Prism::CallNode, Prism::DefNode
- @line_nodes[node.location.start_line] ||= node
- end
- node.compact_child_nodes.each do |child|
- prepare_line_nodes(child)
- end
- end
-
- # Prepares comments for processing. Comments are grouped into consecutive.
- # Consecutive comment is linked to the next non-blank line.
- #
- # Example:
- # 01| class A # modifier comment 1
- # 02| def foo; end # modifier comment 2
- # 03|
- # 04| # consecutive comment 1 start_line: 4
- # 05| # consecutive comment 1 linked to line: 7
- # 06|
- # 07| # consecutive comment 2 start_line: 7
- # 08| # consecutive comment 2 linked to line: 10
- # 09|
- # 10| def bar; end # consecutive comment 2 linked to this line
- # 11| end
-
- def prepare_comments(comments)
- current = []
- consecutive_comments = [current]
- @modifier_comments = {}
- comments.each do |comment|
- if comment.is_a? Prism::EmbDocComment
- consecutive_comments << [comment] << (current = [])
- elsif comment.location.start_line_slice.match?(/\S/)
- @modifier_comments[comment.location.start_line] = RDoc::Comment.new(comment.slice, @top_level, :ruby)
- elsif current.empty? || current.last.location.end_line + 1 == comment.location.start_line
- current << comment
- else
- consecutive_comments << (current = [comment])
- end
- end
- consecutive_comments.reject!(&:empty?)
-
- # Example: line_no = 5, start_line = 2, comment_text = "# comment_start_line\n# comment\n"
- # 1| class A
- # 2| # comment_start_line
- # 3| # comment
- # 4|
- # 5| def f; end # comment linked to this line
- # 6| end
- @unprocessed_comments = consecutive_comments.map! do |comments|
- start_line = comments.first.location.start_line
- line_no = comments.last.location.end_line + (comments.last.location.end_column == 0 ? 0 : 1)
- texts = comments.map do |c|
- c.is_a?(Prism::EmbDocComment) ? c.slice.lines[1...-1].join : c.slice
- end
- text = RDoc::Encoding.change_encoding(texts.join("\n"), @encoding) if @encoding
- line_no += 1 while @lines[line_no - 1]&.match?(/\A\s*$/)
- comment = RDoc::Comment.new(text, @top_level, :ruby)
- comment.line = start_line
- [line_no, start_line, comment]
- end
-
- # The first comment is special. It defines markup for the rest of the comments.
- _, first_comment_start_line, first_comment_text = @unprocessed_comments.first
- if first_comment_text && @lines[0...first_comment_start_line - 1].all? { |l| l.match?(/\A\s*$/) }
- comment = RDoc::Comment.new(first_comment_text.text, @top_level, :ruby)
- handle_consecutive_comment_directive(@container, comment)
- @markup = comment.format
- end
- @unprocessed_comments.each do |_, _, comment|
- comment.format = @markup
- end
- end
-
- # Creates an RDoc::Method on +container+ from +comment+ if there is a
- # Signature section in the comment
-
- def parse_comment_tomdoc(container, comment, line_no, start_line)
- return unless signature = RDoc::TomDoc.signature(comment)
-
- name, = signature.split %r%[ \(]%, 2
-
- meth = RDoc::GhostMethod.new comment.text, name
- record_location(meth)
- meth.line = start_line
- meth.call_seq = signature
- return unless meth.name
-
- meth.start_collecting_tokens
- node = @line_nodes[line_no]
- tokens = node ? visible_tokens_from_location(node.location) : [file_line_comment_token(start_line)]
- tokens.each { |token| meth.token_stream << token }
-
- container.add_method meth
- comment.remove_private
- comment.normalize
- meth.comment = comment
- @stats.add_method meth
- end
-
- def handle_modifier_directive(code_object, line_no) # :nodoc:
- comment = @modifier_comments[line_no]
- @preprocess.handle(comment.text, code_object) if comment
- end
-
- def handle_consecutive_comment_directive(code_object, comment) # :nodoc:
- return unless comment
- @preprocess.handle(comment, code_object) do |directive, param|
- case directive
- when 'method', 'singleton-method',
- 'attr', 'attr_accessor', 'attr_reader', 'attr_writer' then
- # handled elsewhere
- ''
- when 'section' then
- @container.set_current_section(param, comment.dup)
- comment.text = ''
- break
- end
- end
- comment.remove_private
- end
-
- def call_node_name_arguments(call_node) # :nodoc:
- return [] unless call_node.arguments
- call_node.arguments.arguments.map do |arg|
- case arg
- when Prism::SymbolNode
- arg.value
- when Prism::StringNode
- arg.unescaped
- end
- end || []
- end
-
- # Handles meta method comments
-
- def handle_meta_method_comment(comment, node)
- is_call_node = node.is_a?(Prism::CallNode)
- singleton_method = false
- visibility = @visibility
- attributes = rw = line_no = method_name = nil
-
- processed_comment = comment.dup
- @preprocess.handle(processed_comment, @container) do |directive, param, line|
- case directive
- when 'attr', 'attr_reader', 'attr_writer', 'attr_accessor'
- attributes = [param] if param
- attributes ||= call_node_name_arguments(node) if is_call_node
- rw = directive == 'attr_writer' ? 'W' : directive == 'attr_accessor' ? 'RW' : 'R'
- ''
- when 'method'
- method_name = param
- line_no = line
- ''
- when 'singleton-method'
- method_name = param
- line_no = line
- singleton_method = true
- visibility = :public
- ''
- when 'section' then
- @container.set_current_section(param, comment.dup)
- return # If the comment contains :section:, it is not a meta method comment
- end
- end
-
- if attributes
- attributes.each do |attr|
- a = RDoc::Attr.new(@container, attr, rw, processed_comment)
- a.store = @store
- a.line = line_no
- a.singleton = @singleton
- record_location(a)
- @container.add_attribute(a)
- a.visibility = visibility
- end
- elsif line_no || node
- method_name ||= call_node_name_arguments(node).first if is_call_node
- meth = RDoc::AnyMethod.new(@container, method_name)
- meth.singleton = @singleton || singleton_method
- handle_consecutive_comment_directive(meth, comment)
- comment.normalize
- comment.extract_call_seq(meth)
- meth.comment = comment
- if node
- tokens = visible_tokens_from_location(node.location)
- line_no = node.location.start_line
- else
- tokens = [file_line_comment_token(line_no)]
- end
- internal_add_method(
- @container,
- meth,
- line_no: line_no,
- visibility: visibility,
- singleton: @singleton || singleton_method,
- params: '()',
- calls_super: false,
- block_params: nil,
- tokens: tokens
- )
- end
- end
-
- def normal_comment_treat_as_ghost_method_for_now?(comment_text, line_no) # :nodoc:
- # Meta method comment should start with `##` but some comments does not follow this rule.
- # For now, RDoc accepts them as a meta method comment if there is no node linked to it.
- !@line_nodes[line_no] && comment_text.match?(/^#\s+:(method|singleton-method|attr|attr_reader|attr_writer|attr_accessor):/)
- end
-
- def handle_standalone_consecutive_comment_directive(comment, line_no, start_line) # :nodoc:
- if @markup == 'tomdoc'
- parse_comment_tomdoc(@container, comment, line_no, start_line)
- return
- end
-
- if comment.text =~ /\A#\#$/ && comment != @first_non_meta_comment
- node = @line_nodes[line_no]
- handle_meta_method_comment(comment, node)
- elsif normal_comment_treat_as_ghost_method_for_now?(comment.text, line_no) && comment != @first_non_meta_comment
- handle_meta_method_comment(comment, nil)
- else
- handle_consecutive_comment_directive(@container, comment)
- end
- end
-
- # Processes consecutive comments that were not linked to any documentable code until the given line number
-
- def process_comments_until(line_no_until)
- while !@unprocessed_comments.empty? && @unprocessed_comments.first[0] <= line_no_until
- line_no, start_line, rdoc_comment = @unprocessed_comments.shift
- handle_standalone_consecutive_comment_directive(rdoc_comment, line_no, start_line)
- end
- end
-
- # Skips all undocumentable consecutive comments until the given line number.
- # Undocumentable comments are comments written inside `def` or inside undocumentable class/module
-
- def skip_comments_until(line_no_until)
- while !@unprocessed_comments.empty? && @unprocessed_comments.first[0] <= line_no_until
- @unprocessed_comments.shift
- end
- end
-
- # Returns consecutive comment linked to the given line number
-
- def consecutive_comment(line_no)
- if @unprocessed_comments.first&.first == line_no
- @unprocessed_comments.shift.last
- end
- end
-
- def slice_tokens(start_pos, end_pos) # :nodoc:
- start_index = @tokens.bsearch_index { |t| ([t.line_no, t.char_no] <=> start_pos) >= 0 }
- end_index = @tokens.bsearch_index { |t| ([t.line_no, t.char_no] <=> end_pos) >= 0 }
- tokens = @tokens[start_index...end_index]
- tokens.pop if tokens.last&.kind == :on_nl
- tokens
- end
-
- def file_line_comment_token(line_no) # :nodoc:
- position_comment = RDoc::Parser::RipperStateLex::Token.new(line_no - 1, 0, :on_comment)
- position_comment[:text] = "# File #{@top_level.relative_name}, line #{line_no}"
- position_comment
- end
-
- # Returns tokens from the given location
-
- def visible_tokens_from_location(location)
- position_comment = file_line_comment_token(location.start_line)
- newline_token = RDoc::Parser::RipperStateLex::Token.new(0, 0, :on_nl, "\n")
- indent_token = RDoc::Parser::RipperStateLex::Token.new(location.start_line, 0, :on_sp, ' ' * location.start_character_column)
- tokens = slice_tokens(
- [location.start_line, location.start_character_column],
- [location.end_line, location.end_character_column]
- )
- [position_comment, newline_token, indent_token, *tokens]
- end
-
- # Handles `public :foo, :bar` `private :foo, :bar` and `protected :foo, :bar`
-
- def change_method_visibility(names, visibility, singleton: @singleton)
- new_methods = []
- @container.methods_matching(names, singleton) do |m|
- if m.parent != @container
- m = m.dup
- record_location(m)
- new_methods << m
- else
- m.visibility = visibility
- end
- end
- new_methods.each do |method|
- case method
- when RDoc::AnyMethod then
- @container.add_method(method)
- when RDoc::Attr then
- @container.add_attribute(method)
- end
- method.visibility = visibility
- end
- end
-
- # Handles `module_function :foo, :bar`
-
- def change_method_to_module_function(names)
- @container.set_visibility_for(names, :private, false)
- new_methods = []
- @container.methods_matching(names) do |m|
- s_m = m.dup
- record_location(s_m)
- s_m.singleton = true
- new_methods << s_m
- end
- new_methods.each do |method|
- case method
- when RDoc::AnyMethod then
- @container.add_method(method)
- when RDoc::Attr then
- @container.add_attribute(method)
- end
- method.visibility = :public
- end
- end
-
- # Handles `alias foo bar` and `alias_method :foo, :bar`
-
- def add_alias_method(old_name, new_name, line_no)
- comment = consecutive_comment(line_no)
- handle_consecutive_comment_directive(@container, comment)
- visibility = @container.find_method(old_name, @singleton)&.visibility || :public
- a = RDoc::Alias.new(nil, old_name, new_name, comment, @singleton)
- a.comment = comment
- handle_modifier_directive(a, line_no)
- a.store = @store
- a.line = line_no
- record_location(a)
- if should_document?(a)
- @container.add_alias(a)
- @container.find_method(new_name, @singleton)&.visibility = visibility
- end
- end
-
- # Handles `attr :a, :b`, `attr_reader :a, :b`, `attr_writer :a, :b` and `attr_accessor :a, :b`
-
- def add_attributes(names, rw, line_no)
- comment = consecutive_comment(line_no)
- handle_consecutive_comment_directive(@container, comment)
- return unless @container.document_children
-
- names.each do |symbol|
- a = RDoc::Attr.new(nil, symbol.to_s, rw, comment)
- a.store = @store
- a.line = line_no
- a.singleton = @singleton
- record_location(a)
- handle_modifier_directive(a, line_no)
- @container.add_attribute(a) if should_document?(a)
- a.visibility = visibility # should set after adding to container
- end
- end
-
- def add_includes_extends(names, rdoc_class, line_no) # :nodoc:
- comment = consecutive_comment(line_no)
- handle_consecutive_comment_directive(@container, comment)
- names.each do |name|
- ie = @container.add(rdoc_class, name, '')
- ie.store = @store
- ie.line = line_no
- ie.comment = comment
- record_location(ie)
- end
- end
-
- # Handle `include Foo, Bar`
-
- def add_includes(names, line_no) # :nodoc:
- add_includes_extends(names, RDoc::Include, line_no)
- end
-
- # Handle `extend Foo, Bar`
-
- def add_extends(names, line_no) # :nodoc:
- add_includes_extends(names, RDoc::Extend, line_no)
- end
-
- # Adds a method defined by `def` syntax
-
- def add_method(name, receiver_name:, receiver_fallback_type:, visibility:, singleton:, params:, calls_super:, block_params:, tokens:, start_line:, end_line:)
- receiver = receiver_name ? find_or_create_module_path(receiver_name, receiver_fallback_type) : @container
- meth = RDoc::AnyMethod.new(nil, name)
- if (comment = consecutive_comment(start_line))
- handle_consecutive_comment_directive(@container, comment)
- handle_consecutive_comment_directive(meth, comment)
-
- comment.normalize
- comment.extract_call_seq(meth)
- meth.comment = comment
- end
- handle_modifier_directive(meth, start_line)
- handle_modifier_directive(meth, end_line)
- return unless should_document?(meth)
-
-
- if meth.name == 'initialize' && !singleton
- if meth.dont_rename_initialize
- visibility = :protected
- else
- meth.name = 'new'
- singleton = true
- visibility = :public
- end
- end
-
- internal_add_method(
- receiver,
- meth,
- line_no: start_line,
- visibility: visibility,
- singleton: singleton,
- params: params,
- calls_super: calls_super,
- block_params: block_params,
- tokens: tokens
- )
- end
-
- private def internal_add_method(container, meth, line_no:, visibility:, singleton:, params:, calls_super:, block_params:, tokens:) # :nodoc:
- meth.name ||= meth.call_seq[/\A[^()\s]+/] if meth.call_seq
- meth.name ||= 'unknown'
- meth.store = @store
- meth.line = line_no
- meth.singleton = singleton
- container.add_method(meth) # should add after setting singleton and before setting visibility
- meth.visibility = visibility
- meth.params ||= params
- meth.calls_super = calls_super
- meth.block_params ||= block_params if block_params
- record_location(meth)
- meth.start_collecting_tokens
- tokens.each do |token|
- meth.token_stream << token
- end
- end
-
- # Find or create module or class from a given module name.
- # If module or class does not exist, creates a module or a class according to `create_mode` argument.
-
- def find_or_create_module_path(module_name, create_mode)
- root_name, *path, name = module_name.split('::')
- add_module = ->(mod, name, mode) {
- case mode
- when :class
- mod.add_class(RDoc::NormalClass, name, 'Object').tap { |m| m.store = @store }
- when :module
- mod.add_module(RDoc::NormalModule, name).tap { |m| m.store = @store }
- end
- }
- if root_name.empty?
- mod = @top_level
- else
- @module_nesting.reverse_each do |nesting|
- mod = nesting.find_module_named(root_name)
- break if mod
- end
- return mod || add_module.call(@top_level, root_name, create_mode) unless name
- mod ||= add_module.call(@top_level, root_name, :module)
- end
- path.each do |name|
- mod = mod.find_module_named(name) || add_module.call(mod, name, :module)
- end
- mod.find_module_named(name) || add_module.call(mod, name, create_mode)
- end
-
- # Resolves constant path to a full path by searching module nesting
-
- def resolve_constant_path(constant_path)
- owner_name, path = constant_path.split('::', 2)
- return constant_path if owner_name.empty? # ::Foo, ::Foo::Bar
- mod = nil
- @module_nesting.reverse_each do |nesting|
- mod = nesting.find_module_named(owner_name)
- break if mod
- end
- mod ||= @top_level.find_module_named(owner_name)
- [mod.full_name, path].compact.join('::') if mod
- end
-
- # Returns a pair of owner module and constant name from a given constant path.
- # Creates owner module if it does not exist.
-
- def find_or_create_constant_owner_name(constant_path)
- const_path, colon, name = constant_path.rpartition('::')
- if colon.empty? # class Foo
- [@container, name]
- elsif const_path.empty? # class ::Foo
- [@top_level, name]
- else # `class Foo::Bar` or `class ::Foo::Bar`
- [find_or_create_module_path(const_path, :module), name]
- end
- end
-
- # Adds a constant
-
- def add_constant(constant_name, rhs_name, start_line, end_line)
- comment = consecutive_comment(start_line)
- handle_consecutive_comment_directive(@container, comment)
- owner, name = find_or_create_constant_owner_name(constant_name)
- constant = RDoc::Constant.new(name, rhs_name, comment)
- constant.store = @store
- constant.line = start_line
- record_location(constant)
- handle_modifier_directive(constant, start_line)
- handle_modifier_directive(constant, end_line)
- owner.add_constant(constant)
- mod =
- if rhs_name =~ /^::/
- @store.find_class_or_module(rhs_name)
- else
- @container.find_module_named(rhs_name)
- end
- if mod && constant.document_self
- a = @container.add_module_alias(mod, rhs_name, constant, @top_level)
- a.store = @store
- a.line = start_line
- record_location(a)
- end
- end
-
- # Adds module or class
-
- def add_module_or_class(module_name, start_line, end_line, is_class: false, superclass_name: nil)
- comment = consecutive_comment(start_line)
- handle_consecutive_comment_directive(@container, comment)
- return unless @container.document_children
-
- owner, name = find_or_create_constant_owner_name(module_name)
- if is_class
- mod = owner.classes_hash[name] || owner.add_class(RDoc::NormalClass, name, superclass_name || '::Object')
-
- # RDoc::NormalClass resolves superclass name despite of the lack of module nesting information.
- # We need to fix it when RDoc::NormalClass resolved to a wrong constant name
- if superclass_name
- superclass_full_path = resolve_constant_path(superclass_name)
- superclass = @store.find_class_or_module(superclass_full_path) if superclass_full_path
- superclass_full_path ||= superclass_name
- if superclass
- mod.superclass = superclass
- elsif mod.superclass.is_a?(String) && mod.superclass != superclass_full_path
- mod.superclass = superclass_full_path
- end
- end
- else
- mod = owner.modules_hash[name] || owner.add_module(RDoc::NormalModule, name)
- end
-
- mod.store = @store
- mod.line = start_line
- record_location(mod)
- handle_modifier_directive(mod, start_line)
- handle_modifier_directive(mod, end_line)
- mod.add_comment(comment, @top_level) if comment
- mod
- end
-
- class RDocVisitor < Prism::Visitor # :nodoc:
- def initialize(scanner, top_level, store)
- @scanner = scanner
- @top_level = top_level
- @store = store
- end
-
- def visit_call_node(node)
- @scanner.process_comments_until(node.location.start_line - 1)
- if node.receiver.nil?
- case node.name
- when :attr
- _visit_call_attr_reader_writer_accessor(node, 'R')
- when :attr_reader
- _visit_call_attr_reader_writer_accessor(node, 'R')
- when :attr_writer
- _visit_call_attr_reader_writer_accessor(node, 'W')
- when :attr_accessor
- _visit_call_attr_reader_writer_accessor(node, 'RW')
- when :include
- _visit_call_include(node)
- when :extend
- _visit_call_extend(node)
- when :public
- _visit_call_public_private_protected(node, :public) { super }
- when :private
- _visit_call_public_private_protected(node, :private) { super }
- when :protected
- _visit_call_public_private_protected(node, :protected) { super }
- when :private_constant
- _visit_call_private_constant(node)
- when :public_constant
- _visit_call_public_constant(node)
- when :require
- _visit_call_require(node)
- when :alias_method
- _visit_call_alias_method(node)
- when :module_function
- _visit_call_module_function(node) { super }
- when :public_class_method
- _visit_call_public_private_class_method(node, :public) { super }
- when :private_class_method
- _visit_call_public_private_class_method(node, :private) { super }
- else
- super
- end
- else
- super
- end
- end
-
- def visit_alias_method_node(node)
- @scanner.process_comments_until(node.location.start_line - 1)
- return unless node.old_name.is_a?(Prism::SymbolNode) && node.new_name.is_a?(Prism::SymbolNode)
- @scanner.add_alias_method(node.old_name.value.to_s, node.new_name.value.to_s, node.location.start_line)
- end
-
- def visit_module_node(node)
- @scanner.process_comments_until(node.location.start_line - 1)
- module_name = constant_path_string(node.constant_path)
- mod = @scanner.add_module_or_class(module_name, node.location.start_line, node.location.end_line) if module_name
- if mod
- @scanner.with_container(mod) do
- super
- @scanner.process_comments_until(node.location.end_line)
- end
- else
- @scanner.skip_comments_until(node.location.end_line)
- end
- end
-
- def visit_class_node(node)
- @scanner.process_comments_until(node.location.start_line - 1)
- superclass_name = constant_path_string(node.superclass) if node.superclass
- class_name = constant_path_string(node.constant_path)
- klass = @scanner.add_module_or_class(class_name, node.location.start_line, node.location.end_line, is_class: true, superclass_name: superclass_name) if class_name
- if klass
- @scanner.with_container(klass) do
- super
- @scanner.process_comments_until(node.location.end_line)
- end
- else
- @scanner.skip_comments_until(node.location.end_line)
- end
- end
-
- def visit_singleton_class_node(node)
- @scanner.process_comments_until(node.location.start_line - 1)
-
- expression = node.expression
- expression = expression.body.body.first if expression.is_a?(Prism::ParenthesesNode) && expression.body&.body&.size == 1
-
- case expression
- when Prism::ConstantWriteNode
- # Accept `class << (NameErrorCheckers = Object.new)` as a module which is not actually a module
- mod = @scanner.container.add_module(RDoc::NormalModule, expression.name.to_s)
- when Prism::ConstantPathNode, Prism::ConstantReadNode
- expression_name = constant_path_string(expression)
- # If a constant_path does not exist, RDoc creates a module
- mod = @scanner.find_or_create_module_path(expression_name, :module) if expression_name
- when Prism::SelfNode
- mod = @scanner.container if @scanner.container != @top_level
- end
- if mod
- @scanner.with_container(mod, singleton: true) do
- super
- @scanner.process_comments_until(node.location.end_line)
- end
- else
- @scanner.skip_comments_until(node.location.end_line)
- end
- end
-
- def visit_def_node(node)
- start_line = node.location.start_line
- end_line = node.location.end_line
- @scanner.process_comments_until(start_line - 1)
-
- case node.receiver
- when Prism::NilNode, Prism::TrueNode, Prism::FalseNode
- visibility = :public
- singleton = false
- receiver_name =
- case node.receiver
- when Prism::NilNode
- 'NilClass'
- when Prism::TrueNode
- 'TrueClass'
- when Prism::FalseNode
- 'FalseClass'
- end
- receiver_fallback_type = :class
- when Prism::SelfNode
- # singleton method of a singleton class is not documentable
- return if @scanner.singleton
- visibility = :public
- singleton = true
- when Prism::ConstantReadNode, Prism::ConstantPathNode
- visibility = :public
- singleton = true
- receiver_name = constant_path_string(node.receiver)
- receiver_fallback_type = :module
- return unless receiver_name
- when nil
- visibility = @scanner.visibility
- singleton = @scanner.singleton
- else
- # `def (unknown expression).method_name` is not documentable
- return
- end
- name = node.name.to_s
- params, block_params, calls_super = MethodSignatureVisitor.scan_signature(node)
- tokens = @scanner.visible_tokens_from_location(node.location)
-
- @scanner.add_method(
- name,
- receiver_name: receiver_name,
- receiver_fallback_type: receiver_fallback_type,
- visibility: visibility,
- singleton: singleton,
- params: params,
- block_params: block_params,
- calls_super: calls_super,
- tokens: tokens,
- start_line: start_line,
- end_line: end_line
- )
- ensure
- @scanner.skip_comments_until(end_line)
- end
-
- def visit_constant_path_write_node(node)
- @scanner.process_comments_until(node.location.start_line - 1)
- path = constant_path_string(node.target)
- return unless path
-
- @scanner.add_constant(
- path,
- constant_path_string(node.value) || node.value.slice,
- node.location.start_line,
- node.location.end_line
- )
- @scanner.skip_comments_until(node.location.end_line)
- # Do not traverse rhs not to document `A::B = Struct.new{def undocumentable_method; end}`
- end
-
- def visit_constant_write_node(node)
- @scanner.process_comments_until(node.location.start_line - 1)
- @scanner.add_constant(
- node.name.to_s,
- constant_path_string(node.value) || node.value.slice,
- node.location.start_line,
- node.location.end_line
- )
- @scanner.skip_comments_until(node.location.end_line)
- # Do not traverse rhs not to document `A = Struct.new{def undocumentable_method; end}`
- end
-
- private
-
- def constant_arguments_names(call_node)
- return unless call_node.arguments
- names = call_node.arguments.arguments.map { |arg| constant_path_string(arg) }
- names.all? ? names : nil
- end
-
- def symbol_arguments(call_node)
- arguments_node = call_node.arguments
- return unless arguments_node && arguments_node.arguments.all? { |arg| arg.is_a?(Prism::SymbolNode)}
- arguments_node.arguments.map { |arg| arg.value.to_sym }
- end
-
- def visibility_method_arguments(call_node, singleton:)
- arguments_node = call_node.arguments
- return unless arguments_node
- symbols = symbol_arguments(call_node)
- if symbols
- # module_function :foo, :bar
- return symbols.map(&:to_s)
- else
- return unless arguments_node.arguments.size == 1
- arg = arguments_node.arguments.first
- return unless arg.is_a?(Prism::DefNode)
-
- if singleton
- # `private_class_method def foo; end` `private_class_method def not_self.foo; end` should be ignored
- return unless arg.receiver.is_a?(Prism::SelfNode)
- else
- # `module_function def something.foo` should be ignored
- return if arg.receiver
- end
- # `module_function def foo; end` or `private_class_method def self.foo; end`
- [arg.name.to_s]
- end
- end
-
- def constant_path_string(node)
- case node
- when Prism::ConstantReadNode
- node.name.to_s
- when Prism::ConstantPathNode
- parent_name = node.parent ? constant_path_string(node.parent) : ''
- "#{parent_name}::#{node.name}" if parent_name
- end
- end
-
- def _visit_call_require(call_node)
- return unless call_node.arguments&.arguments&.size == 1
- arg = call_node.arguments.arguments.first
- return unless arg.is_a?(Prism::StringNode)
- @scanner.container.add_require(RDoc::Require.new(arg.unescaped, nil))
- end
-
- def _visit_call_module_function(call_node)
- yield
- return if @scanner.singleton
- names = visibility_method_arguments(call_node, singleton: false)&.map(&:to_s)
- @scanner.change_method_to_module_function(names) if names
- end
-
- def _visit_call_public_private_class_method(call_node, visibility)
- yield
- return if @scanner.singleton
- names = visibility_method_arguments(call_node, singleton: true)
- @scanner.change_method_visibility(names, visibility, singleton: true) if names
- end
-
- def _visit_call_public_private_protected(call_node, visibility)
- arguments_node = call_node.arguments
- if arguments_node.nil? # `public` `private`
- @scanner.visibility = visibility
- else # `public :foo, :bar`, `private def foo; end`
- yield
- names = visibility_method_arguments(call_node, singleton: @scanner.singleton)
- @scanner.change_method_visibility(names, visibility) if names
- end
- end
-
- def _visit_call_alias_method(call_node)
- new_name, old_name, *rest = symbol_arguments(call_node)
- return unless old_name && new_name && rest.empty?
- @scanner.add_alias_method(old_name.to_s, new_name.to_s, call_node.location.start_line)
- end
-
- def _visit_call_include(call_node)
- names = constant_arguments_names(call_node)
- line_no = call_node.location.start_line
- return unless names
-
- if @scanner.singleton
- @scanner.add_extends(names, line_no)
- else
- @scanner.add_includes(names, line_no)
- end
- end
-
- def _visit_call_extend(call_node)
- names = constant_arguments_names(call_node)
- @scanner.add_extends(names, call_node.location.start_line) if names && !@scanner.singleton
- end
-
- def _visit_call_public_constant(call_node)
- return if @scanner.singleton
- names = symbol_arguments(call_node)
- @scanner.container.set_constant_visibility_for(names.map(&:to_s), :public) if names
- end
-
- def _visit_call_private_constant(call_node)
- return if @scanner.singleton
- names = symbol_arguments(call_node)
- @scanner.container.set_constant_visibility_for(names.map(&:to_s), :private) if names
- end
-
- def _visit_call_attr_reader_writer_accessor(call_node, rw)
- names = symbol_arguments(call_node)
- @scanner.add_attributes(names.map(&:to_s), rw, call_node.location.start_line) if names
- end
- class MethodSignatureVisitor < Prism::Visitor # :nodoc:
- class << self
- def scan_signature(def_node)
- visitor = new
- def_node.body&.accept(visitor)
- params = "(#{def_node.parameters&.slice})"
- block_params = visitor.yields.first
- [params, block_params, visitor.calls_super]
- end
- end
-
- attr_reader :params, :yields, :calls_super
-
- def initialize
- @params = nil
- @calls_super = false
- @yields = []
- end
-
- def visit_def_node(node)
- # stop traverse inside nested def
- end
-
- def visit_yield_node(node)
- @yields << (node.arguments&.slice || '')
- end
-
- def visit_super_node(node)
- @calls_super = true
- super
- end
-
- def visit_forwarding_super_node(node)
- @calls_super = true
- end
- end
- end
-end
diff --git a/lib/rdoc/parser/rd.rb b/lib/rdoc/parser/rd.rb
index 19e47e549d..25f5711731 100644
--- a/lib/rdoc/parser/rd.rb
+++ b/lib/rdoc/parser/rd.rb
@@ -20,3 +20,4 @@ class RDoc::Parser::RD < RDoc::Parser
end
end
+
diff --git a/lib/rdoc/parser/ripper_state_lex.rb b/lib/rdoc/parser/ripper_state_lex.rb
index 2212906bbd..5492f08726 100644
--- a/lib/rdoc/parser/ripper_state_lex.rb
+++ b/lib/rdoc/parser/ripper_state_lex.rb
@@ -1,18 +1,308 @@
# frozen_string_literal: true
require 'ripper'
-##
-# Wrapper for Ripper lex states
-
class RDoc::Parser::RipperStateLex
- # :stopdoc:
+ # TODO: Remove this constants after Ruby 2.4 EOL
+ RIPPER_HAS_LEX_STATE = Ripper::Filter.method_defined?(:state)
Token = Struct.new(:line_no, :char_no, :kind, :text, :state)
- EXPR_END = Ripper::EXPR_END
- EXPR_ENDFN = Ripper::EXPR_ENDFN
- EXPR_ARG = Ripper::EXPR_ARG
- EXPR_FNAME = Ripper::EXPR_FNAME
+ EXPR_NONE = 0
+ EXPR_BEG = 1
+ EXPR_END = 2
+ EXPR_ENDARG = 4
+ EXPR_ENDFN = 8
+ EXPR_ARG = 16
+ EXPR_CMDARG = 32
+ EXPR_MID = 64
+ EXPR_FNAME = 128
+ EXPR_DOT = 256
+ EXPR_CLASS = 512
+ EXPR_LABEL = 1024
+ EXPR_LABELED = 2048
+ EXPR_FITEM = 4096
+ EXPR_VALUE = EXPR_BEG
+ EXPR_BEG_ANY = (EXPR_BEG | EXPR_MID | EXPR_CLASS)
+ EXPR_ARG_ANY = (EXPR_ARG | EXPR_CMDARG)
+ EXPR_END_ANY = (EXPR_END | EXPR_ENDARG | EXPR_ENDFN)
+
+ class InnerStateLex < Ripper::Filter
+ attr_accessor :lex_state
+
+ def initialize(code)
+ @lex_state = EXPR_BEG
+ @in_fname = false
+ @continue = false
+ reset
+ super(code)
+ end
+
+ def reset
+ @command_start = false
+ @cmd_state = @command_start
+ end
+
+ def on_nl(tok, data)
+ case @lex_state
+ when EXPR_FNAME, EXPR_DOT
+ @continue = true
+ else
+ @continue = false
+ @lex_state = EXPR_BEG unless (EXPR_LABEL & @lex_state) != 0
+ end
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_ignored_nl(tok, data)
+ case @lex_state
+ when EXPR_FNAME, EXPR_DOT
+ @continue = true
+ else
+ @continue = false
+ @lex_state = EXPR_BEG unless (EXPR_LABEL & @lex_state) != 0
+ end
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_op(tok, data)
+ case tok
+ when '&', '|', '!', '!=', '!~'
+ case @lex_state
+ when EXPR_FNAME, EXPR_DOT
+ @lex_state = EXPR_ARG
+ else
+ @lex_state = EXPR_BEG
+ end
+ when '<<'
+ # TODO next token?
+ case @lex_state
+ when EXPR_FNAME, EXPR_DOT
+ @lex_state = EXPR_ARG
+ else
+ @lex_state = EXPR_BEG
+ end
+ when '?'
+ @lex_state = EXPR_BEG
+ when '&&', '||', '+=', '-=', '*=', '**=',
+ '&=', '|=', '^=', '<<=', '>>=', '||=', '&&='
+ @lex_state = EXPR_BEG
+ when '::'
+ case @lex_state
+ when EXPR_ARG, EXPR_CMDARG
+ @lex_state = EXPR_DOT
+ when EXPR_FNAME, EXPR_DOT
+ @lex_state = EXPR_ARG
+ else
+ @lex_state = EXPR_BEG
+ end
+ else
+ case @lex_state
+ when EXPR_FNAME, EXPR_DOT
+ @lex_state = EXPR_ARG
+ else
+ @lex_state = EXPR_BEG
+ end
+ end
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_kw(tok, data)
+ case tok
+ when 'class'
+ @lex_state = EXPR_CLASS
+ @in_fname = true
+ when 'def'
+ @lex_state = EXPR_FNAME
+ @continue = true
+ @in_fname = true
+ when 'if', 'unless', 'while', 'until'
+ if ((EXPR_MID | EXPR_END | EXPR_ENDARG | EXPR_ENDFN | EXPR_ARG | EXPR_CMDARG) & @lex_state) != 0 # postfix if
+ @lex_state = EXPR_BEG | EXPR_LABEL
+ else
+ @lex_state = EXPR_BEG
+ end
+ when 'begin', 'case', 'when'
+ @lex_state = EXPR_BEG
+ when 'return', 'break'
+ @lex_state = EXPR_MID
+ else
+ if @lex_state == EXPR_FNAME
+ @lex_state = EXPR_END
+ else
+ @lex_state = EXPR_END
+ end
+ end
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_tstring_beg(tok, data)
+ @lex_state = EXPR_BEG
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_tstring_end(tok, data)
+ @lex_state = EXPR_END | EXPR_ENDARG
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_CHAR(tok, data)
+ @lex_state = EXPR_END
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_period(tok, data)
+ @lex_state = EXPR_DOT
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_int(tok, data)
+ @lex_state = EXPR_END | EXPR_ENDARG
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_float(tok, data)
+ @lex_state = EXPR_END | EXPR_ENDARG
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_rational(tok, data)
+ @lex_state = EXPR_END | EXPR_ENDARG
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_imaginary(tok, data)
+ @lex_state = EXPR_END | EXPR_ENDARG
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_symbeg(tok, data)
+ @lex_state = EXPR_FNAME
+ @continue = true
+ @in_fname = true
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ private def on_variables(event, tok, data)
+ if @in_fname
+ @lex_state = EXPR_ENDFN
+ @in_fname = false
+ @continue = false
+ elsif @continue
+ case @lex_state
+ when EXPR_DOT
+ @lex_state = EXPR_ARG
+ else
+ @lex_state = EXPR_ENDFN
+ @continue = false
+ end
+ else
+ @lex_state = EXPR_CMDARG
+ end
+ data << Token.new(lineno, column, event, tok, @lex_state)
+ end
+
+ def on_ident(tok, data)
+ on_variables(__method__, tok, data)
+ end
+
+ def on_ivar(tok, data)
+ @lex_state = EXPR_END
+ on_variables(__method__, tok, data)
+ end
+
+ def on_cvar(tok, data)
+ @lex_state = EXPR_END
+ on_variables(__method__, tok, data)
+ end
+
+ def on_gvar(tok, data)
+ @lex_state = EXPR_END
+ on_variables(__method__, tok, data)
+ end
+
+ def on_backref(tok, data)
+ @lex_state = EXPR_END
+ on_variables(__method__, tok, data)
+ end
+
+ def on_lparen(tok, data)
+ @lex_state = EXPR_LABEL | EXPR_BEG
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_rparen(tok, data)
+ @lex_state = EXPR_ENDFN
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_lbrace(tok, data)
+ @lex_state = EXPR_LABEL | EXPR_BEG
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_rbrace(tok, data)
+ @lex_state = EXPR_ENDARG
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_lbracket(tok, data)
+ @lex_state = EXPR_LABEL | EXPR_BEG
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_rbracket(tok, data)
+ @lex_state = EXPR_ENDARG
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_const(tok, data)
+ case @lex_state
+ when EXPR_FNAME
+ @lex_state = EXPR_ENDFN
+ when EXPR_CLASS, EXPR_CMDARG, EXPR_MID
+ @lex_state = EXPR_ARG
+ else
+ @lex_state = EXPR_CMDARG
+ end
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_sp(tok, data)
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_comma(tok, data)
+ @lex_state = EXPR_BEG | EXPR_LABEL if (EXPR_ARG_ANY & @lex_state) != 0
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_comment(tok, data)
+ @lex_state = EXPR_BEG unless (EXPR_LABEL & @lex_state) != 0
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_ignored_sp(tok, data)
+ @lex_state = EXPR_BEG unless (EXPR_LABEL & @lex_state) != 0
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ end
+
+ def on_heredoc_beg(tok, data)
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ @lex_state = EXPR_END
+ data
+ end
+
+ def on_heredoc_end(tok, data)
+ data << Token.new(lineno, column, __method__, tok, @lex_state)
+ @lex_state = EXPR_BEG
+ data
+ end
+
+ def on_default(event, tok, data)
+ reset
+ data << Token.new(lineno, column, event, tok, @lex_state)
+ end
+ end unless RIPPER_HAS_LEX_STATE
class InnerStateLex < Ripper::Filter
def initialize(code)
@@ -22,7 +312,7 @@ class RDoc::Parser::RipperStateLex
def on_default(event, tok, data)
data << Token.new(lineno, column, event, tok, state)
end
- end
+ end if RIPPER_HAS_LEX_STATE
def get_squashed_tk
if @buf.empty?
@@ -38,8 +328,9 @@ class RDoc::Parser::RipperStateLex
tk = get_string_tk(tk)
when :on_backtick then
if (tk[:state] & (EXPR_FNAME | EXPR_ENDFN)) != 0
+ @inner_lex.lex_state = EXPR_ARG unless RIPPER_HAS_LEX_STATE
tk[:kind] = :on_ident
- tk[:state] = Ripper::Lexer::State.new(EXPR_ARG)
+ tk[:state] = Ripper::Lexer.const_defined?(:State) ? Ripper::Lexer::State.new(EXPR_ARG) : EXPR_ARG
else
tk = get_string_tk(tk)
end
@@ -49,6 +340,7 @@ class RDoc::Parser::RipperStateLex
tk = get_embdoc_tk(tk)
when :on_heredoc_beg then
@heredoc_queue << retrieve_heredoc_info(tk)
+ @inner_lex.lex_state = EXPR_END unless RIPPER_HAS_LEX_STATE
when :on_nl, :on_ignored_nl, :on_comment, :on_heredoc_end then
if !@heredoc_queue.empty?
get_heredoc_tk(*@heredoc_queue.shift)
@@ -76,7 +368,7 @@ class RDoc::Parser::RipperStateLex
private def get_symbol_tk(tk)
is_symbol = true
symbol_tk = Token.new(tk.line_no, tk.char_no, :on_symbol)
- if ":'" == tk[:text] or ':"' == tk[:text] or tk[:text].start_with?('%s')
+ if ":'" == tk[:text] or ':"' == tk[:text]
tk1 = get_string_tk(tk)
symbol_tk[:text] = tk1[:text]
symbol_tk[:state] = tk1[:state]
@@ -252,7 +544,8 @@ class RDoc::Parser::RipperStateLex
private def get_op_tk(tk)
redefinable_operators = %w[! != !~ % & * ** + +@ - -@ / < << <= <=> == === =~ > >= >> [] []= ^ ` | ~]
if redefinable_operators.include?(tk[:text]) and tk[:state] == EXPR_ARG then
- tk[:state] = Ripper::Lexer::State.new(EXPR_ARG)
+ @inner_lex.lex_state = EXPR_ARG unless RIPPER_HAS_LEX_STATE
+ tk[:state] = Ripper::Lexer.const_defined?(:State) ? Ripper::Lexer::State.new(EXPR_ARG) : EXPR_ARG
tk[:kind] = :on_ident
elsif tk[:text] =~ /^[-+]$/ then
tk_ahead = get_squashed_tk
@@ -272,9 +565,6 @@ class RDoc::Parser::RipperStateLex
tk
end
- # :startdoc:
-
- # New lexer for +code+.
def initialize(code)
@buf = []
@heredoc_queue = []
@@ -282,7 +572,6 @@ class RDoc::Parser::RipperStateLex
@tokens = @inner_lex.parse([])
end
- # Returns tokens parsed from +code+.
def self.parse(code)
lex = self.new(code)
tokens = []
@@ -295,7 +584,6 @@ class RDoc::Parser::RipperStateLex
tokens
end
- # Returns +true+ if lex state will be +END+ after +token+.
def self.end?(token)
(token[:state] & EXPR_END)
end
diff --git a/lib/rdoc/parser/ruby.rb b/lib/rdoc/parser/ruby.rb
index 909b02d2af..b74ead65ab 100644
--- a/lib/rdoc/parser/ruby.rb
+++ b/lib/rdoc/parser/ruby.rb
@@ -8,18 +8,6 @@
# by Keiju ISHITSUKA (Nippon Rational Inc.)
#
-if ENV['RDOC_USE_PRISM_PARSER']
- require 'rdoc/parser/prism_ruby'
- RDoc::Parser.const_set(:Ruby, RDoc::Parser::PrismRuby)
- puts "========================================================================="
- puts "RDoc is using the experimental Prism parser to generate the documentation"
- puts "========================================================================="
- return
-end
-
-require 'ripper'
-require_relative 'ripper_state_lex'
-
##
# Extracts code elements from a source file returning a TopLevel object
# containing the constituent file elements.
@@ -150,6 +138,9 @@ require_relative 'ripper_state_lex'
# Note that by default, the :method: directive will be ignored if there is a
# standard rdocable item following it.
+require 'ripper'
+require_relative 'ripper_state_lex'
+
class RDoc::Parser::Ruby < RDoc::Parser
parse_files_matching(/\.rbw?$/)
@@ -189,9 +180,6 @@ class RDoc::Parser::Ruby < RDoc::Parser
reset
end
- ##
- # Return +true+ if +tk+ is a newline.
-
def tk_nl?(tk)
:on_nl == tk[:kind] or :on_ignored_nl == tk[:kind]
end
@@ -522,7 +510,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
when :on_comment, :on_embdoc then
@read.pop
if :on_nl == end_token[:kind] and "\n" == tk[:text][-1] and
- (!continue or (tk[:state] & Ripper::EXPR_LABEL) != 0) then
+ (!continue or (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0) then
break if !continue and nest <= 0
end
when :on_comma then
@@ -535,7 +523,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
nest += 1
when 'if', 'unless', 'while', 'until', 'rescue'
# postfix if/unless/while/until/rescue must be EXPR_LABEL
- nest += 1 unless (tk[:state] & Ripper::EXPR_LABEL) != 0
+ nest += 1 unless (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0
when 'end'
nest -= 1
break if nest == 0
@@ -798,10 +786,8 @@ class RDoc::Parser::Ruby < RDoc::Parser
al.line = line_no
read_documentation_modifiers al, RDoc::ATTR_MODIFIERS
- if al.document_self or not @track_visibility
- context.add_alias al
- @stats.add_alias al
- end
+ context.add_alias al
+ @stats.add_alias al
al
end
@@ -1050,7 +1036,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
elsif (:on_kw == tk[:kind] && 'def' == tk[:text]) then
nest += 1
elsif (:on_kw == tk[:kind] && %w{do if unless case begin}.include?(tk[:text])) then
- if (tk[:state] & Ripper::EXPR_LABEL) == 0
+ if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0
nest += 1
end
elsif [:on_rparen, :on_rbrace, :on_rbracket].include?(tk[:kind]) ||
@@ -1464,12 +1450,6 @@ class RDoc::Parser::Ruby < RDoc::Parser
meth = RDoc::AnyMethod.new get_tkread, name
look_for_directives_in meth, comment
meth.singleton = single == SINGLE ? true : singleton
- if singleton
- # `current_line_visibility' is useless because it works against
- # the normal method named as same as the singleton method, after
- # the latter was defined. Of course these are different things.
- container.current_line_visibility = :public
- end
record_location meth
meth.line = line_no
@@ -1671,7 +1651,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
when :on_comment, :on_embdoc then
@read.pop
if :on_nl == end_token[:kind] and "\n" == tk[:text][-1] and
- (!continue or (tk[:state] & Ripper::EXPR_LABEL) != 0) then
+ (!continue or (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) != 0) then
if method && method.block_params.nil? then
unget_tk tk
read_documentation_modifiers method, modifiers
@@ -1793,7 +1773,6 @@ class RDoc::Parser::Ruby < RDoc::Parser
nest = 1
save_visibility = container.visibility
- container.visibility = :public unless current_method
non_comment_seen = true
@@ -1891,7 +1870,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
end
when 'until', 'while' then
- if (tk[:state] & Ripper::EXPR_LABEL) == 0
+ if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0
nest += 1
skip_optional_do_after_expression
end
@@ -1907,7 +1886,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
skip_optional_do_after_expression
when 'case', 'do', 'if', 'unless', 'begin' then
- if (tk[:state] & Ripper::EXPR_LABEL) == 0
+ if (tk[:state] & RDoc::Parser::RipperStateLex::EXPR_LABEL) == 0
nest += 1
end
@@ -2155,7 +2134,7 @@ class RDoc::Parser::Ruby < RDoc::Parser
if :on_nl == tk[:kind] or (:on_kw == tk[:kind] && 'def' == tk[:text]) then
return
elsif :on_comment == tk[:kind] or :on_embdoc == tk[:kind] then
- return unless tk[:text] =~ /:?\b([\w-]+):\s*(.*)/
+ return unless tk[:text] =~ /\s*:?([\w-]+):\s*(.*)/
directive = $1.downcase
diff --git a/lib/rdoc/parser/ruby_tools.rb b/lib/rdoc/parser/ruby_tools.rb
index 40ea517c4d..681d7166ce 100644
--- a/lib/rdoc/parser/ruby_tools.rb
+++ b/lib/rdoc/parser/ruby_tools.rb
@@ -163,3 +163,5 @@ module RDoc::Parser::RubyTools
end
end
+
+
diff --git a/lib/rdoc/parser/text.rb b/lib/rdoc/parser/text.rb
index 5095d8cc64..01de0cc595 100644
--- a/lib/rdoc/parser/text.rb
+++ b/lib/rdoc/parser/text.rb
@@ -9,3 +9,4 @@
module RDoc::Parser::Text
end
+
diff --git a/lib/rdoc/rd/block_parser.rb b/lib/rdoc/rd/block_parser.rb
index 256ba553e5..6f70622c0b 100644
--- a/lib/rdoc/rd/block_parser.rb
+++ b/lib/rdoc/rd/block_parser.rb
@@ -1,655 +1,11 @@
# frozen_string_literal: true
#
# DO NOT MODIFY!!!!
-# This file is automatically generated by Racc 1.8.1
-# from Racc grammar file "block_parser.ry".
+# This file is automatically generated by Racc 1.6.0
+# from Racc grammar file "".
#
-###### racc/parser.rb begin
-unless $".find {|p| p.end_with?('/racc/parser.rb')}
-$".push "#{__dir__}/racc/parser.rb"
-#--
-# Copyright (c) 1999-2006 Minero Aoki
-#
-# This program is free software.
-# You can distribute/modify this program under the same terms of ruby.
-#
-# As a special exception, when this code is copied by Racc
-# into a Racc output file, you may use that output file
-# without restriction.
-#++
-
-unless $".find {|p| p.end_with?('/racc/info.rb')}
-$".push "#{__dir__}/racc/info.rb"
-
-module Racc
- VERSION = '1.8.1'
- Version = VERSION
- Copyright = 'Copyright (c) 1999-2006 Minero Aoki'
-end
-
-end
-
-
-module Racc
- class ParseError < StandardError; end
-end
-unless defined?(::ParseError)
- ParseError = Racc::ParseError # :nodoc:
-end
-
-# Racc is an LALR(1) parser generator.
-# It is written in Ruby itself, and generates Ruby programs.
-#
-# == Command-line Reference
-#
-# racc [-o<var>filename</var>] [--output-file=<var>filename</var>]
-# [-e<var>rubypath</var>] [--executable=<var>rubypath</var>]
-# [-v] [--verbose]
-# [-O<var>filename</var>] [--log-file=<var>filename</var>]
-# [-g] [--debug]
-# [-E] [--embedded]
-# [-l] [--no-line-convert]
-# [-c] [--line-convert-all]
-# [-a] [--no-omit-actions]
-# [-C] [--check-only]
-# [-S] [--output-status]
-# [--version] [--copyright] [--help] <var>grammarfile</var>
-#
-# [+grammarfile+]
-# Racc grammar file. Any extension is permitted.
-# [-o+outfile+, --output-file=+outfile+]
-# A filename for output. default is <+filename+>.tab.rb
-# [-O+filename+, --log-file=+filename+]
-# Place logging output in file +filename+.
-# Default log file name is <+filename+>.output.
-# [-e+rubypath+, --executable=+rubypath+]
-# output executable file(mode 755). where +path+ is the Ruby interpreter.
-# [-v, --verbose]
-# verbose mode. create +filename+.output file, like yacc's y.output file.
-# [-g, --debug]
-# add debug code to parser class. To display debugging information,
-# use this '-g' option and set @yydebug true in parser class.
-# [-E, --embedded]
-# Output parser which doesn't need runtime files (racc/parser.rb).
-# [-F, --frozen]
-# Output parser which declares frozen_string_literals: true
-# [-C, --check-only]
-# Check syntax of racc grammar file and quit.
-# [-S, --output-status]
-# Print messages time to time while compiling.
-# [-l, --no-line-convert]
-# turns off line number converting.
-# [-c, --line-convert-all]
-# Convert line number of actions, inner, header and footer.
-# [-a, --no-omit-actions]
-# Call all actions, even if an action is empty.
-# [--version]
-# print Racc version and quit.
-# [--copyright]
-# Print copyright and quit.
-# [--help]
-# Print usage and quit.
-#
-# == Generating Parser Using Racc
-#
-# To compile Racc grammar file, simply type:
-#
-# $ racc parse.y
-#
-# This creates Ruby script file "parse.tab.y". The -o option can change the output filename.
-#
-# == Writing A Racc Grammar File
-#
-# If you want your own parser, you have to write a grammar file.
-# A grammar file contains the name of your parser class, grammar for the parser,
-# user code, and anything else.
-# When writing a grammar file, yacc's knowledge is helpful.
-# If you have not used yacc before, Racc is not too difficult.
-#
-# Here's an example Racc grammar file.
-#
-# class Calcparser
-# rule
-# target: exp { print val[0] }
-#
-# exp: exp '+' exp
-# | exp '*' exp
-# | '(' exp ')'
-# | NUMBER
-# end
-#
-# Racc grammar files resemble yacc files.
-# But (of course), this is Ruby code.
-# yacc's $$ is the 'result', $0, $1... is
-# an array called 'val', and $-1, $-2... is an array called '_values'.
-#
-# See the {Grammar File Reference}[rdoc-ref:lib/racc/rdoc/grammar.en.rdoc] for
-# more information on grammar files.
-#
-# == Parser
-#
-# Then you must prepare the parse entry method. There are two types of
-# parse methods in Racc, Racc::Parser#do_parse and Racc::Parser#yyparse
-#
-# Racc::Parser#do_parse is simple.
-#
-# It's yyparse() of yacc, and Racc::Parser#next_token is yylex().
-# This method must returns an array like [TOKENSYMBOL, ITS_VALUE].
-# EOF is [false, false].
-# (TOKENSYMBOL is a Ruby symbol (taken from String#intern) by default.
-# If you want to change this, see the grammar reference.
-#
-# Racc::Parser#yyparse is little complicated, but useful.
-# It does not use Racc::Parser#next_token, instead it gets tokens from any iterator.
-#
-# For example, <code>yyparse(obj, :scan)</code> causes
-# calling +obj#scan+, and you can return tokens by yielding them from +obj#scan+.
-#
-# == Debugging
-#
-# When debugging, "-v" or/and the "-g" option is helpful.
-#
-# "-v" creates verbose log file (.output).
-# "-g" creates a "Verbose Parser".
-# Verbose Parser prints the internal status when parsing.
-# But it's _not_ automatic.
-# You must use -g option and set +@yydebug+ to +true+ in order to get output.
-# -g option only creates the verbose parser.
-#
-# === Racc reported syntax error.
-#
-# Isn't there too many "end"?
-# grammar of racc file is changed in v0.10.
-#
-# Racc does not use '%' mark, while yacc uses huge number of '%' marks..
-#
-# === Racc reported "XXXX conflicts".
-#
-# Try "racc -v xxxx.y".
-# It causes producing racc's internal log file, xxxx.output.
-#
-# === Generated parsers does not work correctly
-#
-# Try "racc -g xxxx.y".
-# This command let racc generate "debugging parser".
-# Then set @yydebug=true in your parser.
-# It produces a working log of your parser.
-#
-# == Re-distributing Racc runtime
-#
-# A parser, which is created by Racc, requires the Racc runtime module;
-# racc/parser.rb.
-#
-# Ruby 1.8.x comes with Racc runtime module,
-# you need NOT distribute Racc runtime files.
-#
-# If you want to include the Racc runtime module with your parser.
-# This can be done by using '-E' option:
-#
-# $ racc -E -omyparser.rb myparser.y
-#
-# This command creates myparser.rb which `includes' Racc runtime.
-# Only you must do is to distribute your parser file (myparser.rb).
-#
-# Note: parser.rb is ruby license, but your parser is not.
-# Your own parser is completely yours.
-module Racc
-
- unless defined?(Racc_No_Extensions)
- Racc_No_Extensions = false # :nodoc:
- end
-
- class Parser
-
- Racc_Runtime_Version = ::Racc::VERSION
- Racc_Runtime_Core_Version_R = ::Racc::VERSION
-
- begin
- if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
- require 'jruby'
- require 'racc/cparse-jruby.jar'
- com.headius.racc.Cparse.new.load(JRuby.runtime, false)
- else
- require 'racc/cparse'
- end
-
- unless new.respond_to?(:_racc_do_parse_c, true)
- raise LoadError, 'old cparse.so'
- end
- if Racc_No_Extensions
- raise LoadError, 'selecting ruby version of racc runtime core'
- end
-
- Racc_Main_Parsing_Routine = :_racc_do_parse_c # :nodoc:
- Racc_YY_Parse_Method = :_racc_yyparse_c # :nodoc:
- Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C # :nodoc:
- Racc_Runtime_Type = 'c' # :nodoc:
- rescue LoadError
- Racc_Main_Parsing_Routine = :_racc_do_parse_rb
- Racc_YY_Parse_Method = :_racc_yyparse_rb
- Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R
- Racc_Runtime_Type = 'ruby'
- end
-
- def Parser.racc_runtime_type # :nodoc:
- Racc_Runtime_Type
- end
-
- def _racc_setup
- @yydebug = false unless self.class::Racc_debug_parser
- @yydebug = false unless defined?(@yydebug)
- if @yydebug
- @racc_debug_out = $stderr unless defined?(@racc_debug_out)
- @racc_debug_out ||= $stderr
- end
- arg = self.class::Racc_arg
- arg[13] = true if arg.size < 14
- arg
- end
-
- def _racc_init_sysvars
- @racc_state = [0]
- @racc_tstack = []
- @racc_vstack = []
-
- @racc_t = nil
- @racc_val = nil
-
- @racc_read_next = true
-
- @racc_user_yyerror = false
- @racc_error_status = 0
- end
-
- # The entry point of the parser. This method is used with #next_token.
- # If Racc wants to get token (and its value), calls next_token.
- #
- # Example:
- # def parse
- # @q = [[1,1],
- # [2,2],
- # [3,3],
- # [false, '$']]
- # do_parse
- # end
- #
- # def next_token
- # @q.shift
- # end
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
- def do_parse
- #{Racc_Main_Parsing_Routine}(_racc_setup(), false)
- end
- RUBY
-
- # The method to fetch next token.
- # If you use #do_parse method, you must implement #next_token.
- #
- # The format of return value is [TOKEN_SYMBOL, VALUE].
- # +token-symbol+ is represented by Ruby's symbol by default, e.g. :IDENT
- # for 'IDENT'. ";" (String) for ';'.
- #
- # The final symbol (End of file) must be false.
- def next_token
- raise NotImplementedError, "#{self.class}\#next_token is not defined"
- end
-
- def _racc_do_parse_rb(arg, in_debug)
- action_table, action_check, action_default, action_pointer,
- _, _, _, _,
- _, _, token_table, * = arg
-
- _racc_init_sysvars
- tok = act = i = nil
-
- catch(:racc_end_parse) {
- while true
- if i = action_pointer[@racc_state[-1]]
- if @racc_read_next
- if @racc_t != 0 # not EOF
- tok, @racc_val = next_token()
- unless tok # EOF
- @racc_t = 0
- else
- @racc_t = (token_table[tok] or 1) # error token
- end
- racc_read_token(@racc_t, tok, @racc_val) if @yydebug
- @racc_read_next = false
- end
- end
- i += @racc_t
- unless i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- else
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
- end
- }
- end
-
- # Another entry point for the parser.
- # If you use this method, you must implement RECEIVER#METHOD_ID method.
- #
- # RECEIVER#METHOD_ID is a method to get next token.
- # It must 'yield' the token, which format is [TOKEN-SYMBOL, VALUE].
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
- def yyparse(recv, mid)
- #{Racc_YY_Parse_Method}(recv, mid, _racc_setup(), false)
- end
- RUBY
-
- def _racc_yyparse_rb(recv, mid, arg, c_debug)
- action_table, action_check, action_default, action_pointer,
- _, _, _, _,
- _, _, token_table, * = arg
-
- _racc_init_sysvars
-
- catch(:racc_end_parse) {
- until i = action_pointer[@racc_state[-1]]
- while act = _racc_evalact(action_default[@racc_state[-1]], arg)
- ;
- end
- end
- recv.__send__(mid) do |tok, val|
- unless tok
- @racc_t = 0
- else
- @racc_t = (token_table[tok] or 1) # error token
- end
- @racc_val = val
- @racc_read_next = false
-
- i += @racc_t
- unless i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
-
- while !(i = action_pointer[@racc_state[-1]]) ||
- ! @racc_read_next ||
- @racc_t == 0 # $
- unless i and i += @racc_t and
- i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
- end
- end
- }
- end
-
- ###
- ### common
- ###
-
- def _racc_evalact(act, arg)
- action_table, action_check, _, action_pointer,
- _, _, _, _,
- _, _, _, shift_n,
- reduce_n, * = arg
- nerr = 0 # tmp
-
- if act > 0 and act < shift_n
- #
- # shift
- #
- if @racc_error_status > 0
- @racc_error_status -= 1 unless @racc_t <= 1 # error token or EOF
- end
- @racc_vstack.push @racc_val
- @racc_state.push act
- @racc_read_next = true
- if @yydebug
- @racc_tstack.push @racc_t
- racc_shift @racc_t, @racc_tstack, @racc_vstack
- end
-
- elsif act < 0 and act > -reduce_n
- #
- # reduce
- #
- code = catch(:racc_jump) {
- @racc_state.push _racc_do_reduce(arg, act)
- false
- }
- if code
- case code
- when 1 # yyerror
- @racc_user_yyerror = true # user_yyerror
- return -reduce_n
- when 2 # yyaccept
- return shift_n
- else
- raise '[Racc Bug] unknown jump code'
- end
- end
-
- elsif act == shift_n
- #
- # accept
- #
- racc_accept if @yydebug
- throw :racc_end_parse, @racc_vstack[0]
-
- elsif act == -reduce_n
- #
- # error
- #
- case @racc_error_status
- when 0
- unless arg[21] # user_yyerror
- nerr += 1
- on_error @racc_t, @racc_val, @racc_vstack
- end
- when 3
- if @racc_t == 0 # is $
- # We're at EOF, and another error occurred immediately after
- # attempting auto-recovery
- throw :racc_end_parse, nil
- end
- @racc_read_next = true
- end
- @racc_user_yyerror = false
- @racc_error_status = 3
- while true
- if i = action_pointer[@racc_state[-1]]
- i += 1 # error token
- if i >= 0 and
- (act = action_table[i]) and
- action_check[i] == @racc_state[-1]
- break
- end
- end
- throw :racc_end_parse, nil if @racc_state.size <= 1
- @racc_state.pop
- @racc_vstack.pop
- if @yydebug
- @racc_tstack.pop
- racc_e_pop @racc_state, @racc_tstack, @racc_vstack
- end
- end
- return act
-
- else
- raise "[Racc Bug] unknown action #{act.inspect}"
- end
-
- racc_next_state(@racc_state[-1], @racc_state) if @yydebug
-
- nil
- end
-
- def _racc_do_reduce(arg, act)
- _, _, _, _,
- goto_table, goto_check, goto_default, goto_pointer,
- nt_base, reduce_table, _, _,
- _, use_result, * = arg
-
- state = @racc_state
- vstack = @racc_vstack
- tstack = @racc_tstack
-
- i = act * -3
- len = reduce_table[i]
- reduce_to = reduce_table[i+1]
- method_id = reduce_table[i+2]
- void_array = []
-
- tmp_t = tstack[-len, len] if @yydebug
- tmp_v = vstack[-len, len]
- tstack[-len, len] = void_array if @yydebug
- vstack[-len, len] = void_array
- state[-len, len] = void_array
-
- # tstack must be updated AFTER method call
- if use_result
- vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0])
- else
- vstack.push __send__(method_id, tmp_v, vstack)
- end
- tstack.push reduce_to
-
- racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug
-
- k1 = reduce_to - nt_base
- if i = goto_pointer[k1]
- i += state[-1]
- if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1
- return curstate
- end
- end
- goto_default[k1]
- end
-
- # This method is called when a parse error is found.
- #
- # ERROR_TOKEN_ID is an internal ID of token which caused error.
- # You can get string representation of this ID by calling
- # #token_to_str.
- #
- # ERROR_VALUE is a value of error token.
- #
- # value_stack is a stack of symbol values.
- # DO NOT MODIFY this object.
- #
- # This method raises ParseError by default.
- #
- # If this method returns, parsers enter "error recovering mode".
- def on_error(t, val, vstack)
- raise ParseError, sprintf("parse error on value %s (%s)",
- val.inspect, token_to_str(t) || '?')
- end
-
- # Enter error recovering mode.
- # This method does not call #on_error.
- def yyerror
- throw :racc_jump, 1
- end
-
- # Exit parser.
- # Return value is +Symbol_Value_Stack[0]+.
- def yyaccept
- throw :racc_jump, 2
- end
-
- # Leave error recovering mode.
- def yyerrok
- @racc_error_status = 0
- end
-
- # For debugging output
- def racc_read_token(t, tok, val)
- @racc_debug_out.print 'read '
- @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') '
- @racc_debug_out.puts val.inspect
- @racc_debug_out.puts
- end
-
- def racc_shift(tok, tstack, vstack)
- @racc_debug_out.puts "shift #{racc_token2str tok}"
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
-
- def racc_reduce(toks, sim, tstack, vstack)
- out = @racc_debug_out
- out.print 'reduce '
- if toks.empty?
- out.print ' <none>'
- else
- toks.each {|t| out.print ' ', racc_token2str(t) }
- end
- out.puts " --> #{racc_token2str(sim)}"
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
-
- def racc_accept
- @racc_debug_out.puts 'accept'
- @racc_debug_out.puts
- end
-
- def racc_e_pop(state, tstack, vstack)
- @racc_debug_out.puts 'error recovering mode: pop token'
- racc_print_states state
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
-
- def racc_next_state(curstate, state)
- @racc_debug_out.puts "goto #{curstate}"
- racc_print_states state
- @racc_debug_out.puts
- end
-
- def racc_print_stacks(t, v)
- out = @racc_debug_out
- out.print ' ['
- t.each_index do |i|
- out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')'
- end
- out.puts ' ]'
- end
-
- def racc_print_states(s)
- out = @racc_debug_out
- out.print ' ['
- s.each {|st| out.print ' ', st }
- out.puts ' ]'
- end
-
- def racc_token2str(tok)
- self.class::Racc_token_to_s_table[tok] or
- raise "[Racc Bug] can't convert token #{tok} to string"
- end
-
- # Convert internal ID of token symbol to the string.
- def token_to_str(t)
- self.class::Racc_token_to_s_table[t]
- end
-
- end
-
-end
-
-end
-###### racc/parser.rb end
+require 'racc/parser.rb'
class RDoc::RD
@@ -1004,7 +360,7 @@ def get_included(file)
file_name = File.join dir, file
if File.exist? file_name then
- included = File.readlines file_name
+ included = IO.readlines file_name
break
end
end
@@ -1268,7 +624,6 @@ Racc_arg = [
racc_shift_n,
racc_reduce_n,
racc_use_result_var ]
-Ractor.make_shareable(Racc_arg) if defined?(Ractor)
Racc_token_to_s_table = [
"$end",
@@ -1319,7 +674,6 @@ Racc_token_to_s_table = [
"blocks_in_list",
"block_in_list",
"whitelines2" ]
-Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
Racc_debug_parser = false
diff --git a/lib/rdoc/rd/inline.rb b/lib/rdoc/rd/inline.rb
index 77d88b2860..e5cb545728 100644
--- a/lib/rdoc/rd/inline.rb
+++ b/lib/rdoc/rd/inline.rb
@@ -69,3 +69,4 @@ class RDoc::RD::Inline
alias to_s rdoc # :nodoc:
end
+
diff --git a/lib/rdoc/rd/inline_parser.rb b/lib/rdoc/rd/inline_parser.rb
index b6d521c6bd..c1da35a109 100644
--- a/lib/rdoc/rd/inline_parser.rb
+++ b/lib/rdoc/rd/inline_parser.rb
@@ -1,655 +1,11 @@
# frozen_string_literal: true
#
# DO NOT MODIFY!!!!
-# This file is automatically generated by Racc 1.8.1
-# from Racc grammar file "inline_parser.ry".
+# This file is automatically generated by Racc 1.6.0
+# from Racc grammar file "".
#
-###### racc/parser.rb begin
-unless $".find {|p| p.end_with?('/racc/parser.rb')}
-$".push "#{__dir__}/racc/parser.rb"
-#--
-# Copyright (c) 1999-2006 Minero Aoki
-#
-# This program is free software.
-# You can distribute/modify this program under the same terms of ruby.
-#
-# As a special exception, when this code is copied by Racc
-# into a Racc output file, you may use that output file
-# without restriction.
-#++
-
-unless $".find {|p| p.end_with?('/racc/info.rb')}
-$".push "#{__dir__}/racc/info.rb"
-
-module Racc
- VERSION = '1.8.1'
- Version = VERSION
- Copyright = 'Copyright (c) 1999-2006 Minero Aoki'
-end
-
-end
-
-
-module Racc
- class ParseError < StandardError; end
-end
-unless defined?(::ParseError)
- ParseError = Racc::ParseError # :nodoc:
-end
-
-# Racc is an LALR(1) parser generator.
-# It is written in Ruby itself, and generates Ruby programs.
-#
-# == Command-line Reference
-#
-# racc [-o<var>filename</var>] [--output-file=<var>filename</var>]
-# [-e<var>rubypath</var>] [--executable=<var>rubypath</var>]
-# [-v] [--verbose]
-# [-O<var>filename</var>] [--log-file=<var>filename</var>]
-# [-g] [--debug]
-# [-E] [--embedded]
-# [-l] [--no-line-convert]
-# [-c] [--line-convert-all]
-# [-a] [--no-omit-actions]
-# [-C] [--check-only]
-# [-S] [--output-status]
-# [--version] [--copyright] [--help] <var>grammarfile</var>
-#
-# [+grammarfile+]
-# Racc grammar file. Any extension is permitted.
-# [-o+outfile+, --output-file=+outfile+]
-# A filename for output. default is <+filename+>.tab.rb
-# [-O+filename+, --log-file=+filename+]
-# Place logging output in file +filename+.
-# Default log file name is <+filename+>.output.
-# [-e+rubypath+, --executable=+rubypath+]
-# output executable file(mode 755). where +path+ is the Ruby interpreter.
-# [-v, --verbose]
-# verbose mode. create +filename+.output file, like yacc's y.output file.
-# [-g, --debug]
-# add debug code to parser class. To display debugging information,
-# use this '-g' option and set @yydebug true in parser class.
-# [-E, --embedded]
-# Output parser which doesn't need runtime files (racc/parser.rb).
-# [-F, --frozen]
-# Output parser which declares frozen_string_literals: true
-# [-C, --check-only]
-# Check syntax of racc grammar file and quit.
-# [-S, --output-status]
-# Print messages time to time while compiling.
-# [-l, --no-line-convert]
-# turns off line number converting.
-# [-c, --line-convert-all]
-# Convert line number of actions, inner, header and footer.
-# [-a, --no-omit-actions]
-# Call all actions, even if an action is empty.
-# [--version]
-# print Racc version and quit.
-# [--copyright]
-# Print copyright and quit.
-# [--help]
-# Print usage and quit.
-#
-# == Generating Parser Using Racc
-#
-# To compile Racc grammar file, simply type:
-#
-# $ racc parse.y
-#
-# This creates Ruby script file "parse.tab.y". The -o option can change the output filename.
-#
-# == Writing A Racc Grammar File
-#
-# If you want your own parser, you have to write a grammar file.
-# A grammar file contains the name of your parser class, grammar for the parser,
-# user code, and anything else.
-# When writing a grammar file, yacc's knowledge is helpful.
-# If you have not used yacc before, Racc is not too difficult.
-#
-# Here's an example Racc grammar file.
-#
-# class Calcparser
-# rule
-# target: exp { print val[0] }
-#
-# exp: exp '+' exp
-# | exp '*' exp
-# | '(' exp ')'
-# | NUMBER
-# end
-#
-# Racc grammar files resemble yacc files.
-# But (of course), this is Ruby code.
-# yacc's $$ is the 'result', $0, $1... is
-# an array called 'val', and $-1, $-2... is an array called '_values'.
-#
-# See the {Grammar File Reference}[rdoc-ref:lib/racc/rdoc/grammar.en.rdoc] for
-# more information on grammar files.
-#
-# == Parser
-#
-# Then you must prepare the parse entry method. There are two types of
-# parse methods in Racc, Racc::Parser#do_parse and Racc::Parser#yyparse
-#
-# Racc::Parser#do_parse is simple.
-#
-# It's yyparse() of yacc, and Racc::Parser#next_token is yylex().
-# This method must returns an array like [TOKENSYMBOL, ITS_VALUE].
-# EOF is [false, false].
-# (TOKENSYMBOL is a Ruby symbol (taken from String#intern) by default.
-# If you want to change this, see the grammar reference.
-#
-# Racc::Parser#yyparse is little complicated, but useful.
-# It does not use Racc::Parser#next_token, instead it gets tokens from any iterator.
-#
-# For example, <code>yyparse(obj, :scan)</code> causes
-# calling +obj#scan+, and you can return tokens by yielding them from +obj#scan+.
-#
-# == Debugging
-#
-# When debugging, "-v" or/and the "-g" option is helpful.
-#
-# "-v" creates verbose log file (.output).
-# "-g" creates a "Verbose Parser".
-# Verbose Parser prints the internal status when parsing.
-# But it's _not_ automatic.
-# You must use -g option and set +@yydebug+ to +true+ in order to get output.
-# -g option only creates the verbose parser.
-#
-# === Racc reported syntax error.
-#
-# Isn't there too many "end"?
-# grammar of racc file is changed in v0.10.
-#
-# Racc does not use '%' mark, while yacc uses huge number of '%' marks..
-#
-# === Racc reported "XXXX conflicts".
-#
-# Try "racc -v xxxx.y".
-# It causes producing racc's internal log file, xxxx.output.
-#
-# === Generated parsers does not work correctly
-#
-# Try "racc -g xxxx.y".
-# This command let racc generate "debugging parser".
-# Then set @yydebug=true in your parser.
-# It produces a working log of your parser.
-#
-# == Re-distributing Racc runtime
-#
-# A parser, which is created by Racc, requires the Racc runtime module;
-# racc/parser.rb.
-#
-# Ruby 1.8.x comes with Racc runtime module,
-# you need NOT distribute Racc runtime files.
-#
-# If you want to include the Racc runtime module with your parser.
-# This can be done by using '-E' option:
-#
-# $ racc -E -omyparser.rb myparser.y
-#
-# This command creates myparser.rb which `includes' Racc runtime.
-# Only you must do is to distribute your parser file (myparser.rb).
-#
-# Note: parser.rb is ruby license, but your parser is not.
-# Your own parser is completely yours.
-module Racc
-
- unless defined?(Racc_No_Extensions)
- Racc_No_Extensions = false # :nodoc:
- end
-
- class Parser
-
- Racc_Runtime_Version = ::Racc::VERSION
- Racc_Runtime_Core_Version_R = ::Racc::VERSION
-
- begin
- if Object.const_defined?(:RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
- require 'jruby'
- require 'racc/cparse-jruby.jar'
- com.headius.racc.Cparse.new.load(JRuby.runtime, false)
- else
- require 'racc/cparse'
- end
-
- unless new.respond_to?(:_racc_do_parse_c, true)
- raise LoadError, 'old cparse.so'
- end
- if Racc_No_Extensions
- raise LoadError, 'selecting ruby version of racc runtime core'
- end
-
- Racc_Main_Parsing_Routine = :_racc_do_parse_c # :nodoc:
- Racc_YY_Parse_Method = :_racc_yyparse_c # :nodoc:
- Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C # :nodoc:
- Racc_Runtime_Type = 'c' # :nodoc:
- rescue LoadError
- Racc_Main_Parsing_Routine = :_racc_do_parse_rb
- Racc_YY_Parse_Method = :_racc_yyparse_rb
- Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R
- Racc_Runtime_Type = 'ruby'
- end
-
- def Parser.racc_runtime_type # :nodoc:
- Racc_Runtime_Type
- end
-
- def _racc_setup
- @yydebug = false unless self.class::Racc_debug_parser
- @yydebug = false unless defined?(@yydebug)
- if @yydebug
- @racc_debug_out = $stderr unless defined?(@racc_debug_out)
- @racc_debug_out ||= $stderr
- end
- arg = self.class::Racc_arg
- arg[13] = true if arg.size < 14
- arg
- end
-
- def _racc_init_sysvars
- @racc_state = [0]
- @racc_tstack = []
- @racc_vstack = []
-
- @racc_t = nil
- @racc_val = nil
-
- @racc_read_next = true
-
- @racc_user_yyerror = false
- @racc_error_status = 0
- end
-
- # The entry point of the parser. This method is used with #next_token.
- # If Racc wants to get token (and its value), calls next_token.
- #
- # Example:
- # def parse
- # @q = [[1,1],
- # [2,2],
- # [3,3],
- # [false, '$']]
- # do_parse
- # end
- #
- # def next_token
- # @q.shift
- # end
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
- def do_parse
- #{Racc_Main_Parsing_Routine}(_racc_setup(), false)
- end
- RUBY
-
- # The method to fetch next token.
- # If you use #do_parse method, you must implement #next_token.
- #
- # The format of return value is [TOKEN_SYMBOL, VALUE].
- # +token-symbol+ is represented by Ruby's symbol by default, e.g. :IDENT
- # for 'IDENT'. ";" (String) for ';'.
- #
- # The final symbol (End of file) must be false.
- def next_token
- raise NotImplementedError, "#{self.class}\#next_token is not defined"
- end
-
- def _racc_do_parse_rb(arg, in_debug)
- action_table, action_check, action_default, action_pointer,
- _, _, _, _,
- _, _, token_table, * = arg
-
- _racc_init_sysvars
- tok = act = i = nil
-
- catch(:racc_end_parse) {
- while true
- if i = action_pointer[@racc_state[-1]]
- if @racc_read_next
- if @racc_t != 0 # not EOF
- tok, @racc_val = next_token()
- unless tok # EOF
- @racc_t = 0
- else
- @racc_t = (token_table[tok] or 1) # error token
- end
- racc_read_token(@racc_t, tok, @racc_val) if @yydebug
- @racc_read_next = false
- end
- end
- i += @racc_t
- unless i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- else
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
- end
- }
- end
-
- # Another entry point for the parser.
- # If you use this method, you must implement RECEIVER#METHOD_ID method.
- #
- # RECEIVER#METHOD_ID is a method to get next token.
- # It must 'yield' the token, which format is [TOKEN-SYMBOL, VALUE].
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
- def yyparse(recv, mid)
- #{Racc_YY_Parse_Method}(recv, mid, _racc_setup(), false)
- end
- RUBY
-
- def _racc_yyparse_rb(recv, mid, arg, c_debug)
- action_table, action_check, action_default, action_pointer,
- _, _, _, _,
- _, _, token_table, * = arg
-
- _racc_init_sysvars
-
- catch(:racc_end_parse) {
- until i = action_pointer[@racc_state[-1]]
- while act = _racc_evalact(action_default[@racc_state[-1]], arg)
- ;
- end
- end
- recv.__send__(mid) do |tok, val|
- unless tok
- @racc_t = 0
- else
- @racc_t = (token_table[tok] or 1) # error token
- end
- @racc_val = val
- @racc_read_next = false
-
- i += @racc_t
- unless i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
-
- while !(i = action_pointer[@racc_state[-1]]) ||
- ! @racc_read_next ||
- @racc_t == 0 # $
- unless i and i += @racc_t and
- i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
- end
- end
- }
- end
-
- ###
- ### common
- ###
-
- def _racc_evalact(act, arg)
- action_table, action_check, _, action_pointer,
- _, _, _, _,
- _, _, _, shift_n,
- reduce_n, * = arg
- nerr = 0 # tmp
-
- if act > 0 and act < shift_n
- #
- # shift
- #
- if @racc_error_status > 0
- @racc_error_status -= 1 unless @racc_t <= 1 # error token or EOF
- end
- @racc_vstack.push @racc_val
- @racc_state.push act
- @racc_read_next = true
- if @yydebug
- @racc_tstack.push @racc_t
- racc_shift @racc_t, @racc_tstack, @racc_vstack
- end
-
- elsif act < 0 and act > -reduce_n
- #
- # reduce
- #
- code = catch(:racc_jump) {
- @racc_state.push _racc_do_reduce(arg, act)
- false
- }
- if code
- case code
- when 1 # yyerror
- @racc_user_yyerror = true # user_yyerror
- return -reduce_n
- when 2 # yyaccept
- return shift_n
- else
- raise '[Racc Bug] unknown jump code'
- end
- end
-
- elsif act == shift_n
- #
- # accept
- #
- racc_accept if @yydebug
- throw :racc_end_parse, @racc_vstack[0]
-
- elsif act == -reduce_n
- #
- # error
- #
- case @racc_error_status
- when 0
- unless arg[21] # user_yyerror
- nerr += 1
- on_error @racc_t, @racc_val, @racc_vstack
- end
- when 3
- if @racc_t == 0 # is $
- # We're at EOF, and another error occurred immediately after
- # attempting auto-recovery
- throw :racc_end_parse, nil
- end
- @racc_read_next = true
- end
- @racc_user_yyerror = false
- @racc_error_status = 3
- while true
- if i = action_pointer[@racc_state[-1]]
- i += 1 # error token
- if i >= 0 and
- (act = action_table[i]) and
- action_check[i] == @racc_state[-1]
- break
- end
- end
- throw :racc_end_parse, nil if @racc_state.size <= 1
- @racc_state.pop
- @racc_vstack.pop
- if @yydebug
- @racc_tstack.pop
- racc_e_pop @racc_state, @racc_tstack, @racc_vstack
- end
- end
- return act
-
- else
- raise "[Racc Bug] unknown action #{act.inspect}"
- end
-
- racc_next_state(@racc_state[-1], @racc_state) if @yydebug
-
- nil
- end
-
- def _racc_do_reduce(arg, act)
- _, _, _, _,
- goto_table, goto_check, goto_default, goto_pointer,
- nt_base, reduce_table, _, _,
- _, use_result, * = arg
-
- state = @racc_state
- vstack = @racc_vstack
- tstack = @racc_tstack
-
- i = act * -3
- len = reduce_table[i]
- reduce_to = reduce_table[i+1]
- method_id = reduce_table[i+2]
- void_array = []
-
- tmp_t = tstack[-len, len] if @yydebug
- tmp_v = vstack[-len, len]
- tstack[-len, len] = void_array if @yydebug
- vstack[-len, len] = void_array
- state[-len, len] = void_array
-
- # tstack must be updated AFTER method call
- if use_result
- vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0])
- else
- vstack.push __send__(method_id, tmp_v, vstack)
- end
- tstack.push reduce_to
-
- racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug
-
- k1 = reduce_to - nt_base
- if i = goto_pointer[k1]
- i += state[-1]
- if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1
- return curstate
- end
- end
- goto_default[k1]
- end
-
- # This method is called when a parse error is found.
- #
- # ERROR_TOKEN_ID is an internal ID of token which caused error.
- # You can get string representation of this ID by calling
- # #token_to_str.
- #
- # ERROR_VALUE is a value of error token.
- #
- # value_stack is a stack of symbol values.
- # DO NOT MODIFY this object.
- #
- # This method raises ParseError by default.
- #
- # If this method returns, parsers enter "error recovering mode".
- def on_error(t, val, vstack)
- raise ParseError, sprintf("parse error on value %s (%s)",
- val.inspect, token_to_str(t) || '?')
- end
-
- # Enter error recovering mode.
- # This method does not call #on_error.
- def yyerror
- throw :racc_jump, 1
- end
-
- # Exit parser.
- # Return value is +Symbol_Value_Stack[0]+.
- def yyaccept
- throw :racc_jump, 2
- end
-
- # Leave error recovering mode.
- def yyerrok
- @racc_error_status = 0
- end
-
- # For debugging output
- def racc_read_token(t, tok, val)
- @racc_debug_out.print 'read '
- @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') '
- @racc_debug_out.puts val.inspect
- @racc_debug_out.puts
- end
-
- def racc_shift(tok, tstack, vstack)
- @racc_debug_out.puts "shift #{racc_token2str tok}"
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
-
- def racc_reduce(toks, sim, tstack, vstack)
- out = @racc_debug_out
- out.print 'reduce '
- if toks.empty?
- out.print ' <none>'
- else
- toks.each {|t| out.print ' ', racc_token2str(t) }
- end
- out.puts " --> #{racc_token2str(sim)}"
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
-
- def racc_accept
- @racc_debug_out.puts 'accept'
- @racc_debug_out.puts
- end
-
- def racc_e_pop(state, tstack, vstack)
- @racc_debug_out.puts 'error recovering mode: pop token'
- racc_print_states state
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
-
- def racc_next_state(curstate, state)
- @racc_debug_out.puts "goto #{curstate}"
- racc_print_states state
- @racc_debug_out.puts
- end
-
- def racc_print_stacks(t, v)
- out = @racc_debug_out
- out.print ' ['
- t.each_index do |i|
- out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')'
- end
- out.puts ' ]'
- end
-
- def racc_print_states(s)
- out = @racc_debug_out
- out.print ' ['
- s.each {|st| out.print ' ', st }
- out.puts ' ]'
- end
-
- def racc_token2str(tok)
- self.class::Racc_token_to_s_table[tok] or
- raise "[Racc Bug] can't convert token #{tok} to string"
- end
-
- # Convert internal ID of token symbol to the string.
- def token_to_str(t)
- self.class::Racc_token_to_s_table[t]
- end
-
- end
-
-end
-
-end
-###### racc/parser.rb end
+require 'racc/parser.rb'
require 'strscan'
@@ -1296,7 +652,6 @@ Racc_arg = [
racc_shift_n,
racc_reduce_n,
racc_use_result_var ]
-Ractor.make_shareable(Racc_arg) if defined?(Ractor)
Racc_token_to_s_table = [
"$end",
@@ -1368,7 +723,6 @@ Racc_token_to_s_table = [
"normal_strings",
"verb_string",
"verb_normal_string" ]
-Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
Racc_debug_parser = false
diff --git a/lib/rdoc/rdoc.gemspec b/lib/rdoc/rdoc.gemspec
index 26f9ba1a87..3c96f7deb1 100644
--- a/lib/rdoc/rdoc.gemspec
+++ b/lib/rdoc/rdoc.gemspec
@@ -28,10 +28,6 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
s.homepage = "https://ruby.github.io/rdoc"
s.licenses = ["Ruby"]
- s.metadata["homepage_uri"] = s.homepage
- s.metadata["source_code_uri"] = "https://github.com/ruby/rdoc"
- s.metadata["changelog_uri"] = "#{s.metadata["source_code_uri"]}/releases"
-
s.bindir = "exe"
s.executables = ["rdoc", "ri"]
s.require_paths = ["lib"]
@@ -46,27 +42,27 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
"LEGAL.rdoc",
"LICENSE.rdoc",
"README.rdoc",
- "RI.md",
+ "RI.rdoc",
"TODO.rdoc",
"exe/rdoc",
"exe/ri",
"lib/rdoc.rb",
- "lib/rdoc/code_object/alias.rb",
- "lib/rdoc/code_object/anon_class.rb",
- "lib/rdoc/code_object/any_method.rb",
- "lib/rdoc/code_object/attr.rb",
- "lib/rdoc/code_object/class_module.rb",
+ "lib/rdoc/alias.rb",
+ "lib/rdoc/anon_class.rb",
+ "lib/rdoc/any_method.rb",
+ "lib/rdoc/attr.rb",
+ "lib/rdoc/class_module.rb",
"lib/rdoc/code_object.rb",
"lib/rdoc/code_objects.rb",
"lib/rdoc/comment.rb",
- "lib/rdoc/code_object/constant.rb",
- "lib/rdoc/code_object/context.rb",
- "lib/rdoc/code_object/context/section.rb",
+ "lib/rdoc/constant.rb",
+ "lib/rdoc/context.rb",
+ "lib/rdoc/context/section.rb",
"lib/rdoc/cross_reference.rb",
"lib/rdoc/encoding.rb",
"lib/rdoc/erb_partial.rb",
"lib/rdoc/erbio.rb",
- "lib/rdoc/code_object/extend.rb",
+ "lib/rdoc/extend.rb",
"lib/rdoc/generator.rb",
"lib/rdoc/generator/darkfish.rb",
"lib/rdoc/generator/json_index.rb",
@@ -136,11 +132,11 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
"lib/rdoc/generator/template/json_index/.document",
"lib/rdoc/generator/template/json_index/js/navigation.js",
"lib/rdoc/generator/template/json_index/js/searcher.js",
- "lib/rdoc/code_object/ghost_method.rb",
+ "lib/rdoc/ghost_method.rb",
"lib/rdoc/i18n.rb",
"lib/rdoc/i18n/locale.rb",
"lib/rdoc/i18n/text.rb",
- "lib/rdoc/code_object/include.rb",
+ "lib/rdoc/include.rb",
"lib/rdoc/known_classes.rb",
"lib/rdoc/markdown.kpeg",
"lib/rdoc/markdown/entities.rb",
@@ -180,11 +176,11 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
"lib/rdoc/markup/to_test.rb",
"lib/rdoc/markup/to_tt_only.rb",
"lib/rdoc/markup/verbatim.rb",
- "lib/rdoc/code_object/meta_method.rb",
- "lib/rdoc/code_object/method_attr.rb",
- "lib/rdoc/code_object/mixin.rb",
- "lib/rdoc/code_object/normal_class.rb",
- "lib/rdoc/code_object/normal_module.rb",
+ "lib/rdoc/meta_method.rb",
+ "lib/rdoc/method_attr.rb",
+ "lib/rdoc/mixin.rb",
+ "lib/rdoc/normal_class.rb",
+ "lib/rdoc/normal_module.rb",
"lib/rdoc/options.rb",
"lib/rdoc/parser.rb",
"lib/rdoc/parser/c.rb",
@@ -201,7 +197,7 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
"lib/rdoc/rd/inline.rb",
"lib/rdoc/rd/inline_parser.ry",
"lib/rdoc/rdoc.rb",
- "lib/rdoc/code_object/require.rb",
+ "lib/rdoc/require.rb",
"lib/rdoc/ri.rb",
"lib/rdoc/ri/driver.rb",
"lib/rdoc/ri/formatter.rb",
@@ -210,7 +206,7 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
"lib/rdoc/ri/task.rb",
"lib/rdoc/rubygems_hook.rb",
"lib/rdoc/servlet.rb",
- "lib/rdoc/code_object/single_class.rb",
+ "lib/rdoc/single_class.rb",
"lib/rdoc/stats.rb",
"lib/rdoc/stats/normal.rb",
"lib/rdoc/stats/quiet.rb",
@@ -220,7 +216,7 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
"lib/rdoc/text.rb",
"lib/rdoc/token_stream.rb",
"lib/rdoc/tom_doc.rb",
- "lib/rdoc/code_object/top_level.rb",
+ "lib/rdoc/top_level.rb",
"lib/rdoc/version.rb",
"man/ri.1",
]
@@ -230,7 +226,7 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat
s.rdoc_options = ["--main", "README.rdoc"]
s.extra_rdoc_files += s.files.grep(%r[\A[^\/]+\.(?:rdoc|md)\z])
- s.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
+ s.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
s.required_rubygems_version = Gem::Requirement.new(">= 2.2")
s.add_dependency 'psych', '>= 4.0.0'
diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb
index 88ae55b409..2d8a9dea8c 100644
--- a/lib/rdoc/rdoc.rb
+++ b/lib/rdoc/rdoc.rb
@@ -119,7 +119,7 @@ class RDoc::RDoc
# +files+.
def gather_files files
- files = [@options.root.to_s] if files.empty?
+ files = ["."] if files.empty?
file_list = normalized_file_list files, true, @options.exclude
@@ -356,7 +356,7 @@ option)
top_level = @store.add_file filename, relative_name: relative_path.to_s
- parser = RDoc::Parser.for top_level, content, @options, @stats
+ parser = RDoc::Parser.for top_level, filename, content, @options, @stats
return unless parser
@@ -429,7 +429,9 @@ The internal error was:
files.reject do |file, *|
file =~ /\.(?:class|eps|erb|scpt\.txt|svg|ttf|yml)$/i or
(file =~ /tags$/i and
- /\A(\f\n[^,]+,\d+$|!_TAG_)/.match?(File.binread(file, 100)))
+ File.open(file, 'rb') { |io|
+ io.read(100) =~ /\A(\f\n[^,]+,\d+$|!_TAG_)/
+ })
end
end
@@ -520,7 +522,6 @@ The internal error was:
Dir.chdir @options.op_dir do
unless @options.quiet then
$stderr.puts "\nGenerating #{@generator.class.name.sub(/^.*::/, '')} format into #{Dir.pwd}..."
- $stderr.puts "\nYou can visit the home page at: \e]8;;file://#{Dir.pwd}/index.html\e\\file://#{Dir.pwd}/index.html\e]8;;\e\\"
end
@generator.generate
@@ -545,7 +546,7 @@ end
begin
require 'rubygems'
- rdoc_extensions = Gem.find_latest_files 'rdoc/discover'
+ rdoc_extensions = Gem.find_files 'rdoc/discover'
rdoc_extensions.each do |extension|
begin
diff --git a/lib/rdoc/require.rb b/lib/rdoc/require.rb
new file mode 100644
index 0000000000..91f9c24e5d
--- /dev/null
+++ b/lib/rdoc/require.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+##
+# A file loaded by \#require
+
+class RDoc::Require < RDoc::CodeObject
+
+ ##
+ # Name of the required file
+
+ attr_accessor :name
+
+ ##
+ # Creates a new Require that loads +name+ with +comment+
+
+ def initialize(name, comment)
+ super()
+ @name = name.gsub(/'|"/, "") #'
+ @top_level = nil
+ self.comment = comment
+ end
+
+ def inspect # :nodoc:
+ "#<%s:0x%x require '%s' in %s>" % [
+ self.class,
+ object_id,
+ @name,
+ parent_file_name,
+ ]
+ end
+
+ def to_s # :nodoc:
+ "require #{name} in: #{parent}"
+ end
+
+ ##
+ # The RDoc::TopLevel corresponding to this require, or +nil+ if not found.
+
+ def top_level
+ @top_level ||= begin
+ tl = RDoc::TopLevel.all_files_hash[name + '.rb']
+
+ if tl.nil? and RDoc::TopLevel.all_files.first.full_name =~ %r(^lib/) then
+ # second chance
+ tl = RDoc::TopLevel.all_files_hash['lib/' + name + '.rb']
+ end
+
+ tl
+ end
+ end
+
+end
+
diff --git a/lib/rdoc/ri/driver.rb b/lib/rdoc/ri/driver.rb
index c6fddbac67..819cff8aa3 100644
--- a/lib/rdoc/ri/driver.rb
+++ b/lib/rdoc/ri/driver.rb
@@ -34,9 +34,9 @@ class RDoc::RI::Driver
class NotFoundError < Error
- def initialize(klass, suggestion_proc = nil) # :nodoc:
+ def initialize(klass, suggestions = nil) # :nodoc:
@klass = klass
- @suggestion_proc = suggestion_proc
+ @suggestions = suggestions
end
##
@@ -48,9 +48,8 @@ class RDoc::RI::Driver
def message # :nodoc:
str = "Nothing known about #{@klass}"
- suggestions = @suggestion_proc&.call
- if suggestions and !suggestions.empty?
- str += "\nDid you mean? #{suggestions.join("\n ")}"
+ if @suggestions and !@suggestions.empty?
+ str += "\nDid you mean? #{@suggestions.join("\n ")}"
end
str
end
@@ -110,6 +109,10 @@ class RDoc::RI::Driver
options = default_options
opts = OptionParser.new do |opt|
+ opt.accept File do |file,|
+ File.readable?(file) and not File.directory?(file) and file
+ end
+
opt.program_name = File.basename $0
opt.version = RDoc::VERSION
opt.release = nil
@@ -341,17 +344,9 @@ or the PAGER environment variable.
opt.separator nil
- opt.on("--dump=CACHE",
+ opt.on("--dump=CACHE", File,
"Dump data from an ri cache or data file.") do |value|
- unless File.readable?(value)
- abort "#{value.inspect} is not readable"
- end
-
- if File.directory?(value)
- abort "#{value.inspect} is a directory"
- end
-
- options[:dump_path] = File.new(value)
+ options[:dump_path] = value
end
end
@@ -953,8 +948,8 @@ or the PAGER environment variable.
ary = class_names.grep(Regexp.new("\\A#{klass.gsub(/(?=::|\z)/, '[^:]*')}\\z"))
if ary.length != 1 && ary.first != klass
if check_did_you_mean
- suggestion_proc = -> { DidYouMean::SpellChecker.new(dictionary: class_names).correct(klass) }
- raise NotFoundError.new(klass, suggestion_proc)
+ suggestions = DidYouMean::SpellChecker.new(dictionary: class_names).correct(klass)
+ raise NotFoundError.new(klass, suggestions)
else
raise NotFoundError, klass
end
@@ -1092,7 +1087,7 @@ or the PAGER environment variable.
loop do
name = if defined? Readline then
- Readline.readline ">> ", true
+ Readline.readline ">> "
else
print ">> "
$stdin.gets
@@ -1242,8 +1237,8 @@ or the PAGER environment variable.
methods.push(*store.instance_methods[klass]) if [:instance, :both].include? types
end
methods = methods.uniq
- suggestion_proc = -> { DidYouMean::SpellChecker.new(dictionary: methods).correct(method_name) }
- raise NotFoundError.new(name, suggestion_proc)
+ suggestions = DidYouMean::SpellChecker.new(dictionary: methods).correct(method_name)
+ raise NotFoundError.new(name, suggestions)
else
raise NotFoundError, name
end
diff --git a/lib/rdoc/ri/store.rb b/lib/rdoc/ri/store.rb
index 96742e7ae3..9f4b03734a 100644
--- a/lib/rdoc/ri/store.rb
+++ b/lib/rdoc/ri/store.rb
@@ -4,3 +4,4 @@ module RDoc::RI
Store = RDoc::Store # :nodoc:
end
+
diff --git a/lib/rdoc/single_class.rb b/lib/rdoc/single_class.rb
new file mode 100644
index 0000000000..860f06a6e5
--- /dev/null
+++ b/lib/rdoc/single_class.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+##
+# A singleton class
+
+class RDoc::SingleClass < RDoc::ClassModule
+
+ ##
+ # Adds the superclass to the included modules.
+
+ def ancestors
+ superclass ? super + [superclass] : super
+ end
+
+ def aref_prefix # :nodoc:
+ 'sclass'
+ end
+
+ ##
+ # The definition of this singleton class, <tt>class << MyClassName</tt>
+
+ def definition
+ "class << #{full_name}"
+ end
+
+ def pretty_print q # :nodoc:
+ q.group 2, "[class << #{full_name}", "]" do
+ next
+ end
+ end
+end
+
diff --git a/lib/rdoc/stats/quiet.rb b/lib/rdoc/stats/quiet.rb
index 9c98ea5f86..bc4161b2d4 100644
--- a/lib/rdoc/stats/quiet.rb
+++ b/lib/rdoc/stats/quiet.rb
@@ -57,3 +57,4 @@ class RDoc::Stats::Quiet
def done_adding(*) end
end
+
diff --git a/lib/rdoc/stats/verbose.rb b/lib/rdoc/stats/verbose.rb
index 7090d561f8..6ace8937a2 100644
--- a/lib/rdoc/stats/verbose.rb
+++ b/lib/rdoc/stats/verbose.rb
@@ -42,3 +42,5 @@ class RDoc::Stats::Verbose < RDoc::Stats::Normal
end
end
+
+
diff --git a/lib/rdoc/store.rb b/lib/rdoc/store.rb
index cd27d47dd1..c793e49ed8 100644
--- a/lib/rdoc/store.rb
+++ b/lib/rdoc/store.rb
@@ -197,9 +197,6 @@ class RDoc::Store
top_level
end
- ##
- # Sets the parser of +absolute_name+, unless it from a source code file.
-
def update_parser_of_file(absolute_name, parser)
if top_level = @files_hash[absolute_name] then
@text_files_hash[absolute_name] = top_level if top_level.text?
diff --git a/lib/rdoc/task.rb b/lib/rdoc/task.rb
index ba697d0a93..8ea2d0588c 100644
--- a/lib/rdoc/task.rb
+++ b/lib/rdoc/task.rb
@@ -50,9 +50,6 @@ require 'rake/tasklib'
# [rerdoc]
# Rebuild the rdoc files from scratch, even if they are not out of date.
#
-# [rdoc:coverage]
-# Print RDoc coverage report for all rdoc files.
-#
# Simple Example:
#
# require 'rdoc/task'
@@ -93,8 +90,8 @@ require 'rake/tasklib'
# RDoc::Task.new(:rdoc => "rdoc", :clobber_rdoc => "rdoc:clean",
# :rerdoc => "rdoc:force")
#
-# This will create the tasks <tt>:rdoc</tt>, <tt>:rdoc:clean</tt>,
-# <tt>:rdoc:force</tt>, and <tt>:rdoc:coverage</tt>.
+# This will create the tasks <tt>:rdoc</tt>, <tt>:rdoc:clean</tt> and
+# <tt>:rdoc:force</tt>.
class RDoc::Task < Rake::TaskLib
@@ -104,8 +101,9 @@ class RDoc::Task < Rake::TaskLib
attr_accessor :name
##
- # The markup format; one of: +rdoc+ (the default), +markdown+, +rd+, +tomdoc+.
- # See {Markup Formats}[rdoc-ref:RDoc::Markup@Markup+Formats].
+ # Comment markup format. rdoc, rd and tomdoc are supported. (default is
+ # 'rdoc')
+
attr_accessor :markup
##
@@ -250,18 +248,6 @@ class RDoc::Task < Rake::TaskLib
RDoc::RDoc.new.document args
end
- namespace rdoc_task_name do
- desc coverage_task_description
- task coverage_task_name do
- @before_running_rdoc.call if @before_running_rdoc
- opts = option_list << "-C"
- args = opts + @rdoc_files
-
- $stderr.puts "rdoc #{args.join ' '}" if Rake.application.options.trace
- RDoc::RDoc.new.document args
- end
- end
-
self
end
@@ -302,13 +288,6 @@ class RDoc::Task < Rake::TaskLib
"Rebuild RDoc HTML files"
end
- ##
- # Task description for the coverage task or its renamed description
-
- def coverage_task_description
- "Print RDoc coverage report"
- end
-
private
def rdoc_target
@@ -336,10 +315,6 @@ class RDoc::Task < Rake::TaskLib
end
end
- def coverage_task_name
- "coverage"
- end
-
end
# :stopdoc:
diff --git a/lib/rdoc/text.rb b/lib/rdoc/text.rb
index 9804f81abe..0bc4aba428 100644
--- a/lib/rdoc/text.rb
+++ b/lib/rdoc/text.rb
@@ -10,10 +10,6 @@ require 'strscan'
module RDoc::Text
- ##
- # The language for this text. This affects stripping comments
- # markers.
-
attr_accessor :language
##
@@ -313,10 +309,4 @@ module RDoc::Text
res.join.strip
end
- ##
- # Character class to be separated by a space when concatenating
- # lines.
-
- SPACE_SEPARATED_LETTER_CLASS = /[\p{Nd}\p{Lc}\p{Pc}]|[!-~&&\W]/
-
end
diff --git a/lib/rdoc/token_stream.rb b/lib/rdoc/token_stream.rb
index 19ca7ed248..f428e2400c 100644
--- a/lib/rdoc/token_stream.rb
+++ b/lib/rdoc/token_stream.rb
@@ -112,7 +112,8 @@ module RDoc::TokenStream
# Returns a string representation of the token stream
def tokens_to_s
- (token_stream or return '').compact.map { |token| token[:text] }.join ''
+ token_stream.compact.map { |token| token[:text] }.join ''
end
end
+
diff --git a/lib/rdoc/tom_doc.rb b/lib/rdoc/tom_doc.rb
index d10f024f70..e161fcf42f 100644
--- a/lib/rdoc/tom_doc.rb
+++ b/lib/rdoc/tom_doc.rb
@@ -3,7 +3,13 @@
# A parser for TomDoc based on TomDoc 1.0.0-rc1 (02adef9b5a)
#
-# The TomDoc specification can be found at http://tomdoc.org.
+# The TomDoc specification can be found at:
+#
+# http://tomdoc.org
+#
+# The latest version of the TomDoc specification can be found at:
+#
+# https://github.com/mojombo/tomdoc/blob/master/tomdoc.md
#
# To choose TomDoc as your only default format see RDoc::Options@Saved+Options
# for instructions on setting up a <code>.rdoc_options</code> file to store
diff --git a/lib/rdoc/top_level.rb b/lib/rdoc/top_level.rb
new file mode 100644
index 0000000000..b8b6110bb2
--- /dev/null
+++ b/lib/rdoc/top_level.rb
@@ -0,0 +1,289 @@
+# frozen_string_literal: true
+##
+# A TopLevel context is a representation of the contents of a single file
+
+class RDoc::TopLevel < RDoc::Context
+
+ MARSHAL_VERSION = 0 # :nodoc:
+
+ ##
+ # This TopLevel's File::Stat struct
+
+ attr_accessor :file_stat
+
+ ##
+ # Relative name of this file
+
+ attr_accessor :relative_name
+
+ ##
+ # Absolute name of this file
+
+ attr_accessor :absolute_name
+
+ ##
+ # All the classes or modules that were declared in
+ # this file. These are assigned to either +#classes_hash+
+ # or +#modules_hash+ once we know what they really are.
+
+ attr_reader :classes_or_modules
+
+ attr_accessor :diagram # :nodoc:
+
+ ##
+ # The parser class that processed this file
+
+ attr_reader :parser
+
+ ##
+ # Creates a new TopLevel for the file at +absolute_name+. If documentation
+ # is being generated outside the source dir +relative_name+ is relative to
+ # the source directory.
+
+ def initialize absolute_name, relative_name = absolute_name
+ super()
+ @name = nil
+ @absolute_name = absolute_name
+ @relative_name = relative_name
+ @file_stat = File.stat(absolute_name) rescue nil # HACK for testing
+ @diagram = nil
+ @parser = nil
+
+ @classes_or_modules = []
+ end
+
+ def parser=(val)
+ @parser = val
+ @store.update_parser_of_file(absolute_name, val) if @store
+ @parser
+ end
+
+ ##
+ # An RDoc::TopLevel is equal to another with the same relative_name
+
+ def == other
+ self.class === other and @relative_name == other.relative_name
+ end
+
+ alias eql? ==
+
+ ##
+ # Adds +an_alias+ to +Object+ instead of +self+.
+
+ def add_alias(an_alias)
+ object_class.record_location self
+ return an_alias unless @document_self
+ object_class.add_alias an_alias
+ end
+
+ ##
+ # Adds +constant+ to +Object+ instead of +self+.
+
+ def add_constant constant
+ object_class.record_location self
+ return constant unless @document_self
+ object_class.add_constant constant
+ end
+
+ ##
+ # Adds +include+ to +Object+ instead of +self+.
+
+ def add_include(include)
+ object_class.record_location self
+ return include unless @document_self
+ object_class.add_include include
+ end
+
+ ##
+ # Adds +method+ to +Object+ instead of +self+.
+
+ def add_method(method)
+ object_class.record_location self
+ return method unless @document_self
+ object_class.add_method method
+ end
+
+ ##
+ # Adds class or module +mod+. Used in the building phase
+ # by the Ruby parser.
+
+ def add_to_classes_or_modules mod
+ @classes_or_modules << mod
+ end
+
+ ##
+ # Base name of this file
+
+ def base_name
+ File.basename @relative_name
+ end
+
+ alias name base_name
+
+ ##
+ # Only a TopLevel that contains text file) will be displayed. See also
+ # RDoc::CodeObject#display?
+
+ def display?
+ text? and super
+ end
+
+ ##
+ # See RDoc::TopLevel::find_class_or_module
+ #--
+ # TODO Why do we search through all classes/modules found, not just the
+ # ones of this instance?
+
+ def find_class_or_module name
+ @store.find_class_or_module name
+ end
+
+ ##
+ # Finds a class or module named +symbol+
+
+ def find_local_symbol(symbol)
+ find_class_or_module(symbol) || super
+ end
+
+ ##
+ # Finds a module or class with +name+
+
+ def find_module_named(name)
+ find_class_or_module(name)
+ end
+
+ ##
+ # Returns the relative name of this file
+
+ def full_name
+ @relative_name
+ end
+
+ ##
+ # An RDoc::TopLevel has the same hash as another with the same
+ # relative_name
+
+ def hash
+ @relative_name.hash
+ end
+
+ ##
+ # URL for this with a +prefix+
+
+ def http_url(prefix)
+ path = [prefix, @relative_name.tr('.', '_')]
+
+ File.join(*path.compact) + '.html'
+ end
+
+ def inspect # :nodoc:
+ "#<%s:0x%x %p modules: %p classes: %p>" % [
+ self.class, object_id,
+ base_name,
+ @modules.map { |n,m| m },
+ @classes.map { |n,c| c }
+ ]
+ end
+
+ ##
+ # Time this file was last modified, if known
+
+ def last_modified
+ @file_stat ? file_stat.mtime : nil
+ end
+
+ ##
+ # Dumps this TopLevel for use by ri. See also #marshal_load
+
+ def marshal_dump
+ [
+ MARSHAL_VERSION,
+ @relative_name,
+ @parser,
+ parse(@comment),
+ ]
+ end
+
+ ##
+ # Loads this TopLevel from +array+.
+
+ def marshal_load array # :nodoc:
+ initialize array[1]
+
+ @parser = array[2]
+ @comment = array[3]
+
+ @file_stat = nil
+ end
+
+ ##
+ # Returns the NormalClass "Object", creating it if not found.
+ #
+ # Records +self+ as a location in "Object".
+
+ def object_class
+ @object_class ||= begin
+ oc = @store.find_class_named('Object') || add_class(RDoc::NormalClass, 'Object')
+ oc.record_location self
+ oc
+ end
+ end
+
+ ##
+ # Base name of this file without the extension
+
+ def page_name
+ basename = File.basename @relative_name
+ basename =~ /\.(rb|rdoc|txt|md)$/i
+
+ $` || basename
+ end
+
+ ##
+ # Path to this file for use with HTML generator output.
+
+ def path
+ http_url @store.rdoc.generator.file_dir
+ end
+
+ def pretty_print q # :nodoc:
+ q.group 2, "[#{self.class}: ", "]" do
+ q.text "base name: #{base_name.inspect}"
+ q.breakable
+
+ items = @modules.map { |n,m| m }
+ items.concat @modules.map { |n,c| c }
+ q.seplist items do |mod| q.pp mod end
+ end
+ end
+
+ ##
+ # Search record used by RDoc::Generator::JsonIndex
+
+ def search_record
+ return unless @parser < RDoc::Parser::Text
+
+ [
+ page_name,
+ '',
+ page_name,
+ '',
+ path,
+ '',
+ snippet(@comment),
+ ]
+ end
+
+ ##
+ # Is this TopLevel from a text file instead of a source code file?
+
+ def text?
+ @parser and @parser.include? RDoc::Parser::Text
+ end
+
+ def to_s # :nodoc:
+ "file #{full_name}"
+ end
+
+end
+
diff --git a/lib/rdoc/version.rb b/lib/rdoc/version.rb
index 427d4ae232..31c1aa0276 100644
--- a/lib/rdoc/version.rb
+++ b/lib/rdoc/version.rb
@@ -5,6 +5,6 @@ module RDoc
##
# RDoc version you are using
- VERSION = '6.7.0'
+ VERSION = '6.5.1.1'
end
diff --git a/lib/readline.gemspec b/lib/readline.gemspec
index 9221c29263..3a18f9edb6 100644
--- a/lib/readline.gemspec
+++ b/lib/readline.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = 'readline'
- spec.version = '0.0.4'
+ spec.version = '0.0.3'
spec.authors = ['aycabta']
spec.email = ['aycabta@gmail.com']
diff --git a/lib/readline.rb b/lib/readline.rb
index d1c9d3a955..29cdf3a14f 100644
--- a/lib/readline.rb
+++ b/lib/readline.rb
@@ -1,5 +1,5 @@
begin
- require "readline.#{RbConfig::CONFIG["DLEXT"]}"
+ require 'readline.so'
rescue LoadError
require 'reline' unless defined? Reline
Object.send(:remove_const, :Readline) if Object.const_defined?(:Readline)
diff --git a/lib/reline.rb b/lib/reline.rb
index 4ba74d2cb2..7800a281ce 100644
--- a/lib/reline.rb
+++ b/lib/reline.rb
@@ -1,4 +1,5 @@
require 'io/console'
+require 'timeout'
require 'forwardable'
require 'reline/version'
require 'reline/config'
@@ -7,29 +8,38 @@ require 'reline/key_stroke'
require 'reline/line_editor'
require 'reline/history'
require 'reline/terminfo'
-require 'reline/io'
-require 'reline/face'
require 'rbconfig'
module Reline
- # NOTE: For making compatible with the rb-readline gem
FILENAME_COMPLETION_PROC = nil
USERNAME_COMPLETION_PROC = nil
class ConfigEncodingConversionError < StandardError; end
- Key = Struct.new(:char, :combined_char, :with_meta) do
- # For dialog_proc `key.match?(dialog.name)`
- def match?(sym)
- combined_char.is_a?(Symbol) && combined_char == sym
+ Key = Struct.new('Key', :char, :combined_char, :with_meta) do
+ def match?(other)
+ case other
+ when Reline::Key
+ (other.char.nil? or char.nil? or char == other.char) and
+ (other.combined_char.nil? or combined_char.nil? or combined_char == other.combined_char) and
+ (other.with_meta.nil? or with_meta.nil? or with_meta == other.with_meta)
+ when Integer, Symbol
+ (combined_char and combined_char == other) or
+ (combined_char.nil? and char and char == other)
+ else
+ false
+ end
end
+ alias_method :==, :match?
end
CursorPos = Struct.new(:x, :y)
DialogRenderInfo = Struct.new(
:pos,
:contents,
- :face,
- :bg_color, # For the time being, this line should stay here for the compatibility with IRB.
+ :bg_color,
+ :pointer_bg_color,
+ :fg_color,
+ :pointer_fg_color,
:width,
:height,
:scrollbar,
@@ -66,54 +76,50 @@ module Reline
def initialize
self.output = STDOUT
- @mutex = Mutex.new
@dialog_proc_list = {}
yield self
@completion_quote_character = nil
- end
-
- def io_gate
- Reline::IOGate
+ @bracketed_paste_finished = false
end
def encoding
- io_gate.encoding
+ Reline::IOGate.encoding
end
def completion_append_character=(val)
if val.nil?
@completion_append_character = nil
elsif val.size == 1
- @completion_append_character = val.encode(encoding)
+ @completion_append_character = val.encode(Reline::IOGate.encoding)
elsif val.size > 1
- @completion_append_character = val[0].encode(encoding)
+ @completion_append_character = val[0].encode(Reline::IOGate.encoding)
else
@completion_append_character = nil
end
end
def basic_word_break_characters=(v)
- @basic_word_break_characters = v.encode(encoding)
+ @basic_word_break_characters = v.encode(Reline::IOGate.encoding)
end
def completer_word_break_characters=(v)
- @completer_word_break_characters = v.encode(encoding)
+ @completer_word_break_characters = v.encode(Reline::IOGate.encoding)
end
def basic_quote_characters=(v)
- @basic_quote_characters = v.encode(encoding)
+ @basic_quote_characters = v.encode(Reline::IOGate.encoding)
end
def completer_quote_characters=(v)
- @completer_quote_characters = v.encode(encoding)
+ @completer_quote_characters = v.encode(Reline::IOGate.encoding)
end
def filename_quote_characters=(v)
- @filename_quote_characters = v.encode(encoding)
+ @filename_quote_characters = v.encode(Reline::IOGate.encoding)
end
def special_prefixes=(v)
- @special_prefixes = v.encode(encoding)
+ @special_prefixes = v.encode(Reline::IOGate.encoding)
end
def completion_case_fold=(v)
@@ -159,13 +165,9 @@ module Reline
DialogProc = Struct.new(:dialog_proc, :context)
def add_dialog_proc(name_sym, p, context = nil)
+ raise ArgumentError unless p.respond_to?(:call) or p.nil?
raise ArgumentError unless name_sym.instance_of?(Symbol)
- if p.nil?
- @dialog_proc_list.delete(name_sym)
- else
- raise ArgumentError unless p.respond_to?(:call)
- @dialog_proc_list[name_sym] = DialogProc.new(p, context)
- end
+ @dialog_proc_list[name_sym] = DialogProc.new(p, context)
end
def dialog_proc(name_sym)
@@ -174,16 +176,20 @@ module Reline
def input=(val)
raise TypeError unless val.respond_to?(:getc) or val.nil?
- if val.respond_to?(:getc) && io_gate.respond_to?(:input=)
- io_gate.input = val
+ if val.respond_to?(:getc)
+ if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
+ Reline::ANSI.input = val
+ elsif Reline::IOGate == Reline::GeneralIO
+ Reline::GeneralIO.input = val
+ end
end
end
def output=(val)
raise TypeError unless val.respond_to?(:write) or val.nil?
@output = val
- if io_gate.respond_to?(:output=)
- io_gate.output = val
+ if defined?(Reline::ANSI) and Reline::IOGate == Reline::ANSI
+ Reline::ANSI.output = val
end
end
@@ -206,30 +212,37 @@ module Reline
end
def get_screen_size
- io_gate.get_screen_size
+ Reline::IOGate.get_screen_size
end
Reline::DEFAULT_DIALOG_PROC_AUTOCOMPLETE = ->() {
# autocomplete
- return unless config.autocompletion
-
- journey_data = completion_journey_data
- return unless journey_data
-
- target = journey_data.list.first
- completed = journey_data.list[journey_data.pointer]
- result = journey_data.list.drop(1)
- pointer = journey_data.pointer - 1
- return if completed.empty? || (result == [completed] && pointer < 0)
-
+ return nil unless config.autocompletion
+ if just_cursor_moving and completion_journey_data.nil?
+ # Auto complete starts only when edited
+ return nil
+ end
+ pre, target, post = retrieve_completion_block(true)
+ if target.nil? or target.empty? or (completion_journey_data&.pointer == -1 and target.size <= 3)
+ return nil
+ end
+ if completion_journey_data and completion_journey_data.list
+ result = completion_journey_data.list.dup
+ result.shift
+ pointer = completion_journey_data.pointer - 1
+ else
+ result = call_completion_proc_with_checking_args(pre, target, post)
+ pointer = nil
+ end
+ if result and result.size == 1 and result[0] == target and pointer != 0
+ result = nil
+ end
target_width = Reline::Unicode.calculate_width(target)
- completed_width = Reline::Unicode.calculate_width(completed)
- if cursor_pos.x <= completed_width - target_width
- # When target is rendered on the line above cursor position
- x = screen_width - completed_width
+ x = cursor_pos.x - target_width
+ if x < 0
+ x = screen_width + x
y = -1
else
- x = [cursor_pos.x - completed_width, 0].max
y = 0
end
cursor_pos_to_render = Reline::CursorPos.new(x, y)
@@ -242,58 +255,47 @@ module Reline
pos: cursor_pos_to_render,
contents: result,
scrollbar: true,
- height: [15, preferred_dialog_height].min,
- face: :completion_dialog
+ height: 15,
+ bg_color: 46,
+ pointer_bg_color: 45,
+ fg_color: 37,
+ pointer_fg_color: 37
)
}
Reline::DEFAULT_DIALOG_CONTEXT = Array.new
def readmultiline(prompt = '', add_hist = false, &confirm_multiline_termination)
- @mutex.synchronize do
- unless confirm_multiline_termination
- raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
- end
-
- io_gate.with_raw_input do
- inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
- end
-
- whole_buffer = line_editor.whole_buffer.dup
- whole_buffer.taint if RUBY_VERSION < '2.7'
- if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
- Reline::HISTORY << whole_buffer
- end
+ unless confirm_multiline_termination
+ raise ArgumentError.new('#readmultiline needs block to confirm multiline termination')
+ end
+ inner_readline(prompt, add_hist, true, &confirm_multiline_termination)
- if line_editor.eof?
- line_editor.reset_line
- # Return nil if the input is aborted by C-d.
- nil
- else
- whole_buffer
- end
+ whole_buffer = line_editor.whole_buffer.dup
+ whole_buffer.taint if RUBY_VERSION < '2.7'
+ if add_hist and whole_buffer and whole_buffer.chomp("\n").size > 0
+ Reline::HISTORY << whole_buffer
end
+
+ line_editor.reset_line if line_editor.whole_buffer.nil?
+ whole_buffer
end
def readline(prompt = '', add_hist = false)
- @mutex.synchronize do
- io_gate.with_raw_input do
- inner_readline(prompt, add_hist, false)
- end
-
- line = line_editor.line.dup
- line.taint if RUBY_VERSION < '2.7'
- if add_hist and line and line.chomp("\n").size > 0
- Reline::HISTORY << line.chomp("\n")
- end
+ inner_readline(prompt, add_hist, false)
- line_editor.reset_line if line_editor.line.nil?
- line
+ line = line_editor.line.dup
+ line.taint if RUBY_VERSION < '2.7'
+ if add_hist and line and line.chomp("\n").size > 0
+ Reline::HISTORY << line.chomp("\n")
end
+
+ line_editor.reset_line if line_editor.line.nil?
+ line
end
private def inner_readline(prompt, add_hist, multiline, &confirm_multiline_termination)
if ENV['RELINE_STDERR_TTY']
- if io_gate.win?
+ if Reline::IOGate.win?
$stderr = File.open(ENV['RELINE_STDERR_TTY'], 'a')
else
$stderr.reopen(ENV['RELINE_STDERR_TTY'], 'w')
@@ -301,14 +303,10 @@ module Reline
$stderr.sync = true
$stderr.puts "Reline is used by #{Process.pid}"
end
- unless config.test_mode or config.loaded?
- config.read
- io_gate.set_default_key_bindings(config)
- end
- otio = io_gate.prep
+ otio = Reline::IOGate.prep
may_req_ambiguous_char_width
- line_editor.reset(prompt, encoding: encoding)
+ line_editor.reset(prompt, encoding: Reline::IOGate.encoding)
if multiline
line_editor.multiline_on
if block_given?
@@ -324,84 +322,157 @@ module Reline
line_editor.prompt_proc = prompt_proc
line_editor.auto_indent_proc = auto_indent_proc
line_editor.dig_perfect_match_proc = dig_perfect_match_proc
+ line_editor.pre_input_hook = pre_input_hook
+ @dialog_proc_list.each_pair do |name_sym, d|
+ line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context)
+ end
- # Readline calls pre_input_hook just after printing the first prompt.
- line_editor.print_nomultiline_prompt
- pre_input_hook&.call
-
- unless Reline::IOGate.dumb?
- @dialog_proc_list.each_pair do |name_sym, d|
- line_editor.add_dialog_proc(name_sym, d.dialog_proc, d.context)
- end
+ unless config.test_mode
+ config.read
+ config.reset_default_key_bindings
+ Reline::IOGate.set_default_key_bindings(config)
end
- line_editor.update_dialogs
line_editor.rerender
begin
line_editor.set_signal_handlers
+ prev_pasting_state = false
loop do
+ prev_pasting_state = Reline::IOGate.in_pasting?
read_io(config.keyseq_timeout) { |inputs|
- line_editor.set_pasting_state(io_gate.in_pasting?)
- inputs.each do |key|
- if key.char == :bracketed_paste_start
- text = io_gate.read_bracketed_paste
- line_editor.insert_multiline_text(text)
- line_editor.scroll_into_view
- else
- line_editor.update(key)
- end
+ line_editor.set_pasting_state(Reline::IOGate.in_pasting?)
+ inputs.each { |c|
+ line_editor.input_key(c)
+ line_editor.rerender
+ }
+ if @bracketed_paste_finished
+ line_editor.rerender_all
+ @bracketed_paste_finished = false
end
}
- if line_editor.finished?
- line_editor.render_finished
- break
- else
- line_editor.set_pasting_state(io_gate.in_pasting?)
- line_editor.rerender
+ if prev_pasting_state == true and not Reline::IOGate.in_pasting? and not line_editor.finished?
+ line_editor.set_pasting_state(false)
+ prev_pasting_state = false
+ line_editor.rerender_all
end
+ break if line_editor.finished?
end
- io_gate.move_cursor_column(0)
+ Reline::IOGate.move_cursor_column(0)
rescue Errno::EIO
# Maybe the I/O has been closed.
- ensure
+ rescue StandardError => e
line_editor.finalize
- io_gate.deprep(otio)
+ Reline::IOGate.deprep(otio)
+ raise e
+ rescue Exception
+ # Including Interrupt
+ line_editor.finalize
+ Reline::IOGate.deprep(otio)
+ raise
end
+
+ line_editor.finalize
+ Reline::IOGate.deprep(otio)
end
- # GNU Readline watis for "keyseq-timeout" milliseconds when the input is
- # ambiguous whether it is matching or matched.
- # If the next character does not arrive within the specified timeout, input
- # is considered as matched.
- # `ESC` is ambiguous because it can be a standalone ESC (matched) or part of
- # `ESC char` or part of CSI sequence (matching).
+ # GNU Readline waits for "keyseq-timeout" milliseconds to see if the ESC
+ # is followed by a character, and times out and treats it as a standalone
+ # ESC if the second character does not arrive. If the second character
+ # comes before timed out, it is treated as a modifier key with the
+ # meta-property of meta-key, so that it can be distinguished from
+ # multibyte characters with the 8th bit turned on.
+ #
+ # GNU Readline will wait for the 2nd character with "keyseq-timeout"
+ # milli-seconds but wait forever after 3rd characters.
private def read_io(keyseq_timeout, &block)
buffer = []
- status = KeyStroke::MATCHING
loop do
- timeout = status == KeyStroke::MATCHING_MATCHED ? keyseq_timeout.fdiv(1000) : Float::INFINITY
- c = io_gate.getc(timeout)
- if c.nil? || c == -1
- if status == KeyStroke::MATCHING_MATCHED
- status = KeyStroke::MATCHED
- elsif buffer.empty?
- # io_gate is closed and reached EOF
- block.call([Key.new(nil, nil, false)])
- return
- else
- status = KeyStroke::UNMATCHED
- end
+ c = Reline::IOGate.getc
+ if c == -1
+ result = :unmatched
+ @bracketed_paste_finished = true
else
buffer << c
- status = key_stroke.match_status(buffer)
+ result = key_stroke.match_status(buffer)
end
+ case result
+ when :matched
+ expanded = key_stroke.expand(buffer).map{ |expanded_c|
+ Reline::Key.new(expanded_c, expanded_c, false)
+ }
+ block.(expanded)
+ break
+ when :matching
+ if buffer.size == 1
+ case read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
+ when :break then break
+ when :next then next
+ end
+ end
+ when :unmatched
+ if buffer.size == 1 and c == "\e".ord
+ read_escaped_key(keyseq_timeout, c, block)
+ else
+ expanded = buffer.map{ |expanded_c|
+ Reline::Key.new(expanded_c, expanded_c, false)
+ }
+ block.(expanded)
+ end
+ break
+ end
+ end
+ end
- if status == KeyStroke::MATCHED || status == KeyStroke::UNMATCHED
- expanded, rest_bytes = key_stroke.expand(buffer)
- rest_bytes.reverse_each { |c| io_gate.ungetc(c) }
- block.call(expanded)
- return
+ private def read_2nd_character_of_key_sequence(keyseq_timeout, buffer, c, block)
+ begin
+ succ_c = nil
+ Timeout.timeout(keyseq_timeout / 1000.0) {
+ succ_c = Reline::IOGate.getc
+ }
+ rescue Timeout::Error # cancel matching only when first byte
+ block.([Reline::Key.new(c, c, false)])
+ return :break
+ else
+ case key_stroke.match_status(buffer.dup.push(succ_c))
+ when :unmatched
+ if c == "\e".ord
+ block.([Reline::Key.new(succ_c, succ_c | 0b10000000, true)])
+ else
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(succ_c, succ_c, false)])
+ end
+ return :break
+ when :matching
+ Reline::IOGate.ungetc(succ_c)
+ return :next
+ when :matched
+ buffer << succ_c
+ expanded = key_stroke.expand(buffer).map{ |expanded_c|
+ Reline::Key.new(expanded_c, expanded_c, false)
+ }
+ block.(expanded)
+ return :break
+ end
+ end
+ end
+
+ private def read_escaped_key(keyseq_timeout, c, block)
+ begin
+ escaped_c = nil
+ Timeout.timeout(keyseq_timeout / 1000.0) {
+ escaped_c = Reline::IOGate.getc
+ }
+ rescue Timeout::Error # independent ESC
+ block.([Reline::Key.new(c, c, false)])
+ else
+ if escaped_c.nil?
+ block.([Reline::Key.new(c, c, false)])
+ elsif escaped_c >= 128 # maybe, first byte of multi byte
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(escaped_c, escaped_c, false)])
+ elsif escaped_c == "\e".ord # escape twice
+ block.([Reline::Key.new(c, c, false), Reline::Key.new(c, c, false)])
+ else
+ block.([Reline::Key.new(escaped_c, escaped_c | 0b10000000, true)])
end
end
end
@@ -412,19 +483,19 @@ module Reline
end
private def may_req_ambiguous_char_width
- @ambiguous_width = 1 if io_gate.dumb? || !STDIN.tty? || !STDOUT.tty?
+ @ambiguous_width = 2 if Reline::IOGate == Reline::GeneralIO or !STDOUT.tty?
return if defined? @ambiguous_width
- io_gate.move_cursor_column(0)
+ Reline::IOGate.move_cursor_column(0)
begin
output.write "\u{25bd}"
rescue Encoding::UndefinedConversionError
# LANG=C
@ambiguous_width = 1
else
- @ambiguous_width = io_gate.cursor_pos.x == 2 ? 2 : 1
+ @ambiguous_width = Reline::IOGate.cursor_pos.x
end
- io_gate.move_cursor_column(0)
- io_gate.erase_after_cursor
+ Reline::IOGate.move_cursor_column(0)
+ Reline::IOGate.erase_after_cursor
end
end
@@ -460,8 +531,8 @@ module Reline
def_single_delegator :line_editor, :byte_pointer, :point
def_single_delegator :line_editor, :byte_pointer=, :point=
- def self.insert_text(text)
- line_editor.insert_multiline_text(text)
+ def self.insert_text(*args, &block)
+ line_editor.insert_text(*args, &block)
self
end
@@ -487,7 +558,7 @@ module Reline
@core ||= Core.new { |core|
core.config = Reline::Config.new
core.key_stroke = Reline::KeyStroke.new(core.config)
- core.line_editor = Reline::LineEditor.new(core.config, core.encoding)
+ core.line_editor = Reline::LineEditor.new(core.config, Reline::IOGate.encoding)
core.basic_word_break_characters = " \t\n`><=;|&{("
core.completer_word_break_characters = " \t\n`><=;|&{("
@@ -500,7 +571,7 @@ module Reline
end
def self.ungetc(c)
- core.io_gate.ungetc(c)
+ Reline::IOGate.ungetc(c)
end
def self.line_editor
@@ -508,12 +579,22 @@ module Reline
end
end
-
-Reline::IOGate = Reline::IO.decide_io_gate
-
-# Deprecated
-Reline::GeneralIO = Reline::Dumb.new
-
-Reline::Face.load_initial_configs
+require 'reline/general_io'
+io = Reline::GeneralIO
+unless ENV['TERM'] == 'dumb'
+ case RbConfig::CONFIG['host_os']
+ when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
+ require 'reline/windows'
+ tty = (io = Reline::Windows).msys_tty?
+ else
+ tty = $stdout.tty?
+ end
+end
+Reline::IOGate = if tty
+ require 'reline/ansi'
+ Reline::ANSI
+else
+ io
+end
Reline::HISTORY = Reline::History.new(Reline.core.config)
diff --git a/lib/reline/ansi.rb b/lib/reline/ansi.rb
new file mode 100644
index 0000000000..c40085e50d
--- /dev/null
+++ b/lib/reline/ansi.rb
@@ -0,0 +1,350 @@
+require 'io/console'
+require 'io/wait'
+require 'timeout'
+require_relative 'terminfo'
+
+class Reline::ANSI
+ CAPNAME_KEY_BINDINGS = {
+ 'khome' => :ed_move_to_beg,
+ 'kend' => :ed_move_to_end,
+ 'kcuu1' => :ed_prev_history,
+ 'kcud1' => :ed_next_history,
+ 'kcuf1' => :ed_next_char,
+ 'kcub1' => :ed_prev_char,
+ 'cuu' => :ed_prev_history,
+ 'cud' => :ed_next_history,
+ 'cuf' => :ed_next_char,
+ 'cub' => :ed_prev_char,
+ }
+
+ if Reline::Terminfo.enabled?
+ Reline::Terminfo.setupterm(0, 2)
+ end
+
+ def self.encoding
+ Encoding.default_external
+ end
+
+ def self.win?
+ false
+ end
+
+ def self.set_default_key_bindings(config)
+ if Reline::Terminfo.enabled?
+ set_default_key_bindings_terminfo(config)
+ else
+ set_default_key_bindings_comprehensive_list(config)
+ end
+ {
+ # extended entries of terminfo
+ [27, 91, 49, 59, 53, 67] => :em_next_word, # Ctrl+→, extended entry
+ [27, 91, 49, 59, 53, 68] => :ed_prev_word, # Ctrl+â†, extended entry
+ [27, 91, 49, 59, 51, 67] => :em_next_word, # Meta+→, extended entry
+ [27, 91, 49, 59, 51, 68] => :ed_prev_word, # Meta+â†, extended entry
+ }.each_pair do |key, func|
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
+ config.add_default_key_binding_by_keymap(:vi_command, key, func)
+ end
+ {
+ [27, 91, 90] => :completion_journey_up, # S-Tab
+ }.each_pair do |key, func|
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
+ end
+ {
+ # default bindings
+ [27, 32] => :em_set_mark, # M-<space>
+ [24, 24] => :em_exchange_mark, # C-x C-x
+ }.each_pair do |key, func|
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
+ end
+ end
+
+ def self.set_default_key_bindings_terminfo(config)
+ key_bindings = CAPNAME_KEY_BINDINGS.map do |capname, key_binding|
+ begin
+ key_code = Reline::Terminfo.tigetstr(capname)
+ case capname
+ # Escape sequences that omit the move distance and are set to defaults
+ # value 1 may be sometimes sent by pressing the arrow-key.
+ when 'cuu', 'cud', 'cuf', 'cub'
+ [ key_code.sub(/%p1%d/, '').bytes, key_binding ]
+ else
+ [ key_code.bytes, key_binding ]
+ end
+ rescue Reline::Terminfo::TerminfoError
+ # capname is undefined
+ end
+ end.compact.to_h
+
+ key_bindings.each_pair do |key, func|
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
+ config.add_default_key_binding_by_keymap(:vi_command, key, func)
+ end
+ end
+
+ def self.set_default_key_bindings_comprehensive_list(config)
+ {
+ # Console (80x25)
+ [27, 91, 49, 126] => :ed_move_to_beg, # Home
+ [27, 91, 52, 126] => :ed_move_to_end, # End
+ [27, 91, 51, 126] => :key_delete, # Del
+ [27, 91, 65] => :ed_prev_history, # ↑
+ [27, 91, 66] => :ed_next_history, # ↓
+ [27, 91, 67] => :ed_next_char, # →
+ [27, 91, 68] => :ed_prev_char, # â†
+
+ # KDE
+ [27, 91, 72] => :ed_move_to_beg, # Home
+ [27, 91, 70] => :ed_move_to_end, # End
+ # Del is 0x08
+ [27, 71, 65] => :ed_prev_history, # ↑
+ [27, 71, 66] => :ed_next_history, # ↓
+ [27, 71, 67] => :ed_next_char, # →
+ [27, 71, 68] => :ed_prev_char, # â†
+
+ # urxvt / exoterm
+ [27, 91, 55, 126] => :ed_move_to_beg, # Home
+ [27, 91, 56, 126] => :ed_move_to_end, # End
+
+ # GNOME
+ [27, 79, 72] => :ed_move_to_beg, # Home
+ [27, 79, 70] => :ed_move_to_end, # End
+ # Del is 0x08
+ # Arrow keys are the same of KDE
+
+ # iTerm2
+ [27, 27, 91, 67] => :em_next_word, # Option+→, extended entry
+ [27, 27, 91, 68] => :ed_prev_word, # Option+â†, extended entry
+ [195, 166] => :em_next_word, # Option+f
+ [195, 162] => :ed_prev_word, # Option+b
+
+ [27, 79, 65] => :ed_prev_history, # ↑
+ [27, 79, 66] => :ed_next_history, # ↓
+ [27, 79, 67] => :ed_next_char, # →
+ [27, 79, 68] => :ed_prev_char, # â†
+ }.each_pair do |key, func|
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
+ config.add_default_key_binding_by_keymap(:vi_command, key, func)
+ end
+ end
+
+ @@input = STDIN
+ def self.input=(val)
+ @@input = val
+ end
+
+ @@output = STDOUT
+ def self.output=(val)
+ @@output = val
+ end
+
+ @@buf = []
+ def self.inner_getc
+ unless @@buf.empty?
+ return @@buf.shift
+ end
+ until c = @@input.raw(intr: true) { @@input.wait_readable(0.1) && @@input.getbyte }
+ Reline.core.line_editor.resize
+ end
+ (c == 0x16 && @@input.raw(min: 0, time: 0, &:getbyte)) || c
+ rescue Errno::EIO
+ # Maybe the I/O has been closed.
+ nil
+ rescue Errno::ENOTTY
+ nil
+ end
+
+ @@in_bracketed_paste_mode = false
+ START_BRACKETED_PASTE = String.new("\e[200~,", encoding: Encoding::ASCII_8BIT)
+ END_BRACKETED_PASTE = String.new("\e[200~.", encoding: Encoding::ASCII_8BIT)
+ def self.getc_with_bracketed_paste
+ buffer = String.new(encoding: Encoding::ASCII_8BIT)
+ buffer << inner_getc
+ while START_BRACKETED_PASTE.start_with?(buffer) or END_BRACKETED_PASTE.start_with?(buffer) do
+ if START_BRACKETED_PASTE == buffer
+ @@in_bracketed_paste_mode = true
+ return inner_getc
+ elsif END_BRACKETED_PASTE == buffer
+ @@in_bracketed_paste_mode = false
+ ungetc(-1)
+ return inner_getc
+ end
+ begin
+ succ_c = nil
+ Timeout.timeout(Reline.core.config.keyseq_timeout * 100) {
+ succ_c = inner_getc
+ }
+ rescue Timeout::Error
+ break
+ else
+ buffer << succ_c
+ end
+ end
+ buffer.bytes.reverse_each do |ch|
+ ungetc ch
+ end
+ inner_getc
+ end
+
+ def self.getc
+ if Reline.core.config.enable_bracketed_paste
+ getc_with_bracketed_paste
+ else
+ inner_getc
+ end
+ end
+
+ def self.in_pasting?
+ @@in_bracketed_paste_mode or (not Reline::IOGate.empty_buffer?)
+ end
+
+ def self.empty_buffer?
+ unless @@buf.empty?
+ return false
+ end
+ !@@input.wait_readable(0)
+ end
+
+ def self.ungetc(c)
+ @@buf.unshift(c)
+ end
+
+ def self.retrieve_keybuffer
+ begin
+ return unless @@input.wait_readable(0.001)
+ str = @@input.read_nonblock(1024)
+ str.bytes.each do |c|
+ @@buf.push(c)
+ end
+ rescue EOFError
+ end
+ end
+
+ def self.get_screen_size
+ s = @@input.winsize
+ return s if s[0] > 0 && s[1] > 0
+ s = [ENV["LINES"].to_i, ENV["COLUMNS"].to_i]
+ return s if s[0] > 0 && s[1] > 0
+ [24, 80]
+ rescue Errno::ENOTTY
+ [24, 80]
+ end
+
+ def self.set_screen_size(rows, columns)
+ @@input.winsize = [rows, columns]
+ self
+ rescue Errno::ENOTTY
+ self
+ end
+
+ def self.cursor_pos
+ begin
+ res = +''
+ m = nil
+ @@input.raw do |stdin|
+ @@output << "\e[6n"
+ @@output.flush
+ loop do
+ c = stdin.getc
+ next if c.nil?
+ res << c
+ m = res.match(/\e\[(?<row>\d+);(?<column>\d+)R/)
+ break if m
+ end
+ (m.pre_match + m.post_match).chars.reverse_each do |ch|
+ stdin.ungetc ch
+ end
+ end
+ column = m[:column].to_i - 1
+ row = m[:row].to_i - 1
+ rescue Errno::ENOTTY
+ begin
+ buf = @@output.pread(@@output.pos, 0)
+ row = buf.count("\n")
+ column = buf.rindex("\n") ? (buf.size - buf.rindex("\n")) - 1 : 0
+ rescue Errno::ESPIPE
+ # Just returns column 1 for ambiguous width because this I/O is not
+ # tty and can't seek.
+ row = 0
+ column = 1
+ end
+ end
+ Reline::CursorPos.new(column, row)
+ end
+
+ def self.move_cursor_column(x)
+ @@output.write "\e[#{x + 1}G"
+ end
+
+ def self.move_cursor_up(x)
+ if x > 0
+ @@output.write "\e[#{x}A"
+ elsif x < 0
+ move_cursor_down(-x)
+ end
+ end
+
+ def self.move_cursor_down(x)
+ if x > 0
+ @@output.write "\e[#{x}B"
+ elsif x < 0
+ move_cursor_up(-x)
+ end
+ end
+
+ def self.hide_cursor
+ if Reline::Terminfo.enabled?
+ begin
+ @@output.write Reline::Terminfo.tigetstr('civis')
+ rescue Reline::Terminfo::TerminfoError
+ # civis is undefined
+ end
+ else
+ # ignored
+ end
+ end
+
+ def self.show_cursor
+ if Reline::Terminfo.enabled?
+ begin
+ @@output.write Reline::Terminfo.tigetstr('cnorm')
+ rescue Reline::Terminfo::TerminfoError
+ # cnorm is undefined
+ end
+ else
+ # ignored
+ end
+ end
+
+ def self.erase_after_cursor
+ @@output.write "\e[K"
+ end
+
+ def self.scroll_down(x)
+ return if x.zero?
+ @@output.write "\e[#{x}S"
+ end
+
+ def self.clear_screen
+ @@output.write "\e[2J"
+ @@output.write "\e[1;1H"
+ end
+
+ @@old_winch_handler = nil
+ def self.set_winch_handler(&handler)
+ @@old_winch_handler = Signal.trap('WINCH', &handler)
+ end
+
+ def self.prep
+ retrieve_keybuffer
+ nil
+ end
+
+ def self.deprep(otio)
+ Signal.trap('WINCH', @@old_winch_handler) if @@old_winch_handler
+ end
+end
diff --git a/lib/reline/config.rb b/lib/reline/config.rb
index e0fc37fc68..5ba269258f 100644
--- a/lib/reline/config.rb
+++ b/lib/reline/config.rb
@@ -1,19 +1,38 @@
class Reline::Config
attr_reader :test_mode
- KEYSEQ_PATTERN = /\\(?:C|Control)-[A-Za-z_]|\\(?:M|Meta)-[0-9A-Za-z_]|\\(?:C|Control)-\\(?:M|Meta)-[A-Za-z_]|\\(?:M|Meta)-\\(?:C|Control)-[A-Za-z_]|\\e|\\[\\\"\'abdfnrtv]|\\\d{1,3}|\\x\h{1,2}|./
+ KEYSEQ_PATTERN = /\\(?:C|Control)-[A-Za-z_]|\\(?:M|Meta)-[0-9A-Za-z_]|\\(?:C|Control)-(?:M|Meta)-[A-Za-z_]|\\(?:M|Meta)-(?:C|Control)-[A-Za-z_]|\\e|\\[\\\"\'abdfnrtv]|\\\d{1,3}|\\x\h{1,2}|./
class InvalidInputrc < RuntimeError
attr_accessor :file, :lineno
end
VARIABLE_NAMES = %w{
+ bind-tty-special-chars
+ blink-matching-paren
+ byte-oriented
completion-ignore-case
convert-meta
disable-completion
+ enable-keypad
+ expand-tilde
+ history-preserve-point
history-size
+ horizontal-scroll-mode
+ input-meta
keyseq-timeout
+ mark-directories
+ mark-modified-lines
+ mark-symlinked-directories
+ match-hidden-files
+ meta-flag
+ output-meta
+ page-completions
+ prefer-visible-bell
+ print-completions-horizontally
show-all-if-ambiguous
+ show-all-if-unmodified
+ visible-stats
show-mode-in-prompt
vi-cmd-mode-string
vi-ins-mode-string
@@ -29,31 +48,20 @@ class Reline::Config
attr_accessor :autocompletion
def initialize
- reset_variables
- end
-
- def reset
- if editing_mode_is?(:vi_command)
- @editing_mode_label = :vi_insert
- end
- @oneshot_key_bindings.clear
- end
-
- def reset_variables
- @additional_key_bindings = { # from inputrc
- emacs: Reline::KeyActor::Base.new,
- vi_insert: Reline::KeyActor::Base.new,
- vi_command: Reline::KeyActor::Base.new
- }
- @oneshot_key_bindings = Reline::KeyActor::Base.new
+ @additional_key_bindings = {} # from inputrc
+ @additional_key_bindings[:emacs] = {}
+ @additional_key_bindings[:vi_insert] = {}
+ @additional_key_bindings[:vi_command] = {}
+ @oneshot_key_bindings = {}
+ @skip_section = nil
+ @if_stack = nil
@editing_mode_label = :emacs
@keymap_label = :emacs
@keymap_prefix = []
- @default_key_bindings = {
- emacs: Reline::KeyActor::Base.new(Reline::KeyActor::EMACS_MAPPING),
- vi_insert: Reline::KeyActor::Base.new(Reline::KeyActor::VI_INSERT_MAPPING),
- vi_command: Reline::KeyActor::Base.new(Reline::KeyActor::VI_COMMAND_MAPPING)
- }
+ @key_actors = {}
+ @key_actors[:emacs] = Reline::KeyActor::Emacs.new
+ @key_actors[:vi_insert] = Reline::KeyActor::ViInsert.new
+ @key_actors[:vi_command] = Reline::KeyActor::ViCommand.new
@vi_cmd_mode_string = '(cmd)'
@vi_ins_mode_string = '(ins)'
@emacs_mode_string = '@'
@@ -62,15 +70,22 @@ class Reline::Config
@keyseq_timeout = 500
@test_mode = false
@autocompletion = false
- @convert_meta = seven_bit_encoding?(Reline::IOGate.encoding)
- @loaded = false
- @enable_bracketed_paste = true
- @show_mode_in_prompt = false
- @default_inputrc_path = nil
+ @convert_meta = true if seven_bit_encoding?(Reline::IOGate.encoding)
+ end
+
+ def reset
+ if editing_mode_is?(:vi_command)
+ @editing_mode_label = :vi_insert
+ end
+ @additional_key_bindings.keys.each do |key|
+ @additional_key_bindings[key].clear
+ end
+ @oneshot_key_bindings.clear
+ reset_default_key_bindings
end
def editing_mode
- @default_key_bindings[@editing_mode_label]
+ @key_actors[@editing_mode_label]
end
def editing_mode=(val)
@@ -78,15 +93,11 @@ class Reline::Config
end
def editing_mode_is?(*val)
- val.any?(@editing_mode_label)
+ (val.respond_to?(:any?) ? val : [val]).any?(@editing_mode_label)
end
def keymap
- @default_key_bindings[@keymap_label]
- end
-
- def loaded?
- @loaded
+ @key_actors[@keymap_label]
end
def inputrc_path
@@ -120,7 +131,6 @@ class Reline::Config
end
def read(file = nil)
- @loaded = true
file ||= default_inputrc_path
begin
if file.respond_to?(:readlines)
@@ -141,14 +151,14 @@ class Reline::Config
def key_bindings
# The key bindings for each editing mode will be overwritten by the user-defined ones.
- Reline::KeyActor::Composite.new([@oneshot_key_bindings, @additional_key_bindings[@editing_mode_label], @default_key_bindings[@editing_mode_label]])
+ kb = @key_actors[@editing_mode_label].default_key_bindings.dup
+ kb.merge!(@additional_key_bindings[@editing_mode_label])
+ kb.merge!(@oneshot_key_bindings)
+ kb
end
def add_oneshot_key_binding(keystroke, target)
- # IRB sets invalid keystroke [Reline::Key]. We should ignore it.
- return unless keystroke.all? { |c| c.is_a?(Integer) }
-
- @oneshot_key_bindings.add(keystroke, target)
+ @oneshot_key_bindings[keystroke] = target
end
def reset_oneshot_key_bindings
@@ -156,11 +166,17 @@ class Reline::Config
end
def add_default_key_binding_by_keymap(keymap, keystroke, target)
- @default_key_bindings[keymap].add(keystroke, target)
+ @key_actors[keymap].default_key_bindings[keystroke] = target
end
def add_default_key_binding(keystroke, target)
- add_default_key_binding_by_keymap(@keymap_label, keystroke, target)
+ @key_actors[@keymap_label].default_key_bindings[keystroke] = target
+ end
+
+ def reset_default_key_bindings
+ @key_actors.values.each do |ka|
+ ka.reset_default_key_bindings
+ end
end
def read_lines(lines, file = nil)
@@ -174,7 +190,9 @@ class Reline::Config
end
end
end
- if_stack = []
+ conditions = [@skip_section, @if_stack]
+ @skip_section = nil
+ @if_stack = []
lines.each_with_index do |line, no|
next if line.match(/\A\s*#/)
@@ -183,68 +201,62 @@ class Reline::Config
line = line.chomp.lstrip
if line.start_with?('$')
- handle_directive(line[1..-1], file, no, if_stack)
+ handle_directive(line[1..-1], file, no)
next
end
- next if if_stack.any? { |_no, skip| skip }
+ next if @skip_section
case line
- when /^set +([^ ]+) +(.+)/i
- # value ignores everything after a space, raw_value does not.
- var, value, raw_value = $1.downcase, $2.partition(' ').first, $2
- bind_variable(var, value, raw_value)
- when /^\s*(?:M|Meta)-([a-zA-Z_])\s*:\s*(.*)\s*$/o
- bind_key("\"\\M-#$1\"", $2)
- when /^\s*(?:C|Control)-([a-zA-Z_])\s*:\s*(.*)\s*$/o
- bind_key("\"\\C-#$1\"", $2)
- when /^\s*(?:(?:C|Control)-(?:M|Meta)|(?:M|Meta)-(?:C|Control))-([a-zA-Z_])\s*:\s*(.*)\s*$/o
- bind_key("\"\\M-\\C-#$1\"", $2)
- when /^\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o
- bind_key($1, $2)
+ when /^set +([^ ]+) +([^ ]+)/i
+ var, value = $1.downcase, $2
+ bind_variable(var, value)
+ next
+ when /\s*("#{KEYSEQ_PATTERN}+")\s*:\s*(.*)\s*$/o
+ key, func_name = $1, $2
+ keystroke, func = bind_key(key, func_name)
+ next unless keystroke
+ @additional_key_bindings[@keymap_label][@keymap_prefix + keystroke] = func
end
end
- unless if_stack.empty?
- raise InvalidInputrc, "#{file}:#{if_stack.last[0]}: unclosed if"
+ unless @if_stack.empty?
+ raise InvalidInputrc, "#{file}:#{@if_stack.last[1]}: unclosed if"
end
+ ensure
+ @skip_section, @if_stack = conditions
end
- def handle_directive(directive, file, no, if_stack)
+ def handle_directive(directive, file, no)
directive, args = directive.split(' ')
case directive
when 'if'
condition = false
case args
- when /^mode=(vi|emacs)$/i
- mode = $1.downcase
- # NOTE: mode=vi means vi-insert mode
- mode = 'vi_insert' if mode == 'vi'
- if @editing_mode_label == mode.to_sym
- condition = true
- end
+ when 'mode'
when 'term'
when 'version'
else # application name
condition = true if args == 'Ruby'
condition = true if args == 'Reline'
end
- if_stack << [no, !condition]
+ @if_stack << [file, no, @skip_section]
+ @skip_section = !condition
when 'else'
- if if_stack.empty?
+ if @if_stack.empty?
raise InvalidInputrc, "#{file}:#{no}: unmatched else"
end
- if_stack.last[1] = !if_stack.last[1]
+ @skip_section = !@skip_section
when 'endif'
- if if_stack.empty?
+ if @if_stack.empty?
raise InvalidInputrc, "#{file}:#{no}: unmatched endif"
end
- if_stack.pop
+ @skip_section = @if_stack.pop
when 'include'
- read(File.expand_path(args))
+ read(args)
end
end
- def bind_variable(name, value, raw_value)
+ def bind_variable(name, value)
case name
when 'history-size'
begin
@@ -252,8 +264,24 @@ class Reline::Config
rescue ArgumentError
@history_size = 500
end
+ when 'bell-style'
+ @bell_style =
+ case value
+ when 'none', 'off'
+ :none
+ when 'audible', 'on'
+ :audible
+ when 'visible'
+ :visible
+ else
+ :audible
+ end
+ when 'comment-begin'
+ @comment_begin = value.dup
+ when 'completion-query-items'
+ @completion_query_items = value.to_i
when 'isearch-terminators'
- @isearch_terminators = retrieve_string(raw_value)
+ @isearch_terminators = retrieve_string(value)
when 'editing-mode'
case value
when 'emacs'
@@ -295,11 +323,11 @@ class Reline::Config
@show_mode_in_prompt = false
end
when 'vi-cmd-mode-string'
- @vi_cmd_mode_string = retrieve_string(raw_value)
+ @vi_cmd_mode_string = retrieve_string(value)
when 'vi-ins-mode-string'
- @vi_ins_mode_string = retrieve_string(raw_value)
+ @vi_ins_mode_string = retrieve_string(value)
when 'emacs-mode-string'
- @emacs_mode_string = retrieve_string(raw_value)
+ @emacs_mode_string = retrieve_string(value)
when *VARIABLE_NAMES then
variable_name = :"@#{name.tr(?-, ?_)}"
instance_variable_set(variable_name, value.nil? || value == '1' || value == 'on')
@@ -311,12 +339,7 @@ class Reline::Config
parse_keyseq(str).map { |c| c.chr(Reline.encoding_system_needs) }.join
end
- def bind_key(key, value)
- keystroke, func = parse_key_binding(key, value)
- @additional_key_bindings[@keymap_label].add(@keymap_prefix + keystroke, func) if keystroke
- end
-
- def parse_key_binding(key, func_name)
+ def bind_key(key, func_name)
if key =~ /\A"(.*)"\z/
keyseq = parse_keyseq($1)
else
@@ -325,19 +348,27 @@ class Reline::Config
if func_name =~ /"(.*)"/
func = parse_keyseq($1)
else
- func = func_name.split.first.tr(?-, ?_).to_sym # It must be macro.
+ func = func_name.tr(?-, ?_).to_sym # It must be macro.
end
[keyseq, func]
end
def key_notation_to_code(notation)
case notation
- when /(?:\\(?:C|Control)-\\(?:M|Meta)|\\(?:M|Meta)-\\(?:C|Control))-([A-Za-z_])/
- [?\e.ord, $1.ord % 32]
when /\\(?:C|Control)-([A-Za-z_])/
- ($1.upcase.ord % 32)
+ (1 + $1.downcase.ord - ?a.ord)
when /\\(?:M|Meta)-([0-9A-Za-z_])/
- [?\e.ord, $1.ord]
+ modified_key = $1
+ case $1
+ when /[0-9]/
+ ?\M-0.bytes.first + (modified_key.ord - ?0.ord)
+ when /[A-Z]/
+ ?\M-A.bytes.first + (modified_key.ord - ?A.ord)
+ when /[a-z]/
+ ?\M-a.bytes.first + (modified_key.ord - ?a.ord)
+ end
+ when /\\(?:C|Control)-(?:M|Meta)-[A-Za-z_]/, /\\(?:M|Meta)-(?:C|Control)-[A-Za-z_]/
+ # 129 M-^A
when /\\(\d{1,3})/ then $1.to_i(8) # octal
when /\\x(\h{1,2})/ then $1.to_i(16) # hexadecimal
when "\\e" then ?\e.ord
@@ -357,14 +388,11 @@ class Reline::Config
end
def parse_keyseq(str)
- str.scan(KEYSEQ_PATTERN).flat_map do |notation|
- key_notation_to_code(notation)
+ ret = []
+ str.scan(KEYSEQ_PATTERN) do
+ ret << key_notation_to_code($&)
end
- end
-
- def reload
- reset_variables
- read
+ ret
end
private def seven_bit_encoding?(encoding)
diff --git a/lib/reline/face.rb b/lib/reline/face.rb
deleted file mode 100644
index 5b4464a623..0000000000
--- a/lib/reline/face.rb
+++ /dev/null
@@ -1,199 +0,0 @@
-# frozen_string_literal: true
-
-class Reline::Face
- SGR_PARAMETERS = {
- foreground: {
- black: 30,
- red: 31,
- green: 32,
- yellow: 33,
- blue: 34,
- magenta: 35,
- cyan: 36,
- white: 37,
- bright_black: 90,
- gray: 90,
- bright_red: 91,
- bright_green: 92,
- bright_yellow: 93,
- bright_blue: 94,
- bright_magenta: 95,
- bright_cyan: 96,
- bright_white: 97
- },
- background: {
- black: 40,
- red: 41,
- green: 42,
- yellow: 43,
- blue: 44,
- magenta: 45,
- cyan: 46,
- white: 47,
- bright_black: 100,
- gray: 100,
- bright_red: 101,
- bright_green: 102,
- bright_yellow: 103,
- bright_blue: 104,
- bright_magenta: 105,
- bright_cyan: 106,
- bright_white: 107,
- },
- style: {
- reset: 0,
- bold: 1,
- faint: 2,
- italicized: 3,
- underlined: 4,
- slowly_blinking: 5,
- blinking: 5,
- rapidly_blinking: 6,
- negative: 7,
- concealed: 8,
- crossed_out: 9
- }
- }.freeze
-
- class Config
- ESSENTIAL_DEFINE_NAMES = %i(default enhanced scrollbar).freeze
- RESET_SGR = "\e[0m".freeze
-
- def initialize(name, &block)
- @definition = {}
- block.call(self)
- ESSENTIAL_DEFINE_NAMES.each do |name|
- @definition[name] ||= { style: :reset, escape_sequence: RESET_SGR }
- end
- end
-
- attr_reader :definition
-
- def define(name, **values)
- values[:escape_sequence] = format_to_sgr(values.to_a).freeze
- @definition[name] = values
- end
-
- def reconfigure
- @definition.each_value do |values|
- values.delete(:escape_sequence)
- values[:escape_sequence] = format_to_sgr(values.to_a).freeze
- end
- end
-
- def [](name)
- @definition.dig(name, :escape_sequence) or raise ArgumentError, "unknown face: #{name}"
- end
-
- private
-
- def sgr_rgb(key, value)
- return nil unless rgb_expression?(value)
- if Reline::Face.truecolor?
- sgr_rgb_truecolor(key, value)
- else
- sgr_rgb_256color(key, value)
- end
- end
-
- def sgr_rgb_truecolor(key, value)
- case key
- when :foreground
- "38;2;"
- when :background
- "48;2;"
- end + value[1, 6].scan(/../).map(&:hex).join(";")
- end
-
- def sgr_rgb_256color(key, value)
- # 256 colors are
- # 0..15: standard colors, high intensity colors
- # 16..232: 216 colors (R, G, B each 6 steps)
- # 233..255: grayscale colors (24 steps)
- # This methods converts rgb_expression to 216 colors
- rgb = value[1, 6].scan(/../).map(&:hex)
- # Color steps are [0, 95, 135, 175, 215, 255]
- r, g, b = rgb.map { |v| v <= 95 ? v / 48 : (v - 35) / 40 }
- color = (16 + 36 * r + 6 * g + b)
- case key
- when :foreground
- "38;5;#{color}"
- when :background
- "48;5;#{color}"
- end
- end
-
- def format_to_sgr(ordered_values)
- sgr = "\e[" + ordered_values.map do |key_value|
- key, value = key_value
- case key
- when :foreground, :background
- case value
- when Symbol
- SGR_PARAMETERS[key][value]
- when String
- sgr_rgb(key, value)
- end
- when :style
- [ value ].flatten.map do |style_name|
- SGR_PARAMETERS[:style][style_name]
- end.then do |sgr_parameters|
- sgr_parameters.include?(nil) ? nil : sgr_parameters
- end
- end.then do |rendition_expression|
- unless rendition_expression
- raise ArgumentError, "invalid SGR parameter: #{value.inspect}"
- end
- rendition_expression
- end
- end.join(';') + "m"
- sgr == RESET_SGR ? RESET_SGR : RESET_SGR + sgr
- end
-
- def rgb_expression?(color)
- color.respond_to?(:match?) and color.match?(/\A#[0-9a-fA-F]{6}\z/)
- end
- end
-
- private_constant :SGR_PARAMETERS, :Config
-
- def self.truecolor?
- @force_truecolor || %w[truecolor 24bit].include?(ENV['COLORTERM'])
- end
-
- def self.force_truecolor
- @force_truecolor = true
- @configs&.each_value(&:reconfigure)
- end
-
- def self.[](name)
- @configs[name]
- end
-
- def self.config(name, &block)
- @configs ||= {}
- @configs[name] = Config.new(name, &block)
- end
-
- def self.configs
- @configs.transform_values(&:definition)
- end
-
- def self.load_initial_configs
- config(:default) do |conf|
- conf.define :default, style: :reset
- conf.define :enhanced, style: :reset
- conf.define :scrollbar, style: :reset
- end
- config(:completion_dialog) do |conf|
- conf.define :default, foreground: :bright_white, background: :gray
- conf.define :enhanced, foreground: :black, background: :white
- conf.define :scrollbar, foreground: :white, background: :gray
- end
- end
-
- def self.reset_to_initial_configs
- @configs = {}
- load_initial_configs
- end
-end
diff --git a/lib/reline/general_io.rb b/lib/reline/general_io.rb
new file mode 100644
index 0000000000..92c76cbba1
--- /dev/null
+++ b/lib/reline/general_io.rb
@@ -0,0 +1,109 @@
+require 'timeout'
+require 'io/wait'
+
+class Reline::GeneralIO
+ def self.reset(encoding: nil)
+ @@pasting = false
+ @@encoding = encoding
+ end
+
+ def self.encoding
+ if defined?(@@encoding)
+ @@encoding
+ elsif RUBY_PLATFORM =~ /mswin|mingw/
+ Encoding::UTF_8
+ else
+ Encoding::default_external
+ end
+ end
+
+ def self.win?
+ false
+ end
+
+ def self.set_default_key_bindings(_)
+ end
+
+ @@buf = []
+ @@input = STDIN
+
+ def self.input=(val)
+ @@input = val
+ end
+
+ def self.getc
+ unless @@buf.empty?
+ return @@buf.shift
+ end
+ c = nil
+ loop do
+ result = @@input.wait_readable(0.1)
+ next if result.nil?
+ c = @@input.read(1)
+ break
+ end
+ c&.ord
+ end
+
+ def self.ungetc(c)
+ @@buf.unshift(c)
+ end
+
+ def self.get_screen_size
+ [1, 1]
+ end
+
+ def self.cursor_pos
+ Reline::CursorPos.new(1, 1)
+ end
+
+ def self.hide_cursor
+ end
+
+ def self.show_cursor
+ end
+
+ def self.move_cursor_column(val)
+ end
+
+ def self.move_cursor_up(val)
+ end
+
+ def self.move_cursor_down(val)
+ end
+
+ def self.erase_after_cursor
+ end
+
+ def self.scroll_down(val)
+ end
+
+ def self.clear_screen
+ end
+
+ def self.set_screen_size(rows, columns)
+ end
+
+ def self.set_winch_handler(&handler)
+ end
+
+ @@pasting = false
+
+ def self.in_pasting?
+ @@pasting
+ end
+
+ def self.start_pasting
+ @@pasting = true
+ end
+
+ def self.finish_pasting
+ @@pasting = false
+ end
+
+ def self.prep
+ end
+
+ def self.deprep(otio)
+ end
+end
diff --git a/lib/reline/history.rb b/lib/reline/history.rb
index 47c68ba774..7a1ed6b90b 100644
--- a/lib/reline/history.rb
+++ b/lib/reline/history.rb
@@ -19,7 +19,7 @@ class Reline::History < Array
def []=(index, val)
index = check_index(index)
- super(index, Reline::Unicode.safe_encode(val, Reline.encoding_system_needs))
+ super(index, String.new(val, encoding: Reline.encoding_system_needs))
end
def concat(*val)
@@ -45,7 +45,7 @@ class Reline::History < Array
end
end
super(*(val.map{ |v|
- Reline::Unicode.safe_encode(v, Reline.encoding_system_needs)
+ String.new(v, encoding: Reline.encoding_system_needs)
}))
end
@@ -56,13 +56,13 @@ class Reline::History < Array
if @config.history_size.positive?
shift if size + 1 > @config.history_size
end
- super(Reline::Unicode.safe_encode(val, Reline.encoding_system_needs))
+ super(String.new(val, encoding: Reline.encoding_system_needs))
end
private def check_index(index)
index += size if index < 0
if index < -2147483648 or 2147483647 < index
- raise RangeError.new("integer #{index} too big to convert to 'int'")
+ raise RangeError.new("integer #{index} too big to convert to `int'")
end
# If history_size is negative, history size is unlimited.
if @config.history_size.positive?
diff --git a/lib/reline/io.rb b/lib/reline/io.rb
deleted file mode 100644
index c1dd1a56c8..0000000000
--- a/lib/reline/io.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-
-module Reline
- class IO
- RESET_COLOR = "\e[0m"
-
- def self.decide_io_gate
- if ENV['TERM'] == 'dumb'
- Reline::Dumb.new
- else
- require 'reline/io/ansi'
-
- case RbConfig::CONFIG['host_os']
- when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
- require 'reline/io/windows'
- io = Reline::Windows.new
- if io.msys_tty?
- Reline::ANSI.new
- else
- io
- end
- else
- Reline::ANSI.new
- end
- end
- end
-
- def dumb?
- false
- end
-
- def win?
- false
- end
-
- def reset_color_sequence
- self.class::RESET_COLOR
- end
- end
-end
-
-require 'reline/io/dumb'
diff --git a/lib/reline/io/ansi.rb b/lib/reline/io/ansi.rb
deleted file mode 100644
index 82d2ee2371..0000000000
--- a/lib/reline/io/ansi.rb
+++ /dev/null
@@ -1,363 +0,0 @@
-require 'io/console'
-require 'io/wait'
-
-class Reline::ANSI < Reline::IO
- CAPNAME_KEY_BINDINGS = {
- 'khome' => :ed_move_to_beg,
- 'kend' => :ed_move_to_end,
- 'kdch1' => :key_delete,
- 'kpp' => :ed_search_prev_history,
- 'knp' => :ed_search_next_history,
- 'kcuu1' => :ed_prev_history,
- 'kcud1' => :ed_next_history,
- 'kcuf1' => :ed_next_char,
- 'kcub1' => :ed_prev_char,
- }
-
- ANSI_CURSOR_KEY_BINDINGS = {
- # Up
- 'A' => [:ed_prev_history, {}],
- # Down
- 'B' => [:ed_next_history, {}],
- # Right
- 'C' => [:ed_next_char, { ctrl: :em_next_word, meta: :em_next_word }],
- # Left
- 'D' => [:ed_prev_char, { ctrl: :ed_prev_word, meta: :ed_prev_word }],
- # End
- 'F' => [:ed_move_to_end, {}],
- # Home
- 'H' => [:ed_move_to_beg, {}],
- }
-
- if Reline::Terminfo.enabled?
- Reline::Terminfo.setupterm(0, 2)
- end
-
- def initialize
- @input = STDIN
- @output = STDOUT
- @buf = []
- @old_winch_handler = nil
- end
-
- def encoding
- Encoding.default_external
- end
-
- def set_default_key_bindings(config, allow_terminfo: true)
- set_bracketed_paste_key_bindings(config)
- set_default_key_bindings_ansi_cursor(config)
- if allow_terminfo && Reline::Terminfo.enabled?
- set_default_key_bindings_terminfo(config)
- else
- set_default_key_bindings_comprehensive_list(config)
- end
- {
- [27, 91, 90] => :completion_journey_up, # S-Tab
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- end
- {
- # default bindings
- [27, 32] => :em_set_mark, # M-<space>
- [24, 24] => :em_exchange_mark, # C-x C-x
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- end
- end
-
- def set_bracketed_paste_key_bindings(config)
- [:emacs, :vi_insert, :vi_command].each do |keymap|
- config.add_default_key_binding_by_keymap(keymap, START_BRACKETED_PASTE.bytes, :bracketed_paste_start)
- end
- end
-
- def set_default_key_bindings_ansi_cursor(config)
- ANSI_CURSOR_KEY_BINDINGS.each do |char, (default_func, modifiers)|
- bindings = [["\e[#{char}", default_func]] # CSI + char
- if modifiers[:ctrl]
- # CSI + ctrl_key_modifier + char
- bindings << ["\e[1;5#{char}", modifiers[:ctrl]]
- end
- if modifiers[:meta]
- # CSI + meta_key_modifier + char
- bindings << ["\e[1;3#{char}", modifiers[:meta]]
- # Meta(ESC) + CSI + char
- bindings << ["\e\e[#{char}", modifiers[:meta]]
- end
- bindings.each do |sequence, func|
- key = sequence.bytes
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
- end
- end
- end
-
- def set_default_key_bindings_terminfo(config)
- key_bindings = CAPNAME_KEY_BINDINGS.map do |capname, key_binding|
- begin
- key_code = Reline::Terminfo.tigetstr(capname)
- [ key_code.bytes, key_binding ]
- rescue Reline::Terminfo::TerminfoError
- # capname is undefined
- end
- end.compact.to_h
-
- key_bindings.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
- end
- end
-
- def set_default_key_bindings_comprehensive_list(config)
- {
- # xterm
- [27, 91, 51, 126] => :key_delete, # kdch1
- [27, 91, 53, 126] => :ed_search_prev_history, # kpp
- [27, 91, 54, 126] => :ed_search_next_history, # knp
-
- # Console (80x25)
- [27, 91, 49, 126] => :ed_move_to_beg, # Home
- [27, 91, 52, 126] => :ed_move_to_end, # End
-
- # KDE
- # Del is 0x08
- [27, 71, 65] => :ed_prev_history, # ↑
- [27, 71, 66] => :ed_next_history, # ↓
- [27, 71, 67] => :ed_next_char, # →
- [27, 71, 68] => :ed_prev_char, # â†
-
- # urxvt / exoterm
- [27, 91, 55, 126] => :ed_move_to_beg, # Home
- [27, 91, 56, 126] => :ed_move_to_end, # End
-
- # GNOME
- [27, 79, 72] => :ed_move_to_beg, # Home
- [27, 79, 70] => :ed_move_to_end, # End
- # Del is 0x08
- # Arrow keys are the same of KDE
-
- [27, 79, 65] => :ed_prev_history, # ↑
- [27, 79, 66] => :ed_next_history, # ↓
- [27, 79, 67] => :ed_next_char, # →
- [27, 79, 68] => :ed_prev_char, # â†
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
- end
- end
-
- def input=(val)
- @input = val
- end
-
- def output=(val)
- @output = val
- end
-
- def with_raw_input
- if @input.tty?
- @input.raw(intr: true) { yield }
- else
- yield
- end
- end
-
- def inner_getc(timeout_second)
- unless @buf.empty?
- return @buf.shift
- end
- until @input.wait_readable(0.01)
- timeout_second -= 0.01
- return nil if timeout_second <= 0
-
- Reline.core.line_editor.handle_signal
- end
- c = @input.getbyte
- (c == 0x16 && @input.tty? && @input.raw(min: 0, time: 0, &:getbyte)) || c
- rescue Errno::EIO
- # Maybe the I/O has been closed.
- nil
- end
-
- START_BRACKETED_PASTE = String.new("\e[200~", encoding: Encoding::ASCII_8BIT)
- END_BRACKETED_PASTE = String.new("\e[201~", encoding: Encoding::ASCII_8BIT)
- def read_bracketed_paste
- buffer = String.new(encoding: Encoding::ASCII_8BIT)
- until buffer.end_with?(END_BRACKETED_PASTE)
- c = inner_getc(Float::INFINITY)
- break unless c
- buffer << c
- end
- string = buffer.delete_suffix(END_BRACKETED_PASTE).force_encoding(encoding)
- string.valid_encoding? ? string : ''
- end
-
- # if the usage expects to wait indefinitely, use Float::INFINITY for timeout_second
- def getc(timeout_second)
- inner_getc(timeout_second)
- end
-
- def in_pasting?
- not empty_buffer?
- end
-
- def empty_buffer?
- unless @buf.empty?
- return false
- end
- !@input.wait_readable(0)
- end
-
- def ungetc(c)
- @buf.unshift(c)
- end
-
- def retrieve_keybuffer
- begin
- return unless @input.wait_readable(0.001)
- str = @input.read_nonblock(1024)
- str.bytes.each do |c|
- @buf.push(c)
- end
- rescue EOFError
- end
- end
-
- def get_screen_size
- s = @input.winsize
- return s if s[0] > 0 && s[1] > 0
- s = [ENV["LINES"].to_i, ENV["COLUMNS"].to_i]
- return s if s[0] > 0 && s[1] > 0
- [24, 80]
- rescue Errno::ENOTTY, Errno::ENODEV
- [24, 80]
- end
-
- def set_screen_size(rows, columns)
- @input.winsize = [rows, columns]
- self
- rescue Errno::ENOTTY, Errno::ENODEV
- self
- end
-
- private def cursor_pos_internal(timeout:)
- match = nil
- @input.raw do |stdin|
- @output << "\e[6n"
- @output.flush
- timeout_at = Time.now + timeout
- buf = +''
- while (wait = timeout_at - Time.now) > 0 && stdin.wait_readable(wait)
- buf << stdin.readpartial(1024)
- if (match = buf.match(/\e\[(?<row>\d+);(?<column>\d+)R/))
- buf = match.pre_match + match.post_match
- break
- end
- end
- buf.chars.reverse_each do |ch|
- stdin.ungetc ch
- end
- end
- [match[:column].to_i - 1, match[:row].to_i - 1] if match
- end
-
- def cursor_pos
- col, row = cursor_pos_internal(timeout: 0.5) if both_tty?
- Reline::CursorPos.new(col || 0, row || 0)
- end
-
- def both_tty?
- @input.tty? && @output.tty?
- end
-
- def move_cursor_column(x)
- @output.write "\e[#{x + 1}G"
- end
-
- def move_cursor_up(x)
- if x > 0
- @output.write "\e[#{x}A"
- elsif x < 0
- move_cursor_down(-x)
- end
- end
-
- def move_cursor_down(x)
- if x > 0
- @output.write "\e[#{x}B"
- elsif x < 0
- move_cursor_up(-x)
- end
- end
-
- def hide_cursor
- seq = "\e[?25l"
- if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
- begin
- seq = Reline::Terminfo.tigetstr('civis')
- rescue Reline::Terminfo::TerminfoError
- # civis is undefined
- end
- end
- @output.write seq
- end
-
- def show_cursor
- seq = "\e[?25h"
- if Reline::Terminfo.enabled? && Reline::Terminfo.term_supported?
- begin
- seq = Reline::Terminfo.tigetstr('cnorm')
- rescue Reline::Terminfo::TerminfoError
- # cnorm is undefined
- end
- end
- @output.write seq
- end
-
- def erase_after_cursor
- @output.write "\e[K"
- end
-
- # This only works when the cursor is at the bottom of the scroll range
- # For more details, see https://github.com/ruby/reline/pull/577#issuecomment-1646679623
- def scroll_down(x)
- return if x.zero?
- # We use `\n` instead of CSI + S because CSI + S would cause https://github.com/ruby/reline/issues/576
- @output.write "\n" * x
- end
-
- def clear_screen
- @output.write "\e[2J"
- @output.write "\e[1;1H"
- end
-
- def set_winch_handler(&handler)
- @old_winch_handler = Signal.trap('WINCH', &handler)
- @old_cont_handler = Signal.trap('CONT') do
- @input.raw!(intr: true) if @input.tty?
- # Rerender the screen. Note that screen size might be changed while suspended.
- handler.call
- end
- rescue ArgumentError
- # Signal.trap may raise an ArgumentError if the platform doesn't support the signal.
- end
-
- def prep
- # Enable bracketed paste
- @output.write "\e[?2004h" if Reline.core.config.enable_bracketed_paste && both_tty?
- retrieve_keybuffer
- nil
- end
-
- def deprep(otio)
- # Disable bracketed paste
- @output.write "\e[?2004l" if Reline.core.config.enable_bracketed_paste && both_tty?
- Signal.trap('WINCH', @old_winch_handler) if @old_winch_handler
- Signal.trap('CONT', @old_cont_handler) if @old_cont_handler
- end
-end
diff --git a/lib/reline/io/dumb.rb b/lib/reline/io/dumb.rb
deleted file mode 100644
index 6a10af4fef..0000000000
--- a/lib/reline/io/dumb.rb
+++ /dev/null
@@ -1,106 +0,0 @@
-require 'io/wait'
-
-class Reline::Dumb < Reline::IO
- RESET_COLOR = '' # Do not send color reset sequence
-
- def initialize(encoding: nil)
- @input = STDIN
- @buf = []
- @pasting = false
- @encoding = encoding
- @screen_size = [24, 80]
- end
-
- def dumb?
- true
- end
-
- def encoding
- if @encoding
- @encoding
- elsif RUBY_PLATFORM =~ /mswin|mingw/
- Encoding::UTF_8
- else
- Encoding::default_external
- end
- end
-
- def set_default_key_bindings(_)
- end
-
- def input=(val)
- @input = val
- end
-
- def with_raw_input
- yield
- end
-
- def getc(_timeout_second)
- unless @buf.empty?
- return @buf.shift
- end
- c = nil
- loop do
- Reline.core.line_editor.handle_signal
- result = @input.wait_readable(0.1)
- next if result.nil?
- c = @input.read(1)
- break
- end
- c&.ord
- end
-
- def ungetc(c)
- @buf.unshift(c)
- end
-
- def get_screen_size
- @screen_size
- end
-
- def cursor_pos
- Reline::CursorPos.new(0, 0)
- end
-
- def hide_cursor
- end
-
- def show_cursor
- end
-
- def move_cursor_column(val)
- end
-
- def move_cursor_up(val)
- end
-
- def move_cursor_down(val)
- end
-
- def erase_after_cursor
- end
-
- def scroll_down(val)
- end
-
- def clear_screen
- end
-
- def set_screen_size(rows, columns)
- @screen_size = [rows, columns]
- end
-
- def set_winch_handler(&handler)
- end
-
- def in_pasting?
- @pasting
- end
-
- def prep
- end
-
- def deprep(otio)
- end
-end
diff --git a/lib/reline/io/windows.rb b/lib/reline/io/windows.rb
deleted file mode 100644
index f718743193..0000000000
--- a/lib/reline/io/windows.rb
+++ /dev/null
@@ -1,513 +0,0 @@
-require 'fiddle/import'
-
-class Reline::Windows < Reline::IO
- def initialize
- @input_buf = []
- @output_buf = []
-
- @output = STDOUT
- @hsg = nil
- @getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
- @kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
- @GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
- @GetConsoleScreenBufferInfo = Win32API.new('kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L')
- @SetConsoleCursorPosition = Win32API.new('kernel32', 'SetConsoleCursorPosition', ['L', 'L'], 'L')
- @GetStdHandle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
- @FillConsoleOutputCharacter = Win32API.new('kernel32', 'FillConsoleOutputCharacter', ['L', 'L', 'L', 'L', 'P'], 'L')
- @ScrollConsoleScreenBuffer = Win32API.new('kernel32', 'ScrollConsoleScreenBuffer', ['L', 'P', 'P', 'L', 'P'], 'L')
- @hConsoleHandle = @GetStdHandle.call(STD_OUTPUT_HANDLE)
- @hConsoleInputHandle = @GetStdHandle.call(STD_INPUT_HANDLE)
- @GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
- @ReadConsoleInputW = Win32API.new('kernel32', 'ReadConsoleInputW', ['L', 'P', 'L', 'P'], 'L')
- @GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
- @GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
- @FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
- @SetConsoleCursorInfo = Win32API.new('kernel32', 'SetConsoleCursorInfo', ['L', 'P'], 'L')
-
- @GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
- @SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
- @WaitForSingleObject = Win32API.new('kernel32', 'WaitForSingleObject', ['L', 'L'], 'L')
-
- @legacy_console = getconsolemode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0
- end
-
- def encoding
- Encoding::UTF_8
- end
-
- def win?
- true
- end
-
- def win_legacy_console?
- @legacy_console
- end
-
- def set_default_key_bindings(config)
- {
- [224, 72] => :ed_prev_history, # ↑
- [224, 80] => :ed_next_history, # ↓
- [224, 77] => :ed_next_char, # →
- [224, 75] => :ed_prev_char, # â†
- [224, 83] => :key_delete, # Del
- [224, 71] => :ed_move_to_beg, # Home
- [224, 79] => :ed_move_to_end, # End
- [ 0, 41] => :ed_unassigned, # input method on/off
- [ 0, 72] => :ed_prev_history, # ↑
- [ 0, 80] => :ed_next_history, # ↓
- [ 0, 77] => :ed_next_char, # →
- [ 0, 75] => :ed_prev_char, # â†
- [ 0, 83] => :key_delete, # Del
- [ 0, 71] => :ed_move_to_beg, # Home
- [ 0, 79] => :ed_move_to_end # End
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- config.add_default_key_binding_by_keymap(:vi_command, key, func)
- end
-
- {
- [27, 32] => :em_set_mark, # M-<space>
- [24, 24] => :em_exchange_mark, # C-x C-x
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- end
-
- # Emulate ANSI key sequence.
- {
- [27, 91, 90] => :completion_journey_up, # S-Tab
- }.each_pair do |key, func|
- config.add_default_key_binding_by_keymap(:emacs, key, func)
- config.add_default_key_binding_by_keymap(:vi_insert, key, func)
- end
- end
-
- if defined? JRUBY_VERSION
- require 'win32api'
- else
- class Win32API
- DLL = {}
- TYPEMAP = {"0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG}
- POINTER_TYPE = Fiddle::SIZEOF_VOIDP == Fiddle::SIZEOF_LONG_LONG ? 'q*' : 'l!*'
-
- WIN32_TYPES = "VPpNnLlIi"
- DL_TYPES = "0SSI"
-
- def initialize(dllname, func, import, export = "0", calltype = :stdcall)
- @proto = [import].join.tr(WIN32_TYPES, DL_TYPES).sub(/^(.)0*$/, '\1')
- import = @proto.chars.map {|win_type| TYPEMAP[win_type.tr(WIN32_TYPES, DL_TYPES)]}
- export = TYPEMAP[export.tr(WIN32_TYPES, DL_TYPES)]
- calltype = Fiddle::Importer.const_get(:CALL_TYPE_TO_ABI)[calltype]
-
- handle = DLL[dllname] ||=
- begin
- Fiddle.dlopen(dllname)
- rescue Fiddle::DLError
- raise unless File.extname(dllname).empty?
- Fiddle.dlopen(dllname + ".dll")
- end
-
- @func = Fiddle::Function.new(handle[func], import, export, calltype)
- rescue Fiddle::DLError => e
- raise LoadError, e.message, e.backtrace
- end
-
- def call(*args)
- import = @proto.split("")
- args.each_with_index do |x, i|
- args[i], = [x == 0 ? nil : +x].pack("p").unpack(POINTER_TYPE) if import[i] == "S"
- args[i], = [x].pack("I").unpack("i") if import[i] == "I"
- end
- ret, = @func.call(*args)
- return ret || 0
- end
- end
- end
-
- VK_RETURN = 0x0D
- VK_MENU = 0x12 # ALT key
- VK_LMENU = 0xA4
- VK_CONTROL = 0x11
- VK_SHIFT = 0x10
- VK_DIVIDE = 0x6F
-
- KEY_EVENT = 0x01
- WINDOW_BUFFER_SIZE_EVENT = 0x04
-
- CAPSLOCK_ON = 0x0080
- ENHANCED_KEY = 0x0100
- LEFT_ALT_PRESSED = 0x0002
- LEFT_CTRL_PRESSED = 0x0008
- NUMLOCK_ON = 0x0020
- RIGHT_ALT_PRESSED = 0x0001
- RIGHT_CTRL_PRESSED = 0x0004
- SCROLLLOCK_ON = 0x0040
- SHIFT_PRESSED = 0x0010
-
- VK_TAB = 0x09
- VK_END = 0x23
- VK_HOME = 0x24
- VK_LEFT = 0x25
- VK_UP = 0x26
- VK_RIGHT = 0x27
- VK_DOWN = 0x28
- VK_DELETE = 0x2E
-
- STD_INPUT_HANDLE = -10
- STD_OUTPUT_HANDLE = -11
- FILE_TYPE_PIPE = 0x0003
- FILE_NAME_INFO = 2
- ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
-
- # Calling Win32API with console handle is reported to fail after executing some external command.
- # We need to refresh console handle and retry the call again.
- private def call_with_console_handle(win32func, *args)
- val = win32func.call(@hConsoleHandle, *args)
- return val if val != 0
-
- @hConsoleHandle = @GetStdHandle.call(STD_OUTPUT_HANDLE)
- win32func.call(@hConsoleHandle, *args)
- end
-
- private def getconsolemode
- mode = "\000\000\000\000"
- call_with_console_handle(@GetConsoleMode, mode)
- mode.unpack1('L')
- end
-
- private def setconsolemode(mode)
- call_with_console_handle(@SetConsoleMode, mode)
- end
-
- #if @legacy_console
- # setconsolemode(getconsolemode() | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
- # @legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
- #end
-
- def msys_tty?(io = @hConsoleInputHandle)
- # check if fd is a pipe
- if @GetFileType.call(io) != FILE_TYPE_PIPE
- return false
- end
-
- bufsize = 1024
- p_buffer = "\0" * bufsize
- res = @GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2)
- return false if res == 0
-
- # get pipe name: p_buffer layout is:
- # struct _FILE_NAME_INFO {
- # DWORD FileNameLength;
- # WCHAR FileName[1];
- # } FILE_NAME_INFO
- len = p_buffer[0, 4].unpack1("L")
- name = p_buffer[4, len].encode(Encoding::UTF_8, Encoding::UTF_16LE, invalid: :replace)
-
- # Check if this could be a MSYS2 pty pipe ('\msys-XXXX-ptyN-XX')
- # or a cygwin pty pipe ('\cygwin-XXXX-ptyN-XX')
- name =~ /(msys-|cygwin-).*-pty/ ? true : false
- end
-
- KEY_MAP = [
- # It's treated as Meta+Enter on Windows.
- [ { control_keys: :CTRL, virtual_key_code: 0x0D }, "\e\r".bytes ],
- [ { control_keys: :SHIFT, virtual_key_code: 0x0D }, "\e\r".bytes ],
-
- # It's treated as Meta+Space on Windows.
- [ { control_keys: :CTRL, char_code: 0x20 }, "\e ".bytes ],
-
- # Emulate getwch() key sequences.
- [ { control_keys: [], virtual_key_code: VK_UP }, [0, 72] ],
- [ { control_keys: [], virtual_key_code: VK_DOWN }, [0, 80] ],
- [ { control_keys: [], virtual_key_code: VK_RIGHT }, [0, 77] ],
- [ { control_keys: [], virtual_key_code: VK_LEFT }, [0, 75] ],
- [ { control_keys: [], virtual_key_code: VK_DELETE }, [0, 83] ],
- [ { control_keys: [], virtual_key_code: VK_HOME }, [0, 71] ],
- [ { control_keys: [], virtual_key_code: VK_END }, [0, 79] ],
-
- # Emulate ANSI key sequence.
- [ { control_keys: :SHIFT, virtual_key_code: VK_TAB }, [27, 91, 90] ],
- ]
-
- def process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
-
- # high-surrogate
- if 0xD800 <= char_code and char_code <= 0xDBFF
- @hsg = char_code
- return
- end
- # low-surrogate
- if 0xDC00 <= char_code and char_code <= 0xDFFF
- if @hsg
- char_code = 0x10000 + (@hsg - 0xD800) * 0x400 + char_code - 0xDC00
- @hsg = nil
- else
- # no high-surrogate. ignored.
- return
- end
- else
- # ignore high-surrogate without low-surrogate if there
- @hsg = nil
- end
-
- key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state)
-
- match = KEY_MAP.find { |args,| key.match?(**args) }
- unless match.nil?
- @output_buf.concat(match.last)
- return
- end
-
- # no char, only control keys
- return if key.char_code == 0 and key.control_keys.any?
-
- @output_buf.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL)
-
- @output_buf.concat(key.char.bytes)
- end
-
- def check_input_event
- num_of_events = 0.chr * 8
- while @output_buf.empty?
- Reline.core.line_editor.handle_signal
- if @WaitForSingleObject.(@hConsoleInputHandle, 100) != 0 # max 0.1 sec
- # prevent for background consolemode change
- @legacy_console = getconsolemode & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0
- next
- end
- next if @GetNumberOfConsoleInputEvents.(@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0
- input_records = 0.chr * 20 * 80
- read_event = 0.chr * 4
- if @ReadConsoleInputW.(@hConsoleInputHandle, input_records, 80, read_event) != 0
- read_events = read_event.unpack1('L')
- 0.upto(read_events) do |idx|
- input_record = input_records[idx * 20, 20]
- event = input_record[0, 2].unpack1('s*')
- case event
- when WINDOW_BUFFER_SIZE_EVENT
- @winch_handler.()
- when KEY_EVENT
- key_down = input_record[4, 4].unpack1('l*')
- repeat_count = input_record[8, 2].unpack1('s*')
- virtual_key_code = input_record[10, 2].unpack1('s*')
- virtual_scan_code = input_record[12, 2].unpack1('s*')
- char_code = input_record[14, 2].unpack1('S*')
- control_key_state = input_record[16, 2].unpack1('S*')
- is_key_down = key_down.zero? ? false : true
- if is_key_down
- process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
- end
- end
- end
- end
- end
- end
-
- def with_raw_input
- yield
- end
-
- def getc(_timeout_second)
- check_input_event
- @output_buf.shift
- end
-
- def ungetc(c)
- @output_buf.unshift(c)
- end
-
- def in_pasting?
- not empty_buffer?
- end
-
- def empty_buffer?
- if not @output_buf.empty?
- false
- elsif @kbhit.call == 0
- true
- else
- false
- end
- end
-
- def get_console_screen_buffer_info
- # CONSOLE_SCREEN_BUFFER_INFO
- # [ 0,2] dwSize.X
- # [ 2,2] dwSize.Y
- # [ 4,2] dwCursorPositions.X
- # [ 6,2] dwCursorPositions.Y
- # [ 8,2] wAttributes
- # [10,2] srWindow.Left
- # [12,2] srWindow.Top
- # [14,2] srWindow.Right
- # [16,2] srWindow.Bottom
- # [18,2] dwMaximumWindowSize.X
- # [20,2] dwMaximumWindowSize.Y
- csbi = 0.chr * 22
- return if call_with_console_handle(@GetConsoleScreenBufferInfo, csbi) == 0
- csbi
- end
-
- def get_screen_size
- unless csbi = get_console_screen_buffer_info
- return [1, 1]
- end
- csbi[0, 4].unpack('SS').reverse
- end
-
- def cursor_pos
- unless csbi = get_console_screen_buffer_info
- return Reline::CursorPos.new(0, 0)
- end
- x = csbi[4, 2].unpack1('s')
- y = csbi[6, 2].unpack1('s')
- Reline::CursorPos.new(x, y)
- end
-
- def move_cursor_column(val)
- call_with_console_handle(@SetConsoleCursorPosition, cursor_pos.y * 65536 + val)
- end
-
- def move_cursor_up(val)
- if val > 0
- y = cursor_pos.y - val
- y = 0 if y < 0
- call_with_console_handle(@SetConsoleCursorPosition, y * 65536 + cursor_pos.x)
- elsif val < 0
- move_cursor_down(-val)
- end
- end
-
- def move_cursor_down(val)
- if val > 0
- return unless csbi = get_console_screen_buffer_info
- screen_height = get_screen_size.first
- y = cursor_pos.y + val
- y = screen_height - 1 if y > (screen_height - 1)
- call_with_console_handle(@SetConsoleCursorPosition, (cursor_pos.y + val) * 65536 + cursor_pos.x)
- elsif val < 0
- move_cursor_up(-val)
- end
- end
-
- def erase_after_cursor
- return unless csbi = get_console_screen_buffer_info
- attributes = csbi[8, 2].unpack1('S')
- cursor = csbi[4, 4].unpack1('L')
- written = 0.chr * 4
- call_with_console_handle(@FillConsoleOutputCharacter, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
- call_with_console_handle(@FillConsoleOutputAttribute, attributes, get_screen_size.last - cursor_pos.x, cursor, written)
- end
-
- def scroll_down(val)
- return if val < 0
- return unless csbi = get_console_screen_buffer_info
- buffer_width, buffer_lines, x, y, attributes, window_left, window_top, window_bottom = csbi.unpack('ssssSssx2s')
- screen_height = window_bottom - window_top + 1
- val = screen_height if val > screen_height
-
- if @legacy_console || window_left != 0
- # unless ENABLE_VIRTUAL_TERMINAL,
- # if srWindow.Left != 0 then it's conhost.exe hosted console
- # and puts "\n" causes horizontal scroll. its glitch.
- # FYI irb write from culumn 1, so this gives no gain.
- scroll_rectangle = [0, val, buffer_width, buffer_lines - val].pack('s4')
- destination_origin = 0 # y * 65536 + x
- fill = [' '.ord, attributes].pack('SS')
- call_with_console_handle(@ScrollConsoleScreenBuffer, scroll_rectangle, nil, destination_origin, fill)
- else
- origin_x = x + 1
- origin_y = y - window_top + 1
- @output.write [
- (origin_y != screen_height) ? "\e[#{screen_height};H" : nil,
- "\n" * val,
- (origin_y != screen_height or !x.zero?) ? "\e[#{origin_y};#{origin_x}H" : nil
- ].join
- end
- end
-
- def clear_screen
- if @legacy_console
- return unless csbi = get_console_screen_buffer_info
- buffer_width, _buffer_lines, attributes, window_top, window_bottom = csbi.unpack('ss@8S@12sx2s')
- fill_length = buffer_width * (window_bottom - window_top + 1)
- screen_topleft = window_top * 65536
- written = 0.chr * 4
- call_with_console_handle(@FillConsoleOutputCharacter, 0x20, fill_length, screen_topleft, written)
- call_with_console_handle(@FillConsoleOutputAttribute, attributes, fill_length, screen_topleft, written)
- call_with_console_handle(@SetConsoleCursorPosition, screen_topleft)
- else
- @output.write "\e[2J" "\e[H"
- end
- end
-
- def set_screen_size(rows, columns)
- raise NotImplementedError
- end
-
- def hide_cursor
- size = 100
- visible = 0 # 0 means false
- cursor_info = [size, visible].pack('Li')
- call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
- end
-
- def show_cursor
- size = 100
- visible = 1 # 1 means true
- cursor_info = [size, visible].pack('Li')
- call_with_console_handle(@SetConsoleCursorInfo, cursor_info)
- end
-
- def set_winch_handler(&handler)
- @winch_handler = handler
- end
-
- def prep
- # do nothing
- nil
- end
-
- def deprep(otio)
- # do nothing
- end
-
- class KeyEventRecord
-
- attr_reader :virtual_key_code, :char_code, :control_key_state, :control_keys
-
- def initialize(virtual_key_code, char_code, control_key_state)
- @virtual_key_code = virtual_key_code
- @char_code = char_code
- @control_key_state = control_key_state
- @enhanced = control_key_state & ENHANCED_KEY != 0
-
- (@control_keys = []).tap do |control_keys|
- # symbols must be sorted to make comparison is easier later on
- control_keys << :ALT if control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0
- control_keys << :CTRL if control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) != 0
- control_keys << :SHIFT if control_key_state & SHIFT_PRESSED != 0
- end.freeze
- end
-
- def char
- @char_code.chr(Encoding::UTF_8)
- end
-
- def enhanced?
- @enhanced
- end
-
- # Verifies if the arguments match with this key event.
- # Nil arguments are ignored, but at least one must be passed as non-nil.
- # To verify that no control keys were pressed, pass an empty array: `control_keys: []`.
- def match?(control_keys: nil, virtual_key_code: nil, char_code: nil)
- raise ArgumentError, 'No argument was passed to match key event' if control_keys.nil? && virtual_key_code.nil? && char_code.nil?
-
- (control_keys.nil? || [*control_keys].sort == @control_keys) &&
- (virtual_key_code.nil? || @virtual_key_code == virtual_key_code) &&
- (char_code.nil? || char_code == @char_code)
- end
-
- end
-end
diff --git a/lib/reline/key_actor.rb b/lib/reline/key_actor.rb
index 0ac7604556..ebe09d2009 100644
--- a/lib/reline/key_actor.rb
+++ b/lib/reline/key_actor.rb
@@ -2,7 +2,6 @@ module Reline::KeyActor
end
require 'reline/key_actor/base'
-require 'reline/key_actor/composite'
require 'reline/key_actor/emacs'
require 'reline/key_actor/vi_command'
require 'reline/key_actor/vi_insert'
diff --git a/lib/reline/key_actor/base.rb b/lib/reline/key_actor/base.rb
index ee28c7681e..a1cd7fb2a1 100644
--- a/lib/reline/key_actor/base.rb
+++ b/lib/reline/key_actor/base.rb
@@ -1,31 +1,19 @@
class Reline::KeyActor::Base
- def initialize(mapping = [])
- @mapping = mapping
- @matching_bytes = {}
- @key_bindings = {}
- end
+ MAPPING = Array.new(256)
def get_method(key)
- @mapping[key]
- end
-
- def add(key, func)
- (1...key.size).each do |size|
- @matching_bytes[key.take(size)] = true
- end
- @key_bindings[key] = func
+ self.class::MAPPING[key]
end
- def matching?(key)
- @matching_bytes[key]
+ def initialize
+ @default_key_bindings = {}
end
- def get(key)
- @key_bindings[key]
+ def default_key_bindings
+ @default_key_bindings
end
- def clear
- @matching_bytes.clear
- @key_bindings.clear
+ def reset_default_key_bindings
+ @default_key_bindings.clear
end
end
diff --git a/lib/reline/key_actor/composite.rb b/lib/reline/key_actor/composite.rb
deleted file mode 100644
index 37e94ce6cf..0000000000
--- a/lib/reline/key_actor/composite.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class Reline::KeyActor::Composite
- def initialize(key_actors)
- @key_actors = key_actors
- end
-
- def matching?(key)
- @key_actors.any? { |key_actor| key_actor.matching?(key) }
- end
-
- def get(key)
- @key_actors.each do |key_actor|
- func = key_actor.get(key)
- return func if func
- end
- nil
- end
-end
diff --git a/lib/reline/key_actor/emacs.rb b/lib/reline/key_actor/emacs.rb
index ad84ee1d99..a561feee57 100644
--- a/lib/reline/key_actor/emacs.rb
+++ b/lib/reline/key_actor/emacs.rb
@@ -1,5 +1,5 @@
-module Reline::KeyActor
- EMACS_MAPPING = [
+class Reline::KeyActor::Emacs < Reline::KeyActor::Base
+ MAPPING = [
# 0 ^@
:em_set_mark,
# 1 ^A
@@ -19,7 +19,7 @@ module Reline::KeyActor
# 8 ^H
:em_delete_prev_char,
# 9 ^I
- :complete,
+ :ed_unassigned,
# 10 ^J
:ed_newline,
# 11 ^K
@@ -49,13 +49,13 @@ module Reline::KeyActor
# 23 ^W
:em_kill_region,
# 24 ^X
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 25 ^Y
:em_yank,
# 26 ^Z
:ed_ignore,
# 27 ^[
- :ed_unassigned,
+ :em_meta_next,
# 28 ^\
:ed_ignore,
# 29 ^]
@@ -63,7 +63,7 @@ module Reline::KeyActor
# 30 ^^
:ed_unassigned,
# 31 ^_
- :undo,
+ :ed_unassigned,
# 32 SPACE
:ed_insert,
# 33 !
@@ -319,9 +319,9 @@ module Reline::KeyActor
# 158 M-^^
:ed_unassigned,
# 159 M-^_
- :redo,
+ :em_copy_prev_word,
# 160 M-SPACE
- :em_set_mark,
+ :ed_unassigned,
# 161 M-!
:ed_unassigned,
# 162 M-"
@@ -415,7 +415,7 @@ module Reline::KeyActor
# 206 M-N
:vi_search_next,
# 207 M-O
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 208 M-P
:vi_search_prev,
# 209 M-Q
@@ -431,15 +431,15 @@ module Reline::KeyActor
# 214 M-V
:ed_unassigned,
# 215 M-W
- :ed_unassigned,
+ :em_copy_region,
# 216 M-X
- :ed_unassigned,
+ :ed_command,
# 217 M-Y
- :em_yank_pop,
+ :ed_unassigned,
# 218 M-Z
:ed_unassigned,
# 219 M-[
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 220 M-\
:ed_unassigned,
# 221 M-]
@@ -495,9 +495,9 @@ module Reline::KeyActor
# 246 M-v
:ed_unassigned,
# 247 M-w
- :ed_unassigned,
+ :em_copy_region,
# 248 M-x
- :ed_unassigned,
+ :ed_command,
# 249 M-y
:ed_unassigned,
# 250 M-z
diff --git a/lib/reline/key_actor/vi_command.rb b/lib/reline/key_actor/vi_command.rb
index d972c5e67f..98146d2f77 100644
--- a/lib/reline/key_actor/vi_command.rb
+++ b/lib/reline/key_actor/vi_command.rb
@@ -1,5 +1,5 @@
-module Reline::KeyActor
- VI_COMMAND_MAPPING = [
+class Reline::KeyActor::ViCommand < Reline::KeyActor::Base
+ MAPPING = [
# 0 ^@
:ed_unassigned,
# 1 ^A
@@ -17,7 +17,7 @@ module Reline::KeyActor
# 7 ^G
:ed_unassigned,
# 8 ^H
- :ed_prev_char,
+ :ed_unassigned,
# 9 ^I
:ed_unassigned,
# 10 ^J
@@ -41,7 +41,7 @@ module Reline::KeyActor
# 19 ^S
:ed_ignore,
# 20 ^T
- :ed_transpose_chars,
+ :ed_unassigned,
# 21 ^U
:vi_kill_line_prev,
# 22 ^V
@@ -51,7 +51,7 @@ module Reline::KeyActor
# 24 ^X
:ed_unassigned,
# 25 ^Y
- :em_yank,
+ :ed_unassigned,
# 26 ^Z
:ed_unassigned,
# 27 ^[
@@ -75,7 +75,7 @@ module Reline::KeyActor
# 36 $
:ed_move_to_end,
# 37 %
- :ed_unassigned,
+ :vi_match,
# 38 &
:ed_unassigned,
# 39 '
@@ -89,11 +89,11 @@ module Reline::KeyActor
# 43 +
:ed_next_history,
# 44 ,
- :ed_unassigned,
+ :vi_repeat_prev_char,
# 45 -
:ed_prev_history,
# 46 .
- :ed_unassigned,
+ :vi_redo,
# 47 /
:vi_search_prev,
# 48 0
@@ -117,9 +117,9 @@ module Reline::KeyActor
# 57 9
:ed_argument_digit,
# 58 :
- :ed_unassigned,
+ :ed_command,
# 59 ;
- :ed_unassigned,
+ :vi_repeat_next_char,
# 60 <
:ed_unassigned,
# 61 =
@@ -157,21 +157,21 @@ module Reline::KeyActor
# 77 M
:ed_unassigned,
# 78 N
- :ed_unassigned,
+ :vi_repeat_search_prev,
# 79 O
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 80 P
:vi_paste_prev,
# 81 Q
:ed_unassigned,
# 82 R
- :ed_unassigned,
+ :vi_replace_mode,
# 83 S
- :ed_unassigned,
+ :vi_substitute_line,
# 84 T
:vi_to_prev_char,
# 85 U
- :ed_unassigned,
+ :vi_undo_line,
# 86 V
:ed_unassigned,
# 87 W
@@ -179,11 +179,11 @@ module Reline::KeyActor
# 88 X
:ed_delete_prev_char,
# 89 Y
- :ed_unassigned,
+ :vi_yank_end,
# 90 Z
:ed_unassigned,
# 91 [
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 92 \
:ed_unassigned,
# 93 ]
@@ -191,7 +191,7 @@ module Reline::KeyActor
# 94 ^
:vi_first_print,
# 95 _
- :ed_unassigned,
+ :vi_history_word,
# 96 `
:ed_unassigned,
# 97 a
@@ -221,7 +221,7 @@ module Reline::KeyActor
# 109 m
:ed_unassigned,
# 110 n
- :ed_unassigned,
+ :vi_repeat_search_next,
# 111 o
:ed_unassigned,
# 112 p
@@ -231,11 +231,11 @@ module Reline::KeyActor
# 114 r
:vi_replace_char,
# 115 s
- :ed_unassigned,
+ :vi_substitute_char,
# 116 t
:vi_to_next_char,
# 117 u
- :ed_unassigned,
+ :vi_undo,
# 118 v
:vi_histedit,
# 119 w
@@ -253,9 +253,9 @@ module Reline::KeyActor
# 125 }
:ed_unassigned,
# 126 ~
- :ed_unassigned,
+ :vi_change_case,
# 127 ^?
- :em_delete_prev_char,
+ :ed_unassigned,
# 128 M-^@
:ed_unassigned,
# 129 M-^A
@@ -415,7 +415,7 @@ module Reline::KeyActor
# 206 M-N
:ed_unassigned,
# 207 M-O
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 208 M-P
:ed_unassigned,
# 209 M-Q
@@ -439,7 +439,7 @@ module Reline::KeyActor
# 218 M-Z
:ed_unassigned,
# 219 M-[
- :ed_unassigned,
+ :ed_sequence_lead_in,
# 220 M-\
:ed_unassigned,
# 221 M-]
diff --git a/lib/reline/key_actor/vi_insert.rb b/lib/reline/key_actor/vi_insert.rb
index 312df1646b..b8e89f81d8 100644
--- a/lib/reline/key_actor/vi_insert.rb
+++ b/lib/reline/key_actor/vi_insert.rb
@@ -1,5 +1,5 @@
-module Reline::KeyActor
- VI_INSERT_MAPPING = [
+class Reline::KeyActor::ViInsert < Reline::KeyActor::Base
+ MAPPING = [
# 0 ^@
:ed_unassigned,
# 1 ^A
@@ -19,7 +19,7 @@ module Reline::KeyActor
# 8 ^H
:vi_delete_prev_char,
# 9 ^I
- :complete,
+ :ed_insert,
# 10 ^J
:ed_newline,
# 11 ^K
@@ -29,11 +29,11 @@ module Reline::KeyActor
# 13 ^M
:ed_newline,
# 14 ^N
- :menu_complete,
+ :ed_insert,
# 15 ^O
:ed_insert,
# 16 ^P
- :menu_complete_backward,
+ :ed_insert,
# 17 ^Q
:ed_ignore,
# 18 ^R
@@ -41,7 +41,7 @@ module Reline::KeyActor
# 19 ^S
:vi_search_next,
# 20 ^T
- :ed_transpose_chars,
+ :ed_insert,
# 21 ^U
:vi_kill_line_prev,
# 22 ^V
@@ -51,7 +51,7 @@ module Reline::KeyActor
# 24 ^X
:ed_insert,
# 25 ^Y
- :em_yank,
+ :ed_insert,
# 26 ^Z
:ed_insert,
# 27 ^[
diff --git a/lib/reline/key_stroke.rb b/lib/reline/key_stroke.rb
index ba40899685..c1c61513a9 100644
--- a/lib/reline/key_stroke.rb
+++ b/lib/reline/key_stroke.rb
@@ -1,108 +1,104 @@
class Reline::KeyStroke
- ESC_BYTE = 27
- CSI_PARAMETER_BYTES_RANGE = 0x30..0x3f
- CSI_INTERMEDIATE_BYTES_RANGE = (0x20..0x2f)
-
def initialize(config)
@config = config
end
- # Input exactly matches to a key sequence
- MATCHING = :matching
- # Input partially matches to a key sequence
- MATCHED = :matched
- # Input matches to a key sequence and the key sequence is a prefix of another key sequence
- MATCHING_MATCHED = :matching_matched
- # Input does not match to any key sequence
- UNMATCHED = :unmatched
-
- def match_status(input)
- matching = key_mapping.matching?(input)
- matched = key_mapping.get(input)
-
- # FIXME: Workaround for single byte. remove this after MAPPING is merged into KeyActor.
- matched ||= input.size == 1
- matching ||= input == [ESC_BYTE]
-
- if matching && matched
- MATCHING_MATCHED
- elsif matching
- MATCHING
- elsif matched
- MATCHED
- elsif input[0] == ESC_BYTE
- match_unknown_escape_sequence(input, vi_mode: @config.editing_mode_is?(:vi_insert, :vi_command))
- elsif input.size == 1
- MATCHED
- else
- UNMATCHED
- end
+ def compress_meta_key(ary)
+ return ary unless @config.convert_meta
+ ary.inject([]) { |result, key|
+ if result.size > 0 and result.last == "\e".ord
+ result[result.size - 1] = Reline::Key.new(key, key | 0b10000000, true)
+ else
+ result << key
+ end
+ result
+ }
end
- def expand(input)
- matched_bytes = nil
- (1..input.size).each do |i|
- bytes = input.take(i)
- status = match_status(bytes)
- matched_bytes = bytes if status == MATCHED || status == MATCHING_MATCHED
+ def start_with?(me, other)
+ compressed_me = compress_meta_key(me)
+ compressed_other = compress_meta_key(other)
+ i = 0
+ loop do
+ my_c = compressed_me[i]
+ other_c = compressed_other[i]
+ other_is_last = (i + 1) == compressed_other.size
+ me_is_last = (i + 1) == compressed_me.size
+ if my_c != other_c
+ if other_c == "\e".ord and other_is_last and my_c.is_a?(Reline::Key) and my_c.with_meta
+ return true
+ else
+ return false
+ end
+ elsif other_is_last
+ return true
+ elsif me_is_last
+ return false
+ end
+ i += 1
end
- return [[], []] unless matched_bytes
+ end
- func = key_mapping.get(matched_bytes)
- if func.is_a?(Array)
- keys = func.map { |c| Reline::Key.new(c, c, false) }
- elsif func
- keys = [Reline::Key.new(func, func, false)]
- elsif matched_bytes.size == 1
- keys = [Reline::Key.new(matched_bytes.first, matched_bytes.first, false)]
- elsif matched_bytes.size == 2 && matched_bytes[0] == ESC_BYTE
- keys = [Reline::Key.new(matched_bytes[1], matched_bytes[1] | 0b10000000, true)]
- else
- keys = []
+ def equal?(me, other)
+ case me
+ when Array
+ compressed_me = compress_meta_key(me)
+ compressed_other = compress_meta_key(other)
+ compressed_me.size == compressed_other.size and [compressed_me, compressed_other].transpose.all?{ |i| equal?(i[0], i[1]) }
+ when Integer
+ if other.is_a?(Reline::Key)
+ if other.combined_char == "\e".ord
+ false
+ else
+ other.combined_char == me
+ end
+ else
+ me == other
+ end
+ when Reline::Key
+ if other.is_a?(Integer)
+ me.combined_char == other
+ else
+ me == other
+ end
end
-
- [keys, input.drop(matched_bytes.size)]
end
- private
-
- # returns match status of CSI/SS3 sequence and matched length
- def match_unknown_escape_sequence(input, vi_mode: false)
- idx = 0
- return UNMATCHED unless input[idx] == ESC_BYTE
- idx += 1
- idx += 1 if input[idx] == ESC_BYTE
+ def match_status(input)
+ key_mapping.keys.select { |lhs|
+ start_with?(lhs, input)
+ }.tap { |it|
+ return :matched if it.size == 1 && equal?(it[0], input)
+ return :matching if it.size == 1 && !equal?(it[0], input)
+ return :matched if it.max_by(&:size)&.size&.< input.size
+ return :matching if it.size > 1
+ }
+ key_mapping.keys.select { |lhs|
+ start_with?(input, lhs)
+ }.tap { |it|
+ return it.size > 0 ? :matched : :unmatched
+ }
+ end
- case input[idx]
- when nil
- if idx == 1 # `ESC`
- return MATCHING_MATCHED
- else # `ESC ESC`
- return MATCHING
- end
- when 91 # == '['.ord
- # CSI sequence `ESC [ ... char`
- idx += 1
- idx += 1 while idx < input.size && CSI_PARAMETER_BYTES_RANGE.cover?(input[idx])
- idx += 1 while idx < input.size && CSI_INTERMEDIATE_BYTES_RANGE.cover?(input[idx])
- when 79 # == 'O'.ord
- # SS3 sequence `ESC O char`
- idx += 1
- else
- # `ESC char` or `ESC ESC char`
- return UNMATCHED if vi_mode
- end
+ def expand(input)
+ input = compress_meta_key(input)
+ lhs = key_mapping.keys.select { |item| start_with?(input, item) }.sort_by(&:size).last
+ return input unless lhs
+ rhs = key_mapping[lhs]
- case input.size
- when idx
- MATCHING
- when idx + 1
- MATCHED
- else
- UNMATCHED
+ case rhs
+ when String
+ rhs_bytes = rhs.bytes
+ expand(expand(rhs_bytes) + expand(input.drop(lhs.size)))
+ when Symbol
+ [rhs] + expand(input.drop(lhs.size))
+ when Array
+ rhs
end
end
+ private
+
def key_mapping
@config.key_bindings
end
diff --git a/lib/reline/kill_ring.rb b/lib/reline/kill_ring.rb
index 201f6f3ca0..bb3684b42b 100644
--- a/lib/reline/kill_ring.rb
+++ b/lib/reline/kill_ring.rb
@@ -14,7 +14,7 @@ class Reline::KillRing
end
def ==(other)
- equal?(other)
+ object_id == other.object_id
end
end
@@ -68,7 +68,7 @@ class Reline::KillRing
def append(string, before_p = false)
case @state
when State::FRESH, State::YANK
- @ring << RingPoint.new(+string)
+ @ring << RingPoint.new(string)
@state = State::CONTINUED
when State::CONTINUED, State::PROCESSED
if before_p
diff --git a/lib/reline/line_editor.rb b/lib/reline/line_editor.rb
index b815659713..8153aaba05 100644
--- a/lib/reline/line_editor.rb
+++ b/lib/reline/line_editor.rb
@@ -4,7 +4,9 @@ require 'reline/unicode'
require 'tempfile'
class Reline::LineEditor
+ # TODO: undo
# TODO: Use "private alias_method" idiom after drop Ruby 2.5.
+ attr_reader :line
attr_reader :byte_pointer
attr_accessor :confirm_multiline_termination_proc
attr_accessor :completion_proc
@@ -12,6 +14,7 @@ class Reline::LineEditor
attr_accessor :output_modifier_proc
attr_accessor :prompt_proc
attr_accessor :auto_indent_proc
+ attr_accessor :pre_input_hook
attr_accessor :dig_perfect_match_proc
attr_writer :output
@@ -32,94 +35,98 @@ class Reline::LineEditor
vi_next_big_word
vi_prev_big_word
vi_end_big_word
+ vi_repeat_next_char
+ vi_repeat_prev_char
}
module CompletionState
NORMAL = :normal
COMPLETION = :completion
MENU = :menu
+ JOURNEY = :journey
MENU_WITH_PERFECT_MATCH = :menu_with_perfect_match
PERFECT_MATCH = :perfect_match
end
- RenderedScreen = Struct.new(:base_y, :lines, :cursor_y, keyword_init: true)
+ CompletionJourneyData = Struct.new('CompletionJourneyData', :preposing, :postposing, :list, :pointer)
+ MenuInfo = Struct.new('MenuInfo', :target, :list)
- CompletionJourneyState = Struct.new(:line_index, :pre, :target, :post, :list, :pointer)
- NullActionState = [nil, nil].freeze
-
- class MenuInfo
- attr_reader :list
-
- def initialize(list)
- @list = list
- end
-
- def lines(screen_width)
- return [] if @list.empty?
-
- list = @list.sort
- sizes = list.map { |item| Reline::Unicode.calculate_width(item) }
- item_width = sizes.max + 2
- num_cols = [screen_width / item_width, 1].max
- num_rows = list.size.fdiv(num_cols).ceil
- list_with_padding = list.zip(sizes).map { |item, size| item + ' ' * (item_width - size) }
- aligned = (list_with_padding + [nil] * (num_rows * num_cols - list_with_padding.size)).each_slice(num_rows).to_a.transpose
- aligned.map do |row|
- row.join.rstrip
- end
- end
- end
-
- MINIMUM_SCROLLBAR_HEIGHT = 1
+ PROMPT_LIST_CACHE_TIMEOUT = 0.5
def initialize(config, encoding)
@config = config
@completion_append_character = ''
- @screen_size = [0, 0] # Should be initialized with actual winsize in LineEditor#reset
reset_variables(encoding: encoding)
end
- def io_gate
- Reline::IOGate
- end
-
def set_pasting_state(in_pasting)
- # While pasting, text to be inserted is stored to @continuous_insertion_buffer.
- # After pasting, this buffer should be force inserted.
- process_insert(force: true) if @in_pasting && !in_pasting
@in_pasting = in_pasting
end
+ def simplified_rendering?
+ if finished?
+ false
+ elsif @just_cursor_moving and not @rerender_all
+ true
+ else
+ not @rerender_all and not finished? and @in_pasting
+ end
+ end
+
private def check_mode_string
+ mode_string = nil
if @config.show_mode_in_prompt
if @config.editing_mode_is?(:vi_command)
- @config.vi_cmd_mode_string
+ mode_string = @config.vi_cmd_mode_string
elsif @config.editing_mode_is?(:vi_insert)
- @config.vi_ins_mode_string
+ mode_string = @config.vi_ins_mode_string
elsif @config.editing_mode_is?(:emacs)
- @config.emacs_mode_string
+ mode_string = @config.emacs_mode_string
else
- '?'
+ mode_string = '?'
end
end
+ if mode_string != @prev_mode_string
+ @rerender_all = true
+ end
+ @prev_mode_string = mode_string
+ mode_string
end
- private def check_multiline_prompt(buffer, mode_string)
+ private def check_multiline_prompt(buffer)
if @vi_arg
prompt = "(arg: #{@vi_arg}) "
+ @rerender_all = true
elsif @searching_prompt
prompt = @searching_prompt
+ @rerender_all = true
else
prompt = @prompt
end
- if !@is_multiline
+ if simplified_rendering?
mode_string = check_mode_string
prompt = mode_string + prompt if mode_string
- [prompt] + [''] * (buffer.size - 1)
- elsif @prompt_proc
- prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") }
+ return [prompt, calculate_width(prompt, true), [prompt] * buffer.size]
+ end
+ if @prompt_proc
+ use_cached_prompt_list = false
+ if @cached_prompt_list
+ if @just_cursor_moving
+ use_cached_prompt_list = true
+ elsif Time.now.to_f < (@prompt_cache_time + PROMPT_LIST_CACHE_TIMEOUT) and buffer.size == @cached_prompt_list.size
+ use_cached_prompt_list = true
+ end
+ end
+ use_cached_prompt_list = false if @rerender_all
+ if use_cached_prompt_list
+ prompt_list = @cached_prompt_list
+ else
+ prompt_list = @cached_prompt_list = @prompt_proc.(buffer).map { |pr| pr.gsub("\n", "\\n") }
+ @prompt_cache_time = Time.now.to_f
+ end
prompt_list.map!{ prompt } if @vi_arg or @searching_prompt
prompt_list = [prompt] if prompt_list.empty?
+ mode_string = check_mode_string
prompt_list = prompt_list.map{ |pr| mode_string + pr } if mode_string
prompt = prompt_list[@line_index]
prompt = prompt_list[0] if prompt.nil?
@@ -129,17 +136,24 @@ class Reline::LineEditor
prompt_list << prompt_list.last
end
end
- prompt_list
+ prompt_width = calculate_width(prompt, true)
+ [prompt, prompt_width, prompt_list]
else
+ mode_string = check_mode_string
prompt = mode_string + prompt if mode_string
- [prompt] * buffer.size
+ prompt_width = calculate_width(prompt, true)
+ [prompt, prompt_width, nil]
end
end
def reset(prompt = '', encoding:)
+ @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
@screen_size = Reline::IOGate.get_screen_size
+ @screen_height = @screen_size.first
reset_variables(prompt, encoding: encoding)
- @rendered_screen.base_y = Reline::IOGate.cursor_pos.y
+ Reline::IOGate.set_winch_handler do
+ @resized = true
+ end
if ENV.key?('RELINE_ALT_SCROLLBAR')
@full_block = '::'
@upper_half_block = "''"
@@ -163,56 +177,82 @@ class Reline::LineEditor
end
end
- def handle_signal
- handle_interrupted
- handle_resized
- end
-
- private def handle_resized
+ def resize
return unless @resized
-
- @screen_size = Reline::IOGate.get_screen_size
@resized = false
- scroll_into_view
- Reline::IOGate.move_cursor_up @rendered_screen.cursor_y
- @rendered_screen.base_y = Reline::IOGate.cursor_pos.y
- clear_rendered_screen_cache
- render
- end
-
- private def handle_interrupted
- return unless @interrupted
-
- @interrupted = false
- clear_dialogs
- render
- cursor_to_bottom_offset = @rendered_screen.lines.size - @rendered_screen.cursor_y
- Reline::IOGate.scroll_down cursor_to_bottom_offset
- Reline::IOGate.move_cursor_column 0
- clear_rendered_screen_cache
- case @old_trap
- when 'DEFAULT', 'SYSTEM_DEFAULT'
- raise Interrupt
- when 'IGNORE'
- # Do nothing
- when 'EXIT'
- exit
+ @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
+ old_screen_size = @screen_size
+ @screen_size = Reline::IOGate.get_screen_size
+ @screen_height = @screen_size.first
+ if old_screen_size.last < @screen_size.last # columns increase
+ @rerender_all = true
+ rerender
else
- @old_trap.call if @old_trap.respond_to?(:call)
+ back = 0
+ new_buffer = whole_lines
+ prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer)
+ new_buffer.each_with_index do |line, index|
+ prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
+ width = prompt_width + calculate_width(line)
+ height = calculate_height_by_width(width)
+ back += height
+ end
+ @highest_in_all = back
+ @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
+ @first_line_started_from =
+ if @line_index.zero?
+ 0
+ else
+ calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
+ end
+ if @prompt_proc
+ prompt = prompt_list[@line_index]
+ prompt_width = calculate_width(prompt, true)
+ end
+ calculate_nearest_cursor
+ @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
+ @rerender_all = true
end
end
def set_signal_handlers
- Reline::IOGate.set_winch_handler do
- @resized = true
- end
- @old_trap = Signal.trap('INT') do
- @interrupted = true
+ @old_trap = Signal.trap('INT') {
+ clear_dialog
+ if @scroll_partial_screen
+ move_cursor_down(@screen_height - (@line_index - @scroll_partial_screen) - 1)
+ else
+ move_cursor_down(@highest_in_all - @line_index - 1)
+ end
+ Reline::IOGate.move_cursor_column(0)
+ scroll_down(1)
+ case @old_trap
+ when 'DEFAULT', 'SYSTEM_DEFAULT'
+ raise Interrupt
+ when 'IGNORE'
+ # Do nothing
+ when 'EXIT'
+ exit
+ else
+ @old_trap.call if @old_trap.respond_to?(:call)
+ end
+ }
+ begin
+ @old_tstp_trap = Signal.trap('TSTP') {
+ Reline::IOGate.ungetc("\C-z".ord)
+ @old_tstp_trap.call if @old_tstp_trap.respond_to?(:call)
+ }
+ rescue ArgumentError
end
end
def finalize
Signal.trap('INT', @old_trap)
+ begin
+ Signal.trap('TSTP', @old_tstp_trap)
+ rescue ArgumentError
+ end
end
def eof?
@@ -225,45 +265,55 @@ class Reline::LineEditor
@encoding = encoding
@is_multiline = false
@finished = false
+ @cleared = false
+ @rerender_all = false
@history_pointer = nil
@kill_ring ||= Reline::KillRing.new
@vi_clipboard = ''
@vi_arg = nil
@waiting_proc = nil
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- @completion_journey_state = nil
+ @waiting_operator_proc = nil
+ @waiting_operator_vi_arg = nil
+ @completion_journey_data = nil
@completion_state = CompletionState::NORMAL
@perfect_matched = nil
@menu_info = nil
+ @first_prompt = true
@searching_prompt = nil
- @just_cursor_moving = false
+ @first_char = true
+ @add_newline_to_end_of_buffer = false
+ @just_cursor_moving = nil
+ @cached_prompt_list = nil
+ @prompt_cache_time = nil
@eof = false
@continuous_insertion_buffer = String.new(encoding: @encoding)
- @scroll_partial_screen = 0
+ @scroll_partial_screen = nil
+ @prev_mode_string = nil
@drop_terminate_spaces = false
@in_pasting = false
@auto_indent_proc = nil
@dialogs = []
- @interrupted = false
+ @last_key = nil
@resized = false
- @cache = {}
- @rendered_screen = RenderedScreen.new(base_y: 0, lines: [], cursor_y: 0)
- @input_lines = [[[""], 0, 0]]
- @input_lines_position = 0
- @undoing = false
- @prev_action_state = NullActionState
- @next_action_state = NullActionState
reset_line
end
def reset_line
+ @cursor = 0
+ @cursor_max = 0
@byte_pointer = 0
@buffer_of_lines = [String.new(encoding: @encoding)]
@line_index = 0
- @cache.clear
+ @previous_line_index = nil
+ @line = @buffer_of_lines[0]
+ @first_line_started_from = 0
+ @move_up = 0
+ @started_from = 0
+ @highest_in_this = 1
+ @highest_in_all = 1
@line_backup_in_history = nil
@multibyte_buffer = String.new(encoding: 'ASCII-8BIT')
+ @check_new_auto_indent = false
end
def multiline_on
@@ -274,44 +324,68 @@ class Reline::LineEditor
@is_multiline = false
end
+ private def calculate_height_by_lines(lines, prompt)
+ result = 0
+ prompt_list = prompt.is_a?(Array) ? prompt : nil
+ lines.each_with_index { |line, i|
+ prompt = prompt_list[i] if prompt_list and prompt_list[i]
+ result += calculate_height_by_width(calculate_width(prompt, true) + calculate_width(line))
+ }
+ result
+ end
+
private def insert_new_line(cursor_line, next_line)
+ @line = cursor_line
@buffer_of_lines.insert(@line_index + 1, String.new(next_line, encoding: @encoding))
- @buffer_of_lines[@line_index] = cursor_line
+ @previous_line_index = @line_index
@line_index += 1
- @byte_pointer = 0
- if @auto_indent_proc && !@in_pasting
- if next_line.empty?
- (
- # For compatibility, use this calculation instead of just `process_auto_indent @line_index - 1, cursor_dependent: false`
- indent1 = @auto_indent_proc.(@buffer_of_lines.take(@line_index - 1).push(''), @line_index - 1, 0, true)
- indent2 = @auto_indent_proc.(@buffer_of_lines.take(@line_index), @line_index - 1, @buffer_of_lines[@line_index - 1].bytesize, false)
- indent = indent2 || indent1
- @buffer_of_lines[@line_index - 1] = ' ' * indent + @buffer_of_lines[@line_index - 1].gsub(/\A\s*/, '')
- )
- process_auto_indent @line_index, add_newline: true
- else
- process_auto_indent @line_index - 1, cursor_dependent: false
- process_auto_indent @line_index, add_newline: true # Need for compatibility
- process_auto_indent @line_index, cursor_dependent: false
- end
+ @just_cursor_moving = false
+ end
+
+ private def calculate_height_by_width(width)
+ width.div(@screen_size.last) + 1
+ end
+
+ private def split_by_width(str, max_width)
+ Reline::Unicode.split_by_width(str, max_width, @encoding)
+ end
+
+ private def scroll_down(val)
+ if val <= @rest_height
+ Reline::IOGate.move_cursor_down(val)
+ @rest_height -= val
+ else
+ Reline::IOGate.move_cursor_down(@rest_height)
+ Reline::IOGate.scroll_down(val - @rest_height)
+ @rest_height = 0
end
end
- private def split_by_width(str, max_width, offset: 0)
- Reline::Unicode.split_by_width(str, max_width, @encoding, offset: offset)
+ private def move_cursor_up(val)
+ if val > 0
+ Reline::IOGate.move_cursor_up(val)
+ @rest_height += val
+ elsif val < 0
+ move_cursor_down(-val)
+ end
end
- def current_byte_pointer_cursor
- calculate_width(current_line.byteslice(0, @byte_pointer))
+ private def move_cursor_down(val)
+ if val > 0
+ Reline::IOGate.move_cursor_down(val)
+ @rest_height -= val
+ @rest_height = 0 if @rest_height < 0
+ elsif val < 0
+ move_cursor_up(-val)
+ end
end
- private def calculate_nearest_cursor(cursor)
- line_to_calc = current_line
+ private def calculate_nearest_cursor(line_to_calc = @line, cursor = @cursor, started_from = @started_from, byte_pointer = @byte_pointer, update = true)
new_cursor_max = calculate_width(line_to_calc)
new_cursor = 0
new_byte_pointer = 0
height = 1
- max_width = screen_width
+ max_width = @screen_size.last
if @config.editing_mode_is?(:vi_command)
last_byte_size = Reline::Unicode.get_prev_mbchar_size(line_to_calc, line_to_calc.bytesize)
if last_byte_size > 0
@@ -337,227 +411,120 @@ class Reline::LineEditor
end
new_byte_pointer += gc.bytesize
end
- @byte_pointer = new_byte_pointer
- end
-
- def with_cache(key, *deps)
- cached_deps, value = @cache[key]
- if cached_deps != deps
- @cache[key] = [deps, value = yield(*deps, cached_deps, value)]
+ new_started_from = height - 1
+ if update
+ @cursor = new_cursor
+ @cursor_max = new_cursor_max
+ @started_from = new_started_from
+ @byte_pointer = new_byte_pointer
+ else
+ [new_cursor, new_cursor_max, new_started_from, new_byte_pointer]
end
- value
end
- def modified_lines
- with_cache(__method__, whole_lines, finished?) do |whole, complete|
- modify_lines(whole, complete)
- end
+ def rerender_all
+ @rerender_all = true
+ process_insert(force: true)
+ rerender
end
- def prompt_list
- with_cache(__method__, whole_lines, check_mode_string, @vi_arg, @searching_prompt) do |lines, mode_string|
- check_multiline_prompt(lines, mode_string)
+ def rerender
+ return if @line.nil?
+ if @menu_info
+ scroll_down(@highest_in_all - @first_line_started_from)
+ @rerender_all = true
end
- end
-
- def screen_height
- @screen_size.first
- end
-
- def screen_width
- @screen_size.last
- end
-
- def screen_scroll_top
- @scroll_partial_screen
- end
-
- def wrapped_prompt_and_input_lines
- with_cache(__method__, @buffer_of_lines.size, modified_lines, prompt_list, screen_width) do |n, lines, prompts, width, prev_cache_key, cached_value|
- prev_n, prev_lines, prev_prompts, prev_width = prev_cache_key
- cached_wraps = {}
- if prev_width == width
- prev_n.times do |i|
- cached_wraps[[prev_prompts[i], prev_lines[i]]] = cached_value[i]
- end
- end
-
- n.times.map do |i|
- prompt = prompts[i] || ''
- line = lines[i] || ''
- if (cached = cached_wraps[[prompt, line]])
- next cached
- end
- *wrapped_prompts, code_line_prompt = split_by_width(prompt, width).first.compact
- wrapped_lines = split_by_width(line, width, offset: calculate_width(code_line_prompt, true)).first.compact
- wrapped_prompts.map { |p| [p, ''] } + [[code_line_prompt, wrapped_lines.first]] + wrapped_lines.drop(1).map { |c| ['', c] }
- end
+ if @menu_info
+ show_menu
+ @menu_info = nil
end
- end
-
- def calculate_overlay_levels(overlay_levels)
- levels = []
- overlay_levels.each do |x, w, l|
- levels.fill(l, x, w)
+ prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
+ if @cleared
+ clear_screen_buffer(prompt, prompt_list, prompt_width)
+ @cleared = false
+ return
end
- levels
- end
-
- def render_line_differential(old_items, new_items)
- old_levels = calculate_overlay_levels(old_items.zip(new_items).each_with_index.map {|((x, w, c), (nx, _nw, nc)), i| [x, w, c == nc && x == nx ? i : -1] if x }.compact)
- new_levels = calculate_overlay_levels(new_items.each_with_index.map { |(x, w), i| [x, w, i] if x }.compact).take(screen_width)
- base_x = 0
- new_levels.zip(old_levels).chunk { |n, o| n == o ? :skip : n || :blank }.each do |level, chunk|
- width = chunk.size
- if level == :skip
- # do nothing
- elsif level == :blank
- Reline::IOGate.move_cursor_column base_x
- @output.write "#{Reline::IOGate.reset_color_sequence}#{' ' * width}"
+ if @is_multiline and finished? and @scroll_partial_screen
+ # Re-output all code higher than the screen when finished.
+ Reline::IOGate.move_cursor_up(@first_line_started_from + @started_from - @scroll_partial_screen)
+ Reline::IOGate.move_cursor_column(0)
+ @scroll_partial_screen = nil
+ prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
+ if @previous_line_index
+ new_lines = whole_lines(index: @previous_line_index, line: @line)
else
- x, w, content = new_items[level]
- cover_begin = base_x != 0 && new_levels[base_x - 1] == level
- cover_end = new_levels[base_x + width] == level
- pos = 0
- unless x == base_x && w == width
- content, pos = Reline::Unicode.take_mbchar_range(content, base_x - x, width, cover_begin: cover_begin, cover_end: cover_end, padding: true)
- end
- Reline::IOGate.move_cursor_column x + pos
- @output.write "#{Reline::IOGate.reset_color_sequence}#{content}#{Reline::IOGate.reset_color_sequence}"
+ new_lines = whole_lines
end
- base_x += width
- end
- if old_levels.size > new_levels.size
- Reline::IOGate.move_cursor_column new_levels.size
- Reline::IOGate.erase_after_cursor
- end
- end
-
- # Calculate cursor position in word wrapped content.
- def wrapped_cursor_position
- prompt_width = calculate_width(prompt_list[@line_index], true)
- line_before_cursor = whole_lines[@line_index].byteslice(0, @byte_pointer)
- wrapped_line_before_cursor = split_by_width(' ' * prompt_width + line_before_cursor, screen_width).first.compact
- wrapped_cursor_y = wrapped_prompt_and_input_lines[0...@line_index].sum(&:size) + wrapped_line_before_cursor.size - 1
- wrapped_cursor_x = calculate_width(wrapped_line_before_cursor.last)
- [wrapped_cursor_x, wrapped_cursor_y]
- end
-
- def clear_dialogs
- @dialogs.each do |dialog|
- dialog.contents = nil
- dialog.trap_key = nil
- end
- end
-
- def update_dialogs(key = nil)
- wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
- @dialogs.each do |dialog|
- dialog.trap_key = nil
- update_each_dialog(dialog, wrapped_cursor_x, wrapped_cursor_y - screen_scroll_top, key)
- end
- end
-
- def render_finished
- render_differential([], 0, 0)
- lines = @buffer_of_lines.size.times.map do |i|
- line = prompt_list[i] + modified_lines[i]
- wrapped_lines, = split_by_width(line, screen_width)
- wrapped_lines.last.empty? ? "#{line} " : line
- end
- @output.puts lines.map { |l| "#{l}\r\n" }.join
- end
-
- def print_nomultiline_prompt
- # Readline's test `TestRelineAsReadline#test_readline` requires first output to be prompt, not cursor reset escape sequence.
- @output.write @prompt if @prompt && !@is_multiline
- end
-
- def render
- wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
- new_lines = wrapped_prompt_and_input_lines.flatten(1)[screen_scroll_top, screen_height].map do |prompt, line|
- prompt_width = Reline::Unicode.calculate_width(prompt, true)
- [[0, prompt_width, prompt], [prompt_width, Reline::Unicode.calculate_width(line, true), line]]
- end
- if @menu_info
- @menu_info.lines(screen_width).each do |item|
- new_lines << [[0, Reline::Unicode.calculate_width(item), item]]
+ modify_lines(new_lines).each_with_index do |line, index|
+ @output.write "#{prompt_list ? prompt_list[index] : prompt}#{line}\n"
+ Reline::IOGate.erase_after_cursor
end
- @menu_info = nil # TODO: do not change state here
+ @output.flush
+ clear_dialog
+ return
end
-
- @dialogs.each_with_index do |dialog, index|
- next unless dialog.contents
-
- x_range, y_range = dialog_range dialog, wrapped_cursor_y - screen_scroll_top
- y_range.each do |row|
- next if row < 0 || row >= screen_height
-
- dialog_rows = new_lines[row] ||= []
- # index 0 is for prompt, index 1 is for line, index 2.. is for dialog
- dialog_rows[index + 2] = [x_range.begin, dialog.width, dialog.contents[row - y_range.begin]]
+ new_highest_in_this = calculate_height_by_width(prompt_width + calculate_width(@line.nil? ? '' : @line))
+ rendered = false
+ if @add_newline_to_end_of_buffer
+ clear_dialog_with_content
+ rerender_added_newline(prompt, prompt_width)
+ @add_newline_to_end_of_buffer = false
+ else
+ if @just_cursor_moving and not @rerender_all
+ clear_dialog_with_content
+ rendered = just_move_cursor
+ @just_cursor_moving = false
+ return
+ elsif @previous_line_index or new_highest_in_this != @highest_in_this
+ clear_dialog_with_content
+ rerender_changed_current_line
+ @previous_line_index = nil
+ rendered = true
+ elsif @rerender_all
+ rerender_all_lines
+ @rerender_all = false
+ rendered = true
+ else
end
end
-
- render_differential new_lines, wrapped_cursor_x, wrapped_cursor_y - screen_scroll_top
- end
-
- # Reflects lines to be rendered and new cursor position to the screen
- # by calculating the difference from the previous render.
-
- private def render_differential(new_lines, new_cursor_x, new_cursor_y)
- rendered_lines = @rendered_screen.lines
- cursor_y = @rendered_screen.cursor_y
- if new_lines != rendered_lines
- # Hide cursor while rendering to avoid cursor flickering.
- Reline::IOGate.hide_cursor
- num_lines = [[new_lines.size, rendered_lines.size].max, screen_height].min
- if @rendered_screen.base_y + num_lines > screen_height
- Reline::IOGate.scroll_down(num_lines - cursor_y - 1)
- @rendered_screen.base_y = screen_height - num_lines
- cursor_y = num_lines - 1
- end
- num_lines.times do |i|
- rendered_line = rendered_lines[i] || []
- line_to_render = new_lines[i] || []
- next if rendered_line == line_to_render
-
- Reline::IOGate.move_cursor_down i - cursor_y
- cursor_y = i
- unless rendered_lines[i]
- Reline::IOGate.move_cursor_column 0
- Reline::IOGate.erase_after_cursor
+ if @is_multiline
+ if finished?
+ # Always rerender on finish because output_modifier_proc may return a different output.
+ if @previous_line_index
+ new_lines = whole_lines(index: @previous_line_index, line: @line)
+ else
+ new_lines = whole_lines
+ end
+ line = modify_lines(new_lines)[@line_index]
+ clear_dialog
+ prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
+ render_partial(prompt, prompt_width, line, @first_line_started_from)
+ move_cursor_down(@highest_in_all - (@first_line_started_from + @highest_in_this - 1) - 1)
+ scroll_down(1)
+ Reline::IOGate.move_cursor_column(0)
+ Reline::IOGate.erase_after_cursor
+ else
+ if not rendered and not @in_pasting
+ line = modify_lines(whole_lines)[@line_index]
+ prompt, prompt_width, prompt_list = check_multiline_prompt(whole_lines)
+ render_partial(prompt, prompt_width, line, @first_line_started_from)
end
- render_line_differential(rendered_line, line_to_render)
+ render_dialog((prompt_width + @cursor) % @screen_size.last)
+ end
+ @buffer_of_lines[@line_index] = @line
+ @rest_height = 0 if @scroll_partial_screen
+ else
+ line = modify_lines(whole_lines)[@line_index]
+ render_partial(prompt, prompt_width, line, 0)
+ if finished?
+ scroll_down(1)
+ Reline::IOGate.move_cursor_column(0)
+ Reline::IOGate.erase_after_cursor
end
- @rendered_screen.lines = new_lines
- Reline::IOGate.show_cursor
end
- Reline::IOGate.move_cursor_column new_cursor_x
- Reline::IOGate.move_cursor_down new_cursor_y - cursor_y
- @rendered_screen.cursor_y = new_cursor_y
- end
-
- private def clear_rendered_screen_cache
- @rendered_screen.lines = []
- @rendered_screen.cursor_y = 0
- end
-
- def upper_space_height(wrapped_cursor_y)
- wrapped_cursor_y - screen_scroll_top
- end
-
- def rest_height(wrapped_cursor_y)
- screen_height - wrapped_cursor_y + screen_scroll_top - @rendered_screen.base_y - 1
- end
-
- def rerender
- render unless @in_pasting
end
class DialogProcScope
- CompletionJourneyData = Struct.new(:preposing, :postposing, :list, :pointer)
-
def initialize(line_editor, config, proc_to_exec, context)
@line_editor = line_editor
@config = config
@@ -608,20 +575,11 @@ class Reline::LineEditor
end
def screen_width
- @line_editor.screen_width
- end
-
- def screen_height
- @line_editor.screen_height
- end
-
- def preferred_dialog_height
- _wrapped_cursor_x, wrapped_cursor_y = @line_editor.wrapped_cursor_position
- [@line_editor.upper_space_height(wrapped_cursor_y), @line_editor.rest_height(wrapped_cursor_y), (screen_height + 6) / 5].max
+ @line_editor.instance_variable_get(:@screen_size).last
end
def completion_journey_data
- @line_editor.dialog_proc_scope_completion_journey_data
+ @line_editor.instance_variable_get(:@completion_journey_data)
end
def config
@@ -635,7 +593,7 @@ class Reline::LineEditor
class Dialog
attr_reader :name, :contents, :width
- attr_accessor :scroll_top, :pointer, :column, :vertical_offset, :trap_key
+ attr_accessor :scroll_top, :scrollbar_pos, :pointer, :column, :vertical_offset, :lines_backup, :trap_key
def initialize(name, config, proc_scope)
@name = name
@@ -670,8 +628,10 @@ class Reline::LineEditor
@trap_key.each do |t|
@config.add_oneshot_key_binding(t, @name)
end
- else
+ elsif @trap_key.is_a?(Array)
@config.add_oneshot_key_binding(@trap_key, @name)
+ elsif @trap_key.is_a?(Integer) or @trap_key.is_a?(Reline::Key)
+ @config.add_oneshot_key_binding([@trap_key], @name)
end
end
dialog_render_info
@@ -688,31 +648,52 @@ class Reline::LineEditor
end
DIALOG_DEFAULT_HEIGHT = 20
+ private def render_dialog(cursor_column)
+ @dialogs.each do |dialog|
+ render_each_dialog(dialog, cursor_column)
+ end
+ end
- private def dialog_range(dialog, dialog_y)
- x_range = dialog.column...dialog.column + dialog.width
- y_range = dialog_y + dialog.vertical_offset...dialog_y + dialog.vertical_offset + dialog.contents.size
- [x_range, y_range]
+ private def padding_space_with_escape_sequences(str, width)
+ padding_width = width - calculate_width(str, true)
+ # padding_width should be only positive value. But macOS and Alacritty returns negative value.
+ padding_width = 0 if padding_width < 0
+ str + (' ' * padding_width)
end
- private def update_each_dialog(dialog, cursor_column, cursor_row, key = nil)
- dialog.set_cursor_pos(cursor_column, cursor_row)
- dialog_render_info = dialog.call(key)
+ private def render_each_dialog(dialog, cursor_column)
+ if @in_pasting
+ clear_each_dialog(dialog)
+ dialog.contents = nil
+ dialog.trap_key = nil
+ return
+ end
+ dialog.set_cursor_pos(cursor_column, @first_line_started_from + @started_from)
+ dialog_render_info = dialog.call(@last_key)
if dialog_render_info.nil? or dialog_render_info.contents.nil? or dialog_render_info.contents.empty?
+ dialog.lines_backup = {
+ lines: modify_lines(whole_lines),
+ line_index: @line_index,
+ first_line_started_from: @first_line_started_from,
+ started_from: @started_from,
+ byte_pointer: @byte_pointer
+ }
+ clear_each_dialog(dialog)
dialog.contents = nil
dialog.trap_key = nil
return
end
- contents = dialog_render_info.contents
+ old_dialog = dialog.clone
+ dialog.contents = dialog_render_info.contents
pointer = dialog.pointer
if dialog_render_info.width
dialog.width = dialog_render_info.width
else
- dialog.width = contents.map { |l| calculate_width(l, true) }.max
+ dialog.width = dialog.contents.map { |l| calculate_width(l, true) }.max
end
height = dialog_render_info.height || DIALOG_DEFAULT_HEIGHT
- height = contents.size if contents.size < height
- if contents.size > height
+ height = dialog.contents.size if dialog.contents.size < height
+ if dialog.contents.size > height
if dialog.pointer
if dialog.pointer < 0
dialog.scroll_top = 0
@@ -722,77 +703,591 @@ class Reline::LineEditor
dialog.scroll_top = dialog.pointer
end
pointer = dialog.pointer - dialog.scroll_top
- else
- dialog.scroll_top = 0
end
- contents = contents[dialog.scroll_top, height]
+ dialog.contents = dialog.contents[dialog.scroll_top, height]
+ end
+ if dialog.contents and dialog.scroll_top >= dialog.contents.size
+ dialog.scroll_top = dialog.contents.size - height
end
if dialog_render_info.scrollbar and dialog_render_info.contents.size > height
bar_max_height = height * 2
moving_distance = (dialog_render_info.contents.size - height) * 2
position_ratio = dialog.scroll_top.zero? ? 0.0 : ((dialog.scroll_top * 2).to_f / moving_distance)
- bar_height = (bar_max_height * ((contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
- bar_height = MINIMUM_SCROLLBAR_HEIGHT if bar_height < MINIMUM_SCROLLBAR_HEIGHT
- scrollbar_pos = ((bar_max_height - bar_height) * position_ratio).floor.to_i
+ bar_height = (bar_max_height * ((dialog.contents.size * 2).to_f / (dialog_render_info.contents.size * 2))).floor.to_i
+ dialog.scrollbar_pos = ((bar_max_height - bar_height) * position_ratio).floor.to_i
else
- scrollbar_pos = nil
+ dialog.scrollbar_pos = nil
end
+ upper_space = @first_line_started_from - @started_from
dialog.column = dialog_render_info.pos.x
- dialog.width += @block_elem_width if scrollbar_pos
- diff = (dialog.column + dialog.width) - screen_width
+ dialog.width += @block_elem_width if dialog.scrollbar_pos
+ diff = (dialog.column + dialog.width) - (@screen_size.last)
if diff > 0
dialog.column -= diff
end
- if rest_height(screen_scroll_top + cursor_row) - dialog_render_info.pos.y >= height
+ if (@rest_height - dialog_render_info.pos.y) >= height
dialog.vertical_offset = dialog_render_info.pos.y + 1
- elsif cursor_row >= height
+ elsif upper_space >= height
dialog.vertical_offset = dialog_render_info.pos.y - height
else
+ if (@rest_height - dialog_render_info.pos.y) < height
+ scroll_down(height + dialog_render_info.pos.y)
+ move_cursor_up(height + dialog_render_info.pos.y)
+ end
dialog.vertical_offset = dialog_render_info.pos.y + 1
end
+ Reline::IOGate.hide_cursor
if dialog.column < 0
dialog.column = 0
- dialog.width = screen_width
- end
- face = Reline::Face[dialog_render_info.face || :default]
- scrollbar_sgr = face[:scrollbar]
- default_sgr = face[:default]
- enhanced_sgr = face[:enhanced]
- dialog.contents = contents.map.with_index do |item, i|
- line_sgr = i == pointer ? enhanced_sgr : default_sgr
- str_width = dialog.width - (scrollbar_pos.nil? ? 0 : @block_elem_width)
- str, = Reline::Unicode.take_mbchar_range(item, 0, str_width, padding: true)
- colored_content = "#{line_sgr}#{str}"
- if scrollbar_pos
- if scrollbar_pos <= (i * 2) and (i * 2 + 1) < (scrollbar_pos + bar_height)
- colored_content + scrollbar_sgr + @full_block
- elsif scrollbar_pos <= (i * 2) and (i * 2) < (scrollbar_pos + bar_height)
- colored_content + scrollbar_sgr + @upper_half_block
- elsif scrollbar_pos <= (i * 2 + 1) and (i * 2) < (scrollbar_pos + bar_height)
- colored_content + scrollbar_sgr + @lower_half_block
+ dialog.width = @screen_size.last
+ end
+ reset_dialog(dialog, old_dialog)
+ move_cursor_down(dialog.vertical_offset)
+ Reline::IOGate.move_cursor_column(dialog.column)
+ dialog.contents.each_with_index do |item, i|
+ if i == pointer
+ fg_color = dialog_render_info.pointer_fg_color
+ bg_color = dialog_render_info.pointer_bg_color
+ else
+ fg_color = dialog_render_info.fg_color
+ bg_color = dialog_render_info.bg_color
+ end
+ str_width = dialog.width - (dialog.scrollbar_pos.nil? ? 0 : @block_elem_width)
+ str = padding_space_with_escape_sequences(Reline::Unicode.take_range(item, 0, str_width), str_width)
+ @output.write "\e[#{bg_color}m\e[#{fg_color}m#{str}"
+ if dialog.scrollbar_pos and (dialog.scrollbar_pos != old_dialog.scrollbar_pos or dialog.column != old_dialog.column)
+ @output.write "\e[37m"
+ if dialog.scrollbar_pos <= (i * 2) and (i * 2 + 1) < (dialog.scrollbar_pos + bar_height)
+ @output.write @full_block
+ elsif dialog.scrollbar_pos <= (i * 2) and (i * 2) < (dialog.scrollbar_pos + bar_height)
+ @output.write @upper_half_block
+ elsif dialog.scrollbar_pos <= (i * 2 + 1) and (i * 2) < (dialog.scrollbar_pos + bar_height)
+ @output.write @lower_half_block
+ else
+ @output.write ' ' * @block_elem_width
+ end
+ end
+ @output.write "\e[0m"
+ Reline::IOGate.move_cursor_column(dialog.column)
+ move_cursor_down(1) if i < (dialog.contents.size - 1)
+ end
+ Reline::IOGate.move_cursor_column(cursor_column)
+ move_cursor_up(dialog.vertical_offset + dialog.contents.size - 1)
+ Reline::IOGate.show_cursor
+ dialog.lines_backup = {
+ lines: modify_lines(whole_lines),
+ line_index: @line_index,
+ first_line_started_from: @first_line_started_from,
+ started_from: @started_from,
+ byte_pointer: @byte_pointer
+ }
+ end
+
+ private def reset_dialog(dialog, old_dialog)
+ return if dialog.lines_backup.nil? or old_dialog.contents.nil?
+ prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines])
+ visual_lines = []
+ visual_start = nil
+ dialog.lines_backup[:lines].each_with_index { |l, i|
+ pr = prompt_list ? prompt_list[i] : prompt
+ vl, _ = split_by_width(pr + l, @screen_size.last)
+ vl.compact!
+ if i == dialog.lines_backup[:line_index]
+ visual_start = visual_lines.size + dialog.lines_backup[:started_from]
+ end
+ visual_lines.concat(vl)
+ }
+ old_y = dialog.lines_backup[:first_line_started_from] + dialog.lines_backup[:started_from]
+ y = @first_line_started_from + @started_from
+ y_diff = y - old_y
+ if (old_y + old_dialog.vertical_offset) < (y + dialog.vertical_offset)
+ # rerender top
+ move_cursor_down(old_dialog.vertical_offset - y_diff)
+ start = visual_start + old_dialog.vertical_offset
+ line_num = dialog.vertical_offset - old_dialog.vertical_offset
+ line_num.times do |i|
+ Reline::IOGate.move_cursor_column(old_dialog.column)
+ if visual_lines[start + i].nil?
+ s = ' ' * old_dialog.width
else
- colored_content + scrollbar_sgr + ' ' * @block_elem_width
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
+ s = padding_space_with_escape_sequences(s, old_dialog.width)
end
+ @output.write "\e[0m#{s}\e[0m"
+ move_cursor_down(1) if i < (line_num - 1)
+ end
+ move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
+ end
+ if (old_y + old_dialog.vertical_offset + old_dialog.contents.size) > (y + dialog.vertical_offset + dialog.contents.size)
+ # rerender bottom
+ move_cursor_down(dialog.vertical_offset + dialog.contents.size - y_diff)
+ start = visual_start + dialog.vertical_offset + dialog.contents.size
+ line_num = (old_dialog.vertical_offset + old_dialog.contents.size) - (dialog.vertical_offset + dialog.contents.size)
+ line_num.times do |i|
+ Reline::IOGate.move_cursor_column(old_dialog.column)
+ if visual_lines[start + i].nil?
+ s = ' ' * old_dialog.width
+ else
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, old_dialog.width)
+ s = padding_space_with_escape_sequences(s, old_dialog.width)
+ end
+ @output.write "\e[0m#{s}\e[0m"
+ move_cursor_down(1) if i < (line_num - 1)
+ end
+ move_cursor_up(dialog.vertical_offset + dialog.contents.size + line_num - 1 - y_diff)
+ end
+ if old_dialog.column < dialog.column
+ # rerender left
+ move_cursor_down(old_dialog.vertical_offset - y_diff)
+ width = dialog.column - old_dialog.column
+ start = visual_start + old_dialog.vertical_offset
+ line_num = old_dialog.contents.size
+ line_num.times do |i|
+ Reline::IOGate.move_cursor_column(old_dialog.column)
+ if visual_lines[start + i].nil?
+ s = ' ' * width
+ else
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column, width)
+ s = padding_space_with_escape_sequences(s, dialog.width)
+ end
+ @output.write "\e[0m#{s}\e[0m"
+ move_cursor_down(1) if i < (line_num - 1)
+ end
+ move_cursor_up(old_dialog.vertical_offset + line_num - 1 - y_diff)
+ end
+ if (old_dialog.column + old_dialog.width) > (dialog.column + dialog.width)
+ # rerender right
+ move_cursor_down(old_dialog.vertical_offset + y_diff)
+ width = (old_dialog.column + old_dialog.width) - (dialog.column + dialog.width)
+ start = visual_start + old_dialog.vertical_offset
+ line_num = old_dialog.contents.size
+ line_num.times do |i|
+ Reline::IOGate.move_cursor_column(old_dialog.column + dialog.width)
+ if visual_lines[start + i].nil?
+ s = ' ' * width
+ else
+ s = Reline::Unicode.take_range(visual_lines[start + i], old_dialog.column + dialog.width, width)
+ rerender_width = old_dialog.width - dialog.width
+ s = padding_space_with_escape_sequences(s, rerender_width)
+ end
+ Reline::IOGate.move_cursor_column(dialog.column + dialog.width)
+ @output.write "\e[0m#{s}\e[0m"
+ move_cursor_down(1) if i < (line_num - 1)
+ end
+ move_cursor_up(old_dialog.vertical_offset + line_num - 1 + y_diff)
+ end
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ end
+
+ private def clear_dialog
+ @dialogs.each do |dialog|
+ clear_each_dialog(dialog)
+ end
+ end
+
+ private def clear_dialog_with_content
+ @dialogs.each do |dialog|
+ clear_each_dialog(dialog)
+ dialog.contents = nil
+ dialog.trap_key = nil
+ end
+ end
+
+ private def clear_each_dialog(dialog)
+ dialog.trap_key = nil
+ return unless dialog.contents
+ prompt, prompt_width, prompt_list = check_multiline_prompt(dialog.lines_backup[:lines])
+ visual_lines = []
+ visual_lines_under_dialog = []
+ visual_start = nil
+ dialog.lines_backup[:lines].each_with_index { |l, i|
+ pr = prompt_list ? prompt_list[i] : prompt
+ vl, _ = split_by_width(pr + l, @screen_size.last)
+ vl.compact!
+ if i == dialog.lines_backup[:line_index]
+ visual_start = visual_lines.size + dialog.lines_backup[:started_from] + dialog.vertical_offset
+ end
+ visual_lines.concat(vl)
+ }
+ visual_lines_under_dialog = visual_lines[visual_start, dialog.contents.size]
+ visual_lines_under_dialog = [] if visual_lines_under_dialog.nil?
+ Reline::IOGate.hide_cursor
+ move_cursor_down(dialog.vertical_offset)
+ dialog_vertical_size = dialog.contents.size
+ dialog_vertical_size.times do |i|
+ if i < visual_lines_under_dialog.size
+ Reline::IOGate.move_cursor_column(dialog.column)
+ str = Reline::Unicode.take_range(visual_lines_under_dialog[i], dialog.column, dialog.width)
+ str = padding_space_with_escape_sequences(str, dialog.width)
+ @output.write "\e[0m#{str}\e[0m"
else
- colored_content
+ Reline::IOGate.move_cursor_column(dialog.column)
+ @output.write "\e[0m#{' ' * dialog.width}\e[0m"
end
+ move_cursor_down(1) if i < (dialog_vertical_size - 1)
end
+ move_cursor_up(dialog_vertical_size - 1 + dialog.vertical_offset)
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ Reline::IOGate.show_cursor
end
- private def modify_lines(before, complete)
- if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: complete)
+ private def calculate_scroll_partial_screen(highest_in_all, cursor_y)
+ if @screen_height < highest_in_all
+ old_scroll_partial_screen = @scroll_partial_screen
+ if cursor_y == 0
+ @scroll_partial_screen = 0
+ elsif cursor_y == (highest_in_all - 1)
+ @scroll_partial_screen = highest_in_all - @screen_height
+ else
+ if @scroll_partial_screen
+ if cursor_y <= @scroll_partial_screen
+ @scroll_partial_screen = cursor_y
+ elsif (@scroll_partial_screen + @screen_height - 1) < cursor_y
+ @scroll_partial_screen = cursor_y - (@screen_height - 1)
+ end
+ else
+ if cursor_y > (@screen_height - 1)
+ @scroll_partial_screen = cursor_y - (@screen_height - 1)
+ else
+ @scroll_partial_screen = 0
+ end
+ end
+ end
+ if @scroll_partial_screen != old_scroll_partial_screen
+ @rerender_all = true
+ end
+ else
+ if @scroll_partial_screen
+ @rerender_all = true
+ end
+ @scroll_partial_screen = nil
+ end
+ end
+
+ private def rerender_added_newline(prompt, prompt_width)
+ scroll_down(1)
+ @buffer_of_lines[@previous_line_index] = @line
+ @line = @buffer_of_lines[@line_index]
+ unless @in_pasting
+ render_partial(prompt, prompt_width, @line, @first_line_started_from + @started_from + 1, with_control: false)
+ end
+ @cursor = @cursor_max = calculate_width(@line)
+ @byte_pointer = @line.bytesize
+ @highest_in_all += @highest_in_this
+ @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
+ @first_line_started_from += @started_from + 1
+ @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
+ @previous_line_index = nil
+ end
+
+ def just_move_cursor
+ prompt, prompt_width, prompt_list = check_multiline_prompt(@buffer_of_lines)
+ move_cursor_up(@started_from)
+ new_first_line_started_from =
+ if @line_index.zero?
+ 0
+ else
+ calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
+ end
+ first_line_diff = new_first_line_started_from - @first_line_started_from
+ new_cursor, new_cursor_max, new_started_from, new_byte_pointer = calculate_nearest_cursor(@buffer_of_lines[@line_index], @cursor, @started_from, @byte_pointer, false)
+ new_started_from = calculate_height_by_width(prompt_width + new_cursor) - 1
+ calculate_scroll_partial_screen(@highest_in_all, new_first_line_started_from + new_started_from)
+ @previous_line_index = nil
+ if @rerender_all
+ @line = @buffer_of_lines[@line_index]
+ rerender_all_lines
+ @rerender_all = false
+ true
+ else
+ @line = @buffer_of_lines[@line_index]
+ @first_line_started_from = new_first_line_started_from
+ @started_from = new_started_from
+ @cursor = new_cursor
+ @cursor_max = new_cursor_max
+ @byte_pointer = new_byte_pointer
+ move_cursor_down(first_line_diff + @started_from)
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ false
+ end
+ end
+
+ private def rerender_changed_current_line
+ if @previous_line_index
+ new_lines = whole_lines(index: @previous_line_index, line: @line)
+ else
+ new_lines = whole_lines
+ end
+ prompt, prompt_width, prompt_list = check_multiline_prompt(new_lines)
+ all_height = calculate_height_by_lines(new_lines, prompt_list || prompt)
+ diff = all_height - @highest_in_all
+ move_cursor_down(@highest_in_all - @first_line_started_from - @started_from - 1)
+ if diff > 0
+ scroll_down(diff)
+ move_cursor_up(all_height - 1)
+ elsif diff < 0
+ (-diff).times do
+ Reline::IOGate.move_cursor_column(0)
+ Reline::IOGate.erase_after_cursor
+ move_cursor_up(1)
+ end
+ move_cursor_up(all_height - 1)
+ else
+ move_cursor_up(all_height - 1)
+ end
+ @highest_in_all = all_height
+ back = render_whole_lines(new_lines, prompt_list || prompt, prompt_width)
+ move_cursor_up(back)
+ if @previous_line_index
+ @buffer_of_lines[@previous_line_index] = @line
+ @line = @buffer_of_lines[@line_index]
+ end
+ @first_line_started_from =
+ if @line_index.zero?
+ 0
+ else
+ calculate_height_by_lines(@buffer_of_lines[0..(@line_index - 1)], prompt_list || prompt)
+ end
+ if @prompt_proc
+ prompt = prompt_list[@line_index]
+ prompt_width = calculate_width(prompt, true)
+ end
+ move_cursor_down(@first_line_started_from)
+ calculate_nearest_cursor
+ @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
+ move_cursor_down(@started_from)
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
+ end
+
+ private def rerender_all_lines
+ move_cursor_up(@first_line_started_from + @started_from)
+ Reline::IOGate.move_cursor_column(0)
+ back = 0
+ new_buffer = whole_lines
+ prompt, prompt_width, prompt_list = check_multiline_prompt(new_buffer)
+ new_buffer.each_with_index do |line, index|
+ prompt_width = calculate_width(prompt_list[index], true) if @prompt_proc
+ width = prompt_width + calculate_width(line)
+ height = calculate_height_by_width(width)
+ back += height
+ end
+ old_highest_in_all = @highest_in_all
+ if @line_index.zero?
+ new_first_line_started_from = 0
+ else
+ new_first_line_started_from = calculate_height_by_lines(new_buffer[0..(@line_index - 1)], prompt_list || prompt)
+ end
+ new_started_from = calculate_height_by_width(prompt_width + @cursor) - 1
+ calculate_scroll_partial_screen(back, new_first_line_started_from + new_started_from)
+ if @scroll_partial_screen
+ move_cursor_up(@first_line_started_from + @started_from)
+ scroll_down(@screen_height - 1)
+ move_cursor_up(@screen_height)
+ Reline::IOGate.move_cursor_column(0)
+ elsif back > old_highest_in_all
+ scroll_down(back - 1)
+ move_cursor_up(back - 1)
+ elsif back < old_highest_in_all
+ scroll_down(back)
+ Reline::IOGate.erase_after_cursor
+ (old_highest_in_all - back - 1).times do
+ scroll_down(1)
+ Reline::IOGate.erase_after_cursor
+ end
+ move_cursor_up(old_highest_in_all - 1)
+ end
+ render_whole_lines(new_buffer, prompt_list || prompt, prompt_width)
+ if @prompt_proc
+ prompt = prompt_list[@line_index]
+ prompt_width = calculate_width(prompt, true)
+ end
+ @highest_in_this = calculate_height_by_width(prompt_width + @cursor_max)
+ @highest_in_all = back
+ @first_line_started_from = new_first_line_started_from
+ @started_from = new_started_from
+ if @scroll_partial_screen
+ Reline::IOGate.move_cursor_up(@screen_height - (@first_line_started_from + @started_from - @scroll_partial_screen) - 1)
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ else
+ move_cursor_down(@first_line_started_from + @started_from - back + 1)
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ end
+ end
+
+ private def render_whole_lines(lines, prompt, prompt_width)
+ rendered_height = 0
+ modify_lines(lines).each_with_index do |line, index|
+ if prompt.is_a?(Array)
+ line_prompt = prompt[index]
+ prompt_width = calculate_width(line_prompt, true)
+ else
+ line_prompt = prompt
+ end
+ height = render_partial(line_prompt, prompt_width, line, rendered_height, with_control: false)
+ if index < (lines.size - 1)
+ if @scroll_partial_screen
+ if (@scroll_partial_screen - height) < rendered_height and (@scroll_partial_screen + @screen_height - 1) >= (rendered_height + height)
+ move_cursor_down(1)
+ end
+ else
+ scroll_down(1)
+ end
+ rendered_height += height
+ else
+ rendered_height += height - 1
+ end
+ end
+ rendered_height
+ end
+
+ private def render_partial(prompt, prompt_width, line_to_render, this_started_from, with_control: true)
+ visual_lines, height = split_by_width(line_to_render.nil? ? prompt : prompt + line_to_render, @screen_size.last)
+ cursor_up_from_last_line = 0
+ if @scroll_partial_screen
+ last_visual_line = this_started_from + (height - 1)
+ last_screen_line = @scroll_partial_screen + (@screen_height - 1)
+ if (@scroll_partial_screen - this_started_from) >= height
+ # Render nothing because this line is before the screen.
+ visual_lines = []
+ elsif this_started_from > last_screen_line
+ # Render nothing because this line is after the screen.
+ visual_lines = []
+ else
+ deleted_lines_before_screen = []
+ if @scroll_partial_screen > this_started_from and last_visual_line >= @scroll_partial_screen
+ # A part of visual lines are before the screen.
+ deleted_lines_before_screen = visual_lines.shift((@scroll_partial_screen - this_started_from) * 2)
+ deleted_lines_before_screen.compact!
+ end
+ if this_started_from <= last_screen_line and last_screen_line < last_visual_line
+ # A part of visual lines are after the screen.
+ visual_lines.pop((last_visual_line - last_screen_line) * 2)
+ end
+ move_cursor_up(deleted_lines_before_screen.size - @started_from)
+ cursor_up_from_last_line = @started_from - deleted_lines_before_screen.size
+ end
+ end
+ if with_control
+ if height > @highest_in_this
+ diff = height - @highest_in_this
+ scroll_down(diff)
+ @highest_in_all += diff
+ @highest_in_this = height
+ move_cursor_up(diff)
+ elsif height < @highest_in_this
+ diff = @highest_in_this - height
+ @highest_in_all -= diff
+ @highest_in_this = height
+ end
+ move_cursor_up(@started_from)
+ @started_from = calculate_height_by_width(prompt_width + @cursor) - 1
+ cursor_up_from_last_line = height - 1 - @started_from
+ end
+ if Reline::Unicode::CSI_REGEXP.match?(prompt + line_to_render)
+ @output.write "\e[0m" # clear character decorations
+ end
+ visual_lines.each_with_index do |line, index|
+ Reline::IOGate.move_cursor_column(0)
+ if line.nil?
+ if calculate_width(visual_lines[index - 1], true) == Reline::IOGate.get_screen_size.last
+ # reaches the end of line
+ if Reline::IOGate.win? and Reline::IOGate.win_legacy_console?
+ # A newline is automatically inserted if a character is rendered at
+ # eol on command prompt.
+ else
+ # When the cursor is at the end of the line and erases characters
+ # after the cursor, some terminals delete the character at the
+ # cursor position.
+ move_cursor_down(1)
+ Reline::IOGate.move_cursor_column(0)
+ end
+ else
+ Reline::IOGate.erase_after_cursor
+ move_cursor_down(1)
+ Reline::IOGate.move_cursor_column(0)
+ end
+ next
+ end
+ @output.write line
+ if Reline::IOGate.win? and Reline::IOGate.win_legacy_console? and calculate_width(line, true) == Reline::IOGate.get_screen_size.last
+ # A newline is automatically inserted if a character is rendered at eol on command prompt.
+ @rest_height -= 1 if @rest_height > 0
+ end
+ @output.flush
+ if @first_prompt
+ @first_prompt = false
+ @pre_input_hook&.call
+ end
+ end
+ unless visual_lines.empty?
+ Reline::IOGate.erase_after_cursor
+ Reline::IOGate.move_cursor_column(0)
+ end
+ if with_control
+ # Just after rendring, so the cursor is on the last line.
+ if finished?
+ Reline::IOGate.move_cursor_column(0)
+ else
+ # Moves up from bottom of lines to the cursor position.
+ move_cursor_up(cursor_up_from_last_line)
+ # This logic is buggy if a fullwidth char is wrapped because there is only one halfwidth at end of a line.
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
+ end
+ end
+ height
+ end
+
+ private def modify_lines(before)
+ return before if before.nil? || before.empty? || simplified_rendering?
+
+ if after = @output_modifier_proc&.call("#{before.join("\n")}\n", complete: finished?)
after.lines("\n").map { |l| l.chomp('') }
else
- before.map { |l| Reline::Unicode.escape_for_print(l) }
+ before
+ end
+ end
+
+ private def show_menu
+ scroll_down(@highest_in_all - @first_line_started_from)
+ @rerender_all = true
+ @menu_info.list.sort!.each do |item|
+ Reline::IOGate.move_cursor_column(0)
+ @output.write item
+ @output.flush
+ scroll_down(1)
end
+ scroll_down(@highest_in_all - 1)
+ move_cursor_up(@highest_in_all - 1 - @first_line_started_from)
+ end
+
+ private def clear_screen_buffer(prompt, prompt_list, prompt_width)
+ Reline::IOGate.clear_screen
+ back = 0
+ modify_lines(whole_lines).each_with_index do |line, index|
+ if @prompt_proc
+ pr = prompt_list[index]
+ height = render_partial(pr, calculate_width(pr), line, back, with_control: false)
+ else
+ height = render_partial(prompt, prompt_width, line, back, with_control: false)
+ end
+ if index < (@buffer_of_lines.size - 1)
+ move_cursor_down(1)
+ back += height
+ end
+ end
+ move_cursor_up(back)
+ move_cursor_down(@first_line_started_from + @started_from)
+ @rest_height = (Reline::IOGate.get_screen_size.first - 1) - Reline::IOGate.cursor_pos.y
+ Reline::IOGate.move_cursor_column((prompt_width + @cursor) % @screen_size.last)
end
def editing_mode
@config.editing_mode
end
- private def menu(_target, list)
- @menu_info = MenuInfo.new(list)
+ private def menu(target, list)
+ @menu_info = MenuInfo.new(target, list)
end
private def complete_internal_proc(list, is_menu)
@@ -820,7 +1315,7 @@ class Reline::LineEditor
item_mbchars = item.grapheme_clusters
end
size = [memo_mbchars.size, item_mbchars.size].min
- result = +''
+ result = ''
size.times do |i|
if @config.completion_ignore_case
if memo_mbchars[i].casecmp?(item_mbchars[i])
@@ -841,9 +1336,9 @@ class Reline::LineEditor
[target, preposing, completed, postposing]
end
- private def perform_completion(list, just_show_list)
+ private def complete(list, just_show_list = false)
case @completion_state
- when CompletionState::NORMAL
+ when CompletionState::NORMAL, CompletionState::JOURNEY
@completion_state = CompletionState::COMPLETION
when CompletionState::PERFECT_MATCH
@dig_perfect_match_proc&.(@perfect_matched)
@@ -870,80 +1365,100 @@ class Reline::LineEditor
@completion_state = CompletionState::PERFECT_MATCH
else
@completion_state = CompletionState::MENU_WITH_PERFECT_MATCH
- perform_completion(list, true) if @config.show_all_if_ambiguous
end
@perfect_matched = completed
else
@completion_state = CompletionState::MENU
- perform_completion(list, true) if @config.show_all_if_ambiguous
end
if not just_show_list and target < completed
- @buffer_of_lines[@line_index] = (preposing + completed + completion_append_character.to_s + postposing).split("\n")[@line_index] || String.new(encoding: @encoding)
- line_to_pointer = (preposing + completed + completion_append_character.to_s).split("\n")[@line_index] || String.new(encoding: @encoding)
+ @line = preposing + completed + completion_append_character.to_s + postposing
+ line_to_pointer = preposing + completed + completion_append_character.to_s
+ @cursor_max = calculate_width(@line)
+ @cursor = calculate_width(line_to_pointer)
@byte_pointer = line_to_pointer.bytesize
end
end
end
- def dialog_proc_scope_completion_journey_data
- return nil unless @completion_journey_state
- line_index = @completion_journey_state.line_index
- pre_lines = @buffer_of_lines[0...line_index].map { |line| line + "\n" }
- post_lines = @buffer_of_lines[(line_index + 1)..-1].map { |line| line + "\n" }
- DialogProcScope::CompletionJourneyData.new(
- pre_lines.join + @completion_journey_state.pre,
- @completion_journey_state.post + post_lines.join,
- @completion_journey_state.list,
- @completion_journey_state.pointer
- )
- end
-
- private def move_completed_list(direction)
- @completion_journey_state ||= retrieve_completion_journey_state
- return false unless @completion_journey_state
-
- if (delta = { up: -1, down: +1 }[direction])
- @completion_journey_state.pointer = (@completion_journey_state.pointer + delta) % @completion_journey_state.list.size
+ private def move_completed_list(list, direction)
+ case @completion_state
+ when CompletionState::NORMAL, CompletionState::COMPLETION,
+ CompletionState::MENU, CompletionState::MENU_WITH_PERFECT_MATCH
+ @completion_state = CompletionState::JOURNEY
+ result = retrieve_completion_block
+ return if result.nil?
+ preposing, target, postposing = result
+ @completion_journey_data = CompletionJourneyData.new(
+ preposing, postposing,
+ [target] + list.select{ |item| item.start_with?(target) }, 0)
+ if @completion_journey_data.list.size == 1
+ @completion_journey_data.pointer = 0
+ else
+ case direction
+ when :up
+ @completion_journey_data.pointer = @completion_journey_data.list.size - 1
+ when :down
+ @completion_journey_data.pointer = 1
+ end
+ end
+ @completion_state = CompletionState::JOURNEY
+ else
+ case direction
+ when :up
+ @completion_journey_data.pointer -= 1
+ if @completion_journey_data.pointer < 0
+ @completion_journey_data.pointer = @completion_journey_data.list.size - 1
+ end
+ when :down
+ @completion_journey_data.pointer += 1
+ if @completion_journey_data.pointer >= @completion_journey_data.list.size
+ @completion_journey_data.pointer = 0
+ end
+ end
end
- completed = @completion_journey_state.list[@completion_journey_state.pointer]
- set_current_line(@completion_journey_state.pre + completed + @completion_journey_state.post, @completion_journey_state.pre.bytesize + completed.bytesize)
- true
- end
-
- private def retrieve_completion_journey_state
- preposing, target, postposing = retrieve_completion_block
- list = call_completion_proc
- return unless list.is_a?(Array)
-
- candidates = list.select{ |item| item.start_with?(target) }
- return if candidates.empty?
-
- pre = preposing.split("\n", -1).last || ''
- post = postposing.split("\n", -1).first || ''
- CompletionJourneyState.new(
- @line_index, pre, target, post, [target] + candidates, 0
- )
+ completed = @completion_journey_data.list[@completion_journey_data.pointer]
+ new_line = (@completion_journey_data.preposing + completed + @completion_journey_data.postposing).split("\n")[@line_index]
+ @line = new_line.nil? ? String.new(encoding: @encoding) : new_line
+ line_to_pointer = (@completion_journey_data.preposing + completed).split("\n").last
+ line_to_pointer = String.new(encoding: @encoding) if line_to_pointer.nil?
+ @cursor_max = calculate_width(@line)
+ @cursor = calculate_width(line_to_pointer)
+ @byte_pointer = line_to_pointer.bytesize
end
private def run_for_operators(key, method_symbol, &block)
- if @vi_waiting_operator
+ if @waiting_operator_proc
if VI_MOTIONS.include?(method_symbol)
- old_byte_pointer = @byte_pointer
- @vi_arg = (@vi_arg || 1) * @vi_waiting_operator_arg
+ old_cursor, old_byte_pointer = @cursor, @byte_pointer
+ @vi_arg = @waiting_operator_vi_arg if @waiting_operator_vi_arg&.> 1
block.(true)
unless @waiting_proc
- byte_pointer_diff = @byte_pointer - old_byte_pointer
- @byte_pointer = old_byte_pointer
- method_obj = method(@vi_waiting_operator)
- wrap_method_call(@vi_waiting_operator, method_obj, byte_pointer_diff)
- cleanup_waiting
+ cursor_diff, byte_pointer_diff = @cursor - old_cursor, @byte_pointer - old_byte_pointer
+ @cursor, @byte_pointer = old_cursor, old_byte_pointer
+ @waiting_operator_proc.(cursor_diff, byte_pointer_diff)
+ else
+ old_waiting_proc = @waiting_proc
+ old_waiting_operator_proc = @waiting_operator_proc
+ current_waiting_operator_proc = @waiting_operator_proc
+ @waiting_proc = proc { |k|
+ old_cursor, old_byte_pointer = @cursor, @byte_pointer
+ old_waiting_proc.(k)
+ cursor_diff, byte_pointer_diff = @cursor - old_cursor, @byte_pointer - old_byte_pointer
+ @cursor, @byte_pointer = old_cursor, old_byte_pointer
+ current_waiting_operator_proc.(cursor_diff, byte_pointer_diff)
+ @waiting_operator_proc = old_waiting_operator_proc
+ }
end
else
# Ignores operator when not motion is given.
block.(false)
- cleanup_waiting
end
- @vi_arg = nil
+ @waiting_operator_proc = nil
+ @waiting_operator_vi_arg = nil
+ if @vi_arg
+ @rerender_all = true
+ @vi_arg = nil
+ end
else
block.(false)
end
@@ -960,7 +1475,7 @@ class Reline::LineEditor
end
def wrap_method_call(method_symbol, method_obj, key, with_operator = false)
- if @config.editing_mode_is?(:emacs, :vi_insert) and @vi_waiting_operator.nil?
+ if @config.editing_mode_is?(:emacs, :vi_insert) and @waiting_proc.nil? and @waiting_operator_proc.nil?
not_insertion = method_symbol != :ed_insert
process_insert(force: not_insertion)
end
@@ -979,33 +1494,11 @@ class Reline::LineEditor
end
end
- private def cleanup_waiting
- @waiting_proc = nil
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- @searching_prompt = nil
- @drop_terminate_spaces = false
- end
-
private def process_key(key, method_symbol)
- if key.is_a?(Symbol)
- cleanup_waiting
- elsif @waiting_proc
- old_byte_pointer = @byte_pointer
- @waiting_proc.call(key)
- if @vi_waiting_operator
- byte_pointer_diff = @byte_pointer - old_byte_pointer
- @byte_pointer = old_byte_pointer
- method_obj = method(@vi_waiting_operator)
- wrap_method_call(@vi_waiting_operator, method_obj, byte_pointer_diff)
- cleanup_waiting
- end
- @kill_ring.process
- return
- end
-
if method_symbol and respond_to?(method_symbol, true)
method_obj = method(method_symbol)
+ else
+ method_obj = nil
end
if method_symbol and key.is_a?(Symbol)
if @vi_arg and argumentable?(method_obj)
@@ -1017,6 +1510,7 @@ class Reline::LineEditor
end
@kill_ring.process
if @vi_arg
+ @rerender_al = true
@vi_arg = nil
end
elsif @vi_arg
@@ -1027,6 +1521,8 @@ class Reline::LineEditor
run_for_operators(key, method_symbol) do |with_operator|
wrap_method_call(method_symbol, method_obj, key, with_operator)
end
+ elsif @waiting_proc
+ @waiting_proc.(key)
elsif method_obj
wrap_method_call(method_symbol, method_obj, key)
else
@@ -1034,9 +1530,13 @@ class Reline::LineEditor
end
@kill_ring.process
if @vi_arg
+ @rerender_all = true
@vi_arg = nil
end
end
+ elsif @waiting_proc
+ @waiting_proc.(key)
+ @kill_ring.process
elsif method_obj
if method_symbol == :ed_argument_digit
wrap_method_call(method_symbol, method_obj, key)
@@ -1052,6 +1552,11 @@ class Reline::LineEditor
end
private def normal_char(key)
+ method_symbol = method_obj = nil
+ if key.combined_char.is_a?(Symbol)
+ process_key(key.combined_char, key.combined_char)
+ return
+ end
@multibyte_buffer << key.combined_char
if @multibyte_buffer.size > 1
if @multibyte_buffer.dup.force_encoding(@encoding).valid_encoding?
@@ -1064,101 +1569,98 @@ class Reline::LineEditor
else # single byte
return if key.char >= 128 # maybe, first byte of multi byte
method_symbol = @config.editing_mode.get_method(key.combined_char)
- process_key(key.combined_char, method_symbol)
+ if key.with_meta and method_symbol == :ed_unassigned
+ # split ESC + key
+ method_symbol = @config.editing_mode.get_method("\e".ord)
+ process_key("\e".ord, method_symbol)
+ method_symbol = @config.editing_mode.get_method(key.char)
+ process_key(key.char, method_symbol)
+ else
+ process_key(key.combined_char, method_symbol)
+ end
@multibyte_buffer.clear
end
- if @config.editing_mode_is?(:vi_command) and @byte_pointer > 0 and @byte_pointer == current_line.bytesize
- byte_size = Reline::Unicode.get_prev_mbchar_size(@buffer_of_lines[@line_index], @byte_pointer)
+ if @config.editing_mode_is?(:vi_command) and @cursor > 0 and @cursor == @cursor_max
+ byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
@byte_pointer -= byte_size
- end
- end
-
- def update(key)
- modified = input_key(key)
- unless @in_pasting
- scroll_into_view
- @just_cursor_moving = !modified
- update_dialogs(key)
- @just_cursor_moving = false
+ mbchar = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor -= width
end
end
def input_key(key)
- save_old_buffer
+ @last_key = key
@config.reset_oneshot_key_bindings
@dialogs.each do |dialog|
if key.char.instance_of?(Symbol) and key.char == dialog.name
return
end
end
+ @just_cursor_moving = nil
if key.char.nil?
- process_insert(force: true)
- @eof = buffer_empty?
+ if @first_char
+ @line = nil
+ end
finish
return
end
- @completion_occurs = false
-
- if key.char.is_a?(Symbol)
+ old_line = @line.dup
+ @first_char = false
+ completion_occurs = false
+ if @config.editing_mode_is?(:emacs, :vi_insert) and key.char == "\C-i".ord
+ unless @config.disable_completion
+ result = call_completion_proc
+ if result.is_a?(Array)
+ completion_occurs = true
+ process_insert
+ if @config.autocompletion
+ move_completed_list(result, :down)
+ else
+ complete(result)
+ end
+ end
+ end
+ elsif @config.editing_mode_is?(:emacs, :vi_insert) and key.char == :completion_journey_up
+ if not @config.disable_completion and @config.autocompletion
+ result = call_completion_proc
+ if result.is_a?(Array)
+ completion_occurs = true
+ process_insert
+ move_completed_list(result, :up)
+ end
+ end
+ elsif not @config.disable_completion and @config.editing_mode_is?(:vi_insert) and ["\C-p".ord, "\C-n".ord].include?(key.char)
+ unless @config.disable_completion
+ result = call_completion_proc
+ if result.is_a?(Array)
+ completion_occurs = true
+ process_insert
+ move_completed_list(result, "\C-p".ord == key.char ? :up : :down)
+ end
+ end
+ elsif Symbol === key.char and respond_to?(key.char, true)
process_key(key.char, key.char)
else
normal_char(key)
end
-
- @prev_action_state, @next_action_state = @next_action_state, NullActionState
-
- unless @completion_occurs
+ unless completion_occurs
@completion_state = CompletionState::NORMAL
- @completion_journey_state = nil
+ @completion_journey_data = nil
end
-
- push_input_lines unless @undoing
- @undoing = false
-
- if @in_pasting
- clear_dialogs
- return
- end
-
- modified = @old_buffer_of_lines != @buffer_of_lines
- if !@completion_occurs && modified && !@config.disable_completion && @config.autocompletion
- # Auto complete starts only when edited
- process_insert(force: true)
- @completion_journey_state = retrieve_completion_journey_state
- end
- modified
- end
-
- def save_old_buffer
- @old_buffer_of_lines = @buffer_of_lines.dup
- end
-
- def push_input_lines
- if @old_buffer_of_lines == @buffer_of_lines
- @input_lines[@input_lines_position] = [@buffer_of_lines.dup, @byte_pointer, @line_index]
+ if not @in_pasting and @just_cursor_moving.nil?
+ if @previous_line_index and @buffer_of_lines[@previous_line_index] == @line
+ @just_cursor_moving = true
+ elsif @previous_line_index.nil? and @buffer_of_lines[@line_index] == @line and old_line == @line
+ @just_cursor_moving = true
+ else
+ @just_cursor_moving = false
+ end
else
- @input_lines = @input_lines[0..@input_lines_position]
- @input_lines_position += 1
- @input_lines.push([@buffer_of_lines.dup, @byte_pointer, @line_index])
- end
- trim_input_lines
- end
-
- MAX_INPUT_LINES = 100
- def trim_input_lines
- if @input_lines.size > MAX_INPUT_LINES
- @input_lines.shift
- @input_lines_position -= 1
- end
- end
-
- def scroll_into_view
- _wrapped_cursor_x, wrapped_cursor_y = wrapped_cursor_position
- if wrapped_cursor_y < screen_scroll_top
- @scroll_partial_screen = wrapped_cursor_y
+ @just_cursor_moving = false
end
- if wrapped_cursor_y >= screen_scroll_top + screen_height
- @scroll_partial_screen = wrapped_cursor_y - screen_height + 1
+ if @is_multiline and @auto_indent_proc and not simplified_rendering?
+ process_auto_indent
end
end
@@ -1192,52 +1694,46 @@ class Reline::LineEditor
result
end
- private def process_auto_indent(line_index = @line_index, cursor_dependent: true, add_newline: false)
- return if @in_pasting
- return unless @auto_indent_proc
-
- line = @buffer_of_lines[line_index]
- byte_pointer = cursor_dependent && @line_index == line_index ? @byte_pointer : line.bytesize
- new_indent = @auto_indent_proc.(@buffer_of_lines.take(line_index + 1).push(''), line_index, byte_pointer, add_newline)
- return unless new_indent
+ private def process_auto_indent
+ return if not @check_new_auto_indent and @previous_line_index # move cursor up or down
+ if @check_new_auto_indent and @previous_line_index and @previous_line_index > 0 and @line_index > @previous_line_index
+ # Fix indent of a line when a newline is inserted to the next
+ new_lines = whole_lines(index: @previous_line_index, line: @line)
+ new_indent = @auto_indent_proc.(new_lines[0..-3].push(''), @line_index - 1, 0, true)
+ md = @line.match(/\A */)
+ prev_indent = md[0].count(' ')
+ @line = ' ' * new_indent + @line.lstrip
- new_line = ' ' * new_indent + line.lstrip
- @buffer_of_lines[line_index] = new_line
- if @line_index == line_index
- indent_diff = new_line.bytesize - line.bytesize
- @byte_pointer = [@byte_pointer + indent_diff, 0].max
- end
- end
-
- def line()
- @buffer_of_lines.join("\n") unless eof?
- end
-
- def current_line
- @buffer_of_lines[@line_index]
- end
-
- def set_current_line(line, byte_pointer = nil)
- cursor = current_byte_pointer_cursor
- @buffer_of_lines[@line_index] = line
- if byte_pointer
- @byte_pointer = byte_pointer
- else
- calculate_nearest_cursor(cursor)
+ new_indent = nil
+ result = @auto_indent_proc.(new_lines[0..-2], @line_index - 1, (new_lines[-2].size + 1), false)
+ if result
+ new_indent = result
+ end
+ if new_indent&.>= 0
+ @line = ' ' * new_indent + @line.lstrip
+ end
end
- process_auto_indent
- end
-
- def set_current_lines(lines, byte_pointer = nil, line_index = 0)
- cursor = current_byte_pointer_cursor
- @buffer_of_lines = lines
- @line_index = line_index
- if byte_pointer
- @byte_pointer = byte_pointer
+ if @previous_line_index
+ new_lines = whole_lines(index: @previous_line_index, line: @line)
else
- calculate_nearest_cursor(cursor)
+ new_lines = whole_lines
+ end
+ new_indent = @auto_indent_proc.(new_lines, @line_index, @byte_pointer, @check_new_auto_indent)
+ new_indent = @cursor_max if new_indent&.> @cursor_max
+ if new_indent&.>= 0
+ md = new_lines[@line_index].match(/\A */)
+ prev_indent = md[0].count(' ')
+ if @check_new_auto_indent
+ @buffer_of_lines[@line_index] = ' ' * new_indent + @buffer_of_lines[@line_index].lstrip
+ @cursor = new_indent
+ @byte_pointer = new_indent
+ else
+ @line = ' ' * new_indent + @line.lstrip
+ @cursor += new_indent - prev_indent
+ @byte_pointer += new_indent - prev_indent
+ end
end
- process_auto_indent
+ @check_new_auto_indent = false
end
def retrieve_completion_block(set_completion_quote_character = false)
@@ -1251,7 +1747,7 @@ class Reline::LineEditor
else
quote_characters_regexp = /\A[#{Regexp.escape(Reline.completer_quote_characters)}]/
end
- before = current_line.byteslice(0, @byte_pointer)
+ before = @line.byteslice(0, @byte_pointer)
rest = nil
break_pointer = nil
quote = nil
@@ -1259,7 +1755,7 @@ class Reline::LineEditor
escaped_quote = nil
i = 0
while i < @byte_pointer do
- slice = current_line.byteslice(i, @byte_pointer - i)
+ slice = @line.byteslice(i, @byte_pointer - i)
unless slice.valid_encoding?
i += 1
next
@@ -1281,15 +1777,15 @@ class Reline::LineEditor
elsif word_break_regexp and not quote and slice =~ word_break_regexp
rest = $'
i += 1
- before = current_line.byteslice(i, @byte_pointer - i)
+ before = @line.byteslice(i, @byte_pointer - i)
break_pointer = i
else
i += 1
end
end
- postposing = current_line.byteslice(@byte_pointer, current_line.bytesize - @byte_pointer)
+ postposing = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer)
if rest
- preposing = current_line.byteslice(0, break_pointer)
+ preposing = @line.byteslice(0, break_pointer)
target = rest
if set_completion_quote_character and quote
Reline.core.instance_variable_set(:@completion_quote_character, quote)
@@ -1300,97 +1796,133 @@ class Reline::LineEditor
else
preposing = ''
if break_pointer
- preposing = current_line.byteslice(0, break_pointer)
+ preposing = @line.byteslice(0, break_pointer)
else
preposing = ''
end
target = before
end
- lines = whole_lines
- if @line_index > 0
- preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
- end
- if (lines.size - 1) > @line_index
- postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
+ if @is_multiline
+ if @previous_line_index
+ lines = whole_lines(index: @previous_line_index, line: @line)
+ else
+ lines = whole_lines
+ end
+ if @line_index > 0
+ preposing = lines[0..(@line_index - 1)].join("\n") + "\n" + preposing
+ end
+ if (lines.size - 1) > @line_index
+ postposing = postposing + "\n" + lines[(@line_index + 1)..-1].join("\n")
+ end
end
[preposing.encode(@encoding), target.encode(@encoding), postposing.encode(@encoding)]
end
def confirm_multiline_termination
temp_buffer = @buffer_of_lines.dup
+ if @previous_line_index and @line_index == (@buffer_of_lines.size - 1)
+ temp_buffer[@previous_line_index] = @line
+ else
+ temp_buffer[@line_index] = @line
+ end
@confirm_multiline_termination_proc.(temp_buffer.join("\n") + "\n")
end
- def insert_multiline_text(text)
- save_old_buffer
- pre = @buffer_of_lines[@line_index].byteslice(0, @byte_pointer)
- post = @buffer_of_lines[@line_index].byteslice(@byte_pointer..)
- lines = (pre + Reline::Unicode.safe_encode(text, @encoding).gsub(/\r\n?/, "\n") + post).split("\n", -1)
- lines << '' if lines.empty?
- @buffer_of_lines[@line_index, 1] = lines
- @line_index += lines.size - 1
- @byte_pointer = @buffer_of_lines[@line_index].bytesize - post.bytesize
- push_input_lines
- end
-
def insert_text(text)
- if @buffer_of_lines[@line_index].bytesize == @byte_pointer
- @buffer_of_lines[@line_index] += text
+ width = calculate_width(text)
+ if @cursor == @cursor_max
+ @line += text
else
- @buffer_of_lines[@line_index] = byteinsert(@buffer_of_lines[@line_index], @byte_pointer, text)
+ @line = byteinsert(@line, @byte_pointer, text)
end
@byte_pointer += text.bytesize
- process_auto_indent
+ @cursor += width
+ @cursor_max += width
end
def delete_text(start = nil, length = nil)
if start.nil? and length.nil?
- if @buffer_of_lines.size == 1
- @buffer_of_lines[@line_index] = ''
- @byte_pointer = 0
- elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0
- @buffer_of_lines.pop
- @line_index -= 1
- @byte_pointer = 0
- elsif @line_index < (@buffer_of_lines.size - 1)
- @buffer_of_lines.delete_at(@line_index)
+ if @is_multiline
+ if @buffer_of_lines.size == 1
+ @line&.clear
+ @byte_pointer = 0
+ @cursor = 0
+ @cursor_max = 0
+ elsif @line_index == (@buffer_of_lines.size - 1) and @line_index > 0
+ @buffer_of_lines.pop
+ @line_index -= 1
+ @line = @buffer_of_lines[@line_index]
+ @byte_pointer = 0
+ @cursor = 0
+ @cursor_max = calculate_width(@line)
+ elsif @line_index < (@buffer_of_lines.size - 1)
+ @buffer_of_lines.delete_at(@line_index)
+ @line = @buffer_of_lines[@line_index]
+ @byte_pointer = 0
+ @cursor = 0
+ @cursor_max = calculate_width(@line)
+ end
+ else
+ @line&.clear
@byte_pointer = 0
+ @cursor = 0
+ @cursor_max = 0
end
elsif not start.nil? and not length.nil?
- if current_line
- before = current_line.byteslice(0, start)
- after = current_line.byteslice(start + length, current_line.bytesize)
- set_current_line(before + after)
+ if @line
+ before = @line.byteslice(0, start)
+ after = @line.byteslice(start + length, @line.bytesize)
+ @line = before + after
+ @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize
+ str = @line.byteslice(0, @byte_pointer)
+ @cursor = calculate_width(str)
+ @cursor_max = calculate_width(@line)
end
elsif start.is_a?(Range)
range = start
first = range.first
last = range.last
- last = current_line.bytesize - 1 if last > current_line.bytesize
- last += current_line.bytesize if last < 0
- first += current_line.bytesize if first < 0
+ last = @line.bytesize - 1 if last > @line.bytesize
+ last += @line.bytesize if last < 0
+ first += @line.bytesize if first < 0
range = range.exclude_end? ? first...last : first..last
- line = current_line.bytes.reject.with_index{ |c, i| range.include?(i) }.map{ |c| c.chr(Encoding::ASCII_8BIT) }.join.force_encoding(@encoding)
- set_current_line(line)
+ @line = @line.bytes.reject.with_index{ |c, i| range.include?(i) }.map{ |c| c.chr(Encoding::ASCII_8BIT) }.join.force_encoding(@encoding)
+ @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize
+ str = @line.byteslice(0, @byte_pointer)
+ @cursor = calculate_width(str)
+ @cursor_max = calculate_width(@line)
else
- set_current_line(current_line.byteslice(0, start))
+ @line = @line.byteslice(0, start)
+ @byte_pointer = @line.bytesize if @byte_pointer > @line.bytesize
+ str = @line.byteslice(0, @byte_pointer)
+ @cursor = calculate_width(str)
+ @cursor_max = calculate_width(@line)
end
end
def byte_pointer=(val)
@byte_pointer = val
+ str = @line.byteslice(0, @byte_pointer)
+ @cursor = calculate_width(str)
+ @cursor_max = calculate_width(@line)
end
- def whole_lines
- @buffer_of_lines.dup
+ def whole_lines(index: @line_index, line: @line)
+ temp_lines = @buffer_of_lines.dup
+ temp_lines[index] = line
+ temp_lines
end
def whole_buffer
- whole_lines.join("\n")
- end
-
- private def buffer_empty?
- current_line.empty? and @buffer_of_lines.size == 1
+ if @buffer_of_lines.size == 1 and @line.nil?
+ nil
+ else
+ if @previous_line_index
+ whole_lines(index: @previous_line_index, line: @line).join("\n")
+ else
+ whole_lines.join("\n")
+ end
+ end
end
def finished?
@@ -1399,6 +1931,7 @@ class Reline::LineEditor
def finish
@finished = true
+ @rerender_all = true
@config.reset
end
@@ -1420,65 +1953,40 @@ class Reline::LineEditor
end
private def key_delete(key)
- if @config.editing_mode_is?(:vi_insert)
+ if @config.editing_mode_is?(:vi_insert, :emacs)
ed_delete_next_char(key)
- elsif @config.editing_mode_is?(:emacs)
- em_delete(key)
end
end
private def key_newline(key)
if @is_multiline
- next_line = current_line.byteslice(@byte_pointer, current_line.bytesize - @byte_pointer)
- cursor_line = current_line.byteslice(0, @byte_pointer)
- insert_new_line(cursor_line, next_line)
- end
- end
-
- private def complete(_key)
- return if @config.disable_completion
-
- process_insert(force: true)
- if @config.autocompletion
- @completion_state = CompletionState::NORMAL
- @completion_occurs = move_completed_list(:down)
- else
- @completion_journey_state = nil
- result = call_completion_proc
- if result.is_a?(Array)
- @completion_occurs = true
- perform_completion(result, false)
+ if (@buffer_of_lines.size - 1) == @line_index and @line.bytesize == @byte_pointer
+ @add_newline_to_end_of_buffer = true
end
+ next_line = @line.byteslice(@byte_pointer, @line.bytesize - @byte_pointer)
+ cursor_line = @line.byteslice(0, @byte_pointer)
+ insert_new_line(cursor_line, next_line)
+ @cursor = 0
+ @check_new_auto_indent = true unless @in_pasting
end
end
- private def completion_journey_move(direction)
- return if @config.disable_completion
-
- process_insert(force: true)
- @completion_state = CompletionState::NORMAL
- @completion_occurs = move_completed_list(direction)
- end
-
- private def menu_complete(_key)
- completion_journey_move(:down)
- end
-
- private def menu_complete_backward(_key)
- completion_journey_move(:up)
- end
-
- private def completion_journey_up(_key)
- completion_journey_move(:up) if @config.autocompletion
- end
-
# Editline:: +ed-unassigned+ This editor command always results in an error.
# GNU Readline:: There is no corresponding macro.
private def ed_unassigned(key) end # do nothing
private def process_insert(force: false)
return if @continuous_insertion_buffer.empty? or (@in_pasting and not force)
- insert_text(@continuous_insertion_buffer)
+ width = Reline::Unicode.calculate_width(@continuous_insertion_buffer)
+ bytesize = @continuous_insertion_buffer.bytesize
+ if @cursor == @cursor_max
+ @line += @continuous_insertion_buffer
+ else
+ @line = byteinsert(@line, @byte_pointer, @continuous_insertion_buffer)
+ end
+ @byte_pointer += bytesize
+ @cursor += width
+ @cursor_max += width
@continuous_insertion_buffer.clear
end
@@ -1496,6 +2004,9 @@ class Reline::LineEditor
# million.
# GNU Readline:: +self-insert+ (a, b, A, 1, !, …) Insert yourself.
private def ed_insert(key)
+ str = nil
+ width = nil
+ bytesize = nil
if key.instance_of?(String)
begin
key.encode(Encoding::UTF_8)
@@ -1503,6 +2014,7 @@ class Reline::LineEditor
return
end
str = key
+ bytesize = key.bytesize
else
begin
key.chr.encode(Encoding::UTF_8)
@@ -1510,6 +2022,7 @@ class Reline::LineEditor
return
end
str = key.chr
+ bytesize = 1
end
if @in_pasting
@continuous_insertion_buffer << str
@@ -1517,8 +2030,28 @@ class Reline::LineEditor
elsif not @continuous_insertion_buffer.empty?
process_insert
end
-
- insert_text(str)
+ width = Reline::Unicode.get_mbchar_width(str)
+ if @cursor == @cursor_max
+ @line += str
+ else
+ @line = byteinsert(@line, @byte_pointer, str)
+ end
+ last_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
+ @byte_pointer += bytesize
+ last_mbchar = @line.byteslice((@byte_pointer - bytesize - last_byte_size), last_byte_size)
+ combined_char = last_mbchar + str
+ if last_byte_size != 0 and combined_char.grapheme_clusters.size == 1
+ # combined char
+ last_mbchar_width = Reline::Unicode.get_mbchar_width(last_mbchar)
+ combined_char_width = Reline::Unicode.get_mbchar_width(combined_char)
+ if combined_char_width > last_mbchar_width
+ width = combined_char_width - last_mbchar_width
+ else
+ width = 0
+ end
+ end
+ @cursor += width
+ @cursor_max += width
end
alias_method :ed_digit, :ed_insert
alias_method :self_insert, :ed_insert
@@ -1540,11 +2073,18 @@ class Reline::LineEditor
alias_method :quoted_insert, :ed_quoted_insert
private def ed_next_char(key, arg: 1)
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- if (@byte_pointer < current_line.bytesize)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
+ if (@byte_pointer < @line.bytesize)
+ mbchar = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor += width if width
@byte_pointer += byte_size
- elsif @config.editing_mode_is?(:emacs) and @byte_pointer == current_line.bytesize and @line_index < @buffer_of_lines.size - 1
+ elsif @is_multiline and @config.editing_mode_is?(:emacs) and @byte_pointer == @line.bytesize and @line_index < @buffer_of_lines.size - 1
+ next_line = @buffer_of_lines[@line_index + 1]
+ @cursor = 0
@byte_pointer = 0
+ @cursor_max = calculate_width(next_line)
+ @previous_line_index = @line_index
@line_index += 1
end
arg -= 1
@@ -1553,12 +2093,19 @@ class Reline::LineEditor
alias_method :forward_char, :ed_next_char
private def ed_prev_char(key, arg: 1)
- if @byte_pointer > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
+ if @cursor > 0
+ byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
@byte_pointer -= byte_size
- elsif @config.editing_mode_is?(:emacs) and @byte_pointer == 0 and @line_index > 0
+ mbchar = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor -= width
+ elsif @is_multiline and @config.editing_mode_is?(:emacs) and @byte_pointer == 0 and @line_index > 0
+ prev_line = @buffer_of_lines[@line_index - 1]
+ @cursor = calculate_width(prev_line)
+ @byte_pointer = prev_line.bytesize
+ @cursor_max = calculate_width(prev_line)
+ @previous_line_index = @line_index
@line_index -= 1
- @byte_pointer = current_line.bytesize
end
arg -= 1
ed_prev_char(key, arg: arg) if arg > 0
@@ -1566,128 +2113,230 @@ class Reline::LineEditor
alias_method :backward_char, :ed_prev_char
private def vi_first_print(key)
- @byte_pointer, = Reline::Unicode.vi_first_print(current_line)
+ @byte_pointer, @cursor = Reline::Unicode.vi_first_print(@line)
end
private def ed_move_to_beg(key)
- @byte_pointer = 0
+ @byte_pointer = @cursor = 0
end
alias_method :beginning_of_line, :ed_move_to_beg
- alias_method :vi_zero, :ed_move_to_beg
private def ed_move_to_end(key)
- @byte_pointer = current_line.bytesize
+ @byte_pointer = 0
+ @cursor = 0
+ byte_size = 0
+ while @byte_pointer < @line.bytesize
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
+ if byte_size > 0
+ mbchar = @line.byteslice(@byte_pointer, byte_size)
+ @cursor += Reline::Unicode.get_mbchar_width(mbchar)
+ end
+ @byte_pointer += byte_size
+ end
end
alias_method :end_of_line, :ed_move_to_end
- private def generate_searcher(search_key)
- search_word = String.new(encoding: @encoding)
- multibyte_buf = String.new(encoding: 'ASCII-8BIT')
- hit_pointer = nil
- lambda do |key|
- search_again = false
- case key
- when "\C-h".ord, "\C-?".ord
- grapheme_clusters = search_word.grapheme_clusters
- if grapheme_clusters.size > 0
- grapheme_clusters.pop
- search_word = grapheme_clusters.join
- end
- when "\C-r".ord, "\C-s".ord
- search_again = true if search_key == key
- search_key = key
- else
- multibyte_buf << key
- if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
- search_word << multibyte_buf.dup.force_encoding(@encoding)
- multibyte_buf.clear
- end
+ private def generate_searcher
+ Fiber.new do |first_key|
+ prev_search_key = first_key
+ search_word = String.new(encoding: @encoding)
+ multibyte_buf = String.new(encoding: 'ASCII-8BIT')
+ last_hit = nil
+ case first_key
+ when "\C-r".ord
+ prompt_name = 'reverse-i-search'
+ when "\C-s".ord
+ prompt_name = 'i-search'
end
- hit = nil
- if not search_word.empty? and @line_backup_in_history&.include?(search_word)
- hit_pointer = Reline::HISTORY.size
- hit = @line_backup_in_history
- else
- if search_again
- if search_word.empty? and Reline.last_incremental_search
- search_word = Reline.last_incremental_search
+ loop do
+ key = Fiber.yield(search_word)
+ search_again = false
+ case key
+ when -1 # determined
+ Reline.last_incremental_search = search_word
+ break
+ when "\C-h".ord, "\C-?".ord
+ grapheme_clusters = search_word.grapheme_clusters
+ if grapheme_clusters.size > 0
+ grapheme_clusters.pop
+ search_word = grapheme_clusters.join
end
- if @history_pointer
- case search_key
+ when "\C-r".ord, "\C-s".ord
+ search_again = true if prev_search_key == key
+ prev_search_key = key
+ else
+ multibyte_buf << key
+ if multibyte_buf.dup.force_encoding(@encoding).valid_encoding?
+ search_word << multibyte_buf.dup.force_encoding(@encoding)
+ multibyte_buf.clear
+ end
+ end
+ hit = nil
+ if not search_word.empty? and @line_backup_in_history&.include?(search_word)
+ @history_pointer = nil
+ hit = @line_backup_in_history
+ else
+ if search_again
+ if search_word.empty? and Reline.last_incremental_search
+ search_word = Reline.last_incremental_search
+ end
+ if @history_pointer
+ case prev_search_key
+ when "\C-r".ord
+ history_pointer_base = 0
+ history = Reline::HISTORY[0..(@history_pointer - 1)]
+ when "\C-s".ord
+ history_pointer_base = @history_pointer + 1
+ history = Reline::HISTORY[(@history_pointer + 1)..-1]
+ end
+ else
+ history_pointer_base = 0
+ history = Reline::HISTORY
+ end
+ elsif @history_pointer
+ case prev_search_key
when "\C-r".ord
history_pointer_base = 0
- history = Reline::HISTORY[0..(@history_pointer - 1)]
+ history = Reline::HISTORY[0..@history_pointer]
when "\C-s".ord
- history_pointer_base = @history_pointer + 1
- history = Reline::HISTORY[(@history_pointer + 1)..-1]
+ history_pointer_base = @history_pointer
+ history = Reline::HISTORY[@history_pointer..-1]
end
else
history_pointer_base = 0
history = Reline::HISTORY
end
- elsif @history_pointer
- case search_key
+ case prev_search_key
when "\C-r".ord
- history_pointer_base = 0
- history = Reline::HISTORY[0..@history_pointer]
+ hit_index = history.rindex { |item|
+ item.include?(search_word)
+ }
when "\C-s".ord
- history_pointer_base = @history_pointer
- history = Reline::HISTORY[@history_pointer..-1]
+ hit_index = history.index { |item|
+ item.include?(search_word)
+ }
+ end
+ if hit_index
+ @history_pointer = history_pointer_base + hit_index
+ hit = Reline::HISTORY[@history_pointer]
end
- else
- history_pointer_base = 0
- history = Reline::HISTORY
end
- case search_key
+ case prev_search_key
when "\C-r".ord
- hit_index = history.rindex { |item|
- item.include?(search_word)
- }
+ prompt_name = 'reverse-i-search'
when "\C-s".ord
- hit_index = history.index { |item|
- item.include?(search_word)
- }
+ prompt_name = 'i-search'
end
- if hit_index
- hit_pointer = history_pointer_base + hit_index
- hit = Reline::HISTORY[hit_pointer]
+ if hit
+ if @is_multiline
+ @buffer_of_lines = hit.split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = @buffer_of_lines.size - 1
+ @line = @buffer_of_lines.last
+ @byte_pointer = @line.bytesize
+ @cursor = @cursor_max = calculate_width(@line)
+ @rerender_all = true
+ @searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
+ else
+ @line = hit
+ @searching_prompt = "(%s)`%s': %s" % [prompt_name, search_word, hit]
+ end
+ last_hit = hit
+ else
+ if @is_multiline
+ @rerender_all = true
+ @searching_prompt = "(failed %s)`%s'" % [prompt_name, search_word]
+ else
+ @searching_prompt = "(failed %s)`%s': %s" % [prompt_name, search_word, last_hit]
+ end
end
end
- case search_key
- when "\C-r".ord
- prompt_name = 'reverse-i-search'
- when "\C-s".ord
- prompt_name = 'i-search'
- end
- prompt_name = "failed #{prompt_name}" unless hit
- [search_word, prompt_name, hit_pointer]
end
end
private def incremental_search_history(key)
- backup = @buffer_of_lines.dup, @line_index, @byte_pointer, @history_pointer, @line_backup_in_history
- searcher = generate_searcher(key)
+ unless @history_pointer
+ if @is_multiline
+ @line_backup_in_history = whole_buffer
+ else
+ @line_backup_in_history = @line
+ end
+ end
+ searcher = generate_searcher
+ searcher.resume(key)
@searching_prompt = "(reverse-i-search)`': "
termination_keys = ["\C-j".ord]
- termination_keys.concat(@config.isearch_terminators.chars.map(&:ord)) if @config.isearch_terminators
+ termination_keys.concat(@config.isearch_terminators&.chars&.map(&:ord)) if @config.isearch_terminators
@waiting_proc = ->(k) {
- chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
- if k == "\C-g".ord
- # cancel search and restore buffer
- @buffer_of_lines, @line_index, @byte_pointer, @history_pointer, @line_backup_in_history = backup
+ case k
+ when *termination_keys
+ if @history_pointer
+ buffer = Reline::HISTORY[@history_pointer]
+ else
+ buffer = @line_backup_in_history
+ end
+ if @is_multiline
+ @buffer_of_lines = buffer.split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = @buffer_of_lines.size - 1
+ @line = @buffer_of_lines.last
+ @rerender_all = true
+ else
+ @line = buffer
+ end
@searching_prompt = nil
@waiting_proc = nil
- elsif !termination_keys.include?(k) && (chr.match?(/[[:print:]]/) || k == "\C-h".ord || k == "\C-?".ord || k == "\C-r".ord || k == "\C-s".ord)
- search_word, prompt_name, hit_pointer = searcher.call(k)
- Reline.last_incremental_search = search_word
- @searching_prompt = "(%s)`%s'" % [prompt_name, search_word]
- @searching_prompt += ': ' unless @is_multiline
- move_history(hit_pointer, line: :end, cursor: :end) if hit_pointer
- else
- # terminaton_keys and other keys will terminalte
- move_history(@history_pointer, line: :end, cursor: :start)
+ @cursor_max = calculate_width(@line)
+ @cursor = @byte_pointer = 0
+ @rerender_all = true
+ @cached_prompt_list = nil
+ searcher.resume(-1)
+ when "\C-g".ord
+ if @is_multiline
+ @buffer_of_lines = @line_backup_in_history.split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = @buffer_of_lines.size - 1
+ @line = @buffer_of_lines.last
+ @rerender_all = true
+ else
+ @line = @line_backup_in_history
+ end
+ @history_pointer = nil
@searching_prompt = nil
@waiting_proc = nil
+ @line_backup_in_history = nil
+ @cursor_max = calculate_width(@line)
+ @cursor = @byte_pointer = 0
+ @rerender_all = true
+ else
+ chr = k.is_a?(String) ? k : k.chr(Encoding::ASCII_8BIT)
+ if chr.match?(/[[:print:]]/) or k == "\C-h".ord or k == "\C-?".ord or k == "\C-r".ord or k == "\C-s".ord
+ searcher.resume(k)
+ else
+ if @history_pointer
+ line = Reline::HISTORY[@history_pointer]
+ else
+ line = @line_backup_in_history
+ end
+ if @is_multiline
+ @line_backup_in_history = whole_buffer
+ @buffer_of_lines = line.split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = @buffer_of_lines.size - 1
+ @line = @buffer_of_lines.last
+ @rerender_all = true
+ else
+ @line_backup_in_history = @line
+ @line = line
+ end
+ @searching_prompt = nil
+ @waiting_proc = nil
+ @cursor_max = calculate_width(@line)
+ @cursor = @byte_pointer = 0
+ @rerender_all = true
+ @cached_prompt_list = nil
+ searcher.resume(-1)
+ end
end
}
end
@@ -1702,97 +2351,199 @@ class Reline::LineEditor
end
alias_method :forward_search_history, :vi_search_next
- private def search_history(prefix, pointer_range)
- pointer_range.each do |pointer|
- lines = Reline::HISTORY[pointer].split("\n")
- lines.each_with_index do |line, index|
- return [pointer, index] if line.start_with?(prefix)
- end
- end
- nil
- end
-
private def ed_search_prev_history(key, arg: 1)
- substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
- return if @history_pointer == 0
- return if @history_pointer.nil? && substr.empty? && !current_line.empty?
-
- history_range = 0...(@history_pointer || Reline::HISTORY.size)
- h_pointer, line_index = search_history(substr, history_range.reverse_each)
- return unless h_pointer
- move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
+ history = nil
+ h_pointer = nil
+ line_no = nil
+ substr = @line.slice(0, @byte_pointer)
+ if @history_pointer.nil?
+ return if not @line.empty? and substr.empty?
+ history = Reline::HISTORY
+ elsif @history_pointer.zero?
+ history = nil
+ h_pointer = nil
+ else
+ history = Reline::HISTORY.slice(0, @history_pointer)
+ end
+ return if history.nil?
+ if @is_multiline
+ h_pointer = history.rindex { |h|
+ h.split("\n").each_with_index { |l, i|
+ if l.start_with?(substr)
+ line_no = i
+ break
+ end
+ }
+ not line_no.nil?
+ }
+ else
+ h_pointer = history.rindex { |l|
+ l.start_with?(substr)
+ }
+ end
+ return if h_pointer.nil?
+ @history_pointer = h_pointer
+ if @is_multiline
+ @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = line_no
+ @line = @buffer_of_lines[@line_index]
+ @rerender_all = true
+ else
+ @line = Reline::HISTORY[@history_pointer]
+ end
+ @cursor_max = calculate_width(@line)
arg -= 1
- set_next_action_state(:search_history, :empty) if substr.empty?
ed_search_prev_history(key, arg: arg) if arg > 0
end
alias_method :history_search_backward, :ed_search_prev_history
private def ed_search_next_history(key, arg: 1)
- substr = prev_action_state_value(:search_history) == :empty ? '' : current_line.byteslice(0, @byte_pointer)
- return if @history_pointer.nil?
-
- history_range = @history_pointer + 1...Reline::HISTORY.size
- h_pointer, line_index = search_history(substr, history_range)
- return if h_pointer.nil? and not substr.empty?
-
- move_history(h_pointer, line: line_index || :start, cursor: substr.empty? ? :end : @byte_pointer)
- arg -= 1
- set_next_action_state(:search_history, :empty) if substr.empty?
- ed_search_next_history(key, arg: arg) if arg > 0
- end
- alias_method :history_search_forward, :ed_search_next_history
-
- private def move_history(history_pointer, line:, cursor:)
- history_pointer ||= Reline::HISTORY.size
- return if history_pointer < 0 || history_pointer > Reline::HISTORY.size
- old_history_pointer = @history_pointer || Reline::HISTORY.size
- if old_history_pointer == Reline::HISTORY.size
- @line_backup_in_history = whole_buffer
+ substr = @line.slice(0, @byte_pointer)
+ if @history_pointer.nil?
+ return
+ elsif @history_pointer == (Reline::HISTORY.size - 1) and not substr.empty?
+ return
+ end
+ history = Reline::HISTORY.slice((@history_pointer + 1)..-1)
+ h_pointer = nil
+ line_no = nil
+ if @is_multiline
+ h_pointer = history.index { |h|
+ h.split("\n").each_with_index { |l, i|
+ if l.start_with?(substr)
+ line_no = i
+ break
+ end
+ }
+ not line_no.nil?
+ }
else
- Reline::HISTORY[old_history_pointer] = whole_buffer
+ h_pointer = history.index { |l|
+ l.start_with?(substr)
+ }
end
- if history_pointer == Reline::HISTORY.size
- buf = @line_backup_in_history
- @history_pointer = @line_backup_in_history = nil
+ h_pointer += @history_pointer + 1 if h_pointer and @history_pointer
+ return if h_pointer.nil? and not substr.empty?
+ @history_pointer = h_pointer
+ if @is_multiline
+ if @history_pointer.nil? and substr.empty?
+ @buffer_of_lines = []
+ @line_index = 0
+ else
+ @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
+ @line_index = line_no
+ end
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line = @buffer_of_lines[@line_index]
+ @rerender_all = true
else
- buf = Reline::HISTORY[history_pointer]
- @history_pointer = history_pointer
+ if @history_pointer.nil? and substr.empty?
+ @line = ''
+ else
+ @line = Reline::HISTORY[@history_pointer]
+ end
end
- @buffer_of_lines = buf.split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = line == :start ? 0 : line == :end ? @buffer_of_lines.size - 1 : line
- @byte_pointer = cursor == :start ? 0 : cursor == :end ? current_line.bytesize : cursor
+ @cursor_max = calculate_width(@line)
+ arg -= 1
+ ed_search_next_history(key, arg: arg) if arg > 0
end
+ alias_method :history_search_forward, :ed_search_next_history
private def ed_prev_history(key, arg: 1)
- if @line_index > 0
- cursor = current_byte_pointer_cursor
+ if @is_multiline and @line_index > 0
+ @previous_line_index = @line_index
@line_index -= 1
- calculate_nearest_cursor(cursor)
return
end
- move_history(
- (@history_pointer || Reline::HISTORY.size) - 1,
- line: :end,
- cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
- )
+ if Reline::HISTORY.empty?
+ return
+ end
+ if @history_pointer.nil?
+ @history_pointer = Reline::HISTORY.size - 1
+ if @is_multiline
+ @line_backup_in_history = whole_buffer
+ @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = @buffer_of_lines.size - 1
+ @line = @buffer_of_lines.last
+ @rerender_all = true
+ else
+ @line_backup_in_history = @line
+ @line = Reline::HISTORY[@history_pointer]
+ end
+ elsif @history_pointer.zero?
+ return
+ else
+ if @is_multiline
+ Reline::HISTORY[@history_pointer] = whole_buffer
+ @history_pointer -= 1
+ @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = @buffer_of_lines.size - 1
+ @line = @buffer_of_lines.last
+ @rerender_all = true
+ else
+ Reline::HISTORY[@history_pointer] = @line
+ @history_pointer -= 1
+ @line = Reline::HISTORY[@history_pointer]
+ end
+ end
+ if @config.editing_mode_is?(:emacs, :vi_insert)
+ @cursor_max = @cursor = calculate_width(@line)
+ @byte_pointer = @line.bytesize
+ elsif @config.editing_mode_is?(:vi_command)
+ @byte_pointer = @cursor = 0
+ @cursor_max = calculate_width(@line)
+ end
arg -= 1
ed_prev_history(key, arg: arg) if arg > 0
end
alias_method :previous_history, :ed_prev_history
private def ed_next_history(key, arg: 1)
- if @line_index < (@buffer_of_lines.size - 1)
- cursor = current_byte_pointer_cursor
+ if @is_multiline and @line_index < (@buffer_of_lines.size - 1)
+ @previous_line_index = @line_index
@line_index += 1
- calculate_nearest_cursor(cursor)
return
end
- move_history(
- (@history_pointer || Reline::HISTORY.size) + 1,
- line: :start,
- cursor: @config.editing_mode_is?(:vi_command) ? :start : :end,
- )
+ if @history_pointer.nil?
+ return
+ elsif @history_pointer == (Reline::HISTORY.size - 1)
+ if @is_multiline
+ @history_pointer = nil
+ @buffer_of_lines = @line_backup_in_history.split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = 0
+ @line = @buffer_of_lines.first
+ @rerender_all = true
+ else
+ @history_pointer = nil
+ @line = @line_backup_in_history
+ end
+ else
+ if @is_multiline
+ Reline::HISTORY[@history_pointer] = whole_buffer
+ @history_pointer += 1
+ @buffer_of_lines = Reline::HISTORY[@history_pointer].split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = 0
+ @line = @buffer_of_lines.first
+ @rerender_all = true
+ else
+ Reline::HISTORY[@history_pointer] = @line
+ @history_pointer += 1
+ @line = Reline::HISTORY[@history_pointer]
+ end
+ end
+ @line = '' unless @line
+ if @config.editing_mode_is?(:emacs, :vi_insert)
+ @cursor_max = @cursor = calculate_width(@line)
+ @byte_pointer = @line.bytesize
+ elsif @config.editing_mode_is?(:vi_command)
+ @byte_pointer = @cursor = 0
+ @cursor_max = calculate_width(@line)
+ end
arg -= 1
ed_next_history(key, arg: arg) if arg > 0
end
@@ -1817,29 +2568,40 @@ class Reline::LineEditor
end
else
# should check confirm_multiline_termination to finish?
+ @previous_line_index = @line_index
@line_index = @buffer_of_lines.size - 1
- @byte_pointer = current_line.bytesize
finish
end
end
else
+ if @history_pointer
+ Reline::HISTORY[@history_pointer] = @line
+ @history_pointer = nil
+ end
finish
end
end
private def em_delete_prev_char(key, arg: 1)
- arg.times do
- if @byte_pointer == 0 and @line_index > 0
- @byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
- @buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
- @line_index -= 1
- elsif @byte_pointer > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
- line, = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
- set_current_line(line, @byte_pointer - byte_size)
- end
+ if @is_multiline and @cursor == 0 and @line_index > 0
+ @buffer_of_lines[@line_index] = @line
+ @cursor = calculate_width(@buffer_of_lines[@line_index - 1])
+ @byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
+ @buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
+ @line_index -= 1
+ @line = @buffer_of_lines[@line_index]
+ @cursor_max = calculate_width(@line)
+ @rerender_all = true
+ elsif @cursor > 0
+ byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
+ @byte_pointer -= byte_size
+ @line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor -= width
+ @cursor_max -= width
end
- process_auto_indent
+ arg -= 1
+ em_delete_prev_char(key, arg: arg) if arg > 0
end
alias_method :backward_delete_char, :em_delete_prev_char
@@ -1849,23 +2611,23 @@ class Reline::LineEditor
# the line. With a negative numeric argument, kill backward
# from the cursor to the beginning of the current line.
private def ed_kill_line(key)
- if current_line.bytesize > @byte_pointer
- line, deleted = byteslice!(current_line, @byte_pointer, current_line.bytesize - @byte_pointer)
- set_current_line(line, line.bytesize)
+ if @line.bytesize > @byte_pointer
+ @line, deleted = byteslice!(@line, @byte_pointer, @line.bytesize - @byte_pointer)
+ @byte_pointer = @line.bytesize
+ @cursor = @cursor_max = calculate_width(@line)
@kill_ring.append(deleted)
- elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
- set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
+ elsif @is_multiline and @byte_pointer == @line.bytesize and @buffer_of_lines.size > @line_index + 1
+ @cursor = calculate_width(@line)
+ @byte_pointer = @line.bytesize
+ @line += @buffer_of_lines.delete_at(@line_index + 1)
+ @cursor_max = calculate_width(@line)
+ @buffer_of_lines[@line_index] = @line
+ @rerender_all = true
+ @rest_height += 1
end
end
alias_method :kill_line, :ed_kill_line
- # Editline:: +vi_change_to_eol+ (vi command: +C+) + Kill and change from the cursor to the end of the line.
- private def vi_change_to_eol(key)
- ed_kill_line(key)
-
- @config.editing_mode = :vi_insert
- end
-
# Editline:: +vi-kill-line-prev+ (vi: +Ctrl-U+) Delete the string from the
# beginning of the edit buffer to the cursor and save it to the
# cut buffer.
@@ -1873,9 +2635,11 @@ class Reline::LineEditor
# to the beginning of the current line.
private def vi_kill_line_prev(key)
if @byte_pointer > 0
- line, deleted = byteslice!(current_line, 0, @byte_pointer)
- set_current_line(line, 0)
+ @line, deleted = byteslice!(@line, 0, @byte_pointer)
+ @byte_pointer = 0
@kill_ring.append(deleted, true)
+ @cursor_max = calculate_width(@line)
+ @cursor = 0
end
end
alias_method :unix_line_discard, :vi_kill_line_prev
@@ -1885,35 +2649,50 @@ class Reline::LineEditor
# GNU Readline:: +kill-whole-line+ (not bound) Kill all characters on the
# current line, no matter where point is.
private def em_kill_line(key)
- if current_line.size > 0
- @kill_ring.append(current_line.dup, true)
- set_current_line('', 0)
+ if @line.size > 0
+ @kill_ring.append(@line.dup, true)
+ @line.clear
+ @byte_pointer = 0
+ @cursor_max = 0
+ @cursor = 0
end
end
alias_method :kill_whole_line, :em_kill_line
private def em_delete(key)
- if buffer_empty? and key == "\C-d".ord
+ if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
+ @line = nil
+ if @buffer_of_lines.size > 1
+ scroll_down(@highest_in_all - @first_line_started_from)
+ end
+ Reline::IOGate.move_cursor_column(0)
@eof = true
finish
- elsif @byte_pointer < current_line.bytesize
- splitted_last = current_line.byteslice(@byte_pointer, current_line.bytesize)
+ elsif @byte_pointer < @line.bytesize
+ splitted_last = @line.byteslice(@byte_pointer, @line.bytesize)
mbchar = splitted_last.grapheme_clusters.first
- line, = byteslice!(current_line, @byte_pointer, mbchar.bytesize)
- set_current_line(line)
- elsif @byte_pointer == current_line.bytesize and @buffer_of_lines.size > @line_index + 1
- set_current_line(current_line + @buffer_of_lines.delete_at(@line_index + 1), current_line.bytesize)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor_max -= width
+ @line, = byteslice!(@line, @byte_pointer, mbchar.bytesize)
+ elsif @is_multiline and @byte_pointer == @line.bytesize and @buffer_of_lines.size > @line_index + 1
+ @cursor = calculate_width(@line)
+ @byte_pointer = @line.bytesize
+ @line += @buffer_of_lines.delete_at(@line_index + 1)
+ @cursor_max = calculate_width(@line)
+ @buffer_of_lines[@line_index] = @line
+ @rerender_all = true
+ @rest_height += 1
end
end
alias_method :delete_char, :em_delete
private def em_delete_or_list(key)
- if current_line.empty? or @byte_pointer < current_line.bytesize
+ if @line.empty? or @byte_pointer < @line.bytesize
em_delete(key)
- elsif !@config.autocompletion # show completed list
+ else # show completed list
result = call_completion_proc
if result.is_a?(Array)
- perform_completion(result, true)
+ complete(result, true)
end
end
end
@@ -1921,135 +2700,162 @@ class Reline::LineEditor
private def em_yank(key)
yanked = @kill_ring.yank
- insert_text(yanked) if yanked
+ if yanked
+ @line = byteinsert(@line, @byte_pointer, yanked)
+ yanked_width = calculate_width(yanked)
+ @cursor += yanked_width
+ @cursor_max += yanked_width
+ @byte_pointer += yanked.bytesize
+ end
end
alias_method :yank, :em_yank
private def em_yank_pop(key)
yanked, prev_yank = @kill_ring.yank_pop
if yanked
- line, = byteslice!(current_line, @byte_pointer - prev_yank.bytesize, prev_yank.bytesize)
- set_current_line(line, @byte_pointer - prev_yank.bytesize)
- insert_text(yanked)
+ prev_yank_width = calculate_width(prev_yank)
+ @cursor -= prev_yank_width
+ @cursor_max -= prev_yank_width
+ @byte_pointer -= prev_yank.bytesize
+ @line, = byteslice!(@line, @byte_pointer, prev_yank.bytesize)
+ @line = byteinsert(@line, @byte_pointer, yanked)
+ yanked_width = calculate_width(yanked)
+ @cursor += yanked_width
+ @cursor_max += yanked_width
+ @byte_pointer += yanked.bytesize
end
end
alias_method :yank_pop, :em_yank_pop
private def ed_clear_screen(key)
- Reline::IOGate.clear_screen
- @screen_size = Reline::IOGate.get_screen_size
- @rendered_screen.base_y = 0
- clear_rendered_screen_cache
+ @cleared = true
end
alias_method :clear_screen, :ed_clear_screen
private def em_next_word(key)
- if current_line.bytesize > @byte_pointer
- byte_size, _ = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
+ if @line.bytesize > @byte_pointer
+ byte_size, width = Reline::Unicode.em_forward_word(@line, @byte_pointer)
@byte_pointer += byte_size
+ @cursor += width
end
end
alias_method :forward_word, :em_next_word
private def ed_prev_word(key)
if @byte_pointer > 0
- byte_size, _ = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
+ byte_size, width = Reline::Unicode.em_backward_word(@line, @byte_pointer)
@byte_pointer -= byte_size
+ @cursor -= width
end
end
alias_method :backward_word, :ed_prev_word
private def em_delete_next_word(key)
- if current_line.bytesize > @byte_pointer
- byte_size, _ = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
- line, word = byteslice!(current_line, @byte_pointer, byte_size)
- set_current_line(line)
+ if @line.bytesize > @byte_pointer
+ byte_size, width = Reline::Unicode.em_forward_word(@line, @byte_pointer)
+ @line, word = byteslice!(@line, @byte_pointer, byte_size)
@kill_ring.append(word)
+ @cursor_max -= width
end
end
- alias_method :kill_word, :em_delete_next_word
private def ed_delete_prev_word(key)
if @byte_pointer > 0
- byte_size, _ = Reline::Unicode.em_backward_word(current_line, @byte_pointer)
- line, word = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
- set_current_line(line, @byte_pointer - byte_size)
+ byte_size, width = Reline::Unicode.em_backward_word(@line, @byte_pointer)
+ @line, word = byteslice!(@line, @byte_pointer - byte_size, byte_size)
@kill_ring.append(word, true)
+ @byte_pointer -= byte_size
+ @cursor -= width
+ @cursor_max -= width
end
end
- alias_method :backward_kill_word, :ed_delete_prev_word
private def ed_transpose_chars(key)
if @byte_pointer > 0
- if @byte_pointer < current_line.bytesize
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
+ if @cursor_max > @cursor
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
+ mbchar = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor += width
@byte_pointer += byte_size
end
- back1_byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
+ back1_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
if (@byte_pointer - back1_byte_size) > 0
- back2_byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer - back1_byte_size)
+ back2_byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer - back1_byte_size)
back2_pointer = @byte_pointer - back1_byte_size - back2_byte_size
- line, back2_mbchar = byteslice!(current_line, back2_pointer, back2_byte_size)
- set_current_line(byteinsert(line, @byte_pointer - back2_byte_size, back2_mbchar))
+ @line, back2_mbchar = byteslice!(@line, back2_pointer, back2_byte_size)
+ @line = byteinsert(@line, @byte_pointer - back2_byte_size, back2_mbchar)
end
end
end
alias_method :transpose_chars, :ed_transpose_chars
private def ed_transpose_words(key)
- left_word_start, middle_start, right_word_start, after_start = Reline::Unicode.ed_transpose_words(current_line, @byte_pointer)
- before = current_line.byteslice(0, left_word_start)
- left_word = current_line.byteslice(left_word_start, middle_start - left_word_start)
- middle = current_line.byteslice(middle_start, right_word_start - middle_start)
- right_word = current_line.byteslice(right_word_start, after_start - right_word_start)
- after = current_line.byteslice(after_start, current_line.bytesize - after_start)
+ left_word_start, middle_start, right_word_start, after_start = Reline::Unicode.ed_transpose_words(@line, @byte_pointer)
+ before = @line.byteslice(0, left_word_start)
+ left_word = @line.byteslice(left_word_start, middle_start - left_word_start)
+ middle = @line.byteslice(middle_start, right_word_start - middle_start)
+ right_word = @line.byteslice(right_word_start, after_start - right_word_start)
+ after = @line.byteslice(after_start, @line.bytesize - after_start)
return if left_word.empty? or right_word.empty?
+ @line = before + right_word + middle + left_word + after
from_head_to_left_word = before + right_word + middle + left_word
- set_current_line(from_head_to_left_word + after, from_head_to_left_word.bytesize)
+ @byte_pointer = from_head_to_left_word.bytesize
+ @cursor = calculate_width(from_head_to_left_word)
end
alias_method :transpose_words, :ed_transpose_words
private def em_capitol_case(key)
- if current_line.bytesize > @byte_pointer
- byte_size, _, new_str = Reline::Unicode.em_forward_word_with_capitalization(current_line, @byte_pointer)
- before = current_line.byteslice(0, @byte_pointer)
- after = current_line.byteslice((@byte_pointer + byte_size)..-1)
- set_current_line(before + new_str + after, @byte_pointer + new_str.bytesize)
+ if @line.bytesize > @byte_pointer
+ byte_size, _, new_str = Reline::Unicode.em_forward_word_with_capitalization(@line, @byte_pointer)
+ before = @line.byteslice(0, @byte_pointer)
+ after = @line.byteslice((@byte_pointer + byte_size)..-1)
+ @line = before + new_str + after
+ @byte_pointer += new_str.bytesize
+ @cursor += calculate_width(new_str)
end
end
alias_method :capitalize_word, :em_capitol_case
private def em_lower_case(key)
- if current_line.bytesize > @byte_pointer
- byte_size, = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
- part = current_line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
+ if @line.bytesize > @byte_pointer
+ byte_size, = Reline::Unicode.em_forward_word(@line, @byte_pointer)
+ part = @line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
mbchar =~ /[A-Z]/ ? mbchar.downcase : mbchar
}.join
- rest = current_line.byteslice((@byte_pointer + byte_size)..-1)
- line = current_line.byteslice(0, @byte_pointer) + part
- set_current_line(line + rest, line.bytesize)
+ rest = @line.byteslice((@byte_pointer + byte_size)..-1)
+ @line = @line.byteslice(0, @byte_pointer) + part
+ @byte_pointer = @line.bytesize
+ @cursor = calculate_width(@line)
+ @cursor_max = @cursor + calculate_width(rest)
+ @line += rest
end
end
alias_method :downcase_word, :em_lower_case
private def em_upper_case(key)
- if current_line.bytesize > @byte_pointer
- byte_size, = Reline::Unicode.em_forward_word(current_line, @byte_pointer)
- part = current_line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
+ if @line.bytesize > @byte_pointer
+ byte_size, = Reline::Unicode.em_forward_word(@line, @byte_pointer)
+ part = @line.byteslice(@byte_pointer, byte_size).grapheme_clusters.map { |mbchar|
mbchar =~ /[a-z]/ ? mbchar.upcase : mbchar
}.join
- rest = current_line.byteslice((@byte_pointer + byte_size)..-1)
- line = current_line.byteslice(0, @byte_pointer) + part
- set_current_line(line + rest, line.bytesize)
+ rest = @line.byteslice((@byte_pointer + byte_size)..-1)
+ @line = @line.byteslice(0, @byte_pointer) + part
+ @byte_pointer = @line.bytesize
+ @cursor = calculate_width(@line)
+ @cursor_max = @cursor + calculate_width(rest)
+ @line += rest
end
end
alias_method :upcase_word, :em_upper_case
private def em_kill_region(key)
if @byte_pointer > 0
- byte_size, _ = Reline::Unicode.em_big_backward_word(current_line, @byte_pointer)
- line, deleted = byteslice!(current_line, @byte_pointer - byte_size, byte_size)
- set_current_line(line, @byte_pointer - byte_size)
+ byte_size, width = Reline::Unicode.em_big_backward_word(@line, @byte_pointer)
+ @line, deleted = byteslice!(@line, @byte_pointer - byte_size, byte_size)
+ @byte_pointer -= byte_size
+ @cursor -= width
+ @cursor_max -= width
@kill_ring.append(deleted, true)
end
end
@@ -2077,9 +2883,10 @@ class Reline::LineEditor
alias_method :vi_movement_mode, :vi_command_mode
private def vi_next_word(key, arg: 1)
- if current_line.bytesize > @byte_pointer
- byte_size, _ = Reline::Unicode.vi_forward_word(current_line, @byte_pointer, @drop_terminate_spaces)
+ if @line.bytesize > @byte_pointer
+ byte_size, width = Reline::Unicode.vi_forward_word(@line, @byte_pointer, @drop_terminate_spaces)
@byte_pointer += byte_size
+ @cursor += width
end
arg -= 1
vi_next_word(key, arg: arg) if arg > 0
@@ -2087,32 +2894,38 @@ class Reline::LineEditor
private def vi_prev_word(key, arg: 1)
if @byte_pointer > 0
- byte_size, _ = Reline::Unicode.vi_backward_word(current_line, @byte_pointer)
+ byte_size, width = Reline::Unicode.vi_backward_word(@line, @byte_pointer)
@byte_pointer -= byte_size
+ @cursor -= width
end
arg -= 1
vi_prev_word(key, arg: arg) if arg > 0
end
private def vi_end_word(key, arg: 1, inclusive: false)
- if current_line.bytesize > @byte_pointer
- byte_size, _ = Reline::Unicode.vi_forward_end_word(current_line, @byte_pointer)
+ if @line.bytesize > @byte_pointer
+ byte_size, width = Reline::Unicode.vi_forward_end_word(@line, @byte_pointer)
@byte_pointer += byte_size
+ @cursor += width
end
arg -= 1
if inclusive and arg.zero?
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
if byte_size > 0
+ c = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(c)
@byte_pointer += byte_size
+ @cursor += width
end
end
vi_end_word(key, arg: arg) if arg > 0
end
private def vi_next_big_word(key, arg: 1)
- if current_line.bytesize > @byte_pointer
- byte_size, _ = Reline::Unicode.vi_big_forward_word(current_line, @byte_pointer)
+ if @line.bytesize > @byte_pointer
+ byte_size, width = Reline::Unicode.vi_big_forward_word(@line, @byte_pointer)
@byte_pointer += byte_size
+ @cursor += width
end
arg -= 1
vi_next_big_word(key, arg: arg) if arg > 0
@@ -2120,39 +2933,50 @@ class Reline::LineEditor
private def vi_prev_big_word(key, arg: 1)
if @byte_pointer > 0
- byte_size, _ = Reline::Unicode.vi_big_backward_word(current_line, @byte_pointer)
+ byte_size, width = Reline::Unicode.vi_big_backward_word(@line, @byte_pointer)
@byte_pointer -= byte_size
+ @cursor -= width
end
arg -= 1
vi_prev_big_word(key, arg: arg) if arg > 0
end
private def vi_end_big_word(key, arg: 1, inclusive: false)
- if current_line.bytesize > @byte_pointer
- byte_size, _ = Reline::Unicode.vi_big_forward_end_word(current_line, @byte_pointer)
+ if @line.bytesize > @byte_pointer
+ byte_size, width = Reline::Unicode.vi_big_forward_end_word(@line, @byte_pointer)
@byte_pointer += byte_size
+ @cursor += width
end
arg -= 1
if inclusive and arg.zero?
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
if byte_size > 0
+ c = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(c)
@byte_pointer += byte_size
+ @cursor += width
end
end
vi_end_big_word(key, arg: arg) if arg > 0
end
private def vi_delete_prev_char(key)
- if @byte_pointer == 0 and @line_index > 0
+ if @is_multiline and @cursor == 0 and @line_index > 0
+ @buffer_of_lines[@line_index] = @line
+ @cursor = calculate_width(@buffer_of_lines[@line_index - 1])
@byte_pointer = @buffer_of_lines[@line_index - 1].bytesize
@buffer_of_lines[@line_index - 1] += @buffer_of_lines.delete_at(@line_index)
@line_index -= 1
- process_auto_indent cursor_dependent: false
- elsif @byte_pointer > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
+ @line = @buffer_of_lines[@line_index]
+ @cursor_max = calculate_width(@line)
+ @rerender_all = true
+ elsif @cursor > 0
+ byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
@byte_pointer -= byte_size
- line, _ = byteslice!(current_line, @byte_pointer, byte_size)
- set_current_line(line)
+ @line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor -= width
+ @cursor_max -= width
end
end
@@ -2167,84 +2991,78 @@ class Reline::LineEditor
end
private def ed_delete_prev_char(key, arg: 1)
- deleted = +''
+ deleted = ''
arg.times do
- if @byte_pointer > 0
- byte_size = Reline::Unicode.get_prev_mbchar_size(current_line, @byte_pointer)
+ if @cursor > 0
+ byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
@byte_pointer -= byte_size
- line, mbchar = byteslice!(current_line, @byte_pointer, byte_size)
- set_current_line(line)
+ @line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
deleted.prepend(mbchar)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor -= width
+ @cursor_max -= width
end
end
copy_for_vi(deleted)
end
- private def vi_change_meta(key, arg: nil)
- if @vi_waiting_operator
- set_current_line('', 0) if @vi_waiting_operator == :vi_change_meta_confirm && arg.nil?
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- else
- @drop_terminate_spaces = true
- @vi_waiting_operator = :vi_change_meta_confirm
- @vi_waiting_operator_arg = arg || 1
- end
- end
-
- private def vi_change_meta_confirm(byte_pointer_diff)
- vi_delete_meta_confirm(byte_pointer_diff)
- @config.editing_mode = :vi_insert
- @drop_terminate_spaces = false
- end
-
- private def vi_delete_meta(key, arg: nil)
- if @vi_waiting_operator
- set_current_line('', 0) if @vi_waiting_operator == :vi_delete_meta_confirm && arg.nil?
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- else
- @vi_waiting_operator = :vi_delete_meta_confirm
- @vi_waiting_operator_arg = arg || 1
- end
- end
-
- private def vi_delete_meta_confirm(byte_pointer_diff)
- if byte_pointer_diff > 0
- line, cut = byteslice!(current_line, @byte_pointer, byte_pointer_diff)
- elsif byte_pointer_diff < 0
- line, cut = byteslice!(current_line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
- else
- return
- end
- copy_for_vi(cut)
- set_current_line(line, @byte_pointer + (byte_pointer_diff < 0 ? byte_pointer_diff : 0))
+ private def vi_zero(key)
+ @byte_pointer = 0
+ @cursor = 0
+ end
+
+ private def vi_change_meta(key, arg: 1)
+ @drop_terminate_spaces = true
+ @waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff|
+ if byte_pointer_diff > 0
+ @line, cut = byteslice!(@line, @byte_pointer, byte_pointer_diff)
+ elsif byte_pointer_diff < 0
+ @line, cut = byteslice!(@line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
+ end
+ copy_for_vi(cut)
+ @cursor += cursor_diff if cursor_diff < 0
+ @cursor_max -= cursor_diff.abs
+ @byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
+ @config.editing_mode = :vi_insert
+ @drop_terminate_spaces = false
+ }
+ @waiting_operator_vi_arg = arg
end
- private def vi_yank(key, arg: nil)
- if @vi_waiting_operator
- copy_for_vi(current_line) if @vi_waiting_operator == :vi_yank_confirm && arg.nil?
- @vi_waiting_operator = nil
- @vi_waiting_operator_arg = nil
- else
- @vi_waiting_operator = :vi_yank_confirm
- @vi_waiting_operator_arg = arg || 1
- end
+ private def vi_delete_meta(key, arg: 1)
+ @waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff|
+ if byte_pointer_diff > 0
+ @line, cut = byteslice!(@line, @byte_pointer, byte_pointer_diff)
+ elsif byte_pointer_diff < 0
+ @line, cut = byteslice!(@line, @byte_pointer + byte_pointer_diff, -byte_pointer_diff)
+ end
+ copy_for_vi(cut)
+ @cursor += cursor_diff if cursor_diff < 0
+ @cursor_max -= cursor_diff.abs
+ @byte_pointer += byte_pointer_diff if byte_pointer_diff < 0
+ }
+ @waiting_operator_vi_arg = arg
end
- private def vi_yank_confirm(byte_pointer_diff)
- if byte_pointer_diff > 0
- cut = current_line.byteslice(@byte_pointer, byte_pointer_diff)
- elsif byte_pointer_diff < 0
- cut = current_line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
- else
- return
- end
- copy_for_vi(cut)
+ private def vi_yank(key, arg: 1)
+ @waiting_operator_proc = proc { |cursor_diff, byte_pointer_diff|
+ if byte_pointer_diff > 0
+ cut = @line.byteslice(@byte_pointer, byte_pointer_diff)
+ elsif byte_pointer_diff < 0
+ cut = @line.byteslice(@byte_pointer + byte_pointer_diff, -byte_pointer_diff)
+ end
+ copy_for_vi(cut)
+ }
+ @waiting_operator_vi_arg = arg
end
private def vi_list_or_eof(key)
- if buffer_empty?
+ if (not @is_multiline and @line.empty?) or (@is_multiline and @line.empty? and @buffer_of_lines.size == 1)
+ @line = nil
+ if @buffer_of_lines.size > 1
+ scroll_down(@highest_in_all - @first_line_started_from)
+ end
+ Reline::IOGate.move_cursor_column(0)
@eof = true
finish
else
@@ -2255,15 +3073,18 @@ class Reline::LineEditor
alias_method :vi_eof_maybe, :vi_list_or_eof
private def ed_delete_next_char(key, arg: 1)
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- unless current_line.empty? || byte_size == 0
- line, mbchar = byteslice!(current_line, @byte_pointer, byte_size)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
+ unless @line.empty? || byte_size == 0
+ @line, mbchar = byteslice!(@line, @byte_pointer, byte_size)
copy_for_vi(mbchar)
- if @byte_pointer > 0 && current_line.bytesize == @byte_pointer + byte_size
- byte_size = Reline::Unicode.get_prev_mbchar_size(line, @byte_pointer)
- set_current_line(line, @byte_pointer - byte_size)
- else
- set_current_line(line, @byte_pointer)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @cursor_max -= width
+ if @cursor > 0 and @cursor >= @cursor_max
+ byte_size = Reline::Unicode.get_prev_mbchar_size(@line, @byte_pointer)
+ mbchar = @line.byteslice(@byte_pointer - byte_size, byte_size)
+ width = Reline::Unicode.get_mbchar_width(mbchar)
+ @byte_pointer -= byte_size
+ @cursor -= width
end
end
arg -= 1
@@ -2274,25 +3095,54 @@ class Reline::LineEditor
if Reline::HISTORY.empty?
return
end
- move_history(0, line: :start, cursor: :start)
+ if @history_pointer.nil?
+ @history_pointer = 0
+ @line_backup_in_history = @line
+ @line = Reline::HISTORY[@history_pointer]
+ @cursor_max = calculate_width(@line)
+ @cursor = 0
+ @byte_pointer = 0
+ elsif @history_pointer.zero?
+ return
+ else
+ Reline::HISTORY[@history_pointer] = @line
+ @history_pointer = 0
+ @line = Reline::HISTORY[@history_pointer]
+ @cursor_max = calculate_width(@line)
+ @cursor = 0
+ @byte_pointer = 0
+ end
end
private def vi_histedit(key)
path = Tempfile.open { |fp|
- fp.write whole_lines.join("\n")
+ if @is_multiline
+ fp.write whole_lines.join("\n")
+ else
+ fp.write @line
+ end
fp.path
}
system("#{ENV['EDITOR']} #{path}")
- @buffer_of_lines = File.read(path).split("\n")
- @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
- @line_index = 0
+ if @is_multiline
+ @buffer_of_lines = File.read(path).split("\n")
+ @buffer_of_lines = [String.new(encoding: @encoding)] if @buffer_of_lines.empty?
+ @line_index = 0
+ @line = @buffer_of_lines[@line_index]
+ @rerender_all = true
+ else
+ @line = File.read(path)
+ end
finish
end
private def vi_paste_prev(key, arg: 1)
if @vi_clipboard.size > 0
+ @line = byteinsert(@line, @byte_pointer, @vi_clipboard)
+ @cursor_max += calculate_width(@vi_clipboard)
cursor_point = @vi_clipboard.grapheme_clusters[0..-2].join
- set_current_line(byteinsert(current_line, @byte_pointer, @vi_clipboard), @byte_pointer + cursor_point.bytesize)
+ @cursor += calculate_width(cursor_point)
+ @byte_pointer += cursor_point.bytesize
end
arg -= 1
vi_paste_prev(key, arg: arg) if arg > 0
@@ -2300,9 +3150,11 @@ class Reline::LineEditor
private def vi_paste_next(key, arg: 1)
if @vi_clipboard.size > 0
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- line = byteinsert(current_line, @byte_pointer + byte_size, @vi_clipboard)
- set_current_line(line, @byte_pointer + @vi_clipboard.bytesize)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
+ @line = byteinsert(@line, @byte_pointer + byte_size, @vi_clipboard)
+ @cursor_max += calculate_width(@vi_clipboard)
+ @cursor += calculate_width(@vi_clipboard)
+ @byte_pointer += @vi_clipboard.bytesize
end
arg -= 1
vi_paste_next(key, arg: arg) if arg > 0
@@ -2326,33 +3178,43 @@ class Reline::LineEditor
end
private def vi_to_column(key, arg: 0)
- # Implementing behavior of vi, not Readline's vi-mode.
- @byte_pointer, = current_line.grapheme_clusters.inject([0, 0]) { |(total_byte_size, total_width), gc|
+ @byte_pointer, @cursor = @line.grapheme_clusters.inject([0, 0]) { |total, gc|
+ # total has [byte_size, cursor]
mbchar_width = Reline::Unicode.get_mbchar_width(gc)
- break [total_byte_size, total_width] if (total_width + mbchar_width) >= arg
- [total_byte_size + gc.bytesize, total_width + mbchar_width]
+ if (total.last + mbchar_width) >= arg
+ break total
+ elsif (total.last + mbchar_width) >= @cursor_max
+ break total
+ else
+ total = [total.first + gc.bytesize, total.last + mbchar_width]
+ total
+ end
}
end
private def vi_replace_char(key, arg: 1)
@waiting_proc = ->(k) {
if arg == 1
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
- before = current_line.byteslice(0, @byte_pointer)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
+ before = @line.byteslice(0, @byte_pointer)
remaining_point = @byte_pointer + byte_size
- after = current_line.byteslice(remaining_point, current_line.bytesize - remaining_point)
- set_current_line(before + k.chr + after)
+ after = @line.byteslice(remaining_point, @line.bytesize - remaining_point)
+ @line = before + k.chr + after
+ @cursor_max = calculate_width(@line)
@waiting_proc = nil
elsif arg > 1
byte_size = 0
arg.times do
- byte_size += Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer + byte_size)
+ byte_size += Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer + byte_size)
end
- before = current_line.byteslice(0, @byte_pointer)
+ before = @line.byteslice(0, @byte_pointer)
remaining_point = @byte_pointer + byte_size
- after = current_line.byteslice(remaining_point, current_line.bytesize - remaining_point)
+ after = @line.byteslice(remaining_point, @line.bytesize - remaining_point)
replaced = k.chr * arg
- set_current_line(before + replaced + after, @byte_pointer + replaced.bytesize)
+ @line = before + replaced + after
+ @byte_pointer += replaced.bytesize
+ @cursor += calculate_width(replaced)
+ @cursor_max = calculate_width(@line)
@waiting_proc = nil
end
}
@@ -2375,7 +3237,7 @@ class Reline::LineEditor
prev_total = nil
total = nil
found = false
- current_line.byteslice(@byte_pointer..-1).grapheme_clusters.each do |mbchar|
+ @line.byteslice(@byte_pointer..-1).grapheme_clusters.each do |mbchar|
# total has [byte_size, cursor]
unless total
# skip cursor point
@@ -2395,16 +3257,21 @@ class Reline::LineEditor
end
end
if not need_prev_char and found and total
- byte_size, _ = total
+ byte_size, width = total
@byte_pointer += byte_size
+ @cursor += width
elsif need_prev_char and found and prev_total
- byte_size, _ = prev_total
+ byte_size, width = prev_total
@byte_pointer += byte_size
+ @cursor += width
end
if inclusive
- byte_size = Reline::Unicode.get_next_mbchar_size(current_line, @byte_pointer)
+ byte_size = Reline::Unicode.get_next_mbchar_size(@line, @byte_pointer)
if byte_size > 0
+ c = @line.byteslice(@byte_pointer, byte_size)
+ width = Reline::Unicode.get_mbchar_width(c)
@byte_pointer += byte_size
+ @cursor += width
end
end
@waiting_proc = nil
@@ -2427,7 +3294,7 @@ class Reline::LineEditor
prev_total = nil
total = nil
found = false
- current_line.byteslice(0..@byte_pointer).grapheme_clusters.reverse_each do |mbchar|
+ @line.byteslice(0..@byte_pointer).grapheme_clusters.reverse_each do |mbchar|
# total has [byte_size, cursor]
unless total
# skip cursor point
@@ -2447,19 +3314,26 @@ class Reline::LineEditor
end
end
if not need_next_char and found and total
- byte_size, _ = total
+ byte_size, width = total
@byte_pointer -= byte_size
+ @cursor -= width
elsif need_next_char and found and prev_total
- byte_size, _ = prev_total
+ byte_size, width = prev_total
@byte_pointer -= byte_size
+ @cursor -= width
end
@waiting_proc = nil
end
private def vi_join_lines(key, arg: 1)
- if @buffer_of_lines.size > @line_index + 1
- next_line = @buffer_of_lines.delete_at(@line_index + 1).lstrip
- set_current_line(current_line + ' ' + next_line, current_line.bytesize)
+ if @is_multiline and @buffer_of_lines.size > @line_index + 1
+ @cursor = calculate_width(@line)
+ @byte_pointer = @line.bytesize
+ @line += ' ' + @buffer_of_lines.delete_at(@line_index + 1).lstrip
+ @cursor_max = calculate_width(@line)
+ @buffer_of_lines[@line_index] = @line
+ @rerender_all = true
+ @rest_height += 1
end
arg -= 1
vi_join_lines(key, arg: arg) if arg > 0
@@ -2473,48 +3347,11 @@ class Reline::LineEditor
private def em_exchange_mark(key)
return unless @mark_pointer
new_pointer = [@byte_pointer, @line_index]
+ @previous_line_index = @line_index
@byte_pointer, @line_index = @mark_pointer
+ @cursor = calculate_width(@line.byteslice(0, @byte_pointer))
+ @cursor_max = calculate_width(@line)
@mark_pointer = new_pointer
end
alias_method :exchange_point_and_mark, :em_exchange_mark
-
- private def emacs_editing_mode(key)
- @config.editing_mode = :emacs
- end
-
- private def vi_editing_mode(key)
- @config.editing_mode = :vi_insert
- end
-
- private def undo(_key)
- @undoing = true
-
- return if @input_lines_position <= 0
-
- @input_lines_position -= 1
- target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position]
- set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y)
- end
-
- private def redo(_key)
- @undoing = true
-
- return if @input_lines_position >= @input_lines.size - 1
-
- @input_lines_position += 1
- target_lines, target_cursor_x, target_cursor_y = @input_lines[@input_lines_position]
- set_current_lines(target_lines.dup, target_cursor_x, target_cursor_y)
- end
-
- private def prev_action_state_value(type)
- @prev_action_state[0] == type ? @prev_action_state[1] : nil
- end
-
- private def set_next_action_state(type, value)
- @next_action_state = [type, value]
- end
-
- private def re_read_init_file(_key)
- @config.reload
- end
end
diff --git a/lib/reline/reline.gemspec b/lib/reline/reline.gemspec
index dfaf966728..7bf1f8758b 100644
--- a/lib/reline/reline.gemspec
+++ b/lib/reline/reline.gemspec
@@ -18,11 +18,6 @@ Gem::Specification.new do |spec|
spec.files = Dir['BSDL', 'COPYING', 'README.md', 'license_of_rb-readline', 'lib/**/*']
spec.require_paths = ['lib']
- spec.metadata = {
- "bug_tracker_uri" => "https://github.com/ruby/reline/issues",
- "changelog_uri" => "https://github.com/ruby/reline/releases",
- "source_code_uri" => "https://github.com/ruby/reline"
- }
spec.required_ruby_version = Gem::Requirement.new('>= 2.6')
diff --git a/lib/reline/terminfo.rb b/lib/reline/terminfo.rb
index c2b1f681b4..f53642b919 100644
--- a/lib/reline/terminfo.rb
+++ b/lib/reline/terminfo.rb
@@ -1,7 +1,4 @@
begin
- # Ignore warning `Add fiddle to your Gemfile or gemspec` in Ruby 3.4.
- # terminfo.rb and ansi.rb supports fiddle unavailable environment.
- verbose, $VERBOSE = $VERBOSE, nil
require 'fiddle'
require 'fiddle/import'
rescue LoadError
@@ -10,8 +7,6 @@ rescue LoadError
false
end
end
-ensure
- $VERBOSE = verbose
end
module Reline::Terminfo
@@ -36,7 +31,21 @@ module Reline::Terminfo
@curses_dl = false
def self.curses_dl
return @curses_dl unless @curses_dl == false
- if Fiddle.const_defined?(:TYPE_VARIADIC)
+ if RUBY_VERSION >= '3.0.0'
+ # Gem module isn't defined in test-all of the Ruby repository, and
+ # Fiddle in Ruby 3.0.0 or later supports Fiddle::TYPE_VARIADIC.
+ fiddle_supports_variadic = true
+ elsif Fiddle.const_defined?(:VERSION,false) and Gem::Version.create(Fiddle::VERSION) >= Gem::Version.create('1.0.1')
+ # Fiddle::TYPE_VARIADIC is supported from Fiddle 1.0.1.
+ fiddle_supports_variadic = true
+ else
+ fiddle_supports_variadic = false
+ end
+ if fiddle_supports_variadic and not Fiddle.const_defined?(:TYPE_VARIADIC)
+ # If the libffi version is not 3.0.5 or higher, there isn't TYPE_VARIADIC.
+ fiddle_supports_variadic = false
+ end
+ if fiddle_supports_variadic
curses_dl_files.each do |curses_name|
result = Fiddle::Handle.new(curses_name)
rescue Fiddle::DLError
@@ -83,13 +92,25 @@ module Reline::Terminfo
end
def self.setupterm(term, fildes)
- errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT, Fiddle::RUBY_FREE)
+ errret_int = Fiddle::Pointer.malloc(Fiddle::SIZEOF_INT)
ret = @setupterm.(term, fildes, errret_int)
+ errret = errret_int[0, Fiddle::SIZEOF_INT].unpack1('i')
case ret
when 0 # OK
- @term_supported = true
+ 0
when -1 # ERR
- @term_supported = false
+ case errret
+ when 1
+ raise TerminfoError.new('The terminal is hardcopy, cannot be used for curses applications.')
+ when 0
+ raise TerminfoError.new('The terminal could not be found, or that it is a generic type, having too little information for curses applications to run.')
+ when -1
+ raise TerminfoError.new('The terminfo database could not be found.')
+ else # unknown
+ -1
+ end
+ else # unknown
+ -2
end
end
@@ -141,14 +162,9 @@ module Reline::Terminfo
num
end
- # NOTE: This means Fiddle and curses are enabled.
def self.enabled?
true
end
-
- def self.term_supported?
- @term_supported
- end
end if Reline::Terminfo.curses_dl
module Reline::Terminfo
diff --git a/lib/reline/unicode.rb b/lib/reline/unicode.rb
index 0ec815aeea..6000c9f82a 100644
--- a/lib/reline/unicode.rb
+++ b/lib/reline/unicode.rb
@@ -38,60 +38,92 @@ class Reline::Unicode
NON_PRINTING_START = "\1"
NON_PRINTING_END = "\2"
CSI_REGEXP = /\e\[[\d;]*[ABCDEFGHJKSTfminsuhl]/
- OSC_REGEXP = /\e\]\d+(?:;[^;\a\e]+)*(?:\a|\e\\)/
+ OSC_REGEXP = /\e\]\d+(?:;[^;]+)*\a/
WIDTH_SCANNER = /\G(?:(#{NON_PRINTING_START})|(#{NON_PRINTING_END})|(#{CSI_REGEXP})|(#{OSC_REGEXP})|(\X))/o
+ NON_PRINTING_START_INDEX = 0
+ NON_PRINTING_END_INDEX = 1
+ CSI_REGEXP_INDEX = 2
+ OSC_REGEXP_INDEX = 3
+ GRAPHEME_CLUSTER_INDEX = 4
+
+ def self.get_mbchar_byte_size_by_first_char(c)
+ # Checks UTF-8 character byte size
+ case c.ord
+ # 0b0xxxxxxx
+ when ->(code) { (code ^ 0b10000000).allbits?(0b10000000) } then 1
+ # 0b110xxxxx
+ when ->(code) { (code ^ 0b00100000).allbits?(0b11100000) } then 2
+ # 0b1110xxxx
+ when ->(code) { (code ^ 0b00010000).allbits?(0b11110000) } then 3
+ # 0b11110xxx
+ when ->(code) { (code ^ 0b00001000).allbits?(0b11111000) } then 4
+ # 0b111110xx
+ when ->(code) { (code ^ 0b00000100).allbits?(0b11111100) } then 5
+ # 0b1111110x
+ when ->(code) { (code ^ 0b00000010).allbits?(0b11111110) } then 6
+ # successor of mbchar
+ else 0
+ end
+ end
def self.escape_for_print(str)
str.chars.map! { |gr|
- case gr
- when -"\n"
- gr
- when -"\t"
- -' '
+ escaped = EscapedPairs[gr.ord]
+ if escaped && gr != -"\n" && gr != -"\t"
+ escaped
else
- EscapedPairs[gr.ord] || gr
+ gr
end
}.join
end
- def self.safe_encode(str, encoding)
- # Reline only supports utf-8 convertible string.
- converted = str.encode(encoding, invalid: :replace, undef: :replace)
- return converted if str.encoding == Encoding::UTF_8 || converted.encoding == Encoding::UTF_8 || converted.ascii_only?
+ require 'reline/unicode/east_asian_width'
- # This code is essentially doing the same thing as
- # `str.encode(utf8, **replace_options).encode(encoding, **replace_options)`
- # but also avoids unneccesary irreversible encoding conversion.
- converted.gsub(/\X/) do |c|
- c.encode(Encoding::UTF_8)
- c
- rescue Encoding::UndefinedConversionError
- '?'
- end
- end
+ HalfwidthDakutenHandakuten = /[\u{FF9E}\u{FF9F}]/
- require 'reline/unicode/east_asian_width'
+ MBCharWidthRE = /
+ (?<width_2_1>
+ [#{ EscapedChars.map {|c| "\\x%02x" % c.ord }.join }] (?# ^ + char, such as ^M, ^H, ^[, ...)
+ )
+ | (?<width_3>^\u{2E3B}) (?# THREE-EM DASH)
+ | (?<width_0>^\p{M})
+ | (?<width_2_2>
+ #{ EastAsianWidth::TYPE_F }
+ | #{ EastAsianWidth::TYPE_W }
+ )
+ | (?<width_1>
+ #{ EastAsianWidth::TYPE_H }
+ | #{ EastAsianWidth::TYPE_NA }
+ | #{ EastAsianWidth::TYPE_N }
+ )(?!#{ HalfwidthDakutenHandakuten })
+ | (?<width_2_3>
+ (?: #{ EastAsianWidth::TYPE_H }
+ | #{ EastAsianWidth::TYPE_NA }
+ | #{ EastAsianWidth::TYPE_N })
+ #{ HalfwidthDakutenHandakuten }
+ )
+ | (?<ambiguous_width>
+ #{EastAsianWidth::TYPE_A}
+ )
+ /x
def self.get_mbchar_width(mbchar)
ord = mbchar.ord
- if ord <= 0x1F # in EscapedPairs
+ if (0x00 <= ord and ord <= 0x1F) # in EscapedPairs
return 2
- elsif ord <= 0x7E # printable ASCII chars
+ elsif (0x20 <= ord and ord <= 0x7E) # printable ASCII chars
return 1
end
- utf8_mbchar = mbchar.encode(Encoding::UTF_8)
- ord = utf8_mbchar.ord
- chunk_index = EastAsianWidth::CHUNK_LAST.bsearch_index { |o| ord <= o }
- size = EastAsianWidth::CHUNK_WIDTH[chunk_index]
- if size == -1
- Reline.ambiguous_width
- elsif size == 1 && utf8_mbchar.size >= 2
- second_char_ord = utf8_mbchar[1].ord
- # Halfwidth Dakuten Handakuten
- # Only these two character has Letter Modifier category and can be combined in a single grapheme cluster
- (second_char_ord == 0xFF9E || second_char_ord == 0xFF9F) ? 2 : 1
+ m = mbchar.encode(Encoding::UTF_8).match(MBCharWidthRE)
+ case
+ when m.nil? then 1 # TODO should be U+FFFD � REPLACEMENT CHARACTER
+ when m[:width_2_1], m[:width_2_2], m[:width_2_3] then 2
+ when m[:width_3] then 3
+ when m[:width_0] then 0
+ when m[:width_1] then 1
+ when m[:ambiguous_width] then Reline.ambiguous_width
else
- size
+ nil
end
end
@@ -100,14 +132,15 @@ class Reline::Unicode
width = 0
rest = str.encode(Encoding::UTF_8)
in_zero_width = false
- rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
+ rest.scan(WIDTH_SCANNER) do |gc|
case
- when non_printing_start
+ when gc[NON_PRINTING_START_INDEX]
in_zero_width = true
- when non_printing_end
+ when gc[NON_PRINTING_END_INDEX]
in_zero_width = false
- when csi, osc
- when gc
+ when gc[CSI_REGEXP_INDEX], gc[OSC_REGEXP_INDEX]
+ when gc[GRAPHEME_CLUSTER_INDEX]
+ gc = gc[GRAPHEME_CLUSTER_INDEX]
unless in_zero_width
width += get_mbchar_width(gc)
end
@@ -121,40 +154,30 @@ class Reline::Unicode
end
end
- def self.split_by_width(str, max_width, encoding = str.encoding, offset: 0)
+ def self.split_by_width(str, max_width, encoding = str.encoding)
lines = [String.new(encoding: encoding)]
height = 1
- width = offset
+ width = 0
rest = str.encode(Encoding::UTF_8)
in_zero_width = false
- seq = String.new(encoding: encoding)
- rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
+ rest.scan(WIDTH_SCANNER) do |gc|
case
- when non_printing_start
+ when gc[NON_PRINTING_START_INDEX]
in_zero_width = true
- lines.last << NON_PRINTING_START
- when non_printing_end
+ when gc[NON_PRINTING_END_INDEX]
in_zero_width = false
- lines.last << NON_PRINTING_END
- when csi
- lines.last << csi
- unless in_zero_width
- if csi == -"\e[m" || csi == -"\e[0m"
- seq.clear
- else
- seq << csi
- end
- end
- when osc
- lines.last << osc
- seq << osc
- when gc
+ when gc[CSI_REGEXP_INDEX]
+ lines.last << gc[CSI_REGEXP_INDEX]
+ when gc[OSC_REGEXP_INDEX]
+ lines.last << gc[OSC_REGEXP_INDEX]
+ when gc[GRAPHEME_CLUSTER_INDEX]
+ gc = gc[GRAPHEME_CLUSTER_INDEX]
unless in_zero_width
mbchar_width = get_mbchar_width(gc)
if (width += mbchar_width) > max_width
width = mbchar_width
lines << nil
- lines << seq.dup
+ lines << String.new(encoding: encoding)
height += 1
end
end
@@ -171,79 +194,34 @@ class Reline::Unicode
end
# Take a chunk of a String cut by width with escape sequences.
- def self.take_range(str, start_col, max_width)
- take_mbchar_range(str, start_col, max_width).first
- end
-
- def self.take_mbchar_range(str, start_col, width, cover_begin: false, cover_end: false, padding: false)
- chunk = String.new(encoding: str.encoding)
-
- end_col = start_col + width
+ def self.take_range(str, start_col, max_width, encoding = str.encoding)
+ chunk = String.new(encoding: encoding)
total_width = 0
rest = str.encode(Encoding::UTF_8)
in_zero_width = false
- chunk_start_col = nil
- chunk_end_col = nil
- has_csi = false
- rest.scan(WIDTH_SCANNER) do |non_printing_start, non_printing_end, csi, osc, gc|
+ rest.scan(WIDTH_SCANNER) do |gc|
case
- when non_printing_start
+ when gc[NON_PRINTING_START_INDEX]
in_zero_width = true
- chunk << NON_PRINTING_START
- when non_printing_end
+ when gc[NON_PRINTING_END_INDEX]
in_zero_width = false
- chunk << NON_PRINTING_END
- when csi
- has_csi = true
- chunk << csi
- when osc
- chunk << osc
- when gc
+ when gc[CSI_REGEXP_INDEX]
+ chunk << gc[CSI_REGEXP_INDEX]
+ when gc[OSC_REGEXP_INDEX]
+ chunk << gc[OSC_REGEXP_INDEX]
+ when gc[GRAPHEME_CLUSTER_INDEX]
+ gc = gc[GRAPHEME_CLUSTER_INDEX]
if in_zero_width
chunk << gc
- next
- end
-
- mbchar_width = get_mbchar_width(gc)
- prev_width = total_width
- total_width += mbchar_width
-
- if (cover_begin || padding ? total_width <= start_col : prev_width < start_col)
- # Current character haven't reached start_col yet
- next
- elsif padding && !cover_begin && prev_width < start_col && start_col < total_width
- # Add preceding padding. This padding might have background color.
- chunk << ' '
- chunk_start_col ||= start_col
- chunk_end_col = total_width
- next
- elsif (cover_end ? prev_width < end_col : total_width <= end_col)
- # Current character is in the range
- chunk << gc
- chunk_start_col ||= prev_width
- chunk_end_col = total_width
- break if total_width >= end_col
else
- # Current character exceeds end_col
- if padding && end_col < total_width
- # Add succeeding padding. This padding might have background color.
- chunk << ' '
- chunk_start_col ||= prev_width
- chunk_end_col = end_col
- end
- break
+ mbchar_width = get_mbchar_width(gc)
+ total_width += mbchar_width
+ break if (start_col + max_width) < total_width
+ chunk << gc if start_col < total_width
end
end
end
- chunk_start_col ||= start_col
- chunk_end_col ||= start_col
- if padding && chunk_end_col < end_col
- # Append padding. This padding should not include background color.
- chunk << "\e[0m" if has_csi
- chunk << ' ' * (end_col - chunk_end_col)
- chunk_end_col = end_col
- end
- [chunk, chunk_start_col, chunk_end_col - chunk_start_col]
+ chunk
end
def self.get_next_mbchar_size(line, byte_pointer)
diff --git a/lib/reline/unicode/east_asian_width.rb b/lib/reline/unicode/east_asian_width.rb
index 106ca4881a..89bc9d9435 100644
--- a/lib/reline/unicode/east_asian_width.rb
+++ b/lib/reline/unicode/east_asian_width.rb
@@ -1,1267 +1,1164 @@
class Reline::Unicode::EastAsianWidth
# This is based on EastAsianWidth.txt
- # UNICODE_VERSION = '15.1.0'
+ # EastAsianWidth.txt
- CHUNK_LAST, CHUNK_WIDTH = [
- [0x1f, 2],
- [0x7e, 1],
- [0x7f, 2],
- [0xa0, 1],
- [0xa1, -1],
- [0xa3, 1],
- [0xa4, -1],
- [0xa6, 1],
- [0xa8, -1],
- [0xa9, 1],
- [0xaa, -1],
- [0xac, 1],
- [0xae, -1],
- [0xaf, 1],
- [0xb4, -1],
- [0xb5, 1],
- [0xba, -1],
- [0xbb, 1],
- [0xbf, -1],
- [0xc5, 1],
- [0xc6, -1],
- [0xcf, 1],
- [0xd0, -1],
- [0xd6, 1],
- [0xd8, -1],
- [0xdd, 1],
- [0xe1, -1],
- [0xe5, 1],
- [0xe6, -1],
- [0xe7, 1],
- [0xea, -1],
- [0xeb, 1],
- [0xed, -1],
- [0xef, 1],
- [0xf0, -1],
- [0xf1, 1],
- [0xf3, -1],
- [0xf6, 1],
- [0xfa, -1],
- [0xfb, 1],
- [0xfc, -1],
- [0xfd, 1],
- [0xfe, -1],
- [0x100, 1],
- [0x101, -1],
- [0x110, 1],
- [0x111, -1],
- [0x112, 1],
- [0x113, -1],
- [0x11a, 1],
- [0x11b, -1],
- [0x125, 1],
- [0x127, -1],
- [0x12a, 1],
- [0x12b, -1],
- [0x130, 1],
- [0x133, -1],
- [0x137, 1],
- [0x138, -1],
- [0x13e, 1],
- [0x142, -1],
- [0x143, 1],
- [0x144, -1],
- [0x147, 1],
- [0x14b, -1],
- [0x14c, 1],
- [0x14d, -1],
- [0x151, 1],
- [0x153, -1],
- [0x165, 1],
- [0x167, -1],
- [0x16a, 1],
- [0x16b, -1],
- [0x1cd, 1],
- [0x1ce, -1],
- [0x1cf, 1],
- [0x1d0, -1],
- [0x1d1, 1],
- [0x1d2, -1],
- [0x1d3, 1],
- [0x1d4, -1],
- [0x1d5, 1],
- [0x1d6, -1],
- [0x1d7, 1],
- [0x1d8, -1],
- [0x1d9, 1],
- [0x1da, -1],
- [0x1db, 1],
- [0x1dc, -1],
- [0x250, 1],
- [0x251, -1],
- [0x260, 1],
- [0x261, -1],
- [0x2c3, 1],
- [0x2c4, -1],
- [0x2c6, 1],
- [0x2c7, -1],
- [0x2c8, 1],
- [0x2cb, -1],
- [0x2cc, 1],
- [0x2cd, -1],
- [0x2cf, 1],
- [0x2d0, -1],
- [0x2d7, 1],
- [0x2db, -1],
- [0x2dc, 1],
- [0x2dd, -1],
- [0x2de, 1],
- [0x2df, -1],
- [0x2ff, 1],
- [0x36f, 0],
- [0x390, 1],
- [0x3a1, -1],
- [0x3a2, 1],
- [0x3a9, -1],
- [0x3b0, 1],
- [0x3c1, -1],
- [0x3c2, 1],
- [0x3c9, -1],
- [0x400, 1],
- [0x401, -1],
- [0x40f, 1],
- [0x44f, -1],
- [0x450, 1],
- [0x451, -1],
- [0x482, 1],
- [0x487, 0],
- [0x590, 1],
- [0x5bd, 0],
- [0x5be, 1],
- [0x5bf, 0],
- [0x5c0, 1],
- [0x5c2, 0],
- [0x5c3, 1],
- [0x5c5, 0],
- [0x5c6, 1],
- [0x5c7, 0],
- [0x60f, 1],
- [0x61a, 0],
- [0x64a, 1],
- [0x65f, 0],
- [0x66f, 1],
- [0x670, 0],
- [0x6d5, 1],
- [0x6dc, 0],
- [0x6de, 1],
- [0x6e4, 0],
- [0x6e6, 1],
- [0x6e8, 0],
- [0x6e9, 1],
- [0x6ed, 0],
- [0x710, 1],
- [0x711, 0],
- [0x72f, 1],
- [0x74a, 0],
- [0x7a5, 1],
- [0x7b0, 0],
- [0x7ea, 1],
- [0x7f3, 0],
- [0x7fc, 1],
- [0x7fd, 0],
- [0x815, 1],
- [0x819, 0],
- [0x81a, 1],
- [0x823, 0],
- [0x824, 1],
- [0x827, 0],
- [0x828, 1],
- [0x82d, 0],
- [0x858, 1],
- [0x85b, 0],
- [0x897, 1],
- [0x89f, 0],
- [0x8c9, 1],
- [0x8e1, 0],
- [0x8e2, 1],
- [0x902, 0],
- [0x939, 1],
- [0x93a, 0],
- [0x93b, 1],
- [0x93c, 0],
- [0x940, 1],
- [0x948, 0],
- [0x94c, 1],
- [0x94d, 0],
- [0x950, 1],
- [0x957, 0],
- [0x961, 1],
- [0x963, 0],
- [0x980, 1],
- [0x981, 0],
- [0x9bb, 1],
- [0x9bc, 0],
- [0x9c0, 1],
- [0x9c4, 0],
- [0x9cc, 1],
- [0x9cd, 0],
- [0x9e1, 1],
- [0x9e3, 0],
- [0x9fd, 1],
- [0x9fe, 0],
- [0xa00, 1],
- [0xa02, 0],
- [0xa3b, 1],
- [0xa3c, 0],
- [0xa40, 1],
- [0xa42, 0],
- [0xa46, 1],
- [0xa48, 0],
- [0xa4a, 1],
- [0xa4d, 0],
- [0xa50, 1],
- [0xa51, 0],
- [0xa6f, 1],
- [0xa71, 0],
- [0xa74, 1],
- [0xa75, 0],
- [0xa80, 1],
- [0xa82, 0],
- [0xabb, 1],
- [0xabc, 0],
- [0xac0, 1],
- [0xac5, 0],
- [0xac6, 1],
- [0xac8, 0],
- [0xacc, 1],
- [0xacd, 0],
- [0xae1, 1],
- [0xae3, 0],
- [0xaf9, 1],
- [0xaff, 0],
- [0xb00, 1],
- [0xb01, 0],
- [0xb3b, 1],
- [0xb3c, 0],
- [0xb3e, 1],
- [0xb3f, 0],
- [0xb40, 1],
- [0xb44, 0],
- [0xb4c, 1],
- [0xb4d, 0],
- [0xb54, 1],
- [0xb56, 0],
- [0xb61, 1],
- [0xb63, 0],
- [0xb81, 1],
- [0xb82, 0],
- [0xbbf, 1],
- [0xbc0, 0],
- [0xbcc, 1],
- [0xbcd, 0],
- [0xbff, 1],
- [0xc00, 0],
- [0xc03, 1],
- [0xc04, 0],
- [0xc3b, 1],
- [0xc3c, 0],
- [0xc3d, 1],
- [0xc40, 0],
- [0xc45, 1],
- [0xc48, 0],
- [0xc49, 1],
- [0xc4d, 0],
- [0xc54, 1],
- [0xc56, 0],
- [0xc61, 1],
- [0xc63, 0],
- [0xc80, 1],
- [0xc81, 0],
- [0xcbb, 1],
- [0xcbc, 0],
- [0xcbe, 1],
- [0xcbf, 0],
- [0xcc5, 1],
- [0xcc6, 0],
- [0xccb, 1],
- [0xccd, 0],
- [0xce1, 1],
- [0xce3, 0],
- [0xcff, 1],
- [0xd01, 0],
- [0xd3a, 1],
- [0xd3c, 0],
- [0xd40, 1],
- [0xd44, 0],
- [0xd4c, 1],
- [0xd4d, 0],
- [0xd61, 1],
- [0xd63, 0],
- [0xd80, 1],
- [0xd81, 0],
- [0xdc9, 1],
- [0xdca, 0],
- [0xdd1, 1],
- [0xdd4, 0],
- [0xdd5, 1],
- [0xdd6, 0],
- [0xe30, 1],
- [0xe31, 0],
- [0xe33, 1],
- [0xe3a, 0],
- [0xe46, 1],
- [0xe4e, 0],
- [0xeb0, 1],
- [0xeb1, 0],
- [0xeb3, 1],
- [0xebc, 0],
- [0xec7, 1],
- [0xece, 0],
- [0xf17, 1],
- [0xf19, 0],
- [0xf34, 1],
- [0xf35, 0],
- [0xf36, 1],
- [0xf37, 0],
- [0xf38, 1],
- [0xf39, 0],
- [0xf70, 1],
- [0xf7e, 0],
- [0xf7f, 1],
- [0xf84, 0],
- [0xf85, 1],
- [0xf87, 0],
- [0xf8c, 1],
- [0xf97, 0],
- [0xf98, 1],
- [0xfbc, 0],
- [0xfc5, 1],
- [0xfc6, 0],
- [0x102c, 1],
- [0x1030, 0],
- [0x1031, 1],
- [0x1037, 0],
- [0x1038, 1],
- [0x103a, 0],
- [0x103c, 1],
- [0x103e, 0],
- [0x1057, 1],
- [0x1059, 0],
- [0x105d, 1],
- [0x1060, 0],
- [0x1070, 1],
- [0x1074, 0],
- [0x1081, 1],
- [0x1082, 0],
- [0x1084, 1],
- [0x1086, 0],
- [0x108c, 1],
- [0x108d, 0],
- [0x109c, 1],
- [0x109d, 0],
- [0x10ff, 1],
- [0x115f, 2],
- [0x135c, 1],
- [0x135f, 0],
- [0x1711, 1],
- [0x1714, 0],
- [0x1731, 1],
- [0x1733, 0],
- [0x1751, 1],
- [0x1753, 0],
- [0x1771, 1],
- [0x1773, 0],
- [0x17b3, 1],
- [0x17b5, 0],
- [0x17b6, 1],
- [0x17bd, 0],
- [0x17c5, 1],
- [0x17c6, 0],
- [0x17c8, 1],
- [0x17d3, 0],
- [0x17dc, 1],
- [0x17dd, 0],
- [0x180a, 1],
- [0x180d, 0],
- [0x180e, 1],
- [0x180f, 0],
- [0x1884, 1],
- [0x1886, 0],
- [0x18a8, 1],
- [0x18a9, 0],
- [0x191f, 1],
- [0x1922, 0],
- [0x1926, 1],
- [0x1928, 0],
- [0x1931, 1],
- [0x1932, 0],
- [0x1938, 1],
- [0x193b, 0],
- [0x1a16, 1],
- [0x1a18, 0],
- [0x1a1a, 1],
- [0x1a1b, 0],
- [0x1a55, 1],
- [0x1a56, 0],
- [0x1a57, 1],
- [0x1a5e, 0],
- [0x1a5f, 1],
- [0x1a60, 0],
- [0x1a61, 1],
- [0x1a62, 0],
- [0x1a64, 1],
- [0x1a6c, 0],
- [0x1a72, 1],
- [0x1a7c, 0],
- [0x1a7e, 1],
- [0x1a7f, 0],
- [0x1aaf, 1],
- [0x1abd, 0],
- [0x1abe, 1],
- [0x1ace, 0],
- [0x1aff, 1],
- [0x1b03, 0],
- [0x1b33, 1],
- [0x1b34, 0],
- [0x1b35, 1],
- [0x1b3a, 0],
- [0x1b3b, 1],
- [0x1b3c, 0],
- [0x1b41, 1],
- [0x1b42, 0],
- [0x1b6a, 1],
- [0x1b73, 0],
- [0x1b7f, 1],
- [0x1b81, 0],
- [0x1ba1, 1],
- [0x1ba5, 0],
- [0x1ba7, 1],
- [0x1ba9, 0],
- [0x1baa, 1],
- [0x1bad, 0],
- [0x1be5, 1],
- [0x1be6, 0],
- [0x1be7, 1],
- [0x1be9, 0],
- [0x1bec, 1],
- [0x1bed, 0],
- [0x1bee, 1],
- [0x1bf1, 0],
- [0x1c2b, 1],
- [0x1c33, 0],
- [0x1c35, 1],
- [0x1c37, 0],
- [0x1ccf, 1],
- [0x1cd2, 0],
- [0x1cd3, 1],
- [0x1ce0, 0],
- [0x1ce1, 1],
- [0x1ce8, 0],
- [0x1cec, 1],
- [0x1ced, 0],
- [0x1cf3, 1],
- [0x1cf4, 0],
- [0x1cf7, 1],
- [0x1cf9, 0],
- [0x1dbf, 1],
- [0x1dff, 0],
- [0x200f, 1],
- [0x2010, -1],
- [0x2012, 1],
- [0x2016, -1],
- [0x2017, 1],
- [0x2019, -1],
- [0x201b, 1],
- [0x201d, -1],
- [0x201f, 1],
- [0x2022, -1],
- [0x2023, 1],
- [0x2027, -1],
- [0x202f, 1],
- [0x2030, -1],
- [0x2031, 1],
- [0x2033, -1],
- [0x2034, 1],
- [0x2035, -1],
- [0x203a, 1],
- [0x203b, -1],
- [0x203d, 1],
- [0x203e, -1],
- [0x2073, 1],
- [0x2074, -1],
- [0x207e, 1],
- [0x207f, -1],
- [0x2080, 1],
- [0x2084, -1],
- [0x20ab, 1],
- [0x20ac, -1],
- [0x20cf, 1],
- [0x20dc, 0],
- [0x20e0, 1],
- [0x20e1, 0],
- [0x20e4, 1],
- [0x20f0, 0],
- [0x2102, 1],
- [0x2103, -1],
- [0x2104, 1],
- [0x2105, -1],
- [0x2108, 1],
- [0x2109, -1],
- [0x2112, 1],
- [0x2113, -1],
- [0x2115, 1],
- [0x2116, -1],
- [0x2120, 1],
- [0x2122, -1],
- [0x2125, 1],
- [0x2126, -1],
- [0x212a, 1],
- [0x212b, -1],
- [0x2152, 1],
- [0x2154, -1],
- [0x215a, 1],
- [0x215e, -1],
- [0x215f, 1],
- [0x216b, -1],
- [0x216f, 1],
- [0x2179, -1],
- [0x2188, 1],
- [0x2189, -1],
- [0x218f, 1],
- [0x2199, -1],
- [0x21b7, 1],
- [0x21b9, -1],
- [0x21d1, 1],
- [0x21d2, -1],
- [0x21d3, 1],
- [0x21d4, -1],
- [0x21e6, 1],
- [0x21e7, -1],
- [0x21ff, 1],
- [0x2200, -1],
- [0x2201, 1],
- [0x2203, -1],
- [0x2206, 1],
- [0x2208, -1],
- [0x220a, 1],
- [0x220b, -1],
- [0x220e, 1],
- [0x220f, -1],
- [0x2210, 1],
- [0x2211, -1],
- [0x2214, 1],
- [0x2215, -1],
- [0x2219, 1],
- [0x221a, -1],
- [0x221c, 1],
- [0x2220, -1],
- [0x2222, 1],
- [0x2223, -1],
- [0x2224, 1],
- [0x2225, -1],
- [0x2226, 1],
- [0x222c, -1],
- [0x222d, 1],
- [0x222e, -1],
- [0x2233, 1],
- [0x2237, -1],
- [0x223b, 1],
- [0x223d, -1],
- [0x2247, 1],
- [0x2248, -1],
- [0x224b, 1],
- [0x224c, -1],
- [0x2251, 1],
- [0x2252, -1],
- [0x225f, 1],
- [0x2261, -1],
- [0x2263, 1],
- [0x2267, -1],
- [0x2269, 1],
- [0x226b, -1],
- [0x226d, 1],
- [0x226f, -1],
- [0x2281, 1],
- [0x2283, -1],
- [0x2285, 1],
- [0x2287, -1],
- [0x2294, 1],
- [0x2295, -1],
- [0x2298, 1],
- [0x2299, -1],
- [0x22a4, 1],
- [0x22a5, -1],
- [0x22be, 1],
- [0x22bf, -1],
- [0x2311, 1],
- [0x2312, -1],
- [0x2319, 1],
- [0x231b, 2],
- [0x2328, 1],
- [0x232a, 2],
- [0x23e8, 1],
- [0x23ec, 2],
- [0x23ef, 1],
- [0x23f0, 2],
- [0x23f2, 1],
- [0x23f3, 2],
- [0x245f, 1],
- [0x24e9, -1],
- [0x24ea, 1],
- [0x254b, -1],
- [0x254f, 1],
- [0x2573, -1],
- [0x257f, 1],
- [0x258f, -1],
- [0x2591, 1],
- [0x2595, -1],
- [0x259f, 1],
- [0x25a1, -1],
- [0x25a2, 1],
- [0x25a9, -1],
- [0x25b1, 1],
- [0x25b3, -1],
- [0x25b5, 1],
- [0x25b7, -1],
- [0x25bb, 1],
- [0x25bd, -1],
- [0x25bf, 1],
- [0x25c1, -1],
- [0x25c5, 1],
- [0x25c8, -1],
- [0x25ca, 1],
- [0x25cb, -1],
- [0x25cd, 1],
- [0x25d1, -1],
- [0x25e1, 1],
- [0x25e5, -1],
- [0x25ee, 1],
- [0x25ef, -1],
- [0x25fc, 1],
- [0x25fe, 2],
- [0x2604, 1],
- [0x2606, -1],
- [0x2608, 1],
- [0x2609, -1],
- [0x260d, 1],
- [0x260f, -1],
- [0x2613, 1],
- [0x2615, 2],
- [0x261b, 1],
- [0x261c, -1],
- [0x261d, 1],
- [0x261e, -1],
- [0x263f, 1],
- [0x2640, -1],
- [0x2641, 1],
- [0x2642, -1],
- [0x2647, 1],
- [0x2653, 2],
- [0x265f, 1],
- [0x2661, -1],
- [0x2662, 1],
- [0x2665, -1],
- [0x2666, 1],
- [0x266a, -1],
- [0x266b, 1],
- [0x266d, -1],
- [0x266e, 1],
- [0x266f, -1],
- [0x267e, 1],
- [0x267f, 2],
- [0x2692, 1],
- [0x2693, 2],
- [0x269d, 1],
- [0x269f, -1],
- [0x26a0, 1],
- [0x26a1, 2],
- [0x26a9, 1],
- [0x26ab, 2],
- [0x26bc, 1],
- [0x26be, 2],
- [0x26bf, -1],
- [0x26c3, 1],
- [0x26c5, 2],
- [0x26cd, -1],
- [0x26ce, 2],
- [0x26d3, -1],
- [0x26d4, 2],
- [0x26e1, -1],
- [0x26e2, 1],
- [0x26e3, -1],
- [0x26e7, 1],
- [0x26e9, -1],
- [0x26ea, 2],
- [0x26f1, -1],
- [0x26f3, 2],
- [0x26f4, -1],
- [0x26f5, 2],
- [0x26f9, -1],
- [0x26fa, 2],
- [0x26fc, -1],
- [0x26fd, 2],
- [0x26ff, -1],
- [0x2704, 1],
- [0x2705, 2],
- [0x2709, 1],
- [0x270b, 2],
- [0x2727, 1],
- [0x2728, 2],
- [0x273c, 1],
- [0x273d, -1],
- [0x274b, 1],
- [0x274c, 2],
- [0x274d, 1],
- [0x274e, 2],
- [0x2752, 1],
- [0x2755, 2],
- [0x2756, 1],
- [0x2757, 2],
- [0x2775, 1],
- [0x277f, -1],
- [0x2794, 1],
- [0x2797, 2],
- [0x27af, 1],
- [0x27b0, 2],
- [0x27be, 1],
- [0x27bf, 2],
- [0x2b1a, 1],
- [0x2b1c, 2],
- [0x2b4f, 1],
- [0x2b50, 2],
- [0x2b54, 1],
- [0x2b55, 2],
- [0x2b59, -1],
- [0x2cee, 1],
- [0x2cf1, 0],
- [0x2d7e, 1],
- [0x2d7f, 0],
- [0x2ddf, 1],
- [0x2dff, 0],
- [0x2e7f, 1],
- [0x2e99, 2],
- [0x2e9a, 1],
- [0x2ef3, 2],
- [0x2eff, 1],
- [0x2fd5, 2],
- [0x2fef, 1],
- [0x3029, 2],
- [0x302d, 0],
- [0x303e, 2],
- [0x3040, 1],
- [0x3096, 2],
- [0x3098, 1],
- [0x309a, 0],
- [0x30ff, 2],
- [0x3104, 1],
- [0x312f, 2],
- [0x3130, 1],
- [0x318e, 2],
- [0x318f, 1],
- [0x31e3, 2],
- [0x31ee, 1],
- [0x321e, 2],
- [0x321f, 1],
- [0x3247, 2],
- [0x324f, -1],
- [0x4dbf, 2],
- [0x4dff, 1],
- [0xa48c, 2],
- [0xa48f, 1],
- [0xa4c6, 2],
- [0xa66e, 1],
- [0xa66f, 0],
- [0xa673, 1],
- [0xa67d, 0],
- [0xa69d, 1],
- [0xa69f, 0],
- [0xa6ef, 1],
- [0xa6f1, 0],
- [0xa801, 1],
- [0xa802, 0],
- [0xa805, 1],
- [0xa806, 0],
- [0xa80a, 1],
- [0xa80b, 0],
- [0xa824, 1],
- [0xa826, 0],
- [0xa82b, 1],
- [0xa82c, 0],
- [0xa8c3, 1],
- [0xa8c5, 0],
- [0xa8df, 1],
- [0xa8f1, 0],
- [0xa8fe, 1],
- [0xa8ff, 0],
- [0xa925, 1],
- [0xa92d, 0],
- [0xa946, 1],
- [0xa951, 0],
- [0xa95f, 1],
- [0xa97c, 2],
- [0xa97f, 1],
- [0xa982, 0],
- [0xa9b2, 1],
- [0xa9b3, 0],
- [0xa9b5, 1],
- [0xa9b9, 0],
- [0xa9bb, 1],
- [0xa9bd, 0],
- [0xa9e4, 1],
- [0xa9e5, 0],
- [0xaa28, 1],
- [0xaa2e, 0],
- [0xaa30, 1],
- [0xaa32, 0],
- [0xaa34, 1],
- [0xaa36, 0],
- [0xaa42, 1],
- [0xaa43, 0],
- [0xaa4b, 1],
- [0xaa4c, 0],
- [0xaa7b, 1],
- [0xaa7c, 0],
- [0xaaaf, 1],
- [0xaab0, 0],
- [0xaab1, 1],
- [0xaab4, 0],
- [0xaab6, 1],
- [0xaab8, 0],
- [0xaabd, 1],
- [0xaabf, 0],
- [0xaac0, 1],
- [0xaac1, 0],
- [0xaaeb, 1],
- [0xaaed, 0],
- [0xaaf5, 1],
- [0xaaf6, 0],
- [0xabe4, 1],
- [0xabe5, 0],
- [0xabe7, 1],
- [0xabe8, 0],
- [0xabec, 1],
- [0xabed, 0],
- [0xabff, 1],
- [0xd7a3, 2],
- [0xdfff, 1],
- [0xf8ff, -1],
- [0xfaff, 2],
- [0xfb1d, 1],
- [0xfb1e, 0],
- [0xfdff, 1],
- [0xfe0f, 0],
- [0xfe19, 2],
- [0xfe1f, 1],
- [0xfe2f, 0],
- [0xfe52, 2],
- [0xfe53, 1],
- [0xfe66, 2],
- [0xfe67, 1],
- [0xfe6b, 2],
- [0xff00, 1],
- [0xff60, 2],
- [0xffdf, 1],
- [0xffe6, 2],
- [0xfffc, 1],
- [0xfffd, -1],
- [0x101fc, 1],
- [0x101fd, 0],
- [0x102df, 1],
- [0x102e0, 0],
- [0x10375, 1],
- [0x1037a, 0],
- [0x10a00, 1],
- [0x10a03, 0],
- [0x10a04, 1],
- [0x10a06, 0],
- [0x10a0b, 1],
- [0x10a0f, 0],
- [0x10a37, 1],
- [0x10a3a, 0],
- [0x10a3e, 1],
- [0x10a3f, 0],
- [0x10ae4, 1],
- [0x10ae6, 0],
- [0x10d23, 1],
- [0x10d27, 0],
- [0x10eaa, 1],
- [0x10eac, 0],
- [0x10efc, 1],
- [0x10eff, 0],
- [0x10f45, 1],
- [0x10f50, 0],
- [0x10f81, 1],
- [0x10f85, 0],
- [0x11000, 1],
- [0x11001, 0],
- [0x11037, 1],
- [0x11046, 0],
- [0x1106f, 1],
- [0x11070, 0],
- [0x11072, 1],
- [0x11074, 0],
- [0x1107e, 1],
- [0x11081, 0],
- [0x110b2, 1],
- [0x110b6, 0],
- [0x110b8, 1],
- [0x110ba, 0],
- [0x110c1, 1],
- [0x110c2, 0],
- [0x110ff, 1],
- [0x11102, 0],
- [0x11126, 1],
- [0x1112b, 0],
- [0x1112c, 1],
- [0x11134, 0],
- [0x11172, 1],
- [0x11173, 0],
- [0x1117f, 1],
- [0x11181, 0],
- [0x111b5, 1],
- [0x111be, 0],
- [0x111c8, 1],
- [0x111cc, 0],
- [0x111ce, 1],
- [0x111cf, 0],
- [0x1122e, 1],
- [0x11231, 0],
- [0x11233, 1],
- [0x11234, 0],
- [0x11235, 1],
- [0x11237, 0],
- [0x1123d, 1],
- [0x1123e, 0],
- [0x11240, 1],
- [0x11241, 0],
- [0x112de, 1],
- [0x112df, 0],
- [0x112e2, 1],
- [0x112ea, 0],
- [0x112ff, 1],
- [0x11301, 0],
- [0x1133a, 1],
- [0x1133c, 0],
- [0x1133f, 1],
- [0x11340, 0],
- [0x11365, 1],
- [0x1136c, 0],
- [0x1136f, 1],
- [0x11374, 0],
- [0x11437, 1],
- [0x1143f, 0],
- [0x11441, 1],
- [0x11444, 0],
- [0x11445, 1],
- [0x11446, 0],
- [0x1145d, 1],
- [0x1145e, 0],
- [0x114b2, 1],
- [0x114b8, 0],
- [0x114b9, 1],
- [0x114ba, 0],
- [0x114be, 1],
- [0x114c0, 0],
- [0x114c1, 1],
- [0x114c3, 0],
- [0x115b1, 1],
- [0x115b5, 0],
- [0x115bb, 1],
- [0x115bd, 0],
- [0x115be, 1],
- [0x115c0, 0],
- [0x115db, 1],
- [0x115dd, 0],
- [0x11632, 1],
- [0x1163a, 0],
- [0x1163c, 1],
- [0x1163d, 0],
- [0x1163e, 1],
- [0x11640, 0],
- [0x116aa, 1],
- [0x116ab, 0],
- [0x116ac, 1],
- [0x116ad, 0],
- [0x116af, 1],
- [0x116b5, 0],
- [0x116b6, 1],
- [0x116b7, 0],
- [0x1171c, 1],
- [0x1171f, 0],
- [0x11721, 1],
- [0x11725, 0],
- [0x11726, 1],
- [0x1172b, 0],
- [0x1182e, 1],
- [0x11837, 0],
- [0x11838, 1],
- [0x1183a, 0],
- [0x1193a, 1],
- [0x1193c, 0],
- [0x1193d, 1],
- [0x1193e, 0],
- [0x11942, 1],
- [0x11943, 0],
- [0x119d3, 1],
- [0x119d7, 0],
- [0x119d9, 1],
- [0x119db, 0],
- [0x119df, 1],
- [0x119e0, 0],
- [0x11a00, 1],
- [0x11a0a, 0],
- [0x11a32, 1],
- [0x11a38, 0],
- [0x11a3a, 1],
- [0x11a3e, 0],
- [0x11a46, 1],
- [0x11a47, 0],
- [0x11a50, 1],
- [0x11a56, 0],
- [0x11a58, 1],
- [0x11a5b, 0],
- [0x11a89, 1],
- [0x11a96, 0],
- [0x11a97, 1],
- [0x11a99, 0],
- [0x11c2f, 1],
- [0x11c36, 0],
- [0x11c37, 1],
- [0x11c3d, 0],
- [0x11c3e, 1],
- [0x11c3f, 0],
- [0x11c91, 1],
- [0x11ca7, 0],
- [0x11ca9, 1],
- [0x11cb0, 0],
- [0x11cb1, 1],
- [0x11cb3, 0],
- [0x11cb4, 1],
- [0x11cb6, 0],
- [0x11d30, 1],
- [0x11d36, 0],
- [0x11d39, 1],
- [0x11d3a, 0],
- [0x11d3b, 1],
- [0x11d3d, 0],
- [0x11d3e, 1],
- [0x11d45, 0],
- [0x11d46, 1],
- [0x11d47, 0],
- [0x11d8f, 1],
- [0x11d91, 0],
- [0x11d94, 1],
- [0x11d95, 0],
- [0x11d96, 1],
- [0x11d97, 0],
- [0x11ef2, 1],
- [0x11ef4, 0],
- [0x11eff, 1],
- [0x11f01, 0],
- [0x11f35, 1],
- [0x11f3a, 0],
- [0x11f3f, 1],
- [0x11f40, 0],
- [0x11f41, 1],
- [0x11f42, 0],
- [0x1343f, 1],
- [0x13440, 0],
- [0x13446, 1],
- [0x13455, 0],
- [0x16aef, 1],
- [0x16af4, 0],
- [0x16b2f, 1],
- [0x16b36, 0],
- [0x16f4e, 1],
- [0x16f4f, 0],
- [0x16f8e, 1],
- [0x16f92, 0],
- [0x16fdf, 1],
- [0x16fe3, 2],
- [0x16fe4, 0],
- [0x16fef, 1],
- [0x16ff1, 2],
- [0x16fff, 1],
- [0x187f7, 2],
- [0x187ff, 1],
- [0x18cd5, 2],
- [0x18cff, 1],
- [0x18d08, 2],
- [0x1afef, 1],
- [0x1aff3, 2],
- [0x1aff4, 1],
- [0x1affb, 2],
- [0x1affc, 1],
- [0x1affe, 2],
- [0x1afff, 1],
- [0x1b122, 2],
- [0x1b131, 1],
- [0x1b132, 2],
- [0x1b14f, 1],
- [0x1b152, 2],
- [0x1b154, 1],
- [0x1b155, 2],
- [0x1b163, 1],
- [0x1b167, 2],
- [0x1b16f, 1],
- [0x1b2fb, 2],
- [0x1bc9c, 1],
- [0x1bc9e, 0],
- [0x1ceff, 1],
- [0x1cf2d, 0],
- [0x1cf2f, 1],
- [0x1cf46, 0],
- [0x1d166, 1],
- [0x1d169, 0],
- [0x1d17a, 1],
- [0x1d182, 0],
- [0x1d184, 1],
- [0x1d18b, 0],
- [0x1d1a9, 1],
- [0x1d1ad, 0],
- [0x1d241, 1],
- [0x1d244, 0],
- [0x1d9ff, 1],
- [0x1da36, 0],
- [0x1da3a, 1],
- [0x1da6c, 0],
- [0x1da74, 1],
- [0x1da75, 0],
- [0x1da83, 1],
- [0x1da84, 0],
- [0x1da9a, 1],
- [0x1da9f, 0],
- [0x1daa0, 1],
- [0x1daaf, 0],
- [0x1dfff, 1],
- [0x1e006, 0],
- [0x1e007, 1],
- [0x1e018, 0],
- [0x1e01a, 1],
- [0x1e021, 0],
- [0x1e022, 1],
- [0x1e024, 0],
- [0x1e025, 1],
- [0x1e02a, 0],
- [0x1e08e, 1],
- [0x1e08f, 0],
- [0x1e12f, 1],
- [0x1e136, 0],
- [0x1e2ad, 1],
- [0x1e2ae, 0],
- [0x1e2eb, 1],
- [0x1e2ef, 0],
- [0x1e4eb, 1],
- [0x1e4ef, 0],
- [0x1e8cf, 1],
- [0x1e8d6, 0],
- [0x1e943, 1],
- [0x1e94a, 0],
- [0x1f003, 1],
- [0x1f004, 2],
- [0x1f0ce, 1],
- [0x1f0cf, 2],
- [0x1f0ff, 1],
- [0x1f10a, -1],
- [0x1f10f, 1],
- [0x1f12d, -1],
- [0x1f12f, 1],
- [0x1f169, -1],
- [0x1f16f, 1],
- [0x1f18d, -1],
- [0x1f18e, 2],
- [0x1f190, -1],
- [0x1f19a, 2],
- [0x1f1ac, -1],
- [0x1f1ff, 1],
- [0x1f202, 2],
- [0x1f20f, 1],
- [0x1f23b, 2],
- [0x1f23f, 1],
- [0x1f248, 2],
- [0x1f24f, 1],
- [0x1f251, 2],
- [0x1f25f, 1],
- [0x1f265, 2],
- [0x1f2ff, 1],
- [0x1f320, 2],
- [0x1f32c, 1],
- [0x1f335, 2],
- [0x1f336, 1],
- [0x1f37c, 2],
- [0x1f37d, 1],
- [0x1f393, 2],
- [0x1f39f, 1],
- [0x1f3ca, 2],
- [0x1f3ce, 1],
- [0x1f3d3, 2],
- [0x1f3df, 1],
- [0x1f3f0, 2],
- [0x1f3f3, 1],
- [0x1f3f4, 2],
- [0x1f3f7, 1],
- [0x1f43e, 2],
- [0x1f43f, 1],
- [0x1f440, 2],
- [0x1f441, 1],
- [0x1f4fc, 2],
- [0x1f4fe, 1],
- [0x1f53d, 2],
- [0x1f54a, 1],
- [0x1f54e, 2],
- [0x1f54f, 1],
- [0x1f567, 2],
- [0x1f579, 1],
- [0x1f57a, 2],
- [0x1f594, 1],
- [0x1f596, 2],
- [0x1f5a3, 1],
- [0x1f5a4, 2],
- [0x1f5fa, 1],
- [0x1f64f, 2],
- [0x1f67f, 1],
- [0x1f6c5, 2],
- [0x1f6cb, 1],
- [0x1f6cc, 2],
- [0x1f6cf, 1],
- [0x1f6d2, 2],
- [0x1f6d4, 1],
- [0x1f6d7, 2],
- [0x1f6db, 1],
- [0x1f6df, 2],
- [0x1f6ea, 1],
- [0x1f6ec, 2],
- [0x1f6f3, 1],
- [0x1f6fc, 2],
- [0x1f7df, 1],
- [0x1f7eb, 2],
- [0x1f7ef, 1],
- [0x1f7f0, 2],
- [0x1f90b, 1],
- [0x1f93a, 2],
- [0x1f93b, 1],
- [0x1f945, 2],
- [0x1f946, 1],
- [0x1f9ff, 2],
- [0x1fa6f, 1],
- [0x1fa7c, 2],
- [0x1fa7f, 1],
- [0x1fa88, 2],
- [0x1fa8f, 1],
- [0x1fabd, 2],
- [0x1fabe, 1],
- [0x1fac5, 2],
- [0x1facd, 1],
- [0x1fadb, 2],
- [0x1fadf, 1],
- [0x1fae8, 2],
- [0x1faef, 1],
- [0x1faf8, 2],
- [0x1ffff, 1],
- [0x2fffd, 2],
- [0x2ffff, 1],
- [0x3fffd, 2],
- [0xe00ff, 1],
- [0xe01ef, 0],
- [0xeffff, 1],
- [0xffffd, -1],
- [0xfffff, 1],
- [0x10fffd, -1],
- [0x7fffffff, 1]
- ].transpose.map(&:freeze)
+ # Fullwidth
+ TYPE_F = /^[#{ %W(
+ \u{3000}
+ \u{FF01}-\u{FF60}
+ \u{FFE0}-\u{FFE6}
+ ).join }]/
+
+ # Halfwidth
+ TYPE_H = /^[#{ %W(
+ \u{20A9}
+ \u{FF61}-\u{FFBE}
+ \u{FFC2}-\u{FFC7}
+ \u{FFCA}-\u{FFCF}
+ \u{FFD2}-\u{FFD7}
+ \u{FFDA}-\u{FFDC}
+ \u{FFE8}-\u{FFEE}
+ ).join }]/
+
+ # Wide
+ TYPE_W = /^[#{ %W(
+ \u{1100}-\u{115F}
+ \u{231A}-\u{231B}
+ \u{2329}-\u{232A}
+ \u{23E9}-\u{23EC}
+ \u{23F0}
+ \u{23F3}
+ \u{25FD}-\u{25FE}
+ \u{2614}-\u{2615}
+ \u{2648}-\u{2653}
+ \u{267F}
+ \u{2693}
+ \u{26A1}
+ \u{26AA}-\u{26AB}
+ \u{26BD}-\u{26BE}
+ \u{26C4}-\u{26C5}
+ \u{26CE}
+ \u{26D4}
+ \u{26EA}
+ \u{26F2}-\u{26F3}
+ \u{26F5}
+ \u{26FA}
+ \u{26FD}
+ \u{2705}
+ \u{270A}-\u{270B}
+ \u{2728}
+ \u{274C}
+ \u{274E}
+ \u{2753}-\u{2755}
+ \u{2757}
+ \u{2795}-\u{2797}
+ \u{27B0}
+ \u{27BF}
+ \u{2B1B}-\u{2B1C}
+ \u{2B50}
+ \u{2B55}
+ \u{2E80}-\u{2E99}
+ \u{2E9B}-\u{2EF3}
+ \u{2F00}-\u{2FD5}
+ \u{2FF0}-\u{2FFB}
+ \u{3001}-\u{303E}
+ \u{3041}-\u{3096}
+ \u{3099}-\u{30FF}
+ \u{3105}-\u{312F}
+ \u{3131}-\u{318E}
+ \u{3190}-\u{31E3}
+ \u{31F0}-\u{321E}
+ \u{3220}-\u{3247}
+ \u{3250}-\u{4DBF}
+ \u{4E00}-\u{A48C}
+ \u{A490}-\u{A4C6}
+ \u{A960}-\u{A97C}
+ \u{AC00}-\u{D7A3}
+ \u{F900}-\u{FAFF}
+ \u{FE10}-\u{FE19}
+ \u{FE30}-\u{FE52}
+ \u{FE54}-\u{FE66}
+ \u{FE68}-\u{FE6B}
+ \u{16FE0}-\u{16FE4}
+ \u{16FF0}-\u{16FF1}
+ \u{17000}-\u{187F7}
+ \u{18800}-\u{18CD5}
+ \u{18D00}-\u{18D08}
+ \u{1B000}-\u{1B11E}
+ \u{1B150}-\u{1B152}
+ \u{1B164}-\u{1B167}
+ \u{1B170}-\u{1B2FB}
+ \u{1F004}
+ \u{1F0CF}
+ \u{1F18E}
+ \u{1F191}-\u{1F19A}
+ \u{1F200}-\u{1F202}
+ \u{1F210}-\u{1F23B}
+ \u{1F240}-\u{1F248}
+ \u{1F250}-\u{1F251}
+ \u{1F260}-\u{1F265}
+ \u{1F300}-\u{1F320}
+ \u{1F32D}-\u{1F335}
+ \u{1F337}-\u{1F37C}
+ \u{1F37E}-\u{1F393}
+ \u{1F3A0}-\u{1F3CA}
+ \u{1F3CF}-\u{1F3D3}
+ \u{1F3E0}-\u{1F3F0}
+ \u{1F3F4}
+ \u{1F3F8}-\u{1F43E}
+ \u{1F440}
+ \u{1F442}-\u{1F4FC}
+ \u{1F4FF}-\u{1F53D}
+ \u{1F54B}-\u{1F54E}
+ \u{1F550}-\u{1F567}
+ \u{1F57A}
+ \u{1F595}-\u{1F596}
+ \u{1F5A4}
+ \u{1F5FB}-\u{1F64F}
+ \u{1F680}-\u{1F6C5}
+ \u{1F6CC}
+ \u{1F6D0}-\u{1F6D2}
+ \u{1F6D5}-\u{1F6D7}
+ \u{1F6EB}-\u{1F6EC}
+ \u{1F6F4}-\u{1F6FC}
+ \u{1F7E0}-\u{1F7EB}
+ \u{1F90C}-\u{1F93A}
+ \u{1F93C}-\u{1F945}
+ \u{1F947}-\u{1F978}
+ \u{1F97A}-\u{1F9CB}
+ \u{1F9CD}-\u{1F9FF}
+ \u{1FA70}-\u{1FA74}
+ \u{1FA78}-\u{1FA7A}
+ \u{1FA80}-\u{1FA86}
+ \u{1FA90}-\u{1FAA8}
+ \u{1FAB0}-\u{1FAB6}
+ \u{1FAC0}-\u{1FAC2}
+ \u{1FAD0}-\u{1FAD6}
+ \u{20000}-\u{2FFFD}
+ \u{30000}-\u{3FFFD}
+ ).join }]/
+
+ # Narrow
+ TYPE_NA = /^[#{ %W(
+ \u{0020}-\u{007E}
+ \u{00A2}-\u{00A3}
+ \u{00A5}-\u{00A6}
+ \u{00AC}
+ \u{00AF}
+ \u{27E6}-\u{27ED}
+ \u{2985}-\u{2986}
+ ).join }]/
+
+ # Ambiguous
+ TYPE_A = /^[#{ %W(
+ \u{00A1}
+ \u{00A4}
+ \u{00A7}-\u{00A8}
+ \u{00AA}
+ \u{00AD}-\u{00AE}
+ \u{00B0}-\u{00B4}
+ \u{00B6}-\u{00BA}
+ \u{00BC}-\u{00BF}
+ \u{00C6}
+ \u{00D0}
+ \u{00D7}-\u{00D8}
+ \u{00DE}-\u{00E1}
+ \u{00E6}
+ \u{00E8}-\u{00EA}
+ \u{00EC}-\u{00ED}
+ \u{00F0}
+ \u{00F2}-\u{00F3}
+ \u{00F7}-\u{00FA}
+ \u{00FC}
+ \u{00FE}
+ \u{0101}
+ \u{0111}
+ \u{0113}
+ \u{011B}
+ \u{0126}-\u{0127}
+ \u{012B}
+ \u{0131}-\u{0133}
+ \u{0138}
+ \u{013F}-\u{0142}
+ \u{0144}
+ \u{0148}-\u{014B}
+ \u{014D}
+ \u{0152}-\u{0153}
+ \u{0166}-\u{0167}
+ \u{016B}
+ \u{01CE}
+ \u{01D0}
+ \u{01D2}
+ \u{01D4}
+ \u{01D6}
+ \u{01D8}
+ \u{01DA}
+ \u{01DC}
+ \u{0251}
+ \u{0261}
+ \u{02C4}
+ \u{02C7}
+ \u{02C9}-\u{02CB}
+ \u{02CD}
+ \u{02D0}
+ \u{02D8}-\u{02DB}
+ \u{02DD}
+ \u{02DF}
+ \u{0300}-\u{036F}
+ \u{0391}-\u{03A1}
+ \u{03A3}-\u{03A9}
+ \u{03B1}-\u{03C1}
+ \u{03C3}-\u{03C9}
+ \u{0401}
+ \u{0410}-\u{044F}
+ \u{0451}
+ \u{2010}
+ \u{2013}-\u{2016}
+ \u{2018}-\u{2019}
+ \u{201C}-\u{201D}
+ \u{2020}-\u{2022}
+ \u{2024}-\u{2027}
+ \u{2030}
+ \u{2032}-\u{2033}
+ \u{2035}
+ \u{203B}
+ \u{203E}
+ \u{2074}
+ \u{207F}
+ \u{2081}-\u{2084}
+ \u{20AC}
+ \u{2103}
+ \u{2105}
+ \u{2109}
+ \u{2113}
+ \u{2116}
+ \u{2121}-\u{2122}
+ \u{2126}
+ \u{212B}
+ \u{2153}-\u{2154}
+ \u{215B}-\u{215E}
+ \u{2160}-\u{216B}
+ \u{2170}-\u{2179}
+ \u{2189}
+ \u{2190}-\u{2199}
+ \u{21B8}-\u{21B9}
+ \u{21D2}
+ \u{21D4}
+ \u{21E7}
+ \u{2200}
+ \u{2202}-\u{2203}
+ \u{2207}-\u{2208}
+ \u{220B}
+ \u{220F}
+ \u{2211}
+ \u{2215}
+ \u{221A}
+ \u{221D}-\u{2220}
+ \u{2223}
+ \u{2225}
+ \u{2227}-\u{222C}
+ \u{222E}
+ \u{2234}-\u{2237}
+ \u{223C}-\u{223D}
+ \u{2248}
+ \u{224C}
+ \u{2252}
+ \u{2260}-\u{2261}
+ \u{2264}-\u{2267}
+ \u{226A}-\u{226B}
+ \u{226E}-\u{226F}
+ \u{2282}-\u{2283}
+ \u{2286}-\u{2287}
+ \u{2295}
+ \u{2299}
+ \u{22A5}
+ \u{22BF}
+ \u{2312}
+ \u{2460}-\u{24E9}
+ \u{24EB}-\u{254B}
+ \u{2550}-\u{2573}
+ \u{2580}-\u{258F}
+ \u{2592}-\u{2595}
+ \u{25A0}-\u{25A1}
+ \u{25A3}-\u{25A9}
+ \u{25B2}-\u{25B3}
+ \u{25B6}-\u{25B7}
+ \u{25BC}-\u{25BD}
+ \u{25C0}-\u{25C1}
+ \u{25C6}-\u{25C8}
+ \u{25CB}
+ \u{25CE}-\u{25D1}
+ \u{25E2}-\u{25E5}
+ \u{25EF}
+ \u{2605}-\u{2606}
+ \u{2609}
+ \u{260E}-\u{260F}
+ \u{261C}
+ \u{261E}
+ \u{2640}
+ \u{2642}
+ \u{2660}-\u{2661}
+ \u{2663}-\u{2665}
+ \u{2667}-\u{266A}
+ \u{266C}-\u{266D}
+ \u{266F}
+ \u{269E}-\u{269F}
+ \u{26BF}
+ \u{26C6}-\u{26CD}
+ \u{26CF}-\u{26D3}
+ \u{26D5}-\u{26E1}
+ \u{26E3}
+ \u{26E8}-\u{26E9}
+ \u{26EB}-\u{26F1}
+ \u{26F4}
+ \u{26F6}-\u{26F9}
+ \u{26FB}-\u{26FC}
+ \u{26FE}-\u{26FF}
+ \u{273D}
+ \u{2776}-\u{277F}
+ \u{2B56}-\u{2B59}
+ \u{3248}-\u{324F}
+ \u{E000}-\u{F8FF}
+ \u{FE00}-\u{FE0F}
+ \u{FFFD}
+ \u{1F100}-\u{1F10A}
+ \u{1F110}-\u{1F12D}
+ \u{1F130}-\u{1F169}
+ \u{1F170}-\u{1F18D}
+ \u{1F18F}-\u{1F190}
+ \u{1F19B}-\u{1F1AC}
+ \u{E0100}-\u{E01EF}
+ \u{F0000}-\u{FFFFD}
+ \u{100000}-\u{10FFFD}
+ ).join }]/
+
+ # Neutral
+ TYPE_N = /^[#{ %W(
+ \u{0000}-\u{001F}
+ \u{007F}-\u{00A0}
+ \u{00A9}
+ \u{00AB}
+ \u{00B5}
+ \u{00BB}
+ \u{00C0}-\u{00C5}
+ \u{00C7}-\u{00CF}
+ \u{00D1}-\u{00D6}
+ \u{00D9}-\u{00DD}
+ \u{00E2}-\u{00E5}
+ \u{00E7}
+ \u{00EB}
+ \u{00EE}-\u{00EF}
+ \u{00F1}
+ \u{00F4}-\u{00F6}
+ \u{00FB}
+ \u{00FD}
+ \u{00FF}-\u{0100}
+ \u{0102}-\u{0110}
+ \u{0112}
+ \u{0114}-\u{011A}
+ \u{011C}-\u{0125}
+ \u{0128}-\u{012A}
+ \u{012C}-\u{0130}
+ \u{0134}-\u{0137}
+ \u{0139}-\u{013E}
+ \u{0143}
+ \u{0145}-\u{0147}
+ \u{014C}
+ \u{014E}-\u{0151}
+ \u{0154}-\u{0165}
+ \u{0168}-\u{016A}
+ \u{016C}-\u{01CD}
+ \u{01CF}
+ \u{01D1}
+ \u{01D3}
+ \u{01D5}
+ \u{01D7}
+ \u{01D9}
+ \u{01DB}
+ \u{01DD}-\u{0250}
+ \u{0252}-\u{0260}
+ \u{0262}-\u{02C3}
+ \u{02C5}-\u{02C6}
+ \u{02C8}
+ \u{02CC}
+ \u{02CE}-\u{02CF}
+ \u{02D1}-\u{02D7}
+ \u{02DC}
+ \u{02DE}
+ \u{02E0}-\u{02FF}
+ \u{0370}-\u{0377}
+ \u{037A}-\u{037F}
+ \u{0384}-\u{038A}
+ \u{038C}
+ \u{038E}-\u{0390}
+ \u{03AA}-\u{03B0}
+ \u{03C2}
+ \u{03CA}-\u{0400}
+ \u{0402}-\u{040F}
+ \u{0450}
+ \u{0452}-\u{052F}
+ \u{0531}-\u{0556}
+ \u{0559}-\u{058A}
+ \u{058D}-\u{058F}
+ \u{0591}-\u{05C7}
+ \u{05D0}-\u{05EA}
+ \u{05EF}-\u{05F4}
+ \u{0600}-\u{061C}
+ \u{061E}-\u{070D}
+ \u{070F}-\u{074A}
+ \u{074D}-\u{07B1}
+ \u{07C0}-\u{07FA}
+ \u{07FD}-\u{082D}
+ \u{0830}-\u{083E}
+ \u{0840}-\u{085B}
+ \u{085E}
+ \u{0860}-\u{086A}
+ \u{08A0}-\u{08B4}
+ \u{08B6}-\u{08C7}
+ \u{08D3}-\u{0983}
+ \u{0985}-\u{098C}
+ \u{098F}-\u{0990}
+ \u{0993}-\u{09A8}
+ \u{09AA}-\u{09B0}
+ \u{09B2}
+ \u{09B6}-\u{09B9}
+ \u{09BC}-\u{09C4}
+ \u{09C7}-\u{09C8}
+ \u{09CB}-\u{09CE}
+ \u{09D7}
+ \u{09DC}-\u{09DD}
+ \u{09DF}-\u{09E3}
+ \u{09E6}-\u{09FE}
+ \u{0A01}-\u{0A03}
+ \u{0A05}-\u{0A0A}
+ \u{0A0F}-\u{0A10}
+ \u{0A13}-\u{0A28}
+ \u{0A2A}-\u{0A30}
+ \u{0A32}-\u{0A33}
+ \u{0A35}-\u{0A36}
+ \u{0A38}-\u{0A39}
+ \u{0A3C}
+ \u{0A3E}-\u{0A42}
+ \u{0A47}-\u{0A48}
+ \u{0A4B}-\u{0A4D}
+ \u{0A51}
+ \u{0A59}-\u{0A5C}
+ \u{0A5E}
+ \u{0A66}-\u{0A76}
+ \u{0A81}-\u{0A83}
+ \u{0A85}-\u{0A8D}
+ \u{0A8F}-\u{0A91}
+ \u{0A93}-\u{0AA8}
+ \u{0AAA}-\u{0AB0}
+ \u{0AB2}-\u{0AB3}
+ \u{0AB5}-\u{0AB9}
+ \u{0ABC}-\u{0AC5}
+ \u{0AC7}-\u{0AC9}
+ \u{0ACB}-\u{0ACD}
+ \u{0AD0}
+ \u{0AE0}-\u{0AE3}
+ \u{0AE6}-\u{0AF1}
+ \u{0AF9}-\u{0AFF}
+ \u{0B01}-\u{0B03}
+ \u{0B05}-\u{0B0C}
+ \u{0B0F}-\u{0B10}
+ \u{0B13}-\u{0B28}
+ \u{0B2A}-\u{0B30}
+ \u{0B32}-\u{0B33}
+ \u{0B35}-\u{0B39}
+ \u{0B3C}-\u{0B44}
+ \u{0B47}-\u{0B48}
+ \u{0B4B}-\u{0B4D}
+ \u{0B55}-\u{0B57}
+ \u{0B5C}-\u{0B5D}
+ \u{0B5F}-\u{0B63}
+ \u{0B66}-\u{0B77}
+ \u{0B82}-\u{0B83}
+ \u{0B85}-\u{0B8A}
+ \u{0B8E}-\u{0B90}
+ \u{0B92}-\u{0B95}
+ \u{0B99}-\u{0B9A}
+ \u{0B9C}
+ \u{0B9E}-\u{0B9F}
+ \u{0BA3}-\u{0BA4}
+ \u{0BA8}-\u{0BAA}
+ \u{0BAE}-\u{0BB9}
+ \u{0BBE}-\u{0BC2}
+ \u{0BC6}-\u{0BC8}
+ \u{0BCA}-\u{0BCD}
+ \u{0BD0}
+ \u{0BD7}
+ \u{0BE6}-\u{0BFA}
+ \u{0C00}-\u{0C0C}
+ \u{0C0E}-\u{0C10}
+ \u{0C12}-\u{0C28}
+ \u{0C2A}-\u{0C39}
+ \u{0C3D}-\u{0C44}
+ \u{0C46}-\u{0C48}
+ \u{0C4A}-\u{0C4D}
+ \u{0C55}-\u{0C56}
+ \u{0C58}-\u{0C5A}
+ \u{0C60}-\u{0C63}
+ \u{0C66}-\u{0C6F}
+ \u{0C77}-\u{0C8C}
+ \u{0C8E}-\u{0C90}
+ \u{0C92}-\u{0CA8}
+ \u{0CAA}-\u{0CB3}
+ \u{0CB5}-\u{0CB9}
+ \u{0CBC}-\u{0CC4}
+ \u{0CC6}-\u{0CC8}
+ \u{0CCA}-\u{0CCD}
+ \u{0CD5}-\u{0CD6}
+ \u{0CDE}
+ \u{0CE0}-\u{0CE3}
+ \u{0CE6}-\u{0CEF}
+ \u{0CF1}-\u{0CF2}
+ \u{0D00}-\u{0D0C}
+ \u{0D0E}-\u{0D10}
+ \u{0D12}-\u{0D44}
+ \u{0D46}-\u{0D48}
+ \u{0D4A}-\u{0D4F}
+ \u{0D54}-\u{0D63}
+ \u{0D66}-\u{0D7F}
+ \u{0D81}-\u{0D83}
+ \u{0D85}-\u{0D96}
+ \u{0D9A}-\u{0DB1}
+ \u{0DB3}-\u{0DBB}
+ \u{0DBD}
+ \u{0DC0}-\u{0DC6}
+ \u{0DCA}
+ \u{0DCF}-\u{0DD4}
+ \u{0DD6}
+ \u{0DD8}-\u{0DDF}
+ \u{0DE6}-\u{0DEF}
+ \u{0DF2}-\u{0DF4}
+ \u{0E01}-\u{0E3A}
+ \u{0E3F}-\u{0E5B}
+ \u{0E81}-\u{0E82}
+ \u{0E84}
+ \u{0E86}-\u{0E8A}
+ \u{0E8C}-\u{0EA3}
+ \u{0EA5}
+ \u{0EA7}-\u{0EBD}
+ \u{0EC0}-\u{0EC4}
+ \u{0EC6}
+ \u{0EC8}-\u{0ECD}
+ \u{0ED0}-\u{0ED9}
+ \u{0EDC}-\u{0EDF}
+ \u{0F00}-\u{0F47}
+ \u{0F49}-\u{0F6C}
+ \u{0F71}-\u{0F97}
+ \u{0F99}-\u{0FBC}
+ \u{0FBE}-\u{0FCC}
+ \u{0FCE}-\u{0FDA}
+ \u{1000}-\u{10C5}
+ \u{10C7}
+ \u{10CD}
+ \u{10D0}-\u{10FF}
+ \u{1160}-\u{1248}
+ \u{124A}-\u{124D}
+ \u{1250}-\u{1256}
+ \u{1258}
+ \u{125A}-\u{125D}
+ \u{1260}-\u{1288}
+ \u{128A}-\u{128D}
+ \u{1290}-\u{12B0}
+ \u{12B2}-\u{12B5}
+ \u{12B8}-\u{12BE}
+ \u{12C0}
+ \u{12C2}-\u{12C5}
+ \u{12C8}-\u{12D6}
+ \u{12D8}-\u{1310}
+ \u{1312}-\u{1315}
+ \u{1318}-\u{135A}
+ \u{135D}-\u{137C}
+ \u{1380}-\u{1399}
+ \u{13A0}-\u{13F5}
+ \u{13F8}-\u{13FD}
+ \u{1400}-\u{169C}
+ \u{16A0}-\u{16F8}
+ \u{1700}-\u{170C}
+ \u{170E}-\u{1714}
+ \u{1720}-\u{1736}
+ \u{1740}-\u{1753}
+ \u{1760}-\u{176C}
+ \u{176E}-\u{1770}
+ \u{1772}-\u{1773}
+ \u{1780}-\u{17DD}
+ \u{17E0}-\u{17E9}
+ \u{17F0}-\u{17F9}
+ \u{1800}-\u{180E}
+ \u{1810}-\u{1819}
+ \u{1820}-\u{1878}
+ \u{1880}-\u{18AA}
+ \u{18B0}-\u{18F5}
+ \u{1900}-\u{191E}
+ \u{1920}-\u{192B}
+ \u{1930}-\u{193B}
+ \u{1940}
+ \u{1944}-\u{196D}
+ \u{1970}-\u{1974}
+ \u{1980}-\u{19AB}
+ \u{19B0}-\u{19C9}
+ \u{19D0}-\u{19DA}
+ \u{19DE}-\u{1A1B}
+ \u{1A1E}-\u{1A5E}
+ \u{1A60}-\u{1A7C}
+ \u{1A7F}-\u{1A89}
+ \u{1A90}-\u{1A99}
+ \u{1AA0}-\u{1AAD}
+ \u{1AB0}-\u{1AC0}
+ \u{1B00}-\u{1B4B}
+ \u{1B50}-\u{1B7C}
+ \u{1B80}-\u{1BF3}
+ \u{1BFC}-\u{1C37}
+ \u{1C3B}-\u{1C49}
+ \u{1C4D}-\u{1C88}
+ \u{1C90}-\u{1CBA}
+ \u{1CBD}-\u{1CC7}
+ \u{1CD0}-\u{1CFA}
+ \u{1D00}-\u{1DF9}
+ \u{1DFB}-\u{1F15}
+ \u{1F18}-\u{1F1D}
+ \u{1F20}-\u{1F45}
+ \u{1F48}-\u{1F4D}
+ \u{1F50}-\u{1F57}
+ \u{1F59}
+ \u{1F5B}
+ \u{1F5D}
+ \u{1F5F}-\u{1F7D}
+ \u{1F80}-\u{1FB4}
+ \u{1FB6}-\u{1FC4}
+ \u{1FC6}-\u{1FD3}
+ \u{1FD6}-\u{1FDB}
+ \u{1FDD}-\u{1FEF}
+ \u{1FF2}-\u{1FF4}
+ \u{1FF6}-\u{1FFE}
+ \u{2000}-\u{200F}
+ \u{2011}-\u{2012}
+ \u{2017}
+ \u{201A}-\u{201B}
+ \u{201E}-\u{201F}
+ \u{2023}
+ \u{2028}-\u{202F}
+ \u{2031}
+ \u{2034}
+ \u{2036}-\u{203A}
+ \u{203C}-\u{203D}
+ \u{203F}-\u{2064}
+ \u{2066}-\u{2071}
+ \u{2075}-\u{207E}
+ \u{2080}
+ \u{2085}-\u{208E}
+ \u{2090}-\u{209C}
+ \u{20A0}-\u{20A8}
+ \u{20AA}-\u{20AB}
+ \u{20AD}-\u{20BF}
+ \u{20D0}-\u{20F0}
+ \u{2100}-\u{2102}
+ \u{2104}
+ \u{2106}-\u{2108}
+ \u{210A}-\u{2112}
+ \u{2114}-\u{2115}
+ \u{2117}-\u{2120}
+ \u{2123}-\u{2125}
+ \u{2127}-\u{212A}
+ \u{212C}-\u{2152}
+ \u{2155}-\u{215A}
+ \u{215F}
+ \u{216C}-\u{216F}
+ \u{217A}-\u{2188}
+ \u{218A}-\u{218B}
+ \u{219A}-\u{21B7}
+ \u{21BA}-\u{21D1}
+ \u{21D3}
+ \u{21D5}-\u{21E6}
+ \u{21E8}-\u{21FF}
+ \u{2201}
+ \u{2204}-\u{2206}
+ \u{2209}-\u{220A}
+ \u{220C}-\u{220E}
+ \u{2210}
+ \u{2212}-\u{2214}
+ \u{2216}-\u{2219}
+ \u{221B}-\u{221C}
+ \u{2221}-\u{2222}
+ \u{2224}
+ \u{2226}
+ \u{222D}
+ \u{222F}-\u{2233}
+ \u{2238}-\u{223B}
+ \u{223E}-\u{2247}
+ \u{2249}-\u{224B}
+ \u{224D}-\u{2251}
+ \u{2253}-\u{225F}
+ \u{2262}-\u{2263}
+ \u{2268}-\u{2269}
+ \u{226C}-\u{226D}
+ \u{2270}-\u{2281}
+ \u{2284}-\u{2285}
+ \u{2288}-\u{2294}
+ \u{2296}-\u{2298}
+ \u{229A}-\u{22A4}
+ \u{22A6}-\u{22BE}
+ \u{22C0}-\u{2311}
+ \u{2313}-\u{2319}
+ \u{231C}-\u{2328}
+ \u{232B}-\u{23E8}
+ \u{23ED}-\u{23EF}
+ \u{23F1}-\u{23F2}
+ \u{23F4}-\u{2426}
+ \u{2440}-\u{244A}
+ \u{24EA}
+ \u{254C}-\u{254F}
+ \u{2574}-\u{257F}
+ \u{2590}-\u{2591}
+ \u{2596}-\u{259F}
+ \u{25A2}
+ \u{25AA}-\u{25B1}
+ \u{25B4}-\u{25B5}
+ \u{25B8}-\u{25BB}
+ \u{25BE}-\u{25BF}
+ \u{25C2}-\u{25C5}
+ \u{25C9}-\u{25CA}
+ \u{25CC}-\u{25CD}
+ \u{25D2}-\u{25E1}
+ \u{25E6}-\u{25EE}
+ \u{25F0}-\u{25FC}
+ \u{25FF}-\u{2604}
+ \u{2607}-\u{2608}
+ \u{260A}-\u{260D}
+ \u{2610}-\u{2613}
+ \u{2616}-\u{261B}
+ \u{261D}
+ \u{261F}-\u{263F}
+ \u{2641}
+ \u{2643}-\u{2647}
+ \u{2654}-\u{265F}
+ \u{2662}
+ \u{2666}
+ \u{266B}
+ \u{266E}
+ \u{2670}-\u{267E}
+ \u{2680}-\u{2692}
+ \u{2694}-\u{269D}
+ \u{26A0}
+ \u{26A2}-\u{26A9}
+ \u{26AC}-\u{26BC}
+ \u{26C0}-\u{26C3}
+ \u{26E2}
+ \u{26E4}-\u{26E7}
+ \u{2700}-\u{2704}
+ \u{2706}-\u{2709}
+ \u{270C}-\u{2727}
+ \u{2729}-\u{273C}
+ \u{273E}-\u{274B}
+ \u{274D}
+ \u{274F}-\u{2752}
+ \u{2756}
+ \u{2758}-\u{2775}
+ \u{2780}-\u{2794}
+ \u{2798}-\u{27AF}
+ \u{27B1}-\u{27BE}
+ \u{27C0}-\u{27E5}
+ \u{27EE}-\u{2984}
+ \u{2987}-\u{2B1A}
+ \u{2B1D}-\u{2B4F}
+ \u{2B51}-\u{2B54}
+ \u{2B5A}-\u{2B73}
+ \u{2B76}-\u{2B95}
+ \u{2B97}-\u{2C2E}
+ \u{2C30}-\u{2C5E}
+ \u{2C60}-\u{2CF3}
+ \u{2CF9}-\u{2D25}
+ \u{2D27}
+ \u{2D2D}
+ \u{2D30}-\u{2D67}
+ \u{2D6F}-\u{2D70}
+ \u{2D7F}-\u{2D96}
+ \u{2DA0}-\u{2DA6}
+ \u{2DA8}-\u{2DAE}
+ \u{2DB0}-\u{2DB6}
+ \u{2DB8}-\u{2DBE}
+ \u{2DC0}-\u{2DC6}
+ \u{2DC8}-\u{2DCE}
+ \u{2DD0}-\u{2DD6}
+ \u{2DD8}-\u{2DDE}
+ \u{2DE0}-\u{2E52}
+ \u{303F}
+ \u{4DC0}-\u{4DFF}
+ \u{A4D0}-\u{A62B}
+ \u{A640}-\u{A6F7}
+ \u{A700}-\u{A7BF}
+ \u{A7C2}-\u{A7CA}
+ \u{A7F5}-\u{A82C}
+ \u{A830}-\u{A839}
+ \u{A840}-\u{A877}
+ \u{A880}-\u{A8C5}
+ \u{A8CE}-\u{A8D9}
+ \u{A8E0}-\u{A953}
+ \u{A95F}
+ \u{A980}-\u{A9CD}
+ \u{A9CF}-\u{A9D9}
+ \u{A9DE}-\u{A9FE}
+ \u{AA00}-\u{AA36}
+ \u{AA40}-\u{AA4D}
+ \u{AA50}-\u{AA59}
+ \u{AA5C}-\u{AAC2}
+ \u{AADB}-\u{AAF6}
+ \u{AB01}-\u{AB06}
+ \u{AB09}-\u{AB0E}
+ \u{AB11}-\u{AB16}
+ \u{AB20}-\u{AB26}
+ \u{AB28}-\u{AB2E}
+ \u{AB30}-\u{AB6B}
+ \u{AB70}-\u{ABED}
+ \u{ABF0}-\u{ABF9}
+ \u{D7B0}-\u{D7C6}
+ \u{D7CB}-\u{D7FB}
+ \u{FB00}-\u{FB06}
+ \u{FB13}-\u{FB17}
+ \u{FB1D}-\u{FB36}
+ \u{FB38}-\u{FB3C}
+ \u{FB3E}
+ \u{FB40}-\u{FB41}
+ \u{FB43}-\u{FB44}
+ \u{FB46}-\u{FBC1}
+ \u{FBD3}-\u{FD3F}
+ \u{FD50}-\u{FD8F}
+ \u{FD92}-\u{FDC7}
+ \u{FDF0}-\u{FDFD}
+ \u{FE20}-\u{FE2F}
+ \u{FE70}-\u{FE74}
+ \u{FE76}-\u{FEFC}
+ \u{FEFF}
+ \u{FFF9}-\u{FFFC}
+ \u{10000}-\u{1000B}
+ \u{1000D}-\u{10026}
+ \u{10028}-\u{1003A}
+ \u{1003C}-\u{1003D}
+ \u{1003F}-\u{1004D}
+ \u{10050}-\u{1005D}
+ \u{10080}-\u{100FA}
+ \u{10100}-\u{10102}
+ \u{10107}-\u{10133}
+ \u{10137}-\u{1018E}
+ \u{10190}-\u{1019C}
+ \u{101A0}
+ \u{101D0}-\u{101FD}
+ \u{10280}-\u{1029C}
+ \u{102A0}-\u{102D0}
+ \u{102E0}-\u{102FB}
+ \u{10300}-\u{10323}
+ \u{1032D}-\u{1034A}
+ \u{10350}-\u{1037A}
+ \u{10380}-\u{1039D}
+ \u{1039F}-\u{103C3}
+ \u{103C8}-\u{103D5}
+ \u{10400}-\u{1049D}
+ \u{104A0}-\u{104A9}
+ \u{104B0}-\u{104D3}
+ \u{104D8}-\u{104FB}
+ \u{10500}-\u{10527}
+ \u{10530}-\u{10563}
+ \u{1056F}
+ \u{10600}-\u{10736}
+ \u{10740}-\u{10755}
+ \u{10760}-\u{10767}
+ \u{10800}-\u{10805}
+ \u{10808}
+ \u{1080A}-\u{10835}
+ \u{10837}-\u{10838}
+ \u{1083C}
+ \u{1083F}-\u{10855}
+ \u{10857}-\u{1089E}
+ \u{108A7}-\u{108AF}
+ \u{108E0}-\u{108F2}
+ \u{108F4}-\u{108F5}
+ \u{108FB}-\u{1091B}
+ \u{1091F}-\u{10939}
+ \u{1093F}
+ \u{10980}-\u{109B7}
+ \u{109BC}-\u{109CF}
+ \u{109D2}-\u{10A03}
+ \u{10A05}-\u{10A06}
+ \u{10A0C}-\u{10A13}
+ \u{10A15}-\u{10A17}
+ \u{10A19}-\u{10A35}
+ \u{10A38}-\u{10A3A}
+ \u{10A3F}-\u{10A48}
+ \u{10A50}-\u{10A58}
+ \u{10A60}-\u{10A9F}
+ \u{10AC0}-\u{10AE6}
+ \u{10AEB}-\u{10AF6}
+ \u{10B00}-\u{10B35}
+ \u{10B39}-\u{10B55}
+ \u{10B58}-\u{10B72}
+ \u{10B78}-\u{10B91}
+ \u{10B99}-\u{10B9C}
+ \u{10BA9}-\u{10BAF}
+ \u{10C00}-\u{10C48}
+ \u{10C80}-\u{10CB2}
+ \u{10CC0}-\u{10CF2}
+ \u{10CFA}-\u{10D27}
+ \u{10D30}-\u{10D39}
+ \u{10E60}-\u{10E7E}
+ \u{10E80}-\u{10EA9}
+ \u{10EAB}-\u{10EAD}
+ \u{10EB0}-\u{10EB1}
+ \u{10F00}-\u{10F27}
+ \u{10F30}-\u{10F59}
+ \u{10FB0}-\u{10FCB}
+ \u{10FE0}-\u{10FF6}
+ \u{11000}-\u{1104D}
+ \u{11052}-\u{1106F}
+ \u{1107F}-\u{110C1}
+ \u{110CD}
+ \u{110D0}-\u{110E8}
+ \u{110F0}-\u{110F9}
+ \u{11100}-\u{11134}
+ \u{11136}-\u{11147}
+ \u{11150}-\u{11176}
+ \u{11180}-\u{111DF}
+ \u{111E1}-\u{111F4}
+ \u{11200}-\u{11211}
+ \u{11213}-\u{1123E}
+ \u{11280}-\u{11286}
+ \u{11288}
+ \u{1128A}-\u{1128D}
+ \u{1128F}-\u{1129D}
+ \u{1129F}-\u{112A9}
+ \u{112B0}-\u{112EA}
+ \u{112F0}-\u{112F9}
+ \u{11300}-\u{11303}
+ \u{11305}-\u{1130C}
+ \u{1130F}-\u{11310}
+ \u{11313}-\u{11328}
+ \u{1132A}-\u{11330}
+ \u{11332}-\u{11333}
+ \u{11335}-\u{11339}
+ \u{1133B}-\u{11344}
+ \u{11347}-\u{11348}
+ \u{1134B}-\u{1134D}
+ \u{11350}
+ \u{11357}
+ \u{1135D}-\u{11363}
+ \u{11366}-\u{1136C}
+ \u{11370}-\u{11374}
+ \u{11400}-\u{1145B}
+ \u{1145D}-\u{11461}
+ \u{11480}-\u{114C7}
+ \u{114D0}-\u{114D9}
+ \u{11580}-\u{115B5}
+ \u{115B8}-\u{115DD}
+ \u{11600}-\u{11644}
+ \u{11650}-\u{11659}
+ \u{11660}-\u{1166C}
+ \u{11680}-\u{116B8}
+ \u{116C0}-\u{116C9}
+ \u{11700}-\u{1171A}
+ \u{1171D}-\u{1172B}
+ \u{11730}-\u{1173F}
+ \u{11800}-\u{1183B}
+ \u{118A0}-\u{118F2}
+ \u{118FF}-\u{11906}
+ \u{11909}
+ \u{1190C}-\u{11913}
+ \u{11915}-\u{11916}
+ \u{11918}-\u{11935}
+ \u{11937}-\u{11938}
+ \u{1193B}-\u{11946}
+ \u{11950}-\u{11959}
+ \u{119A0}-\u{119A7}
+ \u{119AA}-\u{119D7}
+ \u{119DA}-\u{119E4}
+ \u{11A00}-\u{11A47}
+ \u{11A50}-\u{11AA2}
+ \u{11AC0}-\u{11AF8}
+ \u{11C00}-\u{11C08}
+ \u{11C0A}-\u{11C36}
+ \u{11C38}-\u{11C45}
+ \u{11C50}-\u{11C6C}
+ \u{11C70}-\u{11C8F}
+ \u{11C92}-\u{11CA7}
+ \u{11CA9}-\u{11CB6}
+ \u{11D00}-\u{11D06}
+ \u{11D08}-\u{11D09}
+ \u{11D0B}-\u{11D36}
+ \u{11D3A}
+ \u{11D3C}-\u{11D3D}
+ \u{11D3F}-\u{11D47}
+ \u{11D50}-\u{11D59}
+ \u{11D60}-\u{11D65}
+ \u{11D67}-\u{11D68}
+ \u{11D6A}-\u{11D8E}
+ \u{11D90}-\u{11D91}
+ \u{11D93}-\u{11D98}
+ \u{11DA0}-\u{11DA9}
+ \u{11EE0}-\u{11EF8}
+ \u{11FB0}
+ \u{11FC0}-\u{11FF1}
+ \u{11FFF}-\u{12399}
+ \u{12400}-\u{1246E}
+ \u{12470}-\u{12474}
+ \u{12480}-\u{12543}
+ \u{13000}-\u{1342E}
+ \u{13430}-\u{13438}
+ \u{14400}-\u{14646}
+ \u{16800}-\u{16A38}
+ \u{16A40}-\u{16A5E}
+ \u{16A60}-\u{16A69}
+ \u{16A6E}-\u{16A6F}
+ \u{16AD0}-\u{16AED}
+ \u{16AF0}-\u{16AF5}
+ \u{16B00}-\u{16B45}
+ \u{16B50}-\u{16B59}
+ \u{16B5B}-\u{16B61}
+ \u{16B63}-\u{16B77}
+ \u{16B7D}-\u{16B8F}
+ \u{16E40}-\u{16E9A}
+ \u{16F00}-\u{16F4A}
+ \u{16F4F}-\u{16F87}
+ \u{16F8F}-\u{16F9F}
+ \u{1BC00}-\u{1BC6A}
+ \u{1BC70}-\u{1BC7C}
+ \u{1BC80}-\u{1BC88}
+ \u{1BC90}-\u{1BC99}
+ \u{1BC9C}-\u{1BCA3}
+ \u{1D000}-\u{1D0F5}
+ \u{1D100}-\u{1D126}
+ \u{1D129}-\u{1D1E8}
+ \u{1D200}-\u{1D245}
+ \u{1D2E0}-\u{1D2F3}
+ \u{1D300}-\u{1D356}
+ \u{1D360}-\u{1D378}
+ \u{1D400}-\u{1D454}
+ \u{1D456}-\u{1D49C}
+ \u{1D49E}-\u{1D49F}
+ \u{1D4A2}
+ \u{1D4A5}-\u{1D4A6}
+ \u{1D4A9}-\u{1D4AC}
+ \u{1D4AE}-\u{1D4B9}
+ \u{1D4BB}
+ \u{1D4BD}-\u{1D4C3}
+ \u{1D4C5}-\u{1D505}
+ \u{1D507}-\u{1D50A}
+ \u{1D50D}-\u{1D514}
+ \u{1D516}-\u{1D51C}
+ \u{1D51E}-\u{1D539}
+ \u{1D53B}-\u{1D53E}
+ \u{1D540}-\u{1D544}
+ \u{1D546}
+ \u{1D54A}-\u{1D550}
+ \u{1D552}-\u{1D6A5}
+ \u{1D6A8}-\u{1D7CB}
+ \u{1D7CE}-\u{1DA8B}
+ \u{1DA9B}-\u{1DA9F}
+ \u{1DAA1}-\u{1DAAF}
+ \u{1E000}-\u{1E006}
+ \u{1E008}-\u{1E018}
+ \u{1E01B}-\u{1E021}
+ \u{1E023}-\u{1E024}
+ \u{1E026}-\u{1E02A}
+ \u{1E100}-\u{1E12C}
+ \u{1E130}-\u{1E13D}
+ \u{1E140}-\u{1E149}
+ \u{1E14E}-\u{1E14F}
+ \u{1E2C0}-\u{1E2F9}
+ \u{1E2FF}
+ \u{1E800}-\u{1E8C4}
+ \u{1E8C7}-\u{1E8D6}
+ \u{1E900}-\u{1E94B}
+ \u{1E950}-\u{1E959}
+ \u{1E95E}-\u{1E95F}
+ \u{1EC71}-\u{1ECB4}
+ \u{1ED01}-\u{1ED3D}
+ \u{1EE00}-\u{1EE03}
+ \u{1EE05}-\u{1EE1F}
+ \u{1EE21}-\u{1EE22}
+ \u{1EE24}
+ \u{1EE27}
+ \u{1EE29}-\u{1EE32}
+ \u{1EE34}-\u{1EE37}
+ \u{1EE39}
+ \u{1EE3B}
+ \u{1EE42}
+ \u{1EE47}
+ \u{1EE49}
+ \u{1EE4B}
+ \u{1EE4D}-\u{1EE4F}
+ \u{1EE51}-\u{1EE52}
+ \u{1EE54}
+ \u{1EE57}
+ \u{1EE59}
+ \u{1EE5B}
+ \u{1EE5D}
+ \u{1EE5F}
+ \u{1EE61}-\u{1EE62}
+ \u{1EE64}
+ \u{1EE67}-\u{1EE6A}
+ \u{1EE6C}-\u{1EE72}
+ \u{1EE74}-\u{1EE77}
+ \u{1EE79}-\u{1EE7C}
+ \u{1EE7E}
+ \u{1EE80}-\u{1EE89}
+ \u{1EE8B}-\u{1EE9B}
+ \u{1EEA1}-\u{1EEA3}
+ \u{1EEA5}-\u{1EEA9}
+ \u{1EEAB}-\u{1EEBB}
+ \u{1EEF0}-\u{1EEF1}
+ \u{1F000}-\u{1F003}
+ \u{1F005}-\u{1F02B}
+ \u{1F030}-\u{1F093}
+ \u{1F0A0}-\u{1F0AE}
+ \u{1F0B1}-\u{1F0BF}
+ \u{1F0C1}-\u{1F0CE}
+ \u{1F0D1}-\u{1F0F5}
+ \u{1F10B}-\u{1F10F}
+ \u{1F12E}-\u{1F12F}
+ \u{1F16A}-\u{1F16F}
+ \u{1F1AD}
+ \u{1F1E6}-\u{1F1FF}
+ \u{1F321}-\u{1F32C}
+ \u{1F336}
+ \u{1F37D}
+ \u{1F394}-\u{1F39F}
+ \u{1F3CB}-\u{1F3CE}
+ \u{1F3D4}-\u{1F3DF}
+ \u{1F3F1}-\u{1F3F3}
+ \u{1F3F5}-\u{1F3F7}
+ \u{1F43F}
+ \u{1F441}
+ \u{1F4FD}-\u{1F4FE}
+ \u{1F53E}-\u{1F54A}
+ \u{1F54F}
+ \u{1F568}-\u{1F579}
+ \u{1F57B}-\u{1F594}
+ \u{1F597}-\u{1F5A3}
+ \u{1F5A5}-\u{1F5FA}
+ \u{1F650}-\u{1F67F}
+ \u{1F6C6}-\u{1F6CB}
+ \u{1F6CD}-\u{1F6CF}
+ \u{1F6D3}-\u{1F6D4}
+ \u{1F6E0}-\u{1F6EA}
+ \u{1F6F0}-\u{1F6F3}
+ \u{1F700}-\u{1F773}
+ \u{1F780}-\u{1F7D8}
+ \u{1F800}-\u{1F80B}
+ \u{1F810}-\u{1F847}
+ \u{1F850}-\u{1F859}
+ \u{1F860}-\u{1F887}
+ \u{1F890}-\u{1F8AD}
+ \u{1F8B0}-\u{1F8B1}
+ \u{1F900}-\u{1F90B}
+ \u{1F93B}
+ \u{1F946}
+ \u{1FA00}-\u{1FA53}
+ \u{1FA60}-\u{1FA6D}
+ \u{1FB00}-\u{1FB92}
+ \u{1FB94}-\u{1FBCA}
+ \u{1FBF0}-\u{1FBF9}
+ \u{E0001}
+ \u{E0020}-\u{E007F}
+ ).join }]/
end
diff --git a/lib/reline/version.rb b/lib/reline/version.rb
index b75d874adb..67a3d694bd 100644
--- a/lib/reline/version.rb
+++ b/lib/reline/version.rb
@@ -1,3 +1,3 @@
module Reline
- VERSION = '0.5.10'
+ VERSION = '0.3.2'
end
diff --git a/lib/reline/windows.rb b/lib/reline/windows.rb
new file mode 100644
index 0000000000..b952329911
--- /dev/null
+++ b/lib/reline/windows.rb
@@ -0,0 +1,497 @@
+require 'fiddle/import'
+
+class Reline::Windows
+ def self.encoding
+ Encoding::UTF_8
+ end
+
+ def self.win?
+ true
+ end
+
+ def self.win_legacy_console?
+ @@legacy_console
+ end
+
+ def self.set_default_key_bindings(config)
+ {
+ [224, 72] => :ed_prev_history, # ↑
+ [224, 80] => :ed_next_history, # ↓
+ [224, 77] => :ed_next_char, # →
+ [224, 75] => :ed_prev_char, # â†
+ [224, 83] => :key_delete, # Del
+ [224, 71] => :ed_move_to_beg, # Home
+ [224, 79] => :ed_move_to_end, # End
+ [ 0, 41] => :ed_unassigned, # input method on/off
+ [ 0, 72] => :ed_prev_history, # ↑
+ [ 0, 80] => :ed_next_history, # ↓
+ [ 0, 77] => :ed_next_char, # →
+ [ 0, 75] => :ed_prev_char, # â†
+ [ 0, 83] => :key_delete, # Del
+ [ 0, 71] => :ed_move_to_beg, # Home
+ [ 0, 79] => :ed_move_to_end # End
+ }.each_pair do |key, func|
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
+ config.add_default_key_binding_by_keymap(:vi_command, key, func)
+ end
+
+ {
+ [27, 32] => :em_set_mark, # M-<space>
+ [24, 24] => :em_exchange_mark, # C-x C-x
+ }.each_pair do |key, func|
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
+ end
+
+ # Emulate ANSI key sequence.
+ {
+ [27, 91, 90] => :completion_journey_up, # S-Tab
+ }.each_pair do |key, func|
+ config.add_default_key_binding_by_keymap(:emacs, key, func)
+ config.add_default_key_binding_by_keymap(:vi_insert, key, func)
+ end
+ end
+
+ if defined? JRUBY_VERSION
+ require 'win32api'
+ else
+ class Win32API
+ DLL = {}
+ TYPEMAP = {"0" => Fiddle::TYPE_VOID, "S" => Fiddle::TYPE_VOIDP, "I" => Fiddle::TYPE_LONG}
+ POINTER_TYPE = Fiddle::SIZEOF_VOIDP == Fiddle::SIZEOF_LONG_LONG ? 'q*' : 'l!*'
+
+ WIN32_TYPES = "VPpNnLlIi"
+ DL_TYPES = "0SSI"
+
+ def initialize(dllname, func, import, export = "0", calltype = :stdcall)
+ @proto = [import].join.tr(WIN32_TYPES, DL_TYPES).sub(/^(.)0*$/, '\1')
+ import = @proto.chars.map {|win_type| TYPEMAP[win_type.tr(WIN32_TYPES, DL_TYPES)]}
+ export = TYPEMAP[export.tr(WIN32_TYPES, DL_TYPES)]
+ calltype = Fiddle::Importer.const_get(:CALL_TYPE_TO_ABI)[calltype]
+
+ handle = DLL[dllname] ||=
+ begin
+ Fiddle.dlopen(dllname)
+ rescue Fiddle::DLError
+ raise unless File.extname(dllname).empty?
+ Fiddle.dlopen(dllname + ".dll")
+ end
+
+ @func = Fiddle::Function.new(handle[func], import, export, calltype)
+ rescue Fiddle::DLError => e
+ raise LoadError, e.message, e.backtrace
+ end
+
+ def call(*args)
+ import = @proto.split("")
+ args.each_with_index do |x, i|
+ args[i], = [x == 0 ? nil : x].pack("p").unpack(POINTER_TYPE) if import[i] == "S"
+ args[i], = [x].pack("I").unpack("i") if import[i] == "I"
+ end
+ ret, = @func.call(*args)
+ return ret || 0
+ end
+ end
+ end
+
+ VK_RETURN = 0x0D
+ VK_MENU = 0x12 # ALT key
+ VK_LMENU = 0xA4
+ VK_CONTROL = 0x11
+ VK_SHIFT = 0x10
+ VK_DIVIDE = 0x6F
+
+ KEY_EVENT = 0x01
+ WINDOW_BUFFER_SIZE_EVENT = 0x04
+
+ CAPSLOCK_ON = 0x0080
+ ENHANCED_KEY = 0x0100
+ LEFT_ALT_PRESSED = 0x0002
+ LEFT_CTRL_PRESSED = 0x0008
+ NUMLOCK_ON = 0x0020
+ RIGHT_ALT_PRESSED = 0x0001
+ RIGHT_CTRL_PRESSED = 0x0004
+ SCROLLLOCK_ON = 0x0040
+ SHIFT_PRESSED = 0x0010
+
+ VK_TAB = 0x09
+ VK_END = 0x23
+ VK_HOME = 0x24
+ VK_LEFT = 0x25
+ VK_UP = 0x26
+ VK_RIGHT = 0x27
+ VK_DOWN = 0x28
+ VK_DELETE = 0x2E
+
+ STD_INPUT_HANDLE = -10
+ STD_OUTPUT_HANDLE = -11
+ FILE_TYPE_PIPE = 0x0003
+ FILE_NAME_INFO = 2
+ @@getwch = Win32API.new('msvcrt', '_getwch', [], 'I')
+ @@kbhit = Win32API.new('msvcrt', '_kbhit', [], 'I')
+ @@GetKeyState = Win32API.new('user32', 'GetKeyState', ['L'], 'L')
+ @@GetConsoleScreenBufferInfo = Win32API.new('kernel32', 'GetConsoleScreenBufferInfo', ['L', 'P'], 'L')
+ @@SetConsoleCursorPosition = Win32API.new('kernel32', 'SetConsoleCursorPosition', ['L', 'L'], 'L')
+ @@GetStdHandle = Win32API.new('kernel32', 'GetStdHandle', ['L'], 'L')
+ @@FillConsoleOutputCharacter = Win32API.new('kernel32', 'FillConsoleOutputCharacter', ['L', 'L', 'L', 'L', 'P'], 'L')
+ @@ScrollConsoleScreenBuffer = Win32API.new('kernel32', 'ScrollConsoleScreenBuffer', ['L', 'P', 'P', 'L', 'P'], 'L')
+ @@hConsoleHandle = @@GetStdHandle.call(STD_OUTPUT_HANDLE)
+ @@hConsoleInputHandle = @@GetStdHandle.call(STD_INPUT_HANDLE)
+ @@GetNumberOfConsoleInputEvents = Win32API.new('kernel32', 'GetNumberOfConsoleInputEvents', ['L', 'P'], 'L')
+ @@ReadConsoleInputW = Win32API.new('kernel32', 'ReadConsoleInputW', ['L', 'P', 'L', 'P'], 'L')
+ @@GetFileType = Win32API.new('kernel32', 'GetFileType', ['L'], 'L')
+ @@GetFileInformationByHandleEx = Win32API.new('kernel32', 'GetFileInformationByHandleEx', ['L', 'I', 'P', 'L'], 'I')
+ @@FillConsoleOutputAttribute = Win32API.new('kernel32', 'FillConsoleOutputAttribute', ['L', 'L', 'L', 'L', 'P'], 'L')
+ @@SetConsoleCursorInfo = Win32API.new('kernel32', 'SetConsoleCursorInfo', ['L', 'P'], 'L')
+
+ @@GetConsoleMode = Win32API.new('kernel32', 'GetConsoleMode', ['L', 'P'], 'L')
+ @@SetConsoleMode = Win32API.new('kernel32', 'SetConsoleMode', ['L', 'L'], 'L')
+ @@WaitForSingleObject = Win32API.new('kernel32', 'WaitForSingleObject', ['L', 'L'], 'L')
+ ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4
+
+ private_class_method def self.getconsolemode
+ mode = "\000\000\000\000"
+ @@GetConsoleMode.call(@@hConsoleHandle, mode)
+ mode.unpack1('L')
+ end
+
+ private_class_method def self.setconsolemode(mode)
+ @@SetConsoleMode.call(@@hConsoleHandle, mode)
+ end
+
+ @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
+ #if @@legacy_console
+ # setconsolemode(getconsolemode() | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+ # @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
+ #end
+
+ @@input_buf = []
+ @@output_buf = []
+
+ @@output = STDOUT
+
+ def self.msys_tty?(io = @@hConsoleInputHandle)
+ # check if fd is a pipe
+ if @@GetFileType.call(io) != FILE_TYPE_PIPE
+ return false
+ end
+
+ bufsize = 1024
+ p_buffer = "\0" * bufsize
+ res = @@GetFileInformationByHandleEx.call(io, FILE_NAME_INFO, p_buffer, bufsize - 2)
+ return false if res == 0
+
+ # get pipe name: p_buffer layout is:
+ # struct _FILE_NAME_INFO {
+ # DWORD FileNameLength;
+ # WCHAR FileName[1];
+ # } FILE_NAME_INFO
+ len = p_buffer[0, 4].unpack1("L")
+ name = p_buffer[4, len].encode(Encoding::UTF_8, Encoding::UTF_16LE, invalid: :replace)
+
+ # Check if this could be a MSYS2 pty pipe ('\msys-XXXX-ptyN-XX')
+ # or a cygwin pty pipe ('\cygwin-XXXX-ptyN-XX')
+ name =~ /(msys-|cygwin-).*-pty/ ? true : false
+ end
+
+ KEY_MAP = [
+ # It's treated as Meta+Enter on Windows.
+ [ { control_keys: :CTRL, virtual_key_code: 0x0D }, "\e\r".bytes ],
+ [ { control_keys: :SHIFT, virtual_key_code: 0x0D }, "\e\r".bytes ],
+
+ # It's treated as Meta+Space on Windows.
+ [ { control_keys: :CTRL, char_code: 0x20 }, "\e ".bytes ],
+
+ # Emulate getwch() key sequences.
+ [ { control_keys: [], virtual_key_code: VK_UP }, [0, 72] ],
+ [ { control_keys: [], virtual_key_code: VK_DOWN }, [0, 80] ],
+ [ { control_keys: [], virtual_key_code: VK_RIGHT }, [0, 77] ],
+ [ { control_keys: [], virtual_key_code: VK_LEFT }, [0, 75] ],
+ [ { control_keys: [], virtual_key_code: VK_DELETE }, [0, 83] ],
+ [ { control_keys: [], virtual_key_code: VK_HOME }, [0, 71] ],
+ [ { control_keys: [], virtual_key_code: VK_END }, [0, 79] ],
+
+ # Emulate ANSI key sequence.
+ [ { control_keys: :SHIFT, virtual_key_code: VK_TAB }, [27, 91, 90] ],
+ ]
+
+ @@hsg = nil
+
+ def self.process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
+
+ # high-surrogate
+ if 0xD800 <= char_code and char_code <= 0xDBFF
+ @@hsg = char_code
+ return
+ end
+ # low-surrogate
+ if 0xDC00 <= char_code and char_code <= 0xDFFF
+ if @@hsg
+ char_code = 0x10000 + (@@hsg - 0xD800) * 0x400 + char_code - 0xDC00
+ @@hsg = nil
+ else
+ # no high-surrogate. ignored.
+ return
+ end
+ else
+ # ignore high-surrogate without low-surrogate if there
+ @@hsg = nil
+ end
+
+ key = KeyEventRecord.new(virtual_key_code, char_code, control_key_state)
+
+ match = KEY_MAP.find { |args,| key.matches?(**args) }
+ unless match.nil?
+ @@output_buf.concat(match.last)
+ return
+ end
+
+ # no char, only control keys
+ return if key.char_code == 0 and key.control_keys.any?
+
+ @@output_buf.push("\e".ord) if key.control_keys.include?(:ALT) and !key.control_keys.include?(:CTRL)
+
+ @@output_buf.concat(key.char.bytes)
+ end
+
+ def self.check_input_event
+ num_of_events = 0.chr * 8
+ while @@output_buf.empty?
+ Reline.core.line_editor.resize
+ if @@WaitForSingleObject.(@@hConsoleInputHandle, 100) != 0 # max 0.1 sec
+ # prevent for background consolemode change
+ @@legacy_console = (getconsolemode() & ENABLE_VIRTUAL_TERMINAL_PROCESSING == 0)
+ next
+ end
+ next if @@GetNumberOfConsoleInputEvents.(@@hConsoleInputHandle, num_of_events) == 0 or num_of_events.unpack1('L') == 0
+ input_records = 0.chr * 20 * 80
+ read_event = 0.chr * 4
+ if @@ReadConsoleInputW.(@@hConsoleInputHandle, input_records, 80, read_event) != 0
+ read_events = read_event.unpack1('L')
+ 0.upto(read_events) do |idx|
+ input_record = input_records[idx * 20, 20]
+ event = input_record[0, 2].unpack1('s*')
+ case event
+ when WINDOW_BUFFER_SIZE_EVENT
+ @@winch_handler.()
+ when KEY_EVENT
+ key_down = input_record[4, 4].unpack1('l*')
+ repeat_count = input_record[8, 2].unpack1('s*')
+ virtual_key_code = input_record[10, 2].unpack1('s*')
+ virtual_scan_code = input_record[12, 2].unpack1('s*')
+ char_code = input_record[14, 2].unpack1('S*')
+ control_key_state = input_record[16, 2].unpack1('S*')
+ is_key_down = key_down.zero? ? false : true
+ if is_key_down
+ process_key_event(repeat_count, virtual_key_code, virtual_scan_code, char_code, control_key_state)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ def self.getc
+ check_input_event
+ @@output_buf.shift
+ end
+
+ def self.ungetc(c)
+ @@output_buf.unshift(c)
+ end
+
+ def self.in_pasting?
+ not self.empty_buffer?
+ end
+
+ def self.empty_buffer?
+ if not @@output_buf.empty?
+ false
+ elsif @@kbhit.call == 0
+ true
+ else
+ false
+ end
+ end
+
+ def self.get_console_screen_buffer_info
+ # CONSOLE_SCREEN_BUFFER_INFO
+ # [ 0,2] dwSize.X
+ # [ 2,2] dwSize.Y
+ # [ 4,2] dwCursorPositions.X
+ # [ 6,2] dwCursorPositions.Y
+ # [ 8,2] wAttributes
+ # [10,2] srWindow.Left
+ # [12,2] srWindow.Top
+ # [14,2] srWindow.Right
+ # [16,2] srWindow.Bottom
+ # [18,2] dwMaximumWindowSize.X
+ # [20,2] dwMaximumWindowSize.Y
+ csbi = 0.chr * 22
+ return if @@GetConsoleScreenBufferInfo.call(@@hConsoleHandle, csbi) == 0
+ csbi
+ end
+
+ def self.get_screen_size
+ unless csbi = get_console_screen_buffer_info
+ return [1, 1]
+ end
+ csbi[0, 4].unpack('SS').reverse
+ end
+
+ def self.cursor_pos
+ unless csbi = get_console_screen_buffer_info
+ return Reline::CursorPos.new(0, 0)
+ end
+ x = csbi[4, 2].unpack1('s')
+ y = csbi[6, 2].unpack1('s')
+ Reline::CursorPos.new(x, y)
+ end
+
+ def self.move_cursor_column(val)
+ @@SetConsoleCursorPosition.call(@@hConsoleHandle, cursor_pos.y * 65536 + val)
+ end
+
+ def self.move_cursor_up(val)
+ if val > 0
+ y = cursor_pos.y - val
+ y = 0 if y < 0
+ @@SetConsoleCursorPosition.call(@@hConsoleHandle, y * 65536 + cursor_pos.x)
+ elsif val < 0
+ move_cursor_down(-val)
+ end
+ end
+
+ def self.move_cursor_down(val)
+ if val > 0
+ return unless csbi = get_console_screen_buffer_info
+ screen_height = get_screen_size.first
+ y = cursor_pos.y + val
+ y = screen_height - 1 if y > (screen_height - 1)
+ @@SetConsoleCursorPosition.call(@@hConsoleHandle, (cursor_pos.y + val) * 65536 + cursor_pos.x)
+ elsif val < 0
+ move_cursor_up(-val)
+ end
+ end
+
+ def self.erase_after_cursor
+ return unless csbi = get_console_screen_buffer_info
+ attributes = csbi[8, 2].unpack1('S')
+ cursor = csbi[4, 4].unpack1('L')
+ written = 0.chr * 4
+ @@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, get_screen_size.last - cursor_pos.x, cursor, written)
+ @@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, get_screen_size.last - cursor_pos.x, cursor, written)
+ end
+
+ def self.scroll_down(val)
+ return if val < 0
+ return unless csbi = get_console_screen_buffer_info
+ buffer_width, buffer_lines, x, y, attributes, window_left, window_top, window_bottom = csbi.unpack('ssssSssx2s')
+ screen_height = window_bottom - window_top + 1
+ val = screen_height if val > screen_height
+
+ if @@legacy_console || window_left != 0
+ # unless ENABLE_VIRTUAL_TERMINAL,
+ # if srWindow.Left != 0 then it's conhost.exe hosted console
+ # and puts "\n" causes horizontal scroll. its glitch.
+ # FYI irb write from culumn 1, so this gives no gain.
+ scroll_rectangle = [0, val, buffer_width, buffer_lines - val].pack('s4')
+ destination_origin = 0 # y * 65536 + x
+ fill = [' '.ord, attributes].pack('SS')
+ @@ScrollConsoleScreenBuffer.call(@@hConsoleHandle, scroll_rectangle, nil, destination_origin, fill)
+ else
+ origin_x = x + 1
+ origin_y = y - window_top + 1
+ @@output.write [
+ (origin_y != screen_height) ? "\e[#{screen_height};H" : nil,
+ "\n" * val,
+ (origin_y != screen_height or !x.zero?) ? "\e[#{origin_y};#{origin_x}H" : nil
+ ].join
+ end
+ end
+
+ def self.clear_screen
+ if @@legacy_console
+ return unless csbi = get_console_screen_buffer_info
+ buffer_width, _buffer_lines, attributes, window_top, window_bottom = csbi.unpack('ss@8S@12sx2s')
+ fill_length = buffer_width * (window_bottom - window_top + 1)
+ screen_topleft = window_top * 65536
+ written = 0.chr * 4
+ @@FillConsoleOutputCharacter.call(@@hConsoleHandle, 0x20, fill_length, screen_topleft, written)
+ @@FillConsoleOutputAttribute.call(@@hConsoleHandle, attributes, fill_length, screen_topleft, written)
+ @@SetConsoleCursorPosition.call(@@hConsoleHandle, screen_topleft)
+ else
+ @@output.write "\e[2J" "\e[H"
+ end
+ end
+
+ def self.set_screen_size(rows, columns)
+ raise NotImplementedError
+ end
+
+ def self.hide_cursor
+ size = 100
+ visible = 0 # 0 means false
+ cursor_info = [size, visible].pack('Li')
+ @@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
+ end
+
+ def self.show_cursor
+ size = 100
+ visible = 1 # 1 means true
+ cursor_info = [size, visible].pack('Li')
+ @@SetConsoleCursorInfo.call(@@hConsoleHandle, cursor_info)
+ end
+
+ def self.set_winch_handler(&handler)
+ @@winch_handler = handler
+ end
+
+ def self.prep
+ # do nothing
+ nil
+ end
+
+ def self.deprep(otio)
+ # do nothing
+ end
+
+ class KeyEventRecord
+
+ attr_reader :virtual_key_code, :char_code, :control_key_state, :control_keys
+
+ def initialize(virtual_key_code, char_code, control_key_state)
+ @virtual_key_code = virtual_key_code
+ @char_code = char_code
+ @control_key_state = control_key_state
+ @enhanced = control_key_state & ENHANCED_KEY != 0
+
+ (@control_keys = []).tap do |control_keys|
+ # symbols must be sorted to make comparison is easier later on
+ control_keys << :ALT if control_key_state & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED) != 0
+ control_keys << :CTRL if control_key_state & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) != 0
+ control_keys << :SHIFT if control_key_state & SHIFT_PRESSED != 0
+ end.freeze
+ end
+
+ def char
+ @char_code.chr(Encoding::UTF_8)
+ end
+
+ def enhanced?
+ @enhanced
+ end
+
+ # Verifies if the arguments match with this key event.
+ # Nil arguments are ignored, but at least one must be passed as non-nil.
+ # To verify that no control keys were pressed, pass an empty array: `control_keys: []`.
+ def matches?(control_keys: nil, virtual_key_code: nil, char_code: nil)
+ raise ArgumentError, 'No argument was passed to match key event' if control_keys.nil? && virtual_key_code.nil? && char_code.nil?
+
+ (control_keys.nil? || [*control_keys].sort == @control_keys) &&
+ (virtual_key_code.nil? || @virtual_key_code == virtual_key_code) &&
+ (char_code.nil? || char_code == @char_code)
+ end
+
+ end
+end
diff --git a/lib/resolv-replace.gemspec b/lib/resolv-replace.gemspec
new file mode 100644
index 0000000000..48f7108a8e
--- /dev/null
+++ b/lib/resolv-replace.gemspec
@@ -0,0 +1,22 @@
+Gem::Specification.new do |spec|
+ spec.name = "resolv-replace"
+ spec.version = "0.1.1"
+ spec.authors = ["Tanaka Akira"]
+ spec.email = ["akr@fsij.org"]
+
+ spec.summary = %q{Replace Socket DNS with Resolv.}
+ spec.description = %q{Replace Socket DNS with Resolv.}
+ spec.homepage = "https://github.com/ruby/resolv-replace"
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.require_paths = ["lib"]
+
+ spec.add_dependency "resolv"
+end
diff --git a/lib/resolv-replace.rb b/lib/resolv-replace.rb
new file mode 100644
index 0000000000..a83e79d996
--- /dev/null
+++ b/lib/resolv-replace.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+require 'socket'
+require 'resolv'
+
+class << IPSocket
+ # :stopdoc:
+ alias original_resolv_getaddress getaddress
+ # :startdoc:
+ def getaddress(host)
+ begin
+ return Resolv.getaddress(host).to_s
+ rescue Resolv::ResolvError
+ raise SocketError, "Hostname not known: #{host}"
+ end
+ end
+end
+
+class TCPSocket < IPSocket
+ # :stopdoc:
+ alias original_resolv_initialize initialize
+ # :startdoc:
+ def initialize(host, serv, *rest)
+ rest[0] = IPSocket.getaddress(rest[0]) if rest[0]
+ original_resolv_initialize(IPSocket.getaddress(host), serv, *rest)
+ end
+end
+
+class UDPSocket < IPSocket
+ # :stopdoc:
+ alias original_resolv_bind bind
+ # :startdoc:
+ def bind(host, port)
+ host = IPSocket.getaddress(host) if host != ""
+ original_resolv_bind(host, port)
+ end
+
+ # :stopdoc:
+ alias original_resolv_connect connect
+ # :startdoc:
+ def connect(host, port)
+ original_resolv_connect(IPSocket.getaddress(host), port)
+ end
+
+ # :stopdoc:
+ alias original_resolv_send send
+ # :startdoc:
+ def send(mesg, flags, *rest)
+ if rest.length == 2
+ host, port = rest
+ begin
+ addrs = Resolv.getaddresses(host)
+ rescue Resolv::ResolvError
+ raise SocketError, "Hostname not known: #{host}"
+ end
+ addrs[0...-1].each {|addr|
+ begin
+ return original_resolv_send(mesg, flags, addr, port)
+ rescue SystemCallError
+ end
+ }
+ original_resolv_send(mesg, flags, addrs[-1], port)
+ else
+ original_resolv_send(mesg, flags, *rest)
+ end
+ end
+end
+
+class SOCKSSocket < TCPSocket
+ # :stopdoc:
+ alias original_resolv_initialize initialize
+ # :startdoc:
+ def initialize(host, serv)
+ original_resolv_initialize(IPSocket.getaddress(host), port)
+ end
+end if defined? SOCKSSocket
diff --git a/lib/resolv.gemspec b/lib/resolv.gemspec
index bfa2f9ff31..f221010ab6 100644
--- a/lib/resolv.gemspec
+++ b/lib/resolv.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "resolv"
+ spec.version = "0.2.3"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
@@ -16,7 +9,6 @@ Gem::Specification.new do |spec|
spec.homepage = "https://github.com/ruby/resolv"
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.extensions << "ext/win32/resolv/extconf.rb"
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
diff --git a/lib/resolv.rb b/lib/resolv.rb
index 47ea97deff..eaea69bfd5 100644
--- a/lib/resolv.rb
+++ b/lib/resolv.rb
@@ -37,8 +37,6 @@ end
class Resolv
- VERSION = "0.4.0"
-
##
# Looks up the first IP address for +name+.
@@ -84,8 +82,8 @@ class Resolv
##
# Creates a new Resolv using +resolvers+.
- def initialize(resolvers=nil, use_ipv6: nil)
- @resolvers = resolvers || [Hosts.new, DNS.new(DNS::Config.default_config_hash.merge(use_ipv6: use_ipv6))]
+ def initialize(resolvers=[Hosts.new, DNS.new])
+ @resolvers = resolvers
end
##
@@ -194,10 +192,17 @@ class Resolv
File.open(@filename, 'rb') {|f|
f.each {|line|
line.sub!(/#.*/, '')
- addr, *hostnames = line.split(/\s+/)
+ addr, hostname, *aliases = line.split(/\s+/)
next unless addr
- (@addr2name[addr] ||= []).concat(hostnames)
- hostnames.each {|hostname| (@name2addr[hostname] ||= []) << addr}
+ @addr2name[addr] = [] unless @addr2name.include? addr
+ @addr2name[addr] << hostname
+ @addr2name[addr] += aliases
+ @name2addr[hostname] = [] unless @name2addr.include? hostname
+ @name2addr[hostname] << addr
+ aliases.each {|n|
+ @name2addr[n] = [] unless @name2addr.include? n
+ @name2addr[n] << addr
+ }
}
}
@name2addr.each {|name, arr| arr.reverse!}
@@ -305,8 +310,6 @@ class Resolv
# String:: Path to a file using /etc/resolv.conf's format.
# Hash:: Must contain :nameserver, :search and :ndots keys.
# :nameserver_port can be used to specify port number of nameserver address.
- # :raise_timeout_errors can be used to raise timeout errors
- # as exceptions instead of treating the same as an NXDOMAIN response.
#
# The value of :nameserver should be an address string or
# an array of address strings.
@@ -396,18 +399,13 @@ class Resolv
# be a Resolv::IPv4 or Resolv::IPv6
def each_address(name)
+ each_resource(name, Resource::IN::A) {|resource| yield resource.address}
if use_ipv6?
each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address}
end
- each_resource(name, Resource::IN::A) {|resource| yield resource.address}
end
def use_ipv6? # :nodoc:
- use_ipv6 = @config.use_ipv6?
- unless use_ipv6.nil?
- return use_ipv6
- end
-
begin
list = Socket.ip_address_list
rescue NotImplementedError
@@ -513,40 +511,35 @@ class Resolv
def fetch_resource(name, typeclass)
lazy_initialize
- truncated = {}
- requesters = {}
- udp_requester = begin
- make_udp_requester
+ begin
+ requester = make_udp_requester
rescue Errno::EACCES
# fall back to TCP
end
senders = {}
-
begin
- @config.resolv(name) do |candidate, tout, nameserver, port|
+ @config.resolv(name) {|candidate, tout, nameserver, port|
+ requester ||= make_tcp_requester(nameserver, port)
msg = Message.new
msg.rd = 1
msg.add_question(candidate, typeclass)
-
- requester = requesters.fetch([nameserver, port]) do
- if !truncated[candidate] && udp_requester
- udp_requester
- else
- requesters[[nameserver, port]] = make_tcp_requester(nameserver, port)
- end
- end
-
- unless sender = senders[[candidate, requester, nameserver, port]]
+ unless sender = senders[[candidate, nameserver, port]]
sender = requester.sender(msg, candidate, nameserver, port)
next if !sender
- senders[[candidate, requester, nameserver, port]] = sender
+ senders[[candidate, nameserver, port]] = sender
end
reply, reply_name = requester.request(sender, tout)
case reply.rcode
when RCode::NoError
if reply.tc == 1 and not Requester::TCP === requester
+ requester.close
# Retry via TCP:
- truncated[candidate] = true
+ requester = make_tcp_requester(nameserver, port)
+ senders = {}
+ # This will use TCP for all remaining candidates (assuming the
+ # current candidate does not already respond successfully via
+ # TCP). This makes sense because we already know the full
+ # response will not fit in an untruncated UDP packet.
redo
else
yield(reply, reply_name)
@@ -557,10 +550,9 @@ class Resolv
else
raise Config::OtherResolvError.new(reply_name.to_s)
end
- end
+ }
ensure
- udp_requester&.close
- requesters.each_value { |requester| requester&.close }
+ requester&.close
end
end
@@ -575,11 +567,6 @@ class Resolv
def make_tcp_requester(host, port) # :nodoc:
return Requester::TCP.new(host, port)
- rescue Errno::ECONNREFUSED
- # Treat a refused TCP connection attempt to a nameserver like a timeout,
- # as Resolv::DNS::Config#resolv considers ResolvTimeout exceptions as a
- # hint to try the next nameserver:
- raise ResolvTimeout
end
def extract_resources(msg, name, typeclass) # :nodoc:
@@ -761,7 +748,7 @@ class Resolv
next if @socks_hash[bind_host]
begin
sock = UDPSocket.new(af)
- rescue Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT
+ rescue Errno::EAFNOSUPPORT
next # The kernel doesn't support the address family.
end
@socks << sock
@@ -978,7 +965,7 @@ class Resolv
next unless keyword
case keyword
when 'nameserver'
- nameserver.concat(args)
+ nameserver += args
when 'domain'
next if args.empty?
search = [args[0]]
@@ -1017,7 +1004,6 @@ class Resolv
@mutex.synchronize {
unless @initialized
@nameserver_port = []
- @use_ipv6 = nil
@search = nil
@ndots = 1
case @config_info
@@ -1042,12 +1028,8 @@ class Resolv
if config_hash.include? :nameserver_port
@nameserver_port = config_hash[:nameserver_port].map {|ns, port| [ns, (port || Port)] }
end
- if config_hash.include? :use_ipv6
- @use_ipv6 = config_hash[:use_ipv6]
- end
@search = config_hash[:search] if config_hash.include? :search
@ndots = config_hash[:ndots] if config_hash.include? :ndots
- @raise_timeout_errors = config_hash[:raise_timeout_errors]
if @nameserver_port.empty?
@nameserver_port << ['0.0.0.0', Port]
@@ -1101,10 +1083,6 @@ class Resolv
@nameserver_port
end
- def use_ipv6?
- @use_ipv6
- end
-
def generate_candidates(name)
candidates = nil
name = Name.create(name)
@@ -1138,7 +1116,6 @@ class Resolv
def resolv(name)
candidates = generate_candidates(name)
timeouts = @timeouts || generate_timeouts
- timeout_error = false
begin
candidates.each {|candidate|
begin
@@ -1150,13 +1127,11 @@ class Resolv
end
}
}
- timeout_error = true
raise ResolvError.new("DNS resolv timeout: #{name}")
rescue NXDomain
end
}
rescue ResolvError
- raise if @raise_timeout_errors && timeout_error
end
end
@@ -1512,14 +1487,14 @@ class Resolv
}
end
- def put_name(d, compress: true)
- put_labels(d.to_a, compress: compress)
+ def put_name(d)
+ put_labels(d.to_a)
end
- def put_labels(d, compress: true)
+ def put_labels(d)
d.each_index {|i|
domain = d[i..-1]
- if compress && idx = @names[domain]
+ if idx = @names[domain]
self.put_pack("n", 0xc000 | idx)
return
else
@@ -1543,15 +1518,13 @@ class Resolv
id, flag, qdcount, ancount, nscount, arcount =
msg.get_unpack('nnnnnn')
o.id = id
- o.tc = (flag >> 9) & 1
- o.rcode = flag & 15
- return o unless o.tc.zero?
-
o.qr = (flag >> 15) & 1
o.opcode = (flag >> 11) & 15
o.aa = (flag >> 10) & 1
+ o.tc = (flag >> 9) & 1
o.rd = (flag >> 8) & 1
o.ra = (flag >> 7) & 1
+ o.rcode = flag & 15
(1..qdcount).each {
name, typeclass = msg.get_question
o.add_question(name, typeclass)
@@ -1643,14 +1616,6 @@ class Resolv
strings
end
- def get_list
- [].tap do |values|
- while @index < @limit
- values << yield
- end
- end
- end
-
def get_name
return Name.new(self.get_labels)
end
@@ -1659,6 +1624,7 @@ class Resolv
prev_index = @index
save_index = nil
d = []
+ size = -1
while true
raise DecodeError.new("limit exceeded") if @limit <= @index
case @data.getbyte(@index)
@@ -1679,7 +1645,10 @@ class Resolv
end
@index = idx
else
- d << self.get_label
+ l = self.get_label
+ d << l
+ size += 1 + l.string.bytesize
+ raise DecodeError.new("name label data exceed 255 octets") if size > 255
end
end
end
@@ -1712,377 +1681,6 @@ class Resolv
end
##
- # SvcParams for service binding RRs. [RFC9460]
-
- class SvcParams
- include Enumerable
-
- ##
- # Create a list of SvcParams with the given initial content.
- #
- # +params+ has to be an enumerable of +SvcParam+s.
- # If its content has +SvcParam+s with the duplicate key,
- # the one appears last takes precedence.
-
- def initialize(params = [])
- @params = {}
-
- params.each do |param|
- add param
- end
- end
-
- ##
- # Get SvcParam for the given +key+ in this list.
-
- def [](key)
- @params[canonical_key(key)]
- end
-
- ##
- # Get the number of SvcParams in this list.
-
- def count
- @params.count
- end
-
- ##
- # Get whether this list is empty.
-
- def empty?
- @params.empty?
- end
-
- ##
- # Add the SvcParam +param+ to this list, overwriting the existing one with the same key.
-
- def add(param)
- @params[param.class.key_number] = param
- end
-
- ##
- # Remove the +SvcParam+ with the given +key+ and return it.
-
- def delete(key)
- @params.delete(canonical_key(key))
- end
-
- ##
- # Enumerate the +SvcParam+s in this list.
-
- def each(&block)
- return enum_for(:each) unless block
- @params.each_value(&block)
- end
-
- def encode(msg) # :nodoc:
- @params.keys.sort.each do |key|
- msg.put_pack('n', key)
- msg.put_length16 do
- @params.fetch(key).encode(msg)
- end
- end
- end
-
- def self.decode(msg) # :nodoc:
- params = msg.get_list do
- key, = msg.get_unpack('n')
- msg.get_length16 do
- SvcParam::ClassHash[key].decode(msg)
- end
- end
-
- return self.new(params)
- end
-
- private
-
- def canonical_key(key) # :nodoc:
- case key
- when Integer
- key
- when /\Akey(\d+)\z/
- Integer($1)
- when Symbol
- SvcParam::ClassHash[key].key_number
- else
- raise TypeError, 'key must be either String or Symbol'
- end
- end
- end
-
- ##
- # Base class for SvcParam. [RFC9460]
-
- class SvcParam
-
- ##
- # Get the presentation name of the SvcParamKey.
-
- def self.key_name
- const_get(:KeyName)
- end
-
- ##
- # Get the registered number of the SvcParamKey.
-
- def self.key_number
- const_get(:KeyNumber)
- end
-
- ClassHash = Hash.new do |h, key| # :nodoc:
- case key
- when Integer
- Generic.create(key)
- when /\Akey(?<key>\d+)\z/
- Generic.create(key.to_int)
- when Symbol
- raise KeyError, "unknown key #{key}"
- else
- raise TypeError, 'key must be either String or Symbol'
- end
- end
-
- ##
- # Generic SvcParam abstract class.
-
- class Generic < SvcParam
-
- ##
- # SvcParamValue in wire-format byte string.
-
- attr_reader :value
-
- ##
- # Create generic SvcParam
-
- def initialize(value)
- @value = value
- end
-
- def encode(msg) # :nodoc:
- msg.put_bytes(@value)
- end
-
- def self.decode(msg) # :nodoc:
- return self.new(msg.get_bytes)
- end
-
- def self.create(key_number)
- c = Class.new(Generic)
- key_name = :"key#{key_number}"
- c.const_set(:KeyName, key_name)
- c.const_set(:KeyNumber, key_number)
- self.const_set(:"Key#{key_number}", c)
- ClassHash[key_name] = ClassHash[key_number] = c
- return c
- end
- end
-
- ##
- # "mandatory" SvcParam -- Mandatory keys in service binding RR
-
- class Mandatory < SvcParam
- KeyName = :mandatory
- KeyNumber = 0
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Mandatory keys.
-
- attr_reader :keys
-
- ##
- # Initialize "mandatory" ScvParam.
-
- def initialize(keys)
- @keys = keys.map(&:to_int)
- end
-
- def encode(msg) # :nodoc:
- @keys.sort.each do |key|
- msg.put_pack('n', key)
- end
- end
-
- def self.decode(msg) # :nodoc:
- keys = msg.get_list { msg.get_unpack('n')[0] }
- return self.new(keys)
- end
- end
-
- ##
- # "alpn" SvcParam -- Additional supported protocols
-
- class ALPN < SvcParam
- KeyName = :alpn
- KeyNumber = 1
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Supported protocol IDs.
-
- attr_reader :protocol_ids
-
- ##
- # Initialize "alpn" ScvParam.
-
- def initialize(protocol_ids)
- @protocol_ids = protocol_ids.map(&:to_str)
- end
-
- def encode(msg) # :nodoc:
- msg.put_string_list(@protocol_ids)
- end
-
- def self.decode(msg) # :nodoc:
- return self.new(msg.get_string_list)
- end
- end
-
- ##
- # "no-default-alpn" SvcParam -- No support for default protocol
-
- class NoDefaultALPN < SvcParam
- KeyName = :'no-default-alpn'
- KeyNumber = 2
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- def encode(msg) # :nodoc:
- # no payload
- end
-
- def self.decode(msg) # :nodoc:
- return self.new
- end
- end
-
- ##
- # "port" SvcParam -- Port for alternative endpoint
-
- class Port < SvcParam
- KeyName = :port
- KeyNumber = 3
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Port number.
-
- attr_reader :port
-
- ##
- # Initialize "port" ScvParam.
-
- def initialize(port)
- @port = port.to_int
- end
-
- def encode(msg) # :nodoc:
- msg.put_pack('n', @port)
- end
-
- def self.decode(msg) # :nodoc:
- port, = msg.get_unpack('n')
- return self.new(port)
- end
- end
-
- ##
- # "ipv4hint" SvcParam -- IPv4 address hints
-
- class IPv4Hint < SvcParam
- KeyName = :ipv4hint
- KeyNumber = 4
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Set of IPv4 addresses.
-
- attr_reader :addresses
-
- ##
- # Initialize "ipv4hint" ScvParam.
-
- def initialize(addresses)
- @addresses = addresses.map {|address| IPv4.create(address) }
- end
-
- def encode(msg) # :nodoc:
- @addresses.each do |address|
- msg.put_bytes(address.address)
- end
- end
-
- def self.decode(msg) # :nodoc:
- addresses = msg.get_list { IPv4.new(msg.get_bytes(4)) }
- return self.new(addresses)
- end
- end
-
- ##
- # "ipv6hint" SvcParam -- IPv6 address hints
-
- class IPv6Hint < SvcParam
- KeyName = :ipv6hint
- KeyNumber = 6
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Set of IPv6 addresses.
-
- attr_reader :addresses
-
- ##
- # Initialize "ipv6hint" ScvParam.
-
- def initialize(addresses)
- @addresses = addresses.map {|address| IPv6.create(address) }
- end
-
- def encode(msg) # :nodoc:
- @addresses.each do |address|
- msg.put_bytes(address.address)
- end
- end
-
- def self.decode(msg) # :nodoc:
- addresses = msg.get_list { IPv6.new(msg.get_bytes(16)) }
- return self.new(addresses)
- end
- end
-
- ##
- # "dohpath" SvcParam -- DNS over HTTPS path template [RFC9461]
-
- class DoHPath < SvcParam
- KeyName = :dohpath
- KeyNumber = 7
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # URI template for DoH queries.
-
- attr_reader :template
-
- ##
- # Initialize "dohpath" ScvParam.
-
- def initialize(template)
- @template = template.encode('utf-8')
- end
-
- def encode(msg) # :nodoc:
- msg.put_bytes(@template)
- end
-
- def self.decode(msg) # :nodoc:
- template = msg.get_bytes.force_encoding('utf-8')
- return self.new(template)
- end
- end
- end
-
- ##
# A DNS query abstract class.
class Query
@@ -2509,6 +2107,7 @@ class Resolv
attr_reader :altitude
+
def encode_rdata(msg) # :nodoc:
msg.put_bytes(@version)
msg.put_bytes(@ssize.scalar)
@@ -2546,70 +2145,8 @@ class Resolv
TypeValue = 255 # :nodoc:
end
- ##
- # CAA resource record defined in RFC 8659
- #
- # These records identify certificate authority allowed to issue
- # certificates for the given domain.
-
- class CAA < Resource
- TypeValue = 257
-
- ##
- # Creates a new CAA for +flags+, +tag+ and +value+.
-
- def initialize(flags, tag, value)
- unless (0..255) === flags
- raise ArgumentError.new('flags must be an Integer between 0 and 255')
- end
- unless (1..15) === tag.bytesize
- raise ArgumentError.new('length of tag must be between 1 and 15')
- end
-
- @flags = flags
- @tag = tag
- @value = value
- end
-
- ##
- # Flags for this proprty:
- # - Bit 0 : 0 = not critical, 1 = critical
-
- attr_reader :flags
-
- ##
- # Property tag ("issue", "issuewild", "iodef"...).
-
- attr_reader :tag
-
- ##
- # Property value.
-
- attr_reader :value
-
- ##
- # Whether the critical flag is set on this property.
-
- def critical?
- flags & 0x80 != 0
- end
-
- def encode_rdata(msg) # :nodoc:
- msg.put_pack('C', @flags)
- msg.put_string(@tag)
- msg.put_bytes(@value)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- flags, = msg.get_unpack('C')
- tag = msg.get_string
- value = msg.get_bytes
- self.new flags, tag, value
- end
- end
-
ClassInsensitiveTypes = [ # :nodoc:
- NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, LOC, ANY, CAA
+ NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, LOC, ANY
]
##
@@ -2795,7 +2332,7 @@ class Resolv
msg.put_pack("n", @priority)
msg.put_pack("n", @weight)
msg.put_pack("n", @port)
- msg.put_name(@target, compress: false)
+ msg.put_name(@target)
end
def self.decode_rdata(msg) # :nodoc:
@@ -2806,84 +2343,6 @@ class Resolv
return self.new(priority, weight, port, target)
end
end
-
- ##
- # Common implementation for SVCB-compatible resource records.
-
- class ServiceBinding
-
- ##
- # Create a service binding resource record.
-
- def initialize(priority, target, params = [])
- @priority = priority.to_int
- @target = Name.create(target)
- @params = SvcParams.new(params)
- end
-
- ##
- # The priority of this target host.
- #
- # The range is 0-65535.
- # If set to 0, this RR is in AliasMode. Otherwise, it is in ServiceMode.
-
- attr_reader :priority
-
- ##
- # The domain name of the target host.
-
- attr_reader :target
-
- ##
- # The service parameters for the target host.
-
- attr_reader :params
-
- ##
- # Whether this RR is in AliasMode.
-
- def alias_mode?
- self.priority == 0
- end
-
- ##
- # Whether this RR is in ServiceMode.
-
- def service_mode?
- !alias_mode?
- end
-
- def encode_rdata(msg) # :nodoc:
- msg.put_pack("n", @priority)
- msg.put_name(@target, compress: false)
- @params.encode(msg)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- priority, = msg.get_unpack("n")
- target = msg.get_name
- params = SvcParams.decode(msg)
- return self.new(priority, target, params)
- end
- end
-
- ##
- # SVCB resource record [RFC9460]
-
- class SVCB < ServiceBinding
- TypeValue = 64
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
- end
-
- ##
- # HTTPS resource record [RFC9460]
-
- class HTTPS < ServiceBinding
- TypeValue = 65
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
- end
end
end
end
@@ -3103,7 +2562,11 @@ class Resolv
attr_reader :address
def to_s # :nodoc:
- sprintf("%x:%x:%x:%x:%x:%x:%x:%x", *@address.unpack("nnnnnnnn")).sub(/(^|:)0(:0)+(:|$)/, '::')
+ address = sprintf("%x:%x:%x:%x:%x:%x:%x:%x", *@address.unpack("nnnnnnnn"))
+ unless address.sub!(/(^|:)0(:0)+(:|$)/, '::')
+ address.sub!(/(^|:)0(:|$)/, '::')
+ end
+ return address
end
def inspect # :nodoc:
@@ -3448,3 +2911,4 @@ class Resolv
AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/
end
+
diff --git a/lib/rinda/rinda.gemspec b/lib/rinda/rinda.gemspec
new file mode 100644
index 0000000000..0c13e3c2df
--- /dev/null
+++ b/lib/rinda/rinda.gemspec
@@ -0,0 +1,28 @@
+Gem::Specification.new do |spec|
+ spec.name = "rinda"
+ spec.version = "0.1.1"
+ spec.authors = ["Masatoshi SEKI"]
+ spec.email = ["seki@ruby-lang.org"]
+
+ spec.summary = %q{The Linda distributed computing paradigm in Ruby.}
+ spec.description = %q{The Linda distributed computing paradigm in Ruby.}
+ spec.homepage = "https://github.com/ruby/rinda"
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+
+ spec.add_dependency "drb"
+ spec.add_dependency "ipaddr"
+ spec.add_dependency "forwardable"
+end
diff --git a/lib/rinda/rinda.rb b/lib/rinda/rinda.rb
new file mode 100644
index 0000000000..e762286d3b
--- /dev/null
+++ b/lib/rinda/rinda.rb
@@ -0,0 +1,327 @@
+# frozen_string_literal: false
+require 'drb/drb'
+
+##
+# A module to implement the Linda distributed computing paradigm in Ruby.
+#
+# Rinda is part of DRb (dRuby).
+#
+# == Example(s)
+#
+# See the sample/drb/ directory in the Ruby distribution, from 1.8.2 onwards.
+#
+#--
+# TODO
+# == Introduction to Linda/rinda?
+#
+# == Why is this library separate from DRb?
+
+module Rinda
+
+ ##
+ # Rinda error base class
+
+ class RindaError < RuntimeError; end
+
+ ##
+ # Raised when a hash-based tuple has an invalid key.
+
+ class InvalidHashTupleKey < RindaError; end
+
+ ##
+ # Raised when trying to use a canceled tuple.
+
+ class RequestCanceledError < ThreadError; end
+
+ ##
+ # Raised when trying to use an expired tuple.
+
+ class RequestExpiredError < ThreadError; end
+
+ ##
+ # A tuple is the elementary object in Rinda programming.
+ # Tuples may be matched against templates if the tuple and
+ # the template are the same size.
+
+ class Tuple
+
+ ##
+ # Creates a new Tuple from +ary_or_hash+ which must be an Array or Hash.
+
+ def initialize(ary_or_hash)
+ if hash?(ary_or_hash)
+ init_with_hash(ary_or_hash)
+ else
+ init_with_ary(ary_or_hash)
+ end
+ end
+
+ ##
+ # The number of elements in the tuple.
+
+ def size
+ @tuple.size
+ end
+
+ ##
+ # Accessor method for elements of the tuple.
+
+ def [](k)
+ @tuple[k]
+ end
+
+ ##
+ # Fetches item +k+ from the tuple.
+
+ def fetch(k)
+ @tuple.fetch(k)
+ end
+
+ ##
+ # Iterate through the tuple, yielding the index or key, and the
+ # value, thus ensuring arrays are iterated similarly to hashes.
+
+ def each # FIXME
+ if Hash === @tuple
+ @tuple.each { |k, v| yield(k, v) }
+ else
+ @tuple.each_with_index { |v, k| yield(k, v) }
+ end
+ end
+
+ ##
+ # Return the tuple itself
+ def value
+ @tuple
+ end
+
+ private
+
+ def hash?(ary_or_hash)
+ ary_or_hash.respond_to?(:keys)
+ end
+
+ ##
+ # Munges +ary+ into a valid Tuple.
+
+ def init_with_ary(ary)
+ @tuple = Array.new(ary.size)
+ @tuple.size.times do |i|
+ @tuple[i] = ary[i]
+ end
+ end
+
+ ##
+ # Ensures +hash+ is a valid Tuple.
+
+ def init_with_hash(hash)
+ @tuple = Hash.new
+ hash.each do |k, v|
+ raise InvalidHashTupleKey unless String === k
+ @tuple[k] = v
+ end
+ end
+
+ end
+
+ ##
+ # Templates are used to match tuples in Rinda.
+
+ class Template < Tuple
+
+ ##
+ # Matches this template against +tuple+. The +tuple+ must be the same
+ # size as the template. An element with a +nil+ value in a template acts
+ # as a wildcard, matching any value in the corresponding position in the
+ # tuple. Elements of the template match the +tuple+ if the are #== or
+ # #===.
+ #
+ # Template.new([:foo, 5]).match Tuple.new([:foo, 5]) # => true
+ # Template.new([:foo, nil]).match Tuple.new([:foo, 5]) # => true
+ # Template.new([String]).match Tuple.new(['hello']) # => true
+ #
+ # Template.new([:foo]).match Tuple.new([:foo, 5]) # => false
+ # Template.new([:foo, 6]).match Tuple.new([:foo, 5]) # => false
+ # Template.new([:foo, nil]).match Tuple.new([:foo]) # => false
+ # Template.new([:foo, 6]).match Tuple.new([:foo]) # => false
+
+ def match(tuple)
+ return false unless tuple.respond_to?(:size)
+ return false unless tuple.respond_to?(:fetch)
+ return false unless self.size == tuple.size
+ each do |k, v|
+ begin
+ it = tuple.fetch(k)
+ rescue
+ return false
+ end
+ next if v.nil?
+ next if v == it
+ next if v === it
+ return false
+ end
+ return true
+ end
+
+ ##
+ # Alias for #match.
+
+ def ===(tuple)
+ match(tuple)
+ end
+
+ end
+
+ ##
+ # <i>Documentation?</i>
+
+ class DRbObjectTemplate
+
+ ##
+ # Creates a new DRbObjectTemplate that will match against +uri+ and +ref+.
+
+ def initialize(uri=nil, ref=nil)
+ @drb_uri = uri
+ @drb_ref = ref
+ end
+
+ ##
+ # This DRbObjectTemplate matches +ro+ if the remote object's drburi and
+ # drbref are the same. +nil+ is used as a wildcard.
+
+ def ===(ro)
+ return true if super(ro)
+ unless @drb_uri.nil?
+ return false unless (@drb_uri === ro.__drburi rescue false)
+ end
+ unless @drb_ref.nil?
+ return false unless (@drb_ref === ro.__drbref rescue false)
+ end
+ true
+ end
+
+ end
+
+ ##
+ # TupleSpaceProxy allows a remote Tuplespace to appear as local.
+
+ class TupleSpaceProxy
+ ##
+ # A Port ensures that a moved tuple arrives properly at its destination
+ # and does not get lost.
+ #
+ # See https://bugs.ruby-lang.org/issues/8125
+
+ class Port # :nodoc:
+ attr_reader :value
+
+ def self.deliver
+ port = new
+
+ begin
+ yield(port)
+ ensure
+ port.close
+ end
+
+ port.value
+ end
+
+ def initialize
+ @open = true
+ @value = nil
+ end
+
+ ##
+ # Don't let the DRb thread push to it when remote sends tuple
+
+ def close
+ @open = false
+ end
+
+ ##
+ # Stores +value+ and ensure it does not get marshaled multiple times.
+
+ def push value
+ raise 'port closed' unless @open
+
+ @value = value
+
+ nil # avoid Marshal
+ end
+ end
+
+ ##
+ # Creates a new TupleSpaceProxy to wrap +ts+.
+
+ def initialize(ts)
+ @ts = ts
+ end
+
+ ##
+ # Adds +tuple+ to the proxied TupleSpace. See TupleSpace#write.
+
+ def write(tuple, sec=nil)
+ @ts.write(tuple, sec)
+ end
+
+ ##
+ # Takes +tuple+ from the proxied TupleSpace. See TupleSpace#take.
+
+ def take(tuple, sec=nil, &block)
+ Port.deliver do |port|
+ @ts.move(DRbObject.new(port), tuple, sec, &block)
+ end
+ end
+
+ ##
+ # Reads +tuple+ from the proxied TupleSpace. See TupleSpace#read.
+
+ def read(tuple, sec=nil, &block)
+ @ts.read(tuple, sec, &block)
+ end
+
+ ##
+ # Reads all tuples matching +tuple+ from the proxied TupleSpace. See
+ # TupleSpace#read_all.
+
+ def read_all(tuple)
+ @ts.read_all(tuple)
+ end
+
+ ##
+ # Registers for notifications of event +ev+ on the proxied TupleSpace.
+ # See TupleSpace#notify
+
+ def notify(ev, tuple, sec=nil)
+ @ts.notify(ev, tuple, sec)
+ end
+
+ end
+
+ ##
+ # An SimpleRenewer allows a TupleSpace to check if a TupleEntry is still
+ # alive.
+
+ class SimpleRenewer
+
+ include DRbUndumped
+
+ ##
+ # Creates a new SimpleRenewer that keeps an object alive for another +sec+
+ # seconds.
+
+ def initialize(sec=180)
+ @sec = sec
+ end
+
+ ##
+ # Called by the TupleSpace to check if the object is still alive.
+
+ def renew
+ @sec
+ end
+ end
+
+end
+
diff --git a/lib/rinda/ring.rb b/lib/rinda/ring.rb
new file mode 100644
index 0000000000..948cfaf208
--- /dev/null
+++ b/lib/rinda/ring.rb
@@ -0,0 +1,484 @@
+# frozen_string_literal: false
+#
+# Note: Rinda::Ring API is unstable.
+#
+require 'drb/drb'
+require_relative 'rinda'
+require 'ipaddr'
+
+module Rinda
+
+ ##
+ # The default port Ring discovery will use.
+
+ Ring_PORT = 7647
+
+ ##
+ # A RingServer allows a Rinda::TupleSpace to be located via UDP broadcasts.
+ # Default service location uses the following steps:
+ #
+ # 1. A RingServer begins listening on the network broadcast UDP address.
+ # 2. A RingFinger sends a UDP packet containing the DRb URI where it will
+ # listen for a reply.
+ # 3. The RingServer receives the UDP packet and connects back to the
+ # provided DRb URI with the DRb service.
+ #
+ # A RingServer requires a TupleSpace:
+ #
+ # ts = Rinda::TupleSpace.new
+ # rs = Rinda::RingServer.new
+ #
+ # RingServer can also listen on multicast addresses for announcements. This
+ # allows multiple RingServers to run on the same host. To use network
+ # broadcast and multicast:
+ #
+ # ts = Rinda::TupleSpace.new
+ # rs = Rinda::RingServer.new ts, %w[Socket::INADDR_ANY, 239.0.0.1 ff02::1]
+
+ class RingServer
+
+ include DRbUndumped
+
+ ##
+ # Special renewer for the RingServer to allow shutdown
+
+ class Renewer # :nodoc:
+ include DRbUndumped
+
+ ##
+ # Set to false to shutdown future requests using this Renewer
+
+ attr_writer :renew
+
+ def initialize # :nodoc:
+ @renew = true
+ end
+
+ def renew # :nodoc:
+ @renew ? 1 : true
+ end
+ end
+
+ ##
+ # Advertises +ts+ on the given +addresses+ at +port+.
+ #
+ # If +addresses+ is omitted only the UDP broadcast address is used.
+ #
+ # +addresses+ can contain multiple addresses. If a multicast address is
+ # given in +addresses+ then the RingServer will listen for multicast
+ # queries.
+ #
+ # If you use IPv4 multicast you may need to set an address of the inbound
+ # interface which joins a multicast group.
+ #
+ # ts = Rinda::TupleSpace.new
+ # rs = Rinda::RingServer.new(ts, [['239.0.0.1', '9.5.1.1']])
+ #
+ # You can set addresses as an Array Object. The first element of the
+ # Array is a multicast address and the second is an inbound interface
+ # address. If the second is omitted then '0.0.0.0' is used.
+ #
+ # If you use IPv6 multicast you may need to set both the local interface
+ # address and the inbound interface index:
+ #
+ # rs = Rinda::RingServer.new(ts, [['ff02::1', '::1', 1]])
+ #
+ # The first element is a multicast address and the second is an inbound
+ # interface address. The third is an inbound interface index.
+ #
+ # At this time there is no easy way to get an interface index by name.
+ #
+ # If the second is omitted then '::1' is used.
+ # If the third is omitted then 0 (default interface) is used.
+
+ def initialize(ts, addresses=[Socket::INADDR_ANY], port=Ring_PORT)
+ @port = port
+
+ if Integer === addresses then
+ addresses, @port = [Socket::INADDR_ANY], addresses
+ end
+
+ @renewer = Renewer.new
+
+ @ts = ts
+ @sockets = []
+ addresses.each do |address|
+ if Array === address
+ make_socket(*address)
+ else
+ make_socket(address)
+ end
+ end
+
+ @w_services = write_services
+ @r_service = reply_service
+ end
+
+ ##
+ # Creates a socket at +address+
+ #
+ # If +address+ is multicast address then +interface_address+ and
+ # +multicast_interface+ can be set as optional.
+ #
+ # A created socket is bound to +interface_address+. If you use IPv4
+ # multicast then the interface of +interface_address+ is used as the
+ # inbound interface. If +interface_address+ is omitted or nil then
+ # '0.0.0.0' or '::1' is used.
+ #
+ # If you use IPv6 multicast then +multicast_interface+ is used as the
+ # inbound interface. +multicast_interface+ is a network interface index.
+ # If +multicast_interface+ is omitted then 0 (default interface) is used.
+
+ def make_socket(address, interface_address=nil, multicast_interface=0)
+ addrinfo = Addrinfo.udp(address, @port)
+
+ socket = Socket.new(addrinfo.pfamily, addrinfo.socktype,
+ addrinfo.protocol)
+
+ if addrinfo.ipv4_multicast? or addrinfo.ipv6_multicast? then
+ if Socket.const_defined?(:SO_REUSEPORT) then
+ socket.setsockopt(:SOCKET, :SO_REUSEPORT, true)
+ else
+ socket.setsockopt(:SOCKET, :SO_REUSEADDR, true)
+ end
+
+ if addrinfo.ipv4_multicast? then
+ interface_address = '0.0.0.0' if interface_address.nil?
+ socket.bind(Addrinfo.udp(interface_address, @port))
+
+ mreq = IPAddr.new(addrinfo.ip_address).hton +
+ IPAddr.new(interface_address).hton
+
+ socket.setsockopt(:IPPROTO_IP, :IP_ADD_MEMBERSHIP, mreq)
+ else
+ interface_address = '::1' if interface_address.nil?
+ socket.bind(Addrinfo.udp(interface_address, @port))
+
+ mreq = IPAddr.new(addrinfo.ip_address).hton +
+ [multicast_interface].pack('I')
+
+ socket.setsockopt(:IPPROTO_IPV6, :IPV6_JOIN_GROUP, mreq)
+ end
+ else
+ socket.bind(addrinfo)
+ end
+
+ socket
+ rescue
+ socket = socket.close if socket
+ raise
+ ensure
+ @sockets << socket if socket
+ end
+
+ ##
+ # Creates threads that pick up UDP packets and passes them to do_write for
+ # decoding.
+
+ def write_services
+ @sockets.map do |s|
+ Thread.new(s) do |socket|
+ loop do
+ msg = socket.recv(1024)
+ do_write(msg)
+ end
+ end
+ end
+ end
+
+ ##
+ # Extracts the response URI from +msg+ and adds it to TupleSpace where it
+ # will be picked up by +reply_service+ for notification.
+
+ def do_write(msg)
+ Thread.new do
+ begin
+ tuple, sec = Marshal.load(msg)
+ @ts.write(tuple, sec)
+ rescue
+ end
+ end
+ end
+
+ ##
+ # Creates a thread that notifies waiting clients from the TupleSpace.
+
+ def reply_service
+ Thread.new do
+ loop do
+ do_reply
+ end
+ end
+ end
+
+ ##
+ # Pulls lookup tuples out of the TupleSpace and sends their DRb object the
+ # address of the local TupleSpace.
+
+ def do_reply
+ tuple = @ts.take([:lookup_ring, nil], @renewer)
+ Thread.new { tuple[1].call(@ts) rescue nil}
+ rescue
+ end
+
+ ##
+ # Shuts down the RingServer
+
+ def shutdown
+ @renewer.renew = false
+
+ @w_services.each do |thread|
+ thread.kill
+ thread.join
+ end
+
+ @sockets.each do |socket|
+ socket.close
+ end
+
+ @r_service.kill
+ @r_service.join
+ end
+
+ end
+
+ ##
+ # RingFinger is used by RingServer clients to discover the RingServer's
+ # TupleSpace. Typically, all a client needs to do is call
+ # RingFinger.primary to retrieve the remote TupleSpace, which it can then
+ # begin using.
+ #
+ # To find the first available remote TupleSpace:
+ #
+ # Rinda::RingFinger.primary
+ #
+ # To create a RingFinger that broadcasts to a custom list:
+ #
+ # rf = Rinda::RingFinger.new ['localhost', '192.0.2.1']
+ # rf.primary
+ #
+ # Rinda::RingFinger also understands multicast addresses and sets them up
+ # properly. This allows you to run multiple RingServers on the same host:
+ #
+ # rf = Rinda::RingFinger.new ['239.0.0.1']
+ # rf.primary
+ #
+ # You can set the hop count (or TTL) for multicast searches using
+ # #multicast_hops.
+ #
+ # If you use IPv6 multicast you may need to set both an address and the
+ # outbound interface index:
+ #
+ # rf = Rinda::RingFinger.new ['ff02::1']
+ # rf.multicast_interface = 1
+ # rf.primary
+ #
+ # At this time there is no easy way to get an interface index by name.
+
+ class RingFinger
+
+ @@broadcast_list = ['<broadcast>', 'localhost']
+
+ @@finger = nil
+
+ ##
+ # Creates a singleton RingFinger and looks for a RingServer. Returns the
+ # created RingFinger.
+
+ def self.finger
+ unless @@finger
+ @@finger = self.new
+ @@finger.lookup_ring_any
+ end
+ @@finger
+ end
+
+ ##
+ # Returns the first advertised TupleSpace.
+
+ def self.primary
+ finger.primary
+ end
+
+ ##
+ # Contains all discovered TupleSpaces except for the primary.
+
+ def self.to_a
+ finger.to_a
+ end
+
+ ##
+ # The list of addresses where RingFinger will send query packets.
+
+ attr_accessor :broadcast_list
+
+ ##
+ # Maximum number of hops for sent multicast packets (if using a multicast
+ # address in the broadcast list). The default is 1 (same as UDP
+ # broadcast).
+
+ attr_accessor :multicast_hops
+
+ ##
+ # The interface index to send IPv6 multicast packets from.
+
+ attr_accessor :multicast_interface
+
+ ##
+ # The port that RingFinger will send query packets to.
+
+ attr_accessor :port
+
+ ##
+ # Contain the first advertised TupleSpace after lookup_ring_any is called.
+
+ attr_accessor :primary
+
+ ##
+ # Creates a new RingFinger that will look for RingServers at +port+ on
+ # the addresses in +broadcast_list+.
+ #
+ # If +broadcast_list+ contains a multicast address then multicast queries
+ # will be made using the given multicast_hops and multicast_interface.
+
+ def initialize(broadcast_list=@@broadcast_list, port=Ring_PORT)
+ @broadcast_list = broadcast_list || ['localhost']
+ @port = port
+ @primary = nil
+ @rings = []
+
+ @multicast_hops = 1
+ @multicast_interface = 0
+ end
+
+ ##
+ # Contains all discovered TupleSpaces except for the primary.
+
+ def to_a
+ @rings
+ end
+
+ ##
+ # Iterates over all discovered TupleSpaces starting with the primary.
+
+ def each
+ lookup_ring_any unless @primary
+ return unless @primary
+ yield(@primary)
+ @rings.each { |x| yield(x) }
+ end
+
+ ##
+ # Looks up RingServers waiting +timeout+ seconds. RingServers will be
+ # given +block+ as a callback, which will be called with the remote
+ # TupleSpace.
+
+ def lookup_ring(timeout=5, &block)
+ return lookup_ring_any(timeout) unless block_given?
+
+ msg = Marshal.dump([[:lookup_ring, DRbObject.new(block)], timeout])
+ @broadcast_list.each do |it|
+ send_message(it, msg)
+ end
+ sleep(timeout)
+ end
+
+ ##
+ # Returns the first found remote TupleSpace. Any further recovered
+ # TupleSpaces can be found by calling +to_a+.
+
+ def lookup_ring_any(timeout=5)
+ queue = Thread::Queue.new
+
+ Thread.new do
+ self.lookup_ring(timeout) do |ts|
+ queue.push(ts)
+ end
+ queue.push(nil)
+ end
+
+ @primary = queue.pop
+ raise('RingNotFound') if @primary.nil?
+
+ Thread.new do
+ while it = queue.pop
+ @rings.push(it)
+ end
+ end
+
+ @primary
+ end
+
+ ##
+ # Creates a socket for +address+ with the appropriate multicast options
+ # for multicast addresses.
+
+ def make_socket(address) # :nodoc:
+ addrinfo = Addrinfo.udp(address, @port)
+
+ soc = Socket.new(addrinfo.pfamily, addrinfo.socktype, addrinfo.protocol)
+ begin
+ if addrinfo.ipv4_multicast? then
+ soc.setsockopt(Socket::Option.ipv4_multicast_loop(1))
+ soc.setsockopt(Socket::Option.ipv4_multicast_ttl(@multicast_hops))
+ elsif addrinfo.ipv6_multicast? then
+ soc.setsockopt(:IPPROTO_IPV6, :IPV6_MULTICAST_LOOP, true)
+ soc.setsockopt(:IPPROTO_IPV6, :IPV6_MULTICAST_HOPS,
+ [@multicast_hops].pack('I'))
+ soc.setsockopt(:IPPROTO_IPV6, :IPV6_MULTICAST_IF,
+ [@multicast_interface].pack('I'))
+ else
+ soc.setsockopt(:SOL_SOCKET, :SO_BROADCAST, true)
+ end
+
+ soc.connect(addrinfo)
+ rescue Exception
+ soc.close
+ raise
+ end
+
+ soc
+ end
+
+ def send_message(address, message) # :nodoc:
+ soc = make_socket(address)
+
+ soc.send(message, 0)
+ rescue
+ nil
+ ensure
+ soc.close if soc
+ end
+
+ end
+
+ ##
+ # RingProvider uses a RingServer advertised TupleSpace as a name service.
+ # TupleSpace clients can register themselves with the remote TupleSpace and
+ # look up other provided services via the remote TupleSpace.
+ #
+ # Services are registered with a tuple of the format [:name, klass,
+ # DRbObject, description].
+
+ class RingProvider
+
+ ##
+ # Creates a RingProvider that will provide a +klass+ service running on
+ # +front+, with a +description+. +renewer+ is optional.
+
+ def initialize(klass, front, desc, renewer = nil)
+ @tuple = [:name, klass, front, desc]
+ @renewer = renewer || Rinda::SimpleRenewer.new
+ end
+
+ ##
+ # Advertises this service on the primary remote TupleSpace.
+
+ def provide
+ ts = Rinda::RingFinger.primary
+ ts.write(@tuple, @renewer)
+ end
+
+ end
+
+end
diff --git a/lib/rinda/tuplespace.rb b/lib/rinda/tuplespace.rb
new file mode 100644
index 0000000000..6a41a7ba75
--- /dev/null
+++ b/lib/rinda/tuplespace.rb
@@ -0,0 +1,641 @@
+# frozen_string_literal: false
+require 'monitor'
+require 'drb/drb'
+require_relative 'rinda'
+require 'forwardable'
+
+module Rinda
+
+ ##
+ # A TupleEntry is a Tuple (i.e. a possible entry in some Tuplespace)
+ # together with expiry and cancellation data.
+
+ class TupleEntry
+
+ include DRbUndumped
+
+ attr_accessor :expires
+
+ ##
+ # Creates a TupleEntry based on +ary+ with an optional renewer or expiry
+ # time +sec+.
+ #
+ # A renewer must implement the +renew+ method which returns a Numeric,
+ # nil, or true to indicate when the tuple has expired.
+
+ def initialize(ary, sec=nil)
+ @cancel = false
+ @expires = nil
+ @tuple = make_tuple(ary)
+ @renewer = nil
+ renew(sec)
+ end
+
+ ##
+ # Marks this TupleEntry as canceled.
+
+ def cancel
+ @cancel = true
+ end
+
+ ##
+ # A TupleEntry is dead when it is canceled or expired.
+
+ def alive?
+ !canceled? && !expired?
+ end
+
+ ##
+ # Return the object which makes up the tuple itself: the Array
+ # or Hash.
+
+ def value; @tuple.value; end
+
+ ##
+ # Returns the canceled status.
+
+ def canceled?; @cancel; end
+
+ ##
+ # Has this tuple expired? (true/false).
+ #
+ # A tuple has expired when its expiry timer based on the +sec+ argument to
+ # #initialize runs out.
+
+ def expired?
+ return true unless @expires
+ return false if @expires > Time.now
+ return true if @renewer.nil?
+ renew(@renewer)
+ return true unless @expires
+ return @expires < Time.now
+ end
+
+ ##
+ # Reset the expiry time according to +sec_or_renewer+.
+ #
+ # +nil+:: it is set to expire in the far future.
+ # +true+:: it has expired.
+ # Numeric:: it will expire in that many seconds.
+ #
+ # Otherwise the argument refers to some kind of renewer object
+ # which will reset its expiry time.
+
+ def renew(sec_or_renewer)
+ sec, @renewer = get_renewer(sec_or_renewer)
+ @expires = make_expires(sec)
+ end
+
+ ##
+ # Returns an expiry Time based on +sec+ which can be one of:
+ # Numeric:: +sec+ seconds into the future
+ # +true+:: the expiry time is the start of 1970 (i.e. expired)
+ # +nil+:: it is Tue Jan 19 03:14:07 GMT Standard Time 2038 (i.e. when
+ # UNIX clocks will die)
+
+ def make_expires(sec=nil)
+ case sec
+ when Numeric
+ Time.now + sec
+ when true
+ Time.at(1)
+ when nil
+ Time.at(2**31-1)
+ end
+ end
+
+ ##
+ # Retrieves +key+ from the tuple.
+
+ def [](key)
+ @tuple[key]
+ end
+
+ ##
+ # Fetches +key+ from the tuple.
+
+ def fetch(key)
+ @tuple.fetch(key)
+ end
+
+ ##
+ # The size of the tuple.
+
+ def size
+ @tuple.size
+ end
+
+ ##
+ # Creates a Rinda::Tuple for +ary+.
+
+ def make_tuple(ary)
+ Rinda::Tuple.new(ary)
+ end
+
+ private
+
+ ##
+ # Returns a valid argument to make_expires and the renewer or nil.
+ #
+ # Given +true+, +nil+, or Numeric, returns that value and +nil+ (no actual
+ # renewer). Otherwise it returns an expiry value from calling +it.renew+
+ # and the renewer.
+
+ def get_renewer(it)
+ case it
+ when Numeric, true, nil
+ return it, nil
+ else
+ begin
+ return it.renew, it
+ rescue Exception
+ return it, nil
+ end
+ end
+ end
+
+ end
+
+ ##
+ # A TemplateEntry is a Template together with expiry and cancellation data.
+
+ class TemplateEntry < TupleEntry
+ ##
+ # Matches this TemplateEntry against +tuple+. See Template#match for
+ # details on how a Template matches a Tuple.
+
+ def match(tuple)
+ @tuple.match(tuple)
+ end
+
+ alias === match
+
+ def make_tuple(ary) # :nodoc:
+ Rinda::Template.new(ary)
+ end
+
+ end
+
+ ##
+ # <i>Documentation?</i>
+
+ class WaitTemplateEntry < TemplateEntry
+
+ attr_reader :found
+
+ def initialize(place, ary, expires=nil)
+ super(ary, expires)
+ @place = place
+ @cond = place.new_cond
+ @found = nil
+ end
+
+ def cancel
+ super
+ signal
+ end
+
+ def wait
+ @cond.wait
+ end
+
+ def read(tuple)
+ @found = tuple
+ signal
+ end
+
+ def signal
+ @place.synchronize do
+ @cond.signal
+ end
+ end
+
+ end
+
+ ##
+ # A NotifyTemplateEntry is returned by TupleSpace#notify and is notified of
+ # TupleSpace changes. You may receive either your subscribed event or the
+ # 'close' event when iterating over notifications.
+ #
+ # See TupleSpace#notify_event for valid notification types.
+ #
+ # == Example
+ #
+ # ts = Rinda::TupleSpace.new
+ # observer = ts.notify 'write', [nil]
+ #
+ # Thread.start do
+ # observer.each { |t| p t }
+ # end
+ #
+ # 3.times { |i| ts.write [i] }
+ #
+ # Outputs:
+ #
+ # ['write', [0]]
+ # ['write', [1]]
+ # ['write', [2]]
+
+ class NotifyTemplateEntry < TemplateEntry
+
+ ##
+ # Creates a new NotifyTemplateEntry that watches +place+ for +event+s that
+ # match +tuple+.
+
+ def initialize(place, event, tuple, expires=nil)
+ ary = [event, Rinda::Template.new(tuple)]
+ super(ary, expires)
+ @queue = Thread::Queue.new
+ @done = false
+ end
+
+ ##
+ # Called by TupleSpace to notify this NotifyTemplateEntry of a new event.
+
+ def notify(ev)
+ @queue.push(ev)
+ end
+
+ ##
+ # Retrieves a notification. Raises RequestExpiredError when this
+ # NotifyTemplateEntry expires.
+
+ def pop
+ raise RequestExpiredError if @done
+ it = @queue.pop
+ @done = true if it[0] == 'close'
+ return it
+ end
+
+ ##
+ # Yields event/tuple pairs until this NotifyTemplateEntry expires.
+
+ def each # :yields: event, tuple
+ while !@done
+ it = pop
+ yield(it)
+ end
+ rescue
+ ensure
+ cancel
+ end
+
+ end
+
+ ##
+ # TupleBag is an unordered collection of tuples. It is the basis
+ # of Tuplespace.
+
+ class TupleBag
+ class TupleBin
+ extend Forwardable
+ def_delegators '@bin', :find_all, :delete_if, :each, :empty?
+
+ def initialize
+ @bin = []
+ end
+
+ def add(tuple)
+ @bin.push(tuple)
+ end
+
+ def delete(tuple)
+ idx = @bin.rindex(tuple)
+ @bin.delete_at(idx) if idx
+ end
+
+ def find
+ @bin.reverse_each do |x|
+ return x if yield(x)
+ end
+ nil
+ end
+ end
+
+ def initialize # :nodoc:
+ @hash = {}
+ @enum = enum_for(:each_entry)
+ end
+
+ ##
+ # +true+ if the TupleBag to see if it has any expired entries.
+
+ def has_expires?
+ @enum.find do |tuple|
+ tuple.expires
+ end
+ end
+
+ ##
+ # Add +tuple+ to the TupleBag.
+
+ def push(tuple)
+ key = bin_key(tuple)
+ @hash[key] ||= TupleBin.new
+ @hash[key].add(tuple)
+ end
+
+ ##
+ # Removes +tuple+ from the TupleBag.
+
+ def delete(tuple)
+ key = bin_key(tuple)
+ bin = @hash[key]
+ return nil unless bin
+ bin.delete(tuple)
+ @hash.delete(key) if bin.empty?
+ tuple
+ end
+
+ ##
+ # Finds all live tuples that match +template+.
+ def find_all(template)
+ bin_for_find(template).find_all do |tuple|
+ tuple.alive? && template.match(tuple)
+ end
+ end
+
+ ##
+ # Finds a live tuple that matches +template+.
+
+ def find(template)
+ bin_for_find(template).find do |tuple|
+ tuple.alive? && template.match(tuple)
+ end
+ end
+
+ ##
+ # Finds all tuples in the TupleBag which when treated as templates, match
+ # +tuple+ and are alive.
+
+ def find_all_template(tuple)
+ @enum.find_all do |template|
+ template.alive? && template.match(tuple)
+ end
+ end
+
+ ##
+ # Delete tuples which dead tuples from the TupleBag, returning the deleted
+ # tuples.
+
+ def delete_unless_alive
+ deleted = []
+ @hash.each do |key, bin|
+ bin.delete_if do |tuple|
+ if tuple.alive?
+ false
+ else
+ deleted.push(tuple)
+ true
+ end
+ end
+ end
+ deleted
+ end
+
+ private
+ def each_entry(&blk)
+ @hash.each do |k, v|
+ v.each(&blk)
+ end
+ end
+
+ def bin_key(tuple)
+ head = tuple[0]
+ if head.class == Symbol
+ return head
+ else
+ false
+ end
+ end
+
+ def bin_for_find(template)
+ key = bin_key(template)
+ key ? @hash.fetch(key, []) : @enum
+ end
+ end
+
+ ##
+ # The Tuplespace manages access to the tuples it contains,
+ # ensuring mutual exclusion requirements are met.
+ #
+ # The +sec+ option for the write, take, move, read and notify methods may
+ # either be a number of seconds or a Renewer object.
+
+ class TupleSpace
+
+ include DRbUndumped
+ include MonitorMixin
+
+ ##
+ # Creates a new TupleSpace. +period+ is used to control how often to look
+ # for dead tuples after modifications to the TupleSpace.
+ #
+ # If no dead tuples are found +period+ seconds after the last
+ # modification, the TupleSpace will stop looking for dead tuples.
+
+ def initialize(period=60)
+ super()
+ @bag = TupleBag.new
+ @read_waiter = TupleBag.new
+ @take_waiter = TupleBag.new
+ @notify_waiter = TupleBag.new
+ @period = period
+ @keeper = nil
+ end
+
+ ##
+ # Adds +tuple+
+
+ def write(tuple, sec=nil)
+ entry = create_entry(tuple, sec)
+ synchronize do
+ if entry.expired?
+ @read_waiter.find_all_template(entry).each do |template|
+ template.read(tuple)
+ end
+ notify_event('write', entry.value)
+ notify_event('delete', entry.value)
+ else
+ @bag.push(entry)
+ start_keeper if entry.expires
+ @read_waiter.find_all_template(entry).each do |template|
+ template.read(tuple)
+ end
+ @take_waiter.find_all_template(entry).each do |template|
+ template.signal
+ end
+ notify_event('write', entry.value)
+ end
+ end
+ entry
+ end
+
+ ##
+ # Removes +tuple+
+
+ def take(tuple, sec=nil, &block)
+ move(nil, tuple, sec, &block)
+ end
+
+ ##
+ # Moves +tuple+ to +port+.
+
+ def move(port, tuple, sec=nil)
+ template = WaitTemplateEntry.new(self, tuple, sec)
+ yield(template) if block_given?
+ synchronize do
+ entry = @bag.find(template)
+ if entry
+ port.push(entry.value) if port
+ @bag.delete(entry)
+ notify_event('take', entry.value)
+ return port ? nil : entry.value
+ end
+ raise RequestExpiredError if template.expired?
+
+ begin
+ @take_waiter.push(template)
+ start_keeper if template.expires
+ while true
+ raise RequestCanceledError if template.canceled?
+ raise RequestExpiredError if template.expired?
+ entry = @bag.find(template)
+ if entry
+ port.push(entry.value) if port
+ @bag.delete(entry)
+ notify_event('take', entry.value)
+ return port ? nil : entry.value
+ end
+ template.wait
+ end
+ ensure
+ @take_waiter.delete(template)
+ end
+ end
+ end
+
+ ##
+ # Reads +tuple+, but does not remove it.
+
+ def read(tuple, sec=nil)
+ template = WaitTemplateEntry.new(self, tuple, sec)
+ yield(template) if block_given?
+ synchronize do
+ entry = @bag.find(template)
+ return entry.value if entry
+ raise RequestExpiredError if template.expired?
+
+ begin
+ @read_waiter.push(template)
+ start_keeper if template.expires
+ template.wait
+ raise RequestCanceledError if template.canceled?
+ raise RequestExpiredError if template.expired?
+ return template.found
+ ensure
+ @read_waiter.delete(template)
+ end
+ end
+ end
+
+ ##
+ # Returns all tuples matching +tuple+. Does not remove the found tuples.
+
+ def read_all(tuple)
+ template = WaitTemplateEntry.new(self, tuple, nil)
+ synchronize do
+ entry = @bag.find_all(template)
+ entry.collect do |e|
+ e.value
+ end
+ end
+ end
+
+ ##
+ # Registers for notifications of +event+. Returns a NotifyTemplateEntry.
+ # See NotifyTemplateEntry for examples of how to listen for notifications.
+ #
+ # +event+ can be:
+ # 'write':: A tuple was added
+ # 'take':: A tuple was taken or moved
+ # 'delete':: A tuple was lost after being overwritten or expiring
+ #
+ # The TupleSpace will also notify you of the 'close' event when the
+ # NotifyTemplateEntry has expired.
+
+ def notify(event, tuple, sec=nil)
+ template = NotifyTemplateEntry.new(self, event, tuple, sec)
+ synchronize do
+ @notify_waiter.push(template)
+ end
+ template
+ end
+
+ private
+
+ def create_entry(tuple, sec)
+ TupleEntry.new(tuple, sec)
+ end
+
+ ##
+ # Removes dead tuples.
+
+ def keep_clean
+ synchronize do
+ @read_waiter.delete_unless_alive.each do |e|
+ e.signal
+ end
+ @take_waiter.delete_unless_alive.each do |e|
+ e.signal
+ end
+ @notify_waiter.delete_unless_alive.each do |e|
+ e.notify(['close'])
+ end
+ @bag.delete_unless_alive.each do |e|
+ notify_event('delete', e.value)
+ end
+ end
+ end
+
+ ##
+ # Notifies all registered listeners for +event+ of a status change of
+ # +tuple+.
+
+ def notify_event(event, tuple)
+ ev = [event, tuple]
+ @notify_waiter.find_all_template(ev).each do |template|
+ template.notify(ev)
+ end
+ end
+
+ ##
+ # Creates a thread that scans the tuplespace for expired tuples.
+
+ def start_keeper
+ return if @keeper && @keeper.alive?
+ @keeper = Thread.new do
+ while true
+ sleep(@period)
+ synchronize do
+ break unless need_keeper?
+ keep_clean
+ end
+ end
+ end
+ end
+
+ ##
+ # Checks the tuplespace to see if it needs cleaning.
+
+ def need_keeper?
+ return true if @bag.has_expires?
+ return true if @read_waiter.has_expires?
+ return true if @take_waiter.has_expires?
+ return true if @notify_waiter.has_expires?
+ end
+
+ end
+
+end
+
diff --git a/lib/ruby_vm/mjit/c_pointer.rb b/lib/ruby_vm/mjit/c_pointer.rb
new file mode 100644
index 0000000000..a92c2140ae
--- /dev/null
+++ b/lib/ruby_vm/mjit/c_pointer.rb
@@ -0,0 +1,329 @@
+module RubyVM::MJIT # :nodoc: all
+ # Every class under this namespace is a pointer. Even if the type is
+ # immediate, it shouldn't be dereferenced until `*` is called.
+ module CPointer
+ # Note: We'd like to avoid alphabetic method names to avoid a conflict
+ # with member methods. to_i and to_s are considered an exception.
+ class Struct
+ # @param name [String]
+ # @param sizeof [Integer]
+ # @param members [Hash{ Symbol => [RubyVM::MJIT::CType::*, Integer, TrueClass] }]
+ def initialize(addr, sizeof, members)
+ @addr = addr
+ @sizeof = sizeof
+ @members = members
+ end
+
+ # Get a raw address
+ def to_i
+ @addr
+ end
+
+ # Serialized address for generated code
+ def to_s
+ "0x#{@addr.to_s(16)}"
+ end
+
+ # Pointer diff
+ def -(struct)
+ raise ArgumentError if self.class != struct.class
+ (@addr - struct.to_i) / @sizeof
+ end
+
+ # Primitive API that does no automatic dereference
+ # TODO: remove this?
+ # @param member [Symbol]
+ def [](member)
+ type, offset = @members.fetch(member)
+ type.new(@addr + offset / 8)
+ end
+
+ private
+
+ # @param member [Symbol]
+ # @param value [Object]
+ def []=(member, value)
+ type, offset = @members.fetch(member)
+ type[@addr + offset / 8] = value
+ end
+
+ # @param sizeof [Integer]
+ # @param members [Hash{ Symbol => [Integer, RubyVM::MJIT::CType::*] }]
+ def self.define(sizeof, members)
+ Class.new(self) do
+ # Return the size of this type
+ define_singleton_method(:sizeof) { sizeof }
+
+ define_method(:initialize) do |addr = nil|
+ if addr.nil? # TODO: get rid of this feature later
+ addr = Fiddle.malloc(sizeof)
+ end
+ super(addr, sizeof, members)
+ end
+
+ members.each do |member, (type, offset, to_ruby)|
+ # Intelligent API that does automatic dereference
+ define_method(member) do
+ value = self[member]
+ if value.respond_to?(:*)
+ value = value.*
+ end
+ if to_ruby
+ value = C.to_ruby(value)
+ end
+ value
+ end
+
+ define_method("#{member}=") do |value|
+ self[member] = value
+ end
+ end
+ end
+ end
+ end
+
+ # Note: We'd like to avoid alphabetic method names to avoid a conflict
+ # with member methods. to_i is considered an exception.
+ class Union
+ # @param _name [String] To be used when it starts defining a union pointer class
+ # @param sizeof [Integer]
+ # @param members [Hash{ Symbol => RubyVM::MJIT::CType::* }]
+ def initialize(addr, sizeof, members)
+ @addr = addr
+ @sizeof = sizeof
+ @members = members
+ end
+
+ # Get a raw address
+ def to_i
+ @addr
+ end
+
+ # Move addr to access this pointer like an array
+ def +(index)
+ raise ArgumentError unless index.is_a?(Integer)
+ self.class.new(@addr + index * @sizeof)
+ end
+
+ # Pointer diff
+ def -(union)
+ raise ArgumentError if self.class != union.class
+ (@addr - union.instance_variable_get(:@addr)) / @sizeof
+ end
+
+ # @param sizeof [Integer]
+ # @param members [Hash{ Symbol => RubyVM::MJIT::CType::* }]
+ def self.define(sizeof, members)
+ Class.new(self) do
+ # Return the size of this type
+ define_singleton_method(:sizeof) { sizeof }
+
+ define_method(:initialize) do |addr|
+ super(addr, sizeof, members)
+ end
+
+ members.each do |member, type|
+ # Intelligent API that does automatic dereference
+ define_method(member) do
+ value = type.new(@addr)
+ if value.respond_to?(:*)
+ value = value.*
+ end
+ value
+ end
+ end
+ end
+ end
+ end
+
+ class Immediate
+ # @param addr [Integer]
+ # @param size [Integer]
+ # @param pack [String]
+ def initialize(addr, size, pack)
+ @addr = addr
+ @size = size
+ @pack = pack
+ end
+
+ # Get a raw address
+ def to_i
+ @addr
+ end
+
+ # Move addr to addess this pointer like an array
+ def +(index)
+ Immediate.new(@addr + index * @size, @size, @pack)
+ end
+
+ # Dereference
+ def *
+ self[0]
+ end
+
+ # Array access
+ def [](index)
+ return nil if @addr == 0
+ Fiddle::Pointer.new(@addr + index * @size)[0, @size].unpack1(@pack)
+ end
+
+ # Array set
+ def []=(index, value)
+ Fiddle::Pointer.new(@addr + index * @size)[0, @size] = [value].pack(@pack)
+ end
+
+ # Serialized address for generated code. Used for embedding things like body->iseq_encoded.
+ def to_s
+ "0x#{Integer(@addr).to_s(16)}"
+ end
+
+ # @param fiddle_type [Integer] Fiddle::TYPE_*
+ def self.define(fiddle_type)
+ size = Fiddle::PackInfo::SIZE_MAP.fetch(fiddle_type)
+ pack = Fiddle::PackInfo::PACK_MAP.fetch(fiddle_type)
+
+ Class.new(self) do
+ define_method(:initialize) do |addr|
+ super(addr, size, pack)
+ end
+
+ define_singleton_method(:size) do
+ size
+ end
+
+ # Type-level []=: Used by struct fields
+ define_singleton_method(:[]=) do |addr, value|
+ Fiddle::Pointer.new(addr)[0, size] = [value].pack(pack)
+ end
+ end
+ end
+ end
+
+ # -Fiddle::TYPE_CHAR Immediate with special handling of true/false
+ class Bool < Immediate.define(-Fiddle::TYPE_CHAR)
+ # Dereference
+ def *
+ return nil if @addr == 0
+ super != 0
+ end
+
+ def self.[]=(addr, value)
+ super(addr, value ? 1 : 0)
+ end
+ end
+
+ class Pointer
+ attr_reader :type
+
+ # @param addr [Integer]
+ # @param type [Class] RubyVM::MJIT::CType::*
+ def initialize(addr, type)
+ @addr = addr
+ @type = type
+ end
+
+ # Move addr to addess this pointer like an array
+ def +(index)
+ raise ArgumentError unless index.is_a?(Integer)
+ Pointer.new(@addr + index * Fiddle::SIZEOF_VOIDP, @type)
+ end
+
+ # Dereference
+ def *
+ return nil if dest_addr == 0
+ @type.new(dest_addr)
+ end
+
+ # Array access
+ def [](index)
+ (self + index).*
+ end
+
+ # Array set
+ # @param index [Integer]
+ # @param value [Integer, RubyVM::MJIT::CPointer::Struct] an address itself or an object that return an address with to_i
+ def []=(index, value)
+ Fiddle::Pointer.new(@addr + index * Fiddle::SIZEOF_VOIDP)[0, Fiddle::SIZEOF_VOIDP] =
+ [value.to_i].pack(Fiddle::PackInfo::PACK_MAP[Fiddle::TYPE_VOIDP])
+ end
+
+ private
+
+ def dest_addr
+ Fiddle::Pointer.new(@addr)[0, Fiddle::SIZEOF_VOIDP].unpack1(Fiddle::PackInfo::PACK_MAP[Fiddle::TYPE_VOIDP])
+ end
+
+ def self.define(block)
+ Class.new(self) do
+ define_method(:initialize) do |addr|
+ super(addr, block.call)
+ end
+
+ # Type-level []=: Used by struct fields
+ # @param addr [Integer]
+ # @param value [Integer, RubyVM::MJIT::CPointer::Struct] an address itself, or an object that return an address with to_i
+ define_singleton_method(:[]=) do |addr, value|
+ value = value.to_i
+ Fiddle::Pointer.new(addr)[0, Fiddle::SIZEOF_VOIDP] = [value].pack(Fiddle::PackInfo::PACK_MAP[Fiddle::TYPE_VOIDP])
+ end
+ end
+ end
+ end
+
+ class BitField
+ # @param addr [Integer]
+ # @param width [Integer]
+ # @param offset [Integer]
+ def initialize(addr, width, offset)
+ @addr = addr
+ @width = width
+ @offset = offset
+ end
+
+ # Dereference
+ def *
+ byte = Fiddle::Pointer.new(@addr)[0, Fiddle::SIZEOF_CHAR].unpack1('c')
+ if @width == 1
+ bit = (1 & (byte >> @offset))
+ bit == 1
+ elsif @width <= 8 && @offset == 0
+ bitmask = @width.times.sum { |i| 1 << i }
+ byte & bitmask
+ else
+ raise NotImplementedError.new("not-implemented bit field access: width=#{@width} offset=#{@offset}")
+ end
+ end
+
+ # @param width [Integer]
+ # @param offset [Integer]
+ def self.define(width, offset)
+ Class.new(self) do
+ define_method(:initialize) do |addr|
+ super(addr, width, offset)
+ end
+ end
+ end
+ end
+
+ # Give a name to a dynamic CPointer class to see it on inspect
+ def self.with_class_name(prefix, name, cache: false, &block)
+ return block.call if name.empty?
+
+ # Use a cached result only if cache: true
+ class_name = "#{prefix}_#{name}"
+ klass =
+ if cache && self.const_defined?(class_name)
+ self.const_get(class_name)
+ else
+ block.call
+ end
+
+ # Give it a name unless it's already defined
+ unless self.const_defined?(class_name)
+ self.const_set(class_name, klass)
+ end
+
+ klass
+ end
+ end
+end
diff --git a/lib/ruby_vm/mjit/c_type.rb b/lib/ruby_vm/mjit/c_type.rb
new file mode 100644
index 0000000000..9c965ad2fb
--- /dev/null
+++ b/lib/ruby_vm/mjit/c_type.rb
@@ -0,0 +1,91 @@
+require 'fiddle'
+require 'fiddle/pack'
+require_relative 'c_pointer'
+
+module RubyVM::MJIT # :nodoc: all
+ module CType
+ module Struct
+ # @param name [String]
+ # @param members [Hash{ Symbol => [Integer, RubyVM::MJIT::CType::*] }]
+ def self.new(name, sizeof, **members)
+ name = members.keys.join('_') if name.empty?
+ CPointer.with_class_name('Struct', name) do
+ CPointer::Struct.define(sizeof, members)
+ end
+ end
+ end
+
+ module Union
+ # @param name [String]
+ # @param members [Hash{ Symbol => RubyVM::MJIT::CType::* }]
+ def self.new(name, sizeof, **members)
+ name = members.keys.join('_') if name.empty?
+ CPointer.with_class_name('Union', name) do
+ CPointer::Union.define(sizeof, members)
+ end
+ end
+ end
+
+ module Immediate
+ # @param fiddle_type [Integer]
+ def self.new(fiddle_type)
+ name = Fiddle.constants.find do |const|
+ const.start_with?('TYPE_') && Fiddle.const_get(const) == fiddle_type.abs
+ end&.to_s
+ name.delete_prefix!('TYPE_')
+ if fiddle_type.negative?
+ name.prepend('U')
+ end
+ CPointer.with_class_name('Immediate', name, cache: true) do
+ CPointer::Immediate.define(fiddle_type)
+ end
+ end
+
+ # @param type [String]
+ def self.parse(ctype)
+ new(Fiddle::Importer.parse_ctype(ctype))
+ end
+
+ def self.find(size, signed)
+ fiddle_type = TYPE_MAP.fetch(size)
+ fiddle_type = -fiddle_type unless signed
+ new(fiddle_type)
+ end
+
+ TYPE_MAP = Fiddle::PackInfo::SIZE_MAP.map { |type, size| [size, type.abs] }.to_h
+ private_constant :TYPE_MAP
+ end
+
+ module Bool
+ def self.new
+ CPointer::Bool
+ end
+ end
+
+ class Pointer
+ # This takes a block to avoid "stack level too deep" on a cyclic reference
+ # @param block [Proc]
+ def self.new(&block)
+ CPointer.with_class_name('Pointer', block.object_id.to_s) do
+ CPointer::Pointer.define(block)
+ end
+ end
+ end
+
+ module BitField
+ # @param width [Integer]
+ # @param offset [Integer]
+ def self.new(width, offset)
+ CPointer.with_class_name('BitField', "#{offset}_#{width}") do
+ CPointer::BitField.define(width, offset)
+ end
+ end
+ end
+
+ # Types that are referenced but not part of code generation targets
+ Stub = ::Struct.new(:name)
+
+ # Types that it failed to figure out from the header
+ Unknown = Module.new
+ end
+end
diff --git a/lib/ruby_vm/mjit/compiler.rb b/lib/ruby_vm/mjit/compiler.rb
new file mode 100644
index 0000000000..81022cd0a8
--- /dev/null
+++ b/lib/ruby_vm/mjit/compiler.rb
@@ -0,0 +1,952 @@
+# Available variables and macros in JIT-ed function:
+# ec: the first argument of _mjitXXX
+# reg_cfp: the second argument of _mjitXXX
+# GET_CFP(): refers to `reg_cfp`
+# GET_EP(): refers to `reg_cfp->ep`
+# GET_SP(): refers to `reg_cfp->sp`, or `(stack + stack_size)` if local_stack_p
+# GET_SELF(): refers to `cfp_self`
+# GET_LEP(): refers to `VM_EP_LEP(reg_cfp->ep)`
+# EXEC_EC_CFP(): refers to `val = vm_exec(ec, true)` with frame setup
+# CALL_METHOD(): using `GET_CFP()` and `EXEC_EC_CFP()`
+# TOPN(): refers to `reg_cfp->sp`, or `*(stack + (stack_size - num - 1))` if local_stack_p
+# STACK_ADDR_FROM_TOP(): refers to `reg_cfp->sp`, or `stack + (stack_size - num)` if local_stack_p
+# DISPATCH_ORIGINAL_INSN(): expanded in _mjit_compile_insn.erb
+# THROW_EXCEPTION(): specially defined for JIT
+# RESTORE_REGS(): specially defined for `leave`
+class RubyVM::MJIT::Compiler # :nodoc: all
+ C = RubyVM::MJIT.const_get(:C, false)
+ INSNS = RubyVM::MJIT.const_get(:INSNS, false)
+ UNSUPPORTED_INSNS = [
+ :defineclass, # low priority
+ ]
+
+ def initialize = freeze
+
+ # @param iseq [RubyVM::MJIT::CPointer::Struct]
+ # @param funcname [String]
+ # @param id [Integer]
+ # @return [String,NilClass]
+ def compile(iseq, funcname, id)
+ status = C.compile_status.new # not freed for now
+ status.compiled_iseq = iseq.body
+ status.compiled_id = id
+ init_compile_status(status, iseq.body, true) # not freed for now
+ if iseq.body.ci_size > 0 && status.cc_entries_index == -1
+ return nil
+ end
+
+ src = +''
+ if !status.compile_info.disable_send_cache && !status.compile_info.disable_inlining
+ unless precompile_inlinable_iseqs(src, iseq, status)
+ return nil
+ end
+ end
+
+ src << "VALUE\n#{funcname}(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp)\n{\n"
+ success = compile_body(src, iseq, status)
+ src << "\n} // end of #{funcname}\n"
+
+ return success ? src : nil
+ rescue Exception => e # should we use rb_rescue in C instead?
+ if C.mjit_opts.warnings || C.mjit_opts.verbose > 0
+ $stderr.puts "MJIT error: #{e.full_message}"
+ end
+ return nil
+ end
+
+ private
+
+ def compile_body(src, iseq, status)
+ status.success = true
+ status.local_stack_p = !iseq.body.catch_except_p
+
+ if status.local_stack_p
+ src << " VALUE stack[#{iseq.body.stack_max}];\n"
+ else
+ src << " VALUE *stack = reg_cfp->sp;\n"
+ end
+
+ unless status.inlined_iseqs.nil? # i.e. compile root
+ src << " static const rb_iseq_t *original_iseq = (const rb_iseq_t *)#{iseq};\n"
+ end
+ src << " static const VALUE *const original_body_iseq = (VALUE *)#{iseq.body.iseq_encoded};\n"
+
+ src << " VALUE cfp_self = reg_cfp->self;\n" # cache self across the method
+ src << "#undef GET_SELF\n"
+ src << "#define GET_SELF() cfp_self\n"
+
+ # Generate merged ivar guards first if needed
+ if !status.compile_info.disable_ivar_cache && using_ivar?(iseq.body)
+ src << " if (UNLIKELY(!RB_TYPE_P(GET_SELF(), T_OBJECT))) {"
+ src << " goto ivar_cancel;\n"
+ src << " }\n"
+ end
+
+ # Simulate `opt_pc` in setup_parameters_complex. Other PCs which may be passed by catch tables
+ # are not considered since vm_exec doesn't call jit_exec for catch tables.
+ if iseq.body.param.flags.has_opt
+ src << "\n"
+ src << " switch (reg_cfp->pc - ISEQ_BODY(reg_cfp->iseq)->iseq_encoded) {\n"
+ (0..iseq.body.param.opt_num).each do |i|
+ pc_offset = iseq.body.param.opt_table[i]
+ src << " case #{pc_offset}:\n"
+ src << " goto label_#{pc_offset};\n"
+ end
+ src << " }\n"
+ end
+
+ compile_insns(0, 0, status, iseq.body, src)
+ compile_cancel_handler(src, iseq.body, status)
+ src << "#undef GET_SELF\n"
+ return status.success
+ end
+
+ # Compile one conditional branch. If it has branchXXX insn, this should be
+ # called multiple times for each branch.
+ def compile_insns(stack_size, pos, status, body, src)
+ branch = C.compile_branch.new # not freed for now
+ branch.stack_size = stack_size
+ branch.finish_p = false
+
+ while pos < body.iseq_size && !already_compiled?(status, pos) && !branch.finish_p
+ insn = INSNS.fetch(C.rb_vm_insn_decode(body.iseq_encoded[pos]))
+ status.stack_size_for_pos[pos] = branch.stack_size
+
+ src << "\nlabel_#{pos}: /* #{insn.name} */\n"
+ pos = compile_insn(insn, pos, status, body.iseq_encoded + (pos+1), body, branch, src)
+ if status.success && branch.stack_size > body.stack_max
+ if mjit_opts.warnings || mjit_opts.verbose > 0
+ $stderr.puts "MJIT warning: JIT stack size (#{branch.stack_size}) exceeded its max size (#{body.stack_max})"
+ end
+ status.success = false
+ end
+ break unless status.success
+ end
+ end
+
+ # Main function of JIT compilation, vm_exec_core counterpart for JIT. Compile one insn to `f`, may modify
+ # b->stack_size and return next position.
+ #
+ # When you add a new instruction to insns.def, it would be nice to have JIT compilation support here but
+ # it's optional. This JIT compiler just ignores ISeq which includes unknown instruction, and ISeq which
+ # does not have it can be compiled as usual.
+ def compile_insn(insn, pos, status, operands, body, b, src)
+ sp_inc = C.mjit_call_attribute_sp_inc(insn.bin, operands)
+ next_pos = pos + insn.len
+
+ result = compile_insn_entry(insn, b.stack_size, sp_inc, status.local_stack_p, pos, next_pos, insn.len,
+ status.inlined_iseqs.nil?, status, operands, body)
+ if result.nil?
+ if C.mjit_opts.warnings || C.mjit_opts.verbose > 0
+ $stderr.puts "MJIT warning: Skipped to compile unsupported instruction: #{insn.name}"
+ end
+ status.success = false
+ else
+ result_src, next_pos, finish_p, compile_insns_p = result
+
+ src << result_src
+ b.stack_size += sp_inc
+
+ if finish_p
+ b.finish_p = true
+ end
+ if compile_insns_p
+ if already_compiled?(status, pos + insn.len)
+ src << "goto label_#{pos + insn.len};\n"
+ else
+ compile_insns(b.stack_size, pos + insn.len, status, body, src)
+ end
+ end
+ end
+
+ # If next_pos is already compiled and this branch is not finished yet,
+ # next instruction won't be compiled in C code next and will need `goto`.
+ if !b.finish_p && next_pos < body.iseq_size && already_compiled?(status, next_pos)
+ src << "goto label_#{next_pos};\n"
+
+ # Verify stack size assumption is the same among multiple branches
+ if status.stack_size_for_pos[next_pos] != b.stack_size
+ if mjit_opts.warnings || mjit_opts.verbose > 0
+ $stderr.puts "MJIT warning: JIT stack assumption is not the same between branches (#{status.stack_size_for_pos[next_pos]} != #{b.stack_size})\n"
+ end
+ status.success = false
+ end
+ end
+
+ return next_pos
+ end
+
+ def compile_insn_entry(insn, stack_size, sp_inc, local_stack_p, pos, next_pos, insn_len, inlined_iseq_p, status, operands, body)
+ finish_p = false
+ compile_insns = false
+
+ # TODO: define this outside this method, or at least cache it
+ opt_send_without_block = INSNS.values.find { |i| i.name == :opt_send_without_block }
+ if opt_send_without_block.nil?
+ raise 'opt_send_without_block not found'
+ end
+ send_compatible_opt_insns = INSNS.values.select do |insn|
+ insn.name.start_with?('opt_') && opt_send_without_block.opes == insn.opes &&
+ insn.expr.lines.any? { |l| l.match(/\A\s+CALL_SIMPLE_METHOD\(\);\s+\z/) }
+ end.map(&:name)
+
+ case insn.name
+ when *UNSUPPORTED_INSNS
+ return nil
+ when :opt_send_without_block, :send
+ if src = compile_send(insn, stack_size, sp_inc, local_stack_p, pos, next_pos, status, operands, body)
+ return src, next_pos, finish_p, compile_insns
+ end
+ when *send_compatible_opt_insns
+ if C.has_cache_for_send(captured_cc_entries(status)[call_data_index(C.CALL_DATA.new(operands[0]), body)], insn.bin) &&
+ src = compile_send(opt_send_without_block, stack_size, sp_inc, local_stack_p, pos, next_pos, status, operands, body)
+ return src, next_pos, finish_p, compile_insns
+ end
+ when :getinstancevariable, :setinstancevariable
+ if src = compile_ivar(insn.name, stack_size, pos, status, operands, body)
+ return src, next_pos, finish_p, compile_insns
+ end
+ when :opt_getconstant_path
+ if src = compile_getconstant_path(stack_size, pos, insn_len, operands, status)
+ return src, next_pos, finish_p, compile_insns
+ end
+ when :invokebuiltin, :opt_invokebuiltin_delegate, :opt_invokebuiltin_delegate_leave
+ if src = compile_invokebuiltin(insn, stack_size, sp_inc, body, operands)
+ if insn.name == :opt_invokebuiltin_delegate_leave
+ src << compile_leave(stack_size, pos, inlined_iseq_p)
+ finish_p = true
+ end
+ return src, next_pos, finish_p, compile_insns
+ end
+ when :leave
+ if stack_size != 1
+ raise "Unexpected JIT stack_size on leave: #{stack_size}"
+ end
+ src = compile_leave(stack_size, pos, inlined_iseq_p)
+ finish_p = true
+ return src, next_pos, finish_p, compile_insns
+ end
+
+ return compile_insn_default(insn, stack_size, sp_inc, local_stack_p, pos, next_pos, insn_len, inlined_iseq_p, operands)
+ end
+
+ # Optimized case of send / opt_send_without_block instructions.
+ def compile_send(insn, stack_size, sp_inc, local_stack_p, pos, next_pos, status, operands, body)
+ # compiler: Use captured cc to avoid race condition
+ cd = C.CALL_DATA.new(operands[0])
+ cd_index = call_data_index(cd, body)
+ captured_cc = captured_cc_entries(status)[cd_index]
+
+ # compiler: Inline send insn where some supported fastpath is used.
+ ci = cd.ci
+ kw_splat = (C.vm_ci_flag(ci) & C.VM_CALL_KW_SPLAT) > 0
+ if !status.compile_info.disable_send_cache && has_valid_method_type?(captured_cc) && (
+ # `CC_SET_FASTPATH(cd->cc, vm_call_cfunc_with_frame, ...)` in `vm_call_cfunc`
+ (vm_cc_cme(captured_cc).def.type == C.VM_METHOD_TYPE_CFUNC && !C.rb_splat_or_kwargs_p(ci) && !kw_splat) ||
+ # `CC_SET_FASTPATH(cc, vm_call_iseq_setup_func(...), vm_call_iseq_optimizable_p(...))` in `vm_callee_setup_arg`,
+ # and support only non-VM_CALL_TAILCALL path inside it
+ (vm_cc_cme(captured_cc).def.type == C.VM_METHOD_TYPE_ISEQ &&
+ C.fastpath_applied_iseq_p(ci, captured_cc, iseq = def_iseq_ptr(vm_cc_cme(captured_cc).def)) &&
+ (C.vm_ci_flag(ci) & C.VM_CALL_TAILCALL) == 0)
+ )
+ src = +"{\n"
+
+ # JIT: Invalidate call cache if it requires vm_search_method. This allows to inline some of following things.
+ src << " const struct rb_callcache *cc = (struct rb_callcache *)#{captured_cc};\n"
+ src << " const rb_callable_method_entry_t *cc_cme = (rb_callable_method_entry_t *)#{vm_cc_cme(captured_cc)};\n"
+ src << " const VALUE recv = stack[#{stack_size + sp_inc - 1}];\n"
+ # If opt_class_of is true, use RBASIC_CLASS instead of CLASS_OF to reduce code size
+ opt_class_of = !maybe_special_const?(captured_cc.klass)
+ src << " if (UNLIKELY(#{opt_class_of ? 'RB_SPECIAL_CONST_P(recv)' : 'false'} || !vm_cc_valid_p(cc, cc_cme, #{opt_class_of ? 'RBASIC_CLASS' : 'CLASS_OF'}(recv)))) {\n"
+ src << " reg_cfp->pc = original_body_iseq + #{pos};\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ src << " goto send_cancel;\n"
+ src << " }\n"
+
+ # JIT: move sp and pc if necessary
+ pc_moved_p = compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos)
+
+ # JIT: If ISeq is inlinable, call the inlined method without pushing a frame.
+ if iseq && status.inlined_iseqs && iseq.body.to_i == status.inlined_iseqs[pos]&.to_i
+ src << " {\n"
+ src << " VALUE orig_self = reg_cfp->self;\n"
+ src << " reg_cfp->self = stack[#{stack_size + sp_inc - 1}];\n"
+ src << " stack[#{stack_size + sp_inc - 1}] = _mjit#{status.compiled_id}_inlined_#{pos}(ec, reg_cfp, orig_self, original_iseq);\n"
+ src << " reg_cfp->self = orig_self;\n"
+ src << " }\n"
+ else
+ # JIT: Forked `vm_sendish` (except method_explorer = vm_search_method_wrap) to inline various things
+ src << " {\n"
+ src << " VALUE val;\n"
+ src << " struct rb_calling_info calling;\n"
+ if insn.name == :send
+ src << " calling.block_handler = vm_caller_setup_arg_block(ec, reg_cfp, (const struct rb_callinfo *)#{ci}, (rb_iseq_t *)0x#{operands[1].to_s(16)}, FALSE);\n"
+ else
+ src << " calling.block_handler = VM_BLOCK_HANDLER_NONE;\n"
+ end
+ src << " calling.kw_splat = #{kw_splat ? 1 : 0};\n"
+ src << " calling.recv = stack[#{stack_size + sp_inc - 1}];\n"
+ src << " calling.argc = #{C.vm_ci_argc(ci)};\n"
+
+ if vm_cc_cme(captured_cc).def.type == C.VM_METHOD_TYPE_CFUNC
+ # TODO: optimize this more
+ src << " calling.ci = (const struct rb_callinfo *)#{ci};\n" # creating local cd here because operand's cd->cc may not be the same as inlined cc.
+ src << " calling.cc = cc;"
+ src << " val = vm_call_cfunc_with_frame(ec, reg_cfp, &calling);\n"
+ else # :iseq
+ # fastpath_applied_iseq_p checks rb_simple_iseq_p, which ensures has_opt == FALSE
+ src << " vm_call_iseq_setup_normal(ec, reg_cfp, &calling, cc_cme, 0, #{iseq.body.param.size}, #{iseq.body.local_table_size});\n"
+ if iseq.body.catch_except_p
+ src << " VM_ENV_FLAGS_SET(ec->cfp->ep, VM_FRAME_FLAG_FINISH);\n"
+ src << " val = vm_exec(ec, true);\n"
+ else
+ src << " if ((val = jit_exec(ec)) == Qundef) {\n"
+ src << " VM_ENV_FLAGS_SET(ec->cfp->ep, VM_FRAME_FLAG_FINISH);\n" # This is vm_call0_body's code after vm_call_iseq_setup
+ src << " val = vm_exec(ec, false);\n"
+ src << " }\n"
+ end
+ end
+ src << " stack[#{stack_size + sp_inc - 1}] = val;\n"
+ src << " }\n"
+
+ # JIT: We should evaluate ISeq modified for TracePoint if it's enabled. Note: This is slow.
+ src << " if (UNLIKELY(!mjit_call_p)) {\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size + sp_inc};\n"
+ if !pc_moved_p
+ src << " reg_cfp->pc = original_body_iseq + #{next_pos};\n"
+ end
+ src << " goto cancel;\n"
+ src << " }\n"
+ end
+
+ src << "}\n"
+ return src
+ else
+ return nil
+ end
+ end
+
+ def compile_ivar(insn_name, stack_size, pos, status, operands, body)
+ iv_cache = C.iseq_inline_storage_entry.new(operands[1]).iv_cache
+ dest_shape_id = iv_cache.value >> C.SHAPE_FLAG_SHIFT
+ source_shape_id = parent_shape_id(dest_shape_id)
+ attr_index = iv_cache.value & ((1 << C.SHAPE_FLAG_SHIFT) - 1)
+
+ src = +''
+ if !status.compile_info.disable_ivar_cache && source_shape_id != C.INVALID_SHAPE_ID
+ # JIT: optimize away motion of sp and pc. This path does not call rb_warning() and so it's always leaf and not `handles_sp`.
+ # compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos)
+
+ # JIT: prepare vm_getivar/vm_setivar arguments and variables
+ src << "{\n"
+ src << " VALUE obj = GET_SELF();\n" # T_OBJECT guaranteed by compile_body
+ # JIT: cache hit path of vm_getivar/vm_setivar, or cancel JIT (recompile it with exivar)
+ if insn_name == :setinstancevariable
+ src << " const uint32_t index = #{attr_index - 1};\n"
+ src << " const shape_id_t dest_shape_id = (shape_id_t)#{dest_shape_id};\n"
+ src << " if (dest_shape_id == ROBJECT_SHAPE_ID(obj)) {\n"
+ src << " VALUE *ptr = ROBJECT_IVPTR(obj);\n"
+ src << " RB_OBJ_WRITE(obj, &ptr[index], stack[#{stack_size - 1}]);\n"
+ src << " }\n"
+ else
+ src << " const shape_id_t source_shape_id = (shape_id_t)#{dest_shape_id};\n"
+ if attr_index == 0 # cache hit, but uninitialized iv
+ src << " /* Uninitialized instance variable */\n"
+ src << " if (source_shape_id == ROBJECT_SHAPE_ID(obj)) {\n"
+ src << " stack[#{stack_size}] = Qnil;\n"
+ src << " }\n"
+ else
+ src << " const uint32_t index = #{attr_index - 1};\n"
+ src << " if (source_shape_id == ROBJECT_SHAPE_ID(obj)) {\n"
+ src << " stack[#{stack_size}] = ROBJECT_IVPTR(obj)[index];\n"
+ src << " }\n"
+ end
+ end
+ src << " else {\n"
+ src << " reg_cfp->pc = original_body_iseq + #{pos};\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ src << " goto ivar_cancel;\n"
+ src << " }\n"
+ src << "}\n"
+ return src
+ elsif insn_name == :getinstancevariable && !status.compile_info.disable_exivar_cache && source_shape_id != C.INVALID_SHAPE_ID
+ # JIT: optimize away motion of sp and pc. This path does not call rb_warning() and so it's always leaf and not `handles_sp`.
+ # compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos)
+
+ # JIT: prepare vm_getivar's arguments and variables
+ src << "{\n"
+ src << " VALUE obj = GET_SELF();\n"
+ src << " const shape_id_t source_shape_id = (shape_id_t)#{dest_shape_id};\n"
+ src << " const uint32_t index = #{attr_index - 1};\n"
+ # JIT: cache hit path of vm_getivar, or cancel JIT (recompile it without any ivar optimization)
+ src << " struct gen_ivtbl *ivtbl;\n"
+ src << " if (LIKELY(FL_TEST_RAW(GET_SELF(), FL_EXIVAR) && source_shape_id == rb_shape_get_shape_id(obj) && rb_ivar_generic_ivtbl_lookup(obj, &ivtbl))) {\n"
+ src << " stack[#{stack_size}] = ivtbl->ivptr[index];\n"
+ src << " }\n"
+ src << " else {\n"
+ src << " reg_cfp->pc = original_body_iseq + #{pos};\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ src << " goto exivar_cancel;\n"
+ src << " }\n"
+ src << "}\n"
+ return src
+ else
+ return nil
+ end
+ end
+
+ def compile_invokebuiltin(insn, stack_size, sp_inc, body, operands)
+ bf = C.RB_BUILTIN.new(operands[0])
+ if bf.compiler > 0
+ index = (insn.name == :invokebuiltin ? -1 : operands[1])
+ src = +"{\n"
+ src << " VALUE val;\n"
+ C.builtin_compiler(src, bf, index, stack_size, body.builtin_inline_p)
+ src << " stack[#{stack_size + sp_inc - 1}] = val;\n"
+ src << "}\n"
+ return src
+ else
+ return nil
+ end
+ end
+
+ def compile_leave(stack_size, pos, inlined_iseq_p)
+ src = +''
+ # Skip vm_pop_frame for inlined call
+ unless inlined_iseq_p
+ # Cancel on interrupts to make leave insn leaf
+ src << " if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(ec))) {\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ src << " reg_cfp->pc = original_body_iseq + #{pos};\n"
+ src << " rb_threadptr_execute_interrupts(rb_ec_thread_ptr(ec), 0);\n"
+ src << " }\n"
+ src << " ec->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(reg_cfp);\n" # vm_pop_frame
+ end
+ src << " return stack[0];\n"
+ end
+
+ def compile_getconstant_path(stack_size, pos, insn_len, operands, status)
+ ice = C.IC.new(operands[0]).entry
+ if !status.compile_info.disable_const_cache && ice
+ # JIT: Inline everything in IC, and cancel the slow path
+ src = +" if (vm_inlined_ic_hit_p(#{ice.flags}, #{ice.value}, (const rb_cref_t *)#{to_addr(ice.ic_cref)}, reg_cfp->ep)) {\n"
+ src << " stack[#{stack_size}] = #{ice.value};\n"
+ src << " }\n"
+ src << " else {\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ src << " reg_cfp->pc = original_body_iseq + #{pos};\n"
+ src << " goto const_cancel;\n"
+ src << " }\n"
+ return src
+ else
+ return nil
+ end
+ end
+
+ def compile_insn_default(insn, stack_size, sp_inc, local_stack_p, pos, next_pos, insn_len, inlined_iseq_p, operands)
+ src = +''
+ finish_p = false
+ compile_insns = false
+
+ # JIT: Declare stack_size to be used in some macro of _mjit_compile_insn_body.erb
+ src << "{\n"
+ if local_stack_p
+ src << " MAYBE_UNUSED(unsigned int) stack_size = #{stack_size};\n"
+ end
+
+ # JIT: Declare variables for operands, popped values and return values
+ insn.declarations.each do |decl|
+ src << " #{decl};\n"
+ end
+
+ # JIT: Set const expressions for `RubyVM::OperandsUnifications` insn
+ insn.preamble.each do |amble|
+ src << "#{amble.sub(/const \S+\s+/, '')}\n"
+ end
+
+ # JIT: Initialize operands
+ insn.opes.each_with_index do |ope, i|
+ src << " #{ope.fetch(:name)} = (#{ope.fetch(:type)})#{operands[i]};\n"
+ # TODO: resurrect comment_id
+ end
+
+ # JIT: Initialize popped values
+ insn.pops.reverse_each.with_index.reverse_each do |pop, i|
+ src << " #{pop.fetch(:name)} = stack[#{stack_size - (i + 1)}];\n"
+ end
+
+ # JIT: move sp and pc if necessary
+ pc_moved_p = compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos)
+
+ # JIT: Print insn body in insns.def
+ next_pos = compile_insn_body(src, insn, pos, next_pos, insn_len, local_stack_p, stack_size, sp_inc, operands)
+
+ # JIT: Set return values
+ insn.rets.reverse_each.with_index do |ret, i|
+ # TOPN(n) = ...
+ src << " stack[#{stack_size + sp_inc - (i + 1)}] = #{ret.fetch(:name)};\n"
+ end
+
+ # JIT: We should evaluate ISeq modified for TracePoint if it's enabled. Note: This is slow.
+ # leaf insn may not cancel JIT. leaf_without_check_ints is covered in RUBY_VM_CHECK_INTS of _mjit_compile_insn_body.erb.
+ unless insn.always_leaf? || insn.leaf_without_check_ints?
+ src << " if (UNLIKELY(!mjit_call_p)) {\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size + sp_inc};\n"
+ if !pc_moved_p
+ src << " reg_cfp->pc = original_body_iseq + #{next_pos};\n"
+ end
+ src << " goto cancel;\n"
+ src << " }\n"
+ end
+
+ src << "}\n"
+
+ # compiler: If insn has conditional JUMP, the code should go to the branch not targeted by JUMP next.
+ if insn.expr.match?(/if\s+\([^{}]+\)\s+\{[^{}]+JUMP\([^)]+\);[^{}]+\}/)
+ compile_insns = true
+ end
+
+ # compiler: If insn returns (leave) or does longjmp (throw), the branch should no longer be compiled. TODO: create attr for it?
+ if insn.expr.match?(/\sTHROW_EXCEPTION\([^)]+\);/) || insn.expr.match?(/\bvm_pop_frame\(/)
+ finish_p = true
+ end
+
+ return src, next_pos, finish_p, compile_insns
+ end
+
+ def compile_insn_body(src, insn, pos, next_pos, insn_len, local_stack_p, stack_size, sp_inc, operands)
+ # Print a body of insn, but with macro expansion.
+ expand_simple_macros(insn.expr).each_line do |line|
+ # Expand dynamic macro here
+ # TODO: support combination of following macros in the same line
+ case line
+ when /\A\s+RUBY_VM_CHECK_INTS\(ec\);\s+\z/
+ if insn.leaf_without_check_ints? # lazily move PC and optionalize mjit_call_p here
+ src << " if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(ec))) {\n"
+ src << " reg_cfp->pc = original_body_iseq + #{next_pos};\n" # ADD_PC(INSN_ATTR(width));
+ src << " rb_threadptr_execute_interrupts(rb_ec_thread_ptr(ec), 0);\n"
+ src << " if (UNLIKELY(!mjit_call_p)) {\n"
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ src << " goto cancel;\n"
+ src << " }\n"
+ src << " }\n"
+ else
+ src << to_cstr(line)
+ end
+ when /\A\s+JUMP\((?<dest>[^)]+)\);\s+\z/
+ dest = Regexp.last_match[:dest]
+ if insn.name == :opt_case_dispatch # special case... TODO: use another macro to avoid checking name
+ hash_offsets = C.rb_hash_values(operands[0]).uniq
+ else_offset = cast_offset(operands[1])
+ base_pos = pos + insn_len
+
+ src << " switch (#{dest}) {\n"
+ hash_offsets.each do |offset|
+ src << " case #{offset}:\n"
+ src << " goto label_#{base_pos + offset};\n"
+ end
+ src << " case #{else_offset}:\n"
+ src << " goto label_#{base_pos + else_offset};\n"
+ src << " }\n"
+ else
+ # Before we `goto` next insn, we need to set return values, especially for getinlinecache
+ insn.rets.reverse_each.with_index do |ret, i|
+ # TOPN(n) = ...
+ src << " stack[#{stack_size + sp_inc - (i + 1)}] = #{ret.fetch(:name)};\n"
+ end
+
+ next_pos = pos + insn_len + cast_offset(operands[0]) # workaround: assuming dest == operands[0]. TODO: avoid relying on it
+ src << " goto label_#{next_pos};\n"
+ end
+ when /\A\s+CALL_SIMPLE_METHOD\(\);\s+\z/
+ # For `opt_xxx`'s fallbacks.
+ if local_stack_p
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ end
+ src << " reg_cfp->pc = original_body_iseq + #{pos};\n"
+ src << " goto cancel;\n"
+ when /\A(?<prefix>.+\b)INSN_LABEL\((?<name>[^)]+)\)(?<suffix>.+)\z/m
+ prefix, name, suffix = Regexp.last_match[:prefix], Regexp.last_match[:name], Regexp.last_match[:suffix]
+ src << "#{prefix}INSN_LABEL(#{name}_#{pos})#{suffix}"
+ else
+ if insn.handles_sp?
+ # If insn.handles_sp? is true, cfp->sp might be changed inside insns (like vm_caller_setup_arg_block)
+ # and thus we need to use cfp->sp, even when local_stack_p is TRUE. When insn.handles_sp? is true,
+ # cfp->sp should be available too because _mjit_compile_pc_and_sp.erb sets it.
+ src << to_cstr(line)
+ else
+ # If local_stack_p is TRUE and insn.handles_sp? is false, stack values are only available in local variables
+ # for stack. So we need to replace those macros if local_stack_p is TRUE here.
+ case line
+ when /\bGET_SP\(\)/
+ # reg_cfp->sp
+ src << to_cstr(line.sub(/\bGET_SP\(\)/, local_stack_p ? '(stack + stack_size)' : 'GET_SP()'))
+ when /\bSTACK_ADDR_FROM_TOP\((?<num>[^)]+)\)/
+ # #define STACK_ADDR_FROM_TOP(n) (GET_SP()-(n))
+ num = Regexp.last_match[:num]
+ src << to_cstr(line.sub(/\bSTACK_ADDR_FROM_TOP\(([^)]+)\)/, local_stack_p ? "(stack + (stack_size - (#{num})))" : "STACK_ADDR_FROM_TOP(#{num})"))
+ when /\bTOPN\((?<num>[^)]+)\)/
+ # #define TOPN(n) (*(GET_SP()-(n)-1))
+ num = Regexp.last_match[:num]
+ src << to_cstr(line.sub(/\bTOPN\(([^)]+)\)/, local_stack_p ? "*(stack + (stack_size - (#{num}) - 1))" : "TOPN(#{num})"))
+ else
+ src << to_cstr(line)
+ end
+ end
+ end
+ end
+ return next_pos
+ end
+
+ def compile_pc_and_sp(src, insn, stack_size, sp_inc, local_stack_p, next_pos)
+ # JIT: When an insn is leaf, we don't need to Move pc for a catch table on catch_except_p, #caller_locations,
+ # and rb_profile_frames. For check_ints, we lazily move PC when we have interruptions.
+ pc_moved_p = false
+ unless insn.always_leaf? || insn.leaf_without_check_ints?
+ src << " reg_cfp->pc = original_body_iseq + #{next_pos};\n" # ADD_PC(INSN_ATTR(width));
+ pc_moved_p = true
+ end
+
+ # JIT: move sp to use or preserve stack variables
+ if local_stack_p
+ # sp motion is optimized away for `handles_sp? #=> false` case.
+ # Thus sp should be set properly before `goto cancel`.
+ if insn.handles_sp?
+ # JIT-only behavior (pushing JIT's local variables to VM's stack):
+ push_size = -sp_inc + insn.rets.size - insn.pops.size
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{push_size};\n"
+ push_size.times do |i|
+ src << " *(reg_cfp->sp + #{i - push_size}) = stack[#{stack_size - push_size + i}];\n"
+ end
+ end
+ else
+ if insn.handles_sp?
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size - insn.pops.size};\n" # POPN(INSN_ATTR(popn));
+ else
+ src << " reg_cfp->sp = vm_base_ptr(reg_cfp) + #{stack_size};\n"
+ end
+ end
+ return pc_moved_p
+ end
+
+ # Print the block to cancel inlined method call. It's supporting only `opt_send_without_block` for now.
+ def compile_inlined_cancel_handler(src, body, inline_context)
+ src << "\ncancel:\n"
+ src << " rb_mjit_recompile_inlining(original_iseq);\n"
+
+ # Swap pc/sp set on cancel with original pc/sp.
+ src << " const VALUE *current_pc = reg_cfp->pc;\n"
+ src << " VALUE *current_sp = reg_cfp->sp;\n"
+ src << " reg_cfp->pc = orig_pc;\n"
+ src << " reg_cfp->sp = orig_sp;\n\n"
+
+ # Lazily push the current call frame.
+ src << " struct rb_calling_info calling;\n"
+ src << " calling.block_handler = VM_BLOCK_HANDLER_NONE;\n" # assumes `opt_send_without_block`
+ src << " calling.argc = #{inline_context.orig_argc};\n"
+ src << " calling.recv = reg_cfp->self;\n"
+ src << " reg_cfp->self = orig_self;\n"
+ # fastpath_applied_iseq_p checks rb_simple_iseq_p, which ensures has_opt == FALSE
+ src << " vm_call_iseq_setup_normal(ec, reg_cfp, &calling, (const rb_callable_method_entry_t *)#{inline_context.me}, 0, #{inline_context.param_size}, #{inline_context.local_size});\n\n"
+
+ # Start usual cancel from here.
+ src << " reg_cfp = ec->cfp;\n" # work on the new frame
+ src << " reg_cfp->pc = current_pc;\n"
+ src << " reg_cfp->sp = current_sp;\n"
+ (0...body.stack_max).each do |i| # should be always `status->local_stack_p`
+ src << " *(vm_base_ptr(reg_cfp) + #{i}) = stack[#{i}];\n"
+ end
+ # We're not just returning Qundef here so that caller's normal cancel handler can
+ # push back `stack` to `cfp->sp`.
+ src << " return vm_exec(ec, false);\n"
+ end
+
+ # Print the block to cancel JIT execution.
+ def compile_cancel_handler(src, body, status)
+ if status.inlined_iseqs.nil? # the current ISeq is being inlined
+ compile_inlined_cancel_handler(src, body, status.inline_context)
+ return
+ end
+
+ src << "\nsend_cancel:\n"
+ src << " rb_mjit_recompile_send(original_iseq);\n"
+ src << " goto cancel;\n"
+
+ src << "\nivar_cancel:\n"
+ src << " rb_mjit_recompile_ivar(original_iseq);\n"
+ src << " goto cancel;\n"
+
+ src << "\nexivar_cancel:\n"
+ src << " rb_mjit_recompile_exivar(original_iseq);\n"
+ src << " goto cancel;\n"
+
+ src << "\nconst_cancel:\n"
+ src << " rb_mjit_recompile_const(original_iseq);\n"
+ src << " goto cancel;\n"
+
+ src << "\ncancel:\n"
+ if status.local_stack_p
+ (0...body.stack_max).each do |i|
+ src << " *(vm_base_ptr(reg_cfp) + #{i}) = stack[#{i}];\n"
+ end
+ end
+ src << " return Qundef;\n"
+ end
+
+ def precompile_inlinable_child_iseq(src, child_iseq, status, ci, cc, pos)
+ child_status = C.compile_status.new # not freed for now
+ child_status.compiled_iseq = status.compiled_iseq
+ child_status.compiled_id = status.compiled_id
+ init_compile_status(child_status, child_iseq.body, false) # not freed for now
+ child_status.inline_context.orig_argc = C.vm_ci_argc(ci)
+ child_status.inline_context.me = vm_cc_cme(cc).to_i
+ child_status.inline_context.param_size = child_iseq.body.param.size
+ child_status.inline_context.local_size = child_iseq.body.local_table_size
+ if child_iseq.body.ci_size > 0 && child_status.cc_entries_index == -1
+ return false
+ end
+
+ src << "ALWAYS_INLINE(static VALUE _mjit#{status.compiled_id}_inlined_#{pos}(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, const VALUE orig_self, const rb_iseq_t *original_iseq));\n"
+ src << "static inline VALUE\n_mjit#{status.compiled_id}_inlined_#{pos}(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, const VALUE orig_self, const rb_iseq_t *original_iseq)\n{\n"
+ src << " const VALUE *orig_pc = reg_cfp->pc;\n"
+ src << " VALUE *orig_sp = reg_cfp->sp;\n"
+
+ success = compile_body(src, child_iseq, child_status)
+
+ src << "\n} /* end of _mjit#{status.compiled_id}_inlined_#{pos} */\n\n"
+
+ return success;
+ end
+
+ def precompile_inlinable_iseqs(src, iseq, status)
+ body = iseq.body
+ pos = 0
+ while pos < body.iseq_size
+ insn = INSNS.fetch(C.rb_vm_insn_decode(body.iseq_encoded[pos]))
+ if insn.name == :opt_send_without_block || insn.name == :opt_size # `compile_inlined_cancel_handler` supports only `opt_send_without_block`
+ cd = C.CALL_DATA.new(body.iseq_encoded[pos + 1])
+ ci = cd.ci
+ cc = captured_cc_entries(status)[call_data_index(cd, body)] # use copy to avoid race condition
+
+ if (child_iseq = rb_mjit_inlinable_iseq(ci, cc)) != nil
+ status.inlined_iseqs[pos] = child_iseq.body
+
+ if C.mjit_opts.verbose >= 1 # print beforehand because ISeq may be GCed during copy job.
+ child_location = child_iseq.body.location
+ $stderr.puts "JIT inline: #{child_location.label}@#{C.rb_iseq_path(child_iseq)}:#{C.rb_iseq_first_lineno(child_iseq)} " \
+ "=> #{iseq.body.location.label}@#{C.rb_iseq_path(iseq)}:#{C.rb_iseq_first_lineno(iseq)}"
+ end
+ if !precompile_inlinable_child_iseq(src, child_iseq, status, ci, cc, pos)
+ return false
+ end
+ end
+ end
+ pos += insn.len
+ end
+ return true
+ end
+
+ def init_compile_status(status, body, compile_root_p)
+ status.stack_size_for_pos = Fiddle.malloc(Fiddle::SIZEOF_INT * body.iseq_size)
+ body.iseq_size.times do |i|
+ status.stack_size_for_pos[i] = C.NOT_COMPILED_STACK_SIZE
+ end
+ if compile_root_p
+ status.inlined_iseqs = Fiddle.malloc(Fiddle::SIZEOF_VOIDP * body.iseq_size)
+ body.iseq_size.times do |i|
+ status.inlined_iseqs[i] = nil
+ end
+ end
+ if body.ci_size > 0
+ status.cc_entries_index = C.mjit_capture_cc_entries(status.compiled_iseq, body)
+ else
+ status.cc_entries_index = -1
+ end
+ if compile_root_p
+ status.compile_info = rb_mjit_iseq_compile_info(body)
+ else
+ status.compile_info = Fiddle.malloc(C.rb_mjit_compile_info.sizeof)
+ status.compile_info.disable_ivar_cache = false
+ status.compile_info.disable_exivar_cache = false
+ status.compile_info.disable_send_cache = false
+ status.compile_info.disable_inlining = false
+ status.compile_info.disable_const_cache = false
+ end
+ end
+
+ def using_ivar?(body)
+ pos = 0
+ while pos < body.iseq_size
+ insn = INSNS.fetch(C.rb_vm_insn_decode(body.iseq_encoded[pos]))
+ case insn.name
+ when :getinstancevariable, :setinstancevariable
+ return true
+ end
+ pos += insn.len
+ end
+ return false
+ end
+
+ # Expand simple macro that doesn't require dynamic C code.
+ def expand_simple_macros(arg_expr)
+ arg_expr.dup.tap do |expr|
+ # For `leave`. We can't proceed next ISeq in the same JIT function.
+ expr.gsub!(/^(?<indent>\s*)RESTORE_REGS\(\);\n/) do
+ indent = Regexp.last_match[:indent]
+ <<-end.gsub(/^ {12}/, '')
+ #if OPT_CALL_THREADED_CODE
+ #{indent}rb_ec_thread_ptr(ec)->retval = val;
+ #{indent}return 0;
+ #else
+ #{indent}return val;
+ #endif
+ end
+ end
+ expr.gsub!(/^(?<indent>\s*)NEXT_INSN\(\);\n/) do
+ indent = Regexp.last_match[:indent]
+ <<-end.gsub(/^ {12}/, '')
+ #{indent}UNREACHABLE_RETURN(Qundef);
+ end
+ end
+ end
+ end
+
+ def to_cstr(expr)
+ expr.gsub(/^(?!#)/, ' ') # indent everything but preprocessor lines
+ end
+
+ # Interpret unsigned long as signed long (VALUE -> OFFSET)
+ def cast_offset(offset)
+ if offset >= 1 << 8 * Fiddle::SIZEOF_VOIDP - 1 # negative
+ offset -= 1 << 8 * Fiddle::SIZEOF_VOIDP
+ end
+ offset
+ end
+
+ def captured_cc_entries(status)
+ status.compiled_iseq.mjit_unit.cc_entries + status.cc_entries_index
+ end
+
+ def call_data_index(cd, body)
+ cd - body.call_data
+ end
+
+ def vm_cc_cme(cc)
+ # TODO: add VM_ASSERT like actual vm_cc_cme
+ cc.cme_
+ end
+
+ def def_iseq_ptr(method_def)
+ C.rb_iseq_check(method_def.body.iseq.iseqptr)
+ end
+
+ def rb_mjit_iseq_compile_info(body)
+ body.mjit_unit.compile_info
+ end
+
+ def ISEQ_IS_SIZE(body)
+ body.ic_size + body.ivc_size + body.ise_size + body.icvarc_size
+ end
+
+ # Return true if an object of the class may be a special const (immediate).
+ # It's "maybe" because Integer and Float are not guaranteed to be an immediate.
+ # If this returns false, rb_class_of could be optimzied to RBASIC_CLASS.
+ def maybe_special_const?(klass)
+ [
+ C.rb_cFalseClass,
+ C.rb_cNilClass,
+ C.rb_cTrueClass,
+ C.rb_cInteger,
+ C.rb_cSymbol,
+ C.rb_cFloat,
+ ].include?(klass)
+ end
+
+ def has_valid_method_type?(cc)
+ vm_cc_cme(cc) != nil
+ end
+
+ def already_compiled?(status, pos)
+ status.stack_size_for_pos[pos] != C.NOT_COMPILED_STACK_SIZE
+ end
+
+ # Return an iseq pointer if cc has inlinable iseq.
+ def rb_mjit_inlinable_iseq(ci, cc)
+ if has_valid_method_type?(cc) &&
+ C.vm_ci_flag(ci) & C.VM_CALL_TAILCALL == 0 && # inlining only non-tailcall path
+ vm_cc_cme(cc).def.type == C.VM_METHOD_TYPE_ISEQ &&
+ C.fastpath_applied_iseq_p(ci, cc, iseq = def_iseq_ptr(vm_cc_cme(cc).def)) &&
+ inlinable_iseq_p(iseq.body) # CC_SET_FASTPATH in vm_callee_setup_arg
+ return iseq
+ end
+ return nil
+ end
+
+ # Return true if the ISeq can be inlined without pushing a new control frame.
+ def inlinable_iseq_p(body)
+ # 1) If catch_except_p, caller frame should be preserved when callee catches an exception.
+ # Then we need to wrap `vm_exec()` but then we can't inline the call inside it.
+ #
+ # 2) If `body->catch_except_p` is false and `handles_sp?` of an insn is false,
+ # sp is not moved as we assume `status->local_stack_p = !body->catch_except_p`.
+ #
+ # 3) If `body->catch_except_p` is false and `always_leaf?` of an insn is true,
+ # pc is not moved.
+ if body.catch_except_p
+ return false
+ end
+
+ pos = 0
+ while pos < body.iseq_size
+ insn = INSNS.fetch(C.rb_vm_insn_decode(body.iseq_encoded[pos]))
+ # All insns in the ISeq except `leave` (to be overridden in the inlined code)
+ # should meet following strong assumptions:
+ # * Do not require `cfp->sp` motion
+ # * Do not move `cfp->pc`
+ # * Do not read any `cfp->pc`
+ if insn.name == :invokebuiltin || insn.name == :opt_invokebuiltin_delegate || insn.name == :opt_invokebuiltin_delegate_leave
+ # builtin insn's inlinability is handled by `Primitive.attr! 'inline'` per iseq
+ if !body.builtin_inline_p
+ return false;
+ end
+ elsif insn.name != :leave && C.insn_may_depend_on_sp_or_pc(insn.bin, body.iseq_encoded + (pos + 1))
+ return false
+ end
+ # At this moment, `cfp->ep` in an inlined method is not working.
+ case insn.name
+ when :getlocal,
+ :getlocal_WC_0,
+ :getlocal_WC_1,
+ :setlocal,
+ :setlocal_WC_0,
+ :setlocal_WC_1,
+ :getblockparam,
+ :getblockparamproxy,
+ :setblockparam
+ return false
+ end
+ pos += insn.len
+ end
+ return true
+ end
+
+ # CPointer::Struct could be nil on field reference, and this is a helper to
+ # handle that case while using CPointer::Struct#to_s in most cases.
+ # @param struct [RubyVM::MJIT::CPointer::Struct]
+ def to_addr(struct)
+ struct&.to_s || 'NULL'
+ end
+
+ def parent_shape_id(shape_id)
+ return shape_id if shape_id == C.INVALID_SHAPE_ID
+
+ parent_id = C.rb_shape_get_shape_by_id(shape_id).parent_id
+ parent = C.rb_shape_get_shape_by_id(parent_id)
+
+ if parent.type == C.SHAPE_CAPACITY_CHANGE
+ parent.parent_id
+ else
+ parent_id
+ end
+ end
+end
diff --git a/lib/ruby_vm/mjit/hooks.rb b/lib/ruby_vm/mjit/hooks.rb
new file mode 100644
index 0000000000..3fb1004111
--- /dev/null
+++ b/lib/ruby_vm/mjit/hooks.rb
@@ -0,0 +1,32 @@
+module RubyVM::MJIT::Hooks # :nodoc: all
+ C = RubyVM::MJIT.const_get(:C, false)
+
+ def self.on_bop_redefined(_redefined_flag, _bop)
+ C.mjit_cancel_all("BOP is redefined")
+ end
+
+ def self.on_cme_invalidate(_cme)
+ # to be used later
+ end
+
+ def self.on_ractor_spawn
+ C.mjit_cancel_all("Ractor is spawned")
+ end
+
+ def self.on_constant_state_changed(_id)
+ # to be used later
+ end
+
+ def self.on_constant_ic_update(_iseq, _ic, _insn_idx)
+ # to be used later
+ end
+
+ def self.on_tracing_invalidate_all(new_iseq_events)
+ # Stop calling all JIT-ed code. We can't rewrite existing JIT-ed code to trace_ insns for now.
+ # :class events are triggered only in ISEQ_TYPE_CLASS, but mjit_target_iseq_p ignores such iseqs.
+ # Thus we don't need to cancel JIT-ed code for :class events.
+ if new_iseq_events != C.RUBY_EVENT_CLASS
+ C.mjit_cancel_all("TracePoint is enabled")
+ end
+ end
+end
diff --git a/lib/ruby_vm/rjit/.document b/lib/ruby_vm/rjit/.document
deleted file mode 100644
index 0a603afe3d..0000000000
--- a/lib/ruby_vm/rjit/.document
+++ /dev/null
@@ -1 +0,0 @@
-stats.rb
diff --git a/lib/ruby_vm/rjit/assembler.rb b/lib/ruby_vm/rjit/assembler.rb
deleted file mode 100644
index 42995e6c8c..0000000000
--- a/lib/ruby_vm/rjit/assembler.rb
+++ /dev/null
@@ -1,1160 +0,0 @@
-# frozen_string_literal: true
-module RubyVM::RJIT
- # 8-bit memory access
- class BytePtr < Data.define(:reg, :disp); end
-
- # 32-bit memory access
- class DwordPtr < Data.define(:reg, :disp); end
-
- # 64-bit memory access
- QwordPtr = Array
-
- # SystemV x64 calling convention
- C_ARGS = [:rdi, :rsi, :rdx, :rcx, :r8, :r9]
- C_RET = :rax
-
- # https://cdrdv2.intel.com/v1/dl/getContent/671110
- # Mostly an x86_64 assembler, but this also has some stuff that is useful for any architecture.
- class Assembler
- # rel8 jumps are made with labels
- class Label < Data.define(:id, :name); end
-
- # rel32 is inserted as [Rel32, Rel32Pad..] and converted on #resolve_rel32
- class Rel32 < Data.define(:addr); end
- Rel32Pad = Object.new
-
- # A set of ModR/M values encoded on #insn
- class ModRM < Data.define(:mod, :reg, :rm); end
- Mod00 = 0b00 # Mod 00: [reg]
- Mod01 = 0b01 # Mod 01: [reg]+disp8
- Mod10 = 0b10 # Mod 10: [reg]+disp32
- Mod11 = 0b11 # Mod 11: reg
-
- # REX = 0100WR0B
- REX_B = 0b01000001
- REX_R = 0b01000100
- REX_W = 0b01001000
-
- # Operand matchers
- R32 = -> (op) { op.is_a?(Symbol) && r32?(op) }
- R64 = -> (op) { op.is_a?(Symbol) && r64?(op) }
- IMM8 = -> (op) { op.is_a?(Integer) && imm8?(op) }
- IMM32 = -> (op) { op.is_a?(Integer) && imm32?(op) }
- IMM64 = -> (op) { op.is_a?(Integer) && imm64?(op) }
-
- def initialize
- @bytes = []
- @labels = {}
- @label_id = 0
- @comments = Hash.new { |h, k| h[k] = [] }
- @blocks = Hash.new { |h, k| h[k] = [] }
- @stub_starts = Hash.new { |h, k| h[k] = [] }
- @stub_ends = Hash.new { |h, k| h[k] = [] }
- @pos_markers = Hash.new { |h, k| h[k] = [] }
- end
-
- def assemble(addr)
- set_code_addrs(addr)
- resolve_rel32(addr)
- resolve_labels
-
- write_bytes(addr)
-
- @pos_markers.each do |write_pos, markers|
- markers.each { |marker| marker.call(addr + write_pos) }
- end
- @bytes.size
- ensure
- @bytes.clear
- end
-
- def size
- @bytes.size
- end
-
- #
- # Instructions
- #
-
- def add(dst, src)
- case [dst, src]
- # ADD r/m64, imm8 (Mod 00: [reg])
- in [QwordPtr[R64 => dst_reg], IMM8 => src_imm]
- # REX.W + 83 /0 ib
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod00, reg: 0, rm: dst_reg],
- imm: imm8(src_imm),
- )
- # ADD r/m64, imm8 (Mod 11: reg)
- in [R64 => dst_reg, IMM8 => src_imm]
- # REX.W + 83 /0 ib
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod11, reg: 0, rm: dst_reg],
- imm: imm8(src_imm),
- )
- # ADD r/m64 imm32 (Mod 11: reg)
- in [R64 => dst_reg, IMM32 => src_imm]
- # REX.W + 81 /0 id
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x81,
- mod_rm: ModRM[mod: Mod11, reg: 0, rm: dst_reg],
- imm: imm32(src_imm),
- )
- # ADD r/m64, r64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 01 /r
- # MR: Operand 1: ModRM:r/m (r, w), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x01,
- mod_rm: ModRM[mod: Mod11, reg: src_reg, rm: dst_reg],
- )
- end
- end
-
- def and(dst, src)
- case [dst, src]
- # AND r/m64, imm8 (Mod 11: reg)
- in [R64 => dst_reg, IMM8 => src_imm]
- # REX.W + 83 /4 ib
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod11, reg: 4, rm: dst_reg],
- imm: imm8(src_imm),
- )
- # AND r/m64, imm32 (Mod 11: reg)
- in [R64 => dst_reg, IMM32 => src_imm]
- # REX.W + 81 /4 id
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x81,
- mod_rm: ModRM[mod: Mod11, reg: 4, rm: dst_reg],
- imm: imm32(src_imm),
- )
- # AND r64, r/m64 (Mod 01: [reg]+disp8)
- in [R64 => dst_reg, QwordPtr[R64 => src_reg, IMM8 => src_disp]]
- # REX.W + 23 /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x23,
- mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
- disp: imm8(src_disp),
- )
- # AND r64, r/m64 (Mod 10: [reg]+disp32)
- in [R64 => dst_reg, QwordPtr[R64 => src_reg, IMM32 => src_disp]]
- # REX.W + 23 /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x23,
- mod_rm: ModRM[mod: Mod10, reg: dst_reg, rm: src_reg],
- disp: imm32(src_disp),
- )
- end
- end
-
- def call(dst)
- case dst
- # CALL rel32
- in Integer => dst_addr
- # E8 cd
- # D: Operand 1: Offset
- insn(opcode: 0xe8, imm: rel32(dst_addr))
- # CALL r/m64 (Mod 11: reg)
- in R64 => dst_reg
- # FF /2
- # M: Operand 1: ModRM:r/m (r)
- insn(
- opcode: 0xff,
- mod_rm: ModRM[mod: Mod11, reg: 2, rm: dst_reg],
- )
- end
- end
-
- def cmove(dst, src)
- case [dst, src]
- # CMOVE r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 44 /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x44],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovg(dst, src)
- case [dst, src]
- # CMOVG r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 4F /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x4f],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovge(dst, src)
- case [dst, src]
- # CMOVGE r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 4D /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x4d],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovl(dst, src)
- case [dst, src]
- # CMOVL r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 4C /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x4c],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovle(dst, src)
- case [dst, src]
- # CMOVLE r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 4E /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x4e],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovne(dst, src)
- case [dst, src]
- # CMOVNE r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 45 /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x45],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovnz(dst, src)
- case [dst, src]
- # CMOVNZ r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 45 /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x45],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- end
- end
-
- def cmovz(dst, src)
- case [dst, src]
- # CMOVZ r64, r/m64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 0F 44 /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x44],
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- # CMOVZ r64, r/m64 (Mod 01: [reg]+disp8)
- in [R64 => dst_reg, QwordPtr[R64 => src_reg, IMM8 => src_disp]]
- # REX.W + 0F 44 /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: [0x0f, 0x44],
- mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
- disp: imm8(src_disp),
- )
- end
- end
-
- def cmp(left, right)
- case [left, right]
- # CMP r/m8, imm8 (Mod 01: [reg]+disp8)
- in [BytePtr[R64 => left_reg, IMM8 => left_disp], IMM8 => right_imm]
- # 80 /7 ib
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- opcode: 0x80,
- mod_rm: ModRM[mod: Mod01, reg: 7, rm: left_reg],
- disp: left_disp,
- imm: imm8(right_imm),
- )
- # CMP r/m32, imm32 (Mod 01: [reg]+disp8)
- in [DwordPtr[R64 => left_reg, IMM8 => left_disp], IMM32 => right_imm]
- # 81 /7 id
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- opcode: 0x81,
- mod_rm: ModRM[mod: Mod01, reg: 7, rm: left_reg],
- disp: left_disp,
- imm: imm32(right_imm),
- )
- # CMP r/m64, imm8 (Mod 01: [reg]+disp8)
- in [QwordPtr[R64 => left_reg, IMM8 => left_disp], IMM8 => right_imm]
- # REX.W + 83 /7 ib
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod01, reg: 7, rm: left_reg],
- disp: left_disp,
- imm: imm8(right_imm),
- )
- # CMP r/m64, imm32 (Mod 01: [reg]+disp8)
- in [QwordPtr[R64 => left_reg, IMM8 => left_disp], IMM32 => right_imm]
- # REX.W + 81 /7 id
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x81,
- mod_rm: ModRM[mod: Mod01, reg: 7, rm: left_reg],
- disp: left_disp,
- imm: imm32(right_imm),
- )
- # CMP r/m64, imm8 (Mod 10: [reg]+disp32)
- in [QwordPtr[R64 => left_reg, IMM32 => left_disp], IMM8 => right_imm]
- # REX.W + 83 /7 ib
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod10, reg: 7, rm: left_reg],
- disp: imm32(left_disp),
- imm: imm8(right_imm),
- )
- # CMP r/m64, imm8 (Mod 11: reg)
- in [R64 => left_reg, IMM8 => right_imm]
- # REX.W + 83 /7 ib
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod11, reg: 7, rm: left_reg],
- imm: imm8(right_imm),
- )
- # CMP r/m64, imm32 (Mod 11: reg)
- in [R64 => left_reg, IMM32 => right_imm]
- # REX.W + 81 /7 id
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x81,
- mod_rm: ModRM[mod: Mod11, reg: 7, rm: left_reg],
- imm: imm32(right_imm),
- )
- # CMP r/m64, r64 (Mod 01: [reg]+disp8)
- in [QwordPtr[R64 => left_reg, IMM8 => left_disp], R64 => right_reg]
- # REX.W + 39 /r
- # MR: Operand 1: ModRM:r/m (r), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x39,
- mod_rm: ModRM[mod: Mod01, reg: right_reg, rm: left_reg],
- disp: left_disp,
- )
- # CMP r/m64, r64 (Mod 10: [reg]+disp32)
- in [QwordPtr[R64 => left_reg, IMM32 => left_disp], R64 => right_reg]
- # REX.W + 39 /r
- # MR: Operand 1: ModRM:r/m (r), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x39,
- mod_rm: ModRM[mod: Mod10, reg: right_reg, rm: left_reg],
- disp: imm32(left_disp),
- )
- # CMP r/m64, r64 (Mod 11: reg)
- in [R64 => left_reg, R64 => right_reg]
- # REX.W + 39 /r
- # MR: Operand 1: ModRM:r/m (r), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x39,
- mod_rm: ModRM[mod: Mod11, reg: right_reg, rm: left_reg],
- )
- end
- end
-
- def jbe(dst)
- case dst
- # JBE rel8
- in Label => dst_label
- # 76 cb
- insn(opcode: 0x76, imm: dst_label)
- # JBE rel32
- in Integer => dst_addr
- # 0F 86 cd
- insn(opcode: [0x0f, 0x86], imm: rel32(dst_addr))
- end
- end
-
- def je(dst)
- case dst
- # JE rel8
- in Label => dst_label
- # 74 cb
- insn(opcode: 0x74, imm: dst_label)
- # JE rel32
- in Integer => dst_addr
- # 0F 84 cd
- insn(opcode: [0x0f, 0x84], imm: rel32(dst_addr))
- end
- end
-
- def jl(dst)
- case dst
- # JL rel32
- in Integer => dst_addr
- # 0F 8C cd
- insn(opcode: [0x0f, 0x8c], imm: rel32(dst_addr))
- end
- end
-
- def jmp(dst)
- case dst
- # JZ rel8
- in Label => dst_label
- # EB cb
- insn(opcode: 0xeb, imm: dst_label)
- # JMP rel32
- in Integer => dst_addr
- # E9 cd
- insn(opcode: 0xe9, imm: rel32(dst_addr))
- # JMP r/m64 (Mod 01: [reg]+disp8)
- in QwordPtr[R64 => dst_reg, IMM8 => dst_disp]
- # FF /4
- insn(opcode: 0xff, mod_rm: ModRM[mod: Mod01, reg: 4, rm: dst_reg], disp: dst_disp)
- # JMP r/m64 (Mod 11: reg)
- in R64 => dst_reg
- # FF /4
- insn(opcode: 0xff, mod_rm: ModRM[mod: Mod11, reg: 4, rm: dst_reg])
- end
- end
-
- def jne(dst)
- case dst
- # JNE rel8
- in Label => dst_label
- # 75 cb
- insn(opcode: 0x75, imm: dst_label)
- # JNE rel32
- in Integer => dst_addr
- # 0F 85 cd
- insn(opcode: [0x0f, 0x85], imm: rel32(dst_addr))
- end
- end
-
- def jnz(dst)
- case dst
- # JE rel8
- in Label => dst_label
- # 75 cb
- insn(opcode: 0x75, imm: dst_label)
- # JNZ rel32
- in Integer => dst_addr
- # 0F 85 cd
- insn(opcode: [0x0f, 0x85], imm: rel32(dst_addr))
- end
- end
-
- def jo(dst)
- case dst
- # JO rel32
- in Integer => dst_addr
- # 0F 80 cd
- insn(opcode: [0x0f, 0x80], imm: rel32(dst_addr))
- end
- end
-
- def jz(dst)
- case dst
- # JZ rel8
- in Label => dst_label
- # 74 cb
- insn(opcode: 0x74, imm: dst_label)
- # JZ rel32
- in Integer => dst_addr
- # 0F 84 cd
- insn(opcode: [0x0f, 0x84], imm: rel32(dst_addr))
- end
- end
-
- def lea(dst, src)
- case [dst, src]
- # LEA r64,m (Mod 01: [reg]+disp8)
- in [R64 => dst_reg, QwordPtr[R64 => src_reg, IMM8 => src_disp]]
- # REX.W + 8D /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x8d,
- mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
- disp: imm8(src_disp),
- )
- # LEA r64,m (Mod 10: [reg]+disp32)
- in [R64 => dst_reg, QwordPtr[R64 => src_reg, IMM32 => src_disp]]
- # REX.W + 8D /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x8d,
- mod_rm: ModRM[mod: Mod10, reg: dst_reg, rm: src_reg],
- disp: imm32(src_disp),
- )
- end
- end
-
- def mov(dst, src)
- case dst
- in R32 => dst_reg
- case src
- # MOV r32 r/m32 (Mod 01: [reg]+disp8)
- in DwordPtr[R64 => src_reg, IMM8 => src_disp]
- # 8B /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- opcode: 0x8b,
- mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
- disp: src_disp,
- )
- # MOV r32, imm32 (Mod 11: reg)
- in IMM32 => src_imm
- # B8+ rd id
- # OI: Operand 1: opcode + rd (w), Operand 2: imm8/16/32/64
- insn(
- opcode: 0xb8,
- rd: dst_reg,
- imm: imm32(src_imm),
- )
- end
- in R64 => dst_reg
- case src
- # MOV r64, r/m64 (Mod 00: [reg])
- in QwordPtr[R64 => src_reg]
- # REX.W + 8B /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x8b,
- mod_rm: ModRM[mod: Mod00, reg: dst_reg, rm: src_reg],
- )
- # MOV r64, r/m64 (Mod 01: [reg]+disp8)
- in QwordPtr[R64 => src_reg, IMM8 => src_disp]
- # REX.W + 8B /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x8b,
- mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
- disp: src_disp,
- )
- # MOV r64, r/m64 (Mod 10: [reg]+disp32)
- in QwordPtr[R64 => src_reg, IMM32 => src_disp]
- # REX.W + 8B /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x8b,
- mod_rm: ModRM[mod: Mod10, reg: dst_reg, rm: src_reg],
- disp: imm32(src_disp),
- )
- # MOV r64, r/m64 (Mod 11: reg)
- in R64 => src_reg
- # REX.W + 8B /r
- # RM: Operand 1: ModRM:reg (w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x8b,
- mod_rm: ModRM[mod: Mod11, reg: dst_reg, rm: src_reg],
- )
- # MOV r/m64, imm32 (Mod 11: reg)
- in IMM32 => src_imm
- # REX.W + C7 /0 id
- # MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
- insn(
- prefix: REX_W,
- opcode: 0xc7,
- mod_rm: ModRM[mod: Mod11, reg: 0, rm: dst_reg],
- imm: imm32(src_imm),
- )
- # MOV r64, imm64
- in IMM64 => src_imm
- # REX.W + B8+ rd io
- # OI: Operand 1: opcode + rd (w), Operand 2: imm8/16/32/64
- insn(
- prefix: REX_W,
- opcode: 0xb8,
- rd: dst_reg,
- imm: imm64(src_imm),
- )
- end
- in DwordPtr[R64 => dst_reg, IMM8 => dst_disp]
- case src
- # MOV r/m32, imm32 (Mod 01: [reg]+disp8)
- in IMM32 => src_imm
- # C7 /0 id
- # MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
- insn(
- opcode: 0xc7,
- mod_rm: ModRM[mod: Mod01, reg: 0, rm: dst_reg],
- disp: dst_disp,
- imm: imm32(src_imm),
- )
- end
- in QwordPtr[R64 => dst_reg]
- case src
- # MOV r/m64, imm32 (Mod 00: [reg])
- in IMM32 => src_imm
- # REX.W + C7 /0 id
- # MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
- insn(
- prefix: REX_W,
- opcode: 0xc7,
- mod_rm: ModRM[mod: Mod00, reg: 0, rm: dst_reg],
- imm: imm32(src_imm),
- )
- # MOV r/m64, r64 (Mod 00: [reg])
- in R64 => src_reg
- # REX.W + 89 /r
- # MR: Operand 1: ModRM:r/m (w), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x89,
- mod_rm: ModRM[mod: Mod00, reg: src_reg, rm: dst_reg],
- )
- end
- in QwordPtr[R64 => dst_reg, IMM8 => dst_disp]
- # Optimize encoding when disp is 0
- return mov([dst_reg], src) if dst_disp == 0
-
- case src
- # MOV r/m64, imm32 (Mod 01: [reg]+disp8)
- in IMM32 => src_imm
- # REX.W + C7 /0 id
- # MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
- insn(
- prefix: REX_W,
- opcode: 0xc7,
- mod_rm: ModRM[mod: Mod01, reg: 0, rm: dst_reg],
- disp: dst_disp,
- imm: imm32(src_imm),
- )
- # MOV r/m64, r64 (Mod 01: [reg]+disp8)
- in R64 => src_reg
- # REX.W + 89 /r
- # MR: Operand 1: ModRM:r/m (w), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x89,
- mod_rm: ModRM[mod: Mod01, reg: src_reg, rm: dst_reg],
- disp: dst_disp,
- )
- end
- in QwordPtr[R64 => dst_reg, IMM32 => dst_disp]
- case src
- # MOV r/m64, imm32 (Mod 10: [reg]+disp32)
- in IMM32 => src_imm
- # REX.W + C7 /0 id
- # MI: Operand 1: ModRM:r/m (w), Operand 2: imm8/16/32/64
- insn(
- prefix: REX_W,
- opcode: 0xc7,
- mod_rm: ModRM[mod: Mod10, reg: 0, rm: dst_reg],
- disp: imm32(dst_disp),
- imm: imm32(src_imm),
- )
- # MOV r/m64, r64 (Mod 10: [reg]+disp32)
- in R64 => src_reg
- # REX.W + 89 /r
- # MR: Operand 1: ModRM:r/m (w), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x89,
- mod_rm: ModRM[mod: Mod10, reg: src_reg, rm: dst_reg],
- disp: imm32(dst_disp),
- )
- end
- end
- end
-
- def or(dst, src)
- case [dst, src]
- # OR r/m64, imm8 (Mod 11: reg)
- in [R64 => dst_reg, IMM8 => src_imm]
- # REX.W + 83 /1 ib
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod11, reg: 1, rm: dst_reg],
- imm: imm8(src_imm),
- )
- # OR r/m64, imm32 (Mod 11: reg)
- in [R64 => dst_reg, IMM32 => src_imm]
- # REX.W + 81 /1 id
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x81,
- mod_rm: ModRM[mod: Mod11, reg: 1, rm: dst_reg],
- imm: imm32(src_imm),
- )
- # OR r64, r/m64 (Mod 01: [reg]+disp8)
- in [R64 => dst_reg, QwordPtr[R64 => src_reg, IMM8 => src_disp]]
- # REX.W + 0B /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x0b,
- mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
- disp: imm8(src_disp),
- )
- # OR r64, r/m64 (Mod 10: [reg]+disp32)
- in [R64 => dst_reg, QwordPtr[R64 => src_reg, IMM32 => src_disp]]
- # REX.W + 0B /r
- # RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
- insn(
- prefix: REX_W,
- opcode: 0x0b,
- mod_rm: ModRM[mod: Mod10, reg: dst_reg, rm: src_reg],
- disp: imm32(src_disp),
- )
- end
- end
-
- def push(src)
- case src
- # PUSH r64
- in R64 => src_reg
- # 50+rd
- # O: Operand 1: opcode + rd (r)
- insn(opcode: 0x50, rd: src_reg)
- end
- end
-
- def pop(dst)
- case dst
- # POP r64
- in R64 => dst_reg
- # 58+ rd
- # O: Operand 1: opcode + rd (r)
- insn(opcode: 0x58, rd: dst_reg)
- end
- end
-
- def ret
- # RET
- # Near return: A return to a procedure within the current code segment
- insn(opcode: 0xc3)
- end
-
- def sar(dst, src)
- case [dst, src]
- in [R64 => dst_reg, IMM8 => src_imm]
- # REX.W + C1 /7 ib
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8
- insn(
- prefix: REX_W,
- opcode: 0xc1,
- mod_rm: ModRM[mod: Mod11, reg: 7, rm: dst_reg],
- imm: imm8(src_imm),
- )
- end
- end
-
- def sub(dst, src)
- case [dst, src]
- # SUB r/m64, imm8 (Mod 11: reg)
- in [R64 => dst_reg, IMM8 => src_imm]
- # REX.W + 83 /5 ib
- # MI: Operand 1: ModRM:r/m (r, w), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0x83,
- mod_rm: ModRM[mod: Mod11, reg: 5, rm: dst_reg],
- imm: imm8(src_imm),
- )
- # SUB r/m64, r64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 29 /r
- # MR: Operand 1: ModRM:r/m (r, w), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x29,
- mod_rm: ModRM[mod: Mod11, reg: src_reg, rm: dst_reg],
- )
- end
- end
-
- def test(left, right)
- case [left, right]
- # TEST r/m8*, imm8 (Mod 01: [reg]+disp8)
- in [BytePtr[R64 => left_reg, IMM8 => left_disp], IMM8 => right_imm]
- # REX + F6 /0 ib
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- opcode: 0xf6,
- mod_rm: ModRM[mod: Mod01, reg: 0, rm: left_reg],
- disp: left_disp,
- imm: imm8(right_imm),
- )
- # TEST r/m64, imm32 (Mod 01: [reg]+disp8)
- in [QwordPtr[R64 => left_reg, IMM8 => left_disp], IMM32 => right_imm]
- # REX.W + F7 /0 id
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0xf7,
- mod_rm: ModRM[mod: Mod01, reg: 0, rm: left_reg],
- disp: left_disp,
- imm: imm32(right_imm),
- )
- # TEST r/m64, imm32 (Mod 10: [reg]+disp32)
- in [QwordPtr[R64 => left_reg, IMM32 => left_disp], IMM32 => right_imm]
- # REX.W + F7 /0 id
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0xf7,
- mod_rm: ModRM[mod: Mod10, reg: 0, rm: left_reg],
- disp: imm32(left_disp),
- imm: imm32(right_imm),
- )
- # TEST r/m64, imm32 (Mod 11: reg)
- in [R64 => left_reg, IMM32 => right_imm]
- # REX.W + F7 /0 id
- # MI: Operand 1: ModRM:r/m (r), Operand 2: imm8/16/32
- insn(
- prefix: REX_W,
- opcode: 0xf7,
- mod_rm: ModRM[mod: Mod11, reg: 0, rm: left_reg],
- imm: imm32(right_imm),
- )
- # TEST r/m32, r32 (Mod 11: reg)
- in [R32 => left_reg, R32 => right_reg]
- # 85 /r
- # MR: Operand 1: ModRM:r/m (r), Operand 2: ModRM:reg (r)
- insn(
- opcode: 0x85,
- mod_rm: ModRM[mod: Mod11, reg: right_reg, rm: left_reg],
- )
- # TEST r/m64, r64 (Mod 11: reg)
- in [R64 => left_reg, R64 => right_reg]
- # REX.W + 85 /r
- # MR: Operand 1: ModRM:r/m (r), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x85,
- mod_rm: ModRM[mod: Mod11, reg: right_reg, rm: left_reg],
- )
- end
- end
-
- def xor(dst, src)
- case [dst, src]
- # XOR r/m64, r64 (Mod 11: reg)
- in [R64 => dst_reg, R64 => src_reg]
- # REX.W + 31 /r
- # MR: Operand 1: ModRM:r/m (r, w), Operand 2: ModRM:reg (r)
- insn(
- prefix: REX_W,
- opcode: 0x31,
- mod_rm: ModRM[mod: Mod11, reg: src_reg, rm: dst_reg],
- )
- end
- end
-
- #
- # Utilities
- #
-
- attr_reader :comments
-
- def comment(message)
- @comments[@bytes.size] << message
- end
-
- # Mark the starting address of a block
- def block(block)
- @blocks[@bytes.size] << block
- end
-
- # Mark the starting/ending addresses of a stub
- def stub(stub)
- @stub_starts[@bytes.size] << stub
- yield
- ensure
- @stub_ends[@bytes.size] << stub
- end
-
- def pos_marker(&block)
- @pos_markers[@bytes.size] << block
- end
-
- def new_label(name)
- Label.new(id: @label_id += 1, name:)
- end
-
- # @param [RubyVM::RJIT::Assembler::Label] label
- def write_label(label)
- @labels[label] = @bytes.size
- end
-
- def incr_counter(name)
- if C.rjit_opts.stats
- comment("increment counter #{name}")
- mov(:rax, C.rb_rjit_counters[name].to_i)
- add([:rax], 1) # TODO: lock
- end
- end
-
- private
-
- def insn(prefix: 0, opcode:, rd: nil, mod_rm: nil, disp: nil, imm: nil)
- # Determine prefix
- if rd
- prefix |= REX_B if extended_reg?(rd)
- opcode += reg_code(rd)
- end
- if mod_rm
- prefix |= REX_R if mod_rm.reg.is_a?(Symbol) && extended_reg?(mod_rm.reg)
- prefix |= REX_B if mod_rm.rm.is_a?(Symbol) && extended_reg?(mod_rm.rm)
- end
-
- # Encode insn
- if prefix > 0
- @bytes.push(prefix)
- end
- @bytes.push(*Array(opcode))
- if mod_rm
- mod_rm_byte = encode_mod_rm(
- mod: mod_rm.mod,
- reg: mod_rm.reg.is_a?(Symbol) ? reg_code(mod_rm.reg) : mod_rm.reg,
- rm: mod_rm.rm.is_a?(Symbol) ? reg_code(mod_rm.rm) : mod_rm.rm,
- )
- @bytes.push(mod_rm_byte)
- end
- if disp
- @bytes.push(*Array(disp))
- end
- if imm
- @bytes.push(*imm)
- end
- end
-
- def reg_code(reg)
- reg_code_extended(reg).first
- end
-
- # Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte
- #
- # 7 6 5 4 3 2 1 0
- # +--+--+--+--+--+--+--+--+
- # | Mod | Reg/ | R/M |
- # | | Opcode | |
- # +--+--+--+--+--+--+--+--+
- #
- # The r/m field can specify a register as an operand or it can be combined
- # with the mod field to encode an addressing mode.
- #
- # /0: R/M is 0 (not used)
- # /r: R/M is a register
- def encode_mod_rm(mod:, reg: 0, rm: 0)
- if mod > 0b11
- raise ArgumentError, "too large Mod: #{mod}"
- end
- if reg > 0b111
- raise ArgumentError, "too large Reg/Opcode: #{reg}"
- end
- if rm > 0b111
- raise ArgumentError, "too large R/M: #{rm}"
- end
- (mod << 6) + (reg << 3) + rm
- end
-
- # ib: 1 byte
- def imm8(imm)
- unless imm8?(imm)
- raise ArgumentError, "unexpected imm8: #{imm}"
- end
- [imm].pack('c').unpack('c*') # TODO: consider uimm
- end
-
- # id: 4 bytes
- def imm32(imm)
- unless imm32?(imm)
- raise ArgumentError, "unexpected imm32: #{imm}"
- end
- [imm].pack('l').unpack('c*') # TODO: consider uimm
- end
-
- # io: 8 bytes
- def imm64(imm)
- unless imm64?(imm)
- raise ArgumentError, "unexpected imm64: #{imm}"
- end
- imm_bytes(imm, 8)
- end
-
- def imm_bytes(imm, num_bytes)
- bytes = []
- bits = imm
- num_bytes.times do
- bytes << (bits & 0xff)
- bits >>= 8
- end
- if bits != 0
- raise ArgumentError, "unexpected imm with #{num_bytes} bytes: #{imm}"
- end
- bytes
- end
-
- def rel32(addr)
- [Rel32.new(addr), Rel32Pad, Rel32Pad, Rel32Pad]
- end
-
- def set_code_addrs(write_addr)
- (@bytes.size + 1).times do |index|
- @blocks.fetch(index, []).each do |block|
- block.start_addr = write_addr + index
- end
- @stub_starts.fetch(index, []).each do |stub|
- stub.start_addr = write_addr + index
- end
- @stub_ends.fetch(index, []).each do |stub|
- stub.end_addr = write_addr + index
- end
- end
- end
-
- def resolve_rel32(write_addr)
- @bytes.each_with_index do |byte, index|
- if byte.is_a?(Rel32)
- src_addr = write_addr + index + 4 # offset 4 bytes for rel32 itself
- dst_addr = byte.addr
- rel32 = dst_addr - src_addr
- raise "unexpected offset: #{rel32}" unless imm32?(rel32)
- imm32(rel32).each_with_index do |rel_byte, rel_index|
- @bytes[index + rel_index] = rel_byte
- end
- end
- end
- end
-
- def resolve_labels
- @bytes.each_with_index do |byte, index|
- if byte.is_a?(Label)
- src_index = index + 1 # offset 1 byte for rel8 itself
- dst_index = @labels.fetch(byte)
- rel8 = dst_index - src_index
- raise "unexpected offset: #{rel8}" unless imm8?(rel8)
- @bytes[index] = rel8
- end
- end
- end
-
- def write_bytes(addr)
- Fiddle::Pointer.new(addr)[0, @bytes.size] = @bytes.pack('c*')
- end
- end
-
- module OperandMatcher
- def imm8?(imm)
- (-0x80..0x7f).include?(imm)
- end
-
- def imm32?(imm)
- (-0x8000_0000..0x7fff_ffff).include?(imm) # TODO: consider uimm
- end
-
- def imm64?(imm)
- (-0x8000_0000_0000_0000..0xffff_ffff_ffff_ffff).include?(imm)
- end
-
- def r32?(reg)
- if extended_reg?(reg)
- reg.end_with?('d')
- else
- reg.start_with?('e')
- end
- end
-
- def r64?(reg)
- if extended_reg?(reg)
- reg.match?(/\Ar\d+\z/)
- else
- reg.start_with?('r')
- end
- end
-
- def extended_reg?(reg)
- reg_code_extended(reg).last
- end
-
- def reg_code_extended(reg)
- case reg
- # Not extended
- when :al, :ax, :eax, :rax then [0, false]
- when :cl, :cx, :ecx, :rcx then [1, false]
- when :dl, :dx, :edx, :rdx then [2, false]
- when :bl, :bx, :ebx, :rbx then [3, false]
- when :ah, :sp, :esp, :rsp then [4, false]
- when :ch, :bp, :ebp, :rbp then [5, false]
- when :dh, :si, :esi, :rsi then [6, false]
- when :bh, :di, :edi, :rdi then [7, false]
- # Extended
- when :r8b, :r8w, :r8d, :r8 then [0, true]
- when :r9b, :r9w, :r9d, :r9 then [1, true]
- when :r10b, :r10w, :r10d, :r10 then [2, true]
- when :r11b, :r11w, :r11d, :r11 then [3, true]
- when :r12b, :r12w, :r12d, :r12 then [4, true]
- when :r13b, :r13w, :r13d, :r13 then [5, true]
- when :r14b, :r14w, :r14d, :r14 then [6, true]
- when :r15b, :r15w, :r15d, :r15 then [7, true]
- else raise ArgumentError, "unexpected reg: #{reg.inspect}"
- end
- end
- end
-
- class Assembler
- include OperandMatcher
- extend OperandMatcher
- end
-end
diff --git a/lib/ruby_vm/rjit/block.rb b/lib/ruby_vm/rjit/block.rb
deleted file mode 100644
index cfdaade8b1..0000000000
--- a/lib/ruby_vm/rjit/block.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class RubyVM::RJIT::Block < Struct.new(
- :iseq, # @param ``
- :pc, # @param [Integer] Starting PC
- :ctx, # @param [RubyVM::RJIT::Context] **Starting** Context (TODO: freeze?)
- :start_addr, # @param [Integer] Starting address of this block's JIT code
- :entry_exit, # @param [Integer] Address of entry exit (optional)
- :incoming, # @param [Array<RubyVM::RJIT::BranchStub>] Incoming branches
- :invalidated, # @param [TrueClass,FalseClass] true if already invalidated
-)
- def initialize(incoming: [], invalidated: false, **) = super
-end
diff --git a/lib/ruby_vm/rjit/branch_stub.rb b/lib/ruby_vm/rjit/branch_stub.rb
deleted file mode 100644
index b9fe78b744..0000000000
--- a/lib/ruby_vm/rjit/branch_stub.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-module RubyVM::RJIT
- # Branch shapes
- Next0 = :Next0 # target0 is a fallthrough
- Next1 = :Next1 # target1 is a fallthrough
- Default = :Default # neither targets is a fallthrough
-
- class BranchStub < Struct.new(
- :iseq, # @param [RubyVM::RJIT::CPointer::Struct_rb_iseq_struct] Branch target ISEQ
- :shape, # @param [Symbol] Next0, Next1, or Default
- :target0, # @param [RubyVM::RJIT::BranchTarget] First branch target
- :target1, # @param [RubyVM::RJIT::BranchTarget,NilClass] Second branch target (optional)
- :compile, # @param [Proc] A callback to (re-)generate this branch stub
- :start_addr, # @param [Integer] Stub source start address to be re-generated
- :end_addr, # @param [Integer] Stub source end address to be re-generated
- )
- end
-
- class BranchTarget < Struct.new(
- :pc,
- :ctx,
- :address,
- )
- end
-end
diff --git a/lib/ruby_vm/rjit/c_pointer.rb b/lib/ruby_vm/rjit/c_pointer.rb
deleted file mode 100644
index db00c4cd11..0000000000
--- a/lib/ruby_vm/rjit/c_pointer.rb
+++ /dev/null
@@ -1,394 +0,0 @@
-module RubyVM::RJIT
- # Every class under this namespace is a pointer. Even if the type is
- # immediate, it shouldn't be dereferenced until `*` is called.
- module CPointer
- # Note: We'd like to avoid alphabetic method names to avoid a conflict
- # with member methods. to_i and to_s are considered an exception.
- class Struct
- # @param name [String]
- # @param sizeof [Integer]
- # @param members [Hash{ Symbol => [RubyVM::RJIT::CType::*, Integer, TrueClass] }]
- def initialize(addr, sizeof, members)
- @addr = addr
- @sizeof = sizeof
- @members = members
- end
-
- # Get a raw address
- def to_i
- @addr
- end
-
- # Serialized address for generated code
- def to_s
- "0x#{@addr.to_s(16)}"
- end
-
- # Pointer diff
- def -(struct)
- raise ArgumentError if self.class != struct.class
- (@addr - struct.to_i) / @sizeof
- end
-
- # Primitive API that does no automatic dereference
- # TODO: remove this?
- # @param member [Symbol]
- def [](member)
- type, offset = @members.fetch(member)
- type.new(@addr + offset / 8)
- end
-
- private
-
- # @param member [Symbol]
- # @param value [Object]
- def []=(member, value)
- type, offset = @members.fetch(member)
- type[@addr + offset / 8] = value
- end
-
- # @param size [Integer]
- # @param members [Hash{ Symbol => [Integer, RubyVM::RJIT::CType::*] }]
- def self.define(size, members)
- Class.new(self) do
- # Return the size of this type
- define_singleton_method(:size) { size }
-
- # Return the offset to a field
- define_singleton_method(:offsetof) do |field, *fields|
- member, offset = members.fetch(field)
- offset /= 8
- unless fields.empty?
- offset += member.offsetof(*fields)
- end
- offset
- end
-
- # Return member names
- define_singleton_method(:members) { members.keys }
-
- define_method(:initialize) do |addr = nil|
- if addr.nil? # TODO: get rid of this feature later
- addr = Fiddle.malloc(size)
- end
- super(addr, size, members)
- end
-
- members.each do |member, (type, offset, to_ruby)|
- # Intelligent API that does automatic dereference
- define_method(member) do
- value = self[member]
- if value.respond_to?(:*)
- value = value.*
- end
- if to_ruby
- value = C.to_ruby(value)
- end
- value
- end
-
- define_method("#{member}=") do |value|
- if to_ruby
- value = C.to_value(value)
- end
- self[member] = value
- end
- end
- end
- end
- end
-
- # Note: We'd like to avoid alphabetic method names to avoid a conflict
- # with member methods. to_i is considered an exception.
- class Union
- # @param _name [String] To be used when it starts defining a union pointer class
- # @param sizeof [Integer]
- # @param members [Hash{ Symbol => RubyVM::RJIT::CType::* }]
- def initialize(addr, sizeof, members)
- @addr = addr
- @sizeof = sizeof
- @members = members
- end
-
- # Get a raw address
- def to_i
- @addr
- end
-
- # Move addr to access this pointer like an array
- def +(index)
- raise ArgumentError unless index.is_a?(Integer)
- self.class.new(@addr + index * @sizeof)
- end
-
- # Pointer diff
- def -(union)
- raise ArgumentError if self.class != union.class
- (@addr - union.instance_variable_get(:@addr)) / @sizeof
- end
-
- # @param sizeof [Integer]
- # @param members [Hash{ Symbol => RubyVM::RJIT::CType::* }]
- def self.define(sizeof, members)
- Class.new(self) do
- # Return the size of this type
- define_singleton_method(:sizeof) { sizeof }
-
- # Part of Struct's offsetof implementation
- define_singleton_method(:offsetof) do |field, *fields|
- member = members.fetch(field)
- offset = 0
- unless fields.empty?
- offset += member.offsetof(*fields)
- end
- offset
- end
-
- define_method(:initialize) do |addr|
- super(addr, sizeof, members)
- end
-
- members.each do |member, type|
- # Intelligent API that does automatic dereference
- define_method(member) do
- value = type.new(@addr)
- if value.respond_to?(:*)
- value = value.*
- end
- value
- end
- end
- end
- end
- end
-
- class Immediate
- # @param addr [Integer]
- # @param size [Integer]
- # @param pack [String]
- def initialize(addr, size, pack)
- @addr = addr
- @size = size
- @pack = pack
- end
-
- # Get a raw address
- def to_i
- @addr
- end
-
- # Move addr to addess this pointer like an array
- def +(index)
- Immediate.new(@addr + index * @size, @size, @pack)
- end
-
- # Dereference
- def *
- self[0]
- end
-
- # Array access
- def [](index)
- return nil if @addr == 0
- Fiddle::Pointer.new(@addr + index * @size)[0, @size].unpack1(@pack)
- end
-
- # Array set
- def []=(index, value)
- Fiddle::Pointer.new(@addr + index * @size)[0, @size] = [value].pack(@pack)
- end
-
- # Serialized address for generated code. Used for embedding things like body->iseq_encoded.
- def to_s
- "0x#{Integer(@addr).to_s(16)}"
- end
-
- # @param fiddle_type [Integer] Fiddle::TYPE_*
- def self.define(fiddle_type)
- size = Fiddle::PackInfo::SIZE_MAP.fetch(fiddle_type)
- pack = Fiddle::PackInfo::PACK_MAP.fetch(fiddle_type)
-
- Class.new(self) do
- define_method(:initialize) do |addr|
- super(addr, size, pack)
- end
-
- define_singleton_method(:size) do
- size
- end
-
- # Type-level []=: Used by struct fields
- define_singleton_method(:[]=) do |addr, value|
- Fiddle::Pointer.new(addr)[0, size] = [value].pack(pack)
- end
- end
- end
- end
-
- # -Fiddle::TYPE_CHAR Immediate with special handling of true/false
- class Bool < Immediate.define(-Fiddle::TYPE_CHAR)
- # Dereference
- def *
- return nil if @addr == 0
- super != 0
- end
-
- def self.[]=(addr, value)
- super(addr, value ? 1 : 0)
- end
- end
-
- # Basically Immediate but without #* to skip auto-dereference of structs.
- class Array
- attr_reader :type
-
- # @param addr [Integer]
- # @param type [Class] RubyVM::RJIT::CType::*
- def initialize(addr, type)
- @addr = addr
- @type = type
- end
-
- # Array access
- def [](index)
- @type.new(@addr)[index]
- end
-
- # Array set
- # @param index [Integer]
- # @param value [Integer, RubyVM::RJIT::CPointer::Struct] an address itself or an object that return an address with to_i
- def []=(index, value)
- @type.new(@addr)[index] = value
- end
-
- private
-
- def self.define(block)
- Class.new(self) do
- define_method(:initialize) do |addr|
- super(addr, block.call)
- end
- end
- end
- end
-
- class Pointer
- attr_reader :type
-
- # @param addr [Integer]
- # @param type [Class] RubyVM::RJIT::CType::*
- def initialize(addr, type)
- @addr = addr
- @type = type
- end
-
- # Move addr to addess this pointer like an array
- def +(index)
- raise ArgumentError unless index.is_a?(Integer)
- Pointer.new(@addr + index * Fiddle::SIZEOF_VOIDP, @type)
- end
-
- # Dereference
- def *
- return nil if dest_addr == 0
- @type.new(dest_addr)
- end
-
- # Array access
- def [](index)
- (self + index).*
- end
-
- # Array set
- # @param index [Integer]
- # @param value [Integer, RubyVM::RJIT::CPointer::Struct] an address itself or an object that return an address with to_i
- def []=(index, value)
- Fiddle::Pointer.new(@addr + index * Fiddle::SIZEOF_VOIDP)[0, Fiddle::SIZEOF_VOIDP] =
- [value.to_i].pack(Fiddle::PackInfo::PACK_MAP[Fiddle::TYPE_VOIDP])
- end
-
- # Get a raw address
- def to_i
- @addr
- end
-
- private
-
- def dest_addr
- Fiddle::Pointer.new(@addr)[0, Fiddle::SIZEOF_VOIDP].unpack1(Fiddle::PackInfo::PACK_MAP[Fiddle::TYPE_VOIDP])
- end
-
- def self.define(block)
- Class.new(self) do
- define_method(:initialize) do |addr|
- super(addr, block.call)
- end
-
- # Type-level []=: Used by struct fields
- # @param addr [Integer]
- # @param value [Integer, RubyVM::RJIT::CPointer::Struct] an address itself, or an object that return an address with to_i
- define_singleton_method(:[]=) do |addr, value|
- value = value.to_i
- Fiddle::Pointer.new(addr)[0, Fiddle::SIZEOF_VOIDP] = [value].pack(Fiddle::PackInfo::PACK_MAP[Fiddle::TYPE_VOIDP])
- end
- end
- end
- end
-
- class BitField
- # @param addr [Integer]
- # @param width [Integer]
- # @param offset [Integer]
- def initialize(addr, width, offset)
- @addr = addr
- @width = width
- @offset = offset
- end
-
- # Dereference
- def *
- byte = Fiddle::Pointer.new(@addr)[0, Fiddle::SIZEOF_CHAR].unpack('c').first
- if @width == 1
- bit = (1 & (byte >> @offset))
- bit == 1
- elsif @width <= 8 && @offset == 0
- bitmask = @width.times.map { |i| 1 << i }.sum
- byte & bitmask
- else
- raise NotImplementedError.new("not-implemented bit field access: width=#{@width} offset=#{@offset}")
- end
- end
-
- # @param width [Integer]
- # @param offset [Integer]
- def self.define(width, offset)
- Class.new(self) do
- define_method(:initialize) do |addr|
- super(addr, width, offset)
- end
- end
- end
- end
-
- # Give a name to a dynamic CPointer class to see it on inspect
- def self.with_class_name(prefix, name, cache: false, &block)
- return block.call if !name.nil? && name.empty?
-
- # Use a cached result only if cache: true
- class_name = "#{prefix}_#{name}"
- klass =
- if cache && self.const_defined?(class_name)
- self.const_get(class_name)
- else
- block.call
- end
-
- # Give it a name unless it's already defined
- unless self.const_defined?(class_name)
- self.const_set(class_name, klass)
- end
-
- klass
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/c_type.rb b/lib/ruby_vm/rjit/c_type.rb
deleted file mode 100644
index 3b313a658b..0000000000
--- a/lib/ruby_vm/rjit/c_type.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-require 'fiddle'
-require 'fiddle/pack'
-require_relative 'c_pointer'
-
-module RubyVM::RJIT
- module CType
- module Struct
- # @param name [String]
- # @param members [Hash{ Symbol => [Integer, RubyVM::RJIT::CType::*] }]
- def self.new(name, sizeof, **members)
- name = members.keys.join('_') if name.empty?
- CPointer.with_class_name('Struct', name) do
- CPointer::Struct.define(sizeof, members)
- end
- end
- end
-
- module Union
- # @param name [String]
- # @param members [Hash{ Symbol => RubyVM::RJIT::CType::* }]
- def self.new(name, sizeof, **members)
- name = members.keys.join('_') if name.empty?
- CPointer.with_class_name('Union', name) do
- CPointer::Union.define(sizeof, members)
- end
- end
- end
-
- module Immediate
- # @param fiddle_type [Integer]
- def self.new(fiddle_type)
- name = Fiddle.constants.find do |const|
- const.start_with?('TYPE_') && Fiddle.const_get(const) == fiddle_type.abs
- end&.to_s
- name.delete_prefix!('TYPE_')
- if fiddle_type.negative?
- name.prepend('U')
- end
- CPointer.with_class_name('Immediate', name, cache: true) do
- CPointer::Immediate.define(fiddle_type)
- end
- end
-
- # @param type [String]
- def self.parse(ctype)
- new(Fiddle::Importer.parse_ctype(ctype))
- end
-
- def self.find(size, signed)
- fiddle_type = TYPE_MAP.fetch(size)
- fiddle_type = -fiddle_type unless signed
- new(fiddle_type)
- end
-
- TYPE_MAP = Fiddle::PackInfo::SIZE_MAP.map { |type, size| [size, type.abs] }.to_h
- private_constant :TYPE_MAP
- end
-
- module Bool
- def self.new
- CPointer::Bool
- end
- end
-
- class Array
- def self.new(&block)
- CPointer.with_class_name('Array', block.object_id.to_s) do
- CPointer::Array.define(block)
- end
- end
- end
-
- class Pointer
- # This takes a block to avoid "stack level too deep" on a cyclic reference
- # @param block [Proc]
- def self.new(&block)
- CPointer.with_class_name('Pointer', block.object_id.to_s) do
- CPointer::Pointer.define(block)
- end
- end
- end
-
- module BitField
- # @param width [Integer]
- # @param offset [Integer]
- def self.new(width, offset)
- CPointer.with_class_name('BitField', "#{offset}_#{width}") do
- CPointer::BitField.define(width, offset)
- end
- end
- end
-
- # Types that are referenced but not part of code generation targets
- Stub = ::Struct.new(:name)
-
- # Types that it failed to figure out from the header
- Unknown = Module.new
- end
-end
diff --git a/lib/ruby_vm/rjit/code_block.rb b/lib/ruby_vm/rjit/code_block.rb
deleted file mode 100644
index 260bd98671..0000000000
--- a/lib/ruby_vm/rjit/code_block.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-module RubyVM::RJIT
- class CodeBlock
- # @param mem_block [Integer] JIT buffer address
- # @param mem_size [Integer] JIT buffer size
- # @param outliend [TrueClass,FalseClass] true for outlined CodeBlock
- def initialize(mem_block:, mem_size:, outlined: false)
- @comments = Hash.new { |h, k| h[k] = [] } if dump_disasm?
- @mem_block = mem_block
- @mem_size = mem_size
- @write_pos = 0
- @outlined = outlined
- end
-
- # @param asm [RubyVM::RJIT::Assembler]
- def write(asm)
- return 0 if @write_pos + asm.size >= @mem_size
-
- start_addr = write_addr
-
- # Write machine code
- C.mprotect_write(@mem_block, @mem_size)
- @write_pos += asm.assemble(start_addr)
- C.mprotect_exec(@mem_block, @mem_size)
-
- end_addr = write_addr
-
- # Convert comment indexes to addresses
- asm.comments.each do |index, comments|
- @comments[start_addr + index] += comments if dump_disasm?
- end
- asm.comments.clear
-
- # Dump disasm if --rjit-dump-disasm
- if C.rjit_opts.dump_disasm && start_addr < end_addr
- dump_disasm(start_addr, end_addr)
- end
- start_addr
- end
-
- def set_write_addr(addr)
- @write_pos = addr - @mem_block
- @comments.delete(addr) if dump_disasm?
- end
-
- def with_write_addr(addr)
- old_write_pos = @write_pos
- set_write_addr(addr)
- yield
- ensure
- @write_pos = old_write_pos
- end
-
- def write_addr
- @mem_block + @write_pos
- end
-
- def include?(addr)
- (@mem_block...(@mem_block + @mem_size)).include?(addr)
- end
-
- def dump_disasm(from, to, io: STDOUT, color: true, test: false)
- C.dump_disasm(from, to, test:).each do |address, mnemonic, op_str|
- @comments.fetch(address, []).each do |comment|
- io.puts colorize(" # #{comment}", bold: true, color:)
- end
- io.puts colorize(" 0x#{format("%x", address)}: #{mnemonic} #{op_str}", color:)
- end
- io.puts
- end
-
- private
-
- def colorize(text, bold: false, color:)
- return text unless color
- buf = +''
- buf << "\e[1m" if bold
- buf << "\e[34m" if @outlined
- buf << text
- buf << "\e[0m"
- buf
- end
-
- def bold(text)
- "\e[1m#{text}\e[0m"
- end
-
- def dump_disasm?
- C.rjit_opts.dump_disasm
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/compiler.rb b/lib/ruby_vm/rjit/compiler.rb
deleted file mode 100644
index e5c3adf0ec..0000000000
--- a/lib/ruby_vm/rjit/compiler.rb
+++ /dev/null
@@ -1,518 +0,0 @@
-require 'ruby_vm/rjit/assembler'
-require 'ruby_vm/rjit/block'
-require 'ruby_vm/rjit/branch_stub'
-require 'ruby_vm/rjit/code_block'
-require 'ruby_vm/rjit/context'
-require 'ruby_vm/rjit/entry_stub'
-require 'ruby_vm/rjit/exit_compiler'
-require 'ruby_vm/rjit/insn_compiler'
-require 'ruby_vm/rjit/instruction'
-require 'ruby_vm/rjit/invariants'
-require 'ruby_vm/rjit/jit_state'
-require 'ruby_vm/rjit/type'
-
-module RubyVM::RJIT
- # Compilation status
- KeepCompiling = :KeepCompiling
- CantCompile = :CantCompile
- EndBlock = :EndBlock
-
- # Ruby constants
- Qtrue = Fiddle::Qtrue
- Qfalse = Fiddle::Qfalse
- Qnil = Fiddle::Qnil
- Qundef = Fiddle::Qundef
-
- # Callee-saved registers
- # TODO: support using r12/r13 here
- EC = :r14
- CFP = :r15
- SP = :rbx
-
- # Scratch registers: rax, rcx, rdx
-
- # Mark objects in this Array during GC
- GC_REFS = []
-
- # Maximum number of versions per block
- # 1 means always create generic versions
- MAX_VERSIONS = 4
-
- class Compiler
- attr_accessor :write_pos
-
- def self.decode_insn(encoded)
- INSNS.fetch(C.rb_vm_insn_decode(encoded))
- end
-
- def initialize
- mem_size = C.rjit_opts.exec_mem_size * 1024 * 1024
- mem_block = C.mmap(mem_size)
- @cb = CodeBlock.new(mem_block: mem_block, mem_size: mem_size / 2)
- @ocb = CodeBlock.new(mem_block: mem_block + mem_size / 2, mem_size: mem_size / 2, outlined: true)
- @exit_compiler = ExitCompiler.new
- @insn_compiler = InsnCompiler.new(@cb, @ocb, @exit_compiler)
- Invariants.initialize(@cb, @ocb, self, @exit_compiler)
- end
-
- # Compile an ISEQ from its entry point.
- # @param iseq `RubyVM::RJIT::CPointer::Struct_rb_iseq_t`
- # @param cfp `RubyVM::RJIT::CPointer::Struct_rb_control_frame_t`
- def compile(iseq, cfp)
- return unless supported_platform?
- pc = cfp.pc.to_i
- jit = JITState.new(iseq:, cfp:)
- asm = Assembler.new
- compile_prologue(asm, iseq, pc)
- compile_block(asm, jit:, pc:)
- iseq.body.jit_entry = @cb.write(asm)
- rescue Exception => e
- STDERR.puts "#{e.class}: #{e.message}"
- STDERR.puts e.backtrace
- exit 1
- end
-
- # Compile an entry.
- # @param entry [RubyVM::RJIT::EntryStub]
- def entry_stub_hit(entry_stub, cfp)
- # Compile a new entry guard as a next entry
- pc = cfp.pc.to_i
- next_entry = Assembler.new.then do |asm|
- compile_entry_chain_guard(asm, cfp.iseq, pc)
- @cb.write(asm)
- end
-
- # Try to find an existing compiled version of this block
- ctx = Context.new
- block = find_block(cfp.iseq, pc, ctx)
- if block
- # If an existing block is found, generate a jump to the block.
- asm = Assembler.new
- asm.jmp(block.start_addr)
- @cb.write(asm)
- else
- # If this block hasn't yet been compiled, generate blocks after the entry guard.
- asm = Assembler.new
- jit = JITState.new(iseq: cfp.iseq, cfp:)
- compile_block(asm, jit:, pc:, ctx:)
- @cb.write(asm)
-
- block = jit.block
- end
-
- # Regenerate the previous entry
- @cb.with_write_addr(entry_stub.start_addr) do
- # The last instruction of compile_entry_chain_guard is jne
- asm = Assembler.new
- asm.jne(next_entry)
- @cb.write(asm)
- end
-
- return block.start_addr
- rescue Exception => e
- STDERR.puts e.full_message
- exit 1
- end
-
- # Compile a branch stub.
- # @param branch_stub [RubyVM::RJIT::BranchStub]
- # @param cfp `RubyVM::RJIT::CPointer::Struct_rb_control_frame_t`
- # @param target0_p [TrueClass,FalseClass]
- # @return [Integer] The starting address of the compiled branch stub
- def branch_stub_hit(branch_stub, cfp, target0_p)
- # Update cfp->pc for `jit.at_current_insn?`
- target = target0_p ? branch_stub.target0 : branch_stub.target1
- cfp.pc = target.pc
-
- # Reuse an existing block if it already exists
- block = find_block(branch_stub.iseq, target.pc, target.ctx)
-
- # If the branch stub's jump is the last code, allow overwriting part of
- # the old branch code with the new block code.
- fallthrough = block.nil? && @cb.write_addr == branch_stub.end_addr
- if fallthrough
- # If the branch stub's jump is the last code, allow overwriting part of
- # the old branch code with the new block code.
- @cb.set_write_addr(branch_stub.start_addr)
- branch_stub.shape = target0_p ? Next0 : Next1
- Assembler.new.tap do |branch_asm|
- branch_stub.compile.call(branch_asm)
- @cb.write(branch_asm)
- end
- end
-
- # Reuse or generate a block
- if block
- target.address = block.start_addr
- else
- jit = JITState.new(iseq: branch_stub.iseq, cfp:)
- target.address = Assembler.new.then do |asm|
- compile_block(asm, jit:, pc: target.pc, ctx: target.ctx.dup)
- @cb.write(asm)
- end
- block = jit.block
- end
- block.incoming << branch_stub # prepare for invalidate_block
-
- # Re-generate the branch code for non-fallthrough cases
- unless fallthrough
- @cb.with_write_addr(branch_stub.start_addr) do
- branch_asm = Assembler.new
- branch_stub.compile.call(branch_asm)
- @cb.write(branch_asm)
- end
- end
-
- return target.address
- rescue Exception => e
- STDERR.puts e.full_message
- exit 1
- end
-
- # @param iseq `RubyVM::RJIT::CPointer::Struct_rb_iseq_t`
- # @param pc [Integer]
- def invalidate_blocks(iseq, pc)
- list_blocks(iseq, pc).each do |block|
- invalidate_block(block)
- end
-
- # If they were the ISEQ's first blocks, re-compile RJIT entry as well
- if iseq.body.iseq_encoded.to_i == pc
- iseq.body.jit_entry = 0
- iseq.body.jit_entry_calls = 0
- end
- end
-
- def invalidate_block(block)
- iseq = block.iseq
- # Avoid touching GCed ISEQs. We assume it won't be re-entered.
- return unless C.imemo_type_p(iseq, C.imemo_iseq)
-
- # Remove this block from the version array
- remove_block(iseq, block)
-
- # Invalidate the block with entry exit
- unless block.invalidated
- @cb.with_write_addr(block.start_addr) do
- asm = Assembler.new
- asm.comment('invalidate_block')
- asm.jmp(block.entry_exit)
- @cb.write(asm)
- end
- block.invalidated = true
- end
-
- # Re-stub incoming branches
- block.incoming.each do |branch_stub|
- target = [branch_stub.target0, branch_stub.target1].compact.find do |target|
- target.pc == block.pc && target.ctx == block.ctx
- end
- next if target.nil?
- # TODO: Could target.address be a stub address? Is invalidation not needed in that case?
-
- # If the target being re-generated is currently a fallthrough block,
- # the fallthrough code must be rewritten with a jump to the stub.
- if target.address == branch_stub.end_addr
- branch_stub.shape = Default
- end
-
- target.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(block.ctx, ocb_asm, branch_stub, target == branch_stub.target0)
- @ocb.write(ocb_asm)
- end
- @cb.with_write_addr(branch_stub.start_addr) do
- branch_asm = Assembler.new
- branch_stub.compile.call(branch_asm)
- @cb.write(branch_asm)
- end
- end
- end
-
- private
-
- # Callee-saved: rbx, rsp, rbp, r12, r13, r14, r15
- # Caller-saved: rax, rdi, rsi, rdx, rcx, r8, r9, r10, r11
- #
- # @param asm [RubyVM::RJIT::Assembler]
- def compile_prologue(asm, iseq, pc)
- asm.comment('RJIT entry point')
-
- # Save callee-saved registers used by JITed code
- asm.push(CFP)
- asm.push(EC)
- asm.push(SP)
-
- # Move arguments EC and CFP to dedicated registers
- asm.mov(EC, :rdi)
- asm.mov(CFP, :rsi)
-
- # Load sp to a dedicated register
- asm.mov(SP, [CFP, C.rb_control_frame_t.offsetof(:sp)]) # rbx = cfp->sp
-
- # Setup cfp->jit_return
- asm.mov(:rax, leave_exit)
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:jit_return)], :rax)
-
- # We're compiling iseqs that we *expect* to start at `insn_idx`. But in
- # the case of optional parameters, the interpreter can set the pc to a
- # different location depending on the optional parameters. If an iseq
- # has optional parameters, we'll add a runtime check that the PC we've
- # compiled for is the same PC that the interpreter wants us to run with.
- # If they don't match, then we'll take a side exit.
- if iseq.body.param.flags.has_opt
- compile_entry_chain_guard(asm, iseq, pc)
- end
- end
-
- def compile_entry_chain_guard(asm, iseq, pc)
- entry_stub = EntryStub.new
- stub_addr = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_entry_stub(ocb_asm, entry_stub)
- @ocb.write(ocb_asm)
- end
-
- asm.comment('guard expected PC')
- asm.mov(:rax, pc)
- asm.cmp([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax)
-
- asm.stub(entry_stub) do
- asm.jne(stub_addr)
- end
- end
-
- # @param asm [RubyVM::RJIT::Assembler]
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- def compile_block(asm, jit:, pc:, ctx: Context.new)
- # Mark the block start address and prepare an exit code storage
- ctx = limit_block_versions(jit.iseq, pc, ctx)
- block = Block.new(iseq: jit.iseq, pc:, ctx: ctx.dup)
- jit.block = block
- asm.block(block)
-
- iseq = jit.iseq
- asm.comment("Block: #{iseq.body.location.label}@#{C.rb_iseq_path(iseq)}:#{iseq_lineno(iseq, pc)}")
-
- # Compile each insn
- index = (pc - iseq.body.iseq_encoded.to_i) / C.VALUE.size
- while index < iseq.body.iseq_size
- # Set the current instruction
- insn = self.class.decode_insn(iseq.body.iseq_encoded[index])
- jit.pc = (iseq.body.iseq_encoded + index).to_i
- jit.stack_size_for_pc = ctx.stack_size
- jit.side_exit_for_pc.clear
-
- # If previous instruction requested to record the boundary
- if jit.record_boundary_patch_point
- # Generate an exit to this instruction and record it
- exit_pos = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_side_exit(jit.pc, ctx, ocb_asm)
- @ocb.write(ocb_asm)
- end
- Invariants.record_global_inval_patch(asm, exit_pos)
- jit.record_boundary_patch_point = false
- end
-
- # In debug mode, verify our existing assumption
- if C.rjit_opts.verify_ctx && jit.at_current_insn?
- verify_ctx(jit, ctx)
- end
-
- case status = @insn_compiler.compile(jit, ctx, asm, insn)
- when KeepCompiling
- # For now, reset the chain depth after each instruction as only the
- # first instruction in the block can concern itself with the depth.
- ctx.chain_depth = 0
-
- index += insn.len
- when EndBlock
- # TODO: pad nops if entry exit exists (not needed for x86_64?)
- break
- when CantCompile
- # Rewind stack_size using ctx.with_stack_size to allow stack_size changes
- # before you return CantCompile.
- @exit_compiler.compile_side_exit(jit.pc, ctx.with_stack_size(jit.stack_size_for_pc), asm)
-
- # If this is the first instruction, this block never needs to be invalidated.
- if block.pc == iseq.body.iseq_encoded.to_i + index * C.VALUE.size
- block.invalidated = true
- end
-
- break
- else
- raise "compiling #{insn.name} returned unexpected status: #{status.inspect}"
- end
- end
-
- incr_counter(:compiled_block_count)
- add_block(iseq, block)
- end
-
- def leave_exit
- @leave_exit ||= Assembler.new.then do |asm|
- @exit_compiler.compile_leave_exit(asm)
- @ocb.write(asm)
- end
- end
-
- def incr_counter(name)
- if C.rjit_opts.stats
- C.rb_rjit_counters[name][0] += 1
- end
- end
-
- # Produce a generic context when the block version limit is hit for the block
- def limit_block_versions(iseq, pc, ctx)
- # Guard chains implement limits separately, do nothing
- if ctx.chain_depth > 0
- return ctx.dup
- end
-
- # If this block version we're about to add will hit the version limit
- if list_blocks(iseq, pc).size + 1 >= MAX_VERSIONS
- # Produce a generic context that stores no type information,
- # but still respects the stack_size and sp_offset constraints.
- # This new context will then match all future requests.
- generic_ctx = Context.new
- generic_ctx.stack_size = ctx.stack_size
- generic_ctx.sp_offset = ctx.sp_offset
-
- if ctx.diff(generic_ctx) == TypeDiff::Incompatible
- raise 'should substitute a compatible context'
- end
-
- return generic_ctx
- end
-
- return ctx.dup
- end
-
- def list_blocks(iseq, pc)
- rjit_blocks(iseq)[pc]
- end
-
- # @param [Integer] pc
- # @param [RubyVM::RJIT::Context] ctx
- # @return [RubyVM::RJIT::Block,NilClass]
- def find_block(iseq, pc, ctx)
- versions = rjit_blocks(iseq)[pc]
-
- best_version = nil
- best_diff = Float::INFINITY
-
- versions.each do |block|
- # Note that we always prefer the first matching
- # version found because of inline-cache chains
- case ctx.diff(block.ctx)
- in TypeDiff::Compatible[diff] if diff < best_diff
- best_version = block
- best_diff = diff
- else
- end
- end
-
- return best_version
- end
-
- # @param [RubyVM::RJIT::Block] block
- def add_block(iseq, block)
- rjit_blocks(iseq)[block.pc] << block
- end
-
- # @param [RubyVM::RJIT::Block] block
- def remove_block(iseq, block)
- rjit_blocks(iseq)[block.pc].delete(block)
- end
-
- def rjit_blocks(iseq)
- # Guard against ISEQ GC at random moments
-
- unless C.imemo_type_p(iseq, C.imemo_iseq)
- return Hash.new { |h, k| h[k] = [] }
- end
-
- unless iseq.body.rjit_blocks
- iseq.body.rjit_blocks = Hash.new { |blocks, pc| blocks[pc] = [] }
- # For some reason, rb_rjit_iseq_mark didn't protect this Hash
- # from being freed. So we rely on GC_REFS to keep the Hash.
- GC_REFS << iseq.body.rjit_blocks
- end
- iseq.body.rjit_blocks
- end
-
- def iseq_lineno(iseq, pc)
- C.rb_iseq_line_no(iseq, (pc - iseq.body.iseq_encoded.to_i) / C.VALUE.size)
- rescue RangeError # bignum too big to convert into `unsigned long long' (RangeError)
- -1
- end
-
- # Verify the ctx's types and mappings against the compile-time stack, self, and locals.
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- def verify_ctx(jit, ctx)
- # Only able to check types when at current insn
- assert(jit.at_current_insn?)
-
- self_val = jit.peek_at_self
- self_val_type = Type.from(self_val)
-
- # Verify self operand type
- assert_compatible(self_val_type, ctx.get_opnd_type(SelfOpnd))
-
- # Verify stack operand types
- [ctx.stack_size, MAX_TEMP_TYPES].min.times do |i|
- learned_mapping, learned_type = ctx.get_opnd_mapping(StackOpnd[i])
- stack_val = jit.peek_at_stack(i)
- val_type = Type.from(stack_val)
-
- case learned_mapping
- in MapToSelf
- if C.to_value(self_val) != C.to_value(stack_val)
- raise "verify_ctx: stack value was mapped to self, but values did not match:\n"\
- "stack: #{stack_val.inspect}, self: #{self_val.inspect}"
- end
- in MapToLocal[local_idx]
- local_val = jit.peek_at_local(local_idx)
- if C.to_value(local_val) != C.to_value(stack_val)
- raise "verify_ctx: stack value was mapped to local, but values did not match:\n"\
- "stack: #{stack_val.inspect}, local: #{local_val.inspect}"
- end
- in MapToStack
- # noop
- end
-
- # If the actual type differs from the learned type
- assert_compatible(val_type, learned_type)
- end
-
- # Verify local variable types
- local_table_size = jit.iseq.body.local_table_size
- [local_table_size, MAX_TEMP_TYPES].min.times do |i|
- learned_type = ctx.get_local_type(i)
- local_val = jit.peek_at_local(i)
- local_type = Type.from(local_val)
-
- assert_compatible(local_type, learned_type)
- end
- end
-
- def assert_compatible(actual_type, ctx_type)
- if actual_type.diff(ctx_type) == TypeDiff::Incompatible
- raise "verify_ctx: ctx type (#{ctx_type.type.inspect}) is incompatible with actual type (#{actual_type.type.inspect})"
- end
- end
-
- def assert(cond)
- unless cond
- raise "'#{cond.inspect}' was not true"
- end
- end
-
- def supported_platform?
- return @supported_platform if defined?(@supported_platform)
- @supported_platform = RUBY_PLATFORM.match?(/x86_64/).tap do |supported|
- warn "warning: RJIT does not support #{RUBY_PLATFORM} yet" unless supported
- end
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/context.rb b/lib/ruby_vm/rjit/context.rb
deleted file mode 100644
index a2a7ecc6dc..0000000000
--- a/lib/ruby_vm/rjit/context.rb
+++ /dev/null
@@ -1,377 +0,0 @@
-module RubyVM::RJIT
- # Maximum number of temp value types we keep track of
- MAX_TEMP_TYPES = 8
- # Maximum number of local variable types we keep track of
- MAX_LOCAL_TYPES = 8
-
- # Operand to a YARV bytecode instruction
- SelfOpnd = :SelfOpnd # The value is self
- StackOpnd = Data.define(:index) # Temporary stack operand with stack index
-
- # Potential mapping of a value on the temporary stack to self,
- # a local variable, or constant so that we can track its type
- MapToStack = :MapToStack # Normal stack value
- MapToSelf = :MapToSelf # Temp maps to the self operand
- MapToLocal = Data.define(:local_index) # Temp maps to a local variable with index
-
- class Context < Struct.new(
- :stack_size, # @param [Integer] The number of values on the stack
- :sp_offset, # @param [Integer] JIT sp offset relative to the interpreter's sp
- :chain_depth, # @param [Integer] jit_chain_guard depth
- :local_types, # @param [Array<RubyVM::RJIT::Type>] Local variable types we keep track of
- :temp_types, # @param [Array<RubyVM::RJIT::Type>] Temporary variable types we keep track of
- :self_type, # @param [RubyVM::RJIT::Type] Type we track for self
- :temp_mapping, # @param [Array<Symbol>] Mapping of temp stack entries to types we track
- )
- def initialize(
- stack_size: 0,
- sp_offset: 0,
- chain_depth: 0,
- local_types: [Type::Unknown] * MAX_LOCAL_TYPES,
- temp_types: [Type::Unknown] * MAX_TEMP_TYPES,
- self_type: Type::Unknown,
- temp_mapping: [MapToStack] * MAX_TEMP_TYPES
- ) = super
-
- # Deep dup by default for safety
- def dup
- ctx = super
- ctx.local_types = ctx.local_types.dup
- ctx.temp_types = ctx.temp_types.dup
- ctx.temp_mapping = ctx.temp_mapping.dup
- ctx
- end
-
- # Create a new Context instance with a given stack_size and sp_offset adjusted
- # accordingly. This is useful when you want to virtually rewind a stack_size for
- # generating a side exit while considering past sp_offset changes on gen_save_sp.
- def with_stack_size(stack_size)
- ctx = self.dup
- ctx.sp_offset -= ctx.stack_size - stack_size
- ctx.stack_size = stack_size
- ctx
- end
-
- def stack_opnd(depth_from_top)
- [SP, C.VALUE.size * (self.sp_offset - 1 - depth_from_top)]
- end
-
- def sp_opnd(offset_bytes = 0)
- [SP, (C.VALUE.size * self.sp_offset) + offset_bytes]
- end
-
- # Push one new value on the temp stack with an explicit mapping
- # Return a pointer to the new stack top
- def stack_push_mapping(mapping_temp_type)
- stack_size = self.stack_size
-
- # Keep track of the type and mapping of the value
- if stack_size < MAX_TEMP_TYPES
- mapping, temp_type = mapping_temp_type
- self.temp_mapping[stack_size] = mapping
- self.temp_types[stack_size] = temp_type
-
- case mapping
- in MapToLocal[idx]
- assert(idx < MAX_LOCAL_TYPES)
- else
- end
- end
-
- self.stack_size += 1
- self.sp_offset += 1
-
- return self.stack_opnd(0)
- end
-
- # Push one new value on the temp stack
- # Return a pointer to the new stack top
- def stack_push(val_type)
- return self.stack_push_mapping([MapToStack, val_type])
- end
-
- # Push the self value on the stack
- def stack_push_self
- return self.stack_push_mapping([MapToStack, Type::Unknown])
- end
-
- # Push a local variable on the stack
- def stack_push_local(local_idx)
- if local_idx >= MAX_LOCAL_TYPES
- return self.stack_push(Type::Unknown)
- end
-
- return self.stack_push_mapping([MapToLocal[local_idx], Type::Unknown])
- end
-
- # Pop N values off the stack
- # Return a pointer to the stack top before the pop operation
- def stack_pop(n = 1)
- assert(n <= self.stack_size)
-
- top = self.stack_opnd(0)
-
- # Clear the types of the popped values
- n.times do |i|
- idx = self.stack_size - i - 1
-
- if idx < MAX_TEMP_TYPES
- self.temp_types[idx] = Type::Unknown
- self.temp_mapping[idx] = MapToStack
- end
- end
-
- self.stack_size -= n
- self.sp_offset -= n
-
- return top
- end
-
- def shift_stack(argc)
- assert(argc < self.stack_size)
-
- method_name_index = self.stack_size - argc - 1
-
- (method_name_index...(self.stack_size - 1)).each do |i|
- if i + 1 < MAX_TEMP_TYPES
- self.temp_types[i] = self.temp_types[i + 1]
- self.temp_mapping[i] = self.temp_mapping[i + 1]
- end
- end
- self.stack_pop(1)
- end
-
- # Get the type of an instruction operand
- def get_opnd_type(opnd)
- case opnd
- in SelfOpnd
- self.self_type
- in StackOpnd[idx]
- assert(idx < self.stack_size)
- stack_idx = self.stack_size - 1 - idx
-
- # If outside of tracked range, do nothing
- if stack_idx >= MAX_TEMP_TYPES
- return Type::Unknown
- end
-
- mapping = self.temp_mapping[stack_idx]
-
- case mapping
- in MapToSelf
- self.self_type
- in MapToStack
- self.temp_types[self.stack_size - 1 - idx]
- in MapToLocal[idx]
- assert(idx < MAX_LOCAL_TYPES)
- self.local_types[idx]
- end
- end
- end
-
- # Get the currently tracked type for a local variable
- def get_local_type(idx)
- self.local_types[idx] || Type::Unknown
- end
-
- # Upgrade (or "learn") the type of an instruction operand
- # This value must be compatible and at least as specific as the previously known type.
- # If this value originated from self, or an lvar, the learned type will be
- # propagated back to its source.
- def upgrade_opnd_type(opnd, opnd_type)
- case opnd
- in SelfOpnd
- self.self_type = self.self_type.upgrade(opnd_type)
- in StackOpnd[idx]
- assert(idx < self.stack_size)
- stack_idx = self.stack_size - 1 - idx
-
- # If outside of tracked range, do nothing
- if stack_idx >= MAX_TEMP_TYPES
- return
- end
-
- mapping = self.temp_mapping[stack_idx]
-
- case mapping
- in MapToSelf
- self.self_type = self.self_type.upgrade(opnd_type)
- in MapToStack
- self.temp_types[stack_idx] = self.temp_types[stack_idx].upgrade(opnd_type)
- in MapToLocal[idx]
- assert(idx < MAX_LOCAL_TYPES)
- self.local_types[idx] = self.local_types[idx].upgrade(opnd_type)
- end
- end
- end
-
- # Get both the type and mapping (where the value originates) of an operand.
- # This is can be used with stack_push_mapping or set_opnd_mapping to copy
- # a stack value's type while maintaining the mapping.
- def get_opnd_mapping(opnd)
- opnd_type = self.get_opnd_type(opnd)
-
- case opnd
- in SelfOpnd
- return [MapToSelf, opnd_type]
- in StackOpnd[idx]
- assert(idx < self.stack_size)
- stack_idx = self.stack_size - 1 - idx
-
- if stack_idx < MAX_TEMP_TYPES
- return [self.temp_mapping[stack_idx], opnd_type]
- else
- # We can't know the source of this stack operand, so we assume it is
- # a stack-only temporary. type will be UNKNOWN
- assert(opnd_type == Type::Unknown)
- return [MapToStack, opnd_type]
- end
- end
- end
-
- # Overwrite both the type and mapping of a stack operand.
- def set_opnd_mapping(opnd, mapping_opnd_type)
- case opnd
- in SelfOpnd
- raise 'self always maps to self'
- in StackOpnd[idx]
- assert(idx < self.stack_size)
- stack_idx = self.stack_size - 1 - idx
-
- # If outside of tracked range, do nothing
- if stack_idx >= MAX_TEMP_TYPES
- return
- end
-
- mapping, opnd_type = mapping_opnd_type
- self.temp_mapping[stack_idx] = mapping
-
- # Only used when mapping == MAP_STACK
- self.temp_types[stack_idx] = opnd_type
- end
- end
-
- # Set the type of a local variable
- def set_local_type(local_idx, local_type)
- if local_idx >= MAX_LOCAL_TYPES
- return
- end
-
- # If any values on the stack map to this local we must detach them
- MAX_TEMP_TYPES.times do |stack_idx|
- case self.temp_mapping[stack_idx]
- in MapToStack
- # noop
- in MapToSelf
- # noop
- in MapToLocal[idx]
- if idx == local_idx
- self.temp_types[stack_idx] = self.local_types[idx]
- self.temp_mapping[stack_idx] = MapToStack
- else
- # noop
- end
- end
- end
-
- self.local_types[local_idx] = local_type
- end
-
- # Erase local variable type information
- # eg: because of a call we can't track
- def clear_local_types
- # When clearing local types we must detach any stack mappings to those
- # locals. Even if local values may have changed, stack values will not.
- MAX_TEMP_TYPES.times do |stack_idx|
- case self.temp_mapping[stack_idx]
- in MapToStack
- # noop
- in MapToSelf
- # noop
- in MapToLocal[local_idx]
- self.temp_types[stack_idx] = self.local_types[local_idx]
- self.temp_mapping[stack_idx] = MapToStack
- end
- end
-
- # Clear the local types
- self.local_types = [Type::Unknown] * MAX_LOCAL_TYPES
- end
-
- # Compute a difference score for two context objects
- def diff(dst)
- # Self is the source context (at the end of the predecessor)
- src = self
-
- # Can only lookup the first version in the chain
- if dst.chain_depth != 0
- return TypeDiff::Incompatible
- end
-
- # Blocks with depth > 0 always produce new versions
- # Sidechains cannot overlap
- if src.chain_depth != 0
- return TypeDiff::Incompatible
- end
-
- if dst.stack_size != src.stack_size
- return TypeDiff::Incompatible
- end
-
- if dst.sp_offset != src.sp_offset
- return TypeDiff::Incompatible
- end
-
- # Difference sum
- diff = 0
-
- # Check the type of self
- diff += case src.self_type.diff(dst.self_type)
- in TypeDiff::Compatible[diff] then diff
- in TypeDiff::Incompatible then return TypeDiff::Incompatible
- end
-
- # For each local type we track
- src.local_types.size.times do |i|
- t_src = src.local_types[i]
- t_dst = dst.local_types[i]
- diff += case t_src.diff(t_dst)
- in TypeDiff::Compatible[diff] then diff
- in TypeDiff::Incompatible then return TypeDiff::Incompatible
- end
- end
-
- # For each value on the temp stack
- src.stack_size.times do |i|
- src_mapping, src_type = src.get_opnd_mapping(StackOpnd[i])
- dst_mapping, dst_type = dst.get_opnd_mapping(StackOpnd[i])
-
- # If the two mappings aren't the same
- if src_mapping != dst_mapping
- if dst_mapping == MapToStack
- # We can safely drop information about the source of the temp
- # stack operand.
- diff += 1
- else
- return TypeDiff::Incompatible
- end
- end
-
- diff += case src_type.diff(dst_type)
- in TypeDiff::Compatible[diff] then diff
- in TypeDiff::Incompatible then return TypeDiff::Incompatible
- end
- end
-
- return TypeDiff::Compatible[diff]
- end
-
- private
-
- def assert(cond)
- unless cond
- raise "'#{cond.inspect}' was not true"
- end
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/entry_stub.rb b/lib/ruby_vm/rjit/entry_stub.rb
deleted file mode 100644
index 9bcef14053..0000000000
--- a/lib/ruby_vm/rjit/entry_stub.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-module RubyVM::RJIT
- class EntryStub < Struct.new(
- :start_addr, # @param [Integer] Stub source start address to be re-generated
- :end_addr, # @param [Integer] Stub source end address to be re-generated
- )
- end
-end
diff --git a/lib/ruby_vm/rjit/exit_compiler.rb b/lib/ruby_vm/rjit/exit_compiler.rb
deleted file mode 100644
index 1ced2141a4..0000000000
--- a/lib/ruby_vm/rjit/exit_compiler.rb
+++ /dev/null
@@ -1,164 +0,0 @@
-module RubyVM::RJIT
- class ExitCompiler
- def initialize = freeze
-
- # Used for invalidating a block on entry.
- # @param pc [Integer]
- # @param asm [RubyVM::RJIT::Assembler]
- def compile_entry_exit(pc, ctx, asm, cause:)
- # Fix pc/sp offsets for the interpreter
- save_pc_and_sp(pc, ctx, asm, reset_sp_offset: false)
-
- # Increment per-insn exit counter
- count_insn_exit(pc, asm)
-
- # Restore callee-saved registers
- asm.comment("#{cause}: entry exit")
- asm.pop(SP)
- asm.pop(EC)
- asm.pop(CFP)
-
- asm.mov(C_RET, Qundef)
- asm.ret
- end
-
- # Set to cfp->jit_return by default for leave insn
- # @param asm [RubyVM::RJIT::Assembler]
- def compile_leave_exit(asm)
- asm.comment('default cfp->jit_return')
-
- # Restore callee-saved registers
- asm.pop(SP)
- asm.pop(EC)
- asm.pop(CFP)
-
- # :rax is written by #leave
- asm.ret
- end
-
- # Fire cfunc events on invalidation by TracePoint
- # @param asm [RubyVM::RJIT::Assembler]
- def compile_full_cfunc_return(asm)
- # This chunk of code expects REG_EC to be filled properly and
- # RAX to contain the return value of the C method.
-
- asm.comment('full cfunc return')
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], :rax)
- asm.call(C.rjit_full_cfunc_return)
-
- # TODO: count the exit
-
- # Restore callee-saved registers
- asm.pop(SP)
- asm.pop(EC)
- asm.pop(CFP)
-
- asm.mov(C_RET, Qundef)
- asm.ret
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def compile_side_exit(pc, ctx, asm)
- # Fix pc/sp offsets for the interpreter
- save_pc_and_sp(pc, ctx.dup, asm) # dup to avoid sp_offset update
-
- # Increment per-insn exit counter
- count_insn_exit(pc, asm)
-
- # Restore callee-saved registers
- asm.comment("exit to interpreter on #{pc_to_insn(pc).name}")
- asm.pop(SP)
- asm.pop(EC)
- asm.pop(CFP)
-
- asm.mov(C_RET, Qundef)
- asm.ret
- end
-
- # @param asm [RubyVM::RJIT::Assembler]
- # @param entry_stub [RubyVM::RJIT::EntryStub]
- def compile_entry_stub(asm, entry_stub)
- # Call rb_rjit_entry_stub_hit
- asm.comment('entry stub hit')
- asm.mov(C_ARGS[0], to_value(entry_stub))
- asm.call(C.rb_rjit_entry_stub_hit)
-
- # Jump to the address returned by rb_rjit_entry_stub_hit
- asm.jmp(:rax)
- end
-
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- # @param branch_stub [RubyVM::RJIT::BranchStub]
- # @param target0_p [TrueClass,FalseClass]
- def compile_branch_stub(ctx, asm, branch_stub, target0_p)
- # Call rb_rjit_branch_stub_hit
- iseq = branch_stub.iseq
- if C.rjit_opts.dump_disasm && C.imemo_type_p(iseq, C.imemo_iseq) # Guard against ISEQ GC at random moments
- asm.comment("branch stub hit: #{iseq.body.location.label}@#{C.rb_iseq_path(iseq)}:#{iseq_lineno(iseq, target0_p ? branch_stub.target0.pc : branch_stub.target1.pc)}")
- end
- asm.mov(:rdi, to_value(branch_stub))
- asm.mov(:esi, ctx.sp_offset)
- asm.mov(:edx, target0_p ? 1 : 0)
- asm.call(C.rb_rjit_branch_stub_hit)
-
- # Jump to the address returned by rb_rjit_branch_stub_hit
- asm.jmp(:rax)
- end
-
- private
-
- def pc_to_insn(pc)
- Compiler.decode_insn(C.VALUE.new(pc).*)
- end
-
- # @param pc [Integer]
- # @param asm [RubyVM::RJIT::Assembler]
- def count_insn_exit(pc, asm)
- if C.rjit_opts.stats
- insn = Compiler.decode_insn(C.VALUE.new(pc).*)
- asm.comment("increment insn exit: #{insn.name}")
- asm.mov(:rax, (C.rjit_insn_exits + insn.bin).to_i)
- asm.add([:rax], 1) # TODO: lock
- end
- if C.rjit_opts.trace_exits
- asm.comment('rjit_record_exit_stack')
- asm.mov(C_ARGS[0], pc)
- asm.call(C.rjit_record_exit_stack)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def save_pc_and_sp(pc, ctx, asm, reset_sp_offset: true)
- # Update pc (TODO: manage PC offset?)
- asm.comment("save PC#{' and SP' if ctx.sp_offset != 0} to CFP")
- asm.mov(:rax, pc) # rax = jit.pc
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax) # cfp->pc = rax
-
- # Update sp
- if ctx.sp_offset != 0
- asm.add(SP, C.VALUE.size * ctx.sp_offset) # sp += stack_size
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], SP) # cfp->sp = sp
- if reset_sp_offset
- ctx.sp_offset = 0
- end
- end
- end
-
- def to_value(obj)
- GC_REFS << obj
- C.to_value(obj)
- end
-
- def iseq_lineno(iseq, pc)
- C.rb_iseq_line_no(iseq, (pc - iseq.body.iseq_encoded.to_i) / C.VALUE.size)
- rescue RangeError # bignum too big to convert into `unsigned long long' (RangeError)
- -1
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/hooks.rb b/lib/ruby_vm/rjit/hooks.rb
deleted file mode 100644
index ea9d7bf5a8..0000000000
--- a/lib/ruby_vm/rjit/hooks.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-module RubyVM::RJIT
- module Hooks # :nodoc: all
- def self.on_bop_redefined(_redefined_flag, _bop)
- # C.rjit_cancel_all("BOP is redefined")
- end
-
- def self.on_cme_invalidate(cme)
- cme = C.rb_callable_method_entry_struct.new(cme)
- Invariants.on_cme_invalidate(cme)
- end
-
- def self.on_ractor_spawn
- # C.rjit_cancel_all("Ractor is spawned")
- end
-
- # Global constant changes like const_set
- def self.on_constant_state_changed(id)
- Invariants.on_constant_state_changed(id)
- end
-
- # ISEQ-specific constant invalidation
- def self.on_constant_ic_update(iseq, ic, insn_idx)
- iseq = C.rb_iseq_t.new(iseq)
- ic = C.IC.new(ic)
- Invariants.on_constant_ic_update(iseq, ic, insn_idx)
- end
-
- def self.on_tracing_invalidate_all(_new_iseq_events)
- Invariants.on_tracing_invalidate_all
- end
-
- def self.on_update_references
- Invariants.on_update_references
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/insn_compiler.rb b/lib/ruby_vm/rjit/insn_compiler.rb
deleted file mode 100644
index a33ba9f468..0000000000
--- a/lib/ruby_vm/rjit/insn_compiler.rb
+++ /dev/null
@@ -1,6046 +0,0 @@
-# frozen_string_literal: true
-module RubyVM::RJIT
- class InsnCompiler
- # struct rb_calling_info. Storing flags instead of ci.
- CallingInfo = Struct.new(:argc, :flags, :kwarg, :ci_addr, :send_shift, :block_handler) do
- def kw_splat = flags & C::VM_CALL_KW_SPLAT != 0
- end
-
- # @param ocb [CodeBlock]
- # @param exit_compiler [RubyVM::RJIT::ExitCompiler]
- def initialize(cb, ocb, exit_compiler)
- @ocb = ocb
- @exit_compiler = exit_compiler
-
- @cfunc_codegen_table = {}
- register_cfunc_codegen_funcs
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- # @param insn `RubyVM::RJIT::Instruction`
- def compile(jit, ctx, asm, insn)
- asm.incr_counter(:rjit_insns_count)
-
- stack = ctx.stack_size.times.map do |stack_idx|
- ctx.get_opnd_type(StackOpnd[ctx.stack_size - stack_idx - 1]).type
- end
- locals = jit.iseq.body.local_table_size.times.map do |local_idx|
- (ctx.local_types[local_idx] || Type::Unknown).type
- end
-
- insn_idx = format('%04d', (jit.pc.to_i - jit.iseq.body.iseq_encoded.to_i) / C.VALUE.size)
- asm.comment("Insn: #{insn_idx} #{insn.name} (stack: [#{stack.join(', ')}], locals: [#{locals.join(', ')}])")
-
- # 83/102
- case insn.name
- when :nop then nop(jit, ctx, asm)
- when :getlocal then getlocal(jit, ctx, asm)
- when :setlocal then setlocal(jit, ctx, asm)
- when :getblockparam then getblockparam(jit, ctx, asm)
- # setblockparam
- when :getblockparamproxy then getblockparamproxy(jit, ctx, asm)
- when :getspecial then getspecial(jit, ctx, asm)
- # setspecial
- when :getinstancevariable then getinstancevariable(jit, ctx, asm)
- when :setinstancevariable then setinstancevariable(jit, ctx, asm)
- when :getclassvariable then getclassvariable(jit, ctx, asm)
- when :setclassvariable then setclassvariable(jit, ctx, asm)
- when :opt_getconstant_path then opt_getconstant_path(jit, ctx, asm)
- when :getconstant then getconstant(jit, ctx, asm)
- # setconstant
- when :getglobal then getglobal(jit, ctx, asm)
- # setglobal
- when :putnil then putnil(jit, ctx, asm)
- when :putself then putself(jit, ctx, asm)
- when :putobject then putobject(jit, ctx, asm)
- when :putspecialobject then putspecialobject(jit, ctx, asm)
- when :putstring then putstring(jit, ctx, asm)
- when :putchilledstring then putchilledstring(jit, ctx, asm)
- when :concatstrings then concatstrings(jit, ctx, asm)
- when :anytostring then anytostring(jit, ctx, asm)
- when :toregexp then toregexp(jit, ctx, asm)
- when :intern then intern(jit, ctx, asm)
- when :newarray then newarray(jit, ctx, asm)
- when :duparray then duparray(jit, ctx, asm)
- # duphash
- when :expandarray then expandarray(jit, ctx, asm)
- when :concatarray then concatarray(jit, ctx, asm)
- when :splatarray then splatarray(jit, ctx, asm)
- when :newhash then newhash(jit, ctx, asm)
- when :newrange then newrange(jit, ctx, asm)
- when :pop then pop(jit, ctx, asm)
- when :dup then dup(jit, ctx, asm)
- when :dupn then dupn(jit, ctx, asm)
- when :swap then swap(jit, ctx, asm)
- # opt_reverse
- when :topn then topn(jit, ctx, asm)
- when :setn then setn(jit, ctx, asm)
- when :adjuststack then adjuststack(jit, ctx, asm)
- when :defined then defined(jit, ctx, asm)
- when :definedivar then definedivar(jit, ctx, asm)
- # checkmatch
- when :checkkeyword then checkkeyword(jit, ctx, asm)
- # checktype
- # defineclass
- # definemethod
- # definesmethod
- when :send then send(jit, ctx, asm)
- when :opt_send_without_block then opt_send_without_block(jit, ctx, asm)
- when :objtostring then objtostring(jit, ctx, asm)
- when :opt_str_freeze then opt_str_freeze(jit, ctx, asm)
- when :opt_ary_freeze then opt_ary_freeze(jit, ctx, asm)
- when :opt_hash_freeze then opt_hash_freeze(jit, ctx, asm)
- when :opt_nil_p then opt_nil_p(jit, ctx, asm)
- # opt_str_uminus
- when :opt_newarray_send then opt_newarray_send(jit, ctx, asm)
- when :invokesuper then invokesuper(jit, ctx, asm)
- when :invokeblock then invokeblock(jit, ctx, asm)
- when :leave then leave(jit, ctx, asm)
- when :throw then throw(jit, ctx, asm)
- when :jump then jump(jit, ctx, asm)
- when :branchif then branchif(jit, ctx, asm)
- when :branchunless then branchunless(jit, ctx, asm)
- when :branchnil then branchnil(jit, ctx, asm)
- # once
- when :opt_case_dispatch then opt_case_dispatch(jit, ctx, asm)
- when :opt_plus then opt_plus(jit, ctx, asm)
- when :opt_minus then opt_minus(jit, ctx, asm)
- when :opt_mult then opt_mult(jit, ctx, asm)
- when :opt_div then opt_div(jit, ctx, asm)
- when :opt_mod then opt_mod(jit, ctx, asm)
- when :opt_eq then opt_eq(jit, ctx, asm)
- when :opt_neq then opt_neq(jit, ctx, asm)
- when :opt_lt then opt_lt(jit, ctx, asm)
- when :opt_le then opt_le(jit, ctx, asm)
- when :opt_gt then opt_gt(jit, ctx, asm)
- when :opt_ge then opt_ge(jit, ctx, asm)
- when :opt_ltlt then opt_ltlt(jit, ctx, asm)
- when :opt_and then opt_and(jit, ctx, asm)
- when :opt_or then opt_or(jit, ctx, asm)
- when :opt_aref then opt_aref(jit, ctx, asm)
- when :opt_aset then opt_aset(jit, ctx, asm)
- # opt_aset_with
- # opt_aref_with
- when :opt_length then opt_length(jit, ctx, asm)
- when :opt_size then opt_size(jit, ctx, asm)
- when :opt_empty_p then opt_empty_p(jit, ctx, asm)
- when :opt_succ then opt_succ(jit, ctx, asm)
- when :opt_not then opt_not(jit, ctx, asm)
- when :opt_regexpmatch2 then opt_regexpmatch2(jit, ctx, asm)
- # invokebuiltin
- when :opt_invokebuiltin_delegate then opt_invokebuiltin_delegate(jit, ctx, asm)
- when :opt_invokebuiltin_delegate_leave then opt_invokebuiltin_delegate_leave(jit, ctx, asm)
- when :getlocal_WC_0 then getlocal_WC_0(jit, ctx, asm)
- when :getlocal_WC_1 then getlocal_WC_1(jit, ctx, asm)
- when :setlocal_WC_0 then setlocal_WC_0(jit, ctx, asm)
- when :setlocal_WC_1 then setlocal_WC_1(jit, ctx, asm)
- when :putobject_INT2FIX_0_ then putobject_INT2FIX_0_(jit, ctx, asm)
- when :putobject_INT2FIX_1_ then putobject_INT2FIX_1_(jit, ctx, asm)
- else CantCompile
- end
- end
-
- private
-
- #
- # Insns
- #
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def nop(jit, ctx, asm)
- # Do nothing
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getlocal(jit, ctx, asm)
- idx = jit.operand(0)
- level = jit.operand(1)
- jit_getlocal_generic(jit, ctx, asm, idx:, level:)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getlocal_WC_0(jit, ctx, asm)
- idx = jit.operand(0)
- jit_getlocal_generic(jit, ctx, asm, idx:, level: 0)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getlocal_WC_1(jit, ctx, asm)
- idx = jit.operand(0)
- jit_getlocal_generic(jit, ctx, asm, idx:, level: 1)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def setlocal(jit, ctx, asm)
- idx = jit.operand(0)
- level = jit.operand(1)
- jit_setlocal_generic(jit, ctx, asm, idx:, level:)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def setlocal_WC_0(jit, ctx, asm)
- idx = jit.operand(0)
- jit_setlocal_generic(jit, ctx, asm, idx:, level: 0)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def setlocal_WC_1(jit, ctx, asm)
- idx = jit.operand(0)
- jit_setlocal_generic(jit, ctx, asm, idx:, level: 1)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getblockparam(jit, ctx, asm)
- # EP level
- level = jit.operand(1)
-
- # Save the PC and SP because we might allocate
- jit_prepare_routine_call(jit, ctx, asm)
-
- # A mirror of the interpreter code. Checking for the case
- # where it's pushing rb_block_param_proxy.
- side_exit = side_exit(jit, ctx)
-
- # Load environment pointer EP from CFP
- ep_reg = :rax
- jit_get_ep(asm, level, reg: ep_reg)
-
- # Bail when VM_ENV_FLAGS(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM) is non zero
- # FIXME: This is testing bits in the same place that the WB check is testing.
- # We should combine these at some point
- asm.test([ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_FLAGS], C::VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM)
-
- # If the frame flag has been modified, then the actual proc value is
- # already in the EP and we should just use the value.
- frame_flag_modified = asm.new_label('frame_flag_modified')
- asm.jnz(frame_flag_modified)
-
- # This instruction writes the block handler to the EP. If we need to
- # fire a write barrier for the write, then exit (we'll let the
- # interpreter handle it so it can fire the write barrier).
- # flags & VM_ENV_FLAG_WB_REQUIRED
- asm.test([ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_FLAGS], C::VM_ENV_FLAG_WB_REQUIRED)
-
- # if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0
- asm.jnz(side_exit)
-
- # Convert the block handler in to a proc
- # call rb_vm_bh_to_procval(const rb_execution_context_t *ec, VALUE block_handler)
- asm.mov(C_ARGS[0], EC)
- # The block handler for the current frame
- # note, VM_ASSERT(VM_ENV_LOCAL_P(ep))
- asm.mov(C_ARGS[1], [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL])
- asm.call(C.rb_vm_bh_to_procval)
-
- # Load environment pointer EP from CFP (again)
- ep_reg = :rcx
- jit_get_ep(asm, level, reg: ep_reg)
-
- # Write the value at the environment pointer
- idx = jit.operand(0)
- offs = -(C.VALUE.size * idx)
- asm.mov([ep_reg, offs], C_RET);
-
- # Set the frame modified flag
- asm.mov(:rax, [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_FLAGS]) # flag_check
- asm.or(:rax, C::VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM) # modified_flag
- asm.mov([ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_FLAGS], :rax)
-
- asm.write_label(frame_flag_modified)
-
- # Push the proc on the stack
- stack_ret = ctx.stack_push(Type::Unknown)
- ep_reg = :rax
- jit_get_ep(asm, level, reg: ep_reg)
- asm.mov(:rax, [ep_reg, offs])
- asm.mov(stack_ret, :rax)
-
- KeepCompiling
- end
-
- # setblockparam
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getblockparamproxy(jit, ctx, asm)
- # To get block_handler
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- starting_context = ctx.dup # make a copy for use with jit_chain_guard
-
- # A mirror of the interpreter code. Checking for the case
- # where it's pushing rb_block_param_proxy.
- side_exit = side_exit(jit, ctx)
-
- # EP level
- level = jit.operand(1)
-
- # Peek at the block handler so we can check whether it's nil
- comptime_handler = jit.peek_at_block_handler(level)
-
- # When a block handler is present, it should always be a GC-guarded
- # pointer (VM_BH_ISEQ_BLOCK_P)
- if comptime_handler != 0 && comptime_handler & 0x3 != 0x1
- asm.incr_counter(:getblockpp_not_gc_guarded)
- return CantCompile
- end
-
- # Load environment pointer EP from CFP
- ep_reg = :rax
- jit_get_ep(asm, level, reg: ep_reg)
-
- # Bail when VM_ENV_FLAGS(ep, VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM) is non zero
- asm.test([ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_FLAGS], C::VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM)
- asm.jnz(counted_exit(side_exit, :getblockpp_block_param_modified))
-
- # Load the block handler for the current frame
- # note, VM_ASSERT(VM_ENV_LOCAL_P(ep))
- block_handler = :rax
- asm.mov(block_handler, [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL])
-
- # Specialize compilation for the case where no block handler is present
- if comptime_handler == 0
- # Bail if there is a block handler
- asm.cmp(block_handler, 0)
-
- jit_chain_guard(:jnz, jit, starting_context, asm, counted_exit(side_exit, :getblockpp_block_handler_none))
-
- putobject(jit, ctx, asm, val: Qnil)
- else
- # Block handler is a tagged pointer. Look at the tag. 0x03 is from VM_BH_ISEQ_BLOCK_P().
- asm.and(block_handler, 0x3)
-
- # Bail unless VM_BH_ISEQ_BLOCK_P(bh). This also checks for null.
- asm.cmp(block_handler, 0x1)
-
- jit_chain_guard(:jnz, jit, starting_context, asm, counted_exit(side_exit, :getblockpp_not_iseq_block))
-
- # Push rb_block_param_proxy. It's a root, so no need to use jit_mov_gc_ptr.
- top = ctx.stack_push(Type::BlockParamProxy)
- asm.mov(:rax, C.rb_block_param_proxy)
- asm.mov(top, :rax)
- end
-
- jump_to_next_insn(jit, ctx, asm)
-
- EndBlock
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getspecial(jit, ctx, asm)
- # This takes two arguments, key and type
- # key is only used when type == 0
- # A non-zero type determines which type of backref to fetch
- #rb_num_t key = jit.jit_get_arg(0);
- rtype = jit.operand(1)
-
- if rtype == 0
- # not yet implemented
- return CantCompile;
- elsif rtype & 0x01 != 0
- # Fetch a "special" backref based on a char encoded by shifting by 1
-
- # Can raise if matchdata uninitialized
- jit_prepare_routine_call(jit, ctx, asm)
-
- # call rb_backref_get()
- asm.comment('rb_backref_get')
- asm.call(C.rb_backref_get)
-
- asm.mov(C_ARGS[0], C_RET) # backref
- case [rtype >> 1].pack('c')
- in ?&
- asm.comment("rb_reg_last_match")
- asm.call(C.rb_reg_last_match)
- in ?`
- asm.comment("rb_reg_match_pre")
- asm.call(C.rb_reg_match_pre)
- in ?'
- asm.comment("rb_reg_match_post")
- asm.call(C.rb_reg_match_post)
- in ?+
- asm.comment("rb_reg_match_last")
- asm.call(C.rb_reg_match_last)
- end
-
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- else
- # Fetch the N-th match from the last backref based on type shifted by 1
-
- # Can raise if matchdata uninitialized
- jit_prepare_routine_call(jit, ctx, asm)
-
- # call rb_backref_get()
- asm.comment('rb_backref_get')
- asm.call(C.rb_backref_get)
-
- # rb_reg_nth_match((int)(type >> 1), backref);
- asm.comment('rb_reg_nth_match')
- asm.mov(C_ARGS[0], rtype >> 1)
- asm.mov(C_ARGS[1], C_RET) # backref
- asm.call(C.rb_reg_nth_match)
-
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
- end
-
- # setspecial
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getinstancevariable(jit, ctx, asm)
- # Specialize on a compile-time receiver, and split a block for chain guards
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- id = jit.operand(0)
- comptime_obj = jit.peek_at_self
-
- jit_getivar(jit, ctx, asm, comptime_obj, id, nil, SelfOpnd)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def setinstancevariable(jit, ctx, asm)
- starting_context = ctx.dup # make a copy for use with jit_chain_guard
-
- # Defer compilation so we can specialize on a runtime `self`
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- ivar_name = jit.operand(0)
- comptime_receiver = jit.peek_at_self
-
- # If the comptime receiver is frozen, writing an IV will raise an exception
- # and we don't want to JIT code to deal with that situation.
- if C.rb_obj_frozen_p(comptime_receiver)
- asm.incr_counter(:setivar_frozen)
- return CantCompile
- end
-
- # Check if the comptime receiver is a T_OBJECT
- receiver_t_object = C::BUILTIN_TYPE(comptime_receiver) == C::T_OBJECT
-
- # If the receiver isn't a T_OBJECT, or uses a custom allocator,
- # then just write out the IV write as a function call.
- # too-complex shapes can't use index access, so we use rb_ivar_get for them too.
- if !receiver_t_object || shape_too_complex?(comptime_receiver) || ctx.chain_depth >= 10
- asm.comment('call rb_vm_setinstancevariable')
-
- ic = jit.operand(1)
-
- # The function could raise exceptions.
- # Note that this modifies REG_SP, which is why we do it first
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Get the operands from the stack
- val_opnd = ctx.stack_pop(1)
-
- # Call rb_vm_setinstancevariable(iseq, obj, id, val, ic);
- asm.mov(:rdi, jit.iseq.to_i)
- asm.mov(:rsi, [CFP, C.rb_control_frame_t.offsetof(:self)])
- asm.mov(:rdx, ivar_name)
- asm.mov(:rcx, val_opnd)
- asm.mov(:r8, ic)
- asm.call(C.rb_vm_setinstancevariable)
- else
- # Get the iv index
- shape_id = C.rb_shape_get_shape_id(comptime_receiver)
- ivar_index = C.rb_shape_get_iv_index(shape_id, ivar_name)
-
- # Get the receiver
- asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)])
-
- # Generate a side exit
- side_exit = side_exit(jit, ctx)
-
- # Upgrade type
- guard_object_is_heap(jit, ctx, asm, :rax, SelfOpnd, :setivar_not_heap)
-
- asm.comment('guard shape')
- asm.cmp(DwordPtr[:rax, C.rb_shape_id_offset], shape_id)
- megamorphic_side_exit = counted_exit(side_exit, :setivar_megamorphic)
- jit_chain_guard(:jne, jit, starting_context, asm, megamorphic_side_exit)
-
- # If we don't have an instance variable index, then we need to
- # transition out of the current shape.
- if ivar_index.nil?
- shape = C.rb_shape_get_shape_by_id(shape_id)
-
- current_capacity = shape.capacity
- dest_shape = C.rb_shape_get_next_no_warnings(shape, comptime_receiver, ivar_name)
- new_shape_id = C.rb_shape_id(dest_shape)
-
- if new_shape_id == C::OBJ_TOO_COMPLEX_SHAPE_ID
- asm.incr_counter(:setivar_too_complex)
- return CantCompile
- end
-
- ivar_index = shape.next_iv_index
-
- # If the new shape has a different capacity, we need to
- # reallocate the object.
- needs_extension = dest_shape.capacity != shape.capacity
-
- if needs_extension
- # Generate the C call so that runtime code will increase
- # the capacity and set the buffer.
- asm.mov(C_ARGS[0], :rax)
- asm.mov(C_ARGS[1], current_capacity)
- asm.mov(C_ARGS[2], dest_shape.capacity)
- asm.call(C.rb_ensure_iv_list_size)
-
- # Load the receiver again after the function call
- asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)])
- end
-
- write_val = ctx.stack_pop(1)
- jit_write_iv(asm, comptime_receiver, :rax, :rcx, ivar_index, write_val, needs_extension)
-
- # Store the new shape
- asm.comment('write shape')
- asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)]) # reload after jit_write_iv
- asm.mov(DwordPtr[:rax, C.rb_shape_id_offset], new_shape_id)
- else
- # If the iv index already exists, then we don't need to
- # transition to a new shape. The reason is because we find
- # the iv index by searching up the shape tree. If we've
- # made the transition already, then there's no reason to
- # update the shape on the object. Just set the IV.
- write_val = ctx.stack_pop(1)
- jit_write_iv(asm, comptime_receiver, :rax, :rcx, ivar_index, write_val, false)
- end
-
- skip_wb = asm.new_label('skip_wb')
- # If the value we're writing is an immediate, we don't need to WB
- asm.test(write_val, C::RUBY_IMMEDIATE_MASK)
- asm.jnz(skip_wb)
-
- # If the value we're writing is nil or false, we don't need to WB
- asm.cmp(write_val, Qnil)
- asm.jbe(skip_wb)
-
- asm.comment('write barrier')
- asm.mov(C_ARGS[0], [CFP, C.rb_control_frame_t.offsetof(:self)]) # reload after jit_write_iv
- asm.mov(C_ARGS[1], write_val)
- asm.call(C.rb_gc_writebarrier)
-
- asm.write_label(skip_wb)
- end
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getclassvariable(jit, ctx, asm)
- # rb_vm_getclassvariable can raise exceptions.
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.mov(C_ARGS[0], [CFP, C.rb_control_frame_t.offsetof(:iseq)])
- asm.mov(C_ARGS[1], CFP)
- asm.mov(C_ARGS[2], jit.operand(0))
- asm.mov(C_ARGS[3], jit.operand(1))
- asm.call(C.rb_vm_getclassvariable)
-
- top = ctx.stack_push(Type::Unknown)
- asm.mov(top, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def setclassvariable(jit, ctx, asm)
- # rb_vm_setclassvariable can raise exceptions.
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.mov(C_ARGS[0], [CFP, C.rb_control_frame_t.offsetof(:iseq)])
- asm.mov(C_ARGS[1], CFP)
- asm.mov(C_ARGS[2], jit.operand(0))
- asm.mov(C_ARGS[3], ctx.stack_pop(1))
- asm.mov(C_ARGS[4], jit.operand(1))
- asm.call(C.rb_vm_setclassvariable)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_getconstant_path(jit, ctx, asm)
- # Cut the block for invalidation
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- ic = C.iseq_inline_constant_cache.new(jit.operand(0))
- idlist = ic.segments
-
- # Make sure there is an exit for this block as the interpreter might want
- # to invalidate this block from rb_rjit_constant_ic_update().
- # For now, we always take an entry exit even if it was a side exit.
- Invariants.ensure_block_entry_exit(jit, cause: 'opt_getconstant_path')
-
- # See vm_ic_hit_p(). The same conditions are checked in yjit_constant_ic_update().
- ice = ic.entry
- if ice.nil?
- # In this case, leave a block that unconditionally side exits
- # for the interpreter to invalidate.
- asm.incr_counter(:optgetconst_not_cached)
- return CantCompile
- end
-
- if ice.ic_cref # with cref
- # Cache is keyed on a certain lexical scope. Use the interpreter's cache.
- side_exit = side_exit(jit, ctx)
-
- # Call function to verify the cache. It doesn't allocate or call methods.
- asm.mov(C_ARGS[0], ic.to_i)
- asm.mov(C_ARGS[1], [CFP, C.rb_control_frame_t.offsetof(:ep)])
- asm.call(C.rb_vm_ic_hit_p)
-
- # Check the result. SysV only specifies one byte for _Bool return values,
- # so it's important we only check one bit to ignore the higher bits in the register.
- asm.test(C_RET, 1)
- asm.jz(counted_exit(side_exit, :optgetconst_cache_miss))
-
- asm.mov(:rax, ic.to_i) # inline_cache
- asm.mov(:rax, [:rax, C.iseq_inline_constant_cache.offsetof(:entry)]) # ic_entry
- asm.mov(:rax, [:rax, C.iseq_inline_constant_cache_entry.offsetof(:value)]) # ic_entry_val
-
- # Push ic->entry->value
- stack_top = ctx.stack_push(Type::Unknown)
- asm.mov(stack_top, :rax)
- else # without cref
- # TODO: implement this
- # Optimize for single ractor mode.
- # if !assume_single_ractor_mode(jit, ocb)
- # return CantCompile
- # end
-
- # Invalidate output code on any constant writes associated with
- # constants referenced within the current block.
- Invariants.assume_stable_constant_names(jit, idlist)
-
- putobject(jit, ctx, asm, val: ice.value)
- end
-
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getconstant(jit, ctx, asm)
- id = jit.operand(0)
-
- # vm_get_ev_const can raise exceptions.
- jit_prepare_routine_call(jit, ctx, asm)
-
- allow_nil_opnd = ctx.stack_pop(1)
- klass_opnd = ctx.stack_pop(1)
-
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], klass_opnd)
- asm.mov(C_ARGS[2], id)
- asm.mov(C_ARGS[3], allow_nil_opnd)
- asm.call(C.rb_vm_get_ev_const)
-
- top = ctx.stack_push(Type::Unknown)
- asm.mov(top, C_RET)
-
- KeepCompiling
- end
-
- # setconstant
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def getglobal(jit, ctx, asm)
- gid = jit.operand(0)
-
- # Save the PC and SP because we might make a Ruby call for warning
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.mov(C_ARGS[0], gid)
- asm.call(C.rb_gvar_get)
-
- top = ctx.stack_push(Type::Unknown)
- asm.mov(top, C_RET)
-
- KeepCompiling
- end
-
- # setglobal
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putnil(jit, ctx, asm)
- putobject(jit, ctx, asm, val: Qnil)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putself(jit, ctx, asm)
- stack_top = ctx.stack_push_self
- asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)])
- asm.mov(stack_top, :rax)
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putobject(jit, ctx, asm, val: jit.operand(0))
- # Push it to the stack
- val_type = Type.from(C.to_ruby(val))
- stack_top = ctx.stack_push(val_type)
- if asm.imm32?(val)
- asm.mov(stack_top, val)
- else # 64-bit immediates can't be directly written to memory
- asm.mov(:rax, val)
- asm.mov(stack_top, :rax)
- end
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putspecialobject(jit, ctx, asm)
- object_type = jit.operand(0)
- if object_type == C::VM_SPECIAL_OBJECT_VMCORE
- stack_top = ctx.stack_push(Type::UnknownHeap)
- asm.mov(:rax, C.rb_mRubyVMFrozenCore)
- asm.mov(stack_top, :rax)
- KeepCompiling
- else
- # TODO: implement for VM_SPECIAL_OBJECT_CBASE and
- # VM_SPECIAL_OBJECT_CONST_BASE
- CantCompile
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putstring(jit, ctx, asm)
- put_val = jit.operand(0, ruby: true)
-
- # Save the PC and SP because the callee will allocate
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], to_value(put_val))
- asm.mov(C_ARGS[2], 0)
- asm.call(C.rb_ec_str_resurrect)
-
- stack_top = ctx.stack_push(Type::TString)
- asm.mov(stack_top, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putchilledstring(jit, ctx, asm)
- put_val = jit.operand(0, ruby: true)
-
- # Save the PC and SP because the callee will allocate
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], to_value(put_val))
- asm.mov(C_ARGS[2], 1)
- asm.call(C.rb_ec_str_resurrect)
-
- stack_top = ctx.stack_push(Type::TString)
- asm.mov(stack_top, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def concatstrings(jit, ctx, asm)
- n = jit.operand(0)
-
- # Save the PC and SP because we are allocating
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.lea(:rax, ctx.sp_opnd(-C.VALUE.size * n))
-
- # call rb_str_concat_literals(size_t n, const VALUE *strings);
- asm.mov(C_ARGS[0], n)
- asm.mov(C_ARGS[1], :rax)
- asm.call(C.rb_str_concat_literals)
-
- ctx.stack_pop(n)
- stack_ret = ctx.stack_push(Type::TString)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def anytostring(jit, ctx, asm)
- # Save the PC and SP since we might call #to_s
- jit_prepare_routine_call(jit, ctx, asm)
-
- str = ctx.stack_pop(1)
- val = ctx.stack_pop(1)
-
- asm.mov(C_ARGS[0], str)
- asm.mov(C_ARGS[1], val)
- asm.call(C.rb_obj_as_string_result)
-
- # Push the return value
- stack_ret = ctx.stack_push(Type::TString)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def toregexp(jit, ctx, asm)
- opt = jit.operand(0, signed: true)
- cnt = jit.operand(1)
-
- # Save the PC and SP because this allocates an object and could
- # raise an exception.
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.lea(:rax, ctx.sp_opnd(-C.VALUE.size * cnt)) # values_ptr
- ctx.stack_pop(cnt)
-
- asm.mov(C_ARGS[0], 0)
- asm.mov(C_ARGS[1], cnt)
- asm.mov(C_ARGS[2], :rax) # values_ptr
- asm.call(C.rb_ary_tmp_new_from_values)
-
- # Save the array so we can clear it later
- asm.push(C_RET)
- asm.push(C_RET) # Alignment
-
- asm.mov(C_ARGS[0], C_RET)
- asm.mov(C_ARGS[1], opt)
- asm.call(C.rb_reg_new_ary)
-
- # The actual regex is in RAX now. Pop the temp array from
- # rb_ary_tmp_new_from_values into C arg regs so we can clear it
- asm.pop(:rcx) # Alignment
- asm.pop(:rcx) # ary
-
- # The value we want to push on the stack is in RAX right now
- stack_ret = ctx.stack_push(Type::UnknownHeap)
- asm.mov(stack_ret, C_RET)
-
- # Clear the temp array.
- asm.mov(C_ARGS[0], :rcx) # ary
- asm.call(C.rb_ary_clear)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def intern(jit, ctx, asm)
- # Save the PC and SP because we might allocate
- jit_prepare_routine_call(jit, ctx, asm);
-
- str = ctx.stack_pop(1)
- asm.mov(C_ARGS[0], str)
- asm.call(C.rb_str_intern)
-
- # Push the return value
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def newarray(jit, ctx, asm)
- n = jit.operand(0)
-
- # Save the PC and SP because we are allocating
- jit_prepare_routine_call(jit, ctx, asm)
-
- # If n is 0, then elts is never going to be read, so we can just pass null
- if n == 0
- values_ptr = 0
- else
- asm.comment('load pointer to array elts')
- offset_magnitude = C.VALUE.size * n
- values_opnd = ctx.sp_opnd(-(offset_magnitude))
- asm.lea(:rax, values_opnd)
- values_ptr = :rax
- end
-
- # call rb_ec_ary_new_from_values(struct rb_execution_context_struct *ec, long n, const VALUE *elts);
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], n)
- asm.mov(C_ARGS[2], values_ptr)
- asm.call(C.rb_ec_ary_new_from_values)
-
- ctx.stack_pop(n)
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def duparray(jit, ctx, asm)
- ary = jit.operand(0)
-
- # Save the PC and SP because we are allocating
- jit_prepare_routine_call(jit, ctx, asm)
-
- # call rb_ary_resurrect(VALUE ary);
- asm.comment('call rb_ary_resurrect')
- asm.mov(C_ARGS[0], ary)
- asm.call(C.rb_ary_resurrect)
-
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # duphash
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def expandarray(jit, ctx, asm)
- # Both arguments are rb_num_t which is unsigned
- num = jit.operand(0)
- flag = jit.operand(1)
-
- # If this instruction has the splat flag, then bail out.
- if flag & 0x01 != 0
- asm.incr_counter(:expandarray_splat)
- return CantCompile
- end
-
- # If this instruction has the postarg flag, then bail out.
- if flag & 0x02 != 0
- asm.incr_counter(:expandarray_postarg)
- return CantCompile
- end
-
- side_exit = side_exit(jit, ctx)
-
- array_opnd = ctx.stack_opnd(0)
- array_stack_opnd = StackOpnd[0]
-
- # num is the number of requested values. If there aren't enough in the
- # array then we're going to push on nils.
- if ctx.get_opnd_type(array_stack_opnd) == Type::Nil
- ctx.stack_pop(1) # pop after using the type info
- # special case for a, b = nil pattern
- # push N nils onto the stack
- num.times do
- push_opnd = ctx.stack_push(Type::Nil)
- asm.mov(push_opnd, Qnil)
- end
- return KeepCompiling
- end
-
- # Move the array from the stack and check that it's an array.
- asm.mov(:rax, array_opnd)
- guard_object_is_array(jit, ctx, asm, :rax, :rcx, array_stack_opnd, :expandarray_not_array)
- ctx.stack_pop(1) # pop after using the type info
-
- # If we don't actually want any values, then just return.
- if num == 0
- return KeepCompiling
- end
-
- jit_array_len(asm, :rax, :rcx)
-
- # Only handle the case where the number of values in the array is greater
- # than or equal to the number of values requested.
- asm.cmp(:rcx, num)
- asm.jl(counted_exit(side_exit, :expandarray_rhs_too_small))
-
- # Conditionally load the address of the heap array into REG1.
- # (struct RArray *)(obj)->as.heap.ptr
- #asm.mov(:rax, array_opnd)
- asm.mov(:rcx, [:rax, C.RBasic.offsetof(:flags)])
- asm.test(:rcx, C::RARRAY_EMBED_FLAG);
- asm.mov(:rcx, [:rax, C.RArray.offsetof(:as, :heap, :ptr)])
-
- # Load the address of the embedded array into REG1.
- # (struct RArray *)(obj)->as.ary
- asm.lea(:rax, [:rax, C.RArray.offsetof(:as, :ary)])
-
- asm.cmovnz(:rcx, :rax)
-
- # Loop backward through the array and push each element onto the stack.
- (num - 1).downto(0).each do |i|
- top = ctx.stack_push(Type::Unknown)
- asm.mov(:rax, [:rcx, i * C.VALUE.size])
- asm.mov(top, :rax)
- end
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def concatarray(jit, ctx, asm)
- # Save the PC and SP because the callee may allocate
- # Note that this modifies REG_SP, which is why we do it first
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Get the operands from the stack
- ary2st_opnd = ctx.stack_pop(1)
- ary1_opnd = ctx.stack_pop(1)
-
- # Call rb_vm_concat_array(ary1, ary2st)
- asm.mov(C_ARGS[0], ary1_opnd)
- asm.mov(C_ARGS[1], ary2st_opnd)
- asm.call(C.rb_vm_concat_array)
-
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def splatarray(jit, ctx, asm)
- flag = jit.operand(0)
-
- # Save the PC and SP because the callee may allocate
- # Note that this modifies REG_SP, which is why we do it first
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Get the operands from the stack
- ary_opnd = ctx.stack_pop(1)
-
- # Call rb_vm_splat_array(flag, ary)
- asm.mov(C_ARGS[0], flag)
- asm.mov(C_ARGS[1], ary_opnd)
- asm.call(C.rb_vm_splat_array)
-
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def newhash(jit, ctx, asm)
- num = jit.operand(0)
-
- # Save the PC and SP because we are allocating
- jit_prepare_routine_call(jit, ctx, asm)
-
- if num != 0
- # val = rb_hash_new_with_size(num / 2);
- asm.mov(C_ARGS[0], num / 2)
- asm.call(C.rb_hash_new_with_size)
-
- # Save the allocated hash as we want to push it after insertion
- asm.push(C_RET)
- asm.push(C_RET) # x86 alignment
-
- # Get a pointer to the values to insert into the hash
- asm.lea(:rcx, ctx.stack_opnd(num - 1))
-
- # rb_hash_bulk_insert(num, STACK_ADDR_FROM_TOP(num), val);
- asm.mov(C_ARGS[0], num)
- asm.mov(C_ARGS[1], :rcx)
- asm.mov(C_ARGS[2], C_RET)
- asm.call(C.rb_hash_bulk_insert)
-
- asm.pop(:rax)
- asm.pop(:rax)
-
- ctx.stack_pop(num)
- stack_ret = ctx.stack_push(Type::Hash)
- asm.mov(stack_ret, :rax)
- else
- # val = rb_hash_new();
- asm.call(C.rb_hash_new)
- stack_ret = ctx.stack_push(Type::Hash)
- asm.mov(stack_ret, C_RET)
- end
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def newrange(jit, ctx, asm)
- flag = jit.operand(0)
-
- # rb_range_new() allocates and can raise
- jit_prepare_routine_call(jit, ctx, asm)
-
- # val = rb_range_new(low, high, (int)flag);
- asm.mov(C_ARGS[0], ctx.stack_opnd(1))
- asm.mov(C_ARGS[1], ctx.stack_opnd(0))
- asm.mov(C_ARGS[2], flag)
- asm.call(C.rb_range_new)
-
- ctx.stack_pop(2)
- stack_ret = ctx.stack_push(Type::UnknownHeap)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def pop(jit, ctx, asm)
- ctx.stack_pop
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def dup(jit, ctx, asm)
- dup_val = ctx.stack_opnd(0)
- mapping, tmp_type = ctx.get_opnd_mapping(StackOpnd[0])
-
- loc0 = ctx.stack_push_mapping([mapping, tmp_type])
- asm.mov(:rax, dup_val)
- asm.mov(loc0, :rax)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def dupn(jit, ctx, asm)
- n = jit.operand(0)
-
- # In practice, seems to be only used for n==2
- if n != 2
- return CantCompile
- end
-
- opnd1 = ctx.stack_opnd(1)
- opnd0 = ctx.stack_opnd(0)
-
- mapping1 = ctx.get_opnd_mapping(StackOpnd[1])
- mapping0 = ctx.get_opnd_mapping(StackOpnd[0])
-
- dst1 = ctx.stack_push_mapping(mapping1)
- asm.mov(:rax, opnd1)
- asm.mov(dst1, :rax)
-
- dst0 = ctx.stack_push_mapping(mapping0)
- asm.mov(:rax, opnd0)
- asm.mov(dst0, :rax)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def swap(jit, ctx, asm)
- stack_swap(jit, ctx, asm, 0, 1)
- KeepCompiling
- end
-
- # opt_reverse
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def topn(jit, ctx, asm)
- n = jit.operand(0)
-
- top_n_val = ctx.stack_opnd(n)
- mapping = ctx.get_opnd_mapping(StackOpnd[n])
- loc0 = ctx.stack_push_mapping(mapping)
- asm.mov(:rax, top_n_val)
- asm.mov(loc0, :rax)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def setn(jit, ctx, asm)
- n = jit.operand(0)
-
- top_val = ctx.stack_pop(0)
- dst_opnd = ctx.stack_opnd(n)
- asm.mov(:rax, top_val)
- asm.mov(dst_opnd, :rax)
-
- mapping = ctx.get_opnd_mapping(StackOpnd[0])
- ctx.set_opnd_mapping(StackOpnd[n], mapping)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def adjuststack(jit, ctx, asm)
- n = jit.operand(0)
- ctx.stack_pop(n)
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def defined(jit, ctx, asm)
- op_type = jit.operand(0)
- obj = jit.operand(1, ruby: true)
- pushval = jit.operand(2, ruby: true)
-
- # Save the PC and SP because the callee may allocate
- # Note that this modifies REG_SP, which is why we do it first
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Get the operands from the stack
- v_opnd = ctx.stack_pop(1)
-
- # Call vm_defined(ec, reg_cfp, op_type, obj, v)
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], CFP)
- asm.mov(C_ARGS[2], op_type)
- asm.mov(C_ARGS[3], to_value(obj))
- asm.mov(C_ARGS[4], v_opnd)
- asm.call(C.rb_vm_defined)
-
- asm.test(C_RET, 255)
- asm.mov(:rax, Qnil)
- asm.mov(:rcx, to_value(pushval))
- asm.cmovnz(:rax, :rcx)
-
- # Push the return value onto the stack
- out_type = if C::SPECIAL_CONST_P(pushval)
- Type::UnknownImm
- else
- Type::Unknown
- end
- stack_ret = ctx.stack_push(out_type)
- asm.mov(stack_ret, :rax)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def definedivar(jit, ctx, asm)
- # Defer compilation so we can specialize base on a runtime receiver
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- ivar_name = jit.operand(0)
- # Value that will be pushed on the stack if the ivar is defined. In practice this is always the
- # string "instance-variable". If the ivar is not defined, nil will be pushed instead.
- pushval = jit.operand(2, ruby: true)
-
- # Get the receiver
- recv = :rcx
- asm.mov(recv, [CFP, C.rb_control_frame_t.offsetof(:self)])
-
- # Specialize base on compile time values
- comptime_receiver = jit.peek_at_self
-
- if shape_too_complex?(comptime_receiver)
- # Fall back to calling rb_ivar_defined
-
- # Save the PC and SP because the callee may allocate
- # Note that this modifies REG_SP, which is why we do it first
- jit_prepare_routine_call(jit, ctx, asm) # clobbers :rax
-
- # Call rb_ivar_defined(recv, ivar_name)
- asm.mov(C_ARGS[0], recv)
- asm.mov(C_ARGS[1], ivar_name)
- asm.call(C.rb_ivar_defined)
-
- # if (rb_ivar_defined(recv, ivar_name)) {
- # val = pushval;
- # }
- asm.test(C_RET, 255)
- asm.mov(:rax, Qnil)
- asm.mov(:rcx, to_value(pushval))
- asm.cmovnz(:rax, :rcx)
-
- # Push the return value onto the stack
- out_type = C::SPECIAL_CONST_P(pushval) ? Type::UnknownImm : Type::Unknown
- stack_ret = ctx.stack_push(out_type)
- asm.mov(stack_ret, :rax)
-
- return KeepCompiling
- end
-
- shape_id = C.rb_shape_get_shape_id(comptime_receiver)
- ivar_exists = C.rb_shape_get_iv_index(shape_id, ivar_name)
-
- side_exit = side_exit(jit, ctx)
-
- # Guard heap object (recv_opnd must be used before stack_pop)
- guard_object_is_heap(jit, ctx, asm, recv, SelfOpnd)
-
- shape_opnd = DwordPtr[recv, C.rb_shape_id_offset]
-
- asm.comment('guard shape')
- asm.cmp(shape_opnd, shape_id)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit)
-
- result = ivar_exists ? C.to_value(pushval) : Qnil
- putobject(jit, ctx, asm, val: result)
-
- # Jump to next instruction. This allows guard chains to share the same successor.
- jump_to_next_insn(jit, ctx, asm)
-
- return EndBlock
- end
-
- # checkmatch
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def checkkeyword(jit, ctx, asm)
- # When a keyword is unspecified past index 32, a hash will be used
- # instead. This can only happen in iseqs taking more than 32 keywords.
- if jit.iseq.body.param.keyword.num >= 32
- return CantCompile
- end
-
- # The EP offset to the undefined bits local
- bits_offset = jit.operand(0)
-
- # The index of the keyword we want to check
- index = jit.operand(1, signed: true)
-
- # Load environment pointer EP
- ep_reg = :rax
- jit_get_ep(asm, 0, reg: ep_reg)
-
- # VALUE kw_bits = *(ep - bits)
- bits_opnd = [ep_reg, C.VALUE.size * -bits_offset]
-
- # unsigned int b = (unsigned int)FIX2ULONG(kw_bits);
- # if ((b & (0x01 << idx))) {
- #
- # We can skip the FIX2ULONG conversion by shifting the bit we test
- bit_test = 0x01 << (index + 1)
- asm.test(bits_opnd, bit_test)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmovz(:rax, :rcx)
-
- stack_ret = ctx.stack_push(Type::UnknownImm)
- asm.mov(stack_ret, :rax)
-
- KeepCompiling
- end
-
- # checktype
- # defineclass
- # definemethod
- # definesmethod
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def send(jit, ctx, asm)
- # Specialize on a compile-time receiver, and split a block for chain guards
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- cd = C.rb_call_data.new(jit.operand(0))
- blockiseq = jit.operand(1)
-
- # calling->ci
- mid = C.vm_ci_mid(cd.ci)
- calling = build_calling(ci: cd.ci, block_handler: blockiseq)
-
- if calling.flags & C::VM_CALL_FORWARDING != 0
- return CantCompile
- end
-
- # vm_sendish
- cme, comptime_recv_klass = jit_search_method(jit, ctx, asm, mid, calling)
- if cme == CantCompile
- return CantCompile
- end
- jit_call_general(jit, ctx, asm, mid, calling, cme, comptime_recv_klass)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_send_without_block(jit, ctx, asm, cd: C.rb_call_data.new(jit.operand(0)))
- # Specialize on a compile-time receiver, and split a block for chain guards
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- # calling->ci
- mid = C.vm_ci_mid(cd.ci)
- calling = build_calling(ci: cd.ci, block_handler: C::VM_BLOCK_HANDLER_NONE)
-
- # vm_sendish
- cme, comptime_recv_klass = jit_search_method(jit, ctx, asm, mid, calling)
- if cme == CantCompile
- return CantCompile
- end
- jit_call_general(jit, ctx, asm, mid, calling, cme, comptime_recv_klass)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def objtostring(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- recv = ctx.stack_opnd(0)
- comptime_recv = jit.peek_at_stack(0)
-
- if C.RB_TYPE_P(comptime_recv, C::RUBY_T_STRING)
- side_exit = side_exit(jit, ctx)
-
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_recv), recv, StackOpnd[0], comptime_recv, side_exit)
- # No work needed. The string value is already on the top of the stack.
- KeepCompiling
- else
- cd = C.rb_call_data.new(jit.operand(0))
- opt_send_without_block(jit, ctx, asm, cd:)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_ary_freeze(jit, ctx, asm)
- unless Invariants.assume_bop_not_redefined(jit, C::ARRAY_REDEFINED_OP_FLAG, C::BOP_FREEZE)
- return CantCompile;
- end
-
- ary = jit.operand(0, ruby: true)
-
- # Push the return value onto the stack
- stack_ret = ctx.stack_push(Type::CArray)
- asm.mov(:rax, to_value(ary))
- asm.mov(stack_ret, :rax)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_hash_freeze(jit, ctx, asm)
- unless Invariants.assume_bop_not_redefined(jit, C::HASH_REDEFINED_OP_FLAG, C::BOP_FREEZE)
- return CantCompile;
- end
-
- hash = jit.operand(0, ruby: true)
-
- # Push the return value onto the stack
- stack_ret = ctx.stack_push(Type::CHash)
- asm.mov(:rax, to_value(hash))
- asm.mov(stack_ret, :rax)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_str_freeze(jit, ctx, asm)
- unless Invariants.assume_bop_not_redefined(jit, C::STRING_REDEFINED_OP_FLAG, C::BOP_FREEZE)
- return CantCompile;
- end
-
- str = jit.operand(0, ruby: true)
-
- # Push the return value onto the stack
- stack_ret = ctx.stack_push(Type::CString)
- asm.mov(:rax, to_value(str))
- asm.mov(stack_ret, :rax)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_nil_p(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # opt_str_uminus
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_newarray_send(jit, ctx, asm)
- type = C.ID2SYM jit.operand(1)
-
- case type
- when :min then opt_newarray_min(jit, ctx, asm)
- when :max then opt_newarray_max(jit, ctx, asm)
- when :hash then opt_newarray_hash(jit, ctx, asm)
- else
- return CantCompile
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_newarray_min(jit, ctx, asm)
- num = jit.operand(0)
-
- # Save the PC and SP because we may allocate
- jit_prepare_routine_call(jit, ctx, asm)
-
- offset_magnitude = C.VALUE.size * num
- values_opnd = ctx.sp_opnd(-offset_magnitude)
- asm.lea(:rax, values_opnd)
-
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], num)
- asm.mov(C_ARGS[2], :rax)
- asm.call(C.rb_vm_opt_newarray_min)
-
- ctx.stack_pop(num)
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_newarray_max(jit, ctx, asm)
- num = jit.operand(0)
-
- # Save the PC and SP because we may allocate
- jit_prepare_routine_call(jit, ctx, asm)
-
- offset_magnitude = C.VALUE.size * num
- values_opnd = ctx.sp_opnd(-offset_magnitude)
- asm.lea(:rax, values_opnd)
-
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], num)
- asm.mov(C_ARGS[2], :rax)
- asm.call(C.rb_vm_opt_newarray_max)
-
- ctx.stack_pop(num)
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_newarray_hash(jit, ctx, asm)
- num = jit.operand(0)
-
- # Save the PC and SP because we may allocate
- jit_prepare_routine_call(jit, ctx, asm)
-
- offset_magnitude = C.VALUE.size * num
- values_opnd = ctx.sp_opnd(-offset_magnitude)
- asm.lea(:rax, values_opnd)
-
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], num)
- asm.mov(C_ARGS[2], :rax)
- asm.call(C.rb_vm_opt_newarray_hash)
-
- ctx.stack_pop(num)
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def invokesuper(jit, ctx, asm)
- cd = C.rb_call_data.new(jit.operand(0))
- block = jit.operand(1)
-
- # Defer compilation so we can specialize on class of receiver
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- me = C.rb_vm_frame_method_entry(jit.cfp)
- if me.nil?
- return CantCompile
- end
-
- # FIXME: We should track and invalidate this block when this cme is invalidated
- current_defined_class = me.defined_class
- mid = me.def.original_id
-
- if me.to_i != C.rb_callable_method_entry(current_defined_class, me.called_id).to_i
- # Though we likely could generate this call, as we are only concerned
- # with the method entry remaining valid, assume_method_lookup_stable
- # below requires that the method lookup matches as well
- return CantCompile
- end
-
- # vm_search_normal_superclass
- rbasic_klass = C.to_ruby(C.RBasic.new(C.to_value(current_defined_class)).klass)
- if C::BUILTIN_TYPE(current_defined_class) == C::RUBY_T_ICLASS && C::BUILTIN_TYPE(rbasic_klass) == C::RUBY_T_MODULE && \
- C::FL_TEST_RAW(rbasic_klass, C::RMODULE_IS_REFINEMENT)
- return CantCompile
- end
- comptime_superclass = C.rb_class_get_superclass(C.RCLASS_ORIGIN(current_defined_class))
-
- ci = cd.ci
- argc = C.vm_ci_argc(ci)
-
- ci_flags = C.vm_ci_flag(ci)
-
- # Don't JIT calls that aren't simple
- # Note, not using VM_CALL_ARGS_SIMPLE because sometimes we pass a block.
-
- if ci_flags & C::VM_CALL_KWARG != 0
- asm.incr_counter(:send_keywords)
- return CantCompile
- end
- if ci_flags & C::VM_CALL_KW_SPLAT != 0
- asm.incr_counter(:send_kw_splat)
- return CantCompile
- end
- if ci_flags & C::VM_CALL_ARGS_BLOCKARG != 0
- asm.incr_counter(:send_block_arg)
- return CantCompile
- end
-
- # Ensure we haven't rebound this method onto an incompatible class.
- # In the interpreter we try to avoid making this check by performing some
- # cheaper calculations first, but since we specialize on the method entry
- # and so only have to do this once at compile time this is fine to always
- # check and side exit.
- comptime_recv = jit.peek_at_stack(argc)
- unless C.obj_is_kind_of(comptime_recv, current_defined_class)
- return CantCompile
- end
-
- # Do method lookup
- cme = C.rb_callable_method_entry(comptime_superclass, mid)
-
- if cme.nil?
- return CantCompile
- end
-
- # Check that we'll be able to write this method dispatch before generating checks
- cme_def_type = cme.def.type
- if cme_def_type != C::VM_METHOD_TYPE_ISEQ && cme_def_type != C::VM_METHOD_TYPE_CFUNC
- # others unimplemented
- return CantCompile
- end
-
- asm.comment('guard known me')
- lep_opnd = :rax
- jit_get_lep(jit, asm, reg: lep_opnd)
- ep_me_opnd = [lep_opnd, C.VALUE.size * C::VM_ENV_DATA_INDEX_ME_CREF]
-
- asm.mov(:rcx, me.to_i)
- asm.cmp(ep_me_opnd, :rcx)
- asm.jne(counted_exit(side_exit(jit, ctx), :invokesuper_me_changed))
-
- if block == C::VM_BLOCK_HANDLER_NONE
- # Guard no block passed
- # rb_vm_frame_block_handler(GET_EC()->cfp) == VM_BLOCK_HANDLER_NONE
- # note, we assume VM_ASSERT(VM_ENV_LOCAL_P(ep))
- #
- # TODO: this could properly forward the current block handler, but
- # would require changes to gen_send_*
- asm.comment('guard no block given')
- ep_specval_opnd = [lep_opnd, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]
- asm.cmp(ep_specval_opnd, C::VM_BLOCK_HANDLER_NONE)
- asm.jne(counted_exit(side_exit(jit, ctx), :invokesuper_block))
- end
-
- # We need to assume that both our current method entry and the super
- # method entry we invoke remain stable
- Invariants.assume_method_lookup_stable(jit, me)
- Invariants.assume_method_lookup_stable(jit, cme)
-
- # Method calls may corrupt types
- ctx.clear_local_types
-
- calling = build_calling(ci:, block_handler: block)
- case cme_def_type
- in C::VM_METHOD_TYPE_ISEQ
- iseq = def_iseq_ptr(cme.def)
- frame_type = C::VM_FRAME_MAGIC_METHOD | C::VM_ENV_FLAG_LOCAL
- jit_call_iseq(jit, ctx, asm, cme, calling, iseq, frame_type:)
- in C::VM_METHOD_TYPE_CFUNC
- jit_call_cfunc(jit, ctx, asm, cme, calling)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def invokeblock(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- # Get call info
- cd = C.rb_call_data.new(jit.operand(0))
- calling = build_calling(ci: cd.ci, block_handler: :captured)
-
- # Get block_handler
- cfp = jit.cfp
- lep = C.rb_vm_ep_local_ep(cfp.ep)
- comptime_handler = lep[C::VM_ENV_DATA_INDEX_SPECVAL]
-
- # Handle each block_handler type
- if comptime_handler == C::VM_BLOCK_HANDLER_NONE # no block given
- asm.incr_counter(:invokeblock_none)
- CantCompile
- elsif comptime_handler & 0x3 == 0x1 # VM_BH_ISEQ_BLOCK_P
- asm.comment('get local EP')
- ep_reg = :rax
- jit_get_lep(jit, asm, reg: ep_reg)
- asm.mov(:rax, [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]) # block_handler_opnd
-
- asm.comment('guard block_handler type')
- side_exit = side_exit(jit, ctx)
- asm.mov(:rcx, :rax)
- asm.and(:rcx, 0x3) # block_handler is a tagged pointer
- asm.cmp(:rcx, 0x1) # VM_BH_ISEQ_BLOCK_P
- tag_changed_exit = counted_exit(side_exit, :invokeblock_tag_changed)
- jit_chain_guard(:jne, jit, ctx, asm, tag_changed_exit)
-
- comptime_captured = C.rb_captured_block.new(comptime_handler & ~0x3)
- comptime_iseq = comptime_captured.code.iseq
-
- asm.comment('guard known ISEQ')
- asm.and(:rax, ~0x3) # captured
- asm.mov(:rax, [:rax, C.VALUE.size * 2]) # captured->iseq
- asm.mov(:rcx, comptime_iseq.to_i)
- asm.cmp(:rax, :rcx)
- block_changed_exit = counted_exit(side_exit, :invokeblock_iseq_block_changed)
- jit_chain_guard(:jne, jit, ctx, asm, block_changed_exit)
-
- jit_call_iseq(jit, ctx, asm, nil, calling, comptime_iseq, frame_type: C::VM_FRAME_MAGIC_BLOCK)
- elsif comptime_handler & 0x3 == 0x3 # VM_BH_IFUNC_P
- # We aren't handling CALLER_SETUP_ARG and CALLER_REMOVE_EMPTY_KW_SPLAT yet.
- if calling.flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:invokeblock_ifunc_args_splat)
- return CantCompile
- end
- if calling.flags & C::VM_CALL_KW_SPLAT != 0
- asm.incr_counter(:invokeblock_ifunc_kw_splat)
- return CantCompile
- end
-
- asm.comment('get local EP')
- jit_get_lep(jit, asm, reg: :rax)
- asm.mov(:rcx, [:rax, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]) # block_handler_opnd
-
- asm.comment('guard block_handler type');
- side_exit = side_exit(jit, ctx)
- asm.mov(:rax, :rcx) # block_handler_opnd
- asm.and(:rax, 0x3) # tag_opnd: block_handler is a tagged pointer
- asm.cmp(:rax, 0x3) # VM_BH_IFUNC_P
- tag_changed_exit = counted_exit(side_exit, :invokeblock_tag_changed)
- jit_chain_guard(:jne, jit, ctx, asm, tag_changed_exit)
-
- # The cfunc may not be leaf
- jit_prepare_routine_call(jit, ctx, asm) # clobbers :rax
-
- asm.comment('call ifunc')
- asm.and(:rcx, ~0x3) # captured_opnd
- asm.lea(:rax, ctx.sp_opnd(-calling.argc * C.VALUE.size)) # argv
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], :rcx) # captured_opnd
- asm.mov(C_ARGS[2], calling.argc)
- asm.mov(C_ARGS[3], :rax) # argv
- asm.call(C.rb_vm_yield_with_cfunc)
-
- ctx.stack_pop(calling.argc)
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- # cfunc calls may corrupt types
- ctx.clear_local_types
-
- # Share the successor with other chains
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- elsif symbol?(comptime_handler)
- asm.incr_counter(:invokeblock_symbol)
- CantCompile
- else # Proc
- asm.incr_counter(:invokeblock_proc)
- CantCompile
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def leave(jit, ctx, asm)
- assert_equal(ctx.stack_size, 1)
-
- jit_check_ints(jit, ctx, asm)
-
- asm.comment('pop stack frame')
- asm.lea(:rax, [CFP, C.rb_control_frame_t.size])
- asm.mov(CFP, :rax)
- asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], :rax)
-
- # Return a value (for compile_leave_exit)
- ret_opnd = ctx.stack_pop
- asm.mov(:rax, ret_opnd)
-
- # Set caller's SP and push a value to its stack (for JIT)
- asm.mov(SP, [CFP, C.rb_control_frame_t.offsetof(:sp)]) # Note: SP is in the position after popping a receiver and arguments
- asm.mov([SP], :rax)
-
- # Jump to cfp->jit_return
- asm.jmp([CFP, -C.rb_control_frame_t.size + C.rb_control_frame_t.offsetof(:jit_return)])
-
- EndBlock
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def throw(jit, ctx, asm)
- throw_state = jit.operand(0)
- asm.mov(:rcx, ctx.stack_pop(1)) # throwobj
-
- # THROW_DATA_NEW allocates. Save SP for GC and PC for allocation tracing as
- # well as handling the catch table. However, not using jit_prepare_routine_call
- # since we don't need a patch point for this implementation.
- jit_save_pc(jit, asm) # clobbers rax
- jit_save_sp(ctx, asm)
-
- # rb_vm_throw verifies it's a valid throw, sets ec->tag->state, and returns throw
- # data, which is throwobj or a vm_throw_data wrapping it. When ec->tag->state is
- # set, JIT code callers will handle the throw with vm_exec_handle_exception.
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], CFP)
- asm.mov(C_ARGS[2], throw_state)
- # asm.mov(C_ARGS[3], :rcx) # same reg
- asm.call(C.rb_vm_throw)
-
- asm.comment('exit from throw')
- asm.pop(SP)
- asm.pop(EC)
- asm.pop(CFP)
-
- # return C_RET as C_RET
- asm.ret
- EndBlock
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jump(jit, ctx, asm)
- # Check for interrupts, but only on backward branches that may create loops
- jump_offset = jit.operand(0, signed: true)
- if jump_offset < 0
- jit_check_ints(jit, ctx, asm)
- end
-
- pc = jit.pc + C.VALUE.size * (jit.insn.len + jump_offset)
- jit_direct_jump(jit.iseq, pc, ctx, asm)
- EndBlock
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def branchif(jit, ctx, asm)
- # Check for interrupts, but only on backward branches that may create loops
- jump_offset = jit.operand(0, signed: true)
- if jump_offset < 0
- jit_check_ints(jit, ctx, asm)
- end
-
- # Get the branch target instruction offsets
- next_pc = jit.pc + C.VALUE.size * jit.insn.len
- jump_pc = jit.pc + C.VALUE.size * (jit.insn.len + jump_offset)
-
- val_type = ctx.get_opnd_type(StackOpnd[0])
- val_opnd = ctx.stack_pop(1)
-
- if (result = val_type.known_truthy) != nil
- target_pc = result ? jump_pc : next_pc
- jit_direct_jump(jit.iseq, target_pc, ctx, asm)
- else
- # This `test` sets ZF only for Qnil and Qfalse, which let jz jump.
- asm.test(val_opnd, ~Qnil)
-
- # Set stubs
- branch_stub = BranchStub.new(
- iseq: jit.iseq,
- shape: Default,
- target0: BranchTarget.new(ctx:, pc: jump_pc), # branch target
- target1: BranchTarget.new(ctx:, pc: next_pc), # fallthrough
- )
- branch_stub.target0.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, true)
- @ocb.write(ocb_asm)
- end
- branch_stub.target1.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, false)
- @ocb.write(ocb_asm)
- end
-
- # Jump to target0 on jnz
- branch_stub.compile = compile_branchif(branch_stub)
- branch_stub.compile.call(asm)
- end
-
- EndBlock
- end
-
- def compile_branchif(branch_stub) # Proc escapes arguments in memory
- proc do |branch_asm|
- branch_asm.comment("branchif #{branch_stub.shape}")
- branch_asm.stub(branch_stub) do
- case branch_stub.shape
- in Default
- branch_asm.jnz(branch_stub.target0.address)
- branch_asm.jmp(branch_stub.target1.address)
- in Next0
- branch_asm.jz(branch_stub.target1.address)
- in Next1
- branch_asm.jnz(branch_stub.target0.address)
- end
- end
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def branchunless(jit, ctx, asm)
- # Check for interrupts, but only on backward branches that may create loops
- jump_offset = jit.operand(0, signed: true)
- if jump_offset < 0
- jit_check_ints(jit, ctx, asm)
- end
-
- # Get the branch target instruction offsets
- next_pc = jit.pc + C.VALUE.size * jit.insn.len
- jump_pc = jit.pc + C.VALUE.size * (jit.insn.len + jump_offset)
-
- val_type = ctx.get_opnd_type(StackOpnd[0])
- val_opnd = ctx.stack_pop(1)
-
- if (result = val_type.known_truthy) != nil
- target_pc = result ? next_pc : jump_pc
- jit_direct_jump(jit.iseq, target_pc, ctx, asm)
- else
- # This `test` sets ZF only for Qnil and Qfalse, which let jz jump.
- asm.test(val_opnd, ~Qnil)
-
- # Set stubs
- branch_stub = BranchStub.new(
- iseq: jit.iseq,
- shape: Default,
- target0: BranchTarget.new(ctx:, pc: jump_pc), # branch target
- target1: BranchTarget.new(ctx:, pc: next_pc), # fallthrough
- )
- branch_stub.target0.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, true)
- @ocb.write(ocb_asm)
- end
- branch_stub.target1.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, false)
- @ocb.write(ocb_asm)
- end
-
- # Jump to target0 on jz
- branch_stub.compile = compile_branchunless(branch_stub)
- branch_stub.compile.call(asm)
- end
-
- EndBlock
- end
-
- def compile_branchunless(branch_stub) # Proc escapes arguments in memory
- proc do |branch_asm|
- branch_asm.comment("branchunless #{branch_stub.shape}")
- branch_asm.stub(branch_stub) do
- case branch_stub.shape
- in Default
- branch_asm.jz(branch_stub.target0.address)
- branch_asm.jmp(branch_stub.target1.address)
- in Next0
- branch_asm.jnz(branch_stub.target1.address)
- in Next1
- branch_asm.jz(branch_stub.target0.address)
- end
- end
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def branchnil(jit, ctx, asm)
- # Check for interrupts, but only on backward branches that may create loops
- jump_offset = jit.operand(0, signed: true)
- if jump_offset < 0
- jit_check_ints(jit, ctx, asm)
- end
-
- # Get the branch target instruction offsets
- next_pc = jit.pc + C.VALUE.size * jit.insn.len
- jump_pc = jit.pc + C.VALUE.size * (jit.insn.len + jump_offset)
-
- val_type = ctx.get_opnd_type(StackOpnd[0])
- val_opnd = ctx.stack_pop(1)
-
- if (result = val_type.known_nil) != nil
- target_pc = result ? jump_pc : next_pc
- jit_direct_jump(jit.iseq, target_pc, ctx, asm)
- else
- asm.cmp(val_opnd, Qnil)
-
- # Set stubs
- branch_stub = BranchStub.new(
- iseq: jit.iseq,
- shape: Default,
- target0: BranchTarget.new(ctx:, pc: jump_pc), # branch target
- target1: BranchTarget.new(ctx:, pc: next_pc), # fallthrough
- )
- branch_stub.target0.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, true)
- @ocb.write(ocb_asm)
- end
- branch_stub.target1.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, false)
- @ocb.write(ocb_asm)
- end
-
- # Jump to target0 on je
- branch_stub.compile = compile_branchnil(branch_stub)
- branch_stub.compile.call(asm)
- end
-
- EndBlock
- end
-
- def compile_branchnil(branch_stub) # Proc escapes arguments in memory
- proc do |branch_asm|
- branch_asm.comment("branchnil #{branch_stub.shape}")
- branch_asm.stub(branch_stub) do
- case branch_stub.shape
- in Default
- branch_asm.je(branch_stub.target0.address)
- branch_asm.jmp(branch_stub.target1.address)
- in Next0
- branch_asm.jne(branch_stub.target1.address)
- in Next1
- branch_asm.je(branch_stub.target0.address)
- end
- end
- end
- end
-
- # once
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_case_dispatch(jit, ctx, asm)
- # Normally this instruction would lookup the key in a hash and jump to an
- # offset based on that.
- # Instead we can take the fallback case and continue with the next
- # instruction.
- # We'd hope that our jitted code will be sufficiently fast without the
- # hash lookup, at least for small hashes, but it's worth revisiting this
- # assumption in the future.
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
- starting_context = ctx.dup
-
- case_hash = jit.operand(0, ruby: true)
- else_offset = jit.operand(1)
-
- # Try to reorder case/else branches so that ones that are actually used come first.
- # Supporting only Fixnum for now so that the implementation can be an equality check.
- key_opnd = ctx.stack_pop(1)
- comptime_key = jit.peek_at_stack(0)
-
- # Check that all cases are fixnums to avoid having to register BOP assumptions on
- # all the types that case hashes support. This spends compile time to save memory.
- if fixnum?(comptime_key) && comptime_key <= 2**32 && C.rb_hash_keys(case_hash).all? { |key| fixnum?(key) }
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_EQQ)
- return CantCompile
- end
-
- # Check if the key is the same value
- asm.cmp(key_opnd, to_value(comptime_key))
- side_exit = side_exit(jit, starting_context)
- jit_chain_guard(:jne, jit, starting_context, asm, side_exit)
-
- # Get the offset for the compile-time key
- offset = C.rb_hash_stlike_lookup(case_hash, comptime_key)
- # NOTE: If we hit the else branch with various values, it could negatively impact the performance.
- jump_offset = offset || else_offset
-
- # Jump to the offset of case or else
- target_pc = jit.pc + (jit.insn.len + jump_offset) * C.VALUE.size
- jit_direct_jump(jit.iseq, target_pc, ctx, asm)
- EndBlock
- else
- KeepCompiling # continue with === branches
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_plus(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- comptime_recv = jit.peek_at_stack(1)
- comptime_obj = jit.peek_at_stack(0)
-
- if fixnum?(comptime_recv) && fixnum?(comptime_obj)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_PLUS)
- return CantCompile
- end
-
- # Check that both operands are fixnums
- guard_two_fixnums(jit, ctx, asm)
-
- obj_opnd = ctx.stack_pop
- recv_opnd = ctx.stack_pop
-
- asm.mov(:rax, recv_opnd)
- asm.sub(:rax, 1) # untag
- asm.mov(:rcx, obj_opnd)
- asm.add(:rax, :rcx)
- asm.jo(side_exit(jit, ctx))
-
- dst_opnd = ctx.stack_push(Type::Fixnum)
- asm.mov(dst_opnd, :rax)
-
- KeepCompiling
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_minus(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- comptime_recv = jit.peek_at_stack(1)
- comptime_obj = jit.peek_at_stack(0)
-
- if fixnum?(comptime_recv) && fixnum?(comptime_obj)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_MINUS)
- return CantCompile
- end
-
- # Check that both operands are fixnums
- guard_two_fixnums(jit, ctx, asm)
-
- obj_opnd = ctx.stack_pop
- recv_opnd = ctx.stack_pop
-
- asm.mov(:rax, recv_opnd)
- asm.mov(:rcx, obj_opnd)
- asm.sub(:rax, :rcx)
- asm.jo(side_exit(jit, ctx))
- asm.add(:rax, 1) # re-tag
-
- dst_opnd = ctx.stack_push(Type::Fixnum)
- asm.mov(dst_opnd, :rax)
-
- KeepCompiling
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_mult(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_div(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_mod(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- if two_fixnums_on_stack?(jit)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_MOD)
- return CantCompile
- end
-
- # Check that both operands are fixnums
- guard_two_fixnums(jit, ctx, asm)
-
- # Get the operands and destination from the stack
- arg1 = ctx.stack_pop(1)
- arg0 = ctx.stack_pop(1)
-
- # Check for arg0 % 0
- asm.cmp(arg1, 0)
- asm.je(side_exit(jit, ctx))
-
- # Call rb_fix_mod_fix(VALUE recv, VALUE obj)
- asm.mov(C_ARGS[0], arg0)
- asm.mov(C_ARGS[1], arg1)
- asm.call(C.rb_fix_mod_fix)
-
- # Push the return value onto the stack
- stack_ret = ctx.stack_push(Type::Fixnum)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_eq(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- if jit_equality_specialized(jit, ctx, asm, true)
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_neq(jit, ctx, asm)
- # opt_neq is passed two rb_call_data as arguments:
- # first for ==, second for !=
- neq_cd = C.rb_call_data.new(jit.operand(1))
- opt_send_without_block(jit, ctx, asm, cd: neq_cd)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_lt(jit, ctx, asm)
- jit_fixnum_cmp(jit, ctx, asm, opcode: :cmovl, bop: C::BOP_LT)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_le(jit, ctx, asm)
- jit_fixnum_cmp(jit, ctx, asm, opcode: :cmovle, bop: C::BOP_LE)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_gt(jit, ctx, asm)
- jit_fixnum_cmp(jit, ctx, asm, opcode: :cmovg, bop: C::BOP_GT)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_ge(jit, ctx, asm)
- jit_fixnum_cmp(jit, ctx, asm, opcode: :cmovge, bop: C::BOP_GE)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_ltlt(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_and(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- if two_fixnums_on_stack?(jit)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_AND)
- return CantCompile
- end
-
- # Check that both operands are fixnums
- guard_two_fixnums(jit, ctx, asm)
-
- # Get the operands and destination from the stack
- arg1 = ctx.stack_pop(1)
- arg0 = ctx.stack_pop(1)
-
- asm.comment('bitwise and')
- asm.mov(:rax, arg0)
- asm.and(:rax, arg1)
-
- # Push the return value onto the stack
- dst = ctx.stack_push(Type::Fixnum)
- asm.mov(dst, :rax)
-
- KeepCompiling
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_or(jit, ctx, asm)
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- if two_fixnums_on_stack?(jit)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_OR)
- return CantCompile
- end
-
- # Check that both operands are fixnums
- guard_two_fixnums(jit, ctx, asm)
-
- # Get the operands and destination from the stack
- asm.comment('bitwise or')
- arg1 = ctx.stack_pop(1)
- arg0 = ctx.stack_pop(1)
-
- # Do the bitwise or arg0 | arg1
- asm.mov(:rax, arg0)
- asm.or(:rax, arg1)
-
- # Push the return value onto the stack
- dst = ctx.stack_push(Type::Fixnum)
- asm.mov(dst, :rax)
-
- KeepCompiling
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_aref(jit, ctx, asm)
- cd = C.rb_call_data.new(jit.operand(0))
- argc = C.vm_ci_argc(cd.ci)
-
- if argc != 1
- asm.incr_counter(:optaref_argc_not_one)
- return CantCompile
- end
-
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- comptime_recv = jit.peek_at_stack(1)
- comptime_obj = jit.peek_at_stack(0)
-
- side_exit = side_exit(jit, ctx)
-
- if C.rb_class_of(comptime_recv) == Array && fixnum?(comptime_obj)
- unless Invariants.assume_bop_not_redefined(jit, C::ARRAY_REDEFINED_OP_FLAG, C::BOP_AREF)
- return CantCompile
- end
-
- idx_opnd = ctx.stack_opnd(0)
- recv_opnd = ctx.stack_opnd(1)
-
- not_array_exit = counted_exit(side_exit, :optaref_recv_not_array)
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_recv), recv_opnd, StackOpnd[1], comptime_recv, not_array_exit)
-
- # Bail if idx is not a FIXNUM
- asm.mov(:rax, idx_opnd)
- asm.test(:rax, C::RUBY_FIXNUM_FLAG)
- asm.jz(counted_exit(side_exit, :optaref_arg_not_fixnum))
-
- # Call VALUE rb_ary_entry_internal(VALUE ary, long offset).
- # It never raises or allocates, so we don't need to write to cfp->pc.
- asm.sar(:rax, 1) # Convert fixnum to int
- asm.mov(C_ARGS[0], recv_opnd)
- asm.mov(C_ARGS[1], :rax)
- asm.call(C.rb_ary_entry_internal)
-
- # Pop the argument and the receiver
- ctx.stack_pop(2)
-
- # Push the return value onto the stack
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- # Let guard chains share the same successor
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- elsif C.rb_class_of(comptime_recv) == Hash
- unless Invariants.assume_bop_not_redefined(jit, C::HASH_REDEFINED_OP_FLAG, C::BOP_AREF)
- return CantCompile
- end
-
- recv_opnd = ctx.stack_opnd(1)
-
- # Guard that the receiver is a Hash
- not_hash_exit = counted_exit(side_exit, :optaref_recv_not_hash)
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_recv), recv_opnd, StackOpnd[1], comptime_recv, not_hash_exit)
-
- # Prepare to call rb_hash_aref(). It might call #hash on the key.
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.comment('call rb_hash_aref')
- key_opnd = ctx.stack_opnd(0)
- recv_opnd = ctx.stack_opnd(1)
- asm.mov(:rdi, recv_opnd)
- asm.mov(:rsi, key_opnd)
- asm.call(C.rb_hash_aref)
-
- # Pop the key and the receiver
- ctx.stack_pop(2)
-
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- # Let guard chains share the same successor
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_aset(jit, ctx, asm)
- # Defer compilation so we can specialize on a runtime `self`
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- comptime_recv = jit.peek_at_stack(2)
- comptime_key = jit.peek_at_stack(1)
-
- # Get the operands from the stack
- recv = ctx.stack_opnd(2)
- key = ctx.stack_opnd(1)
- _val = ctx.stack_opnd(0)
-
- if C.rb_class_of(comptime_recv) == Array && fixnum?(comptime_key)
- side_exit = side_exit(jit, ctx)
-
- # Guard receiver is an Array
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_recv), recv, StackOpnd[2], comptime_recv, side_exit)
-
- # Guard key is a fixnum
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_key), key, StackOpnd[1], comptime_key, side_exit)
-
- # We might allocate or raise
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.comment('call rb_ary_store')
- recv = ctx.stack_opnd(2)
- key = ctx.stack_opnd(1)
- val = ctx.stack_opnd(0)
- asm.mov(:rax, key)
- asm.sar(:rax, 1) # FIX2LONG(key)
- asm.mov(C_ARGS[0], recv)
- asm.mov(C_ARGS[1], :rax)
- asm.mov(C_ARGS[2], val)
- asm.call(C.rb_ary_store)
-
- # rb_ary_store returns void
- # stored value should still be on stack
- val = ctx.stack_opnd(0)
-
- # Push the return value onto the stack
- ctx.stack_pop(3)
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(:rax, val)
- asm.mov(stack_ret, :rax)
-
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- elsif C.rb_class_of(comptime_recv) == Hash
- side_exit = side_exit(jit, ctx)
-
- # Guard receiver is a Hash
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_recv), recv, StackOpnd[2], comptime_recv, side_exit)
-
- # We might allocate or raise
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Call rb_hash_aset
- recv = ctx.stack_opnd(2)
- key = ctx.stack_opnd(1)
- val = ctx.stack_opnd(0)
- asm.mov(C_ARGS[0], recv)
- asm.mov(C_ARGS[1], key)
- asm.mov(C_ARGS[2], val)
- asm.call(C.rb_hash_aset)
-
- # Push the return value onto the stack
- ctx.stack_pop(3)
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # opt_aset_with
- # opt_aref_with
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_length(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_size(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_empty_p(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_succ(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_not(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_regexpmatch2(jit, ctx, asm)
- opt_send_without_block(jit, ctx, asm)
- end
-
- # invokebuiltin
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_invokebuiltin_delegate(jit, ctx, asm)
- bf = C.rb_builtin_function.new(jit.operand(0))
- bf_argc = bf.argc
- start_index = jit.operand(1)
-
- # ec, self, and arguments
- if bf_argc + 2 > C_ARGS.size
- return CantCompile
- end
-
- # If the calls don't allocate, do they need up to date PC, SP?
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Call the builtin func (ec, recv, arg1, arg2, ...)
- asm.comment('call builtin func')
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], [CFP, C.rb_control_frame_t.offsetof(:self)])
-
- # Copy arguments from locals
- if bf_argc > 0
- # Load environment pointer EP from CFP
- asm.mov(:rax, [CFP, C.rb_control_frame_t.offsetof(:ep)])
-
- bf_argc.times do |i|
- table_size = jit.iseq.body.local_table_size
- offs = -table_size - C::VM_ENV_DATA_SIZE + 1 + start_index + i
- asm.mov(C_ARGS[2 + i], [:rax, offs * C.VALUE.size])
- end
- end
- asm.call(bf.func_ptr)
-
- # Push the return value
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- KeepCompiling
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def opt_invokebuiltin_delegate_leave(jit, ctx, asm)
- opt_invokebuiltin_delegate(jit, ctx, asm)
- # opt_invokebuiltin_delegate is always followed by leave insn
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putobject_INT2FIX_0_(jit, ctx, asm)
- putobject(jit, ctx, asm, val: C.to_value(0))
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def putobject_INT2FIX_1_(jit, ctx, asm)
- putobject(jit, ctx, asm, val: C.to_value(1))
- end
-
- #
- # C func
- #
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_true(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 0
- asm.comment('nil? == true')
- ctx.stack_pop(1)
- stack_ret = ctx.stack_push(Type::True)
- asm.mov(stack_ret, Qtrue)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_false(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 0
- asm.comment('nil? == false')
- ctx.stack_pop(1)
- stack_ret = ctx.stack_push(Type::False)
- asm.mov(stack_ret, Qfalse)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_kernel_is_a(jit, ctx, asm, argc, known_recv_class)
- if argc != 1
- return false
- end
-
- # If this is a super call we might not know the class
- if known_recv_class.nil?
- return false
- end
-
- # Important note: The output code will simply `return true/false`.
- # Correctness follows from:
- # - `known_recv_class` implies there is a guard scheduled before here
- # for a particular `CLASS_OF(lhs)`.
- # - We guard that rhs is identical to the compile-time sample
- # - In general, for any two Class instances A, B, `A < B` does not change at runtime.
- # Class#superclass is stable.
-
- sample_rhs = jit.peek_at_stack(0)
- sample_lhs = jit.peek_at_stack(1)
-
- # We are not allowing module here because the module hierarchy can change at runtime.
- if C.RB_TYPE_P(sample_rhs, C::RUBY_T_CLASS)
- return false
- end
- sample_is_a = C.obj_is_kind_of(sample_lhs, sample_rhs)
-
- side_exit = side_exit(jit, ctx)
- asm.comment('Kernel#is_a?')
- asm.mov(:rax, to_value(sample_rhs))
- asm.cmp(ctx.stack_opnd(0), :rax)
- asm.jne(counted_exit(side_exit, :send_is_a_class_mismatch))
-
- ctx.stack_pop(2)
-
- if sample_is_a
- stack_ret = ctx.stack_push(Type::True)
- asm.mov(stack_ret, Qtrue)
- else
- stack_ret = ctx.stack_push(Type::False)
- asm.mov(stack_ret, Qfalse)
- end
- return true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_kernel_instance_of(jit, ctx, asm, argc, known_recv_class)
- if argc != 1
- return false
- end
-
- # If this is a super call we might not know the class
- if known_recv_class.nil?
- return false
- end
-
- # Important note: The output code will simply `return true/false`.
- # Correctness follows from:
- # - `known_recv_class` implies there is a guard scheduled before here
- # for a particular `CLASS_OF(lhs)`.
- # - We guard that rhs is identical to the compile-time sample
- # - For a particular `CLASS_OF(lhs)`, `rb_obj_class(lhs)` does not change.
- # (because for any singleton class `s`, `s.superclass.equal?(s.attached_object.class)`)
-
- sample_rhs = jit.peek_at_stack(0)
- sample_lhs = jit.peek_at_stack(1)
-
- # Filters out cases where the C implementation raises
- unless C.RB_TYPE_P(sample_rhs, C::RUBY_T_CLASS) || C.RB_TYPE_P(sample_rhs, C::RUBY_T_MODULE)
- return false
- end
-
- # We need to grab the class here to deal with singleton classes.
- # Instance of grabs the "real class" of the object rather than the
- # singleton class.
- sample_lhs_real_class = C.rb_obj_class(sample_lhs)
-
- sample_instance_of = (sample_lhs_real_class == sample_rhs)
-
- side_exit = side_exit(jit, ctx)
- asm.comment('Kernel#instance_of?')
- asm.mov(:rax, to_value(sample_rhs))
- asm.cmp(ctx.stack_opnd(0), :rax)
- asm.jne(counted_exit(side_exit, :send_instance_of_class_mismatch))
-
- ctx.stack_pop(2)
-
- if sample_instance_of
- stack_ret = ctx.stack_push(Type::True)
- asm.mov(stack_ret, Qtrue)
- else
- stack_ret = ctx.stack_push(Type::False)
- asm.mov(stack_ret, Qfalse)
- end
- return true;
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_obj_not(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 0
- recv_type = ctx.get_opnd_type(StackOpnd[0])
-
- case recv_type.known_truthy
- in false
- asm.comment('rb_obj_not(nil_or_false)')
- ctx.stack_pop(1)
- out_opnd = ctx.stack_push(Type::True)
- asm.mov(out_opnd, Qtrue)
- in true
- # Note: recv_type != Type::Nil && recv_type != Type::False.
- asm.comment('rb_obj_not(truthy)')
- ctx.stack_pop(1)
- out_opnd = ctx.stack_push(Type::False)
- asm.mov(out_opnd, Qfalse)
- in nil
- asm.comment('rb_obj_not')
-
- recv = ctx.stack_pop
- # This `test` sets ZF only for Qnil and Qfalse, which let cmovz set.
- asm.test(recv, ~Qnil)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmovz(:rax, :rcx)
-
- stack_ret = ctx.stack_push(Type::UnknownImm)
- asm.mov(stack_ret, :rax)
- end
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_obj_equal(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- asm.comment('equal?')
- obj1 = ctx.stack_pop(1)
- obj2 = ctx.stack_pop(1)
-
- asm.mov(:rax, obj1)
- asm.mov(:rcx, obj2)
- asm.cmp(:rax, :rcx)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmove(:rax, :rcx)
-
- stack_ret = ctx.stack_push(Type::UnknownImm)
- asm.mov(stack_ret, :rax)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_obj_not_equal(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- jit_equality_specialized(jit, ctx, asm, false)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_mod_eqq(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
-
- asm.comment('Module#===')
- # By being here, we know that the receiver is a T_MODULE or a T_CLASS, because Module#=== can
- # only live on these objects. With that, we can call rb_obj_is_kind_of() without
- # jit_prepare_routine_call() or a control frame push because it can't raise, allocate, or call
- # Ruby methods with these inputs.
- # Note the difference in approach from Kernel#is_a? because we don't get a free guard for the
- # right hand side.
- lhs = ctx.stack_opnd(1) # the module
- rhs = ctx.stack_opnd(0)
- asm.mov(C_ARGS[0], rhs);
- asm.mov(C_ARGS[1], lhs);
- asm.call(C.rb_obj_is_kind_of)
-
- # Return the result
- ctx.stack_pop(2)
- stack_ret = ctx.stack_push(Type::UnknownImm)
- asm.mov(stack_ret, C_RET)
-
- return true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_int_equal(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- return false unless two_fixnums_on_stack?(jit)
-
- guard_two_fixnums(jit, ctx, asm)
-
- # Compare the arguments
- asm.comment('rb_int_equal')
- arg1 = ctx.stack_pop(1)
- arg0 = ctx.stack_pop(1)
- asm.mov(:rax, arg1)
- asm.cmp(arg0, :rax)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmove(:rax, :rcx)
-
- stack_ret = ctx.stack_push(Type::UnknownImm)
- asm.mov(stack_ret, :rax)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_int_mul(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- return false unless two_fixnums_on_stack?(jit)
-
- guard_two_fixnums(jit, ctx, asm)
-
- asm.comment('rb_int_mul')
- y_opnd = ctx.stack_pop
- x_opnd = ctx.stack_pop
- asm.mov(C_ARGS[0], x_opnd)
- asm.mov(C_ARGS[1], y_opnd)
- asm.call(C.rb_fix_mul_fix)
-
- ret_opnd = ctx.stack_push(Type::Unknown)
- asm.mov(ret_opnd, C_RET)
- true
- end
-
- def jit_rb_int_div(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- return false unless two_fixnums_on_stack?(jit)
-
- guard_two_fixnums(jit, ctx, asm)
-
- asm.comment('rb_int_div')
- y_opnd = ctx.stack_pop
- x_opnd = ctx.stack_pop
- asm.mov(:rax, y_opnd)
- asm.cmp(:rax, C.to_value(0))
- asm.je(side_exit(jit, ctx))
-
- asm.mov(C_ARGS[0], x_opnd)
- asm.mov(C_ARGS[1], :rax)
- asm.call(C.rb_fix_div_fix)
-
- ret_opnd = ctx.stack_push(Type::Unknown)
- asm.mov(ret_opnd, C_RET)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_int_aref(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- return false unless two_fixnums_on_stack?(jit)
-
- guard_two_fixnums(jit, ctx, asm)
-
- asm.comment('rb_int_aref')
- y_opnd = ctx.stack_pop
- x_opnd = ctx.stack_pop
-
- asm.mov(C_ARGS[0], x_opnd)
- asm.mov(C_ARGS[1], y_opnd)
- asm.call(C.rb_fix_aref)
-
- ret_opnd = ctx.stack_push(Type::UnknownImm)
- asm.mov(ret_opnd, C_RET)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_str_empty_p(jit, ctx, asm, argc, known_recv_class)
- recv_opnd = ctx.stack_pop(1)
- out_opnd = ctx.stack_push(Type::UnknownImm)
-
- asm.comment('get string length')
- asm.mov(:rax, recv_opnd)
- str_len_opnd = [:rax, C.RString.offsetof(:len)]
-
- asm.cmp(str_len_opnd, 0)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmove(:rax, :rcx)
- asm.mov(out_opnd, :rax)
-
- return true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_str_to_s(jit, ctx, asm, argc, known_recv_class)
- return false if argc != 0
- if known_recv_class == String
- asm.comment('to_s on plain string')
- # The method returns the receiver, which is already on the stack.
- # No stack movement.
- return true
- end
- false
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_str_bytesize(jit, ctx, asm, argc, known_recv_class)
- asm.comment('String#bytesize')
-
- recv = ctx.stack_pop(1)
- asm.mov(C_ARGS[0], recv)
- asm.call(C.rb_str_bytesize)
-
- out_opnd = ctx.stack_push(Type::Fixnum)
- asm.mov(out_opnd, C_RET)
-
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_str_concat(jit, ctx, asm, argc, known_recv_class)
- # The << operator can accept integer codepoints for characters
- # as the argument. We only specially optimise string arguments.
- # If the peeked-at compile time argument is something other than
- # a string, assume it won't be a string later either.
- comptime_arg = jit.peek_at_stack(0)
- unless C.RB_TYPE_P(comptime_arg, C::RUBY_T_STRING)
- return false
- end
-
- # Guard that the concat argument is a string
- asm.mov(:rax, ctx.stack_opnd(0))
- guard_object_is_string(jit, ctx, asm, :rax, :rcx, StackOpnd[0])
-
- # Guard buffers from GC since rb_str_buf_append may allocate. During the VM lock on GC,
- # other Ractors may trigger global invalidation, so we need ctx.clear_local_types.
- # PC is used on errors like Encoding::CompatibilityError raised by rb_str_buf_append.
- jit_prepare_routine_call(jit, ctx, asm)
-
- concat_arg = ctx.stack_pop(1)
- recv = ctx.stack_pop(1)
-
- # Test if string encodings differ. If different, use rb_str_append. If the same,
- # use rb_yjit_str_simple_append, which calls rb_str_cat.
- asm.comment('<< on strings')
-
- # Take receiver's object flags XOR arg's flags. If any
- # string-encoding flags are different between the two,
- # the encodings don't match.
- recv_reg = :rax
- asm.mov(recv_reg, recv)
- concat_arg_reg = :rcx
- asm.mov(concat_arg_reg, concat_arg)
- asm.mov(recv_reg, [recv_reg, C.RBasic.offsetof(:flags)])
- asm.mov(concat_arg_reg, [concat_arg_reg, C.RBasic.offsetof(:flags)])
- asm.xor(recv_reg, concat_arg_reg)
- asm.test(recv_reg, C::RUBY_ENCODING_MASK)
-
- # Push once, use the resulting operand in both branches below.
- stack_ret = ctx.stack_push(Type::TString)
-
- enc_mismatch = asm.new_label('enc_mismatch')
- asm.jnz(enc_mismatch)
-
- # If encodings match, call the simple append function and jump to return
- asm.mov(C_ARGS[0], recv)
- asm.mov(C_ARGS[1], concat_arg)
- asm.call(C.rjit_str_simple_append)
- ret_label = asm.new_label('func_return')
- asm.mov(stack_ret, C_RET)
- asm.jmp(ret_label)
-
- # If encodings are different, use a slower encoding-aware concatenate
- asm.write_label(enc_mismatch)
- asm.mov(C_ARGS[0], recv)
- asm.mov(C_ARGS[1], concat_arg)
- asm.call(C.rb_str_buf_append)
- asm.mov(stack_ret, C_RET)
- # Drop through to return
-
- asm.write_label(ret_label)
-
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_str_uplus(jit, ctx, asm, argc, _known_recv_class)
- if argc != 0
- return false
- end
-
- # We allocate when we dup the string
- jit_prepare_routine_call(jit, ctx, asm)
-
- asm.comment('Unary plus on string')
- asm.mov(:rax, ctx.stack_pop(1)) # recv_opnd
- asm.mov(:rcx, [:rax, C.RBasic.offsetof(:flags)]) # flags_opnd
- asm.test(:rcx, C::RUBY_FL_FREEZE)
-
- ret_label = asm.new_label('stack_ret')
-
- # String#+@ can only exist on T_STRING
- stack_ret = ctx.stack_push(Type::TString)
-
- # If the string isn't frozen, we just return it.
- asm.mov(stack_ret, :rax) # recv_opnd
- asm.jz(ret_label)
-
- # Str is frozen - duplicate it
- asm.mov(C_ARGS[0], :rax) # recv_opnd
- asm.call(C.rb_str_dup)
- asm.mov(stack_ret, C_RET)
-
- asm.write_label(ret_label)
-
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_str_getbyte(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- asm.comment('rb_str_getbyte')
-
- index_opnd = ctx.stack_pop
- str_opnd = ctx.stack_pop
- asm.mov(C_ARGS[0], str_opnd)
- asm.mov(C_ARGS[1], index_opnd)
- asm.call(C.rb_str_getbyte)
-
- ret_opnd = ctx.stack_push(Type::Fixnum)
- asm.mov(ret_opnd, C_RET)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_ary_empty_p(jit, ctx, asm, argc, _known_recv_class)
- array_reg = :rax
- asm.mov(array_reg, ctx.stack_pop(1))
- jit_array_len(asm, array_reg, :rcx)
-
- asm.test(:rcx, :rcx)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmovz(:rax, :rcx)
-
- out_opnd = ctx.stack_push(Type::UnknownImm)
- asm.mov(out_opnd, :rax)
-
- return true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_ary_push(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 1
- asm.comment('rb_ary_push')
-
- jit_prepare_routine_call(jit, ctx, asm)
-
- item_opnd = ctx.stack_pop
- ary_opnd = ctx.stack_pop
- asm.mov(C_ARGS[0], ary_opnd)
- asm.mov(C_ARGS[1], item_opnd)
- asm.call(C.rb_ary_push)
-
- ret_opnd = ctx.stack_push(Type::TArray)
- asm.mov(ret_opnd, C_RET)
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_obj_respond_to(jit, ctx, asm, argc, known_recv_class)
- # respond_to(:sym) or respond_to(:sym, true)
- if argc != 1 && argc != 2
- return false
- end
-
- if known_recv_class.nil?
- return false
- end
-
- recv_class = known_recv_class
-
- # Get the method_id from compile time. We will later add a guard against it.
- mid_sym = jit.peek_at_stack(argc - 1)
- unless static_symbol?(mid_sym)
- return false
- end
- mid = C.rb_sym2id(mid_sym)
-
- # This represents the value of the "include_all" argument and whether it's known
- allow_priv = if argc == 1
- # Default is false
- false
- else
- # Get value from type information (may or may not be known)
- ctx.get_opnd_type(StackOpnd[0]).known_truthy
- end
-
- target_cme = C.rb_callable_method_entry_or_negative(recv_class, mid)
-
- # Should never be null, as in that case we will be returned a "negative CME"
- assert_equal(false, target_cme.nil?)
-
- cme_def_type = C.UNDEFINED_METHOD_ENTRY_P(target_cme) ? C::VM_METHOD_TYPE_UNDEF : target_cme.def.type
-
- if cme_def_type == C::VM_METHOD_TYPE_REFINED
- return false
- end
-
- visibility = if cme_def_type == C::VM_METHOD_TYPE_UNDEF
- C::METHOD_VISI_UNDEF
- else
- C.METHOD_ENTRY_VISI(target_cme)
- end
-
- result =
- case [visibility, allow_priv]
- in C::METHOD_VISI_UNDEF, _ then Qfalse # No method => false
- in C::METHOD_VISI_PUBLIC, _ then Qtrue # Public method => true regardless of include_all
- in _, true then Qtrue # include_all => always true
- else return false # not public and include_all not known, can't compile
- end
-
- if result != Qtrue
- # Only if respond_to_missing? hasn't been overridden
- # In the future, we might want to jit the call to respond_to_missing?
- unless Invariants.assume_method_basic_definition(jit, recv_class, C.idRespond_to_missing)
- return false
- end
- end
-
- # Invalidate this block if method lookup changes for the method being queried. This works
- # both for the case where a method does or does not exist, as for the latter we asked for a
- # "negative CME" earlier.
- Invariants.assume_method_lookup_stable(jit, target_cme)
-
- # Generate a side exit
- side_exit = side_exit(jit, ctx)
-
- if argc == 2
- # pop include_all argument (we only use its type info)
- ctx.stack_pop(1)
- end
-
- sym_opnd = ctx.stack_pop(1)
- _recv_opnd = ctx.stack_pop(1)
-
- # This is necessary because we have no guarantee that sym_opnd is a constant
- asm.comment('guard known mid')
- asm.mov(:rax, to_value(mid_sym))
- asm.cmp(sym_opnd, :rax)
- asm.jne(side_exit)
-
- putobject(jit, ctx, asm, val: result)
-
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_rb_f_block_given_p(jit, ctx, asm, argc, _known_recv_class)
- asm.comment('block_given?')
-
- # Same as rb_vm_frame_block_handler
- jit_get_lep(jit, asm, reg: :rax)
- asm.mov(:rax, [:rax, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]) # block_handler
-
- ctx.stack_pop(1)
- out_opnd = ctx.stack_push(Type::UnknownImm)
-
- # Return `block_handler != VM_BLOCK_HANDLER_NONE`
- asm.cmp(:rax, C::VM_BLOCK_HANDLER_NONE)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.cmovne(:rax, :rcx) # block_given
- asm.mov(out_opnd, :rax)
-
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_thread_s_current(jit, ctx, asm, argc, _known_recv_class)
- return false if argc != 0
- asm.comment('Thread.current')
- ctx.stack_pop(1)
-
- # ec->thread_ptr
- asm.mov(:rax, [EC, C.rb_execution_context_t.offsetof(:thread_ptr)])
-
- # thread->self
- asm.mov(:rax, [:rax, C.rb_thread_struct.offsetof(:self)])
-
- stack_ret = ctx.stack_push(Type::UnknownHeap)
- asm.mov(stack_ret, :rax)
- true
- end
-
- #
- # Helpers
- #
-
- def register_cfunc_codegen_funcs
- # Specialization for C methods. See register_cfunc_method for details.
- register_cfunc_method(BasicObject, :!, :jit_rb_obj_not)
-
- register_cfunc_method(NilClass, :nil?, :jit_rb_true)
- register_cfunc_method(Kernel, :nil?, :jit_rb_false)
- register_cfunc_method(Kernel, :is_a?, :jit_rb_kernel_is_a)
- register_cfunc_method(Kernel, :kind_of?, :jit_rb_kernel_is_a)
- register_cfunc_method(Kernel, :instance_of?, :jit_rb_kernel_instance_of)
-
- register_cfunc_method(BasicObject, :==, :jit_rb_obj_equal)
- register_cfunc_method(BasicObject, :equal?, :jit_rb_obj_equal)
- register_cfunc_method(BasicObject, :!=, :jit_rb_obj_not_equal)
- register_cfunc_method(Kernel, :eql?, :jit_rb_obj_equal)
- register_cfunc_method(Module, :==, :jit_rb_obj_equal)
- register_cfunc_method(Module, :===, :jit_rb_mod_eqq)
- register_cfunc_method(Symbol, :==, :jit_rb_obj_equal)
- register_cfunc_method(Symbol, :===, :jit_rb_obj_equal)
- register_cfunc_method(Integer, :==, :jit_rb_int_equal)
- register_cfunc_method(Integer, :===, :jit_rb_int_equal)
-
- # rb_str_to_s() methods in string.c
- register_cfunc_method(String, :empty?, :jit_rb_str_empty_p)
- register_cfunc_method(String, :to_s, :jit_rb_str_to_s)
- register_cfunc_method(String, :to_str, :jit_rb_str_to_s)
- register_cfunc_method(String, :bytesize, :jit_rb_str_bytesize)
- register_cfunc_method(String, :<<, :jit_rb_str_concat)
- register_cfunc_method(String, :+@, :jit_rb_str_uplus)
-
- # rb_ary_empty_p() method in array.c
- register_cfunc_method(Array, :empty?, :jit_rb_ary_empty_p)
-
- register_cfunc_method(Kernel, :respond_to?, :jit_obj_respond_to)
- register_cfunc_method(Kernel, :block_given?, :jit_rb_f_block_given_p)
-
- # Thread.current
- register_cfunc_method(C.rb_singleton_class(Thread), :current, :jit_thread_s_current)
-
- #---
- register_cfunc_method(Array, :<<, :jit_rb_ary_push)
- register_cfunc_method(Integer, :*, :jit_rb_int_mul)
- register_cfunc_method(Integer, :/, :jit_rb_int_div)
- register_cfunc_method(Integer, :[], :jit_rb_int_aref)
- register_cfunc_method(String, :getbyte, :jit_rb_str_getbyte)
- end
-
- def register_cfunc_method(klass, mid_sym, func)
- mid = C.rb_intern(mid_sym.to_s)
- me = C.rb_method_entry_at(klass, mid)
-
- assert_equal(false, me.nil?)
-
- # Only cfuncs are supported
- method_serial = me.def.method_serial
-
- @cfunc_codegen_table[method_serial] = method(func)
- end
-
- def lookup_cfunc_codegen(cme_def)
- @cfunc_codegen_table[cme_def.method_serial]
- end
-
- def stack_swap(_jit, ctx, asm, offset0, offset1)
- stack0_mem = ctx.stack_opnd(offset0)
- stack1_mem = ctx.stack_opnd(offset1)
-
- mapping0 = ctx.get_opnd_mapping(StackOpnd[offset0])
- mapping1 = ctx.get_opnd_mapping(StackOpnd[offset1])
-
- asm.mov(:rax, stack0_mem)
- asm.mov(:rcx, stack1_mem)
- asm.mov(stack0_mem, :rcx)
- asm.mov(stack1_mem, :rax)
-
- ctx.set_opnd_mapping(StackOpnd[offset0], mapping1)
- ctx.set_opnd_mapping(StackOpnd[offset1], mapping0)
- end
-
- def jit_getlocal_generic(jit, ctx, asm, idx:, level:)
- # Load environment pointer EP (level 0) from CFP
- ep_reg = :rax
- jit_get_ep(asm, level, reg: ep_reg)
-
- # Load the local from the block
- # val = *(vm_get_ep(GET_EP(), level) - idx);
- asm.mov(:rax, [ep_reg, -idx * C.VALUE.size])
-
- # Write the local at SP
- stack_top = if level == 0
- local_idx = ep_offset_to_local_idx(jit.iseq, idx)
- ctx.stack_push_local(local_idx)
- else
- ctx.stack_push(Type::Unknown)
- end
-
- asm.mov(stack_top, :rax)
- KeepCompiling
- end
-
- def jit_setlocal_generic(jit, ctx, asm, idx:, level:)
- value_type = ctx.get_opnd_type(StackOpnd[0])
-
- # Load environment pointer EP at level
- ep_reg = :rax
- jit_get_ep(asm, level, reg: ep_reg)
-
- # Write barriers may be required when VM_ENV_FLAG_WB_REQUIRED is set, however write barriers
- # only affect heap objects being written. If we know an immediate value is being written we
- # can skip this check.
- unless value_type.imm?
- # flags & VM_ENV_FLAG_WB_REQUIRED
- flags_opnd = [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_FLAGS]
- asm.test(flags_opnd, C::VM_ENV_FLAG_WB_REQUIRED)
-
- # if (flags & VM_ENV_FLAG_WB_REQUIRED) != 0
- asm.jnz(side_exit(jit, ctx))
- end
-
- if level == 0
- local_idx = ep_offset_to_local_idx(jit.iseq, idx)
- ctx.set_local_type(local_idx, value_type)
- end
-
- # Pop the value to write from the stack
- stack_top = ctx.stack_pop(1)
-
- # Write the value at the environment pointer
- asm.mov(:rcx, stack_top)
- asm.mov([ep_reg, -(C.VALUE.size * idx)], :rcx)
-
- KeepCompiling
- end
-
- # Compute the index of a local variable from its slot index
- def ep_offset_to_local_idx(iseq, ep_offset)
- # Layout illustration
- # This is an array of VALUE
- # | VM_ENV_DATA_SIZE |
- # v v
- # low addr <+-------+-------+-------+-------+------------------+
- # |local 0|local 1| ... |local n| .... |
- # +-------+-------+-------+-------+------------------+
- # ^ ^ ^ ^
- # +-------+---local_table_size----+ cfp->ep--+
- # | |
- # +------------------ep_offset---------------+
- #
- # See usages of local_var_name() from iseq.c for similar calculation.
-
- # Equivalent of iseq->body->local_table_size
- local_table_size = iseq.body.local_table_size
- op = ep_offset - C::VM_ENV_DATA_SIZE
- local_idx = local_table_size - op - 1
- assert_equal(true, local_idx >= 0 && local_idx < local_table_size)
- local_idx
- end
-
- # Compute the index of a local variable from its slot index
- def slot_to_local_idx(iseq, slot_idx)
- # Layout illustration
- # This is an array of VALUE
- # | VM_ENV_DATA_SIZE |
- # v v
- # low addr <+-------+-------+-------+-------+------------------+
- # |local 0|local 1| ... |local n| .... |
- # +-------+-------+-------+-------+------------------+
- # ^ ^ ^ ^
- # +-------+---local_table_size----+ cfp->ep--+
- # | |
- # +------------------slot_idx----------------+
- #
- # See usages of local_var_name() from iseq.c for similar calculation.
-
- local_table_size = iseq.body.local_table_size
- op = slot_idx - C::VM_ENV_DATA_SIZE
- local_table_size - op - 1
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def guard_object_is_heap(jit, ctx, asm, object, object_opnd, counter = nil)
- object_type = ctx.get_opnd_type(object_opnd)
- if object_type.heap?
- return
- end
-
- side_exit = side_exit(jit, ctx)
- side_exit = counted_exit(side_exit, counter) if counter
-
- asm.comment('guard object is heap')
- # Test that the object is not an immediate
- asm.test(object, C::RUBY_IMMEDIATE_MASK)
- asm.jnz(side_exit)
-
- # Test that the object is not false
- asm.cmp(object, Qfalse)
- asm.je(side_exit)
-
- if object_type.diff(Type::UnknownHeap) != TypeDiff::Incompatible
- ctx.upgrade_opnd_type(object_opnd, Type::UnknownHeap)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def guard_object_is_array(jit, ctx, asm, object_reg, flags_reg, object_opnd, counter = nil)
- object_type = ctx.get_opnd_type(object_opnd)
- if object_type.array?
- return
- end
-
- guard_object_is_heap(jit, ctx, asm, object_reg, object_opnd, counter)
-
- side_exit = side_exit(jit, ctx)
- side_exit = counted_exit(side_exit, counter) if counter
-
- asm.comment('guard object is array')
- # Pull out the type mask
- asm.mov(flags_reg, [object_reg, C.RBasic.offsetof(:flags)])
- asm.and(flags_reg, C::RUBY_T_MASK)
-
- # Compare the result with T_ARRAY
- asm.cmp(flags_reg, C::RUBY_T_ARRAY)
- asm.jne(side_exit)
-
- if object_type.diff(Type::TArray) != TypeDiff::Incompatible
- ctx.upgrade_opnd_type(object_opnd, Type::TArray)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def guard_object_is_string(jit, ctx, asm, object_reg, flags_reg, object_opnd, counter = nil)
- object_type = ctx.get_opnd_type(object_opnd)
- if object_type.string?
- return
- end
-
- guard_object_is_heap(jit, ctx, asm, object_reg, object_opnd, counter)
-
- side_exit = side_exit(jit, ctx)
- side_exit = counted_exit(side_exit, counter) if counter
-
- asm.comment('guard object is string')
- # Pull out the type mask
- asm.mov(flags_reg, [object_reg, C.RBasic.offsetof(:flags)])
- asm.and(flags_reg, C::RUBY_T_MASK)
-
- # Compare the result with T_STRING
- asm.cmp(flags_reg, C::RUBY_T_STRING)
- asm.jne(side_exit)
-
- if object_type.diff(Type::TString) != TypeDiff::Incompatible
- ctx.upgrade_opnd_type(object_opnd, Type::TString)
- end
- end
-
- # clobbers object_reg
- def guard_object_is_not_ruby2_keyword_hash(asm, object_reg, flags_reg, side_exit)
- asm.comment('guard object is not ruby2 keyword hash')
-
- not_ruby2_keyword = asm.new_label('not_ruby2_keyword')
- asm.test(object_reg, C::RUBY_IMMEDIATE_MASK)
- asm.jnz(not_ruby2_keyword)
-
- asm.cmp(object_reg, Qfalse)
- asm.je(not_ruby2_keyword)
-
- asm.mov(flags_reg, [object_reg, C.RBasic.offsetof(:flags)])
- type_reg = object_reg
- asm.mov(type_reg, flags_reg)
- asm.and(type_reg, C::RUBY_T_MASK)
-
- asm.cmp(type_reg, C::RUBY_T_HASH)
- asm.jne(not_ruby2_keyword)
-
- asm.test(flags_reg, C::RHASH_PASS_AS_KEYWORDS)
- asm.jnz(side_exit)
-
- asm.write_label(not_ruby2_keyword)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_chain_guard(opcode, jit, ctx, asm, side_exit, limit: 20)
- opcode => :je | :jne | :jnz | :jz
-
- if ctx.chain_depth < limit
- deeper = ctx.dup
- deeper.chain_depth += 1
-
- branch_stub = BranchStub.new(
- iseq: jit.iseq,
- shape: Default,
- target0: BranchTarget.new(ctx: deeper, pc: jit.pc),
- )
- branch_stub.target0.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(deeper, ocb_asm, branch_stub, true)
- @ocb.write(ocb_asm)
- end
- branch_stub.compile = compile_jit_chain_guard(branch_stub, opcode:)
- branch_stub.compile.call(asm)
- else
- asm.public_send(opcode, side_exit)
- end
- end
-
- def compile_jit_chain_guard(branch_stub, opcode:) # Proc escapes arguments in memory
- proc do |branch_asm|
- # Not using `asm.comment` here since it's usually put before cmp/test before this.
- branch_asm.stub(branch_stub) do
- case branch_stub.shape
- in Default
- branch_asm.public_send(opcode, branch_stub.target0.address)
- end
- end
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_guard_known_klass(jit, ctx, asm, known_klass, obj_opnd, insn_opnd, comptime_obj, side_exit, limit: 10)
- # Only memory operand is supported for now
- assert_equal(true, obj_opnd.is_a?(Array))
-
- known_klass = C.to_value(known_klass)
- val_type = ctx.get_opnd_type(insn_opnd)
- if val_type.known_class == known_klass
- # We already know from type information that this is a match
- return
- end
-
- # Touching this as Ruby could crash for FrozenCore
- if known_klass == C.rb_cNilClass
- assert(!val_type.heap?)
- assert(val_type.unknown?)
-
- asm.comment('guard object is nil')
- asm.cmp(obj_opnd, Qnil)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
-
- ctx.upgrade_opnd_type(insn_opnd, Type::Nil)
- elsif known_klass == C.rb_cTrueClass
- assert(!val_type.heap?)
- assert(val_type.unknown?)
-
- asm.comment('guard object is true')
- asm.cmp(obj_opnd, Qtrue)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
-
- ctx.upgrade_opnd_type(insn_opnd, Type::True)
- elsif known_klass == C.rb_cFalseClass
- assert(!val_type.heap?)
- assert(val_type.unknown?)
-
- asm.comment('guard object is false')
- asm.cmp(obj_opnd, Qfalse)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
-
- ctx.upgrade_opnd_type(insn_opnd, Type::False)
- elsif known_klass == C.rb_cInteger && fixnum?(comptime_obj)
- # We will guard fixnum and bignum as though they were separate classes
- # BIGNUM can be handled by the general else case below
- assert(val_type.unknown?)
-
- asm.comment('guard object is fixnum')
- asm.test(obj_opnd, C::RUBY_FIXNUM_FLAG)
- jit_chain_guard(:jz, jit, ctx, asm, side_exit, limit:)
-
- ctx.upgrade_opnd_type(insn_opnd, Type::Fixnum)
- elsif known_klass == C.rb_cSymbol && static_symbol?(comptime_obj)
- assert(!val_type.heap?)
- # We will guard STATIC vs DYNAMIC as though they were separate classes
- # DYNAMIC symbols can be handled by the general else case below
- if val_type != Type::ImmSymbol || !val_type.imm?
- assert(val_type.unknown?)
-
- asm.comment('guard object is static symbol')
- assert_equal(8, C::RUBY_SPECIAL_SHIFT)
- asm.cmp(BytePtr[*obj_opnd], C::RUBY_SYMBOL_FLAG)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
-
- ctx.upgrade_opnd_type(insn_opnd, Type::ImmSymbol)
- end
- elsif known_klass == C.rb_cFloat && flonum?(comptime_obj)
- assert(!val_type.heap?)
- if val_type != Type::Flonum || !val_type.imm?
- assert(val_type.unknown?)
-
- # We will guard flonum vs heap float as though they were separate classes
- asm.comment('guard object is flonum')
- asm.mov(:rax, obj_opnd)
- asm.and(:rax, C::RUBY_FLONUM_MASK)
- asm.cmp(:rax, C::RUBY_FLONUM_FLAG)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
-
- ctx.upgrade_opnd_type(insn_opnd, Type::Flonum)
- end
- elsif C.RCLASS_SINGLETON_P(known_klass) && comptime_obj == C.rb_class_attached_object(known_klass)
- # Singleton classes are attached to one specific object, so we can
- # avoid one memory access (and potentially the is_heap check) by
- # looking for the expected object directly.
- # Note that in case the sample instance has a singleton class that
- # doesn't attach to the sample instance, it means the sample instance
- # has an empty singleton class that hasn't been materialized yet. In
- # this case, comparing against the sample instance doesn't guarantee
- # that its singleton class is empty, so we can't avoid the memory
- # access. As an example, `Object.new.singleton_class` is an object in
- # this situation.
- asm.comment('guard known object with singleton class')
- asm.mov(:rax, to_value(comptime_obj))
- asm.cmp(obj_opnd, :rax)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
- elsif val_type == Type::CString && known_klass == C.rb_cString
- # guard elided because the context says we've already checked
- assert_equal(C.to_value(C.rb_class_of(comptime_obj)), C.rb_cString)
- else
- assert(!val_type.imm?)
-
- # Load memory to a register
- asm.mov(:rax, obj_opnd)
- obj_opnd = :rax
-
- # Check that the receiver is a heap object
- # Note: if we get here, the class doesn't have immediate instances.
- unless val_type.heap?
- asm.comment('guard not immediate')
- asm.test(obj_opnd, C::RUBY_IMMEDIATE_MASK)
- jit_chain_guard(:jnz, jit, ctx, asm, side_exit, limit:)
- asm.cmp(obj_opnd, Qfalse)
- jit_chain_guard(:je, jit, ctx, asm, side_exit, limit:)
- end
-
- # Bail if receiver class is different from known_klass
- klass_opnd = [obj_opnd, C.RBasic.offsetof(:klass)]
- asm.comment("guard known class #{known_klass}")
- asm.mov(:rcx, known_klass)
- asm.cmp(klass_opnd, :rcx)
- jit_chain_guard(:jne, jit, ctx, asm, side_exit, limit:)
-
- if known_klass == C.rb_cString
- # Upgrading to Type::CString here is incorrect.
- # The guard we put only checks RBASIC_CLASS(obj),
- # which adding a singleton class can change. We
- # additionally need to know the string is frozen
- # to claim Type::CString.
- ctx.upgrade_opnd_type(insn_opnd, Type::TString)
- elsif known_klass == C.rb_cArray
- ctx.upgrade_opnd_type(insn_opnd, Type::TArray)
- end
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- def two_fixnums_on_stack?(jit)
- comptime_recv = jit.peek_at_stack(1)
- comptime_arg = jit.peek_at_stack(0)
- return fixnum?(comptime_recv) && fixnum?(comptime_arg)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def guard_two_fixnums(jit, ctx, asm)
- # Get stack operands without popping them
- arg1 = ctx.stack_opnd(0)
- arg0 = ctx.stack_opnd(1)
-
- # Get the stack operand types
- arg1_type = ctx.get_opnd_type(StackOpnd[0])
- arg0_type = ctx.get_opnd_type(StackOpnd[1])
-
- if arg0_type.heap? || arg1_type.heap?
- asm.comment('arg is heap object')
- asm.jmp(side_exit(jit, ctx))
- return
- end
-
- if arg0_type != Type::Fixnum && arg0_type.specific?
- asm.comment('arg0 not fixnum')
- asm.jmp(side_exit(jit, ctx))
- return
- end
-
- if arg1_type != Type::Fixnum && arg1_type.specific?
- asm.comment('arg1 not fixnum')
- asm.jmp(side_exit(jit, ctx))
- return
- end
-
- assert(!arg0_type.heap?)
- assert(!arg1_type.heap?)
- assert(arg0_type == Type::Fixnum || arg0_type.unknown?)
- assert(arg1_type == Type::Fixnum || arg1_type.unknown?)
-
- # If not fixnums at run-time, fall back
- if arg0_type != Type::Fixnum
- asm.comment('guard arg0 fixnum')
- asm.test(arg0, C::RUBY_FIXNUM_FLAG)
- jit_chain_guard(:jz, jit, ctx, asm, side_exit(jit, ctx))
- end
- if arg1_type != Type::Fixnum
- asm.comment('guard arg1 fixnum')
- asm.test(arg1, C::RUBY_FIXNUM_FLAG)
- jit_chain_guard(:jz, jit, ctx, asm, side_exit(jit, ctx))
- end
-
- # Set stack types in context
- ctx.upgrade_opnd_type(StackOpnd[0], Type::Fixnum)
- ctx.upgrade_opnd_type(StackOpnd[1], Type::Fixnum)
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_fixnum_cmp(jit, ctx, asm, opcode:, bop:)
- opcode => :cmovl | :cmovle | :cmovg | :cmovge
-
- unless jit.at_current_insn?
- defer_compilation(jit, ctx, asm)
- return EndBlock
- end
-
- comptime_recv = jit.peek_at_stack(1)
- comptime_obj = jit.peek_at_stack(0)
-
- if fixnum?(comptime_recv) && fixnum?(comptime_obj)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, bop)
- return CantCompile
- end
-
- # Check that both operands are fixnums
- guard_two_fixnums(jit, ctx, asm)
-
- obj_opnd = ctx.stack_pop
- recv_opnd = ctx.stack_pop
-
- asm.mov(:rax, obj_opnd)
- asm.cmp(recv_opnd, :rax)
- asm.mov(:rax, Qfalse)
- asm.mov(:rcx, Qtrue)
- asm.public_send(opcode, :rax, :rcx)
-
- dst_opnd = ctx.stack_push(Type::UnknownImm)
- asm.mov(dst_opnd, :rax)
-
- KeepCompiling
- else
- opt_send_without_block(jit, ctx, asm)
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_equality_specialized(jit, ctx, asm, gen_eq)
- # Create a side-exit to fall back to the interpreter
- side_exit = side_exit(jit, ctx)
-
- a_opnd = ctx.stack_opnd(1)
- b_opnd = ctx.stack_opnd(0)
-
- comptime_a = jit.peek_at_stack(1)
- comptime_b = jit.peek_at_stack(0)
-
- if two_fixnums_on_stack?(jit)
- unless Invariants.assume_bop_not_redefined(jit, C::INTEGER_REDEFINED_OP_FLAG, C::BOP_EQ)
- return false
- end
-
- guard_two_fixnums(jit, ctx, asm)
-
- asm.comment('check fixnum equality')
- asm.mov(:rax, a_opnd)
- asm.mov(:rcx, b_opnd)
- asm.cmp(:rax, :rcx)
- asm.mov(:rax, gen_eq ? Qfalse : Qtrue)
- asm.mov(:rcx, gen_eq ? Qtrue : Qfalse)
- asm.cmove(:rax, :rcx)
-
- # Push the output on the stack
- ctx.stack_pop(2)
- dst = ctx.stack_push(Type::UnknownImm)
- asm.mov(dst, :rax)
-
- true
- elsif C.rb_class_of(comptime_a) == String && C.rb_class_of(comptime_b) == String
- unless Invariants.assume_bop_not_redefined(jit, C::STRING_REDEFINED_OP_FLAG, C::BOP_EQ)
- # if overridden, emit the generic version
- return false
- end
-
- # Guard that a is a String
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_a), a_opnd, StackOpnd[1], comptime_a, side_exit)
-
- equal_label = asm.new_label(:equal)
- ret_label = asm.new_label(:ret)
-
- # If they are equal by identity, return true
- asm.mov(:rax, a_opnd)
- asm.mov(:rcx, b_opnd)
- asm.cmp(:rax, :rcx)
- asm.je(equal_label)
-
- # Otherwise guard that b is a T_STRING (from type info) or String (from runtime guard)
- btype = ctx.get_opnd_type(StackOpnd[0])
- unless btype.string?
- # Note: any T_STRING is valid here, but we check for a ::String for simplicity
- # To pass a mutable static variable (rb_cString) requires an unsafe block
- jit_guard_known_klass(jit, ctx, asm, C.rb_class_of(comptime_b), b_opnd, StackOpnd[0], comptime_b, side_exit)
- end
-
- asm.comment('call rb_str_eql_internal')
- asm.mov(C_ARGS[0], a_opnd)
- asm.mov(C_ARGS[1], b_opnd)
- asm.call(gen_eq ? C.rb_str_eql_internal : C.rjit_str_neq_internal)
-
- # Push the output on the stack
- ctx.stack_pop(2)
- dst = ctx.stack_push(Type::UnknownImm)
- asm.mov(dst, C_RET)
- asm.jmp(ret_label)
-
- asm.write_label(equal_label)
- asm.mov(dst, gen_eq ? Qtrue : Qfalse)
-
- asm.write_label(ret_label)
-
- true
- else
- false
- end
- end
-
- # NOTE: This clobbers :rax
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_prepare_routine_call(jit, ctx, asm)
- jit.record_boundary_patch_point = true
- jit_save_pc(jit, asm)
- jit_save_sp(ctx, asm)
-
- # In case the routine calls Ruby methods, it can set local variables
- # through Kernel#binding and other means.
- ctx.clear_local_types
- end
-
- # NOTE: This clobbers :rax
- # @param jit [RubyVM::RJIT::JITState]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_save_pc(jit, asm, comment: 'save PC to CFP')
- next_pc = jit.pc + jit.insn.len * C.VALUE.size # Use the next one for backtrace and side exits
- asm.comment(comment)
- asm.mov(:rax, next_pc)
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:pc)], :rax)
- end
-
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_save_sp(ctx, asm)
- if ctx.sp_offset != 0
- asm.comment('save SP to CFP')
- asm.lea(SP, ctx.sp_opnd)
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], SP)
- ctx.sp_offset = 0
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jump_to_next_insn(jit, ctx, asm)
- reset_depth = ctx.dup
- reset_depth.chain_depth = 0
-
- next_pc = jit.pc + jit.insn.len * C.VALUE.size
-
- # We are at the end of the current instruction. Record the boundary.
- if jit.record_boundary_patch_point
- exit_pos = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_side_exit(next_pc, ctx, ocb_asm)
- @ocb.write(ocb_asm)
- end
- Invariants.record_global_inval_patch(asm, exit_pos)
- jit.record_boundary_patch_point = false
- end
-
- jit_direct_jump(jit.iseq, next_pc, reset_depth, asm, comment: 'jump_to_next_insn')
- end
-
- # rb_vm_check_ints
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_check_ints(jit, ctx, asm)
- asm.comment('RUBY_VM_CHECK_INTS(ec)')
- asm.mov(:eax, DwordPtr[EC, C.rb_execution_context_t.offsetof(:interrupt_flag)])
- asm.test(:eax, :eax)
- asm.jnz(side_exit(jit, ctx))
- end
-
- # See get_lvar_level in compile.c
- def get_lvar_level(iseq)
- level = 0
- while iseq.to_i != iseq.body.local_iseq.to_i
- level += 1
- iseq = iseq.body.parent_iseq
- end
- return level
- end
-
- # GET_LEP
- # @param jit [RubyVM::RJIT::JITState]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_get_lep(jit, asm, reg:)
- level = get_lvar_level(jit.iseq)
- jit_get_ep(asm, level, reg:)
- end
-
- # vm_get_ep
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_get_ep(asm, level, reg:)
- asm.mov(reg, [CFP, C.rb_control_frame_t.offsetof(:ep)])
- level.times do
- # GET_PREV_EP: ep[VM_ENV_DATA_INDEX_SPECVAL] & ~0x03
- asm.mov(reg, [reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL])
- asm.and(reg, ~0x03)
- end
- end
-
- # vm_getivar
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_getivar(jit, ctx, asm, comptime_obj, ivar_id, obj_opnd, obj_yarv_opnd)
- side_exit = side_exit(jit, ctx)
- starting_ctx = ctx.dup # copy for jit_chain_guard
-
- # Guard not special const
- if C::SPECIAL_CONST_P(comptime_obj)
- asm.incr_counter(:getivar_special_const)
- return CantCompile
- end
-
- case C::BUILTIN_TYPE(comptime_obj)
- when C::T_OBJECT
- # This is the only supported case for now (ROBJECT_IVPTR)
- else
- # General case. Call rb_ivar_get().
- # VALUE rb_ivar_get(VALUE obj, ID id)
- asm.comment('call rb_ivar_get()')
- asm.mov(C_ARGS[0], obj_opnd ? obj_opnd : [CFP, C.rb_control_frame_t.offsetof(:self)])
- asm.mov(C_ARGS[1], ivar_id)
-
- # The function could raise exceptions.
- jit_prepare_routine_call(jit, ctx, asm) # clobbers obj_opnd and :rax
-
- asm.call(C.rb_ivar_get)
-
- if obj_opnd # attr_reader
- ctx.stack_pop
- end
-
- # Push the ivar on the stack
- out_opnd = ctx.stack_push(Type::Unknown)
- asm.mov(out_opnd, C_RET)
-
- # Jump to next instruction. This allows guard chains to share the same successor.
- jump_to_next_insn(jit, ctx, asm)
- return EndBlock
- end
-
- asm.mov(:rax, obj_opnd ? obj_opnd : [CFP, C.rb_control_frame_t.offsetof(:self)])
- guard_object_is_heap(jit, ctx, asm, :rax, obj_yarv_opnd, :getivar_not_heap)
-
- shape_id = C.rb_shape_get_shape_id(comptime_obj)
- if shape_id == C::OBJ_TOO_COMPLEX_SHAPE_ID
- asm.incr_counter(:getivar_too_complex)
- return CantCompile
- end
-
- asm.comment('guard shape')
- asm.cmp(DwordPtr[:rax, C.rb_shape_id_offset], shape_id)
- jit_chain_guard(:jne, jit, starting_ctx, asm, counted_exit(side_exit, :getivar_megamorphic))
-
- if obj_opnd
- ctx.stack_pop # pop receiver for attr_reader
- end
-
- index = C.rb_shape_get_iv_index(shape_id, ivar_id)
- # If there is no IVAR index, then the ivar was undefined
- # when we entered the compiler. That means we can just return
- # nil for this shape + iv name
- if index.nil?
- stack_opnd = ctx.stack_push(Type::Nil)
- val_opnd = Qnil
- else
- asm.comment('ROBJECT_IVPTR')
- if C::FL_TEST_RAW(comptime_obj, C::ROBJECT_EMBED)
- # Access embedded array
- asm.mov(:rax, [:rax, C.RObject.offsetof(:as, :ary) + (index * C.VALUE.size)])
- else
- # Pull out an ivar table on heap
- asm.mov(:rax, [:rax, C.RObject.offsetof(:as, :heap, :ivptr)])
- # Read the table
- asm.mov(:rax, [:rax, index * C.VALUE.size])
- end
- stack_opnd = ctx.stack_push(Type::Unknown)
- val_opnd = :rax
- end
- asm.mov(stack_opnd, val_opnd)
-
- # Let guard chains share the same successor
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- end
-
- def jit_write_iv(asm, comptime_receiver, recv_reg, temp_reg, ivar_index, set_value, needs_extension)
- # Compile time self is embedded and the ivar index lands within the object
- embed_test_result = C::FL_TEST_RAW(comptime_receiver, C::ROBJECT_EMBED) && !needs_extension
-
- if embed_test_result
- # Find the IV offset
- offs = C.RObject.offsetof(:as, :ary) + ivar_index * C.VALUE.size
-
- # Write the IV
- asm.comment('write IV')
- asm.mov(temp_reg, set_value)
- asm.mov([recv_reg, offs], temp_reg)
- else
- # Compile time value is *not* embedded.
-
- # Get a pointer to the extended table
- asm.mov(recv_reg, [recv_reg, C.RObject.offsetof(:as, :heap, :ivptr)])
-
- # Write the ivar in to the extended table
- asm.comment("write IV");
- asm.mov(temp_reg, set_value)
- asm.mov([recv_reg, C.VALUE.size * ivar_index], temp_reg)
- end
- end
-
- # vm_caller_setup_arg_block: Handle VM_CALL_ARGS_BLOCKARG cases.
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def guard_block_arg(jit, ctx, asm, calling)
- if calling.flags & C::VM_CALL_ARGS_BLOCKARG != 0
- block_arg_type = ctx.get_opnd_type(StackOpnd[0])
- case block_arg_type
- in Type::Nil
- calling.block_handler = C::VM_BLOCK_HANDLER_NONE
- in Type::BlockParamProxy
- calling.block_handler = C.rb_block_param_proxy
- else
- asm.incr_counter(:send_block_arg)
- return CantCompile
- end
- end
- end
-
- # vm_search_method
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_search_method(jit, ctx, asm, mid, calling)
- assert_equal(true, jit.at_current_insn?)
-
- # Generate a side exit
- side_exit = side_exit(jit, ctx)
-
- # kw_splat is not supported yet
- if calling.flags & C::VM_CALL_KW_SPLAT != 0
- asm.incr_counter(:send_kw_splat)
- return CantCompile
- end
-
- # Get a compile-time receiver and its class
- recv_idx = calling.argc + (calling.flags & C::VM_CALL_ARGS_BLOCKARG != 0 ? 1 : 0) # blockarg is not popped yet
- recv_idx += calling.send_shift
- comptime_recv = jit.peek_at_stack(recv_idx)
- comptime_recv_klass = C.rb_class_of(comptime_recv)
-
- # Guard the receiver class (part of vm_search_method_fastpath)
- recv_opnd = ctx.stack_opnd(recv_idx)
- megamorphic_exit = counted_exit(side_exit, :send_klass_megamorphic)
- jit_guard_known_klass(jit, ctx, asm, comptime_recv_klass, recv_opnd, StackOpnd[recv_idx], comptime_recv, megamorphic_exit)
-
- # Do method lookup (vm_cc_cme(cc) != NULL)
- cme = C.rb_callable_method_entry(comptime_recv_klass, mid)
- if cme.nil?
- asm.incr_counter(:send_missing_cme)
- return CantCompile # We don't support vm_call_method_name
- end
-
- # Invalidate on redefinition (part of vm_search_method_fastpath)
- Invariants.assume_method_lookup_stable(jit, cme)
-
- return cme, comptime_recv_klass
- end
-
- # vm_call_general
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_general(jit, ctx, asm, mid, calling, cme, known_recv_class)
- jit_call_method(jit, ctx, asm, mid, calling, cme, known_recv_class)
- end
-
- # vm_call_method
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- # @param send_shift [Integer] The number of shifts needed for VM_CALL_OPT_SEND
- def jit_call_method(jit, ctx, asm, mid, calling, cme, known_recv_class)
- # The main check of vm_call_method before vm_call_method_each_type
- case C::METHOD_ENTRY_VISI(cme)
- in C::METHOD_VISI_PUBLIC
- # You can always call public methods
- in C::METHOD_VISI_PRIVATE
- # Allow only callsites without a receiver
- if calling.flags & C::VM_CALL_FCALL == 0
- asm.incr_counter(:send_private)
- return CantCompile
- end
- in C::METHOD_VISI_PROTECTED
- # If the method call is an FCALL, it is always valid
- if calling.flags & C::VM_CALL_FCALL == 0
- # otherwise we need an ancestry check to ensure the receiver is valid to be called as protected
- jit_protected_callee_ancestry_guard(asm, cme, side_exit(jit, ctx))
- end
- end
-
- # Get a compile-time receiver
- recv_idx = calling.argc + (calling.flags & C::VM_CALL_ARGS_BLOCKARG != 0 ? 1 : 0) # blockarg is not popped yet
- recv_idx += calling.send_shift
- comptime_recv = jit.peek_at_stack(recv_idx)
- recv_opnd = ctx.stack_opnd(recv_idx)
-
- jit_call_method_each_type(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- end
-
- # Generate ancestry guard for protected callee.
- # Calls to protected callees only go through when self.is_a?(klass_that_defines_the_callee).
- def jit_protected_callee_ancestry_guard(asm, cme, side_exit)
- # See vm_call_method().
- def_class = cme.defined_class
- # Note: PC isn't written to current control frame as rb_is_kind_of() shouldn't raise.
- # VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass);
-
- asm.mov(C_ARGS[0], [CFP, C.rb_control_frame_t.offsetof(:self)])
- asm.mov(C_ARGS[1], to_value(def_class))
- asm.call(C.rb_obj_is_kind_of)
- asm.test(C_RET, C_RET)
- asm.jz(counted_exit(side_exit, :send_protected_check_failed))
- end
-
- # vm_call_method_each_type
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_method_each_type(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- case cme.def.type
- in C::VM_METHOD_TYPE_ISEQ
- iseq = def_iseq_ptr(cme.def)
- jit_call_iseq(jit, ctx, asm, cme, calling, iseq)
- in C::VM_METHOD_TYPE_NOTIMPLEMENTED
- asm.incr_counter(:send_notimplemented)
- return CantCompile
- in C::VM_METHOD_TYPE_CFUNC
- jit_call_cfunc(jit, ctx, asm, cme, calling, known_recv_class:)
- in C::VM_METHOD_TYPE_ATTRSET
- jit_call_attrset(jit, ctx, asm, cme, calling, comptime_recv, recv_opnd)
- in C::VM_METHOD_TYPE_IVAR
- jit_call_ivar(jit, ctx, asm, cme, calling, comptime_recv, recv_opnd)
- in C::VM_METHOD_TYPE_MISSING
- asm.incr_counter(:send_missing)
- return CantCompile
- in C::VM_METHOD_TYPE_BMETHOD
- jit_call_bmethod(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- in C::VM_METHOD_TYPE_ALIAS
- jit_call_alias(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- in C::VM_METHOD_TYPE_OPTIMIZED
- jit_call_optimized(jit, ctx, asm, cme, calling, known_recv_class)
- in C::VM_METHOD_TYPE_UNDEF
- asm.incr_counter(:send_undef)
- return CantCompile
- in C::VM_METHOD_TYPE_ZSUPER
- asm.incr_counter(:send_zsuper)
- return CantCompile
- in C::VM_METHOD_TYPE_REFINED
- asm.incr_counter(:send_refined)
- return CantCompile
- end
- end
-
- # vm_call_iseq_setup
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_iseq(jit, ctx, asm, cme, calling, iseq, frame_type: nil, prev_ep: nil)
- argc = calling.argc
- flags = calling.flags
- send_shift = calling.send_shift
-
- # When you have keyword arguments, there is an extra object that gets
- # placed on the stack the represents a bitmap of the keywords that were not
- # specified at the call site. We need to keep track of the fact that this
- # value is present on the stack in order to properly set up the callee's
- # stack pointer.
- doing_kw_call = iseq.body.param.flags.has_kw
- supplying_kws = flags & C::VM_CALL_KWARG != 0
-
- if flags & C::VM_CALL_TAILCALL != 0
- # We can't handle tailcalls
- asm.incr_counter(:send_tailcall)
- return CantCompile
- end
-
- # No support for callees with these parameters yet as they require allocation
- # or complex handling.
- if iseq.body.param.flags.has_post
- asm.incr_counter(:send_iseq_has_opt)
- return CantCompile
- end
- if iseq.body.param.flags.has_kwrest
- asm.incr_counter(:send_iseq_has_kwrest)
- return CantCompile
- end
-
- # In order to handle backwards compatibility between ruby 3 and 2
- # ruby2_keywords was introduced. It is called only on methods
- # with splat and changes they way they handle them.
- # We are just going to not compile these.
- # https://www.rubydoc.info/stdlib/core/Proc:ruby2_keywords
- if iseq.body.param.flags.ruby2_keywords && flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_iseq_ruby2_keywords)
- return CantCompile
- end
-
- iseq_has_rest = iseq.body.param.flags.has_rest
- if iseq_has_rest && calling.block_handler == :captured
- asm.incr_counter(:send_iseq_has_rest_and_captured)
- return CantCompile
- end
-
- if iseq_has_rest && iseq.body.param.flags.has_kw && supplying_kws
- asm.incr_counter(:send_iseq_has_rest_and_kw_supplied)
- return CantCompile
- end
-
- # If we have keyword arguments being passed to a callee that only takes
- # positionals, then we need to allocate a hash. For now we're going to
- # call that too complex and bail.
- if supplying_kws && !iseq.body.param.flags.has_kw
- asm.incr_counter(:send_iseq_has_no_kw)
- return CantCompile
- end
-
- # If we have a method accepting no kwargs (**nil), exit if we have passed
- # it any kwargs.
- if supplying_kws && iseq.body.param.flags.accepts_no_kwarg
- asm.incr_counter(:send_iseq_accepts_no_kwarg)
- return CantCompile
- end
-
- # For computing number of locals to set up for the callee
- num_params = iseq.body.param.size
-
- # Block parameter handling. This mirrors setup_parameters_complex().
- if iseq.body.param.flags.has_block
- if iseq.body.local_iseq.to_i == iseq.to_i
- num_params -= 1
- else
- # In this case (param.flags.has_block && local_iseq != iseq),
- # the block argument is setup as a local variable and requires
- # materialization (allocation). Bail.
- asm.incr_counter(:send_iseq_materialized_block)
- return CantCompile
- end
- end
-
- if flags & C::VM_CALL_ARGS_SPLAT != 0 && flags & C::VM_CALL_ZSUPER != 0
- # zsuper methods are super calls without any arguments.
- # They are also marked as splat, but don't actually have an array
- # they pull arguments from, instead we need to change to call
- # a different method with the current stack.
- asm.incr_counter(:send_iseq_zsuper)
- return CantCompile
- end
-
- start_pc_offset = 0
- required_num = iseq.body.param.lead_num
-
- # This struct represents the metadata about the caller-specified
- # keyword arguments.
- kw_arg = calling.kwarg
- kw_arg_num = if kw_arg.nil?
- 0
- else
- kw_arg.keyword_len
- end
-
- # Arity handling and optional parameter setup
- opts_filled = argc - required_num - kw_arg_num
- opt_num = iseq.body.param.opt_num
- opts_missing = opt_num - opts_filled
-
- if doing_kw_call && flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_iseq_splat_with_kw)
- return CantCompile
- end
-
- if flags & C::VM_CALL_KW_SPLAT != 0
- asm.incr_counter(:send_iseq_kw_splat)
- return CantCompile
- end
-
- if iseq_has_rest && opt_num != 0
- asm.incr_counter(:send_iseq_has_rest_and_optional)
- return CantCompile
- end
-
- if opts_filled < 0 && flags & C::VM_CALL_ARGS_SPLAT == 0
- # Too few arguments and no splat to make up for it
- asm.incr_counter(:send_iseq_arity_error)
- return CantCompile
- end
-
- if opts_filled > opt_num && !iseq_has_rest
- # Too many arguments and no place to put them (i.e. rest arg)
- asm.incr_counter(:send_iseq_arity_error)
- return CantCompile
- end
-
- block_arg = flags & C::VM_CALL_ARGS_BLOCKARG != 0
-
- # Guard block_arg_type
- if guard_block_arg(jit, ctx, asm, calling) == CantCompile
- return CantCompile
- end
-
- # If we have unfilled optional arguments and keyword arguments then we
- # would need to adjust the arguments location to account for that.
- # For now we aren't handling this case.
- if doing_kw_call && opts_missing > 0
- asm.incr_counter(:send_iseq_missing_optional_kw)
- return CantCompile
- end
-
- # We will handle splat case later
- if opt_num > 0 && flags & C::VM_CALL_ARGS_SPLAT == 0
- num_params -= opts_missing
- start_pc_offset = iseq.body.param.opt_table[opts_filled]
- end
-
- if doing_kw_call
- # Here we're calling a method with keyword arguments and specifying
- # keyword arguments at this call site.
-
- # This struct represents the metadata about the callee-specified
- # keyword parameters.
- keyword = iseq.body.param.keyword
- keyword_num = keyword.num
- keyword_required_num = keyword.required_num
-
- required_kwargs_filled = 0
-
- if keyword_num > 30
- # We have so many keywords that (1 << num) encoded as a FIXNUM
- # (which shifts it left one more) no longer fits inside a 32-bit
- # immediate.
- asm.incr_counter(:send_iseq_too_many_kwargs)
- return CantCompile
- end
-
- # Check that the kwargs being passed are valid
- if supplying_kws
- # This is the list of keyword arguments that the callee specified
- # in its initial declaration.
- # SAFETY: see compile.c for sizing of this slice.
- callee_kwargs = keyword_num.times.map { |i| keyword.table[i] }
-
- # Here we're going to build up a list of the IDs that correspond to
- # the caller-specified keyword arguments. If they're not in the
- # same order as the order specified in the callee declaration, then
- # we're going to need to generate some code to swap values around
- # on the stack.
- caller_kwargs = []
- kw_arg.keyword_len.times do |kwarg_idx|
- sym = C.to_ruby(kw_arg[:keywords][kwarg_idx])
- caller_kwargs << C.rb_sym2id(sym)
- end
-
- # First, we're going to be sure that the names of every
- # caller-specified keyword argument correspond to a name in the
- # list of callee-specified keyword parameters.
- caller_kwargs.each do |caller_kwarg|
- search_result = callee_kwargs.map.with_index.find { |kwarg, _| kwarg == caller_kwarg }
-
- case search_result
- in nil
- # If the keyword was never found, then we know we have a
- # mismatch in the names of the keyword arguments, so we need to
- # bail.
- asm.incr_counter(:send_iseq_kwargs_mismatch)
- return CantCompile
- in _, callee_idx if callee_idx < keyword_required_num
- # Keep a count to ensure all required kwargs are specified
- required_kwargs_filled += 1
- else
- end
- end
- end
- assert_equal(true, required_kwargs_filled <= keyword_required_num)
- if required_kwargs_filled != keyword_required_num
- asm.incr_counter(:send_iseq_kwargs_mismatch)
- return CantCompile
- end
- end
-
- # Check if we need the arg0 splat handling of vm_callee_setup_block_arg
- arg_setup_block = (calling.block_handler == :captured) # arg_setup_type: arg_setup_block (invokeblock)
- block_arg0_splat = arg_setup_block && argc == 1 &&
- (iseq.body.param.flags.has_lead || opt_num > 1) &&
- !iseq.body.param.flags.ambiguous_param0
- if block_arg0_splat
- # If block_arg0_splat, we still need side exits after splat, but
- # doing push_splat_args here disallows it. So bail out.
- if flags & C::VM_CALL_ARGS_SPLAT != 0 && !iseq_has_rest
- asm.incr_counter(:invokeblock_iseq_arg0_args_splat)
- return CantCompile
- end
- # The block_arg0_splat implementation is for the rb_simple_iseq_p case,
- # but doing_kw_call means it's not a simple ISEQ.
- if doing_kw_call
- asm.incr_counter(:invokeblock_iseq_arg0_has_kw)
- return CantCompile
- end
- # The block_arg0_splat implementation cannot deal with optional parameters.
- # This is a setup_parameters_complex() situation and interacts with the
- # starting position of the callee.
- if opt_num > 1
- asm.incr_counter(:invokeblock_iseq_arg0_optional)
- return CantCompile
- end
- end
- if flags & C::VM_CALL_ARGS_SPLAT != 0 && !iseq_has_rest
- array = jit.peek_at_stack(block_arg ? 1 : 0)
- splat_array_length = if array.nil?
- 0
- else
- array.length
- end
-
- if opt_num == 0 && required_num != splat_array_length + argc - 1
- asm.incr_counter(:send_iseq_splat_arity_error)
- return CantCompile
- end
- end
-
- # Don't compile forwardable iseqs
- if iseq.body.param.flags.forwardable
- return CantCompile
- end
-
- # We will not have CantCompile from here.
-
- if block_arg
- ctx.stack_pop(1)
- end
-
- if calling.block_handler == C::VM_BLOCK_HANDLER_NONE && iseq.body.builtin_attrs & C::BUILTIN_ATTR_LEAF != 0
- if jit_leaf_builtin_func(jit, ctx, asm, flags, iseq)
- return KeepCompiling
- end
- end
-
- # Number of locals that are not parameters
- num_locals = iseq.body.local_table_size - num_params
-
- # Stack overflow check
- # Note that vm_push_frame checks it against a decremented cfp, hence the multiply by 2.
- # #define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin)
- asm.comment('stack overflow check')
- locals_offs = C.VALUE.size * (num_locals + iseq.body.stack_max) + 2 * C.rb_control_frame_t.size
- asm.lea(:rax, ctx.sp_opnd(locals_offs))
- asm.cmp(CFP, :rax)
- asm.jbe(counted_exit(side_exit(jit, ctx), :send_stackoverflow))
-
- # push_splat_args does stack manipulation so we can no longer side exit
- if splat_array_length
- remaining_opt = (opt_num + required_num) - (splat_array_length + (argc - 1))
-
- if opt_num > 0
- # We are going to jump to the correct offset based on how many optional
- # params are remaining.
- offset = opt_num - remaining_opt
- start_pc_offset = iseq.body.param.opt_table[offset]
- end
- # We are going to assume that the splat fills
- # all the remaining arguments. In the generated code
- # we test if this is true and if not side exit.
- argc = argc - 1 + splat_array_length + remaining_opt
- push_splat_args(splat_array_length, jit, ctx, asm)
-
- remaining_opt.times do
- # We need to push nil for the optional arguments
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, Qnil)
- end
- end
-
- # This is a .send call and we need to adjust the stack
- if flags & C::VM_CALL_OPT_SEND != 0
- handle_opt_send_shift_stack(asm, argc, ctx, send_shift:)
- end
-
- if iseq_has_rest
- # We are going to allocate so setting pc and sp.
- jit_save_pc(jit, asm) # clobbers rax
- jit_save_sp(ctx, asm)
-
- if flags & C::VM_CALL_ARGS_SPLAT != 0
- non_rest_arg_count = argc - 1
- # We start by dupping the array because someone else might have
- # a reference to it.
- array = ctx.stack_pop(1)
- asm.mov(C_ARGS[0], array)
- asm.call(C.rb_ary_dup)
- array = C_RET
- if non_rest_arg_count > required_num
- # If we have more arguments than required, we need to prepend
- # the items from the stack onto the array.
- diff = (non_rest_arg_count - required_num)
-
- # diff is >0 so no need to worry about null pointer
- asm.comment('load pointer to array elements')
- offset_magnitude = C.VALUE.size * diff
- values_opnd = ctx.sp_opnd(-offset_magnitude)
- values_ptr = :rcx
- asm.lea(values_ptr, values_opnd)
-
- asm.comment('prepend stack values to rest array')
- asm.mov(C_ARGS[0], diff)
- asm.mov(C_ARGS[1], values_ptr)
- asm.mov(C_ARGS[2], array)
- asm.call(C.rb_ary_unshift_m)
- ctx.stack_pop(diff)
-
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
- # We now should have the required arguments
- # and an array of all the rest arguments
- argc = required_num + 1
- elsif non_rest_arg_count < required_num
- # If we have fewer arguments than required, we need to take some
- # from the array and move them to the stack.
- diff = (required_num - non_rest_arg_count)
- # This moves the arguments onto the stack. But it doesn't modify the array.
- move_rest_args_to_stack(array, diff, jit, ctx, asm)
-
- # We will now slice the array to give us a new array of the correct size
- asm.mov(C_ARGS[0], array)
- asm.mov(C_ARGS[1], diff)
- asm.call(C.rjit_rb_ary_subseq_length)
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
-
- # We now should have the required arguments
- # and an array of all the rest arguments
- argc = required_num + 1
- else
- # The arguments are equal so we can just push to the stack
- assert_equal(non_rest_arg_count, required_num)
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, array)
- end
- else
- assert_equal(true, argc >= required_num)
- n = (argc - required_num)
- argc = required_num + 1
- # If n is 0, then elts is never going to be read, so we can just pass null
- if n == 0
- values_ptr = 0
- else
- asm.comment('load pointer to array elements')
- offset_magnitude = C.VALUE.size * n
- values_opnd = ctx.sp_opnd(-offset_magnitude)
- values_ptr = :rcx
- asm.lea(values_ptr, values_opnd)
- end
-
- asm.mov(C_ARGS[0], EC)
- asm.mov(C_ARGS[1], n)
- asm.mov(C_ARGS[2], values_ptr)
- asm.call(C.rb_ec_ary_new_from_values)
-
- ctx.stack_pop(n)
- stack_ret = ctx.stack_push(Type::TArray)
- asm.mov(stack_ret, C_RET)
- end
- end
-
- if doing_kw_call
- # Here we're calling a method with keyword arguments and specifying
- # keyword arguments at this call site.
-
- # Number of positional arguments the callee expects before the first
- # keyword argument
- args_before_kw = required_num + opt_num
-
- # This struct represents the metadata about the caller-specified
- # keyword arguments.
- ci_kwarg = calling.kwarg
- caller_keyword_len = if ci_kwarg.nil?
- 0
- else
- ci_kwarg.keyword_len
- end
-
- # This struct represents the metadata about the callee-specified
- # keyword parameters.
- keyword = iseq.body.param.keyword
-
- asm.comment('keyword args')
-
- # This is the list of keyword arguments that the callee specified
- # in its initial declaration.
- callee_kwargs = keyword.table
- total_kwargs = keyword.num
-
- # Here we're going to build up a list of the IDs that correspond to
- # the caller-specified keyword arguments. If they're not in the
- # same order as the order specified in the callee declaration, then
- # we're going to need to generate some code to swap values around
- # on the stack.
- caller_kwargs = []
-
- caller_keyword_len.times do |kwarg_idx|
- sym = C.to_ruby(ci_kwarg[:keywords][kwarg_idx])
- caller_kwargs << C.rb_sym2id(sym)
- end
- kwarg_idx = caller_keyword_len
-
- unspecified_bits = 0
-
- keyword_required_num = keyword.required_num
- (keyword_required_num...total_kwargs).each do |callee_idx|
- already_passed = false
- callee_kwarg = callee_kwargs[callee_idx]
-
- caller_keyword_len.times do |caller_idx|
- if caller_kwargs[caller_idx] == callee_kwarg
- already_passed = true
- break
- end
- end
-
- unless already_passed
- # Reserve space on the stack for each default value we'll be
- # filling in (which is done in the next loop). Also increments
- # argc so that the callee's SP is recorded correctly.
- argc += 1
- default_arg = ctx.stack_push(Type::Unknown)
-
- # callee_idx - keyword->required_num is used in a couple of places below.
- req_num = keyword.required_num
- extra_args = callee_idx - req_num
-
- # VALUE default_value = keyword->default_values[callee_idx - keyword->required_num];
- default_value = keyword.default_values[extra_args]
-
- if default_value == Qundef
- # Qundef means that this value is not constant and must be
- # recalculated at runtime, so we record it in unspecified_bits
- # (Qnil is then used as a placeholder instead of Qundef).
- unspecified_bits |= 0x01 << extra_args
- default_value = Qnil
- end
-
- asm.mov(:rax, default_value)
- asm.mov(default_arg, :rax)
-
- caller_kwargs[kwarg_idx] = callee_kwarg
- kwarg_idx += 1
- end
- end
-
- assert_equal(kwarg_idx, total_kwargs)
-
- # Next, we're going to loop through every keyword that was
- # specified by the caller and make sure that it's in the correct
- # place. If it's not we're going to swap it around with another one.
- total_kwargs.times do |kwarg_idx|
- callee_kwarg = callee_kwargs[kwarg_idx]
-
- # If the argument is already in the right order, then we don't
- # need to generate any code since the expected value is already
- # in the right place on the stack.
- if callee_kwarg == caller_kwargs[kwarg_idx]
- next
- end
-
- # In this case the argument is not in the right place, so we
- # need to find its position where it _should_ be and swap with
- # that location.
- ((kwarg_idx + 1)...total_kwargs).each do |swap_idx|
- if callee_kwarg == caller_kwargs[swap_idx]
- # First we're going to generate the code that is going
- # to perform the actual swapping at runtime.
- offset0 = argc - 1 - swap_idx - args_before_kw
- offset1 = argc - 1 - kwarg_idx - args_before_kw
- stack_swap(jit, ctx, asm, offset0, offset1)
-
- # Next we're going to do some bookkeeping on our end so
- # that we know the order that the arguments are
- # actually in now.
- caller_kwargs[kwarg_idx], caller_kwargs[swap_idx] =
- caller_kwargs[swap_idx], caller_kwargs[kwarg_idx]
-
- break
- end
- end
- end
-
- # Keyword arguments cause a special extra local variable to be
- # pushed onto the stack that represents the parameters that weren't
- # explicitly given a value and have a non-constant default.
- asm.mov(ctx.stack_opnd(-1), C.to_value(unspecified_bits))
- end
-
- # Same as vm_callee_setup_block_arg_arg0_check and vm_callee_setup_block_arg_arg0_splat
- # on vm_callee_setup_block_arg for arg_setup_block. This is done after CALLER_SETUP_ARG
- # and CALLER_REMOVE_EMPTY_KW_SPLAT, so this implementation is put here. This may need
- # side exits, so you still need to allow side exits here if block_arg0_splat is true.
- # Note that you can't have side exits after this arg0 splat.
- if block_arg0_splat
- asm.incr_counter(:send_iseq_block_arg0_splat)
- return CantCompile
- end
-
- # Create a context for the callee
- callee_ctx = Context.new
-
- # Set the argument types in the callee's context
- argc.times do |arg_idx|
- stack_offs = argc - arg_idx - 1
- arg_type = ctx.get_opnd_type(StackOpnd[stack_offs])
- callee_ctx.set_local_type(arg_idx, arg_type)
- end
-
- recv_type = if calling.block_handler == :captured
- Type::Unknown # we don't track the type information of captured->self for now
- else
- ctx.get_opnd_type(StackOpnd[argc])
- end
- callee_ctx.upgrade_opnd_type(SelfOpnd, recv_type)
-
- # Setup the new frame
- frame_type ||= C::VM_FRAME_MAGIC_METHOD | C::VM_ENV_FLAG_LOCAL
- jit_push_frame(
- jit, ctx, asm, cme, flags, argc, frame_type, calling.block_handler,
- iseq: iseq,
- local_size: num_locals,
- stack_max: iseq.body.stack_max,
- prev_ep:,
- doing_kw_call:,
- )
-
- # Directly jump to the entry point of the callee
- pc = (iseq.body.iseq_encoded + start_pc_offset).to_i
- jit_direct_jump(iseq, pc, callee_ctx, asm)
-
- EndBlock
- end
-
- def jit_leaf_builtin_func(jit, ctx, asm, flags, iseq)
- builtin_func = builtin_function(iseq)
- if builtin_func.nil?
- return false
- end
-
- # this is a .send call not currently supported for builtins
- if flags & C::VM_CALL_OPT_SEND != 0
- return false
- end
-
- builtin_argc = builtin_func.argc
- if builtin_argc + 1 >= C_ARGS.size
- return false
- end
-
- asm.comment('inlined leaf builtin')
-
- # The callee may allocate, e.g. Integer#abs on a Bignum.
- # Save SP for GC, save PC for allocation tracing, and prepare
- # for global invalidation after GC's VM lock contention.
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Call the builtin func (ec, recv, arg1, arg2, ...)
- asm.mov(C_ARGS[0], EC)
-
- # Copy self and arguments
- (0..builtin_argc).each do |i|
- stack_opnd = ctx.stack_opnd(builtin_argc - i)
- asm.mov(C_ARGS[i + 1], stack_opnd)
- end
- ctx.stack_pop(builtin_argc + 1)
- asm.call(builtin_func.func_ptr)
-
- # Push the return value
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
- return true
- end
-
- # vm_call_cfunc
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_cfunc(jit, ctx, asm, cme, calling, known_recv_class: nil)
- argc = calling.argc
- flags = calling.flags
-
- cfunc = cme.def.body.cfunc
- cfunc_argc = cfunc.argc
-
- # If the function expects a Ruby array of arguments
- if cfunc_argc < 0 && cfunc_argc != -1
- asm.incr_counter(:send_cfunc_ruby_array_varg)
- return CantCompile
- end
-
- # We aren't handling a vararg cfuncs with splat currently.
- if flags & C::VM_CALL_ARGS_SPLAT != 0 && cfunc_argc == -1
- asm.incr_counter(:send_args_splat_cfunc_var_args)
- return CantCompile
- end
-
- if flags & C::VM_CALL_ARGS_SPLAT != 0 && flags & C::VM_CALL_ZSUPER != 0
- # zsuper methods are super calls without any arguments.
- # They are also marked as splat, but don't actually have an array
- # they pull arguments from, instead we need to change to call
- # a different method with the current stack.
- asm.incr_counter(:send_args_splat_cfunc_zuper)
- return CantCompile;
- end
-
- # In order to handle backwards compatibility between ruby 3 and 2
- # ruby2_keywords was introduced. It is called only on methods
- # with splat and changes they way they handle them.
- # We are just going to not compile these.
- # https://docs.ruby-lang.org/en/3.2/Module.html#method-i-ruby2_keywords
- if jit.iseq.body.param.flags.ruby2_keywords && flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_args_splat_cfunc_ruby2_keywords)
- return CantCompile;
- end
-
- kw_arg = calling.kwarg
- kw_arg_num = if kw_arg.nil?
- 0
- else
- kw_arg.keyword_len
- end
-
- if kw_arg_num != 0 && flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_cfunc_splat_with_kw)
- return CantCompile
- end
-
- if c_method_tracing_currently_enabled?
- # Don't JIT if tracing c_call or c_return
- asm.incr_counter(:send_cfunc_tracing)
- return CantCompile
- end
-
- # Delegate to codegen for C methods if we have it.
- if kw_arg.nil? && flags & C::VM_CALL_OPT_SEND == 0 && flags & C::VM_CALL_ARGS_SPLAT == 0 && (cfunc_argc == -1 || argc == cfunc_argc)
- known_cfunc_codegen = lookup_cfunc_codegen(cme.def)
- if known_cfunc_codegen&.call(jit, ctx, asm, argc, known_recv_class)
- # cfunc codegen generated code. Terminate the block so
- # there isn't multiple calls in the same block.
- jump_to_next_insn(jit, ctx, asm)
- return EndBlock
- end
- end
-
- # Check for interrupts
- jit_check_ints(jit, ctx, asm)
-
- # Stack overflow check
- # #define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin)
- # REG_CFP <= REG_SP + 4 * SIZEOF_VALUE + sizeof(rb_control_frame_t)
- asm.comment('stack overflow check')
- asm.lea(:rax, ctx.sp_opnd(C.VALUE.size * 4 + 2 * C.rb_control_frame_t.size))
- asm.cmp(CFP, :rax)
- asm.jbe(counted_exit(side_exit(jit, ctx), :send_stackoverflow))
-
- # Number of args which will be passed through to the callee
- # This is adjusted by the kwargs being combined into a hash.
- passed_argc = if kw_arg.nil?
- argc
- else
- argc - kw_arg_num + 1
- end
-
- # If the argument count doesn't match
- if cfunc_argc >= 0 && cfunc_argc != passed_argc && flags & C::VM_CALL_ARGS_SPLAT == 0
- asm.incr_counter(:send_cfunc_argc_mismatch)
- return CantCompile
- end
-
- # Don't JIT functions that need C stack arguments for now
- if cfunc_argc >= 0 && passed_argc + 1 > C_ARGS.size
- asm.incr_counter(:send_cfunc_toomany_args)
- return CantCompile
- end
-
- block_arg = flags & C::VM_CALL_ARGS_BLOCKARG != 0
-
- # Guard block_arg_type
- if guard_block_arg(jit, ctx, asm, calling) == CantCompile
- return CantCompile
- end
-
- if block_arg
- ctx.stack_pop(1)
- end
-
- # push_splat_args does stack manipulation so we can no longer side exit
- if flags & C::VM_CALL_ARGS_SPLAT != 0
- assert_equal(true, cfunc_argc >= 0)
- required_args = cfunc_argc - (argc - 1)
- # + 1 because we pass self
- if required_args + 1 >= C_ARGS.size
- asm.incr_counter(:send_cfunc_toomany_args)
- return CantCompile
- end
-
- # We are going to assume that the splat fills
- # all the remaining arguments. So the number of args
- # should just equal the number of args the cfunc takes.
- # In the generated code we test if this is true
- # and if not side exit.
- argc = cfunc_argc
- passed_argc = argc
- push_splat_args(required_args, jit, ctx, asm)
- end
-
- # This is a .send call and we need to adjust the stack
- if flags & C::VM_CALL_OPT_SEND != 0
- handle_opt_send_shift_stack(asm, argc, ctx, send_shift: calling.send_shift)
- end
-
- # Points to the receiver operand on the stack
-
- # Store incremented PC into current control frame in case callee raises.
- jit_save_pc(jit, asm)
-
- # Increment the stack pointer by 3 (in the callee)
- # sp += 3
-
- frame_type = C::VM_FRAME_MAGIC_CFUNC | C::VM_FRAME_FLAG_CFRAME | C::VM_ENV_FLAG_LOCAL
- if kw_arg
- frame_type |= C::VM_FRAME_FLAG_CFRAME_KW
- end
-
- jit_push_frame(jit, ctx, asm, cme, flags, argc, frame_type, calling.block_handler)
-
- if kw_arg
- # Build a hash from all kwargs passed
- asm.comment('build_kwhash')
- imemo_ci = calling.ci_addr
- # we assume all callinfos with kwargs are on the GC heap
- assert_equal(true, C.imemo_type_p(imemo_ci, C.imemo_callinfo))
- asm.mov(C_ARGS[0], imemo_ci)
- asm.lea(C_ARGS[1], ctx.sp_opnd(0))
- asm.call(C.rjit_build_kwhash)
-
- # Replace the stack location at the start of kwargs with the new hash
- stack_opnd = ctx.stack_opnd(argc - passed_argc)
- asm.mov(stack_opnd, C_RET)
- end
-
- # Copy SP because REG_SP will get overwritten
- sp = :rax
- asm.lea(sp, ctx.sp_opnd(0))
-
- # Pop the C function arguments from the stack (in the caller)
- ctx.stack_pop(argc + 1)
-
- # Write interpreter SP into CFP.
- # Needed in case the callee yields to the block.
- jit_save_sp(ctx, asm)
-
- # Non-variadic method
- case cfunc_argc
- in (0..) # Non-variadic method
- # Copy the arguments from the stack to the C argument registers
- # self is the 0th argument and is at index argc from the stack top
- (0..passed_argc).each do |i|
- asm.mov(C_ARGS[i], [sp, -(argc + 1 - i) * C.VALUE.size])
- end
- in -1 # Variadic method: rb_f_puts(int argc, VALUE *argv, VALUE recv)
- # The method gets a pointer to the first argument
- # rb_f_puts(int argc, VALUE *argv, VALUE recv)
- asm.mov(C_ARGS[0], passed_argc)
- asm.lea(C_ARGS[1], [sp, -argc * C.VALUE.size]) # argv
- asm.mov(C_ARGS[2], [sp, -(argc + 1) * C.VALUE.size]) # recv
- end
-
- # Call the C function
- # VALUE ret = (cfunc->func)(recv, argv[0], argv[1]);
- # cfunc comes from compile-time cme->def, which we assume to be stable.
- # Invalidation logic is in yjit_method_lookup_change()
- asm.comment('call C function')
- asm.mov(:rax, cfunc.func)
- asm.call(:rax) # TODO: use rel32 if close enough
-
- # Record code position for TracePoint patching. See full_cfunc_return().
- Invariants.record_global_inval_patch(asm, full_cfunc_return)
-
- # Push the return value on the Ruby stack
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
-
- # Pop the stack frame (ec->cfp++)
- # Instead of recalculating, we can reuse the previous CFP, which is stored in a callee-saved
- # register
- asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], CFP)
-
- # cfunc calls may corrupt types
- ctx.clear_local_types
-
- # Note: the return block of jit_call_iseq has ctx->sp_offset == 1
- # which allows for sharing the same successor.
-
- # Jump (fall through) to the call continuation block
- # We do this to end the current block after the call
- assert_equal(1, ctx.sp_offset)
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- end
-
- # vm_call_attrset
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_attrset(jit, ctx, asm, cme, calling, comptime_recv, recv_opnd)
- argc = calling.argc
- flags = calling.flags
- send_shift = calling.send_shift
-
- if flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_attrset_splat)
- return CantCompile
- end
- if flags & C::VM_CALL_KWARG != 0
- asm.incr_counter(:send_attrset_kwarg)
- return CantCompile
- elsif argc != 1 || !C.RB_TYPE_P(comptime_recv, C::RUBY_T_OBJECT)
- asm.incr_counter(:send_attrset_method)
- return CantCompile
- elsif c_method_tracing_currently_enabled?
- # Can't generate code for firing c_call and c_return events
- # See :attr-tracing:
- asm.incr_counter(:send_c_tracingg)
- return CantCompile
- elsif flags & C::VM_CALL_ARGS_BLOCKARG != 0
- asm.incr_counter(:send_block_arg)
- return CantCompile
- end
-
- ivar_name = cme.def.body.attr.id
-
- # This is a .send call and we need to adjust the stack
- if flags & C::VM_CALL_OPT_SEND != 0
- handle_opt_send_shift_stack(asm, argc, ctx, send_shift:)
- end
-
- # Save the PC and SP because the callee may allocate
- # Note that this modifies REG_SP, which is why we do it first
- jit_prepare_routine_call(jit, ctx, asm)
-
- # Get the operands from the stack
- val_opnd = ctx.stack_pop(1)
- recv_opnd = ctx.stack_pop(1)
-
- # Call rb_vm_set_ivar_id with the receiver, the ivar name, and the value
- asm.mov(C_ARGS[0], recv_opnd)
- asm.mov(C_ARGS[1], ivar_name)
- asm.mov(C_ARGS[2], val_opnd)
- asm.call(C.rb_vm_set_ivar_id)
-
- out_opnd = ctx.stack_push(Type::Unknown)
- asm.mov(out_opnd, C_RET)
-
- KeepCompiling
- end
-
- # vm_call_ivar (+ part of vm_call_method_each_type)
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_ivar(jit, ctx, asm, cme, calling, comptime_recv, recv_opnd)
- argc = calling.argc
- flags = calling.flags
-
- if flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_ivar_splat)
- return CantCompile
- end
-
- if argc != 0
- asm.incr_counter(:send_arity)
- return CantCompile
- end
-
- # We don't support handle_opt_send_shift_stack for this yet.
- if flags & C::VM_CALL_OPT_SEND != 0
- asm.incr_counter(:send_ivar_opt_send)
- return CantCompile
- end
-
- ivar_id = cme.def.body.attr.id
-
- # Not handling block_handler
- if flags & C::VM_CALL_ARGS_BLOCKARG != 0
- asm.incr_counter(:send_block_arg)
- return CantCompile
- end
-
- jit_getivar(jit, ctx, asm, comptime_recv, ivar_id, recv_opnd, StackOpnd[0])
- end
-
- # vm_call_bmethod
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_bmethod(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- proc_addr = cme.def.body.bmethod.proc
-
- proc_t = C.rb_yjit_get_proc_ptr(proc_addr)
- proc_block = proc_t.block
-
- if proc_block.type != C.block_type_iseq
- asm.incr_counter(:send_bmethod_not_iseq)
- return CantCompile
- end
-
- capture = proc_block.as.captured
- iseq = capture.code.iseq
-
- # TODO: implement this
- # Optimize for single ractor mode and avoid runtime check for
- # "defined with an un-shareable Proc in a different Ractor"
- # if !assume_single_ractor_mode(jit, ocb)
- # return CantCompile;
- # end
-
- # Passing a block to a block needs logic different from passing
- # a block to a method and sometimes requires allocation. Bail for now.
- if calling.block_handler != C::VM_BLOCK_HANDLER_NONE
- asm.incr_counter(:send_bmethod_blockarg)
- return CantCompile
- end
-
- jit_call_iseq(
- jit, ctx, asm, cme, calling, iseq,
- frame_type: C::VM_FRAME_MAGIC_BLOCK | C::VM_FRAME_FLAG_BMETHOD | C::VM_FRAME_FLAG_LAMBDA,
- prev_ep: capture.ep,
- )
- end
-
- # vm_call_alias
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_alias(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- cme = C.rb_aliased_callable_method_entry(cme)
- jit_call_method_each_type(jit, ctx, asm, calling, cme, comptime_recv, recv_opnd, known_recv_class)
- end
-
- # vm_call_optimized
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_optimized(jit, ctx, asm, cme, calling, known_recv_class)
- if calling.flags & C::VM_CALL_ARGS_BLOCKARG != 0
- # Not working yet
- asm.incr_counter(:send_block_arg)
- return CantCompile
- end
-
- case cme.def.body.optimized.type
- in C::OPTIMIZED_METHOD_TYPE_SEND
- jit_call_opt_send(jit, ctx, asm, cme, calling, known_recv_class)
- in C::OPTIMIZED_METHOD_TYPE_CALL
- jit_call_opt_call(jit, ctx, asm, cme, calling.flags, calling.argc, calling.block_handler, known_recv_class, send_shift: calling.send_shift)
- in C::OPTIMIZED_METHOD_TYPE_BLOCK_CALL
- asm.incr_counter(:send_optimized_block_call)
- return CantCompile
- in C::OPTIMIZED_METHOD_TYPE_STRUCT_AREF
- jit_call_opt_struct_aref(jit, ctx, asm, cme, calling.flags, calling.argc, calling.block_handler, known_recv_class, send_shift: calling.send_shift)
- in C::OPTIMIZED_METHOD_TYPE_STRUCT_ASET
- asm.incr_counter(:send_optimized_struct_aset)
- return CantCompile
- end
- end
-
- # vm_call_opt_send
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_opt_send(jit, ctx, asm, cme, calling, known_recv_class)
- if jit_caller_setup_arg(jit, ctx, asm, calling.flags) == CantCompile
- return CantCompile
- end
-
- if calling.argc == 0
- asm.incr_counter(:send_optimized_send_no_args)
- return CantCompile
- end
-
- calling.argc -= 1
- # We aren't handling `send(:send, ...)` yet. This might work, but not tested yet.
- if calling.send_shift > 0
- asm.incr_counter(:send_optimized_send_send)
- return CantCompile
- end
- # Lazily handle stack shift in handle_opt_send_shift_stack
- calling.send_shift += 1
-
- jit_call_symbol(jit, ctx, asm, cme, calling, known_recv_class, C::VM_CALL_FCALL)
- end
-
- # vm_call_opt_call
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_opt_call(jit, ctx, asm, cme, flags, argc, block_handler, known_recv_class, send_shift:)
- if block_handler != C::VM_BLOCK_HANDLER_NONE
- asm.incr_counter(:send_optimized_call_block)
- return CantCompile
- end
-
- if flags & C::VM_CALL_KWARG != 0
- asm.incr_counter(:send_optimized_call_kwarg)
- return CantCompile
- end
-
- if flags & C::VM_CALL_ARGS_SPLAT != 0
- asm.incr_counter(:send_optimized_call_splat)
- return CantCompile
- end
-
- # TODO: implement this
- # Optimize for single ractor mode and avoid runtime check for
- # "defined with an un-shareable Proc in a different Ractor"
- # if !assume_single_ractor_mode(jit, ocb)
- # return CantCompile
- # end
-
- # If this is a .send call we need to adjust the stack
- if flags & C::VM_CALL_OPT_SEND != 0
- handle_opt_send_shift_stack(asm, argc, ctx, send_shift:)
- end
-
- # About to reset the SP, need to load this here
- recv_idx = argc # blockarg is not supported. send_shift is already handled.
- asm.mov(:rcx, ctx.stack_opnd(recv_idx)) # recv
-
- # Save the PC and SP because the callee can make Ruby calls
- jit_prepare_routine_call(jit, ctx, asm) # NOTE: clobbers rax
-
- asm.lea(:rax, ctx.sp_opnd(0)) # sp
-
- kw_splat = flags & C::VM_CALL_KW_SPLAT
-
- asm.mov(C_ARGS[0], :rcx)
- asm.mov(C_ARGS[1], EC)
- asm.mov(C_ARGS[2], argc)
- asm.lea(C_ARGS[3], [:rax, -argc * C.VALUE.size]) # stack_argument_pointer. NOTE: C_ARGS[3] is rcx
- asm.mov(C_ARGS[4], kw_splat)
- asm.mov(C_ARGS[5], C::VM_BLOCK_HANDLER_NONE)
- asm.call(C.rjit_optimized_call)
-
- ctx.stack_pop(argc + 1)
-
- stack_ret = ctx.stack_push(Type::Unknown)
- asm.mov(stack_ret, C_RET)
- return KeepCompiling
- end
-
- # vm_call_opt_struct_aref
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_opt_struct_aref(jit, ctx, asm, cme, flags, argc, block_handler, known_recv_class, send_shift:)
- if argc != 0
- asm.incr_counter(:send_optimized_struct_aref_error)
- return CantCompile
- end
-
- if c_method_tracing_currently_enabled?
- # Don't JIT if tracing c_call or c_return
- asm.incr_counter(:send_cfunc_tracing)
- return CantCompile
- end
-
- off = cme.def.body.optimized.index
-
- recv_idx = argc # blockarg is not supported
- recv_idx += send_shift
- comptime_recv = jit.peek_at_stack(recv_idx)
-
- # This is a .send call and we need to adjust the stack
- if flags & C::VM_CALL_OPT_SEND != 0
- handle_opt_send_shift_stack(asm, argc, ctx, send_shift:)
- end
-
- # All structs from the same Struct class should have the same
- # length. So if our comptime_recv is embedded all runtime
- # structs of the same class should be as well, and the same is
- # true of the converse.
- embedded = C::FL_TEST_RAW(comptime_recv, C::RSTRUCT_EMBED_LEN_MASK)
-
- asm.comment('struct aref')
- asm.mov(:rax, ctx.stack_pop(1)) # recv
-
- if embedded
- asm.mov(:rax, [:rax, C.RStruct.offsetof(:as, :ary) + (C.VALUE.size * off)])
- else
- asm.mov(:rax, [:rax, C.RStruct.offsetof(:as, :heap, :ptr)])
- asm.mov(:rax, [:rax, C.VALUE.size * off])
- end
-
- ret = ctx.stack_push(Type::Unknown)
- asm.mov(ret, :rax)
-
- jump_to_next_insn(jit, ctx, asm)
- EndBlock
- end
-
- # vm_call_opt_send (lazy part)
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def handle_opt_send_shift_stack(asm, argc, ctx, send_shift:)
- # We don't support `send(:send, ...)` for now.
- assert_equal(1, send_shift)
-
- asm.comment('shift stack')
- (0...argc).reverse_each do |i|
- opnd = ctx.stack_opnd(i)
- opnd2 = ctx.stack_opnd(i + 1)
- asm.mov(:rax, opnd)
- asm.mov(opnd2, :rax)
- end
-
- ctx.shift_stack(argc)
- end
-
- # vm_call_symbol
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_call_symbol(jit, ctx, asm, cme, calling, known_recv_class, flags)
- flags |= C::VM_CALL_OPT_SEND | (calling.kw_splat ? C::VM_CALL_KW_SPLAT : 0)
-
- comptime_symbol = jit.peek_at_stack(calling.argc)
- if comptime_symbol.class != String && !static_symbol?(comptime_symbol)
- asm.incr_counter(:send_optimized_send_not_sym_or_str)
- return CantCompile
- end
-
- mid = C.get_symbol_id(comptime_symbol)
- if mid == 0
- asm.incr_counter(:send_optimized_send_null_mid)
- return CantCompile
- end
-
- asm.comment("Guard #{comptime_symbol.inspect} is on stack")
- class_changed_exit = counted_exit(side_exit(jit, ctx), :send_optimized_send_mid_class_changed)
- jit_guard_known_klass(
- jit, ctx, asm, C.rb_class_of(comptime_symbol), ctx.stack_opnd(calling.argc),
- StackOpnd[calling.argc], comptime_symbol, class_changed_exit,
- )
- asm.mov(C_ARGS[0], ctx.stack_opnd(calling.argc))
- asm.call(C.rb_get_symbol_id)
- asm.cmp(C_RET, mid)
- id_changed_exit = counted_exit(side_exit(jit, ctx), :send_optimized_send_mid_id_changed)
- jit_chain_guard(:jne, jit, ctx, asm, id_changed_exit)
-
- # rb_callable_method_entry_with_refinements
- calling.flags = flags
- cme, _ = jit_search_method(jit, ctx, asm, mid, calling)
- if cme == CantCompile
- return CantCompile
- end
-
- if flags & C::VM_CALL_FCALL != 0
- return jit_call_method(jit, ctx, asm, mid, calling, cme, known_recv_class)
- end
-
- raise NotImplementedError # unreachable for now
- end
-
- # vm_push_frame
- #
- # Frame structure:
- # | args | locals | cme/cref | block_handler/prev EP | frame type (EP here) | stack bottom (SP here)
- #
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_push_frame(jit, ctx, asm, cme, flags, argc, frame_type, block_handler, iseq: nil, local_size: 0, stack_max: 0, prev_ep: nil, doing_kw_call: nil)
- # Save caller SP and PC before pushing a callee frame for backtrace and side exits
- asm.comment('save SP to caller CFP')
- recv_idx = argc # blockarg is already popped
- recv_idx += (block_handler == :captured) ? 0 : 1 # receiver is not on stack when captured->self is used
- if iseq
- # Skip setting this to SP register. This cfp->sp will be copied to SP on leave insn.
- asm.lea(:rax, ctx.sp_opnd(C.VALUE.size * -recv_idx)) # Pop receiver and arguments to prepare for side exits
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], :rax)
- else
- asm.lea(SP, ctx.sp_opnd(C.VALUE.size * -recv_idx))
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:sp)], SP)
- ctx.sp_offset = recv_idx
- end
- jit_save_pc(jit, asm, comment: 'save PC to caller CFP')
-
- sp_offset = ctx.sp_offset + 3 + local_size + (doing_kw_call ? 1 : 0) # callee_sp
- local_size.times do |i|
- asm.comment('set local variables') if i == 0
- local_index = sp_offset + i - local_size - 3
- asm.mov([SP, C.VALUE.size * local_index], Qnil)
- end
-
- asm.comment('set up EP with managing data')
- ep_offset = sp_offset - 1
- # ep[-2]: cref_or_me
- asm.mov(:rax, cme.to_i)
- asm.mov([SP, C.VALUE.size * (ep_offset - 2)], :rax)
- # ep[-1]: block handler or prev env ptr (specval)
- if prev_ep
- asm.mov(:rax, prev_ep.to_i | 1) # tagged prev ep
- asm.mov([SP, C.VALUE.size * (ep_offset - 1)], :rax)
- elsif block_handler == :captured
- # Set captured->ep, saving captured in :rcx for captured->self
- ep_reg = :rcx
- jit_get_lep(jit, asm, reg: ep_reg)
- asm.mov(:rcx, [ep_reg, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]) # block_handler
- asm.and(:rcx, ~0x3) # captured
- asm.mov(:rax, [:rcx, C.VALUE.size]) # captured->ep
- asm.or(:rax, 0x1) # GC_GUARDED_PTR
- asm.mov([SP, C.VALUE.size * (ep_offset - 1)], :rax)
- elsif block_handler == C::VM_BLOCK_HANDLER_NONE
- asm.mov([SP, C.VALUE.size * (ep_offset - 1)], C::VM_BLOCK_HANDLER_NONE)
- elsif block_handler == C.rb_block_param_proxy
- # vm_caller_setup_arg_block: block_code == rb_block_param_proxy
- jit_get_lep(jit, asm, reg: :rax) # VM_CF_BLOCK_HANDLER: VM_CF_LEP
- asm.mov(:rax, [:rax, C.VALUE.size * C::VM_ENV_DATA_INDEX_SPECVAL]) # VM_CF_BLOCK_HANDLER: VM_ENV_BLOCK_HANDLER
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:block_code)], :rax) # reg_cfp->block_code = handler
- asm.mov([SP, C.VALUE.size * (ep_offset - 1)], :rax) # return handler;
- else # assume blockiseq
- asm.mov(:rax, block_handler)
- asm.mov([CFP, C.rb_control_frame_t.offsetof(:block_code)], :rax)
- asm.lea(:rax, [CFP, C.rb_control_frame_t.offsetof(:self)]) # VM_CFP_TO_CAPTURED_BLOCK
- asm.or(:rax, 1) # VM_BH_FROM_ISEQ_BLOCK
- asm.mov([SP, C.VALUE.size * (ep_offset - 1)], :rax)
- end
- # ep[-0]: ENV_FLAGS
- asm.mov([SP, C.VALUE.size * (ep_offset - 0)], frame_type)
-
- asm.comment('set up new frame')
- cfp_offset = -C.rb_control_frame_t.size # callee CFP
- # For ISEQ, JIT code will set it as needed. However, C func needs 0 there for svar frame detection.
- if iseq.nil?
- asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:pc)], 0)
- end
- asm.mov(:rax, iseq.to_i)
- asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:iseq)], :rax)
- if block_handler == :captured
- asm.mov(:rax, [:rcx]) # captured->self
- else
- self_index = ctx.sp_offset - (1 + argc) # blockarg has been popped
- asm.mov(:rax, [SP, C.VALUE.size * self_index])
- end
- asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:self)], :rax)
- asm.lea(:rax, [SP, C.VALUE.size * ep_offset])
- asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:ep)], :rax)
- asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:block_code)], 0)
- # Update SP register only for ISEQ calls. SP-relative operations should be done above this.
- sp_reg = iseq ? SP : :rax
- asm.lea(sp_reg, [SP, C.VALUE.size * sp_offset])
- asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:sp)], sp_reg)
-
- # cfp->jit_return is used only for ISEQs
- if iseq
- # The callee might change locals through Kernel#binding and other means.
- ctx.clear_local_types
-
- # Stub cfp->jit_return
- return_ctx = ctx.dup
- return_ctx.stack_pop(argc + ((block_handler == :captured) ? 0 : 1)) # Pop args and receiver. blockarg has been popped
- return_ctx.stack_push(Type::Unknown) # push callee's return value
- return_ctx.sp_offset = 1 # SP is in the position after popping a receiver and arguments
- return_ctx.chain_depth = 0
- branch_stub = BranchStub.new(
- iseq: jit.iseq,
- shape: Default,
- target0: BranchTarget.new(ctx: return_ctx, pc: jit.pc + jit.insn.len * C.VALUE.size),
- )
- branch_stub.target0.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(return_ctx, ocb_asm, branch_stub, true)
- @ocb.write(ocb_asm)
- end
- branch_stub.compile = compile_jit_return(branch_stub, cfp_offset:)
- branch_stub.compile.call(asm)
- end
-
- asm.comment('switch to callee CFP')
- # Update CFP register only for ISEQ calls
- cfp_reg = iseq ? CFP : :rax
- asm.lea(cfp_reg, [CFP, cfp_offset])
- asm.mov([EC, C.rb_execution_context_t.offsetof(:cfp)], cfp_reg)
- end
-
- def compile_jit_return(branch_stub, cfp_offset:) # Proc escapes arguments in memory
- proc do |branch_asm|
- branch_asm.comment('set jit_return to callee CFP')
- branch_asm.stub(branch_stub) do
- case branch_stub.shape
- in Default
- branch_asm.mov(:rax, branch_stub.target0.address)
- branch_asm.mov([CFP, cfp_offset + C.rb_control_frame_t.offsetof(:jit_return)], :rax)
- end
- end
- end
- end
-
- # CALLER_SETUP_ARG: Return CantCompile if not supported
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def jit_caller_setup_arg(jit, ctx, asm, flags)
- if flags & C::VM_CALL_ARGS_SPLAT != 0 && flags & C::VM_CALL_KW_SPLAT != 0
- asm.incr_counter(:send_args_splat_kw_splat)
- return CantCompile
- elsif flags & C::VM_CALL_ARGS_SPLAT != 0
- # splat is not supported in this path
- asm.incr_counter(:send_args_splat)
- return CantCompile
- elsif flags & C::VM_CALL_KW_SPLAT != 0
- asm.incr_counter(:send_args_kw_splat)
- return CantCompile
- elsif flags & C::VM_CALL_KWARG != 0
- asm.incr_counter(:send_kwarg)
- return CantCompile
- end
- end
-
- # Pushes arguments from an array to the stack. Differs from push splat because
- # the array can have items left over.
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def move_rest_args_to_stack(array, num_args, jit, ctx, asm)
- side_exit = side_exit(jit, ctx)
-
- asm.comment('move_rest_args_to_stack')
-
- # array is :rax
- array_len_opnd = :rcx
- jit_array_len(asm, array, array_len_opnd)
-
- asm.comment('Side exit if length is less than required')
- asm.cmp(array_len_opnd, num_args)
- asm.jl(counted_exit(side_exit, :send_iseq_has_rest_and_splat_not_equal))
-
- asm.comment('Push arguments from array')
-
- # Load the address of the embedded array
- # (struct RArray *)(obj)->as.ary
- array_reg = array
-
- # Conditionally load the address of the heap array
- # (struct RArray *)(obj)->as.heap.ptr
- flags_opnd = [array_reg, C.RBasic.offsetof(:flags)]
- asm.test(flags_opnd, C::RARRAY_EMBED_FLAG)
- heap_ptr_opnd = [array_reg, C.RArray.offsetof(:as, :heap, :ptr)]
- # Load the address of the embedded array
- # (struct RArray *)(obj)->as.ary
- ary_opnd = :rdx # NOTE: array :rax is used after move_rest_args_to_stack too
- asm.lea(:rcx, [array_reg, C.RArray.offsetof(:as, :ary)])
- asm.mov(ary_opnd, heap_ptr_opnd)
- asm.cmovnz(ary_opnd, :rcx)
-
- num_args.times do |i|
- top = ctx.stack_push(Type::Unknown)
- asm.mov(:rcx, [ary_opnd, i * C.VALUE.size])
- asm.mov(top, :rcx)
- end
- end
-
- # vm_caller_setup_arg_splat (+ CALLER_SETUP_ARG):
- # Pushes arguments from an array to the stack that are passed with a splat (i.e. *args).
- # It optimistically compiles to a static size that is the exact number of arguments needed for the function.
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def push_splat_args(required_args, jit, ctx, asm)
- side_exit = side_exit(jit, ctx)
-
- asm.comment('push_splat_args')
-
- array_opnd = ctx.stack_opnd(0)
- array_stack_opnd = StackOpnd[0]
- array_reg = :rax
- asm.mov(array_reg, array_opnd)
-
- guard_object_is_array(jit, ctx, asm, array_reg, :rcx, array_stack_opnd, :send_args_splat_not_array)
-
- array_len_opnd = :rcx
- jit_array_len(asm, array_reg, array_len_opnd)
-
- asm.comment('Side exit if length is not equal to remaining args')
- asm.cmp(array_len_opnd, required_args)
- asm.jne(counted_exit(side_exit, :send_args_splat_length_not_equal))
-
- asm.comment('Check last argument is not ruby2keyword hash')
-
- ary_opnd = :rcx
- jit_array_ptr(asm, array_reg, ary_opnd) # clobbers array_reg
-
- last_array_value = :rax
- asm.mov(last_array_value, [ary_opnd, (required_args - 1) * C.VALUE.size])
-
- ruby2_exit = counted_exit(side_exit, :send_args_splat_ruby2_hash);
- guard_object_is_not_ruby2_keyword_hash(asm, last_array_value, :rcx, ruby2_exit) # clobbers :rax
-
- asm.comment('Push arguments from array')
- array_opnd = ctx.stack_pop(1)
-
- if required_args > 0
- # Load the address of the embedded array
- # (struct RArray *)(obj)->as.ary
- array_reg = :rax
- asm.mov(array_reg, array_opnd)
-
- # Conditionally load the address of the heap array
- # (struct RArray *)(obj)->as.heap.ptr
- flags_opnd = [array_reg, C.RBasic.offsetof(:flags)]
- asm.test(flags_opnd, C::RARRAY_EMBED_FLAG)
- heap_ptr_opnd = [array_reg, C.RArray.offsetof(:as, :heap, :ptr)]
- # Load the address of the embedded array
- # (struct RArray *)(obj)->as.ary
- asm.lea(:rcx, [array_reg, C.RArray.offsetof(:as, :ary)])
- asm.mov(:rax, heap_ptr_opnd)
- asm.cmovnz(:rax, :rcx)
- ary_opnd = :rax
-
- (0...required_args).each do |i|
- top = ctx.stack_push(Type::Unknown)
- asm.mov(:rcx, [ary_opnd, i * C.VALUE.size])
- asm.mov(top, :rcx)
- end
-
- asm.comment('end push_each')
- end
- end
-
- # Generate RARRAY_LEN. For array_opnd, use Opnd::Reg to reduce memory access,
- # and use Opnd::Mem to save registers.
- def jit_array_len(asm, array_reg, len_reg)
- asm.comment('get array length for embedded or heap')
-
- # Pull out the embed flag to check if it's an embedded array.
- asm.mov(len_reg, [array_reg, C.RBasic.offsetof(:flags)])
-
- # Get the length of the array
- asm.and(len_reg, C::RARRAY_EMBED_LEN_MASK)
- asm.sar(len_reg, C::RARRAY_EMBED_LEN_SHIFT)
-
- # Conditionally move the length of the heap array
- asm.test([array_reg, C.RBasic.offsetof(:flags)], C::RARRAY_EMBED_FLAG)
-
- # Select the array length value
- asm.cmovz(len_reg, [array_reg, C.RArray.offsetof(:as, :heap, :len)])
- end
-
- # Generate RARRAY_CONST_PTR (part of RARRAY_AREF)
- def jit_array_ptr(asm, array_reg, ary_opnd) # clobbers array_reg
- asm.comment('get array pointer for embedded or heap')
-
- flags_opnd = [array_reg, C.RBasic.offsetof(:flags)]
- asm.test(flags_opnd, C::RARRAY_EMBED_FLAG)
- # Load the address of the embedded array
- # (struct RArray *)(obj)->as.ary
- asm.mov(ary_opnd, [array_reg, C.RArray.offsetof(:as, :heap, :ptr)])
- asm.lea(array_reg, [array_reg, C.RArray.offsetof(:as, :ary)]) # clobbers array_reg
- asm.cmovnz(ary_opnd, array_reg)
- end
-
- def assert(cond)
- assert_equal(cond, true)
- end
-
- def assert_equal(left, right)
- if left != right
- raise "'#{left.inspect}' was not '#{right.inspect}'"
- end
- end
-
- def fixnum?(obj)
- (C.to_value(obj) & C::RUBY_FIXNUM_FLAG) == C::RUBY_FIXNUM_FLAG
- end
-
- def flonum?(obj)
- (C.to_value(obj) & C::RUBY_FLONUM_MASK) == C::RUBY_FLONUM_FLAG
- end
-
- def symbol?(obj)
- static_symbol?(obj) || dynamic_symbol?(obj)
- end
-
- def static_symbol?(obj)
- (C.to_value(obj) & 0xff) == C::RUBY_SYMBOL_FLAG
- end
-
- def dynamic_symbol?(obj)
- return false if C::SPECIAL_CONST_P(obj)
- C.RB_TYPE_P(obj, C::RUBY_T_SYMBOL)
- end
-
- def shape_too_complex?(obj)
- C.rb_shape_get_shape_id(obj) == C::OBJ_TOO_COMPLEX_SHAPE_ID
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- # @param asm [RubyVM::RJIT::Assembler]
- def defer_compilation(jit, ctx, asm)
- # Make a stub to compile the current insn
- if ctx.chain_depth != 0
- raise "double defer!"
- end
- ctx.chain_depth += 1
- jit_direct_jump(jit.iseq, jit.pc, ctx, asm, comment: 'defer_compilation')
- end
-
- def jit_direct_jump(iseq, pc, ctx, asm, comment: 'jit_direct_jump')
- branch_stub = BranchStub.new(
- iseq:,
- shape: Default,
- target0: BranchTarget.new(ctx:, pc:),
- )
- branch_stub.target0.address = Assembler.new.then do |ocb_asm|
- @exit_compiler.compile_branch_stub(ctx, ocb_asm, branch_stub, true)
- @ocb.write(ocb_asm)
- end
- branch_stub.compile = compile_jit_direct_jump(branch_stub, comment:)
- branch_stub.compile.call(asm)
- end
-
- def compile_jit_direct_jump(branch_stub, comment:) # Proc escapes arguments in memory
- proc do |branch_asm|
- branch_asm.comment(comment)
- branch_asm.stub(branch_stub) do
- case branch_stub.shape
- in Default
- branch_asm.jmp(branch_stub.target0.address)
- in Next0
- # Just write the block without a jump
- end
- end
- end
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param ctx [RubyVM::RJIT::Context]
- def side_exit(jit, ctx)
- # We use the latest ctx.sp_offset to generate a side exit to tolerate sp_offset changes by jit_save_sp.
- # However, we want to simulate an old stack_size when we take a side exit. We do that by adjusting the
- # sp_offset because gen_outlined_exit uses ctx.sp_offset to move SP.
- ctx = ctx.with_stack_size(jit.stack_size_for_pc)
-
- jit.side_exit_for_pc[ctx.sp_offset] ||= Assembler.new.then do |asm|
- @exit_compiler.compile_side_exit(jit.pc, ctx, asm)
- @ocb.write(asm)
- end
- end
-
- def counted_exit(side_exit, name)
- asm = Assembler.new
- asm.incr_counter(name)
- asm.jmp(side_exit)
- @ocb.write(asm)
- end
-
- def def_iseq_ptr(cme_def)
- C.rb_iseq_check(cme_def.body.iseq.iseqptr)
- end
-
- def to_value(obj)
- GC_REFS << obj
- C.to_value(obj)
- end
-
- def full_cfunc_return
- @full_cfunc_return ||= Assembler.new.then do |asm|
- @exit_compiler.compile_full_cfunc_return(asm)
- @ocb.write(asm)
- end
- end
-
- def c_method_tracing_currently_enabled?
- C.rb_rjit_global_events & (C::RUBY_EVENT_C_CALL | C::RUBY_EVENT_C_RETURN) != 0
- end
-
- # Return a builtin function if a given iseq consists of only that builtin function
- def builtin_function(iseq)
- opt_invokebuiltin_delegate_leave = INSNS.values.find { |i| i.name == :opt_invokebuiltin_delegate_leave }
- leave = INSNS.values.find { |i| i.name == :leave }
- if iseq.body.iseq_size == opt_invokebuiltin_delegate_leave.len + leave.len &&
- C.rb_vm_insn_decode(iseq.body.iseq_encoded[0]) == opt_invokebuiltin_delegate_leave.bin &&
- C.rb_vm_insn_decode(iseq.body.iseq_encoded[opt_invokebuiltin_delegate_leave.len]) == leave.bin
- C.rb_builtin_function.new(iseq.body.iseq_encoded[1])
- end
- end
-
- def build_calling(ci:, block_handler:)
- CallingInfo.new(
- argc: C.vm_ci_argc(ci),
- flags: C.vm_ci_flag(ci),
- kwarg: C.vm_ci_kwarg(ci),
- ci_addr: ci.to_i,
- send_shift: 0,
- block_handler:,
- )
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/invariants.rb b/lib/ruby_vm/rjit/invariants.rb
deleted file mode 100644
index 5b061d1994..0000000000
--- a/lib/ruby_vm/rjit/invariants.rb
+++ /dev/null
@@ -1,155 +0,0 @@
-require 'set'
-
-module RubyVM::RJIT
- class Invariants
- class << self
- # Called by RubyVM::RJIT::Compiler to lazily initialize this
- # @param cb [CodeBlock]
- # @param ocb [CodeBlock]
- # @param compiler [RubyVM::RJIT::Compiler]
- # @param exit_compiler [RubyVM::RJIT::ExitCompiler]
- def initialize(cb, ocb, compiler, exit_compiler)
- @cb = cb
- @ocb = ocb
- @compiler = compiler
- @exit_compiler = exit_compiler
- @bop_blocks = Set.new # TODO: actually invalidate this
- @cme_blocks = Hash.new { |h, k| h[k] = Set.new }
- @const_blocks = Hash.new { |h, k| h[k] = Set.new }
- @patches = {}
-
- # freeze # workaround a binding.irb issue. TODO: resurrect this
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param klass [Integer]
- # @param op [Integer]
- def assume_bop_not_redefined(jit, klass, op)
- return false unless C.BASIC_OP_UNREDEFINED_P(klass, op)
-
- ensure_block_entry_exit(jit, cause: 'assume_bop_not_redefined')
- @bop_blocks << jit.block
- true
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- def assume_method_lookup_stable(jit, cme)
- ensure_block_entry_exit(jit, cause: 'assume_method_lookup_stable')
- @cme_blocks[cme.to_i] << jit.block
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- def assume_method_basic_definition(jit, klass, mid)
- if C.rb_method_basic_definition_p(klass, mid)
- cme = C.rb_callable_method_entry(klass, mid)
- assume_method_lookup_stable(jit, cme)
- true
- else
- false
- end
- end
-
- def assume_stable_constant_names(jit, idlist)
- (0..).each do |i|
- break if (id = idlist[i]) == 0
- @const_blocks[id] << jit.block
- end
- end
-
- # @param asm [RubyVM::RJIT::Assembler]
- def record_global_inval_patch(asm, target)
- asm.pos_marker do |address|
- if @patches.key?(address)
- raise 'multiple patches in the same address'
- end
- @patches[address] = target
- end
- end
-
- def on_cme_invalidate(cme)
- @cme_blocks.fetch(cme.to_i, []).each do |block|
- @cb.with_write_addr(block.start_addr) do
- asm = Assembler.new
- asm.comment('on_cme_invalidate')
- asm.jmp(block.entry_exit)
- @cb.write(asm)
- end
- # TODO: re-generate branches that refer to this block
- end
- @cme_blocks.delete(cme.to_i)
- end
-
- def on_constant_ic_update(iseq, ic, insn_idx)
- # TODO: check multi ractor as well
- if ic.entry.ic_cref
- # No need to recompile the slowpath
- return
- end
-
- pc = iseq.body.iseq_encoded + insn_idx
- insn_name = Compiler.decode_insn(pc.*).name
- if insn_name != :opt_getconstant_path && insn_name != :trace_opt_getconstant_path
- raise 'insn_idx was not at opt_getconstant_path'
- end
- if ic.to_i != pc[1]
- raise 'insn_idx + 1 was not at the updated IC'
- end
- @compiler.invalidate_blocks(iseq, pc.to_i)
- end
-
- def on_constant_state_changed(id)
- @const_blocks.fetch(id, []).each do |block|
- @compiler.invalidate_block(block)
- end
- end
-
- def on_tracing_invalidate_all
- invalidate_all
- end
-
- def on_update_references
- # Give up. In order to support GC.compact, you'd have to update ISEQ
- # addresses in BranchStub, etc. Ideally, we'd need to update moved
- # pointers in JITed code here, but we just invalidate all for now.
- invalidate_all
- end
-
- # @param jit [RubyVM::RJIT::JITState]
- # @param block [RubyVM::RJIT::Block]
- def ensure_block_entry_exit(jit, cause:)
- block = jit.block
- if block.entry_exit.nil?
- block.entry_exit = Assembler.new.then do |asm|
- @exit_compiler.compile_entry_exit(block.pc, block.ctx, asm, cause:)
- @ocb.write(asm)
- end
- end
- end
-
- private
-
- def invalidate_all
- # On-Stack Replacement
- @patches.each do |address, target|
- # TODO: assert patches don't overlap each other
- @cb.with_write_addr(address) do
- asm = Assembler.new
- asm.comment('on_tracing_invalidate_all')
- asm.jmp(target)
- @cb.write(asm)
- end
- end
- @patches.clear
-
- C.rjit_for_each_iseq do |iseq|
- # Avoid entering past code
- iseq.body.jit_entry = 0
- # Avoid reusing past code
- iseq.body.rjit_blocks.clear if iseq.body.rjit_blocks
- # Compile this again if not converted to trace_* insns
- iseq.body.jit_entry_calls = 0
- end
- end
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/jit_state.rb b/lib/ruby_vm/rjit/jit_state.rb
deleted file mode 100644
index 02a713474e..0000000000
--- a/lib/ruby_vm/rjit/jit_state.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-module RubyVM::RJIT
- class JITState < Struct.new(
- :iseq, # @param `RubyVM::RJIT::CPointer::Struct_rb_iseq_t`
- :pc, # @param [Integer] The JIT target PC
- :cfp, # @param `RubyVM::RJIT::CPointer::Struct_rb_control_frame_t` The JIT source CFP (before RJIT is called)
- :block, # @param [RubyVM::RJIT::Block]
- :stack_size_for_pc, # @param [Integer]
- :side_exit_for_pc, # @param [Hash{ Integer => Integer }] { sp_offset => address }
- :record_boundary_patch_point, # @param [TrueClass,FalseClass]
- )
- def initialize(side_exit_for_pc: {}, record_boundary_patch_point: false, **) = super
-
- def insn
- Compiler.decode_insn(C.VALUE.new(pc).*)
- end
-
- def operand(index, signed: false, ruby: false)
- addr = pc + (index + 1) * Fiddle::SIZEOF_VOIDP
- value = Fiddle::Pointer.new(addr)[0, Fiddle::SIZEOF_VOIDP].unpack(signed ? 'q' : 'Q')[0]
- if ruby
- value = C.to_ruby(value)
- end
- value
- end
-
- def at_current_insn?
- pc == cfp.pc.to_i
- end
-
- def peek_at_local(n)
- local_table_size = iseq.body.local_table_size
- offset = -C::VM_ENV_DATA_SIZE - local_table_size + n + 1
- value = (cfp.ep + offset).*
- C.to_ruby(value)
- end
-
- def peek_at_stack(depth_from_top)
- raise 'not at current insn' unless at_current_insn?
- offset = -(1 + depth_from_top)
- # rb_rjit_branch_stub_hit updates SP, so you don't need to worry about sp_offset
- value = (cfp.sp + offset).*
- C.to_ruby(value)
- end
-
- def peek_at_self
- C.to_ruby(cfp.self)
- end
-
- def peek_at_block_handler(level)
- ep = ep_at_level(cfp, level:)
- ep[C::VM_ENV_DATA_INDEX_SPECVAL]
- end
-
- private
-
- def ep_at_level(cfp, level:)
- ep = cfp.ep
- level.times do
- # VM_ENV_PREV_EP
- ep = C.VALUE.new(ep[C::VM_ENV_DATA_INDEX_SPECVAL] & ~0x03)
- end
- ep
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/stats.rb b/lib/ruby_vm/rjit/stats.rb
deleted file mode 100644
index 7e353c698e..0000000000
--- a/lib/ruby_vm/rjit/stats.rb
+++ /dev/null
@@ -1,191 +0,0 @@
-# frozen_string_literal: true
-module RubyVM::RJIT
- # Return a Hash for \RJIT statistics. \--rjit-stats makes more information available.
- def self.runtime_stats
- stats = {}
-
- # Insn exits
- INSNS.each_value do |insn|
- exits = C.rjit_insn_exits[insn.bin]
- if exits > 0
- stats[:"exit_#{insn.name}"] = exits
- end
- end
-
- # Runtime stats
- C.rb_rjit_runtime_counters.members.each do |member|
- stats[member] = C.rb_rjit_counters.public_send(member)
- end
- stats[:vm_insns_count] = C.rb_vm_insns_count
-
- # Other stats are calculated here
- stats[:side_exit_count] = stats.select { |name, _count| name.start_with?('exit_') }.sum(&:last)
- if stats[:vm_insns_count] > 0
- retired_in_rjit = stats[:rjit_insns_count] - stats[:side_exit_count]
- stats[:total_insns_count] = retired_in_rjit + stats[:vm_insns_count]
- stats[:ratio_in_rjit] = 100.0 * retired_in_rjit / stats[:total_insns_count]
- else
- stats.delete(:vm_insns_count)
- end
-
- stats
- end
-
- # :nodoc: all
- class << self
- private
-
- # --yjit-stats at_exit
- def print_stats
- stats = runtime_stats
- $stderr.puts("***RJIT: Printing RJIT statistics on exit***")
-
- print_counters(stats, prefix: 'send_', prompt: 'method call exit reasons')
- print_counters(stats, prefix: 'invokeblock_', prompt: 'invokeblock exit reasons')
- print_counters(stats, prefix: 'invokesuper_', prompt: 'invokesuper exit reasons')
- print_counters(stats, prefix: 'getblockpp_', prompt: 'getblockparamproxy exit reasons')
- print_counters(stats, prefix: 'getivar_', prompt: 'getinstancevariable exit reasons')
- print_counters(stats, prefix: 'setivar_', prompt: 'setinstancevariable exit reasons')
- print_counters(stats, prefix: 'optaref_', prompt: 'opt_aref exit reasons')
- print_counters(stats, prefix: 'optgetconst_', prompt: 'opt_getconstant_path exit reasons')
- print_counters(stats, prefix: 'expandarray_', prompt: 'expandarray exit reasons')
-
- $stderr.puts "compiled_block_count: #{format_number(13, stats[:compiled_block_count])}"
- $stderr.puts "side_exit_count: #{format_number(13, stats[:side_exit_count])}"
- $stderr.puts "total_insns_count: #{format_number(13, stats[:total_insns_count])}" if stats.key?(:total_insns_count)
- $stderr.puts "vm_insns_count: #{format_number(13, stats[:vm_insns_count])}" if stats.key?(:vm_insns_count)
- $stderr.puts "rjit_insns_count: #{format_number(13, stats[:rjit_insns_count])}"
- $stderr.puts "ratio_in_rjit: #{format('%12.1f', stats[:ratio_in_rjit])}%" if stats.key?(:ratio_in_rjit)
-
- print_exit_counts(stats)
- end
-
- def print_counters(stats, prefix:, prompt:)
- $stderr.puts("#{prompt}: ")
- counters = stats.filter { |key, _| key.start_with?(prefix) }
- counters.filter! { |_, value| value != 0 }
- counters.transform_keys! { |key| key.to_s.delete_prefix(prefix) }
-
- if counters.empty?
- $stderr.puts(" (all relevant counters are zero)")
- return
- end
-
- counters = counters.to_a
- counters.sort_by! { |(_, counter_value)| counter_value }
- longest_name_length = counters.max_by { |(name, _)| name.length }.first.length
- total = counters.sum { |(_, counter_value)| counter_value }
-
- counters.reverse_each do |(name, value)|
- percentage = value.fdiv(total) * 100
- $stderr.printf(" %*s %s (%4.1f%%)\n", longest_name_length, name, format_number(10, value), percentage)
- end
- end
-
- def print_exit_counts(stats, how_many: 20, padding: 2)
- exits = stats.filter_map { |name, count| [name.to_s.delete_prefix('exit_'), count] if name.start_with?('exit_') }.to_h
- return if exits.empty?
-
- top_exits = exits.sort_by { |_name, count| -count }.first(how_many).to_h
- total_exits = exits.values.sum
- $stderr.puts "Top-#{top_exits.size} most frequent exit ops (#{format("%.1f", 100.0 * top_exits.values.sum / total_exits)}% of exits):"
-
- name_width = top_exits.map { |name, _count| name.length }.max + padding
- count_width = top_exits.map { |_name, count| format_number(10, count).length }.max + padding
- top_exits.each do |name, count|
- ratio = 100.0 * count / total_exits
- $stderr.puts "#{format("%#{name_width}s", name)}: #{format_number(count_width, count)} (#{format('%4.1f', ratio)}%)"
- end
- end
-
- # Format large numbers with comma separators for readability
- def format_number(pad, number)
- integer, decimal = number.to_s.split('.')
- d_groups = integer.chars.reverse.each_slice(3)
- with_commas = d_groups.map(&:join).join(',').reverse
- [with_commas, decimal].compact.join('.').rjust(pad, ' ')
- end
-
- # --yjit-trace-exits at_exit
- def dump_trace_exits
- filename = "#{Dir.pwd}/rjit_exit_locations.dump"
- File.binwrite(filename, Marshal.dump(exit_traces))
- $stderr.puts("RJIT exit locations dumped to:\n#{filename}")
- end
-
- # Convert rb_rjit_raw_samples and rb_rjit_line_samples into a StackProf format.
- def exit_traces
- results = C.rjit_exit_traces
- raw_samples = results[:raw].dup
- line_samples = results[:lines].dup
- frames = results[:frames].dup
- samples_count = 0
-
- # Loop through the instructions and set the frame hash with the data.
- # We use nonexistent.def for the file name, otherwise insns.def will be displayed
- # and that information isn't useful in this context.
- RubyVM::INSTRUCTION_NAMES.each_with_index do |name, frame_id|
- frame_hash = { samples: 0, total_samples: 0, edges: {}, name: name, file: "nonexistent.def", line: nil, lines: {} }
- results[:frames][frame_id] = frame_hash
- frames[frame_id] = frame_hash
- end
-
- # Loop through the raw_samples and build the hashes for StackProf.
- # The loop is based off an example in the StackProf documentation and therefore
- # this functionality can only work with that library.
- #
- # Raw Samples:
- # [ length, frame1, frame2, frameN, ..., instruction, count
- #
- # Line Samples
- # [ length, line_1, line_2, line_n, ..., dummy value, count
- i = 0
- while i < raw_samples.length
- stack_length = raw_samples[i] + 1
- i += 1 # consume the stack length
-
- prev_frame_id = nil
- stack_length.times do |idx|
- idx += i
- frame_id = raw_samples[idx]
-
- if prev_frame_id
- prev_frame = frames[prev_frame_id]
- prev_frame[:edges][frame_id] ||= 0
- prev_frame[:edges][frame_id] += 1
- end
-
- frame_info = frames[frame_id]
- frame_info[:total_samples] += 1
-
- frame_info[:lines][line_samples[idx]] ||= [0, 0]
- frame_info[:lines][line_samples[idx]][0] += 1
-
- prev_frame_id = frame_id
- end
-
- i += stack_length # consume the stack
-
- top_frame_id = prev_frame_id
- top_frame_line = 1
-
- sample_count = raw_samples[i]
-
- frames[top_frame_id][:samples] += sample_count
- frames[top_frame_id][:lines] ||= {}
- frames[top_frame_id][:lines][top_frame_line] ||= [0, 0]
- frames[top_frame_id][:lines][top_frame_line][1] += sample_count
-
- samples_count += sample_count
- i += 1
- end
-
- results[:samples] = samples_count
- # Set missed_samples and gc_samples to 0 as their values
- # don't matter to us in this context.
- results[:missed_samples] = 0
- results[:gc_samples] = 0
- results
- end
- end
-end
diff --git a/lib/ruby_vm/rjit/type.rb b/lib/ruby_vm/rjit/type.rb
deleted file mode 100644
index 119692014b..0000000000
--- a/lib/ruby_vm/rjit/type.rb
+++ /dev/null
@@ -1,221 +0,0 @@
-module RubyVM::RJIT
- # Represent the type of a value (local/stack/self) in RJIT
- Type = Data.define(:type) do
- # Check if the type is an immediate
- def imm?
- case self
- in Type::UnknownImm then true
- in Type::Nil then true
- in Type::True then true
- in Type::False then true
- in Type::Fixnum then true
- in Type::Flonum then true
- in Type::ImmSymbol then true
- else false
- end
- end
-
- # Returns true when the type is not specific.
- def unknown?
- case self
- in Type::Unknown | Type::UnknownImm | Type::UnknownHeap then true
- else false
- end
- end
-
- # Returns true when we know the VALUE is a specific handle type,
- # such as a static symbol ([Type::ImmSymbol], i.e. true from RB_STATIC_SYM_P()).
- # Opposite of [Self::is_unknown].
- def specific?
- !self.unknown?
- end
-
- # Check if the type is a heap object
- def heap?
- case self
- in Type::UnknownHeap then true
- in Type::TArray then true
- in Type::Hash then true
- in Type::HeapSymbol then true
- in Type::TString then true
- in Type::CString then true
- in Type::BlockParamProxy then true
- else false
- end
- end
-
- # Check if it's a T_ARRAY object
- def array?
- case self
- in Type::TArray then true
- else false
- end
- end
-
- # Check if it's a T_STRING object (both TString and CString are T_STRING)
- def string?
- case self
- in Type::TString then true
- in Type::CString then true
- else false
- end
- end
-
- # Returns the class if it is known, otherwise nil
- def known_class
- case self
- in Type::Nil then C.rb_cNilClass
- in Type::True then C.rb_cTrueClass
- in Type::False then C.rb_cFalseClass
- in Type::Fixnum then C.rb_cInteger
- in Type::Flonum then C.rb_cFloat
- in Type::ImmSymbol | Type::HeapSymbol then C.rb_cSymbol
- in Type::CString then C.rb_cString
- else nil
- end
- end
-
- # Returns a boolean representing whether the value is truthy if known, otherwise nil
- def known_truthy
- case self
- in Type::Nil then false
- in Type::False then false
- in Type::UnknownHeap then false
- in Type::Unknown | Type::UnknownImm then nil
- else true
- end
- end
-
- # Returns a boolean representing whether the value is equal to nil if known, otherwise nil
- def known_nil
- case [self, self.known_truthy]
- in Type::Nil, _ then true
- in Type::False, _ then false # Qfalse is not nil
- in _, true then false # if truthy, can't be nil
- in _, _ then nil # otherwise unknown
- end
- end
-
- def diff(dst)
- # Perfect match, difference is zero
- if self == dst
- return TypeDiff::Compatible[0]
- end
-
- # Any type can flow into an unknown type
- if dst == Type::Unknown
- return TypeDiff::Compatible[1]
- end
-
- # A CString is also a TString.
- if self == Type::CString && dst == Type::TString
- return TypeDiff::Compatible[1]
- end
-
- # Specific heap type into unknown heap type is imperfect but valid
- if self.heap? && dst == Type::UnknownHeap
- return TypeDiff::Compatible[1]
- end
-
- # Specific immediate type into unknown immediate type is imperfect but valid
- if self.imm? && dst == Type::UnknownImm
- return TypeDiff::Compatible[1]
- end
-
- # Incompatible types
- return TypeDiff::Incompatible
- end
-
- def upgrade(new_type)
- assert(new_type.diff(self) != TypeDiff::Incompatible)
- new_type
- end
-
- private
-
- def assert(cond)
- unless cond
- raise "'#{cond.inspect}' was not true"
- end
- end
- end
-
- # This returns an appropriate Type based on a known value
- class << Type
- def from(val)
- if C::SPECIAL_CONST_P(val)
- if fixnum?(val)
- Type::Fixnum
- elsif val.nil?
- Type::Nil
- elsif val == true
- Type::True
- elsif val == false
- Type::False
- elsif static_symbol?(val)
- Type::ImmSymbol
- elsif flonum?(val)
- Type::Flonum
- else
- raise "Illegal value: #{val.inspect}"
- end
- else
- val_class = C.to_value(C.rb_class_of(val))
- if val_class == C.rb_cString && C.rb_obj_frozen_p(val)
- return Type::CString
- end
- if C.to_value(val) == C.rb_block_param_proxy
- return Type::BlockParamProxy
- end
- case C::BUILTIN_TYPE(val)
- in C::RUBY_T_ARRAY
- Type::TArray
- in C::RUBY_T_HASH
- Type::Hash
- in C::RUBY_T_STRING
- Type::TString
- else
- Type::UnknownHeap
- end
- end
- end
-
- private
-
- def fixnum?(obj)
- (C.to_value(obj) & C::RUBY_FIXNUM_FLAG) == C::RUBY_FIXNUM_FLAG
- end
-
- def flonum?(obj)
- (C.to_value(obj) & C::RUBY_FLONUM_MASK) == C::RUBY_FLONUM_FLAG
- end
-
- def static_symbol?(obj)
- (C.to_value(obj) & 0xff) == C::RUBY_SYMBOL_FLAG
- end
- end
-
- # List of types
- Type::Unknown = Type[:Unknown]
- Type::UnknownImm = Type[:UnknownImm]
- Type::UnknownHeap = Type[:UnknownHeap]
- Type::Nil = Type[:Nil]
- Type::True = Type[:True]
- Type::False = Type[:False]
- Type::Fixnum = Type[:Fixnum]
- Type::Flonum = Type[:Flonum]
- Type::Hash = Type[:Hash]
- Type::ImmSymbol = Type[:ImmSymbol]
- Type::HeapSymbol = Type[:HeapSymbol]
-
- Type::TString = Type[:TString] # An object with the T_STRING flag set, possibly an rb_cString
- Type::CString = Type[:CString] # An un-subclassed string of type rb_cString (can have instance vars in some cases)
- Type::TArray = Type[:TArray] # An object with the T_ARRAY flag set, possibly an rb_cArray
-
- Type::BlockParamProxy = Type[:BlockParamProxy] # A special sentinel value indicating the block parameter should be read from
-
- module TypeDiff
- Compatible = Data.define(:diversion) # The smaller, the more compatible.
- Incompatible = :Incompatible
- end
-end
diff --git a/lib/rubygems.rb b/lib/rubygems.rb
index 43c0d8f13c..af86646a82 100644
--- a/lib/rubygems.rb
+++ b/lib/rubygems.rb
@@ -9,7 +9,7 @@
require "rbconfig"
module Gem
- VERSION = "3.6.0.dev"
+ VERSION = "3.4.19"
end
# Must be first since it unloads the prelude from 1.9.2
@@ -18,7 +18,6 @@ require_relative "rubygems/compatibility"
require_relative "rubygems/defaults"
require_relative "rubygems/deprecate"
require_relative "rubygems/errors"
-require_relative "rubygems/target_rbconfig"
##
# RubyGems is the Ruby standard for publishing and managing third party
@@ -116,6 +115,11 @@ require_relative "rubygems/target_rbconfig"
module Gem
RUBYGEMS_DIR = __dir__
+ # Taint support is deprecated in Ruby 2.7.
+ # This allows switching ".untaint" to ".tap(&Gem::UNTAINT)",
+ # to avoid deprecation warnings in Ruby 2.7.
+ UNTAINT = RUBY_VERSION < "2.7" ? :untaint.to_sym : proc {}
+
##
# An Array of Regexps that match windows Ruby platforms.
@@ -180,8 +184,6 @@ module Gem
@discover_gems_on_require = true
- @target_rbconfig = nil
-
##
# Try to activate a gem containing +path+. Returns true if
# activation succeeded or wasn't needed because it was already
@@ -209,7 +211,7 @@ module Gem
end
end
- true
+ return true
end
def self.needs
@@ -337,6 +339,16 @@ module Gem
end
##
+ # The path to the data directory specified by the gem name. If the
+ # package is not available as a gem, return nil.
+
+ def self.datadir(gem_name)
+ spec = @loaded_specs[gem_name]
+ return nil if spec.nil?
+ spec.datadir
+ end
+
+ ##
# A Zlib::Deflate.deflate wrapper
def self.deflate(data)
@@ -400,23 +412,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
##
- # The RbConfig object for the deployment target platform.
- #
- # This is usually the same as the running platform, but may be
- # different if you are cross-compiling.
-
- def self.target_rbconfig
- @target_rbconfig || Gem::TargetRbConfig.for_running_ruby
- end
-
- def self.set_target_rbconfig(rbconfig_path)
- @target_rbconfig = Gem::TargetRbConfig.from_path(rbconfig_path)
- Gem::Platform.local(refresh: true)
- Gem.platforms << Gem::Platform.local unless Gem.platforms.include? Gem::Platform.local
- @target_rbconfig
- end
-
- ##
# Quietly ensure the Gem directory +dir+ contains all the proper
# subdirectories. If we can't create a directory due to a permission
# problem, then we will silently continue.
@@ -444,7 +439,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
def self.ensure_subdirectories(dir, mode, subdirs) # :nodoc:
old_umask = File.umask
- File.umask old_umask | 0o002
+ File.umask old_umask | 002
options = {}
@@ -470,7 +465,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# distinction as extensions cannot be shared between the two.
def self.extension_api_version # :nodoc:
- if target_rbconfig["ENABLE_SHARED"] == "no"
+ if "no" == RbConfig::CONFIG["ENABLE_SHARED"]
"#{ruby_api_version}-static"
else
ruby_api_version
@@ -504,14 +499,14 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# the spec dirs directly, so we prune.
files.uniq! if check_load_path
- files
+ return files
end
def self.find_files_from_load_path(glob) # :nodoc:
glob_with_suffixes = "#{glob}#{Gem.suffix_pattern}"
$LOAD_PATH.map do |load_path|
Gem::Util.glob_files_in_dir(glob_with_suffixes, load_path)
- end.flatten.select {|file| File.file? file }
+ end.flatten.select {|file| File.file? file.tap(&Gem::UNTAINT) }
end
##
@@ -539,7 +534,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# the spec dirs directly, so we prune.
files.uniq! if check_load_path
- files
+ return files
end
##
@@ -587,7 +582,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
##
# The number of paths in the +$LOAD_PATH+ from activated gems. Used to
- # prioritize +-I+ and <code>ENV['RUBYLIB']</code> entries during +require+.
+ # prioritize +-I+ and +ENV['RUBYLIB']+ entries during +require+.
def self.activated_gem_paths
@activated_gem_paths ||= 0
@@ -619,16 +614,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
@yaml_loaded = true
end
- @safe_marshal_loaded = false
-
- def self.load_safe_marshal
- return if @safe_marshal_loaded
-
- require_relative "rubygems/safe_marshal"
-
- @safe_marshal_loaded = true
- end
-
##
# The file name and line number of the caller of the caller of this method.
#
@@ -757,7 +742,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
if prefix != File.expand_path(RbConfig::CONFIG["sitelibdir"]) &&
prefix != File.expand_path(RbConfig::CONFIG["libdir"]) &&
- File.basename(RUBYGEMS_DIR) == "lib"
+ "lib" == File.basename(RUBYGEMS_DIR)
prefix
end
end
@@ -773,14 +758,21 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# Safely read a file in binary mode on all platforms.
def self.read_binary(path)
- File.binread(path)
+ open_file(path, "rb+") do |io|
+ io.read
+ end
+ rescue Errno::EACCES, Errno::EROFS
+ open_file(path, "rb") do |io|
+ io.read
+ end
end
##
# Safely write a file in binary mode on all platforms.
-
def self.write_binary(path, data)
- File.binwrite(path, data)
+ open_file(path, "wb") do |io|
+ io.write data
+ end
rescue Errno::ENOSPC
# If we ran out of space but the file exists, it's *guaranteed* to be corrupted.
File.delete(path) if File.exist?(path)
@@ -788,38 +780,26 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
##
- # Open a file with given flags
+ # Open a file with given flags, and on Windows protect access with flock
def self.open_file(path, flags, &block)
- File.open(path, flags, &block)
- end
-
- ##
- # Open a file with given flags, and protect access with a file lock
-
- def self.open_file_with_lock(path, &block)
- file_lock = "#{path}.lock"
- open_file_with_flock(file_lock, &block)
- ensure
- FileUtils.rm_f file_lock
- end
-
- ##
- # Open a file with given flags, and protect access with flock
-
- def self.open_file_with_flock(path, &block)
- mode = IO::RDONLY | IO::APPEND | IO::CREAT | IO::BINARY
- mode |= IO::SHARE_DELETE if IO.const_defined?(:SHARE_DELETE)
-
- File.open(path, mode) do |io|
- begin
- io.flock(File::LOCK_EX)
- rescue Errno::ENOSYS, Errno::ENOTSUP
- rescue Errno::ENOLCK # NFS
- raise unless Thread.main == Thread.current
+ File.open(path, flags) do |io|
+ if !java_platform? && win_platform?
+ begin
+ io.flock(File::LOCK_EX)
+ rescue Errno::ENOSYS, Errno::ENOTSUP
+ end
end
yield io
end
+ rescue Errno::ENOLCK # NFS
+ if Thread.main != Thread.current
+ raise
+ else
+ File.open(path, flags) do |io|
+ yield io
+ end
+ end
end
##
@@ -829,7 +809,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
if @ruby.nil?
@ruby = RbConfig.ruby
- @ruby = "\"#{@ruby}\"" if /\s/.match?(@ruby)
+ @ruby = "\"#{@ruby}\"" if @ruby =~ /\s/
end
@ruby
@@ -839,7 +819,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# Returns a String containing the API compatibility version of Ruby
def self.ruby_api_version
- @ruby_api_version ||= target_rbconfig["ruby_version"].dup
+ @ruby_api_version ||= RbConfig::CONFIG["ruby_version"].dup
end
def self.env_requirement(gem_name)
@@ -886,7 +866,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
return @ruby_version if defined? @ruby_version
version = RUBY_VERSION.dup
- if RUBY_PATCHLEVEL == -1
+ unless defined?(RUBY_PATCHLEVEL) && RUBY_PATCHLEVEL != -1
if RUBY_ENGINE == "ruby"
desc = RUBY_DESCRIPTION[/\Aruby #{Regexp.quote(RUBY_VERSION)}([^ ]+) /, 1]
else
@@ -934,7 +914,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# Glob pattern for require-able path suffixes.
def self.suffix_pattern
- @suffix_pattern ||= "{#{suffixes.join(",")}}"
+ @suffix_pattern ||= "{#{suffixes.join(',')}}"
end
##
@@ -968,14 +948,8 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
val = RbConfig::CONFIG[key]
next unless val && !val.empty?
".#{val}"
- end].compact.uniq
- end
-
- ##
- # Suffixes for dynamic library require-able paths.
-
- def self.dynamic_library_suffixes
- @dynamic_library_suffixes ||= suffixes - [".rb"]
+ end,
+ ].compact.uniq
end
##
@@ -989,7 +963,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
elapsed = Time.now - now
- ui.say format("%2$*1$s: %3$3.3fs", -width, msg, elapsed) if display
+ ui.say "%2$*1$s: %3$3.3fs" % [-width, msg, elapsed] if display
value
end
@@ -1021,7 +995,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
def self.win_platform?
if @@win_platform.nil?
ruby_platform = RbConfig::CONFIG["host_os"]
- @@win_platform = !WIN_PATTERNS.find {|r| ruby_platform =~ r }.nil?
+ @@win_platform = !!WIN_PATTERNS.find {|r| ruby_platform =~ r }
end
@@win_platform
@@ -1042,13 +1016,6 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
##
- # Is this platform FreeBSD
-
- def self.freebsd_platform?
- RbConfig::CONFIG["host_os"].to_s.include?("bsd")
- end
-
- ##
# Load +plugins+ as Ruby files
def self.load_plugin_files(plugins) # :nodoc:
@@ -1056,11 +1023,11 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# Skip older versions of the GemCutter plugin: Its commands are in
# RubyGems proper now.
- next if /gemcutter-0\.[0-3]/.match?(plugin)
+ next if plugin =~ /gemcutter-0\.[0-3]/
begin
load plugin
- rescue ScriptError, StandardError => e
+ rescue ::Exception => e
details = "#{plugin.inspect}: #{e.message} (#{e.class})"
warn "Error loading RubyGems plugin #{details}"
end
@@ -1122,6 +1089,8 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
end
end
+ path.tap(&Gem::UNTAINT)
+
unless File.file? path
return unless raise_exception
@@ -1133,11 +1102,13 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
require "bundler"
begin
Gem::DefaultUserInteraction.use_ui(ui) do
- Bundler.ui.silence do
- @gemdeps = Bundler.setup
+ begin
+ Bundler.ui.silence do
+ @gemdeps = Bundler.setup
+ end
+ ensure
+ Gem::DefaultUserInteraction.ui.close
end
- ensure
- Gem::DefaultUserInteraction.ui.close
end
rescue Bundler::BundlerError => e
warn e.message
@@ -1183,7 +1154,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
# This is used throughout RubyGems for enabling reproducible builds.
def self.source_date_epoch
- Time.at(source_date_epoch_string.to_i).utc.freeze
+ Time.at(self.source_date_epoch_string.to_i).utc.freeze
end
# FIX: Almost everywhere else we use the `def self.` way of defining class
@@ -1252,16 +1223,9 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
##
# Find a Gem::Specification of default gem from +path+
- def find_default_spec(path)
- @path_to_default_spec_map[path]
- end
-
- ##
- # Find an unresolved Gem::Specification of default gem from +path+
-
def find_unresolved_default_spec(path)
default_spec = @path_to_default_spec_map[path]
- default_spec if default_spec && loaded_specs[default_spec.name] != default_spec
+ return default_spec if default_spec && loaded_specs[default_spec.name] != default_spec
end
##
@@ -1337,10 +1301,9 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
##
# Location of Marshal quick gemspecs on remote repositories
- MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/".freeze
+ MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/"
autoload :ConfigFile, File.expand_path("rubygems/config_file", __dir__)
- autoload :CIDetector, File.expand_path("rubygems/ci_detector", __dir__)
autoload :Dependency, File.expand_path("rubygems/dependency", __dir__)
autoload :DependencyList, File.expand_path("rubygems/dependency_list", __dir__)
autoload :Installer, File.expand_path("rubygems/installer", __dir__)
@@ -1387,17 +1350,6 @@ begin
rescue LoadError
end
-# TruffleRuby >= 24 defines REUSE_AS_BINARY_ON_TRUFFLERUBY in defaults/truffleruby.
-# However, TruffleRuby < 24 defines REUSE_AS_BINARY_ON_TRUFFLERUBY directly in its copy
-# of lib/rubygems/platform.rb, so it is not defined if RubyGems is updated (gem update --system).
-# Instead, we define it here in that case, similar to bundler/lib/bundler/rubygems_ext.rb.
-# We must define it here and not in platform.rb because platform.rb is loaded before defaults/truffleruby.
-class Gem::Platform
- if RUBY_ENGINE == "truffleruby" && !defined?(REUSE_AS_BINARY_ON_TRUFFLERUBY)
- REUSE_AS_BINARY_ON_TRUFFLERUBY = %w[libv8 libv8-node sorbet-static].freeze
- end
-end
-
##
# Loads the default specs.
Gem::Specification.load_defaults
@@ -1407,7 +1359,7 @@ require_relative "rubygems/core_ext/kernel_gem"
path = File.join(__dir__, "rubygems/core_ext/kernel_require.rb")
# When https://bugs.ruby-lang.org/issues/17259 is available, there is no need to override Kernel#warn
if RUBY_ENGINE == "truffleruby" ||
- RUBY_ENGINE == "ruby"
+ (RUBY_ENGINE == "ruby" && RUBY_VERSION >= "3.0")
file = "<internal:#{path}>"
else
require_relative "rubygems/core_ext/kernel_warn"
diff --git a/lib/rubygems/available_set.rb b/lib/rubygems/available_set.rb
index 0af80cc3db..2ab3e137da 100644
--- a/lib/rubygems/available_set.rb
+++ b/lib/rubygems/available_set.rb
@@ -27,7 +27,7 @@ class Gem::AvailableSet
s = o.set
when Array
s = o.map do |sp,so|
- if !sp.is_a?(Gem::Specification) || !so.is_a?(Gem::Source)
+ if !sp.kind_of?(Gem::Specification) || !so.kind_of?(Gem::Source)
raise TypeError, "Array must be in [[spec, source], ...] form"
end
@@ -70,7 +70,7 @@ class Gem::AvailableSet
end
def all_specs
- @set.map(&:spec)
+ @set.map {|t| t.spec }
end
def match_platform!
@@ -105,14 +105,14 @@ class Gem::AvailableSet
def to_request_set(development = :none)
request_set = Gem::RequestSet.new
- request_set.development = development == :all
+ request_set.development = :all == development
each_spec do |spec|
request_set.always_install << spec
request_set.gem spec.name, spec.version
request_set.import spec.development_dependencies if
- development == :shallow
+ :shallow == development
end
request_set
@@ -147,7 +147,7 @@ class Gem::AvailableSet
end
def remove_installed!(dep)
- @set.reject! do |_t|
+ @set.reject! do |t|
# already locally installed
Gem::Specification.any? do |installed_spec|
dep.name == installed_spec.name &&
diff --git a/lib/rubygems/basic_specification.rb b/lib/rubygems/basic_specification.rb
index 204231e95e..5d198114e0 100644
--- a/lib/rubygems/basic_specification.rb
+++ b/lib/rubygems/basic_specification.rb
@@ -76,21 +76,15 @@ class Gem::BasicSpecification
elsif missing_extensions?
@ignored = true
- if platform == Gem::Platform::RUBY || Gem::Platform.local === platform
- warn "Ignoring #{full_name} because its extensions are not built. " \
+ if Gem::Platform::RUBY == platform || Gem::Platform.local === platform
+ warn "Ignoring #{full_name} because its extensions are not built. " +
"Try: gem pristine #{name} --version #{version}"
end
return false
end
- is_soext = file.end_with?(".so", ".o")
-
- if is_soext
- have_file? file.delete_suffix(File.extname(file)), Gem.dynamic_library_suffixes
- else
- have_file? file, Gem.suffixes
- end
+ have_file? file, Gem.suffixes
end
def default_gem?
@@ -99,24 +93,10 @@ class Gem::BasicSpecification
end
##
- # Regular gems take precedence over default gems
-
- def default_gem_priority
- default_gem? ? 1 : -1
- end
-
- ##
- # Gems higher up in +gem_path+ take precedence
-
- def base_dir_priority(gem_path)
- gem_path.index(base_dir) || gem_path.size
- end
-
- ##
# Returns full path to the directory where gem's extensions are installed.
def extension_dir
- @extension_dir ||= File.expand_path(File.join(extensions_dir, full_name))
+ @extension_dir ||= File.expand_path(File.join(extensions_dir, full_name)).tap(&Gem::UNTAINT)
end
##
@@ -129,17 +109,20 @@ class Gem::BasicSpecification
end
def find_full_gem_path # :nodoc:
- File.expand_path File.join(gems_dir, full_name)
+ # TODO: also, shouldn't it default to full_name if it hasn't been written?
+ path = File.expand_path File.join(gems_dir, full_name)
+ path.tap(&Gem::UNTAINT)
+ path
end
private :find_full_gem_path
##
# The full path to the gem (install path + full name).
- #
- # TODO: This is duplicated with #gem_dir. Eventually either of them should be deprecated.
def full_gem_path
+ # TODO: This is a heavily used method by gems, so we'll need
+ # to aleast just alias it to #gem_dir rather than remove it.
@full_gem_path ||= find_full_gem_path
end
@@ -150,22 +133,9 @@ class Gem::BasicSpecification
def full_name
if platform == Gem::Platform::RUBY || platform.nil?
- "#{name}-#{version}"
+ "#{name}-#{version}".dup.tap(&Gem::UNTAINT)
else
- "#{name}-#{version}-#{platform}"
- end
- end
-
- ##
- # Returns the full name of this Gem (see `Gem::BasicSpecification#full_name`).
- # Information about where the gem is installed is also included if not
- # installed in the default GEM_HOME.
-
- def full_name_with_location
- if base_dir != Gem.dir
- "#{full_name} in #{base_dir}"
- else
- full_name
+ "#{name}-#{version}-#{platform}".dup.tap(&Gem::UNTAINT)
end
end
@@ -175,15 +145,15 @@ class Gem::BasicSpecification
def full_require_paths
@full_require_paths ||=
- begin
- full_paths = raw_require_paths.map do |path|
- File.join full_gem_path, path
- end
+ begin
+ full_paths = raw_require_paths.map do |path|
+ File.join full_gem_path, path.tap(&Gem::UNTAINT)
+ end
- full_paths << extension_dir if have_extensions?
+ full_paths << extension_dir if have_extensions?
- full_paths
- end
+ full_paths
+ end
end
##
@@ -191,7 +161,7 @@ class Gem::BasicSpecification
def datadir
# TODO: drop the extra ", gem_name" which is uselessly redundant
- File.expand_path(File.join(gems_dir, full_name, "data", name))
+ File.expand_path(File.join(gems_dir, full_name, "data", name)).tap(&Gem::UNTAINT)
end
##
@@ -201,25 +171,27 @@ class Gem::BasicSpecification
def to_fullpath(path)
if activated?
@paths_map ||= {}
- Gem.suffixes.each do |suf|
- full_require_paths.each do |dir|
- fullpath = "#{dir}/#{path}#{suf}"
- next unless File.file?(fullpath)
- @paths_map[path] ||= fullpath
- end
+ @paths_map[path] ||=
+ begin
+ fullpath = nil
+ suffixes = Gem.suffixes
+ suffixes.find do |suf|
+ full_require_paths.find do |dir|
+ File.file?(fullpath = "#{dir}/#{path}#{suf}")
+ end
+ end ? fullpath : nil
end
- @paths_map[path]
+ else
+ nil
end
end
##
# Returns the full path to this spec's gem directory.
# eg: /usr/local/lib/ruby/1.8/gems/mygem-1.0
- #
- # TODO: This is duplicated with #full_gem_path. Eventually either of them should be deprecated.
def gem_dir
- @gem_dir ||= find_full_gem_path
+ @gem_dir ||= File.expand_path File.join(gems_dir, full_name)
end
##
@@ -300,9 +272,9 @@ class Gem::BasicSpecification
# Return all files in this gem that match for +glob+.
def matches_for_glob(glob) # TODO: rename?
- glob = File.join(lib_dirs_glob, glob)
+ glob = File.join(self.lib_dirs_glob, glob)
- Dir[glob]
+ Dir[glob].map {|f| f.tap(&Gem::UNTAINT) } # FIX our tests are broken, run w/ SAFE=1
end
##
@@ -317,17 +289,17 @@ class Gem::BasicSpecification
# for this spec.
def lib_dirs_glob
- dirs = if raw_require_paths
- if raw_require_paths.size > 1
- "{#{raw_require_paths.join(",")}}"
+ dirs = if self.raw_require_paths
+ if self.raw_require_paths.size > 1
+ "{#{self.raw_require_paths.join(',')}}"
else
- raw_require_paths.first
+ self.raw_require_paths.first
end
else
"lib" # default value for require_paths for bundler/inline
end
- "#{full_gem_path}/#{dirs}"
+ "#{self.full_gem_path}/#{dirs}".dup.tap(&Gem::UNTAINT)
end
##
@@ -352,19 +324,15 @@ class Gem::BasicSpecification
raise NotImplementedError
end
- def this
- self
- end
+ def this; self; end
private
- def have_extensions?
- !extensions.empty?
- end
+ def have_extensions?; !extensions.empty?; end
def have_file?(file, suffixes)
return true if raw_require_paths.any? do |path|
- base = File.join(gems_dir, full_name, path, file)
+ base = File.join(gems_dir, full_name, path.tap(&Gem::UNTAINT), file).tap(&Gem::UNTAINT)
suffixes.any? {|suf| File.file? base + suf }
end
diff --git a/lib/rubygems/bundler_version_finder.rb b/lib/rubygems/bundler_version_finder.rb
index 4ebbad1c0c..5b34227d3a 100644
--- a/lib/rubygems/bundler_version_finder.rb
+++ b/lib/rubygems/bundler_version_finder.rb
@@ -21,7 +21,7 @@ module Gem::BundlerVersionFinder
end
def self.bundle_update_bundler_version
- return unless ["bundle", "bundler"].include? File.basename($0)
+ return unless File.basename($0) == "bundle"
return unless "update".start_with?(ARGV.first || " ")
bundler_version = nil
update_index = nil
@@ -52,7 +52,7 @@ module Gem::BundlerVersionFinder
unless gemfile
begin
Gem::Util.traverse_parents(Dir.pwd) do |directory|
- next unless gemfile = Gem::GEM_DEP_FILES.find {|f| File.file?(f) }
+ next unless gemfile = Gem::GEM_DEP_FILES.find {|f| File.file?(f.tap(&Gem::UNTAINT)) }
gemfile = File.join directory, gemfile
break
@@ -65,9 +65,9 @@ module Gem::BundlerVersionFinder
return unless gemfile
lockfile = case gemfile
- when "gems.rb" then "gems.locked"
- else "#{gemfile}.lock"
- end
+ when "gems.rb" then "gems.locked"
+ else "#{gemfile}.lock"
+ end.dup.tap(&Gem::UNTAINT)
return unless File.file?(lockfile)
diff --git a/lib/rubygems/ci_detector.rb b/lib/rubygems/ci_detector.rb
deleted file mode 100644
index 7a2d4ee29a..0000000000
--- a/lib/rubygems/ci_detector.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# frozen_string_literal: true
-
-module Gem
- module CIDetector
- # NOTE: Any changes made here will need to be made to both lib/rubygems/ci_detector.rb and
- # bundler/lib/bundler/ci_detector.rb (which are enforced duplicates).
- # TODO: Drop that duplication once bundler drops support for RubyGems 3.4
- #
- # ## Recognized CI providers, their signifiers, and the relevant docs ##
- #
- # Travis CI - CI, TRAVIS https://docs.travis-ci.com/user/environment-variables/#default-environment-variables
- # Cirrus CI - CI, CIRRUS_CI https://cirrus-ci.org/guide/writing-tasks/#environment-variables
- # Circle CI - CI, CIRCLECI https://circleci.com/docs/variables/#built-in-environment-variables
- # Gitlab CI - CI, GITLAB_CI https://docs.gitlab.com/ee/ci/variables/
- # AppVeyor - CI, APPVEYOR https://www.appveyor.com/docs/environment-variables/
- # CodeShip - CI_NAME https://docs.cloudbees.com/docs/cloudbees-codeship/latest/pro-builds-and-configuration/environment-variables#_default_environment_variables
- # dsari - CI, DSARI https://github.com/rfinnie/dsari#running
- # Jenkins - BUILD_NUMBER https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables
- # TeamCity - TEAMCITY_VERSION https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Predefined+Server+Build+Parameters
- # Appflow - CI_BUILD_ID https://ionic.io/docs/appflow/automation/environments#predefined-environments
- # TaskCluster - TASKCLUSTER_ROOT_URL https://docs.taskcluster.net/docs/manual/design/env-vars
- # Semaphore - CI, SEMAPHORE https://docs.semaphoreci.com/ci-cd-environment/environment-variables/
- # BuildKite - CI, BUILDKITE https://buildkite.com/docs/pipelines/environment-variables
- # GoCD - GO_SERVER_URL https://docs.gocd.org/current/faq/dev_use_current_revision_in_build.html
- # GH Actions - CI, GITHUB_ACTIONS https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
- #
- # ### Some "standard" ENVs that multiple providers may set ###
- #
- # * CI - this is set by _most_ (but not all) CI providers now; it's approaching a standard.
- # * CI_NAME - Not as frequently used, but some providers set this to specify their own name
-
- # Any of these being set is a reasonably reliable indicator that we are
- # executing in a CI environment.
- ENV_INDICATORS = [
- "CI",
- "CI_NAME",
- "CONTINUOUS_INTEGRATION",
- "BUILD_NUMBER",
- "CI_APP_ID",
- "CI_BUILD_ID",
- "CI_BUILD_NUMBER",
- "RUN_ID",
- "TASKCLUSTER_ROOT_URL",
- ].freeze
-
- # For each CI, this env suffices to indicate that we're on _that_ CI's
- # containers. (A few of them only supply a CI_NAME variable, which is also
- # nice). And if they set "CI" but we can't tell which one they are, we also
- # want to know that - a bare "ci" without another token tells us as much.
- ENV_DESCRIPTORS = {
- "TRAVIS" => "travis",
- "CIRCLECI" => "circle",
- "CIRRUS_CI" => "cirrus",
- "DSARI" => "dsari",
- "SEMAPHORE" => "semaphore",
- "JENKINS_URL" => "jenkins",
- "BUILDKITE" => "buildkite",
- "GO_SERVER_URL" => "go",
- "GITLAB_CI" => "gitlab",
- "GITHUB_ACTIONS" => "github",
- "TASKCLUSTER_ROOT_URL" => "taskcluster",
- "CI" => "ci",
- }.freeze
-
- def self.ci?
- ENV_INDICATORS.any? {|var| ENV.include?(var) }
- end
-
- def self.ci_strings
- matching_names = ENV_DESCRIPTORS.select {|env, _| ENV[env] }.values
- matching_names << ENV["CI_NAME"].downcase if ENV["CI_NAME"]
- matching_names.reject(&:empty?).sort.uniq
- end
- end
-end
diff --git a/lib/rubygems/command.rb b/lib/rubygems/command.rb
index ec498a8b94..07cf4e0e81 100644
--- a/lib/rubygems/command.rb
+++ b/lib/rubygems/command.rb
@@ -6,7 +6,7 @@
# See LICENSE.txt for permissions.
#++
-require_relative "vendored_optparse"
+require_relative "optparse"
require_relative "requirement"
require_relative "user_interaction"
@@ -20,7 +20,9 @@ require_relative "user_interaction"
class Gem::Command
include Gem::UserInteraction
- Gem::OptionParser.accept Symbol, &:to_sym
+ Gem::OptionParser.accept Symbol do |value|
+ value.to_sym
+ end
##
# The name of the command.
@@ -92,7 +94,7 @@ class Gem::Command
# array or a string to be split on white space.
def self.add_specific_extra_args(cmd,args)
- args = args.split(/\s+/) if args.is_a? String
+ args = args.split(/\s+/) if args.kind_of? String
specific_extra_args_hash[cmd] = args
end
@@ -190,7 +192,7 @@ class Gem::Command
"Please specify at least one gem name (e.g. gem build GEMNAME)"
end
- args.reject {|arg| arg.start_with?("-") }
+ args.select {|arg| arg !~ /^-/ }
end
##
@@ -226,7 +228,7 @@ class Gem::Command
if args.size > 1
raise Gem::CommandLineError,
- "Too many gem names (#{args.join(", ")}); please specify only one"
+ "Too many gem names (#{args.join(', ')}); please specify only one"
end
args.first
@@ -314,7 +316,7 @@ class Gem::Command
options[:build_args] = build_args
if options[:silent]
- old_ui = ui
+ old_ui = self.ui
self.ui = ui = Gem::SilentUI.new
end
@@ -396,21 +398,22 @@ class Gem::Command
def check_deprecated_options(options)
options.each do |option|
- next unless option_is_deprecated?(option)
- deprecation = @deprecated_options[command][option]
- version_to_expire = deprecation["rg_version_to_expire"]
+ if option_is_deprecated?(option)
+ deprecation = @deprecated_options[command][option]
+ version_to_expire = deprecation["rg_version_to_expire"]
- deprecate_option_msg = if version_to_expire
- "The \"#{option}\" option has been deprecated and will be removed in Rubygems #{version_to_expire}."
- else
- "The \"#{option}\" option has been deprecated and will be removed in future versions of Rubygems."
- end
+ deprecate_option_msg = if version_to_expire
+ "The \"#{option}\" option has been deprecated and will be removed in Rubygems #{version_to_expire}."
+ else
+ "The \"#{option}\" option has been deprecated and will be removed in future versions of Rubygems."
+ end
- extra_msg = deprecation["extra_msg"]
+ extra_msg = deprecation["extra_msg"]
- deprecate_option_msg += " #{extra_msg}" if extra_msg
+ deprecate_option_msg += " #{extra_msg}" if extra_msg
- alert_warning(deprecate_option_msg)
+ alert_warning(deprecate_option_msg)
+ end
end
end
@@ -427,10 +430,12 @@ class Gem::Command
# True if the command handles the given argument list.
def handles?(args)
- parser.parse!(args.dup)
- true
- rescue StandardError
- false
+ begin
+ parser.parse!(args.dup)
+ return true
+ rescue
+ return false
+ end
end
##
@@ -457,7 +462,7 @@ class Gem::Command
until extra.empty? do
ex = []
ex << extra.shift
- ex << extra.shift if /^[^-]/.match?(extra.first.to_s)
+ ex << extra.shift if extra.first.to_s =~ /^[^-]/ # rubocop:disable Performance/StartWith
result << ex if handles?(ex)
end
@@ -473,7 +478,7 @@ class Gem::Command
private
def option_is_deprecated?(option)
- @deprecated_options[command].key?(option)
+ @deprecated_options[command].has_key?(option)
end
def add_parser_description # :nodoc:
@@ -485,7 +490,7 @@ class Gem::Command
@parser.separator nil
@parser.separator " Description:"
- formatted.each_line do |line|
+ formatted.split("\n").each do |line|
@parser.separator " #{line.rstrip}"
end
end
@@ -512,8 +517,8 @@ class Gem::Command
@parser.separator nil
@parser.separator " #{title}:"
- content.each_line do |line|
- @parser.separator " #{line.rstrip}"
+ content.split(/\n/).each do |line|
+ @parser.separator " #{line}"
end
end
@@ -522,7 +527,7 @@ class Gem::Command
@parser.separator nil
@parser.separator " Summary:"
- wrap(@summary, 80 - 4).each_line do |line|
+ wrap(@summary, 80 - 4).split("\n").each do |line|
@parser.separator " #{line.strip}"
end
end
@@ -579,12 +584,12 @@ class Gem::Command
# Add the options common to all commands.
add_common_option("-h", "--help",
- "Get help on this command") do |_value, options|
+ "Get help on this command") do |value, options|
options[:help] = true
end
add_common_option("-V", "--[no-]verbose",
- "Set the verbose level of output") do |value, _options|
+ "Set the verbose level of output") do |value, options|
# Set us to "really verbose" so the progress meter works
if Gem.configuration.verbose && value
Gem.configuration.verbose = 1
@@ -593,12 +598,12 @@ class Gem::Command
end
end
- add_common_option("-q", "--quiet", "Silence command progress meter") do |_value, _options|
+ add_common_option("-q", "--quiet", "Silence command progress meter") do |value, options|
Gem.configuration.verbose = false
end
add_common_option("--silent",
- "Silence RubyGems output") do |_value, options|
+ "Silence RubyGems output") do |value, options|
options[:silent] = true
end
diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb
index 4d54d1d49d..b3913d465a 100644
--- a/lib/rubygems/command_manager.rb
+++ b/lib/rubygems/command_manager.rb
@@ -60,7 +60,6 @@ class Gem::CommandManager
:push,
:query,
:rdoc,
- :rebuild,
:search,
:server,
:signin,
@@ -107,7 +106,7 @@ class Gem::CommandManager
# Register all the subcommands supported by the gem command.
def initialize
- require_relative "vendored_timeout"
+ require "timeout"
@commands = {}
BUILTIN_COMMANDS.each do |name|
@@ -142,7 +141,7 @@ class Gem::CommandManager
# Return a sorted list of all command names as strings.
def command_names
- @commands.keys.collect(&:to_s).sort
+ @commands.keys.collect {|key| key.to_s }.sort
end
##
@@ -150,7 +149,7 @@ class Gem::CommandManager
def run(args, build_args=nil)
process_args(args, build_args)
- rescue StandardError, Gem::Timeout::Error => ex
+ rescue StandardError, Timeout::Error => ex
if ex.respond_to?(:detailed_message)
msg = ex.detailed_message(highlight: false).sub(/\A(.*?)(?: \(.+?\))/) { $1 }
else
@@ -202,7 +201,7 @@ class Gem::CommandManager
if possibilities.size > 1
raise Gem::CommandLineError,
- "Ambiguous command #{cmd_name} matches [#{possibilities.join(", ")}]"
+ "Ambiguous command #{cmd_name} matches [#{possibilities.join(', ')}]"
elsif possibilities.empty?
raise Gem::UnknownCommandError.new(cmd_name)
end
@@ -230,11 +229,18 @@ class Gem::CommandManager
def load_and_instantiate(command_name)
command_name = command_name.to_s
const_name = command_name.capitalize.gsub(/_(.)/) { $1.upcase } << "Command"
+ load_error = nil
begin
- require "rubygems/commands/#{command_name}_command"
+ begin
+ require "rubygems/commands/#{command_name}_command"
+ rescue LoadError => e
+ load_error = e
+ end
Gem::Commands.const_get(const_name).new
- rescue StandardError, LoadError => e
+ rescue Exception => e
+ e = load_error if load_error
+
alert_error clean_text("Loading command: #{command_name} (#{e.class})\n\t#{e}")
ui.backtrace e
end
@@ -243,7 +249,6 @@ class Gem::CommandManager
def invoke_command(args, build_args)
cmd_name = args.shift.downcase
cmd = find_command cmd_name
- terminate_interaction 1 unless cmd
cmd.deprecation_warning if cmd.deprecated?
cmd.invoke_with_build_args args, build_args
end
diff --git a/lib/rubygems/commands/build_command.rb b/lib/rubygems/commands/build_command.rb
index 2ec8324141..68e020d94a 100644
--- a/lib/rubygems/commands/build_command.rb
+++ b/lib/rubygems/commands/build_command.rb
@@ -1,24 +1,22 @@
# frozen_string_literal: true
require_relative "../command"
-require_relative "../gemspec_helpers"
require_relative "../package"
require_relative "../version_option"
class Gem::Commands::BuildCommand < Gem::Command
include Gem::VersionOption
- include Gem::GemspecHelpers
def initialize
super "build", "Build a gem from a gemspec"
add_platform_option
- add_option "--force", "skip validation of the spec" do |_value, options|
+ add_option "--force", "skip validation of the spec" do |value, options|
options[:force] = true
end
- add_option "--strict", "consider warnings as errors when validating the spec" do |_value, options|
+ add_option "--strict", "consider warnings as errors when validating the spec" do |value, options|
options[:strict] = true
end
@@ -77,6 +75,17 @@ Gems can be saved to a specified filename with the output option:
private
+ def find_gemspec(glob = "*.gemspec")
+ gemspecs = Dir.glob(glob).sort
+
+ if gemspecs.size > 1
+ alert_error "Multiple gemspecs found: #{gemspecs}, please specify one"
+ terminate_interaction(1)
+ end
+
+ gemspecs.first
+ end
+
def build_gem
gemspec = resolve_gem_name
diff --git a/lib/rubygems/commands/cert_command.rb b/lib/rubygems/commands/cert_command.rb
index 72dcf1dd17..344f31fba9 100644
--- a/lib/rubygems/commands/cert_command.rb
+++ b/lib/rubygems/commands/cert_command.rb
@@ -6,7 +6,7 @@ require_relative "../security"
class Gem::Commands::CertCommand < Gem::Command
def initialize
super "cert", "Manage RubyGems certificates and signing settings",
- add: [], remove: [], list: [], build: [], sign: []
+ :add => [], :remove => [], :list => [], :build => [], :sign => []
add_option("-a", "--add CERT",
"Add a trusted certificate.") do |cert_file, options|
@@ -136,7 +136,7 @@ class Gem::Commands::CertCommand < Gem::Command
end
def build(email)
- unless valid_email?(email)
+ if !valid_email?(email)
raise Gem::CommandLineError, "Invalid email address #{email}"
end
@@ -178,9 +178,9 @@ class Gem::Commands::CertCommand < Gem::Command
algorithm = options[:key_algorithm] || Gem::Security::DEFAULT_KEY_ALGORITHM
key = Gem::Security.create_key(algorithm)
- key_path = Gem::Security.write key, "gem-private_key.pem", 0o600, passphrase
+ key_path = Gem::Security.write key, "gem-private_key.pem", 0600, passphrase
- [key, key_path]
+ return key, key_path
end
def certificates_matching(filter)
@@ -263,6 +263,7 @@ For further reading on signing gems see `ri Gem::Security`.
key = File.read key_file
passphrase = ENV["GEM_PRIVATE_KEY_PASSPHRASE"]
options[:key] = OpenSSL::PKey.read key, passphrase
+
rescue Errno::ENOENT
alert_error \
"--private-key not specified and ~/.gem/gem-private_key.pem does not exist"
@@ -291,7 +292,7 @@ For further reading on signing gems see `ri Gem::Security`.
cert = File.read cert_file
cert = OpenSSL::X509::Certificate.new cert
- permissions = File.stat(cert_file).mode & 0o777
+ permissions = File.stat(cert_file).mode & 0777
issuer_cert = options[:issuer_cert]
issuer_key = options[:key]
diff --git a/lib/rubygems/commands/check_command.rb b/lib/rubygems/commands/check_command.rb
index fb23dd9cb4..b300b4f87a 100644
--- a/lib/rubygems/commands/check_command.rb
+++ b/lib/rubygems/commands/check_command.rb
@@ -10,7 +10,7 @@ class Gem::Commands::CheckCommand < Gem::Command
def initialize
super "check", "Check a gem repository for added or missing files",
- alien: true, doctor: false, dry_run: false, gems: true
+ :alien => true, :doctor => false, :dry_run => false, :gems => true
add_option("-a", "--[no-]alien",
'Report "unmanaged" or rogue files in the',
@@ -41,21 +41,17 @@ class Gem::Commands::CheckCommand < Gem::Command
def check_gems
say "Checking gems..."
say
- gems = begin
- get_all_gem_names
- rescue StandardError
- []
- end
+ gems = get_all_gem_names rescue []
Gem::Validator.new.alien(gems).sort.each do |key, val|
- if val.empty?
- say "#{key} is error-free" if Gem.configuration.verbose
- else
+ unless val.empty?
say "#{key} has #{val.size} problems"
val.each do |error_entry|
say " #{error_entry.path}:"
say " #{error_entry.problem}"
end
+ else
+ say "#{key} is error-free" if Gem.configuration.verbose
end
say
end
diff --git a/lib/rubygems/commands/cleanup_command.rb b/lib/rubygems/commands/cleanup_command.rb
index bc24aaf753..ee5e1252b6 100644
--- a/lib/rubygems/commands/cleanup_command.rb
+++ b/lib/rubygems/commands/cleanup_command.rb
@@ -8,16 +8,16 @@ class Gem::Commands::CleanupCommand < Gem::Command
def initialize
super "cleanup",
"Clean up old versions of installed gems",
- force: false, install_dir: Gem.dir,
- check_dev: true
+ :force => false, :install_dir => Gem.dir,
+ :check_dev => true
add_option("-n", "-d", "--dry-run",
- "Do not uninstall gems") do |_value, options|
+ "Do not uninstall gems") do |value, options|
options[:dryrun] = true
end
add_option(:Deprecated, "--dryrun",
- "Do not uninstall gems") do |_value, options|
+ "Do not uninstall gems") do |value, options|
options[:dryrun] = true
end
deprecate_option("--dryrun", extra_msg: "Use --dry-run instead")
@@ -38,6 +38,8 @@ class Gem::Commands::CleanupCommand < Gem::Command
@default_gems = []
@full = nil
@gems_to_cleanup = nil
+ @original_home = nil
+ @original_path = nil
@primary_gems = nil
end
@@ -73,7 +75,7 @@ If no gems are named all gems in GEM_HOME are cleaned.
until done do
clean_gems
- this_set = @gems_to_cleanup.map(&:full_name).sort
+ this_set = @gems_to_cleanup.map {|spec| spec.full_name }.sort
done = this_set.empty? || last_set == this_set
@@ -86,13 +88,16 @@ If no gems are named all gems in GEM_HOME are cleaned.
say "Clean up complete"
verbose do
- skipped = @default_gems.map(&:full_name)
+ skipped = @default_gems.map {|spec| spec.full_name }
- "Skipped default gems: #{skipped.join ", "}"
+ "Skipped default gems: #{skipped.join ', '}"
end
end
def clean_gems
+ @original_home = Gem.dir
+ @original_path = Gem.path
+
get_primary_gems
get_candidate_gems
get_gems_to_cleanup
@@ -107,15 +112,17 @@ If no gems are named all gems in GEM_HOME are cleaned.
deps.reverse_each do |spec|
uninstall_dep spec
end
+
+ Gem::Specification.reset
end
def get_candidate_gems
- @candidate_gems = if options[:args].empty?
- Gem::Specification.to_a
- else
+ @candidate_gems = unless options[:args].empty?
options[:args].map do |gem_name|
Gem::Specification.find_all_by_name gem_name
end.flatten
+ else
+ Gem::Specification.to_a
end
end
@@ -124,9 +131,11 @@ If no gems are named all gems in GEM_HOME are cleaned.
@primary_gems[spec.name].version != spec.version
end
- default_gems, gems_to_cleanup = gems_to_cleanup.partition(&:default_gem?)
+ default_gems, gems_to_cleanup = gems_to_cleanup.partition do |spec|
+ spec.default_gem?
+ end
- uninstall_from = options[:user_install] ? Gem.user_dir : Gem.dir
+ uninstall_from = options[:user_install] ? Gem.user_dir : @original_home
gems_to_cleanup = gems_to_cleanup.select do |spec|
spec.base_dir == uninstall_from
@@ -159,8 +168,8 @@ If no gems are named all gems in GEM_HOME are cleaned.
say "Attempting to uninstall #{spec.full_name}"
uninstall_options = {
- executables: false,
- version: "= #{spec.version}",
+ :executables => false,
+ :version => "= #{spec.version}",
}
uninstall_options[:user_install] = Gem.user_dir == spec.base_dir
@@ -174,5 +183,8 @@ If no gems are named all gems in GEM_HOME are cleaned.
say "Unable to uninstall #{spec.full_name}:"
say "\t#{e.class}: #{e.message}"
end
+ ensure
+ # Restore path Gem::Uninstaller may have changed
+ Gem.use_paths @original_home, *@original_path
end
end
diff --git a/lib/rubygems/commands/contents_command.rb b/lib/rubygems/commands/contents_command.rb
index 807158d9c9..f378441ca4 100644
--- a/lib/rubygems/commands/contents_command.rb
+++ b/lib/rubygems/commands/contents_command.rb
@@ -8,8 +8,8 @@ class Gem::Commands::ContentsCommand < Gem::Command
def initialize
super "contents", "Display the contents of the installed gems",
- specdirs: [], lib_only: false, prefix: true,
- show_install_dir: false
+ :specdirs => [], :lib_only => false, :prefix => true,
+ :show_install_dir => false
add_version_option
@@ -92,9 +92,9 @@ prefix or only the files that are requireable.
def files_in_gem(spec)
gem_path = spec.full_gem_path
- extra = "/{#{spec.require_paths.join ","}}" if options[:lib_only]
+ extra = "/{#{spec.require_paths.join ','}}" if options[:lib_only]
glob = "#{gem_path}#{extra}/**/*"
- prefix_re = %r{#{Regexp.escape(gem_path)}/}
+ prefix_re = /#{Regexp.escape(gem_path)}\//
Dir[glob].map do |file|
[gem_path, file.sub(prefix_re, "")]
@@ -104,7 +104,7 @@ prefix or only the files that are requireable.
def files_in_default_gem(spec)
spec.files.map do |file|
case file
- when %r{\A#{spec.bindir}/}
+ when /\A#{spec.bindir}\//
# $' is POSTMATCH
[RbConfig::CONFIG["bindir"], $']
when /\.so\z/
@@ -178,7 +178,7 @@ prefix or only the files that are requireable.
@spec_dirs.sort.each {|dir| say dir }
end
- nil
+ return nil
end
def specification_directories # :nodoc:
diff --git a/lib/rubygems/commands/dependency_command.rb b/lib/rubygems/commands/dependency_command.rb
index 9aaefae999..cef98e30d3 100644
--- a/lib/rubygems/commands/dependency_command.rb
+++ b/lib/rubygems/commands/dependency_command.rb
@@ -11,14 +11,15 @@ class Gem::Commands::DependencyCommand < Gem::Command
def initialize
super "dependency",
"Show the dependencies of an installed gem",
- version: Gem::Requirement.default, domain: :local
+ :version => Gem::Requirement.default, :domain => :local
add_version_option
add_platform_option
add_prerelease_option
add_option("-R", "--[no-]reverse-dependencies",
- "Include reverse dependencies in the output") do |value, options|
+ "Include reverse dependencies in the output") do
+ |value, options|
options[:reverse_dependencies] = value
end
@@ -90,9 +91,10 @@ use with other commands.
def display_pipe(specs) # :nodoc:
specs.each do |spec|
- next if spec.dependencies.empty?
- spec.dependencies.sort_by(&:name).each do |dep|
- say "#{dep.name} --version '#{dep.requirement}'"
+ unless spec.dependencies.empty?
+ spec.dependencies.sort_by {|dep| dep.name }.each do |dep|
+ say "#{dep.name} --version '#{dep.requirement}'"
+ end
end
end
end
@@ -152,7 +154,7 @@ use with other commands.
response = String.new
response << " " * level + "Gem #{spec.full_name}\n"
unless spec.dependencies.empty?
- spec.dependencies.sort_by(&:name).each do |dep|
+ spec.dependencies.sort_by {|dep| dep.name }.each do |dep|
response << " " * level + " #{dep}\n"
end
end
diff --git a/lib/rubygems/commands/environment_command.rb b/lib/rubygems/commands/environment_command.rb
index 8ed0996069..28dbf93c50 100644
--- a/lib/rubygems/commands/environment_command.rb
+++ b/lib/rubygems/commands/environment_command.rb
@@ -17,7 +17,7 @@ class Gem::Commands::EnvironmentCommand < Gem::Command
platform display the supported gem platforms
<omitted> display everything
EOF
- args.gsub(/^\s+/, "")
+ return args.gsub(/^\s+/, "")
end
def description # :nodoc:
@@ -108,7 +108,9 @@ lib/rubygems/defaults/operating_system.rb
out << " - RUBYGEMS VERSION: #{Gem::VERSION}\n"
- out << " - RUBY VERSION: #{RUBY_VERSION} (#{RUBY_RELEASE_DATE} patchlevel #{RUBY_PATCHLEVEL}) [#{RUBY_PLATFORM}]\n"
+ out << " - RUBY VERSION: #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}"
+ out << " patchlevel #{RUBY_PATCHLEVEL}" if defined? RUBY_PATCHLEVEL
+ out << ") [#{RUBY_PLATFORM}]\n"
out << " - INSTALLATION DIRECTORY: #{Gem.dir}\n"
@@ -171,6 +173,6 @@ lib/rubygems/defaults/operating_system.rb
end
end
- nil
+ return nil
end
end
diff --git a/lib/rubygems/commands/exec_command.rb b/lib/rubygems/commands/exec_command.rb
index 7985b0fda6..383c8c5b37 100644
--- a/lib/rubygems/commands/exec_command.rb
+++ b/lib/rubygems/commands/exec_command.rb
@@ -23,7 +23,7 @@ class Gem::Commands::ExecCommand < Gem::Command
add_option(:"Install/Update", "--conservative",
"Prefer the most recent installed version, ",
- "rather than the latest version overall") do |_value, options|
+ "rather than the latest version overall") do |value, options|
options[:conservative] = true
end
end
@@ -57,6 +57,8 @@ to the same gem path as user-installed gems.
end
def execute
+ gem_paths = { "GEM_HOME" => Gem.paths.home, "GEM_PATH" => Gem.paths.path.join(File::PATH_SEPARATOR), "GEM_SPEC_CACHE" => Gem.paths.spec_cache_dir }.compact
+
check_executable
print_command
@@ -72,6 +74,9 @@ to the same gem path as user-installed gems.
end
load!
+ ensure
+ ENV.update(gem_paths) if gem_paths
+ Gem.clear_paths
end
private
@@ -138,7 +143,7 @@ to the same gem path as user-installed gems.
end
def set_gem_exec_install_paths
- home = Gem.dir
+ home = File.join(Gem.dir, "gem_exec")
ENV["GEM_PATH"] = ([home] + Gem.path).join(File::PATH_SEPARATOR)
ENV["GEM_HOME"] = home
diff --git a/lib/rubygems/commands/fetch_command.rb b/lib/rubygems/commands/fetch_command.rb
index c524cf7922..950d4fe30e 100644
--- a/lib/rubygems/commands/fetch_command.rb
+++ b/lib/rubygems/commands/fetch_command.rb
@@ -10,8 +10,8 @@ class Gem::Commands::FetchCommand < Gem::Command
def initialize
defaults = {
- suggest_alternate: true,
- version: Gem::Requirement.default,
+ :suggest_alternate => true,
+ :version => Gem::Requirement.default,
}
super "fetch", "Download a gem and place it in the current directory", defaults
@@ -63,17 +63,6 @@ then repackaging it.
def execute
check_version
-
- exit_code = fetch_gems
-
- terminate_interaction exit_code
- end
-
- private
-
- def fetch_gems
- exit_code = 0
-
version = options[:version]
platform = Gem.platforms.last
@@ -97,13 +86,10 @@ then repackaging it.
if spec.nil?
show_lookup_failure gem_name, gem_version, errors, suppress_suggestions, options[:domain]
- exit_code |= 2
next
end
source.download spec
say "Downloaded #{spec.full_name}"
end
-
- exit_code
end
end
diff --git a/lib/rubygems/commands/generate_index_command.rb b/lib/rubygems/commands/generate_index_command.rb
index 13be92593b..ce580cfaf9 100644
--- a/lib/rubygems/commands/generate_index_command.rb
+++ b/lib/rubygems/commands/generate_index_command.rb
@@ -1,51 +1,86 @@
# frozen_string_literal: true
require_relative "../command"
+require_relative "../indexer"
-unless defined? Gem::Commands::GenerateIndexCommand
- class Gem::Commands::GenerateIndexCommand < Gem::Command
- module RubygemsTrampoline
- def description # :nodoc:
- <<~EOF
- The generate_index command has been moved to the rubygems-generate_index gem.
- EOF
- end
+##
+# Generates a index files for use as a gem server.
+#
+# See `gem help generate_index`
- def execute
- alert_error "Install the rubygems-generate_index gem for the generate_index command"
- end
+class Gem::Commands::GenerateIndexCommand < Gem::Command
+ def initialize
+ super "generate_index",
+ "Generates the index files for a gem server directory",
+ :directory => ".", :build_modern => true
- def invoke_with_build_args(args, build_args)
- name = "rubygems-generate_index"
- spec = begin
- Gem::Specification.find_by_name(name)
- rescue Gem::LoadError
- require "rubygems/dependency_installer"
- Gem.install(name, Gem::Requirement.default, Gem::DependencyInstaller::DEFAULT_OPTIONS).find {|s| s.name == name }
- end
-
- # remove the methods defined in this file so that the methods defined in the gem are used instead,
- # and without a method redefinition warning
- %w[description execute invoke_with_build_args].each do |method|
- RubygemsTrampoline.remove_method(method)
- end
- self.class.singleton_class.remove_method(:new)
-
- spec.activate
- Gem.load_plugin_files spec.matches_for_glob("rubygems_plugin#{Gem.suffix_pattern}")
-
- self.class.new.invoke_with_build_args(args, build_args)
- end
+ add_option "-d", "--directory=DIRNAME",
+ "repository base dir containing gems subdir" do |dir, options|
+ options[:directory] = File.expand_path dir
+ end
+
+ add_option "--[no-]modern",
+ "Generate indexes for RubyGems",
+ "(always true)" do |value, options|
+ options[:build_modern] = value
end
- private_constant :RubygemsTrampoline
- # remove_method(:initialize) warns, but removing new does not warn
- def self.new
- command = allocate
- command.send(:initialize, "generate_index", "Generates the index files for a gem server directory (requires rubygems-generate_index)")
- command
+ deprecate_option("--modern", version: "4.0", extra_msg: "Modern indexes (specs, latest_specs, and prerelease_specs) are always generated, so this option is not needed.")
+ deprecate_option("--no-modern", version: "4.0", extra_msg: "The `--no-modern` option is currently ignored. Modern indexes (specs, latest_specs, and prerelease_specs) are always generated.")
+
+ add_option "--update",
+ "Update modern indexes with gems added",
+ "since the last update" do |value, options|
+ options[:update] = value
end
+ end
+
+ def defaults_str # :nodoc:
+ "--directory . --modern"
+ end
+
+ def description # :nodoc:
+ <<-EOF
+The generate_index command creates a set of indexes for serving gems
+statically. The command expects a 'gems' directory under the path given to
+the --directory option. The given directory will be the directory you serve
+as the gem repository.
- prepend(RubygemsTrampoline)
+For `gem generate_index --directory /path/to/repo`, expose /path/to/repo via
+your HTTP server configuration (not /path/to/repo/gems).
+
+When done, it will generate a set of files like this:
+
+ gems/*.gem # .gem files you want to
+ # index
+
+ specs.<version>.gz # specs index
+ latest_specs.<version>.gz # latest specs index
+ prerelease_specs.<version>.gz # prerelease specs index
+ quick/Marshal.<version>/<gemname>.gemspec.rz # Marshal quick index file
+
+The .rz extension files are compressed with the inflate algorithm.
+The Marshal version number comes from ruby's Marshal::MAJOR_VERSION and
+Marshal::MINOR_VERSION constants. It is used to ensure compatibility.
+ EOF
+ end
+
+ def execute
+ # This is always true because it's the only way now.
+ options[:build_modern] = true
+
+ if !File.exist?(options[:directory]) ||
+ !File.directory?(options[:directory])
+ alert_error "unknown directory name #{options[:directory]}."
+ terminate_interaction 1
+ else
+ indexer = Gem::Indexer.new options.delete(:directory), options
+
+ if options[:update]
+ indexer.update_index
+ else
+ indexer.generate_index
+ end
+ end
end
end
diff --git a/lib/rubygems/commands/help_command.rb b/lib/rubygems/commands/help_command.rb
index 1619b152e7..20b99fa366 100644
--- a/lib/rubygems/commands/help_command.rb
+++ b/lib/rubygems/commands/help_command.rb
@@ -59,7 +59,7 @@ multiple environments. The RubyGems implementation is designed to be
compatible with Bundler's Gemfile format. You can see additional
documentation on the format at:
- https://bundler.io
+ http://bundler.io
RubyGems automatically looks for these gem dependencies files:
@@ -172,7 +172,7 @@ and #platforms methods:
See the bundler Gemfile manual page for a list of platforms supported in a gem
dependencies file.:
- https://bundler.io/v2.5/man/gemfile.5.html
+ http://bundler.io/v1.6/man/gemfile.5.html
Ruby Version and Engine Dependency
==================================
@@ -269,7 +269,7 @@ Gem::Platform::CURRENT. This will correctly mark the gem with your ruby's
platform.
EOF
- # NOTE: when updating also update Gem::Command::HELP
+ # NOTE when updating also update Gem::Command::HELP
SUBCOMMANDS = [
["commands", :show_commands],
@@ -324,16 +324,16 @@ platform.
margin_width = 4
- desc_width = @command_manager.command_names.map(&:size).max + 4
+ desc_width = @command_manager.command_names.map {|n| n.size }.max + 4
summary_width = 80 - margin_width - desc_width
wrap_indent = " " * (margin_width + desc_width)
- format = "#{" " * margin_width}%-#{desc_width}s%s"
+ format = "#{' ' * margin_width}%-#{desc_width}s%s"
@command_manager.command_names.each do |cmd_name|
command = @command_manager[cmd_name]
- next if command&.deprecated?
+ next if command.deprecated?
summary =
if command
@@ -343,7 +343,7 @@ platform.
end
summary = wrap(summary, summary_width).split "\n"
- out << format(format, cmd_name, summary.shift)
+ out << sprintf(format, cmd_name, summary.shift)
until summary.empty? do
out << "#{wrap_indent}#{summary.shift}"
end
@@ -367,7 +367,7 @@ platform.
command = @command_manager[possibilities.first]
command.invoke("--help")
elsif possibilities.size > 1
- alert_warning "Ambiguous command #{command_name} (#{possibilities.join(", ")})"
+ alert_warning "Ambiguous command #{command_name} (#{possibilities.join(', ')})"
else
alert_warning "Unknown command #{command_name}. Try: gem help commands"
end
diff --git a/lib/rubygems/commands/info_command.rb b/lib/rubygems/commands/info_command.rb
index f65c639662..ced7751ff5 100644
--- a/lib/rubygems/commands/info_command.rb
+++ b/lib/rubygems/commands/info_command.rb
@@ -8,8 +8,8 @@ class Gem::Commands::InfoCommand < Gem::Command
def initialize
super "info", "Show information for the given gem",
- name: //, domain: :local, details: false, versions: true,
- installed: nil, version: Gem::Requirement.default
+ :name => //, :domain => :local, :details => false, :versions => true,
+ :installed => nil, :version => Gem::Requirement.default
add_query_options
diff --git a/lib/rubygems/commands/install_command.rb b/lib/rubygems/commands/install_command.rb
index 2888b6c55a..b0bc2908b4 100644
--- a/lib/rubygems/commands/install_command.rb
+++ b/lib/rubygems/commands/install_command.rb
@@ -23,11 +23,11 @@ class Gem::Commands::InstallCommand < Gem::Command
def initialize
defaults = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
- format_executable: false,
- lock: true,
- suggest_alternate: true,
- version: Gem::Requirement.default,
- without_groups: [],
+ :format_executable => false,
+ :lock => true,
+ :suggest_alternate => true,
+ :version => Gem::Requirement.default,
+ :without_groups => [],
})
defaults.merge!(install_update_options)
@@ -48,7 +48,7 @@ class Gem::Commands::InstallCommand < Gem::Command
end
def defaults_str # :nodoc:
- "--both --version '#{Gem::Requirement.default}' --no-force\n" \
+ "--both --version '#{Gem::Requirement.default}' --no-force\n" +
"--install-dir #{Gem.dir} --lock\n" +
install_update_defaults_str
end
@@ -136,6 +136,13 @@ You can use `i` command instead of `install`.
"#{program_name} [options] GEMNAME [GEMNAME ...] -- --build-flags"
end
+ def check_install_dir # :nodoc:
+ if options[:install_dir] && options[:user_install]
+ alert_error "Use --install-dir or --user-install but not both"
+ terminate_interaction 1
+ end
+ end
+
def check_version # :nodoc:
if options[:version] != Gem::Requirement.default &&
get_all_gem_names.size > 1
@@ -155,6 +162,7 @@ You can use `i` command instead of `install`.
ENV.delete "GEM_PATH" if options[:install_dir].nil?
+ check_install_dir
check_version
load_hooks
@@ -163,7 +171,7 @@ You can use `i` command instead of `install`.
show_installed
- say update_suggestion if eligible_for_update?
+ say update_suggestion if eglible_for_update?
terminate_interaction exit_code
end
@@ -224,6 +232,10 @@ You can use `i` command instead of `install`.
rescue Gem::InstallError => e
alert_error "Error installing #{gem_name}:\n\t#{e.message}"
exit_code |= 1
+ rescue Gem::GemNotFoundException => e
+ show_lookup_failure e.name, e.version, e.errors, suppress_suggestions
+
+ exit_code |= 2
rescue Gem::UnsatisfiableDependencyError => e
show_lookup_failure e.name, e.version, e.errors, suppress_suggestions,
"'#{gem_name}' (#{gem_version})"
@@ -251,7 +263,7 @@ You can use `i` command instead of `install`.
return unless errors
errors.each do |x|
- next unless Gem::SourceFetchProblem === x
+ return unless Gem::SourceFetchProblem === x
require_relative "../uri"
msg = "Unable to pull data from '#{Gem::Uri.redact(x.source.uri)}': #{x.error.message}"
diff --git a/lib/rubygems/commands/list_command.rb b/lib/rubygems/commands/list_command.rb
index fab4b73814..522c771f90 100644
--- a/lib/rubygems/commands/list_command.rb
+++ b/lib/rubygems/commands/list_command.rb
@@ -11,8 +11,8 @@ class Gem::Commands::ListCommand < Gem::Command
def initialize
super "list", "Display local gems whose name matches REGEXP",
- domain: :local, details: false, versions: true,
- installed: nil, version: Gem::Requirement.default
+ :domain => :local, :details => false, :versions => true,
+ :installed => nil, :version => Gem::Requirement.default
add_query_options
end
diff --git a/lib/rubygems/commands/lock_command.rb b/lib/rubygems/commands/lock_command.rb
index f7fd5ada16..3a9512fe3f 100644
--- a/lib/rubygems/commands/lock_command.rb
+++ b/lib/rubygems/commands/lock_command.rb
@@ -5,7 +5,7 @@ require_relative "../command"
class Gem::Commands::LockCommand < Gem::Command
def initialize
super "lock", "Generate a lockdown list of gems",
- strict: false
+ :strict => false
add_option "-s", "--[no-]strict",
"fail if unable to satisfy a dependency" do |strict, options|
diff --git a/lib/rubygems/commands/open_command.rb b/lib/rubygems/commands/open_command.rb
index 0fe90dc8b8..5a13074a1d 100644
--- a/lib/rubygems/commands/open_command.rb
+++ b/lib/rubygems/commands/open_command.rb
@@ -70,7 +70,9 @@ class Gem::Commands::OpenCommand < Gem::Command
end
def open_editor(path)
- system(*@editor.split(/\s+/) + [path], { chdir: path })
+ Dir.chdir(path) do
+ system(*@editor.split(/\s+/) + [path])
+ end
end
def spec_for(name)
diff --git a/lib/rubygems/commands/owner_command.rb b/lib/rubygems/commands/owner_command.rb
index 12bfe3a834..b51c9cf888 100644
--- a/lib/rubygems/commands/owner_command.rb
+++ b/lib/rubygems/commands/owner_command.rb
@@ -39,7 +39,7 @@ permission to.
add_proxy_option
add_key_option
add_otp_option
- defaults.merge! add: [], remove: []
+ defaults.merge! :add => [], :remove => []
add_option "-a", "--add NEW_OWNER", "Add an owner by user identifier" do |value, options|
options[:add] << value
@@ -79,7 +79,7 @@ permission to.
say "Owners for gem: #{name}"
owners.each do |owner|
- say "- #{owner["email"] || owner["handle"] || owner["id"]}"
+ say "- #{owner['email'] || owner['handle'] || owner['id']}"
end
end
end
@@ -94,14 +94,16 @@ permission to.
def manage_owners(method, name, owners)
owners.each do |owner|
- response = send_owner_request(method, name, owner)
- action = method == :delete ? "Removing" : "Adding"
-
- with_response response, "#{action} #{owner}"
- rescue Gem::WebauthnVerificationError => e
- raise e
- rescue StandardError
- # ignore early exits to allow for completing the iteration of all owners
+ begin
+ response = send_owner_request(method, name, owner)
+ action = method == :delete ? "Removing" : "Adding"
+
+ with_response response, "#{action} #{owner}"
+ rescue Gem::WebauthnVerificationError => e
+ raise e
+ rescue StandardError
+ # ignore early exits to allow for completing the iteration of all owners
+ end
end
end
diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb
index 999c9fef0f..64608a033f 100644
--- a/lib/rubygems/commands/pristine_command.rb
+++ b/lib/rubygems/commands/pristine_command.rb
@@ -11,10 +11,10 @@ class Gem::Commands::PristineCommand < Gem::Command
def initialize
super "pristine",
"Restores installed gems to pristine condition from files located in the gem cache",
- version: Gem::Requirement.default,
- extensions: true,
- extensions_set: false,
- all: false
+ :version => Gem::Requirement.default,
+ :extensions => true,
+ :extensions_set => false,
+ :all => false
add_option("--all",
"Restore all installed gems to pristine",
@@ -57,7 +57,7 @@ class Gem::Commands::PristineCommand < Gem::Command
end
add_option("-i", "--install-dir DIR",
- "Gem repository to get gems restored") do |value, options|
+ "Gem repository to get binstubs and plugins installed") do |value, options|
options[:install_dir] = File.expand_path(value)
end
@@ -103,29 +103,27 @@ extensions will be restored.
end
def execute
- install_dir = options[:install_dir]
-
- specification_record = install_dir ? Gem::SpecificationRecord.from_path(install_dir) : Gem::Specification.specification_record
-
specs = if options[:all]
- specification_record.map
+ Gem::Specification.map
# `--extensions` must be explicitly given to pristine only gems
# with extensions.
elsif options[:extensions_set] &&
options[:extensions] && options[:args].empty?
- specification_record.select do |spec|
+ Gem::Specification.select do |spec|
spec.extensions && !spec.extensions.empty?
end
elsif options[:only_missing_extensions]
- specification_record.select(&:missing_extensions?)
+ Gem::Specification.select do |spec|
+ spec.missing_extensions?
+ end
else
get_all_gem_names.sort.map do |gem_name|
- specification_record.find_all_by_name(gem_name, options[:version]).reverse
+ Gem::Specification.find_all_by_name(gem_name, options[:version]).reverse
end.flatten
end
- specs = specs.select {|spec| spec.platform == RUBY_ENGINE || Gem::Platform.local === spec.platform || spec.platform == Gem::Platform::RUBY }
+ specs = specs.select {|spec| RUBY_ENGINE == spec.platform || Gem::Platform.local === spec.platform || spec.platform == Gem::Platform::RUBY }
if specs.to_a.empty?
raise Gem::Exception,
@@ -140,7 +138,7 @@ extensions will be restored.
next
end
- if options.key? :skip
+ if options.has_key? :skip
if options[:skip].include? spec.name
say "Skipped #{spec.full_name}, it was given through options"
next
@@ -148,7 +146,7 @@ extensions will be restored.
end
unless spec.extensions.empty? || options[:extensions] || options[:only_executables] || options[:only_plugins]
- say "Skipped #{spec.full_name_with_location}, it needs to compile an extension"
+ say "Skipped #{spec.full_name}, it needs to compile an extension"
next
end
@@ -157,7 +155,7 @@ extensions will be restored.
unless File.exist?(gem) || options[:only_executables] || options[:only_plugins]
require_relative "../remote_fetcher"
- say "Cached gem for #{spec.full_name_with_location} not found, attempting to fetch..."
+ say "Cached gem for #{spec.full_name} not found, attempting to fetch..."
dep = Gem::Dependency.new spec.name, spec.version
found, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dep
@@ -180,14 +178,15 @@ extensions will be restored.
end
bin_dir = options[:bin_dir] if options[:bin_dir]
+ install_dir = options[:install_dir] if options[:install_dir]
installer_options = {
- wrappers: true,
- force: true,
- install_dir: install_dir || spec.base_dir,
- env_shebang: env_shebang,
- build_args: spec.build_args,
- bin_dir: bin_dir,
+ :wrappers => true,
+ :force => true,
+ :install_dir => install_dir || spec.base_dir,
+ :env_shebang => env_shebang,
+ :build_args => spec.build_args,
+ :bin_dir => bin_dir,
}
if options[:only_executables]
@@ -201,7 +200,7 @@ extensions will be restored.
installer.install
end
- say "Restored #{spec.full_name_with_location}"
+ say "Restored #{spec.full_name}"
end
end
end
diff --git a/lib/rubygems/commands/push_command.rb b/lib/rubygems/commands/push_command.rb
index 591ddc3a80..79ca3d59b0 100644
--- a/lib/rubygems/commands/push_command.rb
+++ b/lib/rubygems/commands/push_command.rb
@@ -30,7 +30,7 @@ The push command will use ~/.gem/credentials to authenticate to a server, but yo
end
def initialize
- super "push", "Push a gem up to the gem server", host: host
+ super "push", "Push a gem up to the gem server", :host => self.host
@user_defined_host = false
@@ -75,7 +75,7 @@ The push command will use ~/.gem/credentials to authenticate to a server, but yo
@host ||= push_host
# Always include @host, even if it's nil
- args += [@host, push_host]
+ args += [ @host, push_host ]
say "Pushing gem to #{@host || Gem.host}..."
diff --git a/lib/rubygems/commands/query_command.rb b/lib/rubygems/commands/query_command.rb
index 3b527974a3..4fa201272e 100644
--- a/lib/rubygems/commands/query_command.rb
+++ b/lib/rubygems/commands/query_command.rb
@@ -10,7 +10,7 @@ class Gem::Commands::QueryCommand < Gem::Command
include Gem::QueryUtils
- alias_method :warning_without_suggested_alternatives, :deprecation_warning
+ alias warning_without_suggested_alternatives deprecation_warning
def deprecation_warning
warning_without_suggested_alternatives
@@ -18,10 +18,11 @@ class Gem::Commands::QueryCommand < Gem::Command
alert_warning message unless Gem::Deprecate.skip
end
- def initialize(name = "query", summary = "Query gem information in local or remote repositories")
+ def initialize(name = "query",
+ summary = "Query gem information in local or remote repositories")
super name, summary,
- domain: :local, details: false, versions: true,
- installed: nil, version: Gem::Requirement.default
+ :domain => :local, :details => false, :versions => true,
+ :installed => nil, :version => Gem::Requirement.default
add_option("-n", "--name-matches REGEXP",
"Name of gem(s) to query on matches the",
diff --git a/lib/rubygems/commands/rdoc_command.rb b/lib/rubygems/commands/rdoc_command.rb
index 977c90b8c4..e318a52914 100644
--- a/lib/rubygems/commands/rdoc_command.rb
+++ b/lib/rubygems/commands/rdoc_command.rb
@@ -10,8 +10,8 @@ class Gem::Commands::RdocCommand < Gem::Command
def initialize
super "rdoc", "Generates RDoc for pre-installed gems",
- version: Gem::Requirement.default,
- include_rdoc: false, include_ri: true, overwrite: false
+ :version => Gem::Requirement.default,
+ :include_rdoc => false, :include_ri => true, :overwrite => false
add_option("--all",
"Generate RDoc/RI documentation for all",
@@ -84,7 +84,14 @@ Use --overwrite to force rebuilding of documentation.
FileUtils.rm_rf File.join(spec.doc_dir, "rdoc")
end
- doc.generate
+ begin
+ doc.generate
+ rescue Errno::ENOENT => e
+ match = / - /.match(e.message)
+ alert_error "Unable to document #{spec.full_name}, " \
+ " #{match.post_match} is missing, skipping"
+ terminate_interaction 1 if specs.length == 1
+ end
end
end
end
diff --git a/lib/rubygems/commands/rebuild_command.rb b/lib/rubygems/commands/rebuild_command.rb
deleted file mode 100644
index 77a474ef1d..0000000000
--- a/lib/rubygems/commands/rebuild_command.rb
+++ /dev/null
@@ -1,262 +0,0 @@
-# frozen_string_literal: true
-
-require "date"
-require "digest"
-require "fileutils"
-require "tmpdir"
-require_relative "../gemspec_helpers"
-require_relative "../package"
-
-class Gem::Commands::RebuildCommand < Gem::Command
- include Gem::GemspecHelpers
-
- def initialize
- super "rebuild", "Attempt to reproduce a build of a gem."
-
- add_option "--diff", "If the files don't match, compare them using diffoscope." do |_value, options|
- options[:diff] = true
- end
-
- add_option "--force", "Skip validation of the spec." do |_value, options|
- options[:force] = true
- end
-
- add_option "--strict", "Consider warnings as errors when validating the spec." do |_value, options|
- options[:strict] = true
- end
-
- add_option "--source GEM_SOURCE", "Specify the source to download the gem from." do |value, options|
- options[:source] = value
- end
-
- add_option "--original GEM_FILE", "Specify a local file to compare against (instead of downloading it)." do |value, options|
- options[:original_gem_file] = value
- end
-
- add_option "--gemspec GEMSPEC_FILE", "Specify the name of the gemspec file." do |value, options|
- options[:gemspec_file] = value
- end
-
- add_option "-C PATH", "Run as if gem build was started in <PATH> instead of the current working directory." do |value, options|
- options[:build_path] = value
- end
- end
-
- def arguments # :nodoc:
- "GEM_NAME gem name on gem server\n" \
- "GEM_VERSION gem version you are attempting to rebuild"
- end
-
- def description # :nodoc:
- <<-EOF
-The rebuild command allows you to (attempt to) reproduce a build of a gem
-from a ruby gemspec.
-
-This command assumes the gemspec can be built with the `gem build` command.
-If you use any of `gem build`, `rake build`, or`rake release` in the
-build/release process for a gem, it is a potential candidate.
-
-You will need to match the RubyGems version used, since this is included in
-the Gem metadata.
-
-If the gem includes lockfiles (e.g. Gemfile.lock) and similar, it will
-require more effort to reproduce a build. For example, it might require
-more precisely matched versions of Ruby and/or Bundler to be used.
- EOF
- end
-
- def usage # :nodoc:
- "#{program_name} GEM_NAME GEM_VERSION"
- end
-
- def execute
- gem_name, gem_version = get_gem_name_and_version
-
- old_dir, new_dir = prep_dirs
-
- gem_filename = "#{gem_name}-#{gem_version}.gem"
- old_file = File.join(old_dir, gem_filename)
- new_file = File.join(new_dir, gem_filename)
-
- if options[:original_gem_file]
- FileUtils.copy_file(options[:original_gem_file], old_file)
- else
- download_gem(gem_name, gem_version, old_file)
- end
-
- rg_version = rubygems_version(old_file)
- unless rg_version == Gem::VERSION
- alert_error <<-EOF
-You need to use the same RubyGems version #{gem_name} v#{gem_version} was built with.
-
-#{gem_name} v#{gem_version} was built using RubyGems v#{rg_version}.
-Gem files include the version of RubyGems used to build them.
-This means in order to reproduce #{gem_filename}, you must also use RubyGems v#{rg_version}.
-
-You're using RubyGems v#{Gem::VERSION}.
-
-Please install RubyGems v#{rg_version} and try again.
- EOF
- terminate_interaction 1
- end
-
- source_date_epoch = get_timestamp(old_file).to_s
-
- if build_path = options[:build_path]
- Dir.chdir(build_path) { build_gem(gem_name, source_date_epoch, new_file) }
- else
- build_gem(gem_name, source_date_epoch, new_file)
- end
-
- compare(source_date_epoch, old_file, new_file)
- end
-
- private
-
- def sha256(file)
- Digest::SHA256.hexdigest(Gem.read_binary(file))
- end
-
- def get_timestamp(file)
- mtime = nil
- File.open(file, Gem.binary_mode) do |f|
- Gem::Package::TarReader.new(f) do |tar|
- mtime = tar.seek("metadata.gz") {|tf| tf.header.mtime }
- end
- end
-
- mtime
- end
-
- def compare(source_date_epoch, old_file, new_file)
- date = Time.at(source_date_epoch.to_i).strftime("%F %T %Z")
-
- old_hash = sha256(old_file)
- new_hash = sha256(new_file)
-
- say
- say "Built at: #{date} (#{source_date_epoch})"
- say "Original build saved to: #{old_file}"
- say "Reproduced build saved to: #{new_file}"
- say "Working directory: #{options[:build_path] || Dir.pwd}"
- say
- say "Hash comparison:"
- say " #{old_hash}\t#{old_file}"
- say " #{new_hash}\t#{new_file}"
- say
-
- if old_hash == new_hash
- say "SUCCESS - original and rebuild hashes matched"
- else
- say "FAILURE - original and rebuild hashes did not match"
- say
-
- if options[:diff]
- if system("diffoscope", old_file, new_file).nil?
- alert_error "error: could not find `diffoscope` executable"
- end
- else
- say "Pass --diff for more details (requires diffoscope to be installed)."
- end
-
- terminate_interaction 1
- end
- end
-
- def prep_dirs
- rebuild_dir = Dir.mktmpdir("gem_rebuild")
- old_dir = File.join(rebuild_dir, "old")
- new_dir = File.join(rebuild_dir, "new")
-
- FileUtils.mkdir_p(old_dir)
- FileUtils.mkdir_p(new_dir)
-
- [old_dir, new_dir]
- end
-
- def get_gem_name_and_version
- args = options[:args] || []
- if args.length == 2
- gem_name, gem_version = args
- elsif args.length > 2
- raise Gem::CommandLineError, "Too many arguments"
- else
- raise Gem::CommandLineError, "Expected GEM_NAME and GEM_VERSION arguments (gem rebuild GEM_NAME GEM_VERSION)"
- end
-
- [gem_name, gem_version]
- end
-
- def build_gem(gem_name, source_date_epoch, output_file)
- gemspec = options[:gemspec_file] || find_gemspec("#{gem_name}.gemspec")
-
- if gemspec
- build_package(gemspec, source_date_epoch, output_file)
- else
- alert_error error_message(gem_name)
- terminate_interaction(1)
- end
- end
-
- def build_package(gemspec, source_date_epoch, output_file)
- with_source_date_epoch(source_date_epoch) do
- spec = Gem::Specification.load(gemspec)
- if spec
- Gem::Package.build(
- spec,
- options[:force],
- options[:strict],
- output_file
- )
- else
- alert_error "Error loading gemspec. Aborting."
- terminate_interaction 1
- end
- end
- end
-
- def with_source_date_epoch(source_date_epoch)
- old_sde = ENV["SOURCE_DATE_EPOCH"]
- ENV["SOURCE_DATE_EPOCH"] = source_date_epoch.to_s
-
- yield
- ensure
- ENV["SOURCE_DATE_EPOCH"] = old_sde
- end
-
- def error_message(gem_name)
- if gem_name
- "Couldn't find a gemspec file matching '#{gem_name}' in #{Dir.pwd}"
- else
- "Couldn't find a gemspec file in #{Dir.pwd}"
- end
- end
-
- def download_gem(gem_name, gem_version, old_file)
- # This code was based loosely off the `gem fetch` command.
- version = "= #{gem_version}"
- dep = Gem::Dependency.new gem_name, version
-
- specs_and_sources, errors =
- Gem::SpecFetcher.fetcher.spec_for_dependency dep
-
- # There should never be more than one item in specs_and_sources,
- # since we search for an exact version.
- spec, source = specs_and_sources[0]
-
- if spec.nil?
- show_lookup_failure gem_name, version, errors, options[:domain]
- terminate_interaction 1
- end
-
- download_path = source.download spec
-
- FileUtils.move(download_path, old_file)
-
- say "Downloaded #{gem_name} version #{gem_version} as #{old_file}."
- end
-
- def rubygems_version(gem_file)
- Gem::Package.new(gem_file).spec.rubygems_version
- end
-end
diff --git a/lib/rubygems/commands/search_command.rb b/lib/rubygems/commands/search_command.rb
index 50e161ac9b..c7469e1fa8 100644
--- a/lib/rubygems/commands/search_command.rb
+++ b/lib/rubygems/commands/search_command.rb
@@ -8,8 +8,8 @@ class Gem::Commands::SearchCommand < Gem::Command
def initialize
super "search", "Display remote gems whose name matches REGEXP",
- domain: :remote, details: false, versions: true,
- installed: nil, version: Gem::Requirement.default
+ :domain => :remote, :details => false, :versions => true,
+ :installed => nil, :version => Gem::Requirement.default
add_query_options
end
diff --git a/lib/rubygems/commands/setup_command.rb b/lib/rubygems/commands/setup_command.rb
index bb2246ca31..df1732b49e 100644
--- a/lib/rubygems/commands/setup_command.rb
+++ b/lib/rubygems/commands/setup_command.rb
@@ -7,19 +7,19 @@ require_relative "../command"
# RubyGems checkout or tarball.
class Gem::Commands::SetupCommand < Gem::Command
- HISTORY_HEADER = %r{^#\s*[\d.a-zA-Z]+\s*/\s*\d{4}-\d{2}-\d{2}\s*$}
- VERSION_MATCHER = %r{^#\s*([\d.a-zA-Z]+)\s*/\s*\d{4}-\d{2}-\d{2}\s*$}
+ HISTORY_HEADER = /^#\s*[\d.a-zA-Z]+\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/.freeze
+ VERSION_MATCHER = /^#\s*([\d.a-zA-Z]+)\s*\/\s*\d{4}-\d{2}-\d{2}\s*$/.freeze
ENV_PATHS = %w[/usr/bin/env /bin/env].freeze
def initialize
super "setup", "Install RubyGems",
- format_executable: false, document: %w[ri],
- force: true,
- site_or_vendor: "sitelibdir",
- destdir: "", prefix: "", previous_version: "",
- regenerate_binstubs: true,
- regenerate_plugins: true
+ :format_executable => false, :document => %w[ri],
+ :force => true,
+ :site_or_vendor => "sitelibdir",
+ :destdir => "", :prefix => "", :previous_version => "",
+ :regenerate_binstubs => true,
+ :regenerate_plugins => true
add_option "--previous-version=VERSION",
"Previous version of RubyGems",
@@ -55,9 +55,9 @@ class Gem::Commands::SetupCommand < Gem::Command
"List the documentation types you wish to",
"generate. For example: rdoc,ri" do |value, options|
options[:document] = case value
- when nil then %w[rdoc ri]
- when false then []
- else value
+ when nil then %w[rdoc ri]
+ when false then []
+ else value
end
end
@@ -134,7 +134,7 @@ prefix and suffix. If ruby was installed as `ruby18`, gem will be
installed as `gem18`.
By default, this RubyGems will install gem as:
- #{Gem.default_exec_format % "gem"}
+ #{Gem.default_exec_format % 'gem'}
EOF
end
@@ -243,7 +243,7 @@ By default, this RubyGems will install gem as:
end
def install_executables(bin_dir)
- prog_mode = options[:prog_mode] || 0o755
+ prog_mode = options[:prog_mode] || 0755
executables = { "gem" => "exe" }
executables.each do |tool, path|
@@ -265,7 +265,7 @@ By default, this RubyGems will install gem as:
fp.puts bin.join
end
- install bin_tmp_file, dest_file, mode: prog_mode
+ install bin_tmp_file, dest_file, :mode => prog_mode
bin_file_names << dest_file
ensure
rm bin_tmp_file
@@ -279,11 +279,15 @@ By default, this RubyGems will install gem as:
File.open bin_cmd_file, "w" do |file|
file.puts <<-TEXT
@ECHO OFF
- @"%~dp0#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %*
+ IF NOT "%~f0" == "~f0" GOTO :WinNT
+ @"#{File.basename(Gem.ruby).chomp('"')}" "#{dest_file}" %1 %2 %3 %4 %5 %6 %7 %8 %9
+ GOTO :EOF
+ :WinNT
+ @"#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %*
TEXT
end
- install bin_cmd_file, "#{dest_file}.bat", mode: prog_mode
+ install bin_cmd_file, "#{dest_file}.bat", :mode => prog_mode
ensure
rm bin_cmd_file
end
@@ -336,8 +340,6 @@ By default, this RubyGems will install gem as:
require_relative "../rdoc"
- return false unless defined?(Gem::RDoc)
-
fake_spec = Gem::Specification.new "rubygems", Gem::VERSION
def fake_spec.full_gem_path
File.expand_path "../../..", __dir__
@@ -355,7 +357,7 @@ By default, this RubyGems will install gem as:
say "Set the GEM_HOME environment variable if you want RDoc generated"
end
- false
+ return false
end
def install_default_bundler_gem(bin_dir)
@@ -367,21 +369,18 @@ By default, this RubyGems will install gem as:
File.dirname(loaded_from)
else
target_specs_dir = File.join(default_dir, "specifications", "default")
- mkdir_p target_specs_dir, mode: 0o755
+ mkdir_p target_specs_dir, :mode => 0755
target_specs_dir
end
- new_bundler_spec = Dir.chdir("bundler") { Gem::Specification.load("bundler.gemspec") }
- full_name = new_bundler_spec.full_name
- gemspec_path = "#{full_name}.gemspec"
-
- default_spec_path = File.join(specs_dir, gemspec_path)
- Gem.write_binary(default_spec_path, new_bundler_spec.to_ruby)
+ bundler_spec = Dir.chdir("bundler") { Gem::Specification.load("bundler.gemspec") }
+ default_spec_path = File.join(specs_dir, "#{bundler_spec.full_name}.gemspec")
+ Gem.write_binary(default_spec_path, bundler_spec.to_ruby)
bundler_spec = Gem::Specification.load(default_spec_path)
# Remove gemspec that was same version of vendored bundler.
- normal_gemspec = File.join(default_dir, "specifications", gemspec_path)
+ normal_gemspec = File.join(default_dir, "specifications", "bundler-#{bundler_spec.version}.gemspec")
if File.file? normal_gemspec
File.delete normal_gemspec
end
@@ -389,14 +388,20 @@ By default, this RubyGems will install gem as:
# Remove gem files that were same version of vendored bundler.
if File.directory? bundler_spec.gems_dir
Dir.entries(bundler_spec.gems_dir).
- select {|default_gem| File.basename(default_gem) == full_name }.
+ select {|default_gem| File.basename(default_gem) == "bundler-#{bundler_spec.version}" }.
each {|default_gem| rm_r File.join(bundler_spec.gems_dir, default_gem) }
end
+ bundler_bin_dir = bundler_spec.bin_dir
+ mkdir_p bundler_bin_dir, :mode => 0755
+ bundler_spec.executables.each do |e|
+ cp File.join("bundler", bundler_spec.bindir, e), File.join(bundler_bin_dir, e)
+ end
+
require_relative "../installer"
Dir.chdir("bundler") do
- built_gem = Gem::Package.build(new_bundler_spec)
+ built_gem = Gem::Package.build(bundler_spec)
begin
Gem::Installer.at(
built_gem,
@@ -413,9 +418,9 @@ By default, this RubyGems will install gem as:
end
end
- new_bundler_spec.executables.each {|executable| bin_file_names << target_bin_path(bin_dir, executable) }
+ bundler_spec.executables.each {|executable| bin_file_names << target_bin_path(bin_dir, executable) }
- say "Bundler #{new_bundler_spec.version} installed"
+ say "Bundler #{bundler_spec.version} installed"
end
def make_destination_dirs
@@ -425,10 +430,10 @@ By default, this RubyGems will install gem as:
lib_dir, bin_dir = generate_default_dirs
end
- mkdir_p lib_dir, mode: 0o755
- mkdir_p bin_dir, mode: 0o755
+ mkdir_p lib_dir, :mode => 0755
+ mkdir_p bin_dir, :mode => 0755
- [lib_dir, bin_dir]
+ return lib_dir, bin_dir
end
def generate_default_man_dir
@@ -571,8 +576,8 @@ abort "#{deprecation_message}"
def uninstall_old_gemcutter
require_relative "../uninstaller"
- ui = Gem::Uninstaller.new("gemcutter", all: true, ignore: true,
- version: "< 0.4")
+ ui = Gem::Uninstaller.new("gemcutter", :all => true, :ignore => true,
+ :version => "< 0.4")
ui.uninstall
rescue Gem::InstallError
end
@@ -583,8 +588,6 @@ abort "#{deprecation_message}"
args = %w[--all --only-executables --silent]
args << "--bindir=#{bindir}"
- args << "--install-dir=#{default_dir}"
-
if options[:env_shebang]
args << "--env-shebang"
end
@@ -636,10 +639,10 @@ abort "#{deprecation_message}"
dest_file = File.join dest_dir, file
dest_dir = File.dirname dest_file
unless File.directory? dest_dir
- mkdir_p dest_dir, mode: 0o755
+ mkdir_p dest_dir, :mode => 0755
end
- install file, dest_file, mode: options[:data_mode] || 0o644
+ install file, dest_file, :mode => options[:data_mode] || 0644
end
def remove_file_list(files, dir)
diff --git a/lib/rubygems/commands/sources_command.rb b/lib/rubygems/commands/sources_command.rb
index 976f4a4ea2..85cc68ac09 100644
--- a/lib/rubygems/commands/sources_command.rb
+++ b/lib/rubygems/commands/sources_command.rb
@@ -59,7 +59,7 @@ class Gem::Commands::SourcesCommand < Gem::Command
say "#{source_uri} added to sources"
end
- rescue Gem::URI::Error, ArgumentError
+ rescue URI::Error, ArgumentError
say "#{source_uri} is not a URI"
terminate_interaction 1
rescue Gem::RemoteFetcher::FetchError => e
@@ -71,7 +71,7 @@ class Gem::Commands::SourcesCommand < Gem::Command
def check_typo_squatting(source)
if source.typo_squatting?("rubygems.org")
question = <<-QUESTION.chomp
-#{source.uri} is too similar to https://rubygems.org
+#{source.uri.to_s} is too similar to https://rubygems.org
Do you want to add this source?
QUESTION
@@ -81,10 +81,10 @@ Do you want to add this source?
end
def check_rubygems_https(source_uri) # :nodoc:
- uri = Gem::URI source_uri
+ uri = URI source_uri
- if uri.scheme && uri.scheme.casecmp("http").zero? &&
- uri.host.casecmp("rubygems.org").zero?
+ if uri.scheme && uri.scheme.downcase == "http" &&
+ uri.host.downcase == "rubygems.org"
question = <<-QUESTION.chomp
https://rubygems.org is recommended for security over #{uri}
@@ -99,16 +99,16 @@ Do you want to add this insecure source?
path = Gem.spec_cache_dir
FileUtils.rm_rf path
- if File.exist? path
- if File.writable? path
- say "*** Unable to remove source cache ***"
- else
+ unless File.exist? path
+ say "*** Removed specs cache ***"
+ else
+ unless File.writable? path
say "*** Unable to remove source cache (write protected) ***"
+ else
+ say "*** Unable to remove source cache ***"
end
terminate_interaction 1
- else
- say "*** Removed specs cache ***"
end
end
@@ -194,13 +194,13 @@ To remove a source use the --remove argument:
end
def remove_source(source_uri) # :nodoc:
- if Gem.sources.include? source_uri
+ unless Gem.sources.include? source_uri
+ say "source #{source_uri} not present in cache"
+ else
Gem.sources.delete source_uri
Gem.configuration.write
say "#{source_uri} removed from sources"
- else
- say "source #{source_uri} not present in cache"
end
end
diff --git a/lib/rubygems/commands/specification_command.rb b/lib/rubygems/commands/specification_command.rb
index a21ed35be3..ed158506e0 100644
--- a/lib/rubygems/commands/specification_command.rb
+++ b/lib/rubygems/commands/specification_command.rb
@@ -13,27 +13,27 @@ class Gem::Commands::SpecificationCommand < Gem::Command
Gem.load_yaml
super "specification", "Display gem specification (in yaml)",
- domain: :local, version: Gem::Requirement.default,
- format: :yaml
+ :domain => :local, :version => Gem::Requirement.default,
+ :format => :yaml
add_version_option("examine")
add_platform_option
add_prerelease_option
add_option("--all", "Output specifications for all versions of",
- "the gem") do |_value, options|
+ "the gem") do |value, options|
options[:all] = true
end
- add_option("--ruby", "Output ruby format") do |_value, options|
+ add_option("--ruby", "Output ruby format") do |value, options|
options[:format] = :ruby
end
- add_option("--yaml", "Output YAML format") do |_value, options|
+ add_option("--yaml", "Output YAML format") do |value, options|
options[:format] = :yaml
end
- add_option("--marshal", "Output Marshal format") do |_value, options|
+ add_option("--marshal", "Output Marshal format") do |value, options|
options[:format] = :marshal
end
@@ -107,11 +107,7 @@ Specific fields in the specification can be extracted in YAML format:
if local?
if File.exist? gem
- begin
- specs << Gem::Package.new(gem).spec
- rescue StandardError
- nil
- end
+ specs << Gem::Package.new(gem).spec rescue nil
end
if specs.empty?
@@ -138,16 +134,16 @@ Specific fields in the specification can be extracted in YAML format:
end
unless options[:all]
- specs = [specs.max_by(&:version)]
+ specs = [specs.max_by {|s| s.version }]
end
specs.each do |s|
s = s.send field if field
say case options[:format]
- when :ruby then s.to_ruby
- when :marshal then Marshal.dump s
- else s.to_yaml
+ when :ruby then s.to_ruby
+ when :marshal then Marshal.dump s
+ else s.to_yaml
end
say "\n"
diff --git a/lib/rubygems/commands/stale_command.rb b/lib/rubygems/commands/stale_command.rb
index 0be2b85159..a94d77c193 100644
--- a/lib/rubygems/commands/stale_command.rb
+++ b/lib/rubygems/commands/stale_command.rb
@@ -18,7 +18,7 @@ longer using.
end
def usage # :nodoc:
- program_name.to_s
+ "#{program_name}"
end
def execute
@@ -34,7 +34,7 @@ longer using.
end
gem_to_atime.sort_by {|_, atime| atime }.each do |name, atime|
- say "#{name} at #{atime.strftime "%c"}"
+ say "#{name} at #{atime.strftime '%c'}"
end
end
end
diff --git a/lib/rubygems/commands/uninstall_command.rb b/lib/rubygems/commands/uninstall_command.rb
index 3d6e41e49e..feba1c5b7c 100644
--- a/lib/rubygems/commands/uninstall_command.rb
+++ b/lib/rubygems/commands/uninstall_command.rb
@@ -15,11 +15,12 @@ class Gem::Commands::UninstallCommand < Gem::Command
def initialize
super "uninstall", "Uninstall gems from the local repository",
- version: Gem::Requirement.default, user_install: true,
- check_dev: false, vendor: false
+ :version => Gem::Requirement.default, :user_install => true,
+ :check_dev => false, :vendor => false
add_option("-a", "--[no-]all",
- "Uninstall all matching versions") do |value, options|
+ "Uninstall all matching versions"
+ ) do |value, options|
options[:all] = value
end
@@ -79,7 +80,7 @@ class Gem::Commands::UninstallCommand < Gem::Command
add_option("--vendor",
"Uninstall gem from the vendor directory.",
- "Only for use by gem repackagers.") do |_value, options|
+ "Only for use by gem repackagers.") do |value, options|
unless Gem.vendor_dir
raise Gem::OptionParser::InvalidOption.new "your platform is not supported"
end
@@ -95,7 +96,7 @@ class Gem::Commands::UninstallCommand < Gem::Command
end
def defaults_str # :nodoc:
- "--version '#{Gem::Requirement.default}' --no-force " \
+ "--version '#{Gem::Requirement.default}' --no-force " +
"--user-install"
end
@@ -138,7 +139,7 @@ that is a dependency of an existing gem. You can use the
end
def uninstall_all
- specs = Gem::Specification.reject(&:default_gem?)
+ specs = Gem::Specification.reject {|spec| spec.default_gem? }
specs.each do |spec|
options[:version] = spec.version
@@ -157,14 +158,9 @@ that is a dependency of an existing gem. You can use the
gem_specs = Gem::Specification.find_all_by_name(name, original_gem_version[name])
- if gem_specs.empty?
- say("Gem '#{name}' is not installed")
- else
- gem_specs.reject!(&:default_gem?) if gem_specs.size > 1
-
- gem_specs.each do |spec|
- deplist.add spec
- end
+ say("Gem '#{name}' is not installed") if gem_specs.empty?
+ gem_specs.each do |spec|
+ deplist.add spec
end
end
@@ -173,14 +169,15 @@ that is a dependency of an existing gem. You can use the
gems_to_uninstall = {}
deps.each do |dep|
- if original_gem_version[dep.name] == Gem::Requirement.default
- next if gems_to_uninstall[dep.name]
+ unless gems_to_uninstall[dep.name]
gems_to_uninstall[dep.name] = true
- else
- options[:version] = dep.version
- end
- uninstall_gem(dep.name)
+ unless original_gem_version[dep.name] == Gem::Requirement.default
+ options[:version] = dep.version
+ end
+
+ uninstall_gem(dep.name)
+ end
end
end
@@ -188,12 +185,12 @@ that is a dependency of an existing gem. You can use the
uninstall(gem_name)
rescue Gem::GemNotInHomeException => e
spec = e.spec
- alert("In order to remove #{spec.name}, please execute:\n" \
- "\tgem uninstall #{spec.name} --install-dir=#{spec.base_dir}")
+ alert("In order to remove #{spec.name}, please execute:\n" +
+ "\tgem uninstall #{spec.name} --install-dir=#{spec.installation_path}")
rescue Gem::UninstallError => e
spec = e.spec
- alert_error("Error: unable to successfully uninstall '#{spec.name}' which is " \
- "located at '#{spec.full_gem_path}'. This is most likely because" \
+ alert_error("Error: unable to successfully uninstall '#{spec.name}' which is " +
+ "located at '#{spec.full_gem_path}'. This is most likely because" +
"the current user does not have the appropriate permissions")
terminate_interaction 1
end
diff --git a/lib/rubygems/commands/unpack_command.rb b/lib/rubygems/commands/unpack_command.rb
index c2fc720297..1bff53429b 100644
--- a/lib/rubygems/commands/unpack_command.rb
+++ b/lib/rubygems/commands/unpack_command.rb
@@ -21,15 +21,15 @@ class Gem::Commands::UnpackCommand < Gem::Command
require "fileutils"
super "unpack", "Unpack an installed gem to the current directory",
- version: Gem::Requirement.default,
- target: Dir.pwd
+ :version => Gem::Requirement.default,
+ :target => Dir.pwd
add_option("--target=DIR",
"target directory for unpacking") do |value, options|
options[:target] = value
end
- add_option("--spec", "unpack the gem specification") do |_value, options|
+ add_option("--spec", "unpack the gem specification") do |value, options|
options[:spec] = true
end
@@ -96,10 +96,12 @@ command help for an example.
FileUtils.mkdir_p @options[:target] if @options[:target]
- destination = if @options[:target]
- File.join @options[:target], spec_file
- else
- spec_file
+ destination = begin
+ if @options[:target]
+ File.join @options[:target], spec_file
+ else
+ spec_file
+ end
end
File.open destination, "w" do |io|
@@ -130,7 +132,7 @@ command help for an example.
return this_path if File.exist? this_path
end
- nil
+ return nil
end
##
@@ -143,18 +145,24 @@ command help for an example.
# get_path 'rake', '< 0.1' # nil
# get_path 'rak' # nil (exact name required)
#--
+ # TODO: This should be refactored so that it's a general service. I don't
+ # think any of our existing classes are the right place though. Just maybe
+ # 'Cache'?
+ #
+ # TODO: It just uses Gem.dir for now. What's an easy way to get the list of
+ # source directories?
def get_path(dependency)
- return dependency.name if /\.gem$/i.match?(dependency.name)
+ return dependency.name if dependency.name =~ /\.gem$/i
specs = dependency.matching_specs
- selected = specs.max_by(&:version)
+ selected = specs.max_by {|s| s.version }
return Gem::RemoteFetcher.fetcher.download_to_cache(dependency) unless
selected
- return unless /^#{selected.name}$/i.match?(dependency.name)
+ return unless dependency.name =~ /^#{selected.name}$/i
# We expect to find (basename).gem in the 'cache' directory. Furthermore,
# the name match must be exact (ignoring case).
diff --git a/lib/rubygems/commands/update_command.rb b/lib/rubygems/commands/update_command.rb
index 8e80d46856..6f084d1c38 100644
--- a/lib/rubygems/commands/update_command.rb
+++ b/lib/rubygems/commands/update_command.rb
@@ -21,7 +21,7 @@ class Gem::Commands::UpdateCommand < Gem::Command
def initialize
options = {
- force: false,
+ :force => false,
}
options.merge!(install_update_options)
@@ -37,10 +37,10 @@ class Gem::Commands::UpdateCommand < Gem::Command
end
add_option("--system [VERSION]", Gem::Version,
- "Update the RubyGems system software") do |value, opts|
- value ||= true
+ "Update the RubyGems system software") do |value, options|
+ value = true unless value
- opts[:system] = value
+ options[:system] = value
end
add_local_remote_options
@@ -120,7 +120,7 @@ command to remove old versions.
updated = update_gems gems_to_update
installed_names = highest_installed_gems.keys
- updated_names = updated.map(&:name)
+ updated_names = updated.map {|spec| spec.name }
not_updated_names = options[:args].uniq - updated_names
not_installed_names = not_updated_names - installed_names
up_to_date_names = not_updated_names - not_installed_names
@@ -128,10 +128,10 @@ command to remove old versions.
if updated.empty?
say "Nothing to update"
else
- say "Gems updated: #{updated_names.join(" ")}"
+ say "Gems updated: #{updated_names.join(' ')}"
end
- say "Gems already up-to-date: #{up_to_date_names.join(" ")}" unless up_to_date_names.empty?
- say "Gems not currently installed: #{not_installed_names.join(" ")}" unless not_installed_names.empty?
+ say "Gems already up-to-date: #{up_to_date_names.join(' ')}" unless up_to_date_names.empty?
+ say "Gems not currently installed: #{not_installed_names.join(' ')}" unless not_installed_names.empty?
end
def fetch_remote_gems(spec) # :nodoc:
@@ -186,9 +186,7 @@ command to remove old versions.
system Gem.ruby, "--disable-gems", "setup.rb", *args
end
- unless options[:silent]
- say "RubyGems system software updated" if installed
- end
+ say "RubyGems system software updated" if installed unless options[:silent]
end
end
@@ -197,17 +195,18 @@ command to remove old versions.
yield
else
require "tmpdir"
- Dir.mktmpdir("gem_update") do |tmpdir|
- FileUtils.mv Gem.plugindir, tmpdir
-
- status = yield
+ tmpdir = Dir.mktmpdir
+ FileUtils.mv Gem.plugindir, tmpdir
- unless status
- FileUtils.mv File.join(tmpdir, "plugins"), Gem.plugindir
- end
+ status = yield
- status
+ if status
+ FileUtils.rm_rf tmpdir
+ else
+ FileUtils.mv File.join(tmpdir, "plugins"), Gem.plugindir
end
+
+ status
end
end
@@ -232,7 +231,7 @@ command to remove old versions.
highest_remote_tup = highest_remote_name_tuple(rubygems_update)
target = highest_remote_tup ? highest_remote_tup.version : version
- [target, requirement]
+ return target, requirement
end
def update_gem(name, version = Gem::Requirement.default)
@@ -243,7 +242,7 @@ command to remove old versions.
@installer = Gem::DependencyInstaller.new update_options
- say "Updating #{name}" unless options[:system]
+ say "Updating #{name}" unless options[:system] && options[:silent]
begin
@installer.install name, Gem::Requirement.new(version)
rescue Gem::InstallError, Gem::DependencyError => e
@@ -281,7 +280,7 @@ command to remove old versions.
check_oldest_rubygems version
installed_gems = Gem::Specification.find_all_by_name "rubygems-update", requirement
- installed_gems = update_gem("rubygems-update", requirement) if installed_gems.empty? || installed_gems.first.version != version
+ installed_gems = update_gem("rubygems-update", version) if installed_gems.empty? || installed_gems.first.version != version
return if installed_gems.empty?
install_rubygems installed_gems.first
@@ -293,14 +292,16 @@ command to remove old versions.
args << "--prefix" << Gem.prefix if Gem.prefix
args << "--no-document" unless options[:document].include?("rdoc") || options[:document].include?("ri")
args << "--no-format-executable" if options[:no_format_executable]
- args << "--previous-version" << Gem::VERSION
+ args << "--previous-version" << Gem::VERSION if
+ options[:system] == true ||
+ Gem::Version.new(options[:system]) >= Gem::Version.new(2)
args
end
def which_to_update(highest_installed_gems, gem_names)
result = []
- highest_installed_gems.each do |_l_name, l_spec|
+ highest_installed_gems.each do |l_name, l_spec|
next if !gem_names.empty? &&
gem_names.none? {|name| name == l_spec.name }
@@ -325,8 +326,12 @@ command to remove old versions.
@oldest_supported_version ||=
if Gem.ruby_version > Gem::Version.new("3.1.a")
Gem::Version.new("3.3.3")
- else
+ elsif Gem.ruby_version > Gem::Version.new("3.0.a")
Gem::Version.new("3.2.3")
+ elsif Gem.ruby_version > Gem::Version.new("2.7.a")
+ Gem::Version.new("3.1.2")
+ else
+ Gem::Version.new("3.0.1")
end
end
end
diff --git a/lib/rubygems/commands/which_command.rb b/lib/rubygems/commands/which_command.rb
index 5ed4d9d142..ec464d9672 100644
--- a/lib/rubygems/commands/which_command.rb
+++ b/lib/rubygems/commands/which_command.rb
@@ -5,7 +5,7 @@ require_relative "../command"
class Gem::Commands::WhichCommand < Gem::Command
def initialize
super "which", "Find the location of a library file you can require",
- search_gems_first: false, show_all: false
+ :search_gems_first => false, :show_all => false
add_option "-a", "--[no-]all", "show all matching files" do |show_all, options|
options[:show_all] = show_all
diff --git a/lib/rubygems/commands/yank_command.rb b/lib/rubygems/commands/yank_command.rb
index fbdc262549..d344a020c3 100644
--- a/lib/rubygems/commands/yank_command.rb
+++ b/lib/rubygems/commands/yank_command.rb
@@ -62,7 +62,7 @@ data you will need to change them immediately and yank your gem.
end
def yank_gem(version, platform)
- say "Yanking gem from #{host}..."
+ say "Yanking gem from #{self.host}..."
args = [:delete, version, platform, "api/v1/gems/yank"]
response = yank_api_request(*args)
@@ -89,7 +89,7 @@ data you will need to change them immediately and yank your gem.
def get_version_from_requirements(requirements)
requirements.requirements.first[1].version
- rescue StandardError
+ rescue
nil
end
diff --git a/lib/rubygems/compatibility.rb b/lib/rubygems/compatibility.rb
index 0d9df56f8a..b4c1ef16fa 100644
--- a/lib/rubygems/compatibility.rb
+++ b/lib/rubygems/compatibility.rb
@@ -26,16 +26,17 @@ module Gem
rubylibdir
].freeze
- if defined?(ConfigMap)
- RbConfigPriorities.each do |key|
- ConfigMap[key.to_sym] = RbConfig::CONFIG[key]
- end
- else
+ unless defined?(ConfigMap)
##
# Configuration settings from ::RbConfig
ConfigMap = Hash.new do |cm, key|
cm[key] = RbConfig::CONFIG[key.to_s]
end
deprecate_constant(:ConfigMap)
+ else
+ RbConfigPriorities.each do |key|
+ ConfigMap[key.to_sym] = RbConfig::CONFIG[key]
+ end
end
+
end
diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb
index a2bcb6dfbc..68c653269e 100644
--- a/lib/rubygems/config_file.rb
+++ b/lib/rubygems/config_file.rb
@@ -47,8 +47,6 @@ class Gem::ConfigFile
DEFAULT_CONCURRENT_DOWNLOADS = 8
DEFAULT_CERT_EXPIRATION_LENGTH_DAYS = 365
DEFAULT_IPV4_FALLBACK_ENABLED = false
- # TODO: Use false as default value for this option in RubyGems 4.0
- DEFAULT_INSTALL_EXTENSION_IN_LIB = true
##
# For Ruby packagers to set configuration defaults. Set in
@@ -145,11 +143,6 @@ class Gem::ConfigFile
attr_accessor :cert_expiration_length_days
##
- # Install extensions into lib as well as into the extension directory.
-
- attr_accessor :install_extension_in_lib
-
- ##
# == Experimental ==
# Fallback to IPv4 when IPv6 is not reachable or slow (default: false)
@@ -190,16 +183,15 @@ class Gem::ConfigFile
@update_sources = DEFAULT_UPDATE_SOURCES
@concurrent_downloads = DEFAULT_CONCURRENT_DOWNLOADS
@cert_expiration_length_days = DEFAULT_CERT_EXPIRATION_LENGTH_DAYS
- @install_extension_in_lib = DEFAULT_INSTALL_EXTENSION_IN_LIB
@ipv4_fallback_enabled = ENV["IPV4_FALLBACK_ENABLED"] == "true" || DEFAULT_IPV4_FALLBACK_ENABLED
operating_system_config = Marshal.load Marshal.dump(OPERATING_SYSTEM_DEFAULTS)
platform_config = Marshal.load Marshal.dump(PLATFORM_DEFAULTS)
system_config = load_file SYSTEM_WIDE_CONFIG_FILE
- user_config = load_file config_file_name
+ user_config = load_file config_file_name.dup.tap(&Gem::UNTAINT)
- environment_config = (ENV["GEMRC"] || "").
- split(File::PATH_SEPARATOR).inject({}) do |result, file|
+ environment_config = (ENV["GEMRC"] || "")
+ .split(File::PATH_SEPARATOR).inject({}) do |result, file|
result.merge load_file file
end
@@ -210,34 +202,21 @@ class Gem::ConfigFile
@hash = @hash.merge environment_config
end
- @hash.transform_keys! do |k|
- # gemhome and gempath are not working with symbol keys
- if %w[backtrace bulk_threshold verbose update_sources cert_expiration_length_days
- install_extension_in_lib ipv4_fallback_enabled sources disable_default_gem_server
- ssl_verify_mode ssl_ca_cert ssl_client_cert].include?(k)
- k.to_sym
- else
- k
- end
- end
-
- # HACK: these override command-line args, which is bad
+ # HACK these override command-line args, which is bad
@backtrace = @hash[:backtrace] if @hash.key? :backtrace
@bulk_threshold = @hash[:bulk_threshold] if @hash.key? :bulk_threshold
- @verbose = @hash[:verbose] if @hash.key? :verbose
+ @home = @hash[:gemhome] if @hash.key? :gemhome
+ @path = @hash[:gempath] if @hash.key? :gempath
@update_sources = @hash[:update_sources] if @hash.key? :update_sources
- # TODO: We should handle concurrent_downloads same as other options
+ @verbose = @hash[:verbose] if @hash.key? :verbose
+ @disable_default_gem_server = @hash[:disable_default_gem_server] if @hash.key? :disable_default_gem_server
+ @sources = @hash[:sources] if @hash.key? :sources
@cert_expiration_length_days = @hash[:cert_expiration_length_days] if @hash.key? :cert_expiration_length_days
- @install_extension_in_lib = @hash[:install_extension_in_lib] if @hash.key? :install_extension_in_lib
@ipv4_fallback_enabled = @hash[:ipv4_fallback_enabled] if @hash.key? :ipv4_fallback_enabled
- @home = @hash[:gemhome] if @hash.key? :gemhome
- @path = @hash[:gempath] if @hash.key? :gempath
- @sources = @hash[:sources] if @hash.key? :sources
- @disable_default_gem_server = @hash[:disable_default_gem_server] if @hash.key? :disable_default_gem_server
- @ssl_verify_mode = @hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode
- @ssl_ca_cert = @hash[:ssl_ca_cert] if @hash.key? :ssl_ca_cert
- @ssl_client_cert = @hash[:ssl_client_cert] if @hash.key? :ssl_client_cert
+ @ssl_verify_mode = @hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode
+ @ssl_ca_cert = @hash[:ssl_ca_cert] if @hash.key? :ssl_ca_cert
+ @ssl_client_cert = @hash[:ssl_client_cert] if @hash.key? :ssl_client_cert
@api_keys = nil
@rubygems_api_key = nil
@@ -262,9 +241,9 @@ class Gem::ConfigFile
return if Gem.win_platform? # windows doesn't write 0600 as 0600
return unless File.exist? credentials_path
- existing_permissions = File.stat(credentials_path).mode & 0o777
+ existing_permissions = File.stat(credentials_path).mode & 0777
- return if existing_permissions == 0o600
+ return if existing_permissions == 0600
alert_error <<-ERROR
Your gem push credentials file located at:
@@ -345,9 +324,11 @@ if you believe they were disclosed to a third party.
require "fileutils"
FileUtils.mkdir_p(dirname)
- permissions = 0o600 & (~File.umask)
+ Gem.load_yaml
+
+ permissions = 0600 & (~File.umask)
File.open(credentials_path, "w", permissions) do |f|
- f.write self.class.dump_with_rubygems_yaml(config)
+ f.write config.to_yaml
end
load_api_keys # reload
@@ -363,18 +344,20 @@ if you believe they were disclosed to a third party.
end
def load_file(filename)
+ Gem.load_yaml
+
yaml_errors = [ArgumentError]
+ yaml_errors << Psych::SyntaxError if defined?(Psych::SyntaxError)
return {} unless filename && !filename.empty? && File.exist?(filename)
begin
- config = self.class.load_with_rubygems_config_hash(File.read(filename))
- if config.keys.any? {|k| k.to_s.gsub(%r{https?:\/\/}, "").include?(": ") }
+ content = Gem::SafeYAML.load(File.read(filename))
+ unless content.kind_of? Hash
warn "Failed to load #{filename} because it doesn't contain valid YAML hash"
return {}
- else
- return config
end
+ return content
rescue *yaml_errors => e
warn "Failed to load #{filename}, #{e}"
rescue Errno::EACCES
@@ -485,9 +468,6 @@ if you believe they were disclosed to a third party.
yaml_hash[:concurrent_downloads] =
@hash.fetch(:concurrent_downloads, DEFAULT_CONCURRENT_DOWNLOADS)
- yaml_hash[:install_extension_in_lib] =
- @hash.fetch(:install_extension_in_lib, DEFAULT_INSTALL_EXTENSION_IN_LIB)
-
yaml_hash[:ssl_verify_mode] =
@hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode
@@ -497,17 +477,17 @@ if you believe they were disclosed to a third party.
yaml_hash[:ssl_client_cert] =
@hash[:ssl_client_cert] if @hash.key? :ssl_client_cert
- keys = yaml_hash.keys.map(&:to_s)
+ keys = yaml_hash.keys.map {|key| key.to_s }
keys << "debug"
re = Regexp.union(*keys)
@hash.each do |key, value|
key = key.to_s
- next if key&.match?(re)
+ next if key =~ re
yaml_hash[key.to_s] = value
end
- self.class.dump_with_rubygems_yaml(yaml_hash)
+ yaml_hash.to_yaml
end
# Writes out this config file, replacing its source.
@@ -522,12 +502,12 @@ if you believe they were disclosed to a third party.
# Return the configuration information for +key+.
def [](key)
- @hash[key] || @hash[key.to_s]
+ @hash[key.to_s]
end
# Set configuration option +key+ to +value+.
def []=(key, value)
- @hash[key] = value
+ @hash[key.to_s] = value
end
def ==(other) # :nodoc:
@@ -542,64 +522,8 @@ if you believe they were disclosed to a third party.
attr_reader :hash
protected :hash
- def self.dump_with_rubygems_yaml(content)
- content.transform_keys! do |k|
- k.is_a?(Symbol) ? ":#{k}" : k
- end
-
- require_relative "yaml_serializer"
- Gem::YAMLSerializer.dump(content)
- end
-
- def self.load_with_rubygems_config_hash(yaml)
- require_relative "yaml_serializer"
-
- content = Gem::YAMLSerializer.load(yaml)
- deep_transform_config_keys!(content)
- end
-
private
- def self.deep_transform_config_keys!(config)
- config.transform_keys! do |k|
- if k.match?(/\A:(.*)\Z/)
- k[1..-1].to_sym
- elsif k.include?("__") || k.match?(%r{/\Z})
- if k.is_a?(Symbol)
- k.to_s.gsub(/__/,".").gsub(%r{/\Z}, "").to_sym
- else
- k.dup.gsub(/__/,".").gsub(%r{/\Z}, "")
- end
- else
- k
- end
- end
-
- config.transform_values! do |v|
- if v.is_a?(String)
- if v.match?(/\A:(.*)\Z/)
- v[1..-1].to_sym
- elsif v.match?(/\A[+-]?\d+\Z/)
- v.to_i
- elsif v.match?(/\Atrue|false\Z/)
- v == "true"
- elsif v.empty?
- nil
- else
- v
- end
- elsif v.empty?
- nil
- elsif v.is_a?(Hash)
- deep_transform_config_keys!(v)
- else
- v
- end
- end
-
- config
- end
-
def set_config_file_name(args)
@config_file_name = ENV["GEMRC"]
need_config_file_name = false
@@ -610,7 +534,7 @@ if you believe they were disclosed to a third party.
need_config_file_name = false
elsif arg =~ /^--config-file=(.*)/
@config_file_name = $1
- elsif /^--config-file$/.match?(arg)
+ elsif arg =~ /^--config-file$/
need_config_file_name = true
end
end
diff --git a/lib/rubygems/core_ext/kernel_gem.rb b/lib/rubygems/core_ext/kernel_gem.rb
index 4e09b95c44..b2f97b9ed9 100644
--- a/lib/rubygems/core_ext/kernel_gem.rb
+++ b/lib/rubygems/core_ext/kernel_gem.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
module Kernel
+
##
# Use Kernel#gem to activate a specific version of +gem_name+.
#
@@ -36,9 +37,9 @@ module Kernel
skip_list = (ENV["GEM_SKIP"] || "").split(/:/)
raise Gem::LoadError, "skipping #{gem_name}" if skip_list.include? gem_name
- if gem_name.is_a? Gem::Dependency
+ if gem_name.kind_of? Gem::Dependency
unless Gem::Deprecate.skip
- warn "#{Gem.location_of_caller.join ":"}:Warning: Kernel.gem no longer "\
+ warn "#{Gem.location_of_caller.join ':'}:Warning: Kernel.gem no longer "\
"accepts a Gem::Dependency object, please pass the name "\
"and requirements directly"
end
@@ -65,4 +66,5 @@ module Kernel
end
private :gem
+
end
diff --git a/lib/rubygems/core_ext/kernel_require.rb b/lib/rubygems/core_ext/kernel_require.rb
index 073966b696..0869c8746f 100644
--- a/lib/rubygems/core_ext/kernel_require.rb
+++ b/lib/rubygems/core_ext/kernel_require.rb
@@ -9,12 +9,13 @@
require "monitor"
module Kernel
+
RUBYGEMS_ACTIVATION_MONITOR = Monitor.new # :nodoc:
# Make sure we have a reference to Ruby's original Kernel#require
unless defined?(gem_original_require)
# :stopdoc:
- alias_method :gem_original_require, :require
+ alias gem_original_require require
private :gem_original_require
# :startdoc:
end
@@ -36,45 +37,53 @@ module Kernel
def require(path) # :doc:
return gem_original_require(path) unless Gem.discover_gems_on_require
- RUBYGEMS_ACTIVATION_MONITOR.synchronize do
- path = File.path(path)
-
- # If +path+ belongs to a default gem, we activate it and then go straight
- # to normal require
-
- if spec = Gem.find_default_spec(path)
- name = spec.name
+ begin
+ RUBYGEMS_ACTIVATION_MONITOR.enter
- next if Gem.loaded_specs[name]
+ path = path.to_path if path.respond_to? :to_path
+ if spec = Gem.find_unresolved_default_spec(path)
# Ensure -I beats a default gem
resolved_path = begin
rp = nil
load_path_check_index = Gem.load_path_insert_index - Gem.activated_gem_paths
- Gem.suffixes.find do |s|
- $LOAD_PATH[0...load_path_check_index].find do |lp|
- if File.symlink? lp # for backward compatibility
- next
+ Gem.suffixes.each do |s|
+ $LOAD_PATH[0...load_path_check_index].each do |lp|
+ safe_lp = lp.dup.tap(&Gem::UNTAINT)
+ begin
+ if File.symlink? safe_lp # for backward compatibility
+ next
+ end
+ rescue SecurityError
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ raise
end
- full_path = File.expand_path(File.join(lp, "#{path}#{s}"))
- rp = full_path if File.file?(full_path)
+ full_path = File.expand_path(File.join(safe_lp, "#{path}#{s}"))
+ if File.file?(full_path)
+ rp = full_path
+ break
+ end
end
+ break if rp
end
rp
end
- Kernel.send(:gem, name, Gem::Requirement.default_prerelease) unless
- resolved_path
-
- next
+ begin
+ Kernel.send(:gem, spec.name, Gem::Requirement.default_prerelease)
+ rescue Exception
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ raise
+ end unless resolved_path
end
# If there are no unresolved deps, then we can use just try
# normal require handle loading a gem from the rescue below.
if Gem::Specification.unresolved_deps.empty?
- next
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ return gem_original_require(path)
end
# If +path+ is for a gem that has already been loaded, don't
@@ -84,7 +93,8 @@ module Kernel
# TODO request access to the C implementation of this to speed up RubyGems
if Gem::Specification.find_active_stub_by_path(path)
- next
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ return gem_original_require(path)
end
# Attempt to find +path+ in any unresolved gems...
@@ -104,7 +114,9 @@ module Kernel
if found_specs.empty?
found_specs = Gem::Specification.find_in_unresolved_tree path
- found_specs.each(&:activate)
+ found_specs.each do |found_spec|
+ found_spec.activate
+ end
# We found +path+ directly in an unresolved gem. Now we figure out, of
# the possible found specs, which one we should activate.
@@ -115,7 +127,8 @@ module Kernel
names = found_specs.map(&:name).uniq
if names.size > 1
- raise Gem::LoadError, "#{path} found in multiple gems: #{names.join ", "}"
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ raise Gem::LoadError, "#{path} found in multiple gems: #{names.join ', '}"
end
# Ok, now find a gem that has no conflicts, starting
@@ -125,20 +138,26 @@ module Kernel
unless valid
le = Gem::LoadError.new "unable to find a version of '#{names.first}' to activate"
le.name = names.first
+ RUBYGEMS_ACTIVATION_MONITOR.exit
raise le
end
valid.activate
end
- end
- begin
- gem_original_require(path)
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ return gem_original_require(path)
rescue LoadError => load_error
- if load_error.path == path &&
- RUBYGEMS_ACTIVATION_MONITOR.synchronize { Gem.try_activate(path) }
+ if load_error.path == path
+ RUBYGEMS_ACTIVATION_MONITOR.enter
- return gem_original_require(path)
+ begin
+ require_again = Gem.try_activate(path)
+ ensure
+ RUBYGEMS_ACTIVATION_MONITOR.exit
+ end
+
+ return gem_original_require(path) if require_again
end
raise load_error
@@ -146,4 +165,5 @@ module Kernel
end
private :require
+
end
diff --git a/lib/rubygems/core_ext/kernel_warn.rb b/lib/rubygems/core_ext/kernel_warn.rb
index f806b77fab..1f4c77f04b 100644
--- a/lib/rubygems/core_ext/kernel_warn.rb
+++ b/lib/rubygems/core_ext/kernel_warn.rb
@@ -13,7 +13,11 @@ module Kernel
module_function define_method(:warn) {|*messages, **kw|
unless uplevel = kw[:uplevel]
- return original_warn.bind_call(self, *messages, **kw)
+ if Gem.java_platform? && RUBY_VERSION < "3.1"
+ return original_warn.bind(self).call(*messages)
+ else
+ return original_warn.bind(self).call(*messages, **kw)
+ end
end
# Ensure `uplevel` fits a `long`
@@ -31,15 +35,16 @@ module Kernel
start += 1
- next unless path = loc.path
- unless path.start_with?(rubygems_path, "<internal:")
- # Non-rubygems frames
- uplevel -= 1
+ if path = loc.path
+ unless path.start_with?(rubygems_path) || path.start_with?("<internal:")
+ # Non-rubygems frames
+ uplevel -= 1
+ end
end
end
kw[:uplevel] = start
end
- original_warn.bind_call(self, *messages, **kw)
+ original_warn.bind(self).call(*messages, **kw)
}
end
diff --git a/lib/rubygems/core_ext/tcpsocket_init.rb b/lib/rubygems/core_ext/tcpsocket_init.rb
index 018c49dbeb..451ffa50b2 100644
--- a/lib/rubygems/core_ext/tcpsocket_init.rb
+++ b/lib/rubygems/core_ext/tcpsocket_init.rb
@@ -19,7 +19,7 @@ module CoreExtensions
cond_var = Thread::ConditionVariable.new
Addrinfo.foreach(host, serv, nil, :STREAM) do |addr|
- Thread.report_on_exception = false
+ Thread.report_on_exception = false if defined? Thread.report_on_exception = ()
threads << Thread.new(addr) do
# give head start to ipv6 addresses
diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb
index 1bd208feb9..2b1baa333d 100644
--- a/lib/rubygems/defaults.rb
+++ b/lib/rubygems/defaults.rb
@@ -24,7 +24,7 @@ module Gem
default_spec_cache_dir = File.join Gem.user_home, ".gem", "specs"
unless File.exist?(default_spec_cache_dir)
- default_spec_cache_dir = File.join Gem.cache_home, "gem", "specs"
+ default_spec_cache_dir = File.join Gem.data_home, "gem", "specs"
end
default_spec_cache_dir
@@ -80,7 +80,7 @@ module Gem
def self.find_home
Dir.home.dup
- rescue StandardError
+ rescue
if Gem.win_platform?
File.expand_path File.join(ENV["HOMEDRIVE"] || ENV["SystemDrive"], "/")
else
@@ -94,7 +94,7 @@ module Gem
# The home directory for the user.
def self.user_home
- @user_home ||= find_home
+ @user_home ||= find_home.tap(&Gem::UNTAINT)
end
##
@@ -112,7 +112,7 @@ module Gem
# The path to standard location of the user's configuration directory.
def self.config_home
- @config_home ||= ENV["XDG_CONFIG_HOME"] || File.join(Gem.user_home, ".config")
+ @config_home ||= (ENV["XDG_CONFIG_HOME"] || File.join(Gem.user_home, ".config"))
end
##
@@ -131,35 +131,35 @@ module Gem
# The path to standard location of the user's .gemrc file.
def self.config_file
- @config_file ||= find_config_file
+ @config_file ||= find_config_file.tap(&Gem::UNTAINT)
end
##
# The path to standard location of the user's state file.
def self.state_file
- @state_file ||= File.join(Gem.state_home, "gem", "last_update_check")
+ @state_file ||= File.join(Gem.state_home, "gem", "last_update_check").tap(&Gem::UNTAINT)
end
##
# The path to standard location of the user's cache directory.
def self.cache_home
- @cache_home ||= ENV["XDG_CACHE_HOME"] || File.join(Gem.user_home, ".cache")
+ @cache_home ||= (ENV["XDG_CACHE_HOME"] || File.join(Gem.user_home, ".cache"))
end
##
# The path to standard location of the user's data directory.
def self.data_home
- @data_home ||= ENV["XDG_DATA_HOME"] || File.join(Gem.user_home, ".local", "share")
+ @data_home ||= (ENV["XDG_DATA_HOME"] || File.join(Gem.user_home, ".local", "share"))
end
##
# The path to standard location of the user's state directory.
def self.state_home
- @state_home ||= ENV["XDG_STATE_HOME"] || File.join(Gem.user_home, ".local", "state")
+ @state_home ||= (ENV["XDG_STATE_HOME"] || File.join(Gem.user_home, ".local", "state"))
end
##
@@ -184,11 +184,7 @@ module Gem
# Deduce Ruby's --program-prefix and --program-suffix from its install name
def self.default_exec_format
- exec_format = begin
- RbConfig::CONFIG["ruby_install_name"].sub("ruby", "%s")
- rescue StandardError
- "%s"
- end
+ exec_format = RbConfig::CONFIG["ruby_install_name"].sub("ruby", "%s") rescue "%s"
unless exec_format.include?("%s")
raise Gem::Exception,
@@ -236,22 +232,10 @@ module Gem
end
##
- # Enables automatic installation into user directory
-
- def self.default_user_install # :nodoc:
- if !ENV.key?("GEM_HOME") && (File.exist?(Gem.dir) && !File.writable?(Gem.dir))
- Gem.ui.say "Defaulting to user installation because default installation directory (#{Gem.dir}) is not writable."
- return true
- end
-
- false
- end
-
- ##
# Install extensions into lib as well as into the extension directory.
def self.install_extension_in_lib # :nodoc:
- Gem.configuration.install_extension_in_lib
+ true
end
##
diff --git a/lib/rubygems/dependency.rb b/lib/rubygems/dependency.rb
index ecb4824d7e..d9e0c07b0f 100644
--- a/lib/rubygems/dependency.rb
+++ b/lib/rubygems/dependency.rb
@@ -46,10 +46,10 @@ class Gem::Dependency
end
type = Symbol === requirements.last ? requirements.pop : :runtime
- requirements = requirements.first if requirements.length == 1 # unpack
+ requirements = requirements.first if 1 == requirements.length # unpack
unless TYPES.include? type
- raise ArgumentError, "Valid types are #{TYPES.inspect}, " \
+ raise ArgumentError, "Valid types are #{TYPES.inspect}, " +
"not #{type.inspect}"
end
@@ -74,9 +74,11 @@ class Gem::Dependency
def inspect # :nodoc:
if prerelease?
- format("<%s type=%p name=%p requirements=%p prerelease=ok>", self.class, type, name, requirement.to_s)
+ "<%s type=%p name=%p requirements=%p prerelease=ok>" %
+ [self.class, self.type, self.name, requirement.to_s]
else
- format("<%s type=%p name=%p requirements=%p>", self.class, type, name, requirement.to_s)
+ "<%s type=%p name=%p requirements=%p>" %
+ [self.class, self.type, self.name, requirement.to_s]
end
end
@@ -167,16 +169,16 @@ class Gem::Dependency
def ==(other) # :nodoc:
Gem::Dependency === other &&
- name == other.name &&
- type == other.type &&
- requirement == other.requirement
+ self.name == other.name &&
+ self.type == other.type &&
+ self.requirement == other.requirement
end
##
# Dependencies are ordered by name.
def <=>(other)
- name <=> other.name
+ self.name <=> other.name
end
##
@@ -203,7 +205,7 @@ class Gem::Dependency
requirement.satisfied_by? version
end
- alias_method :===, :=~
+ alias === =~
##
# :call-seq:
@@ -261,7 +263,7 @@ class Gem::Dependency
end
default = Gem::Requirement.default
- self_req = requirement
+ self_req = self.requirement
other_req = other.requirement
return self.class.new name, self_req if other_req == default
@@ -271,7 +273,15 @@ class Gem::Dependency
end
def matching_specs(platform_only = false)
- matches = Gem::Specification.find_all_by_name(name, requirement)
+ env_req = Gem.env_requirement(name)
+ matches = Gem::Specification.stubs_for(name).find_all do |spec|
+ requirement.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version)
+ end.map(&:to_spec)
+
+ if prioritizes_bundler?
+ require_relative "bundler_version_finder"
+ Gem::BundlerVersionFinder.prioritize!(matches)
+ end
if platform_only
matches.reject! do |spec|
@@ -289,6 +299,10 @@ class Gem::Dependency
@requirement.specific?
end
+ def prioritizes_bundler?
+ name == "bundler" && !specific?
+ end
+
def to_specs
matches = matching_specs true
@@ -310,15 +324,15 @@ class Gem::Dependency
end
def to_spec
- matches = to_specs.compact
+ matches = self.to_specs.compact
- active = matches.find(&:activated?)
+ active = matches.find {|spec| spec.activated? }
return active if active
unless prerelease?
- # Consider prereleases only as a fallback
+ # Move prereleases to the end of the list for >= 0 requirements
pre, matches = matches.partition {|spec| spec.version.prerelease? }
- matches = pre if matches.empty?
+ matches += pre if requirement == Gem::Requirement.default
end
matches.first
@@ -337,12 +351,4 @@ class Gem::Dependency
:released
end
end
-
- def encode_with(coder) # :nodoc:
- coder.add "name", @name
- coder.add "requirement", @requirement
- coder.add "type", @type
- coder.add "prerelease", @prerelease
- coder.add "version_requirements", @version_requirements
- end
end
diff --git a/lib/rubygems/dependency_installer.rb b/lib/rubygems/dependency_installer.rb
index b119dca1cf..a8d73e521b 100644
--- a/lib/rubygems/dependency_installer.rb
+++ b/lib/rubygems/dependency_installer.rb
@@ -17,18 +17,18 @@ class Gem::DependencyInstaller
extend Gem::Deprecate
DEFAULT_OPTIONS = { # :nodoc:
- env_shebang: false,
- document: %w[ri],
- domain: :both, # HACK: dup
- force: false,
- format_executable: false, # HACK: dup
- ignore_dependencies: false,
- prerelease: false,
- security_policy: nil, # HACK: NoSecurity requires OpenSSL. AlmostNo? Low?
- wrappers: true,
- build_args: nil,
- build_docs_in_background: false,
- install_as_default: false,
+ :env_shebang => false,
+ :document => %w[ri],
+ :domain => :both, # HACK dup
+ :force => false,
+ :format_executable => false, # HACK dup
+ :ignore_dependencies => false,
+ :prerelease => false,
+ :security_policy => nil, # HACK NoSecurity requires OpenSSL. AlmostNo? Low?
+ :wrappers => true,
+ :build_args => nil,
+ :build_docs_in_background => false,
+ :install_as_default => false,
}.freeze
##
@@ -66,7 +66,7 @@ class Gem::DependencyInstaller
# :build_args:: See Gem::Installer::new
def initialize(options = {})
- @only_install_dir = !options[:install_dir].nil?
+ @only_install_dir = !!options[:install_dir]
@install_dir = options[:install_dir] || Gem.dir
@build_root = options[:build_root]
@@ -163,11 +163,13 @@ class Gem::DependencyInstaller
specs = []
tuples.each do |tup, source|
- spec = source.fetch_spec(tup)
- rescue Gem::RemoteFetcher::FetchError => e
- errors << Gem::SourceFetchProblem.new(source, e)
- else
- specs << [spec, source]
+ begin
+ spec = source.fetch_spec(tup)
+ rescue Gem::RemoteFetcher::FetchError => e
+ errors << Gem::SourceFetchProblem.new(source, e)
+ else
+ specs << [spec, source]
+ end
end
if @errors
@@ -177,6 +179,7 @@ class Gem::DependencyInstaller
end
set << specs
+
rescue Gem::RemoteFetcher::FetchError => e
# FIX if there is a problem talking to the network, we either need to always tell
# the user (no really_verbose) or fail hard, not silently tell them that we just
@@ -228,22 +231,22 @@ class Gem::DependencyInstaller
@installed_gems = []
options = {
- bin_dir: @bin_dir,
- build_args: @build_args,
- document: @document,
- env_shebang: @env_shebang,
- force: @force,
- format_executable: @format_executable,
- ignore_dependencies: @ignore_dependencies,
- prerelease: @prerelease,
- security_policy: @security_policy,
- user_install: @user_install,
- wrappers: @wrappers,
- build_root: @build_root,
- install_as_default: @install_as_default,
- dir_mode: @dir_mode,
- data_mode: @data_mode,
- prog_mode: @prog_mode,
+ :bin_dir => @bin_dir,
+ :build_args => @build_args,
+ :document => @document,
+ :env_shebang => @env_shebang,
+ :force => @force,
+ :format_executable => @format_executable,
+ :ignore_dependencies => @ignore_dependencies,
+ :prerelease => @prerelease,
+ :security_policy => @security_policy,
+ :user_install => @user_install,
+ :wrappers => @wrappers,
+ :build_root => @build_root,
+ :install_as_default => @install_as_default,
+ :dir_mode => @dir_mode,
+ :data_mode => @data_mode,
+ :prog_mode => @prog_mode,
}
options[:install_dir] = @install_dir if @only_install_dir
@@ -291,11 +294,13 @@ class Gem::DependencyInstaller
src = Gem::Source::SpecificFile.new dep_or_name
installer_set.add_local dep_or_name, src.spec, src
version = src.spec.version if version == Gem::Requirement.default
- elsif dep_or_name =~ /\.gem$/ # rubocop:disable Performance/RegexpMatch
+ elsif dep_or_name =~ /\.gem$/
Dir[dep_or_name].each do |name|
- src = Gem::Source::SpecificFile.new name
- installer_set.add_local dep_or_name, src.spec, src
- rescue Gem::Package::FormatError
+ begin
+ src = Gem::Source::SpecificFile.new name
+ installer_set.add_local dep_or_name, src.spec, src
+ rescue Gem::Package::FormatError
+ end
end
# else This is a dependency. InstallerSet handles this case
end
diff --git a/lib/rubygems/dependency_list.rb b/lib/rubygems/dependency_list.rb
index ad5e59e8c1..5820298bb9 100644
--- a/lib/rubygems/dependency_list.rb
+++ b/lib/rubygems/dependency_list.rb
@@ -6,7 +6,7 @@
# See LICENSE.txt for permissions.
#++
-require_relative "vendored_tsort"
+require_relative "tsort"
require_relative "deprecate"
##
@@ -105,7 +105,7 @@ class Gem::DependencyList
end
def inspect # :nodoc:
- format("%s %p>", super[0..-2], map(&:full_name))
+ "%s %p>" % [super[0..-2], map {|s| s.full_name }]
end
##
diff --git a/lib/rubygems/deprecate.rb b/lib/rubygems/deprecate.rb
index 7d24f9cbfc..9fff306949 100644
--- a/lib/rubygems/deprecate.rb
+++ b/lib/rubygems/deprecate.rb
@@ -69,101 +69,97 @@
# end
# end
-module Gem
- module Deprecate
- def self.skip # :nodoc:
- @skip ||= false
- end
+module Gem::Deprecate
- def self.skip=(v) # :nodoc:
- @skip = v
- end
+ def self.skip # :nodoc:
+ @skip ||= false
+ end
- ##
- # Temporarily turn off warnings. Intended for tests only.
+ def self.skip=(v) # :nodoc:
+ @skip = v
+ end
- def skip_during
- original = Gem::Deprecate.skip
- Gem::Deprecate.skip = true
- yield
- ensure
- Gem::Deprecate.skip = original
- end
+ ##
+ # Temporarily turn off warnings. Intended for tests only.
- def self.next_rubygems_major_version # :nodoc:
- Gem::Version.new(Gem.rubygems_version.segments.first).bump
- end
+ def skip_during
+ Gem::Deprecate.skip, original = true, Gem::Deprecate.skip
+ yield
+ ensure
+ Gem::Deprecate.skip = original
+ end
+
+ def self.next_rubygems_major_version # :nodoc:
+ Gem::Version.new(Gem.rubygems_version.segments.first).bump
+ end
+
+ ##
+ # Simple deprecation method that deprecates +name+ by wrapping it up
+ # in a dummy method. It warns on each call to the dummy method
+ # telling the user of +repl+ (unless +repl+ is :none) and the
+ # year/month that it is planned to go away.
- ##
- # Simple deprecation method that deprecates +name+ by wrapping it up
- # in a dummy method. It warns on each call to the dummy method
- # telling the user of +repl+ (unless +repl+ is :none) and the
- # year/month that it is planned to go away.
-
- def deprecate(name, repl, year, month)
- class_eval do
- old = "_deprecated_#{name}"
- alias_method old, name
- define_method name do |*args, &block|
- klass = is_a? Module
- target = klass ? "#{self}." : "#{self.class}#"
- msg = [
- "NOTE: #{target}#{name} is deprecated",
- repl == :none ? " with no replacement" : "; use #{repl} instead",
- format(". It will be removed on or after %4d-%02d.", year, month),
- "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
- ]
- warn "#{msg.join}." unless Gem::Deprecate.skip
- send old, *args, &block
- end
- ruby2_keywords name if respond_to?(:ruby2_keywords, true)
+ def deprecate(name, repl, year, month)
+ class_eval do
+ old = "_deprecated_#{name}"
+ alias_method old, name
+ define_method name do |*args, &block|
+ klass = self.kind_of? Module
+ target = klass ? "#{self}." : "#{self.class}#"
+ msg = [ "NOTE: #{target}#{name} is deprecated",
+ repl == :none ? " with no replacement" : "; use #{repl} instead",
+ ". It will be removed on or after %4d-%02d." % [year, month],
+ "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
+ ]
+ warn "#{msg.join}." unless Gem::Deprecate.skip
+ send old, *args, &block
end
+ ruby2_keywords name if respond_to?(:ruby2_keywords, true)
end
+ end
+
+ ##
+ # Simple deprecation method that deprecates +name+ by wrapping it up
+ # in a dummy method. It warns on each call to the dummy method
+ # telling the user of +repl+ (unless +repl+ is :none) and the
+ # Rubygems version that it is planned to go away.
- ##
- # Simple deprecation method that deprecates +name+ by wrapping it up
- # in a dummy method. It warns on each call to the dummy method
- # telling the user of +repl+ (unless +repl+ is :none) and the
- # Rubygems version that it is planned to go away.
-
- def rubygems_deprecate(name, replacement=:none)
- class_eval do
- old = "_deprecated_#{name}"
- alias_method old, name
- define_method name do |*args, &block|
- klass = is_a? Module
- target = klass ? "#{self}." : "#{self.class}#"
- msg = [
- "NOTE: #{target}#{name} is deprecated",
- replacement == :none ? " with no replacement" : "; use #{replacement} instead",
- ". It will be removed in Rubygems #{Gem::Deprecate.next_rubygems_major_version}",
- "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
- ]
- warn "#{msg.join}." unless Gem::Deprecate.skip
- send old, *args, &block
- end
- ruby2_keywords name if respond_to?(:ruby2_keywords, true)
+ def rubygems_deprecate(name, replacement=:none)
+ class_eval do
+ old = "_deprecated_#{name}"
+ alias_method old, name
+ define_method name do |*args, &block|
+ klass = self.kind_of? Module
+ target = klass ? "#{self}." : "#{self.class}#"
+ msg = [ "NOTE: #{target}#{name} is deprecated",
+ replacement == :none ? " with no replacement" : "; use #{replacement} instead",
+ ". It will be removed in Rubygems #{Gem::Deprecate.next_rubygems_major_version}",
+ "\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
+ ]
+ warn "#{msg.join}." unless Gem::Deprecate.skip
+ send old, *args, &block
end
+ ruby2_keywords name if respond_to?(:ruby2_keywords, true)
end
+ end
- # Deprecation method to deprecate Rubygems commands
- def rubygems_deprecate_command(version = Gem::Deprecate.next_rubygems_major_version)
- class_eval do
- define_method "deprecated?" do
- true
- end
-
- define_method "deprecation_warning" do
- msg = [
- "#{command} command is deprecated",
- ". It will be removed in Rubygems #{version}.\n",
- ]
-
- alert_warning msg.join.to_s unless Gem::Deprecate.skip
- end
+ # Deprecation method to deprecate Rubygems commands
+ def rubygems_deprecate_command(version = Gem::Deprecate.next_rubygems_major_version)
+ class_eval do
+ define_method "deprecated?" do
+ true
end
- end
- module_function :rubygems_deprecate, :rubygems_deprecate_command, :skip_during
+ define_method "deprecation_warning" do
+ msg = [ "#{self.command} command is deprecated",
+ ". It will be removed in Rubygems #{version}.\n",
+ ]
+
+ alert_warning "#{msg.join}" unless Gem::Deprecate.skip
+ end
+ end
end
+
+ module_function :rubygems_deprecate, :rubygems_deprecate_command, :skip_during
+
end
diff --git a/lib/rubygems/doctor.rb b/lib/rubygems/doctor.rb
index 56b7c081eb..1d3889af77 100644
--- a/lib/rubygems/doctor.rb
+++ b/lib/rubygems/doctor.rb
@@ -33,7 +33,7 @@ class Gem::Doctor
Gem::REPOSITORY_SUBDIRECTORIES.sort -
REPOSITORY_EXTENSION_MAP.map {|(k,_)| k }.sort
- raise "Update REPOSITORY_EXTENSION_MAP, missing: #{missing.join ", "}" unless
+ raise "Update REPOSITORY_EXTENSION_MAP, missing: #{missing.join ', '}" unless
missing.empty?
##
@@ -53,7 +53,7 @@ class Gem::Doctor
# Specs installed in this gem repository
def installed_specs # :nodoc:
- @installed_specs ||= Gem::Specification.map(&:full_name)
+ @installed_specs ||= Gem::Specification.map {|s| s.full_name }
end
##
@@ -75,7 +75,7 @@ class Gem::Doctor
Gem.use_paths @gem_repository.to_s
unless gem_repository?
- say "This directory does not appear to be a RubyGems repository, " \
+ say "This directory does not appear to be a RubyGems repository, " +
"skipping"
say
return
@@ -104,16 +104,16 @@ class Gem::Doctor
directory = File.join(@gem_repository, sub_directory)
Dir.entries(directory).sort.each do |ent|
- next if [".", ".."].include?(ent)
+ next if ent == "." || ent == ".."
child = File.join(directory, ent)
next unless File.exist?(child)
basename = File.basename(child, extension)
next if installed_specs.include? basename
- next if /^rubygems-\d/.match?(basename)
- next if sub_directory == "specifications" && basename == "default"
- next if sub_directory == "plugins" && Gem.plugin_suffix_regexp =~ (basename)
+ next if /^rubygems-\d/ =~ basename
+ next if "specifications" == sub_directory && "default" == basename
+ next if "plugins" == sub_directory && Gem.plugin_suffix_regexp =~ (basename)
type = File.directory?(child) ? "directory" : "file"
diff --git a/lib/rubygems/errors.rb b/lib/rubygems/errors.rb
index 57fb3eb120..b36fabffc2 100644
--- a/lib/rubygems/errors.rb
+++ b/lib/rubygems/errors.rb
@@ -30,7 +30,6 @@ module Gem
@name = name
@requirement = requirement
@extra_message = extra_message
- super(message)
end
def message # :nodoc:
@@ -54,15 +53,15 @@ module Gem
attr_reader :specs
def initialize(name, requirement, specs)
- @specs = specs
super(name, requirement)
+ @specs = specs
end
private
def build_message
names = specs.map(&:full_name)
- "Could not find '#{name}' (#{requirement}) - did find: [#{names.join ","}]\n"
+ "Could not find '#{name}' (#{requirement}) - did find: [#{names.join ','}]\n"
end
end
@@ -135,7 +134,11 @@ module Gem
##
# A wordy description of the error.
def wordy
- format("Found %s (%s), but was for platform%s %s", @name, @version, @platforms.size == 1 ? "" : "s", @platforms.join(" ,"))
+ "Found %s (%s), but was for platform%s %s" %
+ [@name,
+ @version,
+ @platforms.size == 1 ? "" : "s",
+ @platforms.join(" ,")]
end
end
@@ -172,6 +175,6 @@ module Gem
##
# The "exception" alias allows you to call raise on a SourceFetchProblem.
- alias_method :exception, :error
+ alias exception error
end
end
diff --git a/lib/rubygems/exceptions.rb b/lib/rubygems/exceptions.rb
index 793324b875..b92396f0ef 100644
--- a/lib/rubygems/exceptions.rb
+++ b/lib/rubygems/exceptions.rb
@@ -104,6 +104,9 @@ end
class Gem::GemNotFoundException < Gem::Exception; end
+##
+# Raised by the DependencyInstaller when a specific gem cannot be found
+
class Gem::SpecificGemNotFoundException < Gem::GemNotFoundException
##
# Creates a new SpecificGemNotFoundException for a gem with the given +name+
@@ -134,8 +137,6 @@ class Gem::SpecificGemNotFoundException < Gem::GemNotFoundException
attr_reader :errors
end
-Gem.deprecate_constant :SpecificGemNotFoundException
-
##
# Raised by Gem::Resolver when dependencies conflict and create the
# inability to find a valid possible spec for a request.
@@ -171,7 +172,6 @@ class Gem::ImpossibleDependenciesError < Gem::Exception
end
class Gem::InstallError < Gem::Exception; end
-
class Gem::RuntimeRequirementNotMetError < Gem::InstallError
attr_accessor :suggestion
def message
@@ -231,7 +231,7 @@ class Gem::SystemExitException < SystemExit
##
# The exit code for the process
- alias_method :exit_code, :status
+ alias exit_code status
##
# Creates a new SystemExitException with the given +exit_code+
@@ -264,7 +264,7 @@ class Gem::UnsatisfiableDependencyError < Gem::DependencyError
def initialize(dep, platform_mismatch=nil)
if platform_mismatch && !platform_mismatch.empty?
plats = platform_mismatch.map {|x| x.platform.to_s }.sort.uniq
- super "Unable to resolve dependency: No match for '#{dep}' on this platform. Found: #{plats.join(", ")}"
+ super "Unable to resolve dependency: No match for '#{dep}' on this platform. Found: #{plats.join(', ')}"
else
if dep.explicit?
super "Unable to resolve dependency: user requested '#{dep}'"
@@ -291,3 +291,9 @@ class Gem::UnsatisfiableDependencyError < Gem::DependencyError
@dependency.requirement
end
end
+
+##
+# Backwards compatible typo'd exception class for early RubyGems 2.0.x
+
+Gem::UnsatisfiableDepedencyError = Gem::UnsatisfiableDependencyError # :nodoc:
+Gem.deprecate_constant :UnsatisfiableDepedencyError
diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb
index 12eb62ef16..4960ddd7b1 100644
--- a/lib/rubygems/ext/builder.rb
+++ b/lib/rubygems/ext/builder.rb
@@ -19,26 +19,27 @@ class Gem::Ext::Builder
$1.downcase
end
- def self.make(dest_path, results, make_dir = Dir.pwd, sitedir = nil, targets = ["clean", "", "install"],
- target_rbconfig: Gem.target_rbconfig)
+ def self.make(dest_path, results, make_dir = Dir.pwd, sitedir = nil, targets = ["clean", "", "install"])
unless File.exist? File.join(make_dir, "Makefile")
raise Gem::InstallError, "Makefile not found"
end
# try to find make program from Ruby configure arguments first
- target_rbconfig["configure_args"] =~ /with-make-prog\=(\w+)/
+ RbConfig::CONFIG["configure_args"] =~ /with-make-prog\=(\w+)/
make_program_name = ENV["MAKE"] || ENV["make"] || $1
- make_program_name ||= RUBY_PLATFORM.include?("mswin") ? "nmake" : "make"
+ unless make_program_name
+ make_program_name = (RUBY_PLATFORM.include?("mswin")) ? "nmake" : "make"
+ end
make_program = Shellwords.split(make_program_name)
# The installation of the bundled gems is failed when DESTDIR is empty in mswin platform.
- destdir = /\bnmake/i !~ make_program_name || ENV["DESTDIR"] && ENV["DESTDIR"] != "" ? format("DESTDIR=%s", ENV["DESTDIR"]) : ""
+ destdir = (/\bnmake/i !~ make_program_name || ENV["DESTDIR"] && ENV["DESTDIR"] != "") ? "DESTDIR=%s" % ENV["DESTDIR"] : ""
env = [destdir]
if sitedir
- env << format("sitearchdir=%s", sitedir)
- env << format("sitelibdir=%s", sitedir)
+ env << "sitearchdir=%s" % sitedir
+ env << "sitelibdir=%s" % sitedir
end
targets.each do |target|
@@ -76,8 +77,7 @@ class Gem::Ext::Builder
verbose = Gem.configuration.really_verbose
begin
- rubygems_gemdeps = ENV["RUBYGEMS_GEMDEPS"]
- ENV["RUBYGEMS_GEMDEPS"] = nil
+ rubygems_gemdeps, ENV["RUBYGEMS_GEMDEPS"] = ENV["RUBYGEMS_GEMDEPS"], nil
if verbose
puts("current directory: #{dir}")
p(command)
@@ -89,20 +89,13 @@ class Gem::Ext::Builder
# Set $SOURCE_DATE_EPOCH for the subprocess.
build_env = { "SOURCE_DATE_EPOCH" => Gem.source_date_epoch_string }.merge(env)
output, status = begin
- Open3.popen2e(build_env, *command, chdir: dir) do |_stdin, stdouterr, wait_thread|
- output = String.new
- while line = stdouterr.gets
- output << line
- if verbose
- print line
- end
- end
- [output, wait_thread.value]
- end
- rescue StandardError => error
+ Open3.capture2e(build_env, *command, :chdir => dir)
+ rescue => error
raise Gem::InstallError, "#{command_name || class_name} failed#{error.message}"
end
- unless verbose
+ if verbose
+ puts output
+ else
results << output
end
ensure
@@ -132,11 +125,10 @@ class Gem::Ext::Builder
# have build arguments, saved, set +build_args+ which is an ARGV-style
# array.
- def initialize(spec, build_args = spec.build_args, target_rbconfig = Gem.target_rbconfig)
+ def initialize(spec, build_args = spec.build_args)
@spec = spec
@build_args = build_args
@gem_dir = spec.full_gem_path
- @target_rbconfig = target_rbconfig
@ran_rake = false
end
@@ -193,12 +185,12 @@ EOF
FileUtils.mkdir_p dest_path
results = builder.build(extension, dest_path,
- results, @build_args, lib_dir, extension_dir, @target_rbconfig)
+ results, @build_args, lib_dir, extension_dir)
verbose { results.join("\n") }
write_gem_make_out results.join "\n"
- rescue StandardError => e
+ rescue => e
results << e.message
build_error(results.join("\n"), $@)
end
@@ -214,7 +206,7 @@ EOF
if @build_args.empty?
say "Building native extensions. This could take a while..."
else
- say "Building native extensions with: '#{@build_args.join " "}'"
+ say "Building native extensions with: '#{@build_args.join ' '}'"
say "This could take a while..."
end
diff --git a/lib/rubygems/ext/cargo_builder.rb b/lib/rubygems/ext/cargo_builder.rb
index 81b28c3c77..ce3b296f79 100644
--- a/lib/rubygems/ext/cargo_builder.rb
+++ b/lib/rubygems/ext/cargo_builder.rb
@@ -16,15 +16,10 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
@profile = :release
end
- def build(extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd,
- target_rbconfig=Gem.target_rbconfig)
+ def build(extension, dest_path, results, args = [], lib_dir = nil, cargo_dir = Dir.pwd)
require "tempfile"
require "fileutils"
- if target_rbconfig.path
- warn "--target-rbconfig is not yet supported for Rust extensions. Ignoring"
- end
-
# Where's the Cargo.toml of the crate we're building
cargo_toml = File.join(cargo_dir, "Cargo.toml")
# What's the crate's name
@@ -52,6 +47,7 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
nesting = extension_nesting(extension)
+ # TODO: remove in RubyGems 4
if Gem.install_extension_in_lib && lib_dir
nested_lib_dir = File.join(lib_dir, nesting)
FileUtils.mkdir_p nested_lib_dir
@@ -189,7 +185,6 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
end
def cargo_dylib_path(dest_path, crate_name)
- so_ext = RbConfig::CONFIG["SOEXT"]
prefix = so_ext == "dll" ? "" : "lib"
path_parts = [dest_path]
path_parts << ENV["CARGO_BUILD_TARGET"] if ENV["CARGO_BUILD_TARGET"]
@@ -203,8 +198,8 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
output, status =
begin
- Open3.capture2e(cargo, "metadata", "--no-deps", "--format-version", "1", chdir: cargo_dir)
- rescue StandardError => error
+ Open3.capture2e(cargo, "metadata", "--no-deps", "--format-version", "1", :chdir => cargo_dir)
+ rescue => error
raise Gem::InstallError, "cargo metadata failed #{error.message}"
end
@@ -251,10 +246,10 @@ EOF
end
def rustc_dynamic_linker_flags(dest_dir, crate_name)
- split_flags("DLDFLAGS").
- map {|arg| maybe_resolve_ldflag_variable(arg, dest_dir, crate_name) }.
- compact.
- flat_map {|arg| ldflag_to_link_modifier(arg) }
+ split_flags("DLDFLAGS")
+ .map {|arg| maybe_resolve_ldflag_variable(arg, dest_dir, crate_name) }
+ .compact
+ .flat_map {|arg| ldflag_to_link_modifier(arg) }
end
def rustc_lib_flags(dest_dir)
@@ -298,7 +293,7 @@ EOF
case var_name
# On windows, it is assumed that mkmf has setup an exports file for the
- # extension, so we have to create one ourselves.
+ # extension, so we have to to create one ourselves.
when "DEFFILE"
write_deffile(dest_dir, crate_name)
else
@@ -318,6 +313,22 @@ EOF
deffile_path
end
+ # We have to basically reimplement RbConfig::CONFIG['SOEXT'] here to support
+ # Ruby < 2.5
+ #
+ # @see https://github.com/ruby/ruby/blob/c87c027f18c005460746a74c07cd80ee355b16e4/configure.ac#L3185
+ def so_ext
+ return RbConfig::CONFIG["SOEXT"] if RbConfig::CONFIG.key?("SOEXT")
+
+ if win_target?
+ "dll"
+ elsif darwin_target?
+ "dylib"
+ else
+ "so"
+ end
+ end
+
# Corresponds to $(LIBPATH) in mkmf
def mkmf_libpath
["-L", "native=#{makefile_config("libdir")}"]
diff --git a/lib/rubygems/ext/cmake_builder.rb b/lib/rubygems/ext/cmake_builder.rb
index 34564f668d..b162664784 100644
--- a/lib/rubygems/ext/cmake_builder.rb
+++ b/lib/rubygems/ext/cmake_builder.rb
@@ -1,12 +1,7 @@
# frozen_string_literal: true
class Gem::Ext::CmakeBuilder < Gem::Ext::Builder
- def self.build(extension, dest_path, results, args=[], lib_dir=nil, cmake_dir=Dir.pwd,
- target_rbconfig=Gem.target_rbconfig)
- if target_rbconfig.path
- warn "--target-rbconfig is not yet supported for CMake extensions. Ignoring"
- end
-
+ def self.build(extension, dest_path, results, args=[], lib_dir=nil, cmake_dir=Dir.pwd)
unless File.exist?(File.join(cmake_dir, "Makefile"))
require_relative "../command"
cmd = ["cmake", ".", "-DCMAKE_INSTALL_PREFIX=#{dest_path}", *Gem::Command.build_args]
@@ -14,7 +9,7 @@ class Gem::Ext::CmakeBuilder < Gem::Ext::Builder
run cmd, results, class_name, cmake_dir
end
- make dest_path, results, cmake_dir, target_rbconfig: target_rbconfig
+ make dest_path, results, cmake_dir
results
end
diff --git a/lib/rubygems/ext/configure_builder.rb b/lib/rubygems/ext/configure_builder.rb
index d91b1ec5e8..6b8590ba2e 100644
--- a/lib/rubygems/ext/configure_builder.rb
+++ b/lib/rubygems/ext/configure_builder.rb
@@ -7,19 +7,14 @@
#++
class Gem::Ext::ConfigureBuilder < Gem::Ext::Builder
- def self.build(extension, dest_path, results, args=[], lib_dir=nil, configure_dir=Dir.pwd,
- target_rbconfig=Gem.target_rbconfig)
- if target_rbconfig.path
- warn "--target-rbconfig is not yet supported for configure-based extensions. Ignoring"
- end
-
+ def self.build(extension, dest_path, results, args=[], lib_dir=nil, configure_dir=Dir.pwd)
unless File.exist?(File.join(configure_dir, "Makefile"))
cmd = ["sh", "./configure", "--prefix=#{dest_path}", *args]
run cmd, results, class_name, configure_dir
end
- make dest_path, results, configure_dir, target_rbconfig: target_rbconfig
+ make dest_path, results, configure_dir
results
end
diff --git a/lib/rubygems/ext/ext_conf_builder.rb b/lib/rubygems/ext/ext_conf_builder.rb
index e652a221f8..9c22329fe3 100644
--- a/lib/rubygems/ext/ext_conf_builder.rb
+++ b/lib/rubygems/ext/ext_conf_builder.rb
@@ -7,8 +7,7 @@
#++
class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
- def self.build(extension, dest_path, results, args=[], lib_dir=nil, extension_dir=Dir.pwd,
- target_rbconfig=Gem.target_rbconfig)
+ def self.build(extension, dest_path, results, args=[], lib_dir=nil, extension_dir=Dir.pwd)
require "fileutils"
require "tempfile"
@@ -24,7 +23,6 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
begin
cmd = ruby << File.basename(extension)
- cmd << "--target-rbconfig=#{target_rbconfig.path}" if target_rbconfig.path
cmd.push(*args)
run(cmd, results, class_name, extension_dir) do |s, r|
@@ -41,18 +39,16 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
ENV["DESTDIR"] = nil
- make dest_path, results, extension_dir, tmp_dest_relative, target_rbconfig: target_rbconfig
+ make dest_path, results, extension_dir, tmp_dest_relative
full_tmp_dest = File.join(extension_dir, tmp_dest_relative)
- is_cross_compiling = target_rbconfig["platform"] != RbConfig::CONFIG["platform"]
- # Do not copy extension libraries by default when cross-compiling
- # not to conflict with the one already built for the host platform.
- if Gem.install_extension_in_lib && lib_dir && !is_cross_compiling
+ # TODO remove in RubyGems 4
+ if Gem.install_extension_in_lib && lib_dir
FileUtils.mkdir_p lib_dir
entries = Dir.entries(full_tmp_dest) - %w[. ..]
entries = entries.map {|entry| File.join full_tmp_dest, entry }
- FileUtils.cp_r entries, lib_dir, remove_destination: true
+ FileUtils.cp_r entries, lib_dir, :remove_destination => true
end
FileUtils::Entry_.new(full_tmp_dest).traverse do |ent|
@@ -60,7 +56,7 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
destent.exist? || FileUtils.mv(ent.path, destent.path)
end
- make dest_path, results, extension_dir, tmp_dest_relative, ["clean"], target_rbconfig: target_rbconfig
+ make dest_path, results, extension_dir, tmp_dest_relative, ["clean"]
ensure
ENV["DESTDIR"] = destdir
end
@@ -70,6 +66,8 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
FileUtils.rm_rf tmp_dest if tmp_dest
end
+ private
+
def self.get_relative_path(path, base)
path[0..base.length - 1] = "." if path.start_with?(base)
path
diff --git a/lib/rubygems/ext/rake_builder.rb b/lib/rubygems/ext/rake_builder.rb
index 42393a4a06..8f39a63e11 100644
--- a/lib/rubygems/ext/rake_builder.rb
+++ b/lib/rubygems/ext/rake_builder.rb
@@ -9,13 +9,8 @@ require_relative "../shellwords"
#++
class Gem::Ext::RakeBuilder < Gem::Ext::Builder
- def self.build(extension, dest_path, results, args=[], lib_dir=nil, extension_dir=Dir.pwd,
- target_rbconfig=Gem.target_rbconfig)
- if target_rbconfig.path
- warn "--target-rbconfig is not yet supported for Rake extensions. Ignoring"
- end
-
- if /mkrf_conf/i.match?(File.basename(extension))
+ def self.build(extension, dest_path, results, args=[], lib_dir=nil, extension_dir=Dir.pwd)
+ if File.basename(extension) =~ /mkrf_conf/i
run([Gem.ruby, File.basename(extension), *args], results, class_name, extension_dir)
end
diff --git a/lib/rubygems/gem_runner.rb b/lib/rubygems/gem_runner.rb
index 8335a0ad03..d238a5863b 100644
--- a/lib/rubygems/gem_runner.rb
+++ b/lib/rubygems/gem_runner.rb
@@ -33,11 +33,7 @@ class Gem::GemRunner
do_configuration args
- begin
- Gem.load_env_plugins
- rescue StandardError
- nil
- end
+ Gem.load_env_plugins rescue nil
Gem.load_plugins
cmd = @command_manager_class.instance
@@ -45,10 +41,10 @@ class Gem::GemRunner
cmd.command_names.each do |command_name|
config_args = Gem.configuration[command_name]
config_args = case config_args
- when String
- config_args.split " "
- else
- Array(config_args)
+ when String
+ config_args.split " "
+ else
+ Array(config_args)
end
Gem::Command.add_specific_extra_args command_name, config_args
end
diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb
index a8361b7ff1..92739617f6 100644
--- a/lib/rubygems/gemcutter_utilities.rb
+++ b/lib/rubygems/gemcutter_utilities.rb
@@ -9,9 +9,9 @@ require_relative "gemcutter_utilities/webauthn_poller"
# Utility methods for using the RubyGems API.
module Gem::GemcutterUtilities
+
ERROR_CODE = 1
- API_SCOPES = [:index_rubygems, :push_rubygem, :yank_rubygem, :add_owner, :remove_owner, :access_webhooks].freeze
- EXCLUSIVELY_API_SCOPES = [:show_dashboard].freeze
+ API_SCOPES = %i[index_rubygems push_rubygem yank_rubygem add_owner remove_owner access_webhooks show_dashboard].freeze
include Gem::Text
@@ -85,7 +85,7 @@ module Gem::GemcutterUtilities
# If +allowed_push_host+ metadata is present, then it will only allow that host.
def rubygems_api_request(method, path, host = nil, allowed_push_host = nil, scope: nil, credentials: {}, &block)
- require_relative "vendored_net_http"
+ require "net/http"
self.host = host if host
unless self.host
@@ -94,8 +94,8 @@ module Gem::GemcutterUtilities
end
if allowed_push_host
- allowed_host_uri = Gem::URI.parse(allowed_push_host)
- host_uri = Gem::URI.parse(self.host)
+ allowed_host_uri = URI.parse(allowed_push_host)
+ host_uri = URI.parse(self.host)
unless (host_uri.scheme == allowed_host_uri.scheme) && (host_uri.host == allowed_host_uri.host)
alert_error "#{self.host.inspect} is not allowed by the gemspec, which only allows #{allowed_push_host.inspect}"
@@ -103,7 +103,7 @@ module Gem::GemcutterUtilities
end
end
- uri = Gem::URI.parse "#{self.host}/#{path}"
+ uri = URI.parse "#{self.host}/#{path}"
response = request_with_otp(method, uri, &block)
if mfa_unauthorized?(response)
@@ -120,27 +120,27 @@ module Gem::GemcutterUtilities
end
def mfa_unauthorized?(response)
- response.is_a?(Gem::Net::HTTPUnauthorized) && response.body.start_with?("You have enabled multifactor authentication")
+ response.kind_of?(Net::HTTPUnauthorized) && response.body.start_with?("You have enabled multifactor authentication")
end
def update_scope(scope)
- sign_in_host = host
+ sign_in_host = self.host
pretty_host = pretty_host(sign_in_host)
update_scope_params = { scope => true }
say "The existing key doesn't have access of #{scope} on #{pretty_host}. Please sign in to update access."
- identifier = ask "Username/email: "
- password = ask_for_password " Password: "
+ email = ask " Email: "
+ password = ask_for_password "Password: "
response = rubygems_api_request(:put, "api/v1/api_key",
sign_in_host, scope: scope) do |request|
- request.basic_auth identifier, password
+ request.basic_auth email, password
request["OTP"] = otp if otp
- request.body = Gem::URI.encode_www_form({ api_key: api_key }.merge(update_scope_params))
+ request.body = URI.encode_www_form({ :api_key => api_key }.merge(update_scope_params))
end
- with_response response do |_resp|
+ with_response response do |resp|
say "Added #{scope} scope to the existing API key"
end
end
@@ -150,34 +150,34 @@ module Gem::GemcutterUtilities
# key.
def sign_in(sign_in_host = nil, scope: nil)
- sign_in_host ||= host
+ sign_in_host ||= self.host
return if api_key
pretty_host = pretty_host(sign_in_host)
say "Enter your #{pretty_host} credentials."
- say "Don't have an account yet? " \
+ say "Don't have an account yet? " +
"Create one at #{sign_in_host}/sign_up"
- identifier = ask "Username/email: "
- password = ask_for_password " Password: "
+ email = ask " Email: "
+ password = ask_for_password "Password: "
say "\n"
key_name = get_key_name(scope)
scope_params = get_scope_params(scope)
- profile = get_user_profile(identifier, password)
+ profile = get_user_profile(email, password)
mfa_params = get_mfa_params(profile)
all_params = scope_params.merge(mfa_params)
warning = profile["warning"]
- credentials = { identifier: identifier, password: password }
+ credentials = { email: email, password: password }
say "#{warning}\n" if warning
response = rubygems_api_request(:post, "api/v1/api_key",
sign_in_host, credentials: credentials, scope: scope) do |request|
- request.basic_auth identifier, password
+ request.basic_auth email, password
request["OTP"] = otp if otp
- request.body = Gem::URI.encode_www_form({ name: key_name }.merge(all_params))
+ request.body = URI.encode_www_form({ name: key_name }.merge(all_params))
end
with_response response do |resp|
@@ -209,14 +209,14 @@ module Gem::GemcutterUtilities
def with_response(response, error_prefix = nil)
case response
- when Gem::Net::HTTPSuccess then
+ when Net::HTTPSuccess then
if block_given?
yield response
else
say clean_text(response.body)
end
- when Gem::Net::HTTPPermanentRedirect, Gem::Net::HTTPRedirection then
- message = "The request has redirected permanently to #{response["location"]}. Please check your defined push host URL."
+ when Net::HTTPPermanentRedirect, Net::HTTPRedirection then
+ message = "The request has redirected permanently to #{response['location']}. Please check your defined push host URL."
message = "#{error_prefix}: #{message}" if error_prefix
say clean_text(message)
@@ -245,7 +245,7 @@ module Gem::GemcutterUtilities
private
def request_with_otp(method, uri, &block)
- request_method = Gem::Net::HTTP.const_get method.to_s.capitalize
+ request_method = Net::HTTP.const_get method.to_s.capitalize
Gem::RemoteFetcher.fetcher.request(uri, request_method) do |req|
req["OTP"] = otp if otp
@@ -295,10 +295,10 @@ module Gem::GemcutterUtilities
if credentials.empty?
request.add_field "Authorization", api_key
else
- request.basic_auth credentials[:identifier], credentials[:password]
+ request.basic_auth credentials[:email], credentials[:password]
end
end
- response.is_a?(Gem::Net::HTTPSuccess) ? response.body : nil
+ response.is_a?(Net::HTTPSuccess) ? response.body : nil
end
def pretty_host(host)
@@ -310,31 +310,15 @@ module Gem::GemcutterUtilities
end
def get_scope_params(scope)
- scope_params = { index_rubygems: true }
+ scope_params = {}
if scope
scope_params = { scope => true }
else
- say "The default access scope is:"
- scope_params.each do |k, _v|
- say " #{k}: y"
- end
- say "\n"
- customise = ask_yes_no("Do you want to customise scopes?", false)
- if customise
- EXCLUSIVELY_API_SCOPES.each do |excl_scope|
- selected = ask_yes_no("#{excl_scope} (exclusive scope, answering yes will not prompt for other scopes)", false)
- next unless selected
-
- return { excl_scope => true }
- end
-
- scope_params = {}
-
- API_SCOPES.each do |s|
- selected = ask_yes_no(s.to_s, false)
- scope_params[s] = true if selected
- end
+ say "Please select scopes you want to enable for the API key (y/n)"
+ API_SCOPES.each do |scope|
+ selected = ask_yes_no("#{scope}", false)
+ scope_params[scope] = true if selected
end
say "\n"
end
@@ -343,25 +327,25 @@ module Gem::GemcutterUtilities
end
def default_host?
- host == Gem::DEFAULT_HOST
+ self.host == Gem::DEFAULT_HOST
end
- def get_user_profile(identifier, password)
+ def get_user_profile(email, password)
return {} unless default_host?
response = rubygems_api_request(:get, "api/v1/profile/me.yaml") do |request|
- request.basic_auth identifier, password
+ request.basic_auth email, password
end
with_response response do |resp|
- Gem::ConfigFile.load_with_rubygems_config_hash(clean_text(resp.body))
+ Gem::SafeYAML.load clean_text(resp.body)
end
end
def get_mfa_params(profile)
mfa_level = profile["mfa"]
params = {}
- if ["ui_only", "ui_and_gem_signin"].include?(mfa_level)
+ if mfa_level == "ui_only" || mfa_level == "ui_and_gem_signin"
selected = ask_yes_no("Would you like to enable MFA for this key? (strongly recommended)")
params["mfa"] = true if selected
end
@@ -383,6 +367,6 @@ module Gem::GemcutterUtilities
end
def api_key_forbidden?(response)
- response.is_a?(Gem::Net::HTTPForbidden) && response.body.start_with?("The API key doesn't have access")
+ response.kind_of?(Net::HTTPForbidden) && response.body.start_with?("The API key doesn't have access")
end
end
diff --git a/lib/rubygems/gemcutter_utilities/webauthn_listener.rb b/lib/rubygems/gemcutter_utilities/webauthn_listener.rb
index abf65efe37..bea9d9e397 100644
--- a/lib/rubygems/gemcutter_utilities/webauthn_listener.rb
+++ b/lib/rubygems/gemcutter_utilities/webauthn_listener.rb
@@ -51,7 +51,7 @@ module Gem::GemcutterUtilities
request_line = socket.gets
method, req_uri, _protocol = request_line.split(" ")
- req_uri = Gem::URI.parse(req_uri)
+ req_uri = URI.parse(req_uri)
responder = SocketResponder.new(socket)
diff --git a/lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb b/lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb
index 17baa64fff..7709a8fef3 100644
--- a/lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb
+++ b/lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb
@@ -2,9 +2,9 @@
##
# The WebauthnListener Response class is used by the WebauthnListener to create
-# responses to be sent to the Gem host. It creates a Gem::Net::HTTPResponse instance
+# responses to be sent to the Gem host. It creates a Net::HTTPResponse instance
# when initialized and can be converted to the appropriate format to be sent by a socket using `to_s`.
-# Gem::Net::HTTPResponse instances cannot be directly sent over a socket.
+# Net::HTTPResponse instances cannot be directly sent over a socket.
#
# Types of response classes:
# - OkResponse
@@ -60,7 +60,7 @@ module Gem::GemcutterUtilities
def body; end
def build_http_response
- response_class = Gem::Net::HTTPResponse::CODE_TO_OBJ[code.to_s]
+ response_class = Net::HTTPResponse::CODE_TO_OBJ[code.to_s]
@http_response = response_class.new("1.1", code, reason_phrase)
@http_response.instance_variable_set(:@read, true)
diff --git a/lib/rubygems/gemcutter_utilities/webauthn_poller.rb b/lib/rubygems/gemcutter_utilities/webauthn_poller.rb
index fe3f163a88..e7068605a4 100644
--- a/lib/rubygems/gemcutter_utilities/webauthn_poller.rb
+++ b/lib/rubygems/gemcutter_utilities/webauthn_poller.rb
@@ -37,16 +37,16 @@ module Gem::GemcutterUtilities
thread.abort_on_exception = true
thread.report_on_exception = false
thread[:otp] = new(options, host).poll_for_otp(webauthn_url, credentials)
- rescue Gem::WebauthnVerificationError, Gem::Timeout::Error => e
+ rescue Gem::WebauthnVerificationError, Timeout::Error => e
thread[:error] = e
end
end
def poll_for_otp(webauthn_url, credentials)
- Gem::Timeout.timeout(TIMEOUT_IN_SECONDS) do
+ Timeout.timeout(TIMEOUT_IN_SECONDS) do
loop do
response = webauthn_verification_poll_response(webauthn_url, credentials)
- raise Gem::WebauthnVerificationError, response.message unless response.is_a?(Gem::Net::HTTPSuccess)
+ raise Gem::WebauthnVerificationError, response.message unless response.is_a?(Net::HTTPSuccess)
require "json"
parsed_response = JSON.parse(response.body)
@@ -69,10 +69,8 @@ module Gem::GemcutterUtilities
rubygems_api_request(:get, "api/v1/webauthn_verification/#{webauthn_token}/status.json") do |request|
if credentials.empty?
request.add_field "Authorization", api_key
- elsif credentials[:identifier] && credentials[:password]
- request.basic_auth credentials[:identifier], credentials[:password]
else
- raise Gem::WebauthnVerificationError, "Provided missing credentials"
+ request.basic_auth credentials[:email], credentials[:password]
end
end
end
diff --git a/lib/rubygems/gemspec_helpers.rb b/lib/rubygems/gemspec_helpers.rb
deleted file mode 100644
index 2b20fcafa1..0000000000
--- a/lib/rubygems/gemspec_helpers.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../rubygems"
-
-##
-# Mixin methods for commands that work with gemspecs.
-
-module Gem::GemspecHelpers
- def find_gemspec(glob = "*.gemspec")
- gemspecs = Dir.glob(glob).sort
-
- if gemspecs.size > 1
- alert_error "Multiple gemspecs found: #{gemspecs}, please specify one"
- terminate_interaction(1)
- end
-
- gemspecs.first
- end
-end
diff --git a/lib/rubygems/indexer.rb b/lib/rubygems/indexer.rb
new file mode 100644
index 0000000000..0935fe8486
--- /dev/null
+++ b/lib/rubygems/indexer.rb
@@ -0,0 +1,428 @@
+# frozen_string_literal: true
+
+require_relative "../rubygems"
+require_relative "package"
+require "tmpdir"
+
+##
+# Top level class for building the gem repository index.
+
+class Gem::Indexer
+ include Gem::UserInteraction
+
+ ##
+ # Build indexes for RubyGems 1.2.0 and newer when true
+
+ attr_accessor :build_modern
+
+ ##
+ # Index install location
+
+ attr_reader :dest_directory
+
+ ##
+ # Specs index install location
+
+ attr_reader :dest_specs_index
+
+ ##
+ # Latest specs index install location
+
+ attr_reader :dest_latest_specs_index
+
+ ##
+ # Prerelease specs index install location
+
+ attr_reader :dest_prerelease_specs_index
+
+ ##
+ # Index build directory
+
+ attr_reader :directory
+
+ ##
+ # Create an indexer that will index the gems in +directory+.
+
+ def initialize(directory, options = {})
+ require "fileutils"
+ require "tmpdir"
+ require "zlib"
+
+ options = { :build_modern => true }.merge options
+
+ @build_modern = options[:build_modern]
+
+ @dest_directory = directory
+ @directory = Dir.mktmpdir "gem_generate_index"
+
+ marshal_name = "Marshal.#{Gem.marshal_version}"
+
+ @master_index = File.join @directory, "yaml"
+ @marshal_index = File.join @directory, marshal_name
+
+ @quick_dir = File.join @directory, "quick"
+ @quick_marshal_dir = File.join @quick_dir, marshal_name
+ @quick_marshal_dir_base = File.join "quick", marshal_name # FIX: UGH
+
+ @quick_index = File.join @quick_dir, "index"
+ @latest_index = File.join @quick_dir, "latest_index"
+
+ @specs_index = File.join @directory, "specs.#{Gem.marshal_version}"
+ @latest_specs_index =
+ File.join(@directory, "latest_specs.#{Gem.marshal_version}")
+ @prerelease_specs_index =
+ File.join(@directory, "prerelease_specs.#{Gem.marshal_version}")
+ @dest_specs_index =
+ File.join(@dest_directory, "specs.#{Gem.marshal_version}")
+ @dest_latest_specs_index =
+ File.join(@dest_directory, "latest_specs.#{Gem.marshal_version}")
+ @dest_prerelease_specs_index =
+ File.join(@dest_directory, "prerelease_specs.#{Gem.marshal_version}")
+
+ @files = []
+ end
+
+ ##
+ # Build various indices
+
+ def build_indices
+ specs = map_gems_to_specs gem_file_list
+ Gem::Specification._resort! specs
+ build_marshal_gemspecs specs
+ build_modern_indices specs if @build_modern
+
+ compress_indices
+ end
+
+ ##
+ # Builds Marshal quick index gemspecs.
+
+ def build_marshal_gemspecs(specs)
+ count = specs.count
+ progress = ui.progress_reporter count,
+ "Generating Marshal quick index gemspecs for #{count} gems",
+ "Complete"
+
+ files = []
+
+ Gem.time "Generated Marshal quick index gemspecs" do
+ specs.each do |spec|
+ next if spec.default_gem?
+ spec_file_name = "#{spec.original_name}.gemspec.rz"
+ marshal_name = File.join @quick_marshal_dir, spec_file_name
+
+ marshal_zipped = Gem.deflate Marshal.dump(spec)
+
+ File.open marshal_name, "wb" do |io|
+ io.write marshal_zipped
+ end
+
+ files << marshal_name
+
+ progress.updated spec.original_name
+ end
+
+ progress.done
+ end
+
+ @files << @quick_marshal_dir
+
+ files
+ end
+
+ ##
+ # Build a single index for RubyGems 1.2 and newer
+
+ def build_modern_index(index, file, name)
+ say "Generating #{name} index"
+
+ Gem.time "Generated #{name} index" do
+ File.open(file, "wb") do |io|
+ specs = index.map do |*spec|
+ # We have to splat here because latest_specs is an array, while the
+ # others are hashes.
+ spec = spec.flatten.last
+ platform = spec.original_platform
+
+ # win32-api-1.0.4-x86-mswin32-60
+ unless String === platform
+ alert_warning "Skipping invalid platform in gem: #{spec.full_name}"
+ next
+ end
+
+ platform = Gem::Platform::RUBY if platform.nil? || platform.empty?
+ [spec.name, spec.version, platform]
+ end
+
+ specs = compact_specs(specs)
+ Marshal.dump(specs, io)
+ end
+ end
+ end
+
+ ##
+ # Builds indices for RubyGems 1.2 and newer. Handles full, latest, prerelease
+
+ def build_modern_indices(specs)
+ prerelease, released = specs.partition do |s|
+ s.version.prerelease?
+ end
+ latest_specs =
+ Gem::Specification._latest_specs specs
+
+ build_modern_index(released.sort, @specs_index, "specs")
+ build_modern_index(latest_specs.sort, @latest_specs_index, "latest specs")
+ build_modern_index(prerelease.sort, @prerelease_specs_index,
+ "prerelease specs")
+
+ @files += [@specs_index,
+ "#{@specs_index}.gz",
+ @latest_specs_index,
+ "#{@latest_specs_index}.gz",
+ @prerelease_specs_index,
+ "#{@prerelease_specs_index}.gz"]
+ end
+
+ def map_gems_to_specs(gems)
+ gems.map do |gemfile|
+ if File.size(gemfile) == 0
+ alert_warning "Skipping zero-length gem: #{gemfile}"
+ next
+ end
+
+ begin
+ spec = Gem::Package.new(gemfile).spec
+ spec.loaded_from = gemfile
+
+ spec.abbreviate
+ spec.sanitize
+
+ spec
+ rescue SignalException
+ alert_error "Received signal, exiting"
+ raise
+ rescue Exception => e
+ msg = ["Unable to process #{gemfile}",
+ "#{e.message} (#{e.class})",
+ "\t#{e.backtrace.join "\n\t"}"].join("\n")
+ alert_error msg
+ end
+ end.compact
+ end
+
+ ##
+ # Compresses indices on disk
+ #--
+ # All future files should be compressed using gzip, not deflate
+
+ def compress_indices
+ say "Compressing indices"
+
+ Gem.time "Compressed indices" do
+ if @build_modern
+ gzip @specs_index
+ gzip @latest_specs_index
+ gzip @prerelease_specs_index
+ end
+ end
+ end
+
+ ##
+ # Compacts Marshal output for the specs index data source by using identical
+ # objects as much as possible.
+
+ def compact_specs(specs)
+ names = {}
+ versions = {}
+ platforms = {}
+
+ specs.map do |(name, version, platform)|
+ names[name] = name unless names.include? name
+ versions[version] = version unless versions.include? version
+ platforms[platform] = platform unless platforms.include? platform
+
+ [names[name], versions[version], platforms[platform]]
+ end
+ end
+
+ ##
+ # Compress +filename+ with +extension+.
+
+ def compress(filename, extension)
+ data = Gem.read_binary filename
+
+ zipped = Gem.deflate data
+
+ File.open "#{filename}.#{extension}", "wb" do |io|
+ io.write zipped
+ end
+ end
+
+ ##
+ # List of gem file names to index.
+
+ def gem_file_list
+ Gem::Util.glob_files_in_dir("*.gem", File.join(@dest_directory, "gems"))
+ end
+
+ ##
+ # Builds and installs indices.
+
+ def generate_index
+ make_temp_directories
+ build_indices
+ install_indices
+ rescue SignalException
+ ensure
+ FileUtils.rm_rf @directory
+ end
+
+ ##
+ # Zlib::GzipWriter wrapper that gzips +filename+ on disk.
+
+ def gzip(filename)
+ Zlib::GzipWriter.open "#{filename}.gz" do |io|
+ io.write Gem.read_binary(filename)
+ end
+ end
+
+ ##
+ # Install generated indices into the destination directory.
+
+ def install_indices
+ verbose = Gem.configuration.really_verbose
+
+ say "Moving index into production dir #{@dest_directory}" if verbose
+
+ files = @files
+ files.delete @quick_marshal_dir if files.include? @quick_dir
+
+ if files.include?(@quick_marshal_dir) && !files.include?(@quick_dir)
+ files.delete @quick_marshal_dir
+
+ dst_name = File.join(@dest_directory, @quick_marshal_dir_base)
+
+ FileUtils.mkdir_p File.dirname(dst_name), :verbose => verbose
+ FileUtils.rm_rf dst_name, :verbose => verbose
+ FileUtils.mv(@quick_marshal_dir, dst_name,
+ :verbose => verbose, :force => true)
+ end
+
+ files = files.map do |path|
+ path.sub(/^#{Regexp.escape @directory}\/?/, "") # HACK?
+ end
+
+ files.each do |file|
+ src_name = File.join @directory, file
+ dst_name = File.join @dest_directory, file
+
+ FileUtils.rm_rf dst_name, :verbose => verbose
+ FileUtils.mv(src_name, @dest_directory,
+ :verbose => verbose, :force => true)
+ end
+ end
+
+ ##
+ # Make directories for index generation
+
+ def make_temp_directories
+ FileUtils.rm_rf @directory
+ FileUtils.mkdir_p @directory, :mode => 0700
+ FileUtils.mkdir_p @quick_marshal_dir
+ end
+
+ ##
+ # Ensure +path+ and path with +extension+ are identical.
+
+ def paranoid(path, extension)
+ data = Gem.read_binary path
+ compressed_data = Gem.read_binary "#{path}.#{extension}"
+
+ unless data == Gem::Util.inflate(compressed_data)
+ raise "Compressed file #{compressed_path} does not match uncompressed file #{path}"
+ end
+ end
+
+ ##
+ # Perform an in-place update of the repository from newly added gems.
+
+ def update_index
+ make_temp_directories
+
+ specs_mtime = File.stat(@dest_specs_index).mtime
+ newest_mtime = Time.at 0
+
+ updated_gems = gem_file_list.select do |gem|
+ gem_mtime = File.stat(gem).mtime
+ newest_mtime = gem_mtime if gem_mtime > newest_mtime
+ gem_mtime >= specs_mtime
+ end
+
+ if updated_gems.empty?
+ say "No new gems"
+ terminate_interaction 0
+ end
+
+ specs = map_gems_to_specs updated_gems
+ prerelease, released = specs.partition {|s| s.version.prerelease? }
+
+ files = build_marshal_gemspecs specs
+
+ Gem.time "Updated indexes" do
+ update_specs_index released, @dest_specs_index, @specs_index
+ update_specs_index released, @dest_latest_specs_index, @latest_specs_index
+ update_specs_index(prerelease,
+ @dest_prerelease_specs_index,
+ @prerelease_specs_index)
+ end
+
+ compress_indices
+
+ verbose = Gem.configuration.really_verbose
+
+ say "Updating production dir #{@dest_directory}" if verbose
+
+ files << @specs_index
+ files << "#{@specs_index}.gz"
+ files << @latest_specs_index
+ files << "#{@latest_specs_index}.gz"
+ files << @prerelease_specs_index
+ files << "#{@prerelease_specs_index}.gz"
+
+ files = files.map do |path|
+ path.sub(/^#{Regexp.escape @directory}\/?/, "") # HACK?
+ end
+
+ files.each do |file|
+ src_name = File.join @directory, file
+ dst_name = File.join @dest_directory, file # REFACTOR: duped above
+
+ FileUtils.mv src_name, dst_name, :verbose => verbose,
+ :force => true
+
+ File.utime newest_mtime, newest_mtime, dst_name
+ end
+ ensure
+ FileUtils.rm_rf @directory
+ end
+
+ ##
+ # Combines specs in +index+ and +source+ then writes out a new copy to
+ # +dest+. For a latest index, does not ensure the new file is minimal.
+
+ def update_specs_index(index, source, dest)
+ specs_index = Marshal.load Gem.read_binary(source)
+
+ index.each do |spec|
+ platform = spec.original_platform
+ platform = Gem::Platform::RUBY if platform.nil? || platform.empty?
+ specs_index << [spec.name, spec.version, platform]
+ end
+
+ specs_index = compact_specs specs_index.uniq.sort
+
+ File.open dest, "wb" do |io|
+ Marshal.dump specs_index, io
+ end
+ end
+end
diff --git a/lib/rubygems/install_update_options.rb b/lib/rubygems/install_update_options.rb
index 0d0f0dc211..e125b3b9b3 100644
--- a/lib/rubygems/install_update_options.rb
+++ b/lib/rubygems/install_update_options.rb
@@ -36,9 +36,9 @@ module Gem::InstallUpdateOptions
"List the documentation types you wish to",
"generate. For example: rdoc,ri") do |value, options|
options[:document] = case value
- when nil then %w[ri]
- when false then []
- else value
+ when nil then %w[ri]
+ when false then []
+ else value
end
end
@@ -50,7 +50,7 @@ module Gem::InstallUpdateOptions
add_option(:"Install/Update", "--vendor",
"Install gem into the vendor directory.",
- "Only for use by gem repackagers.") do |_value, options|
+ "Only for use by gem repackagers.") do |value, options|
unless Gem.vendor_dir
raise Gem::OptionParser::InvalidOption.new "your platform is not supported"
end
@@ -60,7 +60,7 @@ module Gem::InstallUpdateOptions
end
add_option(:"Install/Update", "-N", "--no-document",
- "Disable documentation generation") do |_value, options|
+ "Disable documentation generation") do |value, options|
options[:document] = []
end
@@ -104,21 +104,21 @@ module Gem::InstallUpdateOptions
add_option(:"Install/Update", "--development",
"Install additional development",
- "dependencies") do |_value, options|
+ "dependencies") do |value, options|
options[:development] = true
options[:dev_shallow] = true
end
add_option(:"Install/Update", "--development-all",
"Install development dependencies for all",
- "gems (including dev deps themselves)") do |_value, options|
+ "gems (including dev deps themselves)") do |value, options|
options[:development] = true
options[:dev_shallow] = false
end
add_option(:"Install/Update", "--conservative",
"Don't attempt to upgrade gems already",
- "meeting version requirement") do |_value, options|
+ "meeting version requirement") do |value, options|
options[:conservative] = true
options[:minimal_deps] = true
end
@@ -136,13 +136,13 @@ module Gem::InstallUpdateOptions
add_option(:"Install/Update", "-g", "--file [FILE]",
"Read from a gem dependencies API file and",
- "install the listed gems") do |v,_o|
- v ||= Gem::GEM_DEP_FILES.find do |file|
+ "install the listed gems") do |v,o|
+ v = Gem::GEM_DEP_FILES.find do |file|
File.exist? file
- end
+ end unless v
unless v
- message = v ? v : "(tried #{Gem::GEM_DEP_FILES.join ", "})"
+ message = v ? v : "(tried #{Gem::GEM_DEP_FILES.join ', '})"
raise Gem::OptionParser::InvalidArgument,
"cannot find gem dependencies file #{message}"
@@ -154,36 +154,31 @@ module Gem::InstallUpdateOptions
add_option(:"Install/Update", "--without GROUPS", Array,
"Omit the named groups (comma separated)",
"when installing from a gem dependencies",
- "file") do |v,_o|
- options[:without_groups].concat v.map(&:intern)
+ "file") do |v,o|
+ options[:without_groups].concat v.map {|without| without.intern }
end
add_option(:"Install/Update", "--default",
"Add the gem's full specification to",
- "specifications/default and extract only its bin") do |v,_o|
+ "specifications/default and extract only its bin") do |v,o|
options[:install_as_default] = v
end
add_option(:"Install/Update", "--explain",
"Rather than install the gems, indicate which would",
- "be installed") do |v,_o|
+ "be installed") do |v,o|
options[:explain] = v
end
add_option(:"Install/Update", "--[no-]lock",
- "Create a lock file (when used with -g/--file)") do |v,_o|
+ "Create a lock file (when used with -g/--file)") do |v,o|
options[:lock] = v
end
add_option(:"Install/Update", "--[no-]suggestions",
- "Suggest alternates when gems are not found") do |v,_o|
+ "Suggest alternates when gems are not found") do |v,o|
options[:suggest_alternate] = v
end
-
- add_option(:"Install/Update", "--target-rbconfig [FILE]",
- "rbconfig.rb for the deployment target platform") do |v, _o|
- Gem.set_target_rbconfig(v)
- end
end
##
@@ -191,7 +186,7 @@ module Gem::InstallUpdateOptions
def install_update_options
{
- document: %w[ri],
+ :document => %w[ri],
}
end
@@ -201,4 +196,5 @@ module Gem::InstallUpdateOptions
def install_update_defaults_str
"--document=ri"
end
+
end
diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb
index 21b72973cc..1b152aaf1f 100644
--- a/lib/rubygems/installer.rb
+++ b/lib/rubygems/installer.rb
@@ -66,6 +66,8 @@ class Gem::Installer
attr_reader :package
+ @path_warning = false
+
class << self
#
# Changes in rubygems to lazily loading `rubygems/command` (in order to
@@ -85,6 +87,11 @@ class Gem::Installer
end
##
+ # True if we've warned about PATH not including Gem.bindir
+
+ attr_accessor :path_warning
+
+ ##
# Overrides the executable format.
#
# This is a sprintf format with a "%s" which will be replaced with the
@@ -181,6 +188,13 @@ class Gem::Installer
@package.dir_mode = options[:dir_mode]
@package.prog_mode = options[:prog_mode]
@package.data_mode = options[:data_mode]
+
+ if options[:user_install]
+ @gem_home = Gem.user_dir
+ @bin_dir = Gem.bindir gem_home unless options[:bin_dir]
+ @plugins_dir = Gem.plugindir(gem_home)
+ check_that_user_bin_dir_is_in_path
+ end
end
##
@@ -208,32 +222,31 @@ class Gem::Installer
File.open generated_bin, "rb" do |io|
line = io.gets
- shebang = /^#!.*ruby/o
+ shebang = /^#!.*ruby/
- # TruffleRuby uses a bash prelude in default launchers
- if load_relative_enabled? || RUBY_ENGINE == "truffleruby"
- until line.nil? || shebang.match?(line) do
+ if load_relative_enabled?
+ until line.nil? || line =~ shebang do
line = io.gets
end
end
- next unless line&.match?(shebang)
+ next unless line =~ shebang
io.gets # blankline
- # TODO: detect a specially formatted comment instead of trying
+ # TODO detect a specially formatted comment instead of trying
# to find a string inside Ruby code.
- next unless io.gets&.include?("This file was generated by RubyGems")
+ next unless io.gets.to_s.include?("This file was generated by RubyGems")
ruby_executable = true
- existing = io.read.slice(/
+ existing = io.read.slice(%r{
^\s*(
gem \s |
load \s Gem\.bin_path\( |
load \s Gem\.activate_bin_path\(
)
(['"])(.*?)(\2),
- /x, 3)
+ }x, 3)
end
return if spec.name == existing
@@ -303,7 +316,7 @@ class Gem::Installer
FileUtils.rm_rf spec.extension_dir
dir_mode = options[:dir_mode]
- FileUtils.mkdir_p gem_dir, mode: dir_mode && 0o755
+ FileUtils.mkdir_p gem_dir, :mode => dir_mode && 0755
if @options[:install_as_default]
extract_bin
@@ -328,37 +341,41 @@ class Gem::Installer
say spec.post_install_message if options[:post_install_message] && !spec.post_install_message.nil?
- Gem::Specification.add_spec(spec) unless @install_dir
+ Gem::Specification.add_spec(spec)
load_plugin
run_post_install_hooks
spec
- rescue Errno::EACCES => e
- # Permission denied - /path/to/foo
- raise Gem::FilePermissionError, e.message.split(" - ").last
+
+ # TODO This rescue is in the wrong place. What is raising this exception?
+ # move this rescue to around the code that actually might raise it.
+ rescue Zlib::GzipFile::Error
+ raise Gem::InstallError, "gzip error installing #{gem}"
end
def run_pre_install_hooks # :nodoc:
Gem.pre_install_hooks.each do |hook|
- next unless hook.call(self) == false
- location = " at #{$1}" if hook.inspect =~ /[ @](.*:\d+)/
+ if hook.call(self) == false
+ location = " at #{$1}" if hook.inspect =~ /[ @](.*:\d+)/
- message = "pre-install hook#{location} failed for #{spec.full_name}"
- raise Gem::InstallError, message
+ message = "pre-install hook#{location} failed for #{spec.full_name}"
+ raise Gem::InstallError, message
+ end
end
end
def run_post_build_hooks # :nodoc:
Gem.post_build_hooks.each do |hook|
- next unless hook.call(self) == false
- FileUtils.rm_rf gem_dir
+ if hook.call(self) == false
+ FileUtils.rm_rf gem_dir
- location = " at #{$1}" if hook.inspect =~ /[ @](.*:\d+)/
+ location = " at #{$1}" if hook.inspect =~ /[ @](.*:\d+)/
- message = "post-build hook#{location} failed for #{spec.full_name}"
- raise Gem::InstallError, message
+ message = "post-build hook#{location} failed for #{spec.full_name}"
+ raise Gem::InstallError, message
+ end
end
end
@@ -378,7 +395,7 @@ class Gem::Installer
specs = []
Gem::Util.glob_files_in_dir("*.gemspec", File.join(gem_home, "specifications")).each do |path|
- spec = Gem::Specification.load path
+ spec = Gem::Specification.load path.tap(&Gem::UNTAINT)
specs << spec if spec
end
@@ -448,9 +465,6 @@ class Gem::Installer
##
# Writes the full .gemspec specification (in Ruby) to the gem home's
# specifications/default directory.
- #
- # In contrast to #write_spec, this keeps file lists, so the `gem contents`
- # command works.
def write_default_spec
Gem.write_binary(default_spec_file, spec.to_ruby)
@@ -472,29 +486,21 @@ class Gem::Installer
end
def generate_bin # :nodoc:
- executables = spec.executables
- return if executables.nil? || executables.empty?
-
- if @gem_home == Gem.user_dir
- # If we get here, then one of the following likely happened:
- # - `--user-install` was specified
- # - `Gem::PathSupport#home` fell back to `Gem.user_dir`
- # - GEM_HOME was manually set to `Gem.user_dir`
-
- check_that_user_bin_dir_is_in_path(executables)
- end
+ return if spec.executables.nil? || spec.executables.empty?
ensure_writable_dir @bin_dir
- executables.each do |filename|
+ spec.executables.each do |filename|
+ filename.tap(&Gem::UNTAINT)
bin_path = File.join gem_dir, spec.bindir, filename
next unless File.exist? bin_path
mode = File.stat(bin_path).mode
- dir_mode = options[:prog_mode] || (mode | 0o111)
+ dir_mode = options[:prog_mode] || (mode | 0111)
unless dir_mode == mode
- File.chmod dir_mode, bin_path
+ require "fileutils"
+ FileUtils.chmod dir_mode, bin_path
end
check_executable_overwrite filename
@@ -518,8 +524,6 @@ class Gem::Installer
else
regenerate_plugins_for(spec, @plugins_dir)
end
- rescue ArgumentError => e
- raise e, "#{latest.name} #{latest.version} #{spec.name} #{spec.version}: #{e.message}"
end
##
@@ -527,19 +531,17 @@ class Gem::Installer
#--
# The Windows script is generated in addition to the regular one due to a
# bug or misfeature in the Windows shell's pipe. See
- # https://blade.ruby-lang.org/ruby-talk/193379
+ # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/193379
def generate_bin_script(filename, bindir)
bin_script_path = File.join bindir, formatted_program_filename(filename)
- Gem.open_file_with_lock(bin_script_path) do
- require "fileutils"
- FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers
+ require "fileutils"
+ FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers
- File.open(bin_script_path, "wb", 0o755) do |file|
- file.write app_script_text(filename)
- file.chmod(options[:prog_mode] || 0o755)
- end
+ File.open bin_script_path, "wb", 0755 do |file|
+ file.print app_script_text(filename)
+ file.chmod(options[:prog_mode] || 0755)
end
verbose bin_script_path
@@ -564,7 +566,7 @@ class Gem::Installer
File.unlink dst
end
- FileUtils.symlink src, dst, verbose: Gem.configuration.really_verbose
+ FileUtils.symlink src, dst, :verbose => Gem.configuration.really_verbose
rescue NotImplementedError, SystemCallError
alert_warning "Unable to use symlinks, installing wrapper"
generate_bin_script filename, bindir
@@ -587,7 +589,7 @@ class Gem::Installer
def shebang(bin_file_name)
path = File.join gem_dir, spec.bindir, bin_file_name
- first_line = File.open(path, "rb", &:gets) || ""
+ first_line = File.open(path, "rb") {|file| file.gets } || ""
if first_line.start_with?("#!")
# Preserve extra words on shebang line, like "-w". Thanks RPA.
@@ -629,6 +631,7 @@ class Gem::Installer
def ensure_loadable_spec
ruby = spec.to_ruby_for_cache
+ ruby.tap(&Gem::UNTAINT)
begin
eval ruby
@@ -649,36 +652,31 @@ class Gem::Installer
def process_options # :nodoc:
@options = {
- bin_dir: nil,
- env_shebang: false,
- force: false,
- only_install_dir: false,
- post_install_message: true,
+ :bin_dir => nil,
+ :env_shebang => false,
+ :force => false,
+ :only_install_dir => false,
+ :post_install_message => true,
}.merge options
@env_shebang = options[:env_shebang]
@force = options[:force]
@install_dir = options[:install_dir]
- @user_install = options[:user_install]
+ @gem_home = options[:install_dir] || Gem.dir
+ @plugins_dir = Gem.plugindir(@gem_home)
@ignore_dependencies = options[:ignore_dependencies]
@format_executable = options[:format_executable]
@wrappers = options[:wrappers]
@only_install_dir = options[:only_install_dir]
- @bin_dir = options[:bin_dir]
- @development = options[:development]
- @build_root = options[:build_root]
-
- @build_args = options[:build_args]
-
- @gem_home = @install_dir || user_install_dir || Gem.dir
-
# If the user has asked for the gem to be installed in a directory that is
# the system gem directory, then use the system bin directory, else create
# (or use) a new bin dir under the gem_home.
- @bin_dir ||= Gem.bindir(@gem_home)
+ @bin_dir = options[:bin_dir] || Gem.bindir(gem_home)
+ @development = options[:development]
+ @build_root = options[:build_root]
- @plugins_dir = Gem.plugindir(@gem_home)
+ @build_args = options[:build_args]
unless @build_root.nil?
@bin_dir = File.join(@build_root, @bin_dir.gsub(/^[a-zA-Z]:/, ""))
@@ -688,7 +686,9 @@ class Gem::Installer
end
end
- def check_that_user_bin_dir_is_in_path(executables) # :nodoc:
+ def check_that_user_bin_dir_is_in_path # :nodoc:
+ return if self.class.path_warning
+
user_bin_dir = @bin_dir || Gem.bindir(gem_home)
user_bin_dir = user_bin_dir.tr(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
@@ -704,17 +704,19 @@ class Gem::Installer
unless path.include? user_bin_dir
unless !Gem.win_platform? && (path.include? user_bin_dir.sub(ENV["HOME"], "~"))
- alert_warning "You don't have #{user_bin_dir} in your PATH,\n\t gem executables (#{executables.join(", ")}) will not run."
+ alert_warning "You don't have #{user_bin_dir} in your PATH,\n\t gem executables will not run."
+ self.class.path_warning = true
end
end
end
def verify_gem_home # :nodoc:
- FileUtils.mkdir_p gem_home, mode: options[:dir_mode] && 0o755
+ FileUtils.mkdir_p gem_home, :mode => options[:dir_mode] && 0755
+ raise Gem::FilePermissionError, gem_home unless File.writable?(gem_home)
end
def verify_spec
- unless Gem::Specification::VALID_NAME_PATTERN.match?(spec.name)
+ unless spec.name =~ Gem::Specification::VALID_NAME_PATTERN
raise Gem::InstallError, "#{spec} has an invalid name"
end
@@ -726,11 +728,11 @@ class Gem::Installer
raise Gem::InstallError, "#{spec} has an invalid extensions"
end
- if /\R/.match?(spec.platform.to_s)
+ if spec.platform.to_s =~ /\R/
raise Gem::InstallError, "#{spec.platform} is an invalid platform"
end
- unless /\A\d+\z/.match?(spec.specification_version.to_s)
+ unless spec.specification_version.to_s =~ /\A\d+\z/
raise Gem::InstallError, "#{spec} has an invalid specification_version"
end
@@ -747,9 +749,9 @@ class Gem::Installer
# Return the text for an application file.
def app_script_text(bin_file_name)
- # NOTE: that the `load` lines cannot be indented, as old RG versions match
+ # note that the `load` lines cannot be indented, as old RG versions match
# against the beginning of the line
- <<-TEXT
+ return <<-TEXT
#{shebang bin_file_name}
#
# This file was generated by RubyGems.
@@ -806,10 +808,10 @@ TEXT
rb_topdir = RbConfig::TOPDIR || File.dirname(rb_config["bindir"])
# get ruby executable file name from RbConfig
- ruby_exe = "#{rb_config["RUBY_INSTALL_NAME"]}#{rb_config["EXEEXT"]}"
+ ruby_exe = "#{rb_config['RUBY_INSTALL_NAME']}#{rb_config['EXEEXT']}"
ruby_exe = "ruby.exe" if ruby_exe.empty?
- if File.exist?(File.join(bindir, ruby_exe))
+ if File.exist?(File.join bindir, ruby_exe)
# stub & ruby.exe within same folder. Portable
<<-TEXT
@ECHO OFF
@@ -839,7 +841,7 @@ TEXT
# configure scripts and rakefiles or mkrf_conf files.
def build_extensions
- builder = Gem::Ext::Builder.new spec, build_args, Gem.target_rbconfig
+ builder = Gem::Ext::Builder.new spec, build_args
builder.build_extensions
end
@@ -931,7 +933,7 @@ TEXT
build_info_dir = File.join gem_home, "build_info"
dir_mode = options[:dir_mode]
- FileUtils.mkdir_p build_info_dir, mode: dir_mode && 0o755
+ FileUtils.mkdir_p build_info_dir, :mode => dir_mode && 0755
build_info_file = File.join build_info_dir, "#{spec.full_name}.info"
@@ -954,7 +956,7 @@ TEXT
def ensure_writable_dir(dir) # :nodoc:
begin
- Dir.mkdir dir, *[options[:dir_mode] && 0o755].compact
+ Dir.mkdir dir, *[options[:dir_mode] && 0755].compact
rescue SystemCallError
raise unless File.directory? dir
end
@@ -964,19 +966,6 @@ TEXT
private
- def user_install_dir
- # never install to user home in --build-root mode
- return unless @build_root.nil?
-
- # Please note that @user_install might have three states:
- # * `true`: `--user-install`
- # * `false`: `--no-user-install` and
- # * `nil`: option was not specified
- if @user_install || (@user_install.nil? && Gem.default_user_install)
- Gem.user_dir
- end
- end
-
def build_args
@build_args ||= begin
require_relative "command"
@@ -985,7 +974,7 @@ TEXT
end
def rb_config
- Gem.target_rbconfig
+ RbConfig::CONFIG
end
def ruby_install_name
@@ -1002,7 +991,7 @@ TEXT
bindir="${0%/*}"
EOS
- script << %(exec "$bindir/#{ruby_install_name}" "-x" "$0" "$@"\n)
+ script << %Q(exec "$bindir/#{ruby_install_name}" "-x" "$0" "$@"\n)
<<~EOS
#!/bin/sh
diff --git a/lib/rubygems/installer_uninstaller_utils.rb b/lib/rubygems/installer_uninstaller_utils.rb
index c5c2a52bab..d97b4e29b1 100644
--- a/lib/rubygems/installer_uninstaller_utils.rb
+++ b/lib/rubygems/installer_uninstaller_utils.rb
@@ -4,6 +4,7 @@
# Helper methods for both Gem::Installer and Gem::Uninstaller
module Gem::InstallerUninstallerUtils
+
def regenerate_plugins_for(spec, plugins_dir)
plugins = spec.plugins
return if plugins.empty?
@@ -24,4 +25,5 @@ module Gem::InstallerUninstallerUtils
def remove_plugins_for(spec, plugins_dir)
FileUtils.rm_f Gem::Util.glob_files_in_dir("#{spec.name}#{Gem.plugin_suffix_pattern}", plugins_dir)
end
+
end
diff --git a/lib/rubygems/local_remote_options.rb b/lib/rubygems/local_remote_options.rb
index 51a61213a5..3d970ef225 100644
--- a/lib/rubygems/local_remote_options.rb
+++ b/lib/rubygems/local_remote_options.rb
@@ -6,21 +6,22 @@
# See LICENSE.txt for permissions.
#++
-require_relative "vendor/uri/lib/uri"
+require "uri"
require_relative "../rubygems"
##
# Mixin methods for local and remote Gem::Command options.
module Gem::LocalRemoteOptions
+
##
# Allows Gem::OptionParser to handle HTTP URIs.
def accept_uri_http
- Gem::OptionParser.accept Gem::URI::HTTP do |value|
+ Gem::OptionParser.accept URI::HTTP do |value|
begin
- uri = Gem::URI.parse value
- rescue Gem::URI::InvalidURIError
+ uri = URI.parse value
+ rescue URI::InvalidURIError
raise Gem::OptionParser::InvalidArgument, value
end
@@ -39,17 +40,17 @@ module Gem::LocalRemoteOptions
def add_local_remote_options
add_option(:"Local/Remote", "-l", "--local",
- "Restrict operations to the LOCAL domain") do |_value, options|
+ "Restrict operations to the LOCAL domain") do |value, options|
options[:domain] = :local
end
add_option(:"Local/Remote", "-r", "--remote",
- "Restrict operations to the REMOTE domain") do |_value, options|
+ "Restrict operations to the REMOTE domain") do |value, options|
options[:domain] = :remote
end
add_option(:"Local/Remote", "-b", "--both",
- "Allow LOCAL and REMOTE operations") do |_value, options|
+ "Allow LOCAL and REMOTE operations") do |value, options|
options[:domain] = :both
end
@@ -66,7 +67,8 @@ module Gem::LocalRemoteOptions
def add_bulk_threshold_option
add_option(:"Local/Remote", "-B", "--bulk-threshold COUNT",
"Threshold for switching to bulk",
- "synchronization (default #{Gem.configuration.bulk_threshold})") do |value, _options|
+ "synchronization (default #{Gem.configuration.bulk_threshold})") do
+ |value, options|
Gem.configuration.bulk_threshold = value.to_i
end
end
@@ -76,7 +78,7 @@ module Gem::LocalRemoteOptions
def add_clear_sources_option
add_option(:"Local/Remote", "--clear-sources",
- "Clear the gem sources") do |_value, options|
+ "Clear the gem sources") do |value, options|
Gem.sources = nil
options[:sources_cleared] = true
end
@@ -88,9 +90,9 @@ module Gem::LocalRemoteOptions
def add_proxy_option
accept_uri_http
- add_option(:"Local/Remote", "-p", "--[no-]http-proxy [URL]", Gem::URI::HTTP,
+ add_option(:"Local/Remote", "-p", "--[no-]http-proxy [URL]", URI::HTTP,
"Use HTTP proxy for remote operations") do |value, options|
- options[:http_proxy] = value == false ? :no_proxy : value
+ options[:http_proxy] = (value == false) ? :no_proxy : value
Gem.configuration[:http_proxy] = options[:http_proxy]
end
end
@@ -101,9 +103,9 @@ module Gem::LocalRemoteOptions
def add_source_option
accept_uri_http
- add_option(:"Local/Remote", "-s", "--source URL", Gem::URI::HTTP,
+ add_option(:"Local/Remote", "-s", "--source URL", URI::HTTP,
"Append URL to list of remote gem sources") do |source, options|
- source << "/" unless source.end_with?("/")
+ source << "/" if source !~ /\/\z/
if options.delete :sources_cleared
Gem.sources = [source]
@@ -118,7 +120,7 @@ module Gem::LocalRemoteOptions
def add_update_sources_option
add_option(:Deprecated, "-u", "--[no-]update-sources",
- "Update local source cache") do |value, _options|
+ "Update local source cache") do |value, options|
Gem.configuration.update_sources = value
end
end
@@ -143,4 +145,5 @@ module Gem::LocalRemoteOptions
def remote?
options[:domain] == :remote || options[:domain] == :both
end
+
end
diff --git a/lib/rubygems/mock_gem_ui.rb b/lib/rubygems/mock_gem_ui.rb
new file mode 100644
index 0000000000..2dfdc6d523
--- /dev/null
+++ b/lib/rubygems/mock_gem_ui.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require_relative "user_interaction"
+
+##
+# This Gem::StreamUI subclass records input and output to StringIO for
+# retrieval during tests.
+
+class Gem::MockGemUi < Gem::StreamUI
+ ##
+ # Raised when you haven't provided enough input to your MockGemUi
+
+ class InputEOFError < RuntimeError
+ def initialize(question)
+ super "Out of input for MockGemUi on #{question.inspect}"
+ end
+ end
+
+ class TermError < RuntimeError
+ attr_reader :exit_code
+
+ def initialize(exit_code)
+ super
+ @exit_code = exit_code
+ end
+ end
+ class SystemExitException < RuntimeError; end
+
+ module TTY
+
+ attr_accessor :tty
+
+ def tty?()
+ @tty = true unless defined?(@tty)
+ @tty
+ end
+
+ def noecho
+ yield self
+ end
+ end
+
+ def initialize(input = "")
+ require "stringio"
+ ins = StringIO.new input
+ outs = StringIO.new
+ errs = StringIO.new
+
+ ins.extend TTY
+ outs.extend TTY
+ errs.extend TTY
+
+ super ins, outs, errs, true
+
+ @terminated = false
+ end
+
+ def ask(question)
+ raise InputEOFError, question if @ins.eof?
+
+ super
+ end
+
+ def input
+ @ins.string
+ end
+
+ def output
+ @outs.string
+ end
+
+ def error
+ @errs.string
+ end
+
+ def terminated?
+ @terminated
+ end
+
+ def terminate_interaction(status=0)
+ @terminated = true
+
+ raise TermError, status if status != 0
+ raise SystemExitException
+ end
+end
diff --git a/lib/rubygems/name_tuple.rb b/lib/rubygems/name_tuple.rb
index 3f4a6fcf3d..c26d0765e6 100644
--- a/lib/rubygems/name_tuple.rb
+++ b/lib/rubygems/name_tuple.rb
@@ -6,12 +6,14 @@
# wrap the data returned from the indexes.
class Gem::NameTuple
- def initialize(name, version, platform=Gem::Platform::RUBY)
+ def initialize(name, version, platform="ruby")
@name = name
@version = version
- platform &&= platform.to_s
- platform = Gem::Platform::RUBY if !platform || platform.empty?
+ unless platform.kind_of? Gem::Platform
+ platform = "ruby" if !platform || platform.empty?
+ end
+
@platform = platform
end
@@ -30,7 +32,7 @@ class Gem::NameTuple
# [name, version, platform] tuples.
def self.to_basic(list)
- list.map(&:to_a)
+ list.map {|t| t.to_a }
end
##
@@ -47,11 +49,11 @@ class Gem::NameTuple
def full_name
case @platform
- when nil, "", Gem::Platform::RUBY
+ when nil, "ruby", ""
"#{@name}-#{@version}"
else
"#{@name}-#{@version}-#{@platform}"
- end
+ end.dup.tap(&Gem::UNTAINT)
end
##
@@ -85,7 +87,7 @@ class Gem::NameTuple
"#<Gem::NameTuple #{@name}, #{@version}, #{@platform}>"
end
- alias_method :to_s, :inspect # :nodoc:
+ alias to_s inspect # :nodoc:
def <=>(other)
[@name, @version, Gem::Platform.sort_priority(@platform)] <=>
diff --git a/lib/rubygems/optparse.rb b/lib/rubygems/optparse.rb
new file mode 100644
index 0000000000..6ed718423c
--- /dev/null
+++ b/lib/rubygems/optparse.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+require_relative "optparse/lib/optparse"
diff --git a/lib/bundler/vendor/connection_pool/.document b/lib/rubygems/optparse/.document
index 0c43bbd6b3..0c43bbd6b3 100644
--- a/lib/bundler/vendor/connection_pool/.document
+++ b/lib/rubygems/optparse/.document
diff --git a/lib/rubygems/vendor/optparse/lib/optionparser.rb b/lib/rubygems/optparse/lib/optionparser.rb
index 4b9b40d82a..4b9b40d82a 100644
--- a/lib/rubygems/vendor/optparse/lib/optionparser.rb
+++ b/lib/rubygems/optparse/lib/optionparser.rb
diff --git a/lib/rubygems/optparse/lib/optparse.rb b/lib/rubygems/optparse/lib/optparse.rb
new file mode 100644
index 0000000000..1e50bda769
--- /dev/null
+++ b/lib/rubygems/optparse/lib/optparse.rb
@@ -0,0 +1,2308 @@
+# frozen_string_literal: true
+#
+# optparse.rb - command-line option analysis with the Gem::OptionParser class.
+#
+# Author:: Nobu Nakada
+# Documentation:: Nobu Nakada and Gavin Sinclair.
+#
+# See Gem::OptionParser for documentation.
+#
+
+
+#--
+# == Developer Documentation (not for RDoc output)
+#
+# === Class tree
+#
+# - Gem::OptionParser:: front end
+# - Gem::OptionParser::Switch:: each switches
+# - Gem::OptionParser::List:: options list
+# - Gem::OptionParser::ParseError:: errors on parsing
+# - Gem::OptionParser::AmbiguousOption
+# - Gem::OptionParser::NeedlessArgument
+# - Gem::OptionParser::MissingArgument
+# - Gem::OptionParser::InvalidOption
+# - Gem::OptionParser::InvalidArgument
+# - Gem::OptionParser::AmbiguousArgument
+#
+# === Object relationship diagram
+#
+# +--------------+
+# | Gem::OptionParser |<>-----+
+# +--------------+ | +--------+
+# | ,-| Switch |
+# on_head -------->+---------------+ / +--------+
+# accept/reject -->| List |<|>-
+# | |<|>- +----------+
+# on ------------->+---------------+ `-| argument |
+# : : | class |
+# +---------------+ |==========|
+# on_tail -------->| | |pattern |
+# +---------------+ |----------|
+# Gem::OptionParser.accept ->| DefaultList | |converter |
+# reject |(shared between| +----------+
+# | all instances)|
+# +---------------+
+#
+#++
+#
+# == Gem::OptionParser
+#
+# === New to \Gem::OptionParser?
+#
+# See the {Tutorial}[optparse/tutorial.rdoc].
+#
+# === Introduction
+#
+# Gem::OptionParser is a class for command-line option analysis. It is much more
+# advanced, yet also easier to use, than GetoptLong, and is a more Ruby-oriented
+# solution.
+#
+# === Features
+#
+# 1. The argument specification and the code to handle it are written in the
+# same place.
+# 2. It can output an option summary; you don't need to maintain this string
+# separately.
+# 3. Optional and mandatory arguments are specified very gracefully.
+# 4. Arguments can be automatically converted to a specified class.
+# 5. Arguments can be restricted to a certain set.
+#
+# All of these features are demonstrated in the examples below. See
+# #make_switch for full documentation.
+#
+# === Minimal example
+#
+# require 'rubygems/optparse/lib/optparse'
+#
+# options = {}
+# Gem::OptionParser.new do |parser|
+# parser.banner = "Usage: example.rb [options]"
+#
+# parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
+# options[:verbose] = v
+# end
+# end.parse!
+#
+# p options
+# p ARGV
+#
+# === Generating Help
+#
+# Gem::OptionParser can be used to automatically generate help for the commands you
+# write:
+#
+# require 'rubygems/optparse/lib/optparse'
+#
+# Options = Struct.new(:name)
+#
+# class Parser
+# def self.parse(options)
+# args = Options.new("world")
+#
+# opt_parser = Gem::OptionParser.new do |parser|
+# parser.banner = "Usage: example.rb [options]"
+#
+# parser.on("-nNAME", "--name=NAME", "Name to say hello to") do |n|
+# args.name = n
+# end
+#
+# parser.on("-h", "--help", "Prints this help") do
+# puts parser
+# exit
+# end
+# end
+#
+# opt_parser.parse!(options)
+# return args
+# end
+# end
+# options = Parser.parse %w[--help]
+#
+# #=>
+# # Usage: example.rb [options]
+# # -n, --name=NAME Name to say hello to
+# # -h, --help Prints this help
+#
+# === Required Arguments
+#
+# For options that require an argument, option specification strings may include an
+# option name in all caps. If an option is used without the required argument,
+# an exception will be raised.
+#
+# require 'rubygems/optparse/lib/optparse'
+#
+# options = {}
+# Gem::OptionParser.new do |parser|
+# parser.on("-r", "--require LIBRARY",
+# "Require the LIBRARY before executing your script") do |lib|
+# puts "You required #{lib}!"
+# end
+# end.parse!
+#
+# Used:
+#
+# $ ruby optparse-test.rb -r
+# optparse-test.rb:9:in `<main>': missing argument: -r (Gem::OptionParser::MissingArgument)
+# $ ruby optparse-test.rb -r my-library
+# You required my-library!
+#
+# === Type Coercion
+#
+# Gem::OptionParser supports the ability to coerce command line arguments
+# into objects for us.
+#
+# Gem::OptionParser comes with a few ready-to-use kinds of type
+# coercion. They are:
+#
+# - Date -- Anything accepted by +Date.parse+
+# - DateTime -- Anything accepted by +DateTime.parse+
+# - Time -- Anything accepted by +Time.httpdate+ or +Time.parse+
+# - URI -- Anything accepted by +URI.parse+
+# - Shellwords -- Anything accepted by +Shellwords.shellwords+
+# - String -- Any non-empty string
+# - Integer -- Any integer. Will convert octal. (e.g. 124, -3, 040)
+# - Float -- Any float. (e.g. 10, 3.14, -100E+13)
+# - Numeric -- Any integer, float, or rational (1, 3.4, 1/3)
+# - DecimalInteger -- Like +Integer+, but no octal format.
+# - OctalInteger -- Like +Integer+, but no decimal format.
+# - DecimalNumeric -- Decimal integer or float.
+# - TrueClass -- Accepts '+, yes, true, -, no, false' and
+# defaults as +true+
+# - FalseClass -- Same as +TrueClass+, but defaults to +false+
+# - Array -- Strings separated by ',' (e.g. 1,2,3)
+# - Regexp -- Regular expressions. Also includes options.
+#
+# We can also add our own coercions, which we will cover below.
+#
+# ==== Using Built-in Conversions
+#
+# As an example, the built-in +Time+ conversion is used. The other built-in
+# conversions behave in the same way.
+# Gem::OptionParser will attempt to parse the argument
+# as a +Time+. If it succeeds, that time will be passed to the
+# handler block. Otherwise, an exception will be raised.
+#
+# require 'rubygems/optparse/lib/optparse'
+# require 'rubygems/optparse/lib/optparse/time'
+# Gem::OptionParser.new do |parser|
+# parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
+# p time
+# end
+# end.parse!
+#
+# Used:
+#
+# $ ruby optparse-test.rb -t nonsense
+# ... invalid argument: -t nonsense (Gem::OptionParser::InvalidArgument)
+# $ ruby optparse-test.rb -t 10-11-12
+# 2010-11-12 00:00:00 -0500
+# $ ruby optparse-test.rb -t 9:30
+# 2014-08-13 09:30:00 -0400
+#
+# ==== Creating Custom Conversions
+#
+# The +accept+ method on Gem::OptionParser may be used to create converters.
+# It specifies which conversion block to call whenever a class is specified.
+# The example below uses it to fetch a +User+ object before the +on+ handler receives it.
+#
+# require 'rubygems/optparse/lib/optparse'
+#
+# User = Struct.new(:id, :name)
+#
+# def find_user id
+# not_found = ->{ raise "No User Found for id #{id}" }
+# [ User.new(1, "Sam"),
+# User.new(2, "Gandalf") ].find(not_found) do |u|
+# u.id == id
+# end
+# end
+#
+# op = Gem::OptionParser.new
+# op.accept(User) do |user_id|
+# find_user user_id.to_i
+# end
+#
+# op.on("--user ID", User) do |user|
+# puts user
+# end
+#
+# op.parse!
+#
+# Used:
+#
+# $ ruby optparse-test.rb --user 1
+# #<struct User id=1, name="Sam">
+# $ ruby optparse-test.rb --user 2
+# #<struct User id=2, name="Gandalf">
+# $ ruby optparse-test.rb --user 3
+# optparse-test.rb:15:in `block in find_user': No User Found for id 3 (RuntimeError)
+#
+# === Store options to a Hash
+#
+# The +into+ option of +order+, +parse+ and so on methods stores command line options into a Hash.
+#
+# require 'rubygems/optparse/lib/optparse'
+#
+# options = {}
+# Gem::OptionParser.new do |parser|
+# parser.on('-a')
+# parser.on('-b NUM', Integer)
+# parser.on('-v', '--verbose')
+# end.parse!(into: options)
+#
+# p options
+#
+# Used:
+#
+# $ ruby optparse-test.rb -a
+# {:a=>true}
+# $ ruby optparse-test.rb -a -v
+# {:a=>true, :verbose=>true}
+# $ ruby optparse-test.rb -a -b 100
+# {:a=>true, :b=>100}
+#
+# === Complete example
+#
+# The following example is a complete Ruby program. You can run it and see the
+# effect of specifying various options. This is probably the best way to learn
+# the features of +optparse+.
+#
+# require 'rubygems/optparse/lib/optparse'
+# require 'rubygems/optparse/lib/optparse/time'
+# require 'ostruct'
+# require 'pp'
+#
+# class OptparseExample
+# Version = '1.0.0'
+#
+# CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
+# CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
+#
+# class ScriptOptions
+# attr_accessor :library, :inplace, :encoding, :transfer_type,
+# :verbose, :extension, :delay, :time, :record_separator,
+# :list
+#
+# def initialize
+# self.library = []
+# self.inplace = false
+# self.encoding = "utf8"
+# self.transfer_type = :auto
+# self.verbose = false
+# end
+#
+# def define_options(parser)
+# parser.banner = "Usage: example.rb [options]"
+# parser.separator ""
+# parser.separator "Specific options:"
+#
+# # add additional options
+# perform_inplace_option(parser)
+# delay_execution_option(parser)
+# execute_at_time_option(parser)
+# specify_record_separator_option(parser)
+# list_example_option(parser)
+# specify_encoding_option(parser)
+# optional_option_argument_with_keyword_completion_option(parser)
+# boolean_verbose_option(parser)
+#
+# parser.separator ""
+# parser.separator "Common options:"
+# # No argument, shows at tail. This will print an options summary.
+# # Try it and see!
+# parser.on_tail("-h", "--help", "Show this message") do
+# puts parser
+# exit
+# end
+# # Another typical switch to print the version.
+# parser.on_tail("--version", "Show version") do
+# puts Version
+# exit
+# end
+# end
+#
+# def perform_inplace_option(parser)
+# # Specifies an optional option argument
+# parser.on("-i", "--inplace [EXTENSION]",
+# "Edit ARGV files in place",
+# "(make backup if EXTENSION supplied)") do |ext|
+# self.inplace = true
+# self.extension = ext || ''
+# self.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
+# end
+# end
+#
+# def delay_execution_option(parser)
+# # Cast 'delay' argument to a Float.
+# parser.on("--delay N", Float, "Delay N seconds before executing") do |n|
+# self.delay = n
+# end
+# end
+#
+# def execute_at_time_option(parser)
+# # Cast 'time' argument to a Time object.
+# parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
+# self.time = time
+# end
+# end
+#
+# def specify_record_separator_option(parser)
+# # Cast to octal integer.
+# parser.on("-F", "--irs [OCTAL]", Gem::OptionParser::OctalInteger,
+# "Specify record separator (default \\0)") do |rs|
+# self.record_separator = rs
+# end
+# end
+#
+# def list_example_option(parser)
+# # List of arguments.
+# parser.on("--list x,y,z", Array, "Example 'list' of arguments") do |list|
+# self.list = list
+# end
+# end
+#
+# def specify_encoding_option(parser)
+# # Keyword completion. We are specifying a specific set of arguments (CODES
+# # and CODE_ALIASES - notice the latter is a Hash), and the user may provide
+# # the shortest unambiguous text.
+# code_list = (CODE_ALIASES.keys + CODES).join(', ')
+# parser.on("--code CODE", CODES, CODE_ALIASES, "Select encoding",
+# "(#{code_list})") do |encoding|
+# self.encoding = encoding
+# end
+# end
+#
+# def optional_option_argument_with_keyword_completion_option(parser)
+# # Optional '--type' option argument with keyword completion.
+# parser.on("--type [TYPE]", [:text, :binary, :auto],
+# "Select transfer type (text, binary, auto)") do |t|
+# self.transfer_type = t
+# end
+# end
+#
+# def boolean_verbose_option(parser)
+# # Boolean switch.
+# parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
+# self.verbose = v
+# end
+# end
+# end
+#
+# #
+# # Return a structure describing the options.
+# #
+# def parse(args)
+# # The options specified on the command line will be collected in
+# # *options*.
+#
+# @options = ScriptOptions.new
+# @args = Gem::OptionParser.new do |parser|
+# @options.define_options(parser)
+# parser.parse!(args)
+# end
+# @options
+# end
+#
+# attr_reader :parser, :options
+# end # class OptparseExample
+#
+# example = OptparseExample.new
+# options = example.parse(ARGV)
+# pp options # example.options
+# pp ARGV
+#
+# === Shell Completion
+#
+# For modern shells (e.g. bash, zsh, etc.), you can use shell
+# completion for command line options.
+#
+# === Further documentation
+#
+# The above examples, along with the accompanying
+# {Tutorial}[optparse/tutorial.rdoc],
+# should be enough to learn how to use this class.
+# If you have any questions, file a ticket at http://bugs.ruby-lang.org.
+#
+class Gem::OptionParser
+ Gem::OptionParser::Version = "0.3.0"
+
+ # :stopdoc:
+ NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
+ RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze
+ OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze
+ # :startdoc:
+
+ #
+ # Keyword completion module. This allows partial arguments to be specified
+ # and resolved against a list of acceptable values.
+ #
+ module Completion
+ def self.regexp(key, icase)
+ Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'), icase)
+ end
+
+ def self.candidate(key, icase = false, pat = nil, &block)
+ pat ||= Completion.regexp(key, icase)
+ candidates = []
+ block.call do |k, *v|
+ (if Regexp === k
+ kn = ""
+ k === key
+ else
+ kn = defined?(k.id2name) ? k.id2name : k
+ pat === kn
+ end) or next
+ v << k if v.empty?
+ candidates << [k, v, kn]
+ end
+ candidates
+ end
+
+ def candidate(key, icase = false, pat = nil)
+ Completion.candidate(key, icase, pat, &method(:each))
+ end
+
+ public
+ def complete(key, icase = false, pat = nil)
+ candidates = candidate(key, icase, pat, &method(:each)).sort_by {|k, v, kn| kn.size}
+ if candidates.size == 1
+ canon, sw, * = candidates[0]
+ elsif candidates.size > 1
+ canon, sw, cn = candidates.shift
+ candidates.each do |k, v, kn|
+ next if sw == v
+ if String === cn and String === kn
+ if cn.rindex(kn, 0)
+ canon, sw, cn = k, v, kn
+ next
+ elsif kn.rindex(cn, 0)
+ next
+ end
+ end
+ throw :ambiguous, key
+ end
+ end
+ if canon
+ block_given? or return key, *sw
+ yield(key, *sw)
+ end
+ end
+
+ def convert(opt = nil, val = nil, *)
+ val
+ end
+ end
+
+
+ #
+ # Map from option/keyword string to object with completion.
+ #
+ class OptionMap < Hash
+ include Completion
+ end
+
+
+ #
+ # Individual switch class. Not important to the user.
+ #
+ # Defined within Switch are several Switch-derived classes: NoArgument,
+ # RequiredArgument, etc.
+ #
+ class Switch
+ attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block
+
+ #
+ # Guesses argument style from +arg+. Returns corresponding
+ # Gem::OptionParser::Switch class (OptionalArgument, etc.).
+ #
+ def self.guess(arg)
+ case arg
+ when ""
+ t = self
+ when /\A=?\[/
+ t = Switch::OptionalArgument
+ when /\A\s+\[/
+ t = Switch::PlacedArgument
+ else
+ t = Switch::RequiredArgument
+ end
+ self >= t or incompatible_argument_styles(arg, t)
+ t
+ end
+
+ def self.incompatible_argument_styles(arg, t)
+ raise(ArgumentError, "#{arg}: incompatible argument styles\n #{self}, #{t}",
+ ParseError.filter_backtrace(caller(2)))
+ end
+
+ def self.pattern
+ NilClass
+ end
+
+ def initialize(pattern = nil, conv = nil,
+ short = nil, long = nil, arg = nil,
+ desc = ([] if short or long), block = nil, &_block)
+ raise if Array === pattern
+ block ||= _block
+ @pattern, @conv, @short, @long, @arg, @desc, @block =
+ pattern, conv, short, long, arg, desc, block
+ end
+
+ #
+ # Parses +arg+ and returns rest of +arg+ and matched portion to the
+ # argument pattern. Yields when the pattern doesn't match substring.
+ #
+ def parse_arg(arg) # :nodoc:
+ pattern or return nil, [arg]
+ unless m = pattern.match(arg)
+ yield(InvalidArgument, arg)
+ return arg, []
+ end
+ if String === m
+ m = [s = m]
+ else
+ m = m.to_a
+ s = m[0]
+ return nil, m unless String === s
+ end
+ raise InvalidArgument, arg unless arg.rindex(s, 0)
+ return nil, m if s.length == arg.length
+ yield(InvalidArgument, arg) # didn't match whole arg
+ return arg[s.length..-1], m
+ end
+ private :parse_arg
+
+ #
+ # Parses argument, converts and returns +arg+, +block+ and result of
+ # conversion. Yields at semi-error condition instead of raising an
+ # exception.
+ #
+ def conv_arg(arg, val = []) # :nodoc:
+ if conv
+ val = conv.call(*val)
+ else
+ val = proc {|v| v}.call(*val)
+ end
+ return arg, block, val
+ end
+ private :conv_arg
+
+ #
+ # Produces the summary text. Each line of the summary is yielded to the
+ # block (without newline).
+ #
+ # +sdone+:: Already summarized short style options keyed hash.
+ # +ldone+:: Already summarized long style options keyed hash.
+ # +width+:: Width of left side (option part). In other words, the right
+ # side (description part) starts after +width+ columns.
+ # +max+:: Maximum width of left side -> the options are filled within
+ # +max+ columns.
+ # +indent+:: Prefix string indents all summarized lines.
+ #
+ def summarize(sdone = {}, ldone = {}, width = 1, max = width - 1, indent = "")
+ sopts, lopts = [], [], nil
+ @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
+ @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
+ return if sopts.empty? and lopts.empty? # completely hidden
+
+ left = [sopts.join(', ')]
+ right = desc.dup
+
+ while s = lopts.shift
+ l = left[-1].length + s.length
+ l += arg.length if left.size == 1 && arg
+ l < max or sopts.empty? or left << +''
+ left[-1] << (left[-1].empty? ? ' ' * 4 : ', ') << s
+ end
+
+ if arg
+ left[0] << (left[1] ? arg.sub(/\A(\[?)=/, '\1') + ',' : arg)
+ end
+ mlen = left.collect {|ss| ss.length}.max.to_i
+ while mlen > width and l = left.shift
+ mlen = left.collect {|ss| ss.length}.max.to_i if l.length == mlen
+ if l.length < width and (r = right[0]) and !r.empty?
+ l = l.to_s.ljust(width) + ' ' + r
+ right.shift
+ end
+ yield(indent + l)
+ end
+
+ while begin l = left.shift; r = right.shift; l or r end
+ l = l.to_s.ljust(width) + ' ' + r if r and !r.empty?
+ yield(indent + l)
+ end
+
+ self
+ end
+
+ def add_banner(to) # :nodoc:
+ unless @short or @long
+ s = desc.join
+ to << " [" + s + "]..." unless s.empty?
+ end
+ to
+ end
+
+ def match_nonswitch?(str) # :nodoc:
+ @pattern =~ str unless @short or @long
+ end
+
+ #
+ # Main name of the switch.
+ #
+ def switch_name
+ (long.first || short.first).sub(/\A-+(?:\[no-\])?/, '')
+ end
+
+ def compsys(sdone, ldone) # :nodoc:
+ sopts, lopts = [], []
+ @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
+ @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
+ return if sopts.empty? and lopts.empty? # completely hidden
+
+ (sopts+lopts).each do |opt|
+ # "(-x -c -r)-l[left justify]"
+ if /^--\[no-\](.+)$/ =~ opt
+ o = $1
+ yield("--#{o}", desc.join(""))
+ yield("--no-#{o}", desc.join(""))
+ else
+ yield("#{opt}", desc.join(""))
+ end
+ end
+ end
+
+ def pretty_print_contents(q) # :nodoc:
+ if @block
+ q.text ":" + @block.source_location.join(":") + ":"
+ first = false
+ else
+ first = true
+ end
+ [@short, @long].each do |list|
+ list.each do |opt|
+ if first
+ q.text ":"
+ first = false
+ end
+ q.breakable
+ q.text opt
+ end
+ end
+ end
+
+ def pretty_print(q) # :nodoc:
+ q.object_group(self) {pretty_print_contents(q)}
+ end
+
+ #
+ # Switch that takes no arguments.
+ #
+ class NoArgument < self
+
+ #
+ # Raises an exception if any arguments given.
+ #
+ def parse(arg, argv)
+ yield(NeedlessArgument, arg) if arg
+ conv_arg(arg)
+ end
+
+ def self.incompatible_argument_styles(*)
+ end
+
+ def self.pattern
+ Object
+ end
+
+ def pretty_head # :nodoc:
+ "NoArgument"
+ end
+ end
+
+ #
+ # Switch that takes an argument.
+ #
+ class RequiredArgument < self
+
+ #
+ # Raises an exception if argument is not present.
+ #
+ def parse(arg, argv)
+ unless arg
+ raise MissingArgument if argv.empty?
+ arg = argv.shift
+ end
+ conv_arg(*parse_arg(arg, &method(:raise)))
+ end
+
+ def pretty_head # :nodoc:
+ "Required"
+ end
+ end
+
+ #
+ # Switch that can omit argument.
+ #
+ class OptionalArgument < self
+
+ #
+ # Parses argument if given, or uses default value.
+ #
+ def parse(arg, argv, &error)
+ if arg
+ conv_arg(*parse_arg(arg, &error))
+ else
+ conv_arg(arg)
+ end
+ end
+
+ def pretty_head # :nodoc:
+ "Optional"
+ end
+ end
+
+ #
+ # Switch that takes an argument, which does not begin with '-' or is '-'.
+ #
+ class PlacedArgument < self
+
+ #
+ # Returns nil if argument is not present or begins with '-' and is not '-'.
+ #
+ def parse(arg, argv, &error)
+ if !(val = arg) and (argv.empty? or /\A-./ =~ (val = argv[0]))
+ return nil, block, nil
+ end
+ opt = (val = parse_arg(val, &error))[1]
+ val = conv_arg(*val)
+ if opt and !arg
+ argv.shift
+ else
+ val[0] = nil
+ end
+ val
+ end
+
+ def pretty_head # :nodoc:
+ "Placed"
+ end
+ end
+ end
+
+ #
+ # Simple option list providing mapping from short and/or long option
+ # string to Gem::OptionParser::Switch and mapping from acceptable argument to
+ # matching pattern and converter pair. Also provides summary feature.
+ #
+ class List
+ # Map from acceptable argument types to pattern and converter pairs.
+ attr_reader :atype
+
+ # Map from short style option switches to actual switch objects.
+ attr_reader :short
+
+ # Map from long style option switches to actual switch objects.
+ attr_reader :long
+
+ # List of all switches and summary string.
+ attr_reader :list
+
+ #
+ # Just initializes all instance variables.
+ #
+ def initialize
+ @atype = {}
+ @short = OptionMap.new
+ @long = OptionMap.new
+ @list = []
+ end
+
+ def pretty_print(q) # :nodoc:
+ q.group(1, "(", ")") do
+ @list.each do |sw|
+ next unless Switch === sw
+ q.group(1, "(" + sw.pretty_head, ")") do
+ sw.pretty_print_contents(q)
+ end
+ end
+ end
+ end
+
+ #
+ # See Gem::OptionParser.accept.
+ #
+ def accept(t, pat = /.*/m, &block)
+ if pat
+ pat.respond_to?(:match) or
+ raise TypeError, "has no `match'", ParseError.filter_backtrace(caller(2))
+ else
+ pat = t if t.respond_to?(:match)
+ end
+ unless block
+ block = pat.method(:convert).to_proc if pat.respond_to?(:convert)
+ end
+ @atype[t] = [pat, block]
+ end
+
+ #
+ # See Gem::OptionParser.reject.
+ #
+ def reject(t)
+ @atype.delete(t)
+ end
+
+ #
+ # Adds +sw+ according to +sopts+, +lopts+ and +nlopts+.
+ #
+ # +sw+:: Gem::OptionParser::Switch instance to be added.
+ # +sopts+:: Short style option list.
+ # +lopts+:: Long style option list.
+ # +nlopts+:: Negated long style options list.
+ #
+ def update(sw, sopts, lopts, nsw = nil, nlopts = nil) # :nodoc:
+ sopts.each {|o| @short[o] = sw} if sopts
+ lopts.each {|o| @long[o] = sw} if lopts
+ nlopts.each {|o| @long[o] = nsw} if nsw and nlopts
+ used = @short.invert.update(@long.invert)
+ @list.delete_if {|o| Switch === o and !used[o]}
+ end
+ private :update
+
+ #
+ # Inserts +switch+ at the head of the list, and associates short, long
+ # and negated long options. Arguments are:
+ #
+ # +switch+:: Gem::OptionParser::Switch instance to be inserted.
+ # +short_opts+:: List of short style options.
+ # +long_opts+:: List of long style options.
+ # +nolong_opts+:: List of long style options with "no-" prefix.
+ #
+ # prepend(switch, short_opts, long_opts, nolong_opts)
+ #
+ def prepend(*args)
+ update(*args)
+ @list.unshift(args[0])
+ end
+
+ #
+ # Appends +switch+ at the tail of the list, and associates short, long
+ # and negated long options. Arguments are:
+ #
+ # +switch+:: Gem::OptionParser::Switch instance to be inserted.
+ # +short_opts+:: List of short style options.
+ # +long_opts+:: List of long style options.
+ # +nolong_opts+:: List of long style options with "no-" prefix.
+ #
+ # append(switch, short_opts, long_opts, nolong_opts)
+ #
+ def append(*args)
+ update(*args)
+ @list.push(args[0])
+ end
+
+ #
+ # Searches +key+ in +id+ list. The result is returned or yielded if a
+ # block is given. If it isn't found, nil is returned.
+ #
+ def search(id, key)
+ if list = __send__(id)
+ val = list.fetch(key) {return nil}
+ block_given? ? yield(val) : val
+ end
+ end
+
+ #
+ # Searches list +id+ for +opt+ and the optional patterns for completion
+ # +pat+. If +icase+ is true, the search is case insensitive. The result
+ # is returned or yielded if a block is given. If it isn't found, nil is
+ # returned.
+ #
+ def complete(id, opt, icase = false, *pat, &block)
+ __send__(id).complete(opt, icase, *pat, &block)
+ end
+
+ def get_candidates(id)
+ yield __send__(id).keys
+ end
+
+ #
+ # Iterates over each option, passing the option to the +block+.
+ #
+ def each_option(&block)
+ list.each(&block)
+ end
+
+ #
+ # Creates the summary table, passing each line to the +block+ (without
+ # newline). The arguments +args+ are passed along to the summarize
+ # method which is called on every option.
+ #
+ def summarize(*args, &block)
+ sum = []
+ list.reverse_each do |opt|
+ if opt.respond_to?(:summarize) # perhaps Gem::OptionParser::Switch
+ s = []
+ opt.summarize(*args) {|l| s << l}
+ sum.concat(s.reverse)
+ elsif !opt or opt.empty?
+ sum << ""
+ elsif opt.respond_to?(:each_line)
+ sum.concat([*opt.each_line].reverse)
+ else
+ sum.concat([*opt.each].reverse)
+ end
+ end
+ sum.reverse_each(&block)
+ end
+
+ def add_banner(to) # :nodoc:
+ list.each do |opt|
+ if opt.respond_to?(:add_banner)
+ opt.add_banner(to)
+ end
+ end
+ to
+ end
+
+ def compsys(*args, &block) # :nodoc:
+ list.each do |opt|
+ if opt.respond_to?(:compsys)
+ opt.compsys(*args, &block)
+ end
+ end
+ end
+ end
+
+ #
+ # Hash with completion search feature. See Gem::OptionParser::Completion.
+ #
+ class CompletingHash < Hash
+ include Completion
+
+ #
+ # Completion for hash key.
+ #
+ def match(key)
+ *values = fetch(key) {
+ raise AmbiguousArgument, catch(:ambiguous) {return complete(key)}
+ }
+ return key, *values
+ end
+ end
+
+ # :stopdoc:
+
+ #
+ # Enumeration of acceptable argument styles. Possible values are:
+ #
+ # NO_ARGUMENT:: The switch takes no arguments. (:NONE)
+ # REQUIRED_ARGUMENT:: The switch requires an argument. (:REQUIRED)
+ # OPTIONAL_ARGUMENT:: The switch requires an optional argument. (:OPTIONAL)
+ #
+ # Use like --switch=argument (long style) or -Xargument (short style). For
+ # short style, only portion matched to argument pattern is treated as
+ # argument.
+ #
+ ArgumentStyle = {}
+ NoArgument.each {|el| ArgumentStyle[el] = Switch::NoArgument}
+ RequiredArgument.each {|el| ArgumentStyle[el] = Switch::RequiredArgument}
+ OptionalArgument.each {|el| ArgumentStyle[el] = Switch::OptionalArgument}
+ ArgumentStyle.freeze
+
+ #
+ # Switches common used such as '--', and also provides default
+ # argument classes
+ #
+ DefaultList = List.new
+ DefaultList.short['-'] = Switch::NoArgument.new {}
+ DefaultList.long[''] = Switch::NoArgument.new {throw :terminate}
+
+
+ COMPSYS_HEADER = <<'XXX' # :nodoc:
+
+typeset -A opt_args
+local context state line
+
+_arguments -s -S \
+XXX
+
+ def compsys(to, name = File.basename($0)) # :nodoc:
+ to << "#compdef #{name}\n"
+ to << COMPSYS_HEADER
+ visit(:compsys, {}, {}) {|o, d|
+ to << %Q[ "#{o}[#{d.gsub(/[\"\[\]]/, '\\\\\&')}]" \\\n]
+ }
+ to << " '*:file:_files' && return 0\n"
+ end
+
+ #
+ # Default options for ARGV, which never appear in option summary.
+ #
+ Officious = {}
+
+ #
+ # --help
+ # Shows option summary.
+ #
+ Officious['help'] = proc do |parser|
+ Switch::NoArgument.new do |arg|
+ puts parser.help
+ exit
+ end
+ end
+
+ #
+ # --*-completion-bash=WORD
+ # Shows candidates for command line completion.
+ #
+ Officious['*-completion-bash'] = proc do |parser|
+ Switch::RequiredArgument.new do |arg|
+ puts parser.candidate(arg)
+ exit
+ end
+ end
+
+ #
+ # --*-completion-zsh[=NAME:FILE]
+ # Creates zsh completion file.
+ #
+ Officious['*-completion-zsh'] = proc do |parser|
+ Switch::OptionalArgument.new do |arg|
+ parser.compsys(STDOUT, arg)
+ exit
+ end
+ end
+
+ #
+ # --version
+ # Shows version string if Version is defined.
+ #
+ Officious['version'] = proc do |parser|
+ Switch::OptionalArgument.new do |pkg|
+ if pkg
+ begin
+ require 'rubygems/optparse/lib/optparse/version'
+ rescue LoadError
+ else
+ show_version(*pkg.split(/,/)) or
+ abort("#{parser.program_name}: no version found in package #{pkg}")
+ exit
+ end
+ end
+ v = parser.ver or abort("#{parser.program_name}: version unknown")
+ puts v
+ exit
+ end
+ end
+
+ # :startdoc:
+
+ #
+ # Class methods
+ #
+
+ #
+ # Initializes a new instance and evaluates the optional block in context
+ # of the instance. Arguments +args+ are passed to #new, see there for
+ # description of parameters.
+ #
+ # This method is *deprecated*, its behavior corresponds to the older #new
+ # method.
+ #
+ def self.with(*args, &block)
+ opts = new(*args)
+ opts.instance_eval(&block)
+ opts
+ end
+
+ #
+ # Returns an incremented value of +default+ according to +arg+.
+ #
+ def self.inc(arg, default = nil)
+ case arg
+ when Integer
+ arg.nonzero?
+ when nil
+ default.to_i + 1
+ end
+ end
+ def inc(*args)
+ self.class.inc(*args)
+ end
+
+ #
+ # Initializes the instance and yields itself if called with a block.
+ #
+ # +banner+:: Banner message.
+ # +width+:: Summary width.
+ # +indent+:: Summary indent.
+ #
+ def initialize(banner = nil, width = 32, indent = ' ' * 4)
+ @stack = [DefaultList, List.new, List.new]
+ @program_name = nil
+ @banner = banner
+ @summary_width = width
+ @summary_indent = indent
+ @default_argv = ARGV
+ @require_exact = false
+ @raise_unknown = true
+ add_officious
+ yield self if block_given?
+ end
+
+ def add_officious # :nodoc:
+ list = base()
+ Officious.each do |opt, block|
+ list.long[opt] ||= block.call(self)
+ end
+ end
+
+ #
+ # Terminates option parsing. Optional parameter +arg+ is a string pushed
+ # back to be the first non-option argument.
+ #
+ def terminate(arg = nil)
+ self.class.terminate(arg)
+ end
+ def self.terminate(arg = nil)
+ throw :terminate, arg
+ end
+
+ @stack = [DefaultList]
+ def self.top() DefaultList end
+
+ #
+ # Directs to accept specified class +t+. The argument string is passed to
+ # the block in which it should be converted to the desired class.
+ #
+ # +t+:: Argument class specifier, any object including Class.
+ # +pat+:: Pattern for argument, defaults to +t+ if it responds to match.
+ #
+ # accept(t, pat, &block)
+ #
+ def accept(*args, &blk) top.accept(*args, &blk) end
+ #
+ # See #accept.
+ #
+ def self.accept(*args, &blk) top.accept(*args, &blk) end
+
+ #
+ # Directs to reject specified class argument.
+ #
+ # +t+:: Argument class specifier, any object including Class.
+ #
+ # reject(t)
+ #
+ def reject(*args, &blk) top.reject(*args, &blk) end
+ #
+ # See #reject.
+ #
+ def self.reject(*args, &blk) top.reject(*args, &blk) end
+
+ #
+ # Instance methods
+ #
+
+ # Heading banner preceding summary.
+ attr_writer :banner
+
+ # Program name to be emitted in error message and default banner,
+ # defaults to $0.
+ attr_writer :program_name
+
+ # Width for option list portion of summary. Must be Numeric.
+ attr_accessor :summary_width
+
+ # Indentation for summary. Must be String (or have + String method).
+ attr_accessor :summary_indent
+
+ # Strings to be parsed in default.
+ attr_accessor :default_argv
+
+ # Whether to require that options match exactly (disallows providing
+ # abbreviated long option as short option).
+ attr_accessor :require_exact
+
+ # Whether to raise at unknown option.
+ attr_accessor :raise_unknown
+
+ #
+ # Heading banner preceding summary.
+ #
+ def banner
+ unless @banner
+ @banner = +"Usage: #{program_name} [options]"
+ visit(:add_banner, @banner)
+ end
+ @banner
+ end
+
+ #
+ # Program name to be emitted in error message and default banner, defaults
+ # to $0.
+ #
+ def program_name
+ @program_name || File.basename($0, '.*')
+ end
+
+ # for experimental cascading :-)
+ alias set_banner banner=
+ alias set_program_name program_name=
+ alias set_summary_width summary_width=
+ alias set_summary_indent summary_indent=
+
+ # Version
+ attr_writer :version
+ # Release code
+ attr_writer :release
+
+ #
+ # Version
+ #
+ def version
+ (defined?(@version) && @version) || (defined?(::Version) && ::Version)
+ end
+
+ #
+ # Release code
+ #
+ def release
+ (defined?(@release) && @release) || (defined?(::Release) && ::Release) || (defined?(::RELEASE) && ::RELEASE)
+ end
+
+ #
+ # Returns version string from program_name, version and release.
+ #
+ def ver
+ if v = version
+ str = +"#{program_name} #{[v].join('.')}"
+ str << " (#{v})" if v = release
+ str
+ end
+ end
+
+ def warn(mesg = $!)
+ super("#{program_name}: #{mesg}")
+ end
+
+ def abort(mesg = $!)
+ super("#{program_name}: #{mesg}")
+ end
+
+ #
+ # Subject of #on / #on_head, #accept / #reject
+ #
+ def top
+ @stack[-1]
+ end
+
+ #
+ # Subject of #on_tail.
+ #
+ def base
+ @stack[1]
+ end
+
+ #
+ # Pushes a new List.
+ #
+ def new
+ @stack.push(List.new)
+ if block_given?
+ yield self
+ else
+ self
+ end
+ end
+
+ #
+ # Removes the last List.
+ #
+ def remove
+ @stack.pop
+ end
+
+ #
+ # Puts option summary into +to+ and returns +to+. Yields each line if
+ # a block is given.
+ #
+ # +to+:: Output destination, which must have method <<. Defaults to [].
+ # +width+:: Width of left side, defaults to @summary_width.
+ # +max+:: Maximum length allowed for left side, defaults to +width+ - 1.
+ # +indent+:: Indentation, defaults to @summary_indent.
+ #
+ def summarize(to = [], width = @summary_width, max = width - 1, indent = @summary_indent, &blk)
+ nl = "\n"
+ blk ||= proc {|l| to << (l.index(nl, -1) ? l : l + nl)}
+ visit(:summarize, {}, {}, width, max, indent, &blk)
+ to
+ end
+
+ #
+ # Returns option summary string.
+ #
+ def help; summarize("#{banner}".sub(/\n?\z/, "\n")) end
+ alias to_s help
+
+ def pretty_print(q) # :nodoc:
+ q.object_group(self) do
+ first = true
+ if @stack.size > 2
+ @stack.each_with_index do |s, i|
+ next if i < 2
+ next if s.list.empty?
+ if first
+ first = false
+ q.text ":"
+ end
+ q.breakable
+ s.pretty_print(q)
+ end
+ end
+ end
+ end
+
+ def inspect # :nodoc:
+ require 'pp'
+ pretty_print_inspect
+ end
+
+ #
+ # Returns option summary list.
+ #
+ def to_a; summarize("#{banner}".split(/^/)) end
+
+ #
+ # Checks if an argument is given twice, in which case an ArgumentError is
+ # raised. Called from Gem::OptionParser#switch only.
+ #
+ # +obj+:: New argument.
+ # +prv+:: Previously specified argument.
+ # +msg+:: Exception message.
+ #
+ def notwice(obj, prv, msg) # :nodoc:
+ unless !prv or prv == obj
+ raise(ArgumentError, "argument #{msg} given twice: #{obj}",
+ ParseError.filter_backtrace(caller(2)))
+ end
+ obj
+ end
+ private :notwice
+
+ SPLAT_PROC = proc {|*a| a.length <= 1 ? a.first : a} # :nodoc:
+
+ # :call-seq:
+ # make_switch(params, block = nil)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ def make_switch(opts, block = nil)
+ short, long, nolong, style, pattern, conv, not_pattern, not_conv, not_style = [], [], []
+ ldesc, sdesc, desc, arg = [], [], []
+ default_style = Switch::NoArgument
+ default_pattern = nil
+ klass = nil
+ q, a = nil
+ has_arg = false
+
+ opts.each do |o|
+ # argument class
+ next if search(:atype, o) do |pat, c|
+ klass = notwice(o, klass, 'type')
+ if not_style and not_style != Switch::NoArgument
+ not_pattern, not_conv = pat, c
+ else
+ default_pattern, conv = pat, c
+ end
+ end
+
+ # directly specified pattern(any object possible to match)
+ if (!(String === o || Symbol === o)) and o.respond_to?(:match)
+ pattern = notwice(o, pattern, 'pattern')
+ if pattern.respond_to?(:convert)
+ conv = pattern.method(:convert).to_proc
+ else
+ conv = SPLAT_PROC
+ end
+ next
+ end
+
+ # anything others
+ case o
+ when Proc, Method
+ block = notwice(o, block, 'block')
+ when Array, Hash
+ case pattern
+ when CompletingHash
+ when nil
+ pattern = CompletingHash.new
+ conv = pattern.method(:convert).to_proc if pattern.respond_to?(:convert)
+ else
+ raise ArgumentError, "argument pattern given twice"
+ end
+ o.each {|pat, *v| pattern[pat] = v.fetch(0) {pat}}
+ when Module
+ raise ArgumentError, "unsupported argument type: #{o}", ParseError.filter_backtrace(caller(4))
+ when *ArgumentStyle.keys
+ style = notwice(ArgumentStyle[o], style, 'style')
+ when /^--no-([^\[\]=\s]*)(.+)?/
+ q, a = $1, $2
+ o = notwice(a ? Object : TrueClass, klass, 'type')
+ not_pattern, not_conv = search(:atype, o) unless not_style
+ not_style = (not_style || default_style).guess(arg = a) if a
+ default_style = Switch::NoArgument
+ default_pattern, conv = search(:atype, FalseClass) unless default_pattern
+ ldesc << "--no-#{q}"
+ (q = q.downcase).tr!('_', '-')
+ long << "no-#{q}"
+ nolong << q
+ when /^--\[no-\]([^\[\]=\s]*)(.+)?/
+ q, a = $1, $2
+ o = notwice(a ? Object : TrueClass, klass, 'type')
+ if a
+ default_style = default_style.guess(arg = a)
+ default_pattern, conv = search(:atype, o) unless default_pattern
+ end
+ ldesc << "--[no-]#{q}"
+ (o = q.downcase).tr!('_', '-')
+ long << o
+ not_pattern, not_conv = search(:atype, FalseClass) unless not_style
+ not_style = Switch::NoArgument
+ nolong << "no-#{o}"
+ when /^--([^\[\]=\s]*)(.+)?/
+ q, a = $1, $2
+ if a
+ o = notwice(NilClass, klass, 'type')
+ default_style = default_style.guess(arg = a)
+ default_pattern, conv = search(:atype, o) unless default_pattern
+ end
+ ldesc << "--#{q}"
+ (o = q.downcase).tr!('_', '-')
+ long << o
+ when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
+ q, a = $1, $2
+ o = notwice(Object, klass, 'type')
+ if a
+ default_style = default_style.guess(arg = a)
+ default_pattern, conv = search(:atype, o) unless default_pattern
+ else
+ has_arg = true
+ end
+ sdesc << "-#{q}"
+ short << Regexp.new(q)
+ when /^-(.)(.+)?/
+ q, a = $1, $2
+ if a
+ o = notwice(NilClass, klass, 'type')
+ default_style = default_style.guess(arg = a)
+ default_pattern, conv = search(:atype, o) unless default_pattern
+ end
+ sdesc << "-#{q}"
+ short << q
+ when /^=/
+ style = notwice(default_style.guess(arg = o), style, 'style')
+ default_pattern, conv = search(:atype, Object) unless default_pattern
+ else
+ desc.push(o) if o && !o.empty?
+ end
+ end
+
+ default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern
+ if !(short.empty? and long.empty?)
+ if has_arg and default_style == Switch::NoArgument
+ default_style = Switch::RequiredArgument
+ end
+ s = (style || default_style).new(pattern || default_pattern,
+ conv, sdesc, ldesc, arg, desc, block)
+ elsif !block
+ if style or pattern
+ raise ArgumentError, "no switch given", ParseError.filter_backtrace(caller)
+ end
+ s = desc
+ else
+ short << pattern
+ s = (style || default_style).new(pattern,
+ conv, nil, nil, arg, desc, block)
+ end
+ return s, short, long,
+ (not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style),
+ nolong
+ end
+
+ # :call-seq:
+ # define(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ def define(*opts, &block)
+ top.append(*(sw = make_switch(opts, block)))
+ sw[0]
+ end
+
+ # :call-seq:
+ # on(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ def on(*opts, &block)
+ define(*opts, &block)
+ self
+ end
+ alias def_option define
+
+ # :call-seq:
+ # define_head(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ def define_head(*opts, &block)
+ top.prepend(*(sw = make_switch(opts, block)))
+ sw[0]
+ end
+
+ # :call-seq:
+ # on_head(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ # The new option is added at the head of the summary.
+ #
+ def on_head(*opts, &block)
+ define_head(*opts, &block)
+ self
+ end
+ alias def_head_option define_head
+
+ # :call-seq:
+ # define_tail(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ def define_tail(*opts, &block)
+ base.append(*(sw = make_switch(opts, block)))
+ sw[0]
+ end
+
+ #
+ # :call-seq:
+ # on_tail(*params, &block)
+ #
+ # :include: ../doc/optparse/creates_option.rdoc
+ #
+ # The new option is added at the tail of the summary.
+ #
+ def on_tail(*opts, &block)
+ define_tail(*opts, &block)
+ self
+ end
+ alias def_tail_option define_tail
+
+ #
+ # Add separator in summary.
+ #
+ def separator(string)
+ top.append(string, nil, nil)
+ end
+
+ #
+ # Parses command line arguments +argv+ in order. When a block is given,
+ # each non-option argument is yielded. When optional +into+ keyword
+ # argument is provided, the parsed option values are stored there via
+ # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
+ # similar object).
+ #
+ # Returns the rest of +argv+ left unparsed.
+ #
+ def order(*argv, into: nil, &nonopt)
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
+ order!(argv, into: into, &nonopt)
+ end
+
+ #
+ # Same as #order, but removes switches destructively.
+ # Non-option arguments remain in +argv+.
+ #
+ def order!(argv = default_argv, into: nil, &nonopt)
+ setter = ->(name, val) {into[name.to_sym] = val} if into
+ parse_in_order(argv, setter, &nonopt)
+ end
+
+ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
+ opt, arg, val, rest = nil
+ nonopt ||= proc {|a| throw :terminate, a}
+ argv.unshift(arg) if arg = catch(:terminate) {
+ while arg = argv.shift
+ case arg
+ # long option
+ when /\A--([^=]*)(?:=(.*))?/m
+ opt, rest = $1, $2
+ opt.tr!('_', '-')
+ begin
+ sw, = complete(:long, opt, true)
+ if require_exact && !sw.long.include?(arg)
+ throw :terminate, arg unless raise_unknown
+ raise InvalidOption, arg
+ end
+ rescue ParseError
+ throw :terminate, arg unless raise_unknown
+ raise $!.set_option(arg, true)
+ end
+ begin
+ opt, cb, val = sw.parse(rest, argv) {|*exc| raise(*exc)}
+ val = cb.call(val) if cb
+ setter.call(sw.switch_name, val) if setter
+ rescue ParseError
+ raise $!.set_option(arg, rest)
+ end
+
+ # short option
+ when /\A-(.)((=).*|.+)?/m
+ eq, rest, opt = $3, $2, $1
+ has_arg, val = eq, rest
+ begin
+ sw, = search(:short, opt)
+ unless sw
+ begin
+ sw, = complete(:short, opt)
+ # short option matched.
+ val = arg.delete_prefix('-')
+ has_arg = true
+ rescue InvalidOption
+ raise if require_exact
+ # if no short options match, try completion with long
+ # options.
+ sw, = complete(:long, opt)
+ eq ||= !rest
+ end
+ end
+ rescue ParseError
+ throw :terminate, arg unless raise_unknown
+ raise $!.set_option(arg, true)
+ end
+ begin
+ opt, cb, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq}
+ rescue ParseError
+ raise $!.set_option(arg, arg.length > 2)
+ else
+ raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}"
+ end
+ begin
+ argv.unshift(opt) if opt and (!rest or (opt = opt.sub(/\A-*/, '-')) != '-')
+ val = cb.call(val) if cb
+ setter.call(sw.switch_name, val) if setter
+ rescue ParseError
+ raise $!.set_option(arg, arg.length > 2)
+ end
+
+ # non-option argument
+ else
+ catch(:prune) do
+ visit(:each_option) do |sw0|
+ sw = sw0
+ sw.block.call(arg) if Switch === sw and sw.match_nonswitch?(arg)
+ end
+ nonopt.call(arg)
+ end
+ end
+ end
+
+ nil
+ }
+
+ visit(:search, :short, nil) {|sw| sw.block.call(*argv) if !sw.pattern}
+
+ argv
+ end
+ private :parse_in_order
+
+ #
+ # Parses command line arguments +argv+ in permutation mode and returns
+ # list of non-option arguments. When optional +into+ keyword
+ # argument is provided, the parsed option values are stored there via
+ # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
+ # similar object).
+ #
+ def permute(*argv, into: nil)
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
+ permute!(argv, into: into)
+ end
+
+ #
+ # Same as #permute, but removes switches destructively.
+ # Non-option arguments remain in +argv+.
+ #
+ def permute!(argv = default_argv, into: nil)
+ nonopts = []
+ order!(argv, into: into, &nonopts.method(:<<))
+ argv[0, 0] = nonopts
+ argv
+ end
+
+ #
+ # Parses command line arguments +argv+ in order when environment variable
+ # POSIXLY_CORRECT is set, and in permutation mode otherwise.
+ # When optional +into+ keyword argument is provided, the parsed option
+ # values are stored there via <code>[]=</code> method (so it can be Hash,
+ # or OpenStruct, or other similar object).
+ #
+ def parse(*argv, into: nil)
+ argv = argv[0].dup if argv.size == 1 and Array === argv[0]
+ parse!(argv, into: into)
+ end
+
+ #
+ # Same as #parse, but removes switches destructively.
+ # Non-option arguments remain in +argv+.
+ #
+ def parse!(argv = default_argv, into: nil)
+ if ENV.include?('POSIXLY_CORRECT')
+ order!(argv, into: into)
+ else
+ permute!(argv, into: into)
+ end
+ end
+
+ #
+ # Wrapper method for getopts.rb.
+ #
+ # params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option")
+ # # params["a"] = true # -a
+ # # params["b"] = "1" # -b1
+ # # params["foo"] = "1" # --foo
+ # # params["bar"] = "x" # --bar x
+ # # params["zot"] = "z" # --zot Z
+ #
+ def getopts(*args)
+ argv = Array === args.first ? args.shift : default_argv
+ single_options, *long_options = *args
+
+ result = {}
+
+ single_options.scan(/(.)(:)?/) do |opt, val|
+ if val
+ result[opt] = nil
+ define("-#{opt} VAL")
+ else
+ result[opt] = false
+ define("-#{opt}")
+ end
+ end if single_options
+
+ long_options.each do |arg|
+ arg, desc = arg.split(';', 2)
+ opt, val = arg.split(':', 2)
+ if val
+ result[opt] = val.empty? ? nil : val
+ define("--#{opt}=#{result[opt] || "VAL"}", *[desc].compact)
+ else
+ result[opt] = false
+ define("--#{opt}", *[desc].compact)
+ end
+ end
+
+ parse_in_order(argv, result.method(:[]=))
+ result
+ end
+
+ #
+ # See #getopts.
+ #
+ def self.getopts(*args)
+ new.getopts(*args)
+ end
+
+ #
+ # Traverses @stack, sending each element method +id+ with +args+ and
+ # +block+.
+ #
+ def visit(id, *args, &block) # :nodoc:
+ @stack.reverse_each do |el|
+ el.__send__(id, *args, &block)
+ end
+ nil
+ end
+ private :visit
+
+ #
+ # Searches +key+ in @stack for +id+ hash and returns or yields the result.
+ #
+ def search(id, key) # :nodoc:
+ block_given = block_given?
+ visit(:search, id, key) do |k|
+ return block_given ? yield(k) : k
+ end
+ end
+ private :search
+
+ #
+ # Completes shortened long style option switch and returns pair of
+ # canonical switch and switch descriptor Gem::OptionParser::Switch.
+ #
+ # +typ+:: Searching table.
+ # +opt+:: Searching key.
+ # +icase+:: Search case insensitive if true.
+ # +pat+:: Optional pattern for completion.
+ #
+ def complete(typ, opt, icase = false, *pat) # :nodoc:
+ if pat.empty?
+ search(typ, opt) {|sw| return [sw, opt]} # exact match or...
+ end
+ ambiguous = catch(:ambiguous) {
+ visit(:complete, typ, opt, icase, *pat) {|o, *sw| return sw}
+ }
+ exc = ambiguous ? AmbiguousOption : InvalidOption
+ raise exc.new(opt, additional: self.method(:additional_message).curry[typ])
+ end
+ private :complete
+
+ #
+ # Returns additional info.
+ #
+ def additional_message(typ, opt)
+ return unless typ and opt and defined?(DidYouMean::SpellChecker)
+ all_candidates = []
+ visit(:get_candidates, typ) do |candidates|
+ all_candidates.concat(candidates)
+ end
+ all_candidates.select! {|cand| cand.is_a?(String) }
+ checker = DidYouMean::SpellChecker.new(dictionary: all_candidates)
+ DidYouMean.formatter.message_for(all_candidates & checker.correct(opt))
+ end
+
+ def candidate(word)
+ list = []
+ case word
+ when '-'
+ long = short = true
+ when /\A--/
+ word, arg = word.split(/=/, 2)
+ argpat = Completion.regexp(arg, false) if arg and !arg.empty?
+ long = true
+ when /\A-/
+ short = true
+ end
+ pat = Completion.regexp(word, long)
+ visit(:each_option) do |opt|
+ next unless Switch === opt
+ opts = (long ? opt.long : []) + (short ? opt.short : [])
+ opts = Completion.candidate(word, true, pat, &opts.method(:each)).map(&:first) if pat
+ if /\A=/ =~ opt.arg
+ opts.map! {|sw| sw + "="}
+ if arg and CompletingHash === opt.pattern
+ if opts = opt.pattern.candidate(arg, false, argpat)
+ opts.map!(&:last)
+ end
+ end
+ end
+ list.concat(opts)
+ end
+ list
+ end
+
+ #
+ # Loads options from file names as +filename+. Does nothing when the file
+ # is not present. Returns whether successfully loaded.
+ #
+ # +filename+ defaults to basename of the program without suffix in a
+ # directory ~/.options, then the basename with '.options' suffix
+ # under XDG and Haiku standard places.
+ #
+ # The optional +into+ keyword argument works exactly like that accepted in
+ # method #parse.
+ #
+ def load(filename = nil, into: nil)
+ unless filename
+ basename = File.basename($0, '.*')
+ return true if load(File.expand_path(basename, '~/.options'), into: into) rescue nil
+ basename << ".options"
+ return [
+ # XDG
+ ENV['XDG_CONFIG_HOME'],
+ '~/.config',
+ *ENV['XDG_CONFIG_DIRS']&.split(File::PATH_SEPARATOR),
+
+ # Haiku
+ '~/config/settings',
+ ].any? {|dir|
+ next if !dir or dir.empty?
+ load(File.expand_path(basename, dir), into: into) rescue nil
+ }
+ end
+ begin
+ parse(*File.readlines(filename, chomp: true), into: into)
+ true
+ rescue Errno::ENOENT, Errno::ENOTDIR
+ false
+ end
+ end
+
+ #
+ # Parses environment variable +env+ or its uppercase with splitting like a
+ # shell.
+ #
+ # +env+ defaults to the basename of the program.
+ #
+ def environment(env = File.basename($0, '.*'))
+ env = ENV[env] || ENV[env.upcase] or return
+ require 'shellwords'
+ parse(*Shellwords.shellwords(env))
+ end
+
+ #
+ # Acceptable argument classes
+ #
+
+ #
+ # Any string and no conversion. This is fall-back.
+ #
+ accept(Object) {|s,|s or s.nil?}
+
+ accept(NilClass) {|s,|s}
+
+ #
+ # Any non-empty string, and no conversion.
+ #
+ accept(String, /.+/m) {|s,*|s}
+
+ #
+ # Ruby/C-like integer, octal for 0-7 sequence, binary for 0b, hexadecimal
+ # for 0x, and decimal for others; with optional sign prefix. Converts to
+ # Integer.
+ #
+ decimal = '\d+(?:_\d+)*'
+ binary = 'b[01]+(?:_[01]+)*'
+ hex = 'x[\da-f]+(?:_[\da-f]+)*'
+ octal = "0(?:[0-7]+(?:_[0-7]+)*|#{binary}|#{hex})?"
+ integer = "#{octal}|#{decimal}"
+
+ accept(Integer, %r"\A[-+]?(?:#{integer})\z"io) {|s,|
+ begin
+ Integer(s)
+ rescue ArgumentError
+ raise Gem::OptionParser::InvalidArgument, s
+ end if s
+ }
+
+ #
+ # Float number format, and converts to Float.
+ #
+ float = "(?:#{decimal}(?=(.)?)(?:\\.(?:#{decimal})?)?|\\.#{decimal})(?:E[-+]?#{decimal})?"
+ floatpat = %r"\A[-+]?#{float}\z"io
+ accept(Float, floatpat) {|s,| s.to_f if s}
+
+ #
+ # Generic numeric format, converts to Integer for integer format, Float
+ # for float format, and Rational for rational format.
+ #
+ real = "[-+]?(?:#{octal}|#{float})"
+ accept(Numeric, /\A(#{real})(?:\/(#{real}))?\z/io) {|s, d, f, n,|
+ if n
+ Rational(d, n)
+ elsif f
+ Float(s)
+ else
+ Integer(s)
+ end
+ }
+
+ #
+ # Decimal integer format, to be converted to Integer.
+ #
+ DecimalInteger = /\A[-+]?#{decimal}\z/io
+ accept(DecimalInteger, DecimalInteger) {|s,|
+ begin
+ Integer(s, 10)
+ rescue ArgumentError
+ raise Gem::OptionParser::InvalidArgument, s
+ end if s
+ }
+
+ #
+ # Ruby/C like octal/hexadecimal/binary integer format, to be converted to
+ # Integer.
+ #
+ OctalInteger = /\A[-+]?(?:[0-7]+(?:_[0-7]+)*|0(?:#{binary}|#{hex}))\z/io
+ accept(OctalInteger, OctalInteger) {|s,|
+ begin
+ Integer(s, 8)
+ rescue ArgumentError
+ raise Gem::OptionParser::InvalidArgument, s
+ end if s
+ }
+
+ #
+ # Decimal integer/float number format, to be converted to Integer for
+ # integer format, Float for float format.
+ #
+ DecimalNumeric = floatpat # decimal integer is allowed as float also.
+ accept(DecimalNumeric, floatpat) {|s, f|
+ begin
+ if f
+ Float(s)
+ else
+ Integer(s)
+ end
+ rescue ArgumentError
+ raise Gem::OptionParser::InvalidArgument, s
+ end if s
+ }
+
+ #
+ # Boolean switch, which means whether it is present or not, whether it is
+ # absent or not with prefix no-, or it takes an argument
+ # yes/no/true/false/+/-.
+ #
+ yesno = CompletingHash.new
+ %w[- no false].each {|el| yesno[el] = false}
+ %w[+ yes true].each {|el| yesno[el] = true}
+ yesno['nil'] = false # should be nil?
+ accept(TrueClass, yesno) {|arg, val| val == nil or val}
+ #
+ # Similar to TrueClass, but defaults to false.
+ #
+ accept(FalseClass, yesno) {|arg, val| val != nil and val}
+
+ #
+ # List of strings separated by ",".
+ #
+ accept(Array) do |s, |
+ if s
+ s = s.split(',').collect {|ss| ss unless ss.empty?}
+ end
+ s
+ end
+
+ #
+ # Regular expression with options.
+ #
+ accept(Regexp, %r"\A/((?:\\.|[^\\])*)/([[:alpha:]]+)?\z|.*") do |all, s, o|
+ f = 0
+ if o
+ f |= Regexp::IGNORECASE if /i/ =~ o
+ f |= Regexp::MULTILINE if /m/ =~ o
+ f |= Regexp::EXTENDED if /x/ =~ o
+ k = o.delete("imx")
+ k = nil if k.empty?
+ end
+ Regexp.new(s || all, f, k)
+ end
+
+ #
+ # Exceptions
+ #
+
+ #
+ # Base class of exceptions from Gem::OptionParser.
+ #
+ class ParseError < RuntimeError
+ # Reason which caused the error.
+ Reason = 'parse error'
+
+ def initialize(*args, additional: nil)
+ @additional = additional
+ @arg0, = args
+ @args = args
+ @reason = nil
+ end
+
+ attr_reader :args
+ attr_writer :reason
+ attr_accessor :additional
+
+ #
+ # Pushes back erred argument(s) to +argv+.
+ #
+ def recover(argv)
+ argv[0, 0] = @args
+ argv
+ end
+
+ def self.filter_backtrace(array)
+ unless $DEBUG
+ array.delete_if(&%r"\A#{Regexp.quote(__FILE__)}:"o.method(:=~))
+ end
+ array
+ end
+
+ def set_backtrace(array)
+ super(self.class.filter_backtrace(array))
+ end
+
+ def set_option(opt, eq)
+ if eq
+ @args[0] = opt
+ else
+ @args.unshift(opt)
+ end
+ self
+ end
+
+ #
+ # Returns error reason. Override this for I18N.
+ #
+ def reason
+ @reason || self.class::Reason
+ end
+
+ def inspect
+ "#<#{self.class}: #{args.join(' ')}>"
+ end
+
+ #
+ # Default stringizing method to emit standard error message.
+ #
+ def message
+ "#{reason}: #{args.join(' ')}#{additional[@arg0] if additional}"
+ end
+
+ alias to_s message
+ end
+
+ #
+ # Raises when ambiguously completable string is encountered.
+ #
+ class AmbiguousOption < ParseError
+ const_set(:Reason, 'ambiguous option')
+ end
+
+ #
+ # Raises when there is an argument for a switch which takes no argument.
+ #
+ class NeedlessArgument < ParseError
+ const_set(:Reason, 'needless argument')
+ end
+
+ #
+ # Raises when a switch with mandatory argument has no argument.
+ #
+ class MissingArgument < ParseError
+ const_set(:Reason, 'missing argument')
+ end
+
+ #
+ # Raises when switch is undefined.
+ #
+ class InvalidOption < ParseError
+ const_set(:Reason, 'invalid option')
+ end
+
+ #
+ # Raises when the given argument does not match required format.
+ #
+ class InvalidArgument < ParseError
+ const_set(:Reason, 'invalid argument')
+ end
+
+ #
+ # Raises when the given argument word can't be completed uniquely.
+ #
+ class AmbiguousArgument < InvalidArgument
+ const_set(:Reason, 'ambiguous argument')
+ end
+
+ #
+ # Miscellaneous
+ #
+
+ #
+ # Extends command line arguments array (ARGV) to parse itself.
+ #
+ module Arguable
+
+ #
+ # Sets Gem::OptionParser object, when +opt+ is +false+ or +nil+, methods
+ # Gem::OptionParser::Arguable#options and Gem::OptionParser::Arguable#options= are
+ # undefined. Thus, there is no ways to access the Gem::OptionParser object
+ # via the receiver object.
+ #
+ def options=(opt)
+ unless @optparse = opt
+ class << self
+ undef_method(:options)
+ undef_method(:options=)
+ end
+ end
+ end
+
+ #
+ # Actual Gem::OptionParser object, automatically created if nonexistent.
+ #
+ # If called with a block, yields the Gem::OptionParser object and returns the
+ # result of the block. If an Gem::OptionParser::ParseError exception occurs
+ # in the block, it is rescued, a error message printed to STDERR and
+ # +nil+ returned.
+ #
+ def options
+ @optparse ||= Gem::OptionParser.new
+ @optparse.default_argv = self
+ block_given? or return @optparse
+ begin
+ yield @optparse
+ rescue ParseError
+ @optparse.warn $!
+ nil
+ end
+ end
+
+ #
+ # Parses +self+ destructively in order and returns +self+ containing the
+ # rest arguments left unparsed.
+ #
+ def order!(&blk) options.order!(self, &blk) end
+
+ #
+ # Parses +self+ destructively in permutation mode and returns +self+
+ # containing the rest arguments left unparsed.
+ #
+ def permute!() options.permute!(self) end
+
+ #
+ # Parses +self+ destructively and returns +self+ containing the
+ # rest arguments left unparsed.
+ #
+ def parse!() options.parse!(self) end
+
+ #
+ # Substitution of getopts is possible as follows. Also see
+ # Gem::OptionParser#getopts.
+ #
+ # def getopts(*args)
+ # ($OPT = ARGV.getopts(*args)).each do |opt, val|
+ # eval "$OPT_#{opt.gsub(/[^A-Za-z0-9_]/, '_')} = val"
+ # end
+ # rescue Gem::OptionParser::ParseError
+ # end
+ #
+ def getopts(*args)
+ options.getopts(self, *args)
+ end
+
+ #
+ # Initializes instance variable.
+ #
+ def self.extend_object(obj)
+ super
+ obj.instance_eval {@optparse = nil}
+ end
+ def initialize(*args)
+ super
+ @optparse = nil
+ end
+ end
+
+ #
+ # Acceptable argument classes. Now contains DecimalInteger, OctalInteger
+ # and DecimalNumeric. See Acceptable argument classes (in source code).
+ #
+ module Acceptables
+ const_set(:DecimalInteger, Gem::OptionParser::DecimalInteger)
+ const_set(:OctalInteger, Gem::OptionParser::OctalInteger)
+ const_set(:DecimalNumeric, Gem::OptionParser::DecimalNumeric)
+ end
+end
+
+# ARGV is arguable by Gem::OptionParser
+ARGV.extend(Gem::OptionParser::Arguable)
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/ac.rb b/lib/rubygems/optparse/lib/optparse/ac.rb
index e84d01bf91..e84d01bf91 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse/ac.rb
+++ b/lib/rubygems/optparse/lib/optparse/ac.rb
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/date.rb b/lib/rubygems/optparse/lib/optparse/date.rb
index d9a9f4f48a..d9a9f4f48a 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse/date.rb
+++ b/lib/rubygems/optparse/lib/optparse/date.rb
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/kwargs.rb b/lib/rubygems/optparse/lib/optparse/kwargs.rb
index 6987a5ed62..6987a5ed62 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse/kwargs.rb
+++ b/lib/rubygems/optparse/lib/optparse/kwargs.rb
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/shellwords.rb b/lib/rubygems/optparse/lib/optparse/shellwords.rb
index d47ad60255..d47ad60255 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse/shellwords.rb
+++ b/lib/rubygems/optparse/lib/optparse/shellwords.rb
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/time.rb b/lib/rubygems/optparse/lib/optparse/time.rb
index c59e1e4ced..c59e1e4ced 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse/time.rb
+++ b/lib/rubygems/optparse/lib/optparse/time.rb
diff --git a/lib/rubygems/optparse/lib/optparse/uri.rb b/lib/rubygems/optparse/lib/optparse/uri.rb
new file mode 100644
index 0000000000..664d7f2af4
--- /dev/null
+++ b/lib/rubygems/optparse/lib/optparse/uri.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: false
+# -*- ruby -*-
+
+require_relative '../optparse'
+require 'uri'
+
+Gem::OptionParser.accept(URI) {|s,| URI.parse(s) if s}
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/version.rb b/lib/rubygems/optparse/lib/optparse/version.rb
index 5d79e9db44..5d79e9db44 100644
--- a/lib/rubygems/vendor/optparse/lib/optparse/version.rb
+++ b/lib/rubygems/optparse/lib/optparse/version.rb
diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb
index c855423ed7..f28d521bdf 100644
--- a/lib/rubygems/package.rb
+++ b/lib/rubygems/package.rb
@@ -1,12 +1,11 @@
# frozen_string_literal: true
-# rubocop:disable Style/AsciiComments
-
+#--
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
+#++
-# rubocop:enable Style/AsciiComments
-
+require_relative "../rubygems"
require_relative "security"
require_relative "user_interaction"
@@ -58,9 +57,9 @@ class Gem::Package
def initialize(message, source = nil)
if source
- @path = source.is_a?(String) ? source : source.path
+ @path = source.path
- message += " in #{path}" if path
+ message = message + " in #{path}" if path
end
super message
@@ -69,13 +68,15 @@ class Gem::Package
class PathError < Error
def initialize(destination, destination_dir)
- super format("installing into parent path %s of %s is not allowed", destination, destination_dir)
+ super "installing into parent path %s of %s is not allowed" %
+ [destination, destination_dir]
end
end
class SymlinkError < Error
def initialize(name, destination, destination_dir)
- super format("installing symlink '%s' pointing to parent path %s of %s is not allowed", name, destination, destination_dir)
+ super "installing symlink '%s' pointing to parent path %s of %s is not allowed" %
+ [name, destination, destination_dir]
end
end
@@ -154,7 +155,7 @@ class Gem::Package
Gem::Package::FileSource.new gem
end
- return super unless self == Gem::Package
+ return super unless Gem::Package == self
return super unless gem.present?
return super unless gem.start
@@ -186,7 +187,7 @@ class Gem::Package
end
end
- [spec, metadata]
+ return spec, metadata
end
##
@@ -229,7 +230,7 @@ class Gem::Package
end
end
- tar.add_file_signed "checksums.yaml.gz", 0o444, @signer do |io|
+ tar.add_file_signed "checksums.yaml.gz", 0444, @signer do |io|
gzip_to io do |gz_io|
Psych.dump checksums_by_algorithm, gz_io
end
@@ -241,7 +242,7 @@ class Gem::Package
# and adds this file to the +tar+.
def add_contents(tar) # :nodoc:
- digests = tar.add_file_signed "data.tar.gz", 0o444, @signer do |io|
+ digests = tar.add_file_signed "data.tar.gz", 0444, @signer do |io|
gzip_to io do |gz_io|
Gem::Package::TarWriter.new gz_io do |data_tar|
add_files data_tar
@@ -267,7 +268,7 @@ class Gem::Package
tar.add_file_simple file, stat.mode, stat.size do |dst_io|
File.open file, "rb" do |src_io|
- copy_stream(src_io, dst_io)
+ dst_io.write src_io.read 16384 until src_io.eof?
end
end
end
@@ -277,7 +278,7 @@ class Gem::Package
# Adds the package's Gem::Specification to the +tar+ file
def add_metadata(tar) # :nodoc:
- digests = tar.add_file_signed "metadata.gz", 0o444, @signer do |io|
+ digests = tar.add_file_signed "metadata.gz", 0444, @signer do |io|
gzip_to io do |gz_io|
gz_io.write @spec.to_yaml
end
@@ -294,6 +295,7 @@ class Gem::Package
Gem.load_yaml
+ @spec.mark_version
@spec.validate true, strict_validation unless skip_validation
setup_signer(
@@ -345,8 +347,6 @@ EOM
return @contents
end
end
- rescue Zlib::GzipFile::Error, EOFError, Gem::Package::TarInvalidError => e
- raise Gem::Package::FormatError.new e.message, @gem
end
##
@@ -355,21 +355,18 @@ EOM
def digest(entry) # :nodoc:
algorithms = if @checksums
- @checksums.to_h {|algorithm, _| [algorithm, Gem::Security.create_digest(algorithm)] }
- elsif Gem::Security::DIGEST_NAME
- { Gem::Security::DIGEST_NAME => Gem::Security.create_digest(Gem::Security::DIGEST_NAME) }
+ @checksums.keys
+ else
+ [Gem::Security::DIGEST_NAME].compact
end
- return @digests if algorithms.nil? || algorithms.empty?
+ algorithms.each do |algorithm|
+ digester = Gem::Security.create_digest(algorithm)
- buf = String.new(capacity: 16_384, encoding: Encoding::BINARY)
- until entry.eof?
- entry.readpartial(16_384, buf)
- algorithms.each_value {|digester| digester << buf }
- end
- entry.rewind
+ digester << entry.read(16384) until entry.eof?
+
+ entry.rewind
- algorithms.each do |algorithm, digester|
@digests[algorithm][entry.full_name] = digester
end
@@ -385,7 +382,7 @@ EOM
def extract_files(destination_dir, pattern = "*")
verify unless @spec
- FileUtils.mkdir_p destination_dir, mode: dir_mode && 0o755
+ FileUtils.mkdir_p destination_dir, :mode => dir_mode && 0755
@gem.with_read_io do |io|
reader = Gem::Package::TarReader.new io
@@ -395,11 +392,9 @@ EOM
extract_tar_gz entry, destination_dir, pattern
- break # ignore further entries
+ return # ignore further entries
end
end
- rescue Zlib::GzipFile::Error, EOFError, Gem::Package::TarInvalidError => e
- raise Gem::Package::FormatError.new e.message, @gem
end
##
@@ -414,8 +409,6 @@ EOM
# extracted.
def extract_tar_gz(io, destination_dir, pattern = "*") # :nodoc:
- destination_dir = File.realpath(destination_dir)
-
directories = []
symlinks = []
@@ -438,6 +431,8 @@ EOM
FileUtils.rm_rf destination
+ mkdir_options = {}
+ mkdir_options[:mode] = dir_mode ? 0755 : (entry.header.mode if entry.directory?)
mkdir =
if entry.directory?
destination
@@ -446,13 +441,13 @@ EOM
end
unless directories.include?(mkdir)
- FileUtils.mkdir_p mkdir, mode: dir_mode ? 0o755 : (entry.header.mode if entry.directory?)
+ FileUtils.mkdir_p mkdir, **mkdir_options
directories << mkdir
end
if entry.file?
- File.open(destination, "wb") {|out| copy_stream(entry, out) }
- FileUtils.chmod file_mode(entry.header.mode) & ~File.umask, destination
+ File.open(destination, "wb") {|out| out.write entry.read }
+ FileUtils.chmod file_mode(entry.header.mode), destination
end
verbose destination
@@ -473,7 +468,7 @@ EOM
end
def file_mode(mode) # :nodoc:
- ((mode & 0o111).zero? ? data_mode : prog_mode) ||
+ ((mode & 0111).zero? ? data_mode : prog_mode) ||
# If we're not using one of the default modes, then we're going to fall
# back to the mode from the tarball. In this case we need to mask it down
# to fit into 2^16 bits (the maximum value for a mode in CRuby since it
@@ -511,6 +506,7 @@ EOM
raise Gem::Package::PathError.new(destination, destination_dir) unless
normalize_path(destination).start_with? normalize_path(destination_dir + "/")
+ destination.tap(&Gem::UNTAINT)
destination
end
@@ -526,13 +522,12 @@ EOM
# Loads a Gem::Specification from the TarEntry +entry+
def load_spec(entry) # :nodoc:
- limit = 10 * 1024 * 1024
case entry.full_name
when "metadata" then
- @spec = Gem::Specification.from_yaml limit_read(entry, "metadata", limit)
+ @spec = Gem::Specification.from_yaml entry.read
when "metadata.gz" then
Zlib::GzipReader.wrap(entry, external_encoding: Encoding::UTF_8) do |gzio|
- @spec = Gem::Specification.from_yaml limit_read(gzio, "metadata.gz", limit)
+ @spec = Gem::Specification.from_yaml gzio.read
end
end
end
@@ -556,7 +551,7 @@ EOM
@checksums = gem.seek "checksums.yaml.gz" do |entry|
Zlib::GzipReader.wrap entry do |gz_io|
- Gem::SafeYAML.safe_load limit_read(gz_io, "checksums.yaml.gz", 10 * 1024 * 1024)
+ Gem::SafeYAML.safe_load gz_io.read
end
end
end
@@ -577,10 +572,10 @@ EOM
)
@spec.signing_key = nil
- @spec.cert_chain = @signer.cert_chain.map(&:to_s)
+ @spec.cert_chain = @signer.cert_chain.map {|cert| cert.to_s }
else
@signer = Gem::Security::Signer.new nil, nil, passphrase
- @spec.cert_chain = @signer.cert_chain.map(&:to_pem) if
+ @spec.cert_chain = @signer.cert_chain.map {|cert| cert.to_pem } if
@signer.cert_chain
end
end
@@ -631,7 +626,7 @@ EOM
raise
rescue Errno::ENOENT => e
raise Gem::Package::FormatError.new e.message
- rescue Zlib::GzipFile::Error, EOFError, Gem::Package::TarInvalidError => e
+ rescue Gem::Package::TarInvalidError => e
raise Gem::Package::FormatError.new e.message, @gem
end
@@ -663,7 +658,7 @@ EOM
case file_name
when /\.sig$/ then
- @signatures[$`] = limit_read(entry, file_name, 1024 * 1024) if @security_policy
+ @signatures[$`] = entry.read if @security_policy
return
else
digest entry
@@ -675,7 +670,7 @@ EOM
when "data.tar.gz" then
verify_gz entry
end
- rescue StandardError
+ rescue
warn "Exception while verifying #{@gem.path}"
raise
end
@@ -694,11 +689,11 @@ EOM
unless @files.include? "data.tar.gz"
raise Gem::Package::FormatError.new \
- "package content (data.tar.gz) is missing", @gem
+ "package content (data.tar.gz) is missing", @gem
end
- if (duplicates = @files.group_by {|f| f }.select {|_k,v| v.size > 1 }.map(&:first)) && duplicates.any?
- raise Gem::Security::Exception, "duplicate files in the package: (#{duplicates.map(&:inspect).join(", ")})"
+ if (duplicates = @files.group_by {|f| f }.select {|k,v| v.size > 1 }.map(&:first)) && duplicates.any?
+ raise Gem::Security::Exception, "duplicate files in the package: (#{duplicates.map(&:inspect).join(', ')})"
end
end
@@ -707,28 +702,11 @@ EOM
def verify_gz(entry) # :nodoc:
Zlib::GzipReader.wrap entry do |gzio|
- # TODO: read into a buffer once zlib supports it
- gzio.read 16_384 until gzio.eof? # gzip checksum verification
+ gzio.read 16384 until gzio.eof? # gzip checksum verification
end
rescue Zlib::GzipFile::Error => e
raise Gem::Package::FormatError.new(e.message, entry.full_name)
end
-
- if RUBY_ENGINE == "truffleruby"
- def copy_stream(src, dst) # :nodoc:
- dst.write src.read
- end
- else
- def copy_stream(src, dst) # :nodoc:
- IO.copy_stream(src, dst)
- end
- end
-
- def limit_read(io, name, limit)
- bytes = io.read(limit + 1)
- raise Gem::Package::FormatError, "#{name} is too big (over #{limit} bytes)" if bytes.size > limit
- bytes
- end
end
require_relative "package/digest_io"
diff --git a/lib/rubygems/package/digest_io.rb b/lib/rubygems/package/digest_io.rb
index f04ab97462..1572cb9f2c 100644
--- a/lib/rubygems/package/digest_io.rb
+++ b/lib/rubygems/package/digest_io.rb
@@ -36,7 +36,7 @@ class Gem::Package::DigestIO
yield digest_io
- digests
+ return digests
end
##
diff --git a/lib/rubygems/package/old.rb b/lib/rubygems/package/old.rb
index 1a13ac3e29..bf0ed61b0a 100644
--- a/lib/rubygems/package/old.rb
+++ b/lib/rubygems/package/old.rb
@@ -70,7 +70,7 @@ class Gem::Package::Old < Gem::Package
file_data << line
end
- file_data = file_data.strip.unpack1("m")
+ file_data = file_data.strip.unpack("m")[0]
file_data = Zlib::Inflate.inflate file_data
raise Gem::Package::FormatError, "#{full_name} in #{@gem} is corrupt" if
@@ -78,7 +78,7 @@ class Gem::Package::Old < Gem::Package
FileUtils.rm_rf destination
- FileUtils.mkdir_p File.dirname(destination), mode: dir_mode && 0o755
+ FileUtils.mkdir_p File.dirname(destination), :mode => dir_mode && 0755
File.open destination, "wb", file_mode(entry["mode"]) do |out|
out.write file_data
diff --git a/lib/rubygems/package/tar_header.rb b/lib/rubygems/package/tar_header.rb
index dd5e835a1e..99bd755f90 100644
--- a/lib/rubygems/package/tar_header.rb
+++ b/lib/rubygems/package/tar_header.rb
@@ -1,11 +1,9 @@
# frozen_string_literal: true
-# rubocop:disable Style/AsciiComments
-
+#--
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
-
-# rubocop:enable Style/AsciiComments
+#++
##
#--
@@ -95,40 +93,39 @@ class Gem::Package::TarHeader
attr_reader(*FIELDS)
- EMPTY_HEADER = ("\0" * 512).b.freeze # :nodoc:
+ EMPTY_HEADER = ("\0" * 512).freeze # :nodoc:
##
# Creates a tar header from IO +stream+
def self.from(stream)
header = stream.read 512
- return EMPTY if header == EMPTY_HEADER
+ empty = (EMPTY_HEADER == header)
fields = header.unpack UNPACK_FORMAT
- new name: fields.shift,
- mode: strict_oct(fields.shift),
- uid: oct_or_256based(fields.shift),
- gid: oct_or_256based(fields.shift),
- size: strict_oct(fields.shift),
- mtime: strict_oct(fields.shift),
- checksum: strict_oct(fields.shift),
- typeflag: fields.shift,
- linkname: fields.shift,
- magic: fields.shift,
- version: strict_oct(fields.shift),
- uname: fields.shift,
- gname: fields.shift,
- devmajor: strict_oct(fields.shift),
- devminor: strict_oct(fields.shift),
- prefix: fields.shift,
-
- empty: false
+ new :name => fields.shift,
+ :mode => strict_oct(fields.shift),
+ :uid => oct_or_256based(fields.shift),
+ :gid => oct_or_256based(fields.shift),
+ :size => strict_oct(fields.shift),
+ :mtime => strict_oct(fields.shift),
+ :checksum => strict_oct(fields.shift),
+ :typeflag => fields.shift,
+ :linkname => fields.shift,
+ :magic => fields.shift,
+ :version => strict_oct(fields.shift),
+ :uname => fields.shift,
+ :gname => fields.shift,
+ :devmajor => strict_oct(fields.shift),
+ :devminor => strict_oct(fields.shift),
+ :prefix => fields.shift,
+
+ :empty => empty
end
def self.strict_oct(str)
- str.strip!
- return str.oct if /\A[0-7]*\z/.match?(str)
+ return str.strip.oct if str.strip =~ /\A[0-7]*\z/
raise ArgumentError, "#{str.inspect} is not an octal string"
end
@@ -138,8 +135,7 @@ class Gem::Package::TarHeader
# \ff flags a negative 256-based number
# In case we have a match, parse it as a signed binary value
# in big-endian order, except that the high-order bit is ignored.
-
- return str.unpack1("@4N") if /\A[\x80\xff]/n.match?(str)
+ return str.unpack("N2").last if str =~ /\A[\x80\xff]/n
strict_oct(str)
end
@@ -151,43 +147,25 @@ class Gem::Package::TarHeader
raise ArgumentError, ":name, :size, :prefix and :mode required"
end
- @checksum = vals[:checksum] || ""
- @devmajor = vals[:devmajor] || 0
- @devminor = vals[:devminor] || 0
- @gid = vals[:gid] || 0
- @gname = vals[:gname] || "wheel"
- @linkname = vals[:linkname]
- @magic = vals[:magic] || "ustar"
- @mode = vals[:mode]
- @mtime = vals[:mtime] || 0
- @name = vals[:name]
- @prefix = vals[:prefix]
- @size = vals[:size]
- @typeflag = vals[:typeflag]
- @typeflag = "0" if @typeflag.nil? || @typeflag.empty?
- @uid = vals[:uid] || 0
- @uname = vals[:uname] || "wheel"
- @version = vals[:version] || "00"
+ vals[:uid] ||= 0
+ vals[:gid] ||= 0
+ vals[:mtime] ||= 0
+ vals[:checksum] ||= ""
+ vals[:typeflag] = "0" if vals[:typeflag].nil? || vals[:typeflag].empty?
+ vals[:magic] ||= "ustar"
+ vals[:version] ||= "00"
+ vals[:uname] ||= "wheel"
+ vals[:gname] ||= "wheel"
+ vals[:devmajor] ||= 0
+ vals[:devminor] ||= 0
+
+ FIELDS.each do |name|
+ instance_variable_set "@#{name}", vals[name]
+ end
@empty = vals[:empty]
end
- EMPTY = new({ # :nodoc:
- checksum: 0,
- gname: "",
- linkname: "",
- magic: "",
- mode: 0,
- name: "",
- prefix: "",
- size: 0,
- uname: "",
- version: 0,
-
- empty: true,
- }).freeze
- private_constant :EMPTY
-
##
# Is the tar entry empty?
@@ -257,10 +235,10 @@ class Gem::Package::TarHeader
header = header.pack PACK_FORMAT
- header.ljust 512, "\0"
+ header << ("\0" * ((512 - header.size) % 512))
end
def oct(num, len)
- format("%0#{len}o", num)
+ "%0#{len}o" % num
end
end
diff --git a/lib/rubygems/package/tar_reader.rb b/lib/rubygems/package/tar_reader.rb
index 25f9b2f945..a8dd39c572 100644
--- a/lib/rubygems/package/tar_reader.rb
+++ b/lib/rubygems/package/tar_reader.rb
@@ -1,11 +1,9 @@
# frozen_string_literal: true
-# rubocop:disable Style/AsciiComments
-
+#--
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
-
-# rubocop:enable Style/AsciiComments
+#++
##
# TarReader reads tar files and allows iteration over their items
@@ -14,6 +12,11 @@ class Gem::Package::TarReader
include Enumerable
##
+ # Raised if the tar IO is not seekable
+
+ class UnexpectedEOF < StandardError; end
+
+ ##
# Creates a new TarReader on +io+ and yields it to the block, if given.
def self.new(io)
@@ -52,14 +55,7 @@ class Gem::Package::TarReader
return enum_for __method__ unless block_given?
until @io.eof? do
- begin
- header = Gem::Package::TarHeader.from @io
- rescue ArgumentError => e
- # Specialize only exceptions from Gem::Package::TarHeader.strict_oct
- raise e unless e.message.match?(/ is not an octal string$/)
- raise Gem::Package::TarInvalidError, e.message
- end
-
+ header = Gem::Package::TarHeader.from @io
return if header.empty?
entry = Gem::Package::TarReader::Entry.new header, @io
yield entry
@@ -67,7 +63,7 @@ class Gem::Package::TarReader
end
end
- alias_method :each_entry, :each
+ alias each_entry each
##
# NOTE: Do not call #rewind during #each
@@ -92,7 +88,7 @@ class Gem::Package::TarReader
return unless found
- yield found
+ return yield found
ensure
rewind
end
diff --git a/lib/rubygems/package/tar_reader/entry.rb b/lib/rubygems/package/tar_reader/entry.rb
index 5e9d9af5c6..e770079f41 100644
--- a/lib/rubygems/package/tar_reader/entry.rb
+++ b/lib/rubygems/package/tar_reader/entry.rb
@@ -1,11 +1,9 @@
# frozen_string_literal: true
-# rubocop:disable Style/AsciiComments
-
+#++
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
-
-# rubocop:enable Style/AsciiComments
+#--
##
# Class for reading entries out of a tar file
@@ -102,7 +100,9 @@ class Gem::Package::TarReader::Entry
# Read one byte from the tar entry
def getc
- return nil if eof?
+ check_closed
+
+ return nil if @read >= @header.size
ret = @io.getc
@read += 1 if ret
@@ -145,37 +145,40 @@ class Gem::Package::TarReader::Entry
def pos=(new_pos)
seek(new_pos, IO::SEEK_SET)
+ new_pos
end
def size
@header.size
end
- alias_method :length, :size
+ alias length size
##
- # Reads +maxlen+ bytes from the tar file entry, or the rest of the entry if nil
+ # Reads +len+ bytes from the tar file entry, or the rest of the entry if
+ # nil
- def read(maxlen = nil)
- if eof?
- return maxlen.to_i.zero? ? "" : nil
- end
+ def read(len = nil)
+ check_closed
+
+ len ||= @header.size - @read
- max_read = [maxlen, @header.size - @read].compact.min
+ return nil if len > 0 && @read >= @header.size
+
+ max_read = [len, @header.size - @read].min
ret = @io.read max_read
- if ret.nil?
- return maxlen ? nil : "" # IO.read returns nil on EOF with len argument
- end
@read += ret.size
ret
end
- def readpartial(maxlen, outbuf = "".b)
- if eof? && maxlen > 0
- raise EOFError, "end of file reached"
- end
+ def readpartial(maxlen = nil, outbuf = "".b)
+ check_closed
+
+ maxlen ||= @header.size - @read
+
+ raise EOFError if maxlen > 0 && @read >= @header.size
max_read = [maxlen, @header.size - @read].min
@@ -209,8 +212,6 @@ class Gem::Package::TarReader::Entry
pending = new_pos - @io.pos
- return 0 if pending == 0
-
if @io.respond_to?(:seek)
begin
# avoid reading if the @io supports seeking
@@ -228,8 +229,8 @@ class Gem::Package::TarReader::Entry
end
while pending > 0 do
- size_read = @io.read([pending, 4096].min)&.size
- raise(EOFError, "end of file reached") if size_read.nil?
+ size_read = @io.read([pending, 4096].min).size
+ raise UnexpectedEOF if @io.eof?
pending -= size_read
end
diff --git a/lib/rubygems/package/tar_writer.rb b/lib/rubygems/package/tar_writer.rb
index b24bdb63e7..32a13e9162 100644
--- a/lib/rubygems/package/tar_writer.rb
+++ b/lib/rubygems/package/tar_writer.rb
@@ -1,11 +1,9 @@
# frozen_string_literal: true
-# rubocop:disable Style/AsciiComments
-
+#--
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
# See LICENSE.txt for additional licensing information.
-
-# rubocop:enable Style/AsciiComments
+#++
##
# Allows writing of tar files
@@ -116,9 +114,9 @@ class Gem::Package::TarWriter
final_pos = @io.pos
@io.pos = init_pos
- header = Gem::Package::TarHeader.new name: name, mode: mode,
- size: size, prefix: prefix,
- mtime: Gem.source_date_epoch
+ header = Gem::Package::TarHeader.new :name => name, :mode => mode,
+ :size => size, :prefix => prefix,
+ :mtime => Gem.source_date_epoch
@io.write header
@io.pos = final_pos
@@ -192,7 +190,7 @@ class Gem::Package::TarWriter
if signer.key
signature = signer.sign signature_digest.digest
- add_file_simple "#{name}.sig", 0o444, signature.length do |io|
+ add_file_simple "#{name}.sig", 0444, signature.length do |io|
io.write signature
end
end
@@ -209,9 +207,9 @@ class Gem::Package::TarWriter
name, prefix = split_name name
- header = Gem::Package::TarHeader.new(name: name, mode: mode,
- size: size, prefix: prefix,
- mtime: Gem.source_date_epoch).to_s
+ header = Gem::Package::TarHeader.new(:name => name, :mode => mode,
+ :size => size, :prefix => prefix,
+ :mtime => Gem.source_date_epoch).to_s
@io.write header
os = BoundedStream.new @io, size
@@ -235,11 +233,11 @@ class Gem::Package::TarWriter
name, prefix = split_name name
- header = Gem::Package::TarHeader.new(name: name, mode: mode,
- size: 0, typeflag: "2",
- linkname: target,
- prefix: prefix,
- mtime: Gem.source_date_epoch).to_s
+ header = Gem::Package::TarHeader.new(:name => name, :mode => mode,
+ :size => 0, :typeflag => "2",
+ :linkname => target,
+ :prefix => prefix,
+ :mtime => Gem.source_date_epoch).to_s
@io.write header
@@ -289,10 +287,10 @@ class Gem::Package::TarWriter
name, prefix = split_name(name)
- header = Gem::Package::TarHeader.new name: name, mode: mode,
- typeflag: "5", size: 0,
- prefix: prefix,
- mtime: Gem.source_date_epoch
+ header = Gem::Package::TarHeader.new :name => name, :mode => mode,
+ :typeflag => "5", :size => 0,
+ :prefix => prefix,
+ :mtime => Gem.source_date_epoch
@io.write header
@@ -326,6 +324,6 @@ class Gem::Package::TarWriter
end
end
- [name, prefix]
+ return name, prefix
end
end
diff --git a/lib/rubygems/package_task.rb b/lib/rubygems/package_task.rb
index d26411684d..a67d8cb916 100644
--- a/lib/rubygems/package_task.rb
+++ b/lib/rubygems/package_task.rb
@@ -97,13 +97,13 @@ class Gem::PackageTask < Rake::PackageTask
gem_path = File.join package_dir, gem_file
gem_dir = File.join package_dir, gem_spec.full_name
- task package: [:gem]
+ task :package => [:gem]
directory package_dir
directory gem_dir
desc "Build the gem file #{gem_file}"
- task gem: [gem_path]
+ task :gem => [gem_path]
trace = Rake.application.options.trace
Gem.configuration.verbose = trace
diff --git a/lib/rubygems/path_support.rb b/lib/rubygems/path_support.rb
index 13091e29ba..d9df543ad9 100644
--- a/lib/rubygems/path_support.rb
+++ b/lib/rubygems/path_support.rb
@@ -24,22 +24,23 @@ class Gem::PathSupport
# hashtable, or defaults to ENV, the system environment.
#
def initialize(env)
- @home = normalize_home_dir(env["GEM_HOME"] || Gem.default_dir)
+ @home = env["GEM_HOME"] || Gem.default_dir
+
+ if File::ALT_SEPARATOR
+ @home = @home.gsub(File::ALT_SEPARATOR, File::SEPARATOR)
+ end
+
+ @home = expand(@home)
+
@path = split_gem_path env["GEM_PATH"], @home
@spec_cache_dir = env["GEM_SPEC_CACHE"] || Gem.default_spec_cache_dir
+
+ @spec_cache_dir = @spec_cache_dir.dup.tap(&Gem::UNTAINT)
end
private
- def normalize_home_dir(home)
- if File::ALT_SEPARATOR
- home = home.gsub(File::ALT_SEPARATOR, File::SEPARATOR)
- end
-
- expand(home)
- end
-
##
# Split the Gem search path (as reported by Gem.path).
@@ -52,7 +53,7 @@ class Gem::PathSupport
gem_path = gpaths.split(Gem.path_separator)
# Handle the path_separator being set to a regexp, which will cause
# end_with? to error
- if /#{Gem.path_separator}\z/.match?(gpaths)
+ if gpaths =~ /#{Gem.path_separator}\z/
gem_path += default_path
end
diff --git a/lib/rubygems/platform.rb b/lib/rubygems/platform.rb
index 450c214167..b721629b78 100644
--- a/lib/rubygems/platform.rb
+++ b/lib/rubygems/platform.rb
@@ -12,24 +12,16 @@ class Gem::Platform
attr_accessor :cpu, :os, :version
- def self.local(refresh: false)
- return @local if @local && !refresh
- @local = begin
- arch = Gem.target_rbconfig["arch"]
- arch = "#{arch}_60" if /mswin(?:32|64)$/.match?(arch)
- new(arch)
- end
+ def self.local
+ arch = RbConfig::CONFIG["arch"]
+ arch = "#{arch}_60" if arch =~ /mswin(?:32|64)$/
+ @local ||= new(arch)
end
def self.match(platform)
match_platforms?(platform, Gem.platforms)
end
- class << self
- extend Gem::Deprecate
- rubygems_deprecate :match, "Gem::Platform.match_spec? or match_gem?"
- end
-
def self.match_platforms?(platform, platforms)
platform = Gem::Platform.new(platform) unless platform.is_a?(Gem::Platform)
platforms.any? do |local_platform|
@@ -44,20 +36,10 @@ class Gem::Platform
match_gem?(spec.platform, spec.name)
end
- if RUBY_ENGINE == "truffleruby"
- def self.match_gem?(platform, gem_name)
- raise "Not a string: #{gem_name.inspect}" unless String === gem_name
-
- if REUSE_AS_BINARY_ON_TRUFFLERUBY.include?(gem_name)
- match_platforms?(platform, [Gem::Platform::RUBY, Gem::Platform.local])
- else
- match_platforms?(platform, Gem.platforms)
- end
- end
- else
- def self.match_gem?(platform, gem_name)
- match_platforms?(platform, Gem.platforms)
- end
+ def self.match_gem?(platform, gem_name)
+ # Note: this method might be redefined by Ruby implementations to
+ # customize behavior per RUBY_ENGINE, gem_name or other criteria.
+ match_platforms?(platform, Gem.platforms)
end
def self.sort_priority(platform)
@@ -90,7 +72,7 @@ class Gem::Platform
when String then
arch = arch.split "-"
- if arch.length > 2 && !arch.last.match?(/\d+(\.\d+)?$/) # reassemble x86-linux-{libc}
+ if arch.length > 2 && arch.last !~ /\d+(\.\d+)?$/ # reassemble x86-linux-{libc}
extra = arch.pop
arch.last << "-#{extra}"
end
@@ -98,47 +80,42 @@ class Gem::Platform
cpu = arch.shift
@cpu = case cpu
- when /i\d86/ then "x86"
- else cpu
+ when /i\d86/ then "x86"
+ else cpu
end
- if arch.length == 2 && arch.last.match?(/^\d+(\.\d+)?$/) # for command-line
+ if arch.length == 2 && arch.last =~ /^\d+(\.\d+)?$/ # for command-line
@os, @version = arch
return
end
os, = arch
- if os.nil?
- @cpu = nil
- os = cpu
- end # legacy jruby
+ @cpu, os = nil, cpu if os.nil? # legacy jruby
@os, @version = case os
- when /aix(\d+)?/ then ["aix", $1]
- when /cygwin/ then ["cygwin", nil]
- when /darwin(\d+)?/ then ["darwin", $1]
- when /^macruby$/ then ["macruby", nil]
- when /freebsd(\d+)?/ then ["freebsd", $1]
- when /^java$/, /^jruby$/ then ["java", nil]
- when /^java([\d.]*)/ then ["java", $1]
- when /^dalvik(\d+)?$/ then ["dalvik", $1]
- when /^dotnet$/ then ["dotnet", nil]
- when /^dotnet([\d.]*)/ then ["dotnet", $1]
- when /linux-?(\w+)?/ then ["linux", $1]
- when /mingw32/ then ["mingw32", nil]
- when /mingw-?(\w+)?/ then ["mingw", $1]
- when /(mswin\d+)(\_(\d+))?/ then
- os = $1
- version = $3
- @cpu = "x86" if @cpu.nil? && os =~ /32$/
- [os, version]
- when /netbsdelf/ then ["netbsdelf", nil]
- when /openbsd(\d+\.\d+)?/ then ["openbsd", $1]
- when /solaris(\d+\.\d+)?/ then ["solaris", $1]
- when /wasi/ then ["wasi", nil]
- # test
- when /^(\w+_platform)(\d+)?/ then [$1, $2]
- else ["unknown", nil]
+ when /aix(\d+)?/ then [ "aix", $1 ]
+ when /cygwin/ then [ "cygwin", nil ]
+ when /darwin(\d+)?/ then [ "darwin", $1 ]
+ when /^macruby$/ then [ "macruby", nil ]
+ when /freebsd(\d+)?/ then [ "freebsd", $1 ]
+ when /^java$/, /^jruby$/ then [ "java", nil ]
+ when /^java([\d.]*)/ then [ "java", $1 ]
+ when /^dalvik(\d+)?$/ then [ "dalvik", $1 ]
+ when /^dotnet$/ then [ "dotnet", nil ]
+ when /^dotnet([\d.]*)/ then [ "dotnet", $1 ]
+ when /linux-?(\w+)?/ then [ "linux", $1 ]
+ when /mingw32/ then [ "mingw32", nil ]
+ when /mingw-?(\w+)?/ then [ "mingw", $1 ]
+ when /(mswin\d+)(\_(\d+))?/ then
+ os, version = $1, $3
+ @cpu = "x86" if @cpu.nil? && os =~ /32$/
+ [os, version]
+ when /netbsdelf/ then [ "netbsdelf", nil ]
+ when /openbsd(\d+\.\d+)?/ then [ "openbsd", $1 ]
+ when /solaris(\d+\.\d+)?/ then [ "solaris", $1 ]
+ # test
+ when /^(\w+_platform)(\d+)?/ then [ $1, $2 ]
+ else [ "unknown", nil ]
end
when Gem::Platform then
@cpu = arch.cpu
@@ -165,7 +142,7 @@ class Gem::Platform
self.class === other && to_a == other.to_a
end
- alias_method :eql?, :==
+ alias :eql? :==
def hash # :nodoc:
to_a.hash
@@ -177,7 +154,7 @@ class Gem::Platform
# they have the same version, or either one has no version
#
# Additionally, the platform will match if the local CPU is 'arm' and the
- # other CPU starts with "armv" (for generic 32-bit ARM family support).
+ # other CPU starts with "arm" (for generic ARM family support).
#
# Of note, this method is not commutative. Indeed the OS 'linux' has a
# special case: the version is the libc name, yet while "no version" stands
@@ -198,7 +175,7 @@ class Gem::Platform
# cpu
([nil,"universal"].include?(@cpu) || [nil, "universal"].include?(other.cpu) || @cpu == other.cpu ||
- (@cpu == "arm" && other.cpu.start_with?("armv"))) &&
+ (@cpu == "arm" && other.cpu.start_with?("arm"))) &&
# os
@os == other.os &&
@@ -233,18 +210,18 @@ class Gem::Platform
when String then
# This data is from http://gems.rubyforge.org/gems/yaml on 19 Aug 2007
other = case other
- when /^i686-darwin(\d)/ then ["x86", "darwin", $1]
- when /^i\d86-linux/ then ["x86", "linux", nil]
- when "java", "jruby" then [nil, "java", nil]
- when /^dalvik(\d+)?$/ then [nil, "dalvik", $1]
- when /dotnet(\-(\d+\.\d+))?/ then ["universal","dotnet", $2]
- when /mswin32(\_(\d+))?/ then ["x86", "mswin32", $2]
- when /mswin64(\_(\d+))?/ then ["x64", "mswin64", $2]
- when "powerpc-darwin" then ["powerpc", "darwin", nil]
- when /powerpc-darwin(\d)/ then ["powerpc", "darwin", $1]
- when /sparc-solaris2.8/ then ["sparc", "solaris", "2.8"]
- when /universal-darwin(\d)/ then ["universal", "darwin", $1]
- else other
+ when /^i686-darwin(\d)/ then ["x86", "darwin", $1 ]
+ when /^i\d86-linux/ then ["x86", "linux", nil ]
+ when "java", "jruby" then [nil, "java", nil ]
+ when /^dalvik(\d+)?$/ then [nil, "dalvik", $1 ]
+ when /dotnet(\-(\d+\.\d+))?/ then ["universal","dotnet", $2 ]
+ when /mswin32(\_(\d+))?/ then ["x86", "mswin32", $2 ]
+ when /mswin64(\_(\d+))?/ then ["x64", "mswin64", $2 ]
+ when "powerpc-darwin" then ["powerpc", "darwin", nil ]
+ when /powerpc-darwin(\d)/ then ["powerpc", "darwin", $1 ]
+ when /sparc-solaris2.8/ then ["sparc", "solaris", "2.8" ]
+ when /universal-darwin(\d)/ then ["universal", "darwin", $1 ]
+ else other
end
other = Gem::Platform.new other
diff --git a/lib/rubygems/psych_tree.rb b/lib/rubygems/psych_tree.rb
index 24857adb9d..2d478c94d9 100644
--- a/lib/rubygems/psych_tree.rb
+++ b/lib/rubygems/psych_tree.rb
@@ -14,10 +14,6 @@ module Gem
@emitter.scalar str, nil, nil, false, true, quote
end
- def visit_Hash(o)
- super(o.compact)
- end
-
# Noop this out so there are no anchors
def register(target, obj)
end
diff --git a/lib/rubygems/query_utils.rb b/lib/rubygems/query_utils.rb
index ea05969422..c72955f83b 100644
--- a/lib/rubygems/query_utils.rb
+++ b/lib/rubygems/query_utils.rb
@@ -6,6 +6,7 @@ require_relative "version_option"
require_relative "text"
module Gem::QueryUtils
+
include Gem::Text
include Gem::LocalRemoteOptions
include Gem::VersionOption
@@ -16,7 +17,7 @@ module Gem::QueryUtils
options[:installed] = value
end
- add_option("-I", "Equivalent to --no-installed") do |_value, options|
+ add_option("-I", "Equivalent to --no-installed") do |value, options|
options[:installed] = false
end
@@ -84,7 +85,7 @@ module Gem::QueryUtils
installed = !installed unless options[:installed]
say(installed)
- exit_code = 1 unless installed
+ exit_code = 1 if !installed
end
exit_code
@@ -118,7 +119,7 @@ module Gem::QueryUtils
end
end
- # Guts of original execute
+ #Guts of original execute
def show_gems(name)
show_local_gems(name) if local?
show_remote_gems(name) if remote?
@@ -132,7 +133,7 @@ module Gem::QueryUtils
version_matches = show_prereleases? || !s.version.prerelease?
name_matches && version_matches
- end.uniq(&:full_name)
+ end
spec_tuples = specs.map do |spec|
[spec.name_tuple, spec]
@@ -196,7 +197,7 @@ module Gem::QueryUtils
end
def output_versions(output, versions)
- versions.each do |_gem_name, matching_tuples|
+ versions.each do |gem_name, matching_tuples|
matching_tuples = matching_tuples.sort_by {|n,_| n.version }.reverse
platforms = Hash.new {|h,version| h[version] = [] }
@@ -242,7 +243,7 @@ module Gem::QueryUtils
list =
if platforms.empty? || options[:details]
- name_tuples.map(&:version).uniq
+ name_tuples.map {|n| n.version }.uniq
else
platforms.sort.reverse.map do |version, pls|
out = version.to_s
@@ -263,7 +264,7 @@ module Gem::QueryUtils
end
end
- entry << " (#{list.join ", "})"
+ entry << " (#{list.join ', '})"
end
def make_entry(entry_tuples, platforms)
@@ -282,7 +283,7 @@ module Gem::QueryUtils
end
def spec_authors(entry, spec)
- authors = "Author#{spec.authors.length > 1 ? "s" : ""}: ".dup
+ authors = "Author#{spec.authors.length > 1 ? 's' : ''}: ".dup
authors << spec.authors.join(", ")
entry << format_text(authors, 68, 4)
end
@@ -296,7 +297,7 @@ module Gem::QueryUtils
def spec_license(entry, spec)
return if spec.license.nil? || spec.license.empty?
- licenses = "License#{spec.licenses.length > 1 ? "s" : ""}: ".dup
+ licenses = "License#{spec.licenses.length > 1 ? 's' : ''}: ".dup
licenses << spec.licenses.join(", ")
entry << "\n" << format_text(licenses, 68, 4)
end
@@ -311,8 +312,8 @@ module Gem::QueryUtils
label = "Installed at"
specs.each do |s|
version = s.version.to_s
- default = ", default" if s.default_gem?
- entry << "\n" << " #{label} (#{version}#{default}): #{s.base_dir}"
+ version << ", default" if s.default_gem?
+ entry << "\n" << " #{label} (#{version}): #{s.base_dir}"
label = " " * label.length
end
end
@@ -327,11 +328,11 @@ module Gem::QueryUtils
if platforms.length == 1
title = platforms.values.length == 1 ? "Platform" : "Platforms"
- entry << " #{title}: #{platforms.values.sort.join(", ")}\n"
+ entry << " #{title}: #{platforms.values.sort.join(', ')}\n"
else
entry << " Platforms:\n"
- sorted_platforms = platforms.sort
+ sorted_platforms = platforms.sort_by {|version,| version }
sorted_platforms.each do |version, pls|
label = " #{version}: "
@@ -346,4 +347,5 @@ module Gem::QueryUtils
summary = truncate_text(spec.summary, "the summary for #{spec.full_name}")
entry << "\n\n" << format_text(summary, 68, 4)
end
+
end
diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb
index 4b5c74e0ea..1c8a441d0c 100644
--- a/lib/rubygems/remote_fetcher.rb
+++ b/lib/rubygems/remote_fetcher.rb
@@ -53,7 +53,7 @@ class Gem::RemoteFetcher
# Cached RemoteFetcher instance.
def self.fetcher
- @fetcher ||= new Gem.configuration[:http_proxy]
+ @fetcher ||= self.new Gem.configuration[:http_proxy]
end
attr_accessor :headers
@@ -74,8 +74,9 @@ class Gem::RemoteFetcher
def initialize(proxy=nil, dns=nil, headers={})
require_relative "core_ext/tcpsocket_init" if Gem.configuration.ipv4_fallback_enabled
- require_relative "vendored_net_http"
- require_relative "vendor/uri/lib/uri"
+ require "net/http"
+ require "stringio"
+ require "uri"
Socket.do_not_reverse_lookup = true
@@ -114,7 +115,7 @@ class Gem::RemoteFetcher
cache_dir =
if Dir.pwd == install_dir # see fetch_command
install_dir
- elsif File.writable?(install_cache_dir) || (File.writable?(install_dir) && !File.exist?(install_cache_dir))
+ elsif File.writable?(install_cache_dir) || (File.writable?(install_dir) && (!File.exist?(install_cache_dir)))
install_cache_dir
else
File.join Gem.user_dir, "cache"
@@ -124,18 +125,14 @@ class Gem::RemoteFetcher
local_gem_path = File.join cache_dir, gem_file_name
require "fileutils"
- begin
- FileUtils.mkdir_p cache_dir
- rescue StandardError
- nil
- end unless File.exist? cache_dir
+ FileUtils.mkdir_p cache_dir rescue nil unless File.exist? cache_dir
source_uri = Gem::Uri.new(source_uri)
scheme = source_uri.scheme
- # Gem::URI.parse gets confused by MS Windows paths with forward slashes.
- scheme = nil if /^[a-z]$/i.match?(scheme)
+ # URI.parse gets confused by MS Windows paths with forward slashes.
+ scheme = nil if scheme =~ /^[a-z]$/i
# REFACTOR: split this up and dispatch on scheme (eg download_http)
# REFACTOR: be sure to clean up fake fetcher when you do this... cleaner
@@ -147,7 +144,7 @@ class Gem::RemoteFetcher
remote_gem_path = source_uri + "gems/#{gem_file_name}"
- cache_update_path remote_gem_path, local_gem_path
+ self.cache_update_path remote_gem_path, local_gem_path
rescue FetchError
raise if spec.original_platform == spec.platform
@@ -157,7 +154,7 @@ class Gem::RemoteFetcher
remote_gem_path = source_uri + "gems/#{alternate_name}"
- cache_update_path remote_gem_path, local_gem_path
+ self.cache_update_path remote_gem_path, local_gem_path
end
end
when "file" then
@@ -173,7 +170,7 @@ class Gem::RemoteFetcher
end
verbose "Using local gem #{local_gem_path}"
- when nil then # TODO: test for local overriding cache
+ when nil then # TODO test for local overriding cache
source_path = if Gem.win_platform? && source_uri.scheme &&
!source_uri.path.include?(":")
"#{source_uri.scheme}:#{source_uri.path}"
@@ -209,17 +206,17 @@ class Gem::RemoteFetcher
# HTTP Fetcher. Dispatched by +fetch_path+. Use it instead.
def fetch_http(uri, last_modified = nil, head = false, depth = 0)
- fetch_type = head ? Gem::Net::HTTP::Head : Gem::Net::HTTP::Get
+ fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get
response = request uri, fetch_type, last_modified do |req|
headers.each {|k,v| req.add_field(k,v) }
end
case response
- when Gem::Net::HTTPOK, Gem::Net::HTTPNotModified then
+ when Net::HTTPOK, Net::HTTPNotModified then
response.uri = uri
head ? response : response.body
- when Gem::Net::HTTPMovedPermanently, Gem::Net::HTTPFound, Gem::Net::HTTPSeeOther,
- Gem::Net::HTTPTemporaryRedirect then
+ when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther,
+ Net::HTTPTemporaryRedirect then
raise FetchError.new("too many redirects", uri) if depth > 10
unless location = response["Location"]
@@ -237,7 +234,7 @@ class Gem::RemoteFetcher
end
end
- alias_method :fetch_https, :fetch_http
+ alias :fetch_https :fetch_http
##
# Downloads +uri+ and returns it as a String.
@@ -260,7 +257,7 @@ class Gem::RemoteFetcher
end
data
- rescue Gem::Timeout::Error, IOError, SocketError, SystemCallError,
+ rescue Timeout::Error, IOError, SocketError, SystemCallError,
*(OpenSSL::SSL::SSLError if Gem::HAVE_OPENSSL) => e
raise FetchError.new("#{e.class}: #{e}", uri)
end
@@ -284,11 +281,7 @@ class Gem::RemoteFetcher
# passes the data.
def cache_update_path(uri, path = nil, update = true)
- mtime = begin
- path && File.stat(path).mtime
- rescue StandardError
- nil
- end
+ mtime = path && File.stat(path).mtime rescue nil
data = fetch_path(uri, mtime)
@@ -304,8 +297,8 @@ class Gem::RemoteFetcher
end
##
- # Performs a Gem::Net::HTTP request of type +request_class+ on +uri+ returning
- # a Gem::Net::HTTP response object. request maintains a table of persistent
+ # Performs a Net::HTTP request of type +request_class+ on +uri+ returning
+ # a Net::HTTP response object. request maintains a table of persistent
# connections to reduce connect overhead.
def request(uri, request_class, last_modified = nil)
@@ -320,11 +313,11 @@ class Gem::RemoteFetcher
end
def https?(uri)
- uri.scheme.casecmp("https").zero?
+ uri.scheme.downcase == "https"
end
def close_all
- @pools.each_value(&:close_all)
+ @pools.each_value {|pool| pool.close_all }
end
private
diff --git a/lib/rubygems/request.rb b/lib/rubygems/request.rb
index 9116785231..8ea39d9358 100644
--- a/lib/rubygems/request.rb
+++ b/lib/rubygems/request.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require_relative "vendored_net_http"
+require "net/http"
require_relative "user_interaction"
class Gem::Request
@@ -18,11 +18,11 @@ class Gem::Request
end
def self.proxy_uri(proxy) # :nodoc:
- require_relative "vendor/uri/lib/uri"
+ require "uri"
case proxy
when :no_proxy then nil
- when Gem::URI::HTTP then proxy
- else Gem::URI.parse(proxy)
+ when URI::HTTP then proxy
+ else URI.parse(proxy)
end
end
@@ -30,19 +30,14 @@ class Gem::Request
@uri = uri
@request_class = request_class
@last_modified = last_modified
- @requests = Hash.new(0).compare_by_identity
+ @requests = Hash.new 0
@user_agent = user_agent
@connection_pool = pool
end
- def proxy_uri
- @connection_pool.proxy_uri
- end
-
- def cert_files
- @connection_pool.cert_files
- end
+ def proxy_uri; @connection_pool.proxy_uri; end
+ def cert_files; @connection_pool.cert_files; end
def self.get_cert_files
pattern = File.expand_path("./ssl_certs/*/*.pem", __dir__)
@@ -165,22 +160,23 @@ class Gem::Request
# environment variables.
def self.get_proxy_from_env(scheme = "http")
- downcase_scheme = scheme.downcase
- upcase_scheme = scheme.upcase
- env_proxy = ENV["#{downcase_scheme}_proxy"] || ENV["#{upcase_scheme}_PROXY"]
+ _scheme = scheme.downcase
+ _SCHEME = scheme.upcase
+ env_proxy = ENV["#{_scheme}_proxy"] || ENV["#{_SCHEME}_PROXY"]
no_env_proxy = env_proxy.nil? || env_proxy.empty?
if no_env_proxy
- return ["https", "http"].include?(downcase_scheme) ? :no_proxy : get_proxy_from_env("http")
+ return (_scheme == "https" || _scheme == "http") ?
+ :no_proxy : get_proxy_from_env("http")
end
require "uri"
- uri = Gem::URI(Gem::UriFormatter.new(env_proxy).normalize)
+ uri = URI(Gem::UriFormatter.new(env_proxy).normalize)
if uri && uri.user.nil? && uri.password.nil?
- user = ENV["#{downcase_scheme}_proxy_user"] || ENV["#{upcase_scheme}_PROXY_USER"]
- password = ENV["#{downcase_scheme}_proxy_pass"] || ENV["#{upcase_scheme}_PROXY_PASS"]
+ user = ENV["#{_scheme}_proxy_user"] || ENV["#{_SCHEME}_PROXY_USER"]
+ password = ENV["#{_scheme}_proxy_pass"] || ENV["#{_SCHEME}_PROXY_PASS"]
uri.user = Gem::UriFormatter.new(user).escape
uri.password = Gem::UriFormatter.new(password).escape
@@ -196,7 +192,7 @@ class Gem::Request
bad_response = false
begin
- @requests[connection] += 1
+ @requests[connection.object_id] += 1
verbose "#{request.method} #{Gem::Uri.redact(@uri)}"
@@ -205,7 +201,7 @@ class Gem::Request
if request.response_body_permitted? && file_name =~ /\.gem$/
reporter = ui.download_reporter
response = connection.request(request) do |incomplete_response|
- if Gem::Net::HTTPOK === incomplete_response
+ if Net::HTTPOK === incomplete_response
reporter.fetch(file_name, incomplete_response.content_length)
downloaded = 0
data = String.new
@@ -228,7 +224,8 @@ class Gem::Request
end
verbose "#{response.code} #{response.message}"
- rescue Gem::Net::HTTPBadResponse
+
+ rescue Net::HTTPBadResponse
verbose "bad response"
reset connection
@@ -237,17 +234,17 @@ class Gem::Request
bad_response = true
retry
- rescue Gem::Net::HTTPFatalError
+ rescue Net::HTTPFatalError
verbose "fatal error"
raise Gem::RemoteFetcher::FetchError.new("fatal error", @uri)
- # HACK: work around EOFError bug in Gem::Net::HTTP
+ # HACK work around EOFError bug in Net::HTTP
# NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible
# to install gems.
- rescue EOFError, Gem::Timeout::Error,
+ rescue EOFError, Timeout::Error,
Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE
- requests = @requests[connection]
+ requests = @requests[connection.object_id]
verbose "connection reset after #{requests} requests, retrying"
raise Gem::RemoteFetcher::FetchError.new("too many connection resets", @uri) if retried
@@ -267,7 +264,7 @@ class Gem::Request
# Resets HTTP connection +connection+.
def reset(connection)
- @requests.delete connection
+ @requests.delete connection.object_id
connection.finish
connection.start
@@ -282,7 +279,7 @@ class Gem::Request
ua << " Ruby/#{ruby_version} (#{RUBY_RELEASE_DATE}"
if RUBY_PATCHLEVEL >= 0
ua << " patchlevel #{RUBY_PATCHLEVEL}"
- else
+ elsif defined?(RUBY_REVISION)
ua << " revision #{RUBY_REVISION}"
end
ua << ")"
diff --git a/lib/rubygems/request/connection_pools.rb b/lib/rubygems/request/connection_pools.rb
index 6c1b04ab65..44280489fb 100644
--- a/lib/rubygems/request/connection_pools.rb
+++ b/lib/rubygems/request/connection_pools.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class Gem::Request::ConnectionPools # :nodoc:
- @client = Gem::Net::HTTP
+ @client = Net::HTTP
class << self
attr_accessor :client
@@ -28,7 +28,7 @@ class Gem::Request::ConnectionPools # :nodoc:
end
def close_all
- @pools.each_value(&:close_all)
+ @pools.each_value {|pool| pool.close_all }
end
private
@@ -45,7 +45,7 @@ class Gem::Request::ConnectionPools # :nodoc:
end
def https?(uri)
- uri.scheme.casecmp("https").zero?
+ uri.scheme.downcase == "https"
end
def no_proxy?(host, env_no_proxy)
diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb
index 875df7e019..b6e0995726 100644
--- a/lib/rubygems/request_set.rb
+++ b/lib/rubygems/request_set.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require_relative "vendored_tsort"
+require_relative "tsort"
##
# A RequestSet groups a request to activate a set of dependencies.
@@ -160,7 +160,7 @@ class Gem::RequestSet
end
# Create N threads in a pool, have them download all the gems
- threads = Array.new(Gem.configuration.concurrent_downloads) do
+ threads = Gem.configuration.concurrent_downloads.times.map do
# When a thread pops this item, it knows to stop running. The symbol
# is queued here so that there will be one symbol per thread.
download_queue << :stop
@@ -255,8 +255,7 @@ class Gem::RequestSet
end
def install_into(dir, force = true, options = {})
- gem_home = ENV["GEM_HOME"]
- ENV["GEM_HOME"] = dir
+ gem_home, ENV["GEM_HOME"] = ENV["GEM_HOME"], dir
existing = force ? [] : specs_in(dir)
existing.delete_if {|s| @always_install.include? s }
@@ -324,7 +323,7 @@ class Gem::RequestSet
@git_set.root_dir = @install_dir
- lock_file = "#{File.expand_path(path)}.lock"
+ lock_file = "#{File.expand_path(path)}.lock".dup.tap(&Gem::UNTAINT)
begin
tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file lock_file
parser = tokenizer.make_parser self, []
@@ -376,7 +375,7 @@ class Gem::RequestSet
q.text "sets:"
q.breakable
- q.pp @sets.map(&:class)
+ q.pp @sets.map {|set| set.class }
end
end
@@ -430,7 +429,7 @@ class Gem::RequestSet
end
def specs
- @specs ||= @requests.map(&:full_spec)
+ @specs ||= @requests.map {|r| r.full_spec }
end
def specs_in(dir)
@@ -448,7 +447,7 @@ class Gem::RequestSet
next if dep.type == :development && !@development
match = @requests.find do |r|
- dep.match?(r.spec.name, r.spec.version, r.spec.is_a?(Gem::Resolver::InstalledSpecification) || @prerelease)
+ dep.match? r.spec.name, r.spec.version, r.spec.is_a?(Gem::Resolver::InstalledSpecification) || @prerelease
end
unless match
diff --git a/lib/rubygems/request_set/gem_dependency_api.rb b/lib/rubygems/request_set/gem_dependency_api.rb
index 4347d22ccb..2fd0da340a 100644
--- a/lib/rubygems/request_set/gem_dependency_api.rb
+++ b/lib/rubygems/request_set/gem_dependency_api.rb
@@ -33,22 +33,22 @@
class Gem::RequestSet::GemDependencyAPI
ENGINE_MAP = { # :nodoc:
- jruby: %w[jruby],
- jruby_18: %w[jruby],
- jruby_19: %w[jruby],
- maglev: %w[maglev],
- mri: %w[ruby],
- mri_18: %w[ruby],
- mri_19: %w[ruby],
- mri_20: %w[ruby],
- mri_21: %w[ruby],
- rbx: %w[rbx],
- truffleruby: %w[truffleruby],
- ruby: %w[ruby rbx maglev truffleruby],
- ruby_18: %w[ruby rbx maglev truffleruby],
- ruby_19: %w[ruby rbx maglev truffleruby],
- ruby_20: %w[ruby rbx maglev truffleruby],
- ruby_21: %w[ruby rbx maglev truffleruby],
+ :jruby => %w[jruby],
+ :jruby_18 => %w[jruby],
+ :jruby_19 => %w[jruby],
+ :maglev => %w[maglev],
+ :mri => %w[ruby],
+ :mri_18 => %w[ruby],
+ :mri_19 => %w[ruby],
+ :mri_20 => %w[ruby],
+ :mri_21 => %w[ruby],
+ :rbx => %w[rbx],
+ :truffleruby => %w[truffleruby],
+ :ruby => %w[ruby rbx maglev truffleruby],
+ :ruby_18 => %w[ruby rbx maglev truffleruby],
+ :ruby_19 => %w[ruby rbx maglev truffleruby],
+ :ruby_20 => %w[ruby rbx maglev truffleruby],
+ :ruby_21 => %w[ruby rbx maglev truffleruby],
}.freeze
mswin = Gem::Platform.new "x86-mswin32"
@@ -57,39 +57,39 @@ class Gem::RequestSet::GemDependencyAPI
x64_mingw = Gem::Platform.new "x64-mingw32"
PLATFORM_MAP = { # :nodoc:
- jruby: Gem::Platform::RUBY,
- jruby_18: Gem::Platform::RUBY,
- jruby_19: Gem::Platform::RUBY,
- maglev: Gem::Platform::RUBY,
- mingw: x86_mingw,
- mingw_18: x86_mingw,
- mingw_19: x86_mingw,
- mingw_20: x86_mingw,
- mingw_21: x86_mingw,
- mri: Gem::Platform::RUBY,
- mri_18: Gem::Platform::RUBY,
- mri_19: Gem::Platform::RUBY,
- mri_20: Gem::Platform::RUBY,
- mri_21: Gem::Platform::RUBY,
- mswin: mswin,
- mswin_18: mswin,
- mswin_19: mswin,
- mswin_20: mswin,
- mswin_21: mswin,
- mswin64: mswin64,
- mswin64_19: mswin64,
- mswin64_20: mswin64,
- mswin64_21: mswin64,
- rbx: Gem::Platform::RUBY,
- ruby: Gem::Platform::RUBY,
- ruby_18: Gem::Platform::RUBY,
- ruby_19: Gem::Platform::RUBY,
- ruby_20: Gem::Platform::RUBY,
- ruby_21: Gem::Platform::RUBY,
- truffleruby: Gem::Platform::RUBY,
- x64_mingw: x64_mingw,
- x64_mingw_20: x64_mingw,
- x64_mingw_21: x64_mingw,
+ :jruby => Gem::Platform::RUBY,
+ :jruby_18 => Gem::Platform::RUBY,
+ :jruby_19 => Gem::Platform::RUBY,
+ :maglev => Gem::Platform::RUBY,
+ :mingw => x86_mingw,
+ :mingw_18 => x86_mingw,
+ :mingw_19 => x86_mingw,
+ :mingw_20 => x86_mingw,
+ :mingw_21 => x86_mingw,
+ :mri => Gem::Platform::RUBY,
+ :mri_18 => Gem::Platform::RUBY,
+ :mri_19 => Gem::Platform::RUBY,
+ :mri_20 => Gem::Platform::RUBY,
+ :mri_21 => Gem::Platform::RUBY,
+ :mswin => mswin,
+ :mswin_18 => mswin,
+ :mswin_19 => mswin,
+ :mswin_20 => mswin,
+ :mswin_21 => mswin,
+ :mswin64 => mswin64,
+ :mswin64_19 => mswin64,
+ :mswin64_20 => mswin64,
+ :mswin64_21 => mswin64,
+ :rbx => Gem::Platform::RUBY,
+ :ruby => Gem::Platform::RUBY,
+ :ruby_18 => Gem::Platform::RUBY,
+ :ruby_19 => Gem::Platform::RUBY,
+ :ruby_20 => Gem::Platform::RUBY,
+ :ruby_21 => Gem::Platform::RUBY,
+ :truffleruby => Gem::Platform::RUBY,
+ :x64_mingw => x64_mingw,
+ :x64_mingw_20 => x64_mingw,
+ :x64_mingw_21 => x64_mingw,
}.freeze
gt_eq_0 = Gem::Requirement.new ">= 0"
@@ -99,70 +99,70 @@ class Gem::RequestSet::GemDependencyAPI
tilde_gt_2_1_0 = Gem::Requirement.new "~> 2.1.0"
VERSION_MAP = { # :nodoc:
- jruby: gt_eq_0,
- jruby_18: tilde_gt_1_8_0,
- jruby_19: tilde_gt_1_9_0,
- maglev: gt_eq_0,
- mingw: gt_eq_0,
- mingw_18: tilde_gt_1_8_0,
- mingw_19: tilde_gt_1_9_0,
- mingw_20: tilde_gt_2_0_0,
- mingw_21: tilde_gt_2_1_0,
- mri: gt_eq_0,
- mri_18: tilde_gt_1_8_0,
- mri_19: tilde_gt_1_9_0,
- mri_20: tilde_gt_2_0_0,
- mri_21: tilde_gt_2_1_0,
- mswin: gt_eq_0,
- mswin_18: tilde_gt_1_8_0,
- mswin_19: tilde_gt_1_9_0,
- mswin_20: tilde_gt_2_0_0,
- mswin_21: tilde_gt_2_1_0,
- mswin64: gt_eq_0,
- mswin64_19: tilde_gt_1_9_0,
- mswin64_20: tilde_gt_2_0_0,
- mswin64_21: tilde_gt_2_1_0,
- rbx: gt_eq_0,
- ruby: gt_eq_0,
- ruby_18: tilde_gt_1_8_0,
- ruby_19: tilde_gt_1_9_0,
- ruby_20: tilde_gt_2_0_0,
- ruby_21: tilde_gt_2_1_0,
- truffleruby: gt_eq_0,
- x64_mingw: gt_eq_0,
- x64_mingw_20: tilde_gt_2_0_0,
- x64_mingw_21: tilde_gt_2_1_0,
+ :jruby => gt_eq_0,
+ :jruby_18 => tilde_gt_1_8_0,
+ :jruby_19 => tilde_gt_1_9_0,
+ :maglev => gt_eq_0,
+ :mingw => gt_eq_0,
+ :mingw_18 => tilde_gt_1_8_0,
+ :mingw_19 => tilde_gt_1_9_0,
+ :mingw_20 => tilde_gt_2_0_0,
+ :mingw_21 => tilde_gt_2_1_0,
+ :mri => gt_eq_0,
+ :mri_18 => tilde_gt_1_8_0,
+ :mri_19 => tilde_gt_1_9_0,
+ :mri_20 => tilde_gt_2_0_0,
+ :mri_21 => tilde_gt_2_1_0,
+ :mswin => gt_eq_0,
+ :mswin_18 => tilde_gt_1_8_0,
+ :mswin_19 => tilde_gt_1_9_0,
+ :mswin_20 => tilde_gt_2_0_0,
+ :mswin_21 => tilde_gt_2_1_0,
+ :mswin64 => gt_eq_0,
+ :mswin64_19 => tilde_gt_1_9_0,
+ :mswin64_20 => tilde_gt_2_0_0,
+ :mswin64_21 => tilde_gt_2_1_0,
+ :rbx => gt_eq_0,
+ :ruby => gt_eq_0,
+ :ruby_18 => tilde_gt_1_8_0,
+ :ruby_19 => tilde_gt_1_9_0,
+ :ruby_20 => tilde_gt_2_0_0,
+ :ruby_21 => tilde_gt_2_1_0,
+ :truffleruby => gt_eq_0,
+ :x64_mingw => gt_eq_0,
+ :x64_mingw_20 => tilde_gt_2_0_0,
+ :x64_mingw_21 => tilde_gt_2_1_0,
}.freeze
WINDOWS = { # :nodoc:
- mingw: :only,
- mingw_18: :only,
- mingw_19: :only,
- mingw_20: :only,
- mingw_21: :only,
- mri: :never,
- mri_18: :never,
- mri_19: :never,
- mri_20: :never,
- mri_21: :never,
- mswin: :only,
- mswin_18: :only,
- mswin_19: :only,
- mswin_20: :only,
- mswin_21: :only,
- mswin64: :only,
- mswin64_19: :only,
- mswin64_20: :only,
- mswin64_21: :only,
- rbx: :never,
- ruby: :never,
- ruby_18: :never,
- ruby_19: :never,
- ruby_20: :never,
- ruby_21: :never,
- x64_mingw: :only,
- x64_mingw_20: :only,
- x64_mingw_21: :only,
+ :mingw => :only,
+ :mingw_18 => :only,
+ :mingw_19 => :only,
+ :mingw_20 => :only,
+ :mingw_21 => :only,
+ :mri => :never,
+ :mri_18 => :never,
+ :mri_19 => :never,
+ :mri_20 => :never,
+ :mri_21 => :never,
+ :mswin => :only,
+ :mswin_18 => :only,
+ :mswin_19 => :only,
+ :mswin_20 => :only,
+ :mswin_21 => :only,
+ :mswin64 => :only,
+ :mswin64_19 => :only,
+ :mswin64_20 => :only,
+ :mswin64_21 => :only,
+ :rbx => :never,
+ :ruby => :never,
+ :ruby_18 => :never,
+ :ruby_19 => :never,
+ :ruby_20 => :never,
+ :ruby_21 => :never,
+ :x64_mingw => :only,
+ :x64_mingw_20 => :only,
+ :x64_mingw_21 => :only,
}.freeze
##
@@ -262,7 +262,7 @@ class Gem::RequestSet::GemDependencyAPI
raise ArgumentError, "no gemspecs found at #{Dir.pwd}"
else
raise ArgumentError,
- "found multiple gemspecs at #{Dir.pwd}, " \
+ "found multiple gemspecs at #{Dir.pwd}, " +
"use the name: option to specify the one you want"
end
end
@@ -280,7 +280,7 @@ class Gem::RequestSet::GemDependencyAPI
# Loads the gem dependency file and returns self.
def load
- instance_eval File.read(@path), @path, 1
+ instance_eval File.read(@path).tap(&Gem::UNTAINT), @path, 1
self
end
@@ -357,7 +357,7 @@ class Gem::RequestSet::GemDependencyAPI
# Use the given tag for git:, gist: and github: dependencies.
def gem(name, *requirements)
- options = requirements.pop if requirements.last.is_a?(Hash)
+ options = requirements.pop if requirements.last.kind_of?(Hash)
options ||= {}
options[:git] = @current_repository if @current_repository
@@ -533,8 +533,8 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
# platform matches the current platform.
def gem_platforms(name, options) # :nodoc:
- platform_names = Array(options.delete(:platform))
- platform_names.concat Array(options.delete(:platforms))
+ platform_names = Array(options.delete :platform)
+ platform_names.concat Array(options.delete :platforms)
platform_names.concat @current_platforms if @current_platforms
return true if platform_names.empty?
@@ -593,6 +593,7 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
@current_repository = repository
yield
+
ensure
@current_repository = nil
end
@@ -684,6 +685,7 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
@current_groups = groups
yield
+
ensure
@current_groups = nil
end
@@ -758,6 +760,7 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
@current_platforms = platforms
yield
+
ensure
@current_platforms = nil
end
@@ -768,7 +771,7 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
# Block form for restricting gems to a particular set of platforms. See
# #platform.
- alias_method :platforms, :platform
+ alias :platforms :platform
##
# :category: Gem Dependencies DSL
@@ -790,15 +793,15 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
return true if @installing
- unless version == RUBY_VERSION
- message = "Your Ruby version is #{RUBY_VERSION}, " \
+ unless RUBY_VERSION == version
+ message = "Your Ruby version is #{RUBY_VERSION}, " +
"but your #{gem_deps_file} requires #{version}"
raise Gem::RubyVersionMismatch, message
end
if engine && engine != Gem.ruby_engine
- message = "Your Ruby engine is #{Gem.ruby_engine}, " \
+ message = "Your Ruby engine is #{Gem.ruby_engine}, " +
"but your #{gem_deps_file} requires #{engine}"
raise Gem::RubyVersionMismatch, message
@@ -807,14 +810,14 @@ Gem dependencies file #{@path} includes git reference for both ref/branch and ta
if engine_version
if engine_version != RUBY_ENGINE_VERSION
message =
- "Your Ruby engine version is #{Gem.ruby_engine} #{RUBY_ENGINE_VERSION}, " \
+ "Your Ruby engine version is #{Gem.ruby_engine} #{RUBY_ENGINE_VERSION}, " +
"but your #{gem_deps_file} requires #{engine} #{engine_version}"
raise Gem::RubyVersionMismatch, message
end
end
- true
+ return true
end
##
diff --git a/lib/rubygems/request_set/lockfile.rb b/lib/rubygems/request_set/lockfile.rb
index c446b3ae51..9523fa7786 100644
--- a/lib/rubygems/request_set/lockfile.rb
+++ b/lib/rubygems/request_set/lockfile.rb
@@ -76,13 +76,18 @@ class Gem::RequestSet::Lockfile
@dependencies = dependencies
@gem_deps_file = File.expand_path(gem_deps_file)
@gem_deps_dir = File.dirname(@gem_deps_file)
+
+ if RUBY_VERSION < "2.7"
+ @gem_deps_file.untaint unless gem_deps_file.tainted?
+ end
+
@platforms = []
end
def add_DEPENDENCIES(out) # :nodoc:
out << "DEPENDENCIES"
- out.concat @dependencies.sort.map {|name, requirement|
+ out.concat @dependencies.sort_by {|name,| name }.map {|name, requirement|
" #{name}#{requirement.for_lockfile}"
}
@@ -101,10 +106,10 @@ class Gem::RequestSet::Lockfile
out << " remote: #{group}"
out << " specs:"
- requests.sort_by(&:name).each do |request|
+ requests.sort_by {|request| request.name }.each do |request|
next if request.spec.name == "bundler"
platform = "-#{request.spec.platform}" unless
- request.spec.platform == Gem::Platform::RUBY
+ Gem::Platform::RUBY == request.spec.platform
out << " #{request.name} (#{request.version}#{platform})"
@@ -133,10 +138,10 @@ class Gem::RequestSet::Lockfile
out << " revision: #{revision}"
out << " specs:"
- requests.sort_by(&:name).each do |request|
+ requests.sort_by {|request| request.name }.each do |request|
out << " #{request.name} (#{request.version})"
- dependencies = request.spec.dependencies.sort_by(&:name)
+ dependencies = request.spec.dependencies.sort_by {|dep| dep.name }
dependencies.each do |dep|
out << " #{dep.name}#{dep.requirement.for_lockfile}"
end
@@ -180,7 +185,7 @@ class Gem::RequestSet::Lockfile
platforms = requests.map {|request| request.spec.platform }.uniq
- platforms = platforms.sort_by(&:to_s)
+ platforms = platforms.sort_by {|platform| platform.to_s }
platforms.each do |platform|
out << " #{platform}"
diff --git a/lib/rubygems/request_set/lockfile/parser.rb b/lib/rubygems/request_set/lockfile/parser.rb
index e751a1445e..1daec1fabd 100644
--- a/lib/rubygems/request_set/lockfile/parser.rb
+++ b/lib/rubygems/request_set/lockfile/parser.rb
@@ -48,7 +48,7 @@ class Gem::RequestSet::Lockfile::Parser
if expected_types && !Array(expected_types).include?(token.type)
unget token
- message = "unexpected token [#{token.type.inspect}, #{token.value.inspect}], " \
+ message = "unexpected token [#{token.type.inspect}, #{token.value.inspect}], " +
"expected #{expected_types.inspect}"
raise Gem::RequestSet::Lockfile::ParseError.new message, token.column, token.line, @filename
@@ -57,8 +57,8 @@ class Gem::RequestSet::Lockfile::Parser
if expected_value && expected_value != token.value
unget token
- message = "unexpected token [#{token.type.inspect}, #{token.value.inspect}], " \
- "expected [#{expected_types.inspect}, " \
+ message = "unexpected token [#{token.type.inspect}, #{token.value.inspect}], " +
+ "expected [#{expected_types.inspect}, " +
"#{expected_value.inspect}]"
raise Gem::RequestSet::Lockfile::ParseError.new message, token.column, token.line, @filename
@@ -68,7 +68,7 @@ class Gem::RequestSet::Lockfile::Parser
end
def parse_DEPENDENCIES # :nodoc:
- while !@tokens.empty? && peek.type == :text do
+ while !@tokens.empty? && :text == peek.type do
token = get :text
requirements = []
@@ -111,7 +111,7 @@ class Gem::RequestSet::Lockfile::Parser
def parse_GEM # :nodoc:
sources = []
- while peek.first(2) == [:entry, "remote"] do
+ while [:entry, "remote"] == peek.first(2) do
get :entry, "remote"
data = get(:text).value
skip :newline
@@ -128,7 +128,7 @@ class Gem::RequestSet::Lockfile::Parser
set = Gem::Resolver::LockSet.new sources
last_specs = nil
- while !@tokens.empty? && peek.type == :text do
+ while !@tokens.empty? && :text == peek.type do
token = get :text
name = token.value
column = token.column
@@ -200,7 +200,7 @@ class Gem::RequestSet::Lockfile::Parser
last_spec = nil
- while !@tokens.empty? && peek.type == :text do
+ while !@tokens.empty? && :text == peek.type do
token = get :text
name = token.value
column = token.column
@@ -247,7 +247,7 @@ class Gem::RequestSet::Lockfile::Parser
set = Gem::Resolver::VendorSet.new
last_spec = nil
- while !@tokens.empty? && peek.first == :text do
+ while !@tokens.empty? && :text == peek.first do
token = get :text
name = token.value
column = token.column
@@ -282,7 +282,7 @@ class Gem::RequestSet::Lockfile::Parser
end
def parse_PLATFORMS # :nodoc:
- while !@tokens.empty? && peek.first == :text do
+ while !@tokens.empty? && :text == peek.first do
name = get(:text).value
@platforms << name
diff --git a/lib/rubygems/request_set/lockfile/tokenizer.rb b/lib/rubygems/request_set/lockfile/tokenizer.rb
index 65cef3baa0..e91a11ca93 100644
--- a/lib/rubygems/request_set/lockfile/tokenizer.rb
+++ b/lib/rubygems/request_set/lockfile/tokenizer.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# ) frozen_string_literal: true
+#) frozen_string_literal: true
require_relative "parser"
class Gem::RequestSet::Lockfile::Tokenizer
@@ -50,7 +50,7 @@ class Gem::RequestSet::Lockfile::Tokenizer
def next_token
@tokens.shift
end
- alias_method :shift, :next_token
+ alias :shift :next_token
def peek
@tokens.first || EOF
@@ -75,14 +75,13 @@ class Gem::RequestSet::Lockfile::Tokenizer
end
@tokens <<
- if s.scan(/\r?\n/)
-
+ case
+ when s.scan(/\r?\n/) then
token = Token.new(:newline, nil, *token_pos(pos))
@line_pos = s.pos
@line += 1
token
- elsif s.scan(/[A-Z]+/)
-
+ when s.scan(/[A-Z]+/) then
if leading_whitespace
text = s.matched
text += s.scan(/[^\s)]*/).to_s # in case of no match
@@ -90,27 +89,20 @@ class Gem::RequestSet::Lockfile::Tokenizer
else
Token.new(:section, s.matched, *token_pos(pos))
end
- elsif s.scan(/([a-z]+):\s/)
-
+ when s.scan(/([a-z]+):\s/) then
s.pos -= 1 # rewind for possible newline
Token.new(:entry, s[1], *token_pos(pos))
- elsif s.scan(/\(/)
-
+ when s.scan(/\(/) then
Token.new(:l_paren, nil, *token_pos(pos))
- elsif s.scan(/\)/)
-
+ when s.scan(/\)/) then
Token.new(:r_paren, nil, *token_pos(pos))
- elsif s.scan(/<=|>=|=|~>|<|>|!=/)
-
+ when s.scan(/<=|>=|=|~>|<|>|!=/) then
Token.new(:requirement, s.matched, *token_pos(pos))
- elsif s.scan(/,/)
-
+ when s.scan(/,/) then
Token.new(:comma, nil, *token_pos(pos))
- elsif s.scan(/!/)
-
+ when s.scan(/!/) then
Token.new(:bang, nil, *token_pos(pos))
- elsif s.scan(/[^\s),!]*/)
-
+ when s.scan(/[^\s),!]*/) then
Token.new(:text, s.matched, *token_pos(pos))
else
raise "BUG: can't create token for: #{s.string[s.pos..-1].inspect}"
diff --git a/lib/rubygems/requirement.rb b/lib/rubygems/requirement.rb
index d9796c4208..eed12c4914 100644
--- a/lib/rubygems/requirement.rb
+++ b/lib/rubygems/requirement.rb
@@ -10,11 +10,11 @@ require_relative "version"
# together in RubyGems.
class Gem::Requirement
- OPS = { # :nodoc:
+ OPS = { #:nodoc:
"=" => lambda {|v, r| v == r },
"!=" => lambda {|v, r| v != r },
- ">" => lambda {|v, r| v > r },
- "<" => lambda {|v, r| v < r },
+ ">" => lambda {|v, r| v > r },
+ "<" => lambda {|v, r| v < r },
">=" => lambda {|v, r| v >= r },
"<=" => lambda {|v, r| v <= r },
"~>" => lambda {|v, r| v >= r && v.release < r.bump },
@@ -23,12 +23,12 @@ class Gem::Requirement
SOURCE_SET_REQUIREMENT = Struct.new(:for_lockfile).new "!" # :nodoc:
quoted = OPS.keys.map {|k| Regexp.quote k }.join "|"
- PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{Gem::Version::VERSION_PATTERN})\\s*".freeze # :nodoc:
+ PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{Gem::Version::VERSION_PATTERN})\\s*" # :nodoc:
##
# A regular expression that matches a requirement
- PATTERN = /\A#{PATTERN_RAW}\z/
+ PATTERN = /\A#{PATTERN_RAW}\z/.freeze
##
# The default requirement matches any non-prerelease version
@@ -120,7 +120,7 @@ class Gem::Requirement
# An array of requirement pairs. The first element of the pair is
# the op, and the second is the Gem::Version.
- attr_reader :requirements # :nodoc:
+ attr_reader :requirements #:nodoc:
##
# Constructs a requirement from +requirements+. Requirements can be
@@ -156,7 +156,7 @@ class Gem::Requirement
# Formats this requirement for use in a Gem::RequestSet::Lockfile.
def for_lockfile # :nodoc:
- return if @requirements == [DefaultRequirement]
+ return if [DefaultRequirement] == @requirements
list = requirements.sort_by do |_, version|
version
@@ -164,7 +164,7 @@ class Gem::Requirement
"#{op} #{version}"
end.uniq
- " (#{list.join ", "})"
+ " (#{list.join ', '})"
end
##
@@ -214,6 +214,10 @@ class Gem::Requirement
yaml_initialize coder.tag, coder.map
end
+ def to_yaml_properties # :nodoc:
+ ["@requirements"]
+ end
+
def encode_with(coder) # :nodoc:
coder.add "requirements", @requirements
end
@@ -241,8 +245,8 @@ class Gem::Requirement
requirements.all? {|op, rv| OPS[op].call version, rv }
end
- alias_method :===, :satisfied_by?
- alias_method :=~, :satisfied_by?
+ alias :=== :satisfied_by?
+ alias :=~ :satisfied_by?
##
# True if the requirement will not always match the latest version.
@@ -280,11 +284,6 @@ class Gem::Requirement
def _tilde_requirements
@_tilde_requirements ||= _sorted_requirements.select {|r| r.first == "~>" }
end
-
- def initialize_copy(other) # :nodoc:
- @requirements = other.requirements.dup
- super
- end
end
class Gem::Version
diff --git a/lib/rubygems/resolver.rb b/lib/rubygems/resolver.rb
index 115c716b6b..a912729b37 100644
--- a/lib/rubygems/resolver.rb
+++ b/lib/rubygems/resolver.rb
@@ -11,7 +11,7 @@ require_relative "util/list"
# all the requirements.
class Gem::Resolver
- require_relative "vendored_molinillo"
+ require_relative "resolver/molinillo"
##
# If the DEBUG_RESOLVER environment variable is set then debugging mode is
@@ -38,6 +38,8 @@ class Gem::Resolver
##
# List of dependencies that could not be found in the configured sources.
+ attr_reader :missing
+
attr_reader :stats
##
@@ -47,7 +49,8 @@ class Gem::Resolver
attr_accessor :skip_gems
##
- #
+ # When a missing dependency, don't stop. Just go on and record what was
+ # missing.
attr_accessor :soft_missing
@@ -103,6 +106,7 @@ class Gem::Resolver
@development = false
@development_shallow = false
@ignore_dependencies = false
+ @missing = []
@skip_gems = {}
@soft_missing = false
@stats = Gem::Resolver::Stats.new
@@ -111,7 +115,7 @@ class Gem::Resolver
def explain(stage, *data) # :nodoc:
return unless DEBUG_RESOLVER
- d = data.map(&:pretty_inspect).join(", ")
+ d = data.map {|x| x.pretty_inspect }.join(", ")
$stderr.printf "%10s %s\n", stage.to_s.upcase, d
end
@@ -141,7 +145,7 @@ class Gem::Resolver
activation_request =
Gem::Resolver::ActivationRequest.new spec, dep, possible
- [spec, activation_request]
+ return spec, activation_request
end
def requests(s, act, reqs=[]) # :nodoc:
@@ -167,7 +171,7 @@ class Gem::Resolver
reqs
end
- include Gem::Molinillo::UI
+ include Molinillo::UI
def output
@output ||= debug? ? $stdout : File.open(IO::NULL, "w")
@@ -177,14 +181,15 @@ class Gem::Resolver
DEBUG_RESOLVER
end
- include Gem::Molinillo::SpecificationProvider
+ include Molinillo::SpecificationProvider
##
# Proceed with resolution! Returns an array of ActivationRequest objects.
def resolve
- Gem::Molinillo::Resolver.new(self, self).resolve(@needed.map {|d| DependencyRequest.new d, nil }).tsort.map(&:payload).compact
- rescue Gem::Molinillo::VersionConflict => e
+ locking_dg = Molinillo::DependencyGraph.new
+ Molinillo::Resolver.new(self, self).resolve(@needed.map {|d| DependencyRequest.new d, nil }, locking_dg).tsort.map(&:payload).compact
+ rescue Molinillo::VersionConflict => e
conflict = e.conflicts.values.first
raise Gem::DependencyResolutionError, Conflict.new(conflict.requirement_trees.first.first, conflict.existing, conflict.requirement)
ensure
@@ -208,7 +213,7 @@ class Gem::Resolver
matching_platform = select_local_platforms all
- [matching_platform, all]
+ return matching_platform, all
end
##
@@ -223,6 +228,7 @@ class Gem::Resolver
def search_for(dependency)
possibles, all = find_possible(dependency)
if !@soft_missing && possibles.empty?
+ @missing << dependency
exc = Gem::UnsatisfiableDependencyError.new dependency, all
exc.errors = @set.errors
raise exc
@@ -241,7 +247,7 @@ class Gem::Resolver
sources.each do |source|
groups[source].
- sort_by {|spec| [spec.version, spec.platform =~ Gem::Platform.local ? 1 : 0] }. # rubocop:disable Performance/RegexpMatch
+ sort_by {|spec| [spec.version, spec.platform =~ Gem::Platform.local ? 1 : 0] }.
map {|spec| ActivationRequest.new spec, dependency }.
each {|activation_request| activation_requests << activation_request }
end
@@ -269,6 +275,7 @@ class Gem::Resolver
end
def allow_missing?(dependency)
+ @missing << dependency
@soft_missing
end
diff --git a/lib/rubygems/resolver/activation_request.rb b/lib/rubygems/resolver/activation_request.rb
index 5c722001b1..d59859c102 100644
--- a/lib/rubygems/resolver/activation_request.rb
+++ b/lib/rubygems/resolver/activation_request.rb
@@ -59,8 +59,10 @@ class Gem::Resolver::ActivationRequest
if @spec.respond_to? :sources
exception = nil
path = @spec.sources.find do |source|
- source.download full_spec, path
- rescue exception
+ begin
+ source.download full_spec, path
+ rescue exception
+ end
end
return path if path
raise exception if exception
@@ -92,7 +94,9 @@ class Gem::Resolver::ActivationRequest
end
def inspect # :nodoc:
- format("#<%s for %p from %s>", self.class, @spec, @request)
+ "#<%s for %p from %s>" % [
+ self.class, @spec, @request
+ ]
end
##
@@ -106,7 +110,7 @@ class Gem::Resolver::ActivationRequest
this_spec = full_spec
Gem::Specification.any? do |s|
- s == this_spec && s.base_dir == this_spec.base_dir
+ s == this_spec
end
end
end
diff --git a/lib/rubygems/resolver/api_set.rb b/lib/rubygems/resolver/api_set.rb
index 9f6695a6a9..9b57b03192 100644
--- a/lib/rubygems/resolver/api_set.rb
+++ b/lib/rubygems/resolver/api_set.rb
@@ -30,7 +30,7 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
def initialize(dep_uri = "https://index.rubygems.org/info/")
super()
- dep_uri = Gem::URI dep_uri unless Gem::URI === dep_uri
+ dep_uri = URI dep_uri unless URI === dep_uri
@dep_uri = dep_uri
@uri = dep_uri + ".."
@@ -76,8 +76,7 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
end
def prefetch_now # :nodoc:
- needed = @to_fetch
- @to_fetch = []
+ needed, @to_fetch = @to_fetch, []
needed.sort.each do |name|
versions(name)
@@ -104,21 +103,16 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
end
uri = @dep_uri + name
+ str = Gem::RemoteFetcher.fetcher.fetch_path uri
- begin
- str = Gem::RemoteFetcher.fetcher.fetch_path uri
- rescue Gem::RemoteFetcher::FetchError
- @data[name] = []
- else
- lines(str).each do |ver|
- number, platform, dependencies, requirements = parse_gem(ver)
+ lines(str).each do |ver|
+ number, platform, dependencies, requirements = parse_gem(ver)
- platform ||= "ruby"
- dependencies = dependencies.map {|dep_name, reqs| [dep_name, reqs.join(", ")] }
- requirements = requirements.map {|req_name, reqs| [req_name.to_sym, reqs] }.to_h
+ platform ||= "ruby"
+ dependencies = dependencies.map {|dep_name, reqs| [dep_name, reqs.join(", ")] }
+ requirements = requirements.map {|req_name, reqs| [req_name.to_sym, reqs] }.to_h
- @data[name] << { name: name, number: number, platform: platform, dependencies: dependencies, requirements: requirements }
- end
+ @data[name] << { name: name, number: number, platform: platform, dependencies: dependencies, requirements: requirements }
end
@data[name]
diff --git a/lib/rubygems/resolver/api_set/gem_parser.rb b/lib/rubygems/resolver/api_set/gem_parser.rb
index 643b857107..685c39558d 100644
--- a/lib/rubygems/resolver/api_set/gem_parser.rb
+++ b/lib/rubygems/resolver/api_set/gem_parser.rb
@@ -1,15 +1,12 @@
# frozen_string_literal: true
class Gem::Resolver::APISet::GemParser
- EMPTY_ARRAY = [].freeze
- private_constant :EMPTY_ARRAY
-
def parse(line)
version_and_platform, rest = line.split(" ", 2)
version, platform = version_and_platform.split("-", 2)
- dependencies, requirements = rest.split("|", 2).map! {|s| s.split(",") } if rest
- dependencies = dependencies ? dependencies.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
- requirements = requirements ? requirements.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
+ dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest
+ dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : []
+ requirements = requirements ? requirements.map {|d| parse_dependency(d) } : []
[version, platform, dependencies, requirements]
end
@@ -18,7 +15,6 @@ class Gem::Resolver::APISet::GemParser
def parse_dependency(string)
dependency = string.split(":")
dependency[-1] = dependency[-1].split("&") if dependency.size > 1
- dependency[0] = -dependency[0]
dependency
end
end
diff --git a/lib/rubygems/resolver/api_specification.rb b/lib/rubygems/resolver/api_specification.rb
index a14bcbfeb1..f26f82757e 100644
--- a/lib/rubygems/resolver/api_specification.rb
+++ b/lib/rubygems/resolver/api_specification.rb
@@ -22,7 +22,7 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification
# Creates an APISpecification for the given +set+ from the rubygems.org
# +api_data+.
#
- # See https://guides.rubygems.org/rubygems-org-api/#misc-methods for the
+ # See https://guides.rubygems.org/rubygems-org-api/#misc_methods for the
# format of the +api_data+.
def initialize(set, api_data)
diff --git a/lib/rubygems/resolver/best_set.rb b/lib/rubygems/resolver/best_set.rb
index e2307f6e02..d75fa7c00a 100644
--- a/lib/rubygems/resolver/best_set.rb
+++ b/lib/rubygems/resolver/best_set.rb
@@ -29,6 +29,10 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
pick_sets if @remote && @sets.empty?
super
+ rescue Gem::RemoteFetcher::FetchError => e
+ replace_failed_api_set e
+
+ retry
end
def prefetch(reqs) # :nodoc:
@@ -46,4 +50,28 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
q.pp @sets
end
end
+
+ ##
+ # Replaces a failed APISet for the URI in +error+ with an IndexSet.
+ #
+ # If no matching APISet can be found the original +error+ is raised.
+ #
+ # The calling method must retry the exception to repeat the lookup.
+
+ def replace_failed_api_set(error) # :nodoc:
+ uri = error.original_uri
+ uri = URI uri unless URI === uri
+ uri = uri + "."
+
+ raise error unless api_set = @sets.find do |set|
+ Gem::Resolver::APISet === set && set.dep_uri == uri
+ end
+
+ index_set = Gem::Resolver::IndexSet.new api_set.source
+
+ @sets.map! do |set|
+ next set unless set == api_set
+ index_set
+ end
+ end
end
diff --git a/lib/rubygems/resolver/composed_set.rb b/lib/rubygems/resolver/composed_set.rb
index 8a714ad447..0991f0713e 100644
--- a/lib/rubygems/resolver/composed_set.rb
+++ b/lib/rubygems/resolver/composed_set.rb
@@ -44,7 +44,7 @@ class Gem::Resolver::ComposedSet < Gem::Resolver::Set
end
def errors
- @errors + @sets.map(&:errors).flatten
+ @errors + @sets.map {|set| set.errors }.flatten
end
##
diff --git a/lib/rubygems/resolver/conflict.rb b/lib/rubygems/resolver/conflict.rb
index 367a36b43d..dca41da51f 100644
--- a/lib/rubygems/resolver/conflict.rb
+++ b/lib/rubygems/resolver/conflict.rb
@@ -55,7 +55,7 @@ class Gem::Resolver::Conflict
activated = @activated.spec.full_name
dependency = @failed_dep.dependency
requirement = dependency.requirement
- alternates = dependency.matching_specs.map(&:full_name)
+ alternates = dependency.matching_specs.map {|spec| spec.full_name }
unless alternates.empty?
matching = <<-MATCHING.chomp
@@ -64,7 +64,10 @@ class Gem::Resolver::Conflict
%s
MATCHING
- matching = format(matching, dependency, alternates.join(", "))
+ matching = matching % [
+ dependency,
+ alternates.join(", "),
+ ]
end
explanation = <<-EXPLANATION
@@ -79,7 +82,12 @@ class Gem::Resolver::Conflict
%s
EXPLANATION
- format(explanation, activated, requirement, request_path(@activated).reverse.join(", depends on\n "), request_path(@failed_dep).reverse.join(", depends on\n "), matching)
+ explanation % [
+ activated, requirement,
+ request_path(@activated).reverse.join(", depends on\n "),
+ request_path(@failed_dep).reverse.join(", depends on\n "),
+ matching
+ ]
end
##
@@ -124,7 +132,7 @@ class Gem::Resolver::Conflict
current = current.parent
when Gem::Resolver::DependencyRequest then
- path << current.dependency.to_s
+ path << "#{current.dependency}"
current = current.requester
else
diff --git a/lib/rubygems/resolver/index_set.rb b/lib/rubygems/resolver/index_set.rb
index 0b4f376452..5e8632c7d8 100644
--- a/lib/rubygems/resolver/index_set.rb
+++ b/lib/rubygems/resolver/index_set.rb
@@ -44,10 +44,10 @@ class Gem::Resolver::IndexSet < Gem::Resolver::Set
name = req.dependency.name
@all[name].each do |uri, n|
- next unless req.match? n, @prerelease
- res << Gem::Resolver::IndexSpecification.new(
- self, n.name, n.version, uri, n.platform
- )
+ if req.match? n, @prerelease
+ res << Gem::Resolver::IndexSpecification.new(
+ self, n.name, n.version, uri, n.platform)
+ end
end
res
diff --git a/lib/rubygems/resolver/index_specification.rb b/lib/rubygems/resolver/index_specification.rb
index 7b95608071..6fac8c1487 100644
--- a/lib/rubygems/resolver/index_specification.rb
+++ b/lib/rubygems/resolver/index_specification.rb
@@ -68,7 +68,7 @@ class Gem::Resolver::IndexSpecification < Gem::Resolver::Specification
end
def inspect # :nodoc:
- format("#<%s %s source %s>", self.class, full_name, @source)
+ "#<%s %s source %s>" % [self.class, full_name, @source]
end
def pretty_print(q) # :nodoc:
@@ -76,7 +76,7 @@ class Gem::Resolver::IndexSpecification < Gem::Resolver::Specification
q.breakable
q.text full_name
- unless @platform == Gem::Platform::RUBY
+ unless Gem::Platform::RUBY == @platform
q.breakable
q.text @platform.to_s
end
diff --git a/lib/rubygems/resolver/installed_specification.rb b/lib/rubygems/resolver/installed_specification.rb
index 8280ae4672..b80f882c77 100644
--- a/lib/rubygems/resolver/installed_specification.rb
+++ b/lib/rubygems/resolver/installed_specification.rb
@@ -25,7 +25,7 @@ class Gem::Resolver::InstalledSpecification < Gem::Resolver::SpecSpecification
def installable_platform?
# BACKCOMPAT If the file is coming out of a specified file, then we
# ignore the platform. This code can be removed in RG 3.0.
- return true if @source.is_a? Gem::Source::SpecificFile
+ return true if @source.kind_of? Gem::Source::SpecificFile
super
end
diff --git a/lib/rubygems/resolver/installer_set.rb b/lib/rubygems/resolver/installer_set.rb
index d9fe36c589..521d241fd5 100644
--- a/lib/rubygems/resolver/installer_set.rb
+++ b/lib/rubygems/resolver/installer_set.rb
@@ -163,8 +163,7 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
if local_spec = @local_source.find_gem(name, dep.requirement)
res << Gem::Resolver::IndexSpecification.new(
self, local_spec.name, local_spec.version,
- @local_source, local_spec.platform
- )
+ @local_source, local_spec.platform)
end
rescue Gem::Package::FormatError
# ignore
@@ -187,9 +186,11 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
end
def inspect # :nodoc:
- always_install = @always_install.map(&:full_name)
+ always_install = @always_install.map {|s| s.full_name }
- format("#<%s domain: %s specs: %p always install: %p>", self.class, @domain, @specs.keys, always_install)
+ "#<%s domain: %s specs: %p always install: %p>" % [
+ self.class, @domain, @specs.keys, always_install
+ ]
end
##
@@ -263,7 +264,7 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
unless rrgv.satisfied_by? Gem.rubygems_version
rg_version = Gem::VERSION
raise Gem::RuntimeRequirementNotMetError,
- "#{spec.full_name} requires RubyGems version #{rrgv}. The current RubyGems version is #{rg_version}. " \
+ "#{spec.full_name} requires RubyGems version #{rrgv}. The current RubyGems version is #{rg_version}. " +
"Try 'gem update --system' to update RubyGems itself."
end
end
diff --git a/lib/rubygems/resolver/local_specification.rb b/lib/rubygems/resolver/local_specification.rb
index b57d40e795..50bf276345 100644
--- a/lib/rubygems/resolver/local_specification.rb
+++ b/lib/rubygems/resolver/local_specification.rb
@@ -8,7 +8,7 @@ class Gem::Resolver::LocalSpecification < Gem::Resolver::SpecSpecification
# Returns +true+ if this gem is installable for the current platform.
def installable_platform?
- return true if @source.is_a? Gem::Source::SpecificFile
+ return true if @source.kind_of? Gem::Source::SpecificFile
super
end
diff --git a/lib/rubygems/resolver/lock_set.rb b/lib/rubygems/resolver/lock_set.rb
index e5ee32a9a6..8eec041bdc 100644
--- a/lib/rubygems/resolver/lock_set.rb
+++ b/lib/rubygems/resolver/lock_set.rb
@@ -75,7 +75,7 @@ class Gem::Resolver::LockSet < Gem::Resolver::Set
q.text "specs:"
q.breakable
- q.pp @specs.map(&:full_name)
+ q.pp @specs.map {|spec| spec.full_name }
end
end
end
diff --git a/lib/rubygems/resolver/molinillo.rb b/lib/rubygems/resolver/molinillo.rb
new file mode 100644
index 0000000000..d703505410
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+require_relative "molinillo/lib/molinillo"
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo.rb b/lib/rubygems/resolver/molinillo/lib/molinillo.rb
new file mode 100644
index 0000000000..f67badbde7
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require_relative 'molinillo/gem_metadata'
+require_relative 'molinillo/errors'
+require_relative 'molinillo/resolver'
+require_relative 'molinillo/modules/ui'
+require_relative 'molinillo/modules/specification_provider'
+
+# Gem::Resolver::Molinillo is a generic dependency resolution algorithm.
+module Gem::Resolver::Molinillo
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb
new file mode 100644
index 0000000000..d540d3baff
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ # @!visibility private
+ module Delegates
+ # Delegates all {Gem::Resolver::Molinillo::ResolutionState} methods to a `#state` property.
+ module ResolutionState
+ # (see Gem::Resolver::Molinillo::ResolutionState#name)
+ def name
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.name
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#requirements)
+ def requirements
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.requirements
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#activated)
+ def activated
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.activated
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#requirement)
+ def requirement
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.requirement
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#possibilities)
+ def possibilities
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.possibilities
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#depth)
+ def depth
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.depth
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#conflicts)
+ def conflicts
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.conflicts
+ end
+
+ # (see Gem::Resolver::Molinillo::ResolutionState#unused_unwind_options)
+ def unused_unwind_options
+ current_state = state || Gem::Resolver::Molinillo::ResolutionState.empty
+ current_state.unused_unwind_options
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb
new file mode 100644
index 0000000000..b765226fb0
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ module Delegates
+ # Delegates all {Gem::Resolver::Molinillo::SpecificationProvider} methods to a
+ # `#specification_provider` property.
+ module SpecificationProvider
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#search_for)
+ def search_for(dependency)
+ with_no_such_dependency_error_handling do
+ specification_provider.search_for(dependency)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#dependencies_for)
+ def dependencies_for(specification)
+ with_no_such_dependency_error_handling do
+ specification_provider.dependencies_for(specification)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#requirement_satisfied_by?)
+ def requirement_satisfied_by?(requirement, activated, spec)
+ with_no_such_dependency_error_handling do
+ specification_provider.requirement_satisfied_by?(requirement, activated, spec)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#dependencies_equal?)
+ def dependencies_equal?(dependencies, other_dependencies)
+ with_no_such_dependency_error_handling do
+ specification_provider.dependencies_equal?(dependencies, other_dependencies)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#name_for)
+ def name_for(dependency)
+ with_no_such_dependency_error_handling do
+ specification_provider.name_for(dependency)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#name_for_explicit_dependency_source)
+ def name_for_explicit_dependency_source
+ with_no_such_dependency_error_handling do
+ specification_provider.name_for_explicit_dependency_source
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#name_for_locking_dependency_source)
+ def name_for_locking_dependency_source
+ with_no_such_dependency_error_handling do
+ specification_provider.name_for_locking_dependency_source
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#sort_dependencies)
+ def sort_dependencies(dependencies, activated, conflicts)
+ with_no_such_dependency_error_handling do
+ specification_provider.sort_dependencies(dependencies, activated, conflicts)
+ end
+ end
+
+ # (see Gem::Resolver::Molinillo::SpecificationProvider#allow_missing?)
+ def allow_missing?(dependency)
+ with_no_such_dependency_error_handling do
+ specification_provider.allow_missing?(dependency)
+ end
+ end
+
+ private
+
+ # Ensures any raised {NoSuchDependencyError} has its
+ # {NoSuchDependencyError#required_by} set.
+ # @yield
+ def with_no_such_dependency_error_handling
+ yield
+ rescue NoSuchDependencyError => error
+ if state
+ vertex = activated.vertex_named(name_for(error.dependency))
+ error.required_by += vertex.incoming_edges.map { |e| e.origin.name }
+ error.required_by << name_for_explicit_dependency_source unless vertex.explicit_requirements.empty?
+ end
+ raise
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb
new file mode 100644
index 0000000000..731a9e3e90
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb
@@ -0,0 +1,255 @@
+# frozen_string_literal: true
+
+require_relative '../../../../tsort'
+
+require_relative 'dependency_graph/log'
+require_relative 'dependency_graph/vertex'
+
+module Gem::Resolver::Molinillo
+ # A directed acyclic graph that is tuned to hold named dependencies
+ class DependencyGraph
+ include Enumerable
+
+ # Enumerates through the vertices of the graph.
+ # @return [Array<Vertex>] The graph's vertices.
+ def each
+ return vertices.values.each unless block_given?
+ vertices.values.each { |v| yield v }
+ end
+
+ include Gem::TSort
+
+ # @!visibility private
+ alias tsort_each_node each
+
+ # @!visibility private
+ def tsort_each_child(vertex, &block)
+ vertex.successors.each(&block)
+ end
+
+ # Topologically sorts the given vertices.
+ # @param [Enumerable<Vertex>] vertices the vertices to be sorted, which must
+ # all belong to the same graph.
+ # @return [Array<Vertex>] The sorted vertices.
+ def self.tsort(vertices)
+ Gem::TSort.tsort(
+ lambda { |b| vertices.each(&b) },
+ lambda { |v, &b| (v.successors & vertices).each(&b) }
+ )
+ end
+
+ # A directed edge of a {DependencyGraph}
+ # @attr [Vertex] origin The origin of the directed edge
+ # @attr [Vertex] destination The destination of the directed edge
+ # @attr [Object] requirement The requirement the directed edge represents
+ Edge = Struct.new(:origin, :destination, :requirement)
+
+ # @return [{String => Vertex}] the vertices of the dependency graph, keyed
+ # by {Vertex#name}
+ attr_reader :vertices
+
+ # @return [Log] the op log for this graph
+ attr_reader :log
+
+ # Initializes an empty dependency graph
+ def initialize
+ @vertices = {}
+ @log = Log.new
+ end
+
+ # Tags the current state of the dependency as the given tag
+ # @param [Object] tag an opaque tag for the current state of the graph
+ # @return [Void]
+ def tag(tag)
+ log.tag(self, tag)
+ end
+
+ # Rewinds the graph to the state tagged as `tag`
+ # @param [Object] tag the tag to rewind to
+ # @return [Void]
+ def rewind_to(tag)
+ log.rewind_to(self, tag)
+ end
+
+ # Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices}
+ # are properly copied.
+ # @param [DependencyGraph] other the graph to copy.
+ def initialize_copy(other)
+ super
+ @vertices = {}
+ @log = other.log.dup
+ traverse = lambda do |new_v, old_v|
+ return if new_v.outgoing_edges.size == old_v.outgoing_edges.size
+ old_v.outgoing_edges.each do |edge|
+ destination = add_vertex(edge.destination.name, edge.destination.payload)
+ add_edge_no_circular(new_v, destination, edge.requirement)
+ traverse.call(destination, edge.destination)
+ end
+ end
+ other.vertices.each do |name, vertex|
+ new_vertex = add_vertex(name, vertex.payload, vertex.root?)
+ new_vertex.explicit_requirements.replace(vertex.explicit_requirements)
+ traverse.call(new_vertex, vertex)
+ end
+ end
+
+ # @return [String] a string suitable for debugging
+ def inspect
+ "#{self.class}:#{vertices.values.inspect}"
+ end
+
+ # @param [Hash] options options for dot output.
+ # @return [String] Returns a dot format representation of the graph
+ def to_dot(options = {})
+ edge_label = options.delete(:edge_label)
+ raise ArgumentError, "Unknown options: #{options.keys}" unless options.empty?
+
+ dot_vertices = []
+ dot_edges = []
+ vertices.each do |n, v|
+ dot_vertices << " #{n} [label=\"{#{n}|#{v.payload}}\"]"
+ v.outgoing_edges.each do |e|
+ label = edge_label ? edge_label.call(e) : e.requirement
+ dot_edges << " #{e.origin.name} -> #{e.destination.name} [label=#{label.to_s.dump}]"
+ end
+ end
+
+ dot_vertices.uniq!
+ dot_vertices.sort!
+ dot_edges.uniq!
+ dot_edges.sort!
+
+ dot = dot_vertices.unshift('digraph G {').push('') + dot_edges.push('}')
+ dot.join("\n")
+ end
+
+ # @param [DependencyGraph] other
+ # @return [Boolean] whether the two dependency graphs are equal, determined
+ # by a recursive traversal of each {#root_vertices} and its
+ # {Vertex#successors}
+ def ==(other)
+ return false unless other
+ return true if equal?(other)
+ vertices.each do |name, vertex|
+ other_vertex = other.vertex_named(name)
+ return false unless other_vertex
+ return false unless vertex.payload == other_vertex.payload
+ return false unless other_vertex.successors.to_set == vertex.successors.to_set
+ end
+ end
+
+ # @param [String] name
+ # @param [Object] payload
+ # @param [Array<String>] parent_names
+ # @param [Object] requirement the requirement that is requiring the child
+ # @return [void]
+ def add_child_vertex(name, payload, parent_names, requirement)
+ root = !parent_names.delete(nil) { true }
+ vertex = add_vertex(name, payload, root)
+ vertex.explicit_requirements << requirement if root
+ parent_names.each do |parent_name|
+ parent_vertex = vertex_named(parent_name)
+ add_edge(parent_vertex, vertex, requirement)
+ end
+ vertex
+ end
+
+ # Adds a vertex with the given name, or updates the existing one.
+ # @param [String] name
+ # @param [Object] payload
+ # @return [Vertex] the vertex that was added to `self`
+ def add_vertex(name, payload, root = false)
+ log.add_vertex(self, name, payload, root)
+ end
+
+ # Detaches the {#vertex_named} `name` {Vertex} from the graph, recursively
+ # removing any non-root vertices that were orphaned in the process
+ # @param [String] name
+ # @return [Array<Vertex>] the vertices which have been detached
+ def detach_vertex_named(name)
+ log.detach_vertex_named(self, name)
+ end
+
+ # @param [String] name
+ # @return [Vertex,nil] the vertex with the given name
+ def vertex_named(name)
+ vertices[name]
+ end
+
+ # @param [String] name
+ # @return [Vertex,nil] the root vertex with the given name
+ def root_vertex_named(name)
+ vertex = vertex_named(name)
+ vertex if vertex && vertex.root?
+ end
+
+ # Adds a new {Edge} to the dependency graph
+ # @param [Vertex] origin
+ # @param [Vertex] destination
+ # @param [Object] requirement the requirement that this edge represents
+ # @return [Edge] the added edge
+ def add_edge(origin, destination, requirement)
+ if destination.path_to?(origin)
+ raise CircularDependencyError.new(path(destination, origin))
+ end
+ add_edge_no_circular(origin, destination, requirement)
+ end
+
+ # Deletes an {Edge} from the dependency graph
+ # @param [Edge] edge
+ # @return [Void]
+ def delete_edge(edge)
+ log.delete_edge(self, edge.origin.name, edge.destination.name, edge.requirement)
+ end
+
+ # Sets the payload of the vertex with the given name
+ # @param [String] name the name of the vertex
+ # @param [Object] payload the payload
+ # @return [Void]
+ def set_payload(name, payload)
+ log.set_payload(self, name, payload)
+ end
+
+ private
+
+ # Adds a new {Edge} to the dependency graph without checking for
+ # circularity.
+ # @param (see #add_edge)
+ # @return (see #add_edge)
+ def add_edge_no_circular(origin, destination, requirement)
+ log.add_edge_no_circular(self, origin.name, destination.name, requirement)
+ end
+
+ # Returns the path between two vertices
+ # @raise [ArgumentError] if there is no path between the vertices
+ # @param [Vertex] from
+ # @param [Vertex] to
+ # @return [Array<Vertex>] the shortest path from `from` to `to`
+ def path(from, to)
+ distances = Hash.new(vertices.size + 1)
+ distances[from.name] = 0
+ predecessors = {}
+ each do |vertex|
+ vertex.successors.each do |successor|
+ if distances[successor.name] > distances[vertex.name] + 1
+ distances[successor.name] = distances[vertex.name] + 1
+ predecessors[successor] = vertex
+ end
+ end
+ end
+
+ path = [to]
+ while before = predecessors[to]
+ path << before
+ to = before
+ break if to == from
+ end
+
+ unless path.last.equal?(from)
+ raise ArgumentError, "There is no path from #{from.name} to #{to.name}"
+ end
+
+ path.reverse
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb
new file mode 100644
index 0000000000..cc140031b3
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # An action that modifies a {DependencyGraph} that is reversible.
+ # @abstract
+ class Action
+ # rubocop:disable Lint/UnusedMethodArgument
+
+ # @return [Symbol] The name of the action.
+ def self.action_name
+ raise 'Abstract'
+ end
+
+ # Performs the action on the given graph.
+ # @param [DependencyGraph] graph the graph to perform the action on.
+ # @return [Void]
+ def up(graph)
+ raise 'Abstract'
+ end
+
+ # Reverses the action on the given graph.
+ # @param [DependencyGraph] graph the graph to reverse the action on.
+ # @return [Void]
+ def down(graph)
+ raise 'Abstract'
+ end
+
+ # @return [Action,Nil] The previous action
+ attr_accessor :previous
+
+ # @return [Action,Nil] The next action
+ attr_accessor :next
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb
new file mode 100644
index 0000000000..5570483253
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require_relative 'action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # (see DependencyGraph#add_edge_no_circular)
+ class AddEdgeNoCircular < Action
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :add_vertex
+ end
+
+ # (see Action#up)
+ def up(graph)
+ edge = make_edge(graph)
+ edge.origin.outgoing_edges << edge
+ edge.destination.incoming_edges << edge
+ edge
+ end
+
+ # (see Action#down)
+ def down(graph)
+ edge = make_edge(graph)
+ delete_first(edge.origin.outgoing_edges, edge)
+ delete_first(edge.destination.incoming_edges, edge)
+ end
+
+ # @!group AddEdgeNoCircular
+
+ # @return [String] the name of the origin of the edge
+ attr_reader :origin
+
+ # @return [String] the name of the destination of the edge
+ attr_reader :destination
+
+ # @return [Object] the requirement that the edge represents
+ attr_reader :requirement
+
+ # @param [DependencyGraph] graph the graph to find vertices from
+ # @return [Edge] The edge this action adds
+ def make_edge(graph)
+ Edge.new(graph.vertex_named(origin), graph.vertex_named(destination), requirement)
+ end
+
+ # Initialize an action to add an edge to a dependency graph
+ # @param [String] origin the name of the origin of the edge
+ # @param [String] destination the name of the destination of the edge
+ # @param [Object] requirement the requirement that the edge represents
+ def initialize(origin, destination, requirement)
+ @origin = origin
+ @destination = destination
+ @requirement = requirement
+ end
+
+ private
+
+ def delete_first(array, item)
+ return unless index = array.index(item)
+ array.delete_at(index)
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb
new file mode 100644
index 0000000000..f1411d5efa
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require_relative 'action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # (see DependencyGraph#add_vertex)
+ class AddVertex < Action # :nodoc:
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :add_vertex
+ end
+
+ # (see Action#up)
+ def up(graph)
+ if existing = graph.vertices[name]
+ @existing_payload = existing.payload
+ @existing_root = existing.root
+ end
+ vertex = existing || Vertex.new(name, payload)
+ graph.vertices[vertex.name] = vertex
+ vertex.payload ||= payload
+ vertex.root ||= root
+ vertex
+ end
+
+ # (see Action#down)
+ def down(graph)
+ if defined?(@existing_payload)
+ vertex = graph.vertices[name]
+ vertex.payload = @existing_payload
+ vertex.root = @existing_root
+ else
+ graph.vertices.delete(name)
+ end
+ end
+
+ # @!group AddVertex
+
+ # @return [String] the name of the vertex
+ attr_reader :name
+
+ # @return [Object] the payload for the vertex
+ attr_reader :payload
+
+ # @return [Boolean] whether the vertex is root or not
+ attr_reader :root
+
+ # Initialize an action to add a vertex to a dependency graph
+ # @param [String] name the name of the vertex
+ # @param [Object] payload the payload for the vertex
+ # @param [Boolean] root whether the vertex is root or not
+ def initialize(name, payload, root)
+ @name = name
+ @payload = payload
+ @root = root
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/delete_edge.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/delete_edge.rb
new file mode 100644
index 0000000000..3b48d77a50
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/delete_edge.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require_relative 'action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # (see DependencyGraph#delete_edge)
+ class DeleteEdge < Action
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :delete_edge
+ end
+
+ # (see Action#up)
+ def up(graph)
+ edge = make_edge(graph)
+ edge.origin.outgoing_edges.delete(edge)
+ edge.destination.incoming_edges.delete(edge)
+ end
+
+ # (see Action#down)
+ def down(graph)
+ edge = make_edge(graph)
+ edge.origin.outgoing_edges << edge
+ edge.destination.incoming_edges << edge
+ edge
+ end
+
+ # @!group DeleteEdge
+
+ # @return [String] the name of the origin of the edge
+ attr_reader :origin_name
+
+ # @return [String] the name of the destination of the edge
+ attr_reader :destination_name
+
+ # @return [Object] the requirement that the edge represents
+ attr_reader :requirement
+
+ # @param [DependencyGraph] graph the graph to find vertices from
+ # @return [Edge] The edge this action adds
+ def make_edge(graph)
+ Edge.new(
+ graph.vertex_named(origin_name),
+ graph.vertex_named(destination_name),
+ requirement
+ )
+ end
+
+ # Initialize an action to add an edge to a dependency graph
+ # @param [String] origin_name the name of the origin of the edge
+ # @param [String] destination_name the name of the destination of the edge
+ # @param [Object] requirement the requirement that the edge represents
+ def initialize(origin_name, destination_name, requirement)
+ @origin_name = origin_name
+ @destination_name = destination_name
+ @requirement = requirement
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb
new file mode 100644
index 0000000000..92f60d5be8
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require_relative 'action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # @see DependencyGraph#detach_vertex_named
+ class DetachVertexNamed < Action
+ # @!group Action
+
+ # (see Action#name)
+ def self.action_name
+ :add_vertex
+ end
+
+ # (see Action#up)
+ def up(graph)
+ return [] unless @vertex = graph.vertices.delete(name)
+
+ removed_vertices = [@vertex]
+ @vertex.outgoing_edges.each do |e|
+ v = e.destination
+ v.incoming_edges.delete(e)
+ if !v.root? && v.incoming_edges.empty?
+ removed_vertices.concat graph.detach_vertex_named(v.name)
+ end
+ end
+
+ @vertex.incoming_edges.each do |e|
+ v = e.origin
+ v.outgoing_edges.delete(e)
+ end
+
+ removed_vertices
+ end
+
+ # (see Action#down)
+ def down(graph)
+ return unless @vertex
+ graph.vertices[@vertex.name] = @vertex
+ @vertex.outgoing_edges.each do |e|
+ e.destination.incoming_edges << e
+ end
+ @vertex.incoming_edges.each do |e|
+ e.origin.outgoing_edges << e
+ end
+ end
+
+ # @!group DetachVertexNamed
+
+ # @return [String] the name of the vertex to detach
+ attr_reader :name
+
+ # Initialize an action to detach a vertex from a dependency graph
+ # @param [String] name the name of the vertex to detach
+ def initialize(name)
+ @name = name
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb
new file mode 100644
index 0000000000..7aeb8847ec
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb
@@ -0,0 +1,126 @@
+# frozen_string_literal: true
+
+require_relative 'add_edge_no_circular'
+require_relative 'add_vertex'
+require_relative 'delete_edge'
+require_relative 'detach_vertex_named'
+require_relative 'set_payload'
+require_relative 'tag'
+
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # A log for dependency graph actions
+ class Log
+ # Initializes an empty log
+ def initialize
+ @current_action = @first_action = nil
+ end
+
+ # @!macro [new] action
+ # {include:DependencyGraph#$0}
+ # @param [Graph] graph the graph to perform the action on
+ # @param (see DependencyGraph#$0)
+ # @return (see DependencyGraph#$0)
+
+ # @macro action
+ def tag(graph, tag)
+ push_action(graph, Tag.new(tag))
+ end
+
+ # @macro action
+ def add_vertex(graph, name, payload, root)
+ push_action(graph, AddVertex.new(name, payload, root))
+ end
+
+ # @macro action
+ def detach_vertex_named(graph, name)
+ push_action(graph, DetachVertexNamed.new(name))
+ end
+
+ # @macro action
+ def add_edge_no_circular(graph, origin, destination, requirement)
+ push_action(graph, AddEdgeNoCircular.new(origin, destination, requirement))
+ end
+
+ # {include:DependencyGraph#delete_edge}
+ # @param [Graph] graph the graph to perform the action on
+ # @param [String] origin_name
+ # @param [String] destination_name
+ # @param [Object] requirement
+ # @return (see DependencyGraph#delete_edge)
+ def delete_edge(graph, origin_name, destination_name, requirement)
+ push_action(graph, DeleteEdge.new(origin_name, destination_name, requirement))
+ end
+
+ # @macro action
+ def set_payload(graph, name, payload)
+ push_action(graph, SetPayload.new(name, payload))
+ end
+
+ # Pops the most recent action from the log and undoes the action
+ # @param [DependencyGraph] graph
+ # @return [Action] the action that was popped off the log
+ def pop!(graph)
+ return unless action = @current_action
+ unless @current_action = action.previous
+ @first_action = nil
+ end
+ action.down(graph)
+ action
+ end
+
+ extend Enumerable
+
+ # @!visibility private
+ # Enumerates each action in the log
+ # @yield [Action]
+ def each
+ return enum_for unless block_given?
+ action = @first_action
+ loop do
+ break unless action
+ yield action
+ action = action.next
+ end
+ self
+ end
+
+ # @!visibility private
+ # Enumerates each action in the log in reverse order
+ # @yield [Action]
+ def reverse_each
+ return enum_for(:reverse_each) unless block_given?
+ action = @current_action
+ loop do
+ break unless action
+ yield action
+ action = action.previous
+ end
+ self
+ end
+
+ # @macro action
+ def rewind_to(graph, tag)
+ loop do
+ action = pop!(graph)
+ raise "No tag #{tag.inspect} found" unless action
+ break if action.class.action_name == :tag && action.tag == tag
+ end
+ end
+
+ private
+
+ # Adds the given action to the log, running the action
+ # @param [DependencyGraph] graph
+ # @param [Action] action
+ # @return The value returned by `action.up`
+ def push_action(graph, action)
+ action.previous = @current_action
+ @current_action.next = action if @current_action
+ @current_action = action
+ @first_action ||= action
+ action.up(graph)
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb
new file mode 100644
index 0000000000..726292a2c3
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require_relative 'action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # @see DependencyGraph#set_payload
+ class SetPayload < Action # :nodoc:
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :set_payload
+ end
+
+ # (see Action#up)
+ def up(graph)
+ vertex = graph.vertex_named(name)
+ @old_payload = vertex.payload
+ vertex.payload = payload
+ end
+
+ # (see Action#down)
+ def down(graph)
+ graph.vertex_named(name).payload = @old_payload
+ end
+
+ # @!group SetPayload
+
+ # @return [String] the name of the vertex
+ attr_reader :name
+
+ # @return [Object] the payload for the vertex
+ attr_reader :payload
+
+ # Initialize an action to add set the payload for a vertex in a dependency
+ # graph
+ # @param [String] name the name of the vertex
+ # @param [Object] payload the payload for the vertex
+ def initialize(name, payload)
+ @name = name
+ @payload = payload
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb
new file mode 100644
index 0000000000..bfe6fd31f8
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require_relative 'action'
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # @!visibility private
+ # @see DependencyGraph#tag
+ class Tag < Action
+ # @!group Action
+
+ # (see Action.action_name)
+ def self.action_name
+ :tag
+ end
+
+ # (see Action#up)
+ def up(graph)
+ end
+
+ # (see Action#down)
+ def down(graph)
+ end
+
+ # @!group Tag
+
+ # @return [Object] An opaque tag
+ attr_reader :tag
+
+ # Initialize an action to tag a state of a dependency graph
+ # @param [Object] tag an opaque tag
+ def initialize(tag)
+ @tag = tag
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb
new file mode 100644
index 0000000000..77114951b2
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb
@@ -0,0 +1,164 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ class DependencyGraph
+ # A vertex in a {DependencyGraph} that encapsulates a {#name} and a
+ # {#payload}
+ class Vertex
+ # @return [String] the name of the vertex
+ attr_accessor :name
+
+ # @return [Object] the payload the vertex holds
+ attr_accessor :payload
+
+ # @return [Array<Object>] the explicit requirements that required
+ # this vertex
+ attr_reader :explicit_requirements
+
+ # @return [Boolean] whether the vertex is considered a root vertex
+ attr_accessor :root
+ alias root? root
+
+ # Initializes a vertex with the given name and payload.
+ # @param [String] name see {#name}
+ # @param [Object] payload see {#payload}
+ def initialize(name, payload)
+ @name = name.frozen? ? name : name.dup.freeze
+ @payload = payload
+ @explicit_requirements = []
+ @outgoing_edges = []
+ @incoming_edges = []
+ end
+
+ # @return [Array<Object>] all of the requirements that required
+ # this vertex
+ def requirements
+ (incoming_edges.map(&:requirement) + explicit_requirements).uniq
+ end
+
+ # @return [Array<Edge>] the edges of {#graph} that have `self` as their
+ # {Edge#origin}
+ attr_accessor :outgoing_edges
+
+ # @return [Array<Edge>] the edges of {#graph} that have `self` as their
+ # {Edge#destination}
+ attr_accessor :incoming_edges
+
+ # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
+ # `self` as their {Edge#destination}
+ def predecessors
+ incoming_edges.map(&:origin)
+ end
+
+ # @return [Set<Vertex>] the vertices of {#graph} where `self` is a
+ # {#descendent?}
+ def recursive_predecessors
+ _recursive_predecessors
+ end
+
+ # @param [Set<Vertex>] vertices the set to add the predecessors to
+ # @return [Set<Vertex>] the vertices of {#graph} where `self` is a
+ # {#descendent?}
+ def _recursive_predecessors(vertices = new_vertex_set)
+ incoming_edges.each do |edge|
+ vertex = edge.origin
+ next unless vertices.add?(vertex)
+ vertex._recursive_predecessors(vertices)
+ end
+
+ vertices
+ end
+ protected :_recursive_predecessors
+
+ # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
+ # `self` as their {Edge#origin}
+ def successors
+ outgoing_edges.map(&:destination)
+ end
+
+ # @return [Set<Vertex>] the vertices of {#graph} where `self` is an
+ # {#ancestor?}
+ def recursive_successors
+ _recursive_successors
+ end
+
+ # @param [Set<Vertex>] vertices the set to add the successors to
+ # @return [Set<Vertex>] the vertices of {#graph} where `self` is an
+ # {#ancestor?}
+ def _recursive_successors(vertices = new_vertex_set)
+ outgoing_edges.each do |edge|
+ vertex = edge.destination
+ next unless vertices.add?(vertex)
+ vertex._recursive_successors(vertices)
+ end
+
+ vertices
+ end
+ protected :_recursive_successors
+
+ # @return [String] a string suitable for debugging
+ def inspect
+ "#{self.class}:#{name}(#{payload.inspect})"
+ end
+
+ # @return [Boolean] whether the two vertices are equal, determined
+ # by a recursive traversal of each {Vertex#successors}
+ def ==(other)
+ return true if equal?(other)
+ shallow_eql?(other) &&
+ successors.to_set == other.successors.to_set
+ end
+
+ # @param [Vertex] other the other vertex to compare to
+ # @return [Boolean] whether the two vertices are equal, determined
+ # solely by {#name} and {#payload} equality
+ def shallow_eql?(other)
+ return true if equal?(other)
+ other &&
+ name == other.name &&
+ payload == other.payload
+ end
+
+ alias eql? ==
+
+ # @return [Fixnum] a hash for the vertex based upon its {#name}
+ def hash
+ name.hash
+ end
+
+ # Is there a path from `self` to `other` following edges in the
+ # dependency graph?
+ # @return whether there is a path following edges within this {#graph}
+ def path_to?(other)
+ _path_to?(other)
+ end
+
+ alias descendent? path_to?
+
+ # @param [Vertex] other the vertex to check if there's a path to
+ # @param [Set<Vertex>] visited the vertices of {#graph} that have been visited
+ # @return [Boolean] whether there is a path to `other` from `self`
+ def _path_to?(other, visited = new_vertex_set)
+ return false unless visited.add?(self)
+ return true if equal?(other)
+ successors.any? { |v| v._path_to?(other, visited) }
+ end
+ protected :_path_to?
+
+ # Is there a path from `other` to `self` following edges in the
+ # dependency graph?
+ # @return whether there is a path following edges within this {#graph}
+ def ancestor?(other)
+ other.path_to?(self)
+ end
+
+ alias is_reachable_from? ancestor?
+
+ def new_vertex_set
+ require 'set'
+ Set.new
+ end
+ private :new_vertex_set
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb
new file mode 100644
index 0000000000..4289902828
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb
@@ -0,0 +1,149 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ # An error that occurred during the resolution process
+ class ResolverError < StandardError; end
+
+ # An error caused by searching for a dependency that is completely unknown,
+ # i.e. has no versions available whatsoever.
+ class NoSuchDependencyError < ResolverError
+ # @return [Object] the dependency that could not be found
+ attr_accessor :dependency
+
+ # @return [Array<Object>] the specifications that depended upon {#dependency}
+ attr_accessor :required_by
+
+ # Initializes a new error with the given missing dependency.
+ # @param [Object] dependency @see {#dependency}
+ # @param [Array<Object>] required_by @see {#required_by}
+ def initialize(dependency, required_by = [])
+ @dependency = dependency
+ @required_by = required_by.uniq
+ super()
+ end
+
+ # The error message for the missing dependency, including the specifications
+ # that had this dependency.
+ def message
+ sources = required_by.map { |r| "`#{r}`" }.join(' and ')
+ message = "Unable to find a specification for `#{dependency}`"
+ message += " depended upon by #{sources}" unless sources.empty?
+ message
+ end
+ end
+
+ # An error caused by attempting to fulfil a dependency that was circular
+ #
+ # @note This exception will be thrown if and only if a {Vertex} is added to a
+ # {DependencyGraph} that has a {DependencyGraph::Vertex#path_to?} an
+ # existing {DependencyGraph::Vertex}
+ class CircularDependencyError < ResolverError
+ # [Set<Object>] the dependencies responsible for causing the error
+ attr_reader :dependencies
+
+ # Initializes a new error with the given circular vertices.
+ # @param [Array<DependencyGraph::Vertex>] vertices the vertices in the dependency
+ # that caused the error
+ def initialize(vertices)
+ super "There is a circular dependency between #{vertices.map(&:name).join(' and ')}"
+ @dependencies = vertices.map { |vertex| vertex.payload.possibilities.last }.to_set
+ end
+ end
+
+ # An error caused by conflicts in version
+ class VersionConflict < ResolverError
+ # @return [{String => Resolution::Conflict}] the conflicts that caused
+ # resolution to fail
+ attr_reader :conflicts
+
+ # @return [SpecificationProvider] the specification provider used during
+ # resolution
+ attr_reader :specification_provider
+
+ # Initializes a new error with the given version conflicts.
+ # @param [{String => Resolution::Conflict}] conflicts see {#conflicts}
+ # @param [SpecificationProvider] specification_provider see {#specification_provider}
+ def initialize(conflicts, specification_provider)
+ pairs = []
+ conflicts.values.flat_map(&:requirements).each do |conflicting|
+ conflicting.each do |source, conflict_requirements|
+ conflict_requirements.each do |c|
+ pairs << [c, source]
+ end
+ end
+ end
+
+ super "Unable to satisfy the following requirements:\n\n" \
+ "#{pairs.map { |r, d| "- `#{r}` required by `#{d}`" }.join("\n")}"
+
+ @conflicts = conflicts
+ @specification_provider = specification_provider
+ end
+
+ require_relative 'delegates/specification_provider'
+ include Delegates::SpecificationProvider
+
+ # @return [String] An error message that includes requirement trees,
+ # which is much more detailed & customizable than the default message
+ # @param [Hash] opts the options to create a message with.
+ # @option opts [String] :solver_name The user-facing name of the solver
+ # @option opts [String] :possibility_type The generic name of a possibility
+ # @option opts [Proc] :reduce_trees A proc that reduced the list of requirement trees
+ # @option opts [Proc] :printable_requirement A proc that pretty-prints requirements
+ # @option opts [Proc] :additional_message_for_conflict A proc that appends additional
+ # messages for each conflict
+ # @option opts [Proc] :version_for_spec A proc that returns the version number for a
+ # possibility
+ def message_with_trees(opts = {})
+ solver_name = opts.delete(:solver_name) { self.class.name.split('::').first }
+ possibility_type = opts.delete(:possibility_type) { 'possibility named' }
+ reduce_trees = opts.delete(:reduce_trees) { proc { |trees| trees.uniq.sort_by(&:to_s) } }
+ printable_requirement = opts.delete(:printable_requirement) { proc { |req| req.to_s } }
+ additional_message_for_conflict = opts.delete(:additional_message_for_conflict) { proc {} }
+ version_for_spec = opts.delete(:version_for_spec) { proc(&:to_s) }
+ incompatible_version_message_for_conflict = opts.delete(:incompatible_version_message_for_conflict) do
+ proc do |name, _conflict|
+ %(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":)
+ end
+ end
+
+ full_message_for_conflict = opts.delete(:full_message_for_conflict) do
+ proc do |name, conflict|
+ o = "\n".dup << incompatible_version_message_for_conflict.call(name, conflict) << "\n"
+ if conflict.locked_requirement
+ o << %( In snapshot (#{name_for_locking_dependency_source}):\n)
+ o << %( #{printable_requirement.call(conflict.locked_requirement)}\n)
+ o << %(\n)
+ end
+ o << %( In #{name_for_explicit_dependency_source}:\n)
+ trees = reduce_trees.call(conflict.requirement_trees)
+
+ o << trees.map do |tree|
+ t = ''.dup
+ depth = 2
+ tree.each do |req|
+ t << ' ' * depth << printable_requirement.call(req)
+ unless tree.last == req
+ if spec = conflict.activated_by_name[name_for(req)]
+ t << %( was resolved to #{version_for_spec.call(spec)}, which)
+ end
+ t << %( depends on)
+ end
+ t << %(\n)
+ depth += 1
+ end
+ t
+ end.join("\n")
+
+ additional_message_for_conflict.call(o, name, conflict)
+
+ o
+ end
+ end
+
+ conflicts.sort.reduce(''.dup) do |o, (name, conflict)|
+ o << full_message_for_conflict.call(name, conflict)
+ end.strip
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb
new file mode 100644
index 0000000000..86c249c404
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ # The version of Gem::Resolver::Molinillo.
+ VERSION = '0.8.0'.freeze
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb
new file mode 100644
index 0000000000..1067bf7439
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ # Provides information about specifications and dependencies to the resolver,
+ # allowing the {Resolver} class to remain generic while still providing power
+ # and flexibility.
+ #
+ # This module contains the methods that users of Gem::Resolver::Molinillo must to implement,
+ # using knowledge of their own model classes.
+ module SpecificationProvider
+ # Search for the specifications that match the given dependency.
+ # The specifications in the returned array will be considered in reverse
+ # order, so the latest version ought to be last.
+ # @note This method should be 'pure', i.e. the return value should depend
+ # only on the `dependency` parameter.
+ #
+ # @param [Object] dependency
+ # @return [Array<Object>] the specifications that satisfy the given
+ # `dependency`.
+ def search_for(dependency)
+ []
+ end
+
+ # Returns the dependencies of `specification`.
+ # @note This method should be 'pure', i.e. the return value should depend
+ # only on the `specification` parameter.
+ #
+ # @param [Object] specification
+ # @return [Array<Object>] the dependencies that are required by the given
+ # `specification`.
+ def dependencies_for(specification)
+ []
+ end
+
+ # Determines whether the given `requirement` is satisfied by the given
+ # `spec`, in the context of the current `activated` dependency graph.
+ #
+ # @param [Object] requirement
+ # @param [DependencyGraph] activated the current dependency graph in the
+ # resolution process.
+ # @param [Object] spec
+ # @return [Boolean] whether `requirement` is satisfied by `spec` in the
+ # context of the current `activated` dependency graph.
+ def requirement_satisfied_by?(requirement, activated, spec)
+ true
+ end
+
+ # Determines whether two arrays of dependencies are equal, and thus can be
+ # grouped.
+ #
+ # @param [Array<Object>] dependencies
+ # @param [Array<Object>] other_dependencies
+ # @return [Boolean] whether `dependencies` and `other_dependencies` should
+ # be considered equal.
+ def dependencies_equal?(dependencies, other_dependencies)
+ dependencies == other_dependencies
+ end
+
+ # Returns the name for the given `dependency`.
+ # @note This method should be 'pure', i.e. the return value should depend
+ # only on the `dependency` parameter.
+ #
+ # @param [Object] dependency
+ # @return [String] the name for the given `dependency`.
+ def name_for(dependency)
+ dependency.to_s
+ end
+
+ # @return [String] the name of the source of explicit dependencies, i.e.
+ # those passed to {Resolver#resolve} directly.
+ def name_for_explicit_dependency_source
+ 'user-specified dependency'
+ end
+
+ # @return [String] the name of the source of 'locked' dependencies, i.e.
+ # those passed to {Resolver#resolve} directly as the `base`
+ def name_for_locking_dependency_source
+ 'Lockfile'
+ end
+
+ # Sort dependencies so that the ones that are easiest to resolve are first.
+ # Easiest to resolve is (usually) defined by:
+ # 1) Is this dependency already activated?
+ # 2) How relaxed are the requirements?
+ # 3) Are there any conflicts for this dependency?
+ # 4) How many possibilities are there to satisfy this dependency?
+ #
+ # @param [Array<Object>] dependencies
+ # @param [DependencyGraph] activated the current dependency graph in the
+ # resolution process.
+ # @param [{String => Array<Conflict>}] conflicts
+ # @return [Array<Object>] a sorted copy of `dependencies`.
+ def sort_dependencies(dependencies, activated, conflicts)
+ dependencies.sort_by do |dependency|
+ name = name_for(dependency)
+ [
+ activated.vertex_named(name).payload ? 0 : 1,
+ conflicts[name] ? 0 : 1,
+ ]
+ end
+ end
+
+ # Returns whether this dependency, which has no possible matching
+ # specifications, can safely be ignored.
+ #
+ # @param [Object] dependency
+ # @return [Boolean] whether this dependency can safely be skipped.
+ def allow_missing?(dependency)
+ false
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb
new file mode 100644
index 0000000000..a810fd519c
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ # Conveys information about the resolution process to a user.
+ module UI
+ # The {IO} object that should be used to print output. `STDOUT`, by default.
+ #
+ # @return [IO]
+ def output
+ STDOUT
+ end
+
+ # Called roughly every {#progress_rate}, this method should convey progress
+ # to the user.
+ #
+ # @return [void]
+ def indicate_progress
+ output.print '.' unless debug?
+ end
+
+ # How often progress should be conveyed to the user via
+ # {#indicate_progress}, in seconds. A third of a second, by default.
+ #
+ # @return [Float]
+ def progress_rate
+ 0.33
+ end
+
+ # Called before resolution begins.
+ #
+ # @return [void]
+ def before_resolution
+ output.print 'Resolving dependencies...'
+ end
+
+ # Called after resolution ends (either successfully or with an error).
+ # By default, prints a newline.
+ #
+ # @return [void]
+ def after_resolution
+ output.puts
+ end
+
+ # Conveys debug information to the user.
+ #
+ # @param [Integer] depth the current depth of the resolution process.
+ # @return [void]
+ def debug(depth = 0)
+ if debug?
+ debug_info = yield
+ debug_info = debug_info.inspect unless debug_info.is_a?(String)
+ debug_info = debug_info.split("\n").map { |s| ":#{depth.to_s.rjust 4}: #{s}" }
+ output.puts debug_info
+ end
+ end
+
+ # Whether or not debug messages should be printed.
+ # By default, whether or not the `MOLINILLO_DEBUG` environment variable is
+ # set.
+ #
+ # @return [Boolean]
+ def debug?
+ return @debug_mode if defined?(@debug_mode)
+ @debug_mode = ENV['MOLINILLO_DEBUG']
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb
new file mode 100644
index 0000000000..8b40e59e42
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb
@@ -0,0 +1,839 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ class Resolver
+ # A specific resolution from a given {Resolver}
+ class Resolution
+ # A conflict that the resolution process encountered
+ # @attr [Object] requirement the requirement that immediately led to the conflict
+ # @attr [{String,Nil=>[Object]}] requirements the requirements that caused the conflict
+ # @attr [Object, nil] existing the existing spec that was in conflict with
+ # the {#possibility}
+ # @attr [Object] possibility_set the set of specs that was unable to be
+ # activated due to a conflict.
+ # @attr [Object] locked_requirement the relevant locking requirement.
+ # @attr [Array<Array<Object>>] requirement_trees the different requirement
+ # trees that led to every requirement for the conflicting name.
+ # @attr [{String=>Object}] activated_by_name the already-activated specs.
+ # @attr [Object] underlying_error an error that has occurred during resolution, and
+ # will be raised at the end of it if no resolution is found.
+ Conflict = Struct.new(
+ :requirement,
+ :requirements,
+ :existing,
+ :possibility_set,
+ :locked_requirement,
+ :requirement_trees,
+ :activated_by_name,
+ :underlying_error
+ )
+
+ class Conflict
+ # @return [Object] a spec that was unable to be activated due to a conflict
+ def possibility
+ possibility_set && possibility_set.latest_version
+ end
+ end
+
+ # A collection of possibility states that share the same dependencies
+ # @attr [Array] dependencies the dependencies for this set of possibilities
+ # @attr [Array] possibilities the possibilities
+ PossibilitySet = Struct.new(:dependencies, :possibilities)
+
+ class PossibilitySet
+ # String representation of the possibility set, for debugging
+ def to_s
+ "[#{possibilities.join(', ')}]"
+ end
+
+ # @return [Object] most up-to-date dependency in the possibility set
+ def latest_version
+ possibilities.last
+ end
+ end
+
+ # Details of the state to unwind to when a conflict occurs, and the cause of the unwind
+ # @attr [Integer] state_index the index of the state to unwind to
+ # @attr [Object] state_requirement the requirement of the state we're unwinding to
+ # @attr [Array] requirement_tree for the requirement we're relaxing
+ # @attr [Array] conflicting_requirements the requirements that combined to cause the conflict
+ # @attr [Array] requirement_trees for the conflict
+ # @attr [Array] requirements_unwound_to_instead array of unwind requirements that were chosen over this unwind
+ UnwindDetails = Struct.new(
+ :state_index,
+ :state_requirement,
+ :requirement_tree,
+ :conflicting_requirements,
+ :requirement_trees,
+ :requirements_unwound_to_instead
+ )
+
+ class UnwindDetails
+ include Comparable
+
+ # We compare UnwindDetails when choosing which state to unwind to. If
+ # two options have the same state_index we prefer the one most
+ # removed from a requirement that caused the conflict. Both options
+ # would unwind to the same state, but a `grandparent` option will
+ # filter out fewer of its possibilities after doing so - where a state
+ # is both a `parent` and a `grandparent` to requirements that have
+ # caused a conflict this is the correct behaviour.
+ # @param [UnwindDetail] other UnwindDetail to be compared
+ # @return [Integer] integer specifying ordering
+ def <=>(other)
+ if state_index > other.state_index
+ 1
+ elsif state_index == other.state_index
+ reversed_requirement_tree_index <=> other.reversed_requirement_tree_index
+ else
+ -1
+ end
+ end
+
+ # @return [Integer] index of state requirement in reversed requirement tree
+ # (the conflicting requirement itself will be at position 0)
+ def reversed_requirement_tree_index
+ @reversed_requirement_tree_index ||=
+ if state_requirement
+ requirement_tree.reverse.index(state_requirement)
+ else
+ 999_999
+ end
+ end
+
+ # @return [Boolean] where the requirement of the state we're unwinding
+ # to directly caused the conflict. Note: in this case, it is
+ # impossible for the state we're unwinding to to be a parent of
+ # any of the other conflicting requirements (or we would have
+ # circularity)
+ def unwinding_to_primary_requirement?
+ requirement_tree.last == state_requirement
+ end
+
+ # @return [Array] array of sub-dependencies to avoid when choosing a
+ # new possibility for the state we've unwound to. Only relevant for
+ # non-primary unwinds
+ def sub_dependencies_to_avoid
+ @requirements_to_avoid ||=
+ requirement_trees.map do |tree|
+ index = tree.index(state_requirement)
+ tree[index + 1] if index
+ end.compact
+ end
+
+ # @return [Array] array of all the requirements that led to the need for
+ # this unwind
+ def all_requirements
+ @all_requirements ||= requirement_trees.flatten(1)
+ end
+ end
+
+ # @return [SpecificationProvider] the provider that knows about
+ # dependencies, requirements, specifications, versions, etc.
+ attr_reader :specification_provider
+
+ # @return [UI] the UI that knows how to communicate feedback about the
+ # resolution process back to the user
+ attr_reader :resolver_ui
+
+ # @return [DependencyGraph] the base dependency graph to which
+ # dependencies should be 'locked'
+ attr_reader :base
+
+ # @return [Array] the dependencies that were explicitly required
+ attr_reader :original_requested
+
+ # Initializes a new resolution.
+ # @param [SpecificationProvider] specification_provider
+ # see {#specification_provider}
+ # @param [UI] resolver_ui see {#resolver_ui}
+ # @param [Array] requested see {#original_requested}
+ # @param [DependencyGraph] base see {#base}
+ def initialize(specification_provider, resolver_ui, requested, base)
+ @specification_provider = specification_provider
+ @resolver_ui = resolver_ui
+ @original_requested = requested
+ @base = base
+ @states = []
+ @iteration_counter = 0
+ @parents_of = Hash.new { |h, k| h[k] = [] }
+ end
+
+ # Resolves the {#original_requested} dependencies into a full dependency
+ # graph
+ # @raise [ResolverError] if successful resolution is impossible
+ # @return [DependencyGraph] the dependency graph of successfully resolved
+ # dependencies
+ def resolve
+ start_resolution
+
+ while state
+ break if !state.requirement && state.requirements.empty?
+ indicate_progress
+ if state.respond_to?(:pop_possibility_state) # DependencyState
+ debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" }
+ state.pop_possibility_state.tap do |s|
+ if s
+ states.push(s)
+ activated.tag(s)
+ end
+ end
+ end
+ process_topmost_state
+ end
+
+ resolve_activated_specs
+ ensure
+ end_resolution
+ end
+
+ # @return [Integer] the number of resolver iterations in between calls to
+ # {#resolver_ui}'s {UI#indicate_progress} method
+ attr_accessor :iteration_rate
+ private :iteration_rate
+
+ # @return [Time] the time at which resolution began
+ attr_accessor :started_at
+ private :started_at
+
+ # @return [Array<ResolutionState>] the stack of states for the resolution
+ attr_accessor :states
+ private :states
+
+ private
+
+ # Sets up the resolution process
+ # @return [void]
+ def start_resolution
+ @started_at = Time.now
+
+ push_initial_state
+
+ debug { "Starting resolution (#{@started_at})\nUser-requested dependencies: #{original_requested}" }
+ resolver_ui.before_resolution
+ end
+
+ def resolve_activated_specs
+ activated.vertices.each do |_, vertex|
+ next unless vertex.payload
+
+ latest_version = vertex.payload.possibilities.reverse_each.find do |possibility|
+ vertex.requirements.all? { |req| requirement_satisfied_by?(req, activated, possibility) }
+ end
+
+ activated.set_payload(vertex.name, latest_version)
+ end
+ activated.freeze
+ end
+
+ # Ends the resolution process
+ # @return [void]
+ def end_resolution
+ resolver_ui.after_resolution
+ debug do
+ "Finished resolution (#{@iteration_counter} steps) " \
+ "(Took #{(ended_at = Time.now) - @started_at} seconds) (#{ended_at})"
+ end
+ debug { 'Unactivated: ' + Hash[activated.vertices.reject { |_n, v| v.payload }].keys.join(', ') } if state
+ debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state
+ end
+
+ require_relative 'state'
+ require_relative 'modules/specification_provider'
+
+ require_relative 'delegates/resolution_state'
+ require_relative 'delegates/specification_provider'
+
+ include Gem::Resolver::Molinillo::Delegates::ResolutionState
+ include Gem::Resolver::Molinillo::Delegates::SpecificationProvider
+
+ # Processes the topmost available {RequirementState} on the stack
+ # @return [void]
+ def process_topmost_state
+ if possibility
+ attempt_to_activate
+ else
+ create_conflict
+ unwind_for_conflict
+ end
+ rescue CircularDependencyError => underlying_error
+ create_conflict(underlying_error)
+ unwind_for_conflict
+ end
+
+ # @return [Object] the current possibility that the resolution is trying
+ # to activate
+ def possibility
+ possibilities.last
+ end
+
+ # @return [RequirementState] the current state the resolution is
+ # operating upon
+ def state
+ states.last
+ end
+
+ # Creates and pushes the initial state for the resolution, based upon the
+ # {#requested} dependencies
+ # @return [void]
+ def push_initial_state
+ graph = DependencyGraph.new.tap do |dg|
+ original_requested.each do |requested|
+ vertex = dg.add_vertex(name_for(requested), nil, true)
+ vertex.explicit_requirements << requested
+ end
+ dg.tag(:initial_state)
+ end
+
+ push_state_for_requirements(original_requested, true, graph)
+ end
+
+ # Unwinds the states stack because a conflict has been encountered
+ # @return [void]
+ def unwind_for_conflict
+ details_for_unwind = build_details_for_unwind
+ unwind_options = unused_unwind_options
+ debug(depth) { "Unwinding for conflict: #{requirement} to #{details_for_unwind.state_index / 2}" }
+ conflicts.tap do |c|
+ sliced_states = states.slice!((details_for_unwind.state_index + 1)..-1)
+ raise_error_unless_state(c)
+ activated.rewind_to(sliced_states.first || :initial_state) if sliced_states
+ state.conflicts = c
+ state.unused_unwind_options = unwind_options
+ filter_possibilities_after_unwind(details_for_unwind)
+ index = states.size - 1
+ @parents_of.each { |_, a| a.reject! { |i| i >= index } }
+ state.unused_unwind_options.reject! { |uw| uw.state_index >= index }
+ end
+ end
+
+ # Raises a VersionConflict error, or any underlying error, if there is no
+ # current state
+ # @return [void]
+ def raise_error_unless_state(conflicts)
+ return if state
+
+ error = conflicts.values.map(&:underlying_error).compact.first
+ raise error || VersionConflict.new(conflicts, specification_provider)
+ end
+
+ # @return [UnwindDetails] Details of the nearest index to which we could unwind
+ def build_details_for_unwind
+ # Get the possible unwinds for the current conflict
+ current_conflict = conflicts[name]
+ binding_requirements = binding_requirements_for_conflict(current_conflict)
+ unwind_details = unwind_options_for_requirements(binding_requirements)
+
+ last_detail_for_current_unwind = unwind_details.sort.last
+ current_detail = last_detail_for_current_unwind
+
+ # Look for past conflicts that could be unwound to affect the
+ # requirement tree for the current conflict
+ all_reqs = last_detail_for_current_unwind.all_requirements
+ all_reqs_size = all_reqs.size
+ relevant_unused_unwinds = unused_unwind_options.select do |alternative|
+ diff_reqs = all_reqs - alternative.requirements_unwound_to_instead
+ next if diff_reqs.size == all_reqs_size
+ # Find the highest index unwind whilst looping through
+ current_detail = alternative if alternative > current_detail
+ alternative
+ end
+
+ # Add the current unwind options to the `unused_unwind_options` array.
+ # The "used" option will be filtered out during `unwind_for_conflict`.
+ state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 }
+
+ # Update the requirements_unwound_to_instead on any relevant unused unwinds
+ relevant_unused_unwinds.each do |d|
+ (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
+ end
+ unwind_details.each do |d|
+ (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
+ end
+
+ current_detail
+ end
+
+ # @param [Array<Object>] binding_requirements array of requirements that combine to create a conflict
+ # @return [Array<UnwindDetails>] array of UnwindDetails that have a chance
+ # of resolving the passed requirements
+ def unwind_options_for_requirements(binding_requirements)
+ unwind_details = []
+
+ trees = []
+ binding_requirements.reverse_each do |r|
+ partial_tree = [r]
+ trees << partial_tree
+ unwind_details << UnwindDetails.new(-1, nil, partial_tree, binding_requirements, trees, [])
+
+ # If this requirement has alternative possibilities, check if any would
+ # satisfy the other requirements that created this conflict
+ requirement_state = find_state_for(r)
+ if conflict_fixing_possibilities?(requirement_state, binding_requirements)
+ unwind_details << UnwindDetails.new(
+ states.index(requirement_state),
+ r,
+ partial_tree,
+ binding_requirements,
+ trees,
+ []
+ )
+ end
+
+ # Next, look at the parent of this requirement, and check if the requirement
+ # could have been avoided if an alternative PossibilitySet had been chosen
+ parent_r = parent_of(r)
+ next if parent_r.nil?
+ partial_tree.unshift(parent_r)
+ requirement_state = find_state_for(parent_r)
+ if requirement_state.possibilities.any? { |set| !set.dependencies.include?(r) }
+ unwind_details << UnwindDetails.new(
+ states.index(requirement_state),
+ parent_r,
+ partial_tree,
+ binding_requirements,
+ trees,
+ []
+ )
+ end
+
+ # Finally, look at the grandparent and up of this requirement, looking
+ # for any possibilities that wouldn't create their parent requirement
+ grandparent_r = parent_of(parent_r)
+ until grandparent_r.nil?
+ partial_tree.unshift(grandparent_r)
+ requirement_state = find_state_for(grandparent_r)
+ if requirement_state.possibilities.any? { |set| !set.dependencies.include?(parent_r) }
+ unwind_details << UnwindDetails.new(
+ states.index(requirement_state),
+ grandparent_r,
+ partial_tree,
+ binding_requirements,
+ trees,
+ []
+ )
+ end
+ parent_r = grandparent_r
+ grandparent_r = parent_of(parent_r)
+ end
+ end
+
+ unwind_details
+ end
+
+ # @param [DependencyState] state
+ # @param [Array] binding_requirements array of requirements
+ # @return [Boolean] whether or not the given state has any possibilities
+ # that could satisfy the given requirements
+ def conflict_fixing_possibilities?(state, binding_requirements)
+ return false unless state
+
+ state.possibilities.any? do |possibility_set|
+ possibility_set.possibilities.any? do |poss|
+ possibility_satisfies_requirements?(poss, binding_requirements)
+ end
+ end
+ end
+
+ # Filter's a state's possibilities to remove any that would not fix the
+ # conflict we've just rewound from
+ # @param [UnwindDetails] unwind_details details of the conflict just
+ # unwound from
+ # @return [void]
+ def filter_possibilities_after_unwind(unwind_details)
+ return unless state && !state.possibilities.empty?
+
+ if unwind_details.unwinding_to_primary_requirement?
+ filter_possibilities_for_primary_unwind(unwind_details)
+ else
+ filter_possibilities_for_parent_unwind(unwind_details)
+ end
+ end
+
+ # Filter's a state's possibilities to remove any that would not satisfy
+ # the requirements in the conflict we've just rewound from
+ # @param [UnwindDetails] unwind_details details of the conflict just unwound from
+ # @return [void]
+ def filter_possibilities_for_primary_unwind(unwind_details)
+ unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index }
+ unwinds_to_state << unwind_details
+ unwind_requirement_sets = unwinds_to_state.map(&:conflicting_requirements)
+
+ state.possibilities.reject! do |possibility_set|
+ possibility_set.possibilities.none? do |poss|
+ unwind_requirement_sets.any? do |requirements|
+ possibility_satisfies_requirements?(poss, requirements)
+ end
+ end
+ end
+ end
+
+ # @param [Object] possibility a single possibility
+ # @param [Array] requirements an array of requirements
+ # @return [Boolean] whether the possibility satisfies all of the
+ # given requirements
+ def possibility_satisfies_requirements?(possibility, requirements)
+ name = name_for(possibility)
+
+ activated.tag(:swap)
+ activated.set_payload(name, possibility) if activated.vertex_named(name)
+ satisfied = requirements.all? { |r| requirement_satisfied_by?(r, activated, possibility) }
+ activated.rewind_to(:swap)
+
+ satisfied
+ end
+
+ # Filter's a state's possibilities to remove any that would (eventually)
+ # create a requirement in the conflict we've just rewound from
+ # @param [UnwindDetails] unwind_details details of the conflict just unwound from
+ # @return [void]
+ def filter_possibilities_for_parent_unwind(unwind_details)
+ unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index }
+ unwinds_to_state << unwind_details
+
+ primary_unwinds = unwinds_to_state.select(&:unwinding_to_primary_requirement?).uniq
+ parent_unwinds = unwinds_to_state.uniq - primary_unwinds
+
+ allowed_possibility_sets = primary_unwinds.flat_map do |unwind|
+ states[unwind.state_index].possibilities.select do |possibility_set|
+ possibility_set.possibilities.any? do |poss|
+ possibility_satisfies_requirements?(poss, unwind.conflicting_requirements)
+ end
+ end
+ end
+
+ requirements_to_avoid = parent_unwinds.flat_map(&:sub_dependencies_to_avoid)
+
+ state.possibilities.reject! do |possibility_set|
+ !allowed_possibility_sets.include?(possibility_set) &&
+ (requirements_to_avoid - possibility_set.dependencies).empty?
+ end
+ end
+
+ # @param [Conflict] conflict
+ # @return [Array] minimal array of requirements that would cause the passed
+ # conflict to occur.
+ def binding_requirements_for_conflict(conflict)
+ return [conflict.requirement] if conflict.possibility.nil?
+
+ possible_binding_requirements = conflict.requirements.values.flatten(1).uniq
+
+ # When there's a `CircularDependency` error the conflicting requirement
+ # (the one causing the circular) won't be `conflict.requirement`
+ # (which won't be for the right state, because we won't have created it,
+ # because it's circular).
+ # We need to make sure we have that requirement in the conflict's list,
+ # otherwise we won't be able to unwind properly, so we just return all
+ # the requirements for the conflict.
+ return possible_binding_requirements if conflict.underlying_error
+
+ possibilities = search_for(conflict.requirement)
+
+ # If all the requirements together don't filter out all possibilities,
+ # then the only two requirements we need to consider are the initial one
+ # (where the dependency's version was first chosen) and the last
+ if binding_requirement_in_set?(nil, possible_binding_requirements, possibilities)
+ return [conflict.requirement, requirement_for_existing_name(name_for(conflict.requirement))].compact
+ end
+
+ # Loop through the possible binding requirements, removing each one
+ # that doesn't bind. Use a `reverse_each` as we want the earliest set of
+ # binding requirements, and don't use `reject!` as we wish to refine the
+ # array *on each iteration*.
+ binding_requirements = possible_binding_requirements.dup
+ possible_binding_requirements.reverse_each do |req|
+ next if req == conflict.requirement
+ unless binding_requirement_in_set?(req, binding_requirements, possibilities)
+ binding_requirements -= [req]
+ end
+ end
+
+ binding_requirements
+ end
+
+ # @param [Object] requirement we wish to check
+ # @param [Array] possible_binding_requirements array of requirements
+ # @param [Array] possibilities array of possibilities the requirements will be used to filter
+ # @return [Boolean] whether or not the given requirement is required to filter
+ # out all elements of the array of possibilities.
+ def binding_requirement_in_set?(requirement, possible_binding_requirements, possibilities)
+ possibilities.any? do |poss|
+ possibility_satisfies_requirements?(poss, possible_binding_requirements - [requirement])
+ end
+ end
+
+ # @param [Object] requirement
+ # @return [Object] the requirement that led to `requirement` being added
+ # to the list of requirements.
+ def parent_of(requirement)
+ return unless requirement
+ return unless index = @parents_of[requirement].last
+ return unless parent_state = @states[index]
+ parent_state.requirement
+ end
+
+ # @param [String] name
+ # @return [Object] the requirement that led to a version of a possibility
+ # with the given name being activated.
+ def requirement_for_existing_name(name)
+ return nil unless vertex = activated.vertex_named(name)
+ return nil unless vertex.payload
+ states.find { |s| s.name == name }.requirement
+ end
+
+ # @param [Object] requirement
+ # @return [ResolutionState] the state whose `requirement` is the given
+ # `requirement`.
+ def find_state_for(requirement)
+ return nil unless requirement
+ states.find { |i| requirement == i.requirement }
+ end
+
+ # @param [Object] underlying_error
+ # @return [Conflict] a {Conflict} that reflects the failure to activate
+ # the {#possibility} in conjunction with the current {#state}
+ def create_conflict(underlying_error = nil)
+ vertex = activated.vertex_named(name)
+ locked_requirement = locked_requirement_named(name)
+
+ requirements = {}
+ unless vertex.explicit_requirements.empty?
+ requirements[name_for_explicit_dependency_source] = vertex.explicit_requirements
+ end
+ requirements[name_for_locking_dependency_source] = [locked_requirement] if locked_requirement
+ vertex.incoming_edges.each do |edge|
+ (requirements[edge.origin.payload.latest_version] ||= []).unshift(edge.requirement)
+ end
+
+ activated_by_name = {}
+ activated.each { |v| activated_by_name[v.name] = v.payload.latest_version if v.payload }
+ conflicts[name] = Conflict.new(
+ requirement,
+ requirements,
+ vertex.payload && vertex.payload.latest_version,
+ possibility,
+ locked_requirement,
+ requirement_trees,
+ activated_by_name,
+ underlying_error
+ )
+ end
+
+ # @return [Array<Array<Object>>] The different requirement
+ # trees that led to every requirement for the current spec.
+ def requirement_trees
+ vertex = activated.vertex_named(name)
+ vertex.requirements.map { |r| requirement_tree_for(r) }
+ end
+
+ # @param [Object] requirement
+ # @return [Array<Object>] the list of requirements that led to
+ # `requirement` being required.
+ def requirement_tree_for(requirement)
+ tree = []
+ while requirement
+ tree.unshift(requirement)
+ requirement = parent_of(requirement)
+ end
+ tree
+ end
+
+ # Indicates progress roughly once every second
+ # @return [void]
+ def indicate_progress
+ @iteration_counter += 1
+ @progress_rate ||= resolver_ui.progress_rate
+ if iteration_rate.nil?
+ if Time.now - started_at >= @progress_rate
+ self.iteration_rate = @iteration_counter
+ end
+ end
+
+ if iteration_rate && (@iteration_counter % iteration_rate) == 0
+ resolver_ui.indicate_progress
+ end
+ end
+
+ # Calls the {#resolver_ui}'s {UI#debug} method
+ # @param [Integer] depth the depth of the {#states} stack
+ # @param [Proc] block a block that yields a {#to_s}
+ # @return [void]
+ def debug(depth = 0, &block)
+ resolver_ui.debug(depth, &block)
+ end
+
+ # Attempts to activate the current {#possibility}
+ # @return [void]
+ def attempt_to_activate
+ debug(depth) { 'Attempting to activate ' + possibility.to_s }
+ existing_vertex = activated.vertex_named(name)
+ if existing_vertex.payload
+ debug(depth) { "Found existing spec (#{existing_vertex.payload})" }
+ attempt_to_filter_existing_spec(existing_vertex)
+ else
+ latest = possibility.latest_version
+ possibility.possibilities.select! do |possibility|
+ requirement_satisfied_by?(requirement, activated, possibility)
+ end
+ if possibility.latest_version.nil?
+ # ensure there's a possibility for better error messages
+ possibility.possibilities << latest if latest
+ create_conflict
+ unwind_for_conflict
+ else
+ activate_new_spec
+ end
+ end
+ end
+
+ # Attempts to update the existing vertex's `PossibilitySet` with a filtered version
+ # @return [void]
+ def attempt_to_filter_existing_spec(vertex)
+ filtered_set = filtered_possibility_set(vertex)
+ if !filtered_set.possibilities.empty?
+ activated.set_payload(name, filtered_set)
+ new_requirements = requirements.dup
+ push_state_for_requirements(new_requirements, false)
+ else
+ create_conflict
+ debug(depth) { "Unsatisfied by existing spec (#{vertex.payload})" }
+ unwind_for_conflict
+ end
+ end
+
+ # Generates a filtered version of the existing vertex's `PossibilitySet` using the
+ # current state's `requirement`
+ # @param [Object] vertex existing vertex
+ # @return [PossibilitySet] filtered possibility set
+ def filtered_possibility_set(vertex)
+ PossibilitySet.new(vertex.payload.dependencies, vertex.payload.possibilities & possibility.possibilities)
+ end
+
+ # @param [String] requirement_name the spec name to search for
+ # @return [Object] the locked spec named `requirement_name`, if one
+ # is found on {#base}
+ def locked_requirement_named(requirement_name)
+ vertex = base.vertex_named(requirement_name)
+ vertex && vertex.payload
+ end
+
+ # Add the current {#possibility} to the dependency graph of the current
+ # {#state}
+ # @return [void]
+ def activate_new_spec
+ conflicts.delete(name)
+ debug(depth) { "Activated #{name} at #{possibility}" }
+ activated.set_payload(name, possibility)
+ require_nested_dependencies_for(possibility)
+ end
+
+ # Requires the dependencies that the recently activated spec has
+ # @param [Object] possibility_set the PossibilitySet that has just been
+ # activated
+ # @return [void]
+ def require_nested_dependencies_for(possibility_set)
+ nested_dependencies = dependencies_for(possibility_set.latest_version)
+ debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" }
+ nested_dependencies.each do |d|
+ activated.add_child_vertex(name_for(d), nil, [name_for(possibility_set.latest_version)], d)
+ parent_index = states.size - 1
+ parents = @parents_of[d]
+ parents << parent_index if parents.empty?
+ end
+
+ push_state_for_requirements(requirements + nested_dependencies, !nested_dependencies.empty?)
+ end
+
+ # Pushes a new {DependencyState} that encapsulates both existing and new
+ # requirements
+ # @param [Array] new_requirements
+ # @param [Boolean] requires_sort
+ # @param [Object] new_activated
+ # @return [void]
+ def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated)
+ new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort
+ new_requirement = nil
+ loop do
+ new_requirement = new_requirements.shift
+ break if new_requirement.nil? || states.none? { |s| s.requirement == new_requirement }
+ end
+ new_name = new_requirement ? name_for(new_requirement) : ''.freeze
+ possibilities = possibilities_for_requirement(new_requirement)
+ handle_missing_or_push_dependency_state DependencyState.new(
+ new_name, new_requirements, new_activated,
+ new_requirement, possibilities, depth, conflicts.dup, unused_unwind_options.dup
+ )
+ end
+
+ # Checks a proposed requirement with any existing locked requirement
+ # before generating an array of possibilities for it.
+ # @param [Object] requirement the proposed requirement
+ # @param [Object] activated
+ # @return [Array] possibilities
+ def possibilities_for_requirement(requirement, activated = self.activated)
+ return [] unless requirement
+ if locked_requirement_named(name_for(requirement))
+ return locked_requirement_possibility_set(requirement, activated)
+ end
+
+ group_possibilities(search_for(requirement))
+ end
+
+ # @param [Object] requirement the proposed requirement
+ # @param [Object] activated
+ # @return [Array] possibility set containing only the locked requirement, if any
+ def locked_requirement_possibility_set(requirement, activated = self.activated)
+ all_possibilities = search_for(requirement)
+ locked_requirement = locked_requirement_named(name_for(requirement))
+
+ # Longwinded way to build a possibilities array with either the locked
+ # requirement or nothing in it. Required, since the API for
+ # locked_requirement isn't guaranteed.
+ locked_possibilities = all_possibilities.select do |possibility|
+ requirement_satisfied_by?(locked_requirement, activated, possibility)
+ end
+
+ group_possibilities(locked_possibilities)
+ end
+
+ # Build an array of PossibilitySets, with each element representing a group of
+ # dependency versions that all have the same sub-dependency version constraints
+ # and are contiguous.
+ # @param [Array] possibilities an array of possibilities
+ # @return [Array<PossibilitySet>] an array of possibility sets
+ def group_possibilities(possibilities)
+ possibility_sets = []
+ current_possibility_set = nil
+
+ possibilities.reverse_each do |possibility|
+ dependencies = dependencies_for(possibility)
+ if current_possibility_set && dependencies_equal?(current_possibility_set.dependencies, dependencies)
+ current_possibility_set.possibilities.unshift(possibility)
+ else
+ possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility]))
+ current_possibility_set = possibility_sets.first
+ end
+ end
+
+ possibility_sets
+ end
+
+ # Pushes a new {DependencyState}.
+ # If the {#specification_provider} says to
+ # {SpecificationProvider#allow_missing?} that particular requirement, and
+ # there are no possibilities for that requirement, then `state` is not
+ # pushed, and the vertex in {#activated} is removed, and we continue
+ # resolving the remaining requirements.
+ # @param [DependencyState] state
+ # @return [void]
+ def handle_missing_or_push_dependency_state(state)
+ if state.requirement && state.possibilities.empty? && allow_missing?(state.requirement)
+ state.activated.detach_vertex_named(state.name)
+ push_state_for_requirements(state.requirements.dup, false, state.activated)
+ else
+ states.push(state).tap { activated.tag(state) }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb
new file mode 100644
index 0000000000..d43121f8ca
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require_relative 'dependency_graph'
+
+module Gem::Resolver::Molinillo
+ # This class encapsulates a dependency resolver.
+ # The resolver is responsible for determining which set of dependencies to
+ # activate, with feedback from the {#specification_provider}
+ #
+ #
+ class Resolver
+ require_relative 'resolution'
+
+ # @return [SpecificationProvider] the specification provider used
+ # in the resolution process
+ attr_reader :specification_provider
+
+ # @return [UI] the UI module used to communicate back to the user
+ # during the resolution process
+ attr_reader :resolver_ui
+
+ # Initializes a new resolver.
+ # @param [SpecificationProvider] specification_provider
+ # see {#specification_provider}
+ # @param [UI] resolver_ui
+ # see {#resolver_ui}
+ def initialize(specification_provider, resolver_ui)
+ @specification_provider = specification_provider
+ @resolver_ui = resolver_ui
+ end
+
+ # Resolves the requested dependencies into a {DependencyGraph},
+ # locking to the base dependency graph (if specified)
+ # @param [Array] requested an array of 'requested' dependencies that the
+ # {#specification_provider} can understand
+ # @param [DependencyGraph,nil] base the base dependency graph to which
+ # dependencies should be 'locked'
+ def resolve(requested, base = DependencyGraph.new)
+ Resolution.new(specification_provider,
+ resolver_ui,
+ requested,
+ base).
+ resolve
+ end
+ end
+end
diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/state.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/state.rb
new file mode 100644
index 0000000000..6e7c715fce
--- /dev/null
+++ b/lib/rubygems/resolver/molinillo/lib/molinillo/state.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module Gem::Resolver::Molinillo
+ # A state that a {Resolution} can be in
+ # @attr [String] name the name of the current requirement
+ # @attr [Array<Object>] requirements currently unsatisfied requirements
+ # @attr [DependencyGraph] activated the graph of activated dependencies
+ # @attr [Object] requirement the current requirement
+ # @attr [Object] possibilities the possibilities to satisfy the current requirement
+ # @attr [Integer] depth the depth of the resolution
+ # @attr [Hash] conflicts unresolved conflicts, indexed by dependency name
+ # @attr [Array<UnwindDetails>] unused_unwind_options unwinds for previous conflicts that weren't explored
+ ResolutionState = Struct.new(
+ :name,
+ :requirements,
+ :activated,
+ :requirement,
+ :possibilities,
+ :depth,
+ :conflicts,
+ :unused_unwind_options
+ )
+
+ class ResolutionState
+ # Returns an empty resolution state
+ # @return [ResolutionState] an empty state
+ def self.empty
+ new(nil, [], DependencyGraph.new, nil, nil, 0, {}, [])
+ end
+ end
+
+ # A state that encapsulates a set of {#requirements} with an {Array} of
+ # possibilities
+ class DependencyState < ResolutionState
+ # Removes a possibility from `self`
+ # @return [PossibilityState] a state with a single possibility,
+ # the possibility that was removed from `self`
+ def pop_possibility_state
+ PossibilityState.new(
+ name,
+ requirements.dup,
+ activated,
+ requirement,
+ [possibilities.pop],
+ depth + 1,
+ conflicts.dup,
+ unused_unwind_options.dup
+ ).tap do |state|
+ state.activated.tag(state)
+ end
+ end
+ end
+
+ # A state that encapsulates a single possibility to fulfill the given
+ # {#requirement}
+ class PossibilityState < ResolutionState
+ end
+end
diff --git a/lib/rubygems/resolver/spec_specification.rb b/lib/rubygems/resolver/spec_specification.rb
index 00ef9fdba0..79a34d8063 100644
--- a/lib/rubygems/resolver/spec_specification.rb
+++ b/lib/rubygems/resolver/spec_specification.rb
@@ -66,11 +66,4 @@ class Gem::Resolver::SpecSpecification < Gem::Resolver::Specification
def version
spec.version
end
-
- ##
- # The hash value for this specification.
-
- def hash
- spec.hash
- end
end
diff --git a/lib/rubygems/s3_uri_signer.rb b/lib/rubygems/s3_uri_signer.rb
index 7c95a9d4f5..5161e43ebb 100644
--- a/lib/rubygems/s3_uri_signer.rb
+++ b/lib/rubygems/s3_uri_signer.rb
@@ -12,7 +12,7 @@ class Gem::S3URISigner
end
def to_s # :nodoc:
- super.to_s
+ "#{super}"
end
end
@@ -22,7 +22,7 @@ class Gem::S3URISigner
end
def to_s # :nodoc:
- super.to_s
+ "#{super}"
end
end
@@ -34,7 +34,7 @@ class Gem::S3URISigner
##
# Signs S3 URI using query-params according to the reference: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
- def sign(expiration = 86_400)
+ def sign(expiration = 86400)
s3_config = fetch_s3_config
current_time = Time.now.utc
@@ -49,7 +49,7 @@ class Gem::S3URISigner
string_to_sign = generate_string_to_sign(date_time, credential_info, canonical_request)
signature = generate_signature(s3_config, date, string_to_sign)
- Gem::URI.parse("https://#{canonical_host}#{uri.path}?#{query_params}&X-Amz-Signature=#{signature}")
+ URI.parse("https://#{canonical_host}#{uri.path}?#{query_params}&X-Amz-Signature=#{signature}")
end
private
@@ -136,11 +136,11 @@ class Gem::S3URISigner
end
def base64_uri_escape(str)
- str.gsub(%r{[\+/=\n]}, BASE64_URI_TRANSLATE)
+ str.gsub(/[\+\/=\n]/, BASE64_URI_TRANSLATE)
end
def ec2_metadata_credentials_json
- require_relative "vendored_net_http"
+ require "net/http"
require_relative "request"
require_relative "request/connection_pools"
require "json"
@@ -152,13 +152,13 @@ class Gem::S3URISigner
end
def ec2_metadata_request(url)
- uri = Gem::URI(url)
+ uri = URI(url)
@request_pool ||= create_request_pool(uri)
- request = Gem::Request.new(uri, Gem::Net::HTTP::Get, nil, @request_pool)
+ request = Gem::Request.new(uri, Net::HTTP::Get, nil, @request_pool)
response = request.fetch
case response
- when Gem::Net::HTTPOK then
+ when Net::HTTPOK then
JSON.parse(response.body)
else
raise InstanceProfileError.new("Unable to fetch AWS metadata from #{uri}: #{response.message} #{response.code}")
diff --git a/lib/rubygems/safe_marshal.rb b/lib/rubygems/safe_marshal.rb
deleted file mode 100644
index b81d1a0a47..0000000000
--- a/lib/rubygems/safe_marshal.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-require "stringio"
-
-require_relative "safe_marshal/reader"
-require_relative "safe_marshal/visitors/to_ruby"
-
-module Gem
- ###
- # This module is used for safely loading Marshal specs from a gem. The
- # `safe_load` method defined on this module is specifically designed for
- # loading Gem specifications.
-
- module SafeMarshal
- PERMITTED_CLASSES = %w[
- Date
- Time
- Rational
-
- Gem::Dependency
- Gem::NameTuple
- Gem::Platform
- Gem::Requirement
- Gem::Specification
- Gem::Version
- Gem::Version::Requirement
-
- YAML::Syck::DefaultKey
- YAML::PrivateType
- ].freeze
- private_constant :PERMITTED_CLASSES
-
- PERMITTED_SYMBOLS = %w[
- development
- runtime
-
- name
- number
- platform
- dependencies
- ].freeze
- private_constant :PERMITTED_SYMBOLS
-
- PERMITTED_IVARS = {
- "String" => %w[E encoding @taguri @debug_created_info],
- "Time" => %w[
- offset zone nano_num nano_den submicro
- @_zone @marshal_with_utc_coercion
- ],
- "Gem::Dependency" => %w[
- @name @requirement @prerelease @version_requirement @version_requirements @type
- @force_ruby_platform
- ],
- "Gem::NameTuple" => %w[@name @version @platform],
- "Gem::Platform" => %w[@os @cpu @version],
- "Psych::PrivateType" => %w[@value @type_id],
- }.freeze
- private_constant :PERMITTED_IVARS
-
- def self.safe_load(input)
- load(input, permitted_classes: PERMITTED_CLASSES, permitted_symbols: PERMITTED_SYMBOLS, permitted_ivars: PERMITTED_IVARS)
- end
-
- def self.load(input, permitted_classes: [::Symbol], permitted_symbols: [], permitted_ivars: {})
- root = Reader.new(StringIO.new(input, "r").binmode).read!
-
- Visitors::ToRuby.new(
- permitted_classes: permitted_classes,
- permitted_symbols: permitted_symbols,
- permitted_ivars: permitted_ivars,
- ).visit(root)
- end
- end
-end
diff --git a/lib/rubygems/safe_marshal/elements.rb b/lib/rubygems/safe_marshal/elements.rb
deleted file mode 100644
index f8874b1b2f..0000000000
--- a/lib/rubygems/safe_marshal/elements.rb
+++ /dev/null
@@ -1,146 +0,0 @@
-# frozen_string_literal: true
-
-module Gem
- module SafeMarshal
- module Elements
- class Element
- end
-
- class Symbol < Element
- def initialize(name)
- @name = name
- end
- attr_reader :name
- end
-
- class UserDefined < Element
- def initialize(name, binary_string)
- @name = name
- @binary_string = binary_string
- end
-
- attr_reader :name, :binary_string
- end
-
- class UserMarshal < Element
- def initialize(name, data)
- @name = name
- @data = data
- end
-
- attr_reader :name, :data
- end
-
- class String < Element
- def initialize(str)
- @str = str
- end
-
- attr_reader :str
- end
-
- class Hash < Element
- def initialize(pairs)
- @pairs = pairs
- end
-
- attr_reader :pairs
- end
-
- class HashWithDefaultValue < Hash
- def initialize(pairs, default)
- super(pairs)
- @default = default
- end
-
- attr_reader :default
- end
-
- class Array < Element
- def initialize(elements)
- @elements = elements
- end
-
- attr_reader :elements
- end
-
- class Integer < Element
- def initialize(int)
- @int = int
- end
-
- attr_reader :int
- end
-
- class True < Element
- def initialize
- end
- TRUE = new.freeze
- end
-
- class False < Element
- def initialize
- end
-
- FALSE = new.freeze
- end
-
- class WithIvars < Element
- def initialize(object, ivars)
- @object = object
- @ivars = ivars
- end
-
- attr_reader :object, :ivars
- end
-
- class Object < Element
- def initialize(name)
- @name = name
- end
- attr_reader :name
- end
-
- class Nil < Element
- NIL = new.freeze
- end
-
- class ObjectLink < Element
- def initialize(offset)
- @offset = offset
- end
- attr_reader :offset
- end
-
- class SymbolLink < Element
- def initialize(offset)
- @offset = offset
- end
- attr_reader :offset
- end
-
- class Float < Element
- def initialize(string)
- @string = string
- end
- attr_reader :string
- end
-
- class Bignum < Element # rubocop:disable Lint/UnifiedInteger
- def initialize(sign, data)
- @sign = sign
- @data = data
- end
- attr_reader :sign, :data
- end
-
- class UserClass < Element
- def initialize(name, wrapped_object)
- @name = name
- @wrapped_object = wrapped_object
- end
- attr_reader :name, :wrapped_object
- end
- end
- end
-end
diff --git a/lib/rubygems/safe_marshal/reader.rb b/lib/rubygems/safe_marshal/reader.rb
deleted file mode 100644
index 740be113e5..0000000000
--- a/lib/rubygems/safe_marshal/reader.rb
+++ /dev/null
@@ -1,308 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "elements"
-
-module Gem
- module SafeMarshal
- class Reader
- class Error < StandardError
- end
-
- class UnsupportedVersionError < Error
- end
-
- class UnconsumedBytesError < Error
- end
-
- class NotImplementedError < Error
- end
-
- class EOFError < Error
- end
-
- def initialize(io)
- @io = io
- end
-
- def read!
- read_header
- root = read_element
- raise UnconsumedBytesError unless @io.eof?
- root
- end
-
- private
-
- MARSHAL_VERSION = [Marshal::MAJOR_VERSION, Marshal::MINOR_VERSION].map(&:chr).join.freeze
- private_constant :MARSHAL_VERSION
-
- def read_header
- v = @io.read(2)
- raise UnsupportedVersionError, "Unsupported marshal version #{v.bytes.map(&:ord).join(".")}, expected #{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}" unless v == MARSHAL_VERSION
- end
-
- def read_byte
- @io.getbyte
- end
-
- def read_integer
- b = read_byte
-
- case b
- when 0x00
- 0
- when 0x01
- read_byte
- when 0x02
- read_byte | (read_byte << 8)
- when 0x03
- read_byte | (read_byte << 8) | (read_byte << 16)
- when 0x04
- read_byte | (read_byte << 8) | (read_byte << 16) | (read_byte << 24)
- when 0xFC
- read_byte | (read_byte << 8) | (read_byte << 16) | (read_byte << 24) | -0x100000000
- when 0xFD
- read_byte | (read_byte << 8) | (read_byte << 16) | -0x1000000
- when 0xFE
- read_byte | (read_byte << 8) | -0x10000
- when 0xFF
- read_byte | -0x100
- when nil
- raise EOFError, "Unexpected EOF"
- else
- signed = (b ^ 128) - 128
- if b >= 128
- signed + 5
- else
- signed - 5
- end
- end
- end
-
- def read_element
- type = read_byte
- case type
- when 34 then read_string # ?"
- when 48 then read_nil # ?0
- when 58 then read_symbol # ?:
- when 59 then read_symbol_link # ?;
- when 64 then read_object_link # ?@
- when 70 then read_false # ?F
- when 73 then read_object_with_ivars # ?I
- when 84 then read_true # ?T
- when 85 then read_user_marshal # ?U
- when 91 then read_array # ?[
- when 102 then read_float # ?f
- when 105 then Elements::Integer.new(read_integer) # ?i
- when 108 then read_bignum # ?l
- when 111 then read_object # ?o
- when 117 then read_user_defined # ?u
- when 123 then read_hash # ?{
- when 125 then read_hash_with_default_value # ?}
- when 101 then read_extended_object # ?e
- when 99 then read_class # ?c
- when 109 then read_module # ?m
- when 77 then read_class_or_module # ?M
- when 100 then read_data # ?d
- when 47 then read_regexp # ?/
- when 83 then read_struct # ?S
- when 67 then read_user_class # ?C
- when nil
- raise EOFError, "Unexpected EOF"
- else
- raise Error, "Unknown marshal type discriminator #{type.chr.inspect} (#{type})"
- end
- end
-
- STRING_E_SYMBOL = Elements::Symbol.new("E").freeze
- private_constant :STRING_E_SYMBOL
-
- def read_symbol
- len = read_integer
- if len == 1
- byte = read_byte
- if byte == 69 # ?E
- STRING_E_SYMBOL
- else
- Elements::Symbol.new(byte.chr)
- end
- else
- name = -@io.read(len)
- Elements::Symbol.new(name)
- end
- end
-
- EMPTY_STRING = Elements::String.new("".b.freeze).freeze
- private_constant :EMPTY_STRING
-
- def read_string
- length = read_integer
- return EMPTY_STRING if length == 0
- str = @io.read(length)
- Elements::String.new(str)
- end
-
- def read_true
- Elements::True::TRUE
- end
-
- def read_false
- Elements::False::FALSE
- end
-
- def read_user_defined
- name = read_element
- binary_string = @io.read(read_integer)
- Elements::UserDefined.new(name, binary_string)
- end
-
- EMPTY_ARRAY = Elements::Array.new([].freeze).freeze
- private_constant :EMPTY_ARRAY
-
- def read_array
- length = read_integer
- return EMPTY_ARRAY if length == 0
- elements = Array.new(length) do
- read_element
- end
- Elements::Array.new(elements)
- end
-
- def read_object_with_ivars
- object = read_element
- ivars = Array.new(read_integer) do
- [read_element, read_element]
- end
- Elements::WithIvars.new(object, ivars)
- end
-
- def read_symbol_link
- offset = read_integer
- Elements::SymbolLink.new(offset)
- end
-
- def read_user_marshal
- name = read_element
- data = read_element
- Elements::UserMarshal.new(name, data)
- end
-
- # profiling bundle install --full-index shows that
- # offset 6 is by far the most common object link,
- # so we special case it to avoid allocating a new
- # object a third of the time.
- # the following are all the object links that
- # appear more than 10000 times in my profiling
-
- OBJECT_LINKS = {
- 6 => Elements::ObjectLink.new(6).freeze,
- 30 => Elements::ObjectLink.new(30).freeze,
- 81 => Elements::ObjectLink.new(81).freeze,
- 34 => Elements::ObjectLink.new(34).freeze,
- 38 => Elements::ObjectLink.new(38).freeze,
- 50 => Elements::ObjectLink.new(50).freeze,
- 91 => Elements::ObjectLink.new(91).freeze,
- 42 => Elements::ObjectLink.new(42).freeze,
- 46 => Elements::ObjectLink.new(46).freeze,
- 150 => Elements::ObjectLink.new(150).freeze,
- 100 => Elements::ObjectLink.new(100).freeze,
- 104 => Elements::ObjectLink.new(104).freeze,
- 108 => Elements::ObjectLink.new(108).freeze,
- 242 => Elements::ObjectLink.new(242).freeze,
- 246 => Elements::ObjectLink.new(246).freeze,
- 139 => Elements::ObjectLink.new(139).freeze,
- 143 => Elements::ObjectLink.new(143).freeze,
- 114 => Elements::ObjectLink.new(114).freeze,
- 308 => Elements::ObjectLink.new(308).freeze,
- 200 => Elements::ObjectLink.new(200).freeze,
- 54 => Elements::ObjectLink.new(54).freeze,
- 62 => Elements::ObjectLink.new(62).freeze,
- 1_286_245 => Elements::ObjectLink.new(1_286_245).freeze,
- }.freeze
- private_constant :OBJECT_LINKS
-
- def read_object_link
- offset = read_integer
- OBJECT_LINKS[offset] || Elements::ObjectLink.new(offset)
- end
-
- EMPTY_HASH = Elements::Hash.new([].freeze).freeze
- private_constant :EMPTY_HASH
-
- def read_hash
- length = read_integer
- return EMPTY_HASH if length == 0
- pairs = Array.new(length) do
- [read_element, read_element]
- end
- Elements::Hash.new(pairs)
- end
-
- def read_hash_with_default_value
- pairs = Array.new(read_integer) do
- [read_element, read_element]
- end
- default = read_element
- Elements::HashWithDefaultValue.new(pairs, default)
- end
-
- def read_object
- name = read_element
- object = Elements::Object.new(name)
- ivars = Array.new(read_integer) do
- [read_element, read_element]
- end
- Elements::WithIvars.new(object, ivars)
- end
-
- def read_nil
- Elements::Nil::NIL
- end
-
- def read_float
- string = @io.read(read_integer)
- Elements::Float.new(string)
- end
-
- def read_bignum
- sign = read_byte
- data = @io.read(read_integer * 2)
- Elements::Bignum.new(sign, data)
- end
-
- def read_extended_object
- raise NotImplementedError, "Reading Marshal objects of type extended_object is not implemented"
- end
-
- def read_class
- raise NotImplementedError, "Reading Marshal objects of type class is not implemented"
- end
-
- def read_module
- raise NotImplementedError, "Reading Marshal objects of type module is not implemented"
- end
-
- def read_class_or_module
- raise NotImplementedError, "Reading Marshal objects of type class_or_module is not implemented"
- end
-
- def read_data
- raise NotImplementedError, "Reading Marshal objects of type data is not implemented"
- end
-
- def read_regexp
- raise NotImplementedError, "Reading Marshal objects of type regexp is not implemented"
- end
-
- def read_struct
- raise NotImplementedError, "Reading Marshal objects of type struct is not implemented"
- end
-
- def read_user_class
- name = read_element
- wrapped_object = read_element
- Elements::UserClass.new(name, wrapped_object)
- end
- end
- end
-end
diff --git a/lib/rubygems/safe_marshal/visitors/stream_printer.rb b/lib/rubygems/safe_marshal/visitors/stream_printer.rb
deleted file mode 100644
index 162b36ad05..0000000000
--- a/lib/rubygems/safe_marshal/visitors/stream_printer.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "visitor"
-
-module Gem::SafeMarshal
- module Visitors
- class StreamPrinter < Visitor
- def initialize(io, indent: "")
- @io = io
- @indent = indent
- @level = 0
- end
-
- def visit(target)
- @io.write("#{@indent * @level}#{target.class}")
- target.instance_variables.each do |ivar|
- value = target.instance_variable_get(ivar)
- next if Elements::Element === value || Array === value
- @io.write(" #{ivar}=#{value.inspect}")
- end
- @io.write("\n")
- begin
- @level += 1
- super
- ensure
- @level -= 1
- end
- end
- end
- end
-end
diff --git a/lib/rubygems/safe_marshal/visitors/to_ruby.rb b/lib/rubygems/safe_marshal/visitors/to_ruby.rb
deleted file mode 100644
index a9f1d048d4..0000000000
--- a/lib/rubygems/safe_marshal/visitors/to_ruby.rb
+++ /dev/null
@@ -1,415 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "visitor"
-
-module Gem::SafeMarshal
- module Visitors
- class ToRuby < Visitor
- def initialize(permitted_classes:, permitted_symbols:, permitted_ivars:)
- @permitted_classes = permitted_classes
- @permitted_symbols = ["E"].concat(permitted_symbols).concat(permitted_classes)
- @permitted_ivars = permitted_ivars
-
- @objects = []
- @symbols = []
- @class_cache = {}
-
- @stack = ["root"]
- @stack_idx = 1
- end
-
- def inspect # :nodoc:
- format("#<%s permitted_classes: %p permitted_symbols: %p permitted_ivars: %p>",
- self.class, @permitted_classes, @permitted_symbols, @permitted_ivars)
- end
-
- def visit(target)
- stack_idx = @stack_idx
- super
- ensure
- @stack_idx = stack_idx - 1
- end
-
- private
-
- def push_stack(element)
- @stack[@stack_idx] = element
- @stack_idx += 1
- end
-
- def visit_Gem_SafeMarshal_Elements_Array(a)
- array = register_object([])
-
- elements = a.elements
- size = elements.size
- idx = 0
- # not idiomatic, but there's a huge number of IMEMOs allocated here, so we avoid the block
- # because this is such a hot path when doing a bundle install with the full index
- until idx == size
- push_stack idx
- array << visit(elements[idx])
- idx += 1
- end
-
- array
- end
-
- def visit_Gem_SafeMarshal_Elements_Symbol(s)
- name = s.name
- raise UnpermittedSymbolError.new(symbol: name, stack: formatted_stack) unless @permitted_symbols.include?(name)
- visit_symbol_type(s)
- end
-
- def map_ivars(klass, ivars)
- stack_idx = @stack_idx
- ivars.map.with_index do |(k, v), i|
- @stack_idx = stack_idx
-
- push_stack "ivar_"
- push_stack i
- k = resolve_ivar(klass, k)
-
- @stack_idx = stack_idx
- push_stack k
-
- next k, visit(v)
- end
- end
-
- def visit_Gem_SafeMarshal_Elements_WithIvars(e)
- object_offset = @objects.size
- push_stack "object"
- object = visit(e.object)
- ivars = map_ivars(object.class, e.ivars)
-
- case e.object
- when Elements::UserDefined
- if object.class == ::Time
- internal = []
-
- ivars.reject! do |k, v|
- case k
- when :offset, :zone, :nano_num, :nano_den, :submicro
- internal << [k, v]
- true
- else
- false
- end
- end
-
- s = e.object.binary_string
-
- marshal_string = "\x04\bIu:\tTime".b
- marshal_string.concat(s.size + 5)
- marshal_string << s
- marshal_string.concat(internal.size + 5)
-
- internal.each do |k, v|
- marshal_string.concat(":")
- marshal_string.concat(k.size + 5)
- marshal_string.concat(k.to_s)
- dumped = Marshal.dump(v)
- dumped[0, 2] = ""
- marshal_string.concat(dumped)
- end
-
- object = @objects[object_offset] = Marshal.load(marshal_string)
- end
- when Elements::String
- enc = nil
-
- ivars.reject! do |k, v|
- case k
- when :E
- case v
- when TrueClass
- enc = "UTF-8"
- when FalseClass
- enc = "US-ASCII"
- else
- raise FormatError, "Unexpected value for String :E #{v.inspect}"
- end
- when :encoding
- enc = v
- else
- next false
- end
- true
- end
-
- object.force_encoding(enc) if enc
- end
-
- ivars.each do |k, v|
- object.instance_variable_set k, v
- end
- object
- end
-
- def visit_Gem_SafeMarshal_Elements_Hash(o)
- hash = register_object({})
-
- o.pairs.each_with_index do |(k, v), i|
- push_stack i
- k = visit(k)
- push_stack k
- hash[k] = visit(v)
- end
-
- hash
- end
-
- def visit_Gem_SafeMarshal_Elements_HashWithDefaultValue(o)
- hash = visit_Gem_SafeMarshal_Elements_Hash(o)
- push_stack :default
- hash.default = visit(o.default)
- hash
- end
-
- def visit_Gem_SafeMarshal_Elements_Object(o)
- register_object(resolve_class(o.name).allocate)
- end
-
- def visit_Gem_SafeMarshal_Elements_ObjectLink(o)
- @objects[o.offset]
- end
-
- def visit_Gem_SafeMarshal_Elements_SymbolLink(o)
- @symbols[o.offset]
- end
-
- def visit_Gem_SafeMarshal_Elements_UserDefined(o)
- register_object(call_method(resolve_class(o.name), :_load, o.binary_string))
- end
-
- def visit_Gem_SafeMarshal_Elements_UserMarshal(o)
- klass = resolve_class(o.name)
- compat = COMPAT_CLASSES.fetch(klass, nil)
- idx = @objects.size
- object = register_object(call_method(compat || klass, :allocate))
-
- push_stack :data
- ret = call_method(object, :marshal_load, visit(o.data))
-
- if compat
- object = @objects[idx] = ret
- end
-
- object
- end
-
- def visit_Gem_SafeMarshal_Elements_Integer(i)
- i.int
- end
-
- def visit_Gem_SafeMarshal_Elements_Nil(_)
- nil
- end
-
- def visit_Gem_SafeMarshal_Elements_True(_)
- true
- end
-
- def visit_Gem_SafeMarshal_Elements_False(_)
- false
- end
-
- def visit_Gem_SafeMarshal_Elements_String(s)
- register_object(+s.str)
- end
-
- def visit_Gem_SafeMarshal_Elements_Float(f)
- case f.string
- when "inf"
- ::Float::INFINITY
- when "-inf"
- -::Float::INFINITY
- when "nan"
- ::Float::NAN
- else
- f.string.to_f
- end
- end
-
- def visit_Gem_SafeMarshal_Elements_Bignum(b)
- result = 0
- b.data.each_byte.with_index do |byte, exp|
- result += (byte * 2**(exp * 8))
- end
-
- case b.sign
- when 43 # ?+
- result
- when 45 # ?-
- -result
- else
- raise FormatError, "Unexpected sign for Bignum #{b.sign.chr.inspect} (#{b.sign})"
- end
- end
-
- def visit_Gem_SafeMarshal_Elements_UserClass(r)
- if resolve_class(r.name) == ::Hash && r.wrapped_object.is_a?(Elements::Hash)
-
- hash = register_object({}.compare_by_identity)
-
- o = r.wrapped_object
- o.pairs.each_with_index do |(k, v), i|
- push_stack i
- k = visit(k)
- push_stack k
- hash[k] = visit(v)
- end
-
- if o.is_a?(Elements::HashWithDefaultValue)
- push_stack :default
- hash.default = visit(o.default)
- end
-
- hash
- else
- raise UnsupportedError.new("Unsupported user class #{resolve_class(r.name)} in marshal stream", stack: formatted_stack)
- end
- end
-
- def resolve_class(n)
- @class_cache[n] ||= begin
- to_s = resolve_symbol_name(n)
- raise UnpermittedClassError.new(name: to_s, stack: formatted_stack) unless @permitted_classes.include?(to_s)
- visit_symbol_type(n)
- begin
- ::Object.const_get(to_s)
- rescue NameError
- raise ArgumentError, "Undefined class #{to_s.inspect}"
- end
- end
- end
-
- class RationalCompat
- def marshal_load(s)
- num, den = s
- raise ArgumentError, "Expected 2 ints" unless s.size == 2 && num.is_a?(Integer) && den.is_a?(Integer)
- Rational(num, den)
- end
- end
- private_constant :RationalCompat
-
- COMPAT_CLASSES = {}.tap do |h|
- h[Rational] = RationalCompat
- end.compare_by_identity.freeze
- private_constant :COMPAT_CLASSES
-
- def resolve_ivar(klass, name)
- to_s = resolve_symbol_name(name)
-
- raise UnpermittedIvarError.new(symbol: to_s, klass: klass, stack: formatted_stack) unless @permitted_ivars.fetch(klass.name, [].freeze).include?(to_s)
-
- visit_symbol_type(name)
- end
-
- def visit_symbol_type(element)
- case element
- when Elements::Symbol
- sym = element.name.to_sym
- @symbols << sym
- sym
- when Elements::SymbolLink
- visit_Gem_SafeMarshal_Elements_SymbolLink(element)
- end
- end
-
- # This is a hot method, so avoid respond_to? checks on every invocation
- if :read.respond_to?(:name)
- def resolve_symbol_name(element)
- case element
- when Elements::Symbol
- element.name
- when Elements::SymbolLink
- visit_Gem_SafeMarshal_Elements_SymbolLink(element).name
- else
- raise FormatError, "Expected symbol or symbol link, got #{element.inspect} @ #{formatted_stack.join(".")}"
- end
- end
- else
- def resolve_symbol_name(element)
- case element
- when Elements::Symbol
- element.name
- when Elements::SymbolLink
- visit_Gem_SafeMarshal_Elements_SymbolLink(element).to_s
- else
- raise FormatError, "Expected symbol or symbol link, got #{element.inspect} @ #{formatted_stack.join(".")}"
- end
- end
- end
-
- def register_object(o)
- @objects << o
- o
- end
-
- def call_method(receiver, method, *args)
- receiver.__send__(method, *args)
- rescue NoMethodError => e
- raise unless e.receiver == receiver
-
- raise MethodCallError, "Unable to call #{method.inspect} on #{receiver.inspect}, perhaps it is a class using marshal compat, which is not visible in ruby? #{e}"
- end
-
- def formatted_stack
- formatted = []
- @stack[0, @stack_idx].each do |e|
- if e.is_a?(Integer)
- if formatted.last == "ivar_"
- formatted[-1] = "ivar_#{e}"
- else
- formatted << "[#{e}]"
- end
- else
- formatted << e
- end
- end
- formatted
- end
-
- class Error < StandardError
- end
-
- class UnpermittedSymbolError < Error
- def initialize(symbol:, stack:)
- @symbol = symbol
- @stack = stack
- super "Attempting to load unpermitted symbol #{symbol.inspect} @ #{stack.join "."}"
- end
- end
-
- class UnpermittedIvarError < Error
- def initialize(symbol:, klass:, stack:)
- @symbol = symbol
- @klass = klass
- @stack = stack
- super "Attempting to set unpermitted ivar #{symbol.inspect} on object of class #{klass} @ #{stack.join "."}"
- end
- end
-
- class UnpermittedClassError < Error
- def initialize(name:, stack:)
- @name = name
- @stack = stack
- super "Attempting to load unpermitted class #{name.inspect} @ #{stack.join "."}"
- end
- end
-
- class UnsupportedError < Error
- def initialize(message, stack:)
- super "#{message} @ #{stack.join "."}"
- end
- end
-
- class FormatError < Error
- end
-
- class MethodCallError < Error
- end
- end
- end
-end
diff --git a/lib/rubygems/safe_marshal/visitors/visitor.rb b/lib/rubygems/safe_marshal/visitors/visitor.rb
deleted file mode 100644
index c9a079dc0e..0000000000
--- a/lib/rubygems/safe_marshal/visitors/visitor.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::SafeMarshal::Visitors
- class Visitor
- def visit(target)
- send DISPATCH.fetch(target.class), target
- end
-
- private
-
- DISPATCH = Gem::SafeMarshal::Elements.constants.each_with_object({}) do |c, h|
- next if c == :Element
-
- klass = Gem::SafeMarshal::Elements.const_get(c)
- h[klass] = :"visit_#{klass.name.gsub("::", "_")}"
- h.default = :visit_unknown_element
- end.compare_by_identity.freeze
- private_constant :DISPATCH
-
- def visit_unknown_element(e)
- raise ArgumentError, "Attempting to visit unknown element #{e.inspect}"
- end
-
- def visit_Gem_SafeMarshal_Elements_Array(target)
- target.elements.each {|e| visit(e) }
- end
-
- def visit_Gem_SafeMarshal_Elements_Bignum(target); end
- def visit_Gem_SafeMarshal_Elements_False(target); end
- def visit_Gem_SafeMarshal_Elements_Float(target); end
-
- def visit_Gem_SafeMarshal_Elements_Hash(target)
- target.pairs.each do |k, v|
- visit(k)
- visit(v)
- end
- end
-
- def visit_Gem_SafeMarshal_Elements_HashWithDefaultValue(target)
- visit_Gem_SafeMarshal_Elements_Hash(target)
- visit(target.default)
- end
-
- def visit_Gem_SafeMarshal_Elements_Integer(target); end
- def visit_Gem_SafeMarshal_Elements_Nil(target); end
-
- def visit_Gem_SafeMarshal_Elements_Object(target)
- visit(target.name)
- end
-
- def visit_Gem_SafeMarshal_Elements_ObjectLink(target); end
- def visit_Gem_SafeMarshal_Elements_String(target); end
- def visit_Gem_SafeMarshal_Elements_Symbol(target); end
- def visit_Gem_SafeMarshal_Elements_SymbolLink(target); end
- def visit_Gem_SafeMarshal_Elements_True(target); end
-
- def visit_Gem_SafeMarshal_Elements_UserDefined(target)
- visit(target.name)
- end
-
- def visit_Gem_SafeMarshal_Elements_UserMarshal(target)
- visit(target.name)
- visit(target.data)
- end
-
- def visit_Gem_SafeMarshal_Elements_WithIvars(target)
- visit(target.object)
- target.ivars.each do |k, v|
- visit(k)
- visit(v)
- end
- end
- end
-end
diff --git a/lib/rubygems/safe_yaml.rb b/lib/rubygems/safe_yaml.rb
index 6a02a48230..74ad25ca15 100644
--- a/lib/rubygems/safe_yaml.rb
+++ b/lib/rubygems/safe_yaml.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
module Gem
+
###
# This module is used for safely loading YAML specs from a gem. The
# `safe_load` method defined on this module is specifically designed for
@@ -25,21 +26,34 @@ module Gem
runtime
].freeze
- @aliases_enabled = true
- def self.aliases_enabled=(value) # :nodoc:
- @aliases_enabled = !!value
- end
+ if ::Psych.respond_to? :safe_load
+ def self.safe_load(input)
+ if Gem::Version.new(Psych::VERSION) >= Gem::Version.new("3.1.0.pre1")
+ ::Psych.safe_load(input, permitted_classes: PERMITTED_CLASSES, permitted_symbols: PERMITTED_SYMBOLS, aliases: true)
+ else
+ ::Psych.safe_load(input, PERMITTED_CLASSES, PERMITTED_SYMBOLS, true)
+ end
+ end
- def self.aliases_enabled? # :nodoc:
- @aliases_enabled
- end
+ def self.load(input)
+ if Gem::Version.new(Psych::VERSION) >= Gem::Version.new("3.1.0.pre1")
+ ::Psych.safe_load(input, permitted_classes: [::Symbol])
+ else
+ ::Psych.safe_load(input, [::Symbol])
+ end
+ end
+ else
+ unless Gem::Deprecate.skip
+ warn "Psych safe loading is not available. Please upgrade psych to a version that supports safe loading (>= 2.0)."
+ end
- def self.safe_load(input)
- ::Psych.safe_load(input, permitted_classes: PERMITTED_CLASSES, permitted_symbols: PERMITTED_SYMBOLS, aliases: @aliases_enabled)
- end
+ def self.safe_load(input, *args)
+ ::Psych.load input
+ end
- def self.load(input)
- ::Psych.safe_load(input, permitted_classes: [::Symbol])
+ def self.load(input)
+ ::Psych.load input
+ end
end
end
end
diff --git a/lib/rubygems/security.rb b/lib/rubygems/security.rb
index 69ba87b07f..73ee1e4bb9 100644
--- a/lib/rubygems/security.rb
+++ b/lib/rubygems/security.rb
@@ -323,9 +323,10 @@ require_relative "openssl"
# == Original author
#
# Paul Duncan <pabs@pablotron.org>
-# https://pablotron.org/
+# http://pablotron.org/
module Gem::Security
+
##
# Gem::Security default exception type
@@ -360,7 +361,7 @@ module Gem::Security
##
# One day in seconds
- ONE_DAY = 86_400
+ ONE_DAY = 86400
##
# One year in seconds
@@ -398,7 +399,8 @@ module Gem::Security
#
# The +extensions+ restrict the key to the indicated uses.
- def self.create_cert(subject, key, age = ONE_YEAR, extensions = EXTENSIONS, serial = 1)
+ def self.create_cert(subject, key, age = ONE_YEAR, extensions = EXTENSIONS,
+ serial = 1)
cert = OpenSSL::X509::Certificate.new
cert.public_key = get_public_key(key)
@@ -449,7 +451,8 @@ module Gem::Security
# Creates a self-signed certificate with an issuer and subject of +subject+
# and the given +extensions+ for the +key+.
- def self.create_cert_self_signed(subject, key, age = ONE_YEAR, extensions = EXTENSIONS, serial = 1)
+ def self.create_cert_self_signed(subject, key, age = ONE_YEAR,
+ extensions = EXTENSIONS, serial = 1)
certificate = create_cert subject, key, age, extensions
sign certificate, key, certificate, age, extensions, serial
@@ -459,8 +462,16 @@ module Gem::Security
# Creates a new digest instance using the specified +algorithm+. The default
# is SHA256.
- def self.create_digest(algorithm = DIGEST_NAME)
- OpenSSL::Digest.new(algorithm)
+ if defined?(OpenSSL::Digest)
+ def self.create_digest(algorithm = DIGEST_NAME)
+ OpenSSL::Digest.new(algorithm)
+ end
+ else
+ require "digest"
+
+ def self.create_digest(algorithm = DIGEST_NAME)
+ Digest.const_get(algorithm).new
+ end
end
##
@@ -505,10 +516,11 @@ module Gem::Security
#--
# TODO increment serial
- def self.re_sign(expired_certificate, private_key, age = ONE_YEAR, extensions = EXTENSIONS)
+ def self.re_sign(expired_certificate, private_key, age = ONE_YEAR,
+ extensions = EXTENSIONS)
raise Gem::Security::Exception,
"incorrect signing key for re-signing " +
- expired_certificate.subject.to_s unless
+ "#{expired_certificate.subject}" unless
expired_certificate.check_private_key(private_key)
unless expired_certificate.subject.to_s ==
@@ -517,7 +529,7 @@ module Gem::Security
issuer = alt_name_or_x509_entry expired_certificate, :issuer
raise Gem::Security::Exception,
- "#{subject} is not self-signed, contact #{issuer} " \
+ "#{subject} is not self-signed, contact #{issuer} " +
"to obtain a valid certificate"
end
@@ -541,7 +553,8 @@ module Gem::Security
#
# Returns the newly signed certificate.
- def self.sign(certificate, signing_key, signing_cert, age = ONE_YEAR, extensions = EXTENSIONS, serial = 1)
+ def self.sign(certificate, signing_key, signing_cert,
+ age = ONE_YEAR, extensions = EXTENSIONS, serial = 1)
signee_subject = certificate.subject
signee_key = certificate.public_key
@@ -589,7 +602,7 @@ module Gem::Security
# +permissions+. If passed +cipher+ and +passphrase+ those arguments will be
# passed to +to_pem+.
- def self.write(pemmable, path, permissions = 0o600, passphrase = nil, cipher = KEY_CIPHER)
+ def self.write(pemmable, path, permissions = 0600, passphrase = nil, cipher = KEY_CIPHER)
path = File.expand_path path
File.open path, "wb", permissions do |io|
@@ -604,6 +617,7 @@ module Gem::Security
end
reset
+
end
if Gem::HAVE_OPENSSL
diff --git a/lib/rubygems/security/policies.rb b/lib/rubygems/security/policies.rb
index 41f66043ad..bdfe9ed43f 100644
--- a/lib/rubygems/security/policies.rb
+++ b/lib/rubygems/security/policies.rb
@@ -1,17 +1,18 @@
# frozen_string_literal: true
module Gem::Security
+
##
# No security policy: all package signature checks are disabled.
NoSecurity = Policy.new(
"No Security",
- verify_data: false,
- verify_signer: false,
- verify_chain: false,
- verify_root: false,
- only_trusted: false,
- only_signed: false
+ :verify_data => false,
+ :verify_signer => false,
+ :verify_chain => false,
+ :verify_root => false,
+ :only_trusted => false,
+ :only_signed => false
)
##
@@ -24,12 +25,12 @@ module Gem::Security
AlmostNoSecurity = Policy.new(
"Almost No Security",
- verify_data: true,
- verify_signer: false,
- verify_chain: false,
- verify_root: false,
- only_trusted: false,
- only_signed: false
+ :verify_data => true,
+ :verify_signer => false,
+ :verify_chain => false,
+ :verify_root => false,
+ :only_trusted => false,
+ :only_signed => false
)
##
@@ -41,12 +42,12 @@ module Gem::Security
LowSecurity = Policy.new(
"Low Security",
- verify_data: true,
- verify_signer: true,
- verify_chain: false,
- verify_root: false,
- only_trusted: false,
- only_signed: false
+ :verify_data => true,
+ :verify_signer => true,
+ :verify_chain => false,
+ :verify_root => false,
+ :only_trusted => false,
+ :only_signed => false
)
##
@@ -60,12 +61,12 @@ module Gem::Security
MediumSecurity = Policy.new(
"Medium Security",
- verify_data: true,
- verify_signer: true,
- verify_chain: true,
- verify_root: true,
- only_trusted: true,
- only_signed: false
+ :verify_data => true,
+ :verify_signer => true,
+ :verify_chain => true,
+ :verify_root => true,
+ :only_trusted => true,
+ :only_signed => false
)
##
@@ -79,12 +80,12 @@ module Gem::Security
HighSecurity = Policy.new(
"High Security",
- verify_data: true,
- verify_signer: true,
- verify_chain: true,
- verify_root: true,
- only_trusted: true,
- only_signed: true
+ :verify_data => true,
+ :verify_signer => true,
+ :verify_chain => true,
+ :verify_root => true,
+ :only_trusted => true,
+ :only_signed => true
)
##
@@ -92,12 +93,12 @@ module Gem::Security
SigningPolicy = Policy.new(
"Signing Policy",
- verify_data: false,
- verify_signer: true,
- verify_chain: true,
- verify_root: true,
- only_trusted: false,
- only_signed: false
+ :verify_data => false,
+ :verify_signer => true,
+ :verify_chain => true,
+ :verify_root => true,
+ :only_trusted => false,
+ :only_signed => false
)
##
@@ -111,4 +112,5 @@ module Gem::Security
"HighSecurity" => HighSecurity,
# SigningPolicy is not intended for use by `gem -P` so do not list it
}.freeze
+
end
diff --git a/lib/rubygems/security/policy.rb b/lib/rubygems/security/policy.rb
index 7b86ac5763..9b9eac46bf 100644
--- a/lib/rubygems/security/policy.rb
+++ b/lib/rubygems/security/policy.rb
@@ -135,7 +135,7 @@ class Gem::Security::Policy
raise Gem::Security::Exception, "missing root certificate" unless root
raise Gem::Security::Exception,
- "root certificate #{root.subject} is not self-signed " \
+ "root certificate #{root.subject} is not self-signed " +
"(issuer #{root.issuer})" if
root.issuer != root.subject
@@ -171,7 +171,7 @@ class Gem::Security::Policy
cert_dgst = digester.digest pkey_str
raise Gem::Security::Exception,
- "trusted root certificate #{root.subject} checksum " \
+ "trusted root certificate #{root.subject} checksum " +
"does not match signing root certificate checksum" unless
save_dgst == cert_dgst
@@ -192,8 +192,11 @@ class Gem::Security::Policy
end
def inspect # :nodoc:
- format("[Policy: %s - data: %p signer: %p chain: %p root: %p " \
- "signed-only: %p trusted-only: %p]", @name, @verify_chain, @verify_data, @verify_root, @verify_signer, @only_signed, @only_trusted)
+ ("[Policy: %s - data: %p signer: %p chain: %p root: %p " +
+ "signed-only: %p trusted-only: %p]") % [
+ @name, @verify_chain, @verify_data, @verify_root, @verify_signer,
+ @only_signed, @only_trusted
+ ]
end
##
@@ -203,7 +206,8 @@ class Gem::Security::Policy
#
# If +key+ is given it is used to validate the signing certificate.
- def verify(chain, key = nil, digests = {}, signatures = {}, full_name = "(unknown)")
+ def verify(chain, key = nil, digests = {}, signatures = {},
+ full_name = "(unknown)")
if signatures.empty?
if @only_signed
raise Gem::Security::Exception,
@@ -222,7 +226,7 @@ class Gem::Security::Policy
trust_dir = opt[:trust_dir]
time = Time.now
- _, signer_digests = digests.find do |_algorithm, file_digests|
+ _, signer_digests = digests.find do |algorithm, file_digests|
file_digests.values.first.name == Gem::Security::DIGEST_NAME
end
@@ -284,5 +288,5 @@ class Gem::Security::Policy
true
end
- alias_method :to_s, :name # :nodoc:
+ alias to_s name # :nodoc:
end
diff --git a/lib/rubygems/security/signer.rb b/lib/rubygems/security/signer.rb
index 5732fb57fd..d76af03eb8 100644
--- a/lib/rubygems/security/signer.rb
+++ b/lib/rubygems/security/signer.rb
@@ -106,7 +106,7 @@ class Gem::Security::Signer
# this value is preferred, otherwise the subject is used.
def extract_name(cert) # :nodoc:
- subject_alt_name = cert.extensions.find {|e| e.oid == "subjectAltName" }
+ subject_alt_name = cert.extensions.find {|e| "subjectAltName" == e.oid }
if subject_alt_name
/\Aemail:/ =~ subject_alt_name.value # rubocop:disable Performance/StartWith
@@ -175,18 +175,10 @@ class Gem::Security::Signer
old_cert = @cert_chain.last
disk_cert_path = File.join(Gem.default_cert_path)
- disk_cert = begin
- File.read(disk_cert_path)
- rescue StandardError
- nil
- end
+ disk_cert = File.read(disk_cert_path) rescue nil
disk_key_path = File.join(Gem.default_key_path)
- disk_key = begin
- OpenSSL::PKey.read(File.read(disk_key_path), @passphrase)
- rescue StandardError
- nil
- end
+ disk_key = OpenSSL::PKey.read(File.read(disk_key_path), @passphrase) rescue nil
return unless disk_key
diff --git a/lib/rubygems/security/trust_dir.rb b/lib/rubygems/security/trust_dir.rb
index d23d161cfe..4de33068f9 100644
--- a/lib/rubygems/security/trust_dir.rb
+++ b/lib/rubygems/security/trust_dir.rb
@@ -9,8 +9,8 @@ class Gem::Security::TrustDir
# Default permissions for the trust directory and its contents
DEFAULT_PERMISSIONS = {
- trust_dir: 0o700,
- trusted_cert: 0o600,
+ :trust_dir => 0700,
+ :trusted_cert => 0600,
}.freeze
##
@@ -45,11 +45,13 @@ class Gem::Security::TrustDir
glob = File.join @dir, "*.pem"
Dir[glob].each do |certificate_file|
- certificate = load_certificate certificate_file
+ begin
+ certificate = load_certificate certificate_file
- yield certificate, certificate_file
- rescue OpenSSL::X509::CertificateError
- next # HACK: warn
+ yield certificate, certificate_file
+ rescue OpenSSL::X509::CertificateError
+ next # HACK warn
+ end
end
end
@@ -91,7 +93,7 @@ class Gem::Security::TrustDir
destination = cert_path certificate
- File.open destination, "wb", 0o600 do |io|
+ File.open destination, "wb", 0600 do |io|
io.write certificate.to_pem
io.chmod(@permissions[:trusted_cert])
end
@@ -109,9 +111,9 @@ class Gem::Security::TrustDir
"trust directory #{@dir} is not a directory" unless
File.directory? @dir
- FileUtils.chmod 0o700, @dir
+ FileUtils.chmod 0700, @dir
else
- FileUtils.mkdir_p @dir, mode: @permissions[:trust_dir]
+ FileUtils.mkdir_p @dir, :mode => @permissions[:trust_dir]
end
end
end
diff --git a/lib/rubygems/security_option.rb b/lib/rubygems/security_option.rb
index 3a101fe9db..f288ebd047 100644
--- a/lib/rubygems/security_option.rb
+++ b/lib/rubygems/security_option.rb
@@ -29,7 +29,7 @@ module Gem::SecurityOption
policy = Gem::Security::Policies[value]
unless policy
valid = Gem::Security::Policies.keys.sort
- raise Gem::OptionParser::InvalidArgument, "#{value} (#{valid.join ", "} are valid)"
+ raise Gem::OptionParser::InvalidArgument, "#{value} (#{valid.join ', '} are valid)"
end
policy
end
diff --git a/lib/rubygems/source.rb b/lib/rubygems/source.rb
index bee5681dab..aa0cbc1641 100644
--- a/lib/rubygems/source.rb
+++ b/lib/rubygems/source.rb
@@ -12,9 +12,9 @@ class Gem::Source
include Gem::Text
FILES = { # :nodoc:
- released: "specs",
- latest: "latest_specs",
- prerelease: "prerelease_specs",
+ :released => "specs",
+ :latest => "latest_specs",
+ :prerelease => "prerelease_specs",
}.freeze
##
@@ -44,18 +44,20 @@ class Gem::Source
Gem::Source::Vendor then
-1
when Gem::Source then
- unless @uri
+ if !@uri
return 0 unless other.uri
return 1
end
- return -1 unless other.uri
+ return -1 if !other.uri
# Returning 1 here ensures that when sorting a list of sources, the
# original ordering of sources supplied by the user is preserved.
return 1 unless @uri.to_s == other.uri.to_s
0
+ else
+ nil
end
end
@@ -69,7 +71,7 @@ class Gem::Source
# Returns a Set that can fetch specifications from this source.
def dependency_resolver_set # :nodoc:
- return Gem::Resolver::IndexSet.new self if uri.scheme == "file"
+ return Gem::Resolver::IndexSet.new self if "file" == uri.scheme
fetch_uri = if uri.host == "rubygems.org"
index_uri = uri.dup
@@ -79,7 +81,7 @@ class Gem::Source
uri
end
- bundler_api_uri = enforce_trailing_slash(fetch_uri) + "versions"
+ bundler_api_uri = enforce_trailing_slash(fetch_uri)
begin
fetcher = Gem::RemoteFetcher.fetcher
@@ -100,7 +102,8 @@ class Gem::Source
def cache_dir(uri)
# Correct for windows paths
- escaped_path = uri.path.sub(%r{^/([a-z]):/}i, '/\\1-/')
+ escaped_path = uri.path.sub(/^\/([a-z]):\//i, '/\\1-/')
+ escaped_path.tap(&Gem::UNTAINT)
File.join Gem.spec_cache_dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path)
end
@@ -134,12 +137,7 @@ class Gem::Source
if File.exist? local_spec
spec = Gem.read_binary local_spec
- Gem.load_safe_marshal
- spec = begin
- Gem::SafeMarshal.safe_load(spec)
- rescue StandardError
- nil
- end
+ spec = Marshal.load(spec) rescue nil
return spec if spec
end
@@ -157,9 +155,8 @@ class Gem::Source
end
end
- Gem.load_safe_marshal
# TODO: Investigate setting Gem::Specification#loaded_from to a URI
- Gem::SafeMarshal.safe_load spec
+ Marshal.load spec
end
##
@@ -189,9 +186,8 @@ class Gem::Source
spec_dump = fetcher.cache_update_path spec_path, local_file, update_cache?
- Gem.load_safe_marshal
begin
- Gem::NameTuple.from_list Gem::SafeMarshal.safe_load(spec_dump)
+ Gem::NameTuple.from_list Marshal.load(spec_dump)
rescue ArgumentError
if update_cache? && !retried
FileUtils.rm local_file
@@ -213,16 +209,14 @@ class Gem::Source
end
def pretty_print(q) # :nodoc:
- q.object_group(self) do
- q.group 2, "[Remote:", "]" do
- q.breakable
- q.text @uri.to_s
+ q.group 2, "[Remote:", "]" do
+ q.breakable
+ q.text @uri.to_s
- if api = uri
- q.breakable
- q.text "API URI: "
- q.text api.to_s
- end
+ if api = uri
+ q.breakable
+ q.text "API URI: "
+ q.text api.to_s
end
end
end
@@ -235,7 +229,7 @@ class Gem::Source
private
def enforce_trailing_slash(uri)
- uri.merge(uri.path.gsub(%r{/+$}, "") + "/")
+ uri.merge(uri.path.gsub(/\/+$/, "") + "/")
end
end
diff --git a/lib/rubygems/source/git.rb b/lib/rubygems/source/git.rb
index 34f6851bc4..7ac685f978 100644
--- a/lib/rubygems/source/git.rb
+++ b/lib/rubygems/source/git.rb
@@ -70,6 +70,8 @@ class Gem::Source::Git < Gem::Source
-1
when Gem::Source then
1
+ else
+ nil
end
end
@@ -157,14 +159,12 @@ class Gem::Source::Git < Gem::Source
end
def pretty_print(q) # :nodoc:
- q.object_group(self) do
- q.group 2, "[Git: ", "]" do
- q.breakable
- q.text @repository
+ q.group 2, "[Git: ", "]" do
+ q.breakable
+ q.text @repository
- q.breakable
- q.text @reference
- end
+ q.breakable
+ q.text @reference
end
end
@@ -223,14 +223,14 @@ class Gem::Source::Git < Gem::Source
end
##
- # A hash for the git gem based on the git repository Gem::URI.
+ # A hash for the git gem based on the git repository URI.
def uri_hash # :nodoc:
require_relative "../openssl"
normalized =
- if @repository.match?(%r{^\w+://(\w+@)?})
- uri = Gem::URI(@repository).normalize.to_s.sub %r{/$},""
+ if @repository =~ %r{^\w+://(\w+@)?}
+ uri = URI(@repository).normalize.to_s.sub %r{/$},""
uri.sub(/\A(\w+)/) { $1.downcase }
else
@repository
diff --git a/lib/rubygems/source/installed.rb b/lib/rubygems/source/installed.rb
index f5c96fee51..f5d3f06d6a 100644
--- a/lib/rubygems/source/installed.rb
+++ b/lib/rubygems/source/installed.rb
@@ -21,6 +21,8 @@ class Gem::Source::Installed < Gem::Source
0
when Gem::Source then
1
+ else
+ nil
end
end
@@ -32,8 +34,6 @@ class Gem::Source::Installed < Gem::Source
end
def pretty_print(q) # :nodoc:
- q.object_group(self) do
- q.text "[Installed]"
- end
+ q.text "[Installed]"
end
end
diff --git a/lib/rubygems/source/local.rb b/lib/rubygems/source/local.rb
index ba6eea1f9a..5068b0b906 100644
--- a/lib/rubygems/source/local.rb
+++ b/lib/rubygems/source/local.rb
@@ -24,12 +24,14 @@ class Gem::Source::Local < Gem::Source
0
when Gem::Source then
1
+ else
+ nil
end
end
def inspect # :nodoc:
keys = @specs ? @specs.keys.sort : "NOT LOADED"
- format("#<%s specs: %p>", self.class, keys)
+ "#<%s specs: %p>" % [self.class, keys]
end
def load_specs(type) # :nodoc:
@@ -39,35 +41,36 @@ class Gem::Source::Local < Gem::Source
@specs = {}
Dir["*.gem"].each do |file|
- pkg = Gem::Package.new(file)
- spec = pkg.spec
- rescue SystemCallError, Gem::Package::FormatError
- # ignore
- else
- tup = spec.name_tuple
- @specs[tup] = [File.expand_path(file), pkg]
-
- case type
- when :released
- unless pkg.spec.version.prerelease?
- names << pkg.spec.name_tuple
- end
- when :prerelease
- if pkg.spec.version.prerelease?
- names << pkg.spec.name_tuple
- end
- when :latest
+ begin
+ pkg = Gem::Package.new(file)
+ rescue SystemCallError, Gem::Package::FormatError
+ # ignore
+ else
tup = pkg.spec.name_tuple
-
- cur = names.find {|x| x.name == tup.name }
- if !cur
- names << tup
- elsif cur.version < tup.version
- names.delete cur
- names << tup
+ @specs[tup] = [File.expand_path(file), pkg]
+
+ case type
+ when :released
+ unless pkg.spec.version.prerelease?
+ names << pkg.spec.name_tuple
+ end
+ when :prerelease
+ if pkg.spec.version.prerelease?
+ names << pkg.spec.name_tuple
+ end
+ when :latest
+ tup = pkg.spec.name_tuple
+
+ cur = names.find {|x| x.name == tup.name }
+ if !cur
+ names << tup
+ elsif cur.version < tup.version
+ names.delete cur
+ names << tup
+ end
+ else
+ names << pkg.spec.name_tuple
end
- else
- names << pkg.spec.name_tuple
end
end
@@ -75,25 +78,27 @@ class Gem::Source::Local < Gem::Source
end
end
- def find_gem(gem_name, version = Gem::Requirement.default, prerelease = false) # :nodoc:
+ def find_gem(gem_name, version = Gem::Requirement.default, # :nodoc:
+ prerelease = false)
load_specs :complete
found = []
@specs.each do |n, data|
- next unless n.name == gem_name
- s = data[1].spec
-
- if version.satisfied_by?(s.version)
- if prerelease
- found << s
- elsif !s.version.prerelease? || version.prerelease?
- found << s
+ if n.name == gem_name
+ s = data[1].spec
+
+ if version.satisfied_by?(s.version)
+ if prerelease
+ found << s
+ elsif !s.version.prerelease? || version.prerelease?
+ found << s
+ end
end
end
end
- found.max_by(&:version)
+ found.max_by {|s| s.version }
end
def fetch_spec(name) # :nodoc:
@@ -109,7 +114,7 @@ class Gem::Source::Local < Gem::Source
def download(spec, cache_dir = nil) # :nodoc:
load_specs :complete
- @specs.each do |_name, data|
+ @specs.each do |name, data|
return data[0] if data[1].spec == spec
end
@@ -117,14 +122,10 @@ class Gem::Source::Local < Gem::Source
end
def pretty_print(q) # :nodoc:
- q.object_group(self) do
- q.group 2, "[Local gems:", "]" do
- q.breakable
- if @specs
- q.seplist @specs.keys do |v|
- q.text v.full_name
- end
- end
+ q.group 2, "[Local gems:", "]" do
+ q.breakable
+ q.seplist @specs.keys do |v|
+ q.text v.full_name
end
end
end
diff --git a/lib/rubygems/source/lock.rb b/lib/rubygems/source/lock.rb
index 70849210bd..f9388bbd61 100644
--- a/lib/rubygems/source/lock.rb
+++ b/lib/rubygems/source/lock.rb
@@ -25,11 +25,13 @@ class Gem::Source::Lock < Gem::Source
@wrapped <=> other.wrapped
when Gem::Source then
1
+ else
+ nil
end
end
def ==(other) # :nodoc:
- (self <=> other) == 0
+ 0 == (self <=> other)
end
def hash # :nodoc:
diff --git a/lib/rubygems/source/specific_file.rb b/lib/rubygems/source/specific_file.rb
index dde1d48a21..61965c2644 100644
--- a/lib/rubygems/source/specific_file.rb
+++ b/lib/rubygems/source/specific_file.rb
@@ -34,6 +34,7 @@ class Gem::Source::SpecificFile < Gem::Source
def fetch_spec(name) # :nodoc:
return @spec if name == @name
raise Gem::Exception, "Unable to find '#{name}'"
+ @spec
end
def download(spec, dir = nil) # :nodoc:
@@ -42,11 +43,9 @@ class Gem::Source::SpecificFile < Gem::Source
end
def pretty_print(q) # :nodoc:
- q.object_group(self) do
- q.group 2, "[SpecificFile:", "]" do
- q.breakable
- q.text @path
- end
+ q.group 2, "[SpecificFile:", "]" do
+ q.breakable
+ q.text @path
end
end
diff --git a/lib/rubygems/source/vendor.rb b/lib/rubygems/source/vendor.rb
index 44ef614441..12161b8cf5 100644
--- a/lib/rubygems/source/vendor.rb
+++ b/lib/rubygems/source/vendor.rb
@@ -19,6 +19,8 @@ class Gem::Source::Vendor < Gem::Source::Installed
0
when Gem::Source then
1
+ else
+ nil
end
end
end
diff --git a/lib/rubygems/source_list.rb b/lib/rubygems/source_list.rb
index 33db64fbc1..7abe796409 100644
--- a/lib/rubygems/source_list.rb
+++ b/lib/rubygems/source_list.rb
@@ -36,7 +36,7 @@ class Gem::SourceList
list.replace ary
- list
+ return list
end
def initialize_copy(other) # :nodoc:
@@ -44,15 +44,15 @@ class Gem::SourceList
end
##
- # Appends +obj+ to the source list which may be a Gem::Source, Gem::URI or URI
+ # Appends +obj+ to the source list which may be a Gem::Source, URI or URI
# String.
def <<(obj)
src = case obj
- when Gem::Source
- obj
- else
- Gem::Source.new(obj)
+ when Gem::Source
+ obj
+ else
+ Gem::Source.new(obj)
end
@sources << src unless @sources.include?(src)
@@ -126,7 +126,7 @@ class Gem::SourceList
# Gem::Source or a source URI.
def include?(other)
- if other.is_a? Gem::Source
+ if other.kind_of? Gem::Source
@sources.include? other
else
@sources.find {|x| x.uri.to_s == other.to_s }
@@ -137,7 +137,7 @@ class Gem::SourceList
# Deletes +source+ from the source list which may be a Gem::Source or a URI.
def delete(source)
- if source.is_a? Gem::Source
+ if source.kind_of? Gem::Source
@sources.delete source
else
@sources.delete_if {|x| x.uri.to_s == source.to_s }
diff --git a/lib/rubygems/spec_fetcher.rb b/lib/rubygems/spec_fetcher.rb
index 9c0399f196..a5a4fa0c0f 100644
--- a/lib/rubygems/spec_fetcher.rb
+++ b/lib/rubygems/spec_fetcher.rb
@@ -69,9 +69,9 @@ class Gem::SpecFetcher
@prerelease_specs = {}
@caches = {
- latest: @latest_specs,
- prerelease: @prerelease_specs,
- released: @specs,
+ :latest => @latest_specs,
+ :prerelease => @prerelease_specs,
+ :released => @specs,
}
@fetcher = Gem::RemoteFetcher.fetcher
@@ -92,9 +92,9 @@ class Gem::SpecFetcher
list.each do |source, specs|
if dependency.name.is_a?(String) && specs.respond_to?(:bsearch)
- start_index = (0...specs.length).bsearch {|i| specs[i].name >= dependency.name }
- end_index = (0...specs.length).bsearch {|i| specs[i].name > dependency.name }
- specs = specs[start_index...end_index] if start_index && end_index
+ start_index = (0 ... specs.length).bsearch {|i| specs[i].name >= dependency.name }
+ end_index = (0 ... specs.length).bsearch {|i| specs[i].name > dependency.name }
+ specs = specs[start_index ... end_index] if start_index && end_index
end
found[source] = specs.select do |tup|
@@ -124,7 +124,7 @@ class Gem::SpecFetcher
tuples = tuples.sort_by {|x| x[0].version }
- [tuples, errors]
+ return [tuples, errors]
end
##
@@ -155,14 +155,16 @@ class Gem::SpecFetcher
specs = []
tuples.each do |tup, source|
- spec = source.fetch_spec(tup)
- rescue Gem::RemoteFetcher::FetchError => e
- errors << Gem::SourceFetchProblem.new(source, e)
- else
- specs << [spec, source]
+ begin
+ spec = source.fetch_spec(tup)
+ rescue Gem::RemoteFetcher::FetchError => e
+ errors << Gem::SourceFetchProblem.new(source, e)
+ else
+ specs << [spec, source]
+ end
end
- [specs, errors]
+ return [specs, errors]
end
##
@@ -176,19 +178,26 @@ class Gem::SpecFetcher
matches = names.map do |n|
next unless n.match_platform?
- distance = levenshtein_distance gem_name, n.name.downcase.tr("_-", "")
- next if distance >= max
- return [n.name] if distance == 0
- [n.name, distance]
+ [n.name, 0] if n.name.downcase.tr("_-", "").include?(gem_name)
end.compact
+ if matches.length < num_results
+ matches += names.map do |n|
+ next unless n.match_platform?
+ distance = levenshtein_distance gem_name, n.name.downcase.tr("_-", "")
+ next if distance >= max
+ return [n.name] if distance == 0
+ [n.name, distance]
+ end.compact
+ end
+
matches = if matches.empty? && type != :prerelease
suggest_gems_from_name gem_name, :prerelease
else
- matches.uniq.sort_by {|_name, dist| dist }
+ matches.uniq.sort_by {|name, dist| dist }
end
- matches.map {|name, _dist| name }.uniq.first(num_results)
+ matches.map {|name, dist| name }.uniq.first(num_results)
end
##
@@ -206,32 +215,34 @@ class Gem::SpecFetcher
list = {}
@sources.each_source do |source|
- names = case type
- when :latest
- tuples_for source, :latest
- when :released
- tuples_for source, :released
- when :complete
- names =
- tuples_for(source, :prerelease, true) +
- tuples_for(source, :released)
-
- names.sort
- when :abs_latest
- names =
- tuples_for(source, :prerelease, true) +
- tuples_for(source, :latest)
-
- names.sort
- when :prerelease
- tuples_for(source, :prerelease)
- else
- raise Gem::Exception, "Unknown type - :#{type}"
+ begin
+ names = case type
+ when :latest
+ tuples_for source, :latest
+ when :released
+ tuples_for source, :released
+ when :complete
+ names =
+ tuples_for(source, :prerelease, true) +
+ tuples_for(source, :released)
+
+ names.sort
+ when :abs_latest
+ names =
+ tuples_for(source, :prerelease, true) +
+ tuples_for(source, :latest)
+
+ names.sort
+ when :prerelease
+ tuples_for(source, :prerelease)
+ else
+ raise Gem::Exception, "Unknown type - :#{type}"
+ end
+ rescue Gem::RemoteFetcher::FetchError => e
+ errors << Gem::SourceFetchProblem.new(source, e)
+ else
+ list[source] = names
end
- rescue Gem::RemoteFetcher::FetchError => e
- errors << Gem::SourceFetchProblem.new(source, e)
- else
- list[source] = names
end
[list, errors]
@@ -243,7 +254,7 @@ class Gem::SpecFetcher
def tuples_for(source, type, gracefully_ignore=false) # :nodoc:
@caches[type][source.uri] ||=
- source.load_specs(type).sort_by(&:name)
+ source.load_specs(type).sort_by {|tup| tup.name }
rescue Gem::RemoteFetcher::FetchError
raise unless gracefully_ignore
[]
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index e5541e57b1..7611e1ba1f 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -11,11 +11,8 @@ require_relative "deprecate"
require_relative "basic_specification"
require_relative "stub_specification"
require_relative "platform"
-require_relative "specification_record"
require_relative "util/list"
-require "rbconfig"
-
##
# The Specification class contains the information for a gem. Typically
# defined in a .gemspec file or a Rakefile, and looks like this:
@@ -109,7 +106,7 @@ class Gem::Specification < Gem::BasicSpecification
@load_cache = {} # :nodoc:
@load_cache_mutex = Thread::Mutex.new
- VALID_NAME_PATTERN = /\A[a-zA-Z0-9\.\-\_]+\z/ # :nodoc:
+ VALID_NAME_PATTERN = /\A[a-zA-Z0-9\.\-\_]+\z/.freeze # :nodoc:
# :startdoc:
@@ -128,35 +125,35 @@ class Gem::Specification < Gem::BasicSpecification
# Map of attribute names to default values.
@@default_value = {
- authors: [],
- autorequire: nil,
- bindir: "bin",
- cert_chain: [],
- date: nil,
- dependencies: [],
- description: nil,
- email: nil,
- executables: [],
- extensions: [],
- extra_rdoc_files: [],
- files: [],
- homepage: nil,
- licenses: [],
- metadata: {},
- name: nil,
- platform: Gem::Platform::RUBY,
- post_install_message: nil,
- rdoc_options: [],
- require_paths: ["lib"],
- required_ruby_version: Gem::Requirement.default,
- required_rubygems_version: Gem::Requirement.default,
- requirements: [],
- rubygems_version: Gem::VERSION,
- signing_key: nil,
- specification_version: CURRENT_SPECIFICATION_VERSION,
- summary: nil,
- test_files: [],
- version: nil,
+ :authors => [],
+ :autorequire => nil,
+ :bindir => "bin",
+ :cert_chain => [],
+ :date => nil,
+ :dependencies => [],
+ :description => nil,
+ :email => nil,
+ :executables => [],
+ :extensions => [],
+ :extra_rdoc_files => [],
+ :files => [],
+ :homepage => nil,
+ :licenses => [],
+ :metadata => {},
+ :name => nil,
+ :platform => Gem::Platform::RUBY,
+ :post_install_message => nil,
+ :rdoc_options => [],
+ :require_paths => ["lib"],
+ :required_ruby_version => Gem::Requirement.default,
+ :required_rubygems_version => Gem::Requirement.default,
+ :requirements => [],
+ :rubygems_version => Gem::VERSION,
+ :signing_key => nil,
+ :specification_version => CURRENT_SPECIFICATION_VERSION,
+ :summary => nil,
+ :test_files => [],
+ :version => nil,
}.freeze
# rubocop:disable Style/MutableConstant
@@ -165,27 +162,39 @@ class Gem::Specification < Gem::BasicSpecification
@@default_value.each do |k,v|
INITIALIZE_CODE_FOR_DEFAULTS[k] = case v
- when [], {}, true, false, nil, Numeric, Symbol
- v.inspect
- when String
- v.dump
- else
- "default_value(:#{k}).dup"
+ when [], {}, true, false, nil, Numeric, Symbol
+ v.inspect
+ when String
+ v.dump
+ when Numeric
+ "default_value(:#{k})"
+ else
+ "default_value(:#{k}).dup"
end
end
- @@attributes = @@default_value.keys.sort_by(&:to_s)
- @@array_attributes = @@default_value.select {|_k,v| v.is_a?(Array) }.keys
+ @@attributes = @@default_value.keys.sort_by {|s| s.to_s }
+ @@array_attributes = @@default_value.reject {|k,v| v != [] }.keys
@@nil_attributes, @@non_nil_attributes = @@default_value.keys.partition do |k|
@@default_value[k].nil?
end
+ def self.clear_specs # :nodoc:
+ @@all = nil
+ @@stubs = nil
+ @@stubs_by_name = {}
+ @@spec_with_requirable_file = {}
+ @@active_stub_with_requirable_file = {}
+ end
+ private_class_method :clear_specs
+
+ clear_specs
+
# Sentinel object to represent "not found" stubs
NOT_FOUND = Struct.new(:to_spec, :this).new # :nodoc:
- deprecate_constant :NOT_FOUND
# Tracking removed method calls to warn users during build time.
- REMOVED_METHODS = [:rubyforge_project=, :mark_version].freeze # :nodoc:
+ REMOVED_METHODS = [:rubyforge_project=].freeze # :nodoc:
def removed_method_calls
@removed_method_calls ||= []
end
@@ -254,7 +263,8 @@ class Gem::Specification < Gem::BasicSpecification
@test_files,
add_bindir(@executables),
@extra_rdoc_files,
- @extensions].flatten.compact.uniq.sort
+ @extensions,
+ ].flatten.compact.uniq.sort
end
##
@@ -292,7 +302,7 @@ class Gem::Specification < Gem::BasicSpecification
#
# Usage:
#
- # spec.description = <<~EOF
+ # spec.description = <<-EOF
# Rake is a Make-like program implemented in Ruby. Tasks and
# dependencies are specified in standard Ruby syntax.
# EOF
@@ -332,7 +342,7 @@ class Gem::Specification < Gem::BasicSpecification
# https://opensource.org/licenses/ approved.
#
# The most commonly used OSI-approved licenses are MIT and Apache-2.0.
- # GitHub also provides a license picker at https://choosealicense.com/.
+ # GitHub also provides a license picker at http://choosealicense.com/.
#
# You can also use a custom license file along with your gemspec and specify
# a LicenseRef-<idstring>, where idstring is the name of the file containing
@@ -417,11 +427,11 @@ class Gem::Specification < Gem::BasicSpecification
end
##
- # The path in the gem for executable scripts. Usually 'exe'
+ # The path in the gem for executable scripts. Usually 'bin'
#
# Usage:
#
- # spec.bindir = 'exe'
+ # spec.bindir = 'bin'
attr_accessor :bindir
@@ -493,6 +503,8 @@ class Gem::Specification < Gem::BasicSpecification
@platform = @new_platform.to_s
invalidate_memoized_attributes
+
+ @new_platform
end
##
@@ -522,6 +534,13 @@ class Gem::Specification < Gem::BasicSpecification
attr_reader :required_rubygems_version
##
+ # The version of RubyGems used to create this gem.
+ #
+ # Do not set this, it is set automatically when the gem is packaged.
+
+ attr_accessor :rubygems_version
+
+ ##
# The key used to sign this gem. See Gem::Security for details.
attr_accessor :signing_key
@@ -546,9 +565,9 @@ class Gem::Specification < Gem::BasicSpecification
#
# Usage:
#
- # spec.add_dependency 'example', '~> 1.1', '>= 1.1.4'
+ # spec.add_runtime_dependency 'example', '~> 1.1', '>= 1.1.4'
- def add_dependency(gem, *requirements)
+ def add_runtime_dependency(gem, *requirements)
if requirements.uniq.size != requirements.size
warn "WARNING: duplicated #{gem} dependency #{requirements}"
end
@@ -559,7 +578,7 @@ class Gem::Specification < Gem::BasicSpecification
##
# Executables included in the gem.
#
- # For example, the rake gem has rake as an executable. You don't specify the
+ # For example, the rake gem has rake as an executable. You don’t specify the
# full path (as in bin/rake); all application-style files are expected to be
# found in bindir. These files must be executable Ruby files. Files that
# use bash or other interpreters will not work.
@@ -580,7 +599,7 @@ class Gem::Specification < Gem::BasicSpecification
# extconf.rb-style files used to compile extensions.
#
# These files will be run when the gem is installed, causing the C (or
- # whatever) code to be compiled on the user's machine.
+ # whatever) code to be compiled on the user’s machine.
#
# Usage:
#
@@ -709,21 +728,6 @@ class Gem::Specification < Gem::BasicSpecification
end
######################################################################
- # :section: Read-only attributes
-
- ##
- # The version of RubyGems used to create this gem.
-
- attr_accessor :rubygems_version
-
- ##
- # The path where this gem installs its extensions.
-
- def extensions_dir
- @extensions_dir ||= super
- end
-
- ######################################################################
# :section: Specification internals
##
@@ -731,7 +735,7 @@ class Gem::Specification < Gem::BasicSpecification
attr_accessor :activated
- alias_method :activated?, :activated
+ alias :activated? :activated
##
# Autorequire was used by old RubyGems to automatically require a file.
@@ -761,7 +765,7 @@ class Gem::Specification < Gem::BasicSpecification
attr_accessor :specification_version
def self._all # :nodoc:
- specification_record.all
+ @@all ||= Gem.loaded_specs.values | stubs.map(&:to_spec)
end
def self.clear_load_cache # :nodoc:
@@ -771,22 +775,34 @@ class Gem::Specification < Gem::BasicSpecification
end
private_class_method :clear_load_cache
- def self.gem_path # :nodoc:
- Gem.path
- end
- private_class_method :gem_path
-
def self.each_gemspec(dirs) # :nodoc:
dirs.each do |dir|
Gem::Util.glob_files_in_dir("*.gemspec", dir).each do |path|
- yield path
+ yield path.tap(&Gem::UNTAINT)
end
end
end
- def self.gemspec_stubs_in(dir, pattern) # :nodoc:
+ def self.gemspec_stubs_in(dir, pattern)
Gem::Util.glob_files_in_dir(pattern, dir).map {|path| yield path }.select(&:valid?)
end
+ private_class_method :gemspec_stubs_in
+
+ def self.installed_stubs(dirs, pattern)
+ map_stubs(dirs, pattern) do |path, base_dir, gems_dir|
+ Gem::StubSpecification.gemspec_stub(path, base_dir, gems_dir)
+ end
+ end
+ private_class_method :installed_stubs
+
+ def self.map_stubs(dirs, pattern) # :nodoc:
+ dirs.flat_map do |dir|
+ base_dir = File.dirname dir
+ gems_dir = File.join base_dir, "gems"
+ gemspec_stubs_in(dir, pattern) {|path| yield path, base_dir, gems_dir }
+ end
+ end
+ private_class_method :map_stubs
def self.each_spec(dirs) # :nodoc:
each_gemspec(dirs) do |path|
@@ -799,7 +815,13 @@ class Gem::Specification < Gem::BasicSpecification
# Returns a Gem::StubSpecification for every installed gem
def self.stubs
- specification_record.stubs
+ @@stubs ||= begin
+ pattern = "*.gemspec"
+ stubs = stubs_for_pattern(pattern, false)
+
+ @@stubs_by_name = stubs.select {|s| Gem::Platform.match_spec? s }.group_by(&:name)
+ stubs
+ end
end
##
@@ -818,7 +840,13 @@ class Gem::Specification < Gem::BasicSpecification
# only returns stubs that match Gem.platforms
def self.stubs_for(name)
- specification_record.stubs_for(name)
+ if @@stubs
+ @@stubs_by_name[name] || []
+ else
+ @@stubs_by_name[name] ||= stubs_for_pattern("#{name}-*.gemspec").select do |s|
+ s.name == name
+ end
+ end
end
##
@@ -826,7 +854,12 @@ class Gem::Specification < Gem::BasicSpecification
# optionally filtering out specs not matching the current platform
#
def self.stubs_for_pattern(pattern, match_platform = true) # :nodoc:
- specification_record.stubs_for_pattern(pattern, match_platform)
+ installed_stubs = installed_stubs(Gem::Specification.dirs, pattern)
+ installed_stubs.select! {|s| Gem::Platform.match_spec? s } if match_platform
+ stubs = installed_stubs + default_stubs(pattern)
+ stubs = stubs.uniq {|stub| stub.full_name }
+ _resort!(stubs)
+ stubs
end
def self._resort!(specs) # :nodoc:
@@ -835,11 +868,7 @@ class Gem::Specification < Gem::BasicSpecification
next names if names.nonzero?
versions = b.version <=> a.version
next versions if versions.nonzero?
- platforms = Gem::Platform.sort_priority(b.platform) <=> Gem::Platform.sort_priority(a.platform)
- next platforms if platforms.nonzero?
- default_gem = a.default_gem_priority <=> b.default_gem_priority
- next default_gem if default_gem.nonzero?
- a.base_dir_priority(gem_path) <=> b.base_dir_priority(gem_path)
+ Gem::Platform.sort_priority(b.platform)
end
end
@@ -859,14 +888,23 @@ class Gem::Specification < Gem::BasicSpecification
# properly sorted.
def self.add_spec(spec)
- specification_record.add_spec(spec)
+ return if _all.include? spec
+
+ _all << spec
+ stubs << spec
+ (@@stubs_by_name[spec.name] ||= []) << spec
+
+ _resort!(@@stubs_by_name[spec.name])
+ _resort!(stubs)
end
##
# Removes +spec+ from the known specs.
def self.remove_spec(spec)
- specification_record.remove_spec(spec)
+ _all.delete spec.to_spec
+ stubs.delete spec
+ (@@stubs_by_name[spec.name] || []).delete spec
end
##
@@ -874,23 +912,33 @@ class Gem::Specification < Gem::BasicSpecification
# You probably want to use one of the Enumerable methods instead.
def self.all
- warn "NOTE: Specification.all called from #{caller(1, 1).first}" unless
+ warn "NOTE: Specification.all called from #{caller.first}" unless
Gem::Deprecate.skip
_all
end
##
- # Sets the known specs to +specs+.
+ # Sets the known specs to +specs+. Not guaranteed to work for you in
+ # the future. Use at your own risk. Caveat emptor. Doomy doom doom.
+ # Etc etc.
+ #
+ #--
+ # Makes +specs+ the known specs
+ # Listen, time is a river
+ # Winter comes, code breaks
+ #
+ # -- wilsonb
def self.all=(specs)
- specification_record.all = specs
+ @@stubs_by_name = specs.group_by(&:name)
+ @@all = @@stubs = specs
end
##
# Return full names of all specs in sorted order.
def self.all_names
- specification_record.all_names
+ self._all.map(&:full_name)
end
##
@@ -915,7 +963,9 @@ class Gem::Specification < Gem::BasicSpecification
# Return the directories that Specification uses to find specs.
def self.dirs
- @@dirs ||= Gem::SpecificationRecord.dirs_from(gem_path)
+ @@dirs ||= Gem.path.collect do |dir|
+ File.join dir.dup.tap(&Gem::UNTAINT), "specifications"
+ end
end
##
@@ -923,9 +973,9 @@ class Gem::Specification < Gem::BasicSpecification
# this resets the list of known specs.
def self.dirs=(dirs)
- reset
+ self.reset
- @@dirs = Gem::SpecificationRecord.dirs_from(Array(dirs))
+ @@dirs = Array(dirs).map {|dir| File.join dir, "specifications" }
end
extend Enumerable
@@ -934,15 +984,23 @@ class Gem::Specification < Gem::BasicSpecification
# Enumerate every known spec. See ::dirs= and ::add_spec to set the list of
# specs.
- def self.each(&block)
- specification_record.each(&block)
+ def self.each
+ return enum_for(:each) unless block_given?
+
+ self._all.each do |x|
+ yield x
+ end
end
##
# Returns every spec that matches +name+ and optional +requirements+.
def self.find_all_by_name(name, *requirements)
- specification_record.find_all_by_name(name, *requirements)
+ requirements = Gem::Requirement.default if requirements.empty?
+
+ # TODO: maybe try: find_all { |s| spec === dep }
+
+ Gem::Dependency.new(name, *requirements).matching_specs
end
##
@@ -959,6 +1017,8 @@ class Gem::Specification < Gem::BasicSpecification
def self.find_by_name(name, *requirements)
requirements = Gem::Requirement.default if requirements.empty?
+ # TODO: maybe try: find { |s| spec === dep }
+
Gem::Dependency.new(name, *requirements).to_spec
end
@@ -972,7 +1032,11 @@ class Gem::Specification < Gem::BasicSpecification
# Return the best specification that contains the file matching +path+.
def self.find_by_path(path)
- specification_record.find_by_path(path)
+ path = path.dup.freeze
+ spec = @@spec_with_requirable_file[path] ||= (stubs.find do |s|
+ s.contains_requirable_file? path
+ end || NOT_FOUND)
+ spec.to_spec
end
##
@@ -980,15 +1044,18 @@ class Gem::Specification < Gem::BasicSpecification
# amongst the specs that are not activated.
def self.find_inactive_by_path(path)
- specification_record.find_inactive_by_path(path)
+ stub = stubs.find do |s|
+ next if s.activated?
+ s.contains_requirable_file? path
+ end
+ stub&.to_spec
end
- ##
- # Return the best specification that contains the file matching +path+, among
- # those already activated.
-
def self.find_active_stub_by_path(path)
- specification_record.find_active_stub_by_path(path)
+ stub = @@active_stub_with_requirable_file[path] ||= (stubs.find do |s|
+ s.activated? && s.contains_requirable_file?(path)
+ end || NOT_FOUND)
+ stub.this
end
##
@@ -1004,7 +1071,7 @@ class Gem::Specification < Gem::BasicSpecification
def self.find_in_unresolved_tree(path)
unresolved_specs.each do |spec|
- spec.traverse do |_from_spec, _dep, to_spec, trail|
+ spec.traverse do |from_spec, dep, to_spec, trail|
if to_spec.has_conflicts? || to_spec.conficts_when_loaded_with?(trail)
:next
else
@@ -1017,7 +1084,7 @@ class Gem::Specification < Gem::BasicSpecification
end
def self.unresolved_specs
- unresolved_deps.values.map(&:to_specs).flatten
+ unresolved_deps.values.map {|dep| dep.to_specs }.flatten
end
private_class_method :unresolved_specs
@@ -1055,28 +1122,26 @@ class Gem::Specification < Gem::BasicSpecification
# +prerelease+ is true.
def self.latest_specs(prerelease = false)
- specification_record.latest_specs(prerelease)
+ _latest_specs Gem::Specification.stubs, prerelease
end
##
# Return the latest installed spec for gem +name+.
def self.latest_spec_for(name)
- specification_record.latest_spec_for(name)
+ latest_specs(true).find {|installed_spec| installed_spec.name == name }
end
def self._latest_specs(specs, prerelease = false) # :nodoc:
result = {}
specs.reverse_each do |spec|
- unless prerelease
- next if spec.version.prerelease?
- end
+ next if spec.version.prerelease? unless prerelease
result[spec.name] = spec
end
- result.map(&:last).flatten.sort_by(&:name)
+ result.map(&:last).flatten.sort_by {|tup| tup.name }
end
##
@@ -1085,33 +1150,36 @@ class Gem::Specification < Gem::BasicSpecification
def self.load(file)
return unless file
- spec = @load_cache_mutex.synchronize { @load_cache[file] }
- return spec if spec
+ _spec = @load_cache_mutex.synchronize { @load_cache[file] }
+ return _spec if _spec
+ file = file.dup.tap(&Gem::UNTAINT)
return unless File.file?(file)
code = Gem.open_file(file, "r:UTF-8:-", &:read)
+ code.tap(&Gem::UNTAINT)
+
begin
- spec = eval code, binding, file
+ _spec = eval code, binding, file
- if Gem::Specification === spec
- spec.loaded_from = File.expand_path file.to_s
+ if Gem::Specification === _spec
+ _spec.loaded_from = File.expand_path file.to_s
@load_cache_mutex.synchronize do
prev = @load_cache[file]
if prev
- spec = prev
+ _spec = prev
else
- @load_cache[file] = spec
+ @load_cache[file] = _spec
end
end
- return spec
+ return _spec
end
- warn "[#{file}] isn't a Gem::Specification (#{spec.class} instead)."
+ warn "[#{file}] isn't a Gem::Specification (#{_spec.class} instead)."
rescue SignalException, SystemExit
raise
- rescue SyntaxError, StandardError => e
+ rescue SyntaxError, Exception => e
warn "Invalid gemspec in [#{file}]: #{e}"
end
@@ -1199,8 +1267,8 @@ class Gem::Specification < Gem::BasicSpecification
def self.reset
@@dirs = nil
- Gem.pre_reset_hooks.each(&:call)
- @specification_record = nil
+ Gem.pre_reset_hooks.each {|hook| hook.call }
+ clear_specs
clear_load_cache
unresolved = unresolved_deps
unless unresolved.empty?
@@ -1208,7 +1276,7 @@ class Gem::Specification < Gem::BasicSpecification
unresolved.values.each do |dep|
warn " #{dep}"
- versions = find_all_by_name(dep.name).uniq(&:full_name)
+ versions = find_all_by_name(dep.name)
unless versions.empty?
warn " Available/installed versions of this gem:"
versions.each {|s| warn " - #{s.version}" }
@@ -1218,14 +1286,7 @@ class Gem::Specification < Gem::BasicSpecification
warn "Please report a bug if this causes problems."
unresolved.clear
end
- Gem.post_reset_hooks.each(&:call)
- end
-
- ##
- # Keeps track of all currently known specifications
-
- def self.specification_record
- @specification_record ||= Gem::SpecificationRecord.new(dirs)
+ Gem.post_reset_hooks.each {|hook| hook.call }
end
# DOC: This method needs documented or nodoc'd
@@ -1238,23 +1299,12 @@ class Gem::Specification < Gem::BasicSpecification
def self._load(str)
Gem.load_yaml
- Gem.load_safe_marshal
yaml_set = false
- retry_count = 0
array = begin
- Gem::SafeMarshal.safe_load str
+ Marshal.load str
rescue ArgumentError => e
- # Avoid an infinite retry loop when the argument error has nothing to do
- # with the classes not being defined.
- # 1 retry each allowed in case all 3 of
- # - YAML
- # - YAML::Syck::DefaultKey
- # - YAML::PrivateType
- # need to be defined
- raise if retry_count >= 3
-
#
# Some very old marshaled specs included references to `YAML::PrivateType`
# and `YAML::Syck::DefaultKey` constants due to bugs in the old emitter
@@ -1272,12 +1322,11 @@ class Gem::Specification < Gem::BasicSpecification
if message.include?("YAML::Syck::")
YAML.const_set "Syck", YAML unless YAML.const_defined?(:Syck)
- YAML::Syck.const_set "DefaultKey", Class.new if message.include?("YAML::Syck::DefaultKey") && !YAML::Syck.const_defined?(:DefaultKey)
- elsif message.include?("YAML::PrivateType") && !YAML.const_defined?(:PrivateType)
+ YAML::Syck.const_set "DefaultKey", Class.new if message.include?("YAML::Syck::DefaultKey")
+ elsif message.include?("YAML::PrivateType")
YAML.const_set "PrivateType", Class.new
end
- retry_count += 1
retry
ensure
Object.__send__(:remove_const, "YAML") if yaml_set
@@ -1318,7 +1367,7 @@ class Gem::Specification < Gem::BasicSpecification
spec.instance_variable_set :@has_rdoc, array[15]
spec.instance_variable_set :@new_platform, array[16]
spec.instance_variable_set :@platform, array[16].to_s
- spec.instance_variable_set :@licenses, [array[17]]
+ spec.instance_variable_set :@license, array[17]
spec.instance_variable_set :@metadata, array[18]
spec.instance_variable_set :@loaded, false
spec.instance_variable_set :@activated, false
@@ -1374,7 +1423,7 @@ class Gem::Specification < Gem::BasicSpecification
# there are conflicts upon activation.
def activate
- other = Gem.loaded_specs[name]
+ other = Gem.loaded_specs[self.name]
if other
check_version_conflict other
return false
@@ -1385,11 +1434,11 @@ class Gem::Specification < Gem::BasicSpecification
activate_dependencies
add_self_to_load_path
- Gem.loaded_specs[name] = self
+ Gem.loaded_specs[self.name] = self
@activated = true
@loaded = true
- true
+ return true
end
##
@@ -1400,7 +1449,7 @@ class Gem::Specification < Gem::BasicSpecification
def activate_dependencies
unresolved = Gem::Specification.unresolved_deps
- runtime_dependencies.each do |spec_dep|
+ self.runtime_dependencies.each do |spec_dep|
if loaded = Gem.loaded_specs[spec_dep.name]
next if spec_dep.matches_spec? loaded
@@ -1412,9 +1461,9 @@ class Gem::Specification < Gem::BasicSpecification
end
begin
- specs = spec_dep.to_specs.uniq(&:full_name)
+ specs = spec_dep.to_specs
rescue Gem::MissingSpecError => e
- raise Gem::MissingSpecError.new(e.name, e.requirement, "at: #{spec_file}")
+ raise Gem::MissingSpecError.new(e.name, e.requirement, "at: #{self.spec_file}")
end
if specs.size == 1
@@ -1460,7 +1509,7 @@ class Gem::Specification < Gem::BasicSpecification
def sanitize_string(string)
return string unless string
- # HACK: the #to_s is in here because RSpec has an Array of Arrays of
+ # HACK the #to_s is in here because RSpec has an Array of Arrays of
# Strings for authors. Need a way to disallow bad values on gemspec
# generation. (Probably won't happen.)
string.to_s
@@ -1478,8 +1527,8 @@ class Gem::Specification < Gem::BasicSpecification
else
executables
end
- rescue StandardError
- nil
+ rescue
+ return nil
end
##
@@ -1504,7 +1553,7 @@ class Gem::Specification < Gem::BasicSpecification
private :add_dependency_with_type
- alias_method :add_runtime_dependency, :add_dependency
+ alias add_dependency add_runtime_dependency
##
# Adds this spec's require paths to LOAD_PATH, in the proper location.
@@ -1556,7 +1605,7 @@ class Gem::Specification < Gem::BasicSpecification
def build_args
if File.exist? build_info_file
build_info = File.readlines build_info_file
- build_info = build_info.map(&:strip)
+ build_info = build_info.map {|x| x.strip }
build_info.delete ""
build_info
else
@@ -1574,8 +1623,8 @@ class Gem::Specification < Gem::BasicSpecification
# we need to fresh build when same name and version of default gems
return if self.class.find_by_full_name(full_name)&.default_gem?
return if File.exist? gem_build_complete_path
- return unless File.writable?(base_dir)
- return unless File.exist?(File.join(base_dir, "extensions"))
+ return if !File.writable?(base_dir)
+ return if !File.exist?(File.join(base_dir, "extensions"))
begin
# We need to require things in $LOAD_PATH without looking for the
@@ -1633,7 +1682,7 @@ class Gem::Specification < Gem::BasicSpecification
def conflicts
conflicts = {}
- runtime_dependencies.each do |dep|
+ self.runtime_dependencies.each do |dep|
spec = Gem.loaded_specs[dep.name]
if spec && !spec.satisfies_requirement?(dep)
(conflicts[spec] ||= []) << dep
@@ -1649,7 +1698,7 @@ class Gem::Specification < Gem::BasicSpecification
def conficts_when_loaded_with?(list_of_specs) # :nodoc:
result = list_of_specs.any? do |spec|
- spec.runtime_dependencies.any? {|dep| (dep.name == name) && !satisfies_requirement?(dep) }
+ spec.dependencies.any? {|dep| dep.runtime? && (dep.name == name) && !satisfies_requirement?(dep) }
end
result
end
@@ -1659,12 +1708,14 @@ class Gem::Specification < Gem::BasicSpecification
def has_conflicts?
return true unless Gem.env_requirement(name).satisfied_by?(version)
- runtime_dependencies.any? do |dep|
- spec = Gem.loaded_specs[dep.name]
- spec && !spec.satisfies_requirement?(dep)
+ self.dependencies.any? do |dep|
+ if dep.runtime?
+ spec = Gem.loaded_specs[dep.name]
+ spec && !spec.satisfies_requirement?(dep)
+ else
+ false
+ end
end
- rescue ArgumentError => e
- raise e, "#{name} #{version}: #{e.message}"
end
# The date this gem was created.
@@ -1688,7 +1739,7 @@ class Gem::Specification < Gem::BasicSpecification
/\A
(\d{4})-(\d{2})-(\d{2})
(\s+ \d{2}:\d{2}:\d{2}\.\d+ \s* (Z | [-+]\d\d:\d\d) )?
- \Z/x
+ \Z/x.freeze
##
# The date this gem was created
@@ -1700,17 +1751,17 @@ class Gem::Specification < Gem::BasicSpecification
# This is the cleanest, most-readable, faster-than-using-Date
# way to do it.
@date = case date
- when String then
- if DateTimeFormat =~ date
- Time.utc($1.to_i, $2.to_i, $3.to_i)
- else
- raise(Gem::InvalidSpecificationException,
- "invalid date format in specification: #{date.inspect}")
- end
- when Time, DateLike then
- Time.utc(date.year, date.month, date.day)
- else
- TODAY
+ when String then
+ if DateTimeFormat =~ date
+ Time.utc($1.to_i, $2.to_i, $3.to_i)
+ else
+ raise(Gem::InvalidSpecificationException,
+ "invalid date format in specification: #{date.inspect}")
+ end
+ when Time, DateLike then
+ Time.utc(date.year, date.month, date.day)
+ else
+ TODAY
end
end
@@ -1760,12 +1811,13 @@ class Gem::Specification < Gem::BasicSpecification
Gem::Specification.each do |spec|
deps = check_dev ? spec.dependencies : spec.runtime_dependencies
deps.each do |dep|
- next unless satisfies_requirement?(dep)
- sats = []
- find_all_satisfiers(dep) do |sat|
- sats << sat
+ if self.satisfies_requirement?(dep)
+ sats = []
+ find_all_satisfiers(dep) do |sat|
+ sats << sat
+ end
+ out << [spec, dep, sats]
end
- out << [spec, dep, sats]
end
end
out
@@ -1775,7 +1827,7 @@ class Gem::Specification < Gem::BasicSpecification
# Returns all specs that matches this spec's runtime dependencies.
def dependent_specs
- runtime_dependencies.map(&:to_specs).flatten
+ runtime_dependencies.map {|dep| dep.to_specs }.flatten
end
##
@@ -1811,22 +1863,23 @@ class Gem::Specification < Gem::BasicSpecification
end
def encode_with(coder) # :nodoc:
+ mark_version
+
coder.add "name", @name
coder.add "version", @version
platform = case @original_platform
- when nil, "" then
- "ruby"
- when String then
- @original_platform
- else
- @original_platform.to_s
+ when nil, "" then
+ "ruby"
+ when String then
+ @original_platform
+ else
+ @original_platform.to_s
end
coder.add "platform", platform
attributes = @@attributes.map(&:to_s) - %w[name version platform]
attributes.each do |name|
- value = instance_variable_get("@#{name}")
- coder.add name, value unless value.nil?
+ coder.add name, instance_variable_get("@#{name}")
end
end
@@ -1913,8 +1966,7 @@ class Gem::Specification < Gem::BasicSpecification
end
##
- # Work around old bundler versions removing my methods
- # Can be removed once RubyGems can no longer install Bundler 2.5
+ # Work around bundler removing my methods
def gem_dir # :nodoc:
super
@@ -1944,7 +1996,7 @@ class Gem::Specification < Gem::BasicSpecification
end
rubygems_deprecate :has_rdoc=
- alias_method :has_rdoc?, :has_rdoc # :nodoc:
+ alias :has_rdoc? :has_rdoc # :nodoc:
rubygems_deprecate :has_rdoc?
##
@@ -1955,7 +2007,7 @@ class Gem::Specification < Gem::BasicSpecification
end
# :stopdoc:
- alias_method :has_test_suite?, :has_unit_tests?
+ alias has_test_suite? has_unit_tests?
# :startdoc:
def hash # :nodoc:
@@ -2012,8 +2064,7 @@ class Gem::Specification < Gem::BasicSpecification
end
##
- # Duplicates Array and Gem::Requirement attributes from +other_spec+ so state isn't shared.
- #
+ # Duplicates array_attributes from +other_spec+ so state isn't shared.
def initialize_copy(other_spec)
self.class.array_attributes.each do |name|
@@ -2035,9 +2086,6 @@ class Gem::Specification < Gem::BasicSpecification
raise e
end
end
-
- @required_ruby_version = other_spec.required_ruby_version.dup
- @required_rubygems_version = other_spec.required_rubygems_version.dup
end
def base_dir
@@ -2107,6 +2155,13 @@ class Gem::Specification < Gem::BasicSpecification
end
##
+ # Sets the rubygems_version to the current RubyGems version.
+
+ def mark_version
+ @rubygems_version = Gem::VERSION
+ end
+
+ ##
# Track removed method calls to warn about during build time.
# Warn about unknown attributes while loading a spec.
@@ -2199,22 +2254,23 @@ class Gem::Specification < Gem::BasicSpecification
attributes.unshift :name
attributes.each do |attr_name|
- current_value = send attr_name
- current_value = current_value.sort if [:files, :test_files].include? attr_name
- next unless current_value != default_value(attr_name) ||
- self.class.required_attribute?(attr_name)
+ current_value = self.send attr_name
+ current_value = current_value.sort if %i[files test_files].include? attr_name
+ if current_value != default_value(attr_name) ||
+ self.class.required_attribute?(attr_name)
- q.text "s.#{attr_name} = "
+ q.text "s.#{attr_name} = "
- if attr_name == :date
- current_value = current_value.utc
+ if attr_name == :date
+ current_value = current_value.utc
- q.text "Time.utc(#{current_value.year}, #{current_value.month}, #{current_value.day})"
- else
- q.pp current_value
- end
+ q.text "Time.utc(#{current_value.year}, #{current_value.month}, #{current_value.day})"
+ else
+ q.pp current_value
+ end
- q.breakable
+ q.breakable
+ end
end
end
end
@@ -2224,7 +2280,7 @@ class Gem::Specification < Gem::BasicSpecification
# that is already loaded (+other+)
def check_version_conflict(other) # :nodoc:
- return if version == other.version
+ return if self.version == other.version
# This gem is already loaded. If the currently loaded gem is not in the
# list of candidate gems, then we have a version conflict.
@@ -2232,7 +2288,7 @@ class Gem::Specification < Gem::BasicSpecification
msg = "can't activate #{full_name}, already activated #{other.full_name}"
e = Gem::LoadError.new msg
- e.name = name
+ e.name = self.name
raise e
end
@@ -2297,13 +2353,13 @@ class Gem::Specification < Gem::BasicSpecification
when Array then "[" + obj.map {|x| ruby_code x }.join(", ") + "]"
when Hash then
seg = obj.keys.sort.map {|k| "#{k.to_s.dump} => #{obj[k].to_s.dump}" }
- "{ #{seg.join(", ")} }"
- when Gem::Version then ruby_code(obj.to_s)
+ "{ #{seg.join(', ')} }"
+ when Gem::Version then obj.to_s.dump
when DateLike then obj.strftime("%Y-%m-%d").dump
when Time then obj.strftime("%Y-%m-%d").dump
when Numeric then obj.inspect
when true, false, nil then obj.inspect
- when Gem::Platform then "Gem::Platform.new(#{ruby_code obj.to_a})"
+ when Gem::Platform then "Gem::Platform.new(#{obj.to_a.inspect})"
when Gem::Requirement then
list = obj.as_list
"Gem::Requirement.new(#{ruby_code(list.size == 1 ? obj.to_s : list)})"
@@ -2324,7 +2380,7 @@ class Gem::Specification < Gem::BasicSpecification
# True if this gem has the same attributes as +other+.
def same_attributes?(spec)
- @@attributes.all? {|name, _default| send(name) == spec.send(name) }
+ @@attributes.all? {|name, default| self.send(name) == spec.send(name) }
end
private :same_attributes?
@@ -2333,8 +2389,8 @@ class Gem::Specification < Gem::BasicSpecification
# Checks if this specification meets the requirement of +dependency+.
def satisfies_requirement?(dependency)
- @name == dependency.name &&
- dependency.requirement.satisfied_by?(@version)
+ return @name == dependency.name &&
+ dependency.requirement.satisfied_by?(@version)
end
##
@@ -2423,6 +2479,7 @@ class Gem::Specification < Gem::BasicSpecification
# still have their default values are omitted.
def to_ruby
+ mark_version
result = []
result << "# -*- encoding: utf-8 -*-"
result << "#{Gem::StubSpecification::PREFIX}#{name} #{version} #{platform} #{raw_require_paths.join("\0")}"
@@ -2460,19 +2517,19 @@ class Gem::Specification < Gem::BasicSpecification
@@attributes.each do |attr_name|
next if handled.include? attr_name
- current_value = send(attr_name)
+ current_value = self.send(attr_name)
if current_value != default_value(attr_name) || self.class.required_attribute?(attr_name)
result << " s.#{attr_name} = #{ruby_code current_value}"
end
end
if String === signing_key
- result << " s.signing_key = #{ruby_code signing_key}"
+ result << " s.signing_key = #{signing_key.dump}.freeze"
end
if @installed_by_version
result << nil
- result << " s.installed_by_version = #{ruby_code Gem::VERSION}"
+ result << " s.installed_by_version = \"#{Gem::VERSION}\" if s.respond_to? :installed_by_version"
end
unless dependencies.empty?
@@ -2481,8 +2538,9 @@ class Gem::Specification < Gem::BasicSpecification
result << nil
dependencies.each do |dep|
+ req = dep.requirements_list.inspect
dep.instance_variable_set :@type, :runtime if dep.type.nil? # HACK
- result << " s.add_#{dep.type}_dependency(%q<#{dep.name}>.freeze, #{ruby_code dep.requirements_list})"
+ result << " s.add_#{dep.type}_dependency(%q<#{dep.name}>.freeze, #{req})"
end
end
@@ -2543,9 +2601,10 @@ class Gem::Specification < Gem::BasicSpecification
def traverse(trail = [], visited = {}, &block)
trail.push(self)
begin
- runtime_dependencies.each do |dep|
+ dependencies.each do |dep|
+ next unless dep.runtime?
dep.matching_specs(true).each do |dep_spec|
- next if visited.key?(dep_spec)
+ next if visited.has_key?(dep_spec)
visited[dep_spec] = true
trail.push(dep_spec)
begin
@@ -2553,10 +2612,11 @@ class Gem::Specification < Gem::BasicSpecification
ensure
trail.pop
end
- next if result == :next
- spec_name = dep_spec.name
- dep_spec.traverse(trail, visited, &block) unless
- trail.any? {|s| s.name == spec_name }
+ unless result == :next
+ spec_name = dep_spec.name
+ dep_spec.traverse(trail, visited, &block) unless
+ trail.any? {|s| s.name == spec_name }
+ end
end
end
ensure
@@ -2587,10 +2647,6 @@ class Gem::Specification < Gem::BasicSpecification
@test_files.delete_if {|x| File.directory?(x) && !File.symlink?(x) }
end
- def validate_for_resolution
- Gem::SpecificationPolicy.new(self).validate_for_resolution
- end
-
def validate_metadata
Gem::SpecificationPolicy.new(self).validate_metadata
end
@@ -2607,13 +2663,22 @@ class Gem::Specification < Gem::BasicSpecification
rubygems_deprecate :validate_permissions
##
- # Set the version to +version+.
+ # Set the version to +version+, potentially also setting
+ # required_rubygems_version if +version+ indicates it is a
+ # prerelease.
def version=(version)
@version = Gem::Version.create(version)
return if @version.nil?
+ # skip to set required_ruby_version when pre-released rubygems.
+ # It caused to raise CircularDependencyError
+ if @version.prerelease? && (@name.nil? || @name.strip != "rubygems")
+ self.required_rubygems_version = "> 1.3.1"
+ end
invalidate_memoized_attributes
+
+ return @version
end
def stubbed?
@@ -2625,9 +2690,9 @@ class Gem::Specification < Gem::BasicSpecification
case ivar
when "date"
# Force Date to go through the extra coerce logic in date=
- self.date = val
+ self.date = val.tap(&Gem::UNTAINT)
else
- instance_variable_set "@#{ivar}", val
+ instance_variable_set "@#{ivar}", val.tap(&Gem::UNTAINT)
end
end
@@ -2644,11 +2709,11 @@ class Gem::Specification < Gem::BasicSpecification
end
nil_attributes.each do |attribute|
- default = default_value attribute
+ default = self.default_value attribute
value = case default
- when Time, Numeric, Symbol, true, false, nil then default
- else default.dup
+ when Time, Numeric, Symbol, true, false, nil then default
+ else default.dup
end
instance_variable_set "@#{attribute}", value
diff --git a/lib/rubygems/specification_policy.rb b/lib/rubygems/specification_policy.rb
index d79ee7df92..cee7eb3fdc 100644
--- a/lib/rubygems/specification_policy.rb
+++ b/lib/rubygems/specification_policy.rb
@@ -5,21 +5,20 @@ require_relative "user_interaction"
class Gem::SpecificationPolicy
include Gem::UserInteraction
- VALID_NAME_PATTERN = /\A[a-zA-Z0-9\.\-\_]+\z/ # :nodoc:
+ VALID_NAME_PATTERN = /\A[a-zA-Z0-9\.\-\_]+\z/.freeze # :nodoc:
- SPECIAL_CHARACTERS = /\A[#{Regexp.escape(".-_")}]+/ # :nodoc:
+ SPECIAL_CHARACTERS = /\A[#{Regexp.escape('.-_')}]+/.freeze # :nodoc:
- VALID_URI_PATTERN = %r{\Ahttps?:\/\/([^\s:@]+:[^\s:@]*@)?[A-Za-z\d\-]+(\.[A-Za-z\d\-]+)+\.?(:\d{1,5})?([\/?]\S*)?\z} # :nodoc:
+ VALID_URI_PATTERN = %r{\Ahttps?:\/\/([^\s:@]+:[^\s:@]*@)?[A-Za-z\d\-]+(\.[A-Za-z\d\-]+)+\.?(:\d{1,5})?([\/?]\S*)?\z}.freeze # :nodoc:
METADATA_LINK_KEYS = %w[
- homepage_uri
+ bug_tracker_uri
changelog_uri
- source_code_uri
documentation_uri
- wiki_uri
+ homepage_uri
mailing_list_uri
- bug_tracker_uri
- download_uri
+ source_code_uri
+ wiki_uri
funding_uri
].freeze # :nodoc:
@@ -45,7 +44,6 @@ class Gem::SpecificationPolicy
def validate(strict = false)
validate_required!
- validate_required_metadata!
validate_optional(strict) if packaging || strict
@@ -86,15 +84,13 @@ class Gem::SpecificationPolicy
validate_authors_field
- validate_licenses_length
-
- validate_duplicate_dependencies
- end
-
- def validate_required_metadata!
validate_metadata
+ validate_licenses_length
+
validate_lazy_metadata
+
+ validate_duplicate_dependencies
end
def validate_optional(strict)
@@ -106,14 +102,10 @@ class Gem::SpecificationPolicy
validate_dependencies
- validate_required_ruby_version
-
validate_extensions
validate_removed_attributes
- validate_unique_links
-
if @warnings > 0
if strict
error "specification has warnings"
@@ -124,13 +116,6 @@ class Gem::SpecificationPolicy
end
##
- # Implementation for Specification#validate_for_resolution
-
- def validate_for_resolution
- validate_required!
- end
-
- ##
# Implementation for Specification#validate_metadata
def validate_metadata
@@ -142,7 +127,7 @@ class Gem::SpecificationPolicy
metadata.each do |key, value|
entry = "metadata['#{key}']"
- unless key.is_a?(String)
+ if !key.kind_of?(String)
error "metadata keys must be a String"
end
@@ -150,7 +135,7 @@ class Gem::SpecificationPolicy
error "metadata key is too large (#{key.size} > 128)"
end
- unless value.is_a?(String)
+ if !value.kind_of?(String)
error "#{entry} value must be a String"
end
@@ -158,9 +143,10 @@ class Gem::SpecificationPolicy
error "#{entry} value is too large (#{value.size} > 1024)"
end
- next unless METADATA_LINK_KEYS.include? key
- unless VALID_URI_PATTERN.match?(value)
- error "#{entry} has invalid link: #{value.inspect}"
+ if METADATA_LINK_KEYS.include? key
+ if value !~ VALID_URI_PATTERN
+ error "#{entry} has invalid link: #{value.inspect}"
+ end
end
end
end
@@ -177,7 +163,7 @@ class Gem::SpecificationPolicy
if prev = seen[dep.type][dep.name]
error_messages << <<-MESSAGE
duplicate dependency on #{dep}, (#{prev.requirement}) use:
- add_#{dep.type}_dependency \"#{dep.name}\", \"#{dep.requirement}\", \"#{prev.requirement}\"
+ add_#{dep.type}_dependency '#{dep.name}', '#{dep.requirement}', '#{prev.requirement}'
MESSAGE
end
@@ -209,42 +195,37 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
prerelease_dep && !@specification.version.prerelease?
open_ended = dep.requirement.requirements.all? do |op, version|
- !version.prerelease? && [">", ">="].include?(op)
+ !version.prerelease? && (op == ">" || op == ">=")
end
- next unless open_ended
- op, dep_version = dep.requirement.requirements.first
+ if open_ended
+ op, dep_version = dep.requirement.requirements.first
- segments = dep_version.segments
+ segments = dep_version.segments
- base = segments.first 2
+ base = segments.first 2
- recommendation = if [">", ">="].include?(op) && segments == [0]
- " use a bounded requirement, such as \"~> x.y\""
- else
- bugfix = if op == ">"
- ", \"> #{dep_version}\""
- elsif op == ">=" && base != segments
- ", \">= #{dep_version}\""
+ recommendation = if (op == ">" || op == ">=") && segments == [0]
+ " use a bounded requirement, such as '~> x.y'"
+ else
+ bugfix = if op == ">"
+ ", '> #{dep_version}'"
+ elsif op == ">=" && base != segments
+ ", '>= #{dep_version}'"
+ end
+
+ " if #{dep.name} is semantically versioned, use:\n" \
+ " add_#{dep.type}_dependency '#{dep.name}', '~> #{base.join '.'}'#{bugfix}"
end
- " if #{dep.name} is semantically versioned, use:\n" \
- " add_#{dep.type}_dependency \"#{dep.name}\", \"~> #{base.join "."}\"#{bugfix}"
+ warning_messages << ["open-ended dependency on #{dep} is not recommended", recommendation].join("\n") + "\n"
end
-
- warning_messages << ["open-ended dependency on #{dep} is not recommended", recommendation].join("\n") + "\n"
end
if warning_messages.any?
warning_messages.each {|warning_message| warning warning_message }
end
end
- def validate_required_ruby_version
- if @specification.required_ruby_version.requirements == [Gem::Requirement::DefaultRequirement]
- warning "make sure you specify the oldest ruby version constraint (like \">= 3.0\") that you want your gem to support by setting the `required_ruby_version` gemspec attribute"
- end
- end
-
##
# Issues a warning for each file to be packaged which is world-readable.
#
@@ -255,7 +236,7 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
@specification.files.each do |file|
next unless File.file?(file)
- next if File.stat(file).mode & 0o444 == 0o444
+ next if File.stat(file).mode & 0444 == 0444
warning "#{file} is not world-readable"
end
@@ -274,7 +255,7 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
@specification.instance_variable_get("@#{attrname}").nil?
end
return if nil_attributes.empty?
- error "#{nil_attributes.join ", "} must not be nil"
+ error "#{nil_attributes.join ', '} must not be nil"
end
def validate_rubygems_version
@@ -284,9 +265,7 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
return if rubygems_version == Gem::VERSION
- warning "expected RubyGems version #{Gem::VERSION}, was #{rubygems_version}"
-
- @specification.rubygems_version = Gem::VERSION
+ error "expected RubyGems version #{Gem::VERSION}, was #{rubygems_version}"
end
def validate_required_attributes
@@ -302,12 +281,12 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
if !name.is_a?(String)
error "invalid value for attribute name: \"#{name.inspect}\" must be a string"
- elsif !/[a-zA-Z]/.match?(name)
+ elsif name !~ /[a-zA-Z]/
error "invalid value for attribute name: #{name.dump} must include at least one letter"
- elsif !VALID_NAME_PATTERN.match?(name)
+ elsif name !~ VALID_NAME_PATTERN
error "invalid value for attribute name: #{name.dump} can only include letters, numbers, dashes, and underscores"
- elsif SPECIAL_CHARACTERS.match?(name)
- error "invalid value for attribute name: #{name.dump} cannot begin with a period, dash, or underscore"
+ elsif name =~ SPECIAL_CHARACTERS
+ error "invalid value for attribute name: #{name.dump} can not begin with a period, dash, or underscore"
end
end
@@ -360,13 +339,13 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
def validate_array_attribute(field)
val = @specification.send(field)
klass = case field
- when :dependencies then
- Gem::Dependency
- else
- String
+ when :dependencies then
+ Gem::Dependency
+ else
+ String
end
- unless Array === val && val.all? {|x| x.is_a?(klass) || (field == :licenses && x.nil?) }
+ unless Array === val && val.all? {|x| x.kind_of?(klass) }
error "#{field} must be an Array of #{klass}"
end
end
@@ -381,8 +360,6 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
licenses = @specification.licenses
licenses.each do |license|
- next if license.nil?
-
if license.length > 64
error "each license must be 64 characters or less"
end
@@ -393,38 +370,26 @@ duplicate dependency on #{dep}, (#{prev.requirement}) use:
licenses = @specification.licenses
licenses.each do |license|
- next if Gem::Licenses.match?(license) || license.nil?
- license_id_deprecated = Gem::Licenses.deprecated_license_id?(license)
- exception_id_deprecated = Gem::Licenses.deprecated_exception_id?(license)
- suggestions = Gem::Licenses.suggestions(license)
-
- if license_id_deprecated
- main_message = "License identifier '#{license}' is deprecated"
- elsif exception_id_deprecated
- main_message = "Exception identifier at '#{license}' is deprecated"
- else
- main_message = "License identifier '#{license}' is invalid"
+ if !Gem::Licenses.match?(license)
+ suggestions = Gem::Licenses.suggestions(license)
+ message = <<-WARNING
+license value '#{license}' is invalid. Use a license identifier from
+http://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard license.
+ WARNING
+ message += "Did you mean #{suggestions.map {|s| "'#{s}'" }.join(', ')}?\n" unless suggestions.nil?
+ warning(message)
end
-
- message = <<-WARNING
-#{main_message}. Use an identifier from
-https://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard license,
-or set it to nil if you don't want to specify a license.
- WARNING
- message += "Did you mean #{suggestions.map {|s| "'#{s}'" }.join(", ")}?\n" unless suggestions.nil?
- warning(message)
end
warning <<-WARNING if licenses.empty?
-licenses is empty, but is recommended. Use an license identifier from
-https://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard license,
-or set it to nil if you don't want to specify a license.
+licenses is empty, but is recommended. Use a license identifier from
+http://spdx.org/licenses or '#{Gem::Licenses::NONSTANDARD}' for a nonstandard license.
WARNING
end
LAZY = '"FIxxxXME" or "TOxxxDO"'.gsub(/xxx/, "")
- LAZY_PATTERN = /\AFI XME|\ATO DO/x
- HOMEPAGE_URI_PATTERN = /\A[a-z][a-z\d+.-]*:/i
+ LAZY_PATTERN = /\AFI XME|\ATO DO/x.freeze
+ HOMEPAGE_URI_PATTERN = /\A[a-z][a-z\d+.-]*:/i.freeze
def validate_lazy_metadata
unless @specification.authors.grep(LAZY_PATTERN).empty?
@@ -435,11 +400,11 @@ or set it to nil if you don't want to specify a license.
error "#{LAZY} is not an email"
end
- if LAZY_PATTERN.match?(@specification.description)
+ if @specification.description =~ LAZY_PATTERN
error "#{LAZY} is not a description"
end
- if LAZY_PATTERN.match?(@specification.summary)
+ if @specification.summary =~ LAZY_PATTERN
error "#{LAZY} is not a summary"
end
@@ -447,13 +412,13 @@ or set it to nil if you don't want to specify a license.
# Make sure a homepage is valid HTTP/HTTPS URI
if homepage && !homepage.empty?
- require_relative "vendor/uri/lib/uri"
+ require "uri"
begin
- homepage_uri = Gem::URI.parse(homepage)
- unless [Gem::URI::HTTP, Gem::URI::HTTPS].member? homepage_uri.class
+ homepage_uri = URI.parse(homepage)
+ unless [URI::HTTP, URI::HTTPS].member? homepage_uri.class
error "\"#{homepage}\" is not a valid HTTP URI"
end
- rescue Gem::URI::InvalidURIError
+ rescue URI::InvalidURIError
error "\"#{homepage}\" is not a valid HTTP URI"
end
end
@@ -517,29 +482,13 @@ You have specified rust based extension, but Cargo.lock is not part of the gem f
def validate_rake_extensions(builder) # :nodoc:
rake_extension = @specification.extensions.any? {|s| builder.builder_for(s) == Gem::Ext::RakeBuilder }
- rake_dependency = @specification.dependencies.any? {|d| d.name == "rake" && d.type == :runtime }
+ rake_dependency = @specification.dependencies.any? {|d| d.name == "rake" }
warning <<-WARNING if rake_extension && !rake_dependency
-You have specified rake based extension, but rake is not added as runtime dependency. It is recommended to add rake as a runtime dependency in gemspec since there's no guarantee rake will be already installed.
+You have specified rake based extension, but rake is not added as dependency. It is recommended to add rake as a dependency in gemspec since there's no guarantee rake will be already installed.
WARNING
end
- def validate_unique_links
- links = @specification.metadata.slice(*METADATA_LINK_KEYS)
- grouped = links.group_by {|_key, uri| uri }
- grouped.each do |uri, copies|
- next unless copies.length > 1
- keys = copies.map(&:first).join("\n ")
- warning <<~WARNING
- You have specified the uri:
- #{uri}
- for all of the following keys:
- #{keys}
- Only the first one will be shown on rubygems.org
- WARNING
- end
- end
-
def warning(statement) # :nodoc:
@warnings += 1
diff --git a/lib/rubygems/specification_record.rb b/lib/rubygems/specification_record.rb
deleted file mode 100644
index 664d506265..0000000000
--- a/lib/rubygems/specification_record.rb
+++ /dev/null
@@ -1,212 +0,0 @@
-# frozen_string_literal: true
-
-module Gem
- class SpecificationRecord
- def self.dirs_from(paths)
- paths.map do |path|
- File.join(path, "specifications")
- end
- end
-
- def self.from_path(path)
- new(dirs_from([path]))
- end
-
- def initialize(dirs)
- @all = nil
- @stubs = nil
- @stubs_by_name = {}
- @spec_with_requirable_file = {}
- @active_stub_with_requirable_file = {}
-
- @dirs = dirs
- end
-
- # Sentinel object to represent "not found" stubs
- NOT_FOUND = Struct.new(:to_spec, :this).new
- private_constant :NOT_FOUND
-
- ##
- # Returns the list of all specifications in the record
-
- def all
- @all ||= Gem.loaded_specs.values | stubs.map(&:to_spec)
- end
-
- ##
- # Returns a Gem::StubSpecification for every specification in the record
-
- def stubs
- @stubs ||= begin
- pattern = "*.gemspec"
- stubs = stubs_for_pattern(pattern, false)
-
- @stubs_by_name = stubs.select {|s| Gem::Platform.match_spec? s }.group_by(&:name)
- stubs
- end
- end
-
- ##
- # Returns a Gem::StubSpecification for every specification in the record
- # named +name+ only returns stubs that match Gem.platforms
-
- def stubs_for(name)
- if @stubs
- @stubs_by_name[name] || []
- else
- @stubs_by_name[name] ||= stubs_for_pattern("#{name}-*.gemspec").select do |s|
- s.name == name
- end
- end
- end
-
- ##
- # Finds stub specifications matching a pattern in the record, optionally
- # filtering out specs not matching the current platform
-
- def stubs_for_pattern(pattern, match_platform = true)
- installed_stubs = installed_stubs(pattern)
- installed_stubs.select! {|s| Gem::Platform.match_spec? s } if match_platform
- stubs = installed_stubs + Gem::Specification.default_stubs(pattern)
- Gem::Specification._resort!(stubs)
- stubs
- end
-
- ##
- # Adds +spec+ to the the record, keeping the collection properly sorted.
-
- def add_spec(spec)
- return if all.include? spec
-
- all << spec
- stubs << spec
- (@stubs_by_name[spec.name] ||= []) << spec
-
- Gem::Specification._resort!(@stubs_by_name[spec.name])
- Gem::Specification._resort!(stubs)
- end
-
- ##
- # Removes +spec+ from the record.
-
- def remove_spec(spec)
- all.delete spec.to_spec
- stubs.delete spec
- (@stubs_by_name[spec.name] || []).delete spec
- end
-
- ##
- # Sets the specs known by the record to +specs+.
-
- def all=(specs)
- @stubs_by_name = specs.group_by(&:name)
- @all = @stubs = specs
- end
-
- ##
- # Return full names of all specs in the record in sorted order.
-
- def all_names
- all.map(&:full_name)
- end
-
- include Enumerable
-
- ##
- # Enumerate every known spec.
-
- def each
- return enum_for(:each) unless block_given?
-
- all.each do |x|
- yield x
- end
- end
-
- ##
- # Returns every spec in the record that matches +name+ and optional +requirements+.
-
- def find_all_by_name(name, *requirements)
- req = Gem::Requirement.create(*requirements)
- env_req = Gem.env_requirement(name)
-
- matches = stubs_for(name).find_all do |spec|
- req.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version)
- end.map(&:to_spec)
-
- if name == "bundler" && !req.specific?
- require_relative "bundler_version_finder"
- Gem::BundlerVersionFinder.prioritize!(matches)
- end
-
- matches
- end
-
- ##
- # Return the best specification in the record that contains the file matching +path+.
-
- def find_by_path(path)
- path = path.dup.freeze
- spec = @spec_with_requirable_file[path] ||= stubs.find do |s|
- s.contains_requirable_file? path
- end || NOT_FOUND
-
- spec.to_spec
- end
-
- ##
- # Return the best specification in the record that contains the file
- # matching +path+ amongst the specs that are not activated.
-
- def find_inactive_by_path(path)
- stub = stubs.find do |s|
- next if s.activated?
- s.contains_requirable_file? path
- end
- stub&.to_spec
- end
-
- ##
- # Return the best specification in the record that contains the file
- # matching +path+, among those already activated.
-
- def find_active_stub_by_path(path)
- stub = @active_stub_with_requirable_file[path] ||= stubs.find do |s|
- s.activated? && s.contains_requirable_file?(path)
- end || NOT_FOUND
-
- stub.this
- end
-
- ##
- # Return the latest specs in the record, optionally including prerelease
- # specs if +prerelease+ is true.
-
- def latest_specs(prerelease)
- Gem::Specification._latest_specs stubs, prerelease
- end
-
- ##
- # Return the latest installed spec in the record for gem +name+.
-
- def latest_spec_for(name)
- latest_specs(true).find {|installed_spec| installed_spec.name == name }
- end
-
- private
-
- def installed_stubs(pattern)
- map_stubs(pattern) do |path, base_dir, gems_dir|
- Gem::StubSpecification.gemspec_stub(path, base_dir, gems_dir)
- end
- end
-
- def map_stubs(pattern)
- @dirs.flat_map do |dir|
- base_dir = File.dirname dir
- gems_dir = File.join base_dir, "gems"
- Gem::Specification.gemspec_stubs_in(dir, pattern) {|path| yield path, base_dir, gems_dir }
- end
- end
- end
-end
diff --git a/lib/rubygems/stub_specification.rb b/lib/rubygems/stub_specification.rb
index ea66fbc3f6..d64d611f48 100644
--- a/lib/rubygems/stub_specification.rb
+++ b/lib/rubygems/stub_specification.rb
@@ -35,7 +35,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
def initialize(data, extensions)
parts = data[PREFIX.length..-1].split(" ", 4)
- @name = -parts[0]
+ @name = parts[0].freeze
@version = if Gem::Version.correct?(parts[1])
Gem::Version.new(parts[1])
else
@@ -69,6 +69,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
def initialize(filename, base_dir, gems_dir, default_gem)
super()
+ filename.tap(&Gem::UNTAINT)
self.loaded_from = filename
@data = nil
@@ -84,10 +85,10 @@ class Gem::StubSpecification < Gem::BasicSpecification
def activated?
@activated ||=
- begin
- loaded = Gem.loaded_specs[name]
- loaded && loaded.version == version
- end
+ begin
+ loaded = Gem.loaded_specs[name]
+ loaded && loaded.version == version
+ end
end
def default_gem?
@@ -111,23 +112,20 @@ class Gem::StubSpecification < Gem::BasicSpecification
saved_lineno = $.
Gem.open_file loaded_from, OPEN_MODE do |file|
- file.readline # discard encoding line
- stubline = file.readline
- if stubline.start_with?(PREFIX)
- extline = file.readline
-
- extensions =
- if extline.delete_prefix!(PREFIX)
- extline.chomp!
- extline.split "\0"
+ begin
+ file.readline # discard encoding line
+ stubline = file.readline.chomp
+ if stubline.start_with?(PREFIX)
+ extensions = if /\A#{PREFIX}/ =~ file.readline.chomp
+ $'.split "\0"
else
StubLine::NO_EXTENSIONS
end
- stubline.chomp! # readline(chomp: true) allocates 3x as much as .readline.chomp!
- @data = StubLine.new stubline, extensions
+ @data = StubLine.new stubline, extensions
+ end
+ rescue EOFError
end
- rescue EOFError
end
ensure
$. = saved_lineno
@@ -210,25 +208,4 @@ class Gem::StubSpecification < Gem::BasicSpecification
def stubbed?
data.is_a? StubLine
end
-
- def ==(other) # :nodoc:
- self.class === other &&
- name == other.name &&
- version == other.version &&
- platform == other.platform
- end
-
- alias_method :eql?, :== # :nodoc:
-
- def hash # :nodoc:
- name.hash ^ version.hash ^ platform.hash
- end
-
- def <=>(other) # :nodoc:
- sort_obj <=> other.sort_obj
- end
-
- def sort_obj # :nodoc:
- [name, version, Gem::Platform.sort_priority(platform)]
- end
end
diff --git a/lib/rubygems/target_rbconfig.rb b/lib/rubygems/target_rbconfig.rb
deleted file mode 100644
index 21d90ee9db..0000000000
--- a/lib/rubygems/target_rbconfig.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-# frozen_string_literal: true
-
-require "rbconfig"
-
-##
-# A TargetConfig is a wrapper around an RbConfig object that provides a
-# consistent interface for querying configuration for *deployment target
-# platform*, where the gem being installed is intended to run on.
-#
-# The TargetConfig is typically created from the RbConfig of the running Ruby
-# process, but can also be created from an RbConfig file on disk for cross-
-# compiling gems.
-
-class Gem::TargetRbConfig
- attr_reader :path
-
- def initialize(rbconfig, path)
- @rbconfig = rbconfig
- @path = path
- end
-
- ##
- # Creates a TargetRbConfig for the platform that RubyGems is running on.
-
- def self.for_running_ruby
- new(::RbConfig, nil)
- end
-
- ##
- # Creates a TargetRbConfig from the RbConfig file at the given path.
- # Typically used for cross-compiling gems.
-
- def self.from_path(rbconfig_path)
- namespace = Module.new do |m|
- # Load the rbconfig.rb file within a new anonymous module to avoid
- # conflicts with the rbconfig for the running platform.
- Kernel.load rbconfig_path, m
- end
- rbconfig = namespace.const_get(:RbConfig)
-
- new(rbconfig, rbconfig_path)
- end
-
- ##
- # Queries the configuration for the given key.
-
- def [](key)
- @rbconfig::CONFIG[key]
- end
-end
diff --git a/lib/rubygems/text.rb b/lib/rubygems/text.rb
index da0795b771..be811525f2 100644
--- a/lib/rubygems/text.rb
+++ b/lib/rubygems/text.rb
@@ -4,6 +4,7 @@
# A collection of text-wrangling methods
module Gem::Text
+
##
# Remove any non-printable characters and make the text suitable for
# printing.
@@ -66,7 +67,7 @@ module Gem::Text
str1.each_codepoint.with_index(1) do |char1, i|
j = 0
while j < m
- cost = char1 == str2_codepoints[j] ? 0 : 1
+ cost = (char1 == str2_codepoints[j]) ? 0 : 1
x = min3(
d[j + 1] + 1, # insertion
i + 1, # deletion
diff --git a/lib/rubygems/tsort.rb b/lib/rubygems/tsort.rb
new file mode 100644
index 0000000000..60ebe22e81
--- /dev/null
+++ b/lib/rubygems/tsort.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+require_relative "tsort/lib/tsort"
diff --git a/lib/bundler/vendor/fileutils/.document b/lib/rubygems/tsort/.document
index 0c43bbd6b3..0c43bbd6b3 100644
--- a/lib/bundler/vendor/fileutils/.document
+++ b/lib/rubygems/tsort/.document
diff --git a/lib/rubygems/tsort/lib/tsort.rb b/lib/rubygems/tsort/lib/tsort.rb
new file mode 100644
index 0000000000..f825f14257
--- /dev/null
+++ b/lib/rubygems/tsort/lib/tsort.rb
@@ -0,0 +1,452 @@
+# frozen_string_literal: true
+
+#--
+# tsort.rb - provides a module for topological sorting and strongly connected components.
+#++
+#
+
+#
+# Gem::TSort implements topological sorting using Tarjan's algorithm for
+# strongly connected components.
+#
+# Gem::TSort is designed to be able to be used with any object which can be
+# interpreted as a directed graph.
+#
+# Gem::TSort requires two methods to interpret an object as a graph,
+# tsort_each_node and tsort_each_child.
+#
+# * tsort_each_node is used to iterate for all nodes over a graph.
+# * tsort_each_child is used to iterate for child nodes of a given node.
+#
+# The equality of nodes are defined by eql? and hash since
+# Gem::TSort uses Hash internally.
+#
+# == A Simple Example
+#
+# The following example demonstrates how to mix the Gem::TSort module into an
+# existing class (in this case, Hash). Here, we're treating each key in
+# the hash as a node in the graph, and so we simply alias the required
+# #tsort_each_node method to Hash's #each_key method. For each key in the
+# hash, the associated value is an array of the node's child nodes. This
+# choice in turn leads to our implementation of the required #tsort_each_child
+# method, which fetches the array of child nodes and then iterates over that
+# array using the user-supplied block.
+#
+# require 'rubygems/tsort/lib/tsort'
+#
+# class Hash
+# include Gem::TSort
+# alias tsort_each_node each_key
+# def tsort_each_child(node, &block)
+# fetch(node).each(&block)
+# end
+# end
+#
+# {1=>[2, 3], 2=>[3], 3=>[], 4=>[]}.tsort
+# #=> [3, 2, 1, 4]
+#
+# {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}.strongly_connected_components
+# #=> [[4], [2, 3], [1]]
+#
+# == A More Realistic Example
+#
+# A very simple `make' like tool can be implemented as follows:
+#
+# require 'rubygems/tsort/lib/tsort'
+#
+# class Make
+# def initialize
+# @dep = {}
+# @dep.default = []
+# end
+#
+# def rule(outputs, inputs=[], &block)
+# triple = [outputs, inputs, block]
+# outputs.each {|f| @dep[f] = [triple]}
+# @dep[triple] = inputs
+# end
+#
+# def build(target)
+# each_strongly_connected_component_from(target) {|ns|
+# if ns.length != 1
+# fs = ns.delete_if {|n| Array === n}
+# raise Gem::TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}")
+# end
+# n = ns.first
+# if Array === n
+# outputs, inputs, block = n
+# inputs_time = inputs.map {|f| File.mtime f}.max
+# begin
+# outputs_time = outputs.map {|f| File.mtime f}.min
+# rescue Errno::ENOENT
+# outputs_time = nil
+# end
+# if outputs_time == nil ||
+# inputs_time != nil && outputs_time <= inputs_time
+# sleep 1 if inputs_time != nil && inputs_time.to_i == Time.now.to_i
+# block.call
+# end
+# end
+# }
+# end
+#
+# def tsort_each_child(node, &block)
+# @dep[node].each(&block)
+# end
+# include Gem::TSort
+# end
+#
+# def command(arg)
+# print arg, "\n"
+# system arg
+# end
+#
+# m = Make.new
+# m.rule(%w[t1]) { command 'date > t1' }
+# m.rule(%w[t2]) { command 'date > t2' }
+# m.rule(%w[t3]) { command 'date > t3' }
+# m.rule(%w[t4], %w[t1 t3]) { command 'cat t1 t3 > t4' }
+# m.rule(%w[t5], %w[t4 t2]) { command 'cat t4 t2 > t5' }
+# m.build('t5')
+#
+# == Bugs
+#
+# * 'tsort.rb' is wrong name because this library uses
+# Tarjan's algorithm for strongly connected components.
+# Although 'strongly_connected_components.rb' is correct but too long.
+#
+# == References
+#
+# R. E. Tarjan, "Depth First Search and Linear Graph Algorithms",
+# <em>SIAM Journal on Computing</em>, Vol. 1, No. 2, pp. 146-160, June 1972.
+#
+
+module Gem::TSort
+ class Cyclic < StandardError
+ end
+
+ # Returns a topologically sorted array of nodes.
+ # The array is sorted from children to parents, i.e.
+ # the first element has no child and the last node has no parent.
+ #
+ # If there is a cycle, Gem::TSort::Cyclic is raised.
+ #
+ # class G
+ # include Gem::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # p graph.tsort #=> [4, 2, 3, 1]
+ #
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
+ # p graph.tsort # raises Gem::TSort::Cyclic
+ #
+ def tsort
+ each_node = method(:tsort_each_node)
+ each_child = method(:tsort_each_child)
+ Gem::TSort.tsort(each_node, each_child)
+ end
+
+ # Returns a topologically sorted array of nodes.
+ # The array is sorted from children to parents, i.e.
+ # the first element has no child and the last node has no parent.
+ #
+ # The graph is represented by _each_node_ and _each_child_.
+ # _each_node_ should have +call+ method which yields for each node in the graph.
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
+ #
+ # If there is a cycle, Gem::TSort::Cyclic is raised.
+ #
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # p Gem::TSort.tsort(each_node, each_child) #=> [4, 2, 3, 1]
+ #
+ # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # p Gem::TSort.tsort(each_node, each_child) # raises Gem::TSort::Cyclic
+ #
+ def self.tsort(each_node, each_child)
+ tsort_each(each_node, each_child).to_a
+ end
+
+ # The iterator version of the #tsort method.
+ # <tt><em>obj</em>.tsort_each</tt> is similar to <tt><em>obj</em>.tsort.each</tt>, but
+ # modification of _obj_ during the iteration may lead to unexpected results.
+ #
+ # #tsort_each returns +nil+.
+ # If there is a cycle, Gem::TSort::Cyclic is raised.
+ #
+ # class G
+ # include Gem::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # graph.tsort_each {|n| p n }
+ # #=> 4
+ # # 2
+ # # 3
+ # # 1
+ #
+ def tsort_each(&block) # :yields: node
+ each_node = method(:tsort_each_node)
+ each_child = method(:tsort_each_child)
+ Gem::TSort.tsort_each(each_node, each_child, &block)
+ end
+
+ # The iterator version of the Gem::TSort.tsort method.
+ #
+ # The graph is represented by _each_node_ and _each_child_.
+ # _each_node_ should have +call+ method which yields for each node in the graph.
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
+ #
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # Gem::TSort.tsort_each(each_node, each_child) {|n| p n }
+ # #=> 4
+ # # 2
+ # # 3
+ # # 1
+ #
+ def self.tsort_each(each_node, each_child) # :yields: node
+ return to_enum(__method__, each_node, each_child) unless block_given?
+
+ each_strongly_connected_component(each_node, each_child) {|component|
+ if component.size == 1
+ yield component.first
+ else
+ raise Cyclic.new("topological sort failed: #{component.inspect}")
+ end
+ }
+ end
+
+ # Returns strongly connected components as an array of arrays of nodes.
+ # The array is sorted from children to parents.
+ # Each elements of the array represents a strongly connected component.
+ #
+ # class G
+ # include Gem::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # p graph.strongly_connected_components #=> [[4], [2], [3], [1]]
+ #
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
+ # p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
+ #
+ def strongly_connected_components
+ each_node = method(:tsort_each_node)
+ each_child = method(:tsort_each_child)
+ Gem::TSort.strongly_connected_components(each_node, each_child)
+ end
+
+ # Returns strongly connected components as an array of arrays of nodes.
+ # The array is sorted from children to parents.
+ # Each elements of the array represents a strongly connected component.
+ #
+ # The graph is represented by _each_node_ and _each_child_.
+ # _each_node_ should have +call+ method which yields for each node in the graph.
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
+ #
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # p Gem::TSort.strongly_connected_components(each_node, each_child)
+ # #=> [[4], [2], [3], [1]]
+ #
+ # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # p Gem::TSort.strongly_connected_components(each_node, each_child)
+ # #=> [[4], [2, 3], [1]]
+ #
+ def self.strongly_connected_components(each_node, each_child)
+ each_strongly_connected_component(each_node, each_child).to_a
+ end
+
+ # The iterator version of the #strongly_connected_components method.
+ # <tt><em>obj</em>.each_strongly_connected_component</tt> is similar to
+ # <tt><em>obj</em>.strongly_connected_components.each</tt>, but
+ # modification of _obj_ during the iteration may lead to unexpected results.
+ #
+ # #each_strongly_connected_component returns +nil+.
+ #
+ # class G
+ # include Gem::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # graph.each_strongly_connected_component {|scc| p scc }
+ # #=> [4]
+ # # [2]
+ # # [3]
+ # # [1]
+ #
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
+ # graph.each_strongly_connected_component {|scc| p scc }
+ # #=> [4]
+ # # [2, 3]
+ # # [1]
+ #
+ def each_strongly_connected_component(&block) # :yields: nodes
+ each_node = method(:tsort_each_node)
+ each_child = method(:tsort_each_child)
+ Gem::TSort.each_strongly_connected_component(each_node, each_child, &block)
+ end
+
+ # The iterator version of the Gem::TSort.strongly_connected_components method.
+ #
+ # The graph is represented by _each_node_ and _each_child_.
+ # _each_node_ should have +call+ method which yields for each node in the graph.
+ # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
+ #
+ # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # Gem::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
+ # #=> [4]
+ # # [2]
+ # # [3]
+ # # [1]
+ #
+ # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
+ # each_node = lambda {|&b| g.each_key(&b) }
+ # each_child = lambda {|n, &b| g[n].each(&b) }
+ # Gem::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
+ # #=> [4]
+ # # [2, 3]
+ # # [1]
+ #
+ def self.each_strongly_connected_component(each_node, each_child) # :yields: nodes
+ return to_enum(__method__, each_node, each_child) unless block_given?
+
+ id_map = {}
+ stack = []
+ each_node.call {|node|
+ unless id_map.include? node
+ each_strongly_connected_component_from(node, each_child, id_map, stack) {|c|
+ yield c
+ }
+ end
+ }
+ nil
+ end
+
+ # Iterates over strongly connected component in the subgraph reachable from
+ # _node_.
+ #
+ # Return value is unspecified.
+ #
+ # #each_strongly_connected_component_from doesn't call #tsort_each_node.
+ #
+ # class G
+ # include Gem::TSort
+ # def initialize(g)
+ # @g = g
+ # end
+ # def tsort_each_child(n, &b) @g[n].each(&b) end
+ # def tsort_each_node(&b) @g.each_key(&b) end
+ # end
+ #
+ # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
+ # graph.each_strongly_connected_component_from(2) {|scc| p scc }
+ # #=> [4]
+ # # [2]
+ #
+ # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
+ # graph.each_strongly_connected_component_from(2) {|scc| p scc }
+ # #=> [4]
+ # # [2, 3]
+ #
+ def each_strongly_connected_component_from(node, id_map={}, stack=[], &block) # :yields: nodes
+ Gem::TSort.each_strongly_connected_component_from(node, method(:tsort_each_child), id_map, stack, &block)
+ end
+
+ # Iterates over strongly connected components in a graph.
+ # The graph is represented by _node_ and _each_child_.
+ #
+ # _node_ is the first node.
+ # _each_child_ should have +call+ method which takes a node argument
+ # and yields for each child node.
+ #
+ # Return value is unspecified.
+ #
+ # #Gem::TSort.each_strongly_connected_component_from is a class method and
+ # it doesn't need a class to represent a graph which includes Gem::TSort.
+ #
+ # graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
+ # each_child = lambda {|n, &b| graph[n].each(&b) }
+ # Gem::TSort.each_strongly_connected_component_from(1, each_child) {|scc|
+ # p scc
+ # }
+ # #=> [4]
+ # # [2, 3]
+ # # [1]
+ #
+ def self.each_strongly_connected_component_from(node, each_child, id_map={}, stack=[]) # :yields: nodes
+ return to_enum(__method__, node, each_child, id_map, stack) unless block_given?
+
+ minimum_id = node_id = id_map[node] = id_map.size
+ stack_length = stack.length
+ stack << node
+
+ each_child.call(node) {|child|
+ if id_map.include? child
+ child_id = id_map[child]
+ minimum_id = child_id if child_id && child_id < minimum_id
+ else
+ sub_minimum_id =
+ each_strongly_connected_component_from(child, each_child, id_map, stack) {|c|
+ yield c
+ }
+ minimum_id = sub_minimum_id if sub_minimum_id < minimum_id
+ end
+ }
+
+ if node_id == minimum_id
+ component = stack.slice!(stack_length .. -1)
+ component.each {|n| id_map[n] = nil}
+ yield component
+ end
+
+ minimum_id
+ end
+
+ # Should be implemented by a extended class.
+ #
+ # #tsort_each_node is used to iterate for all nodes over a graph.
+ #
+ def tsort_each_node # :yields: node
+ raise NotImplementedError.new
+ end
+
+ # Should be implemented by a extended class.
+ #
+ # #tsort_each_child is used to iterate for child nodes of _node_.
+ #
+ def tsort_each_child(node) # :yields: child
+ raise NotImplementedError.new
+ end
+end
diff --git a/lib/rubygems/uninstaller.rb b/lib/rubygems/uninstaller.rb
index 471c29b6e4..f678f960f0 100644
--- a/lib/rubygems/uninstaller.rb
+++ b/lib/rubygems/uninstaller.rb
@@ -32,7 +32,7 @@ class Gem::Uninstaller
attr_reader :bin_dir
##
- # The gem repository the gem will be uninstalled from
+ # The gem repository the gem will be installed into
attr_reader :gem_home
@@ -46,12 +46,11 @@ class Gem::Uninstaller
# Constructs an uninstaller that will uninstall +gem+
def initialize(gem, options = {})
- # TODO: document the valid options
+ # TODO document the valid options
@gem = gem
@version = options[:version] || Gem::Requirement.default
- @install_dir = options[:install_dir]
- @gem_home = File.realpath(@install_dir || Gem.dir)
- @user_dir = File.exist?(Gem.user_dir) ? File.realpath(Gem.user_dir) : Gem.user_dir
+ @gem_home = File.realpath(options[:install_dir] || Gem.dir)
+ @plugins_dir = Gem.plugindir(@gem_home)
@force_executables = options[:executables]
@force_all = options[:all]
@force_ignore = options[:ignore]
@@ -71,7 +70,7 @@ class Gem::Uninstaller
# only add user directory if install_dir is not set
@user_install = false
- @user_install = options[:user_install] unless @install_dir
+ @user_install = options[:user_install] unless options[:install_dir]
# Optimization: populated during #uninstall
@default_specs_matching_uninstall_params = []
@@ -86,7 +85,11 @@ class Gem::Uninstaller
list = []
- specification_record.stubs.each do |spec|
+ dirs =
+ Gem::Specification.dirs +
+ [Gem.default_specifications_dir]
+
+ Gem::Specification.each_spec dirs do |spec|
next unless dependency.matches_spec? spec
list << spec
@@ -96,13 +99,15 @@ class Gem::Uninstaller
raise Gem::InstallError, "gem #{@gem.inspect} is not installed"
end
- default_specs, list = list.partition(&:default_gem?)
+ default_specs, list = list.partition do |spec|
+ spec.default_gem?
+ end
warn_cannot_uninstall_default_gems(default_specs - list)
- @default_specs_matching_uninstall_params = default_specs.map(&:to_spec)
+ @default_specs_matching_uninstall_params = default_specs
list, other_repo_specs = list.partition do |spec|
@gem_home == spec.base_dir ||
- (@user_install && spec.base_dir == @user_dir)
+ (@user_install && spec.base_dir == Gem.user_dir)
end
list.sort!
@@ -110,7 +115,7 @@ class Gem::Uninstaller
if list.empty?
return unless other_repo_specs.any?
- other_repos = other_repo_specs.map(&:base_dir).uniq
+ other_repos = other_repo_specs.map {|spec| spec.base_dir }.uniq
message = ["#{@gem} is not installed in GEM_HOME, try:"]
message.concat other_repos.map {|repo|
@@ -122,7 +127,7 @@ class Gem::Uninstaller
remove_all list
elsif list.size > 1
- gem_names = list.map(&:full_name_with_location)
+ gem_names = list.map {|gem| gem.full_name }
gem_names << "All versions"
say
@@ -130,7 +135,7 @@ class Gem::Uninstaller
if index == list.size
remove_all list
- elsif index && index >= 0 && index < list.size
+ elsif index >= 0 && index < list.size
uninstall_gem list[index]
else
say "Error: must enter a number [1-#{list.size + 1}]"
@@ -143,9 +148,7 @@ class Gem::Uninstaller
##
# Uninstalls gem +spec+
- def uninstall_gem(stub)
- spec = stub.to_spec
-
+ def uninstall_gem(spec)
@spec = spec
unless dependencies_ok? spec
@@ -163,8 +166,6 @@ class Gem::Uninstaller
remove_plugins @spec
remove @spec
- specification_record.remove_spec(stub)
-
regenerate_plugins
Gem.post_uninstall_hooks.each do |hook|
@@ -178,7 +179,7 @@ class Gem::Uninstaller
# Removes installed executables and batch files (windows only) for +spec+.
def remove_executables(spec)
- return if spec.executables.empty? || default_spec_matches?(spec)
+ return if spec.executables.empty?
executables = spec.executables.clone
@@ -200,8 +201,8 @@ class Gem::Uninstaller
executables = executables.map {|exec| formatted_program_filename exec }
remove = if @force_executables.nil?
- ask_yes_no("Remove executables:\n" \
- "\t#{executables.join ", "}\n\n" \
+ ask_yes_no("Remove executables:\n" +
+ "\t#{executables.join ', '}\n\n" +
"in addition to the gem?",
true)
else
@@ -240,9 +241,9 @@ class Gem::Uninstaller
def remove(spec)
unless path_ok?(@gem_home, spec) ||
- (@user_install && path_ok?(@user_dir, spec))
+ (@user_install && path_ok?(Gem.user_dir, spec))
e = Gem::GemNotInHomeException.new \
- "Gem '#{spec.full_name}' is not installed in directory #{@gem_home}"
+ "Gem '#{spec.full_name}' is not installed in directory #{@gem_home}"
e.spec = spec
raise e
@@ -251,15 +252,7 @@ class Gem::Uninstaller
raise Gem::FilePermissionError, spec.base_dir unless
File.writable?(spec.base_dir)
- full_gem_path = spec.full_gem_path
- exclusions = []
-
- if default_spec_matches?(spec) && spec.executables.any?
- exclusions = spec.executables.map {|exe| File.join(spec.bin_dir, exe) }
- exclusions << File.dirname(exclusions.last) until exclusions.last == full_gem_path
- end
-
- safe_delete { rm_r full_gem_path, exclusions: exclusions }
+ safe_delete { FileUtils.rm_r spec.full_gem_path }
safe_delete { FileUtils.rm_r spec.extension_dir }
old_platform_name = spec.original_name
@@ -283,6 +276,8 @@ class Gem::Uninstaller
safe_delete { FileUtils.rm_r gemspec }
announce_deletion_of(spec)
+
+ Gem::Specification.reset
end
##
@@ -291,17 +286,17 @@ class Gem::Uninstaller
def remove_plugins(spec) # :nodoc:
return if spec.plugins.empty?
- remove_plugins_for(spec, plugin_dir_for(spec))
+ remove_plugins_for(spec, @plugins_dir)
end
##
# Regenerates plugin wrappers after removal.
def regenerate_plugins
- latest = specification_record.latest_spec_for(@spec.name)
+ latest = Gem::Specification.latest_spec_for(@spec.name)
return if latest.nil?
- regenerate_plugins_for(latest, plugin_dir_for(@spec))
+ regenerate_plugins_for(latest, @plugins_dir)
end
##
@@ -347,7 +342,7 @@ class Gem::Uninstaller
s.name == spec.name && s.full_name != spec.full_name
end
- spec.dependent_gems(@check_dev).each do |dep_spec, dep, _satlist|
+ spec.dependent_gems(@check_dev).each do |dep_spec, dep, satlist|
unless siblings.any? {|s| s.satisfies_requirement? dep }
msg << "#{dep_spec.name}-#{dep_spec.version} depends on #{dep}"
end
@@ -355,7 +350,7 @@ class Gem::Uninstaller
msg << "If you remove this gem, these dependencies will not be met."
msg << "Continue with Uninstall?"
- ask_yes_no(msg.join("\n"), false)
+ return ask_yes_no(msg.join("\n"), false)
end
##
@@ -386,16 +381,6 @@ class Gem::Uninstaller
private
- def rm_r(path, exclusions:)
- FileUtils::Entry_.new(path).postorder_traverse do |ent|
- ent.remove unless exclusions.include?(ent.path)
- end
- end
-
- def specification_record
- @specification_record ||= @install_dir ? Gem::SpecificationRecord.from_path(@install_dir) : Gem::Specification.specification_record
- end
-
def announce_deletion_of(spec)
name = spec.full_name
say "Successfully uninstalled #{name}"
@@ -423,8 +408,4 @@ class Gem::Uninstaller
say "Gem #{spec.full_name} cannot be uninstalled because it is a default gem"
end
end
-
- def plugin_dir_for(spec)
- Gem.plugindir(spec.base_dir)
- end
end
diff --git a/lib/rubygems/update_suggestion.rb b/lib/rubygems/update_suggestion.rb
index 6f3ec5f493..c2e81b2374 100644
--- a/lib/rubygems/update_suggestion.rb
+++ b/lib/rubygems/update_suggestion.rb
@@ -4,6 +4,15 @@
# Mixin methods for Gem::Command to promote available RubyGems update
module Gem::UpdateSuggestion
+ # list taken from https://github.com/watson/ci-info/blob/7a3c30d/index.js#L56-L66
+ CI_ENV_VARS = [
+ "CI", # Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari
+ "CONTINUOUS_INTEGRATION", # Travis CI, Cirrus CI
+ "BUILD_NUMBER", # Jenkins, TeamCity
+ "CI_APP_ID", "CI_BUILD_ID", "CI_BUILD_NUMBER", # Applfow
+ "RUN_ID" # TaskCluster, dsari
+ ].freeze
+
ONE_WEEK = 7 * 24 * 60 * 60
##
@@ -19,9 +28,9 @@ Run `gem update --system #{Gem.latest_rubygems_version}` to update your installa
end
##
- # Determines if current environment is eligible for update suggestion.
+ # Determines if current environment is eglible for update suggestion.
- def eligible_for_update?
+ def eglible_for_update?
# explicit opt-out
return false if Gem.configuration[:prevent_update_suggestion]
return false if ENV["RUBYGEMS_PREVENT_UPDATE_SUGGESTION"]
@@ -30,7 +39,7 @@ Run `gem update --system #{Gem.latest_rubygems_version}` to update your installa
return false unless Gem.ui.tty?
return false if Gem.rubygems_version.prerelease?
return false if Gem.disable_system_update_message
- return false if Gem::CIDetector.ci?
+ return false if ci?
# check makes sense only when we can store timestamp of last try
# otherwise we will not be able to prevent "annoying" update message
@@ -44,13 +53,17 @@ Run `gem update --system #{Gem.latest_rubygems_version}` to update your installa
# compare current and latest version, this is the part where
# latest rubygems spec is fetched from remote
- (Gem.rubygems_version < Gem.latest_rubygems_version).tap do |eligible|
+ (Gem.rubygems_version < Gem.latest_rubygems_version).tap do |eglible|
# store the time of last successful check into state file
Gem.configuration.last_update_check = check_time
- return eligible
+ return eglible
end
- rescue StandardError # don't block install command on any problem
+ rescue # don't block install command on any problem
false
end
+
+ def ci?
+ CI_ENV_VARS.any? {|var| ENV.include?(var) }
+ end
end
diff --git a/lib/rubygems/uri.rb b/lib/rubygems/uri.rb
index a44aaceba5..4b5d035aa0 100644
--- a/lib/rubygems/uri.rb
+++ b/lib/rubygems/uri.rb
@@ -16,9 +16,9 @@ class Gem::Uri
# Parses uri, raising if it's invalid
def self.parse!(uri)
- require_relative "vendor/uri/lib/uri"
+ require "uri"
- raise Gem::URI::InvalidURIError unless uri
+ raise URI::InvalidURIError unless uri
return uri unless uri.is_a?(String)
@@ -28,9 +28,9 @@ class Gem::Uri
# as "%7BDESede%7D". If this is escaped again the percentage
# symbols will be escaped.
begin
- Gem::URI.parse(uri)
- rescue Gem::URI::InvalidURIError
- Gem::URI.parse(Gem::URI::DEFAULT_PARSER.escape(uri))
+ URI.parse(uri)
+ rescue URI::InvalidURIError
+ URI.parse(URI::DEFAULT_PARSER.escape(uri))
end
end
@@ -39,7 +39,7 @@ class Gem::Uri
def self.parse(uri)
parse!(uri)
- rescue Gem::URI::InvalidURIError
+ rescue URI::InvalidURIError
uri
end
diff --git a/lib/rubygems/uri_formatter.rb b/lib/rubygems/uri_formatter.rb
index 517ce33637..3f1d02d774 100644
--- a/lib/rubygems/uri_formatter.rb
+++ b/lib/rubygems/uri_formatter.rb
@@ -34,7 +34,7 @@ class Gem::UriFormatter
# Normalize the URI by adding "http://" if it is missing.
def normalize
- /^(https?|ftp|file):/i.match?(@uri) ? @uri : "http://#{@uri}"
+ (@uri =~ /^(https?|ftp|file):/i) ? @uri : "http://#{@uri}"
end
##
diff --git a/lib/rubygems/user_interaction.rb b/lib/rubygems/user_interaction.rb
index 0172c4ee89..451dba070f 100644
--- a/lib/rubygems/user_interaction.rb
+++ b/lib/rubygems/user_interaction.rb
@@ -14,6 +14,7 @@ require_relative "text"
# module will have access to the +ui+ method that returns the default UI.
module Gem::DefaultUserInteraction
+
include Gem::Text
##
@@ -68,6 +69,7 @@ module Gem::DefaultUserInteraction
def use_ui(new_ui, &block)
Gem::DefaultUserInteraction.use_ui(new_ui, &block)
end
+
end
##
@@ -90,6 +92,7 @@ end
# end
module Gem::UserInteraction
+
include Gem::DefaultUserInteraction
##
@@ -193,7 +196,7 @@ class Gem::StreamUI
# then special operations (like asking for passwords) will use the TTY
# commands to disable character echo.
- def initialize(in_stream, out_stream, err_stream=$stderr, usetty=true)
+ def initialize(in_stream, out_stream, err_stream=STDERR, usetty=true)
@ins = in_stream
@outs = out_stream
@errs = err_stream
@@ -238,7 +241,7 @@ class Gem::StreamUI
result = result.strip.to_i - 1
return nil, nil unless (0...list.size) === result
- [list[result], result]
+ return list[result], result
end
##
@@ -257,32 +260,33 @@ class Gem::StreamUI
end
default_answer = case default
- when nil
- "yn"
- when true
- "Yn"
- else
- "yN"
+ when nil
+ "yn"
+ when true
+ "Yn"
+ else
+ "yN"
end
result = nil
while result.nil? do
result = case ask "#{question} [#{default_answer}]"
- when /^y/i then true
- when /^n/i then false
- when /^$/ then default
+ when /^y/i then true
+ when /^n/i then false
+ when /^$/ then default
+ else nil
end
end
- result
+ return result
end
##
# Ask a question. Returns an answer if connected to a tty, nil otherwise.
def ask(question)
- return nil unless tty?
+ return nil if !tty?
@outs.print(question + " ")
@outs.flush
@@ -296,7 +300,7 @@ class Gem::StreamUI
# Ask for a password. Does not echo response to terminal.
def ask_for_password(question)
- return nil unless tty?
+ return nil if !tty?
@outs.print(question, " ")
@outs.flush
@@ -426,7 +430,8 @@ class Gem::StreamUI
# +size+ items. Shows the given +initial_message+ when progress starts
# and the +terminal_message+ when it is complete.
- def initialize(out_stream, size, initial_message, terminal_message = "complete")
+ def initialize(out_stream, size, initial_message,
+ terminal_message = "complete")
@out = out_stream
@total = size
@count = 0
@@ -468,7 +473,8 @@ class Gem::StreamUI
# +size+ items. Shows the given +initial_message+ when progress starts
# and the +terminal_message+ when it is complete.
- def initialize(out_stream, size, initial_message, terminal_message = "complete")
+ def initialize(out_stream, size, initial_message,
+ terminal_message = "complete")
@out = out_stream
@total = size
@count = 0
@@ -591,8 +597,8 @@ class Gem::StreamUI
end
##
-# Subclass of StreamUI that instantiates the user interaction using $stdin,
-# $stdout, and $stderr.
+# Subclass of StreamUI that instantiates the user interaction using STDIN,
+# STDOUT, and STDERR.
class Gem::ConsoleUI < Gem::StreamUI
##
@@ -600,7 +606,7 @@ class Gem::ConsoleUI < Gem::StreamUI
# stdin, output to stdout and warnings or errors to stderr.
def initialize
- super $stdin, $stdout, $stderr, true
+ super STDIN, STDOUT, STDERR, true
end
end
diff --git a/lib/rubygems/util.rb b/lib/rubygems/util.rb
index 51f9c2029f..bd6ea92cc9 100644
--- a/lib/rubygems/util.rb
+++ b/lib/rubygems/util.rb
@@ -6,6 +6,7 @@ require_relative "deprecate"
# This module contains various utility methods as module methods.
module Gem::Util
+
##
# Zlib::GzipReader wrapper that unzips +data+.
@@ -60,7 +61,7 @@ module Gem::Util
# Invokes system, but silences all output.
def self.silent_system(*command)
- opt = { out: IO::NULL, err: [:child, :out] }
+ opt = { :out => IO::NULL, :err => [:child, :out] }
if Hash === command.last
opt.update(command.last)
cmds = command[0...-1]
@@ -84,11 +85,7 @@ module Gem::Util
here = File.expand_path directory
loop do
- begin
- Dir.chdir here, &block
- rescue StandardError
- Errno::EACCES
- end
+ Dir.chdir here, &block rescue Errno::EACCES
new_here = File.expand_path("..", here)
return if new_here == here # toplevel
@@ -105,14 +102,15 @@ module Gem::Util
end
##
- # Corrects +path+ (usually returned by `Gem::URI.parse().path` on Windows), that
+ # Corrects +path+ (usually returned by `URI.parse().path` on Windows), that
# comes with a leading slash.
def self.correct_for_windows_path(path)
- if path[0].chr == "/" && path[1].chr.match?(/[a-z]/i) && path[2].chr == ":"
+ if path[0].chr == "/" && path[1].chr =~ /[a-z]/i && path[2].chr == ":"
path[1..-1]
else
path
end
end
+
end
diff --git a/lib/rubygems/util/licenses.rb b/lib/rubygems/util/licenses.rb
index 192ae30b9b..1d5efde576 100644
--- a/lib/rubygems/util/licenses.rb
+++ b/lib/rubygems/util/licenses.rb
@@ -1,8 +1,5 @@
# frozen_string_literal: true
-# This is generated by generate_spdx_license_list.rb, any edits to this
-# file will be discarded.
-
require_relative "../text"
class Gem::Licenses
@@ -15,7 +12,6 @@ class Gem::Licenses
# license identifiers
LICENSE_IDENTIFIERS = %w[
0BSD
- 3D-Slicer-1.0
AAL
ADSL
AFL-1.1
@@ -23,14 +19,14 @@ class Gem::Licenses
AFL-2.0
AFL-2.1
AFL-3.0
+ AGPL-1.0
AGPL-1.0-only
AGPL-1.0-or-later
+ AGPL-3.0
AGPL-3.0-only
AGPL-3.0-or-later
- AMD-newlib
AMDPLPA
AML
- AML-glslang
AMPAS
ANTLR-PD
ANTLR-PD-fallback
@@ -40,35 +36,27 @@ class Gem::Licenses
APSL-1.1
APSL-1.2
APSL-2.0
- ASWF-Digital-Assets-1.0
- ASWF-Digital-Assets-1.1
Abstyles
- AdaCore-doc
Adobe-2006
- Adobe-Display-PostScript
Adobe-Glyph
- Adobe-Utopia
Afmparse
Aladdin
Apache-1.0
Apache-1.1
Apache-2.0
- App-s2p
- Arphic-1999
Artistic-1.0
Artistic-1.0-Perl
Artistic-1.0-cl8
Artistic-2.0
BSD-1-Clause
BSD-2-Clause
- BSD-2-Clause-Darwin
+ BSD-2-Clause-FreeBSD
+ BSD-2-Clause-NetBSD
BSD-2-Clause-Patent
BSD-2-Clause-Views
- BSD-2-Clause-first-lines
BSD-3-Clause
BSD-3-Clause-Attribution
BSD-3-Clause-Clear
- BSD-3-Clause-HP
BSD-3-Clause-LBNL
BSD-3-Clause-Modification
BSD-3-Clause-No-Military-License
@@ -76,37 +64,20 @@ class Gem::Licenses
BSD-3-Clause-No-Nuclear-License-2014
BSD-3-Clause-No-Nuclear-Warranty
BSD-3-Clause-Open-MPI
- BSD-3-Clause-Sun
- BSD-3-Clause-acpica
- BSD-3-Clause-flex
BSD-4-Clause
BSD-4-Clause-Shortened
BSD-4-Clause-UC
- BSD-4.3RENO
- BSD-4.3TAHOE
- BSD-Advertising-Acknowledgement
- BSD-Attribution-HPND-disclaimer
- BSD-Inferno-Nettverk
BSD-Protection
BSD-Source-Code
- BSD-Source-beginning-file
- BSD-Systemics
- BSD-Systemics-W3Works
BSL-1.0
BUSL-1.1
- Baekmuk
Bahyph
Barr
Beerware
BitTorrent-1.0
BitTorrent-1.1
- Bitstream-Charter
- Bitstream-Vera
BlueOak-1.0.0
- Boehm-GC
Borceux
- Brian-Gladman-2-Clause
- Brian-Gladman-3-Clause
C-UDA-1.0
CAL-1.0
CAL-1.0-Combined-Work-Exception
@@ -114,43 +85,30 @@ class Gem::Licenses
CC-BY-1.0
CC-BY-2.0
CC-BY-2.5
- CC-BY-2.5-AU
CC-BY-3.0
CC-BY-3.0-AT
- CC-BY-3.0-AU
- CC-BY-3.0-DE
- CC-BY-3.0-IGO
- CC-BY-3.0-NL
CC-BY-3.0-US
CC-BY-4.0
CC-BY-NC-1.0
CC-BY-NC-2.0
CC-BY-NC-2.5
CC-BY-NC-3.0
- CC-BY-NC-3.0-DE
CC-BY-NC-4.0
CC-BY-NC-ND-1.0
CC-BY-NC-ND-2.0
CC-BY-NC-ND-2.5
CC-BY-NC-ND-3.0
- CC-BY-NC-ND-3.0-DE
CC-BY-NC-ND-3.0-IGO
CC-BY-NC-ND-4.0
CC-BY-NC-SA-1.0
CC-BY-NC-SA-2.0
- CC-BY-NC-SA-2.0-DE
- CC-BY-NC-SA-2.0-FR
- CC-BY-NC-SA-2.0-UK
CC-BY-NC-SA-2.5
CC-BY-NC-SA-3.0
- CC-BY-NC-SA-3.0-DE
- CC-BY-NC-SA-3.0-IGO
CC-BY-NC-SA-4.0
CC-BY-ND-1.0
CC-BY-ND-2.0
CC-BY-ND-2.5
CC-BY-ND-3.0
- CC-BY-ND-3.0-DE
CC-BY-ND-4.0
CC-BY-SA-1.0
CC-BY-SA-2.0
@@ -159,8 +117,6 @@ class Gem::Licenses
CC-BY-SA-2.5
CC-BY-SA-3.0
CC-BY-SA-3.0-AT
- CC-BY-SA-3.0-DE
- CC-BY-SA-3.0-IGO
CC-BY-SA-4.0
CC-PDDC
CC0-1.0
@@ -168,7 +124,6 @@ class Gem::Licenses
CDDL-1.1
CDL-1.0
CDLA-Permissive-1.0
- CDLA-Permissive-2.0
CDLA-Sharing-1.0
CECILL-1.0
CECILL-1.1
@@ -181,36 +136,22 @@ class Gem::Licenses
CERN-OHL-P-2.0
CERN-OHL-S-2.0
CERN-OHL-W-2.0
- CFITSIO
- CMU-Mach
- CMU-Mach-nodoc
CNRI-Jython
CNRI-Python
CNRI-Python-GPL-Compatible
- COIL-1.0
CPAL-1.0
CPL-1.0
CPOL-1.02
CUA-OPL-1.0
Caldera
- Caldera-no-preamble
- Catharon
ClArtistic
- Clips
- Community-Spec-1.0
Condor-1.1
- Cornell-Lossless-JPEG
- Cronyx
Crossword
CrystalStacker
Cube
D-FSL-1.0
- DEC-3-Clause
- DL-DE-BY-2.0
- DL-DE-ZERO-2.0
DOC
DRL-1.0
- DRL-1.1
DSDP
Dotseqn
ECL-1.0
@@ -224,38 +165,33 @@ class Gem::Licenses
EUPL-1.0
EUPL-1.1
EUPL-1.2
- Elastic-2.0
Entessa
ErlPL-1.1
Eurosym
- FBM
- FDK-AAC
FSFAP
- FSFAP-no-warranty-disclaimer
FSFUL
FSFULLR
- FSFULLRWD
FTL
Fair
- Ferguson-Twofish
Frameworx-1.0
FreeBSD-DOC
FreeImage
- Furuseth
- GCR-docs
GD
+ GFDL-1.1
GFDL-1.1-invariants-only
GFDL-1.1-invariants-or-later
GFDL-1.1-no-invariants-only
GFDL-1.1-no-invariants-or-later
GFDL-1.1-only
GFDL-1.1-or-later
+ GFDL-1.2
GFDL-1.2-invariants-only
GFDL-1.2-invariants-or-later
GFDL-1.2-no-invariants-only
GFDL-1.2-no-invariants-or-later
GFDL-1.2-only
GFDL-1.2-or-later
+ GFDL-1.3
GFDL-1.3-invariants-only
GFDL-1.3-invariants-or-later
GFDL-1.3-no-invariants-only
@@ -264,80 +200,63 @@ class Gem::Licenses
GFDL-1.3-or-later
GL2PS
GLWTPL
+ GPL-1.0
+ GPL-1.0+
GPL-1.0-only
GPL-1.0-or-later
+ GPL-2.0
+ GPL-2.0+
GPL-2.0-only
GPL-2.0-or-later
+ GPL-2.0-with-GCC-exception
+ GPL-2.0-with-autoconf-exception
+ GPL-2.0-with-bison-exception
+ GPL-2.0-with-classpath-exception
+ GPL-2.0-with-font-exception
+ GPL-3.0
+ GPL-3.0+
GPL-3.0-only
GPL-3.0-or-later
+ GPL-3.0-with-GCC-exception
+ GPL-3.0-with-autoconf-exception
Giftware
Glide
Glulxe
- Graphics-Gems
- Gutmann
- HP-1986
- HP-1989
HPND
- HPND-DEC
- HPND-Fenneberg-Livingston
- HPND-INRIA-IMAG
- HPND-Intel
- HPND-Kevlin-Henney
- HPND-MIT-disclaimer
- HPND-Markus-Kuhn
- HPND-Pbmplus
- HPND-UC
- HPND-UC-export-US
- HPND-doc
- HPND-doc-sell
- HPND-export-US
- HPND-export-US-acknowledgement
- HPND-export-US-modify
- HPND-export2-US
- HPND-merchantability-variant
- HPND-sell-MIT-disclaimer-xserver
- HPND-sell-regexpr
HPND-sell-variant
- HPND-sell-variant-MIT-disclaimer
- HPND-sell-variant-MIT-disclaimer-rev
HTMLTIDY
HaskellReport
Hippocratic-2.1
IBM-pibs
ICU
- IEC-Code-Components-EULA
IJG
- IJG-short
IPA
IPL-1.0
ISC
- ISC-Veillard
ImageMagick
Imlib2
Info-ZIP
- Inner-Net-2.0
Intel
Intel-ACPI
Interbase-1.0
- JPL-image
JPNIC
JSON
- Jam
JasPer-2.0
- Kastrup
- Kazlib
- Knuth-CTAN
LAL-1.2
LAL-1.3
+ LGPL-2.0
+ LGPL-2.0+
LGPL-2.0-only
LGPL-2.0-or-later
+ LGPL-2.1
+ LGPL-2.1+
LGPL-2.1-only
LGPL-2.1-or-later
+ LGPL-3.0
+ LGPL-3.0+
LGPL-3.0-only
LGPL-3.0-or-later
LGPLLR
- LOOP
- LPD-document
LPL-1.0
LPL-1.02
LPPL-1.0
@@ -345,50 +264,30 @@ class Gem::Licenses
LPPL-1.2
LPPL-1.3a
LPPL-1.3c
- LZMA-SDK-9.11-to-9.20
- LZMA-SDK-9.22
Latex2e
- Latex2e-translated-notice
Leptonica
LiLiQ-P-1.1
LiLiQ-R-1.1
LiLiQ-Rplus-1.1
Libpng
Linux-OpenIB
- Linux-man-pages-1-para
- Linux-man-pages-copyleft
- Linux-man-pages-copyleft-2-para
- Linux-man-pages-copyleft-var
- Lucida-Bitmap-Fonts
MIT
MIT-0
MIT-CMU
- MIT-Festival
- MIT-Khronos-old
MIT-Modern-Variant
- MIT-Wu
MIT-advertising
MIT-enna
MIT-feh
MIT-open-group
- MIT-testregex
MITNFA
- MMIXware
- MPEG-SSG
MPL-1.0
MPL-1.1
MPL-2.0
MPL-2.0-no-copyleft-exception
- MS-LPL
MS-PL
MS-RL
MTLL
- Mackerras-3-Clause
- Mackerras-3-Clause-acknowledgment
MakeIndex
- Martin-Birgmeier
- McPhee-slideshow
- Minpack
MirOS
Motosoto
MulanPSL-1.0
@@ -398,17 +297,12 @@ class Gem::Licenses
NAIST-2003
NASA-1.3
NBPL-1.0
- NCBI-PD
NCGL-UK-2.0
- NCL
NCSA
NGPL
- NICTA-1.0
NIST-PD
NIST-PD-fallback
- NIST-Software
NLOD-1.0
- NLOD-2.0
NLPL
NOSL
NPL-1.0
@@ -423,13 +317,12 @@ class Gem::Licenses
Newsletr
Nokia
Noweb
+ Nunit
O-UDA-1.0
- OAR
OCCT-PL
OCLC-2.0
ODC-By-1.0
ODbL-1.0
- OFFIS
OFL-1.0
OFL-1.0-RFN
OFL-1.0-no-RFN
@@ -459,38 +352,27 @@ class Gem::Licenses
OLDAP-2.6
OLDAP-2.7
OLDAP-2.8
- OLFL-1.3
OML
OPL-1.0
- OPL-UK-3.0
- OPUBL-1.0
OSET-PL-2.1
OSL-1.0
OSL-1.1
OSL-2.0
OSL-2.1
OSL-3.0
- OpenPBS-2.3
OpenSSL
- OpenSSL-standalone
- OpenVision
- PADL
PDDL-1.0
PHP-3.0
PHP-3.01
- PPL
PSF-2.0
Parity-6.0.0
Parity-7.0.0
- Pixar
Plexus
PolyForm-Noncommercial-1.0.0
PolyForm-Small-Business-1.0.0
PostgreSQL
Python-2.0
- Python-2.0.1
QPL-1.0
- QPL-1.0-INRIA-2004
Qhull
RHeCos-1.1
RPL-1.1
@@ -501,66 +383,45 @@ class Gem::Licenses
Rdisc
Ruby
SAX-PD
- SAX-PD-2.0
SCEA
SGI-B-1.0
SGI-B-1.1
SGI-B-2.0
- SGI-OpenGL
- SGP4
SHL-0.5
SHL-0.51
SISSL
SISSL-1.2
- SL
SMLNJ
SMPPL
SNIA
SPL-1.0
SSH-OpenSSH
SSH-short
- SSLeay-standalone
SSPL-1.0
SWL
Saxpath
- SchemeReport
Sendmail
Sendmail-8.23
SimPL-2.0
Sleepycat
- Soundex
Spencer-86
Spencer-94
Spencer-99
+ StandardML-NJ
SugarCRM-1.1.3
- Sun-PPP
- Sun-PPP-2000
- SunPro
- Symlinks
TAPR-OHL-1.0
TCL
TCP-wrappers
- TGPPL-1.0
TMate
TORQUE-1.1
TOSL
- TPDL
- TPL-1.0
- TTWL
- TTYP0
TU-Berlin-1.0
TU-Berlin-2.0
- TermReadKey
- UCAR
UCL-1.0
- UMich-Merit
UPL-1.0
- URT-RLE
- Unicode-3.0
Unicode-DFS-2015
Unicode-DFS-2016
Unicode-TOU
- UnixCrypt
Unlicense
VOSTROM
VSL-1.0
@@ -570,15 +431,11 @@ class Gem::Licenses
W3C-20150513
WTFPL
Watcom-1.0
- Widget-Workshop
Wsuipa
X11
- X11-distribute-modifications-variant
XFree86-1.1
XSkat
- Xdebug-1.03
Xerox
- Xfig
Xnet
YPL-1.0
YPL-1.1
@@ -586,109 +443,41 @@ class Gem::Licenses
ZPL-2.0
ZPL-2.1
Zed
- Zeeff
Zend-2.0
Zimbra-1.3
Zimbra-1.4
Zlib
- any-OSI
- bcrypt-Solar-Designer
blessing
+ bzip2-1.0.5
bzip2-1.0.6
- check-cvs
- checkmk
copyleft-next-0.3.0
copyleft-next-0.3.1
curl
- cve-tou
diffmark
- dtoa
dvipdfm
+ eCos-2.0
eGenix
etalab-2.0
- fwlw
gSOAP-1.3b
gnuplot
- gtkbook
- hdparm
iMatix
libpng-2.0
libselinux-1.0
libtiff
- libutil-David-Nugent
- lsof
- magaz
- mailprio
- metamail
- mpi-permissive
mpich2
- mplus
- pkgconf
- pnmstitch
psfrag
psutils
- python-ldap
- radvd
- snprintf
- softSurfer
- ssh-keyscan
- swrule
- threeparttable
- ulem
- w3m
+ wxWindows
xinetd
- xkeyboard-config-Zinoviev
- xlock
xpp
- xzoom
zlib-acknowledgement
].freeze
- DEPRECATED_LICENSE_IDENTIFIERS = %w[
- AGPL-1.0
- AGPL-3.0
- BSD-2-Clause-FreeBSD
- BSD-2-Clause-NetBSD
- GFDL-1.1
- GFDL-1.2
- GFDL-1.3
- GPL-1.0
- GPL-1.0+
- GPL-2.0
- GPL-2.0+
- GPL-2.0-with-GCC-exception
- GPL-2.0-with-autoconf-exception
- GPL-2.0-with-bison-exception
- GPL-2.0-with-classpath-exception
- GPL-2.0-with-font-exception
- GPL-3.0
- GPL-3.0+
- GPL-3.0-with-GCC-exception
- GPL-3.0-with-autoconf-exception
- LGPL-2.0
- LGPL-2.0+
- LGPL-2.1
- LGPL-2.1+
- LGPL-3.0
- LGPL-3.0+
- Nunit
- StandardML-NJ
- bzip2-1.0.5
- eCos-2.0
- wxWindows
- ].freeze
-
# exception identifiers
EXCEPTION_IDENTIFIERS = %w[
389-exception
- Asterisk-exception
- Asterisk-linking-protocols-exception
Autoconf-exception-2.0
Autoconf-exception-3.0
- Autoconf-exception-generic
- Autoconf-exception-generic-3.0
- Autoconf-exception-macro
- Bison-exception-1.24
Bison-exception-2.2
Bootloader-exception
CLISP-exception-2.0
@@ -698,64 +487,38 @@ class Gem::Licenses
Fawkes-Runtime-exception
Font-exception-2.0
GCC-exception-2.0
- GCC-exception-2.0-note
GCC-exception-3.1
- GNAT-exception
- GNOME-examples-exception
- GNU-compiler-exception
- GPL-3.0-interface-exception
GPL-3.0-linking-exception
GPL-3.0-linking-source-exception
GPL-CC-1.0
- GStreamer-exception-2005
- GStreamer-exception-2008
- Gmsh-exception
- KiCad-libraries-exception
LGPL-3.0-linking-exception
- LLGPL
LLVM-exception
LZMA-exception
Libtool-exception
Linux-syscall-note
+ Nokia-Qt-exception-1.1
OCCT-exception-1.0
OCaml-LGPL-linking-exception
OpenJDK-assembly-exception-1.0
- PCRE2-exception
PS-or-PDF-font-exception-20170817
- QPL-1.0-INRIA-2004-exception
Qt-GPL-exception-1.0
Qt-LGPL-exception-1.1
Qwt-exception-1.0
- RRDtool-FLOSS-exception-2.0
- SANE-exception
SHL-2.0
SHL-2.1
- SWI-exception
Swift-exception
- Texinfo-exception
- UBDL-exception
Universal-FOSS-exception-1.0
WxWindows-exception-3.1
- cryptsetup-OpenSSL-exception
eCos-exception-2.0
- fmt-exception
freertos-exception-2.0
gnu-javamail-exception
i2p-gpl-java-exception
- libpri-OpenH323-exception
mif-exception
openvpn-openssl-exception
- stunnel-exception
u-boot-exception-2.0
- vsftpd-openssl-exception
- x11vnc-openssl-exception
].freeze
- DEPRECATED_EXCEPTION_IDENTIFIERS = %w[
- Nokia-Qt-exception-1.1
- ].freeze
-
- VALID_REGEXP = /
+ REGEXP = %r{
\A
(?:
#{Regexp.union(LICENSE_IDENTIFIERS)}
@@ -765,34 +528,10 @@ class Gem::Licenses
| #{LICENSE_REF}
)
\Z
- /ox
-
- DEPRECATED_LICENSE_REGEXP = /
- \A
- #{Regexp.union(DEPRECATED_LICENSE_IDENTIFIERS)}
- \+?
- (?:\s WITH \s .+?)?
- \Z
- /ox
-
- DEPRECATED_EXCEPTION_REGEXP = /
- \A
- .+?
- \+?
- (?:\s WITH \s #{Regexp.union(DEPRECATED_EXCEPTION_IDENTIFIERS)})
- \Z
- /ox
+ }ox.freeze
def self.match?(license)
- VALID_REGEXP.match?(license)
- end
-
- def self.deprecated_license_id?(license)
- DEPRECATED_LICENSE_REGEXP.match?(license)
- end
-
- def self.deprecated_exception_id?(license)
- DEPRECATED_EXCEPTION_REGEXP.match?(license)
+ !REGEXP.match(license).nil?
end
def self.suggestions(license)
diff --git a/lib/rubygems/util/list.rb b/lib/rubygems/util/list.rb
index 2899e8a2b9..acb6c73ddb 100644
--- a/lib/rubygems/util/list.rb
+++ b/lib/rubygems/util/list.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
module Gem
- # The Gem::List class is currently unused and will be removed in the next major rubygems version
- class List # :nodoc:
+ class List
include Enumerable
attr_accessor :value, :tail
@@ -36,5 +35,4 @@ module Gem
List.new value, list
end
end
- deprecate_constant :List
end
diff --git a/lib/rubygems/validator.rb b/lib/rubygems/validator.rb
index 57e0747eb4..63493638b6 100644
--- a/lib/rubygems/validator.rb
+++ b/lib/rubygems/validator.rb
@@ -25,7 +25,7 @@ class Gem::Validator
installed_files = []
Find.find gem_directory do |file_name|
- fn = file_name[gem_directory.size..file_name.size - 1].sub(%r{^/}, "")
+ fn = file_name[gem_directory.size..file_name.size - 1].sub(/^\//, "")
installed_files << fn unless
fn.empty? || fn.include?("CVS") || File.directory?(file_name)
end
@@ -63,9 +63,7 @@ class Gem::Validator
errors = Hash.new {|h,k| h[k] = {} }
Gem::Specification.each do |spec|
- unless gems.empty?
- next unless gems.include? spec.name
- end
+ next unless gems.include? spec.name unless gems.empty?
next if spec.default_gem?
gem_name = spec.file_name
@@ -90,7 +88,7 @@ class Gem::Validator
good, gone, unreadable = nil, nil, nil, nil
- File.open gem_path, Gem.binary_mode do |_file|
+ File.open gem_path, Gem.binary_mode do |file|
package = Gem::Package.new gem_path
good, gone = package.contents.partition do |file_name|
@@ -110,13 +108,15 @@ class Gem::Validator
end
good.each do |entry, data|
- next unless data # HACK: `gem check -a mkrf`
+ begin
+ next unless data # HACK `gem check -a mkrf`
- source = File.join gem_directory, entry["path"]
+ source = File.join gem_directory, entry["path"]
- File.open source, Gem.binary_mode do |f|
- unless f.read == data
- errors[gem_name][entry["path"]] = "Modified from original"
+ File.open source, Gem.binary_mode do |f|
+ unless f.read == data
+ errors[gem_name][entry["path"]] = "Modified from original"
+ end
end
end
end
diff --git a/lib/rubygems/vendor/molinillo/.document b/lib/rubygems/vendor/molinillo/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/molinillo/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo.rb b/lib/rubygems/vendor/molinillo/lib/molinillo.rb
deleted file mode 100644
index dd5600c9e3..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'molinillo/gem_metadata'
-require_relative 'molinillo/errors'
-require_relative 'molinillo/resolver'
-require_relative 'molinillo/modules/ui'
-require_relative 'molinillo/modules/specification_provider'
-
-# Gem::Molinillo is a generic dependency resolution algorithm.
-module Gem::Molinillo
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb
deleted file mode 100644
index 34842d46d5..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- # @!visibility private
- module Delegates
- # Delegates all {Gem::Molinillo::ResolutionState} methods to a `#state` property.
- module ResolutionState
- # (see Gem::Molinillo::ResolutionState#name)
- def name
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.name
- end
-
- # (see Gem::Molinillo::ResolutionState#requirements)
- def requirements
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.requirements
- end
-
- # (see Gem::Molinillo::ResolutionState#activated)
- def activated
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.activated
- end
-
- # (see Gem::Molinillo::ResolutionState#requirement)
- def requirement
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.requirement
- end
-
- # (see Gem::Molinillo::ResolutionState#possibilities)
- def possibilities
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.possibilities
- end
-
- # (see Gem::Molinillo::ResolutionState#depth)
- def depth
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.depth
- end
-
- # (see Gem::Molinillo::ResolutionState#conflicts)
- def conflicts
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.conflicts
- end
-
- # (see Gem::Molinillo::ResolutionState#unused_unwind_options)
- def unused_unwind_options
- current_state = state || Gem::Molinillo::ResolutionState.empty
- current_state.unused_unwind_options
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb
deleted file mode 100644
index 8417721537..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- module Delegates
- # Delegates all {Gem::Molinillo::SpecificationProvider} methods to a
- # `#specification_provider` property.
- module SpecificationProvider
- # (see Gem::Molinillo::SpecificationProvider#search_for)
- def search_for(dependency)
- with_no_such_dependency_error_handling do
- specification_provider.search_for(dependency)
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#dependencies_for)
- def dependencies_for(specification)
- with_no_such_dependency_error_handling do
- specification_provider.dependencies_for(specification)
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#requirement_satisfied_by?)
- def requirement_satisfied_by?(requirement, activated, spec)
- with_no_such_dependency_error_handling do
- specification_provider.requirement_satisfied_by?(requirement, activated, spec)
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#dependencies_equal?)
- def dependencies_equal?(dependencies, other_dependencies)
- with_no_such_dependency_error_handling do
- specification_provider.dependencies_equal?(dependencies, other_dependencies)
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#name_for)
- def name_for(dependency)
- with_no_such_dependency_error_handling do
- specification_provider.name_for(dependency)
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#name_for_explicit_dependency_source)
- def name_for_explicit_dependency_source
- with_no_such_dependency_error_handling do
- specification_provider.name_for_explicit_dependency_source
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#name_for_locking_dependency_source)
- def name_for_locking_dependency_source
- with_no_such_dependency_error_handling do
- specification_provider.name_for_locking_dependency_source
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#sort_dependencies)
- def sort_dependencies(dependencies, activated, conflicts)
- with_no_such_dependency_error_handling do
- specification_provider.sort_dependencies(dependencies, activated, conflicts)
- end
- end
-
- # (see Gem::Molinillo::SpecificationProvider#allow_missing?)
- def allow_missing?(dependency)
- with_no_such_dependency_error_handling do
- specification_provider.allow_missing?(dependency)
- end
- end
-
- private
-
- # Ensures any raised {NoSuchDependencyError} has its
- # {NoSuchDependencyError#required_by} set.
- # @yield
- def with_no_such_dependency_error_handling
- yield
- rescue NoSuchDependencyError => error
- if state
- vertex = activated.vertex_named(name_for(error.dependency))
- error.required_by += vertex.incoming_edges.map { |e| e.origin.name }
- error.required_by << name_for_explicit_dependency_source unless vertex.explicit_requirements.empty?
- end
- raise
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph.rb
deleted file mode 100644
index 2dbbc589dc..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph.rb
+++ /dev/null
@@ -1,255 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../../../../vendored_tsort'
-
-require_relative 'dependency_graph/log'
-require_relative 'dependency_graph/vertex'
-
-module Gem::Molinillo
- # A directed acyclic graph that is tuned to hold named dependencies
- class DependencyGraph
- include Enumerable
-
- # Enumerates through the vertices of the graph.
- # @return [Array<Vertex>] The graph's vertices.
- def each
- return vertices.values.each unless block_given?
- vertices.values.each { |v| yield v }
- end
-
- include Gem::TSort
-
- # @!visibility private
- alias tsort_each_node each
-
- # @!visibility private
- def tsort_each_child(vertex, &block)
- vertex.successors.each(&block)
- end
-
- # Topologically sorts the given vertices.
- # @param [Enumerable<Vertex>] vertices the vertices to be sorted, which must
- # all belong to the same graph.
- # @return [Array<Vertex>] The sorted vertices.
- def self.tsort(vertices)
- Gem::TSort.tsort(
- lambda { |b| vertices.each(&b) },
- lambda { |v, &b| (v.successors & vertices).each(&b) }
- )
- end
-
- # A directed edge of a {DependencyGraph}
- # @attr [Vertex] origin The origin of the directed edge
- # @attr [Vertex] destination The destination of the directed edge
- # @attr [Object] requirement The requirement the directed edge represents
- Edge = Struct.new(:origin, :destination, :requirement)
-
- # @return [{String => Vertex}] the vertices of the dependency graph, keyed
- # by {Vertex#name}
- attr_reader :vertices
-
- # @return [Log] the op log for this graph
- attr_reader :log
-
- # Initializes an empty dependency graph
- def initialize
- @vertices = {}
- @log = Log.new
- end
-
- # Tags the current state of the dependency as the given tag
- # @param [Object] tag an opaque tag for the current state of the graph
- # @return [Void]
- def tag(tag)
- log.tag(self, tag)
- end
-
- # Rewinds the graph to the state tagged as `tag`
- # @param [Object] tag the tag to rewind to
- # @return [Void]
- def rewind_to(tag)
- log.rewind_to(self, tag)
- end
-
- # Initializes a copy of a {DependencyGraph}, ensuring that all {#vertices}
- # are properly copied.
- # @param [DependencyGraph] other the graph to copy.
- def initialize_copy(other)
- super
- @vertices = {}
- @log = other.log.dup
- traverse = lambda do |new_v, old_v|
- return if new_v.outgoing_edges.size == old_v.outgoing_edges.size
- old_v.outgoing_edges.each do |edge|
- destination = add_vertex(edge.destination.name, edge.destination.payload)
- add_edge_no_circular(new_v, destination, edge.requirement)
- traverse.call(destination, edge.destination)
- end
- end
- other.vertices.each do |name, vertex|
- new_vertex = add_vertex(name, vertex.payload, vertex.root?)
- new_vertex.explicit_requirements.replace(vertex.explicit_requirements)
- traverse.call(new_vertex, vertex)
- end
- end
-
- # @return [String] a string suitable for debugging
- def inspect
- "#{self.class}:#{vertices.values.inspect}"
- end
-
- # @param [Hash] options options for dot output.
- # @return [String] Returns a dot format representation of the graph
- def to_dot(options = {})
- edge_label = options.delete(:edge_label)
- raise ArgumentError, "Unknown options: #{options.keys}" unless options.empty?
-
- dot_vertices = []
- dot_edges = []
- vertices.each do |n, v|
- dot_vertices << " #{n} [label=\"{#{n}|#{v.payload}}\"]"
- v.outgoing_edges.each do |e|
- label = edge_label ? edge_label.call(e) : e.requirement
- dot_edges << " #{e.origin.name} -> #{e.destination.name} [label=#{label.to_s.dump}]"
- end
- end
-
- dot_vertices.uniq!
- dot_vertices.sort!
- dot_edges.uniq!
- dot_edges.sort!
-
- dot = dot_vertices.unshift('digraph G {').push('') + dot_edges.push('}')
- dot.join("\n")
- end
-
- # @param [DependencyGraph] other
- # @return [Boolean] whether the two dependency graphs are equal, determined
- # by a recursive traversal of each {#root_vertices} and its
- # {Vertex#successors}
- def ==(other)
- return false unless other
- return true if equal?(other)
- vertices.each do |name, vertex|
- other_vertex = other.vertex_named(name)
- return false unless other_vertex
- return false unless vertex.payload == other_vertex.payload
- return false unless other_vertex.successors.to_set == vertex.successors.to_set
- end
- end
-
- # @param [String] name
- # @param [Object] payload
- # @param [Array<String>] parent_names
- # @param [Object] requirement the requirement that is requiring the child
- # @return [void]
- def add_child_vertex(name, payload, parent_names, requirement)
- root = !parent_names.delete(nil) { true }
- vertex = add_vertex(name, payload, root)
- vertex.explicit_requirements << requirement if root
- parent_names.each do |parent_name|
- parent_vertex = vertex_named(parent_name)
- add_edge(parent_vertex, vertex, requirement)
- end
- vertex
- end
-
- # Adds a vertex with the given name, or updates the existing one.
- # @param [String] name
- # @param [Object] payload
- # @return [Vertex] the vertex that was added to `self`
- def add_vertex(name, payload, root = false)
- log.add_vertex(self, name, payload, root)
- end
-
- # Detaches the {#vertex_named} `name` {Vertex} from the graph, recursively
- # removing any non-root vertices that were orphaned in the process
- # @param [String] name
- # @return [Array<Vertex>] the vertices which have been detached
- def detach_vertex_named(name)
- log.detach_vertex_named(self, name)
- end
-
- # @param [String] name
- # @return [Vertex,nil] the vertex with the given name
- def vertex_named(name)
- vertices[name]
- end
-
- # @param [String] name
- # @return [Vertex,nil] the root vertex with the given name
- def root_vertex_named(name)
- vertex = vertex_named(name)
- vertex if vertex && vertex.root?
- end
-
- # Adds a new {Edge} to the dependency graph
- # @param [Vertex] origin
- # @param [Vertex] destination
- # @param [Object] requirement the requirement that this edge represents
- # @return [Edge] the added edge
- def add_edge(origin, destination, requirement)
- if destination.path_to?(origin)
- raise CircularDependencyError.new(path(destination, origin))
- end
- add_edge_no_circular(origin, destination, requirement)
- end
-
- # Deletes an {Edge} from the dependency graph
- # @param [Edge] edge
- # @return [Void]
- def delete_edge(edge)
- log.delete_edge(self, edge.origin.name, edge.destination.name, edge.requirement)
- end
-
- # Sets the payload of the vertex with the given name
- # @param [String] name the name of the vertex
- # @param [Object] payload the payload
- # @return [Void]
- def set_payload(name, payload)
- log.set_payload(self, name, payload)
- end
-
- private
-
- # Adds a new {Edge} to the dependency graph without checking for
- # circularity.
- # @param (see #add_edge)
- # @return (see #add_edge)
- def add_edge_no_circular(origin, destination, requirement)
- log.add_edge_no_circular(self, origin.name, destination.name, requirement)
- end
-
- # Returns the path between two vertices
- # @raise [ArgumentError] if there is no path between the vertices
- # @param [Vertex] from
- # @param [Vertex] to
- # @return [Array<Vertex>] the shortest path from `from` to `to`
- def path(from, to)
- distances = Hash.new(vertices.size + 1)
- distances[from.name] = 0
- predecessors = {}
- each do |vertex|
- vertex.successors.each do |successor|
- if distances[successor.name] > distances[vertex.name] + 1
- distances[successor.name] = distances[vertex.name] + 1
- predecessors[successor] = vertex
- end
- end
- end
-
- path = [to]
- while before = predecessors[to]
- path << before
- to = before
- break if to == from
- end
-
- unless path.last.equal?(from)
- raise ArgumentError, "There is no path from #{from.name} to #{to.name}"
- end
-
- path.reverse
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/action.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/action.rb
deleted file mode 100644
index 8707ec451d..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/action.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- class DependencyGraph
- # An action that modifies a {DependencyGraph} that is reversible.
- # @abstract
- class Action
- # rubocop:disable Lint/UnusedMethodArgument
-
- # @return [Symbol] The name of the action.
- def self.action_name
- raise 'Abstract'
- end
-
- # Performs the action on the given graph.
- # @param [DependencyGraph] graph the graph to perform the action on.
- # @return [Void]
- def up(graph)
- raise 'Abstract'
- end
-
- # Reverses the action on the given graph.
- # @param [DependencyGraph] graph the graph to reverse the action on.
- # @return [Void]
- def down(graph)
- raise 'Abstract'
- end
-
- # @return [Action,Nil] The previous action
- attr_accessor :previous
-
- # @return [Action,Nil] The next action
- attr_accessor :next
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb
deleted file mode 100644
index aa9815c5ae..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'action'
-module Gem::Molinillo
- class DependencyGraph
- # @!visibility private
- # (see DependencyGraph#add_edge_no_circular)
- class AddEdgeNoCircular < Action
- # @!group Action
-
- # (see Action.action_name)
- def self.action_name
- :add_vertex
- end
-
- # (see Action#up)
- def up(graph)
- edge = make_edge(graph)
- edge.origin.outgoing_edges << edge
- edge.destination.incoming_edges << edge
- edge
- end
-
- # (see Action#down)
- def down(graph)
- edge = make_edge(graph)
- delete_first(edge.origin.outgoing_edges, edge)
- delete_first(edge.destination.incoming_edges, edge)
- end
-
- # @!group AddEdgeNoCircular
-
- # @return [String] the name of the origin of the edge
- attr_reader :origin
-
- # @return [String] the name of the destination of the edge
- attr_reader :destination
-
- # @return [Object] the requirement that the edge represents
- attr_reader :requirement
-
- # @param [DependencyGraph] graph the graph to find vertices from
- # @return [Edge] The edge this action adds
- def make_edge(graph)
- Edge.new(graph.vertex_named(origin), graph.vertex_named(destination), requirement)
- end
-
- # Initialize an action to add an edge to a dependency graph
- # @param [String] origin the name of the origin of the edge
- # @param [String] destination the name of the destination of the edge
- # @param [Object] requirement the requirement that the edge represents
- def initialize(origin, destination, requirement)
- @origin = origin
- @destination = destination
- @requirement = requirement
- end
-
- private
-
- def delete_first(array, item)
- return unless index = array.index(item)
- array.delete_at(index)
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb
deleted file mode 100644
index 9c7066a669..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'action'
-module Gem::Molinillo
- class DependencyGraph
- # @!visibility private
- # (see DependencyGraph#add_vertex)
- class AddVertex < Action # :nodoc:
- # @!group Action
-
- # (see Action.action_name)
- def self.action_name
- :add_vertex
- end
-
- # (see Action#up)
- def up(graph)
- if existing = graph.vertices[name]
- @existing_payload = existing.payload
- @existing_root = existing.root
- end
- vertex = existing || Vertex.new(name, payload)
- graph.vertices[vertex.name] = vertex
- vertex.payload ||= payload
- vertex.root ||= root
- vertex
- end
-
- # (see Action#down)
- def down(graph)
- if defined?(@existing_payload)
- vertex = graph.vertices[name]
- vertex.payload = @existing_payload
- vertex.root = @existing_root
- else
- graph.vertices.delete(name)
- end
- end
-
- # @!group AddVertex
-
- # @return [String] the name of the vertex
- attr_reader :name
-
- # @return [Object] the payload for the vertex
- attr_reader :payload
-
- # @return [Boolean] whether the vertex is root or not
- attr_reader :root
-
- # Initialize an action to add a vertex to a dependency graph
- # @param [String] name the name of the vertex
- # @param [Object] payload the payload for the vertex
- # @param [Boolean] root whether the vertex is root or not
- def initialize(name, payload, root)
- @name = name
- @payload = payload
- @root = root
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb
deleted file mode 100644
index 1e62c0a0b6..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'action'
-module Gem::Molinillo
- class DependencyGraph
- # @!visibility private
- # (see DependencyGraph#delete_edge)
- class DeleteEdge < Action
- # @!group Action
-
- # (see Action.action_name)
- def self.action_name
- :delete_edge
- end
-
- # (see Action#up)
- def up(graph)
- edge = make_edge(graph)
- edge.origin.outgoing_edges.delete(edge)
- edge.destination.incoming_edges.delete(edge)
- end
-
- # (see Action#down)
- def down(graph)
- edge = make_edge(graph)
- edge.origin.outgoing_edges << edge
- edge.destination.incoming_edges << edge
- edge
- end
-
- # @!group DeleteEdge
-
- # @return [String] the name of the origin of the edge
- attr_reader :origin_name
-
- # @return [String] the name of the destination of the edge
- attr_reader :destination_name
-
- # @return [Object] the requirement that the edge represents
- attr_reader :requirement
-
- # @param [DependencyGraph] graph the graph to find vertices from
- # @return [Edge] The edge this action adds
- def make_edge(graph)
- Edge.new(
- graph.vertex_named(origin_name),
- graph.vertex_named(destination_name),
- requirement
- )
- end
-
- # Initialize an action to add an edge to a dependency graph
- # @param [String] origin_name the name of the origin of the edge
- # @param [String] destination_name the name of the destination of the edge
- # @param [Object] requirement the requirement that the edge represents
- def initialize(origin_name, destination_name, requirement)
- @origin_name = origin_name
- @destination_name = destination_name
- @requirement = requirement
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb
deleted file mode 100644
index 6132f969b9..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'action'
-module Gem::Molinillo
- class DependencyGraph
- # @!visibility private
- # @see DependencyGraph#detach_vertex_named
- class DetachVertexNamed < Action
- # @!group Action
-
- # (see Action#name)
- def self.action_name
- :add_vertex
- end
-
- # (see Action#up)
- def up(graph)
- return [] unless @vertex = graph.vertices.delete(name)
-
- removed_vertices = [@vertex]
- @vertex.outgoing_edges.each do |e|
- v = e.destination
- v.incoming_edges.delete(e)
- if !v.root? && v.incoming_edges.empty?
- removed_vertices.concat graph.detach_vertex_named(v.name)
- end
- end
-
- @vertex.incoming_edges.each do |e|
- v = e.origin
- v.outgoing_edges.delete(e)
- end
-
- removed_vertices
- end
-
- # (see Action#down)
- def down(graph)
- return unless @vertex
- graph.vertices[@vertex.name] = @vertex
- @vertex.outgoing_edges.each do |e|
- e.destination.incoming_edges << e
- end
- @vertex.incoming_edges.each do |e|
- e.origin.outgoing_edges << e
- end
- end
-
- # @!group DetachVertexNamed
-
- # @return [String] the name of the vertex to detach
- attr_reader :name
-
- # Initialize an action to detach a vertex from a dependency graph
- # @param [String] name the name of the vertex to detach
- def initialize(name)
- @name = name
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/log.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/log.rb
deleted file mode 100644
index 6954c4b1f8..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/log.rb
+++ /dev/null
@@ -1,126 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'add_edge_no_circular'
-require_relative 'add_vertex'
-require_relative 'delete_edge'
-require_relative 'detach_vertex_named'
-require_relative 'set_payload'
-require_relative 'tag'
-
-module Gem::Molinillo
- class DependencyGraph
- # A log for dependency graph actions
- class Log
- # Initializes an empty log
- def initialize
- @current_action = @first_action = nil
- end
-
- # @!macro [new] action
- # {include:DependencyGraph#$0}
- # @param [Graph] graph the graph to perform the action on
- # @param (see DependencyGraph#$0)
- # @return (see DependencyGraph#$0)
-
- # @macro action
- def tag(graph, tag)
- push_action(graph, Tag.new(tag))
- end
-
- # @macro action
- def add_vertex(graph, name, payload, root)
- push_action(graph, AddVertex.new(name, payload, root))
- end
-
- # @macro action
- def detach_vertex_named(graph, name)
- push_action(graph, DetachVertexNamed.new(name))
- end
-
- # @macro action
- def add_edge_no_circular(graph, origin, destination, requirement)
- push_action(graph, AddEdgeNoCircular.new(origin, destination, requirement))
- end
-
- # {include:DependencyGraph#delete_edge}
- # @param [Graph] graph the graph to perform the action on
- # @param [String] origin_name
- # @param [String] destination_name
- # @param [Object] requirement
- # @return (see DependencyGraph#delete_edge)
- def delete_edge(graph, origin_name, destination_name, requirement)
- push_action(graph, DeleteEdge.new(origin_name, destination_name, requirement))
- end
-
- # @macro action
- def set_payload(graph, name, payload)
- push_action(graph, SetPayload.new(name, payload))
- end
-
- # Pops the most recent action from the log and undoes the action
- # @param [DependencyGraph] graph
- # @return [Action] the action that was popped off the log
- def pop!(graph)
- return unless action = @current_action
- unless @current_action = action.previous
- @first_action = nil
- end
- action.down(graph)
- action
- end
-
- extend Enumerable
-
- # @!visibility private
- # Enumerates each action in the log
- # @yield [Action]
- def each
- return enum_for unless block_given?
- action = @first_action
- loop do
- break unless action
- yield action
- action = action.next
- end
- self
- end
-
- # @!visibility private
- # Enumerates each action in the log in reverse order
- # @yield [Action]
- def reverse_each
- return enum_for(:reverse_each) unless block_given?
- action = @current_action
- loop do
- break unless action
- yield action
- action = action.previous
- end
- self
- end
-
- # @macro action
- def rewind_to(graph, tag)
- loop do
- action = pop!(graph)
- raise "No tag #{tag.inspect} found" unless action
- break if action.class.action_name == :tag && action.tag == tag
- end
- end
-
- private
-
- # Adds the given action to the log, running the action
- # @param [DependencyGraph] graph
- # @param [Action] action
- # @return The value returned by `action.up`
- def push_action(graph, action)
- action.previous = @current_action
- @current_action.next = action if @current_action
- @current_action = action
- @first_action ||= action
- action.up(graph)
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb
deleted file mode 100644
index 9bcaaae0f9..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'action'
-module Gem::Molinillo
- class DependencyGraph
- # @!visibility private
- # @see DependencyGraph#set_payload
- class SetPayload < Action # :nodoc:
- # @!group Action
-
- # (see Action.action_name)
- def self.action_name
- :set_payload
- end
-
- # (see Action#up)
- def up(graph)
- vertex = graph.vertex_named(name)
- @old_payload = vertex.payload
- vertex.payload = payload
- end
-
- # (see Action#down)
- def down(graph)
- graph.vertex_named(name).payload = @old_payload
- end
-
- # @!group SetPayload
-
- # @return [String] the name of the vertex
- attr_reader :name
-
- # @return [Object] the payload for the vertex
- attr_reader :payload
-
- # Initialize an action to add set the payload for a vertex in a dependency
- # graph
- # @param [String] name the name of the vertex
- # @param [Object] payload the payload for the vertex
- def initialize(name, payload)
- @name = name
- @payload = payload
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb
deleted file mode 100644
index 62f243a2af..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'action'
-module Gem::Molinillo
- class DependencyGraph
- # @!visibility private
- # @see DependencyGraph#tag
- class Tag < Action
- # @!group Action
-
- # (see Action.action_name)
- def self.action_name
- :tag
- end
-
- # (see Action#up)
- def up(graph)
- end
-
- # (see Action#down)
- def down(graph)
- end
-
- # @!group Tag
-
- # @return [Object] An opaque tag
- attr_reader :tag
-
- # Initialize an action to tag a state of a dependency graph
- # @param [Object] tag an opaque tag
- def initialize(tag)
- @tag = tag
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb
deleted file mode 100644
index 074de369be..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb
+++ /dev/null
@@ -1,164 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- class DependencyGraph
- # A vertex in a {DependencyGraph} that encapsulates a {#name} and a
- # {#payload}
- class Vertex
- # @return [String] the name of the vertex
- attr_accessor :name
-
- # @return [Object] the payload the vertex holds
- attr_accessor :payload
-
- # @return [Array<Object>] the explicit requirements that required
- # this vertex
- attr_reader :explicit_requirements
-
- # @return [Boolean] whether the vertex is considered a root vertex
- attr_accessor :root
- alias root? root
-
- # Initializes a vertex with the given name and payload.
- # @param [String] name see {#name}
- # @param [Object] payload see {#payload}
- def initialize(name, payload)
- @name = name.frozen? ? name : name.dup.freeze
- @payload = payload
- @explicit_requirements = []
- @outgoing_edges = []
- @incoming_edges = []
- end
-
- # @return [Array<Object>] all of the requirements that required
- # this vertex
- def requirements
- (incoming_edges.map(&:requirement) + explicit_requirements).uniq
- end
-
- # @return [Array<Edge>] the edges of {#graph} that have `self` as their
- # {Edge#origin}
- attr_accessor :outgoing_edges
-
- # @return [Array<Edge>] the edges of {#graph} that have `self` as their
- # {Edge#destination}
- attr_accessor :incoming_edges
-
- # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
- # `self` as their {Edge#destination}
- def predecessors
- incoming_edges.map(&:origin)
- end
-
- # @return [Set<Vertex>] the vertices of {#graph} where `self` is a
- # {#descendent?}
- def recursive_predecessors
- _recursive_predecessors
- end
-
- # @param [Set<Vertex>] vertices the set to add the predecessors to
- # @return [Set<Vertex>] the vertices of {#graph} where `self` is a
- # {#descendent?}
- def _recursive_predecessors(vertices = new_vertex_set)
- incoming_edges.each do |edge|
- vertex = edge.origin
- next unless vertices.add?(vertex)
- vertex._recursive_predecessors(vertices)
- end
-
- vertices
- end
- protected :_recursive_predecessors
-
- # @return [Array<Vertex>] the vertices of {#graph} that have an edge with
- # `self` as their {Edge#origin}
- def successors
- outgoing_edges.map(&:destination)
- end
-
- # @return [Set<Vertex>] the vertices of {#graph} where `self` is an
- # {#ancestor?}
- def recursive_successors
- _recursive_successors
- end
-
- # @param [Set<Vertex>] vertices the set to add the successors to
- # @return [Set<Vertex>] the vertices of {#graph} where `self` is an
- # {#ancestor?}
- def _recursive_successors(vertices = new_vertex_set)
- outgoing_edges.each do |edge|
- vertex = edge.destination
- next unless vertices.add?(vertex)
- vertex._recursive_successors(vertices)
- end
-
- vertices
- end
- protected :_recursive_successors
-
- # @return [String] a string suitable for debugging
- def inspect
- "#{self.class}:#{name}(#{payload.inspect})"
- end
-
- # @return [Boolean] whether the two vertices are equal, determined
- # by a recursive traversal of each {Vertex#successors}
- def ==(other)
- return true if equal?(other)
- shallow_eql?(other) &&
- successors.to_set == other.successors.to_set
- end
-
- # @param [Vertex] other the other vertex to compare to
- # @return [Boolean] whether the two vertices are equal, determined
- # solely by {#name} and {#payload} equality
- def shallow_eql?(other)
- return true if equal?(other)
- other &&
- name == other.name &&
- payload == other.payload
- end
-
- alias eql? ==
-
- # @return [Fixnum] a hash for the vertex based upon its {#name}
- def hash
- name.hash
- end
-
- # Is there a path from `self` to `other` following edges in the
- # dependency graph?
- # @return whether there is a path following edges within this {#graph}
- def path_to?(other)
- _path_to?(other)
- end
-
- alias descendent? path_to?
-
- # @param [Vertex] other the vertex to check if there's a path to
- # @param [Set<Vertex>] visited the vertices of {#graph} that have been visited
- # @return [Boolean] whether there is a path to `other` from `self`
- def _path_to?(other, visited = new_vertex_set)
- return false unless visited.add?(self)
- return true if equal?(other)
- successors.any? { |v| v._path_to?(other, visited) }
- end
- protected :_path_to?
-
- # Is there a path from `other` to `self` following edges in the
- # dependency graph?
- # @return whether there is a path following edges within this {#graph}
- def ancestor?(other)
- other.path_to?(self)
- end
-
- alias is_reachable_from? ancestor?
-
- def new_vertex_set
- require 'set'
- Set.new
- end
- private :new_vertex_set
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/errors.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/errors.rb
deleted file mode 100644
index 07ea5fdf37..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/errors.rb
+++ /dev/null
@@ -1,149 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- # An error that occurred during the resolution process
- class ResolverError < StandardError; end
-
- # An error caused by searching for a dependency that is completely unknown,
- # i.e. has no versions available whatsoever.
- class NoSuchDependencyError < ResolverError
- # @return [Object] the dependency that could not be found
- attr_accessor :dependency
-
- # @return [Array<Object>] the specifications that depended upon {#dependency}
- attr_accessor :required_by
-
- # Initializes a new error with the given missing dependency.
- # @param [Object] dependency @see {#dependency}
- # @param [Array<Object>] required_by @see {#required_by}
- def initialize(dependency, required_by = [])
- @dependency = dependency
- @required_by = required_by.uniq
- super()
- end
-
- # The error message for the missing dependency, including the specifications
- # that had this dependency.
- def message
- sources = required_by.map { |r| "`#{r}`" }.join(' and ')
- message = "Unable to find a specification for `#{dependency}`"
- message += " depended upon by #{sources}" unless sources.empty?
- message
- end
- end
-
- # An error caused by attempting to fulfil a dependency that was circular
- #
- # @note This exception will be thrown if and only if a {Vertex} is added to a
- # {DependencyGraph} that has a {DependencyGraph::Vertex#path_to?} an
- # existing {DependencyGraph::Vertex}
- class CircularDependencyError < ResolverError
- # [Set<Object>] the dependencies responsible for causing the error
- attr_reader :dependencies
-
- # Initializes a new error with the given circular vertices.
- # @param [Array<DependencyGraph::Vertex>] vertices the vertices in the dependency
- # that caused the error
- def initialize(vertices)
- super "There is a circular dependency between #{vertices.map(&:name).join(' and ')}"
- @dependencies = vertices.map { |vertex| vertex.payload.possibilities.last }.to_set
- end
- end
-
- # An error caused by conflicts in version
- class VersionConflict < ResolverError
- # @return [{String => Resolution::Conflict}] the conflicts that caused
- # resolution to fail
- attr_reader :conflicts
-
- # @return [SpecificationProvider] the specification provider used during
- # resolution
- attr_reader :specification_provider
-
- # Initializes a new error with the given version conflicts.
- # @param [{String => Resolution::Conflict}] conflicts see {#conflicts}
- # @param [SpecificationProvider] specification_provider see {#specification_provider}
- def initialize(conflicts, specification_provider)
- pairs = []
- conflicts.values.flat_map(&:requirements).each do |conflicting|
- conflicting.each do |source, conflict_requirements|
- conflict_requirements.each do |c|
- pairs << [c, source]
- end
- end
- end
-
- super "Unable to satisfy the following requirements:\n\n" \
- "#{pairs.map { |r, d| "- `#{r}` required by `#{d}`" }.join("\n")}"
-
- @conflicts = conflicts
- @specification_provider = specification_provider
- end
-
- require_relative 'delegates/specification_provider'
- include Delegates::SpecificationProvider
-
- # @return [String] An error message that includes requirement trees,
- # which is much more detailed & customizable than the default message
- # @param [Hash] opts the options to create a message with.
- # @option opts [String] :solver_name The user-facing name of the solver
- # @option opts [String] :possibility_type The generic name of a possibility
- # @option opts [Proc] :reduce_trees A proc that reduced the list of requirement trees
- # @option opts [Proc] :printable_requirement A proc that pretty-prints requirements
- # @option opts [Proc] :additional_message_for_conflict A proc that appends additional
- # messages for each conflict
- # @option opts [Proc] :version_for_spec A proc that returns the version number for a
- # possibility
- def message_with_trees(opts = {})
- solver_name = opts.delete(:solver_name) { self.class.name.split('::').first }
- possibility_type = opts.delete(:possibility_type) { 'possibility named' }
- reduce_trees = opts.delete(:reduce_trees) { proc { |trees| trees.uniq.sort_by(&:to_s) } }
- printable_requirement = opts.delete(:printable_requirement) { proc { |req| req.to_s } }
- additional_message_for_conflict = opts.delete(:additional_message_for_conflict) { proc {} }
- version_for_spec = opts.delete(:version_for_spec) { proc(&:to_s) }
- incompatible_version_message_for_conflict = opts.delete(:incompatible_version_message_for_conflict) do
- proc do |name, _conflict|
- %(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":)
- end
- end
-
- full_message_for_conflict = opts.delete(:full_message_for_conflict) do
- proc do |name, conflict|
- o = "\n".dup << incompatible_version_message_for_conflict.call(name, conflict) << "\n"
- if conflict.locked_requirement
- o << %( In snapshot (#{name_for_locking_dependency_source}):\n)
- o << %( #{printable_requirement.call(conflict.locked_requirement)}\n)
- o << %(\n)
- end
- o << %( In #{name_for_explicit_dependency_source}:\n)
- trees = reduce_trees.call(conflict.requirement_trees)
-
- o << trees.map do |tree|
- t = ''.dup
- depth = 2
- tree.each do |req|
- t << ' ' * depth << printable_requirement.call(req)
- unless tree.last == req
- if spec = conflict.activated_by_name[name_for(req)]
- t << %( was resolved to #{version_for_spec.call(spec)}, which)
- end
- t << %( depends on)
- end
- t << %(\n)
- depth += 1
- end
- t
- end.join("\n")
-
- additional_message_for_conflict.call(o, name, conflict)
-
- o
- end
- end
-
- conflicts.sort.reduce(''.dup) do |o, (name, conflict)|
- o << full_message_for_conflict.call(name, conflict)
- end.strip
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/gem_metadata.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/gem_metadata.rb
deleted file mode 100644
index 8ed3a920a2..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/gem_metadata.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- # The version of Gem::Molinillo.
- VERSION = '0.8.0'.freeze
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/modules/specification_provider.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/modules/specification_provider.rb
deleted file mode 100644
index 85860902fc..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/modules/specification_provider.rb
+++ /dev/null
@@ -1,112 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- # Provides information about specifications and dependencies to the resolver,
- # allowing the {Resolver} class to remain generic while still providing power
- # and flexibility.
- #
- # This module contains the methods that users of Gem::Molinillo must to implement,
- # using knowledge of their own model classes.
- module SpecificationProvider
- # Search for the specifications that match the given dependency.
- # The specifications in the returned array will be considered in reverse
- # order, so the latest version ought to be last.
- # @note This method should be 'pure', i.e. the return value should depend
- # only on the `dependency` parameter.
- #
- # @param [Object] dependency
- # @return [Array<Object>] the specifications that satisfy the given
- # `dependency`.
- def search_for(dependency)
- []
- end
-
- # Returns the dependencies of `specification`.
- # @note This method should be 'pure', i.e. the return value should depend
- # only on the `specification` parameter.
- #
- # @param [Object] specification
- # @return [Array<Object>] the dependencies that are required by the given
- # `specification`.
- def dependencies_for(specification)
- []
- end
-
- # Determines whether the given `requirement` is satisfied by the given
- # `spec`, in the context of the current `activated` dependency graph.
- #
- # @param [Object] requirement
- # @param [DependencyGraph] activated the current dependency graph in the
- # resolution process.
- # @param [Object] spec
- # @return [Boolean] whether `requirement` is satisfied by `spec` in the
- # context of the current `activated` dependency graph.
- def requirement_satisfied_by?(requirement, activated, spec)
- true
- end
-
- # Determines whether two arrays of dependencies are equal, and thus can be
- # grouped.
- #
- # @param [Array<Object>] dependencies
- # @param [Array<Object>] other_dependencies
- # @return [Boolean] whether `dependencies` and `other_dependencies` should
- # be considered equal.
- def dependencies_equal?(dependencies, other_dependencies)
- dependencies == other_dependencies
- end
-
- # Returns the name for the given `dependency`.
- # @note This method should be 'pure', i.e. the return value should depend
- # only on the `dependency` parameter.
- #
- # @param [Object] dependency
- # @return [String] the name for the given `dependency`.
- def name_for(dependency)
- dependency.to_s
- end
-
- # @return [String] the name of the source of explicit dependencies, i.e.
- # those passed to {Resolver#resolve} directly.
- def name_for_explicit_dependency_source
- 'user-specified dependency'
- end
-
- # @return [String] the name of the source of 'locked' dependencies, i.e.
- # those passed to {Resolver#resolve} directly as the `base`
- def name_for_locking_dependency_source
- 'Lockfile'
- end
-
- # Sort dependencies so that the ones that are easiest to resolve are first.
- # Easiest to resolve is (usually) defined by:
- # 1) Is this dependency already activated?
- # 2) How relaxed are the requirements?
- # 3) Are there any conflicts for this dependency?
- # 4) How many possibilities are there to satisfy this dependency?
- #
- # @param [Array<Object>] dependencies
- # @param [DependencyGraph] activated the current dependency graph in the
- # resolution process.
- # @param [{String => Array<Conflict>}] conflicts
- # @return [Array<Object>] a sorted copy of `dependencies`.
- def sort_dependencies(dependencies, activated, conflicts)
- dependencies.sort_by do |dependency|
- name = name_for(dependency)
- [
- activated.vertex_named(name).payload ? 0 : 1,
- conflicts[name] ? 0 : 1,
- ]
- end
- end
-
- # Returns whether this dependency, which has no possible matching
- # specifications, can safely be ignored.
- #
- # @param [Object] dependency
- # @return [Boolean] whether this dependency can safely be skipped.
- def allow_missing?(dependency)
- false
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/modules/ui.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/modules/ui.rb
deleted file mode 100644
index 464722902e..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/modules/ui.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- # Conveys information about the resolution process to a user.
- module UI
- # The {IO} object that should be used to print output. `STDOUT`, by default.
- #
- # @return [IO]
- def output
- STDOUT
- end
-
- # Called roughly every {#progress_rate}, this method should convey progress
- # to the user.
- #
- # @return [void]
- def indicate_progress
- output.print '.' unless debug?
- end
-
- # How often progress should be conveyed to the user via
- # {#indicate_progress}, in seconds. A third of a second, by default.
- #
- # @return [Float]
- def progress_rate
- 0.33
- end
-
- # Called before resolution begins.
- #
- # @return [void]
- def before_resolution
- output.print 'Resolving dependencies...'
- end
-
- # Called after resolution ends (either successfully or with an error).
- # By default, prints a newline.
- #
- # @return [void]
- def after_resolution
- output.puts
- end
-
- # Conveys debug information to the user.
- #
- # @param [Integer] depth the current depth of the resolution process.
- # @return [void]
- def debug(depth = 0)
- if debug?
- debug_info = yield
- debug_info = debug_info.inspect unless debug_info.is_a?(String)
- debug_info = debug_info.split("\n").map { |s| ":#{depth.to_s.rjust 4}: #{s}" }
- output.puts debug_info
- end
- end
-
- # Whether or not debug messages should be printed.
- # By default, whether or not the `MOLINILLO_DEBUG` environment variable is
- # set.
- #
- # @return [Boolean]
- def debug?
- return @debug_mode if defined?(@debug_mode)
- @debug_mode = ENV['MOLINILLO_DEBUG']
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/resolution.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/resolution.rb
deleted file mode 100644
index 84ec6cb095..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/resolution.rb
+++ /dev/null
@@ -1,839 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- class Resolver
- # A specific resolution from a given {Resolver}
- class Resolution
- # A conflict that the resolution process encountered
- # @attr [Object] requirement the requirement that immediately led to the conflict
- # @attr [{String,Nil=>[Object]}] requirements the requirements that caused the conflict
- # @attr [Object, nil] existing the existing spec that was in conflict with
- # the {#possibility}
- # @attr [Object] possibility_set the set of specs that was unable to be
- # activated due to a conflict.
- # @attr [Object] locked_requirement the relevant locking requirement.
- # @attr [Array<Array<Object>>] requirement_trees the different requirement
- # trees that led to every requirement for the conflicting name.
- # @attr [{String=>Object}] activated_by_name the already-activated specs.
- # @attr [Object] underlying_error an error that has occurred during resolution, and
- # will be raised at the end of it if no resolution is found.
- Conflict = Struct.new(
- :requirement,
- :requirements,
- :existing,
- :possibility_set,
- :locked_requirement,
- :requirement_trees,
- :activated_by_name,
- :underlying_error
- )
-
- class Conflict
- # @return [Object] a spec that was unable to be activated due to a conflict
- def possibility
- possibility_set && possibility_set.latest_version
- end
- end
-
- # A collection of possibility states that share the same dependencies
- # @attr [Array] dependencies the dependencies for this set of possibilities
- # @attr [Array] possibilities the possibilities
- PossibilitySet = Struct.new(:dependencies, :possibilities)
-
- class PossibilitySet
- # String representation of the possibility set, for debugging
- def to_s
- "[#{possibilities.join(', ')}]"
- end
-
- # @return [Object] most up-to-date dependency in the possibility set
- def latest_version
- possibilities.last
- end
- end
-
- # Details of the state to unwind to when a conflict occurs, and the cause of the unwind
- # @attr [Integer] state_index the index of the state to unwind to
- # @attr [Object] state_requirement the requirement of the state we're unwinding to
- # @attr [Array] requirement_tree for the requirement we're relaxing
- # @attr [Array] conflicting_requirements the requirements that combined to cause the conflict
- # @attr [Array] requirement_trees for the conflict
- # @attr [Array] requirements_unwound_to_instead array of unwind requirements that were chosen over this unwind
- UnwindDetails = Struct.new(
- :state_index,
- :state_requirement,
- :requirement_tree,
- :conflicting_requirements,
- :requirement_trees,
- :requirements_unwound_to_instead
- )
-
- class UnwindDetails
- include Comparable
-
- # We compare UnwindDetails when choosing which state to unwind to. If
- # two options have the same state_index we prefer the one most
- # removed from a requirement that caused the conflict. Both options
- # would unwind to the same state, but a `grandparent` option will
- # filter out fewer of its possibilities after doing so - where a state
- # is both a `parent` and a `grandparent` to requirements that have
- # caused a conflict this is the correct behaviour.
- # @param [UnwindDetail] other UnwindDetail to be compared
- # @return [Integer] integer specifying ordering
- def <=>(other)
- if state_index > other.state_index
- 1
- elsif state_index == other.state_index
- reversed_requirement_tree_index <=> other.reversed_requirement_tree_index
- else
- -1
- end
- end
-
- # @return [Integer] index of state requirement in reversed requirement tree
- # (the conflicting requirement itself will be at position 0)
- def reversed_requirement_tree_index
- @reversed_requirement_tree_index ||=
- if state_requirement
- requirement_tree.reverse.index(state_requirement)
- else
- 999_999
- end
- end
-
- # @return [Boolean] where the requirement of the state we're unwinding
- # to directly caused the conflict. Note: in this case, it is
- # impossible for the state we're unwinding to be a parent of
- # any of the other conflicting requirements (or we would have
- # circularity)
- def unwinding_to_primary_requirement?
- requirement_tree.last == state_requirement
- end
-
- # @return [Array] array of sub-dependencies to avoid when choosing a
- # new possibility for the state we've unwound to. Only relevant for
- # non-primary unwinds
- def sub_dependencies_to_avoid
- @requirements_to_avoid ||=
- requirement_trees.map do |tree|
- index = tree.index(state_requirement)
- tree[index + 1] if index
- end.compact
- end
-
- # @return [Array] array of all the requirements that led to the need for
- # this unwind
- def all_requirements
- @all_requirements ||= requirement_trees.flatten(1)
- end
- end
-
- # @return [SpecificationProvider] the provider that knows about
- # dependencies, requirements, specifications, versions, etc.
- attr_reader :specification_provider
-
- # @return [UI] the UI that knows how to communicate feedback about the
- # resolution process back to the user
- attr_reader :resolver_ui
-
- # @return [DependencyGraph] the base dependency graph to which
- # dependencies should be 'locked'
- attr_reader :base
-
- # @return [Array] the dependencies that were explicitly required
- attr_reader :original_requested
-
- # Initializes a new resolution.
- # @param [SpecificationProvider] specification_provider
- # see {#specification_provider}
- # @param [UI] resolver_ui see {#resolver_ui}
- # @param [Array] requested see {#original_requested}
- # @param [DependencyGraph] base see {#base}
- def initialize(specification_provider, resolver_ui, requested, base)
- @specification_provider = specification_provider
- @resolver_ui = resolver_ui
- @original_requested = requested
- @base = base
- @states = []
- @iteration_counter = 0
- @parents_of = Hash.new { |h, k| h[k] = [] }
- end
-
- # Resolves the {#original_requested} dependencies into a full dependency
- # graph
- # @raise [ResolverError] if successful resolution is impossible
- # @return [DependencyGraph] the dependency graph of successfully resolved
- # dependencies
- def resolve
- start_resolution
-
- while state
- break if !state.requirement && state.requirements.empty?
- indicate_progress
- if state.respond_to?(:pop_possibility_state) # DependencyState
- debug(depth) { "Creating possibility state for #{requirement} (#{possibilities.count} remaining)" }
- state.pop_possibility_state.tap do |s|
- if s
- states.push(s)
- activated.tag(s)
- end
- end
- end
- process_topmost_state
- end
-
- resolve_activated_specs
- ensure
- end_resolution
- end
-
- # @return [Integer] the number of resolver iterations in between calls to
- # {#resolver_ui}'s {UI#indicate_progress} method
- attr_accessor :iteration_rate
- private :iteration_rate
-
- # @return [Time] the time at which resolution began
- attr_accessor :started_at
- private :started_at
-
- # @return [Array<ResolutionState>] the stack of states for the resolution
- attr_accessor :states
- private :states
-
- private
-
- # Sets up the resolution process
- # @return [void]
- def start_resolution
- @started_at = Time.now
-
- push_initial_state
-
- debug { "Starting resolution (#{@started_at})\nUser-requested dependencies: #{original_requested}" }
- resolver_ui.before_resolution
- end
-
- def resolve_activated_specs
- activated.vertices.each do |_, vertex|
- next unless vertex.payload
-
- latest_version = vertex.payload.possibilities.reverse_each.find do |possibility|
- vertex.requirements.all? { |req| requirement_satisfied_by?(req, activated, possibility) }
- end
-
- activated.set_payload(vertex.name, latest_version)
- end
- activated.freeze
- end
-
- # Ends the resolution process
- # @return [void]
- def end_resolution
- resolver_ui.after_resolution
- debug do
- "Finished resolution (#{@iteration_counter} steps) " \
- "(Took #{(ended_at = Time.now) - @started_at} seconds) (#{ended_at})"
- end
- debug { 'Unactivated: ' + Hash[activated.vertices.reject { |_n, v| v.payload }].keys.join(', ') } if state
- debug { 'Activated: ' + Hash[activated.vertices.select { |_n, v| v.payload }].keys.join(', ') } if state
- end
-
- require_relative 'state'
- require_relative 'modules/specification_provider'
-
- require_relative 'delegates/resolution_state'
- require_relative 'delegates/specification_provider'
-
- include Gem::Molinillo::Delegates::ResolutionState
- include Gem::Molinillo::Delegates::SpecificationProvider
-
- # Processes the topmost available {RequirementState} on the stack
- # @return [void]
- def process_topmost_state
- if possibility
- attempt_to_activate
- else
- create_conflict
- unwind_for_conflict
- end
- rescue CircularDependencyError => underlying_error
- create_conflict(underlying_error)
- unwind_for_conflict
- end
-
- # @return [Object] the current possibility that the resolution is trying
- # to activate
- def possibility
- possibilities.last
- end
-
- # @return [RequirementState] the current state the resolution is
- # operating upon
- def state
- states.last
- end
-
- # Creates and pushes the initial state for the resolution, based upon the
- # {#requested} dependencies
- # @return [void]
- def push_initial_state
- graph = DependencyGraph.new.tap do |dg|
- original_requested.each do |requested|
- vertex = dg.add_vertex(name_for(requested), nil, true)
- vertex.explicit_requirements << requested
- end
- dg.tag(:initial_state)
- end
-
- push_state_for_requirements(original_requested, true, graph)
- end
-
- # Unwinds the states stack because a conflict has been encountered
- # @return [void]
- def unwind_for_conflict
- details_for_unwind = build_details_for_unwind
- unwind_options = unused_unwind_options
- debug(depth) { "Unwinding for conflict: #{requirement} to #{details_for_unwind.state_index / 2}" }
- conflicts.tap do |c|
- sliced_states = states.slice!((details_for_unwind.state_index + 1)..-1)
- raise_error_unless_state(c)
- activated.rewind_to(sliced_states.first || :initial_state) if sliced_states
- state.conflicts = c
- state.unused_unwind_options = unwind_options
- filter_possibilities_after_unwind(details_for_unwind)
- index = states.size - 1
- @parents_of.each { |_, a| a.reject! { |i| i >= index } }
- state.unused_unwind_options.reject! { |uw| uw.state_index >= index }
- end
- end
-
- # Raises a VersionConflict error, or any underlying error, if there is no
- # current state
- # @return [void]
- def raise_error_unless_state(conflicts)
- return if state
-
- error = conflicts.values.map(&:underlying_error).compact.first
- raise error || VersionConflict.new(conflicts, specification_provider)
- end
-
- # @return [UnwindDetails] Details of the nearest index to which we could unwind
- def build_details_for_unwind
- # Get the possible unwinds for the current conflict
- current_conflict = conflicts[name]
- binding_requirements = binding_requirements_for_conflict(current_conflict)
- unwind_details = unwind_options_for_requirements(binding_requirements)
-
- last_detail_for_current_unwind = unwind_details.sort.last
- current_detail = last_detail_for_current_unwind
-
- # Look for past conflicts that could be unwound to affect the
- # requirement tree for the current conflict
- all_reqs = last_detail_for_current_unwind.all_requirements
- all_reqs_size = all_reqs.size
- relevant_unused_unwinds = unused_unwind_options.select do |alternative|
- diff_reqs = all_reqs - alternative.requirements_unwound_to_instead
- next if diff_reqs.size == all_reqs_size
- # Find the highest index unwind whilst looping through
- current_detail = alternative if alternative > current_detail
- alternative
- end
-
- # Add the current unwind options to the `unused_unwind_options` array.
- # The "used" option will be filtered out during `unwind_for_conflict`.
- state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 }
-
- # Update the requirements_unwound_to_instead on any relevant unused unwinds
- relevant_unused_unwinds.each do |d|
- (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
- end
- unwind_details.each do |d|
- (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
- end
-
- current_detail
- end
-
- # @param [Array<Object>] binding_requirements array of requirements that combine to create a conflict
- # @return [Array<UnwindDetails>] array of UnwindDetails that have a chance
- # of resolving the passed requirements
- def unwind_options_for_requirements(binding_requirements)
- unwind_details = []
-
- trees = []
- binding_requirements.reverse_each do |r|
- partial_tree = [r]
- trees << partial_tree
- unwind_details << UnwindDetails.new(-1, nil, partial_tree, binding_requirements, trees, [])
-
- # If this requirement has alternative possibilities, check if any would
- # satisfy the other requirements that created this conflict
- requirement_state = find_state_for(r)
- if conflict_fixing_possibilities?(requirement_state, binding_requirements)
- unwind_details << UnwindDetails.new(
- states.index(requirement_state),
- r,
- partial_tree,
- binding_requirements,
- trees,
- []
- )
- end
-
- # Next, look at the parent of this requirement, and check if the requirement
- # could have been avoided if an alternative PossibilitySet had been chosen
- parent_r = parent_of(r)
- next if parent_r.nil?
- partial_tree.unshift(parent_r)
- requirement_state = find_state_for(parent_r)
- if requirement_state.possibilities.any? { |set| !set.dependencies.include?(r) }
- unwind_details << UnwindDetails.new(
- states.index(requirement_state),
- parent_r,
- partial_tree,
- binding_requirements,
- trees,
- []
- )
- end
-
- # Finally, look at the grandparent and up of this requirement, looking
- # for any possibilities that wouldn't create their parent requirement
- grandparent_r = parent_of(parent_r)
- until grandparent_r.nil?
- partial_tree.unshift(grandparent_r)
- requirement_state = find_state_for(grandparent_r)
- if requirement_state.possibilities.any? { |set| !set.dependencies.include?(parent_r) }
- unwind_details << UnwindDetails.new(
- states.index(requirement_state),
- grandparent_r,
- partial_tree,
- binding_requirements,
- trees,
- []
- )
- end
- parent_r = grandparent_r
- grandparent_r = parent_of(parent_r)
- end
- end
-
- unwind_details
- end
-
- # @param [DependencyState] state
- # @param [Array] binding_requirements array of requirements
- # @return [Boolean] whether or not the given state has any possibilities
- # that could satisfy the given requirements
- def conflict_fixing_possibilities?(state, binding_requirements)
- return false unless state
-
- state.possibilities.any? do |possibility_set|
- possibility_set.possibilities.any? do |poss|
- possibility_satisfies_requirements?(poss, binding_requirements)
- end
- end
- end
-
- # Filter's a state's possibilities to remove any that would not fix the
- # conflict we've just rewound from
- # @param [UnwindDetails] unwind_details details of the conflict just
- # unwound from
- # @return [void]
- def filter_possibilities_after_unwind(unwind_details)
- return unless state && !state.possibilities.empty?
-
- if unwind_details.unwinding_to_primary_requirement?
- filter_possibilities_for_primary_unwind(unwind_details)
- else
- filter_possibilities_for_parent_unwind(unwind_details)
- end
- end
-
- # Filter's a state's possibilities to remove any that would not satisfy
- # the requirements in the conflict we've just rewound from
- # @param [UnwindDetails] unwind_details details of the conflict just unwound from
- # @return [void]
- def filter_possibilities_for_primary_unwind(unwind_details)
- unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index }
- unwinds_to_state << unwind_details
- unwind_requirement_sets = unwinds_to_state.map(&:conflicting_requirements)
-
- state.possibilities.reject! do |possibility_set|
- possibility_set.possibilities.none? do |poss|
- unwind_requirement_sets.any? do |requirements|
- possibility_satisfies_requirements?(poss, requirements)
- end
- end
- end
- end
-
- # @param [Object] possibility a single possibility
- # @param [Array] requirements an array of requirements
- # @return [Boolean] whether the possibility satisfies all of the
- # given requirements
- def possibility_satisfies_requirements?(possibility, requirements)
- name = name_for(possibility)
-
- activated.tag(:swap)
- activated.set_payload(name, possibility) if activated.vertex_named(name)
- satisfied = requirements.all? { |r| requirement_satisfied_by?(r, activated, possibility) }
- activated.rewind_to(:swap)
-
- satisfied
- end
-
- # Filter's a state's possibilities to remove any that would (eventually)
- # create a requirement in the conflict we've just rewound from
- # @param [UnwindDetails] unwind_details details of the conflict just unwound from
- # @return [void]
- def filter_possibilities_for_parent_unwind(unwind_details)
- unwinds_to_state = unused_unwind_options.select { |uw| uw.state_index == unwind_details.state_index }
- unwinds_to_state << unwind_details
-
- primary_unwinds = unwinds_to_state.select(&:unwinding_to_primary_requirement?).uniq
- parent_unwinds = unwinds_to_state.uniq - primary_unwinds
-
- allowed_possibility_sets = primary_unwinds.flat_map do |unwind|
- states[unwind.state_index].possibilities.select do |possibility_set|
- possibility_set.possibilities.any? do |poss|
- possibility_satisfies_requirements?(poss, unwind.conflicting_requirements)
- end
- end
- end
-
- requirements_to_avoid = parent_unwinds.flat_map(&:sub_dependencies_to_avoid)
-
- state.possibilities.reject! do |possibility_set|
- !allowed_possibility_sets.include?(possibility_set) &&
- (requirements_to_avoid - possibility_set.dependencies).empty?
- end
- end
-
- # @param [Conflict] conflict
- # @return [Array] minimal array of requirements that would cause the passed
- # conflict to occur.
- def binding_requirements_for_conflict(conflict)
- return [conflict.requirement] if conflict.possibility.nil?
-
- possible_binding_requirements = conflict.requirements.values.flatten(1).uniq
-
- # When there's a `CircularDependency` error the conflicting requirement
- # (the one causing the circular) won't be `conflict.requirement`
- # (which won't be for the right state, because we won't have created it,
- # because it's circular).
- # We need to make sure we have that requirement in the conflict's list,
- # otherwise we won't be able to unwind properly, so we just return all
- # the requirements for the conflict.
- return possible_binding_requirements if conflict.underlying_error
-
- possibilities = search_for(conflict.requirement)
-
- # If all the requirements together don't filter out all possibilities,
- # then the only two requirements we need to consider are the initial one
- # (where the dependency's version was first chosen) and the last
- if binding_requirement_in_set?(nil, possible_binding_requirements, possibilities)
- return [conflict.requirement, requirement_for_existing_name(name_for(conflict.requirement))].compact
- end
-
- # Loop through the possible binding requirements, removing each one
- # that doesn't bind. Use a `reverse_each` as we want the earliest set of
- # binding requirements, and don't use `reject!` as we wish to refine the
- # array *on each iteration*.
- binding_requirements = possible_binding_requirements.dup
- possible_binding_requirements.reverse_each do |req|
- next if req == conflict.requirement
- unless binding_requirement_in_set?(req, binding_requirements, possibilities)
- binding_requirements -= [req]
- end
- end
-
- binding_requirements
- end
-
- # @param [Object] requirement we wish to check
- # @param [Array] possible_binding_requirements array of requirements
- # @param [Array] possibilities array of possibilities the requirements will be used to filter
- # @return [Boolean] whether or not the given requirement is required to filter
- # out all elements of the array of possibilities.
- def binding_requirement_in_set?(requirement, possible_binding_requirements, possibilities)
- possibilities.any? do |poss|
- possibility_satisfies_requirements?(poss, possible_binding_requirements - [requirement])
- end
- end
-
- # @param [Object] requirement
- # @return [Object] the requirement that led to `requirement` being added
- # to the list of requirements.
- def parent_of(requirement)
- return unless requirement
- return unless index = @parents_of[requirement].last
- return unless parent_state = @states[index]
- parent_state.requirement
- end
-
- # @param [String] name
- # @return [Object] the requirement that led to a version of a possibility
- # with the given name being activated.
- def requirement_for_existing_name(name)
- return nil unless vertex = activated.vertex_named(name)
- return nil unless vertex.payload
- states.find { |s| s.name == name }.requirement
- end
-
- # @param [Object] requirement
- # @return [ResolutionState] the state whose `requirement` is the given
- # `requirement`.
- def find_state_for(requirement)
- return nil unless requirement
- states.find { |i| requirement == i.requirement }
- end
-
- # @param [Object] underlying_error
- # @return [Conflict] a {Conflict} that reflects the failure to activate
- # the {#possibility} in conjunction with the current {#state}
- def create_conflict(underlying_error = nil)
- vertex = activated.vertex_named(name)
- locked_requirement = locked_requirement_named(name)
-
- requirements = {}
- unless vertex.explicit_requirements.empty?
- requirements[name_for_explicit_dependency_source] = vertex.explicit_requirements
- end
- requirements[name_for_locking_dependency_source] = [locked_requirement] if locked_requirement
- vertex.incoming_edges.each do |edge|
- (requirements[edge.origin.payload.latest_version] ||= []).unshift(edge.requirement)
- end
-
- activated_by_name = {}
- activated.each { |v| activated_by_name[v.name] = v.payload.latest_version if v.payload }
- conflicts[name] = Conflict.new(
- requirement,
- requirements,
- vertex.payload && vertex.payload.latest_version,
- possibility,
- locked_requirement,
- requirement_trees,
- activated_by_name,
- underlying_error
- )
- end
-
- # @return [Array<Array<Object>>] The different requirement
- # trees that led to every requirement for the current spec.
- def requirement_trees
- vertex = activated.vertex_named(name)
- vertex.requirements.map { |r| requirement_tree_for(r) }
- end
-
- # @param [Object] requirement
- # @return [Array<Object>] the list of requirements that led to
- # `requirement` being required.
- def requirement_tree_for(requirement)
- tree = []
- while requirement
- tree.unshift(requirement)
- requirement = parent_of(requirement)
- end
- tree
- end
-
- # Indicates progress roughly once every second
- # @return [void]
- def indicate_progress
- @iteration_counter += 1
- @progress_rate ||= resolver_ui.progress_rate
- if iteration_rate.nil?
- if Time.now - started_at >= @progress_rate
- self.iteration_rate = @iteration_counter
- end
- end
-
- if iteration_rate && (@iteration_counter % iteration_rate) == 0
- resolver_ui.indicate_progress
- end
- end
-
- # Calls the {#resolver_ui}'s {UI#debug} method
- # @param [Integer] depth the depth of the {#states} stack
- # @param [Proc] block a block that yields a {#to_s}
- # @return [void]
- def debug(depth = 0, &block)
- resolver_ui.debug(depth, &block)
- end
-
- # Attempts to activate the current {#possibility}
- # @return [void]
- def attempt_to_activate
- debug(depth) { 'Attempting to activate ' + possibility.to_s }
- existing_vertex = activated.vertex_named(name)
- if existing_vertex.payload
- debug(depth) { "Found existing spec (#{existing_vertex.payload})" }
- attempt_to_filter_existing_spec(existing_vertex)
- else
- latest = possibility.latest_version
- possibility.possibilities.select! do |possibility|
- requirement_satisfied_by?(requirement, activated, possibility)
- end
- if possibility.latest_version.nil?
- # ensure there's a possibility for better error messages
- possibility.possibilities << latest if latest
- create_conflict
- unwind_for_conflict
- else
- activate_new_spec
- end
- end
- end
-
- # Attempts to update the existing vertex's `PossibilitySet` with a filtered version
- # @return [void]
- def attempt_to_filter_existing_spec(vertex)
- filtered_set = filtered_possibility_set(vertex)
- if !filtered_set.possibilities.empty?
- activated.set_payload(name, filtered_set)
- new_requirements = requirements.dup
- push_state_for_requirements(new_requirements, false)
- else
- create_conflict
- debug(depth) { "Unsatisfied by existing spec (#{vertex.payload})" }
- unwind_for_conflict
- end
- end
-
- # Generates a filtered version of the existing vertex's `PossibilitySet` using the
- # current state's `requirement`
- # @param [Object] vertex existing vertex
- # @return [PossibilitySet] filtered possibility set
- def filtered_possibility_set(vertex)
- PossibilitySet.new(vertex.payload.dependencies, vertex.payload.possibilities & possibility.possibilities)
- end
-
- # @param [String] requirement_name the spec name to search for
- # @return [Object] the locked spec named `requirement_name`, if one
- # is found on {#base}
- def locked_requirement_named(requirement_name)
- vertex = base.vertex_named(requirement_name)
- vertex && vertex.payload
- end
-
- # Add the current {#possibility} to the dependency graph of the current
- # {#state}
- # @return [void]
- def activate_new_spec
- conflicts.delete(name)
- debug(depth) { "Activated #{name} at #{possibility}" }
- activated.set_payload(name, possibility)
- require_nested_dependencies_for(possibility)
- end
-
- # Requires the dependencies that the recently activated spec has
- # @param [Object] possibility_set the PossibilitySet that has just been
- # activated
- # @return [void]
- def require_nested_dependencies_for(possibility_set)
- nested_dependencies = dependencies_for(possibility_set.latest_version)
- debug(depth) { "Requiring nested dependencies (#{nested_dependencies.join(', ')})" }
- nested_dependencies.each do |d|
- activated.add_child_vertex(name_for(d), nil, [name_for(possibility_set.latest_version)], d)
- parent_index = states.size - 1
- parents = @parents_of[d]
- parents << parent_index if parents.empty?
- end
-
- push_state_for_requirements(requirements + nested_dependencies, !nested_dependencies.empty?)
- end
-
- # Pushes a new {DependencyState} that encapsulates both existing and new
- # requirements
- # @param [Array] new_requirements
- # @param [Boolean] requires_sort
- # @param [Object] new_activated
- # @return [void]
- def push_state_for_requirements(new_requirements, requires_sort = true, new_activated = activated)
- new_requirements = sort_dependencies(new_requirements.uniq, new_activated, conflicts) if requires_sort
- new_requirement = nil
- loop do
- new_requirement = new_requirements.shift
- break if new_requirement.nil? || states.none? { |s| s.requirement == new_requirement }
- end
- new_name = new_requirement ? name_for(new_requirement) : ''.freeze
- possibilities = possibilities_for_requirement(new_requirement)
- handle_missing_or_push_dependency_state DependencyState.new(
- new_name, new_requirements, new_activated,
- new_requirement, possibilities, depth, conflicts.dup, unused_unwind_options.dup
- )
- end
-
- # Checks a proposed requirement with any existing locked requirement
- # before generating an array of possibilities for it.
- # @param [Object] requirement the proposed requirement
- # @param [Object] activated
- # @return [Array] possibilities
- def possibilities_for_requirement(requirement, activated = self.activated)
- return [] unless requirement
- if locked_requirement_named(name_for(requirement))
- return locked_requirement_possibility_set(requirement, activated)
- end
-
- group_possibilities(search_for(requirement))
- end
-
- # @param [Object] requirement the proposed requirement
- # @param [Object] activated
- # @return [Array] possibility set containing only the locked requirement, if any
- def locked_requirement_possibility_set(requirement, activated = self.activated)
- all_possibilities = search_for(requirement)
- locked_requirement = locked_requirement_named(name_for(requirement))
-
- # Longwinded way to build a possibilities array with either the locked
- # requirement or nothing in it. Required, since the API for
- # locked_requirement isn't guaranteed.
- locked_possibilities = all_possibilities.select do |possibility|
- requirement_satisfied_by?(locked_requirement, activated, possibility)
- end
-
- group_possibilities(locked_possibilities)
- end
-
- # Build an array of PossibilitySets, with each element representing a group of
- # dependency versions that all have the same sub-dependency version constraints
- # and are contiguous.
- # @param [Array] possibilities an array of possibilities
- # @return [Array<PossibilitySet>] an array of possibility sets
- def group_possibilities(possibilities)
- possibility_sets = []
- current_possibility_set = nil
-
- possibilities.reverse_each do |possibility|
- dependencies = dependencies_for(possibility)
- if current_possibility_set && dependencies_equal?(current_possibility_set.dependencies, dependencies)
- current_possibility_set.possibilities.unshift(possibility)
- else
- possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility]))
- current_possibility_set = possibility_sets.first
- end
- end
-
- possibility_sets
- end
-
- # Pushes a new {DependencyState}.
- # If the {#specification_provider} says to
- # {SpecificationProvider#allow_missing?} that particular requirement, and
- # there are no possibilities for that requirement, then `state` is not
- # pushed, and the vertex in {#activated} is removed, and we continue
- # resolving the remaining requirements.
- # @param [DependencyState] state
- # @return [void]
- def handle_missing_or_push_dependency_state(state)
- if state.requirement && state.possibilities.empty? && allow_missing?(state.requirement)
- state.activated.detach_vertex_named(state.name)
- push_state_for_requirements(state.requirements.dup, false, state.activated)
- else
- states.push(state).tap { activated.tag(state) }
- end
- end
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/resolver.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/resolver.rb
deleted file mode 100644
index 86229c3fa1..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/resolver.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'dependency_graph'
-
-module Gem::Molinillo
- # This class encapsulates a dependency resolver.
- # The resolver is responsible for determining which set of dependencies to
- # activate, with feedback from the {#specification_provider}
- #
- #
- class Resolver
- require_relative 'resolution'
-
- # @return [SpecificationProvider] the specification provider used
- # in the resolution process
- attr_reader :specification_provider
-
- # @return [UI] the UI module used to communicate back to the user
- # during the resolution process
- attr_reader :resolver_ui
-
- # Initializes a new resolver.
- # @param [SpecificationProvider] specification_provider
- # see {#specification_provider}
- # @param [UI] resolver_ui
- # see {#resolver_ui}
- def initialize(specification_provider, resolver_ui)
- @specification_provider = specification_provider
- @resolver_ui = resolver_ui
- end
-
- # Resolves the requested dependencies into a {DependencyGraph},
- # locking to the base dependency graph (if specified)
- # @param [Array] requested an array of 'requested' dependencies that the
- # {#specification_provider} can understand
- # @param [DependencyGraph,nil] base the base dependency graph to which
- # dependencies should be 'locked'
- def resolve(requested, base = DependencyGraph.new)
- Resolution.new(specification_provider,
- resolver_ui,
- requested,
- base).
- resolve
- end
- end
-end
diff --git a/lib/rubygems/vendor/molinillo/lib/molinillo/state.rb b/lib/rubygems/vendor/molinillo/lib/molinillo/state.rb
deleted file mode 100644
index c48ec6af9c..0000000000
--- a/lib/rubygems/vendor/molinillo/lib/molinillo/state.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Molinillo
- # A state that a {Resolution} can be in
- # @attr [String] name the name of the current requirement
- # @attr [Array<Object>] requirements currently unsatisfied requirements
- # @attr [DependencyGraph] activated the graph of activated dependencies
- # @attr [Object] requirement the current requirement
- # @attr [Object] possibilities the possibilities to satisfy the current requirement
- # @attr [Integer] depth the depth of the resolution
- # @attr [Hash] conflicts unresolved conflicts, indexed by dependency name
- # @attr [Array<UnwindDetails>] unused_unwind_options unwinds for previous conflicts that weren't explored
- ResolutionState = Struct.new(
- :name,
- :requirements,
- :activated,
- :requirement,
- :possibilities,
- :depth,
- :conflicts,
- :unused_unwind_options
- )
-
- class ResolutionState
- # Returns an empty resolution state
- # @return [ResolutionState] an empty state
- def self.empty
- new(nil, [], DependencyGraph.new, nil, nil, 0, {}, [])
- end
- end
-
- # A state that encapsulates a set of {#requirements} with an {Array} of
- # possibilities
- class DependencyState < ResolutionState
- # Removes a possibility from `self`
- # @return [PossibilityState] a state with a single possibility,
- # the possibility that was removed from `self`
- def pop_possibility_state
- PossibilityState.new(
- name,
- requirements.dup,
- activated,
- requirement,
- [possibilities.pop],
- depth + 1,
- conflicts.dup,
- unused_unwind_options.dup
- ).tap do |state|
- state.activated.tag(state)
- end
- end
- end
-
- # A state that encapsulates a single possibility to fulfill the given
- # {#requirement}
- class PossibilityState < ResolutionState
- end
-end
diff --git a/lib/rubygems/vendor/net-http/.document b/lib/rubygems/vendor/net-http/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/net-http/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/net-http/lib/net/http.rb b/lib/rubygems/vendor/net-http/lib/net/http.rb
deleted file mode 100644
index 7b15c3cf54..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http.rb
+++ /dev/null
@@ -1,2496 +0,0 @@
-# frozen_string_literal: true
-#
-# = net/http.rb
-#
-# Copyright (c) 1999-2007 Yukihiro Matsumoto
-# Copyright (c) 1999-2007 Minero Aoki
-# Copyright (c) 2001 GOTOU Yuuzou
-#
-# Written and maintained by Minero Aoki <aamine@loveruby.net>.
-# HTTPS support added by GOTOU Yuuzou <gotoyuzo@notwork.org>.
-#
-# This file is derived from "http-access.rb".
-#
-# Documented by Minero Aoki; converted to RDoc by William Webber.
-#
-# This program is free software. You can re-distribute and/or
-# modify this program under the same terms of ruby itself ---
-# Ruby Distribution License or GNU General Public License.
-#
-# See Gem::Net::HTTP for an overview and examples.
-#
-
-require_relative '../../../net-protocol/lib/net/protocol'
-require_relative '../../../uri/lib/uri'
-require_relative '../../../resolv/lib/resolv'
-autoload :OpenSSL, 'openssl'
-
-module Gem::Net #:nodoc:
-
- # :stopdoc:
- class HTTPBadResponse < StandardError; end
- class HTTPHeaderSyntaxError < StandardError; end
- # :startdoc:
-
- # \Class \Gem::Net::HTTP provides a rich library that implements the client
- # in a client-server model that uses the \HTTP request-response protocol.
- # For information about \HTTP, see:
- #
- # - {Hypertext Transfer Protocol}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol].
- # - {Technical overview}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Technical_overview].
- #
- # == About the Examples
- #
- # :include: doc/net-http/examples.rdoc
- #
- # == Strategies
- #
- # - If you will make only a few GET requests,
- # consider using {OpenURI}[rdoc-ref:OpenURI].
- # - If you will make only a few requests of all kinds,
- # consider using the various singleton convenience methods in this class.
- # Each of the following methods automatically starts and finishes
- # a {session}[rdoc-ref:Gem::Net::HTTP@Sessions] that sends a single request:
- #
- # # Return string response body.
- # Gem::Net::HTTP.get(hostname, path)
- # Gem::Net::HTTP.get(uri)
- #
- # # Write string response body to $stdout.
- # Gem::Net::HTTP.get_print(hostname, path)
- # Gem::Net::HTTP.get_print(uri)
- #
- # # Return response as Gem::Net::HTTPResponse object.
- # Gem::Net::HTTP.get_response(hostname, path)
- # Gem::Net::HTTP.get_response(uri)
- # data = '{"title": "foo", "body": "bar", "userId": 1}'
- # Gem::Net::HTTP.post(uri, data)
- # params = {title: 'foo', body: 'bar', userId: 1}
- # Gem::Net::HTTP.post_form(uri, params)
- #
- # - If performance is important, consider using sessions, which lower request overhead.
- # This {session}[rdoc-ref:Gem::Net::HTTP@Sessions] has multiple requests for
- # {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods]
- # and {WebDAV methods}[https://en.wikipedia.org/wiki/WebDAV#Implementation]:
- #
- # Gem::Net::HTTP.start(hostname) do |http|
- # # Session started automatically before block execution.
- # http.get(path)
- # http.head(path)
- # body = 'Some text'
- # http.post(path, body) # Can also have a block.
- # http.put(path, body)
- # http.delete(path)
- # http.options(path)
- # http.trace(path)
- # http.patch(path, body) # Can also have a block.
- # http.copy(path)
- # http.lock(path, body)
- # http.mkcol(path, body)
- # http.move(path)
- # http.propfind(path, body)
- # http.proppatch(path, body)
- # http.unlock(path, body)
- # # Session finished automatically at block exit.
- # end
- #
- # The methods cited above are convenience methods that, via their few arguments,
- # allow minimal control over the requests.
- # For greater control, consider using {request objects}[rdoc-ref:Gem::Net::HTTPRequest].
- #
- # == URIs
- #
- # On the internet, a URI
- # ({Universal Resource Identifier}[https://en.wikipedia.org/wiki/Uniform_Resource_Identifier])
- # is a string that identifies a particular resource.
- # It consists of some or all of: scheme, hostname, path, query, and fragment;
- # see {URI syntax}[https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax].
- #
- # A Ruby {Gem::URI::Generic}[rdoc-ref:Gem::URI::Generic] object
- # represents an internet URI.
- # It provides, among others, methods
- # +scheme+, +hostname+, +path+, +query+, and +fragment+.
- #
- # === Schemes
- #
- # An internet \Gem::URI has
- # a {scheme}[https://en.wikipedia.org/wiki/List_of_URI_schemes].
- #
- # The two schemes supported in \Gem::Net::HTTP are <tt>'https'</tt> and <tt>'http'</tt>:
- #
- # uri.scheme # => "https"
- # Gem::URI('http://example.com').scheme # => "http"
- #
- # === Hostnames
- #
- # A hostname identifies a server (host) to which requests may be sent:
- #
- # hostname = uri.hostname # => "jsonplaceholder.typicode.com"
- # Gem::Net::HTTP.start(hostname) do |http|
- # # Some HTTP stuff.
- # end
- #
- # === Paths
- #
- # A host-specific path identifies a resource on the host:
- #
- # _uri = uri.dup
- # _uri.path = '/todos/1'
- # hostname = _uri.hostname
- # path = _uri.path
- # Gem::Net::HTTP.get(hostname, path)
- #
- # === Queries
- #
- # A host-specific query adds name/value pairs to the URI:
- #
- # _uri = uri.dup
- # params = {userId: 1, completed: false}
- # _uri.query = Gem::URI.encode_www_form(params)
- # _uri # => #<Gem::URI::HTTPS https://jsonplaceholder.typicode.com?userId=1&completed=false>
- # Gem::Net::HTTP.get(_uri)
- #
- # === Fragments
- #
- # A {URI fragment}[https://en.wikipedia.org/wiki/URI_fragment] has no effect
- # in \Gem::Net::HTTP;
- # the same data is returned, regardless of whether a fragment is included.
- #
- # == Request Headers
- #
- # Request headers may be used to pass additional information to the host,
- # similar to arguments passed in a method call;
- # each header is a name/value pair.
- #
- # Each of the \Gem::Net::HTTP methods that sends a request to the host
- # has optional argument +headers+,
- # where the headers are expressed as a hash of field-name/value pairs:
- #
- # headers = {Accept: 'application/json', Connection: 'Keep-Alive'}
- # Gem::Net::HTTP.get(uri, headers)
- #
- # See lists of both standard request fields and common request fields at
- # {Request Fields}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields].
- # A host may also accept other custom fields.
- #
- # == \HTTP Sessions
- #
- # A _session_ is a connection between a server (host) and a client that:
- #
- # - Is begun by instance method Gem::Net::HTTP#start.
- # - May contain any number of requests.
- # - Is ended by instance method Gem::Net::HTTP#finish.
- #
- # See example sessions at {Strategies}[rdoc-ref:Gem::Net::HTTP@Strategies].
- #
- # === Session Using \Gem::Net::HTTP.start
- #
- # If you have many requests to make to a single host (and port),
- # consider using singleton method Gem::Net::HTTP.start with a block;
- # the method handles the session automatically by:
- #
- # - Calling #start before block execution.
- # - Executing the block.
- # - Calling #finish after block execution.
- #
- # In the block, you can use these instance methods,
- # each of which that sends a single request:
- #
- # - {HTTP methods}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods]:
- #
- # - #get, #request_get: GET.
- # - #head, #request_head: HEAD.
- # - #post, #request_post: POST.
- # - #delete: DELETE.
- # - #options: OPTIONS.
- # - #trace: TRACE.
- # - #patch: PATCH.
- #
- # - {WebDAV methods}[https://en.wikipedia.org/wiki/WebDAV#Implementation]:
- #
- # - #copy: COPY.
- # - #lock: LOCK.
- # - #mkcol: MKCOL.
- # - #move: MOVE.
- # - #propfind: PROPFIND.
- # - #proppatch: PROPPATCH.
- # - #unlock: UNLOCK.
- #
- # === Session Using \Gem::Net::HTTP.start and \Gem::Net::HTTP.finish
- #
- # You can manage a session manually using methods #start and #finish:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.start
- # http.get('/todos/1')
- # http.get('/todos/2')
- # http.delete('/posts/1')
- # http.finish # Needed to free resources.
- #
- # === Single-Request Session
- #
- # Certain convenience methods automatically handle a session by:
- #
- # - Creating an \HTTP object
- # - Starting a session.
- # - Sending a single request.
- # - Finishing the session.
- # - Destroying the object.
- #
- # Such methods that send GET requests:
- #
- # - ::get: Returns the string response body.
- # - ::get_print: Writes the string response body to $stdout.
- # - ::get_response: Returns a Gem::Net::HTTPResponse object.
- #
- # Such methods that send POST requests:
- #
- # - ::post: Posts data to the host.
- # - ::post_form: Posts form data to the host.
- #
- # == \HTTP Requests and Responses
- #
- # Many of the methods above are convenience methods,
- # each of which sends a request and returns a string
- # without directly using \Gem::Net::HTTPRequest and \Gem::Net::HTTPResponse objects.
- #
- # You can, however, directly create a request object, send the request,
- # and retrieve the response object; see:
- #
- # - Gem::Net::HTTPRequest.
- # - Gem::Net::HTTPResponse.
- #
- # == Following Redirection
- #
- # Each returned response is an instance of a subclass of Gem::Net::HTTPResponse.
- # See the {response class hierarchy}[rdoc-ref:Gem::Net::HTTPResponse@Response+Subclasses].
- #
- # In particular, class Gem::Net::HTTPRedirection is the parent
- # of all redirection classes.
- # This allows you to craft a case statement to handle redirections properly:
- #
- # def fetch(uri, limit = 10)
- # # You should choose a better exception.
- # raise ArgumentError, 'Too many HTTP redirects' if limit == 0
- #
- # res = Gem::Net::HTTP.get_response(Gem::URI(uri))
- # case res
- # when Gem::Net::HTTPSuccess # Any success class.
- # res
- # when Gem::Net::HTTPRedirection # Any redirection class.
- # location = res['Location']
- # warn "Redirected to #{location}"
- # fetch(location, limit - 1)
- # else # Any other class.
- # res.value
- # end
- # end
- #
- # fetch(uri)
- #
- # == Basic Authentication
- #
- # Basic authentication is performed according to
- # {RFC2617}[http://www.ietf.org/rfc/rfc2617.txt]:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.basic_auth('user', 'pass')
- # res = Gem::Net::HTTP.start(hostname) do |http|
- # http.request(req)
- # end
- #
- # == Streaming Response Bodies
- #
- # By default \Gem::Net::HTTP reads an entire response into memory. If you are
- # handling large files or wish to implement a progress bar you can instead
- # stream the body directly to an IO.
- #
- # Gem::Net::HTTP.start(hostname) do |http|
- # req = Gem::Net::HTTP::Get.new(uri)
- # http.request(req) do |res|
- # open('t.tmp', 'w') do |f|
- # res.read_body do |chunk|
- # f.write chunk
- # end
- # end
- # end
- # end
- #
- # == HTTPS
- #
- # HTTPS is enabled for an \HTTP connection by Gem::Net::HTTP#use_ssl=:
- #
- # Gem::Net::HTTP.start(hostname, :use_ssl => true) do |http|
- # req = Gem::Net::HTTP::Get.new(uri)
- # res = http.request(req)
- # end
- #
- # Or if you simply want to make a GET request, you may pass in a URI
- # object that has an \HTTPS URL. \Gem::Net::HTTP automatically turns on TLS
- # verification if the URI object has a 'https' :URI scheme:
- #
- # uri # => #<Gem::URI::HTTPS https://jsonplaceholder.typicode.com/>
- # Gem::Net::HTTP.get(uri)
- #
- # == Proxy Server
- #
- # An \HTTP object can have
- # a {proxy server}[https://en.wikipedia.org/wiki/Proxy_server].
- #
- # You can create an \HTTP object with a proxy server
- # using method Gem::Net::HTTP.new or method Gem::Net::HTTP.start.
- #
- # The proxy may be defined either by argument +p_addr+
- # or by environment variable <tt>'http_proxy'</tt>.
- #
- # === Proxy Using Argument +p_addr+ as a \String
- #
- # When argument +p_addr+ is a string hostname,
- # the returned +http+ has the given host as its proxy:
- #
- # http = Gem::Net::HTTP.new(hostname, nil, 'proxy.example')
- # http.proxy? # => true
- # http.proxy_from_env? # => false
- # http.proxy_address # => "proxy.example"
- # # These use default values.
- # http.proxy_port # => 80
- # http.proxy_user # => nil
- # http.proxy_pass # => nil
- #
- # The port, username, and password for the proxy may also be given:
- #
- # http = Gem::Net::HTTP.new(hostname, nil, 'proxy.example', 8000, 'pname', 'ppass')
- # # => #<Gem::Net::HTTP jsonplaceholder.typicode.com:80 open=false>
- # http.proxy? # => true
- # http.proxy_from_env? # => false
- # http.proxy_address # => "proxy.example"
- # http.proxy_port # => 8000
- # http.proxy_user # => "pname"
- # http.proxy_pass # => "ppass"
- #
- # === Proxy Using '<tt>ENV['http_proxy']</tt>'
- #
- # When environment variable <tt>'http_proxy'</tt>
- # is set to a \Gem::URI string,
- # the returned +http+ will have the server at that URI as its proxy;
- # note that the \Gem::URI string must have a protocol
- # such as <tt>'http'</tt> or <tt>'https'</tt>:
- #
- # ENV['http_proxy'] = 'http://example.com'
- # http = Gem::Net::HTTP.new(hostname)
- # http.proxy? # => true
- # http.proxy_from_env? # => true
- # http.proxy_address # => "example.com"
- # # These use default values.
- # http.proxy_port # => 80
- # http.proxy_user # => nil
- # http.proxy_pass # => nil
- #
- # The \Gem::URI string may include proxy username, password, and port number:
- #
- # ENV['http_proxy'] = 'http://pname:ppass@example.com:8000'
- # http = Gem::Net::HTTP.new(hostname)
- # http.proxy? # => true
- # http.proxy_from_env? # => true
- # http.proxy_address # => "example.com"
- # http.proxy_port # => 8000
- # http.proxy_user # => "pname"
- # http.proxy_pass # => "ppass"
- #
- # === Filtering Proxies
- #
- # With method Gem::Net::HTTP.new (but not Gem::Net::HTTP.start),
- # you can use argument +p_no_proxy+ to filter proxies:
- #
- # - Reject a certain address:
- #
- # http = Gem::Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example')
- # http.proxy_address # => nil
- #
- # - Reject certain domains or subdomains:
- #
- # http = Gem::Net::HTTP.new('example.com', nil, 'my.proxy.example', 8000, 'pname', 'ppass', 'proxy.example')
- # http.proxy_address # => nil
- #
- # - Reject certain addresses and port combinations:
- #
- # http = Gem::Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example:1234')
- # http.proxy_address # => "proxy.example"
- #
- # http = Gem::Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'proxy.example:8000')
- # http.proxy_address # => nil
- #
- # - Reject a list of the types above delimited using a comma:
- #
- # http = Gem::Net::HTTP.new('example.com', nil, 'proxy.example', 8000, 'pname', 'ppass', 'my.proxy,proxy.example:8000')
- # http.proxy_address # => nil
- #
- # http = Gem::Net::HTTP.new('example.com', nil, 'my.proxy', 8000, 'pname', 'ppass', 'my.proxy,proxy.example:8000')
- # http.proxy_address # => nil
- #
- # == Compression and Decompression
- #
- # \Gem::Net::HTTP does not compress the body of a request before sending.
- #
- # By default, \Gem::Net::HTTP adds header <tt>'Accept-Encoding'</tt>
- # to a new {request object}[rdoc-ref:Gem::Net::HTTPRequest]:
- #
- # Gem::Net::HTTP::Get.new(uri)['Accept-Encoding']
- # # => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
- #
- # This requests the server to zip-encode the response body if there is one;
- # the server is not required to do so.
- #
- # \Gem::Net::HTTP does not automatically decompress a response body
- # if the response has header <tt>'Content-Range'</tt>.
- #
- # Otherwise decompression (or not) depends on the value of header
- # {Content-Encoding}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-encoding-response-header]:
- #
- # - <tt>'deflate'</tt>, <tt>'gzip'</tt>, or <tt>'x-gzip'</tt>:
- # decompresses the body and deletes the header.
- # - <tt>'none'</tt> or <tt>'identity'</tt>:
- # does not decompress the body, but deletes the header.
- # - Any other value:
- # leaves the body and header unchanged.
- #
- # == What's Here
- #
- # This is a categorized summary of methods and attributes.
- #
- # === \Gem::Net::HTTP Objects
- #
- # - {::new}[rdoc-ref:Gem::Net::HTTP.new]:
- # Creates a new instance.
- # - {#inspect}[rdoc-ref:Gem::Net::HTTP#inspect]:
- # Returns a string representation of +self+.
- #
- # === Sessions
- #
- # - {::start}[rdoc-ref:Gem::Net::HTTP.start]:
- # Begins a new session in a new \Gem::Net::HTTP object.
- # - {#started?}[rdoc-ref:Gem::Net::HTTP#started?]
- # (aliased as {#active?}[rdoc-ref:Gem::Net::HTTP#active?]):
- # Returns whether in a session.
- # - {#finish}[rdoc-ref:Gem::Net::HTTP#finish]:
- # Ends an active session.
- # - {#start}[rdoc-ref:Gem::Net::HTTP#start]:
- # Begins a new session in an existing \Gem::Net::HTTP object (+self+).
- #
- # === Connections
- #
- # - {:continue_timeout}[rdoc-ref:Gem::Net::HTTP#continue_timeout]:
- # Returns the continue timeout.
- # - {#continue_timeout=}[rdoc-ref:Gem::Net::HTTP#continue_timeout=]:
- # Sets the continue timeout seconds.
- # - {:keep_alive_timeout}[rdoc-ref:Gem::Net::HTTP#keep_alive_timeout]:
- # Returns the keep-alive timeout.
- # - {:keep_alive_timeout=}[rdoc-ref:Gem::Net::HTTP#keep_alive_timeout=]:
- # Sets the keep-alive timeout.
- # - {:max_retries}[rdoc-ref:Gem::Net::HTTP#max_retries]:
- # Returns the maximum retries.
- # - {#max_retries=}[rdoc-ref:Gem::Net::HTTP#max_retries=]:
- # Sets the maximum retries.
- # - {:open_timeout}[rdoc-ref:Gem::Net::HTTP#open_timeout]:
- # Returns the open timeout.
- # - {:open_timeout=}[rdoc-ref:Gem::Net::HTTP#open_timeout=]:
- # Sets the open timeout.
- # - {:read_timeout}[rdoc-ref:Gem::Net::HTTP#read_timeout]:
- # Returns the open timeout.
- # - {:read_timeout=}[rdoc-ref:Gem::Net::HTTP#read_timeout=]:
- # Sets the read timeout.
- # - {:ssl_timeout}[rdoc-ref:Gem::Net::HTTP#ssl_timeout]:
- # Returns the ssl timeout.
- # - {:ssl_timeout=}[rdoc-ref:Gem::Net::HTTP#ssl_timeout=]:
- # Sets the ssl timeout.
- # - {:write_timeout}[rdoc-ref:Gem::Net::HTTP#write_timeout]:
- # Returns the write timeout.
- # - {write_timeout=}[rdoc-ref:Gem::Net::HTTP#write_timeout=]:
- # Sets the write timeout.
- #
- # === Requests
- #
- # - {::get}[rdoc-ref:Gem::Net::HTTP.get]:
- # Sends a GET request and returns the string response body.
- # - {::get_print}[rdoc-ref:Gem::Net::HTTP.get_print]:
- # Sends a GET request and write the string response body to $stdout.
- # - {::get_response}[rdoc-ref:Gem::Net::HTTP.get_response]:
- # Sends a GET request and returns a response object.
- # - {::post_form}[rdoc-ref:Gem::Net::HTTP.post_form]:
- # Sends a POST request with form data and returns a response object.
- # - {::post}[rdoc-ref:Gem::Net::HTTP.post]:
- # Sends a POST request with data and returns a response object.
- # - {#copy}[rdoc-ref:Gem::Net::HTTP#copy]:
- # Sends a COPY request and returns a response object.
- # - {#delete}[rdoc-ref:Gem::Net::HTTP#delete]:
- # Sends a DELETE request and returns a response object.
- # - {#get}[rdoc-ref:Gem::Net::HTTP#get]:
- # Sends a GET request and returns a response object.
- # - {#head}[rdoc-ref:Gem::Net::HTTP#head]:
- # Sends a HEAD request and returns a response object.
- # - {#lock}[rdoc-ref:Gem::Net::HTTP#lock]:
- # Sends a LOCK request and returns a response object.
- # - {#mkcol}[rdoc-ref:Gem::Net::HTTP#mkcol]:
- # Sends a MKCOL request and returns a response object.
- # - {#move}[rdoc-ref:Gem::Net::HTTP#move]:
- # Sends a MOVE request and returns a response object.
- # - {#options}[rdoc-ref:Gem::Net::HTTP#options]:
- # Sends a OPTIONS request and returns a response object.
- # - {#patch}[rdoc-ref:Gem::Net::HTTP#patch]:
- # Sends a PATCH request and returns a response object.
- # - {#post}[rdoc-ref:Gem::Net::HTTP#post]:
- # Sends a POST request and returns a response object.
- # - {#propfind}[rdoc-ref:Gem::Net::HTTP#propfind]:
- # Sends a PROPFIND request and returns a response object.
- # - {#proppatch}[rdoc-ref:Gem::Net::HTTP#proppatch]:
- # Sends a PROPPATCH request and returns a response object.
- # - {#put}[rdoc-ref:Gem::Net::HTTP#put]:
- # Sends a PUT request and returns a response object.
- # - {#request}[rdoc-ref:Gem::Net::HTTP#request]:
- # Sends a request and returns a response object.
- # - {#request_get}[rdoc-ref:Gem::Net::HTTP#request_get]
- # (aliased as {#get2}[rdoc-ref:Gem::Net::HTTP#get2]):
- # Sends a GET request and forms a response object;
- # if a block given, calls the block with the object,
- # otherwise returns the object.
- # - {#request_head}[rdoc-ref:Gem::Net::HTTP#request_head]
- # (aliased as {#head2}[rdoc-ref:Gem::Net::HTTP#head2]):
- # Sends a HEAD request and forms a response object;
- # if a block given, calls the block with the object,
- # otherwise returns the object.
- # - {#request_post}[rdoc-ref:Gem::Net::HTTP#request_post]
- # (aliased as {#post2}[rdoc-ref:Gem::Net::HTTP#post2]):
- # Sends a POST request and forms a response object;
- # if a block given, calls the block with the object,
- # otherwise returns the object.
- # - {#send_request}[rdoc-ref:Gem::Net::HTTP#send_request]:
- # Sends a request and returns a response object.
- # - {#trace}[rdoc-ref:Gem::Net::HTTP#trace]:
- # Sends a TRACE request and returns a response object.
- # - {#unlock}[rdoc-ref:Gem::Net::HTTP#unlock]:
- # Sends an UNLOCK request and returns a response object.
- #
- # === Responses
- #
- # - {:close_on_empty_response}[rdoc-ref:Gem::Net::HTTP#close_on_empty_response]:
- # Returns whether to close connection on empty response.
- # - {:close_on_empty_response=}[rdoc-ref:Gem::Net::HTTP#close_on_empty_response=]:
- # Sets whether to close connection on empty response.
- # - {:ignore_eof}[rdoc-ref:Gem::Net::HTTP#ignore_eof]:
- # Returns whether to ignore end-of-file when reading a response body
- # with <tt>Content-Length</tt> headers.
- # - {:ignore_eof=}[rdoc-ref:Gem::Net::HTTP#ignore_eof=]:
- # Sets whether to ignore end-of-file when reading a response body
- # with <tt>Content-Length</tt> headers.
- # - {:response_body_encoding}[rdoc-ref:Gem::Net::HTTP#response_body_encoding]:
- # Returns the encoding to use for the response body.
- # - {#response_body_encoding=}[rdoc-ref:Gem::Net::HTTP#response_body_encoding=]:
- # Sets the response body encoding.
- #
- # === Proxies
- #
- # - {:proxy_address}[rdoc-ref:Gem::Net::HTTP#proxy_address]:
- # Returns the proxy address.
- # - {:proxy_address=}[rdoc-ref:Gem::Net::HTTP#proxy_address=]:
- # Sets the proxy address.
- # - {::proxy_class?}[rdoc-ref:Gem::Net::HTTP.proxy_class?]:
- # Returns whether +self+ is a proxy class.
- # - {#proxy?}[rdoc-ref:Gem::Net::HTTP#proxy?]:
- # Returns whether +self+ has a proxy.
- # - {#proxy_address}[rdoc-ref:Gem::Net::HTTP#proxy_address]
- # (aliased as {#proxyaddr}[rdoc-ref:Gem::Net::HTTP#proxyaddr]):
- # Returns the proxy address.
- # - {#proxy_from_env?}[rdoc-ref:Gem::Net::HTTP#proxy_from_env?]:
- # Returns whether the proxy is taken from an environment variable.
- # - {:proxy_from_env=}[rdoc-ref:Gem::Net::HTTP#proxy_from_env=]:
- # Sets whether the proxy is to be taken from an environment variable.
- # - {:proxy_pass}[rdoc-ref:Gem::Net::HTTP#proxy_pass]:
- # Returns the proxy password.
- # - {:proxy_pass=}[rdoc-ref:Gem::Net::HTTP#proxy_pass=]:
- # Sets the proxy password.
- # - {:proxy_port}[rdoc-ref:Gem::Net::HTTP#proxy_port]:
- # Returns the proxy port.
- # - {:proxy_port=}[rdoc-ref:Gem::Net::HTTP#proxy_port=]:
- # Sets the proxy port.
- # - {#proxy_user}[rdoc-ref:Gem::Net::HTTP#proxy_user]:
- # Returns the proxy user name.
- # - {:proxy_user=}[rdoc-ref:Gem::Net::HTTP#proxy_user=]:
- # Sets the proxy user.
- #
- # === Security
- #
- # - {:ca_file}[rdoc-ref:Gem::Net::HTTP#ca_file]:
- # Returns the path to a CA certification file.
- # - {:ca_file=}[rdoc-ref:Gem::Net::HTTP#ca_file=]:
- # Sets the path to a CA certification file.
- # - {:ca_path}[rdoc-ref:Gem::Net::HTTP#ca_path]:
- # Returns the path of to CA directory containing certification files.
- # - {:ca_path=}[rdoc-ref:Gem::Net::HTTP#ca_path=]:
- # Sets the path of to CA directory containing certification files.
- # - {:cert}[rdoc-ref:Gem::Net::HTTP#cert]:
- # Returns the OpenSSL::X509::Certificate object to be used for client certification.
- # - {:cert=}[rdoc-ref:Gem::Net::HTTP#cert=]:
- # Sets the OpenSSL::X509::Certificate object to be used for client certification.
- # - {:cert_store}[rdoc-ref:Gem::Net::HTTP#cert_store]:
- # Returns the X509::Store to be used for verifying peer certificate.
- # - {:cert_store=}[rdoc-ref:Gem::Net::HTTP#cert_store=]:
- # Sets the X509::Store to be used for verifying peer certificate.
- # - {:ciphers}[rdoc-ref:Gem::Net::HTTP#ciphers]:
- # Returns the available SSL ciphers.
- # - {:ciphers=}[rdoc-ref:Gem::Net::HTTP#ciphers=]:
- # Sets the available SSL ciphers.
- # - {:extra_chain_cert}[rdoc-ref:Gem::Net::HTTP#extra_chain_cert]:
- # Returns the extra X509 certificates to be added to the certificate chain.
- # - {:extra_chain_cert=}[rdoc-ref:Gem::Net::HTTP#extra_chain_cert=]:
- # Sets the extra X509 certificates to be added to the certificate chain.
- # - {:key}[rdoc-ref:Gem::Net::HTTP#key]:
- # Returns the OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
- # - {:key=}[rdoc-ref:Gem::Net::HTTP#key=]:
- # Sets the OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
- # - {:max_version}[rdoc-ref:Gem::Net::HTTP#max_version]:
- # Returns the maximum SSL version.
- # - {:max_version=}[rdoc-ref:Gem::Net::HTTP#max_version=]:
- # Sets the maximum SSL version.
- # - {:min_version}[rdoc-ref:Gem::Net::HTTP#min_version]:
- # Returns the minimum SSL version.
- # - {:min_version=}[rdoc-ref:Gem::Net::HTTP#min_version=]:
- # Sets the minimum SSL version.
- # - {#peer_cert}[rdoc-ref:Gem::Net::HTTP#peer_cert]:
- # Returns the X509 certificate chain for the session's socket peer.
- # - {:ssl_version}[rdoc-ref:Gem::Net::HTTP#ssl_version]:
- # Returns the SSL version.
- # - {:ssl_version=}[rdoc-ref:Gem::Net::HTTP#ssl_version=]:
- # Sets the SSL version.
- # - {#use_ssl=}[rdoc-ref:Gem::Net::HTTP#use_ssl=]:
- # Sets whether a new session is to use Transport Layer Security.
- # - {#use_ssl?}[rdoc-ref:Gem::Net::HTTP#use_ssl?]:
- # Returns whether +self+ uses SSL.
- # - {:verify_callback}[rdoc-ref:Gem::Net::HTTP#verify_callback]:
- # Returns the callback for the server certification verification.
- # - {:verify_callback=}[rdoc-ref:Gem::Net::HTTP#verify_callback=]:
- # Sets the callback for the server certification verification.
- # - {:verify_depth}[rdoc-ref:Gem::Net::HTTP#verify_depth]:
- # Returns the maximum depth for the certificate chain verification.
- # - {:verify_depth=}[rdoc-ref:Gem::Net::HTTP#verify_depth=]:
- # Sets the maximum depth for the certificate chain verification.
- # - {:verify_hostname}[rdoc-ref:Gem::Net::HTTP#verify_hostname]:
- # Returns the flags for server the certification verification at the beginning of the SSL/TLS session.
- # - {:verify_hostname=}[rdoc-ref:Gem::Net::HTTP#verify_hostname=]:
- # Sets he flags for server the certification verification at the beginning of the SSL/TLS session.
- # - {:verify_mode}[rdoc-ref:Gem::Net::HTTP#verify_mode]:
- # Returns the flags for server the certification verification at the beginning of the SSL/TLS session.
- # - {:verify_mode=}[rdoc-ref:Gem::Net::HTTP#verify_mode=]:
- # Sets the flags for server the certification verification at the beginning of the SSL/TLS session.
- #
- # === Addresses and Ports
- #
- # - {:address}[rdoc-ref:Gem::Net::HTTP#address]:
- # Returns the string host name or host IP.
- # - {::default_port}[rdoc-ref:Gem::Net::HTTP.default_port]:
- # Returns integer 80, the default port to use for HTTP requests.
- # - {::http_default_port}[rdoc-ref:Gem::Net::HTTP.http_default_port]:
- # Returns integer 80, the default port to use for HTTP requests.
- # - {::https_default_port}[rdoc-ref:Gem::Net::HTTP.https_default_port]:
- # Returns integer 443, the default port to use for HTTPS requests.
- # - {#ipaddr}[rdoc-ref:Gem::Net::HTTP#ipaddr]:
- # Returns the IP address for the connection.
- # - {#ipaddr=}[rdoc-ref:Gem::Net::HTTP#ipaddr=]:
- # Sets the IP address for the connection.
- # - {:local_host}[rdoc-ref:Gem::Net::HTTP#local_host]:
- # Returns the string local host used to establish the connection.
- # - {:local_host=}[rdoc-ref:Gem::Net::HTTP#local_host=]:
- # Sets the string local host used to establish the connection.
- # - {:local_port}[rdoc-ref:Gem::Net::HTTP#local_port]:
- # Returns the integer local port used to establish the connection.
- # - {:local_port=}[rdoc-ref:Gem::Net::HTTP#local_port=]:
- # Sets the integer local port used to establish the connection.
- # - {:port}[rdoc-ref:Gem::Net::HTTP#port]:
- # Returns the integer port number.
- #
- # === \HTTP Version
- #
- # - {::version_1_2?}[rdoc-ref:Gem::Net::HTTP.version_1_2?]
- # (aliased as {::is_version_1_2?}[rdoc-ref:Gem::Net::HTTP.is_version_1_2?]
- # and {::version_1_2}[rdoc-ref:Gem::Net::HTTP.version_1_2]):
- # Returns true; retained for compatibility.
- #
- # === Debugging
- #
- # - {#set_debug_output}[rdoc-ref:Gem::Net::HTTP#set_debug_output]:
- # Sets the output stream for debugging.
- #
- class HTTP < Protocol
-
- # :stopdoc:
- VERSION = "0.4.0"
- HTTPVersion = '1.1'
- begin
- require 'zlib'
- HAVE_ZLIB=true
- rescue LoadError
- HAVE_ZLIB=false
- end
- # :startdoc:
-
- # Returns +true+; retained for compatibility.
- def HTTP.version_1_2
- true
- end
-
- # Returns +true+; retained for compatibility.
- def HTTP.version_1_2?
- true
- end
-
- # Returns +false+; retained for compatibility.
- def HTTP.version_1_1? #:nodoc:
- false
- end
-
- class << HTTP
- alias is_version_1_1? version_1_1? #:nodoc:
- alias is_version_1_2? version_1_2? #:nodoc:
- end
-
- # :call-seq:
- # Gem::Net::HTTP.get_print(hostname, path, port = 80) -> nil
- # Gem::Net::HTTP:get_print(uri, headers = {}, port = uri.port) -> nil
- #
- # Like Gem::Net::HTTP.get, but writes the returned body to $stdout;
- # returns +nil+.
- def HTTP.get_print(uri_or_host, path_or_headers = nil, port = nil)
- get_response(uri_or_host, path_or_headers, port) {|res|
- res.read_body do |chunk|
- $stdout.print chunk
- end
- }
- nil
- end
-
- # :call-seq:
- # Gem::Net::HTTP.get(hostname, path, port = 80) -> body
- # Gem::Net::HTTP:get(uri, headers = {}, port = uri.port) -> body
- #
- # Sends a GET request and returns the \HTTP response body as a string.
- #
- # With string arguments +hostname+ and +path+:
- #
- # hostname = 'jsonplaceholder.typicode.com'
- # path = '/todos/1'
- # puts Gem::Net::HTTP.get(hostname, path)
- #
- # Output:
- #
- # {
- # "userId": 1,
- # "id": 1,
- # "title": "delectus aut autem",
- # "completed": false
- # }
- #
- # With URI object +uri+ and optional hash argument +headers+:
- #
- # uri = Gem::URI('https://jsonplaceholder.typicode.com/todos/1')
- # headers = {'Content-type' => 'application/json; charset=UTF-8'}
- # Gem::Net::HTTP.get(uri, headers)
- #
- # Related:
- #
- # - Gem::Net::HTTP::Get: request class for \HTTP method +GET+.
- # - Gem::Net::HTTP#get: convenience method for \HTTP method +GET+.
- #
- def HTTP.get(uri_or_host, path_or_headers = nil, port = nil)
- get_response(uri_or_host, path_or_headers, port).body
- end
-
- # :call-seq:
- # Gem::Net::HTTP.get_response(hostname, path, port = 80) -> http_response
- # Gem::Net::HTTP:get_response(uri, headers = {}, port = uri.port) -> http_response
- #
- # Like Gem::Net::HTTP.get, but returns a Gem::Net::HTTPResponse object
- # instead of the body string.
- def HTTP.get_response(uri_or_host, path_or_headers = nil, port = nil, &block)
- if path_or_headers && !path_or_headers.is_a?(Hash)
- host = uri_or_host
- path = path_or_headers
- new(host, port || HTTP.default_port).start {|http|
- return http.request_get(path, &block)
- }
- else
- uri = uri_or_host
- headers = path_or_headers
- start(uri.hostname, uri.port,
- :use_ssl => uri.scheme == 'https') {|http|
- return http.request_get(uri, headers, &block)
- }
- end
- end
-
- # Posts data to a host; returns a Gem::Net::HTTPResponse object.
- #
- # Argument +url+ must be a URL;
- # argument +data+ must be a string:
- #
- # _uri = uri.dup
- # _uri.path = '/posts'
- # data = '{"title": "foo", "body": "bar", "userId": 1}'
- # headers = {'content-type': 'application/json'}
- # res = Gem::Net::HTTP.post(_uri, data, headers) # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- # puts res.body
- #
- # Output:
- #
- # {
- # "title": "foo",
- # "body": "bar",
- # "userId": 1,
- # "id": 101
- # }
- #
- # Related:
- #
- # - Gem::Net::HTTP::Post: request class for \HTTP method +POST+.
- # - Gem::Net::HTTP#post: convenience method for \HTTP method +POST+.
- #
- def HTTP.post(url, data, header = nil)
- start(url.hostname, url.port,
- :use_ssl => url.scheme == 'https' ) {|http|
- http.post(url, data, header)
- }
- end
-
- # Posts data to a host; returns a Gem::Net::HTTPResponse object.
- #
- # Argument +url+ must be a URI;
- # argument +data+ must be a hash:
- #
- # _uri = uri.dup
- # _uri.path = '/posts'
- # data = {title: 'foo', body: 'bar', userId: 1}
- # res = Gem::Net::HTTP.post_form(_uri, data) # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- # puts res.body
- #
- # Output:
- #
- # {
- # "title": "foo",
- # "body": "bar",
- # "userId": "1",
- # "id": 101
- # }
- #
- def HTTP.post_form(url, params)
- req = Post.new(url)
- req.form_data = params
- req.basic_auth url.user, url.password if url.user
- start(url.hostname, url.port,
- :use_ssl => url.scheme == 'https' ) {|http|
- http.request(req)
- }
- end
-
- #
- # \HTTP session management
- #
-
- # Returns integer +80+, the default port to use for \HTTP requests:
- #
- # Gem::Net::HTTP.default_port # => 80
- #
- def HTTP.default_port
- http_default_port()
- end
-
- # Returns integer +80+, the default port to use for \HTTP requests:
- #
- # Gem::Net::HTTP.http_default_port # => 80
- #
- def HTTP.http_default_port
- 80
- end
-
- # Returns integer +443+, the default port to use for HTTPS requests:
- #
- # Gem::Net::HTTP.https_default_port # => 443
- #
- def HTTP.https_default_port
- 443
- end
-
- def HTTP.socket_type #:nodoc: obsolete
- BufferedIO
- end
-
- # :call-seq:
- # HTTP.start(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, opts) -> http
- # HTTP.start(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, opts) {|http| ... } -> object
- #
- # Creates a new \Gem::Net::HTTP object, +http+, via \Gem::Net::HTTP.new:
- #
- # - For arguments +address+ and +port+, see Gem::Net::HTTP.new.
- # - For proxy-defining arguments +p_addr+ through +p_pass+,
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- # - For argument +opts+, see below.
- #
- # With no block given:
- #
- # - Calls <tt>http.start</tt> with no block (see #start),
- # which opens a TCP connection and \HTTP session.
- # - Returns +http+.
- # - The caller should call #finish to close the session:
- #
- # http = Gem::Net::HTTP.start(hostname)
- # http.started? # => true
- # http.finish
- # http.started? # => false
- #
- # With a block given:
- #
- # - Calls <tt>http.start</tt> with the block (see #start), which:
- #
- # - Opens a TCP connection and \HTTP session.
- # - Calls the block,
- # which may make any number of requests to the host.
- # - Closes the \HTTP session and TCP connection on block exit.
- # - Returns the block's value +object+.
- #
- # - Returns +object+.
- #
- # Example:
- #
- # hostname = 'jsonplaceholder.typicode.com'
- # Gem::Net::HTTP.start(hostname) do |http|
- # puts http.get('/todos/1').body
- # puts http.get('/todos/2').body
- # end
- #
- # Output:
- #
- # {
- # "userId": 1,
- # "id": 1,
- # "title": "delectus aut autem",
- # "completed": false
- # }
- # {
- # "userId": 1,
- # "id": 2,
- # "title": "quis ut nam facilis et officia qui",
- # "completed": false
- # }
- #
- # If the last argument given is a hash, it is the +opts+ hash,
- # where each key is a method or accessor to be called,
- # and its value is the value to be set.
- #
- # The keys may include:
- #
- # - #ca_file
- # - #ca_path
- # - #cert
- # - #cert_store
- # - #ciphers
- # - #close_on_empty_response
- # - +ipaddr+ (calls #ipaddr=)
- # - #keep_alive_timeout
- # - #key
- # - #open_timeout
- # - #read_timeout
- # - #ssl_timeout
- # - #ssl_version
- # - +use_ssl+ (calls #use_ssl=)
- # - #verify_callback
- # - #verify_depth
- # - #verify_mode
- # - #write_timeout
- #
- # Note: If +port+ is +nil+ and <tt>opts[:use_ssl]</tt> is a truthy value,
- # the value passed to +new+ is Gem::Net::HTTP.https_default_port, not +port+.
- #
- def HTTP.start(address, *arg, &block) # :yield: +http+
- arg.pop if opt = Hash.try_convert(arg[-1])
- port, p_addr, p_port, p_user, p_pass = *arg
- p_addr = :ENV if arg.size < 2
- port = https_default_port if !port && opt && opt[:use_ssl]
- http = new(address, port, p_addr, p_port, p_user, p_pass)
- http.ipaddr = opt[:ipaddr] if opt && opt[:ipaddr]
-
- if opt
- if opt[:use_ssl]
- opt = {verify_mode: OpenSSL::SSL::VERIFY_PEER}.update(opt)
- end
- http.methods.grep(/\A(\w+)=\z/) do |meth|
- key = $1.to_sym
- opt.key?(key) or next
- http.__send__(meth, opt[key])
- end
- end
-
- http.start(&block)
- end
-
- class << HTTP
- alias newobj new # :nodoc:
- end
-
- # Returns a new \Gem::Net::HTTP object +http+
- # (but does not open a TCP connection or \HTTP session).
- #
- # With only string argument +address+ given
- # (and <tt>ENV['http_proxy']</tt> undefined or +nil+),
- # the returned +http+:
- #
- # - Has the given address.
- # - Has the default port number, Gem::Net::HTTP.default_port (80).
- # - Has no proxy.
- #
- # Example:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # # => #<Gem::Net::HTTP jsonplaceholder.typicode.com:80 open=false>
- # http.address # => "jsonplaceholder.typicode.com"
- # http.port # => 80
- # http.proxy? # => false
- #
- # With integer argument +port+ also given,
- # the returned +http+ has the given port:
- #
- # http = Gem::Net::HTTP.new(hostname, 8000)
- # # => #<Gem::Net::HTTP jsonplaceholder.typicode.com:8000 open=false>
- # http.port # => 8000
- #
- # For proxy-defining arguments +p_addr+ through +p_no_proxy+,
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- #
- def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_no_proxy = nil)
- http = super address, port
-
- if proxy_class? then # from Gem::Net::HTTP::Proxy()
- http.proxy_from_env = @proxy_from_env
- http.proxy_address = @proxy_address
- http.proxy_port = @proxy_port
- http.proxy_user = @proxy_user
- http.proxy_pass = @proxy_pass
- elsif p_addr == :ENV then
- http.proxy_from_env = true
- else
- if p_addr && p_no_proxy && !Gem::URI::Generic.use_proxy?(address, address, port, p_no_proxy)
- p_addr = nil
- p_port = nil
- end
- http.proxy_address = p_addr
- http.proxy_port = p_port || default_port
- http.proxy_user = p_user
- http.proxy_pass = p_pass
- end
-
- http
- end
-
- # Creates a new \Gem::Net::HTTP object for the specified server address,
- # without opening the TCP connection or initializing the \HTTP session.
- # The +address+ should be a DNS hostname or IP address.
- def initialize(address, port = nil) # :nodoc:
- @address = address
- @port = (port || HTTP.default_port)
- @ipaddr = nil
- @local_host = nil
- @local_port = nil
- @curr_http_version = HTTPVersion
- @keep_alive_timeout = 2
- @last_communicated = nil
- @close_on_empty_response = false
- @socket = nil
- @started = false
- @open_timeout = 60
- @read_timeout = 60
- @write_timeout = 60
- @continue_timeout = nil
- @max_retries = 1
- @debug_output = nil
- @response_body_encoding = false
- @ignore_eof = true
-
- @proxy_from_env = false
- @proxy_uri = nil
- @proxy_address = nil
- @proxy_port = nil
- @proxy_user = nil
- @proxy_pass = nil
-
- @use_ssl = false
- @ssl_context = nil
- @ssl_session = nil
- @sspi_enabled = false
- SSL_IVNAMES.each do |ivname|
- instance_variable_set ivname, nil
- end
- end
-
- # Returns a string representation of +self+:
- #
- # Gem::Net::HTTP.new(hostname).inspect
- # # => "#<Gem::Net::HTTP jsonplaceholder.typicode.com:80 open=false>"
- #
- def inspect
- "#<#{self.class} #{@address}:#{@port} open=#{started?}>"
- end
-
- # *WARNING* This method opens a serious security hole.
- # Never use this method in production code.
- #
- # Sets the output stream for debugging:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # File.open('t.tmp', 'w') do |file|
- # http.set_debug_output(file)
- # http.start
- # http.get('/nosuch/1')
- # http.finish
- # end
- # puts File.read('t.tmp')
- #
- # Output:
- #
- # opening connection to jsonplaceholder.typicode.com:80...
- # opened
- # <- "GET /nosuch/1 HTTP/1.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: jsonplaceholder.typicode.com\r\n\r\n"
- # -> "HTTP/1.1 404 Not Found\r\n"
- # -> "Date: Mon, 12 Dec 2022 21:14:11 GMT\r\n"
- # -> "Content-Type: application/json; charset=utf-8\r\n"
- # -> "Content-Length: 2\r\n"
- # -> "Connection: keep-alive\r\n"
- # -> "X-Powered-By: Express\r\n"
- # -> "X-Ratelimit-Limit: 1000\r\n"
- # -> "X-Ratelimit-Remaining: 999\r\n"
- # -> "X-Ratelimit-Reset: 1670879660\r\n"
- # -> "Vary: Origin, Accept-Encoding\r\n"
- # -> "Access-Control-Allow-Credentials: true\r\n"
- # -> "Cache-Control: max-age=43200\r\n"
- # -> "Pragma: no-cache\r\n"
- # -> "Expires: -1\r\n"
- # -> "X-Content-Type-Options: nosniff\r\n"
- # -> "Etag: W/\"2-vyGp6PvFo4RvsFtPoIWeCReyIC8\"\r\n"
- # -> "Via: 1.1 vegur\r\n"
- # -> "CF-Cache-Status: MISS\r\n"
- # -> "Server-Timing: cf-q-config;dur=1.3000000762986e-05\r\n"
- # -> "Report-To: {\"endpoints\":[{\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v3?s=yOr40jo%2BwS1KHzhTlVpl54beJ5Wx2FcG4gGV0XVrh3X9OlR5q4drUn2dkt5DGO4GDcE%2BVXT7CNgJvGs%2BZleIyMu8CLieFiDIvOviOY3EhHg94m0ZNZgrEdpKD0S85S507l1vsEwEHkoTm%2Ff19SiO\"}],\"group\":\"cf-nel\",\"max_age\":604800}\r\n"
- # -> "NEL: {\"success_fraction\":0,\"report_to\":\"cf-nel\",\"max_age\":604800}\r\n"
- # -> "Server: cloudflare\r\n"
- # -> "CF-RAY: 778977dc484ce591-DFW\r\n"
- # -> "alt-svc: h3=\":443\"; ma=86400, h3-29=\":443\"; ma=86400\r\n"
- # -> "\r\n"
- # reading 2 bytes...
- # -> "{}"
- # read 2 bytes
- # Conn keep-alive
- #
- def set_debug_output(output)
- warn 'Gem::Net::HTTP#set_debug_output called after HTTP started', uplevel: 1 if started?
- @debug_output = output
- end
-
- # Returns the string host name or host IP given as argument +address+ in ::new.
- attr_reader :address
-
- # Returns the integer port number given as argument +port+ in ::new.
- attr_reader :port
-
- # Sets or returns the string local host used to establish the connection;
- # initially +nil+.
- attr_accessor :local_host
-
- # Sets or returns the integer local port used to establish the connection;
- # initially +nil+.
- attr_accessor :local_port
-
- # Returns the encoding to use for the response body;
- # see #response_body_encoding=.
- attr_reader :response_body_encoding
-
- # Sets the encoding to be used for the response body;
- # returns the encoding.
- #
- # The given +value+ may be:
- #
- # - An Encoding object.
- # - The name of an encoding.
- # - An alias for an encoding name.
- #
- # See {Encoding}[rdoc-ref:Encoding].
- #
- # Examples:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.response_body_encoding = Encoding::US_ASCII # => #<Encoding:US-ASCII>
- # http.response_body_encoding = 'US-ASCII' # => "US-ASCII"
- # http.response_body_encoding = 'ASCII' # => "ASCII"
- #
- def response_body_encoding=(value)
- value = Encoding.find(value) if value.is_a?(String)
- @response_body_encoding = value
- end
-
- # Sets whether to determine the proxy from environment variable
- # '<tt>ENV['http_proxy']</tt>';
- # see {Proxy Using ENV['http_proxy']}[rdoc-ref:Gem::Net::HTTP@Proxy+Using+-27ENV-5B-27http_proxy-27-5D-27].
- attr_writer :proxy_from_env
-
- # Sets the proxy address;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- attr_writer :proxy_address
-
- # Sets the proxy port;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- attr_writer :proxy_port
-
- # Sets the proxy user;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- attr_writer :proxy_user
-
- # Sets the proxy password;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- attr_writer :proxy_pass
-
- # Returns the IP address for the connection.
- #
- # If the session has not been started,
- # returns the value set by #ipaddr=,
- # or +nil+ if it has not been set:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.ipaddr # => nil
- # http.ipaddr = '172.67.155.76'
- # http.ipaddr # => "172.67.155.76"
- #
- # If the session has been started,
- # returns the IP address from the socket:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.start
- # http.ipaddr # => "172.67.155.76"
- # http.finish
- #
- def ipaddr
- started? ? @socket.io.peeraddr[3] : @ipaddr
- end
-
- # Sets the IP address for the connection:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.ipaddr # => nil
- # http.ipaddr = '172.67.155.76'
- # http.ipaddr # => "172.67.155.76"
- #
- # The IP address may not be set if the session has been started.
- def ipaddr=(addr)
- raise IOError, "ipaddr value changed, but session already started" if started?
- @ipaddr = addr
- end
-
- # Sets or returns the numeric (\Integer or \Float) number of seconds
- # to wait for a connection to open;
- # initially 60.
- # If the connection is not made in the given interval,
- # an exception is raised.
- attr_accessor :open_timeout
-
- # Returns the numeric (\Integer or \Float) number of seconds
- # to wait for one block to be read (via one read(2) call);
- # see #read_timeout=.
- attr_reader :read_timeout
-
- # Returns the numeric (\Integer or \Float) number of seconds
- # to wait for one block to be written (via one write(2) call);
- # see #write_timeout=.
- attr_reader :write_timeout
-
- # Sets the maximum number of times to retry an idempotent request in case of
- # \Gem::Net::ReadTimeout, IOError, EOFError, Errno::ECONNRESET,
- # Errno::ECONNABORTED, Errno::EPIPE, OpenSSL::SSL::SSLError,
- # Gem::Timeout::Error.
- # The initial value is 1.
- #
- # Argument +retries+ must be a non-negative numeric value:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.max_retries = 2 # => 2
- # http.max_retries # => 2
- #
- def max_retries=(retries)
- retries = retries.to_int
- if retries < 0
- raise ArgumentError, 'max_retries should be non-negative integer number'
- end
- @max_retries = retries
- end
-
- # Returns the maximum number of times to retry an idempotent request;
- # see #max_retries=.
- attr_reader :max_retries
-
- # Sets the read timeout, in seconds, for +self+ to integer +sec+;
- # the initial value is 60.
- #
- # Argument +sec+ must be a non-negative numeric value:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.read_timeout # => 60
- # http.get('/todos/1') # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- # http.read_timeout = 0
- # http.get('/todos/1') # Raises Gem::Net::ReadTimeout.
- #
- def read_timeout=(sec)
- @socket.read_timeout = sec if @socket
- @read_timeout = sec
- end
-
- # Sets the write timeout, in seconds, for +self+ to integer +sec+;
- # the initial value is 60.
- #
- # Argument +sec+ must be a non-negative numeric value:
- #
- # _uri = uri.dup
- # _uri.path = '/posts'
- # body = 'bar' * 200000
- # data = <<EOF
- # {"title": "foo", "body": "#{body}", "userId": "1"}
- # EOF
- # headers = {'content-type': 'application/json'}
- # http = Gem::Net::HTTP.new(hostname)
- # http.write_timeout # => 60
- # http.post(_uri.path, data, headers)
- # # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- # http.write_timeout = 0
- # http.post(_uri.path, data, headers) # Raises Gem::Net::WriteTimeout.
- #
- def write_timeout=(sec)
- @socket.write_timeout = sec if @socket
- @write_timeout = sec
- end
-
- # Returns the continue timeout value;
- # see continue_timeout=.
- attr_reader :continue_timeout
-
- # Sets the continue timeout value,
- # which is the number of seconds to wait for an expected 100 Continue response.
- # If the \HTTP object does not receive a response in this many seconds
- # it sends the request body.
- def continue_timeout=(sec)
- @socket.continue_timeout = sec if @socket
- @continue_timeout = sec
- end
-
- # Sets or returns the numeric (\Integer or \Float) number of seconds
- # to keep the connection open after a request is sent;
- # initially 2.
- # If a new request is made during the given interval,
- # the still-open connection is used;
- # otherwise the connection will have been closed
- # and a new connection is opened.
- attr_accessor :keep_alive_timeout
-
- # Sets or returns whether to ignore end-of-file when reading a response body
- # with <tt>Content-Length</tt> headers;
- # initially +true+.
- attr_accessor :ignore_eof
-
- # Returns +true+ if the \HTTP session has been started:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.started? # => false
- # http.start
- # http.started? # => true
- # http.finish # => nil
- # http.started? # => false
- #
- # Gem::Net::HTTP.start(hostname) do |http|
- # http.started?
- # end # => true
- # http.started? # => false
- #
- def started?
- @started
- end
-
- alias active? started? #:nodoc: obsolete
-
- # Sets or returns whether to close the connection when the response is empty;
- # initially +false+.
- attr_accessor :close_on_empty_response
-
- # Returns +true+ if +self+ uses SSL, +false+ otherwise.
- # See Gem::Net::HTTP#use_ssl=.
- def use_ssl?
- @use_ssl
- end
-
- # Sets whether a new session is to use
- # {Transport Layer Security}[https://en.wikipedia.org/wiki/Transport_Layer_Security]:
- #
- # Raises IOError if attempting to change during a session.
- #
- # Raises OpenSSL::SSL::SSLError if the port is not an HTTPS port.
- def use_ssl=(flag)
- flag = flag ? true : false
- if started? and @use_ssl != flag
- raise IOError, "use_ssl value changed, but session already started"
- end
- @use_ssl = flag
- end
-
- SSL_IVNAMES = [
- :@ca_file,
- :@ca_path,
- :@cert,
- :@cert_store,
- :@ciphers,
- :@extra_chain_cert,
- :@key,
- :@ssl_timeout,
- :@ssl_version,
- :@min_version,
- :@max_version,
- :@verify_callback,
- :@verify_depth,
- :@verify_mode,
- :@verify_hostname,
- ] # :nodoc:
- SSL_ATTRIBUTES = [
- :ca_file,
- :ca_path,
- :cert,
- :cert_store,
- :ciphers,
- :extra_chain_cert,
- :key,
- :ssl_timeout,
- :ssl_version,
- :min_version,
- :max_version,
- :verify_callback,
- :verify_depth,
- :verify_mode,
- :verify_hostname,
- ] # :nodoc:
-
- # Sets or returns the path to a CA certification file in PEM format.
- attr_accessor :ca_file
-
- # Sets or returns the path of to CA directory
- # containing certification files in PEM format.
- attr_accessor :ca_path
-
- # Sets or returns the OpenSSL::X509::Certificate object
- # to be used for client certification.
- attr_accessor :cert
-
- # Sets or returns the X509::Store to be used for verifying peer certificate.
- attr_accessor :cert_store
-
- # Sets or returns the available SSL ciphers.
- # See {OpenSSL::SSL::SSLContext#ciphers=}[rdoc-ref:OpenSSL::SSL::SSLContext#ciphers-3D].
- attr_accessor :ciphers
-
- # Sets or returns the extra X509 certificates to be added to the certificate chain.
- # See {OpenSSL::SSL::SSLContext#add_certificate}[rdoc-ref:OpenSSL::SSL::SSLContext#add_certificate].
- attr_accessor :extra_chain_cert
-
- # Sets or returns the OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
- attr_accessor :key
-
- # Sets or returns the SSL timeout seconds.
- attr_accessor :ssl_timeout
-
- # Sets or returns the SSL version.
- # See {OpenSSL::SSL::SSLContext#ssl_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#ssl_version-3D].
- attr_accessor :ssl_version
-
- # Sets or returns the minimum SSL version.
- # See {OpenSSL::SSL::SSLContext#min_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#min_version-3D].
- attr_accessor :min_version
-
- # Sets or returns the maximum SSL version.
- # See {OpenSSL::SSL::SSLContext#max_version=}[rdoc-ref:OpenSSL::SSL::SSLContext#max_version-3D].
- attr_accessor :max_version
-
- # Sets or returns the callback for the server certification verification.
- attr_accessor :verify_callback
-
- # Sets or returns the maximum depth for the certificate chain verification.
- attr_accessor :verify_depth
-
- # Sets or returns the flags for server the certification verification
- # at the beginning of the SSL/TLS session.
- # OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER are acceptable.
- attr_accessor :verify_mode
-
- # Sets or returns whether to verify that the server certificate is valid
- # for the hostname.
- # See {OpenSSL::SSL::SSLContext#verify_hostname=}[rdoc-ref:OpenSSL::SSL::SSLContext#attribute-i-verify_mode].
- attr_accessor :verify_hostname
-
- # Returns the X509 certificate chain (an array of strings)
- # for the session's socket peer,
- # or +nil+ if none.
- def peer_cert
- if not use_ssl? or not @socket
- return nil
- end
- @socket.io.peer_cert
- end
-
- # Starts an \HTTP session.
- #
- # Without a block, returns +self+:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # # => #<Gem::Net::HTTP jsonplaceholder.typicode.com:80 open=false>
- # http.start
- # # => #<Gem::Net::HTTP jsonplaceholder.typicode.com:80 open=true>
- # http.started? # => true
- # http.finish
- #
- # With a block, calls the block with +self+,
- # finishes the session when the block exits,
- # and returns the block's value:
- #
- # http.start do |http|
- # http
- # end
- # # => #<Gem::Net::HTTP jsonplaceholder.typicode.com:80 open=false>
- # http.started? # => false
- #
- def start # :yield: http
- raise IOError, 'HTTP session already opened' if @started
- if block_given?
- begin
- do_start
- return yield(self)
- ensure
- do_finish
- end
- end
- do_start
- self
- end
-
- def do_start
- connect
- @started = true
- end
- private :do_start
-
- def connect
- if use_ssl?
- # reference early to load OpenSSL before connecting,
- # as OpenSSL may take time to load.
- @ssl_context = OpenSSL::SSL::SSLContext.new
- end
-
- if proxy? then
- conn_addr = proxy_address
- conn_port = proxy_port
- else
- conn_addr = conn_address
- conn_port = port
- end
-
- debug "opening connection to #{conn_addr}:#{conn_port}..."
- s = Gem::Timeout.timeout(@open_timeout, Gem::Net::OpenTimeout) {
- begin
- TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
- rescue => e
- raise e, "Failed to open TCP connection to " +
- "#{conn_addr}:#{conn_port} (#{e.message})"
- end
- }
- s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
- debug "opened"
- if use_ssl?
- if proxy?
- plain_sock = BufferedIO.new(s, read_timeout: @read_timeout,
- write_timeout: @write_timeout,
- continue_timeout: @continue_timeout,
- debug_output: @debug_output)
- buf = +"CONNECT #{conn_address}:#{@port} HTTP/#{HTTPVersion}\r\n" \
- "Host: #{@address}:#{@port}\r\n"
- if proxy_user
- credential = ["#{proxy_user}:#{proxy_pass}"].pack('m0')
- buf << "Proxy-Authorization: Basic #{credential}\r\n"
- end
- buf << "\r\n"
- plain_sock.write(buf)
- HTTPResponse.read_new(plain_sock).value
- # assuming nothing left in buffers after successful CONNECT response
- end
-
- ssl_parameters = Hash.new
- iv_list = instance_variables
- SSL_IVNAMES.each_with_index do |ivname, i|
- if iv_list.include?(ivname)
- value = instance_variable_get(ivname)
- unless value.nil?
- ssl_parameters[SSL_ATTRIBUTES[i]] = value
- end
- end
- end
- @ssl_context.set_params(ssl_parameters)
- unless @ssl_context.session_cache_mode.nil? # a dummy method on JRuby
- @ssl_context.session_cache_mode =
- OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
- OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
- end
- if @ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby
- @ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
- end
-
- # Still do the post_connection_check below even if connecting
- # to IP address
- verify_hostname = @ssl_context.verify_hostname
-
- # Server Name Indication (SNI) RFC 3546/6066
- case @address
- when Gem::Resolv::IPv4::Regex, Gem::Resolv::IPv6::Regex
- # don't set SNI, as IP addresses in SNI is not valid
- # per RFC 6066, section 3.
-
- # Avoid openssl warning
- @ssl_context.verify_hostname = false
- else
- ssl_host_address = @address
- end
-
- debug "starting SSL for #{conn_addr}:#{conn_port}..."
- s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
- s.sync_close = true
- s.hostname = ssl_host_address if s.respond_to?(:hostname=) && ssl_host_address
-
- if @ssl_session and
- Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout
- s.session = @ssl_session
- end
- ssl_socket_connect(s, @open_timeout)
- if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
- s.post_connection_check(@address)
- end
- debug "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
- end
- @socket = BufferedIO.new(s, read_timeout: @read_timeout,
- write_timeout: @write_timeout,
- continue_timeout: @continue_timeout,
- debug_output: @debug_output)
- @last_communicated = nil
- on_connect
- rescue => exception
- if s
- debug "Conn close because of connect error #{exception}"
- s.close
- end
- raise
- end
- private :connect
-
- def on_connect
- end
- private :on_connect
-
- # Finishes the \HTTP session:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.start
- # http.started? # => true
- # http.finish # => nil
- # http.started? # => false
- #
- # Raises IOError if not in a session.
- def finish
- raise IOError, 'HTTP session not yet started' unless started?
- do_finish
- end
-
- def do_finish
- @started = false
- @socket.close if @socket
- @socket = nil
- end
- private :do_finish
-
- #
- # proxy
- #
-
- public
-
- # no proxy
- @is_proxy_class = false
- @proxy_from_env = false
- @proxy_addr = nil
- @proxy_port = nil
- @proxy_user = nil
- @proxy_pass = nil
-
- # Creates an \HTTP proxy class which behaves like \Gem::Net::HTTP, but
- # performs all access via the specified proxy.
- #
- # This class is obsolete. You may pass these same parameters directly to
- # \Gem::Net::HTTP.new. See Gem::Net::HTTP.new for details of the arguments.
- def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil) #:nodoc:
- return self unless p_addr
-
- Class.new(self) {
- @is_proxy_class = true
-
- if p_addr == :ENV then
- @proxy_from_env = true
- @proxy_address = nil
- @proxy_port = nil
- else
- @proxy_from_env = false
- @proxy_address = p_addr
- @proxy_port = p_port || default_port
- end
-
- @proxy_user = p_user
- @proxy_pass = p_pass
- }
- end
-
- class << HTTP
- # Returns true if self is a class which was created by HTTP::Proxy.
- def proxy_class?
- defined?(@is_proxy_class) ? @is_proxy_class : false
- end
-
- # Returns the address of the proxy host, or +nil+ if none;
- # see Gem::Net::HTTP@Proxy+Server.
- attr_reader :proxy_address
-
- # Returns the port number of the proxy host, or +nil+ if none;
- # see Gem::Net::HTTP@Proxy+Server.
- attr_reader :proxy_port
-
- # Returns the user name for accessing the proxy, or +nil+ if none;
- # see Gem::Net::HTTP@Proxy+Server.
- attr_reader :proxy_user
-
- # Returns the password for accessing the proxy, or +nil+ if none;
- # see Gem::Net::HTTP@Proxy+Server.
- attr_reader :proxy_pass
- end
-
- # Returns +true+ if a proxy server is defined, +false+ otherwise;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- def proxy?
- !!(@proxy_from_env ? proxy_uri : @proxy_address)
- end
-
- # Returns +true+ if the proxy server is defined in the environment,
- # +false+ otherwise;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- def proxy_from_env?
- @proxy_from_env
- end
-
- # The proxy URI determined from the environment for this connection.
- def proxy_uri # :nodoc:
- return if @proxy_uri == false
- @proxy_uri ||= Gem::URI::HTTP.new(
- "http", nil, address, port, nil, nil, nil, nil, nil
- ).find_proxy || false
- @proxy_uri || nil
- end
-
- # Returns the address of the proxy server, if defined, +nil+ otherwise;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- def proxy_address
- if @proxy_from_env then
- proxy_uri&.hostname
- else
- @proxy_address
- end
- end
-
- # Returns the port number of the proxy server, if defined, +nil+ otherwise;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- def proxy_port
- if @proxy_from_env then
- proxy_uri&.port
- else
- @proxy_port
- end
- end
-
- # Returns the user name of the proxy server, if defined, +nil+ otherwise;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- def proxy_user
- if @proxy_from_env
- user = proxy_uri&.user
- unescape(user) if user
- else
- @proxy_user
- end
- end
-
- # Returns the password of the proxy server, if defined, +nil+ otherwise;
- # see {Proxy Server}[rdoc-ref:Gem::Net::HTTP@Proxy+Server].
- def proxy_pass
- if @proxy_from_env
- pass = proxy_uri&.password
- unescape(pass) if pass
- else
- @proxy_pass
- end
- end
-
- alias proxyaddr proxy_address #:nodoc: obsolete
- alias proxyport proxy_port #:nodoc: obsolete
-
- private
-
- def unescape(value)
- require 'cgi/util'
- CGI.unescape(value)
- end
-
- # without proxy, obsolete
-
- def conn_address # :nodoc:
- @ipaddr || address()
- end
-
- def conn_port # :nodoc:
- port()
- end
-
- def edit_path(path)
- if proxy?
- if path.start_with?("ftp://") || use_ssl?
- path
- else
- "http://#{addr_port}#{path}"
- end
- else
- path
- end
- end
-
- #
- # HTTP operations
- #
-
- public
-
- # :call-seq:
- # get(path, initheader = nil) {|res| ... }
- #
- # Sends a GET request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Get object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # With a block given, calls the block with the response body:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.get('/todos/1') do |res|
- # p res
- # end # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # Output:
- #
- # "{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n}"
- #
- # With no block given, simply returns the response object:
- #
- # http.get('/') # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # Related:
- #
- # - Gem::Net::HTTP::Get: request class for \HTTP method GET.
- # - Gem::Net::HTTP.get: sends GET request, returns response body.
- #
- def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+
- res = nil
-
- request(Get.new(path, initheader)) {|r|
- r.read_body dest, &block
- res = r
- }
- res
- end
-
- # Sends a HEAD request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Head object
- # created from string +path+ and initial headers hash +initheader+:
- #
- # res = http.head('/todos/1') # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- # res.body # => nil
- # res.to_hash.take(3)
- # # =>
- # [["date", ["Wed, 15 Feb 2023 15:25:42 GMT"]],
- # ["content-type", ["application/json; charset=utf-8"]],
- # ["connection", ["close"]]]
- #
- def head(path, initheader = nil)
- request(Head.new(path, initheader))
- end
-
- # :call-seq:
- # post(path, data, initheader = nil) {|res| ... }
- #
- # Sends a POST request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Post object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # With a block given, calls the block with the response body:
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.post('/todos', data) do |res|
- # p res
- # end # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- # Output:
- #
- # "{\n \"{\\\"userId\\\": 1, \\\"id\\\": 1, \\\"title\\\": \\\"delectus aut autem\\\", \\\"completed\\\": false}\": \"\",\n \"id\": 201\n}"
- #
- # With no block given, simply returns the response object:
- #
- # http.post('/todos', data) # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- # Related:
- #
- # - Gem::Net::HTTP::Post: request class for \HTTP method POST.
- # - Gem::Net::HTTP.post: sends POST request, returns response body.
- #
- def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
- send_entity(path, data, initheader, dest, Post, &block)
- end
-
- # :call-seq:
- # patch(path, data, initheader = nil) {|res| ... }
- #
- # Sends a PATCH request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Patch object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # With a block given, calls the block with the response body:
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.patch('/todos/1', data) do |res|
- # p res
- # end # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # Output:
- #
- # "{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false,\n \"{\\\"userId\\\": 1, \\\"id\\\": 1, \\\"title\\\": \\\"delectus aut autem\\\", \\\"completed\\\": false}\": \"\"\n}"
- #
- # With no block given, simply returns the response object:
- #
- # http.patch('/todos/1', data) # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- def patch(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
- send_entity(path, data, initheader, dest, Patch, &block)
- end
-
- # Sends a PUT request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Put object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.put('/todos/1', data) # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- def put(path, data, initheader = nil)
- request(Put.new(path, initheader), data)
- end
-
- # Sends a PROPPATCH request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Proppatch object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.proppatch('/todos/1', data)
- #
- def proppatch(path, body, initheader = nil)
- request(Proppatch.new(path, initheader), body)
- end
-
- # Sends a LOCK request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Lock object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.lock('/todos/1', data)
- #
- def lock(path, body, initheader = nil)
- request(Lock.new(path, initheader), body)
- end
-
- # Sends an UNLOCK request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Unlock object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.unlock('/todos/1', data)
- #
- def unlock(path, body, initheader = nil)
- request(Unlock.new(path, initheader), body)
- end
-
- # Sends an Options request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Options object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.options('/')
- #
- def options(path, initheader = nil)
- request(Options.new(path, initheader))
- end
-
- # Sends a PROPFIND request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Propfind object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http = Gem::Net::HTTP.new(hostname)
- # http.propfind('/todos/1', data)
- #
- def propfind(path, body = nil, initheader = {'Depth' => '0'})
- request(Propfind.new(path, initheader), body)
- end
-
- # Sends a DELETE request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Delete object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.delete('/todos/1')
- #
- def delete(path, initheader = {'Depth' => 'Infinity'})
- request(Delete.new(path, initheader))
- end
-
- # Sends a MOVE request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Move object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.move('/todos/1')
- #
- def move(path, initheader = nil)
- request(Move.new(path, initheader))
- end
-
- # Sends a COPY request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Copy object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.copy('/todos/1')
- #
- def copy(path, initheader = nil)
- request(Copy.new(path, initheader))
- end
-
- # Sends a MKCOL request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Mkcol object
- # created from string +path+, string +body+, and initial headers hash +initheader+.
- #
- # data = '{"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}'
- # http.mkcol('/todos/1', data)
- # http = Gem::Net::HTTP.new(hostname)
- #
- def mkcol(path, body = nil, initheader = nil)
- request(Mkcol.new(path, initheader), body)
- end
-
- # Sends a TRACE request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Trace object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.trace('/todos/1')
- #
- def trace(path, initheader = nil)
- request(Trace.new(path, initheader))
- end
-
- # Sends a GET request to the server;
- # forms the response into a Gem::Net::HTTPResponse object.
- #
- # The request is based on the Gem::Net::HTTP::Get object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # With no block given, returns the response object:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.request_get('/todos') # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # With a block given, calls the block with the response object
- # and returns the response object:
- #
- # http.request_get('/todos') do |res|
- # p res
- # end # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # Output:
- #
- # #<Gem::Net::HTTPOK 200 OK readbody=false>
- #
- def request_get(path, initheader = nil, &block) # :yield: +response+
- request(Get.new(path, initheader), &block)
- end
-
- # Sends a HEAD request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Head object
- # created from string +path+ and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.head('/todos/1') # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- def request_head(path, initheader = nil, &block)
- request(Head.new(path, initheader), &block)
- end
-
- # Sends a POST request to the server;
- # forms the response into a Gem::Net::HTTPResponse object.
- #
- # The request is based on the Gem::Net::HTTP::Post object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # With no block given, returns the response object:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.post('/todos', 'xyzzy')
- # # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- # With a block given, calls the block with the response body
- # and returns the response object:
- #
- # http.post('/todos', 'xyzzy') do |res|
- # p res
- # end # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- # Output:
- #
- # "{\n \"xyzzy\": \"\",\n \"id\": 201\n}"
- #
- def request_post(path, data, initheader = nil, &block) # :yield: +response+
- request Post.new(path, initheader), data, &block
- end
-
- # Sends a PUT request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTP::Put object
- # created from string +path+, string +data+, and initial headers hash +initheader+.
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.put('/todos/1', 'xyzzy')
- # # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- def request_put(path, data, initheader = nil, &block) #:nodoc:
- request Put.new(path, initheader), data, &block
- end
-
- alias get2 request_get #:nodoc: obsolete
- alias head2 request_head #:nodoc: obsolete
- alias post2 request_post #:nodoc: obsolete
- alias put2 request_put #:nodoc: obsolete
-
- # Sends an \HTTP request to the server;
- # returns an instance of a subclass of Gem::Net::HTTPResponse.
- #
- # The request is based on the Gem::Net::HTTPRequest object
- # created from string +path+, string +data+, and initial headers hash +header+.
- # That object is an instance of the
- # {subclass of Gem::Net::HTTPRequest}[rdoc-ref:Gem::Net::HTTPRequest@Request+Subclasses],
- # that corresponds to the given uppercase string +name+,
- # which must be
- # an {HTTP request method}[https://en.wikipedia.org/wiki/HTTP#Request_methods]
- # or a {WebDAV request method}[https://en.wikipedia.org/wiki/WebDAV#Implementation].
- #
- # Examples:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # http.send_request('GET', '/todos/1')
- # # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- # http.send_request('POST', '/todos', 'xyzzy')
- # # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- def send_request(name, path, data = nil, header = nil)
- has_response_body = name != 'HEAD'
- r = HTTPGenericRequest.new(name,(data ? true : false),has_response_body,path,header)
- request r, data
- end
-
- # Sends the given request +req+ to the server;
- # forms the response into a Gem::Net::HTTPResponse object.
- #
- # The given +req+ must be an instance of a
- # {subclass of Gem::Net::HTTPRequest}[rdoc-ref:Gem::Net::HTTPRequest@Request+Subclasses].
- # Argument +body+ should be given only if needed for the request.
- #
- # With no block given, returns the response object:
- #
- # http = Gem::Net::HTTP.new(hostname)
- #
- # req = Gem::Net::HTTP::Get.new('/todos/1')
- # http.request(req)
- # # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # req = Gem::Net::HTTP::Post.new('/todos')
- # http.request(req, 'xyzzy')
- # # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- # With a block given, calls the block with the response and returns the response:
- #
- # req = Gem::Net::HTTP::Get.new('/todos/1')
- # http.request(req) do |res|
- # p res
- # end # => #<Gem::Net::HTTPOK 200 OK readbody=true>
- #
- # Output:
- #
- # #<Gem::Net::HTTPOK 200 OK readbody=false>
- #
- def request(req, body = nil, &block) # :yield: +response+
- unless started?
- start {
- req['connection'] ||= 'close'
- return request(req, body, &block)
- }
- end
- if proxy_user()
- req.proxy_basic_auth proxy_user(), proxy_pass() unless use_ssl?
- end
- req.set_body_internal body
- res = transport_request(req, &block)
- if sspi_auth?(res)
- sspi_auth(req)
- res = transport_request(req, &block)
- end
- res
- end
-
- private
-
- # Executes a request which uses a representation
- # and returns its body.
- def send_entity(path, data, initheader, dest, type, &block)
- res = nil
- request(type.new(path, initheader), data) {|r|
- r.read_body dest, &block
- res = r
- }
- res
- end
-
- IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc:
-
- def transport_request(req)
- count = 0
- begin
- begin_transport req
- res = catch(:response) {
- begin
- req.exec @socket, @curr_http_version, edit_path(req.path)
- rescue Errno::EPIPE
- # Failure when writing full request, but we can probably
- # still read the received response.
- end
-
- begin
- res = HTTPResponse.read_new(@socket)
- res.decode_content = req.decode_content
- res.body_encoding = @response_body_encoding
- res.ignore_eof = @ignore_eof
- end while res.kind_of?(HTTPInformation)
-
- res.uri = req.uri
-
- res
- }
- res.reading_body(@socket, req.response_body_permitted?) {
- yield res if block_given?
- }
- rescue Gem::Net::OpenTimeout
- raise
- rescue Gem::Net::ReadTimeout, IOError, EOFError,
- Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE, Errno::ETIMEDOUT,
- # avoid a dependency on OpenSSL
- defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : IOError,
- Gem::Timeout::Error => exception
- if count < max_retries && IDEMPOTENT_METHODS_.include?(req.method)
- count += 1
- @socket.close if @socket
- debug "Conn close because of error #{exception}, and retry"
- retry
- end
- debug "Conn close because of error #{exception}"
- @socket.close if @socket
- raise
- end
-
- end_transport req, res
- res
- rescue => exception
- debug "Conn close because of error #{exception}"
- @socket.close if @socket
- raise exception
- end
-
- def begin_transport(req)
- if @socket.closed?
- connect
- elsif @last_communicated
- if @last_communicated + @keep_alive_timeout < Process.clock_gettime(Process::CLOCK_MONOTONIC)
- debug 'Conn close because of keep_alive_timeout'
- @socket.close
- connect
- elsif @socket.io.to_io.wait_readable(0) && @socket.eof?
- debug "Conn close because of EOF"
- @socket.close
- connect
- end
- end
-
- if not req.response_body_permitted? and @close_on_empty_response
- req['connection'] ||= 'close'
- end
-
- req.update_uri address, port, use_ssl?
- req['host'] ||= addr_port()
- end
-
- def end_transport(req, res)
- @curr_http_version = res.http_version
- @last_communicated = nil
- if @socket.closed?
- debug 'Conn socket closed'
- elsif not res.body and @close_on_empty_response
- debug 'Conn close'
- @socket.close
- elsif keep_alive?(req, res)
- debug 'Conn keep-alive'
- @last_communicated = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- else
- debug 'Conn close'
- @socket.close
- end
- end
-
- def keep_alive?(req, res)
- return false if req.connection_close?
- if @curr_http_version <= '1.0'
- res.connection_keep_alive?
- else # HTTP/1.1 or later
- not res.connection_close?
- end
- end
-
- def sspi_auth?(res)
- return false unless @sspi_enabled
- if res.kind_of?(HTTPProxyAuthenticationRequired) and
- proxy? and res["Proxy-Authenticate"].include?("Negotiate")
- begin
- require 'win32/sspi'
- true
- rescue LoadError
- false
- end
- else
- false
- end
- end
-
- def sspi_auth(req)
- n = Win32::SSPI::NegotiateAuth.new
- req["Proxy-Authorization"] = "Negotiate #{n.get_initial_token}"
- # Some versions of ISA will close the connection if this isn't present.
- req["Connection"] = "Keep-Alive"
- req["Proxy-Connection"] = "Keep-Alive"
- res = transport_request(req)
- authphrase = res["Proxy-Authenticate"] or return res
- req["Proxy-Authorization"] = "Negotiate #{n.complete_authentication(authphrase)}"
- rescue => err
- raise HTTPAuthenticationError.new('HTTP authentication failed', err)
- end
-
- #
- # utils
- #
-
- private
-
- def addr_port
- addr = address
- addr = "[#{addr}]" if addr.include?(":")
- default_port = use_ssl? ? HTTP.https_default_port : HTTP.http_default_port
- default_port == port ? addr : "#{addr}:#{port}"
- end
-
- # Adds a message to debugging output
- def debug(msg)
- return unless @debug_output
- @debug_output << msg
- @debug_output << "\n"
- end
-
- alias_method :D, :debug
- end
-
-end
-
-require_relative 'http/exceptions'
-
-require_relative 'http/header'
-
-require_relative 'http/generic_request'
-require_relative 'http/request'
-require_relative 'http/requests'
-
-require_relative 'http/response'
-require_relative 'http/responses'
-
-require_relative 'http/proxy_delta'
-
-require_relative 'http/backward'
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/backward.rb b/lib/rubygems/vendor/net-http/lib/net/http/backward.rb
deleted file mode 100644
index 10dbc16224..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/backward.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-# for backward compatibility
-
-# :enddoc:
-
-class Gem::Net::HTTP
- ProxyMod = ProxyDelta
- deprecate_constant :ProxyMod
-end
-
-module Gem::Net::NetPrivate
- HTTPRequest = ::Gem::Net::HTTPRequest
- deprecate_constant :HTTPRequest
-end
-
-module Gem::Net
- HTTPSession = HTTP
-
- HTTPInformationCode = HTTPInformation
- HTTPSuccessCode = HTTPSuccess
- HTTPRedirectionCode = HTTPRedirection
- HTTPRetriableCode = HTTPRedirection
- HTTPClientErrorCode = HTTPClientError
- HTTPFatalErrorCode = HTTPClientError
- HTTPServerErrorCode = HTTPServerError
- HTTPResponseReceiver = HTTPResponse
-
- HTTPResponceReceiver = HTTPResponse # Typo since 2001
-
- deprecate_constant :HTTPSession,
- :HTTPInformationCode,
- :HTTPSuccessCode,
- :HTTPRedirectionCode,
- :HTTPRetriableCode,
- :HTTPClientErrorCode,
- :HTTPFatalErrorCode,
- :HTTPServerErrorCode,
- :HTTPResponseReceiver,
- :HTTPResponceReceiver
-end
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb b/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb
deleted file mode 100644
index c629c0113b..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/exceptions.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# frozen_string_literal: true
-module Gem::Net
- # Gem::Net::HTTP exception class.
- # You cannot use Gem::Net::HTTPExceptions directly; instead, you must use
- # its subclasses.
- module HTTPExceptions
- def initialize(msg, res) #:nodoc:
- super msg
- @response = res
- end
- attr_reader :response
- alias data response #:nodoc: obsolete
- end
-
- class HTTPError < ProtocolError
- include HTTPExceptions
- end
-
- class HTTPRetriableError < ProtoRetriableError
- include HTTPExceptions
- end
-
- class HTTPClientException < ProtoServerError
- include HTTPExceptions
- end
-
- class HTTPFatalError < ProtoFatalError
- include HTTPExceptions
- end
-
- # We cannot use the name "HTTPServerError", it is the name of the response.
- HTTPServerException = HTTPClientException # :nodoc:
- deprecate_constant(:HTTPServerException)
-end
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb b/lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb
deleted file mode 100644
index 5cfe75a7cd..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/generic_request.rb
+++ /dev/null
@@ -1,414 +0,0 @@
-# frozen_string_literal: true
-#
-# \HTTPGenericRequest is the parent of the Gem::Net::HTTPRequest class.
-#
-# Do not use this directly; instead, use a subclass of Gem::Net::HTTPRequest.
-#
-# == About the Examples
-#
-# :include: doc/net-http/examples.rdoc
-#
-class Gem::Net::HTTPGenericRequest
-
- include Gem::Net::HTTPHeader
-
- def initialize(m, reqbody, resbody, uri_or_path, initheader = nil) # :nodoc:
- @method = m
- @request_has_body = reqbody
- @response_has_body = resbody
-
- if Gem::URI === uri_or_path then
- raise ArgumentError, "not an HTTP Gem::URI" unless Gem::URI::HTTP === uri_or_path
- hostname = uri_or_path.hostname
- raise ArgumentError, "no host component for Gem::URI" unless (hostname && hostname.length > 0)
- @uri = uri_or_path.dup
- host = @uri.hostname.dup
- host << ":" << @uri.port.to_s if @uri.port != @uri.default_port
- @path = uri_or_path.request_uri
- raise ArgumentError, "no HTTP request path given" unless @path
- else
- @uri = nil
- host = nil
- raise ArgumentError, "no HTTP request path given" unless uri_or_path
- raise ArgumentError, "HTTP request path is empty" if uri_or_path.empty?
- @path = uri_or_path.dup
- end
-
- @decode_content = false
-
- if Gem::Net::HTTP::HAVE_ZLIB then
- if !initheader ||
- !initheader.keys.any? { |k|
- %w[accept-encoding range].include? k.downcase
- } then
- @decode_content = true if @response_has_body
- initheader = initheader ? initheader.dup : {}
- initheader["accept-encoding"] =
- "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
- end
- end
-
- initialize_http_header initheader
- self['Accept'] ||= '*/*'
- self['User-Agent'] ||= 'Ruby'
- self['Host'] ||= host if host
- @body = nil
- @body_stream = nil
- @body_data = nil
- end
-
- # Returns the string method name for the request:
- #
- # Gem::Net::HTTP::Get.new(uri).method # => "GET"
- # Gem::Net::HTTP::Post.new(uri).method # => "POST"
- #
- attr_reader :method
-
- # Returns the string path for the request:
- #
- # Gem::Net::HTTP::Get.new(uri).path # => "/"
- # Gem::Net::HTTP::Post.new('example.com').path # => "example.com"
- #
- attr_reader :path
-
- # Returns the Gem::URI object for the request, or +nil+ if none:
- #
- # Gem::Net::HTTP::Get.new(uri).uri
- # # => #<Gem::URI::HTTPS https://jsonplaceholder.typicode.com/>
- # Gem::Net::HTTP::Get.new('example.com').uri # => nil
- #
- attr_reader :uri
-
- # Returns +false+ if the request's header <tt>'Accept-Encoding'</tt>
- # has been set manually or deleted
- # (indicating that the user intends to handle encoding in the response),
- # +true+ otherwise:
- #
- # req = Gem::Net::HTTP::Get.new(uri) # => #<Gem::Net::HTTP::Get GET>
- # req['Accept-Encoding'] # => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
- # req.decode_content # => true
- # req['Accept-Encoding'] = 'foo'
- # req.decode_content # => false
- # req.delete('Accept-Encoding')
- # req.decode_content # => false
- #
- attr_reader :decode_content
-
- # Returns a string representation of the request:
- #
- # Gem::Net::HTTP::Post.new(uri).inspect # => "#<Gem::Net::HTTP::Post POST>"
- #
- def inspect
- "\#<#{self.class} #{@method}>"
- end
-
- ##
- # Don't automatically decode response content-encoding if the user indicates
- # they want to handle it.
-
- def []=(key, val) # :nodoc:
- @decode_content = false if key.downcase == 'accept-encoding'
-
- super key, val
- end
-
- # Returns whether the request may have a body:
- #
- # Gem::Net::HTTP::Post.new(uri).request_body_permitted? # => true
- # Gem::Net::HTTP::Get.new(uri).request_body_permitted? # => false
- #
- def request_body_permitted?
- @request_has_body
- end
-
- # Returns whether the response may have a body:
- #
- # Gem::Net::HTTP::Post.new(uri).response_body_permitted? # => true
- # Gem::Net::HTTP::Head.new(uri).response_body_permitted? # => false
- #
- def response_body_permitted?
- @response_has_body
- end
-
- def body_exist? # :nodoc:
- warn "Gem::Net::HTTPRequest#body_exist? is obsolete; use response_body_permitted?", uplevel: 1 if $VERBOSE
- response_body_permitted?
- end
-
- # Returns the string body for the request, or +nil+ if there is none:
- #
- # req = Gem::Net::HTTP::Post.new(uri)
- # req.body # => nil
- # req.body = '{"title": "foo","body": "bar","userId": 1}'
- # req.body # => "{\"title\": \"foo\",\"body\": \"bar\",\"userId\": 1}"
- #
- attr_reader :body
-
- # Sets the body for the request:
- #
- # req = Gem::Net::HTTP::Post.new(uri)
- # req.body # => nil
- # req.body = '{"title": "foo","body": "bar","userId": 1}'
- # req.body # => "{\"title\": \"foo\",\"body\": \"bar\",\"userId\": 1}"
- #
- def body=(str)
- @body = str
- @body_stream = nil
- @body_data = nil
- str
- end
-
- # Returns the body stream object for the request, or +nil+ if there is none:
- #
- # req = Gem::Net::HTTP::Post.new(uri) # => #<Gem::Net::HTTP::Post POST>
- # req.body_stream # => nil
- # require 'stringio'
- # req.body_stream = StringIO.new('xyzzy') # => #<StringIO:0x0000027d1e5affa8>
- # req.body_stream # => #<StringIO:0x0000027d1e5affa8>
- #
- attr_reader :body_stream
-
- # Sets the body stream for the request:
- #
- # req = Gem::Net::HTTP::Post.new(uri) # => #<Gem::Net::HTTP::Post POST>
- # req.body_stream # => nil
- # require 'stringio'
- # req.body_stream = StringIO.new('xyzzy') # => #<StringIO:0x0000027d1e5affa8>
- # req.body_stream # => #<StringIO:0x0000027d1e5affa8>
- #
- def body_stream=(input)
- @body = nil
- @body_stream = input
- @body_data = nil
- input
- end
-
- def set_body_internal(str) #:nodoc: internal use only
- raise ArgumentError, "both of body argument and HTTPRequest#body set" if str and (@body or @body_stream)
- self.body = str if str
- if @body.nil? && @body_stream.nil? && @body_data.nil? && request_body_permitted?
- self.body = ''
- end
- end
-
- #
- # write
- #
-
- def exec(sock, ver, path) #:nodoc: internal use only
- if @body
- send_request_with_body sock, ver, path, @body
- elsif @body_stream
- send_request_with_body_stream sock, ver, path, @body_stream
- elsif @body_data
- send_request_with_body_data sock, ver, path, @body_data
- else
- write_header sock, ver, path
- end
- end
-
- def update_uri(addr, port, ssl) # :nodoc: internal use only
- # reflect the connection and @path to @uri
- return unless @uri
-
- if ssl
- scheme = 'https'
- klass = Gem::URI::HTTPS
- else
- scheme = 'http'
- klass = Gem::URI::HTTP
- end
-
- if host = self['host']
- host.sub!(/:.*/m, '')
- elsif host = @uri.host
- else
- host = addr
- end
- # convert the class of the Gem::URI
- if @uri.is_a?(klass)
- @uri.host = host
- @uri.port = port
- else
- @uri = klass.new(
- scheme, @uri.userinfo,
- host, port, nil,
- @uri.path, nil, @uri.query, nil)
- end
- end
-
- private
-
- class Chunker #:nodoc:
- def initialize(sock)
- @sock = sock
- @prev = nil
- end
-
- def write(buf)
- # avoid memcpy() of buf, buf can huge and eat memory bandwidth
- rv = buf.bytesize
- @sock.write("#{rv.to_s(16)}\r\n", buf, "\r\n")
- rv
- end
-
- def finish
- @sock.write("0\r\n\r\n")
- end
- end
-
- def send_request_with_body(sock, ver, path, body)
- self.content_length = body.bytesize
- delete 'Transfer-Encoding'
- supply_default_content_type
- write_header sock, ver, path
- wait_for_continue sock, ver if sock.continue_timeout
- sock.write body
- end
-
- def send_request_with_body_stream(sock, ver, path, f)
- unless content_length() or chunked?
- raise ArgumentError,
- "Content-Length not given and Transfer-Encoding is not `chunked'"
- end
- supply_default_content_type
- write_header sock, ver, path
- wait_for_continue sock, ver if sock.continue_timeout
- if chunked?
- chunker = Chunker.new(sock)
- IO.copy_stream(f, chunker)
- chunker.finish
- else
- IO.copy_stream(f, sock)
- end
- end
-
- def send_request_with_body_data(sock, ver, path, params)
- if /\Amultipart\/form-data\z/i !~ self.content_type
- self.content_type = 'application/x-www-form-urlencoded'
- return send_request_with_body(sock, ver, path, Gem::URI.encode_www_form(params))
- end
-
- opt = @form_option.dup
- require 'securerandom' unless defined?(SecureRandom)
- opt[:boundary] ||= SecureRandom.urlsafe_base64(40)
- self.set_content_type(self.content_type, boundary: opt[:boundary])
- if chunked?
- write_header sock, ver, path
- encode_multipart_form_data(sock, params, opt)
- else
- require 'tempfile'
- file = Tempfile.new('multipart')
- file.binmode
- encode_multipart_form_data(file, params, opt)
- file.rewind
- self.content_length = file.size
- write_header sock, ver, path
- IO.copy_stream(file, sock)
- file.close(true)
- end
- end
-
- def encode_multipart_form_data(out, params, opt)
- charset = opt[:charset]
- boundary = opt[:boundary]
- require 'securerandom' unless defined?(SecureRandom)
- boundary ||= SecureRandom.urlsafe_base64(40)
- chunked_p = chunked?
-
- buf = +''
- params.each do |key, value, h={}|
- key = quote_string(key, charset)
- filename =
- h.key?(:filename) ? h[:filename] :
- value.respond_to?(:to_path) ? File.basename(value.to_path) :
- nil
-
- buf << "--#{boundary}\r\n"
- if filename
- filename = quote_string(filename, charset)
- type = h[:content_type] || 'application/octet-stream'
- buf << "Content-Disposition: form-data; " \
- "name=\"#{key}\"; filename=\"#{filename}\"\r\n" \
- "Content-Type: #{type}\r\n\r\n"
- if !out.respond_to?(:write) || !value.respond_to?(:read)
- # if +out+ is not an IO or +value+ is not an IO
- buf << (value.respond_to?(:read) ? value.read : value)
- elsif value.respond_to?(:size) && chunked_p
- # if +out+ is an IO and +value+ is a File, use IO.copy_stream
- flush_buffer(out, buf, chunked_p)
- out << "%x\r\n" % value.size if chunked_p
- IO.copy_stream(value, out)
- out << "\r\n" if chunked_p
- else
- # +out+ is an IO, and +value+ is not a File but an IO
- flush_buffer(out, buf, chunked_p)
- 1 while flush_buffer(out, value.read(4096), chunked_p)
- end
- else
- # non-file field:
- # HTML5 says, "The parts of the generated multipart/form-data
- # resource that correspond to non-file fields must not have a
- # Content-Type header specified."
- buf << "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n"
- buf << (value.respond_to?(:read) ? value.read : value)
- end
- buf << "\r\n"
- end
- buf << "--#{boundary}--\r\n"
- flush_buffer(out, buf, chunked_p)
- out << "0\r\n\r\n" if chunked_p
- end
-
- def quote_string(str, charset)
- str = str.encode(charset, fallback:->(c){'&#%d;'%c.encode("UTF-8").ord}) if charset
- str.gsub(/[\\"]/, '\\\\\&')
- end
-
- def flush_buffer(out, buf, chunked_p)
- return unless buf
- out << "%x\r\n"%buf.bytesize if chunked_p
- out << buf
- out << "\r\n" if chunked_p
- buf.clear
- end
-
- def supply_default_content_type
- return if content_type()
- warn 'net/http: Content-Type did not set; using application/x-www-form-urlencoded', uplevel: 1 if $VERBOSE
- set_content_type 'application/x-www-form-urlencoded'
- end
-
- ##
- # Waits up to the continue timeout for a response from the server provided
- # we're speaking HTTP 1.1 and are expecting a 100-continue response.
-
- def wait_for_continue(sock, ver)
- if ver >= '1.1' and @header['expect'] and
- @header['expect'].include?('100-continue')
- if sock.io.to_io.wait_readable(sock.continue_timeout)
- res = Gem::Net::HTTPResponse.read_new(sock)
- unless res.kind_of?(Gem::Net::HTTPContinue)
- res.decode_content = @decode_content
- throw :response, res
- end
- end
- end
- end
-
- def write_header(sock, ver, path)
- reqline = "#{@method} #{path} HTTP/#{ver}"
- if /[\r\n]/ =~ reqline
- raise ArgumentError, "A Request-Line must not contain CR or LF"
- end
- buf = +''
- buf << reqline << "\r\n"
- each_capitalized do |k,v|
- buf << "#{k}: #{v}\r\n"
- end
- buf << "\r\n"
- sock.write buf
- end
-
-end
-
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/header.rb b/lib/rubygems/vendor/net-http/lib/net/http/header.rb
deleted file mode 100644
index 1488e60068..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/header.rb
+++ /dev/null
@@ -1,981 +0,0 @@
-# frozen_string_literal: true
-#
-# The \HTTPHeader module provides access to \HTTP headers.
-#
-# The module is included in:
-#
-# - Gem::Net::HTTPGenericRequest (and therefore Gem::Net::HTTPRequest).
-# - Gem::Net::HTTPResponse.
-#
-# The headers are a hash-like collection of key/value pairs called _fields_.
-#
-# == Request and Response Fields
-#
-# Headers may be included in:
-#
-# - A Gem::Net::HTTPRequest object:
-# the object's headers will be sent with the request.
-# Any fields may be defined in the request;
-# see {Setters}[rdoc-ref:Gem::Net::HTTPHeader@Setters].
-# - A Gem::Net::HTTPResponse object:
-# the objects headers are usually those returned from the host.
-# Fields may be retrieved from the object;
-# see {Getters}[rdoc-ref:Gem::Net::HTTPHeader@Getters]
-# and {Iterators}[rdoc-ref:Gem::Net::HTTPHeader@Iterators].
-#
-# Exactly which fields should be sent or expected depends on the host;
-# see:
-#
-# - {Request fields}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields].
-# - {Response fields}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields].
-#
-# == About the Examples
-#
-# :include: doc/net-http/examples.rdoc
-#
-# == Fields
-#
-# A header field is a key/value pair.
-#
-# === Field Keys
-#
-# A field key may be:
-#
-# - A string: Key <tt>'Accept'</tt> is treated as if it were
-# <tt>'Accept'.downcase</tt>; i.e., <tt>'accept'</tt>.
-# - A symbol: Key <tt>:Accept</tt> is treated as if it were
-# <tt>:Accept.to_s.downcase</tt>; i.e., <tt>'accept'</tt>.
-#
-# Examples:
-#
-# req = Gem::Net::HTTP::Get.new(uri)
-# req[:accept] # => "*/*"
-# req['Accept'] # => "*/*"
-# req['ACCEPT'] # => "*/*"
-#
-# req['accept'] = 'text/html'
-# req[:accept] = 'text/html'
-# req['ACCEPT'] = 'text/html'
-#
-# === Field Values
-#
-# A field value may be returned as an array of strings or as a string:
-#
-# - These methods return field values as arrays:
-#
-# - #get_fields: Returns the array value for the given key,
-# or +nil+ if it does not exist.
-# - #to_hash: Returns a hash of all header fields:
-# each key is a field name; its value is the array value for the field.
-#
-# - These methods return field values as string;
-# the string value for a field is equivalent to
-# <tt>self[key.downcase.to_s].join(', '))</tt>:
-#
-# - #[]: Returns the string value for the given key,
-# or +nil+ if it does not exist.
-# - #fetch: Like #[], but accepts a default value
-# to be returned if the key does not exist.
-#
-# The field value may be set:
-#
-# - #[]=: Sets the value for the given key;
-# the given value may be a string, a symbol, an array, or a hash.
-# - #add_field: Adds a given value to a value for the given key
-# (not overwriting the existing value).
-# - #delete: Deletes the field for the given key.
-#
-# Example field values:
-#
-# - \String:
-#
-# req['Accept'] = 'text/html' # => "text/html"
-# req['Accept'] # => "text/html"
-# req.get_fields('Accept') # => ["text/html"]
-#
-# - \Symbol:
-#
-# req['Accept'] = :text # => :text
-# req['Accept'] # => "text"
-# req.get_fields('Accept') # => ["text"]
-#
-# - Simple array:
-#
-# req[:foo] = %w[bar baz bat]
-# req[:foo] # => "bar, baz, bat"
-# req.get_fields(:foo) # => ["bar", "baz", "bat"]
-#
-# - Simple hash:
-#
-# req[:foo] = {bar: 0, baz: 1, bat: 2}
-# req[:foo] # => "bar, 0, baz, 1, bat, 2"
-# req.get_fields(:foo) # => ["bar", "0", "baz", "1", "bat", "2"]
-#
-# - Nested:
-#
-# req[:foo] = [%w[bar baz], {bat: 0, bam: 1}]
-# req[:foo] # => "bar, baz, bat, 0, bam, 1"
-# req.get_fields(:foo) # => ["bar", "baz", "bat", "0", "bam", "1"]
-#
-# req[:foo] = {bar: %w[baz bat], bam: {bah: 0, bad: 1}}
-# req[:foo] # => "bar, baz, bat, bam, bah, 0, bad, 1"
-# req.get_fields(:foo) # => ["bar", "baz", "bat", "bam", "bah", "0", "bad", "1"]
-#
-# == Convenience Methods
-#
-# Various convenience methods retrieve values, set values, query values,
-# set form values, or iterate over fields.
-#
-# === Setters
-#
-# \Method #[]= can set any field, but does little to validate the new value;
-# some of the other setter methods provide some validation:
-#
-# - #[]=: Sets the string or array value for the given key.
-# - #add_field: Creates or adds to the array value for the given key.
-# - #basic_auth: Sets the string authorization header for <tt>'Authorization'</tt>.
-# - #content_length=: Sets the integer length for field <tt>'Content-Length</tt>.
-# - #content_type=: Sets the string value for field <tt>'Content-Type'</tt>.
-# - #proxy_basic_auth: Sets the string authorization header for <tt>'Proxy-Authorization'</tt>.
-# - #set_range: Sets the value for field <tt>'Range'</tt>.
-#
-# === Form Setters
-#
-# - #set_form: Sets an HTML form data set.
-# - #set_form_data: Sets header fields and a body from HTML form data.
-#
-# === Getters
-#
-# \Method #[] can retrieve the value of any field that exists,
-# but always as a string;
-# some of the other getter methods return something different
-# from the simple string value:
-#
-# - #[]: Returns the string field value for the given key.
-# - #content_length: Returns the integer value of field <tt>'Content-Length'</tt>.
-# - #content_range: Returns the Range value of field <tt>'Content-Range'</tt>.
-# - #content_type: Returns the string value of field <tt>'Content-Type'</tt>.
-# - #fetch: Returns the string field value for the given key.
-# - #get_fields: Returns the array field value for the given +key+.
-# - #main_type: Returns first part of the string value of field <tt>'Content-Type'</tt>.
-# - #sub_type: Returns second part of the string value of field <tt>'Content-Type'</tt>.
-# - #range: Returns an array of Range objects of field <tt>'Range'</tt>, or +nil+.
-# - #range_length: Returns the integer length of the range given in field <tt>'Content-Range'</tt>.
-# - #type_params: Returns the string parameters for <tt>'Content-Type'</tt>.
-#
-# === Queries
-#
-# - #chunked?: Returns whether field <tt>'Transfer-Encoding'</tt> is set to <tt>'chunked'</tt>.
-# - #connection_close?: Returns whether field <tt>'Connection'</tt> is set to <tt>'close'</tt>.
-# - #connection_keep_alive?: Returns whether field <tt>'Connection'</tt> is set to <tt>'keep-alive'</tt>.
-# - #key?: Returns whether a given key exists.
-#
-# === Iterators
-#
-# - #each_capitalized: Passes each field capitalized-name/value pair to the block.
-# - #each_capitalized_name: Passes each capitalized field name to the block.
-# - #each_header: Passes each field name/value pair to the block.
-# - #each_name: Passes each field name to the block.
-# - #each_value: Passes each string field value to the block.
-#
-module Gem::Net::HTTPHeader
- MAX_KEY_LENGTH = 1024
- MAX_FIELD_LENGTH = 65536
-
- def initialize_http_header(initheader) #:nodoc:
- @header = {}
- return unless initheader
- initheader.each do |key, value|
- warn "net/http: duplicated HTTP header: #{key}", uplevel: 3 if key?(key) and $VERBOSE
- if value.nil?
- warn "net/http: nil HTTP header: #{key}", uplevel: 3 if $VERBOSE
- else
- value = value.strip # raise error for invalid byte sequences
- if key.to_s.bytesize > MAX_KEY_LENGTH
- raise ArgumentError, "too long (#{key.bytesize} bytes) header: #{key[0, 30].inspect}..."
- end
- if value.to_s.bytesize > MAX_FIELD_LENGTH
- raise ArgumentError, "header #{key} has too long field value: #{value.bytesize}"
- end
- if value.count("\r\n") > 0
- raise ArgumentError, "header #{key} has field value #{value.inspect}, this cannot include CR/LF"
- end
- @header[key.downcase.to_s] = [value]
- end
- end
- end
-
- def size #:nodoc: obsolete
- @header.size
- end
-
- alias length size #:nodoc: obsolete
-
- # Returns the string field value for the case-insensitive field +key+,
- # or +nil+ if there is no such key;
- # see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['Connection'] # => "keep-alive"
- # res['Nosuch'] # => nil
- #
- # Note that some field values may be retrieved via convenience methods;
- # see {Getters}[rdoc-ref:Gem::Net::HTTPHeader@Getters].
- def [](key)
- a = @header[key.downcase.to_s] or return nil
- a.join(', ')
- end
-
- # Sets the value for the case-insensitive +key+ to +val+,
- # overwriting the previous value if the field exists;
- # see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req['Accept'] # => "*/*"
- # req['Accept'] = 'text/html'
- # req['Accept'] # => "text/html"
- #
- # Note that some field values may be set via convenience methods;
- # see {Setters}[rdoc-ref:Gem::Net::HTTPHeader@Setters].
- def []=(key, val)
- unless val
- @header.delete key.downcase.to_s
- return val
- end
- set_field(key, val)
- end
-
- # Adds value +val+ to the value array for field +key+ if the field exists;
- # creates the field with the given +key+ and +val+ if it does not exist.
- # see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.add_field('Foo', 'bar')
- # req['Foo'] # => "bar"
- # req.add_field('Foo', 'baz')
- # req['Foo'] # => "bar, baz"
- # req.add_field('Foo', %w[baz bam])
- # req['Foo'] # => "bar, baz, baz, bam"
- # req.get_fields('Foo') # => ["bar", "baz", "baz", "bam"]
- #
- def add_field(key, val)
- stringified_downcased_key = key.downcase.to_s
- if @header.key?(stringified_downcased_key)
- append_field_value(@header[stringified_downcased_key], val)
- else
- set_field(key, val)
- end
- end
-
- private def set_field(key, val)
- case val
- when Enumerable
- ary = []
- append_field_value(ary, val)
- @header[key.downcase.to_s] = ary
- else
- val = val.to_s # for compatibility use to_s instead of to_str
- if val.b.count("\r\n") > 0
- raise ArgumentError, 'header field value cannot include CR/LF'
- end
- @header[key.downcase.to_s] = [val]
- end
- end
-
- private def append_field_value(ary, val)
- case val
- when Enumerable
- val.each{|x| append_field_value(ary, x)}
- else
- val = val.to_s
- if /[\r\n]/n.match?(val.b)
- raise ArgumentError, 'header field value cannot include CR/LF'
- end
- ary.push val
- end
- end
-
- # Returns the array field value for the given +key+,
- # or +nil+ if there is no such field;
- # see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res.get_fields('Connection') # => ["keep-alive"]
- # res.get_fields('Nosuch') # => nil
- #
- def get_fields(key)
- stringified_downcased_key = key.downcase.to_s
- return nil unless @header[stringified_downcased_key]
- @header[stringified_downcased_key].dup
- end
-
- # call-seq:
- # fetch(key, default_val = nil) {|key| ... } -> object
- # fetch(key, default_val = nil) -> value or default_val
- #
- # With a block, returns the string value for +key+ if it exists;
- # otherwise returns the value of the block;
- # ignores the +default_val+;
- # see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- #
- # # Field exists; block not called.
- # res.fetch('Connection') do |value|
- # fail 'Cannot happen'
- # end # => "keep-alive"
- #
- # # Field does not exist; block called.
- # res.fetch('Nosuch') do |value|
- # value.downcase
- # end # => "nosuch"
- #
- # With no block, returns the string value for +key+ if it exists;
- # otherwise, returns +default_val+ if it was given;
- # otherwise raises an exception:
- #
- # res.fetch('Connection', 'Foo') # => "keep-alive"
- # res.fetch('Nosuch', 'Foo') # => "Foo"
- # res.fetch('Nosuch') # Raises KeyError.
- #
- def fetch(key, *args, &block) #:yield: +key+
- a = @header.fetch(key.downcase.to_s, *args, &block)
- a.kind_of?(Array) ? a.join(', ') : a
- end
-
- # Calls the block with each key/value pair:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res.each_header do |key, value|
- # p [key, value] if key.start_with?('c')
- # end
- #
- # Output:
- #
- # ["content-type", "application/json; charset=utf-8"]
- # ["connection", "keep-alive"]
- # ["cache-control", "max-age=43200"]
- # ["cf-cache-status", "HIT"]
- # ["cf-ray", "771d17e9bc542cf5-ORD"]
- #
- # Returns an enumerator if no block is given.
- #
- # Gem::Net::HTTPHeader#each is an alias for Gem::Net::HTTPHeader#each_header.
- def each_header #:yield: +key+, +value+
- block_given? or return enum_for(__method__) { @header.size }
- @header.each do |k,va|
- yield k, va.join(', ')
- end
- end
-
- alias each each_header
-
- # Calls the block with each field key:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res.each_key do |key|
- # p key if key.start_with?('c')
- # end
- #
- # Output:
- #
- # "content-type"
- # "connection"
- # "cache-control"
- # "cf-cache-status"
- # "cf-ray"
- #
- # Returns an enumerator if no block is given.
- #
- # Gem::Net::HTTPHeader#each_name is an alias for Gem::Net::HTTPHeader#each_key.
- def each_name(&block) #:yield: +key+
- block_given? or return enum_for(__method__) { @header.size }
- @header.each_key(&block)
- end
-
- alias each_key each_name
-
- # Calls the block with each capitalized field name:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res.each_capitalized_name do |key|
- # p key if key.start_with?('C')
- # end
- #
- # Output:
- #
- # "Content-Type"
- # "Connection"
- # "Cache-Control"
- # "Cf-Cache-Status"
- # "Cf-Ray"
- #
- # The capitalization is system-dependent;
- # see {Case Mapping}[https://docs.ruby-lang.org/en/master/case_mapping_rdoc.html].
- #
- # Returns an enumerator if no block is given.
- def each_capitalized_name #:yield: +key+
- block_given? or return enum_for(__method__) { @header.size }
- @header.each_key do |k|
- yield capitalize(k)
- end
- end
-
- # Calls the block with each string field value:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res.each_value do |value|
- # p value if value.start_with?('c')
- # end
- #
- # Output:
- #
- # "chunked"
- # "cf-q-config;dur=6.0000002122251e-06"
- # "cloudflare"
- #
- # Returns an enumerator if no block is given.
- def each_value #:yield: +value+
- block_given? or return enum_for(__method__) { @header.size }
- @header.each_value do |va|
- yield va.join(', ')
- end
- end
-
- # Removes the header for the given case-insensitive +key+
- # (see {Fields}[rdoc-ref:Gem::Net::HTTPHeader@Fields]);
- # returns the deleted value, or +nil+ if no such field exists:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.delete('Accept') # => ["*/*"]
- # req.delete('Nosuch') # => nil
- #
- def delete(key)
- @header.delete(key.downcase.to_s)
- end
-
- # Returns +true+ if the field for the case-insensitive +key+ exists, +false+ otherwise:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.key?('Accept') # => true
- # req.key?('Nosuch') # => false
- #
- def key?(key)
- @header.key?(key.downcase.to_s)
- end
-
- # Returns a hash of the key/value pairs:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.to_hash
- # # =>
- # {"accept-encoding"=>["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"],
- # "accept"=>["*/*"],
- # "user-agent"=>["Ruby"],
- # "host"=>["jsonplaceholder.typicode.com"]}
- #
- def to_hash
- @header.dup
- end
-
- # Like #each_header, but the keys are returned in capitalized form.
- #
- # Gem::Net::HTTPHeader#canonical_each is an alias for Gem::Net::HTTPHeader#each_capitalized.
- def each_capitalized
- block_given? or return enum_for(__method__) { @header.size }
- @header.each do |k,v|
- yield capitalize(k), v.join(', ')
- end
- end
-
- alias canonical_each each_capitalized
-
- def capitalize(name)
- name.to_s.split(/-/).map {|s| s.capitalize }.join('-')
- end
- private :capitalize
-
- # Returns an array of Range objects that represent
- # the value of field <tt>'Range'</tt>,
- # or +nil+ if there is no such field;
- # see {Range request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#range-request-header]:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req['Range'] = 'bytes=0-99,200-299,400-499'
- # req.range # => [0..99, 200..299, 400..499]
- # req.delete('Range')
- # req.range # # => nil
- #
- def range
- return nil unless @header['range']
-
- value = self['Range']
- # byte-range-set = *( "," OWS ) ( byte-range-spec / suffix-byte-range-spec )
- # *( OWS "," [ OWS ( byte-range-spec / suffix-byte-range-spec ) ] )
- # corrected collected ABNF
- # http://tools.ietf.org/html/draft-ietf-httpbis-p5-range-19#section-5.4.1
- # http://tools.ietf.org/html/draft-ietf-httpbis-p5-range-19#appendix-C
- # http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-19#section-3.2.5
- unless /\Abytes=((?:,[ \t]*)*(?:\d+-\d*|-\d+)(?:[ \t]*,(?:[ \t]*\d+-\d*|-\d+)?)*)\z/ =~ value
- raise Gem::Net::HTTPHeaderSyntaxError, "invalid syntax for byte-ranges-specifier: '#{value}'"
- end
-
- byte_range_set = $1
- result = byte_range_set.split(/,/).map {|spec|
- m = /(\d+)?\s*-\s*(\d+)?/i.match(spec) or
- raise Gem::Net::HTTPHeaderSyntaxError, "invalid byte-range-spec: '#{spec}'"
- d1 = m[1].to_i
- d2 = m[2].to_i
- if m[1] and m[2]
- if d1 > d2
- raise Gem::Net::HTTPHeaderSyntaxError, "last-byte-pos MUST greater than or equal to first-byte-pos but '#{spec}'"
- end
- d1..d2
- elsif m[1]
- d1..-1
- elsif m[2]
- -d2..-1
- else
- raise Gem::Net::HTTPHeaderSyntaxError, 'range is not specified'
- end
- }
- # if result.empty?
- # byte-range-set must include at least one byte-range-spec or suffix-byte-range-spec
- # but above regexp already denies it.
- if result.size == 1 && result[0].begin == 0 && result[0].end == -1
- raise Gem::Net::HTTPHeaderSyntaxError, 'only one suffix-byte-range-spec with zero suffix-length'
- end
- result
- end
-
- # call-seq:
- # set_range(length) -> length
- # set_range(offset, length) -> range
- # set_range(begin..length) -> range
- #
- # Sets the value for field <tt>'Range'</tt>;
- # see {Range request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#range-request-header]:
- #
- # With argument +length+:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.set_range(100) # => 100
- # req['Range'] # => "bytes=0-99"
- #
- # With arguments +offset+ and +length+:
- #
- # req.set_range(100, 100) # => 100...200
- # req['Range'] # => "bytes=100-199"
- #
- # With argument +range+:
- #
- # req.set_range(100..199) # => 100..199
- # req['Range'] # => "bytes=100-199"
- #
- # Gem::Net::HTTPHeader#range= is an alias for Gem::Net::HTTPHeader#set_range.
- def set_range(r, e = nil)
- unless r
- @header.delete 'range'
- return r
- end
- r = (r...r+e) if e
- case r
- when Numeric
- n = r.to_i
- rangestr = (n > 0 ? "0-#{n-1}" : "-#{-n}")
- when Range
- first = r.first
- last = r.end
- last -= 1 if r.exclude_end?
- if last == -1
- rangestr = (first > 0 ? "#{first}-" : "-#{-first}")
- else
- raise Gem::Net::HTTPHeaderSyntaxError, 'range.first is negative' if first < 0
- raise Gem::Net::HTTPHeaderSyntaxError, 'range.last is negative' if last < 0
- raise Gem::Net::HTTPHeaderSyntaxError, 'must be .first < .last' if first > last
- rangestr = "#{first}-#{last}"
- end
- else
- raise TypeError, 'Range/Integer is required'
- end
- @header['range'] = ["bytes=#{rangestr}"]
- r
- end
-
- alias range= set_range
-
- # Returns the value of field <tt>'Content-Length'</tt> as an integer,
- # or +nil+ if there is no such field;
- # see {Content-Length request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-length-request-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/nosuch/1')
- # res.content_length # => 2
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res.content_length # => nil
- #
- def content_length
- return nil unless key?('Content-Length')
- len = self['Content-Length'].slice(/\d+/) or
- raise Gem::Net::HTTPHeaderSyntaxError, 'wrong Content-Length format'
- len.to_i
- end
-
- # Sets the value of field <tt>'Content-Length'</tt> to the given numeric;
- # see {Content-Length response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-length-response-header]:
- #
- # _uri = uri.dup
- # hostname = _uri.hostname # => "jsonplaceholder.typicode.com"
- # _uri.path = '/posts' # => "/posts"
- # req = Gem::Net::HTTP::Post.new(_uri) # => #<Gem::Net::HTTP::Post POST>
- # req.body = '{"title": "foo","body": "bar","userId": 1}'
- # req.content_length = req.body.size # => 42
- # req.content_type = 'application/json'
- # res = Gem::Net::HTTP.start(hostname) do |http|
- # http.request(req)
- # end # => #<Gem::Net::HTTPCreated 201 Created readbody=true>
- #
- def content_length=(len)
- unless len
- @header.delete 'content-length'
- return nil
- end
- @header['content-length'] = [len.to_i.to_s]
- end
-
- # Returns +true+ if field <tt>'Transfer-Encoding'</tt>
- # exists and has value <tt>'chunked'</tt>,
- # +false+ otherwise;
- # see {Transfer-Encoding response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#transfer-encoding-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['Transfer-Encoding'] # => "chunked"
- # res.chunked? # => true
- #
- def chunked?
- return false unless @header['transfer-encoding']
- field = self['Transfer-Encoding']
- (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false
- end
-
- # Returns a Range object representing the value of field
- # <tt>'Content-Range'</tt>, or +nil+ if no such field exists;
- # see {Content-Range response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-range-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['Content-Range'] # => nil
- # res['Content-Range'] = 'bytes 0-499/1000'
- # res['Content-Range'] # => "bytes 0-499/1000"
- # res.content_range # => 0..499
- #
- def content_range
- return nil unless @header['content-range']
- m = %r<\A\s*(\w+)\s+(\d+)-(\d+)/(\d+|\*)>.match(self['Content-Range']) or
- raise Gem::Net::HTTPHeaderSyntaxError, 'wrong Content-Range format'
- return unless m[1] == 'bytes'
- m[2].to_i .. m[3].to_i
- end
-
- # Returns the integer representing length of the value of field
- # <tt>'Content-Range'</tt>, or +nil+ if no such field exists;
- # see {Content-Range response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-range-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['Content-Range'] # => nil
- # res['Content-Range'] = 'bytes 0-499/1000'
- # res.range_length # => 500
- #
- def range_length
- r = content_range() or return nil
- r.end - r.begin + 1
- end
-
- # Returns the {media type}[https://en.wikipedia.org/wiki/Media_type]
- # from the value of field <tt>'Content-Type'</tt>,
- # or +nil+ if no such field exists;
- # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['content-type'] # => "application/json; charset=utf-8"
- # res.content_type # => "application/json"
- #
- def content_type
- main = main_type()
- return nil unless main
-
- sub = sub_type()
- if sub
- "#{main}/#{sub}"
- else
- main
- end
- end
-
- # Returns the leading ('type') part of the
- # {media type}[https://en.wikipedia.org/wiki/Media_type]
- # from the value of field <tt>'Content-Type'</tt>,
- # or +nil+ if no such field exists;
- # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['content-type'] # => "application/json; charset=utf-8"
- # res.main_type # => "application"
- #
- def main_type
- return nil unless @header['content-type']
- self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip
- end
-
- # Returns the trailing ('subtype') part of the
- # {media type}[https://en.wikipedia.org/wiki/Media_type]
- # from the value of field <tt>'Content-Type'</tt>,
- # or +nil+ if no such field exists;
- # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['content-type'] # => "application/json; charset=utf-8"
- # res.sub_type # => "json"
- #
- def sub_type
- return nil unless @header['content-type']
- _, sub = *self['Content-Type'].split(';').first.to_s.split('/')
- return nil unless sub
- sub.strip
- end
-
- # Returns the trailing ('parameters') part of the value of field <tt>'Content-Type'</tt>,
- # or +nil+ if no such field exists;
- # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
- #
- # res = Gem::Net::HTTP.get_response(hostname, '/todos/1')
- # res['content-type'] # => "application/json; charset=utf-8"
- # res.type_params # => {"charset"=>"utf-8"}
- #
- def type_params
- result = {}
- list = self['Content-Type'].to_s.split(';')
- list.shift
- list.each do |param|
- k, v = *param.split('=', 2)
- result[k.strip] = v.strip
- end
- result
- end
-
- # Sets the value of field <tt>'Content-Type'</tt>;
- # returns the new value;
- # see {Content-Type request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-request-header]:
- #
- # req = Gem::Net::HTTP::Get.new(uri)
- # req.set_content_type('application/json') # => ["application/json"]
- #
- # Gem::Net::HTTPHeader#content_type= is an alias for Gem::Net::HTTPHeader#set_content_type.
- def set_content_type(type, params = {})
- @header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')]
- end
-
- alias content_type= set_content_type
-
- # Sets the request body to a URL-encoded string derived from argument +params+,
- # and sets request header field <tt>'Content-Type'</tt>
- # to <tt>'application/x-www-form-urlencoded'</tt>.
- #
- # The resulting request is suitable for HTTP request +POST+ or +PUT+.
- #
- # Argument +params+ must be suitable for use as argument +enum+ to
- # {Gem::URI.encode_www_form}[https://docs.ruby-lang.org/en/master/Gem::URI.html#method-c-encode_www_form].
- #
- # With only argument +params+ given,
- # sets the body to a URL-encoded string with the default separator <tt>'&'</tt>:
- #
- # req = Gem::Net::HTTP::Post.new('example.com')
- #
- # req.set_form_data(q: 'ruby', lang: 'en')
- # req.body # => "q=ruby&lang=en"
- # req['Content-Type'] # => "application/x-www-form-urlencoded"
- #
- # req.set_form_data([['q', 'ruby'], ['lang', 'en']])
- # req.body # => "q=ruby&lang=en"
- #
- # req.set_form_data(q: ['ruby', 'perl'], lang: 'en')
- # req.body # => "q=ruby&q=perl&lang=en"
- #
- # req.set_form_data([['q', 'ruby'], ['q', 'perl'], ['lang', 'en']])
- # req.body # => "q=ruby&q=perl&lang=en"
- #
- # With string argument +sep+ also given,
- # uses that string as the separator:
- #
- # req.set_form_data({q: 'ruby', lang: 'en'}, '|')
- # req.body # => "q=ruby|lang=en"
- #
- # Gem::Net::HTTPHeader#form_data= is an alias for Gem::Net::HTTPHeader#set_form_data.
- def set_form_data(params, sep = '&')
- query = Gem::URI.encode_www_form(params)
- query.gsub!(/&/, sep) if sep != '&'
- self.body = query
- self.content_type = 'application/x-www-form-urlencoded'
- end
-
- alias form_data= set_form_data
-
- # Stores form data to be used in a +POST+ or +PUT+ request.
- #
- # The form data given in +params+ consists of zero or more fields;
- # each field is:
- #
- # - A scalar value.
- # - A name/value pair.
- # - An IO stream opened for reading.
- #
- # Argument +params+ should be an
- # {Enumerable}[https://docs.ruby-lang.org/en/master/Enumerable.html#module-Enumerable-label-Enumerable+in+Ruby+Classes]
- # (method <tt>params.map</tt> will be called),
- # and is often an array or hash.
- #
- # First, we set up a request:
- #
- # _uri = uri.dup
- # _uri.path ='/posts'
- # req = Gem::Net::HTTP::Post.new(_uri)
- #
- # <b>Argument +params+ As an Array</b>
- #
- # When +params+ is an array,
- # each of its elements is a subarray that defines a field;
- # the subarray may contain:
- #
- # - One string:
- #
- # req.set_form([['foo'], ['bar'], ['baz']])
- #
- # - Two strings:
- #
- # req.set_form([%w[foo 0], %w[bar 1], %w[baz 2]])
- #
- # - When argument +enctype+ (see below) is given as
- # <tt>'multipart/form-data'</tt>:
- #
- # - A string name and an IO stream opened for reading:
- #
- # require 'stringio'
- # req.set_form([['file', StringIO.new('Ruby is cool.')]])
- #
- # - A string name, an IO stream opened for reading,
- # and an options hash, which may contain these entries:
- #
- # - +:filename+: The name of the file to use.
- # - +:content_type+: The content type of the uploaded file.
- #
- # Example:
- #
- # req.set_form([['file', file, {filename: "other-filename.foo"}]]
- #
- # The various forms may be mixed:
- #
- # req.set_form(['foo', %w[bar 1], ['file', file]])
- #
- # <b>Argument +params+ As a Hash</b>
- #
- # When +params+ is a hash,
- # each of its entries is a name/value pair that defines a field:
- #
- # - The name is a string.
- # - The value may be:
- #
- # - +nil+.
- # - Another string.
- # - An IO stream opened for reading
- # (only when argument +enctype+ -- see below -- is given as
- # <tt>'multipart/form-data'</tt>).
- #
- # Examples:
- #
- # # Nil-valued fields.
- # req.set_form({'foo' => nil, 'bar' => nil, 'baz' => nil})
- #
- # # String-valued fields.
- # req.set_form({'foo' => 0, 'bar' => 1, 'baz' => 2})
- #
- # # IO-valued field.
- # require 'stringio'
- # req.set_form({'file' => StringIO.new('Ruby is cool.')})
- #
- # # Mixture of fields.
- # req.set_form({'foo' => nil, 'bar' => 1, 'file' => file})
- #
- # Optional argument +enctype+ specifies the value to be given
- # to field <tt>'Content-Type'</tt>, and must be one of:
- #
- # - <tt>'application/x-www-form-urlencoded'</tt> (the default).
- # - <tt>'multipart/form-data'</tt>;
- # see {RFC 7578}[https://www.rfc-editor.org/rfc/rfc7578].
- #
- # Optional argument +formopt+ is a hash of options
- # (applicable only when argument +enctype+
- # is <tt>'multipart/form-data'</tt>)
- # that may include the following entries:
- #
- # - +:boundary+: The value is the boundary string for the multipart message.
- # If not given, the boundary is a random string.
- # See {Boundary}[https://www.rfc-editor.org/rfc/rfc7578#section-4.1].
- # - +:charset+: Value is the character set for the form submission.
- # Field names and values of non-file fields should be encoded with this charset.
- #
- def set_form(params, enctype='application/x-www-form-urlencoded', formopt={})
- @body_data = params
- @body = nil
- @body_stream = nil
- @form_option = formopt
- case enctype
- when /\Aapplication\/x-www-form-urlencoded\z/i,
- /\Amultipart\/form-data\z/i
- self.content_type = enctype
- else
- raise ArgumentError, "invalid enctype: #{enctype}"
- end
- end
-
- # Sets header <tt>'Authorization'</tt> using the given
- # +account+ and +password+ strings:
- #
- # req.basic_auth('my_account', 'my_password')
- # req['Authorization']
- # # => "Basic bXlfYWNjb3VudDpteV9wYXNzd29yZA=="
- #
- def basic_auth(account, password)
- @header['authorization'] = [basic_encode(account, password)]
- end
-
- # Sets header <tt>'Proxy-Authorization'</tt> using the given
- # +account+ and +password+ strings:
- #
- # req.proxy_basic_auth('my_account', 'my_password')
- # req['Proxy-Authorization']
- # # => "Basic bXlfYWNjb3VudDpteV9wYXNzd29yZA=="
- #
- def proxy_basic_auth(account, password)
- @header['proxy-authorization'] = [basic_encode(account, password)]
- end
-
- def basic_encode(account, password)
- 'Basic ' + ["#{account}:#{password}"].pack('m0')
- end
- private :basic_encode
-
-# Returns whether the HTTP session is to be closed.
- def connection_close?
- token = /(?:\A|,)\s*close\s*(?:\z|,)/i
- @header['connection']&.grep(token) {return true}
- @header['proxy-connection']&.grep(token) {return true}
- false
- end
-
-# Returns whether the HTTP session is to be kept alive.
- def connection_keep_alive?
- token = /(?:\A|,)\s*keep-alive\s*(?:\z|,)/i
- @header['connection']&.grep(token) {return true}
- @header['proxy-connection']&.grep(token) {return true}
- false
- end
-
-end
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/proxy_delta.rb b/lib/rubygems/vendor/net-http/lib/net/http/proxy_delta.rb
deleted file mode 100644
index 137295a883..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/proxy_delta.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-module Gem::Net::HTTP::ProxyDelta #:nodoc: internal use only
- private
-
- def conn_address
- proxy_address()
- end
-
- def conn_port
- proxy_port()
- end
-
- def edit_path(path)
- use_ssl? ? path : "http://#{addr_port()}#{path}"
- end
-end
-
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/request.rb b/lib/rubygems/vendor/net-http/lib/net/http/request.rb
deleted file mode 100644
index 495ec9be54..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/request.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# frozen_string_literal: true
-
-# This class is the base class for \Gem::Net::HTTP request classes.
-# The class should not be used directly;
-# instead you should use its subclasses, listed below.
-#
-# == Creating a Request
-#
-# An request object may be created with either a Gem::URI or a string hostname:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('https://jsonplaceholder.typicode.com/')
-# req = Gem::Net::HTTP::Get.new(uri) # => #<Gem::Net::HTTP::Get GET>
-# req = Gem::Net::HTTP::Get.new(uri.hostname) # => #<Gem::Net::HTTP::Get GET>
-#
-# And with any of the subclasses:
-#
-# req = Gem::Net::HTTP::Head.new(uri) # => #<Gem::Net::HTTP::Head HEAD>
-# req = Gem::Net::HTTP::Post.new(uri) # => #<Gem::Net::HTTP::Post POST>
-# req = Gem::Net::HTTP::Put.new(uri) # => #<Gem::Net::HTTP::Put PUT>
-# # ...
-#
-# The new instance is suitable for use as the argument to Gem::Net::HTTP#request.
-#
-# == Request Headers
-#
-# A new request object has these header fields by default:
-#
-# req.to_hash
-# # =>
-# {"accept-encoding"=>["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"],
-# "accept"=>["*/*"],
-# "user-agent"=>["Ruby"],
-# "host"=>["jsonplaceholder.typicode.com"]}
-#
-# See:
-#
-# - {Request header Accept-Encoding}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Accept-Encoding]
-# and {Compression and Decompression}[rdoc-ref:Gem::Net::HTTP@Compression+and+Decompression].
-# - {Request header Accept}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#accept-request-header].
-# - {Request header User-Agent}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#user-agent-request-header].
-# - {Request header Host}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#host-request-header].
-#
-# You can add headers or override default headers:
-#
-# # res = Gem::Net::HTTP::Get.new(uri, {'foo' => '0', 'bar' => '1'})
-#
-# This class (and therefore its subclasses) also includes (indirectly)
-# module Gem::Net::HTTPHeader, which gives access to its
-# {methods for setting headers}[rdoc-ref:Gem::Net::HTTPHeader@Setters].
-#
-# == Request Subclasses
-#
-# Subclasses for HTTP requests:
-#
-# - Gem::Net::HTTP::Get
-# - Gem::Net::HTTP::Head
-# - Gem::Net::HTTP::Post
-# - Gem::Net::HTTP::Put
-# - Gem::Net::HTTP::Delete
-# - Gem::Net::HTTP::Options
-# - Gem::Net::HTTP::Trace
-# - Gem::Net::HTTP::Patch
-#
-# Subclasses for WebDAV requests:
-#
-# - Gem::Net::HTTP::Propfind
-# - Gem::Net::HTTP::Proppatch
-# - Gem::Net::HTTP::Mkcol
-# - Gem::Net::HTTP::Copy
-# - Gem::Net::HTTP::Move
-# - Gem::Net::HTTP::Lock
-# - Gem::Net::HTTP::Unlock
-#
-class Gem::Net::HTTPRequest < Gem::Net::HTTPGenericRequest
- # Creates an HTTP request object for +path+.
- #
- # +initheader+ are the default headers to use. Gem::Net::HTTP adds
- # Accept-Encoding to enable compression of the response body unless
- # Accept-Encoding or Range are supplied in +initheader+.
-
- def initialize(path, initheader = nil)
- super self.class::METHOD,
- self.class::REQUEST_HAS_BODY,
- self.class::RESPONSE_HAS_BODY,
- path, initheader
- end
-end
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/requests.rb b/lib/rubygems/vendor/net-http/lib/net/http/requests.rb
deleted file mode 100644
index 1a57ddc7c2..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/requests.rb
+++ /dev/null
@@ -1,425 +0,0 @@
-# frozen_string_literal: true
-
-# HTTP/1.1 methods --- RFC2616
-
-# \Class for representing
-# {HTTP method GET}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#GET_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Get.new(uri) # => #<Gem::Net::HTTP::Get GET>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: optional.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: yes.
-#
-# Related:
-#
-# - Gem::Net::HTTP.get: sends +GET+ request, returns response body.
-# - Gem::Net::HTTP#get: sends +GET+ request, returns response object.
-#
-class Gem::Net::HTTP::Get < Gem::Net::HTTPRequest
- METHOD = 'GET'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {HTTP method HEAD}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#HEAD_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Head.new(uri) # => #<Gem::Net::HTTP::Head HEAD>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: optional.
-# - Response body: no.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: yes.
-#
-# Related:
-#
-# - Gem::Net::HTTP#head: sends +HEAD+ request, returns response object.
-#
-class Gem::Net::HTTP::Head < Gem::Net::HTTPRequest
- METHOD = 'HEAD'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = false
-end
-
-# \Class for representing
-# {HTTP method POST}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#POST_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# uri.path = '/posts'
-# req = Gem::Net::HTTP::Post.new(uri) # => #<Gem::Net::HTTP::Post POST>
-# req.body = '{"title": "foo","body": "bar","userId": 1}'
-# req.content_type = 'application/json'
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: yes.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: no.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: yes.
-#
-# Related:
-#
-# - Gem::Net::HTTP.post: sends +POST+ request, returns response object.
-# - Gem::Net::HTTP#post: sends +POST+ request, returns response object.
-#
-class Gem::Net::HTTP::Post < Gem::Net::HTTPRequest
- METHOD = 'POST'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {HTTP method PUT}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#PUT_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# uri.path = '/posts'
-# req = Gem::Net::HTTP::Put.new(uri) # => #<Gem::Net::HTTP::Put PUT>
-# req.body = '{"title": "foo","body": "bar","userId": 1}'
-# req.content_type = 'application/json'
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: yes.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
-#
-class Gem::Net::HTTP::Put < Gem::Net::HTTPRequest
- METHOD = 'PUT'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {HTTP method DELETE}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#DELETE_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# uri.path = '/posts/1'
-# req = Gem::Net::HTTP::Delete.new(uri) # => #<Gem::Net::HTTP::Delete DELETE>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: optional.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
-#
-# Related:
-#
-# - Gem::Net::HTTP#delete: sends +DELETE+ request, returns response object.
-#
-class Gem::Net::HTTP::Delete < Gem::Net::HTTPRequest
- METHOD = 'DELETE'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {HTTP method OPTIONS}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#OPTIONS_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Options.new(uri) # => #<Gem::Net::HTTP::Options OPTIONS>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: optional.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
-#
-# Related:
-#
-# - Gem::Net::HTTP#options: sends +OPTIONS+ request, returns response object.
-#
-class Gem::Net::HTTP::Options < Gem::Net::HTTPRequest
- METHOD = 'OPTIONS'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {HTTP method TRACE}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#TRACE_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Trace.new(uri) # => #<Gem::Net::HTTP::Trace TRACE>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: no.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
-#
-# Related:
-#
-# - Gem::Net::HTTP#trace: sends +TRACE+ request, returns response object.
-#
-class Gem::Net::HTTP::Trace < Gem::Net::HTTPRequest
- METHOD = 'TRACE'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {HTTP method PATCH}[https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol#PATCH_method]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# uri.path = '/posts'
-# req = Gem::Net::HTTP::Patch.new(uri) # => #<Gem::Net::HTTP::Patch PATCH>
-# req.body = '{"title": "foo","body": "bar","userId": 1}'
-# req.content_type = 'application/json'
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Properties:
-#
-# - Request body: yes.
-# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: no.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
-#
-# Related:
-#
-# - Gem::Net::HTTP#patch: sends +PATCH+ request, returns response object.
-#
-class Gem::Net::HTTP::Patch < Gem::Net::HTTPRequest
- METHOD = 'PATCH'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-#
-# WebDAV methods --- RFC2518
-#
-
-# \Class for representing
-# {WebDAV method PROPFIND}[http://www.webdav.org/specs/rfc4918.html#METHOD_PROPFIND]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Propfind.new(uri) # => #<Gem::Net::HTTP::Propfind PROPFIND>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#propfind: sends +PROPFIND+ request, returns response object.
-#
-class Gem::Net::HTTP::Propfind < Gem::Net::HTTPRequest
- METHOD = 'PROPFIND'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {WebDAV method PROPPATCH}[http://www.webdav.org/specs/rfc4918.html#METHOD_PROPPATCH]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Proppatch.new(uri) # => #<Gem::Net::HTTP::Proppatch PROPPATCH>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#proppatch: sends +PROPPATCH+ request, returns response object.
-#
-class Gem::Net::HTTP::Proppatch < Gem::Net::HTTPRequest
- METHOD = 'PROPPATCH'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {WebDAV method MKCOL}[http://www.webdav.org/specs/rfc4918.html#METHOD_MKCOL]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Mkcol.new(uri) # => #<Gem::Net::HTTP::Mkcol MKCOL>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#mkcol: sends +MKCOL+ request, returns response object.
-#
-class Gem::Net::HTTP::Mkcol < Gem::Net::HTTPRequest
- METHOD = 'MKCOL'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {WebDAV method COPY}[http://www.webdav.org/specs/rfc4918.html#METHOD_COPY]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Copy.new(uri) # => #<Gem::Net::HTTP::Copy COPY>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#copy: sends +COPY+ request, returns response object.
-#
-class Gem::Net::HTTP::Copy < Gem::Net::HTTPRequest
- METHOD = 'COPY'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {WebDAV method MOVE}[http://www.webdav.org/specs/rfc4918.html#METHOD_MOVE]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Move.new(uri) # => #<Gem::Net::HTTP::Move MOVE>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#move: sends +MOVE+ request, returns response object.
-#
-class Gem::Net::HTTP::Move < Gem::Net::HTTPRequest
- METHOD = 'MOVE'
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {WebDAV method LOCK}[http://www.webdav.org/specs/rfc4918.html#METHOD_LOCK]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Lock.new(uri) # => #<Gem::Net::HTTP::Lock LOCK>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#lock: sends +LOCK+ request, returns response object.
-#
-class Gem::Net::HTTP::Lock < Gem::Net::HTTPRequest
- METHOD = 'LOCK'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
-# \Class for representing
-# {WebDAV method UNLOCK}[http://www.webdav.org/specs/rfc4918.html#METHOD_UNLOCK]:
-#
-# require 'rubygems/vendor/net-http/lib/net/http'
-# uri = Gem::URI('http://example.com')
-# hostname = uri.hostname # => "example.com"
-# req = Gem::Net::HTTP::Unlock.new(uri) # => #<Gem::Net::HTTP::Unlock UNLOCK>
-# res = Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end
-#
-# See {Request Headers}[rdoc-ref:Gem::Net::HTTPRequest@Request+Headers].
-#
-# Related:
-#
-# - Gem::Net::HTTP#unlock: sends +UNLOCK+ request, returns response object.
-#
-class Gem::Net::HTTP::Unlock < Gem::Net::HTTPRequest
- METHOD = 'UNLOCK'
- REQUEST_HAS_BODY = true
- RESPONSE_HAS_BODY = true
-end
-
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/response.rb b/lib/rubygems/vendor/net-http/lib/net/http/response.rb
deleted file mode 100644
index cbbd191d87..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/response.rb
+++ /dev/null
@@ -1,738 +0,0 @@
-# frozen_string_literal: true
-
-# This class is the base class for \Gem::Net::HTTP response classes.
-#
-# == About the Examples
-#
-# :include: doc/net-http/examples.rdoc
-#
-# == Returned Responses
-#
-# \Method Gem::Net::HTTP.get_response returns
-# an instance of one of the subclasses of \Gem::Net::HTTPResponse:
-#
-# Gem::Net::HTTP.get_response(uri)
-# # => #<Gem::Net::HTTPOK 200 OK readbody=true>
-# Gem::Net::HTTP.get_response(hostname, '/nosuch')
-# # => #<Gem::Net::HTTPNotFound 404 Not Found readbody=true>
-#
-# As does method Gem::Net::HTTP#request:
-#
-# req = Gem::Net::HTTP::Get.new(uri)
-# Gem::Net::HTTP.start(hostname) do |http|
-# http.request(req)
-# end # => #<Gem::Net::HTTPOK 200 OK readbody=true>
-#
-# \Class \Gem::Net::HTTPResponse includes module Gem::Net::HTTPHeader,
-# which provides access to response header values via (among others):
-#
-# - \Hash-like method <tt>[]</tt>.
-# - Specific reader methods, such as +content_type+.
-#
-# Examples:
-#
-# res = Gem::Net::HTTP.get_response(uri) # => #<Gem::Net::HTTPOK 200 OK readbody=true>
-# res['Content-Type'] # => "text/html; charset=UTF-8"
-# res.content_type # => "text/html"
-#
-# == Response Subclasses
-#
-# \Class \Gem::Net::HTTPResponse has a subclass for each
-# {HTTP status code}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes].
-# You can look up the response class for a given code:
-#
-# Gem::Net::HTTPResponse::CODE_TO_OBJ['200'] # => Gem::Net::HTTPOK
-# Gem::Net::HTTPResponse::CODE_TO_OBJ['400'] # => Gem::Net::HTTPBadRequest
-# Gem::Net::HTTPResponse::CODE_TO_OBJ['404'] # => Gem::Net::HTTPNotFound
-#
-# And you can retrieve the status code for a response object:
-#
-# Gem::Net::HTTP.get_response(uri).code # => "200"
-# Gem::Net::HTTP.get_response(hostname, '/nosuch').code # => "404"
-#
-# The response subclasses (indentation shows class hierarchy):
-#
-# - Gem::Net::HTTPUnknownResponse (for unhandled \HTTP extensions).
-#
-# - Gem::Net::HTTPInformation:
-#
-# - Gem::Net::HTTPContinue (100)
-# - Gem::Net::HTTPSwitchProtocol (101)
-# - Gem::Net::HTTPProcessing (102)
-# - Gem::Net::HTTPEarlyHints (103)
-#
-# - Gem::Net::HTTPSuccess:
-#
-# - Gem::Net::HTTPOK (200)
-# - Gem::Net::HTTPCreated (201)
-# - Gem::Net::HTTPAccepted (202)
-# - Gem::Net::HTTPNonAuthoritativeInformation (203)
-# - Gem::Net::HTTPNoContent (204)
-# - Gem::Net::HTTPResetContent (205)
-# - Gem::Net::HTTPPartialContent (206)
-# - Gem::Net::HTTPMultiStatus (207)
-# - Gem::Net::HTTPAlreadyReported (208)
-# - Gem::Net::HTTPIMUsed (226)
-#
-# - Gem::Net::HTTPRedirection:
-#
-# - Gem::Net::HTTPMultipleChoices (300)
-# - Gem::Net::HTTPMovedPermanently (301)
-# - Gem::Net::HTTPFound (302)
-# - Gem::Net::HTTPSeeOther (303)
-# - Gem::Net::HTTPNotModified (304)
-# - Gem::Net::HTTPUseProxy (305)
-# - Gem::Net::HTTPTemporaryRedirect (307)
-# - Gem::Net::HTTPPermanentRedirect (308)
-#
-# - Gem::Net::HTTPClientError:
-#
-# - Gem::Net::HTTPBadRequest (400)
-# - Gem::Net::HTTPUnauthorized (401)
-# - Gem::Net::HTTPPaymentRequired (402)
-# - Gem::Net::HTTPForbidden (403)
-# - Gem::Net::HTTPNotFound (404)
-# - Gem::Net::HTTPMethodNotAllowed (405)
-# - Gem::Net::HTTPNotAcceptable (406)
-# - Gem::Net::HTTPProxyAuthenticationRequired (407)
-# - Gem::Net::HTTPRequestTimeOut (408)
-# - Gem::Net::HTTPConflict (409)
-# - Gem::Net::HTTPGone (410)
-# - Gem::Net::HTTPLengthRequired (411)
-# - Gem::Net::HTTPPreconditionFailed (412)
-# - Gem::Net::HTTPRequestEntityTooLarge (413)
-# - Gem::Net::HTTPRequestURITooLong (414)
-# - Gem::Net::HTTPUnsupportedMediaType (415)
-# - Gem::Net::HTTPRequestedRangeNotSatisfiable (416)
-# - Gem::Net::HTTPExpectationFailed (417)
-# - Gem::Net::HTTPMisdirectedRequest (421)
-# - Gem::Net::HTTPUnprocessableEntity (422)
-# - Gem::Net::HTTPLocked (423)
-# - Gem::Net::HTTPFailedDependency (424)
-# - Gem::Net::HTTPUpgradeRequired (426)
-# - Gem::Net::HTTPPreconditionRequired (428)
-# - Gem::Net::HTTPTooManyRequests (429)
-# - Gem::Net::HTTPRequestHeaderFieldsTooLarge (431)
-# - Gem::Net::HTTPUnavailableForLegalReasons (451)
-#
-# - Gem::Net::HTTPServerError:
-#
-# - Gem::Net::HTTPInternalServerError (500)
-# - Gem::Net::HTTPNotImplemented (501)
-# - Gem::Net::HTTPBadGateway (502)
-# - Gem::Net::HTTPServiceUnavailable (503)
-# - Gem::Net::HTTPGatewayTimeOut (504)
-# - Gem::Net::HTTPVersionNotSupported (505)
-# - Gem::Net::HTTPVariantAlsoNegotiates (506)
-# - Gem::Net::HTTPInsufficientStorage (507)
-# - Gem::Net::HTTPLoopDetected (508)
-# - Gem::Net::HTTPNotExtended (510)
-# - Gem::Net::HTTPNetworkAuthenticationRequired (511)
-#
-# There is also the Gem::Net::HTTPBadResponse exception which is raised when
-# there is a protocol error.
-#
-class Gem::Net::HTTPResponse
- class << self
- # true if the response has a body.
- def body_permitted?
- self::HAS_BODY
- end
-
- def exception_type # :nodoc: internal use only
- self::EXCEPTION_TYPE
- end
-
- def read_new(sock) #:nodoc: internal use only
- httpv, code, msg = read_status_line(sock)
- res = response_class(code).new(httpv, code, msg)
- each_response_header(sock) do |k,v|
- res.add_field k, v
- end
- res
- end
-
- private
-
- def read_status_line(sock)
- str = sock.readline
- m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)(?:\s+(.*))?\z/in.match(str) or
- raise Gem::Net::HTTPBadResponse, "wrong status line: #{str.dump}"
- m.captures
- end
-
- def response_class(code)
- CODE_TO_OBJ[code] or
- CODE_CLASS_TO_OBJ[code[0,1]] or
- Gem::Net::HTTPUnknownResponse
- end
-
- def each_response_header(sock)
- key = value = nil
- while true
- line = sock.readuntil("\n", true).sub(/\s+\z/, '')
- break if line.empty?
- if line[0] == ?\s or line[0] == ?\t and value
- value << ' ' unless value.empty?
- value << line.strip
- else
- yield key, value if key
- key, value = line.strip.split(/\s*:\s*/, 2)
- raise Gem::Net::HTTPBadResponse, 'wrong header line format' if value.nil?
- end
- end
- yield key, value if key
- end
- end
-
- # next is to fix bug in RDoc, where the private inside class << self
- # spills out.
- public
-
- include Gem::Net::HTTPHeader
-
- def initialize(httpv, code, msg) #:nodoc: internal use only
- @http_version = httpv
- @code = code
- @message = msg
- initialize_http_header nil
- @body = nil
- @read = false
- @uri = nil
- @decode_content = false
- @body_encoding = false
- @ignore_eof = true
- end
-
- # The HTTP version supported by the server.
- attr_reader :http_version
-
- # The HTTP result code string. For example, '302'. You can also
- # determine the response type by examining which response subclass
- # the response object is an instance of.
- attr_reader :code
-
- # The HTTP result message sent by the server. For example, 'Not Found'.
- attr_reader :message
- alias msg message # :nodoc: obsolete
-
- # The Gem::URI used to fetch this response. The response Gem::URI is only available
- # if a Gem::URI was used to create the request.
- attr_reader :uri
-
- # Set to true automatically when the request did not contain an
- # Accept-Encoding header from the user.
- attr_accessor :decode_content
-
- # Returns the value set by body_encoding=, or +false+ if none;
- # see #body_encoding=.
- attr_reader :body_encoding
-
- # Sets the encoding that should be used when reading the body:
- #
- # - If the given value is an Encoding object, that encoding will be used.
- # - Otherwise if the value is a string, the value of
- # {Encoding#find(value)}[https://docs.ruby-lang.org/en/master/Encoding.html#method-c-find]
- # will be used.
- # - Otherwise an encoding will be deduced from the body itself.
- #
- # Examples:
- #
- # http = Gem::Net::HTTP.new(hostname)
- # req = Gem::Net::HTTP::Get.new('/')
- #
- # http.request(req) do |res|
- # p res.body.encoding # => #<Encoding:ASCII-8BIT>
- # end
- #
- # http.request(req) do |res|
- # res.body_encoding = "UTF-8"
- # p res.body.encoding # => #<Encoding:UTF-8>
- # end
- #
- def body_encoding=(value)
- value = Encoding.find(value) if value.is_a?(String)
- @body_encoding = value
- end
-
- # Whether to ignore EOF when reading bodies with a specified Content-Length
- # header.
- attr_accessor :ignore_eof
-
- def inspect
- "#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
- end
-
- #
- # response <-> exception relationship
- #
-
- def code_type #:nodoc:
- self.class
- end
-
- def error! #:nodoc:
- message = @code
- message = "#{message} #{@message.dump}" if @message
- raise error_type().new(message, self)
- end
-
- def error_type #:nodoc:
- self.class::EXCEPTION_TYPE
- end
-
- # Raises an HTTP error if the response is not 2xx (success).
- def value
- error! unless self.kind_of?(Gem::Net::HTTPSuccess)
- end
-
- def uri= uri # :nodoc:
- @uri = uri.dup if uri
- end
-
- #
- # header (for backward compatibility only; DO NOT USE)
- #
-
- def response #:nodoc:
- warn "Gem::Net::HTTPResponse#response is obsolete", uplevel: 1 if $VERBOSE
- self
- end
-
- def header #:nodoc:
- warn "Gem::Net::HTTPResponse#header is obsolete", uplevel: 1 if $VERBOSE
- self
- end
-
- def read_header #:nodoc:
- warn "Gem::Net::HTTPResponse#read_header is obsolete", uplevel: 1 if $VERBOSE
- self
- end
-
- #
- # body
- #
-
- def reading_body(sock, reqmethodallowbody) #:nodoc: internal use only
- @socket = sock
- @body_exist = reqmethodallowbody && self.class.body_permitted?
- begin
- yield
- self.body # ensure to read body
- ensure
- @socket = nil
- end
- end
-
- # Gets the entity body returned by the remote HTTP server.
- #
- # If a block is given, the body is passed to the block, and
- # the body is provided in fragments, as it is read in from the socket.
- #
- # If +dest+ argument is given, response is read into that variable,
- # with <code>dest#<<</code> method (it could be String or IO, or any
- # other object responding to <code><<</code>).
- #
- # Calling this method a second or subsequent time for the same
- # HTTPResponse object will return the value already read.
- #
- # http.request_get('/index.html') {|res|
- # puts res.read_body
- # }
- #
- # http.request_get('/index.html') {|res|
- # p res.read_body.object_id # 538149362
- # p res.read_body.object_id # 538149362
- # }
- #
- # # using iterator
- # http.request_get('/index.html') {|res|
- # res.read_body do |segment|
- # print segment
- # end
- # }
- #
- def read_body(dest = nil, &block)
- if @read
- raise IOError, "#{self.class}\#read_body called twice" if dest or block
- return @body
- end
- to = procdest(dest, block)
- stream_check
- if @body_exist
- read_body_0 to
- @body = to
- else
- @body = nil
- end
- @read = true
- return if @body.nil?
-
- case enc = @body_encoding
- when Encoding, false, nil
- # Encoding: force given encoding
- # false/nil: do not force encoding
- else
- # other value: detect encoding from body
- enc = detect_encoding(@body)
- end
-
- @body.force_encoding(enc) if enc
-
- @body
- end
-
- # Returns the string response body;
- # note that repeated calls for the unmodified body return a cached string:
- #
- # path = '/todos/1'
- # Gem::Net::HTTP.start(hostname) do |http|
- # res = http.get(path)
- # p res.body
- # p http.head(path).body # No body.
- # end
- #
- # Output:
- #
- # "{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n}"
- # nil
- #
- def body
- read_body()
- end
-
- # Sets the body of the response to the given value.
- def body=(value)
- @body = value
- end
-
- alias entity body #:nodoc: obsolete
-
- private
-
- # :nodoc:
- def detect_encoding(str, encoding=nil)
- if encoding
- elsif encoding = type_params['charset']
- elsif encoding = check_bom(str)
- else
- encoding = case content_type&.downcase
- when %r{text/x(?:ht)?ml|application/(?:[^+]+\+)?xml}
- /\A<xml[ \t\r\n]+
- version[ \t\r\n]*=[ \t\r\n]*(?:"[0-9.]+"|'[0-9.]*')[ \t\r\n]+
- encoding[ \t\r\n]*=[ \t\r\n]*
- (?:"([A-Za-z][\-A-Za-z0-9._]*)"|'([A-Za-z][\-A-Za-z0-9._]*)')/x =~ str
- encoding = $1 || $2 || Encoding::UTF_8
- when %r{text/html.*}
- sniff_encoding(str)
- end
- end
- return encoding
- end
-
- # :nodoc:
- def sniff_encoding(str, encoding=nil)
- # the encoding sniffing algorithm
- # http://www.w3.org/TR/html5/parsing.html#determining-the-character-encoding
- if enc = scanning_meta(str)
- enc
- # 6. last visited page or something
- # 7. frequency
- elsif str.ascii_only?
- Encoding::US_ASCII
- elsif str.dup.force_encoding(Encoding::UTF_8).valid_encoding?
- Encoding::UTF_8
- end
- # 8. implementation-defined or user-specified
- end
-
- # :nodoc:
- def check_bom(str)
- case str.byteslice(0, 2)
- when "\xFE\xFF"
- return Encoding::UTF_16BE
- when "\xFF\xFE"
- return Encoding::UTF_16LE
- end
- if "\xEF\xBB\xBF" == str.byteslice(0, 3)
- return Encoding::UTF_8
- end
- nil
- end
-
- # :nodoc:
- def scanning_meta(str)
- require 'strscan'
- ss = StringScanner.new(str)
- if ss.scan_until(/<meta[\t\n\f\r ]*/)
- attrs = {} # attribute_list
- got_pragma = false
- need_pragma = nil
- charset = nil
-
- # step: Attributes
- while attr = get_attribute(ss)
- name, value = *attr
- next if attrs[name]
- attrs[name] = true
- case name
- when 'http-equiv'
- got_pragma = true if value == 'content-type'
- when 'content'
- encoding = extracting_encodings_from_meta_elements(value)
- unless charset
- charset = encoding
- end
- need_pragma = true
- when 'charset'
- need_pragma = false
- charset = value
- end
- end
-
- # step: Processing
- return if need_pragma.nil?
- return if need_pragma && !got_pragma
-
- charset = Encoding.find(charset) rescue nil
- return unless charset
- charset = Encoding::UTF_8 if charset == Encoding::UTF_16
- return charset # tentative
- end
- nil
- end
-
- def get_attribute(ss)
- ss.scan(/[\t\n\f\r \/]*/)
- if ss.peek(1) == '>'
- ss.getch
- return nil
- end
- name = ss.scan(/[^=\t\n\f\r \/>]*/)
- name.downcase!
- raise if name.empty?
- ss.skip(/[\t\n\f\r ]*/)
- if ss.getch != '='
- value = ''
- return [name, value]
- end
- ss.skip(/[\t\n\f\r ]*/)
- case ss.peek(1)
- when '"'
- ss.getch
- value = ss.scan(/[^"]+/)
- value.downcase!
- ss.getch
- when "'"
- ss.getch
- value = ss.scan(/[^']+/)
- value.downcase!
- ss.getch
- when '>'
- value = ''
- else
- value = ss.scan(/[^\t\n\f\r >]+/)
- value.downcase!
- end
- [name, value]
- end
-
- def extracting_encodings_from_meta_elements(value)
- # http://dev.w3.org/html5/spec/fetching-resources.html#algorithm-for-extracting-an-encoding-from-a-meta-element
- if /charset[\t\n\f\r ]*=(?:"([^"]*)"|'([^']*)'|["']|\z|([^\t\n\f\r ;]+))/i =~ value
- return $1 || $2 || $3
- end
- return nil
- end
-
- ##
- # Checks for a supported Content-Encoding header and yields an Inflate
- # wrapper for this response's socket when zlib is present. If the
- # Content-Encoding is not supported or zlib is missing, the plain socket is
- # yielded.
- #
- # If a Content-Range header is present, a plain socket is yielded as the
- # bytes in the range may not be a complete deflate block.
-
- def inflater # :nodoc:
- return yield @socket unless Gem::Net::HTTP::HAVE_ZLIB
- return yield @socket unless @decode_content
- return yield @socket if self['content-range']
-
- v = self['content-encoding']
- case v&.downcase
- when 'deflate', 'gzip', 'x-gzip' then
- self.delete 'content-encoding'
-
- inflate_body_io = Inflater.new(@socket)
-
- begin
- yield inflate_body_io
- success = true
- ensure
- begin
- inflate_body_io.finish
- if self['content-length']
- self['content-length'] = inflate_body_io.bytes_inflated.to_s
- end
- rescue => err
- # Ignore #finish's error if there is an exception from yield
- raise err if success
- end
- end
- when 'none', 'identity' then
- self.delete 'content-encoding'
-
- yield @socket
- else
- yield @socket
- end
- end
-
- def read_body_0(dest)
- inflater do |inflate_body_io|
- if chunked?
- read_chunked dest, inflate_body_io
- return
- end
-
- @socket = inflate_body_io
-
- clen = content_length()
- if clen
- @socket.read clen, dest, @ignore_eof
- return
- end
- clen = range_length()
- if clen
- @socket.read clen, dest
- return
- end
- @socket.read_all dest
- end
- end
-
- ##
- # read_chunked reads from +@socket+ for chunk-size, chunk-extension, CRLF,
- # etc. and +chunk_data_io+ for chunk-data which may be deflate or gzip
- # encoded.
- #
- # See RFC 2616 section 3.6.1 for definitions
-
- def read_chunked(dest, chunk_data_io) # :nodoc:
- total = 0
- while true
- line = @socket.readline
- hexlen = line.slice(/[0-9a-fA-F]+/) or
- raise Gem::Net::HTTPBadResponse, "wrong chunk size line: #{line}"
- len = hexlen.hex
- break if len == 0
- begin
- chunk_data_io.read len, dest
- ensure
- total += len
- @socket.read 2 # \r\n
- end
- end
- until @socket.readline.empty?
- # none
- end
- end
-
- def stream_check
- raise IOError, 'attempt to read body out of block' if @socket.nil? || @socket.closed?
- end
-
- def procdest(dest, block)
- raise ArgumentError, 'both arg and block given for HTTP method' if
- dest and block
- if block
- Gem::Net::ReadAdapter.new(block)
- else
- dest || +''
- end
- end
-
- ##
- # Inflater is a wrapper around Gem::Net::BufferedIO that transparently inflates
- # zlib and gzip streams.
-
- class Inflater # :nodoc:
-
- ##
- # Creates a new Inflater wrapping +socket+
-
- def initialize socket
- @socket = socket
- # zlib with automatic gzip detection
- @inflate = Zlib::Inflate.new(32 + Zlib::MAX_WBITS)
- end
-
- ##
- # Finishes the inflate stream.
-
- def finish
- return if @inflate.total_in == 0
- @inflate.finish
- end
-
- ##
- # The number of bytes inflated, used to update the Content-Length of
- # the response.
-
- def bytes_inflated
- @inflate.total_out
- end
-
- ##
- # Returns a Gem::Net::ReadAdapter that inflates each read chunk into +dest+.
- #
- # This allows a large response body to be inflated without storing the
- # entire body in memory.
-
- def inflate_adapter(dest)
- if dest.respond_to?(:set_encoding)
- dest.set_encoding(Encoding::ASCII_8BIT)
- elsif dest.respond_to?(:force_encoding)
- dest.force_encoding(Encoding::ASCII_8BIT)
- end
- block = proc do |compressed_chunk|
- @inflate.inflate(compressed_chunk) do |chunk|
- compressed_chunk.clear
- dest << chunk
- end
- end
-
- Gem::Net::ReadAdapter.new(block)
- end
-
- ##
- # Reads +clen+ bytes from the socket, inflates them, then writes them to
- # +dest+. +ignore_eof+ is passed down to Gem::Net::BufferedIO#read
- #
- # Unlike Gem::Net::BufferedIO#read, this method returns more than +clen+ bytes.
- # At this time there is no way for a user of Gem::Net::HTTPResponse to read a
- # specific number of bytes from the HTTP response body, so this internal
- # API does not return the same number of bytes as were requested.
- #
- # See https://bugs.ruby-lang.org/issues/6492 for further discussion.
-
- def read clen, dest, ignore_eof = false
- temp_dest = inflate_adapter(dest)
-
- @socket.read clen, temp_dest, ignore_eof
- end
-
- ##
- # Reads the rest of the socket, inflates it, then writes it to +dest+.
-
- def read_all dest
- temp_dest = inflate_adapter(dest)
-
- @socket.read_all temp_dest
- end
-
- end
-
-end
-
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/responses.rb b/lib/rubygems/vendor/net-http/lib/net/http/responses.rb
deleted file mode 100644
index 0f26ae6c26..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/responses.rb
+++ /dev/null
@@ -1,1174 +0,0 @@
-# frozen_string_literal: true
-#--
-# https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
-
-module Gem::Net
-
- class HTTPUnknownResponse < HTTPResponse
- HAS_BODY = true
- EXCEPTION_TYPE = HTTPError #
- end
-
- # Parent class for informational (1xx) HTTP response classes.
- #
- # An informational response indicates that the request was received and understood.
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#status.1xx].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#1xx_informational_response].
- #
- class HTTPInformation < HTTPResponse
- HAS_BODY = false
- EXCEPTION_TYPE = HTTPError #
- end
-
- # Parent class for success (2xx) HTTP response classes.
- #
- # A success response indicates the action requested by the client
- # was received, understood, and accepted.
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#status.2xx].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_success].
- #
- class HTTPSuccess < HTTPResponse
- HAS_BODY = true
- EXCEPTION_TYPE = HTTPError #
- end
-
- # Parent class for redirection (3xx) HTTP response classes.
- #
- # A redirection response indicates the client must take additional action
- # to complete the request.
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#status.3xx].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_redirection].
- #
- class HTTPRedirection < HTTPResponse
- HAS_BODY = true
- EXCEPTION_TYPE = HTTPRetriableError #
- end
-
- # Parent class for client error (4xx) HTTP response classes.
- #
- # A client error response indicates that the client may have caused an error.
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#status.4xx].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_client_errors].
- #
- class HTTPClientError < HTTPResponse
- HAS_BODY = true
- EXCEPTION_TYPE = HTTPClientException #
- end
-
- # Parent class for server error (5xx) HTTP response classes.
- #
- # A server error response indicates that the server failed to fulfill a request.
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#status.5xx].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#5xx_server_errors].
- #
- class HTTPServerError < HTTPResponse
- HAS_BODY = true
- EXCEPTION_TYPE = HTTPFatalError #
- end
-
- # Response class for +Continue+ responses (status code 100).
- #
- # A +Continue+ response indicates that the server has received the request headers.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/100].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-100-continue].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#100].
- #
- class HTTPContinue < HTTPInformation
- HAS_BODY = false
- end
-
- # Response class for <tt>Switching Protocol</tt> responses (status code 101).
- #
- # The <tt>Switching Protocol<tt> response indicates that the server has received
- # a request to switch protocols, and has agreed to do so.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/101].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-101-switching-protocols].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#101].
- #
- class HTTPSwitchProtocol < HTTPInformation
- HAS_BODY = false
- end
-
- # Response class for +Processing+ responses (status code 102).
- #
- # The +Processing+ response indicates that the server has received
- # and is processing the request, but no response is available yet.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 2518}[https://www.rfc-editor.org/rfc/rfc2518#section-10.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#102].
- #
- class HTTPProcessing < HTTPInformation
- HAS_BODY = false
- end
-
- # Response class for <tt>Early Hints</tt> responses (status code 103).
- #
- # The <tt>Early Hints</tt> indicates that the server has received
- # and is processing the request, and contains certain headers;
- # the final response is not available yet.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/103].
- # - {RFC 8297}[https://www.rfc-editor.org/rfc/rfc8297.html#section-2].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#103].
- #
- class HTTPEarlyHints < HTTPInformation
- HAS_BODY = false
- end
-
- # Response class for +OK+ responses (status code 200).
- #
- # The +OK+ response indicates that the server has received
- # a request and has responded successfully.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-200-ok].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#200].
- #
- class HTTPOK < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for +Created+ responses (status code 201).
- #
- # The +Created+ response indicates that the server has received
- # and has fulfilled a request to create a new resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-201-created].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#201].
- #
- class HTTPCreated < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for +Accepted+ responses (status code 202).
- #
- # The +Accepted+ response indicates that the server has received
- # and is processing a request, but the processing has not yet been completed.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/202].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-202-accepted].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#202].
- #
- class HTTPAccepted < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for <tt>Non-Authoritative Information</tt> responses (status code 203).
- #
- # The <tt>Non-Authoritative Information</tt> response indicates that the server
- # is a transforming proxy (such as a Web accelerator)
- # that received a 200 OK response from its origin,
- # and is returning a modified version of the origin's response.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/203].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-203-non-authoritative-infor].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#203].
- #
- class HTTPNonAuthoritativeInformation < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for <tt>No Content</tt> responses (status code 204).
- #
- # The <tt>No Content</tt> response indicates that the server
- # successfully processed the request, and is not returning any content.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-204-no-content].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#204].
- #
- class HTTPNoContent < HTTPSuccess
- HAS_BODY = false
- end
-
- # Response class for <tt>Reset Content</tt> responses (status code 205).
- #
- # The <tt>Reset Content</tt> response indicates that the server
- # successfully processed the request,
- # asks that the client reset its document view, and is not returning any content.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/205].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-205-reset-content].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#205].
- #
- class HTTPResetContent < HTTPSuccess
- HAS_BODY = false
- end
-
- # Response class for <tt>Partial Content</tt> responses (status code 206).
- #
- # The <tt>Partial Content</tt> response indicates that the server is delivering
- # only part of the resource (byte serving)
- # due to a Range header in the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/206].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-206-partial-content].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#206].
- #
- class HTTPPartialContent < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for <tt>Multi-Status (WebDAV)</tt> responses (status code 207).
- #
- # The <tt>Multi-Status (WebDAV)</tt> response indicates that the server
- # has received the request,
- # and that the message body can contain a number of separate response codes.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 4818}[https://www.rfc-editor.org/rfc/rfc4918#section-11.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#207].
- #
- class HTTPMultiStatus < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for <tt>Already Reported (WebDAV)</tt> responses (status code 208).
- #
- # The <tt>Already Reported (WebDAV)</tt> response indicates that the server
- # has received the request,
- # and that the members of a DAV binding have already been enumerated
- # in a preceding part of the (multi-status) response,
- # and are not being included again.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 5842}[https://www.rfc-editor.org/rfc/rfc5842.html#section-7.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#208].
- #
- class HTTPAlreadyReported < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for <tt>IM Used</tt> responses (status code 226).
- #
- # The <tt>IM Used</tt> response indicates that the server has fulfilled a request
- # for the resource, and the response is a representation of the result
- # of one or more instance-manipulations applied to the current instance.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 3229}[https://www.rfc-editor.org/rfc/rfc3229.html#section-10.4.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#226].
- #
- class HTTPIMUsed < HTTPSuccess
- HAS_BODY = true
- end
-
- # Response class for <tt>Multiple Choices</tt> responses (status code 300).
- #
- # The <tt>Multiple Choices</tt> response indicates that the server
- # offers multiple options for the resource from which the client may choose.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/300].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-300-multiple-choices].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#300].
- #
- class HTTPMultipleChoices < HTTPRedirection
- HAS_BODY = true
- end
- HTTPMultipleChoice = HTTPMultipleChoices
-
- # Response class for <tt>Moved Permanently</tt> responses (status code 301).
- #
- # The <tt>Moved Permanently</tt> response indicates that links or records
- # returning this response should be updated to use the given URL.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/301].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-301-moved-permanently].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#301].
- #
- class HTTPMovedPermanently < HTTPRedirection
- HAS_BODY = true
- end
-
- # Response class for <tt>Found</tt> responses (status code 302).
- #
- # The <tt>Found</tt> response indicates that the client
- # should look at (browse to) another URL.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-302-found].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#302].
- #
- class HTTPFound < HTTPRedirection
- HAS_BODY = true
- end
- HTTPMovedTemporarily = HTTPFound
-
- # Response class for <tt>See Other</tt> responses (status code 303).
- #
- # The response to the request can be found under another Gem::URI using the GET method.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/303].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-303-see-other].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#303].
- #
- class HTTPSeeOther < HTTPRedirection
- HAS_BODY = true
- end
-
- # Response class for <tt>Not Modified</tt> responses (status code 304).
- #
- # Indicates that the resource has not been modified since the version
- # specified by the request headers.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/304].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-304-not-modified].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#304].
- #
- class HTTPNotModified < HTTPRedirection
- HAS_BODY = false
- end
-
- # Response class for <tt>Use Proxy</tt> responses (status code 305).
- #
- # The requested resource is available only through a proxy,
- # whose address is provided in the response.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-305-use-proxy].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#305].
- #
- class HTTPUseProxy < HTTPRedirection
- HAS_BODY = false
- end
-
- # Response class for <tt>Temporary Redirect</tt> responses (status code 307).
- #
- # The request should be repeated with another Gem::URI;
- # however, future requests should still use the original Gem::URI.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-307-temporary-redirect].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#307].
- #
- class HTTPTemporaryRedirect < HTTPRedirection
- HAS_BODY = true
- end
-
- # Response class for <tt>Permanent Redirect</tt> responses (status code 308).
- #
- # This and all future requests should be directed to the given Gem::URI.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/308].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-308-permanent-redirect].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#308].
- #
- class HTTPPermanentRedirect < HTTPRedirection
- HAS_BODY = true
- end
-
- # Response class for <tt>Bad Request</tt> responses (status code 400).
- #
- # The server cannot or will not process the request due to an apparent client error.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-400-bad-request].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#400].
- #
- class HTTPBadRequest < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Unauthorized</tt> responses (status code 401).
- #
- # Authentication is required, but either was not provided or failed.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-401-unauthorized].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#401].
- #
- class HTTPUnauthorized < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Payment Required</tt> responses (status code 402).
- #
- # Reserved for future use.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/402].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-402-payment-required].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#402].
- #
- class HTTPPaymentRequired < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Forbidden</tt> responses (status code 403).
- #
- # The request contained valid data and was understood by the server,
- # but the server is refusing action.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-403-forbidden].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#403].
- #
- class HTTPForbidden < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Not Found</tt> responses (status code 404).
- #
- # The requested resource could not be found but may be available in the future.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-404-not-found].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#404].
- #
- class HTTPNotFound < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Method Not Allowed</tt> responses (status code 405).
- #
- # The request method is not supported for the requested resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-405-method-not-allowed].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#405].
- #
- class HTTPMethodNotAllowed < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Not Acceptable</tt> responses (status code 406).
- #
- # The requested resource is capable of generating only content
- # that not acceptable according to the Accept headers sent in the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/406].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-406-not-acceptable].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#406].
- #
- class HTTPNotAcceptable < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Proxy Authentication Required</tt> responses (status code 407).
- #
- # The client must first authenticate itself with the proxy.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/407].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-407-proxy-authentication-re].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#407].
- #
- class HTTPProxyAuthenticationRequired < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Request Gem::Timeout</tt> responses (status code 408).
- #
- # The server timed out waiting for the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-408-request-timeout].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#408].
- #
- class HTTPRequestTimeout < HTTPClientError
- HAS_BODY = true
- end
- HTTPRequestTimeOut = HTTPRequestTimeout
-
- # Response class for <tt>Conflict</tt> responses (status code 409).
- #
- # The request could not be processed because of conflict in the current state of the resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/409].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-409-conflict].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#409].
- #
- class HTTPConflict < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Gone</tt> responses (status code 410).
- #
- # The resource requested was previously in use but is no longer available
- # and will not be available again.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/410].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-410-gone].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#410].
- #
- class HTTPGone < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Length Required</tt> responses (status code 411).
- #
- # The request did not specify the length of its content,
- # which is required by the requested resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/411].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-411-length-required].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#411].
- #
- class HTTPLengthRequired < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Precondition Failed</tt> responses (status code 412).
- #
- # The server does not meet one of the preconditions
- # specified in the request headers.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/412].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-412-precondition-failed].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#412].
- #
- class HTTPPreconditionFailed < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Payload Too Large</tt> responses (status code 413).
- #
- # The request is larger than the server is willing or able to process.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/413].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-413-content-too-large].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#413].
- #
- class HTTPPayloadTooLarge < HTTPClientError
- HAS_BODY = true
- end
- HTTPRequestEntityTooLarge = HTTPPayloadTooLarge
-
- # Response class for <tt>Gem::URI Too Long</tt> responses (status code 414).
- #
- # The Gem::URI provided was too long for the server to process.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/414].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-414-uri-too-long].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#414].
- #
- class HTTPURITooLong < HTTPClientError
- HAS_BODY = true
- end
- HTTPRequestURITooLong = HTTPURITooLong
- HTTPRequestURITooLarge = HTTPRequestURITooLong
-
- # Response class for <tt>Unsupported Media Type</tt> responses (status code 415).
- #
- # The request entity has a media type which the server or resource does not support.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/415].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-415-unsupported-media-type].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#415].
- #
- class HTTPUnsupportedMediaType < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Range Not Satisfiable</tt> responses (status code 416).
- #
- # The request entity has a media type which the server or resource does not support.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/416].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-416-range-not-satisfiable].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#416].
- #
- class HTTPRangeNotSatisfiable < HTTPClientError
- HAS_BODY = true
- end
- HTTPRequestedRangeNotSatisfiable = HTTPRangeNotSatisfiable
-
- # Response class for <tt>Expectation Failed</tt> responses (status code 417).
- #
- # The server cannot meet the requirements of the Expect request-header field.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/417].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-417-expectation-failed].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#417].
- #
- class HTTPExpectationFailed < HTTPClientError
- HAS_BODY = true
- end
-
- # 418 I'm a teapot - RFC 2324; a joke RFC
- # See https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#418.
-
- # 420 Enhance Your Calm - Twitter
-
- # Response class for <tt>Misdirected Request</tt> responses (status code 421).
- #
- # The request was directed at a server that is not able to produce a response.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-421-misdirected-request].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#421].
- #
- class HTTPMisdirectedRequest < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Unprocessable Entity</tt> responses (status code 422).
- #
- # The request was well-formed but had semantic errors.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-422-unprocessable-content].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#422].
- #
- class HTTPUnprocessableEntity < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Locked (WebDAV)</tt> responses (status code 423).
- #
- # The requested resource is locked.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 4918}[https://www.rfc-editor.org/rfc/rfc4918#section-11.3].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#423].
- #
- class HTTPLocked < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Failed Dependency (WebDAV)</tt> responses (status code 424).
- #
- # The request failed because it depended on another request and that request failed.
- # See {424 Failed Dependency (WebDAV)}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#424].
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {RFC 4918}[https://www.rfc-editor.org/rfc/rfc4918#section-11.4].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#424].
- #
- class HTTPFailedDependency < HTTPClientError
- HAS_BODY = true
- end
-
- # 425 Too Early
- # https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#425.
-
- # Response class for <tt>Upgrade Required</tt> responses (status code 426).
- #
- # The client should switch to the protocol given in the Upgrade header field.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/426].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-426-upgrade-required].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#426].
- #
- class HTTPUpgradeRequired < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Precondition Required</tt> responses (status code 428).
- #
- # The origin server requires the request to be conditional.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/428].
- # - {RFC 6585}[https://www.rfc-editor.org/rfc/rfc6585#section-3].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#428].
- #
- class HTTPPreconditionRequired < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Too Many Requests</tt> responses (status code 429).
- #
- # The user has sent too many requests in a given amount of time.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429].
- # - {RFC 6585}[https://www.rfc-editor.org/rfc/rfc6585#section-4].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#429].
- #
- class HTTPTooManyRequests < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Request Header Fields Too Large</tt> responses (status code 431).
- #
- # An individual header field is too large,
- # or all the header fields collectively, are too large.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/431].
- # - {RFC 6585}[https://www.rfc-editor.org/rfc/rfc6585#section-5].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#431].
- #
- class HTTPRequestHeaderFieldsTooLarge < HTTPClientError
- HAS_BODY = true
- end
-
- # Response class for <tt>Unavailable For Legal Reasons</tt> responses (status code 451).
- #
- # A server operator has received a legal demand to deny access to a resource or to a set of resources
- # that includes the requested resource.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/451].
- # - {RFC 7725}[https://www.rfc-editor.org/rfc/rfc7725.html#section-3].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#451].
- #
- class HTTPUnavailableForLegalReasons < HTTPClientError
- HAS_BODY = true
- end
- # 444 No Response - Nginx
- # 449 Retry With - Microsoft
- # 450 Blocked by Windows Parental Controls - Microsoft
- # 499 Client Closed Request - Nginx
-
- # Response class for <tt>Internal Server Error</tt> responses (status code 500).
- #
- # An unexpected condition was encountered and no more specific message is suitable.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-500-internal-server-error].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#500].
- #
- class HTTPInternalServerError < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Not Implemented</tt> responses (status code 501).
- #
- # The server either does not recognize the request method,
- # or it lacks the ability to fulfil the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-501-not-implemented].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#501].
- #
- class HTTPNotImplemented < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Bad Gateway</tt> responses (status code 502).
- #
- # The server was acting as a gateway or proxy
- # and received an invalid response from the upstream server.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/502].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-502-bad-gateway].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#502].
- #
- class HTTPBadGateway < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Service Unavailable</tt> responses (status code 503).
- #
- # The server cannot handle the request
- # (because it is overloaded or down for maintenance).
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/503].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-503-service-unavailable].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#503].
- #
- class HTTPServiceUnavailable < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Gateway Gem::Timeout</tt> responses (status code 504).
- #
- # The server was acting as a gateway or proxy
- # and did not receive a timely response from the upstream server.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-504-gateway-timeout].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#504].
- #
- class HTTPGatewayTimeout < HTTPServerError
- HAS_BODY = true
- end
- HTTPGatewayTimeOut = HTTPGatewayTimeout
-
- # Response class for <tt>HTTP Version Not Supported</tt> responses (status code 505).
- #
- # The server does not support the HTTP version used in the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/505].
- # - {RFC 9110}[https://www.rfc-editor.org/rfc/rfc9110.html#name-505-http-version-not-suppor].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#505].
- #
- class HTTPVersionNotSupported < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Variant Also Negotiates</tt> responses (status code 506).
- #
- # Transparent content negotiation for the request results in a circular reference.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/506].
- # - {RFC 2295}[https://www.rfc-editor.org/rfc/rfc2295#section-8.1].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#506].
- #
- class HTTPVariantAlsoNegotiates < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Insufficient Storage (WebDAV)</tt> responses (status code 507).
- #
- # The server is unable to store the representation needed to complete the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/507].
- # - {RFC 4918}[https://www.rfc-editor.org/rfc/rfc4918#section-11.5].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#507].
- #
- class HTTPInsufficientStorage < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Loop Detected (WebDAV)</tt> responses (status code 508).
- #
- # The server detected an infinite loop while processing the request.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/508].
- # - {RFC 5942}[https://www.rfc-editor.org/rfc/rfc5842.html#section-7.2].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#508].
- #
- class HTTPLoopDetected < HTTPServerError
- HAS_BODY = true
- end
- # 509 Bandwidth Limit Exceeded - Apache bw/limited extension
-
- # Response class for <tt>Not Extended</tt> responses (status code 510).
- #
- # Further extensions to the request are required for the server to fulfill it.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/510].
- # - {RFC 2774}[https://www.rfc-editor.org/rfc/rfc2774.html#section-7].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#510].
- #
- class HTTPNotExtended < HTTPServerError
- HAS_BODY = true
- end
-
- # Response class for <tt>Network Authentication Required</tt> responses (status code 511).
- #
- # The client needs to authenticate to gain network access.
- #
- # :include: doc/net-http/included_getters.rdoc
- #
- # References:
- #
- # - {Mozilla}[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/511].
- # - {RFC 6585}[https://www.rfc-editor.org/rfc/rfc6585#section-6].
- # - {Wikipedia}[https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#511].
- #
- class HTTPNetworkAuthenticationRequired < HTTPServerError
- HAS_BODY = true
- end
-
-end
-
-class Gem::Net::HTTPResponse
- CODE_CLASS_TO_OBJ = {
- '1' => Gem::Net::HTTPInformation,
- '2' => Gem::Net::HTTPSuccess,
- '3' => Gem::Net::HTTPRedirection,
- '4' => Gem::Net::HTTPClientError,
- '5' => Gem::Net::HTTPServerError
- }
- CODE_TO_OBJ = {
- '100' => Gem::Net::HTTPContinue,
- '101' => Gem::Net::HTTPSwitchProtocol,
- '102' => Gem::Net::HTTPProcessing,
- '103' => Gem::Net::HTTPEarlyHints,
-
- '200' => Gem::Net::HTTPOK,
- '201' => Gem::Net::HTTPCreated,
- '202' => Gem::Net::HTTPAccepted,
- '203' => Gem::Net::HTTPNonAuthoritativeInformation,
- '204' => Gem::Net::HTTPNoContent,
- '205' => Gem::Net::HTTPResetContent,
- '206' => Gem::Net::HTTPPartialContent,
- '207' => Gem::Net::HTTPMultiStatus,
- '208' => Gem::Net::HTTPAlreadyReported,
- '226' => Gem::Net::HTTPIMUsed,
-
- '300' => Gem::Net::HTTPMultipleChoices,
- '301' => Gem::Net::HTTPMovedPermanently,
- '302' => Gem::Net::HTTPFound,
- '303' => Gem::Net::HTTPSeeOther,
- '304' => Gem::Net::HTTPNotModified,
- '305' => Gem::Net::HTTPUseProxy,
- '307' => Gem::Net::HTTPTemporaryRedirect,
- '308' => Gem::Net::HTTPPermanentRedirect,
-
- '400' => Gem::Net::HTTPBadRequest,
- '401' => Gem::Net::HTTPUnauthorized,
- '402' => Gem::Net::HTTPPaymentRequired,
- '403' => Gem::Net::HTTPForbidden,
- '404' => Gem::Net::HTTPNotFound,
- '405' => Gem::Net::HTTPMethodNotAllowed,
- '406' => Gem::Net::HTTPNotAcceptable,
- '407' => Gem::Net::HTTPProxyAuthenticationRequired,
- '408' => Gem::Net::HTTPRequestTimeout,
- '409' => Gem::Net::HTTPConflict,
- '410' => Gem::Net::HTTPGone,
- '411' => Gem::Net::HTTPLengthRequired,
- '412' => Gem::Net::HTTPPreconditionFailed,
- '413' => Gem::Net::HTTPPayloadTooLarge,
- '414' => Gem::Net::HTTPURITooLong,
- '415' => Gem::Net::HTTPUnsupportedMediaType,
- '416' => Gem::Net::HTTPRangeNotSatisfiable,
- '417' => Gem::Net::HTTPExpectationFailed,
- '421' => Gem::Net::HTTPMisdirectedRequest,
- '422' => Gem::Net::HTTPUnprocessableEntity,
- '423' => Gem::Net::HTTPLocked,
- '424' => Gem::Net::HTTPFailedDependency,
- '426' => Gem::Net::HTTPUpgradeRequired,
- '428' => Gem::Net::HTTPPreconditionRequired,
- '429' => Gem::Net::HTTPTooManyRequests,
- '431' => Gem::Net::HTTPRequestHeaderFieldsTooLarge,
- '451' => Gem::Net::HTTPUnavailableForLegalReasons,
-
- '500' => Gem::Net::HTTPInternalServerError,
- '501' => Gem::Net::HTTPNotImplemented,
- '502' => Gem::Net::HTTPBadGateway,
- '503' => Gem::Net::HTTPServiceUnavailable,
- '504' => Gem::Net::HTTPGatewayTimeout,
- '505' => Gem::Net::HTTPVersionNotSupported,
- '506' => Gem::Net::HTTPVariantAlsoNegotiates,
- '507' => Gem::Net::HTTPInsufficientStorage,
- '508' => Gem::Net::HTTPLoopDetected,
- '510' => Gem::Net::HTTPNotExtended,
- '511' => Gem::Net::HTTPNetworkAuthenticationRequired,
- }
-end
diff --git a/lib/rubygems/vendor/net-http/lib/net/http/status.rb b/lib/rubygems/vendor/net-http/lib/net/http/status.rb
deleted file mode 100644
index 9110b108b8..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/http/status.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# frozen_string_literal: true
-
-require_relative '../http'
-
-if $0 == __FILE__
- require 'open-uri'
- File.foreach(__FILE__) do |line|
- puts line
- break if line.start_with?('end')
- end
- puts
- puts "Gem::Net::HTTP::STATUS_CODES = {"
- url = "https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv"
- Gem::URI(url).read.each_line do |line|
- code, mes, = line.split(',')
- next if ['(Unused)', 'Unassigned', 'Description'].include?(mes)
- puts " #{code} => '#{mes}',"
- end
- puts "} # :nodoc:"
-end
-
-Gem::Net::HTTP::STATUS_CODES = {
- 100 => 'Continue',
- 101 => 'Switching Protocols',
- 102 => 'Processing',
- 103 => 'Early Hints',
- 200 => 'OK',
- 201 => 'Created',
- 202 => 'Accepted',
- 203 => 'Non-Authoritative Information',
- 204 => 'No Content',
- 205 => 'Reset Content',
- 206 => 'Partial Content',
- 207 => 'Multi-Status',
- 208 => 'Already Reported',
- 226 => 'IM Used',
- 300 => 'Multiple Choices',
- 301 => 'Moved Permanently',
- 302 => 'Found',
- 303 => 'See Other',
- 304 => 'Not Modified',
- 305 => 'Use Proxy',
- 307 => 'Temporary Redirect',
- 308 => 'Permanent Redirect',
- 400 => 'Bad Request',
- 401 => 'Unauthorized',
- 402 => 'Payment Required',
- 403 => 'Forbidden',
- 404 => 'Not Found',
- 405 => 'Method Not Allowed',
- 406 => 'Not Acceptable',
- 407 => 'Proxy Authentication Required',
- 408 => 'Request Timeout',
- 409 => 'Conflict',
- 410 => 'Gone',
- 411 => 'Length Required',
- 412 => 'Precondition Failed',
- 413 => 'Content Too Large',
- 414 => 'URI Too Long',
- 415 => 'Unsupported Media Type',
- 416 => 'Range Not Satisfiable',
- 417 => 'Expectation Failed',
- 421 => 'Misdirected Request',
- 422 => 'Unprocessable Content',
- 423 => 'Locked',
- 424 => 'Failed Dependency',
- 425 => 'Too Early',
- 426 => 'Upgrade Required',
- 428 => 'Precondition Required',
- 429 => 'Too Many Requests',
- 431 => 'Request Header Fields Too Large',
- 451 => 'Unavailable For Legal Reasons',
- 500 => 'Internal Server Error',
- 501 => 'Not Implemented',
- 502 => 'Bad Gateway',
- 503 => 'Service Unavailable',
- 504 => 'Gateway Timeout',
- 505 => 'HTTP Version Not Supported',
- 506 => 'Variant Also Negotiates',
- 507 => 'Insufficient Storage',
- 508 => 'Loop Detected',
- 510 => 'Not Extended (OBSOLETED)',
- 511 => 'Network Authentication Required',
-} # :nodoc:
diff --git a/lib/rubygems/vendor/net-http/lib/net/https.rb b/lib/rubygems/vendor/net-http/lib/net/https.rb
deleted file mode 100644
index f104c85c81..0000000000
--- a/lib/rubygems/vendor/net-http/lib/net/https.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-=begin
-
-= net/https -- SSL/TLS enhancement for Gem::Net::HTTP.
-
- This file has been merged with net/http. There is no longer any need to
- require_relative 'https' to use HTTPS.
-
- See Gem::Net::HTTP for details on how to make HTTPS connections.
-
-== Info
- 'OpenSSL for Ruby 2' project
- Copyright (C) 2001 GOTOU Yuuzou <gotoyuzo@notwork.org>
- All rights reserved.
-
-== Licence
- This program is licensed under the same licence as Ruby.
- (See the file 'LICENCE'.)
-
-=end
-
-require_relative 'http'
-require 'openssl'
diff --git a/lib/rubygems/vendor/net-protocol/.document b/lib/rubygems/vendor/net-protocol/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/net-protocol/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/net-protocol/lib/net/protocol.rb b/lib/rubygems/vendor/net-protocol/lib/net/protocol.rb
deleted file mode 100644
index 53d34d8d98..0000000000
--- a/lib/rubygems/vendor/net-protocol/lib/net/protocol.rb
+++ /dev/null
@@ -1,544 +0,0 @@
-# frozen_string_literal: true
-#
-# = net/protocol.rb
-#
-#--
-# Copyright (c) 1999-2004 Yukihiro Matsumoto
-# Copyright (c) 1999-2004 Minero Aoki
-#
-# written and maintained by Minero Aoki <aamine@loveruby.net>
-#
-# This program is free software. You can re-distribute and/or
-# modify this program under the same terms as Ruby itself,
-# Ruby Distribute License or GNU General Public License.
-#
-# $Id$
-#++
-#
-# WARNING: This file is going to remove.
-# Do not rely on the implementation written in this file.
-#
-
-require 'socket'
-require_relative '../../../timeout/lib/timeout'
-require 'io/wait'
-
-module Gem::Net # :nodoc:
-
- class Protocol #:nodoc: internal use only
- VERSION = "0.2.2"
-
- private
- def Protocol.protocol_param(name, val)
- module_eval(<<-End, __FILE__, __LINE__ + 1)
- def #{name}
- #{val}
- end
- End
- end
-
- def ssl_socket_connect(s, timeout)
- if timeout
- while true
- raise Gem::Net::OpenTimeout if timeout <= 0
- start = Process.clock_gettime Process::CLOCK_MONOTONIC
- # to_io is required because SSLSocket doesn't have wait_readable yet
- case s.connect_nonblock(exception: false)
- when :wait_readable; s.to_io.wait_readable(timeout)
- when :wait_writable; s.to_io.wait_writable(timeout)
- else; break
- end
- timeout -= Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
- end
- else
- s.connect
- end
- end
- end
-
-
- class ProtocolError < StandardError; end
- class ProtoSyntaxError < ProtocolError; end
- class ProtoFatalError < ProtocolError; end
- class ProtoUnknownError < ProtocolError; end
- class ProtoServerError < ProtocolError; end
- class ProtoAuthError < ProtocolError; end
- class ProtoCommandError < ProtocolError; end
- class ProtoRetriableError < ProtocolError; end
- ProtocRetryError = ProtoRetriableError
-
- ##
- # OpenTimeout, a subclass of Gem::Timeout::Error, is raised if a connection cannot
- # be created within the open_timeout.
-
- class OpenTimeout < Gem::Timeout::Error; end
-
- ##
- # ReadTimeout, a subclass of Gem::Timeout::Error, is raised if a chunk of the
- # response cannot be read within the read_timeout.
-
- class ReadTimeout < Gem::Timeout::Error
- def initialize(io = nil)
- @io = io
- end
- attr_reader :io
-
- def message
- msg = super
- if @io
- msg = "#{msg} with #{@io.inspect}"
- end
- msg
- end
- end
-
- ##
- # WriteTimeout, a subclass of Gem::Timeout::Error, is raised if a chunk of the
- # response cannot be written within the write_timeout. Not raised on Windows.
-
- class WriteTimeout < Gem::Timeout::Error
- def initialize(io = nil)
- @io = io
- end
- attr_reader :io
-
- def message
- msg = super
- if @io
- msg = "#{msg} with #{@io.inspect}"
- end
- msg
- end
- end
-
-
- class BufferedIO #:nodoc: internal use only
- def initialize(io, read_timeout: 60, write_timeout: 60, continue_timeout: nil, debug_output: nil)
- @io = io
- @read_timeout = read_timeout
- @write_timeout = write_timeout
- @continue_timeout = continue_timeout
- @debug_output = debug_output
- @rbuf = ''.b
- @rbuf_empty = true
- @rbuf_offset = 0
- end
-
- attr_reader :io
- attr_accessor :read_timeout
- attr_accessor :write_timeout
- attr_accessor :continue_timeout
- attr_accessor :debug_output
-
- def inspect
- "#<#{self.class} io=#{@io}>"
- end
-
- def eof?
- @io.eof?
- end
-
- def closed?
- @io.closed?
- end
-
- def close
- @io.close
- end
-
- #
- # Read
- #
-
- public
-
- def read(len, dest = ''.b, ignore_eof = false)
- LOG "reading #{len} bytes..."
- read_bytes = 0
- begin
- while read_bytes + rbuf_size < len
- if s = rbuf_consume_all
- read_bytes += s.bytesize
- dest << s
- end
- rbuf_fill
- end
- s = rbuf_consume(len - read_bytes)
- read_bytes += s.bytesize
- dest << s
- rescue EOFError
- raise unless ignore_eof
- end
- LOG "read #{read_bytes} bytes"
- dest
- end
-
- def read_all(dest = ''.b)
- LOG 'reading all...'
- read_bytes = 0
- begin
- while true
- if s = rbuf_consume_all
- read_bytes += s.bytesize
- dest << s
- end
- rbuf_fill
- end
- rescue EOFError
- ;
- end
- LOG "read #{read_bytes} bytes"
- dest
- end
-
- def readuntil(terminator, ignore_eof = false)
- offset = @rbuf_offset
- begin
- until idx = @rbuf.index(terminator, offset)
- offset = @rbuf.bytesize
- rbuf_fill
- end
- return rbuf_consume(idx + terminator.bytesize - @rbuf_offset)
- rescue EOFError
- raise unless ignore_eof
- return rbuf_consume
- end
- end
-
- def readline
- readuntil("\n").chop
- end
-
- private
-
- BUFSIZE = 1024 * 16
-
- def rbuf_fill
- tmp = @rbuf_empty ? @rbuf : nil
- case rv = @io.read_nonblock(BUFSIZE, tmp, exception: false)
- when String
- @rbuf_empty = false
- if rv.equal?(tmp)
- @rbuf_offset = 0
- else
- @rbuf << rv
- rv.clear
- end
- return
- when :wait_readable
- (io = @io.to_io).wait_readable(@read_timeout) or raise Gem::Net::ReadTimeout.new(io)
- # continue looping
- when :wait_writable
- # OpenSSL::Buffering#read_nonblock may fail with IO::WaitWritable.
- # http://www.openssl.org/support/faq.html#PROG10
- (io = @io.to_io).wait_writable(@read_timeout) or raise Gem::Net::ReadTimeout.new(io)
- # continue looping
- when nil
- raise EOFError, 'end of file reached'
- end while true
- end
-
- def rbuf_flush
- if @rbuf_empty
- @rbuf.clear
- @rbuf_offset = 0
- end
- nil
- end
-
- def rbuf_size
- @rbuf.bytesize - @rbuf_offset
- end
-
- def rbuf_consume_all
- rbuf_consume if rbuf_size > 0
- end
-
- def rbuf_consume(len = nil)
- if @rbuf_offset == 0 && (len.nil? || len == @rbuf.bytesize)
- s = @rbuf
- @rbuf = ''.b
- @rbuf_offset = 0
- @rbuf_empty = true
- elsif len.nil?
- s = @rbuf.byteslice(@rbuf_offset..-1)
- @rbuf = ''.b
- @rbuf_offset = 0
- @rbuf_empty = true
- else
- s = @rbuf.byteslice(@rbuf_offset, len)
- @rbuf_offset += len
- @rbuf_empty = @rbuf_offset == @rbuf.bytesize
- rbuf_flush
- end
-
- @debug_output << %Q[-> #{s.dump}\n] if @debug_output
- s
- end
-
- #
- # Write
- #
-
- public
-
- def write(*strs)
- writing {
- write0(*strs)
- }
- end
-
- alias << write
-
- def writeline(str)
- writing {
- write0 str + "\r\n"
- }
- end
-
- private
-
- def writing
- @written_bytes = 0
- @debug_output << '<- ' if @debug_output
- yield
- @debug_output << "\n" if @debug_output
- bytes = @written_bytes
- @written_bytes = nil
- bytes
- end
-
- def write0(*strs)
- @debug_output << strs.map(&:dump).join if @debug_output
- orig_written_bytes = @written_bytes
- strs.each_with_index do |str, i|
- need_retry = true
- case len = @io.write_nonblock(str, exception: false)
- when Integer
- @written_bytes += len
- len -= str.bytesize
- if len == 0
- if strs.size == i+1
- return @written_bytes - orig_written_bytes
- else
- need_retry = false
- # next string
- end
- elsif len < 0
- str = str.byteslice(len, -len)
- else # len > 0
- need_retry = false
- # next string
- end
- # continue looping
- when :wait_writable
- (io = @io.to_io).wait_writable(@write_timeout) or raise Gem::Net::WriteTimeout.new(io)
- # continue looping
- end while need_retry
- end
- end
-
- #
- # Logging
- #
-
- private
-
- def LOG_off
- @save_debug_out = @debug_output
- @debug_output = nil
- end
-
- def LOG_on
- @debug_output = @save_debug_out
- end
-
- def LOG(msg)
- return unless @debug_output
- @debug_output << msg + "\n"
- end
- end
-
-
- class InternetMessageIO < BufferedIO #:nodoc: internal use only
- def initialize(*, **)
- super
- @wbuf = nil
- end
-
- #
- # Read
- #
-
- def each_message_chunk
- LOG 'reading message...'
- LOG_off()
- read_bytes = 0
- while (line = readuntil("\r\n")) != ".\r\n"
- read_bytes += line.size
- yield line.delete_prefix('.')
- end
- LOG_on()
- LOG "read message (#{read_bytes} bytes)"
- end
-
- # *library private* (cannot handle 'break')
- def each_list_item
- while (str = readuntil("\r\n")) != ".\r\n"
- yield str.chop
- end
- end
-
- def write_message_0(src)
- prev = @written_bytes
- each_crlf_line(src) do |line|
- write0 dot_stuff(line)
- end
- @written_bytes - prev
- end
-
- #
- # Write
- #
-
- def write_message(src)
- LOG "writing message from #{src.class}"
- LOG_off()
- len = writing {
- using_each_crlf_line {
- write_message_0 src
- }
- }
- LOG_on()
- LOG "wrote #{len} bytes"
- len
- end
-
- def write_message_by_block(&block)
- LOG 'writing message from block'
- LOG_off()
- len = writing {
- using_each_crlf_line {
- begin
- block.call(WriteAdapter.new(self.method(:write_message_0)))
- rescue LocalJumpError
- # allow `break' from writer block
- end
- }
- }
- LOG_on()
- LOG "wrote #{len} bytes"
- len
- end
-
- private
-
- def dot_stuff(s)
- s.sub(/\A\./, '..')
- end
-
- def using_each_crlf_line
- @wbuf = ''.b
- yield
- if not @wbuf.empty? # unterminated last line
- write0 dot_stuff(@wbuf.chomp) + "\r\n"
- elsif @written_bytes == 0 # empty src
- write0 "\r\n"
- end
- write0 ".\r\n"
- @wbuf = nil
- end
-
- def each_crlf_line(src)
- buffer_filling(@wbuf, src) do
- while line = @wbuf.slice!(/\A[^\r\n]*(?:\n|\r(?:\n|(?!\z)))/)
- yield line.chomp("\n") + "\r\n"
- end
- end
- end
-
- def buffer_filling(buf, src)
- case src
- when String # for speeding up.
- 0.step(src.size - 1, 1024) do |i|
- buf << src[i, 1024]
- yield
- end
- when File # for speeding up.
- while s = src.read(1024)
- buf << s
- yield
- end
- else # generic reader
- src.each do |str|
- buf << str
- yield if buf.size > 1024
- end
- yield unless buf.empty?
- end
- end
- end
-
-
- #
- # The writer adapter class
- #
- class WriteAdapter
- def initialize(writer)
- @writer = writer
- end
-
- def inspect
- "#<#{self.class} writer=#{@writer.inspect}>"
- end
-
- def write(str)
- @writer.call(str)
- end
-
- alias print write
-
- def <<(str)
- write str
- self
- end
-
- def puts(str = '')
- write str.chomp("\n") + "\n"
- end
-
- def printf(*args)
- write sprintf(*args)
- end
- end
-
-
- class ReadAdapter #:nodoc: internal use only
- def initialize(block)
- @block = block
- end
-
- def inspect
- "#<#{self.class}>"
- end
-
- def <<(str)
- call_block(str, &@block) if @block
- end
-
- private
-
- # This method is needed because @block must be called by yield,
- # not Proc#call. You can see difference when using `break' in
- # the block.
- def call_block(str)
- yield str
- end
- end
-
-
- module NetPrivate #:nodoc: obsolete
- Socket = ::Gem::Net::InternetMessageIO
- end
-
-end # module Gem::Net
diff --git a/lib/rubygems/vendor/optparse/.document b/lib/rubygems/vendor/optparse/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/optparse/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/optparse/lib/optparse.rb b/lib/rubygems/vendor/optparse/lib/optparse.rb
deleted file mode 100644
index 00dc7c8a67..0000000000
--- a/lib/rubygems/vendor/optparse/lib/optparse.rb
+++ /dev/null
@@ -1,2330 +0,0 @@
-# frozen_string_literal: true
-#
-# optparse.rb - command-line option analysis with the Gem::OptionParser class.
-#
-# Author:: Nobu Nakada
-# Documentation:: Nobu Nakada and Gavin Sinclair.
-#
-# See Gem::OptionParser for documentation.
-#
-
-
-#--
-# == Developer Documentation (not for RDoc output)
-#
-# === Class tree
-#
-# - Gem::OptionParser:: front end
-# - Gem::OptionParser::Switch:: each switches
-# - Gem::OptionParser::List:: options list
-# - Gem::OptionParser::ParseError:: errors on parsing
-# - Gem::OptionParser::AmbiguousOption
-# - Gem::OptionParser::NeedlessArgument
-# - Gem::OptionParser::MissingArgument
-# - Gem::OptionParser::InvalidOption
-# - Gem::OptionParser::InvalidArgument
-# - Gem::OptionParser::AmbiguousArgument
-#
-# === Object relationship diagram
-#
-# +--------------+
-# | Gem::OptionParser |<>-----+
-# +--------------+ | +--------+
-# | ,-| Switch |
-# on_head -------->+---------------+ / +--------+
-# accept/reject -->| List |<|>-
-# | |<|>- +----------+
-# on ------------->+---------------+ `-| argument |
-# : : | class |
-# +---------------+ |==========|
-# on_tail -------->| | |pattern |
-# +---------------+ |----------|
-# Gem::OptionParser.accept ->| DefaultList | |converter |
-# reject |(shared between| +----------+
-# | all instances)|
-# +---------------+
-#
-#++
-#
-# == Gem::OptionParser
-#
-# === New to +Gem::OptionParser+?
-#
-# See the {Tutorial}[optparse/tutorial.rdoc].
-#
-# === Introduction
-#
-# Gem::OptionParser is a class for command-line option analysis. It is much more
-# advanced, yet also easier to use, than GetoptLong, and is a more Ruby-oriented
-# solution.
-#
-# === Features
-#
-# 1. The argument specification and the code to handle it are written in the
-# same place.
-# 2. It can output an option summary; you don't need to maintain this string
-# separately.
-# 3. Optional and mandatory arguments are specified very gracefully.
-# 4. Arguments can be automatically converted to a specified class.
-# 5. Arguments can be restricted to a certain set.
-#
-# All of these features are demonstrated in the examples below. See
-# #make_switch for full documentation.
-#
-# === Minimal example
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-#
-# options = {}
-# Gem::OptionParser.new do |parser|
-# parser.banner = "Usage: example.rb [options]"
-#
-# parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
-# options[:verbose] = v
-# end
-# end.parse!
-#
-# p options
-# p ARGV
-#
-# === Generating Help
-#
-# Gem::OptionParser can be used to automatically generate help for the commands you
-# write:
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-#
-# Options = Struct.new(:name)
-#
-# class Parser
-# def self.parse(options)
-# args = Options.new("world")
-#
-# opt_parser = Gem::OptionParser.new do |parser|
-# parser.banner = "Usage: example.rb [options]"
-#
-# parser.on("-nNAME", "--name=NAME", "Name to say hello to") do |n|
-# args.name = n
-# end
-#
-# parser.on("-h", "--help", "Prints this help") do
-# puts parser
-# exit
-# end
-# end
-#
-# opt_parser.parse!(options)
-# return args
-# end
-# end
-# options = Parser.parse %w[--help]
-#
-# #=>
-# # Usage: example.rb [options]
-# # -n, --name=NAME Name to say hello to
-# # -h, --help Prints this help
-#
-# === Required Arguments
-#
-# For options that require an argument, option specification strings may include an
-# option name in all caps. If an option is used without the required argument,
-# an exception will be raised.
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-#
-# options = {}
-# Gem::OptionParser.new do |parser|
-# parser.on("-r", "--require LIBRARY",
-# "Require the LIBRARY before executing your script") do |lib|
-# puts "You required #{lib}!"
-# end
-# end.parse!
-#
-# Used:
-#
-# $ ruby optparse-test.rb -r
-# optparse-test.rb:9:in `<main>': missing argument: -r (Gem::OptionParser::MissingArgument)
-# $ ruby optparse-test.rb -r my-library
-# You required my-library!
-#
-# === Type Coercion
-#
-# Gem::OptionParser supports the ability to coerce command line arguments
-# into objects for us.
-#
-# Gem::OptionParser comes with a few ready-to-use kinds of type
-# coercion. They are:
-#
-# - Date -- Anything accepted by +Date.parse+ (need to require +optparse/date+)
-# - DateTime -- Anything accepted by +DateTime.parse+ (need to require +optparse/date+)
-# - Time -- Anything accepted by +Time.httpdate+ or +Time.parse+ (need to require +optparse/time+)
-# - URI -- Anything accepted by +Gem::URI.parse+ (need to require +optparse/uri+)
-# - Shellwords -- Anything accepted by +Shellwords.shellwords+ (need to require +optparse/shellwords+)
-# - String -- Any non-empty string
-# - Integer -- Any integer. Will convert octal. (e.g. 124, -3, 040)
-# - Float -- Any float. (e.g. 10, 3.14, -100E+13)
-# - Numeric -- Any integer, float, or rational (1, 3.4, 1/3)
-# - DecimalInteger -- Like +Integer+, but no octal format.
-# - OctalInteger -- Like +Integer+, but no decimal format.
-# - DecimalNumeric -- Decimal integer or float.
-# - TrueClass -- Accepts '+, yes, true, -, no, false' and
-# defaults as +true+
-# - FalseClass -- Same as +TrueClass+, but defaults to +false+
-# - Array -- Strings separated by ',' (e.g. 1,2,3)
-# - Regexp -- Regular expressions. Also includes options.
-#
-# We can also add our own coercions, which we will cover below.
-#
-# ==== Using Built-in Conversions
-#
-# As an example, the built-in +Time+ conversion is used. The other built-in
-# conversions behave in the same way.
-# Gem::OptionParser will attempt to parse the argument
-# as a +Time+. If it succeeds, that time will be passed to the
-# handler block. Otherwise, an exception will be raised.
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-# require 'rubygems/vendor/optparse/lib/optparse/time'
-# Gem::OptionParser.new do |parser|
-# parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
-# p time
-# end
-# end.parse!
-#
-# Used:
-#
-# $ ruby optparse-test.rb -t nonsense
-# ... invalid argument: -t nonsense (Gem::OptionParser::InvalidArgument)
-# $ ruby optparse-test.rb -t 10-11-12
-# 2010-11-12 00:00:00 -0500
-# $ ruby optparse-test.rb -t 9:30
-# 2014-08-13 09:30:00 -0400
-#
-# ==== Creating Custom Conversions
-#
-# The +accept+ method on Gem::OptionParser may be used to create converters.
-# It specifies which conversion block to call whenever a class is specified.
-# The example below uses it to fetch a +User+ object before the +on+ handler receives it.
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-#
-# User = Struct.new(:id, :name)
-#
-# def find_user id
-# not_found = ->{ raise "No User Found for id #{id}" }
-# [ User.new(1, "Sam"),
-# User.new(2, "Gandalf") ].find(not_found) do |u|
-# u.id == id
-# end
-# end
-#
-# op = Gem::OptionParser.new
-# op.accept(User) do |user_id|
-# find_user user_id.to_i
-# end
-#
-# op.on("--user ID", User) do |user|
-# puts user
-# end
-#
-# op.parse!
-#
-# Used:
-#
-# $ ruby optparse-test.rb --user 1
-# #<struct User id=1, name="Sam">
-# $ ruby optparse-test.rb --user 2
-# #<struct User id=2, name="Gandalf">
-# $ ruby optparse-test.rb --user 3
-# optparse-test.rb:15:in `block in find_user': No User Found for id 3 (RuntimeError)
-#
-# === Store options to a Hash
-#
-# The +into+ option of +order+, +parse+ and so on methods stores command line options into a Hash.
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-#
-# options = {}
-# Gem::OptionParser.new do |parser|
-# parser.on('-a')
-# parser.on('-b NUM', Integer)
-# parser.on('-v', '--verbose')
-# end.parse!(into: options)
-#
-# p options
-#
-# Used:
-#
-# $ ruby optparse-test.rb -a
-# {:a=>true}
-# $ ruby optparse-test.rb -a -v
-# {:a=>true, :verbose=>true}
-# $ ruby optparse-test.rb -a -b 100
-# {:a=>true, :b=>100}
-#
-# === Complete example
-#
-# The following example is a complete Ruby program. You can run it and see the
-# effect of specifying various options. This is probably the best way to learn
-# the features of +optparse+.
-#
-# require 'rubygems/vendor/optparse/lib/optparse'
-# require 'rubygems/vendor/optparse/lib/optparse/time'
-# require 'ostruct'
-# require 'pp'
-#
-# class OptparseExample
-# Version = '1.0.0'
-#
-# CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
-# CODE_ALIASES = { "jis" => "iso-2022-jp", "sjis" => "shift_jis" }
-#
-# class ScriptOptions
-# attr_accessor :library, :inplace, :encoding, :transfer_type,
-# :verbose, :extension, :delay, :time, :record_separator,
-# :list
-#
-# def initialize
-# self.library = []
-# self.inplace = false
-# self.encoding = "utf8"
-# self.transfer_type = :auto
-# self.verbose = false
-# end
-#
-# def define_options(parser)
-# parser.banner = "Usage: example.rb [options]"
-# parser.separator ""
-# parser.separator "Specific options:"
-#
-# # add additional options
-# perform_inplace_option(parser)
-# delay_execution_option(parser)
-# execute_at_time_option(parser)
-# specify_record_separator_option(parser)
-# list_example_option(parser)
-# specify_encoding_option(parser)
-# optional_option_argument_with_keyword_completion_option(parser)
-# boolean_verbose_option(parser)
-#
-# parser.separator ""
-# parser.separator "Common options:"
-# # No argument, shows at tail. This will print an options summary.
-# # Try it and see!
-# parser.on_tail("-h", "--help", "Show this message") do
-# puts parser
-# exit
-# end
-# # Another typical switch to print the version.
-# parser.on_tail("--version", "Show version") do
-# puts Version
-# exit
-# end
-# end
-#
-# def perform_inplace_option(parser)
-# # Specifies an optional option argument
-# parser.on("-i", "--inplace [EXTENSION]",
-# "Edit ARGV files in place",
-# "(make backup if EXTENSION supplied)") do |ext|
-# self.inplace = true
-# self.extension = ext || ''
-# self.extension.sub!(/\A\.?(?=.)/, ".") # Ensure extension begins with dot.
-# end
-# end
-#
-# def delay_execution_option(parser)
-# # Cast 'delay' argument to a Float.
-# parser.on("--delay N", Float, "Delay N seconds before executing") do |n|
-# self.delay = n
-# end
-# end
-#
-# def execute_at_time_option(parser)
-# # Cast 'time' argument to a Time object.
-# parser.on("-t", "--time [TIME]", Time, "Begin execution at given time") do |time|
-# self.time = time
-# end
-# end
-#
-# def specify_record_separator_option(parser)
-# # Cast to octal integer.
-# parser.on("-F", "--irs [OCTAL]", Gem::OptionParser::OctalInteger,
-# "Specify record separator (default \\0)") do |rs|
-# self.record_separator = rs
-# end
-# end
-#
-# def list_example_option(parser)
-# # List of arguments.
-# parser.on("--list x,y,z", Array, "Example 'list' of arguments") do |list|
-# self.list = list
-# end
-# end
-#
-# def specify_encoding_option(parser)
-# # Keyword completion. We are specifying a specific set of arguments (CODES
-# # and CODE_ALIASES - notice the latter is a Hash), and the user may provide
-# # the shortest unambiguous text.
-# code_list = (CODE_ALIASES.keys + CODES).join(', ')
-# parser.on("--code CODE", CODES, CODE_ALIASES, "Select encoding",
-# "(#{code_list})") do |encoding|
-# self.encoding = encoding
-# end
-# end
-#
-# def optional_option_argument_with_keyword_completion_option(parser)
-# # Optional '--type' option argument with keyword completion.
-# parser.on("--type [TYPE]", [:text, :binary, :auto],
-# "Select transfer type (text, binary, auto)") do |t|
-# self.transfer_type = t
-# end
-# end
-#
-# def boolean_verbose_option(parser)
-# # Boolean switch.
-# parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
-# self.verbose = v
-# end
-# end
-# end
-#
-# #
-# # Return a structure describing the options.
-# #
-# def parse(args)
-# # The options specified on the command line will be collected in
-# # *options*.
-#
-# @options = ScriptOptions.new
-# @args = Gem::OptionParser.new do |parser|
-# @options.define_options(parser)
-# parser.parse!(args)
-# end
-# @options
-# end
-#
-# attr_reader :parser, :options
-# end # class OptparseExample
-#
-# example = OptparseExample.new
-# options = example.parse(ARGV)
-# pp options # example.options
-# pp ARGV
-#
-# === Shell Completion
-#
-# For modern shells (e.g. bash, zsh, etc.), you can use shell
-# completion for command line options.
-#
-# === Further documentation
-#
-# The above examples, along with the accompanying
-# {Tutorial}[optparse/tutorial.rdoc],
-# should be enough to learn how to use this class.
-# If you have any questions, file a ticket at http://bugs.ruby-lang.org.
-#
-class Gem::OptionParser
- Gem::OptionParser::Version = "0.4.0"
-
- # :stopdoc:
- NoArgument = [NO_ARGUMENT = :NONE, nil].freeze
- RequiredArgument = [REQUIRED_ARGUMENT = :REQUIRED, true].freeze
- OptionalArgument = [OPTIONAL_ARGUMENT = :OPTIONAL, false].freeze
- # :startdoc:
-
- #
- # Keyword completion module. This allows partial arguments to be specified
- # and resolved against a list of acceptable values.
- #
- module Completion
- def self.regexp(key, icase)
- Regexp.new('\A' + Regexp.quote(key).gsub(/\w+\b/, '\&\w*'), icase)
- end
-
- def self.candidate(key, icase = false, pat = nil, &block)
- pat ||= Completion.regexp(key, icase)
- candidates = []
- block.call do |k, *v|
- (if Regexp === k
- kn = ""
- k === key
- else
- kn = defined?(k.id2name) ? k.id2name : k
- pat === kn
- end) or next
- v << k if v.empty?
- candidates << [k, v, kn]
- end
- candidates
- end
-
- def candidate(key, icase = false, pat = nil)
- Completion.candidate(key, icase, pat, &method(:each))
- end
-
- public
- def complete(key, icase = false, pat = nil)
- candidates = candidate(key, icase, pat, &method(:each)).sort_by {|k, v, kn| kn.size}
- if candidates.size == 1
- canon, sw, * = candidates[0]
- elsif candidates.size > 1
- canon, sw, cn = candidates.shift
- candidates.each do |k, v, kn|
- next if sw == v
- if String === cn and String === kn
- if cn.rindex(kn, 0)
- canon, sw, cn = k, v, kn
- next
- elsif kn.rindex(cn, 0)
- next
- end
- end
- throw :ambiguous, key
- end
- end
- if canon
- block_given? or return key, *sw
- yield(key, *sw)
- end
- end
-
- def convert(opt = nil, val = nil, *)
- val
- end
- end
-
-
- #
- # Map from option/keyword string to object with completion.
- #
- class OptionMap < Hash
- include Completion
- end
-
-
- #
- # Individual switch class. Not important to the user.
- #
- # Defined within Switch are several Switch-derived classes: NoArgument,
- # RequiredArgument, etc.
- #
- class Switch
- attr_reader :pattern, :conv, :short, :long, :arg, :desc, :block
-
- #
- # Guesses argument style from +arg+. Returns corresponding
- # Gem::OptionParser::Switch class (OptionalArgument, etc.).
- #
- def self.guess(arg)
- case arg
- when ""
- t = self
- when /\A=?\[/
- t = Switch::OptionalArgument
- when /\A\s+\[/
- t = Switch::PlacedArgument
- else
- t = Switch::RequiredArgument
- end
- self >= t or incompatible_argument_styles(arg, t)
- t
- end
-
- def self.incompatible_argument_styles(arg, t)
- raise(ArgumentError, "#{arg}: incompatible argument styles\n #{self}, #{t}",
- ParseError.filter_backtrace(caller(2)))
- end
-
- def self.pattern
- NilClass
- end
-
- def initialize(pattern = nil, conv = nil,
- short = nil, long = nil, arg = nil,
- desc = ([] if short or long), block = nil, &_block)
- raise if Array === pattern
- block ||= _block
- @pattern, @conv, @short, @long, @arg, @desc, @block =
- pattern, conv, short, long, arg, desc, block
- end
-
- #
- # Parses +arg+ and returns rest of +arg+ and matched portion to the
- # argument pattern. Yields when the pattern doesn't match substring.
- #
- def parse_arg(arg) # :nodoc:
- pattern or return nil, [arg]
- unless m = pattern.match(arg)
- yield(InvalidArgument, arg)
- return arg, []
- end
- if String === m
- m = [s = m]
- else
- m = m.to_a
- s = m[0]
- return nil, m unless String === s
- end
- raise InvalidArgument, arg unless arg.rindex(s, 0)
- return nil, m if s.length == arg.length
- yield(InvalidArgument, arg) # didn't match whole arg
- return arg[s.length..-1], m
- end
- private :parse_arg
-
- #
- # Parses argument, converts and returns +arg+, +block+ and result of
- # conversion. Yields at semi-error condition instead of raising an
- # exception.
- #
- def conv_arg(arg, val = []) # :nodoc:
- if conv
- val = conv.call(*val)
- else
- val = proc {|v| v}.call(*val)
- end
- return arg, block, val
- end
- private :conv_arg
-
- #
- # Produces the summary text. Each line of the summary is yielded to the
- # block (without newline).
- #
- # +sdone+:: Already summarized short style options keyed hash.
- # +ldone+:: Already summarized long style options keyed hash.
- # +width+:: Width of left side (option part). In other words, the right
- # side (description part) starts after +width+ columns.
- # +max+:: Maximum width of left side -> the options are filled within
- # +max+ columns.
- # +indent+:: Prefix string indents all summarized lines.
- #
- def summarize(sdone = {}, ldone = {}, width = 1, max = width - 1, indent = "")
- sopts, lopts = [], [], nil
- @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
- @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
- return if sopts.empty? and lopts.empty? # completely hidden
-
- left = [sopts.join(', ')]
- right = desc.dup
-
- while s = lopts.shift
- l = left[-1].length + s.length
- l += arg.length if left.size == 1 && arg
- l < max or sopts.empty? or left << +''
- left[-1] << (left[-1].empty? ? ' ' * 4 : ', ') << s
- end
-
- if arg
- left[0] << (left[1] ? arg.sub(/\A(\[?)=/, '\1') + ',' : arg)
- end
- mlen = left.collect {|ss| ss.length}.max.to_i
- while mlen > width and l = left.shift
- mlen = left.collect {|ss| ss.length}.max.to_i if l.length == mlen
- if l.length < width and (r = right[0]) and !r.empty?
- l = l.to_s.ljust(width) + ' ' + r
- right.shift
- end
- yield(indent + l)
- end
-
- while begin l = left.shift; r = right.shift; l or r end
- l = l.to_s.ljust(width) + ' ' + r if r and !r.empty?
- yield(indent + l)
- end
-
- self
- end
-
- def add_banner(to) # :nodoc:
- unless @short or @long
- s = desc.join
- to << " [" + s + "]..." unless s.empty?
- end
- to
- end
-
- def match_nonswitch?(str) # :nodoc:
- @pattern =~ str unless @short or @long
- end
-
- #
- # Main name of the switch.
- #
- def switch_name
- (long.first || short.first).sub(/\A-+(?:\[no-\])?/, '')
- end
-
- def compsys(sdone, ldone) # :nodoc:
- sopts, lopts = [], []
- @short.each {|s| sdone.fetch(s) {sopts << s}; sdone[s] = true} if @short
- @long.each {|s| ldone.fetch(s) {lopts << s}; ldone[s] = true} if @long
- return if sopts.empty? and lopts.empty? # completely hidden
-
- (sopts+lopts).each do |opt|
- # "(-x -c -r)-l[left justify]"
- if /^--\[no-\](.+)$/ =~ opt
- o = $1
- yield("--#{o}", desc.join(""))
- yield("--no-#{o}", desc.join(""))
- else
- yield("#{opt}", desc.join(""))
- end
- end
- end
-
- def pretty_print_contents(q) # :nodoc:
- if @block
- q.text ":" + @block.source_location.join(":") + ":"
- first = false
- else
- first = true
- end
- [@short, @long].each do |list|
- list.each do |opt|
- if first
- q.text ":"
- first = false
- end
- q.breakable
- q.text opt
- end
- end
- end
-
- def pretty_print(q) # :nodoc:
- q.object_group(self) {pretty_print_contents(q)}
- end
-
- #
- # Switch that takes no arguments.
- #
- class NoArgument < self
-
- #
- # Raises an exception if any arguments given.
- #
- def parse(arg, argv)
- yield(NeedlessArgument, arg) if arg
- conv_arg(arg)
- end
-
- def self.incompatible_argument_styles(*)
- end
-
- def self.pattern
- Object
- end
-
- def pretty_head # :nodoc:
- "NoArgument"
- end
- end
-
- #
- # Switch that takes an argument.
- #
- class RequiredArgument < self
-
- #
- # Raises an exception if argument is not present.
- #
- def parse(arg, argv)
- unless arg
- raise MissingArgument if argv.empty?
- arg = argv.shift
- end
- conv_arg(*parse_arg(arg, &method(:raise)))
- end
-
- def pretty_head # :nodoc:
- "Required"
- end
- end
-
- #
- # Switch that can omit argument.
- #
- class OptionalArgument < self
-
- #
- # Parses argument if given, or uses default value.
- #
- def parse(arg, argv, &error)
- if arg
- conv_arg(*parse_arg(arg, &error))
- else
- conv_arg(arg)
- end
- end
-
- def pretty_head # :nodoc:
- "Optional"
- end
- end
-
- #
- # Switch that takes an argument, which does not begin with '-' or is '-'.
- #
- class PlacedArgument < self
-
- #
- # Returns nil if argument is not present or begins with '-' and is not '-'.
- #
- def parse(arg, argv, &error)
- if !(val = arg) and (argv.empty? or /\A-./ =~ (val = argv[0]))
- return nil, block, nil
- end
- opt = (val = parse_arg(val, &error))[1]
- val = conv_arg(*val)
- if opt and !arg
- argv.shift
- else
- val[0] = nil
- end
- val
- end
-
- def pretty_head # :nodoc:
- "Placed"
- end
- end
- end
-
- #
- # Simple option list providing mapping from short and/or long option
- # string to Gem::OptionParser::Switch and mapping from acceptable argument to
- # matching pattern and converter pair. Also provides summary feature.
- #
- class List
- # Map from acceptable argument types to pattern and converter pairs.
- attr_reader :atype
-
- # Map from short style option switches to actual switch objects.
- attr_reader :short
-
- # Map from long style option switches to actual switch objects.
- attr_reader :long
-
- # List of all switches and summary string.
- attr_reader :list
-
- #
- # Just initializes all instance variables.
- #
- def initialize
- @atype = {}
- @short = OptionMap.new
- @long = OptionMap.new
- @list = []
- end
-
- def pretty_print(q) # :nodoc:
- q.group(1, "(", ")") do
- @list.each do |sw|
- next unless Switch === sw
- q.group(1, "(" + sw.pretty_head, ")") do
- sw.pretty_print_contents(q)
- end
- end
- end
- end
-
- #
- # See Gem::OptionParser.accept.
- #
- def accept(t, pat = /.*/m, &block)
- if pat
- pat.respond_to?(:match) or
- raise TypeError, "has no `match'", ParseError.filter_backtrace(caller(2))
- else
- pat = t if t.respond_to?(:match)
- end
- unless block
- block = pat.method(:convert).to_proc if pat.respond_to?(:convert)
- end
- @atype[t] = [pat, block]
- end
-
- #
- # See Gem::OptionParser.reject.
- #
- def reject(t)
- @atype.delete(t)
- end
-
- #
- # Adds +sw+ according to +sopts+, +lopts+ and +nlopts+.
- #
- # +sw+:: Gem::OptionParser::Switch instance to be added.
- # +sopts+:: Short style option list.
- # +lopts+:: Long style option list.
- # +nlopts+:: Negated long style options list.
- #
- def update(sw, sopts, lopts, nsw = nil, nlopts = nil) # :nodoc:
- sopts.each {|o| @short[o] = sw} if sopts
- lopts.each {|o| @long[o] = sw} if lopts
- nlopts.each {|o| @long[o] = nsw} if nsw and nlopts
- used = @short.invert.update(@long.invert)
- @list.delete_if {|o| Switch === o and !used[o]}
- end
- private :update
-
- #
- # Inserts +switch+ at the head of the list, and associates short, long
- # and negated long options. Arguments are:
- #
- # +switch+:: Gem::OptionParser::Switch instance to be inserted.
- # +short_opts+:: List of short style options.
- # +long_opts+:: List of long style options.
- # +nolong_opts+:: List of long style options with "no-" prefix.
- #
- # prepend(switch, short_opts, long_opts, nolong_opts)
- #
- def prepend(*args)
- update(*args)
- @list.unshift(args[0])
- end
-
- #
- # Appends +switch+ at the tail of the list, and associates short, long
- # and negated long options. Arguments are:
- #
- # +switch+:: Gem::OptionParser::Switch instance to be inserted.
- # +short_opts+:: List of short style options.
- # +long_opts+:: List of long style options.
- # +nolong_opts+:: List of long style options with "no-" prefix.
- #
- # append(switch, short_opts, long_opts, nolong_opts)
- #
- def append(*args)
- update(*args)
- @list.push(args[0])
- end
-
- #
- # Searches +key+ in +id+ list. The result is returned or yielded if a
- # block is given. If it isn't found, nil is returned.
- #
- def search(id, key)
- if list = __send__(id)
- val = list.fetch(key) {return nil}
- block_given? ? yield(val) : val
- end
- end
-
- #
- # Searches list +id+ for +opt+ and the optional patterns for completion
- # +pat+. If +icase+ is true, the search is case insensitive. The result
- # is returned or yielded if a block is given. If it isn't found, nil is
- # returned.
- #
- def complete(id, opt, icase = false, *pat, &block)
- __send__(id).complete(opt, icase, *pat, &block)
- end
-
- def get_candidates(id)
- yield __send__(id).keys
- end
-
- #
- # Iterates over each option, passing the option to the +block+.
- #
- def each_option(&block)
- list.each(&block)
- end
-
- #
- # Creates the summary table, passing each line to the +block+ (without
- # newline). The arguments +args+ are passed along to the summarize
- # method which is called on every option.
- #
- def summarize(*args, &block)
- sum = []
- list.reverse_each do |opt|
- if opt.respond_to?(:summarize) # perhaps Gem::OptionParser::Switch
- s = []
- opt.summarize(*args) {|l| s << l}
- sum.concat(s.reverse)
- elsif !opt or opt.empty?
- sum << ""
- elsif opt.respond_to?(:each_line)
- sum.concat([*opt.each_line].reverse)
- else
- sum.concat([*opt.each].reverse)
- end
- end
- sum.reverse_each(&block)
- end
-
- def add_banner(to) # :nodoc:
- list.each do |opt|
- if opt.respond_to?(:add_banner)
- opt.add_banner(to)
- end
- end
- to
- end
-
- def compsys(*args, &block) # :nodoc:
- list.each do |opt|
- if opt.respond_to?(:compsys)
- opt.compsys(*args, &block)
- end
- end
- end
- end
-
- #
- # Hash with completion search feature. See Gem::OptionParser::Completion.
- #
- class CompletingHash < Hash
- include Completion
-
- #
- # Completion for hash key.
- #
- def match(key)
- *values = fetch(key) {
- raise AmbiguousArgument, catch(:ambiguous) {return complete(key)}
- }
- return key, *values
- end
- end
-
- # :stopdoc:
-
- #
- # Enumeration of acceptable argument styles. Possible values are:
- #
- # NO_ARGUMENT:: The switch takes no arguments. (:NONE)
- # REQUIRED_ARGUMENT:: The switch requires an argument. (:REQUIRED)
- # OPTIONAL_ARGUMENT:: The switch requires an optional argument. (:OPTIONAL)
- #
- # Use like --switch=argument (long style) or -Xargument (short style). For
- # short style, only portion matched to argument pattern is treated as
- # argument.
- #
- ArgumentStyle = {}
- NoArgument.each {|el| ArgumentStyle[el] = Switch::NoArgument}
- RequiredArgument.each {|el| ArgumentStyle[el] = Switch::RequiredArgument}
- OptionalArgument.each {|el| ArgumentStyle[el] = Switch::OptionalArgument}
- ArgumentStyle.freeze
-
- #
- # Switches common used such as '--', and also provides default
- # argument classes
- #
- DefaultList = List.new
- DefaultList.short['-'] = Switch::NoArgument.new {}
- DefaultList.long[''] = Switch::NoArgument.new {throw :terminate}
-
-
- COMPSYS_HEADER = <<'XXX' # :nodoc:
-
-typeset -A opt_args
-local context state line
-
-_arguments -s -S \
-XXX
-
- def compsys(to, name = File.basename($0)) # :nodoc:
- to << "#compdef #{name}\n"
- to << COMPSYS_HEADER
- visit(:compsys, {}, {}) {|o, d|
- to << %Q[ "#{o}[#{d.gsub(/[\"\[\]]/, '\\\\\&')}]" \\\n]
- }
- to << " '*:file:_files' && return 0\n"
- end
-
- #
- # Default options for ARGV, which never appear in option summary.
- #
- Officious = {}
-
- #
- # --help
- # Shows option summary.
- #
- Officious['help'] = proc do |parser|
- Switch::NoArgument.new do |arg|
- puts parser.help
- exit
- end
- end
-
- #
- # --*-completion-bash=WORD
- # Shows candidates for command line completion.
- #
- Officious['*-completion-bash'] = proc do |parser|
- Switch::RequiredArgument.new do |arg|
- puts parser.candidate(arg)
- exit
- end
- end
-
- #
- # --*-completion-zsh[=NAME:FILE]
- # Creates zsh completion file.
- #
- Officious['*-completion-zsh'] = proc do |parser|
- Switch::OptionalArgument.new do |arg|
- parser.compsys(STDOUT, arg)
- exit
- end
- end
-
- #
- # --version
- # Shows version string if Version is defined.
- #
- Officious['version'] = proc do |parser|
- Switch::OptionalArgument.new do |pkg|
- if pkg
- begin
- require_relative 'optparse/version'
- rescue LoadError
- else
- show_version(*pkg.split(/,/)) or
- abort("#{parser.program_name}: no version found in package #{pkg}")
- exit
- end
- end
- v = parser.ver or abort("#{parser.program_name}: version unknown")
- puts v
- exit
- end
- end
-
- # :startdoc:
-
- #
- # Class methods
- #
-
- #
- # Initializes a new instance and evaluates the optional block in context
- # of the instance. Arguments +args+ are passed to #new, see there for
- # description of parameters.
- #
- # This method is *deprecated*, its behavior corresponds to the older #new
- # method.
- #
- def self.with(*args, &block)
- opts = new(*args)
- opts.instance_eval(&block)
- opts
- end
-
- #
- # Returns an incremented value of +default+ according to +arg+.
- #
- def self.inc(arg, default = nil)
- case arg
- when Integer
- arg.nonzero?
- when nil
- default.to_i + 1
- end
- end
- def inc(*args)
- self.class.inc(*args)
- end
-
- #
- # Initializes the instance and yields itself if called with a block.
- #
- # +banner+:: Banner message.
- # +width+:: Summary width.
- # +indent+:: Summary indent.
- #
- def initialize(banner = nil, width = 32, indent = ' ' * 4)
- @stack = [DefaultList, List.new, List.new]
- @program_name = nil
- @banner = banner
- @summary_width = width
- @summary_indent = indent
- @default_argv = ARGV
- @require_exact = false
- @raise_unknown = true
- add_officious
- yield self if block_given?
- end
-
- def add_officious # :nodoc:
- list = base()
- Officious.each do |opt, block|
- list.long[opt] ||= block.call(self)
- end
- end
-
- #
- # Terminates option parsing. Optional parameter +arg+ is a string pushed
- # back to be the first non-option argument.
- #
- def terminate(arg = nil)
- self.class.terminate(arg)
- end
- def self.terminate(arg = nil)
- throw :terminate, arg
- end
-
- @stack = [DefaultList]
- def self.top() DefaultList end
-
- #
- # Directs to accept specified class +t+. The argument string is passed to
- # the block in which it should be converted to the desired class.
- #
- # +t+:: Argument class specifier, any object including Class.
- # +pat+:: Pattern for argument, defaults to +t+ if it responds to match.
- #
- # accept(t, pat, &block)
- #
- def accept(*args, &blk) top.accept(*args, &blk) end
- #
- # See #accept.
- #
- def self.accept(*args, &blk) top.accept(*args, &blk) end
-
- #
- # Directs to reject specified class argument.
- #
- # +t+:: Argument class specifier, any object including Class.
- #
- # reject(t)
- #
- def reject(*args, &blk) top.reject(*args, &blk) end
- #
- # See #reject.
- #
- def self.reject(*args, &blk) top.reject(*args, &blk) end
-
- #
- # Instance methods
- #
-
- # Heading banner preceding summary.
- attr_writer :banner
-
- # Program name to be emitted in error message and default banner,
- # defaults to $0.
- attr_writer :program_name
-
- # Width for option list portion of summary. Must be Numeric.
- attr_accessor :summary_width
-
- # Indentation for summary. Must be String (or have + String method).
- attr_accessor :summary_indent
-
- # Strings to be parsed in default.
- attr_accessor :default_argv
-
- # Whether to require that options match exactly (disallows providing
- # abbreviated long option as short option).
- attr_accessor :require_exact
-
- # Whether to raise at unknown option.
- attr_accessor :raise_unknown
-
- #
- # Heading banner preceding summary.
- #
- def banner
- unless @banner
- @banner = +"Usage: #{program_name} [options]"
- visit(:add_banner, @banner)
- end
- @banner
- end
-
- #
- # Program name to be emitted in error message and default banner, defaults
- # to $0.
- #
- def program_name
- @program_name || File.basename($0, '.*')
- end
-
- # for experimental cascading :-)
- alias set_banner banner=
- alias set_program_name program_name=
- alias set_summary_width summary_width=
- alias set_summary_indent summary_indent=
-
- # Version
- attr_writer :version
- # Release code
- attr_writer :release
-
- #
- # Version
- #
- def version
- (defined?(@version) && @version) || (defined?(::Version) && ::Version)
- end
-
- #
- # Release code
- #
- def release
- (defined?(@release) && @release) || (defined?(::Release) && ::Release) || (defined?(::RELEASE) && ::RELEASE)
- end
-
- #
- # Returns version string from program_name, version and release.
- #
- def ver
- if v = version
- str = +"#{program_name} #{[v].join('.')}"
- str << " (#{v})" if v = release
- str
- end
- end
-
- def warn(mesg = $!)
- super("#{program_name}: #{mesg}")
- end
-
- def abort(mesg = $!)
- super("#{program_name}: #{mesg}")
- end
-
- #
- # Subject of #on / #on_head, #accept / #reject
- #
- def top
- @stack[-1]
- end
-
- #
- # Subject of #on_tail.
- #
- def base
- @stack[1]
- end
-
- #
- # Pushes a new List.
- #
- def new
- @stack.push(List.new)
- if block_given?
- yield self
- else
- self
- end
- end
-
- #
- # Removes the last List.
- #
- def remove
- @stack.pop
- end
-
- #
- # Puts option summary into +to+ and returns +to+. Yields each line if
- # a block is given.
- #
- # +to+:: Output destination, which must have method <<. Defaults to [].
- # +width+:: Width of left side, defaults to @summary_width.
- # +max+:: Maximum length allowed for left side, defaults to +width+ - 1.
- # +indent+:: Indentation, defaults to @summary_indent.
- #
- def summarize(to = [], width = @summary_width, max = width - 1, indent = @summary_indent, &blk)
- nl = "\n"
- blk ||= proc {|l| to << (l.index(nl, -1) ? l : l + nl)}
- visit(:summarize, {}, {}, width, max, indent, &blk)
- to
- end
-
- #
- # Returns option summary string.
- #
- def help; summarize("#{banner}".sub(/\n?\z/, "\n")) end
- alias to_s help
-
- def pretty_print(q) # :nodoc:
- q.object_group(self) do
- first = true
- if @stack.size > 2
- @stack.each_with_index do |s, i|
- next if i < 2
- next if s.list.empty?
- if first
- first = false
- q.text ":"
- end
- q.breakable
- s.pretty_print(q)
- end
- end
- end
- end
-
- def inspect # :nodoc:
- require 'pp'
- pretty_print_inspect
- end
-
- #
- # Returns option summary list.
- #
- def to_a; summarize("#{banner}".split(/^/)) end
-
- #
- # Checks if an argument is given twice, in which case an ArgumentError is
- # raised. Called from Gem::OptionParser#switch only.
- #
- # +obj+:: New argument.
- # +prv+:: Previously specified argument.
- # +msg+:: Exception message.
- #
- def notwice(obj, prv, msg) # :nodoc:
- unless !prv or prv == obj
- raise(ArgumentError, "argument #{msg} given twice: #{obj}",
- ParseError.filter_backtrace(caller(2)))
- end
- obj
- end
- private :notwice
-
- SPLAT_PROC = proc {|*a| a.length <= 1 ? a.first : a} # :nodoc:
-
- # :call-seq:
- # make_switch(params, block = nil)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- def make_switch(opts, block = nil)
- short, long, nolong, style, pattern, conv, not_pattern, not_conv, not_style = [], [], []
- ldesc, sdesc, desc, arg = [], [], []
- default_style = Switch::NoArgument
- default_pattern = nil
- klass = nil
- q, a = nil
- has_arg = false
-
- opts.each do |o|
- # argument class
- next if search(:atype, o) do |pat, c|
- klass = notwice(o, klass, 'type')
- if not_style and not_style != Switch::NoArgument
- not_pattern, not_conv = pat, c
- else
- default_pattern, conv = pat, c
- end
- end
-
- # directly specified pattern(any object possible to match)
- if (!(String === o || Symbol === o)) and o.respond_to?(:match)
- pattern = notwice(o, pattern, 'pattern')
- if pattern.respond_to?(:convert)
- conv = pattern.method(:convert).to_proc
- else
- conv = SPLAT_PROC
- end
- next
- end
-
- # anything others
- case o
- when Proc, Method
- block = notwice(o, block, 'block')
- when Array, Hash
- case pattern
- when CompletingHash
- when nil
- pattern = CompletingHash.new
- conv = pattern.method(:convert).to_proc if pattern.respond_to?(:convert)
- else
- raise ArgumentError, "argument pattern given twice"
- end
- o.each {|pat, *v| pattern[pat] = v.fetch(0) {pat}}
- when Module
- raise ArgumentError, "unsupported argument type: #{o}", ParseError.filter_backtrace(caller(4))
- when *ArgumentStyle.keys
- style = notwice(ArgumentStyle[o], style, 'style')
- when /^--no-([^\[\]=\s]*)(.+)?/
- q, a = $1, $2
- o = notwice(a ? Object : TrueClass, klass, 'type')
- not_pattern, not_conv = search(:atype, o) unless not_style
- not_style = (not_style || default_style).guess(arg = a) if a
- default_style = Switch::NoArgument
- default_pattern, conv = search(:atype, FalseClass) unless default_pattern
- ldesc << "--no-#{q}"
- (q = q.downcase).tr!('_', '-')
- long << "no-#{q}"
- nolong << q
- when /^--\[no-\]([^\[\]=\s]*)(.+)?/
- q, a = $1, $2
- o = notwice(a ? Object : TrueClass, klass, 'type')
- if a
- default_style = default_style.guess(arg = a)
- default_pattern, conv = search(:atype, o) unless default_pattern
- end
- ldesc << "--[no-]#{q}"
- (o = q.downcase).tr!('_', '-')
- long << o
- not_pattern, not_conv = search(:atype, FalseClass) unless not_style
- not_style = Switch::NoArgument
- nolong << "no-#{o}"
- when /^--([^\[\]=\s]*)(.+)?/
- q, a = $1, $2
- if a
- o = notwice(NilClass, klass, 'type')
- default_style = default_style.guess(arg = a)
- default_pattern, conv = search(:atype, o) unless default_pattern
- end
- ldesc << "--#{q}"
- (o = q.downcase).tr!('_', '-')
- long << o
- when /^-(\[\^?\]?(?:[^\\\]]|\\.)*\])(.+)?/
- q, a = $1, $2
- o = notwice(Object, klass, 'type')
- if a
- default_style = default_style.guess(arg = a)
- default_pattern, conv = search(:atype, o) unless default_pattern
- else
- has_arg = true
- end
- sdesc << "-#{q}"
- short << Regexp.new(q)
- when /^-(.)(.+)?/
- q, a = $1, $2
- if a
- o = notwice(NilClass, klass, 'type')
- default_style = default_style.guess(arg = a)
- default_pattern, conv = search(:atype, o) unless default_pattern
- end
- sdesc << "-#{q}"
- short << q
- when /^=/
- style = notwice(default_style.guess(arg = o), style, 'style')
- default_pattern, conv = search(:atype, Object) unless default_pattern
- else
- desc.push(o) if o && !o.empty?
- end
- end
-
- default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern
- if !(short.empty? and long.empty?)
- if has_arg and default_style == Switch::NoArgument
- default_style = Switch::RequiredArgument
- end
- s = (style || default_style).new(pattern || default_pattern,
- conv, sdesc, ldesc, arg, desc, block)
- elsif !block
- if style or pattern
- raise ArgumentError, "no switch given", ParseError.filter_backtrace(caller)
- end
- s = desc
- else
- short << pattern
- s = (style || default_style).new(pattern,
- conv, nil, nil, arg, desc, block)
- end
- return s, short, long,
- (not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style),
- nolong
- end
-
- # :call-seq:
- # define(*params, &block)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- def define(*opts, &block)
- top.append(*(sw = make_switch(opts, block)))
- sw[0]
- end
-
- # :call-seq:
- # on(*params, &block)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- def on(*opts, &block)
- define(*opts, &block)
- self
- end
- alias def_option define
-
- # :call-seq:
- # define_head(*params, &block)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- def define_head(*opts, &block)
- top.prepend(*(sw = make_switch(opts, block)))
- sw[0]
- end
-
- # :call-seq:
- # on_head(*params, &block)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- # The new option is added at the head of the summary.
- #
- def on_head(*opts, &block)
- define_head(*opts, &block)
- self
- end
- alias def_head_option define_head
-
- # :call-seq:
- # define_tail(*params, &block)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- def define_tail(*opts, &block)
- base.append(*(sw = make_switch(opts, block)))
- sw[0]
- end
-
- #
- # :call-seq:
- # on_tail(*params, &block)
- #
- # :include: ../doc/optparse/creates_option.rdoc
- #
- # The new option is added at the tail of the summary.
- #
- def on_tail(*opts, &block)
- define_tail(*opts, &block)
- self
- end
- alias def_tail_option define_tail
-
- #
- # Add separator in summary.
- #
- def separator(string)
- top.append(string, nil, nil)
- end
-
- #
- # Parses command line arguments +argv+ in order. When a block is given,
- # each non-option argument is yielded. When optional +into+ keyword
- # argument is provided, the parsed option values are stored there via
- # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
- # similar object).
- #
- # Returns the rest of +argv+ left unparsed.
- #
- def order(*argv, into: nil, &nonopt)
- argv = argv[0].dup if argv.size == 1 and Array === argv[0]
- order!(argv, into: into, &nonopt)
- end
-
- #
- # Same as #order, but removes switches destructively.
- # Non-option arguments remain in +argv+.
- #
- def order!(argv = default_argv, into: nil, &nonopt)
- setter = ->(name, val) {into[name.to_sym] = val} if into
- parse_in_order(argv, setter, &nonopt)
- end
-
- def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
- opt, arg, val, rest = nil
- nonopt ||= proc {|a| throw :terminate, a}
- argv.unshift(arg) if arg = catch(:terminate) {
- while arg = argv.shift
- case arg
- # long option
- when /\A--([^=]*)(?:=(.*))?/m
- opt, rest = $1, $2
- opt.tr!('_', '-')
- begin
- sw, = complete(:long, opt, true)
- if require_exact && !sw.long.include?(arg)
- throw :terminate, arg unless raise_unknown
- raise InvalidOption, arg
- end
- rescue ParseError
- throw :terminate, arg unless raise_unknown
- raise $!.set_option(arg, true)
- end
- begin
- opt, cb, val = sw.parse(rest, argv) {|*exc| raise(*exc)}
- val = cb.call(val) if cb
- setter.call(sw.switch_name, val) if setter
- rescue ParseError
- raise $!.set_option(arg, rest)
- end
-
- # short option
- when /\A-(.)((=).*|.+)?/m
- eq, rest, opt = $3, $2, $1
- has_arg, val = eq, rest
- begin
- sw, = search(:short, opt)
- unless sw
- begin
- sw, = complete(:short, opt)
- # short option matched.
- val = arg.delete_prefix('-')
- has_arg = true
- rescue InvalidOption
- raise if require_exact
- # if no short options match, try completion with long
- # options.
- sw, = complete(:long, opt)
- eq ||= !rest
- end
- end
- rescue ParseError
- throw :terminate, arg unless raise_unknown
- raise $!.set_option(arg, true)
- end
- begin
- opt, cb, val = sw.parse(val, argv) {|*exc| raise(*exc) if eq}
- rescue ParseError
- raise $!.set_option(arg, arg.length > 2)
- else
- raise InvalidOption, arg if has_arg and !eq and arg == "-#{opt}"
- end
- begin
- argv.unshift(opt) if opt and (!rest or (opt = opt.sub(/\A-*/, '-')) != '-')
- val = cb.call(val) if cb
- setter.call(sw.switch_name, val) if setter
- rescue ParseError
- raise $!.set_option(arg, arg.length > 2)
- end
-
- # non-option argument
- else
- catch(:prune) do
- visit(:each_option) do |sw0|
- sw = sw0
- sw.block.call(arg) if Switch === sw and sw.match_nonswitch?(arg)
- end
- nonopt.call(arg)
- end
- end
- end
-
- nil
- }
-
- visit(:search, :short, nil) {|sw| sw.block.call(*argv) if !sw.pattern}
-
- argv
- end
- private :parse_in_order
-
- #
- # Parses command line arguments +argv+ in permutation mode and returns
- # list of non-option arguments. When optional +into+ keyword
- # argument is provided, the parsed option values are stored there via
- # <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
- # similar object).
- #
- def permute(*argv, into: nil)
- argv = argv[0].dup if argv.size == 1 and Array === argv[0]
- permute!(argv, into: into)
- end
-
- #
- # Same as #permute, but removes switches destructively.
- # Non-option arguments remain in +argv+.
- #
- def permute!(argv = default_argv, into: nil)
- nonopts = []
- order!(argv, into: into, &nonopts.method(:<<))
- argv[0, 0] = nonopts
- argv
- end
-
- #
- # Parses command line arguments +argv+ in order when environment variable
- # POSIXLY_CORRECT is set, and in permutation mode otherwise.
- # When optional +into+ keyword argument is provided, the parsed option
- # values are stored there via <code>[]=</code> method (so it can be Hash,
- # or OpenStruct, or other similar object).
- #
- def parse(*argv, into: nil)
- argv = argv[0].dup if argv.size == 1 and Array === argv[0]
- parse!(argv, into: into)
- end
-
- #
- # Same as #parse, but removes switches destructively.
- # Non-option arguments remain in +argv+.
- #
- def parse!(argv = default_argv, into: nil)
- if ENV.include?('POSIXLY_CORRECT')
- order!(argv, into: into)
- else
- permute!(argv, into: into)
- end
- end
-
- #
- # Wrapper method for getopts.rb.
- #
- # params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option")
- # # params["a"] = true # -a
- # # params["b"] = "1" # -b1
- # # params["foo"] = "1" # --foo
- # # params["bar"] = "x" # --bar x
- # # params["zot"] = "z" # --zot Z
- #
- # Option +symbolize_names+ (boolean) specifies whether returned Hash keys should be Symbols; defaults to +false+ (use Strings).
- #
- # params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option", symbolize_names: true)
- # # params[:a] = true # -a
- # # params[:b] = "1" # -b1
- # # params[:foo] = "1" # --foo
- # # params[:bar] = "x" # --bar x
- # # params[:zot] = "z" # --zot Z
- #
- def getopts(*args, symbolize_names: false)
- argv = Array === args.first ? args.shift : default_argv
- single_options, *long_options = *args
-
- result = {}
-
- single_options.scan(/(.)(:)?/) do |opt, val|
- if val
- result[opt] = nil
- define("-#{opt} VAL")
- else
- result[opt] = false
- define("-#{opt}")
- end
- end if single_options
-
- long_options.each do |arg|
- arg, desc = arg.split(';', 2)
- opt, val = arg.split(':', 2)
- if val
- result[opt] = val.empty? ? nil : val
- define("--#{opt}=#{result[opt] || "VAL"}", *[desc].compact)
- else
- result[opt] = false
- define("--#{opt}", *[desc].compact)
- end
- end
-
- parse_in_order(argv, result.method(:[]=))
- symbolize_names ? result.transform_keys(&:to_sym) : result
- end
-
- #
- # See #getopts.
- #
- def self.getopts(*args, symbolize_names: false)
- new.getopts(*args, symbolize_names: symbolize_names)
- end
-
- #
- # Traverses @stack, sending each element method +id+ with +args+ and
- # +block+.
- #
- def visit(id, *args, &block) # :nodoc:
- @stack.reverse_each do |el|
- el.__send__(id, *args, &block)
- end
- nil
- end
- private :visit
-
- #
- # Searches +key+ in @stack for +id+ hash and returns or yields the result.
- #
- def search(id, key) # :nodoc:
- block_given = block_given?
- visit(:search, id, key) do |k|
- return block_given ? yield(k) : k
- end
- end
- private :search
-
- #
- # Completes shortened long style option switch and returns pair of
- # canonical switch and switch descriptor Gem::OptionParser::Switch.
- #
- # +typ+:: Searching table.
- # +opt+:: Searching key.
- # +icase+:: Search case insensitive if true.
- # +pat+:: Optional pattern for completion.
- #
- def complete(typ, opt, icase = false, *pat) # :nodoc:
- if pat.empty?
- search(typ, opt) {|sw| return [sw, opt]} # exact match or...
- end
- ambiguous = catch(:ambiguous) {
- visit(:complete, typ, opt, icase, *pat) {|o, *sw| return sw}
- }
- exc = ambiguous ? AmbiguousOption : InvalidOption
- raise exc.new(opt, additional: self.method(:additional_message).curry[typ])
- end
- private :complete
-
- #
- # Returns additional info.
- #
- def additional_message(typ, opt)
- return unless typ and opt and defined?(DidYouMean::SpellChecker)
- all_candidates = []
- visit(:get_candidates, typ) do |candidates|
- all_candidates.concat(candidates)
- end
- all_candidates.select! {|cand| cand.is_a?(String) }
- checker = DidYouMean::SpellChecker.new(dictionary: all_candidates)
- DidYouMean.formatter.message_for(all_candidates & checker.correct(opt))
- end
-
- def candidate(word)
- list = []
- case word
- when '-'
- long = short = true
- when /\A--/
- word, arg = word.split(/=/, 2)
- argpat = Completion.regexp(arg, false) if arg and !arg.empty?
- long = true
- when /\A-/
- short = true
- end
- pat = Completion.regexp(word, long)
- visit(:each_option) do |opt|
- next unless Switch === opt
- opts = (long ? opt.long : []) + (short ? opt.short : [])
- opts = Completion.candidate(word, true, pat, &opts.method(:each)).map(&:first) if pat
- if /\A=/ =~ opt.arg
- opts.map! {|sw| sw + "="}
- if arg and CompletingHash === opt.pattern
- if opts = opt.pattern.candidate(arg, false, argpat)
- opts.map!(&:last)
- end
- end
- end
- list.concat(opts)
- end
- list
- end
-
- #
- # Loads options from file names as +filename+. Does nothing when the file
- # is not present. Returns whether successfully loaded.
- #
- # +filename+ defaults to basename of the program without suffix in a
- # directory ~/.options, then the basename with '.options' suffix
- # under XDG and Haiku standard places.
- #
- # The optional +into+ keyword argument works exactly like that accepted in
- # method #parse.
- #
- def load(filename = nil, into: nil)
- unless filename
- basename = File.basename($0, '.*')
- return true if load(File.expand_path(basename, '~/.options'), into: into) rescue nil
- basename << ".options"
- return [
- # XDG
- ENV['XDG_CONFIG_HOME'],
- '~/.config',
- *ENV['XDG_CONFIG_DIRS']&.split(File::PATH_SEPARATOR),
-
- # Haiku
- '~/config/settings',
- ].any? {|dir|
- next if !dir or dir.empty?
- load(File.expand_path(basename, dir), into: into) rescue nil
- }
- end
- begin
- parse(*File.readlines(filename, chomp: true), into: into)
- true
- rescue Errno::ENOENT, Errno::ENOTDIR
- false
- end
- end
-
- #
- # Parses environment variable +env+ or its uppercase with splitting like a
- # shell.
- #
- # +env+ defaults to the basename of the program.
- #
- def environment(env = File.basename($0, '.*'))
- env = ENV[env] || ENV[env.upcase] or return
- require 'shellwords'
- parse(*Shellwords.shellwords(env))
- end
-
- #
- # Acceptable argument classes
- #
-
- #
- # Any string and no conversion. This is fall-back.
- #
- accept(Object) {|s,|s or s.nil?}
-
- accept(NilClass) {|s,|s}
-
- #
- # Any non-empty string, and no conversion.
- #
- accept(String, /.+/m) {|s,*|s}
-
- #
- # Ruby/C-like integer, octal for 0-7 sequence, binary for 0b, hexadecimal
- # for 0x, and decimal for others; with optional sign prefix. Converts to
- # Integer.
- #
- decimal = '\d+(?:_\d+)*'
- binary = 'b[01]+(?:_[01]+)*'
- hex = 'x[\da-f]+(?:_[\da-f]+)*'
- octal = "0(?:[0-7]+(?:_[0-7]+)*|#{binary}|#{hex})?"
- integer = "#{octal}|#{decimal}"
-
- accept(Integer, %r"\A[-+]?(?:#{integer})\z"io) {|s,|
- begin
- Integer(s)
- rescue ArgumentError
- raise Gem::OptionParser::InvalidArgument, s
- end if s
- }
-
- #
- # Float number format, and converts to Float.
- #
- float = "(?:#{decimal}(?=(.)?)(?:\\.(?:#{decimal})?)?|\\.#{decimal})(?:E[-+]?#{decimal})?"
- floatpat = %r"\A[-+]?#{float}\z"io
- accept(Float, floatpat) {|s,| s.to_f if s}
-
- #
- # Generic numeric format, converts to Integer for integer format, Float
- # for float format, and Rational for rational format.
- #
- real = "[-+]?(?:#{octal}|#{float})"
- accept(Numeric, /\A(#{real})(?:\/(#{real}))?\z/io) {|s, d, f, n,|
- if n
- Rational(d, n)
- elsif f
- Float(s)
- else
- Integer(s)
- end
- }
-
- #
- # Decimal integer format, to be converted to Integer.
- #
- DecimalInteger = /\A[-+]?#{decimal}\z/io
- accept(DecimalInteger, DecimalInteger) {|s,|
- begin
- Integer(s, 10)
- rescue ArgumentError
- raise Gem::OptionParser::InvalidArgument, s
- end if s
- }
-
- #
- # Ruby/C like octal/hexadecimal/binary integer format, to be converted to
- # Integer.
- #
- OctalInteger = /\A[-+]?(?:[0-7]+(?:_[0-7]+)*|0(?:#{binary}|#{hex}))\z/io
- accept(OctalInteger, OctalInteger) {|s,|
- begin
- Integer(s, 8)
- rescue ArgumentError
- raise Gem::OptionParser::InvalidArgument, s
- end if s
- }
-
- #
- # Decimal integer/float number format, to be converted to Integer for
- # integer format, Float for float format.
- #
- DecimalNumeric = floatpat # decimal integer is allowed as float also.
- accept(DecimalNumeric, floatpat) {|s, f|
- begin
- if f
- Float(s)
- else
- Integer(s)
- end
- rescue ArgumentError
- raise Gem::OptionParser::InvalidArgument, s
- end if s
- }
-
- #
- # Boolean switch, which means whether it is present or not, whether it is
- # absent or not with prefix no-, or it takes an argument
- # yes/no/true/false/+/-.
- #
- yesno = CompletingHash.new
- %w[- no false].each {|el| yesno[el] = false}
- %w[+ yes true].each {|el| yesno[el] = true}
- yesno['nil'] = false # should be nil?
- accept(TrueClass, yesno) {|arg, val| val == nil or val}
- #
- # Similar to TrueClass, but defaults to false.
- #
- accept(FalseClass, yesno) {|arg, val| val != nil and val}
-
- #
- # List of strings separated by ",".
- #
- accept(Array) do |s, |
- if s
- s = s.split(',').collect {|ss| ss unless ss.empty?}
- end
- s
- end
-
- #
- # Regular expression with options.
- #
- accept(Regexp, %r"\A/((?:\\.|[^\\])*)/([[:alpha:]]+)?\z|.*") do |all, s, o|
- f = 0
- if o
- f |= Regexp::IGNORECASE if /i/ =~ o
- f |= Regexp::MULTILINE if /m/ =~ o
- f |= Regexp::EXTENDED if /x/ =~ o
- case o = o.delete("imx")
- when ""
- when "u"
- s = s.encode(Encoding::UTF_8)
- when "e"
- s = s.encode(Encoding::EUC_JP)
- when "s"
- s = s.encode(Encoding::SJIS)
- when "n"
- f |= Regexp::NOENCODING
- else
- raise Gem::OptionParser::InvalidArgument, "unknown regexp option - #{o}"
- end
- else
- s ||= all
- end
- Regexp.new(s, f)
- end
-
- #
- # Exceptions
- #
-
- #
- # Base class of exceptions from Gem::OptionParser.
- #
- class ParseError < RuntimeError
- # Reason which caused the error.
- Reason = 'parse error'
-
- def initialize(*args, additional: nil)
- @additional = additional
- @arg0, = args
- @args = args
- @reason = nil
- end
-
- attr_reader :args
- attr_writer :reason
- attr_accessor :additional
-
- #
- # Pushes back erred argument(s) to +argv+.
- #
- def recover(argv)
- argv[0, 0] = @args
- argv
- end
-
- def self.filter_backtrace(array)
- unless $DEBUG
- array.delete_if(&%r"\A#{Regexp.quote(__FILE__)}:"o.method(:=~))
- end
- array
- end
-
- def set_backtrace(array)
- super(self.class.filter_backtrace(array))
- end
-
- def set_option(opt, eq)
- if eq
- @args[0] = opt
- else
- @args.unshift(opt)
- end
- self
- end
-
- #
- # Returns error reason. Override this for I18N.
- #
- def reason
- @reason || self.class::Reason
- end
-
- def inspect
- "#<#{self.class}: #{args.join(' ')}>"
- end
-
- #
- # Default stringizing method to emit standard error message.
- #
- def message
- "#{reason}: #{args.join(' ')}#{additional[@arg0] if additional}"
- end
-
- alias to_s message
- end
-
- #
- # Raises when ambiguously completable string is encountered.
- #
- class AmbiguousOption < ParseError
- const_set(:Reason, 'ambiguous option')
- end
-
- #
- # Raises when there is an argument for a switch which takes no argument.
- #
- class NeedlessArgument < ParseError
- const_set(:Reason, 'needless argument')
- end
-
- #
- # Raises when a switch with mandatory argument has no argument.
- #
- class MissingArgument < ParseError
- const_set(:Reason, 'missing argument')
- end
-
- #
- # Raises when switch is undefined.
- #
- class InvalidOption < ParseError
- const_set(:Reason, 'invalid option')
- end
-
- #
- # Raises when the given argument does not match required format.
- #
- class InvalidArgument < ParseError
- const_set(:Reason, 'invalid argument')
- end
-
- #
- # Raises when the given argument word can't be completed uniquely.
- #
- class AmbiguousArgument < InvalidArgument
- const_set(:Reason, 'ambiguous argument')
- end
-
- #
- # Miscellaneous
- #
-
- #
- # Extends command line arguments array (ARGV) to parse itself.
- #
- module Arguable
-
- #
- # Sets Gem::OptionParser object, when +opt+ is +false+ or +nil+, methods
- # Gem::OptionParser::Arguable#options and Gem::OptionParser::Arguable#options= are
- # undefined. Thus, there is no ways to access the Gem::OptionParser object
- # via the receiver object.
- #
- def options=(opt)
- unless @optparse = opt
- class << self
- undef_method(:options)
- undef_method(:options=)
- end
- end
- end
-
- #
- # Actual Gem::OptionParser object, automatically created if nonexistent.
- #
- # If called with a block, yields the Gem::OptionParser object and returns the
- # result of the block. If an Gem::OptionParser::ParseError exception occurs
- # in the block, it is rescued, a error message printed to STDERR and
- # +nil+ returned.
- #
- def options
- @optparse ||= Gem::OptionParser.new
- @optparse.default_argv = self
- block_given? or return @optparse
- begin
- yield @optparse
- rescue ParseError
- @optparse.warn $!
- nil
- end
- end
-
- #
- # Parses +self+ destructively in order and returns +self+ containing the
- # rest arguments left unparsed.
- #
- def order!(&blk) options.order!(self, &blk) end
-
- #
- # Parses +self+ destructively in permutation mode and returns +self+
- # containing the rest arguments left unparsed.
- #
- def permute!() options.permute!(self) end
-
- #
- # Parses +self+ destructively and returns +self+ containing the
- # rest arguments left unparsed.
- #
- def parse!() options.parse!(self) end
-
- #
- # Substitution of getopts is possible as follows. Also see
- # Gem::OptionParser#getopts.
- #
- # def getopts(*args)
- # ($OPT = ARGV.getopts(*args)).each do |opt, val|
- # eval "$OPT_#{opt.gsub(/[^A-Za-z0-9_]/, '_')} = val"
- # end
- # rescue Gem::OptionParser::ParseError
- # end
- #
- def getopts(*args, symbolize_names: false)
- options.getopts(self, *args, symbolize_names: symbolize_names)
- end
-
- #
- # Initializes instance variable.
- #
- def self.extend_object(obj)
- super
- obj.instance_eval {@optparse = nil}
- end
- def initialize(*args)
- super
- @optparse = nil
- end
- end
-
- #
- # Acceptable argument classes. Now contains DecimalInteger, OctalInteger
- # and DecimalNumeric. See Acceptable argument classes (in source code).
- #
- module Acceptables
- const_set(:DecimalInteger, Gem::OptionParser::DecimalInteger)
- const_set(:OctalInteger, Gem::OptionParser::OctalInteger)
- const_set(:DecimalNumeric, Gem::OptionParser::DecimalNumeric)
- end
-end
-
-# ARGV is arguable by Gem::OptionParser
-ARGV.extend(Gem::OptionParser::Arguable)
diff --git a/lib/rubygems/vendor/optparse/lib/optparse/uri.rb b/lib/rubygems/vendor/optparse/lib/optparse/uri.rb
deleted file mode 100644
index 398127479a..0000000000
--- a/lib/rubygems/vendor/optparse/lib/optparse/uri.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# frozen_string_literal: false
-# -*- ruby -*-
-
-require_relative '../optparse'
-require_relative '../../../uri/lib/uri'
-
-Gem::OptionParser.accept(Gem::URI) {|s,| Gem::URI.parse(s) if s}
diff --git a/lib/rubygems/vendor/resolv/.document b/lib/rubygems/vendor/resolv/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/resolv/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/resolv/lib/resolv.rb b/lib/rubygems/vendor/resolv/lib/resolv.rb
deleted file mode 100644
index 0f5ded3b76..0000000000
--- a/lib/rubygems/vendor/resolv/lib/resolv.rb
+++ /dev/null
@@ -1,3442 +0,0 @@
-# frozen_string_literal: true
-
-require 'socket'
-require_relative '../../timeout/lib/timeout'
-require 'io/wait'
-
-begin
- require_relative '../../../vendored_securerandom'
-rescue LoadError
-end
-
-# Gem::Resolv is a thread-aware DNS resolver library written in Ruby. Gem::Resolv can
-# handle multiple DNS requests concurrently without blocking the entire Ruby
-# interpreter.
-#
-# See also resolv-replace.rb to replace the libc resolver with Gem::Resolv.
-#
-# Gem::Resolv can look up various DNS resources using the DNS module directly.
-#
-# Examples:
-#
-# p Gem::Resolv.getaddress "www.ruby-lang.org"
-# p Gem::Resolv.getname "210.251.121.214"
-#
-# Gem::Resolv::DNS.open do |dns|
-# ress = dns.getresources "www.ruby-lang.org", Gem::Resolv::DNS::Resource::IN::A
-# p ress.map(&:address)
-# ress = dns.getresources "ruby-lang.org", Gem::Resolv::DNS::Resource::IN::MX
-# p ress.map { |r| [r.exchange.to_s, r.preference] }
-# end
-#
-#
-# == Bugs
-#
-# * NIS is not supported.
-# * /etc/nsswitch.conf is not supported.
-
-class Gem::Resolv
-
- VERSION = "0.4.0"
-
- ##
- # Looks up the first IP address for +name+.
-
- def self.getaddress(name)
- DefaultResolver.getaddress(name)
- end
-
- ##
- # Looks up all IP address for +name+.
-
- def self.getaddresses(name)
- DefaultResolver.getaddresses(name)
- end
-
- ##
- # Iterates over all IP addresses for +name+.
-
- def self.each_address(name, &block)
- DefaultResolver.each_address(name, &block)
- end
-
- ##
- # Looks up the hostname of +address+.
-
- def self.getname(address)
- DefaultResolver.getname(address)
- end
-
- ##
- # Looks up all hostnames for +address+.
-
- def self.getnames(address)
- DefaultResolver.getnames(address)
- end
-
- ##
- # Iterates over all hostnames for +address+.
-
- def self.each_name(address, &proc)
- DefaultResolver.each_name(address, &proc)
- end
-
- ##
- # Creates a new Gem::Resolv using +resolvers+.
-
- def initialize(resolvers=nil, use_ipv6: nil)
- @resolvers = resolvers || [Hosts.new, DNS.new(DNS::Config.default_config_hash.merge(use_ipv6: use_ipv6))]
- end
-
- ##
- # Looks up the first IP address for +name+.
-
- def getaddress(name)
- each_address(name) {|address| return address}
- raise ResolvError.new("no address for #{name}")
- end
-
- ##
- # Looks up all IP address for +name+.
-
- def getaddresses(name)
- ret = []
- each_address(name) {|address| ret << address}
- return ret
- end
-
- ##
- # Iterates over all IP addresses for +name+.
-
- def each_address(name)
- if AddressRegex =~ name
- yield name
- return
- end
- yielded = false
- @resolvers.each {|r|
- r.each_address(name) {|address|
- yield address.to_s
- yielded = true
- }
- return if yielded
- }
- end
-
- ##
- # Looks up the hostname of +address+.
-
- def getname(address)
- each_name(address) {|name| return name}
- raise ResolvError.new("no name for #{address}")
- end
-
- ##
- # Looks up all hostnames for +address+.
-
- def getnames(address)
- ret = []
- each_name(address) {|name| ret << name}
- return ret
- end
-
- ##
- # Iterates over all hostnames for +address+.
-
- def each_name(address)
- yielded = false
- @resolvers.each {|r|
- r.each_name(address) {|name|
- yield name.to_s
- yielded = true
- }
- return if yielded
- }
- end
-
- ##
- # Indicates a failure to resolve a name or address.
-
- class ResolvError < StandardError; end
-
- ##
- # Indicates a timeout resolving a name or address.
-
- class ResolvTimeout < Gem::Timeout::Error; end
-
- ##
- # Gem::Resolv::Hosts is a hostname resolver that uses the system hosts file.
-
- class Hosts
- if /mswin|mingw|cygwin/ =~ RUBY_PLATFORM and
- begin
- require 'win32/resolv'
- DefaultFileName = Win32::Resolv.get_hosts_path || IO::NULL
- rescue LoadError
- end
- end
- DefaultFileName ||= '/etc/hosts'
-
- ##
- # Creates a new Gem::Resolv::Hosts, using +filename+ for its data source.
-
- def initialize(filename = DefaultFileName)
- @filename = filename
- @mutex = Thread::Mutex.new
- @initialized = nil
- end
-
- def lazy_initialize # :nodoc:
- @mutex.synchronize {
- unless @initialized
- @name2addr = {}
- @addr2name = {}
- File.open(@filename, 'rb') {|f|
- f.each {|line|
- line.sub!(/#.*/, '')
- addr, *hostnames = line.split(/\s+/)
- next unless addr
- (@addr2name[addr] ||= []).concat(hostnames)
- hostnames.each {|hostname| (@name2addr[hostname] ||= []) << addr}
- }
- }
- @name2addr.each {|name, arr| arr.reverse!}
- @initialized = true
- end
- }
- self
- end
-
- ##
- # Gets the IP address of +name+ from the hosts file.
-
- def getaddress(name)
- each_address(name) {|address| return address}
- raise ResolvError.new("#{@filename} has no name: #{name}")
- end
-
- ##
- # Gets all IP addresses for +name+ from the hosts file.
-
- def getaddresses(name)
- ret = []
- each_address(name) {|address| ret << address}
- return ret
- end
-
- ##
- # Iterates over all IP addresses for +name+ retrieved from the hosts file.
-
- def each_address(name, &proc)
- lazy_initialize
- @name2addr[name]&.each(&proc)
- end
-
- ##
- # Gets the hostname of +address+ from the hosts file.
-
- def getname(address)
- each_name(address) {|name| return name}
- raise ResolvError.new("#{@filename} has no address: #{address}")
- end
-
- ##
- # Gets all hostnames for +address+ from the hosts file.
-
- def getnames(address)
- ret = []
- each_name(address) {|name| ret << name}
- return ret
- end
-
- ##
- # Iterates over all hostnames for +address+ retrieved from the hosts file.
-
- def each_name(address, &proc)
- lazy_initialize
- @addr2name[address]&.each(&proc)
- end
- end
-
- ##
- # Gem::Resolv::DNS is a DNS stub resolver.
- #
- # Information taken from the following places:
- #
- # * STD0013
- # * RFC 1035
- # * ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters
- # * etc.
-
- class DNS
-
- ##
- # Default DNS Port
-
- Port = 53
-
- ##
- # Default DNS UDP packet size
-
- UDPSize = 512
-
- ##
- # Creates a new DNS resolver. See Gem::Resolv::DNS.new for argument details.
- #
- # Yields the created DNS resolver to the block, if given, otherwise
- # returns it.
-
- def self.open(*args)
- dns = new(*args)
- return dns unless block_given?
- begin
- yield dns
- ensure
- dns.close
- end
- end
-
- ##
- # Creates a new DNS resolver.
- #
- # +config_info+ can be:
- #
- # nil:: Uses /etc/resolv.conf.
- # String:: Path to a file using /etc/resolv.conf's format.
- # Hash:: Must contain :nameserver, :search and :ndots keys.
- # :nameserver_port can be used to specify port number of nameserver address.
- # :raise_timeout_errors can be used to raise timeout errors
- # as exceptions instead of treating the same as an NXDOMAIN response.
- #
- # The value of :nameserver should be an address string or
- # an array of address strings.
- # - :nameserver => '8.8.8.8'
- # - :nameserver => ['8.8.8.8', '8.8.4.4']
- #
- # The value of :nameserver_port should be an array of
- # pair of nameserver address and port number.
- # - :nameserver_port => [['8.8.8.8', 53], ['8.8.4.4', 53]]
- #
- # Example:
- #
- # Gem::Resolv::DNS.new(:nameserver => ['210.251.121.21'],
- # :search => ['ruby-lang.org'],
- # :ndots => 1)
-
- def initialize(config_info=nil)
- @mutex = Thread::Mutex.new
- @config = Config.new(config_info)
- @initialized = nil
- end
-
- # Sets the resolver timeouts. This may be a single positive number
- # or an array of positive numbers representing timeouts in seconds.
- # If an array is specified, a DNS request will retry and wait for
- # each successive interval in the array until a successful response
- # is received. Specifying +nil+ reverts to the default timeouts:
- # [ 5, second = 5 * 2 / nameserver_count, 2 * second, 4 * second ]
- #
- # Example:
- #
- # dns.timeouts = 3
- #
- def timeouts=(values)
- @config.timeouts = values
- end
-
- def lazy_initialize # :nodoc:
- @mutex.synchronize {
- unless @initialized
- @config.lazy_initialize
- @initialized = true
- end
- }
- self
- end
-
- ##
- # Closes the DNS resolver.
-
- def close
- @mutex.synchronize {
- if @initialized
- @initialized = false
- end
- }
- end
-
- ##
- # Gets the IP address of +name+ from the DNS resolver.
- #
- # +name+ can be a Gem::Resolv::DNS::Name or a String. Retrieved address will
- # be a Gem::Resolv::IPv4 or Gem::Resolv::IPv6
-
- def getaddress(name)
- each_address(name) {|address| return address}
- raise ResolvError.new("DNS result has no information for #{name}")
- end
-
- ##
- # Gets all IP addresses for +name+ from the DNS resolver.
- #
- # +name+ can be a Gem::Resolv::DNS::Name or a String. Retrieved addresses will
- # be a Gem::Resolv::IPv4 or Gem::Resolv::IPv6
-
- def getaddresses(name)
- ret = []
- each_address(name) {|address| ret << address}
- return ret
- end
-
- ##
- # Iterates over all IP addresses for +name+ retrieved from the DNS
- # resolver.
- #
- # +name+ can be a Gem::Resolv::DNS::Name or a String. Retrieved addresses will
- # be a Gem::Resolv::IPv4 or Gem::Resolv::IPv6
-
- def each_address(name)
- each_resource(name, Resource::IN::A) {|resource| yield resource.address}
- if use_ipv6?
- each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address}
- end
- end
-
- def use_ipv6? # :nodoc:
- use_ipv6 = @config.use_ipv6?
- unless use_ipv6.nil?
- return use_ipv6
- end
-
- begin
- list = Socket.ip_address_list
- rescue NotImplementedError
- return true
- end
- list.any? {|a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? }
- end
- private :use_ipv6?
-
- ##
- # Gets the hostname for +address+ from the DNS resolver.
- #
- # +address+ must be a Gem::Resolv::IPv4, Gem::Resolv::IPv6 or a String. Retrieved
- # name will be a Gem::Resolv::DNS::Name.
-
- def getname(address)
- each_name(address) {|name| return name}
- raise ResolvError.new("DNS result has no information for #{address}")
- end
-
- ##
- # Gets all hostnames for +address+ from the DNS resolver.
- #
- # +address+ must be a Gem::Resolv::IPv4, Gem::Resolv::IPv6 or a String. Retrieved
- # names will be Gem::Resolv::DNS::Name instances.
-
- def getnames(address)
- ret = []
- each_name(address) {|name| ret << name}
- return ret
- end
-
- ##
- # Iterates over all hostnames for +address+ retrieved from the DNS
- # resolver.
- #
- # +address+ must be a Gem::Resolv::IPv4, Gem::Resolv::IPv6 or a String. Retrieved
- # names will be Gem::Resolv::DNS::Name instances.
-
- def each_name(address)
- case address
- when Name
- ptr = address
- when IPv4, IPv6
- ptr = address.to_name
- when IPv4::Regex
- ptr = IPv4.create(address).to_name
- when IPv6::Regex
- ptr = IPv6.create(address).to_name
- else
- raise ResolvError.new("cannot interpret as address: #{address}")
- end
- each_resource(ptr, Resource::IN::PTR) {|resource| yield resource.name}
- end
-
- ##
- # Look up the +typeclass+ DNS resource of +name+.
- #
- # +name+ must be a Gem::Resolv::DNS::Name or a String.
- #
- # +typeclass+ should be one of the following:
- #
- # * Gem::Resolv::DNS::Resource::IN::A
- # * Gem::Resolv::DNS::Resource::IN::AAAA
- # * Gem::Resolv::DNS::Resource::IN::ANY
- # * Gem::Resolv::DNS::Resource::IN::CNAME
- # * Gem::Resolv::DNS::Resource::IN::HINFO
- # * Gem::Resolv::DNS::Resource::IN::MINFO
- # * Gem::Resolv::DNS::Resource::IN::MX
- # * Gem::Resolv::DNS::Resource::IN::NS
- # * Gem::Resolv::DNS::Resource::IN::PTR
- # * Gem::Resolv::DNS::Resource::IN::SOA
- # * Gem::Resolv::DNS::Resource::IN::TXT
- # * Gem::Resolv::DNS::Resource::IN::WKS
- #
- # Returned resource is represented as a Gem::Resolv::DNS::Resource instance,
- # i.e. Gem::Resolv::DNS::Resource::IN::A.
-
- def getresource(name, typeclass)
- each_resource(name, typeclass) {|resource| return resource}
- raise ResolvError.new("DNS result has no information for #{name}")
- end
-
- ##
- # Looks up all +typeclass+ DNS resources for +name+. See #getresource for
- # argument details.
-
- def getresources(name, typeclass)
- ret = []
- each_resource(name, typeclass) {|resource| ret << resource}
- return ret
- end
-
- ##
- # Iterates over all +typeclass+ DNS resources for +name+. See
- # #getresource for argument details.
-
- def each_resource(name, typeclass, &proc)
- fetch_resource(name, typeclass) {|reply, reply_name|
- extract_resources(reply, reply_name, typeclass, &proc)
- }
- end
-
- def fetch_resource(name, typeclass)
- lazy_initialize
- begin
- requester = make_udp_requester
- rescue Errno::EACCES
- # fall back to TCP
- end
- senders = {}
- begin
- @config.resolv(name) {|candidate, tout, nameserver, port|
- requester ||= make_tcp_requester(nameserver, port)
- msg = Message.new
- msg.rd = 1
- msg.add_question(candidate, typeclass)
- unless sender = senders[[candidate, nameserver, port]]
- sender = requester.sender(msg, candidate, nameserver, port)
- next if !sender
- senders[[candidate, nameserver, port]] = sender
- end
- reply, reply_name = requester.request(sender, tout)
- case reply.rcode
- when RCode::NoError
- if reply.tc == 1 and not Requester::TCP === requester
- requester.close
- # Retry via TCP:
- requester = make_tcp_requester(nameserver, port)
- senders = {}
- # This will use TCP for all remaining candidates (assuming the
- # current candidate does not already respond successfully via
- # TCP). This makes sense because we already know the full
- # response will not fit in an untruncated UDP packet.
- redo
- else
- yield(reply, reply_name)
- end
- return
- when RCode::NXDomain
- raise Config::NXDomain.new(reply_name.to_s)
- else
- raise Config::OtherResolvError.new(reply_name.to_s)
- end
- }
- ensure
- requester&.close
- end
- end
-
- def make_udp_requester # :nodoc:
- nameserver_port = @config.nameserver_port
- if nameserver_port.length == 1
- Requester::ConnectedUDP.new(*nameserver_port[0])
- else
- Requester::UnconnectedUDP.new(*nameserver_port)
- end
- end
-
- def make_tcp_requester(host, port) # :nodoc:
- return Requester::TCP.new(host, port)
- end
-
- def extract_resources(msg, name, typeclass) # :nodoc:
- if typeclass < Resource::ANY
- n0 = Name.create(name)
- msg.each_resource {|n, ttl, data|
- yield data if n0 == n
- }
- end
- yielded = false
- n0 = Name.create(name)
- msg.each_resource {|n, ttl, data|
- if n0 == n
- case data
- when typeclass
- yield data
- yielded = true
- when Resource::CNAME
- n0 = data.name
- end
- end
- }
- return if yielded
- msg.each_resource {|n, ttl, data|
- if n0 == n
- case data
- when typeclass
- yield data
- end
- end
- }
- end
-
- if defined? Gem::SecureRandom
- def self.random(arg) # :nodoc:
- begin
- Gem::SecureRandom.random_number(arg)
- rescue NotImplementedError
- rand(arg)
- end
- end
- else
- def self.random(arg) # :nodoc:
- rand(arg)
- end
- end
-
- RequestID = {} # :nodoc:
- RequestIDMutex = Thread::Mutex.new # :nodoc:
-
- def self.allocate_request_id(host, port) # :nodoc:
- id = nil
- RequestIDMutex.synchronize {
- h = (RequestID[[host, port]] ||= {})
- begin
- id = random(0x0000..0xffff)
- end while h[id]
- h[id] = true
- }
- id
- end
-
- def self.free_request_id(host, port, id) # :nodoc:
- RequestIDMutex.synchronize {
- key = [host, port]
- if h = RequestID[key]
- h.delete id
- if h.empty?
- RequestID.delete key
- end
- end
- }
- end
-
- def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
- begin
- port = random(1024..65535)
- udpsock.bind(bind_host, port)
- rescue Errno::EADDRINUSE, # POSIX
- Errno::EACCES, # SunOS: See PRIV_SYS_NFS in privileges(5)
- Errno::EPERM # FreeBSD: security.mac.portacl.port_high is configurable. See mac_portacl(4).
- retry
- end
- end
-
- class Requester # :nodoc:
- def initialize
- @senders = {}
- @socks = nil
- end
-
- def request(sender, tout)
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- timelimit = start + tout
- begin
- sender.send
- rescue Errno::EHOSTUNREACH, # multi-homed IPv6 may generate this
- Errno::ENETUNREACH
- raise ResolvTimeout
- end
- while true
- before_select = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- timeout = timelimit - before_select
- if timeout <= 0
- raise ResolvTimeout
- end
- if @socks.size == 1
- select_result = @socks[0].wait_readable(timeout) ? [ @socks ] : nil
- else
- select_result = IO.select(@socks, nil, nil, timeout)
- end
- if !select_result
- after_select = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- next if after_select < timelimit
- raise ResolvTimeout
- end
- begin
- reply, from = recv_reply(select_result[0])
- rescue Errno::ECONNREFUSED, # GNU/Linux, FreeBSD
- Errno::ECONNRESET # Windows
- # No name server running on the server?
- # Don't wait anymore.
- raise ResolvTimeout
- end
- begin
- msg = Message.decode(reply)
- rescue DecodeError
- next # broken DNS message ignored
- end
- if sender == sender_for(from, msg)
- break
- else
- # unexpected DNS message ignored
- end
- end
- return msg, sender.data
- end
-
- def sender_for(addr, msg)
- @senders[[addr,msg.id]]
- end
-
- def close
- socks = @socks
- @socks = nil
- socks&.each(&:close)
- end
-
- class Sender # :nodoc:
- def initialize(msg, data, sock)
- @msg = msg
- @data = data
- @sock = sock
- end
- end
-
- class UnconnectedUDP < Requester # :nodoc:
- def initialize(*nameserver_port)
- super()
- @nameserver_port = nameserver_port
- @initialized = false
- @mutex = Thread::Mutex.new
- end
-
- def lazy_initialize
- @mutex.synchronize {
- next if @initialized
- @initialized = true
- @socks_hash = {}
- @socks = []
- @nameserver_port.each {|host, port|
- if host.index(':')
- bind_host = "::"
- af = Socket::AF_INET6
- else
- bind_host = "0.0.0.0"
- af = Socket::AF_INET
- end
- next if @socks_hash[bind_host]
- begin
- sock = UDPSocket.new(af)
- rescue Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT
- next # The kernel doesn't support the address family.
- end
- @socks << sock
- @socks_hash[bind_host] = sock
- sock.do_not_reverse_lookup = true
- DNS.bind_random_port(sock, bind_host)
- }
- }
- self
- end
-
- def recv_reply(readable_socks)
- lazy_initialize
- reply, from = readable_socks[0].recvfrom(UDPSize)
- return reply, [from[3],from[1]]
- end
-
- def sender(msg, data, host, port=Port)
- host = Addrinfo.ip(host).ip_address
- lazy_initialize
- sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"]
- return nil if !sock
- service = [host, port]
- id = DNS.allocate_request_id(host, port)
- request = msg.encode
- request[0,2] = [id].pack('n')
- return @senders[[service, id]] =
- Sender.new(request, data, sock, host, port)
- end
-
- def close
- @mutex.synchronize {
- if @initialized
- super
- @senders.each_key {|service, id|
- DNS.free_request_id(service[0], service[1], id)
- }
- @initialized = false
- end
- }
- end
-
- class Sender < Requester::Sender # :nodoc:
- def initialize(msg, data, sock, host, port)
- super(msg, data, sock)
- @host = host
- @port = port
- end
- attr_reader :data
-
- def send
- raise "@sock is nil." if @sock.nil?
- @sock.send(@msg, 0, @host, @port)
- end
- end
- end
-
- class ConnectedUDP < Requester # :nodoc:
- def initialize(host, port=Port)
- super()
- @host = host
- @port = port
- @mutex = Thread::Mutex.new
- @initialized = false
- end
-
- def lazy_initialize
- @mutex.synchronize {
- next if @initialized
- @initialized = true
- is_ipv6 = @host.index(':')
- sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET)
- @socks = [sock]
- sock.do_not_reverse_lookup = true
- DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0")
- sock.connect(@host, @port)
- }
- self
- end
-
- def recv_reply(readable_socks)
- lazy_initialize
- reply = readable_socks[0].recv(UDPSize)
- return reply, nil
- end
-
- def sender(msg, data, host=@host, port=@port)
- lazy_initialize
- unless host == @host && port == @port
- raise RequestError.new("host/port don't match: #{host}:#{port}")
- end
- id = DNS.allocate_request_id(@host, @port)
- request = msg.encode
- request[0,2] = [id].pack('n')
- return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
- end
-
- def close
- @mutex.synchronize do
- if @initialized
- super
- @senders.each_key {|from, id|
- DNS.free_request_id(@host, @port, id)
- }
- @initialized = false
- end
- end
- end
-
- class Sender < Requester::Sender # :nodoc:
- def send
- raise "@sock is nil." if @sock.nil?
- @sock.send(@msg, 0)
- end
- attr_reader :data
- end
- end
-
- class MDNSOneShot < UnconnectedUDP # :nodoc:
- def sender(msg, data, host, port=Port)
- lazy_initialize
- id = DNS.allocate_request_id(host, port)
- request = msg.encode
- request[0,2] = [id].pack('n')
- sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"]
- return @senders[id] =
- UnconnectedUDP::Sender.new(request, data, sock, host, port)
- end
-
- def sender_for(addr, msg)
- lazy_initialize
- @senders[msg.id]
- end
- end
-
- class TCP < Requester # :nodoc:
- def initialize(host, port=Port)
- super()
- @host = host
- @port = port
- sock = TCPSocket.new(@host, @port)
- @socks = [sock]
- @senders = {}
- end
-
- def recv_reply(readable_socks)
- len = readable_socks[0].read(2).unpack('n')[0]
- reply = @socks[0].read(len)
- return reply, nil
- end
-
- def sender(msg, data, host=@host, port=@port)
- unless host == @host && port == @port
- raise RequestError.new("host/port don't match: #{host}:#{port}")
- end
- id = DNS.allocate_request_id(@host, @port)
- request = msg.encode
- request[0,2] = [request.length, id].pack('nn')
- return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
- end
-
- class Sender < Requester::Sender # :nodoc:
- def send
- @sock.print(@msg)
- @sock.flush
- end
- attr_reader :data
- end
-
- def close
- super
- @senders.each_key {|from,id|
- DNS.free_request_id(@host, @port, id)
- }
- end
- end
-
- ##
- # Indicates a problem with the DNS request.
-
- class RequestError < StandardError
- end
- end
-
- class Config # :nodoc:
- def initialize(config_info=nil)
- @mutex = Thread::Mutex.new
- @config_info = config_info
- @initialized = nil
- @timeouts = nil
- end
-
- def timeouts=(values)
- if values
- values = Array(values)
- values.each do |t|
- Numeric === t or raise ArgumentError, "#{t.inspect} is not numeric"
- t > 0.0 or raise ArgumentError, "timeout=#{t} must be positive"
- end
- @timeouts = values
- else
- @timeouts = nil
- end
- end
-
- def Config.parse_resolv_conf(filename)
- nameserver = []
- search = nil
- ndots = 1
- File.open(filename, 'rb') {|f|
- f.each {|line|
- line.sub!(/[#;].*/, '')
- keyword, *args = line.split(/\s+/)
- next unless keyword
- case keyword
- when 'nameserver'
- nameserver.concat(args)
- when 'domain'
- next if args.empty?
- search = [args[0]]
- when 'search'
- next if args.empty?
- search = args
- when 'options'
- args.each {|arg|
- case arg
- when /\Andots:(\d+)\z/
- ndots = $1.to_i
- end
- }
- end
- }
- }
- return { :nameserver => nameserver, :search => search, :ndots => ndots }
- end
-
- def Config.default_config_hash(filename="/etc/resolv.conf")
- if File.exist? filename
- config_hash = Config.parse_resolv_conf(filename)
- else
- if /mswin|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
- require 'win32/resolv'
- search, nameserver = Win32::Resolv.get_resolv_info
- config_hash = {}
- config_hash[:nameserver] = nameserver if nameserver
- config_hash[:search] = [search].flatten if search
- end
- end
- config_hash || {}
- end
-
- def lazy_initialize
- @mutex.synchronize {
- unless @initialized
- @nameserver_port = []
- @use_ipv6 = nil
- @search = nil
- @ndots = 1
- case @config_info
- when nil
- config_hash = Config.default_config_hash
- when String
- config_hash = Config.parse_resolv_conf(@config_info)
- when Hash
- config_hash = @config_info.dup
- if String === config_hash[:nameserver]
- config_hash[:nameserver] = [config_hash[:nameserver]]
- end
- if String === config_hash[:search]
- config_hash[:search] = [config_hash[:search]]
- end
- else
- raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}")
- end
- if config_hash.include? :nameserver
- @nameserver_port = config_hash[:nameserver].map {|ns| [ns, Port] }
- end
- if config_hash.include? :nameserver_port
- @nameserver_port = config_hash[:nameserver_port].map {|ns, port| [ns, (port || Port)] }
- end
- if config_hash.include? :use_ipv6
- @use_ipv6 = config_hash[:use_ipv6]
- end
- @search = config_hash[:search] if config_hash.include? :search
- @ndots = config_hash[:ndots] if config_hash.include? :ndots
- @raise_timeout_errors = config_hash[:raise_timeout_errors]
-
- if @nameserver_port.empty?
- @nameserver_port << ['0.0.0.0', Port]
- end
- if @search
- @search = @search.map {|arg| Label.split(arg) }
- else
- hostname = Socket.gethostname
- if /\./ =~ hostname
- @search = [Label.split($')]
- else
- @search = [[]]
- end
- end
-
- if !@nameserver_port.kind_of?(Array) ||
- @nameserver_port.any? {|ns_port|
- !(Array === ns_port) ||
- ns_port.length != 2
- !(String === ns_port[0]) ||
- !(Integer === ns_port[1])
- }
- raise ArgumentError.new("invalid nameserver config: #{@nameserver_port.inspect}")
- end
-
- if !@search.kind_of?(Array) ||
- !@search.all? {|ls| ls.all? {|l| Label::Str === l } }
- raise ArgumentError.new("invalid search config: #{@search.inspect}")
- end
-
- if !@ndots.kind_of?(Integer)
- raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}")
- end
-
- @initialized = true
- end
- }
- self
- end
-
- def single?
- lazy_initialize
- if @nameserver_port.length == 1
- return @nameserver_port[0]
- else
- return nil
- end
- end
-
- def nameserver_port
- @nameserver_port
- end
-
- def use_ipv6?
- @use_ipv6
- end
-
- def generate_candidates(name)
- candidates = nil
- name = Name.create(name)
- if name.absolute?
- candidates = [name]
- else
- if @ndots <= name.length - 1
- candidates = [Name.new(name.to_a)]
- else
- candidates = []
- end
- candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)})
- fname = Name.create("#{name}.")
- if !candidates.include?(fname)
- candidates << fname
- end
- end
- return candidates
- end
-
- InitialTimeout = 5
-
- def generate_timeouts
- ts = [InitialTimeout]
- ts << ts[-1] * 2 / @nameserver_port.length
- ts << ts[-1] * 2
- ts << ts[-1] * 2
- return ts
- end
-
- def resolv(name)
- candidates = generate_candidates(name)
- timeouts = @timeouts || generate_timeouts
- timeout_error = false
- begin
- candidates.each {|candidate|
- begin
- timeouts.each {|tout|
- @nameserver_port.each {|nameserver, port|
- begin
- yield candidate, tout, nameserver, port
- rescue ResolvTimeout
- end
- }
- }
- timeout_error = true
- raise ResolvError.new("DNS resolv timeout: #{name}")
- rescue NXDomain
- end
- }
- rescue ResolvError
- raise if @raise_timeout_errors && timeout_error
- end
- end
-
- ##
- # Indicates no such domain was found.
-
- class NXDomain < ResolvError
- end
-
- ##
- # Indicates some other unhandled resolver error was encountered.
-
- class OtherResolvError < ResolvError
- end
- end
-
- module OpCode # :nodoc:
- Query = 0
- IQuery = 1
- Status = 2
- Notify = 4
- Update = 5
- end
-
- module RCode # :nodoc:
- NoError = 0
- FormErr = 1
- ServFail = 2
- NXDomain = 3
- NotImp = 4
- Refused = 5
- YXDomain = 6
- YXRRSet = 7
- NXRRSet = 8
- NotAuth = 9
- NotZone = 10
- BADVERS = 16
- BADSIG = 16
- BADKEY = 17
- BADTIME = 18
- BADMODE = 19
- BADNAME = 20
- BADALG = 21
- end
-
- ##
- # Indicates that the DNS response was unable to be decoded.
-
- class DecodeError < StandardError
- end
-
- ##
- # Indicates that the DNS request was unable to be encoded.
-
- class EncodeError < StandardError
- end
-
- module Label # :nodoc:
- def self.split(arg)
- labels = []
- arg.scan(/[^\.]+/) {labels << Str.new($&)}
- return labels
- end
-
- class Str # :nodoc:
- def initialize(string)
- @string = string
- # case insensivity of DNS labels doesn't apply non-ASCII characters. [RFC 4343]
- # This assumes @string is given in ASCII compatible encoding.
- @downcase = string.b.downcase
- end
- attr_reader :string, :downcase
-
- def to_s
- return @string
- end
-
- def inspect
- return "#<#{self.class} #{self}>"
- end
-
- def ==(other)
- return self.class == other.class && @downcase == other.downcase
- end
-
- def eql?(other)
- return self == other
- end
-
- def hash
- return @downcase.hash
- end
- end
- end
-
- ##
- # A representation of a DNS name.
-
- class Name
-
- ##
- # Creates a new DNS name from +arg+. +arg+ can be:
- #
- # Name:: returns +arg+.
- # String:: Creates a new Name.
-
- def self.create(arg)
- case arg
- when Name
- return arg
- when String
- return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false)
- else
- raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}")
- end
- end
-
- def initialize(labels, absolute=true) # :nodoc:
- labels = labels.map {|label|
- case label
- when String then Label::Str.new(label)
- when Label::Str then label
- else
- raise ArgumentError, "unexpected label: #{label.inspect}"
- end
- }
- @labels = labels
- @absolute = absolute
- end
-
- def inspect # :nodoc:
- "#<#{self.class}: #{self}#{@absolute ? '.' : ''}>"
- end
-
- ##
- # True if this name is absolute.
-
- def absolute?
- return @absolute
- end
-
- def ==(other) # :nodoc:
- return false unless Name === other
- return false unless @absolute == other.absolute?
- return @labels == other.to_a
- end
-
- alias eql? == # :nodoc:
-
- ##
- # Returns true if +other+ is a subdomain.
- #
- # Example:
- #
- # domain = Gem::Resolv::DNS::Name.create("y.z")
- # p Gem::Resolv::DNS::Name.create("w.x.y.z").subdomain_of?(domain) #=> true
- # p Gem::Resolv::DNS::Name.create("x.y.z").subdomain_of?(domain) #=> true
- # p Gem::Resolv::DNS::Name.create("y.z").subdomain_of?(domain) #=> false
- # p Gem::Resolv::DNS::Name.create("z").subdomain_of?(domain) #=> false
- # p Gem::Resolv::DNS::Name.create("x.y.z.").subdomain_of?(domain) #=> false
- # p Gem::Resolv::DNS::Name.create("w.z").subdomain_of?(domain) #=> false
- #
-
- def subdomain_of?(other)
- raise ArgumentError, "not a domain name: #{other.inspect}" unless Name === other
- return false if @absolute != other.absolute?
- other_len = other.length
- return false if @labels.length <= other_len
- return @labels[-other_len, other_len] == other.to_a
- end
-
- def hash # :nodoc:
- return @labels.hash ^ @absolute.hash
- end
-
- def to_a # :nodoc:
- return @labels
- end
-
- def length # :nodoc:
- return @labels.length
- end
-
- def [](i) # :nodoc:
- return @labels[i]
- end
-
- ##
- # returns the domain name as a string.
- #
- # The domain name doesn't have a trailing dot even if the name object is
- # absolute.
- #
- # Example:
- #
- # p Gem::Resolv::DNS::Name.create("x.y.z.").to_s #=> "x.y.z"
- # p Gem::Resolv::DNS::Name.create("x.y.z").to_s #=> "x.y.z"
-
- def to_s
- return @labels.join('.')
- end
- end
-
- class Message # :nodoc:
- @@identifier = -1
-
- def initialize(id = (@@identifier += 1) & 0xffff)
- @id = id
- @qr = 0
- @opcode = 0
- @aa = 0
- @tc = 0
- @rd = 0 # recursion desired
- @ra = 0 # recursion available
- @rcode = 0
- @question = []
- @answer = []
- @authority = []
- @additional = []
- end
-
- attr_accessor :id, :qr, :opcode, :aa, :tc, :rd, :ra, :rcode
- attr_reader :question, :answer, :authority, :additional
-
- def ==(other)
- return @id == other.id &&
- @qr == other.qr &&
- @opcode == other.opcode &&
- @aa == other.aa &&
- @tc == other.tc &&
- @rd == other.rd &&
- @ra == other.ra &&
- @rcode == other.rcode &&
- @question == other.question &&
- @answer == other.answer &&
- @authority == other.authority &&
- @additional == other.additional
- end
-
- def add_question(name, typeclass)
- @question << [Name.create(name), typeclass]
- end
-
- def each_question
- @question.each {|name, typeclass|
- yield name, typeclass
- }
- end
-
- def add_answer(name, ttl, data)
- @answer << [Name.create(name), ttl, data]
- end
-
- def each_answer
- @answer.each {|name, ttl, data|
- yield name, ttl, data
- }
- end
-
- def add_authority(name, ttl, data)
- @authority << [Name.create(name), ttl, data]
- end
-
- def each_authority
- @authority.each {|name, ttl, data|
- yield name, ttl, data
- }
- end
-
- def add_additional(name, ttl, data)
- @additional << [Name.create(name), ttl, data]
- end
-
- def each_additional
- @additional.each {|name, ttl, data|
- yield name, ttl, data
- }
- end
-
- def each_resource
- each_answer {|name, ttl, data| yield name, ttl, data}
- each_authority {|name, ttl, data| yield name, ttl, data}
- each_additional {|name, ttl, data| yield name, ttl, data}
- end
-
- def encode
- return MessageEncoder.new {|msg|
- msg.put_pack('nnnnnn',
- @id,
- (@qr & 1) << 15 |
- (@opcode & 15) << 11 |
- (@aa & 1) << 10 |
- (@tc & 1) << 9 |
- (@rd & 1) << 8 |
- (@ra & 1) << 7 |
- (@rcode & 15),
- @question.length,
- @answer.length,
- @authority.length,
- @additional.length)
- @question.each {|q|
- name, typeclass = q
- msg.put_name(name)
- msg.put_pack('nn', typeclass::TypeValue, typeclass::ClassValue)
- }
- [@answer, @authority, @additional].each {|rr|
- rr.each {|r|
- name, ttl, data = r
- msg.put_name(name)
- msg.put_pack('nnN', data.class::TypeValue, data.class::ClassValue, ttl)
- msg.put_length16 {data.encode_rdata(msg)}
- }
- }
- }.to_s
- end
-
- class MessageEncoder # :nodoc:
- def initialize
- @data = ''.dup
- @names = {}
- yield self
- end
-
- def to_s
- return @data
- end
-
- def put_bytes(d)
- @data << d
- end
-
- def put_pack(template, *d)
- @data << d.pack(template)
- end
-
- def put_length16
- length_index = @data.length
- @data << "\0\0"
- data_start = @data.length
- yield
- data_end = @data.length
- @data[length_index, 2] = [data_end - data_start].pack("n")
- end
-
- def put_string(d)
- self.put_pack("C", d.length)
- @data << d
- end
-
- def put_string_list(ds)
- ds.each {|d|
- self.put_string(d)
- }
- end
-
- def put_name(d, compress: true)
- put_labels(d.to_a, compress: compress)
- end
-
- def put_labels(d, compress: true)
- d.each_index {|i|
- domain = d[i..-1]
- if compress && idx = @names[domain]
- self.put_pack("n", 0xc000 | idx)
- return
- else
- if @data.length < 0x4000
- @names[domain] = @data.length
- end
- self.put_label(d[i])
- end
- }
- @data << "\0"
- end
-
- def put_label(d)
- self.put_string(d.to_s)
- end
- end
-
- def Message.decode(m)
- o = Message.new(0)
- MessageDecoder.new(m) {|msg|
- id, flag, qdcount, ancount, nscount, arcount =
- msg.get_unpack('nnnnnn')
- o.id = id
- o.tc = (flag >> 9) & 1
- o.rcode = flag & 15
- return o unless o.tc.zero?
-
- o.qr = (flag >> 15) & 1
- o.opcode = (flag >> 11) & 15
- o.aa = (flag >> 10) & 1
- o.rd = (flag >> 8) & 1
- o.ra = (flag >> 7) & 1
- (1..qdcount).each {
- name, typeclass = msg.get_question
- o.add_question(name, typeclass)
- }
- (1..ancount).each {
- name, ttl, data = msg.get_rr
- o.add_answer(name, ttl, data)
- }
- (1..nscount).each {
- name, ttl, data = msg.get_rr
- o.add_authority(name, ttl, data)
- }
- (1..arcount).each {
- name, ttl, data = msg.get_rr
- o.add_additional(name, ttl, data)
- }
- }
- return o
- end
-
- class MessageDecoder # :nodoc:
- def initialize(data)
- @data = data
- @index = 0
- @limit = data.bytesize
- yield self
- end
-
- def inspect
- "\#<#{self.class}: #{@data.byteslice(0, @index).inspect} #{@data.byteslice(@index..-1).inspect}>"
- end
-
- def get_length16
- len, = self.get_unpack('n')
- save_limit = @limit
- @limit = @index + len
- d = yield(len)
- if @index < @limit
- raise DecodeError.new("junk exists")
- elsif @limit < @index
- raise DecodeError.new("limit exceeded")
- end
- @limit = save_limit
- return d
- end
-
- def get_bytes(len = @limit - @index)
- raise DecodeError.new("limit exceeded") if @limit < @index + len
- d = @data.byteslice(@index, len)
- @index += len
- return d
- end
-
- def get_unpack(template)
- len = 0
- template.each_byte {|byte|
- byte = "%c" % byte
- case byte
- when ?c, ?C
- len += 1
- when ?n
- len += 2
- when ?N
- len += 4
- else
- raise StandardError.new("unsupported template: '#{byte.chr}' in '#{template}'")
- end
- }
- raise DecodeError.new("limit exceeded") if @limit < @index + len
- arr = @data.unpack("@#{@index}#{template}")
- @index += len
- return arr
- end
-
- def get_string
- raise DecodeError.new("limit exceeded") if @limit <= @index
- len = @data.getbyte(@index)
- raise DecodeError.new("limit exceeded") if @limit < @index + 1 + len
- d = @data.byteslice(@index + 1, len)
- @index += 1 + len
- return d
- end
-
- def get_string_list
- strings = []
- while @index < @limit
- strings << self.get_string
- end
- strings
- end
-
- def get_list
- [].tap do |values|
- while @index < @limit
- values << yield
- end
- end
- end
-
- def get_name
- return Name.new(self.get_labels)
- end
-
- def get_labels
- prev_index = @index
- save_index = nil
- d = []
- while true
- raise DecodeError.new("limit exceeded") if @limit <= @index
- case @data.getbyte(@index)
- when 0
- @index += 1
- if save_index
- @index = save_index
- end
- return d
- when 192..255
- idx = self.get_unpack('n')[0] & 0x3fff
- if prev_index <= idx
- raise DecodeError.new("non-backward name pointer")
- end
- prev_index = idx
- if !save_index
- save_index = @index
- end
- @index = idx
- else
- d << self.get_label
- end
- end
- end
-
- def get_label
- return Label::Str.new(self.get_string)
- end
-
- def get_question
- name = self.get_name
- type, klass = self.get_unpack("nn")
- return name, Resource.get_class(type, klass)
- end
-
- def get_rr
- name = self.get_name
- type, klass, ttl = self.get_unpack('nnN')
- typeclass = Resource.get_class(type, klass)
- res = self.get_length16 do
- begin
- typeclass.decode_rdata self
- rescue => e
- raise DecodeError, e.message, e.backtrace
- end
- end
- res.instance_variable_set :@ttl, ttl
- return name, ttl, res
- end
- end
- end
-
- ##
- # SvcParams for service binding RRs. [RFC9460]
-
- class SvcParams
- include Enumerable
-
- ##
- # Create a list of SvcParams with the given initial content.
- #
- # +params+ has to be an enumerable of +SvcParam+s.
- # If its content has +SvcParam+s with the duplicate key,
- # the one appears last takes precedence.
-
- def initialize(params = [])
- @params = {}
-
- params.each do |param|
- add param
- end
- end
-
- ##
- # Get SvcParam for the given +key+ in this list.
-
- def [](key)
- @params[canonical_key(key)]
- end
-
- ##
- # Get the number of SvcParams in this list.
-
- def count
- @params.count
- end
-
- ##
- # Get whether this list is empty.
-
- def empty?
- @params.empty?
- end
-
- ##
- # Add the SvcParam +param+ to this list, overwriting the existing one with the same key.
-
- def add(param)
- @params[param.class.key_number] = param
- end
-
- ##
- # Remove the +SvcParam+ with the given +key+ and return it.
-
- def delete(key)
- @params.delete(canonical_key(key))
- end
-
- ##
- # Enumerate the +SvcParam+s in this list.
-
- def each(&block)
- return enum_for(:each) unless block
- @params.each_value(&block)
- end
-
- def encode(msg) # :nodoc:
- @params.keys.sort.each do |key|
- msg.put_pack('n', key)
- msg.put_length16 do
- @params.fetch(key).encode(msg)
- end
- end
- end
-
- def self.decode(msg) # :nodoc:
- params = msg.get_list do
- key, = msg.get_unpack('n')
- msg.get_length16 do
- SvcParam::ClassHash[key].decode(msg)
- end
- end
-
- return self.new(params)
- end
-
- private
-
- def canonical_key(key) # :nodoc:
- case key
- when Integer
- key
- when /\Akey(\d+)\z/
- Integer($1)
- when Symbol
- SvcParam::ClassHash[key].key_number
- else
- raise TypeError, 'key must be either String or Symbol'
- end
- end
- end
-
-
- ##
- # Base class for SvcParam. [RFC9460]
-
- class SvcParam
-
- ##
- # Get the presentation name of the SvcParamKey.
-
- def self.key_name
- const_get(:KeyName)
- end
-
- ##
- # Get the registered number of the SvcParamKey.
-
- def self.key_number
- const_get(:KeyNumber)
- end
-
- ClassHash = Hash.new do |h, key| # :nodoc:
- case key
- when Integer
- Generic.create(key)
- when /\Akey(?<key>\d+)\z/
- Generic.create(key.to_int)
- when Symbol
- raise KeyError, "unknown key #{key}"
- else
- raise TypeError, 'key must be either String or Symbol'
- end
- end
-
- ##
- # Generic SvcParam abstract class.
-
- class Generic < SvcParam
-
- ##
- # SvcParamValue in wire-format byte string.
-
- attr_reader :value
-
- ##
- # Create generic SvcParam
-
- def initialize(value)
- @value = value
- end
-
- def encode(msg) # :nodoc:
- msg.put_bytes(@value)
- end
-
- def self.decode(msg) # :nodoc:
- return self.new(msg.get_bytes)
- end
-
- def self.create(key_number)
- c = Class.new(Generic)
- key_name = :"key#{key_number}"
- c.const_set(:KeyName, key_name)
- c.const_set(:KeyNumber, key_number)
- self.const_set(:"Key#{key_number}", c)
- ClassHash[key_name] = ClassHash[key_number] = c
- return c
- end
- end
-
- ##
- # "mandatory" SvcParam -- Mandatory keys in service binding RR
-
- class Mandatory < SvcParam
- KeyName = :mandatory
- KeyNumber = 0
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Mandatory keys.
-
- attr_reader :keys
-
- ##
- # Initialize "mandatory" ScvParam.
-
- def initialize(keys)
- @keys = keys.map(&:to_int)
- end
-
- def encode(msg) # :nodoc:
- @keys.sort.each do |key|
- msg.put_pack('n', key)
- end
- end
-
- def self.decode(msg) # :nodoc:
- keys = msg.get_list { msg.get_unpack('n')[0] }
- return self.new(keys)
- end
- end
-
- ##
- # "alpn" SvcParam -- Additional supported protocols
-
- class ALPN < SvcParam
- KeyName = :alpn
- KeyNumber = 1
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Supported protocol IDs.
-
- attr_reader :protocol_ids
-
- ##
- # Initialize "alpn" ScvParam.
-
- def initialize(protocol_ids)
- @protocol_ids = protocol_ids.map(&:to_str)
- end
-
- def encode(msg) # :nodoc:
- msg.put_string_list(@protocol_ids)
- end
-
- def self.decode(msg) # :nodoc:
- return self.new(msg.get_string_list)
- end
- end
-
- ##
- # "no-default-alpn" SvcParam -- No support for default protocol
-
- class NoDefaultALPN < SvcParam
- KeyName = :'no-default-alpn'
- KeyNumber = 2
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- def encode(msg) # :nodoc:
- # no payload
- end
-
- def self.decode(msg) # :nodoc:
- return self.new
- end
- end
-
- ##
- # "port" SvcParam -- Port for alternative endpoint
-
- class Port < SvcParam
- KeyName = :port
- KeyNumber = 3
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Port number.
-
- attr_reader :port
-
- ##
- # Initialize "port" ScvParam.
-
- def initialize(port)
- @port = port.to_int
- end
-
- def encode(msg) # :nodoc:
- msg.put_pack('n', @port)
- end
-
- def self.decode(msg) # :nodoc:
- port, = msg.get_unpack('n')
- return self.new(port)
- end
- end
-
- ##
- # "ipv4hint" SvcParam -- IPv4 address hints
-
- class IPv4Hint < SvcParam
- KeyName = :ipv4hint
- KeyNumber = 4
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Set of IPv4 addresses.
-
- attr_reader :addresses
-
- ##
- # Initialize "ipv4hint" ScvParam.
-
- def initialize(addresses)
- @addresses = addresses.map {|address| IPv4.create(address) }
- end
-
- def encode(msg) # :nodoc:
- @addresses.each do |address|
- msg.put_bytes(address.address)
- end
- end
-
- def self.decode(msg) # :nodoc:
- addresses = msg.get_list { IPv4.new(msg.get_bytes(4)) }
- return self.new(addresses)
- end
- end
-
- ##
- # "ipv6hint" SvcParam -- IPv6 address hints
-
- class IPv6Hint < SvcParam
- KeyName = :ipv6hint
- KeyNumber = 6
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # Set of IPv6 addresses.
-
- attr_reader :addresses
-
- ##
- # Initialize "ipv6hint" ScvParam.
-
- def initialize(addresses)
- @addresses = addresses.map {|address| IPv6.create(address) }
- end
-
- def encode(msg) # :nodoc:
- @addresses.each do |address|
- msg.put_bytes(address.address)
- end
- end
-
- def self.decode(msg) # :nodoc:
- addresses = msg.get_list { IPv6.new(msg.get_bytes(16)) }
- return self.new(addresses)
- end
- end
-
- ##
- # "dohpath" SvcParam -- DNS over HTTPS path template [RFC9461]
-
- class DoHPath < SvcParam
- KeyName = :dohpath
- KeyNumber = 7
- ClassHash[KeyName] = ClassHash[KeyNumber] = self # :nodoc:
-
- ##
- # URI template for DoH queries.
-
- attr_reader :template
-
- ##
- # Initialize "dohpath" ScvParam.
-
- def initialize(template)
- @template = template.encode('utf-8')
- end
-
- def encode(msg) # :nodoc:
- msg.put_bytes(@template)
- end
-
- def self.decode(msg) # :nodoc:
- template = msg.get_bytes.force_encoding('utf-8')
- return self.new(template)
- end
- end
- end
-
- ##
- # A DNS query abstract class.
-
- class Query
- def encode_rdata(msg) # :nodoc:
- raise EncodeError.new("#{self.class} is query.")
- end
-
- def self.decode_rdata(msg) # :nodoc:
- raise DecodeError.new("#{self.class} is query.")
- end
- end
-
- ##
- # A DNS resource abstract class.
-
- class Resource < Query
-
- ##
- # Remaining Time To Live for this Resource.
-
- attr_reader :ttl
-
- ClassHash = {} # :nodoc:
-
- def encode_rdata(msg) # :nodoc:
- raise NotImplementedError.new
- end
-
- def self.decode_rdata(msg) # :nodoc:
- raise NotImplementedError.new
- end
-
- def ==(other) # :nodoc:
- return false unless self.class == other.class
- s_ivars = self.instance_variables
- s_ivars.sort!
- s_ivars.delete :@ttl
- o_ivars = other.instance_variables
- o_ivars.sort!
- o_ivars.delete :@ttl
- return s_ivars == o_ivars &&
- s_ivars.collect {|name| self.instance_variable_get name} ==
- o_ivars.collect {|name| other.instance_variable_get name}
- end
-
- def eql?(other) # :nodoc:
- return self == other
- end
-
- def hash # :nodoc:
- h = 0
- vars = self.instance_variables
- vars.delete :@ttl
- vars.each {|name|
- h ^= self.instance_variable_get(name).hash
- }
- return h
- end
-
- def self.get_class(type_value, class_value) # :nodoc:
- return ClassHash[[type_value, class_value]] ||
- Generic.create(type_value, class_value)
- end
-
- ##
- # A generic resource abstract class.
-
- class Generic < Resource
-
- ##
- # Creates a new generic resource.
-
- def initialize(data)
- @data = data
- end
-
- ##
- # Data for this generic resource.
-
- attr_reader :data
-
- def encode_rdata(msg) # :nodoc:
- msg.put_bytes(data)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- return self.new(msg.get_bytes)
- end
-
- def self.create(type_value, class_value) # :nodoc:
- c = Class.new(Generic)
- c.const_set(:TypeValue, type_value)
- c.const_set(:ClassValue, class_value)
- Generic.const_set("Type#{type_value}_Class#{class_value}", c)
- ClassHash[[type_value, class_value]] = c
- return c
- end
- end
-
- ##
- # Domain Name resource abstract class.
-
- class DomainName < Resource
-
- ##
- # Creates a new DomainName from +name+.
-
- def initialize(name)
- @name = name
- end
-
- ##
- # The name of this DomainName.
-
- attr_reader :name
-
- def encode_rdata(msg) # :nodoc:
- msg.put_name(@name)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- return self.new(msg.get_name)
- end
- end
-
- # Standard (class generic) RRs
-
- ClassValue = nil # :nodoc:
-
- ##
- # An authoritative name server.
-
- class NS < DomainName
- TypeValue = 2 # :nodoc:
- end
-
- ##
- # The canonical name for an alias.
-
- class CNAME < DomainName
- TypeValue = 5 # :nodoc:
- end
-
- ##
- # Start Of Authority resource.
-
- class SOA < Resource
-
- TypeValue = 6 # :nodoc:
-
- ##
- # Creates a new SOA record. See the attr documentation for the
- # details of each argument.
-
- def initialize(mname, rname, serial, refresh, retry_, expire, minimum)
- @mname = mname
- @rname = rname
- @serial = serial
- @refresh = refresh
- @retry = retry_
- @expire = expire
- @minimum = minimum
- end
-
- ##
- # Name of the host where the master zone file for this zone resides.
-
- attr_reader :mname
-
- ##
- # The person responsible for this domain name.
-
- attr_reader :rname
-
- ##
- # The version number of the zone file.
-
- attr_reader :serial
-
- ##
- # How often, in seconds, a secondary name server is to check for
- # updates from the primary name server.
-
- attr_reader :refresh
-
- ##
- # How often, in seconds, a secondary name server is to retry after a
- # failure to check for a refresh.
-
- attr_reader :retry
-
- ##
- # Time in seconds that a secondary name server is to use the data
- # before refreshing from the primary name server.
-
- attr_reader :expire
-
- ##
- # The minimum number of seconds to be used for TTL values in RRs.
-
- attr_reader :minimum
-
- def encode_rdata(msg) # :nodoc:
- msg.put_name(@mname)
- msg.put_name(@rname)
- msg.put_pack('NNNNN', @serial, @refresh, @retry, @expire, @minimum)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- mname = msg.get_name
- rname = msg.get_name
- serial, refresh, retry_, expire, minimum = msg.get_unpack('NNNNN')
- return self.new(
- mname, rname, serial, refresh, retry_, expire, minimum)
- end
- end
-
- ##
- # A Pointer to another DNS name.
-
- class PTR < DomainName
- TypeValue = 12 # :nodoc:
- end
-
- ##
- # Host Information resource.
-
- class HINFO < Resource
-
- TypeValue = 13 # :nodoc:
-
- ##
- # Creates a new HINFO running +os+ on +cpu+.
-
- def initialize(cpu, os)
- @cpu = cpu
- @os = os
- end
-
- ##
- # CPU architecture for this resource.
-
- attr_reader :cpu
-
- ##
- # Operating system for this resource.
-
- attr_reader :os
-
- def encode_rdata(msg) # :nodoc:
- msg.put_string(@cpu)
- msg.put_string(@os)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- cpu = msg.get_string
- os = msg.get_string
- return self.new(cpu, os)
- end
- end
-
- ##
- # Mailing list or mailbox information.
-
- class MINFO < Resource
-
- TypeValue = 14 # :nodoc:
-
- def initialize(rmailbx, emailbx)
- @rmailbx = rmailbx
- @emailbx = emailbx
- end
-
- ##
- # Domain name responsible for this mail list or mailbox.
-
- attr_reader :rmailbx
-
- ##
- # Mailbox to use for error messages related to the mail list or mailbox.
-
- attr_reader :emailbx
-
- def encode_rdata(msg) # :nodoc:
- msg.put_name(@rmailbx)
- msg.put_name(@emailbx)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- rmailbx = msg.get_string
- emailbx = msg.get_string
- return self.new(rmailbx, emailbx)
- end
- end
-
- ##
- # Mail Exchanger resource.
-
- class MX < Resource
-
- TypeValue= 15 # :nodoc:
-
- ##
- # Creates a new MX record with +preference+, accepting mail at
- # +exchange+.
-
- def initialize(preference, exchange)
- @preference = preference
- @exchange = exchange
- end
-
- ##
- # The preference for this MX.
-
- attr_reader :preference
-
- ##
- # The host of this MX.
-
- attr_reader :exchange
-
- def encode_rdata(msg) # :nodoc:
- msg.put_pack('n', @preference)
- msg.put_name(@exchange)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- preference, = msg.get_unpack('n')
- exchange = msg.get_name
- return self.new(preference, exchange)
- end
- end
-
- ##
- # Unstructured text resource.
-
- class TXT < Resource
-
- TypeValue = 16 # :nodoc:
-
- def initialize(first_string, *rest_strings)
- @strings = [first_string, *rest_strings]
- end
-
- ##
- # Returns an Array of Strings for this TXT record.
-
- attr_reader :strings
-
- ##
- # Returns the concatenated string from +strings+.
-
- def data
- @strings.join("")
- end
-
- def encode_rdata(msg) # :nodoc:
- msg.put_string_list(@strings)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- strings = msg.get_string_list
- return self.new(*strings)
- end
- end
-
- ##
- # Location resource
-
- class LOC < Resource
-
- TypeValue = 29 # :nodoc:
-
- def initialize(version, ssize, hprecision, vprecision, latitude, longitude, altitude)
- @version = version
- @ssize = Gem::Resolv::LOC::Size.create(ssize)
- @hprecision = Gem::Resolv::LOC::Size.create(hprecision)
- @vprecision = Gem::Resolv::LOC::Size.create(vprecision)
- @latitude = Gem::Resolv::LOC::Coord.create(latitude)
- @longitude = Gem::Resolv::LOC::Coord.create(longitude)
- @altitude = Gem::Resolv::LOC::Alt.create(altitude)
- end
-
- ##
- # Returns the version value for this LOC record which should always be 00
-
- attr_reader :version
-
- ##
- # The spherical size of this LOC
- # in meters using scientific notation as 2 integers of XeY
-
- attr_reader :ssize
-
- ##
- # The horizontal precision using ssize type values
- # in meters using scientific notation as 2 integers of XeY
- # for precision use value/2 e.g. 2m = +/-1m
-
- attr_reader :hprecision
-
- ##
- # The vertical precision using ssize type values
- # in meters using scientific notation as 2 integers of XeY
- # for precision use value/2 e.g. 2m = +/-1m
-
- attr_reader :vprecision
-
- ##
- # The latitude for this LOC where 2**31 is the equator
- # in thousandths of an arc second as an unsigned 32bit integer
-
- attr_reader :latitude
-
- ##
- # The longitude for this LOC where 2**31 is the prime meridian
- # in thousandths of an arc second as an unsigned 32bit integer
-
- attr_reader :longitude
-
- ##
- # The altitude of the LOC above a reference sphere whose surface sits 100km below the WGS84 spheroid
- # in centimeters as an unsigned 32bit integer
-
- attr_reader :altitude
-
-
- def encode_rdata(msg) # :nodoc:
- msg.put_bytes(@version)
- msg.put_bytes(@ssize.scalar)
- msg.put_bytes(@hprecision.scalar)
- msg.put_bytes(@vprecision.scalar)
- msg.put_bytes(@latitude.coordinates)
- msg.put_bytes(@longitude.coordinates)
- msg.put_bytes(@altitude.altitude)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- version = msg.get_bytes(1)
- ssize = msg.get_bytes(1)
- hprecision = msg.get_bytes(1)
- vprecision = msg.get_bytes(1)
- latitude = msg.get_bytes(4)
- longitude = msg.get_bytes(4)
- altitude = msg.get_bytes(4)
- return self.new(
- version,
- Gem::Resolv::LOC::Size.new(ssize),
- Gem::Resolv::LOC::Size.new(hprecision),
- Gem::Resolv::LOC::Size.new(vprecision),
- Gem::Resolv::LOC::Coord.new(latitude,"lat"),
- Gem::Resolv::LOC::Coord.new(longitude,"lon"),
- Gem::Resolv::LOC::Alt.new(altitude)
- )
- end
- end
-
- ##
- # A Query type requesting any RR.
-
- class ANY < Query
- TypeValue = 255 # :nodoc:
- end
-
- ##
- # CAA resource record defined in RFC 8659
- #
- # These records identify certificate authority allowed to issue
- # certificates for the given domain.
-
- class CAA < Resource
- TypeValue = 257
-
- ##
- # Creates a new CAA for +flags+, +tag+ and +value+.
-
- def initialize(flags, tag, value)
- unless (0..255) === flags
- raise ArgumentError.new('flags must be an Integer between 0 and 255')
- end
- unless (1..15) === tag.bytesize
- raise ArgumentError.new('length of tag must be between 1 and 15')
- end
-
- @flags = flags
- @tag = tag
- @value = value
- end
-
- ##
- # Flags for this proprty:
- # - Bit 0 : 0 = not critical, 1 = critical
-
- attr_reader :flags
-
- ##
- # Property tag ("issue", "issuewild", "iodef"...).
-
- attr_reader :tag
-
- ##
- # Property value.
-
- attr_reader :value
-
- ##
- # Whether the critical flag is set on this property.
-
- def critical?
- flags & 0x80 != 0
- end
-
- def encode_rdata(msg) # :nodoc:
- msg.put_pack('C', @flags)
- msg.put_string(@tag)
- msg.put_bytes(@value)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- flags, = msg.get_unpack('C')
- tag = msg.get_string
- value = msg.get_bytes
- self.new flags, tag, value
- end
- end
-
- ClassInsensitiveTypes = [ # :nodoc:
- NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, LOC, ANY, CAA
- ]
-
- ##
- # module IN contains ARPA Internet specific RRs.
-
- module IN
-
- ClassValue = 1 # :nodoc:
-
- ClassInsensitiveTypes.each {|s|
- c = Class.new(s)
- c.const_set(:TypeValue, s::TypeValue)
- c.const_set(:ClassValue, ClassValue)
- ClassHash[[s::TypeValue, ClassValue]] = c
- self.const_set(s.name.sub(/.*::/, ''), c)
- }
-
- ##
- # IPv4 Address resource
-
- class A < Resource
- TypeValue = 1
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
-
- ##
- # Creates a new A for +address+.
-
- def initialize(address)
- @address = IPv4.create(address)
- end
-
- ##
- # The Gem::Resolv::IPv4 address for this A.
-
- attr_reader :address
-
- def encode_rdata(msg) # :nodoc:
- msg.put_bytes(@address.address)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- return self.new(IPv4.new(msg.get_bytes(4)))
- end
- end
-
- ##
- # Well Known Service resource.
-
- class WKS < Resource
- TypeValue = 11
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
-
- def initialize(address, protocol, bitmap)
- @address = IPv4.create(address)
- @protocol = protocol
- @bitmap = bitmap
- end
-
- ##
- # The host these services run on.
-
- attr_reader :address
-
- ##
- # IP protocol number for these services.
-
- attr_reader :protocol
-
- ##
- # A bit map of enabled services on this host.
- #
- # If protocol is 6 (TCP) then the 26th bit corresponds to the SMTP
- # service (port 25). If this bit is set, then an SMTP server should
- # be listening on TCP port 25; if zero, SMTP service is not
- # supported.
-
- attr_reader :bitmap
-
- def encode_rdata(msg) # :nodoc:
- msg.put_bytes(@address.address)
- msg.put_pack("n", @protocol)
- msg.put_bytes(@bitmap)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- address = IPv4.new(msg.get_bytes(4))
- protocol, = msg.get_unpack("n")
- bitmap = msg.get_bytes
- return self.new(address, protocol, bitmap)
- end
- end
-
- ##
- # An IPv6 address record.
-
- class AAAA < Resource
- TypeValue = 28
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
-
- ##
- # Creates a new AAAA for +address+.
-
- def initialize(address)
- @address = IPv6.create(address)
- end
-
- ##
- # The Gem::Resolv::IPv6 address for this AAAA.
-
- attr_reader :address
-
- def encode_rdata(msg) # :nodoc:
- msg.put_bytes(@address.address)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- return self.new(IPv6.new(msg.get_bytes(16)))
- end
- end
-
- ##
- # SRV resource record defined in RFC 2782
- #
- # These records identify the hostname and port that a service is
- # available at.
-
- class SRV < Resource
- TypeValue = 33
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
-
- # Create a SRV resource record.
- #
- # See the documentation for #priority, #weight, #port and #target
- # for +priority+, +weight+, +port and +target+ respectively.
-
- def initialize(priority, weight, port, target)
- @priority = priority.to_int
- @weight = weight.to_int
- @port = port.to_int
- @target = Name.create(target)
- end
-
- # The priority of this target host.
- #
- # A client MUST attempt to contact the target host with the
- # lowest-numbered priority it can reach; target hosts with the same
- # priority SHOULD be tried in an order defined by the weight field.
- # The range is 0-65535. Note that it is not widely implemented and
- # should be set to zero.
-
- attr_reader :priority
-
- # A server selection mechanism.
- #
- # The weight field specifies a relative weight for entries with the
- # same priority. Larger weights SHOULD be given a proportionately
- # higher probability of being selected. The range of this number is
- # 0-65535. Domain administrators SHOULD use Weight 0 when there
- # isn't any server selection to do, to make the RR easier to read
- # for humans (less noisy). Note that it is not widely implemented
- # and should be set to zero.
-
- attr_reader :weight
-
- # The port on this target host of this service.
- #
- # The range is 0-65535.
-
- attr_reader :port
-
- # The domain name of the target host.
- #
- # A target of "." means that the service is decidedly not available
- # at this domain.
-
- attr_reader :target
-
- def encode_rdata(msg) # :nodoc:
- msg.put_pack("n", @priority)
- msg.put_pack("n", @weight)
- msg.put_pack("n", @port)
- msg.put_name(@target, compress: false)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- priority, = msg.get_unpack("n")
- weight, = msg.get_unpack("n")
- port, = msg.get_unpack("n")
- target = msg.get_name
- return self.new(priority, weight, port, target)
- end
- end
-
- ##
- # Common implementation for SVCB-compatible resource records.
-
- class ServiceBinding
-
- ##
- # Create a service binding resource record.
-
- def initialize(priority, target, params = [])
- @priority = priority.to_int
- @target = Name.create(target)
- @params = SvcParams.new(params)
- end
-
- ##
- # The priority of this target host.
- #
- # The range is 0-65535.
- # If set to 0, this RR is in AliasMode. Otherwise, it is in ServiceMode.
-
- attr_reader :priority
-
- ##
- # The domain name of the target host.
-
- attr_reader :target
-
- ##
- # The service parameters for the target host.
-
- attr_reader :params
-
- ##
- # Whether this RR is in AliasMode.
-
- def alias_mode?
- self.priority == 0
- end
-
- ##
- # Whether this RR is in ServiceMode.
-
- def service_mode?
- !alias_mode?
- end
-
- def encode_rdata(msg) # :nodoc:
- msg.put_pack("n", @priority)
- msg.put_name(@target, compress: false)
- @params.encode(msg)
- end
-
- def self.decode_rdata(msg) # :nodoc:
- priority, = msg.get_unpack("n")
- target = msg.get_name
- params = SvcParams.decode(msg)
- return self.new(priority, target, params)
- end
- end
-
- ##
- # SVCB resource record [RFC9460]
-
- class SVCB < ServiceBinding
- TypeValue = 64
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
- end
-
- ##
- # HTTPS resource record [RFC9460]
-
- class HTTPS < ServiceBinding
- TypeValue = 65
- ClassValue = IN::ClassValue
- ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
- end
- end
- end
- end
-
- ##
- # A Gem::Resolv::DNS IPv4 address.
-
- class IPv4
-
- ##
- # Regular expression IPv4 addresses must match.
-
- Regex256 = /0
- |1(?:[0-9][0-9]?)?
- |2(?:[0-4][0-9]?|5[0-5]?|[6-9])?
- |[3-9][0-9]?/x
- Regex = /\A(#{Regex256})\.(#{Regex256})\.(#{Regex256})\.(#{Regex256})\z/
-
- def self.create(arg)
- case arg
- when IPv4
- return arg
- when Regex
- if (0..255) === (a = $1.to_i) &&
- (0..255) === (b = $2.to_i) &&
- (0..255) === (c = $3.to_i) &&
- (0..255) === (d = $4.to_i)
- return self.new([a, b, c, d].pack("CCCC"))
- else
- raise ArgumentError.new("IPv4 address with invalid value: " + arg)
- end
- else
- raise ArgumentError.new("cannot interpret as IPv4 address: #{arg.inspect}")
- end
- end
-
- def initialize(address) # :nodoc:
- unless address.kind_of?(String)
- raise ArgumentError, 'IPv4 address must be a string'
- end
- unless address.length == 4
- raise ArgumentError, "IPv4 address expects 4 bytes but #{address.length} bytes"
- end
- @address = address
- end
-
- ##
- # A String representation of this IPv4 address.
-
- ##
- # The raw IPv4 address as a String.
-
- attr_reader :address
-
- def to_s # :nodoc:
- return sprintf("%d.%d.%d.%d", *@address.unpack("CCCC"))
- end
-
- def inspect # :nodoc:
- return "#<#{self.class} #{self}>"
- end
-
- ##
- # Turns this IPv4 address into a Gem::Resolv::DNS::Name.
-
- def to_name
- return DNS::Name.create(
- '%d.%d.%d.%d.in-addr.arpa.' % @address.unpack('CCCC').reverse)
- end
-
- def ==(other) # :nodoc:
- return @address == other.address
- end
-
- def eql?(other) # :nodoc:
- return self == other
- end
-
- def hash # :nodoc:
- return @address.hash
- end
- end
-
- ##
- # A Gem::Resolv::DNS IPv6 address.
-
- class IPv6
-
- ##
- # IPv6 address format a:b:c:d:e:f:g:h
- Regex_8Hex = /\A
- (?:[0-9A-Fa-f]{1,4}:){7}
- [0-9A-Fa-f]{1,4}
- \z/x
-
- ##
- # Compressed IPv6 address format a::b
-
- Regex_CompressedHex = /\A
- ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
- ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
- \z/x
-
- ##
- # IPv4 mapped IPv6 address format a:b:c:d:e:f:w.x.y.z
-
- Regex_6Hex4Dec = /\A
- ((?:[0-9A-Fa-f]{1,4}:){6,6})
- (\d+)\.(\d+)\.(\d+)\.(\d+)
- \z/x
-
- ##
- # Compressed IPv4 mapped IPv6 address format a::b:w.x.y.z
-
- Regex_CompressedHex4Dec = /\A
- ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
- ((?:[0-9A-Fa-f]{1,4}:)*)
- (\d+)\.(\d+)\.(\d+)\.(\d+)
- \z/x
-
- ##
- # IPv6 link local address format fe80:b:c:d:e:f:g:h%em1
- Regex_8HexLinkLocal = /\A
- [Ff][Ee]80
- (?::[0-9A-Fa-f]{1,4}){7}
- %[-0-9A-Za-z._~]+
- \z/x
-
- ##
- # Compressed IPv6 link local address format fe80::b%em1
-
- Regex_CompressedHexLinkLocal = /\A
- [Ff][Ee]80:
- (?:
- ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
- ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
- |
- :((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
- )?
- :[0-9A-Fa-f]{1,4}%[-0-9A-Za-z._~]+
- \z/x
-
- ##
- # A composite IPv6 address Regexp.
-
- Regex = /
- (?:#{Regex_8Hex}) |
- (?:#{Regex_CompressedHex}) |
- (?:#{Regex_6Hex4Dec}) |
- (?:#{Regex_CompressedHex4Dec}) |
- (?:#{Regex_8HexLinkLocal}) |
- (?:#{Regex_CompressedHexLinkLocal})
- /x
-
- ##
- # Creates a new IPv6 address from +arg+ which may be:
- #
- # IPv6:: returns +arg+.
- # String:: +arg+ must match one of the IPv6::Regex* constants
-
- def self.create(arg)
- case arg
- when IPv6
- return arg
- when String
- address = ''.b
- if Regex_8Hex =~ arg
- arg.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
- elsif Regex_CompressedHex =~ arg
- prefix = $1
- suffix = $2
- a1 = ''.b
- a2 = ''.b
- prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
- suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
- omitlen = 16 - a1.length - a2.length
- address << a1 << "\0" * omitlen << a2
- elsif Regex_6Hex4Dec =~ arg
- prefix, a, b, c, d = $1, $2.to_i, $3.to_i, $4.to_i, $5.to_i
- if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
- prefix.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
- address << [a, b, c, d].pack('CCCC')
- else
- raise ArgumentError.new("not numeric IPv6 address: " + arg)
- end
- elsif Regex_CompressedHex4Dec =~ arg
- prefix, suffix, a, b, c, d = $1, $2, $3.to_i, $4.to_i, $5.to_i, $6.to_i
- if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
- a1 = ''.b
- a2 = ''.b
- prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
- suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
- omitlen = 12 - a1.length - a2.length
- address << a1 << "\0" * omitlen << a2 << [a, b, c, d].pack('CCCC')
- else
- raise ArgumentError.new("not numeric IPv6 address: " + arg)
- end
- else
- raise ArgumentError.new("not numeric IPv6 address: " + arg)
- end
- return IPv6.new(address)
- else
- raise ArgumentError.new("cannot interpret as IPv6 address: #{arg.inspect}")
- end
- end
-
- def initialize(address) # :nodoc:
- unless address.kind_of?(String) && address.length == 16
- raise ArgumentError.new('IPv6 address must be 16 bytes')
- end
- @address = address
- end
-
- ##
- # The raw IPv6 address as a String.
-
- attr_reader :address
-
- def to_s # :nodoc:
- sprintf("%x:%x:%x:%x:%x:%x:%x:%x", *@address.unpack("nnnnnnnn")).sub(/(^|:)0(:0)+(:|$)/, '::')
- end
-
- def inspect # :nodoc:
- return "#<#{self.class} #{self}>"
- end
-
- ##
- # Turns this IPv6 address into a Gem::Resolv::DNS::Name.
- #--
- # ip6.arpa should be searched too. [RFC3152]
-
- def to_name
- return DNS::Name.new(
- @address.unpack("H32")[0].split(//).reverse + ['ip6', 'arpa'])
- end
-
- def ==(other) # :nodoc:
- return @address == other.address
- end
-
- def eql?(other) # :nodoc:
- return self == other
- end
-
- def hash # :nodoc:
- return @address.hash
- end
- end
-
- ##
- # Gem::Resolv::MDNS is a one-shot Multicast DNS (mDNS) resolver. It blindly
- # makes queries to the mDNS addresses without understanding anything about
- # multicast ports.
- #
- # Information taken form the following places:
- #
- # * RFC 6762
-
- class MDNS < DNS
-
- ##
- # Default mDNS Port
-
- Port = 5353
-
- ##
- # Default IPv4 mDNS address
-
- AddressV4 = '224.0.0.251'
-
- ##
- # Default IPv6 mDNS address
-
- AddressV6 = 'ff02::fb'
-
- ##
- # Default mDNS addresses
-
- Addresses = [
- [AddressV4, Port],
- [AddressV6, Port],
- ]
-
- ##
- # Creates a new one-shot Multicast DNS (mDNS) resolver.
- #
- # +config_info+ can be:
- #
- # nil::
- # Uses the default mDNS addresses
- #
- # Hash::
- # Must contain :nameserver or :nameserver_port like
- # Gem::Resolv::DNS#initialize.
-
- def initialize(config_info=nil)
- if config_info then
- super({ nameserver_port: Addresses }.merge(config_info))
- else
- super(nameserver_port: Addresses)
- end
- end
-
- ##
- # Iterates over all IP addresses for +name+ retrieved from the mDNS
- # resolver, provided name ends with "local". If the name does not end in
- # "local" no records will be returned.
- #
- # +name+ can be a Gem::Resolv::DNS::Name or a String. Retrieved addresses will
- # be a Gem::Resolv::IPv4 or Gem::Resolv::IPv6
-
- def each_address(name)
- name = Gem::Resolv::DNS::Name.create(name)
-
- return unless name[-1].to_s == 'local'
-
- super(name)
- end
-
- def make_udp_requester # :nodoc:
- nameserver_port = @config.nameserver_port
- Requester::MDNSOneShot.new(*nameserver_port)
- end
-
- end
-
- module LOC
-
- ##
- # A Gem::Resolv::LOC::Size
-
- class Size
-
- Regex = /^(\d+\.*\d*)[m]$/
-
- ##
- # Creates a new LOC::Size from +arg+ which may be:
- #
- # LOC::Size:: returns +arg+.
- # String:: +arg+ must match the LOC::Size::Regex constant
-
- def self.create(arg)
- case arg
- when Size
- return arg
- when String
- scalar = ''
- if Regex =~ arg
- scalar = [(($1.to_f*(1e2)).to_i.to_s[0].to_i*(2**4)+(($1.to_f*(1e2)).to_i.to_s.length-1))].pack("C")
- else
- raise ArgumentError.new("not a properly formed Size string: " + arg)
- end
- return Size.new(scalar)
- else
- raise ArgumentError.new("cannot interpret as Size: #{arg.inspect}")
- end
- end
-
- def initialize(scalar)
- @scalar = scalar
- end
-
- ##
- # The raw size
-
- attr_reader :scalar
-
- def to_s # :nodoc:
- s = @scalar.unpack("H2").join.to_s
- return ((s[0].to_i)*(10**(s[1].to_i-2))).to_s << "m"
- end
-
- def inspect # :nodoc:
- return "#<#{self.class} #{self}>"
- end
-
- def ==(other) # :nodoc:
- return @scalar == other.scalar
- end
-
- def eql?(other) # :nodoc:
- return self == other
- end
-
- def hash # :nodoc:
- return @scalar.hash
- end
-
- end
-
- ##
- # A Gem::Resolv::LOC::Coord
-
- class Coord
-
- Regex = /^(\d+)\s(\d+)\s(\d+\.\d+)\s([NESW])$/
-
- ##
- # Creates a new LOC::Coord from +arg+ which may be:
- #
- # LOC::Coord:: returns +arg+.
- # String:: +arg+ must match the LOC::Coord::Regex constant
-
- def self.create(arg)
- case arg
- when Coord
- return arg
- when String
- coordinates = ''
- if Regex =~ arg && $1.to_f < 180
- m = $~
- hemi = (m[4][/[NE]/]) || (m[4][/[SW]/]) ? 1 : -1
- coordinates = [ ((m[1].to_i*(36e5)) + (m[2].to_i*(6e4)) +
- (m[3].to_f*(1e3))) * hemi+(2**31) ].pack("N")
- orientation = m[4][/[NS]/] ? 'lat' : 'lon'
- else
- raise ArgumentError.new("not a properly formed Coord string: " + arg)
- end
- return Coord.new(coordinates,orientation)
- else
- raise ArgumentError.new("cannot interpret as Coord: #{arg.inspect}")
- end
- end
-
- def initialize(coordinates,orientation)
- unless coordinates.kind_of?(String)
- raise ArgumentError.new("Coord must be a 32bit unsigned integer in hex format: #{coordinates.inspect}")
- end
- unless orientation.kind_of?(String) && orientation[/^lon$|^lat$/]
- raise ArgumentError.new('Coord expects orientation to be a String argument of "lat" or "lon"')
- end
- @coordinates = coordinates
- @orientation = orientation
- end
-
- ##
- # The raw coordinates
-
- attr_reader :coordinates
-
- ## The orientation of the hemisphere as 'lat' or 'lon'
-
- attr_reader :orientation
-
- def to_s # :nodoc:
- c = @coordinates.unpack("N").join.to_i
- val = (c - (2**31)).abs
- fracsecs = (val % 1e3).to_i.to_s
- val = val / 1e3
- secs = (val % 60).to_i.to_s
- val = val / 60
- mins = (val % 60).to_i.to_s
- degs = (val / 60).to_i.to_s
- posi = (c >= 2**31)
- case posi
- when true
- hemi = @orientation[/^lat$/] ? "N" : "E"
- else
- hemi = @orientation[/^lon$/] ? "W" : "S"
- end
- return degs << " " << mins << " " << secs << "." << fracsecs << " " << hemi
- end
-
- def inspect # :nodoc:
- return "#<#{self.class} #{self}>"
- end
-
- def ==(other) # :nodoc:
- return @coordinates == other.coordinates
- end
-
- def eql?(other) # :nodoc:
- return self == other
- end
-
- def hash # :nodoc:
- return @coordinates.hash
- end
-
- end
-
- ##
- # A Gem::Resolv::LOC::Alt
-
- class Alt
-
- Regex = /^([+-]*\d+\.*\d*)[m]$/
-
- ##
- # Creates a new LOC::Alt from +arg+ which may be:
- #
- # LOC::Alt:: returns +arg+.
- # String:: +arg+ must match the LOC::Alt::Regex constant
-
- def self.create(arg)
- case arg
- when Alt
- return arg
- when String
- altitude = ''
- if Regex =~ arg
- altitude = [($1.to_f*(1e2))+(1e7)].pack("N")
- else
- raise ArgumentError.new("not a properly formed Alt string: " + arg)
- end
- return Alt.new(altitude)
- else
- raise ArgumentError.new("cannot interpret as Alt: #{arg.inspect}")
- end
- end
-
- def initialize(altitude)
- @altitude = altitude
- end
-
- ##
- # The raw altitude
-
- attr_reader :altitude
-
- def to_s # :nodoc:
- a = @altitude.unpack("N").join.to_i
- return ((a.to_f/1e2)-1e5).to_s + "m"
- end
-
- def inspect # :nodoc:
- return "#<#{self.class} #{self}>"
- end
-
- def ==(other) # :nodoc:
- return @altitude == other.altitude
- end
-
- def eql?(other) # :nodoc:
- return self == other
- end
-
- def hash # :nodoc:
- return @altitude.hash
- end
-
- end
-
- end
-
- ##
- # Default resolver to use for Gem::Resolv class methods.
-
- DefaultResolver = self.new
-
- ##
- # Replaces the resolvers in the default resolver with +new_resolvers+. This
- # allows resolvers to be changed for resolv-replace.
-
- def DefaultResolver.replace_resolvers new_resolvers
- @resolvers = new_resolvers
- end
-
- ##
- # Address Regexp to use for matching IP addresses.
-
- AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/
-
-end
-
diff --git a/lib/rubygems/vendor/securerandom/.document b/lib/rubygems/vendor/securerandom/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/securerandom/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/securerandom/lib/random/formatter.rb b/lib/rubygems/vendor/securerandom/lib/random/formatter.rb
deleted file mode 100644
index 3544033340..0000000000
--- a/lib/rubygems/vendor/securerandom/lib/random/formatter.rb
+++ /dev/null
@@ -1,373 +0,0 @@
-# -*- coding: us-ascii -*-
-# frozen_string_literal: true
-
-# == \Random number formatter.
-#
-# Formats generated random numbers in many manners. When <tt>'random/formatter'</tt>
-# is required, several methods are added to empty core module <tt>Gem::Random::Formatter</tt>,
-# making them available as Random's instance and module methods.
-#
-# Standard library Gem::SecureRandom is also extended with the module, and the methods
-# described below are available as a module methods in it.
-#
-# === Examples
-#
-# Generate random hexadecimal strings:
-#
-# require 'rubygems/vendor/securerandom/lib/random/formatter'
-#
-# prng = Random.new
-# prng.hex(10) #=> "52750b30ffbc7de3b362"
-# prng.hex(10) #=> "92b15d6c8dc4beb5f559"
-# prng.hex(13) #=> "39b290146bea6ce975c37cfc23"
-# # or just
-# Random.hex #=> "1aed0c631e41be7f77365415541052ee"
-#
-# Generate random base64 strings:
-#
-# prng.base64(10) #=> "EcmTPZwWRAozdA=="
-# prng.base64(10) #=> "KO1nIU+p9DKxGg=="
-# prng.base64(12) #=> "7kJSM/MzBJI+75j8"
-# Random.base64(4) #=> "bsQ3fQ=="
-#
-# Generate random binary strings:
-#
-# prng.random_bytes(10) #=> "\016\t{\370g\310pbr\301"
-# prng.random_bytes(10) #=> "\323U\030TO\234\357\020\a\337"
-# Random.random_bytes(6) #=> "\xA1\xE6Lr\xC43"
-#
-# Generate alphanumeric strings:
-#
-# prng.alphanumeric(10) #=> "S8baxMJnPl"
-# prng.alphanumeric(10) #=> "aOxAg8BAJe"
-# Random.alphanumeric #=> "TmP9OsJHJLtaZYhP"
-#
-# Generate UUIDs:
-#
-# prng.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
-# prng.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
-# Random.uuid #=> "f14e0271-de96-45cc-8911-8910292a42cd"
-#
-# All methods are available in the standard library Gem::SecureRandom, too:
-#
-# Gem::SecureRandom.hex #=> "05b45376a30c67238eb93b16499e50cf"
-
-module Gem::Random::Formatter
-
- # Generate a random binary string.
- #
- # The argument _n_ specifies the length of the result string.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in future.
- #
- # The result may contain any byte: "\x00" - "\xff".
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # Random.random_bytes #=> "\xD8\\\xE0\xF4\r\xB2\xFC*WM\xFF\x83\x18\xF45\xB6"
- # # or
- # prng = Random.new
- # prng.random_bytes #=> "m\xDC\xFC/\a\x00Uf\xB2\xB2P\xBD\xFF6S\x97"
- def random_bytes(n=nil)
- n = n ? n.to_int : 16
- gen_random(n)
- end
-
- # Generate a random hexadecimal string.
- #
- # The argument _n_ specifies the length, in bytes, of the random number to be generated.
- # The length of the resulting hexadecimal string is twice of _n_.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in the future.
- #
- # The result may contain 0-9 and a-f.
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # Random.hex #=> "eb693ec8252cd630102fd0d0fb7c3485"
- # # or
- # prng = Random.new
- # prng.hex #=> "91dc3bfb4de5b11d029d376634589b61"
- def hex(n=nil)
- random_bytes(n).unpack1("H*")
- end
-
- # Generate a random base64 string.
- #
- # The argument _n_ specifies the length, in bytes, of the random number
- # to be generated. The length of the result string is about 4/3 of _n_.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in the future.
- #
- # The result may contain A-Z, a-z, 0-9, "+", "/" and "=".
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # Random.base64 #=> "/2BuBuLf3+WfSKyQbRcc/A=="
- # # or
- # prng = Random.new
- # prng.base64 #=> "6BbW0pxO0YENxn38HMUbcQ=="
- #
- # See RFC 3548 for the definition of base64.
- def base64(n=nil)
- [random_bytes(n)].pack("m0")
- end
-
- # Generate a random URL-safe base64 string.
- #
- # The argument _n_ specifies the length, in bytes, of the random number
- # to be generated. The length of the result string is about 4/3 of _n_.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in the future.
- #
- # The boolean argument _padding_ specifies the padding.
- # If it is false or nil, padding is not generated.
- # Otherwise padding is generated.
- # By default, padding is not generated because "=" may be used as a URL delimiter.
- #
- # The result may contain A-Z, a-z, 0-9, "-" and "_".
- # "=" is also used if _padding_ is true.
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # Random.urlsafe_base64 #=> "b4GOKm4pOYU_-BOXcrUGDg"
- # # or
- # prng = Random.new
- # prng.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
- #
- # prng.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="
- # prng.urlsafe_base64(nil, true) #=> "-M8rLhr7JEpJlqFGUMmOxg=="
- #
- # See RFC 3548 for the definition of URL-safe base64.
- def urlsafe_base64(n=nil, padding=false)
- s = [random_bytes(n)].pack("m0")
- s.tr!("+/", "-_")
- s.delete!("=") unless padding
- s
- end
-
- # Generate a random v4 UUID (Universally Unique IDentifier).
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # Random.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"
- # Random.uuid #=> "bad85eb9-0713-4da7-8d36-07a8e4b00eab"
- # # or
- # prng = Random.new
- # prng.uuid #=> "62936e70-1815-439b-bf89-8492855a7e6b"
- #
- # The version 4 UUID is purely random (except the version).
- # It doesn't contain meaningful information such as MAC addresses, timestamps, etc.
- #
- # The result contains 122 random bits (15.25 random bytes).
- #
- # See RFC4122[https://datatracker.ietf.org/doc/html/rfc4122] for details of UUID.
- #
- def uuid
- ary = random_bytes(16).unpack("NnnnnN")
- ary[2] = (ary[2] & 0x0fff) | 0x4000
- ary[3] = (ary[3] & 0x3fff) | 0x8000
- "%08x-%04x-%04x-%04x-%04x%08x" % ary
- end
-
- alias uuid_v4 uuid
-
- # Generate a random v7 UUID (Universally Unique IDentifier).
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # Random.uuid_v7 # => "0188d4c3-1311-7f96-85c7-242a7aa58f1e"
- # Random.uuid_v7 # => "0188d4c3-16fe-744f-86af-38fa04c62bb5"
- # Random.uuid_v7 # => "0188d4c3-1af8-764f-b049-c204ce0afa23"
- # Random.uuid_v7 # => "0188d4c3-1e74-7085-b14f-ef6415dc6f31"
- # # |<--sorted-->| |<----- random ---->|
- #
- # # or
- # prng = Random.new
- # prng.uuid_v7 # => "0188ca51-5e72-7950-a11d-def7ff977c98"
- #
- # The version 7 UUID starts with the least significant 48 bits of a 64 bit
- # Unix timestamp (milliseconds since the epoch) and fills the remaining bits
- # with random data, excluding the version and variant bits.
- #
- # This allows version 7 UUIDs to be sorted by creation time. Time ordered
- # UUIDs can be used for better database index locality of newly inserted
- # records, which may have a significant performance benefit compared to random
- # data inserts.
- #
- # The result contains 74 random bits (9.25 random bytes).
- #
- # Note that this method cannot be made reproducable because its output
- # includes not only random bits but also timestamp.
- #
- # See draft-ietf-uuidrev-rfc4122bis[https://datatracker.ietf.org/doc/draft-ietf-uuidrev-rfc4122bis/]
- # for details of UUIDv7.
- #
- # ==== Monotonicity
- #
- # UUIDv7 has millisecond precision by default, so multiple UUIDs created
- # within the same millisecond are not issued in monotonically increasing
- # order. To create UUIDs that are time-ordered with sub-millisecond
- # precision, up to 12 bits of additional timestamp may added with
- # +extra_timestamp_bits+. The extra timestamp precision comes at the expense
- # of random bits. Setting <tt>extra_timestamp_bits: 12</tt> provides ~244ns
- # of precision, but only 62 random bits (7.75 random bytes).
- #
- # prng = Random.new
- # Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 12) }
- # # =>
- # ["0188d4c7-13da-74f9-8b53-22a786ffdd5a",
- # "0188d4c7-13da-753b-83a5-7fb9b2afaeea",
- # "0188d4c7-13da-754a-88ea-ac0baeedd8db",
- # "0188d4c7-13da-7557-83e1-7cad9cda0d8d"]
- # # |<--- sorted --->| |<-- random --->|
- #
- # Array.new(4) { prng.uuid_v7(extra_timestamp_bits: 8) }
- # # =>
- # ["0188d4c7-3333-7a95-850a-de6edb858f7e",
- # "0188d4c7-3333-7ae8-842e-bc3a8b7d0cf9", # <- out of order
- # "0188d4c7-3333-7ae2-995a-9f135dc44ead", # <- out of order
- # "0188d4c7-3333-7af9-87c3-8f612edac82e"]
- # # |<--- sorted -->||<---- random --->|
- #
- # Any rollbacks of the system clock will break monotonicity. UUIDv7 is based
- # on UTC, which excludes leap seconds and can rollback the clock. To avoid
- # this, the system clock can synchronize with an NTP server configured to use
- # a "leap smear" approach. NTP or PTP will also be needed to synchronize
- # across distributed nodes.
- #
- # Counters and other mechanisms for stronger guarantees of monotonicity are
- # not implemented. Applications with stricter requirements should follow
- # {Section 6.2}[https://www.ietf.org/archive/id/draft-ietf-uuidrev-rfc4122bis-07.html#monotonicity_counters]
- # of the specification.
- #
- def uuid_v7(extra_timestamp_bits: 0)
- case (extra_timestamp_bits = Integer(extra_timestamp_bits))
- when 0 # min timestamp precision
- ms = Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
- rand = random_bytes(10)
- rand.setbyte(0, rand.getbyte(0) & 0x0f | 0x70) # version
- rand.setbyte(2, rand.getbyte(2) & 0x3f | 0x80) # variant
- "%08x-%04x-%s" % [
- (ms & 0x0000_ffff_ffff_0000) >> 16,
- (ms & 0x0000_0000_0000_ffff),
- rand.unpack("H4H4H12").join("-")
- ]
-
- when 12 # max timestamp precision
- ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
- .divmod(1_000_000)
- extra_bits = ns * 4096 / 1_000_000
- rand = random_bytes(8)
- rand.setbyte(0, rand.getbyte(0) & 0x3f | 0x80) # variant
- "%08x-%04x-7%03x-%s" % [
- (ms & 0x0000_ffff_ffff_0000) >> 16,
- (ms & 0x0000_0000_0000_ffff),
- extra_bits,
- rand.unpack("H4H12").join("-")
- ]
-
- when (0..12) # the generic version is slower than the special cases above
- rand_a, rand_b1, rand_b2, rand_b3 = random_bytes(10).unpack("nnnN")
- rand_mask_bits = 12 - extra_timestamp_bits
- ms, ns = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
- .divmod(1_000_000)
- "%08x-%04x-%04x-%04x-%04x%08x" % [
- (ms & 0x0000_ffff_ffff_0000) >> 16,
- (ms & 0x0000_0000_0000_ffff),
- 0x7000 |
- ((ns * (1 << extra_timestamp_bits) / 1_000_000) << rand_mask_bits) |
- rand_a & ((1 << rand_mask_bits) - 1),
- 0x8000 | (rand_b1 & 0x3fff),
- rand_b2,
- rand_b3
- ]
-
- else
- raise ArgumentError, "extra_timestamp_bits must be in 0..12"
- end
- end
-
- # Internal interface to Random; Generate random data _n_ bytes.
- private def gen_random(n)
- self.bytes(n)
- end
-
- # Generate a string that randomly draws from a
- # source array of characters.
- #
- # The argument _source_ specifies the array of characters from which
- # to generate the string.
- # The argument _n_ specifies the length, in characters, of the string to be
- # generated.
- #
- # The result may contain whatever characters are in the source array.
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # prng.choose([*'l'..'r'], 16) #=> "lmrqpoonmmlqlron"
- # prng.choose([*'0'..'9'], 5) #=> "27309"
- private def choose(source, n)
- size = source.size
- m = 1
- limit = size
- while limit * size <= 0x100000000
- limit *= size
- m += 1
- end
- result = ''.dup
- while m <= n
- rs = random_number(limit)
- is = rs.digits(size)
- (m-is.length).times { is << 0 }
- result << source.values_at(*is).join('')
- n -= m
- end
- if 0 < n
- rs = random_number(limit)
- is = rs.digits(size)
- if is.length < n
- (n-is.length).times { is << 0 }
- else
- is.pop while n < is.length
- end
- result.concat source.values_at(*is).join('')
- end
- result
- end
-
- # The default character list for #alphanumeric.
- ALPHANUMERIC = [*'A'..'Z', *'a'..'z', *'0'..'9']
-
- # Generate a random alphanumeric string.
- #
- # The argument _n_ specifies the length, in characters, of the alphanumeric
- # string to be generated.
- # The argument _chars_ specifies the character list which the result is
- # consist of.
- #
- # If _n_ is not specified or is nil, 16 is assumed.
- # It may be larger in the future.
- #
- # The result may contain A-Z, a-z and 0-9, unless _chars_ is specified.
- #
- # require 'rubygems/vendor/securerandom/lib/random/formatter'
- #
- # Random.alphanumeric #=> "2BuBuLf3WfSKyQbR"
- # # or
- # prng = Random.new
- # prng.alphanumeric(10) #=> "i6K93NdqiH"
- #
- # Random.alphanumeric(4, chars: [*"0".."9"]) #=> "2952"
- # # or
- # prng = Random.new
- # prng.alphanumeric(10, chars: [*"!".."/"]) #=> ",.,++%/''."
- def alphanumeric(n = nil, chars: ALPHANUMERIC)
- n = 16 if n.nil?
- choose(chars, n)
- end
-end
diff --git a/lib/rubygems/vendor/securerandom/lib/securerandom.rb b/lib/rubygems/vendor/securerandom/lib/securerandom.rb
deleted file mode 100644
index f83d2a74fc..0000000000
--- a/lib/rubygems/vendor/securerandom/lib/securerandom.rb
+++ /dev/null
@@ -1,96 +0,0 @@
-# -*- coding: us-ascii -*-
-# frozen_string_literal: true
-
-require_relative 'random/formatter'
-
-# == Secure random number generator interface.
-#
-# This library is an interface to secure random number generators which are
-# suitable for generating session keys in HTTP cookies, etc.
-#
-# You can use this library in your application by requiring it:
-#
-# require 'rubygems/vendor/securerandom/lib/securerandom'
-#
-# It supports the following secure random number generators:
-#
-# * openssl
-# * /dev/urandom
-# * Win32
-#
-# Gem::SecureRandom is extended by the Gem::Random::Formatter module which
-# defines the following methods:
-#
-# * alphanumeric
-# * base64
-# * choose
-# * gen_random
-# * hex
-# * rand
-# * random_bytes
-# * random_number
-# * urlsafe_base64
-# * uuid
-#
-# These methods are usable as class methods of Gem::SecureRandom such as
-# +Gem::SecureRandom.hex+.
-#
-# If a secure random number generator is not available,
-# +NotImplementedError+ is raised.
-
-module Gem::SecureRandom
-
- # The version
- VERSION = "0.3.1"
-
- class << self
- # Returns a random binary string containing +size+ bytes.
- #
- # See Random.bytes
- def bytes(n)
- return gen_random(n)
- end
-
- private
-
- # :stopdoc:
-
- # Implementation using OpenSSL
- def gen_random_openssl(n)
- return OpenSSL::Random.random_bytes(n)
- end
-
- # Implementation using system random device
- def gen_random_urandom(n)
- ret = Random.urandom(n)
- unless ret
- raise NotImplementedError, "No random device"
- end
- unless ret.length == n
- raise NotImplementedError, "Unexpected partial read from random device: only #{ret.length} for #{n} bytes"
- end
- ret
- end
-
- begin
- # Check if Random.urandom is available
- Random.urandom(1)
- alias gen_random gen_random_urandom
- rescue RuntimeError
- begin
- require 'openssl'
- rescue NoMethodError
- raise NotImplementedError, "No random device"
- else
- alias gen_random gen_random_openssl
- end
- end
-
- # :startdoc:
-
- # Generate random data bytes for Gem::Random::Formatter
- public :gen_random
- end
-end
-
-Gem::SecureRandom.extend(Gem::Random::Formatter)
diff --git a/lib/rubygems/vendor/timeout/.document b/lib/rubygems/vendor/timeout/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/timeout/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/timeout/lib/timeout.rb b/lib/rubygems/vendor/timeout/lib/timeout.rb
deleted file mode 100644
index df97d64ca0..0000000000
--- a/lib/rubygems/vendor/timeout/lib/timeout.rb
+++ /dev/null
@@ -1,199 +0,0 @@
-# frozen_string_literal: true
-# Timeout long-running blocks
-#
-# == Synopsis
-#
-# require 'rubygems/vendor/timeout/lib/timeout'
-# status = Gem::Timeout::timeout(5) {
-# # Something that should be interrupted if it takes more than 5 seconds...
-# }
-#
-# == Description
-#
-# Gem::Timeout provides a way to auto-terminate a potentially long-running
-# operation if it hasn't finished in a fixed amount of time.
-#
-# Previous versions didn't use a module for namespacing, however
-# #timeout is provided for backwards compatibility. You
-# should prefer Gem::Timeout.timeout instead.
-#
-# == Copyright
-#
-# Copyright:: (C) 2000 Network Applied Communication Laboratory, Inc.
-# Copyright:: (C) 2000 Information-technology Promotion Agency, Japan
-
-module Gem::Timeout
- VERSION = "0.4.1"
-
- # Internal error raised to when a timeout is triggered.
- class ExitException < Exception
- def exception(*)
- self
- end
- end
-
- # Raised by Gem::Timeout.timeout when the block times out.
- class Error < RuntimeError
- def self.handle_timeout(message)
- exc = ExitException.new(message)
-
- begin
- yield exc
- rescue ExitException => e
- raise new(message) if exc.equal?(e)
- raise
- end
- end
- end
-
- # :stopdoc:
- CONDVAR = ConditionVariable.new
- QUEUE = Queue.new
- QUEUE_MUTEX = Mutex.new
- TIMEOUT_THREAD_MUTEX = Mutex.new
- @timeout_thread = nil
- private_constant :CONDVAR, :QUEUE, :QUEUE_MUTEX, :TIMEOUT_THREAD_MUTEX
-
- class Request
- attr_reader :deadline
-
- def initialize(thread, timeout, exception_class, message)
- @thread = thread
- @deadline = GET_TIME.call(Process::CLOCK_MONOTONIC) + timeout
- @exception_class = exception_class
- @message = message
-
- @mutex = Mutex.new
- @done = false # protected by @mutex
- end
-
- def done?
- @mutex.synchronize do
- @done
- end
- end
-
- def expired?(now)
- now >= @deadline
- end
-
- def interrupt
- @mutex.synchronize do
- unless @done
- @thread.raise @exception_class, @message
- @done = true
- end
- end
- end
-
- def finished
- @mutex.synchronize do
- @done = true
- end
- end
- end
- private_constant :Request
-
- def self.create_timeout_thread
- watcher = Thread.new do
- requests = []
- while true
- until QUEUE.empty? and !requests.empty? # wait to have at least one request
- req = QUEUE.pop
- requests << req unless req.done?
- end
- closest_deadline = requests.min_by(&:deadline).deadline
-
- now = 0.0
- QUEUE_MUTEX.synchronize do
- while (now = GET_TIME.call(Process::CLOCK_MONOTONIC)) < closest_deadline and QUEUE.empty?
- CONDVAR.wait(QUEUE_MUTEX, closest_deadline - now)
- end
- end
-
- requests.each do |req|
- req.interrupt if req.expired?(now)
- end
- requests.reject!(&:done?)
- end
- end
- ThreadGroup::Default.add(watcher) unless watcher.group.enclosed?
- watcher.name = "Gem::Timeout stdlib thread"
- watcher.thread_variable_set(:"\0__detached_thread__", true)
- watcher
- end
- private_class_method :create_timeout_thread
-
- def self.ensure_timeout_thread_created
- unless @timeout_thread and @timeout_thread.alive?
- TIMEOUT_THREAD_MUTEX.synchronize do
- unless @timeout_thread and @timeout_thread.alive?
- @timeout_thread = create_timeout_thread
- end
- end
- end
- end
-
- # We keep a private reference so that time mocking libraries won't break
- # Gem::Timeout.
- GET_TIME = Process.method(:clock_gettime)
- private_constant :GET_TIME
-
- # :startdoc:
-
- # Perform an operation in a block, raising an error if it takes longer than
- # +sec+ seconds to complete.
- #
- # +sec+:: Number of seconds to wait for the block to terminate. Any number
- # may be used, including Floats to specify fractional seconds. A
- # value of 0 or +nil+ will execute the block without any timeout.
- # +klass+:: Exception Class to raise if the block fails to terminate
- # in +sec+ seconds. Omitting will use the default, Gem::Timeout::Error
- # +message+:: Error message to raise with Exception Class.
- # Omitting will use the default, "execution expired"
- #
- # Returns the result of the block *if* the block completed before
- # +sec+ seconds, otherwise throws an exception, based on the value of +klass+.
- #
- # The exception thrown to terminate the given block cannot be rescued inside
- # the block unless +klass+ is given explicitly. However, the block can use
- # ensure to prevent the handling of the exception. For that reason, this
- # method cannot be relied on to enforce timeouts for untrusted blocks.
- #
- # If a scheduler is defined, it will be used to handle the timeout by invoking
- # Scheduler#timeout_after.
- #
- # Note that this is both a method of module Gem::Timeout, so you can <tt>include
- # Gem::Timeout</tt> into your classes so they have a #timeout method, as well as
- # a module method, so you can call it directly as Gem::Timeout.timeout().
- def timeout(sec, klass = nil, message = nil, &block) #:yield: +sec+
- return yield(sec) if sec == nil or sec.zero?
-
- message ||= "execution expired"
-
- if Fiber.respond_to?(:current_scheduler) && (scheduler = Fiber.current_scheduler)&.respond_to?(:timeout_after)
- return scheduler.timeout_after(sec, klass || Error, message, &block)
- end
-
- Gem::Timeout.ensure_timeout_thread_created
- perform = Proc.new do |exc|
- request = Request.new(Thread.current, sec, exc, message)
- QUEUE_MUTEX.synchronize do
- QUEUE << request
- CONDVAR.signal
- end
- begin
- return yield(sec)
- ensure
- request.finished
- end
- end
-
- if klass
- perform.call(klass)
- else
- Error.handle_timeout(message, &perform)
- end
- end
- module_function :timeout
-end
diff --git a/lib/rubygems/vendor/tsort/.document b/lib/rubygems/vendor/tsort/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/tsort/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/tsort/lib/tsort.rb b/lib/rubygems/vendor/tsort/lib/tsort.rb
deleted file mode 100644
index 9dd7c09521..0000000000
--- a/lib/rubygems/vendor/tsort/lib/tsort.rb
+++ /dev/null
@@ -1,455 +0,0 @@
-# frozen_string_literal: true
-
-#--
-# tsort.rb - provides a module for topological sorting and strongly connected components.
-#++
-#
-
-#
-# Gem::TSort implements topological sorting using Tarjan's algorithm for
-# strongly connected components.
-#
-# Gem::TSort is designed to be able to be used with any object which can be
-# interpreted as a directed graph.
-#
-# Gem::TSort requires two methods to interpret an object as a graph,
-# tsort_each_node and tsort_each_child.
-#
-# * tsort_each_node is used to iterate for all nodes over a graph.
-# * tsort_each_child is used to iterate for child nodes of a given node.
-#
-# The equality of nodes are defined by eql? and hash since
-# Gem::TSort uses Hash internally.
-#
-# == A Simple Example
-#
-# The following example demonstrates how to mix the Gem::TSort module into an
-# existing class (in this case, Hash). Here, we're treating each key in
-# the hash as a node in the graph, and so we simply alias the required
-# #tsort_each_node method to Hash's #each_key method. For each key in the
-# hash, the associated value is an array of the node's child nodes. This
-# choice in turn leads to our implementation of the required #tsort_each_child
-# method, which fetches the array of child nodes and then iterates over that
-# array using the user-supplied block.
-#
-# require 'rubygems/vendor/tsort/lib/tsort'
-#
-# class Hash
-# include Gem::TSort
-# alias tsort_each_node each_key
-# def tsort_each_child(node, &block)
-# fetch(node).each(&block)
-# end
-# end
-#
-# {1=>[2, 3], 2=>[3], 3=>[], 4=>[]}.tsort
-# #=> [3, 2, 1, 4]
-#
-# {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}.strongly_connected_components
-# #=> [[4], [2, 3], [1]]
-#
-# == A More Realistic Example
-#
-# A very simple `make' like tool can be implemented as follows:
-#
-# require 'rubygems/vendor/tsort/lib/tsort'
-#
-# class Make
-# def initialize
-# @dep = {}
-# @dep.default = []
-# end
-#
-# def rule(outputs, inputs=[], &block)
-# triple = [outputs, inputs, block]
-# outputs.each {|f| @dep[f] = [triple]}
-# @dep[triple] = inputs
-# end
-#
-# def build(target)
-# each_strongly_connected_component_from(target) {|ns|
-# if ns.length != 1
-# fs = ns.delete_if {|n| Array === n}
-# raise Gem::TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}")
-# end
-# n = ns.first
-# if Array === n
-# outputs, inputs, block = n
-# inputs_time = inputs.map {|f| File.mtime f}.max
-# begin
-# outputs_time = outputs.map {|f| File.mtime f}.min
-# rescue Errno::ENOENT
-# outputs_time = nil
-# end
-# if outputs_time == nil ||
-# inputs_time != nil && outputs_time <= inputs_time
-# sleep 1 if inputs_time != nil && inputs_time.to_i == Time.now.to_i
-# block.call
-# end
-# end
-# }
-# end
-#
-# def tsort_each_child(node, &block)
-# @dep[node].each(&block)
-# end
-# include Gem::TSort
-# end
-#
-# def command(arg)
-# print arg, "\n"
-# system arg
-# end
-#
-# m = Make.new
-# m.rule(%w[t1]) { command 'date > t1' }
-# m.rule(%w[t2]) { command 'date > t2' }
-# m.rule(%w[t3]) { command 'date > t3' }
-# m.rule(%w[t4], %w[t1 t3]) { command 'cat t1 t3 > t4' }
-# m.rule(%w[t5], %w[t4 t2]) { command 'cat t4 t2 > t5' }
-# m.build('t5')
-#
-# == Bugs
-#
-# * 'tsort.rb' is wrong name because this library uses
-# Tarjan's algorithm for strongly connected components.
-# Although 'strongly_connected_components.rb' is correct but too long.
-#
-# == References
-#
-# R. E. Tarjan, "Depth First Search and Linear Graph Algorithms",
-# <em>SIAM Journal on Computing</em>, Vol. 1, No. 2, pp. 146-160, June 1972.
-#
-
-module Gem::TSort
-
- VERSION = "0.2.0"
-
- class Cyclic < StandardError
- end
-
- # Returns a topologically sorted array of nodes.
- # The array is sorted from children to parents, i.e.
- # the first element has no child and the last node has no parent.
- #
- # If there is a cycle, Gem::TSort::Cyclic is raised.
- #
- # class G
- # include Gem::TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # p graph.tsort #=> [4, 2, 3, 1]
- #
- # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
- # p graph.tsort # raises Gem::TSort::Cyclic
- #
- def tsort
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- Gem::TSort.tsort(each_node, each_child)
- end
-
- # Returns a topologically sorted array of nodes.
- # The array is sorted from children to parents, i.e.
- # the first element has no child and the last node has no parent.
- #
- # The graph is represented by _each_node_ and _each_child_.
- # _each_node_ should have +call+ method which yields for each node in the graph.
- # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
- #
- # If there is a cycle, Gem::TSort::Cyclic is raised.
- #
- # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # p Gem::TSort.tsort(each_node, each_child) #=> [4, 2, 3, 1]
- #
- # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # p Gem::TSort.tsort(each_node, each_child) # raises Gem::TSort::Cyclic
- #
- def self.tsort(each_node, each_child)
- tsort_each(each_node, each_child).to_a
- end
-
- # The iterator version of the #tsort method.
- # <tt><em>obj</em>.tsort_each</tt> is similar to <tt><em>obj</em>.tsort.each</tt>, but
- # modification of _obj_ during the iteration may lead to unexpected results.
- #
- # #tsort_each returns +nil+.
- # If there is a cycle, Gem::TSort::Cyclic is raised.
- #
- # class G
- # include Gem::TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # graph.tsort_each {|n| p n }
- # #=> 4
- # # 2
- # # 3
- # # 1
- #
- def tsort_each(&block) # :yields: node
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- Gem::TSort.tsort_each(each_node, each_child, &block)
- end
-
- # The iterator version of the Gem::TSort.tsort method.
- #
- # The graph is represented by _each_node_ and _each_child_.
- # _each_node_ should have +call+ method which yields for each node in the graph.
- # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
- #
- # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # Gem::TSort.tsort_each(each_node, each_child) {|n| p n }
- # #=> 4
- # # 2
- # # 3
- # # 1
- #
- def self.tsort_each(each_node, each_child) # :yields: node
- return to_enum(__method__, each_node, each_child) unless block_given?
-
- each_strongly_connected_component(each_node, each_child) {|component|
- if component.size == 1
- yield component.first
- else
- raise Cyclic.new("topological sort failed: #{component.inspect}")
- end
- }
- end
-
- # Returns strongly connected components as an array of arrays of nodes.
- # The array is sorted from children to parents.
- # Each elements of the array represents a strongly connected component.
- #
- # class G
- # include Gem::TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # p graph.strongly_connected_components #=> [[4], [2], [3], [1]]
- #
- # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
- # p graph.strongly_connected_components #=> [[4], [2, 3], [1]]
- #
- def strongly_connected_components
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- Gem::TSort.strongly_connected_components(each_node, each_child)
- end
-
- # Returns strongly connected components as an array of arrays of nodes.
- # The array is sorted from children to parents.
- # Each elements of the array represents a strongly connected component.
- #
- # The graph is represented by _each_node_ and _each_child_.
- # _each_node_ should have +call+ method which yields for each node in the graph.
- # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
- #
- # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # p Gem::TSort.strongly_connected_components(each_node, each_child)
- # #=> [[4], [2], [3], [1]]
- #
- # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # p Gem::TSort.strongly_connected_components(each_node, each_child)
- # #=> [[4], [2, 3], [1]]
- #
- def self.strongly_connected_components(each_node, each_child)
- each_strongly_connected_component(each_node, each_child).to_a
- end
-
- # The iterator version of the #strongly_connected_components method.
- # <tt><em>obj</em>.each_strongly_connected_component</tt> is similar to
- # <tt><em>obj</em>.strongly_connected_components.each</tt>, but
- # modification of _obj_ during the iteration may lead to unexpected results.
- #
- # #each_strongly_connected_component returns +nil+.
- #
- # class G
- # include Gem::TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # graph.each_strongly_connected_component {|scc| p scc }
- # #=> [4]
- # # [2]
- # # [3]
- # # [1]
- #
- # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
- # graph.each_strongly_connected_component {|scc| p scc }
- # #=> [4]
- # # [2, 3]
- # # [1]
- #
- def each_strongly_connected_component(&block) # :yields: nodes
- each_node = method(:tsort_each_node)
- each_child = method(:tsort_each_child)
- Gem::TSort.each_strongly_connected_component(each_node, each_child, &block)
- end
-
- # The iterator version of the Gem::TSort.strongly_connected_components method.
- #
- # The graph is represented by _each_node_ and _each_child_.
- # _each_node_ should have +call+ method which yields for each node in the graph.
- # _each_child_ should have +call+ method which takes a node argument and yields for each child node.
- #
- # g = {1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # Gem::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
- # #=> [4]
- # # [2]
- # # [3]
- # # [1]
- #
- # g = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_node = lambda {|&b| g.each_key(&b) }
- # each_child = lambda {|n, &b| g[n].each(&b) }
- # Gem::TSort.each_strongly_connected_component(each_node, each_child) {|scc| p scc }
- # #=> [4]
- # # [2, 3]
- # # [1]
- #
- def self.each_strongly_connected_component(each_node, each_child) # :yields: nodes
- return to_enum(__method__, each_node, each_child) unless block_given?
-
- id_map = {}
- stack = []
- each_node.call {|node|
- unless id_map.include? node
- each_strongly_connected_component_from(node, each_child, id_map, stack) {|c|
- yield c
- }
- end
- }
- nil
- end
-
- # Iterates over strongly connected component in the subgraph reachable from
- # _node_.
- #
- # Return value is unspecified.
- #
- # #each_strongly_connected_component_from doesn't call #tsort_each_node.
- #
- # class G
- # include Gem::TSort
- # def initialize(g)
- # @g = g
- # end
- # def tsort_each_child(n, &b) @g[n].each(&b) end
- # def tsort_each_node(&b) @g.each_key(&b) end
- # end
- #
- # graph = G.new({1=>[2, 3], 2=>[4], 3=>[2, 4], 4=>[]})
- # graph.each_strongly_connected_component_from(2) {|scc| p scc }
- # #=> [4]
- # # [2]
- #
- # graph = G.new({1=>[2], 2=>[3, 4], 3=>[2], 4=>[]})
- # graph.each_strongly_connected_component_from(2) {|scc| p scc }
- # #=> [4]
- # # [2, 3]
- #
- def each_strongly_connected_component_from(node, id_map={}, stack=[], &block) # :yields: nodes
- Gem::TSort.each_strongly_connected_component_from(node, method(:tsort_each_child), id_map, stack, &block)
- end
-
- # Iterates over strongly connected components in a graph.
- # The graph is represented by _node_ and _each_child_.
- #
- # _node_ is the first node.
- # _each_child_ should have +call+ method which takes a node argument
- # and yields for each child node.
- #
- # Return value is unspecified.
- #
- # #Gem::TSort.each_strongly_connected_component_from is a class method and
- # it doesn't need a class to represent a graph which includes Gem::TSort.
- #
- # graph = {1=>[2], 2=>[3, 4], 3=>[2], 4=>[]}
- # each_child = lambda {|n, &b| graph[n].each(&b) }
- # Gem::TSort.each_strongly_connected_component_from(1, each_child) {|scc|
- # p scc
- # }
- # #=> [4]
- # # [2, 3]
- # # [1]
- #
- def self.each_strongly_connected_component_from(node, each_child, id_map={}, stack=[]) # :yields: nodes
- return to_enum(__method__, node, each_child, id_map, stack) unless block_given?
-
- minimum_id = node_id = id_map[node] = id_map.size
- stack_length = stack.length
- stack << node
-
- each_child.call(node) {|child|
- if id_map.include? child
- child_id = id_map[child]
- minimum_id = child_id if child_id && child_id < minimum_id
- else
- sub_minimum_id =
- each_strongly_connected_component_from(child, each_child, id_map, stack) {|c|
- yield c
- }
- minimum_id = sub_minimum_id if sub_minimum_id < minimum_id
- end
- }
-
- if node_id == minimum_id
- component = stack.slice!(stack_length .. -1)
- component.each {|n| id_map[n] = nil}
- yield component
- end
-
- minimum_id
- end
-
- # Should be implemented by a extended class.
- #
- # #tsort_each_node is used to iterate for all nodes over a graph.
- #
- def tsort_each_node # :yields: node
- raise NotImplementedError.new
- end
-
- # Should be implemented by a extended class.
- #
- # #tsort_each_child is used to iterate for child nodes of _node_.
- #
- def tsort_each_child(node) # :yields: child
- raise NotImplementedError.new
- end
-end
diff --git a/lib/rubygems/vendor/uri/.document b/lib/rubygems/vendor/uri/.document
deleted file mode 100644
index 0c43bbd6b3..0000000000
--- a/lib/rubygems/vendor/uri/.document
+++ /dev/null
@@ -1 +0,0 @@
-# Vendored files do not need to be documented
diff --git a/lib/rubygems/vendor/uri/lib/uri.rb b/lib/rubygems/vendor/uri/lib/uri.rb
deleted file mode 100644
index f1ccc167cc..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri.rb
+++ /dev/null
@@ -1,104 +0,0 @@
-# frozen_string_literal: false
-# Gem::URI is a module providing classes to handle Uniform Resource Identifiers
-# (RFC2396[http://tools.ietf.org/html/rfc2396]).
-#
-# == Features
-#
-# * Uniform way of handling URIs.
-# * Flexibility to introduce custom Gem::URI schemes.
-# * Flexibility to have an alternate Gem::URI::Parser (or just different patterns
-# and regexp's).
-#
-# == Basic example
-#
-# require 'rubygems/vendor/uri/lib/uri'
-#
-# uri = Gem::URI("http://foo.com/posts?id=30&limit=5#time=1305298413")
-# #=> #<Gem::URI::HTTP http://foo.com/posts?id=30&limit=5#time=1305298413>
-#
-# uri.scheme #=> "http"
-# uri.host #=> "foo.com"
-# uri.path #=> "/posts"
-# uri.query #=> "id=30&limit=5"
-# uri.fragment #=> "time=1305298413"
-#
-# uri.to_s #=> "http://foo.com/posts?id=30&limit=5#time=1305298413"
-#
-# == Adding custom URIs
-#
-# module Gem::URI
-# class RSYNC < Generic
-# DEFAULT_PORT = 873
-# end
-# register_scheme 'RSYNC', RSYNC
-# end
-# #=> Gem::URI::RSYNC
-#
-# Gem::URI.scheme_list
-# #=> {"FILE"=>Gem::URI::File, "FTP"=>Gem::URI::FTP, "HTTP"=>Gem::URI::HTTP,
-# # "HTTPS"=>Gem::URI::HTTPS, "LDAP"=>Gem::URI::LDAP, "LDAPS"=>Gem::URI::LDAPS,
-# # "MAILTO"=>Gem::URI::MailTo, "RSYNC"=>Gem::URI::RSYNC}
-#
-# uri = Gem::URI("rsync://rsync.foo.com")
-# #=> #<Gem::URI::RSYNC rsync://rsync.foo.com>
-#
-# == RFC References
-#
-# A good place to view an RFC spec is http://www.ietf.org/rfc.html.
-#
-# Here is a list of all related RFC's:
-# - RFC822[http://tools.ietf.org/html/rfc822]
-# - RFC1738[http://tools.ietf.org/html/rfc1738]
-# - RFC2255[http://tools.ietf.org/html/rfc2255]
-# - RFC2368[http://tools.ietf.org/html/rfc2368]
-# - RFC2373[http://tools.ietf.org/html/rfc2373]
-# - RFC2396[http://tools.ietf.org/html/rfc2396]
-# - RFC2732[http://tools.ietf.org/html/rfc2732]
-# - RFC3986[http://tools.ietf.org/html/rfc3986]
-#
-# == Class tree
-#
-# - Gem::URI::Generic (in uri/generic.rb)
-# - Gem::URI::File - (in uri/file.rb)
-# - Gem::URI::FTP - (in uri/ftp.rb)
-# - Gem::URI::HTTP - (in uri/http.rb)
-# - Gem::URI::HTTPS - (in uri/https.rb)
-# - Gem::URI::LDAP - (in uri/ldap.rb)
-# - Gem::URI::LDAPS - (in uri/ldaps.rb)
-# - Gem::URI::MailTo - (in uri/mailto.rb)
-# - Gem::URI::Parser - (in uri/common.rb)
-# - Gem::URI::REGEXP - (in uri/common.rb)
-# - Gem::URI::REGEXP::PATTERN - (in uri/common.rb)
-# - Gem::URI::Util - (in uri/common.rb)
-# - Gem::URI::Error - (in uri/common.rb)
-# - Gem::URI::InvalidURIError - (in uri/common.rb)
-# - Gem::URI::InvalidComponentError - (in uri/common.rb)
-# - Gem::URI::BadURIError - (in uri/common.rb)
-#
-# == Copyright Info
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# Documentation::
-# Akira Yamada <akira@ruby-lang.org>
-# Dmitry V. Sabanin <sdmitry@lrn.ru>
-# Vincent Batts <vbatts@hashbangbash.com>
-# License::
-# Copyright (c) 2001 akira yamada <akira@ruby-lang.org>
-# You can redistribute it and/or modify it under the same term as Ruby.
-#
-
-module Gem::URI
-end
-
-require_relative 'uri/version'
-require_relative 'uri/common'
-require_relative 'uri/generic'
-require_relative 'uri/file'
-require_relative 'uri/ftp'
-require_relative 'uri/http'
-require_relative 'uri/https'
-require_relative 'uri/ldap'
-require_relative 'uri/ldaps'
-require_relative 'uri/mailto'
-require_relative 'uri/ws'
-require_relative 'uri/wss'
diff --git a/lib/rubygems/vendor/uri/lib/uri/common.rb b/lib/rubygems/vendor/uri/lib/uri/common.rb
deleted file mode 100644
index 921fb9dd28..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/common.rb
+++ /dev/null
@@ -1,853 +0,0 @@
-# frozen_string_literal: true
-#--
-# = uri/common.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License::
-# You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative "rfc2396_parser"
-require_relative "rfc3986_parser"
-
-module Gem::URI
- include RFC2396_REGEXP
-
- REGEXP = RFC2396_REGEXP
- Parser = RFC2396_Parser
- RFC3986_PARSER = RFC3986_Parser.new
- Ractor.make_shareable(RFC3986_PARSER) if defined?(Ractor)
-
- # Gem::URI::Parser.new
- DEFAULT_PARSER = Parser.new
- DEFAULT_PARSER.pattern.each_pair do |sym, str|
- unless REGEXP::PATTERN.const_defined?(sym)
- REGEXP::PATTERN.const_set(sym, str)
- end
- end
- DEFAULT_PARSER.regexp.each_pair do |sym, str|
- const_set(sym, str)
- end
- Ractor.make_shareable(DEFAULT_PARSER) if defined?(Ractor)
-
- module Util # :nodoc:
- def make_components_hash(klass, array_hash)
- tmp = {}
- if array_hash.kind_of?(Array) &&
- array_hash.size == klass.component.size - 1
- klass.component[1..-1].each_index do |i|
- begin
- tmp[klass.component[i + 1]] = array_hash[i].clone
- rescue TypeError
- tmp[klass.component[i + 1]] = array_hash[i]
- end
- end
-
- elsif array_hash.kind_of?(Hash)
- array_hash.each do |key, value|
- begin
- tmp[key] = value.clone
- rescue TypeError
- tmp[key] = value
- end
- end
- else
- raise ArgumentError,
- "expected Array of or Hash of components of #{klass} (#{klass.component[1..-1].join(', ')})"
- end
- tmp[:scheme] = klass.to_s.sub(/\A.*::/, '').downcase
-
- return tmp
- end
- module_function :make_components_hash
- end
-
- module Schemes
- end
- private_constant :Schemes
-
- # Registers the given +klass+ as the class to be instantiated
- # when parsing a \Gem::URI with the given +scheme+:
- #
- # Gem::URI.register_scheme('MS_SEARCH', Gem::URI::Generic) # => Gem::URI::Generic
- # Gem::URI.scheme_list['MS_SEARCH'] # => Gem::URI::Generic
- #
- # Note that after calling String#upcase on +scheme+, it must be a valid
- # constant name.
- def self.register_scheme(scheme, klass)
- Schemes.const_set(scheme.to_s.upcase, klass)
- end
-
- # Returns a hash of the defined schemes:
- #
- # Gem::URI.scheme_list
- # # =>
- # {"MAILTO"=>Gem::URI::MailTo,
- # "LDAPS"=>Gem::URI::LDAPS,
- # "WS"=>Gem::URI::WS,
- # "HTTP"=>Gem::URI::HTTP,
- # "HTTPS"=>Gem::URI::HTTPS,
- # "LDAP"=>Gem::URI::LDAP,
- # "FILE"=>Gem::URI::File,
- # "FTP"=>Gem::URI::FTP}
- #
- # Related: Gem::URI.register_scheme.
- def self.scheme_list
- Schemes.constants.map { |name|
- [name.to_s.upcase, Schemes.const_get(name)]
- }.to_h
- end
-
- INITIAL_SCHEMES = scheme_list
- private_constant :INITIAL_SCHEMES
- Ractor.make_shareable(INITIAL_SCHEMES) if defined?(Ractor)
-
- # Returns a new object constructed from the given +scheme+, +arguments+,
- # and +default+:
- #
- # - The new object is an instance of <tt>Gem::URI.scheme_list[scheme.upcase]</tt>.
- # - The object is initialized by calling the class initializer
- # using +scheme+ and +arguments+.
- # See Gem::URI::Generic.new.
- #
- # Examples:
- #
- # values = ['john.doe', 'www.example.com', '123', nil, '/forum/questions/', nil, 'tag=networking&order=newest', 'top']
- # Gem::URI.for('https', *values)
- # # => #<Gem::URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- # Gem::URI.for('foo', *values, default: Gem::URI::HTTP)
- # # => #<Gem::URI::HTTP foo://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- #
- def self.for(scheme, *arguments, default: Generic)
- const_name = scheme.to_s.upcase
-
- uri_class = INITIAL_SCHEMES[const_name]
- uri_class ||= if /\A[A-Z]\w*\z/.match?(const_name) && Schemes.const_defined?(const_name, false)
- Schemes.const_get(const_name, false)
- end
- uri_class ||= default
-
- return uri_class.new(scheme, *arguments)
- end
-
- #
- # Base class for all Gem::URI exceptions.
- #
- class Error < StandardError; end
- #
- # Not a Gem::URI.
- #
- class InvalidURIError < Error; end
- #
- # Not a Gem::URI component.
- #
- class InvalidComponentError < Error; end
- #
- # Gem::URI is valid, bad usage is not.
- #
- class BadURIError < Error; end
-
- # Returns a 9-element array representing the parts of the \Gem::URI
- # formed from the string +uri+;
- # each array element is a string or +nil+:
- #
- # names = %w[scheme userinfo host port registry path opaque query fragment]
- # values = Gem::URI.split('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # names.zip(values)
- # # =>
- # [["scheme", "https"],
- # ["userinfo", "john.doe"],
- # ["host", "www.example.com"],
- # ["port", "123"],
- # ["registry", nil],
- # ["path", "/forum/questions/"],
- # ["opaque", nil],
- # ["query", "tag=networking&order=newest"],
- # ["fragment", "top"]]
- #
- def self.split(uri)
- RFC3986_PARSER.split(uri)
- end
-
- # Returns a new \Gem::URI object constructed from the given string +uri+:
- #
- # Gem::URI.parse('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # # => #<Gem::URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- # Gem::URI.parse('http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # # => #<Gem::URI::HTTP http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- #
- # It's recommended to first ::escape string +uri+
- # if it may contain invalid Gem::URI characters.
- #
- def self.parse(uri)
- RFC3986_PARSER.parse(uri)
- end
-
- # Merges the given Gem::URI strings +str+
- # per {RFC 2396}[https://www.rfc-editor.org/rfc/rfc2396.html].
- #
- # Each string in +str+ is converted to an
- # {RFC3986 Gem::URI}[https://www.rfc-editor.org/rfc/rfc3986.html] before being merged.
- #
- # Examples:
- #
- # Gem::URI.join("http://example.com/","main.rbx")
- # # => #<Gem::URI::HTTP http://example.com/main.rbx>
- #
- # Gem::URI.join('http://example.com', 'foo')
- # # => #<Gem::URI::HTTP http://example.com/foo>
- #
- # Gem::URI.join('http://example.com', '/foo', '/bar')
- # # => #<Gem::URI::HTTP http://example.com/bar>
- #
- # Gem::URI.join('http://example.com', '/foo', 'bar')
- # # => #<Gem::URI::HTTP http://example.com/bar>
- #
- # Gem::URI.join('http://example.com', '/foo/', 'bar')
- # # => #<Gem::URI::HTTP http://example.com/foo/bar>
- #
- def self.join(*str)
- RFC3986_PARSER.join(*str)
- end
-
- #
- # == Synopsis
- #
- # Gem::URI::extract(str[, schemes][,&blk])
- #
- # == Args
- #
- # +str+::
- # String to extract URIs from.
- # +schemes+::
- # Limit Gem::URI matching to specific schemes.
- #
- # == Description
- #
- # Extracts URIs from a string. If block given, iterates through all matched URIs.
- # Returns nil if block given or array with matches.
- #
- # == Usage
- #
- # require "rubygems/vendor/uri/lib/uri"
- #
- # Gem::URI.extract("text here http://foo.example.org/bla and here mailto:test@example.com and here also.")
- # # => ["http://foo.example.com/bla", "mailto:test@example.com"]
- #
- def self.extract(str, schemes = nil, &block) # :nodoc:
- warn "Gem::URI.extract is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.extract(str, schemes, &block)
- end
-
- #
- # == Synopsis
- #
- # Gem::URI::regexp([match_schemes])
- #
- # == Args
- #
- # +match_schemes+::
- # Array of schemes. If given, resulting regexp matches to URIs
- # whose scheme is one of the match_schemes.
- #
- # == Description
- #
- # Returns a Regexp object which matches to Gem::URI-like strings.
- # The Regexp object returned by this method includes arbitrary
- # number of capture group (parentheses). Never rely on its number.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # # extract first Gem::URI from html_string
- # html_string.slice(Gem::URI.regexp)
- #
- # # remove ftp URIs
- # html_string.sub(Gem::URI.regexp(['ftp']), '')
- #
- # # You should not rely on the number of parentheses
- # html_string.scan(Gem::URI.regexp) do |*matches|
- # p $&
- # end
- #
- def self.regexp(schemes = nil)# :nodoc:
- warn "Gem::URI.regexp is obsolete", uplevel: 1 if $VERBOSE
- DEFAULT_PARSER.make_regexp(schemes)
- end
-
- TBLENCWWWCOMP_ = {} # :nodoc:
- 256.times do |i|
- TBLENCWWWCOMP_[-i.chr] = -('%%%02X' % i)
- end
- TBLENCURICOMP_ = TBLENCWWWCOMP_.dup.freeze
- TBLENCWWWCOMP_[' '] = '+'
- TBLENCWWWCOMP_.freeze
- TBLDECWWWCOMP_ = {} # :nodoc:
- 256.times do |i|
- h, l = i>>4, i&15
- TBLDECWWWCOMP_[-('%%%X%X' % [h, l])] = -i.chr
- TBLDECWWWCOMP_[-('%%%x%X' % [h, l])] = -i.chr
- TBLDECWWWCOMP_[-('%%%X%x' % [h, l])] = -i.chr
- TBLDECWWWCOMP_[-('%%%x%x' % [h, l])] = -i.chr
- end
- TBLDECWWWCOMP_['+'] = ' '
- TBLDECWWWCOMP_.freeze
-
- # Returns a URL-encoded string derived from the given string +str+.
- #
- # The returned string:
- #
- # - Preserves:
- #
- # - Characters <tt>'*'</tt>, <tt>'.'</tt>, <tt>'-'</tt>, and <tt>'_'</tt>.
- # - Character in ranges <tt>'a'..'z'</tt>, <tt>'A'..'Z'</tt>,
- # and <tt>'0'..'9'</tt>.
- #
- # Example:
- #
- # Gem::URI.encode_www_form_component('*.-_azAZ09')
- # # => "*.-_azAZ09"
- #
- # - Converts:
- #
- # - Character <tt>' '</tt> to character <tt>'+'</tt>.
- # - Any other character to "percent notation";
- # the percent notation for character <i>c</i> is <tt>'%%%X' % c.ord</tt>.
- #
- # Example:
- #
- # Gem::URI.encode_www_form_component('Here are some punctuation characters: ,;?:')
- # # => "Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A"
- #
- # Encoding:
- #
- # - If +str+ has encoding Encoding::ASCII_8BIT, argument +enc+ is ignored.
- # - Otherwise +str+ is converted first to Encoding::UTF_8
- # (with suitable character replacements),
- # and then to encoding +enc+.
- #
- # In either case, the returned string has forced encoding Encoding::US_ASCII.
- #
- # Related: Gem::URI.encode_uri_component (encodes <tt>' '</tt> as <tt>'%20'</tt>).
- def self.encode_www_form_component(str, enc=nil)
- _encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_, str, enc)
- end
-
- # Returns a string decoded from the given \URL-encoded string +str+.
- #
- # The given string is first encoded as Encoding::ASCII-8BIT (using String#b),
- # then decoded (as below), and finally force-encoded to the given encoding +enc+.
- #
- # The returned string:
- #
- # - Preserves:
- #
- # - Characters <tt>'*'</tt>, <tt>'.'</tt>, <tt>'-'</tt>, and <tt>'_'</tt>.
- # - Character in ranges <tt>'a'..'z'</tt>, <tt>'A'..'Z'</tt>,
- # and <tt>'0'..'9'</tt>.
- #
- # Example:
- #
- # Gem::URI.decode_www_form_component('*.-_azAZ09')
- # # => "*.-_azAZ09"
- #
- # - Converts:
- #
- # - Character <tt>'+'</tt> to character <tt>' '</tt>.
- # - Each "percent notation" to an ASCII character.
- #
- # Example:
- #
- # Gem::URI.decode_www_form_component('Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A')
- # # => "Here are some punctuation characters: ,;?:"
- #
- # Related: Gem::URI.decode_uri_component (preserves <tt>'+'</tt>).
- def self.decode_www_form_component(str, enc=Encoding::UTF_8)
- _decode_uri_component(/\+|%\h\h/, str, enc)
- end
-
- # Like Gem::URI.encode_www_form_component, except that <tt>' '</tt> (space)
- # is encoded as <tt>'%20'</tt> (instead of <tt>'+'</tt>).
- def self.encode_uri_component(str, enc=nil)
- _encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCURICOMP_, str, enc)
- end
-
- # Like Gem::URI.decode_www_form_component, except that <tt>'+'</tt> is preserved.
- def self.decode_uri_component(str, enc=Encoding::UTF_8)
- _decode_uri_component(/%\h\h/, str, enc)
- end
-
- def self._encode_uri_component(regexp, table, str, enc)
- str = str.to_s.dup
- if str.encoding != Encoding::ASCII_8BIT
- if enc && enc != Encoding::ASCII_8BIT
- str.encode!(Encoding::UTF_8, invalid: :replace, undef: :replace)
- str.encode!(enc, fallback: ->(x){"&##{x.ord};"})
- end
- str.force_encoding(Encoding::ASCII_8BIT)
- end
- str.gsub!(regexp, table)
- str.force_encoding(Encoding::US_ASCII)
- end
- private_class_method :_encode_uri_component
-
- def self._decode_uri_component(regexp, str, enc)
- raise ArgumentError, "invalid %-encoding (#{str})" if /%(?!\h\h)/.match?(str)
- str.b.gsub(regexp, TBLDECWWWCOMP_).force_encoding(enc)
- end
- private_class_method :_decode_uri_component
-
- # Returns a URL-encoded string derived from the given
- # {Enumerable}[https://docs.ruby-lang.org/en/master/Enumerable.html#module-Enumerable-label-Enumerable+in+Ruby+Classes]
- # +enum+.
- #
- # The result is suitable for use as form data
- # for an \HTTP request whose <tt>Content-Type</tt> is
- # <tt>'application/x-www-form-urlencoded'</tt>.
- #
- # The returned string consists of the elements of +enum+,
- # each converted to one or more URL-encoded strings,
- # and all joined with character <tt>'&'</tt>.
- #
- # Simple examples:
- #
- # Gem::URI.encode_www_form([['foo', 0], ['bar', 1], ['baz', 2]])
- # # => "foo=0&bar=1&baz=2"
- # Gem::URI.encode_www_form({foo: 0, bar: 1, baz: 2})
- # # => "foo=0&bar=1&baz=2"
- #
- # The returned string is formed using method Gem::URI.encode_www_form_component,
- # which converts certain characters:
- #
- # Gem::URI.encode_www_form('f#o': '/', 'b-r': '$', 'b z': '@')
- # # => "f%23o=%2F&b-r=%24&b+z=%40"
- #
- # When +enum+ is Array-like, each element +ele+ is converted to a field:
- #
- # - If +ele+ is an array of two or more elements,
- # the field is formed from its first two elements
- # (and any additional elements are ignored):
- #
- # name = Gem::URI.encode_www_form_component(ele[0], enc)
- # value = Gem::URI.encode_www_form_component(ele[1], enc)
- # "#{name}=#{value}"
- #
- # Examples:
- #
- # Gem::URI.encode_www_form([%w[foo bar], %w[baz bat bah]])
- # # => "foo=bar&baz=bat"
- # Gem::URI.encode_www_form([['foo', 0], ['bar', :baz, 'bat']])
- # # => "foo=0&bar=baz"
- #
- # - If +ele+ is an array of one element,
- # the field is formed from <tt>ele[0]</tt>:
- #
- # Gem::URI.encode_www_form_component(ele[0])
- #
- # Example:
- #
- # Gem::URI.encode_www_form([['foo'], [:bar], [0]])
- # # => "foo&bar&0"
- #
- # - Otherwise the field is formed from +ele+:
- #
- # Gem::URI.encode_www_form_component(ele)
- #
- # Example:
- #
- # Gem::URI.encode_www_form(['foo', :bar, 0])
- # # => "foo&bar&0"
- #
- # The elements of an Array-like +enum+ may be mixture:
- #
- # Gem::URI.encode_www_form([['foo', 0], ['bar', 1, 2], ['baz'], :bat])
- # # => "foo=0&bar=1&baz&bat"
- #
- # When +enum+ is Hash-like,
- # each +key+/+value+ pair is converted to one or more fields:
- #
- # - If +value+ is
- # {Array-convertible}[https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html#label-Array-Convertible+Objects],
- # each element +ele+ in +value+ is paired with +key+ to form a field:
- #
- # name = Gem::URI.encode_www_form_component(key, enc)
- # value = Gem::URI.encode_www_form_component(ele, enc)
- # "#{name}=#{value}"
- #
- # Example:
- #
- # Gem::URI.encode_www_form({foo: [:bar, 1], baz: [:bat, :bam, 2]})
- # # => "foo=bar&foo=1&baz=bat&baz=bam&baz=2"
- #
- # - Otherwise, +key+ and +value+ are paired to form a field:
- #
- # name = Gem::URI.encode_www_form_component(key, enc)
- # value = Gem::URI.encode_www_form_component(value, enc)
- # "#{name}=#{value}"
- #
- # Example:
- #
- # Gem::URI.encode_www_form({foo: 0, bar: 1, baz: 2})
- # # => "foo=0&bar=1&baz=2"
- #
- # The elements of a Hash-like +enum+ may be mixture:
- #
- # Gem::URI.encode_www_form({foo: [0, 1], bar: 2})
- # # => "foo=0&foo=1&bar=2"
- #
- def self.encode_www_form(enum, enc=nil)
- enum.map do |k,v|
- if v.nil?
- encode_www_form_component(k, enc)
- elsif v.respond_to?(:to_ary)
- v.to_ary.map do |w|
- str = encode_www_form_component(k, enc)
- unless w.nil?
- str << '='
- str << encode_www_form_component(w, enc)
- end
- end.join('&')
- else
- str = encode_www_form_component(k, enc)
- str << '='
- str << encode_www_form_component(v, enc)
- end
- end.join('&')
- end
-
- # Returns name/value pairs derived from the given string +str+,
- # which must be an ASCII string.
- #
- # The method may be used to decode the body of Net::HTTPResponse object +res+
- # for which <tt>res['Content-Type']</tt> is <tt>'application/x-www-form-urlencoded'</tt>.
- #
- # The returned data is an array of 2-element subarrays;
- # each subarray is a name/value pair (both are strings).
- # Each returned string has encoding +enc+,
- # and has had invalid characters removed via
- # {String#scrub}[https://docs.ruby-lang.org/en/master/String.html#method-i-scrub].
- #
- # A simple example:
- #
- # Gem::URI.decode_www_form('foo=0&bar=1&baz')
- # # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
- #
- # The returned strings have certain conversions,
- # similar to those performed in Gem::URI.decode_www_form_component:
- #
- # Gem::URI.decode_www_form('f%23o=%2F&b-r=%24&b+z=%40')
- # # => [["f#o", "/"], ["b-r", "$"], ["b z", "@"]]
- #
- # The given string may contain consecutive separators:
- #
- # Gem::URI.decode_www_form('foo=0&&bar=1&&baz=2')
- # # => [["foo", "0"], ["", ""], ["bar", "1"], ["", ""], ["baz", "2"]]
- #
- # A different separator may be specified:
- #
- # Gem::URI.decode_www_form('foo=0--bar=1--baz', separator: '--')
- # # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
- #
- def self.decode_www_form(str, enc=Encoding::UTF_8, separator: '&', use__charset_: false, isindex: false)
- raise ArgumentError, "the input of #{self.name}.#{__method__} must be ASCII only string" unless str.ascii_only?
- ary = []
- return ary if str.empty?
- enc = Encoding.find(enc)
- str.b.each_line(separator) do |string|
- string.chomp!(separator)
- key, sep, val = string.partition('=')
- if isindex
- if sep.empty?
- val = key
- key = +''
- end
- isindex = false
- end
-
- if use__charset_ and key == '_charset_' and e = get_encoding(val)
- enc = e
- use__charset_ = false
- end
-
- key.gsub!(/\+|%\h\h/, TBLDECWWWCOMP_)
- if val
- val.gsub!(/\+|%\h\h/, TBLDECWWWCOMP_)
- else
- val = +''
- end
-
- ary << [key, val]
- end
- ary.each do |k, v|
- k.force_encoding(enc)
- k.scrub!
- v.force_encoding(enc)
- v.scrub!
- end
- ary
- end
-
- private
-=begin command for WEB_ENCODINGS_
- curl https://encoding.spec.whatwg.org/encodings.json|
- ruby -rjson -e 'H={}
- h={
- "shift_jis"=>"Windows-31J",
- "euc-jp"=>"cp51932",
- "iso-2022-jp"=>"cp50221",
- "x-mac-cyrillic"=>"macCyrillic",
- }
- JSON($<.read).map{|x|x["encodings"]}.flatten.each{|x|
- Encoding.find(n=h.fetch(n=x["name"].downcase,n))rescue next
- x["labels"].each{|y|H[y]=n}
- }
- puts "{"
- H.each{|k,v|puts %[ #{k.dump}=>#{v.dump},]}
- puts "}"
-'
-=end
- WEB_ENCODINGS_ = {
- "unicode-1-1-utf-8"=>"utf-8",
- "utf-8"=>"utf-8",
- "utf8"=>"utf-8",
- "866"=>"ibm866",
- "cp866"=>"ibm866",
- "csibm866"=>"ibm866",
- "ibm866"=>"ibm866",
- "csisolatin2"=>"iso-8859-2",
- "iso-8859-2"=>"iso-8859-2",
- "iso-ir-101"=>"iso-8859-2",
- "iso8859-2"=>"iso-8859-2",
- "iso88592"=>"iso-8859-2",
- "iso_8859-2"=>"iso-8859-2",
- "iso_8859-2:1987"=>"iso-8859-2",
- "l2"=>"iso-8859-2",
- "latin2"=>"iso-8859-2",
- "csisolatin3"=>"iso-8859-3",
- "iso-8859-3"=>"iso-8859-3",
- "iso-ir-109"=>"iso-8859-3",
- "iso8859-3"=>"iso-8859-3",
- "iso88593"=>"iso-8859-3",
- "iso_8859-3"=>"iso-8859-3",
- "iso_8859-3:1988"=>"iso-8859-3",
- "l3"=>"iso-8859-3",
- "latin3"=>"iso-8859-3",
- "csisolatin4"=>"iso-8859-4",
- "iso-8859-4"=>"iso-8859-4",
- "iso-ir-110"=>"iso-8859-4",
- "iso8859-4"=>"iso-8859-4",
- "iso88594"=>"iso-8859-4",
- "iso_8859-4"=>"iso-8859-4",
- "iso_8859-4:1988"=>"iso-8859-4",
- "l4"=>"iso-8859-4",
- "latin4"=>"iso-8859-4",
- "csisolatincyrillic"=>"iso-8859-5",
- "cyrillic"=>"iso-8859-5",
- "iso-8859-5"=>"iso-8859-5",
- "iso-ir-144"=>"iso-8859-5",
- "iso8859-5"=>"iso-8859-5",
- "iso88595"=>"iso-8859-5",
- "iso_8859-5"=>"iso-8859-5",
- "iso_8859-5:1988"=>"iso-8859-5",
- "arabic"=>"iso-8859-6",
- "asmo-708"=>"iso-8859-6",
- "csiso88596e"=>"iso-8859-6",
- "csiso88596i"=>"iso-8859-6",
- "csisolatinarabic"=>"iso-8859-6",
- "ecma-114"=>"iso-8859-6",
- "iso-8859-6"=>"iso-8859-6",
- "iso-8859-6-e"=>"iso-8859-6",
- "iso-8859-6-i"=>"iso-8859-6",
- "iso-ir-127"=>"iso-8859-6",
- "iso8859-6"=>"iso-8859-6",
- "iso88596"=>"iso-8859-6",
- "iso_8859-6"=>"iso-8859-6",
- "iso_8859-6:1987"=>"iso-8859-6",
- "csisolatingreek"=>"iso-8859-7",
- "ecma-118"=>"iso-8859-7",
- "elot_928"=>"iso-8859-7",
- "greek"=>"iso-8859-7",
- "greek8"=>"iso-8859-7",
- "iso-8859-7"=>"iso-8859-7",
- "iso-ir-126"=>"iso-8859-7",
- "iso8859-7"=>"iso-8859-7",
- "iso88597"=>"iso-8859-7",
- "iso_8859-7"=>"iso-8859-7",
- "iso_8859-7:1987"=>"iso-8859-7",
- "sun_eu_greek"=>"iso-8859-7",
- "csiso88598e"=>"iso-8859-8",
- "csisolatinhebrew"=>"iso-8859-8",
- "hebrew"=>"iso-8859-8",
- "iso-8859-8"=>"iso-8859-8",
- "iso-8859-8-e"=>"iso-8859-8",
- "iso-ir-138"=>"iso-8859-8",
- "iso8859-8"=>"iso-8859-8",
- "iso88598"=>"iso-8859-8",
- "iso_8859-8"=>"iso-8859-8",
- "iso_8859-8:1988"=>"iso-8859-8",
- "visual"=>"iso-8859-8",
- "csisolatin6"=>"iso-8859-10",
- "iso-8859-10"=>"iso-8859-10",
- "iso-ir-157"=>"iso-8859-10",
- "iso8859-10"=>"iso-8859-10",
- "iso885910"=>"iso-8859-10",
- "l6"=>"iso-8859-10",
- "latin6"=>"iso-8859-10",
- "iso-8859-13"=>"iso-8859-13",
- "iso8859-13"=>"iso-8859-13",
- "iso885913"=>"iso-8859-13",
- "iso-8859-14"=>"iso-8859-14",
- "iso8859-14"=>"iso-8859-14",
- "iso885914"=>"iso-8859-14",
- "csisolatin9"=>"iso-8859-15",
- "iso-8859-15"=>"iso-8859-15",
- "iso8859-15"=>"iso-8859-15",
- "iso885915"=>"iso-8859-15",
- "iso_8859-15"=>"iso-8859-15",
- "l9"=>"iso-8859-15",
- "iso-8859-16"=>"iso-8859-16",
- "cskoi8r"=>"koi8-r",
- "koi"=>"koi8-r",
- "koi8"=>"koi8-r",
- "koi8-r"=>"koi8-r",
- "koi8_r"=>"koi8-r",
- "koi8-ru"=>"koi8-u",
- "koi8-u"=>"koi8-u",
- "dos-874"=>"windows-874",
- "iso-8859-11"=>"windows-874",
- "iso8859-11"=>"windows-874",
- "iso885911"=>"windows-874",
- "tis-620"=>"windows-874",
- "windows-874"=>"windows-874",
- "cp1250"=>"windows-1250",
- "windows-1250"=>"windows-1250",
- "x-cp1250"=>"windows-1250",
- "cp1251"=>"windows-1251",
- "windows-1251"=>"windows-1251",
- "x-cp1251"=>"windows-1251",
- "ansi_x3.4-1968"=>"windows-1252",
- "ascii"=>"windows-1252",
- "cp1252"=>"windows-1252",
- "cp819"=>"windows-1252",
- "csisolatin1"=>"windows-1252",
- "ibm819"=>"windows-1252",
- "iso-8859-1"=>"windows-1252",
- "iso-ir-100"=>"windows-1252",
- "iso8859-1"=>"windows-1252",
- "iso88591"=>"windows-1252",
- "iso_8859-1"=>"windows-1252",
- "iso_8859-1:1987"=>"windows-1252",
- "l1"=>"windows-1252",
- "latin1"=>"windows-1252",
- "us-ascii"=>"windows-1252",
- "windows-1252"=>"windows-1252",
- "x-cp1252"=>"windows-1252",
- "cp1253"=>"windows-1253",
- "windows-1253"=>"windows-1253",
- "x-cp1253"=>"windows-1253",
- "cp1254"=>"windows-1254",
- "csisolatin5"=>"windows-1254",
- "iso-8859-9"=>"windows-1254",
- "iso-ir-148"=>"windows-1254",
- "iso8859-9"=>"windows-1254",
- "iso88599"=>"windows-1254",
- "iso_8859-9"=>"windows-1254",
- "iso_8859-9:1989"=>"windows-1254",
- "l5"=>"windows-1254",
- "latin5"=>"windows-1254",
- "windows-1254"=>"windows-1254",
- "x-cp1254"=>"windows-1254",
- "cp1255"=>"windows-1255",
- "windows-1255"=>"windows-1255",
- "x-cp1255"=>"windows-1255",
- "cp1256"=>"windows-1256",
- "windows-1256"=>"windows-1256",
- "x-cp1256"=>"windows-1256",
- "cp1257"=>"windows-1257",
- "windows-1257"=>"windows-1257",
- "x-cp1257"=>"windows-1257",
- "cp1258"=>"windows-1258",
- "windows-1258"=>"windows-1258",
- "x-cp1258"=>"windows-1258",
- "x-mac-cyrillic"=>"macCyrillic",
- "x-mac-ukrainian"=>"macCyrillic",
- "chinese"=>"gbk",
- "csgb2312"=>"gbk",
- "csiso58gb231280"=>"gbk",
- "gb2312"=>"gbk",
- "gb_2312"=>"gbk",
- "gb_2312-80"=>"gbk",
- "gbk"=>"gbk",
- "iso-ir-58"=>"gbk",
- "x-gbk"=>"gbk",
- "gb18030"=>"gb18030",
- "big5"=>"big5",
- "big5-hkscs"=>"big5",
- "cn-big5"=>"big5",
- "csbig5"=>"big5",
- "x-x-big5"=>"big5",
- "cseucpkdfmtjapanese"=>"cp51932",
- "euc-jp"=>"cp51932",
- "x-euc-jp"=>"cp51932",
- "csiso2022jp"=>"cp50221",
- "iso-2022-jp"=>"cp50221",
- "csshiftjis"=>"Windows-31J",
- "ms932"=>"Windows-31J",
- "ms_kanji"=>"Windows-31J",
- "shift-jis"=>"Windows-31J",
- "shift_jis"=>"Windows-31J",
- "sjis"=>"Windows-31J",
- "windows-31j"=>"Windows-31J",
- "x-sjis"=>"Windows-31J",
- "cseuckr"=>"euc-kr",
- "csksc56011987"=>"euc-kr",
- "euc-kr"=>"euc-kr",
- "iso-ir-149"=>"euc-kr",
- "korean"=>"euc-kr",
- "ks_c_5601-1987"=>"euc-kr",
- "ks_c_5601-1989"=>"euc-kr",
- "ksc5601"=>"euc-kr",
- "ksc_5601"=>"euc-kr",
- "windows-949"=>"euc-kr",
- "utf-16be"=>"utf-16be",
- "utf-16"=>"utf-16le",
- "utf-16le"=>"utf-16le",
- } # :nodoc:
- Ractor.make_shareable(WEB_ENCODINGS_) if defined?(Ractor)
-
- # :nodoc:
- # return encoding or nil
- # http://encoding.spec.whatwg.org/#concept-encoding-get
- def self.get_encoding(label)
- Encoding.find(WEB_ENCODINGS_[label.to_str.strip.downcase]) rescue nil
- end
-end # module Gem::URI
-
-module Gem
-
- #
- # Returns a \Gem::URI object derived from the given +uri+,
- # which may be a \Gem::URI string or an existing \Gem::URI object:
- #
- # # Returns a new Gem::URI.
- # uri = Gem::URI('http://github.com/ruby/ruby')
- # # => #<Gem::URI::HTTP http://github.com/ruby/ruby>
- # # Returns the given Gem::URI.
- # Gem::URI(uri)
- # # => #<Gem::URI::HTTP http://github.com/ruby/ruby>
- #
- def URI(uri)
- if uri.is_a?(Gem::URI::Generic)
- uri
- elsif uri = String.try_convert(uri)
- Gem::URI.parse(uri)
- else
- raise ArgumentError,
- "bad argument (expected Gem::URI object or Gem::URI string)"
- end
- end
- module_function :URI
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/file.rb b/lib/rubygems/vendor/uri/lib/uri/file.rb
deleted file mode 100644
index d419b26055..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/file.rb
+++ /dev/null
@@ -1,100 +0,0 @@
-# frozen_string_literal: true
-
-require_relative 'generic'
-
-module Gem::URI
-
- #
- # The "file" Gem::URI is defined by RFC8089.
- #
- class File < Generic
- # A Default port of nil for Gem::URI::File.
- DEFAULT_PORT = nil
-
- #
- # An Array of the available components for Gem::URI::File.
- #
- COMPONENT = [
- :scheme,
- :host,
- :path
- ].freeze
-
- #
- # == Description
- #
- # Creates a new Gem::URI::File object from components, with syntax checking.
- #
- # The components accepted are +host+ and +path+.
- #
- # The components should be provided either as an Array, or as a Hash
- # with keys formed by preceding the component names with a colon.
- #
- # If an Array is used, the components must be passed in the
- # order <code>[host, path]</code>.
- #
- # A path from e.g. the File class should be escaped before
- # being passed.
- #
- # Examples:
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri1 = Gem::URI::File.build(['host.example.com', '/path/file.zip'])
- # uri1.to_s # => "file://host.example.com/path/file.zip"
- #
- # uri2 = Gem::URI::File.build({:host => 'host.example.com',
- # :path => '/ruby/src'})
- # uri2.to_s # => "file://host.example.com/ruby/src"
- #
- # uri3 = Gem::URI::File.build({:path => Gem::URI::escape('/path/my file.txt')})
- # uri3.to_s # => "file:///path/my%20file.txt"
- #
- def self.build(args)
- tmp = Util::make_components_hash(self, args)
- super(tmp)
- end
-
- # Protected setter for the host component +v+.
- #
- # See also Gem::URI::Generic.host=.
- #
- def set_host(v)
- v = "" if v.nil? || v == "localhost"
- @host = v
- end
-
- # do nothing
- def set_port(v)
- end
-
- # raise InvalidURIError
- def check_userinfo(user)
- raise Gem::URI::InvalidURIError, "can not set userinfo for file Gem::URI"
- end
-
- # raise InvalidURIError
- def check_user(user)
- raise Gem::URI::InvalidURIError, "can not set user for file Gem::URI"
- end
-
- # raise InvalidURIError
- def check_password(user)
- raise Gem::URI::InvalidURIError, "can not set password for file Gem::URI"
- end
-
- # do nothing
- def set_userinfo(v)
- end
-
- # do nothing
- def set_user(v)
- end
-
- # do nothing
- def set_password(v)
- end
- end
-
- register_scheme 'FILE', File
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/ftp.rb b/lib/rubygems/vendor/uri/lib/uri/ftp.rb
deleted file mode 100644
index 100498ffb2..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/ftp.rb
+++ /dev/null
@@ -1,267 +0,0 @@
-# frozen_string_literal: false
-# = uri/ftp.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'generic'
-
-module Gem::URI
-
- #
- # FTP Gem::URI syntax is defined by RFC1738 section 3.2.
- #
- # This class will be redesigned because of difference of implementations;
- # the structure of its path. draft-hoffman-ftp-uri-04 is a draft but it
- # is a good summary about the de facto spec.
- # http://tools.ietf.org/html/draft-hoffman-ftp-uri-04
- #
- class FTP < Generic
- # A Default port of 21 for Gem::URI::FTP.
- DEFAULT_PORT = 21
-
- #
- # An Array of the available components for Gem::URI::FTP.
- #
- COMPONENT = [
- :scheme,
- :userinfo, :host, :port,
- :path, :typecode
- ].freeze
-
- #
- # Typecode is "a", "i", or "d".
- #
- # * "a" indicates a text file (the FTP command was ASCII)
- # * "i" indicates a binary file (FTP command IMAGE)
- # * "d" indicates the contents of a directory should be displayed
- #
- TYPECODE = ['a', 'i', 'd'].freeze
-
- # Typecode prefix ";type=".
- TYPECODE_PREFIX = ';type='.freeze
-
- def self.new2(user, password, host, port, path,
- typecode = nil, arg_check = true) # :nodoc:
- # Do not use this method! Not tested. [Bug #7301]
- # This methods remains just for compatibility,
- # Keep it undocumented until the active maintainer is assigned.
- typecode = nil if typecode.size == 0
- if typecode && !TYPECODE.include?(typecode)
- raise ArgumentError,
- "bad typecode is specified: #{typecode}"
- end
-
- # do escape
-
- self.new('ftp',
- [user, password],
- host, port, nil,
- typecode ? path + TYPECODE_PREFIX + typecode : path,
- nil, nil, nil, arg_check)
- end
-
- #
- # == Description
- #
- # Creates a new Gem::URI::FTP object from components, with syntax checking.
- #
- # The components accepted are +userinfo+, +host+, +port+, +path+, and
- # +typecode+.
- #
- # The components should be provided either as an Array, or as a Hash
- # with keys formed by preceding the component names with a colon.
- #
- # If an Array is used, the components must be passed in the
- # order <code>[userinfo, host, port, path, typecode]</code>.
- #
- # If the path supplied is absolute, it will be escaped in order to
- # make it absolute in the Gem::URI.
- #
- # Examples:
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri1 = Gem::URI::FTP.build(['user:password', 'ftp.example.com', nil,
- # '/path/file.zip', 'i'])
- # uri1.to_s # => "ftp://user:password@ftp.example.com/%2Fpath/file.zip;type=i"
- #
- # uri2 = Gem::URI::FTP.build({:host => 'ftp.example.com',
- # :path => 'ruby/src'})
- # uri2.to_s # => "ftp://ftp.example.com/ruby/src"
- #
- def self.build(args)
-
- # Fix the incoming path to be generic URL syntax
- # FTP path -> URL path
- # foo/bar /foo/bar
- # /foo/bar /%2Ffoo/bar
- #
- if args.kind_of?(Array)
- args[3] = '/' + args[3].sub(/^\//, '%2F')
- else
- args[:path] = '/' + args[:path].sub(/^\//, '%2F')
- end
-
- tmp = Util::make_components_hash(self, args)
-
- if tmp[:typecode]
- if tmp[:typecode].size == 1
- tmp[:typecode] = TYPECODE_PREFIX + tmp[:typecode]
- end
- tmp[:path] << tmp[:typecode]
- end
-
- return super(tmp)
- end
-
- #
- # == Description
- #
- # Creates a new Gem::URI::FTP object from generic URL components with no
- # syntax checking.
- #
- # Unlike build(), this method does not escape the path component as
- # required by RFC1738; instead it is treated as per RFC2396.
- #
- # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+,
- # +opaque+, +query+, and +fragment+, in that order.
- #
- def initialize(scheme,
- userinfo, host, port, registry,
- path, opaque,
- query,
- fragment,
- parser = nil,
- arg_check = false)
- raise InvalidURIError unless path
- path = path.sub(/^\//,'')
- path.sub!(/^%2F/,'/')
- super(scheme, userinfo, host, port, registry, path, opaque,
- query, fragment, parser, arg_check)
- @typecode = nil
- if tmp = @path.index(TYPECODE_PREFIX)
- typecode = @path[tmp + TYPECODE_PREFIX.size..-1]
- @path = @path[0..tmp - 1]
-
- if arg_check
- self.typecode = typecode
- else
- self.set_typecode(typecode)
- end
- end
- end
-
- # typecode accessor.
- #
- # See Gem::URI::FTP::COMPONENT.
- attr_reader :typecode
-
- # Validates typecode +v+,
- # returns +true+ or +false+.
- #
- def check_typecode(v)
- if TYPECODE.include?(v)
- return true
- else
- raise InvalidComponentError,
- "bad typecode(expected #{TYPECODE.join(', ')}): #{v}"
- end
- end
- private :check_typecode
-
- # Private setter for the typecode +v+.
- #
- # See also Gem::URI::FTP.typecode=.
- #
- def set_typecode(v)
- @typecode = v
- end
- protected :set_typecode
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the typecode +v+
- # (with validation).
- #
- # See also Gem::URI::FTP.check_typecode.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("ftp://john@ftp.example.com/my_file.img")
- # #=> #<Gem::URI::FTP ftp://john@ftp.example.com/my_file.img>
- # uri.typecode = "i"
- # uri
- # #=> #<Gem::URI::FTP ftp://john@ftp.example.com/my_file.img;type=i>
- #
- def typecode=(typecode)
- check_typecode(typecode)
- set_typecode(typecode)
- typecode
- end
-
- def merge(oth) # :nodoc:
- tmp = super(oth)
- if self != tmp
- tmp.set_typecode(oth.typecode)
- end
-
- return tmp
- end
-
- # Returns the path from an FTP Gem::URI.
- #
- # RFC 1738 specifically states that the path for an FTP Gem::URI does not
- # include the / which separates the Gem::URI path from the Gem::URI host. Example:
- #
- # <code>ftp://ftp.example.com/pub/ruby</code>
- #
- # The above Gem::URI indicates that the client should connect to
- # ftp.example.com then cd to pub/ruby from the initial login directory.
- #
- # If you want to cd to an absolute directory, you must include an
- # escaped / (%2F) in the path. Example:
- #
- # <code>ftp://ftp.example.com/%2Fpub/ruby</code>
- #
- # This method will then return "/pub/ruby".
- #
- def path
- return @path.sub(/^\//,'').sub(/^%2F/,'/')
- end
-
- # Private setter for the path of the Gem::URI::FTP.
- def set_path(v)
- super("/" + v.sub(/^\//, "%2F"))
- end
- protected :set_path
-
- # Returns a String representation of the Gem::URI::FTP.
- def to_s
- save_path = nil
- if @typecode
- save_path = @path
- @path = @path + TYPECODE_PREFIX + @typecode
- end
- str = super
- if @typecode
- @path = save_path
- end
-
- return str
- end
- end
-
- register_scheme 'FTP', FTP
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/generic.rb b/lib/rubygems/vendor/uri/lib/uri/generic.rb
deleted file mode 100644
index 72c52aa8ee..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/generic.rb
+++ /dev/null
@@ -1,1588 +0,0 @@
-# frozen_string_literal: true
-
-# = uri/generic.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'common'
-autoload :IPSocket, 'socket'
-autoload :IPAddr, 'ipaddr'
-
-module Gem::URI
-
- #
- # Base class for all Gem::URI classes.
- # Implements generic Gem::URI syntax as per RFC 2396.
- #
- class Generic
- include Gem::URI
-
- #
- # A Default port of nil for Gem::URI::Generic.
- #
- DEFAULT_PORT = nil
-
- #
- # Returns default port.
- #
- def self.default_port
- self::DEFAULT_PORT
- end
-
- #
- # Returns default port.
- #
- def default_port
- self.class.default_port
- end
-
- #
- # An Array of the available components for Gem::URI::Generic.
- #
- COMPONENT = [
- :scheme,
- :userinfo, :host, :port, :registry,
- :path, :opaque,
- :query,
- :fragment
- ].freeze
-
- #
- # Components of the Gem::URI in the order.
- #
- def self.component
- self::COMPONENT
- end
-
- USE_REGISTRY = false # :nodoc:
-
- def self.use_registry # :nodoc:
- self::USE_REGISTRY
- end
-
- #
- # == Synopsis
- #
- # See ::new.
- #
- # == Description
- #
- # At first, tries to create a new Gem::URI::Generic instance using
- # Gem::URI::Generic::build. But, if exception Gem::URI::InvalidComponentError is raised,
- # then it does Gem::URI::Escape.escape all Gem::URI components and tries again.
- #
- def self.build2(args)
- begin
- return self.build(args)
- rescue InvalidComponentError
- if args.kind_of?(Array)
- return self.build(args.collect{|x|
- if x.is_a?(String)
- DEFAULT_PARSER.escape(x)
- else
- x
- end
- })
- elsif args.kind_of?(Hash)
- tmp = {}
- args.each do |key, value|
- tmp[key] = if value
- DEFAULT_PARSER.escape(value)
- else
- value
- end
- end
- return self.build(tmp)
- end
- end
- end
-
- #
- # == Synopsis
- #
- # See ::new.
- #
- # == Description
- #
- # Creates a new Gem::URI::Generic instance from components of Gem::URI::Generic
- # with check. Components are: scheme, userinfo, host, port, registry, path,
- # opaque, query, and fragment. You can provide arguments either by an Array or a Hash.
- # See ::new for hash keys to use or for order of array items.
- #
- def self.build(args)
- if args.kind_of?(Array) &&
- args.size == ::Gem::URI::Generic::COMPONENT.size
- tmp = args.dup
- elsif args.kind_of?(Hash)
- tmp = ::Gem::URI::Generic::COMPONENT.collect do |c|
- if args.include?(c)
- args[c]
- else
- nil
- end
- end
- else
- component = self.class.component rescue ::Gem::URI::Generic::COMPONENT
- raise ArgumentError,
- "expected Array of or Hash of components of #{self.class} (#{component.join(', ')})"
- end
-
- tmp << nil
- tmp << true
- return self.new(*tmp)
- end
-
- #
- # == Args
- #
- # +scheme+::
- # Protocol scheme, i.e. 'http','ftp','mailto' and so on.
- # +userinfo+::
- # User name and password, i.e. 'sdmitry:bla'.
- # +host+::
- # Server host name.
- # +port+::
- # Server port.
- # +registry+::
- # Registry of naming authorities.
- # +path+::
- # Path on server.
- # +opaque+::
- # Opaque part.
- # +query+::
- # Query data.
- # +fragment+::
- # Part of the Gem::URI after '#' character.
- # +parser+::
- # Parser for internal use [Gem::URI::DEFAULT_PARSER by default].
- # +arg_check+::
- # Check arguments [false by default].
- #
- # == Description
- #
- # Creates a new Gem::URI::Generic instance from ``generic'' components without check.
- #
- def initialize(scheme,
- userinfo, host, port, registry,
- path, opaque,
- query,
- fragment,
- parser = DEFAULT_PARSER,
- arg_check = false)
- @scheme = nil
- @user = nil
- @password = nil
- @host = nil
- @port = nil
- @path = nil
- @query = nil
- @opaque = nil
- @fragment = nil
- @parser = parser == DEFAULT_PARSER ? nil : parser
-
- if arg_check
- self.scheme = scheme
- self.userinfo = userinfo
- self.hostname = host
- self.port = port
- self.path = path
- self.query = query
- self.opaque = opaque
- self.fragment = fragment
- else
- self.set_scheme(scheme)
- self.set_userinfo(userinfo)
- self.set_host(host)
- self.set_port(port)
- self.set_path(path)
- self.query = query
- self.set_opaque(opaque)
- self.fragment=(fragment)
- end
- if registry
- raise InvalidURIError,
- "the scheme #{@scheme} does not accept registry part: #{registry} (or bad hostname?)"
- end
-
- @scheme&.freeze
- self.set_path('') if !@path && !@opaque # (see RFC2396 Section 5.2)
- self.set_port(self.default_port) if self.default_port && !@port
- end
-
- #
- # Returns the scheme component of the Gem::URI.
- #
- # Gem::URI("http://foo/bar/baz").scheme #=> "http"
- #
- attr_reader :scheme
-
- # Returns the host component of the Gem::URI.
- #
- # Gem::URI("http://foo/bar/baz").host #=> "foo"
- #
- # It returns nil if no host component exists.
- #
- # Gem::URI("mailto:foo@example.org").host #=> nil
- #
- # The component does not contain the port number.
- #
- # Gem::URI("http://foo:8080/bar/baz").host #=> "foo"
- #
- # Since IPv6 addresses are wrapped with brackets in URIs,
- # this method returns IPv6 addresses wrapped with brackets.
- # This form is not appropriate to pass to socket methods such as TCPSocket.open.
- # If unwrapped host names are required, use the #hostname method.
- #
- # Gem::URI("http://[::1]/bar/baz").host #=> "[::1]"
- # Gem::URI("http://[::1]/bar/baz").hostname #=> "::1"
- #
- attr_reader :host
-
- # Returns the port component of the Gem::URI.
- #
- # Gem::URI("http://foo/bar/baz").port #=> 80
- # Gem::URI("http://foo:8080/bar/baz").port #=> 8080
- #
- attr_reader :port
-
- def registry # :nodoc:
- nil
- end
-
- # Returns the path component of the Gem::URI.
- #
- # Gem::URI("http://foo/bar/baz").path #=> "/bar/baz"
- #
- attr_reader :path
-
- # Returns the query component of the Gem::URI.
- #
- # Gem::URI("http://foo/bar/baz?search=FooBar").query #=> "search=FooBar"
- #
- attr_reader :query
-
- # Returns the opaque part of the Gem::URI.
- #
- # Gem::URI("mailto:foo@example.org").opaque #=> "foo@example.org"
- # Gem::URI("http://foo/bar/baz").opaque #=> nil
- #
- # The portion of the path that does not make use of the slash '/'.
- # The path typically refers to an absolute path or an opaque part.
- # (See RFC2396 Section 3 and 5.2.)
- #
- attr_reader :opaque
-
- # Returns the fragment component of the Gem::URI.
- #
- # Gem::URI("http://foo/bar/baz?search=FooBar#ponies").fragment #=> "ponies"
- #
- attr_reader :fragment
-
- # Returns the parser to be used.
- #
- # Unless a Gem::URI::Parser is defined, DEFAULT_PARSER is used.
- #
- def parser
- if !defined?(@parser) || !@parser
- DEFAULT_PARSER
- else
- @parser || DEFAULT_PARSER
- end
- end
-
- # Replaces self by other Gem::URI object.
- #
- def replace!(oth)
- if self.class != oth.class
- raise ArgumentError, "expected #{self.class} object"
- end
-
- component.each do |c|
- self.__send__("#{c}=", oth.__send__(c))
- end
- end
- private :replace!
-
- #
- # Components of the Gem::URI in the order.
- #
- def component
- self.class.component
- end
-
- #
- # Checks the scheme +v+ component against the Gem::URI::Parser Regexp for :SCHEME.
- #
- def check_scheme(v)
- if v && parser.regexp[:SCHEME] !~ v
- raise InvalidComponentError,
- "bad component(expected scheme component): #{v}"
- end
-
- return true
- end
- private :check_scheme
-
- # Protected setter for the scheme component +v+.
- #
- # See also Gem::URI::Generic.scheme=.
- #
- def set_scheme(v)
- @scheme = v&.downcase
- end
- protected :set_scheme
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the scheme component +v+
- # (with validation).
- #
- # See also Gem::URI::Generic.check_scheme.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com")
- # uri.scheme = "https"
- # uri.to_s #=> "https://my.example.com"
- #
- def scheme=(v)
- check_scheme(v)
- set_scheme(v)
- v
- end
-
- #
- # Checks the +user+ and +password+.
- #
- # If +password+ is not provided, then +user+ is
- # split, using Gem::URI::Generic.split_userinfo, to
- # pull +user+ and +password.
- #
- # See also Gem::URI::Generic.check_user, Gem::URI::Generic.check_password.
- #
- def check_userinfo(user, password = nil)
- if !password
- user, password = split_userinfo(user)
- end
- check_user(user)
- check_password(password, user)
-
- return true
- end
- private :check_userinfo
-
- #
- # Checks the user +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :USERINFO.
- #
- # Can not have a registry or opaque component defined,
- # with a user component defined.
- #
- def check_user(v)
- if @opaque
- raise InvalidURIError,
- "can not set user with opaque"
- end
-
- return v unless v
-
- if parser.regexp[:USERINFO] !~ v
- raise InvalidComponentError,
- "bad component(expected userinfo component or user component): #{v}"
- end
-
- return true
- end
- private :check_user
-
- #
- # Checks the password +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :USERINFO.
- #
- # Can not have a registry or opaque component defined,
- # with a user component defined.
- #
- def check_password(v, user = @user)
- if @opaque
- raise InvalidURIError,
- "can not set password with opaque"
- end
- return v unless v
-
- if !user
- raise InvalidURIError,
- "password component depends user component"
- end
-
- if parser.regexp[:USERINFO] !~ v
- raise InvalidComponentError,
- "bad password component"
- end
-
- return true
- end
- private :check_password
-
- #
- # Sets userinfo, argument is string like 'name:pass'.
- #
- def userinfo=(userinfo)
- if userinfo.nil?
- return nil
- end
- check_userinfo(*userinfo)
- set_userinfo(*userinfo)
- # returns userinfo
- end
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the +user+ component
- # (with validation).
- #
- # See also Gem::URI::Generic.check_user.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://john:S3nsit1ve@my.example.com")
- # uri.user = "sam"
- # uri.to_s #=> "http://sam:V3ry_S3nsit1ve@my.example.com"
- #
- def user=(user)
- check_user(user)
- set_user(user)
- # returns user
- end
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the +password+ component
- # (with validation).
- #
- # See also Gem::URI::Generic.check_password.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://john:S3nsit1ve@my.example.com")
- # uri.password = "V3ry_S3nsit1ve"
- # uri.to_s #=> "http://john:V3ry_S3nsit1ve@my.example.com"
- #
- def password=(password)
- check_password(password)
- set_password(password)
- # returns password
- end
-
- # Protected setter for the +user+ component, and +password+ if available
- # (with validation).
- #
- # See also Gem::URI::Generic.userinfo=.
- #
- def set_userinfo(user, password = nil)
- unless password
- user, password = split_userinfo(user)
- end
- @user = user
- @password = password if password
-
- [@user, @password]
- end
- protected :set_userinfo
-
- # Protected setter for the user component +v+.
- #
- # See also Gem::URI::Generic.user=.
- #
- def set_user(v)
- set_userinfo(v, @password)
- v
- end
- protected :set_user
-
- # Protected setter for the password component +v+.
- #
- # See also Gem::URI::Generic.password=.
- #
- def set_password(v)
- @password = v
- # returns v
- end
- protected :set_password
-
- # Returns the userinfo +ui+ as <code>[user, password]</code>
- # if properly formatted as 'user:password'.
- def split_userinfo(ui)
- return nil, nil unless ui
- user, password = ui.split(':', 2)
-
- return user, password
- end
- private :split_userinfo
-
- # Escapes 'user:password' +v+ based on RFC 1738 section 3.1.
- def escape_userpass(v)
- parser.escape(v, /[@:\/]/o) # RFC 1738 section 3.1 #/
- end
- private :escape_userpass
-
- # Returns the userinfo, either as 'user' or 'user:password'.
- def userinfo
- if @user.nil?
- nil
- elsif @password.nil?
- @user
- else
- @user + ':' + @password
- end
- end
-
- # Returns the user component (without Gem::URI decoding).
- def user
- @user
- end
-
- # Returns the password component (without Gem::URI decoding).
- def password
- @password
- end
-
- # Returns the user component after Gem::URI decoding.
- def decoded_user
- Gem::URI.decode_uri_component(@user) if @user
- end
-
- # Returns the password component after Gem::URI decoding.
- def decoded_password
- Gem::URI.decode_uri_component(@password) if @password
- end
-
- #
- # Checks the host +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :HOST.
- #
- # Can not have a registry or opaque component defined,
- # with a host component defined.
- #
- def check_host(v)
- return v unless v
-
- if @opaque
- raise InvalidURIError,
- "can not set host with registry or opaque"
- elsif parser.regexp[:HOST] !~ v
- raise InvalidComponentError,
- "bad component(expected host component): #{v}"
- end
-
- return true
- end
- private :check_host
-
- # Protected setter for the host component +v+.
- #
- # See also Gem::URI::Generic.host=.
- #
- def set_host(v)
- @host = v
- end
- protected :set_host
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the host component +v+
- # (with validation).
- #
- # See also Gem::URI::Generic.check_host.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com")
- # uri.host = "foo.com"
- # uri.to_s #=> "http://foo.com"
- #
- def host=(v)
- check_host(v)
- set_host(v)
- v
- end
-
- # Extract the host part of the Gem::URI and unwrap brackets for IPv6 addresses.
- #
- # This method is the same as Gem::URI::Generic#host except
- # brackets for IPv6 (and future IP) addresses are removed.
- #
- # uri = Gem::URI("http://[::1]/bar")
- # uri.hostname #=> "::1"
- # uri.host #=> "[::1]"
- #
- def hostname
- v = self.host
- v&.start_with?('[') && v.end_with?(']') ? v[1..-2] : v
- end
-
- # Sets the host part of the Gem::URI as the argument with brackets for IPv6 addresses.
- #
- # This method is the same as Gem::URI::Generic#host= except
- # the argument can be a bare IPv6 address.
- #
- # uri = Gem::URI("http://foo/bar")
- # uri.hostname = "::1"
- # uri.to_s #=> "http://[::1]/bar"
- #
- # If the argument seems to be an IPv6 address,
- # it is wrapped with brackets.
- #
- def hostname=(v)
- v = "[#{v}]" if !(v&.start_with?('[') && v&.end_with?(']')) && v&.index(':')
- self.host = v
- end
-
- #
- # Checks the port +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp for :PORT.
- #
- # Can not have a registry or opaque component defined,
- # with a port component defined.
- #
- def check_port(v)
- return v unless v
-
- if @opaque
- raise InvalidURIError,
- "can not set port with registry or opaque"
- elsif !v.kind_of?(Integer) && parser.regexp[:PORT] !~ v
- raise InvalidComponentError,
- "bad component(expected port component): #{v.inspect}"
- end
-
- return true
- end
- private :check_port
-
- # Protected setter for the port component +v+.
- #
- # See also Gem::URI::Generic.port=.
- #
- def set_port(v)
- v = v.empty? ? nil : v.to_i unless !v || v.kind_of?(Integer)
- @port = v
- end
- protected :set_port
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the port component +v+
- # (with validation).
- #
- # See also Gem::URI::Generic.check_port.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com")
- # uri.port = 8080
- # uri.to_s #=> "http://my.example.com:8080"
- #
- def port=(v)
- check_port(v)
- set_port(v)
- port
- end
-
- def check_registry(v) # :nodoc:
- raise InvalidURIError, "can not set registry"
- end
- private :check_registry
-
- def set_registry(v) #:nodoc:
- raise InvalidURIError, "can not set registry"
- end
- protected :set_registry
-
- def registry=(v)
- raise InvalidURIError, "can not set registry"
- end
-
- #
- # Checks the path +v+ component for RFC2396 compliance
- # and against the Gem::URI::Parser Regexp
- # for :ABS_PATH and :REL_PATH.
- #
- # Can not have a opaque component defined,
- # with a path component defined.
- #
- def check_path(v)
- # raise if both hier and opaque are not nil, because:
- # absoluteURI = scheme ":" ( hier_part | opaque_part )
- # hier_part = ( net_path | abs_path ) [ "?" query ]
- if v && @opaque
- raise InvalidURIError,
- "path conflicts with opaque"
- end
-
- # If scheme is ftp, path may be relative.
- # See RFC 1738 section 3.2.2, and RFC 2396.
- if @scheme && @scheme != "ftp"
- if v && v != '' && parser.regexp[:ABS_PATH] !~ v
- raise InvalidComponentError,
- "bad component(expected absolute path component): #{v}"
- end
- else
- if v && v != '' && parser.regexp[:ABS_PATH] !~ v &&
- parser.regexp[:REL_PATH] !~ v
- raise InvalidComponentError,
- "bad component(expected relative path component): #{v}"
- end
- end
-
- return true
- end
- private :check_path
-
- # Protected setter for the path component +v+.
- #
- # See also Gem::URI::Generic.path=.
- #
- def set_path(v)
- @path = v
- end
- protected :set_path
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the path component +v+
- # (with validation).
- #
- # See also Gem::URI::Generic.check_path.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com/pub/files")
- # uri.path = "/faq/"
- # uri.to_s #=> "http://my.example.com/faq/"
- #
- def path=(v)
- check_path(v)
- set_path(v)
- v
- end
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the query component +v+.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com/?id=25")
- # uri.query = "id=1"
- # uri.to_s #=> "http://my.example.com/?id=1"
- #
- def query=(v)
- return @query = nil unless v
- raise InvalidURIError, "query conflicts with opaque" if @opaque
-
- x = v.to_str
- v = x.dup if x.equal? v
- v.encode!(Encoding::UTF_8) rescue nil
- v.delete!("\t\r\n")
- v.force_encoding(Encoding::ASCII_8BIT)
- raise InvalidURIError, "invalid percent escape: #{$1}" if /(%\H\H)/n.match(v)
- v.gsub!(/(?!%\h\h|[!$-&(-;=?-_a-~])./n.freeze){'%%%02X' % $&.ord}
- v.force_encoding(Encoding::US_ASCII)
- @query = v
- end
-
- #
- # Checks the opaque +v+ component for RFC2396 compliance and
- # against the Gem::URI::Parser Regexp for :OPAQUE.
- #
- # Can not have a host, port, user, or path component defined,
- # with an opaque component defined.
- #
- def check_opaque(v)
- return v unless v
-
- # raise if both hier and opaque are not nil, because:
- # absoluteURI = scheme ":" ( hier_part | opaque_part )
- # hier_part = ( net_path | abs_path ) [ "?" query ]
- if @host || @port || @user || @path # userinfo = @user + ':' + @password
- raise InvalidURIError,
- "can not set opaque with host, port, userinfo or path"
- elsif v && parser.regexp[:OPAQUE] !~ v
- raise InvalidComponentError,
- "bad component(expected opaque component): #{v}"
- end
-
- return true
- end
- private :check_opaque
-
- # Protected setter for the opaque component +v+.
- #
- # See also Gem::URI::Generic.opaque=.
- #
- def set_opaque(v)
- @opaque = v
- end
- protected :set_opaque
-
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the opaque component +v+
- # (with validation).
- #
- # See also Gem::URI::Generic.check_opaque.
- #
- def opaque=(v)
- check_opaque(v)
- set_opaque(v)
- v
- end
-
- #
- # Checks the fragment +v+ component against the Gem::URI::Parser Regexp for :FRAGMENT.
- #
- #
- # == Args
- #
- # +v+::
- # String
- #
- # == Description
- #
- # Public setter for the fragment component +v+
- # (with validation).
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com/?id=25#time=1305212049")
- # uri.fragment = "time=1305212086"
- # uri.to_s #=> "http://my.example.com/?id=25#time=1305212086"
- #
- def fragment=(v)
- return @fragment = nil unless v
-
- x = v.to_str
- v = x.dup if x.equal? v
- v.encode!(Encoding::UTF_8) rescue nil
- v.delete!("\t\r\n")
- v.force_encoding(Encoding::ASCII_8BIT)
- v.gsub!(/(?!%\h\h|[!-~])./n){'%%%02X' % $&.ord}
- v.force_encoding(Encoding::US_ASCII)
- @fragment = v
- end
-
- #
- # Returns true if Gem::URI is hierarchical.
- #
- # == Description
- #
- # Gem::URI has components listed in order of decreasing significance from left to right,
- # see RFC3986 https://tools.ietf.org/html/rfc3986 1.2.3.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com/")
- # uri.hierarchical?
- # #=> true
- # uri = Gem::URI.parse("mailto:joe@example.com")
- # uri.hierarchical?
- # #=> false
- #
- def hierarchical?
- if @path
- true
- else
- false
- end
- end
-
- #
- # Returns true if Gem::URI has a scheme (e.g. http:// or https://) specified.
- #
- def absolute?
- if @scheme
- true
- else
- false
- end
- end
- alias absolute absolute?
-
- #
- # Returns true if Gem::URI does not have a scheme (e.g. http:// or https://) specified.
- #
- def relative?
- !absolute?
- end
-
- #
- # Returns an Array of the path split on '/'.
- #
- def split_path(path)
- path.split("/", -1)
- end
- private :split_path
-
- #
- # Merges a base path +base+, with relative path +rel+,
- # returns a modified base path.
- #
- def merge_path(base, rel)
-
- # RFC2396, Section 5.2, 5)
- # RFC2396, Section 5.2, 6)
- base_path = split_path(base)
- rel_path = split_path(rel)
-
- # RFC2396, Section 5.2, 6), a)
- base_path << '' if base_path.last == '..'
- while i = base_path.index('..')
- base_path.slice!(i - 1, 2)
- end
-
- if (first = rel_path.first) and first.empty?
- base_path.clear
- rel_path.shift
- end
-
- # RFC2396, Section 5.2, 6), c)
- # RFC2396, Section 5.2, 6), d)
- rel_path.push('') if rel_path.last == '.' || rel_path.last == '..'
- rel_path.delete('.')
-
- # RFC2396, Section 5.2, 6), e)
- tmp = []
- rel_path.each do |x|
- if x == '..' &&
- !(tmp.empty? || tmp.last == '..')
- tmp.pop
- else
- tmp << x
- end
- end
-
- add_trailer_slash = !tmp.empty?
- if base_path.empty?
- base_path = [''] # keep '/' for root directory
- elsif add_trailer_slash
- base_path.pop
- end
- while x = tmp.shift
- if x == '..'
- # RFC2396, Section 4
- # a .. or . in an absolute path has no special meaning
- base_path.pop if base_path.size > 1
- else
- # if x == '..'
- # valid absolute (but abnormal) path "/../..."
- # else
- # valid absolute path
- # end
- base_path << x
- tmp.each {|t| base_path << t}
- add_trailer_slash = false
- break
- end
- end
- base_path.push('') if add_trailer_slash
-
- return base_path.join('/')
- end
- private :merge_path
-
- #
- # == Args
- #
- # +oth+::
- # Gem::URI or String
- #
- # == Description
- #
- # Destructive form of #merge.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com")
- # uri.merge!("/main.rbx?page=1")
- # uri.to_s # => "http://my.example.com/main.rbx?page=1"
- #
- def merge!(oth)
- t = merge(oth)
- if self == t
- nil
- else
- replace!(t)
- self
- end
- end
-
- #
- # == Args
- #
- # +oth+::
- # Gem::URI or String
- #
- # == Description
- #
- # Merges two URIs.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com")
- # uri.merge("/main.rbx?page=1")
- # # => "http://my.example.com/main.rbx?page=1"
- #
- def merge(oth)
- rel = parser.__send__(:convert_to_uri, oth)
-
- if rel.absolute?
- #raise BadURIError, "both Gem::URI are absolute" if absolute?
- # hmm... should return oth for usability?
- return rel
- end
-
- unless self.absolute?
- raise BadURIError, "both Gem::URI are relative"
- end
-
- base = self.dup
-
- authority = rel.userinfo || rel.host || rel.port
-
- # RFC2396, Section 5.2, 2)
- if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query
- base.fragment=(rel.fragment) if rel.fragment
- return base
- end
-
- base.query = nil
- base.fragment=(nil)
-
- # RFC2396, Section 5.2, 4)
- if !authority
- base.set_path(merge_path(base.path, rel.path)) if base.path && rel.path
- else
- # RFC2396, Section 5.2, 4)
- base.set_path(rel.path) if rel.path
- end
-
- # RFC2396, Section 5.2, 7)
- base.set_userinfo(rel.userinfo) if rel.userinfo
- base.set_host(rel.host) if rel.host
- base.set_port(rel.port) if rel.port
- base.query = rel.query if rel.query
- base.fragment=(rel.fragment) if rel.fragment
-
- return base
- end # merge
- alias + merge
-
- # :stopdoc:
- def route_from_path(src, dst)
- case dst
- when src
- # RFC2396, Section 4.2
- return ''
- when %r{(?:\A|/)\.\.?(?:/|\z)}
- # dst has abnormal absolute path,
- # like "/./", "/../", "/x/../", ...
- return dst.dup
- end
-
- src_path = src.scan(%r{[^/]*/})
- dst_path = dst.scan(%r{[^/]*/?})
-
- # discard same parts
- while !dst_path.empty? && dst_path.first == src_path.first
- src_path.shift
- dst_path.shift
- end
-
- tmp = dst_path.join
-
- # calculate
- if src_path.empty?
- if tmp.empty?
- return './'
- elsif dst_path.first.include?(':') # (see RFC2396 Section 5)
- return './' + tmp
- else
- return tmp
- end
- end
-
- return '../' * src_path.size + tmp
- end
- private :route_from_path
- # :startdoc:
-
- # :stopdoc:
- def route_from0(oth)
- oth = parser.__send__(:convert_to_uri, oth)
- if self.relative?
- raise BadURIError,
- "relative Gem::URI: #{self}"
- end
- if oth.relative?
- raise BadURIError,
- "relative Gem::URI: #{oth}"
- end
-
- if self.scheme != oth.scheme
- return self, self.dup
- end
- rel = Gem::URI::Generic.new(nil, # it is relative Gem::URI
- self.userinfo, self.host, self.port,
- nil, self.path, self.opaque,
- self.query, self.fragment, parser)
-
- if rel.userinfo != oth.userinfo ||
- rel.host.to_s.downcase != oth.host.to_s.downcase ||
- rel.port != oth.port
-
- if self.userinfo.nil? && self.host.nil?
- return self, self.dup
- end
-
- rel.set_port(nil) if rel.port == oth.default_port
- return rel, rel
- end
- rel.set_userinfo(nil)
- rel.set_host(nil)
- rel.set_port(nil)
-
- if rel.path && rel.path == oth.path
- rel.set_path('')
- rel.query = nil if rel.query == oth.query
- return rel, rel
- elsif rel.opaque && rel.opaque == oth.opaque
- rel.set_opaque('')
- rel.query = nil if rel.query == oth.query
- return rel, rel
- end
-
- # you can modify `rel', but can not `oth'.
- return oth, rel
- end
- private :route_from0
- # :startdoc:
-
- #
- # == Args
- #
- # +oth+::
- # Gem::URI or String
- #
- # == Description
- #
- # Calculates relative path from oth to self.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse('http://my.example.com/main.rbx?page=1')
- # uri.route_from('http://my.example.com')
- # #=> #<Gem::URI::Generic /main.rbx?page=1>
- #
- def route_from(oth)
- # you can modify `rel', but can not `oth'.
- begin
- oth, rel = route_from0(oth)
- rescue
- raise $!.class, $!.message
- end
- if oth == rel
- return rel
- end
-
- rel.set_path(route_from_path(oth.path, self.path))
- if rel.path == './' && self.query
- # "./?foo" -> "?foo"
- rel.set_path('')
- end
-
- return rel
- end
-
- alias - route_from
-
- #
- # == Args
- #
- # +oth+::
- # Gem::URI or String
- #
- # == Description
- #
- # Calculates relative path to oth from self.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse('http://my.example.com')
- # uri.route_to('http://my.example.com/main.rbx?page=1')
- # #=> #<Gem::URI::Generic /main.rbx?page=1>
- #
- def route_to(oth)
- parser.__send__(:convert_to_uri, oth).route_from(self)
- end
-
- #
- # Returns normalized Gem::URI.
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # Gem::URI("HTTP://my.EXAMPLE.com").normalize
- # #=> #<Gem::URI::HTTP http://my.example.com/>
- #
- # Normalization here means:
- #
- # * scheme and host are converted to lowercase,
- # * an empty path component is set to "/".
- #
- def normalize
- uri = dup
- uri.normalize!
- uri
- end
-
- #
- # Destructive version of #normalize.
- #
- def normalize!
- if path&.empty?
- set_path('/')
- end
- if scheme && scheme != scheme.downcase
- set_scheme(self.scheme.downcase)
- end
- if host && host != host.downcase
- set_host(self.host.downcase)
- end
- end
-
- #
- # Constructs String from Gem::URI.
- #
- def to_s
- str = ''.dup
- if @scheme
- str << @scheme
- str << ':'
- end
-
- if @opaque
- str << @opaque
- else
- if @host || %w[file postgres].include?(@scheme)
- str << '//'
- end
- if self.userinfo
- str << self.userinfo
- str << '@'
- end
- if @host
- str << @host
- end
- if @port && @port != self.default_port
- str << ':'
- str << @port.to_s
- end
- str << @path
- if @query
- str << '?'
- str << @query
- end
- end
- if @fragment
- str << '#'
- str << @fragment
- end
- str
- end
- alias to_str to_s
-
- #
- # Compares two URIs.
- #
- def ==(oth)
- if self.class == oth.class
- self.normalize.component_ary == oth.normalize.component_ary
- else
- false
- end
- end
-
- def hash
- self.component_ary.hash
- end
-
- def eql?(oth)
- self.class == oth.class &&
- parser == oth.parser &&
- self.component_ary.eql?(oth.component_ary)
- end
-
-=begin
-
---- Gem::URI::Generic#===(oth)
-
-=end
-# def ===(oth)
-# raise NotImplementedError
-# end
-
-=begin
-=end
-
-
- # Returns an Array of the components defined from the COMPONENT Array.
- def component_ary
- component.collect do |x|
- self.__send__(x)
- end
- end
- protected :component_ary
-
- # == Args
- #
- # +components+::
- # Multiple Symbol arguments defined in Gem::URI::HTTP.
- #
- # == Description
- #
- # Selects specified components from Gem::URI.
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse('http://myuser:mypass@my.example.com/test.rbx')
- # uri.select(:userinfo, :host, :path)
- # # => ["myuser:mypass", "my.example.com", "/test.rbx"]
- #
- def select(*components)
- components.collect do |c|
- if component.include?(c)
- self.__send__(c)
- else
- raise ArgumentError,
- "expected of components of #{self.class} (#{self.class.component.join(', ')})"
- end
- end
- end
-
- def inspect
- "#<#{self.class} #{self}>"
- end
-
- #
- # == Args
- #
- # +v+::
- # Gem::URI or String
- #
- # == Description
- #
- # Attempts to parse other Gem::URI +oth+,
- # returns [parsed_oth, self].
- #
- # == Usage
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("http://my.example.com")
- # uri.coerce("http://foo.com")
- # #=> [#<Gem::URI::HTTP http://foo.com>, #<Gem::URI::HTTP http://my.example.com>]
- #
- def coerce(oth)
- case oth
- when String
- oth = parser.parse(oth)
- else
- super
- end
-
- return oth, self
- end
-
- # Returns a proxy Gem::URI.
- # The proxy Gem::URI is obtained from environment variables such as http_proxy,
- # ftp_proxy, no_proxy, etc.
- # If there is no proper proxy, nil is returned.
- #
- # If the optional parameter +env+ is specified, it is used instead of ENV.
- #
- # Note that capitalized variables (HTTP_PROXY, FTP_PROXY, NO_PROXY, etc.)
- # are examined, too.
- #
- # But http_proxy and HTTP_PROXY is treated specially under CGI environment.
- # It's because HTTP_PROXY may be set by Proxy: header.
- # So HTTP_PROXY is not used.
- # http_proxy is not used too if the variable is case insensitive.
- # CGI_HTTP_PROXY can be used instead.
- def find_proxy(env=ENV)
- raise BadURIError, "relative Gem::URI: #{self}" if self.relative?
- name = self.scheme.downcase + '_proxy'
- proxy_uri = nil
- if name == 'http_proxy' && env.include?('REQUEST_METHOD') # CGI?
- # HTTP_PROXY conflicts with *_proxy for proxy settings and
- # HTTP_* for header information in CGI.
- # So it should be careful to use it.
- pairs = env.reject {|k, v| /\Ahttp_proxy\z/i !~ k }
- case pairs.length
- when 0 # no proxy setting anyway.
- proxy_uri = nil
- when 1
- k, _ = pairs.shift
- if k == 'http_proxy' && env[k.upcase] == nil
- # http_proxy is safe to use because ENV is case sensitive.
- proxy_uri = env[name]
- else
- proxy_uri = nil
- end
- else # http_proxy is safe to use because ENV is case sensitive.
- proxy_uri = env.to_hash[name]
- end
- if !proxy_uri
- # Use CGI_HTTP_PROXY. cf. libwww-perl.
- proxy_uri = env["CGI_#{name.upcase}"]
- end
- elsif name == 'http_proxy'
- if RUBY_ENGINE == 'jruby' && p_addr = ENV_JAVA['http.proxyHost']
- p_port = ENV_JAVA['http.proxyPort']
- if p_user = ENV_JAVA['http.proxyUser']
- p_pass = ENV_JAVA['http.proxyPass']
- proxy_uri = "http://#{p_user}:#{p_pass}@#{p_addr}:#{p_port}"
- else
- proxy_uri = "http://#{p_addr}:#{p_port}"
- end
- else
- unless proxy_uri = env[name]
- if proxy_uri = env[name.upcase]
- warn 'The environment variable HTTP_PROXY is discouraged. Use http_proxy.', uplevel: 1
- end
- end
- end
- else
- proxy_uri = env[name] || env[name.upcase]
- end
-
- if proxy_uri.nil? || proxy_uri.empty?
- return nil
- end
-
- if self.hostname
- begin
- addr = IPSocket.getaddress(self.hostname)
- return nil if /\A127\.|\A::1\z/ =~ addr
- rescue SocketError
- end
- end
-
- name = 'no_proxy'
- if no_proxy = env[name] || env[name.upcase]
- return nil unless Gem::URI::Generic.use_proxy?(self.hostname, addr, self.port, no_proxy)
- end
- Gem::URI.parse(proxy_uri)
- end
-
- def self.use_proxy?(hostname, addr, port, no_proxy) # :nodoc:
- hostname = hostname.downcase
- dothostname = ".#{hostname}"
- no_proxy.scan(/([^:,\s]+)(?::(\d+))?/) {|p_host, p_port|
- if !p_port || port == p_port.to_i
- if p_host.start_with?('.')
- return false if hostname.end_with?(p_host.downcase)
- else
- return false if dothostname.end_with?(".#{p_host.downcase}")
- end
- if addr
- begin
- return false if IPAddr.new(p_host).include?(addr)
- rescue IPAddr::InvalidAddressError
- next
- end
- end
- end
- }
- true
- end
- end
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/http.rb b/lib/rubygems/vendor/uri/lib/uri/http.rb
deleted file mode 100644
index bef43490a3..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/http.rb
+++ /dev/null
@@ -1,125 +0,0 @@
-# frozen_string_literal: false
-# = uri/http.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'generic'
-
-module Gem::URI
-
- #
- # The syntax of HTTP URIs is defined in RFC1738 section 3.3.
- #
- # Note that the Ruby Gem::URI library allows HTTP URLs containing usernames and
- # passwords. This is not legal as per the RFC, but used to be
- # supported in Internet Explorer 5 and 6, before the MS04-004 security
- # update. See <URL:http://support.microsoft.com/kb/834489>.
- #
- class HTTP < Generic
- # A Default port of 80 for Gem::URI::HTTP.
- DEFAULT_PORT = 80
-
- # An Array of the available components for Gem::URI::HTTP.
- COMPONENT = %i[
- scheme
- userinfo host port
- path
- query
- fragment
- ].freeze
-
- #
- # == Description
- #
- # Creates a new Gem::URI::HTTP object from components, with syntax checking.
- #
- # The components accepted are userinfo, host, port, path, query, and
- # fragment.
- #
- # The components should be provided either as an Array, or as a Hash
- # with keys formed by preceding the component names with a colon.
- #
- # If an Array is used, the components must be passed in the
- # order <code>[userinfo, host, port, path, query, fragment]</code>.
- #
- # Example:
- #
- # uri = Gem::URI::HTTP.build(host: 'www.example.com', path: '/foo/bar')
- #
- # uri = Gem::URI::HTTP.build([nil, "www.example.com", nil, "/path",
- # "query", 'fragment'])
- #
- # Currently, if passed userinfo components this method generates
- # invalid HTTP URIs as per RFC 1738.
- #
- def self.build(args)
- tmp = Util.make_components_hash(self, args)
- super(tmp)
- end
-
- #
- # == Description
- #
- # Returns the full path for an HTTP request, as required by Net::HTTP::Get.
- #
- # If the Gem::URI contains a query, the full path is Gem::URI#path + '?' + Gem::URI#query.
- # Otherwise, the path is simply Gem::URI#path.
- #
- # Example:
- #
- # uri = Gem::URI::HTTP.build(path: '/foo/bar', query: 'test=true')
- # uri.request_uri # => "/foo/bar?test=true"
- #
- def request_uri
- return unless @path
-
- url = @query ? "#@path?#@query" : @path.dup
- url.start_with?(?/.freeze) ? url : ?/ + url
- end
-
- #
- # == Description
- #
- # Returns the authority for an HTTP uri, as defined in
- # https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.
- #
- #
- # Example:
- #
- # Gem::URI::HTTP.build(host: 'www.example.com', path: '/foo/bar').authority #=> "www.example.com"
- # Gem::URI::HTTP.build(host: 'www.example.com', port: 8000, path: '/foo/bar').authority #=> "www.example.com:8000"
- # Gem::URI::HTTP.build(host: 'www.example.com', port: 80, path: '/foo/bar').authority #=> "www.example.com"
- #
- def authority
- if port == default_port
- host
- else
- "#{host}:#{port}"
- end
- end
-
- #
- # == Description
- #
- # Returns the origin for an HTTP uri, as defined in
- # https://datatracker.ietf.org/doc/html/rfc6454.
- #
- #
- # Example:
- #
- # Gem::URI::HTTP.build(host: 'www.example.com', path: '/foo/bar').origin #=> "http://www.example.com"
- # Gem::URI::HTTP.build(host: 'www.example.com', port: 8000, path: '/foo/bar').origin #=> "http://www.example.com:8000"
- # Gem::URI::HTTP.build(host: 'www.example.com', port: 80, path: '/foo/bar').origin #=> "http://www.example.com"
- # Gem::URI::HTTPS.build(host: 'www.example.com', path: '/foo/bar').origin #=> "https://www.example.com"
- #
- def origin
- "#{scheme}://#{authority}"
- end
- end
-
- register_scheme 'HTTP', HTTP
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/https.rb b/lib/rubygems/vendor/uri/lib/uri/https.rb
deleted file mode 100644
index 6e8e732e1d..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/https.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: false
-# = uri/https.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'http'
-
-module Gem::URI
-
- # The default port for HTTPS URIs is 443, and the scheme is 'https:' rather
- # than 'http:'. Other than that, HTTPS URIs are identical to HTTP URIs;
- # see Gem::URI::HTTP.
- class HTTPS < HTTP
- # A Default port of 443 for Gem::URI::HTTPS
- DEFAULT_PORT = 443
- end
-
- register_scheme 'HTTPS', HTTPS
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/ldap.rb b/lib/rubygems/vendor/uri/lib/uri/ldap.rb
deleted file mode 100644
index 1a08b5ab7e..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/ldap.rb
+++ /dev/null
@@ -1,261 +0,0 @@
-# frozen_string_literal: false
-# = uri/ldap.rb
-#
-# Author::
-# Takaaki Tateishi <ttate@jaist.ac.jp>
-# Akira Yamada <akira@ruby-lang.org>
-# License::
-# Gem::URI::LDAP is copyrighted free software by Takaaki Tateishi and Akira Yamada.
-# You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'generic'
-
-module Gem::URI
-
- #
- # LDAP Gem::URI SCHEMA (described in RFC2255).
- #--
- # ldap://<host>/<dn>[?<attrs>[?<scope>[?<filter>[?<extensions>]]]]
- #++
- class LDAP < Generic
-
- # A Default port of 389 for Gem::URI::LDAP.
- DEFAULT_PORT = 389
-
- # An Array of the available components for Gem::URI::LDAP.
- COMPONENT = [
- :scheme,
- :host, :port,
- :dn,
- :attributes,
- :scope,
- :filter,
- :extensions,
- ].freeze
-
- # Scopes available for the starting point.
- #
- # * SCOPE_BASE - the Base DN
- # * SCOPE_ONE - one level under the Base DN, not including the base DN and
- # not including any entries under this
- # * SCOPE_SUB - subtrees, all entries at all levels
- #
- SCOPE = [
- SCOPE_ONE = 'one',
- SCOPE_SUB = 'sub',
- SCOPE_BASE = 'base',
- ].freeze
-
- #
- # == Description
- #
- # Creates a new Gem::URI::LDAP object from components, with syntax checking.
- #
- # The components accepted are host, port, dn, attributes,
- # scope, filter, and extensions.
- #
- # The components should be provided either as an Array, or as a Hash
- # with keys formed by preceding the component names with a colon.
- #
- # If an Array is used, the components must be passed in the
- # order <code>[host, port, dn, attributes, scope, filter, extensions]</code>.
- #
- # Example:
- #
- # uri = Gem::URI::LDAP.build({:host => 'ldap.example.com',
- # :dn => '/dc=example'})
- #
- # uri = Gem::URI::LDAP.build(["ldap.example.com", nil,
- # "/dc=example;dc=com", "query", nil, nil, nil])
- #
- def self.build(args)
- tmp = Util::make_components_hash(self, args)
-
- if tmp[:dn]
- tmp[:path] = tmp[:dn]
- end
-
- query = []
- [:extensions, :filter, :scope, :attributes].collect do |x|
- next if !tmp[x] && query.size == 0
- query.unshift(tmp[x])
- end
-
- tmp[:query] = query.join('?')
-
- return super(tmp)
- end
-
- #
- # == Description
- #
- # Creates a new Gem::URI::LDAP object from generic Gem::URI components as per
- # RFC 2396. No LDAP-specific syntax checking is performed.
- #
- # Arguments are +scheme+, +userinfo+, +host+, +port+, +registry+, +path+,
- # +opaque+, +query+, and +fragment+, in that order.
- #
- # Example:
- #
- # uri = Gem::URI::LDAP.new("ldap", nil, "ldap.example.com", nil, nil,
- # "/dc=example;dc=com", nil, "query", nil)
- #
- # See also Gem::URI::Generic.new.
- #
- def initialize(*arg)
- super(*arg)
-
- if @fragment
- raise InvalidURIError, 'bad LDAP URL'
- end
-
- parse_dn
- parse_query
- end
-
- # Private method to cleanup +dn+ from using the +path+ component attribute.
- def parse_dn
- raise InvalidURIError, 'bad LDAP URL' unless @path
- @dn = @path[1..-1]
- end
- private :parse_dn
-
- # Private method to cleanup +attributes+, +scope+, +filter+, and +extensions+
- # from using the +query+ component attribute.
- def parse_query
- @attributes = nil
- @scope = nil
- @filter = nil
- @extensions = nil
-
- if @query
- attrs, scope, filter, extensions = @query.split('?')
-
- @attributes = attrs if attrs && attrs.size > 0
- @scope = scope if scope && scope.size > 0
- @filter = filter if filter && filter.size > 0
- @extensions = extensions if extensions && extensions.size > 0
- end
- end
- private :parse_query
-
- # Private method to assemble +query+ from +attributes+, +scope+, +filter+, and +extensions+.
- def build_path_query
- @path = '/' + @dn
-
- query = []
- [@extensions, @filter, @scope, @attributes].each do |x|
- next if !x && query.size == 0
- query.unshift(x)
- end
- @query = query.join('?')
- end
- private :build_path_query
-
- # Returns dn.
- def dn
- @dn
- end
-
- # Private setter for dn +val+.
- def set_dn(val)
- @dn = val
- build_path_query
- @dn
- end
- protected :set_dn
-
- # Setter for dn +val+.
- def dn=(val)
- set_dn(val)
- val
- end
-
- # Returns attributes.
- def attributes
- @attributes
- end
-
- # Private setter for attributes +val+.
- def set_attributes(val)
- @attributes = val
- build_path_query
- @attributes
- end
- protected :set_attributes
-
- # Setter for attributes +val+.
- def attributes=(val)
- set_attributes(val)
- val
- end
-
- # Returns scope.
- def scope
- @scope
- end
-
- # Private setter for scope +val+.
- def set_scope(val)
- @scope = val
- build_path_query
- @scope
- end
- protected :set_scope
-
- # Setter for scope +val+.
- def scope=(val)
- set_scope(val)
- val
- end
-
- # Returns filter.
- def filter
- @filter
- end
-
- # Private setter for filter +val+.
- def set_filter(val)
- @filter = val
- build_path_query
- @filter
- end
- protected :set_filter
-
- # Setter for filter +val+.
- def filter=(val)
- set_filter(val)
- val
- end
-
- # Returns extensions.
- def extensions
- @extensions
- end
-
- # Private setter for extensions +val+.
- def set_extensions(val)
- @extensions = val
- build_path_query
- @extensions
- end
- protected :set_extensions
-
- # Setter for extensions +val+.
- def extensions=(val)
- set_extensions(val)
- val
- end
-
- # Checks if Gem::URI has a path.
- # For Gem::URI::LDAP this will return +false+.
- def hierarchical?
- false
- end
- end
-
- register_scheme 'LDAP', LDAP
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/ldaps.rb b/lib/rubygems/vendor/uri/lib/uri/ldaps.rb
deleted file mode 100644
index b7a5b50e27..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/ldaps.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: false
-# = uri/ldap.rb
-#
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'ldap'
-
-module Gem::URI
-
- # The default port for LDAPS URIs is 636, and the scheme is 'ldaps:' rather
- # than 'ldap:'. Other than that, LDAPS URIs are identical to LDAP URIs;
- # see Gem::URI::LDAP.
- class LDAPS < LDAP
- # A Default port of 636 for Gem::URI::LDAPS
- DEFAULT_PORT = 636
- end
-
- register_scheme 'LDAPS', LDAPS
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/mailto.rb b/lib/rubygems/vendor/uri/lib/uri/mailto.rb
deleted file mode 100644
index 7ae544d194..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/mailto.rb
+++ /dev/null
@@ -1,293 +0,0 @@
-# frozen_string_literal: false
-# = uri/mailto.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'generic'
-
-module Gem::URI
-
- #
- # RFC6068, the mailto URL scheme.
- #
- class MailTo < Generic
- include RFC2396_REGEXP
-
- # A Default port of nil for Gem::URI::MailTo.
- DEFAULT_PORT = nil
-
- # An Array of the available components for Gem::URI::MailTo.
- COMPONENT = [ :scheme, :to, :headers ].freeze
-
- # :stopdoc:
- # "hname" and "hvalue" are encodings of an RFC 822 header name and
- # value, respectively. As with "to", all URL reserved characters must
- # be encoded.
- #
- # "#mailbox" is as specified in RFC 822 [RFC822]. This means that it
- # consists of zero or more comma-separated mail addresses, possibly
- # including "phrase" and "comment" components. Note that all URL
- # reserved characters in "to" must be encoded: in particular,
- # parentheses, commas, and the percent sign ("%"), which commonly occur
- # in the "mailbox" syntax.
- #
- # Within mailto URLs, the characters "?", "=", "&" are reserved.
-
- # ; RFC 6068
- # hfields = "?" hfield *( "&" hfield )
- # hfield = hfname "=" hfvalue
- # hfname = *qchar
- # hfvalue = *qchar
- # qchar = unreserved / pct-encoded / some-delims
- # some-delims = "!" / "$" / "'" / "(" / ")" / "*"
- # / "+" / "," / ";" / ":" / "@"
- #
- # ; RFC3986
- # unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
- # pct-encoded = "%" HEXDIG HEXDIG
- HEADER_REGEXP = /\A(?<hfield>(?:%\h\h|[!$'-.0-;@-Z_a-z~])*=(?:%\h\h|[!$'-.0-;@-Z_a-z~])*)(?:&\g<hfield>)*\z/
- # practical regexp for email address
- # https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
- EMAIL_REGEXP = /\A[a-zA-Z0-9.!\#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\z/
- # :startdoc:
-
- #
- # == Description
- #
- # Creates a new Gem::URI::MailTo object from components, with syntax checking.
- #
- # Components can be provided as an Array or Hash. If an Array is used,
- # the components must be supplied as <code>[to, headers]</code>.
- #
- # If a Hash is used, the keys are the component names preceded by colons.
- #
- # The headers can be supplied as a pre-encoded string, such as
- # <code>"subject=subscribe&cc=address"</code>, or as an Array of Arrays
- # like <code>[['subject', 'subscribe'], ['cc', 'address']]</code>.
- #
- # Examples:
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # m1 = Gem::URI::MailTo.build(['joe@example.com', 'subject=Ruby'])
- # m1.to_s # => "mailto:joe@example.com?subject=Ruby"
- #
- # m2 = Gem::URI::MailTo.build(['john@example.com', [['Subject', 'Ruby'], ['Cc', 'jack@example.com']]])
- # m2.to_s # => "mailto:john@example.com?Subject=Ruby&Cc=jack@example.com"
- #
- # m3 = Gem::URI::MailTo.build({:to => 'listman@example.com', :headers => [['subject', 'subscribe']]})
- # m3.to_s # => "mailto:listman@example.com?subject=subscribe"
- #
- def self.build(args)
- tmp = Util.make_components_hash(self, args)
-
- case tmp[:to]
- when Array
- tmp[:opaque] = tmp[:to].join(',')
- when String
- tmp[:opaque] = tmp[:to].dup
- else
- tmp[:opaque] = ''
- end
-
- if tmp[:headers]
- query =
- case tmp[:headers]
- when Array
- tmp[:headers].collect { |x|
- if x.kind_of?(Array)
- x[0] + '=' + x[1..-1].join
- else
- x.to_s
- end
- }.join('&')
- when Hash
- tmp[:headers].collect { |h,v|
- h + '=' + v
- }.join('&')
- else
- tmp[:headers].to_s
- end
- unless query.empty?
- tmp[:opaque] << '?' << query
- end
- end
-
- super(tmp)
- end
-
- #
- # == Description
- #
- # Creates a new Gem::URI::MailTo object from generic URL components with
- # no syntax checking.
- #
- # This method is usually called from Gem::URI::parse, which checks
- # the validity of each component.
- #
- def initialize(*arg)
- super(*arg)
-
- @to = nil
- @headers = []
-
- # The RFC3986 parser does not normally populate opaque
- @opaque = "?#{@query}" if @query && !@opaque
-
- unless @opaque
- raise InvalidComponentError,
- "missing opaque part for mailto URL"
- end
- to, header = @opaque.split('?', 2)
- # allow semicolon as a addr-spec separator
- # http://support.microsoft.com/kb/820868
- unless /\A(?:[^@,;]+@[^@,;]+(?:\z|[,;]))*\z/ =~ to
- raise InvalidComponentError,
- "unrecognised opaque part for mailtoURL: #{@opaque}"
- end
-
- if arg[10] # arg_check
- self.to = to
- self.headers = header
- else
- set_to(to)
- set_headers(header)
- end
- end
-
- # The primary e-mail address of the URL, as a String.
- attr_reader :to
-
- # E-mail headers set by the URL, as an Array of Arrays.
- attr_reader :headers
-
- # Checks the to +v+ component.
- def check_to(v)
- return true unless v
- return true if v.size == 0
-
- v.split(/[,;]/).each do |addr|
- # check url safety as path-rootless
- if /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*\z/ !~ addr
- raise InvalidComponentError,
- "an address in 'to' is invalid as Gem::URI #{addr.dump}"
- end
-
- # check addr-spec
- # don't s/\+/ /g
- addr.gsub!(/%\h\h/, Gem::URI::TBLDECWWWCOMP_)
- if EMAIL_REGEXP !~ addr
- raise InvalidComponentError,
- "an address in 'to' is invalid as uri-escaped addr-spec #{addr.dump}"
- end
- end
-
- true
- end
- private :check_to
-
- # Private setter for to +v+.
- def set_to(v)
- @to = v
- end
- protected :set_to
-
- # Setter for to +v+.
- def to=(v)
- check_to(v)
- set_to(v)
- v
- end
-
- # Checks the headers +v+ component against either
- # * HEADER_REGEXP
- def check_headers(v)
- return true unless v
- return true if v.size == 0
- if HEADER_REGEXP !~ v
- raise InvalidComponentError,
- "bad component(expected opaque component): #{v}"
- end
-
- true
- end
- private :check_headers
-
- # Private setter for headers +v+.
- def set_headers(v)
- @headers = []
- if v
- v.split('&').each do |x|
- @headers << x.split(/=/, 2)
- end
- end
- end
- protected :set_headers
-
- # Setter for headers +v+.
- def headers=(v)
- check_headers(v)
- set_headers(v)
- v
- end
-
- # Constructs String from Gem::URI.
- def to_s
- @scheme + ':' +
- if @to
- @to
- else
- ''
- end +
- if @headers.size > 0
- '?' + @headers.collect{|x| x.join('=')}.join('&')
- else
- ''
- end +
- if @fragment
- '#' + @fragment
- else
- ''
- end
- end
-
- # Returns the RFC822 e-mail text equivalent of the URL, as a String.
- #
- # Example:
- #
- # require 'rubygems/vendor/uri/lib/uri'
- #
- # uri = Gem::URI.parse("mailto:ruby-list@ruby-lang.org?Subject=subscribe&cc=myaddr")
- # uri.to_mailtext
- # # => "To: ruby-list@ruby-lang.org\nSubject: subscribe\nCc: myaddr\n\n\n"
- #
- def to_mailtext
- to = Gem::URI.decode_www_form_component(@to)
- head = ''
- body = ''
- @headers.each do |x|
- case x[0]
- when 'body'
- body = Gem::URI.decode_www_form_component(x[1])
- when 'to'
- to << ', ' + Gem::URI.decode_www_form_component(x[1])
- else
- head << Gem::URI.decode_www_form_component(x[0]).capitalize + ': ' +
- Gem::URI.decode_www_form_component(x[1]) + "\n"
- end
- end
-
- "To: #{to}
-#{head}
-#{body}
-"
- end
- alias to_rfc822text to_mailtext
- end
-
- register_scheme 'MAILTO', MailTo
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb b/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb
deleted file mode 100644
index 735a269f2c..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/rfc2396_parser.rb
+++ /dev/null
@@ -1,539 +0,0 @@
-# frozen_string_literal: false
-#--
-# = uri/common.rb
-#
-# Author:: Akira Yamada <akira@ruby-lang.org>
-# License::
-# You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-module Gem::URI
- #
- # Includes Gem::URI::REGEXP::PATTERN
- #
- module RFC2396_REGEXP
- #
- # Patterns used to parse Gem::URI's
- #
- module PATTERN
- # :stopdoc:
-
- # RFC 2396 (Gem::URI Generic Syntax)
- # RFC 2732 (IPv6 Literal Addresses in URL's)
- # RFC 2373 (IPv6 Addressing Architecture)
-
- # alpha = lowalpha | upalpha
- ALPHA = "a-zA-Z"
- # alphanum = alpha | digit
- ALNUM = "#{ALPHA}\\d"
-
- # hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
- # "a" | "b" | "c" | "d" | "e" | "f"
- HEX = "a-fA-F\\d"
- # escaped = "%" hex hex
- ESCAPED = "%[#{HEX}]{2}"
- # mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
- # "(" | ")"
- # unreserved = alphanum | mark
- UNRESERVED = "\\-_.!~*'()#{ALNUM}"
- # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
- # "$" | ","
- # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
- # "$" | "," | "[" | "]" (RFC 2732)
- RESERVED = ";/?:@&=+$,\\[\\]"
-
- # domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
- DOMLABEL = "(?:[#{ALNUM}](?:[-#{ALNUM}]*[#{ALNUM}])?)"
- # toplabel = alpha | alpha *( alphanum | "-" ) alphanum
- TOPLABEL = "(?:[#{ALPHA}](?:[-#{ALNUM}]*[#{ALNUM}])?)"
- # hostname = *( domainlabel "." ) toplabel [ "." ]
- HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?"
-
- # :startdoc:
- end # PATTERN
-
- # :startdoc:
- end # REGEXP
-
- # Class that parses String's into Gem::URI's.
- #
- # It contains a Hash set of patterns and Regexp's that match and validate.
- #
- class RFC2396_Parser
- include RFC2396_REGEXP
-
- #
- # == Synopsis
- #
- # Gem::URI::Parser.new([opts])
- #
- # == Args
- #
- # The constructor accepts a hash as options for parser.
- # Keys of options are pattern names of Gem::URI components
- # and values of options are pattern strings.
- # The constructor generates set of regexps for parsing URIs.
- #
- # You can use the following keys:
- #
- # * :ESCAPED (Gem::URI::PATTERN::ESCAPED in default)
- # * :UNRESERVED (Gem::URI::PATTERN::UNRESERVED in default)
- # * :DOMLABEL (Gem::URI::PATTERN::DOMLABEL in default)
- # * :TOPLABEL (Gem::URI::PATTERN::TOPLABEL in default)
- # * :HOSTNAME (Gem::URI::PATTERN::HOSTNAME in default)
- #
- # == Examples
- #
- # p = Gem::URI::Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})")
- # u = p.parse("http://example.jp/%uABCD") #=> #<Gem::URI::HTTP http://example.jp/%uABCD>
- # Gem::URI.parse(u.to_s) #=> raises Gem::URI::InvalidURIError
- #
- # s = "http://example.com/ABCD"
- # u1 = p.parse(s) #=> #<Gem::URI::HTTP http://example.com/ABCD>
- # u2 = Gem::URI.parse(s) #=> #<Gem::URI::HTTP http://example.com/ABCD>
- # u1 == u2 #=> true
- # u1.eql?(u2) #=> false
- #
- def initialize(opts = {})
- @pattern = initialize_pattern(opts)
- @pattern.each_value(&:freeze)
- @pattern.freeze
-
- @regexp = initialize_regexp(@pattern)
- @regexp.each_value(&:freeze)
- @regexp.freeze
- end
-
- # The Hash of patterns.
- #
- # See also Gem::URI::Parser.initialize_pattern.
- attr_reader :pattern
-
- # The Hash of Regexp.
- #
- # See also Gem::URI::Parser.initialize_regexp.
- attr_reader :regexp
-
- # Returns a split Gem::URI against +regexp[:ABS_URI]+.
- def split(uri)
- case uri
- when ''
- # null uri
-
- when @regexp[:ABS_URI]
- scheme, opaque, userinfo, host, port,
- registry, path, query, fragment = $~[1..-1]
-
- # Gem::URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
-
- # absoluteURI = scheme ":" ( hier_part | opaque_part )
- # hier_part = ( net_path | abs_path ) [ "?" query ]
- # opaque_part = uric_no_slash *uric
-
- # abs_path = "/" path_segments
- # net_path = "//" authority [ abs_path ]
-
- # authority = server | reg_name
- # server = [ [ userinfo "@" ] hostport ]
-
- if !scheme
- raise InvalidURIError,
- "bad Gem::URI(absolute but no scheme): #{uri}"
- end
- if !opaque && (!path && (!host && !registry))
- raise InvalidURIError,
- "bad Gem::URI(absolute but no path): #{uri}"
- end
-
- when @regexp[:REL_URI]
- scheme = nil
- opaque = nil
-
- userinfo, host, port, registry,
- rel_segment, abs_path, query, fragment = $~[1..-1]
- if rel_segment && abs_path
- path = rel_segment + abs_path
- elsif rel_segment
- path = rel_segment
- elsif abs_path
- path = abs_path
- end
-
- # Gem::URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
-
- # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
-
- # net_path = "//" authority [ abs_path ]
- # abs_path = "/" path_segments
- # rel_path = rel_segment [ abs_path ]
-
- # authority = server | reg_name
- # server = [ [ userinfo "@" ] hostport ]
-
- else
- raise InvalidURIError, "bad Gem::URI(is not Gem::URI?): #{uri}"
- end
-
- path = '' if !path && !opaque # (see RFC2396 Section 5.2)
- ret = [
- scheme,
- userinfo, host, port, # X
- registry, # X
- path, # Y
- opaque, # Y
- query,
- fragment
- ]
- return ret
- end
-
- #
- # == Args
- #
- # +uri+::
- # String
- #
- # == Description
- #
- # Parses +uri+ and constructs either matching Gem::URI scheme object
- # (File, FTP, HTTP, HTTPS, LDAP, LDAPS, or MailTo) or Gem::URI::Generic.
- #
- # == Usage
- #
- # p = Gem::URI::Parser.new
- # p.parse("ldap://ldap.example.com/dc=example?user=john")
- # #=> #<Gem::URI::LDAP ldap://ldap.example.com/dc=example?user=john>
- #
- def parse(uri)
- Gem::URI.for(*self.split(uri), self)
- end
-
- #
- # == Args
- #
- # +uris+::
- # an Array of Strings
- #
- # == Description
- #
- # Attempts to parse and merge a set of URIs.
- #
- def join(*uris)
- uris[0] = convert_to_uri(uris[0])
- uris.inject :merge
- end
-
- #
- # :call-seq:
- # extract( str )
- # extract( str, schemes )
- # extract( str, schemes ) {|item| block }
- #
- # == Args
- #
- # +str+::
- # String to search
- # +schemes+::
- # Patterns to apply to +str+
- #
- # == Description
- #
- # Attempts to parse and merge a set of URIs.
- # If no +block+ given, then returns the result,
- # else it calls +block+ for each element in result.
- #
- # See also Gem::URI::Parser.make_regexp.
- #
- def extract(str, schemes = nil)
- if block_given?
- str.scan(make_regexp(schemes)) { yield $& }
- nil
- else
- result = []
- str.scan(make_regexp(schemes)) { result.push $& }
- result
- end
- end
-
- # Returns Regexp that is default +self.regexp[:ABS_URI_REF]+,
- # unless +schemes+ is provided. Then it is a Regexp.union with +self.pattern[:X_ABS_URI]+.
- def make_regexp(schemes = nil)
- unless schemes
- @regexp[:ABS_URI_REF]
- else
- /(?=#{Regexp.union(*schemes)}:)#{@pattern[:X_ABS_URI]}/x
- end
- end
-
- #
- # :call-seq:
- # escape( str )
- # escape( str, unsafe )
- #
- # == Args
- #
- # +str+::
- # String to make safe
- # +unsafe+::
- # Regexp to apply. Defaults to +self.regexp[:UNSAFE]+
- #
- # == Description
- #
- # Constructs a safe String from +str+, removing unsafe characters,
- # replacing them with codes.
- #
- def escape(str, unsafe = @regexp[:UNSAFE])
- unless unsafe.kind_of?(Regexp)
- # perhaps unsafe is String object
- unsafe = Regexp.new("[#{Regexp.quote(unsafe)}]", false)
- end
- str.gsub(unsafe) do
- us = $&
- tmp = ''
- us.each_byte do |uc|
- tmp << sprintf('%%%02X', uc)
- end
- tmp
- end.force_encoding(Encoding::US_ASCII)
- end
-
- #
- # :call-seq:
- # unescape( str )
- # unescape( str, escaped )
- #
- # == Args
- #
- # +str+::
- # String to remove escapes from
- # +escaped+::
- # Regexp to apply. Defaults to +self.regexp[:ESCAPED]+
- #
- # == Description
- #
- # Removes escapes from +str+.
- #
- def unescape(str, escaped = @regexp[:ESCAPED])
- enc = str.encoding
- enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
- str.gsub(escaped) { [$&[1, 2]].pack('H2').force_encoding(enc) }
- end
-
- @@to_s = Kernel.instance_method(:to_s)
- if @@to_s.respond_to?(:bind_call)
- def inspect
- @@to_s.bind_call(self)
- end
- else
- def inspect
- @@to_s.bind(self).call
- end
- end
-
- private
-
- # Constructs the default Hash of patterns.
- def initialize_pattern(opts = {})
- ret = {}
- ret[:ESCAPED] = escaped = (opts.delete(:ESCAPED) || PATTERN::ESCAPED)
- ret[:UNRESERVED] = unreserved = opts.delete(:UNRESERVED) || PATTERN::UNRESERVED
- ret[:RESERVED] = reserved = opts.delete(:RESERVED) || PATTERN::RESERVED
- ret[:DOMLABEL] = opts.delete(:DOMLABEL) || PATTERN::DOMLABEL
- ret[:TOPLABEL] = opts.delete(:TOPLABEL) || PATTERN::TOPLABEL
- ret[:HOSTNAME] = hostname = opts.delete(:HOSTNAME)
-
- # RFC 2396 (Gem::URI Generic Syntax)
- # RFC 2732 (IPv6 Literal Addresses in URL's)
- # RFC 2373 (IPv6 Addressing Architecture)
-
- # uric = reserved | unreserved | escaped
- ret[:URIC] = uric = "(?:[#{unreserved}#{reserved}]|#{escaped})"
- # uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
- # "&" | "=" | "+" | "$" | ","
- ret[:URIC_NO_SLASH] = uric_no_slash = "(?:[#{unreserved};?:@&=+$,]|#{escaped})"
- # query = *uric
- ret[:QUERY] = query = "#{uric}*"
- # fragment = *uric
- ret[:FRAGMENT] = fragment = "#{uric}*"
-
- # hostname = *( domainlabel "." ) toplabel [ "." ]
- # reg-name = *( unreserved / pct-encoded / sub-delims ) # RFC3986
- unless hostname
- ret[:HOSTNAME] = hostname = "(?:[a-zA-Z0-9\\-.]|%\\h\\h)+"
- end
-
- # RFC 2373, APPENDIX B:
- # IPv6address = hexpart [ ":" IPv4address ]
- # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
- # hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
- # hexseq = hex4 *( ":" hex4)
- # hex4 = 1*4HEXDIG
- #
- # XXX: This definition has a flaw. "::" + IPv4address must be
- # allowed too. Here is a replacement.
- #
- # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
- ret[:IPV4ADDR] = ipv4addr = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"
- # hex4 = 1*4HEXDIG
- hex4 = "[#{PATTERN::HEX}]{1,4}"
- # lastpart = hex4 | IPv4address
- lastpart = "(?:#{hex4}|#{ipv4addr})"
- # hexseq1 = *( hex4 ":" ) hex4
- hexseq1 = "(?:#{hex4}:)*#{hex4}"
- # hexseq2 = *( hex4 ":" ) lastpart
- hexseq2 = "(?:#{hex4}:)*#{lastpart}"
- # IPv6address = hexseq2 | [ hexseq1 ] "::" [ hexseq2 ]
- ret[:IPV6ADDR] = ipv6addr = "(?:#{hexseq2}|(?:#{hexseq1})?::(?:#{hexseq2})?)"
-
- # IPv6prefix = ( hexseq1 | [ hexseq1 ] "::" [ hexseq1 ] ) "/" 1*2DIGIT
- # unused
-
- # ipv6reference = "[" IPv6address "]" (RFC 2732)
- ret[:IPV6REF] = ipv6ref = "\\[#{ipv6addr}\\]"
-
- # host = hostname | IPv4address
- # host = hostname | IPv4address | IPv6reference (RFC 2732)
- ret[:HOST] = host = "(?:#{hostname}|#{ipv4addr}|#{ipv6ref})"
- # port = *digit
- ret[:PORT] = port = '\d*'
- # hostport = host [ ":" port ]
- ret[:HOSTPORT] = hostport = "#{host}(?::#{port})?"
-
- # userinfo = *( unreserved | escaped |
- # ";" | ":" | "&" | "=" | "+" | "$" | "," )
- ret[:USERINFO] = userinfo = "(?:[#{unreserved};:&=+$,]|#{escaped})*"
-
- # pchar = unreserved | escaped |
- # ":" | "@" | "&" | "=" | "+" | "$" | ","
- pchar = "(?:[#{unreserved}:@&=+$,]|#{escaped})"
- # param = *pchar
- param = "#{pchar}*"
- # segment = *pchar *( ";" param )
- segment = "#{pchar}*(?:;#{param})*"
- # path_segments = segment *( "/" segment )
- ret[:PATH_SEGMENTS] = path_segments = "#{segment}(?:/#{segment})*"
-
- # server = [ [ userinfo "@" ] hostport ]
- server = "(?:#{userinfo}@)?#{hostport}"
- # reg_name = 1*( unreserved | escaped | "$" | "," |
- # ";" | ":" | "@" | "&" | "=" | "+" )
- ret[:REG_NAME] = reg_name = "(?:[#{unreserved}$,;:@&=+]|#{escaped})+"
- # authority = server | reg_name
- authority = "(?:#{server}|#{reg_name})"
-
- # rel_segment = 1*( unreserved | escaped |
- # ";" | "@" | "&" | "=" | "+" | "$" | "," )
- ret[:REL_SEGMENT] = rel_segment = "(?:[#{unreserved};@&=+$,]|#{escaped})+"
-
- # scheme = alpha *( alpha | digit | "+" | "-" | "." )
- ret[:SCHEME] = scheme = "[#{PATTERN::ALPHA}][\\-+.#{PATTERN::ALPHA}\\d]*"
-
- # abs_path = "/" path_segments
- ret[:ABS_PATH] = abs_path = "/#{path_segments}"
- # rel_path = rel_segment [ abs_path ]
- ret[:REL_PATH] = rel_path = "#{rel_segment}(?:#{abs_path})?"
- # net_path = "//" authority [ abs_path ]
- ret[:NET_PATH] = net_path = "//#{authority}(?:#{abs_path})?"
-
- # hier_part = ( net_path | abs_path ) [ "?" query ]
- ret[:HIER_PART] = hier_part = "(?:#{net_path}|#{abs_path})(?:\\?(?:#{query}))?"
- # opaque_part = uric_no_slash *uric
- ret[:OPAQUE_PART] = opaque_part = "#{uric_no_slash}#{uric}*"
-
- # absoluteURI = scheme ":" ( hier_part | opaque_part )
- ret[:ABS_URI] = abs_uri = "#{scheme}:(?:#{hier_part}|#{opaque_part})"
- # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
- ret[:REL_URI] = rel_uri = "(?:#{net_path}|#{abs_path}|#{rel_path})(?:\\?#{query})?"
-
- # Gem::URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
- ret[:URI_REF] = "(?:#{abs_uri}|#{rel_uri})?(?:##{fragment})?"
-
- ret[:X_ABS_URI] = "
- (#{scheme}): (?# 1: scheme)
- (?:
- (#{opaque_part}) (?# 2: opaque)
- |
- (?:(?:
- //(?:
- (?:(?:(#{userinfo})@)? (?# 3: userinfo)
- (?:(#{host})(?::(\\d*))?))? (?# 4: host, 5: port)
- |
- (#{reg_name}) (?# 6: registry)
- )
- |
- (?!//)) (?# XXX: '//' is the mark for hostport)
- (#{abs_path})? (?# 7: path)
- )(?:\\?(#{query}))? (?# 8: query)
- )
- (?:\\#(#{fragment}))? (?# 9: fragment)
- "
-
- ret[:X_REL_URI] = "
- (?:
- (?:
- //
- (?:
- (?:(#{userinfo})@)? (?# 1: userinfo)
- (#{host})?(?::(\\d*))? (?# 2: host, 3: port)
- |
- (#{reg_name}) (?# 4: registry)
- )
- )
- |
- (#{rel_segment}) (?# 5: rel_segment)
- )?
- (#{abs_path})? (?# 6: abs_path)
- (?:\\?(#{query}))? (?# 7: query)
- (?:\\#(#{fragment}))? (?# 8: fragment)
- "
-
- ret
- end
-
- # Constructs the default Hash of Regexp's.
- def initialize_regexp(pattern)
- ret = {}
-
- # for Gem::URI::split
- ret[:ABS_URI] = Regexp.new('\A\s*+' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED)
- ret[:REL_URI] = Regexp.new('\A\s*+' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED)
-
- # for Gem::URI::extract
- ret[:URI_REF] = Regexp.new(pattern[:URI_REF])
- ret[:ABS_URI_REF] = Regexp.new(pattern[:X_ABS_URI], Regexp::EXTENDED)
- ret[:REL_URI_REF] = Regexp.new(pattern[:X_REL_URI], Regexp::EXTENDED)
-
- # for Gem::URI::escape/unescape
- ret[:ESCAPED] = Regexp.new(pattern[:ESCAPED])
- ret[:UNSAFE] = Regexp.new("[^#{pattern[:UNRESERVED]}#{pattern[:RESERVED]}]")
-
- # for Generic#initialize
- ret[:SCHEME] = Regexp.new("\\A#{pattern[:SCHEME]}\\z")
- ret[:USERINFO] = Regexp.new("\\A#{pattern[:USERINFO]}\\z")
- ret[:HOST] = Regexp.new("\\A#{pattern[:HOST]}\\z")
- ret[:PORT] = Regexp.new("\\A#{pattern[:PORT]}\\z")
- ret[:OPAQUE] = Regexp.new("\\A#{pattern[:OPAQUE_PART]}\\z")
- ret[:REGISTRY] = Regexp.new("\\A#{pattern[:REG_NAME]}\\z")
- ret[:ABS_PATH] = Regexp.new("\\A#{pattern[:ABS_PATH]}\\z")
- ret[:REL_PATH] = Regexp.new("\\A#{pattern[:REL_PATH]}\\z")
- ret[:QUERY] = Regexp.new("\\A#{pattern[:QUERY]}\\z")
- ret[:FRAGMENT] = Regexp.new("\\A#{pattern[:FRAGMENT]}\\z")
-
- ret
- end
-
- def convert_to_uri(uri)
- if uri.is_a?(Gem::URI::Generic)
- uri
- elsif uri = String.try_convert(uri)
- parse(uri)
- else
- raise ArgumentError,
- "bad argument (expected Gem::URI object or Gem::URI string)"
- end
- end
-
- end # class Parser
-end # module Gem::URI
diff --git a/lib/rubygems/vendor/uri/lib/uri/rfc3986_parser.rb b/lib/rubygems/vendor/uri/lib/uri/rfc3986_parser.rb
deleted file mode 100644
index 728bb55674..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/rfc3986_parser.rb
+++ /dev/null
@@ -1,183 +0,0 @@
-# frozen_string_literal: true
-module Gem::URI
- class RFC3986_Parser # :nodoc:
- # Gem::URI defined in RFC3986
- HOST = %r[
- (?<IP-literal>\[(?:
- (?<IPv6address>
- (?:\h{1,4}:){6}
- (?<ls32>\h{1,4}:\h{1,4}
- | (?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)
- \.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>)
- )
- | ::(?:\h{1,4}:){5}\g<ls32>
- | \h{1,4}?::(?:\h{1,4}:){4}\g<ls32>
- | (?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>
- | (?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>
- | (?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>
- | (?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>
- | (?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}
- | (?:(?:\h{1,4}:){,6}\h{1,4})?::
- )
- | (?<IPvFuture>v\h++\.[!$&-.0-9:;=A-Z_a-z~]++)
- )\])
- | \g<IPv4address>
- | (?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*+)
- ]x
-
- USERINFO = /(?:%\h\h|[!$&-.0-9:;=A-Z_a-z~])*+/
-
- SCHEME = %r[[A-Za-z][+\-.0-9A-Za-z]*+].source
- SEG = %r[(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/])].source
- SEG_NC = %r[(?:%\h\h|[!$&-.0-9;=@A-Z_a-z~])].source
- FRAGMENT = %r[(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/?])*+].source
-
- RFC3986_URI = %r[\A
- (?<seg>#{SEG}){0}
- (?<Gem::URI>
- (?<scheme>#{SCHEME}):
- (?<hier-part>//
- (?<authority>
- (?:(?<userinfo>#{USERINFO.source})@)?
- (?<host>#{HOST.source.delete(" \n")})
- (?::(?<port>\d*+))?
- )
- (?<path-abempty>(?:/\g<seg>*+)?)
- | (?<path-absolute>/((?!/)\g<seg>++)?)
- | (?<path-rootless>(?!/)\g<seg>++)
- | (?<path-empty>)
- )
- (?:\?(?<query>[^\#]*+))?
- (?:\#(?<fragment>#{FRAGMENT}))?
- )\z]x
-
- RFC3986_relative_ref = %r[\A
- (?<seg>#{SEG}){0}
- (?<relative-ref>
- (?<relative-part>//
- (?<authority>
- (?:(?<userinfo>#{USERINFO.source})@)?
- (?<host>#{HOST.source.delete(" \n")}(?<!/))?
- (?::(?<port>\d*+))?
- )
- (?<path-abempty>(?:/\g<seg>*+)?)
- | (?<path-absolute>/\g<seg>*+)
- | (?<path-noscheme>#{SEG_NC}++(?:/\g<seg>*+)?)
- | (?<path-empty>)
- )
- (?:\?(?<query>[^#]*+))?
- (?:\#(?<fragment>#{FRAGMENT}))?
- )\z]x
- attr_reader :regexp
-
- def initialize
- @regexp = default_regexp.each_value(&:freeze).freeze
- end
-
- def split(uri) #:nodoc:
- begin
- uri = uri.to_str
- rescue NoMethodError
- raise InvalidURIError, "bad Gem::URI(is not Gem::URI?): #{uri.inspect}"
- end
- uri.ascii_only? or
- raise InvalidURIError, "Gem::URI must be ascii only #{uri.dump}"
- if m = RFC3986_URI.match(uri)
- query = m["query"]
- scheme = m["scheme"]
- opaque = m["path-rootless"]
- if opaque
- opaque << "?#{query}" if query
- [ scheme,
- nil, # userinfo
- nil, # host
- nil, # port
- nil, # registry
- nil, # path
- opaque,
- nil, # query
- m["fragment"]
- ]
- else # normal
- [ scheme,
- m["userinfo"],
- m["host"],
- m["port"],
- nil, # registry
- (m["path-abempty"] ||
- m["path-absolute"] ||
- m["path-empty"]),
- nil, # opaque
- query,
- m["fragment"]
- ]
- end
- elsif m = RFC3986_relative_ref.match(uri)
- [ nil, # scheme
- m["userinfo"],
- m["host"],
- m["port"],
- nil, # registry,
- (m["path-abempty"] ||
- m["path-absolute"] ||
- m["path-noscheme"] ||
- m["path-empty"]),
- nil, # opaque
- m["query"],
- m["fragment"]
- ]
- else
- raise InvalidURIError, "bad Gem::URI(is not Gem::URI?): #{uri.inspect}"
- end
- end
-
- def parse(uri) # :nodoc:
- Gem::URI.for(*self.split(uri), self)
- end
-
-
- def join(*uris) # :nodoc:
- uris[0] = convert_to_uri(uris[0])
- uris.inject :merge
- end
-
- @@to_s = Kernel.instance_method(:to_s)
- if @@to_s.respond_to?(:bind_call)
- def inspect
- @@to_s.bind_call(self)
- end
- else
- def inspect
- @@to_s.bind(self).call
- end
- end
-
- private
-
- def default_regexp # :nodoc:
- {
- SCHEME: %r[\A#{SCHEME}\z]o,
- USERINFO: %r[\A#{USERINFO}\z]o,
- HOST: %r[\A#{HOST}\z]o,
- ABS_PATH: %r[\A/#{SEG}*+\z]o,
- REL_PATH: %r[\A(?!/)#{SEG}++\z]o,
- QUERY: %r[\A(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/?])*+\z],
- FRAGMENT: %r[\A#{FRAGMENT}\z]o,
- OPAQUE: %r[\A(?:[^/].*)?\z],
- PORT: /\A[\x09\x0a\x0c\x0d ]*+\d*[\x09\x0a\x0c\x0d ]*\z/,
- }
- end
-
- def convert_to_uri(uri)
- if uri.is_a?(Gem::URI::Generic)
- uri
- elsif uri = String.try_convert(uri)
- parse(uri)
- else
- raise ArgumentError,
- "bad argument (expected Gem::URI object or Gem::URI string)"
- end
- end
-
- end # class Parser
-end # module Gem::URI
diff --git a/lib/rubygems/vendor/uri/lib/uri/version.rb b/lib/rubygems/vendor/uri/lib/uri/version.rb
deleted file mode 100644
index 3c80c334d4..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/version.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-module Gem::URI
- # :stopdoc:
- VERSION_CODE = '001300'.freeze
- VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
- # :startdoc:
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/ws.rb b/lib/rubygems/vendor/uri/lib/uri/ws.rb
deleted file mode 100644
index 0dd2a7a1bb..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/ws.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-# frozen_string_literal: false
-# = uri/ws.rb
-#
-# Author:: Matt Muller <mamuller@amazon.com>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'generic'
-
-module Gem::URI
-
- #
- # The syntax of WS URIs is defined in RFC6455 section 3.
- #
- # Note that the Ruby Gem::URI library allows WS URLs containing usernames and
- # passwords. This is not legal as per the RFC, but used to be
- # supported in Internet Explorer 5 and 6, before the MS04-004 security
- # update. See <URL:http://support.microsoft.com/kb/834489>.
- #
- class WS < Generic
- # A Default port of 80 for Gem::URI::WS.
- DEFAULT_PORT = 80
-
- # An Array of the available components for Gem::URI::WS.
- COMPONENT = %i[
- scheme
- userinfo host port
- path
- query
- ].freeze
-
- #
- # == Description
- #
- # Creates a new Gem::URI::WS object from components, with syntax checking.
- #
- # The components accepted are userinfo, host, port, path, and query.
- #
- # The components should be provided either as an Array, or as a Hash
- # with keys formed by preceding the component names with a colon.
- #
- # If an Array is used, the components must be passed in the
- # order <code>[userinfo, host, port, path, query]</code>.
- #
- # Example:
- #
- # uri = Gem::URI::WS.build(host: 'www.example.com', path: '/foo/bar')
- #
- # uri = Gem::URI::WS.build([nil, "www.example.com", nil, "/path", "query"])
- #
- # Currently, if passed userinfo components this method generates
- # invalid WS URIs as per RFC 1738.
- #
- def self.build(args)
- tmp = Util.make_components_hash(self, args)
- super(tmp)
- end
-
- #
- # == Description
- #
- # Returns the full path for a WS Gem::URI, as required by Net::HTTP::Get.
- #
- # If the Gem::URI contains a query, the full path is Gem::URI#path + '?' + Gem::URI#query.
- # Otherwise, the path is simply Gem::URI#path.
- #
- # Example:
- #
- # uri = Gem::URI::WS.build(path: '/foo/bar', query: 'test=true')
- # uri.request_uri # => "/foo/bar?test=true"
- #
- def request_uri
- return unless @path
-
- url = @query ? "#@path?#@query" : @path.dup
- url.start_with?(?/.freeze) ? url : ?/ + url
- end
- end
-
- register_scheme 'WS', WS
-end
diff --git a/lib/rubygems/vendor/uri/lib/uri/wss.rb b/lib/rubygems/vendor/uri/lib/uri/wss.rb
deleted file mode 100644
index 0b91d334bb..0000000000
--- a/lib/rubygems/vendor/uri/lib/uri/wss.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: false
-# = uri/wss.rb
-#
-# Author:: Matt Muller <mamuller@amazon.com>
-# License:: You can redistribute it and/or modify it under the same term as Ruby.
-#
-# See Gem::URI for general documentation
-#
-
-require_relative 'ws'
-
-module Gem::URI
-
- # The default port for WSS URIs is 443, and the scheme is 'wss:' rather
- # than 'ws:'. Other than that, WSS URIs are identical to WS URIs;
- # see Gem::URI::WS.
- class WSS < WS
- # A Default port of 443 for Gem::URI::WSS
- DEFAULT_PORT = 443
- end
-
- register_scheme 'WSS', WSS
-end
diff --git a/lib/rubygems/vendored_molinillo.rb b/lib/rubygems/vendored_molinillo.rb
deleted file mode 100644
index 45906c0e5c..0000000000
--- a/lib/rubygems/vendored_molinillo.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "vendor/molinillo/lib/molinillo"
diff --git a/lib/rubygems/vendored_net_http.rb b/lib/rubygems/vendored_net_http.rb
deleted file mode 100644
index a84c52a947..0000000000
--- a/lib/rubygems/vendored_net_http.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-# frozen_string_literal: true
-
-# Ruby 3.3 and RubyGems 3.5 is already load Gem::Timeout from lib/rubygems/net/http.rb
-# We should avoid to load it again
-require_relative "vendor/net-http/lib/net/http" unless defined?(Gem::Net::HTTP)
diff --git a/lib/rubygems/vendored_optparse.rb b/lib/rubygems/vendored_optparse.rb
deleted file mode 100644
index a5611d32f0..0000000000
--- a/lib/rubygems/vendored_optparse.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "vendor/optparse/lib/optparse"
diff --git a/lib/rubygems/vendored_securerandom.rb b/lib/rubygems/vendored_securerandom.rb
deleted file mode 100644
index 0ce26905c4..0000000000
--- a/lib/rubygems/vendored_securerandom.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-# frozen_string_literal: true
-
-module Gem::Random; end
-require_relative "vendor/securerandom/lib/securerandom"
diff --git a/lib/rubygems/vendored_timeout.rb b/lib/rubygems/vendored_timeout.rb
deleted file mode 100644
index 45541928e6..0000000000
--- a/lib/rubygems/vendored_timeout.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-# frozen_string_literal: true
-
-# Ruby 3.3 and RubyGems 3.5 is already load Gem::Timeout from lib/rubygems/timeout.rb
-# We should avoid to load it again
-require_relative "vendor/timeout/lib/timeout" unless defined?(Gem::Timeout)
diff --git a/lib/rubygems/vendored_tsort.rb b/lib/rubygems/vendored_tsort.rb
deleted file mode 100644
index c3d815650d..0000000000
--- a/lib/rubygems/vendored_tsort.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "vendor/tsort/lib/tsort"
diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb
index d9cd91bffa..c319e1f820 100644
--- a/lib/rubygems/version.rb
+++ b/lib/rubygems/version.rb
@@ -131,7 +131,7 @@ require_relative "deprecate"
#
# == Preventing Version Catastrophe:
#
-# From: https://www.zenspider.com/ruby/2008/10/rubygems-how-to-preventing-catastrophe.html
+# From: http://blog.zenspider.com/2008/10/rubygems-howto-preventing-cata.html
#
# Let's say you're depending on the fnord gem version 2.y.z. If you
# specify your dependency as ">= 2.0.0" then, you're good, right? What
@@ -156,16 +156,16 @@ class Gem::Version
include Comparable
VERSION_PATTERN = '[0-9]+(?>\.[0-9a-zA-Z]+)*(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?' # :nodoc:
- ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/ # :nodoc:
+ ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/.freeze # :nodoc:
##
# A string representation of this Version.
def version
- @version
+ @version.dup
end
- alias_method :to_s, :version
+ alias to_s version
##
# True if the +version+ string matches RubyGems' requirements.
@@ -173,7 +173,7 @@ class Gem::Version
def self.correct?(version)
nil_versions_are_discouraged! if version.nil?
- ANCHORED_VERSION_PATTERN.match?(version.to_s)
+ !!(version.to_s =~ ANCHORED_VERSION_PATTERN)
end
##
@@ -201,7 +201,7 @@ class Gem::Version
@@release = {}
def self.new(version) # :nodoc:
- return super unless self == Gem::Version
+ return super unless Gem::Version == self
@@all[version] ||= super
end
@@ -224,17 +224,9 @@ class Gem::Version
end
# If version is an empty string convert it to 0
- version = 0 if version.is_a?(String) && /\A\s*\Z/.match?(version)
-
- @version = version.to_s
+ version = 0 if version.is_a?(String) && version =~ /\A\s*\Z/
- # optimization to avoid allocation when given an integer, since we know
- # it's to_s won't have any spaces or dashes
- unless version.is_a?(Integer)
- @version = @version.strip
- @version.gsub!("-",".pre.")
- end
- @version = -@version
+ @version = version.to_s.strip.gsub("-",".pre.")
@segments = nil
end
@@ -260,7 +252,7 @@ class Gem::Version
# same precision. Version "1.0" is not the same as version "1".
def eql?(other)
- self.class === other && @version == other.version
+ self.class === other && @version == other._version
end
def hash # :nodoc:
@@ -292,11 +284,15 @@ class Gem::Version
end
def yaml_initialize(tag, map) # :nodoc:
- @version = -map["version"]
+ @version = map["version"]
@segments = nil
@hash = nil
end
+ def to_yaml_properties # :nodoc:
+ ["@version"]
+ end
+
def encode_with(coder) # :nodoc:
coder.add "version", @version
end
@@ -306,7 +302,7 @@ class Gem::Version
def prerelease?
unless instance_variable_defined? :@prerelease
- @prerelease = /[a-zA-Z]/.match?(version)
+ @prerelease = !!(@version =~ /[a-zA-Z]/)
end
@prerelease
end
@@ -358,7 +354,7 @@ class Gem::Version
return self <=> self.class.new(other) if (String === other) && self.class.correct?(other)
return unless Gem::Version === other
- return 0 if @version == other.version || canonical_segments == other.canonical_segments
+ return 0 if @version == other._version || canonical_segments == other.canonical_segments
lhsegments = canonical_segments
rhsegments = other.canonical_segments
@@ -370,8 +366,7 @@ class Gem::Version
i = 0
while i <= limit
- lhs = lhsegments[i] || 0
- rhs = rhsegments[i] || 0
+ lhs, rhs = lhsegments[i] || 0, rhsegments[i] || 0
i += 1
next if lhs == rhs
@@ -381,40 +376,42 @@ class Gem::Version
return lhs <=> rhs
end
- 0
+ return 0
end
- # remove trailing zeros segments before first letter or at the end of the version
def canonical_segments
- @canonical_segments ||= begin
- # remove trailing 0 segments, using dot or letter as anchor
- # may leave a trailing dot which will be ignored by partition_segments
- canonical_version = @version.sub(/(?<=[a-zA-Z.])[.0]+\z/, "")
- # remove 0 segments before the first letter in a prerelease version
- canonical_version.sub!(/(?<=\.|\A)[0.]+(?=[a-zA-Z])/, "") if prerelease?
- partition_segments(canonical_version)
- end
+ @canonical_segments ||=
+ _split_segments.map! do |segments|
+ segments.reverse_each.drop_while {|s| s == 0 }.reverse
+ end.reduce(&:concat)
end
def freeze
prerelease?
- _segments
canonical_segments
super
end
protected
+ def _version
+ @version
+ end
+
def _segments
# segments is lazy so it can pick up version values that come from
# old marshaled versions, which don't go through marshal_load.
# since this version object is cached in @@all, its @segments should be frozen
- @segments ||= partition_segments(@version)
- end
- def partition_segments(ver)
- ver.scan(/\d+|[a-z]+/i).map! do |s|
- /\A\d/.match?(s) ? s.to_i : -s
+ @segments ||= @version.scan(/[0-9]+|[a-z]+/i).map do |s|
+ /^\d+$/ =~ s ? s.to_i : s
end.freeze
end
+
+ def _split_segments
+ string_start = _segments.index {|s| s.is_a?(String) }
+ string_segments = segments
+ numeric_segments = string_segments.slice!(0, string_start || string_segments.size)
+ return numeric_segments, string_segments
+ end
end
diff --git a/lib/rubygems/version_option.rb b/lib/rubygems/version_option.rb
index 7910fd3d1b..d83a69cf0d 100644
--- a/lib/rubygems/version_option.rb
+++ b/lib/rubygems/version_option.rb
@@ -12,6 +12,7 @@ require_relative "../rubygems"
# Mixin methods for --version and --platform Gem::Command options.
module Gem::VersionOption
+
##
# Add the --platform option to the option parser.
@@ -25,7 +26,8 @@ module Gem::VersionOption
end
add_option("--platform PLATFORM", Gem::Platform,
- "Specify the platform of gem to #{task}", *wrap) do |value, options|
+ "Specify the platform of gem to #{task}", *wrap) do
+ |value, options|
unless options[:added_platform]
Gem.platforms = [Gem::Platform::RUBY]
options[:added_platform] = true
@@ -55,7 +57,8 @@ module Gem::VersionOption
end
add_option("-v", "--version VERSION", Gem::Requirement,
- "Specify version of gem to #{task}", *wrap) do |value, options|
+ "Specify version of gem to #{task}", *wrap) do
+ |value, options|
# Allow handling for multiple --version operators
if options[:version] && !options[:version].none?
options[:version].concat([value])
diff --git a/lib/rubygems/yaml_serializer.rb b/lib/rubygems/yaml_serializer.rb
deleted file mode 100644
index f89004f32a..0000000000
--- a/lib/rubygems/yaml_serializer.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-# frozen_string_literal: true
-
-module Gem
- # A stub yaml serializer that can handle only hashes and strings (as of now).
- module YAMLSerializer
- module_function
-
- def dump(hash)
- yaml = String.new("---")
- yaml << dump_hash(hash)
- end
-
- def dump_hash(hash)
- yaml = String.new("\n")
- hash.each do |k, v|
- yaml << k << ":"
- if v.is_a?(Hash)
- yaml << dump_hash(v).gsub(/^(?!$)/, " ") # indent all non-empty lines
- elsif v.is_a?(Array) # Expected to be array of strings
- if v.empty?
- yaml << " []\n"
- else
- yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n"
- end
- else
- yaml << " " << v.to_s.gsub(/\s+/, " ").inspect << "\n"
- end
- end
- yaml
- end
-
- ARRAY_REGEX = /
- ^
- (?:[ ]*-[ ]) # '- ' before array items
- (['"]?) # optional opening quote
- (.*) # value
- \1 # matching closing quote
- $
- /xo
-
- HASH_REGEX = /
- ^
- ([ ]*) # indentations
- ([^#]+) # key excludes comment char '#'
- (?::(?=(?:\s|$))) # : (without the lookahead the #key includes this when : is present in value)
- [ ]?
- (['"]?) # optional opening quote
- (.*) # value
- \3 # matching closing quote
- $
- /xo
-
- def load(str)
- res = {}
- stack = [res]
- last_hash = nil
- last_empty_key = nil
- str.split(/\r?\n/) do |line|
- if match = HASH_REGEX.match(line)
- indent, key, quote, val = match.captures
- val = strip_comment(val)
-
- depth = indent.size / 2
- if quote.empty? && val.empty?
- new_hash = {}
- stack[depth][key] = new_hash
- stack[depth + 1] = new_hash
- last_empty_key = key
- last_hash = stack[depth]
- else
- val = [] if val == "[]" # empty array
- stack[depth][key] = val
- end
- elsif match = ARRAY_REGEX.match(line)
- _, val = match.captures
- val = strip_comment(val)
-
- last_hash[last_empty_key] = [] unless last_hash[last_empty_key].is_a?(Array)
-
- last_hash[last_empty_key].push(val)
- end
- end
- res
- end
-
- def strip_comment(val)
- if val.include?("#") && !val.start_with?("#")
- val.split("#", 2).first.strip
- else
- val
- end
- end
-
- class << self
- private :dump_hash
- end
- end
-end
diff --git a/lib/securerandom.gemspec b/lib/securerandom.gemspec
index 0b023486a6..e095244ce9 100644
--- a/lib/securerandom.gemspec
+++ b/lib/securerandom.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "securerandom"
+ spec.version = "0.2.2"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
@@ -20,13 +13,8 @@ Gem::Specification.new do |spec|
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
- # Specify which files should be added to the gem when it is released.
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- spec.files = Dir.chdir(__dir__) do
- `git ls-files -z`.split("\x0").reject do |f|
- (File.expand_path(f) == __FILE__) ||
- f.start_with?(*%w[bin/ test/ spec/ features/ docs/ rakelib/ .document .git Gemfile Rakefile])
- end
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/securerandom.rb b/lib/securerandom.rb
index 81757f3100..07ae048634 100644
--- a/lib/securerandom.rb
+++ b/lib/securerandom.rb
@@ -39,28 +39,28 @@ require 'random/formatter'
# +NotImplementedError+ is raised.
module SecureRandom
-
- # The version
- VERSION = "0.3.1"
-
class << self
- # Returns a random binary string containing +size+ bytes.
- #
- # See Random.bytes
def bytes(n)
return gen_random(n)
end
private
- # :stopdoc:
-
- # Implementation using OpenSSL
def gen_random_openssl(n)
+ @pid = 0 unless defined?(@pid)
+ pid = $$
+ unless @pid == pid
+ now = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
+ OpenSSL::Random.random_add([now, @pid, pid].join(""), 0.0)
+ seed = Random.urandom(16)
+ if (seed)
+ OpenSSL::Random.random_add(seed, 16)
+ end
+ @pid = pid
+ end
return OpenSSL::Random.random_bytes(n)
end
- # Implementation using system random device
def gen_random_urandom(n)
ret = Random.urandom(n)
unless ret
@@ -86,9 +86,6 @@ module SecureRandom
end
end
- # :startdoc:
-
- # Generate random data bytes for Random::Formatter
public :gen_random
end
end
diff --git a/lib/set.rb b/lib/set.rb
index 8ac9ce45b1..df1e68d081 100644
--- a/lib/set.rb
+++ b/lib/set.rb
@@ -3,7 +3,7 @@
#
# set.rb - defines the Set class
#
-# Copyright (c) 2002-2024 Akinori MUSHA <knu@iDaemons.org>
+# Copyright (c) 2002-2020 Akinori MUSHA <knu@iDaemons.org>
#
# Documentation by Akinori MUSHA and Gavin Sinclair.
#
@@ -12,12 +12,16 @@
##
-# This library provides the Set class, which implements a collection
-# of unordered values with no duplicates. It is a hybrid of Array's
+# This library provides the Set class, which deals with a collection
+# of unordered values with no duplicates. It is a hybrid of Array's
# intuitive inter-operation facilities and Hash's fast lookup.
#
# The method `to_set` is added to Enumerable for convenience.
#
+# Set implements a collection of unordered values with no duplicates.
+# This is a hybrid of Array's intuitive inter-operation facilities and
+# Hash's fast lookup.
+#
# Set is easy to use with Enumerable objects (implementing `each`).
# Most of the initializer methods and binary operators accept generic
# Enumerable objects besides sets and arrays. An Enumerable object
@@ -152,7 +156,7 @@
# If the given object is not an element in the set,
# adds it and returns +self+; otherwise, returns +nil+.
# - \#merge:
-# Merges the elements of each given enumerable object to the set; returns +self+.
+# Adds each given object to the set; returns +self+.
# - \#replace:
# Replaces the contents of the set with the contents
# of a given enumerable.
@@ -216,8 +220,6 @@
# has been modified while an element in the set.
#
class Set
- VERSION = "1.1.0"
-
include Enumerable
# Creates a new set containing the given objects.
@@ -286,10 +288,18 @@ class Set
@hash = orig.instance_variable_get(:@hash).dup
end
- # Clone internal hash.
- def initialize_clone(orig, **options)
- super
- @hash = orig.instance_variable_get(:@hash).clone(**options)
+ if Kernel.instance_method(:initialize_clone).arity != 1
+ # Clone internal hash.
+ def initialize_clone(orig, **options)
+ super
+ @hash = orig.instance_variable_get(:@hash).clone(**options)
+ end
+ else
+ # Clone internal hash.
+ def initialize_clone(orig)
+ super
+ @hash = orig.instance_variable_get(:@hash).clone
+ end
end
def freeze # :nodoc:
@@ -335,7 +345,7 @@ class Set
end
end
- # Returns an array containing all elements in the set.
+ # Converts the set to an array. The order of elements is uncertain.
#
# Set[1, 2].to_a #=> [1, 2]
# Set[1, 'c', :s].to_a #=> [1, "c", :s]
@@ -381,7 +391,7 @@ class Set
# Equivalent to Set#flatten, but replaces the receiver with the
# result in place. Returns nil if no modifications were made.
def flatten!
- replace(flatten()) if any?(Set)
+ replace(flatten()) if any? { |e| e.is_a?(Set) }
end
# Returns true if the set contains the given object.
@@ -401,7 +411,7 @@ class Set
when set.instance_of?(self.class) && @hash.respond_to?(:>=)
@hash >= set.instance_variable_get(:@hash)
when set.is_a?(Set)
- size >= set.size && set.all?(self)
+ size >= set.size && set.all? { |o| include?(o) }
else
raise ArgumentError, "value must be a set"
end
@@ -414,7 +424,7 @@ class Set
when set.instance_of?(self.class) && @hash.respond_to?(:>)
@hash > set.instance_variable_get(:@hash)
when set.is_a?(Set)
- size > set.size && set.all?(self)
+ size > set.size && set.all? { |o| include?(o) }
else
raise ArgumentError, "value must be a set"
end
@@ -427,7 +437,7 @@ class Set
when set.instance_of?(self.class) && @hash.respond_to?(:<=)
@hash <= set.instance_variable_get(:@hash)
when set.is_a?(Set)
- size <= set.size && all?(set)
+ size <= set.size && all? { |o| set.include?(o) }
else
raise ArgumentError, "value must be a set"
end
@@ -440,7 +450,7 @@ class Set
when set.instance_of?(self.class) && @hash.respond_to?(:<)
@hash < set.instance_variable_get(:@hash)
when set.is_a?(Set)
- size < set.size && all?(set)
+ size < set.size && all? { |o| set.include?(o) }
else
raise ArgumentError, "value must be a set"
end
@@ -471,12 +481,12 @@ class Set
case set
when Set
if size < set.size
- any?(set)
+ any? { |o| set.include?(o) }
else
- set.any?(self)
+ set.any? { |o| include?(o) }
end
when Enumerable
- set.any?(self)
+ set.any? { |o| include?(o) }
else
raise ArgumentError, "value must be enumerable"
end
@@ -497,7 +507,7 @@ class Set
# the element as parameter. Returns an enumerator if no block is
# given.
def each(&block)
- block_given? or return enum_for(__method__) { size }
+ block or return enum_for(__method__) { size }
@hash.each_key(&block)
self
end
@@ -540,22 +550,22 @@ class Set
# Deletes every element of the set for which block evaluates to
# true, and returns self. Returns an enumerator if no block is
# given.
- def delete_if(&block)
+ def delete_if
block_given? or return enum_for(__method__) { size }
- # Instead of directly using @hash.delete_if, perform enumeration
- # using self.each that subclasses may override.
- select(&block).each { |o| @hash.delete(o) }
+ # @hash.delete_if should be faster, but using it breaks the order
+ # of enumeration in subclasses.
+ select { |o| yield o }.each { |o| @hash.delete(o) }
self
end
# Deletes every element of the set for which block evaluates to
# false, and returns self. Returns an enumerator if no block is
# given.
- def keep_if(&block)
+ def keep_if
block_given? or return enum_for(__method__) { size }
- # Instead of directly using @hash.keep_if, perform enumeration
- # using self.each that subclasses may override.
- reject(&block).each { |o| @hash.delete(o) }
+ # @hash.keep_if should be faster, but using it breaks the order of
+ # enumeration in subclasses.
+ reject { |o| yield o }.each { |o| @hash.delete(o) }
self
end
@@ -572,7 +582,7 @@ class Set
# Equivalent to Set#delete_if, but returns nil if no changes were
# made. Returns an enumerator if no block is given.
def reject!(&block)
- block_given? or return enum_for(__method__) { size }
+ block or return enum_for(__method__) { size }
n = size
delete_if(&block)
self if size != n
@@ -581,7 +591,7 @@ class Set
# Equivalent to Set#keep_if, but returns nil if no changes were
# made. Returns an enumerator if no block is given.
def select!(&block)
- block_given? or return enum_for(__method__) { size }
+ block or return enum_for(__method__) { size }
n = size
keep_if(&block)
self if size != n
@@ -590,15 +600,13 @@ class Set
# Equivalent to Set#select!
alias filter! select!
- # Merges the elements of the given enumerable objects to the set and
+ # Merges the elements of the given enumerable object to the set and
# returns self.
- def merge(*enums, **nil)
- enums.each do |enum|
- if enum.instance_of?(self.class)
- @hash.update(enum.instance_variable_get(:@hash))
- else
- do_with_enum(enum) { |o| add(o) }
- end
+ def merge(enum)
+ if enum.instance_of?(self.class)
+ @hash.update(enum.instance_variable_get(:@hash))
+ else
+ do_with_enum(enum) { |o| add(o) }
end
self
diff --git a/lib/set/set.gemspec b/lib/set/set.gemspec
index 2ebef6985d..0def52e859 100644
--- a/lib/set/set.gemspec
+++ b/lib/set/set.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "set"
+ spec.version = "1.0.3"
spec.authors = ["Akinori MUSHA"]
spec.email = ["knu@idaemons.org"]
@@ -15,7 +8,7 @@ Gem::Specification.new do |spec|
spec.description = %q{Provides a class to deal with collections of unordered, unique values}
spec.homepage = "https://github.com/ruby/set"
spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0")
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
diff --git a/lib/shellwords.gemspec b/lib/shellwords.gemspec
index 8d0c518ca5..8ae87b230e 100644
--- a/lib/shellwords.gemspec
+++ b/lib/shellwords.gemspec
@@ -1,14 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "shellwords"
+ spec.version = "0.1.0"
spec.authors = ["Akinori MUSHA"]
spec.email = ["knu@idaemons.org"]
@@ -21,9 +13,8 @@ Gem::Specification.new do |spec|
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
- srcdir, gemspec_file = File.split(__FILE__)
- spec.files = Dir.chdir(srcdir) do
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:(?:test|spec|features)/|\.git|Rake)}) || f == gemspec_file}
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/shellwords.rb b/lib/shellwords.rb
index d8243abd61..4368a53ea8 100644
--- a/lib/shellwords.rb
+++ b/lib/shellwords.rb
@@ -5,9 +5,9 @@
# This module manipulates strings according to the word parsing rules
# of the UNIX Bourne shell.
#
-# The <tt>shellwords()</tt> function was originally a port of shellwords.pl, but
-# modified to conform to {the Shell & Utilities volume of the IEEE Std 1003.1-2008, 2016
-# Edition}[http://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html]
+# The shellwords() function was originally a port of shellwords.pl,
+# but modified to conform to the Shell & Utilities volume of the IEEE
+# Std 1003.1-2008, 2016 Edition [1].
#
# === Usage
#
@@ -62,11 +62,12 @@
#
# === Contact
# * Akinori MUSHA <knu@iDaemons.org> (current maintainer)
+#
+# === Resources
+#
+# 1: {IEEE Std 1003.1-2008, 2016 Edition, the Shell & Utilities volume}[http://pubs.opengroup.org/onlinepubs/9699919799/utilities/contents.html]
module Shellwords
- # The version number string.
- VERSION = "0.2.0"
-
# Splits a string into an array of tokens in the same way the UNIX
# Bourne shell does.
#
diff --git a/lib/singleton.gemspec b/lib/singleton.gemspec
deleted file mode 100644
index 7646914905..0000000000
--- a/lib/singleton.gemspec
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{The Singleton module implements the Singleton pattern.}
- spec.description = spec.summary
- spec.homepage = "https://github.com/ruby/singleton"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
-
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.bindir = "exe"
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
- spec.require_paths = ["lib"]
-end
diff --git a/lib/singleton.rb b/lib/singleton.rb
index 1011335adf..07420d2ea2 100644
--- a/lib/singleton.rb
+++ b/lib/singleton.rb
@@ -1,4 +1,4 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
# The Singleton module implements the Singleton pattern.
#
@@ -92,25 +92,22 @@
# p a.strip # => nil
#
module Singleton
- VERSION = "0.2.0"
+ VERSION = "0.1.1"
- module SingletonInstanceMethods
- # Raises a TypeError to prevent cloning.
- def clone
- raise TypeError, "can't clone instance of singleton #{self.class}"
- end
+ # Raises a TypeError to prevent cloning.
+ def clone
+ raise TypeError, "can't clone instance of singleton #{self.class}"
+ end
- # Raises a TypeError to prevent duping.
- def dup
- raise TypeError, "can't dup instance of singleton #{self.class}"
- end
+ # Raises a TypeError to prevent duping.
+ def dup
+ raise TypeError, "can't dup instance of singleton #{self.class}"
+ end
- # By default, do not retain any state when marshalling.
- def _dump(depth = -1)
- ''
- end
+ # By default, do not retain any state when marshalling.
+ def _dump(depth = -1)
+ ''
end
- include SingletonInstanceMethods
module SingletonClassMethods # :nodoc:
@@ -124,7 +121,12 @@ module Singleton
end
def instance # :nodoc:
- @singleton__instance__ || @singleton__mutex__.synchronize { @singleton__instance__ ||= new }
+ return @singleton__instance__ if @singleton__instance__
+ @singleton__mutex__.synchronize {
+ return @singleton__instance__ if @singleton__instance__
+ @singleton__instance__ = new()
+ }
+ @singleton__instance__
end
private
@@ -133,42 +135,22 @@ module Singleton
super
Singleton.__init__(sub_klass)
end
-
- def set_instance(val)
- @singleton__instance__ = val
- end
-
- def set_mutex(val)
- @singleton__mutex__ = val
- end
- end
-
- def self.module_with_class_methods
- SingletonClassMethods
end
- module SingletonClassProperties
-
- def self.included(c)
- # extending an object with Singleton is a bad idea
- c.undef_method :extend_object
- end
-
- def self.extended(c)
- # extending an object with Singleton is a bad idea
- c.singleton_class.send(:undef_method, :extend_object)
- end
-
+ class << Singleton # :nodoc:
def __init__(klass) # :nodoc:
klass.instance_eval {
- set_instance(nil)
- set_mutex(Thread::Mutex.new)
+ @singleton__instance__ = nil
+ @singleton__mutex__ = Thread::Mutex.new
}
klass
end
private
+ # extending an object with Singleton is a bad idea
+ undef_method :extend_object
+
def append_features(mod)
# help out people counting on transitive mixins
unless mod.instance_of?(Class)
@@ -180,11 +162,10 @@ module Singleton
def included(klass)
super
klass.private_class_method :new, :allocate
- klass.extend module_with_class_methods
+ klass.extend SingletonClassMethods
Singleton.__init__(klass)
end
end
- extend SingletonClassProperties
##
# :singleton-method: _load
@@ -194,46 +175,3 @@ module Singleton
# :singleton-method: instance
# Returns the singleton instance.
end
-
-if defined?(Ractor)
- module RactorLocalSingleton
- include Singleton::SingletonInstanceMethods
-
- module RactorLocalSingletonClassMethods
- include Singleton::SingletonClassMethods
- def instance
- set_mutex(Thread::Mutex.new) if Ractor.current[mutex_key].nil?
- return Ractor.current[instance_key] if Ractor.current[instance_key]
- Ractor.current[mutex_key].synchronize {
- return Ractor.current[instance_key] if Ractor.current[instance_key]
- set_instance(new())
- }
- Ractor.current[instance_key]
- end
-
- private
-
- def instance_key
- :"__RactorLocalSingleton_instance_with_class_id_#{object_id}__"
- end
-
- def mutex_key
- :"__RactorLocalSingleton_mutex_with_class_id_#{object_id}__"
- end
-
- def set_instance(val)
- Ractor.current[instance_key] = val
- end
-
- def set_mutex(val)
- Ractor.current[mutex_key] = val
- end
- end
-
- def self.module_with_class_methods
- RactorLocalSingletonClassMethods
- end
-
- extend Singleton::SingletonClassProperties
- end
-end
diff --git a/lib/singleton/singleton.gemspec b/lib/singleton/singleton.gemspec
new file mode 100644
index 0000000000..88d3111b65
--- /dev/null
+++ b/lib/singleton/singleton.gemspec
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{The Singleton module implements the Singleton pattern.}
+ spec.description = spec.summary
+ spec.homepage = "https://github.com/ruby/singleton"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/syntax_suggest/api.rb b/lib/syntax_suggest/api.rb
index 65660ec5e5..74e53c2563 100644
--- a/lib/syntax_suggest/api.rb
+++ b/lib/syntax_suggest/api.rb
@@ -5,27 +5,8 @@ require_relative "version"
require "tmpdir"
require "stringio"
require "pathname"
-require "timeout"
-
-# We need Ripper loaded for `Prism.lex_compat` even if we're using Prism
-# for lexing and parsing
require "ripper"
-
-# Prism is the new parser, replacing Ripper
-#
-# We need to "dual boot" both for now because syntax_suggest
-# supports older rubies that do not ship with syntax suggest.
-#
-# We also need the ability to control loading of this library
-# so we can test that both modes work correctly in CI.
-if (value = ENV["SYNTAX_SUGGEST_DISABLE_PRISM"])
- warn "Skipping loading prism due to SYNTAX_SUGGEST_DISABLE_PRISM=#{value}"
-else
- begin
- require "prism"
- rescue LoadError
- end
-end
+require "timeout"
module SyntaxSuggest
# Used to indicate a default value that cannot
@@ -35,14 +16,6 @@ module SyntaxSuggest
class Error < StandardError; end
TIMEOUT_DEFAULT = ENV.fetch("SYNTAX_SUGGEST_TIMEOUT", 1).to_i
- # SyntaxSuggest.use_prism_parser? [Private]
- #
- # Tells us if the prism parser is available for use
- # or if we should fallback to `Ripper`
- def self.use_prism_parser?
- defined?(Prism)
- end
-
# SyntaxSuggest.handle_error [Public]
#
# Takes a `SyntaxError` exception, uses the
@@ -156,20 +129,11 @@ module SyntaxSuggest
# SyntaxSuggest.invalid? [Private]
#
# Opposite of `SyntaxSuggest.valid?`
- if defined?(Prism)
- def self.invalid?(source)
- source = source.join if source.is_a?(Array)
- source = source.to_s
+ def self.invalid?(source)
+ source = source.join if source.is_a?(Array)
+ source = source.to_s
- Prism.parse(source).failure?
- end
- else
- def self.invalid?(source)
- source = source.join if source.is_a?(Array)
- source = source.to_s
-
- Ripper.new(source).tap(&:parse).error?
- end
+ Ripper.new(source).tap(&:parse).error?
end
# SyntaxSuggest.valid? [Private]
@@ -227,6 +191,7 @@ require_relative "lex_all"
require_relative "code_line"
require_relative "code_block"
require_relative "block_expand"
+require_relative "ripper_errors"
require_relative "priority_queue"
require_relative "unvisited_lines"
require_relative "around_block_scan"
diff --git a/lib/syntax_suggest/around_block_scan.rb b/lib/syntax_suggest/around_block_scan.rb
index dd9af729c5..ce00431b3a 100644
--- a/lib/syntax_suggest/around_block_scan.rb
+++ b/lib/syntax_suggest/around_block_scan.rb
@@ -118,7 +118,7 @@ module SyntaxSuggest
end
# Scanning is intentionally conservative because
- # we have no way of rolling back an aggressive block (at this time)
+ # we have no way of rolling back an agressive block (at this time)
#
# If a block was stopped for some trivial reason, (like an empty line)
# but the next line would have caused it to be balanced then we
@@ -224,7 +224,7 @@ module SyntaxSuggest
@scanner.lines
end
- # Manageable rspec errors
+ # Managable rspec errors
def inspect
"#<#{self.class}:0x0000123843lol >"
end
diff --git a/lib/syntax_suggest/block_expand.rb b/lib/syntax_suggest/block_expand.rb
index 2751ae2a64..e9b486c720 100644
--- a/lib/syntax_suggest/block_expand.rb
+++ b/lib/syntax_suggest/block_expand.rb
@@ -157,7 +157,7 @@ module SyntaxSuggest
end
end
- # Manageable rspec errors
+ # Managable rspec errors
def inspect
"#<SyntaxSuggest::CodeBlock:0x0000123843lol >"
end
diff --git a/lib/syntax_suggest/capture_code_context.rb b/lib/syntax_suggest/capture_code_context.rb
index 1f232cfae3..6dc7047176 100644
--- a/lib/syntax_suggest/capture_code_context.rb
+++ b/lib/syntax_suggest/capture_code_context.rb
@@ -26,7 +26,7 @@ module SyntaxSuggest
# they can't add extra data that's not present.
#
# In the case of known ambiguious cases, this class adds context
- # back to the ambiguity so the programmer has full information.
+ # back to the ambiguitiy so the programmer has full information.
#
# Beyond handling these ambiguities, it also captures surrounding
# code context information:
diff --git a/lib/syntax_suggest/clean_document.rb b/lib/syntax_suggest/clean_document.rb
index 2790ccae86..2c26061bfc 100644
--- a/lib/syntax_suggest/clean_document.rb
+++ b/lib/syntax_suggest/clean_document.rb
@@ -47,9 +47,9 @@ module SyntaxSuggest
# ## Heredocs
#
# A heredoc is an way of defining a multi-line string. They can cause many
- # problems. If left as a single line, the parser would try to parse the contents
+ # problems. If left as a single line, Ripper would try to parse the contents
# as ruby code rather than as a string. Even without this problem, we still
- # hit an issue with indentation:
+ # hit an issue with indentation
#
# 1 foo = <<~HEREDOC
# 2 "Be yourself; everyone else is already taken.""
@@ -224,7 +224,7 @@ module SyntaxSuggest
#
def join_consecutive!
consecutive_groups = @document.select(&:ignore_newline_not_beg?).map do |code_line|
- take_while_including(code_line.index..) do |line|
+ take_while_including(code_line.index..-1) do |line|
line.ignore_newline_not_beg?
end
end
@@ -245,7 +245,7 @@ module SyntaxSuggest
# expect(lines[1].to_s).to eq("")
def join_trailing_slash!
trailing_groups = @document.select(&:trailing_slash?).map do |code_line|
- take_while_including(code_line.index..) { |x| x.trailing_slash? }
+ take_while_including(code_line.index..-1) { |x| x.trailing_slash? }
end
join_groups(trailing_groups)
self
@@ -267,7 +267,7 @@ module SyntaxSuggest
groups.each do |lines|
line = lines.first
- # Handle the case of multiple groups in a row
+ # Handle the case of multiple groups in a a row
# if one is already replaced, move on
next if @document[line.index].empty?
@@ -279,7 +279,7 @@ module SyntaxSuggest
)
# Hide the rest of the lines
- lines[1..].each do |line|
+ lines[1..-1].each do |line|
# The above lines already have newlines in them, if add more
# then there will be double newline, use an empty line instead
@document[line.index] = CodeLine.new(line: "", index: line.index, lex: [])
@@ -293,7 +293,7 @@ module SyntaxSuggest
# Like `take_while` except when it stops
# iterating, it also returns the line
# that caused it to stop
- def take_while_including(range = 0..)
+ def take_while_including(range = 0..-1)
take_next_and_stop = false
@document[range].take_while do |line|
next if take_next_and_stop
diff --git a/lib/syntax_suggest/code_block.rb b/lib/syntax_suggest/code_block.rb
index d842890300..61e7986da4 100644
--- a/lib/syntax_suggest/code_block.rb
+++ b/lib/syntax_suggest/code_block.rb
@@ -81,7 +81,7 @@ module SyntaxSuggest
# lines then the result cannot be invalid
#
# That means there's no reason to re-check all
- # lines with the parser (which is expensive).
+ # lines with ripper (which is expensive).
# Benchmark in commit message
@valid = if lines.all? { |l| l.hidden? || l.empty? }
true
diff --git a/lib/syntax_suggest/code_frontier.rb b/lib/syntax_suggest/code_frontier.rb
index 0f870d0df0..8e93b32514 100644
--- a/lib/syntax_suggest/code_frontier.rb
+++ b/lib/syntax_suggest/code_frontier.rb
@@ -117,7 +117,7 @@ module SyntaxSuggest
if ENV["SYNTAX_SUGGEST_DEBUG"]
puts "```"
- puts @queue.peek
+ puts @queue.peek.to_s
puts "```"
puts " @frontier indent: #{frontier_indent}"
puts " @unvisited indent: #{unvisited_indent}"
diff --git a/lib/syntax_suggest/code_line.rb b/lib/syntax_suggest/code_line.rb
index 58197e95d0..a20f34afa4 100644
--- a/lib/syntax_suggest/code_line.rb
+++ b/lib/syntax_suggest/code_line.rb
@@ -180,19 +180,12 @@ module SyntaxSuggest
# EOM
# expect(lines.first.trailing_slash?).to eq(true)
#
- if SyntaxSuggest.use_prism_parser?
- def trailing_slash?
- last = @lex.last
- last&.type == :on_tstring_end
- end
- else
- def trailing_slash?
- last = @lex.last
- return false unless last
- return false unless last.type == :on_sp
+ def trailing_slash?
+ last = @lex.last
+ return false unless last
+ return false unless last.type == :on_sp
- last.token == TRAILING_SLASH
- end
+ last.token == TRAILING_SLASH
end
# Endless method detection
diff --git a/lib/syntax_suggest/code_search.rb b/lib/syntax_suggest/code_search.rb
index 7628dcd131..2a86dfea90 100644
--- a/lib/syntax_suggest/code_search.rb
+++ b/lib/syntax_suggest/code_search.rb
@@ -43,7 +43,7 @@ module SyntaxSuggest
def initialize(source, record_dir: DEFAULT_VALUE)
record_dir = if record_dir == DEFAULT_VALUE
- (ENV["SYNTAX_SUGGEST_RECORD_DIR"] || ENV["SYNTAX_SUGGEST_DEBUG"]) ? "tmp" : nil
+ ENV["SYNTAX_SUGGEST_RECORD_DIR"] || ENV["SYNTAX_SUGGEST_DEBUG"] ? "tmp" : nil
else
record_dir
end
@@ -73,7 +73,7 @@ module SyntaxSuggest
if ENV["SYNTAX_SUGGEST_DEBUG"]
puts "\n\n==== #{filename} ===="
puts "\n```#{block.starts_at}..#{block.ends_at}"
- puts block
+ puts block.to_s
puts "```"
puts " block indent: #{block.current_indent}"
end
diff --git a/lib/syntax_suggest/core_ext.rb b/lib/syntax_suggest/core_ext.rb
index c299627bb7..e0fd62b81c 100644
--- a/lib/syntax_suggest/core_ext.rb
+++ b/lib/syntax_suggest/core_ext.rb
@@ -21,7 +21,7 @@ if SyntaxError.method_defined?(:detailed_message)
attr_reader :string
end
- # SyntaxSuggest.module_for_detailed_message [Private]
+ # SyntaxSuggest.record_dir [Private]
#
# Used to monkeypatch SyntaxError via Module.prepend
def self.module_for_detailed_message
diff --git a/lib/syntax_suggest/display_invalid_blocks.rb b/lib/syntax_suggest/display_invalid_blocks.rb
index 5e79b3a262..32ec0021a3 100644
--- a/lib/syntax_suggest/display_invalid_blocks.rb
+++ b/lib/syntax_suggest/display_invalid_blocks.rb
@@ -14,7 +14,7 @@ module SyntaxSuggest
@filename = filename
@code_lines = code_lines
- @terminal = (terminal == DEFAULT_VALUE) ? io.isatty : terminal
+ @terminal = terminal == DEFAULT_VALUE ? io.isatty : terminal
end
def document_ok?
diff --git a/lib/syntax_suggest/explain_syntax.rb b/lib/syntax_suggest/explain_syntax.rb
index 0d80c4d869..142ed2e269 100644
--- a/lib/syntax_suggest/explain_syntax.rb
+++ b/lib/syntax_suggest/explain_syntax.rb
@@ -2,21 +2,7 @@
require_relative "left_right_lex_count"
-if !SyntaxSuggest.use_prism_parser?
- require_relative "ripper_errors"
-end
-
module SyntaxSuggest
- class GetParseErrors
- def self.errors(source)
- if SyntaxSuggest.use_prism_parser?
- Prism.parse(source).errors.map(&:message)
- else
- RipperErrors.new(source).call.errors
- end
- end
- end
-
# Explains syntax errors based on their source
#
# example:
@@ -29,8 +15,8 @@ module SyntaxSuggest
# # => "Unmatched keyword, missing `end' ?"
#
# When the error cannot be determined by lexical counting
- # then the parser is run against the input and the raw
- # errors are returned.
+ # then ripper is run against the input and the raw ripper
+ # errors returned.
#
# Example:
#
@@ -105,10 +91,10 @@ module SyntaxSuggest
# Returns an array of syntax error messages
#
# If no missing pairs are found it falls back
- # on the original error messages
+ # on the original ripper error messages
def errors
if missing.empty?
- return GetParseErrors.errors(@code_lines.map(&:original).join).uniq
+ return RipperErrors.new(@code_lines.map(&:original).join).call.errors
end
missing.map { |miss| why(miss) }
diff --git a/lib/syntax_suggest/lex_all.rb b/lib/syntax_suggest/lex_all.rb
index c16fbb52d3..132cba9f5d 100644
--- a/lib/syntax_suggest/lex_all.rb
+++ b/lib/syntax_suggest/lex_all.rb
@@ -3,53 +3,34 @@
module SyntaxSuggest
# Ripper.lex is not guaranteed to lex the entire source document
#
- # This class guarantees the whole document is lex-ed by iteratively
- # lexing the document where ripper stopped.
- #
- # Prism likely doesn't have the same problem. Once ripper support is removed
- # we can likely reduce the complexity here if not remove the whole concept.
- #
- # Example usage:
- #
- # lex = LexAll.new(source: source)
- # lex.each do |value|
- # puts value.line
- # end
+ # lex = LexAll.new(source: source)
+ # lex.each do |value|
+ # puts value.line
+ # end
class LexAll
include Enumerable
def initialize(source:, source_lines: nil)
- @lex = self.class.lex(source, 1)
- lineno = @lex.last[0][0] + 1
+ @lex = Ripper::Lexer.new(source, "-", 1).parse.sort_by(&:pos)
+ lineno = @lex.last.pos.first + 1
source_lines ||= source.lines
last_lineno = source_lines.length
until lineno >= last_lineno
- lines = source_lines[lineno..]
+ lines = source_lines[lineno..-1]
@lex.concat(
- self.class.lex(lines.join, lineno + 1)
+ Ripper::Lexer.new(lines.join, "-", lineno + 1).parse.sort_by(&:pos)
)
-
- lineno = @lex.last[0].first + 1
+ lineno = @lex.last.pos.first + 1
end
last_lex = nil
@lex.map! { |elem|
- last_lex = LexValue.new(elem[0].first, elem[1], elem[2], elem[3], last_lex)
+ last_lex = LexValue.new(elem.pos.first, elem.event, elem.tok, elem.state, last_lex)
}
end
- if SyntaxSuggest.use_prism_parser?
- def self.lex(source, line_number)
- Prism.lex_compat(source, line: line_number).value.sort_by { |values| values[0] }
- end
- else
- def self.lex(source, line_number)
- Ripper::Lexer.new(source, "-", line_number).parse.sort_by(&:pos)
- end
- end
-
def to_a
@lex
end
diff --git a/lib/syntax_suggest/parse_blocks_from_indent_line.rb b/lib/syntax_suggest/parse_blocks_from_indent_line.rb
index 39dfca55d2..241ed6acb4 100644
--- a/lib/syntax_suggest/parse_blocks_from_indent_line.rb
+++ b/lib/syntax_suggest/parse_blocks_from_indent_line.rb
@@ -8,7 +8,7 @@ module SyntaxSuggest
# grabbing one that contains only an "end". In this example:
#
# def dog
- # begonn # misspelled `begin`
+ # begonn # mispelled `begin`
# puts "bark"
# end
# end
diff --git a/lib/syntax_suggest/pathname_from_message.rb b/lib/syntax_suggest/pathname_from_message.rb
index ab90227427..b6fe1617be 100644
--- a/lib/syntax_suggest/pathname_from_message.rb
+++ b/lib/syntax_suggest/pathname_from_message.rb
@@ -13,7 +13,7 @@ module SyntaxSuggest
# # => "/tmp/scratch.rb"
#
class PathnameFromMessage
- EVAL_RE = /^\(eval.*\):\d+/
+ EVAL_RE = /^\(eval\):\d+/
STREAMING_RE = /^-:\d+/
attr_reader :name
diff --git a/lib/syntax_suggest/ripper_errors.rb b/lib/syntax_suggest/ripper_errors.rb
index 4e2bc90948..48eb206e48 100644
--- a/lib/syntax_suggest/ripper_errors.rb
+++ b/lib/syntax_suggest/ripper_errors.rb
@@ -1,10 +1,7 @@
# frozen_string_literal: true
module SyntaxSuggest
- # Capture parse errors from Ripper
- #
- # Prism returns the errors with their messages, but Ripper
- # does not. To get them we must make a custom subclass.
+ # Capture parse errors from ripper
#
# Example:
#
diff --git a/lib/syntax_suggest/scan_history.rb b/lib/syntax_suggest/scan_history.rb
index dc36e6ba2e..d15597c440 100644
--- a/lib/syntax_suggest/scan_history.rb
+++ b/lib/syntax_suggest/scan_history.rb
@@ -118,7 +118,7 @@ module SyntaxSuggest
# Returns an array of all the CodeLines that exist after
# the currently scanned block
private def after_lines
- @code_lines[@after_index.next..] || []
+ @code_lines[@after_index.next..-1] || []
end
private def current
diff --git a/lib/syntax_suggest/syntax_suggest.gemspec b/lib/syntax_suggest/syntax_suggest.gemspec
index 756a85bf63..0e611c13d0 100644
--- a/lib/syntax_suggest/syntax_suggest.gemspec
+++ b/lib/syntax_suggest/syntax_suggest.gemspec
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
spec.description = 'When you get an "unexpected end" in your syntax this gem helps you find it'
spec.homepage = "https://github.com/ruby/syntax_suggest.git"
spec.license = "MIT"
- spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0")
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = "https://github.com/ruby/syntax_suggest.git"
diff --git a/lib/syntax_suggest/version.rb b/lib/syntax_suggest/version.rb
index 4320adb218..ac8c2f62e5 100644
--- a/lib/syntax_suggest/version.rb
+++ b/lib/syntax_suggest/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module SyntaxSuggest
- VERSION = "2.0.0"
+ VERSION = "1.1.0"
end
diff --git a/lib/tempfile.gemspec b/lib/tempfile.gemspec
index 0b362b0a86..acb26b68db 100644
--- a/lib/tempfile.gemspec
+++ b/lib/tempfile.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "tempfile"
+ spec.version = "0.1.3"
spec.authors = ["Yukihiro Matsumoto"]
spec.email = ["matz@ruby-lang.org"]
@@ -22,12 +15,8 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- gemspec = File.basename(__FILE__)
- spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL, exception: false) do |ls|
- ls.readlines("\x0", chomp: true).reject do |f|
- (f == gemspec) ||
- f.start_with?(*%w[bin/ test/ spec/ features/ .git Gemfile])
- end
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.require_paths = ["lib"]
end
diff --git a/lib/tempfile.rb b/lib/tempfile.rb
index 2f8a39cfe5..c3263ed3c6 100644
--- a/lib/tempfile.rb
+++ b/lib/tempfile.rb
@@ -8,61 +8,18 @@
require 'delegate'
require 'tmpdir'
-# A utility class for managing temporary files.
-#
-# There are two kind of methods of creating a temporary file:
-#
-# - Tempfile.create (recommended)
-# - Tempfile.new and Tempfile.open (mostly for backward compatibility, not recommended)
-#
-# Tempfile.create creates a usual \File object.
-# The timing of file deletion is predictable.
-# Also, it supports open-and-unlink technique which
-# removes the temporary file immediately after creation.
-#
-# Tempfile.new and Tempfile.open creates a \Tempfile object.
-# The created file is removed by the GC (finalizer).
-# The timing of file deletion is not predictable.
+# A utility class for managing temporary files. When you create a Tempfile
+# object, it will create a temporary file with a unique filename. A Tempfile
+# objects behaves just like a File object, and you can perform all the usual
+# file operations on it: reading data, writing data, changing its permissions,
+# etc. So although this class does not explicitly document all instance methods
+# supported by File, you can in fact call any File instance method on a
+# Tempfile object.
#
# == Synopsis
#
# require 'tempfile'
#
-# # Tempfile.create with a block
-# # The filename are choosen automatically.
-# # (You can specify the prefix and suffix of the filename by an optional argument.)
-# Tempfile.create {|f|
-# f.puts "foo"
-# f.rewind
-# f.read # => "foo\n"
-# } # The file is removed at block exit.
-#
-# # Tempfile.create without a block
-# # You need to unlink the file in non-block form.
-# f = Tempfile.create
-# f.puts "foo"
-# f.close
-# File.unlink(f.path) # You need to unlink the file.
-#
-# # Tempfile.create(anonymous: true) without a block
-# f = Tempfile.create(anonymous: true)
-# # The file is already removed because anonymous.
-# f.path # => "/tmp/" (no filename since no file)
-# f.puts "foo"
-# f.rewind
-# f.read # => "foo\n"
-# f.close
-#
-# # Tempfile.create(anonymous: true) with a block
-# Tempfile.create(anonymous: true) {|f|
-# # The file is already removed because anonymous.
-# f.path # => "/tmp/" (no filename since no file)
-# f.puts "foo"
-# f.rewind
-# f.read # => "foo\n"
-# }
-#
-# # Not recommended: Tempfile.new without a block
# file = Tempfile.new('foo')
# file.path # => A unique filename in the OS's temp directory,
# # e.g.: "/tmp/foo.24722.0"
@@ -73,27 +30,7 @@ require 'tmpdir'
# file.close
# file.unlink # deletes the temp file
#
-# == About Tempfile.new and Tempfile.open
-#
-# This section does not apply to Tempfile.create because
-# it returns a File object (not a Tempfile object).
-#
-# When you create a Tempfile object,
-# it will create a temporary file with a unique filename. A Tempfile
-# objects behaves just like a File object, and you can perform all the usual
-# file operations on it: reading data, writing data, changing its permissions,
-# etc. So although this class does not explicitly document all instance methods
-# supported by File, you can in fact call any File instance method on a
-# Tempfile object.
-#
-# A Tempfile object has a finalizer to remove the temporary file.
-# This means that the temporary file is removed via GC.
-# This can cause several problems:
-#
-# - Long GC intervals and conservative GC can accumulate temporary files that are not removed.
-# - Temporary files are not removed if Ruby exits abnormally (such as SIGKILL, SEGV).
-#
-# There are legacy good practices for Tempfile.new and Tempfile.open as follows.
+# == Good practices
#
# === Explicit close
#
@@ -120,7 +57,7 @@ require 'tmpdir'
# Note that Tempfile.create returns a File instance instead of a Tempfile, which
# also avoids the overhead and complications of delegation.
#
-# Tempfile.create('foo') do |file|
+# Tempfile.open('foo') do |file|
# # ...do something with file...
# end
#
@@ -134,17 +71,12 @@ require 'tmpdir'
# be able to read from or write to the Tempfile, and you do not need to
# know the Tempfile's filename either.
#
-# Also, this guarantees the temporary file is removed even if Ruby exits abnormally.
-# The OS reclaims the storage for the temporary file when the file is closed or
-# the Ruby process exits (normally or abnormally).
-#
# For example, a practical use case for unlink-after-creation would be this:
# you need a large byte buffer that's too large to comfortably fit in RAM,
# e.g. when you're writing a web server and you want to buffer the client's
# file upload data.
#
-# `Tempfile.create(anonymous: true)` supports this behavior.
-# It also works on Windows.
+# Please refer to #unlink for more information and a code example.
#
# == Minor notes
#
@@ -156,9 +88,6 @@ require 'tmpdir'
# mutex.
class Tempfile < DelegateClass(File)
- # The version
- VERSION = "0.2.1"
-
# Creates a file in the underlying file system;
# returns a new \Tempfile object based on that file.
#
@@ -221,52 +150,26 @@ class Tempfile < DelegateClass(File)
@unlinked = false
@mode = mode|File::RDWR|File::CREAT|File::EXCL
- tmpfile = nil
::Dir::Tmpname.create(basename, tmpdir, **options) do |tmpname, n, opts|
opts[:perm] = 0600
- tmpfile = File.open(tmpname, @mode, **opts)
+ @tmpfile = File.open(tmpname, @mode, **opts)
@opts = opts.freeze
end
+ ObjectSpace.define_finalizer(self, Remover.new(@tmpfile))
- super(tmpfile)
-
- @finalizer_manager = FinalizerManager.new(__getobj__.path)
- @finalizer_manager.register(self, __getobj__)
- end
-
- def initialize_dup(other) # :nodoc:
- initialize_copy_iv(other)
- super(other)
- @finalizer_manager.register(self, __getobj__)
- end
-
- def initialize_clone(other) # :nodoc:
- initialize_copy_iv(other)
- super(other)
- @finalizer_manager.register(self, __getobj__)
- end
-
- private def initialize_copy_iv(other) # :nodoc:
- @unlinked = other.unlinked
- @mode = other.mode
- @opts = other.opts
- @finalizer_manager = other.finalizer_manager
+ super(@tmpfile)
end
# Opens or reopens the file with mode "r+".
def open
_close
-
mode = @mode & ~(File::CREAT|File::EXCL)
- __setobj__(File.open(__getobj__.path, mode, **@opts))
-
- @finalizer_manager.register(self, __getobj__)
-
- __getobj__
+ @tmpfile = File.open(@tmpfile.path, mode, **@opts)
+ __setobj__(@tmpfile)
end
def _close # :nodoc:
- __getobj__.close
+ @tmpfile.close
end
protected :_close
@@ -323,15 +226,13 @@ class Tempfile < DelegateClass(File)
def unlink
return if @unlinked
begin
- File.unlink(__getobj__.path)
+ File.unlink(@tmpfile.path)
rescue Errno::ENOENT
rescue Errno::EACCES
# may not be able to unlink on Windows; just ignore
return
end
-
- @finalizer_manager.unlinked = true
-
+ ObjectSpace.undefine_finalizer(self)
@unlinked = true
end
alias delete unlink
@@ -339,61 +240,47 @@ class Tempfile < DelegateClass(File)
# Returns the full path name of the temporary file.
# This will be nil if #unlink has been called.
def path
- @unlinked ? nil : __getobj__.path
+ @unlinked ? nil : @tmpfile.path
end
# Returns the size of the temporary file. As a side effect, the IO
# buffer is flushed before determining the size.
def size
- if !__getobj__.closed?
- __getobj__.size # File#size calls rb_io_flush_raw()
+ if !@tmpfile.closed?
+ @tmpfile.size # File#size calls rb_io_flush_raw()
else
- File.size(__getobj__.path)
+ File.size(@tmpfile.path)
end
end
alias length size
# :stopdoc:
def inspect
- if __getobj__.closed?
+ if @tmpfile.closed?
"#<#{self.class}:#{path} (closed)>"
else
"#<#{self.class}:#{path}>"
end
end
- alias to_s inspect
-
- protected
-
- attr_reader :unlinked, :mode, :opts, :finalizer_manager
-
- class FinalizerManager # :nodoc:
- attr_accessor :unlinked
- def initialize(path)
- @open_files = {}
- @path = path
+ class Remover # :nodoc:
+ def initialize(tmpfile)
@pid = Process.pid
- @unlinked = false
+ @tmpfile = tmpfile
end
- def register(obj, file)
- ObjectSpace.undefine_finalizer(obj)
- ObjectSpace.define_finalizer(obj, self)
- @open_files[obj.object_id] = file
- end
+ def call(*args)
+ return if @pid != Process.pid
- def call(object_id)
- @open_files.delete(object_id).close
+ $stderr.puts "removing #{@tmpfile.path}..." if $DEBUG
- if @open_files.empty? && !@unlinked && Process.pid == @pid
- $stderr.puts "removing #{@path}..." if $DEBUG
- begin
- File.unlink(@path)
- rescue Errno::ENOENT
- end
- $stderr.puts "done" if $DEBUG
+ @tmpfile.close
+ begin
+ File.unlink(@tmpfile.path)
+ rescue Errno::ENOENT
end
+
+ $stderr.puts "done" if $DEBUG
end
end
@@ -464,9 +351,8 @@ end
# see {File Permissions}[rdoc-ref:File@File+Permissions].
# - Mode is <tt>'w+'</tt> (read/write mode, positioned at the end).
#
-# The temporary file removal depends on the keyword argument +anonymous+ and
-# whether a block is given or not.
-# See the description about the +anonymous+ keyword argument later.
+# With no block, the file is not removed automatically,
+# and so should be explicitly removed.
#
# Example:
#
@@ -474,36 +360,11 @@ end
# f.class # => File
# f.path # => "/tmp/20220505-9795-17ky6f6"
# f.stat.mode.to_s(8) # => "100600"
-# f.close
# File.exist?(f.path) # => true
# File.unlink(f.path)
# File.exist?(f.path) # => false
#
-# Tempfile.create {|f|
-# f.puts "foo"
-# f.rewind
-# f.read # => "foo\n"
-# f.path # => "/tmp/20240524-380207-oma0ny"
-# File.exist?(f.path) # => true
-# } # The file is removed at block exit.
-#
-# f = Tempfile.create(anonymous: true)
-# # The file is already removed because anonymous
-# f.path # => "/tmp/" (no filename since no file)
-# f.puts "foo"
-# f.rewind
-# f.read # => "foo\n"
-# f.close
-#
-# Tempfile.create(anonymous: true) {|f|
-# # The file is already removed because anonymous
-# f.path # => "/tmp/" (no filename since no file)
-# f.puts "foo"
-# f.rewind
-# f.read # => "foo\n"
-# }
-#
-# The argument +basename+, if given, may be one of the following:
+# Argument +basename+, if given, may be one of:
#
# - A string: the generated filename begins with +basename+:
#
@@ -514,57 +375,27 @@ end
#
# Tempfile.create(%w/foo .jpg/) # => #<File:/tmp/foo20220505-17839-tnjchh.jpg>
#
-# With arguments +basename+ and +tmpdir+, the file is created in the directory +tmpdir+:
+# With arguments +basename+ and +tmpdir+, the file is created in directory +tmpdir+:
#
# Tempfile.create('foo', '.') # => #<File:./foo20220505-9795-1emu6g8>
#
-# Keyword arguments +mode+ and +options+ are passed directly to the method
+# Keyword arguments +mode+ and +options+ are passed directly to method
# {File.open}[rdoc-ref:File.open]:
#
-# - The value given for +mode+ must be an integer
+# - The value given with +mode+ must be an integer,
# and may be expressed as the logical OR of constants defined in
# {File::Constants}[rdoc-ref:File::Constants].
# - For +options+, see {Open Options}[rdoc-ref:IO@Open+Options].
#
-# The keyword argument +anonymous+ specifies when the file is removed.
-#
-# - <tt>anonymous=false</tt> (default) without a block: the file is not removed.
-# - <tt>anonymous=false</tt> (default) with a block: the file is removed after the block exits.
-# - <tt>anonymous=true</tt> without a block: the file is removed before returning.
-# - <tt>anonymous=true</tt> with a block: the file is removed before the block is called.
-#
-# In the first case (<tt>anonymous=false</tt> without a block),
-# the file is not removed automatically.
-# It should be explicitly closed.
-# It can be used to rename to the desired filename.
-# If the file is not needed, it should be explicitly removed.
-#
-# The File#path method of the created file object returns the temporary directory with a trailing slash
-# when +anonymous+ is true.
-#
-# When a block is given, it creates the file as described above, passes it to the block,
-# and returns the block's value.
-# Before the returning, the file object is closed and the underlying file is removed:
+# With a block given, creates the file as above, passes it to the block,
+# and returns the block's value;
+# before the return, the file object is closed and the underlying file is removed:
#
# Tempfile.create {|file| file.path } # => "/tmp/20220505-9795-rkists"
#
-# Implementation note:
-#
-# The keyword argument +anonymous=true+ is implemented using FILE_SHARE_DELETE on Windows.
-# O_TMPFILE is used on Linux.
-#
# Related: Tempfile.new.
#
-def Tempfile.create(basename="", tmpdir=nil, mode: 0, anonymous: false, **options, &block)
- if anonymous
- create_anonymous(basename, tmpdir, mode: mode, **options, &block)
- else
- create_with_filename(basename, tmpdir, mode: mode, **options, &block)
- end
-end
-
-class << Tempfile
-private def create_with_filename(basename="", tmpdir=nil, mode: 0, **options)
+def Tempfile.create(basename="", tmpdir=nil, mode: 0, **options)
tmpfile = nil
Dir::Tmpname.create(basename, tmpdir, **options) do |tmpname, n, opts|
mode |= File::RDWR|File::CREAT|File::EXCL
@@ -592,51 +423,3 @@ private def create_with_filename(basename="", tmpdir=nil, mode: 0, **options)
tmpfile
end
end
-
-File.open(IO::NULL) do |f|
- File.new(f.fileno, autoclose: false, path: "").path
-rescue IOError
- module PathAttr # :nodoc:
- attr_reader :path
-
- def self.set_path(file, path)
- file.extend(self).instance_variable_set(:@path, path)
- end
- end
-end
-
-private def create_anonymous(basename="", tmpdir=nil, mode: 0, **options, &block)
- tmpfile = nil
- tmpdir = Dir.tmpdir() if tmpdir.nil?
- if defined?(File::TMPFILE) # O_TMPFILE since Linux 3.11
- begin
- tmpfile = File.open(tmpdir, File::RDWR | File::TMPFILE, 0600)
- rescue Errno::EISDIR, Errno::ENOENT, Errno::EOPNOTSUPP
- # kernel or the filesystem does not support O_TMPFILE
- # fallback to create-and-unlink
- end
- end
- if tmpfile.nil?
- mode |= File::SHARE_DELETE | File::BINARY # Windows needs them to unlink the opened file.
- tmpfile = create_with_filename(basename, tmpdir, mode: mode, **options)
- File.unlink(tmpfile.path)
- tmppath = tmpfile.path
- end
- path = File.join(tmpdir, '')
- unless tmppath == path
- # clear path.
- tmpfile.autoclose = false
- tmpfile = File.new(tmpfile.fileno, mode: File::RDWR, path: path)
- PathAttr.set_path(tmpfile, path) if defined?(PathAttr)
- end
- if block
- begin
- yield tmpfile
- ensure
- tmpfile.close
- end
- else
- tmpfile
- end
-end
-end
diff --git a/lib/time.gemspec b/lib/time.gemspec
index 4b9f9e1218..bada91a30b 100644
--- a/lib/time.gemspec
+++ b/lib/time.gemspec
@@ -1,31 +1,20 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "time"
+ spec.version = "0.2.2"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
spec.summary = %q{Extends the Time class with methods for parsing and conversion.}
spec.description = %q{Extends the Time class with methods for parsing and conversion.}
spec.homepage = "https://github.com/ruby/time"
- spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
spec.licenses = ["Ruby", "BSD-2-Clause"]
spec.metadata["homepage_uri"] = spec.homepage
spec.metadata["source_code_uri"] = spec.homepage
- srcdir, gemspec = File.split(__FILE__)
- spec.files = Dir.chdir(srcdir) do
- `git ls-files -z`.split("\x0").reject { |f|
- f == gemspec or
- f.start_with?(".git", "bin/", "test/", "rakelib/", "Gemfile", "Rakefile")
- }
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/time.rb b/lib/time.rb
index 10f75b1dda..6a13212a49 100644
--- a/lib/time.rb
+++ b/lib/time.rb
@@ -25,9 +25,6 @@ require 'date'
# :startdoc:
class Time
-
- VERSION = "0.4.0"
-
class << Time
#
@@ -391,8 +388,6 @@ class Time
# heuristic to detect the format of the input string, you provide
# a second argument that describes the format of the string.
#
- # Raises `ArgumentError` if the date or format is invalid.
- #
# If a block is given, the year described in +date+ is converted by the
# block. For example:
#
@@ -457,7 +452,7 @@ class Time
#
def strptime(date, format, now=self.now)
d = Date._strptime(date, format)
- raise ArgumentError, "invalid date or strptime format - '#{date}' '#{format}'" unless d
+ raise ArgumentError, "invalid date or strptime format - `#{date}' `#{format}'" unless d
if seconds = d[:seconds]
if sec_fraction = d[:sec_fraction]
usec = sec_fraction * 1000000
@@ -695,36 +690,35 @@ class Time
getutc.strftime('%a, %d %b %Y %T GMT')
end
- unless method_defined?(:xmlschema)
- #
- # Returns a string which represents the time as a dateTime defined by XML
- # Schema:
- #
- # CCYY-MM-DDThh:mm:ssTZD
- # CCYY-MM-DDThh:mm:ss.sssTZD
- #
- # where TZD is Z or [+-]hh:mm.
- #
- # If self is a UTC time, Z is used as TZD. [+-]hh:mm is used otherwise.
- #
- # +fraction_digits+ specifies a number of digits to use for fractional
- # seconds. Its default value is 0.
- #
- # require 'time'
- #
- # t = Time.now
- # t.iso8601 # => "2011-10-05T22:26:12-04:00"
- #
- # You must require 'time' to use this method.
- #
- def xmlschema(fraction_digits=0)
- fraction_digits = fraction_digits.to_i
- s = strftime("%FT%T")
- if fraction_digits > 0
- s << strftime(".%#{fraction_digits}N")
- end
- s << (utc? ? 'Z' : strftime("%:z"))
+ #
+ # Returns a string which represents the time as a dateTime defined by XML
+ # Schema:
+ #
+ # CCYY-MM-DDThh:mm:ssTZD
+ # CCYY-MM-DDThh:mm:ss.sssTZD
+ #
+ # where TZD is Z or [+-]hh:mm.
+ #
+ # If self is a UTC time, Z is used as TZD. [+-]hh:mm is used otherwise.
+ #
+ # +fraction_digits+ specifies a number of digits to use for fractional
+ # seconds. Its default value is 0.
+ #
+ # require 'time'
+ #
+ # t = Time.now
+ # t.iso8601 # => "2011-10-05T22:26:12-04:00"
+ #
+ # You must require 'time' to use this method.
+ #
+ def xmlschema(fraction_digits=0)
+ fraction_digits = fraction_digits.to_i
+ s = strftime("%FT%T")
+ if fraction_digits > 0
+ s << strftime(".%#{fraction_digits}N")
end
+ s << (utc? ? 'Z' : strftime("%:z"))
end
- alias iso8601 xmlschema unless method_defined?(:iso8601)
+ alias iso8601 xmlschema
end
+
diff --git a/lib/timeout.gemspec b/lib/timeout.gemspec
deleted file mode 100644
index 5449494e07..0000000000
--- a/lib/timeout.gemspec
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{Auto-terminate potentially long-running operations in Ruby.}
- spec.description = %q{Auto-terminate potentially long-running operations in Ruby.}
- spec.homepage = "https://github.com/ruby/timeout"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = spec.homepage
- spec.metadata["changelog_uri"] = spec.homepage + "/releases"
-
- spec.required_ruby_version = '>= 2.6.0'
-
- spec.files = Dir.chdir(__dir__) do
- `git ls-files -z`.split("\x0").reject do |f|
- (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features|rakelib)/|\.(?:git|travis|circleci)|appveyor|Rakefile)})
- end
- end
- spec.require_paths = ["lib"]
-end
diff --git a/lib/timeout.rb b/lib/timeout.rb
index 6448f4f114..7f40bafa4d 100644
--- a/lib/timeout.rb
+++ b/lib/timeout.rb
@@ -4,7 +4,7 @@
# == Synopsis
#
# require 'timeout'
-# status = Timeout.timeout(5) {
+# status = Timeout::timeout(5) {
# # Something that should be interrupted if it takes more than 5 seconds...
# }
#
@@ -13,33 +13,39 @@
# Timeout provides a way to auto-terminate a potentially long-running
# operation if it hasn't finished in a fixed amount of time.
#
+# Previous versions didn't use a module for namespacing, however
+# #timeout is provided for backwards compatibility. You
+# should prefer Timeout.timeout instead.
+#
# == Copyright
#
# Copyright:: (C) 2000 Network Applied Communication Laboratory, Inc.
# Copyright:: (C) 2000 Information-technology Promotion Agency, Japan
module Timeout
- # The version
- VERSION = "0.4.1"
-
- # Internal error raised to when a timeout is triggered.
- class ExitException < Exception
- def exception(*) # :nodoc:
- self
- end
- end
+ VERSION = "0.3.1"
# Raised by Timeout.timeout when the block times out.
class Error < RuntimeError
- def self.handle_timeout(message) # :nodoc:
- exc = ExitException.new(message)
+ attr_reader :thread
- begin
- yield exc
- rescue ExitException => e
- raise new(message) if exc.equal?(e)
- raise
+ def self.catch(*args)
+ exc = new(*args)
+ exc.instance_variable_set(:@thread, Thread.current)
+ exc.instance_variable_set(:@catch_value, exc)
+ ::Kernel.catch(exc) {yield exc}
+ end
+
+ def exception(*)
+ # TODO: use Fiber.current to see if self can be thrown
+ if self.thread == Thread.current
+ bt = caller
+ begin
+ throw(@catch_value, bt)
+ rescue UncaughtThrowError
+ end
end
+ super
end
end
@@ -114,7 +120,7 @@ module Timeout
requests.reject!(&:done?)
end
end
- ThreadGroup::Default.add(watcher) unless watcher.group.enclosed?
+ ThreadGroup::Default.add(watcher)
watcher.name = "Timeout stdlib thread"
watcher.thread_variable_set(:"\0__detached_thread__", true)
watcher
@@ -189,7 +195,8 @@ module Timeout
if klass
perform.call(klass)
else
- Error.handle_timeout(message, &perform)
+ backtrace = Error.catch(&perform)
+ raise Error, message, backtrace
end
end
module_function :timeout
diff --git a/lib/timeout/timeout.gemspec b/lib/timeout/timeout.gemspec
new file mode 100644
index 0000000000..7449ae1980
--- /dev/null
+++ b/lib/timeout/timeout.gemspec
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{Auto-terminate potentially long-running operations in Ruby.}
+ spec.description = %q{Auto-terminate potentially long-running operations in Ruby.}
+ spec.homepage = "https://github.com/ruby/timeout"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
+
+ spec.files = Dir.chdir(__dir__) do
+ `git ls-files -z`.split("\x0").reject do |f|
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features|rakelib)/|\.(?:git|travis|circleci)|appveyor|Rakefile)})
+ end
+ end
+ spec.require_paths = ["lib"]
+end
diff --git a/lib/tmpdir.gemspec b/lib/tmpdir.gemspec
index 4c96e5984b..e42662ea3b 100644
--- a/lib/tmpdir.gemspec
+++ b/lib/tmpdir.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = "tmpdir"
- spec.version = "0.2.0"
+ spec.version = "0.1.3"
spec.authors = ["Yukihiro Matsumoto"]
spec.email = ["matz@ruby-lang.org"]
@@ -15,12 +15,8 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- gemspec = File.basename(__FILE__)
- spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL, exception: false) do |ls|
- ls.readlines("\x0", chomp: true).reject do |f|
- (f == gemspec) ||
- f.start_with?(*%w[bin/ test/ spec/ features/ .git Gemfile])
- end
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/tmpdir.rb b/lib/tmpdir.rb
index 66ac7cfb32..55920a4a74 100644
--- a/lib/tmpdir.rb
+++ b/lib/tmpdir.rb
@@ -13,23 +13,15 @@ end
class Dir
- # Class variables are inaccessible from non-main Ractor.
- # And instance variables too, in Ruby 3.0.
-
- # System-wide temporary directory path
- SYSTMPDIR = (defined?(Etc.systmpdir) ? Etc.systmpdir.freeze : '/tmp')
- private_constant :SYSTMPDIR
+ @@systmpdir ||= defined?(Etc.systmpdir) ? Etc.systmpdir : '/tmp'
##
# Returns the operating system's temporary file path.
- #
- # require 'tmpdir'
- # Dir.tmpdir # => "/tmp"
def self.tmpdir
- ['TMPDIR', 'TMP', 'TEMP', ['system temporary path', SYSTMPDIR], ['/tmp']*2, ['.']*2].find do |name, dir|
+ ['TMPDIR', 'TMP', 'TEMP', ['system temporary path', @@systmpdir], ['/tmp']*2, ['.']*2].find do |name, dir|
unless dir
- next if !(dir = ENV[name] rescue next) or dir.empty?
+ next if !(dir = ENV[name]) or dir.empty?
end
dir = File.expand_path(dir)
stat = File.stat(dir) rescue next
@@ -48,11 +40,6 @@ class Dir
# Dir.mktmpdir creates a temporary directory.
#
- # require 'tmpdir'
- # Dir.mktmpdir {|dir|
- # # use the directory
- # }
- #
# The directory is created with 0700 permission.
# Application should not change the permission to make the temporary directory accessible from other users.
#
@@ -107,10 +94,9 @@ class Dir
yield path.dup
ensure
unless base
- base = File.dirname(path)
- stat = File.stat(base)
+ stat = File.stat(File.dirname(path))
if stat.world_writable? and !stat.sticky?
- raise ArgumentError, "parent directory is world writable but not sticky: #{base}"
+ raise ArgumentError, "parent directory is world writable but not sticky"
end
end
FileUtils.remove_entry path
@@ -132,27 +118,22 @@ class Dir
UNUSABLE_CHARS = "^,-.0-9A-Z_a-z~"
# Dedicated random number generator
- RANDOM = Object.new
+ RANDOM = Random.new
class << RANDOM # :nodoc:
# Maximum random number
MAX = 36**6 # < 0x100000000
# Returns new random string upto 6 bytes
def next
- (::Random.urandom(4).unpack1("L")%MAX).to_s(36)
+ rand(MAX).to_s(36)
end
end
- RANDOM.freeze
private_constant :RANDOM
# Generates and yields random names to create a temporary name
def create(basename, tmpdir=nil, max_try: nil, **opts)
origdir = tmpdir
- if tmpdir
- raise ArgumentError, "empty parent path" if tmpdir.empty?
- else
- tmpdir = tmpdir()
- end
+ tmpdir ||= tmpdir()
n = nil
prefix, suffix = basename
prefix = (String.try_convert(prefix) or
@@ -171,7 +152,7 @@ class Dir
n ||= 0
n += 1
retry if !max_try or n < max_try
- raise "cannot generate temporary name using '#{basename}' under '#{tmpdir}'"
+ raise "cannot generate temporary name using `#{basename}' under `#{tmpdir}'"
end
path
end
diff --git a/lib/tsort.gemspec b/lib/tsort.gemspec
index 0e2f110a53..a82393b70b 100644
--- a/lib/tsort.gemspec
+++ b/lib/tsort.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "tsort"
+ spec.version = "0.1.1"
spec.authors = ["Tanaka Akira"]
spec.email = ["akr@fsij.org"]
diff --git a/lib/tsort.rb b/lib/tsort.rb
index dbaed45415..00ee609d64 100644
--- a/lib/tsort.rb
+++ b/lib/tsort.rb
@@ -122,9 +122,6 @@
#
module TSort
-
- VERSION = "0.2.0"
-
class Cyclic < StandardError
end
diff --git a/lib/un.gemspec b/lib/un.gemspec
index 2ed49511cc..1a466fdebe 100644
--- a/lib/un.gemspec
+++ b/lib/un.gemspec
@@ -1,15 +1,8 @@
# frozen_string_literal: true
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1).join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "un"
+ spec.version = "0.2.1"
spec.authors = ["WATANABE Hirofumi"]
spec.email = ["eban@ruby-lang.org"]
diff --git a/lib/un.rb b/lib/un.rb
index 8fb3c61a93..796b36fbab 100644
--- a/lib/un.rb
+++ b/lib/un.rb
@@ -30,6 +30,7 @@ require "fileutils"
require "optparse"
module FileUtils
+# @fileutils_label = ""
@fileutils_output = $stdout
end
@@ -411,9 +412,6 @@ def help
end
module UN # :nodoc:
-
- VERSION = "0.3.0"
-
module_function
def help(argv, output: $stdout)
all = argv.empty?
diff --git a/lib/uri.rb b/lib/uri.rb
index dfdb052a79..59a7c4ad28 100644
--- a/lib/uri.rb
+++ b/lib/uri.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: false
# URI is a module providing classes to handle Uniform Resource Identifiers
-# (RFC2396[https://www.rfc-editor.org/rfc/rfc2396]).
+# (RFC2396[http://tools.ietf.org/html/rfc2396]).
#
# == Features
#
@@ -47,14 +47,14 @@
# A good place to view an RFC spec is http://www.ietf.org/rfc.html.
#
# Here is a list of all related RFC's:
-# - RFC822[https://www.rfc-editor.org/rfc/rfc822]
-# - RFC1738[https://www.rfc-editor.org/rfc/rfc1738]
-# - RFC2255[https://www.rfc-editor.org/rfc/rfc2255]
-# - RFC2368[https://www.rfc-editor.org/rfc/rfc2368]
-# - RFC2373[https://www.rfc-editor.org/rfc/rfc2373]
-# - RFC2396[https://www.rfc-editor.org/rfc/rfc2396]
-# - RFC2732[https://www.rfc-editor.org/rfc/rfc2732]
-# - RFC3986[https://www.rfc-editor.org/rfc/rfc3986]
+# - RFC822[http://tools.ietf.org/html/rfc822]
+# - RFC1738[http://tools.ietf.org/html/rfc1738]
+# - RFC2255[http://tools.ietf.org/html/rfc2255]
+# - RFC2368[http://tools.ietf.org/html/rfc2368]
+# - RFC2373[http://tools.ietf.org/html/rfc2373]
+# - RFC2396[http://tools.ietf.org/html/rfc2396]
+# - RFC2732[http://tools.ietf.org/html/rfc2732]
+# - RFC3986[http://tools.ietf.org/html/rfc3986]
#
# == Class tree
#
diff --git a/lib/uri/common.rb b/lib/uri/common.rb
index 904df10663..0c4064a67a 100644
--- a/lib/uri/common.rb
+++ b/lib/uri/common.rb
@@ -13,46 +13,26 @@ require_relative "rfc2396_parser"
require_relative "rfc3986_parser"
module URI
- RFC2396_PARSER = RFC2396_Parser.new
- Ractor.make_shareable(RFC2396_PARSER) if defined?(Ractor)
+ include RFC2396_REGEXP
+ REGEXP = RFC2396_REGEXP
+ Parser = RFC2396_Parser
RFC3986_PARSER = RFC3986_Parser.new
Ractor.make_shareable(RFC3986_PARSER) if defined?(Ractor)
+ RFC2396_PARSER = RFC2396_Parser.new
+ Ractor.make_shareable(RFC2396_PARSER) if defined?(Ractor)
- DEFAULT_PARSER = RFC3986_PARSER
- Ractor.make_shareable(DEFAULT_PARSER) if defined?(Ractor)
-
- def self.parser=(parser = RFC3986_PARSER)
- remove_const(:Parser) if defined?(::URI::Parser)
- const_set("Parser", parser.class)
-
- remove_const(:REGEXP) if defined?(::URI::REGEXP)
- remove_const(:PATTERN) if defined?(::URI::PATTERN)
- if Parser == RFC2396_Parser
- const_set("REGEXP", URI::RFC2396_REGEXP)
- const_set("PATTERN", URI::RFC2396_REGEXP::PATTERN)
- Parser.new.pattern.each_pair do |sym, str|
- unless REGEXP::PATTERN.const_defined?(sym)
- REGEXP::PATTERN.const_set(sym, str)
- end
- end
- end
-
- Parser.new.regexp.each_pair do |sym, str|
- remove_const(sym) if const_defined?(sym)
- const_set(sym, str)
+ # URI::Parser.new
+ DEFAULT_PARSER = Parser.new
+ DEFAULT_PARSER.pattern.each_pair do |sym, str|
+ unless REGEXP::PATTERN.const_defined?(sym)
+ REGEXP::PATTERN.const_set(sym, str)
end
end
- self.parser = RFC3986_PARSER
-
- def self.const_missing(const)
- if value = RFC2396_PARSER.regexp[const]
- warn "URI::#{const} is obsolete. Use RFC2396_PARSER.regexp[#{const.inspect}] explicitly.", uplevel: 1 if $VERBOSE
- value
- else
- super
- end
+ DEFAULT_PARSER.regexp.each_pair do |sym, str|
+ const_set(sym, str)
end
+ Ractor.make_shareable(DEFAULT_PARSER) if defined?(Ractor)
module Util # :nodoc:
def make_components_hash(klass, array_hash)
@@ -90,32 +70,16 @@ module URI
end
private_constant :Schemes
- # Registers the given +klass+ as the class to be instantiated
- # when parsing a \URI with the given +scheme+:
#
- # URI.register_scheme('MS_SEARCH', URI::Generic) # => URI::Generic
- # URI.scheme_list['MS_SEARCH'] # => URI::Generic
+ # Register the given +klass+ to be instantiated when parsing URLs with the given +scheme+.
+ # Note that currently only schemes which after .upcase are valid constant names
+ # can be registered (no -/+/. allowed).
#
- # Note that after calling String#upcase on +scheme+, it must be a valid
- # constant name.
def self.register_scheme(scheme, klass)
Schemes.const_set(scheme.to_s.upcase, klass)
end
- # Returns a hash of the defined schemes:
- #
- # URI.scheme_list
- # # =>
- # {"MAILTO"=>URI::MailTo,
- # "LDAPS"=>URI::LDAPS,
- # "WS"=>URI::WS,
- # "HTTP"=>URI::HTTP,
- # "HTTPS"=>URI::HTTPS,
- # "LDAP"=>URI::LDAP,
- # "FILE"=>URI::File,
- # "FTP"=>URI::FTP}
- #
- # Related: URI.register_scheme.
+ # Returns a Hash of the defined schemes.
def self.scheme_list
Schemes.constants.map { |name|
[name.to_s.upcase, Schemes.const_get(name)]
@@ -126,21 +90,9 @@ module URI
private_constant :INITIAL_SCHEMES
Ractor.make_shareable(INITIAL_SCHEMES) if defined?(Ractor)
- # Returns a new object constructed from the given +scheme+, +arguments+,
- # and +default+:
- #
- # - The new object is an instance of <tt>URI.scheme_list[scheme.upcase]</tt>.
- # - The object is initialized by calling the class initializer
- # using +scheme+ and +arguments+.
- # See URI::Generic.new.
#
- # Examples:
- #
- # values = ['john.doe', 'www.example.com', '123', nil, '/forum/questions/', nil, 'tag=networking&order=newest', 'top']
- # URI.for('https', *values)
- # # => #<URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- # URI.for('foo', *values, default: URI::HTTP)
- # # => #<URI::HTTP foo://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
+ # Construct a URI instance, using the scheme to detect the appropriate class
+ # from +URI.scheme_list+.
#
def self.for(scheme, *arguments, default: Generic)
const_name = scheme.to_s.upcase
@@ -171,49 +123,95 @@ module URI
#
class BadURIError < Error; end
- # Returns a 9-element array representing the parts of the \URI
- # formed from the string +uri+;
- # each array element is a string or +nil+:
- #
- # names = %w[scheme userinfo host port registry path opaque query fragment]
- # values = URI.split('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # names.zip(values)
- # # =>
- # [["scheme", "https"],
- # ["userinfo", "john.doe"],
- # ["host", "www.example.com"],
- # ["port", "123"],
- # ["registry", nil],
- # ["path", "/forum/questions/"],
- # ["opaque", nil],
- # ["query", "tag=networking&order=newest"],
- # ["fragment", "top"]]
+ #
+ # == Synopsis
+ #
+ # URI::split(uri)
+ #
+ # == Args
+ #
+ # +uri+::
+ # String with URI.
+ #
+ # == Description
+ #
+ # Splits the string on following parts and returns array with result:
+ #
+ # * Scheme
+ # * Userinfo
+ # * Host
+ # * Port
+ # * Registry
+ # * Path
+ # * Opaque
+ # * Query
+ # * Fragment
+ #
+ # == Usage
+ #
+ # require 'uri'
+ #
+ # URI.split("http://www.ruby-lang.org/")
+ # # => ["http", nil, "www.ruby-lang.org", nil, nil, "/", nil, nil, nil]
#
def self.split(uri)
- DEFAULT_PARSER.split(uri)
+ RFC3986_PARSER.split(uri)
end
- # Returns a new \URI object constructed from the given string +uri+:
#
- # URI.parse('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # # => #<URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
- # URI.parse('http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
- # # => #<URI::HTTP http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
+ # == Synopsis
+ #
+ # URI::parse(uri_str)
+ #
+ # == Args
+ #
+ # +uri_str+::
+ # String with URI.
+ #
+ # == Description
+ #
+ # Creates one of the URI's subclasses instance from the string.
+ #
+ # == Raises
+ #
+ # URI::InvalidURIError::
+ # Raised if URI given is not a correct one.
#
- # It's recommended to first ::escape string +uri+
- # if it may contain invalid URI characters.
+ # == Usage
+ #
+ # require 'uri'
+ #
+ # uri = URI.parse("http://www.ruby-lang.org/")
+ # # => #<URI::HTTP http://www.ruby-lang.org/>
+ # uri.scheme
+ # # => "http"
+ # uri.host
+ # # => "www.ruby-lang.org"
+ #
+ # It's recommended to first ::escape the provided +uri_str+ if there are any
+ # invalid URI characters.
#
def self.parse(uri)
- DEFAULT_PARSER.parse(uri)
+ RFC3986_PARSER.parse(uri)
end
- # Merges the given URI strings +str+
- # per {RFC 2396}[https://www.rfc-editor.org/rfc/rfc2396.html].
#
- # Each string in +str+ is converted to an
- # {RFC3986 URI}[https://www.rfc-editor.org/rfc/rfc3986.html] before being merged.
+ # == Synopsis
+ #
+ # URI::join(str[, str, ...])
+ #
+ # == Args
+ #
+ # +str+::
+ # String(s) to work with, will be converted to RFC3986 URIs before merging.
+ #
+ # == Description
+ #
+ # Joins URIs.
#
- # Examples:
+ # == Usage
+ #
+ # require 'uri'
#
# URI.join("http://example.com/","main.rbx")
# # => #<URI::HTTP http://example.com/main.rbx>
@@ -231,7 +229,7 @@ module URI
# # => #<URI::HTTP http://example.com/foo/bar>
#
def self.join(*str)
- DEFAULT_PARSER.join(*str)
+ RFC3986_PARSER.join(*str)
end
#
@@ -258,7 +256,7 @@ module URI
# URI.extract("text here http://foo.example.org/bla and here mailto:test@example.com and here also.")
# # => ["http://foo.example.com/bla", "mailto:test@example.com"]
#
- def self.extract(str, schemes = nil, &block) # :nodoc:
+ def self.extract(str, schemes = nil, &block)
warn "URI.extract is obsolete", uplevel: 1 if $VERBOSE
DEFAULT_PARSER.extract(str, schemes, &block)
end
@@ -295,7 +293,7 @@ module URI
# p $&
# end
#
- def self.regexp(schemes = nil)# :nodoc:
+ def self.regexp(schemes = nil)
warn "URI.regexp is obsolete", uplevel: 1 if $VERBOSE
DEFAULT_PARSER.make_regexp(schemes)
end
@@ -318,86 +316,40 @@ module URI
TBLDECWWWCOMP_['+'] = ' '
TBLDECWWWCOMP_.freeze
- # Returns a URL-encoded string derived from the given string +str+.
- #
- # The returned string:
- #
- # - Preserves:
- #
- # - Characters <tt>'*'</tt>, <tt>'.'</tt>, <tt>'-'</tt>, and <tt>'_'</tt>.
- # - Character in ranges <tt>'a'..'z'</tt>, <tt>'A'..'Z'</tt>,
- # and <tt>'0'..'9'</tt>.
- #
- # Example:
- #
- # URI.encode_www_form_component('*.-_azAZ09')
- # # => "*.-_azAZ09"
+ # Encodes given +str+ to URL-encoded form data.
#
- # - Converts:
+ # This method doesn't convert *, -, ., 0-9, A-Z, _, a-z, but does convert SP
+ # (ASCII space) to + and converts others to %XX.
#
- # - Character <tt>' '</tt> to character <tt>'+'</tt>.
- # - Any other character to "percent notation";
- # the percent notation for character <i>c</i> is <tt>'%%%X' % c.ord</tt>.
+ # If +enc+ is given, convert +str+ to the encoding before percent encoding.
#
- # Example:
+ # This is an implementation of
+ # https://www.w3.org/TR/2013/CR-html5-20130806/forms.html#url-encoded-form-data.
#
- # URI.encode_www_form_component('Here are some punctuation characters: ,;?:')
- # # => "Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A"
- #
- # Encoding:
- #
- # - If +str+ has encoding Encoding::ASCII_8BIT, argument +enc+ is ignored.
- # - Otherwise +str+ is converted first to Encoding::UTF_8
- # (with suitable character replacements),
- # and then to encoding +enc+.
- #
- # In either case, the returned string has forced encoding Encoding::US_ASCII.
- #
- # Related: URI.encode_uri_component (encodes <tt>' '</tt> as <tt>'%20'</tt>).
+ # See URI.decode_www_form_component, URI.encode_www_form.
def self.encode_www_form_component(str, enc=nil)
_encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_, str, enc)
end
- # Returns a string decoded from the given \URL-encoded string +str+.
- #
- # The given string is first encoded as Encoding::ASCII-8BIT (using String#b),
- # then decoded (as below), and finally force-encoded to the given encoding +enc+.
- #
- # The returned string:
- #
- # - Preserves:
+ # Decodes given +str+ of URL-encoded form data.
#
- # - Characters <tt>'*'</tt>, <tt>'.'</tt>, <tt>'-'</tt>, and <tt>'_'</tt>.
- # - Character in ranges <tt>'a'..'z'</tt>, <tt>'A'..'Z'</tt>,
- # and <tt>'0'..'9'</tt>.
+ # This decodes + to SP.
#
- # Example:
- #
- # URI.decode_www_form_component('*.-_azAZ09')
- # # => "*.-_azAZ09"
- #
- # - Converts:
- #
- # - Character <tt>'+'</tt> to character <tt>' '</tt>.
- # - Each "percent notation" to an ASCII character.
- #
- # Example:
- #
- # URI.decode_www_form_component('Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A')
- # # => "Here are some punctuation characters: ,;?:"
- #
- # Related: URI.decode_uri_component (preserves <tt>'+'</tt>).
+ # See URI.encode_www_form_component, URI.decode_www_form.
def self.decode_www_form_component(str, enc=Encoding::UTF_8)
_decode_uri_component(/\+|%\h\h/, str, enc)
end
- # Like URI.encode_www_form_component, except that <tt>' '</tt> (space)
- # is encoded as <tt>'%20'</tt> (instead of <tt>'+'</tt>).
+ # Encodes +str+ using URL encoding
+ #
+ # This encodes SP to %20 instead of +.
def self.encode_uri_component(str, enc=nil)
_encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCURICOMP_, str, enc)
end
- # Like URI.decode_www_form_component, except that <tt>'+'</tt> is preserved.
+ # Decodes given +str+ of URL-encoded data.
+ #
+ # This does not decode + to SP.
def self.decode_uri_component(str, enc=Encoding::UTF_8)
_decode_uri_component(/%\h\h/, str, enc)
end
@@ -422,104 +374,33 @@ module URI
end
private_class_method :_decode_uri_component
- # Returns a URL-encoded string derived from the given
- # {Enumerable}[rdoc-ref:Enumerable@Enumerable+in+Ruby+Classes]
- # +enum+.
- #
- # The result is suitable for use as form data
- # for an \HTTP request whose <tt>Content-Type</tt> is
- # <tt>'application/x-www-form-urlencoded'</tt>.
- #
- # The returned string consists of the elements of +enum+,
- # each converted to one or more URL-encoded strings,
- # and all joined with character <tt>'&'</tt>.
- #
- # Simple examples:
- #
- # URI.encode_www_form([['foo', 0], ['bar', 1], ['baz', 2]])
- # # => "foo=0&bar=1&baz=2"
- # URI.encode_www_form({foo: 0, bar: 1, baz: 2})
- # # => "foo=0&bar=1&baz=2"
- #
- # The returned string is formed using method URI.encode_www_form_component,
- # which converts certain characters:
- #
- # URI.encode_www_form('f#o': '/', 'b-r': '$', 'b z': '@')
- # # => "f%23o=%2F&b-r=%24&b+z=%40"
+ # Generates URL-encoded form data from given +enum+.
#
- # When +enum+ is Array-like, each element +ele+ is converted to a field:
+ # This generates application/x-www-form-urlencoded data defined in HTML5
+ # from given an Enumerable object.
#
- # - If +ele+ is an array of two or more elements,
- # the field is formed from its first two elements
- # (and any additional elements are ignored):
+ # This internally uses URI.encode_www_form_component(str).
#
- # name = URI.encode_www_form_component(ele[0], enc)
- # value = URI.encode_www_form_component(ele[1], enc)
- # "#{name}=#{value}"
+ # This method doesn't convert the encoding of given items, so convert them
+ # before calling this method if you want to send data as other than original
+ # encoding or mixed encoding data. (Strings which are encoded in an HTML5
+ # ASCII incompatible encoding are converted to UTF-8.)
#
- # Examples:
+ # This method doesn't handle files. When you send a file, use
+ # multipart/form-data.
#
- # URI.encode_www_form([%w[foo bar], %w[baz bat bah]])
- # # => "foo=bar&baz=bat"
- # URI.encode_www_form([['foo', 0], ['bar', :baz, 'bat']])
- # # => "foo=0&bar=baz"
+ # This refers https://url.spec.whatwg.org/#concept-urlencoded-serializer
#
- # - If +ele+ is an array of one element,
- # the field is formed from <tt>ele[0]</tt>:
- #
- # URI.encode_www_form_component(ele[0])
- #
- # Example:
- #
- # URI.encode_www_form([['foo'], [:bar], [0]])
- # # => "foo&bar&0"
- #
- # - Otherwise the field is formed from +ele+:
- #
- # URI.encode_www_form_component(ele)
- #
- # Example:
- #
- # URI.encode_www_form(['foo', :bar, 0])
- # # => "foo&bar&0"
- #
- # The elements of an Array-like +enum+ may be mixture:
- #
- # URI.encode_www_form([['foo', 0], ['bar', 1, 2], ['baz'], :bat])
- # # => "foo=0&bar=1&baz&bat"
- #
- # When +enum+ is Hash-like,
- # each +key+/+value+ pair is converted to one or more fields:
- #
- # - If +value+ is
- # {Array-convertible}[rdoc-ref:implicit_conversion.rdoc@Array-Convertible+Objects],
- # each element +ele+ in +value+ is paired with +key+ to form a field:
- #
- # name = URI.encode_www_form_component(key, enc)
- # value = URI.encode_www_form_component(ele, enc)
- # "#{name}=#{value}"
- #
- # Example:
- #
- # URI.encode_www_form({foo: [:bar, 1], baz: [:bat, :bam, 2]})
- # # => "foo=bar&foo=1&baz=bat&baz=bam&baz=2"
- #
- # - Otherwise, +key+ and +value+ are paired to form a field:
- #
- # name = URI.encode_www_form_component(key, enc)
- # value = URI.encode_www_form_component(value, enc)
- # "#{name}=#{value}"
- #
- # Example:
- #
- # URI.encode_www_form({foo: 0, bar: 1, baz: 2})
- # # => "foo=0&bar=1&baz=2"
- #
- # The elements of a Hash-like +enum+ may be mixture:
- #
- # URI.encode_www_form({foo: [0, 1], bar: 2})
- # # => "foo=0&foo=1&bar=2"
+ # URI.encode_www_form([["q", "ruby"], ["lang", "en"]])
+ # #=> "q=ruby&lang=en"
+ # URI.encode_www_form("q" => "ruby", "lang" => "en")
+ # #=> "q=ruby&lang=en"
+ # URI.encode_www_form("q" => ["ruby", "perl"], "lang" => "en")
+ # #=> "q=ruby&q=perl&lang=en"
+ # URI.encode_www_form([["q", "ruby"], ["q", "perl"], ["lang", "en"]])
+ # #=> "q=ruby&q=perl&lang=en"
#
+ # See URI.encode_www_form_component, URI.decode_www_form.
def self.encode_www_form(enum, enc=nil)
enum.map do |k,v|
if v.nil?
@@ -540,39 +421,22 @@ module URI
end.join('&')
end
- # Returns name/value pairs derived from the given string +str+,
- # which must be an ASCII string.
- #
- # The method may be used to decode the body of Net::HTTPResponse object +res+
- # for which <tt>res['Content-Type']</tt> is <tt>'application/x-www-form-urlencoded'</tt>.
+ # Decodes URL-encoded form data from given +str+.
#
- # The returned data is an array of 2-element subarrays;
- # each subarray is a name/value pair (both are strings).
- # Each returned string has encoding +enc+,
- # and has had invalid characters removed via
- # {String#scrub}[rdoc-ref:String#scrub].
+ # This decodes application/x-www-form-urlencoded data
+ # and returns an array of key-value arrays.
#
- # A simple example:
+ # This refers http://url.spec.whatwg.org/#concept-urlencoded-parser,
+ # so this supports only &-separator, and doesn't support ;-separator.
#
- # URI.decode_www_form('foo=0&bar=1&baz')
- # # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
- #
- # The returned strings have certain conversions,
- # similar to those performed in URI.decode_www_form_component:
- #
- # URI.decode_www_form('f%23o=%2F&b-r=%24&b+z=%40')
- # # => [["f#o", "/"], ["b-r", "$"], ["b z", "@"]]
- #
- # The given string may contain consecutive separators:
- #
- # URI.decode_www_form('foo=0&&bar=1&&baz=2')
- # # => [["foo", "0"], ["", ""], ["bar", "1"], ["", ""], ["baz", "2"]]
- #
- # A different separator may be specified:
- #
- # URI.decode_www_form('foo=0--bar=1--baz', separator: '--')
- # # => [["foo", "0"], ["bar", "1"], ["baz", ""]]
+ # ary = URI.decode_www_form("a=1&a=2&b=3")
+ # ary #=> [['a', '1'], ['a', '2'], ['b', '3']]
+ # ary.assoc('a').last #=> '1'
+ # ary.assoc('b').last #=> '3'
+ # ary.rassoc('a').last #=> '2'
+ # Hash[ary] #=> {"a"=>"2", "b"=>"3"}
#
+ # See URI.decode_www_form_component, URI.encode_www_form.
def self.decode_www_form(str, enc=Encoding::UTF_8, separator: '&', use__charset_: false, isindex: false)
raise ArgumentError, "the input of #{self.name}.#{__method__} must be ASCII only string" unless str.ascii_only?
ary = []
@@ -851,15 +715,7 @@ end # module URI
module Kernel
#
- # Returns a \URI object derived from the given +uri+,
- # which may be a \URI string or an existing \URI object:
- #
- # # Returns a new URI.
- # uri = URI('http://github.com/ruby/ruby')
- # # => #<URI::HTTP http://github.com/ruby/ruby>
- # # Returns the given URI.
- # URI(uri)
- # # => #<URI::HTTP http://github.com/ruby/ruby>
+ # Returns +uri+ converted to an URI object.
#
def URI(uri)
if uri.is_a?(URI::Generic)
diff --git a/lib/uri/file.rb b/lib/uri/file.rb
index 940d361af8..4ff0bc097e 100644
--- a/lib/uri/file.rb
+++ b/lib/uri/file.rb
@@ -70,17 +70,17 @@ module URI
# raise InvalidURIError
def check_userinfo(user)
- raise URI::InvalidURIError, "cannot set userinfo for file URI"
+ raise URI::InvalidURIError, "can not set userinfo for file URI"
end
# raise InvalidURIError
def check_user(user)
- raise URI::InvalidURIError, "cannot set user for file URI"
+ raise URI::InvalidURIError, "can not set user for file URI"
end
# raise InvalidURIError
def check_password(user)
- raise URI::InvalidURIError, "cannot set password for file URI"
+ raise URI::InvalidURIError, "can not set password for file URI"
end
# do nothing
diff --git a/lib/uri/ftp.rb b/lib/uri/ftp.rb
index 1c75e242ba..abad613c33 100644
--- a/lib/uri/ftp.rb
+++ b/lib/uri/ftp.rb
@@ -17,7 +17,7 @@ module URI
# This class will be redesigned because of difference of implementations;
# the structure of its path. draft-hoffman-ftp-uri-04 is a draft but it
# is a good summary about the de facto spec.
- # https://datatracker.ietf.org/doc/html/draft-hoffman-ftp-uri-04
+ # http://tools.ietf.org/html/draft-hoffman-ftp-uri-04
#
class FTP < Generic
# A Default port of 21 for URI::FTP.
diff --git a/lib/uri/generic.rb b/lib/uri/generic.rb
index d4bfa3b919..f7eed57924 100644
--- a/lib/uri/generic.rb
+++ b/lib/uri/generic.rb
@@ -82,7 +82,7 @@ module URI
if args.kind_of?(Array)
return self.build(args.collect{|x|
if x.is_a?(String)
- URI::RFC2396_PARSER.escape(x)
+ DEFAULT_PARSER.escape(x)
else
x
end
@@ -91,7 +91,7 @@ module URI
tmp = {}
args.each do |key, value|
tmp[key] = if value
- URI::RFC2396_PARSER.escape(value)
+ DEFAULT_PARSER.escape(value)
else
value
end
@@ -393,7 +393,7 @@ module URI
def check_user(v)
if @opaque
raise InvalidURIError,
- "cannot set user with opaque"
+ "can not set user with opaque"
end
return v unless v
@@ -417,7 +417,7 @@ module URI
def check_password(v, user = @user)
if @opaque
raise InvalidURIError,
- "cannot set password with opaque"
+ "can not set password with opaque"
end
return v unless v
@@ -596,7 +596,7 @@ module URI
if @opaque
raise InvalidURIError,
- "cannot set host with registry or opaque"
+ "can not set host with registry or opaque"
elsif parser.regexp[:HOST] !~ v
raise InvalidComponentError,
"bad component(expected host component): #{v}"
@@ -685,7 +685,7 @@ module URI
if @opaque
raise InvalidURIError,
- "cannot set port with registry or opaque"
+ "can not set port with registry or opaque"
elsif !v.kind_of?(Integer) && parser.regexp[:PORT] !~ v
raise InvalidComponentError,
"bad component(expected port component): #{v.inspect}"
@@ -733,17 +733,17 @@ module URI
end
def check_registry(v) # :nodoc:
- raise InvalidURIError, "cannot set registry"
+ raise InvalidURIError, "can not set registry"
end
private :check_registry
def set_registry(v) #:nodoc:
- raise InvalidURIError, "cannot set registry"
+ raise InvalidURIError, "can not set registry"
end
protected :set_registry
def registry=(v)
- raise InvalidURIError, "cannot set registry"
+ raise InvalidURIError, "can not set registry"
end
#
@@ -866,7 +866,7 @@ module URI
# hier_part = ( net_path | abs_path ) [ "?" query ]
if @host || @port || @user || @path # userinfo = @user + ':' + @password
raise InvalidURIError,
- "cannot set opaque with host, port, userinfo or path"
+ "can not set opaque with host, port, userinfo or path"
elsif v && parser.regexp[:OPAQUE] !~ v
raise InvalidComponentError,
"bad component(expected opaque component): #{v}"
@@ -945,7 +945,7 @@ module URI
# == Description
#
# URI has components listed in order of decreasing significance from left to right,
- # see RFC3986 https://www.rfc-editor.org/rfc/rfc3986 1.2.3.
+ # see RFC3986 https://tools.ietf.org/html/rfc3986 1.2.3.
#
# == Usage
#
@@ -1133,17 +1133,16 @@ module URI
base.fragment=(nil)
# RFC2396, Section 5.2, 4)
- if !authority
- base.set_path(merge_path(base.path, rel.path)) if base.path && rel.path
- else
- # RFC2396, Section 5.2, 4)
- base.set_path(rel.path) if rel.path
+ if authority
+ base.set_userinfo(rel.userinfo)
+ base.set_host(rel.host)
+ base.set_port(rel.port || base.default_port)
+ base.set_path(rel.path)
+ elsif base.path && rel.path
+ base.set_path(merge_path(base.path, rel.path))
end
# RFC2396, Section 5.2, 7)
- base.set_userinfo(rel.userinfo) if rel.userinfo
- base.set_host(rel.host) if rel.host
- base.set_port(rel.port) if rel.port
base.query = rel.query if rel.query
base.fragment=(rel.fragment) if rel.fragment
@@ -1235,7 +1234,7 @@ module URI
return rel, rel
end
- # you can modify `rel', but cannot `oth'.
+ # you can modify `rel', but can not `oth'.
return oth, rel
end
private :route_from0
@@ -1260,7 +1259,7 @@ module URI
# #=> #<URI::Generic /main.rbx?page=1>
#
def route_from(oth)
- # you can modify `rel', but cannot `oth'.
+ # you can modify `rel', but can not `oth'.
begin
oth, rel = route_from0(oth)
rescue
@@ -1364,9 +1363,6 @@ module URI
str << ':'
str << @port.to_s
end
- if (@host || @port) && !@path.empty? && !@path.start_with?('/')
- str << '/'
- end
str << @path
if @query
str << '?'
@@ -1379,7 +1375,6 @@ module URI
end
str
end
- alias to_str to_s
#
# Compares two URIs.
@@ -1402,6 +1397,19 @@ module URI
self.component_ary.eql?(oth.component_ary)
end
+=begin
+
+--- URI::Generic#===(oth)
+
+=end
+# def ===(oth)
+# raise NotImplementedError
+# end
+
+=begin
+=end
+
+
# Returns an Array of the components defined from the COMPONENT Array.
def component_ary
component.collect do |x|
diff --git a/lib/uri/http.rb b/lib/uri/http.rb
index 900b132c8c..306daf1965 100644
--- a/lib/uri/http.rb
+++ b/lib/uri/http.rb
@@ -85,7 +85,7 @@ module URI
# == Description
#
# Returns the authority for an HTTP uri, as defined in
- # https://www.rfc-editor.org/rfc/rfc3986#section-3.2.
+ # https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.
#
#
# Example:
@@ -106,7 +106,7 @@ module URI
# == Description
#
# Returns the origin for an HTTP uri, as defined in
- # https://www.rfc-editor.org/rfc/rfc6454.
+ # https://datatracker.ietf.org/doc/html/rfc6454.
#
#
# Example:
diff --git a/lib/uri/rfc2396_parser.rb b/lib/uri/rfc2396_parser.rb
index a56ca34267..00c66cf042 100644
--- a/lib/uri/rfc2396_parser.rb
+++ b/lib/uri/rfc2396_parser.rb
@@ -140,11 +140,11 @@ module URI
if !scheme
raise InvalidURIError,
- "bad URI (absolute but no scheme): #{uri}"
+ "bad URI(absolute but no scheme): #{uri}"
end
if !opaque && (!path && (!host && !registry))
raise InvalidURIError,
- "bad URI (absolute but no path): #{uri}"
+ "bad URI(absolute but no path): #{uri}"
end
when @regexp[:REL_URI]
@@ -173,7 +173,7 @@ module URI
# server = [ [ userinfo "@" ] hostport ]
else
- raise InvalidURIError, "bad URI (is not URI?): #{uri}"
+ raise InvalidURIError, "bad URI(is not URI?): #{uri}"
end
path = '' if !path && !opaque # (see RFC2396 Section 5.2)
diff --git a/lib/uri/rfc3986_parser.rb b/lib/uri/rfc3986_parser.rb
index 4000f1357f..9b1663dbb6 100644
--- a/lib/uri/rfc3986_parser.rb
+++ b/lib/uri/rfc3986_parser.rb
@@ -1,73 +1,9 @@
-# frozen_string_literal: true
+# frozen_string_literal: false
module URI
class RFC3986_Parser # :nodoc:
# URI defined in RFC3986
- HOST = %r[
- (?<IP-literal>\[(?:
- (?<IPv6address>
- (?:\h{1,4}:){6}
- (?<ls32>\h{1,4}:\h{1,4}
- | (?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)
- \.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>)
- )
- | ::(?:\h{1,4}:){5}\g<ls32>
- | \h{1,4}?::(?:\h{1,4}:){4}\g<ls32>
- | (?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>
- | (?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>
- | (?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>
- | (?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>
- | (?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}
- | (?:(?:\h{1,4}:){,6}\h{1,4})?::
- )
- | (?<IPvFuture>v\h++\.[!$&-.0-9:;=A-Z_a-z~]++)
- )\])
- | \g<IPv4address>
- | (?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*+)
- ]x
-
- USERINFO = /(?:%\h\h|[!$&-.0-9:;=A-Z_a-z~])*+/
-
- SCHEME = %r[[A-Za-z][+\-.0-9A-Za-z]*+].source
- SEG = %r[(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/])].source
- SEG_NC = %r[(?:%\h\h|[!$&-.0-9;=@A-Z_a-z~])].source
- FRAGMENT = %r[(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/?])*+].source
-
- RFC3986_URI = %r[\A
- (?<seg>#{SEG}){0}
- (?<URI>
- (?<scheme>#{SCHEME}):
- (?<hier-part>//
- (?<authority>
- (?:(?<userinfo>#{USERINFO.source})@)?
- (?<host>#{HOST.source.delete(" \n")})
- (?::(?<port>\d*+))?
- )
- (?<path-abempty>(?:/\g<seg>*+)?)
- | (?<path-absolute>/((?!/)\g<seg>++)?)
- | (?<path-rootless>(?!/)\g<seg>++)
- | (?<path-empty>)
- )
- (?:\?(?<query>[^\#]*+))?
- (?:\#(?<fragment>#{FRAGMENT}))?
- )\z]x
-
- RFC3986_relative_ref = %r[\A
- (?<seg>#{SEG}){0}
- (?<relative-ref>
- (?<relative-part>//
- (?<authority>
- (?:(?<userinfo>#{USERINFO.source})@)?
- (?<host>#{HOST.source.delete(" \n")}(?<!/))?
- (?::(?<port>\d*+))?
- )
- (?<path-abempty>(?:/\g<seg>*+)?)
- | (?<path-absolute>/\g<seg>*+)
- | (?<path-noscheme>#{SEG_NC}++(?:/\g<seg>*+)?)
- | (?<path-empty>)
- )
- (?:\?(?<query>[^#]*+))?
- (?:\#(?<fragment>#{FRAGMENT}))?
- )\z]x
+ RFC3986_URI = /\A(?<URI>(?<scheme>[A-Za-z][+\-.0-9A-Za-z]*+):(?<hier-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*+)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h++\.[!$&-.0-;=A-Z_a-z~]++))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*+))(?::(?<port>\d*+))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*+))*+)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])++)(?:\/\g<segment>)*+)?)|(?<path-rootless>\g<segment-nz>(?:\/\g<segment>)*+)|(?<path-empty>))(?:\?(?<query>[^#]*+))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*+))?)\z/
+ RFC3986_relative_ref = /\A(?<relative-ref>(?<relative-part>\/\/(?<authority>(?:(?<userinfo>(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*+)@)?(?<host>(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{1,4}?::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:){,1}\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h++\.[!$&-.0-;=A-Z_a-z~]++))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])++))?(?::(?<port>\d*+))?)(?<path-abempty>(?:\/(?<segment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*+))*+)|(?<path-absolute>\/(?:(?<segment-nz>(?:%\h\h|[!$&-.0-;=@-Z_a-z~])++)(?:\/\g<segment>)*+)?)|(?<path-noscheme>(?<segment-nz-nc>(?:%\h\h|[!$&-.0-9;=@-Z_a-z~])++)(?:\/\g<segment>)*+)|(?<path-empty>))(?:\?(?<query>[^#]*+))?(?:\#(?<fragment>(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*+))?)\z/
attr_reader :regexp
def initialize
@@ -78,14 +14,14 @@ module URI
begin
uri = uri.to_str
rescue NoMethodError
- raise InvalidURIError, "bad URI (is not URI?): #{uri.inspect}"
+ raise InvalidURIError, "bad URI(is not URI?): #{uri.inspect}"
end
uri.ascii_only? or
raise InvalidURIError, "URI must be ascii only #{uri.dump}"
if m = RFC3986_URI.match(uri)
- query = m["query"]
- scheme = m["scheme"]
- opaque = m["path-rootless"]
+ query = m["query".freeze]
+ scheme = m["scheme".freeze]
+ opaque = m["path-rootless".freeze]
if opaque
opaque << "?#{query}" if query
[ scheme,
@@ -96,38 +32,38 @@ module URI
nil, # path
opaque,
nil, # query
- m["fragment"]
+ m["fragment".freeze]
]
else # normal
[ scheme,
- m["userinfo"],
- m["host"],
- m["port"],
+ m["userinfo".freeze],
+ m["host".freeze],
+ m["port".freeze],
nil, # registry
- (m["path-abempty"] ||
- m["path-absolute"] ||
- m["path-empty"]),
+ (m["path-abempty".freeze] ||
+ m["path-absolute".freeze] ||
+ m["path-empty".freeze]),
nil, # opaque
query,
- m["fragment"]
+ m["fragment".freeze]
]
end
elsif m = RFC3986_relative_ref.match(uri)
[ nil, # scheme
- m["userinfo"],
- m["host"],
- m["port"],
+ m["userinfo".freeze],
+ m["host".freeze],
+ m["port".freeze],
nil, # registry,
- (m["path-abempty"] ||
- m["path-absolute"] ||
- m["path-noscheme"] ||
- m["path-empty"]),
+ (m["path-abempty".freeze] ||
+ m["path-absolute".freeze] ||
+ m["path-noscheme".freeze] ||
+ m["path-empty".freeze]),
nil, # opaque
- m["query"],
- m["fragment"]
+ m["query".freeze],
+ m["fragment".freeze]
]
else
- raise InvalidURIError, "bad URI (is not URI?): #{uri.inspect}"
+ raise InvalidURIError, "bad URI(is not URI?): #{uri.inspect}"
end
end
@@ -135,35 +71,12 @@ module URI
URI.for(*self.split(uri), self)
end
+
def join(*uris) # :nodoc:
uris[0] = convert_to_uri(uris[0])
uris.inject :merge
end
- # Compatibility for RFC2396 parser
- def extract(str, schemes = nil, &block) # :nodoc:
- warn "URI::RFC3986_PARSER.extract is obsoleted. Use URI::RFC2396_PARSER.extract explicitly.", uplevel: 1 if $VERBOSE
- RFC2396_PARSER.extract(str, schemes, &block)
- end
-
- # Compatibility for RFC2396 parser
- def make_regexp(schemes = nil) # :nodoc:
- warn "URI::RFC3986_PARSER.make_regexp is obsoleted. Use URI::RFC2396_PARSER.make_regexp explicitly.", uplevel: 1 if $VERBOSE
- RFC2396_PARSER.make_regexp(schemes)
- end
-
- # Compatibility for RFC2396 parser
- def escape(str, unsafe = nil) # :nodoc:
- warn "URI::RFC3986_PARSER.escape is obsoleted. Use URI::RFC2396_PARSER.escape explicitly.", uplevel: 1 if $VERBOSE
- unsafe ? RFC2396_PARSER.escape(str, unsafe) : RFC2396_PARSER.escape(str)
- end
-
- # Compatibility for RFC2396 parser
- def unescape(str, escaped = nil) # :nodoc:
- warn "URI::RFC3986_PARSER.unescape is obsoleted. Use URI::RFC2396_PARSER.unescape explicitly.", uplevel: 1 if $VERBOSE
- escaped ? RFC2396_PARSER.unescape(str, escaped) : RFC2396_PARSER.unescape(str)
- end
-
@@to_s = Kernel.instance_method(:to_s)
if @@to_s.respond_to?(:bind_call)
def inspect
@@ -179,14 +92,14 @@ module URI
def default_regexp # :nodoc:
{
- SCHEME: %r[\A#{SCHEME}\z]o,
- USERINFO: %r[\A#{USERINFO}\z]o,
- HOST: %r[\A#{HOST}\z]o,
- ABS_PATH: %r[\A/#{SEG}*+\z]o,
- REL_PATH: %r[\A(?!/)#{SEG}++\z]o,
- QUERY: %r[\A(?:%\h\h|[!$&-.0-9:;=@A-Z_a-z~/?])*+\z],
- FRAGMENT: %r[\A#{FRAGMENT}\z]o,
- OPAQUE: %r[\A(?:[^/].*)?\z],
+ SCHEME: /\A[A-Za-z][A-Za-z0-9+\-.]*\z/,
+ USERINFO: /\A(?:%\h\h|[!$&-.0-;=A-Z_a-z~])*\z/,
+ HOST: /\A(?:(?<IP-literal>\[(?:(?<IPv6address>(?:\h{1,4}:){6}(?<ls32>\h{1,4}:\h{1,4}|(?<IPv4address>(?<dec-octet>[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]|\d)\.\g<dec-octet>\.\g<dec-octet>\.\g<dec-octet>))|::(?:\h{1,4}:){5}\g<ls32>|\h{,4}::(?:\h{1,4}:){4}\g<ls32>|(?:(?:\h{1,4}:)?\h{1,4})?::(?:\h{1,4}:){3}\g<ls32>|(?:(?:\h{1,4}:){,2}\h{1,4})?::(?:\h{1,4}:){2}\g<ls32>|(?:(?:\h{1,4}:){,3}\h{1,4})?::\h{1,4}:\g<ls32>|(?:(?:\h{1,4}:){,4}\h{1,4})?::\g<ls32>|(?:(?:\h{1,4}:){,5}\h{1,4})?::\h{1,4}|(?:(?:\h{1,4}:){,6}\h{1,4})?::)|(?<IPvFuture>v\h+\.[!$&-.0-;=A-Z_a-z~]+))\])|\g<IPv4address>|(?<reg-name>(?:%\h\h|[!$&-.0-9;=A-Z_a-z~])*))\z/,
+ ABS_PATH: /\A\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/,
+ REL_PATH: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~])+(?:\/(?:%\h\h|[!$&-.0-;=@-Z_a-z~])*)*\z/,
+ QUERY: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/,
+ FRAGMENT: /\A(?:%\h\h|[!$&-.0-;=@-Z_a-z~\/?])*\z/,
+ OPAQUE: /\A(?:[^\/].*)?\z/,
PORT: /\A[\x09\x0a\x0c\x0d ]*+\d*[\x09\x0a\x0c\x0d ]*\z/,
}
end
diff --git a/lib/uri/uri.gemspec b/lib/uri/uri.gemspec
index 9cf0a71196..584a4faa11 100644
--- a/lib/uri/uri.gemspec
+++ b/lib/uri/uri.gemspec
@@ -12,26 +12,18 @@ Gem::Specification.new do |spec|
spec.summary = %q{URI is a module providing classes to handle Uniform Resource Identifiers}
spec.description = spec.summary
-
- github_link = "https://github.com/ruby/uri"
-
- spec.homepage = github_link
+ spec.homepage = "https://github.com/ruby/uri"
spec.licenses = ["Ruby", "BSD-2-Clause"]
- spec.required_ruby_version = '>= 2.5'
+ spec.required_ruby_version = '>= 2.4'
- spec.metadata = {
- "bug_tracker_uri" => "#{github_link}/issues",
- "changelog_uri" => "#{github_link}/releases",
- "documentation_uri" => "https://ruby.github.io/uri/",
- "homepage_uri" => spec.homepage,
- "source_code_uri" => github_link
- }
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = spec.homepage
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/lib/uri/version.rb b/lib/uri/version.rb
index bfe3f47670..c93c97cf6f 100644
--- a/lib/uri/version.rb
+++ b/lib/uri/version.rb
@@ -1,6 +1,6 @@
module URI
# :stopdoc:
- VERSION_CODE = '001301'.freeze
+ VERSION_CODE = '001204'.freeze
VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
# :startdoc:
end
diff --git a/lib/weakref.gemspec b/lib/weakref.gemspec
deleted file mode 100644
index 03893f77e6..0000000000
--- a/lib/weakref.gemspec
+++ /dev/null
@@ -1,34 +0,0 @@
-# frozen_string_literal: true
-
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, ".").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
-Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
- spec.authors = ["Yukihiro Matsumoto"]
- spec.email = ["matz@ruby-lang.org"]
-
- spec.summary = %q{Allows a referenced object to be garbage-collected.}
- spec.description = %q{Allows a referenced object to be garbage-collected.}
- spec.homepage = "https://github.com/ruby/weakref"
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = "https://github.com/ruby/weakref"
- spec.licenses = ["Ruby", "BSD-2-Clause"]
-
- # Specify which files should be added to the gem when it is released.
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
- end
- spec.bindir = "exe"
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
- spec.require_paths = ["lib"]
-
- spec.add_dependency "delegate"
-end
diff --git a/lib/weakref.rb b/lib/weakref.rb
index a8da39a26a..2bbadf68f9 100644
--- a/lib/weakref.rb
+++ b/lib/weakref.rb
@@ -17,7 +17,7 @@ require "delegate"
#
class WeakRef < Delegator
- VERSION = "0.1.3"
+ VERSION = "0.1.2"
##
# RefError is raised when a referenced object has been recycled by the
diff --git a/lib/weakref/weakref.gemspec b/lib/weakref/weakref.gemspec
new file mode 100644
index 0000000000..96a9765079
--- /dev/null
+++ b/lib/weakref/weakref.gemspec
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+name = File.basename(__FILE__, ".gemspec")
+version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
+ break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
+ /^\s*VERSION\s*=\s*"(.*)"/ =~ line and break $1
+ end rescue nil
+end
+
+Gem::Specification.new do |spec|
+ spec.name = name
+ spec.version = version
+ spec.authors = ["Yukihiro Matsumoto"]
+ spec.email = ["matz@ruby-lang.org"]
+
+ spec.summary = %q{Allows a referenced object to be garbage-collected.}
+ spec.description = %q{Allows a referenced object to be garbage-collected.}
+ spec.homepage = "https://github.com/ruby/weakref"
+
+ spec.metadata["homepage_uri"] = spec.homepage
+ spec.metadata["source_code_uri"] = "https://github.com/ruby/weakref"
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
+
+ # Specify which files should be added to the gem when it is released.
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ end
+ spec.bindir = "exe"
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
+ spec.require_paths = ["lib"]
+
+ spec.add_dependency "delegate"
+end
diff --git a/lib/yaml.rb b/lib/yaml.rb
index b2669899dd..6d5d5ebd4c 100644
--- a/lib/yaml.rb
+++ b/lib/yaml.rb
@@ -66,5 +66,4 @@ YAML = Psych # :nodoc:
#
# Syck can also be found on github: https://github.com/ruby/syck
module YAML
- LOADER_VERSION = "0.3.0"
end
diff --git a/lib/yaml/store.rb b/lib/yaml/store.rb
index f24e4ad332..f8650b942f 100644
--- a/lib/yaml/store.rb
+++ b/lib/yaml/store.rb
@@ -3,11 +3,7 @@
# YAML::Store
#
require 'yaml'
-
-begin
- require 'pstore'
-rescue LoadError
-end
+require 'pstore'
# YAML::Store provides the same functionality as PStore, except it uses YAML
# to dump objects instead of Marshal.
@@ -69,7 +65,7 @@ class YAML::Store < PStore
end
def load(content)
- table = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(content) : YAML.load(content)
+ table = YAML.unsafe_load(content)
if table == false
{}
else
@@ -87,4 +83,4 @@ class YAML::Store < PStore
def empty_marshal_checksum
CHECKSUM_ALGO.digest(empty_marshal_data)
end
-end if defined?(::PStore)
+end
diff --git a/lib/yaml/yaml.gemspec b/lib/yaml/yaml.gemspec
index 17e1ce89e0..80554d8a7a 100644
--- a/lib/yaml/yaml.gemspec
+++ b/lib/yaml/yaml.gemspec
@@ -1,13 +1,6 @@
-name = File.basename(__FILE__, ".gemspec")
-version = ["lib", Array.new(name.count("-")+1, "..").join("/")].find do |dir|
- break File.foreach(File.join(__dir__, dir, "#{name.tr('-', '/')}.rb")) do |line|
- /^\s*LOADER_VERSION\s*=\s*"(.*)"/ =~ line and break $1
- end rescue nil
-end
-
Gem::Specification.new do |spec|
- spec.name = name
- spec.version = version
+ spec.name = "yaml"
+ spec.version = "0.2.1"
spec.authors = ["Aaron Patterson", "SHIBATA Hiroshi"]
spec.email = ["aaron@tenderlovemaking.com", "hsbt@ruby-lang.org"]
@@ -22,7 +15,7 @@ Gem::Specification.new do |spec|
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
- `git ls-files -z 2>#{IO::NULL}`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
+ `git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end
spec.bindir = "exe"
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
diff --git a/libexec/bundle b/libexec/bundle
index 92387bc2cf..90c62627f8 100755
--- a/libexec/bundle
+++ b/libexec/bundle
@@ -15,6 +15,15 @@ end
require "bundler"
+if Gem.rubygems_version < Gem::Version.new("3.2.3") && Gem.ruby_version < Gem::Version.new("2.7.a") && !ENV["BUNDLER_NO_OLD_RUBYGEMS_WARNING"]
+ Bundler.ui.warn \
+ "Your RubyGems version (#{Gem::VERSION}) has a bug that prevents " \
+ "`required_ruby_version` from working for Bundler. Any scripts that use " \
+ "`gem install bundler` will break as soon as Bundler drops support for " \
+ "your Ruby version. Please upgrade RubyGems to avoid future breakage " \
+ "and silence this warning by running `gem update --system 3.2.3`"
+end
+
require "bundler/friendly_errors"
Bundler.with_friendly_errors do
@@ -25,5 +34,5 @@ Bundler.with_friendly_errors do
help_flag_used = ARGV.any? {|a| help_flags.include? a }
args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV
- Bundler::CLI.start(args, debug: true)
+ Bundler::CLI.start(args, :debug => true)
end
diff --git a/libexec/irb b/libexec/irb
index 12f41e4f0a..c64ee85fbd 100755
--- a/libexec/irb
+++ b/libexec/irb
@@ -1,6 +1,8 @@
#!/usr/bin/env ruby
#
# irb.rb - interactive ruby
+# $Release Version: 0.9.6 $
+# $Revision$
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
diff --git a/libexec/racc b/libexec/racc
new file mode 100755
index 0000000000..4507d04962
--- /dev/null
+++ b/libexec/racc
@@ -0,0 +1,320 @@
+#!/usr/bin/env ruby
+#
+#
+#
+# Copyright (c) 1999-2006 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the same terms of ruby.
+# see the file "COPYING".
+
+require 'racc/static'
+require 'optparse'
+
+def main
+ output = nil
+ debug_parser = false
+ make_logfile = false
+ logfilename = nil
+ make_executable = false
+ rubypath = nil
+ embed_runtime = false
+ debug_flags = Racc::DebugFlags.new
+ line_convert = true
+ line_convert_all = false
+ omit_action_call = true
+ superclass = nil
+ check_only = false
+ verbose = false
+ profiler = RaccProfiler.new(false)
+
+ parser = OptionParser.new
+ parser.banner = "Usage: #{File.basename($0)} [options] <input>"
+ parser.on('-o', '--output-file=PATH',
+ 'output file name [<input>.tab.rb]') {|name|
+ output = name
+ }
+ parser.on('-t', '--debug', 'Outputs debugging parser.') {|fl|
+ debug_parser = fl
+ }
+ parser.on('-g', 'Equivalent to -t (obsolete).') {|fl|
+ $stderr.puts "racc -g is obsolete. Use racc -t instead." if $VERBOSE
+ debug_parser = fl
+ }
+ parser.on('-v', '--verbose',
+ 'Creates <filename>.output log file.') {|fl|
+ make_logfile = fl
+ }
+ parser.on('-O', '--log-file=PATH',
+ 'Log file name [<input>.output]') {|path|
+ make_logfile = true
+ logfilename = path
+ }
+ parser.on('-e', '--executable [RUBYPATH]', 'Makes executable parser.') {|path|
+ make_executable = true
+ rubypath = (path == 'ruby' ? nil : path)
+ }
+ parser.on('-E', '--embedded', "Embeds Racc runtime in output.") {
+ embed_runtime = true
+ }
+ parser.on('--line-convert-all', 'Converts line numbers of user codes.') {
+ line_convert_all = true
+ }
+ parser.on('-l', '--no-line-convert', 'Never convert line numbers.') {
+ line_convert = false
+ line_convert_all = false
+ }
+ parser.on('-a', '--no-omit-actions', 'Never omit actions.') {
+ omit_action_call = false
+ }
+ parser.on('--superclass=CLASSNAME',
+ 'Uses CLASSNAME instead of Racc::Parser.') {|name|
+ superclass = name
+ }
+ parser.on('-C', '--check-only', 'Checks syntax and quit immediately.') {|fl|
+ check_only = fl
+ }
+ parser.on('-S', '--output-status', 'Outputs internal status time to time.') {
+ verbose = true
+ }
+ parser.on('-P', 'Enables generator profile') {
+ profiler = RaccProfiler.new(true)
+ }
+ parser.on('-D flags', "Flags for Racc debugging (do not use).") {|flags|
+ debug_flags = Racc::DebugFlags.parse_option_string(flags)
+ }
+ #parser.on('--no-extensions', 'Run Racc without any Ruby extension.') {
+ # Racc.const_set :Racc_No_Extensions, true
+ #}
+ parser.on('--version', 'Prints version and quit.') {
+ puts "racc version #{Racc::Version}"
+ exit 0
+ }
+ parser.on('--runtime-version', 'Prints runtime version and quit.') {
+ printf "racc runtime version %s; %s\n",
+ Racc::Parser::Racc_Runtime_Version,
+ if Racc::Parser.racc_runtime_type == 'ruby'
+ sprintf('ruby core version %s',
+ Racc::Parser::Racc_Runtime_Core_Version_R)
+ else
+ sprintf('c core version %s',
+ Racc::Parser::Racc_Runtime_Core_Version_C)
+ end
+ exit 0
+ }
+ parser.on('--copyright', 'Prints copyright and quit.') {
+ puts Racc::Copyright
+ exit 0
+ }
+ parser.on('--help', 'Prints this message and quit.') {
+ puts parser.help
+ exit 1
+ }
+ begin
+ parser.parse!
+ rescue OptionParser::ParseError => err
+ $stderr.puts err.message
+ $stderr.puts parser.help
+ exit 1
+ end
+ if ARGV.empty?
+ $stderr.puts 'no input'
+ exit 1
+ end
+ if ARGV.size > 1
+ $stderr.puts 'too many input'
+ exit 1
+ end
+ input = ARGV[0]
+
+ begin
+ $stderr.puts 'Parsing grammar file...' if verbose
+ result = profiler.section('parse') {
+ parser = Racc::GrammarFileParser.new(debug_flags)
+ parser.parse(File.read(input), File.basename(input))
+ }
+ if check_only
+ $stderr.puts 'syntax ok'
+ exit 0
+ end
+
+ $stderr.puts 'Generating LALR states...' if verbose
+ states = profiler.section('nfa') {
+ Racc::States.new(result.grammar).nfa
+ }
+
+ $stderr.puts "Resolving #{states.size} states..." if verbose
+ profiler.section('dfa') {
+ states.dfa
+ }
+
+ $stderr.puts 'Creating parser file...' if verbose
+ params = result.params.dup
+ # Overwrites parameters given by a grammar file with command line options.
+ params.superclass = superclass if superclass
+ params.omit_action_call = true if omit_action_call
+ # From command line option
+ if make_executable
+ params.make_executable = true
+ params.interpreter = rubypath
+ end
+ params.debug_parser = debug_parser
+ params.convert_line = line_convert
+ params.convert_line_all = line_convert_all
+ params.embed_runtime = embed_runtime
+ profiler.section('generation') {
+ generator = Racc::ParserFileGenerator.new(states, params)
+ generator.generate_parser_file(output || make_filename(input, '.tab.rb'))
+ }
+
+ if make_logfile
+ profiler.section('logging') {
+ $stderr.puts 'Creating log file...' if verbose
+ logfilename ||= make_filename(output || File.basename(input), '.output')
+ File.open(logfilename, 'w') {|f|
+ Racc::LogFileGenerator.new(states, debug_flags).output f
+ }
+ }
+ end
+ if debug_flags.status_logging
+ log_useless states.grammar
+ log_conflict states
+ else
+ has_useless = report_useless states.grammar
+ has_conflicts = report_conflict states
+ if has_useless || has_conflicts
+ preamble = make_logfile ? 'C' : 'Turn on logging with "-v" and c'
+ $stderr.puts %Q{#{preamble}heck ".output" file for details}
+ end
+ end
+
+ profiler.report
+ rescue Racc::Error, Errno::ENOENT, Errno::EPERM => err
+ raise if $DEBUG or debug_flags.any?
+ lineno = err.message.slice(/\A\d+:/).to_s
+ $stderr.puts "#{File.basename $0}: #{input}:#{lineno} #{err.message.strip}"
+ exit 1
+ end
+end
+
+def make_filename(path, suffix)
+ path.sub(/(?:\..*?)?\z/, suffix)
+end
+
+LIST_LIMIT = 10
+def report_list(enum, label)
+ c = enum.count
+ if c > 0
+ $stderr.puts "#{c} #{label}:"
+ enum.first(LIST_LIMIT).each do |item|
+ $stderr.puts " #{yield item}"
+ end
+ $stderr.puts " ..." if c > LIST_LIMIT
+ end
+end
+
+# @return [Boolean] if anything was reported
+def report_conflict(states)
+ if states.should_report_srconflict?
+ reported = true
+ $stderr.puts "#{states.n_srconflicts} shift/reduce conflicts"
+ end
+ if states.rrconflict_exist?
+ reported = true
+ $stderr.puts "#{states.n_rrconflicts} reduce/reduce conflicts"
+ end
+ reported
+end
+
+def log_conflict(states)
+ logging('w') {|f|
+ f.puts "ex#{states.grammar.n_expected_srconflicts}"
+ if states.should_report_srconflict?
+ f.puts "sr#{states.n_srconflicts}"
+ end
+ if states.rrconflict_exist?
+ f.puts "rr#{states.n_rrconflicts}"
+ end
+ }
+end
+
+# @return [Boolean] if anything was reported
+def report_useless(grammar)
+ reported = report_list(grammar.each_useless_nonterminal, 'useless nonterminals', &:to_s)
+
+ reported ||= report_list(grammar.each_useless_rule, 'useless rules') { |r| "##{r.ident} (#{r.target})" }
+
+ if grammar.start.useless?
+ $stderr.puts 'fatal: start symbol does not derive any sentence'
+ reported = true
+ end
+ reported
+end
+
+def log_useless(grammar)
+ logging('a') {|f|
+ if grammar.useless_nonterminal_exist?
+ f.puts "un#{grammar.n_useless_nonterminals}"
+ end
+ if grammar.useless_rule_exist?
+ f.puts "ur#{grammar.n_useless_rules}"
+ end
+ }
+end
+
+def logging(mode, &block)
+ File.open("log/#{File.basename(ARGV[0])}", mode, &block)
+end
+
+class RaccProfiler
+ def initialize(really)
+ @really = really
+ @log = []
+ unless ::Process.respond_to?(:times)
+ # Ruby 1.6
+ @class = ::Time
+ else
+ @class = ::Process
+ end
+ end
+
+ def section(name)
+ if @really
+ t1 = @class.times.utime
+ result = yield
+ t2 = @class.times.utime
+ @log.push [name, t2 - t1]
+ result
+ else
+ yield
+ end
+ end
+
+ def report
+ return unless @really
+ f = $stderr
+ total = cumulative_time()
+ f.puts '--task-----------+--sec------+---%-'
+ @log.each do |name, time|
+ f.printf "%-19s %s %3d%%\n", name, pjust(time,4,4), (time/total*100).to_i
+ end
+ f.puts '-----------------+-----------+-----'
+ f.printf "%-20s%s\n", 'total', pjust(total,4,4)
+ end
+
+ private
+
+ def cumulative_time
+ t = @log.inject(0) {|sum, (name, time)| sum + time }
+ t == 0 ? 0.01 : t
+ end
+
+ def pjust(num, i, j)
+ m = /(\d+)(\.\d+)?/.match(num.to_s)
+ str = m[1].rjust(i)
+ str.concat m[2].ljust(j+1)[0,j+1] if m[2]
+ str
+ end
+end
+
+main
diff --git a/load.c b/load.c
index c1862c38fa..ecb21faa72 100644
--- a/load.c
+++ b/load.c
@@ -8,9 +8,8 @@
#include "internal/dir.h"
#include "internal/error.h"
#include "internal/file.h"
-#include "internal/hash.h"
#include "internal/load.h"
-#include "internal/ruby_parser.h"
+#include "internal/parse.h"
#include "internal/thread.h"
#include "internal/variable.h"
#include "iseq.h"
@@ -19,27 +18,12 @@
#include "ruby/encoding.h"
#include "ruby/util.h"
-static VALUE ruby_dln_libmap;
+static VALUE ruby_dln_librefs;
#define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
-#if SIZEOF_VALUE <= SIZEOF_LONG
-# define SVALUE2NUM(x) LONG2NUM((long)(x))
-# define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LONG(x)
-#elif SIZEOF_VALUE <= SIZEOF_LONG_LONG
-# define SVALUE2NUM(x) LL2NUM((LONG_LONG)(x))
-# define NUM2SVALUE(x) (SIGNED_VALUE)NUM2LL(x)
-#else
-# error Need integer for VALUE
-#endif
-
-enum {
- loadable_ext_rb = (0+ /* .rb extension is the first in both tables */
- 1) /* offset by rb_find_file_ext() */
-};
-
static const char *const loadable_ext[] = {
".rb", DLEXT,
0
@@ -104,7 +88,7 @@ rb_construct_expanded_load_path(rb_vm_t *vm, enum expand_type type, int *has_rel
if (NIL_P(expanded_path)) expanded_path = as_str;
rb_ary_push(ary, rb_fstring(expanded_path));
}
- rb_ary_freeze(ary);
+ rb_obj_freeze(ary);
vm->expanded_load_path = ary;
rb_ary_replace(vm->load_path_snapshot, vm->load_path);
}
@@ -253,9 +237,9 @@ features_index_add_single_callback(st_data_t *key, st_data_t *value, st_data_t r
rb_darray_set(feature_indexes, top^0, FIX2LONG(this_feature_index));
rb_darray_set(feature_indexes, top^1, FIX2LONG(offset));
- RUBY_ASSERT(rb_darray_size(feature_indexes) == 2);
+ assert(rb_darray_size(feature_indexes) == 2);
// assert feature_indexes does not look like a special const
- RUBY_ASSERT(!SPECIAL_CONST_P((VALUE)feature_indexes));
+ assert(!SPECIAL_CONST_P((VALUE)feature_indexes));
*value = (st_data_t)feature_indexes;
}
@@ -371,13 +355,6 @@ loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
return ST_DELETE;
}
-void
-rb_free_loaded_features_index(rb_vm_t *vm)
-{
- st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
- st_free_table(vm->loaded_features_index);
-}
-
static st_table *
get_loaded_features_index(rb_vm_t *vm)
{
@@ -399,7 +376,7 @@ get_loaded_features_index(rb_vm_t *vm)
VALUE entry, as_str;
as_str = entry = rb_ary_entry(features, i);
StringValue(as_str);
- as_str = rb_fstring(as_str);
+ as_str = rb_fstring(rb_str_freeze(as_str));
if (as_str != entry)
rb_ary_store(features, i, as_str);
features_index_add(vm, as_str, INT2FIX(i));
@@ -498,12 +475,6 @@ loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
return ST_STOP;
}
-/*
- * Returns the type of already provided feature.
- * 'r': ruby script (".rb")
- * 's': shared object (".so"/"."DLEXT)
- * 'u': unsuffixed
- */
static int
rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn)
{
@@ -596,7 +567,7 @@ rb_feature_p(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expa
loading_tbl = get_loading_table(vm);
f = 0;
- if (!expanded) {
+ if (!expanded && !rb_is_absolute_path(feature)) {
struct loaded_feature_searching fs;
fs.name = feature;
fs.len = len;
@@ -698,14 +669,14 @@ rb_provide_feature(rb_vm_t *vm, VALUE feature)
rb_raise(rb_eRuntimeError,
"$LOADED_FEATURES is frozen; cannot append feature");
}
- feature = rb_fstring(feature);
+ rb_str_freeze(feature);
get_loaded_features_index(vm);
// If loaded_features and loaded_features_snapshot share the same backing
// array, pushing into it would cause the whole array to be copied.
// To avoid this we first clear loaded_features_snapshot.
rb_ary_clear(vm->loaded_features_snapshot);
- rb_ary_push(features, feature);
+ rb_ary_push(features, rb_fstring(feature));
features_index_add(vm, feature, INT2FIX(RARRAY_LEN(features)-1));
reset_loaded_features_snapshot(vm);
}
@@ -718,19 +689,6 @@ rb_provide(const char *feature)
NORETURN(static void load_failed(VALUE));
-static inline VALUE
-realpath_internal_cached(VALUE hash, VALUE path)
-{
- VALUE ret = rb_hash_aref(hash, path);
- if(RTEST(ret)) {
- return ret;
- }
-
- VALUE realpath = rb_realpath_internal(Qnil, path, 1);
- rb_hash_aset(hash, rb_fstring(path), rb_fstring(realpath));
- return realpath;
-}
-
static inline void
load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
{
@@ -739,41 +697,13 @@ load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
if (!iseq) {
rb_execution_context_t *ec = GET_EC();
VALUE v = rb_vm_push_frame_fname(ec, fname);
-
- rb_thread_t *th = rb_ec_thread_ptr(ec);
- VALUE realpath_map = get_loaded_features_realpath_map(th->vm);
-
- if (rb_ruby_prism_p()) {
- pm_parse_result_t result = { 0 };
- result.options.line = 1;
- result.node.coverage_enabled = 1;
-
- VALUE error = pm_load_parse_file(&result, fname, NULL);
-
- if (error == Qnil) {
- iseq = pm_iseq_new_top(&result.node, rb_fstring_lit("<top (required)>"), fname, realpath_internal_cached(realpath_map, fname), NULL);
- pm_parse_result_free(&result);
- }
- else {
- rb_vm_pop_frame(ec);
- RB_GC_GUARD(v);
- pm_parse_result_free(&result);
- rb_exc_raise(error);
- }
- }
- else {
- rb_ast_t *ast;
- VALUE ast_value;
- VALUE parser = rb_parser_new();
- rb_parser_set_context(parser, NULL, FALSE);
- ast_value = rb_parser_load_file(parser, fname);
- ast = rb_ruby_ast_data_get(ast_value);
-
- iseq = rb_iseq_new_top(ast_value, rb_fstring_lit("<top (required)>"),
- fname, realpath_internal_cached(realpath_map, fname), NULL);
- rb_ast_dispose(ast);
- }
-
+ rb_ast_t *ast;
+ VALUE parser = rb_parser_new();
+ rb_parser_set_context(parser, NULL, FALSE);
+ ast = (rb_ast_t *)rb_parser_load_file(parser, fname);
+ iseq = rb_iseq_new_top(&ast->body, rb_fstring_lit("<top (required)>"),
+ fname, rb_realpath_internal(Qnil, fname, 1), NULL);
+ rb_ast_dispose(ast);
rb_vm_pop_frame(ec);
RB_GC_GUARD(v);
}
@@ -890,8 +820,9 @@ rb_load_protect(VALUE fname, int wrap, int *pstate)
* LoadError will be raised.
*
* If the optional _wrap_ parameter is +true+, the loaded script will
- * be executed under an anonymous module. If the optional _wrap_ parameter
- * is a module, the loaded script will be executed under the given module.
+ * be executed under an anonymous module, protecting the calling
+ * program's global namespace. If the optional _wrap_ parameter is a
+ * module, the loaded script will be executed under the given module.
* In no circumstance will any local variables in the loaded file be
* propagated to the loading environment.
*/
@@ -976,7 +907,7 @@ load_unlock(rb_vm_t *vm, const char *ftptr, int done)
}
}
-static VALUE rb_require_string_internal(VALUE fname, bool resurrect);
+static VALUE rb_require_string_internal(VALUE fname);
/*
* call-seq:
@@ -991,14 +922,15 @@ static VALUE rb_require_string_internal(VALUE fname, bool resurrect);
* If the filename starts with './' or '../', resolution is based on Dir.pwd.
*
* If the filename has the extension ".rb", it is loaded as a source file; if
- * the extension is ".so", ".o", or the default shared library extension on
- * the current platform, Ruby loads the shared library as a Ruby extension.
- * Otherwise, Ruby tries adding ".rb", ".so", and so on to the name until
- * found. If the file named cannot be found, a LoadError will be raised.
+ * the extension is ".so", ".o", or ".dll", or the default shared library
+ * extension on the current platform, Ruby loads the shared library as a
+ * Ruby extension. Otherwise, Ruby tries adding ".rb", ".so", and so on
+ * to the name until found. If the file named cannot be found, a LoadError
+ * will be raised.
*
- * For Ruby extensions the filename given may use ".so" or ".o". For example,
- * on macOS the socket extension is "socket.bundle" and
- * <code>require 'socket.so'</code> will load the socket extension.
+ * For Ruby extensions the filename given may use any shared library
+ * extension. For example, on Linux the socket extension is "socket.so" and
+ * <code>require 'socket.dll'</code> will load the socket extension.
*
* The absolute path of the loaded file is added to
* <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be
@@ -1038,7 +970,7 @@ rb_f_require_relative(VALUE obj, VALUE fname)
rb_loaderror("cannot infer basepath");
}
base = rb_file_dirname(base);
- return rb_require_string_internal(rb_file_absolute_path(fname, base), false);
+ return rb_require_string_internal(rb_file_absolute_path(fname, base));
}
typedef int (*feature_func)(rb_vm_t *vm, const char *feature, const char *ext, int rb, int expanded, const char **fn);
@@ -1048,7 +980,7 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
{
VALUE tmp;
char *ext, *ftptr;
- int ft = 0;
+ int type, ft = 0;
const char *loading;
*path = 0;
@@ -1100,11 +1032,11 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
return 'r';
}
tmp = fname;
- const unsigned int type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
+ type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
// Check if it's a statically linked extension when
// not already a feature and not found as a dynamic library.
- if (!ft && type != loadable_ext_rb && vm->static_ext_inits) {
+ if (!ft && type != 1 && vm->static_ext_inits) {
VALUE lookup_name = tmp;
// Append ".so" if not already present so for example "etc" can find "etc.so".
// We always register statically linked extensions with a ".so" extension.
@@ -1132,13 +1064,13 @@ search_required(rb_vm_t *vm, VALUE fname, volatile VALUE *path, feature_func rb_
goto feature_present;
}
/* fall through */
- case loadable_ext_rb:
+ case 1:
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
- if (rb_feature_p(vm, ftptr, ext, type == loadable_ext_rb, TRUE, &loading) && !loading)
+ if (rb_feature_p(vm, ftptr, ext, !--type, TRUE, &loading) && !loading)
break;
*path = tmp;
}
- return type > loadable_ext_rb ? 's' : 'r';
+ return type ? 's' : 'r';
feature_present:
if (loading) *path = rb_filesystem_str_new_cstr(loading);
@@ -1236,10 +1168,8 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
rb_thread_t *th = rb_ec_thread_ptr(ec);
volatile const struct {
VALUE wrapper, self, errinfo;
- rb_execution_context_t *ec;
} saved = {
th->top_wrapper, th->top_self, ec->errinfo,
- ec,
};
enum ruby_tag_type state;
char *volatile ftptr = 0;
@@ -1259,7 +1189,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
ec->errinfo = Qnil; /* ensure */
th->top_wrapper = 0;
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- VALUE handle;
+ long handle;
int found;
RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
@@ -1278,21 +1208,21 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
result = TAG_RETURN;
}
else if (RTEST(rb_hash_aref(realpaths,
- realpath = realpath_internal_cached(realpath_map, path)))) {
+ realpath = rb_realpath_internal(Qnil, path, 1)))) {
result = 0;
}
else {
switch (found) {
case 'r':
- load_iseq_eval(saved.ec, path);
+ load_iseq_eval(ec, path);
break;
case 's':
reset_ext_config = true;
ext_config_push(th, &prev_ext_config);
- handle = rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
- path, VM_BLOCK_HANDLER_NONE, path);
- rb_hash_aset(ruby_dln_libmap, path, SVALUE2NUM((SIGNED_VALUE)handle));
+ handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
+ path, VM_BLOCK_HANDLER_NONE, path);
+ rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
break;
}
result = TAG_RETURN;
@@ -1301,7 +1231,6 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
}
EC_POP_TAG();
- ec = saved.ec;
rb_thread_t *th2 = rb_ec_thread_ptr(ec);
th2->top_self = saved.self;
th2->top_wrapper = saved.wrapper;
@@ -1339,6 +1268,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
if (real) {
real = rb_fstring(real);
rb_hash_aset(realpaths, real, Qtrue);
+ rb_hash_aset(realpath_map, path, real);
}
}
ec->errinfo = saved.errinfo;
@@ -1376,11 +1306,11 @@ ruby_require_internal(const char *fname, unsigned int len)
VALUE
rb_require_string(VALUE fname)
{
- return rb_require_string_internal(FilePathValue(fname), false);
+ return rb_require_string_internal(FilePathValue(fname));
}
static VALUE
-rb_require_string_internal(VALUE fname, bool resurrect)
+rb_require_string_internal(VALUE fname)
{
rb_execution_context_t *ec = GET_EC();
int result = require_internal(ec, fname, 1, RTEST(ruby_verbose));
@@ -1389,7 +1319,6 @@ rb_require_string_internal(VALUE fname, bool resurrect)
EC_JUMP_TAG(ec, result);
}
if (result < 0) {
- if (resurrect) fname = rb_str_resurrect(fname);
load_failed(fname);
}
@@ -1401,7 +1330,7 @@ rb_require(const char *fname)
{
struct RString fake;
VALUE str = rb_setup_fake_str(&fake, fname, strlen(fname), 0);
- return rb_require_string_internal(str, true);
+ return rb_require_string_internal(str);
}
static int
@@ -1451,9 +1380,9 @@ ruby_init_ext(const char *name, void (*init)(void))
* A.autoload(:B, "b")
* A::B.doit # autoloads "b"
*
- * If _const_ in _mod_ is defined as autoload, the file name to be
- * loaded is replaced with _filename_. If _const_ is defined but not
- * as autoload, does nothing.
+ * If _const_ in _mod_ is defined as autoload, the file name to be
+ * loaded is replaced with _filename_. If _const_ is defined but not
+ * as autoload, does nothing.
*/
static VALUE
@@ -1515,9 +1444,9 @@ rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
*
* autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
*
- * If _const_ is defined as autoload, the file name to be loaded is
- * replaced with _filename_. If _const_ is defined but not as
- * autoload, does nothing.
+ * If _const_ is defined as autoload, the file name to be loaded is
+ * replaced with _filename_. If _const_ is defined but not as
+ * autoload, does nothing.
*/
static VALUE
@@ -1535,22 +1464,10 @@ rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
* autoload?(name, inherit=true) -> String or nil
*
* Returns _filename_ to be loaded if _name_ is registered as
- * +autoload+ in the current namespace or one of its ancestors.
+ * +autoload+.
*
* autoload(:B, "b")
* autoload?(:B) #=> "b"
- *
- * module C
- * autoload(:D, "d")
- * autoload?(:D) #=> "d"
- * autoload?(:B) #=> nil
- * end
- *
- * class E
- * autoload(:F, "f")
- * autoload?(:F) #=> "f"
- * autoload?(:B) #=> "b"
- * end
*/
static VALUE
@@ -1564,37 +1481,6 @@ rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
return rb_mod_autoload_p(argc, argv, klass);
}
-void *
-rb_ext_resolve_symbol(const char* fname, const char* symbol)
-{
- VALUE handle;
- VALUE resolved;
- VALUE path;
- char *ext;
- VALUE fname_str = rb_str_new_cstr(fname);
-
- resolved = rb_resolve_feature_path((VALUE)NULL, fname_str);
- if (NIL_P(resolved)) {
- ext = strrchr(fname, '.');
- if (!ext || !IS_SOEXT(ext)) {
- rb_str_cat_cstr(fname_str, ".so");
- }
- if (rb_feature_p(GET_VM(), fname, 0, FALSE, FALSE, 0)) {
- return dln_symbol(NULL, symbol);
- }
- return NULL;
- }
- if (RARRAY_LEN(resolved) != 2 || rb_ary_entry(resolved, 0) != ID2SYM(rb_intern("so"))) {
- return NULL;
- }
- path = rb_ary_entry(resolved, 1);
- handle = rb_hash_lookup(ruby_dln_libmap, path);
- if (NIL_P(handle)) {
- return NULL;
- }
- return dln_symbol((void *)NUM2SVALUE(handle), symbol);
-}
-
void
Init_load(void)
{
@@ -1629,6 +1515,6 @@ Init_load(void)
rb_define_global_function("autoload", rb_f_autoload, 2);
rb_define_global_function("autoload?", rb_f_autoload_p, -1);
- ruby_dln_libmap = rb_hash_new_with_size(0);
- rb_vm_register_global_object(ruby_dln_libmap);
+ ruby_dln_librefs = rb_ary_hidden_new(0);
+ rb_gc_register_mark_object(ruby_dln_librefs);
}
diff --git a/main.c b/main.c
index 92363d3fb7..c87355e46e 100644
--- a/main.c
+++ b/main.c
@@ -20,14 +20,9 @@
#undef RUBY_EXPORT
#include "ruby.h"
#include "vm_debug.h"
-#include "internal/sanitizers.h"
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
-#if USE_SHARED_GC
-#include "internal/gc.h"
-#endif
-
#if defined RUBY_DEVEL && !defined RUBY_DEBUG_ENV
# define RUBY_DEBUG_ENV 1
#endif
@@ -48,10 +43,16 @@ int rb_wasm_rt_start(int (main)(int argc, char **argv), int argc, char **argv);
#define rb_main(argc, argv) rb_wasm_rt_start(rb_main, argc, argv)
#endif
+#ifdef _WIN32
+#define main(argc, argv) w32_main(argc, argv)
+static int main(int argc, char **argv);
+int wmain(void) {return main(0, NULL);}
+#endif
+
int
main(int argc, char **argv)
{
-#if defined(RUBY_DEBUG_ENV) || USE_RUBY_DEBUG_LOG
+#ifdef RUBY_DEBUG_ENV
ruby_set_debug_option(getenv("RUBY_DEBUG"));
#endif
#ifdef HAVE_LOCALE_H
@@ -61,14 +62,3 @@ main(int argc, char **argv)
ruby_sysinit(&argc, &argv);
return rb_main(argc, argv);
}
-
-#ifdef RUBY_ASAN_ENABLED
-/* Compile in the ASAN options Ruby needs, rather than relying on environment variables, so
- * that even tests which fork ruby with a clean environment will run ASAN with the right
- * settings */
-const char *
-__asan_default_options(void)
-{
- return "use_sigaltstack=0:detect_leaks=0";
-}
-#endif
diff --git a/man/irb.1 b/man/irb.1
index 93ef9b8f66..c589c99c78 100644
--- a/man/irb.1
+++ b/man/irb.1
@@ -140,13 +140,6 @@ Use autocompletion.
Don't use autocompletion.
.Pp
.Pp
-.It Fl -regexp-completor
-Use regexp based completion.
-.Pp
-.It Fl -type-completor
-Use type based completion.
-.Pp
-.Pp
.It Fl -verbose
Show details.
.Pp
diff --git a/man/ruby.1 b/man/ruby.1
index 905c712f4c..86ad73c2ab 100644
--- a/man/ruby.1
+++ b/man/ruby.1
@@ -25,7 +25,6 @@
.Op Fl - Ns Bro Cm enable Ns | Ns Cm disable Brc Ns - Ns Ar FEATURE
.Op Fl -dump Ns = Ns Ar target
.Op Fl -verbose
-.Op Fl -crash-report Ns = Ns Ar template
.Op Fl -
.Op Ar program_file
.Op Ar argument ...
@@ -101,10 +100,10 @@ different character encodings, without dependence on Unicode.
.It Sy "Bignums"
With built-in bignums, you can for example calculate factorial(400).
.Pp
-.It Sy "Reflection and domain-specific languages"
+.It Sy "Reflection and domain specific languages"
Class is also an instance of the Class class. Definition of classes and methods
is an expression just as 1+1 is. So your programs can even write and modify programs.
-Thus, you can write your application in your own programming language on top of Ruby.
+Thus you can write your application in your own programming language on top of Ruby.
.Pp
.It Sy "Exception handling"
As in Java(tm).
@@ -272,11 +271,6 @@ In auto-split mode, Ruby executes
.Dl $F = $_.split
at beginning of each loop.
.Pp
-.It Fl -backtrace-limit Ns = Ns Ar num
-Limits the maximum length of backtraces to
-.Ar num
-lines (default -1, meaning no limit).
-.Pp
.It Fl c
Causes Ruby to check the syntax of the script and exit without
executing. If there are no syntax errors, Ruby will print
@@ -394,7 +388,7 @@ before executing script.
.Pp
.It Fl y
.It Fl -yydebug
-This option is not guaranteed to be compatible.
+DO NOT USE.
.Pp
Turns on compiler debug mode. Ruby will print a bunch of internal
state messages during compilation. Only specify this switch you are going to
@@ -430,7 +424,7 @@ Dump some information.
Prints the specified target.
.Ar target
can be one of:
-.Bl -hang -offset indent -width "version"
+.Bl -hang -offset indent
.It Sy version
Print version description (same as
.Fl -version).
@@ -448,20 +442,18 @@ Check syntax (same as
.El
.Pp
Or one of the following, which are intended for debugging the interpreter:
-.Bl -hang -offset indent -width "parsetree"
+.Bl -hang -offset indent -tag -width "parsetree_with_comment"
.It Sy yydebug
Enable compiler debug mode (same as
.Fl -yydebug).
.It Sy parsetree
Print a textual representation of the Ruby AST for the program.
+.It Sy parsetree_with_comment
+Print a textual representation of the Ruby AST for the program, but with each node annoted with the associated Ruby source code.
.It Sy insns
Print a list of disassembled bytecode instructions.
-.It Sy -optimize
-Disable various optimizations to print a list disassembled bytecode instructions.
-.It Sy +error-tolerant
-Enable error-tolerant parsing, when yydebug or parsetree.
-.It Sy +comment
-Annotate a textual representation of the Ruby AST for the program with the associated Ruby source code.
+.It Sy insns_without_opt
+Print the list of disassembled bytecode instructions before various optimizations have been applied.
.El
.Pp
.It Fl -verbose
@@ -472,12 +464,6 @@ variable to true.
If this switch is given, and no script arguments (script file or
.Fl e
options) are present, Ruby quits immediately.
-.Pp
-.It Fl -crash-report Ns = Ns Ar template
-Sets the template of path name to save crash report.
-See
-.Ev RUBY_CRASH_REPORT
-environment variable for details.
.El
.Pp
.Sh ENVIRONMENT
@@ -517,32 +503,6 @@ enabled for only mswin32, mingw32, and OS/2 platforms. If this
variable is not defined, Ruby refers to
.Ev COMSPEC .
.Pp
-.It Ev RUBY_FREE_AT_EXIT
-If set, Ruby tries to free all dynamically allocated memories.
-Introduced in Ruby 3.3, default: unset.
-.Pp
-.It Ev RUBY_IO_BUFFER_DEFAULT_SIZE
-The custom default buffer size of
-.Li IO::Buffer .
-.Pp
-.It Ev RUBY_MAX_CPU
-The maximum number of native threads used by M:N Threads scheduler
-Introduced in Ruby 3.3, default: 8.
-.Pp
-.It Ev RUBY_MN_THREADS
-If set to
-.Li 1 ,
-M:N Thread scheduler is enabled on the main Ractor.
-Introduced in Ruby 3.3, default: unset.
-.Pp
-.It Ev RUBY_PAGER
-The pager command that will be used for
-.Fl -help
-option.
-Introduced in Ruby 3.0, default:
-.Ev PAGER
-environment variable.
-.Pp
.It Ev PATH
Ruby refers to the
.Ev PATH
@@ -565,7 +525,7 @@ malloc family of C standard library calls (
.Xr calloc 3 ,
and
.Xr realloc 3 ) .
-In this documentation, the "heap" refers to the Ruby object heap
+In this documentatation, the "heap" refers to the Ruby object heap
of fixed-sized slots, while "malloc" refers to auxiliary
allocations commonly referred to as the "process heap".
Thus there are at least two possible ways to trigger GC:
@@ -587,16 +547,10 @@ Reaching the old malloc limit.
.El
.Pp
There are currently 4 possible areas where the GC may be tuned by
-the following environment variables:
-.Bl -hang -compact -width "RUBY_GC_HEAP_n_INIT_SLOTS"
-.Pp
-.It Ev RUBY_GC_HEAP_ Ns Ar n Ns Ev _INIT_SLOTS
-Initial allocation of slots in a specific heap.
-The available heaps can be found in the keys of
-.Li GC.stat_heap .
-.Ar n
-is a decimal number between 0 and 4.
-Introduced in Ruby 3.3.
+the following 11 environment variables:
+.Bl -hang -compact -width "RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR"
+.It Ev RUBY_GC_HEAP_INIT_SLOTS
+Initial allocation slots. Introduced in Ruby 2.1, default: 10000.
.Pp
.It Ev RUBY_GC_HEAP_FREE_SLOTS
Prepare at least this amount of slots after GC.
@@ -618,12 +572,6 @@ where R is this factor and N is the number of old objects after the
last full GC.
Introduced in Ruby 2.1.1, default: 2.0
.Pp
-.It Ev RUBY_GC_HEAP_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO
-Used to calculate the
-.Li remembered_wb_unprotected_objects_limit
-using a ratio of
-.Li old_objects .
-Introduced in Ruby 3.3, default: 0.1, minimum: 0.0
.It Ev RUBY_GC_MALLOC_LIMIT
The initial limit of young generation allocation from the malloc-family.
GC will start when this limit is reached.
@@ -640,31 +588,6 @@ GC frequency but increasing malloc growth until RUBY_GC_MALLOC_LIMIT_MAX
is reached.
Introduced in Ruby 2.1, default: 1.4, minimum: 1.0 (no growth)
.Pp
-.It Ev RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO
-Allocate additional pages when the number of free slots is
-lower than the value
-.Li (total_slots * (this ratio)) .
-Introduced in Ruby 2.4, default: 0.2, minimum: 0.0, maximum: 1.0
-.Pp
-.It Ev RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO
-Allow to free pages when the number of free slots is greater than the value
-.Li (total_slots * (this ratio)) .
-Introduced in Ruby 2.4, default: 0.4, minimum:
-.Li RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO,
-maximum: 1.0
-.Pp
-.It Ev RUBY_GC_HEAP_FREE_SLOTS_GOAL_RATIO
-Allocate slots to satisfy this formula:
-.Li free_slots = total_slots * goal_ratio
-In other words, prepare
-.Li (total_slots * goal_ratio)
-free slots.
-if this value is 0.0, then use RUBY_GC_HEAP_GROWTH_FACTOR directly.
-Introduced in Ruby 2.4, default: 0.65, minimum:
-.Li RUBY_GC_HEAP_FREE_SLOTS_MIN_RATIO,
-maximum:
-.Li RUBY_GC_HEAP_FREE_SLOTS_MAX_RATIO
-.Pp
.It Ev RUBY_GC_OLDMALLOC_LIMIT
The initial limit of old generation allocation from malloc,
a full GC will start when this limit is reached.
@@ -682,11 +605,6 @@ GC frequency but increasing malloc growth until RUBY_GC_OLDMALLOC_LIMIT_MAX
is reached.
Introduced in Ruby 2.1, default: 1.2, minimum: 1.0 (no growth)
.Pp
-.It Ev RUBY_SHARED_FIBER_POOL_FREE_STACKS
-Frees stacks of pooled fibers, if set to 1.
-Do not free the stacks if set to 0.
-Introduced in Ruby 2.7, default: 1 (no growth)
-.Pp
.El
.Sh STACK SIZE ENVIRONMENT
Stack size environment variables are implementation-dependent and
@@ -717,61 +635,6 @@ Machine stack size used at fiber creation.
default: 262144 or 524288
.Pp
.El
-.Sh CRASH REPORT ENVIRONMENT
-.Pp
-.Bl -tag -compact -width "RUBY_CRASH_REPORT"
-.It Ev RUBY_CRASH_REPORT
-The template of path name to save crash report.
-default: none
-.El
-.Ss Naming crash report files
-The template can contain
-.Li \fB%\fP
-specifiers which are substituted by the following values when a crash
-report file is created:
-.Pp
-.Bl -hang -compact -width "%NNN"
-.It Li \fB%%\fP
-A single
-.Li \fB%\fP
-character.
-.It Li \fB%e\fP
-Basename of executable.
-.It Li \fB%E\fP
-Pathname of executable,
-with slashes (\fB/\fP) replaced by exclamation marks (\fB!\fP).
-.It Li \fB%f\fP
-Basename of the program name,
-.Li "$0" .
-.It Li \fB%F\fP
-Pathname of the program name,
-.Li "$0",
-with slashes (\fB/\fP) replaced by exclamation marks (\fB!\fP).
-.It Li \fB%p\fP
-PID of dumped process.
-.It Li \fB%t\fP
-Time of dump, expressed as seconds since the
-Epoch, 1970-01-01 00:00:00 +0000 (UTC).
-.It Li \fB%NNN\fP
-A character code in octal.
-.El
-.Pp
-A single
-.Li \fB%\fP
-at the end of the template is dropped from the core filename, as is
-the combination of a
-.Li \fB%\fP
-followed by any character other than those listed above. All other
-characters in the template become a literal part of the core filename.
-The template may include \(aq/\(aq characters, which are interpreted
-as delimiters for directory names.
-.Ss Piping crash reports to a program
-If the first character of this file is a pipe symbol (\fB|\fP),
-then the remainder of the line is interpreted as the command-line for
-a program (or script) that is to be executed.
-.Pp
-The pipe template is split on spaces into an argument list before the
-template parameters are expanded.
.Sh SEE ALSO
.Bl -hang -compact -width "https://www.ruby-toolbox.com/"
.It Lk https://www.ruby-lang.org/
@@ -799,5 +662,5 @@ Ruby is designed and implemented by
.An Yukihiro Matsumoto Aq matz@netlab.jp .
.Pp
See
-.Aq Lk https://github.com/ruby/ruby/graphs/contributors
+.Aq Lk https://bugs.ruby-lang.org/projects/ruby/wiki/Contributors
for contributors to Ruby.
diff --git a/marshal.c b/marshal.c
index c0bc2dd6da..4ea4255971 100644
--- a/marshal.c
+++ b/marshal.c
@@ -40,6 +40,7 @@
#include "ruby/util.h"
#include "builtin.h"
#include "shape.h"
+#include "ruby/internal/attr/nonstring.h"
#define BITSPERSHORT (2*CHAR_BIT)
#define SHORTMASK ((1<<BITSPERSHORT)-1)
@@ -128,6 +129,22 @@ static VALUE compat_allocator_tbl_wrapper;
static VALUE rb_marshal_dump_limited(VALUE obj, VALUE port, int limit);
static VALUE rb_marshal_load_with_proc(VALUE port, VALUE proc, bool freeze);
+static int
+mark_marshal_compat_i(st_data_t key, st_data_t value, st_data_t _)
+{
+ marshal_compat_t *p = (marshal_compat_t *)value;
+ rb_gc_mark(p->newclass);
+ rb_gc_mark(p->oldclass);
+ return ST_CONTINUE;
+}
+
+static void
+mark_marshal_compat_t(void *tbl)
+{
+ if (!tbl) return;
+ st_foreach(tbl, mark_marshal_compat_i, 0);
+}
+
static st_table *compat_allocator_table(void);
void
@@ -140,10 +157,11 @@ rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE (*dumper)(VALUE),
rb_raise(rb_eTypeError, "no allocator");
}
- compat_allocator_table();
compat = ALLOC(marshal_compat_t);
- RB_OBJ_WRITE(compat_allocator_tbl_wrapper, &compat->newclass, newclass);
- RB_OBJ_WRITE(compat_allocator_tbl_wrapper, &compat->oldclass, oldclass);
+ compat->newclass = Qnil;
+ compat->oldclass = Qnil;
+ compat->newclass = newclass;
+ compat->oldclass = oldclass;
compat->dumper = dumper;
compat->loader = loader;
@@ -156,7 +174,7 @@ struct dump_arg {
st_table *data;
st_table *compat_tbl;
st_table *encodings;
- st_index_t num_entries;
+ unsigned long num_entries;
};
struct dump_call_arg {
@@ -211,24 +229,19 @@ static void
free_dump_arg(void *ptr)
{
clear_dump_arg(ptr);
+ xfree(ptr);
}
static size_t
memsize_dump_arg(const void *ptr)
{
- const struct dump_arg *p = (struct dump_arg *)ptr;
- size_t memsize = 0;
- if (p->symbols) memsize += rb_st_memsize(p->symbols);
- if (p->data) memsize += rb_st_memsize(p->data);
- if (p->compat_tbl) memsize += rb_st_memsize(p->compat_tbl);
- if (p->encodings) memsize += rb_st_memsize(p->encodings);
- return memsize;
+ return sizeof(struct dump_arg);
}
static const rb_data_type_t dump_arg_data = {
"dump_arg",
{mark_dump_arg, free_dump_arg, memsize_dump_arg,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static VALUE
@@ -449,7 +462,7 @@ w_float(double d, struct dump_arg *arg)
memcpy(buf + len, p, digs);
len += digs;
}
- free(p);
+ xfree(p);
w_bytes(buf, len, arg);
}
}
@@ -511,12 +524,12 @@ hash_each(VALUE key, VALUE value, VALUE v)
#define SINGLETON_DUMP_UNABLE_P(klass) \
(rb_id_table_size(RCLASS_M_TBL(klass)) > 0 || \
- rb_ivar_count(klass) > 0)
+ rb_ivar_count(klass) > 1)
static void
w_extended(VALUE klass, struct dump_arg *arg, int check)
{
- if (check && RCLASS_SINGLETON_P(klass)) {
+ if (check && FL_TEST(klass, FL_SINGLETON)) {
VALUE origin = RCLASS_ORIGIN(klass);
if (SINGLETON_DUMP_UNABLE_P(klass) ||
(origin != klass && SINGLETON_DUMP_UNABLE_P(origin))) {
@@ -593,18 +606,20 @@ struct w_ivar_arg {
};
static int
-w_obj_each(ID id, VALUE value, st_data_t a)
+w_obj_each(st_data_t key, st_data_t val, st_data_t a)
{
+ ID id = (ID)key;
+ VALUE value = (VALUE)val;
struct w_ivar_arg *ivarg = (struct w_ivar_arg *)a;
struct dump_call_arg *arg = ivarg->dump;
if (to_be_skipped_id(id)) {
if (id == s_encoding_short) {
- rb_warn("instance variable '"name_s_encoding_short"' on class %"PRIsVALUE" is not dumped",
+ rb_warn("instance variable `"name_s_encoding_short"' on class %"PRIsVALUE" is not dumped",
CLASS_OF(arg->obj));
}
if (id == s_ruby2_keywords_flag) {
- rb_warn("instance variable '"name_s_ruby2_keywords_flag"' on class %"PRIsVALUE" is not dumped",
+ rb_warn("instance variable `"name_s_ruby2_keywords_flag"' on class %"PRIsVALUE" is not dumped",
CLASS_OF(arg->obj));
}
return ST_CONTINUE;
@@ -616,8 +631,9 @@ w_obj_each(ID id, VALUE value, st_data_t a)
}
static int
-obj_count_ivars(ID id, VALUE val, st_data_t a)
+obj_count_ivars(st_data_t key, st_data_t val, st_data_t a)
{
+ ID id = (ID)key;
if (!to_be_skipped_id(id) && UNLIKELY(!++*(st_index_t *)a)) {
rb_raise(rb_eRuntimeError, "too many instance variables");
}
@@ -1257,24 +1273,19 @@ static void
free_load_arg(void *ptr)
{
clear_load_arg(ptr);
+ xfree(ptr);
}
static size_t
memsize_load_arg(const void *ptr)
{
- const struct load_arg *p = (struct load_arg *)ptr;
- size_t memsize = 0;
- if (p->symbols) memsize += rb_st_memsize(p->symbols);
- if (p->data) memsize += rb_st_memsize(p->data);
- if (p->partial_objects) memsize += rb_st_memsize(p->partial_objects);
- if (p->compat_tbl) memsize += rb_st_memsize(p->compat_tbl);
- return memsize;
+ return sizeof(struct load_arg);
}
static const rb_data_type_t load_arg_data = {
"load_arg",
{mark_load_arg, free_load_arg, memsize_load_arg,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
#define r_entry(v, arg) r_entry0((v), (arg)->data->num_entries, (arg))
@@ -1491,7 +1502,7 @@ name_equal(const char *name, size_t nlen, const char *p, long l)
static int
sym2encidx(VALUE sym, VALUE val)
{
- static const char name_encoding[8] = "encoding";
+ RBIMPL_ATTR_NONSTRING() static const char name_encoding[8] = "encoding";
const char *p;
long l;
if (rb_enc_get_index(sym) != ENCINDEX_US_ASCII) return -1;
@@ -1663,9 +1674,10 @@ r_leave(VALUE v, struct load_arg *arg, bool partial)
}
static int
-copy_ivar_i(ID vid, VALUE value, st_data_t arg)
+copy_ivar_i(st_data_t key, st_data_t val, st_data_t arg)
{
- VALUE obj = (VALUE)arg;
+ VALUE obj = (VALUE)arg, value = (VALUE)val;
+ ID vid = (ID)key;
if (!rb_ivar_defined(obj, vid))
rb_ivar_set(obj, vid, value);
@@ -1679,11 +1691,6 @@ r_copy_ivar(VALUE v, VALUE data)
return v;
}
-#define override_ivar_error(type, str) \
- rb_raise(rb_eTypeError, \
- "can't override instance variable of "type" '%"PRIsVALUE"'", \
- (str))
-
static void
r_ivar(VALUE obj, int *has_encoding, struct load_arg *arg)
{
@@ -1691,12 +1698,6 @@ r_ivar(VALUE obj, int *has_encoding, struct load_arg *arg)
len = r_long(arg);
if (len > 0) {
- if (RB_TYPE_P(obj, T_MODULE)) {
- override_ivar_error("module", rb_mod_name(obj));
- }
- else if (RB_TYPE_P(obj, T_CLASS)) {
- override_ivar_error("class", rb_class_name(obj));
- }
do {
VALUE sym = r_symbol(arg);
VALUE val = r_object(arg);
@@ -1789,7 +1790,9 @@ append_extmod(VALUE obj, VALUE extmod)
#define prohibit_ivar(type, str) do { \
if (!ivp || !*ivp) break; \
- override_ivar_error(type, str); \
+ rb_raise(rb_eTypeError, \
+ "can't override instance variable of "type" `%"PRIsVALUE"'", \
+ (str)); \
} while (0)
static VALUE r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int type);
@@ -1801,6 +1804,20 @@ r_object0(struct load_arg *arg, bool partial, int *ivp, VALUE extmod)
return r_object_for(arg, partial, ivp, extmod, type);
}
+static int
+r_move_ivar(st_data_t k, st_data_t v, st_data_t d)
+{
+ ID key = (ID)k;
+ VALUE value = (VALUE)v;
+ VALUE dest = (VALUE)d;
+
+ if (rb_is_instance_id(key)) {
+ rb_ivar_set(dest, key, value);
+ return ST_DELETE;
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int type)
{
@@ -1862,7 +1879,6 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
rb_extend_object(v, m);
}
}
- v = r_leave(v, arg, partial);
}
break;
@@ -1881,7 +1897,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
goto type_hash;
}
v = r_object_for(arg, partial, 0, extmod, type);
- if (RB_SPECIAL_CONST_P(v) || RB_TYPE_P(v, T_OBJECT) || RB_TYPE_P(v, T_CLASS)) {
+ if (rb_special_const_p(v) || RB_TYPE_P(v, T_OBJECT) || RB_TYPE_P(v, T_CLASS)) {
goto format_error;
}
if (RB_TYPE_P(v, T_MODULE) || !RTEST(rb_class_inherited_p(c, RBASIC(v)->klass))) {
@@ -2018,7 +2034,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
rb_str_set_len(str, dst - ptr);
}
VALUE regexp = rb_reg_new_str(str, options);
- r_copy_ivar(regexp, str);
+ rb_ivar_foreach(str, r_move_ivar, regexp);
v = r_entry0(regexp, idx, arg);
v = r_leave(v, arg, partial);
@@ -2125,7 +2141,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
st_data_t d;
if (!rb_obj_respond_to(klass, s_load, TRUE)) {
- rb_raise(rb_eTypeError, "class %"PRIsVALUE" needs to have method '_load'",
+ rb_raise(rb_eTypeError, "class %"PRIsVALUE" needs to have method `_load'",
name);
}
data = r_string(arg);
@@ -2139,12 +2155,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
marshal_compat_t *compat = (marshal_compat_t*)d;
v = compat->loader(klass, v);
}
- if (!partial) {
- if (arg->freeze) {
- OBJ_FREEZE(v);
- }
- v = r_post_proc(v, arg);
- }
+ if (!partial) v = r_post_proc(v, arg);
}
break;
@@ -2161,7 +2172,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
append_extmod(v, extmod);
}
if (!rb_obj_respond_to(v, s_mload, TRUE)) {
- rb_raise(rb_eTypeError, "instance of %"PRIsVALUE" needs to have method 'marshal_load'",
+ rb_raise(rb_eTypeError, "instance of %"PRIsVALUE" needs to have method `marshal_load'",
name);
}
v = r_entry(v, arg);
@@ -2169,9 +2180,6 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
load_funcall(arg, v, s_mload, 1, &data);
v = r_fixup_compat(v, arg);
v = r_copy_ivar(v, data);
- if (arg->freeze) {
- OBJ_FREEZE(v);
- }
v = r_post_proc(v, arg);
if (!NIL_P(extmod)) {
if (oldclass) append_extmod(v, extmod);
@@ -2207,7 +2215,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ
v = r_entry(v, arg);
if (!rb_obj_respond_to(v, s_load_data, TRUE)) {
rb_raise(rb_eTypeError,
- "class %"PRIsVALUE" needs to have instance method '_load_data'",
+ "class %"PRIsVALUE" needs to have instance method `_load_data'",
name);
}
r = r_object0(arg, partial, 0, extmod);
@@ -2286,8 +2294,10 @@ r_object(struct load_arg *arg)
static void
clear_load_arg(struct load_arg *arg)
{
- xfree(arg->buf);
- arg->buf = NULL;
+ if (arg->buf) {
+ xfree(arg->buf);
+ arg->buf = 0;
+ }
arg->buflen = 0;
arg->offset = 0;
arg->readable = 0;
@@ -2507,77 +2517,16 @@ Init_marshal(void)
rb_define_const(rb_mMarshal, "MINOR_VERSION", INT2FIX(MARSHAL_MINOR));
}
-static int
-marshal_compat_table_mark_i(st_data_t key, st_data_t value, st_data_t _)
-{
- marshal_compat_t *p = (marshal_compat_t *)value;
- rb_gc_mark_movable(p->newclass);
- rb_gc_mark_movable(p->oldclass);
- return ST_CONTINUE;
-}
-
-static void
-marshal_compat_table_mark(void *tbl)
-{
- if (!tbl) return;
- st_foreach(tbl, marshal_compat_table_mark_i, 0);
-}
-
-static int
-marshal_compat_table_free_i(st_data_t key, st_data_t value, st_data_t _)
-{
- xfree((marshal_compat_t *)value);
- return ST_CONTINUE;
-}
-
-static void
-marshal_compat_table_free(void *data)
-{
- st_foreach(data, marshal_compat_table_free_i, 0);
- st_free_table(data);
-}
-
-static size_t
-marshal_compat_table_memsize(const void *data)
-{
- return st_memsize(data) + sizeof(marshal_compat_t) * st_table_size(data);
-}
-
-static int
-marshal_compat_table_compact_i(st_data_t key, st_data_t value, st_data_t _)
-{
- marshal_compat_t *p = (marshal_compat_t *)value;
- p->newclass = rb_gc_location(p->newclass);
- p->oldclass = rb_gc_location(p->oldclass);
- return ST_CONTINUE;
-}
-
-static void
-marshal_compat_table_compact(void *tbl)
-{
- if (!tbl) return;
- st_foreach(tbl, marshal_compat_table_compact_i, 0);
-}
-
-static const rb_data_type_t marshal_compat_type = {
- .wrap_struct_name = "marshal_compat_table",
- .function = {
- .dmark = marshal_compat_table_mark,
- .dfree = marshal_compat_table_free,
- .dsize = marshal_compat_table_memsize,
- .dcompact = marshal_compat_table_compact,
- },
- .flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY,
-};
-
static st_table *
compat_allocator_table(void)
{
if (compat_allocator_tbl) return compat_allocator_tbl;
compat_allocator_tbl = st_init_numtable();
+#undef RUBY_UNTYPED_DATA_WARNING
+#define RUBY_UNTYPED_DATA_WARNING 0
compat_allocator_tbl_wrapper =
- TypedData_Wrap_Struct(0, &marshal_compat_type, compat_allocator_tbl);
- rb_vm_register_global_object(compat_allocator_tbl_wrapper);
+ Data_Wrap_Struct(0, mark_marshal_compat_t, 0, compat_allocator_tbl);
+ rb_gc_register_mark_object(compat_allocator_tbl_wrapper);
return compat_allocator_tbl;
}
diff --git a/math.c b/math.c
index 2394fe9f58..67bf8b7b63 100644
--- a/math.c
+++ b/math.c
@@ -170,12 +170,6 @@ math_tan(VALUE unused_obj, VALUE x)
return DBL2NUM(tan(Get_Double(x)));
}
-#define math_arc(num, func) \
- double d; \
- d = Get_Double((num)); \
- domain_check_range(d, -1.0, 1.0, #func); \
- return DBL2NUM(func(d));
-
/*
* call-seq:
* Math.acos(x) -> float
@@ -196,7 +190,11 @@ math_tan(VALUE unused_obj, VALUE x)
static VALUE
math_acos(VALUE unused_obj, VALUE x)
{
- math_arc(x, acos)
+ double d;
+
+ d = Get_Double(x);
+ domain_check_range(d, -1.0, 1.0, "acos");
+ return DBL2NUM(acos(d));
}
/*
@@ -219,7 +217,11 @@ math_acos(VALUE unused_obj, VALUE x)
static VALUE
math_asin(VALUE unused_obj, VALUE x)
{
- math_arc(x, asin)
+ double d;
+
+ d = Get_Double(x);
+ domain_check_range(d, -1.0, 1.0, "asin");
+ return DBL2NUM(asin(d));
}
/*
@@ -474,6 +476,7 @@ math_exp(VALUE unused_obj, VALUE x)
# define M_LN10 2.30258509299404568401799145468436421
#endif
+static double math_log1(VALUE x);
FUNC_MINIMIZED(static VALUE math_log(int, const VALUE *, VALUE));
/*
@@ -508,6 +511,20 @@ math_log(int argc, const VALUE *argv, VALUE unused_obj)
return rb_math_log(argc, argv);
}
+VALUE
+rb_math_log(int argc, const VALUE *argv)
+{
+ VALUE x, base;
+ double d;
+
+ rb_scan_args(argc, argv, "11", &x, &base);
+ d = math_log1(x);
+ if (argc == 2) {
+ d /= math_log1(base);
+ }
+ return DBL2NUM(d);
+}
+
static double
get_double_rshift(VALUE x, size_t *pnumbits)
{
@@ -526,51 +543,16 @@ get_double_rshift(VALUE x, size_t *pnumbits)
}
static double
-math_log_split(VALUE x, size_t *numbits)
+math_log1(VALUE x)
{
- double d = get_double_rshift(x, numbits);
+ size_t numbits;
+ double d = get_double_rshift(x, &numbits);
domain_check_min(d, 0.0, "log");
- return d;
-}
-
-#if defined(log2) || defined(HAVE_LOG2)
-# define log_intermediate log2
-#else
-# define log_intermediate log10
-double log2(double x);
-#endif
-
-VALUE
-rb_math_log(int argc, const VALUE *argv)
-{
- VALUE x, base;
- double d;
- size_t numbits;
+ /* check for pole error */
+ if (d == 0.0) return -HUGE_VAL;
- argc = rb_scan_args(argc, argv, "11", &x, &base);
- d = math_log_split(x, &numbits);
- if (argc == 2) {
- size_t numbits_2;
- double b = math_log_split(base, &numbits_2);
- /* check for pole error */
- if (d == 0.0) {
- // Already DomainError if b < 0.0
- return b ? DBL2NUM(-HUGE_VAL) : DBL2NUM(NAN);
- }
- else if (b == 0.0) {
- return DBL2NUM(-0.0);
- }
- d = log_intermediate(d) / log_intermediate(b);
- d += (numbits - numbits_2) / log2(b);
- }
- else {
- /* check for pole error */
- if (d == 0.0) return DBL2NUM(-HUGE_VAL);
- d = log(d);
- d += numbits * M_LN2;
- }
- return DBL2NUM(d);
+ return log(d) + numbits * M_LN2; /* log(d * 2 ** numbits) */
}
#ifndef log2
@@ -731,7 +713,7 @@ rb_math_sqrt(VALUE x)
* cbrt(1.0) # => 1.0
* cbrt(0.0) # => 0.0
* cbrt(1.0) # => 1.0
- * cbrt(2.0) # => 1.2599210498948732
+ cbrt(2.0) # => 1.2599210498948732
* cbrt(8.0) # => 2.0
* cbrt(27.0) # => 3.0
* cbrt(INFINITY) # => Infinity
diff --git a/memory_view.c b/memory_view.c
index 519aad2ca1..3fb79202f9 100644
--- a/memory_view.c
+++ b/memory_view.c
@@ -845,7 +845,9 @@ rb_memory_view_release(rb_memory_view_t* view)
if (rv) {
unregister_exported_object(view->obj);
view->obj = Qnil;
- xfree((void *)view->item_desc.components);
+ if (view->item_desc.components) {
+ xfree((void *)view->item_desc.components);
+ }
}
return rv;
}
@@ -863,7 +865,7 @@ Init_MemoryView(void)
VALUE obj = TypedData_Wrap_Struct(
0, &rb_memory_view_exported_object_registry_data_type,
exported_object_table);
- rb_vm_register_global_object(obj);
+ rb_gc_register_mark_object(obj);
rb_memory_view_exported_object_registry = obj;
id_memory_view = rb_intern_const("__memory_view__");
diff --git a/method.h b/method.h
index fdc7c263d1..ec89bf26bb 100644
--- a/method.h
+++ b/method.h
@@ -136,9 +136,8 @@ typedef struct rb_method_iseq_struct {
rb_cref_t * cref; /*!< class reference, should be marked */
} rb_method_iseq_t; /* check rb_add_method_iseq() when modify the fields */
-typedef VALUE (*rb_cfunc_t)(ANYARGS);
typedef struct rb_method_cfunc_struct {
- rb_cfunc_t func;
+ VALUE (*func)(ANYARGS);
VALUE (*invoker)(VALUE recv, int argc, const VALUE *argv, VALUE (*func)(ANYARGS));
int argc;
} rb_method_cfunc_t;
@@ -154,6 +153,7 @@ typedef struct rb_method_alias_struct {
typedef struct rb_method_refined_struct {
struct rb_method_entry_struct * orig_me;
+ VALUE owner;
} rb_method_refined_t;
typedef struct rb_method_bmethod_struct {
@@ -200,7 +200,7 @@ struct rb_method_definition_struct {
struct rb_id_table;
typedef struct rb_method_definition_struct rb_method_definition_t;
-STATIC_ASSERT(sizeof_method_def, offsetof(rb_method_definition_t, body) <= 8);
+STATIC_ASSERT(sizeof_method_def, offsetof(rb_method_definition_t, body)==8);
#define UNDEFINED_METHOD_ENTRY_P(me) (!(me) || !(me)->def || (me)->def->type == VM_METHOD_TYPE_UNDEF)
#define UNDEFINED_REFINED_METHOD_P(def) \
@@ -250,6 +250,6 @@ void rb_scope_visibility_set(rb_method_visibility_t);
VALUE rb_unnamed_parameters(int arity);
void rb_clear_method_cache(VALUE klass_or_module, ID mid);
-void rb_clear_all_refinement_method_cache(void);
+void rb_clear_method_cache_all(void);
#endif /* RUBY_METHOD_H */
diff --git a/mini_builtin.c b/mini_builtin.c
index 2fbc00234d..c263d1ee71 100644
--- a/mini_builtin.c
+++ b/mini_builtin.c
@@ -6,85 +6,50 @@
#include "miniprelude.c"
-static VALUE
-prelude_ast_value(VALUE name, VALUE code, int line)
-{
- rb_ast_t *ast;
- VALUE ast_value = rb_parser_compile_string_path(rb_parser_new(), name, code, line);
- ast = rb_ruby_ast_data_get(ast_value);
- if (!ast || !ast->body.root) {
- if (ast) rb_ast_dispose(ast);
- rb_exc_raise(rb_errinfo());
- }
- return ast_value;
-}
+// included from miniinit.c
-static void
-pm_prelude_load(pm_parse_result_t *result, VALUE name, VALUE code, int line)
-{
- pm_options_line_set(&result->options, line);
- VALUE error = pm_parse_string(result, code, name, NULL);
+#ifndef INCLUDED_BY_BUILTIN_C
+static struct st_table *loaded_builtin_table;
+#endif
- if (!NIL_P(error)) {
- pm_parse_result_free(result);
- rb_exc_raise(error);
- }
-}
+rb_ast_t *rb_builtin_ast(const char *feature_name, VALUE *name_str);
static const rb_iseq_t *
builtin_iseq_load(const char *feature_name, const struct rb_builtin_function *table)
{
VALUE name_str = 0;
- int start_line;
- const rb_iseq_t *iseq;
- VALUE code = rb_builtin_find(feature_name, &name_str, &start_line);
- if (NIL_P(code)) {
- rb_fatal("builtin_iseq_load: can not find %s; "
- "probably miniprelude.c is out of date",
- feature_name);
- }
-
+ rb_ast_t *ast = rb_builtin_ast(feature_name, &name_str);
rb_vm_t *vm = GET_VM();
+
+ vm->builtin_function_table = table;
+ vm->builtin_inline_index = 0;
static const rb_compile_option_t optimization = {
- .inline_const_cache = TRUE,
- .peephole_optimization = TRUE,
- .tailcall_optimization = FALSE,
- .specialized_instruction = TRUE,
- .operands_unification = TRUE,
- .instructions_unification = TRUE,
- .frozen_string_literal = TRUE,
- .debug_frozen_string_literal = FALSE,
- .coverage_enabled = FALSE,
- .debug_level = 0,
+ TRUE, /* int inline_const_cache; */
+ TRUE, /* int peephole_optimization; */
+ FALSE,/* int tailcall_optimization; */
+ TRUE, /* int specialized_instruction; */
+ TRUE, /* int operands_unification; */
+ TRUE, /* int instructions_unification; */
+ TRUE, /* int stack_caching; */
+ TRUE, /* int frozen_string_literal; */
+ FALSE, /* int debug_frozen_string_literal; */
+ FALSE, /* unsigned int coverage_enabled; */
+ 0, /* int debug_level; */
};
+ const rb_iseq_t *iseq = rb_iseq_new_with_opt(&ast->body, name_str, name_str, Qnil, 0, NULL, 0, ISEQ_TYPE_TOP, &optimization);
+ GET_VM()->builtin_function_table = NULL;
- if (rb_ruby_prism_p()) {
- pm_parse_result_t result = { 0 };
- pm_prelude_load(&result, name_str, code, start_line);
-
- vm->builtin_function_table = table;
- iseq = pm_iseq_new_with_opt(&result.node, name_str, name_str, Qnil, 0, NULL, 0, ISEQ_TYPE_TOP, &optimization);
-
- vm->builtin_function_table = NULL;
- pm_parse_result_free(&result);
- }
- else {
- VALUE ast_value = prelude_ast_value(name_str, code, start_line);
- rb_ast_t *ast = rb_ruby_ast_data_get(ast_value);
-
- vm->builtin_function_table = table;
- iseq = rb_iseq_new_with_opt(ast_value, name_str, name_str, Qnil, 0, NULL, 0, ISEQ_TYPE_TOP, &optimization, Qnil);
-
- vm->builtin_function_table = NULL;
- rb_ast_dispose(ast);
- }
+ rb_ast_dispose(ast);
// for debug
if (0 && strcmp("prelude", feature_name) == 0) {
rb_io_write(rb_stdout, rb_iseq_disasm((const rb_iseq_t *)iseq));
}
- BUILTIN_LOADED(feature_name, iseq);
+#ifndef INCLUDED_BY_BUILTIN_C
+ st_insert(loaded_builtin_table, (st_data_t)feature_name, (st_data_t)iseq);
+ rb_gc_register_mark_object((VALUE)iseq);
+#endif
return iseq;
}
@@ -95,3 +60,38 @@ rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin
const rb_iseq_t *iseq = builtin_iseq_load(feature_name, table);
rb_iseq_eval(iseq);
}
+
+#ifndef INCLUDED_BY_BUILTIN_C
+
+static int
+each_builtin_i(st_data_t key, st_data_t val, st_data_t dmy)
+{
+ const char *feature = (const char *)key;
+ const rb_iseq_t *iseq = (const rb_iseq_t *)val;
+
+ rb_yield_values(2, rb_str_new2(feature), rb_iseqw_new(iseq));
+
+ return ST_CONTINUE;
+}
+
+static VALUE
+each_builtin(VALUE self)
+{
+ st_foreach(loaded_builtin_table, each_builtin_i, 0);
+ return Qnil;
+}
+
+void
+Init_builtin(void)
+{
+ rb_define_singleton_method(rb_cRubyVM, "each_builtin", each_builtin, 0);
+ loaded_builtin_table = st_init_strtable();
+}
+
+void
+Init_builtin_features(void)
+{
+ // register for ruby
+ builtin_iseq_load("gem_prelude", NULL);
+}
+#endif
diff --git a/miniinit.c b/miniinit.c
index b0adf9da2a..2a14a0d1c5 100644
--- a/miniinit.c
+++ b/miniinit.c
@@ -48,62 +48,4 @@ Init_enc(void)
rb_encdb_alias("ASCII", "US-ASCII");
}
-/* miniruby does not support dynamic loading. */
-void
-Init_ext(void)
-{
-}
-
-static void builtin_loaded(const char *feature_name, VALUE iseq);
-#define BUILTIN_LOADED(feature_name, iseq) builtin_loaded(feature_name, (VALUE)(iseq))
-
#include "mini_builtin.c"
-
-static struct st_table *loaded_builtin_table;
-
-static void
-builtin_loaded(const char *feature_name, VALUE iseq)
-{
- st_insert(loaded_builtin_table, (st_data_t)feature_name, (st_data_t)iseq);
- rb_vm_register_global_object(iseq);
-}
-
-static int
-each_builtin_i(st_data_t key, st_data_t val, st_data_t dmy)
-{
- const char *feature = (const char *)key;
- const rb_iseq_t *iseq = (const rb_iseq_t *)val;
-
- rb_yield_values(2, rb_str_new2(feature), rb_iseqw_new(iseq));
-
- return ST_CONTINUE;
-}
-
-/* :nodoc: */
-static VALUE
-each_builtin(VALUE self)
-{
- st_foreach(loaded_builtin_table, each_builtin_i, 0);
- return Qnil;
-}
-
-void
-Init_builtin(void)
-{
- rb_define_singleton_method(rb_cRubyVM, "each_builtin", each_builtin, 0);
- loaded_builtin_table = st_init_strtable();
-}
-
-void
-Init_builtin_features(void)
-{
- // register for ruby
- builtin_iseq_load("gem_prelude", NULL);
-}
-
-void
-rb_free_loaded_builtin_table(void)
-{
- if (loaded_builtin_table)
- st_free_table(loaded_builtin_table);
-}
diff --git a/misc/.vscode/launch.json b/misc/.vscode/launch.json
deleted file mode 100644
index 51bfef09d7..0000000000
--- a/misc/.vscode/launch.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "version": "0.2.0",
- "configurations": [
- {
- "type": "lldb",
- "name": "Run ruby",
- "request": "launch",
- "program": "${workspaceFolder}/ruby",
- "args": ["test.rb"],
- "preLaunchTask": "${defaultBuildTask}"
- }
- ]
-}
diff --git a/misc/.vscode/settings.json b/misc/.vscode/settings.json
deleted file mode 100644
index 7b1a38c536..0000000000
--- a/misc/.vscode/settings.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "rust-analyzer.cargo.features": [
- "disasm",
- ],
- "rust-analyzer.cargo.unsetTest": [
- "yjit",
- ],
-}
diff --git a/misc/.vscode/tasks.json b/misc/.vscode/tasks.json
deleted file mode 100644
index 045fe7e5c0..0000000000
--- a/misc/.vscode/tasks.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "version": "2.0.0",
- "tasks": [
- {
- "label": "build",
- "type": "shell",
- "command": "make -j",
- "group": {
- "kind": "build",
- "isDefault": true
- }
- }
- ]
-}
diff --git a/misc/README b/misc/README
index 86b680e724..1728b42700 100644
--- a/misc/README
+++ b/misc/README
@@ -4,4 +4,3 @@ rb_optparse.zsh zsh completion script
ruby-style.el Ruby's C/C++ mode style for emacs
lldb_cruby.py LLDB port of debug utility
test_lldb_cruby.rb test file for LLDB port
-.vscode example VSCode config to debug Ruby
diff --git a/misc/call_fuzzer.rb b/misc/call_fuzzer.rb
deleted file mode 100644
index c3f9f90490..0000000000
--- a/misc/call_fuzzer.rb
+++ /dev/null
@@ -1,372 +0,0 @@
-require 'optparse'
-require 'set'
-
-# Number of iterations to test
-num_iters = 10_000
-
-# Parse the command-line options
-OptionParser.new do |opts|
- opts.on("--num-iters=N") do |n|
- num_iters = n.to_i
- end
-end.parse!
-
-# Format large numbers with comma separators for readability
-def format_number(pad, number)
- s = number.to_s
- i = s.index('.') || s.size
- s.insert(i -= 3, ',') while i > 3
- s.rjust(pad, ' ')
-end
-
-# Wrap an integer to pass as argument
-# We use this so we can have some object arguments
-class IntWrapper
- def initialize(v)
- # Force the object to have a random shape
- if rand() < 50
- @v0 = 1
- end
- if rand() < 50
- @v1 = 1
- end
- if rand() < 50
- @v2 = 1
- end
- if rand() < 50
- @v3 = 1
- end
- if rand() < 50
- @v4 = 1
- end
- if rand() < 50
- @v5 = 1
- end
- if rand() < 50
- @v6 = 1
- end
-
- @value = v
- end
-
- attr_reader :value
-end
-
-# Generate a random argument value, integer or string or object
-def sample_arg()
- c = ['int', 'string', 'object'].sample()
-
- if c == 'int'
- return rand(0...100)
- end
-
- if c == 'string'
- return 'f' * rand(0...100)
- end
-
- if c == 'object'
- return IntWrapper.new(rand(0...100))
- end
-
- raise "should not get here"
-end
-
-# Evaluate the value of an argument with respect to the checksum
-def arg_val(arg)
- if arg.kind_of? Integer
- return arg
- end
-
- if arg.kind_of? String
- return arg.length
- end
-
- if arg.kind_of? Object
- return arg.value
- end
-
- raise "unknown arg type"
-end
-
-# List of parameters/arguments for a method
-class ParamList
- def initialize()
- self.sample_params()
- self.sample_args()
- end
-
- # Sample/generate a random set of parameters for a method
- def sample_params()
- # Choose how many positional arguments to use, and how many are optional
- num_pargs = rand(10)
- @opt_parg_idx = rand(num_pargs)
- @num_opt_pargs = rand(num_pargs + 1 - @opt_parg_idx)
- @num_pargs_req = num_pargs - @num_opt_pargs
- @pargs = (0...num_pargs).map do |i|
- {
- :name => "p#{i}",
- :optional => (i >= @opt_parg_idx && i < @opt_parg_idx + @num_opt_pargs)
- }
- end
-
- # Choose how many kwargs to use, and how many are optional
- num_kwargs = rand(10)
- @kwargs = (0...num_kwargs).map do |i|
- {
- :name => "k#{i}",
- :optional => rand() < 0.5
- }
- end
-
- # Choose whether to have rest parameters or not
- @has_rest = @num_opt_pargs == 0 && rand() < 0.5
- @has_kwrest = rand() < 0.25
-
- # Choose whether to have a named block parameter or not
- @has_block_param = rand() < 0.25
- end
-
- # Sample/generate a random set of arguments corresponding to the parameters
- def sample_args()
- # Choose how many positional args to pass
- num_pargs_passed = rand(@num_pargs_req..@pargs.size)
-
- # How many optional arguments will be filled
- opt_pargs_filled = num_pargs_passed - @num_pargs_req
-
- @pargs.each_with_index do |parg, i|
- if parg[:optional]
- parg[:default] = rand(100)
- end
-
- if !parg[:optional] || i < @opt_parg_idx + opt_pargs_filled
- parg[:argval] = rand(100)
- end
- end
-
- @kwargs.each_with_index do |kwarg, i|
- if kwarg[:optional]
- kwarg[:default] = rand(100)
- end
-
- if !kwarg[:optional] || rand() < 0.5
- kwarg[:argval] = rand(100)
- end
- end
-
- # Randomly pass a block or not
- @block_arg = nil
- if rand() < 0.5
- @block_arg = rand(100)
- end
- end
-
- # Compute the expected checksum of arguments ahead of time
- def compute_checksum()
- checksum = 0
-
- @pargs.each_with_index do |arg, i|
- value = (arg.key? :argval)? arg[:argval]:arg[:default]
- checksum += (i+1) * arg_val(value)
- end
-
- @kwargs.each_with_index do |arg, i|
- value = (arg.key? :argval)? arg[:argval]:arg[:default]
- checksum += (i+1) * arg_val(value)
- end
-
- if @block_arg
- if @has_block_param
- checksum += arg_val(@block_arg)
- end
-
- checksum += arg_val(@block_arg)
- end
-
- checksum
- end
-
- # Generate code for the method signature and method body
- def gen_method_str()
- m_str = "def m("
-
- @pargs.each do |arg|
- if !m_str.end_with?("(")
- m_str += ", "
- end
-
- m_str += arg[:name]
-
- # If this has a default value
- if arg[:optional]
- m_str += " = #{arg[:default]}"
- end
- end
-
- if @has_rest
- if !m_str.end_with?("(")
- m_str += ", "
- end
- m_str += "*rest"
- end
-
- @kwargs.each do |arg|
- if !m_str.end_with?("(")
- m_str += ", "
- end
-
- m_str += "#{arg[:name]}:"
-
- # If this has a default value
- if arg[:optional]
- m_str += " #{arg[:default]}"
- end
- end
-
- if @has_kwrest
- if !m_str.end_with?("(")
- m_str += ", "
- end
- m_str += "**kwrest"
- end
-
- if @has_block_param
- if !m_str.end_with?("(")
- m_str += ", "
- end
-
- m_str += "&block"
- end
-
- m_str += ")\n"
-
- # Add some useless locals
- rand(0...16).times do |i|
- m_str += "local#{i} = #{i}\n"
- end
-
- # Add some useless if statements
- @pargs.each_with_index do |arg, i|
- if rand() < 50
- m_str += "if #{arg[:name]} > 4; end\n"
- end
- end
-
- m_str += "checksum = 0\n"
-
- @pargs.each_with_index do |arg, i|
- m_str += "checksum += #{i+1} * arg_val(#{arg[:name]})\n"
- end
-
- @kwargs.each_with_index do |arg, i|
- m_str += "checksum += #{i+1} * arg_val(#{arg[:name]})\n"
- end
-
- if @has_block_param
- m_str += "if block; r = block.call; checksum += arg_val(r); end\n"
- end
-
- m_str += "if block_given?; r = yield; checksum += arg_val(r); end\n"
-
- if @has_rest
- m_str += "raise 'rest is not array' unless rest.kind_of?(Array)\n"
- m_str += "raise 'rest size not integer' unless rest.size.kind_of?(Integer)\n"
- end
-
- if @has_kwrest
- m_str += "raise 'kwrest is not a hash' unless kwrest.kind_of?(Hash)\n"
- m_str += "raise 'kwrest size not integer' unless kwrest.size.kind_of?(Integer)\n"
- end
-
- m_str += "checksum\n"
- m_str += "end"
-
- m_str
- end
-
- # Generate code to call into the method and pass the arguments
- def gen_call_str()
- c_str = "m("
-
- @pargs.each_with_index do |arg, i|
- if !arg.key? :argval
- next
- end
-
- if !c_str.end_with?("(")
- c_str += ", "
- end
-
- c_str += "#{arg[:argval]}"
- end
-
- @kwargs.each_with_index do |arg, i|
- if !arg.key? :argval
- next
- end
-
- if !c_str.end_with?("(")
- c_str += ", "
- end
-
- c_str += "#{arg[:name]}: #{arg[:argval]}"
- end
-
- c_str += ")"
-
- # Randomly pass a block or not
- if @block_arg
- c_str += " { #{@block_arg} }"
- end
-
- c_str
- end
-end
-
-iseqs_compiled_start = RubyVM::YJIT.runtime_stats[:compiled_iseq_entry]
-start_time = Time.now.to_f
-
-num_iters.times do |i|
- puts "Iteration #{i}"
-
- lst = ParamList.new()
- m_str = lst.gen_method_str()
- c_str = lst.gen_call_str()
- checksum = lst.compute_checksum()
-
- f = Object.new
-
- # Define the method on f
- puts "Defining"
- p m_str
- f.instance_eval(m_str)
- #puts RubyVM::InstructionSequence.disasm(f.method(:m))
- #exit 0
-
- puts "Calling"
- c_str = "f.#{c_str}"
- p c_str
- r = eval(c_str)
- puts "checksum=#{r}"
-
- if r != checksum
- raise "return value #{r} doesn't match checksum #{checksum}"
- end
-
- puts ""
-end
-
-# Make sure that YJIT actually compiled the tests we ran
-# Should be run with --yjit-call-threshold=1
-iseqs_compiled_end = RubyVM::YJIT.runtime_stats[:compiled_iseq_entry]
-if iseqs_compiled_end - iseqs_compiled_start < num_iters
- raise "YJIT did not compile enough ISEQs"
-end
-
-puts "Code region size: #{ format_number(0, RubyVM::YJIT.runtime_stats[:code_region_size]) }"
-
-end_time = Time.now.to_f
-itrs_per_sec = num_iters / (end_time - start_time)
-itrs_per_hour = 3600 * itrs_per_sec
-puts "#{'%.1f' % itrs_per_sec} iterations/s"
-puts "#{format_number(0, itrs_per_hour.round)} iterations/hour"
diff --git a/misc/call_fuzzer.sh b/misc/call_fuzzer.sh
deleted file mode 100755
index cf4ec76fe8..0000000000
--- a/misc/call_fuzzer.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-# Stop at first error
-set -e
-
-# TODO
-# TODO: boost --num-iters to 1M+ for actual test
-# TODO
-export NUM_ITERS=25000
-
-# Enable code GC so we don't stop compiling when we hit the code size limit
-ruby --yjit-call-threshold=1 --yjit-code-gc misc/call_fuzzer.rb --num-iters=$NUM_ITERS
-
-# Do another pass with --verify-ctx
-ruby --yjit-call-threshold=1 --yjit-code-gc --yjit-verify-ctx misc/call_fuzzer.rb --num-iters=$NUM_ITERS
diff --git a/misc/gdb.py b/misc/gdb.py
deleted file mode 100644
index 6034a389bb..0000000000
--- a/misc/gdb.py
+++ /dev/null
@@ -1,181 +0,0 @@
-import argparse
-import textwrap
-
-# usage: [-h] [-a | --all | --no-all] [-s STACK_SIZE] [uplevel]
-#
-# Dump a control frame
-#
-# positional arguments:
-# uplevel CFP offset from the stack top
-#
-# options:
-# -h, --help show this help message and exit
-# -a, --all, --no-all dump all frames
-# -s STACK_SIZE, --stack-size STACK_SIZE
-# override stack_size (useful for JIT frames)
-class CFP(gdb.Command):
- FRAME_MAGICS = [
- # frame types
- 'VM_FRAME_MAGIC_METHOD',
- 'VM_FRAME_MAGIC_BLOCK',
- 'VM_FRAME_MAGIC_CLASS',
- 'VM_FRAME_MAGIC_TOP',
- 'VM_FRAME_MAGIC_CFUNC',
- 'VM_FRAME_MAGIC_IFUNC',
- 'VM_FRAME_MAGIC_EVAL',
- 'VM_FRAME_MAGIC_RESCUE',
- 'VM_FRAME_MAGIC_DUMMY',
- ]
- FRAME_FLAGS = [
- # frame flag
- 'VM_FRAME_FLAG_FINISH',
- 'VM_FRAME_FLAG_BMETHOD',
- 'VM_FRAME_FLAG_CFRAME',
- 'VM_FRAME_FLAG_LAMBDA',
- 'VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM',
- 'VM_FRAME_FLAG_CFRAME_KW',
- 'VM_FRAME_FLAG_PASSED',
- # env flag
- 'VM_ENV_FLAG_LOCAL',
- 'VM_ENV_FLAG_ESCAPED',
- 'VM_ENV_FLAG_WB_REQUIRED',
- 'VM_ENV_FLAG_ISOLATED',
- ]
-
- def __init__(self):
- super(CFP, self).__init__('cfp', gdb.COMMAND_USER)
-
- self.parser = argparse.ArgumentParser(description='Dump a control frame')
- self.parser.add_argument('uplevel', type=int, nargs='?', default=0, help='CFP offset from the stack top')
- self.parser.add_argument('-a', '--all', action=argparse.BooleanOptionalAction, help='dump all frames')
- self.parser.add_argument('-s', '--stack-size', type=int, help='override stack_size (useful for JIT frames)')
-
- def invoke(self, args, from_tty):
- try:
- args = self.parser.parse_args(args.split())
- except SystemExit:
- return
- cfp = f'(ruby_current_ec->cfp + ({args.uplevel}))'
- end_cfp = self.get_int('ruby_current_ec->vm_stack + ruby_current_ec->vm_stack_size')
- cfp_index = int((end_cfp - self.get_int(cfp) - 1) / self.get_int('sizeof(rb_control_frame_t)'))
-
- if args.all:
- cfp_count = int((end_cfp - self.get_int('ruby_current_ec->cfp')) / self.get_int('sizeof(rb_control_frame_t)')) - 1 # exclude dummy CFP
- for i in range(cfp_count):
- print('-' * 80)
- self.invoke(str(cfp_count - i - 1), from_tty)
- return
-
- print('CFP (addr=0x{:x}, index={}):'.format(self.get_int(cfp), cfp_index))
- gdb.execute(f'p *({cfp})')
- print()
-
- if self.get_int(f'{cfp}->iseq'):
- local_size = self.get_int(f'{cfp}->iseq->body->local_table_size - {cfp}->iseq->body->param.size')
- param_size = self.get_int(f'{cfp}->iseq->body->param.size')
-
- if local_size:
- print(f'Params (size={param_size}):')
- for i in range(-3 - local_size - param_size, -3 - local_size):
- self.print_stack(cfp, i, self.rp(cfp, i))
- print()
-
- if param_size:
- print(f'Locals (size={local_size}):')
- for i in range(-3 - local_size, -3):
- self.print_stack(cfp, i, self.rp(cfp, i))
- print()
-
- print('Env:')
- self.print_env(cfp, -3, self.rp_env(cfp, -3))
- self.print_env(cfp, -2, self.specval(cfp, -2))
- self.print_env(cfp, -1, self.frame_types(cfp, -1))
- print()
-
- # We can't calculate BP for the first frame.
- # vm_base_ptr doesn't work for C frames either.
- if cfp_index > 0 and self.get_int(f'{cfp}->iseq'):
- if args.stack_size is not None:
- stack_size = args.stack_size
- else:
- stack_size = int((self.get_int(f'{cfp}->sp') - self.get_int(f'vm_base_ptr({cfp})')) / 8)
- print(f'Stack (size={stack_size}):')
- for i in range(0, stack_size):
- self.print_stack(cfp, i, self.rp(cfp, i))
- print(self.regs(cfp, stack_size))
-
- def print_env(self, cfp, bp_index, content):
- ep_index = bp_index + 1
- address = self.get_int(f'((rb_control_frame_t *){cfp})->ep + {ep_index}')
- value = self.get_env(cfp, bp_index)
- regs = self.regs(cfp, bp_index)
- if content:
- content = textwrap.indent(content, ' ' * 3).lstrip() # Leave the regs column empty
- content = f'{content} '
- print('{:2} 0x{:x} [{}] {}(0x{:x})'.format(regs, address, bp_index, content, value))
-
- def print_stack(self, cfp, bp_index, content):
- address = self.get_int(f'vm_base_ptr({cfp}) + {bp_index}')
- value = self.get_value(cfp, bp_index)
- regs = self.regs(cfp, bp_index)
- if content:
- content = textwrap.indent(content, ' ' * 3).lstrip() # Leave the regs column empty
- content = f'{content} '
- print('{:2} 0x{:x} [{}] {}(0x{:x})'.format(regs, address, bp_index, content, value))
-
- def regs(self, cfp, bp_index):
- address = self.get_int(f'vm_base_ptr({cfp}) + {bp_index}')
- regs = []
- for reg, field in { 'EP': 'ep', 'SP': 'sp' }.items():
- if address == self.get_int(f'{cfp}->{field}'):
- regs.append(reg)
- return ' '.join(regs)
-
- def rp(self, cfp, bp_index):
- value = self.get_value(cfp, bp_index)
- return self.get_string(f'rp {value}').rstrip()
-
- def rp_env(self, cfp, bp_index):
- value = self.get_env(cfp, bp_index)
- return self.get_string(f'rp {value}').rstrip()
-
- # specval: block_handler or previous EP
- def specval(self, cfp, bp_index):
- value = self.get_env(cfp, bp_index)
- if value == 0:
- return 'VM_BLOCK_HANDLER_NONE'
- if value == self.get_int('rb_block_param_proxy'):
- return 'rb_block_param_proxy'
- return ''
-
- def frame_types(self, cfp, bp_index):
- types = []
- value = self.get_env(cfp, bp_index)
-
- magic_mask = self.get_int('VM_FRAME_MAGIC_MASK')
- for magic in self.FRAME_MAGICS:
- magic_value = self.get_int(magic)
- if value & magic_mask == magic_value:
- types.append(magic)
-
- for flag in self.FRAME_FLAGS:
- flag_value = self.get_int(flag)
- if value & flag_value:
- types.append(flag)
-
- return ' | '.join(types)
-
- def get_env(self, cfp, bp_index):
- ep_index = bp_index + 1
- return self.get_int(f'((rb_control_frame_t *){cfp})->ep[{ep_index}]')
-
- def get_value(self, cfp, bp_index):
- return self.get_int(f'vm_base_ptr({cfp})[{bp_index}]')
-
- def get_int(self, expr):
- return int(self.get_string(f'printf "%ld", ({expr})'))
-
- def get_string(self, expr):
- return gdb.execute(expr, to_string=True)
-
-CFP()
diff --git a/misc/lldb_cruby.py b/misc/lldb_cruby.py
index 0707bb42d3..9ef9d3967b 100755
--- a/misc/lldb_cruby.py
+++ b/misc/lldb_cruby.py
@@ -197,16 +197,18 @@ def string2cstr(rstring):
flags = rstring.GetValueForExpressionPath(".basic->flags").unsigned
if flags & RUBY_T_MASK != RUBY_T_STRING:
raise TypeError("not a string")
- clen = int(rstring.GetValueForExpressionPath(".len").value, 0)
if flags & RUBY_FL_USER1:
cptr = int(rstring.GetValueForExpressionPath(".as.heap.ptr").value, 0)
+ clen = int(rstring.GetValueForExpressionPath(".as.heap.len").value, 0)
else:
cptr = int(rstring.GetValueForExpressionPath(".as.embed.ary").location, 0)
+ clen = int(rstring.GetValueForExpressionPath(".as.embed.len").value, 0)
return cptr, clen
def output_string(debugger, result, rstring):
cptr, clen = string2cstr(rstring)
- append_expression(debugger, "*(const char (*)[%d])%0#x" % (clen, cptr), result)
+ expr = "print *(const char (*)[%d])%0#x" % (clen, cptr)
+ append_command_output(debugger, expr, result)
def fixnum_p(x):
return x & RUBY_FIXNUM_FLAG != 0
@@ -225,9 +227,6 @@ def append_command_output(debugger, command, result):
result.write(output1)
result.write(output2)
-def append_expression(debugger, expression, result):
- append_command_output(debugger, "expression " + expression, result)
-
def lldb_rp(debugger, command, result, internal_dict):
if not ('RUBY_Qfalse' in globals()):
lldb_init(debugger)
@@ -259,13 +258,13 @@ def lldb_inspect(debugger, target, result, val):
elif fixnum_p(num):
print(num >> 1, file=result)
elif flonum_p(num):
- append_expression(debugger, "rb_float_value(%0#x)" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "print rb_float_value(%0#x)" % val.GetValueAsUnsigned(), result)
elif static_sym_p(num):
if num < 128:
print("T_SYMBOL: %c" % num, file=result)
else:
print("T_SYMBOL: (%x)" % num, file=result)
- append_expression(debugger, "rb_id2name(%0#x)" % (num >> 8), result)
+ append_command_output(debugger, "p rb_id2name(%0#x)" % (num >> 8), result)
elif num & RUBY_IMMEDIATE_MASK:
print('immediate(%x)' % num, file=result)
else:
@@ -293,13 +292,13 @@ def lldb_inspect(debugger, target, result, val):
print('T_NIL: %s%s' % (flaginfo, val.Dereference()), file=result)
elif flType == RUBY_T_OBJECT:
result.write('T_OBJECT: %s' % flaginfo)
- append_expression(debugger, "*(struct RObject*)%0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "print *(struct RObject*)%0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_CLASS or flType == RUBY_T_MODULE or flType == RUBY_T_ICLASS:
result.write('T_%s: %s' % ('CLASS' if flType == RUBY_T_CLASS else 'MODULE' if flType == RUBY_T_MODULE else 'ICLASS', flaginfo))
- append_expression(debugger, "*(struct RClass*)%0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "print *(struct RClass*)%0#x" % val.GetValueAsUnsigned(), result)
tRClass = target.FindFirstType("struct RClass")
if not val.Cast(tRClass).GetChildMemberWithName("ptr").IsValid():
- append_expression(debugger, "*(struct rb_classext_struct*)%0#x" % (val.GetValueAsUnsigned() + tRClass.GetByteSize()), result)
+ append_command_output(debugger, "print *(struct rb_classext_struct*)%0#x" % (val.GetValueAsUnsigned() + tRClass.GetByteSize()), result)
elif flType == RUBY_T_STRING:
result.write('T_STRING: %s' % flaginfo)
encidx = ((flags & RUBY_ENCODING_MASK)>>RUBY_ENCODING_SHIFT)
@@ -313,12 +312,12 @@ def lldb_inspect(debugger, target, result, val):
if len == 0:
result.write("(empty)\n")
else:
- append_expression(debugger, "*(const char (*)[%d])%0#x" % (len, ptr), result)
+ append_command_output(debugger, "print *(const char (*)[%d])%0#x" % (len, ptr), result)
elif flType == RUBY_T_SYMBOL:
result.write('T_SYMBOL: %s' % flaginfo)
tRSymbol = target.FindFirstType("struct RSymbol").GetPointerType()
val = val.Cast(tRSymbol)
- append_expression(debugger, '(ID)%0#x ' % val.GetValueForExpressionPath("->id").GetValueAsUnsigned(), result)
+ append_command_output(debugger, 'print (ID)%0#x ' % val.GetValueForExpressionPath("->id").GetValueAsUnsigned(), result)
tRString = target.FindFirstType("struct RString").GetPointerType()
output_string(debugger, result, val.GetValueForExpressionPath("->fstr").Cast(tRString))
elif flType == RUBY_T_ARRAY:
@@ -344,12 +343,12 @@ def lldb_inspect(debugger, target, result, val):
else:
result.write("\n")
if ptr.GetValueAsSigned() == 0:
- append_expression(debugger, "-fx -- ((struct RArray*)%0#x)->as.ary" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "expression -fx -- ((struct RArray*)%0#x)->as.ary" % val.GetValueAsUnsigned(), result)
else:
- append_expression(debugger, "-Z %d -fx -- (const VALUE*)%0#x" % (len, ptr.GetValueAsUnsigned()), result)
+ append_command_output(debugger, "expression -Z %d -fx -- (const VALUE*)%0#x" % (len, ptr.GetValueAsUnsigned()), result)
elif flType == RUBY_T_HASH:
result.write("T_HASH: %s" % flaginfo)
- append_expression(debugger, "*(struct RHash *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RHash *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_BIGNUM:
tRBignum = target.FindFirstType("struct RBignum").GetPointerType()
val = val.Cast(tRBignum)
@@ -357,15 +356,15 @@ def lldb_inspect(debugger, target, result, val):
if flags & RUBY_FL_USER2:
len = ((flags & (RUBY_FL_USER3|RUBY_FL_USER4|RUBY_FL_USER5)) >> (RUBY_FL_USHIFT+3))
print("T_BIGNUM: sign=%s len=%d (embed)" % (sign, len), file=result)
- append_expression(debugger, "((struct RBignum *) %0#x)->as.ary" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "print ((struct RBignum *) %0#x)->as.ary" % val.GetValueAsUnsigned(), result)
else:
len = val.GetValueForExpressionPath("->as.heap.len").GetValueAsSigned()
print("T_BIGNUM: sign=%s len=%d" % (sign, len), file=result)
print(val.Dereference(), file=result)
- append_expression(debugger, "-Z %x -fx -- (const BDIGIT*)((struct RBignum*)%d)->as.heap.digits" % (len, val.GetValueAsUnsigned()), result)
- # append_expression(debugger, "((struct RBignum *) %0#x)->as.heap.digits / %d" % (val.GetValueAsUnsigned(), len), result)
+ append_command_output(debugger, "expression -Z %x -fx -- (const BDIGIT*)((struct RBignum*)%d)->as.heap.digits" % (len, val.GetValueAsUnsigned()), result)
+ # append_command_output(debugger, "x ((struct RBignum *) %0#x)->as.heap.digits / %d" % (val.GetValueAsUnsigned(), len), result)
elif flType == RUBY_T_FLOAT:
- append_expression(debugger, "((struct RFloat *)%d)->float_value" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "print ((struct RFloat *)%d)->float_value" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_RATIONAL:
tRRational = target.FindFirstType("struct RRational").GetPointerType()
val = val.Cast(tRRational)
@@ -398,39 +397,39 @@ def lldb_inspect(debugger, target, result, val):
flag = val.GetValueForExpressionPath("->typed_flag")
if flag.GetValueAsUnsigned() == 1:
print("T_DATA: %s" % val.GetValueForExpressionPath("->type->wrap_struct_name"), file=result)
- append_expression(debugger, "*(struct RTypedData *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RTypedData *) %0#x" % val.GetValueAsUnsigned(), result)
else:
print("T_DATA:", file=result)
- append_expression(debugger, "*(struct RData *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RData *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_NODE:
tRTypedData = target.FindFirstType("struct RNode").GetPointerType()
nd_type = (flags & RUBY_NODE_TYPEMASK) >> RUBY_NODE_TYPESHIFT
- append_expression(debugger, "(node_type) %d" % nd_type, result)
+ append_command_output(debugger, "p (node_type) %d" % nd_type, result)
val = val.Cast(tRTypedData)
- append_expression(debugger, "*(struct RNode *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RNode *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_MOVED:
tRTypedData = target.FindFirstType("struct RMoved").GetPointerType()
val = val.Cast(tRTypedData)
- append_expression(debugger, "*(struct RMoved *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RMoved *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_MATCH:
tRTypedData = target.FindFirstType("struct RMatch").GetPointerType()
val = val.Cast(tRTypedData)
- append_expression(debugger, "*(struct RMatch *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RMatch *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_IMEMO:
# I'm not sure how to get IMEMO_MASK out of lldb. It's not in globals()
imemo_type = (flags >> RUBY_FL_USHIFT) & 0x0F # IMEMO_MASK
print("T_IMEMO: ", file=result)
- append_expression(debugger, "(enum imemo_type) %d" % imemo_type, result)
- append_expression(debugger, "*(struct MEMO *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p (enum imemo_type) %d" % imemo_type, result)
+ append_command_output(debugger, "p *(struct MEMO *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_STRUCT:
tRTypedData = target.FindFirstType("struct RStruct").GetPointerType()
val = val.Cast(tRTypedData)
- append_expression(debugger, "*(struct RStruct *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RStruct *) %0#x" % val.GetValueAsUnsigned(), result)
elif flType == RUBY_T_ZOMBIE:
tRZombie = target.FindFirstType("struct RZombie").GetPointerType()
val = val.Cast(tRZombie)
- append_expression(debugger, "*(struct RZombie *) %0#x" % val.GetValueAsUnsigned(), result)
+ append_command_output(debugger, "p *(struct RZombie *) %0#x" % val.GetValueAsUnsigned(), result)
else:
print("Not-handled type %0#x" % flType, file=result)
print(val, file=result)
@@ -547,7 +546,7 @@ class HeapPageIter:
self.target = target
self.start = page.GetChildMemberWithName('start').GetValueAsUnsigned();
self.num_slots = page.GetChildMemberWithName('total_slots').unsigned
- self.slot_size = page.GetChildMemberWithName('heap').GetChildMemberWithName('slot_size').unsigned
+ self.slot_size = page.GetChildMemberWithName('size_pool').GetChildMemberWithName('slot_size').unsigned
self.counter = 0
self.tRBasic = target.FindFirstType("struct RBasic")
self.tRValue = target.FindFirstType("struct RVALUE")
@@ -728,13 +727,13 @@ def __lldb_init_module(debugger, internal_dict):
# Register all classes that subclass RbBaseCommand
for memname, mem in inspect.getmembers(sys.modules["lldb_rb.rb_base_command"]):
- if memname == "RbBaseCommand":
+ if inspect.isclass(mem):
for sclass in mem.__subclasses__():
sclass.register_lldb_command(debugger, f"{__name__}.{sclass.__module__}")
## FUNCTION INITS - These should be removed when converted to class commands
- debugger.HandleCommand("command script add -f lldb_cruby.lldb_rp old_rp")
+ debugger.HandleCommand("command script add -f lldb_cruby.lldb_rp rp")
debugger.HandleCommand("command script add -f lldb_cruby.count_objects rb_count_objects")
debugger.HandleCommand("command script add -f lldb_cruby.stack_dump_raw SDR")
debugger.HandleCommand("command script add -f lldb_cruby.dump_node dump_node")
@@ -742,7 +741,7 @@ def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand("command script add -f lldb_cruby.rb_backtrace rbbt")
debugger.HandleCommand("command script add -f lldb_cruby.dump_page dump_page")
debugger.HandleCommand("command script add -f lldb_cruby.dump_page_rvalue dump_page_rvalue")
- debugger.HandleCommand("command script add -f lldb_cruby.rb_id2str old_rb_id2str")
+ debugger.HandleCommand("command script add -f lldb_cruby.rb_id2str rb_id2str")
lldb_rb.rb_base_command.RbBaseCommand.lldb_init(debugger)
diff --git a/misc/lldb_rb/commands/heap_page_command.py b/misc/lldb_rb/commands/heap_page_command.py
index b56a3eae4e..edb74a415b 100644
--- a/misc/lldb_rb/commands/heap_page_command.py
+++ b/misc/lldb_rb/commands/heap_page_command.py
@@ -14,8 +14,8 @@ class HeapPageCommand(RbBaseCommand):
page = self._get_page(self.frame.EvaluateExpression(command))
page.Cast(self.t_heap_page_ptr)
- self._append_expression(debugger, "(struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
- self._append_expression(debugger, "*(struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
+ self._append_command_output(debugger, "p (struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
+ self._append_command_output(debugger, "p *(struct heap_page *) %0#x" % page.GetValueAsUnsigned(), result)
def _get_page(self, val):
addr = val.GetValueAsUnsigned()
diff --git a/misc/lldb_rb/commands/print_flags_command.py b/misc/lldb_rb/commands/print_flags_command.py
deleted file mode 100644
index 00da4834bf..0000000000
--- a/misc/lldb_rb/commands/print_flags_command.py
+++ /dev/null
@@ -1,31 +0,0 @@
-import lldb
-import re
-
-from lldb_rb.constants import *
-from lldb_rb.rb_base_command import RbBaseCommand
-
-class PrintFlagsCommand(RbBaseCommand):
- program = "print_flags"
-
- help_string = "Print out the individial flags of an RVALUE object in human readable format"
-
- # call is where our command logic will be implemented
- def call(self, debugger, command, exe_ctx, result):
- rclass_t = self.target.FindFirstType("struct RBasic")
- rcass_ptr = self.target.EvaluateExpression(command).Cast(rclass_t.GetPointerType())
- obj_flags = rcass_ptr.GetValueForExpressionPath("->flags").GetValueAsUnsigned()
-
- flags = [
- "RUBY_FL_WB_PROTECTED", "RUBY_FL_PROMOTED0", "RUBY_FL_PROMOTED1", "RUBY_FL_FINALIZE",
- "RUBY_FL_SHAREABLE", "RUBY_FL_EXIVAR", "RUBY_FL_FREEZE",
- "RUBY_FL_USER0", "RUBY_FL_USER1", "RUBY_FL_USER2", "RUBY_FL_USER3", "RUBY_FL_USER4",
- "RUBY_FL_USER5", "RUBY_FL_USER6", "RUBY_FL_USER7", "RUBY_FL_USER8", "RUBY_FL_USER9",
- "RUBY_FL_USER10", "RUBY_FL_USER11", "RUBY_FL_USER12", "RUBY_FL_USER13", "RUBY_FL_USER14",
- "RUBY_FL_USER15", "RUBY_FL_USER16", "RUBY_FL_USER17", "RUBY_FL_USER18"
- ]
-
- types_index = {v: k for k, v in self.ruby_globals.items() if re.match(r'RUBY_T_', k)}
- print("TYPE: {}".format(types_index[obj_flags & self.ruby_globals["RUBY_T_MASK"]]))
- for flag in flags:
- output = "{} : {}".format(flag, "1" if (obj_flags & self.ruby_globals[flag]) else "0")
- print(output, file=result)
diff --git a/misc/lldb_rb/commands/rb_id2str_command.py b/misc/lldb_rb/commands/rb_id2str_command.py
deleted file mode 100644
index 6ee859ebf6..0000000000
--- a/misc/lldb_rb/commands/rb_id2str_command.py
+++ /dev/null
@@ -1,49 +0,0 @@
-import lldb
-
-from lldb_rb.constants import *
-from lldb_rb.utils import *
-from lldb_rb.rb_base_command import RbBaseCommand
-
-class RbID2StrCommand(RbBaseCommand):
- program = "rb_id2str"
-
- help_string = "convert and print a Ruby ID to a C string and print it to the LLDB console"
-
- def call(self, debugger, command, exe_ctx, result):
- global_symbols = self.target.FindFirstGlobalVariable("ruby_global_symbols")
-
- id_val = self.frame.EvaluateExpression(command).GetValueAsUnsigned()
- num = self.rb_id_to_serial(id_val)
-
- last_id = global_symbols.GetChildMemberWithName("last_id").GetValueAsUnsigned()
- ID_ENTRY_SIZE = 2
- ID_ENTRY_UNIT = int(self.target.FindFirstGlobalVariable("ID_ENTRY_UNIT").GetValue())
-
- ids = global_symbols.GetChildMemberWithName("ids")
-
- if num <= last_id:
- idx = num // ID_ENTRY_UNIT
- ary = self.rb_ary_entry(ids, idx, result)
- pos = (num % ID_ENTRY_UNIT) * ID_ENTRY_SIZE
- id_str = self.rb_ary_entry(ary, pos, result)
-
- RbInspector(debugger, result, self.ruby_globals).inspect(id_str)
-
- def rb_id_to_serial(self, id_val):
- if id_val > self.ruby_globals["tLAST_OP_ID"]:
- return id_val >> self.ruby_globals["RUBY_ID_SCOPE_SHIFT"]
- else:
- return id_val
-
- def rb_ary_entry(self, ary, idx, result):
- tRArray = self.target.FindFirstType("struct RArray").GetPointerType()
- ary = ary.Cast(tRArray)
- flags = ary.GetValueForExpressionPath("->flags").GetValueAsUnsigned()
-
- if flags & self.ruby_globals["RUBY_FL_USER1"]:
- ptr = ary.GetValueForExpressionPath("->as.ary")
- else:
- ptr = ary.GetValueForExpressionPath("->as.heap.ptr")
-
- ptr_addr = ptr.GetValueAsUnsigned() + (idx * ptr.GetType().GetByteSize())
- return self.target.CreateValueFromAddress("ary_entry[%d]" % idx, lldb.SBAddress(ptr_addr, self.target), ptr.GetType().GetPointeeType())
diff --git a/misc/lldb_rb/commands/rp_command.py b/misc/lldb_rb/commands/rp_command.py
deleted file mode 100644
index 06b2516d50..0000000000
--- a/misc/lldb_rb/commands/rp_command.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import lldb
-
-from lldb_rb.constants import *
-from lldb_rb.utils import *
-from lldb_rb.rb_base_command import RbBaseCommand
-
-class RbID2StrCommand(RbBaseCommand):
- program = "rp"
-
- help_string = "convert and print a Ruby ID to a C string and print it to the LLDB console"
-
- def call(self, debugger, command, exe_ctx, result):
- val = self.frame.EvaluateExpression(command)
- inspector = RbInspector(debugger, result, self.ruby_globals)
- inspector.inspect(val)
diff --git a/misc/lldb_rb/constants.py b/misc/lldb_rb/constants.py
index 9cd56eccb0..ec3050a399 100644
--- a/misc/lldb_rb/constants.py
+++ b/misc/lldb_rb/constants.py
@@ -2,5 +2,3 @@ HEAP_PAGE_ALIGN_LOG = 16
HEAP_PAGE_ALIGN_MASK = (~(~0 << HEAP_PAGE_ALIGN_LOG))
HEAP_PAGE_ALIGN = (1 << HEAP_PAGE_ALIGN_LOG)
HEAP_PAGE_SIZE = HEAP_PAGE_ALIGN
-
-IMEMO_MASK = 0x0F
diff --git a/misc/lldb_rb/lldb_interface.py b/misc/lldb_rb/lldb_interface.py
deleted file mode 100644
index 785a54b3e3..0000000000
--- a/misc/lldb_rb/lldb_interface.py
+++ /dev/null
@@ -1,7 +0,0 @@
-class LLDBInterface:
- def build_environment(self, debugger):
- self.debugger = debugger
- self.target = debugger.GetSelectedTarget()
- self.process = self.target.GetProcess()
- self.thread = self.process.GetSelectedThread()
- self.frame = self.thread.GetSelectedFrame()
diff --git a/misc/lldb_rb/rb_base_command.py b/misc/lldb_rb/rb_base_command.py
index 70a5addd6d..de90a1617c 100644
--- a/misc/lldb_rb/rb_base_command.py
+++ b/misc/lldb_rb/rb_base_command.py
@@ -1,9 +1,7 @@
import lldb
from pydoc import locate
-from lldb_rb.constants import *
-from lldb_rb.utils import *
-class RbBaseCommand(LLDBInterface):
+class RbBaseCommand:
@classmethod
def register_lldb_command(cls, debugger, module_name):
# Add any commands contained in this module to LLDB
@@ -36,14 +34,14 @@ class RbBaseCommand(LLDBInterface):
if name.startswith("RUBY_T_"):
value_types.append(name)
g["value_types"] = value_types
- return g
def __init__(self, debugger, _internal_dict):
- self.ruby_globals = RbBaseCommand.lldb_init(debugger)
self.internal_dict = _internal_dict
def __call__(self, debugger, command, exe_ctx, result):
- self.ruby_globals = RbBaseCommand.lldb_init(debugger)
+ if not ("RUBY_Qfalse" in globals()):
+ RbBaseCommand.lldb_init(debugger)
+
self.build_environment(debugger)
self.call(debugger, command, exe_ctx, result)
@@ -55,3 +53,17 @@ class RbBaseCommand(LLDBInterface):
def get_long_help(self):
return self.__class__.help_string
+
+ def build_environment(self, debugger):
+ self.target = debugger.GetSelectedTarget()
+ self.process = self.target.GetProcess()
+ self.thread = self.process.GetSelectedThread()
+ self.frame = self.thread.GetSelectedFrame()
+
+ def _append_command_output(self, debugger, command, result):
+ output1 = result.GetOutput()
+ debugger.GetCommandInterpreter().HandleCommand(command, result)
+ output2 = result.GetOutput()
+ result.Clear()
+ result.write(output1)
+ result.write(output2)
diff --git a/misc/lldb_rb/rb_heap_structs.py b/misc/lldb_rb/rb_heap_structs.py
deleted file mode 100644
index 86b38dbbbd..0000000000
--- a/misc/lldb_rb/rb_heap_structs.py
+++ /dev/null
@@ -1,143 +0,0 @@
-import lldb
-from lldb_rb.lldb_interface import LLDBInterface
-from lldb_rb.constants import *
-
-class HeapPage(LLDBInterface):
- def __init__(self, debugger, val):
- self.build_environment(debugger)
- self.page_type = self.target.FindFirstType("struct heap_page").GetPointerType()
- self.val = val
-
- def heap_page_body(self, command, ctx, result, internal_dict):
- process = self.target.GetProcess()
- thread = process.GetSelectedThread()
- frame = thread.GetSelectedFrame()
-
- val = frame.EvaluateExpression(command)
- page = self.get_page_body(val)
- print("Page body address: ", page.GetAddress(), file=result)
- print(page, file=result)
-
- def get_page_body(self, val):
- tHeapPageBody = self.target.FindFirstType("struct heap_page_body")
- addr = val.GetValueAsUnsigned()
- page_addr = addr & ~(HEAP_PAGE_ALIGN_MASK)
- address = lldb.SBAddress(page_addr, self.target)
- return self.target.CreateValueFromAddress("page", address, tHeapPageBody)
-
- def get_page_raw(self, val):
- body = self.get_page_body(val)
- return body.GetValueForExpressionPath("->header.page")
-
- def to_heap_page_struct(self):
- pagePtr = self.get_page_raw(self.val)
- return pagePtr.Cast(self.page_type)
-
-
-class RbObject(LLDBInterface):
- def __init__(self, ptr, debugger, ruby_globals):
- self.build_environment(debugger)
- self.ruby_globals = ruby_globals
-
- self.flUser1 = self.ruby_globals["RUBY_FL_USER1"]
- self.flUser2 = self.ruby_globals["RUBY_FL_USER2"]
- self.flUser3 = self.ruby_globals["RUBY_FL_USER3"]
- self.flUser4 = self.ruby_globals["RUBY_FL_USER4"]
- self.flUser5 = self.ruby_globals["RUBY_FL_USER5"]
- self.flUser6 = self.ruby_globals["RUBY_FL_USER6"]
- self.flUser7 = self.ruby_globals["RUBY_FL_USER7"]
- self.flUser8 = self.ruby_globals["RUBY_FL_USER8"]
- self.flUser9 = self.ruby_globals["RUBY_FL_USER9"]
- self.flUshift = self.ruby_globals["RUBY_FL_USHIFT"]
-
- self.tRBasic = self.target.FindFirstType("struct RBasic").GetPointerType()
- self.tRValue = self.target.FindFirstType("struct RVALUE")
-
- self.val = ptr.Cast(self.tRBasic)
- self.page = HeapPage(self.debugger, self.val)
- self.flags = self.val.GetValueForExpressionPath("->flags").GetValueAsUnsigned()
-
- self.type = None
- self.type_name = ""
-
- def check_bits(self, bitmap_name, bitmap_index, bitmap_bit, v):
- page = self.page.to_heap_page_struct()
- bits = page.GetChildMemberWithName(bitmap_name)
- plane = bits.GetChildAtIndex(bitmap_index).GetValueAsUnsigned()
- if (plane & bitmap_bit) != 0:
- return v
- else:
- return ' '
-
- def dump_bits(self, result, end = "\n"):
- tRValue = self.target.FindFirstType("struct RVALUE")
- tUintPtr = self.target.FindFirstType("uintptr_t") # bits_t
-
- num_in_page = (self.val.GetValueAsUnsigned() & HEAP_PAGE_ALIGN_MASK) // tRValue.GetByteSize();
- bits_bitlength = tUintPtr.GetByteSize() * 8
- bitmap_index = num_in_page // bits_bitlength
- bitmap_offset = num_in_page & (bits_bitlength - 1)
- bitmap_bit = 1 << bitmap_offset
-
- page = self.page.to_heap_page_struct()
- print("bits: [%s%s%s%s%s]" % (
- self.check_bits("uncollectible_bits", bitmap_index, bitmap_bit, "L"),
- self.check_bits("mark_bits", bitmap_index, bitmap_bit, "M"),
- self.check_bits("pinned_bits", bitmap_index, bitmap_bit, "P"),
- self.check_bits("marking_bits", bitmap_index, bitmap_bit, "R"),
- self.check_bits("wb_unprotected_bits", bitmap_index, bitmap_bit, "U"),
- ), end=end, file=result)
-
- def promoted_p(self):
- rbFlPromoted = self.ruby_globals["RUBY_FL_PROMOTED"]
- return (self.flags & rbFlPromoted) == rbFlPromoted
-
- def frozen_p(self):
- rbFlFreeze = self.ruby_globals["RUBY_FL_FREEZE"]
- return (self.flags & rbFlFreeze) == rbFlFreeze
-
- def is_type(self, type_name):
- if self.type is None:
- flTMask = self.ruby_globals["RUBY_T_MASK"]
- flType = self.flags & flTMask
- self.type = flType
-
- if self.type == self.ruby_globals[type_name]:
- self.type_name = type_name
- return True
- else:
- return False
-
- def as_type(self, type_name):
- return self.val.Cast(self.tRValue.GetPointerType()).GetValueForExpressionPath("->as."+type_name)
-
- def ary_ptr(self):
- rval = self.as_type("array")
- if self.flags & self.ruby_globals["RUBY_FL_USER1"]:
- ptr = rval.GetValueForExpressionPath("->as.ary")
- else:
- ptr = rval.GetValueForExpressionPath("->as.heap.ptr")
- return ptr
-
- def ary_len(self):
- if self.flags & self.flUser1:
- len = ((self.flags &
- (self.flUser3 | self.flUser4 | self.flUser5 | self.flUser6 |
- self.flUser7 | self.flUser8 | self.flUser9)
- ) >> (self.flUshift + 3))
- else:
- rval = self.as_type("array")
- len = rval.GetValueForExpressionPath("->as.heap.len").GetValueAsSigned()
-
- return len
-
- def bignum_len(self):
- if self.flags & self.flUser2:
- len = ((self.flags &
- (self.flUser3 | self.flUser4 | self.flUser5)
- ) >> (self.flUshift + 3))
- else:
- len = (self.as_type("bignum").GetValueForExpressionPath("->as.heap.len").
- GetValueAsUnsigned())
-
- return len
diff --git a/misc/lldb_rb/utils.py b/misc/lldb_rb/utils.py
deleted file mode 100644
index a6bbd385cd..0000000000
--- a/misc/lldb_rb/utils.py
+++ /dev/null
@@ -1,513 +0,0 @@
-from lldb_rb.lldb_interface import LLDBInterface
-from lldb_rb.rb_heap_structs import HeapPage, RbObject
-from lldb_rb.constants import *
-
-class RbInspector(LLDBInterface):
- def __init__(self, debugger, result, ruby_globals):
- self.build_environment(debugger)
- self.result = result
- self.ruby_globals = ruby_globals
-
- def _append_command_output(self, command):
- output1 = self.result.GetOutput()
- self.debugger.GetCommandInterpreter().HandleCommand(command, self.result)
- output2 = self.result.GetOutput()
- self.result.Clear()
- self.result.write(output1)
- self.result.write(output2)
-
- def _append_expression(self, expression):
- self._append_command_output("expression " + expression)
-
- def string2cstr(self, rstring):
- """Returns the pointer to the C-string in the given String object"""
- if rstring.TypeIsPointerType():
- rstring = rstring.Dereference()
-
- flags = rstring.GetValueForExpressionPath(".basic->flags").unsigned
- clen = int(rstring.GetValueForExpressionPath(".len").value, 0)
- if flags & self.ruby_globals["RUBY_FL_USER1"]:
- cptr = int(rstring.GetValueForExpressionPath(".as.heap.ptr").value, 0)
- else:
- cptr = int(rstring.GetValueForExpressionPath(".as.embed.ary").location, 0)
-
- return cptr, clen
-
- def output_string(self, rstring):
- cptr, clen = self.string2cstr(rstring)
- self._append_expression("*(const char (*)[%d])%0#x" % (clen, cptr))
-
- def fixnum_p(self, x):
- return x & self.ruby_globals["RUBY_FIXNUM_FLAG"] != 0
-
- def flonum_p(self, x):
- return (x & self.ruby_globals["RUBY_FLONUM_MASK"]) == self.ruby_globals["RUBY_FLONUM_FLAG"]
-
- def static_sym_p(self, x):
- special_shift = self.ruby_globals["RUBY_SPECIAL_SHIFT"]
- symbol_flag = self.ruby_globals["RUBY_SYMBOL_FLAG"]
- return (x & ~(~0 << special_shift)) == symbol_flag
-
- def generic_inspect(self, val, rtype):
- tRType = self.target.FindFirstType("struct %s" % rtype).GetPointerType()
- val = val.Cast(tRType)
- self._append_expression("*(struct %s *) %0#x" % (rtype, val.GetValueAsUnsigned()))
-
- def inspect(self, val):
- rbTrue = self.ruby_globals["RUBY_Qtrue"]
- rbFalse = self.ruby_globals["RUBY_Qfalse"]
- rbNil = self.ruby_globals["RUBY_Qnil"]
- rbUndef = self.ruby_globals["RUBY_Qundef"]
- rbImmediateMask = self.ruby_globals["RUBY_IMMEDIATE_MASK"]
-
- if self.inspect_node(val):
- return
-
- num = val.GetValueAsSigned()
- if num == rbFalse:
- print('false', file=self.result)
- elif num == rbTrue:
- print('true', file=self.result)
- elif num == rbNil:
- print('nil', file=self.result)
- elif num == rbUndef:
- print('undef', file=self.result)
- elif self.fixnum_p(num):
- print(num >> 1, file=self.result)
- elif self.flonum_p(num):
- self._append_expression("rb_float_value(%0#x)" % val.GetValueAsUnsigned())
- elif self.static_sym_p(num):
- if num < 128:
- print("T_SYMBOL: %c" % num, file=self.result)
- else:
- print("T_SYMBOL: (%x)" % num, file=self.result)
- self._append_expression("rb_id2name(%0#x)" % (num >> 8))
-
- elif num & rbImmediateMask:
- print('immediate(%x)' % num, file=self.result)
- else:
- rval = RbObject(val, self.debugger, self.ruby_globals)
- rval.dump_bits(self.result)
-
- flaginfo = ""
- if rval.promoted_p():
- flaginfo += "[PROMOTED] "
- if rval.frozen_p():
- flaginfo += "[FROZEN] "
-
- if rval.is_type("RUBY_T_NONE"):
- print('T_NONE: %s%s' % (flaginfo, val.Dereference()), file=self.result)
-
- elif rval.is_type("RUBY_T_NIL"):
- print('T_NIL: %s%s' % (flaginfo, val.Dereference()), file=self.result)
-
- elif rval.is_type("RUBY_T_OBJECT"):
- self.result.write('T_OBJECT: %s' % flaginfo)
- self._append_expression("*(struct RObject*)%0#x" % val.GetValueAsUnsigned())
-
- elif (rval.is_type("RUBY_T_CLASS") or
- rval.is_type("RUBY_T_MODULE") or
- rval.is_type("RUBY_T_ICLASS")):
- self.result.write('T_%s: %s' % (rval.type_name.split('_')[-1], flaginfo))
- tRClass = self.target.FindFirstType("struct RClass")
-
- self._append_expression("*(struct RClass*)%0#x" % val.GetValueAsUnsigned())
- if not val.Cast(tRClass).GetChildMemberWithName("ptr").IsValid():
- self._append_expression(
- "*(struct rb_classext_struct*)%0#x" %
- (val.GetValueAsUnsigned() + tRClass.GetByteSize())
- )
-
- elif rval.is_type("RUBY_T_STRING"):
- self.result.write('T_STRING: %s' % flaginfo)
- tRString = self.target.FindFirstType("struct RString").GetPointerType()
-
- chilled = self.ruby_globals["RUBY_FL_USER3"]
- if (rval.flags & chilled) != 0:
- self.result.write("[CHILLED] ")
-
- rb_enc_mask = self.ruby_globals["RUBY_ENCODING_MASK"]
- rb_enc_shift = self.ruby_globals["RUBY_ENCODING_SHIFT"]
- encidx = ((rval.flags & rb_enc_mask) >> rb_enc_shift)
- encname = self.target.FindFirstType("enum ruby_preserved_encindex") \
- .GetEnumMembers().GetTypeEnumMemberAtIndex(encidx) \
- .GetName()
-
- if encname is not None:
- self.result.write('[%s] ' % encname[14:])
- else:
- self.result.write('[enc=%d] ' % encidx)
-
- coderange = rval.flags & self.ruby_globals["RUBY_ENC_CODERANGE_MASK"]
- if coderange == self.ruby_globals["RUBY_ENC_CODERANGE_7BIT"]:
- self.result.write('[7BIT] ')
- elif coderange == self.ruby_globals["RUBY_ENC_CODERANGE_VALID"]:
- self.result.write('[VALID] ')
- elif coderange == self.ruby_globals["RUBY_ENC_CODERANGE_BROKEN"]:
- self.result.write('[BROKEN] ')
- else:
- self.result.write('[UNKNOWN] ')
-
- ptr, len = self.string2cstr(val.Cast(tRString))
- if len == 0:
- self.result.write("(empty)\n")
- else:
- self._append_expression("*(const char (*)[%d])%0#x" % (len, ptr))
-
- elif rval.is_type("RUBY_T_SYMBOL"):
- self.result.write('T_SYMBOL: %s' % flaginfo)
- tRSymbol = self.target.FindFirstType("struct RSymbol").GetPointerType()
- tRString = self.target.FindFirstType("struct RString").GetPointerType()
-
- val = val.Cast(tRSymbol)
- self._append_expression('(ID)%0#x ' % val.GetValueForExpressionPath("->id").GetValueAsUnsigned())
- self.output_string(val.GetValueForExpressionPath("->fstr").Cast(tRString))
-
- elif rval.is_type("RUBY_T_ARRAY"):
- len = rval.ary_len()
- ptr = rval.ary_ptr()
-
- self.result.write("T_ARRAY: %slen=%d" % (flaginfo, len))
-
- if rval.flags & self.ruby_globals["RUBY_FL_USER1"]:
- self.result.write(" (embed)")
- elif rval.flags & self.ruby_globals["RUBY_FL_USER2"]:
- shared = val.GetValueForExpressionPath("->as.heap.aux.shared").GetValueAsUnsigned()
- self.result.write(" (shared) shared=%016x" % shared)
- else:
- capa = val.GetValueForExpressionPath("->as.heap.aux.capa").GetValueAsSigned()
- self.result.write(" (ownership) capa=%d" % capa)
- if len == 0:
- self.result.write(" {(empty)}\n")
- else:
- self.result.write("\n")
- if ptr.GetValueAsSigned() == 0:
- self._append_expression("-fx -- ((struct RArray*)%0#x)->as.ary" % val.GetValueAsUnsigned())
- else:
- self._append_expression("-Z %d -fx -- (const VALUE*)%0#x" % (len, ptr.GetValueAsUnsigned()))
-
- elif rval.is_type("RUBY_T_HASH"):
- self.result.write("T_HASH: %s" % flaginfo)
- ptr = val.GetValueAsUnsigned()
- self._append_expression("*(struct RHash *) %0#x" % ptr)
- if rval.flags & self.ruby_globals["RUBY_FL_USER3"]:
- self._append_expression("*(struct st_table *) (%0#x + sizeof(struct RHash))" % ptr)
- else:
- self._append_expression("*(struct ar_table *) (%0#x + sizeof(struct RHash))" % ptr)
-
- elif rval.is_type("RUBY_T_BIGNUM"):
- sign = '-'
- if (rval.flags & self.ruby_globals["RUBY_FL_USER1"]) != 0:
- sign = '+'
- len = rval.bignum_len()
-
- if rval.flags & self.ruby_globals["RUBY_FL_USER2"]:
- print("T_BIGNUM: sign=%s len=%d (embed)" % (sign, len), file=self.result)
- self._append_expression("((struct RBignum *) %0#x)->as.ary"
- % val.GetValueAsUnsigned())
- else:
- print("T_BIGNUM: sign=%s len=%d" % (sign, len), file=self.result)
- print(rval.as_type("bignum"), file=self.result)
- self._append_expression("-Z %d -fx -- ((struct RBignum*)%d)->as.heap.digits" %
- (len, val.GetValueAsUnsigned()))
-
- elif rval.is_type("RUBY_T_FLOAT"):
- self._append_expression("((struct RFloat *)%d)->float_value"
- % val.GetValueAsUnsigned())
-
- elif rval.is_type("RUBY_T_RATIONAL"):
- tRRational = self.target.FindFirstType("struct RRational").GetPointerType()
- val = val.Cast(tRRational)
- self.inspect(val.GetValueForExpressionPath("->num"))
- output = self.result.GetOutput()
- self.result.Clear()
- self.result.write("(Rational) " + output.rstrip() + " / ")
- self.inspect(val.GetValueForExpressionPath("->den"))
-
- elif rval.is_type("RUBY_T_COMPLEX"):
- tRComplex = self.target.FindFirstType("struct RComplex").GetPointerType()
- val = val.Cast(tRComplex)
- self.inspect(val.GetValueForExpressionPath("->real"))
- real = self.result.GetOutput().rstrip()
- self.result.Clear()
- self.inspect(val.GetValueForExpressionPath("->imag"))
- imag = self.result.GetOutput().rstrip()
- self.result.Clear()
- if not imag.startswith("-"):
- imag = "+" + imag
- print("(Complex) " + real + imag + "i", file=self.result)
-
- elif rval.is_type("RUBY_T_REGEXP"):
- tRRegex = self.target.FindFirstType("struct RRegexp").GetPointerType()
- val = val.Cast(tRRegex)
- print("(Regex) ->src {", file=self.result)
- self.inspect(val.GetValueForExpressionPath("->src"))
- print("}", file=self.result)
-
- elif rval.is_type("RUBY_T_DATA"):
- tRTypedData = self.target.FindFirstType("struct RTypedData").GetPointerType()
- val = val.Cast(tRTypedData)
- flag = val.GetValueForExpressionPath("->typed_flag")
-
- if flag.GetValueAsUnsigned() == 1:
- print("T_DATA: %s" %
- val.GetValueForExpressionPath("->type->wrap_struct_name"),
- file=self.result)
- self._append_expression("*(struct RTypedData *) %0#x" % val.GetValueAsUnsigned())
- else:
- print("T_DATA:", file=self.result)
- self._append_expression("*(struct RData *) %0#x" % val.GetValueAsUnsigned())
-
- elif rval.is_type("RUBY_T_IMEMO"):
- imemo_type = ((rval.flags >> self.ruby_globals["RUBY_FL_USHIFT"])
- & IMEMO_MASK)
- print("T_IMEMO: ", file=self.result)
-
- self._append_expression("(enum imemo_type) %d" % imemo_type)
- self._append_expression("*(struct MEMO *) %0#x" % val.GetValueAsUnsigned())
-
- elif rval.is_type("RUBY_T_FILE"):
- self.generic_inspect(val, "RFile")
-
- elif rval.is_type("RUBY_T_MOVED"):
- self.generic_inspect(val, "RMoved")
-
- elif rval.is_type("RUBY_T_MATCH"):
- self.generic_inspect(val, "RMatch")
-
- elif rval.is_type("RUBY_T_STRUCT"):
- self.generic_inspect(val, "RStruct")
-
- elif rval.is_type("RUBY_T_ZOMBIE"):
- self.generic_inspect(val, "RZombie")
-
- else:
- print("Not-handled type %0#x" % rval.type, file=self.result)
- print(val, file=self.result)
-
- def inspect_node(self, val):
- tRNode = self.target.FindFirstType("struct RNode").GetPointerType()
-
- # if val.GetType() != tRNode: does not work for unknown reason
-
- if val.GetType().GetPointeeType().name != "NODE":
- return False
-
- rbNodeTypeMask = self.ruby_globals["RUBY_NODE_TYPEMASK"]
- rbNodeTypeShift = self.ruby_globals["RUBY_NODE_TYPESHIFT"]
- flags = val.Cast(tRNode).GetChildMemberWithName("flags").GetValueAsUnsigned()
- nd_type = (flags & rbNodeTypeMask) >> rbNodeTypeShift
-
- self._append_expression("(node_type) %d" % nd_type)
-
- if nd_type == self.ruby_globals["NODE_SCOPE"]:
- self._append_expression("*(rb_node_scope_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BLOCK"]:
- self._append_expression("*(rb_node_block_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_IF"]:
- self._append_expression("*(rb_node_if_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_UNLESS"]:
- self._append_expression("*(rb_node_unless_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CASE"]:
- self._append_expression("*(rb_node_case_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CASE2"]:
- self._append_expression("*(rb_node_case2_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CASE3"]:
- self._append_expression("*(rb_node_case3_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_WHEN"]:
- self._append_expression("*(rb_node_when_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_IN"]:
- self._append_expression("*(rb_node_in_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_WHILE"]:
- self._append_expression("*(rb_node_while_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_UNTIL"]:
- self._append_expression("*(rb_node_until_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ITER"]:
- self._append_expression("*(rb_node_iter_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FOR"]:
- self._append_expression("*(rb_node_for_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FOR_MASGN"]:
- self._append_expression("*(rb_node_for_masgn_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BREAK"]:
- self._append_expression("*(rb_node_break_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_NEXT"]:
- self._append_expression("*(rb_node_next_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_REDO"]:
- self._append_expression("*(rb_node_redo_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RETRY"]:
- self._append_expression("*(rb_node_retry_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BEGIN"]:
- self._append_expression("*(rb_node_begin_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RESCUE"]:
- self._append_expression("*(rb_node_rescue_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RESBODY"]:
- self._append_expression("*(rb_node_resbody_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ENSURE"]:
- self._append_expression("*(rb_node_ensure_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_AND"]:
- self._append_expression("*(rb_node_and_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OR"]:
- self._append_expression("*(rb_node_or_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MASGN"]:
- self._append_expression("*(rb_node_masgn_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LASGN"]:
- self._append_expression("*(rb_node_lasgn_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DASGN"]:
- self._append_expression("*(rb_node_dasgn_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_GASGN"]:
- self._append_expression("*(rb_node_gasgn_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_IASGN"]:
- self._append_expression("*(rb_node_iasgn_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CDECL"]:
- self._append_expression("*(rb_node_cdecl_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CVASGN"]:
- self._append_expression("*(rb_node_cvasgn_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN1"]:
- self._append_expression("*(rb_node_op_asgn1_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN2"]:
- self._append_expression("*(rb_node_op_asgn2_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN_AND"]:
- self._append_expression("*(rb_node_op_asgn_and_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_ASGN_OR"]:
- self._append_expression("*(rb_node_op_asgn_or_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OP_CDECL"]:
- self._append_expression("*(rb_node_op_cdecl_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CALL"]:
- self._append_expression("*(rb_node_call_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OPCALL"]:
- self._append_expression("*(rb_node_opcall_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FCALL"]:
- self._append_expression("*(rb_node_fcall_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_VCALL"]:
- self._append_expression("*(rb_node_vcall_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_QCALL"]:
- self._append_expression("*(rb_node_qcall_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SUPER"]:
- self._append_expression("*(rb_node_super_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ZSUPER"]:
- self._append_expression("*(rb_node_zsuper_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LIST"]:
- self._append_expression("*(rb_node_list_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ZLIST"]:
- self._append_expression("*(rb_node_zlist_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_HASH"]:
- self._append_expression("*(rb_node_hash_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_RETURN"]:
- self._append_expression("*(rb_node_return_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_YIELD"]:
- self._append_expression("*(rb_node_yield_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LVAR"]:
- self._append_expression("*(rb_node_lvar_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DVAR"]:
- self._append_expression("*(rb_node_dvar_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_GVAR"]:
- self._append_expression("*(rb_node_gvar_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CONST"]:
- self._append_expression("*(rb_node_const_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CVAR"]:
- self._append_expression("*(rb_node_cvar_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_NTH_REF"]:
- self._append_expression("*(rb_node_nth_ref_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_BACK_REF"]:
- self._append_expression("*(rb_node_back_ref_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MATCH"]:
- self._append_expression("*(rb_node_match_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MATCH2"]:
- self._append_expression("*(rb_node_match2_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MATCH3"]:
- self._append_expression("*(rb_node_match3_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_STR"]:
- self._append_expression("*(rb_node_str_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DSTR"]:
- self._append_expression("*(rb_node_dstr_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_XSTR"]:
- self._append_expression("*(rb_node_xstr_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DXSTR"]:
- self._append_expression("*(rb_node_dxstr_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_EVSTR"]:
- self._append_expression("*(rb_node_evstr_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_REGX"]:
- self._append_expression("*(rb_node_regx_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DREGX"]:
- self._append_expression("*(rb_node_dregx_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ONCE"]:
- self._append_expression("*(rb_node_once_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGS"]:
- self._append_expression("*(rb_node_args_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGS_AUX"]:
- self._append_expression("*(rb_node_args_aux_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_OPT_ARG"]:
- self._append_expression("*(rb_node_opt_arg_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_KW_ARG"]:
- self._append_expression("*(rb_node_kw_arg_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_POSTARG"]:
- self._append_expression("*(rb_node_postarg_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGSCAT"]:
- self._append_expression("*(rb_node_argscat_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARGSPUSH"]:
- self._append_expression("*(rb_node_argspush_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SPLAT"]:
- self._append_expression("*(rb_node_splat_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DEFN"]:
- self._append_expression("*(rb_node_defn_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DEFS"]:
- self._append_expression("*(rb_node_defs_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ALIAS"]:
- self._append_expression("*(rb_node_alias_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_VALIAS"]:
- self._append_expression("*(rb_node_valias_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_UNDEF"]:
- self._append_expression("*(rb_node_undef_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_CLASS"]:
- self._append_expression("*(rb_node_class_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_MODULE"]:
- self._append_expression("*(rb_node_module_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SCLASS"]:
- self._append_expression("*(rb_node_sclass_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_COLON2"]:
- self._append_expression("*(rb_node_colon2_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_COLON3"]:
- self._append_expression("*(rb_node_colon3_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DOT2"]:
- self._append_expression("*(rb_node_dot2_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DOT3"]:
- self._append_expression("*(rb_node_dot3_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FLIP2"]:
- self._append_expression("*(rb_node_flip2_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FLIP3"]:
- self._append_expression("*(rb_node_flip3_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_SELF"]:
- self._append_expression("*(rb_node_self_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_NIL"]:
- self._append_expression("*(rb_node_nil_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_TRUE"]:
- self._append_expression("*(rb_node_true_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FALSE"]:
- self._append_expression("*(rb_node_false_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ERRINFO"]:
- self._append_expression("*(rb_node_errinfo_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DEFINED"]:
- self._append_expression("*(rb_node_defined_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_POSTEXE"]:
- self._append_expression("*(rb_node_postexe_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_DSYM"]:
- self._append_expression("*(rb_node_dsym_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ATTRASGN"]:
- self._append_expression("*(rb_node_attrasgn_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LAMBDA"]:
- self._append_expression("*(rb_node_lambda_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ARYPTN"]:
- self._append_expression("*(rb_node_aryptn_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_HSHPTN"]:
- self._append_expression("*(rb_node_hshptn_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FNDPTN"]:
- self._append_expression("*(rb_node_fndptn_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_ERROR"]:
- self._append_expression("*(rb_node_error_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_LINE"]:
- self._append_expression("*(rb_node_line_t *) %0#x" % val.GetValueAsUnsigned())
- elif nd_type == self.ruby_globals["NODE_FILE"]:
- self._append_expression("*(rb_node_file_t *) %0#x" % val.GetValueAsUnsigned())
- else:
- self._append_expression("*(NODE *) %0#x" % val.GetValueAsUnsigned())
- return True
diff --git a/misc/lldb_yjit.py b/misc/lldb_yjit.py
new file mode 100644
index 0000000000..cc37b990ea
--- /dev/null
+++ b/misc/lldb_yjit.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+#coding: utf-8
+#
+# Usage: run `command script import -r misc/lldb_yjit.py` on LLDB
+#
+
+from __future__ import print_function
+import lldb
+import os
+import shlex
+
+def list_comments(debugger, command, result, internal_dict):
+ target = debugger.GetSelectedTarget()
+ process = target.GetProcess()
+ thread = process.GetSelectedThread()
+ frame = thread.GetSelectedFrame()
+
+ # Get the different types we need
+ rb_darray_meta_t = target.FindFirstType("rb_darray_meta_t")
+ codeblock_t = target.FindFirstType("codeblock_t")
+ yjit_comment = target.FindFirstType("yjit_comment")
+
+ # Get the global variables we need
+ comments = target.FindFirstGlobalVariable("yjit_code_comments")
+ cb = target.FindFirstGlobalVariable("cb").Cast(codeblock_t.GetPointerType())
+
+ # Get the address of the memory block we're using
+ mem_addr = cb.GetChildMemberWithName("mem_block").GetValueAsUnsigned()
+
+ # Find the size of the darray comment list
+ meta = comments.Cast(rb_darray_meta_t.GetPointerType())
+ size = meta.GetChildMemberWithName("size").GetValueAsUnsigned()
+
+ # Get the address of the block following the metadata header
+ t_offset = comments.GetValueAsUnsigned() + rb_darray_meta_t.GetByteSize()
+
+ # Loop through each comment and print
+ for t in range(0, size):
+ addr = lldb.SBAddress(t_offset + (t * yjit_comment.GetByteSize()), target)
+ comment = target.CreateValueFromAddress("yjit_comment", addr, yjit_comment)
+ string = comment.GetChildMemberWithName("comment")
+ comment_offset = mem_addr + comment.GetChildMemberWithName("offset").GetValueAsUnsigned()
+ print("%0#x %s" % (comment_offset, string.GetSummary()), file = result)
+
+
+def __lldb_init_module(debugger, internal_dict):
+ debugger.HandleCommand("command script add -f lldb_yjit.list_comments lc")
diff --git a/misc/ruby-style.el b/misc/ruby-style.el
index 45fdccc6f2..13aad77b3d 100644
--- a/misc/ruby-style.el
+++ b/misc/ruby-style.el
@@ -66,17 +66,6 @@
(access-label /)
)))
-(c-add-style
- "prism"
- '("bsd"
- (c-basic-offset . 4)
- (tab-width . 8)
- (indent-tabs-mode . nil)
- (setq show-trailing-whitespace t)
- (c-offsets-alist
- (case-label . +)
- )))
-
;;;###autoload
(defun ruby-style-c-mode ()
(interactive)
diff --git a/misc/yjit_perf.py b/misc/yjit_perf.py
deleted file mode 100755
index 61434e5eb4..0000000000
--- a/misc/yjit_perf.py
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/usr/bin/env python3
-import os
-import sys
-from collections import Counter, defaultdict
-import os.path
-
-# Aggregating cycles per symbol and dso
-total_cycles = 0
-category_cycles = Counter()
-detailed_category_cycles = defaultdict(Counter)
-categories = set()
-
-def truncate_symbol(symbol, max_length=50):
- """ Truncate the symbol name to a maximum length """
- return symbol if len(symbol) <= max_length else symbol[:max_length-3] + '...'
-
-def categorize_symbol(dso, symbol):
- """ Categorize the symbol based on the defined criteria """
- if dso == 'sqlite3_native.so':
- return '[sqlite3]'
- elif 'SHA256' in symbol:
- return '[sha256]'
- elif symbol.startswith('[JIT] gen_send'):
- return '[JIT send]'
- elif symbol.startswith('[JIT]'):
- return '[JIT code]'
- elif '::' in symbol or symbol.startswith('yjit::') or symbol.startswith('_ZN4yjit'):
- return '[YJIT compile]'
- elif symbol.startswith('rb_vm_') or symbol.startswith('vm_') or symbol in {
- "rb_call0", "callable_method_entry_or_negative", "invoke_block_from_c_bh",
- "rb_funcallv_scope", "setup_parameters_complex", "rb_yield"}:
- return '[interpreter]'
- elif symbol.startswith('rb_hash_') or symbol.startswith('hash_'):
- return '[rb_hash_*]'
- elif symbol.startswith('rb_ary_') or symbol.startswith('ary_'):
- return '[rb_ary_*]'
- elif symbol.startswith('rb_str_') or symbol.startswith('str_'):
- return '[rb_str_*]'
- elif symbol.startswith('rb_sym') or symbol.startswith('sym_'):
- return '[rb_sym_*]'
- elif symbol.startswith('rb_st_') or symbol.startswith('st_'):
- return '[rb_st_*]'
- elif symbol.startswith('rb_ivar_') or 'shape' in symbol:
- return '[ivars]'
- elif 'match' in symbol or symbol.startswith('rb_reg') or symbol.startswith('onig'):
- return '[regexp]'
- elif 'alloc' in symbol or 'free' in symbol or 'gc' in symbol:
- return '[GC]'
- elif 'pthread' in symbol and 'lock' in symbol:
- return '[pthread lock]'
- else:
- return symbol # Return the symbol itself for uncategorized symbols
-
-def process_event(event):
- global total_cycles, category_cycles, detailed_category_cycles, categories
-
- full_dso = event.get("dso", "Unknown_dso")
- dso = os.path.basename(full_dso)
- symbol = event.get("symbol", "[unknown]")
- cycles = event["sample"]["period"]
- total_cycles += cycles
-
- category = categorize_symbol(dso, symbol)
- category_cycles[category] += cycles
- detailed_category_cycles[category][(dso, symbol)] += cycles
-
- if category.startswith('[') and category.endswith(']'):
- categories.add(category)
-
-def trace_end():
- if total_cycles == 0:
- return
-
- print("Aggregated Event Data:")
- print("{:<20} {:<50} {:>20} {:>15}".format("[dso]", "[symbol or category]", "[top-most cycle ratio]", "[num cycles]"))
-
- for category, cycles in category_cycles.most_common():
- ratio = (cycles / total_cycles) * 100
- dsos = {dso for dso, _ in detailed_category_cycles[category]}
- dso_display = next(iter(dsos)) if len(dsos) == 1 else "Multiple DSOs"
- print("{:<20} {:<50} {:>20.2f}% {:>15}".format(dso_display, truncate_symbol(category), ratio, cycles))
-
- # Category breakdown
- for category in categories:
- symbols = detailed_category_cycles[category]
- category_total = sum(symbols.values())
- category_ratio = (category_total / total_cycles) * 100
- print(f"\nCategory: {category} ({category_ratio:.2f}%)")
- print("{:<20} {:<50} {:>20} {:>15}".format("[dso]", "[symbol]", "[top-most cycle ratio]", "[num cycles]"))
- for (dso, symbol), cycles in symbols.most_common():
- symbol_ratio = (cycles / category_total) * 100
- print("{:<20} {:<50} {:>20.2f}% {:>15}".format(dso, truncate_symbol(symbol), symbol_ratio, cycles))
-
-# There are two ways to use this script:
-# 1) perf script -s misc/yjit_perf.py -- native interface
-# 2) perf script > perf.txt && misc/yjit_perf.py perf.txt -- hack, which doesn't require perf with Python support
-#
-# In both cases, __name__ is "__main__". The following code implements (2) when sys.argv is 2.
-if __name__ == "__main__" and len(sys.argv) == 2:
- if len(sys.argv) != 2:
- print("Usage: yjit_perf.py <filename>")
- sys.exit(1)
-
- with open(sys.argv[1], "r") as file:
- for line in file:
- # [Example]
- # ruby 78207 3482.848465: 1212775 cpu_core/cycles:P/: 5c0333f682e1 [JIT] getlocal_WC_0+0x0 (/tmp/perf-78207.map)
- row = line.split(maxsplit=6)
-
- period = row[3] # "1212775"
- symbol, dso = row[6].split(" (") # "[JIT] getlocal_WC_0+0x0", "/tmp/perf-78207.map)\n"
- symbol = symbol.split("+")[0] # "[JIT] getlocal_WC_0"
- dso = dso.split(")")[0] # "/tmp/perf-78207.map"
-
- process_event({"dso": dso, "symbol": symbol, "sample": {"period": int(period)}})
- trace_end()
diff --git a/missing/dtoa.c b/missing/dtoa.c
index 477b212a1b..b7a8302875 100644
--- a/missing/dtoa.c
+++ b/missing/dtoa.c
@@ -183,10 +183,7 @@
#undef Long
#undef ULong
-#include <assert.h>
#include <limits.h>
-#include <stddef.h>
-#include <stdint.h>
#if (INT_MAX >> 30) && !(INT_MAX >> 31)
#define Long int
@@ -198,7 +195,7 @@
#error No 32bit integer
#endif
-#if defined(HAVE_LONG_LONG) && (HAVE_LONG_LONG)
+#if HAVE_LONG_LONG
#define Llong LONG_LONG
#else
#define NO_LONG_LONG
@@ -224,12 +221,12 @@
#ifdef MALLOC
extern void *MALLOC(size_t);
#else
-#define MALLOC malloc
+#define MALLOC xmalloc
#endif
#ifdef FREE
extern void FREE(void*);
#else
-#define FREE free
+#define FREE xfree
#endif
#ifndef NO_SANITIZE
#define NO_SANITIZE(x, y) y
@@ -505,7 +502,7 @@ extern double rnd_prod(double, double), rnd_quot(double, double);
#endif
#ifndef ATOMIC_PTR_CAS
-#define ATOMIC_PTR_CAS(var, old, new) ((var) = (new), (void *)(old))
+#define ATOMIC_PTR_CAS(var, old, new) ((var) = (new), (old))
#endif
#ifndef LIKELY
#define LIKELY(x) (x)
@@ -1552,7 +1549,7 @@ break2:
aadj = 1.0;
nd0 = -4;
- if (!*++s || (!(s1 = strchr(hexdigit, *s)) && *s != '.')) goto ret0;
+ if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0;
if (*s == '0') {
while (*++s == '0');
if (!*s) goto ret;
@@ -1566,7 +1563,9 @@ break2:
} while (*++s && (s1 = strchr(hexdigit, *s)));
}
- if ((*s == '.') && *++s && (s1 = strchr(hexdigit, *s))) {
+ if (*s == '.') {
+ dsign = 1;
+ if (!*++s || !(s1 = strchr(hexdigit, *s))) goto ret0;
if (nd0 < 0) {
while (*s == '0') {
s++;
@@ -1581,6 +1580,9 @@ break2:
}
}
}
+ else {
+ dsign = 0;
+ }
if (*s == 'P' || *s == 'p') {
dsign = 0x2C - *++s; /* +: 2B, -: 2D */
@@ -1603,6 +1605,9 @@ break2:
} while ('0' <= c && c <= '9');
nd0 += nd * dsign;
}
+ else {
+ if (dsign) goto ret0;
+ }
dval(rv) = ldexp(adj, nd0);
goto ret;
}
@@ -1639,9 +1644,9 @@ break2:
}
#endif
if (c == '.') {
- c = *++s;
- if (!ISDIGIT(c))
+ if (!ISDIGIT(s[1]))
goto dig_done;
+ c = *++s;
if (!nd) {
for (; c == '0'; c = *++s)
nz++;
diff --git a/missing/explicit_bzero.c b/missing/explicit_bzero.c
index 59417e158e..1220e5f9ad 100644
--- a/missing/explicit_bzero.c
+++ b/missing/explicit_bzero.c
@@ -1,9 +1,12 @@
#ifndef __STDC_WANT_LIB_EXT1__
-#define __STDC_WANT_LIB_EXT1__ 1 /* for memset_s() */
+#define __STDC_WANT_LIB_EXT1__ 1
#endif
#include "ruby/missing.h"
#include <string.h>
+#ifdef HAVE_MEMSET_S
+# include <string.h>
+#endif
#ifdef _WIN32
#include <windows.h>
diff --git a/missing/procstat_vm.c b/missing/procstat_vm.c
index 155ee355d1..76fd8f61ba 100644
--- a/missing/procstat_vm.c
+++ b/missing/procstat_vm.c
@@ -6,7 +6,7 @@
# define KVME_TYPE_MGTDEVICE 8
# endif
void
-procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp, FILE *errout)
+procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp)
{
struct kinfo_vmentry *freep, *kve;
int ptrwidth;
@@ -17,7 +17,7 @@ procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp, FILE *errout)
#else
ptrwidth = 2*sizeof(void *) + 2;
#endif
- fprintf(errout, "%*s %*s %3s %4s %4s %3s %3s %4s %-2s %-s\n",
+ fprintf(stderr, "%*s %*s %3s %4s %4s %3s %3s %4s %-2s %-s\n",
ptrwidth, "START", ptrwidth, "END", "PRT", "RES",
"P""RES", "REF", "SHD", "FL", "TP", "PATH");
@@ -30,20 +30,20 @@ procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp, FILE *errout)
return;
for (i = 0; i < cnt; i++) {
kve = &freep[i];
- fprintf(errout, "%#*jx ", ptrwidth, (uintmax_t)kve->kve_start);
- fprintf(errout, "%#*jx ", ptrwidth, (uintmax_t)kve->kve_end);
- fprintf(errout, "%s", kve->kve_protection & KVME_PROT_READ ? "r" : "-");
- fprintf(errout, "%s", kve->kve_protection & KVME_PROT_WRITE ? "w" : "-");
- fprintf(errout, "%s ", kve->kve_protection & KVME_PROT_EXEC ? "x" : "-");
- fprintf(errout, "%4d ", kve->kve_resident);
- fprintf(errout, "%4d ", kve->kve_private_resident);
- fprintf(errout, "%3d ", kve->kve_ref_count);
- fprintf(errout, "%3d ", kve->kve_shadow_count);
- fprintf(errout, "%-1s", kve->kve_flags & KVME_FLAG_COW ? "C" : "-");
- fprintf(errout, "%-1s", kve->kve_flags & KVME_FLAG_NEEDS_COPY ? "N" :
+ fprintf(stderr, "%#*jx ", ptrwidth, (uintmax_t)kve->kve_start);
+ fprintf(stderr, "%#*jx ", ptrwidth, (uintmax_t)kve->kve_end);
+ fprintf(stderr, "%s", kve->kve_protection & KVME_PROT_READ ? "r" : "-");
+ fprintf(stderr, "%s", kve->kve_protection & KVME_PROT_WRITE ? "w" : "-");
+ fprintf(stderr, "%s ", kve->kve_protection & KVME_PROT_EXEC ? "x" : "-");
+ fprintf(stderr, "%4d ", kve->kve_resident);
+ fprintf(stderr, "%4d ", kve->kve_private_resident);
+ fprintf(stderr, "%3d ", kve->kve_ref_count);
+ fprintf(stderr, "%3d ", kve->kve_shadow_count);
+ fprintf(stderr, "%-1s", kve->kve_flags & KVME_FLAG_COW ? "C" : "-");
+ fprintf(stderr, "%-1s", kve->kve_flags & KVME_FLAG_NEEDS_COPY ? "N" :
"-");
- fprintf(errout, "%-1s", kve->kve_flags & KVME_FLAG_SUPER ? "S" : "-");
- fprintf(errout, "%-1s ", kve->kve_flags & KVME_FLAG_GROWS_UP ? "U" :
+ fprintf(stderr, "%-1s", kve->kve_flags & KVME_FLAG_SUPER ? "S" : "-");
+ fprintf(stderr, "%-1s ", kve->kve_flags & KVME_FLAG_GROWS_UP ? "U" :
kve->kve_flags & KVME_FLAG_GROWS_DOWN ? "D" : "-");
switch (kve->kve_type) {
case KVME_TYPE_NONE:
@@ -78,8 +78,8 @@ procstat_vm(struct procstat *procstat, struct kinfo_proc *kipp, FILE *errout)
str = "??";
break;
}
- fprintf(errout, "%-2s ", str);
- fprintf(errout, "%-s\n", kve->kve_path);
+ fprintf(stderr, "%-2s ", str);
+ fprintf(stderr, "%-s\n", kve->kve_path);
}
free(freep);
}
diff --git a/missing/setproctitle.c b/missing/setproctitle.c
index 5b2dfa65ce..811829c060 100644
--- a/missing/setproctitle.c
+++ b/missing/setproctitle.c
@@ -80,43 +80,10 @@ static char **argv1_addr = NULL;
#endif /* HAVE_SETPROCTITLE */
-#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV
-# define ALLOCATE_ENVIRON 1
-#else
-# define ALLOCATE_ENVIRON 0
-#endif
-
-#if ALLOCATE_ENVIRON
-/* system_environ is the value of environ before we allocate a custom buffer.
- *
- * We use this to restore environ in ruby_free_proctitle.
- */
-static char **system_environ = NULL;
-/* orig_environ is the buffer we allocate for environ.
- *
- * We use this to free this buffer in ruby_free_proctitle. When we add new
- * environment variables using setenv, the system may change environ to a
- * different buffer and will not free the original buffer, so we need to hold
- * onto this so we can free it in ruby_free_proctitle.
- *
- * We must not free any of the contents because it may change if the system
- * updates existing environment variables.
- */
-static char **orig_environ = NULL;
-/* alloc_environ is a copy of orig_environ.
- *
- * We use this to free all the original string copies that were in orig_environ.
- * Since environ could be changed to point to strings allocated by the system
- * if environment variables are updated, so we need this to point to the
- * original strings.
- */
-static char **alloc_environ = NULL;
-#endif
-
void
compat_init_setproctitle(int argc, char *argv[])
{
-#if ALLOCATE_ENVIRON
+#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV
extern char **environ;
char *lastargv = NULL;
char *lastenvp = NULL;
@@ -133,13 +100,9 @@ compat_init_setproctitle(int argc, char *argv[])
return;
/* Fail if we can't allocate room for the new environment */
- for (i = 0; envp[i] != NULL; i++);
-
- system_environ = environ;
-
- alloc_environ = xcalloc(i + 1, sizeof(*environ));
- orig_environ = environ = xcalloc(i + 1, sizeof(*environ));
- if (environ == NULL) {
+ for (i = 0; envp[i] != NULL; i++)
+ ;
+ if ((environ = calloc(i + 1, sizeof(*environ))) == NULL) {
environ = envp; /* put it back */
return;
}
@@ -166,31 +129,12 @@ compat_init_setproctitle(int argc, char *argv[])
argv_env_len = lastenvp - argv[0];
for (i = 0; envp[i] != NULL; i++)
- alloc_environ[i] = environ[i] = ruby_strdup(envp[i]);
- alloc_environ[i] = environ[i] = NULL;
+ environ[i] = ruby_strdup(envp[i]);
+ environ[i] = NULL;
#endif /* SPT_REUSEARGV */
}
-void
-ruby_free_proctitle(void)
-{
-#if ALLOCATE_ENVIRON
- extern char **environ;
-
- if (!orig_environ) return; /* environ is allocated by OS */
-
- for (int i = 0; alloc_environ[i] != NULL; i++) {
- xfree(alloc_environ[i]);
- }
- xfree(alloc_environ);
- xfree(orig_environ);
-
- environ = system_environ;
-#endif
-}
-
#ifndef HAVE_SETPROCTITLE
-
void
setproctitle(const char *fmt, ...)
{
diff --git a/mjit.c b/mjit.c
new file mode 100644
index 0000000000..3200ee2621
--- /dev/null
+++ b/mjit.c
@@ -0,0 +1,1999 @@
+/**********************************************************************
+
+ mjit.c - MRI method JIT compiler functions
+
+ Copyright (C) 2017 Vladimir Makarov <vmakarov@redhat.com>.
+ Copyright (C) 2017 Takashi Kokubun <k0kubun@ruby-lang.org>.
+
+**********************************************************************/
+
+/* We utilize widely used C compilers (GCC and LLVM Clang) to
+ implement MJIT. We feed them a C code generated from ISEQ. The
+ industrial C compilers are slower than regular JIT engines.
+ Generated code performance of the used C compilers has a higher
+ priority over the compilation speed.
+
+ So our major goal is to minimize the ISEQ compilation time when we
+ use widely optimization level (-O2). It is achieved by
+
+ o Using a precompiled version of the header
+ o Keeping all files in `/tmp`. On modern Linux `/tmp` is a file
+ system in memory. So it is pretty fast
+ o Implementing MJIT as a multi-threaded code because we want to
+ compile ISEQs in parallel with iseq execution to speed up Ruby
+ code execution. MJIT has one thread (*worker*) to do
+ parallel compilations:
+ o It prepares a precompiled code of the minimized header.
+ It starts at the MRI execution start
+ o It generates PIC object files of ISEQs
+ o It takes one JIT unit from a priority queue unless it is empty.
+ o It translates the JIT unit ISEQ into C-code using the precompiled
+ header, calls CC and load PIC code when it is ready
+ o Currently MJIT put ISEQ in the queue when ISEQ is called
+ o MJIT can reorder ISEQs in the queue if some ISEQ has been called
+ many times and its compilation did not start yet
+ o MRI reuses the machine code if it already exists for ISEQ
+ o The machine code we generate can stop and switch to the ISEQ
+ interpretation if some condition is not satisfied as the machine
+ code can be speculative or some exception raises
+ o Speculative machine code can be canceled.
+
+ Here is a diagram showing the MJIT organization:
+
+ _______
+ |header |
+ |_______|
+ | MRI building
+ --------------|----------------------------------------
+ | MRI execution
+ |
+ _____________|_____
+ | | |
+ | ___V__ | CC ____________________
+ | | |----------->| precompiled header |
+ | | | | |____________________|
+ | | | | |
+ | | MJIT | | |
+ | | | | |
+ | | | | ____V___ CC __________
+ | |______|----------->| C code |--->| .so file |
+ | | |________| |__________|
+ | | |
+ | | |
+ | MRI machine code |<-----------------------------
+ |___________________| loading
+
+*/
+
+#include "ruby/internal/config.h" // defines USE_MJIT
+
+#if USE_MJIT
+
+#include "constant.h"
+#include "id_table.h"
+#include "internal.h"
+#include "internal/class.h"
+#include "internal/cmdlineopt.h"
+#include "internal/cont.h"
+#include "internal/file.h"
+#include "internal/hash.h"
+#include "internal/process.h"
+#include "internal/warnings.h"
+#include "vm_sync.h"
+#include "ractor_core.h"
+
+#ifdef __sun
+#define __EXTENSIONS__ 1
+#endif
+
+#include "vm_core.h"
+#include "vm_callinfo.h"
+#include "mjit.h"
+#include "mjit_c.h"
+#include "gc.h"
+#include "ruby_assert.h"
+#include "ruby/debug.h"
+#include "ruby/thread.h"
+#include "ruby/version.h"
+#include "builtin.h"
+#include "insns.inc"
+#include "insns_info.inc"
+#include "internal/compile.h"
+
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <dlfcn.h>
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#include "dln.h"
+
+#include "ruby/util.h"
+#undef strdup // ruby_strdup may trigger GC
+
+#ifndef MAXPATHLEN
+# define MAXPATHLEN 1024
+#endif
+
+// Atomically set function pointer if possible.
+#define MJIT_ATOMIC_SET(var, val) (void)ATOMIC_PTR_EXCHANGE(var, val)
+
+#define MJIT_TMP_PREFIX "_ruby_mjit_"
+
+extern void rb_native_mutex_lock(rb_nativethread_lock_t *lock);
+extern void rb_native_mutex_unlock(rb_nativethread_lock_t *lock);
+extern void rb_native_mutex_initialize(rb_nativethread_lock_t *lock);
+extern void rb_native_mutex_destroy(rb_nativethread_lock_t *lock);
+
+// process.c
+extern void mjit_add_waiting_pid(rb_vm_t *vm, rb_pid_t pid);
+
+// A copy of MJIT portion of MRI options since MJIT initialization. We
+// need them as MJIT threads still can work when the most MRI data were
+// freed.
+struct mjit_options mjit_opts;
+
+// true if MJIT is enabled.
+bool mjit_enabled = false;
+// true if JIT-ed code should be called. When `ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS`
+// and `mjit_call_p == false`, any JIT-ed code execution is cancelled as soon as possible.
+bool mjit_call_p = false;
+// A flag to communicate that mjit_call_p should be disabled while it's temporarily false.
+bool mjit_cancel_p = false;
+// There's an ISEQ in unit_queue whose total_calls reached 2 * call_threshold.
+// If this is true, check_unit_queue will start compiling ISEQs in unit_queue.
+static bool mjit_compile_p = false;
+// The actual number of units in active_units
+static int active_units_length = 0;
+// The actual number of units in compact_units
+static int compact_units_length = 0;
+
+// Priority queue of iseqs waiting for JIT compilation.
+// This variable is a pointer to head unit of the queue.
+static struct rb_mjit_unit_list unit_queue = { CCAN_LIST_HEAD_INIT(unit_queue.head) };
+// List of units which are successfully compiled.
+static struct rb_mjit_unit_list active_units = { CCAN_LIST_HEAD_INIT(active_units.head) };
+// List of compacted so files which will be cleaned up by `free_list()` in `mjit_finish()`.
+static struct rb_mjit_unit_list compact_units = { CCAN_LIST_HEAD_INIT(compact_units.head) };
+// List of units before recompilation and just waiting for dlclose().
+static struct rb_mjit_unit_list stale_units = { CCAN_LIST_HEAD_INIT(stale_units.head) };
+// The number of so far processed ISEQs, used to generate unique id.
+static int current_unit_num;
+// A mutex for conitionals and critical sections.
+static rb_nativethread_lock_t mjit_engine_mutex;
+// Set to true to stop worker.
+static bool stop_worker_p;
+// Set to true if worker is stopped.
+static bool worker_stopped = true;
+
+// Path of "/tmp", which is different on Windows or macOS. See: system_default_tmpdir()
+static char *tmp_dir;
+
+// Used C compiler path.
+static const char *cc_path;
+// Used C compiler flags.
+static const char **cc_common_args;
+// Used C compiler flags added by --mjit-debug=...
+static char **cc_added_args;
+// Name of the precompiled header file.
+static char *pch_file;
+// The process id which should delete the pch_file on mjit_finish.
+static rb_pid_t pch_owner_pid;
+// Status of the precompiled header creation. The status is
+// shared by the workers and the pch thread.
+static enum {PCH_NOT_READY, PCH_FAILED, PCH_SUCCESS} pch_status;
+
+// The start timestamp of current compilation
+static double current_cc_ms = 0.0; // TODO: make this part of unit?
+// Currently compiling MJIT unit
+static struct rb_mjit_unit *current_cc_unit = NULL;
+// PID of currently running C compiler process. 0 if nothing is running.
+static pid_t current_cc_pid = 0; // TODO: make this part of unit?
+
+// Name of the header file.
+static char *header_file;
+
+#include "mjit_config.h"
+
+#if defined(__GNUC__) && \
+ (!defined(__clang__) || \
+ (defined(__clang__) && (defined(__FreeBSD__) || defined(__GLIBC__))))
+# define GCC_PIC_FLAGS "-Wfatal-errors", "-fPIC", "-shared", "-w", "-pipe",
+# define MJIT_CFLAGS_PIPE 1
+#else
+# define GCC_PIC_FLAGS /* empty */
+# define MJIT_CFLAGS_PIPE 0
+#endif
+
+// Use `-nodefaultlibs -nostdlib` for GCC where possible, which does not work on cygwin, AIX, and OpenBSD.
+// This seems to improve MJIT performance on GCC.
+#if defined __GNUC__ && !defined __clang__ && !defined(__CYGWIN__) && !defined(_AIX) && !defined(__OpenBSD__)
+# define GCC_NOSTDLIB_FLAGS "-nodefaultlibs", "-nostdlib",
+#else
+# define GCC_NOSTDLIB_FLAGS // empty
+#endif
+
+static const char *const CC_COMMON_ARGS[] = {
+ MJIT_CC_COMMON MJIT_CFLAGS GCC_PIC_FLAGS
+ NULL
+};
+
+static const char *const CC_DEBUG_ARGS[] = {MJIT_DEBUGFLAGS NULL};
+static const char *const CC_OPTIMIZE_ARGS[] = {MJIT_OPTFLAGS NULL};
+
+static const char *const CC_LDSHARED_ARGS[] = {MJIT_LDSHARED MJIT_CFLAGS GCC_PIC_FLAGS NULL};
+static const char *const CC_DLDFLAGS_ARGS[] = {MJIT_DLDFLAGS NULL};
+// `CC_LINKER_ARGS` are linker flags which must be passed to `-c` as well.
+static const char *const CC_LINKER_ARGS[] = {
+#if defined __GNUC__ && !defined __clang__ && !defined(__OpenBSD__)
+ "-nostartfiles",
+#endif
+ GCC_NOSTDLIB_FLAGS NULL
+};
+
+static const char *const CC_LIBS[] = {
+#if defined(__CYGWIN__)
+ MJIT_LIBS // mswin, cygwin
+#endif
+#if defined __GNUC__ && !defined __clang__
+ "-lgcc", // cygwin, and GCC platforms using `-nodefaultlibs -nostdlib`
+#endif
+#if defined __ANDROID__
+ "-lm", // to avoid 'cannot locate symbol "modf" referenced by .../_ruby_mjit_XXX.so"'
+#endif
+ NULL
+};
+
+#define CC_CODEFLAG_ARGS (mjit_opts.debug ? CC_DEBUG_ARGS : CC_OPTIMIZE_ARGS)
+
+// Print the arguments according to FORMAT to stderr only if MJIT
+// verbose option value is more or equal to LEVEL.
+PRINTF_ARGS(static void, 2, 3)
+verbose(int level, const char *format, ...)
+{
+ if (mjit_opts.verbose >= level) {
+ va_list args;
+ size_t len = strlen(format);
+ char *full_format = alloca(sizeof(char) * (len + 2));
+
+ // Creating `format + '\n'` to atomically print format and '\n'.
+ memcpy(full_format, format, len);
+ full_format[len] = '\n';
+ full_format[len+1] = '\0';
+
+ va_start(args, format);
+ vfprintf(stderr, full_format, args);
+ va_end(args);
+ }
+}
+
+PRINTF_ARGS(static void, 1, 2)
+mjit_warning(const char *format, ...)
+{
+ if (mjit_opts.warnings || mjit_opts.verbose) {
+ va_list args;
+
+ fprintf(stderr, "MJIT warning: ");
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ }
+}
+
+// Add unit node to the tail of doubly linked `list`. It should be not in
+// the list before.
+static void
+add_to_list(struct rb_mjit_unit *unit, struct rb_mjit_unit_list *list)
+{
+ ccan_list_add_tail(&list->head, &unit->unode);
+ list->length++;
+}
+
+static void
+remove_from_list(struct rb_mjit_unit *unit, struct rb_mjit_unit_list *list)
+{
+ ccan_list_del(&unit->unode);
+ list->length--;
+}
+
+static void
+remove_file(const char *filename)
+{
+ if (remove(filename)) {
+ mjit_warning("failed to remove \"%s\": %s", filename, strerror(errno));
+ }
+}
+
+// This is called in the following situations:
+// 1) On dequeue or `unload_units()`, associated ISeq is already GCed.
+// 2) The unit is not called often and unloaded by `unload_units()`.
+// 3) Freeing lists on `mjit_finish()`.
+//
+// `jit_func` value does not matter for 1 and 3 since the unit won't be used anymore.
+// For the situation 2, this sets the ISeq's JIT state to MJIT_FUNC_FAILED
+// to prevent the situation that the same methods are continuously compiled.
+static void
+free_unit(struct rb_mjit_unit *unit)
+{
+ if (unit->iseq) { // ISeq is not GCed
+ ISEQ_BODY(unit->iseq)->jit_func = (jit_func_t)MJIT_FUNC_FAILED;
+ ISEQ_BODY(unit->iseq)->mjit_unit = NULL;
+ }
+ if (unit->cc_entries) {
+ void *entries = (void *)unit->cc_entries;
+ free(entries);
+ }
+ if (unit->handle && dlclose(unit->handle)) { // handle is NULL if it's in queue
+ mjit_warning("failed to close handle for u%d: %s", unit->id, dlerror());
+ }
+ xfree(unit);
+}
+
+// Start a critical section. Use message `msg` to print debug info at `level`.
+static inline void
+CRITICAL_SECTION_START(int level, const char *msg)
+{
+ verbose(level, "Locking %s", msg);
+ rb_native_mutex_lock(&mjit_engine_mutex);
+ verbose(level, "Locked %s", msg);
+}
+
+// Finish the current critical section. Use message `msg` to print
+// debug info at `level`.
+static inline void
+CRITICAL_SECTION_FINISH(int level, const char *msg)
+{
+ verbose(level, "Unlocked %s", msg);
+ rb_native_mutex_unlock(&mjit_engine_mutex);
+}
+
+static pid_t mjit_pid = 0;
+
+static int
+sprint_uniq_filename(char *str, size_t size, unsigned long id, const char *prefix, const char *suffix)
+{
+ return snprintf(str, size, "%s/%sp%"PRI_PIDT_PREFIX"uu%lu%s", tmp_dir, prefix, mjit_pid, id, suffix);
+}
+
+// Return time in milliseconds as a double.
+#ifdef __APPLE__
+double ruby_real_ms_time(void);
+# define real_ms_time() ruby_real_ms_time()
+#else
+static double
+real_ms_time(void)
+{
+# ifdef HAVE_CLOCK_GETTIME
+ struct timespec tv;
+# ifdef CLOCK_MONOTONIC
+ const clockid_t c = CLOCK_MONOTONIC;
+# else
+ const clockid_t c = CLOCK_REALTIME;
+# endif
+
+ clock_gettime(c, &tv);
+ return tv.tv_nsec / 1000000.0 + tv.tv_sec * 1000.0;
+# else
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ return tv.tv_usec / 1000.0 + tv.tv_sec * 1000.0;
+# endif
+}
+#endif
+
+// Return the best unit from list. The best is the first
+// high priority unit or the unit whose iseq has the biggest number
+// of calls so far.
+static struct rb_mjit_unit *
+get_from_list(struct rb_mjit_unit_list *list)
+{
+ // Find iseq with max total_calls
+ struct rb_mjit_unit *unit = NULL, *next, *best = NULL;
+ ccan_list_for_each_safe(&list->head, unit, next, unode) {
+ if (unit->iseq == NULL) { // ISeq is GCed.
+ remove_from_list(unit, list);
+ free_unit(unit);
+ continue;
+ }
+
+ if (best == NULL || ISEQ_BODY(best->iseq)->total_calls < ISEQ_BODY(unit->iseq)->total_calls) {
+ best = unit;
+ }
+ }
+
+ if (best) {
+ remove_from_list(best, list);
+ }
+ return best;
+}
+
+// Return length of NULL-terminated array `args` excluding the NULL marker.
+static size_t
+args_len(char *const *args)
+{
+ size_t i;
+
+ for (i = 0; (args[i]) != NULL;i++)
+ ;
+ return i;
+}
+
+// Concatenate `num` passed NULL-terminated arrays of strings, put the
+// result (with NULL end marker) into the heap, and return the result.
+static char **
+form_args(int num, ...)
+{
+ va_list argp;
+ size_t len, n;
+ int i;
+ char **args, **res, **tmp;
+
+ va_start(argp, num);
+ res = NULL;
+ for (i = len = 0; i < num; i++) {
+ args = va_arg(argp, char **);
+ n = args_len(args);
+ if ((tmp = (char **)realloc(res, sizeof(char *) * (len + n + 1))) == NULL) {
+ free(res);
+ res = NULL;
+ break;
+ }
+ res = tmp;
+ MEMCPY(res + len, args, char *, n + 1);
+ len += n;
+ }
+ va_end(argp);
+ return res;
+}
+
+COMPILER_WARNING_PUSH
+#if __has_warning("-Wdeprecated-declarations") || RBIMPL_COMPILER_IS(GCC)
+COMPILER_WARNING_IGNORED(-Wdeprecated-declarations)
+#endif
+// Start an OS process of absolute executable path with arguments `argv`.
+// Return PID of the process.
+static pid_t
+start_process(const char *abspath, char *const *argv)
+{
+ // Not calling non-async-signal-safe functions between vfork
+ // and execv for safety
+ int dev_null = rb_cloexec_open(ruby_null_device, O_WRONLY, 0);
+ if (dev_null < 0) {
+ verbose(1, "MJIT: Failed to open a null device: %s", strerror(errno));
+ return -1;
+ }
+ if (mjit_opts.verbose >= 2) {
+ const char *arg;
+ fprintf(stderr, "Starting process: %s", abspath);
+ for (int i = 0; (arg = argv[i]) != NULL; i++)
+ fprintf(stderr, " %s", arg);
+ fprintf(stderr, "\n");
+ }
+
+ pid_t pid;
+ if ((pid = vfork()) == 0) { /* TODO: reuse some function in process.c */
+ umask(0077);
+ if (mjit_opts.verbose == 0) {
+ // CC can be started in a thread using a file which has been
+ // already removed while MJIT is finishing. Discard the
+ // messages about missing files.
+ dup2(dev_null, STDERR_FILENO);
+ dup2(dev_null, STDOUT_FILENO);
+ }
+ (void)close(dev_null);
+ pid = execv(abspath, argv); // Pid will be negative on an error
+ // Even if we successfully found CC to compile PCH we still can
+ // fail with loading the CC in very rare cases for some reasons.
+ // Stop the forked process in this case.
+ verbose(1, "MJIT: Error in execv: %s", abspath);
+ _exit(1);
+ }
+ (void)close(dev_null);
+ return pid;
+}
+COMPILER_WARNING_POP
+
+// Execute an OS process of executable PATH with arguments ARGV.
+// Return -1 or -2 if failed to execute, otherwise exit code of the process.
+// TODO: Use a similar function in process.c
+static int
+exec_process(const char *path, char *const argv[])
+{
+ int stat, exit_code = -2;
+ pid_t pid = start_process(path, argv);
+ for (;pid > 0;) {
+ pid_t r = waitpid(pid, &stat, 0);
+ if (r == -1) {
+ if (errno == EINTR) continue;
+ fprintf(stderr, "[%"PRI_PIDT_PREFIX"d] waitpid(%lu): %s (SIGCHLD=%d,%u)\n",
+ getpid(), (unsigned long)pid, strerror(errno),
+ RUBY_SIGCHLD, SIGCHLD_LOSSY);
+ break;
+ }
+ else if (r == pid) {
+ if (WIFEXITED(stat)) {
+ exit_code = WEXITSTATUS(stat);
+ break;
+ }
+ else if (WIFSIGNALED(stat)) {
+ exit_code = -1;
+ break;
+ }
+ }
+ }
+ return exit_code;
+}
+
+static void
+remove_so_file(const char *so_file, struct rb_mjit_unit *unit)
+{
+ remove_file(so_file);
+}
+
+// Print _mjitX, but make a human-readable funcname when --mjit-debug is used
+static void
+sprint_funcname(char *funcname, size_t funcname_size, const struct rb_mjit_unit *unit)
+{
+ const rb_iseq_t *iseq = unit->iseq;
+ if (iseq == NULL || (!mjit_opts.debug && !mjit_opts.debug_flags)) {
+ snprintf(funcname, funcname_size, "_mjit%d", unit->id);
+ return;
+ }
+
+ // Generate a short path
+ const char *path = RSTRING_PTR(rb_iseq_path(iseq));
+ const char *lib = "/lib/";
+ const char *version = "/" STRINGIZE(RUBY_API_VERSION_MAJOR) "." STRINGIZE(RUBY_API_VERSION_MINOR) "." STRINGIZE(RUBY_API_VERSION_TEENY) "/";
+ while (strstr(path, lib)) // skip "/lib/"
+ path = strstr(path, lib) + strlen(lib);
+ while (strstr(path, version)) // skip "/x.y.z/"
+ path = strstr(path, version) + strlen(version);
+
+ // Annotate all-normalized method names
+ const char *method = RSTRING_PTR(ISEQ_BODY(iseq)->location.label);
+ if (!strcmp(method, "[]")) method = "AREF";
+ if (!strcmp(method, "[]=")) method = "ASET";
+
+ // Print and normalize
+ snprintf(funcname, funcname_size, "_mjit%d_%s_%s", unit->id, path, method);
+ for (size_t i = 0; i < strlen(funcname); i++) {
+ char c = funcname[i];
+ if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_')) {
+ funcname[i] = '_';
+ }
+ }
+}
+
+static const int c_file_access_mode =
+#ifdef O_BINARY
+ O_BINARY|
+#endif
+ O_WRONLY|O_EXCL|O_CREAT;
+
+#define append_str2(p, str, len) ((char *)memcpy((p), str, (len))+(len))
+#define append_str(p, str) append_str2(p, str, sizeof(str)-1)
+#define append_lit(p, str) append_str2(p, str, rb_strlen_lit(str))
+
+// The function producing the pre-compiled header.
+static void
+make_pch(void)
+{
+ const char *rest_args[] = {
+# ifdef __clang__
+ "-Xclang",
+ "-emit-pch",
+ "-c",
+# endif
+ // -nodefaultlibs is a linker flag, but it may affect cc1 behavior on Gentoo, which should NOT be changed on pch:
+ // https://gitweb.gentoo.org/proj/gcc-patches.git/tree/7.3.0/gentoo/13_all_default-ssp-fix.patch
+ GCC_NOSTDLIB_FLAGS
+ "-o", pch_file, header_file,
+ NULL,
+ };
+
+ verbose(2, "Creating precompiled header");
+ char **args = form_args(4, cc_common_args, CC_CODEFLAG_ARGS, cc_added_args, rest_args);
+ if (args == NULL) {
+ mjit_warning("making precompiled header failed on forming args");
+ pch_status = PCH_FAILED;
+ return;
+ }
+
+ int exit_code = exec_process(cc_path, args);
+ free(args);
+
+ if (exit_code == 0) {
+ pch_status = PCH_SUCCESS;
+ }
+ else {
+ mjit_warning("Making precompiled header failed on compilation. Stopping MJIT worker...");
+ pch_status = PCH_FAILED;
+ }
+}
+
+static int
+c_compile(const char *c_file, const char *so_file)
+{
+ const char *so_args[] = {
+ "-o", so_file,
+# ifdef __clang__
+ "-include-pch", pch_file,
+# endif
+ c_file, NULL
+ };
+
+# if defined(__MACH__)
+ extern VALUE rb_libruby_selfpath;
+ const char *loader_args[] = {"-bundle_loader", StringValuePtr(rb_libruby_selfpath), NULL};
+# else
+ const char *loader_args[] = {NULL};
+# endif
+
+ char **args = form_args(8, CC_LDSHARED_ARGS, CC_CODEFLAG_ARGS, cc_added_args,
+ so_args, loader_args, CC_LIBS, CC_DLDFLAGS_ARGS, CC_LINKER_ARGS);
+ if (args == NULL) return 1;
+
+ int exit_code = exec_process(cc_path, args);
+ if (!mjit_opts.save_temps)
+ remove_file(c_file);
+
+ free(args);
+ return exit_code;
+}
+
+static int
+c_compile_unit(struct rb_mjit_unit *unit)
+{
+ static const char c_ext[] = ".c";
+ static const char so_ext[] = DLEXT;
+ char c_file[MAXPATHLEN], so_file[MAXPATHLEN];
+
+ sprint_uniq_filename(c_file, (int)sizeof(c_file), unit->id, MJIT_TMP_PREFIX, c_ext);
+ sprint_uniq_filename(so_file, (int)sizeof(so_file), unit->id, MJIT_TMP_PREFIX, so_ext);
+
+ return c_compile(c_file, so_file);
+}
+
+static void compile_prelude(FILE *f);
+
+static bool
+mjit_batch(struct rb_mjit_unit *unit)
+{
+ VM_ASSERT(unit->type == MJIT_UNIT_BATCH);
+ static const char c_ext[] = ".c";
+ static const char so_ext[] = DLEXT;
+ char c_file[MAXPATHLEN], so_file[MAXPATHLEN];
+
+ sprint_uniq_filename(c_file, (int)sizeof(c_file), unit->id, MJIT_TMP_PREFIX, c_ext);
+ sprint_uniq_filename(so_file, (int)sizeof(so_file), unit->id, MJIT_TMP_PREFIX, so_ext);
+
+ FILE *f;
+ int fd = rb_cloexec_open(c_file, c_file_access_mode, 0600);
+ if (fd < 0 || (f = fdopen(fd, "w")) == NULL) {
+ int e = errno;
+ if (fd >= 0) (void)close(fd);
+ verbose(1, "Failed to fopen '%s', giving up JIT for it (%s)", c_file, strerror(e));
+ return false;
+ }
+
+ compile_prelude(f);
+
+ bool success = true;
+ struct rb_mjit_unit *child_unit = 0;
+ ccan_list_for_each(&unit->units.head, child_unit, unode) {
+ if (!success) continue;
+ if (child_unit->iseq == NULL) continue; // ISEQ is GCed
+
+ char funcname[MAXPATHLEN];
+ sprint_funcname(funcname, sizeof(funcname), child_unit);
+
+ int iseq_lineno = ISEQ_BODY(child_unit->iseq)->location.first_lineno;
+ const char *sep = "@";
+ const char *iseq_label = RSTRING_PTR(ISEQ_BODY(child_unit->iseq)->location.label);
+ const char *iseq_path = RSTRING_PTR(rb_iseq_path(child_unit->iseq));
+ if (!iseq_label) iseq_label = sep = "";
+ fprintf(f, "\n/* %s%s%s:%d */\n", iseq_label, sep, iseq_path, iseq_lineno);
+ success &= mjit_compile(f, child_unit->iseq, funcname, child_unit->id);
+ }
+
+ fclose(f);
+ return success;
+}
+
+// Compile all cached .c files and build a single .so file. Reload all JIT func from it.
+// This improves the code locality for better performance in terms of iTLB and iCache.
+static bool
+mjit_compact(struct rb_mjit_unit *unit)
+{
+ VM_ASSERT(unit->type == MJIT_UNIT_COMPACT);
+ static const char c_ext[] = ".c";
+ static const char so_ext[] = DLEXT;
+ char c_file[MAXPATHLEN], so_file[MAXPATHLEN];
+
+ sprint_uniq_filename(c_file, (int)sizeof(c_file), unit->id, MJIT_TMP_PREFIX, c_ext);
+ sprint_uniq_filename(so_file, (int)sizeof(so_file), unit->id, MJIT_TMP_PREFIX, so_ext);
+
+ FILE *f;
+ int fd = rb_cloexec_open(c_file, c_file_access_mode, 0600);
+ if (fd < 0 || (f = fdopen(fd, "w")) == NULL) {
+ int e = errno;
+ if (fd >= 0) (void)close(fd);
+ verbose(1, "Failed to fopen '%s', giving up JIT for it (%s)", c_file, strerror(e));
+ return false;
+ }
+
+ compile_prelude(f);
+
+ bool success = true;
+ compact_units_length = 0;
+ struct rb_mjit_unit *batch_unit = 0, *child_unit = 0;
+ ccan_list_for_each(&active_units.head, batch_unit, unode) {
+ ccan_list_for_each(&batch_unit->units.head, child_unit, unode) {
+ if (!success) continue;
+ if (child_unit->iseq == NULL) continue; // ISEQ is GCed
+
+ char funcname[MAXPATHLEN];
+ sprint_funcname(funcname, sizeof(funcname), child_unit);
+
+ int iseq_lineno = ISEQ_BODY(child_unit->iseq)->location.first_lineno;
+ const char *sep = "@";
+ const char *iseq_label = RSTRING_PTR(ISEQ_BODY(child_unit->iseq)->location.label);
+ const char *iseq_path = RSTRING_PTR(rb_iseq_path(child_unit->iseq));
+ if (!iseq_label) iseq_label = sep = "";
+ fprintf(f, "\n/* %s%s%s:%d */\n", iseq_label, sep, iseq_path, iseq_lineno);
+ success &= mjit_compile(f, child_unit->iseq, funcname, child_unit->id);
+ compact_units_length++;
+ }
+ }
+
+ fclose(f);
+ return success;
+}
+
+static void
+load_batch_funcs_from_so(struct rb_mjit_unit *unit, char *c_file, char *so_file)
+{
+ double end_time = real_ms_time();
+
+ void *handle = dlopen(so_file, RTLD_NOW);
+ if (handle == NULL) {
+ mjit_warning("failure in loading code from batched '%s': %s", so_file, dlerror());
+ xfree(unit);
+ return;
+ }
+ unit->handle = handle;
+
+ // lazily dlclose handle on `mjit_finish()`.
+ add_to_list(unit, &active_units);
+ active_units_length += unit->units.length;
+
+ if (!mjit_opts.save_temps)
+ remove_so_file(so_file, unit);
+
+ struct rb_mjit_unit *child_unit = 0;
+ ccan_list_for_each(&unit->units.head, child_unit, unode) {
+ char funcname[MAXPATHLEN];
+ sprint_funcname(funcname, sizeof(funcname), child_unit);
+
+ void *func;
+ if ((func = dlsym(handle, funcname)) == NULL) {
+ mjit_warning("skipping to load '%s' from '%s': %s", funcname, so_file, dlerror());
+ continue;
+ }
+
+ if (child_unit->iseq) { // Check whether GCed or not
+ // Usage of jit_code might be not in a critical section.
+ const rb_iseq_t *iseq = child_unit->iseq;
+ MJIT_ATOMIC_SET(ISEQ_BODY(iseq)->jit_func, (jit_func_t)func);
+
+ verbose(1, "JIT success: %s@%s:%d",
+ RSTRING_PTR(ISEQ_BODY(iseq)->location.label),
+ RSTRING_PTR(rb_iseq_path(iseq)), ISEQ_BODY(iseq)->location.first_lineno);
+ }
+ else {
+ verbose(1, "JIT skip: A compiled method has been GCed");
+ }
+ }
+ verbose(1, "JIT batch (%.1fms): Batched %d methods %s -> %s", end_time - current_cc_ms, unit->units.length, c_file, so_file);
+}
+
+static void
+load_compact_funcs_from_so(struct rb_mjit_unit *unit, char *c_file, char *so_file)
+{
+ double end_time = real_ms_time();
+
+ void *handle = dlopen(so_file, RTLD_NOW);
+ if (handle == NULL) {
+ mjit_warning("failure in loading code from compacted '%s': %s", so_file, dlerror());
+ xfree(unit);
+ return;
+ }
+ unit->handle = handle;
+
+ // lazily dlclose handle on `mjit_finish()`.
+ add_to_list(unit, &compact_units);
+
+ if (!mjit_opts.save_temps)
+ remove_so_file(so_file, unit);
+
+ struct rb_mjit_unit *batch_unit = 0, *child_unit = 0;
+ ccan_list_for_each(&active_units.head, batch_unit, unode) {
+ ccan_list_for_each(&batch_unit->units.head, child_unit, unode) {
+ if (child_unit->iseq == NULL) continue; // ISEQ is GCed
+
+ char funcname[MAXPATHLEN];
+ sprint_funcname(funcname, sizeof(funcname), child_unit);
+
+ void *func;
+ if ((func = dlsym(handle, funcname)) == NULL) {
+ mjit_warning("skipping to reload '%s' from '%s': %s", funcname, so_file, dlerror());
+ continue;
+ }
+
+ if (child_unit->iseq) { // Check whether GCed or not
+ // Usage of jit_code might be not in a critical section.
+ MJIT_ATOMIC_SET(ISEQ_BODY(child_unit->iseq)->jit_func, (jit_func_t)func);
+ }
+ }
+ }
+ verbose(1, "JIT compaction (%.1fms): Compacted %d methods %s -> %s", end_time - current_cc_ms, active_units_length, c_file, so_file);
+}
+
+#ifndef __clang__
+static const char *
+header_name_end(const char *s)
+{
+ const char *e = s + strlen(s);
+# ifdef __GNUC__ // don't chomp .pch for mswin
+ static const char suffix[] = ".gch";
+
+ // chomp .gch suffix
+ if (e > s+sizeof(suffix)-1 && strcmp(e-sizeof(suffix)+1, suffix) == 0) {
+ e -= sizeof(suffix)-1;
+ }
+# endif
+ return e;
+}
+#endif
+
+// Print platform-specific prerequisites in generated code.
+static void
+compile_prelude(FILE *f)
+{
+#ifndef __clang__ // -include-pch is used for Clang
+ const char *s = pch_file;
+ const char *e = header_name_end(s);
+
+ fprintf(f, "#include \"");
+ // print pch_file except .gch for gcc, but keep .pch for mswin
+ for (; s < e; s++) {
+ switch (*s) {
+ case '\\': case '"':
+ fputc('\\', f);
+ }
+ fputc(*s, f);
+ }
+ fprintf(f, "\"\n");
+#endif
+}
+
+static pid_t
+start_c_compile_unit(struct rb_mjit_unit *unit)
+{
+ extern pid_t rb_mjit_fork();
+ pid_t pid = rb_mjit_fork();
+ if (pid == 0) {
+ int exit_code = c_compile_unit(unit);
+ exit(exit_code);
+ }
+ else {
+ return pid;
+ }
+}
+
+// Capture cc entries of `captured_iseq` and append them to `compiled_iseq->mjit_unit->cc_entries`.
+// This is needed when `captured_iseq` is inlined by `compiled_iseq` and GC needs to mark inlined cc.
+//
+// Index to refer to `compiled_iseq->mjit_unit->cc_entries` is returned instead of the address
+// because old addresses may be invalidated by `realloc` later. -1 is returned on failure.
+//
+// This assumes that it's safe to reference cc without acquiring GVL.
+int
+mjit_capture_cc_entries(const struct rb_iseq_constant_body *compiled_iseq, const struct rb_iseq_constant_body *captured_iseq)
+{
+ VM_ASSERT(compiled_iseq != NULL);
+ VM_ASSERT(compiled_iseq->mjit_unit != NULL);
+ VM_ASSERT(captured_iseq != NULL);
+
+ struct rb_mjit_unit *unit = compiled_iseq->mjit_unit;
+ unsigned int new_entries_size = unit->cc_entries_size + captured_iseq->ci_size;
+ VM_ASSERT(captured_iseq->ci_size > 0);
+
+ // Allocate new cc_entries and append them to unit->cc_entries
+ const struct rb_callcache **cc_entries;
+ int cc_entries_index = unit->cc_entries_size;
+ if (unit->cc_entries_size == 0) {
+ VM_ASSERT(unit->cc_entries == NULL);
+ unit->cc_entries = cc_entries = malloc(sizeof(struct rb_callcache *) * new_entries_size);
+ if (cc_entries == NULL) return -1;
+ }
+ else {
+ void *cc_ptr = (void *)unit->cc_entries; // get rid of bogus warning by VC
+ cc_entries = realloc(cc_ptr, sizeof(struct rb_callcache *) * new_entries_size);
+ if (cc_entries == NULL) return -1;
+ unit->cc_entries = cc_entries;
+ cc_entries += cc_entries_index;
+ }
+ unit->cc_entries_size = new_entries_size;
+
+ // Capture cc to cc_enties
+ for (unsigned int i = 0; i < captured_iseq->ci_size; i++) {
+ cc_entries[i] = captured_iseq->call_data[i].cc;
+ }
+
+ return cc_entries_index;
+}
+
+static void mjit_add_iseq_to_process(const rb_iseq_t *iseq, const struct rb_mjit_compile_info *compile_info);
+
+// Return an unique file name in /tmp with PREFIX and SUFFIX and
+// number ID. Use getpid if ID == 0. The return file name exists
+// until the next function call.
+static char *
+get_uniq_filename(unsigned long id, const char *prefix, const char *suffix)
+{
+ char buff[70], *str = buff;
+ int size = sprint_uniq_filename(buff, sizeof(buff), id, prefix, suffix);
+ str = 0;
+ ++size;
+ str = xmalloc(size);
+ if (size <= (int)sizeof(buff)) {
+ memcpy(str, buff, size);
+ }
+ else {
+ sprint_uniq_filename(str, size, id, prefix, suffix);
+ }
+ return str;
+}
+
+// Prohibit calling JIT-ed code and let existing JIT-ed frames exit before the next insn.
+void
+mjit_cancel_all(const char *reason)
+{
+ if (!mjit_enabled)
+ return;
+
+ mjit_call_p = false;
+ mjit_cancel_p = true;
+ if (mjit_opts.warnings || mjit_opts.verbose) {
+ fprintf(stderr, "JIT cancel: Disabled JIT-ed code because %s\n", reason);
+ }
+}
+
+// Deal with ISeq movement from compactor
+void
+mjit_update_references(const rb_iseq_t *iseq)
+{
+ if (!mjit_enabled)
+ return;
+
+ CRITICAL_SECTION_START(4, "mjit_update_references");
+ if (ISEQ_BODY(iseq)->mjit_unit) {
+ ISEQ_BODY(iseq)->mjit_unit->iseq = (rb_iseq_t *)rb_gc_location((VALUE)ISEQ_BODY(iseq)->mjit_unit->iseq);
+ // We need to invalidate JIT-ed code for the ISeq because it embeds pointer addresses.
+ // To efficiently do that, we use the same thing as TracePoint and thus everything is cancelled for now.
+ // See mjit.h and tool/ruby_vm/views/_mjit_compile_insn.erb for how `mjit_call_p` is used.
+ mjit_cancel_all("GC.compact is used"); // TODO: instead of cancelling all, invalidate only this one and recompile it with some threshold.
+ }
+
+ // Units in stale_units (list of over-speculated and invalidated code) are not referenced from
+ // `ISEQ_BODY(iseq)->mjit_unit` anymore (because new one replaces that). So we need to check them too.
+ // TODO: we should be able to reduce the number of units checked here.
+ struct rb_mjit_unit *unit = NULL;
+ ccan_list_for_each(&stale_units.head, unit, unode) {
+ if (unit->iseq == iseq) {
+ unit->iseq = (rb_iseq_t *)rb_gc_location((VALUE)unit->iseq);
+ }
+ }
+ CRITICAL_SECTION_FINISH(4, "mjit_update_references");
+}
+
+// Iseqs can be garbage collected. This function should call when it
+// happens. It removes iseq from the unit.
+void
+mjit_free_iseq(const rb_iseq_t *iseq)
+{
+ if (!mjit_enabled)
+ return;
+
+ if (ISEQ_BODY(iseq)->mjit_unit) {
+ // mjit_unit is not freed here because it may be referred by multiple
+ // lists of units. `get_from_list` and `mjit_finish` do the job.
+ ISEQ_BODY(iseq)->mjit_unit->iseq = NULL;
+ }
+ // Units in stale_units (list of over-speculated and invalidated code) are not referenced from
+ // `ISEQ_BODY(iseq)->mjit_unit` anymore (because new one replaces that). So we need to check them too.
+ // TODO: we should be able to reduce the number of units checked here.
+ struct rb_mjit_unit *unit = NULL;
+ ccan_list_for_each(&stale_units.head, unit, unode) {
+ if (unit->iseq == iseq) {
+ unit->iseq = NULL;
+ }
+ }
+}
+
+// Free unit list. This should be called only when worker is finished
+// because node of unit_queue and one of active_units may have the same unit
+// during proceeding unit.
+static void
+free_list(struct rb_mjit_unit_list *list, bool close_handle_p)
+{
+ struct rb_mjit_unit *unit = 0, *next;
+
+ ccan_list_for_each_safe(&list->head, unit, next, unode) {
+ ccan_list_del(&unit->unode);
+ if (!close_handle_p) unit->handle = NULL; /* Skip dlclose in free_unit() */
+
+ if (list == &stale_units) { // `free_unit(unit)` crashes after GC.compact on `stale_units`
+ /*
+ * TODO: REVERT THIS BRANCH
+ * Debug the crash on stale_units w/ GC.compact and just use `free_unit(unit)`!!
+ */
+ if (unit->handle && dlclose(unit->handle)) {
+ mjit_warning("failed to close handle for u%d: %s", unit->id, dlerror());
+ }
+ xfree(unit);
+ }
+ else {
+ free_unit(unit);
+ }
+ }
+ list->length = 0;
+}
+
+static struct rb_mjit_unit*
+create_unit(enum rb_mjit_unit_type type)
+{
+ struct rb_mjit_unit *unit = ZALLOC_N(struct rb_mjit_unit, 1);
+ unit->id = current_unit_num++;
+ unit->type = type;
+ if (type == MJIT_UNIT_BATCH) {
+ ccan_list_head_init(&unit->units.head);
+ }
+ return unit;
+}
+
+static struct rb_mjit_unit*
+create_iseq_unit(const rb_iseq_t *iseq)
+{
+ struct rb_mjit_unit *unit = create_unit(MJIT_UNIT_ISEQ);
+ unit->iseq = (rb_iseq_t *)iseq;
+ ISEQ_BODY(iseq)->mjit_unit = unit;
+ return unit;
+}
+
+static void mjit_wait(struct rb_mjit_unit *unit);
+
+// Check the unit queue and start mjit_compile if nothing is in progress.
+static void
+check_unit_queue(void)
+{
+ if (mjit_opts.custom) return; // Custom RubyVM::MJIT.compile is in use
+ if (worker_stopped) return;
+ if (current_cc_pid != 0) return; // still compiling
+
+ // TODO: resurrect unload_units
+ if (active_units_length >= mjit_opts.max_cache_size) return; // wait until unload_units makes a progress
+
+ // No ISEQ in unit_queue has enough calls to trigger JIT
+ if (!mjit_compile_p) return;
+ mjit_compile_p = false;
+
+ // Compile all ISEQs in unit_queue together
+ struct rb_mjit_unit *unit = create_unit(MJIT_UNIT_BATCH);
+ struct rb_mjit_unit *child_unit = NULL;
+ VM_ASSERT(unit_queue.length > 0);
+ while ((child_unit = get_from_list(&unit_queue)) != NULL && (active_units_length + unit->units.length) < mjit_opts.max_cache_size) {
+ add_to_list(child_unit, &unit->units);
+ ISEQ_BODY(child_unit->iseq)->jit_func = (jit_func_t)MJIT_FUNC_COMPILING;
+ }
+
+ // Run the MJIT compiler synchronously
+ current_cc_ms = real_ms_time();
+ current_cc_unit = unit;
+ bool success = mjit_batch(unit);
+ if (!success) {
+ mjit_notify_waitpid(1);
+ return;
+ }
+
+ // Run the C compiler asynchronously (unless --mjit-wait)
+ if (mjit_opts.wait) {
+ int exit_code = c_compile_unit(unit);
+ mjit_notify_waitpid(exit_code);
+ }
+ else {
+ current_cc_pid = start_c_compile_unit(unit);
+ if (current_cc_pid == -1) { // JIT failure
+ mjit_notify_waitpid(1);
+ }
+ }
+}
+
+// Check if it should compact all JIT code and start it as needed
+static void
+check_compaction(void)
+{
+ // Allow only `max_cache_size / 100` times (default: 100) of compaction.
+ // Note: GC of compacted code has not been implemented yet.
+ int max_compact_size = mjit_opts.max_cache_size / 100;
+ if (max_compact_size < 10) max_compact_size = 10;
+
+ // Run JIT compaction only when it's going to add 10%+ units.
+ int throttle_threshold = active_units_length / 10;
+
+ if (compact_units.length < max_compact_size
+ && active_units_length - compact_units_length > throttle_threshold
+ && ((!mjit_opts.wait && unit_queue.length == 0 && active_units.length > 1)
+ || (active_units_length == mjit_opts.max_cache_size))) {
+ struct rb_mjit_unit *unit = create_unit(MJIT_UNIT_COMPACT);
+
+ // Run the MJIT compiler synchronously
+ current_cc_ms = real_ms_time();
+ current_cc_unit = unit;
+ bool success = mjit_compact(unit);
+ if (!success) {
+ mjit_notify_waitpid(1);
+ return;
+ }
+
+ // Run the C compiler asynchronously (unless --mjit-wait)
+ if (mjit_opts.wait) {
+ int exit_code = c_compile_unit(unit);
+ mjit_notify_waitpid(exit_code);
+ }
+ else {
+ current_cc_pid = start_c_compile_unit(unit);
+ if (current_cc_pid == -1) { // JIT failure
+ mjit_notify_waitpid(1);
+ }
+ }
+ }
+}
+
+// Check the current CC process if any, and start a next C compiler process as needed.
+void
+mjit_notify_waitpid(int exit_code)
+{
+ VM_ASSERT(mjit_opts.wait || current_cc_pid != 0);
+ current_cc_pid = 0;
+
+ // Delete .c file
+ char c_file[MAXPATHLEN];
+ sprint_uniq_filename(c_file, (int)sizeof(c_file), current_cc_unit->id, MJIT_TMP_PREFIX, ".c");
+
+ // Check the result
+ if (exit_code != 0) {
+ verbose(2, "Failed to generate so");
+ // TODO: set MJIT_FUNC_FAILED to unit->units
+ // TODO: free list of unit->units
+ free_unit(current_cc_unit);
+ current_cc_unit = NULL;
+ return;
+ }
+
+ // Load .so file
+ char so_file[MAXPATHLEN];
+ sprint_uniq_filename(so_file, (int)sizeof(so_file), current_cc_unit->id, MJIT_TMP_PREFIX, DLEXT);
+ switch (current_cc_unit->type) {
+ case MJIT_UNIT_ISEQ:
+ rb_bug("unreachable: current_cc_unit->type must not be MJIT_UNIT_ISEQ");
+ case MJIT_UNIT_BATCH:
+ load_batch_funcs_from_so(current_cc_unit, c_file, so_file);
+ current_cc_unit = NULL;
+
+ // Run compaction if it should
+ if (!stop_worker_p) {
+ check_compaction();
+ }
+ break;
+ case MJIT_UNIT_COMPACT:
+ load_compact_funcs_from_so(current_cc_unit, c_file, so_file);
+ current_cc_unit = NULL;
+ break;
+ }
+
+ // Skip further compilation if mjit_finish is trying to stop it
+ if (!stop_worker_p) {
+ // Start the next one as needed
+ check_unit_queue();
+ }
+}
+
+// Return true if given ISeq body should be compiled by MJIT
+static inline int
+mjit_target_iseq_p(const rb_iseq_t *iseq)
+{
+ struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
+ return (body->type == ISEQ_TYPE_METHOD || body->type == ISEQ_TYPE_BLOCK)
+ && !body->builtin_inline_p
+ && strcmp("<internal:mjit>", RSTRING_PTR(rb_iseq_path(iseq))) != 0;
+}
+
+// RubyVM::MJIT
+static VALUE rb_mMJIT = 0;
+// RubyVM::MJIT::C
+static VALUE rb_mMJITC = 0;
+// RubyVM::MJIT::Compiler
+static VALUE rb_cMJITCompiler = 0;
+// RubyVM::MJIT::CPointer::Struct_rb_iseq_t
+static VALUE rb_cMJITIseqPtr = 0;
+// RubyVM::MJIT::CPointer::Struct_IC
+static VALUE rb_cMJITICPtr = 0;
+// RubyVM::MJIT::Compiler
+static VALUE rb_mMJITHooks = 0;
+
+#define WITH_MJIT_DISABLED(stmt) do { \
+ bool original_call_p = mjit_call_p; \
+ mjit_call_p = false; \
+ stmt; \
+ mjit_call_p = original_call_p; \
+ if (mjit_cancel_p) mjit_call_p = false; \
+} while (0);
+
+// Hook MJIT when BOP is redefined.
+MJIT_FUNC_EXPORTED void
+rb_mjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ WITH_MJIT_DISABLED({
+ rb_funcall(rb_mMJITHooks, rb_intern("on_bop_redefined"), 2, INT2NUM(redefined_flag), INT2NUM((int)bop));
+ });
+}
+
+// Hook MJIT when CME is invalidated.
+MJIT_FUNC_EXPORTED void
+rb_mjit_cme_invalidate(rb_callable_method_entry_t *cme)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ WITH_MJIT_DISABLED({
+ VALUE cme_klass = rb_funcall(rb_mMJITC, rb_intern("rb_callable_method_entry_struct"), 0);
+ VALUE cme_ptr = rb_funcall(cme_klass, rb_intern("new"), 1, SIZET2NUM((size_t)cme));
+ rb_funcall(rb_mMJITHooks, rb_intern("on_cme_invalidate"), 1, cme_ptr);
+ });
+}
+
+// Hook MJIT when Ractor is spawned.
+void
+rb_mjit_before_ractor_spawn(void)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ WITH_MJIT_DISABLED({
+ rb_funcall(rb_mMJITHooks, rb_intern("on_ractor_spawn"), 0);
+ });
+}
+
+static void
+mjit_constant_state_changed(void *data)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ ID id = (ID)data;
+ WITH_MJIT_DISABLED({
+ rb_funcall(rb_mMJITHooks, rb_intern("on_constant_state_changed"), 1, ID2SYM(id));
+ });
+}
+
+// Hook MJIT when constant state is changed.
+MJIT_FUNC_EXPORTED void
+rb_mjit_constant_state_changed(ID id)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ // Asynchronously hook the Ruby code since this is hooked during a "Ruby critical section".
+ extern int rb_workqueue_register(unsigned flags, rb_postponed_job_func_t func, void *data);
+ rb_workqueue_register(0, mjit_constant_state_changed, (void *)id);
+}
+
+// Hook MJIT when constant IC is updated.
+MJIT_FUNC_EXPORTED void
+rb_mjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ WITH_MJIT_DISABLED({
+ VALUE iseq_ptr = rb_funcall(rb_cMJITIseqPtr, rb_intern("new"), 1, SIZET2NUM((size_t)iseq));
+ VALUE ic_ptr = rb_funcall(rb_cMJITICPtr, rb_intern("new"), 1, SIZET2NUM((size_t)ic));
+ rb_funcall(rb_mMJITHooks, rb_intern("on_constant_ic_update"), 3, iseq_ptr, ic_ptr, UINT2NUM(insn_idx));
+ });
+}
+
+// Hook MJIT when TracePoint is enabled.
+MJIT_FUNC_EXPORTED void
+rb_mjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events)
+{
+ if (!mjit_enabled || !mjit_call_p || !rb_mMJITHooks) return;
+ WITH_MJIT_DISABLED({
+ rb_funcall(rb_mMJITHooks, rb_intern("on_tracing_invalidate_all"), 1, UINT2NUM(new_iseq_events));
+ });
+}
+
+// [experimental] Call custom RubyVM::MJIT.compile if defined
+static void
+mjit_hook_custom_compile(const rb_iseq_t *iseq)
+{
+ WITH_MJIT_DISABLED({
+ VALUE iseq_class = rb_funcall(rb_mMJITC, rb_intern("rb_iseq_t"), 0);
+ VALUE iseq_ptr = rb_funcall(iseq_class, rb_intern("new"), 1, ULONG2NUM((size_t)iseq));
+ VALUE jit_func = rb_funcall(rb_mMJIT, rb_intern("compile"), 1, iseq_ptr);
+ ISEQ_BODY(iseq)->jit_func = (jit_func_t)NUM2ULONG(jit_func);
+ });
+}
+
+static void
+mjit_add_iseq_to_process(const rb_iseq_t *iseq, const struct rb_mjit_compile_info *compile_info)
+{
+ if (!mjit_enabled) return;
+ if (mjit_opts.custom) { // Hook custom RubyVM::MJIT.compile if defined
+ mjit_hook_custom_compile(iseq);
+ return;
+ }
+ if (pch_status != PCH_SUCCESS || !rb_ractor_main_p()) // TODO: Support non-main Ractors
+ return;
+ if (!mjit_target_iseq_p(iseq)) {
+ ISEQ_BODY(iseq)->jit_func = (jit_func_t)MJIT_FUNC_FAILED; // skip mjit_wait
+ return;
+ }
+
+ // For batching multiple ISEQs, we only enqueue ISEQs when total_calls reaches call_threshold,
+ // and compile all enqueued ISEQs when any ISEQ reaches call_threshold * 2.
+ bool recompile_p = !MJIT_FUNC_STATE_P(ISEQ_BODY(iseq)->jit_func);
+ if (!ISEQ_BODY(iseq)->mjit_unit || recompile_p) { // call_threshold, or recompile
+ // Discard an old unit with recompile_p
+ if (recompile_p) {
+ ISEQ_BODY(iseq)->mjit_unit->iseq = NULL; // Ignore this from compaction
+ ISEQ_BODY(iseq)->jit_func = (jit_func_t)MJIT_FUNC_NOT_COMPILED;
+ active_units_length--;
+ }
+
+ // Create a new unit and enqueue it
+ struct rb_mjit_unit *unit = create_iseq_unit(iseq);
+ if (recompile_p) {
+ VM_ASSERT(compile_info != NULL);
+ unit->compile_info = *compile_info;
+ }
+ add_to_list(unit, &unit_queue);
+ ISEQ_BODY(iseq)->total_calls = 0; // come here again :)
+ }
+ else { // call_threshold * 2
+ VM_ASSERT(compile_info == NULL);
+ mjit_compile_p = true; // compile all ISEQs in unit_queue
+ }
+}
+
+// Add ISEQ to be JITed in parallel with the current thread.
+// Unload some JIT codes if there are too many of them.
+void
+rb_mjit_add_iseq_to_process(const rb_iseq_t *iseq)
+{
+ mjit_add_iseq_to_process(iseq, NULL);
+ check_unit_queue();
+}
+
+// For this timeout seconds, mjit_finish will wait for JIT compilation finish.
+#define MJIT_WAIT_TIMEOUT_SECONDS 5
+
+static void
+mjit_wait(struct rb_mjit_unit *unit)
+{
+ pid_t initial_pid = current_cc_pid;
+ if (initial_pid == 0) {
+ mjit_warning("initial_pid was 0 on mjit_wait");
+ return;
+ }
+ if (pch_status == PCH_FAILED) return;
+
+ int tries = 0;
+ struct timeval tv = { .tv_sec = 0, .tv_usec = 1000 };
+ while (current_cc_pid == initial_pid) {
+ tries++;
+ if (tries / 1000 > MJIT_WAIT_TIMEOUT_SECONDS) {
+ if (unit->type == MJIT_UNIT_ISEQ) {
+ unit->iseq->body->jit_func = (jit_func_t)MJIT_FUNC_FAILED; // C compiler was too slow. Give up.
+ }
+ mjit_warning("timed out to wait for JIT finish");
+ break;
+ }
+
+ rb_thread_wait_for(tv);
+ }
+}
+
+struct rb_mjit_compile_info*
+rb_mjit_iseq_compile_info(const struct rb_iseq_constant_body *body)
+{
+ VM_ASSERT(body->mjit_unit != NULL);
+ return &body->mjit_unit->compile_info;
+}
+
+static void
+mjit_recompile(const rb_iseq_t *iseq)
+{
+ if (MJIT_FUNC_STATE_P(ISEQ_BODY(iseq)->jit_func))
+ return;
+
+ verbose(1, "JIT recompile: %s@%s:%d", RSTRING_PTR(ISEQ_BODY(iseq)->location.label),
+ RSTRING_PTR(rb_iseq_path(iseq)), ISEQ_BODY(iseq)->location.first_lineno);
+ VM_ASSERT(ISEQ_BODY(iseq)->mjit_unit != NULL);
+
+ mjit_add_iseq_to_process(iseq, &ISEQ_BODY(iseq)->mjit_unit->compile_info);
+ check_unit_queue();
+}
+
+// Recompile iseq, disabling send optimization
+void
+rb_mjit_recompile_send(const rb_iseq_t *iseq)
+{
+ rb_mjit_iseq_compile_info(ISEQ_BODY(iseq))->disable_send_cache = true;
+ mjit_recompile(iseq);
+}
+
+// Recompile iseq, disabling ivar optimization
+void
+rb_mjit_recompile_ivar(const rb_iseq_t *iseq)
+{
+ rb_mjit_iseq_compile_info(ISEQ_BODY(iseq))->disable_ivar_cache = true;
+ mjit_recompile(iseq);
+}
+
+// Recompile iseq, disabling exivar optimization
+void
+rb_mjit_recompile_exivar(const rb_iseq_t *iseq)
+{
+ rb_mjit_iseq_compile_info(ISEQ_BODY(iseq))->disable_exivar_cache = true;
+ mjit_recompile(iseq);
+}
+
+// Recompile iseq, disabling method inlining
+void
+rb_mjit_recompile_inlining(const rb_iseq_t *iseq)
+{
+ rb_mjit_iseq_compile_info(ISEQ_BODY(iseq))->disable_inlining = true;
+ mjit_recompile(iseq);
+}
+
+// Recompile iseq, disabling getconstant inlining
+void
+rb_mjit_recompile_const(const rb_iseq_t *iseq)
+{
+ rb_mjit_iseq_compile_info(ISEQ_BODY(iseq))->disable_const_cache = true;
+ mjit_recompile(iseq);
+}
+
+extern VALUE ruby_archlibdir_path, ruby_prefix_path;
+
+// Initialize header_file, pch_file, libruby_pathflag. Return true on success.
+static bool
+init_header_filename(void)
+{
+ int fd;
+#ifdef LOAD_RELATIVE
+ // Root path of the running ruby process. Equal to RbConfig::TOPDIR.
+ VALUE basedir_val;
+#endif
+ const char *basedir = "";
+ size_t baselen = 0;
+ char *p;
+
+#ifdef LOAD_RELATIVE
+ basedir_val = ruby_prefix_path;
+ basedir = StringValuePtr(basedir_val);
+ baselen = RSTRING_LEN(basedir_val);
+#else
+ if (getenv("MJIT_SEARCH_BUILD_DIR")) {
+ // This path is not intended to be used on production, but using build directory's
+ // header file here because people want to run `make test-all` without running
+ // `make install`. Don't use $MJIT_SEARCH_BUILD_DIR except for test-all.
+
+ struct stat st;
+ const char *hdr = dlsym(RTLD_DEFAULT, "MJIT_HEADER");
+ if (!hdr) {
+ verbose(1, "No MJIT_HEADER");
+ }
+ else if (hdr[0] != '/') {
+ verbose(1, "Non-absolute header file path: %s", hdr);
+ }
+ else if (stat(hdr, &st) || !S_ISREG(st.st_mode)) {
+ verbose(1, "Non-file header file path: %s", hdr);
+ }
+ else if ((st.st_uid != getuid()) || (st.st_mode & 022) ||
+ !rb_path_check(hdr)) {
+ verbose(1, "Unsafe header file: uid=%ld mode=%#o %s",
+ (long)st.st_uid, (unsigned)st.st_mode, hdr);
+ return FALSE;
+ }
+ else {
+ // Do not pass PRELOADENV to child processes, on
+ // multi-arch environment
+ verbose(3, "PRELOADENV("PRELOADENV")=%s", getenv(PRELOADENV));
+ // assume no other PRELOADENV in test-all
+ unsetenv(PRELOADENV);
+ verbose(3, "MJIT_HEADER: %s", hdr);
+ header_file = ruby_strdup(hdr);
+ if (!header_file) return false;
+ }
+ }
+ else
+#endif
+ {
+ // A name of the header file included in any C file generated by MJIT for iseqs.
+ static const char header_name[] = MJIT_HEADER_INSTALL_DIR "/" MJIT_MIN_HEADER_NAME;
+ const size_t header_name_len = sizeof(header_name) - 1;
+
+ header_file = xmalloc(baselen + header_name_len + 1);
+ p = append_str2(header_file, basedir, baselen);
+ p = append_str2(p, header_name, header_name_len + 1);
+
+ if ((fd = rb_cloexec_open(header_file, O_RDONLY, 0)) < 0) {
+ verbose(1, "Cannot access header file: %s", header_file);
+ xfree(header_file);
+ header_file = NULL;
+ return false;
+ }
+ (void)close(fd);
+ }
+
+ pch_file = get_uniq_filename(0, MJIT_TMP_PREFIX "h", ".h.gch");
+
+ return true;
+}
+
+static char *
+system_default_tmpdir(void)
+{
+ // c.f. ext/etc/etc.c:etc_systmpdir()
+#if defined _CS_DARWIN_USER_TEMP_DIR
+ char path[MAXPATHLEN];
+ size_t len = confstr(_CS_DARWIN_USER_TEMP_DIR, path, sizeof(path));
+ if (len > 0) {
+ char *tmpdir = xmalloc(len);
+ if (len > sizeof(path)) {
+ confstr(_CS_DARWIN_USER_TEMP_DIR, tmpdir, len);
+ }
+ else {
+ memcpy(tmpdir, path, len);
+ }
+ return tmpdir;
+ }
+#endif
+ return 0;
+}
+
+static int
+check_tmpdir(const char *dir)
+{
+ struct stat st;
+
+ if (!dir) return FALSE;
+ if (stat(dir, &st)) return FALSE;
+#ifndef S_ISDIR
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+ if (!S_ISDIR(st.st_mode)) return FALSE;
+#ifndef S_IWOTH
+# define S_IWOTH 002
+#endif
+ if (st.st_mode & S_IWOTH) {
+#ifdef S_ISVTX
+ if (!(st.st_mode & S_ISVTX)) return FALSE;
+#else
+ return FALSE;
+#endif
+ }
+ if (access(dir, W_OK)) return FALSE;
+ return TRUE;
+}
+
+static char *
+system_tmpdir(void)
+{
+ char *tmpdir;
+# define RETURN_ENV(name) \
+ if (check_tmpdir(tmpdir = getenv(name))) return ruby_strdup(tmpdir)
+ RETURN_ENV("TMPDIR");
+ RETURN_ENV("TMP");
+ tmpdir = system_default_tmpdir();
+ if (check_tmpdir(tmpdir)) return tmpdir;
+ return ruby_strdup("/tmp");
+# undef RETURN_ENV
+}
+
+// Minimum value for JIT cache size.
+#define MIN_CACHE_SIZE 10
+// Default permitted number of units with a JIT code kept in memory.
+#define DEFAULT_MAX_CACHE_SIZE 100
+// A default threshold used to add iseq to JIT.
+#define DEFAULT_CALL_THRESHOLD 10000
+
+// Start MJIT worker. Return TRUE if worker is successfully started.
+static bool
+start_worker(void)
+{
+ stop_worker_p = false;
+ worker_stopped = false;
+ return true;
+}
+
+// There's no strndup on Windows
+static char*
+ruby_strndup(const char *str, size_t n)
+{
+ char *ret = xmalloc(n + 1);
+ memcpy(ret, str, n);
+ ret[n] = '\0';
+ return ret;
+}
+
+// Convert "foo bar" to {"foo", "bar", NULL} array. Caller is responsible for
+// freeing a returned buffer and its elements.
+static char **
+split_flags(const char *flags)
+{
+ char *buf[MAXPATHLEN];
+ int i = 0;
+ char *next;
+ for (; flags != NULL; flags = next) {
+ next = strchr(flags, ' ');
+ if (next == NULL) {
+ if (strlen(flags) > 0)
+ buf[i++] = strdup(flags);
+ }
+ else {
+ if (next > flags)
+ buf[i++] = ruby_strndup(flags, next - flags);
+ next++; // skip space
+ }
+ }
+
+ char **ret = xmalloc(sizeof(char *) * (i + 1));
+ memcpy(ret, buf, sizeof(char *) * i);
+ ret[i] = NULL;
+ return ret;
+}
+
+#define opt_match_noarg(s, l, name) \
+ opt_match(s, l, name) && (*(s) ? (rb_warn("argument to --mjit-" name " is ignored"), 1) : 1)
+#define opt_match_arg(s, l, name) \
+ opt_match(s, l, name) && (*(s) ? 1 : (rb_raise(rb_eRuntimeError, "--mjit-" name " needs an argument"), 0))
+
+void
+mjit_setup_options(const char *s, struct mjit_options *mjit_opt)
+{
+ const size_t l = strlen(s);
+ if (l == 0) {
+ return;
+ }
+ else if (opt_match_noarg(s, l, "warnings")) {
+ mjit_opt->warnings = true;
+ }
+ else if (opt_match(s, l, "debug")) {
+ if (*s)
+ mjit_opt->debug_flags = strdup(s + 1);
+ else
+ mjit_opt->debug = true;
+ }
+ else if (opt_match_noarg(s, l, "wait")) {
+ mjit_opt->wait = true;
+ }
+ else if (opt_match_noarg(s, l, "save-temps")) {
+ mjit_opt->save_temps = true;
+ }
+ else if (opt_match(s, l, "verbose")) {
+ mjit_opt->verbose = *s ? atoi(s + 1) : 1;
+ }
+ else if (opt_match_arg(s, l, "max-cache")) {
+ mjit_opt->max_cache_size = atoi(s + 1);
+ }
+ else if (opt_match_arg(s, l, "call-threshold")) {
+ mjit_opt->call_threshold = atoi(s + 1);
+ }
+ // --mjit=pause is an undocumented feature for experiments
+ else if (opt_match_noarg(s, l, "pause")) {
+ mjit_opt->pause = true;
+ }
+ else {
+ rb_raise(rb_eRuntimeError,
+ "invalid MJIT option `%s' (--help will show valid MJIT options)", s);
+ }
+}
+
+#define M(shortopt, longopt, desc) RUBY_OPT_MESSAGE(shortopt, longopt, desc)
+const struct ruby_opt_message mjit_option_messages[] = {
+ M("--mjit-warnings", "", "Enable printing JIT warnings"),
+ M("--mjit-debug", "", "Enable JIT debugging (very slow), or add cflags if specified"),
+ M("--mjit-wait", "", "Wait until JIT compilation finishes every time (for testing)"),
+ M("--mjit-save-temps", "", "Save JIT temporary files in $TMP or /tmp (for testing)"),
+ M("--mjit-verbose=num", "", "Print JIT logs of level num or less to stderr (default: 0)"),
+ M("--mjit-max-cache=num", "", "Max number of methods to be JIT-ed in a cache (default: "
+ STRINGIZE(DEFAULT_MAX_CACHE_SIZE) ")"),
+ M("--mjit-call-threshold=num", "", "Number of calls to trigger JIT (for testing, default: "
+ STRINGIZE(DEFAULT_CALL_THRESHOLD) ")"),
+ {0}
+};
+#undef M
+
+// Initialize MJIT. Start a thread creating the precompiled header and
+// processing ISeqs. The function should be called first for using MJIT.
+// If everything is successful, MJIT_INIT_P will be TRUE.
+void
+mjit_init(const struct mjit_options *opts)
+{
+ VM_ASSERT(mjit_enabled);
+ mjit_opts = *opts;
+
+ // MJIT doesn't support miniruby, but it might reach here by MJIT_FORCE_ENABLE.
+ rb_mMJIT = rb_const_get(rb_cRubyVM, rb_intern("MJIT"));
+ if (!rb_const_defined(rb_mMJIT, rb_intern("Compiler"))) {
+ verbose(1, "Disabling MJIT because RubyVM::MJIT::Compiler is not defined");
+ mjit_enabled = false;
+ return;
+ }
+ rb_mMJITC = rb_const_get(rb_mMJIT, rb_intern("C"));
+ rb_cMJITCompiler = rb_funcall(rb_const_get(rb_mMJIT, rb_intern("Compiler")), rb_intern("new"), 0);
+ rb_cMJITIseqPtr = rb_funcall(rb_mMJITC, rb_intern("rb_iseq_t"), 0);
+ rb_cMJITICPtr = rb_funcall(rb_mMJITC, rb_intern("IC"), 0);
+ rb_funcall(rb_cMJITICPtr, rb_intern("new"), 1, SIZET2NUM(0)); // Trigger no-op constant events before enabling hooks
+ rb_mMJITHooks = rb_const_get(rb_mMJIT, rb_intern("Hooks"));
+
+ mjit_call_p = true;
+ mjit_pid = getpid();
+
+ // Normalize options
+ if (mjit_opts.call_threshold == 0)
+ mjit_opts.call_threshold = DEFAULT_CALL_THRESHOLD;
+ if (mjit_opts.call_threshold % 2 == 1) {
+ mjit_opts.call_threshold += 1;
+ mjit_warning("--mjit-call-threshold must be an even number. Using %d instead.", mjit_opts.call_threshold);
+ }
+ mjit_opts.call_threshold /= 2; // Half for enqueue, half for trigger
+ if (mjit_opts.max_cache_size <= 0)
+ mjit_opts.max_cache_size = DEFAULT_MAX_CACHE_SIZE;
+ if (mjit_opts.max_cache_size < MIN_CACHE_SIZE)
+ mjit_opts.max_cache_size = MIN_CACHE_SIZE;
+
+ // Initialize variables for compilation
+ pch_status = PCH_NOT_READY;
+ cc_path = CC_COMMON_ARGS[0];
+ verbose(2, "MJIT: CC defaults to %s", cc_path);
+ cc_common_args = xmalloc(sizeof(CC_COMMON_ARGS));
+ memcpy((void *)cc_common_args, CC_COMMON_ARGS, sizeof(CC_COMMON_ARGS));
+ cc_added_args = split_flags(opts->debug_flags);
+ xfree(opts->debug_flags);
+#if MJIT_CFLAGS_PIPE
+ // Filter out `-save-temps`. It's a C compiler flag used by update-deps and not compatible with `-pipe`.
+ for (size_t i = 0, j = 0; i < sizeof(CC_COMMON_ARGS) / sizeof(char *); i++) {
+ if (CC_COMMON_ARGS[i] && strncmp("-save-temps", CC_COMMON_ARGS[i], strlen("-save-temps")) == 0)
+ continue; // Skip `-save-temps`
+ cc_common_args[j] = CC_COMMON_ARGS[i];
+ j++;
+ }
+#endif
+
+ tmp_dir = system_tmpdir();
+ verbose(2, "MJIT: tmp_dir is %s", tmp_dir);
+
+ if (!init_header_filename()) {
+ mjit_enabled = false;
+ verbose(1, "Failure in MJIT header file name initialization\n");
+ return;
+ }
+ pch_owner_pid = getpid();
+
+ // Initialize mutex
+ rb_native_mutex_initialize(&mjit_engine_mutex);
+
+ // If --mjit=pause is given, lazily start MJIT when RubyVM::MJIT.resume is called.
+ // You can use it to control MJIT warmup, or to customize the JIT implementation.
+ if (!mjit_opts.pause) {
+ // TODO: Consider running C compiler asynchronously
+ make_pch();
+
+ // Enable MJIT compilation
+ start_worker();
+ }
+}
+
+static void
+stop_worker(void)
+{
+ stop_worker_p = true;
+ if (current_cc_unit != NULL) {
+ mjit_wait(current_cc_unit);
+ }
+ worker_stopped = true;
+}
+
+// Stop JIT-compiling methods but compiled code is kept available.
+VALUE
+mjit_pause(bool wait_p)
+{
+ if (!mjit_enabled) {
+ rb_raise(rb_eRuntimeError, "MJIT is not enabled");
+ }
+ if (worker_stopped) {
+ return Qfalse;
+ }
+
+ // Flush all queued units with no option or `wait: true`
+ if (wait_p) {
+ while (current_cc_unit != NULL) {
+ mjit_wait(current_cc_unit);
+ }
+ }
+
+ stop_worker();
+ return Qtrue;
+}
+
+// Restart JIT-compiling methods after mjit_pause.
+VALUE
+mjit_resume(void)
+{
+ if (!mjit_enabled) {
+ rb_raise(rb_eRuntimeError, "MJIT is not enabled");
+ }
+ if (!worker_stopped) {
+ return Qfalse;
+ }
+
+ // Lazily prepare PCH when --mjit=pause is given
+ if (pch_status == PCH_NOT_READY) {
+ if (rb_respond_to(rb_mMJIT, rb_intern("compile"))) {
+ // [experimental] defining RubyVM::MJIT.compile allows you to replace JIT
+ mjit_opts.custom = true;
+ pch_status = PCH_SUCCESS;
+ }
+ else {
+ // Lazy MJIT boot
+ make_pch();
+ }
+ }
+
+ if (!start_worker()) {
+ rb_raise(rb_eRuntimeError, "Failed to resume MJIT worker");
+ }
+ return Qtrue;
+}
+
+// This is called after fork initiated by Ruby's method to launch MJIT worker thread
+// for child Ruby process.
+//
+// In multi-process Ruby applications, child Ruby processes do most of the jobs.
+// Thus we want child Ruby processes to enqueue ISeqs to MJIT worker's queue and
+// call the JIT-ed code.
+//
+// But unfortunately current MJIT-generated code is process-specific. After the fork,
+// JIT-ed code created by parent Ruby process cannot be used in child Ruby process
+// because the code could rely on inline cache values (ivar's IC, send's CC) which
+// may vary between processes after fork or embed some process-specific addresses.
+//
+// So child Ruby process can't request parent process to JIT an ISeq and use the code.
+// Instead of that, MJIT worker thread is created for all child Ruby processes, even
+// while child processes would end up with compiling the same ISeqs.
+void
+mjit_child_after_fork(void)
+{
+ if (!mjit_enabled)
+ return;
+
+ /* MJIT worker thread is not inherited on fork. Start it for this child process. */
+ start_worker();
+}
+
+// Finish the threads processing units and creating PCH, finalize
+// and free MJIT data. It should be called last during MJIT
+// life.
+//
+// If close_handle_p is true, it calls dlclose() for JIT-ed code. So it should be false
+// if the code can still be on stack. ...But it means to leak JIT-ed handle forever (FIXME).
+void
+mjit_finish(bool close_handle_p)
+{
+ if (!mjit_enabled)
+ return;
+
+ // Stop worker
+ verbose(2, "Stopping worker thread");
+ stop_worker();
+
+ rb_native_mutex_destroy(&mjit_engine_mutex);
+
+ if (!mjit_opts.save_temps && getpid() == pch_owner_pid && pch_status == PCH_SUCCESS && !mjit_opts.custom)
+ remove_file(pch_file);
+
+ xfree(header_file); header_file = NULL;
+ xfree((void *)cc_common_args); cc_common_args = NULL;
+ for (char **flag = cc_added_args; *flag != NULL; flag++)
+ xfree(*flag);
+ xfree((void *)cc_added_args); cc_added_args = NULL;
+ xfree(tmp_dir); tmp_dir = NULL;
+ xfree(pch_file); pch_file = NULL;
+
+ mjit_call_p = false;
+ free_list(&unit_queue, close_handle_p);
+ free_list(&active_units, close_handle_p);
+ free_list(&compact_units, close_handle_p);
+ free_list(&stale_units, close_handle_p);
+
+ mjit_enabled = false;
+ verbose(1, "Successful MJIT finish");
+}
+
+// Called by rb_vm_mark().
+//
+// Mark active_units so that we do not GC ISeq which may still be
+// referenced by mjit_recompile() or mjit_compact().
+void
+mjit_mark(void)
+{
+ if (!mjit_enabled)
+ return;
+ RUBY_MARK_ENTER("mjit");
+
+ // Mark objects used by the MJIT compiler
+ rb_gc_mark(rb_cMJITCompiler);
+ rb_gc_mark(rb_cMJITIseqPtr);
+ rb_gc_mark(rb_cMJITICPtr);
+ rb_gc_mark(rb_mMJITHooks);
+
+ // Mark JIT-compiled ISEQs
+ struct rb_mjit_unit *unit = NULL;
+ ccan_list_for_each(&active_units.head, unit, unode) {
+ rb_gc_mark((VALUE)unit->iseq);
+ }
+
+ RUBY_MARK_LEAVE("mjit");
+}
+
+// Called by rb_iseq_mark() to mark cc_entries captured for MJIT
+void
+mjit_mark_cc_entries(const struct rb_iseq_constant_body *const body)
+{
+ const struct rb_callcache **cc_entries;
+ if (body->mjit_unit && (cc_entries = body->mjit_unit->cc_entries) != NULL) {
+ // It must be `body->mjit_unit->cc_entries_size` instead of `body->ci_size` to mark children's cc_entries
+ for (unsigned int i = 0; i < body->mjit_unit->cc_entries_size; i++) {
+ const struct rb_callcache *cc = cc_entries[i];
+ if (cc != NULL && vm_cc_markable(cc)) {
+ // Pin `cc` and `cc->cme` against GC.compact as their addresses may be written in JIT-ed code.
+ rb_gc_mark((VALUE)cc);
+ rb_gc_mark((VALUE)vm_cc_cme(cc));
+ }
+ }
+ }
+}
+
+// Compile ISeq to C code in `f`. It returns true if it succeeds to compile.
+bool
+mjit_compile(FILE *f, const rb_iseq_t *iseq, const char *funcname, int id)
+{
+ bool original_call_p = mjit_call_p;
+ mjit_call_p = false; // Avoid impacting JIT metrics by itself
+
+ VALUE iseq_ptr = rb_funcall(rb_cMJITIseqPtr, rb_intern("new"), 1, ULONG2NUM((size_t)iseq));
+ VALUE src = rb_funcall(rb_cMJITCompiler, rb_intern("compile"), 3,
+ iseq_ptr, rb_str_new_cstr(funcname), INT2NUM(id));
+ if (!NIL_P(src)) {
+ fprintf(f, "%s", RSTRING_PTR(src));
+ }
+
+ mjit_call_p = original_call_p;
+ return !NIL_P(src);
+}
+
+#include "mjit.rbinc"
+
+#endif // USE_MJIT
diff --git a/mjit.h b/mjit.h
new file mode 100644
index 0000000000..260cf4af78
--- /dev/null
+++ b/mjit.h
@@ -0,0 +1,145 @@
+#ifndef RUBY_MJIT_H
+#define RUBY_MJIT_H 1
+/**********************************************************************
+
+ mjit.h - Interface to MRI method JIT compiler
+
+ Copyright (C) 2017 Vladimir Makarov <vmakarov@redhat.com>.
+ Copyright (C) 2017 Takashi Kokubun <k0kubun@ruby-lang.org>.
+
+**********************************************************************/
+
+#include "ruby/internal/config.h" // defines USE_MJIT
+#include "ruby/internal/stdbool.h"
+#include "vm_core.h"
+
+# if USE_MJIT
+
+#include "ruby.h"
+#include "vm_core.h"
+
+// Special address values of a function generated from the
+// corresponding iseq by MJIT:
+enum rb_mjit_func_state {
+ // ISEQ has not been compiled yet
+ MJIT_FUNC_NOT_COMPILED = 0,
+ // ISEQ is already queued for the machine code generation but the
+ // code is not ready yet for the execution
+ MJIT_FUNC_COMPILING = 1,
+ // ISEQ included not compilable insn, some internal assertion failed
+ // or the unit is unloaded
+ MJIT_FUNC_FAILED = 2,
+};
+// Return true if jit_func is part of enum rb_mjit_func_state
+#define MJIT_FUNC_STATE_P(jit_func) ((uintptr_t)(jit_func) <= (uintptr_t)MJIT_FUNC_FAILED)
+
+// MJIT options which can be defined on the MRI command line.
+struct mjit_options {
+ // Converted from "jit" feature flag to tell the enablement
+ // information to ruby_show_version().
+ bool on;
+ // Save temporary files after MRI finish. The temporary files
+ // include the pre-compiled header, C code file generated for ISEQ,
+ // and the corresponding object file.
+ bool save_temps;
+ // Print MJIT warnings to stderr.
+ bool warnings;
+ // Disable compiler optimization and add debug symbols. It can be
+ // very slow.
+ bool debug;
+ // Add arbitrary cflags.
+ char* debug_flags;
+ // If true, all ISeqs are synchronously compiled. For testing.
+ bool wait;
+ // Number of calls to trigger JIT compilation. For testing.
+ unsigned int call_threshold;
+ // Force printing info about MJIT work of level VERBOSE or
+ // less. 0=silence, 1=medium, 2=verbose.
+ int verbose;
+ // Maximal permitted number of iseq JIT codes in a MJIT memory
+ // cache.
+ int max_cache_size;
+ // [experimental] Do not start MJIT until MJIT.resume is called.
+ bool pause;
+ // [experimental] Call custom RubyVM::MJIT.compile instead of MJIT.
+ bool custom;
+};
+
+// State of optimization switches
+struct rb_mjit_compile_info {
+ // Disable getinstancevariable/setinstancevariable optimizations based on inline cache (T_OBJECT)
+ bool disable_ivar_cache;
+ // Disable getinstancevariable/setinstancevariable optimizations based on inline cache (FL_EXIVAR)
+ bool disable_exivar_cache;
+ // Disable send/opt_send_without_block optimizations based on inline cache
+ bool disable_send_cache;
+ // Disable method inlining
+ bool disable_inlining;
+ // Disable opt_getinlinecache inlining
+ bool disable_const_cache;
+};
+
+typedef VALUE (*jit_func_t)(rb_execution_context_t *, rb_control_frame_t *);
+
+RUBY_SYMBOL_EXPORT_BEGIN
+RUBY_EXTERN struct mjit_options mjit_opts;
+RUBY_EXTERN bool mjit_call_p;
+
+extern void rb_mjit_add_iseq_to_process(const rb_iseq_t *iseq);
+extern struct rb_mjit_compile_info* rb_mjit_iseq_compile_info(const struct rb_iseq_constant_body *body);
+extern void rb_mjit_recompile_send(const rb_iseq_t *iseq);
+extern void rb_mjit_recompile_ivar(const rb_iseq_t *iseq);
+extern void rb_mjit_recompile_exivar(const rb_iseq_t *iseq);
+extern void rb_mjit_recompile_inlining(const rb_iseq_t *iseq);
+extern void rb_mjit_recompile_const(const rb_iseq_t *iseq);
+RUBY_SYMBOL_EXPORT_END
+
+extern void mjit_cancel_all(const char *reason);
+extern bool mjit_compile(FILE *f, const rb_iseq_t *iseq, const char *funcname, int id);
+extern void mjit_init(const struct mjit_options *opts);
+extern void mjit_free_iseq(const rb_iseq_t *iseq);
+extern void mjit_update_references(const rb_iseq_t *iseq);
+extern void mjit_mark(void);
+extern void mjit_mark_cc_entries(const struct rb_iseq_constant_body *const body);
+extern void mjit_notify_waitpid(int exit_code);
+
+extern void rb_mjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);
+extern void rb_mjit_cme_invalidate(rb_callable_method_entry_t *cme);
+extern void rb_mjit_before_ractor_spawn(void);
+extern void rb_mjit_constant_state_changed(ID id);
+extern void rb_mjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx);
+extern void rb_mjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events);
+
+void mjit_child_after_fork(void);
+
+# ifdef MJIT_HEADER
+#define mjit_enabled true
+# else // MJIT_HEADER
+extern bool mjit_enabled;
+# endif // MJIT_HEADER
+VALUE mjit_pause(bool wait_p);
+VALUE mjit_resume(void);
+void mjit_finish(bool close_handle_p);
+
+# else // USE_MJIT
+
+static inline void mjit_cancel_all(const char *reason){}
+static inline void mjit_free_iseq(const rb_iseq_t *iseq){}
+static inline void mjit_mark(void){}
+static inline VALUE jit_exec(rb_execution_context_t *ec) { return Qundef; /* unreachable */ }
+static inline void mjit_child_after_fork(void){}
+
+static inline void rb_mjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop) {}
+static inline void rb_mjit_cme_invalidate(rb_callable_method_entry_t *cme) {}
+static inline void rb_mjit_before_ractor_spawn(void) {}
+static inline void rb_mjit_constant_state_changed(ID id) {}
+static inline void rb_mjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx) {}
+static inline void rb_mjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events) {}
+
+#define mjit_enabled false
+static inline VALUE mjit_pause(bool wait_p){ return Qnil; } // unreachable
+static inline VALUE mjit_resume(void){ return Qnil; } // unreachable
+static inline void mjit_finish(bool close_handle_p){}
+
+# endif // USE_MJIT
+#endif // RUBY_MJIT_H
diff --git a/mjit.rb b/mjit.rb
new file mode 100644
index 0000000000..717ab832a4
--- /dev/null
+++ b/mjit.rb
@@ -0,0 +1,37 @@
+module RubyVM::MJIT
+ # Return true if MJIT is enabled.
+ def self.enabled?
+ Primitive.cexpr! 'RBOOL(mjit_enabled)'
+ end
+
+ # Stop generating JITed code.
+ def self.pause(wait: true)
+ Primitive.cexpr! 'mjit_pause(RTEST(wait))'
+ end
+
+ # Start generating JITed code again after pause.
+ def self.resume
+ Primitive.cexpr! 'mjit_resume()'
+ end
+end
+
+if RubyVM::MJIT.enabled?
+ begin
+ require 'fiddle'
+ require 'fiddle/import'
+ rescue LoadError
+ return # miniruby doesn't support MJIT
+ end
+
+ # forward declaration for ruby_vm/mjit/compiler
+ RubyVM::MJIT::C = Object.new # :nodoc:
+
+ require 'ruby_vm/mjit/c_type'
+ require 'ruby_vm/mjit/instruction'
+ require 'ruby_vm/mjit/compiler'
+ require 'ruby_vm/mjit/hooks'
+
+ module RubyVM::MJIT
+ private_constant(*constants)
+ end
+end
diff --git a/mjit_c.c b/mjit_c.c
new file mode 100644
index 0000000000..9ba023e84b
--- /dev/null
+++ b/mjit_c.c
@@ -0,0 +1,43 @@
+/**********************************************************************
+
+ mjit_c.c - C helpers for MJIT
+
+ Copyright (C) 2017 Takashi Kokubun <k0kubun@ruby-lang.org>.
+
+**********************************************************************/
+
+#include "ruby/internal/config.h" // defines USE_MJIT
+
+#if USE_MJIT
+
+#include "mjit.h"
+#include "mjit_c.h"
+#include "internal.h"
+#include "internal/compile.h"
+#include "internal/hash.h"
+#include "yjit.h"
+#include "vm_insnhelper.h"
+
+#include "insns.inc"
+#include "insns_info.inc"
+
+#include "mjit_sp_inc.inc"
+
+#if SIZEOF_LONG == SIZEOF_VOIDP
+#define NUM2PTR(x) NUM2ULONG(x)
+#define PTR2NUM(x) ULONG2NUM(x)
+#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
+#define NUM2PTR(x) NUM2ULL(x)
+#define PTR2NUM(x) ULL2NUM(x)
+#endif
+
+// An offsetof implementation that works for unnamed struct and union.
+// Multiplying 8 for compatibility with libclang's offsetof.
+#define OFFSETOF(ptr, member) RB_SIZE2NUM(((char *)&ptr.member - (char*)&ptr) * 8)
+
+#define SIZEOF(type) RB_SIZE2NUM(sizeof(type))
+#define SIGNED_TYPE_P(type) RBOOL((type)(-1) < (type)(1))
+
+#include "mjit_c.rbinc"
+
+#endif // USE_MJIT
diff --git a/mjit_c.h b/mjit_c.h
new file mode 100644
index 0000000000..cc4040c9df
--- /dev/null
+++ b/mjit_c.h
@@ -0,0 +1,97 @@
+// This file is parsed by tool/mjit/generate.rb to generate mjit_c.rb
+#ifndef MJIT_C_H
+#define MJIT_C_H
+
+#include "ruby/internal/config.h"
+#include "vm_core.h"
+#include "vm_callinfo.h"
+#include "builtin.h"
+#include "ccan/list/list.h"
+#include "mjit.h"
+#include "shape.h"
+
+// Macros to check if a position is already compiled using compile_status.stack_size_for_pos
+#define NOT_COMPILED_STACK_SIZE -1
+#define ALREADY_COMPILED_P(status, pos) (status->stack_size_for_pos[pos] != NOT_COMPILED_STACK_SIZE)
+
+// Linked list of struct rb_mjit_unit.
+struct rb_mjit_unit_list {
+ struct ccan_list_head head;
+ int length; // the list length
+};
+
+enum rb_mjit_unit_type {
+ // Single-ISEQ unit for unit_queue
+ MJIT_UNIT_ISEQ = 0,
+ // Multi-ISEQ unit for mjit_batch
+ MJIT_UNIT_BATCH = 1,
+ // All-ISEQ unit for mjit_compact
+ MJIT_UNIT_COMPACT = 2,
+};
+
+// The unit structure that holds metadata of ISeq for MJIT.
+// TODO: Use different structs for ISEQ and BATCH/COMPACT
+struct rb_mjit_unit {
+ struct ccan_list_node unode;
+ // Unique order number of unit.
+ int id;
+ // Type of this unit
+ enum rb_mjit_unit_type type;
+
+ /* MJIT_UNIT_ISEQ */
+ // ISEQ for a non-batch unit
+ rb_iseq_t *iseq;
+ // Only used by unload_units. Flag to check this unit is currently on stack or not.
+ bool used_code_p;
+ // mjit_compile's optimization switches
+ struct rb_mjit_compile_info compile_info;
+ // captured CC values, they should be marked with iseq.
+ const struct rb_callcache **cc_entries;
+ // ISEQ_BODY(iseq)->ci_size + ones of inlined iseqs
+ unsigned int cc_entries_size;
+
+ /* MJIT_UNIT_BATCH, MJIT_UNIT_COMPACT */
+ // Dlopen handle of the loaded object file.
+ void *handle;
+ // Units compacted by this batch
+ struct rb_mjit_unit_list units; // MJIT_UNIT_BATCH only
+};
+
+// Storage to keep data which is consistent in each conditional branch.
+// This is created and used for one `compile_insns` call and its values
+// should be copied for extra `compile_insns` call.
+struct compile_branch {
+ unsigned int stack_size; // this simulates sp (stack pointer) of YARV
+ bool finish_p; // if true, compilation in this branch should stop and let another branch to be compiled
+};
+
+// For propagating information needed for lazily pushing a frame.
+struct inlined_call_context {
+ int orig_argc; // ci->orig_argc
+ VALUE me; // vm_cc_cme(cc)
+ int param_size; // def_iseq_ptr(vm_cc_cme(cc)->def)->body->param.size
+ int local_size; // def_iseq_ptr(vm_cc_cme(cc)->def)->body->local_table_size
+};
+
+// Storage to keep compiler's status. This should have information
+// which is global during one `mjit_compile` call. Ones conditional
+// in each branch should be stored in `compile_branch`.
+struct compile_status {
+ bool success; // has true if compilation has had no issue
+ int *stack_size_for_pos; // stack_size_for_pos[pos] has stack size for the position (otherwise -1)
+ // If true, JIT-ed code will use local variables to store pushed values instead of
+ // using VM's stack and moving stack pointer.
+ bool local_stack_p;
+ // Index of call cache entries captured to compiled_iseq to be marked on GC
+ int cc_entries_index;
+ // A pointer to root (i.e. not inlined) iseq being compiled.
+ const struct rb_iseq_constant_body *compiled_iseq;
+ int compiled_id; // Just a copy of compiled_iseq->jit_unit->id
+ // Mutated optimization levels
+ struct rb_mjit_compile_info *compile_info;
+ // If `inlined_iseqs[pos]` is not NULL, `mjit_compile_body` tries to inline ISeq there.
+ const struct rb_iseq_constant_body **inlined_iseqs;
+ struct inlined_call_context inline_context;
+};
+
+#endif /* MJIT_C_H */
diff --git a/mjit_c.rb b/mjit_c.rb
new file mode 100644
index 0000000000..966289c5ab
--- /dev/null
+++ b/mjit_c.rb
@@ -0,0 +1,807 @@
+# frozen_string_literal: true
+# Part of this file is generated by tool/mjit/bindgen.rb.
+# Run `make mjit-bindgen` to update code between "MJIT bindgen begin" and "MJIT bindgen end".
+module RubyVM::MJIT # :nodoc: all
+ # This `class << C` section is for calling C functions. For importing variables
+ # or macros as is, please consider using tool/mjit/bindgen.rb instead.
+ class << C
+ def rb_hash_values(cdhash_addr)
+ Primitive.cexpr! 'rb_hash_values((VALUE)NUM2PTR(cdhash_addr))'
+ end
+
+ def builtin_compiler(buf, bf_ptr, index, stack_size, builtin_inline_p)
+ _bf_addr = bf_ptr.to_i
+ # Call "mjit_compile_invokebuiltin_for_#{func}" in mk_builtin_loader.rb
+ Primitive.cstmt! %{
+ RB_BUILTIN bf = (RB_BUILTIN)NUM2PTR(_bf_addr);
+ bf->compiler(buf, NIL_P(index) ? -1 : NUM2LONG(index), NUM2UINT(stack_size), RTEST(builtin_inline_p));
+ return Qnil;
+ }
+ end
+
+ def has_cache_for_send(cc_ptr, insn)
+ _cc_addr = cc_ptr.to_i
+ Primitive.cstmt! %{
+ extern bool rb_vm_opt_cfunc_p(CALL_CACHE cc, int insn);
+ CALL_CACHE cc = (CALL_CACHE)NUM2PTR(_cc_addr);
+ bool has_cache = vm_cc_cme(cc) != NULL &&
+ !(vm_cc_cme(cc)->def->type == VM_METHOD_TYPE_CFUNC && rb_vm_opt_cfunc_p(cc, NUM2INT(insn)));
+ return RBOOL(has_cache);
+ }
+ end
+
+ def rb_shape_get_shape_by_id(shape_id)
+ _shape_id = shape_id.to_i
+ shape_addr = Primitive.cexpr! 'PTR2NUM((VALUE)rb_shape_get_shape_by_id((shape_id_t)NUM2UINT(_shape_id)))'
+ rb_shape_t.new(shape_addr)
+ end
+
+ def rb_iseq_check(iseq)
+ _iseq_addr = iseq.to_i
+ iseq_addr = Primitive.cexpr! 'PTR2NUM((VALUE)rb_iseq_check((rb_iseq_t *)NUM2PTR(_iseq_addr)))'
+ rb_iseq_t.new(iseq_addr)
+ end
+
+ def rb_iseq_path(iseq)
+ _iseq_addr = iseq.to_i
+ Primitive.cexpr! 'rb_iseq_path((rb_iseq_t *)NUM2PTR(_iseq_addr))'
+ end
+
+ def rb_iseq_first_lineno(iseq)
+ _iseq_addr = iseq.to_i
+ Primitive.cexpr! 'rb_iseq_first_lineno((rb_iseq_t *)NUM2PTR(_iseq_addr))'
+ end
+
+ def vm_ci_argc(ci)
+ _ci_addr = ci.to_i
+ Primitive.cexpr! 'UINT2NUM(vm_ci_argc((CALL_INFO)NUM2PTR(_ci_addr)))'
+ end
+
+ def vm_ci_flag(ci)
+ _ci_addr = ci.to_i
+ Primitive.cexpr! 'UINT2NUM(vm_ci_flag((CALL_INFO)NUM2PTR(_ci_addr)))'
+ end
+
+ def rb_splat_or_kwargs_p(ci)
+ _ci_addr = ci.to_i
+ Primitive.cstmt! %{
+ extern bool rb_splat_or_kwargs_p(const struct rb_callinfo *restrict ci);
+ return RBOOL(rb_splat_or_kwargs_p((CALL_INFO)NUM2PTR(_ci_addr)));
+ }
+ end
+
+ # Returns true if iseq can use fastpath for setup, otherwise NULL. This becomes true in the same condition
+ # as CC_SET_FASTPATH (in vm_callee_setup_arg) is called from vm_call_iseq_setup.
+ def fastpath_applied_iseq_p(ci_ptr, cc_ptr, iseq_ptr)
+ _ci_addr = ci_ptr.to_i
+ _cc_addr = cc_ptr.to_i
+ _iseq_addr = iseq_ptr.to_i
+ Primitive.cstmt! %q{
+ extern bool rb_simple_iseq_p(const rb_iseq_t *iseq);
+ CALL_INFO ci = (CALL_INFO)NUM2PTR(_ci_addr);
+ CALL_CACHE cc = (CALL_CACHE)NUM2PTR(_cc_addr);
+ const rb_iseq_t *iseq = (rb_iseq_t *)NUM2PTR(_iseq_addr);
+
+ bool result = iseq != NULL
+ && !(vm_ci_flag(ci) & VM_CALL_KW_SPLAT) && rb_simple_iseq_p(iseq) // Top of vm_callee_setup_arg. In this case, opt_pc is 0.
+ && vm_ci_argc(ci) == (unsigned int)ISEQ_BODY(iseq)->param.lead_num // exclude argument_arity_error (assumption: `calling->argc == ci->orig_argc` in send insns)
+ && vm_call_iseq_optimizable_p(ci, cc); // CC_SET_FASTPATH condition
+ return RBOOL(result);
+ }
+ end
+
+ def mjit_opts
+ addr = Primitive.cexpr! 'PTR2NUM((VALUE)&mjit_opts)'
+ mjit_options.new(addr)
+ end
+
+ def mjit_call_attribute_sp_inc(insn, operands)
+ _operands_addr = operands.to_i
+ Primitive.cexpr! 'LONG2NUM(mjit_call_attribute_sp_inc(NUM2INT(insn), (VALUE *)NUM2PTR(_operands_addr)))'
+ end
+
+ def mjit_capture_cc_entries(compiled_body, captured_body)
+ _compiled_body_addr = compiled_body.to_i
+ _captured_body_addr = captured_body.to_i
+ Primitive.cstmt! %{
+ extern int mjit_capture_cc_entries(const struct rb_iseq_constant_body *compiled_iseq, const struct rb_iseq_constant_body *captured_iseq);
+ return INT2NUM(mjit_capture_cc_entries((struct rb_iseq_constant_body *)NUM2PTR(_compiled_body_addr), (struct rb_iseq_constant_body *)NUM2PTR(_captured_body_addr)));
+ }
+ end
+
+ def mjit_cancel_all(reason)
+ Primitive.cstmt! %{
+ mjit_cancel_all(RSTRING_PTR(reason));
+ return Qnil;
+ }
+ end
+
+ # Convert encoded VM pointers to insn BINs.
+ def rb_vm_insn_decode(encoded)
+ Primitive.cexpr! 'INT2NUM(rb_vm_insn_decode(NUM2PTR(encoded)))'
+ end
+
+ # Convert insn BINs to encoded VM pointers. This one is not used by the compiler, but useful for debugging.
+ def rb_vm_insn_encode(bin)
+ Primitive.cexpr! 'PTR2NUM((VALUE)rb_vm_get_insns_address_table()[NUM2INT(bin)])'
+ end
+
+ def insn_may_depend_on_sp_or_pc(insn, opes)
+ _opes_addr = opes.to_i
+ Primitive.cexpr! 'RBOOL(insn_may_depend_on_sp_or_pc(NUM2INT(insn), (VALUE *)NUM2PTR(_opes_addr)))'
+ end
+
+ # Convert Integer VALUE to an actual Ruby object
+ def to_ruby(value)
+ Primitive.cexpr! '(VALUE)NUM2PTR(value)'
+ end
+
+ # Convert RubyVM::InstructionSequence to C.rb_iseq_t. Not used by the compiler, but useful for debugging.
+ def rb_iseqw_to_iseq(iseqw)
+ iseq_addr = Primitive.cexpr! 'PTR2NUM((VALUE)rb_iseqw_to_iseq(iseqw))'
+ rb_iseq_t.new(iseq_addr)
+ end
+ end
+
+ ### MJIT bindgen begin ###
+
+ def C.USE_LAZY_LOAD
+ Primitive.cexpr! %q{ RBOOL(USE_LAZY_LOAD != 0) }
+ end
+
+ def C.NOT_COMPILED_STACK_SIZE
+ Primitive.cexpr! %q{ INT2NUM(NOT_COMPILED_STACK_SIZE) }
+ end
+
+ def C.VM_CALL_KW_SPLAT
+ Primitive.cexpr! %q{ INT2NUM(VM_CALL_KW_SPLAT) }
+ end
+
+ def C.VM_CALL_KW_SPLAT_bit
+ Primitive.cexpr! %q{ INT2NUM(VM_CALL_KW_SPLAT_bit) }
+ end
+
+ def C.VM_CALL_TAILCALL
+ Primitive.cexpr! %q{ INT2NUM(VM_CALL_TAILCALL) }
+ end
+
+ def C.VM_CALL_TAILCALL_bit
+ Primitive.cexpr! %q{ INT2NUM(VM_CALL_TAILCALL_bit) }
+ end
+
+ def C.VM_METHOD_TYPE_CFUNC
+ Primitive.cexpr! %q{ INT2NUM(VM_METHOD_TYPE_CFUNC) }
+ end
+
+ def C.VM_METHOD_TYPE_ISEQ
+ Primitive.cexpr! %q{ INT2NUM(VM_METHOD_TYPE_ISEQ) }
+ end
+
+ def C.RUBY_EVENT_CLASS
+ Primitive.cexpr! %q{ UINT2NUM(RUBY_EVENT_CLASS) }
+ end
+
+ def C.SHAPE_CAPACITY_CHANGE
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_CAPACITY_CHANGE) }
+ end
+
+ def C.SHAPE_FLAG_SHIFT
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_FLAG_SHIFT) }
+ end
+
+ def C.SHAPE_FROZEN
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_FROZEN) }
+ end
+
+ def C.SHAPE_ID_NUM_BITS
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_ID_NUM_BITS) }
+ end
+
+ def C.SHAPE_INITIAL_CAPACITY
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_INITIAL_CAPACITY) }
+ end
+
+ def C.SHAPE_IVAR
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_IVAR) }
+ end
+
+ def C.SHAPE_ROOT
+ Primitive.cexpr! %q{ UINT2NUM(SHAPE_ROOT) }
+ end
+
+ def C.INVALID_SHAPE_ID
+ Primitive.cexpr! %q{ ULONG2NUM(INVALID_SHAPE_ID) }
+ end
+
+ def C.SHAPE_MASK
+ Primitive.cexpr! %q{ ULONG2NUM(SHAPE_MASK) }
+ end
+
+ def C.rb_cFalseClass
+ Primitive.cexpr! %q{ PTR2NUM(rb_cFalseClass) }
+ end
+
+ def C.rb_cFloat
+ Primitive.cexpr! %q{ PTR2NUM(rb_cFloat) }
+ end
+
+ def C.rb_cInteger
+ Primitive.cexpr! %q{ PTR2NUM(rb_cInteger) }
+ end
+
+ def C.rb_cNilClass
+ Primitive.cexpr! %q{ PTR2NUM(rb_cNilClass) }
+ end
+
+ def C.rb_cSymbol
+ Primitive.cexpr! %q{ PTR2NUM(rb_cSymbol) }
+ end
+
+ def C.rb_cTrueClass
+ Primitive.cexpr! %q{ PTR2NUM(rb_cTrueClass) }
+ end
+
+ def C.CALL_DATA
+ @CALL_DATA ||= self.rb_call_data
+ end
+
+ def C.IC
+ @IC ||= self.iseq_inline_constant_cache
+ end
+
+ def C.IVC
+ @IVC ||= self.iseq_inline_iv_cache_entry
+ end
+
+ def C.RB_BUILTIN
+ @RB_BUILTIN ||= self.rb_builtin_function
+ end
+
+ def C.attr_index_t
+ @attr_index_t ||= CType::Immediate.parse("uint32_t")
+ end
+
+ def C.compile_branch
+ @compile_branch ||= CType::Struct.new(
+ "compile_branch", Primitive.cexpr!("SIZEOF(struct compile_branch)"),
+ stack_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct compile_branch *)NULL)), stack_size)")],
+ finish_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct compile_branch *)NULL)), finish_p)")],
+ )
+ end
+
+ def C.compile_status
+ @compile_status ||= CType::Struct.new(
+ "compile_status", Primitive.cexpr!("SIZEOF(struct compile_status)"),
+ success: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), success)")],
+ stack_size_for_pos: [CType::Pointer.new { CType::Immediate.parse("int") }, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), stack_size_for_pos)")],
+ local_stack_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), local_stack_p)")],
+ cc_entries_index: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), cc_entries_index)")],
+ compiled_iseq: [CType::Pointer.new { self.rb_iseq_constant_body }, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), compiled_iseq)")],
+ compiled_id: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), compiled_id)")],
+ compile_info: [CType::Pointer.new { self.rb_mjit_compile_info }, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), compile_info)")],
+ inlined_iseqs: [CType::Pointer.new { CType::Pointer.new { self.rb_iseq_constant_body } }, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), inlined_iseqs)")],
+ inline_context: [self.inlined_call_context, Primitive.cexpr!("OFFSETOF((*((struct compile_status *)NULL)), inline_context)")],
+ )
+ end
+
+ def C.inlined_call_context
+ @inlined_call_context ||= CType::Struct.new(
+ "inlined_call_context", Primitive.cexpr!("SIZEOF(struct inlined_call_context)"),
+ orig_argc: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct inlined_call_context *)NULL)), orig_argc)")],
+ me: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct inlined_call_context *)NULL)), me)")],
+ param_size: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct inlined_call_context *)NULL)), param_size)")],
+ local_size: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct inlined_call_context *)NULL)), local_size)")],
+ )
+ end
+
+ def C.iseq_inline_constant_cache
+ @iseq_inline_constant_cache ||= CType::Struct.new(
+ "iseq_inline_constant_cache", Primitive.cexpr!("SIZEOF(struct iseq_inline_constant_cache)"),
+ entry: [CType::Pointer.new { self.iseq_inline_constant_cache_entry }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache *)NULL)), entry)")],
+ segments: [CType::Pointer.new { self.ID }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache *)NULL)), segments)")],
+ )
+ end
+
+ def C.iseq_inline_constant_cache_entry
+ @iseq_inline_constant_cache_entry ||= CType::Struct.new(
+ "iseq_inline_constant_cache_entry", Primitive.cexpr!("SIZEOF(struct iseq_inline_constant_cache_entry)"),
+ flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), flags)")],
+ value: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), value)")],
+ _unused1: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), _unused1)")],
+ _unused2: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), _unused2)")],
+ ic_cref: [CType::Pointer.new { self.rb_cref_t }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), ic_cref)")],
+ )
+ end
+
+ def C.iseq_inline_iv_cache_entry
+ @iseq_inline_iv_cache_entry ||= CType::Struct.new(
+ "iseq_inline_iv_cache_entry", Primitive.cexpr!("SIZEOF(struct iseq_inline_iv_cache_entry)"),
+ value: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), value)")],
+ iv_set_name: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), iv_set_name)")],
+ )
+ end
+
+ def C.iseq_inline_storage_entry
+ @iseq_inline_storage_entry ||= CType::Union.new(
+ "iseq_inline_storage_entry", Primitive.cexpr!("SIZEOF(union iseq_inline_storage_entry)"),
+ once: CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((union iseq_inline_storage_entry *)NULL)->once)"),
+ running_thread: [CType::Pointer.new { self.rb_thread_struct }, Primitive.cexpr!("OFFSETOF(((union iseq_inline_storage_entry *)NULL)->once, running_thread)")],
+ value: [self.VALUE, Primitive.cexpr!("OFFSETOF(((union iseq_inline_storage_entry *)NULL)->once, value)")],
+ ),
+ ic_cache: self.iseq_inline_constant_cache,
+ iv_cache: self.iseq_inline_iv_cache_entry,
+ )
+ end
+
+ def C.mjit_options
+ @mjit_options ||= CType::Struct.new(
+ "mjit_options", Primitive.cexpr!("SIZEOF(struct mjit_options)"),
+ on: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), on)")],
+ save_temps: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), save_temps)")],
+ warnings: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), warnings)")],
+ debug: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), debug)")],
+ debug_flags: [CType::Pointer.new { CType::Immediate.parse("char") }, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), debug_flags)")],
+ wait: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), wait)")],
+ call_threshold: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), call_threshold)")],
+ verbose: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), verbose)")],
+ max_cache_size: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), max_cache_size)")],
+ pause: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), pause)")],
+ custom: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct mjit_options *)NULL)), custom)")],
+ )
+ end
+
+ def C.rb_builtin_function
+ @rb_builtin_function ||= CType::Struct.new(
+ "rb_builtin_function", Primitive.cexpr!("SIZEOF(struct rb_builtin_function)"),
+ func_ptr: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), func_ptr)")],
+ argc: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), argc)")],
+ index: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), index)")],
+ name: [CType::Pointer.new { CType::Immediate.parse("char") }, Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), name)")],
+ compiler: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), compiler)")],
+ )
+ end
+
+ def C.rb_call_data
+ @rb_call_data ||= CType::Struct.new(
+ "rb_call_data", Primitive.cexpr!("SIZEOF(struct rb_call_data)"),
+ ci: [CType::Pointer.new { self.rb_callinfo }, Primitive.cexpr!("OFFSETOF((*((struct rb_call_data *)NULL)), ci)")],
+ cc: [CType::Pointer.new { self.rb_callcache }, Primitive.cexpr!("OFFSETOF((*((struct rb_call_data *)NULL)), cc)")],
+ )
+ end
+
+ def C.rb_callable_method_entry_struct
+ @rb_callable_method_entry_struct ||= CType::Struct.new(
+ "rb_callable_method_entry_struct", Primitive.cexpr!("SIZEOF(struct rb_callable_method_entry_struct)"),
+ flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), flags)")],
+ defined_class: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), defined_class)")],
+ def: [CType::Pointer.new { self.rb_method_definition_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), def)")],
+ called_id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), called_id)")],
+ owner: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), owner)")],
+ )
+ end
+
+ def C.rb_callcache
+ @rb_callcache ||= CType::Struct.new(
+ "rb_callcache", Primitive.cexpr!("SIZEOF(struct rb_callcache)"),
+ flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), flags)")],
+ klass: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), klass)")],
+ cme_: [CType::Pointer.new { self.rb_callable_method_entry_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), cme_)")],
+ call_: [self.vm_call_handler, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), call_)")],
+ aux_: [CType::Union.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_callcache *)NULL)->aux_)"),
+ attr: CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_callcache *)NULL)->aux_.attr)"),
+ value: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF(((struct rb_callcache *)NULL)->aux_.attr, value)")],
+ ),
+ method_missing_reason: self.method_missing_reason,
+ v: self.VALUE,
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), aux_)")],
+ )
+ end
+
+ def C.rb_callinfo
+ @rb_callinfo ||= CType::Struct.new(
+ "rb_callinfo", Primitive.cexpr!("SIZEOF(struct rb_callinfo)"),
+ flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), flags)")],
+ kwarg: [CType::Pointer.new { self.rb_callinfo_kwarg }, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), kwarg)")],
+ mid: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), mid)")],
+ flag: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), flag)")],
+ argc: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), argc)")],
+ )
+ end
+
+ def C.rb_control_frame_t
+ @rb_control_frame_t ||= CType::Struct.new(
+ "rb_control_frame_struct", Primitive.cexpr!("SIZEOF(struct rb_control_frame_struct)"),
+ pc: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), pc)")],
+ sp: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), sp)")],
+ iseq: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), iseq)")],
+ self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), self)")],
+ ep: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), ep)")],
+ block_code: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), block_code)")],
+ __bp__: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), __bp__)")],
+ jit_return: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), jit_return)")],
+ )
+ end
+
+ def C.rb_cref_t
+ @rb_cref_t ||= CType::Struct.new(
+ "rb_cref_struct", Primitive.cexpr!("SIZEOF(struct rb_cref_struct)"),
+ flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), flags)")],
+ refinements: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), refinements)")],
+ klass_or_self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), klass_or_self)")],
+ next: [CType::Pointer.new { self.rb_cref_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), next)")],
+ scope_visi: [self.rb_scope_visibility_t, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), scope_visi)")],
+ )
+ end
+
+ def C.rb_execution_context_struct
+ @rb_execution_context_struct ||= CType::Struct.new(
+ "rb_execution_context_struct", Primitive.cexpr!("SIZEOF(struct rb_execution_context_struct)"),
+ vm_stack: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), vm_stack)")],
+ vm_stack_size: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), vm_stack_size)")],
+ cfp: [CType::Pointer.new { self.rb_control_frame_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), cfp)")],
+ tag: [CType::Pointer.new { self.rb_vm_tag }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), tag)")],
+ interrupt_flag: [self.rb_atomic_t, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), interrupt_flag)")],
+ interrupt_mask: [self.rb_atomic_t, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), interrupt_mask)")],
+ fiber_ptr: [CType::Pointer.new { self.rb_fiber_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), fiber_ptr)")],
+ thread_ptr: [CType::Pointer.new { self.rb_thread_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), thread_ptr)")],
+ local_storage: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), local_storage)")],
+ local_storage_recursive_hash: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), local_storage_recursive_hash)")],
+ local_storage_recursive_hash_for_trace: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), local_storage_recursive_hash_for_trace)")],
+ storage: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), storage)")],
+ root_lep: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), root_lep)")],
+ root_svar: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), root_svar)")],
+ ensure_list: [CType::Pointer.new { self.rb_ensure_list_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), ensure_list)")],
+ trace_arg: [CType::Pointer.new { self.rb_trace_arg_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), trace_arg)")],
+ errinfo: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), errinfo)")],
+ passed_block_handler: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), passed_block_handler)")],
+ raised_flag: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), raised_flag)")],
+ private_const_reference: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), private_const_reference)")],
+ machine: [CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_execution_context_struct *)NULL)->machine)"),
+ stack_start: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_start)")],
+ stack_end: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_end)")],
+ stack_maxsize: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_maxsize)")],
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), machine)")],
+ )
+ end
+
+ def C.rb_execution_context_t
+ @rb_execution_context_t ||= self.rb_execution_context_struct
+ end
+
+ def C.rb_iseq_constant_body
+ @rb_iseq_constant_body ||= CType::Struct.new(
+ "rb_iseq_constant_body", Primitive.cexpr!("SIZEOF(struct rb_iseq_constant_body)"),
+ type: [self.rb_iseq_type, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), type)")],
+ iseq_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), iseq_size)")],
+ iseq_encoded: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), iseq_encoded)")],
+ param: [CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->param)"),
+ flags: [CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->param.flags)"),
+ has_lead: [CType::BitField.new(1, 0), 0],
+ has_opt: [CType::BitField.new(1, 1), 1],
+ has_rest: [CType::BitField.new(1, 2), 2],
+ has_post: [CType::BitField.new(1, 3), 3],
+ has_kw: [CType::BitField.new(1, 4), 4],
+ has_kwrest: [CType::BitField.new(1, 5), 5],
+ has_block: [CType::BitField.new(1, 6), 6],
+ ambiguous_param0: [CType::BitField.new(1, 7), 7],
+ accepts_no_kwarg: [CType::BitField.new(1, 0), 8],
+ ruby2_keywords: [CType::BitField.new(1, 1), 9],
+ ), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, flags)")],
+ size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, size)")],
+ lead_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, lead_num)")],
+ opt_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, opt_num)")],
+ rest_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, rest_start)")],
+ post_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, post_start)")],
+ post_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, post_num)")],
+ block_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, block_start)")],
+ opt_table: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, opt_table)")],
+ keyword: [CType::Pointer.new { self.rb_iseq_param_keyword }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, keyword)")],
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), param)")],
+ location: [self.rb_iseq_location_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), location)")],
+ insns_info: [self.iseq_insn_info, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), insns_info)")],
+ local_table: [CType::Pointer.new { self.ID }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), local_table)")],
+ catch_table: [CType::Pointer.new { self.iseq_catch_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), catch_table)")],
+ parent_iseq: [CType::Pointer.new { self.rb_iseq_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), parent_iseq)")],
+ local_iseq: [CType::Pointer.new { self.rb_iseq_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), local_iseq)")],
+ is_entries: [CType::Pointer.new { self.iseq_inline_storage_entry }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), is_entries)")],
+ call_data: [CType::Pointer.new { self.rb_call_data }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), call_data)")],
+ variable: [CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->variable)"),
+ flip_count: [self.rb_snum_t, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, flip_count)")],
+ script_lines: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, script_lines)")],
+ coverage: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, coverage)")],
+ pc2branchindex: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, pc2branchindex)")],
+ original_iseq: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, original_iseq)")],
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), variable)")],
+ local_table_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), local_table_size)")],
+ ic_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ic_size)")],
+ ise_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ise_size)")],
+ ivc_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ivc_size)")],
+ icvarc_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), icvarc_size)")],
+ ci_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ci_size)")],
+ stack_max: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), stack_max)")],
+ catch_except_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), catch_except_p)")],
+ builtin_inline_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), builtin_inline_p)")],
+ mark_bits: [CType::Union.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->mark_bits)"),
+ list: CType::Pointer.new { self.iseq_bits_t },
+ single: self.iseq_bits_t,
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), mark_bits)")],
+ outer_variables: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), outer_variables)")],
+ mandatory_only_iseq: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), mandatory_only_iseq)")],
+ jit_func: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), jit_func)")],
+ total_calls: [CType::Immediate.parse("unsigned long"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), total_calls)")],
+ mjit_unit: [CType::Pointer.new { self.rb_mjit_unit }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), mjit_unit)")],
+ )
+ end
+
+ def C.rb_iseq_location_t
+ @rb_iseq_location_t ||= CType::Struct.new(
+ "rb_iseq_location_struct", Primitive.cexpr!("SIZEOF(struct rb_iseq_location_struct)"),
+ pathobj: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), pathobj)"), true],
+ base_label: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), base_label)"), true],
+ label: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), label)"), true],
+ first_lineno: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), first_lineno)"), true],
+ node_id: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), node_id)")],
+ code_location: [self.rb_code_location_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), code_location)")],
+ )
+ end
+
+ def C.rb_iseq_struct
+ @rb_iseq_struct ||= CType::Struct.new(
+ "rb_iseq_struct", Primitive.cexpr!("SIZEOF(struct rb_iseq_struct)"),
+ flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), flags)")],
+ wrapper: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), wrapper)")],
+ body: [CType::Pointer.new { self.rb_iseq_constant_body }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), body)")],
+ aux: [CType::Union.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_struct *)NULL)->aux)"),
+ compile_data: CType::Pointer.new { self.iseq_compile_data },
+ loader: CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_struct *)NULL)->aux.loader)"),
+ obj: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.loader, obj)")],
+ index: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.loader, index)")],
+ ),
+ exec: CType::Struct.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_struct *)NULL)->aux.exec)"),
+ local_hooks: [CType::Pointer.new { self.rb_hook_list_struct }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.exec, local_hooks)")],
+ global_trace_events: [self.rb_event_flag_t, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.exec, global_trace_events)")],
+ ),
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), aux)")],
+ )
+ end
+
+ def C.rb_iseq_t
+ @rb_iseq_t ||= self.rb_iseq_struct
+ end
+
+ def C.rb_method_definition_struct
+ @rb_method_definition_struct ||= CType::Struct.new(
+ "rb_method_definition_struct", Primitive.cexpr!("SIZEOF(struct rb_method_definition_struct)"),
+ type: [CType::BitField.new(4, 0), 0],
+ iseq_overload: [CType::BitField.new(1, 4), 4],
+ no_redef_warning: [CType::BitField.new(1, 5), 5],
+ aliased: [CType::BitField.new(1, 6), 6],
+ reference_count: [CType::BitField.new(28, 0), 32],
+ body: [CType::Union.new(
+ "", Primitive.cexpr!("SIZEOF(((struct rb_method_definition_struct *)NULL)->body)"),
+ iseq: self.rb_method_iseq_t,
+ cfunc: self.rb_method_cfunc_t,
+ attr: self.rb_method_attr_t,
+ alias: self.rb_method_alias_t,
+ refined: self.rb_method_refined_t,
+ bmethod: self.rb_method_bmethod_t,
+ optimized: self.rb_method_optimized_t,
+ ), Primitive.cexpr!("OFFSETOF((*((struct rb_method_definition_struct *)NULL)), body)")],
+ original_id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_method_definition_struct *)NULL)), original_id)")],
+ method_serial: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_method_definition_struct *)NULL)), method_serial)")],
+ )
+ end
+
+ def C.rb_method_iseq_t
+ @rb_method_iseq_t ||= CType::Struct.new(
+ "rb_method_iseq_struct", Primitive.cexpr!("SIZEOF(struct rb_method_iseq_struct)"),
+ iseqptr: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_method_iseq_struct *)NULL)), iseqptr)")],
+ cref: [CType::Pointer.new { self.rb_cref_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_method_iseq_struct *)NULL)), cref)")],
+ )
+ end
+
+ def C.rb_method_type_t
+ @rb_method_type_t ||= CType::Immediate.parse("int")
+ end
+
+ def C.rb_mjit_compile_info
+ @rb_mjit_compile_info ||= CType::Struct.new(
+ "rb_mjit_compile_info", Primitive.cexpr!("SIZEOF(struct rb_mjit_compile_info)"),
+ disable_ivar_cache: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_compile_info *)NULL)), disable_ivar_cache)")],
+ disable_exivar_cache: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_compile_info *)NULL)), disable_exivar_cache)")],
+ disable_send_cache: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_compile_info *)NULL)), disable_send_cache)")],
+ disable_inlining: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_compile_info *)NULL)), disable_inlining)")],
+ disable_const_cache: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_compile_info *)NULL)), disable_const_cache)")],
+ )
+ end
+
+ def C.rb_mjit_unit
+ @rb_mjit_unit ||= CType::Struct.new(
+ "rb_mjit_unit", Primitive.cexpr!("SIZEOF(struct rb_mjit_unit)"),
+ unode: [self.ccan_list_node, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), unode)")],
+ id: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), id)")],
+ type: [self.rb_mjit_unit_type, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), type)")],
+ iseq: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), iseq)")],
+ used_code_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), used_code_p)")],
+ compile_info: [self.rb_mjit_compile_info, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), compile_info)")],
+ cc_entries: [CType::Pointer.new { CType::Pointer.new { self.rb_callcache } }, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), cc_entries)")],
+ cc_entries_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), cc_entries_size)")],
+ handle: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), handle)")],
+ units: [self.rb_mjit_unit_list, Primitive.cexpr!("OFFSETOF((*((struct rb_mjit_unit *)NULL)), units)")],
+ )
+ end
+
+ def C.rb_serial_t
+ @rb_serial_t ||= CType::Immediate.parse("unsigned long long")
+ end
+
+ def C.rb_shape
+ @rb_shape ||= CType::Struct.new(
+ "rb_shape", Primitive.cexpr!("SIZEOF(struct rb_shape)"),
+ edges: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), edges)")],
+ edge_name: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), edge_name)")],
+ next_iv_index: [self.attr_index_t, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), next_iv_index)")],
+ capacity: [CType::Immediate.parse("uint32_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), capacity)")],
+ type: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), type)")],
+ size_pool_index: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), size_pool_index)")],
+ parent_id: [self.shape_id_t, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), parent_id)")],
+ )
+ end
+
+ def C.rb_shape_t
+ @rb_shape_t ||= self.rb_shape
+ end
+
+ def C.VALUE
+ @VALUE ||= CType::Immediate.find(Primitive.cexpr!("SIZEOF(VALUE)"), Primitive.cexpr!("SIGNED_TYPE_P(VALUE)"))
+ end
+
+ def C.shape_id_t
+ @shape_id_t ||= CType::Immediate.find(Primitive.cexpr!("SIZEOF(shape_id_t)"), Primitive.cexpr!("SIGNED_TYPE_P(shape_id_t)"))
+ end
+
+ def C._Bool
+ CType::Bool.new
+ end
+
+ def C.ID
+ CType::Stub.new(:ID)
+ end
+
+ def C.rb_thread_struct
+ CType::Stub.new(:rb_thread_struct)
+ end
+
+ def C.vm_call_handler
+ CType::Stub.new(:vm_call_handler)
+ end
+
+ def C.method_missing_reason
+ CType::Stub.new(:method_missing_reason)
+ end
+
+ def C.rb_callinfo_kwarg
+ CType::Stub.new(:rb_callinfo_kwarg)
+ end
+
+ def C.rb_cref_struct
+ CType::Stub.new(:rb_cref_struct)
+ end
+
+ def C.rb_scope_visibility_t
+ CType::Stub.new(:rb_scope_visibility_t)
+ end
+
+ def C.rb_vm_tag
+ CType::Stub.new(:rb_vm_tag)
+ end
+
+ def C.rb_atomic_t
+ CType::Stub.new(:rb_atomic_t)
+ end
+
+ def C.rb_fiber_t
+ CType::Stub.new(:rb_fiber_t)
+ end
+
+ def C.rb_id_table
+ CType::Stub.new(:rb_id_table)
+ end
+
+ def C.rb_ensure_list_t
+ CType::Stub.new(:rb_ensure_list_t)
+ end
+
+ def C.rb_trace_arg_struct
+ CType::Stub.new(:rb_trace_arg_struct)
+ end
+
+ def C.rb_iseq_type
+ CType::Stub.new(:rb_iseq_type)
+ end
+
+ def C.rb_iseq_param_keyword
+ CType::Stub.new(:rb_iseq_param_keyword)
+ end
+
+ def C.iseq_insn_info
+ CType::Stub.new(:iseq_insn_info)
+ end
+
+ def C.iseq_catch_table
+ CType::Stub.new(:iseq_catch_table)
+ end
+
+ def C.rb_snum_t
+ CType::Stub.new(:rb_snum_t)
+ end
+
+ def C.iseq_bits_t
+ CType::Stub.new(:iseq_bits_t)
+ end
+
+ def C.rb_code_location_t
+ CType::Stub.new(:rb_code_location_t)
+ end
+
+ def C.iseq_compile_data
+ CType::Stub.new(:iseq_compile_data)
+ end
+
+ def C.rb_hook_list_struct
+ CType::Stub.new(:rb_hook_list_struct)
+ end
+
+ def C.rb_event_flag_t
+ CType::Stub.new(:rb_event_flag_t)
+ end
+
+ def C.rb_method_cfunc_t
+ CType::Stub.new(:rb_method_cfunc_t)
+ end
+
+ def C.rb_method_attr_t
+ CType::Stub.new(:rb_method_attr_t)
+ end
+
+ def C.rb_method_alias_t
+ CType::Stub.new(:rb_method_alias_t)
+ end
+
+ def C.rb_method_refined_t
+ CType::Stub.new(:rb_method_refined_t)
+ end
+
+ def C.rb_method_bmethod_t
+ CType::Stub.new(:rb_method_bmethod_t)
+ end
+
+ def C.rb_method_optimized_t
+ CType::Stub.new(:rb_method_optimized_t)
+ end
+
+ def C.ccan_list_node
+ CType::Stub.new(:ccan_list_node)
+ end
+
+ def C.rb_mjit_unit_type
+ CType::Stub.new(:rb_mjit_unit_type)
+ end
+
+ def C.rb_mjit_unit_list
+ CType::Stub.new(:rb_mjit_unit_list)
+ end
+
+ ### MJIT bindgen end ###
+end if RubyVM::MJIT.enabled? && RubyVM::MJIT.const_defined?(:C) # not defined for miniruby
diff --git a/node.c b/node.c
index 1a52fbba3d..a6cb498778 100644
--- a/node.c
+++ b/node.c
@@ -9,123 +9,1204 @@
**********************************************************************/
-#ifdef UNIVERSAL_PARSER
-#include <stddef.h>
-#include "node.h"
-#include "rubyparser.h"
-#endif
-
+#include "internal.h"
+#include "internal/hash.h"
#include "internal/variable.h"
+#include "ruby/ruby.h"
+#include "vm_core.h"
-#define NODE_BUF_DEFAULT_SIZE (sizeof(struct RNode) * 16)
+#define NODE_BUF_DEFAULT_LEN 16
-static void
-init_node_buffer_elem(node_buffer_elem_t *nbe, size_t allocated, void *xmalloc(size_t))
+#define A(str) rb_str_cat2(buf, (str))
+#define AR(str) rb_str_concat(buf, (str))
+
+#define A_INDENT add_indent(buf, indent)
+#define D_INDENT rb_str_cat2(indent, next_indent)
+#define D_DEDENT rb_str_resize(indent, RSTRING_LEN(indent) - 4)
+#define A_ID(id) add_id(buf, (id))
+#define A_INT(val) rb_str_catf(buf, "%d", (val))
+#define A_LONG(val) rb_str_catf(buf, "%ld", (val))
+#define A_LIT(lit) AR(rb_dump_literal(lit))
+#define A_NODE_HEADER(node, term) \
+ rb_str_catf(buf, "@ %s (id: %d, line: %d, location: (%d,%d)-(%d,%d))%s"term, \
+ ruby_node_name(nd_type(node)), nd_node_id(node), nd_line(node), \
+ nd_first_lineno(node), nd_first_column(node), \
+ nd_last_lineno(node), nd_last_column(node), \
+ (node->flags & NODE_FL_NEWLINE ? "*" : ""))
+#define A_FIELD_HEADER(len, name, term) \
+ rb_str_catf(buf, "+- %.*s:"term, (len), (name))
+#define D_FIELD_HEADER(len, name, term) (A_INDENT, A_FIELD_HEADER(len, name, term))
+
+#define D_NULL_NODE (A_INDENT, A("(null node)\n"))
+#define D_NODE_HEADER(node) (A_INDENT, A_NODE_HEADER(node, "\n"))
+
+#define COMPOUND_FIELD(len, name) \
+ FIELD_BLOCK((D_FIELD_HEADER((len), (name), "\n"), D_INDENT), D_DEDENT)
+
+#define COMPOUND_FIELD1(name, ann) \
+ COMPOUND_FIELD(FIELD_NAME_LEN(name, ann), \
+ FIELD_NAME_DESC(name, ann))
+
+#define FIELD_NAME_DESC(name, ann) name " (" ann ")"
+#define FIELD_NAME_LEN(name, ann) (int)( \
+ comment ? \
+ rb_strlen_lit(FIELD_NAME_DESC(name, ann)) : \
+ rb_strlen_lit(name))
+#define SIMPLE_FIELD(len, name) \
+ FIELD_BLOCK(D_FIELD_HEADER((len), (name), " "), A("\n"))
+
+#define FIELD_BLOCK(init, reset) \
+ for (init, field_flag = 1; \
+ field_flag; /* should be optimized away */ \
+ reset, field_flag = 0)
+
+#define SIMPLE_FIELD1(name, ann) SIMPLE_FIELD(FIELD_NAME_LEN(name, ann), FIELD_NAME_DESC(name, ann))
+#define F_CUSTOM1(name, ann) SIMPLE_FIELD1(#name, ann)
+#define F_ID(name, ann) SIMPLE_FIELD1(#name, ann) A_ID(node->name)
+#define F_GENTRY(name, ann) SIMPLE_FIELD1(#name, ann) A_ID(node->name)
+#define F_INT(name, ann) SIMPLE_FIELD1(#name, ann) A_INT(node->name)
+#define F_LONG(name, ann) SIMPLE_FIELD1(#name, ann) A_LONG(node->name)
+#define F_LIT(name, ann) SIMPLE_FIELD1(#name, ann) A_LIT(node->name)
+#define F_MSG(name, ann, desc) SIMPLE_FIELD1(#name, ann) A(desc)
+
+#define F_NODE(name, ann) \
+ COMPOUND_FIELD1(#name, ann) {dump_node(buf, indent, comment, node->name);}
+
+#define ANN(ann) \
+ if (comment) { \
+ A_INDENT; A("| # " ann "\n"); \
+ }
+
+#define LAST_NODE (next_indent = " ")
+
+VALUE
+rb_dump_literal(VALUE lit)
{
- nbe->allocated = allocated;
- nbe->used = 0;
- nbe->len = 0;
- nbe->nodes = xmalloc(allocated / sizeof(struct RNode) * sizeof(struct RNode *)); /* All node requires at least RNode */
+ if (!RB_SPECIAL_CONST_P(lit)) {
+ VALUE str;
+ switch (RB_BUILTIN_TYPE(lit)) {
+ case T_CLASS: case T_MODULE: case T_ICLASS:
+ str = rb_class_path(lit);
+ if (FL_TEST(lit, FL_SINGLETON)) {
+ str = rb_sprintf("<%"PRIsVALUE">", str);
+ }
+ return str;
+ default:
+ break;
+ }
+ }
+ return rb_inspect(lit);
}
static void
-init_node_buffer_list(node_buffer_list_t *nb, node_buffer_elem_t *head, void *xmalloc(size_t))
+add_indent(VALUE buf, VALUE indent)
{
- init_node_buffer_elem(head, NODE_BUF_DEFAULT_SIZE, xmalloc);
- nb->head = nb->last = head;
- nb->head->next = NULL;
+ AR(indent);
}
-#ifdef UNIVERSAL_PARSER
-#define ruby_xmalloc config->malloc
-#endif
-
-#ifdef UNIVERSAL_PARSER
-static node_buffer_t *
-rb_node_buffer_new(const rb_parser_config_t *config)
-#else
-static node_buffer_t *
-rb_node_buffer_new(void)
-#endif
+static void
+add_id(VALUE buf, ID id)
{
- const size_t bucket_size = offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_SIZE;
- const size_t alloc_size = sizeof(node_buffer_t) + (bucket_size);
- STATIC_ASSERT(
- integer_overflow,
- offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_SIZE
- > sizeof(node_buffer_t) + sizeof(node_buffer_elem_t));
- node_buffer_t *nb = ruby_xmalloc(alloc_size);
- init_node_buffer_list(&nb->buffer_list, (node_buffer_elem_t*)&nb[1], ruby_xmalloc);
- nb->local_tables = 0;
- nb->tokens = 0;
- return nb;
+ if (id == 0) {
+ A("(null)");
+ }
+ else {
+ VALUE str = rb_id2str(id);
+ if (str) {
+ A(":"); AR(str);
+ }
+ else {
+ rb_str_catf(buf, "(internal variable: 0x%"PRIsVALUE")", id);
+ }
+ }
}
-#ifdef UNIVERSAL_PARSER
-#undef ruby_xmalloc
-#define ruby_xmalloc ast->config->malloc
-#undef xfree
-#define xfree ast->config->free
-#define rb_xmalloc_mul_add ast->config->xmalloc_mul_add
-#define ruby_xrealloc(var,size) (ast->config->realloc_n((void *)var, 1, size))
-#endif
+struct add_option_arg {
+ VALUE buf, indent;
+ st_index_t count;
+};
-typedef void node_itr_t(rb_ast_t *ast, void *ctx, NODE *node);
-static void iterate_node_values(rb_ast_t *ast, node_buffer_list_t *nb, node_itr_t * func, void *ctx);
+static void dump_node(VALUE, VALUE, int, const NODE *);
+static const char default_indent[] = "| ";
-void
-rb_node_init(NODE *n, enum node_type type)
+static void
+dump_array(VALUE buf, VALUE indent, int comment, const NODE *node)
{
- RNODE(n)->flags = 0;
- nd_init_type(RNODE(n), type);
- RNODE(n)->nd_loc.beg_pos.lineno = 0;
- RNODE(n)->nd_loc.beg_pos.column = 0;
- RNODE(n)->nd_loc.end_pos.lineno = 0;
- RNODE(n)->nd_loc.end_pos.column = 0;
- RNODE(n)->node_id = -1;
+ int field_flag;
+ const char *next_indent = default_indent;
+ F_LONG(nd_alen, "length");
+ F_NODE(nd_head, "element");
+ while (node->nd_next && nd_type_p(node->nd_next, NODE_LIST)) {
+ node = node->nd_next;
+ F_NODE(nd_head, "element");
+ }
+ LAST_NODE;
+ F_NODE(nd_next, "next element");
}
-const char *
-rb_node_name(int node)
+static void
+dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
{
- switch (node) {
-#include "node_name.inc"
- default:
- return 0;
+ int field_flag;
+ int i;
+ const char *next_indent = default_indent;
+ enum node_type type;
+
+ if (!node) {
+ D_NULL_NODE;
+ return;
}
+
+ D_NODE_HEADER(node);
+
+ type = nd_type(node);
+ switch (type) {
+ case NODE_BLOCK:
+ ANN("statement sequence");
+ ANN("format: [nd_head]; ...; [nd_next]");
+ ANN("example: foo; bar");
+ i = 0;
+ do {
+ A_INDENT;
+ rb_str_catf(buf, "+- nd_head (%s%d):\n",
+ comment ? "statement #" : "", ++i);
+ if (!node->nd_next) LAST_NODE;
+ D_INDENT;
+ dump_node(buf, indent, comment, node->nd_head);
+ D_DEDENT;
+ } while (node->nd_next &&
+ nd_type_p(node->nd_next, NODE_BLOCK) &&
+ (node = node->nd_next, 1));
+ if (node->nd_next) {
+ LAST_NODE;
+ F_NODE(nd_next, "next block");
+ }
+ return;
+
+ case NODE_IF:
+ ANN("if statement");
+ ANN("format: if [nd_cond] then [nd_body] else [nd_else] end");
+ ANN("example: if x == 1 then foo else bar end");
+ F_NODE(nd_cond, "condition expr");
+ F_NODE(nd_body, "then clause");
+ LAST_NODE;
+ F_NODE(nd_else, "else clause");
+ return;
+
+ case NODE_UNLESS:
+ ANN("unless statement");
+ ANN("format: unless [nd_cond] then [nd_body] else [nd_else] end");
+ ANN("example: unless x == 1 then foo else bar end");
+ F_NODE(nd_cond, "condition expr");
+ F_NODE(nd_body, "then clause");
+ LAST_NODE;
+ F_NODE(nd_else, "else clause");
+ return;
+
+ case NODE_CASE:
+ ANN("case statement");
+ ANN("format: case [nd_head]; [nd_body]; end");
+ ANN("example: case x; when 1; foo; when 2; bar; else baz; end");
+ F_NODE(nd_head, "case expr");
+ LAST_NODE;
+ F_NODE(nd_body, "when clauses");
+ return;
+ case NODE_CASE2:
+ ANN("case statement with no head");
+ ANN("format: case; [nd_body]; end");
+ ANN("example: case; when 1; foo; when 2; bar; else baz; end");
+ F_NODE(nd_head, "case expr");
+ LAST_NODE;
+ F_NODE(nd_body, "when clauses");
+ return;
+ case NODE_CASE3:
+ ANN("case statement (pattern matching)");
+ ANN("format: case [nd_head]; [nd_body]; end");
+ ANN("example: case x; in 1; foo; in 2; bar; else baz; end");
+ F_NODE(nd_head, "case expr");
+ LAST_NODE;
+ F_NODE(nd_body, "in clauses");
+ return;
+
+ case NODE_WHEN:
+ ANN("when clause");
+ ANN("format: when [nd_head]; [nd_body]; (when or else) [nd_next]");
+ ANN("example: case x; when 1; foo; when 2; bar; else baz; end");
+ F_NODE(nd_head, "when value");
+ F_NODE(nd_body, "when body");
+ LAST_NODE;
+ F_NODE(nd_next, "next when clause");
+ return;
+
+ case NODE_IN:
+ ANN("in clause");
+ ANN("format: in [nd_head]; [nd_body]; (in or else) [nd_next]");
+ ANN("example: case x; in 1; foo; in 2; bar; else baz; end");
+ F_NODE(nd_head, "in pattern");
+ F_NODE(nd_body, "in body");
+ LAST_NODE;
+ F_NODE(nd_next, "next in clause");
+ return;
+
+ case NODE_WHILE:
+ ANN("while statement");
+ ANN("format: while [nd_cond]; [nd_body]; end");
+ ANN("example: while x == 1; foo; end");
+ goto loop;
+ case NODE_UNTIL:
+ ANN("until statement");
+ ANN("format: until [nd_cond]; [nd_body]; end");
+ ANN("example: until x == 1; foo; end");
+ loop:
+ F_CUSTOM1(nd_state, "begin-end-while?") {
+ A_INT((int)node->nd_state);
+ A((node->nd_state == 1) ? " (while-end)" : " (begin-end-while)");
+ }
+ F_NODE(nd_cond, "condition");
+ LAST_NODE;
+ F_NODE(nd_body, "body");
+ return;
+
+ case NODE_ITER:
+ ANN("method call with block");
+ ANN("format: [nd_iter] { [nd_body] }");
+ ANN("example: 3.times { foo }");
+ goto iter;
+ case NODE_FOR:
+ ANN("for statement");
+ ANN("format: for * in [nd_iter] do [nd_body] end");
+ ANN("example: for i in 1..3 do foo end");
+ iter:
+ F_NODE(nd_iter, "iteration receiver");
+ LAST_NODE;
+ F_NODE(nd_body, "body");
+ return;
+
+ case NODE_FOR_MASGN:
+ ANN("vars of for statement with masgn");
+ ANN("format: for [nd_var] in ... do ... end");
+ ANN("example: for x, y in 1..3 do foo end");
+ LAST_NODE;
+ F_NODE(nd_var, "var");
+ return;
+
+ case NODE_BREAK:
+ ANN("break statement");
+ ANN("format: break [nd_stts]");
+ ANN("example: break 1");
+ goto jump;
+ case NODE_NEXT:
+ ANN("next statement");
+ ANN("format: next [nd_stts]");
+ ANN("example: next 1");
+ goto jump;
+ case NODE_RETURN:
+ ANN("return statement");
+ ANN("format: return [nd_stts]");
+ ANN("example: return 1");
+ jump:
+ LAST_NODE;
+ F_NODE(nd_stts, "value");
+ return;
+
+ case NODE_REDO:
+ ANN("redo statement");
+ ANN("format: redo");
+ ANN("example: redo");
+ return;
+
+ case NODE_RETRY:
+ ANN("retry statement");
+ ANN("format: retry");
+ ANN("example: retry");
+ return;
+
+ case NODE_BEGIN:
+ ANN("begin statement");
+ ANN("format: begin; [nd_body]; end");
+ ANN("example: begin; 1; end");
+ LAST_NODE;
+ F_NODE(nd_body, "body");
+ return;
+
+ case NODE_RESCUE:
+ ANN("rescue clause");
+ ANN("format: begin; [nd_body]; (rescue) [nd_resq]; else [nd_else]; end");
+ ANN("example: begin; foo; rescue; bar; else; baz; end");
+ F_NODE(nd_head, "body");
+ F_NODE(nd_resq, "rescue clause list");
+ LAST_NODE;
+ F_NODE(nd_else, "rescue else clause");
+ return;
+
+ case NODE_RESBODY:
+ ANN("rescue clause (cont'd)");
+ ANN("format: rescue [nd_args]; [nd_body]; (rescue) [nd_head]");
+ ANN("example: begin; foo; rescue; bar; else; baz; end");
+ F_NODE(nd_args, "rescue exceptions");
+ F_NODE(nd_body, "rescue clause");
+ LAST_NODE;
+ F_NODE(nd_head, "next rescue clause");
+ return;
+
+ case NODE_ENSURE:
+ ANN("ensure clause");
+ ANN("format: begin; [nd_head]; ensure; [nd_ensr]; end");
+ ANN("example: begin; foo; ensure; bar; end");
+ F_NODE(nd_head, "body");
+ LAST_NODE;
+ F_NODE(nd_ensr, "ensure clause");
+ return;
+
+ case NODE_AND:
+ ANN("&& operator");
+ ANN("format: [nd_1st] && [nd_2nd]");
+ ANN("example: foo && bar");
+ goto andor;
+ case NODE_OR:
+ ANN("|| operator");
+ ANN("format: [nd_1st] || [nd_2nd]");
+ ANN("example: foo || bar");
+ andor:
+ while (1) {
+ F_NODE(nd_1st, "left expr");
+ if (!node->nd_2nd || !nd_type_p(node->nd_2nd, type))
+ break;
+ node = node->nd_2nd;
+ }
+ LAST_NODE;
+ F_NODE(nd_2nd, "right expr");
+ return;
+
+ case NODE_MASGN:
+ ANN("multiple assignment");
+ ANN("format: [nd_head], [nd_args] = [nd_value]");
+ ANN("example: a, b = foo");
+ F_NODE(nd_value, "rhsn");
+ F_NODE(nd_head, "lhsn");
+ if (NODE_NAMED_REST_P(node->nd_args)) {
+ LAST_NODE;
+ F_NODE(nd_args, "splatn");
+ }
+ else {
+ F_MSG(nd_args, "splatn", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
+ }
+ return;
+
+ case NODE_LASGN:
+ ANN("local variable assignment");
+ ANN("format: [nd_vid](lvar) = [nd_value]");
+ ANN("example: x = foo");
+ F_ID(nd_vid, "local variable");
+ if (NODE_REQUIRED_KEYWORD_P(node)) {
+ F_MSG(nd_value, "rvalue", "NODE_SPECIAL_REQUIRED_KEYWORD (required keyword argument)");
+ }
+ else {
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ }
+ return;
+ case NODE_DASGN:
+ ANN("dynamic variable assignment");
+ ANN("format: [nd_vid](dvar) = [nd_value]");
+ ANN("example: x = nil; 1.times { x = foo }");
+ ANN("example: 1.times { x = foo }");
+ F_ID(nd_vid, "local variable");
+ if (NODE_REQUIRED_KEYWORD_P(node)) {
+ F_MSG(nd_value, "rvalue", "NODE_SPECIAL_REQUIRED_KEYWORD (required keyword argument)");
+ }
+ else {
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ }
+ return;
+ case NODE_IASGN:
+ ANN("instance variable assignment");
+ ANN("format: [nd_vid](ivar) = [nd_value]");
+ ANN("example: @x = foo");
+ F_ID(nd_vid, "instance variable");
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+ case NODE_CVASGN:
+ ANN("class variable assignment");
+ ANN("format: [nd_vid](cvar) = [nd_value]");
+ ANN("example: @@x = foo");
+ F_ID(nd_vid, "class variable");
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+ case NODE_GASGN:
+ ANN("global variable assignment");
+ ANN("format: [nd_entry](gvar) = [nd_value]");
+ ANN("example: $x = foo");
+ F_GENTRY(nd_entry, "global variable");
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+
+ case NODE_CDECL:
+ ANN("constant declaration");
+ ANN("format: [nd_else]::[nd_vid](constant) = [nd_value]");
+ ANN("example: X = foo");
+ if (node->nd_vid) {
+ F_ID(nd_vid, "constant");
+ F_MSG(nd_else, "extension", "not used");
+ }
+ else {
+ F_MSG(nd_vid, "constant", "0 (see extension field)");
+ F_NODE(nd_else, "extension");
+ }
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+
+ case NODE_OP_ASGN1:
+ ANN("array assignment with operator");
+ ANN("format: [nd_recv] [ [nd_args->nd_head] ] [nd_mid]= [nd_args->nd_body]");
+ ANN("example: ary[1] += foo");
+ F_NODE(nd_recv, "receiver");
+ F_ID(nd_mid, "operator");
+ F_NODE(nd_args->nd_head, "index");
+ LAST_NODE;
+ F_NODE(nd_args->nd_body, "rvalue");
+ return;
+
+ case NODE_OP_ASGN2:
+ ANN("attr assignment with operator");
+ ANN("format: [nd_recv].[attr] [nd_next->nd_mid]= [nd_value]");
+ ANN(" where [attr]: [nd_next->nd_vid]");
+ ANN("example: struct.field += foo");
+ F_NODE(nd_recv, "receiver");
+ F_CUSTOM1(nd_next->nd_vid, "attr") {
+ if (node->nd_next->nd_aid) A("? ");
+ A_ID(node->nd_next->nd_vid);
+ }
+ F_ID(nd_next->nd_mid, "operator");
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+
+ case NODE_OP_ASGN_AND:
+ ANN("assignment with && operator");
+ ANN("format: [nd_head] &&= [nd_value]");
+ ANN("example: foo &&= bar");
+ goto asgn_andor;
+ case NODE_OP_ASGN_OR:
+ ANN("assignment with || operator");
+ ANN("format: [nd_head] ||= [nd_value]");
+ ANN("example: foo ||= bar");
+ asgn_andor:
+ F_NODE(nd_head, "variable");
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+
+ case NODE_OP_CDECL:
+ ANN("constant declaration with operator");
+ ANN("format: [nd_head](constant) [nd_aid]= [nd_value]");
+ ANN("example: A::B ||= 1");
+ F_NODE(nd_head, "constant");
+ F_ID(nd_aid, "operator");
+ LAST_NODE;
+ F_NODE(nd_value, "rvalue");
+ return;
+
+ case NODE_CALL:
+ ANN("method invocation");
+ ANN("format: [nd_recv].[nd_mid]([nd_args])");
+ ANN("example: obj.foo(1)");
+ F_ID(nd_mid, "method id");
+ F_NODE(nd_recv, "receiver");
+ LAST_NODE;
+ F_NODE(nd_args, "arguments");
+ return;
+
+ case NODE_OPCALL:
+ ANN("method invocation");
+ ANN("format: [nd_recv] [nd_mid] [nd_args]");
+ ANN("example: foo + bar");
+ F_ID(nd_mid, "method id");
+ F_NODE(nd_recv, "receiver");
+ LAST_NODE;
+ F_NODE(nd_args, "arguments");
+ return;
+
+ case NODE_FCALL:
+ ANN("function call");
+ ANN("format: [nd_mid]([nd_args])");
+ ANN("example: foo(1)");
+ F_ID(nd_mid, "method id");
+ LAST_NODE;
+ F_NODE(nd_args, "arguments");
+ return;
+
+ case NODE_VCALL:
+ ANN("function call with no argument");
+ ANN("format: [nd_mid]");
+ ANN("example: foo");
+ F_ID(nd_mid, "method id");
+ return;
+
+ case NODE_QCALL:
+ ANN("safe method invocation");
+ ANN("format: [nd_recv]&.[nd_mid]([nd_args])");
+ ANN("example: obj&.foo(1)");
+ F_ID(nd_mid, "method id");
+ F_NODE(nd_recv, "receiver");
+ LAST_NODE;
+ F_NODE(nd_args, "arguments");
+ return;
+
+ case NODE_SUPER:
+ ANN("super invocation");
+ ANN("format: super [nd_args]");
+ ANN("example: super 1");
+ LAST_NODE;
+ F_NODE(nd_args, "arguments");
+ return;
+
+ case NODE_ZSUPER:
+ ANN("super invocation with no argument");
+ ANN("format: super");
+ ANN("example: super");
+ return;
+
+ case NODE_LIST:
+ ANN("list constructor");
+ ANN("format: [ [nd_head], [nd_next].. ] (length: [nd_alen])");
+ ANN("example: [1, 2, 3]");
+ goto ary;
+ case NODE_VALUES:
+ ANN("return arguments");
+ ANN("format: [ [nd_head], [nd_next].. ] (length: [nd_alen])");
+ ANN("example: return 1, 2, 3");
+ ary:
+ dump_array(buf, indent, comment, node);
+ return;
+
+ case NODE_ZLIST:
+ ANN("empty list constructor");
+ ANN("format: []");
+ ANN("example: []");
+ return;
+
+ case NODE_HASH:
+ if (!node->nd_brace) {
+ ANN("keyword arguments");
+ ANN("format: nd_head");
+ ANN("example: a: 1, b: 2");
+ }
+ else {
+ ANN("hash constructor");
+ ANN("format: { [nd_head] }");
+ ANN("example: { 1 => 2, 3 => 4 }");
+ }
+ F_CUSTOM1(nd_brace, "keyword arguments or hash literal") {
+ switch (node->nd_brace) {
+ case 0: A("0 (keyword argument)"); break;
+ case 1: A("1 (hash literal)"); break;
+ }
+ }
+ LAST_NODE;
+ F_NODE(nd_head, "contents");
+ return;
+
+ case NODE_YIELD:
+ ANN("yield invocation");
+ ANN("format: yield [nd_head]");
+ ANN("example: yield 1");
+ LAST_NODE;
+ F_NODE(nd_head, "arguments");
+ return;
+
+ case NODE_LVAR:
+ ANN("local variable reference");
+ ANN("format: [nd_vid](lvar)");
+ ANN("example: x");
+ F_ID(nd_vid, "local variable");
+ return;
+ case NODE_DVAR:
+ ANN("dynamic variable reference");
+ ANN("format: [nd_vid](dvar)");
+ ANN("example: 1.times { x = 1; x }");
+ F_ID(nd_vid, "local variable");
+ return;
+ case NODE_IVAR:
+ ANN("instance variable reference");
+ ANN("format: [nd_vid](ivar)");
+ ANN("example: @x");
+ F_ID(nd_vid, "instance variable");
+ return;
+ case NODE_CONST:
+ ANN("constant reference");
+ ANN("format: [nd_vid](constant)");
+ ANN("example: X");
+ F_ID(nd_vid, "constant");
+ return;
+ case NODE_CVAR:
+ ANN("class variable reference");
+ ANN("format: [nd_vid](cvar)");
+ ANN("example: @@x");
+ F_ID(nd_vid, "class variable");
+ return;
+
+ case NODE_GVAR:
+ ANN("global variable reference");
+ ANN("format: [nd_entry](gvar)");
+ ANN("example: $x");
+ F_GENTRY(nd_entry, "global variable");
+ return;
+
+ case NODE_NTH_REF:
+ ANN("nth special variable reference");
+ ANN("format: $[nd_nth]");
+ ANN("example: $1, $2, ..");
+ F_CUSTOM1(nd_nth, "variable") { A("$"); A_LONG(node->nd_nth); }
+ return;
+
+ case NODE_BACK_REF:
+ ANN("back special variable reference");
+ ANN("format: $[nd_nth]");
+ ANN("example: $&, $`, $', $+");
+ F_CUSTOM1(nd_nth, "variable") {
+ char name[3] = "$ ";
+ name[1] = (char)node->nd_nth;
+ A(name);
+ }
+ return;
+
+ case NODE_MATCH:
+ ANN("match expression (against $_ implicitly)");
+ ANN("format: [nd_lit] (in condition)");
+ ANN("example: if /foo/; foo; end");
+ F_LIT(nd_lit, "regexp");
+ return;
+
+ case NODE_MATCH2:
+ ANN("match expression (regexp first)");
+ ANN("format: [nd_recv] =~ [nd_value]");
+ ANN("example: /foo/ =~ 'foo'");
+ F_NODE(nd_recv, "regexp (receiver)");
+ if (!node->nd_args) LAST_NODE;
+ F_NODE(nd_value, "string (argument)");
+ if (node->nd_args) {
+ LAST_NODE;
+ F_NODE(nd_args, "named captures");
+ }
+ return;
+
+ case NODE_MATCH3:
+ ANN("match expression (regexp second)");
+ ANN("format: [nd_recv] =~ [nd_value]");
+ ANN("example: 'foo' =~ /foo/");
+ F_NODE(nd_recv, "string (receiver)");
+ LAST_NODE;
+ F_NODE(nd_value, "regexp (argument)");
+ return;
+
+ case NODE_LIT:
+ ANN("literal");
+ ANN("format: [nd_lit]");
+ ANN("example: 1, /foo/");
+ goto lit;
+ case NODE_STR:
+ ANN("string literal");
+ ANN("format: [nd_lit]");
+ ANN("example: 'foo'");
+ goto lit;
+ case NODE_XSTR:
+ ANN("xstring literal");
+ ANN("format: [nd_lit]");
+ ANN("example: `foo`");
+ lit:
+ F_LIT(nd_lit, "literal");
+ return;
+
+ case NODE_ONCE:
+ ANN("once evaluation");
+ ANN("format: [nd_body]");
+ ANN("example: /foo#{ bar }baz/o");
+ LAST_NODE;
+ F_NODE(nd_body, "body");
+ return;
+ case NODE_DSTR:
+ ANN("string literal with interpolation");
+ ANN("format: [nd_lit]");
+ ANN("example: \"foo#{ bar }baz\"");
+ goto dlit;
+ case NODE_DXSTR:
+ ANN("xstring literal with interpolation");
+ ANN("format: [nd_lit]");
+ ANN("example: `foo#{ bar }baz`");
+ goto dlit;
+ case NODE_DREGX:
+ ANN("regexp literal with interpolation");
+ ANN("format: [nd_lit]");
+ ANN("example: /foo#{ bar }baz/");
+ goto dlit;
+ case NODE_DSYM:
+ ANN("symbol literal with interpolation");
+ ANN("format: [nd_lit]");
+ ANN("example: :\"foo#{ bar }baz\"");
+ dlit:
+ F_LIT(nd_lit, "preceding string");
+ if (!node->nd_next) return;
+ F_NODE(nd_next->nd_head, "interpolation");
+ LAST_NODE;
+ F_NODE(nd_next->nd_next, "tailing strings");
+ return;
+
+ case NODE_EVSTR:
+ ANN("interpolation expression");
+ ANN("format: \"..#{ [nd_lit] }..\"");
+ ANN("example: \"foo#{ bar }baz\"");
+ LAST_NODE;
+ F_NODE(nd_body, "body");
+ return;
+
+ case NODE_ARGSCAT:
+ ANN("splat argument following arguments");
+ ANN("format: ..(*[nd_head], [nd_body..])");
+ ANN("example: foo(*ary, post_arg1, post_arg2)");
+ F_NODE(nd_head, "preceding array");
+ LAST_NODE;
+ F_NODE(nd_body, "following array");
+ return;
+
+ case NODE_ARGSPUSH:
+ ANN("splat argument following one argument");
+ ANN("format: ..(*[nd_head], [nd_body])");
+ ANN("example: foo(*ary, post_arg)");
+ F_NODE(nd_head, "preceding array");
+ LAST_NODE;
+ F_NODE(nd_body, "following element");
+ return;
+
+ case NODE_SPLAT:
+ ANN("splat argument");
+ ANN("format: *[nd_head]");
+ ANN("example: foo(*ary)");
+ LAST_NODE;
+ F_NODE(nd_head, "splat'ed array");
+ return;
+
+ case NODE_BLOCK_PASS:
+ ANN("arguments with block argument");
+ ANN("format: ..([nd_head], &[nd_body])");
+ ANN("example: foo(x, &blk)");
+ F_NODE(nd_head, "other arguments");
+ LAST_NODE;
+ F_NODE(nd_body, "block argument");
+ return;
+
+ case NODE_DEFN:
+ ANN("method definition");
+ ANN("format: def [nd_mid] [nd_defn]; end");
+ ANN("example: def foo; bar; end");
+ F_ID(nd_mid, "method name");
+ LAST_NODE;
+ F_NODE(nd_defn, "method definition");
+ return;
+
+ case NODE_DEFS:
+ ANN("singleton method definition");
+ ANN("format: def [nd_recv].[nd_mid] [nd_defn]; end");
+ ANN("example: def obj.foo; bar; end");
+ F_NODE(nd_recv, "receiver");
+ F_ID(nd_mid, "method name");
+ LAST_NODE;
+ F_NODE(nd_defn, "method definition");
+ return;
+
+ case NODE_ALIAS:
+ ANN("method alias statement");
+ ANN("format: alias [nd_1st] [nd_2nd]");
+ ANN("example: alias bar foo");
+ F_NODE(nd_1st, "new name");
+ LAST_NODE;
+ F_NODE(nd_2nd, "old name");
+ return;
+
+ case NODE_VALIAS:
+ ANN("global variable alias statement");
+ ANN("format: alias [nd_alias](gvar) [nd_orig](gvar)");
+ ANN("example: alias $y $x");
+ F_ID(nd_alias, "new name");
+ F_ID(nd_orig, "old name");
+ return;
+
+ case NODE_UNDEF:
+ ANN("method undef statement");
+ ANN("format: undef [nd_undef]");
+ ANN("example: undef foo");
+ LAST_NODE;
+ F_NODE(nd_undef, "old name");
+ return;
+
+ case NODE_CLASS:
+ ANN("class definition");
+ ANN("format: class [nd_cpath] < [nd_super]; [nd_body]; end");
+ ANN("example: class C2 < C; ..; end");
+ F_NODE(nd_cpath, "class path");
+ F_NODE(nd_super, "superclass");
+ LAST_NODE;
+ F_NODE(nd_body, "class definition");
+ return;
+
+ case NODE_MODULE:
+ ANN("module definition");
+ ANN("format: module [nd_cpath]; [nd_body]; end");
+ ANN("example: module M; ..; end");
+ F_NODE(nd_cpath, "module path");
+ LAST_NODE;
+ F_NODE(nd_body, "module definition");
+ return;
+
+ case NODE_SCLASS:
+ ANN("singleton class definition");
+ ANN("format: class << [nd_recv]; [nd_body]; end");
+ ANN("example: class << obj; ..; end");
+ F_NODE(nd_recv, "receiver");
+ LAST_NODE;
+ F_NODE(nd_body, "singleton class definition");
+ return;
+
+ case NODE_COLON2:
+ ANN("scoped constant reference");
+ ANN("format: [nd_head]::[nd_mid]");
+ ANN("example: M::C");
+ F_ID(nd_mid, "constant name");
+ LAST_NODE;
+ F_NODE(nd_head, "receiver");
+ return;
+
+ case NODE_COLON3:
+ ANN("top-level constant reference");
+ ANN("format: ::[nd_mid]");
+ ANN("example: ::Object");
+ F_ID(nd_mid, "constant name");
+ return;
+
+ case NODE_DOT2:
+ ANN("range constructor (incl.)");
+ ANN("format: [nd_beg]..[nd_end]");
+ ANN("example: 1..5");
+ goto dot;
+ case NODE_DOT3:
+ ANN("range constructor (excl.)");
+ ANN("format: [nd_beg]...[nd_end]");
+ ANN("example: 1...5");
+ goto dot;
+ case NODE_FLIP2:
+ ANN("flip-flop condition (incl.)");
+ ANN("format: [nd_beg]..[nd_end]");
+ ANN("example: if (x==1)..(x==5); foo; end");
+ goto dot;
+ case NODE_FLIP3:
+ ANN("flip-flop condition (excl.)");
+ ANN("format: [nd_beg]...[nd_end]");
+ ANN("example: if (x==1)...(x==5); foo; end");
+ dot:
+ F_NODE(nd_beg, "begin");
+ LAST_NODE;
+ F_NODE(nd_end, "end");
+ return;
+
+ case NODE_SELF:
+ ANN("self");
+ ANN("format: self");
+ ANN("example: self");
+ return;
+
+ case NODE_NIL:
+ ANN("nil");
+ ANN("format: nil");
+ ANN("example: nil");
+ return;
+
+ case NODE_TRUE:
+ ANN("true");
+ ANN("format: true");
+ ANN("example: true");
+ return;
+
+ case NODE_FALSE:
+ ANN("false");
+ ANN("format: false");
+ ANN("example: false");
+ return;
+
+ case NODE_ERRINFO:
+ ANN("virtual reference to $!");
+ ANN("format: rescue => id");
+ ANN("example: rescue => id");
+ return;
+
+ case NODE_DEFINED:
+ ANN("defined? expression");
+ ANN("format: defined?([nd_head])");
+ ANN("example: defined?(foo)");
+ F_NODE(nd_head, "expr");
+ return;
+
+ case NODE_POSTEXE:
+ ANN("post-execution");
+ ANN("format: END { [nd_body] }");
+ ANN("example: END { foo }");
+ LAST_NODE;
+ F_NODE(nd_body, "END clause");
+ return;
+
+ case NODE_ATTRASGN:
+ ANN("attr assignment");
+ ANN("format: [nd_recv].[nd_mid] = [nd_args]");
+ ANN("example: struct.field = foo");
+ F_NODE(nd_recv, "receiver");
+ F_ID(nd_mid, "method name");
+ LAST_NODE;
+ F_NODE(nd_args, "arguments");
+ return;
+
+ case NODE_LAMBDA:
+ ANN("lambda expression");
+ ANN("format: -> [nd_body]");
+ ANN("example: -> { foo }");
+ LAST_NODE;
+ F_NODE(nd_body, "lambda clause");
+ return;
+
+ case NODE_OPT_ARG:
+ ANN("optional arguments");
+ ANN("format: def method_name([nd_body=some], [nd_next..])");
+ ANN("example: def foo(a, b=1, c); end");
+ F_NODE(nd_body, "body");
+ LAST_NODE;
+ F_NODE(nd_next, "next");
+ return;
+
+ case NODE_KW_ARG:
+ ANN("keyword arguments");
+ ANN("format: def method_name([nd_body=some], [nd_next..])");
+ ANN("example: def foo(a:1, b:2); end");
+ F_NODE(nd_body, "body");
+ LAST_NODE;
+ F_NODE(nd_next, "next");
+ return;
+
+ case NODE_POSTARG:
+ ANN("post arguments");
+ ANN("format: *[nd_1st], [nd_2nd..] = ..");
+ ANN("example: a, *rest, z = foo");
+ if (NODE_NAMED_REST_P(node->nd_1st)) {
+ F_NODE(nd_1st, "rest argument");
+ }
+ else {
+ F_MSG(nd_1st, "rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
+ }
+ LAST_NODE;
+ F_NODE(nd_2nd, "post arguments");
+ return;
+
+ case NODE_ARGS:
+ ANN("method parameters");
+ ANN("format: def method_name(.., [nd_ainfo->nd_optargs], *[nd_ainfo->rest_arg], [nd_ainfo->first_post_arg], .., [nd_ainfo->kw_args], **[nd_ainfo->kw_rest_arg], &[nd_ainfo->block_arg])");
+ ANN("example: def foo(a, b, opt1=1, opt2=2, *rest, y, z, kw: 1, **kwrest, &blk); end");
+ F_INT(nd_ainfo->pre_args_num, "count of mandatory (pre-)arguments");
+ F_NODE(nd_ainfo->pre_init, "initialization of (pre-)arguments");
+ F_INT(nd_ainfo->post_args_num, "count of mandatory post-arguments");
+ F_NODE(nd_ainfo->post_init, "initialization of post-arguments");
+ F_ID(nd_ainfo->first_post_arg, "first post argument");
+ F_CUSTOM1(nd_ainfo->rest_arg, "rest argument") {
+ if (node->nd_ainfo->rest_arg == NODE_SPECIAL_EXCESSIVE_COMMA) {
+ A("1 (excessed comma)");
+ }
+ else {
+ A_ID(node->nd_ainfo->rest_arg);
+ }
+ }
+ F_ID(nd_ainfo->block_arg, "block argument");
+ F_NODE(nd_ainfo->opt_args, "optional arguments");
+ F_NODE(nd_ainfo->kw_args, "keyword arguments");
+ LAST_NODE;
+ F_NODE(nd_ainfo->kw_rest_arg, "keyword rest argument");
+ return;
+
+ case NODE_SCOPE:
+ ANN("new scope");
+ ANN("format: [nd_tbl]: local table, [nd_args]: arguments, [nd_body]: body");
+ F_CUSTOM1(nd_tbl, "local table") {
+ rb_ast_id_table_t *tbl = node->nd_tbl;
+ int i;
+ int size = tbl ? tbl->size : 0;
+ if (size == 0) A("(empty)");
+ for (i = 0; i < size; i++) {
+ A_ID(tbl->ids[i]); if (i < size - 1) A(",");
+ }
+ }
+ F_NODE(nd_args, "arguments");
+ LAST_NODE;
+ F_NODE(nd_body, "body");
+ return;
+
+ case NODE_ARYPTN:
+ ANN("array pattern");
+ ANN("format: [nd_pconst]([pre_args], ..., *[rest_arg], [post_args], ...)");
+ F_NODE(nd_pconst, "constant");
+ F_NODE(nd_apinfo->pre_args, "pre arguments");
+ if (NODE_NAMED_REST_P(node->nd_apinfo->rest_arg)) {
+ F_NODE(nd_apinfo->rest_arg, "rest argument");
+ }
+ else {
+ F_MSG(nd_apinfo->rest_arg, "rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
+ }
+ LAST_NODE;
+ F_NODE(nd_apinfo->post_args, "post arguments");
+ return;
+
+ case NODE_FNDPTN:
+ ANN("find pattern");
+ ANN("format: [nd_pconst](*[pre_rest_arg], args, ..., *[post_rest_arg])");
+ F_NODE(nd_pconst, "constant");
+ if (NODE_NAMED_REST_P(node->nd_fpinfo->pre_rest_arg)) {
+ F_NODE(nd_fpinfo->pre_rest_arg, "pre rest argument");
+ }
+ else {
+ F_MSG(nd_fpinfo->pre_rest_arg, "pre rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
+ }
+ F_NODE(nd_fpinfo->args, "arguments");
+
+ LAST_NODE;
+ if (NODE_NAMED_REST_P(node->nd_fpinfo->post_rest_arg)) {
+ F_NODE(nd_fpinfo->post_rest_arg, "post rest argument");
+ }
+ else {
+ F_MSG(nd_fpinfo->post_rest_arg, "post rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
+ }
+ return;
+
+ case NODE_HSHPTN:
+ ANN("hash pattern");
+ ANN("format: [nd_pconst]([nd_pkwargs], ..., **[nd_pkwrestarg])");
+ F_NODE(nd_pconst, "constant");
+ F_NODE(nd_pkwargs, "keyword arguments");
+ LAST_NODE;
+ if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
+ F_MSG(nd_pkwrestarg, "keyword rest argument", "NODE_SPECIAL_NO_REST_KEYWORD (**nil)");
+ }
+ else {
+ F_NODE(nd_pkwrestarg, "keyword rest argument");
+ }
+ return;
+ case NODE_ERROR:
+ ANN("Broken input recovered by Error Tolerant mode");
+ return;
+
+ case NODE_ARGS_AUX:
+ case NODE_LAST:
+ break;
+ }
+
+ rb_bug("dump_node: unknown node: %s", ruby_node_name(nd_type(node)));
}
-#ifdef UNIVERSAL_PARSER
-const char *
-ruby_node_name(int node)
+VALUE
+rb_parser_dump_tree(const NODE *node, int comment)
{
- return rb_node_name(node);
+ VALUE buf = rb_str_new_cstr(
+ "###########################################################\n"
+ "## Do NOT use this node dump for any purpose other than ##\n"
+ "## debug and research. Compatibility is not guaranteed. ##\n"
+ "###########################################################\n\n"
+ );
+ dump_node(buf, rb_str_new_cstr("# "), comment, node);
+ return buf;
}
-#else
-const char *
-ruby_node_name(int node)
+
+/* Setup NODE structure.
+ * NODE is not an object managed by GC, but it imitates an object
+ * so that it can work with `RB_TYPE_P(obj, T_NODE)`.
+ * This dirty hack is needed because Ripper jumbles NODEs and other type
+ * objects.
+ */
+void
+rb_node_init(NODE *n, enum node_type type, VALUE a0, VALUE a1, VALUE a2)
+{
+ n->flags = T_NODE;
+ nd_init_type(n, type);
+ n->u1.value = a0;
+ n->u2.value = a1;
+ n->u3.value = a2;
+ n->nd_loc.beg_pos.lineno = 0;
+ n->nd_loc.beg_pos.column = 0;
+ n->nd_loc.end_pos.lineno = 0;
+ n->nd_loc.end_pos.column = 0;
+ n->node_id = -1;
+}
+
+typedef struct node_buffer_elem_struct {
+ struct node_buffer_elem_struct *next;
+ long len;
+ NODE buf[FLEX_ARY_LEN];
+} node_buffer_elem_t;
+
+typedef struct {
+ long idx, len;
+ node_buffer_elem_t *head;
+ node_buffer_elem_t *last;
+} node_buffer_list_t;
+
+struct node_buffer_struct {
+ node_buffer_list_t unmarkable;
+ node_buffer_list_t markable;
+ struct rb_ast_local_table_link *local_tables;
+ VALUE mark_hash;
+ // - id (sequence number)
+ // - token_type
+ // - text of token
+ // - location info
+ // Array, whose entry is array
+ VALUE tokens;
+};
+
+static void
+init_node_buffer_list(node_buffer_list_t * nb, node_buffer_elem_t *head)
{
- const char *name = rb_node_name(node);
+ nb->idx = 0;
+ nb->len = NODE_BUF_DEFAULT_LEN;
+ nb->head = nb->last = head;
+ nb->head->len = nb->len;
+ nb->head->next = NULL;
+}
- if (!name) rb_bug("unknown node: %d", node);
- return name;
+static node_buffer_t *
+rb_node_buffer_new(void)
+{
+ const size_t bucket_size = offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_LEN * sizeof(NODE);
+ const size_t alloc_size = sizeof(node_buffer_t) + (bucket_size * 2);
+ STATIC_ASSERT(
+ integer_overflow,
+ offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_LEN * sizeof(NODE)
+ > sizeof(node_buffer_t) + 2 * sizeof(node_buffer_elem_t));
+ node_buffer_t *nb = ruby_xmalloc(alloc_size);
+ init_node_buffer_list(&nb->unmarkable, (node_buffer_elem_t*)&nb[1]);
+ init_node_buffer_list(&nb->markable, (node_buffer_elem_t*)((size_t)nb->unmarkable.head + bucket_size));
+ nb->local_tables = 0;
+ nb->mark_hash = Qnil;
+ nb->tokens = Qnil;
+ return nb;
}
-#endif
static void
-node_buffer_list_free(rb_ast_t *ast, node_buffer_list_t * nb)
+node_buffer_list_free(node_buffer_list_t * nb)
{
node_buffer_elem_t *nbe = nb->head;
+
while (nbe != nb->last) {
void *buf = nbe;
- xfree(nbe->nodes);
nbe = nbe->next;
xfree(buf);
}
-
- /* The last node_buffer_elem_t is allocated in the node_buffer_t, so we
- * only need to free the nodes. */
- xfree(nbe->nodes);
}
struct rb_ast_local_table_link {
@@ -137,99 +1218,10 @@ struct rb_ast_local_table_link {
};
static void
-parser_string_free(rb_ast_t *ast, rb_parser_string_t *str)
-{
- if (!str) return;
- xfree(str->ptr);
- xfree(str);
-}
-
-static void
-parser_ast_token_free(rb_ast_t *ast, rb_parser_ast_token_t *token)
-{
- if (!token) return;
- parser_string_free(ast, token->str);
- xfree(token);
-}
-
-static void
-parser_tokens_free(rb_ast_t *ast, rb_parser_ary_t *tokens)
-{
- for (long i = 0; i < tokens->len; i++) {
- parser_ast_token_free(ast, tokens->data[i]);
- }
- xfree(tokens->data);
- xfree(tokens);
-}
-
-static void
-parser_nodes_free(rb_ast_t *ast, rb_parser_ary_t *nodes)
-{
- /* Do nothing for nodes because nodes are freed when rb_ast_t is freed */
- xfree(nodes->data);
- xfree(nodes);
-}
-
-static void
-free_ast_value(rb_ast_t *ast, void *ctx, NODE *node)
+rb_node_buffer_free(node_buffer_t *nb)
{
- switch (nd_type(node)) {
- case NODE_STR:
- parser_string_free(ast, RNODE_STR(node)->string);
- break;
- case NODE_DSTR:
- parser_string_free(ast, RNODE_DSTR(node)->string);
- break;
- case NODE_XSTR:
- parser_string_free(ast, RNODE_XSTR(node)->string);
- break;
- case NODE_DXSTR:
- parser_string_free(ast, RNODE_DXSTR(node)->string);
- break;
- case NODE_SYM:
- parser_string_free(ast, RNODE_SYM(node)->string);
- break;
- case NODE_REGX:
- case NODE_MATCH:
- parser_string_free(ast, RNODE_REGX(node)->string);
- break;
- case NODE_DSYM:
- parser_string_free(ast, RNODE_DSYM(node)->string);
- break;
- case NODE_DREGX:
- parser_string_free(ast, RNODE_DREGX(node)->string);
- break;
- case NODE_FILE:
- parser_string_free(ast, RNODE_FILE(node)->path);
- break;
- case NODE_INTEGER:
- xfree(RNODE_INTEGER(node)->val);
- break;
- case NODE_FLOAT:
- xfree(RNODE_FLOAT(node)->val);
- break;
- case NODE_RATIONAL:
- xfree(RNODE_RATIONAL(node)->val);
- break;
- case NODE_IMAGINARY:
- xfree(RNODE_IMAGINARY(node)->val);
- break;
- case NODE_UNDEF:
- parser_nodes_free(ast, RNODE_UNDEF(node)->nd_undefs);
- break;
- default:
- break;
- }
-}
-
-static void
-rb_node_buffer_free(rb_ast_t *ast, node_buffer_t *nb)
-{
- if (nb && nb->tokens) {
- parser_tokens_free(ast, nb->tokens);
- }
- iterate_node_values(ast, &nb->buffer_list, free_ast_value, NULL);
- node_buffer_list_free(ast, &nb->buffer_list);
+ node_buffer_list_free(&nb->unmarkable);
+ node_buffer_list_free(&nb->markable);
struct rb_ast_local_table_link *local_table = nb->local_tables;
while (local_table) {
struct rb_ast_local_table_link *next_table = local_table->next;
@@ -239,39 +1231,61 @@ rb_node_buffer_free(rb_ast_t *ast, node_buffer_t *nb)
xfree(nb);
}
-#define buf_add_offset(nbe, offset) ((char *)(nbe->buf) + (offset))
-
static NODE *
-ast_newnode_in_bucket(rb_ast_t *ast, node_buffer_list_t *nb, size_t size, size_t alignment)
+ast_newnode_in_bucket(node_buffer_list_t *nb)
{
- size_t padding;
- NODE *ptr;
-
- padding = alignment - (size_t)buf_add_offset(nb->head, nb->head->used) % alignment;
- padding = padding == alignment ? 0 : padding;
-
- if (nb->head->used + size + padding > nb->head->allocated) {
- size_t n = nb->head->allocated * 2;
+ if (nb->idx >= nb->len) {
+ long n = nb->len * 2;
node_buffer_elem_t *nbe;
- nbe = rb_xmalloc_mul_add(n, sizeof(char *), offsetof(node_buffer_elem_t, buf));
- init_node_buffer_elem(nbe, n, ruby_xmalloc);
+ nbe = rb_xmalloc_mul_add(n, sizeof(NODE), offsetof(node_buffer_elem_t, buf));
+ nbe->len = n;
+ nb->idx = 0;
+ nb->len = n;
nbe->next = nb->head;
nb->head = nbe;
- padding = 0; /* malloc returns aligned address then no need to add padding */
}
+ return &nb->head->buf[nb->idx++];
+}
- ptr = (NODE *)buf_add_offset(nb->head, nb->head->used + padding);
- nb->head->used += (size + padding);
- nb->head->nodes[nb->head->len++] = ptr;
- return ptr;
+RBIMPL_ATTR_PURE()
+static bool
+nodetype_markable_p(enum node_type type)
+{
+ switch (type) {
+ case NODE_MATCH:
+ case NODE_LIT:
+ case NODE_STR:
+ case NODE_XSTR:
+ case NODE_DSTR:
+ case NODE_DXSTR:
+ case NODE_DREGX:
+ case NODE_DSYM:
+ case NODE_ARGS:
+ case NODE_ARYPTN:
+ case NODE_FNDPTN:
+ return true;
+ default:
+ return false;
+ }
}
NODE *
-rb_ast_newnode(rb_ast_t *ast, enum node_type type, size_t size, size_t alignment)
+rb_ast_newnode(rb_ast_t *ast, enum node_type type)
{
node_buffer_t *nb = ast->node_buffer;
- node_buffer_list_t *bucket = &nb->buffer_list;
- return ast_newnode_in_bucket(ast, bucket, size, alignment);
+ node_buffer_list_t *bucket =
+ (nodetype_markable_p(type) ? &nb->markable : &nb->unmarkable);
+ return ast_newnode_in_bucket(bucket);
+}
+
+void
+rb_ast_node_type_change(NODE *n, enum node_type type)
+{
+ enum node_type old_type = nd_type(n);
+ if (nodetype_markable_p(old_type) != nodetype_markable_p(type)) {
+ rb_bug("node type changed: %s -> %s",
+ ruby_node_name(old_type), ruby_node_name(type));
+ }
}
rb_ast_id_table_t *
@@ -306,63 +1320,131 @@ rb_ast_delete_node(rb_ast_t *ast, NODE *n)
/* should we implement freelist? */
}
-#ifdef UNIVERSAL_PARSER
-rb_ast_t *
-rb_ast_new(const rb_parser_config_t *config)
-{
- node_buffer_t *nb = rb_node_buffer_new(config);
- rb_ast_t *ast = (rb_ast_t *)config->calloc(1, sizeof(rb_ast_t));
- ast->config = config;
- ast->node_buffer = nb;
- return ast;
-}
-#else
rb_ast_t *
rb_ast_new(void)
{
node_buffer_t *nb = rb_node_buffer_new();
- rb_ast_t *ast = ruby_xcalloc(1, sizeof(rb_ast_t));
- ast->node_buffer = nb;
+ rb_ast_t *ast = (rb_ast_t *)rb_imemo_new(imemo_ast, 0, 0, 0, (VALUE)nb);
return ast;
}
-#endif
+
+typedef void node_itr_t(void *ctx, NODE * node);
static void
-iterate_buffer_elements(rb_ast_t *ast, node_buffer_elem_t *nbe, long len, node_itr_t *func, void *ctx)
+iterate_buffer_elements(node_buffer_elem_t *nbe, long len, node_itr_t *func, void *ctx)
{
long cursor;
for (cursor = 0; cursor < len; cursor++) {
- func(ast, ctx, nbe->nodes[cursor]);
+ func(ctx, &nbe->buf[cursor]);
}
}
static void
-iterate_node_values(rb_ast_t *ast, node_buffer_list_t *nb, node_itr_t * func, void *ctx)
+iterate_node_values(node_buffer_list_t *nb, node_itr_t * func, void *ctx)
{
node_buffer_elem_t *nbe = nb->head;
+ /* iterate over the head first because it's not full */
+ iterate_buffer_elements(nbe, nb->idx, func, ctx);
+
+ nbe = nbe->next;
while (nbe) {
- iterate_buffer_elements(ast, nbe, nbe->len, func, ctx);
+ iterate_buffer_elements(nbe, nbe->len, func, ctx);
nbe = nbe->next;
}
}
static void
-script_lines_free(rb_ast_t *ast, rb_parser_ary_t *script_lines)
+mark_ast_value(void *ctx, NODE * node)
+{
+ switch (nd_type(node)) {
+ case NODE_ARGS:
+ {
+ struct rb_args_info *args = node->nd_ainfo;
+ rb_gc_mark_movable(args->imemo);
+ break;
+ }
+ case NODE_MATCH:
+ case NODE_LIT:
+ case NODE_STR:
+ case NODE_XSTR:
+ case NODE_DSTR:
+ case NODE_DXSTR:
+ case NODE_DREGX:
+ case NODE_DSYM:
+ rb_gc_mark_movable(node->nd_lit);
+ break;
+ case NODE_ARYPTN:
+ case NODE_FNDPTN:
+ rb_gc_mark_movable(node->nd_rval);
+ break;
+ default:
+ rb_bug("unreachable node %s", ruby_node_name(nd_type(node)));
+ }
+}
+
+static void
+update_ast_value(void *ctx, NODE * node)
+{
+ switch (nd_type(node)) {
+ case NODE_ARGS:
+ {
+ struct rb_args_info *args = node->nd_ainfo;
+ args->imemo = rb_gc_location(args->imemo);
+ break;
+ }
+ case NODE_MATCH:
+ case NODE_LIT:
+ case NODE_STR:
+ case NODE_XSTR:
+ case NODE_DSTR:
+ case NODE_DXSTR:
+ case NODE_DREGX:
+ case NODE_DSYM:
+ node->nd_lit = rb_gc_location(node->nd_lit);
+ break;
+ case NODE_ARYPTN:
+ case NODE_FNDPTN:
+ node->nd_rval = rb_gc_location(node->nd_rval);
+ break;
+ default:
+ rb_bug("unreachable");
+ }
+}
+
+void
+rb_ast_update_references(rb_ast_t *ast)
{
- if (!script_lines) return;
- for (long i = 0; i < script_lines->len; i++) {
- parser_string_free(ast, (rb_parser_string_t *)script_lines->data[i]);
+ if (ast->node_buffer) {
+ node_buffer_t *nb = ast->node_buffer;
+
+ iterate_node_values(&nb->markable, update_ast_value, NULL);
+ }
+}
+
+void
+rb_ast_mark(rb_ast_t *ast)
+{
+ if (ast->node_buffer) {
+ rb_gc_mark(ast->node_buffer->mark_hash);
+ rb_gc_mark(ast->node_buffer->tokens);
+ }
+ if (ast->body.compile_option) rb_gc_mark(ast->body.compile_option);
+ if (ast->node_buffer) {
+ node_buffer_t *nb = ast->node_buffer;
+
+ iterate_node_values(&nb->markable, mark_ast_value, NULL);
}
- xfree(script_lines->data);
- xfree(script_lines);
+ if (ast->body.script_lines) rb_gc_mark(ast->body.script_lines);
}
void
rb_ast_free(rb_ast_t *ast)
{
- rb_ast_dispose(ast);
- xfree(ast);
+ if (ast->node_buffer) {
+ rb_node_buffer_free(ast->node_buffer);
+ ast->node_buffer = 0;
+ }
}
static size_t
@@ -371,8 +1453,8 @@ buffer_list_size(node_buffer_list_t *nb)
size_t size = 0;
node_buffer_elem_t *nbe = nb->head;
while (nbe != nb->last) {
- size += offsetof(node_buffer_elem_t, buf) + nbe->used;
nbe = nbe->next;
+ size += offsetof(node_buffer_elem_t, buf) + nb->len * sizeof(NODE);
}
return size;
}
@@ -380,61 +1462,40 @@ buffer_list_size(node_buffer_list_t *nb)
size_t
rb_ast_memsize(const rb_ast_t *ast)
{
- size_t size = sizeof(rb_ast_t);
+ size_t size = 0;
node_buffer_t *nb = ast->node_buffer;
- rb_parser_ary_t *tokens = NULL;
- struct rb_ast_local_table_link *link = NULL;
- rb_parser_ary_t *script_lines = ast->body.script_lines;
-
- long i;
if (nb) {
- size += sizeof(node_buffer_t);
- size += buffer_list_size(&nb->buffer_list);
- link = nb->local_tables;
- tokens = nb->tokens;
- }
-
- while (link) {
- size += sizeof(struct rb_ast_local_table_link);
- size += link->size * sizeof(ID);
- link = link->next;
- }
-
- if (tokens) {
- size += sizeof(rb_parser_ary_t);
- for (i = 0; i < tokens->len; i++) {
- size += sizeof(rb_parser_ast_token_t);
- rb_parser_ast_token_t *token = tokens->data[i];
- size += sizeof(rb_parser_string_t);
- size += token->str->len + 1;
- }
- }
-
- if (script_lines) {
- size += sizeof(rb_parser_ary_t);
- for (i = 0; i < script_lines->len; i++) {
- size += sizeof(rb_parser_string_t);
- size += ((rb_parser_string_t *)script_lines->data[i])->len + 1;
- }
+ size += sizeof(node_buffer_t) + offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_LEN * sizeof(NODE);
+ size += buffer_list_size(&nb->unmarkable);
+ size += buffer_list_size(&nb->markable);
}
-
return size;
}
void
rb_ast_dispose(rb_ast_t *ast)
{
- if (ast && ast->node_buffer) {
- script_lines_free(ast, ast->body.script_lines);
- ast->body.script_lines = NULL;
- rb_node_buffer_free(ast, ast->node_buffer);
- ast->node_buffer = 0;
+ rb_ast_free(ast);
+}
+
+void
+rb_ast_add_mark_object(rb_ast_t *ast, VALUE obj)
+{
+ if (NIL_P(ast->node_buffer->mark_hash)) {
+ RB_OBJ_WRITE(ast, &ast->node_buffer->mark_hash, rb_ident_hash_new());
}
+ rb_hash_aset(ast->node_buffer->mark_hash, obj, Qtrue);
}
VALUE
-rb_node_set_type(NODE *n, enum node_type t)
+rb_ast_tokens(rb_ast_t *ast)
+{
+ return ast->node_buffer->tokens;
+}
+
+void
+rb_ast_set_tokens(rb_ast_t *ast, VALUE tokens)
{
- return nd_init_type(n, t);
+ RB_OBJ_WRITE(ast, &ast->node_buffer->tokens, tokens);
}
diff --git a/node.h b/node.h
index 1e411f211b..befb1328fb 100644
--- a/node.h
+++ b/node.h
@@ -11,101 +11,504 @@
**********************************************************************/
-#include <stdbool.h>
-#include "rubyparser.h"
-#include "ruby/backward/2/attributes.h"
-
-typedef void (*bug_report_func)(const char *fmt, ...) RUBYPARSER_ATTRIBUTE_FORMAT(1, 2);
-typedef struct node_buffer_elem_struct {
- struct node_buffer_elem_struct *next;
- long len; /* Length of nodes */
- size_t allocated; /* Total memory size of allocated buf */
- size_t used; /* Current usage of buf */
- NODE **nodes; /* Array of node pointers */
- NODE *buf[FLEX_ARY_LEN];
-} node_buffer_elem_t;
-
-typedef struct {
- node_buffer_elem_t *head;
- node_buffer_elem_t *last;
-} node_buffer_list_t;
-
-struct node_buffer_struct {
- node_buffer_list_t buffer_list;
- struct rb_ast_local_table_link *local_tables;
- // - id (sequence number)
- // - token_type
- // - text of token
- // - location info
- // Array, whose entry is array
- rb_parser_ary_t *tokens;
+#include "internal/compilers.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#if 0
+} /* satisfy cc-mode */
+#endif
+#endif
+
+enum node_type {
+ NODE_SCOPE,
+ NODE_BLOCK,
+ NODE_IF,
+ NODE_UNLESS,
+ NODE_CASE,
+ NODE_CASE2,
+ NODE_CASE3,
+ NODE_WHEN,
+ NODE_IN,
+ NODE_WHILE,
+ NODE_UNTIL,
+ NODE_ITER,
+ NODE_FOR,
+ NODE_FOR_MASGN,
+ NODE_BREAK,
+ NODE_NEXT,
+ NODE_REDO,
+ NODE_RETRY,
+ NODE_BEGIN,
+ NODE_RESCUE,
+ NODE_RESBODY,
+ NODE_ENSURE,
+ NODE_AND,
+ NODE_OR,
+ NODE_MASGN,
+ NODE_LASGN,
+ NODE_DASGN,
+ NODE_GASGN,
+ NODE_IASGN,
+ NODE_CDECL,
+ NODE_CVASGN,
+ NODE_OP_ASGN1,
+ NODE_OP_ASGN2,
+ NODE_OP_ASGN_AND,
+ NODE_OP_ASGN_OR,
+ NODE_OP_CDECL,
+ NODE_CALL,
+ NODE_OPCALL,
+ NODE_FCALL,
+ NODE_VCALL,
+ NODE_QCALL,
+ NODE_SUPER,
+ NODE_ZSUPER,
+ NODE_LIST,
+ NODE_ZLIST,
+ NODE_VALUES,
+ NODE_HASH,
+ NODE_RETURN,
+ NODE_YIELD,
+ NODE_LVAR,
+ NODE_DVAR,
+ NODE_GVAR,
+ NODE_IVAR,
+ NODE_CONST,
+ NODE_CVAR,
+ NODE_NTH_REF,
+ NODE_BACK_REF,
+ NODE_MATCH,
+ NODE_MATCH2,
+ NODE_MATCH3,
+ NODE_LIT,
+ NODE_STR,
+ NODE_DSTR,
+ NODE_XSTR,
+ NODE_DXSTR,
+ NODE_EVSTR,
+ NODE_DREGX,
+ NODE_ONCE,
+ NODE_ARGS,
+ NODE_ARGS_AUX,
+ NODE_OPT_ARG,
+ NODE_KW_ARG,
+ NODE_POSTARG,
+ NODE_ARGSCAT,
+ NODE_ARGSPUSH,
+ NODE_SPLAT,
+ NODE_BLOCK_PASS,
+ NODE_DEFN,
+ NODE_DEFS,
+ NODE_ALIAS,
+ NODE_VALIAS,
+ NODE_UNDEF,
+ NODE_CLASS,
+ NODE_MODULE,
+ NODE_SCLASS,
+ NODE_COLON2,
+ NODE_COLON3,
+ NODE_DOT2,
+ NODE_DOT3,
+ NODE_FLIP2,
+ NODE_FLIP3,
+ NODE_SELF,
+ NODE_NIL,
+ NODE_TRUE,
+ NODE_FALSE,
+ NODE_ERRINFO,
+ NODE_DEFINED,
+ NODE_POSTEXE,
+ NODE_DSYM,
+ NODE_ATTRASGN,
+ NODE_LAMBDA,
+ NODE_ARYPTN,
+ NODE_HSHPTN,
+ NODE_FNDPTN,
+ NODE_ERROR,
+ NODE_LAST
};
-RUBY_SYMBOL_EXPORT_BEGIN
+typedef struct rb_code_position_struct {
+ int lineno;
+ int column;
+} rb_code_position_t;
-#ifdef UNIVERSAL_PARSER
-rb_ast_t *rb_ast_new(const rb_parser_config_t *config);
-#else
-rb_ast_t *rb_ast_new(void);
-#endif
-size_t rb_ast_memsize(const rb_ast_t*);
-void rb_ast_dispose(rb_ast_t*);
-const char *ruby_node_name(int node);
-void rb_node_init(NODE *n, enum node_type type);
+typedef struct rb_code_location_struct {
+ rb_code_position_t beg_pos;
+ rb_code_position_t end_pos;
+} rb_code_location_t;
-void rb_ast_update_references(rb_ast_t*);
-void rb_ast_free(rb_ast_t*);
-NODE *rb_ast_newnode(rb_ast_t*, enum node_type type, size_t size, size_t alignment);
-void rb_ast_delete_node(rb_ast_t*, NODE *n);
-rb_ast_id_table_t *rb_ast_new_local_table(rb_ast_t*, int);
-rb_ast_id_table_t *rb_ast_resize_latest_local_table(rb_ast_t*, int);
+static inline rb_code_location_t
+code_loc_gen(const rb_code_location_t *loc1, const rb_code_location_t *loc2)
+{
+ rb_code_location_t loc;
+ loc.beg_pos = loc1->beg_pos;
+ loc.end_pos = loc2->end_pos;
+ return loc;
+}
-VALUE rb_parser_dump_tree(const NODE *node, int comment);
+typedef struct rb_ast_id_table {
+ int size;
+ ID ids[FLEX_ARY_LEN];
+} rb_ast_id_table_t;
-const struct kwtable *rb_reserved_word(const char *, unsigned int);
+typedef struct RNode {
+ VALUE flags;
+ union {
+ struct RNode *node;
+ ID id;
+ VALUE value;
+ rb_ast_id_table_t *tbl;
+ } u1;
+ union {
+ struct RNode *node;
+ ID id;
+ long argc;
+ VALUE value;
+ } u2;
+ union {
+ struct RNode *node;
+ ID id;
+ long state;
+ struct rb_args_info *args;
+ struct rb_ary_pattern_info *apinfo;
+ struct rb_fnd_pattern_info *fpinfo;
+ VALUE value;
+ } u3;
+ rb_code_location_t nd_loc;
+ int node_id;
+} NODE;
-struct parser_params;
-PRINTF_ARGS(void rb_parser_printf(struct parser_params *parser, const char *fmt, ...), 2, 3);
-VALUE rb_node_set_type(NODE *n, enum node_type t);
+#define RNODE(obj) ((struct RNode *)(obj))
-RUBY_SYMBOL_EXPORT_END
+/* FL : 0..4: T_TYPES, 5: KEEP_WB, 6: PROMOTED, 7: FINALIZE, 8: UNUSED, 9: UNUSED, 10: EXIVAR, 11: FREEZE */
+/* NODE_FL: 0..4: T_TYPES, 5: KEEP_WB, 6: PROMOTED, 7: NODE_FL_NEWLINE,
+ * 8..14: nd_type,
+ * 15..: nd_line
+ */
+#define NODE_FL_NEWLINE (((VALUE)1)<<7)
+
+#define NODE_TYPESHIFT 8
+#define NODE_TYPEMASK (((VALUE)0x7f)<<NODE_TYPESHIFT)
+
+#define nd_type(n) ((int) (((n)->flags & NODE_TYPEMASK)>>NODE_TYPESHIFT))
+#define nd_set_type(n,t) \
+ rb_node_set_type(n, t)
+#define nd_init_type(n,t) \
+ (n)->flags=(((n)->flags&~NODE_TYPEMASK)|((((unsigned long)(t))<<NODE_TYPESHIFT)&NODE_TYPEMASK))
#define NODE_LSHIFT (NODE_TYPESHIFT+7)
#define NODE_LMASK (((SIGNED_VALUE)1<<(sizeof(VALUE)*CHAR_BIT-NODE_LSHIFT))-1)
-
#define nd_line(n) (int)(((SIGNED_VALUE)(n)->flags)>>NODE_LSHIFT)
#define nd_set_line(n,l) \
(n)->flags=(((n)->flags&~((VALUE)(-1)<<NODE_LSHIFT))|((VALUE)((l)&NODE_LMASK)<<NODE_LSHIFT))
+#define nd_first_column(n) ((int)((n)->nd_loc.beg_pos.column))
+#define nd_set_first_column(n, v) ((n)->nd_loc.beg_pos.column = (v))
+#define nd_first_lineno(n) ((int)((n)->nd_loc.beg_pos.lineno))
+#define nd_set_first_lineno(n, v) ((n)->nd_loc.beg_pos.lineno = (v))
+#define nd_first_loc(n) ((n)->nd_loc.beg_pos)
+#define nd_set_first_loc(n, v) (nd_first_loc(n) = (v))
+
+#define nd_last_column(n) ((int)((n)->nd_loc.end_pos.column))
+#define nd_set_last_column(n, v) ((n)->nd_loc.end_pos.column = (v))
+#define nd_last_lineno(n) ((int)((n)->nd_loc.end_pos.lineno))
+#define nd_set_last_lineno(n, v) ((n)->nd_loc.end_pos.lineno = (v))
+#define nd_last_loc(n) ((n)->nd_loc.end_pos)
+#define nd_set_last_loc(n, v) (nd_last_loc(n) = (v))
+#define nd_node_id(n) ((n)->node_id)
+#define nd_set_node_id(n,id) ((n)->node_id = (id))
+
+#define nd_head u1.node
+#define nd_alen u2.argc
+#define nd_next u3.node
+
+#define nd_cond u1.node
+#define nd_body u2.node
+#define nd_else u3.node
+
+#define nd_resq u2.node
+#define nd_ensr u3.node
+
+#define nd_1st u1.node
+#define nd_2nd u2.node
+
+#define nd_stts u1.node
+
+#define nd_entry u3.id
+#define nd_vid u1.id
+
+#define nd_var u1.node
+#define nd_iter u3.node
+
+#define nd_value u2.node
+#define nd_aid u3.id
+
+#define nd_lit u1.value
+
+#define nd_recv u1.node
+#define nd_mid u2.id
+#define nd_args u3.node
+#define nd_ainfo u3.args
+
+#define nd_defn u3.node
+
+#define nd_cpath u1.node
+#define nd_super u3.node
+
+#define nd_beg u1.node
+#define nd_end u2.node
+#define nd_state u3.state
+
+#define nd_nth u2.argc
+
+#define nd_alias u1.id
+#define nd_orig u2.id
+#define nd_undef u2.node
+
+#define nd_brace u2.argc
+
+#define nd_pconst u1.node
+#define nd_pkwargs u2.node
+#define nd_pkwrestarg u3.node
+
+#define nd_apinfo u3.apinfo
+
+#define nd_fpinfo u3.fpinfo
+
+// for NODE_SCOPE
+#define nd_tbl u1.tbl
+
+// for NODE_ARGS_AUX
+#define nd_pid u1.id
+#define nd_plen u2.argc
+#define nd_cflag u2.id
+
+// for ripper
+#define nd_cval u3.value
+#define nd_rval u2.value
+#define nd_tag u1.id
+
+#define NEW_NODE(t,a0,a1,a2,loc) rb_node_newnode((t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2),loc)
+#define NEW_NODE_WITH_LOCALS(t,a1,a2,loc) node_newnode_with_locals(p, (t),(VALUE)(a1),(VALUE)(a2),loc)
+
+#define NEW_DEFN(i,a,d,loc) NEW_NODE(NODE_DEFN,0,i,NEW_SCOPE(a,d,loc),loc)
+#define NEW_DEFS(r,i,a,d,loc) NEW_NODE(NODE_DEFS,r,i,NEW_SCOPE(a,d,loc),loc)
+#define NEW_SCOPE(a,b,loc) NEW_NODE_WITH_LOCALS(NODE_SCOPE,b,a,loc)
+#define NEW_BLOCK(a,loc) NEW_NODE(NODE_BLOCK,a,0,0,loc)
+#define NEW_IF(c,t,e,loc) NEW_NODE(NODE_IF,c,t,e,loc)
+#define NEW_UNLESS(c,t,e,loc) NEW_NODE(NODE_UNLESS,c,t,e,loc)
+#define NEW_CASE(h,b,loc) NEW_NODE(NODE_CASE,h,b,0,loc)
+#define NEW_CASE2(b,loc) NEW_NODE(NODE_CASE2,0,b,0,loc)
+#define NEW_CASE3(h,b,loc) NEW_NODE(NODE_CASE3,h,b,0,loc)
+#define NEW_WHEN(c,t,e,loc) NEW_NODE(NODE_WHEN,c,t,e,loc)
+#define NEW_IN(c,t,e,loc) NEW_NODE(NODE_IN,c,t,e,loc)
+#define NEW_WHILE(c,b,n,loc) NEW_NODE(NODE_WHILE,c,b,n,loc)
+#define NEW_UNTIL(c,b,n,loc) NEW_NODE(NODE_UNTIL,c,b,n,loc)
+#define NEW_FOR(i,b,loc) NEW_NODE(NODE_FOR,0,b,i,loc)
+#define NEW_FOR_MASGN(v,loc) NEW_NODE(NODE_FOR_MASGN,v,0,0,loc)
+#define NEW_ITER(a,b,loc) NEW_NODE(NODE_ITER,0,NEW_SCOPE(a,b,loc),0,loc)
+#define NEW_LAMBDA(a,b,loc) NEW_NODE(NODE_LAMBDA,0,NEW_SCOPE(a,b,loc),0,loc)
+#define NEW_BREAK(s,loc) NEW_NODE(NODE_BREAK,s,0,0,loc)
+#define NEW_NEXT(s,loc) NEW_NODE(NODE_NEXT,s,0,0,loc)
+#define NEW_REDO(loc) NEW_NODE(NODE_REDO,0,0,0,loc)
+#define NEW_RETRY(loc) NEW_NODE(NODE_RETRY,0,0,0,loc)
+#define NEW_BEGIN(b,loc) NEW_NODE(NODE_BEGIN,0,b,0,loc)
+#define NEW_RESCUE(b,res,e,loc) NEW_NODE(NODE_RESCUE,b,res,e,loc)
+#define NEW_RESBODY(a,ex,n,loc) NEW_NODE(NODE_RESBODY,n,ex,a,loc)
+#define NEW_ENSURE(b,en,loc) NEW_NODE(NODE_ENSURE,b,0,en,loc)
+#define NEW_RETURN(s,loc) NEW_NODE(NODE_RETURN,s,0,0,loc)
+#define NEW_YIELD(a,loc) NEW_NODE(NODE_YIELD,a,0,0,loc)
+#define NEW_LIST(a,loc) NEW_NODE(NODE_LIST,a,1,0,loc)
+#define NEW_ZLIST(loc) NEW_NODE(NODE_ZLIST,0,0,0,loc)
+#define NEW_HASH(a,loc) NEW_NODE(NODE_HASH,a,0,0,loc)
+#define NEW_MASGN(l,r,loc) NEW_NODE(NODE_MASGN,l,0,r,loc)
+#define NEW_GASGN(v,val,loc) NEW_NODE(NODE_GASGN,v,val,v,loc)
+#define NEW_LASGN(v,val,loc) NEW_NODE(NODE_LASGN,v,val,0,loc)
+#define NEW_DASGN(v,val,loc) NEW_NODE(NODE_DASGN,v,val,0,loc)
+#define NEW_IASGN(v,val,loc) NEW_NODE(NODE_IASGN,v,val,0,loc)
+#define NEW_CDECL(v,val,path,loc) NEW_NODE(NODE_CDECL,v,val,path,loc)
+#define NEW_CVASGN(v,val,loc) NEW_NODE(NODE_CVASGN,v,val,0,loc)
+#define NEW_OP_ASGN1(p,id,a,loc) NEW_NODE(NODE_OP_ASGN1,p,id,a,loc)
+#define NEW_OP_ASGN2(r,t,i,o,val,loc) NEW_NODE(NODE_OP_ASGN2,r,val,NEW_OP_ASGN22(i,o,t,loc),loc)
+#define NEW_OP_ASGN22(i,o,t,loc) NEW_NODE(NODE_OP_ASGN2,i,o,t,loc)
+#define NEW_OP_ASGN_OR(i,val,loc) NEW_NODE(NODE_OP_ASGN_OR,i,val,0,loc)
+#define NEW_OP_ASGN_AND(i,val,loc) NEW_NODE(NODE_OP_ASGN_AND,i,val,0,loc)
+#define NEW_OP_CDECL(v,op,val,loc) NEW_NODE(NODE_OP_CDECL,v,val,op,loc)
+#define NEW_GVAR(v,loc) NEW_NODE(NODE_GVAR,v,0,v,loc)
+#define NEW_LVAR(v,loc) NEW_NODE(NODE_LVAR,v,0,0,loc)
+#define NEW_DVAR(v,loc) NEW_NODE(NODE_DVAR,v,0,0,loc)
+#define NEW_IVAR(v,loc) NEW_NODE(NODE_IVAR,v,0,0,loc)
+#define NEW_CONST(v,loc) NEW_NODE(NODE_CONST,v,0,0,loc)
+#define NEW_CVAR(v,loc) NEW_NODE(NODE_CVAR,v,0,0,loc)
+#define NEW_NTH_REF(n,loc) NEW_NODE(NODE_NTH_REF,0,n,0,loc)
+#define NEW_BACK_REF(n,loc) NEW_NODE(NODE_BACK_REF,0,n,0,loc)
+#define NEW_MATCH(c,loc) NEW_NODE(NODE_MATCH,c,0,0,loc)
+#define NEW_MATCH2(n1,n2,loc) NEW_NODE(NODE_MATCH2,n1,n2,0,loc)
+#define NEW_MATCH3(r,n2,loc) NEW_NODE(NODE_MATCH3,r,n2,0,loc)
+#define NEW_LIT(l,loc) NEW_NODE(NODE_LIT,l,0,0,loc)
+#define NEW_STR(s,loc) NEW_NODE(NODE_STR,s,0,0,loc)
+#define NEW_DSTR(s,loc) NEW_NODE(NODE_DSTR,s,1,0,loc)
+#define NEW_XSTR(s,loc) NEW_NODE(NODE_XSTR,s,0,0,loc)
+#define NEW_DXSTR(s,loc) NEW_NODE(NODE_DXSTR,s,0,0,loc)
+#define NEW_DSYM(s,loc) NEW_NODE(NODE_DSYM,s,0,0,loc)
+#define NEW_EVSTR(n,loc) NEW_NODE(NODE_EVSTR,0,(n),0,loc)
+#define NEW_CALL(r,m,a,loc) NEW_NODE(NODE_CALL,r,m,a,loc)
+#define NEW_OPCALL(r,m,a,loc) NEW_NODE(NODE_OPCALL,r,m,a,loc)
+#define NEW_FCALL(m,a,loc) NEW_NODE(NODE_FCALL,0,m,a,loc)
+#define NEW_VCALL(m,loc) NEW_NODE(NODE_VCALL,0,m,0,loc)
+#define NEW_SUPER(a,loc) NEW_NODE(NODE_SUPER,0,0,a,loc)
+#define NEW_ZSUPER(loc) NEW_NODE(NODE_ZSUPER,0,0,0,loc)
+#define NEW_ARGS_AUX(r,b,loc) NEW_NODE(NODE_ARGS_AUX,r,b,0,loc)
+#define NEW_OPT_ARG(i,v,loc) NEW_NODE(NODE_OPT_ARG,i,v,0,loc)
+#define NEW_KW_ARG(i,v,loc) NEW_NODE(NODE_KW_ARG,i,v,0,loc)
+#define NEW_POSTARG(i,v,loc) NEW_NODE(NODE_POSTARG,i,v,0,loc)
+#define NEW_ARGSCAT(a,b,loc) NEW_NODE(NODE_ARGSCAT,a,b,0,loc)
+#define NEW_ARGSPUSH(a,b,loc) NEW_NODE(NODE_ARGSPUSH,a,b,0,loc)
+#define NEW_SPLAT(a,loc) NEW_NODE(NODE_SPLAT,a,0,0,loc)
+#define NEW_BLOCK_PASS(b,loc) NEW_NODE(NODE_BLOCK_PASS,0,b,0,loc)
+#define NEW_ALIAS(n,o,loc) NEW_NODE(NODE_ALIAS,n,o,0,loc)
+#define NEW_VALIAS(n,o,loc) NEW_NODE(NODE_VALIAS,n,o,0,loc)
+#define NEW_UNDEF(i,loc) NEW_NODE(NODE_UNDEF,0,i,0,loc)
+#define NEW_CLASS(n,b,s,loc) NEW_NODE(NODE_CLASS,n,NEW_SCOPE(0,b,loc),(s),loc)
+#define NEW_SCLASS(r,b,loc) NEW_NODE(NODE_SCLASS,r,NEW_SCOPE(0,b,loc),0,loc)
+#define NEW_MODULE(n,b,loc) NEW_NODE(NODE_MODULE,n,NEW_SCOPE(0,b,loc),0,loc)
+#define NEW_COLON2(c,i,loc) NEW_NODE(NODE_COLON2,c,i,0,loc)
+#define NEW_COLON3(i,loc) NEW_NODE(NODE_COLON3,0,i,0,loc)
+#define NEW_DOT2(b,e,loc) NEW_NODE(NODE_DOT2,b,e,0,loc)
+#define NEW_DOT3(b,e,loc) NEW_NODE(NODE_DOT3,b,e,0,loc)
+#define NEW_SELF(loc) NEW_NODE(NODE_SELF,0,0,1,loc)
+#define NEW_NIL(loc) NEW_NODE(NODE_NIL,0,0,0,loc)
+#define NEW_TRUE(loc) NEW_NODE(NODE_TRUE,0,0,0,loc)
+#define NEW_FALSE(loc) NEW_NODE(NODE_FALSE,0,0,0,loc)
+#define NEW_ERRINFO(loc) NEW_NODE(NODE_ERRINFO,0,0,0,loc)
+#define NEW_DEFINED(e,loc) NEW_NODE(NODE_DEFINED,e,0,0,loc)
+#define NEW_POSTEXE(b,loc) NEW_NODE(NODE_POSTEXE,0,b,0,loc)
+#define NEW_ATTRASGN(r,m,a,loc) NEW_NODE(NODE_ATTRASGN,r,m,a,loc)
+#define NEW_ERROR(loc) NEW_NODE(NODE_ERROR,0,0,0,loc)
#define NODE_SPECIAL_REQUIRED_KEYWORD ((NODE *)-1)
-#define NODE_REQUIRED_KEYWORD_P(node) ((node) == NODE_SPECIAL_REQUIRED_KEYWORD)
+#define NODE_REQUIRED_KEYWORD_P(node) ((node)->nd_value == NODE_SPECIAL_REQUIRED_KEYWORD)
#define NODE_SPECIAL_NO_NAME_REST ((NODE *)-1)
#define NODE_NAMED_REST_P(node) ((node) != NODE_SPECIAL_NO_NAME_REST)
#define NODE_SPECIAL_EXCESSIVE_COMMA ((ID)1)
#define NODE_SPECIAL_NO_REST_KEYWORD ((NODE *)-1)
-#define nd_code_loc(n) (&RNODE(n)->nd_loc)
-#define nd_first_column(n) ((int)(RNODE(n)->nd_loc.beg_pos.column))
-#define nd_set_first_column(n, v) (RNODE(n)->nd_loc.beg_pos.column = (v))
-#define nd_first_lineno(n) ((int)(RNODE(n)->nd_loc.beg_pos.lineno))
-#define nd_set_first_lineno(n, v) (RNODE(n)->nd_loc.beg_pos.lineno = (v))
-#define nd_first_loc(n) (RNODE(n)->nd_loc.beg_pos)
-#define nd_set_first_loc(n, v) (nd_first_loc(n) = (v))
+VALUE rb_node_case_when_optimizable_literal(const NODE *const node);
-#define nd_last_column(n) ((int)(RNODE(n)->nd_loc.end_pos.column))
-#define nd_set_last_column(n, v) (RNODE(n)->nd_loc.end_pos.column = (v))
-#define nd_last_lineno(n) ((int)(RNODE(n)->nd_loc.end_pos.lineno))
-#define nd_set_last_lineno(n, v) (RNODE(n)->nd_loc.end_pos.lineno = (v))
-#define nd_last_loc(n) (RNODE(n)->nd_loc.end_pos)
-#define nd_set_last_loc(n, v) (nd_last_loc(n) = (v))
-#define nd_node_id(n) (RNODE(n)->node_id)
-#define nd_set_node_id(n,id) (RNODE(n)->node_id = (id))
+RUBY_SYMBOL_EXPORT_BEGIN
+
+typedef struct node_buffer_struct node_buffer_t;
+/* T_IMEMO/ast */
+typedef struct rb_ast_body_struct {
+ const NODE *root;
+ VALUE compile_option;
+ VALUE script_lines;
+ // script_lines is either:
+ // - a Fixnum that represents the line count of the original source, or
+ // - an Array that contains the lines of the original source
+} rb_ast_body_t;
+typedef struct rb_ast_struct {
+ VALUE flags;
+ node_buffer_t *node_buffer;
+ rb_ast_body_t body;
+} rb_ast_t;
+rb_ast_t *rb_ast_new(void);
+void rb_ast_mark(rb_ast_t*);
+void rb_ast_update_references(rb_ast_t*);
+void rb_ast_dispose(rb_ast_t*);
+void rb_ast_free(rb_ast_t*);
+size_t rb_ast_memsize(const rb_ast_t*);
+void rb_ast_add_mark_object(rb_ast_t*, VALUE);
+void rb_ast_set_tokens(rb_ast_t*, VALUE);
+VALUE rb_ast_tokens(rb_ast_t *ast);
+NODE *rb_ast_newnode(rb_ast_t*, enum node_type type);
+void rb_ast_delete_node(rb_ast_t*, NODE *n);
+rb_ast_id_table_t *rb_ast_new_local_table(rb_ast_t*, int);
+rb_ast_id_table_t *rb_ast_resize_latest_local_table(rb_ast_t*, int);
+
+VALUE rb_parser_new(void);
+VALUE rb_parser_end_seen_p(VALUE);
+VALUE rb_parser_encoding(VALUE);
+VALUE rb_parser_set_yydebug(VALUE, VALUE);
+VALUE rb_parser_dump_tree(const NODE *node, int comment);
+void rb_parser_set_options(VALUE, int, int, int, int);
+
+rb_ast_t *rb_parser_compile_string(VALUE, const char*, VALUE, int);
+rb_ast_t *rb_parser_compile_string_path(VALUE vparser, VALUE fname, VALUE src, int line);
+rb_ast_t *rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE input, int line);
+rb_ast_t *rb_parser_compile_generic(VALUE vparser, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int line);
+
+void rb_node_init(NODE *n, enum node_type type, VALUE a0, VALUE a1, VALUE a2);
+const char *ruby_node_name(int node);
+
+const struct kwtable *rb_reserved_word(const char *, unsigned int);
+
+struct rb_args_info {
+ NODE *pre_init;
+ NODE *post_init;
+
+ int pre_args_num; /* count of mandatory pre-arguments */
+ int post_args_num; /* count of mandatory post-arguments */
+
+ ID first_post_arg;
+
+ ID rest_arg;
+ ID block_arg;
+
+ NODE *kw_args;
+ NODE *kw_rest_arg;
+
+ NODE *opt_args;
+ unsigned int no_kwarg: 1;
+ unsigned int ruby2_keywords: 1;
+ unsigned int forwarding: 1;
+
+ VALUE imemo;
+};
+
+struct rb_ary_pattern_info {
+ NODE *pre_args;
+ NODE *rest_arg;
+ NODE *post_args;
+};
+
+struct rb_fnd_pattern_info {
+ NODE *pre_rest_arg;
+ NODE *args;
+ NODE *post_rest_arg;
+};
+
+struct parser_params;
+void *rb_parser_malloc(struct parser_params *, size_t);
+void *rb_parser_realloc(struct parser_params *, void *, size_t);
+void *rb_parser_calloc(struct parser_params *, size_t, size_t);
+void rb_parser_free(struct parser_params *, void *);
+PRINTF_ARGS(void rb_parser_printf(struct parser_params *parser, const char *fmt, ...), 2, 3);
+void rb_ast_node_type_change(NODE *n, enum node_type type);
+
+RUBY_SYMBOL_EXPORT_END
+
+static inline VALUE
+rb_node_set_type(NODE *n, enum node_type t)
+{
+#if RUBY_DEBUG
+ rb_ast_node_type_change(n, t);
+#endif
+ return nd_init_type(n, t);
+}
static inline bool
nd_type_p(const NODE *n, enum node_type t)
{
return (enum node_type)nd_type(n) == t;
}
+#if defined(__cplusplus)
+#if 0
+{ /* satisfy cc-mode */
+#endif
+} /* extern "C" { */
+#endif
#endif /* RUBY_NODE_H */
diff --git a/node_dump.c b/node_dump.c
deleted file mode 100644
index d346ba9a7e..0000000000
--- a/node_dump.c
+++ /dev/null
@@ -1,1281 +0,0 @@
-/**********************************************************************
-
- node_dump.c - dump ruby node tree
-
- $Author: mame $
- created at: 09/12/06 21:23:44 JST
-
- Copyright (C) 2009 Yusuke Endoh
-
-**********************************************************************/
-
-#include "internal.h"
-#include "internal/class.h"
-#include "internal/hash.h"
-#include "internal/ruby_parser.h"
-#include "internal/variable.h"
-#include "ruby/ruby.h"
-#include "vm_core.h"
-
-#define A(str) rb_str_cat2(buf, (str))
-#define AR(str) rb_str_concat(buf, (str))
-
-#define A_INDENT add_indent(buf, indent)
-#define D_INDENT rb_str_cat2(indent, next_indent)
-#define D_DEDENT rb_str_resize(indent, RSTRING_LEN(indent) - 4)
-#define A_ID(id) add_id(buf, (id))
-#define A_INT(val) rb_str_catf(buf, "%d", (val))
-#define A_LONG(val) rb_str_catf(buf, "%ld", (val))
-#define A_LIT(lit) AR(rb_dump_literal(lit))
-#define A_LOC(loc) \
- rb_str_catf(buf, "(%d,%d)-(%d,%d)", \
- loc.beg_pos.lineno, loc.beg_pos.column, \
- loc.end_pos.lineno, loc.end_pos.column)
-#define A_NODE_HEADER(node, term) \
- rb_str_catf(buf, "@ %s (id: %d, line: %d, location: (%d,%d)-(%d,%d))%s"term, \
- ruby_node_name(nd_type(node)), nd_node_id(node), nd_line(node), \
- nd_first_lineno(node), nd_first_column(node), \
- nd_last_lineno(node), nd_last_column(node), \
- (nd_fl_newline(node) ? "*" : ""))
-#define A_FIELD_HEADER(len, name, term) \
- rb_str_catf(buf, "+- %.*s:"term, (len), (name))
-#define D_FIELD_HEADER(len, name, term) (A_INDENT, A_FIELD_HEADER(len, name, term))
-
-#define D_NULL_NODE (A_INDENT, A("(null node)\n"))
-#define D_NODE_HEADER(node) (A_INDENT, A_NODE_HEADER(node, "\n"))
-
-#define COMPOUND_FIELD(len, name) \
- FIELD_BLOCK((D_FIELD_HEADER((len), (name), "\n"), D_INDENT), D_DEDENT)
-
-#define COMPOUND_FIELD1(name, ann) \
- COMPOUND_FIELD(FIELD_NAME_LEN(name, ann), \
- FIELD_NAME_DESC(name, ann))
-
-#define FIELD_NAME_DESC(name, ann) name " (" ann ")"
-#define FIELD_NAME_LEN(name, ann) (int)( \
- comment ? \
- rb_strlen_lit(FIELD_NAME_DESC(name, ann)) : \
- rb_strlen_lit(name))
-#define SIMPLE_FIELD(len, name) \
- FIELD_BLOCK(D_FIELD_HEADER((len), (name), " "), A("\n"))
-
-#define FIELD_BLOCK(init, reset) \
- for (init, field_flag = 1; \
- field_flag; /* should be optimized away */ \
- reset, field_flag = 0)
-
-#define A_SHAREABILITY(shareability) \
- switch (shareability) { \
- case rb_parser_shareable_none: \
- rb_str_cat_cstr(buf, "none"); \
- break; \
- case rb_parser_shareable_literal: \
- rb_str_cat_cstr(buf, "literal"); \
- break; \
- case rb_parser_shareable_copy: \
- rb_str_cat_cstr(buf, "experimental_copy"); \
- break; \
- case rb_parser_shareable_everything: \
- rb_str_cat_cstr(buf, "experimental_everything"); \
- break; \
- }
-
-#define SIMPLE_FIELD1(name, ann) SIMPLE_FIELD(FIELD_NAME_LEN(name, ann), FIELD_NAME_DESC(name, ann))
-#define F_CUSTOM1(name, ann) SIMPLE_FIELD1(#name, ann)
-#define F_ID(name, type, ann) SIMPLE_FIELD1(#name, ann) A_ID(type(node)->name)
-#define F_INT(name, type, ann) SIMPLE_FIELD1(#name, ann) A_INT(type(node)->name)
-#define F_LONG(name, type, ann) SIMPLE_FIELD1(#name, ann) A_LONG(type(node)->name)
-#define F_LIT(name, type, ann) SIMPLE_FIELD1(#name, ann) A_LIT(type(node)->name)
-#define F_VALUE(name, val, ann) SIMPLE_FIELD1(#name, ann) A_LIT(val)
-#define F_MSG(name, ann, desc) SIMPLE_FIELD1(#name, ann) A(desc)
-#define F_LOC(name, type) SIMPLE_FIELD1(#name, "") A_LOC(type(node)->name)
-#define F_SHAREABILITY(name, type, ann) SIMPLE_FIELD1(#name, ann) A_SHAREABILITY(type(node)->name)
-
-#define F_NODE(name, type, ann) \
- COMPOUND_FIELD1(#name, ann) {dump_node(buf, indent, comment, RNODE(type(node)->name));}
-
-#define F_NODE2(name, n, ann) \
- COMPOUND_FIELD1(#name, ann) {dump_node(buf, indent, comment, n);}
-
-#define F_ARRAY(name, type, ann) \
- COMPOUND_FIELD1(#name, ann) {dump_parser_array(buf, indent, comment, type(node)->name);}
-
-#define ANN(ann) \
- if (comment) { \
- A_INDENT; A("| # " ann "\n"); \
- }
-
-#define LAST_NODE (next_indent = " ")
-
-VALUE
-rb_dump_literal(VALUE lit)
-{
- if (!RB_SPECIAL_CONST_P(lit)) {
- VALUE str;
- switch (RB_BUILTIN_TYPE(lit)) {
- case T_CLASS: case T_MODULE: case T_ICLASS:
- str = rb_class_path(lit);
- if (RCLASS_SINGLETON_P(lit)) {
- str = rb_sprintf("<%"PRIsVALUE">", str);
- }
- return str;
- default:
- break;
- }
- }
- return rb_inspect(lit);
-}
-
-static void
-add_indent(VALUE buf, VALUE indent)
-{
- AR(indent);
-}
-
-static void
-add_id(VALUE buf, ID id)
-{
- if (id == 0) {
- A("(null)");
- }
- else {
- VALUE str = rb_id2str(id);
- if (str) {
- A(":"); AR(str);
- }
- else {
- rb_str_catf(buf, "(internal variable: 0x%"PRIsVALUE")", id);
- }
- }
-}
-
-struct add_option_arg {
- VALUE buf, indent;
- st_index_t count;
-};
-
-static void dump_node(VALUE, VALUE, int, const NODE *);
-static const char default_indent[] = "| ";
-
-static void
-dump_array(VALUE buf, VALUE indent, int comment, const NODE *node)
-{
- int field_flag;
- const char *next_indent = default_indent;
- F_LONG(as.nd_alen, RNODE_LIST, "length");
- F_NODE(nd_head, RNODE_LIST, "element");
- while (RNODE_LIST(node)->nd_next && nd_type_p(RNODE_LIST(node)->nd_next, NODE_LIST)) {
- node = RNODE_LIST(node)->nd_next;
- F_NODE(nd_head, RNODE_LIST, "element");
- }
- LAST_NODE;
- F_NODE(nd_next, RNODE_LIST, "next element");
-}
-
-static void
-dump_parser_array(VALUE buf, VALUE indent, int comment, const rb_parser_ary_t *ary)
-{
- int field_flag;
- const char *next_indent = default_indent;
-
- if (ary->data_type != PARSER_ARY_DATA_NODE) {
- rb_bug("unexpected rb_parser_ary_data_type: %d", ary->data_type);
- }
-
- F_CUSTOM1(length, "length") { A_LONG(ary->len); }
- for (long i = 0; i < ary->len; i++) {
- if (i == ary->len - 1) LAST_NODE;
- A_INDENT;
- rb_str_catf(buf, "+- element (%s%ld):\n",
- comment ? "statement #" : "", i);
- D_INDENT;
- dump_node(buf, indent, comment, ary->data[i]);
- D_DEDENT;
- }
-}
-
-static void
-dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
-{
- int field_flag;
- int i;
- const char *next_indent = default_indent;
- enum node_type type;
-
- if (!node) {
- D_NULL_NODE;
- return;
- }
-
- D_NODE_HEADER(node);
-
- type = nd_type(node);
- switch (type) {
- case NODE_BLOCK:
- ANN("statement sequence");
- ANN("format: [nd_head]; ...; [nd_next]");
- ANN("example: foo; bar");
- i = 0;
- do {
- A_INDENT;
- rb_str_catf(buf, "+- nd_head (%s%d):\n",
- comment ? "statement #" : "", ++i);
- if (!RNODE_BLOCK(node)->nd_next) LAST_NODE;
- D_INDENT;
- dump_node(buf, indent, comment, RNODE_BLOCK(node)->nd_head);
- D_DEDENT;
- } while (RNODE_BLOCK(node)->nd_next &&
- nd_type_p(RNODE_BLOCK(node)->nd_next, NODE_BLOCK) &&
- (node = RNODE_BLOCK(node)->nd_next, 1));
- if (RNODE_BLOCK(node)->nd_next) {
- LAST_NODE;
- F_NODE(nd_next, RNODE_BLOCK, "next block");
- }
- return;
-
- case NODE_IF:
- ANN("if statement");
- ANN("format: if [nd_cond] then [nd_body] else [nd_else] end");
- ANN("example: if x == 1 then foo else bar end");
- F_NODE(nd_cond, RNODE_IF, "condition expr");
- F_NODE(nd_body, RNODE_IF, "then clause");
- LAST_NODE;
- F_NODE(nd_else, RNODE_IF, "else clause");
- return;
-
- case NODE_UNLESS:
- ANN("unless statement");
- ANN("format: unless [nd_cond] then [nd_body] else [nd_else] end");
- ANN("example: unless x == 1 then foo else bar end");
- F_NODE(nd_cond, RNODE_UNLESS, "condition expr");
- F_NODE(nd_body, RNODE_UNLESS, "then clause");
- F_NODE(nd_else, RNODE_UNLESS, "else clause");
- F_LOC(keyword_loc, RNODE_UNLESS);
- F_LOC(then_keyword_loc, RNODE_UNLESS);
- LAST_NODE;
- F_LOC(end_keyword_loc, RNODE_UNLESS);
- return;
-
- case NODE_CASE:
- ANN("case statement");
- ANN("format: case [nd_head]; [nd_body]; end");
- ANN("example: case x; when 1; foo; when 2; bar; else baz; end");
- F_NODE(nd_head, RNODE_CASE, "case expr");
- F_NODE(nd_body, RNODE_CASE, "when clauses");
- F_LOC(case_keyword_loc, RNODE_CASE);
- LAST_NODE;
- F_LOC(end_keyword_loc, RNODE_CASE);
- return;
- case NODE_CASE2:
- ANN("case statement with no head");
- ANN("format: case; [nd_body]; end");
- ANN("example: case; when 1; foo; when 2; bar; else baz; end");
- F_NODE(nd_head, RNODE_CASE2, "case expr");
- F_NODE(nd_body, RNODE_CASE2, "when clauses");
- F_LOC(case_keyword_loc, RNODE_CASE2);
- LAST_NODE;
- F_LOC(end_keyword_loc, RNODE_CASE2);
- return;
- case NODE_CASE3:
- ANN("case statement (pattern matching)");
- ANN("format: case [nd_head]; [nd_body]; end");
- ANN("example: case x; in 1; foo; in 2; bar; else baz; end");
- F_NODE(nd_head, RNODE_CASE3, "case expr");
- F_NODE(nd_body, RNODE_CASE3, "in clauses");
- F_LOC(case_keyword_loc, RNODE_CASE3);
- LAST_NODE;
- F_LOC(end_keyword_loc, RNODE_CASE3);
- return;
-
- case NODE_WHEN:
- ANN("when clause");
- ANN("format: when [nd_head]; [nd_body]; (when or else) [nd_next]");
- ANN("example: case x; when 1; foo; when 2; bar; else baz; end");
- F_NODE(nd_head, RNODE_WHEN, "when value");
- F_NODE(nd_body, RNODE_WHEN, "when body");
- LAST_NODE;
- F_NODE(nd_next, RNODE_WHEN, "next when clause");
- F_LOC(keyword_loc, RNODE_WHEN);
- LAST_NODE;
- F_LOC(then_keyword_loc, RNODE_WHEN);
- return;
-
- case NODE_IN:
- ANN("in clause");
- ANN("format: in [nd_head]; [nd_body]; (in or else) [nd_next]");
- ANN("example: case x; in 1; foo; in 2; bar; else baz; end");
- F_NODE(nd_head, RNODE_IN, "in pattern");
- F_NODE(nd_body, RNODE_IN, "in body");
- LAST_NODE;
- F_NODE(nd_next, RNODE_IN, "next in clause");
- return;
-
- case NODE_WHILE:
- ANN("while statement");
- ANN("format: while [nd_cond]; [nd_body]; end");
- ANN("example: while x == 1; foo; end");
- goto loop;
- case NODE_UNTIL:
- ANN("until statement");
- ANN("format: until [nd_cond]; [nd_body]; end");
- ANN("example: until x == 1; foo; end");
- loop:
- F_CUSTOM1(nd_state, "begin-end-while?") {
- A_INT((int)RNODE_WHILE(node)->nd_state);
- A((RNODE_WHILE(node)->nd_state == 1) ? " (while-end)" : " (begin-end-while)");
- }
- F_NODE(nd_cond, RNODE_WHILE, "condition");
- F_NODE(nd_body, RNODE_WHILE, "body");
- F_LOC(keyword_loc, RNODE_WHILE);
- LAST_NODE;
- F_LOC(closing_loc, RNODE_WHILE);
- return;
-
- case NODE_ITER:
- ANN("method call with block");
- ANN("format: [nd_iter] { [nd_body] }");
- ANN("example: 3.times { foo }");
- goto iter;
- case NODE_FOR:
- ANN("for statement");
- ANN("format: for * in [nd_iter] do [nd_body] end");
- ANN("example: for i in 1..3 do foo end");
- iter:
- F_NODE(nd_iter, RNODE_ITER, "iteration receiver");
- LAST_NODE;
- F_NODE(nd_body, RNODE_ITER, "body");
- return;
-
- case NODE_FOR_MASGN:
- ANN("vars of for statement with masgn");
- ANN("format: for [nd_var] in ... do ... end");
- ANN("example: for x, y in 1..3 do foo end");
- LAST_NODE;
- F_NODE(nd_var, RNODE_FOR_MASGN, "var");
- return;
-
- case NODE_BREAK:
- ANN("break statement");
- ANN("format: break [nd_stts]");
- ANN("example: break 1");
- F_NODE(nd_stts, RNODE_BREAK, "value");
- LAST_NODE;
- F_LOC(keyword_loc, RNODE_BREAK);
- return;
- case NODE_NEXT:
- ANN("next statement");
- ANN("format: next [nd_stts]");
- ANN("example: next 1");
- F_NODE(nd_stts, RNODE_NEXT, "value");
- LAST_NODE;
- F_LOC(keyword_loc, RNODE_NEXT);
- return;
- case NODE_RETURN:
- ANN("return statement");
- ANN("format: return [nd_stts]");
- ANN("example: return 1");
- F_NODE(nd_stts, RNODE_RETURN, "value");
- LAST_NODE;
- F_LOC(keyword_loc, RNODE_RETURN);
- return;
-
- case NODE_REDO:
- ANN("redo statement");
- ANN("format: redo");
- ANN("example: redo");
- F_LOC(keyword_loc, RNODE_REDO);
- return;
-
- case NODE_RETRY:
- ANN("retry statement");
- ANN("format: retry");
- ANN("example: retry");
- return;
-
- case NODE_BEGIN:
- ANN("begin statement");
- ANN("format: begin; [nd_body]; end");
- ANN("example: begin; 1; end");
- LAST_NODE;
- F_NODE(nd_body, RNODE_BEGIN, "body");
- return;
-
- case NODE_RESCUE:
- ANN("rescue clause");
- ANN("format: begin; [nd_body]; (rescue) [nd_resq]; else [nd_else]; end");
- ANN("example: begin; foo; rescue; bar; else; baz; end");
- F_NODE(nd_head, RNODE_RESCUE, "body");
- F_NODE(nd_resq, RNODE_RESCUE, "rescue clause list");
- LAST_NODE;
- F_NODE(nd_else, RNODE_RESCUE, "rescue else clause");
- return;
-
- case NODE_RESBODY:
- ANN("rescue clause (cont'd)");
- ANN("format: rescue [nd_args] (=> [nd_exc_var]); [nd_body]; (rescue) [nd_next]");
- ANN("example: begin; foo; rescue; bar; else; baz; end");
- F_NODE(nd_args, RNODE_RESBODY, "rescue exceptions");
- F_NODE(nd_exc_var, RNODE_RESBODY, "exception variable");
- F_NODE(nd_body, RNODE_RESBODY, "rescue clause");
- LAST_NODE;
- F_NODE(nd_next, RNODE_RESBODY, "next rescue clause");
- return;
-
- case NODE_ENSURE:
- ANN("ensure clause");
- ANN("format: begin; [nd_head]; ensure; [nd_ensr]; end");
- ANN("example: begin; foo; ensure; bar; end");
- F_NODE(nd_head, RNODE_ENSURE, "body");
- LAST_NODE;
- F_NODE(nd_ensr, RNODE_ENSURE, "ensure clause");
- return;
-
- case NODE_AND:
- ANN("&& operator");
- ANN("format: [nd_1st] && [nd_2nd]");
- ANN("example: foo && bar");
- goto andor;
- case NODE_OR:
- ANN("|| operator");
- ANN("format: [nd_1st] || [nd_2nd]");
- ANN("example: foo || bar");
- andor:
- while (1) {
- F_NODE(nd_1st, RNODE_AND, "left expr");
- if (!RNODE_AND(node)->nd_2nd || !nd_type_p(RNODE_AND(node)->nd_2nd, type))
- break;
- node = RNODE_AND(node)->nd_2nd;
- }
- F_NODE(nd_2nd, RNODE_AND, "right expr");
- LAST_NODE;
- F_LOC(operator_loc, RNODE_AND);
- return;
-
- case NODE_MASGN:
- ANN("multiple assignment");
- ANN("format: [nd_head], [nd_args] = [nd_value]");
- ANN("example: a, b = foo");
- F_NODE(nd_value, RNODE_MASGN, "rhsn");
- F_NODE(nd_head, RNODE_MASGN, "lhsn");
- if (NODE_NAMED_REST_P(RNODE_MASGN(node)->nd_args)) {
- LAST_NODE;
- F_NODE(nd_args, RNODE_MASGN, "splatn");
- }
- else {
- F_MSG(nd_args, "splatn", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
- }
- return;
-
- case NODE_LASGN:
- ANN("local variable assignment");
- ANN("format: [nd_vid](lvar) = [nd_value]");
- ANN("example: x = foo");
- F_ID(nd_vid, RNODE_LASGN, "local variable");
- if (NODE_REQUIRED_KEYWORD_P(RNODE_LASGN(node)->nd_value)) {
- F_MSG(nd_value, "rvalue", "NODE_SPECIAL_REQUIRED_KEYWORD (required keyword argument)");
- }
- else {
- LAST_NODE;
- F_NODE(nd_value, RNODE_LASGN, "rvalue");
- }
- return;
- case NODE_DASGN:
- ANN("dynamic variable assignment");
- ANN("format: [nd_vid](dvar) = [nd_value]");
- ANN("example: x = nil; 1.times { x = foo }");
- ANN("example: 1.times { x = foo }");
- F_ID(nd_vid, RNODE_DASGN, "local variable");
- if (NODE_REQUIRED_KEYWORD_P(RNODE_DASGN(node)->nd_value)) {
- F_MSG(nd_value, "rvalue", "NODE_SPECIAL_REQUIRED_KEYWORD (required keyword argument)");
- }
- else {
- LAST_NODE;
- F_NODE(nd_value, RNODE_DASGN, "rvalue");
- }
- return;
- case NODE_IASGN:
- ANN("instance variable assignment");
- ANN("format: [nd_vid](ivar) = [nd_value]");
- ANN("example: @x = foo");
- F_ID(nd_vid, RNODE_IASGN, "instance variable");
- LAST_NODE;
- F_NODE(nd_value, RNODE_IASGN, "rvalue");
- return;
- case NODE_CVASGN:
- ANN("class variable assignment");
- ANN("format: [nd_vid](cvar) = [nd_value]");
- ANN("example: @@x = foo");
- F_ID(nd_vid, RNODE_CVASGN, "class variable");
- LAST_NODE;
- F_NODE(nd_value, RNODE_CVASGN, "rvalue");
- return;
- case NODE_GASGN:
- ANN("global variable assignment");
- ANN("format: [nd_vid](gvar) = [nd_value]");
- ANN("example: $x = foo");
- F_ID(nd_vid, RNODE_GASGN, "global variable");
- LAST_NODE;
- F_NODE(nd_value, RNODE_GASGN, "rvalue");
- return;
-
- case NODE_CDECL:
- ANN("constant declaration");
- ANN("format: [nd_else]::[nd_vid](constant) = [nd_value]");
- ANN("example: X = foo");
- if (RNODE_CDECL(node)->nd_vid) {
- F_ID(nd_vid, RNODE_CDECL, "constant");
- F_MSG(nd_else, "extension", "not used");
- }
- else {
- F_MSG(nd_vid, "constant", "0 (see extension field)");
- F_NODE(nd_else, RNODE_CDECL, "extension");
- }
- F_SHAREABILITY(shareability, RNODE_CDECL, "shareability");
- LAST_NODE;
- F_NODE(nd_value, RNODE_CDECL, "rvalue");
- return;
-
- case NODE_OP_ASGN1:
- ANN("array assignment with operator");
- ANN("format: [nd_recv] [ [nd_index] ] [nd_mid]= [nd_rvalue]");
- ANN("example: ary[1] += foo");
- F_NODE(nd_recv, RNODE_OP_ASGN1, "receiver");
- F_ID(nd_mid, RNODE_OP_ASGN1, "operator");
- F_NODE(nd_index, RNODE_OP_ASGN1, "index");
- F_NODE(nd_rvalue, RNODE_OP_ASGN1, "rvalue");
- F_LOC(call_operator_loc, RNODE_OP_ASGN1);
- F_LOC(opening_loc, RNODE_OP_ASGN1);
- F_LOC(closing_loc, RNODE_OP_ASGN1);
- LAST_NODE;
- F_LOC(binary_operator_loc, RNODE_OP_ASGN1);
- return;
-
- case NODE_OP_ASGN2:
- ANN("attr assignment with operator");
- ANN("format: [nd_recv].[nd_vid] [nd_mid]= [nd_value]");
- ANN("example: struct.field += foo");
- F_NODE(nd_recv, RNODE_OP_ASGN2, "receiver");
- F_CUSTOM1(nd_vid, "attr") {
- if (RNODE_OP_ASGN2(node)->nd_aid) A("? ");
- A_ID(RNODE_OP_ASGN2(node)->nd_vid);
- }
- F_ID(nd_mid, RNODE_OP_ASGN2, "operator");
- F_NODE(nd_value, RNODE_OP_ASGN2, "rvalue");
- F_LOC(call_operator_loc, RNODE_OP_ASGN2);
- F_LOC(message_loc, RNODE_OP_ASGN2);
- LAST_NODE;
- F_LOC(binary_operator_loc, RNODE_OP_ASGN2);
- return;
-
- case NODE_OP_ASGN_AND:
- ANN("assignment with && operator");
- ANN("format: [nd_head] &&= [nd_value]");
- ANN("example: foo &&= bar");
- goto asgn_andor;
- case NODE_OP_ASGN_OR:
- ANN("assignment with || operator");
- ANN("format: [nd_head] ||= [nd_value]");
- ANN("example: foo ||= bar");
- asgn_andor:
- F_NODE(nd_head, RNODE_OP_ASGN_AND, "variable");
- LAST_NODE;
- F_NODE(nd_value, RNODE_OP_ASGN_AND, "rvalue");
- return;
-
- case NODE_OP_CDECL:
- ANN("constant declaration with operator");
- ANN("format: [nd_head](constant) [nd_aid]= [nd_value]");
- ANN("example: A::B ||= 1");
- F_NODE(nd_head, RNODE_OP_CDECL, "constant");
- F_ID(nd_aid, RNODE_OP_CDECL, "operator");
- F_SHAREABILITY(shareability, RNODE_OP_CDECL, "shareability");
- LAST_NODE;
- F_NODE(nd_value, RNODE_OP_CDECL, "rvalue");
- return;
-
- case NODE_CALL:
- ANN("method invocation");
- ANN("format: [nd_recv].[nd_mid]([nd_args])");
- ANN("example: obj.foo(1)");
- F_ID(nd_mid, RNODE_CALL, "method id");
- F_NODE(nd_recv, RNODE_CALL, "receiver");
- LAST_NODE;
- F_NODE(nd_args, RNODE_CALL, "arguments");
- return;
-
- case NODE_OPCALL:
- ANN("method invocation");
- ANN("format: [nd_recv] [nd_mid] [nd_args]");
- ANN("example: foo + bar");
- F_ID(nd_mid, RNODE_OPCALL, "method id");
- F_NODE(nd_recv, RNODE_OPCALL, "receiver");
- LAST_NODE;
- F_NODE(nd_args, RNODE_OPCALL, "arguments");
- return;
-
- case NODE_FCALL:
- ANN("function call");
- ANN("format: [nd_mid]([nd_args])");
- ANN("example: foo(1)");
- F_ID(nd_mid, RNODE_FCALL, "method id");
- LAST_NODE;
- F_NODE(nd_args, RNODE_FCALL, "arguments");
- return;
-
- case NODE_VCALL:
- ANN("function call with no argument");
- ANN("format: [nd_mid]");
- ANN("example: foo");
- F_ID(nd_mid, RNODE_VCALL, "method id");
- return;
-
- case NODE_QCALL:
- ANN("safe method invocation");
- ANN("format: [nd_recv]&.[nd_mid]([nd_args])");
- ANN("example: obj&.foo(1)");
- F_ID(nd_mid, RNODE_QCALL, "method id");
- F_NODE(nd_recv, RNODE_QCALL, "receiver");
- LAST_NODE;
- F_NODE(nd_args, RNODE_QCALL, "arguments");
- return;
-
- case NODE_SUPER:
- ANN("super invocation");
- ANN("format: super [nd_args]");
- ANN("example: super 1");
- LAST_NODE;
- F_NODE(nd_args, RNODE_SUPER, "arguments");
- return;
-
- case NODE_ZSUPER:
- ANN("super invocation with no argument");
- ANN("format: super");
- ANN("example: super");
- return;
-
- case NODE_LIST:
- ANN("list constructor");
- ANN("format: [ [nd_head], [nd_next].. ] (length: [nd_alen])");
- ANN("example: [1, 2, 3]");
- dump_array(buf, indent, comment, node);
- return;
-
- case NODE_ZLIST:
- ANN("empty list constructor");
- ANN("format: []");
- ANN("example: []");
- return;
-
- case NODE_HASH:
- if (!RNODE_HASH(node)->nd_brace) {
- ANN("keyword arguments");
- ANN("format: [nd_head]");
- ANN("example: a: 1, b: 2");
- }
- else {
- ANN("hash constructor");
- ANN("format: { [nd_head] }");
- ANN("example: { 1 => 2, 3 => 4 }");
- }
- F_CUSTOM1(nd_brace, "keyword arguments or hash literal") {
- switch (RNODE_HASH(node)->nd_brace) {
- case 0: A("0 (keyword argument)"); break;
- case 1: A("1 (hash literal)"); break;
- }
- }
- LAST_NODE;
- F_NODE(nd_head, RNODE_HASH, "contents");
- return;
-
- case NODE_YIELD:
- ANN("yield invocation");
- ANN("format: yield [nd_head]");
- ANN("example: yield 1");
- LAST_NODE;
- F_NODE(nd_head, RNODE_YIELD, "arguments");
- return;
-
- case NODE_LVAR:
- ANN("local variable reference");
- ANN("format: [nd_vid](lvar)");
- ANN("example: x");
- F_ID(nd_vid, RNODE_LVAR, "local variable");
- return;
- case NODE_DVAR:
- ANN("dynamic variable reference");
- ANN("format: [nd_vid](dvar)");
- ANN("example: 1.times { x = 1; x }");
- F_ID(nd_vid, RNODE_DVAR, "local variable");
- return;
- case NODE_IVAR:
- ANN("instance variable reference");
- ANN("format: [nd_vid](ivar)");
- ANN("example: @x");
- F_ID(nd_vid, RNODE_IVAR, "instance variable");
- return;
- case NODE_CONST:
- ANN("constant reference");
- ANN("format: [nd_vid](constant)");
- ANN("example: X");
- F_ID(nd_vid, RNODE_CONST, "constant");
- return;
- case NODE_CVAR:
- ANN("class variable reference");
- ANN("format: [nd_vid](cvar)");
- ANN("example: @@x");
- F_ID(nd_vid, RNODE_CVAR, "class variable");
- return;
-
- case NODE_GVAR:
- ANN("global variable reference");
- ANN("format: [nd_vid](gvar)");
- ANN("example: $x");
- F_ID(nd_vid, RNODE_GVAR, "global variable");
- return;
-
- case NODE_NTH_REF:
- ANN("nth special variable reference");
- ANN("format: $[nd_nth]");
- ANN("example: $1, $2, ..");
- F_CUSTOM1(nd_nth, "variable") { A("$"); A_LONG(RNODE_NTH_REF(node)->nd_nth); }
- return;
-
- case NODE_BACK_REF:
- ANN("back special variable reference");
- ANN("format: $[nd_nth]");
- ANN("example: $&, $`, $', $+");
- F_CUSTOM1(nd_nth, "variable") {
- char name[3] = "$ ";
- name[1] = (char)RNODE_BACK_REF(node)->nd_nth;
- A(name);
- }
- return;
-
- case NODE_MATCH:
- ANN("match expression (against $_ implicitly)");
- ANN("format: [nd_lit] (in condition)");
- ANN("example: if /foo/; foo; end");
- LAST_NODE;
- F_VALUE(string, rb_node_regx_string_val(node), "string");
- return;
-
- case NODE_MATCH2:
- ANN("match expression (regexp first)");
- ANN("format: [nd_recv] =~ [nd_value]");
- ANN("example: /foo/ =~ 'foo'");
- F_NODE(nd_recv, RNODE_MATCH2, "regexp (receiver)");
- if (!RNODE_MATCH2(node)->nd_args) LAST_NODE;
- F_NODE(nd_value, RNODE_MATCH2, "string (argument)");
- if (RNODE_MATCH2(node)->nd_args) {
- LAST_NODE;
- F_NODE(nd_args, RNODE_MATCH2, "named captures");
- }
- return;
-
- case NODE_MATCH3:
- ANN("match expression (regexp second)");
- ANN("format: [nd_recv] =~ [nd_value]");
- ANN("example: 'foo' =~ /foo/");
- F_NODE(nd_recv, RNODE_MATCH3, "string (receiver)");
- LAST_NODE;
- F_NODE(nd_value, RNODE_MATCH3, "regexp (argument)");
- return;
-
- case NODE_STR:
- ANN("string literal");
- ANN("format: [nd_lit]");
- ANN("example: 'foo'");
- goto str;
- case NODE_XSTR:
- ANN("xstring literal");
- ANN("format: [nd_lit]");
- ANN("example: `foo`");
- str:
- F_VALUE(string, rb_node_str_string_val(node), "literal");
- return;
-
- case NODE_INTEGER:
- ANN("integer literal");
- ANN("format: [val]");
- ANN("example: 1");
- F_VALUE(val, rb_node_integer_literal_val(node), "val");
- return;
-
- case NODE_FLOAT:
- ANN("float literal");
- ANN("format: [val]");
- ANN("example: 1.2");
- F_VALUE(val, rb_node_float_literal_val(node), "val");
- return;
-
- case NODE_RATIONAL:
- ANN("rational number literal");
- ANN("format: [val]");
- ANN("example: 1r");
- F_VALUE(val, rb_node_rational_literal_val(node), "val");
- return;
-
- case NODE_IMAGINARY:
- ANN("complex number literal");
- ANN("format: [val]");
- ANN("example: 1i");
- F_VALUE(val, rb_node_imaginary_literal_val(node), "val");
- return;
-
- case NODE_REGX:
- ANN("regexp literal");
- ANN("format: [string]");
- ANN("example: /foo/");
- LAST_NODE;
- F_VALUE(string, rb_node_regx_string_val(node), "string");
- return;
-
- case NODE_ONCE:
- ANN("once evaluation");
- ANN("format: [nd_body]");
- ANN("example: /foo#{ bar }baz/o");
- LAST_NODE;
- F_NODE(nd_body, RNODE_ONCE, "body");
- return;
-
- case NODE_DSTR:
- ANN("string literal with interpolation");
- ANN("format: [nd_lit]");
- ANN("example: \"foo#{ bar }baz\"");
- goto dlit;
- case NODE_DXSTR:
- ANN("xstring literal with interpolation");
- ANN("format: [nd_lit]");
- ANN("example: `foo#{ bar }baz`");
- goto dlit;
- case NODE_DREGX:
- ANN("regexp literal with interpolation");
- ANN("format: [nd_lit]");
- ANN("example: /foo#{ bar }baz/");
- goto dlit;
- case NODE_DSYM:
- ANN("symbol literal with interpolation");
- ANN("format: [nd_lit]");
- ANN("example: :\"foo#{ bar }baz\"");
- dlit:
- F_VALUE(string, rb_node_dstr_string_val(node), "preceding string");
- if (!RNODE_DSTR(node)->nd_next) return;
- F_NODE(nd_next->nd_head, RNODE_DSTR, "interpolation");
- LAST_NODE;
- F_NODE(nd_next->nd_next, RNODE_DSTR, "tailing strings");
- return;
-
- case NODE_SYM:
- ANN("symbol literal");
- ANN("format: [string]");
- ANN("example: :foo");
- F_VALUE(string, rb_node_sym_string_val(node), "string");
- return;
-
- case NODE_EVSTR:
- ANN("interpolation expression");
- ANN("format: \"..#{ [nd_body] }..\"");
- ANN("example: \"foo#{ bar }baz\"");
- LAST_NODE;
- F_NODE(nd_body, RNODE_EVSTR, "body");
- return;
-
- case NODE_ARGSCAT:
- ANN("splat argument following arguments");
- ANN("format: ..(*[nd_head], [nd_body..])");
- ANN("example: foo(*ary, post_arg1, post_arg2)");
- F_NODE(nd_head, RNODE_ARGSCAT, "preceding array");
- LAST_NODE;
- F_NODE(nd_body, RNODE_ARGSCAT, "following array");
- return;
-
- case NODE_ARGSPUSH:
- ANN("splat argument following one argument");
- ANN("format: ..(*[nd_head], [nd_body])");
- ANN("example: foo(*ary, post_arg)");
- F_NODE(nd_head, RNODE_ARGSPUSH, "preceding array");
- LAST_NODE;
- F_NODE(nd_body, RNODE_ARGSPUSH, "following element");
- return;
-
- case NODE_SPLAT:
- ANN("splat argument");
- ANN("format: *[nd_head]");
- ANN("example: foo(*ary)");
- F_NODE(nd_head, RNODE_SPLAT, "splat'ed array");
- LAST_NODE;
- F_LOC(operator_loc, RNODE_SPLAT);
- return;
-
- case NODE_BLOCK_PASS:
- ANN("arguments with block argument");
- ANN("format: ..([nd_head], &[nd_body])");
- ANN("example: foo(x, &blk)");
- F_CUSTOM1(forwarding, "arguments forwarding or not") {
- switch (RNODE_BLOCK_PASS(node)->forwarding) {
- case 0: A("0 (no forwarding)"); break;
- case 1: A("1 (forwarding)"); break;
- }
- }
- F_NODE(nd_head, RNODE_BLOCK_PASS, "other arguments");
- F_NODE(nd_body, RNODE_BLOCK_PASS, "block argument");
- LAST_NODE;
- F_LOC(operator_loc, RNODE_BLOCK_PASS);
- return;
-
- case NODE_DEFN:
- ANN("method definition");
- ANN("format: def [nd_mid] [nd_defn]; end");
- ANN("example: def foo; bar; end");
- F_ID(nd_mid, RNODE_DEFN, "method name");
- LAST_NODE;
- F_NODE(nd_defn, RNODE_DEFN, "method definition");
- return;
-
- case NODE_DEFS:
- ANN("singleton method definition");
- ANN("format: def [nd_recv].[nd_mid] [nd_defn]; end");
- ANN("example: def obj.foo; bar; end");
- F_NODE(nd_recv, RNODE_DEFS, "receiver");
- F_ID(nd_mid, RNODE_DEFS, "method name");
- LAST_NODE;
- F_NODE(nd_defn, RNODE_DEFS, "method definition");
- return;
-
- case NODE_ALIAS:
- ANN("method alias statement");
- ANN("format: alias [nd_1st] [nd_2nd]");
- ANN("example: alias bar foo");
- F_NODE(nd_1st, RNODE_ALIAS, "new name");
- F_NODE(nd_2nd, RNODE_ALIAS, "old name");
- LAST_NODE;
- F_LOC(keyword_loc, RNODE_ALIAS);
- return;
-
- case NODE_VALIAS:
- ANN("global variable alias statement");
- ANN("format: alias [nd_alias](gvar) [nd_orig](gvar)");
- ANN("example: alias $y $x");
- F_ID(nd_alias, RNODE_VALIAS, "new name");
- F_ID(nd_orig, RNODE_VALIAS, "old name");
- F_LOC(keyword_loc, RNODE_VALIAS);
- return;
-
- case NODE_UNDEF:
- ANN("method undef statement");
- ANN("format: undef [nd_undefs]");
- ANN("example: undef foo");
- LAST_NODE;
- F_ARRAY(nd_undefs, RNODE_UNDEF, "nd_undefs");
- F_LOC(keyword_loc, RNODE_UNDEF);
- return;
-
- case NODE_CLASS:
- ANN("class definition");
- ANN("format: class [nd_cpath] < [nd_super]; [nd_body]; end");
- ANN("example: class C2 < C; ..; end");
- F_NODE(nd_cpath, RNODE_CLASS, "class path");
- F_NODE(nd_super, RNODE_CLASS, "superclass");
- LAST_NODE;
- F_NODE(nd_body, RNODE_CLASS, "class definition");
- return;
-
- case NODE_MODULE:
- ANN("module definition");
- ANN("format: module [nd_cpath]; [nd_body]; end");
- ANN("example: module M; ..; end");
- F_NODE(nd_cpath, RNODE_MODULE, "module path");
- LAST_NODE;
- F_NODE(nd_body, RNODE_MODULE, "module definition");
- return;
-
- case NODE_SCLASS:
- ANN("singleton class definition");
- ANN("format: class << [nd_recv]; [nd_body]; end");
- ANN("example: class << obj; ..; end");
- F_NODE(nd_recv, RNODE_SCLASS, "receiver");
- LAST_NODE;
- F_NODE(nd_body, RNODE_SCLASS, "singleton class definition");
- return;
-
- case NODE_COLON2:
- ANN("scoped constant reference");
- ANN("format: [nd_head]::[nd_mid]");
- ANN("example: M::C");
- F_ID(nd_mid, RNODE_COLON2, "constant name");
- LAST_NODE;
- F_NODE(nd_head, RNODE_COLON2, "receiver");
- return;
-
- case NODE_COLON3:
- ANN("top-level constant reference");
- ANN("format: ::[nd_mid]");
- ANN("example: ::Object");
- F_ID(nd_mid, RNODE_COLON3, "constant name");
- return;
-
- case NODE_DOT2:
- ANN("range constructor (incl.)");
- ANN("format: [nd_beg]..[nd_end]");
- ANN("example: 1..5");
- goto dot;
- case NODE_DOT3:
- ANN("range constructor (excl.)");
- ANN("format: [nd_beg]...[nd_end]");
- ANN("example: 1...5");
- goto dot;
- case NODE_FLIP2:
- ANN("flip-flop condition (incl.)");
- ANN("format: [nd_beg]..[nd_end]");
- ANN("example: if (x==1)..(x==5); foo; end");
- goto dot;
- case NODE_FLIP3:
- ANN("flip-flop condition (excl.)");
- ANN("format: [nd_beg]...[nd_end]");
- ANN("example: if (x==1)...(x==5); foo; end");
- dot:
- F_NODE(nd_beg, RNODE_DOT2, "begin");
- LAST_NODE;
- F_NODE(nd_end, RNODE_DOT2, "end");
- return;
-
- case NODE_SELF:
- ANN("self");
- ANN("format: self");
- ANN("example: self");
- F_CUSTOM1(nd_state, "nd_state") {
- A_INT((int)RNODE_SELF(node)->nd_state);
- }
- return;
-
- case NODE_NIL:
- ANN("nil");
- ANN("format: nil");
- ANN("example: nil");
- return;
-
- case NODE_TRUE:
- ANN("true");
- ANN("format: true");
- ANN("example: true");
- return;
-
- case NODE_FALSE:
- ANN("false");
- ANN("format: false");
- ANN("example: false");
- return;
-
- case NODE_ERRINFO:
- ANN("virtual reference to $!");
- ANN("format: rescue => id");
- ANN("example: rescue => id");
- return;
-
- case NODE_DEFINED:
- ANN("defined? expression");
- ANN("format: defined?([nd_head])");
- ANN("example: defined?(foo)");
- LAST_NODE;
- F_NODE(nd_head, RNODE_DEFINED, "expr");
- return;
-
- case NODE_POSTEXE:
- ANN("post-execution");
- ANN("format: END { [nd_body] }");
- ANN("example: END { foo }");
- LAST_NODE;
- F_NODE(nd_body, RNODE_POSTEXE, "END clause");
- return;
-
- case NODE_ATTRASGN:
- ANN("attr assignment");
- ANN("format: [nd_recv].[nd_mid] = [nd_args]");
- ANN("example: struct.field = foo");
- F_NODE(nd_recv, RNODE_ATTRASGN, "receiver");
- F_ID(nd_mid, RNODE_ATTRASGN, "method name");
- LAST_NODE;
- F_NODE(nd_args, RNODE_ATTRASGN, "arguments");
- return;
-
- case NODE_LAMBDA:
- ANN("lambda expression");
- ANN("format: -> [nd_body]");
- ANN("example: -> { foo }");
- LAST_NODE;
- F_NODE(nd_body, RNODE_LAMBDA, "lambda clause");
- return;
-
- case NODE_OPT_ARG:
- ANN("optional arguments");
- ANN("format: def method_name([nd_body=some], [nd_next..])");
- ANN("example: def foo(a, b=1, c); end");
- F_NODE(nd_body, RNODE_OPT_ARG, "body");
- LAST_NODE;
- F_NODE(nd_next, RNODE_OPT_ARG, "next");
- return;
-
- case NODE_KW_ARG:
- ANN("keyword arguments");
- ANN("format: def method_name([nd_body=some], [nd_next..])");
- ANN("example: def foo(a:1, b:2); end");
- F_NODE(nd_body, RNODE_KW_ARG, "body");
- LAST_NODE;
- F_NODE(nd_next, RNODE_KW_ARG, "next");
- return;
-
- case NODE_POSTARG:
- ANN("post arguments");
- ANN("format: *[nd_1st], [nd_2nd..] = ..");
- ANN("example: a, *rest, z = foo");
- if (NODE_NAMED_REST_P(RNODE_POSTARG(node)->nd_1st)) {
- F_NODE(nd_1st, RNODE_POSTARG, "rest argument");
- }
- else {
- F_MSG(nd_1st, "rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
- }
- LAST_NODE;
- F_NODE(nd_2nd, RNODE_POSTARG, "post arguments");
- return;
-
- case NODE_ARGS:
- ANN("method parameters");
- ANN("format: def method_name(.., [nd_ainfo.nd_optargs], *[nd_ainfo.rest_arg], [nd_ainfo.first_post_arg], .., [nd_ainfo.kw_args], **[nd_ainfo.kw_rest_arg], &[nd_ainfo.block_arg])");
- ANN("example: def foo(a, b, opt1=1, opt2=2, *rest, y, z, kw: 1, **kwrest, &blk); end");
- F_CUSTOM1(nd_ainfo.forwarding, "arguments forwarding or not") {
- switch (RNODE_ARGS(node)->nd_ainfo.forwarding) {
- case 0: A("0 (no forwarding)"); break;
- case 1: A("1 (forwarding)"); break;
- }
- }
- F_INT(nd_ainfo.pre_args_num, RNODE_ARGS, "count of mandatory (pre-)arguments");
- F_NODE(nd_ainfo.pre_init, RNODE_ARGS, "initialization of (pre-)arguments");
- F_INT(nd_ainfo.post_args_num, RNODE_ARGS, "count of mandatory post-arguments");
- F_NODE(nd_ainfo.post_init, RNODE_ARGS, "initialization of post-arguments");
- F_ID(nd_ainfo.first_post_arg, RNODE_ARGS, "first post argument");
- F_CUSTOM1(nd_ainfo.rest_arg, "rest argument") {
- if (RNODE_ARGS(node)->nd_ainfo.rest_arg == NODE_SPECIAL_EXCESSIVE_COMMA) {
- A("1 (excessed comma)");
- }
- else {
- A_ID(RNODE_ARGS(node)->nd_ainfo.rest_arg);
- }
- }
- F_ID(nd_ainfo.block_arg, RNODE_ARGS, "block argument");
- F_NODE(nd_ainfo.opt_args, RNODE_ARGS, "optional arguments");
- F_NODE(nd_ainfo.kw_args, RNODE_ARGS, "keyword arguments");
- LAST_NODE;
- F_NODE(nd_ainfo.kw_rest_arg, RNODE_ARGS, "keyword rest argument");
- return;
-
- case NODE_SCOPE:
- ANN("new scope");
- ANN("format: [nd_tbl]: local table, [nd_args]: arguments, [nd_body]: body");
- F_CUSTOM1(nd_tbl, "local table") {
- rb_ast_id_table_t *tbl = RNODE_SCOPE(node)->nd_tbl;
- int i;
- int size = tbl ? tbl->size : 0;
- if (size == 0) A("(empty)");
- for (i = 0; i < size; i++) {
- A_ID(tbl->ids[i]); if (i < size - 1) A(",");
- }
- }
- F_NODE(nd_args, RNODE_SCOPE, "arguments");
- LAST_NODE;
- F_NODE(nd_body, RNODE_SCOPE, "body");
- return;
-
- case NODE_ARYPTN:
- ANN("array pattern");
- ANN("format: [nd_pconst]([pre_args], ..., *[rest_arg], [post_args], ...)");
- F_NODE(nd_pconst, RNODE_ARYPTN, "constant");
- F_NODE(pre_args, RNODE_ARYPTN, "pre arguments");
- if (NODE_NAMED_REST_P(RNODE_ARYPTN(node)->rest_arg)) {
- F_NODE(rest_arg, RNODE_ARYPTN, "rest argument");
- }
- else {
- F_MSG(rest_arg, "rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
- }
- LAST_NODE;
- F_NODE(post_args, RNODE_ARYPTN, "post arguments");
- return;
-
- case NODE_FNDPTN:
- ANN("find pattern");
- ANN("format: [nd_pconst](*[pre_rest_arg], args, ..., *[post_rest_arg])");
- F_NODE(nd_pconst, RNODE_FNDPTN, "constant");
- if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->pre_rest_arg)) {
- F_NODE(pre_rest_arg, RNODE_FNDPTN, "pre rest argument");
- }
- else {
- F_MSG(pre_rest_arg, "pre rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
- }
- F_NODE(args, RNODE_FNDPTN, "arguments");
-
- LAST_NODE;
- if (NODE_NAMED_REST_P(RNODE_FNDPTN(node)->post_rest_arg)) {
- F_NODE(post_rest_arg, RNODE_FNDPTN, "post rest argument");
- }
- else {
- F_MSG(post_rest_arg, "post rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
- }
- return;
-
- case NODE_HSHPTN:
- ANN("hash pattern");
- ANN("format: [nd_pconst]([nd_pkwargs], ..., **[nd_pkwrestarg])");
- F_NODE(nd_pconst, RNODE_HSHPTN, "constant");
- F_NODE(nd_pkwargs, RNODE_HSHPTN, "keyword arguments");
- LAST_NODE;
- if (RNODE_HSHPTN(node)->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
- F_MSG(nd_pkwrestarg, "keyword rest argument", "NODE_SPECIAL_NO_REST_KEYWORD (**nil)");
- }
- else {
- F_NODE(nd_pkwrestarg, RNODE_HSHPTN, "keyword rest argument");
- }
- return;
-
- case NODE_LINE:
- ANN("line");
- ANN("format: [lineno]");
- ANN("example: __LINE__");
- return;
-
- case NODE_FILE:
- ANN("line");
- ANN("format: [path]");
- ANN("example: __FILE__");
- F_VALUE(path, rb_node_file_path_val(node), "path");
- return;
-
- case NODE_ENCODING:
- ANN("encoding");
- ANN("format: [enc]");
- ANN("example: __ENCODING__");
- F_VALUE(enc, rb_node_encoding_val(node), "enc");
- return;
-
- case NODE_ERROR:
- ANN("Broken input recovered by Error Tolerant mode");
- return;
-
- case NODE_ARGS_AUX:
- case NODE_LAST:
- break;
- }
-
- rb_bug("dump_node: unknown node: %s", ruby_node_name(nd_type(node)));
-}
-
-VALUE
-rb_parser_dump_tree(const NODE *node, int comment)
-{
- VALUE buf = rb_str_new_cstr(
- "###########################################################\n"
- "## Do NOT use this node dump for any purpose other than ##\n"
- "## debug and research. Compatibility is not guaranteed. ##\n"
- "###########################################################\n\n"
- );
- dump_node(buf, rb_str_new_cstr("# "), comment, node);
- return buf;
-}
diff --git a/numeric.c b/numeric.c
index ef7a39dc48..6dd1ff6d2f 100644
--- a/numeric.c
+++ b/numeric.c
@@ -144,37 +144,31 @@ round_half_down(double x, double s)
static double
round_half_even(double x, double s)
{
- double u, v, us, vs, f, d, uf;
-
- v = modf(x, &u);
- us = u * s;
- vs = v * s;
+ double f, d, xs = x * s;
if (x > 0.0) {
- f = floor(vs);
- uf = us + f;
- d = vs - f;
+ f = floor(xs);
+ d = xs - f;
if (d > 0.5)
d = 1.0;
- else if (d == 0.5 || ((double)((uf + 0.5) / s) <= x))
- d = fmod(uf, 2.0);
+ else if (d == 0.5 || ((double)((f + 0.5) / s) <= x))
+ d = fmod(f, 2.0);
else
d = 0.0;
x = f + d;
}
else if (x < 0.0) {
- f = ceil(vs);
- uf = us + f;
- d = f - vs;
+ f = ceil(xs);
+ d = f - xs;
if (d > 0.5)
d = 1.0;
- else if (d == 0.5 || ((double)((uf - 0.5) / s) >= x))
- d = fmod(-uf, 2.0);
+ else if (d == 0.5 || ((double)((f - 0.5) / s) >= x))
+ d = fmod(-f, 2.0);
else
d = 0.0;
x = f - d;
}
- return us + x;
+ return x;
}
static VALUE fix_lshift(long, unsigned long);
@@ -671,7 +665,7 @@ num_div(VALUE x, VALUE y)
* Of the Core and Standard Library classes,
* only Rational uses this implementation.
*
- * For Rational +r+ and real number +n+, these expressions are equivalent:
+ * For \Rational +r+ and real number +n+, these expressions are equivalent:
*
* r % n
* r-n*(r/n).floor
@@ -694,6 +688,8 @@ num_div(VALUE x, VALUE y)
* (-r) % r2 # => (119/100)
* (-r) %-r2 # => (-21/100)
*
+ * Numeric#modulo is an alias for Numeric#%.
+ *
*/
static VALUE
@@ -738,9 +734,6 @@ num_modulo(VALUE x, VALUE y)
static VALUE
num_remainder(VALUE x, VALUE y)
{
- if (!rb_obj_is_kind_of(y, rb_cNumeric)) {
- do_coerce(&x, &y, TRUE);
- }
VALUE z = num_funcall1(x, '%', y);
if ((!rb_equal(z, INT2FIX(0))) &&
@@ -802,6 +795,8 @@ num_divmod(VALUE x, VALUE y)
* (-34.56).abs #=> 34.56
* -34.56.abs #=> 34.56
*
+ * Numeric#magnitude is an alias for Numeric#abs.
+ *
*/
static VALUE
@@ -836,7 +831,7 @@ int_zero_p(VALUE num)
if (FIXNUM_P(num)) {
return FIXNUM_ZERO_P(num);
}
- RUBY_ASSERT(RB_BIGNUM_TYPE_P(num));
+ assert(RB_BIGNUM_TYPE_P(num));
return rb_bigzero_p(num);
}
@@ -862,8 +857,6 @@ rb_int_zero_p(VALUE num)
* Of the Core and Standard Library classes,
* Integer, Float, Rational, and Complex use this implementation.
*
- * Related: #zero?
- *
*/
static VALUE
@@ -950,7 +943,7 @@ num_negative_p(VALUE num)
* So you should know its esoteric system. See following:
*
* - https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
- * - https://github.com/rdp/ruby_tutorials_core/wiki/Ruby-Talk-FAQ#-why-are-rubys-floats-imprecise
+ * - https://github.com/rdp/ruby_tutorials_core/wiki/Ruby-Talk-FAQ#floats_imprecise
* - https://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
*
* You can create a \Float object explicitly with:
@@ -965,10 +958,7 @@ num_negative_p(VALUE num)
*
* First, what's elsewhere. \Class \Float:
*
- * - Inherits from
- * {class Numeric}[rdoc-ref:Numeric@What-27s+Here]
- * and {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Comparable}[rdoc-ref:Comparable@What-27s+Here].
+ * - Inherits from {class Numeric}[rdoc-ref:Numeric@What-27s+Here].
*
* Here, class \Float provides methods for:
*
@@ -1004,10 +994,10 @@ num_negative_p(VALUE num)
* - #/: Returns the quotient of +self+ and the given value.
* - #ceil: Returns the smallest number greater than or equal to +self+.
* - #coerce: Returns a 2-element array containing the given value converted to a \Float
- * and +self+
+ and +self+
* - #divmod: Returns a 2-element array containing the quotient and remainder
* results of dividing +self+ by the given value.
- * - #fdiv: Returns the \Float result of dividing +self+ by the given value.
+ * - #fdiv: Returns the Float result of dividing +self+ by the given value.
* - #floor: Returns the greatest number smaller than or equal to +self+.
* - #next_float: Returns the next-larger representable \Float.
* - #prev_float: Returns the next-smaller representable \Float.
@@ -1023,7 +1013,7 @@ num_negative_p(VALUE num)
VALUE
rb_float_new_in_heap(double d)
{
- NEWOBJ_OF(flt, struct RFloat, rb_cFloat, T_FLOAT | (RGENGC_WB_PROTECTED_FLOAT ? FL_WB_PROTECTED : 0), sizeof(struct RFloat), 0);
+ NEWOBJ_OF(flt, struct RFloat, rb_cFloat, T_FLOAT | (RGENGC_WB_PROTECTED_FLOAT ? FL_WB_PROTECTED : 0));
#if SIZEOF_DOUBLE <= SIZEOF_VALUE
flt->float_value = d;
@@ -1083,7 +1073,7 @@ flo_to_s(VALUE flt)
s = sign ? rb_usascii_str_new_cstr("-") : rb_usascii_str_new(0, 0);
if ((digs = (int)(e - p)) >= (int)sizeof(buf)) digs = (int)sizeof(buf) - 1;
memcpy(buf, p, digs);
- free(p);
+ xfree(p);
if (decpt > 0) {
if (decpt < digs) {
memmove(buf + decpt + 1, buf + decpt, digs - decpt);
@@ -1157,7 +1147,7 @@ flo_coerce(VALUE x, VALUE y)
return rb_assoc_new(rb_Float(y), x);
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_float_uminus(VALUE flt)
{
return DBL2NUM(-RFLOAT_VALUE(flt));
@@ -1270,7 +1260,7 @@ double_div_double(double x, double y)
}
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_flo_div_flo(VALUE x, VALUE y)
{
double num = RFLOAT_VALUE(x);
@@ -1329,6 +1319,8 @@ rb_float_div(VALUE x, VALUE y)
* f.quo(Rational(2, 1)) # => 1.57
* f.quo(Complex(2, 0)) # => (1.57+0.0i)
*
+ * Float#fdiv is an alias for Float#quo.
+ *
*/
static VALUE
@@ -1380,7 +1372,7 @@ flodivmod(double x, double y, double *divp, double *modp)
* An error will be raised if y == 0.
*/
-double
+MJIT_FUNC_EXPORTED double
ruby_float_mod(double x, double y)
{
double mod;
@@ -1415,6 +1407,8 @@ ruby_float_mod(double x, double y)
* 10.0 % 4.0 # => 2.0
* 10.0 % Rational(4, 1) # => 2.0
*
+ * Float#modulo is an alias for Float#%.
+ *
*/
static VALUE
@@ -1555,8 +1549,8 @@ rb_float_pow(VALUE x, VALUE y)
* 1.eql?(Rational(1, 1)) # => false
* 1.eql?(Complex(1, 0)) # => false
*
- * \Method +eql?+ is different from <tt>==</tt> in that +eql?+ requires matching types,
- * while <tt>==</tt> does not.
+ * \Method +eql?+ is different from +==+ in that +eql?+ requires matching types,
+ * while +==+ does not.
*
*/
@@ -1615,7 +1609,7 @@ num_equal(VALUE x, VALUE y)
*
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_float_equal(VALUE x, VALUE y)
{
volatile double a, b;
@@ -1688,12 +1682,12 @@ rb_dbl_cmp(double a, double b)
* Examples:
*
* 2.0 <=> 2 # => 0
- * 2.0 <=> 2.0 # => 0
- * 2.0 <=> Rational(2, 1) # => 0
- * 2.0 <=> Complex(2, 0) # => 0
- * 2.0 <=> 1.9 # => 1
- * 2.0 <=> 2.1 # => -1
- * 2.0 <=> 'foo' # => nil
+ 2.0 <=> 2.0 # => 0
+ 2.0 <=> Rational(2, 1) # => 0
+ 2.0 <=> Complex(2, 0) # => 0
+ 2.0 <=> 1.9 # => 1
+ 2.0 <=> 2.1 # => -1
+ 2.0 <=> 'foo' # => nil
*
* This is the basis for the tests in the Comparable module.
*
@@ -1733,7 +1727,7 @@ flo_cmp(VALUE x, VALUE y)
return rb_dbl_cmp(a, b);
}
-int
+MJIT_FUNC_EXPORTED int
rb_float_cmp(VALUE x, VALUE y)
{
return NUM2INT(ensure_cmp(flo_cmp(x, y), x, y));
@@ -1927,7 +1921,7 @@ flo_le(VALUE x, VALUE y)
* Related: Float#== (performs type conversions).
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_float_eql(VALUE x, VALUE y)
{
if (RB_FLOAT_TYPE_P(y)) {
@@ -1943,7 +1937,7 @@ rb_float_eql(VALUE x, VALUE y)
#define flo_eql rb_float_eql
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_float_abs(VALUE flt)
{
double val = fabs(RFLOAT_VALUE(flt));
@@ -2170,78 +2164,36 @@ flo_ndigits(int argc, VALUE *argv)
}
/*
- * :markup: markdown
- *
* call-seq:
* floor(ndigits = 0) -> float or integer
*
- * Returns a float or integer that is a "floor" value for `self`,
- * as specified by `ndigits`,
- * which must be an
- * [integer-convertible object](rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects).
+ * Returns the largest number less than or equal to +self+ with
+ * a precision of +ndigits+ decimal digits.
*
- * When `self` is zero,
- * returns a zero value:
- * a float if `ndigits` is positive,
- * an integer otherwise:
+ * When +ndigits+ is positive, returns a float with +ndigits+
+ * digits after the decimal point (as available):
*
- * ```
- * f = 0.0 # => 0.0
- * f.floor(20) # => 0.0
- * f.floor(0) # => 0
- * f.floor(-20) # => 0
- * ```
+ * f = 12345.6789
+ * f.floor(1) # => 12345.6
+ * f.floor(3) # => 12345.678
+ * f = -12345.6789
+ * f.floor(1) # => -12345.7
+ * f.floor(3) # => -12345.679
*
- * When `self` is non-zero and `ndigits` is positive, returns a float with `ndigits`
- * digits after the decimal point (as available):
+ * When +ndigits+ is non-positive, returns an integer with at least
+ * <code>ndigits.abs</code> trailing zeros:
*
- * ```
- * f = 12345.6789
- * f.floor(1) # => 12345.6
- * f.floor(3) # => 12345.678
- * f.floor(30) # => 12345.6789
- * f = -12345.6789
- * f.floor(1) # => -12345.7
- * f.floor(3) # => -12345.679
- * f.floor(30) # => -12345.6789
- * ```
- *
- * When `self` is non-zero and `ndigits` is non-positive,
- * returns an integer value based on a computed granularity:
- *
- * - The granularity is `10 ** ndigits.abs`.
- * - The returned value is the largest multiple of the granularity
- * that is less than or equal to `self`.
- *
- * Examples with positive `self`:
- *
- * | ndigits | Granularity | 12345.6789.floor(ndigits) |
- * |--------:|------------:|--------------------------:|
- * | 0 | 1 | 12345 |
- * | -1 | 10 | 12340 |
- * | -2 | 100 | 12300 |
- * | -3 | 1000 | 12000 |
- * | -4 | 10000 | 10000 |
- * | -5 | 100000 | 0 |
- *
- * Examples with negative `self`:
- *
- * | ndigits | Granularity | -12345.6789.floor(ndigits) |
- * |--------:|------------:|---------------------------:|
- * | 0 | 1 | -12346 |
- * | -1 | 10 | -12350 |
- * | -2 | 100 | -12400 |
- * | -3 | 1000 | -13000 |
- * | -4 | 10000 | -20000 |
- * | -5 | 100000 | -100000 |
- * | -6 | 1000000 | -1000000 |
+ * f = 12345.6789
+ * f.floor(0) # => 12345
+ * f.floor(-3) # => 12000
+ * f = -12345.6789
+ * f.floor(0) # => -12346
+ * f.floor(-3) # => -13000
*
* Note that the limited precision of floating-point arithmetic
* may lead to surprising results:
*
- * ```
- * (0.3 / 0.1).floor # => 2 # Not 3, (because (0.3 / 0.1) # => 2.9999999999999996, not 3.0)
- * ```
+ * (0.3 / 0.1).floor #=> 2 (!)
*
* Related: Float#ceil.
*
@@ -2255,78 +2207,36 @@ flo_floor(int argc, VALUE *argv, VALUE num)
}
/*
- * :markup: markdown
- *
* call-seq:
* ceil(ndigits = 0) -> float or integer
*
- * Returns a numeric that is a "ceiling" value for `self`,
- * as specified by the given `ndigits`,
- * which must be an
- * [integer-convertible object](rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects).
- *
- * When `ndigits` is positive, returns a Float with `ndigits`
- * decimal digits after the decimal point
- * (as available, but no fewer than 1):
- *
- * ```
- * f = 12345.6789
- * f.ceil(1) # => 12345.7
- * f.ceil(3) # => 12345.679
- * f.ceil(30) # => 12345.6789
- * f = -12345.6789
- * f.ceil(1) # => -12345.6
- * f.ceil(3) # => -12345.678
- * f.ceil(30) # => -12345.6789
- * f = 0.0
- * f.ceil(1) # => 0.0
- * f.ceil(100) # => 0.0
- * ```
- *
- * When `ndigits` is non-positive,
- * returns an Integer based on a computed granularity:
- *
- * - The granularity is `10 ** ndigits.abs`.
- * - The returned value is the largest multiple of the granularity
- * that is less than or equal to `self`.
- *
- * Examples with positive `self`:
- *
- * | ndigits | Granularity | 12345.6789.ceil(ndigits) |
- * |--------:|------------:|-------------------------:|
- * | 0 | 1 | 12346 |
- * | -1 | 10 | 12350 |
- * | -2 | 100 | 12400 |
- * | -3 | 1000 | 13000 |
- * | -4 | 10000 | 20000 |
- * | -5 | 100000 | 100000 |
- *
- * Examples with negative `self`:
- *
- * | ndigits | Granularity | -12345.6789.ceil(ndigits) |
- * |--------:|------------:|--------------------------:|
- * | 0 | 1 | -12345 |
- * | -1 | 10 | -12340 |
- * | -2 | 100 | -12300 |
- * | -3 | 1000 | -12000 |
- * | -4 | 10000 | -10000 |
- * | -5 | 100000 | 0 |
- *
- * When `self` is zero and `ndigits` is non-positive,
- * returns Integer zero:
- *
- * ```
- * 0.0.ceil(0) # => 0
- * 0.0.ceil(-1) # => 0
- * 0.0.ceil(-2) # => 0
- * ```
+ * Returns the smallest number greater than or equal to +self+ with
+ * a precision of +ndigits+ decimal digits.
+ *
+ * When +ndigits+ is positive, returns a float with +ndigits+
+ * digits after the decimal point (as available):
+ *
+ * f = 12345.6789
+ * f.ceil(1) # => 12345.7
+ * f.ceil(3) # => 12345.679
+ * f = -12345.6789
+ * f.ceil(1) # => -12345.6
+ * f.ceil(3) # => -12345.678
+ *
+ * When +ndigits+ is non-positive, returns an integer with at least
+ * <code>ndigits.abs</code> trailing zeros:
+ *
+ * f = 12345.6789
+ * f.ceil(0) # => 12346
+ * f.ceil(-3) # => 13000
+ * f = -12345.6789
+ * f.ceil(0) # => -12345
+ * f.ceil(-3) # => -12000
*
* Note that the limited precision of floating-point arithmetic
* may lead to surprising results:
*
- * ```
- * (2.1 / 0.7).ceil #=> 4 # Not 3 (because 2.1 / 0.7 # => 3.0000000000000004, not 3.0)
- * ```
+ * (2.1 / 0.7).ceil #=> 4 (!)
*
* Related: Float#floor.
*
@@ -2424,7 +2334,7 @@ int_half_p_half_down(VALUE num, VALUE n, VALUE f)
}
/*
- * Assumes num is an \Integer, ndigits <= 0
+ * Assumes num is an Integer, ndigits <= 0
*/
static VALUE
rb_int_round(VALUE num, int ndigits, enum ruby_num_rounding_mode mode)
@@ -2537,7 +2447,7 @@ rb_int_truncate(VALUE num, int ndigits)
/*
* call-seq:
- * round(ndigits = 0, half: :up) -> integer or float
+ * round(ndigits = 0, half: :up]) -> integer or float
*
* Returns +self+ rounded to the nearest value with
* a precision of +ndigits+ decimal digits.
@@ -2680,6 +2590,7 @@ float_round_underflow(int ndigits, int binexp)
*
* (0.3 / 0.1).to_i # => 2 (!)
*
+ * Float#to_int is an alias for Float#to_i.
*/
static VALUE
@@ -2739,16 +2650,13 @@ flo_truncate(int argc, VALUE *argv, VALUE num)
/*
* call-seq:
- * floor(ndigits = 0) -> float or integer
- *
- * Returns the largest float or integer that is less than or equal to +self+,
- * as specified by the given `ndigits`,
- * which must be an
- * {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects].
+ * floor(digits = 0) -> integer or float
*
- * Equivalent to <tt>self.to_f.floor(ndigits)</tt>.
+ * Returns the largest number that is less than or equal to +self+ with
+ * a precision of +digits+ decimal digits.
*
- * Related: #ceil, Float#floor.
+ * \Numeric implements this by converting +self+ to a Float and
+ * invoking Float#floor.
*/
static VALUE
@@ -2759,16 +2667,13 @@ num_floor(int argc, VALUE *argv, VALUE num)
/*
* call-seq:
- * ceil(ndigits = 0) -> float or integer
- *
- * Returns the smallest float or integer that is greater than or equal to +self+,
- * as specified by the given `ndigits`,
- * which must be an
- * {integer-convertible object}[rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects].
+ * ceil(digits = 0) -> integer or float
*
- * Equivalent to <tt>self.to_f.ceil(ndigits)</tt>.
+ * Returns the smallest number that is greater than or equal to +self+ with
+ * a precision of +digits+ decimal digits.
*
- * Related: #floor, Float#ceil.
+ * \Numeric implements this by converting +self+ to a Float and
+ * invoking Float#ceil.
*/
static VALUE
@@ -2928,7 +2833,7 @@ ruby_num_interval_step_size(VALUE from, VALUE to, VALUE step, int excl)
}
if (RTEST(rb_funcall(from, cmp, 1, to))) return INT2FIX(0);
result = rb_funcall(rb_funcall(to, '-', 1, from), id_div, 1, step);
- if (!excl || RTEST(rb_funcall(to, cmp, 1, rb_funcall(from, '+', 1, rb_funcall(result, '*', 1, step))))) {
+ if (!excl || RTEST(rb_funcall(rb_funcall(from, '+', 1, rb_funcall(result, '*', 1, step)), cmp, 1, to))) {
result = rb_funcall(result, '+', 1, INT2FIX(1));
}
return result;
@@ -3040,88 +2945,88 @@ num_step_size(VALUE from, VALUE args, VALUE eobj)
* step(by: , to: nil) {|n| ... } -> self
* step(by: , to: nil) -> enumerator
*
- * Generates a sequence of numbers; with a block given, traverses the sequence.
- *
- * Of the Core and Standard Library classes,
- * Integer, Float, and Rational use this implementation.
- *
- * A quick example:
- *
- * squares = []
- * 1.step(by: 2, to: 10) {|i| squares.push(i*i) }
- * squares # => [1, 9, 25, 49, 81]
- *
- * The generated sequence:
- *
- * - Begins with +self+.
- * - Continues at intervals of +by+ (which may not be zero).
- * - Ends with the last number that is within or equal to +to+;
- * that is, less than or equal to +to+ if +by+ is positive,
- * greater than or equal to +to+ if +by+ is negative.
- * If +to+ is +nil+, the sequence is of infinite length.
- *
- * If a block is given, calls the block with each number in the sequence;
- * returns +self+. If no block is given, returns an Enumerator::ArithmeticSequence.
- *
- * <b>Keyword Arguments</b>
- *
- * With keyword arguments +by+ and +to+,
- * their values (or defaults) determine the step and limit:
- *
- * # Both keywords given.
- * squares = []
- * 4.step(by: 2, to: 10) {|i| squares.push(i*i) } # => 4
- * squares # => [16, 36, 64, 100]
- * cubes = []
- * 3.step(by: -1.5, to: -3) {|i| cubes.push(i*i*i) } # => 3
- * cubes # => [27.0, 3.375, 0.0, -3.375, -27.0]
- * squares = []
- * 1.2.step(by: 0.2, to: 2.0) {|f| squares.push(f*f) }
- * squares # => [1.44, 1.9599999999999997, 2.5600000000000005, 3.24, 4.0]
- *
- * squares = []
- * Rational(6/5).step(by: 0.2, to: 2.0) {|r| squares.push(r*r) }
- * squares # => [1.0, 1.44, 1.9599999999999997, 2.5600000000000005, 3.24, 4.0]
- *
- * # Only keyword to given.
- * squares = []
- * 4.step(to: 10) {|i| squares.push(i*i) } # => 4
- * squares # => [16, 25, 36, 49, 64, 81, 100]
- * # Only by given.
- *
- * # Only keyword by given
- * squares = []
- * 4.step(by:2) {|i| squares.push(i*i); break if i > 10 }
- * squares # => [16, 36, 64, 100, 144]
- *
- * # No block given.
- * e = 3.step(by: -1.5, to: -3) # => (3.step(by: -1.5, to: -3))
- * e.class # => Enumerator::ArithmeticSequence
- *
- * <b>Positional Arguments</b>
- *
- * With optional positional arguments +to+ and +by+,
- * their values (or defaults) determine the step and limit:
+ * Generates a sequence of numbers; with a block given, traverses the sequence.
*
- * squares = []
- * 4.step(10, 2) {|i| squares.push(i*i) } # => 4
- * squares # => [16, 36, 64, 100]
- * squares = []
- * 4.step(10) {|i| squares.push(i*i) }
- * squares # => [16, 25, 36, 49, 64, 81, 100]
- * squares = []
- * 4.step {|i| squares.push(i*i); break if i > 10 } # => nil
- * squares # => [16, 25, 36, 49, 64, 81, 100, 121]
+ * Of the Core and Standard Library classes,
+ * Integer, Float, and Rational use this implementation.
+ *
+ * A quick example:
+ *
+ * squares = []
+ * 1.step(by: 2, to: 10) {|i| squares.push(i*i) }
+ * squares # => [1, 9, 25, 49, 81]
+ *
+ * The generated sequence:
+ *
+ * - Begins with +self+.
+ * - Continues at intervals of +step+ (which may not be zero).
+ * - Ends with the last number that is within or equal to +limit+;
+ * that is, less than or equal to +limit+ if +step+ is positive,
+ * greater than or equal to +limit+ if +step+ is negative.
+ * If +limit+ is not given, the sequence is of infinite length.
+ *
+ * If a block is given, calls the block with each number in the sequence;
+ * returns +self+. If no block is given, returns an Enumerator::ArithmeticSequence.
+ *
+ * <b>Keyword Arguments</b>
+ *
+ * With keyword arguments +by+ and +to+,
+ * their values (or defaults) determine the step and limit:
+ *
+ * # Both keywords given.
+ * squares = []
+ * 4.step(by: 2, to: 10) {|i| squares.push(i*i) } # => 4
+ * squares # => [16, 36, 64, 100]
+ * cubes = []
+ * 3.step(by: -1.5, to: -3) {|i| cubes.push(i*i*i) } # => 3
+ * cubes # => [27.0, 3.375, 0.0, -3.375, -27.0]
+ * squares = []
+ * 1.2.step(by: 0.2, to: 2.0) {|f| squares.push(f*f) }
+ * squares # => [1.44, 1.9599999999999997, 2.5600000000000005, 3.24, 4.0]
+ *
+ * squares = []
+ * Rational(6/5).step(by: 0.2, to: 2.0) {|r| squares.push(r*r) }
+ * squares # => [1.0, 1.44, 1.9599999999999997, 2.5600000000000005, 3.24, 4.0]
+ *
+ * # Only keyword to given.
+ * squares = []
+ * 4.step(to: 10) {|i| squares.push(i*i) } # => 4
+ * squares # => [16, 25, 36, 49, 64, 81, 100]
+ * # Only by given.
+ *
+ * # Only keyword by given
+ * squares = []
+ * 4.step(by:2) {|i| squares.push(i*i); break if i > 10 }
+ * squares # => [16, 36, 64, 100, 144]
+ *
+ * # No block given.
+ * e = 3.step(by: -1.5, to: -3) # => (3.step(by: -1.5, to: -3))
+ * e.class # => Enumerator::ArithmeticSequence
+ *
+ * <b>Positional Arguments</b>
+ *
+ * With optional positional arguments +limit+ and +step+,
+ * their values (or defaults) determine the step and limit:
+ *
+ * squares = []
+ * 4.step(10, 2) {|i| squares.push(i*i) } # => 4
+ * squares # => [16, 36, 64, 100]
+ * squares = []
+ * 4.step(10) {|i| squares.push(i*i) }
+ * squares # => [16, 25, 36, 49, 64, 81, 100]
+ * squares = []
+ * 4.step {|i| squares.push(i*i); break if i > 10 } # => nil
+ * squares # => [16, 25, 36, 49, 64, 81, 100, 121]
*
* <b>Implementation Notes</b>
*
- * If all the arguments are integers, the loop operates using an integer
- * counter.
+ * If all the arguments are integers, the loop operates using an integer
+ * counter.
*
- * If any of the arguments are floating point numbers, all are converted
- * to floats, and the loop is executed
- * <i>floor(n + n*Float::EPSILON) + 1</i> times,
- * where <i>n = (limit - self)/step</i>.
+ * If any of the arguments are floating point numbers, all are converted
+ * to floats, and the loop is executed
+ * <i>floor(n + n*Float::EPSILON) + 1</i> times,
+ * where <i>n = (limit - self)/step</i>.
*
*/
@@ -3259,7 +3164,7 @@ rb_num2ulong_internal(VALUE val, int *wrap_p)
{
again:
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion of nil into Integer");
+ rb_raise(rb_eTypeError, "no implicit conversion from nil to integer");
}
if (FIXNUM_P(val)) {
@@ -3304,7 +3209,7 @@ rb_num2ulong(VALUE val)
void
rb_out_of_int(SIGNED_VALUE num)
{
- rb_raise(rb_eRangeError, "integer %"PRIdVALUE " too %s to convert to 'int'",
+ rb_raise(rb_eRangeError, "integer %"PRIdVALUE " too %s to convert to `int'",
num, num < 0 ? "small" : "big");
}
@@ -3323,12 +3228,12 @@ check_uint(unsigned long num, int sign)
if (sign) {
/* minus */
if (num < (unsigned long)INT_MIN)
- rb_raise(rb_eRangeError, "integer %ld too small to convert to 'unsigned int'", (long)num);
+ rb_raise(rb_eRangeError, "integer %ld too small to convert to `unsigned int'", (long)num);
}
else {
/* plus */
if (UINT_MAX < num)
- rb_raise(rb_eRangeError, "integer %lu too big to convert to 'unsigned int'", num);
+ rb_raise(rb_eRangeError, "integer %lu too big to convert to `unsigned int'", num);
}
}
@@ -3403,7 +3308,7 @@ NORETURN(static void rb_out_of_short(SIGNED_VALUE num));
static void
rb_out_of_short(SIGNED_VALUE num)
{
- rb_raise(rb_eRangeError, "integer %"PRIdVALUE " too %s to convert to 'short'",
+ rb_raise(rb_eRangeError, "integer %"PRIdVALUE " too %s to convert to `short'",
num, num < 0 ? "small" : "big");
}
@@ -3421,12 +3326,12 @@ check_ushort(unsigned long num, int sign)
if (sign) {
/* minus */
if (num < (unsigned long)SHRT_MIN)
- rb_raise(rb_eRangeError, "integer %ld too small to convert to 'unsigned short'", (long)num);
+ rb_raise(rb_eRangeError, "integer %ld too small to convert to `unsigned short'", (long)num);
}
else {
/* plus */
if (USHRT_MAX < num)
- rb_raise(rb_eRangeError, "integer %lu too big to convert to 'unsigned short'", num);
+ rb_raise(rb_eRangeError, "integer %lu too big to convert to `unsigned short'", num);
}
}
@@ -3534,7 +3439,7 @@ unsigned LONG_LONG
rb_num2ull(VALUE val)
{
if (NIL_P(val)) {
- rb_raise(rb_eTypeError, "no implicit conversion of nil into Integer");
+ rb_raise(rb_eTypeError, "no implicit conversion from nil");
}
else if (FIXNUM_P(val)) {
return (LONG_LONG)FIX2LONG(val); /* this is FIX2LONG, intended */
@@ -3553,10 +3458,15 @@ rb_num2ull(VALUE val)
else if (RB_BIGNUM_TYPE_P(val)) {
return rb_big2ull(val);
}
- else {
- val = rb_to_int(val);
- return NUM2ULL(val);
+ else if (RB_TYPE_P(val, T_STRING)) {
+ rb_raise(rb_eTypeError, "no implicit conversion from string");
+ }
+ else if (RB_TYPE_P(val, T_TRUE) || RB_TYPE_P(val, T_FALSE)) {
+ rb_raise(rb_eTypeError, "no implicit conversion from boolean");
}
+
+ val = rb_to_int(val);
+ return NUM2ULL(val);
}
#endif /* HAVE_LONG_LONG */
@@ -3582,10 +3492,7 @@ rb_num2ull(VALUE val)
*
* First, what's elsewhere. \Class \Integer:
*
- * - Inherits from
- * {class Numeric}[rdoc-ref:Numeric@What-27s+Here]
- * and {class Object}[rdoc-ref:Object@What-27s+Here].
- * - Includes {module Comparable}[rdoc-ref:Comparable@What-27s+Here].
+ * - Inherits from {class Numeric}[rdoc-ref:Numeric@What-27s+Here].
*
* Here, class \Integer provides methods for:
*
@@ -3665,7 +3572,7 @@ rb_int_odd_p(VALUE num)
return RBOOL(num & 2);
}
else {
- RUBY_ASSERT(RB_BIGNUM_TYPE_P(num));
+ assert(RB_BIGNUM_TYPE_P(num));
return rb_big_odd_p(num);
}
}
@@ -3677,7 +3584,7 @@ int_even_p(VALUE num)
return RBOOL((num & 2) == 0);
}
else {
- RUBY_ASSERT(RB_BIGNUM_TYPE_P(num));
+ assert(RB_BIGNUM_TYPE_P(num));
return rb_big_even_p(num);
}
}
@@ -3787,6 +3694,8 @@ int_nobits_p(VALUE num, VALUE mask)
* 1.succ #=> 2
* -1.succ #=> 0
*
+ * Integer#next is an alias for Integer#succ.
+ *
* Related: Integer#pred (predecessor value).
*/
@@ -3934,7 +3843,7 @@ rb_int_uminus(VALUE num)
return fix_uminus(num);
}
else {
- RUBY_ASSERT(RB_BIGNUM_TYPE_P(num));
+ assert(RB_BIGNUM_TYPE_P(num));
return rb_big_uminus(num);
}
}
@@ -3983,7 +3892,7 @@ rb_fix2str(VALUE x, int base)
static VALUE rb_fix_to_s_static[10];
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_fix_to_s(VALUE x)
{
long i = FIX2LONG(x);
@@ -4009,9 +3918,12 @@ rb_fix_to_s(VALUE x)
* 78546939656932.to_s(36) # => "rubyrules"
*
* Raises an exception if +base+ is out of range.
+ *
+ * Integer#inspect is an alias for Integer#to_s.
+ *
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_int_to_s(int argc, VALUE *argv, VALUE x)
{
int base;
@@ -4193,13 +4105,7 @@ static double
fix_fdiv_double(VALUE x, VALUE y)
{
if (FIXNUM_P(y)) {
- long iy = FIX2LONG(y);
-#if SIZEOF_LONG * CHAR_BIT > DBL_MANT_DIG
- if ((iy < 0 ? -iy : iy) >= (1L << DBL_MANT_DIG)) {
- return rb_big_fdiv_double(rb_int2big(FIX2LONG(x)), rb_int2big(iy));
- }
-#endif
- return double_div_double(FIX2LONG(x), iy);
+ return double_div_double(FIX2LONG(x), FIX2LONG(y));
}
else if (RB_BIGNUM_TYPE_P(y)) {
return rb_big_fdiv_double(rb_int2big(FIX2LONG(x)), y);
@@ -4217,7 +4123,7 @@ rb_int_fdiv_double(VALUE x, VALUE y)
{
if (RB_INTEGER_TYPE_P(y) && !FIXNUM_ZERO_P(y)) {
VALUE gcd = rb_gcd(x, y);
- if (!FIXNUM_ZERO_P(gcd) && gcd != INT2FIX(1)) {
+ if (!FIXNUM_ZERO_P(gcd)) {
x = rb_int_idiv(x, gcd);
y = rb_int_idiv(y, gcd);
}
@@ -4339,14 +4245,14 @@ fix_idiv(VALUE x, VALUE y)
* Performs integer division; returns the integer result of dividing +self+
* by +numeric+:
*
- * 4.div(3) # => 1
- * 4.div(-3) # => -2
- * -4.div(3) # => -2
- * -4.div(-3) # => 1
- * 4.div(3.0) # => 1
- * 4.div(Rational(3, 1)) # => 1
+ * 4.div(3) # => 1
+ * 4.div(-3) # => -2
+ * -4.div(3) # => -2
+ * -4.div(-3) # => 1
+ * 4.div(3.0) # => 1
+ * 4.div(Rational(3, 1)) # => 1
*
- * Raises an exception if +numeric+ does not have method +div+.
+ * Raises an exception if +numeric+ does not have method +div+.
*
*/
@@ -4408,6 +4314,8 @@ fix_mod(VALUE x, VALUE y)
* 10 % 3.0 # => 1.0
* 10 % Rational(3, 1) # => (1/1)
*
+ * Integer#modulo is an alias for Integer#%.
+ *
*/
VALUE
rb_int_modulo(VALUE x, VALUE y)
@@ -4448,22 +4356,12 @@ static VALUE
int_remainder(VALUE x, VALUE y)
{
if (FIXNUM_P(x)) {
- if (FIXNUM_P(y)) {
- VALUE z = fix_mod(x, y);
- RUBY_ASSERT(FIXNUM_P(z));
- if (z != INT2FIX(0) && (SIGNED_VALUE)(x ^ y) < 0)
- z = fix_minus(z, y);
- return z;
- }
- else if (!RB_BIGNUM_TYPE_P(y)) {
- return num_remainder(x, y);
- }
- x = rb_int2big(FIX2LONG(x));
+ return num_remainder(x, y);
}
- else if (!RB_BIGNUM_TYPE_P(x)) {
- return Qnil;
+ else if (RB_BIGNUM_TYPE_P(x)) {
+ return rb_big_remainder(x, y);
}
- return rb_big_remainder(x, y);
+ return Qnil;
}
static VALUE
@@ -4726,6 +4624,9 @@ fix_equal(VALUE x, VALUE y)
* 1 == 1.0 #=> true
*
* Related: Integer#eql? (requires +other+ to be an \Integer).
+ *
+ * Integer#=== is an alias for Integer#==.
+ *
*/
VALUE
@@ -4800,7 +4701,7 @@ rb_int_cmp(VALUE x, VALUE y)
return rb_big_cmp(x, y);
}
else {
- rb_raise(rb_eNotImpError, "need to define '<=>' in %s", rb_obj_classname(x));
+ rb_raise(rb_eNotImpError, "need to define `<=>' in %s", rb_obj_classname(x));
}
}
@@ -5260,7 +5161,7 @@ fix_rshift(long val, unsigned long i)
*
*/
-VALUE
+static VALUE
rb_int_rshift(VALUE x, VALUE y)
{
if (FIXNUM_P(x)) {
@@ -5272,7 +5173,7 @@ rb_int_rshift(VALUE x, VALUE y)
return Qnil;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_fix_aref(VALUE fix, VALUE idx)
{
long val = FIX2LONG(fix);
@@ -5442,7 +5343,7 @@ int_aref(int const argc, VALUE * const argv, VALUE const num)
* 1.to_f # => 1.0
* -1.to_f # => -1.0
*
- * If the value of +self+ does not fit in a Float,
+ * If the value of +self+ does not fit in a \Float,
* the result is infinity:
*
* (10**400).to_f # => Infinity
@@ -5496,7 +5397,7 @@ fix_size(VALUE fix)
return INT2FIX(sizeof(long));
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_int_size(VALUE num)
{
if (FIXNUM_P(num)) {
@@ -5535,7 +5436,7 @@ rb_fix_digits(VALUE fix, long base)
VALUE digits;
long x = FIX2LONG(fix);
- RUBY_ASSERT(x >= 0);
+ assert(x >= 0);
if (base < 2)
rb_raise(rb_eArgError, "invalid radix %ld", base);
@@ -5544,12 +5445,11 @@ rb_fix_digits(VALUE fix, long base)
return rb_ary_new_from_args(1, INT2FIX(0));
digits = rb_ary_new();
- while (x >= base) {
+ while (x > 0) {
long q = x % base;
rb_ary_push(digits, LONG2NUM(q));
x /= base;
}
- rb_ary_push(digits, LONG2NUM(x));
return digits;
}
@@ -5559,7 +5459,7 @@ rb_int_digits_bigbase(VALUE num, VALUE base)
{
VALUE digits, bases;
- RUBY_ASSERT(!rb_num_negative_p(num));
+ assert(!rb_num_negative_p(num));
if (RB_BIGNUM_TYPE_P(base))
base = rb_big_norm(base);
@@ -5759,7 +5659,53 @@ int_downto(VALUE from, VALUE to)
static VALUE
int_dotimes_size(VALUE num, VALUE args, VALUE eobj)
{
- return int_neg_p(num) ? INT2FIX(0) : num;
+ if (FIXNUM_P(num)) {
+ if (NUM2LONG(num) <= 0) return INT2FIX(0);
+ }
+ else {
+ if (RTEST(rb_funcall(num, '<', 1, INT2FIX(0)))) return INT2FIX(0);
+ }
+ return num;
+}
+
+/*
+ * call-seq:
+ * times {|i| ... } -> self
+ * times -> enumerator
+ *
+ * Calls the given block +self+ times with each integer in <tt>(0..self-1)</tt>:
+ *
+ * a = []
+ * 5.times {|i| a.push(i) } # => 5
+ * a # => [0, 1, 2, 3, 4]
+ *
+ * With no block given, returns an Enumerator.
+ *
+ */
+
+static VALUE
+int_dotimes(VALUE num)
+{
+ RETURN_SIZED_ENUMERATOR(num, 0, 0, int_dotimes_size);
+
+ if (FIXNUM_P(num)) {
+ long i, end;
+
+ end = FIX2LONG(num);
+ for (i=0; i<end; i++) {
+ rb_yield_1(LONG2FIX(i));
+ }
+ }
+ else {
+ VALUE i = INT2FIX(0);
+
+ for (;;) {
+ if (!RTEST(int_le(i, num))) break;
+ rb_yield(i);
+ i = rb_int_plus(i, INT2FIX(1));
+ }
+ }
+ return num;
}
/*
@@ -5828,56 +5774,24 @@ int_round(int argc, VALUE* argv, VALUE num)
}
/*
- * :markup: markdown
- *
* call-seq:
* floor(ndigits = 0) -> integer
*
- * Returns an integer that is a "floor" value for `self`,
- * as specified by the given `ndigits`,
- * which must be an
- * [integer-convertible object](rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects).
- *
- * - When `self` is zero, returns zero (regardless of the value of `ndigits`):
- *
- * ```
- * 0.floor(2) # => 0
- * 0.floor(-2) # => 0
- * ```
- *
- * - When `self` is non-zero and `ndigits` is non-negative, returns `self`:
- *
- * ```
- * 555.floor # => 555
- * 555.floor(50) # => 555
- * ```
- *
- * - When `self` is non-zero and `ndigits` is negative,
- * returns a value based on a computed granularity:
- *
- * - The granularity is `10 ** ndigits.abs`.
- * - The returned value is the largest multiple of the granularity
- * that is less than or equal to `self`.
+ * Returns the largest number less than or equal to +self+ with
+ * a precision of +ndigits+ decimal digits.
*
- * Examples with positive `self`:
+ * When +ndigits+ is negative, the returned value
+ * has at least <tt>ndigits.abs</tt> trailing zeros:
*
- * | ndigits | Granularity | 1234.floor(ndigits) |
- * |--------:|------------:|--------------------:|
- * | -1 | 10 | 1230 |
- * | -2 | 100 | 1200 |
- * | -3 | 1000 | 1000 |
- * | -4 | 10000 | 0 |
- * | -5 | 100000 | 0 |
+ * 555.floor(-1) # => 550
+ * 555.floor(-2) # => 500
+ * -555.floor(-2) # => -600
+ * 555.floor(-3) # => 0
*
- * Examples with negative `self`:
+ * Returns +self+ when +ndigits+ is zero or positive.
*
- * | ndigits | Granularity | -1234.floor(ndigits) |
- * |--------:|------------:|---------------------:|
- * | -1 | 10 | -1240 |
- * | -2 | 100 | -1300 |
- * | -3 | 1000 | -2000 |
- * | -4 | 10000 | -10000 |
- * | -5 | 100000 | -100000 |
+ * 555.floor # => 555
+ * 555.floor(50) # => 555
*
* Related: Integer#ceil.
*
@@ -5897,58 +5811,27 @@ int_floor(int argc, VALUE* argv, VALUE num)
}
/*
- * :markup: markdown
- *
* call-seq:
* ceil(ndigits = 0) -> integer
*
- * Returns an integer that is a "ceiling" value for `self`,
- * as specified by the given `ndigits`,
- * which must be an
- * [integer-convertible object](rdoc-ref:implicit_conversion.rdoc@Integer-Convertible+Objects).
- *
- * - When `self` is zero, returns zero (regardless of the value of `ndigits`):
- *
- * ```
- * 0.ceil(2) # => 0
- * 0.ceil(-2) # => 0
- * ```
- *
- * - When `self` is non-zero and `ndigits` is non-negative, returns `self`:
- *
- * ```
- * 555.ceil # => 555
- * 555.ceil(50) # => 555
- * ```
- *
- * - When `self` is non-zero and `ndigits` is negative,
- * returns a value based on a computed granularity:
- *
- * - The granularity is `10 ** ndigits.abs`.
- * - The returned value is the smallest multiple of the granularity
- * that is greater than or equal to `self`.
+ * Returns the smallest number greater than or equal to +self+ with
+ * a precision of +ndigits+ decimal digits.
*
- * Examples with positive `self`:
+ * When the precision is negative, the returned value is an integer
+ * with at least <code>ndigits.abs</code> trailing zeros:
*
- * | ndigits | Granularity | 1234.ceil(ndigits) |
- * |--------:|------------:|-------------------:|
- * | -1 | 10 | 1240 |
- * | -2 | 100 | 1300 |
- * | -3 | 1000 | 2000 |
- * | -4 | 10000 | 10000 |
- * | -5 | 100000 | 100000 |
+ * 555.ceil(-1) # => 560
+ * 555.ceil(-2) # => 600
+ * -555.ceil(-2) # => -500
+ * 555.ceil(-3) # => 1000
*
- * Examples with negative `self`:
+ * Returns +self+ when +ndigits+ is zero or positive.
*
- * | ndigits | Granularity | -1234.ceil(ndigits) |
- * |--------:|------------:|--------------------:|
- * | -1 | 10 | -1230 |
- * | -2 | 100 | -1200 |
- * | -3 | 1000 | -1000 |
- * | -4 | 10000 | 0 |
- * | -5 | 100000 | 0 |
+ * 555.ceil # => 555
+ * 555.ceil(50) # => 555
*
* Related: Integer#floor.
+ *
*/
static VALUE
@@ -6105,22 +5988,7 @@ rb_int_s_isqrt(VALUE self, VALUE num)
}
}
-/*
- * call-seq:
- * Integer.try_convert(object) -> object, integer, or nil
- *
- * If +object+ is an \Integer object, returns +object+.
- * Integer.try_convert(1) # => 1
- *
- * Otherwise if +object+ responds to <tt>:to_int</tt>,
- * calls <tt>object.to_int</tt> and returns the result.
- * Integer.try_convert(1.25) # => 1
- *
- * Returns +nil+ if +object+ does not respond to <tt>:to_int</tt>
- * Integer.try_convert([]) # => nil
- *
- * Raises an exception unless <tt>object.to_int</tt> returns an \Integer object.
- */
+/* :nodoc: */
static VALUE
int_s_try_convert(VALUE self, VALUE num)
{
@@ -6153,9 +6021,9 @@ int_s_try_convert(VALUE self, VALUE num)
/*
* Document-class: Numeric
*
- * \Numeric is the class from which all higher-level numeric classes should inherit.
+ * Numeric is the class from which all higher-level numeric classes should inherit.
*
- * \Numeric allows instantiation of heap-allocated objects. Other core numeric classes such as
+ * Numeric allows instantiation of heap-allocated objects. Other core numeric classes such as
* Integer are implemented as immediates, which means that each Integer is a single immutable
* object which is always passed by value.
*
@@ -6169,9 +6037,9 @@ int_s_try_convert(VALUE self, VALUE num)
* 1.dup #=> 1
* 1.object_id == 1.dup.object_id #=> true
*
- * For this reason, \Numeric should be used when defining other numeric classes.
+ * For this reason, Numeric should be used when defining other numeric classes.
*
- * Classes which inherit from \Numeric must implement +coerce+, which returns a two-member
+ * Classes which inherit from Numeric must implement +coerce+, which returns a two-member
* Array containing an object that has been coerced into an instance of the new class
* and +self+ (see #coerce).
*
@@ -6364,6 +6232,7 @@ Init_Numeric(void)
rb_define_method(rb_cInteger, "nobits?", int_nobits_p, 1);
rb_define_method(rb_cInteger, "upto", int_upto, 1);
rb_define_method(rb_cInteger, "downto", int_downto, 1);
+ rb_define_method(rb_cInteger, "times", int_dotimes, 0);
rb_define_method(rb_cInteger, "succ", int_succ, 0);
rb_define_method(rb_cInteger, "next", int_succ, 0);
rb_define_method(rb_cInteger, "pred", int_pred, 0);
@@ -6406,25 +6275,19 @@ Init_Numeric(void)
rb_define_method(rb_cInteger, "digits", rb_int_digits, -1);
-#define fix_to_s_static(n) do { \
- VALUE lit = rb_fstring_literal(#n); \
- rb_fix_to_s_static[n] = lit; \
- rb_vm_register_global_object(lit); \
- RB_GC_GUARD(lit); \
- } while (0)
-
- fix_to_s_static(0);
- fix_to_s_static(1);
- fix_to_s_static(2);
- fix_to_s_static(3);
- fix_to_s_static(4);
- fix_to_s_static(5);
- fix_to_s_static(6);
- fix_to_s_static(7);
- fix_to_s_static(8);
- fix_to_s_static(9);
-
-#undef fix_to_s_static
+ rb_fix_to_s_static[0] = rb_fstring_literal("0");
+ rb_fix_to_s_static[1] = rb_fstring_literal("1");
+ rb_fix_to_s_static[2] = rb_fstring_literal("2");
+ rb_fix_to_s_static[3] = rb_fstring_literal("3");
+ rb_fix_to_s_static[4] = rb_fstring_literal("4");
+ rb_fix_to_s_static[5] = rb_fstring_literal("5");
+ rb_fix_to_s_static[6] = rb_fstring_literal("6");
+ rb_fix_to_s_static[7] = rb_fstring_literal("7");
+ rb_fix_to_s_static[8] = rb_fstring_literal("8");
+ rb_fix_to_s_static[9] = rb_fstring_literal("9");
+ for(int i = 0; i < 10; i++) {
+ rb_gc_register_mark_object(rb_fix_to_s_static[i]);
+ }
rb_cFloat = rb_define_class("Float", rb_cNumeric);
diff --git a/numeric.rb b/numeric.rb
index 852385962e..f026679210 100644
--- a/numeric.rb
+++ b/numeric.rb
@@ -1,56 +1,62 @@
class Numeric
-
+ #
# call-seq:
- # real? -> true or false
+ # num.real? -> true or false
#
- # Returns +true+ if +self+ is a real number (i.e. not Complex).
+ # Returns +true+ if +num+ is a real number (i.e. not Complex).
#
def real?
true
end
+ #
# call-seq:
- # real -> self
+ # num.real -> self
#
- # Returns +self+.
+ # Returns self.
#
def real
self
end
+ #
# call-seq:
- # integer? -> true or false
+ # num.integer? -> true or false
#
- # Returns +true+ if +self+ is an Integer.
+ # Returns +true+ if +num+ is an Integer.
#
- # 1.0.integer? # => false
- # 1.integer? # => true
+ # 1.0.integer? #=> false
+ # 1.integer? #=> true
#
def integer?
false
end
+ #
# call-seq:
- # finite? -> true or false
+ # num.finite? -> true or false
#
- # Returns +true+ if +self+ is a finite number, +false+ otherwise.
+ # Returns +true+ if +num+ is a finite number, otherwise returns +false+.
#
def finite?
true
end
+ #
# call-seq:
- # infinite? -> -1, 1, or nil
+ # num.infinite? -> -1, 1, or nil
#
- # Returns +nil+, -1, or 1 depending on whether +self+ is
- # finite, <tt>-Infinity</tt>, or <tt>+Infinity</tt>.
+ # Returns +nil+, -1, or 1 depending on whether the value is
+ # finite, <code>-Infinity</code>, or <code>+Infinity</code>.
#
def infinite?
nil
end
+ #
# call-seq:
- # imag -> 0
+ # num.imag -> 0
+ # num.imaginary -> 0
#
# Returns zero.
#
@@ -60,10 +66,12 @@ class Numeric
alias imag imaginary
+ #
# call-seq:
- # conj -> self
+ # num.conj -> self
+ # num.conjugate -> self
#
- # Returns +self+.
+ # Returns self.
#
def conjugate
self
@@ -74,296 +82,323 @@ end
class Integer
# call-seq:
- # -int -> integer
+ # -int -> integer
#
- # Returns +self+, negated.
+ # Returns +int+, negated.
def -@
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_uminus(self)'
end
# call-seq:
- # ~int -> integer
- #
- # One's complement:
- # returns the value of +self+ with each bit inverted.
+ # ~int -> integer
#
- # Because an integer value is conceptually of infinite length,
- # the result acts as if it had an infinite number of
- # one bits to the left.
- # In hex representations, this is displayed
- # as two periods to the left of the digits:
+ # One's complement: returns a number where each bit is flipped.
#
- # sprintf("%X", ~0x1122334455) # => "..FEEDDCCBBAA"
+ # Inverts the bits in an Integer. As integers are conceptually of
+ # infinite length, the result acts as if it had an infinite number of
+ # one bits to the left. In hex representations, this is displayed
+ # as two periods to the left of the digits.
#
+ # sprintf("%X", ~0x1122334455) #=> "..FEEDDCCBBAA"
def ~
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_comp(self)'
end
# call-seq:
- # abs -> integer
+ # int.abs -> integer
+ # int.magnitude -> integer
#
- # Returns the absolute value of +self+.
+ # Returns the absolute value of +int+.
#
- # (-12345).abs # => 12345
- # -12345.abs # => 12345
- # 12345.abs # => 12345
+ # (-12345).abs #=> 12345
+ # -12345.abs #=> 12345
+ # 12345.abs #=> 12345
#
+ # Integer#magnitude is an alias for Integer#abs.
def abs
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_abs(self)'
end
# call-seq:
- # bit_length -> integer
+ # int.bit_length -> integer
#
- # Returns the number of bits of the value of +self+,
- # which is the bit position of the highest-order bit
- # that is different from the sign bit
- # (where the least significant bit has bit position 1).
- # If there is no such bit (zero or minus one), returns zero.
- #
- # This method returns <tt>ceil(log2(self < 0 ? -self : self + 1))</tt>>.
- #
- # (-2**1000-1).bit_length # => 1001
- # (-2**1000).bit_length # => 1000
- # (-2**1000+1).bit_length # => 1000
- # (-2**12-1).bit_length # => 13
- # (-2**12).bit_length # => 12
- # (-2**12+1).bit_length # => 12
- # -0x101.bit_length # => 9
- # -0x100.bit_length # => 8
- # -0xff.bit_length # => 8
- # -2.bit_length # => 1
- # -1.bit_length # => 0
- # 0.bit_length # => 0
- # 1.bit_length # => 1
- # 0xff.bit_length # => 8
- # 0x100.bit_length # => 9
- # (2**12-1).bit_length # => 12
- # (2**12).bit_length # => 13
- # (2**12+1).bit_length # => 13
- # (2**1000-1).bit_length # => 1000
- # (2**1000).bit_length # => 1001
- # (2**1000+1).bit_length # => 1001
- #
- # For \Integer _n_,
- # this method can be used to detect overflow in Array#pack:
- #
- # if n.bit_length < 32
- # [n].pack('l') # No overflow.
- # else
- # raise 'Overflow'
- # end
+ # Returns the number of bits of the value of +int+.
#
+ # "Number of bits" means the bit position of the highest bit
+ # which is different from the sign bit
+ # (where the least significant bit has bit position 1).
+ # If there is no such bit (zero or minus one), zero is returned.
+ #
+ # I.e. this method returns <i>ceil(log2(int < 0 ? -int : int+1))</i>.
+ #
+ # (-2**1000-1).bit_length #=> 1001
+ # (-2**1000).bit_length #=> 1000
+ # (-2**1000+1).bit_length #=> 1000
+ # (-2**12-1).bit_length #=> 13
+ # (-2**12).bit_length #=> 12
+ # (-2**12+1).bit_length #=> 12
+ # -0x101.bit_length #=> 9
+ # -0x100.bit_length #=> 8
+ # -0xff.bit_length #=> 8
+ # -2.bit_length #=> 1
+ # -1.bit_length #=> 0
+ # 0.bit_length #=> 0
+ # 1.bit_length #=> 1
+ # 0xff.bit_length #=> 8
+ # 0x100.bit_length #=> 9
+ # (2**12-1).bit_length #=> 12
+ # (2**12).bit_length #=> 13
+ # (2**12+1).bit_length #=> 13
+ # (2**1000-1).bit_length #=> 1000
+ # (2**1000).bit_length #=> 1001
+ # (2**1000+1).bit_length #=> 1001
+ #
+ # This method can be used to detect overflow in Array#pack as follows:
+ #
+ # if n.bit_length < 32
+ # [n].pack("l") # no overflow
+ # else
+ # raise "overflow"
+ # end
def bit_length
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_bit_length(self)'
end
# call-seq:
- # even? -> true or false
+ # int.even? -> true or false
#
- # Returns +true+ if +self+ is an even number, +false+ otherwise.
+ # Returns +true+ if +int+ is an even number.
def even?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_even_p(self)'
end
# call-seq:
- # integer? -> true
+ # int.integer? -> true
#
- # Since +self+ is already an \Integer, always returns +true+.
+ # Since +int+ is already an Integer, this always returns +true+.
def integer?
true
end
alias magnitude abs
+=begin
+ def magnitude
+ Primitive.attr! 'inline'
+ Primitive.cexpr! 'rb_int_abs(self)'
+ end
+=end
# call-seq:
- # odd? -> true or false
+ # int.odd? -> true or false
#
- # Returns +true+ if +self+ is an odd number, +false+ otherwise.
+ # Returns +true+ if +int+ is an odd number.
def odd?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_odd_p(self)'
end
# call-seq:
- # ord -> self
+ # int.ord -> self
+ #
+ # Returns the +int+ itself.
+ #
+ # 97.ord #=> 97
+ #
+ # This method is intended for compatibility to character literals
+ # in Ruby 1.9.
#
- # Returns +self+;
- # intended for compatibility to character literals in Ruby 1.9.
+ # For example, <code>?a.ord</code> returns 97 both in 1.8 and 1.9.
def ord
self
end
+ #
+ # Document-method: Integer#size
# call-seq:
- # size -> integer
+ # int.size -> int
#
- # Returns the number of bytes in the machine representation of +self+;
- # the value is system-dependent:
+ # Returns the number of bytes in the machine representation of +int+
+ # (machine dependent).
#
- # 1.size # => 8
- # -1.size # => 8
- # 2147483647.size # => 8
- # (256**10 - 1).size # => 10
- # (256**20 - 1).size # => 20
- # (256**40 - 1).size # => 40
+ # 1.size #=> 8
+ # -1.size #=> 8
+ # 2147483647.size #=> 8
+ # (256**10 - 1).size #=> 10
+ # (256**20 - 1).size #=> 20
+ # (256**40 - 1).size #=> 40
#
def size
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_size(self)'
end
- # call-seq:
- # times {|i| ... } -> self
- # times -> enumerator
- #
- # Calls the given block +self+ times with each integer in <tt>(0..self-1)</tt>:
- #
- # a = []
- # 5.times {|i| a.push(i) } # => 5
- # a # => [0, 1, 2, 3, 4]
- #
- # With no block given, returns an Enumerator.
- def times
- Primitive.attr! :inline_block
- unless defined?(yield)
- return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, int_dotimes_size)'
- end
- i = 0
- while i < self
- yield i
- i = i.succ
- end
- self
- end
-
# call-seq:
- # to_i -> self
+ # int.to_i -> integer
#
- # Returns +self+ (which is already an \Integer).
+ # Since +int+ is already an Integer, returns +self+.
+ #
+ # #to_int is an alias for #to_i.
def to_i
self
end
# call-seq:
- # to_int -> self
+ # int.to_int -> integer
#
- # Returns +self+ (which is already an \Integer).
+ # Since +int+ is already an Integer, returns +self+.
def to_int
self
end
# call-seq:
- # zero? -> true or false
+ # int.zero? -> true or false
#
- # Returns +true+ if +self+ has a zero value, +false+ otherwise.
+ # Returns +true+ if +int+ has a zero value.
def zero?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_int_zero_p(self)'
end
# call-seq:
- # ceildiv(numeric) -> integer
+ # ceildiv(other) -> integer
#
- # Returns the result of division +self+ by +numeric+.
- # rounded up to the nearest integer.
+ # Returns the result of division +self+ by +other+. The result is rounded up to the nearest integer.
#
- # 3.ceildiv(3) # => 1
- # 4.ceildiv(3) # => 2
+ # 3.ceildiv(3) # => 1
+ # 4.ceildiv(3) # => 2
#
- # 4.ceildiv(-3) # => -1
- # -4.ceildiv(3) # => -1
+ # 4.ceildiv(-3) # => -1
+ # -4.ceildiv(3) # => -1
# -4.ceildiv(-3) # => 2
#
# 3.ceildiv(1.2) # => 3
- #
def ceildiv(other)
- -div(0 - other)
+ -div(-other)
end
#
# call-seq:
- # numerator -> self
+ # int.numerator -> self
#
- # Returns +self+.
+ # Returns self.
#
def numerator
self
end
+ #
# call-seq:
- # denominator -> 1
+ # int.denominator -> 1
+ #
+ # Returns 1.
#
- # Returns +1+.
def denominator
1
end
end
-class Float
+# call-seq:
+# Integer.try_convert(object) -> object, integer, or nil
+#
+# If +object+ is an \Integer object, returns +object+.
+# Integer.try_convert(1) # => 1
+#
+# Otherwise if +object+ responds to <tt>:to_int</tt>,
+# calls <tt>object.to_int</tt> and returns the result.
+# Integer.try_convert(1.25) # => 1
+#
+# Returns +nil+ if +object+ does not respond to <tt>:to_int</tt>
+# Integer.try_convert([]) # => nil
+#
+# Raises an exception unless <tt>object.to_int</tt> returns an \Integer object.
+#
+def Integer.try_convert(num)
+=begin
+ Primitive.attr! 'inline'
+ Primitive.cexpr! 'rb_check_integer_type(num)'
+=end
+end if false
+class Float
+ #
# call-seq:
- # to_f -> self
+ # float.to_f -> self
+ #
+ # Since +float+ is already a Float, returns +self+.
#
- # Returns +self+ (which is already a \Float).
def to_f
self
end
+ #
# call-seq:
- # float.abs -> float
+ # float.abs -> float
+ # float.magnitude -> float
+ #
+ # Returns the absolute value of +float+.
#
- # Returns the absolute value of +self+:
+ # (-34.56).abs #=> 34.56
+ # -34.56.abs #=> 34.56
+ # 34.56.abs #=> 34.56
#
- # (-34.56).abs # => 34.56
- # -34.56.abs # => 34.56
- # 34.56.abs # => 34.56
+ # Float#magnitude is an alias for Float#abs.
#
def abs
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_float_abs(self)'
end
- alias magnitude abs
+ def magnitude
+ Primitive.attr! 'inline'
+ Primitive.cexpr! 'rb_float_abs(self)'
+ end
+ #
# call-seq:
- # -float -> float
+ # -float -> float
#
- # Returns +self+, negated.
+ # Returns +float+, negated.
#
def -@
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'rb_float_uminus(self)'
end
+ #
# call-seq:
- # zero? -> true or false
+ # float.zero? -> true or false
+ #
+ # Returns +true+ if +float+ is 0.0.
#
- # Returns +true+ if +self+ is 0.0, +false+ otherwise.
def zero?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'RBOOL(FLOAT_ZERO_P(self))'
end
+ #
# call-seq:
- # positive? -> true or false
+ # float.positive? -> true or false
+ #
+ # Returns +true+ if +float+ is greater than 0.
#
- # Returns +true+ if +self+ is greater than 0, +false+ otherwise.
def positive?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'RBOOL(RFLOAT_VALUE(self) > 0.0)'
end
+ #
# call-seq:
- # negative? -> true or false
+ # float.negative? -> true or false
+ #
+ # Returns +true+ if +float+ is less than 0.
#
- # Returns +true+ if +self+ is less than 0, +false+ otherwise.
def negative?
- Primitive.attr! :leaf
+ Primitive.attr! 'inline'
Primitive.cexpr! 'RBOOL(RFLOAT_VALUE(self) < 0.0)'
end
diff --git a/object.c b/object.c
index 1bd476b022..e1fc72c89f 100644
--- a/object.c
+++ b/object.c
@@ -31,7 +31,6 @@
#include "internal/object.h"
#include "internal/struct.h"
#include "internal/string.h"
-#include "internal/st.h"
#include "internal/symbol.h"
#include "internal/variable.h"
#include "variable.h"
@@ -42,19 +41,6 @@
#include "ruby/assert.h"
#include "builtin.h"
#include "shape.h"
-#include "yjit.h"
-
-/* Flags of RObject
- *
- * 1: ROBJECT_EMBED
- * The object has its instance variables embedded (the array of
- * instance variables directly follow the object, rather than being
- * on a separately allocated buffer).
- * if !SHAPE_IN_BASIC_FLAGS
- * 4-19: SHAPE_FLAG_MASK
- * Shape ID for the object.
- * endif
- */
/*!
* \addtogroup object
@@ -94,12 +80,6 @@ static VALUE rb_cFalseClass_to_s;
/*! \endcond */
-size_t
-rb_obj_embedded_size(uint32_t numiv)
-{
- return offsetof(struct RObject, as.ary) + (sizeof(VALUE) * numiv);
-}
-
VALUE
rb_obj_hide(VALUE obj)
{
@@ -119,36 +99,6 @@ rb_obj_reveal(VALUE obj, VALUE klass)
}
VALUE
-rb_class_allocate_instance(VALUE klass)
-{
- uint32_t index_tbl_num_entries = RCLASS_EXT(klass)->max_iv_count;
-
- size_t size = rb_obj_embedded_size(index_tbl_num_entries);
- if (!rb_gc_size_allocatable_p(size)) {
- size = sizeof(struct RObject);
- }
-
- NEWOBJ_OF(o, struct RObject, klass,
- T_OBJECT | ROBJECT_EMBED | (RGENGC_WB_PROTECTED_OBJECT ? FL_WB_PROTECTED : 0), size, 0);
- VALUE obj = (VALUE)o;
-
- RUBY_ASSERT(rb_shape_get_shape(obj)->type == SHAPE_ROOT);
-
- // Set the shape to the specific T_OBJECT shape.
- ROBJECT_SET_SHAPE_ID(obj, (shape_id_t)(rb_gc_heap_id_for_size(size) + FIRST_T_OBJECT_SHAPE_ID));
-
-#if RUBY_DEBUG
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
- VALUE *ptr = ROBJECT_IVPTR(obj);
- for (size_t i = 0; i < ROBJECT_IV_CAPACITY(obj); i++) {
- ptr[i] = Qundef;
- }
-#endif
-
- return obj;
-}
-
-VALUE
rb_obj_setup(VALUE obj, VALUE klass, VALUE type)
{
VALUE ignored_flags = RUBY_FL_PROMOTED | RUBY_FL_SEEN_OBJ_ID;
@@ -157,19 +107,13 @@ rb_obj_setup(VALUE obj, VALUE klass, VALUE type)
return obj;
}
-/*
- * call-seq:
- * true === other -> true or false
- * false === other -> true or false
- * nil === other -> true or false
- *
- * Returns +true+ or +false+.
- *
- * Like Object#==, if +object+ is an instance of Object
- * (and not an instance of one of its many subclasses).
+/**
+ * call-seq:
+ * obj === other -> true or false
*
- * This method is commonly overridden by those subclasses,
- * to provide meaningful semantics in +case+ statements.
+ * Case Equality -- For class Object, effectively the same as calling
+ * <code>#==</code>, but typically overridden by descendants to provide
+ * meaningful semantics in +case+ statements.
*/
#define case_equal rb_equal
/* The default implementation of #=== is
@@ -242,7 +186,7 @@ rb_eql(VALUE obj1, VALUE obj2)
* \private
*++
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_obj_equal(VALUE obj1, VALUE obj2)
{
return RBOOL(obj1 == obj2);
@@ -260,7 +204,7 @@ VALUE rb_obj_hash(VALUE obj);
*++
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_obj_not(VALUE obj)
{
return RBOOL(!RTEST(obj));
@@ -276,7 +220,7 @@ rb_obj_not(VALUE obj)
*++
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_obj_not_equal(VALUE obj1, VALUE obj2)
{
VALUE result = rb_funcall(obj1, id_eq, 1, obj2);
@@ -287,7 +231,7 @@ VALUE
rb_class_real(VALUE cl)
{
while (cl &&
- (RCLASS_SINGLETON_P(cl) || BUILTIN_TYPE(cl) == T_ICLASS)) {
+ ((RBASIC(cl)->flags & FL_SINGLETON) || BUILTIN_TYPE(cl) == T_ICLASS)) {
cl = RCLASS_SUPER(cl);
}
return cl;
@@ -323,7 +267,7 @@ rb_obj_singleton_class(VALUE obj)
}
/*! \private */
-void
+MJIT_FUNC_EXPORTED void
rb_obj_copy_ivar(VALUE dest, VALUE obj)
{
RUBY_ASSERT(!RB_TYPE_P(obj, T_CLASS) && !RB_TYPE_P(obj, T_MODULE));
@@ -331,10 +275,13 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
RUBY_ASSERT(BUILTIN_TYPE(dest) == BUILTIN_TYPE(obj));
rb_shape_t * src_shape = rb_shape_get_shape(obj);
- if (rb_shape_obj_too_complex(obj)) {
- // obj is TOO_COMPLEX so we can copy its iv_hash
+ if (rb_shape_id(src_shape) == OBJ_TOO_COMPLEX_SHAPE_ID) {
st_table *table = st_copy(ROBJECT_IV_HASH(obj));
- rb_obj_convert_to_too_complex(dest, table);
+
+ rb_ivar_foreach(obj, rb_obj_evacuate_ivs_to_hash_table, (st_data_t)table);
+ rb_shape_set_too_complex(dest);
+
+ ROBJECT(dest)->as.heap.ivptr = (VALUE *)table;
return;
}
@@ -358,20 +305,13 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
rb_shape_t * initial_shape = rb_shape_get_shape(dest);
- if (initial_shape->heap_index != src_shape->heap_index) {
+ if (initial_shape->size_pool_index != src_shape->size_pool_index) {
RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
shape_to_set_on_dest = rb_shape_rebuild_shape(initial_shape, src_shape);
- if (UNLIKELY(rb_shape_id(shape_to_set_on_dest) == OBJ_TOO_COMPLEX_SHAPE_ID)) {
- st_table * table = rb_st_init_numtable_with_size(src_num_ivs);
- rb_obj_copy_ivs_to_hash_table(obj, table);
- rb_obj_convert_to_too_complex(dest, table);
-
- return;
- }
}
- RUBY_ASSERT(src_num_ivs <= shape_to_set_on_dest->capacity || rb_shape_id(shape_to_set_on_dest) == OBJ_TOO_COMPLEX_SHAPE_ID);
+ RUBY_ASSERT(src_num_ivs <= shape_to_set_on_dest->capacity);
if (initial_shape->capacity < shape_to_set_on_dest->capacity) {
rb_ensure_iv_list_size(dest, initial_shape->capacity, shape_to_set_on_dest->capacity);
dest_buf = ROBJECT_IVPTR(dest);
@@ -396,8 +336,10 @@ init_copy(VALUE dest, VALUE obj)
RBASIC(dest)->flags &= ~(T_MASK|FL_EXIVAR);
// Copies the shape id from obj to dest
RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR);
- rb_gc_copy_attributes(dest, obj);
+ rb_copy_wb_protected_attribute(dest, obj);
rb_copy_generic_ivar(dest, obj);
+ rb_gc_copy_finalizer(dest, obj);
+
if (RB_TYPE_P(obj, T_OBJECT)) {
rb_obj_copy_ivar(dest, obj);
}
@@ -483,14 +425,17 @@ immutable_obj_clone(VALUE obj, VALUE kwfreeze)
return obj;
}
-VALUE
-rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
+static VALUE
+mutable_obj_clone(VALUE obj, VALUE kwfreeze)
{
+ VALUE clone, singleton;
VALUE argv[2];
- VALUE singleton = rb_singleton_class_clone_and_attach(obj, clone);
+ clone = rb_obj_alloc(rb_obj_class(obj));
+
+ singleton = rb_singleton_class_clone_and_attach(obj, clone);
RBASIC_SET_CLASS(clone, singleton);
- if (RCLASS_SINGLETON_P(singleton)) {
+ if (FL_TEST(singleton, FL_SINGLETON)) {
rb_singleton_class_attached(singleton, clone);
}
@@ -500,24 +445,16 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
case Qnil:
rb_funcall(clone, id_init_clone, 1, obj);
RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE;
- if (CHILLED_STRING_P(obj)) {
- STR_CHILL_RAW(clone);
- }
- else if (RB_OBJ_FROZEN(obj)) {
- rb_shape_t * next_shape = rb_shape_transition_shape_frozen(clone);
- if (!rb_shape_obj_too_complex(clone) && next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
- rb_evict_ivars_to_hash(clone);
- }
- else {
- rb_shape_set_shape(clone, next_shape);
- }
+ if (RB_OBJ_FROZEN(obj)) {
+ rb_shape_transition_shape_frozen(clone);
}
break;
- case Qtrue: {
+ case Qtrue:
+ {
static VALUE freeze_true_hash;
if (!freeze_true_hash) {
freeze_true_hash = rb_hash_new();
- rb_vm_register_global_object(freeze_true_hash);
+ rb_gc_register_mark_object(freeze_true_hash);
rb_hash_aset(freeze_true_hash, ID2SYM(idFreeze), Qtrue);
rb_obj_freeze(freeze_true_hash);
}
@@ -526,22 +463,15 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
argv[1] = freeze_true_hash;
rb_funcallv_kw(clone, id_init_clone, 2, argv, RB_PASS_KEYWORDS);
RBASIC(clone)->flags |= FL_FREEZE;
- rb_shape_t * next_shape = rb_shape_transition_shape_frozen(clone);
- // If we're out of shapes, but we want to freeze, then we need to
- // evacuate this clone to a hash
- if (!rb_shape_obj_too_complex(clone) && next_shape->type == SHAPE_OBJ_TOO_COMPLEX) {
- rb_evict_ivars_to_hash(clone);
- }
- else {
- rb_shape_set_shape(clone, next_shape);
- }
+ rb_shape_transition_shape_frozen(clone);
break;
- }
- case Qfalse: {
+ }
+ case Qfalse:
+ {
static VALUE freeze_false_hash;
if (!freeze_false_hash) {
freeze_false_hash = rb_hash_new();
- rb_vm_register_global_object(freeze_false_hash);
+ rb_gc_register_mark_object(freeze_false_hash);
rb_hash_aset(freeze_false_hash, ID2SYM(idFreeze), Qfalse);
rb_obj_freeze(freeze_false_hash);
}
@@ -550,7 +480,7 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
argv[1] = freeze_false_hash;
rb_funcallv_kw(clone, id_init_clone, 2, argv, RB_PASS_KEYWORDS);
break;
- }
+ }
default:
rb_bug("invalid kwfreeze passed to mutable_obj_clone");
}
@@ -558,13 +488,6 @@ rb_obj_clone_setup(VALUE obj, VALUE clone, VALUE kwfreeze)
return clone;
}
-static VALUE
-mutable_obj_clone(VALUE obj, VALUE kwfreeze)
-{
- VALUE clone = rb_obj_alloc(rb_obj_class(obj));
- return rb_obj_clone_setup(obj, clone, kwfreeze);
-}
-
VALUE
rb_obj_clone(VALUE obj)
{
@@ -572,15 +495,6 @@ rb_obj_clone(VALUE obj)
return mutable_obj_clone(obj, Qnil);
}
-VALUE
-rb_obj_dup_setup(VALUE obj, VALUE dup)
-{
- init_copy(dup, obj);
- rb_funcall(dup, id_init_dup, 1, obj);
-
- return dup;
-}
-
/*
* call-seq:
* obj.dup -> an_object
@@ -629,7 +543,10 @@ rb_obj_dup(VALUE obj)
return obj;
}
dup = rb_obj_alloc(rb_obj_class(obj));
- return rb_obj_dup_setup(obj, dup);
+ init_copy(dup, obj);
+ rb_funcall(dup, id_init_dup, 1, obj);
+
+ return dup;
}
/*
@@ -655,12 +572,18 @@ rb_obj_size(VALUE self, VALUE args, VALUE obj)
return LONG2FIX(1);
}
+static VALUE
+block_given_p(rb_execution_context_t *ec, VALUE self)
+{
+ return RBOOL(rb_block_given_p());
+}
+
/**
* :nodoc:
*--
- * Default implementation of `#initialize_copy`
- * @param[in,out] obj the receiver being initialized
- * @param[in] orig the object to be copied from.
+ * Default implementation of \c #initialize_copy
+ * \param[in,out] obj the receiver being initialized
+ * \param[in] orig the object to be copied from.
*++
*/
VALUE
@@ -674,13 +597,13 @@ rb_obj_init_copy(VALUE obj, VALUE orig)
return obj;
}
-/**
+/*!
* :nodoc:
*--
- * Default implementation of `#initialize_dup`
+ * Default implementation of \c #initialize_dup
*
- * @param[in,out] obj the receiver being initialized
- * @param[in] orig the object to be dup from.
+ * \param[in,out] obj the receiver being initialized
+ * \param[in] orig the object to be dup from.
*++
**/
VALUE
@@ -690,14 +613,14 @@ rb_obj_init_dup_clone(VALUE obj, VALUE orig)
return obj;
}
-/**
+/*!
* :nodoc:
*--
- * Default implementation of `#initialize_clone`
+ * Default implementation of \c #initialize_clone
*
- * @param[in] The number of arguments
- * @param[in] The array of arguments
- * @param[in] obj the receiver being initialized
+ * \param[in] The number of arguments
+ * \param[in] The array of arguments
+ * \param[in] obj the receiver being initialized
*++
**/
static VALUE
@@ -751,8 +674,10 @@ rb_inspect(VALUE obj)
}
static int
-inspect_i(ID id, VALUE value, st_data_t a)
+inspect_i(st_data_t k, st_data_t v, st_data_t a)
{
+ ID id = (ID)k;
+ VALUE value = (VALUE)v;
VALUE str = (VALUE)a;
/* need not to show internal data */
@@ -869,7 +794,7 @@ rb_obj_is_instance_of(VALUE obj, VALUE c)
return RBOOL(rb_obj_class(obj) == c);
}
-// Returns whether c is a proper (c != cl) superclass of cl
+// Returns whether c is a proper (c != cl) subclass of cl
// Both c and cl must be T_CLASS
static VALUE
class_search_class_ancestor(VALUE cl, VALUE c)
@@ -882,7 +807,7 @@ class_search_class_ancestor(VALUE cl, VALUE c)
VALUE *classes = RCLASS_SUPERCLASSES(cl);
// If c's inheritance chain is longer, it cannot be an ancestor
- // We are checking for a proper superclass so don't check if they are equal
+ // We are checking for a proper subclass so don't check if they are equal
if (cl_depth <= c_depth)
return Qfalse;
@@ -1335,47 +1260,17 @@ rb_obj_frozen_p(VALUE obj)
/*
* Document-class: NilClass
*
- * The class of the singleton object +nil+.
- *
- * Several of its methods act as operators:
- *
- * - #&
- * - #|
- * - #===
- * - #=~
- * - #^
- *
- * Others act as converters, carrying the concept of _nullity_
- * to other classes:
- *
- * - #rationalize
- * - #to_a
- * - #to_c
- * - #to_h
- * - #to_r
- * - #to_s
- *
- * Another method provides inspection:
- *
- * - #inspect
- *
- * Finally, there is this query method:
- *
- * - #nil?
- *
+ * The class of the singleton object <code>nil</code>.
*/
/*
- * call-seq:
- * to_s -> ''
- *
- * Returns an empty String:
- *
- * nil.to_s # => ""
+ * call-seq:
+ * nil.to_s -> ""
*
+ * Always returns the empty string.
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_nil_to_s(VALUE obj)
{
return rb_cNilClass_to_s;
@@ -1384,13 +1279,12 @@ rb_nil_to_s(VALUE obj)
/*
* Document-method: to_a
*
- * call-seq:
- * to_a -> []
- *
- * Returns an empty Array.
+ * call-seq:
+ * nil.to_a -> []
*
- * nil.to_a # => []
+ * Always returns an empty array.
*
+ * nil.to_a #=> []
*/
static VALUE
@@ -1402,13 +1296,12 @@ nil_to_a(VALUE obj)
/*
* Document-method: to_h
*
- * call-seq:
- * to_h -> {}
- *
- * Returns an empty Hash.
+ * call-seq:
+ * nil.to_h -> {}
*
- * nil.to_h #=> {}
+ * Always returns an empty hash.
*
+ * nil.to_h #=> {}
*/
static VALUE
@@ -1418,13 +1311,10 @@ nil_to_h(VALUE obj)
}
/*
- * call-seq:
- * inspect -> 'nil'
- *
- * Returns string <tt>'nil'</tt>:
- *
- * nil.inspect # => "nil"
+ * call-seq:
+ * nil.inspect -> "nil"
*
+ * Always returns the string "nil".
*/
static VALUE
@@ -1434,17 +1324,12 @@ nil_inspect(VALUE obj)
}
/*
- * call-seq:
- * nil =~ object -> nil
- *
- * Returns +nil+.
- *
- * This method makes it useful to write:
+ * call-seq:
+ * nil =~ other -> nil
*
- * while gets =~ /re/
- * # ...
- * end
+ * Dummy pattern matching -- always returns nil.
*
+ * This method makes it possible to `while gets =~ /re/ do`.
*/
static VALUE
@@ -1453,38 +1338,24 @@ nil_match(VALUE obj1, VALUE obj2)
return Qnil;
}
-/*
+/***********************************************************************
* Document-class: TrueClass
*
- * The class of the singleton object +true+.
- *
- * Several of its methods act as operators:
- *
- * - #&
- * - #|
- * - #===
- * - #^
- *
- * One other method:
- *
- * - #to_s and its alias #inspect.
- *
+ * The global value <code>true</code> is the only instance of class
+ * TrueClass and represents a logically true value in
+ * boolean expressions. The class provides operators allowing
+ * <code>true</code> to be used in logical expressions.
*/
/*
* call-seq:
- * true.to_s -> 'true'
- *
- * Returns string <tt>'true'</tt>:
- *
- * true.to_s # => "true"
- *
- * TrueClass#inspect is an alias for TrueClass#to_s.
+ * true.to_s -> "true"
*
+ * The string representation of <code>true</code> is "true".
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_true_to_s(VALUE obj)
{
return rb_cTrueClass_to_s;
@@ -1493,14 +1364,10 @@ rb_true_to_s(VALUE obj)
/*
* call-seq:
- * true & object -> true or false
- *
- * Returns +false+ if +object+ is +false+ or +nil+, +true+ otherwise:
- *
- * true & Object.new # => true
- * true & false # => false
- * true & nil # => false
+ * true & obj -> true or false
*
+ * And---Returns <code>false</code> if <i>obj</i> is
+ * <code>nil</code> or <code>false</code>, <code>true</code> otherwise.
*/
static VALUE
@@ -1511,21 +1378,18 @@ true_and(VALUE obj, VALUE obj2)
/*
* call-seq:
- * true | object -> true
+ * true | obj -> true
*
- * Returns +true+:
+ * Or---Returns <code>true</code>. As <i>obj</i> is an argument to
+ * a method call, it is always evaluated; there is no short-circuit
+ * evaluation in this case.
*
- * true | Object.new # => true
- * true | false # => true
- * true | nil # => true
+ * true | puts("or")
+ * true || puts("logical or")
*
- * Argument +object+ is evaluated.
- * This is different from +true+ with the short-circuit operator,
- * whose operand is evaluated only if necessary:
- *
- * true | raise # => Raises RuntimeError.
- * true || raise # => true
+ * <em>produces:</em>
*
+ * or
*/
static VALUE
@@ -1537,14 +1401,11 @@ true_or(VALUE obj, VALUE obj2)
/*
* call-seq:
- * true ^ object -> !object
- *
- * Returns +true+ if +object+ is +false+ or +nil+, +false+ otherwise:
- *
- * true ^ Object.new # => false
- * true ^ false # => true
- * true ^ nil # => true
+ * true ^ obj -> !obj
*
+ * Exclusive Or---Returns <code>true</code> if <i>obj</i> is
+ * <code>nil</code> or <code>false</code>, <code>false</code>
+ * otherwise.
*/
static VALUE
@@ -1571,27 +1432,22 @@ true_xor(VALUE obj, VALUE obj2)
* The string representation of <code>false</code> is "false".
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_false_to_s(VALUE obj)
{
return rb_cFalseClass_to_s;
}
/*
- * call-seq:
- * false & object -> false
- * nil & object -> false
- *
- * Returns +false+:
- *
- * false & true # => false
- * false & Object.new # => false
- *
- * Argument +object+ is evaluated:
- *
- * false & raise # Raises RuntimeError.
+ * call-seq:
+ * false & obj -> false
+ * nil & obj -> false
*
+ * And---Returns <code>false</code>. <i>obj</i> is always
+ * evaluated as it is the argument to a method call---there is no
+ * short-circuit evaluation in this case.
*/
+
static VALUE
false_and(VALUE obj, VALUE obj2)
{
@@ -1600,30 +1456,24 @@ false_and(VALUE obj, VALUE obj2)
/*
- * call-seq:
- * false | object -> true or false
- * nil | object -> true or false
- *
- * Returns +false+ if +object+ is +nil+ or +false+, +true+ otherwise:
- *
- * nil | nil # => false
- * nil | false # => false
- * nil | Object.new # => true
+ * call-seq:
+ * false | obj -> true or false
+ * nil | obj -> true or false
*
+ * Or---Returns <code>false</code> if <i>obj</i> is
+ * <code>nil</code> or <code>false</code>; <code>true</code> otherwise.
*/
#define false_or true_and
/*
- * call-seq:
- * false ^ object -> true or false
- * nil ^ object -> true or false
- *
- * Returns +false+ if +object+ is +nil+ or +false+, +true+ otherwise:
+ * call-seq:
+ * false ^ obj -> true or false
+ * nil ^ obj -> true or false
*
- * nil ^ nil # => false
- * nil ^ false # => false
- * nil ^ Object.new # => true
+ * Exclusive Or---If <i>obj</i> is <code>nil</code> or
+ * <code>false</code>, returns <code>false</code>; otherwise, returns
+ * <code>true</code>.
*
*/
@@ -1631,10 +1481,9 @@ false_and(VALUE obj, VALUE obj2)
/*
* call-seq:
- * nil.nil? -> true
+ * nil.nil? -> true
*
- * Returns +true+.
- * For all other objects, method <tt>nil?</tt> returns +false+.
+ * Only the object <i>nil</i> responds <code>true</code> to <code>nil?</code>.
*/
static VALUE
@@ -1654,7 +1503,7 @@ rb_true(VALUE obj)
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_false(VALUE obj)
{
return Qfalse;
@@ -1739,15 +1588,15 @@ rb_obj_cmp(VALUE obj1, VALUE obj2)
* show information on the thing we're attached to as well.
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_mod_to_s(VALUE klass)
{
ID id_defined_at;
VALUE refined_class, defined_at;
- if (RCLASS_SINGLETON_P(klass)) {
+ if (FL_TEST(klass, FL_SINGLETON)) {
VALUE s = rb_usascii_str_new2("#<Class:");
- VALUE v = RCLASS_ATTACHED_OBJECT(klass);
+ VALUE v = rb_ivar_get(klass, id__attached__);
if (CLASS_OR_MODULE_P(v)) {
rb_str_append(s, rb_inspect(v));
@@ -2121,7 +1970,7 @@ class_get_alloc_func(VALUE klass)
if (RCLASS_SUPER(klass) == 0 && klass != rb_cBasicObject) {
rb_raise(rb_eTypeError, "can't instantiate uninitialized class");
}
- if (RCLASS_SINGLETON_P(klass)) {
+ if (FL_TEST(klass, FL_SINGLETON)) {
rb_raise(rb_eTypeError, "can't create instance of singleton class");
}
allocator = rb_get_alloc_func(klass);
@@ -2211,12 +2060,12 @@ rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
* BasicObject.superclass #=> nil
*
*--
- * Returns the superclass of `klass`. Equivalent to `Class#superclass` in Ruby.
+ * Returns the superclass of \a klass. Equivalent to \c Class\#superclass in Ruby.
*
* It skips modules.
- * @param[in] klass a Class object
- * @return the superclass, or `Qnil` if `klass` does not have a parent class.
- * @sa rb_class_get_superclass
+ * \param[in] klass a Class object
+ * \return the superclass, or \c Qnil if \a klass does not have a parent class.
+ * \sa rb_class_get_superclass
*++
*/
@@ -2248,10 +2097,10 @@ rb_class_get_superclass(VALUE klass)
return RCLASS(klass)->super;
}
-static const char bad_instance_name[] = "'%1$s' is not allowed as an instance variable name";
-static const char bad_class_name[] = "'%1$s' is not allowed as a class variable name";
+static const char bad_instance_name[] = "`%1$s' is not allowed as an instance variable name";
+static const char bad_class_name[] = "`%1$s' is not allowed as a class variable name";
static const char bad_const_name[] = "wrong constant name %1$s";
-static const char bad_attr_name[] = "invalid attribute name '%1$s'";
+static const char bad_attr_name[] = "invalid attribute name `%1$s'";
#define wrong_constant_name bad_const_name
/*! \private */
@@ -3082,7 +2931,7 @@ rb_mod_cvar_defined(VALUE obj, VALUE iv)
static VALUE
rb_mod_singleton_p(VALUE klass)
{
- return RBOOL(RCLASS_SINGLETON_P(klass));
+ return RBOOL(RB_TYPE_P(klass, T_CLASS) && FL_TEST(klass, FL_SINGLETON));
}
/*! \private */
@@ -3213,7 +3062,7 @@ rb_check_convert_type(VALUE val, int type, const char *tname, const char *method
}
/*! \private */
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_check_convert_type_with_id(VALUE val, int type, const char *tname, ID method)
{
VALUE v;
@@ -3236,22 +3085,14 @@ ALWAYS_INLINE(static VALUE rb_to_integer_with_id_exception(VALUE val, const char
static inline VALUE
rb_to_integer_with_id_exception(VALUE val, const char *method, ID mid, int raise)
{
- // We need to pop the lazily pushed frame when not raising an exception.
- rb_control_frame_t *current_cfp;
VALUE v;
if (RB_INTEGER_TYPE_P(val)) return val;
- current_cfp = GET_EC()->cfp;
- rb_yjit_lazy_push_frame(GET_EC()->cfp->pc);
v = try_to_int(val, mid, raise);
- if (!raise && NIL_P(v)) {
- GET_EC()->cfp = current_cfp;
- return Qnil;
- }
+ if (!raise && NIL_P(v)) return Qnil;
if (!RB_INTEGER_TYPE_P(v)) {
conversion_mismatch(val, "Integer", method, v);
}
- GET_EC()->cfp = current_cfp;
return v;
}
#define rb_to_integer(val, method, mid) \
@@ -3386,21 +3227,125 @@ rb_opts_exception_p(VALUE opts, int default_value)
return default_value;
}
-static VALUE
-rb_f_integer1(rb_execution_context_t *ec, VALUE obj, VALUE arg)
-{
- return rb_convert_to_integer(arg, 0, TRUE);
-}
+#define opts_exception_p(opts) rb_opts_exception_p((opts), TRUE)
+
+/*
+ * call-seq:
+ * Integer(object, base = 0, exception: true) -> integer or nil
+ *
+ * Returns an integer converted from +object+.
+ *
+ * Tries to convert +object+ to an integer
+ * using +to_int+ first and +to_i+ second;
+ * see below for exceptions.
+ *
+ * With a non-zero +base+, +object+ must be a string or convertible
+ * to a string.
+ *
+ * ==== numeric objects
+ *
+ * With integer argument +object+ given, returns +object+:
+ *
+ * Integer(1) # => 1
+ * Integer(-1) # => -1
+ *
+ * With floating-point argument +object+ given,
+ * returns +object+ truncated to an intger:
+ *
+ * Integer(1.9) # => 1 # Rounds toward zero.
+ * Integer(-1.9) # => -1 # Rounds toward zero.
+ *
+ * ==== string objects
+ *
+ * With string argument +object+ and zero +base+ given,
+ * returns +object+ converted to an integer in base 10:
+ *
+ * Integer('100') # => 100
+ * Integer('-100') # => -100
+ *
+ * With +base+ zero, string +object+ may contain leading characters
+ * to specify the actual base (radix indicator):
+ *
+ * Integer('0100') # => 64 # Leading '0' specifies base 8.
+ * Integer('0b100') # => 4 # Leading '0b', specifies base 2.
+ * Integer('0x100') # => 256 # Leading '0x' specifies base 16.
+ *
+ * With a positive +base+ (in range 2..36) given, returns +object+
+ * converted to an integer in the given base:
+ *
+ * Integer('100', 2) # => 4
+ * Integer('100', 8) # => 64
+ * Integer('-100', 16) # => -256
+ *
+ * With a negative +base+ (in range -36..-2) given, returns +object+
+ * converted to an integer in the radix indicator if exists or
+ * +-base+:
+ *
+ * Integer('0x100', -2) # => 256
+ * Integer('100', -2) # => 4
+ * Integer('0b100', -8) # => 4
+ * Integer('100', -8) # => 64
+ * Integer('0o100', -10) # => 64
+ * Integer('100', -10) # => 100
+ *
+ * +base+ -1 is equal the -10 case.
+ *
+ * When converting strings, surrounding whitespace and embedded underscores
+ * are allowed and ignored:
+ *
+ * Integer(' 100 ') # => 100
+ * Integer('-1_0_0', 16) # => -256
+ *
+ * ==== other classes
+ *
+ * Examples with +object+ of various other classes:
+ *
+ * Integer(Rational(9, 10)) # => 0 # Rounds toward zero.
+ * Integer(Complex(2, 0)) # => 2 # Imaginary part must be zero.
+ * Integer(Time.now) # => 1650974042
+ *
+ * ==== keywords
+ *
+ * With optional keyword argument +exception+ given as +true+ (the default):
+ *
+ * - Raises TypeError if +object+ does not respond to +to_int+ or +to_i+.
+ * - Raises TypeError if +object+ is +nil+.
+ * - Raise ArgumentError if +object+ is an invalid string.
+ *
+ * With +exception+ given as +false+, an exception of any kind is suppressed
+ * and +nil+ is returned.
+ *
+ */
static VALUE
-rb_f_integer(rb_execution_context_t *ec, VALUE obj, VALUE arg, VALUE base, VALUE exception)
+rb_f_integer(int argc, VALUE *argv, VALUE obj)
{
- int exc = rb_bool_expected(exception, "exception", TRUE);
- return rb_convert_to_integer(arg, NUM2INT(base), exc);
+ VALUE arg = Qnil, opts = Qnil;
+ int base = 0;
+
+ if (argc > 1) {
+ int narg = 1;
+ VALUE vbase = rb_check_to_int(argv[1]);
+ if (!NIL_P(vbase)) {
+ base = NUM2INT(vbase);
+ narg = 2;
+ }
+ if (argc > narg) {
+ VALUE hash = rb_check_hash_type(argv[argc-1]);
+ if (!NIL_P(hash)) {
+ opts = rb_extract_keywords(&hash);
+ if (!hash) --argc;
+ }
+ }
+ }
+ rb_check_arity(argc, 1, 2);
+ arg = argv[0];
+
+ return rb_convert_to_integer(arg, base, opts_exception_p(opts));
}
static double
-rb_cstr_to_dbl_raise(const char *p, rb_encoding *enc, int badcheck, int raise, int *error)
+rb_cstr_to_dbl_raise(const char *p, int badcheck, int raise, int *error)
{
const char *q;
char *end;
@@ -3411,7 +3356,6 @@ rb_cstr_to_dbl_raise(const char *p, rb_encoding *enc, int badcheck, int raise, i
#define OutOfRange() ((end - p > max_width) ? \
(w = max_width, ellipsis = "...") : \
(w = (int)(end - p), ellipsis = ""))
- /* p...end has been parsed with strtod, should be ASCII-only */
if (!p) return 0.0;
q = p;
@@ -3507,8 +3451,7 @@ rb_cstr_to_dbl_raise(const char *p, rb_encoding *enc, int badcheck, int raise, i
bad:
if (raise) {
- VALUE s = rb_enc_str_new_cstr(q, enc);
- rb_raise(rb_eArgError, "invalid value for Float(): %+"PRIsVALUE, s);
+ rb_invalid_str(q, "Float()");
UNREACHABLE_RETURN(nan(""));
}
else {
@@ -3520,7 +3463,7 @@ rb_cstr_to_dbl_raise(const char *p, rb_encoding *enc, int badcheck, int raise, i
double
rb_cstr_to_dbl(const char *p, int badcheck)
{
- return rb_cstr_to_dbl_raise(p, NULL, badcheck, TRUE, NULL);
+ return rb_cstr_to_dbl_raise(p, badcheck, TRUE, NULL);
}
static double
@@ -3551,11 +3494,9 @@ rb_str_to_dbl_raise(VALUE str, int badcheck, int raise, int *error)
s = p;
}
}
- ret = rb_cstr_to_dbl_raise(s, rb_enc_get(str), badcheck, raise, error);
+ ret = rb_cstr_to_dbl_raise(s, badcheck, raise, error);
if (v)
ALLOCV_END(v);
- else
- RB_GC_GUARD(str);
return ret;
}
@@ -3994,6 +3935,9 @@ rb_obj_dig(int argc, VALUE *argv, VALUE obj, VALUE notfound)
*
* For details on +format_string+, see
* {Format Specifications}[rdoc-ref:format_specifications.rdoc].
+ *
+ * Kernel#format is an alias for Kernel#sprintf.
+ *
*/
static VALUE
@@ -4002,12 +3946,6 @@ f_sprintf(int c, const VALUE *v, VALUE _)
return rb_f_sprintf(c, v);
}
-static VALUE
-rb_f_loop_size(VALUE self, VALUE args, VALUE eobj)
-{
- return DBL2NUM(HUGE_VAL);
-}
-
/*
* Document-class: Class
*
@@ -4070,51 +4008,57 @@ rb_f_loop_size(VALUE self, VALUE args, VALUE eobj)
*/
-/*
- * Document-class: BasicObject
+/* Document-class: BasicObject
*
- * +BasicObject+ is the parent class of all classes in Ruby.
- * In particular, +BasicObject+ is the parent class of class Object,
- * which is itself the default parent class of every Ruby class:
+ * BasicObject is the parent class of all classes in Ruby. It's an explicit
+ * blank class.
*
- * class Foo; end
- * Foo.superclass # => Object
- * Object.superclass # => BasicObject
+ * BasicObject can be used for creating object hierarchies independent of
+ * Ruby's object hierarchy, proxy objects like the Delegator class, or other
+ * uses where namespace pollution from Ruby's methods and classes must be
+ * avoided.
*
- * +BasicObject+ is the only class that has no parent:
+ * To avoid polluting BasicObject for other users an appropriately named
+ * subclass of BasicObject should be created instead of directly modifying
+ * BasicObject:
*
- * BasicObject.superclass # => nil
+ * class MyObjectSystem < BasicObject
+ * end
*
- * \Class +BasicObject+ can be used to create an object hierarchy
- * (e.g., class Delegator) that is independent of Ruby's object hierarchy.
- * Such objects:
+ * BasicObject does not include Kernel (for methods like +puts+) and
+ * BasicObject is outside of the namespace of the standard library so common
+ * classes will not be found without using a full class path.
*
- * - Do not have namespace "pollution" from the many methods
- * provided in class Object and its included module Kernel.
- * - Do not have definitions of common classes,
- * and so references to such common classes must be fully qualified
- * (+::String+, not +String+).
+ * A variety of strategies can be used to provide useful portions of the
+ * standard library to subclasses of BasicObject. A subclass could
+ * <code>include Kernel</code> to obtain +puts+, +exit+, etc. A custom
+ * Kernel-like module could be created and included or delegation can be used
+ * via #method_missing:
*
- * A variety of strategies can be used to provide useful portions
- * of the Standard Library in subclasses of +BasicObject+:
+ * class MyObjectSystem < BasicObject
+ * DELEGATE = [:puts, :p]
*
- * - The immediate subclass could <tt>include Kernel</tt>,
- * which would define methods such as +puts+, +exit+, etc.
- * - A custom Kernel-like module could be created and included.
- * - Delegation can be used via #method_missing:
+ * def method_missing(name, *args, &block)
+ * return super unless DELEGATE.include? name
+ * ::Kernel.send(name, *args, &block)
+ * end
*
- * class MyObjectSystem < BasicObject
- * DELEGATE = [:puts, :p]
+ * def respond_to_missing?(name, include_private = false)
+ * DELEGATE.include?(name) or super
+ * end
+ * end
*
- * def method_missing(name, *args, &block)
- * return super unless DELEGATE.include? name
- * ::Kernel.send(name, *args, &block)
- * end
+ * Access to classes and modules from the Ruby standard library can be
+ * obtained in a BasicObject subclass by referencing the desired constant
+ * from the root like <code>::File</code> or <code>::Enumerator</code>.
+ * Like #method_missing, #const_missing can be used to delegate constant
+ * lookup to +Object+:
*
- * def respond_to_missing?(name, include_private = false)
- * DELEGATE.include?(name)
- * end
+ * class MyObjectSystem < BasicObject
+ * def self.const_missing(name)
+ * ::Object.const_get(name)
* end
+ * end
*
* === What's Here
*
@@ -4128,11 +4072,8 @@ rb_f_loop_size(VALUE self, VALUE args, VALUE eobj)
* - #__send__: Calls the method identified by the given symbol.
* - #equal?: Returns whether +self+ and the given object are the same object.
* - #instance_eval: Evaluates the given string or block in the context of +self+.
- * - #instance_exec: Executes the given block in the context of +self+, passing the given arguments.
- * - #method_missing: Called when +self+ is called with a method it does not define.
- * - #singleton_method_added: Called when a singleton method is added to +self+.
- * - #singleton_method_removed: Called when a singleton method is removed from +self+.
- * - #singleton_method_undefined: Called when a singleton method is undefined in +self+.
+ * - #instance_exec: Executes the given block in the context of +self+,
+ * passing the given arguments.
*
*/
@@ -4222,7 +4163,7 @@ rb_f_loop_size(VALUE self, VALUE args, VALUE eobj)
* and frozen state.
* - #define_singleton_method: Defines a singleton method in +self+
* for the given symbol method-name and block or proc.
- * - #display: Prints +self+ to the given IO stream or <tt>$stdout</tt>.
+ * - #display: Prints +self+ to the given \IO stream or <tt>$stdout</tt>.
* - #dup: Returns a shallow unfrozen copy of +self+.
* - #enum_for (aliased as #to_enum): Returns an Enumerator for +self+
* using the using the given method, arguments, and block.
@@ -4238,6 +4179,27 @@ rb_f_loop_size(VALUE self, VALUE args, VALUE eobj)
*
*/
+/*!
+ *--
+ * \private
+ * Initializes the world of objects and classes.
+ *
+ * At first, the function bootstraps the class hierarchy.
+ * It initializes the most fundamental classes and their metaclasses.
+ * - \c BasicObject
+ * - \c Object
+ * - \c Module
+ * - \c Class
+ * After the bootstrap step, the class hierarchy becomes as the following
+ * diagram.
+ *
+ * \image html boottime-classes.png
+ *
+ * Then, the function defines classes, modules and methods as usual.
+ * \ingroup class
+ *++
+ */
+
void
InitVM_Object(void)
{
@@ -4453,13 +4415,15 @@ InitVM_Object(void)
rb_define_global_function("sprintf", f_sprintf, -1);
rb_define_global_function("format", f_sprintf, -1);
+ rb_define_global_function("Integer", rb_f_integer, -1);
+
rb_define_global_function("String", rb_f_string, 1);
rb_define_global_function("Array", rb_f_array, 1);
rb_define_global_function("Hash", rb_f_hash, 1);
rb_cNilClass = rb_define_class("NilClass", rb_cObject);
rb_cNilClass_to_s = rb_fstring_enc_lit("", rb_usascii_encoding());
- rb_vm_register_global_object(rb_cNilClass_to_s);
+ rb_gc_register_mark_object(rb_cNilClass_to_s);
rb_define_method(rb_cNilClass, "to_s", rb_nil_to_s, 0);
rb_define_method(rb_cNilClass, "to_a", nil_to_a, 0);
rb_define_method(rb_cNilClass, "to_h", nil_to_h, 0);
@@ -4488,7 +4452,6 @@ InitVM_Object(void)
rb_define_method(rb_cModule, "included_modules", rb_mod_included_modules, 0); /* in class.c */
rb_define_method(rb_cModule, "include?", rb_mod_include_p, 1); /* in class.c */
rb_define_method(rb_cModule, "name", rb_mod_name, 0); /* in variable.c */
- rb_define_method(rb_cModule, "set_temporary_name", rb_mod_set_temporary_name, 1); /* in variable.c */
rb_define_method(rb_cModule, "ancestors", rb_mod_ancestors, 0); /* in class.c */
rb_define_method(rb_cModule, "attr", rb_mod_attr, -1);
@@ -4545,7 +4508,7 @@ InitVM_Object(void)
rb_cTrueClass = rb_define_class("TrueClass", rb_cObject);
rb_cTrueClass_to_s = rb_fstring_enc_lit("true", rb_usascii_encoding());
- rb_vm_register_global_object(rb_cTrueClass_to_s);
+ rb_gc_register_mark_object(rb_cTrueClass_to_s);
rb_define_method(rb_cTrueClass, "to_s", rb_true_to_s, 0);
rb_define_alias(rb_cTrueClass, "inspect", "to_s");
rb_define_method(rb_cTrueClass, "&", true_and, 1);
@@ -4557,7 +4520,7 @@ InitVM_Object(void)
rb_cFalseClass = rb_define_class("FalseClass", rb_cObject);
rb_cFalseClass_to_s = rb_fstring_enc_lit("false", rb_usascii_encoding());
- rb_vm_register_global_object(rb_cFalseClass_to_s);
+ rb_gc_register_mark_object(rb_cFalseClass_to_s);
rb_define_method(rb_cFalseClass, "to_s", rb_false_to_s, 0);
rb_define_alias(rb_cFalseClass, "inspect", "to_s");
rb_define_method(rb_cFalseClass, "&", false_and, 1);
diff --git a/pack.c b/pack.c
index 3a5c1bfb96..3bdae01362 100644
--- a/pack.c
+++ b/pack.c
@@ -36,11 +36,10 @@
*/
#ifdef HAVE_TRUE_LONG_LONG
static const char natstr[] = "sSiIlLqQjJ";
-# define endstr natstr
#else
static const char natstr[] = "sSiIlLjJ";
-static const char endstr[] = "sSiIlLqQjJ";
#endif
+static const char endstr[] = "sSiIlLqQjJ";
#ifdef HAVE_TRUE_LONG_LONG
/* It is intentional to use long long instead of LONG_LONG. */
@@ -155,7 +154,6 @@ associated_pointer(VALUE associates, const char *t)
UNREACHABLE_RETURN(Qnil);
}
-RBIMPL_ATTR_NORETURN()
static void
unknown_directive(const char *mode, char type, VALUE fmt)
{
@@ -169,7 +167,7 @@ unknown_directive(const char *mode, char type, VALUE fmt)
snprintf(unknown, sizeof(unknown), "\\x%.2x", type & 0xff);
}
fmt = rb_str_quote_unprintable(fmt);
- rb_raise(rb_eArgError, "unknown %s directive '%s' in '%"PRIsVALUE"'",
+ rb_warn("unknown %s directive '%s' in '%"PRIsVALUE"'",
mode, unknown, fmt);
}
@@ -193,69 +191,20 @@ VALUE_to_float(VALUE obj)
}
}
-static void
-str_expand_fill(VALUE res, int c, long len)
-{
- long olen = RSTRING_LEN(res);
- memset(RSTRING_PTR(res) + olen, c, len);
- rb_str_set_len(res, olen + len);
-}
-
-static char *
-skip_to_eol(const char *p, const char *pend)
-{
- p = memchr(p, '\n', pend - p);
- return (char *)(p ? p + 1 : pend);
-}
-
-#define skip_blank(p, type) \
- (ISSPACE(type) || (type == '#' && (p = skip_to_eol(p, pend), 1)))
-
-#ifndef NATINT_PACK
-# define pack_modifiers(p, t, n, e) pack_modifiers(p, t, e)
-#endif
-static char *
-pack_modifiers(const char *p, char type, int *natint, int *explicit_endian)
-{
- while (1) {
- switch (*p) {
- case '_':
- case '!':
- if (strchr(natstr, type)) {
-#ifdef NATINT_PACK
- *natint = 1;
-#endif
- p++;
- }
- else {
- rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
- }
- break;
-
- case '<':
- case '>':
- if (!strchr(endstr, type)) {
- rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, endstr);
- }
- if (*explicit_endian) {
- rb_raise(rb_eRangeError, "Can't use both '<' and '>'");
- }
- *explicit_endian = *p++;
- break;
- default:
- return (char *)p;
- }
- }
-}
-
static VALUE
pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
{
+ static const char nul10[] = "\0\0\0\0\0\0\0\0\0\0";
+ static const char spc10[] = " ";
const char *p, *pend;
VALUE res, from, associates = 0;
+ char type;
long len, idx, plen;
const char *ptr;
int enc_info = 1; /* 0 - BINARY, 1 - US-ASCII, 2 - UTF-8 */
+#ifdef NATINT_PACK
+ int natint; /* native integer */
+#endif
int integer_size, bigendian_p;
StringValue(fmt);
@@ -282,16 +231,50 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
while (p < pend) {
int explicit_endian = 0;
- if (RSTRING_END(fmt) != pend) {
+ if (RSTRING_PTR(fmt) + RSTRING_LEN(fmt) != pend) {
rb_raise(rb_eRuntimeError, "format string modified");
}
- const char type = *p++; /* get data type */
+ type = *p++; /* get data type */
#ifdef NATINT_PACK
- int natint = 0; /* native integer */
+ natint = 0;
#endif
- if (skip_blank(p, type)) continue;
- p = pack_modifiers(p, type, &natint, &explicit_endian);
+ if (ISSPACE(type)) continue;
+ if (type == '#') {
+ while ((p < pend) && (*p != '\n')) {
+ p++;
+ }
+ continue;
+ }
+
+ {
+ modifiers:
+ switch (*p) {
+ case '_':
+ case '!':
+ if (strchr(natstr, type)) {
+#ifdef NATINT_PACK
+ natint = 1;
+#endif
+ p++;
+ }
+ else {
+ rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
+ }
+ goto modifiers;
+
+ case '<':
+ case '>':
+ if (!strchr(endstr, type)) {
+ rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, endstr);
+ }
+ if (explicit_endian) {
+ rb_raise(rb_eRangeError, "Can't use both '<' and '>'");
+ }
+ explicit_endian = *p++;
+ goto modifiers;
+ }
+ }
if (*p == '*') { /* set data length */
len = strchr("@Xxu", type) ? 0
@@ -348,12 +331,16 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
if (plen >= len) {
rb_str_buf_cat(res, ptr, len);
if (p[-1] == '*' && type == 'Z')
- rb_str_buf_cat(res, "", 1);
+ rb_str_buf_cat(res, nul10, 1);
}
else {
- rb_str_modify_expand(res, len);
rb_str_buf_cat(res, ptr, plen);
- str_expand_fill(res, (type == 'A' ? ' ' : '\0'), len - plen);
+ len -= plen;
+ while (len >= 10) {
+ rb_str_buf_cat(res, (type == 'A')?spc10:nul10, 10);
+ len -= 10;
+ }
+ rb_str_buf_cat(res, (type == 'A')?spc10:nul10, len);
}
break;
@@ -549,7 +536,7 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
bigendian_p = explicit_endian == '>';
}
if (integer_size > MAX_INTEGER_PACK_SIZE)
- rb_bug("unexpected integer size for pack: %d", integer_size);
+ rb_bug("unexpected intger size for pack: %d", integer_size);
while (len-- > 0) {
char intbuf[MAX_INTEGER_PACK_SIZE];
@@ -627,8 +614,11 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
case 'x': /* null byte */
grow:
- rb_str_modify_expand(res, len);
- str_expand_fill(res, '\0', len);
+ while (len >= 10) {
+ rb_str_buf_cat(res, nul10, 10);
+ len -= 10;
+ }
+ rb_str_buf_cat(res, nul10, len);
break;
case 'X': /* back up byte */
@@ -790,12 +780,6 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
return res;
}
-VALUE
-rb_ec_pack_ary(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
-{
- return pack_pack(ec, ary, fmt, buffer);
-}
-
static const char uu_table[] =
"`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
static const char b64_table[] =
@@ -953,8 +937,13 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
char *s, *send;
char *p, *pend;
VALUE ary, associates = Qfalse;
+ char type;
long len;
AVOID_CC_BUG long tmp_len;
+ int star;
+#ifdef NATINT_PACK
+ int natint; /* native integer */
+#endif
int signed_p, integer_size, bigendian_p;
#define UNPACK_PUSH(item) do {\
VALUE item_val = (item);\
@@ -989,14 +978,49 @@ pack_unpack_internal(VALUE str, VALUE fmt, enum unpack_mode mode, long offset)
ary = mode == UNPACK_ARRAY ? rb_ary_new() : Qnil;
while (p < pend) {
int explicit_endian = 0;
- const char type = *p++;
+ type = *p++;
+#ifdef NATINT_PACK
+ natint = 0;
+#endif
+
+ if (ISSPACE(type)) continue;
+ if (type == '#') {
+ while ((p < pend) && (*p != '\n')) {
+ p++;
+ }
+ continue;
+ }
+
+ star = 0;
+ {
+ modifiers:
+ switch (*p) {
+ case '_':
+ case '!':
+
+ if (strchr(natstr, type)) {
#ifdef NATINT_PACK
- int natint = 0; /* native integer */
+ natint = 1;
#endif
- int star = 0;
+ p++;
+ }
+ else {
+ rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, natstr);
+ }
+ goto modifiers;
- if (skip_blank(p, type)) continue;
- p = pack_modifiers(p, type, &natint, &explicit_endian);
+ case '<':
+ case '>':
+ if (!strchr(endstr, type)) {
+ rb_raise(rb_eArgError, "'%c' allowed only after types %s", *p, endstr);
+ }
+ if (explicit_endian) {
+ rb_raise(rb_eRangeError, "Can't use both '<' and '>'");
+ }
+ explicit_endian = *p++;
+ goto modifiers;
+ }
+ }
if (p >= pend)
len = 1;
diff --git a/pack.rb b/pack.rb
index e70c6c7dc8..d505eaee35 100644
--- a/pack.rb
+++ b/pack.rb
@@ -11,17 +11,12 @@ end
class String
# call-seq:
- # unpack(template, offset: 0, &block) -> array
- #
- # Extracts data from +self+.
- #
- # If +block+ is not given, forming objects that become the elements
- # of a new array, and returns that array. Otherwise, yields each
- # object.
+ # unpack(template, offset: 0) -> array
#
+ # Extracts data from +self+, forming objects that become the elements of a new array;
+ # returns that array.
# See {Packed Data}[rdoc-ref:packed_data.rdoc].
def unpack(fmt, offset: 0)
- Primitive.attr! :use_block
Primitive.pack_unpack(fmt, offset)
end
diff --git a/parse.y b/parse.y
index b532c5ff7d..1c808bd60e 100644
--- a/parse.y
+++ b/parse.y
@@ -19,28 +19,16 @@
#define YYDEBUG 1
#define YYERROR_VERBOSE 1
#define YYSTACK_USE_ALLOCA 0
-
-/* For Ripper */
-#ifdef RUBY_EXTCONF_H
-# include RUBY_EXTCONF_H
-#endif
+#define YYLTYPE rb_code_location_t
+#define YYLTYPE_IS_DECLARED 1
#include "ruby/internal/config.h"
+#include <ctype.h>
#include <errno.h>
+#include <stdio.h>
-#ifdef UNIVERSAL_PARSER
-
-#include "internal/ruby_parser.h"
-#include "parser_node.h"
-#include "universal_parser.c"
-
-#ifdef RIPPER
-#define STATIC_ID2SYM p->config->static_id2sym
-#define rb_str_coderange_scan_restartable p->config->str_coderange_scan_restartable
-#endif
-
-#else
+struct lex_context;
#include "internal.h"
#include "internal/compile.h"
@@ -49,17 +37,16 @@
#include "internal/encoding.h"
#include "internal/error.h"
#include "internal/hash.h"
+#include "internal/imemo.h"
#include "internal/io.h"
#include "internal/numeric.h"
#include "internal/parse.h"
#include "internal/rational.h"
#include "internal/re.h"
-#include "internal/ruby_parser.h"
#include "internal/symbol.h"
#include "internal/thread.h"
#include "internal/variable.h"
#include "node.h"
-#include "parser_node.h"
#include "probes.h"
#include "regenc.h"
#include "ruby/encoding.h"
@@ -70,244 +57,11 @@
#include "ruby/ractor.h"
#include "symbol.h"
-#ifndef RIPPER
-static VALUE
-syntax_error_new(void)
-{
- return rb_class_new_instance(0, 0, rb_eSyntaxError);
-}
-#endif
-
-static NODE *reg_named_capture_assign(struct parser_params* p, VALUE regexp, const YYLTYPE *loc);
-
-#define compile_callback rb_suppress_tracing
-#endif /* !UNIVERSAL_PARSER */
-
-#define NODE_SPECIAL_EMPTY_ARGS ((NODE *)-1)
-#define NODE_EMPTY_ARGS_P(node) ((node) == NODE_SPECIAL_EMPTY_ARGS)
-
-static int rb_parser_string_hash_cmp(rb_parser_string_t *str1, rb_parser_string_t *str2);
-
-#ifndef RIPPER
-static rb_parser_string_t *rb_parser_string_deep_copy(struct parser_params *p, const rb_parser_string_t *original);
-#endif
-
-static int
-node_integer_cmp(rb_node_integer_t *n1, rb_node_integer_t *n2)
-{
- return (n1->minus != n2->minus ||
- n1->base != n2->base ||
- strcmp(n1->val, n2->val));
-}
-
-static int
-node_float_cmp(rb_node_float_t *n1, rb_node_float_t *n2)
-{
- return (n1->minus != n2->minus ||
- strcmp(n1->val, n2->val));
-}
-
-static int
-node_rational_cmp(rb_node_rational_t *n1, rb_node_rational_t *n2)
-{
- return (n1->minus != n2->minus ||
- n1->base != n2->base ||
- n1->seen_point != n2->seen_point ||
- strcmp(n1->val, n2->val));
-}
-
-static int
-node_imaginary_cmp(rb_node_imaginary_t *n1, rb_node_imaginary_t *n2)
-{
- return (n1->minus != n2->minus ||
- n1->base != n2->base ||
- n1->seen_point != n2->seen_point ||
- n1->type != n2->type ||
- strcmp(n1->val, n2->val));
-}
-
-static int
-rb_parser_regx_hash_cmp(rb_node_regx_t *n1, rb_node_regx_t *n2)
-{
- return (n1->options != n2->options ||
- rb_parser_string_hash_cmp(n1->string, n2->string));
-}
-
-static st_index_t rb_parser_str_hash(rb_parser_string_t *str);
-static st_index_t rb_char_p_hash(const char *c);
-
-static int
-literal_cmp(st_data_t val, st_data_t lit)
-{
- if (val == lit) return 0;
-
- NODE *node_val = RNODE(val);
- NODE *node_lit = RNODE(lit);
- enum node_type type_val = nd_type(node_val);
- enum node_type type_lit = nd_type(node_lit);
-
- if (type_val != type_lit) {
- return -1;
- }
-
- switch (type_lit) {
- case NODE_INTEGER:
- return node_integer_cmp(RNODE_INTEGER(node_val), RNODE_INTEGER(node_lit));
- case NODE_FLOAT:
- return node_float_cmp(RNODE_FLOAT(node_val), RNODE_FLOAT(node_lit));
- case NODE_RATIONAL:
- return node_rational_cmp(RNODE_RATIONAL(node_val), RNODE_RATIONAL(node_lit));
- case NODE_IMAGINARY:
- return node_imaginary_cmp(RNODE_IMAGINARY(node_val), RNODE_IMAGINARY(node_lit));
- case NODE_STR:
- return rb_parser_string_hash_cmp(RNODE_STR(node_val)->string, RNODE_STR(node_lit)->string);
- case NODE_SYM:
- return rb_parser_string_hash_cmp(RNODE_SYM(node_val)->string, RNODE_SYM(node_lit)->string);
- case NODE_REGX:
- return rb_parser_regx_hash_cmp(RNODE_REGX(node_val), RNODE_REGX(node_lit));
- case NODE_LINE:
- return node_val->nd_loc.beg_pos.lineno != node_lit->nd_loc.beg_pos.lineno;
- case NODE_FILE:
- return rb_parser_string_hash_cmp(RNODE_FILE(node_val)->path, RNODE_FILE(node_lit)->path);
- case NODE_ENCODING:
- return RNODE_ENCODING(node_val)->enc != RNODE_ENCODING(node_lit)->enc;
- default:
-#ifdef UNIVERSAL_PARSER
- abort();
-#else
- rb_bug("unexpected node: %s, %s", ruby_node_name(type_val), ruby_node_name(type_lit));
-#endif
- }
-}
-
-static st_index_t
-literal_hash(st_data_t a)
-{
- NODE *node = (NODE *)a;
- enum node_type type = nd_type(node);
-
- switch (type) {
- case NODE_INTEGER:
- return rb_char_p_hash(RNODE_INTEGER(node)->val);
- case NODE_FLOAT:
- return rb_char_p_hash(RNODE_FLOAT(node)->val);
- case NODE_RATIONAL:
- return rb_char_p_hash(RNODE_RATIONAL(node)->val);
- case NODE_IMAGINARY:
- return rb_char_p_hash(RNODE_IMAGINARY(node)->val);
- case NODE_STR:
- return rb_parser_str_hash(RNODE_STR(node)->string);
- case NODE_SYM:
- return rb_parser_str_hash(RNODE_SYM(node)->string);
- case NODE_REGX:
- return rb_parser_str_hash(RNODE_REGX(node)->string);
- case NODE_LINE:
- return (st_index_t)node->nd_loc.beg_pos.lineno;
- case NODE_FILE:
- return rb_parser_str_hash(RNODE_FILE(node)->path);
- case NODE_ENCODING:
- return (st_index_t)RNODE_ENCODING(node)->enc;
- default:
-#ifdef UNIVERSAL_PARSER
- abort();
-#else
- rb_bug("unexpected node: %s", ruby_node_name(type));
-#endif
- }
-}
-
-static inline int
-parse_isascii(int c)
-{
- return '\0' <= c && c <= '\x7f';
-}
-
-#undef ISASCII
-#define ISASCII parse_isascii
-
-static inline int
-parse_isspace(int c)
-{
- return c == ' ' || ('\t' <= c && c <= '\r');
-}
-
-#undef ISSPACE
-#define ISSPACE parse_isspace
-
-static inline int
-parse_iscntrl(int c)
-{
- return ('\0' <= c && c < ' ') || c == '\x7f';
-}
-
-#undef ISCNTRL
-#define ISCNTRL(c) parse_iscntrl(c)
-
-static inline int
-parse_isupper(int c)
-{
- return 'A' <= c && c <= 'Z';
-}
-
-static inline int
-parse_islower(int c)
-{
- return 'a' <= c && c <= 'z';
-}
-
-static inline int
-parse_isalpha(int c)
-{
- return parse_isupper(c) || parse_islower(c);
-}
-
-#undef ISALPHA
-#define ISALPHA(c) parse_isalpha(c)
-
-static inline int
-parse_isdigit(int c)
-{
- return '0' <= c && c <= '9';
-}
-
-#undef ISDIGIT
-#define ISDIGIT(c) parse_isdigit(c)
-
-static inline int
-parse_isalnum(int c)
-{
- return parse_isalpha(c) || parse_isdigit(c);
-}
-
-#undef ISALNUM
-#define ISALNUM(c) parse_isalnum(c)
-
-static inline int
-parse_isxdigit(int c)
-{
- return parse_isdigit(c) || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f');
-}
-
-#undef ISXDIGIT
-#define ISXDIGIT(c) parse_isxdigit(c)
-
-#include "parser_st.h"
-
-#undef STRCASECMP
-#define STRCASECMP rb_parser_st_locale_insensitive_strcasecmp
-
-#undef STRNCASECMP
-#define STRNCASECMP rb_parser_st_locale_insensitive_strncasecmp
-
-#ifdef RIPPER
-#include "ripper_init.h"
-#endif
-
-enum rescue_context {
- before_rescue,
- after_rescue,
- after_else,
- after_ensure,
+enum shareability {
+ shareable_none,
+ shareable_literal,
+ shareable_copy,
+ shareable_everything,
};
struct lex_context {
@@ -316,13 +70,9 @@ struct lex_context {
unsigned int in_argdef: 1;
unsigned int in_def: 1;
unsigned int in_class: 1;
- BITFIELD(enum rb_parser_shareability, shareable_constant_value, 2);
- BITFIELD(enum rescue_context, in_rescue, 2);
- unsigned int cant_return: 1;
+ BITFIELD(enum shareability, shareable_constant_value, 2);
};
-typedef struct RNode_DEF_TEMP rb_node_def_temp_t;
-
#if defined(__GNUC__) && !defined(__clang__)
// Suppress "parameter passing for argument of type 'struct
// lex_context' changed" notes. `struct lex_context` is file scope,
@@ -337,6 +87,8 @@ RBIMPL_WARNING_POP()
#define NO_LEX_CTXT (struct lex_context){0}
+#define AREF(ary, i) RARRAY_AREF(ary, i)
+
#ifndef WARN_PAST_SCOPE
# define WARN_PAST_SCOPE 0
#endif
@@ -345,18 +97,22 @@ RBIMPL_WARNING_POP()
#define yydebug (p->debug) /* disable the global variable definition */
-#define YYFPRINTF(out, ...) rb_parser_printf(p, __VA_ARGS__)
-#define YY_LOCATION_PRINT(File, loc, p) \
+#define YYMALLOC(size) rb_parser_malloc(p, (size))
+#define YYREALLOC(ptr, size) rb_parser_realloc(p, (ptr), (size))
+#define YYCALLOC(nelem, size) rb_parser_calloc(p, (nelem), (size))
+#define YYFREE(ptr) rb_parser_free(p, (ptr))
+#define YYFPRINTF rb_parser_printf
+#define YY_LOCATION_PRINT(File, loc) \
rb_parser_printf(p, "%d.%d-%d.%d", \
- (loc).beg_pos.lineno, (loc).beg_pos.column,\
- (loc).end_pos.lineno, (loc).end_pos.column)
+ (loc).beg_pos.lineno, (loc).beg_pos.column,\
+ (loc).end_pos.lineno, (loc).end_pos.column)
#define YYLLOC_DEFAULT(Current, Rhs, N) \
do \
if (N) \
- { \
- (Current).beg_pos = YYRHSLOC(Rhs, 1).beg_pos; \
- (Current).end_pos = YYRHSLOC(Rhs, N).end_pos; \
- } \
+ { \
+ (Current).beg_pos = YYRHSLOC(Rhs, 1).beg_pos; \
+ (Current).end_pos = YYRHSLOC(Rhs, N).end_pos; \
+ } \
else \
{ \
(Current).beg_pos = YYRHSLOC(Rhs, 0).end_pos; \
@@ -381,10 +137,48 @@ RBIMPL_WARNING_POP()
rb_parser_set_location(p, &(Current))
#define RUBY_INIT_YYLLOC() \
{ \
- {p->ruby_sourceline, (int)(p->lex.ptok - p->lex.pbeg)}, \
- {p->ruby_sourceline, (int)(p->lex.pcur - p->lex.pbeg)}, \
- }
-
+ {p->ruby_sourceline, (int)(p->lex.ptok - p->lex.pbeg)}, \
+ {p->ruby_sourceline, (int)(p->lex.pcur - p->lex.pbeg)}, \
+ }
+
+enum lex_state_bits {
+ EXPR_BEG_bit, /* ignore newline, +/- is a sign. */
+ EXPR_END_bit, /* newline significant, +/- is an operator. */
+ EXPR_ENDARG_bit, /* ditto, and unbound braces. */
+ EXPR_ENDFN_bit, /* ditto, and unbound braces. */
+ EXPR_ARG_bit, /* newline significant, +/- is an operator. */
+ EXPR_CMDARG_bit, /* newline significant, +/- is an operator. */
+ EXPR_MID_bit, /* newline significant, +/- is an operator. */
+ EXPR_FNAME_bit, /* ignore newline, no reserved words. */
+ EXPR_DOT_bit, /* right after `.' or `::', no reserved words. */
+ EXPR_CLASS_bit, /* immediate after `class', no here document. */
+ EXPR_LABEL_bit, /* flag bit, label is allowed. */
+ EXPR_LABELED_bit, /* flag bit, just after a label. */
+ EXPR_FITEM_bit, /* symbol literal as FNAME. */
+ EXPR_MAX_STATE
+};
+/* examine combinations */
+enum lex_state_e {
+#define DEF_EXPR(n) EXPR_##n = (1 << EXPR_##n##_bit)
+ DEF_EXPR(BEG),
+ DEF_EXPR(END),
+ DEF_EXPR(ENDARG),
+ DEF_EXPR(ENDFN),
+ DEF_EXPR(ARG),
+ DEF_EXPR(CMDARG),
+ DEF_EXPR(MID),
+ DEF_EXPR(FNAME),
+ DEF_EXPR(DOT),
+ DEF_EXPR(CLASS),
+ DEF_EXPR(LABEL),
+ DEF_EXPR(LABELED),
+ DEF_EXPR(FITEM),
+ EXPR_VALUE = EXPR_BEG,
+ EXPR_BEG_ANY = (EXPR_BEG | EXPR_MID | EXPR_CLASS),
+ EXPR_ARG_ANY = (EXPR_ARG | EXPR_CMDARG),
+ EXPR_END_ANY = (EXPR_END | EXPR_ENDARG | EXPR_ENDFN),
+ EXPR_NONE = 0
+};
#define IS_lex_state_for(x, ls) ((x) & (ls))
#define IS_lex_state_all_for(x, ls) (((x) & (ls)) == (ls))
#define IS_lex_state(ls) IS_lex_state_for(p->lex.state, (ls))
@@ -433,10 +227,11 @@ struct local_vars {
struct vtable *past;
# endif
struct local_vars *prev;
+# ifndef RIPPER
struct {
- NODE *outer, *inner, *current;
+ NODE *outer, *inner, *current;
} numparam;
- NODE *it;
+# endif
};
enum {
@@ -445,6 +240,18 @@ enum {
NUMPARAM_MAX = 9,
};
+#define NUMPARAM_ID_P(id) numparam_id_p(id)
+#define NUMPARAM_ID_TO_IDX(id) (unsigned int)(((id) >> ID_SCOPE_SHIFT) - (tNUMPARAM_1 - 1))
+#define NUMPARAM_IDX_TO_ID(idx) TOKEN2LOCALID((tNUMPARAM_1 - 1 + (idx)))
+static int
+numparam_id_p(ID id)
+{
+ if (!is_local_id(id) || id < (tNUMPARAM_1 << ID_SCOPE_SHIFT)) return 0;
+ unsigned int idx = NUMPARAM_ID_TO_IDX(id);
+ return idx > 0 && idx <= NUMPARAM_MAX;
+}
+static void numparam_name(struct parser_params *p, ID id);
+
#define DVARS_INHERIT ((void*)1)
#define DVARS_TOPSCOPE NULL
#define DVARS_TERMINAL_P(tbl) ((tbl) == DVARS_INHERIT || (tbl) == DVARS_TOPSCOPE)
@@ -457,24 +264,7 @@ typedef struct token_info {
struct token_info *next;
} token_info;
-typedef struct end_expect_token_locations {
- const rb_code_position_t *pos;
- struct end_expect_token_locations *prev;
-} end_expect_token_locations_t;
-
-typedef struct parser_string_buffer_elem {
- struct parser_string_buffer_elem *next;
- long len; /* Total length of allocated buf */
- long used; /* Current usage of buf */
- rb_parser_string_t *buf[FLEX_ARY_LEN];
-} parser_string_buffer_elem_t;
-
-typedef struct parser_string_buffer {
- parser_string_buffer_elem_t *head;
- parser_string_buffer_elem_t *last;
-} parser_string_buffer_t;
-
-#define AFTER_HEREDOC_WITHOUT_TERMINTOR ((rb_parser_string_t *)1)
+typedef struct rb_strterm_struct rb_strterm_t;
/*
Structure of Lexer Buffer:
@@ -486,32 +276,38 @@ typedef struct parser_string_buffer {
token
*/
struct parser_params {
+ rb_imemo_tmpbuf_t *heap;
+
YYSTYPE *lval;
YYLTYPE *yylloc;
struct {
- rb_strterm_t *strterm;
- rb_parser_lex_gets_func *gets;
- rb_parser_input_data input;
- parser_string_buffer_t string_buffer;
- rb_parser_string_t *lastline;
- rb_parser_string_t *nextline;
- const char *pbeg;
- const char *pcur;
- const char *pend;
- const char *ptok;
- enum lex_state_e state;
- /* track the nest level of any parens "()[]{}" */
- int paren_nest;
- /* keep p->lex.paren_nest at the beginning of lambda "->" to detect tLAMBEG and keyword_do_LAMBDA */
- int lpar_beg;
- /* track the nest level of only braces "{}" */
- int brace_nest;
+ rb_strterm_t *strterm;
+ VALUE (*gets)(struct parser_params*,VALUE);
+ VALUE input;
+ VALUE lastline;
+ VALUE nextline;
+ const char *pbeg;
+ const char *pcur;
+ const char *pend;
+ const char *ptok;
+ union {
+ long ptr;
+ VALUE (*call)(VALUE, int);
+ } gets_;
+ enum lex_state_e state;
+ /* track the nest level of any parens "()[]{}" */
+ int paren_nest;
+ /* keep p->lex.paren_nest at the beginning of lambda "->" to detect tLAMBEG and keyword_do_LAMBDA */
+ int lpar_beg;
+ /* track the nest level of only braces "{}" */
+ int brace_nest;
} lex;
stack_type cond_stack;
stack_type cmdarg_stack;
int tokidx;
int toksiz;
+ int tokline;
int heredoc_end;
int heredoc_indent;
int heredoc_line_indent;
@@ -525,40 +321,29 @@ struct parser_params {
VALUE ruby_sourcefile_string;
rb_encoding *enc;
token_info *token_info;
- st_table *case_labels;
- rb_node_exits_t *exits;
+ VALUE case_labels;
+ VALUE compile_option;
VALUE debug_buffer;
VALUE debug_output;
struct {
- rb_parser_string_t *token;
- int beg_line;
- int beg_col;
- int end_line;
- int end_col;
+ VALUE token;
+ int beg_line;
+ int beg_col;
+ int end_line;
+ int end_col;
} delayed;
+ ID cur_arg;
+
rb_ast_t *ast;
int node_id;
- st_table *warn_duplicate_keys_table;
-
int max_numparam;
- ID it_id;
struct lex_context ctxt;
- NODE *eval_tree_begin;
- NODE *eval_tree;
- const struct rb_iseq_struct *parent_iseq;
-
-#ifdef UNIVERSAL_PARSER
- const rb_parser_config_t *config;
-#endif
- /* compile_option */
- signed int frozen_string_literal:2; /* -1: not specified, 0: false, 1: true */
-
unsigned int command_start:1;
unsigned int eofp: 1;
unsigned int ruby__end__seen: 1;
@@ -579,143 +364,45 @@ struct parser_params {
unsigned int do_loop: 1;
unsigned int do_chomp: 1;
unsigned int do_split: 1;
+ unsigned int keep_script_lines: 1;
unsigned int error_tolerant: 1;
unsigned int keep_tokens: 1;
+ NODE *eval_tree_begin;
+ NODE *eval_tree;
VALUE error_buffer;
- rb_parser_ary_t *debug_lines;
- /*
- * Store specific keyword locations to generate dummy end token.
- * Refer to the tail of list element.
- */
- end_expect_token_locations_t *end_expect_token_locations;
+ VALUE debug_lines;
+ const struct rb_iseq_struct *parent_iseq;
+ /* store specific keyword locations to generate dummy end token */
+ VALUE end_expect_token_locations;
/* id for terms */
int token_id;
/* Array for term tokens */
- rb_parser_ary_t *tokens;
+ VALUE tokens;
#else
/* Ripper only */
VALUE value;
VALUE result;
VALUE parsing_thread;
- VALUE s_value; /* Token VALUE */
- VALUE s_lvalue; /* VALUE generated by rule action (reduce) */
- VALUE s_value_stack;
#endif
};
-#define NUMPARAM_ID_P(id) numparam_id_p(p, id)
-#define NUMPARAM_ID_TO_IDX(id) (unsigned int)(((id) >> ID_SCOPE_SHIFT) - (tNUMPARAM_1 - 1))
-#define NUMPARAM_IDX_TO_ID(idx) TOKEN2LOCALID((tNUMPARAM_1 - 1 + (idx)))
-static int
-numparam_id_p(struct parser_params *p, ID id)
-{
- if (!is_local_id(id) || id < (tNUMPARAM_1 << ID_SCOPE_SHIFT)) return 0;
- unsigned int idx = NUMPARAM_ID_TO_IDX(id);
- return idx > 0 && idx <= NUMPARAM_MAX;
-}
-static void numparam_name(struct parser_params *p, ID id);
-
-#ifdef RIPPER
-static void
-after_shift(struct parser_params *p)
-{
- if (p->debug) {
- rb_parser_printf(p, "after-shift: %+"PRIsVALUE"\n", p->s_value);
- }
- rb_ary_push(p->s_value_stack, p->s_value);
- p->s_value = Qnil;
-}
-
-static void
-before_reduce(int len, struct parser_params *p)
-{
- // Initialize $$ with $1.
- if (len) p->s_lvalue = rb_ary_entry(p->s_value_stack, -len);
-}
-
-static void
-after_reduce(int len, struct parser_params *p)
-{
- for (int i = 0; i < len; i++) {
- VALUE tos = rb_ary_pop(p->s_value_stack);
- if (p->debug) {
- rb_parser_printf(p, "after-reduce pop: %+"PRIsVALUE"\n", tos);
- }
- }
- if (p->debug) {
- rb_parser_printf(p, "after-reduce push: %+"PRIsVALUE"\n", p->s_lvalue);
- }
- rb_ary_push(p->s_value_stack, p->s_lvalue);
- p->s_lvalue = Qnil;
-}
-
-static void
-after_shift_error_token(struct parser_params *p)
-{
- if (p->debug) {
- rb_parser_printf(p, "after-shift-error-token:\n");
- }
- rb_ary_push(p->s_value_stack, Qnil);
-}
-
-static void
-after_pop_stack(int len, struct parser_params *p)
-{
- for (int i = 0; i < len; i++) {
- VALUE tos = rb_ary_pop(p->s_value_stack);
- if (p->debug) {
- rb_parser_printf(p, "after-pop-stack pop: %+"PRIsVALUE"\n", tos);
- }
- }
-}
-#else
-static void
-after_shift(struct parser_params *p)
-{
-}
-
-static void
-before_reduce(int len, struct parser_params *p)
-{
-}
-
-static void
-after_reduce(int len, struct parser_params *p)
-{
-}
-
-static void
-after_shift_error_token(struct parser_params *p)
-{
-}
-
-static void
-after_pop_stack(int len, struct parser_params *p)
-{
-}
-#endif
-
#define intern_cstr(n,l,en) rb_intern3(n,l,en)
-#define STRING_NEW0() rb_parser_encoding_string_new(p,0,0,p->enc)
-
#define STR_NEW(ptr,len) rb_enc_str_new((ptr),(len),p->enc)
#define STR_NEW0() rb_enc_str_new(0,0,p->enc)
#define STR_NEW2(ptr) rb_enc_str_new((ptr),strlen(ptr),p->enc)
-#define STR_NEW3(ptr,len,e,func) parser_str_new(p, (ptr),(len),(e),(func),p->enc)
+#define STR_NEW3(ptr,len,e,func) parser_str_new((ptr),(len),(e),(func),p->enc)
#define TOK_INTERN() intern_cstr(tok(p), toklen(p), p->enc)
-#define VALID_SYMNAME_P(s, l, enc, type) (rb_enc_symname_type(s, l, enc, (1U<<(type))) == (int)(type))
-#ifndef RIPPER
-static inline int
-char_at_end(struct parser_params *p, VALUE str, int when_empty)
+static st_table *
+push_pvtbl(struct parser_params *p)
{
- long len = RSTRING_LEN(str);
- return len > 0 ? (unsigned char)RSTRING_PTR(str)[len-1] : when_empty;
+ st_table *tbl = p->pvtbl;
+ p->pvtbl = st_init_numtable();
+ return tbl;
}
-#endif
static void
pop_pvtbl(struct parser_params *p, st_table *tbl)
@@ -724,62 +411,19 @@ pop_pvtbl(struct parser_params *p, st_table *tbl)
p->pvtbl = tbl;
}
-static void
-pop_pktbl(struct parser_params *p, st_table *tbl)
-{
- if (p->pktbl) st_free_table(p->pktbl);
- p->pktbl = tbl;
-}
-
-#define STRING_BUF_DEFAULT_LEN 16
-
-static void
-string_buffer_init(struct parser_params *p)
-{
- parser_string_buffer_t *buf = &p->lex.string_buffer;
- const size_t size = offsetof(parser_string_buffer_elem_t, buf) + sizeof(rb_parser_string_t *) * STRING_BUF_DEFAULT_LEN;
-
- buf->head = buf->last = xmalloc(size);
- buf->head->len = STRING_BUF_DEFAULT_LEN;
- buf->head->used = 0;
- buf->head->next = NULL;
-}
-
-static void
-string_buffer_append(struct parser_params *p, rb_parser_string_t *str)
+static st_table *
+push_pktbl(struct parser_params *p)
{
- parser_string_buffer_t *buf = &p->lex.string_buffer;
-
- if (buf->head->used >= buf->head->len) {
- parser_string_buffer_elem_t *elem;
- long n = buf->head->len * 2;
- const size_t size = offsetof(parser_string_buffer_elem_t, buf) + sizeof(rb_parser_string_t *) * n;
-
- elem = xmalloc(size);
- elem->len = n;
- elem->used = 0;
- elem->next = NULL;
- buf->last->next = elem;
- buf->last = elem;
- }
- buf->last->buf[buf->last->used++] = str;
+ st_table *tbl = p->pktbl;
+ p->pktbl = 0;
+ return tbl;
}
static void
-string_buffer_free(struct parser_params *p)
+pop_pktbl(struct parser_params *p, st_table *tbl)
{
- parser_string_buffer_elem_t *elem = p->lex.string_buffer.head;
-
- while (elem) {
- parser_string_buffer_elem_t *next_elem = elem->next;
-
- for (long i = 0; i < elem->used; i++) {
- rb_parser_string_free(p, elem->buf[i]);
- }
-
- xfree(elem);
- elem = next_elem;
- }
+ if (p->pktbl) st_free_table(p->pktbl);
+ p->pktbl = tbl;
}
#ifndef RIPPER
@@ -789,15 +433,8 @@ static void
debug_end_expect_token_locations(struct parser_params *p, const char *name)
{
if(p->debug) {
- VALUE mesg = rb_sprintf("%s: [", name);
- int i = 0;
- for (end_expect_token_locations_t *loc = p->end_expect_token_locations; loc; loc = loc->prev) {
- if (i > 0)
- rb_str_cat_cstr(mesg, ", ");
- rb_str_catf(mesg, "[%d, %d]", loc->pos->lineno, loc->pos->column);
- i++;
- }
- rb_str_cat_cstr(mesg, "]\n");
+ VALUE mesg = rb_sprintf("%s: ", name);
+ rb_str_catf(mesg, " %"PRIsVALUE"\n", p->end_expect_token_locations);
flush_debug_buffer(p, p->debug_output, mesg);
}
}
@@ -805,215 +442,196 @@ debug_end_expect_token_locations(struct parser_params *p, const char *name)
static void
push_end_expect_token_locations(struct parser_params *p, const rb_code_position_t *pos)
{
- if(!p->error_tolerant) return;
-
- end_expect_token_locations_t *locations;
- locations = ALLOC(end_expect_token_locations_t);
- locations->pos = pos;
- locations->prev = p->end_expect_token_locations;
- p->end_expect_token_locations = locations;
-
+ if(NIL_P(p->end_expect_token_locations)) return;
+ rb_ary_push(p->end_expect_token_locations, rb_ary_new_from_args(2, INT2NUM(pos->lineno), INT2NUM(pos->column)));
debug_end_expect_token_locations(p, "push_end_expect_token_locations");
}
static void
pop_end_expect_token_locations(struct parser_params *p)
{
- if(!p->end_expect_token_locations) return;
-
- end_expect_token_locations_t *locations = p->end_expect_token_locations->prev;
- ruby_sized_xfree(p->end_expect_token_locations, sizeof(end_expect_token_locations_t));
- p->end_expect_token_locations = locations;
-
+ if(NIL_P(p->end_expect_token_locations)) return;
+ rb_ary_pop(p->end_expect_token_locations);
debug_end_expect_token_locations(p, "pop_end_expect_token_locations");
}
-static end_expect_token_locations_t *
+static VALUE
peek_end_expect_token_locations(struct parser_params *p)
{
- return p->end_expect_token_locations;
+ if(NIL_P(p->end_expect_token_locations)) return Qnil;
+ return rb_ary_last(0, 0, p->end_expect_token_locations);
}
-static const char *
-parser_token2char(struct parser_params *p, enum yytokentype tok)
+static ID
+parser_token2id(enum yytokentype tok)
{
switch ((int) tok) {
-#define TOKEN2CHAR(tok) case tok: return (#tok);
-#define TOKEN2CHAR2(tok, name) case tok: return (name);
- TOKEN2CHAR2(' ', "word_sep");
- TOKEN2CHAR2('!', "!")
- TOKEN2CHAR2('%', "%");
- TOKEN2CHAR2('&', "&");
- TOKEN2CHAR2('*', "*");
- TOKEN2CHAR2('+', "+");
- TOKEN2CHAR2('-', "-");
- TOKEN2CHAR2('/', "/");
- TOKEN2CHAR2('<', "<");
- TOKEN2CHAR2('=', "=");
- TOKEN2CHAR2('>', ">");
- TOKEN2CHAR2('?', "?");
- TOKEN2CHAR2('^', "^");
- TOKEN2CHAR2('|', "|");
- TOKEN2CHAR2('~', "~");
- TOKEN2CHAR2(':', ":");
- TOKEN2CHAR2(',', ",");
- TOKEN2CHAR2('.', ".");
- TOKEN2CHAR2(';', ";");
- TOKEN2CHAR2('`', "`");
- TOKEN2CHAR2('\n', "nl");
- TOKEN2CHAR2('{', "\"{\"");
- TOKEN2CHAR2('}', "\"}\"");
- TOKEN2CHAR2('[', "\"[\"");
- TOKEN2CHAR2(']', "\"]\"");
- TOKEN2CHAR2('(', "\"(\"");
- TOKEN2CHAR2(')', "\")\"");
- TOKEN2CHAR2('\\', "backslash");
- TOKEN2CHAR(keyword_class);
- TOKEN2CHAR(keyword_module);
- TOKEN2CHAR(keyword_def);
- TOKEN2CHAR(keyword_undef);
- TOKEN2CHAR(keyword_begin);
- TOKEN2CHAR(keyword_rescue);
- TOKEN2CHAR(keyword_ensure);
- TOKEN2CHAR(keyword_end);
- TOKEN2CHAR(keyword_if);
- TOKEN2CHAR(keyword_unless);
- TOKEN2CHAR(keyword_then);
- TOKEN2CHAR(keyword_elsif);
- TOKEN2CHAR(keyword_else);
- TOKEN2CHAR(keyword_case);
- TOKEN2CHAR(keyword_when);
- TOKEN2CHAR(keyword_while);
- TOKEN2CHAR(keyword_until);
- TOKEN2CHAR(keyword_for);
- TOKEN2CHAR(keyword_break);
- TOKEN2CHAR(keyword_next);
- TOKEN2CHAR(keyword_redo);
- TOKEN2CHAR(keyword_retry);
- TOKEN2CHAR(keyword_in);
- TOKEN2CHAR(keyword_do);
- TOKEN2CHAR(keyword_do_cond);
- TOKEN2CHAR(keyword_do_block);
- TOKEN2CHAR(keyword_do_LAMBDA);
- TOKEN2CHAR(keyword_return);
- TOKEN2CHAR(keyword_yield);
- TOKEN2CHAR(keyword_super);
- TOKEN2CHAR(keyword_self);
- TOKEN2CHAR(keyword_nil);
- TOKEN2CHAR(keyword_true);
- TOKEN2CHAR(keyword_false);
- TOKEN2CHAR(keyword_and);
- TOKEN2CHAR(keyword_or);
- TOKEN2CHAR(keyword_not);
- TOKEN2CHAR(modifier_if);
- TOKEN2CHAR(modifier_unless);
- TOKEN2CHAR(modifier_while);
- TOKEN2CHAR(modifier_until);
- TOKEN2CHAR(modifier_rescue);
- TOKEN2CHAR(keyword_alias);
- TOKEN2CHAR(keyword_defined);
- TOKEN2CHAR(keyword_BEGIN);
- TOKEN2CHAR(keyword_END);
- TOKEN2CHAR(keyword__LINE__);
- TOKEN2CHAR(keyword__FILE__);
- TOKEN2CHAR(keyword__ENCODING__);
- TOKEN2CHAR(tIDENTIFIER);
- TOKEN2CHAR(tFID);
- TOKEN2CHAR(tGVAR);
- TOKEN2CHAR(tIVAR);
- TOKEN2CHAR(tCONSTANT);
- TOKEN2CHAR(tCVAR);
- TOKEN2CHAR(tLABEL);
- TOKEN2CHAR(tINTEGER);
- TOKEN2CHAR(tFLOAT);
- TOKEN2CHAR(tRATIONAL);
- TOKEN2CHAR(tIMAGINARY);
- TOKEN2CHAR(tCHAR);
- TOKEN2CHAR(tNTH_REF);
- TOKEN2CHAR(tBACK_REF);
- TOKEN2CHAR(tSTRING_CONTENT);
- TOKEN2CHAR(tREGEXP_END);
- TOKEN2CHAR(tDUMNY_END);
- TOKEN2CHAR(tSP);
- TOKEN2CHAR(tUPLUS);
- TOKEN2CHAR(tUMINUS);
- TOKEN2CHAR(tPOW);
- TOKEN2CHAR(tCMP);
- TOKEN2CHAR(tEQ);
- TOKEN2CHAR(tEQQ);
- TOKEN2CHAR(tNEQ);
- TOKEN2CHAR(tGEQ);
- TOKEN2CHAR(tLEQ);
- TOKEN2CHAR(tANDOP);
- TOKEN2CHAR(tOROP);
- TOKEN2CHAR(tMATCH);
- TOKEN2CHAR(tNMATCH);
- TOKEN2CHAR(tDOT2);
- TOKEN2CHAR(tDOT3);
- TOKEN2CHAR(tBDOT2);
- TOKEN2CHAR(tBDOT3);
- TOKEN2CHAR(tAREF);
- TOKEN2CHAR(tASET);
- TOKEN2CHAR(tLSHFT);
- TOKEN2CHAR(tRSHFT);
- TOKEN2CHAR(tANDDOT);
- TOKEN2CHAR(tCOLON2);
- TOKEN2CHAR(tCOLON3);
- TOKEN2CHAR(tOP_ASGN);
- TOKEN2CHAR(tASSOC);
- TOKEN2CHAR(tLPAREN);
- TOKEN2CHAR(tLPAREN_ARG);
- TOKEN2CHAR(tRPAREN);
- TOKEN2CHAR(tLBRACK);
- TOKEN2CHAR(tLBRACE);
- TOKEN2CHAR(tLBRACE_ARG);
- TOKEN2CHAR(tSTAR);
- TOKEN2CHAR(tDSTAR);
- TOKEN2CHAR(tAMPER);
- TOKEN2CHAR(tLAMBDA);
- TOKEN2CHAR(tSYMBEG);
- TOKEN2CHAR(tSTRING_BEG);
- TOKEN2CHAR(tXSTRING_BEG);
- TOKEN2CHAR(tREGEXP_BEG);
- TOKEN2CHAR(tWORDS_BEG);
- TOKEN2CHAR(tQWORDS_BEG);
- TOKEN2CHAR(tSYMBOLS_BEG);
- TOKEN2CHAR(tQSYMBOLS_BEG);
- TOKEN2CHAR(tSTRING_END);
- TOKEN2CHAR(tSTRING_DEND);
- TOKEN2CHAR(tSTRING_DBEG);
- TOKEN2CHAR(tSTRING_DVAR);
- TOKEN2CHAR(tLAMBEG);
- TOKEN2CHAR(tLABEL_END);
- TOKEN2CHAR(tIGNORED_NL);
- TOKEN2CHAR(tCOMMENT);
- TOKEN2CHAR(tEMBDOC_BEG);
- TOKEN2CHAR(tEMBDOC);
- TOKEN2CHAR(tEMBDOC_END);
- TOKEN2CHAR(tHEREDOC_BEG);
- TOKEN2CHAR(tHEREDOC_END);
- TOKEN2CHAR(k__END__);
- TOKEN2CHAR(tLOWEST);
- TOKEN2CHAR(tUMINUS_NUM);
- TOKEN2CHAR(tLAST_TOKEN);
-#undef TOKEN2CHAR
-#undef TOKEN2CHAR2
+#define TOKEN2ID(tok) case tok: return rb_intern(#tok);
+#define TOKEN2ID2(tok, name) case tok: return rb_intern(name);
+ TOKEN2ID2(' ', "words_sep")
+ TOKEN2ID2('!', "!")
+ TOKEN2ID2('%', "%");
+ TOKEN2ID2('&', "&");
+ TOKEN2ID2('*', "*");
+ TOKEN2ID2('+', "+");
+ TOKEN2ID2('-', "-");
+ TOKEN2ID2('/', "/");
+ TOKEN2ID2('<', "<");
+ TOKEN2ID2('=', "=");
+ TOKEN2ID2('>', ">");
+ TOKEN2ID2('?', "?");
+ TOKEN2ID2('^', "^");
+ TOKEN2ID2('|', "|");
+ TOKEN2ID2('~', "~");
+ TOKEN2ID2(':', ":");
+ TOKEN2ID2(',', ",");
+ TOKEN2ID2('.', ".");
+ TOKEN2ID2(';', ";");
+ TOKEN2ID2('`', "`");
+ TOKEN2ID2('\n', "nl");
+ TOKEN2ID2('{', "{");
+ TOKEN2ID2('}', "}");
+ TOKEN2ID2('[', "[");
+ TOKEN2ID2(']', "]");
+ TOKEN2ID2('(', "(");
+ TOKEN2ID2(')', ")");
+ TOKEN2ID(keyword_class);
+ TOKEN2ID(keyword_module);
+ TOKEN2ID(keyword_def);
+ TOKEN2ID(keyword_undef);
+ TOKEN2ID(keyword_begin);
+ TOKEN2ID(keyword_rescue);
+ TOKEN2ID(keyword_ensure);
+ TOKEN2ID(keyword_end);
+ TOKEN2ID(keyword_if);
+ TOKEN2ID(keyword_unless);
+ TOKEN2ID(keyword_then);
+ TOKEN2ID(keyword_elsif);
+ TOKEN2ID(keyword_else);
+ TOKEN2ID(keyword_case);
+ TOKEN2ID(keyword_when);
+ TOKEN2ID(keyword_while);
+ TOKEN2ID(keyword_until);
+ TOKEN2ID(keyword_for);
+ TOKEN2ID(keyword_break);
+ TOKEN2ID(keyword_next);
+ TOKEN2ID(keyword_redo);
+ TOKEN2ID(keyword_retry);
+ TOKEN2ID(keyword_in);
+ TOKEN2ID(keyword_do);
+ TOKEN2ID(keyword_do_cond);
+ TOKEN2ID(keyword_do_block);
+ TOKEN2ID(keyword_do_LAMBDA);
+ TOKEN2ID(keyword_return);
+ TOKEN2ID(keyword_yield);
+ TOKEN2ID(keyword_super);
+ TOKEN2ID(keyword_self);
+ TOKEN2ID(keyword_nil);
+ TOKEN2ID(keyword_true);
+ TOKEN2ID(keyword_false);
+ TOKEN2ID(keyword_and);
+ TOKEN2ID(keyword_or);
+ TOKEN2ID(keyword_not);
+ TOKEN2ID(modifier_if);
+ TOKEN2ID(modifier_unless);
+ TOKEN2ID(modifier_while);
+ TOKEN2ID(modifier_until);
+ TOKEN2ID(modifier_rescue);
+ TOKEN2ID(keyword_alias);
+ TOKEN2ID(keyword_defined);
+ TOKEN2ID(keyword_BEGIN);
+ TOKEN2ID(keyword_END);
+ TOKEN2ID(keyword__LINE__);
+ TOKEN2ID(keyword__FILE__);
+ TOKEN2ID(keyword__ENCODING__);
+ TOKEN2ID(tIDENTIFIER);
+ TOKEN2ID(tFID);
+ TOKEN2ID(tGVAR);
+ TOKEN2ID(tIVAR);
+ TOKEN2ID(tCONSTANT);
+ TOKEN2ID(tCVAR);
+ TOKEN2ID(tLABEL);
+ TOKEN2ID(tINTEGER);
+ TOKEN2ID(tFLOAT);
+ TOKEN2ID(tRATIONAL);
+ TOKEN2ID(tIMAGINARY);
+ TOKEN2ID(tCHAR);
+ TOKEN2ID(tNTH_REF);
+ TOKEN2ID(tBACK_REF);
+ TOKEN2ID(tSTRING_CONTENT);
+ TOKEN2ID(tREGEXP_END);
+ TOKEN2ID(tDUMNY_END);
+ TOKEN2ID(tSP);
+ TOKEN2ID(tUPLUS);
+ TOKEN2ID(tUMINUS);
+ TOKEN2ID(tPOW);
+ TOKEN2ID(tCMP);
+ TOKEN2ID(tEQ);
+ TOKEN2ID(tEQQ);
+ TOKEN2ID(tNEQ);
+ TOKEN2ID(tGEQ);
+ TOKEN2ID(tLEQ);
+ TOKEN2ID(tANDOP);
+ TOKEN2ID(tOROP);
+ TOKEN2ID(tMATCH);
+ TOKEN2ID(tNMATCH);
+ TOKEN2ID(tDOT2);
+ TOKEN2ID(tDOT3);
+ TOKEN2ID(tBDOT2);
+ TOKEN2ID(tBDOT3);
+ TOKEN2ID(tAREF);
+ TOKEN2ID(tASET);
+ TOKEN2ID(tLSHFT);
+ TOKEN2ID(tRSHFT);
+ TOKEN2ID(tANDDOT);
+ TOKEN2ID(tCOLON2);
+ TOKEN2ID(tCOLON3);
+ TOKEN2ID(tOP_ASGN);
+ TOKEN2ID(tASSOC);
+ TOKEN2ID(tLPAREN);
+ TOKEN2ID(tLPAREN_ARG);
+ TOKEN2ID(tRPAREN);
+ TOKEN2ID(tLBRACK);
+ TOKEN2ID(tLBRACE);
+ TOKEN2ID(tLBRACE_ARG);
+ TOKEN2ID(tSTAR);
+ TOKEN2ID(tDSTAR);
+ TOKEN2ID(tAMPER);
+ TOKEN2ID(tLAMBDA);
+ TOKEN2ID(tSYMBEG);
+ TOKEN2ID(tSTRING_BEG);
+ TOKEN2ID(tXSTRING_BEG);
+ TOKEN2ID(tREGEXP_BEG);
+ TOKEN2ID(tWORDS_BEG);
+ TOKEN2ID(tQWORDS_BEG);
+ TOKEN2ID(tSYMBOLS_BEG);
+ TOKEN2ID(tQSYMBOLS_BEG);
+ TOKEN2ID(tSTRING_END);
+ TOKEN2ID(tSTRING_DEND);
+ TOKEN2ID(tSTRING_DBEG);
+ TOKEN2ID(tSTRING_DVAR);
+ TOKEN2ID(tLAMBEG);
+ TOKEN2ID(tLABEL_END);
+ TOKEN2ID(tIGNORED_NL);
+ TOKEN2ID(tCOMMENT);
+ TOKEN2ID(tEMBDOC_BEG);
+ TOKEN2ID(tEMBDOC);
+ TOKEN2ID(tEMBDOC_END);
+ TOKEN2ID(tHEREDOC_BEG);
+ TOKEN2ID(tHEREDOC_END);
+ TOKEN2ID(k__END__);
+ TOKEN2ID(tLOWEST);
+ TOKEN2ID(tUMINUS_NUM);
+ TOKEN2ID(tLAST_TOKEN);
+#undef TOKEN2ID
+#undef TOKEN2ID2
}
rb_bug("parser_token2id: unknown token %d", tok);
UNREACHABLE_RETURN(0);
}
-#else
-static void
-push_end_expect_token_locations(struct parser_params *p, const rb_code_position_t *pos)
-{
-}
-static void
-pop_end_expect_token_locations(struct parser_params *p)
-{
-}
#endif
RBIMPL_ATTR_NONNULL((1, 2, 3))
@@ -1025,10 +643,8 @@ static int parser_yyerror0(struct parser_params*, const char*);
#define yyerror(yylloc, p, msg) parser_yyerror(p, yylloc, msg)
#define token_flush(ptr) ((ptr)->lex.ptok = (ptr)->lex.pcur)
#define lex_goto_eol(p) ((p)->lex.pcur = (p)->lex.pend)
-#define lex_eol_p(p) lex_eol_n_p(p, 0)
-#define lex_eol_n_p(p,n) lex_eol_ptr_n_p(p, (p)->lex.pcur, n)
-#define lex_eol_ptr_p(p,ptr) lex_eol_ptr_n_p(p,ptr,0)
-#define lex_eol_ptr_n_p(p,ptr,n) ((ptr)+(n) >= (p)->lex.pend)
+#define lex_eol_p(p) ((p)->lex.pcur >= (p)->lex.pend)
+#define lex_eol_n_p(p,n) ((p)->lex.pcur+(n) >= (p)->lex.pend)
static void token_info_setup(token_info *ptinfo, const char *ptr, const rb_code_location_t *loc);
static void token_info_push(struct parser_params*, const char *token, const rb_code_location_t *loc);
@@ -1044,289 +660,44 @@ static void token_info_drop(struct parser_params *p, const char *token, rb_code_
#define token_column ((int)(p->lex.ptok - p->lex.pbeg))
-#define CALL_Q_P(q) ((q) == tANDDOT)
-#define NEW_QCALL(q,r,m,a,loc) (CALL_Q_P(q) ? NEW_QCALL0(r,m,a,loc) : NEW_CALL(r,m,a,loc))
+#define CALL_Q_P(q) ((q) == TOKEN2VAL(tANDDOT))
+#define NODE_CALL_Q(q) (CALL_Q_P(q) ? NODE_QCALL : NODE_CALL)
+#define NEW_QCALL(q,r,m,a,loc) NEW_NODE(NODE_CALL_Q(q),r,m,a,loc)
#define lambda_beginning_p() (p->lex.lpar_beg == p->lex.paren_nest)
static enum yytokentype yylex(YYSTYPE*, YYLTYPE*, struct parser_params*);
+#ifndef RIPPER
static inline void
rb_discard_node(struct parser_params *p, NODE *n)
{
rb_ast_delete_node(p->ast, n);
}
+#endif
-static rb_node_scope_t *rb_node_scope_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_scope_t *rb_node_scope_new2(struct parser_params *p, rb_ast_id_table_t *nd_tbl, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_block_t *rb_node_block_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc);
-static rb_node_if_t *rb_node_if_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_else, const YYLTYPE *loc);
-static rb_node_unless_t *rb_node_unless_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_else, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *then_keyword_loc, const YYLTYPE *end_keyword_loc);
-static rb_node_case_t *rb_node_case_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *case_keyword_loc, const YYLTYPE *end_keyword_loc);
-static rb_node_case2_t *rb_node_case2_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *case_keyword_loc, const YYLTYPE *end_keyword_loc);
-static rb_node_case3_t *rb_node_case3_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *case_keyword_loc, const YYLTYPE *end_keyword_loc);
-static rb_node_when_t *rb_node_when_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *then_keyword_loc);
-static rb_node_in_t *rb_node_in_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc);
-static rb_node_while_t *rb_node_while_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, long nd_state, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *closing_loc);
-static rb_node_until_t *rb_node_until_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, long nd_state, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *closing_loc);
-static rb_node_iter_t *rb_node_iter_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_for_t *rb_node_for_new(struct parser_params *p, NODE *nd_iter, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_for_masgn_t *rb_node_for_masgn_new(struct parser_params *p, NODE *nd_var, const YYLTYPE *loc);
-static rb_node_retry_t *rb_node_retry_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_begin_t *rb_node_begin_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_rescue_t *rb_node_rescue_new(struct parser_params *p, NODE *nd_head, NODE *nd_resq, NODE *nd_else, const YYLTYPE *loc);
-static rb_node_resbody_t *rb_node_resbody_new(struct parser_params *p, NODE *nd_args, NODE *nd_exc_var, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc);
-static rb_node_ensure_t *rb_node_ensure_new(struct parser_params *p, NODE *nd_head, NODE *nd_ensr, const YYLTYPE *loc);
-static rb_node_and_t *rb_node_and_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc, const YYLTYPE *operator_loc);
-static rb_node_or_t *rb_node_or_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc, const YYLTYPE *operator_loc);
-static rb_node_masgn_t *rb_node_masgn_new(struct parser_params *p, NODE *nd_head, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_lasgn_t *rb_node_lasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_dasgn_t *rb_node_dasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_gasgn_t *rb_node_gasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_iasgn_t *rb_node_iasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_cdecl_t *rb_node_cdecl_new(struct parser_params *p, ID nd_vid, NODE *nd_value, NODE *nd_else, enum rb_parser_shareability shareability, const YYLTYPE *loc);
-static rb_node_cvasgn_t *rb_node_cvasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_op_asgn1_t *rb_node_op_asgn1_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *index, NODE *rvalue, const YYLTYPE *loc, const YYLTYPE *call_operator_loc, const YYLTYPE *opening_loc, const YYLTYPE *closing_loc, const YYLTYPE *binary_operator_loc);
-static rb_node_op_asgn2_t *rb_node_op_asgn2_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, ID nd_vid, ID nd_mid, bool nd_aid, const YYLTYPE *loc, const YYLTYPE *call_operator_loc, const YYLTYPE *message_loc, const YYLTYPE *binary_operator_loc);
-static rb_node_op_asgn_or_t *rb_node_op_asgn_or_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_op_asgn_and_t *rb_node_op_asgn_and_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_op_cdecl_t *rb_node_op_cdecl_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, ID nd_aid, enum rb_parser_shareability shareability, const YYLTYPE *loc);
-static rb_node_call_t *rb_node_call_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_opcall_t *rb_node_opcall_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_fcall_t *rb_node_fcall_new(struct parser_params *p, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_vcall_t *rb_node_vcall_new(struct parser_params *p, ID nd_mid, const YYLTYPE *loc);
-static rb_node_qcall_t *rb_node_qcall_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_super_t *rb_node_super_new(struct parser_params *p, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_zsuper_t * rb_node_zsuper_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_list_t *rb_node_list_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc);
-static rb_node_list_t *rb_node_list_new2(struct parser_params *p, NODE *nd_head, long nd_alen, NODE *nd_next, const YYLTYPE *loc);
-static rb_node_zlist_t *rb_node_zlist_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_hash_t *rb_node_hash_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc);
-static rb_node_return_t *rb_node_return_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc, const YYLTYPE *keyword_loc);
-static rb_node_yield_t *rb_node_yield_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc);
-static rb_node_lvar_t *rb_node_lvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc);
-static rb_node_dvar_t *rb_node_dvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc);
-static rb_node_gvar_t *rb_node_gvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc);
-static rb_node_ivar_t *rb_node_ivar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc);
-static rb_node_const_t *rb_node_const_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc);
-static rb_node_cvar_t *rb_node_cvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc);
-static rb_node_nth_ref_t *rb_node_nth_ref_new(struct parser_params *p, long nd_nth, const YYLTYPE *loc);
-static rb_node_back_ref_t *rb_node_back_ref_new(struct parser_params *p, long nd_nth, const YYLTYPE *loc);
-static rb_node_match2_t *rb_node_match2_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_match3_t *rb_node_match3_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, const YYLTYPE *loc);
-static rb_node_integer_t * rb_node_integer_new(struct parser_params *p, char* val, int base, const YYLTYPE *loc);
-static rb_node_float_t * rb_node_float_new(struct parser_params *p, char* val, const YYLTYPE *loc);
-static rb_node_rational_t * rb_node_rational_new(struct parser_params *p, char* val, int base, int seen_point, const YYLTYPE *loc);
-static rb_node_imaginary_t * rb_node_imaginary_new(struct parser_params *p, char* val, int base, int seen_point, enum rb_numeric_type, const YYLTYPE *loc);
-static rb_node_str_t *rb_node_str_new(struct parser_params *p, rb_parser_string_t *string, const YYLTYPE *loc);
-static rb_node_dstr_t *rb_node_dstr_new0(struct parser_params *p, rb_parser_string_t *string, long nd_alen, NODE *nd_next, const YYLTYPE *loc);
-static rb_node_dstr_t *rb_node_dstr_new(struct parser_params *p, rb_parser_string_t *string, const YYLTYPE *loc);
-static rb_node_xstr_t *rb_node_xstr_new(struct parser_params *p, rb_parser_string_t *string, const YYLTYPE *loc);
-static rb_node_dxstr_t *rb_node_dxstr_new(struct parser_params *p, rb_parser_string_t *string, long nd_alen, NODE *nd_next, const YYLTYPE *loc);
-static rb_node_evstr_t *rb_node_evstr_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_regx_t *rb_node_regx_new(struct parser_params *p, rb_parser_string_t *string, int options, const YYLTYPE *loc);
-static rb_node_once_t *rb_node_once_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_args_t *rb_node_args_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_args_aux_t *rb_node_args_aux_new(struct parser_params *p, ID nd_pid, int nd_plen, const YYLTYPE *loc);
-static rb_node_opt_arg_t *rb_node_opt_arg_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_kw_arg_t *rb_node_kw_arg_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_postarg_t *rb_node_postarg_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc);
-static rb_node_argscat_t *rb_node_argscat_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_argspush_t *rb_node_argspush_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_splat_t *rb_node_splat_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc, const YYLTYPE *operator_loc);
-static rb_node_block_pass_t *rb_node_block_pass_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *operator_loc);
-static rb_node_defn_t *rb_node_defn_new(struct parser_params *p, ID nd_mid, NODE *nd_defn, const YYLTYPE *loc);
-static rb_node_defs_t *rb_node_defs_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_defn, const YYLTYPE *loc);
-static rb_node_alias_t *rb_node_alias_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc, const YYLTYPE *keyword_loc);
-static rb_node_valias_t *rb_node_valias_new(struct parser_params *p, ID nd_alias, ID nd_orig, const YYLTYPE *loc, const YYLTYPE *keyword_loc);
-static rb_node_undef_t *rb_node_undef_new(struct parser_params *p, NODE *nd_undef, const YYLTYPE *loc);
-static rb_node_class_t *rb_node_class_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, NODE *nd_super, const YYLTYPE *loc);
-static rb_node_module_t *rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_sclass_t *rb_node_sclass_new(struct parser_params *p, NODE *nd_recv, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_colon2_t *rb_node_colon2_new(struct parser_params *p, NODE *nd_head, ID nd_mid, const YYLTYPE *loc);
-static rb_node_colon3_t *rb_node_colon3_new(struct parser_params *p, ID nd_mid, const YYLTYPE *loc);
-static rb_node_dot2_t *rb_node_dot2_new(struct parser_params *p, NODE *nd_beg, NODE *nd_end, const YYLTYPE *loc);
-static rb_node_dot3_t *rb_node_dot3_new(struct parser_params *p, NODE *nd_beg, NODE *nd_end, const YYLTYPE *loc);
-static rb_node_self_t *rb_node_self_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_nil_t *rb_node_nil_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_true_t *rb_node_true_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_false_t *rb_node_false_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_errinfo_t *rb_node_errinfo_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_defined_t *rb_node_defined_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc);
-static rb_node_postexe_t *rb_node_postexe_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_sym_t *rb_node_sym_new(struct parser_params *p, VALUE str, const YYLTYPE *loc);
-static rb_node_dsym_t *rb_node_dsym_new(struct parser_params *p, rb_parser_string_t *string, long nd_alen, NODE *nd_next, const YYLTYPE *loc);
-static rb_node_attrasgn_t *rb_node_attrasgn_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
-static rb_node_lambda_t *rb_node_lambda_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc);
-static rb_node_aryptn_t *rb_node_aryptn_new(struct parser_params *p, NODE *pre_args, NODE *rest_arg, NODE *post_args, const YYLTYPE *loc);
-static rb_node_hshptn_t *rb_node_hshptn_new(struct parser_params *p, NODE *nd_pconst, NODE *nd_pkwargs, NODE *nd_pkwrestarg, const YYLTYPE *loc);
-static rb_node_fndptn_t *rb_node_fndptn_new(struct parser_params *p, NODE *pre_rest_arg, NODE *args, NODE *post_rest_arg, const YYLTYPE *loc);
-static rb_node_line_t *rb_node_line_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_file_t *rb_node_file_new(struct parser_params *p, VALUE str, const YYLTYPE *loc);
-static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE *loc);
-
-#define NEW_SCOPE(a,b,loc) (NODE *)rb_node_scope_new(p,a,b,loc)
-#define NEW_SCOPE2(t,a,b,loc) (NODE *)rb_node_scope_new2(p,t,a,b,loc)
-#define NEW_BLOCK(a,loc) (NODE *)rb_node_block_new(p,a,loc)
-#define NEW_IF(c,t,e,loc) (NODE *)rb_node_if_new(p,c,t,e,loc)
-#define NEW_UNLESS(c,t,e,loc,k_loc,t_loc,e_loc) (NODE *)rb_node_unless_new(p,c,t,e,loc,k_loc,t_loc,e_loc)
-#define NEW_CASE(h,b,loc,ck_loc,ek_loc) (NODE *)rb_node_case_new(p,h,b,loc,ck_loc,ek_loc)
-#define NEW_CASE2(b,loc,ck_loc,ek_loc) (NODE *)rb_node_case2_new(p,b,loc,ck_loc,ek_loc)
-#define NEW_CASE3(h,b,loc,ck_loc,ek_loc) (NODE *)rb_node_case3_new(p,h,b,loc,ck_loc,ek_loc)
-#define NEW_WHEN(c,t,e,loc,k_loc,t_loc) (NODE *)rb_node_when_new(p,c,t,e,loc,k_loc,t_loc)
-#define NEW_IN(c,t,e,loc) (NODE *)rb_node_in_new(p,c,t,e,loc)
-#define NEW_WHILE(c,b,n,loc,k_loc,c_loc) (NODE *)rb_node_while_new(p,c,b,n,loc,k_loc,c_loc)
-#define NEW_UNTIL(c,b,n,loc,k_loc,c_loc) (NODE *)rb_node_until_new(p,c,b,n,loc,k_loc,c_loc)
-#define NEW_ITER(a,b,loc) (NODE *)rb_node_iter_new(p,a,b,loc)
-#define NEW_FOR(i,b,loc) (NODE *)rb_node_for_new(p,i,b,loc)
-#define NEW_FOR_MASGN(v,loc) (NODE *)rb_node_for_masgn_new(p,v,loc)
-#define NEW_RETRY(loc) (NODE *)rb_node_retry_new(p,loc)
-#define NEW_BEGIN(b,loc) (NODE *)rb_node_begin_new(p,b,loc)
-#define NEW_RESCUE(b,res,e,loc) (NODE *)rb_node_rescue_new(p,b,res,e,loc)
-#define NEW_RESBODY(a,v,ex,n,loc) (NODE *)rb_node_resbody_new(p,a,v,ex,n,loc)
-#define NEW_ENSURE(b,en,loc) (NODE *)rb_node_ensure_new(p,b,en,loc)
-#define NEW_AND(f,s,loc,op_loc) (NODE *)rb_node_and_new(p,f,s,loc,op_loc)
-#define NEW_OR(f,s,loc,op_loc) (NODE *)rb_node_or_new(p,f,s,loc,op_loc)
-#define NEW_MASGN(l,r,loc) rb_node_masgn_new(p,l,r,loc)
-#define NEW_LASGN(v,val,loc) (NODE *)rb_node_lasgn_new(p,v,val,loc)
-#define NEW_DASGN(v,val,loc) (NODE *)rb_node_dasgn_new(p,v,val,loc)
-#define NEW_GASGN(v,val,loc) (NODE *)rb_node_gasgn_new(p,v,val,loc)
-#define NEW_IASGN(v,val,loc) (NODE *)rb_node_iasgn_new(p,v,val,loc)
-#define NEW_CDECL(v,val,path,share,loc) (NODE *)rb_node_cdecl_new(p,v,val,path,share,loc)
-#define NEW_CVASGN(v,val,loc) (NODE *)rb_node_cvasgn_new(p,v,val,loc)
-#define NEW_OP_ASGN1(r,id,idx,rval,loc,c_op_loc,o_loc,c_loc,b_op_loc) (NODE *)rb_node_op_asgn1_new(p,r,id,idx,rval,loc,c_op_loc,o_loc,c_loc,b_op_loc)
-#define NEW_OP_ASGN2(r,t,i,o,val,loc,c_op_loc,m_loc,b_op_loc) (NODE *)rb_node_op_asgn2_new(p,r,val,i,o,t,loc,c_op_loc,m_loc,b_op_loc)
-#define NEW_OP_ASGN_OR(i,val,loc) (NODE *)rb_node_op_asgn_or_new(p,i,val,loc)
-#define NEW_OP_ASGN_AND(i,val,loc) (NODE *)rb_node_op_asgn_and_new(p,i,val,loc)
-#define NEW_OP_CDECL(v,op,val,share,loc) (NODE *)rb_node_op_cdecl_new(p,v,val,op,share,loc)
-#define NEW_CALL(r,m,a,loc) (NODE *)rb_node_call_new(p,r,m,a,loc)
-#define NEW_OPCALL(r,m,a,loc) (NODE *)rb_node_opcall_new(p,r,m,a,loc)
-#define NEW_FCALL(m,a,loc) rb_node_fcall_new(p,m,a,loc)
-#define NEW_VCALL(m,loc) (NODE *)rb_node_vcall_new(p,m,loc)
-#define NEW_QCALL0(r,m,a,loc) (NODE *)rb_node_qcall_new(p,r,m,a,loc)
-#define NEW_SUPER(a,loc) (NODE *)rb_node_super_new(p,a,loc)
-#define NEW_ZSUPER(loc) (NODE *)rb_node_zsuper_new(p,loc)
-#define NEW_LIST(a,loc) (NODE *)rb_node_list_new(p,a,loc)
-#define NEW_LIST2(h,l,n,loc) (NODE *)rb_node_list_new2(p,h,l,n,loc)
-#define NEW_ZLIST(loc) (NODE *)rb_node_zlist_new(p,loc)
-#define NEW_HASH(a,loc) (NODE *)rb_node_hash_new(p,a,loc)
-#define NEW_RETURN(s,loc,k_loc) (NODE *)rb_node_return_new(p,s,loc,k_loc)
-#define NEW_YIELD(a,loc) (NODE *)rb_node_yield_new(p,a,loc)
-#define NEW_LVAR(v,loc) (NODE *)rb_node_lvar_new(p,v,loc)
-#define NEW_DVAR(v,loc) (NODE *)rb_node_dvar_new(p,v,loc)
-#define NEW_GVAR(v,loc) (NODE *)rb_node_gvar_new(p,v,loc)
-#define NEW_IVAR(v,loc) (NODE *)rb_node_ivar_new(p,v,loc)
-#define NEW_CONST(v,loc) (NODE *)rb_node_const_new(p,v,loc)
-#define NEW_CVAR(v,loc) (NODE *)rb_node_cvar_new(p,v,loc)
-#define NEW_NTH_REF(n,loc) (NODE *)rb_node_nth_ref_new(p,n,loc)
-#define NEW_BACK_REF(n,loc) (NODE *)rb_node_back_ref_new(p,n,loc)
-#define NEW_MATCH2(n1,n2,loc) (NODE *)rb_node_match2_new(p,n1,n2,loc)
-#define NEW_MATCH3(r,n2,loc) (NODE *)rb_node_match3_new(p,r,n2,loc)
-#define NEW_INTEGER(val, base,loc) (NODE *)rb_node_integer_new(p,val,base,loc)
-#define NEW_FLOAT(val,loc) (NODE *)rb_node_float_new(p,val,loc)
-#define NEW_RATIONAL(val,base,seen_point,loc) (NODE *)rb_node_rational_new(p,val,base,seen_point,loc)
-#define NEW_IMAGINARY(val,base,seen_point,numeric_type,loc) (NODE *)rb_node_imaginary_new(p,val,base,seen_point,numeric_type,loc)
-#define NEW_STR(s,loc) (NODE *)rb_node_str_new(p,s,loc)
-#define NEW_DSTR0(s,l,n,loc) (NODE *)rb_node_dstr_new0(p,s,l,n,loc)
-#define NEW_DSTR(s,loc) (NODE *)rb_node_dstr_new(p,s,loc)
-#define NEW_XSTR(s,loc) (NODE *)rb_node_xstr_new(p,s,loc)
-#define NEW_DXSTR(s,l,n,loc) (NODE *)rb_node_dxstr_new(p,s,l,n,loc)
-#define NEW_EVSTR(n,loc) (NODE *)rb_node_evstr_new(p,n,loc)
-#define NEW_REGX(str,opts,loc) (NODE *)rb_node_regx_new(p,str,opts,loc)
-#define NEW_ONCE(b,loc) (NODE *)rb_node_once_new(p,b,loc)
-#define NEW_ARGS(loc) rb_node_args_new(p,loc)
-#define NEW_ARGS_AUX(r,b,loc) rb_node_args_aux_new(p,r,b,loc)
-#define NEW_OPT_ARG(v,loc) rb_node_opt_arg_new(p,v,loc)
-#define NEW_KW_ARG(v,loc) rb_node_kw_arg_new(p,v,loc)
-#define NEW_POSTARG(i,v,loc) (NODE *)rb_node_postarg_new(p,i,v,loc)
-#define NEW_ARGSCAT(a,b,loc) (NODE *)rb_node_argscat_new(p,a,b,loc)
-#define NEW_ARGSPUSH(a,b,loc) (NODE *)rb_node_argspush_new(p,a,b,loc)
-#define NEW_SPLAT(a,loc,op_loc) (NODE *)rb_node_splat_new(p,a,loc,op_loc)
-#define NEW_BLOCK_PASS(b,loc,o_loc) rb_node_block_pass_new(p,b,loc,o_loc)
-#define NEW_DEFN(i,s,loc) (NODE *)rb_node_defn_new(p,i,s,loc)
-#define NEW_DEFS(r,i,s,loc) (NODE *)rb_node_defs_new(p,r,i,s,loc)
-#define NEW_ALIAS(n,o,loc,k_loc) (NODE *)rb_node_alias_new(p,n,o,loc,k_loc)
-#define NEW_VALIAS(n,o,loc,k_loc) (NODE *)rb_node_valias_new(p,n,o,loc,k_loc)
-#define NEW_UNDEF(i,loc) (NODE *)rb_node_undef_new(p,i,loc)
-#define NEW_CLASS(n,b,s,loc) (NODE *)rb_node_class_new(p,n,b,s,loc)
-#define NEW_MODULE(n,b,loc) (NODE *)rb_node_module_new(p,n,b,loc)
-#define NEW_SCLASS(r,b,loc) (NODE *)rb_node_sclass_new(p,r,b,loc)
-#define NEW_COLON2(c,i,loc) (NODE *)rb_node_colon2_new(p,c,i,loc)
-#define NEW_COLON3(i,loc) (NODE *)rb_node_colon3_new(p,i,loc)
-#define NEW_DOT2(b,e,loc) (NODE *)rb_node_dot2_new(p,b,e,loc)
-#define NEW_DOT3(b,e,loc) (NODE *)rb_node_dot3_new(p,b,e,loc)
-#define NEW_SELF(loc) (NODE *)rb_node_self_new(p,loc)
-#define NEW_NIL(loc) (NODE *)rb_node_nil_new(p,loc)
-#define NEW_TRUE(loc) (NODE *)rb_node_true_new(p,loc)
-#define NEW_FALSE(loc) (NODE *)rb_node_false_new(p,loc)
-#define NEW_ERRINFO(loc) (NODE *)rb_node_errinfo_new(p,loc)
-#define NEW_DEFINED(e,loc) (NODE *)rb_node_defined_new(p,e,loc)
-#define NEW_POSTEXE(b,loc) (NODE *)rb_node_postexe_new(p,b,loc)
-#define NEW_SYM(str,loc) (NODE *)rb_node_sym_new(p,str,loc)
-#define NEW_DSYM(s,l,n,loc) (NODE *)rb_node_dsym_new(p,s,l,n,loc)
-#define NEW_ATTRASGN(r,m,a,loc) (NODE *)rb_node_attrasgn_new(p,r,m,a,loc)
-#define NEW_LAMBDA(a,b,loc) (NODE *)rb_node_lambda_new(p,a,b,loc)
-#define NEW_ARYPTN(pre,r,post,loc) (NODE *)rb_node_aryptn_new(p,pre,r,post,loc)
-#define NEW_HSHPTN(c,kw,kwrest,loc) (NODE *)rb_node_hshptn_new(p,c,kw,kwrest,loc)
-#define NEW_FNDPTN(pre,a,post,loc) (NODE *)rb_node_fndptn_new(p,pre,a,post,loc)
-#define NEW_LINE(loc) (NODE *)rb_node_line_new(p,loc)
-#define NEW_FILE(str,loc) (NODE *)rb_node_file_new(p,str,loc)
-#define NEW_ENCODING(loc) (NODE *)rb_node_encoding_new(p,loc)
-#define NEW_ERROR(loc) (NODE *)rb_node_error_new(p,loc)
-
-enum internal_node_type {
- NODE_INTERNAL_ONLY = NODE_LAST,
- NODE_DEF_TEMP,
- NODE_EXITS,
- NODE_INTERNAL_LAST
-};
-
-static const char *
-parser_node_name(int node)
+#ifdef RIPPER
+static inline VALUE
+add_mark_object(struct parser_params *p, VALUE obj)
{
- switch (node) {
- case NODE_DEF_TEMP:
- return "NODE_DEF_TEMP";
- case NODE_EXITS:
- return "NODE_EXITS";
- default:
- return ruby_node_name(node);
+ if (!SPECIAL_CONST_P(obj)
+ && !RB_TYPE_P(obj, T_NODE) /* Ripper jumbles NODE objects and other objects... */
+ ) {
+ rb_ast_add_mark_object(p->ast, obj);
}
+ return obj;
}
+#else
+static NODE* node_newnode_with_locals(struct parser_params *, enum node_type, VALUE, VALUE, const rb_code_location_t*);
+#endif
-/* This node is parse.y internal */
-struct RNode_DEF_TEMP {
- NODE node;
-
- /* for NODE_DEFN/NODE_DEFS */
-
- struct RNode *nd_def;
- ID nd_mid;
-
- struct {
- int max_numparam;
- NODE *numparam_save;
- struct lex_context ctxt;
- } save;
-};
-
-#define RNODE_DEF_TEMP(node) ((struct RNode_DEF_TEMP *)(node))
-
-static rb_node_break_t *rb_node_break_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc, const YYLTYPE *keyword_loc);
-static rb_node_next_t *rb_node_next_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc, const YYLTYPE *keyword_loc);
-static rb_node_redo_t *rb_node_redo_new(struct parser_params *p, const YYLTYPE *loc, const YYLTYPE *keyword_loc);
-static rb_node_def_temp_t *rb_node_def_temp_new(struct parser_params *p, const YYLTYPE *loc);
-static rb_node_def_temp_t *def_head_save(struct parser_params *p, rb_node_def_temp_t *n);
-
-#define NEW_BREAK(s,loc,k_loc) (NODE *)rb_node_break_new(p,s,loc,k_loc)
-#define NEW_NEXT(s,loc,k_loc) (NODE *)rb_node_next_new(p,s,loc,k_loc)
-#define NEW_REDO(loc,k_loc) (NODE *)rb_node_redo_new(p,loc,k_loc)
-#define NEW_DEF_TEMP(loc) rb_node_def_temp_new(p,loc)
+static NODE* node_newnode(struct parser_params *, enum node_type, VALUE, VALUE, VALUE, const rb_code_location_t*);
+#define rb_node_newnode(type, a1, a2, a3, loc) node_newnode(p, (type), (a1), (a2), (a3), (loc))
-/* Make a new internal node, which should not be appeared in the
+/* Make a new temporal node, which should not be appeared in the
* result AST and does not have node_id and location. */
-static NODE* node_new_internal(struct parser_params *p, enum node_type type, size_t size, size_t alignment);
-#define NODE_NEW_INTERNAL(ndtype, type) (type *)node_new_internal(p, (enum node_type)(ndtype), sizeof(type), RUBY_ALIGNOF(type))
+static NODE* node_new_temporal(struct parser_params *p, enum node_type type, VALUE a0, VALUE a1, VALUE a2);
+#define NODE_NEW_TEMPORAL(t,a0,a1,a2) node_new_temporal(p, (t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2))
static NODE *nd_set_loc(NODE *nd, const YYLTYPE *loc);
@@ -1338,14 +709,7 @@ parser_get_node_id(struct parser_params *p)
return node_id;
}
-static void
-anddot_multiple_assignment_check(struct parser_params* p, const YYLTYPE *loc, ID id)
-{
- if (id == tANDDOT) {
- yyerror1(loc, "&. inside multiple assignment destination");
- }
-}
-
+#ifndef RIPPER
static inline void
set_line_body(NODE *body, int line)
{
@@ -1353,44 +717,18 @@ set_line_body(NODE *body, int line)
switch (nd_type(body)) {
case NODE_RESCUE:
case NODE_ENSURE:
- nd_set_line(body, line);
+ nd_set_line(body, line);
}
}
-static void
-set_embraced_location(NODE *node, const rb_code_location_t *beg, const rb_code_location_t *end)
-{
- RNODE_ITER(node)->nd_body->nd_loc = code_loc_gen(beg, end);
- nd_set_line(node, beg->end_pos.lineno);
-}
-
-static NODE *
-last_expr_node(NODE *expr)
-{
- while (expr) {
- if (nd_type_p(expr, NODE_BLOCK)) {
- expr = RNODE_BLOCK(RNODE_BLOCK(expr)->nd_end)->nd_head;
- }
- else if (nd_type_p(expr, NODE_BEGIN) && RNODE_BEGIN(expr)->nd_body) {
- expr = RNODE_BEGIN(expr)->nd_body;
- }
- else {
- break;
- }
- }
- return expr;
-}
-
-#ifndef RIPPER
#define yyparse ruby_yyparse
-#endif
static NODE* cond(struct parser_params *p, NODE *node, const YYLTYPE *loc);
static NODE* method_cond(struct parser_params *p, NODE *node, const YYLTYPE *loc);
#define new_nil(loc) NEW_NIL(loc)
static NODE *new_nil_at(struct parser_params *p, const rb_code_position_t *pos);
static NODE *new_if(struct parser_params*,NODE*,NODE*,NODE*,const YYLTYPE*);
-static NODE *new_unless(struct parser_params*,NODE*,NODE*,NODE*,const YYLTYPE*,const YYLTYPE*,const YYLTYPE*,const YYLTYPE*);
+static NODE *new_unless(struct parser_params*,NODE*,NODE*,NODE*,const YYLTYPE*);
static NODE *logop(struct parser_params*,ID,NODE*,NODE*,const YYLTYPE*,const YYLTYPE*);
static NODE *newline_node(NODE*);
@@ -1399,6 +737,7 @@ static void fixpos(NODE*,NODE*);
static int value_expr_gen(struct parser_params*,NODE*);
static void void_expr(struct parser_params*,NODE*);
static NODE *remove_begin(NODE*);
+static NODE *remove_begin_all(NODE*);
#define value_expr(node) value_expr_gen(p, (node))
static NODE *void_stmts(struct parser_params*,NODE*);
static void reduce_nodes(struct parser_params*,NODE**);
@@ -1413,7 +752,6 @@ static NODE *rest_arg_append(struct parser_params *p, NODE *args, NODE *rest_arg
static NODE *literal_concat(struct parser_params*,NODE*,NODE*,const YYLTYPE*);
static NODE *new_evstr(struct parser_params*,NODE*,const YYLTYPE*);
static NODE *new_dstr(struct parser_params*,NODE*,const YYLTYPE*);
-static NODE *str2dstr(struct parser_params*,NODE*);
static NODE *evstr2dstr(struct parser_params*,NODE*);
static NODE *splat_array(NODE*);
static void mark_lvar_used(struct parser_params *p, NODE *rhs);
@@ -1422,24 +760,24 @@ static NODE *call_bin_op(struct parser_params*,NODE*,ID,NODE*,const YYLTYPE*,con
static NODE *call_uni_op(struct parser_params*,NODE*,ID,const YYLTYPE*,const YYLTYPE*);
static NODE *new_qcall(struct parser_params* p, ID atype, NODE *recv, ID mid, NODE *args, const YYLTYPE *op_loc, const YYLTYPE *loc);
static NODE *new_command_qcall(struct parser_params* p, ID atype, NODE *recv, ID mid, NODE *args, NODE *block, const YYLTYPE *op_loc, const YYLTYPE *loc);
-static NODE *method_add_block(struct parser_params*p, NODE *m, NODE *b, const YYLTYPE *loc) {RNODE_ITER(b)->nd_iter = m; b->nd_loc = *loc; return b;}
+static NODE *method_add_block(struct parser_params*p, NODE *m, NODE *b, const YYLTYPE *loc) {b->nd_iter = m; b->nd_loc = *loc; return b;}
static bool args_info_empty_p(struct rb_args_info *args);
-static rb_node_args_t *new_args(struct parser_params*,rb_node_args_aux_t*,rb_node_opt_arg_t*,ID,rb_node_args_aux_t*,rb_node_args_t*,const YYLTYPE*);
-static rb_node_args_t *new_args_tail(struct parser_params*,rb_node_kw_arg_t*,ID,ID,const YYLTYPE*);
+static NODE *new_args(struct parser_params*,NODE*,NODE*,ID,NODE*,NODE*,const YYLTYPE*);
+static NODE *new_args_tail(struct parser_params*,NODE*,ID,ID,const YYLTYPE*);
static NODE *new_array_pattern(struct parser_params *p, NODE *constant, NODE *pre_arg, NODE *aryptn, const YYLTYPE *loc);
-static NODE *new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, NODE *rest_arg, NODE *post_args, const YYLTYPE *loc);
+static NODE *new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, ID rest_arg, NODE *post_args, const YYLTYPE *loc);
static NODE *new_find_pattern(struct parser_params *p, NODE *constant, NODE *fndptn, const YYLTYPE *loc);
-static NODE *new_find_pattern_tail(struct parser_params *p, NODE *pre_rest_arg, NODE *args, NODE *post_rest_arg, const YYLTYPE *loc);
+static NODE *new_find_pattern_tail(struct parser_params *p, ID pre_rest_arg, NODE *args, ID post_rest_arg, const YYLTYPE *loc);
static NODE *new_hash_pattern(struct parser_params *p, NODE *constant, NODE *hshptn, const YYLTYPE *loc);
static NODE *new_hash_pattern_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, const YYLTYPE *loc);
-static rb_node_kw_arg_t *new_kw_arg(struct parser_params *p, NODE *k, const YYLTYPE *loc);
-static rb_node_args_t *args_with_numbered(struct parser_params*,rb_node_args_t*,int,ID);
+static NODE *new_kw_arg(struct parser_params *p, NODE *k, const YYLTYPE *loc);
+static NODE *args_with_numbered(struct parser_params*,NODE*,int);
-static NODE* negate_lit(struct parser_params*, NODE*);
+static VALUE negate_lit(struct parser_params*, VALUE);
static NODE *ret_args(struct parser_params*,NODE*);
-static NODE *arg_blk_pass(NODE*,rb_node_block_pass_t*);
+static NODE *arg_blk_pass(NODE*,NODE*);
static NODE *new_yield(struct parser_params*,NODE*,const YYLTYPE*);
static NODE *dsym_node(struct parser_params*,NODE*,const YYLTYPE*);
@@ -1449,19 +787,19 @@ static NODE *assignable(struct parser_params*,ID,NODE*,const YYLTYPE*);
static NODE *aryset(struct parser_params*,NODE*,NODE*,const YYLTYPE*);
static NODE *attrset(struct parser_params*,NODE*,ID,ID,const YYLTYPE*);
-static VALUE rb_backref_error(struct parser_params*,NODE*);
+static void rb_backref_error(struct parser_params*,NODE*);
static NODE *node_assign(struct parser_params*,NODE*,NODE*,struct lex_context,const YYLTYPE*);
static NODE *new_op_assign(struct parser_params *p, NODE *lhs, ID op, NODE *rhs, struct lex_context, const YYLTYPE *loc);
-static NODE *new_ary_op_assign(struct parser_params *p, NODE *ary, NODE *args, ID op, NODE *rhs, const YYLTYPE *args_loc, const YYLTYPE *loc, const YYLTYPE *call_operator_loc, const YYLTYPE *opening_loc, const YYLTYPE *closing_loc, const YYLTYPE *binary_operator_loc);
-static NODE *new_attr_op_assign(struct parser_params *p, NODE *lhs, ID atype, ID attr, ID op, NODE *rhs, const YYLTYPE *loc, const YYLTYPE *call_operator_loc, const YYLTYPE *message_loc, const YYLTYPE *binary_operator_loc);
+static NODE *new_ary_op_assign(struct parser_params *p, NODE *ary, NODE *args, ID op, NODE *rhs, const YYLTYPE *args_loc, const YYLTYPE *loc);
+static NODE *new_attr_op_assign(struct parser_params *p, NODE *lhs, ID atype, ID attr, ID op, NODE *rhs, const YYLTYPE *loc);
static NODE *new_const_op_assign(struct parser_params *p, NODE *lhs, ID op, NODE *rhs, struct lex_context, const YYLTYPE *loc);
static NODE *new_bodystmt(struct parser_params *p, NODE *head, NODE *rescue, NODE *rescue_else, NODE *ensure, const YYLTYPE *loc);
static NODE *const_decl(struct parser_params *p, NODE* path, const YYLTYPE *loc);
-static rb_node_opt_arg_t *opt_arg_append(rb_node_opt_arg_t*, rb_node_opt_arg_t*);
-static rb_node_kw_arg_t *kwd_append(rb_node_kw_arg_t*, rb_node_kw_arg_t*);
+static NODE *opt_arg_append(NODE*, NODE*);
+static NODE *kwd_append(NODE*, NODE*);
static NODE *new_hash(struct parser_params *p, NODE *hash, const YYLTYPE *loc);
static NODE *new_unique_key_hash(struct parser_params *p, NODE *hash, const YYLTYPE *loc);
@@ -1480,28 +818,81 @@ static NODE *match_op(struct parser_params*,NODE*,NODE*,const YYLTYPE*,const YYL
static rb_ast_id_table_t *local_tbl(struct parser_params*);
-static VALUE reg_compile(struct parser_params*, rb_parser_string_t*, int);
-static void reg_fragment_setenc(struct parser_params*, rb_parser_string_t*, int);
-#define reg_fragment_check rb_parser_reg_fragment_check
-int reg_fragment_check(struct parser_params*, rb_parser_string_t*, int);
+static VALUE reg_compile(struct parser_params*, VALUE, int);
+static void reg_fragment_setenc(struct parser_params*, VALUE, int);
+static int reg_fragment_check(struct parser_params*, VALUE, int);
+static NODE *reg_named_capture_assign(struct parser_params* p, VALUE regexp, const YYLTYPE *loc);
-static int literal_concat0(struct parser_params *p, rb_parser_string_t *head, rb_parser_string_t *tail);
+static int literal_concat0(struct parser_params *p, VALUE head, VALUE tail);
static NODE *heredoc_dedent(struct parser_params*,NODE*);
static void check_literal_when(struct parser_params *p, NODE *args, const YYLTYPE *loc);
-#ifdef RIPPER
-#define get_value(idx) (rb_ary_entry(p->s_value_stack, idx))
-#define set_value(val) (p->s_lvalue = val)
-static VALUE assign_error(struct parser_params *p, const char *mesg, VALUE a);
+#define get_id(id) (id)
+#define get_value(val) (val)
+#define get_num(num) (num)
+#else /* RIPPER */
+#define NODE_RIPPER NODE_CDECL
+#define NEW_RIPPER(a,b,c,loc) (VALUE)NEW_CDECL(a,b,c,loc)
+
+static inline int ripper_is_node_yylval(VALUE n);
+
+static inline VALUE
+ripper_new_yylval(struct parser_params *p, ID a, VALUE b, VALUE c)
+{
+ if (ripper_is_node_yylval(c)) c = RNODE(c)->nd_cval;
+ add_mark_object(p, b);
+ add_mark_object(p, c);
+ return NEW_RIPPER(a, b, c, &NULL_LOC);
+}
+
+static inline int
+ripper_is_node_yylval(VALUE n)
+{
+ return RB_TYPE_P(n, T_NODE) && nd_type_p(RNODE(n), NODE_RIPPER);
+}
+
+#define value_expr(node) ((void)(node))
+#define remove_begin(node) (node)
+#define void_stmts(p,x) (x)
+#define rb_dvar_defined(id, base) 0
+#define rb_local_defined(id, base) 0
+static ID ripper_get_id(VALUE);
+#define get_id(id) ripper_get_id(id)
+static VALUE ripper_get_value(VALUE);
+#define get_value(val) ripper_get_value(val)
+#define get_num(num) (int)get_id(num)
+static VALUE assignable(struct parser_params*,VALUE);
static int id_is_var(struct parser_params *p, ID id);
-#endif
+
+#define method_cond(p,node,loc) (node)
+#define call_bin_op(p, recv,id,arg1,op_loc,loc) dispatch3(binary, (recv), STATIC_ID2SYM(id), (arg1))
+#define match_op(p,node1,node2,op_loc,loc) call_bin_op(0, (node1), idEqTilde, (node2), op_loc, loc)
+#define call_uni_op(p, recv,id,op_loc,loc) dispatch2(unary, STATIC_ID2SYM(id), (recv))
+#define logop(p,id,node1,node2,op_loc,loc) call_bin_op(0, (node1), (id), (node2), op_loc, loc)
+
+#define new_nil(loc) Qnil
+
+static VALUE new_regexp(struct parser_params *, VALUE, VALUE, const YYLTYPE *);
+
+static VALUE const_decl(struct parser_params *p, VALUE path);
+
+static VALUE var_field(struct parser_params *p, VALUE a);
+static VALUE assign_error(struct parser_params *p, const char *mesg, VALUE a);
+
+static VALUE parser_reg_compile(struct parser_params*, VALUE, int, VALUE *);
+
+static VALUE backref_error(struct parser_params*, NODE *, VALUE);
+#endif /* !RIPPER */
+
+/* forward declaration */
+typedef struct rb_strterm_heredoc_struct rb_strterm_heredoc_t;
RUBY_SYMBOL_EXPORT_BEGIN
VALUE rb_parser_reg_compile(struct parser_params* p, VALUE str, int options);
-int rb_reg_fragment_setenc(struct parser_params*, rb_parser_string_t *, int);
+int rb_reg_fragment_setenc(struct parser_params*, VALUE, int);
enum lex_state_e rb_parser_trace_lex_state(struct parser_params *, enum lex_state_e, enum lex_state_e, int);
-VALUE rb_parser_lex_state_name(struct parser_params *p, enum lex_state_e state);
+VALUE rb_parser_lex_state_name(enum lex_state_e state);
void rb_parser_show_bitstack(struct parser_params *, stack_type, const char *, int);
PRINTF_ARGS(void rb_parser_fatal(struct parser_params *p, const char *fmt, ...), 2, 3);
YYLTYPE *rb_parser_set_location_from_strterm_heredoc(struct parser_params *p, rb_strterm_heredoc_t *here, YYLTYPE *yylloc);
@@ -1510,13 +901,15 @@ YYLTYPE *rb_parser_set_location_of_heredoc_end(struct parser_params *p, YYLTYPE
YYLTYPE *rb_parser_set_location_of_dummy_end(struct parser_params *p, YYLTYPE *yylloc);
YYLTYPE *rb_parser_set_location_of_none(struct parser_params *p, YYLTYPE *yylloc);
YYLTYPE *rb_parser_set_location(struct parser_params *p, YYLTYPE *yylloc);
-void ruby_show_error_line(struct parser_params *p, VALUE errbuf, const YYLTYPE *yylloc, int lineno, rb_parser_string_t *str);
RUBY_SYMBOL_EXPORT_END
-static void flush_string_content(struct parser_params *p, rb_encoding *enc, size_t back);
static void error_duplicate_pattern_variable(struct parser_params *p, ID id, const YYLTYPE *loc);
static void error_duplicate_pattern_key(struct parser_params *p, ID id, const YYLTYPE *loc);
-static VALUE formal_argument_error(struct parser_params*, ID);
+#ifndef RIPPER
+static ID formal_argument(struct parser_params*, ID);
+#else
+static ID formal_argument(struct parser_params*, VALUE);
+#endif
static ID shadowing_lvar(struct parser_params*,ID);
static void new_bv(struct parser_params*,ID);
@@ -1526,20 +919,19 @@ static void local_var(struct parser_params*, ID);
static void arg_var(struct parser_params*, ID);
static int local_id(struct parser_params *p, ID id);
static int local_id_ref(struct parser_params*, ID, ID **);
-#define internal_id rb_parser_internal_id
-ID internal_id(struct parser_params*);
+#ifndef RIPPER
+static ID internal_id(struct parser_params*);
static NODE *new_args_forward_call(struct parser_params*, NODE*, const YYLTYPE*, const YYLTYPE*);
+#endif
static int check_forwarding_args(struct parser_params*);
static void add_forwarding_args(struct parser_params *p);
-static void forwarding_arg_check(struct parser_params *p, ID arg, ID all, const char *var);
static const struct vtable *dyna_push(struct parser_params *);
static void dyna_pop(struct parser_params*, const struct vtable *);
static int dyna_in_block(struct parser_params*);
#define dyna_var(p, id) local_var(p, id)
static int dvar_defined(struct parser_params*, ID);
-#define dvar_defined_ref rb_parser_dvar_defined_ref
-int dvar_defined_ref(struct parser_params*, ID, ID**);
+static int dvar_defined_ref(struct parser_params*, ID, ID**);
static int dvar_curr(struct parser_params*,ID);
static int lvar_defined(struct parser_params*, ID);
@@ -1547,17 +939,18 @@ static int lvar_defined(struct parser_params*, ID);
static NODE *numparam_push(struct parser_params *p);
static void numparam_pop(struct parser_params *p, NODE *prev_inner);
-#define METHOD_NOT '!'
+#ifdef RIPPER
+# define METHOD_NOT idNOT
+#else
+# define METHOD_NOT '!'
+#endif
#define idFWD_REST '*'
#define idFWD_KWREST idPow /* Use simple "**", as tDSTAR is "**arg" */
#define idFWD_BLOCK '&'
#define idFWD_ALL idDot3
-#define arg_FWD_BLOCK idFWD_BLOCK
+#define FORWARD_ARGS_WITH_RUBY2_KEYWORDS
-#define RE_ONIG_OPTION_IGNORECASE 1
-#define RE_ONIG_OPTION_EXTEND (RE_ONIG_OPTION_IGNORECASE<<1)
-#define RE_ONIG_OPTION_MULTILINE (RE_ONIG_OPTION_EXTEND<<1)
#define RE_OPTION_ONCE (1<<16)
#define RE_OPTION_ENCODING_SHIFT 8
#define RE_OPTION_ENCODING(e) (((e)&0xff)<<RE_OPTION_ENCODING_SHIFT)
@@ -1566,11 +959,74 @@ static void numparam_pop(struct parser_params *p, NODE *prev_inner);
#define RE_OPTION_MASK 0xff
#define RE_OPTION_ARG_ENCODING_NONE 32
-#define CHECK_LITERAL_WHEN (st_table *)1
-#define CASE_LABELS_ENABLED_P(case_labels) (case_labels && case_labels != CHECK_LITERAL_WHEN)
+/* structs for managing terminator of string literal and heredocment */
+typedef struct rb_strterm_literal_struct {
+ union {
+ VALUE dummy;
+ long nest;
+ } u0;
+ union {
+ VALUE dummy;
+ long func; /* STR_FUNC_* (e.g., STR_FUNC_ESCAPE and STR_FUNC_EXPAND) */
+ } u1;
+ union {
+ VALUE dummy;
+ long paren; /* '(' of `%q(...)` */
+ } u2;
+ union {
+ VALUE dummy;
+ long term; /* ')' of `%q(...)` */
+ } u3;
+} rb_strterm_literal_t;
+
+#define HERETERM_LENGTH_BITS ((SIZEOF_VALUE - 1) * CHAR_BIT - 1)
+
+struct rb_strterm_heredoc_struct {
+ VALUE lastline; /* the string of line that contains `<<"END"` */
+ long offset; /* the column of END in `<<"END"` */
+ int sourceline; /* lineno of the line that contains `<<"END"` */
+ unsigned length /* the length of END in `<<"END"` */
+#if HERETERM_LENGTH_BITS < SIZEOF_INT * CHAR_BIT
+ : HERETERM_LENGTH_BITS
+# define HERETERM_LENGTH_MAX ((1U << HERETERM_LENGTH_BITS) - 1)
+#else
+# define HERETERM_LENGTH_MAX UINT_MAX
+#endif
+ ;
+#if HERETERM_LENGTH_BITS < SIZEOF_INT * CHAR_BIT
+ unsigned quote: 1;
+ unsigned func: 8;
+#else
+ uint8_t quote;
+ uint8_t func;
+#endif
+};
+STATIC_ASSERT(rb_strterm_heredoc_t, sizeof(rb_strterm_heredoc_t) <= 4 * SIZEOF_VALUE);
+
+#define STRTERM_HEREDOC IMEMO_FL_USER0
+
+struct rb_strterm_struct {
+ VALUE flags;
+ union {
+ rb_strterm_literal_t literal;
+ rb_strterm_heredoc_t heredoc;
+ } u;
+};
+
+#ifndef RIPPER
+void
+rb_strterm_mark(VALUE obj)
+{
+ rb_strterm_t *strterm = (rb_strterm_t*)obj;
+ if (RBASIC(obj)->flags & STRTERM_HEREDOC) {
+ rb_strterm_heredoc_t *heredoc = &strterm->u.heredoc;
+ rb_gc_mark(heredoc->lastline);
+ }
+}
+#endif
#define yytnamerr(yyres, yystr) (YYSIZE_T)rb_yytnamerr(p, yyres, yystr)
-RUBY_FUNC_EXPORTED size_t rb_yytnamerr(struct parser_params *p, char *yyres, const char *yystr);
+size_t rb_yytnamerr(struct parser_params *p, char *yyres, const char *yystr);
#define TOKEN2ID(tok) ( \
tTOKEN_LOCAL_BEGIN<(tok)&&(tok)<tTOKEN_LOCAL_END ? TOKEN2LOCALID(tok) : \
@@ -1584,11 +1040,12 @@ RUBY_FUNC_EXPORTED size_t rb_yytnamerr(struct parser_params *p, char *yyres, con
/****** Ripper *******/
#ifdef RIPPER
+#define RIPPER_VERSION "0.1.0"
-#include "eventids1.h"
-#include "eventids2.h"
+static inline VALUE intern_sym(const char *name);
-extern const struct ripper_parser_ids ripper_parser_ids;
+#include "eventids1.c"
+#include "eventids2.c"
static VALUE ripper_dispatch0(struct parser_params*,ID);
static VALUE ripper_dispatch1(struct parser_params*,ID,VALUE);
@@ -1597,126 +1054,212 @@ static VALUE ripper_dispatch3(struct parser_params*,ID,VALUE,VALUE,VALUE);
static VALUE ripper_dispatch4(struct parser_params*,ID,VALUE,VALUE,VALUE,VALUE);
static VALUE ripper_dispatch5(struct parser_params*,ID,VALUE,VALUE,VALUE,VALUE,VALUE);
static VALUE ripper_dispatch7(struct parser_params*,ID,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE,VALUE);
-void ripper_error(struct parser_params *p);
+static void ripper_error(struct parser_params *p);
-#define dispatch0(n) ripper_dispatch0(p, RIPPER_ID(n))
-#define dispatch1(n,a) ripper_dispatch1(p, RIPPER_ID(n), (a))
-#define dispatch2(n,a,b) ripper_dispatch2(p, RIPPER_ID(n), (a), (b))
-#define dispatch3(n,a,b,c) ripper_dispatch3(p, RIPPER_ID(n), (a), (b), (c))
-#define dispatch4(n,a,b,c,d) ripper_dispatch4(p, RIPPER_ID(n), (a), (b), (c), (d))
-#define dispatch5(n,a,b,c,d,e) ripper_dispatch5(p, RIPPER_ID(n), (a), (b), (c), (d), (e))
-#define dispatch7(n,a,b,c,d,e,f,g) ripper_dispatch7(p, RIPPER_ID(n), (a), (b), (c), (d), (e), (f), (g))
+#define dispatch0(n) ripper_dispatch0(p, TOKEN_PASTE(ripper_id_, n))
+#define dispatch1(n,a) ripper_dispatch1(p, TOKEN_PASTE(ripper_id_, n), (a))
+#define dispatch2(n,a,b) ripper_dispatch2(p, TOKEN_PASTE(ripper_id_, n), (a), (b))
+#define dispatch3(n,a,b,c) ripper_dispatch3(p, TOKEN_PASTE(ripper_id_, n), (a), (b), (c))
+#define dispatch4(n,a,b,c,d) ripper_dispatch4(p, TOKEN_PASTE(ripper_id_, n), (a), (b), (c), (d))
+#define dispatch5(n,a,b,c,d,e) ripper_dispatch5(p, TOKEN_PASTE(ripper_id_, n), (a), (b), (c), (d), (e))
+#define dispatch7(n,a,b,c,d,e,f,g) ripper_dispatch7(p, TOKEN_PASTE(ripper_id_, n), (a), (b), (c), (d), (e), (f), (g))
#define yyparse ripper_yyparse
+#define ID2VAL(id) STATIC_ID2SYM(id)
+#define TOKEN2VAL(t) ID2VAL(TOKEN2ID(t))
+#define KWD2EID(t, v) ripper_new_yylval(p, keyword_##t, get_value(v), 0)
+
+#define params_new(pars, opts, rest, pars2, kws, kwrest, blk) \
+ dispatch7(params, (pars), (opts), (rest), (pars2), (kws), (kwrest), (blk))
+
+#define escape_Qundef(x) ((x)==Qundef ? Qnil : (x))
+
+static inline VALUE
+new_args(struct parser_params *p, VALUE pre_args, VALUE opt_args, VALUE rest_arg, VALUE post_args, VALUE tail, YYLTYPE *loc)
+{
+ NODE *t = (NODE *)tail;
+ VALUE kw_args = t->u1.value, kw_rest_arg = t->u2.value, block = t->u3.value;
+ return params_new(pre_args, opt_args, rest_arg, post_args, kw_args, kw_rest_arg, escape_Qundef(block));
+}
+
+static inline VALUE
+new_args_tail(struct parser_params *p, VALUE kw_args, VALUE kw_rest_arg, VALUE block, YYLTYPE *loc)
+{
+ NODE *t = rb_node_newnode(NODE_ARGS_AUX, kw_args, kw_rest_arg, block, &NULL_LOC);
+ add_mark_object(p, kw_args);
+ add_mark_object(p, kw_rest_arg);
+ add_mark_object(p, block);
+ return (VALUE)t;
+}
+
+static inline VALUE
+args_with_numbered(struct parser_params *p, VALUE args, int max_numparam)
+{
+ return args;
+}
+
static VALUE
-aryptn_pre_args(struct parser_params *p, VALUE pre_arg, VALUE pre_args)
+new_array_pattern(struct parser_params *p, VALUE constant, VALUE pre_arg, VALUE aryptn, const YYLTYPE *loc)
{
+ NODE *t = (NODE *)aryptn;
+ VALUE pre_args = t->u1.value, rest_arg = t->u2.value, post_args = t->u3.value;
+
if (!NIL_P(pre_arg)) {
- if (!NIL_P(pre_args)) {
- rb_ary_unshift(pre_args, pre_arg);
- }
- else {
- pre_args = rb_ary_new_from_args(1, pre_arg);
- }
+ if (!NIL_P(pre_args)) {
+ rb_ary_unshift(pre_args, pre_arg);
+ }
+ else {
+ pre_args = rb_ary_new_from_args(1, pre_arg);
+ }
}
- return pre_args;
+ return dispatch4(aryptn, constant, pre_args, rest_arg, post_args);
}
-#define ID2VAL(id) STATIC_ID2SYM(id)
-#define TOKEN2VAL(t) ID2VAL(TOKEN2ID(t))
-#endif /* RIPPER */
+static VALUE
+new_array_pattern_tail(struct parser_params *p, VALUE pre_args, VALUE has_rest, VALUE rest_arg, VALUE post_args, const YYLTYPE *loc)
+{
+ NODE *t;
+
+ if (has_rest) {
+ rest_arg = dispatch1(var_field, rest_arg ? rest_arg : Qnil);
+ }
+ else {
+ rest_arg = Qnil;
+ }
+
+ t = rb_node_newnode(NODE_ARYPTN, pre_args, rest_arg, post_args, &NULL_LOC);
+ add_mark_object(p, pre_args);
+ add_mark_object(p, rest_arg);
+ add_mark_object(p, post_args);
+ return (VALUE)t;
+}
+
+static VALUE
+new_find_pattern(struct parser_params *p, VALUE constant, VALUE fndptn, const YYLTYPE *loc)
+{
+ NODE *t = (NODE *)fndptn;
+ VALUE pre_rest_arg = t->u1.value, args = t->u2.value, post_rest_arg = t->u3.value;
+ return dispatch4(fndptn, constant, pre_rest_arg, args, post_rest_arg);
+}
+
+static VALUE
+new_find_pattern_tail(struct parser_params *p, VALUE pre_rest_arg, VALUE args, VALUE post_rest_arg, const YYLTYPE *loc)
+{
+ NODE *t;
+
+ pre_rest_arg = dispatch1(var_field, pre_rest_arg ? pre_rest_arg : Qnil);
+ post_rest_arg = dispatch1(var_field, post_rest_arg ? post_rest_arg : Qnil);
+
+ t = rb_node_newnode(NODE_FNDPTN, pre_rest_arg, args, post_rest_arg, &NULL_LOC);
+ add_mark_object(p, pre_rest_arg);
+ add_mark_object(p, args);
+ add_mark_object(p, post_rest_arg);
+ return (VALUE)t;
+}
+
+#define new_hash(p,h,l) rb_ary_new_from_args(0)
+
+static VALUE
+new_unique_key_hash(struct parser_params *p, VALUE ary, const YYLTYPE *loc)
+{
+ return ary;
+}
+
+static VALUE
+new_hash_pattern(struct parser_params *p, VALUE constant, VALUE hshptn, const YYLTYPE *loc)
+{
+ NODE *t = (NODE *)hshptn;
+ VALUE kw_args = t->u1.value, kw_rest_arg = t->u2.value;
+ return dispatch3(hshptn, constant, kw_args, kw_rest_arg);
+}
+
+static VALUE
+new_hash_pattern_tail(struct parser_params *p, VALUE kw_args, VALUE kw_rest_arg, const YYLTYPE *loc)
+{
+ NODE *t;
+ if (kw_rest_arg) {
+ kw_rest_arg = dispatch1(var_field, kw_rest_arg);
+ }
+ else {
+ kw_rest_arg = Qnil;
+ }
+ t = rb_node_newnode(NODE_HSHPTN, kw_args, kw_rest_arg, 0, &NULL_LOC);
+
+ add_mark_object(p, kw_args);
+ add_mark_object(p, kw_rest_arg);
+ return (VALUE)t;
+}
+
+#define new_defined(p,expr,loc) dispatch1(defined, (expr))
+
+static VALUE heredoc_dedent(struct parser_params*,VALUE);
+
+#else
+#define ID2VAL(id) (id)
+#define TOKEN2VAL(t) ID2VAL(t)
#define KWD2EID(t, v) keyword_##t
static NODE *
-new_scope_body(struct parser_params *p, rb_node_args_t *args, NODE *body, const YYLTYPE *loc)
+set_defun_body(struct parser_params *p, NODE *n, NODE *args, NODE *body, const YYLTYPE *loc)
{
body = remove_begin(body);
reduce_nodes(p, &body);
- NODE *n = NEW_SCOPE(args, body, loc);
- nd_set_line(n, loc->end_pos.lineno);
+ n->nd_defn = NEW_SCOPE(args, body, loc);
+ n->nd_loc = *loc;
+ nd_set_line(n->nd_defn, loc->end_pos.lineno);
set_line_body(body, loc->beg_pos.lineno);
return n;
}
static NODE *
rescued_expr(struct parser_params *p, NODE *arg, NODE *rescue,
- const YYLTYPE *arg_loc, const YYLTYPE *mod_loc, const YYLTYPE *res_loc)
+ const YYLTYPE *arg_loc, const YYLTYPE *mod_loc, const YYLTYPE *res_loc)
{
YYLTYPE loc = code_loc_gen(mod_loc, res_loc);
- rescue = NEW_RESBODY(0, 0, remove_begin(rescue), 0, &loc);
+ rescue = NEW_RESBODY(0, remove_begin(rescue), 0, &loc);
loc.beg_pos = arg_loc->beg_pos;
return NEW_RESCUE(arg, rescue, 0, &loc);
}
-static NODE *add_block_exit(struct parser_params *p, NODE *node);
-static rb_node_exits_t *init_block_exit(struct parser_params *p);
-static rb_node_exits_t *allow_block_exit(struct parser_params *p);
-static void restore_block_exit(struct parser_params *p, rb_node_exits_t *exits);
-static void clear_block_exit(struct parser_params *p, bool error);
-
-static void
-next_rescue_context(struct lex_context *next, const struct lex_context *outer, enum rescue_context def)
-{
- next->in_rescue = outer->in_rescue == after_rescue ? after_rescue : def;
-}
+#endif /* RIPPER */
static void
-restore_defun(struct parser_params *p, rb_node_def_temp_t *temp)
+restore_defun(struct parser_params *p, NODE *name)
{
- /* See: def_name action */
- struct lex_context ctxt = temp->save.ctxt;
- p->ctxt.in_def = ctxt.in_def;
- p->ctxt.shareable_constant_value = ctxt.shareable_constant_value;
- p->ctxt.in_rescue = ctxt.in_rescue;
- p->max_numparam = temp->save.max_numparam;
- numparam_pop(p, temp->save.numparam_save);
- clear_block_exit(p, true);
+ NODE *save = name->nd_next;
+ YYSTYPE c = {.val = save->nd_cval};
+ p->cur_arg = name->nd_vid;
+ p->ctxt.in_def = c.ctxt.in_def;
+ p->ctxt.shareable_constant_value = c.ctxt.shareable_constant_value;
+ p->max_numparam = (int)save->nd_nth;
+ numparam_pop(p, save->nd_head);
}
static void
-endless_method_name(struct parser_params *p, ID mid, const YYLTYPE *loc)
+endless_method_name(struct parser_params *p, NODE *defn, const YYLTYPE *loc)
{
+#ifdef RIPPER
+ defn = defn->nd_defn;
+#endif
+ ID mid = defn->nd_mid;
if (is_attrset_id(mid)) {
- yyerror1(loc, "setter method cannot be defined in an endless method definition");
+ yyerror1(loc, "setter method cannot be defined in an endless method definition");
}
token_info_drop(p, "def", loc->beg_pos);
}
-#define debug_token_line(p, name, line) do { \
- if (p->debug) { \
- const char *const pcur = p->lex.pcur; \
- const char *const ptok = p->lex.ptok; \
- rb_parser_printf(p, name ":%d (%d: %"PRIdPTRDIFF"|%"PRIdPTRDIFF"|%"PRIdPTRDIFF")\n", \
- line, p->ruby_sourceline, \
- ptok - p->lex.pbeg, pcur - ptok, p->lex.pend - pcur); \
- } \
- } while (0)
-
-#define begin_definition(k, loc_beg, loc_end) \
- do { \
- if (!(p->ctxt.in_class = (k)[0] != 0)) { \
- /* singleton class */ \
- p->ctxt.cant_return = !p->ctxt.in_def; \
- p->ctxt.in_def = 0; \
- } \
- else if (p->ctxt.in_def) { \
- YYLTYPE loc = code_loc_gen(loc_beg, loc_end); \
- yyerror1(&loc, k " definition in method body"); \
- } \
- else { \
- p->ctxt.cant_return = 1; \
- } \
- local_push(p, 0); \
- } while (0)
+#define debug_token_line(p, name, line) if (p->debug) rb_parser_printf(p, name ":%d (%d: %ld|%ld|%ld)\n", line, p->ruby_sourceline, p->lex.ptok - p->lex.pbeg, p->lex.pcur - p->lex.ptok, p->lex.pend - p->lex.pcur)
#ifndef RIPPER
+# define Qnone 0
+# define Qnull 0
# define ifndef_ripper(x) (x)
-# define ifdef_ripper(r,x) (x)
#else
+# define Qnone Qnil
+# define Qnull Qundef
# define ifndef_ripper(x)
-# define ifdef_ripper(r,x) (r)
#endif
# define rb_warn0(fmt) WARN_CALL(WARN_ARGS(fmt, 1))
@@ -1740,13 +1283,14 @@ endless_method_name(struct parser_params *p, ID mid, const YYLTYPE *loc)
# define rb_warning3L(l,fmt,a,b,c) WARNING_CALL(WARNING_ARGS_L(l, fmt, 4), (a), (b), (c))
# define rb_warning4L(l,fmt,a,b,c,d) WARNING_CALL(WARNING_ARGS_L(l, fmt, 5), (a), (b), (c), (d))
#ifdef RIPPER
-extern const ID id_warn, id_warning, id_gets, id_assoc;
+static ID id_warn, id_warning, id_gets, id_assoc;
# define ERR_MESG() STR_NEW2(mesg) /* to bypass Ripper DSL */
# define WARN_S_L(s,l) STR_NEW(s,l)
# define WARN_S(s) STR_NEW2(s)
# define WARN_I(i) INT2NUM(i)
# define WARN_ID(i) rb_id2str(i)
-# define PRIsWARN PRIsVALUE
+# define WARN_IVAL(i) i
+# define PRIsWARN "s"
# define rb_warn0L_experimental(l,fmt) WARN_CALL(WARN_ARGS_L(l, fmt, 1))
# define WARN_ARGS(fmt,n) p->value, id_warn, n, rb_usascii_str_new_lit(fmt)
# define WARN_ARGS_L(l,fmt,n) WARN_ARGS(fmt,n)
@@ -1762,12 +1306,14 @@ extern const ID id_warn, id_warning, id_gets, id_assoc;
# else
# define WARNING_CALL rb_funcall
# endif
+PRINTF_ARGS(static void ripper_compile_error(struct parser_params*, const char *fmt, ...), 2, 3);
# define compile_error ripper_compile_error
#else
# define WARN_S_L(s,l) s
# define WARN_S(s) s
# define WARN_I(i) i
# define WARN_ID(i) rb_id2name(i)
+# define WARN_IVAL(i) NUM2INT(i)
# define PRIsWARN PRIsVALUE
# define WARN_ARGS(fmt,n) WARN_ARGS_L(p->ruby_sourceline,fmt,n)
# define WARN_ARGS_L(l,fmt,n) p->ruby_sourcefile, (l), (fmt)
@@ -1776,966 +1322,125 @@ extern const ID id_warn, id_warning, id_gets, id_assoc;
# define WARNING_ARGS(fmt,n) WARN_ARGS(fmt,n)
# define WARNING_ARGS_L(l,fmt,n) WARN_ARGS_L(l,fmt,n)
# define WARNING_CALL rb_compile_warning
-PRINTF_ARGS(static void parser_compile_error(struct parser_params*, const rb_code_location_t *loc, const char *fmt, ...), 3, 4);
-# define compile_error(p, ...) parser_compile_error(p, NULL, __VA_ARGS__)
+PRINTF_ARGS(static void parser_compile_error(struct parser_params*, const char *fmt, ...), 2, 3);
+# define compile_error parser_compile_error
#endif
-#define RNODE_EXITS(node) ((rb_node_exits_t*)(node))
-
-static NODE *
-add_block_exit(struct parser_params *p, NODE *node)
-{
- if (!node) {
- compile_error(p, "unexpected null node");
- return 0;
- }
- switch (nd_type(node)) {
- case NODE_BREAK: case NODE_NEXT: case NODE_REDO: break;
- default:
- compile_error(p, "add_block_exit: unexpected node: %s", parser_node_name(nd_type(node)));
- return node;
- }
- if (!p->ctxt.in_defined) {
- rb_node_exits_t *exits = p->exits;
- if (exits) {
- RNODE_EXITS(exits->nd_stts)->nd_chain = node;
- exits->nd_stts = node;
- }
- }
- return node;
-}
-
-static rb_node_exits_t *
-init_block_exit(struct parser_params *p)
-{
- rb_node_exits_t *old = p->exits;
- rb_node_exits_t *exits = NODE_NEW_INTERNAL(NODE_EXITS, rb_node_exits_t);
- exits->nd_chain = 0;
- exits->nd_stts = RNODE(exits);
- p->exits = exits;
- return old;
-}
-
-static rb_node_exits_t *
-allow_block_exit(struct parser_params *p)
-{
- rb_node_exits_t *exits = p->exits;
- p->exits = 0;
- return exits;
-}
-
-static void
-restore_block_exit(struct parser_params *p, rb_node_exits_t *exits)
-{
- p->exits = exits;
-}
-
-static void
-clear_block_exit(struct parser_params *p, bool error)
-{
- rb_node_exits_t *exits = p->exits;
- if (!exits) return;
- if (error) {
- for (NODE *e = RNODE(exits); (e = RNODE_EXITS(e)->nd_chain) != 0; ) {
- switch (nd_type(e)) {
- case NODE_BREAK:
- yyerror1(&e->nd_loc, "Invalid break");
- break;
- case NODE_NEXT:
- yyerror1(&e->nd_loc, "Invalid next");
- break;
- case NODE_REDO:
- yyerror1(&e->nd_loc, "Invalid redo");
- break;
- default:
- yyerror1(&e->nd_loc, "unexpected node");
- goto end_checks; /* no nd_chain */
- }
- }
- end_checks:;
- }
- exits->nd_stts = RNODE(exits);
- exits->nd_chain = 0;
-}
-
#define WARN_EOL(tok) \
(looking_at_eol_p(p) ? \
- (void)rb_warning0("'" tok "' at the end of line without an expression") : \
+ (void)rb_warning0("`" tok "' at the end of line without an expression") : \
(void)0)
static int looking_at_eol_p(struct parser_params *p);
-
-static NODE *
-get_nd_value(struct parser_params *p, NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_GASGN:
- return RNODE_GASGN(node)->nd_value;
- case NODE_IASGN:
- return RNODE_IASGN(node)->nd_value;
- case NODE_LASGN:
- return RNODE_LASGN(node)->nd_value;
- case NODE_DASGN:
- return RNODE_DASGN(node)->nd_value;
- case NODE_MASGN:
- return RNODE_MASGN(node)->nd_value;
- case NODE_CVASGN:
- return RNODE_CVASGN(node)->nd_value;
- case NODE_CDECL:
- return RNODE_CDECL(node)->nd_value;
- default:
- compile_error(p, "get_nd_value: unexpected node: %s", parser_node_name(nd_type(node)));
- return 0;
- }
-}
-
-static void
-set_nd_value(struct parser_params *p, NODE *node, NODE *rhs)
-{
- switch (nd_type(node)) {
- case NODE_CDECL:
- RNODE_CDECL(node)->nd_value = rhs;
- break;
- case NODE_GASGN:
- RNODE_GASGN(node)->nd_value = rhs;
- break;
- case NODE_IASGN:
- RNODE_IASGN(node)->nd_value = rhs;
- break;
- case NODE_LASGN:
- RNODE_LASGN(node)->nd_value = rhs;
- break;
- case NODE_DASGN:
- RNODE_DASGN(node)->nd_value = rhs;
- break;
- case NODE_MASGN:
- RNODE_MASGN(node)->nd_value = rhs;
- break;
- case NODE_CVASGN:
- RNODE_CVASGN(node)->nd_value = rhs;
- break;
- default:
- compile_error(p, "set_nd_value: unexpected node: %s", parser_node_name(nd_type(node)));
- break;
- }
-}
-
-static ID
-get_nd_vid(struct parser_params *p, NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_CDECL:
- return RNODE_CDECL(node)->nd_vid;
- case NODE_GASGN:
- return RNODE_GASGN(node)->nd_vid;
- case NODE_IASGN:
- return RNODE_IASGN(node)->nd_vid;
- case NODE_LASGN:
- return RNODE_LASGN(node)->nd_vid;
- case NODE_DASGN:
- return RNODE_DASGN(node)->nd_vid;
- case NODE_CVASGN:
- return RNODE_CVASGN(node)->nd_vid;
- default:
- compile_error(p, "get_nd_vid: unexpected node: %s", parser_node_name(nd_type(node)));
- return 0;
- }
-}
-
-static NODE *
-get_nd_args(struct parser_params *p, NODE *node)
-{
- switch (nd_type(node)) {
- case NODE_CALL:
- return RNODE_CALL(node)->nd_args;
- case NODE_OPCALL:
- return RNODE_OPCALL(node)->nd_args;
- case NODE_FCALL:
- return RNODE_FCALL(node)->nd_args;
- case NODE_QCALL:
- return RNODE_QCALL(node)->nd_args;
- case NODE_SUPER:
- return RNODE_SUPER(node)->nd_args;
- case NODE_VCALL:
- case NODE_ZSUPER:
- case NODE_YIELD:
- case NODE_RETURN:
- case NODE_BREAK:
- case NODE_NEXT:
- return 0;
- default:
- compile_error(p, "get_nd_args: unexpected node: %s", parser_node_name(nd_type(node)));
- return 0;
- }
-}
-
-static st_index_t
-djb2(const uint8_t *str, size_t len)
-{
- st_index_t hash = 5381;
-
- for (size_t i = 0; i < len; i++) {
- hash = ((hash << 5) + hash) + str[i];
- }
-
- return hash;
-}
-
-static st_index_t
-parser_memhash(const void *ptr, long len)
-{
- return djb2(ptr, len);
-}
-
-#define PARSER_STRING_PTR(str) (str->ptr)
-#define PARSER_STRING_LEN(str) (str->len)
-#define PARSER_STRING_END(str) (&str->ptr[str->len])
-#define STRING_SIZE(str) ((size_t)str->len + 1)
-#define STRING_TERM_LEN(str) (1)
-#define STRING_TERM_FILL(str) (str->ptr[str->len] = '\0')
-#define PARSER_STRING_RESIZE_CAPA_TERM(p,str,capacity,termlen) do {\
- SIZED_REALLOC_N(str->ptr, char, (size_t)total + termlen, STRING_SIZE(str)); \
- str->len = total; \
-} while (0)
-#define STRING_SET_LEN(str, n) do { \
- (str)->len = (n); \
-} while (0)
-#define PARSER_STRING_GETMEM(str, ptrvar, lenvar) \
- ((ptrvar) = str->ptr, \
- (lenvar) = str->len)
-
-static inline int
-parser_string_char_at_end(struct parser_params *p, rb_parser_string_t *str, int when_empty)
-{
- return PARSER_STRING_LEN(str) > 0 ? (unsigned char)PARSER_STRING_END(str)[-1] : when_empty;
-}
-
-static rb_parser_string_t *
-rb_parser_string_new(rb_parser_t *p, const char *ptr, long len)
-{
- rb_parser_string_t *str;
-
- if (len < 0) {
- rb_bug("negative string size (or size too big): %ld", len);
- }
-
- str = xcalloc(1, sizeof(rb_parser_string_t));
- str->ptr = xcalloc(len + 1, sizeof(char));
-
- if (ptr) {
- memcpy(PARSER_STRING_PTR(str), ptr, len);
- }
- STRING_SET_LEN(str, len);
- STRING_TERM_FILL(str);
- return str;
-}
-
-static rb_parser_string_t *
-rb_parser_encoding_string_new(rb_parser_t *p, const char *ptr, long len, rb_encoding *enc)
-{
- rb_parser_string_t *str = rb_parser_string_new(p, ptr, len);
- str->coderange = RB_PARSER_ENC_CODERANGE_UNKNOWN;
- str->enc = enc;
- return str;
-}
-
-#ifndef RIPPER
-rb_parser_string_t *
-rb_str_to_parser_string(rb_parser_t *p, VALUE str)
-{
- /* Type check */
- rb_parser_string_t *ret = rb_parser_encoding_string_new(p, RSTRING_PTR(str), RSTRING_LEN(str), rb_enc_get(str));
- RB_GC_GUARD(str);
- return ret;
-}
-
-void
-rb_parser_string_free(rb_parser_t *p, rb_parser_string_t *str)
-{
- if (!str) return;
- xfree(PARSER_STRING_PTR(str));
- xfree(str);
-}
-#endif
-
-static st_index_t
-rb_parser_str_hash(rb_parser_string_t *str)
-{
- return parser_memhash((const void *)PARSER_STRING_PTR(str), PARSER_STRING_LEN(str));
-}
-
-static st_index_t
-rb_char_p_hash(const char *c)
-{
- return parser_memhash((const void *)c, strlen(c));
-}
-
-static size_t
-rb_parser_str_capacity(rb_parser_string_t *str, const int termlen)
-{
- return PARSER_STRING_LEN(str);
-}
-
-#ifndef RIPPER
-static char *
-rb_parser_string_end(rb_parser_string_t *str)
-{
- return &str->ptr[str->len];
-}
-#endif
-
-static void
-rb_parser_string_set_encoding(rb_parser_string_t *str, rb_encoding *enc)
-{
- str->enc = enc;
-}
-
-static rb_encoding *
-rb_parser_str_get_encoding(rb_parser_string_t *str)
-{
- return str->enc;
-}
-
-#ifndef RIPPER
-static bool
-PARSER_ENCODING_IS_ASCII8BIT(struct parser_params *p, rb_parser_string_t *str)
-{
- return rb_parser_str_get_encoding(str) == rb_ascii8bit_encoding();
-}
-#endif
-
-static int
-PARSER_ENC_CODERANGE(rb_parser_string_t *str)
-{
- return str->coderange;
-}
-
-static void
-PARSER_ENC_CODERANGE_SET(rb_parser_string_t *str, int coderange)
-{
- str->coderange = coderange;
-}
-
-static void
-PARSER_ENCODING_CODERANGE_SET(rb_parser_string_t *str, rb_encoding *enc, enum rb_parser_string_coderange_type cr)
-{
- rb_parser_string_set_encoding(str, enc);
- PARSER_ENC_CODERANGE_SET(str, cr);
-}
-
-static void
-PARSER_ENC_CODERANGE_CLEAR(rb_parser_string_t *str)
-{
- str->coderange = RB_PARSER_ENC_CODERANGE_UNKNOWN;
-}
-
-static bool
-PARSER_ENC_CODERANGE_ASCIIONLY(rb_parser_string_t *str)
-{
- return PARSER_ENC_CODERANGE(str) == RB_PARSER_ENC_CODERANGE_7BIT;
-}
-
-static bool
-PARSER_ENC_CODERANGE_CLEAN_P(int cr)
-{
- return cr == RB_PARSER_ENC_CODERANGE_7BIT || cr == RB_PARSER_ENC_CODERANGE_VALID;
-}
-
-static const char *
-rb_parser_search_nonascii(const char *p, const char *e)
-{
- const char *s = p;
-
- for (; s < e; s++) {
- if (*s & 0x80) return s;
- }
-
- return NULL;
-}
-
-static int
-rb_parser_coderange_scan(struct parser_params *p, const char *ptr, long len, rb_encoding *enc)
-{
- const char *e = ptr + len;
-
- if (enc == rb_ascii8bit_encoding()) {
- /* enc is ASCII-8BIT. ASCII-8BIT string never be broken. */
- ptr = rb_parser_search_nonascii(ptr, e);
- return ptr ? RB_PARSER_ENC_CODERANGE_VALID : RB_PARSER_ENC_CODERANGE_7BIT;
- }
-
- /* parser string encoding is always asciicompat */
- ptr = rb_parser_search_nonascii(ptr, e);
- if (!ptr) return RB_PARSER_ENC_CODERANGE_7BIT;
- for (;;) {
- int ret = rb_enc_precise_mbclen(ptr, e, enc);
- if (!MBCLEN_CHARFOUND_P(ret)) return RB_PARSER_ENC_CODERANGE_BROKEN;
- ptr += MBCLEN_CHARFOUND_LEN(ret);
- if (ptr == e) break;
- ptr = rb_parser_search_nonascii(ptr, e);
- if (!ptr) break;
- }
-
- return RB_PARSER_ENC_CODERANGE_VALID;
-}
-
-static int
-rb_parser_enc_coderange_scan(struct parser_params *p, rb_parser_string_t *str, rb_encoding *enc)
-{
- return rb_parser_coderange_scan(p, PARSER_STRING_PTR(str), PARSER_STRING_LEN(str), enc);
-}
-
-static int
-rb_parser_enc_str_coderange(struct parser_params *p, rb_parser_string_t *str)
-{
- int cr = PARSER_ENC_CODERANGE(str);
-
- if (cr == RB_PARSER_ENC_CODERANGE_UNKNOWN) {
- cr = rb_parser_enc_coderange_scan(p, str, rb_parser_str_get_encoding(str));
- PARSER_ENC_CODERANGE_SET(str, cr);
- }
-
- return cr;
-}
-
-static rb_parser_string_t *
-rb_parser_enc_associate(struct parser_params *p, rb_parser_string_t *str, rb_encoding *enc)
-{
- if (rb_parser_str_get_encoding(str) == enc)
- return str;
- if (!PARSER_ENC_CODERANGE_ASCIIONLY(str)) {
- PARSER_ENC_CODERANGE_CLEAR(str);
- }
- rb_parser_string_set_encoding(str, enc);
- return str;
-}
-
-static bool
-rb_parser_is_ascii_string(struct parser_params *p, rb_parser_string_t *str)
-{
- return rb_parser_enc_str_coderange(p, str) == RB_PARSER_ENC_CODERANGE_7BIT;
-}
-
-static rb_encoding *
-rb_parser_enc_compatible(struct parser_params *p, rb_parser_string_t *str1, rb_parser_string_t *str2)
-{
- rb_encoding *enc1 = rb_parser_str_get_encoding(str1);
- rb_encoding *enc2 = rb_parser_str_get_encoding(str2);
-
- if (enc1 == NULL || enc2 == NULL)
- return 0;
-
- if (enc1 == enc2) {
- return enc1;
- }
-
- if (PARSER_STRING_LEN(str2) == 0)
- return enc1;
- if (PARSER_STRING_LEN(str1) == 0)
- return rb_parser_is_ascii_string(p, str2) ? enc1 : enc2;
-
- int cr1, cr2;
-
- cr1 = rb_parser_enc_str_coderange(p, str1);
- cr2 = rb_parser_enc_str_coderange(p, str2);
-
- if (cr1 != cr2) {
- if (cr1 == RB_PARSER_ENC_CODERANGE_7BIT) return enc2;
- if (cr2 == RB_PARSER_ENC_CODERANGE_7BIT) return enc1;
- }
-
- if (cr2 == RB_PARSER_ENC_CODERANGE_7BIT) {
- return enc1;
- }
-
- if (cr1 == RB_PARSER_ENC_CODERANGE_7BIT) {
- return enc2;
- }
-
- return 0;
-}
-
-static void
-rb_parser_str_modify(rb_parser_string_t *str)
-{
- PARSER_ENC_CODERANGE_CLEAR(str);
-}
-
-static void
-rb_parser_str_set_len(struct parser_params *p, rb_parser_string_t *str, long len)
-{
- long capa;
- const int termlen = STRING_TERM_LEN(str);
-
- if (len > (capa = (long)(rb_parser_str_capacity(str, termlen))) || len < 0) {
- rb_bug("probable buffer overflow: %ld for %ld", len, capa);
- }
-
- int cr = PARSER_ENC_CODERANGE(str);
- if (cr == RB_PARSER_ENC_CODERANGE_UNKNOWN) {
- /* Leave unknown. */
- }
- else if (len > PARSER_STRING_LEN(str)) {
- PARSER_ENC_CODERANGE_SET(str, RB_PARSER_ENC_CODERANGE_UNKNOWN);
- }
- else if (len < PARSER_STRING_LEN(str)) {
- if (cr != RB_PARSER_ENC_CODERANGE_7BIT) {
- /* ASCII-only string is keeping after truncated. Valid
- * and broken may be invalid or valid, leave unknown. */
- PARSER_ENC_CODERANGE_SET(str, RB_PARSER_ENC_CODERANGE_UNKNOWN);
- }
- }
-
- STRING_SET_LEN(str, len);
- STRING_TERM_FILL(str);
-}
-
-static rb_parser_string_t *
-rb_parser_str_buf_cat(struct parser_params *p, rb_parser_string_t *str, const char *ptr, long len)
-{
- rb_parser_str_modify(str);
- if (len == 0) return 0;
-
- long total, olen, off = -1;
- char *sptr;
- const int termlen = STRING_TERM_LEN(str);
-
- PARSER_STRING_GETMEM(str, sptr, olen);
- if (ptr >= sptr && ptr <= sptr + olen) {
- off = ptr - sptr;
- }
-
- if (olen > LONG_MAX - len) {
- compile_error(p, "string sizes too big");
- return 0;
- }
- total = olen + len;
- PARSER_STRING_RESIZE_CAPA_TERM(p, str, total, termlen);
- sptr = PARSER_STRING_PTR(str);
- if (off != -1) {
- ptr = sptr + off;
- }
- memcpy(sptr + olen, ptr, len);
- STRING_SET_LEN(str, total);
- STRING_TERM_FILL(str);
-
- return str;
-}
-
-#define parser_str_cat(str, ptr, len) rb_parser_str_buf_cat(p, str, ptr, len)
-#define parser_str_cat_cstr(str, lit) rb_parser_str_buf_cat(p, str, lit, strlen(lit))
-
-static rb_parser_string_t *
-rb_parser_enc_cr_str_buf_cat(struct parser_params *p, rb_parser_string_t *str, const char *ptr, long len,
- rb_encoding *ptr_enc, int ptr_cr, int *ptr_cr_ret)
-{
- int str_cr, res_cr;
- rb_encoding *str_enc, *res_enc;
-
- str_enc = rb_parser_str_get_encoding(str);
- str_cr = PARSER_STRING_LEN(str) ? PARSER_ENC_CODERANGE(str) : RB_PARSER_ENC_CODERANGE_7BIT;
-
- if (str_enc == ptr_enc) {
- if (str_cr != RB_PARSER_ENC_CODERANGE_UNKNOWN && ptr_cr == RB_PARSER_ENC_CODERANGE_UNKNOWN) {
- ptr_cr = rb_parser_coderange_scan(p, ptr, len, ptr_enc);
- }
- }
- else {
- /* parser string encoding is always asciicompat */
- if (ptr_cr == RB_PARSER_ENC_CODERANGE_UNKNOWN) {
- ptr_cr = rb_parser_coderange_scan(p, ptr, len, ptr_enc);
- }
- if (str_cr == RB_PARSER_ENC_CODERANGE_UNKNOWN) {
- if (str_enc == rb_ascii8bit_encoding() || ptr_cr != RB_PARSER_ENC_CODERANGE_7BIT) {
- str_cr = rb_parser_enc_str_coderange(p, str);
- }
- }
- }
- if (ptr_cr_ret)
- *ptr_cr_ret = ptr_cr;
-
- if (str_enc != ptr_enc &&
- str_cr != RB_PARSER_ENC_CODERANGE_7BIT &&
- ptr_cr != RB_PARSER_ENC_CODERANGE_7BIT) {
- goto incompatible;
- }
-
- if (str_cr == RB_PARSER_ENC_CODERANGE_UNKNOWN) {
- res_enc = str_enc;
- res_cr = RB_PARSER_ENC_CODERANGE_UNKNOWN;
- }
- else if (str_cr == RB_PARSER_ENC_CODERANGE_7BIT) {
- if (ptr_cr == RB_PARSER_ENC_CODERANGE_7BIT) {
- res_enc = str_enc;
- res_cr = RB_PARSER_ENC_CODERANGE_7BIT;
- }
- else {
- res_enc = ptr_enc;
- res_cr = ptr_cr;
- }
- }
- else if (str_cr == RB_PARSER_ENC_CODERANGE_VALID) {
- res_enc = str_enc;
- if (PARSER_ENC_CODERANGE_CLEAN_P(ptr_cr))
- res_cr = str_cr;
- else
- res_cr = ptr_cr;
- }
- else { /* str_cr == RB_PARSER_ENC_CODERANGE_BROKEN */
- res_enc = str_enc;
- res_cr = str_cr;
- if (0 < len) res_cr = RB_PARSER_ENC_CODERANGE_UNKNOWN;
- }
-
- if (len < 0) {
- compile_error(p, "negative string size (or size too big)");
- }
- parser_str_cat(str, ptr, len);
- PARSER_ENCODING_CODERANGE_SET(str, res_enc, res_cr);
- return str;
-
- incompatible:
- compile_error(p, "incompatible character encodings: %s and %s",
- rb_enc_name(str_enc), rb_enc_name(ptr_enc));
- UNREACHABLE_RETURN(0);
-
-}
-
-static rb_parser_string_t *
-rb_parser_enc_str_buf_cat(struct parser_params *p, rb_parser_string_t *str, const char *ptr, long len,
- rb_encoding *ptr_enc)
-{
- return rb_parser_enc_cr_str_buf_cat(p, str, ptr, len, ptr_enc, RB_PARSER_ENC_CODERANGE_UNKNOWN, NULL);
-}
-
-static rb_parser_string_t *
-rb_parser_str_buf_append(struct parser_params *p, rb_parser_string_t *str, rb_parser_string_t *str2)
-{
- int str2_cr = rb_parser_enc_str_coderange(p, str2);
-
- rb_parser_enc_cr_str_buf_cat(p, str, PARSER_STRING_PTR(str2), PARSER_STRING_LEN(str2),
- rb_parser_str_get_encoding(str2), str2_cr, &str2_cr);
-
- PARSER_ENC_CODERANGE_SET(str2, str2_cr);
-
- return str;
-}
-
-static rb_parser_string_t *
-rb_parser_str_resize(struct parser_params *p, rb_parser_string_t *str, long len)
-{
- if (len < 0) {
- rb_bug("negative string size (or size too big)");
- }
-
- long slen = PARSER_STRING_LEN(str);
-
- if (slen > len && PARSER_ENC_CODERANGE(str) != RB_PARSER_ENC_CODERANGE_7BIT) {
- PARSER_ENC_CODERANGE_CLEAR(str);
- }
-
- {
- long capa;
- const int termlen = STRING_TERM_LEN(str);
-
- if ((capa = slen) < len) {
- SIZED_REALLOC_N(str->ptr, char, (size_t)len + termlen, STRING_SIZE(str));
- }
- else if (len == slen) return str;
- STRING_SET_LEN(str, len);
- STRING_TERM_FILL(str);
- }
- return str;
-}
-
-# define PARSER_ENC_STRING_GETMEM(str, ptrvar, lenvar, encvar) \
- ((ptrvar) = str->ptr, \
- (lenvar) = str->len, \
- (encvar) = str->enc)
-
-static int
-rb_parser_string_hash_cmp(rb_parser_string_t *str1, rb_parser_string_t *str2)
-{
- long len1, len2;
- const char *ptr1, *ptr2;
- rb_encoding *enc1, *enc2;
-
- PARSER_ENC_STRING_GETMEM(str1, ptr1, len1, enc1);
- PARSER_ENC_STRING_GETMEM(str2, ptr2, len2, enc2);
-
- return (len1 != len2 ||
- enc1 != enc2 ||
- memcmp(ptr1, ptr2, len1) != 0);
-}
-
-static void
-rb_parser_ary_extend(rb_parser_t *p, rb_parser_ary_t *ary, long len)
-{
- long i;
- if (ary->capa < len) {
- ary->capa = len;
- ary->data = (rb_parser_ary_data *)xrealloc(ary->data, sizeof(rb_parser_ary_data) * len);
- for (i = ary->len; i < len; i++) {
- ary->data[i] = 0;
- }
- }
-}
-
-/*
- * Do not call this directly.
- * Use rb_parser_ary_new_capa_for_XXX() instead.
- */
-static rb_parser_ary_t *
-parser_ary_new_capa(rb_parser_t *p, long len)
-{
- if (len < 0) {
- rb_bug("negative array size (or size too big): %ld", len);
- }
- rb_parser_ary_t *ary = xcalloc(1, sizeof(rb_parser_ary_t));
- ary->data_type = 0;
- ary->len = 0;
- ary->capa = len;
- if (0 < len) {
- ary->data = (rb_parser_ary_data *)xcalloc(len, sizeof(rb_parser_ary_data));
- }
- else {
- ary->data = NULL;
- }
- return ary;
-}
-
-#ifndef RIPPER
-static rb_parser_ary_t *
-rb_parser_ary_new_capa_for_script_line(rb_parser_t *p, long len)
-{
- rb_parser_ary_t *ary = parser_ary_new_capa(p, len);
- ary->data_type = PARSER_ARY_DATA_SCRIPT_LINE;
- return ary;
-}
-
-static rb_parser_ary_t *
-rb_parser_ary_new_capa_for_ast_token(rb_parser_t *p, long len)
-{
- rb_parser_ary_t *ary = parser_ary_new_capa(p, len);
- ary->data_type = PARSER_ARY_DATA_AST_TOKEN;
- return ary;
-}
-#endif
-
-static rb_parser_ary_t *
-rb_parser_ary_new_capa_for_node(rb_parser_t *p, long len)
-{
- rb_parser_ary_t *ary = parser_ary_new_capa(p, len);
- ary->data_type = PARSER_ARY_DATA_NODE;
- return ary;
-}
-
-/*
- * Do not call this directly.
- * Use rb_parser_ary_push_XXX() instead.
- */
-static rb_parser_ary_t *
-parser_ary_push(rb_parser_t *p, rb_parser_ary_t *ary, rb_parser_ary_data val)
-{
- if (ary->len == ary->capa) {
- rb_parser_ary_extend(p, ary, ary->len == 0 ? 1 : ary->len * 2);
- }
- ary->data[ary->len++] = val;
- return ary;
-}
-
-#ifndef RIPPER
-static rb_parser_ary_t *
-rb_parser_ary_push_ast_token(rb_parser_t *p, rb_parser_ary_t *ary, rb_parser_ast_token_t *val)
-{
- if (ary->data_type != PARSER_ARY_DATA_AST_TOKEN) {
- rb_bug("unexpected rb_parser_ary_data_type: %d", ary->data_type);
- }
- return parser_ary_push(p, ary, val);
-}
-
-static rb_parser_ary_t *
-rb_parser_ary_push_script_line(rb_parser_t *p, rb_parser_ary_t *ary, rb_parser_string_t *val)
-{
- if (ary->data_type != PARSER_ARY_DATA_SCRIPT_LINE) {
- rb_bug("unexpected rb_parser_ary_data_type: %d", ary->data_type);
- }
- return parser_ary_push(p, ary, val);
-}
-#endif
-
-static rb_parser_ary_t *
-rb_parser_ary_push_node(rb_parser_t *p, rb_parser_ary_t *ary, NODE *val)
-{
- if (ary->data_type != PARSER_ARY_DATA_NODE) {
- rb_bug("unexpected rb_parser_ary_data_type: %d", ary->data_type);
- }
- return parser_ary_push(p, ary, val);
-}
-
-#ifndef RIPPER
-static void
-rb_parser_ast_token_free(rb_parser_t *p, rb_parser_ast_token_t *token)
-{
- if (!token) return;
- rb_parser_string_free(p, token->str);
- xfree(token);
-}
-
-static void
-rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
-{
-# define foreach_ary(ptr) \
- for (rb_parser_ary_data *ptr = ary->data, *const end_ary_data = ptr + ary->len; \
- ptr < end_ary_data; ptr++)
- switch (ary->data_type) {
- case PARSER_ARY_DATA_AST_TOKEN:
- foreach_ary(data) {rb_parser_ast_token_free(p, *data);}
- break;
- case PARSER_ARY_DATA_SCRIPT_LINE:
- foreach_ary(data) {rb_parser_string_free(p, *data);}
- break;
- case PARSER_ARY_DATA_NODE:
- /* Do nothing because nodes are freed when rb_ast_t is freed */
- break;
- default:
- rb_bug("unexpected rb_parser_ary_data_type: %d", ary->data_type);
- break;
- }
-# undef foreach_ary
- xfree(ary->data);
- xfree(ary);
-}
-
-#endif /* !RIPPER */
%}
%expect 0
%define api.pure
%define parse.error verbose
%printer {
- if ((NODE *)$$ == (NODE *)-1) {
- rb_parser_printf(p, "NODE_SPECIAL");
- }
- else if ($$) {
- rb_parser_printf(p, "%s", parser_node_name(nd_type(RNODE($$))));
+#ifndef RIPPER
+ if ($$) {
+ rb_parser_printf(p, "%s", ruby_node_name(nd_type($$)));
}
-} <node> <node_fcall> <node_args> <node_args_aux> <node_opt_arg>
- <node_kw_arg> <node_block_pass> <node_masgn> <node_def_temp> <node_exits>
+#else
+#endif
+} <node>
%printer {
+#ifndef RIPPER
rb_parser_printf(p, "%"PRIsVALUE, rb_id2str($$));
-} <id>
+#else
+ rb_parser_printf(p, "%"PRIsVALUE, RNODE($$)->nd_rval);
+#endif
+} tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL tOP_ASGN
%printer {
- switch (nd_type(RNODE($$))) {
- case NODE_INTEGER:
- rb_parser_printf(p, "%+"PRIsVALUE, rb_node_integer_literal_val($$));
- break;
- case NODE_FLOAT:
- rb_parser_printf(p, "%+"PRIsVALUE, rb_node_float_literal_val($$));
- break;
- case NODE_RATIONAL:
- rb_parser_printf(p, "%+"PRIsVALUE, rb_node_rational_literal_val($$));
- break;
- case NODE_IMAGINARY:
- rb_parser_printf(p, "%+"PRIsVALUE, rb_node_imaginary_literal_val($$));
- break;
- default:
- break;
- }
+#ifndef RIPPER
+ rb_parser_printf(p, "%+"PRIsVALUE, $$->nd_lit);
+#else
+ rb_parser_printf(p, "%+"PRIsVALUE, get_value($$));
+#endif
} tINTEGER tFLOAT tRATIONAL tIMAGINARY tSTRING_CONTENT tCHAR
%printer {
- rb_parser_printf(p, "$%ld", RNODE_NTH_REF($$)->nd_nth);
+#ifndef RIPPER
+ rb_parser_printf(p, "$%ld", $$->nd_nth);
+#else
+ rb_parser_printf(p, "%"PRIsVALUE, $$);
+#endif
} tNTH_REF
%printer {
- rb_parser_printf(p, "$%c", (int)RNODE_BACK_REF($$)->nd_nth);
+#ifndef RIPPER
+ rb_parser_printf(p, "$%c", (int)$$->nd_nth);
+#else
+ rb_parser_printf(p, "%"PRIsVALUE, $$);
+#endif
} tBACK_REF
-%destructor {
- if (CASE_LABELS_ENABLED_P($$)) st_free_table($$);
-} <labels>
-
%lex-param {struct parser_params *p}
%parse-param {struct parser_params *p}
%initial-action
{
RUBY_SET_YYLLOC_OF_NONE(@$);
};
-%after-shift after_shift
-%before-reduce before_reduce
-%after-reduce after_reduce
-%after-shift-error-token after_shift_error_token
-%after-pop-stack after_pop_stack
%union {
+ VALUE val;
NODE *node;
- rb_node_fcall_t *node_fcall;
- rb_node_args_t *node_args;
- rb_node_args_aux_t *node_args_aux;
- rb_node_opt_arg_t *node_opt_arg;
- rb_node_kw_arg_t *node_kw_arg;
- rb_node_block_pass_t *node_block_pass;
- rb_node_masgn_t *node_masgn;
- rb_node_def_temp_t *node_def_temp;
- rb_node_exits_t *node_exits;
ID id;
int num;
st_table *tbl;
- st_table *labels;
const struct vtable *vars;
struct rb_strterm_struct *strterm;
struct lex_context ctxt;
- enum lex_state_e state;
}
%token <id>
- keyword_class "'class'"
- keyword_module "'module'"
- keyword_def "'def'"
- keyword_undef "'undef'"
- keyword_begin "'begin'"
- keyword_rescue "'rescue'"
- keyword_ensure "'ensure'"
- keyword_end "'end'"
- keyword_if "'if'"
- keyword_unless "'unless'"
- keyword_then "'then'"
- keyword_elsif "'elsif'"
- keyword_else "'else'"
- keyword_case "'case'"
- keyword_when "'when'"
- keyword_while "'while'"
- keyword_until "'until'"
- keyword_for "'for'"
- keyword_break "'break'"
- keyword_next "'next'"
- keyword_redo "'redo'"
- keyword_retry "'retry'"
- keyword_in "'in'"
- keyword_do "'do'"
- keyword_do_cond "'do' for condition"
- keyword_do_block "'do' for block"
- keyword_do_LAMBDA "'do' for lambda"
- keyword_return "'return'"
- keyword_yield "'yield'"
- keyword_super "'super'"
- keyword_self "'self'"
- keyword_nil "'nil'"
- keyword_true "'true'"
- keyword_false "'false'"
- keyword_and "'and'"
- keyword_or "'or'"
- keyword_not "'not'"
- modifier_if "'if' modifier"
- modifier_unless "'unless' modifier"
- modifier_while "'while' modifier"
- modifier_until "'until' modifier"
- modifier_rescue "'rescue' modifier"
- keyword_alias "'alias'"
- keyword_defined "'defined?'"
- keyword_BEGIN "'BEGIN'"
- keyword_END "'END'"
- keyword__LINE__ "'__LINE__'"
- keyword__FILE__ "'__FILE__'"
- keyword__ENCODING__ "'__ENCODING__'"
+ keyword_class "`class'"
+ keyword_module "`module'"
+ keyword_def "`def'"
+ keyword_undef "`undef'"
+ keyword_begin "`begin'"
+ keyword_rescue "`rescue'"
+ keyword_ensure "`ensure'"
+ keyword_end "`end'"
+ keyword_if "`if'"
+ keyword_unless "`unless'"
+ keyword_then "`then'"
+ keyword_elsif "`elsif'"
+ keyword_else "`else'"
+ keyword_case "`case'"
+ keyword_when "`when'"
+ keyword_while "`while'"
+ keyword_until "`until'"
+ keyword_for "`for'"
+ keyword_break "`break'"
+ keyword_next "`next'"
+ keyword_redo "`redo'"
+ keyword_retry "`retry'"
+ keyword_in "`in'"
+ keyword_do "`do'"
+ keyword_do_cond "`do' for condition"
+ keyword_do_block "`do' for block"
+ keyword_do_LAMBDA "`do' for lambda"
+ keyword_return "`return'"
+ keyword_yield "`yield'"
+ keyword_super "`super'"
+ keyword_self "`self'"
+ keyword_nil "`nil'"
+ keyword_true "`true'"
+ keyword_false "`false'"
+ keyword_and "`and'"
+ keyword_or "`or'"
+ keyword_not "`not'"
+ modifier_if "`if' modifier"
+ modifier_unless "`unless' modifier"
+ modifier_while "`while' modifier"
+ modifier_until "`until' modifier"
+ modifier_rescue "`rescue' modifier"
+ keyword_alias "`alias'"
+ keyword_defined "`defined?'"
+ keyword_BEGIN "`BEGIN'"
+ keyword_END "`END'"
+ keyword__LINE__ "`__LINE__'"
+ keyword__FILE__ "`__FILE__'"
+ keyword__ENCODING__ "`__ENCODING__'"
%token <id> tIDENTIFIER "local variable or method"
%token <id> tFID "method"
@@ -2758,54 +1463,39 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%type <node> singleton strings string string1 xstring regexp
%type <node> string_contents xstring_contents regexp_contents string_content
%type <node> words symbols symbol_list qwords qsymbols word_list qword_list qsym_list word
-%type <node> literal numeric simple_numeric ssym dsym symbol cpath
-%type <node_def_temp> defn_head defs_head k_def
-%type <node_exits> block_open k_while k_until k_for allow_exits
-%type <node> top_compstmt top_stmts top_stmt begin_block endless_arg endless_command
+%type <node> literal numeric simple_numeric ssym dsym symbol cpath def_name defn_head defs_head
+%type <node> top_compstmt top_stmts top_stmt begin_block
%type <node> bodystmt compstmt stmts stmt_or_begin stmt expr arg primary command command_call method_call
-%type <node> expr_value expr_value_do arg_value primary_value rel_expr
-%type <node_fcall> fcall
+%type <node> expr_value expr_value_do arg_value primary_value fcall rel_expr
%type <node> if_tail opt_else case_body case_args cases opt_rescue exc_list exc_var opt_ensure
-%type <node> args arg_splat call_args opt_call_args
-%type <node> paren_args opt_paren_args
-%type <node_args> args_tail block_args_tail
-%type <node> command_args aref_args
-%type <node_block_pass> opt_block_arg block_arg
-%type <node> var_ref var_lhs
+%type <node> args call_args opt_call_args
+%type <node> paren_args opt_paren_args args_tail opt_args_tail block_args_tail opt_block_args_tail
+%type <node> command_args aref_args opt_block_arg block_arg var_ref var_lhs
%type <node> command_rhs arg_rhs
%type <node> command_asgn mrhs mrhs_arg superclass block_call block_command
-%type <node_args> f_arglist f_opt_paren_args f_paren_args f_args
-%type <node_args_aux> f_arg f_arg_item
-%type <node> f_marg f_marg_list f_rest_marg
-%type <node_masgn> f_margs
+%type <node> f_block_optarg f_block_opt
+%type <node> f_arglist f_opt_paren_args f_paren_args f_args f_arg f_arg_item
+%type <node> f_optarg f_marg f_marg_list f_margs f_rest_marg
%type <node> assoc_list assocs assoc undef_list backref string_dvar for_var
-%type <node_args> block_param opt_block_param block_param_def
-%type <node_kw_arg> f_kw f_block_kw
-%type <id> bv_decls opt_bv_decl bvar
-%type <node> lambda lambda_body brace_body do_body
-%type <node_args> f_larglist
+%type <node> block_param opt_block_param block_param_def f_opt
+%type <node> f_kwarg f_kw f_block_kwarg f_block_kw
+%type <node> bv_decls opt_bv_decl bvar
+%type <node> lambda f_larglist lambda_body brace_body do_body
%type <node> brace_block cmd_brace_block do_block lhs none fitem
-%type <node> mlhs_head mlhs_item mlhs_node mlhs_post
-%type <node_masgn> mlhs mlhs_basic mlhs_inner
+%type <node> mlhs mlhs_head mlhs_basic mlhs_item mlhs_node mlhs_post mlhs_inner
%type <node> p_case_body p_cases p_top_expr p_top_expr_body
%type <node> p_expr p_as p_alt p_expr_basic p_find
-%type <node> p_args p_args_head p_args_tail p_args_post p_arg p_rest
+%type <node> p_args p_args_head p_args_tail p_args_post p_arg
%type <node> p_value p_primitive p_variable p_var_ref p_expr_ref p_const
%type <node> p_kwargs p_kwarg p_kw
%type <id> keyword_variable user_variable sym operation operation2 operation3
%type <id> cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_bad_arg
%type <id> f_kwrest f_label f_arg_asgn call_op call_op2 reswords relop dot_or_colon
-%type <id> p_kwrest p_kwnorest p_any_kwrest p_kw_label
-%type <id> f_no_kwarg f_any_kwrest args_forward excessed_comma nonlocal_var def_name
-%type <ctxt> lex_ctxt begin_defined k_class k_module k_END k_rescue k_ensure after_rescue
-%type <ctxt> p_in_kwarg
-%type <tbl> p_lparen p_lbracket p_pktbl p_pvtbl
-%type <num> max_numparam
-%type <node> numparam
-%type <id> it_id
+%type <id> p_rest p_kwrest p_kwnorest p_any_kwrest p_kw_label
+%type <id> f_no_kwarg f_any_kwrest args_forward excessed_comma nonlocal_var
+ %type <ctxt> lex_ctxt /* keep <ctxt> in ripper */
%token END_OF_INPUT 0 "end-of-input"
%token <id> '.'
-
/* escaped chars, should be ignored otherwise */
%token <id> '\\' "backslash"
%token tSP "escaped space"
@@ -2848,7 +1538,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%token tSTAR "*"
%token tDSTAR "**arg"
%token tAMPER "&"
-%token <num> tLAMBDA "->"
+%token tLAMBDA "->"
%token tSYMBEG "symbol literal"
%token tSTRING_BEG "string literal"
%token tXSTRING_BEG "backtick literal"
@@ -2859,8 +1549,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%token tQSYMBOLS_BEG "verbatim symbol list"
%token tSTRING_END "terminator"
%token tSTRING_DEND "'}'"
-%token <state> tSTRING_DBEG "'#{'"
-%token tSTRING_DVAR tLAMBEG tLABEL_END
+%token tSTRING_DBEG tSTRING_DVAR tLAMBEG tLABEL_END
%token tIGNORED_NL tCOMMENT tEMBDOC_BEG tEMBDOC tEMBDOC_END
%token tHEREDOC_BEG tHEREDOC_END k__END__
@@ -2895,3051 +1584,3381 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%token tLAST_TOKEN
-/*
- * inlining rules
- */
-%rule %inline ident_or_const
- : tIDENTIFIER
- | tCONSTANT
- ;
-
-%rule %inline user_or_keyword_variable
- : user_variable
- | keyword_variable
- ;
-
-/*
- * parameterizing rules
- */
-%rule f_opt(value) <node_opt_arg>
- : f_arg_asgn f_eq value
- {
- p->ctxt.in_argdef = 1;
- $$ = NEW_OPT_ARG(assignable(p, $1, $3, &@$), &@$);
- /*% ripper: [$:$, $:3] %*/
- }
- ;
-
-%rule f_optarg(value) <node_opt_arg>
- : f_opt(value)
- {
- $$ = $1;
- /*% ripper: rb_ary_new3(1, $:1) %*/
- }
- | f_optarg(value) ',' f_opt(value)
- {
- $$ = opt_arg_append($1, $3);
- /*% ripper: rb_ary_push($:1, $:3) %*/
- }
- ;
-
-%rule f_kwarg(kw) <node_kw_arg>
- : kw
- {
- $$ = $1;
- /*% ripper: rb_ary_new3(1, $:1) %*/
- }
- | f_kwarg(kw) ',' kw
- {
- $$ = kwd_append($1, $3);
- /*% ripper: rb_ary_push($:1, $:3) %*/
- }
- ;
-
-%rule opt_args_tail(tail) <node_args>
- : ',' tail
- {
- $$ = $2;
- /*% ripper: $:2 %*/
- }
- | /* none */
- {
- $$ = new_args_tail(p, 0, 0, 0, &@0);
- /*% ripper: [Qnil, Qnil, Qnil] %*/
- }
- ;
-
-%rule words(begin, word_list)
- : begin ' '+ word_list tSTRING_END
- {
- $$ = make_list($3, &@$);
- /*% ripper: array!($:3) %*/
- }
- ;
-
%%
program : {
- SET_LEX_STATE(EXPR_BEG);
- local_push(p, ifndef_ripper(1)+0);
- /* jumps are possible in the top-level loop. */
- if (!ifndef_ripper(p->do_loop) + 0) init_block_exit(p);
- }
- top_compstmt
- {
- if ($2 && !compile_for_eval) {
- NODE *node = $2;
- /* last expression should not be void */
- if (nd_type_p(node, NODE_BLOCK)) {
- while (RNODE_BLOCK(node)->nd_next) {
- node = RNODE_BLOCK(node)->nd_next;
- }
- node = RNODE_BLOCK(node)->nd_head;
- }
- node = remove_begin(node);
- void_expr(p, node);
- }
- p->eval_tree = NEW_SCOPE(0, block_append(p, p->eval_tree, $2), &@$);
- /*% ripper[final]: program!($:2) %*/
- local_pop(p);
- }
- ;
-
-top_compstmt : top_stmts terms?
- {
- void_stmts(p, $$ = $1);
- }
- ;
+ SET_LEX_STATE(EXPR_BEG);
+ local_push(p, ifndef_ripper(1)+0);
+ }
+ top_compstmt
+ {
+ /*%%%*/
+ if ($2 && !compile_for_eval) {
+ NODE *node = $2;
+ /* last expression should not be void */
+ if (nd_type_p(node, NODE_BLOCK)) {
+ while (node->nd_next) {
+ node = node->nd_next;
+ }
+ node = node->nd_head;
+ }
+ node = remove_begin(node);
+ void_expr(p, node);
+ }
+ p->eval_tree = NEW_SCOPE(0, block_append(p, p->eval_tree, $2), &@$);
+ /*% %*/
+ /*% ripper[final]: program!($2) %*/
+ local_pop(p);
+ }
+ ;
+
+top_compstmt : top_stmts opt_terms
+ {
+ $$ = void_stmts(p, $1);
+ }
+ ;
top_stmts : none
{
- $$ = NEW_BEGIN(0, &@$);
- /*% ripper: stmts_add!(stmts_new!, void_stmt!) %*/
- }
- | top_stmt
- {
- $$ = newline_node($1);
- /*% ripper: stmts_add!(stmts_new!, $:1) %*/
- }
- | top_stmts terms top_stmt
- {
- $$ = block_append(p, $1, newline_node($3));
- /*% ripper: stmts_add!($:1, $:3) %*/
- }
- ;
+ /*%%%*/
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: stmts_add!(stmts_new!, void_stmt!) %*/
+ }
+ | top_stmt
+ {
+ /*%%%*/
+ $$ = newline_node($1);
+ /*% %*/
+ /*% ripper: stmts_add!(stmts_new!, $1) %*/
+ }
+ | top_stmts terms top_stmt
+ {
+ /*%%%*/
+ $$ = block_append(p, $1, newline_node($3));
+ /*% %*/
+ /*% ripper: stmts_add!($1, $3) %*/
+ }
+ ;
top_stmt : stmt
- {
- clear_block_exit(p, true);
- $$ = $1;
- }
- | keyword_BEGIN begin_block
- {
- $$ = $2;
- /*% ripper: $:2 %*/
- }
- ;
-
-block_open : '{' {$$ = init_block_exit(p);};
-
-begin_block : block_open top_compstmt '}'
- {
- restore_block_exit(p, $block_open);
- p->eval_tree_begin = block_append(p, p->eval_tree_begin,
- NEW_BEGIN($2, &@$));
- $$ = NEW_BEGIN(0, &@$);
- /*% ripper: BEGIN!($:2) %*/
- }
- ;
-
-bodystmt : compstmt[body]
- lex_ctxt[ctxt]
- opt_rescue
- k_else
- {
- if (!$opt_rescue) yyerror1(&@k_else, "else without rescue is useless");
- next_rescue_context(&p->ctxt, &$ctxt, after_else);
- }
- compstmt[elsebody]
- {
- next_rescue_context(&p->ctxt, &$ctxt, after_ensure);
- }
- opt_ensure
- {
- $$ = new_bodystmt(p, $body, $opt_rescue, $elsebody, $opt_ensure, &@$);
- /*% ripper: bodystmt!($:body, $:opt_rescue, $:elsebody, $:opt_ensure) %*/
- }
- | compstmt[body]
- lex_ctxt[ctxt]
- opt_rescue
- {
- next_rescue_context(&p->ctxt, &$ctxt, after_ensure);
- }
- opt_ensure
- {
- $$ = new_bodystmt(p, $body, $opt_rescue, 0, $opt_ensure, &@$);
- /*% ripper: bodystmt!($:body, $:opt_rescue, Qnil, $:opt_ensure) %*/
- }
- ;
-
-compstmt : stmts terms?
- {
- void_stmts(p, $$ = $1);
- }
- ;
+ | keyword_BEGIN begin_block
+ {
+ $$ = $2;
+ }
+ ;
+
+begin_block : '{' top_compstmt '}'
+ {
+ /*%%%*/
+ p->eval_tree_begin = block_append(p, p->eval_tree_begin,
+ NEW_BEGIN($2, &@$));
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: BEGIN!($2) %*/
+ }
+ ;
+
+bodystmt : compstmt
+ opt_rescue
+ k_else {if (!$2) {yyerror1(&@3, "else without rescue is useless");}}
+ compstmt
+ opt_ensure
+ {
+ /*%%%*/
+ $$ = new_bodystmt(p, $1, $2, $5, $6, &@$);
+ /*% %*/
+ /*% ripper: bodystmt!(escape_Qundef($1), escape_Qundef($2), escape_Qundef($5), escape_Qundef($6)) %*/
+ }
+ | compstmt
+ opt_rescue
+ opt_ensure
+ {
+ /*%%%*/
+ $$ = new_bodystmt(p, $1, $2, 0, $3, &@$);
+ /*% %*/
+ /*% ripper: bodystmt!(escape_Qundef($1), escape_Qundef($2), Qnil, escape_Qundef($3)) %*/
+ }
+ ;
+
+compstmt : stmts opt_terms
+ {
+ $$ = void_stmts(p, $1);
+ }
+ ;
stmts : none
{
- $$ = NEW_BEGIN(0, &@$);
- /*% ripper: stmts_add!(stmts_new!, void_stmt!) %*/
- }
- | stmt_or_begin
- {
- $$ = newline_node($1);
- /*% ripper: stmts_add!(stmts_new!, $:1) %*/
- }
- | stmts terms stmt_or_begin
- {
- $$ = block_append(p, $1, newline_node($3));
- /*% ripper: stmts_add!($:1, $:3) %*/
- }
- ;
+ /*%%%*/
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: stmts_add!(stmts_new!, void_stmt!) %*/
+ }
+ | stmt_or_begin
+ {
+ /*%%%*/
+ $$ = newline_node($1);
+ /*% %*/
+ /*% ripper: stmts_add!(stmts_new!, $1) %*/
+ }
+ | stmts terms stmt_or_begin
+ {
+ /*%%%*/
+ $$ = block_append(p, $1, newline_node($3));
+ /*% %*/
+ /*% ripper: stmts_add!($1, $3) %*/
+ }
+ ;
stmt_or_begin : stmt
{
- $$ = $1;
- }
+ $$ = $1;
+ }
| keyword_BEGIN
- {
- yyerror1(&@1, "BEGIN is permitted only at toplevel");
- }
- begin_block
- {
- $$ = $3;
- }
- ;
-
-allow_exits : {$$ = allow_block_exit(p);};
-
-k_END : keyword_END lex_ctxt
- {
- $$ = $2;
- p->ctxt.in_rescue = before_rescue;
- /*% ripper: $:2 %*/
- };
+ {
+ yyerror1(&@1, "BEGIN is permitted only at toplevel");
+ }
+ begin_block
+ {
+ $$ = $3;
+ }
+ ;
stmt : keyword_alias fitem {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem
+ {
+ /*%%%*/
+ $$ = NEW_ALIAS($2, $4, &@$);
+ /*% %*/
+ /*% ripper: alias!($2, $4) %*/
+ }
+ | keyword_alias tGVAR tGVAR
+ {
+ /*%%%*/
+ $$ = NEW_VALIAS($2, $3, &@$);
+ /*% %*/
+ /*% ripper: var_alias!($2, $3) %*/
+ }
+ | keyword_alias tGVAR tBACK_REF
+ {
+ /*%%%*/
+ char buf[2];
+ buf[0] = '$';
+ buf[1] = (char)$3->nd_nth;
+ $$ = NEW_VALIAS($2, rb_intern2(buf, 2), &@$);
+ /*% %*/
+ /*% ripper: var_alias!($2, $3) %*/
+ }
+ | keyword_alias tGVAR tNTH_REF
+ {
+ static const char mesg[] = "can't make alias for the number variables";
+ /*%%%*/
+ yyerror1(&@3, mesg);
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper[error]: alias_error!(ERR_MESG(), $3) %*/
+ }
+ | keyword_undef undef_list
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: undef!($2) %*/
+ }
+ | stmt modifier_if expr_value
+ {
+ /*%%%*/
+ $$ = new_if(p, $3, remove_begin($1), 0, &@$);
+ fixpos($$, $3);
+ /*% %*/
+ /*% ripper: if_mod!($3, $1) %*/
+ }
+ | stmt modifier_unless expr_value
+ {
+ /*%%%*/
+ $$ = new_unless(p, $3, remove_begin($1), 0, &@$);
+ fixpos($$, $3);
+ /*% %*/
+ /*% ripper: unless_mod!($3, $1) %*/
+ }
+ | stmt modifier_while expr_value
+ {
+ /*%%%*/
+ if ($1 && nd_type_p($1, NODE_BEGIN)) {
+ $$ = NEW_WHILE(cond(p, $3, &@3), $1->nd_body, 0, &@$);
+ }
+ else {
+ $$ = NEW_WHILE(cond(p, $3, &@3), $1, 1, &@$);
+ }
+ /*% %*/
+ /*% ripper: while_mod!($3, $1) %*/
+ }
+ | stmt modifier_until expr_value
+ {
+ /*%%%*/
+ if ($1 && nd_type_p($1, NODE_BEGIN)) {
+ $$ = NEW_UNTIL(cond(p, $3, &@3), $1->nd_body, 0, &@$);
+ }
+ else {
+ $$ = NEW_UNTIL(cond(p, $3, &@3), $1, 1, &@$);
+ }
+ /*% %*/
+ /*% ripper: until_mod!($3, $1) %*/
+ }
+ | stmt modifier_rescue stmt
+ {
+ /*%%%*/
+ NODE *resq;
+ YYLTYPE loc = code_loc_gen(&@2, &@3);
+ resq = NEW_RESBODY(0, remove_begin($3), 0, &loc);
+ $$ = NEW_RESCUE(remove_begin($1), resq, 0, &@$);
+ /*% %*/
+ /*% ripper: rescue_mod!($1, $3) %*/
+ }
+ | keyword_END '{' compstmt '}'
+ {
+ if (p->ctxt.in_def) {
+ rb_warn0("END in method; use at_exit");
+ }
+ /*%%%*/
+ {
+ NODE *scope = NEW_NODE(
+ NODE_SCOPE, 0 /* tbl */, $3 /* body */, 0 /* args */, &@$);
+ $$ = NEW_POSTEXE(scope, &@$);
+ }
+ /*% %*/
+ /*% ripper: END!($3) %*/
+ }
+ | command_asgn
+ | mlhs '=' lex_ctxt command_call
+ {
+ /*%%%*/
+ value_expr($4);
+ $$ = node_assign(p, $1, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: massign!($1, $4) %*/
+ }
+ | lhs '=' lex_ctxt mrhs
+ {
+ /*%%%*/
+ $$ = node_assign(p, $1, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: assign!($1, $4) %*/
+ }
+ | mlhs '=' lex_ctxt mrhs_arg modifier_rescue stmt
{
- $$ = NEW_ALIAS($2, $4, &@$, &@1);
- /*% ripper: alias!($:2, $:4) %*/
- }
- | keyword_alias tGVAR tGVAR
- {
- $$ = NEW_VALIAS($2, $3, &@$, &@1);
- /*% ripper: var_alias!($:2, $:3) %*/
- }
- | keyword_alias tGVAR tBACK_REF
- {
- char buf[2];
- buf[0] = '$';
- buf[1] = (char)RNODE_BACK_REF($3)->nd_nth;
- $$ = NEW_VALIAS($2, rb_intern2(buf, 2), &@$, &@1);
- /*% ripper: var_alias!($:2, $:3) %*/
- }
- | keyword_alias tGVAR tNTH_REF
- {
- static const char mesg[] = "can't make alias for the number variables";
/*%%%*/
- yyerror1(&@3, mesg);
+ YYLTYPE loc = code_loc_gen(&@5, &@6);
+ $$ = node_assign(p, $1, NEW_RESCUE($4, NEW_RESBODY(0, remove_begin($6), 0, &loc), 0, &@$), $3, &@$);
/*% %*/
- $$ = NEW_ERROR(&@$);
- /*% ripper[error]: alias_error!(ERR_MESG(), $:3) %*/
- }
- | keyword_undef undef_list
- {
- nd_set_first_loc($2, @1.beg_pos);
- RNODE_UNDEF($2)->keyword_loc = @1;
- $$ = $2;
- /*% ripper: undef!($:2) %*/
- }
- | stmt modifier_if expr_value
- {
- $$ = new_if(p, $3, remove_begin($1), 0, &@$);
- fixpos($$, $3);
- /*% ripper: if_mod!($:3, $:1) %*/
- }
- | stmt modifier_unless expr_value
- {
- $$ = new_unless(p, $3, remove_begin($1), 0, &@$, &@2, &NULL_LOC, &NULL_LOC);
- fixpos($$, $3);
- /*% ripper: unless_mod!($:3, $:1) %*/
- }
- | stmt modifier_while expr_value
- {
- clear_block_exit(p, false);
- if ($1 && nd_type_p($1, NODE_BEGIN)) {
- $$ = NEW_WHILE(cond(p, $3, &@3), RNODE_BEGIN($1)->nd_body, 0, &@$, &@2, &NULL_LOC);
- }
- else {
- $$ = NEW_WHILE(cond(p, $3, &@3), $1, 1, &@$, &@2, &NULL_LOC);
- }
- /*% ripper: while_mod!($:3, $:1) %*/
- }
- | stmt modifier_until expr_value
- {
- clear_block_exit(p, false);
- if ($1 && nd_type_p($1, NODE_BEGIN)) {
- $$ = NEW_UNTIL(cond(p, $3, &@3), RNODE_BEGIN($1)->nd_body, 0, &@$, &@2, &NULL_LOC);
- }
- else {
- $$ = NEW_UNTIL(cond(p, $3, &@3), $1, 1, &@$, &@2, &NULL_LOC);
- }
- /*% ripper: until_mod!($:3, $:1) %*/
- }
- | stmt modifier_rescue after_rescue stmt
- {
- p->ctxt.in_rescue = $3.in_rescue;
- NODE *resq;
- YYLTYPE loc = code_loc_gen(&@2, &@4);
- resq = NEW_RESBODY(0, 0, remove_begin($4), 0, &loc);
- $$ = NEW_RESCUE(remove_begin($1), resq, 0, &@$);
- /*% ripper: rescue_mod!($:1, $:4) %*/
- }
- | k_END allow_exits '{' compstmt '}'
- {
- if (p->ctxt.in_def) {
- rb_warn0("END in method; use at_exit");
- }
- restore_block_exit(p, $allow_exits);
- p->ctxt = $k_END;
- {
- NODE *scope = NEW_SCOPE2(0 /* tbl */, 0 /* args */, $compstmt /* body */, &@$);
- $$ = NEW_POSTEXE(scope, &@$);
- }
- /*% ripper: END!($:compstmt) %*/
- }
- | command_asgn
- | mlhs '=' lex_ctxt command_call
- {
- value_expr($4);
- $$ = node_assign(p, (NODE *)$1, $4, $3, &@$);
- /*% ripper: massign!($:1, $:4) %*/
- }
- | lhs '=' lex_ctxt mrhs
- {
- $$ = node_assign(p, $1, $4, $3, &@$);
- /*% ripper: assign!($:1, $:4) %*/
- }
- | mlhs '=' lex_ctxt mrhs_arg modifier_rescue
- after_rescue stmt[resbody]
- {
- p->ctxt.in_rescue = $3.in_rescue;
- YYLTYPE loc = code_loc_gen(&@modifier_rescue, &@resbody);
- $resbody = NEW_RESBODY(0, 0, remove_begin($resbody), 0, &loc);
- loc.beg_pos = @mrhs_arg.beg_pos;
- $mrhs_arg = NEW_RESCUE($mrhs_arg, $resbody, 0, &loc);
- $$ = node_assign(p, (NODE *)$mlhs, $mrhs_arg, $lex_ctxt, &@$);
- /*% ripper: massign!($:1, rescue_mod!($:4, $:7)) %*/
- }
- | mlhs '=' lex_ctxt mrhs_arg
- {
- $$ = node_assign(p, (NODE *)$1, $4, $3, &@$);
- /*% ripper: massign!($:1, $:4) %*/
- }
- | expr
- | error
- {
- (void)yynerrs;
- $$ = NEW_ERROR(&@$);
- }
- ;
+ /*% ripper: massign!($1, rescue_mod!($4, $6)) %*/
+ }
+ | mlhs '=' lex_ctxt mrhs_arg
+ {
+ /*%%%*/
+ $$ = node_assign(p, $1, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: massign!($1, $4) %*/
+ }
+ | expr
+ | error
+ {
+ /*%%%*/
+ $$ = NEW_ERROR(&@$);
+ /*% %*/
+ }
+ ;
command_asgn : lhs '=' lex_ctxt command_rhs
- {
- $$ = node_assign(p, $1, $4, $3, &@$);
- /*% ripper: assign!($:1, $:4) %*/
- }
- | var_lhs tOP_ASGN lex_ctxt command_rhs
- {
- $$ = new_op_assign(p, $1, $2, $4, $3, &@$);
- /*% ripper: opassign!($:1, $:2, $:4) %*/
- }
- | primary_value '[' opt_call_args rbracket tOP_ASGN lex_ctxt command_rhs
- {
- $$ = new_ary_op_assign(p, $1, $3, $5, $7, &@3, &@$, &NULL_LOC, &@2, &@4, &@5);
- /*% ripper: opassign!(aref_field!($:1, $:3), $:5, $:7) %*/
-
- }
- | primary_value call_op ident_or_const tOP_ASGN lex_ctxt command_rhs
- {
- $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$, &@2, &@3, &@4);
- /*% ripper: opassign!(field!($:1, $:2, $:3), $:4, $:6) %*/
- }
- | primary_value tCOLON2 tCONSTANT tOP_ASGN lex_ctxt command_rhs
- {
- YYLTYPE loc = code_loc_gen(&@1, &@3);
- $$ = new_const_op_assign(p, NEW_COLON2($1, $3, &loc), $4, $6, $5, &@$);
- /*% ripper: opassign!(const_path_field!($:1, $:3), $:4, $:6) %*/
- }
- | primary_value tCOLON2 tIDENTIFIER tOP_ASGN lex_ctxt command_rhs
- {
- $$ = new_attr_op_assign(p, $1, idCOLON2, $3, $4, $6, &@$, &@2, &@3, &@4);
- /*% ripper: opassign!(field!($:1, $:2, $:3), $:4, $:6) %*/
- }
- | defn_head[head] f_opt_paren_args[args] '=' endless_command[bodystmt]
- {
- endless_method_name(p, $head->nd_mid, &@head);
- restore_defun(p, $head);
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
- ($$ = $head->nd_def)->nd_loc = @$;
- RNODE_DEFN($$)->nd_defn = $bodystmt;
- /*% ripper: bodystmt!($:bodystmt, Qnil, Qnil, Qnil) %*/
- /*% ripper: def!($:head, $:args, $:$) %*/
- local_pop(p);
- }
- | defs_head[head] f_opt_paren_args[args] '=' endless_command[bodystmt]
- {
- endless_method_name(p, $head->nd_mid, &@head);
- restore_defun(p, $head);
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
- ($$ = $head->nd_def)->nd_loc = @$;
- RNODE_DEFS($$)->nd_defn = $bodystmt;
- /*% ripper: bodystmt!($:bodystmt, Qnil, Qnil, Qnil) %*/
- /*% ripper: defs!(*$:head[0..2], $:args, $:$) %*/
- local_pop(p);
- }
- | backref tOP_ASGN lex_ctxt command_rhs
- {
- VALUE MAYBE_UNUSED(e) = rb_backref_error(p, $1);
- $$ = NEW_ERROR(&@$);
- /*% ripper[error]: assign_error!(?e, opassign!(var_field!($:1), $:2, $:4)) %*/
- }
- ;
-
-endless_command : command
- | endless_command modifier_rescue after_rescue arg
- {
- p->ctxt.in_rescue = $3.in_rescue;
- $$ = rescued_expr(p, $1, $4, &@1, &@2, &@4);
- /*% ripper: rescue_mod!($:1, $:4) %*/
- }
- | keyword_not '\n'? endless_command
- {
- $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
- /*% ripper: unary!(ID2VAL(idNOT), $:3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = node_assign(p, $1, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: assign!($1, $4) %*/
+ }
+ | var_lhs tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ $$ = new_op_assign(p, $1, $2, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: opassign!($1, $2, $4) %*/
+ }
+ | primary_value '[' opt_call_args rbracket tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ $$ = new_ary_op_assign(p, $1, $3, $5, $7, &@3, &@$);
+ /*% %*/
+ /*% ripper: opassign!(aref_field!($1, escape_Qundef($3)), $5, $7) %*/
+
+ }
+ | primary_value call_op tIDENTIFIER tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$);
+ /*% %*/
+ /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
+ }
+ | primary_value call_op tCONSTANT tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$);
+ /*% %*/
+ /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
+ }
+ | primary_value tCOLON2 tCONSTANT tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ YYLTYPE loc = code_loc_gen(&@1, &@3);
+ $$ = new_const_op_assign(p, NEW_COLON2($1, $3, &loc), $4, $6, $5, &@$);
+ /*% %*/
+ /*% ripper: opassign!(const_path_field!($1, $3), $4, $6) %*/
+ }
+ | primary_value tCOLON2 tIDENTIFIER tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ $$ = new_attr_op_assign(p, $1, ID2VAL(idCOLON2), $3, $4, $6, &@$);
+ /*% %*/
+ /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
+ }
+ | defn_head f_opt_paren_args '=' command
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*% %*/
+ /*% ripper[$4]: bodystmt!($4, Qnil, Qnil, Qnil) %*/
+ /*% ripper: def!(get_value($1), $2, $4) %*/
+ local_pop(p);
+ }
+ | defn_head f_opt_paren_args '=' command modifier_rescue arg
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $4 = rescued_expr(p, $4, $6, &@4, &@5, &@6);
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*% %*/
+ /*% ripper[$4]: bodystmt!(rescue_mod!($4, $6), Qnil, Qnil, Qnil) %*/
+ /*% ripper: def!(get_value($1), $2, $4) %*/
+ local_pop(p);
+ }
+ | defs_head f_opt_paren_args '=' command
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*%
+ $1 = get_value($1);
+ %*/
+ /*% ripper[$4]: bodystmt!($4, Qnil, Qnil, Qnil) %*/
+ /*% ripper: defs!(AREF($1, 0), AREF($1, 1), AREF($1, 2), $2, $4) %*/
+ local_pop(p);
+ }
+ | defs_head f_opt_paren_args '=' command modifier_rescue arg
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $4 = rescued_expr(p, $4, $6, &@4, &@5, &@6);
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*%
+ $1 = get_value($1);
+ %*/
+ /*% ripper[$4]: bodystmt!(rescue_mod!($4, $6), Qnil, Qnil, Qnil) %*/
+ /*% ripper: defs!(AREF($1, 0), AREF($1, 1), AREF($1, 2), $2, $4) %*/
+ local_pop(p);
+ }
+ | backref tOP_ASGN lex_ctxt command_rhs
+ {
+ /*%%%*/
+ rb_backref_error(p, $1);
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper[error]: backref_error(p, RNODE($1), assign!(var_field(p, $1), $4)) %*/
+ }
+ ;
command_rhs : command_call %prec tOP_ASGN
- {
- value_expr($1);
- $$ = $1;
- }
- | command_call modifier_rescue after_rescue stmt
- {
- p->ctxt.in_rescue = $3.in_rescue;
- YYLTYPE loc = code_loc_gen(&@2, &@4);
- value_expr($1);
- $$ = NEW_RESCUE($1, NEW_RESBODY(0, 0, remove_begin($4), 0, &loc), 0, &@$);
- /*% ripper: rescue_mod!($:1, $:4) %*/
- }
- | command_asgn
- ;
+ {
+ value_expr($1);
+ $$ = $1;
+ }
+ | command_call modifier_rescue stmt
+ {
+ /*%%%*/
+ YYLTYPE loc = code_loc_gen(&@2, &@3);
+ value_expr($1);
+ $$ = NEW_RESCUE($1, NEW_RESBODY(0, remove_begin($3), 0, &loc), 0, &@$);
+ /*% %*/
+ /*% ripper: rescue_mod!($1, $3) %*/
+ }
+ | command_asgn
+ ;
expr : command_call
- | expr keyword_and expr
- {
- $$ = logop(p, idAND, $1, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idAND), $:3) %*/
- }
- | expr keyword_or expr
- {
- $$ = logop(p, idOR, $1, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idOR), $:3) %*/
- }
- | keyword_not '\n'? expr
- {
- $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
- /*% ripper: unary!(ID2VAL(idNOT), $:3) %*/
- }
- | '!' command_call
- {
- $$ = call_uni_op(p, method_cond(p, $2, &@2), '!', &@1, &@$);
- /*% ripper: unary!(ID2VAL('\'!\''), $:2) %*/
- }
- | arg tASSOC
- {
- value_expr($arg);
- }
- p_in_kwarg[ctxt] p_pvtbl p_pktbl
- p_top_expr_body[body]
- {
- pop_pktbl(p, $p_pktbl);
- pop_pvtbl(p, $p_pvtbl);
- p->ctxt.in_kwarg = $ctxt.in_kwarg;
- $$ = NEW_CASE3($arg, NEW_IN($body, 0, 0, &@body), &@$, &NULL_LOC, &NULL_LOC);
- /*% ripper: case!($:arg, in!($:body, Qnil, Qnil)) %*/
- }
- | arg keyword_in
- {
- value_expr($arg);
- }
- p_in_kwarg[ctxt] p_pvtbl p_pktbl
- p_top_expr_body[body]
- {
- pop_pktbl(p, $p_pktbl);
- pop_pvtbl(p, $p_pvtbl);
- p->ctxt.in_kwarg = $ctxt.in_kwarg;
- $$ = NEW_CASE3($arg, NEW_IN($body, NEW_TRUE(&@body), NEW_FALSE(&@body), &@body), &@$, &NULL_LOC, &NULL_LOC);
- /*% ripper: case!($:arg, in!($:body, Qnil, Qnil)) %*/
- }
- | arg %prec tLBRACE_ARG
- ;
-
-def_name : fname
- {
- ID fname = $1;
+ | expr keyword_and expr
+ {
+ $$ = logop(p, idAND, $1, $3, &@2, &@$);
+ }
+ | expr keyword_or expr
+ {
+ $$ = logop(p, idOR, $1, $3, &@2, &@$);
+ }
+ | keyword_not opt_nl expr
+ {
+ $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
+ }
+ | '!' command_call
+ {
+ $$ = call_uni_op(p, method_cond(p, $2, &@2), '!', &@1, &@$);
+ }
+ | arg tASSOC
+ {
+ value_expr($1);
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ p->command_start = FALSE;
+ $<ctxt>2 = p->ctxt;
+ p->ctxt.in_kwarg = 1;
+ $<tbl>$ = push_pvtbl(p);
+ }
+ {
+ $<tbl>$ = push_pktbl(p);
+ }
+ p_top_expr_body
+ {
+ pop_pktbl(p, $<tbl>4);
+ pop_pvtbl(p, $<tbl>3);
+ p->ctxt.in_kwarg = $<ctxt>2.in_kwarg;
+ /*%%%*/
+ $$ = NEW_CASE3($1, NEW_IN($5, 0, 0, &@5), &@$);
+ /*% %*/
+ /*% ripper: case!($1, in!($5, Qnil, Qnil)) %*/
+ }
+ | arg keyword_in
+ {
+ value_expr($1);
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ p->command_start = FALSE;
+ $<ctxt>2 = p->ctxt;
+ p->ctxt.in_kwarg = 1;
+ $<tbl>$ = push_pvtbl(p);
+ }
+ {
+ $<tbl>$ = push_pktbl(p);
+ }
+ p_top_expr_body
+ {
+ pop_pktbl(p, $<tbl>4);
+ pop_pvtbl(p, $<tbl>3);
+ p->ctxt.in_kwarg = $<ctxt>2.in_kwarg;
+ /*%%%*/
+ $$ = NEW_CASE3($1, NEW_IN($5, NEW_TRUE(&@5), NEW_FALSE(&@5), &@5), &@$);
+ /*% %*/
+ /*% ripper: case!($1, in!($5, Qnil, Qnil)) %*/
+ }
+ | arg %prec tLBRACE_ARG
+ ;
+
+def_name : fname
+ {
+ ID fname = get_id($1);
+ ID cur_arg = p->cur_arg;
+ YYSTYPE c = {.ctxt = p->ctxt};
numparam_name(p, fname);
+ NODE *save =
+ NODE_NEW_TEMPORAL(NODE_SELF,
+ /*head*/numparam_push(p),
+ /*nth*/p->max_numparam,
+ /*cval*/c.val);
local_push(p, 0);
+ p->cur_arg = 0;
p->ctxt.in_def = 1;
- p->ctxt.in_rescue = before_rescue;
- p->ctxt.cant_return = 0;
- $$ = $1;
+ $<node>$ = NEW_NODE(NODE_SELF, /*vid*/cur_arg, /*mid*/fname, /*args*/save, &@$);
+ /*%%%*/
+ /*%
+ $$ = NEW_RIPPER(fname, get_value($1), $$, &NULL_LOC);
+ %*/
}
;
defn_head : k_def def_name
- {
- $$ = def_head_save(p, $k_def);
- $$->nd_mid = $def_name;
- $$->nd_def = NEW_DEFN($def_name, 0, &@$);
- /*% ripper: $:def_name %*/
- }
- ;
+ {
+ $$ = $2;
+ /*%%%*/
+ $$ = NEW_NODE(NODE_DEFN, 0, $$->nd_mid, $$, &@$);
+ /*% %*/
+ }
+ ;
defs_head : k_def singleton dot_or_colon
- {
- SET_LEX_STATE(EXPR_FNAME);
- }
- def_name
- {
- SET_LEX_STATE(EXPR_ENDFN|EXPR_LABEL); /* force for args */
- $$ = def_head_save(p, $k_def);
- $$->nd_mid = $def_name;
- $$->nd_def = NEW_DEFS($singleton, $def_name, 0, &@$);
- /*% ripper: [$:singleton, $:dot_or_colon, $:def_name] %*/
- }
- ;
+ {
+ SET_LEX_STATE(EXPR_FNAME);
+ p->ctxt.in_argdef = 1;
+ }
+ def_name
+ {
+ SET_LEX_STATE(EXPR_ENDFN|EXPR_LABEL); /* force for args */
+ $$ = $5;
+ /*%%%*/
+ $$ = NEW_NODE(NODE_DEFS, $2, $$->nd_mid, $$, &@$);
+ /*%
+ VALUE ary = rb_ary_new_from_args(3, $2, $3, get_value($$));
+ add_mark_object(p, ary);
+ $<node>$->nd_rval = ary;
+ %*/
+ }
+ ;
expr_value : expr
- {
- value_expr($1);
- $$ = $1;
- }
- | error
- {
- $$ = NEW_ERROR(&@$);
- }
- ;
+ {
+ value_expr($1);
+ $$ = $1;
+ }
+ | error
+ {
+ /*%%%*/
+ $$ = NEW_ERROR(&@$);
+ /*% %*/
+ }
+ ;
expr_value_do : {COND_PUSH(1);} expr_value do {COND_POP();}
- {
- $$ = $2;
- /*% ripper: $:2 %*/
- }
- ;
+ {
+ $$ = $2;
+ }
+ ;
command_call : command
- | block_command
- ;
+ | block_command
+ ;
block_command : block_call
- | block_call call_op2 operation2 command_args
- {
- $$ = new_qcall(p, $2, $1, $3, $4, &@3, &@$);
- /*% ripper: method_add_arg!(call!($:1, $:2, $:3), $:4) %*/
- }
- ;
+ | block_call call_op2 operation2 command_args
+ {
+ /*%%%*/
+ $$ = new_qcall(p, $2, $1, $3, $4, &@3, &@$);
+ /*% %*/
+ /*% ripper: method_add_arg!(call!($1, $2, $3), $4) %*/
+ }
+ ;
cmd_brace_block : tLBRACE_ARG brace_body '}'
- {
- $$ = $2;
- set_embraced_location($$, &@1, &@3);
- /*% ripper: $:2 %*/
- }
- ;
+ {
+ $$ = $2;
+ /*%%%*/
+ $$->nd_body->nd_loc = code_loc_gen(&@1, &@3);
+ nd_set_line($$, @1.end_pos.lineno);
+ /*% %*/
+ }
+ ;
fcall : operation
- {
- $$ = NEW_FCALL($1, 0, &@$);
- /*% ripper: $:1 %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_FCALL($1, 0, &@$);
+ nd_set_line($$, p->tokline);
+ /*% %*/
+ /*% ripper: $1 %*/
+ }
+ ;
command : fcall command_args %prec tLOWEST
- {
- $1->nd_args = $2;
- nd_set_last_loc($1, @2.end_pos);
- $$ = (NODE *)$1;
- /*% ripper: command!($:1, $:2) %*/
- }
- | fcall command_args cmd_brace_block
- {
- block_dup_check(p, $2, $3);
- $1->nd_args = $2;
- $$ = method_add_block(p, (NODE *)$1, $3, &@$);
- fixpos($$, RNODE($1));
- nd_set_last_loc($1, @2.end_pos);
- /*% ripper: method_add_block!(command!($:1, $:2), $:3) %*/
- }
- | primary_value call_op operation2 command_args %prec tLOWEST
- {
- $$ = new_command_qcall(p, $2, $1, $3, $4, 0, &@3, &@$);
- /*% ripper: command_call!($:1, $:2, $:3, $:4) %*/
- }
- | primary_value call_op operation2 command_args cmd_brace_block
- {
- $$ = new_command_qcall(p, $2, $1, $3, $4, $5, &@3, &@$);
- /*% ripper: method_add_block!(command_call!($:1, $:2, $:3, $:4), $:5) %*/
- }
- | primary_value tCOLON2 operation2 command_args %prec tLOWEST
- {
- $$ = new_command_qcall(p, idCOLON2, $1, $3, $4, 0, &@3, &@$);
- /*% ripper: command_call!($:1, $:2, $:3, $:4) %*/
- }
- | primary_value tCOLON2 operation2 command_args cmd_brace_block
- {
- $$ = new_command_qcall(p, idCOLON2, $1, $3, $4, $5, &@3, &@$);
- /*% ripper: method_add_block!(command_call!($:1, $:2, $:3, $:4), $:5) %*/
- }
- | primary_value tCOLON2 tCONSTANT '{' brace_body '}'
- {
- set_embraced_location($5, &@4, &@6);
- $$ = new_command_qcall(p, idCOLON2, $1, $3, 0, $5, &@3, &@$);
- /*% ripper: method_add_block!(command_call!($:1, $:2, $:3, Qnil), $:5) %*/
- }
- | keyword_super command_args
- {
- $$ = NEW_SUPER($2, &@$);
- fixpos($$, $2);
- /*% ripper: super!($:2) %*/
- }
- | k_yield command_args
- {
- $$ = new_yield(p, $2, &@$);
- fixpos($$, $2);
- /*% ripper: yield!($:2) %*/
- }
- | k_return call_args
- {
- $$ = NEW_RETURN(ret_args(p, $2), &@$, &@1);
- /*% ripper: return!($:2) %*/
- }
- | keyword_break call_args
- {
- NODE *args = 0;
- args = ret_args(p, $2);
- $$ = add_block_exit(p, NEW_BREAK(args, &@$, &@1));
- /*% ripper: break!($:2) %*/
- }
- | keyword_next call_args
- {
- NODE *args = 0;
- args = ret_args(p, $2);
- $$ = add_block_exit(p, NEW_NEXT(args, &@$, &@1));
- /*% ripper: next!($:2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $1->nd_args = $2;
+ nd_set_last_loc($1, @2.end_pos);
+ $$ = $1;
+ /*% %*/
+ /*% ripper: command!($1, $2) %*/
+ }
+ | fcall command_args cmd_brace_block
+ {
+ /*%%%*/
+ block_dup_check(p, $2, $3);
+ $1->nd_args = $2;
+ $$ = method_add_block(p, $1, $3, &@$);
+ fixpos($$, $1);
+ nd_set_last_loc($1, @2.end_pos);
+ /*% %*/
+ /*% ripper: method_add_block!(command!($1, $2), $3) %*/
+ }
+ | primary_value call_op operation2 command_args %prec tLOWEST
+ {
+ /*%%%*/
+ $$ = new_command_qcall(p, $2, $1, $3, $4, Qnull, &@3, &@$);
+ /*% %*/
+ /*% ripper: command_call!($1, $2, $3, $4) %*/
+ }
+ | primary_value call_op operation2 command_args cmd_brace_block
+ {
+ /*%%%*/
+ $$ = new_command_qcall(p, $2, $1, $3, $4, $5, &@3, &@$);
+ /*% %*/
+ /*% ripper: method_add_block!(command_call!($1, $2, $3, $4), $5) %*/
+ }
+ | primary_value tCOLON2 operation2 command_args %prec tLOWEST
+ {
+ /*%%%*/
+ $$ = new_command_qcall(p, ID2VAL(idCOLON2), $1, $3, $4, Qnull, &@3, &@$);
+ /*% %*/
+ /*% ripper: command_call!($1, $2, $3, $4) %*/
+ }
+ | primary_value tCOLON2 operation2 command_args cmd_brace_block
+ {
+ /*%%%*/
+ $$ = new_command_qcall(p, ID2VAL(idCOLON2), $1, $3, $4, $5, &@3, &@$);
+ /*% %*/
+ /*% ripper: method_add_block!(command_call!($1, $2, $3, $4), $5) %*/
+ }
+ | keyword_super command_args
+ {
+ /*%%%*/
+ $$ = NEW_SUPER($2, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: super!($2) %*/
+ }
+ | keyword_yield command_args
+ {
+ /*%%%*/
+ $$ = new_yield(p, $2, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: yield!($2) %*/
+ }
+ | k_return call_args
+ {
+ /*%%%*/
+ $$ = NEW_RETURN(ret_args(p, $2), &@$);
+ /*% %*/
+ /*% ripper: return!($2) %*/
+ }
+ | keyword_break call_args
+ {
+ /*%%%*/
+ $$ = NEW_BREAK(ret_args(p, $2), &@$);
+ /*% %*/
+ /*% ripper: break!($2) %*/
+ }
+ | keyword_next call_args
+ {
+ /*%%%*/
+ $$ = NEW_NEXT(ret_args(p, $2), &@$);
+ /*% %*/
+ /*% ripper: next!($2) %*/
+ }
+ ;
mlhs : mlhs_basic
- | tLPAREN mlhs_inner rparen
- {
- $$ = $2;
- /*% ripper: mlhs_paren!($:2) %*/
- }
- ;
+ | tLPAREN mlhs_inner rparen
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: mlhs_paren!($2) %*/
+ }
+ ;
mlhs_inner : mlhs_basic
- | tLPAREN mlhs_inner rparen
- {
- $$ = NEW_MASGN(NEW_LIST((NODE *)$2, &@$), 0, &@$);
- /*% ripper: mlhs_paren!($:2) %*/
- }
- ;
+ | tLPAREN mlhs_inner rparen
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(NEW_LIST($2, &@$), 0, &@$);
+ /*% %*/
+ /*% ripper: mlhs_paren!($2) %*/
+ }
+ ;
mlhs_basic : mlhs_head
- {
- $$ = NEW_MASGN($1, 0, &@$);
- /*% ripper: $:1 %*/
- }
- | mlhs_head mlhs_item
- {
- $$ = NEW_MASGN(list_append(p, $1, $2), 0, &@$);
- /*% ripper: mlhs_add!($:1, $:2) %*/
- }
- | mlhs_head tSTAR mlhs_node
- {
- $$ = NEW_MASGN($1, $3, &@$);
- /*% ripper: mlhs_add_star!($:1, $:3) %*/
- }
- | mlhs_head tSTAR mlhs_node ',' mlhs_post
- {
- $$ = NEW_MASGN($1, NEW_POSTARG($3,$5,&@$), &@$);
- /*% ripper: mlhs_add_post!(mlhs_add_star!($:1, $:3), $:5) %*/
- }
- | mlhs_head tSTAR
- {
- $$ = NEW_MASGN($1, NODE_SPECIAL_NO_NAME_REST, &@$);
- /*% ripper: mlhs_add_star!($:1, Qnil) %*/
- }
- | mlhs_head tSTAR ',' mlhs_post
- {
- $$ = NEW_MASGN($1, NEW_POSTARG(NODE_SPECIAL_NO_NAME_REST, $4, &@$), &@$);
- /*% ripper: mlhs_add_post!(mlhs_add_star!($:1, Qnil), $:4) %*/
- }
- | tSTAR mlhs_node
- {
- $$ = NEW_MASGN(0, $2, &@$);
- /*% ripper: mlhs_add_star!(mlhs_new!, $:2) %*/
- }
- | tSTAR mlhs_node ',' mlhs_post
- {
- $$ = NEW_MASGN(0, NEW_POSTARG($2,$4,&@$), &@$);
- /*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, $:2), $:4) %*/
- }
- | tSTAR
- {
- $$ = NEW_MASGN(0, NODE_SPECIAL_NO_NAME_REST, &@$);
- /*% ripper: mlhs_add_star!(mlhs_new!, Qnil) %*/
- }
- | tSTAR ',' mlhs_post
- {
- $$ = NEW_MASGN(0, NEW_POSTARG(NODE_SPECIAL_NO_NAME_REST, $3, &@$), &@$);
- /*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, Qnil), $:3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, 0, &@$);
+ /*% %*/
+ /*% ripper: $1 %*/
+ }
+ | mlhs_head mlhs_item
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(list_append(p, $1,$2), 0, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add!($1, $2) %*/
+ }
+ | mlhs_head tSTAR mlhs_node
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, $3, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_star!($1, $3) %*/
+ }
+ | mlhs_head tSTAR mlhs_node ',' mlhs_post
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, NEW_POSTARG($3,$5,&@$), &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_post!(mlhs_add_star!($1, $3), $5) %*/
+ }
+ | mlhs_head tSTAR
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, NODE_SPECIAL_NO_NAME_REST, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_star!($1, Qnil) %*/
+ }
+ | mlhs_head tSTAR ',' mlhs_post
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, NEW_POSTARG(NODE_SPECIAL_NO_NAME_REST, $4, &@$), &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_post!(mlhs_add_star!($1, Qnil), $4) %*/
+ }
+ | tSTAR mlhs_node
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(0, $2, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_star!(mlhs_new!, $2) %*/
+ }
+ | tSTAR mlhs_node ',' mlhs_post
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(0, NEW_POSTARG($2,$4,&@$), &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, $2), $4) %*/
+ }
+ | tSTAR
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(0, NODE_SPECIAL_NO_NAME_REST, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_star!(mlhs_new!, Qnil) %*/
+ }
+ | tSTAR ',' mlhs_post
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(0, NEW_POSTARG(NODE_SPECIAL_NO_NAME_REST, $3, &@$), &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, Qnil), $3) %*/
+ }
+ ;
mlhs_item : mlhs_node
- | tLPAREN mlhs_inner rparen
- {
- $$ = (NODE *)$2;
- /*% ripper: mlhs_paren!($:2) %*/
- }
- ;
+ | tLPAREN mlhs_inner rparen
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: mlhs_paren!($2) %*/
+ }
+ ;
mlhs_head : mlhs_item ','
- {
- $$ = NEW_LIST($1, &@1);
- /*% ripper: mlhs_add!(mlhs_new!, $:1) %*/
- }
- | mlhs_head mlhs_item ','
- {
- $$ = list_append(p, $1, $2);
- /*% ripper: mlhs_add!($:1, $:2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_LIST($1, &@1);
+ /*% %*/
+ /*% ripper: mlhs_add!(mlhs_new!, $1) %*/
+ }
+ | mlhs_head mlhs_item ','
+ {
+ /*%%%*/
+ $$ = list_append(p, $1, $2);
+ /*% %*/
+ /*% ripper: mlhs_add!($1, $2) %*/
+ }
+ ;
mlhs_post : mlhs_item
- {
- $$ = NEW_LIST($1, &@$);
- /*% ripper: mlhs_add!(mlhs_new!, $:1) %*/
- }
- | mlhs_post ',' mlhs_item
- {
- $$ = list_append(p, $1, $3);
- /*% ripper: mlhs_add!($:1, $:3) %*/
- }
- ;
-
-mlhs_node : user_or_keyword_variable
- {
- /*% ripper: var_field!($:1) %*/
- $$ = assignable(p, $1, 0, &@$);
- }
- | primary_value '[' opt_call_args rbracket
- {
- $$ = aryset(p, $1, $3, &@$);
- /*% ripper: aref_field!($:1, $:3) %*/
- }
- | primary_value call_op tIDENTIFIER
- {
- anddot_multiple_assignment_check(p, &@2, $2);
- $$ = attrset(p, $1, $2, $3, &@$);
- /*% ripper: field!($:1, $:2, $:3) %*/
- }
- | primary_value tCOLON2 tIDENTIFIER
- {
- $$ = attrset(p, $1, idCOLON2, $3, &@$);
- /*% ripper: const_path_field!($:1, $:3) %*/
- }
- | primary_value call_op tCONSTANT
- {
- anddot_multiple_assignment_check(p, &@2, $2);
- $$ = attrset(p, $1, $2, $3, &@$);
- /*% ripper: field!($:1, $:2, $:3) %*/
- }
- | primary_value tCOLON2 tCONSTANT
- {
- /*% ripper: const_path_field!($:1, $:3) %*/
- $$ = const_decl(p, NEW_COLON2($1, $3, &@$), &@$);
- }
- | tCOLON3 tCONSTANT
- {
- /*% ripper: top_const_field!($:2) %*/
- $$ = const_decl(p, NEW_COLON3($2, &@$), &@$);
- }
- | backref
- {
- VALUE MAYBE_UNUSED(e) = rb_backref_error(p, $1);
- $$ = NEW_ERROR(&@$);
- /*% ripper[error]: assign_error!(?e, var_field!($:1)) %*/
- }
- ;
-
-lhs : user_or_keyword_variable
- {
- /*% ripper: var_field!($:1) %*/
- $$ = assignable(p, $1, 0, &@$);
- }
- | primary_value '[' opt_call_args rbracket
- {
- $$ = aryset(p, $1, $3, &@$);
- /*% ripper: aref_field!($:1, $:3) %*/
- }
- | primary_value call_op tIDENTIFIER
- {
- $$ = attrset(p, $1, $2, $3, &@$);
- /*% ripper: field!($:1, $:2, $:3) %*/
- }
- | primary_value tCOLON2 tIDENTIFIER
- {
- $$ = attrset(p, $1, idCOLON2, $3, &@$);
- /*% ripper: field!($:1, $:2, $:3) %*/
- }
- | primary_value call_op tCONSTANT
- {
- $$ = attrset(p, $1, $2, $3, &@$);
- /*% ripper: field!($:1, $:2, $:3) %*/
- }
- | primary_value tCOLON2 tCONSTANT
- {
- /*% ripper: const_path_field!($:1, $:3) %*/
- $$ = const_decl(p, NEW_COLON2($1, $3, &@$), &@$);
- }
- | tCOLON3 tCONSTANT
- {
- /*% ripper: top_const_field!($:2) %*/
- $$ = const_decl(p, NEW_COLON3($2, &@$), &@$);
- }
- | backref
- {
- VALUE MAYBE_UNUSED(e) = rb_backref_error(p, $1);
- $$ = NEW_ERROR(&@$);
- /*% ripper[error]: assign_error!(?e, var_field!($:1)) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add!(mlhs_new!, $1) %*/
+ }
+ | mlhs_post ',' mlhs_item
+ {
+ /*%%%*/
+ $$ = list_append(p, $1, $3);
+ /*% %*/
+ /*% ripper: mlhs_add!($1, $3) %*/
+ }
+ ;
+
+mlhs_node : user_variable
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ | keyword_variable
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ | primary_value '[' opt_call_args rbracket
+ {
+ /*%%%*/
+ $$ = aryset(p, $1, $3, &@$);
+ /*% %*/
+ /*% ripper: aref_field!($1, escape_Qundef($3)) %*/
+ }
+ | primary_value call_op tIDENTIFIER
+ {
+ if ($2 == tANDDOT) {
+ yyerror1(&@2, "&. inside multiple assignment destination");
+ }
+ /*%%%*/
+ $$ = attrset(p, $1, $2, $3, &@$);
+ /*% %*/
+ /*% ripper: field!($1, $2, $3) %*/
+ }
+ | primary_value tCOLON2 tIDENTIFIER
+ {
+ /*%%%*/
+ $$ = attrset(p, $1, idCOLON2, $3, &@$);
+ /*% %*/
+ /*% ripper: const_path_field!($1, $3) %*/
+ }
+ | primary_value call_op tCONSTANT
+ {
+ if ($2 == tANDDOT) {
+ yyerror1(&@2, "&. inside multiple assignment destination");
+ }
+ /*%%%*/
+ $$ = attrset(p, $1, $2, $3, &@$);
+ /*% %*/
+ /*% ripper: field!($1, $2, $3) %*/
+ }
+ | primary_value tCOLON2 tCONSTANT
+ {
+ /*%%%*/
+ $$ = const_decl(p, NEW_COLON2($1, $3, &@$), &@$);
+ /*% %*/
+ /*% ripper: const_decl(p, const_path_field!($1, $3)) %*/
+ }
+ | tCOLON3 tCONSTANT
+ {
+ /*%%%*/
+ $$ = const_decl(p, NEW_COLON3($2, &@$), &@$);
+ /*% %*/
+ /*% ripper: const_decl(p, top_const_field!($2)) %*/
+ }
+ | backref
+ {
+ /*%%%*/
+ rb_backref_error(p, $1);
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper[error]: backref_error(p, RNODE($1), var_field(p, $1)) %*/
+ }
+ ;
+
+lhs : user_variable
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ | keyword_variable
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ | primary_value '[' opt_call_args rbracket
+ {
+ /*%%%*/
+ $$ = aryset(p, $1, $3, &@$);
+ /*% %*/
+ /*% ripper: aref_field!($1, escape_Qundef($3)) %*/
+ }
+ | primary_value call_op tIDENTIFIER
+ {
+ /*%%%*/
+ $$ = attrset(p, $1, $2, $3, &@$);
+ /*% %*/
+ /*% ripper: field!($1, $2, $3) %*/
+ }
+ | primary_value tCOLON2 tIDENTIFIER
+ {
+ /*%%%*/
+ $$ = attrset(p, $1, idCOLON2, $3, &@$);
+ /*% %*/
+ /*% ripper: field!($1, $2, $3) %*/
+ }
+ | primary_value call_op tCONSTANT
+ {
+ /*%%%*/
+ $$ = attrset(p, $1, $2, $3, &@$);
+ /*% %*/
+ /*% ripper: field!($1, $2, $3) %*/
+ }
+ | primary_value tCOLON2 tCONSTANT
+ {
+ /*%%%*/
+ $$ = const_decl(p, NEW_COLON2($1, $3, &@$), &@$);
+ /*% %*/
+ /*% ripper: const_decl(p, const_path_field!($1, $3)) %*/
+ }
+ | tCOLON3 tCONSTANT
+ {
+ /*%%%*/
+ $$ = const_decl(p, NEW_COLON3($2, &@$), &@$);
+ /*% %*/
+ /*% ripper: const_decl(p, top_const_field!($2)) %*/
+ }
+ | backref
+ {
+ /*%%%*/
+ rb_backref_error(p, $1);
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper[error]: backref_error(p, RNODE($1), var_field(p, $1)) %*/
+ }
+ ;
cname : tIDENTIFIER
- {
- static const char mesg[] = "class/module name must be CONSTANT";
- /*%%%*/
- yyerror1(&@1, mesg);
- /*% %*/
- /*% ripper[error]: class_name_error!(ERR_MESG(), $:1) %*/
- }
- | tCONSTANT
- ;
+ {
+ static const char mesg[] = "class/module name must be CONSTANT";
+ /*%%%*/
+ yyerror1(&@1, mesg);
+ /*% %*/
+ /*% ripper[error]: class_name_error!(ERR_MESG(), $1) %*/
+ }
+ | tCONSTANT
+ ;
cpath : tCOLON3 cname
- {
- $$ = NEW_COLON3($2, &@$);
- /*% ripper: top_const_ref!($:2) %*/
- }
- | cname
- {
- $$ = NEW_COLON2(0, $1, &@$);
- /*% ripper: const_ref!($:1) %*/
- }
- | primary_value tCOLON2 cname
- {
- $$ = NEW_COLON2($1, $3, &@$);
- /*% ripper: const_path_ref!($:1, $:3) %*/
- }
- ;
-
-fname : ident_or_const
- | tFID
- | op
- {
- SET_LEX_STATE(EXPR_ENDFN);
- $$ = $1;
- }
- | reswords
- ;
+ {
+ /*%%%*/
+ $$ = NEW_COLON3($2, &@$);
+ /*% %*/
+ /*% ripper: top_const_ref!($2) %*/
+ }
+ | cname
+ {
+ /*%%%*/
+ $$ = NEW_COLON2(0, $$, &@$);
+ /*% %*/
+ /*% ripper: const_ref!($1) %*/
+ }
+ | primary_value tCOLON2 cname
+ {
+ /*%%%*/
+ $$ = NEW_COLON2($1, $3, &@$);
+ /*% %*/
+ /*% ripper: const_path_ref!($1, $3) %*/
+ }
+ ;
+
+fname : tIDENTIFIER
+ | tCONSTANT
+ | tFID
+ | op
+ {
+ SET_LEX_STATE(EXPR_ENDFN);
+ $$ = $1;
+ }
+ | reswords
+ ;
fitem : fname
- {
- $$ = NEW_SYM(rb_id2str($1), &@$);
- /*% ripper: symbol_literal!($:1) %*/
- }
- | symbol
- ;
+ {
+ /*%%%*/
+ $$ = NEW_LIT(ID2SYM($1), &@$);
+ /*% %*/
+ /*% ripper: symbol_literal!($1) %*/
+ }
+ | symbol
+ ;
undef_list : fitem
- {
- $$ = NEW_UNDEF($1, &@$);
- /*% ripper: rb_ary_new3(1, $:1) %*/
- }
- | undef_list ',' {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem
- {
- nd_set_last_loc($1, @4.end_pos);
- rb_parser_ary_push_node(p, RNODE_UNDEF($1)->nd_undefs, $4);
- /*% ripper: rb_ary_push($:1, $:4) %*/
- }
- ;
-
-op : '|' { $$ = '|'; }
- | '^' { $$ = '^'; }
- | '&' { $$ = '&'; }
- | tCMP { $$ = tCMP; }
- | tEQ { $$ = tEQ; }
- | tEQQ { $$ = tEQQ; }
- | tMATCH { $$ = tMATCH; }
- | tNMATCH { $$ = tNMATCH; }
- | '>' { $$ = '>'; }
- | tGEQ { $$ = tGEQ; }
- | '<' { $$ = '<'; }
- | tLEQ { $$ = tLEQ; }
- | tNEQ { $$ = tNEQ; }
- | tLSHFT { $$ = tLSHFT; }
- | tRSHFT { $$ = tRSHFT; }
- | '+' { $$ = '+'; }
- | '-' { $$ = '-'; }
- | '*' { $$ = '*'; }
- | tSTAR { $$ = '*'; }
- | '/' { $$ = '/'; }
- | '%' { $$ = '%'; }
- | tPOW { $$ = tPOW; }
- | tDSTAR { $$ = tDSTAR; }
- | '!' { $$ = '!'; }
- | '~' { $$ = '~'; }
- | tUPLUS { $$ = tUPLUS; }
- | tUMINUS { $$ = tUMINUS; }
- | tAREF { $$ = tAREF; }
- | tASET { $$ = tASET; }
- | '`' { $$ = '`'; }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_UNDEF($1, &@$);
+ /*% %*/
+ /*% ripper: rb_ary_new3(1, get_value($1)) %*/
+ }
+ | undef_list ',' {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem
+ {
+ /*%%%*/
+ NODE *undef = NEW_UNDEF($4, &@4);
+ $$ = block_append(p, $1, undef);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($4)) %*/
+ }
+ ;
+
+op : '|' { ifndef_ripper($$ = '|'); }
+ | '^' { ifndef_ripper($$ = '^'); }
+ | '&' { ifndef_ripper($$ = '&'); }
+ | tCMP { ifndef_ripper($$ = tCMP); }
+ | tEQ { ifndef_ripper($$ = tEQ); }
+ | tEQQ { ifndef_ripper($$ = tEQQ); }
+ | tMATCH { ifndef_ripper($$ = tMATCH); }
+ | tNMATCH { ifndef_ripper($$ = tNMATCH); }
+ | '>' { ifndef_ripper($$ = '>'); }
+ | tGEQ { ifndef_ripper($$ = tGEQ); }
+ | '<' { ifndef_ripper($$ = '<'); }
+ | tLEQ { ifndef_ripper($$ = tLEQ); }
+ | tNEQ { ifndef_ripper($$ = tNEQ); }
+ | tLSHFT { ifndef_ripper($$ = tLSHFT); }
+ | tRSHFT { ifndef_ripper($$ = tRSHFT); }
+ | '+' { ifndef_ripper($$ = '+'); }
+ | '-' { ifndef_ripper($$ = '-'); }
+ | '*' { ifndef_ripper($$ = '*'); }
+ | tSTAR { ifndef_ripper($$ = '*'); }
+ | '/' { ifndef_ripper($$ = '/'); }
+ | '%' { ifndef_ripper($$ = '%'); }
+ | tPOW { ifndef_ripper($$ = tPOW); }
+ | tDSTAR { ifndef_ripper($$ = tDSTAR); }
+ | '!' { ifndef_ripper($$ = '!'); }
+ | '~' { ifndef_ripper($$ = '~'); }
+ | tUPLUS { ifndef_ripper($$ = tUPLUS); }
+ | tUMINUS { ifndef_ripper($$ = tUMINUS); }
+ | tAREF { ifndef_ripper($$ = tAREF); }
+ | tASET { ifndef_ripper($$ = tASET); }
+ | '`' { ifndef_ripper($$ = '`'); }
+ ;
reswords : keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__
- | keyword_BEGIN | keyword_END
- | keyword_alias | keyword_and | keyword_begin
- | keyword_break | keyword_case | keyword_class | keyword_def
- | keyword_defined | keyword_do | keyword_else | keyword_elsif
- | keyword_end | keyword_ensure | keyword_false
- | keyword_for | keyword_in | keyword_module | keyword_next
- | keyword_nil | keyword_not | keyword_or | keyword_redo
- | keyword_rescue | keyword_retry | keyword_return | keyword_self
- | keyword_super | keyword_then | keyword_true | keyword_undef
- | keyword_when | keyword_yield | keyword_if | keyword_unless
- | keyword_while | keyword_until
- ;
+ | keyword_BEGIN | keyword_END
+ | keyword_alias | keyword_and | keyword_begin
+ | keyword_break | keyword_case | keyword_class | keyword_def
+ | keyword_defined | keyword_do | keyword_else | keyword_elsif
+ | keyword_end | keyword_ensure | keyword_false
+ | keyword_for | keyword_in | keyword_module | keyword_next
+ | keyword_nil | keyword_not | keyword_or | keyword_redo
+ | keyword_rescue | keyword_retry | keyword_return | keyword_self
+ | keyword_super | keyword_then | keyword_true | keyword_undef
+ | keyword_when | keyword_yield | keyword_if | keyword_unless
+ | keyword_while | keyword_until
+ ;
arg : lhs '=' lex_ctxt arg_rhs
- {
- $$ = node_assign(p, $1, $4, $3, &@$);
- /*% ripper: assign!($:1, $:4) %*/
- }
- | var_lhs tOP_ASGN lex_ctxt arg_rhs
- {
- $$ = new_op_assign(p, $1, $2, $4, $3, &@$);
- /*% ripper: opassign!($:1, $:2, $:4) %*/
- }
- | primary_value '[' opt_call_args rbracket tOP_ASGN lex_ctxt arg_rhs
- {
- $$ = new_ary_op_assign(p, $1, $3, $5, $7, &@3, &@$, &NULL_LOC, &@2, &@4, &@5);
- /*% ripper: opassign!(aref_field!($:1, $:3), $:5, $:7) %*/
- }
- | primary_value call_op tIDENTIFIER tOP_ASGN lex_ctxt arg_rhs
- {
- $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$, &@2, &@3, &@4);
- /*% ripper: opassign!(field!($:1, $:2, $:3), $:4, $:6) %*/
- }
- | primary_value call_op tCONSTANT tOP_ASGN lex_ctxt arg_rhs
- {
- $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$, &@2, &@3, &@4);
- /*% ripper: opassign!(field!($:1, $:2, $:3), $:4, $:6) %*/
- }
- | primary_value tCOLON2 tIDENTIFIER tOP_ASGN lex_ctxt arg_rhs
- {
- $$ = new_attr_op_assign(p, $1, idCOLON2, $3, $4, $6, &@$, &@2, &@3, &@4);
- /*% ripper: opassign!(field!($:1, $:2, $:3), $:4, $:6) %*/
- }
- | primary_value tCOLON2 tCONSTANT tOP_ASGN lex_ctxt arg_rhs
- {
- YYLTYPE loc = code_loc_gen(&@1, &@3);
- $$ = new_const_op_assign(p, NEW_COLON2($1, $3, &loc), $4, $6, $5, &@$);
- /*% ripper: opassign!(const_path_field!($:1, $:3), $:4, $:6) %*/
- }
- | tCOLON3 tCONSTANT tOP_ASGN lex_ctxt arg_rhs
- {
- YYLTYPE loc = code_loc_gen(&@1, &@2);
- $$ = new_const_op_assign(p, NEW_COLON3($2, &loc), $3, $5, $4, &@$);
- /*% ripper: opassign!(top_const_field!($:2), $:3, $:5) %*/
- }
- | backref tOP_ASGN lex_ctxt arg_rhs
- {
- VALUE MAYBE_UNUSED(e) = rb_backref_error(p, $1);
- $$ = NEW_ERROR(&@$);
- /*% ripper[error]: assign_error!(?e, opassign!(var_field!($:1), $:2, $:4)) %*/
- }
- | arg tDOT2 arg
- {
- value_expr($1);
- value_expr($3);
- $$ = NEW_DOT2($1, $3, &@$);
- /*% ripper: dot2!($:1, $:3) %*/
- }
- | arg tDOT3 arg
- {
- value_expr($1);
- value_expr($3);
- $$ = NEW_DOT3($1, $3, &@$);
- /*% ripper: dot3!($:1, $:3) %*/
- }
- | arg tDOT2
- {
- value_expr($1);
- $$ = NEW_DOT2($1, new_nil_at(p, &@2.end_pos), &@$);
- /*% ripper: dot2!($:1, Qnil) %*/
- }
- | arg tDOT3
- {
- value_expr($1);
- $$ = NEW_DOT3($1, new_nil_at(p, &@2.end_pos), &@$);
- /*% ripper: dot3!($:1, Qnil) %*/
- }
- | tBDOT2 arg
- {
- value_expr($2);
- $$ = NEW_DOT2(new_nil_at(p, &@1.beg_pos), $2, &@$);
- /*% ripper: dot2!(Qnil, $:2) %*/
- }
- | tBDOT3 arg
- {
- value_expr($2);
- $$ = NEW_DOT3(new_nil_at(p, &@1.beg_pos), $2, &@$);
- /*% ripper: dot3!(Qnil, $:2) %*/
- }
- | arg '+' arg
- {
- $$ = call_bin_op(p, $1, '+', $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL('\'+\''), $:3) %*/
- }
- | arg '-' arg
- {
- $$ = call_bin_op(p, $1, '-', $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL('\'-\''), $:3) %*/
- }
- | arg '*' arg
- {
- $$ = call_bin_op(p, $1, '*', $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL('\'*\''), $:3) %*/
- }
- | arg '/' arg
- {
- $$ = call_bin_op(p, $1, '/', $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL('\'/\''), $:3) %*/
- }
- | arg '%' arg
- {
- $$ = call_bin_op(p, $1, '%', $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL('\'%\''), $:3) %*/
- }
- | arg tPOW arg
- {
- $$ = call_bin_op(p, $1, idPow, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idPow), $:3) %*/
- }
- | tUMINUS_NUM simple_numeric tPOW arg
- {
- $$ = call_uni_op(p, call_bin_op(p, $2, idPow, $4, &@2, &@$), idUMinus, &@1, &@$);
- /*% ripper: unary!(ID2VAL(idUMinus), binary!($:2, ID2VAL(idPow), $:4)) %*/
- }
- | tUPLUS arg
- {
- $$ = call_uni_op(p, $2, idUPlus, &@1, &@$);
- /*% ripper: unary!(ID2VAL(idUPlus), $:2) %*/
- }
- | tUMINUS arg
- {
- $$ = call_uni_op(p, $2, idUMinus, &@1, &@$);
- /*% ripper: unary!(ID2VAL(idUMinus), $:2) %*/
- }
- | arg '|' arg
- {
- $$ = call_bin_op(p, $1, '|', $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL('\'|\''), $:3) %*/
- }
- | arg '^' arg
- {
- $$ = call_bin_op(p, $1, '^', $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL('\'^\''), $:3) %*/
- }
- | arg '&' arg
- {
- $$ = call_bin_op(p, $1, '&', $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL('\'&\''), $:3) %*/
- }
- | arg tCMP arg
- {
- $$ = call_bin_op(p, $1, idCmp, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idCmp), $:3) %*/
- }
- | rel_expr %prec tCMP
- | arg tEQ arg
- {
- $$ = call_bin_op(p, $1, idEq, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idEq), $:3) %*/
- }
- | arg tEQQ arg
- {
- $$ = call_bin_op(p, $1, idEqq, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idEqq), $:3) %*/
- }
- | arg tNEQ arg
- {
- $$ = call_bin_op(p, $1, idNeq, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idNeq), $:3) %*/
- }
- | arg tMATCH arg
- {
- $$ = match_op(p, $1, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idEqTilde), $:3) %*/
- }
- | arg tNMATCH arg
- {
- $$ = call_bin_op(p, $1, idNeqTilde, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idNeqTilde), $:3) %*/
- }
- | '!' arg
- {
- $$ = call_uni_op(p, method_cond(p, $2, &@2), '!', &@1, &@$);
- /*% ripper: unary!(ID2VAL('\'!\''), $:2) %*/
- }
- | '~' arg
- {
- $$ = call_uni_op(p, $2, '~', &@1, &@$);
- /*% ripper: unary!(ID2VAL('\'~\''), $:2) %*/
- }
- | arg tLSHFT arg
- {
- $$ = call_bin_op(p, $1, idLTLT, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idLTLT), $:3) %*/
- }
- | arg tRSHFT arg
- {
- $$ = call_bin_op(p, $1, idGTGT, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idGTGT), $:3) %*/
- }
- | arg tANDOP arg
- {
- $$ = logop(p, idANDOP, $1, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idANDOP), $:3) %*/
- }
- | arg tOROP arg
- {
- $$ = logop(p, idOROP, $1, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL(idOROP), $:3) %*/
- }
- | keyword_defined '\n'? begin_defined arg
- {
- p->ctxt.in_defined = $3.in_defined;
- $$ = new_defined(p, $4, &@$);
- /*% ripper: defined!($:4) %*/
- }
- | arg '?' arg '\n'? ':' arg
- {
- value_expr($1);
- $$ = new_if(p, $1, $3, $6, &@$);
- fixpos($$, $1);
- /*% ripper: ifop!($:1, $:3, $:6) %*/
- }
- | defn_head[head] f_opt_paren_args[args] '=' endless_arg[bodystmt]
- {
- endless_method_name(p, $head->nd_mid, &@head);
- restore_defun(p, $head);
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
- ($$ = $head->nd_def)->nd_loc = @$;
- RNODE_DEFN($$)->nd_defn = $bodystmt;
- /*% ripper: bodystmt!($:bodystmt, Qnil, Qnil, Qnil) %*/
- /*% ripper: def!($:head, $:args, $:$) %*/
- local_pop(p);
- }
- | defs_head[head] f_opt_paren_args[args] '=' endless_arg[bodystmt]
- {
- endless_method_name(p, $head->nd_mid, &@head);
- restore_defun(p, $head);
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
- ($$ = $head->nd_def)->nd_loc = @$;
- RNODE_DEFS($$)->nd_defn = $bodystmt;
- /*% ripper: bodystmt!($:bodystmt, Qnil, Qnil, Qnil) %*/
- /*% ripper: defs!(*$:head[0..2], $:args, $:$) %*/
- local_pop(p);
- }
- | primary
- {
- $$ = $1;
- }
- ;
-
-endless_arg : arg %prec modifier_rescue
- | endless_arg modifier_rescue after_rescue arg
- {
- p->ctxt.in_rescue = $3.in_rescue;
- $$ = rescued_expr(p, $1, $4, &@1, &@2, &@4);
- /*% ripper: rescue_mod!($:1, $:4) %*/
- }
- | keyword_not '\n'? endless_arg
- {
- $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
- /*% ripper: unary!(ID2VAL(idNOT), $:3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = node_assign(p, $1, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: assign!($1, $4) %*/
+ }
+ | var_lhs tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ $$ = new_op_assign(p, $1, $2, $4, $3, &@$);
+ /*% %*/
+ /*% ripper: opassign!($1, $2, $4) %*/
+ }
+ | primary_value '[' opt_call_args rbracket tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ $$ = new_ary_op_assign(p, $1, $3, $5, $7, &@3, &@$);
+ /*% %*/
+ /*% ripper: opassign!(aref_field!($1, escape_Qundef($3)), $5, $7) %*/
+ }
+ | primary_value call_op tIDENTIFIER tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$);
+ /*% %*/
+ /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
+ }
+ | primary_value call_op tCONSTANT tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ $$ = new_attr_op_assign(p, $1, $2, $3, $4, $6, &@$);
+ /*% %*/
+ /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
+ }
+ | primary_value tCOLON2 tIDENTIFIER tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ $$ = new_attr_op_assign(p, $1, ID2VAL(idCOLON2), $3, $4, $6, &@$);
+ /*% %*/
+ /*% ripper: opassign!(field!($1, $2, $3), $4, $6) %*/
+ }
+ | primary_value tCOLON2 tCONSTANT tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ YYLTYPE loc = code_loc_gen(&@1, &@3);
+ $$ = new_const_op_assign(p, NEW_COLON2($1, $3, &loc), $4, $6, $5, &@$);
+ /*% %*/
+ /*% ripper: opassign!(const_path_field!($1, $3), $4, $6) %*/
+ }
+ | tCOLON3 tCONSTANT tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ YYLTYPE loc = code_loc_gen(&@1, &@2);
+ $$ = new_const_op_assign(p, NEW_COLON3($2, &loc), $3, $5, $4, &@$);
+ /*% %*/
+ /*% ripper: opassign!(top_const_field!($2), $3, $5) %*/
+ }
+ | backref tOP_ASGN lex_ctxt arg_rhs
+ {
+ /*%%%*/
+ rb_backref_error(p, $1);
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper[error]: backref_error(p, RNODE($1), opassign!(var_field(p, $1), $2, $4)) %*/
+ }
+ | arg tDOT2 arg
+ {
+ /*%%%*/
+ value_expr($1);
+ value_expr($3);
+ $$ = NEW_DOT2($1, $3, &@$);
+ /*% %*/
+ /*% ripper: dot2!($1, $3) %*/
+ }
+ | arg tDOT3 arg
+ {
+ /*%%%*/
+ value_expr($1);
+ value_expr($3);
+ $$ = NEW_DOT3($1, $3, &@$);
+ /*% %*/
+ /*% ripper: dot3!($1, $3) %*/
+ }
+ | arg tDOT2
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = NEW_DOT2($1, new_nil_at(p, &@2.end_pos), &@$);
+ /*% %*/
+ /*% ripper: dot2!($1, Qnil) %*/
+ }
+ | arg tDOT3
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = NEW_DOT3($1, new_nil_at(p, &@2.end_pos), &@$);
+ /*% %*/
+ /*% ripper: dot3!($1, Qnil) %*/
+ }
+ | tBDOT2 arg
+ {
+ /*%%%*/
+ value_expr($2);
+ $$ = NEW_DOT2(new_nil_at(p, &@1.beg_pos), $2, &@$);
+ /*% %*/
+ /*% ripper: dot2!(Qnil, $2) %*/
+ }
+ | tBDOT3 arg
+ {
+ /*%%%*/
+ value_expr($2);
+ $$ = NEW_DOT3(new_nil_at(p, &@1.beg_pos), $2, &@$);
+ /*% %*/
+ /*% ripper: dot3!(Qnil, $2) %*/
+ }
+ | arg '+' arg
+ {
+ $$ = call_bin_op(p, $1, '+', $3, &@2, &@$);
+ }
+ | arg '-' arg
+ {
+ $$ = call_bin_op(p, $1, '-', $3, &@2, &@$);
+ }
+ | arg '*' arg
+ {
+ $$ = call_bin_op(p, $1, '*', $3, &@2, &@$);
+ }
+ | arg '/' arg
+ {
+ $$ = call_bin_op(p, $1, '/', $3, &@2, &@$);
+ }
+ | arg '%' arg
+ {
+ $$ = call_bin_op(p, $1, '%', $3, &@2, &@$);
+ }
+ | arg tPOW arg
+ {
+ $$ = call_bin_op(p, $1, idPow, $3, &@2, &@$);
+ }
+ | tUMINUS_NUM simple_numeric tPOW arg
+ {
+ $$ = call_uni_op(p, call_bin_op(p, $2, idPow, $4, &@2, &@$), idUMinus, &@1, &@$);
+ }
+ | tUPLUS arg
+ {
+ $$ = call_uni_op(p, $2, idUPlus, &@1, &@$);
+ }
+ | tUMINUS arg
+ {
+ $$ = call_uni_op(p, $2, idUMinus, &@1, &@$);
+ }
+ | arg '|' arg
+ {
+ $$ = call_bin_op(p, $1, '|', $3, &@2, &@$);
+ }
+ | arg '^' arg
+ {
+ $$ = call_bin_op(p, $1, '^', $3, &@2, &@$);
+ }
+ | arg '&' arg
+ {
+ $$ = call_bin_op(p, $1, '&', $3, &@2, &@$);
+ }
+ | arg tCMP arg
+ {
+ $$ = call_bin_op(p, $1, idCmp, $3, &@2, &@$);
+ }
+ | rel_expr %prec tCMP
+ | arg tEQ arg
+ {
+ $$ = call_bin_op(p, $1, idEq, $3, &@2, &@$);
+ }
+ | arg tEQQ arg
+ {
+ $$ = call_bin_op(p, $1, idEqq, $3, &@2, &@$);
+ }
+ | arg tNEQ arg
+ {
+ $$ = call_bin_op(p, $1, idNeq, $3, &@2, &@$);
+ }
+ | arg tMATCH arg
+ {
+ $$ = match_op(p, $1, $3, &@2, &@$);
+ }
+ | arg tNMATCH arg
+ {
+ $$ = call_bin_op(p, $1, idNeqTilde, $3, &@2, &@$);
+ }
+ | '!' arg
+ {
+ $$ = call_uni_op(p, method_cond(p, $2, &@2), '!', &@1, &@$);
+ }
+ | '~' arg
+ {
+ $$ = call_uni_op(p, $2, '~', &@1, &@$);
+ }
+ | arg tLSHFT arg
+ {
+ $$ = call_bin_op(p, $1, idLTLT, $3, &@2, &@$);
+ }
+ | arg tRSHFT arg
+ {
+ $$ = call_bin_op(p, $1, idGTGT, $3, &@2, &@$);
+ }
+ | arg tANDOP arg
+ {
+ $$ = logop(p, idANDOP, $1, $3, &@2, &@$);
+ }
+ | arg tOROP arg
+ {
+ $$ = logop(p, idOROP, $1, $3, &@2, &@$);
+ }
+ | keyword_defined opt_nl {p->ctxt.in_defined = 1;} arg
+ {
+ p->ctxt.in_defined = 0;
+ $$ = new_defined(p, $4, &@$);
+ }
+ | arg '?' arg opt_nl ':' arg
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = new_if(p, $1, $3, $6, &@$);
+ fixpos($$, $1);
+ /*% %*/
+ /*% ripper: ifop!($1, $3, $6) %*/
+ }
+ | defn_head f_opt_paren_args '=' arg
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*% %*/
+ /*% ripper[$4]: bodystmt!($4, Qnil, Qnil, Qnil) %*/
+ /*% ripper: def!(get_value($1), $2, $4) %*/
+ local_pop(p);
+ }
+ | defn_head f_opt_paren_args '=' arg modifier_rescue arg
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $4 = rescued_expr(p, $4, $6, &@4, &@5, &@6);
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*% %*/
+ /*% ripper[$4]: bodystmt!(rescue_mod!($4, $6), Qnil, Qnil, Qnil) %*/
+ /*% ripper: def!(get_value($1), $2, $4) %*/
+ local_pop(p);
+ }
+ | defs_head f_opt_paren_args '=' arg
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*%
+ $1 = get_value($1);
+ %*/
+ /*% ripper[$4]: bodystmt!($4, Qnil, Qnil, Qnil) %*/
+ /*% ripper: defs!(AREF($1, 0), AREF($1, 1), AREF($1, 2), $2, $4) %*/
+ local_pop(p);
+ }
+ | defs_head f_opt_paren_args '=' arg modifier_rescue arg
+ {
+ endless_method_name(p, $<node>1, &@1);
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $4 = rescued_expr(p, $4, $6, &@4, &@5, &@6);
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*%
+ $1 = get_value($1);
+ %*/
+ /*% ripper[$4]: bodystmt!(rescue_mod!($4, $6), Qnil, Qnil, Qnil) %*/
+ /*% ripper: defs!(AREF($1, 0), AREF($1, 1), AREF($1, 2), $2, $4) %*/
+ local_pop(p);
+ }
+ | primary
+ {
+ $$ = $1;
+ }
+ ;
relop : '>' {$$ = '>';}
- | '<' {$$ = '<';}
- | tGEQ {$$ = idGE;}
- | tLEQ {$$ = idLE;}
- ;
+ | '<' {$$ = '<';}
+ | tGEQ {$$ = idGE;}
+ | tLEQ {$$ = idLE;}
+ ;
rel_expr : arg relop arg %prec '>'
- {
- $$ = call_bin_op(p, $1, $2, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL($2), $:3) %*/
- }
- | rel_expr relop arg %prec '>'
- {
- rb_warning1("comparison '%s' after comparison", WARN_ID($2));
- $$ = call_bin_op(p, $1, $2, $3, &@2, &@$);
- /*% ripper: binary!($:1, ID2VAL($2), $:3) %*/
- }
- ;
+ {
+ $$ = call_bin_op(p, $1, $2, $3, &@2, &@$);
+ }
+ | rel_expr relop arg %prec '>'
+ {
+ rb_warning1("comparison '%s' after comparison", WARN_ID($2));
+ $$ = call_bin_op(p, $1, $2, $3, &@2, &@$);
+ }
+ ;
lex_ctxt : none
- {
- $$ = p->ctxt;
- }
- ;
-
-begin_defined : lex_ctxt
- {
- p->ctxt.in_defined = 1;
- $$ = $1;
- }
- ;
-
-after_rescue : lex_ctxt
- {
- p->ctxt.in_rescue = after_rescue;
- $$ = $1;
- }
- ;
+ {
+ $$ = p->ctxt;
+ }
+ ;
arg_value : arg
- {
- value_expr($1);
- $$ = $1;
- }
- ;
+ {
+ value_expr($1);
+ $$ = $1;
+ }
+ ;
aref_args : none
- | args trailer
- {
- $$ = $1;
- }
- | args ',' assocs trailer
- {
- $$ = $3 ? arg_append(p, $1, new_hash(p, $3, &@3), &@$) : $1;
- /*% ripper: args_add!($:1, bare_assoc_hash!($:3)) %*/
- }
- | assocs trailer
- {
- $$ = $1 ? NEW_LIST(new_hash(p, $1, &@1), &@$) : 0;
- /*% ripper: args_add!(args_new!, bare_assoc_hash!($:1)) %*/
- }
- ;
+ | args trailer
+ {
+ $$ = $1;
+ }
+ | args ',' assocs trailer
+ {
+ /*%%%*/
+ $$ = $3 ? arg_append(p, $1, new_hash(p, $3, &@3), &@$) : $1;
+ /*% %*/
+ /*% ripper: args_add!($1, bare_assoc_hash!($3)) %*/
+ }
+ | assocs trailer
+ {
+ /*%%%*/
+ $$ = $1 ? NEW_LIST(new_hash(p, $1, &@1), &@$) : 0;
+ /*% %*/
+ /*% ripper: args_add!(args_new!, bare_assoc_hash!($1)) %*/
+ }
+ ;
arg_rhs : arg %prec tOP_ASGN
- {
- value_expr($1);
- $$ = $1;
- }
- | arg modifier_rescue after_rescue arg
- {
- p->ctxt.in_rescue = $3.in_rescue;
- value_expr($1);
- $$ = rescued_expr(p, $1, $4, &@1, &@2, &@4);
- /*% ripper: rescue_mod!($:1, $:4) %*/
- }
- ;
+ {
+ value_expr($1);
+ $$ = $1;
+ }
+ | arg modifier_rescue arg
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = rescued_expr(p, $1, $3, &@1, &@2, &@3);
+ /*% %*/
+ /*% ripper: rescue_mod!($1, $3) %*/
+ }
+ ;
paren_args : '(' opt_call_args rparen
- {
- $$ = $2;
- /*% ripper: arg_paren!($:2) %*/
- }
- | '(' args ',' args_forward rparen
- {
- if (!check_forwarding_args(p)) {
- $$ = 0;
- }
- else {
- $$ = new_args_forward_call(p, $2, &@4, &@$);
- /*% ripper: arg_paren!(args_add!($:2, $:4)) %*/
- }
- }
- | '(' args_forward rparen
- {
- if (!check_forwarding_args(p)) {
- $$ = 0;
- }
- else {
- $$ = new_args_forward_call(p, 0, &@2, &@$);
- /*% ripper: arg_paren!($:2) %*/
- }
- }
- ;
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: arg_paren!(escape_Qundef($2)) %*/
+ }
+ | '(' args ',' args_forward rparen
+ {
+ if (!check_forwarding_args(p)) {
+ $$ = Qnone;
+ }
+ else {
+ /*%%%*/
+ $$ = new_args_forward_call(p, $2, &@4, &@$);
+ /*% %*/
+ /*% ripper: arg_paren!(args_add!($2, $4)) %*/
+ }
+ }
+ | '(' args_forward rparen
+ {
+ if (!check_forwarding_args(p)) {
+ $$ = Qnone;
+ }
+ else {
+ /*%%%*/
+ $$ = new_args_forward_call(p, 0, &@2, &@$);
+ /*% %*/
+ /*% ripper: arg_paren!($2) %*/
+ }
+ }
+ ;
opt_paren_args : none
- | paren_args
- {
- $$ = $1 ? $1 : NODE_SPECIAL_EMPTY_ARGS;
- }
- ;
+ | paren_args
+ ;
opt_call_args : none
- | call_args
- | args ','
- {
- $$ = $1;
- }
- | args ',' assocs ','
- {
- $$ = $3 ? arg_append(p, $1, new_hash(p, $3, &@3), &@$) : $1;
- /*% ripper: args_add!($:1, bare_assoc_hash!($:3)) %*/
- }
- | assocs ','
- {
- $$ = $1 ? NEW_LIST(new_hash(p, $1, &@1), &@1) : 0;
- /*% ripper: args_add!(args_new!, bare_assoc_hash!($:1)) %*/
- }
- ;
+ | call_args
+ | args ','
+ {
+ $$ = $1;
+ }
+ | args ',' assocs ','
+ {
+ /*%%%*/
+ $$ = $3 ? arg_append(p, $1, new_hash(p, $3, &@3), &@$) : $1;
+ /*% %*/
+ /*% ripper: args_add!($1, bare_assoc_hash!($3)) %*/
+ }
+ | assocs ','
+ {
+ /*%%%*/
+ $$ = $1 ? NEW_LIST(new_hash(p, $1, &@1), &@1) : 0;
+ /*% %*/
+ /*% ripper: args_add!(args_new!, bare_assoc_hash!($1)) %*/
+ }
+ ;
call_args : command
- {
- value_expr($1);
- $$ = NEW_LIST($1, &@$);
- /*% ripper: args_add!(args_new!, $:1) %*/
- }
- | args opt_block_arg
- {
- $$ = arg_blk_pass($1, $2);
- /*% ripper: args_add_block!($:1, $:2) %*/
- }
- | assocs opt_block_arg
- {
- $$ = $1 ? NEW_LIST(new_hash(p, $1, &@1), &@1) : 0;
- $$ = arg_blk_pass($$, $2);
- /*% ripper: args_add_block!(args_add!(args_new!, bare_assoc_hash!($:1)), $:2) %*/
- }
- | args ',' assocs opt_block_arg
- {
- $$ = $3 ? arg_append(p, $1, new_hash(p, $3, &@3), &@$) : $1;
- $$ = arg_blk_pass($$, $4);
- /*% ripper: args_add_block!(args_add!($:1, bare_assoc_hash!($:3)), $:4) %*/
- }
- | block_arg
- /*% ripper: args_add_block!(args_new!, $:1) %*/
- ;
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: args_add!(args_new!, $1) %*/
+ }
+ | args opt_block_arg
+ {
+ /*%%%*/
+ $$ = arg_blk_pass($1, $2);
+ /*% %*/
+ /*% ripper: args_add_block!($1, $2) %*/
+ }
+ | assocs opt_block_arg
+ {
+ /*%%%*/
+ $$ = $1 ? NEW_LIST(new_hash(p, $1, &@1), &@1) : 0;
+ $$ = arg_blk_pass($$, $2);
+ /*% %*/
+ /*% ripper: args_add_block!(args_add!(args_new!, bare_assoc_hash!($1)), $2) %*/
+ }
+ | args ',' assocs opt_block_arg
+ {
+ /*%%%*/
+ $$ = $3 ? arg_append(p, $1, new_hash(p, $3, &@3), &@$) : $1;
+ $$ = arg_blk_pass($$, $4);
+ /*% %*/
+ /*% ripper: args_add_block!(args_add!($1, bare_assoc_hash!($3)), $4) %*/
+ }
+ | block_arg
+ /*% ripper[brace]: args_add_block!(args_new!, $1) %*/
+ ;
command_args : {
- /* If call_args starts with a open paren '(' or '[',
- * look-ahead reading of the letters calls CMDARG_PUSH(0),
- * but the push must be done after CMDARG_PUSH(1).
- * So this code makes them consistent by first cancelling
- * the premature CMDARG_PUSH(0), doing CMDARG_PUSH(1),
- * and finally redoing CMDARG_PUSH(0).
- */
- int lookahead = 0;
- switch (yychar) {
- case '(': case tLPAREN: case tLPAREN_ARG: case '[': case tLBRACK:
- lookahead = 1;
- }
- if (lookahead) CMDARG_POP();
- CMDARG_PUSH(1);
- if (lookahead) CMDARG_PUSH(0);
- }
- call_args
- {
- /* call_args can be followed by tLBRACE_ARG (that does CMDARG_PUSH(0) in the lexer)
- * but the push must be done after CMDARG_POP() in the parser.
- * So this code does CMDARG_POP() to pop 0 pushed by tLBRACE_ARG,
- * CMDARG_POP() to pop 1 pushed by command_args,
- * and CMDARG_PUSH(0) to restore back the flag set by tLBRACE_ARG.
- */
- int lookahead = 0;
- switch (yychar) {
- case tLBRACE_ARG:
- lookahead = 1;
- }
- if (lookahead) CMDARG_POP();
- CMDARG_POP();
- if (lookahead) CMDARG_PUSH(0);
- $$ = $2;
- /*% ripper: $:2 %*/
- }
- ;
+ /* If call_args starts with a open paren '(' or '[',
+ * look-ahead reading of the letters calls CMDARG_PUSH(0),
+ * but the push must be done after CMDARG_PUSH(1).
+ * So this code makes them consistent by first cancelling
+ * the premature CMDARG_PUSH(0), doing CMDARG_PUSH(1),
+ * and finally redoing CMDARG_PUSH(0).
+ */
+ int lookahead = 0;
+ switch (yychar) {
+ case '(': case tLPAREN: case tLPAREN_ARG: case '[': case tLBRACK:
+ lookahead = 1;
+ }
+ if (lookahead) CMDARG_POP();
+ CMDARG_PUSH(1);
+ if (lookahead) CMDARG_PUSH(0);
+ }
+ call_args
+ {
+ /* call_args can be followed by tLBRACE_ARG (that does CMDARG_PUSH(0) in the lexer)
+ * but the push must be done after CMDARG_POP() in the parser.
+ * So this code does CMDARG_POP() to pop 0 pushed by tLBRACE_ARG,
+ * CMDARG_POP() to pop 1 pushed by command_args,
+ * and CMDARG_PUSH(0) to restore back the flag set by tLBRACE_ARG.
+ */
+ int lookahead = 0;
+ switch (yychar) {
+ case tLBRACE_ARG:
+ lookahead = 1;
+ }
+ if (lookahead) CMDARG_POP();
+ CMDARG_POP();
+ if (lookahead) CMDARG_PUSH(0);
+ $$ = $2;
+ }
+ ;
block_arg : tAMPER arg_value
- {
- $$ = NEW_BLOCK_PASS($2, &@$, &@1);
- /*% ripper: $:2 %*/
- }
+ {
+ /*%%%*/
+ $$ = NEW_BLOCK_PASS($2, &@$);
+ /*% %*/
+ /*% ripper: $2 %*/
+ }
| tAMPER
{
- forwarding_arg_check(p, idFWD_BLOCK, idFWD_ALL, "block");
- $$ = NEW_BLOCK_PASS(NEW_LVAR(idFWD_BLOCK, &@1), &@$, &@1);
+ if (!local_id(p, idFWD_BLOCK)) {
+ compile_error(p, "no anonymous block parameter");
+ }
+ /*%%%*/
+ $$ = NEW_BLOCK_PASS(NEW_LVAR(idFWD_BLOCK, &@1), &@$);
+ /*% %*/
/*% ripper: Qnil %*/
}
- ;
+ ;
opt_block_arg : ',' block_arg
- {
- $$ = $2;
- /*% ripper: $:2 %*/
- }
- | none
- {
- $$ = 0;
- /*% ripper: Qfalse %*/
- }
- ;
+ {
+ $$ = $2;
+ }
+ | none
+ {
+ $$ = 0;
+ }
+ ;
/* value */
args : arg_value
- {
- $$ = NEW_LIST($arg_value, &@$);
- /*% ripper: args_add!(args_new!, $:arg_value) %*/
- }
- | arg_splat
- {
- $$ = $arg_splat;
- /*% ripper: args_add_star!(args_new!, $:arg_splat) %*/
- }
- | args[non_last_args] ',' arg_value
- {
- $$ = last_arg_append(p, $non_last_args, $arg_value, &@$);
- /*% ripper: args_add!($:non_last_args, $:arg_value) %*/
- }
- | args[non_last_args] ',' arg_splat
- {
- $$ = rest_arg_append(p, $non_last_args, RNODE_SPLAT($arg_splat)->nd_head, &@$);
- /*% ripper: args_add_star!($:non_last_args, $:arg_splat) %*/
- }
- ;
-
-/* value */
-arg_splat : tSTAR arg_value
- {
- $$ = NEW_SPLAT($arg_value, &@$, &@tSTAR);
- /*% ripper: $:arg_value %*/
- }
- | tSTAR /* none */
- {
- forwarding_arg_check(p, idFWD_REST, idFWD_ALL, "rest");
- $$ = NEW_SPLAT(NEW_LVAR(idFWD_REST, &@tSTAR), &@$, &@tSTAR);
- /*% ripper: Qnil %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: args_add!(args_new!, $1) %*/
+ }
+ | tSTAR arg_value
+ {
+ /*%%%*/
+ $$ = NEW_SPLAT($2, &@$);
+ /*% %*/
+ /*% ripper: args_add_star!(args_new!, $2) %*/
+ }
+ | tSTAR
+ {
+ if (!local_id(p, idFWD_REST) ||
+ local_id(p, idFWD_ALL)) {
+ compile_error(p, "no anonymous rest parameter");
+ }
+ /*%%%*/
+ $$ = NEW_SPLAT(NEW_LVAR(idFWD_REST, &@1), &@$);
+ /*% %*/
+ /*% ripper: args_add_star!(args_new!, Qnil) %*/
+ }
+ | args ',' arg_value
+ {
+ /*%%%*/
+ $$ = last_arg_append(p, $1, $3, &@$);
+ /*% %*/
+ /*% ripper: args_add!($1, $3) %*/
+ }
+ | args ',' tSTAR arg_value
+ {
+ /*%%%*/
+ $$ = rest_arg_append(p, $1, $4, &@$);
+ /*% %*/
+ /*% ripper: args_add_star!($1, $4) %*/
+ }
+ | args ',' tSTAR
+ {
+ if (!local_id(p, idFWD_REST) ||
+ local_id(p, idFWD_ALL)) {
+ compile_error(p, "no anonymous rest parameter");
+ }
+ /*%%%*/
+ $$ = rest_arg_append(p, $1, NEW_LVAR(idFWD_REST, &@3), &@$);
+ /*% %*/
+ /*% ripper: args_add_star!($1, Qnil) %*/
+ }
+ ;
/* value */
mrhs_arg : mrhs
- | arg_value
- ;
+ | arg_value
+ ;
/* value */
mrhs : args ',' arg_value
- {
- $$ = last_arg_append(p, $args, $arg_value, &@$);
- /*% ripper: mrhs_add!(mrhs_new_from_args!($:args), $:arg_value) %*/
- }
- | args ',' tSTAR arg_value
- {
- $$ = rest_arg_append(p, $args, $arg_value, &@$);
- /*% ripper: mrhs_add_star!(mrhs_new_from_args!($:args), $:arg_value) %*/
- }
- | tSTAR arg_value
- {
- $$ = NEW_SPLAT($arg_value, &@$, &@tSTAR);
- /*% ripper: mrhs_add_star!(mrhs_new!, $:arg_value) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = last_arg_append(p, $1, $3, &@$);
+ /*% %*/
+ /*% ripper: mrhs_add!(mrhs_new_from_args!($1), $3) %*/
+ }
+ | args ',' tSTAR arg_value
+ {
+ /*%%%*/
+ $$ = rest_arg_append(p, $1, $4, &@$);
+ /*% %*/
+ /*% ripper: mrhs_add_star!(mrhs_new_from_args!($1), $4) %*/
+ }
+ | tSTAR arg_value
+ {
+ /*%%%*/
+ $$ = NEW_SPLAT($2, &@$);
+ /*% %*/
+ /*% ripper: mrhs_add_star!(mrhs_new!, $2) %*/
+ }
+ ;
primary : literal
- | strings
- | xstring
- | regexp
- | words
- | qwords
- | symbols
- | qsymbols
- | var_ref
- | backref
- | tFID
- {
- $$ = (NODE *)NEW_FCALL($1, 0, &@$);
- /*% ripper: method_add_arg!(fcall!($:1), args_new!) %*/
- }
- | k_begin
- {
- CMDARG_PUSH(0);
- }
- bodystmt
- k_end
- {
- CMDARG_POP();
- set_line_body($3, @1.end_pos.lineno);
- $$ = NEW_BEGIN($3, &@$);
- nd_set_line($$, @1.end_pos.lineno);
- /*% ripper: begin!($:3) %*/
- }
- | tLPAREN_ARG compstmt {SET_LEX_STATE(EXPR_ENDARG);} ')'
- {
- if (nd_type_p($2, NODE_SELF)) RNODE_SELF($2)->nd_state = 0;
- $$ = $2;
- /*% ripper: paren!($:2) %*/
- }
- | tLPAREN compstmt ')'
- {
- if (nd_type_p($2, NODE_SELF)) RNODE_SELF($2)->nd_state = 0;
- $$ = NEW_BLOCK($2, &@$);
- /*% ripper: paren!($:2) %*/
- }
- | primary_value tCOLON2 tCONSTANT
- {
- $$ = NEW_COLON2($1, $3, &@$);
- /*% ripper: const_path_ref!($:1, $:3) %*/
- }
- | tCOLON3 tCONSTANT
- {
- $$ = NEW_COLON3($2, &@$);
- /*% ripper: top_const_ref!($:2) %*/
- }
- | tLBRACK aref_args ']'
- {
- $$ = make_list($2, &@$);
- /*% ripper: array!($:2) %*/
- }
- | tLBRACE assoc_list '}'
- {
- $$ = new_hash(p, $2, &@$);
- RNODE_HASH($$)->nd_brace = TRUE;
- /*% ripper: hash!($:2) %*/
- }
- | k_return
- {
- $$ = NEW_RETURN(0, &@$, &@1);
- /*% ripper: return0! %*/
- }
- | k_yield '(' call_args rparen
- {
- $$ = new_yield(p, $3, &@$);
- /*% ripper: yield!(paren!($:3)) %*/
- }
- | k_yield '(' rparen
- {
- $$ = NEW_YIELD(0, &@$);
- /*% ripper: yield!(paren!(args_new!)) %*/
- }
- | k_yield
- {
- $$ = NEW_YIELD(0, &@$);
- /*% ripper: yield0! %*/
- }
- | keyword_defined '\n'? '(' begin_defined expr rparen
- {
- p->ctxt.in_defined = $4.in_defined;
- $$ = new_defined(p, $5, &@$);
- /*% ripper: defined!($:5) %*/
- }
- | keyword_not '(' expr rparen
- {
- $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
- /*% ripper: unary!(ID2VAL(idNOT), $:3) %*/
- }
- | keyword_not '(' rparen
- {
- $$ = call_uni_op(p, method_cond(p, new_nil(&@2), &@2), METHOD_NOT, &@1, &@$);
- /*% ripper: unary!(ID2VAL(idNOT), Qnil) %*/
- }
- | fcall brace_block
- {
- $$ = method_add_block(p, (NODE *)$1, $2, &@$);
- /*% ripper: method_add_block!(method_add_arg!(fcall!($:1), args_new!), $:2) %*/
- }
- | method_call
- | method_call brace_block
- {
- block_dup_check(p, get_nd_args(p, $1), $2);
- $$ = method_add_block(p, $1, $2, &@$);
- /*% ripper: method_add_block!($:1, $:2) %*/
- }
- | lambda
- | k_if expr_value then
- compstmt
- if_tail
- k_end
- {
- $$ = new_if(p, $2, $4, $5, &@$);
- fixpos($$, $2);
- /*% ripper: if!($:2, $:4, $:5) %*/
- }
- | k_unless expr_value then
- compstmt
- opt_else
- k_end
- {
- $$ = new_unless(p, $2, $4, $5, &@$, &@1, &@3, &@6);
- fixpos($$, $2);
- /*% ripper: unless!($:2, $:4, $:5) %*/
- }
- | k_while expr_value_do
- compstmt
- k_end
- {
- restore_block_exit(p, $1);
- $$ = NEW_WHILE(cond(p, $2, &@2), $3, 1, &@$, &@1, &@4);
- fixpos($$, $2);
- /*% ripper: while!($:2, $:3) %*/
- }
- | k_until expr_value_do
- compstmt
- k_end
- {
- restore_block_exit(p, $1);
- $$ = NEW_UNTIL(cond(p, $2, &@2), $3, 1, &@$, &@1, &@4);
- fixpos($$, $2);
- /*% ripper: until!($:2, $:3) %*/
- }
- | k_case expr_value terms?
- {
- $$ = p->case_labels;
- p->case_labels = CHECK_LITERAL_WHEN;
- }<labels>
- case_body
- k_end
- {
- if (CASE_LABELS_ENABLED_P(p->case_labels)) st_free_table(p->case_labels);
- p->case_labels = $4;
- $$ = NEW_CASE($2, $5, &@$, &@1, &@6);
- fixpos($$, $2);
- /*% ripper: case!($:2, $:5) %*/
- }
- | k_case terms?
- {
- $$ = p->case_labels;
- p->case_labels = 0;
- }<labels>
- case_body
- k_end
- {
- if (p->case_labels) st_free_table(p->case_labels);
- p->case_labels = $3;
- $$ = NEW_CASE2($4, &@$, &@1, &@5);
- /*% ripper: case!(Qnil, $:4) %*/
- }
- | k_case expr_value terms?
- p_case_body
- k_end
- {
- $$ = NEW_CASE3($2, $4, &@$, &@1, &@5);
- /*% ripper: case!($:2, $:4) %*/
- }
- | k_for for_var keyword_in expr_value_do
- compstmt
- k_end
- {
- restore_block_exit(p, $1);
- /*
- * for a, b, c in e
- * #=>
- * e.each{|*x| a, b, c = x}
- *
- * for a in e
- * #=>
- * e.each{|x| a, = x}
- */
- ID id = internal_id(p);
- rb_node_args_aux_t *m = NEW_ARGS_AUX(0, 0, &NULL_LOC);
- rb_node_args_t *args;
- NODE *scope, *internal_var = NEW_DVAR(id, &@2);
+ | strings
+ | xstring
+ | regexp
+ | words
+ | qwords
+ | symbols
+ | qsymbols
+ | var_ref
+ | backref
+ | tFID
+ {
+ /*%%%*/
+ $$ = NEW_FCALL($1, 0, &@$);
+ /*% %*/
+ /*% ripper: method_add_arg!(fcall!($1), args_new!) %*/
+ }
+ | k_begin
+ {
+ CMDARG_PUSH(0);
+ }
+ bodystmt
+ k_end
+ {
+ CMDARG_POP();
+ /*%%%*/
+ set_line_body($3, @1.end_pos.lineno);
+ $$ = NEW_BEGIN($3, &@$);
+ nd_set_line($$, @1.end_pos.lineno);
+ /*% %*/
+ /*% ripper: begin!($3) %*/
+ }
+ | tLPAREN_ARG {SET_LEX_STATE(EXPR_ENDARG);} rparen
+ {
+ /*%%%*/
+ $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: paren!(0) %*/
+ }
+ | tLPAREN_ARG stmt {SET_LEX_STATE(EXPR_ENDARG);} rparen
+ {
+ /*%%%*/
+ if (nd_type_p($2, NODE_SELF)) $2->nd_state = 0;
+ $$ = $2;
+ /*% %*/
+ /*% ripper: paren!($2) %*/
+ }
+ | tLPAREN compstmt ')'
+ {
+ /*%%%*/
+ if (nd_type_p($2, NODE_SELF)) $2->nd_state = 0;
+ $$ = $2;
+ /*% %*/
+ /*% ripper: paren!($2) %*/
+ }
+ | primary_value tCOLON2 tCONSTANT
+ {
+ /*%%%*/
+ $$ = NEW_COLON2($1, $3, &@$);
+ /*% %*/
+ /*% ripper: const_path_ref!($1, $3) %*/
+ }
+ | tCOLON3 tCONSTANT
+ {
+ /*%%%*/
+ $$ = NEW_COLON3($2, &@$);
+ /*% %*/
+ /*% ripper: top_const_ref!($2) %*/
+ }
+ | tLBRACK aref_args ']'
+ {
+ /*%%%*/
+ $$ = make_list($2, &@$);
+ /*% %*/
+ /*% ripper: array!(escape_Qundef($2)) %*/
+ }
+ | tLBRACE assoc_list '}'
+ {
+ /*%%%*/
+ $$ = new_hash(p, $2, &@$);
+ $$->nd_brace = TRUE;
+ /*% %*/
+ /*% ripper: hash!(escape_Qundef($2)) %*/
+ }
+ | k_return
+ {
+ /*%%%*/
+ $$ = NEW_RETURN(0, &@$);
+ /*% %*/
+ /*% ripper: return0! %*/
+ }
+ | keyword_yield '(' call_args rparen
+ {
+ /*%%%*/
+ $$ = new_yield(p, $3, &@$);
+ /*% %*/
+ /*% ripper: yield!(paren!($3)) %*/
+ }
+ | keyword_yield '(' rparen
+ {
+ /*%%%*/
+ $$ = NEW_YIELD(0, &@$);
+ /*% %*/
+ /*% ripper: yield!(paren!(args_new!)) %*/
+ }
+ | keyword_yield
+ {
+ /*%%%*/
+ $$ = NEW_YIELD(0, &@$);
+ /*% %*/
+ /*% ripper: yield0! %*/
+ }
+ | keyword_defined opt_nl '(' {p->ctxt.in_defined = 1;} expr rparen
+ {
+ p->ctxt.in_defined = 0;
+ $$ = new_defined(p, $5, &@$);
+ }
+ | keyword_not '(' expr rparen
+ {
+ $$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
+ }
+ | keyword_not '(' rparen
+ {
+ $$ = call_uni_op(p, method_cond(p, new_nil(&@2), &@2), METHOD_NOT, &@1, &@$);
+ }
+ | fcall brace_block
+ {
+ /*%%%*/
+ $$ = method_add_block(p, $1, $2, &@$);
+ /*% %*/
+ /*% ripper: method_add_block!(method_add_arg!(fcall!($1), args_new!), $2) %*/
+ }
+ | method_call
+ | method_call brace_block
+ {
+ /*%%%*/
+ block_dup_check(p, $1->nd_args, $2);
+ $$ = method_add_block(p, $1, $2, &@$);
+ /*% %*/
+ /*% ripper: method_add_block!($1, $2) %*/
+ }
+ | lambda
+ | k_if expr_value then
+ compstmt
+ if_tail
+ k_end
+ {
+ /*%%%*/
+ $$ = new_if(p, $2, $4, $5, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: if!($2, $4, escape_Qundef($5)) %*/
+ }
+ | k_unless expr_value then
+ compstmt
+ opt_else
+ k_end
+ {
+ /*%%%*/
+ $$ = new_unless(p, $2, $4, $5, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: unless!($2, $4, escape_Qundef($5)) %*/
+ }
+ | k_while expr_value_do
+ compstmt
+ k_end
+ {
+ /*%%%*/
+ $$ = NEW_WHILE(cond(p, $2, &@2), $3, 1, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: while!($2, $3) %*/
+ }
+ | k_until expr_value_do
+ compstmt
+ k_end
+ {
+ /*%%%*/
+ $$ = NEW_UNTIL(cond(p, $2, &@2), $3, 1, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: until!($2, $3) %*/
+ }
+ | k_case expr_value opt_terms
+ {
+ $<val>$ = p->case_labels;
+ p->case_labels = Qnil;
+ }
+ case_body
+ k_end
+ {
+ if (RTEST(p->case_labels)) rb_hash_clear(p->case_labels);
+ p->case_labels = $<val>4;
+ /*%%%*/
+ $$ = NEW_CASE($2, $5, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: case!($2, $5) %*/
+ }
+ | k_case opt_terms
+ {
+ $<val>$ = p->case_labels;
+ p->case_labels = 0;
+ }
+ case_body
+ k_end
+ {
+ if (RTEST(p->case_labels)) rb_hash_clear(p->case_labels);
+ p->case_labels = $<val>3;
+ /*%%%*/
+ $$ = NEW_CASE2($4, &@$);
+ /*% %*/
+ /*% ripper: case!(Qnil, $4) %*/
+ }
+ | k_case expr_value opt_terms
+ p_case_body
+ k_end
+ {
+ /*%%%*/
+ $$ = NEW_CASE3($2, $4, &@$);
+ /*% %*/
+ /*% ripper: case!($2, $4) %*/
+ }
+ | k_for for_var keyword_in expr_value_do
+ compstmt
+ k_end
+ {
+ /*%%%*/
+ /*
+ * for a, b, c in e
+ * #=>
+ * e.each{|*x| a, b, c = x}
+ *
+ * for a in e
+ * #=>
+ * e.each{|x| a, = x}
+ */
+ ID id = internal_id(p);
+ NODE *m = NEW_ARGS_AUX(0, 0, &NULL_LOC);
+ NODE *args, *scope, *internal_var = NEW_DVAR(id, &@2);
rb_ast_id_table_t *tbl = rb_ast_new_local_table(p->ast, 1);
- tbl->ids[0] = id; /* internal id */
-
- switch (nd_type($2)) {
- case NODE_LASGN:
- case NODE_DASGN: /* e.each {|internal_var| a = internal_var; ... } */
- set_nd_value(p, $2, internal_var);
- id = 0;
- m->nd_plen = 1;
- m->nd_next = $2;
- break;
- case NODE_MASGN: /* e.each {|*internal_var| a, b, c = (internal_var.length == 1 && Array === (tmp = internal_var[0]) ? tmp : internal_var); ... } */
- m->nd_next = node_assign(p, $2, NEW_FOR_MASGN(internal_var, &@2), NO_LEX_CTXT, &@2);
- break;
- default: /* e.each {|*internal_var| @a, B, c[1], d.attr = internal_val; ... } */
- m->nd_next = node_assign(p, (NODE *)NEW_MASGN(NEW_LIST($2, &@2), 0, &@2), internal_var, NO_LEX_CTXT, &@2);
- }
- /* {|*internal_id| <m> = internal_id; ... } */
- args = new_args(p, m, 0, id, 0, new_args_tail(p, 0, 0, 0, &@2), &@2);
- scope = NEW_SCOPE2(tbl, args, $5, &@$);
- $$ = NEW_FOR($4, scope, &@$);
- fixpos($$, $2);
- /*% ripper: for!($:2, $:4, $:5) %*/
- }
- | k_class cpath superclass
- {
- begin_definition("class", &@k_class, &@cpath);
- }
- bodystmt
- k_end
- {
- $$ = NEW_CLASS($cpath, $bodystmt, $superclass, &@$);
- nd_set_line(RNODE_CLASS($$)->nd_body, @k_end.end_pos.lineno);
- set_line_body($bodystmt, @superclass.end_pos.lineno);
- nd_set_line($$, @superclass.end_pos.lineno);
- /*% ripper: class!($:cpath, $:superclass, $:bodystmt) %*/
- local_pop(p);
- p->ctxt.in_class = $k_class.in_class;
- p->ctxt.cant_return = $k_class.cant_return;
- p->ctxt.shareable_constant_value = $k_class.shareable_constant_value;
- }
- | k_class tLSHFT expr_value
- {
- begin_definition("", &@k_class, &@tLSHFT);
- }
- term
- bodystmt
- k_end
- {
- $$ = NEW_SCLASS($expr_value, $bodystmt, &@$);
- nd_set_line(RNODE_SCLASS($$)->nd_body, @k_end.end_pos.lineno);
- set_line_body($bodystmt, nd_line($expr_value));
- fixpos($$, $expr_value);
- /*% ripper: sclass!($:expr_value, $:bodystmt) %*/
- local_pop(p);
- p->ctxt.in_def = $k_class.in_def;
- p->ctxt.in_class = $k_class.in_class;
- p->ctxt.cant_return = $k_class.cant_return;
- p->ctxt.shareable_constant_value = $k_class.shareable_constant_value;
- }
- | k_module cpath
- {
- begin_definition("module", &@k_module, &@cpath);
- }
- bodystmt
- k_end
- {
- $$ = NEW_MODULE($cpath, $bodystmt, &@$);
- nd_set_line(RNODE_MODULE($$)->nd_body, @k_end.end_pos.lineno);
- set_line_body($bodystmt, @cpath.end_pos.lineno);
- nd_set_line($$, @cpath.end_pos.lineno);
- /*% ripper: module!($:cpath, $:bodystmt) %*/
- local_pop(p);
- p->ctxt.in_class = $k_module.in_class;
- p->ctxt.cant_return = $k_module.cant_return;
- p->ctxt.shareable_constant_value = $k_module.shareable_constant_value;
- }
- | defn_head[head]
- f_arglist[args]
- {
- push_end_expect_token_locations(p, &@head.beg_pos);
- }
- bodystmt
- k_end
- {
- restore_defun(p, $head);
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
- ($$ = $head->nd_def)->nd_loc = @$;
- RNODE_DEFN($$)->nd_defn = $bodystmt;
- /*% ripper: def!($:head, $:args, $:bodystmt) %*/
- local_pop(p);
- }
- | defs_head[head]
- f_arglist[args]
- {
- push_end_expect_token_locations(p, &@head.beg_pos);
- }
- bodystmt
- k_end
- {
- restore_defun(p, $head);
- $bodystmt = new_scope_body(p, $args, $bodystmt, &@$);
- ($$ = $head->nd_def)->nd_loc = @$;
- RNODE_DEFS($$)->nd_defn = $bodystmt;
- /*% ripper: defs!(*$:head[0..2], $:args, $:bodystmt) %*/
- local_pop(p);
- }
- | keyword_break
- {
- $$ = add_block_exit(p, NEW_BREAK(0, &@$, &@1));
- /*% ripper: break!(args_new!) %*/
- }
- | keyword_next
- {
- $$ = add_block_exit(p, NEW_NEXT(0, &@$, &@1));
- /*% ripper: next!(args_new!) %*/
- }
- | keyword_redo
- {
- $$ = add_block_exit(p, NEW_REDO(&@$, &@1));
- /*% ripper: redo! %*/
- }
- | keyword_retry
- {
- if (!p->ctxt.in_defined) {
- switch (p->ctxt.in_rescue) {
- case before_rescue: yyerror1(&@1, "Invalid retry without rescue"); break;
- case after_rescue: /* ok */ break;
- case after_else: yyerror1(&@1, "Invalid retry after else"); break;
- case after_ensure: yyerror1(&@1, "Invalid retry after ensure"); break;
- }
- }
- $$ = NEW_RETRY(&@$);
- /*% ripper: retry! %*/
- }
- ;
+ tbl->ids[0] = id; /* internal id */
+
+ switch (nd_type($2)) {
+ case NODE_LASGN:
+ case NODE_DASGN: /* e.each {|internal_var| a = internal_var; ... } */
+ $2->nd_value = internal_var;
+ id = 0;
+ m->nd_plen = 1;
+ m->nd_next = $2;
+ break;
+ case NODE_MASGN: /* e.each {|*internal_var| a, b, c = (internal_var.length == 1 && Array === (tmp = internal_var[0]) ? tmp : internal_var); ... } */
+ m->nd_next = node_assign(p, $2, NEW_FOR_MASGN(internal_var, &@2), NO_LEX_CTXT, &@2);
+ break;
+ default: /* e.each {|*internal_var| @a, B, c[1], d.attr = internal_val; ... } */
+ m->nd_next = node_assign(p, NEW_MASGN(NEW_LIST($2, &@2), 0, &@2), internal_var, NO_LEX_CTXT, &@2);
+ }
+ /* {|*internal_id| <m> = internal_id; ... } */
+ args = new_args(p, m, 0, id, 0, new_args_tail(p, 0, 0, 0, &@2), &@2);
+ scope = NEW_NODE(NODE_SCOPE, tbl, $5, args, &@$);
+ $$ = NEW_FOR($4, scope, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: for!($2, $4, $5) %*/
+ }
+ | k_class cpath superclass
+ {
+ if (p->ctxt.in_def) {
+ YYLTYPE loc = code_loc_gen(&@1, &@2);
+ yyerror1(&loc, "class definition in method body");
+ }
+ p->ctxt.in_class = 1;
+ local_push(p, 0);
+ }
+ bodystmt
+ k_end
+ {
+ /*%%%*/
+ $$ = NEW_CLASS($2, $5, $3, &@$);
+ nd_set_line($$->nd_body, @6.end_pos.lineno);
+ set_line_body($5, @3.end_pos.lineno);
+ nd_set_line($$, @3.end_pos.lineno);
+ /*% %*/
+ /*% ripper: class!($2, $3, $5) %*/
+ local_pop(p);
+ p->ctxt.in_class = $<ctxt>1.in_class;
+ p->ctxt.shareable_constant_value = $<ctxt>1.shareable_constant_value;
+ }
+ | k_class tLSHFT expr
+ {
+ p->ctxt.in_def = 0;
+ p->ctxt.in_class = 0;
+ local_push(p, 0);
+ }
+ term
+ bodystmt
+ k_end
+ {
+ /*%%%*/
+ $$ = NEW_SCLASS($3, $6, &@$);
+ nd_set_line($$->nd_body, @7.end_pos.lineno);
+ set_line_body($6, nd_line($3));
+ fixpos($$, $3);
+ /*% %*/
+ /*% ripper: sclass!($3, $6) %*/
+ local_pop(p);
+ p->ctxt.in_def = $<ctxt>1.in_def;
+ p->ctxt.in_class = $<ctxt>1.in_class;
+ p->ctxt.shareable_constant_value = $<ctxt>1.shareable_constant_value;
+ }
+ | k_module cpath
+ {
+ if (p->ctxt.in_def) {
+ YYLTYPE loc = code_loc_gen(&@1, &@2);
+ yyerror1(&loc, "module definition in method body");
+ }
+ p->ctxt.in_class = 1;
+ local_push(p, 0);
+ }
+ bodystmt
+ k_end
+ {
+ /*%%%*/
+ $$ = NEW_MODULE($2, $4, &@$);
+ nd_set_line($$->nd_body, @5.end_pos.lineno);
+ set_line_body($4, @2.end_pos.lineno);
+ nd_set_line($$, @2.end_pos.lineno);
+ /*% %*/
+ /*% ripper: module!($2, $4) %*/
+ local_pop(p);
+ p->ctxt.in_class = $<ctxt>1.in_class;
+ p->ctxt.shareable_constant_value = $<ctxt>1.shareable_constant_value;
+ }
+ | defn_head
+ f_arglist
+ {
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ bodystmt
+ k_end
+ {
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*% %*/
+ /*% ripper: def!(get_value($1), $2, $4) %*/
+ local_pop(p);
+ }
+ | defs_head
+ f_arglist
+ {
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ bodystmt
+ k_end
+ {
+ restore_defun(p, $<node>1->nd_defn);
+ /*%%%*/
+ $$ = set_defun_body(p, $1, $2, $4, &@$);
+ /*%
+ $1 = get_value($1);
+ %*/
+ /*% ripper: defs!(AREF($1, 0), AREF($1, 1), AREF($1, 2), $2, $4) %*/
+ local_pop(p);
+ }
+ | keyword_break
+ {
+ /*%%%*/
+ $$ = NEW_BREAK(0, &@$);
+ /*% %*/
+ /*% ripper: break!(args_new!) %*/
+ }
+ | keyword_next
+ {
+ /*%%%*/
+ $$ = NEW_NEXT(0, &@$);
+ /*% %*/
+ /*% ripper: next!(args_new!) %*/
+ }
+ | keyword_redo
+ {
+ /*%%%*/
+ $$ = NEW_REDO(&@$);
+ /*% %*/
+ /*% ripper: redo! %*/
+ }
+ | keyword_retry
+ {
+ /*%%%*/
+ $$ = NEW_RETRY(&@$);
+ /*% %*/
+ /*% ripper: retry! %*/
+ }
+ ;
primary_value : primary
- {
- value_expr($1);
- $$ = $1;
- }
- ;
+ {
+ value_expr($1);
+ $$ = $1;
+ }
+ ;
k_begin : keyword_begin
- {
- token_info_push(p, "begin", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
- }
- ;
+ {
+ token_info_push(p, "begin", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_if : keyword_if
- {
- WARN_EOL("if");
- token_info_push(p, "if", &@$);
- if (p->token_info && p->token_info->nonspc &&
- p->token_info->next && !strcmp(p->token_info->next->token, "else")) {
- const char *tok = p->lex.ptok - rb_strlen_lit("if");
- const char *beg = p->lex.pbeg + p->token_info->next->beg.column;
- beg += rb_strlen_lit("else");
- while (beg < tok && ISSPACE(*beg)) beg++;
- if (beg == tok) {
- p->token_info->nonspc = 0;
- }
- }
- push_end_expect_token_locations(p, &@1.beg_pos);
- }
- ;
+ {
+ WARN_EOL("if");
+ token_info_push(p, "if", &@$);
+ if (p->token_info && p->token_info->nonspc &&
+ p->token_info->next && !strcmp(p->token_info->next->token, "else")) {
+ const char *tok = p->lex.ptok - rb_strlen_lit("if");
+ const char *beg = p->lex.pbeg + p->token_info->next->beg.column;
+ beg += rb_strlen_lit("else");
+ while (beg < tok && ISSPACE(*beg)) beg++;
+ if (beg == tok) {
+ p->token_info->nonspc = 0;
+ }
+ }
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_unless : keyword_unless
- {
- token_info_push(p, "unless", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
- }
- ;
-
-k_while : keyword_while allow_exits
- {
- $$ = $allow_exits;
- token_info_push(p, "while", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
- }
- ;
-
-k_until : keyword_until allow_exits
- {
- $$ = $allow_exits;
- token_info_push(p, "until", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
- }
- ;
+ {
+ token_info_push(p, "unless", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
+
+k_while : keyword_while
+ {
+ token_info_push(p, "while", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
+
+k_until : keyword_until
+ {
+ token_info_push(p, "until", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_case : keyword_case
- {
- token_info_push(p, "case", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
- }
- ;
-
-k_for : keyword_for allow_exits
- {
- $$ = $allow_exits;
- token_info_push(p, "for", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
- }
- ;
+ {
+ token_info_push(p, "case", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
+
+k_for : keyword_for
+ {
+ token_info_push(p, "for", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_class : keyword_class
- {
- token_info_push(p, "class", &@$);
- $$ = p->ctxt;
- p->ctxt.in_rescue = before_rescue;
- push_end_expect_token_locations(p, &@1.beg_pos);
- }
- ;
+ {
+ token_info_push(p, "class", &@$);
+ $<ctxt>$ = p->ctxt;
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_module : keyword_module
- {
- token_info_push(p, "module", &@$);
- $$ = p->ctxt;
- p->ctxt.in_rescue = before_rescue;
- push_end_expect_token_locations(p, &@1.beg_pos);
- }
- ;
+ {
+ token_info_push(p, "module", &@$);
+ $<ctxt>$ = p->ctxt;
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_def : keyword_def
- {
- token_info_push(p, "def", &@$);
- $$ = NEW_DEF_TEMP(&@$);
- p->ctxt.in_argdef = 1;
- }
- ;
+ {
+ token_info_push(p, "def", &@$);
+ p->ctxt.in_argdef = 1;
+ }
+ ;
k_do : keyword_do
- {
- token_info_push(p, "do", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
- }
- ;
+ {
+ token_info_push(p, "do", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+
+ }
+ ;
k_do_block : keyword_do_block
- {
- token_info_push(p, "do", &@$);
- push_end_expect_token_locations(p, &@1.beg_pos);
- }
- ;
+ {
+ token_info_push(p, "do", &@$);
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ ;
k_rescue : keyword_rescue
- {
- token_info_warn(p, "rescue", p->token_info, 1, &@$);
- $$ = p->ctxt;
- p->ctxt.in_rescue = after_rescue;
- }
- ;
+ {
+ token_info_warn(p, "rescue", p->token_info, 1, &@$);
+ }
+ ;
k_ensure : keyword_ensure
- {
- token_info_warn(p, "ensure", p->token_info, 1, &@$);
- $$ = p->ctxt;
- }
- ;
+ {
+ token_info_warn(p, "ensure", p->token_info, 1, &@$);
+ }
+ ;
k_when : keyword_when
- {
- token_info_warn(p, "when", p->token_info, 0, &@$);
- }
- ;
+ {
+ token_info_warn(p, "when", p->token_info, 0, &@$);
+ }
+ ;
k_else : keyword_else
- {
- token_info *ptinfo_beg = p->token_info;
- int same = ptinfo_beg && strcmp(ptinfo_beg->token, "case") != 0;
- token_info_warn(p, "else", p->token_info, same, &@$);
- if (same) {
- token_info e;
- e.next = ptinfo_beg->next;
- e.token = "else";
- token_info_setup(&e, p->lex.pbeg, &@$);
- if (!e.nonspc) *ptinfo_beg = e;
- }
- }
- ;
+ {
+ token_info *ptinfo_beg = p->token_info;
+ int same = ptinfo_beg && strcmp(ptinfo_beg->token, "case") != 0;
+ token_info_warn(p, "else", p->token_info, same, &@$);
+ if (same) {
+ token_info e;
+ e.next = ptinfo_beg->next;
+ e.token = "else";
+ token_info_setup(&e, p->lex.pbeg, &@$);
+ if (!e.nonspc) *ptinfo_beg = e;
+ }
+ }
+ ;
k_elsif : keyword_elsif
- {
- WARN_EOL("elsif");
- token_info_warn(p, "elsif", p->token_info, 1, &@$);
- }
- ;
+ {
+ WARN_EOL("elsif");
+ token_info_warn(p, "elsif", p->token_info, 1, &@$);
+ }
+ ;
k_end : keyword_end
- {
- token_info_pop(p, "end", &@$);
- pop_end_expect_token_locations(p);
- }
- | tDUMNY_END
- {
- compile_error(p, "syntax error, unexpected end-of-input");
- }
- ;
+ {
+ token_info_pop(p, "end", &@$);
+ /*%%%*/
+ pop_end_expect_token_locations(p);
+ /*% %*/
+ }
+ | tDUMNY_END
+ {
+ compile_error(p, "syntax error, unexpected end-of-input");
+ }
+ ;
k_return : keyword_return
- {
- if (p->ctxt.cant_return && !dyna_in_block(p))
- yyerror1(&@1, "Invalid return in class/module body");
- }
- ;
-
-k_yield : keyword_yield
- {
- if (!p->ctxt.in_defined && !p->ctxt.in_def && !compile_for_eval)
- yyerror1(&@1, "Invalid yield");
- }
- ;
+ {
+ if (p->ctxt.in_class && !p->ctxt.in_def && !dyna_in_block(p))
+ yyerror1(&@1, "Invalid return in class/module body");
+ }
+ ;
then : term
- | keyword_then
- | term keyword_then
- ;
+ | keyword_then
+ | term keyword_then
+ ;
do : term
- | keyword_do_cond
- ;
+ | keyword_do_cond
+ ;
if_tail : opt_else
- | k_elsif expr_value then
- compstmt
- if_tail
- {
- $$ = new_if(p, $2, $4, $5, &@$);
- fixpos($$, $2);
- /*% ripper: elsif!($:2, $:4, $:5) %*/
- }
- ;
+ | k_elsif expr_value then
+ compstmt
+ if_tail
+ {
+ /*%%%*/
+ $$ = new_if(p, $2, $4, $5, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: elsif!($2, $4, escape_Qundef($5)) %*/
+ }
+ ;
opt_else : none
- | k_else compstmt
- {
- $$ = $2;
- /*% ripper: else!($:2) %*/
- }
- ;
+ | k_else compstmt
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: else!($2) %*/
+ }
+ ;
for_var : lhs
- | mlhs
- ;
+ | mlhs
+ ;
f_marg : f_norm_arg
- {
- $$ = assignable(p, $1, 0, &@$);
- mark_lvar_used(p, $$);
- }
- | tLPAREN f_margs rparen
- {
- $$ = (NODE *)$2;
- /*% ripper: mlhs_paren!($:2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ mark_lvar_used(p, $$);
+ /*% %*/
+ /*% ripper: assignable(p, $1) %*/
+ }
+ | tLPAREN f_margs rparen
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: mlhs_paren!($2) %*/
+ }
+ ;
f_marg_list : f_marg
- {
- $$ = NEW_LIST($1, &@$);
- /*% ripper: mlhs_add!(mlhs_new!, $:1) %*/
- }
- | f_marg_list ',' f_marg
- {
- $$ = list_append(p, $1, $3);
- /*% ripper: mlhs_add!($:1, $:3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add!(mlhs_new!, $1) %*/
+ }
+ | f_marg_list ',' f_marg
+ {
+ /*%%%*/
+ $$ = list_append(p, $1, $3);
+ /*% %*/
+ /*% ripper: mlhs_add!($1, $3) %*/
+ }
+ ;
f_margs : f_marg_list
- {
- $$ = NEW_MASGN($1, 0, &@$);
- /*% ripper: $:1 %*/
- }
- | f_marg_list ',' f_rest_marg
- {
- $$ = NEW_MASGN($1, $3, &@$);
- /*% ripper: mlhs_add_star!($:1, $:3) %*/
- }
- | f_marg_list ',' f_rest_marg ',' f_marg_list
- {
- $$ = NEW_MASGN($1, NEW_POSTARG($3, $5, &@$), &@$);
- /*% ripper: mlhs_add_post!(mlhs_add_star!($:1, $:3), $:5) %*/
- }
- | f_rest_marg
- {
- $$ = NEW_MASGN(0, $1, &@$);
- /*% ripper: mlhs_add_star!(mlhs_new!, $:1) %*/
- }
- | f_rest_marg ',' f_marg_list
- {
- $$ = NEW_MASGN(0, NEW_POSTARG($1, $3, &@$), &@$);
- /*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, $:1), $:3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, 0, &@$);
+ /*% %*/
+ /*% ripper: $1 %*/
+ }
+ | f_marg_list ',' f_rest_marg
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, $3, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_star!($1, $3) %*/
+ }
+ | f_marg_list ',' f_rest_marg ',' f_marg_list
+ {
+ /*%%%*/
+ $$ = NEW_MASGN($1, NEW_POSTARG($3, $5, &@$), &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_post!(mlhs_add_star!($1, $3), $5) %*/
+ }
+ | f_rest_marg
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(0, $1, &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_star!(mlhs_new!, $1) %*/
+ }
+ | f_rest_marg ',' f_marg_list
+ {
+ /*%%%*/
+ $$ = NEW_MASGN(0, NEW_POSTARG($1, $3, &@$), &@$);
+ /*% %*/
+ /*% ripper: mlhs_add_post!(mlhs_add_star!(mlhs_new!, $1), $3) %*/
+ }
+ ;
f_rest_marg : tSTAR f_norm_arg
- {
- /*% ripper: $:2 %*/
- $$ = assignable(p, $2, 0, &@$);
- mark_lvar_used(p, $$);
- }
- | tSTAR
- {
- $$ = NODE_SPECIAL_NO_NAME_REST;
- /*% ripper: Qnil %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = assignable(p, $2, 0, &@$);
+ mark_lvar_used(p, $$);
+ /*% %*/
+ /*% ripper: assignable(p, $2) %*/
+ }
+ | tSTAR
+ {
+ /*%%%*/
+ $$ = NODE_SPECIAL_NO_NAME_REST;
+ /*% %*/
+ /*% ripper: Qnil %*/
+ }
+ ;
f_any_kwrest : f_kwrest
- | f_no_kwarg
- {
- $$ = idNil;
- /*% ripper: ID2VAL(idNil) %*/
- }
- ;
+ | f_no_kwarg {$$ = ID2VAL(idNil);}
+ ;
f_eq : {p->ctxt.in_argdef = 0;} '=';
-block_args_tail : f_kwarg(f_block_kw) ',' f_kwrest opt_f_block_arg
- {
- $$ = new_args_tail(p, $1, $3, $4, &@3);
- /*% ripper: [$:1, $:3, $:4] %*/
- }
- | f_kwarg(f_block_kw) opt_f_block_arg
- {
- $$ = new_args_tail(p, $1, 0, $2, &@1);
- /*% ripper: [$:1, Qnil, $:2] %*/
- }
- | f_any_kwrest opt_f_block_arg
- {
- $$ = new_args_tail(p, 0, $1, $2, &@1);
- /*% ripper: [Qnil, $:1, $:2] %*/
- }
- | f_block_arg
- {
- $$ = new_args_tail(p, 0, 0, $1, &@1);
- /*% ripper: [Qnil, Qnil, $:1] %*/
- }
- ;
+block_args_tail : f_block_kwarg ',' f_kwrest opt_f_block_arg
+ {
+ $$ = new_args_tail(p, $1, $3, $4, &@3);
+ }
+ | f_block_kwarg opt_f_block_arg
+ {
+ $$ = new_args_tail(p, $1, Qnone, $2, &@1);
+ }
+ | f_any_kwrest opt_f_block_arg
+ {
+ $$ = new_args_tail(p, Qnone, $1, $2, &@1);
+ }
+ | f_block_arg
+ {
+ $$ = new_args_tail(p, Qnone, Qnone, $1, &@1);
+ }
+ ;
+
+opt_block_args_tail : ',' block_args_tail
+ {
+ $$ = $2;
+ }
+ | /* none */
+ {
+ $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
+ }
+ ;
excessed_comma : ','
- {
- /* magic number for rest_id in iseq_set_arguments() */
- $$ = NODE_SPECIAL_EXCESSIVE_COMMA;
- /*% ripper: excessed_comma! %*/
- }
- ;
-
-block_param : f_arg ',' f_optarg(primary_value) ',' f_rest_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, $1, $3, $5, 0, $6, &@$);
- /*% ripper: params!($:1, $:3, $:5, Qnil, *$:6[0..2]) %*/
- }
- | f_arg ',' f_optarg(primary_value) ',' f_rest_arg ',' f_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, $1, $3, $5, $7, $8, &@$);
- /*% ripper: params!($:1, $:3, $:5, $:7, *$:8[0..2]) %*/
- }
- | f_arg ',' f_optarg(primary_value) opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, $1, $3, 0, 0, $4, &@$);
- /*% ripper: params!($:1, $:3, Qnil, Qnil, *$:4[0..2]) %*/
- }
- | f_arg ',' f_optarg(primary_value) ',' f_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, $1, $3, 0, $5, $6, &@$);
- /*% ripper: params!($:1, $:3, Qnil, $:5, *$:6[0..2]) %*/
- }
- | f_arg ',' f_rest_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, $1, 0, $3, 0, $4, &@$);
- /*% ripper: params!($:1, Qnil, $:3, Qnil, *$:4[0..2]) %*/
- }
- | f_arg excessed_comma
- {
- $$ = new_args_tail(p, 0, 0, 0, &@2);
- $$ = new_args(p, $1, 0, $2, 0, $$, &@$);
- /*% ripper: params!($:1, Qnil, $:2, Qnil, Qnil, Qnil, Qnil) %*/
- }
- | f_arg ',' f_rest_arg ',' f_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, $1, 0, $3, $5, $6, &@$);
- /*% ripper: params!($:1, Qnil, $:3, $:5, *$:6[0..2]) %*/
- }
- | f_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, $1, 0, 0, 0, $2, &@$);
- /*% ripper: params!($:1, Qnil, Qnil, Qnil, *$:2[0..2]) %*/
- }
- | f_optarg(primary_value) ',' f_rest_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, 0, $1, $3, 0, $4, &@$);
- /*% ripper: params!(Qnil, $:1, $:3, Qnil, *$:4[0..2]) %*/
- }
- | f_optarg(primary_value) ',' f_rest_arg ',' f_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, 0, $1, $3, $5, $6, &@$);
- /*% ripper: params!(Qnil, $:1, $:3, $:5, *$:6[0..2]) %*/
- }
- | f_optarg(primary_value) opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, 0, $1, 0, 0, $2, &@$);
- /*% ripper: params!(Qnil, $:1, Qnil, Qnil, *$:2[0..2]) %*/
- }
- | f_optarg(primary_value) ',' f_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, 0, $1, 0, $3, $4, &@$);
- /*% ripper: params!(Qnil, $:1, Qnil, $:3, *$:4[0..2]) %*/
- }
- | f_rest_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, 0, 0, $1, 0, $2, &@$);
- /*% ripper: params!(Qnil, Qnil, $:1, Qnil, *$:2[0..2]) %*/
- }
- | f_rest_arg ',' f_arg opt_args_tail(block_args_tail)
- {
- $$ = new_args(p, 0, 0, $1, $3, $4, &@$);
- /*% ripper: params!(Qnil, Qnil, $:1, $:3, *$:4[0..2]) %*/
- }
- | block_args_tail
- {
- $$ = new_args(p, 0, 0, 0, 0, $1, &@$);
- /*% ripper: params!(Qnil, Qnil, Qnil, Qnil, *$:1[0..2]) %*/
- }
- ;
+ {
+ /* magic number for rest_id in iseq_set_arguments() */
+ /*%%%*/
+ $$ = NODE_SPECIAL_EXCESSIVE_COMMA;
+ /*% %*/
+ /*% ripper: excessed_comma! %*/
+ }
+ ;
+
+block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_block_args_tail
+ {
+ $$ = new_args(p, $1, $3, $5, Qnone, $6, &@$);
+ }
+ | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, $1, $3, $5, $7, $8, &@$);
+ }
+ | f_arg ',' f_block_optarg opt_block_args_tail
+ {
+ $$ = new_args(p, $1, $3, Qnone, Qnone, $4, &@$);
+ }
+ | f_arg ',' f_block_optarg ',' f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, $1, $3, Qnone, $5, $6, &@$);
+ }
+ | f_arg ',' f_rest_arg opt_block_args_tail
+ {
+ $$ = new_args(p, $1, Qnone, $3, Qnone, $4, &@$);
+ }
+ | f_arg excessed_comma
+ {
+ $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@2);
+ $$ = new_args(p, $1, Qnone, $2, Qnone, $$, &@$);
+ }
+ | f_arg ',' f_rest_arg ',' f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, $1, Qnone, $3, $5, $6, &@$);
+ }
+ | f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, $1, Qnone, Qnone, Qnone, $2, &@$);
+ }
+ | f_block_optarg ',' f_rest_arg opt_block_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, $3, Qnone, $4, &@$);
+ }
+ | f_block_optarg ',' f_rest_arg ',' f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, $3, $5, $6, &@$);
+ }
+ | f_block_optarg opt_block_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, Qnone, Qnone, $2, &@$);
+ }
+ | f_block_optarg ',' f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, Qnone, $3, $4, &@$);
+ }
+ | f_rest_arg opt_block_args_tail
+ {
+ $$ = new_args(p, Qnone, Qnone, $1, Qnone, $2, &@$);
+ }
+ | f_rest_arg ',' f_arg opt_block_args_tail
+ {
+ $$ = new_args(p, Qnone, Qnone, $1, $3, $4, &@$);
+ }
+ | block_args_tail
+ {
+ $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $1, &@$);
+ }
+ ;
opt_block_param : none
- | block_param_def
- {
- p->command_start = TRUE;
- }
- ;
+ | block_param_def
+ {
+ p->command_start = TRUE;
+ }
+ ;
block_param_def : '|' opt_bv_decl '|'
- {
- p->max_numparam = ORDINAL_PARAM;
- p->ctxt.in_argdef = 0;
- $$ = 0;
- /*% ripper: block_var!(params!(Qnil,Qnil,Qnil,Qnil,Qnil,Qnil,Qnil), $:2) %*/
- }
- | '|' block_param opt_bv_decl '|'
- {
- p->max_numparam = ORDINAL_PARAM;
- p->ctxt.in_argdef = 0;
- $$ = $2;
- /*% ripper: block_var!($:2, $:3) %*/
- }
- ;
-
-
-opt_bv_decl : '\n'?
- {
- $$ = 0;
- /*% ripper: Qfalse %*/
- }
- | '\n'? ';' bv_decls '\n'?
- {
- $$ = 0;
- /*% ripper: $:3 %*/
- }
- ;
+ {
+ p->cur_arg = 0;
+ p->max_numparam = ORDINAL_PARAM;
+ p->ctxt.in_argdef = 0;
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: block_var!(params!(Qnil,Qnil,Qnil,Qnil,Qnil,Qnil,Qnil), escape_Qundef($2)) %*/
+ }
+ | '|' block_param opt_bv_decl '|'
+ {
+ p->cur_arg = 0;
+ p->max_numparam = ORDINAL_PARAM;
+ p->ctxt.in_argdef = 0;
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: block_var!(escape_Qundef($2), escape_Qundef($3)) %*/
+ }
+ ;
+
+
+opt_bv_decl : opt_nl
+ {
+ $$ = 0;
+ }
+ | opt_nl ';' bv_decls opt_nl
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: $3 %*/
+ }
+ ;
bv_decls : bvar
- /*% ripper[brace]: rb_ary_new3(1, $:1) %*/
- | bv_decls ',' bvar
- /*% ripper[brace]: rb_ary_push($:1, $:3) %*/
- ;
+ /*% ripper[brace]: rb_ary_new3(1, get_value($1)) %*/
+ | bv_decls ',' bvar
+ /*% ripper[brace]: rb_ary_push($1, get_value($3)) %*/
+ ;
bvar : tIDENTIFIER
- {
- new_bv(p, $1);
- /*% ripper: $:1 %*/
- }
- | f_bad_arg
- {
- $$ = 0;
- }
- ;
-
-max_numparam : {
- $$ = p->max_numparam;
- p->max_numparam = 0;
- }
- ;
-
-numparam : {
- $$ = numparam_push(p);
- }
- ;
-
-it_id : {
- $$ = p->it_id;
- p->it_id = 0;
- }
- ;
-
-lambda : tLAMBDA[lpar]
- {
- token_info_push(p, "->", &@1);
- $$ = dyna_push(p);
- }[dyna]<vars>
- max_numparam numparam it_id allow_exits
- f_larglist[args]
- {
- CMDARG_PUSH(0);
- }
- lambda_body[body]
- {
- int max_numparam = p->max_numparam;
- ID it_id = p->it_id;
- p->lex.lpar_beg = $lpar;
- p->max_numparam = $max_numparam;
- p->it_id = $it_id;
- restore_block_exit(p, $allow_exits);
- CMDARG_POP();
- $args = args_with_numbered(p, $args, max_numparam, it_id);
+ {
+ new_bv(p, get_id($1));
+ /*% ripper: get_value($1) %*/
+ }
+ | f_bad_arg
+ {
+ $$ = 0;
+ }
+ ;
+
+lambda : tLAMBDA
+ {
+ token_info_push(p, "->", &@1);
+ $<vars>1 = dyna_push(p);
+ $<num>$ = p->lex.lpar_beg;
+ p->lex.lpar_beg = p->lex.paren_nest;
+ }
+ {
+ $<num>$ = p->max_numparam;
+ p->max_numparam = 0;
+ }
+ {
+ $<node>$ = numparam_push(p);
+ }
+ f_larglist
+ {
+ CMDARG_PUSH(0);
+ }
+ lambda_body
+ {
+ int max_numparam = p->max_numparam;
+ p->lex.lpar_beg = $<num>2;
+ p->max_numparam = $<num>3;
+ CMDARG_POP();
+ $5 = args_with_numbered(p, $5, max_numparam);
+ /*%%%*/
{
- YYLTYPE loc = code_loc_gen(&@args, &@body);
- $$ = NEW_LAMBDA($args, $body, &loc);
- nd_set_line(RNODE_LAMBDA($$)->nd_body, @body.end_pos.lineno);
- nd_set_line($$, @args.end_pos.lineno);
- nd_set_first_loc($$, @1.beg_pos);
+ YYLTYPE loc = code_loc_gen(&@5, &@7);
+ $$ = NEW_LAMBDA($5, $7, &loc);
+ nd_set_line($$->nd_body, @7.end_pos.lineno);
+ nd_set_line($$, @5.end_pos.lineno);
+ nd_set_first_loc($$, @1.beg_pos);
}
- /*% ripper: lambda!($:args, $:body) %*/
- numparam_pop(p, $numparam);
- dyna_pop(p, $dyna);
- }
- ;
+ /*% %*/
+ /*% ripper: lambda!($5, $7) %*/
+ numparam_pop(p, $<node>4);
+ dyna_pop(p, $<vars>1);
+ }
+ ;
f_larglist : '(' f_args opt_bv_decl ')'
- {
- p->ctxt.in_argdef = 0;
- $$ = $f_args;
- p->max_numparam = ORDINAL_PARAM;
- /*% ripper: paren!($:2) %*/
- }
- | f_args
- {
- p->ctxt.in_argdef = 0;
- if (!args_info_empty_p(&$1->nd_ainfo))
- p->max_numparam = ORDINAL_PARAM;
- $$ = $f_args;
- }
- ;
+ {
+ p->ctxt.in_argdef = 0;
+ /*%%%*/
+ $$ = $2;
+ p->max_numparam = ORDINAL_PARAM;
+ /*% %*/
+ /*% ripper: paren!($2) %*/
+ }
+ | f_args
+ {
+ p->ctxt.in_argdef = 0;
+ /*%%%*/
+ if (!args_info_empty_p($1->nd_ainfo))
+ p->max_numparam = ORDINAL_PARAM;
+ /*% %*/
+ $$ = $1;
+ }
+ ;
lambda_body : tLAMBEG compstmt '}'
- {
- token_info_pop(p, "}", &@3);
- $$ = $2;
- /*% ripper: $:2 %*/
- }
- | keyword_do_LAMBDA
- {
- push_end_expect_token_locations(p, &@1.beg_pos);
- }
- bodystmt k_end
- {
- $$ = $3;
- /*% ripper: $:3 %*/
- }
- ;
+ {
+ token_info_pop(p, "}", &@3);
+ $$ = $2;
+ }
+ | keyword_do_LAMBDA
+ {
+ /*%%%*/
+ push_end_expect_token_locations(p, &@1.beg_pos);
+ /*% %*/
+ }
+ bodystmt k_end
+ {
+ $$ = $3;
+ }
+ ;
do_block : k_do_block do_body k_end
- {
- $$ = $2;
- set_embraced_location($$, &@1, &@3);
- /*% ripper: $:2 %*/
- }
- ;
+ {
+ $$ = $2;
+ /*%%%*/
+ $$->nd_body->nd_loc = code_loc_gen(&@1, &@3);
+ nd_set_line($$, @1.end_pos.lineno);
+ /*% %*/
+ }
+ ;
block_call : command do_block
- {
- if (nd_type_p($1, NODE_YIELD)) {
- compile_error(p, "block given to yield");
- }
- else {
- block_dup_check(p, get_nd_args(p, $1), $2);
- }
- $$ = method_add_block(p, $1, $2, &@$);
- fixpos($$, $1);
- /*% ripper: method_add_block!($:1, $:2) %*/
- }
- | block_call call_op2 operation2 opt_paren_args
- {
- bool has_args = $4 != 0;
- if (NODE_EMPTY_ARGS_P($4)) $4 = 0;
- $$ = new_qcall(p, $2, $1, $3, $4, &@3, &@$);
- /*% ripper: call!($:1, $:2, $:3) %*/
- if (has_args) {
- /*% ripper: method_add_arg!($:$, $:4) %*/
- }
- }
- | block_call call_op2 operation2 opt_paren_args brace_block
- {
- if (NODE_EMPTY_ARGS_P($4)) $4 = 0;
- $$ = new_command_qcall(p, $2, $1, $3, $4, $5, &@3, &@$);
- /*% ripper: command_call!($:1, $:2, $:3, $:4) %*/
- if ($5) {
- /*% ripper: method_add_block!($:$, $:5) %*/
- }
- }
- | block_call call_op2 operation2 command_args do_block
- {
- $$ = new_command_qcall(p, $2, $1, $3, $4, $5, &@3, &@$);
- /*% ripper: method_add_block!(command_call!($:1, $:2, $:3, $:4), $:5) %*/
- }
- ;
+ {
+ /*%%%*/
+ if (nd_type_p($1, NODE_YIELD)) {
+ compile_error(p, "block given to yield");
+ }
+ else {
+ block_dup_check(p, $1->nd_args, $2);
+ }
+ $$ = method_add_block(p, $1, $2, &@$);
+ fixpos($$, $1);
+ /*% %*/
+ /*% ripper: method_add_block!($1, $2) %*/
+ }
+ | block_call call_op2 operation2 opt_paren_args
+ {
+ /*%%%*/
+ $$ = new_qcall(p, $2, $1, $3, $4, &@3, &@$);
+ /*% %*/
+ /*% ripper: opt_event(:method_add_arg!, call!($1, $2, $3), $4) %*/
+ }
+ | block_call call_op2 operation2 opt_paren_args brace_block
+ {
+ /*%%%*/
+ $$ = new_command_qcall(p, $2, $1, $3, $4, $5, &@3, &@$);
+ /*% %*/
+ /*% ripper: opt_event(:method_add_block!, command_call!($1, $2, $3, $4), $5) %*/
+ }
+ | block_call call_op2 operation2 command_args do_block
+ {
+ /*%%%*/
+ $$ = new_command_qcall(p, $2, $1, $3, $4, $5, &@3, &@$);
+ /*% %*/
+ /*% ripper: method_add_block!(command_call!($1, $2, $3, $4), $5) %*/
+ }
+ ;
method_call : fcall paren_args
- {
- $1->nd_args = $2;
- $$ = (NODE *)$1;
- nd_set_last_loc($1, @2.end_pos);
- /*% ripper: method_add_arg!(fcall!($:1), $:2) %*/
- }
- | primary_value call_op operation2 opt_paren_args
- {
- bool has_args = $4 != 0;
- if (NODE_EMPTY_ARGS_P($4)) $4 = 0;
- $$ = new_qcall(p, $2, $1, $3, $4, &@3, &@$);
- nd_set_line($$, @3.end_pos.lineno);
- /*% ripper: call!($:1, $:2, $:3) %*/
- if (has_args) {
- /*% ripper: method_add_arg!($:$, $:4) %*/
- }
- }
- | primary_value tCOLON2 operation2 paren_args
- {
- $$ = new_qcall(p, idCOLON2, $1, $3, $4, &@3, &@$);
- nd_set_line($$, @3.end_pos.lineno);
- /*% ripper: method_add_arg!(call!($:1, $:2, $:3), $:4) %*/
- }
- | primary_value tCOLON2 operation3
- {
- $$ = new_qcall(p, idCOLON2, $1, $3, 0, &@3, &@$);
- /*% ripper: call!($:1, $:2, $:3) %*/
- }
- | primary_value call_op paren_args
- {
- $$ = new_qcall(p, $2, $1, idCall, $3, &@2, &@$);
- nd_set_line($$, @2.end_pos.lineno);
- /*% ripper: method_add_arg!(call!($:1, $:2, ID2VAL(idCall)), $:3) %*/
- }
- | primary_value tCOLON2 paren_args
- {
- $$ = new_qcall(p, idCOLON2, $1, idCall, $3, &@2, &@$);
- nd_set_line($$, @2.end_pos.lineno);
- /*% ripper: method_add_arg!(call!($:1, $:2, ID2VAL(idCall)), $:3) %*/
- }
- | keyword_super paren_args
- {
- $$ = NEW_SUPER($2, &@$);
- /*% ripper: super!($:2) %*/
- }
- | keyword_super
- {
- $$ = NEW_ZSUPER(&@$);
- /*% ripper: zsuper! %*/
- }
- | primary_value '[' opt_call_args rbracket
- {
- $$ = NEW_CALL($1, tAREF, $3, &@$);
- fixpos($$, $1);
- /*% ripper: aref!($:1, $:3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = $1;
+ $$->nd_args = $2;
+ nd_set_last_loc($1, @2.end_pos);
+ /*% %*/
+ /*% ripper: method_add_arg!(fcall!($1), $2) %*/
+ }
+ | primary_value call_op operation2 opt_paren_args
+ {
+ /*%%%*/
+ $$ = new_qcall(p, $2, $1, $3, $4, &@3, &@$);
+ nd_set_line($$, @3.end_pos.lineno);
+ /*% %*/
+ /*% ripper: opt_event(:method_add_arg!, call!($1, $2, $3), $4) %*/
+ }
+ | primary_value tCOLON2 operation2 paren_args
+ {
+ /*%%%*/
+ $$ = new_qcall(p, ID2VAL(idCOLON2), $1, $3, $4, &@3, &@$);
+ nd_set_line($$, @3.end_pos.lineno);
+ /*% %*/
+ /*% ripper: method_add_arg!(call!($1, $2, $3), $4) %*/
+ }
+ | primary_value tCOLON2 operation3
+ {
+ /*%%%*/
+ $$ = new_qcall(p, ID2VAL(idCOLON2), $1, $3, Qnull, &@3, &@$);
+ /*% %*/
+ /*% ripper: call!($1, $2, $3) %*/
+ }
+ | primary_value call_op paren_args
+ {
+ /*%%%*/
+ $$ = new_qcall(p, $2, $1, ID2VAL(idCall), $3, &@2, &@$);
+ nd_set_line($$, @2.end_pos.lineno);
+ /*% %*/
+ /*% ripper: method_add_arg!(call!($1, $2, ID2VAL(idCall)), $3) %*/
+ }
+ | primary_value tCOLON2 paren_args
+ {
+ /*%%%*/
+ $$ = new_qcall(p, ID2VAL(idCOLON2), $1, ID2VAL(idCall), $3, &@2, &@$);
+ nd_set_line($$, @2.end_pos.lineno);
+ /*% %*/
+ /*% ripper: method_add_arg!(call!($1, $2, ID2VAL(idCall)), $3) %*/
+ }
+ | keyword_super paren_args
+ {
+ /*%%%*/
+ $$ = NEW_SUPER($2, &@$);
+ /*% %*/
+ /*% ripper: super!($2) %*/
+ }
+ | keyword_super
+ {
+ /*%%%*/
+ $$ = NEW_ZSUPER(&@$);
+ /*% %*/
+ /*% ripper: zsuper! %*/
+ }
+ | primary_value '[' opt_call_args rbracket
+ {
+ /*%%%*/
+ if ($1 && nd_type_p($1, NODE_SELF))
+ $$ = NEW_FCALL(tAREF, $3, &@$);
+ else
+ $$ = NEW_CALL($1, tAREF, $3, &@$);
+ fixpos($$, $1);
+ /*% %*/
+ /*% ripper: aref!($1, escape_Qundef($3)) %*/
+ }
+ ;
brace_block : '{' brace_body '}'
- {
- $$ = $2;
- set_embraced_location($$, &@1, &@3);
- /*% ripper: $:2 %*/
- }
- | k_do do_body k_end
- {
- $$ = $2;
- set_embraced_location($$, &@1, &@3);
- /*% ripper: $:2 %*/
- }
- ;
-
-brace_body : {$$ = dyna_push(p);}[dyna]<vars>
- max_numparam numparam it_id allow_exits
- opt_block_param[args] compstmt
- {
- int max_numparam = p->max_numparam;
- ID it_id = p->it_id;
- p->max_numparam = $max_numparam;
- p->it_id = $it_id;
- $args = args_with_numbered(p, $args, max_numparam, it_id);
- $$ = NEW_ITER($args, $compstmt, &@$);
- /*% ripper: brace_block!($:args, $:compstmt) %*/
- restore_block_exit(p, $allow_exits);
- numparam_pop(p, $numparam);
- dyna_pop(p, $dyna);
- }
- ;
-
-do_body : {
- $$ = dyna_push(p);
- CMDARG_PUSH(0);
- }[dyna]<vars>
- max_numparam numparam it_id allow_exits
- opt_block_param[args] bodystmt
- {
- int max_numparam = p->max_numparam;
- ID it_id = p->it_id;
- p->max_numparam = $max_numparam;
- p->it_id = $it_id;
- $args = args_with_numbered(p, $args, max_numparam, it_id);
- $$ = NEW_ITER($args, $bodystmt, &@$);
- /*% ripper: do_block!($:args, $:bodystmt) %*/
- CMDARG_POP();
- restore_block_exit(p, $allow_exits);
- numparam_pop(p, $numparam);
- dyna_pop(p, $dyna);
- }
- ;
+ {
+ $$ = $2;
+ /*%%%*/
+ $$->nd_body->nd_loc = code_loc_gen(&@1, &@3);
+ nd_set_line($$, @1.end_pos.lineno);
+ /*% %*/
+ }
+ | k_do do_body k_end
+ {
+ $$ = $2;
+ /*%%%*/
+ $$->nd_body->nd_loc = code_loc_gen(&@1, &@3);
+ nd_set_line($$, @1.end_pos.lineno);
+ /*% %*/
+ }
+ ;
+
+brace_body : {$<vars>$ = dyna_push(p);}
+ {
+ $<num>$ = p->max_numparam;
+ p->max_numparam = 0;
+ }
+ {
+ $<node>$ = numparam_push(p);
+ }
+ opt_block_param compstmt
+ {
+ int max_numparam = p->max_numparam;
+ p->max_numparam = $<num>2;
+ $4 = args_with_numbered(p, $4, max_numparam);
+ /*%%%*/
+ $$ = NEW_ITER($4, $5, &@$);
+ /*% %*/
+ /*% ripper: brace_block!(escape_Qundef($4), $5) %*/
+ numparam_pop(p, $<node>3);
+ dyna_pop(p, $<vars>1);
+ }
+ ;
+
+do_body : {$<vars>$ = dyna_push(p);}
+ {
+ $<num>$ = p->max_numparam;
+ p->max_numparam = 0;
+ }
+ {
+ $<node>$ = numparam_push(p);
+ CMDARG_PUSH(0);
+ }
+ opt_block_param bodystmt
+ {
+ int max_numparam = p->max_numparam;
+ p->max_numparam = $<num>2;
+ $4 = args_with_numbered(p, $4, max_numparam);
+ /*%%%*/
+ $$ = NEW_ITER($4, $5, &@$);
+ /*% %*/
+ /*% ripper: do_block!(escape_Qundef($4), $5) %*/
+ CMDARG_POP();
+ numparam_pop(p, $<node>3);
+ dyna_pop(p, $<vars>1);
+ }
+ ;
case_args : arg_value
- {
- check_literal_when(p, $arg_value, &@arg_value);
- $$ = NEW_LIST($arg_value, &@$);
- /*% ripper: args_add!(args_new!, $:arg_value) %*/
- }
- | tSTAR arg_value
- {
- $$ = NEW_SPLAT($arg_value, &@$, &@tSTAR);
- /*% ripper: args_add_star!(args_new!, $:arg_value) %*/
- }
- | case_args[non_last_args] ',' arg_value
- {
- check_literal_when(p, $arg_value, &@arg_value);
- $$ = last_arg_append(p, $non_last_args, $arg_value, &@$);
- /*% ripper: args_add!($:non_last_args, $:arg_value) %*/
- }
- | case_args[non_last_args] ',' tSTAR arg_value
- {
- $$ = rest_arg_append(p, $non_last_args, $arg_value, &@$);
- /*% ripper: args_add_star!($:non_last_args, $:arg_value) %*/
- }
- ;
+ {
+ /*%%%*/
+ check_literal_when(p, $1, &@1);
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: args_add!(args_new!, $1) %*/
+ }
+ | tSTAR arg_value
+ {
+ /*%%%*/
+ $$ = NEW_SPLAT($2, &@$);
+ /*% %*/
+ /*% ripper: args_add_star!(args_new!, $2) %*/
+ }
+ | case_args ',' arg_value
+ {
+ /*%%%*/
+ check_literal_when(p, $3, &@3);
+ $$ = last_arg_append(p, $1, $3, &@$);
+ /*% %*/
+ /*% ripper: args_add!($1, $3) %*/
+ }
+ | case_args ',' tSTAR arg_value
+ {
+ /*%%%*/
+ $$ = rest_arg_append(p, $1, $4, &@$);
+ /*% %*/
+ /*% ripper: args_add_star!($1, $4) %*/
+ }
+ ;
case_body : k_when case_args then
- compstmt
- cases
- {
- $$ = NEW_WHEN($2, $4, $5, &@$, &@1, &@3);
- fixpos($$, $2);
- /*% ripper: when!($:2, $:4, $:5) %*/
- }
- ;
+ compstmt
+ cases
+ {
+ /*%%%*/
+ $$ = NEW_WHEN($2, $4, $5, &@$);
+ fixpos($$, $2);
+ /*% %*/
+ /*% ripper: when!($2, $4, escape_Qundef($5)) %*/
+ }
+ ;
cases : opt_else
- | case_body
- ;
-
-p_pvtbl : {$$ = p->pvtbl; p->pvtbl = st_init_numtable();};
-p_pktbl : {$$ = p->pktbl; p->pktbl = 0;};
-
-p_in_kwarg : {
- $$ = p->ctxt;
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- p->command_start = FALSE;
- p->ctxt.in_kwarg = 1;
- }
- ;
+ | case_body
+ ;
p_case_body : keyword_in
- p_in_kwarg[ctxt] p_pvtbl p_pktbl
- p_top_expr[expr] then
- {
- pop_pktbl(p, $p_pktbl);
- pop_pvtbl(p, $p_pvtbl);
- p->ctxt.in_kwarg = $ctxt.in_kwarg;
- }
- compstmt
- p_cases[cases]
- {
- $$ = NEW_IN($expr, $compstmt, $cases, &@$);
- /*% ripper: in!($:expr, $:compstmt, $:cases) %*/
- }
- ;
+ {
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ p->command_start = FALSE;
+ $<ctxt>1 = p->ctxt;
+ p->ctxt.in_kwarg = 1;
+ $<tbl>$ = push_pvtbl(p);
+ }
+ {
+ $<tbl>$ = push_pktbl(p);
+ }
+ p_top_expr then
+ {
+ pop_pktbl(p, $<tbl>3);
+ pop_pvtbl(p, $<tbl>2);
+ p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;
+ }
+ compstmt
+ p_cases
+ {
+ /*%%%*/
+ $$ = NEW_IN($4, $7, $8, &@$);
+ /*% %*/
+ /*% ripper: in!($4, $7, escape_Qundef($8)) %*/
+ }
+ ;
p_cases : opt_else
- | p_case_body
- ;
+ | p_case_body
+ ;
p_top_expr : p_top_expr_body
- | p_top_expr_body modifier_if expr_value
- {
- $$ = new_if(p, $3, $1, 0, &@$);
- fixpos($$, $3);
- /*% ripper: if_mod!($:3, $:1) %*/
- }
- | p_top_expr_body modifier_unless expr_value
- {
- $$ = new_unless(p, $3, $1, 0, &@$, &@2, &NULL_LOC, &NULL_LOC);
- fixpos($$, $3);
- /*% ripper: unless_mod!($:3, $:1) %*/
- }
- ;
+ | p_top_expr_body modifier_if expr_value
+ {
+ /*%%%*/
+ $$ = new_if(p, $3, $1, 0, &@$);
+ fixpos($$, $3);
+ /*% %*/
+ /*% ripper: if_mod!($3, $1) %*/
+ }
+ | p_top_expr_body modifier_unless expr_value
+ {
+ /*%%%*/
+ $$ = new_unless(p, $3, $1, 0, &@$);
+ fixpos($$, $3);
+ /*% %*/
+ /*% ripper: unless_mod!($3, $1) %*/
+ }
+ ;
p_top_expr_body : p_expr
- | p_expr ','
- {
- $$ = new_array_pattern_tail(p, 0, 1, 0, 0, &@$);
- $$ = new_array_pattern(p, 0, $1, $$, &@$);
- /*% ripper: aryptn!(Qnil, [$:1], Qnil, Qnil) %*/
- }
- | p_expr ',' p_args
- {
- $$ = new_array_pattern(p, 0, $1, $3, &@$);
- nd_set_first_loc($$, @1.beg_pos);
- /*% ripper: aryptn!(Qnil, aryptn_pre_args(p, $:1, $:3[0]), *$:3[1..2]) %*/
- }
- | p_find
- {
- $$ = new_find_pattern(p, 0, $1, &@$);
- /*% ripper: fndptn!(Qnil, *$:1[0..2]) %*/
- }
- | p_args_tail
- {
- $$ = new_array_pattern(p, 0, 0, $1, &@$);
- /*% ripper: aryptn!(Qnil, *$:1[0..2]) %*/
- }
- | p_kwargs
- {
- $$ = new_hash_pattern(p, 0, $1, &@$);
- /*% ripper: hshptn!(Qnil, *$:1[0..1]) %*/
- }
- ;
+ | p_expr ','
+ {
+ $$ = new_array_pattern_tail(p, Qnone, 1, 0, Qnone, &@$);
+ $$ = new_array_pattern(p, Qnone, get_value($1), $$, &@$);
+ }
+ | p_expr ',' p_args
+ {
+ $$ = new_array_pattern(p, Qnone, get_value($1), $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_find
+ {
+ $$ = new_find_pattern(p, Qnone, $1, &@$);
+ }
+ | p_args_tail
+ {
+ $$ = new_array_pattern(p, Qnone, Qnone, $1, &@$);
+ }
+ | p_kwargs
+ {
+ $$ = new_hash_pattern(p, Qnone, $1, &@$);
+ }
+ ;
p_expr : p_as
- ;
+ ;
p_as : p_expr tASSOC p_variable
- {
- NODE *n = NEW_LIST($1, &@$);
- n = list_append(p, n, $3);
- $$ = new_hash(p, n, &@$);
- /*% ripper: binary!($:1, ID2VAL((id_assoc)), $:3) %*/
- }
- | p_alt
- ;
+ {
+ /*%%%*/
+ NODE *n = NEW_LIST($1, &@$);
+ n = list_append(p, n, $3);
+ $$ = new_hash(p, n, &@$);
+ /*% %*/
+ /*% ripper: binary!($1, STATIC_ID2SYM((id_assoc)), $3) %*/
+ }
+ | p_alt
+ ;
p_alt : p_alt '|' p_expr_basic
- {
- $$ = NEW_OR($1, $3, &@$, &@2);
- /*% ripper: binary!($:1, ID2VAL(idOr), $:3) %*/
- }
- | p_expr_basic
- ;
-
-p_lparen : '(' p_pktbl
- {
- $$ = $2;
- /*% ripper: $:2 %*/
- }
- ;
-
-p_lbracket : '[' p_pktbl
- {
- $$ = $2;
- /*% ripper: $:2 %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_NODE(NODE_OR, $1, $3, 0, &@$);
+ /*% %*/
+ /*% ripper: binary!($1, STATIC_ID2SYM(idOr), $3) %*/
+ }
+ | p_expr_basic
+ ;
+
+p_lparen : '(' {$<tbl>$ = push_pktbl(p);};
+p_lbracket : '[' {$<tbl>$ = push_pktbl(p);};
p_expr_basic : p_value
- | p_variable
- | p_const p_lparen[p_pktbl] p_args rparen
- {
- pop_pktbl(p, $p_pktbl);
- $$ = new_array_pattern(p, $p_const, 0, $p_args, &@$);
- nd_set_first_loc($$, @p_const.beg_pos);
- /*% ripper: aryptn!($:p_const, *$:p_args[0..2]) %*/
- }
- | p_const p_lparen[p_pktbl] p_find rparen
- {
- pop_pktbl(p, $p_pktbl);
- $$ = new_find_pattern(p, $p_const, $p_find, &@$);
- nd_set_first_loc($$, @p_const.beg_pos);
- /*% ripper: fndptn!($:p_const, *$:p_find[0..2]) %*/
- }
- | p_const p_lparen[p_pktbl] p_kwargs rparen
- {
- pop_pktbl(p, $p_pktbl);
- $$ = new_hash_pattern(p, $p_const, $p_kwargs, &@$);
- nd_set_first_loc($$, @p_const.beg_pos);
- /*% ripper: hshptn!($:p_const, *$:p_kwargs[0..1]) %*/
- }
- | p_const '(' rparen
- {
- $$ = new_array_pattern_tail(p, 0, 0, 0, 0, &@$);
- $$ = new_array_pattern(p, $p_const, 0, $$, &@$);
- /*% ripper: aryptn!($:p_const, Qnil, Qnil, Qnil) %*/
- }
- | p_const p_lbracket[p_pktbl] p_args rbracket
- {
- pop_pktbl(p, $p_pktbl);
- $$ = new_array_pattern(p, $p_const, 0, $p_args, &@$);
- nd_set_first_loc($$, @p_const.beg_pos);
- /*% ripper: aryptn!($:p_const, *$:p_args[0..2]) %*/
- }
- | p_const p_lbracket[p_pktbl] p_find rbracket
- {
- pop_pktbl(p, $p_pktbl);
- $$ = new_find_pattern(p, $p_const, $p_find, &@$);
- nd_set_first_loc($$, @p_const.beg_pos);
- /*% ripper: fndptn!($:p_const, *$:p_find[0..2]) %*/
- }
- | p_const p_lbracket[p_pktbl] p_kwargs rbracket
- {
- pop_pktbl(p, $p_pktbl);
- $$ = new_hash_pattern(p, $p_const, $p_kwargs, &@$);
- nd_set_first_loc($$, @p_const.beg_pos);
- /*% ripper: hshptn!($:p_const, *$:p_kwargs[0..1]) %*/
- }
- | p_const '[' rbracket
- {
- $$ = new_array_pattern_tail(p, 0, 0, 0, 0, &@$);
- $$ = new_array_pattern(p, $1, 0, $$, &@$);
- /*% ripper: aryptn!($:1, Qnil, Qnil, Qnil) %*/
- }
- | tLBRACK p_args rbracket
- {
- $$ = new_array_pattern(p, 0, 0, $p_args, &@$);
- /*% ripper: aryptn!(Qnil, *$:p_args[0..2]) %*/
- }
- | tLBRACK p_find rbracket
- {
- $$ = new_find_pattern(p, 0, $p_find, &@$);
- /*% ripper: fndptn!(Qnil, *$:p_find[0..2]) %*/
- }
- | tLBRACK rbracket
- {
- $$ = new_array_pattern_tail(p, 0, 0, 0, 0, &@$);
- $$ = new_array_pattern(p, 0, 0, $$, &@$);
- /*% ripper: aryptn!(Qnil, Qnil, Qnil, Qnil) %*/
- }
- | tLBRACE p_pktbl lex_ctxt[ctxt]
- {
- p->ctxt.in_kwarg = 0;
- }
- p_kwargs rbrace
- {
- pop_pktbl(p, $p_pktbl);
- p->ctxt.in_kwarg = $ctxt.in_kwarg;
- $$ = new_hash_pattern(p, 0, $p_kwargs, &@$);
- /*% ripper: hshptn!(Qnil, *$:p_kwargs[0..1]) %*/
- }
- | tLBRACE rbrace
- {
- $$ = new_hash_pattern_tail(p, 0, 0, &@$);
- $$ = new_hash_pattern(p, 0, $$, &@$);
- /*% ripper: hshptn!(Qnil, Qnil, Qnil) %*/
- }
- | tLPAREN p_pktbl p_expr rparen
- {
- pop_pktbl(p, $p_pktbl);
- $$ = $p_expr;
- /*% ripper: $:p_expr %*/
- }
- ;
+ | p_variable
+ | p_const p_lparen p_args rparen
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = new_array_pattern(p, $1, Qnone, $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_const p_lparen p_find rparen
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = new_find_pattern(p, $1, $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_const p_lparen p_kwargs rparen
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = new_hash_pattern(p, $1, $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_const '(' rparen
+ {
+ $$ = new_array_pattern_tail(p, Qnone, 0, 0, Qnone, &@$);
+ $$ = new_array_pattern(p, $1, Qnone, $$, &@$);
+ }
+ | p_const p_lbracket p_args rbracket
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = new_array_pattern(p, $1, Qnone, $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_const p_lbracket p_find rbracket
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = new_find_pattern(p, $1, $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_const p_lbracket p_kwargs rbracket
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = new_hash_pattern(p, $1, $3, &@$);
+ /*%%%*/
+ nd_set_first_loc($$, @1.beg_pos);
+ /*%
+ %*/
+ }
+ | p_const '[' rbracket
+ {
+ $$ = new_array_pattern_tail(p, Qnone, 0, 0, Qnone, &@$);
+ $$ = new_array_pattern(p, $1, Qnone, $$, &@$);
+ }
+ | tLBRACK p_args rbracket
+ {
+ $$ = new_array_pattern(p, Qnone, Qnone, $2, &@$);
+ }
+ | tLBRACK p_find rbracket
+ {
+ $$ = new_find_pattern(p, Qnone, $2, &@$);
+ }
+ | tLBRACK rbracket
+ {
+ $$ = new_array_pattern_tail(p, Qnone, 0, 0, Qnone, &@$);
+ $$ = new_array_pattern(p, Qnone, Qnone, $$, &@$);
+ }
+ | tLBRACE
+ {
+ $<tbl>$ = push_pktbl(p);
+ $<ctxt>1 = p->ctxt;
+ p->ctxt.in_kwarg = 0;
+ }
+ p_kwargs rbrace
+ {
+ pop_pktbl(p, $<tbl>2);
+ p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;
+ $$ = new_hash_pattern(p, Qnone, $3, &@$);
+ }
+ | tLBRACE rbrace
+ {
+ $$ = new_hash_pattern_tail(p, Qnone, 0, &@$);
+ $$ = new_hash_pattern(p, Qnone, $$, &@$);
+ }
+ | tLPAREN {$<tbl>$ = push_pktbl(p);} p_expr rparen
+ {
+ pop_pktbl(p, $<tbl>2);
+ $$ = $3;
+ }
+ ;
p_args : p_expr
- {
- NODE *pre_args = NEW_LIST($1, &@$);
- $$ = new_array_pattern_tail(p, pre_args, 0, 0, 0, &@$);
- /*% ripper: [[$:1], Qnil, Qnil] %*/
- }
- | p_args_head
- {
- $$ = new_array_pattern_tail(p, $1, 1, 0, 0, &@$);
- /*% ripper: [$:1, Qnil, Qnil] %*/
- }
- | p_args_head p_arg
- {
- $$ = new_array_pattern_tail(p, list_concat($1, $2), 0, 0, 0, &@$);
- /*% ripper: [rb_ary_concat($:1, $:2), Qnil, Qnil] %*/
- }
- | p_args_head p_rest
- {
- $$ = new_array_pattern_tail(p, $1, 1, $2, 0, &@$);
- /*% ripper: [$:1, $:2, Qnil] %*/
- }
- | p_args_head p_rest ',' p_args_post
- {
- $$ = new_array_pattern_tail(p, $1, 1, $2, $4, &@$);
- /*% ripper: [$:1, $:2, $:4] %*/
- }
- | p_args_tail
- ;
+ {
+ /*%%%*/
+ NODE *pre_args = NEW_LIST($1, &@$);
+ $$ = new_array_pattern_tail(p, pre_args, 0, 0, Qnone, &@$);
+ /*%
+ $$ = new_array_pattern_tail(p, rb_ary_new_from_args(1, get_value($1)), 0, 0, Qnone, &@$);
+ %*/
+ }
+ | p_args_head
+ {
+ $$ = new_array_pattern_tail(p, $1, 1, 0, Qnone, &@$);
+ }
+ | p_args_head p_arg
+ {
+ /*%%%*/
+ $$ = new_array_pattern_tail(p, list_concat($1, $2), 0, 0, Qnone, &@$);
+ /*%
+ VALUE pre_args = rb_ary_concat($1, get_value($2));
+ $$ = new_array_pattern_tail(p, pre_args, 0, 0, Qnone, &@$);
+ %*/
+ }
+ | p_args_head p_rest
+ {
+ $$ = new_array_pattern_tail(p, $1, 1, $2, Qnone, &@$);
+ }
+ | p_args_head p_rest ',' p_args_post
+ {
+ $$ = new_array_pattern_tail(p, $1, 1, $2, $4, &@$);
+ }
+ | p_args_tail
+ ;
p_args_head : p_arg ','
- {
- $$ = $1;
- }
- | p_args_head p_arg ','
- {
- $$ = list_concat($1, $2);
- /*% ripper: rb_ary_concat($:1, $:2) %*/
- }
- ;
+ {
+ $$ = $1;
+ }
+ | p_args_head p_arg ','
+ {
+ /*%%%*/
+ $$ = list_concat($1, $2);
+ /*% %*/
+ /*% ripper: rb_ary_concat($1, get_value($2)) %*/
+ }
+ ;
p_args_tail : p_rest
- {
- $$ = new_array_pattern_tail(p, 0, 1, $1, 0, &@$);
- /*% ripper: [Qnil, $:1, Qnil] %*/
- }
- | p_rest ',' p_args_post
- {
- $$ = new_array_pattern_tail(p, 0, 1, $1, $3, &@$);
- /*% ripper: [Qnil, $:1, $:3] %*/
- }
- ;
+ {
+ $$ = new_array_pattern_tail(p, Qnone, 1, $1, Qnone, &@$);
+ }
+ | p_rest ',' p_args_post
+ {
+ $$ = new_array_pattern_tail(p, Qnone, 1, $1, $3, &@$);
+ }
+ ;
p_find : p_rest ',' p_args_post ',' p_rest
- {
- $$ = new_find_pattern_tail(p, $1, $3, $5, &@$);
- /*% ripper: [$:1, $:3, $:5] %*/
- }
- ;
+ {
+ $$ = new_find_pattern_tail(p, $1, $3, $5, &@$);
+ }
+ ;
p_rest : tSTAR tIDENTIFIER
- {
- error_duplicate_pattern_variable(p, $2, &@2);
- /*% ripper: var_field!($:2) %*/
- $$ = assignable(p, $2, 0, &@$);
- }
- | tSTAR
- {
- $$ = 0;
- /*% ripper: var_field!(Qnil) %*/
- }
- ;
+ {
+ $$ = $2;
+ }
+ | tSTAR
+ {
+ $$ = 0;
+ }
+ ;
p_args_post : p_arg
- | p_args_post ',' p_arg
- {
- $$ = list_concat($1, $3);
- /*% ripper: rb_ary_concat($:1, $:3) %*/
- }
- ;
+ | p_args_post ',' p_arg
+ {
+ /*%%%*/
+ $$ = list_concat($1, $3);
+ /*% %*/
+ /*% ripper: rb_ary_concat($1, get_value($3)) %*/
+ }
+ ;
p_arg : p_expr
- {
- $$ = NEW_LIST($1, &@$);
- /*% ripper: [$:1] %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: rb_ary_new_from_args(1, get_value($1)) %*/
+ }
+ ;
p_kwargs : p_kwarg ',' p_any_kwrest
- {
- $$ = new_hash_pattern_tail(p, new_unique_key_hash(p, $1, &@$), $3, &@$);
- /*% ripper: [$:1, $:3] %*/
- }
- | p_kwarg
- {
- $$ = new_hash_pattern_tail(p, new_unique_key_hash(p, $1, &@$), 0, &@$);
- /*% ripper: [$:1, Qnil] %*/
- }
- | p_kwarg ','
- {
- $$ = new_hash_pattern_tail(p, new_unique_key_hash(p, $1, &@$), 0, &@$);
- /*% ripper: [$:1, Qnil] %*/
- }
- | p_any_kwrest
- {
- $$ = new_hash_pattern_tail(p, new_hash(p, 0, &@$), $1, &@$);
- /*% ripper: [[], $:1] %*/
- }
- ;
+ {
+ $$ = new_hash_pattern_tail(p, new_unique_key_hash(p, $1, &@$), $3, &@$);
+ }
+ | p_kwarg
+ {
+ $$ = new_hash_pattern_tail(p, new_unique_key_hash(p, $1, &@$), 0, &@$);
+ }
+ | p_kwarg ','
+ {
+ $$ = new_hash_pattern_tail(p, new_unique_key_hash(p, $1, &@$), 0, &@$);
+ }
+ | p_any_kwrest
+ {
+ $$ = new_hash_pattern_tail(p, new_hash(p, Qnone, &@$), $1, &@$);
+ }
+ ;
p_kwarg : p_kw
- /*% ripper[brace]: [$:1] %*/
- | p_kwarg ',' p_kw
- {
- $$ = list_concat($1, $3);
- /*% ripper: rb_ary_push($:1, $:3) %*/
- }
- ;
+ /*% ripper[brace]: rb_ary_new_from_args(1, $1) %*/
+ | p_kwarg ',' p_kw
+ {
+ /*%%%*/
+ $$ = list_concat($1, $3);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, $3) %*/
+ }
+ ;
p_kw : p_kw_label p_expr
- {
- error_duplicate_pattern_key(p, $1, &@1);
- $$ = list_append(p, NEW_LIST(NEW_SYM(rb_id2str($1), &@1), &@$), $2);
- /*% ripper: [$:1, $:2] %*/
- }
- | p_kw_label
- {
- error_duplicate_pattern_key(p, $1, &@1);
- if ($1 && !is_local_id($1)) {
- yyerror1(&@1, "key must be valid as local variables");
- }
- error_duplicate_pattern_variable(p, $1, &@1);
- $$ = list_append(p, NEW_LIST(NEW_SYM(rb_id2str($1), &@$), &@$), assignable(p, $1, 0, &@$));
- /*% ripper: [$:1, Qnil] %*/
- }
- ;
+ {
+ error_duplicate_pattern_key(p, get_id($1), &@1);
+ /*%%%*/
+ $$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@1), &@$), $2);
+ /*% %*/
+ /*% ripper: rb_ary_new_from_args(2, get_value($1), get_value($2)) %*/
+ }
+ | p_kw_label
+ {
+ error_duplicate_pattern_key(p, get_id($1), &@1);
+ if ($1 && !is_local_id(get_id($1))) {
+ yyerror1(&@1, "key must be valid as local variables");
+ }
+ error_duplicate_pattern_variable(p, get_id($1), &@1);
+ /*%%%*/
+ $$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@$), &@$), assignable(p, $1, 0, &@$));
+ /*% %*/
+ /*% ripper: rb_ary_new_from_args(2, get_value($1), Qnil) %*/
+ }
+ ;
p_kw_label : tLABEL
- | tSTRING_BEG string_contents tLABEL_END
- {
- YYLTYPE loc = code_loc_gen(&@1, &@3);
- if (!$2 || nd_type_p($2, NODE_STR)) {
- NODE *node = dsym_node(p, $2, &loc);
- $$ = rb_sym2id(rb_node_sym_string_val(node));
- }
- else {
- yyerror1(&loc, "symbol literal with interpolation is not allowed");
- $$ = rb_intern_str(STR_NEW0());
- }
- /*% ripper: $:2 %*/
- }
- ;
+ | tSTRING_BEG string_contents tLABEL_END
+ {
+ YYLTYPE loc = code_loc_gen(&@1, &@3);
+ /*%%%*/
+ if (!$2 || nd_type_p($2, NODE_STR)) {
+ NODE *node = dsym_node(p, $2, &loc);
+ $$ = SYM2ID(node->nd_lit);
+ }
+ /*%
+ if (ripper_is_node_yylval($2) && RNODE($2)->nd_cval) {
+ VALUE label = RNODE($2)->nd_cval;
+ VALUE rval = RNODE($2)->nd_rval;
+ $$ = ripper_new_yylval(p, rb_intern_str(label), rval, label);
+ RNODE($$)->nd_loc = loc;
+ }
+ %*/
+ else {
+ yyerror1(&loc, "symbol literal with interpolation is not allowed");
+ $$ = 0;
+ }
+ }
+ ;
p_kwrest : kwrest_mark tIDENTIFIER
- {
- $$ = $2;
- /*% ripper: var_field!($:2) %*/
- }
- | kwrest_mark
- {
- $$ = 0;
- /*% ripper: Qnil %*/
- }
- ;
+ {
+ $$ = $2;
+ }
+ | kwrest_mark
+ {
+ $$ = 0;
+ }
+ ;
p_kwnorest : kwrest_mark keyword_nil
- {
- $$ = 0;
- }
- ;
+ {
+ $$ = 0;
+ }
+ ;
p_any_kwrest : p_kwrest
- | p_kwnorest
- {
- $$ = idNil;
- /*% ripper: var_field!(ID2VAL(idNil)) %*/
- }
- ;
+ | p_kwnorest {$$ = ID2VAL(idNil);}
+ ;
p_value : p_primitive
- | p_primitive tDOT2 p_primitive
- {
- value_expr($1);
- value_expr($3);
- $$ = NEW_DOT2($1, $3, &@$);
- /*% ripper: dot2!($:1, $:3) %*/
- }
- | p_primitive tDOT3 p_primitive
- {
- value_expr($1);
- value_expr($3);
- $$ = NEW_DOT3($1, $3, &@$);
- /*% ripper: dot3!($:1, $:3) %*/
- }
- | p_primitive tDOT2
- {
- value_expr($1);
- $$ = NEW_DOT2($1, new_nil_at(p, &@2.end_pos), &@$);
- /*% ripper: dot2!($:1, Qnil) %*/
- }
- | p_primitive tDOT3
- {
- value_expr($1);
- $$ = NEW_DOT3($1, new_nil_at(p, &@2.end_pos), &@$);
- /*% ripper: dot3!($:1, Qnil) %*/
- }
- | p_var_ref
- | p_expr_ref
- | p_const
- | tBDOT2 p_primitive
- {
- value_expr($2);
- $$ = NEW_DOT2(new_nil_at(p, &@1.beg_pos), $2, &@$);
- /*% ripper: dot2!(Qnil, $:2) %*/
- }
- | tBDOT3 p_primitive
- {
- value_expr($2);
- $$ = NEW_DOT3(new_nil_at(p, &@1.beg_pos), $2, &@$);
- /*% ripper: dot3!(Qnil, $:2) %*/
- }
- ;
+ | p_primitive tDOT2 p_primitive
+ {
+ /*%%%*/
+ value_expr($1);
+ value_expr($3);
+ $$ = NEW_DOT2($1, $3, &@$);
+ /*% %*/
+ /*% ripper: dot2!($1, $3) %*/
+ }
+ | p_primitive tDOT3 p_primitive
+ {
+ /*%%%*/
+ value_expr($1);
+ value_expr($3);
+ $$ = NEW_DOT3($1, $3, &@$);
+ /*% %*/
+ /*% ripper: dot3!($1, $3) %*/
+ }
+ | p_primitive tDOT2
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = NEW_DOT2($1, new_nil_at(p, &@2.end_pos), &@$);
+ /*% %*/
+ /*% ripper: dot2!($1, Qnil) %*/
+ }
+ | p_primitive tDOT3
+ {
+ /*%%%*/
+ value_expr($1);
+ $$ = NEW_DOT3($1, new_nil_at(p, &@2.end_pos), &@$);
+ /*% %*/
+ /*% ripper: dot3!($1, Qnil) %*/
+ }
+ | p_var_ref
+ | p_expr_ref
+ | p_const
+ | tBDOT2 p_primitive
+ {
+ /*%%%*/
+ value_expr($2);
+ $$ = NEW_DOT2(new_nil_at(p, &@1.beg_pos), $2, &@$);
+ /*% %*/
+ /*% ripper: dot2!(Qnil, $2) %*/
+ }
+ | tBDOT3 p_primitive
+ {
+ /*%%%*/
+ value_expr($2);
+ $$ = NEW_DOT3(new_nil_at(p, &@1.beg_pos), $2, &@$);
+ /*% %*/
+ /*% ripper: dot3!(Qnil, $2) %*/
+ }
+ ;
p_primitive : literal
- | strings
- | xstring
- | regexp
- | words
- | qwords
- | symbols
- | qsymbols
- | keyword_variable
- {
- if (!($$ = gettable(p, $1, &@$))) $$ = NEW_ERROR(&@$);
- /*% ripper: var_ref!($:1) %*/
- }
- | lambda
- ;
+ | strings
+ | xstring
+ | regexp
+ | words
+ | qwords
+ | symbols
+ | qsymbols
+ | keyword_variable
+ {
+ /*%%%*/
+ if (!($$ = gettable(p, $1, &@$))) $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($1) %*/
+ }
+ | lambda
+ ;
p_variable : tIDENTIFIER
- {
- error_duplicate_pattern_variable(p, $1, &@1);
- /*% ripper: var_field!($:1) %*/
- $$ = assignable(p, $1, 0, &@$);
- }
- ;
+ {
+ /*%%%*/
+ error_duplicate_pattern_variable(p, $1, &@1);
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ ;
p_var_ref : '^' tIDENTIFIER
- {
- NODE *n = gettable(p, $2, &@$);
- if (!n) {
- n = NEW_ERROR(&@$);
- }
- else if (!(nd_type_p(n, NODE_LVAR) || nd_type_p(n, NODE_DVAR))) {
- compile_error(p, "%"PRIsVALUE": no such local variable", rb_id2str($2));
- }
- $$ = n;
- /*% ripper: var_ref!($:2) %*/
- }
+ {
+ /*%%%*/
+ NODE *n = gettable(p, $2, &@$);
+ if (!(nd_type_p(n, NODE_LVAR) || nd_type_p(n, NODE_DVAR))) {
+ compile_error(p, "%"PRIsVALUE": no such local variable", rb_id2str($2));
+ }
+ $$ = n;
+ /*% %*/
+ /*% ripper: var_ref!($2) %*/
+ }
| '^' nonlocal_var
- {
- if (!($$ = gettable(p, $2, &@$))) $$ = NEW_ERROR(&@$);
- /*% ripper: var_ref!($:2) %*/
+ {
+ /*%%%*/
+ if (!($$ = gettable(p, $2, &@$))) $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($2) %*/
}
- ;
+ ;
p_expr_ref : '^' tLPAREN expr_value rparen
- {
- $$ = NEW_BLOCK($3, &@$);
- /*% ripper: begin!($:3) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_BEGIN($3, &@$);
+ /*% %*/
+ /*% ripper: begin!($3) %*/
+ }
+ ;
p_const : tCOLON3 cname
- {
- $$ = NEW_COLON3($2, &@$);
- /*% ripper: top_const_ref!($:2) %*/
- }
- | p_const tCOLON2 cname
- {
- $$ = NEW_COLON2($1, $3, &@$);
- /*% ripper: const_path_ref!($:1, $:3) %*/
- }
- | tCONSTANT
- {
- $$ = gettable(p, $1, &@$);
- /*% ripper: var_ref!($:1) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = NEW_COLON3($2, &@$);
+ /*% %*/
+ /*% ripper: top_const_ref!($2) %*/
+ }
+ | p_const tCOLON2 cname
+ {
+ /*%%%*/
+ $$ = NEW_COLON2($1, $3, &@$);
+ /*% %*/
+ /*% ripper: const_path_ref!($1, $3) %*/
+ }
+ | tCONSTANT
+ {
+ /*%%%*/
+ $$ = gettable(p, $1, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($1) %*/
+ }
+ ;
opt_rescue : k_rescue exc_list exc_var then
- compstmt
- opt_rescue
- {
- NODE *err = $3;
- if ($3) {
- err = NEW_ERRINFO(&@3);
- err = node_assign(p, $3, err, NO_LEX_CTXT, &@3);
- }
- $$ = NEW_RESBODY($2, $3, $5, $6, &@$);
+ compstmt
+ opt_rescue
+ {
+ /*%%%*/
+ $$ = NEW_RESBODY($2,
+ $3 ? block_append(p, node_assign(p, $3, NEW_ERRINFO(&@3), NO_LEX_CTXT, &@3), $5) : $5,
+ $6, &@$);
+
if ($2) {
fixpos($$, $2);
}
@@ -5949,942 +4968,1179 @@ opt_rescue : k_rescue exc_list exc_var then
else {
fixpos($$, $5);
}
- /*% ripper: rescue!($:2, $:3, $:5, $:6) %*/
- }
- | none
- ;
+ /*% %*/
+ /*% ripper: rescue!(escape_Qundef($2), escape_Qundef($3), escape_Qundef($5), escape_Qundef($6)) %*/
+ }
+ | none
+ ;
exc_list : arg_value
- {
- $$ = NEW_LIST($1, &@$);
- /*% ripper: rb_ary_new3(1, $:1) %*/
- }
- | mrhs
- {
- if (!($$ = splat_array($1))) $$ = $1;
- }
- | none
- ;
+ {
+ /*%%%*/
+ $$ = NEW_LIST($1, &@$);
+ /*% %*/
+ /*% ripper: rb_ary_new3(1, get_value($1)) %*/
+ }
+ | mrhs
+ {
+ /*%%%*/
+ if (!($$ = splat_array($1))) $$ = $1;
+ /*% %*/
+ /*% ripper: $1 %*/
+ }
+ | none
+ ;
exc_var : tASSOC lhs
- {
- $$ = $2;
- /*% ripper: $:2 %*/
- }
- | none
- ;
-
-opt_ensure : k_ensure stmts terms?
- {
- p->ctxt.in_rescue = $1.in_rescue;
- $$ = $2;
- void_expr(p, void_stmts(p, $$));
- /*% ripper: ensure!($:2) %*/
- }
- | none
- ;
+ {
+ $$ = $2;
+ }
+ | none
+ ;
+
+opt_ensure : k_ensure compstmt
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: ensure!($2) %*/
+ }
+ | none
+ ;
literal : numeric
- | symbol
- ;
+ | symbol
+ ;
strings : string
- {
- NODE *node = $1;
- if (!node) {
- node = NEW_STR(STRING_NEW0(), &@$);
- }
- else {
- node = evstr2dstr(p, node);
- }
- $$ = node;
- /*% ripper: $:1 %*/
- }
- ;
+ {
+ /*%%%*/
+ NODE *node = $1;
+ if (!node) {
+ node = NEW_STR(STR_NEW0(), &@$);
+ RB_OBJ_WRITTEN(p->ast, Qnil, node->nd_lit);
+ }
+ else {
+ node = evstr2dstr(p, node);
+ }
+ $$ = node;
+ /*% %*/
+ /*% ripper: $1 %*/
+ }
+ ;
string : tCHAR
- | string1
- | string string1
- {
- $$ = literal_concat(p, $1, $2, &@$);
- /*% ripper: string_concat!($:1, $:2) %*/
- }
- ;
+ | string1
+ | string string1
+ {
+ /*%%%*/
+ $$ = literal_concat(p, $1, $2, &@$);
+ /*% %*/
+ /*% ripper: string_concat!($1, $2) %*/
+ }
+ ;
string1 : tSTRING_BEG string_contents tSTRING_END
- {
- $$ = heredoc_dedent(p, $2);
- if ($$) nd_set_loc($$, &@$);
- /*% ripper: $:2 %*/
- if (p->heredoc_indent > 0) {
- /*% ripper: heredoc_dedent!($:$, INT2NUM(%{p->heredoc_indent})) %*/
- p->heredoc_indent = 0;
- }
- /*% ripper: string_literal!($:$) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = heredoc_dedent(p, $2);
+ if ($$) nd_set_loc($$, &@$);
+ /*% %*/
+ /*% ripper: string_literal!(heredoc_dedent(p, $2)) %*/
+ }
+ ;
xstring : tXSTRING_BEG xstring_contents tSTRING_END
- {
- $$ = new_xstring(p, heredoc_dedent(p, $2), &@$);
- /*% ripper: $:2 %*/
- if (p->heredoc_indent > 0) {
- /*% ripper: heredoc_dedent!($:$, INT2NUM(%{p->heredoc_indent})) %*/
- p->heredoc_indent = 0;
- }
- /*% ripper: xstring_literal!($:$) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = new_xstring(p, heredoc_dedent(p, $2), &@$);
+ /*% %*/
+ /*% ripper: xstring_literal!(heredoc_dedent(p, $2)) %*/
+ }
+ ;
regexp : tREGEXP_BEG regexp_contents tREGEXP_END
- {
- $$ = new_regexp(p, $2, $3, &@$);
- /*% ripper: regexp_literal!($:2, $:3) %*/
- }
- ;
-
-words : words(tWORDS_BEG, word_list) <node>
- ;
+ {
+ $$ = new_regexp(p, $2, $3, &@$);
+ }
+ ;
+
+words : tWORDS_BEG ' ' word_list tSTRING_END
+ {
+ /*%%%*/
+ $$ = make_list($3, &@$);
+ /*% %*/
+ /*% ripper: array!($3) %*/
+ }
+ ;
word_list : /* none */
- {
- $$ = 0;
- /*% ripper: words_new! %*/
- }
- | word_list word ' '+
- {
- $$ = list_append(p, $1, evstr2dstr(p, $2));
- /*% ripper: words_add!($:1, $:2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: words_new! %*/
+ }
+ | word_list word ' '
+ {
+ /*%%%*/
+ $$ = list_append(p, $1, evstr2dstr(p, $2));
+ /*% %*/
+ /*% ripper: words_add!($1, $2) %*/
+ }
+ ;
word : string_content
- /*% ripper[brace]: word_add!(word_new!, $:1) %*/
- | word string_content
- {
- $$ = literal_concat(p, $1, $2, &@$);
- /*% ripper: word_add!($:1, $:2) %*/
- }
- ;
-
-symbols : words(tSYMBOLS_BEG, symbol_list) <node>
- ;
+ /*% ripper[brace]: word_add!(word_new!, $1) %*/
+ | word string_content
+ {
+ /*%%%*/
+ $$ = literal_concat(p, $1, $2, &@$);
+ /*% %*/
+ /*% ripper: word_add!($1, $2) %*/
+ }
+ ;
+
+symbols : tSYMBOLS_BEG ' ' symbol_list tSTRING_END
+ {
+ /*%%%*/
+ $$ = make_list($3, &@$);
+ /*% %*/
+ /*% ripper: array!($3) %*/
+ }
+ ;
symbol_list : /* none */
- {
- $$ = 0;
- /*% ripper: symbols_new! %*/
- }
- | symbol_list word ' '+
- {
- $$ = symbol_append(p, $1, evstr2dstr(p, $2));
- /*% ripper: symbols_add!($:1, $:2) %*/
- }
- ;
-
-qwords : words(tQWORDS_BEG, qword_list) <node>
- ;
-
-qsymbols : words(tQSYMBOLS_BEG, qsym_list) <node>
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: symbols_new! %*/
+ }
+ | symbol_list word ' '
+ {
+ /*%%%*/
+ $$ = symbol_append(p, $1, evstr2dstr(p, $2));
+ /*% %*/
+ /*% ripper: symbols_add!($1, $2) %*/
+ }
+ ;
+
+qwords : tQWORDS_BEG ' ' qword_list tSTRING_END
+ {
+ /*%%%*/
+ $$ = make_list($3, &@$);
+ /*% %*/
+ /*% ripper: array!($3) %*/
+ }
+ ;
+
+qsymbols : tQSYMBOLS_BEG ' ' qsym_list tSTRING_END
+ {
+ /*%%%*/
+ $$ = make_list($3, &@$);
+ /*% %*/
+ /*% ripper: array!($3) %*/
+ }
+ ;
qword_list : /* none */
- {
- $$ = 0;
- /*% ripper: qwords_new! %*/
- }
- | qword_list tSTRING_CONTENT ' '+
- {
- $$ = list_append(p, $1, $2);
- /*% ripper: qwords_add!($:1, $:2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: qwords_new! %*/
+ }
+ | qword_list tSTRING_CONTENT ' '
+ {
+ /*%%%*/
+ $$ = list_append(p, $1, $2);
+ /*% %*/
+ /*% ripper: qwords_add!($1, $2) %*/
+ }
+ ;
qsym_list : /* none */
- {
- $$ = 0;
- /*% ripper: qsymbols_new! %*/
- }
- | qsym_list tSTRING_CONTENT ' '+
- {
- $$ = symbol_append(p, $1, $2);
- /*% ripper: qsymbols_add!($:1, $:2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: qsymbols_new! %*/
+ }
+ | qsym_list tSTRING_CONTENT ' '
+ {
+ /*%%%*/
+ $$ = symbol_append(p, $1, $2);
+ /*% %*/
+ /*% ripper: qsymbols_add!($1, $2) %*/
+ }
+ ;
string_contents : /* none */
- {
- $$ = 0;
- /*% ripper: string_content! %*/
- }
- | string_contents string_content
- {
- $$ = literal_concat(p, $1, $2, &@$);
- /*% ripper: string_add!($:1, $:2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: string_content! %*/
+ /*%%%*/
+ /*%
+ $$ = ripper_new_yylval(p, 0, $$, 0);
+ %*/
+ }
+ | string_contents string_content
+ {
+ /*%%%*/
+ $$ = literal_concat(p, $1, $2, &@$);
+ /*% %*/
+ /*% ripper: string_add!($1, $2) %*/
+ /*%%%*/
+ /*%
+ if (ripper_is_node_yylval($1) && ripper_is_node_yylval($2) &&
+ !RNODE($1)->nd_cval) {
+ RNODE($1)->nd_cval = RNODE($2)->nd_cval;
+ RNODE($1)->nd_rval = add_mark_object(p, $$);
+ $$ = $1;
+ }
+ %*/
+ }
+ ;
xstring_contents: /* none */
- {
- $$ = 0;
- /*% ripper: xstring_new! %*/
- }
- | xstring_contents string_content
- {
- $$ = literal_concat(p, $1, $2, &@$);
- /*% ripper: xstring_add!($:1, $:2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: xstring_new! %*/
+ }
+ | xstring_contents string_content
+ {
+ /*%%%*/
+ $$ = literal_concat(p, $1, $2, &@$);
+ /*% %*/
+ /*% ripper: xstring_add!($1, $2) %*/
+ }
+ ;
regexp_contents: /* none */
- {
- $$ = 0;
- /*% ripper: regexp_new! %*/
- }
- | regexp_contents string_content
- {
- NODE *head = $1, *tail = $2;
- if (!head) {
- $$ = tail;
- }
- else if (!tail) {
- $$ = head;
- }
- else {
- switch (nd_type(head)) {
- case NODE_STR:
- head = str2dstr(p, head);
- break;
- case NODE_DSTR:
- break;
- default:
- head = list_append(p, NEW_DSTR(0, &@$), head);
- break;
- }
- $$ = list_append(p, head, tail);
- }
- /*% ripper: regexp_add!($:1, $:2) %*/
- }
- ;
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: regexp_new! %*/
+ /*%%%*/
+ /*%
+ $$ = ripper_new_yylval(p, 0, $$, 0);
+ %*/
+ }
+ | regexp_contents string_content
+ {
+ /*%%%*/
+ NODE *head = $1, *tail = $2;
+ if (!head) {
+ $$ = tail;
+ }
+ else if (!tail) {
+ $$ = head;
+ }
+ else {
+ switch (nd_type(head)) {
+ case NODE_STR:
+ nd_set_type(head, NODE_DSTR);
+ break;
+ case NODE_DSTR:
+ break;
+ default:
+ head = list_append(p, NEW_DSTR(Qnil, &@$), head);
+ break;
+ }
+ $$ = list_append(p, head, tail);
+ }
+ /*%
+ VALUE s1 = 1, s2 = 0, n1 = $1, n2 = $2;
+ if (ripper_is_node_yylval(n1)) {
+ s1 = RNODE(n1)->nd_cval;
+ n1 = RNODE(n1)->nd_rval;
+ }
+ if (ripper_is_node_yylval(n2)) {
+ s2 = RNODE(n2)->nd_cval;
+ n2 = RNODE(n2)->nd_rval;
+ }
+ $$ = dispatch2(regexp_add, n1, n2);
+ if (!s1 && s2) {
+ $$ = ripper_new_yylval(p, 0, $$, s2);
+ }
+ %*/
+ }
+ ;
string_content : tSTRING_CONTENT
- /*% ripper[brace]: $:1 %*/
- | tSTRING_DVAR
- {
- /* need to backup p->lex.strterm so that a string literal `%&foo,#$&,bar&` can be parsed */
- $$ = p->lex.strterm;
- p->lex.strterm = 0;
- SET_LEX_STATE(EXPR_BEG);
- }<strterm>
- string_dvar
- {
- p->lex.strterm = $2;
- $$ = NEW_EVSTR($3, &@$);
- nd_set_line($$, @3.end_pos.lineno);
- /*% ripper: string_dvar!($:3) %*/
- }
- | tSTRING_DBEG[state]
- {
- CMDARG_PUSH(0);
- COND_PUSH(0);
- /* need to backup p->lex.strterm so that a string literal `%!foo,#{ !0 },bar!` can be parsed */
- $$ = p->lex.strterm;
- p->lex.strterm = 0;
- SET_LEX_STATE(EXPR_BEG);
- }[term]<strterm>
- {
- $$ = p->lex.brace_nest;
- p->lex.brace_nest = 0;
- }[brace]<num>
- {
- $$ = p->heredoc_indent;
- p->heredoc_indent = 0;
- }[indent]<num>
- compstmt string_dend
- {
- COND_POP();
- CMDARG_POP();
- p->lex.strterm = $term;
- SET_LEX_STATE($state);
- p->lex.brace_nest = $brace;
- p->heredoc_indent = $indent;
- p->heredoc_line_indent = -1;
- if ($compstmt) nd_unset_fl_newline($compstmt);
- $$ = new_evstr(p, $compstmt, &@$);
- /*% ripper: string_embexpr!($:compstmt) %*/
- }
- ;
-
-string_dend : tSTRING_DEND
- | END_OF_INPUT
- ;
-
-string_dvar : nonlocal_var
- {
- if (!($$ = gettable(p, $1, &@$))) $$ = NEW_ERROR(&@$);
- /*% ripper: var_ref!($:1) %*/
- }
- | backref
- ;
+ /*% ripper[brace]: ripper_new_yylval(p, 0, get_value($1), $1) %*/
+ | tSTRING_DVAR
+ {
+ /* need to backup p->lex.strterm so that a string literal `%&foo,#$&,bar&` can be parsed */
+ $<strterm>$ = p->lex.strterm;
+ p->lex.strterm = 0;
+ SET_LEX_STATE(EXPR_BEG);
+ }
+ string_dvar
+ {
+ p->lex.strterm = $<strterm>2;
+ /*%%%*/
+ $$ = NEW_EVSTR($3, &@$);
+ nd_set_line($$, @3.end_pos.lineno);
+ /*% %*/
+ /*% ripper: string_dvar!($3) %*/
+ }
+ | tSTRING_DBEG
+ {
+ CMDARG_PUSH(0);
+ COND_PUSH(0);
+ }
+ {
+ /* need to backup p->lex.strterm so that a string literal `%!foo,#{ !0 },bar!` can be parsed */
+ $<strterm>$ = p->lex.strterm;
+ p->lex.strterm = 0;
+ }
+ {
+ $<num>$ = p->lex.state;
+ SET_LEX_STATE(EXPR_BEG);
+ }
+ {
+ $<num>$ = p->lex.brace_nest;
+ p->lex.brace_nest = 0;
+ }
+ {
+ $<num>$ = p->heredoc_indent;
+ p->heredoc_indent = 0;
+ }
+ compstmt tSTRING_DEND
+ {
+ COND_POP();
+ CMDARG_POP();
+ p->lex.strterm = $<strterm>3;
+ SET_LEX_STATE($<num>4);
+ p->lex.brace_nest = $<num>5;
+ p->heredoc_indent = $<num>6;
+ p->heredoc_line_indent = -1;
+ /*%%%*/
+ if ($7) $7->flags &= ~NODE_FL_NEWLINE;
+ $$ = new_evstr(p, $7, &@$);
+ /*% %*/
+ /*% ripper: string_embexpr!($7) %*/
+ }
+ ;
+
+string_dvar : tGVAR
+ {
+ /*%%%*/
+ $$ = NEW_GVAR($1, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($1) %*/
+ }
+ | tIVAR
+ {
+ /*%%%*/
+ $$ = NEW_IVAR($1, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($1) %*/
+ }
+ | tCVAR
+ {
+ /*%%%*/
+ $$ = NEW_CVAR($1, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($1) %*/
+ }
+ | backref
+ ;
symbol : ssym
- | dsym
- ;
+ | dsym
+ ;
ssym : tSYMBEG sym
- {
- SET_LEX_STATE(EXPR_END);
- VALUE str = rb_id2str($2);
- /*
- * TODO:
- * set_yylval_noname sets invalid id to yylval.
- * This branch can be removed once yylval is changed to
- * hold lexed string.
- */
- if (!str) str = STR_NEW0();
- $$ = NEW_SYM(str, &@$);
- /*% ripper: symbol_literal!(symbol!($:2)) %*/
- }
- ;
+ {
+ SET_LEX_STATE(EXPR_END);
+ /*%%%*/
+ $$ = NEW_LIT(ID2SYM($2), &@$);
+ /*% %*/
+ /*% ripper: symbol_literal!(symbol!($2)) %*/
+ }
+ ;
sym : fname
- | nonlocal_var
- ;
+ | nonlocal_var
+ ;
dsym : tSYMBEG string_contents tSTRING_END
- {
- SET_LEX_STATE(EXPR_END);
- $$ = dsym_node(p, $2, &@$);
- /*% ripper: dyna_symbol!($:2) %*/
- }
- ;
+ {
+ SET_LEX_STATE(EXPR_END);
+ /*%%%*/
+ $$ = dsym_node(p, $2, &@$);
+ /*% %*/
+ /*% ripper: dyna_symbol!($2) %*/
+ }
+ ;
numeric : simple_numeric
- | tUMINUS_NUM simple_numeric %prec tLOWEST
- {
- $$ = $2;
- negate_lit(p, $$);
- /*% ripper: unary!(ID2VAL(idUMinus), $:2) %*/
- }
- ;
+ | tUMINUS_NUM simple_numeric %prec tLOWEST
+ {
+ /*%%%*/
+ $$ = $2;
+ RB_OBJ_WRITE(p->ast, &$$->nd_lit, negate_lit(p, $$->nd_lit));
+ /*% %*/
+ /*% ripper: unary!(ID2VAL(idUMinus), $2) %*/
+ }
+ ;
simple_numeric : tINTEGER
- | tFLOAT
- | tRATIONAL
- | tIMAGINARY
- ;
+ | tFLOAT
+ | tRATIONAL
+ | tIMAGINARY
+ ;
nonlocal_var : tIVAR
- | tGVAR
- | tCVAR
- ;
+ | tGVAR
+ | tCVAR
+ ;
-user_variable : ident_or_const
- | nonlocal_var
- ;
+user_variable : tIDENTIFIER
+ | tCONSTANT
+ | nonlocal_var
+ ;
keyword_variable: keyword_nil {$$ = KWD2EID(nil, $1);}
- | keyword_self {$$ = KWD2EID(self, $1);}
- | keyword_true {$$ = KWD2EID(true, $1);}
- | keyword_false {$$ = KWD2EID(false, $1);}
- | keyword__FILE__ {$$ = KWD2EID(_FILE__, $1);}
- | keyword__LINE__ {$$ = KWD2EID(_LINE__, $1);}
- | keyword__ENCODING__ {$$ = KWD2EID(_ENCODING__, $1);}
- ;
+ | keyword_self {$$ = KWD2EID(self, $1);}
+ | keyword_true {$$ = KWD2EID(true, $1);}
+ | keyword_false {$$ = KWD2EID(false, $1);}
+ | keyword__FILE__ {$$ = KWD2EID(_FILE__, $1);}
+ | keyword__LINE__ {$$ = KWD2EID(_LINE__, $1);}
+ | keyword__ENCODING__ {$$ = KWD2EID(_ENCODING__, $1);}
+ ;
var_ref : user_variable
- {
- if (!($$ = gettable(p, $1, &@$))) $$ = NEW_ERROR(&@$);
- if (ifdef_ripper(id_is_var(p, $1), false)) {
- /*% ripper: var_ref!($:1) %*/
- }
- else {
- /*% ripper: vcall!($:1) %*/
- }
- }
- | keyword_variable
- {
- if (!($$ = gettable(p, $1, &@$))) $$ = NEW_ERROR(&@$);
- /*% ripper: var_ref!($:1) %*/
- }
- ;
-
-var_lhs : user_or_keyword_variable
- {
- /*% ripper: var_field!($:1) %*/
- $$ = assignable(p, $1, 0, &@$);
- }
- ;
+ {
+ /*%%%*/
+ if (!($$ = gettable(p, $1, &@$))) $$ = NEW_BEGIN(0, &@$);
+ /*%
+ if (id_is_var(p, get_id($1))) {
+ $$ = dispatch1(var_ref, $1);
+ }
+ else {
+ $$ = dispatch1(vcall, $1);
+ }
+ %*/
+ }
+ | keyword_variable
+ {
+ /*%%%*/
+ if (!($$ = gettable(p, $1, &@$))) $$ = NEW_BEGIN(0, &@$);
+ /*% %*/
+ /*% ripper: var_ref!($1) %*/
+ }
+ ;
+
+var_lhs : user_variable
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ | keyword_variable
+ {
+ /*%%%*/
+ $$ = assignable(p, $1, 0, &@$);
+ /*% %*/
+ /*% ripper: assignable(p, var_field(p, $1)) %*/
+ }
+ ;
backref : tNTH_REF
- | tBACK_REF
- ;
+ | tBACK_REF
+ ;
superclass : '<'
- {
- SET_LEX_STATE(EXPR_BEG);
- p->command_start = TRUE;
- }
- expr_value term
- {
- $$ = $3;
- /*% ripper: $:3 %*/
- }
- | /* none */
- {
- $$ = 0;
- /*% ripper: Qnil %*/
- }
- ;
+ {
+ SET_LEX_STATE(EXPR_BEG);
+ p->command_start = TRUE;
+ }
+ expr_value term
+ {
+ $$ = $3;
+ }
+ | /* none */
+ {
+ /*%%%*/
+ $$ = 0;
+ /*% %*/
+ /*% ripper: Qnil %*/
+ }
+ ;
f_opt_paren_args: f_paren_args
- | none
- {
- p->ctxt.in_argdef = 0;
- $$ = new_args_tail(p, 0, 0, 0, &@0);
- $$ = new_args(p, 0, 0, 0, 0, $$, &@0);
- /*% ripper: params!(Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil) %*/
- }
- ;
+ | none
+ {
+ p->ctxt.in_argdef = 0;
+ $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
+ $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $$, &@0);
+ }
+ ;
f_paren_args : '(' f_args rparen
- {
- $$ = $2;
- /*% ripper: paren!($:2) %*/
- SET_LEX_STATE(EXPR_BEG);
- p->command_start = TRUE;
- p->ctxt.in_argdef = 0;
- }
+ {
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: paren!($2) %*/
+ SET_LEX_STATE(EXPR_BEG);
+ p->command_start = TRUE;
+ p->ctxt.in_argdef = 0;
+ }
;
f_arglist : f_paren_args
- | {
- $$ = p->ctxt;
- p->ctxt.in_kwarg = 1;
- p->ctxt.in_argdef = 1;
- SET_LEX_STATE(p->lex.state|EXPR_LABEL); /* force for args */
- }<ctxt>
- f_args term
- {
- p->ctxt.in_kwarg = $1.in_kwarg;
- p->ctxt.in_argdef = 0;
- $$ = $2;
- SET_LEX_STATE(EXPR_BEG);
- p->command_start = TRUE;
- /*% ripper: $:2 %*/
- }
- ;
-
-args_tail : f_kwarg(f_kw) ',' f_kwrest opt_f_block_arg
- {
- $$ = new_args_tail(p, $1, $3, $4, &@3);
- /*% ripper: [$:1, $:3, $:4] %*/
- }
- | f_kwarg(f_kw) opt_f_block_arg
- {
- $$ = new_args_tail(p, $1, 0, $2, &@1);
- /*% ripper: [$:1, Qnil, $:2] %*/
- }
- | f_any_kwrest opt_f_block_arg
- {
- $$ = new_args_tail(p, 0, $1, $2, &@1);
- /*% ripper: [Qnil, $:1, $:2] %*/
- }
- | f_block_arg
- {
- $$ = new_args_tail(p, 0, 0, $1, &@1);
- /*% ripper: [Qnil, Qnil, $:1] %*/
- }
- | args_forward
- {
- ID fwd = $args_forward;
- if (lambda_beginning_p() ||
- (p->lex.lpar_beg >= 0 && p->lex.lpar_beg+1 == p->lex.paren_nest)) {
- yyerror0("unexpected ... in lambda argument");
- fwd = 0;
- }
- else {
- add_forwarding_args(p);
- }
- $$ = new_args_tail(p, 0, fwd, arg_FWD_BLOCK, &@1);
- $$->nd_ainfo.forwarding = 1;
- /*% ripper: [Qnil, $:1, Qnil] %*/
- }
- ;
-
-f_args : f_arg ',' f_optarg(arg_value) ',' f_rest_arg opt_args_tail(args_tail)
- {
- $$ = new_args(p, $1, $3, $5, 0, $6, &@$);
- /*% ripper: params!($:1, $:3, $:5, Qnil, *$:6[0..2]) %*/
- }
- | f_arg ',' f_optarg(arg_value) ',' f_rest_arg ',' f_arg opt_args_tail(args_tail)
- {
- $$ = new_args(p, $1, $3, $5, $7, $8, &@$);
- /*% ripper: params!($:1, $:3, $:5, $:7, *$:8[0..2]) %*/
- }
- | f_arg ',' f_optarg(arg_value) opt_args_tail(args_tail)
- {
- $$ = new_args(p, $1, $3, 0, 0, $4, &@$);
- /*% ripper: params!($:1, $:3, Qnil, Qnil, *$:4[0..2]) %*/
- }
- | f_arg ',' f_optarg(arg_value) ',' f_arg opt_args_tail(args_tail)
- {
- $$ = new_args(p, $1, $3, 0, $5, $6, &@$);
- /*% ripper: params!($:1, $:3, Qnil, $:5, *$:6[0..2]) %*/
- }
- | f_arg ',' f_rest_arg opt_args_tail(args_tail)
- {
- $$ = new_args(p, $1, 0, $3, 0, $4, &@$);
- /*% ripper: params!($:1, Qnil, $:3, Qnil, *$:4[0..2]) %*/
- }
- | f_arg ',' f_rest_arg ',' f_arg opt_args_tail(args_tail)
- {
- $$ = new_args(p, $1, 0, $3, $5, $6, &@$);
- /*% ripper: params!($:1, Qnil, $:3, $:5, *$:6[0..2]) %*/
- }
- | f_arg opt_args_tail(args_tail)
- {
- $$ = new_args(p, $1, 0, 0, 0, $2, &@$);
- /*% ripper: params!($:1, Qnil, Qnil, Qnil, *$:2[0..2]) %*/
- }
- | f_optarg(arg_value) ',' f_rest_arg opt_args_tail(args_tail)
- {
- $$ = new_args(p, 0, $1, $3, 0, $4, &@$);
- /*% ripper: params!(Qnil, $:1, $:3, Qnil, *$:4[0..2]) %*/
- }
- | f_optarg(arg_value) ',' f_rest_arg ',' f_arg opt_args_tail(args_tail)
- {
- $$ = new_args(p, 0, $1, $3, $5, $6, &@$);
- /*% ripper: params!(Qnil, $:1, $:3, $:5, *$:6[0..2]) %*/
- }
- | f_optarg(arg_value) opt_args_tail(args_tail)
- {
- $$ = new_args(p, 0, $1, 0, 0, $2, &@$);
- /*% ripper: params!(Qnil, $:1, Qnil, Qnil, *$:2[0..2]) %*/
- }
- | f_optarg(arg_value) ',' f_arg opt_args_tail(args_tail)
- {
- $$ = new_args(p, 0, $1, 0, $3, $4, &@$);
- /*% ripper: params!(Qnil, $:1, Qnil, $:3, *$:4[0..2]) %*/
- }
- | f_rest_arg opt_args_tail(args_tail)
- {
- $$ = new_args(p, 0, 0, $1, 0, $2, &@$);
- /*% ripper: params!(Qnil, Qnil, $:1, Qnil, *$:2[0..2]) %*/
- }
- | f_rest_arg ',' f_arg opt_args_tail(args_tail)
- {
- $$ = new_args(p, 0, 0, $1, $3, $4, &@$);
- /*% ripper: params!(Qnil, Qnil, $:1, $:3, *$:4[0..2]) %*/
- }
- | args_tail
- {
- $$ = new_args(p, 0, 0, 0, 0, $1, &@$);
- /*% ripper: params!(Qnil, Qnil, Qnil, Qnil, *$:1[0..2]) %*/
- }
- | /* none */
- {
- $$ = new_args_tail(p, 0, 0, 0, &@0);
- $$ = new_args(p, 0, 0, 0, 0, $$, &@0);
- /*% ripper: params!(Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil) %*/
- }
- ;
+ | {
+ $<ctxt>$ = p->ctxt;
+ p->ctxt.in_kwarg = 1;
+ p->ctxt.in_argdef = 1;
+ SET_LEX_STATE(p->lex.state|EXPR_LABEL); /* force for args */
+ }
+ f_args term
+ {
+ p->ctxt.in_kwarg = $<ctxt>1.in_kwarg;
+ p->ctxt.in_argdef = 0;
+ $$ = $2;
+ SET_LEX_STATE(EXPR_BEG);
+ p->command_start = TRUE;
+ }
+ ;
+
+args_tail : f_kwarg ',' f_kwrest opt_f_block_arg
+ {
+ $$ = new_args_tail(p, $1, $3, $4, &@3);
+ }
+ | f_kwarg opt_f_block_arg
+ {
+ $$ = new_args_tail(p, $1, Qnone, $2, &@1);
+ }
+ | f_any_kwrest opt_f_block_arg
+ {
+ $$ = new_args_tail(p, Qnone, $1, $2, &@1);
+ }
+ | f_block_arg
+ {
+ $$ = new_args_tail(p, Qnone, Qnone, $1, &@1);
+ }
+ | args_forward
+ {
+ add_forwarding_args(p);
+ $$ = new_args_tail(p, Qnone, $1, ID2VAL(idFWD_BLOCK), &@1);
+ /*%%%*/
+ ($$->nd_ainfo)->forwarding = 1;
+ /*% %*/
+ }
+ ;
+
+opt_args_tail : ',' args_tail
+ {
+ $$ = $2;
+ }
+ | /* none */
+ {
+ $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
+ }
+ ;
+
+f_args : f_arg ',' f_optarg ',' f_rest_arg opt_args_tail
+ {
+ $$ = new_args(p, $1, $3, $5, Qnone, $6, &@$);
+ }
+ | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
+ {
+ $$ = new_args(p, $1, $3, $5, $7, $8, &@$);
+ }
+ | f_arg ',' f_optarg opt_args_tail
+ {
+ $$ = new_args(p, $1, $3, Qnone, Qnone, $4, &@$);
+ }
+ | f_arg ',' f_optarg ',' f_arg opt_args_tail
+ {
+ $$ = new_args(p, $1, $3, Qnone, $5, $6, &@$);
+ }
+ | f_arg ',' f_rest_arg opt_args_tail
+ {
+ $$ = new_args(p, $1, Qnone, $3, Qnone, $4, &@$);
+ }
+ | f_arg ',' f_rest_arg ',' f_arg opt_args_tail
+ {
+ $$ = new_args(p, $1, Qnone, $3, $5, $6, &@$);
+ }
+ | f_arg opt_args_tail
+ {
+ $$ = new_args(p, $1, Qnone, Qnone, Qnone, $2, &@$);
+ }
+ | f_optarg ',' f_rest_arg opt_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, $3, Qnone, $4, &@$);
+ }
+ | f_optarg ',' f_rest_arg ',' f_arg opt_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, $3, $5, $6, &@$);
+ }
+ | f_optarg opt_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, Qnone, Qnone, $2, &@$);
+ }
+ | f_optarg ',' f_arg opt_args_tail
+ {
+ $$ = new_args(p, Qnone, $1, Qnone, $3, $4, &@$);
+ }
+ | f_rest_arg opt_args_tail
+ {
+ $$ = new_args(p, Qnone, Qnone, $1, Qnone, $2, &@$);
+ }
+ | f_rest_arg ',' f_arg opt_args_tail
+ {
+ $$ = new_args(p, Qnone, Qnone, $1, $3, $4, &@$);
+ }
+ | args_tail
+ {
+ $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $1, &@$);
+ }
+ | /* none */
+ {
+ $$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
+ $$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $$, &@0);
+ }
+ ;
args_forward : tBDOT3
- {
+ {
+ /*%%%*/
#ifdef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
- $$ = 0;
+ $$ = 0;
#else
- $$ = idFWD_KWREST;
+ $$ = idFWD_KWREST;
#endif
- /*% ripper: args_forward! %*/
- }
- ;
+ /*% %*/
+ /*% ripper: args_forward! %*/
+ }
+ ;
f_bad_arg : tCONSTANT
- {
- static const char mesg[] = "formal argument cannot be a constant";
- /*%%%*/
- yyerror1(&@1, mesg);
- /*% %*/
- $$ = 0;
- /*% ripper[error]: param_error!(ERR_MESG(), $:1) %*/
- }
- | tIVAR
- {
- static const char mesg[] = "formal argument cannot be an instance variable";
- /*%%%*/
- yyerror1(&@1, mesg);
- /*% %*/
- $$ = 0;
- /*% ripper[error]: param_error!(ERR_MESG(), $:1) %*/
- }
- | tGVAR
- {
- static const char mesg[] = "formal argument cannot be a global variable";
- /*%%%*/
- yyerror1(&@1, mesg);
- /*% %*/
- $$ = 0;
- /*% ripper[error]: param_error!(ERR_MESG(), $:1) %*/
- }
- | tCVAR
- {
- static const char mesg[] = "formal argument cannot be a class variable";
- /*%%%*/
- yyerror1(&@1, mesg);
- /*% %*/
- $$ = 0;
- /*% ripper[error]: param_error!(ERR_MESG(), $:1) %*/
- }
- ;
+ {
+ static const char mesg[] = "formal argument cannot be a constant";
+ /*%%%*/
+ yyerror1(&@1, mesg);
+ $$ = 0;
+ /*% %*/
+ /*% ripper[error]: param_error!(ERR_MESG(), $1) %*/
+ }
+ | tIVAR
+ {
+ static const char mesg[] = "formal argument cannot be an instance variable";
+ /*%%%*/
+ yyerror1(&@1, mesg);
+ $$ = 0;
+ /*% %*/
+ /*% ripper[error]: param_error!(ERR_MESG(), $1) %*/
+ }
+ | tGVAR
+ {
+ static const char mesg[] = "formal argument cannot be a global variable";
+ /*%%%*/
+ yyerror1(&@1, mesg);
+ $$ = 0;
+ /*% %*/
+ /*% ripper[error]: param_error!(ERR_MESG(), $1) %*/
+ }
+ | tCVAR
+ {
+ static const char mesg[] = "formal argument cannot be a class variable";
+ /*%%%*/
+ yyerror1(&@1, mesg);
+ $$ = 0;
+ /*% %*/
+ /*% ripper[error]: param_error!(ERR_MESG(), $1) %*/
+ }
+ ;
f_norm_arg : f_bad_arg
- | tIDENTIFIER
- {
- VALUE e = formal_argument_error(p, $$ = $1);
- if (e) {
- /*% ripper[error]: param_error!(?e, $:1) %*/
- }
- p->max_numparam = ORDINAL_PARAM;
- }
- ;
+ | tIDENTIFIER
+ {
+ formal_argument(p, $1);
+ p->max_numparam = ORDINAL_PARAM;
+ $$ = $1;
+ }
+ ;
f_arg_asgn : f_norm_arg
- {
- ID id = $1;
- arg_var(p, id);
- $$ = $1;
- }
- ;
+ {
+ ID id = get_id($1);
+ arg_var(p, id);
+ p->cur_arg = id;
+ $$ = $1;
+ }
+ ;
f_arg_item : f_arg_asgn
- {
- $$ = NEW_ARGS_AUX($1, 1, &NULL_LOC);
- /*% ripper: $:1 %*/
- }
- | tLPAREN f_margs rparen
- {
- ID tid = internal_id(p);
- YYLTYPE loc;
- loc.beg_pos = @2.beg_pos;
- loc.end_pos = @2.beg_pos;
- arg_var(p, tid);
- if (dyna_in_block(p)) {
- $2->nd_value = NEW_DVAR(tid, &loc);
- }
- else {
- $2->nd_value = NEW_LVAR(tid, &loc);
- }
- $$ = NEW_ARGS_AUX(tid, 1, &NULL_LOC);
- $$->nd_next = (NODE *)$2;
- /*% ripper: mlhs_paren!($:2) %*/
- }
- ;
+ {
+ p->cur_arg = 0;
+ /*%%%*/
+ $$ = NEW_ARGS_AUX($1, 1, &NULL_LOC);
+ /*% %*/
+ /*% ripper: get_value($1) %*/
+ }
+ | tLPAREN f_margs rparen
+ {
+ /*%%%*/
+ ID tid = internal_id(p);
+ YYLTYPE loc;
+ loc.beg_pos = @2.beg_pos;
+ loc.end_pos = @2.beg_pos;
+ arg_var(p, tid);
+ if (dyna_in_block(p)) {
+ $2->nd_value = NEW_DVAR(tid, &loc);
+ }
+ else {
+ $2->nd_value = NEW_LVAR(tid, &loc);
+ }
+ $$ = NEW_ARGS_AUX(tid, 1, &NULL_LOC);
+ $$->nd_next = $2;
+ /*% %*/
+ /*% ripper: mlhs_paren!($2) %*/
+ }
+ ;
f_arg : f_arg_item
- /*% ripper[brace]: rb_ary_new3(1, $:1) %*/
- | f_arg ',' f_arg_item
- {
- $$ = $1;
- $$->nd_plen++;
- $$->nd_next = block_append(p, $$->nd_next, $3->nd_next);
- rb_discard_node(p, (NODE *)$3);
- /*% ripper: rb_ary_push($:1, $:3) %*/
- }
- ;
+ /*% ripper[brace]: rb_ary_new3(1, get_value($1)) %*/
+ | f_arg ',' f_arg_item
+ {
+ /*%%%*/
+ $$ = $1;
+ $$->nd_plen++;
+ $$->nd_next = block_append(p, $$->nd_next, $3->nd_next);
+ rb_discard_node(p, $3);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($3)) %*/
+ }
+ ;
f_label : tLABEL
- {
- VALUE e = formal_argument_error(p, $$ = $1);
- if (e) {
- $$ = 0;
- /*% ripper[error]: param_error!(?e, $:1) %*/
- }
- /*
- * Workaround for Prism::ParseTest#test_filepath for
- * "unparser/corpus/literal/def.txt"
- *
- * See the discussion on https://github.com/ruby/ruby/pull/9923
- */
- arg_var(p, ifdef_ripper(0, $1));
- /*% ripper: $:1 %*/
- p->max_numparam = ORDINAL_PARAM;
- p->ctxt.in_argdef = 0;
- }
- ;
+ {
+ arg_var(p, formal_argument(p, $1));
+ p->cur_arg = get_id($1);
+ p->max_numparam = ORDINAL_PARAM;
+ p->ctxt.in_argdef = 0;
+ $$ = $1;
+ }
+ ;
f_kw : f_label arg_value
- {
- p->ctxt.in_argdef = 1;
- $$ = new_kw_arg(p, assignable(p, $1, $2, &@$), &@$);
- /*% ripper: [$:$, $:2] %*/
- }
- | f_label
- {
- p->ctxt.in_argdef = 1;
- $$ = new_kw_arg(p, assignable(p, $1, NODE_SPECIAL_REQUIRED_KEYWORD, &@$), &@$);
- /*% ripper: [$:$, 0] %*/
- }
- ;
+ {
+ p->cur_arg = 0;
+ p->ctxt.in_argdef = 1;
+ /*%%%*/
+ $$ = new_kw_arg(p, assignable(p, $1, $2, &@$), &@$);
+ /*% %*/
+ /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), get_value($2)) %*/
+ }
+ | f_label
+ {
+ p->cur_arg = 0;
+ p->ctxt.in_argdef = 1;
+ /*%%%*/
+ $$ = new_kw_arg(p, assignable(p, $1, NODE_SPECIAL_REQUIRED_KEYWORD, &@$), &@$);
+ /*% %*/
+ /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), 0) %*/
+ }
+ ;
f_block_kw : f_label primary_value
- {
- p->ctxt.in_argdef = 1;
- $$ = new_kw_arg(p, assignable(p, $1, $2, &@$), &@$);
- /*% ripper: [$:$, $:2] %*/
- }
- | f_label
- {
- p->ctxt.in_argdef = 1;
- $$ = new_kw_arg(p, assignable(p, $1, NODE_SPECIAL_REQUIRED_KEYWORD, &@$), &@$);
- /*% ripper: [$:$, 0] %*/
- }
- ;
+ {
+ p->ctxt.in_argdef = 1;
+ /*%%%*/
+ $$ = new_kw_arg(p, assignable(p, $1, $2, &@$), &@$);
+ /*% %*/
+ /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), get_value($2)) %*/
+ }
+ | f_label
+ {
+ p->ctxt.in_argdef = 1;
+ /*%%%*/
+ $$ = new_kw_arg(p, assignable(p, $1, NODE_SPECIAL_REQUIRED_KEYWORD, &@$), &@$);
+ /*% %*/
+ /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), 0) %*/
+ }
+ ;
+
+f_block_kwarg : f_block_kw
+ {
+ /*%%%*/
+ $$ = $1;
+ /*% %*/
+ /*% ripper: rb_ary_new3(1, get_value($1)) %*/
+ }
+ | f_block_kwarg ',' f_block_kw
+ {
+ /*%%%*/
+ $$ = kwd_append($1, $3);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($3)) %*/
+ }
+ ;
+
+
+f_kwarg : f_kw
+ {
+ /*%%%*/
+ $$ = $1;
+ /*% %*/
+ /*% ripper: rb_ary_new3(1, get_value($1)) %*/
+ }
+ | f_kwarg ',' f_kw
+ {
+ /*%%%*/
+ $$ = kwd_append($1, $3);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($3)) %*/
+ }
+ ;
kwrest_mark : tPOW
- | tDSTAR
- ;
+ | tDSTAR
+ ;
f_no_kwarg : p_kwnorest
- {
- /*% ripper: nokw_param!(Qnil) %*/
- }
- ;
+ {
+ /*%%%*/
+ /*% %*/
+ /*% ripper: nokw_param!(Qnil) %*/
+ }
+ ;
f_kwrest : kwrest_mark tIDENTIFIER
- {
- arg_var(p, shadowing_lvar(p, $2));
- $$ = $2;
- /*% ripper: kwrest_param!($:2) %*/
- }
- | kwrest_mark
- {
- arg_var(p, idFWD_KWREST);
- $$ = idFWD_KWREST;
- /*% ripper: kwrest_param!(Qnil) %*/
- }
- ;
+ {
+ arg_var(p, shadowing_lvar(p, get_id($2)));
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: kwrest_param!($2) %*/
+ }
+ | kwrest_mark
+ {
+ arg_var(p, idFWD_KWREST);
+ /*%%%*/
+ $$ = idFWD_KWREST;
+ /*% %*/
+ /*% ripper: kwrest_param!(Qnil) %*/
+ }
+ ;
+
+f_opt : f_arg_asgn f_eq arg_value
+ {
+ p->cur_arg = 0;
+ p->ctxt.in_argdef = 1;
+ /*%%%*/
+ $$ = NEW_OPT_ARG(0, assignable(p, $1, $3, &@$), &@$);
+ /*% %*/
+ /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), get_value($3)) %*/
+ }
+ ;
+
+f_block_opt : f_arg_asgn f_eq primary_value
+ {
+ p->cur_arg = 0;
+ p->ctxt.in_argdef = 1;
+ /*%%%*/
+ $$ = NEW_OPT_ARG(0, assignable(p, $1, $3, &@$), &@$);
+ /*% %*/
+ /*% ripper: rb_assoc_new(get_value(assignable(p, $1)), get_value($3)) %*/
+ }
+ ;
+
+f_block_optarg : f_block_opt
+ {
+ /*%%%*/
+ $$ = $1;
+ /*% %*/
+ /*% ripper: rb_ary_new3(1, get_value($1)) %*/
+ }
+ | f_block_optarg ',' f_block_opt
+ {
+ /*%%%*/
+ $$ = opt_arg_append($1, $3);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($3)) %*/
+ }
+ ;
+
+f_optarg : f_opt
+ {
+ /*%%%*/
+ $$ = $1;
+ /*% %*/
+ /*% ripper: rb_ary_new3(1, get_value($1)) %*/
+ }
+ | f_optarg ',' f_opt
+ {
+ /*%%%*/
+ $$ = opt_arg_append($1, $3);
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($3)) %*/
+ }
+ ;
restarg_mark : '*'
- | tSTAR
- ;
+ | tSTAR
+ ;
f_rest_arg : restarg_mark tIDENTIFIER
- {
- arg_var(p, shadowing_lvar(p, $2));
- $$ = $2;
- /*% ripper: rest_param!($:2) %*/
- }
- | restarg_mark
- {
- arg_var(p, idFWD_REST);
- $$ = idFWD_REST;
- /*% ripper: rest_param!(Qnil) %*/
- }
- ;
+ {
+ arg_var(p, shadowing_lvar(p, get_id($2)));
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: rest_param!($2) %*/
+ }
+ | restarg_mark
+ {
+ arg_var(p, idFWD_REST);
+ /*%%%*/
+ $$ = idFWD_REST;
+ /*% %*/
+ /*% ripper: rest_param!(Qnil) %*/
+ }
+ ;
blkarg_mark : '&'
- | tAMPER
- ;
+ | tAMPER
+ ;
f_block_arg : blkarg_mark tIDENTIFIER
- {
- arg_var(p, shadowing_lvar(p, $2));
- $$ = $2;
- /*% ripper: blockarg!($:2) %*/
- }
+ {
+ arg_var(p, shadowing_lvar(p, get_id($2)));
+ /*%%%*/
+ $$ = $2;
+ /*% %*/
+ /*% ripper: blockarg!($2) %*/
+ }
| blkarg_mark
{
- arg_var(p, idFWD_BLOCK);
- $$ = idFWD_BLOCK;
- /*% ripper: blockarg!(Qnil) %*/
+ arg_var(p, idFWD_BLOCK);
+ /*%%%*/
+ $$ = idFWD_BLOCK;
+ /*% %*/
+ /*% ripper: blockarg!(Qnil) %*/
}
- ;
+ ;
opt_f_block_arg : ',' f_block_arg
- {
- $$ = $2;
- /*% ripper: $:2 %*/
- }
- | none
- {
- $$ = 0;
- /*% ripper: Qnil %*/
- }
- ;
+ {
+ $$ = $2;
+ }
+ | none
+ {
+ $$ = Qnull;
+ }
+ ;
singleton : var_ref
- {
- value_expr($1);
- $$ = $1;
- }
- | '('
- {
- SET_LEX_STATE(EXPR_BEG);
- p->ctxt.in_argdef = 0;
- }
- expr rparen
- {
- p->ctxt.in_argdef = 1;
- NODE *expr = last_expr_node($3);
- switch (nd_type(expr)) {
- case NODE_STR:
- case NODE_DSTR:
- case NODE_XSTR:
- case NODE_DXSTR:
- case NODE_REGX:
- case NODE_DREGX:
- case NODE_SYM:
- case NODE_LINE:
- case NODE_FILE:
- case NODE_ENCODING:
- case NODE_INTEGER:
- case NODE_FLOAT:
- case NODE_RATIONAL:
- case NODE_IMAGINARY:
- case NODE_DSYM:
- case NODE_LIST:
- case NODE_ZLIST:
- yyerror1(&expr->nd_loc, "can't define singleton method for literals");
- break;
- default:
- value_expr($3);
- break;
- }
- $$ = $3;
- /*% ripper: paren!($:3) %*/
- }
- ;
+ {
+ value_expr($1);
+ $$ = $1;
+ }
+ | '(' {SET_LEX_STATE(EXPR_BEG);} expr rparen
+ {
+ /*%%%*/
+ switch (nd_type($3)) {
+ case NODE_STR:
+ case NODE_DSTR:
+ case NODE_XSTR:
+ case NODE_DXSTR:
+ case NODE_DREGX:
+ case NODE_LIT:
+ case NODE_LIST:
+ case NODE_ZLIST:
+ yyerror1(&@3, "can't define singleton method for literals");
+ break;
+ default:
+ value_expr($3);
+ break;
+ }
+ $$ = $3;
+ /*% %*/
+ /*% ripper: paren!($3) %*/
+ }
+ ;
assoc_list : none
- | assocs trailer
- {
- $$ = $1;
- /*% ripper: assoclist_from_args!($:1) %*/
- }
- ;
+ | assocs trailer
+ {
+ /*%%%*/
+ $$ = $1;
+ /*% %*/
+ /*% ripper: assoclist_from_args!($1) %*/
+ }
+ ;
assocs : assoc
- /*% ripper[brace]: rb_ary_new3(1, $:1) %*/
- | assocs ',' assoc
- {
- NODE *assocs = $1;
- NODE *tail = $3;
- if (!assocs) {
- assocs = tail;
- }
- else if (tail) {
- if (RNODE_LIST(assocs)->nd_head) {
- NODE *n = RNODE_LIST(tail)->nd_next;
- if (!RNODE_LIST(tail)->nd_head && nd_type_p(n, NODE_LIST) &&
- nd_type_p((n = RNODE_LIST(n)->nd_head), NODE_HASH)) {
- /* DSTAR */
- tail = RNODE_HASH(n)->nd_head;
- }
+ /*% ripper[brace]: rb_ary_new3(1, get_value($1)) %*/
+ | assocs ',' assoc
+ {
+ /*%%%*/
+ NODE *assocs = $1;
+ NODE *tail = $3;
+ if (!assocs) {
+ assocs = tail;
+ }
+ else if (tail) {
+ if (assocs->nd_head &&
+ !tail->nd_head && nd_type_p(tail->nd_next, NODE_LIST) &&
+ nd_type_p(tail->nd_next->nd_head, NODE_HASH)) {
+ /* DSTAR */
+ tail = tail->nd_next->nd_head->nd_head;
}
- if (tail) {
- assocs = list_concat(assocs, tail);
- }
- }
- $$ = assocs;
- /*% ripper: rb_ary_push($:1, $:3) %*/
- }
- ;
+ assocs = list_concat(assocs, tail);
+ }
+ $$ = assocs;
+ /*% %*/
+ /*% ripper: rb_ary_push($1, get_value($3)) %*/
+ }
+ ;
assoc : arg_value tASSOC arg_value
- {
- $$ = list_append(p, NEW_LIST($1, &@$), $3);
- /*% ripper: assoc_new!($:1, $:3) %*/
- }
- | tLABEL arg_value
- {
- $$ = list_append(p, NEW_LIST(NEW_SYM(rb_id2str($1), &@1), &@$), $2);
- /*% ripper: assoc_new!($:1, $:2) %*/
- }
- | tLABEL
- {
- NODE *val = gettable(p, $1, &@$);
- if (!val) val = NEW_ERROR(&@$);
- $$ = list_append(p, NEW_LIST(NEW_SYM(rb_id2str($1), &@1), &@$), val);
- /*% ripper: assoc_new!($:1, Qnil) %*/
- }
- | tSTRING_BEG string_contents tLABEL_END arg_value
- {
- YYLTYPE loc = code_loc_gen(&@1, &@3);
- $$ = list_append(p, NEW_LIST(dsym_node(p, $2, &loc), &loc), $4);
- /*% ripper: assoc_new!(dyna_symbol!($:2), $:4) %*/
- }
- | tDSTAR arg_value
- {
- $$ = list_append(p, NEW_LIST(0, &@$), $2);
- /*% ripper: assoc_splat!($:2) %*/
- }
- | tDSTAR
- {
- forwarding_arg_check(p, idFWD_KWREST, idFWD_ALL, "keyword rest");
+ {
+ /*%%%*/
+ if (nd_type_p($1, NODE_STR)) {
+ nd_set_type($1, NODE_LIT);
+ RB_OBJ_WRITE(p->ast, &$1->nd_lit, rb_fstring($1->nd_lit));
+ }
+ $$ = list_append(p, NEW_LIST($1, &@$), $3);
+ /*% %*/
+ /*% ripper: assoc_new!($1, $3) %*/
+ }
+ | tLABEL arg_value
+ {
+ /*%%%*/
+ $$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@1), &@$), $2);
+ /*% %*/
+ /*% ripper: assoc_new!($1, $2) %*/
+ }
+ | tLABEL
+ {
+ /*%%%*/
+ NODE *val = gettable(p, $1, &@$);
+ if (!val) val = NEW_BEGIN(0, &@$);
+ $$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@1), &@$), val);
+ /*% %*/
+ /*% ripper: assoc_new!($1, Qnil) %*/
+ }
+ | tSTRING_BEG string_contents tLABEL_END arg_value
+ {
+ /*%%%*/
+ YYLTYPE loc = code_loc_gen(&@1, &@3);
+ $$ = list_append(p, NEW_LIST(dsym_node(p, $2, &loc), &loc), $4);
+ /*% %*/
+ /*% ripper: assoc_new!(dyna_symbol!($2), $4) %*/
+ }
+ | tDSTAR arg_value
+ {
+ /*%%%*/
+ if (nd_type_p($2, NODE_HASH) &&
+ !($2->nd_head && $2->nd_head->nd_alen)) {
+ static VALUE empty_hash;
+ if (!empty_hash) {
+ empty_hash = rb_obj_freeze(rb_hash_new());
+ rb_gc_register_mark_object(empty_hash);
+ }
+ $$ = list_append(p, NEW_LIST(0, &@$), NEW_LIT(empty_hash, &@$));
+ }
+ else
+ $$ = list_append(p, NEW_LIST(0, &@$), $2);
+ /*% %*/
+ /*% ripper: assoc_splat!($2) %*/
+ }
+ | tDSTAR
+ {
+ if (!local_id(p, idFWD_KWREST) ||
+ local_id(p, idFWD_ALL)) {
+ compile_error(p, "no anonymous keyword rest parameter");
+ }
+ /*%%%*/
$$ = list_append(p, NEW_LIST(0, &@$),
NEW_LVAR(idFWD_KWREST, &@$));
- /*% ripper: assoc_splat!(Qnil) %*/
- }
- ;
+ /*% %*/
+ /*% ripper: assoc_splat!(Qnil) %*/
+ }
+ ;
-operation : ident_or_const
- | tFID
- ;
+operation : tIDENTIFIER
+ | tCONSTANT
+ | tFID
+ ;
operation2 : operation
- | op
- ;
+ | op
+ ;
operation3 : tIDENTIFIER
- | tFID
- | op
- ;
+ | tFID
+ | op
+ ;
dot_or_colon : '.'
- | tCOLON2
- ;
+ | tCOLON2
+ ;
call_op : '.'
- | tANDDOT
- ;
+ | tANDDOT
+ ;
call_op2 : call_op
- | tCOLON2
- ;
+ | tCOLON2
+ ;
-rparen : '\n'? ')'
- ;
+opt_terms : /* none */
+ | terms
+ ;
-rbracket : '\n'? ']'
- ;
+opt_nl : /* none */
+ | '\n'
+ ;
-rbrace : '\n'? '}'
- ;
+rparen : opt_nl ')'
+ ;
-trailer : '\n'?
- | ','
- ;
+rbracket : opt_nl ']'
+ ;
+
+rbrace : opt_nl '}'
+ ;
+
+trailer : opt_nl
+ | ','
+ ;
term : ';' {yyerrok;token_flush(p);}
- | '\n'
- {
- @$.end_pos = @$.beg_pos;
- token_flush(p);
- }
- ;
+ | '\n'
+ {
+ @$.end_pos = @$.beg_pos;
+ token_flush(p);
+ }
+ ;
terms : term
- | terms ';' {yyerrok;}
- ;
+ | terms ';' {yyerrok;}
+ ;
none : /* none */
- {
- $$ = 0;
- }
- ;
+ {
+ $$ = Qnull;
+ }
+ ;
%%
# undef p
# undef yylex
@@ -6897,32 +6153,44 @@ static void tokaddmbc(struct parser_params *p, int c, rb_encoding *enc);
static enum yytokentype parse_string(struct parser_params*,rb_strterm_literal_t*);
static enum yytokentype here_document(struct parser_params*,rb_strterm_heredoc_t*);
-#define set_parser_s_value(x) (ifdef_ripper(p->s_value = (x), (void)0))
-
+#ifndef RIPPER
# define set_yylval_node(x) { \
YYLTYPE _cur_loc; \
rb_parser_set_location(p, &_cur_loc); \
yylval.node = (x); \
- set_parser_s_value(STR_NEW(p->lex.ptok, p->lex.pcur-p->lex.ptok)); \
}
# define set_yylval_str(x) \
do { \
set_yylval_node(NEW_STR(x, &_cur_loc)); \
- set_parser_s_value(rb_str_new_mutable_parser_string(x)); \
+ RB_OBJ_WRITTEN(p->ast, Qnil, x); \
} while(0)
-# define set_yylval_num(x) { \
- yylval.num = (x); \
- set_parser_s_value(x); \
-}
-# define set_yylval_id(x) (yylval.id = (x))
-# define set_yylval_name(x) { \
- (yylval.id = (x)); \
- set_parser_s_value(ID2SYM(x)); \
-}
+# define set_yylval_literal(x) \
+do { \
+ set_yylval_node(NEW_LIT(x, &_cur_loc)); \
+ RB_OBJ_WRITTEN(p->ast, Qnil, x); \
+} while(0)
+# define set_yylval_num(x) (yylval.num = (x))
+# define set_yylval_id(x) (yylval.id = (x))
+# define set_yylval_name(x) (yylval.id = (x))
# define yylval_id() (yylval.id)
+#else
+static inline VALUE
+ripper_yylval_id(struct parser_params *p, ID x)
+{
+ return ripper_new_yylval(p, x, ID2SYM(x), 0);
+}
+# define set_yylval_str(x) (yylval.val = add_mark_object(p, (x)))
+# define set_yylval_num(x) (yylval.val = ripper_new_yylval(p, (x), 0, 0))
+# define set_yylval_id(x) (void)(x)
+# define set_yylval_name(x) (void)(yylval.val = ripper_yylval_id(p, x))
+# define set_yylval_literal(x) add_mark_object(p, (x))
+# define set_yylval_node(x) (yylval.val = ripper_new_yylval(p, 0, 0, STR_NEW(p->lex.ptok, p->lex.pcur-p->lex.ptok)))
+# define yylval_id() yylval.id
+# define _cur_loc NULL_LOC /* dummy */
+#endif
#define set_yylval_noname() set_yylval_id(keyword_nil)
-#define has_delayed_token(p) (p->delayed.token != NULL)
+#define has_delayed_token(p) (!NIL_P(p->delayed.token))
#ifndef RIPPER
#define literal_flush(p, ptr) ((p)->lex.ptok = (ptr))
@@ -6931,108 +6199,39 @@ do { \
static bool
parser_has_token(struct parser_params *p)
{
- const char *const pcur = p->lex.pcur;
- const char *const ptok = p->lex.ptok;
- if (p->keep_tokens && (pcur < ptok)) {
- rb_bug("lex.pcur < lex.ptok. (line: %d) %"PRIdPTRDIFF"|%"PRIdPTRDIFF"|%"PRIdPTRDIFF"",
- p->ruby_sourceline, ptok - p->lex.pbeg, pcur - ptok, p->lex.pend - pcur);
- }
- return pcur > ptok;
+ if (p->keep_tokens && (p->lex.pcur < p->lex.ptok)) rb_bug("lex.pcur < lex.ptok. (line: %d) %ld|%ld|%ld", p->ruby_sourceline, p->lex.ptok - p->lex.pbeg, p->lex.pcur - p->lex.ptok, p->lex.pend - p->lex.pcur);
+ return p->lex.pcur > p->lex.ptok;
}
-static const char *
-escaped_char(int c)
+static VALUE
+code_loc_to_ary(const rb_code_location_t *loc)
{
- switch (c) {
- case '"': return "\\\"";
- case '\\': return "\\\\";
- case '\0': return "\\0";
- case '\n': return "\\n";
- case '\r': return "\\r";
- case '\t': return "\\t";
- case '\f': return "\\f";
- case '\013': return "\\v";
- case '\010': return "\\b";
- case '\007': return "\\a";
- case '\033': return "\\e";
- case '\x7f': return "\\c?";
- }
- return NULL;
-}
+ VALUE ary = rb_ary_new_from_args(4,
+ INT2NUM(loc->beg_pos.lineno), INT2NUM(loc->beg_pos.column),
+ INT2NUM(loc->end_pos.lineno), INT2NUM(loc->end_pos.column));
+ rb_obj_freeze(ary);
-static rb_parser_string_t *
-rb_parser_str_escape(struct parser_params *p, rb_parser_string_t *str)
-{
- rb_encoding *enc = p->enc;
- const char *ptr = str->ptr;
- const char *pend = ptr + str->len;
- const char *prev = ptr;
- char charbuf[5] = {'\\', 'x', 0, 0, 0};
- rb_parser_string_t * result = rb_parser_string_new(p, 0, 0);
-
- while (ptr < pend) {
- unsigned int c;
- const char *cc;
- int n = rb_enc_precise_mbclen(ptr, pend, enc);
- if (!MBCLEN_CHARFOUND_P(n)) {
- if (ptr > prev) parser_str_cat(result, prev, ptr - prev);
- n = rb_enc_mbminlen(enc);
- if (pend < ptr + n)
- n = (int)(pend - ptr);
- while (n--) {
- c = *ptr & 0xf0 >> 4;
- charbuf[2] = (c < 10) ? '0' + c : 'A' + c - 10;
- c = *ptr & 0x0f;
- charbuf[3] = (c < 10) ? '0' + c : 'A' + c - 10;
- parser_str_cat(result, charbuf, 4);
- prev = ++ptr;
- }
- continue;
- }
- n = MBCLEN_CHARFOUND_LEN(n);
- c = rb_enc_mbc_to_codepoint(ptr, pend, enc);
- ptr += n;
- cc = escaped_char(c);
- if (cc) {
- if (ptr - n > prev) parser_str_cat(result, prev, ptr - n - prev);
- parser_str_cat_cstr(result, cc);
- prev = ptr;
- }
- else if (rb_enc_isascii(c, enc) && ISPRINT(c)) {
- }
- else {
- if (ptr - n > prev) {
- parser_str_cat(result, prev, ptr - n - prev);
- prev = ptr - n;
- }
- parser_str_cat(result, prev, ptr - prev);
- prev = ptr;
- }
- }
- if (ptr > prev) parser_str_cat(result, prev, ptr - prev);
-
- return result;
+ return ary;
}
static void
-parser_append_tokens(struct parser_params *p, rb_parser_string_t *str, enum yytokentype t, int line)
-{
- rb_parser_ast_token_t *token = xcalloc(1, sizeof(rb_parser_ast_token_t));
- token->id = p->token_id;
- token->type_name = parser_token2char(p, t);
- token->str = str;
- token->loc.beg_pos = p->yylloc->beg_pos;
- token->loc.end_pos = p->yylloc->end_pos;
- rb_parser_ary_push_ast_token(p, p->tokens, token);
+parser_append_tokens(struct parser_params *p, VALUE str, enum yytokentype t, int line)
+{
+ VALUE ary;
+ int token_id;
+
+ ary = rb_ary_new2(4);
+ token_id = p->token_id;
+ rb_ary_push(ary, INT2FIX(token_id));
+ rb_ary_push(ary, ID2SYM(parser_token2id(t)));
+ rb_ary_push(ary, str);
+ rb_ary_push(ary, code_loc_to_ary(p->yylloc));
+ rb_obj_freeze(ary);
+ rb_ary_push(p->tokens, ary);
p->token_id++;
if (p->debug) {
- rb_parser_string_t *str_escaped = rb_parser_str_escape(p, str);
- rb_parser_printf(p, "Append tokens (line: %d) [%d, :%s, \"%s\", [%d, %d, %d, %d]]\n",
- line, token->id, token->type_name, str_escaped->ptr,
- token->loc.beg_pos.lineno, token->loc.beg_pos.column,
- token->loc.end_pos.lineno, token->loc.end_pos.column);
- rb_parser_string_free(p, str_escaped);
+ rb_parser_printf(p, "Append tokens (line: %d) %"PRIsVALUE"\n", line, ary);
}
}
@@ -7046,8 +6245,8 @@ parser_dispatch_scan_event(struct parser_params *p, enum yytokentype t, int line
RUBY_SET_YYLLOC(*p->yylloc);
if (p->keep_tokens) {
- rb_parser_string_t *str = rb_parser_encoding_string_new(p, p->lex.ptok, p->lex.pcur - p->lex.ptok, p->enc);
- parser_append_tokens(p, str, t, line);
+ VALUE str = STR_NEW(p->lex.ptok, p->lex.pcur - p->lex.ptok);
+ parser_append_tokens(p, str, t, line);
}
token_flush(p);
@@ -7057,6 +6256,9 @@ parser_dispatch_scan_event(struct parser_params *p, enum yytokentype t, int line
static void
parser_dispatch_delayed_token(struct parser_params *p, enum yytokentype t, int line)
{
+ int saved_line = p->ruby_sourceline;
+ const char *saved_tokp = p->lex.ptok;
+
debug_token_line(p, "parser_dispatch_delayed_token", line);
if (!has_delayed_token(p)) return;
@@ -7064,17 +6266,27 @@ parser_dispatch_delayed_token(struct parser_params *p, enum yytokentype t, int l
RUBY_SET_YYLLOC_OF_DELAYED_TOKEN(*p->yylloc);
if (p->keep_tokens) {
- /* p->delayed.token is freed by rb_parser_tokens_free */
- parser_append_tokens(p, p->delayed.token, t, line);
- } else {
- rb_parser_string_free(p, p->delayed.token);
+ p->ruby_sourceline = p->delayed.beg_line;
+ p->lex.ptok = p->lex.pbeg + p->delayed.beg_col;
+ parser_append_tokens(p, p->delayed.token, t, line);
+ p->ruby_sourceline = saved_line;
+ p->lex.ptok = saved_tokp;
}
- p->delayed.token = NULL;
+ p->delayed.token = Qnil;
}
#else
#define literal_flush(p, ptr) ((void)(ptr))
+#define yylval_rval (*(RB_TYPE_P(yylval.val, T_NODE) ? &yylval.node->nd_rval : &yylval.val))
+
+static inline VALUE
+intern_sym(const char *name)
+{
+ ID id = rb_intern_const(name);
+ return ID2SYM(id);
+}
+
static int
ripper_has_scan_event(struct parser_params *p)
{
@@ -7096,27 +6308,21 @@ static void
ripper_dispatch_scan_event(struct parser_params *p, enum yytokentype t)
{
if (!ripper_has_scan_event(p)) return;
-
- set_parser_s_value(ripper_scan_event_val(p, t));
+ add_mark_object(p, yylval_rval = ripper_scan_event_val(p, t));
}
#define dispatch_scan_event(p, t) ripper_dispatch_scan_event(p, t)
static void
ripper_dispatch_delayed_token(struct parser_params *p, enum yytokentype t)
{
- /* save and adjust the location to delayed token for callbacks */
int saved_line = p->ruby_sourceline;
const char *saved_tokp = p->lex.ptok;
- VALUE s_value, str;
if (!has_delayed_token(p)) return;
p->ruby_sourceline = p->delayed.beg_line;
p->lex.ptok = p->lex.pbeg + p->delayed.beg_col;
- str = rb_str_new_mutable_parser_string(p->delayed.token);
- rb_parser_string_free(p, p->delayed.token);
- s_value = ripper_dispatch1(p, ripper_token2eventid(t), str);
- set_parser_s_value(s_value);
- p->delayed.token = NULL;
+ add_mark_object(p, yylval_rval = ripper_dispatch1(p, ripper_token2eventid(t), p->delayed.token));
+ p->delayed.token = Qnil;
p->ruby_sourceline = saved_line;
p->lex.ptok = saved_tokp;
}
@@ -7124,7 +6330,7 @@ ripper_dispatch_delayed_token(struct parser_params *p, enum yytokentype t)
#endif /* RIPPER */
static inline int
-is_identchar(struct parser_params *p, const char *ptr, const char *MAYBE_UNUSED(ptr_end), rb_encoding *enc)
+is_identchar(const char *ptr, const char *MAYBE_UNUSED(ptr_end), rb_encoding *enc)
{
return rb_enc_isalnum((unsigned char)*ptr, enc) || *ptr == '_' || !ISASCII(*ptr);
}
@@ -7132,7 +6338,7 @@ is_identchar(struct parser_params *p, const char *ptr, const char *MAYBE_UNUSED(
static inline int
parser_is_identchar(struct parser_params *p)
{
- return !(p)->eofp && is_identchar(p, p->lex.pcur-1, p->lex.pend, p->enc);
+ return !(p)->eofp && is_identchar(p->lex.pcur-1, p->lex.pend, p->enc);
}
static inline int
@@ -7146,13 +6352,13 @@ token_info_setup(token_info *ptinfo, const char *ptr, const rb_code_location_t *
{
int column = 1, nonspc = 0, i;
for (i = 0; i < loc->beg_pos.column; i++, ptr++) {
- if (*ptr == '\t') {
- column = (((column - 1) / TAB_WIDTH) + 1) * TAB_WIDTH;
- }
- column++;
- if (*ptr != ' ' && *ptr != '\t') {
- nonspc = 1;
- }
+ if (*ptr == '\t') {
+ column = (((column - 1) / TAB_WIDTH) + 1) * TAB_WIDTH;
+ }
+ column++;
+ if (*ptr != ' ' && *ptr != '\t') {
+ nonspc = 1;
+ }
}
ptinfo->beg = loc->beg_pos;
@@ -7180,11 +6386,10 @@ token_info_pop(struct parser_params *p, const char *token, const rb_code_locatio
token_info *ptinfo_beg = p->token_info;
if (!ptinfo_beg) return;
+ p->token_info = ptinfo_beg->next;
/* indentation check of matched keywords (begin..end, if..end, etc.) */
token_info_warn(p, token, ptinfo_beg, 1, loc);
-
- p->token_info = ptinfo_beg->next;
ruby_sized_xfree(ptinfo_beg, sizeof(*ptinfo_beg));
}
@@ -7197,12 +6402,12 @@ token_info_drop(struct parser_params *p, const char *token, rb_code_position_t b
p->token_info = ptinfo_beg->next;
if (ptinfo_beg->beg.lineno != beg_pos.lineno ||
- ptinfo_beg->beg.column != beg_pos.column ||
- strcmp(ptinfo_beg->token, token)) {
- compile_error(p, "token position mismatch: %d:%d:%s expected but %d:%d:%s",
- beg_pos.lineno, beg_pos.column, token,
- ptinfo_beg->beg.lineno, ptinfo_beg->beg.column,
- ptinfo_beg->token);
+ ptinfo_beg->beg.column != beg_pos.column ||
+ strcmp(ptinfo_beg->token, token)) {
+ compile_error(p, "token position mismatch: %d:%d:%s expected but %d:%d:%s",
+ beg_pos.lineno, beg_pos.column, token,
+ ptinfo_beg->beg.lineno, ptinfo_beg->beg.column,
+ ptinfo_beg->token);
}
ruby_sized_xfree(ptinfo_beg, sizeof(*ptinfo_beg));
@@ -7220,8 +6425,8 @@ token_info_warn(struct parser_params *p, const char *token, token_info *ptinfo_b
if (ptinfo_beg->indent == ptinfo_end->indent) return; /* the indents are matched */
if (!same && ptinfo_beg->indent < ptinfo_end->indent) return;
rb_warn3L(ptinfo_end->beg.lineno,
- "mismatched indentations at '%s' with '%s' at %d",
- WARN_S(token), WARN_S(ptinfo_beg->token), WARN_I(ptinfo_beg->beg.lineno));
+ "mismatched indentations at '%s' with '%s' at %d",
+ WARN_S(token), WARN_S(ptinfo_beg->token), WARN_I(ptinfo_beg->beg.lineno));
}
static int
@@ -7229,45 +6434,47 @@ parser_precise_mbclen(struct parser_params *p, const char *ptr)
{
int len = rb_enc_precise_mbclen(ptr, p->lex.pend, p->enc);
if (!MBCLEN_CHARFOUND_P(len)) {
- compile_error(p, "invalid multibyte char (%s)", rb_enc_name(p->enc));
- return -1;
+ compile_error(p, "invalid multibyte char (%s)", rb_enc_name(p->enc));
+ return -1;
}
return len;
}
#ifndef RIPPER
+static void ruby_show_error_line(VALUE errbuf, const YYLTYPE *yylloc, int lineno, VALUE str);
+
static inline void
parser_show_error_line(struct parser_params *p, const YYLTYPE *yylloc)
{
- rb_parser_string_t *str;
+ VALUE str;
int lineno = p->ruby_sourceline;
if (!yylloc) {
- return;
+ return;
}
else if (yylloc->beg_pos.lineno == lineno) {
- str = p->lex.lastline;
+ str = p->lex.lastline;
}
else {
- return;
+ return;
}
- ruby_show_error_line(p, p->error_buffer, yylloc, lineno, str);
+ ruby_show_error_line(p->error_buffer, yylloc, lineno, str);
}
static int
-parser_yyerror(struct parser_params *p, const rb_code_location_t *yylloc, const char *msg)
+parser_yyerror(struct parser_params *p, const YYLTYPE *yylloc, const char *msg)
{
#if 0
YYLTYPE current;
if (!yylloc) {
- yylloc = RUBY_SET_YYLLOC(current);
+ yylloc = RUBY_SET_YYLLOC(current);
}
else if ((p->ruby_sourceline != yylloc->beg_pos.lineno &&
- p->ruby_sourceline != yylloc->end_pos.lineno)) {
- yylloc = 0;
+ p->ruby_sourceline != yylloc->end_pos.lineno)) {
+ yylloc = 0;
}
#endif
- parser_compile_error(p, yylloc, "%s", msg);
+ compile_error(p, "%s", msg);
parser_show_error_line(p, yylloc);
return 0;
}
@@ -7279,8 +6486,8 @@ parser_yyerror0(struct parser_params *p, const char *msg)
return parser_yyerror(p, RUBY_SET_YYLLOC(current), msg);
}
-void
-ruby_show_error_line(struct parser_params *p, VALUE errbuf, const YYLTYPE *yylloc, int lineno, rb_parser_string_t *str)
+static void
+ruby_show_error_line(VALUE errbuf, const YYLTYPE *yylloc, int lineno, VALUE str)
{
VALUE mesg;
const int max_line_margin = 30;
@@ -7288,21 +6495,21 @@ ruby_show_error_line(struct parser_params *p, VALUE errbuf, const YYLTYPE *yyllo
const char *pre = "", *post = "", *pend;
const char *code = "", *caret = "";
const char *lim;
- const char *const pbeg = PARSER_STRING_PTR(str);
+ const char *const pbeg = RSTRING_PTR(str);
char *buf;
long len;
int i;
if (!yylloc) return;
- pend = rb_parser_string_end(str);
+ pend = RSTRING_END(str);
if (pend > pbeg && pend[-1] == '\n') {
- if (--pend > pbeg && pend[-1] == '\r') --pend;
+ if (--pend > pbeg && pend[-1] == '\r') --pend;
}
pt = pend;
if (lineno == yylloc->end_pos.lineno &&
- (pend - pbeg) > yylloc->end_pos.column) {
- pt = pbeg + yylloc->end_pos.column;
+ (pend - pbeg) > yylloc->end_pos.column) {
+ pt = pbeg + yylloc->end_pos.column;
}
ptr = ptr_end = pt;
@@ -7314,92 +6521,91 @@ ruby_show_error_line(struct parser_params *p, VALUE errbuf, const YYLTYPE *yyllo
len = ptr_end - ptr;
if (len > 4) {
- if (ptr > pbeg) {
- ptr = rb_enc_prev_char(pbeg, ptr, pt, rb_parser_str_get_encoding(str));
- if (ptr > pbeg) pre = "...";
- }
- if (ptr_end < pend) {
- ptr_end = rb_enc_prev_char(pt, ptr_end, pend, rb_parser_str_get_encoding(str));
- if (ptr_end < pend) post = "...";
- }
+ if (ptr > pbeg) {
+ ptr = rb_enc_prev_char(pbeg, ptr, pt, rb_enc_get(str));
+ if (ptr > pbeg) pre = "...";
+ }
+ if (ptr_end < pend) {
+ ptr_end = rb_enc_prev_char(pt, ptr_end, pend, rb_enc_get(str));
+ if (ptr_end < pend) post = "...";
+ }
}
pb = pbeg;
if (lineno == yylloc->beg_pos.lineno) {
- pb += yylloc->beg_pos.column;
- if (pb > pt) pb = pt;
+ pb += yylloc->beg_pos.column;
+ if (pb > pt) pb = pt;
}
if (pb < ptr) pb = ptr;
if (len <= 4 && yylloc->beg_pos.lineno == yylloc->end_pos.lineno) {
- return;
+ return;
}
if (RTEST(errbuf)) {
- mesg = rb_attr_get(errbuf, idMesg);
- if (char_at_end(p, mesg, '\n') != '\n')
- rb_str_cat_cstr(mesg, "\n");
+ mesg = rb_attr_get(errbuf, idMesg);
+ if (RSTRING_LEN(mesg) > 0 && *(RSTRING_END(mesg)-1) != '\n')
+ rb_str_cat_cstr(mesg, "\n");
}
else {
- mesg = rb_enc_str_new(0, 0, rb_parser_str_get_encoding(str));
+ mesg = rb_enc_str_new(0, 0, rb_enc_get(str));
}
if (!errbuf && rb_stderr_tty_p()) {
#define CSI_BEGIN "\033["
#define CSI_SGR "m"
- rb_str_catf(mesg,
- CSI_BEGIN""CSI_SGR"%s" /* pre */
- CSI_BEGIN"1"CSI_SGR"%.*s"
- CSI_BEGIN"1;4"CSI_SGR"%.*s"
- CSI_BEGIN";1"CSI_SGR"%.*s"
- CSI_BEGIN""CSI_SGR"%s" /* post */
- "\n",
- pre,
- (int)(pb - ptr), ptr,
- (int)(pt - pb), pb,
- (int)(ptr_end - pt), pt,
- post);
+ rb_str_catf(mesg,
+ CSI_BEGIN""CSI_SGR"%s" /* pre */
+ CSI_BEGIN"1"CSI_SGR"%.*s"
+ CSI_BEGIN"1;4"CSI_SGR"%.*s"
+ CSI_BEGIN";1"CSI_SGR"%.*s"
+ CSI_BEGIN""CSI_SGR"%s" /* post */
+ "\n",
+ pre,
+ (int)(pb - ptr), ptr,
+ (int)(pt - pb), pb,
+ (int)(ptr_end - pt), pt,
+ post);
}
else {
- char *p2;
-
- len = ptr_end - ptr;
- lim = pt < pend ? pt : pend;
- i = (int)(lim - ptr);
- buf = ALLOCA_N(char, i+2);
- code = ptr;
- caret = p2 = buf;
- if (ptr <= pb) {
- while (ptr < pb) {
- *p2++ = *ptr++ == '\t' ? '\t' : ' ';
- }
- *p2++ = '^';
- ptr++;
- }
- if (lim > ptr) {
- memset(p2, '~', (lim - ptr));
- p2 += (lim - ptr);
- }
- *p2 = '\0';
- rb_str_catf(mesg, "%s%.*s%s\n""%s%s\n",
- pre, (int)len, code, post,
- pre, caret);
+ char *p2;
+
+ len = ptr_end - ptr;
+ lim = pt < pend ? pt : pend;
+ i = (int)(lim - ptr);
+ buf = ALLOCA_N(char, i+2);
+ code = ptr;
+ caret = p2 = buf;
+ if (ptr <= pb) {
+ while (ptr < pb) {
+ *p2++ = *ptr++ == '\t' ? '\t' : ' ';
+ }
+ *p2++ = '^';
+ ptr++;
+ }
+ if (lim > ptr) {
+ memset(p2, '~', (lim - ptr));
+ p2 += (lim - ptr);
+ }
+ *p2 = '\0';
+ rb_str_catf(mesg, "%s%.*s%s\n""%s%s\n",
+ pre, (int)len, code, post,
+ pre, caret);
}
if (!errbuf) rb_write_error_str(mesg);
}
#else
-
static int
parser_yyerror(struct parser_params *p, const YYLTYPE *yylloc, const char *msg)
{
const char *pcur = 0, *ptok = 0;
if (p->ruby_sourceline == yylloc->beg_pos.lineno &&
- p->ruby_sourceline == yylloc->end_pos.lineno) {
- pcur = p->lex.pcur;
- ptok = p->lex.ptok;
- p->lex.ptok = p->lex.pbeg + yylloc->beg_pos.column;
- p->lex.pcur = p->lex.pbeg + yylloc->end_pos.column;
+ p->ruby_sourceline == yylloc->end_pos.lineno) {
+ pcur = p->lex.pcur;
+ ptok = p->lex.ptok;
+ p->lex.ptok = p->lex.pbeg + yylloc->beg_pos.column;
+ p->lex.pcur = p->lex.pbeg + yylloc->end_pos.column;
}
parser_yyerror0(p, msg);
if (pcur) {
- p->lex.ptok = ptok;
- p->lex.pcur = pcur;
+ p->lex.ptok = ptok;
+ p->lex.pcur = pcur;
}
return 0;
}
@@ -7418,16 +6624,18 @@ parser_show_error_line(struct parser_params *p, const YYLTYPE *yylloc)
}
#endif /* !RIPPER */
+#ifndef RIPPER
static int
vtable_size(const struct vtable *tbl)
{
if (!DVARS_TERMINAL_P(tbl)) {
- return tbl->pos;
+ return tbl->pos;
}
else {
- return 0;
+ return 0;
}
}
+#endif
static struct vtable *
vtable_alloc_gen(struct parser_params *p, int line, struct vtable *prev)
@@ -7439,7 +6647,7 @@ vtable_alloc_gen(struct parser_params *p, int line, struct vtable *prev)
tbl->prev = prev;
#ifndef RIPPER
if (p->debug) {
- rb_parser_printf(p, "vtable_alloc:%d: %p\n", line, (void *)tbl);
+ rb_parser_printf(p, "vtable_alloc:%d: %p\n", line, (void *)tbl);
}
#endif
return tbl;
@@ -7448,59 +6656,61 @@ vtable_alloc_gen(struct parser_params *p, int line, struct vtable *prev)
static void
vtable_free_gen(struct parser_params *p, int line, const char *name,
- struct vtable *tbl)
+ struct vtable *tbl)
{
#ifndef RIPPER
if (p->debug) {
- rb_parser_printf(p, "vtable_free:%d: %s(%p)\n", line, name, (void *)tbl);
+ rb_parser_printf(p, "vtable_free:%d: %s(%p)\n", line, name, (void *)tbl);
}
#endif
if (!DVARS_TERMINAL_P(tbl)) {
- if (tbl->tbl) {
- ruby_sized_xfree(tbl->tbl, tbl->capa * sizeof(ID));
- }
- ruby_sized_xfree(tbl, sizeof(*tbl));
+ if (tbl->tbl) {
+ ruby_sized_xfree(tbl->tbl, tbl->capa * sizeof(ID));
+ }
+ ruby_sized_xfree(tbl, sizeof(*tbl));
}
}
#define vtable_free(tbl) vtable_free_gen(p, __LINE__, #tbl, tbl)
static void
vtable_add_gen(struct parser_params *p, int line, const char *name,
- struct vtable *tbl, ID id)
+ struct vtable *tbl, ID id)
{
#ifndef RIPPER
if (p->debug) {
- rb_parser_printf(p, "vtable_add:%d: %s(%p), %s\n",
- line, name, (void *)tbl, rb_id2name(id));
+ rb_parser_printf(p, "vtable_add:%d: %s(%p), %s\n",
+ line, name, (void *)tbl, rb_id2name(id));
}
#endif
if (DVARS_TERMINAL_P(tbl)) {
- rb_parser_fatal(p, "vtable_add: vtable is not allocated (%p)", (void *)tbl);
- return;
+ rb_parser_fatal(p, "vtable_add: vtable is not allocated (%p)", (void *)tbl);
+ return;
}
if (tbl->pos == tbl->capa) {
- tbl->capa = tbl->capa * 2;
- SIZED_REALLOC_N(tbl->tbl, ID, tbl->capa, tbl->pos);
+ tbl->capa = tbl->capa * 2;
+ SIZED_REALLOC_N(tbl->tbl, ID, tbl->capa, tbl->pos);
}
tbl->tbl[tbl->pos++] = id;
}
#define vtable_add(tbl, id) vtable_add_gen(p, __LINE__, #tbl, tbl, id)
+#ifndef RIPPER
static void
vtable_pop_gen(struct parser_params *p, int line, const char *name,
- struct vtable *tbl, int n)
+ struct vtable *tbl, int n)
{
if (p->debug) {
- rb_parser_printf(p, "vtable_pop:%d: %s(%p), %d\n",
- line, name, (void *)tbl, n);
+ rb_parser_printf(p, "vtable_pop:%d: %s(%p), %d\n",
+ line, name, (void *)tbl, n);
}
if (tbl->pos < n) {
- rb_parser_fatal(p, "vtable_pop: unreachable (%d < %d)", tbl->pos, n);
- return;
+ rb_parser_fatal(p, "vtable_pop: unreachable (%d < %d)", tbl->pos, n);
+ return;
}
tbl->pos -= n;
}
#define vtable_pop(tbl, n) vtable_pop_gen(p, __LINE__, #tbl, tbl, n)
+#endif
static int
vtable_included(const struct vtable * tbl, ID id)
@@ -7508,107 +6718,139 @@ vtable_included(const struct vtable * tbl, ID id)
int i;
if (!DVARS_TERMINAL_P(tbl)) {
- for (i = 0; i < tbl->pos; i++) {
- if (tbl->tbl[i] == id) {
- return i+1;
- }
- }
+ for (i = 0; i < tbl->pos; i++) {
+ if (tbl->tbl[i] == id) {
+ return i+1;
+ }
+ }
}
return 0;
}
static void parser_prepare(struct parser_params *p);
+#ifndef RIPPER
+static NODE *parser_append_options(struct parser_params *p, NODE *node);
+
+static VALUE
+debug_lines(VALUE fname)
+{
+ ID script_lines;
+ CONST_ID(script_lines, "SCRIPT_LINES__");
+ if (rb_const_defined_at(rb_cObject, script_lines)) {
+ VALUE hash = rb_const_get_at(rb_cObject, script_lines);
+ if (RB_TYPE_P(hash, T_HASH)) {
+ VALUE lines = rb_ary_new();
+ rb_hash_aset(hash, fname, lines);
+ return lines;
+ }
+ }
+ return 0;
+}
+
static int
e_option_supplied(struct parser_params *p)
{
return strcmp(p->ruby_sourcefile, "-e") == 0;
}
-#ifndef RIPPER
-static NODE *parser_append_options(struct parser_params *p, NODE *node);
-
static VALUE
yycompile0(VALUE arg)
{
int n;
NODE *tree;
struct parser_params *p = (struct parser_params *)arg;
- int cov = FALSE;
+ VALUE cov = Qfalse;
- if (!compile_for_eval && !NIL_P(p->ruby_sourcefile_string) && !e_option_supplied(p)) {
- cov = TRUE;
+ if (!compile_for_eval && !NIL_P(p->ruby_sourcefile_string)) {
+ p->debug_lines = debug_lines(p->ruby_sourcefile_string);
+ if (p->debug_lines && p->ruby_sourceline > 0) {
+ VALUE str = rb_default_rs;
+ n = p->ruby_sourceline;
+ do {
+ rb_ary_push(p->debug_lines, str);
+ } while (--n);
+ }
+
+ if (!e_option_supplied(p)) {
+ cov = Qtrue;
+ }
}
- if (p->debug_lines) {
- p->ast->body.script_lines = p->debug_lines;
+ if (p->keep_script_lines || ruby_vm_keep_script_lines) {
+ if (!p->debug_lines) {
+ p->debug_lines = rb_ary_new();
+ }
+
+ RB_OBJ_WRITE(p->ast, &p->ast->body.script_lines, p->debug_lines);
}
parser_prepare(p);
#define RUBY_DTRACE_PARSE_HOOK(name) \
if (RUBY_DTRACE_PARSE_##name##_ENABLED()) { \
- RUBY_DTRACE_PARSE_##name(p->ruby_sourcefile, p->ruby_sourceline); \
+ RUBY_DTRACE_PARSE_##name(p->ruby_sourcefile, p->ruby_sourceline); \
}
RUBY_DTRACE_PARSE_HOOK(BEGIN);
n = yyparse(p);
RUBY_DTRACE_PARSE_HOOK(END);
-
p->debug_lines = 0;
- xfree(p->lex.strterm);
p->lex.strterm = 0;
p->lex.pcur = p->lex.pbeg = p->lex.pend = 0;
if (n || p->error_p) {
- VALUE mesg = p->error_buffer;
- if (!mesg) {
- mesg = syntax_error_new();
- }
- if (!p->error_tolerant) {
- rb_set_errinfo(mesg);
- return FALSE;
- }
+ VALUE mesg = p->error_buffer;
+ if (!mesg) {
+ mesg = rb_class_new_instance(0, 0, rb_eSyntaxError);
+ }
+ if (!p->error_tolerant) {
+ rb_set_errinfo(mesg);
+ return FALSE;
+ }
}
tree = p->eval_tree;
if (!tree) {
- tree = NEW_NIL(&NULL_LOC);
+ tree = NEW_NIL(&NULL_LOC);
}
else {
- rb_parser_ary_t *tokens = p->tokens;
- NODE *prelude;
- NODE *body = parser_append_options(p, RNODE_SCOPE(tree)->nd_body);
- prelude = block_append(p, p->eval_tree_begin, body);
- RNODE_SCOPE(tree)->nd_body = prelude;
- p->ast->body.frozen_string_literal = p->frozen_string_literal;
- p->ast->body.coverage_enabled = cov;
- if (p->keep_tokens) {
- p->ast->node_buffer->tokens = tokens;
- p->tokens = NULL;
- }
+ VALUE opt = p->compile_option;
+ VALUE tokens = p->tokens;
+ NODE *prelude;
+ NODE *body = parser_append_options(p, tree->nd_body);
+ if (!opt) opt = rb_obj_hide(rb_ident_hash_new());
+ rb_hash_aset(opt, rb_sym_intern_ascii_cstr("coverage_enabled"), cov);
+ prelude = block_append(p, p->eval_tree_begin, body);
+ tree->nd_body = prelude;
+ RB_OBJ_WRITE(p->ast, &p->ast->body.compile_option, opt);
+ if (p->keep_tokens) {
+ rb_obj_freeze(tokens);
+ rb_ast_set_tokens(p->ast, tokens);
+ }
}
p->ast->body.root = tree;
- p->ast->body.line_count = p->line_count;
+ if (!p->ast->body.script_lines) p->ast->body.script_lines = INT2FIX(p->line_count);
return TRUE;
}
static rb_ast_t *
-yycompile(struct parser_params *p, VALUE fname, int line)
+yycompile(VALUE vparser, struct parser_params *p, VALUE fname, int line)
{
rb_ast_t *ast;
if (NIL_P(fname)) {
- p->ruby_sourcefile_string = Qnil;
- p->ruby_sourcefile = "(none)";
+ p->ruby_sourcefile_string = Qnil;
+ p->ruby_sourcefile = "(none)";
}
else {
- p->ruby_sourcefile_string = rb_str_to_interned_str(fname);
- p->ruby_sourcefile = StringValueCStr(fname);
+ p->ruby_sourcefile_string = rb_fstring(fname);
+ p->ruby_sourcefile = StringValueCStr(fname);
}
p->ruby_sourceline = line - 1;
p->lvtbl = NULL;
p->ast = ast = rb_ast_new();
- compile_callback(yycompile0, (VALUE)p);
+ rb_suppress_tracing(yycompile0, (VALUE)p);
p->ast = 0;
+ RB_GC_GUARD(vparser); /* prohibit tail call optimization */
while (p->lvtbl) {
local_pop(p);
@@ -7619,35 +6861,118 @@ yycompile(struct parser_params *p, VALUE fname, int line)
#endif /* !RIPPER */
static rb_encoding *
-must_be_ascii_compatible(struct parser_params *p, rb_parser_string_t *s)
+must_be_ascii_compatible(VALUE s)
{
- rb_encoding *enc = rb_parser_str_get_encoding(s);
+ rb_encoding *enc = rb_enc_get(s);
if (!rb_enc_asciicompat(enc)) {
- rb_raise(rb_eArgError, "invalid source encoding");
+ rb_raise(rb_eArgError, "invalid source encoding");
}
return enc;
}
-static rb_parser_string_t *
+static VALUE
+lex_get_str(struct parser_params *p, VALUE s)
+{
+ char *beg, *end, *start;
+ long len;
+
+ beg = RSTRING_PTR(s);
+ len = RSTRING_LEN(s);
+ start = beg;
+ if (p->lex.gets_.ptr) {
+ if (len == p->lex.gets_.ptr) return Qnil;
+ beg += p->lex.gets_.ptr;
+ len -= p->lex.gets_.ptr;
+ }
+ end = memchr(beg, '\n', len);
+ if (end) len = ++end - beg;
+ p->lex.gets_.ptr += len;
+ return rb_str_subseq(s, beg - start, len);
+}
+
+static VALUE
lex_getline(struct parser_params *p)
{
- rb_parser_string_t *line = (*p->lex.gets)(p, p->lex.input, p->line_count);
- if (!line) return 0;
+ VALUE line = (*p->lex.gets)(p, p->lex.input);
+ if (NIL_P(line)) return line;
+ must_be_ascii_compatible(line);
+ if (RB_OBJ_FROZEN(line)) line = rb_str_dup(line); // needed for RubyVM::AST.of because script_lines in iseq is deep-frozen
p->line_count++;
- string_buffer_append(p, line);
- must_be_ascii_compatible(p, line);
return line;
}
+static const rb_data_type_t parser_data_type;
+
#ifndef RIPPER
+static rb_ast_t*
+parser_compile_string(VALUE vparser, VALUE fname, VALUE s, int line)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
+
+ p->lex.gets = lex_get_str;
+ p->lex.gets_.ptr = 0;
+ p->lex.input = rb_str_new_frozen(s);
+ p->lex.pbeg = p->lex.pcur = p->lex.pend = 0;
+
+ return yycompile(vparser, p, fname, line);
+}
+
+rb_ast_t*
+rb_parser_compile_string(VALUE vparser, const char *f, VALUE s, int line)
+{
+ return rb_parser_compile_string_path(vparser, rb_filesystem_str_new_cstr(f), s, line);
+}
+
+rb_ast_t*
+rb_parser_compile_string_path(VALUE vparser, VALUE f, VALUE s, int line)
+{
+ must_be_ascii_compatible(s);
+ return parser_compile_string(vparser, f, s, line);
+}
+
+VALUE rb_io_gets_internal(VALUE io);
+
+static VALUE
+lex_io_gets(struct parser_params *p, VALUE io)
+{
+ return rb_io_gets_internal(io);
+}
+
rb_ast_t*
-rb_parser_compile(rb_parser_t *p, rb_parser_lex_gets_func *gets, VALUE fname, rb_parser_input_data input, int line)
+rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE file, int start)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
+
+ p->lex.gets = lex_io_gets;
+ p->lex.input = file;
+ p->lex.pbeg = p->lex.pcur = p->lex.pend = 0;
+
+ return yycompile(vparser, p, fname, start);
+}
+
+static VALUE
+lex_generic_gets(struct parser_params *p, VALUE input)
{
- p->lex.gets = gets;
+ return (*p->lex.gets_.call)(input, p->line_count);
+}
+
+rb_ast_t*
+rb_parser_compile_generic(VALUE vparser, VALUE (*lex_gets)(VALUE, int), VALUE fname, VALUE input, int start)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
+
+ p->lex.gets = lex_generic_gets;
+ p->lex.gets_.call = lex_gets;
p->lex.input = input;
p->lex.pbeg = p->lex.pcur = p->lex.pend = 0;
- return yycompile(p, fname, line);
+ return yycompile(vparser, p, fname, start);
}
#endif /* !RIPPER */
@@ -7673,48 +6998,21 @@ enum string_type {
str_dsym = (STR_FUNC_SYMBOL|STR_FUNC_EXPAND)
};
-static rb_parser_string_t *
-parser_str_new(struct parser_params *p, const char *ptr, long len, rb_encoding *enc, int func, rb_encoding *enc0)
+static VALUE
+parser_str_new(const char *ptr, long len, rb_encoding *enc, int func, rb_encoding *enc0)
{
- rb_parser_string_t *pstr;
-
- pstr = rb_parser_encoding_string_new(p, ptr, len, enc);
+ VALUE str;
- if (!(func & STR_FUNC_REGEXP)) {
- if (rb_parser_is_ascii_string(p, pstr)) {
- }
- else if (rb_is_usascii_enc((void *)enc0) && enc != rb_utf8_encoding()) {
- /* everything is valid in ASCII-8BIT */
- enc = rb_ascii8bit_encoding();
- PARSER_ENCODING_CODERANGE_SET(pstr, enc, RB_PARSER_ENC_CODERANGE_VALID);
- }
+ str = rb_enc_str_new(ptr, len, enc);
+ if (!(func & STR_FUNC_REGEXP) && rb_enc_asciicompat(enc)) {
+ if (is_ascii_string(str)) {
+ }
+ else if (rb_is_usascii_enc(enc0) && enc != rb_utf8_encoding()) {
+ rb_enc_associate(str, rb_ascii8bit_encoding());
+ }
}
- return pstr;
-}
-
-static int
-strterm_is_heredoc(rb_strterm_t *strterm)
-{
- return strterm->heredoc;
-}
-
-static rb_strterm_t *
-new_strterm(struct parser_params *p, int func, int term, int paren)
-{
- rb_strterm_t *strterm = ZALLOC(rb_strterm_t);
- strterm->u.literal.func = func;
- strterm->u.literal.term = term;
- strterm->u.literal.paren = paren;
- return strterm;
-}
-
-static rb_strterm_t *
-new_heredoc(struct parser_params *p)
-{
- rb_strterm_t *strterm = ZALLOC(rb_strterm_t);
- strterm->heredoc = true;
- return strterm;
+ return str;
}
#define peek(p,c) peek_n(p, (c), 0)
@@ -7722,82 +7020,68 @@ new_heredoc(struct parser_params *p)
#define peekc(p) peekc_n(p, 0)
#define peekc_n(p,n) (lex_eol_n_p(p, n) ? -1 : (unsigned char)(p)->lex.pcur[n])
-#define add_delayed_token(p, tok, end) parser_add_delayed_token(p, tok, end, __LINE__)
static void
-parser_add_delayed_token(struct parser_params *p, const char *tok, const char *end, int line)
+add_delayed_token(struct parser_params *p, const char *tok, const char *end, int line)
{
+#ifndef RIPPER
debug_token_line(p, "add_delayed_token", line);
+#endif
if (tok < end) {
- if (has_delayed_token(p)) {
- bool next_line = parser_string_char_at_end(p, p->delayed.token, 0) == '\n';
- int end_line = (next_line ? 1 : 0) + p->delayed.end_line;
- int end_col = (next_line ? 0 : p->delayed.end_col);
- if (end_line != p->ruby_sourceline || end_col != tok - p->lex.pbeg) {
- dispatch_delayed_token(p, tSTRING_CONTENT);
- }
- }
- if (!has_delayed_token(p)) {
- p->delayed.token = rb_parser_string_new(p, 0, 0);
- rb_parser_enc_associate(p, p->delayed.token, p->enc);
- p->delayed.beg_line = p->ruby_sourceline;
- p->delayed.beg_col = rb_long2int(tok - p->lex.pbeg);
- }
- parser_str_cat(p->delayed.token, tok, end - tok);
- p->delayed.end_line = p->ruby_sourceline;
- p->delayed.end_col = rb_long2int(end - p->lex.pbeg);
- p->lex.ptok = end;
+ if (!has_delayed_token(p)) {
+ p->delayed.token = rb_str_buf_new(end - tok);
+ rb_enc_associate(p->delayed.token, p->enc);
+ p->delayed.beg_line = p->ruby_sourceline;
+ p->delayed.beg_col = rb_long2int(tok - p->lex.pbeg);
+ }
+ rb_str_buf_cat(p->delayed.token, tok, end - tok);
+ p->delayed.end_line = p->ruby_sourceline;
+ p->delayed.end_col = rb_long2int(end - p->lex.pbeg);
+ p->lex.ptok = end;
}
}
-static void
-set_lastline(struct parser_params *p, rb_parser_string_t *str)
-{
- p->lex.pbeg = p->lex.pcur = PARSER_STRING_PTR(str);
- p->lex.pend = p->lex.pcur + PARSER_STRING_LEN(str);
- p->lex.lastline = str;
-}
-
static int
nextline(struct parser_params *p, int set_encoding)
{
- rb_parser_string_t *str = p->lex.nextline;
+ VALUE v = p->lex.nextline;
p->lex.nextline = 0;
- if (!str) {
- if (p->eofp)
- return -1;
-
- if (!lex_eol_ptr_p(p, p->lex.pbeg) && *(p->lex.pend-1) != '\n') {
- goto end_of_input;
- }
-
- if (!p->lex.input || !(str = lex_getline(p))) {
- end_of_input:
- p->eofp = 1;
- lex_goto_eol(p);
- return -1;
- }
+ if (!v) {
+ if (p->eofp)
+ return -1;
+
+ if (p->lex.pend > p->lex.pbeg && *(p->lex.pend-1) != '\n') {
+ goto end_of_input;
+ }
+
+ if (!p->lex.input || NIL_P(v = lex_getline(p))) {
+ end_of_input:
+ p->eofp = 1;
+ lex_goto_eol(p);
+ return -1;
+ }
#ifndef RIPPER
- if (p->debug_lines) {
- if (set_encoding) rb_parser_enc_associate(p, str, p->enc);
- rb_parser_string_t *copy = rb_parser_string_deep_copy(p, str);
- rb_parser_ary_push_script_line(p, p->debug_lines, copy);
- }
+ if (p->debug_lines) {
+ if (set_encoding) rb_enc_associate(v, p->enc);
+ rb_ary_push(p->debug_lines, v);
+ }
#endif
- p->cr_seen = FALSE;
+ p->cr_seen = FALSE;
}
- else if (str == AFTER_HEREDOC_WITHOUT_TERMINTOR) {
- /* after here-document without terminator */
- goto end_of_input;
+ else if (NIL_P(v)) {
+ /* after here-document without terminator */
+ goto end_of_input;
}
- add_delayed_token(p, p->lex.ptok, p->lex.pend);
+ add_delayed_token(p, p->lex.ptok, p->lex.pend, __LINE__);
if (p->heredoc_end > 0) {
- p->ruby_sourceline = p->heredoc_end;
- p->heredoc_end = 0;
+ p->ruby_sourceline = p->heredoc_end;
+ p->heredoc_end = 0;
}
p->ruby_sourceline++;
- set_lastline(p, str);
+ p->lex.pbeg = p->lex.pcur = RSTRING_PTR(v);
+ p->lex.pend = p->lex.pcur + RSTRING_LEN(v);
token_flush(p);
+ p->lex.lastline = v;
return 0;
}
@@ -7805,8 +7089,8 @@ static int
parser_cr(struct parser_params *p, int c)
{
if (peek(p, '\n')) {
- p->lex.pcur++;
- c = '\n';
+ p->lex.pcur++;
+ c = '\n';
}
return c;
}
@@ -7816,12 +7100,12 @@ nextc0(struct parser_params *p, int set_encoding)
{
int c;
- if (UNLIKELY(lex_eol_p(p) || p->eofp || p->lex.nextline > AFTER_HEREDOC_WITHOUT_TERMINTOR)) {
- if (nextline(p, set_encoding)) return -1;
+ if (UNLIKELY((p->lex.pcur == p->lex.pend) || p->eofp || RTEST(p->lex.nextline))) {
+ if (nextline(p, set_encoding)) return -1;
}
c = (unsigned char)*p->lex.pcur++;
if (UNLIKELY(c == '\r')) {
- c = parser_cr(p, c);
+ c = parser_cr(p, c);
}
return c;
@@ -7832,10 +7116,9 @@ static void
pushback(struct parser_params *p, int c)
{
if (c == -1) return;
- p->eofp = 0;
p->lex.pcur--;
if (p->lex.pcur > p->lex.pbeg && p->lex.pcur[0] == '\n' && p->lex.pcur[-1] == '\r') {
- p->lex.pcur--;
+ p->lex.pcur--;
}
}
@@ -7849,12 +7132,12 @@ static int
looking_at_eol_p(struct parser_params *p)
{
const char *ptr = p->lex.pcur;
- while (!lex_eol_ptr_p(p, ptr)) {
- int c = (unsigned char)*ptr++;
- int eol = (c == '\n' || c == '#');
- if (eol || !ISSPACE(c)) {
- return eol;
- }
+ while (ptr < p->lex.pend) {
+ int c = (unsigned char)*ptr++;
+ int eol = (c == '\n' || c == '#');
+ if (eol || !ISSPACE(c)) {
+ return eol;
+ }
}
return TRUE;
}
@@ -7863,13 +7146,14 @@ static char*
newtok(struct parser_params *p)
{
p->tokidx = 0;
+ p->tokline = p->ruby_sourceline;
if (!p->tokenbuf) {
- p->toksiz = 60;
- p->tokenbuf = ALLOC_N(char, 60);
+ p->toksiz = 60;
+ p->tokenbuf = ALLOC_N(char, 60);
}
if (p->toksiz > 4096) {
- p->toksiz = 60;
- REALLOC_N(p->tokenbuf, char, 60);
+ p->toksiz = 60;
+ REALLOC_N(p->tokenbuf, char, 60);
}
return p->tokenbuf;
}
@@ -7880,8 +7164,8 @@ tokspace(struct parser_params *p, int n)
p->tokidx += n;
if (p->tokidx >= p->toksiz) {
- do {p->toksiz *= 2;} while (p->toksiz < p->tokidx);
- REALLOC_N(p->tokenbuf, char, p->toksiz);
+ do {p->toksiz *= 2;} while (p->toksiz < p->tokidx);
+ REALLOC_N(p->tokenbuf, char, p->toksiz);
}
return &p->tokenbuf[p->tokidx-n];
}
@@ -7891,8 +7175,8 @@ tokadd(struct parser_params *p, int c)
{
p->tokenbuf[p->tokidx++] = (char)c;
if (p->tokidx >= p->toksiz) {
- p->toksiz *= 2;
- REALLOC_N(p->tokenbuf, char, p->toksiz);
+ p->toksiz *= 2;
+ REALLOC_N(p->tokenbuf, char, p->toksiz);
}
}
@@ -7901,12 +7185,11 @@ tok_hex(struct parser_params *p, size_t *numlen)
{
int c;
- c = (int)ruby_scan_hex(p->lex.pcur, 2, numlen);
+ c = scan_hex(p->lex.pcur, 2, numlen);
if (!*numlen) {
- flush_string_content(p, p->enc, rb_strlen_lit("\\x"));
- yyerror0("invalid hex escape");
- dispatch_scan_event(p, tSTRING_CONTENT);
- return 0;
+ yyerror0("invalid hex escape");
+ token_flush(p);
+ return 0;
}
p->lex.pcur += *numlen;
return c;
@@ -7920,78 +7203,72 @@ escaped_control_code(int c)
int c2 = 0;
switch (c) {
case ' ':
- c2 = 's';
- break;
+ c2 = 's';
+ break;
case '\n':
- c2 = 'n';
- break;
+ c2 = 'n';
+ break;
case '\t':
- c2 = 't';
- break;
+ c2 = 't';
+ break;
case '\v':
- c2 = 'v';
- break;
+ c2 = 'v';
+ break;
case '\r':
- c2 = 'r';
- break;
+ c2 = 'r';
+ break;
case '\f':
- c2 = 'f';
- break;
+ c2 = 'f';
+ break;
}
return c2;
}
#define WARN_SPACE_CHAR(c, prefix) \
- rb_warn1("invalid character syntax; use "prefix"\\%c", WARN_I(c))
+ rb_warn1("invalid character syntax; use "prefix"\\%c", WARN_I(c2))
static int
tokadd_codepoint(struct parser_params *p, rb_encoding **encp,
- int regexp_literal, const char *begin)
+ int regexp_literal, int wide)
{
- const int wide = !begin;
size_t numlen;
- int codepoint = (int)ruby_scan_hex(p->lex.pcur, wide ? p->lex.pend - p->lex.pcur : 4, &numlen);
-
+ int codepoint = scan_hex(p->lex.pcur, wide ? p->lex.pend - p->lex.pcur : 4, &numlen);
p->lex.pcur += numlen;
if (p->lex.strterm == NULL ||
- strterm_is_heredoc(p->lex.strterm) ||
- (p->lex.strterm->u.literal.func != str_regexp)) {
- if (!begin) begin = p->lex.pcur;
+ (p->lex.strterm->flags & STRTERM_HEREDOC) ||
+ (p->lex.strterm->u.literal.u1.func != str_regexp)) {
if (wide ? (numlen == 0 || numlen > 6) : (numlen < 4)) {
- flush_string_content(p, rb_utf8_encoding(), p->lex.pcur - begin);
+ literal_flush(p, p->lex.pcur);
yyerror0("invalid Unicode escape");
- dispatch_scan_event(p, tSTRING_CONTENT);
return wide && numlen > 0;
}
if (codepoint > 0x10ffff) {
- flush_string_content(p, rb_utf8_encoding(), p->lex.pcur - begin);
+ literal_flush(p, p->lex.pcur);
yyerror0("invalid Unicode codepoint (too large)");
- dispatch_scan_event(p, tSTRING_CONTENT);
return wide;
}
if ((codepoint & 0xfffff800) == 0xd800) {
- flush_string_content(p, rb_utf8_encoding(), p->lex.pcur - begin);
+ literal_flush(p, p->lex.pcur);
yyerror0("invalid Unicode codepoint");
- dispatch_scan_event(p, tSTRING_CONTENT);
return wide;
}
}
if (regexp_literal) {
- tokcopy(p, (int)numlen);
+ tokcopy(p, (int)numlen);
}
else if (codepoint >= 0x80) {
- rb_encoding *utf8 = rb_utf8_encoding();
- if (*encp && utf8 != *encp) {
- YYLTYPE loc = RUBY_INIT_YYLLOC();
- compile_error(p, "UTF-8 mixed within %s source", rb_enc_name(*encp));
- parser_show_error_line(p, &loc);
- return wide;
- }
- *encp = utf8;
- tokaddmbc(p, codepoint, *encp);
+ rb_encoding *utf8 = rb_utf8_encoding();
+ if (*encp && utf8 != *encp) {
+ YYLTYPE loc = RUBY_INIT_YYLLOC();
+ compile_error(p, "UTF-8 mixed within %s source", rb_enc_name(*encp));
+ parser_show_error_line(p, &loc);
+ return wide;
+ }
+ *encp = utf8;
+ tokaddmbc(p, codepoint, *encp);
}
else {
- tokadd(p, codepoint);
+ tokadd(p, codepoint);
}
return TRUE;
}
@@ -8011,7 +7288,7 @@ tokskip_mbchar(struct parser_params *p)
/* return value is for ?\u3042 */
static void
tokadd_utf8(struct parser_params *p, rb_encoding **encp,
- int term, int symbol_literal, int regexp_literal)
+ int term, int symbol_literal, int regexp_literal)
{
/*
* If `term` is not -1, then we allow multiple codepoints in \u{}
@@ -8025,7 +7302,7 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
if (regexp_literal) { tokadd(p, '\\'); tokadd(p, 'u'); }
if (peek(p, open_brace)) { /* handle \u{...} form */
- if (regexp_literal && p->lex.strterm->u.literal.func == str_regexp) {
+ if (regexp_literal && p->lex.strterm->u.literal.u1.func == str_regexp) {
/*
* Skip parsing validation code and copy bytes as-is until term or
* closing brace, in order to correctly handle extended regexps where
@@ -8033,7 +7310,7 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
* does its own validation and will catch any issues.
*/
tokadd(p, open_brace);
- while (!lex_eol_ptr_p(p, ++p->lex.pcur)) {
+ while (++p->lex.pcur < p->lex.pend) {
int c = peekc(p);
if (c == close_brace) {
tokadd(p, c);
@@ -8043,7 +7320,7 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
else if (c == term) {
break;
}
- if (c == '\\' && !lex_eol_n_p(p, 1)) {
+ if (c == '\\' && p->lex.pcur + 1 < p->lex.pend) {
tokadd(p, c);
c = *++p->lex.pcur;
}
@@ -8053,18 +7330,18 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
else {
const char *second = NULL;
int c, last = nextc(p);
- if (lex_eol_p(p)) goto unterminated;
- while (ISSPACE(c = peekc(p)) && !lex_eol_ptr_p(p, ++p->lex.pcur));
+ if (p->lex.pcur >= p->lex.pend) goto unterminated;
+ while (ISSPACE(c = *p->lex.pcur) && ++p->lex.pcur < p->lex.pend);
while (c != close_brace) {
if (c == term) goto unterminated;
if (second == multiple_codepoints)
second = p->lex.pcur;
if (regexp_literal) tokadd(p, last);
- if (!tokadd_codepoint(p, encp, regexp_literal, NULL)) {
+ if (!tokadd_codepoint(p, encp, regexp_literal, TRUE)) {
break;
}
- while (ISSPACE(c = peekc(p))) {
- if (lex_eol_ptr_p(p, ++p->lex.pcur)) goto unterminated;
+ while (ISSPACE(c = *p->lex.pcur)) {
+ if (++p->lex.pcur >= p->lex.pend) goto unterminated;
last = c;
}
if (term == -1 && !second)
@@ -8073,9 +7350,8 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
if (c != close_brace) {
unterminated:
- flush_string_content(p, rb_utf8_encoding(), 0);
+ token_flush(p);
yyerror0("unterminated Unicode escape");
- dispatch_scan_event(p, tSTRING_CONTENT);
return;
}
if (second && second != multiple_codepoints) {
@@ -8093,10 +7369,10 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
}
}
else { /* handle \uxxxx form */
- if (!tokadd_codepoint(p, encp, regexp_literal, p->lex.pcur - rb_strlen_lit("\\u"))) {
- token_flush(p);
- return;
- }
+ if (!tokadd_codepoint(p, encp, regexp_literal, FALSE)) {
+ token_flush(p);
+ return;
+ }
}
}
@@ -8104,140 +7380,139 @@ tokadd_utf8(struct parser_params *p, rb_encoding **encp,
#define ESCAPE_META 2
static int
-read_escape(struct parser_params *p, int flags, const char *begin)
+read_escape(struct parser_params *p, int flags, rb_encoding **encp)
{
int c;
size_t numlen;
switch (c = nextc(p)) {
case '\\': /* Backslash */
- return c;
+ return c;
case 'n': /* newline */
- return '\n';
+ return '\n';
case 't': /* horizontal tab */
- return '\t';
+ return '\t';
case 'r': /* carriage-return */
- return '\r';
+ return '\r';
case 'f': /* form-feed */
- return '\f';
+ return '\f';
case 'v': /* vertical tab */
- return '\13';
+ return '\13';
case 'a': /* alarm(bell) */
- return '\007';
+ return '\007';
case 'e': /* escape */
- return 033;
+ return 033;
case '0': case '1': case '2': case '3': /* octal constant */
case '4': case '5': case '6': case '7':
- pushback(p, c);
- c = (int)ruby_scan_oct(p->lex.pcur, 3, &numlen);
- p->lex.pcur += numlen;
- return c;
+ pushback(p, c);
+ c = scan_oct(p->lex.pcur, 3, &numlen);
+ p->lex.pcur += numlen;
+ return c;
case 'x': /* hex constant */
- c = tok_hex(p, &numlen);
- if (numlen == 0) return 0;
- return c;
+ c = tok_hex(p, &numlen);
+ if (numlen == 0) return 0;
+ return c;
case 'b': /* backspace */
- return '\010';
+ return '\010';
case 's': /* space */
- return ' ';
+ return ' ';
case 'M':
- if (flags & ESCAPE_META) goto eof;
- if ((c = nextc(p)) != '-') {
- goto eof;
- }
- if ((c = nextc(p)) == '\\') {
- switch (peekc(p)) {
- case 'u': case 'U':
- nextc(p);
- goto eof;
- }
- return read_escape(p, flags|ESCAPE_META, begin) | 0x80;
- }
+ if (flags & ESCAPE_META) goto eof;
+ if ((c = nextc(p)) != '-') {
+ goto eof;
+ }
+ if ((c = nextc(p)) == '\\') {
+ switch (peekc(p)) {
+ case 'u': case 'U':
+ nextc(p);
+ goto eof;
+ }
+ return read_escape(p, flags|ESCAPE_META, encp) | 0x80;
+ }
else if (c == -1) goto eof;
else if (!ISASCII(c)) {
tokskip_mbchar(p);
goto eof;
}
- else {
- int c2 = escaped_control_code(c);
- if (c2) {
- if (ISCNTRL(c) || !(flags & ESCAPE_CONTROL)) {
- WARN_SPACE_CHAR(c2, "\\M-");
- }
- else {
- WARN_SPACE_CHAR(c2, "\\C-\\M-");
- }
- }
- else if (ISCNTRL(c)) goto eof;
- return ((c & 0xff) | 0x80);
- }
+ else {
+ int c2 = escaped_control_code(c);
+ if (c2) {
+ if (ISCNTRL(c) || !(flags & ESCAPE_CONTROL)) {
+ WARN_SPACE_CHAR(c2, "\\M-");
+ }
+ else {
+ WARN_SPACE_CHAR(c2, "\\C-\\M-");
+ }
+ }
+ else if (ISCNTRL(c)) goto eof;
+ return ((c & 0xff) | 0x80);
+ }
case 'C':
- if ((c = nextc(p)) != '-') {
- goto eof;
- }
+ if ((c = nextc(p)) != '-') {
+ goto eof;
+ }
case 'c':
- if (flags & ESCAPE_CONTROL) goto eof;
- if ((c = nextc(p))== '\\') {
- switch (peekc(p)) {
- case 'u': case 'U':
- nextc(p);
- goto eof;
- }
- c = read_escape(p, flags|ESCAPE_CONTROL, begin);
- }
- else if (c == '?')
- return 0177;
+ if (flags & ESCAPE_CONTROL) goto eof;
+ if ((c = nextc(p))== '\\') {
+ switch (peekc(p)) {
+ case 'u': case 'U':
+ nextc(p);
+ goto eof;
+ }
+ c = read_escape(p, flags|ESCAPE_CONTROL, encp);
+ }
+ else if (c == '?')
+ return 0177;
else if (c == -1) goto eof;
else if (!ISASCII(c)) {
tokskip_mbchar(p);
goto eof;
}
- else {
- int c2 = escaped_control_code(c);
- if (c2) {
- if (ISCNTRL(c)) {
- if (flags & ESCAPE_META) {
- WARN_SPACE_CHAR(c2, "\\M-");
- }
- else {
- WARN_SPACE_CHAR(c2, "");
- }
- }
- else {
- if (flags & ESCAPE_META) {
- WARN_SPACE_CHAR(c2, "\\M-\\C-");
- }
- else {
- WARN_SPACE_CHAR(c2, "\\C-");
- }
- }
- }
- else if (ISCNTRL(c)) goto eof;
- }
- return c & 0x9f;
+ else {
+ int c2 = escaped_control_code(c);
+ if (c2) {
+ if (ISCNTRL(c)) {
+ if (flags & ESCAPE_META) {
+ WARN_SPACE_CHAR(c2, "\\M-");
+ }
+ else {
+ WARN_SPACE_CHAR(c2, "");
+ }
+ }
+ else {
+ if (flags & ESCAPE_META) {
+ WARN_SPACE_CHAR(c2, "\\M-\\C-");
+ }
+ else {
+ WARN_SPACE_CHAR(c2, "\\C-");
+ }
+ }
+ }
+ else if (ISCNTRL(c)) goto eof;
+ }
+ return c & 0x9f;
eof:
case -1:
- flush_string_content(p, p->enc, p->lex.pcur - begin);
yyerror0("Invalid escape character syntax");
dispatch_scan_event(p, tSTRING_CONTENT);
- return '\0';
+ return '\0';
default:
- return c;
+ return c;
}
}
@@ -8249,104 +7524,47 @@ tokaddmbc(struct parser_params *p, int c, rb_encoding *enc)
}
static int
-tokadd_escape(struct parser_params *p)
+tokadd_escape(struct parser_params *p, rb_encoding **encp)
{
int c;
size_t numlen;
- const char *begin = p->lex.pcur;
switch (c = nextc(p)) {
case '\n':
- return 0; /* just ignore */
+ return 0; /* just ignore */
case '0': case '1': case '2': case '3': /* octal constant */
case '4': case '5': case '6': case '7':
- {
- ruby_scan_oct(--p->lex.pcur, 3, &numlen);
- if (numlen == 0) goto eof;
- p->lex.pcur += numlen;
- tokcopy(p, (int)numlen + 1);
- }
- return 0;
+ {
+ ruby_scan_oct(--p->lex.pcur, 3, &numlen);
+ if (numlen == 0) goto eof;
+ p->lex.pcur += numlen;
+ tokcopy(p, (int)numlen + 1);
+ }
+ return 0;
case 'x': /* hex constant */
- {
- tok_hex(p, &numlen);
- if (numlen == 0) return -1;
- tokcopy(p, (int)numlen + 2);
- }
- return 0;
+ {
+ tok_hex(p, &numlen);
+ if (numlen == 0) return -1;
+ tokcopy(p, (int)numlen + 2);
+ }
+ return 0;
eof:
case -1:
- flush_string_content(p, p->enc, p->lex.pcur - begin);
yyerror0("Invalid escape character syntax");
- token_flush(p);
- return -1;
+ token_flush(p);
+ return -1;
default:
- tokadd(p, '\\');
- tokadd(p, c);
+ tokadd(p, '\\');
+ tokadd(p, c);
}
return 0;
}
static int
-char_to_option(int c)
-{
- int val;
-
- switch (c) {
- case 'i':
- val = RE_ONIG_OPTION_IGNORECASE;
- break;
- case 'x':
- val = RE_ONIG_OPTION_EXTEND;
- break;
- case 'm':
- val = RE_ONIG_OPTION_MULTILINE;
- break;
- default:
- val = 0;
- break;
- }
- return val;
-}
-
-#define ARG_ENCODING_FIXED 16
-#define ARG_ENCODING_NONE 32
-#define ENC_ASCII8BIT 1
-#define ENC_EUC_JP 2
-#define ENC_Windows_31J 3
-#define ENC_UTF8 4
-
-static int
-char_to_option_kcode(int c, int *option, int *kcode)
-{
- *option = 0;
-
- switch (c) {
- case 'n':
- *kcode = ENC_ASCII8BIT;
- return (*option = ARG_ENCODING_NONE);
- case 'e':
- *kcode = ENC_EUC_JP;
- break;
- case 's':
- *kcode = ENC_Windows_31J;
- break;
- case 'u':
- *kcode = ENC_UTF8;
- break;
- default:
- *kcode = -1;
- return (*option = char_to_option(c));
- }
- *option = ARG_ENCODING_FIXED;
- return 1;
-}
-
-static int
regx_options(struct parser_params *p)
{
int kcode = 0;
@@ -8359,27 +7577,27 @@ regx_options(struct parser_params *p)
if (c == 'o') {
options |= RE_OPTION_ONCE;
}
- else if (char_to_option_kcode(c, &opt, &kc)) {
- if (kc >= 0) {
- if (kc != ENC_ASCII8BIT) kcode = c;
- kopt = opt;
- }
- else {
- options |= opt;
- }
+ else if (rb_char_to_option_kcode(c, &opt, &kc)) {
+ if (kc >= 0) {
+ if (kc != rb_ascii8bit_encindex()) kcode = c;
+ kopt = opt;
+ }
+ else {
+ options |= opt;
+ }
}
else {
- tokadd(p, c);
+ tokadd(p, c);
}
}
options |= kopt;
pushback(p, c);
if (toklen(p)) {
- YYLTYPE loc = RUBY_INIT_YYLLOC();
- tokfix(p);
- compile_error(p, "unknown regexp option%s - %*s",
- toklen(p) > 1 ? "s" : "", toklen(p), tok(p));
- parser_show_error_line(p, &loc);
+ YYLTYPE loc = RUBY_INIT_YYLLOC();
+ tokfix(p);
+ compile_error(p, "unknown regexp option%s - %*s",
+ toklen(p) > 1 ? "s" : "", toklen(p), tok(p));
+ parser_show_error_line(p, &loc);
}
return options | RE_OPTION_ENCODING(kcode);
}
@@ -8402,9 +7620,9 @@ simple_re_meta(int c)
case '$': case '*': case '+': case '.':
case '?': case '^': case '|':
case ')': case ']': case '}': case '>':
- return TRUE;
+ return TRUE;
default:
- return FALSE;
+ return FALSE;
}
}
@@ -8412,28 +7630,24 @@ static int
parser_update_heredoc_indent(struct parser_params *p, int c)
{
if (p->heredoc_line_indent == -1) {
- if (c == '\n') p->heredoc_line_indent = 0;
+ if (c == '\n') p->heredoc_line_indent = 0;
}
else {
- if (c == ' ') {
- p->heredoc_line_indent++;
- return TRUE;
- }
- else if (c == '\t') {
- int w = (p->heredoc_line_indent / TAB_WIDTH) + 1;
- p->heredoc_line_indent = w * TAB_WIDTH;
- return TRUE;
- }
- else if (c != '\n') {
- if (p->heredoc_indent > p->heredoc_line_indent) {
- p->heredoc_indent = p->heredoc_line_indent;
- }
- p->heredoc_line_indent = -1;
- }
- else {
- /* Whitespace only line has no indentation */
- p->heredoc_line_indent = 0;
- }
+ if (c == ' ') {
+ p->heredoc_line_indent++;
+ return TRUE;
+ }
+ else if (c == '\t') {
+ int w = (p->heredoc_line_indent / TAB_WIDTH) + 1;
+ p->heredoc_line_indent = w * TAB_WIDTH;
+ return TRUE;
+ }
+ else if (c != '\n') {
+ if (p->heredoc_indent > p->heredoc_line_indent) {
+ p->heredoc_indent = p->heredoc_line_indent;
+ }
+ p->heredoc_line_indent = -1;
+ }
}
return FALSE;
}
@@ -8456,17 +7670,10 @@ parser_mixed_escape(struct parser_params *p, const char *beg, rb_encoding *enc1,
p->lex.pcur = pos;
}
-static inline char
-nibble_char_upper(unsigned int c)
-{
- c &= 0xf;
- return c + (c < 10 ? '0' : 'A' - 10);
-}
-
static int
tokadd_string(struct parser_params *p,
- int func, int term, int paren, long *nest,
- rb_encoding **encp, rb_encoding **enc)
+ int func, int term, int paren, long *nest,
+ rb_encoding **encp, rb_encoding **enc)
{
int c;
bool erred = false;
@@ -8481,9 +7688,9 @@ tokadd_string(struct parser_params *p,
(void)(erred || (parser_mixed_escape(p, beg, enc1, enc2), erred = true))
while ((c = nextc(p)) != -1) {
- if (p->heredoc_indent > 0) {
- parser_update_heredoc_indent(p, c);
- }
+ if (p->heredoc_indent > 0) {
+ parser_update_heredoc_indent(p, c);
+ }
#ifdef RIPPER
if (top_of_line && heredoc_end == p->ruby_sourceline) {
pushback(p, c);
@@ -8491,131 +7698,132 @@ tokadd_string(struct parser_params *p,
}
#endif
- if (paren && c == paren) {
- ++*nest;
- }
- else if (c == term) {
- if (!nest || !*nest) {
- pushback(p, c);
- break;
- }
- --*nest;
- }
- else if ((func & STR_FUNC_EXPAND) && c == '#' && !lex_eol_p(p)) {
- unsigned char c2 = *p->lex.pcur;
- if (c2 == '$' || c2 == '@' || c2 == '{') {
- pushback(p, c);
- break;
- }
- }
- else if (c == '\\') {
- c = nextc(p);
- switch (c) {
- case '\n':
- if (func & STR_FUNC_QWORDS) break;
- if (func & STR_FUNC_EXPAND) {
- if (!(func & STR_FUNC_INDENT) || (p->heredoc_indent < 0))
- continue;
- if (c == term) {
- c = '\\';
- goto terminate;
- }
- }
- tokadd(p, '\\');
- break;
-
- case '\\':
- if (func & STR_FUNC_ESCAPE) tokadd(p, c);
- break;
-
- case 'u':
- if ((func & STR_FUNC_EXPAND) == 0) {
- tokadd(p, '\\');
- break;
- }
- tokadd_utf8(p, enc, term,
- func & STR_FUNC_SYMBOL,
- func & STR_FUNC_REGEXP);
- continue;
-
- default:
- if (c == -1) return -1;
- if (!ISASCII(c)) {
- if ((func & STR_FUNC_EXPAND) == 0) tokadd(p, '\\');
- goto non_ascii;
- }
- if (func & STR_FUNC_REGEXP) {
+ if (paren && c == paren) {
+ ++*nest;
+ }
+ else if (c == term) {
+ if (!nest || !*nest) {
+ pushback(p, c);
+ break;
+ }
+ --*nest;
+ }
+ else if ((func & STR_FUNC_EXPAND) && c == '#' && p->lex.pcur < p->lex.pend) {
+ unsigned char c2 = *p->lex.pcur;
+ if (c2 == '$' || c2 == '@' || c2 == '{') {
+ pushback(p, c);
+ break;
+ }
+ }
+ else if (c == '\\') {
+ c = nextc(p);
+ switch (c) {
+ case '\n':
+ if (func & STR_FUNC_QWORDS) break;
+ if (func & STR_FUNC_EXPAND) {
+ if (!(func & STR_FUNC_INDENT) || (p->heredoc_indent < 0))
+ continue;
+ if (c == term) {
+ c = '\\';
+ goto terminate;
+ }
+ }
+ tokadd(p, '\\');
+ break;
+
+ case '\\':
+ if (func & STR_FUNC_ESCAPE) tokadd(p, c);
+ break;
+
+ case 'u':
+ if ((func & STR_FUNC_EXPAND) == 0) {
+ tokadd(p, '\\');
+ break;
+ }
+ tokadd_utf8(p, enc, term,
+ func & STR_FUNC_SYMBOL,
+ func & STR_FUNC_REGEXP);
+ continue;
+
+ default:
+ if (c == -1) return -1;
+ if (!ISASCII(c)) {
+ if ((func & STR_FUNC_EXPAND) == 0) tokadd(p, '\\');
+ goto non_ascii;
+ }
+ if (func & STR_FUNC_REGEXP) {
switch (c) {
case 'c':
case 'C':
case 'M': {
pushback(p, c);
- c = read_escape(p, 0, p->lex.pcur - 1);
+ c = read_escape(p, 0, enc);
- char *t = tokspace(p, rb_strlen_lit("\\x00"));
- *t++ = '\\';
- *t++ = 'x';
- *t++ = nibble_char_upper(c >> 4);
- *t++ = nibble_char_upper(c);
+ int i;
+ char escbuf[5];
+ snprintf(escbuf, sizeof(escbuf), "\\x%02X", c);
+ for (i = 0; i < 4; i++) {
+ tokadd(p, escbuf[i]);
+ }
continue;
}
}
- if (c == term && !simple_re_meta(c)) {
- tokadd(p, c);
- continue;
- }
- pushback(p, c);
- if ((c = tokadd_escape(p)) < 0)
- return -1;
- if (*enc && *enc != *encp) {
- mixed_escape(p->lex.ptok+2, *enc, *encp);
- }
- continue;
- }
- else if (func & STR_FUNC_EXPAND) {
- pushback(p, c);
- if (func & STR_FUNC_ESCAPE) tokadd(p, '\\');
- c = read_escape(p, 0, p->lex.pcur - 1);
- }
- else if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
- /* ignore backslashed spaces in %w */
- }
- else if (c != term && !(paren && c == paren)) {
- tokadd(p, '\\');
- pushback(p, c);
- continue;
- }
- }
- }
- else if (!parser_isascii(p)) {
- non_ascii:
- if (!*enc) {
- *enc = *encp;
- }
- else if (*enc != *encp) {
- mixed_error(*enc, *encp);
- continue;
- }
- if (tokadd_mbchar(p, c) == -1) return -1;
- continue;
- }
- else if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
- pushback(p, c);
- break;
- }
+ if (c == term && !simple_re_meta(c)) {
+ tokadd(p, c);
+ continue;
+ }
+ pushback(p, c);
+ if ((c = tokadd_escape(p, enc)) < 0)
+ return -1;
+ if (*enc && *enc != *encp) {
+ mixed_escape(p->lex.ptok+2, *enc, *encp);
+ }
+ continue;
+ }
+ else if (func & STR_FUNC_EXPAND) {
+ pushback(p, c);
+ if (func & STR_FUNC_ESCAPE) tokadd(p, '\\');
+ c = read_escape(p, 0, enc);
+ }
+ else if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
+ /* ignore backslashed spaces in %w */
+ }
+ else if (c != term && !(paren && c == paren)) {
+ tokadd(p, '\\');
+ pushback(p, c);
+ continue;
+ }
+ }
+ }
+ else if (!parser_isascii(p)) {
+ non_ascii:
+ if (!*enc) {
+ *enc = *encp;
+ }
+ else if (*enc != *encp) {
+ mixed_error(*enc, *encp);
+ continue;
+ }
+ if (tokadd_mbchar(p, c) == -1) return -1;
+ continue;
+ }
+ else if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
+ pushback(p, c);
+ break;
+ }
if (c & 0x80) {
- if (!*enc) {
- *enc = *encp;
- }
- else if (*enc != *encp) {
- mixed_error(*enc, *encp);
- continue;
- }
- }
- tokadd(p, c);
+ if (!*enc) {
+ *enc = *encp;
+ }
+ else if (*enc != *encp) {
+ mixed_error(*enc, *encp);
+ continue;
+ }
+ }
+ tokadd(p, c);
#ifdef RIPPER
- top_of_line = (c == '\n');
+ top_of_line = (c == '\n');
#endif
}
terminate:
@@ -8623,38 +7831,68 @@ tokadd_string(struct parser_params *p,
return c;
}
-#define NEW_STRTERM(func, term, paren) new_strterm(p, func, term, paren)
+static inline rb_strterm_t *
+new_strterm(VALUE v1, VALUE v2, VALUE v3, VALUE v0)
+{
+ return (rb_strterm_t*)rb_imemo_new(imemo_parser_strterm, v1, v2, v3, v0);
+}
+/* imemo_parser_strterm for literal */
+#define NEW_STRTERM(func, term, paren) \
+ new_strterm((VALUE)(func), (VALUE)(paren), (VALUE)(term), 0)
+
+#ifdef RIPPER
static void
-flush_string_content(struct parser_params *p, rb_encoding *enc, size_t back)
+flush_string_content(struct parser_params *p, rb_encoding *enc)
{
- p->lex.pcur -= back;
+ VALUE content = yylval.val;
+ if (!ripper_is_node_yylval(content))
+ content = ripper_new_yylval(p, 0, 0, content);
if (has_delayed_token(p)) {
- ptrdiff_t len = p->lex.pcur - p->lex.ptok;
- if (len > 0) {
- rb_parser_enc_str_buf_cat(p, p->delayed.token, p->lex.ptok, len, enc);
- p->delayed.end_line = p->ruby_sourceline;
- p->delayed.end_col = rb_long2int(p->lex.pcur - p->lex.pbeg);
- }
- dispatch_delayed_token(p, tSTRING_CONTENT);
- p->lex.ptok = p->lex.pcur;
+ ptrdiff_t len = p->lex.pcur - p->lex.ptok;
+ if (len > 0) {
+ rb_enc_str_buf_cat(p->delayed.token, p->lex.ptok, len, enc);
+ }
+ dispatch_delayed_token(p, tSTRING_CONTENT);
+ p->lex.ptok = p->lex.pcur;
+ RNODE(content)->nd_rval = yylval.val;
+ }
+ dispatch_scan_event(p, tSTRING_CONTENT);
+ if (yylval.val != content)
+ RNODE(content)->nd_rval = yylval.val;
+ yylval.val = content;
+}
+#else
+static void
+flush_string_content(struct parser_params *p, rb_encoding *enc)
+{
+ if (has_delayed_token(p)) {
+ ptrdiff_t len = p->lex.pcur - p->lex.ptok;
+ if (len > 0) {
+ rb_enc_str_buf_cat(p->delayed.token, p->lex.ptok, len, enc);
+ p->delayed.end_line = p->ruby_sourceline;
+ p->delayed.end_col = rb_long2int(p->lex.pcur - p->lex.pbeg);
+ }
+ dispatch_delayed_token(p, tSTRING_CONTENT);
+ p->lex.ptok = p->lex.pcur;
}
dispatch_scan_event(p, tSTRING_CONTENT);
- p->lex.pcur += back;
}
+#endif
+RUBY_FUNC_EXPORTED const unsigned int ruby_global_name_punct_bits[(0x7e - 0x20 + 31) / 32];
/* this can be shared with ripper, since it's independent from struct
* parser_params. */
#ifndef RIPPER
#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
#define SPECIAL_PUNCT(idx) ( \
- BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
- BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
- BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
- BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
- BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
- BIT('0', idx))
-const uint_least32_t ruby_global_name_punct_bits[] = {
+ BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
+ BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
+ BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
+ BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
+ BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
+ BIT('0', idx))
+const unsigned int ruby_global_name_punct_bits[] = {
SPECIAL_PUNCT(0),
SPECIAL_PUNCT(1),
SPECIAL_PUNCT(2),
@@ -8669,34 +7907,33 @@ parser_peek_variable_name(struct parser_params *p)
int c;
const char *ptr = p->lex.pcur;
- if (lex_eol_ptr_n_p(p, ptr, 1)) return 0;
+ if (ptr + 1 >= p->lex.pend) return 0;
c = *ptr++;
switch (c) {
case '$':
- if ((c = *ptr) == '-') {
- if (lex_eol_ptr_p(p, ++ptr)) return 0;
- c = *ptr;
- }
- else if (is_global_name_punct(c) || ISDIGIT(c)) {
- return tSTRING_DVAR;
- }
- break;
+ if ((c = *ptr) == '-') {
+ if (++ptr >= p->lex.pend) return 0;
+ c = *ptr;
+ }
+ else if (is_global_name_punct(c) || ISDIGIT(c)) {
+ return tSTRING_DVAR;
+ }
+ break;
case '@':
- if ((c = *ptr) == '@') {
- if (lex_eol_ptr_p(p, ++ptr)) return 0;
- c = *ptr;
- }
- break;
+ if ((c = *ptr) == '@') {
+ if (++ptr >= p->lex.pend) return 0;
+ c = *ptr;
+ }
+ break;
case '{':
- p->lex.pcur = ptr;
- p->command_start = TRUE;
- yylval.state = p->lex.state;
- return tSTRING_DBEG;
+ p->lex.pcur = ptr;
+ p->command_start = TRUE;
+ return tSTRING_DBEG;
default:
- return 0;
+ return 0;
}
if (!ISASCII(c) || c == '_' || ISALPHA(c))
- return tSTRING_DVAR;
+ return tSTRING_DVAR;
return 0;
}
@@ -8705,26 +7942,25 @@ parser_peek_variable_name(struct parser_params *p)
#define IS_BEG() (IS_lex_state(EXPR_BEG_ANY) || IS_lex_state_all(EXPR_ARG|EXPR_LABELED))
#define IS_SPCARG(c) (IS_ARG() && space_seen && !ISSPACE(c))
#define IS_LABEL_POSSIBLE() (\
- (IS_lex_state(EXPR_LABEL|EXPR_ENDFN) && !cmd_state) || \
- IS_ARG())
+ (IS_lex_state(EXPR_LABEL|EXPR_ENDFN) && !cmd_state) || \
+ IS_ARG())
#define IS_LABEL_SUFFIX(n) (peek_n(p, ':',(n)) && !peek_n(p, ':', (n)+1))
#define IS_AFTER_OPERATOR() IS_lex_state(EXPR_FNAME | EXPR_DOT)
static inline enum yytokentype
parser_string_term(struct parser_params *p, int func)
{
- xfree(p->lex.strterm);
p->lex.strterm = 0;
if (func & STR_FUNC_REGEXP) {
- set_yylval_num(regx_options(p));
- dispatch_scan_event(p, tREGEXP_END);
- SET_LEX_STATE(EXPR_END);
- return tREGEXP_END;
+ set_yylval_num(regx_options(p));
+ dispatch_scan_event(p, tREGEXP_END);
+ SET_LEX_STATE(EXPR_END);
+ return tREGEXP_END;
}
if ((func & STR_FUNC_LABEL) && IS_LABEL_SUFFIX(0)) {
- nextc(p);
- SET_LEX_STATE(EXPR_ARG|EXPR_LABELED);
- return tLABEL_END;
+ nextc(p);
+ SET_LEX_STATE(EXPR_ARG|EXPR_LABELED);
+ return tLABEL_END;
}
SET_LEX_STATE(EXPR_END);
return tSTRING_END;
@@ -8733,82 +7969,80 @@ parser_string_term(struct parser_params *p, int func)
static enum yytokentype
parse_string(struct parser_params *p, rb_strterm_literal_t *quote)
{
- int func = quote->func;
- int term = quote->term;
- int paren = quote->paren;
+ int func = (int)quote->u1.func;
+ int term = (int)quote->u3.term;
+ int paren = (int)quote->u2.paren;
int c, space = 0;
rb_encoding *enc = p->enc;
rb_encoding *base_enc = 0;
- rb_parser_string_t *lit;
+ VALUE lit;
if (func & STR_FUNC_TERM) {
- if (func & STR_FUNC_QWORDS) nextc(p); /* delayed term */
- SET_LEX_STATE(EXPR_END);
- xfree(p->lex.strterm);
- p->lex.strterm = 0;
- return func & STR_FUNC_REGEXP ? tREGEXP_END : tSTRING_END;
+ if (func & STR_FUNC_QWORDS) nextc(p); /* delayed term */
+ SET_LEX_STATE(EXPR_END);
+ p->lex.strterm = 0;
+ return func & STR_FUNC_REGEXP ? tREGEXP_END : tSTRING_END;
}
c = nextc(p);
if ((func & STR_FUNC_QWORDS) && ISSPACE(c)) {
- while (c != '\n' && ISSPACE(c = nextc(p)));
- space = 1;
+ do {c = nextc(p);} while (ISSPACE(c));
+ space = 1;
}
if (func & STR_FUNC_LIST) {
- quote->func &= ~STR_FUNC_LIST;
- space = 1;
- }
- if (c == term && !quote->nest) {
- if (func & STR_FUNC_QWORDS) {
- quote->func |= STR_FUNC_TERM;
- pushback(p, c); /* dispatch the term at tSTRING_END */
- add_delayed_token(p, p->lex.ptok, p->lex.pcur);
- return ' ';
- }
- return parser_string_term(p, func);
+ quote->u1.func &= ~STR_FUNC_LIST;
+ space = 1;
+ }
+ if (c == term && !quote->u0.nest) {
+ if (func & STR_FUNC_QWORDS) {
+ quote->u1.func |= STR_FUNC_TERM;
+ pushback(p, c); /* dispatch the term at tSTRING_END */
+ add_delayed_token(p, p->lex.ptok, p->lex.pcur, __LINE__);
+ return ' ';
+ }
+ return parser_string_term(p, func);
}
if (space) {
- if (!ISSPACE(c)) pushback(p, c);
- add_delayed_token(p, p->lex.ptok, p->lex.pcur);
- return ' ';
+ pushback(p, c);
+ add_delayed_token(p, p->lex.ptok, p->lex.pcur, __LINE__);
+ return ' ';
}
newtok(p);
if ((func & STR_FUNC_EXPAND) && c == '#') {
- enum yytokentype t = parser_peek_variable_name(p);
- if (t) return t;
- tokadd(p, '#');
- c = nextc(p);
+ int t = parser_peek_variable_name(p);
+ if (t) return t;
+ tokadd(p, '#');
+ c = nextc(p);
}
pushback(p, c);
- if (tokadd_string(p, func, term, paren, &quote->nest,
- &enc, &base_enc) == -1) {
- if (p->eofp) {
+ if (tokadd_string(p, func, term, paren, &quote->u0.nest,
+ &enc, &base_enc) == -1) {
+ if (p->eofp) {
#ifndef RIPPER
# define unterminated_literal(mesg) yyerror0(mesg)
#else
-# define unterminated_literal(mesg) compile_error(p, mesg)
+# define unterminated_literal(mesg) compile_error(p, mesg)
#endif
- literal_flush(p, p->lex.pcur);
- if (func & STR_FUNC_QWORDS) {
- /* no content to add, bailing out here */
- unterminated_literal("unterminated list meets end of file");
- xfree(p->lex.strterm);
- p->lex.strterm = 0;
- return tSTRING_END;
- }
- if (func & STR_FUNC_REGEXP) {
- unterminated_literal("unterminated regexp meets end of file");
- }
- else {
- unterminated_literal("unterminated string meets end of file");
- }
- quote->func |= STR_FUNC_TERM;
- }
+ literal_flush(p, p->lex.pcur);
+ if (func & STR_FUNC_QWORDS) {
+ /* no content to add, bailing out here */
+ unterminated_literal("unterminated list meets end of file");
+ p->lex.strterm = 0;
+ return tSTRING_END;
+ }
+ if (func & STR_FUNC_REGEXP) {
+ unterminated_literal("unterminated regexp meets end of file");
+ }
+ else {
+ unterminated_literal("unterminated string meets end of file");
+ }
+ quote->u1.func |= STR_FUNC_TERM;
+ }
}
tokfix(p);
lit = STR_NEW3(tok(p), toklen(p), enc, func);
set_yylval_str(lit);
- flush_string_content(p, enc, 0);
+ flush_string_content(p, enc);
return tSTRING_CONTENT;
}
@@ -8826,70 +8060,70 @@ heredoc_identifier(struct parser_params *p)
int indent = 0;
if (c == '-') {
- c = nextc(p);
- func = STR_FUNC_INDENT;
- offset++;
+ c = nextc(p);
+ func = STR_FUNC_INDENT;
+ offset++;
}
else if (c == '~') {
- c = nextc(p);
- func = STR_FUNC_INDENT;
- offset++;
- indent = INT_MAX;
+ c = nextc(p);
+ func = STR_FUNC_INDENT;
+ offset++;
+ indent = INT_MAX;
}
switch (c) {
case '\'':
- func |= str_squote; goto quoted;
+ func |= str_squote; goto quoted;
case '"':
- func |= str_dquote; goto quoted;
+ func |= str_dquote; goto quoted;
case '`':
- token = tXSTRING_BEG;
- func |= str_xquote; goto quoted;
+ token = tXSTRING_BEG;
+ func |= str_xquote; goto quoted;
quoted:
- quote++;
- offset++;
- term = c;
- len = 0;
- while ((c = nextc(p)) != term) {
- if (c == -1 || c == '\r' || c == '\n') {
- yyerror0("unterminated here document identifier");
- return -1;
- }
- }
- break;
+ quote++;
+ offset++;
+ term = c;
+ len = 0;
+ while ((c = nextc(p)) != term) {
+ if (c == -1 || c == '\r' || c == '\n') {
+ yyerror0("unterminated here document identifier");
+ return -1;
+ }
+ }
+ break;
default:
- if (!parser_is_identchar(p)) {
- pushback(p, c);
- if (func & STR_FUNC_INDENT) {
- pushback(p, indent > 0 ? '~' : '-');
- }
- return 0;
- }
- func |= str_dquote;
- do {
- int n = parser_precise_mbclen(p, p->lex.pcur-1);
- if (n < 0) return 0;
- p->lex.pcur += --n;
- } while ((c = nextc(p)) != -1 && parser_is_identchar(p));
- pushback(p, c);
- break;
+ if (!parser_is_identchar(p)) {
+ pushback(p, c);
+ if (func & STR_FUNC_INDENT) {
+ pushback(p, indent > 0 ? '~' : '-');
+ }
+ return 0;
+ }
+ func |= str_dquote;
+ do {
+ int n = parser_precise_mbclen(p, p->lex.pcur-1);
+ if (n < 0) return 0;
+ p->lex.pcur += --n;
+ } while ((c = nextc(p)) != -1 && parser_is_identchar(p));
+ pushback(p, c);
+ break;
}
len = p->lex.pcur - (p->lex.pbeg + offset) - quote;
if ((unsigned long)len >= HERETERM_LENGTH_MAX)
- yyerror0("too long here document identifier");
+ yyerror0("too long here document identifier");
dispatch_scan_event(p, tHEREDOC_BEG);
lex_goto_eol(p);
- p->lex.strterm = new_heredoc(p);
+ p->lex.strterm = new_strterm(0, 0, 0, p->lex.lastline);
+ p->lex.strterm->flags |= STRTERM_HEREDOC;
rb_strterm_heredoc_t *here = &p->lex.strterm->u.heredoc;
here->offset = offset;
here->sourceline = p->ruby_sourceline;
- here->length = (unsigned)len;
+ here->length = (int)len;
here->quote = quote;
here->func = func;
- here->lastline = p->lex.lastline;
token_flush(p);
p->heredoc_indent = indent;
@@ -8900,141 +8134,160 @@ heredoc_identifier(struct parser_params *p)
static void
heredoc_restore(struct parser_params *p, rb_strterm_heredoc_t *here)
{
- rb_parser_string_t *line;
- rb_strterm_t *term = p->lex.strterm;
+ VALUE line;
p->lex.strterm = 0;
line = here->lastline;
p->lex.lastline = line;
- p->lex.pbeg = PARSER_STRING_PTR(line);
- p->lex.pend = p->lex.pbeg + PARSER_STRING_LEN(line);
+ p->lex.pbeg = RSTRING_PTR(line);
+ p->lex.pend = p->lex.pbeg + RSTRING_LEN(line);
p->lex.pcur = p->lex.pbeg + here->offset + here->length + here->quote;
p->lex.ptok = p->lex.pbeg + here->offset - here->quote;
p->heredoc_end = p->ruby_sourceline;
p->ruby_sourceline = (int)here->sourceline;
- if (p->eofp) p->lex.nextline = AFTER_HEREDOC_WITHOUT_TERMINTOR;
+ if (p->eofp) p->lex.nextline = Qnil;
p->eofp = 0;
- xfree(term);
}
static int
-dedent_string_column(const char *str, long len, int width)
+dedent_string(VALUE string, int width)
{
+ char *str;
+ long len;
int i, col = 0;
+ RSTRING_GETMEM(string, str, len);
for (i = 0; i < len && col < width; i++) {
- if (str[i] == ' ') {
- col++;
- }
- else if (str[i] == '\t') {
- int n = TAB_WIDTH * (col / TAB_WIDTH + 1);
- if (n > width) break;
- col = n;
- }
- else {
- break;
- }
+ if (str[i] == ' ') {
+ col++;
+ }
+ else if (str[i] == '\t') {
+ int n = TAB_WIDTH * (col / TAB_WIDTH + 1);
+ if (n > width) break;
+ col = n;
+ }
+ else {
+ break;
+ }
}
-
- return i;
-}
-
-static int
-dedent_string(struct parser_params *p, rb_parser_string_t *string, int width)
-{
- char *str;
- long len;
- int i;
-
- len = PARSER_STRING_LEN(string);
- str = PARSER_STRING_PTR(string);
-
- i = dedent_string_column(str, len, width);
if (!i) return 0;
-
- rb_parser_str_modify(string);
- str = PARSER_STRING_PTR(string);
- if (PARSER_STRING_LEN(string) != len)
- rb_fatal("literal string changed: %s", PARSER_STRING_PTR(string));
+ rb_str_modify(string);
+ str = RSTRING_PTR(string);
+ if (RSTRING_LEN(string) != len)
+ rb_fatal("literal string changed: %+"PRIsVALUE, string);
MEMMOVE(str, str + i, char, len - i);
- rb_parser_str_set_len(p, string, len - i);
+ rb_str_set_len(string, len - i);
return i;
}
+#ifndef RIPPER
static NODE *
heredoc_dedent(struct parser_params *p, NODE *root)
{
NODE *node, *str_node, *prev_node;
int indent = p->heredoc_indent;
- rb_parser_string_t *prev_lit = 0;
+ VALUE prev_lit = 0;
if (indent <= 0) return root;
+ p->heredoc_indent = 0;
if (!root) return root;
prev_node = node = str_node = root;
- if (nd_type_p(root, NODE_LIST)) str_node = RNODE_LIST(root)->nd_head;
+ if (nd_type_p(root, NODE_LIST)) str_node = root->nd_head;
while (str_node) {
- rb_parser_string_t *lit = RNODE_STR(str_node)->string;
- if (nd_fl_newline(str_node)) {
- dedent_string(p, lit, indent);
- }
- if (!prev_lit) {
- prev_lit = lit;
- }
- else if (!literal_concat0(p, prev_lit, lit)) {
- return 0;
- }
- else {
- NODE *end = RNODE_LIST(node)->as.nd_end;
- node = RNODE_LIST(prev_node)->nd_next = RNODE_LIST(node)->nd_next;
- if (!node) {
- if (nd_type_p(prev_node, NODE_DSTR))
- nd_set_type(prev_node, NODE_STR);
- break;
- }
- RNODE_LIST(node)->as.nd_end = end;
- goto next_str;
- }
-
- str_node = 0;
- while ((nd_type_p(node, NODE_LIST) || nd_type_p(node, NODE_DSTR)) && (node = RNODE_LIST(prev_node = node)->nd_next) != 0) {
- next_str:
- if (!nd_type_p(node, NODE_LIST)) break;
- if ((str_node = RNODE_LIST(node)->nd_head) != 0) {
- enum node_type type = nd_type(str_node);
- if (type == NODE_STR || type == NODE_DSTR) break;
- prev_lit = 0;
- str_node = 0;
- }
- }
+ VALUE lit = str_node->nd_lit;
+ if (str_node->flags & NODE_FL_NEWLINE) {
+ dedent_string(lit, indent);
+ }
+ if (!prev_lit) {
+ prev_lit = lit;
+ }
+ else if (!literal_concat0(p, prev_lit, lit)) {
+ return 0;
+ }
+ else {
+ NODE *end = node->nd_end;
+ node = prev_node->nd_next = node->nd_next;
+ if (!node) {
+ if (nd_type_p(prev_node, NODE_DSTR))
+ nd_set_type(prev_node, NODE_STR);
+ break;
+ }
+ node->nd_end = end;
+ goto next_str;
+ }
+
+ str_node = 0;
+ while ((node = (prev_node = node)->nd_next) != 0) {
+ next_str:
+ if (!nd_type_p(node, NODE_LIST)) break;
+ if ((str_node = node->nd_head) != 0) {
+ enum node_type type = nd_type(str_node);
+ if (type == NODE_STR || type == NODE_DSTR) break;
+ prev_lit = 0;
+ str_node = 0;
+ }
+ }
}
return root;
}
+#else /* RIPPER */
+static VALUE
+heredoc_dedent(struct parser_params *p, VALUE array)
+{
+ int indent = p->heredoc_indent;
+
+ if (indent <= 0) return array;
+ p->heredoc_indent = 0;
+ dispatch2(heredoc_dedent, array, INT2NUM(indent));
+ return array;
+}
+
+/*
+ * call-seq:
+ * Ripper.dedent_string(input, width) -> Integer
+ *
+ * USE OF RIPPER LIBRARY ONLY.
+ *
+ * Strips up to +width+ leading whitespaces from +input+,
+ * and returns the stripped column width.
+ */
+static VALUE
+parser_dedent_string(VALUE self, VALUE input, VALUE width)
+{
+ int wid, col;
+
+ StringValue(input);
+ wid = NUM2UINT(width);
+ col = dedent_string(input, wid);
+ return INT2NUM(col);
+}
+#endif
static int
whole_match_p(struct parser_params *p, const char *eos, long len, int indent)
{
- const char *beg = p->lex.pbeg;
- const char *ptr = p->lex.pend;
+ const char *ptr = p->lex.pbeg;
+ long n;
- if (ptr - beg < len) return FALSE;
- if (ptr > beg && ptr[-1] == '\n') {
- if (--ptr > beg && ptr[-1] == '\r') --ptr;
- if (ptr - beg < len) return FALSE;
- }
- if (strncmp(eos, ptr -= len, len)) return FALSE;
if (indent) {
- while (beg < ptr && ISSPACE(*beg)) beg++;
+ while (*ptr && ISSPACE(*ptr)) ptr++;
}
- return beg == ptr;
+ n = p->lex.pend - (ptr + len);
+ if (n < 0) return FALSE;
+ if (n > 0 && ptr[len] != '\n') {
+ if (ptr[len] != '\r') return FALSE;
+ if (n <= 1 || ptr[len+1] != '\n') return FALSE;
+ }
+ return strncmp(eos, ptr, len) == 0;
}
static int
word_match_p(struct parser_params *p, const char *word, long len)
{
if (strncmp(p->lex.pcur, word, len)) return 0;
- if (lex_eol_n_p(p, len)) return 1;
+ if (p->lex.pcur + len == p->lex.pend) return 1;
int c = (unsigned char)p->lex.pcur[len];
if (ISSPACE(c)) return 1;
switch (c) {
@@ -9054,89 +8307,86 @@ number_literal_suffix(struct parser_params *p, int mask)
const char *lastp = p->lex.pcur;
while ((c = nextc(p)) != -1) {
- if ((mask & NUM_SUFFIX_I) && c == 'i') {
- result |= (mask & NUM_SUFFIX_I);
- mask &= ~NUM_SUFFIX_I;
- /* r after i, rational of complex is disallowed */
- mask &= ~NUM_SUFFIX_R;
- continue;
- }
- if ((mask & NUM_SUFFIX_R) && c == 'r') {
- result |= (mask & NUM_SUFFIX_R);
- mask &= ~NUM_SUFFIX_R;
- continue;
- }
- if (!ISASCII(c) || ISALPHA(c) || c == '_') {
- p->lex.pcur = lastp;
- literal_flush(p, p->lex.pcur);
- return 0;
- }
- pushback(p, c);
- break;
+ if ((mask & NUM_SUFFIX_I) && c == 'i') {
+ result |= (mask & NUM_SUFFIX_I);
+ mask &= ~NUM_SUFFIX_I;
+ /* r after i, rational of complex is disallowed */
+ mask &= ~NUM_SUFFIX_R;
+ continue;
+ }
+ if ((mask & NUM_SUFFIX_R) && c == 'r') {
+ result |= (mask & NUM_SUFFIX_R);
+ mask &= ~NUM_SUFFIX_R;
+ continue;
+ }
+ if (!ISASCII(c) || ISALPHA(c) || c == '_') {
+ p->lex.pcur = lastp;
+ literal_flush(p, p->lex.pcur);
+ return 0;
+ }
+ pushback(p, c);
+ break;
}
return result;
}
static enum yytokentype
-set_number_literal(struct parser_params *p, enum yytokentype type, int suffix, int base, int seen_point)
+set_number_literal(struct parser_params *p, VALUE v,
+ enum yytokentype type, int suffix)
{
- enum rb_numeric_type numeric_type = integer_literal;
-
- if (type == tFLOAT) {
- numeric_type = float_literal;
+ if (suffix & NUM_SUFFIX_I) {
+ v = rb_complex_raw(INT2FIX(0), v);
+ type = tIMAGINARY;
}
+ set_yylval_literal(v);
+ SET_LEX_STATE(EXPR_END);
+ return type;
+}
+static enum yytokentype
+set_integer_literal(struct parser_params *p, VALUE v, int suffix)
+{
+ enum yytokentype type = tINTEGER;
if (suffix & NUM_SUFFIX_R) {
- type = tRATIONAL;
- numeric_type = rational_literal;
- }
- if (suffix & NUM_SUFFIX_I) {
- type = tIMAGINARY;
+ v = rb_rational_raw1(v);
+ type = tRATIONAL;
}
+ return set_number_literal(p, v, type, suffix);
+}
- switch (type) {
- case tINTEGER:
- set_yylval_node(NEW_INTEGER(strdup(tok(p)), base, &_cur_loc));
- break;
- case tFLOAT:
- set_yylval_node(NEW_FLOAT(strdup(tok(p)), &_cur_loc));
- break;
- case tRATIONAL:
- set_yylval_node(NEW_RATIONAL(strdup(tok(p)), base, seen_point, &_cur_loc));
- break;
- case tIMAGINARY:
- set_yylval_node(NEW_IMAGINARY(strdup(tok(p)), base, seen_point, numeric_type, &_cur_loc));
- (void)numeric_type; /* for ripper */
- break;
- default:
- rb_bug("unexpected token: %d", type);
- }
- SET_LEX_STATE(EXPR_END);
- return type;
+#ifdef RIPPER
+static void
+dispatch_heredoc_end(struct parser_params *p)
+{
+ VALUE str;
+ if (has_delayed_token(p))
+ dispatch_delayed_token(p, tSTRING_CONTENT);
+ str = STR_NEW(p->lex.ptok, p->lex.pend - p->lex.ptok);
+ ripper_dispatch1(p, ripper_token2eventid(tHEREDOC_END), str);
+ RUBY_SET_YYLLOC_FROM_STRTERM_HEREDOC(*p->yylloc);
+ lex_goto_eol(p);
+ token_flush(p);
}
+#else
#define dispatch_heredoc_end(p) parser_dispatch_heredoc_end(p, __LINE__)
static void
parser_dispatch_heredoc_end(struct parser_params *p, int line)
{
if (has_delayed_token(p))
- dispatch_delayed_token(p, tSTRING_CONTENT);
+ dispatch_delayed_token(p, tSTRING_CONTENT);
-#ifdef RIPPER
- VALUE str = STR_NEW(p->lex.ptok, p->lex.pend - p->lex.ptok);
- ripper_dispatch1(p, ripper_token2eventid(tHEREDOC_END), str);
-#else
if (p->keep_tokens) {
- rb_parser_string_t *str = rb_parser_encoding_string_new(p, p->lex.ptok, p->lex.pend - p->lex.ptok, p->enc);
- RUBY_SET_YYLLOC_OF_HEREDOC_END(*p->yylloc);
- parser_append_tokens(p, str, tHEREDOC_END, line);
+ VALUE str = STR_NEW(p->lex.ptok, p->lex.pend - p->lex.ptok);
+ RUBY_SET_YYLLOC_OF_HEREDOC_END(*p->yylloc);
+ parser_append_tokens(p, str, tHEREDOC_END, line);
}
-#endif
RUBY_SET_YYLLOC_FROM_STRTERM_HEREDOC(*p->yylloc);
lex_goto_eol(p);
token_flush(p);
}
+#endif
static enum yytokentype
here_document(struct parser_params *p, rb_strterm_heredoc_t *here)
@@ -9144,168 +8394,162 @@ here_document(struct parser_params *p, rb_strterm_heredoc_t *here)
int c, func, indent = 0;
const char *eos, *ptr, *ptr_end;
long len;
- rb_parser_string_t *str = 0;
+ VALUE str = 0;
rb_encoding *enc = p->enc;
rb_encoding *base_enc = 0;
int bol;
-#ifdef RIPPER
- VALUE s_value;
-#endif
- eos = PARSER_STRING_PTR(here->lastline) + here->offset;
+ eos = RSTRING_PTR(here->lastline) + here->offset;
len = here->length;
indent = (func = here->func) & STR_FUNC_INDENT;
if ((c = nextc(p)) == -1) {
error:
#ifdef RIPPER
- if (!has_delayed_token(p)) {
- dispatch_scan_event(p, tSTRING_CONTENT);
- }
- else {
- if ((len = p->lex.pcur - p->lex.ptok) > 0) {
- if (!(func & STR_FUNC_REGEXP)) {
- int cr = ENC_CODERANGE_UNKNOWN;
- rb_str_coderange_scan_restartable(p->lex.ptok, p->lex.pcur, enc, &cr);
- if (cr != ENC_CODERANGE_7BIT &&
- rb_is_usascii_enc(p->enc) &&
- enc != rb_utf8_encoding()) {
- enc = rb_ascii8bit_encoding();
- }
- }
- rb_parser_enc_str_buf_cat(p, p->delayed.token, p->lex.ptok, len, enc);
- }
- dispatch_delayed_token(p, tSTRING_CONTENT);
- }
- lex_goto_eol(p);
+ if (!has_delayed_token(p)) {
+ dispatch_scan_event(p, tSTRING_CONTENT);
+ }
+ else {
+ if ((len = p->lex.pcur - p->lex.ptok) > 0) {
+ if (!(func & STR_FUNC_REGEXP) && rb_enc_asciicompat(enc)) {
+ int cr = ENC_CODERANGE_UNKNOWN;
+ rb_str_coderange_scan_restartable(p->lex.ptok, p->lex.pcur, enc, &cr);
+ if (cr != ENC_CODERANGE_7BIT &&
+ rb_is_usascii_enc(p->enc) &&
+ enc != rb_utf8_encoding()) {
+ enc = rb_ascii8bit_encoding();
+ }
+ }
+ rb_enc_str_buf_cat(p->delayed.token, p->lex.ptok, len, enc);
+ }
+ dispatch_delayed_token(p, tSTRING_CONTENT);
+ }
+ lex_goto_eol(p);
#endif
- heredoc_restore(p, &p->lex.strterm->u.heredoc);
- compile_error(p, "can't find string \"%.*s\" anywhere before EOF",
- (int)len, eos);
- token_flush(p);
- SET_LEX_STATE(EXPR_END);
- return tSTRING_END;
+ heredoc_restore(p, &p->lex.strterm->u.heredoc);
+ compile_error(p, "can't find string \"%.*s\" anywhere before EOF",
+ (int)len, eos);
+ token_flush(p);
+ p->lex.strterm = 0;
+ SET_LEX_STATE(EXPR_END);
+ return tSTRING_END;
}
bol = was_bol(p);
if (!bol) {
- /* not beginning of line, cannot be the terminator */
+ /* not beginning of line, cannot be the terminator */
}
else if (p->heredoc_line_indent == -1) {
- /* `heredoc_line_indent == -1` means
- * - "after an interpolation in the same line", or
- * - "in a continuing line"
- */
- p->heredoc_line_indent = 0;
+ /* `heredoc_line_indent == -1` means
+ * - "after an interpolation in the same line", or
+ * - "in a continuing line"
+ */
+ p->heredoc_line_indent = 0;
}
else if (whole_match_p(p, eos, len, indent)) {
- dispatch_heredoc_end(p);
+ dispatch_heredoc_end(p);
restore:
- heredoc_restore(p, &p->lex.strterm->u.heredoc);
- token_flush(p);
- SET_LEX_STATE(EXPR_END);
- return tSTRING_END;
+ heredoc_restore(p, &p->lex.strterm->u.heredoc);
+ token_flush(p);
+ p->lex.strterm = 0;
+ SET_LEX_STATE(EXPR_END);
+ return tSTRING_END;
}
if (!(func & STR_FUNC_EXPAND)) {
- do {
- ptr = PARSER_STRING_PTR(p->lex.lastline);
- ptr_end = p->lex.pend;
- if (ptr_end > ptr) {
- switch (ptr_end[-1]) {
- case '\n':
- if (--ptr_end == ptr || ptr_end[-1] != '\r') {
- ptr_end++;
- break;
- }
- case '\r':
- --ptr_end;
- }
- }
-
- if (p->heredoc_indent > 0) {
- long i = 0;
- while (ptr + i < ptr_end && parser_update_heredoc_indent(p, ptr[i]))
- i++;
- p->heredoc_line_indent = 0;
- }
-
- if (str)
- parser_str_cat(str, ptr, ptr_end - ptr);
- else
- str = rb_parser_encoding_string_new(p, ptr, ptr_end - ptr, enc);
- if (!lex_eol_ptr_p(p, ptr_end)) parser_str_cat_cstr(str, "\n");
- lex_goto_eol(p);
- if (p->heredoc_indent > 0) {
- goto flush_str;
- }
- if (nextc(p) == -1) {
- if (str) {
- rb_parser_string_free(p, str);
- str = 0;
- }
- goto error;
- }
- } while (!whole_match_p(p, eos, len, indent));
+ do {
+ ptr = RSTRING_PTR(p->lex.lastline);
+ ptr_end = p->lex.pend;
+ if (ptr_end > ptr) {
+ switch (ptr_end[-1]) {
+ case '\n':
+ if (--ptr_end == ptr || ptr_end[-1] != '\r') {
+ ptr_end++;
+ break;
+ }
+ case '\r':
+ --ptr_end;
+ }
+ }
+
+ if (p->heredoc_indent > 0) {
+ long i = 0;
+ while (ptr + i < ptr_end && parser_update_heredoc_indent(p, ptr[i]))
+ i++;
+ p->heredoc_line_indent = 0;
+ }
+
+ if (str)
+ rb_str_cat(str, ptr, ptr_end - ptr);
+ else
+ str = STR_NEW(ptr, ptr_end - ptr);
+ if (ptr_end < p->lex.pend) rb_str_cat(str, "\n", 1);
+ lex_goto_eol(p);
+ if (p->heredoc_indent > 0) {
+ goto flush_str;
+ }
+ if (nextc(p) == -1) {
+ if (str) {
+ str = 0;
+ }
+ goto error;
+ }
+ } while (!whole_match_p(p, eos, len, indent));
}
else {
- /* int mb = ENC_CODERANGE_7BIT, *mbp = &mb;*/
- newtok(p);
- if (c == '#') {
- enum yytokentype t = parser_peek_variable_name(p);
- if (p->heredoc_line_indent != -1) {
- if (p->heredoc_indent > p->heredoc_line_indent) {
- p->heredoc_indent = p->heredoc_line_indent;
- }
- p->heredoc_line_indent = -1;
- }
- if (t) return t;
- tokadd(p, '#');
- c = nextc(p);
- }
- do {
- pushback(p, c);
- enc = p->enc;
- if ((c = tokadd_string(p, func, '\n', 0, NULL, &enc, &base_enc)) == -1) {
- if (p->eofp) goto error;
- goto restore;
- }
- if (c != '\n') {
- if (c == '\\') p->heredoc_line_indent = -1;
- flush:
- str = STR_NEW3(tok(p), toklen(p), enc, func);
- flush_str:
- set_yylval_str(str);
+ /* int mb = ENC_CODERANGE_7BIT, *mbp = &mb;*/
+ newtok(p);
+ if (c == '#') {
+ int t = parser_peek_variable_name(p);
+ if (p->heredoc_line_indent != -1) {
+ if (p->heredoc_indent > p->heredoc_line_indent) {
+ p->heredoc_indent = p->heredoc_line_indent;
+ }
+ p->heredoc_line_indent = -1;
+ }
+ if (t) return t;
+ tokadd(p, '#');
+ c = nextc(p);
+ }
+ do {
+ pushback(p, c);
+ enc = p->enc;
+ if ((c = tokadd_string(p, func, '\n', 0, NULL, &enc, &base_enc)) == -1) {
+ if (p->eofp) goto error;
+ goto restore;
+ }
+ if (c != '\n') {
+ if (c == '\\') p->heredoc_line_indent = -1;
+ flush:
+ str = STR_NEW3(tok(p), toklen(p), enc, func);
+ flush_str:
+ set_yylval_str(str);
#ifndef RIPPER
- if (bol) nd_set_fl_newline(yylval.node);
+ if (bol) yylval.node->flags |= NODE_FL_NEWLINE;
#endif
- flush_string_content(p, enc, 0);
- return tSTRING_CONTENT;
- }
- tokadd(p, nextc(p));
- if (p->heredoc_indent > 0) {
- lex_goto_eol(p);
- goto flush;
- }
- /* if (mbp && mb == ENC_CODERANGE_UNKNOWN) mbp = 0;*/
- if ((c = nextc(p)) == -1) goto error;
- } while (!whole_match_p(p, eos, len, indent));
- str = STR_NEW3(tok(p), toklen(p), enc, func);
+ flush_string_content(p, enc);
+ return tSTRING_CONTENT;
+ }
+ tokadd(p, nextc(p));
+ if (p->heredoc_indent > 0) {
+ lex_goto_eol(p);
+ goto flush;
+ }
+ /* if (mbp && mb == ENC_CODERANGE_UNKNOWN) mbp = 0;*/
+ if ((c = nextc(p)) == -1) goto error;
+ } while (!whole_match_p(p, eos, len, indent));
+ str = STR_NEW3(tok(p), toklen(p), enc, func);
}
dispatch_heredoc_end(p);
+#ifdef RIPPER
+ str = ripper_new_yylval(p, ripper_token2eventid(tSTRING_CONTENT),
+ yylval.val, str);
+#endif
heredoc_restore(p, &p->lex.strterm->u.heredoc);
token_flush(p);
p->lex.strterm = NEW_STRTERM(func | STR_FUNC_TERM, 0, 0);
-#ifdef RIPPER
- /* Preserve s_value for set_yylval_str */
- s_value = p->s_value;
-#endif
set_yylval_str(str);
-#ifdef RIPPER
- set_parser_s_value(s_value);
-#endif
-
#ifndef RIPPER
- if (bol) nd_set_fl_newline(yylval.node);
+ if (bol) yylval.node->flags |= NODE_FL_NEWLINE;
#endif
return tSTRING_CONTENT;
}
@@ -9317,10 +8561,10 @@ arg_ambiguous(struct parser_params *p, char c)
{
#ifndef RIPPER
if (c == '/') {
- rb_warning1("ambiguity between regexp and two divisions: wrap regexp in parentheses or add a space after '%c' operator", WARN_I(c));
+ rb_warning1("ambiguity between regexp and two divisions: wrap regexp in parentheses or add a space after `%c' operator", WARN_I(c));
}
else {
- rb_warning1("ambiguous first argument; put parentheses or a space even after '%c' operator", WARN_I(c));
+ rb_warning1("ambiguous first argument; put parentheses or a space even after `%c' operator", WARN_I(c));
}
#else
dispatch1(arg_ambiguous, rb_usascii_str_new(&c, 1));
@@ -9328,34 +8572,42 @@ arg_ambiguous(struct parser_params *p, char c)
return TRUE;
}
-/* returns true value if formal argument error;
- * Qtrue, or error message if ripper */
-static VALUE
-formal_argument_error(struct parser_params *p, ID id)
+static ID
+#ifndef RIPPER
+formal_argument(struct parser_params *p, ID lhs)
+#else
+formal_argument(struct parser_params *p, VALUE lhs)
+#endif
{
+ ID id = get_id(lhs);
+
switch (id_type(id)) {
case ID_LOCAL:
- break;
+ break;
#ifndef RIPPER
-# define ERR(mesg) (yyerror0(mesg), Qtrue)
+# define ERR(mesg) yyerror0(mesg)
#else
-# define ERR(mesg) WARN_S(mesg)
+# define ERR(mesg) (dispatch2(param_error, WARN_S(mesg), lhs), ripper_error(p))
#endif
case ID_CONST:
- return ERR("formal argument cannot be a constant");
+ ERR("formal argument cannot be a constant");
+ return 0;
case ID_INSTANCE:
- return ERR("formal argument cannot be an instance variable");
+ ERR("formal argument cannot be an instance variable");
+ return 0;
case ID_GLOBAL:
- return ERR("formal argument cannot be a global variable");
+ ERR("formal argument cannot be a global variable");
+ return 0;
case ID_CLASS:
- return ERR("formal argument cannot be a class variable");
+ ERR("formal argument cannot be a class variable");
+ return 0;
default:
- return ERR("formal argument must be local variable");
+ ERR("formal argument must be local variable");
+ return 0;
#undef ERR
}
shadowing_lvar(p, id);
-
- return Qfalse;
+ return lhs;
}
static int
@@ -9371,16 +8623,16 @@ parser_encode_length(struct parser_params *p, const char *name, long len)
long nlen;
if (len > 5 && name[nlen = len - 5] == '-') {
- if (rb_memcicmp(name + nlen + 1, "unix", 4) == 0)
- return nlen;
+ if (rb_memcicmp(name + nlen + 1, "unix", 4) == 0)
+ return nlen;
}
if (len > 4 && name[nlen = len - 4] == '-') {
- if (rb_memcicmp(name + nlen + 1, "dos", 3) == 0)
- return nlen;
- if (rb_memcicmp(name + nlen + 1, "mac", 3) == 0 &&
- !(len == 8 && rb_memcicmp(name, "utf8-mac", len) == 0))
- /* exclude UTF8-MAC because the encoding named "UTF8" doesn't exist in Ruby */
- return nlen;
+ if (rb_memcicmp(name + nlen + 1, "dos", 3) == 0)
+ return nlen;
+ if (rb_memcicmp(name + nlen + 1, "mac", 3) == 0 &&
+ !(len == 8 && rb_memcicmp(name, "utf8-mac", len) == 0))
+ /* exclude UTF8-MAC because the encoding named "UTF8" doesn't exist in Ruby */
+ return nlen;
}
return len;
}
@@ -9388,55 +8640,45 @@ parser_encode_length(struct parser_params *p, const char *name, long len)
static void
parser_set_encode(struct parser_params *p, const char *name)
{
+ int idx = rb_enc_find_index(name);
rb_encoding *enc;
VALUE excargs[3];
- int idx = 0;
- const char *wrong = 0;
- switch (*name) {
- case 'e': case 'E': wrong = "external"; break;
- case 'i': case 'I': wrong = "internal"; break;
- case 'f': case 'F': wrong = "filesystem"; break;
- case 'l': case 'L': wrong = "locale"; break;
- }
- if (wrong && STRCASECMP(name, wrong) == 0) goto unknown;
- idx = rb_enc_find_index(name);
if (idx < 0) {
- unknown:
- excargs[1] = rb_sprintf("unknown encoding name: %s", name);
+ excargs[1] = rb_sprintf("unknown encoding name: %s", name);
error:
- excargs[0] = rb_eArgError;
- excargs[2] = rb_make_backtrace();
- rb_ary_unshift(excargs[2], rb_sprintf("%"PRIsVALUE":%d", p->ruby_sourcefile_string, p->ruby_sourceline));
- VALUE exc = rb_make_exception(3, excargs);
- ruby_show_error_line(p, exc, &(YYLTYPE)RUBY_INIT_YYLLOC(), p->ruby_sourceline, p->lex.lastline);
-
- rb_ast_free(p->ast);
- p->ast = NULL;
-
- rb_exc_raise(exc);
+ excargs[0] = rb_eArgError;
+ excargs[2] = rb_make_backtrace();
+ rb_ary_unshift(excargs[2], rb_sprintf("%"PRIsVALUE":%d", p->ruby_sourcefile_string, p->ruby_sourceline));
+ rb_exc_raise(rb_make_exception(3, excargs));
}
enc = rb_enc_from_index(idx);
if (!rb_enc_asciicompat(enc)) {
- excargs[1] = rb_sprintf("%s is not ASCII compatible", rb_enc_name(enc));
- goto error;
+ excargs[1] = rb_sprintf("%s is not ASCII compatible", rb_enc_name(enc));
+ goto error;
}
p->enc = enc;
#ifndef RIPPER
if (p->debug_lines) {
- long i;
- for (i = 0; i < p->debug_lines->len; i++) {
- rb_parser_enc_associate(p, p->debug_lines->data[i], enc);
- }
+ VALUE lines = p->debug_lines;
+ long i, n = RARRAY_LEN(lines);
+ for (i = 0; i < n; ++i) {
+ rb_enc_associate_index(RARRAY_AREF(lines, i), idx);
+ }
}
#endif
}
-static bool
+static int
comment_at_top(struct parser_params *p)
{
- if (p->token_seen) return false;
- return (p->line_count == (p->has_shebang ? 2 : 1));
+ const char *ptr = p->lex.pbeg, *ptr_end = p->lex.pcur - 1;
+ if (p->line_count != (p->has_shebang ? 2 : 1)) return 0;
+ while (ptr < ptr_end) {
+ if (!ISSPACE(*ptr)) return 0;
+ ptr++;
+ }
+ return 1;
}
typedef long (*rb_magic_comment_length_t)(struct parser_params *p, const char *name, long len);
@@ -9448,7 +8690,7 @@ static void
magic_comment_encoding(struct parser_params *p, const char *name, const char *val)
{
if (!comment_at_top(p)) {
- return;
+ return;
}
parser_set_encode(p, val);
}
@@ -9458,15 +8700,15 @@ parser_get_bool(struct parser_params *p, const char *name, const char *val)
{
switch (*val) {
case 't': case 'T':
- if (STRCASECMP(val, "true") == 0) {
- return TRUE;
- }
- break;
+ if (STRCASECMP(val, "true") == 0) {
+ return TRUE;
+ }
+ break;
case 'f': case 'F':
- if (STRCASECMP(val, "false") == 0) {
- return FALSE;
- }
- break;
+ if (STRCASECMP(val, "false") == 0) {
+ return FALSE;
+ }
+ break;
}
return parser_invalid_pragma_value(p, name, val);
}
@@ -9486,54 +8728,57 @@ parser_set_token_info(struct parser_params *p, const char *name, const char *val
}
static void
-parser_set_frozen_string_literal(struct parser_params *p, const char *name, const char *val)
+parser_set_compile_option_flag(struct parser_params *p, const char *name, const char *val)
{
int b;
if (p->token_seen) {
- rb_warning1("'%s' is ignored after any tokens", WARN_S(name));
- return;
+ rb_warning1("`%s' is ignored after any tokens", WARN_S(name));
+ return;
}
b = parser_get_bool(p, name, val);
if (b < 0) return;
- p->frozen_string_literal = b;
+ if (!p->compile_option)
+ p->compile_option = rb_obj_hide(rb_ident_hash_new());
+ rb_hash_aset(p->compile_option, ID2SYM(rb_intern(name)),
+ RBOOL(b));
}
static void
parser_set_shareable_constant_value(struct parser_params *p, const char *name, const char *val)
{
for (const char *s = p->lex.pbeg, *e = p->lex.pcur; s < e; ++s) {
- if (*s == ' ' || *s == '\t') continue;
- if (*s == '#') break;
- rb_warning1("'%s' is ignored unless in comment-only line", WARN_S(name));
- return;
+ if (*s == ' ' || *s == '\t') continue;
+ if (*s == '#') break;
+ rb_warning1("`%s' is ignored unless in comment-only line", WARN_S(name));
+ return;
}
switch (*val) {
case 'n': case 'N':
- if (STRCASECMP(val, "none") == 0) {
- p->ctxt.shareable_constant_value = rb_parser_shareable_none;
- return;
- }
- break;
+ if (STRCASECMP(val, "none") == 0) {
+ p->ctxt.shareable_constant_value = shareable_none;
+ return;
+ }
+ break;
case 'l': case 'L':
- if (STRCASECMP(val, "literal") == 0) {
- p->ctxt.shareable_constant_value = rb_parser_shareable_literal;
- return;
- }
- break;
+ if (STRCASECMP(val, "literal") == 0) {
+ p->ctxt.shareable_constant_value = shareable_literal;
+ return;
+ }
+ break;
case 'e': case 'E':
- if (STRCASECMP(val, "experimental_copy") == 0) {
- p->ctxt.shareable_constant_value = rb_parser_shareable_copy;
- return;
- }
- if (STRCASECMP(val, "experimental_everything") == 0) {
- p->ctxt.shareable_constant_value = rb_parser_shareable_everything;
- return;
- }
- break;
+ if (STRCASECMP(val, "experimental_copy") == 0) {
+ p->ctxt.shareable_constant_value = shareable_copy;
+ return;
+ }
+ if (STRCASECMP(val, "experimental_everything") == 0) {
+ p->ctxt.shareable_constant_value = shareable_everything;
+ return;
+ }
+ break;
}
parser_invalid_pragma_value(p, name, val);
}
@@ -9556,7 +8801,7 @@ struct magic_comment {
static const struct magic_comment magic_comments[] = {
{"coding", magic_comment_encoding, parser_encode_length},
{"encoding", magic_comment_encoding, parser_encode_length},
- {"frozen_string_literal", parser_set_frozen_string_literal},
+ {"frozen_string_literal", parser_set_compile_option_flag},
{"shareable_constant_value", parser_set_shareable_constant_value},
{"warn_indent", parser_set_token_info},
# if WARN_PAST_SCOPE
@@ -9570,29 +8815,29 @@ magic_comment_marker(const char *str, long len)
long i = 2;
while (i < len) {
- switch (str[i]) {
- case '-':
- if (str[i-1] == '*' && str[i-2] == '-') {
- return str + i + 1;
- }
- i += 2;
- break;
- case '*':
- if (i + 1 >= len) return 0;
- if (str[i+1] != '-') {
- i += 4;
- }
- else if (str[i-1] != '-') {
- i += 2;
- }
- else {
- return str + i + 2;
- }
- break;
- default:
- i += 3;
- break;
- }
+ switch (str[i]) {
+ case '-':
+ if (str[i-1] == '*' && str[i-2] == '-') {
+ return str + i + 1;
+ }
+ i += 2;
+ break;
+ case '*':
+ if (i + 1 >= len) return 0;
+ if (str[i+1] != '-') {
+ i += 4;
+ }
+ else if (str[i-1] != '-') {
+ i += 2;
+ }
+ else {
+ return str + i + 2;
+ }
+ break;
+ default:
+ i += 3;
+ break;
+ }
}
return 0;
}
@@ -9604,101 +8849,97 @@ parser_magic_comment(struct parser_params *p, const char *str, long len)
VALUE name = 0, val = 0;
const char *beg, *end, *vbeg, *vend;
#define str_copy(_s, _p, _n) ((_s) \
- ? (void)(rb_str_resize((_s), (_n)), \
- MEMCPY(RSTRING_PTR(_s), (_p), char, (_n)), (_s)) \
- : (void)((_s) = STR_NEW((_p), (_n))))
+ ? (void)(rb_str_resize((_s), (_n)), \
+ MEMCPY(RSTRING_PTR(_s), (_p), char, (_n)), (_s)) \
+ : (void)((_s) = STR_NEW((_p), (_n))))
if (len <= 7) return FALSE;
if (!!(beg = magic_comment_marker(str, len))) {
- if (!(end = magic_comment_marker(beg, str + len - beg)))
- return FALSE;
- indicator = TRUE;
- str = beg;
- len = end - beg - 3;
+ if (!(end = magic_comment_marker(beg, str + len - beg)))
+ return FALSE;
+ indicator = TRUE;
+ str = beg;
+ len = end - beg - 3;
}
/* %r"([^\\s\'\":;]+)\\s*:\\s*(\"(?:\\\\.|[^\"])*\"|[^\"\\s;]+)[\\s;]*" */
while (len > 0) {
- const struct magic_comment *mc = magic_comments;
- char *s;
- int i;
- long n = 0;
-
- for (; len > 0 && *str; str++, --len) {
- switch (*str) {
- case '\'': case '"': case ':': case ';':
- continue;
- }
- if (!ISSPACE(*str)) break;
- }
- for (beg = str; len > 0; str++, --len) {
- switch (*str) {
- case '\'': case '"': case ':': case ';':
- break;
- default:
- if (ISSPACE(*str)) break;
- continue;
- }
- break;
- }
- for (end = str; len > 0 && ISSPACE(*str); str++, --len);
- if (!len) break;
- if (*str != ':') {
- if (!indicator) return FALSE;
- continue;
- }
-
- do str++; while (--len > 0 && ISSPACE(*str));
- if (!len) break;
- const char *tok_beg = str;
- if (*str == '"') {
- for (vbeg = ++str; --len > 0 && *str != '"'; str++) {
- if (*str == '\\') {
- --len;
- ++str;
- }
- }
- vend = str;
- if (len) {
- --len;
- ++str;
- }
- }
- else {
- for (vbeg = str; len > 0 && *str != '"' && *str != ';' && !ISSPACE(*str); --len, str++);
- vend = str;
- }
- const char *tok_end = str;
- if (indicator) {
- while (len > 0 && (*str == ';' || ISSPACE(*str))) --len, str++;
- }
- else {
- while (len > 0 && (ISSPACE(*str))) --len, str++;
- if (len) return FALSE;
- }
-
- n = end - beg;
- str_copy(name, beg, n);
- s = RSTRING_PTR(name);
- for (i = 0; i < n; ++i) {
- if (s[i] == '-') s[i] = '_';
- }
- do {
- if (STRNCASECMP(mc->name, s, n) == 0 && !mc->name[n]) {
- n = vend - vbeg;
- if (mc->length) {
- n = (*mc->length)(p, vbeg, n);
- }
- str_copy(val, vbeg, n);
- p->lex.ptok = tok_beg;
- p->lex.pcur = tok_end;
- (*mc->func)(p, mc->name, RSTRING_PTR(val));
- break;
- }
- } while (++mc < magic_comments + numberof(magic_comments));
+ const struct magic_comment *mc = magic_comments;
+ char *s;
+ int i;
+ long n = 0;
+
+ for (; len > 0 && *str; str++, --len) {
+ switch (*str) {
+ case '\'': case '"': case ':': case ';':
+ continue;
+ }
+ if (!ISSPACE(*str)) break;
+ }
+ for (beg = str; len > 0; str++, --len) {
+ switch (*str) {
+ case '\'': case '"': case ':': case ';':
+ break;
+ default:
+ if (ISSPACE(*str)) break;
+ continue;
+ }
+ break;
+ }
+ for (end = str; len > 0 && ISSPACE(*str); str++, --len);
+ if (!len) break;
+ if (*str != ':') {
+ if (!indicator) return FALSE;
+ continue;
+ }
+
+ do str++; while (--len > 0 && ISSPACE(*str));
+ if (!len) break;
+ if (*str == '"') {
+ for (vbeg = ++str; --len > 0 && *str != '"'; str++) {
+ if (*str == '\\') {
+ --len;
+ ++str;
+ }
+ }
+ vend = str;
+ if (len) {
+ --len;
+ ++str;
+ }
+ }
+ else {
+ for (vbeg = str; len > 0 && *str != '"' && *str != ';' && !ISSPACE(*str); --len, str++);
+ vend = str;
+ }
+ if (indicator) {
+ while (len > 0 && (*str == ';' || ISSPACE(*str))) --len, str++;
+ }
+ else {
+ while (len > 0 && (ISSPACE(*str))) --len, str++;
+ if (len) return FALSE;
+ }
+
+ n = end - beg;
+ str_copy(name, beg, n);
+ s = RSTRING_PTR(name);
+ for (i = 0; i < n; ++i) {
+ if (s[i] == '-') s[i] = '_';
+ }
+ do {
+ if (STRNCASECMP(mc->name, s, n) == 0 && !mc->name[n]) {
+ n = vend - vbeg;
+ if (mc->length) {
+ n = (*mc->length)(p, vbeg, n);
+ }
+ str_copy(val, vbeg, n);
+ (*mc->func)(p, mc->name, RSTRING_PTR(val));
+ break;
+ }
+ } while (++mc < magic_comments + numberof(magic_comments));
#ifdef RIPPER
- str_copy(val, vbeg, vend - vbeg);
- dispatch2(magic_comment, name, val);
+ str_copy(val, vbeg, vend - vbeg);
+ dispatch2(magic_comment, name, val);
#endif
}
@@ -9713,40 +8954,38 @@ set_file_encoding(struct parser_params *p, const char *str, const char *send)
VALUE s;
for (;;) {
- if (send - str <= 6) return;
- switch (str[6]) {
- case 'C': case 'c': str += 6; continue;
- case 'O': case 'o': str += 5; continue;
- case 'D': case 'd': str += 4; continue;
- case 'I': case 'i': str += 3; continue;
- case 'N': case 'n': str += 2; continue;
- case 'G': case 'g': str += 1; continue;
- case '=': case ':':
- sep = 1;
- str += 6;
- break;
- default:
- str += 6;
- if (ISSPACE(*str)) break;
- continue;
- }
- if (STRNCASECMP(str-6, "coding", 6) == 0) break;
- sep = 0;
+ if (send - str <= 6) return;
+ switch (str[6]) {
+ case 'C': case 'c': str += 6; continue;
+ case 'O': case 'o': str += 5; continue;
+ case 'D': case 'd': str += 4; continue;
+ case 'I': case 'i': str += 3; continue;
+ case 'N': case 'n': str += 2; continue;
+ case 'G': case 'g': str += 1; continue;
+ case '=': case ':':
+ sep = 1;
+ str += 6;
+ break;
+ default:
+ str += 6;
+ if (ISSPACE(*str)) break;
+ continue;
+ }
+ if (STRNCASECMP(str-6, "coding", 6) == 0) break;
+ sep = 0;
}
for (;;) {
- do {
- if (++str >= send) return;
- } while (ISSPACE(*str));
- if (sep) break;
- if (*str != '=' && *str != ':') return;
- sep = 1;
- str++;
+ do {
+ if (++str >= send) return;
+ } while (ISSPACE(*str));
+ if (sep) break;
+ if (*str != '=' && *str != ':') return;
+ sep = 1;
+ str++;
}
beg = str;
while ((*str == '-' || *str == '_' || ISALNUM(*str)) && ++str < send);
s = rb_str_new(beg, parser_encode_length(p, beg, str - beg));
- p->lex.ptok = beg;
- p->lex.pcur = str;
parser_set_encode(p, RSTRING_PTR(s));
rb_str_resize(s, 0);
}
@@ -9758,34 +8997,33 @@ parser_prepare(struct parser_params *p)
p->token_info_enabled = !compile_for_eval && RTEST(ruby_verbose);
switch (c) {
case '#':
- if (peek(p, '!')) p->has_shebang = 1;
- break;
+ if (peek(p, '!')) p->has_shebang = 1;
+ break;
case 0xef: /* UTF-8 BOM marker */
- if (!lex_eol_n_p(p, 2) &&
- (unsigned char)p->lex.pcur[0] == 0xbb &&
- (unsigned char)p->lex.pcur[1] == 0xbf) {
- p->enc = rb_utf8_encoding();
- p->lex.pcur += 2;
+ if (p->lex.pend - p->lex.pcur >= 2 &&
+ (unsigned char)p->lex.pcur[0] == 0xbb &&
+ (unsigned char)p->lex.pcur[1] == 0xbf) {
+ p->enc = rb_utf8_encoding();
+ p->lex.pcur += 2;
#ifndef RIPPER
- if (p->debug_lines) {
- rb_parser_string_set_encoding(p->lex.lastline, p->enc);
- }
+ if (p->debug_lines) {
+ rb_enc_associate(p->lex.lastline, p->enc);
+ }
#endif
- p->lex.pbeg = p->lex.pcur;
- token_flush(p);
- return;
- }
- break;
- case -1: /* end of script. */
- return;
+ p->lex.pbeg = p->lex.pcur;
+ return;
+ }
+ break;
+ case EOF:
+ return;
}
pushback(p, c);
- p->enc = rb_parser_str_get_encoding(p->lex.lastline);
+ p->enc = rb_enc_get(p->lex.lastline);
}
#ifndef RIPPER
#define ambiguous_operator(tok, op, syn) ( \
- rb_warning0("'"op"' after local variable or literal is interpreted as binary operator"), \
+ rb_warning0("`"op"' after local variable or literal is interpreted as binary operator"), \
rb_warning0("even though it seems like "syn""))
#else
#define ambiguous_operator(tok, op, syn) \
@@ -9797,13 +9035,24 @@ parser_prepare(struct parser_params *p)
(ambiguous_operator(tok, op, syn), 0)), \
(enum yytokentype)(tok))
+static VALUE
+parse_rational(struct parser_params *p, char *str, int len, int seen_point)
+{
+ VALUE v;
+ char *point = &str[seen_point];
+ size_t fraclen = len-seen_point-1;
+ memmove(point, point+1, fraclen+1);
+ v = rb_cstr_to_inum(str, 10, FALSE);
+ return rb_rational_new(v, rb_int_positive_pow(10, fraclen));
+}
+
static enum yytokentype
no_digits(struct parser_params *p)
{
yyerror0("numeric literal without digits");
if (peek(p, '_')) nextc(p);
/* dummy 0, for tUMINUS_NUM at numeric */
- return set_number_literal(p, tINTEGER, 0, 10, 0);
+ return set_integer_literal(p, INT2FIX(0), 0);
}
static enum yytokentype
@@ -9816,229 +9065,229 @@ parse_numeric(struct parser_params *p, int c)
SET_LEX_STATE(EXPR_END);
newtok(p);
if (c == '-' || c == '+') {
- tokadd(p, c);
- c = nextc(p);
+ tokadd(p, c);
+ c = nextc(p);
}
if (c == '0') {
- int start = toklen(p);
- c = nextc(p);
- if (c == 'x' || c == 'X') {
- /* hexadecimal */
- c = nextc(p);
- if (c != -1 && ISXDIGIT(c)) {
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (!ISXDIGIT(c)) break;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) != -1);
- }
- pushback(p, c);
- tokfix(p);
- if (toklen(p) == start) {
- return no_digits(p);
- }
- else if (nondigit) goto trailing_uc;
- suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
- return set_number_literal(p, tINTEGER, suffix, 16, 0);
- }
- if (c == 'b' || c == 'B') {
- /* binary */
- c = nextc(p);
- if (c == '0' || c == '1') {
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (c != '0' && c != '1') break;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) != -1);
- }
- pushback(p, c);
- tokfix(p);
- if (toklen(p) == start) {
- return no_digits(p);
- }
- else if (nondigit) goto trailing_uc;
- suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
- return set_number_literal(p, tINTEGER, suffix, 2, 0);
- }
- if (c == 'd' || c == 'D') {
- /* decimal */
- c = nextc(p);
- if (c != -1 && ISDIGIT(c)) {
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (!ISDIGIT(c)) break;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) != -1);
- }
- pushback(p, c);
- tokfix(p);
- if (toklen(p) == start) {
- return no_digits(p);
- }
- else if (nondigit) goto trailing_uc;
- suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
- return set_number_literal(p, tINTEGER, suffix, 10, 0);
- }
- if (c == '_') {
- /* 0_0 */
- goto octal_number;
- }
- if (c == 'o' || c == 'O') {
- /* prefixed octal */
- c = nextc(p);
- if (c == -1 || c == '_' || !ISDIGIT(c)) {
- tokfix(p);
- return no_digits(p);
- }
- }
- if (c >= '0' && c <= '7') {
- /* octal */
- octal_number:
- do {
- if (c == '_') {
- if (nondigit) break;
- nondigit = c;
- continue;
- }
- if (c < '0' || c > '9') break;
- if (c > '7') goto invalid_octal;
- nondigit = 0;
- tokadd(p, c);
- } while ((c = nextc(p)) != -1);
- if (toklen(p) > start) {
- pushback(p, c);
- tokfix(p);
- if (nondigit) goto trailing_uc;
- suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
- return set_number_literal(p, tINTEGER, suffix, 8, 0);
- }
- if (nondigit) {
- pushback(p, c);
- goto trailing_uc;
- }
- }
- if (c > '7' && c <= '9') {
- invalid_octal:
- yyerror0("Invalid octal digit");
- }
- else if (c == '.' || c == 'e' || c == 'E') {
- tokadd(p, '0');
- }
- else {
- pushback(p, c);
- tokfix(p);
- suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
- return set_number_literal(p, tINTEGER, suffix, 10, 0);
- }
+ int start = toklen(p);
+ c = nextc(p);
+ if (c == 'x' || c == 'X') {
+ /* hexadecimal */
+ c = nextc(p);
+ if (c != -1 && ISXDIGIT(c)) {
+ do {
+ if (c == '_') {
+ if (nondigit) break;
+ nondigit = c;
+ continue;
+ }
+ if (!ISXDIGIT(c)) break;
+ nondigit = 0;
+ tokadd(p, c);
+ } while ((c = nextc(p)) != -1);
+ }
+ pushback(p, c);
+ tokfix(p);
+ if (toklen(p) == start) {
+ return no_digits(p);
+ }
+ else if (nondigit) goto trailing_uc;
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ return set_integer_literal(p, rb_cstr_to_inum(tok(p), 16, FALSE), suffix);
+ }
+ if (c == 'b' || c == 'B') {
+ /* binary */
+ c = nextc(p);
+ if (c == '0' || c == '1') {
+ do {
+ if (c == '_') {
+ if (nondigit) break;
+ nondigit = c;
+ continue;
+ }
+ if (c != '0' && c != '1') break;
+ nondigit = 0;
+ tokadd(p, c);
+ } while ((c = nextc(p)) != -1);
+ }
+ pushback(p, c);
+ tokfix(p);
+ if (toklen(p) == start) {
+ return no_digits(p);
+ }
+ else if (nondigit) goto trailing_uc;
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ return set_integer_literal(p, rb_cstr_to_inum(tok(p), 2, FALSE), suffix);
+ }
+ if (c == 'd' || c == 'D') {
+ /* decimal */
+ c = nextc(p);
+ if (c != -1 && ISDIGIT(c)) {
+ do {
+ if (c == '_') {
+ if (nondigit) break;
+ nondigit = c;
+ continue;
+ }
+ if (!ISDIGIT(c)) break;
+ nondigit = 0;
+ tokadd(p, c);
+ } while ((c = nextc(p)) != -1);
+ }
+ pushback(p, c);
+ tokfix(p);
+ if (toklen(p) == start) {
+ return no_digits(p);
+ }
+ else if (nondigit) goto trailing_uc;
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ return set_integer_literal(p, rb_cstr_to_inum(tok(p), 10, FALSE), suffix);
+ }
+ if (c == '_') {
+ /* 0_0 */
+ goto octal_number;
+ }
+ if (c == 'o' || c == 'O') {
+ /* prefixed octal */
+ c = nextc(p);
+ if (c == -1 || c == '_' || !ISDIGIT(c)) {
+ return no_digits(p);
+ }
+ }
+ if (c >= '0' && c <= '7') {
+ /* octal */
+ octal_number:
+ do {
+ if (c == '_') {
+ if (nondigit) break;
+ nondigit = c;
+ continue;
+ }
+ if (c < '0' || c > '9') break;
+ if (c > '7') goto invalid_octal;
+ nondigit = 0;
+ tokadd(p, c);
+ } while ((c = nextc(p)) != -1);
+ if (toklen(p) > start) {
+ pushback(p, c);
+ tokfix(p);
+ if (nondigit) goto trailing_uc;
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ return set_integer_literal(p, rb_cstr_to_inum(tok(p), 8, FALSE), suffix);
+ }
+ if (nondigit) {
+ pushback(p, c);
+ goto trailing_uc;
+ }
+ }
+ if (c > '7' && c <= '9') {
+ invalid_octal:
+ yyerror0("Invalid octal digit");
+ }
+ else if (c == '.' || c == 'e' || c == 'E') {
+ tokadd(p, '0');
+ }
+ else {
+ pushback(p, c);
+ suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
+ return set_integer_literal(p, INT2FIX(0), suffix);
+ }
}
for (;;) {
- switch (c) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- nondigit = 0;
- tokadd(p, c);
- break;
-
- case '.':
- if (nondigit) goto trailing_uc;
- if (seen_point || seen_e) {
- goto decode_num;
- }
- else {
- int c0 = nextc(p);
- if (c0 == -1 || !ISDIGIT(c0)) {
- pushback(p, c0);
- goto decode_num;
- }
- c = c0;
- }
- seen_point = toklen(p);
- tokadd(p, '.');
- tokadd(p, c);
- is_float++;
- nondigit = 0;
- break;
-
- case 'e':
- case 'E':
- if (nondigit) {
- pushback(p, c);
- c = nondigit;
- goto decode_num;
- }
- if (seen_e) {
- goto decode_num;
- }
- nondigit = c;
- c = nextc(p);
- if (c != '-' && c != '+' && !ISDIGIT(c)) {
- pushback(p, c);
- c = nondigit;
- nondigit = 0;
- goto decode_num;
- }
- tokadd(p, nondigit);
- seen_e++;
- is_float++;
- tokadd(p, c);
- nondigit = (c == '-' || c == '+') ? c : 0;
- break;
-
- case '_': /* `_' in number just ignored */
- if (nondigit) goto decode_num;
- nondigit = c;
- break;
-
- default:
- goto decode_num;
- }
- c = nextc(p);
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ nondigit = 0;
+ tokadd(p, c);
+ break;
+
+ case '.':
+ if (nondigit) goto trailing_uc;
+ if (seen_point || seen_e) {
+ goto decode_num;
+ }
+ else {
+ int c0 = nextc(p);
+ if (c0 == -1 || !ISDIGIT(c0)) {
+ pushback(p, c0);
+ goto decode_num;
+ }
+ c = c0;
+ }
+ seen_point = toklen(p);
+ tokadd(p, '.');
+ tokadd(p, c);
+ is_float++;
+ nondigit = 0;
+ break;
+
+ case 'e':
+ case 'E':
+ if (nondigit) {
+ pushback(p, c);
+ c = nondigit;
+ goto decode_num;
+ }
+ if (seen_e) {
+ goto decode_num;
+ }
+ nondigit = c;
+ c = nextc(p);
+ if (c != '-' && c != '+' && !ISDIGIT(c)) {
+ pushback(p, c);
+ nondigit = 0;
+ goto decode_num;
+ }
+ tokadd(p, nondigit);
+ seen_e++;
+ is_float++;
+ tokadd(p, c);
+ nondigit = (c == '-' || c == '+') ? c : 0;
+ break;
+
+ case '_': /* `_' in number just ignored */
+ if (nondigit) goto decode_num;
+ nondigit = c;
+ break;
+
+ default:
+ goto decode_num;
+ }
+ c = nextc(p);
}
decode_num:
pushback(p, c);
if (nondigit) {
trailing_uc:
- literal_flush(p, p->lex.pcur - 1);
- YYLTYPE loc = RUBY_INIT_YYLLOC();
- compile_error(p, "trailing '%c' in number", nondigit);
- parser_show_error_line(p, &loc);
+ literal_flush(p, p->lex.pcur - 1);
+ YYLTYPE loc = RUBY_INIT_YYLLOC();
+ compile_error(p, "trailing `%c' in number", nondigit);
+ parser_show_error_line(p, &loc);
}
tokfix(p);
if (is_float) {
- enum yytokentype type = tFLOAT;
-
- suffix = number_literal_suffix(p, seen_e ? NUM_SUFFIX_I : NUM_SUFFIX_ALL);
- if (suffix & NUM_SUFFIX_R) {
- type = tRATIONAL;
- }
- else {
- strtod(tok(p), 0);
- if (errno == ERANGE) {
- rb_warning1("Float %s out of range", WARN_S(tok(p)));
- errno = 0;
- }
- }
- return set_number_literal(p, type, suffix, 0, seen_point);
+ enum yytokentype type = tFLOAT;
+ VALUE v;
+
+ suffix = number_literal_suffix(p, seen_e ? NUM_SUFFIX_I : NUM_SUFFIX_ALL);
+ if (suffix & NUM_SUFFIX_R) {
+ type = tRATIONAL;
+ v = parse_rational(p, tok(p), toklen(p), seen_point);
+ }
+ else {
+ double d = strtod(tok(p), 0);
+ if (errno == ERANGE) {
+ rb_warning1("Float %s out of range", WARN_S(tok(p)));
+ errno = 0;
+ }
+ v = DBL2NUM(d);
+ }
+ return set_number_literal(p, v, type, suffix);
}
suffix = number_literal_suffix(p, NUM_SUFFIX_ALL);
- return set_number_literal(p, tINTEGER, suffix, 10, 0);
+ return set_integer_literal(p, rb_cstr_to_inum(tok(p), 10, FALSE), suffix);
}
static enum yytokentype
@@ -10046,66 +9295,66 @@ parse_qmark(struct parser_params *p, int space_seen)
{
rb_encoding *enc;
register int c;
- rb_parser_string_t *lit;
+ VALUE lit;
if (IS_END()) {
- SET_LEX_STATE(EXPR_VALUE);
- return '?';
+ SET_LEX_STATE(EXPR_VALUE);
+ return '?';
}
c = nextc(p);
if (c == -1) {
- compile_error(p, "incomplete character syntax");
- return 0;
+ compile_error(p, "incomplete character syntax");
+ return 0;
}
if (rb_enc_isspace(c, p->enc)) {
- if (!IS_ARG()) {
- int c2 = escaped_control_code(c);
- if (c2) {
- WARN_SPACE_CHAR(c2, "?");
- }
- }
+ if (!IS_ARG()) {
+ int c2 = escaped_control_code(c);
+ if (c2) {
+ WARN_SPACE_CHAR(c2, "?");
+ }
+ }
ternary:
- pushback(p, c);
- SET_LEX_STATE(EXPR_VALUE);
- return '?';
+ pushback(p, c);
+ SET_LEX_STATE(EXPR_VALUE);
+ return '?';
}
newtok(p);
enc = p->enc;
if (!parser_isascii(p)) {
- if (tokadd_mbchar(p, c) == -1) return 0;
+ if (tokadd_mbchar(p, c) == -1) return 0;
}
else if ((rb_enc_isalnum(c, p->enc) || c == '_') &&
- !lex_eol_p(p) && is_identchar(p, p->lex.pcur, p->lex.pend, p->enc)) {
- if (space_seen) {
- const char *start = p->lex.pcur - 1, *ptr = start;
- do {
- int n = parser_precise_mbclen(p, ptr);
- if (n < 0) return -1;
- ptr += n;
- } while (!lex_eol_ptr_p(p, ptr) && is_identchar(p, ptr, p->lex.pend, p->enc));
- rb_warn2("'?' just followed by '%.*s' is interpreted as" \
- " a conditional operator, put a space after '?'",
- WARN_I((int)(ptr - start)), WARN_S_L(start, (ptr - start)));
- }
- goto ternary;
+ p->lex.pcur < p->lex.pend && is_identchar(p->lex.pcur, p->lex.pend, p->enc)) {
+ if (space_seen) {
+ const char *start = p->lex.pcur - 1, *ptr = start;
+ do {
+ int n = parser_precise_mbclen(p, ptr);
+ if (n < 0) return -1;
+ ptr += n;
+ } while (ptr < p->lex.pend && is_identchar(ptr, p->lex.pend, p->enc));
+ rb_warn2("`?' just followed by `%.*s' is interpreted as" \
+ " a conditional operator, put a space after `?'",
+ WARN_I((int)(ptr - start)), WARN_S_L(start, (ptr - start)));
+ }
+ goto ternary;
}
else if (c == '\\') {
- if (peek(p, 'u')) {
- nextc(p);
- enc = rb_utf8_encoding();
- tokadd_utf8(p, &enc, -1, 0, 0);
- }
- else if (!ISASCII(c = peekc(p)) && c != -1) {
- nextc(p);
- if (tokadd_mbchar(p, c) == -1) return 0;
- }
- else {
- c = read_escape(p, 0, p->lex.pcur - rb_strlen_lit("?\\"));
- tokadd(p, c);
- }
+ if (peek(p, 'u')) {
+ nextc(p);
+ enc = rb_utf8_encoding();
+ tokadd_utf8(p, &enc, -1, 0, 0);
+ }
+ else if (!ISASCII(c = peekc(p))) {
+ nextc(p);
+ if (tokadd_mbchar(p, c) == -1) return 0;
+ }
+ else {
+ c = read_escape(p, 0, &enc);
+ tokadd(p, c);
+ }
}
else {
- tokadd(p, c);
+ tokadd(p, c);
}
tokfix(p);
lit = STR_NEW3(tok(p), toklen(p), enc, 0);
@@ -10121,92 +9370,92 @@ parse_percent(struct parser_params *p, const int space_seen, const enum lex_stat
const char *ptok = p->lex.pcur;
if (IS_BEG()) {
- int term;
- int paren;
+ int term;
+ int paren;
- c = nextc(p);
+ c = nextc(p);
quotation:
- if (c == -1) goto unterminated;
- if (!ISALNUM(c)) {
- term = c;
- if (!ISASCII(c)) goto unknown;
- c = 'Q';
- }
- else {
- term = nextc(p);
- if (rb_enc_isalnum(term, p->enc) || !parser_isascii(p)) {
- unknown:
- pushback(p, term);
- c = parser_precise_mbclen(p, p->lex.pcur);
- if (c < 0) return 0;
- p->lex.pcur += c;
- yyerror0("unknown type of %string");
- return 0;
- }
- }
- if (term == -1) {
- unterminated:
- compile_error(p, "unterminated quoted string meets end of file");
- return 0;
- }
- paren = term;
- if (term == '(') term = ')';
- else if (term == '[') term = ']';
- else if (term == '{') term = '}';
- else if (term == '<') term = '>';
- else paren = 0;
-
- p->lex.ptok = ptok-1;
- switch (c) {
- case 'Q':
- p->lex.strterm = NEW_STRTERM(str_dquote, term, paren);
- return tSTRING_BEG;
-
- case 'q':
- p->lex.strterm = NEW_STRTERM(str_squote, term, paren);
- return tSTRING_BEG;
-
- case 'W':
- p->lex.strterm = NEW_STRTERM(str_dword, term, paren);
- return tWORDS_BEG;
-
- case 'w':
- p->lex.strterm = NEW_STRTERM(str_sword, term, paren);
- return tQWORDS_BEG;
-
- case 'I':
- p->lex.strterm = NEW_STRTERM(str_dword, term, paren);
- return tSYMBOLS_BEG;
-
- case 'i':
- p->lex.strterm = NEW_STRTERM(str_sword, term, paren);
- return tQSYMBOLS_BEG;
-
- case 'x':
- p->lex.strterm = NEW_STRTERM(str_xquote, term, paren);
- return tXSTRING_BEG;
-
- case 'r':
- p->lex.strterm = NEW_STRTERM(str_regexp, term, paren);
- return tREGEXP_BEG;
-
- case 's':
- p->lex.strterm = NEW_STRTERM(str_ssym, term, paren);
- SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);
- return tSYMBEG;
-
- default:
- yyerror0("unknown type of %string");
- return 0;
- }
+ if (c == -1) goto unterminated;
+ if (!ISALNUM(c)) {
+ term = c;
+ if (!ISASCII(c)) goto unknown;
+ c = 'Q';
+ }
+ else {
+ term = nextc(p);
+ if (rb_enc_isalnum(term, p->enc) || !parser_isascii(p)) {
+ unknown:
+ pushback(p, term);
+ c = parser_precise_mbclen(p, p->lex.pcur);
+ if (c < 0) return 0;
+ p->lex.pcur += c;
+ yyerror0("unknown type of %string");
+ return 0;
+ }
+ }
+ if (term == -1) {
+ unterminated:
+ compile_error(p, "unterminated quoted string meets end of file");
+ return 0;
+ }
+ paren = term;
+ if (term == '(') term = ')';
+ else if (term == '[') term = ']';
+ else if (term == '{') term = '}';
+ else if (term == '<') term = '>';
+ else paren = 0;
+
+ p->lex.ptok = ptok-1;
+ switch (c) {
+ case 'Q':
+ p->lex.strterm = NEW_STRTERM(str_dquote, term, paren);
+ return tSTRING_BEG;
+
+ case 'q':
+ p->lex.strterm = NEW_STRTERM(str_squote, term, paren);
+ return tSTRING_BEG;
+
+ case 'W':
+ p->lex.strterm = NEW_STRTERM(str_dword, term, paren);
+ return tWORDS_BEG;
+
+ case 'w':
+ p->lex.strterm = NEW_STRTERM(str_sword, term, paren);
+ return tQWORDS_BEG;
+
+ case 'I':
+ p->lex.strterm = NEW_STRTERM(str_dword, term, paren);
+ return tSYMBOLS_BEG;
+
+ case 'i':
+ p->lex.strterm = NEW_STRTERM(str_sword, term, paren);
+ return tQSYMBOLS_BEG;
+
+ case 'x':
+ p->lex.strterm = NEW_STRTERM(str_xquote, term, paren);
+ return tXSTRING_BEG;
+
+ case 'r':
+ p->lex.strterm = NEW_STRTERM(str_regexp, term, paren);
+ return tREGEXP_BEG;
+
+ case 's':
+ p->lex.strterm = NEW_STRTERM(str_ssym, term, paren);
+ SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);
+ return tSYMBEG;
+
+ default:
+ yyerror0("unknown type of %string");
+ return 0;
+ }
}
if ((c = nextc(p)) == '=') {
- set_yylval_id('%');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
+ set_yylval_id('%');
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
}
if (IS_SPCARG(c) || (IS_lex_state(EXPR_FITEM) && c == 's')) {
- goto quotation;
+ goto quotation;
}
SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
pushback(p, c);
@@ -10217,15 +9466,15 @@ static int
tokadd_ident(struct parser_params *p, int c)
{
do {
- if (tokadd_mbchar(p, c) == -1) return -1;
- c = nextc(p);
+ if (tokadd_mbchar(p, c) == -1) return -1;
+ c = nextc(p);
} while (parser_is_identchar(p));
pushback(p, c);
return 0;
}
static ID
-tokenize_ident(struct parser_params *p)
+tokenize_ident(struct parser_params *p, const enum lex_state_e last_state)
{
ID ident = TOK_INTERN();
@@ -10241,17 +9490,17 @@ parse_numvar(struct parser_params *p)
int overflow;
unsigned long n = ruby_scan_digits(tok(p)+1, toklen(p)-1, 10, &len, &overflow);
const unsigned long nth_ref_max =
- ((FIXNUM_MAX < INT_MAX) ? FIXNUM_MAX : INT_MAX) >> 1;
+ ((FIXNUM_MAX < INT_MAX) ? FIXNUM_MAX : INT_MAX) >> 1;
/* NTH_REF is left-shifted to be ORed with back-ref flag and
* turned into a Fixnum, in compile.c */
if (overflow || n > nth_ref_max) {
- /* compile_error()? */
- rb_warn1("'%s' is too big for a number variable, always nil", WARN_S(tok(p)));
- return 0; /* $0 is $PROGRAM_NAME, not NTH_REF */
+ /* compile_error()? */
+ rb_warn1("`%s' is too big for a number variable, always nil", WARN_S(tok(p)));
+ return 0; /* $0 is $PROGRAM_NAME, not NTH_REF */
}
else {
- return (int)n;
+ return (int)n;
}
}
@@ -10267,130 +9516,126 @@ parse_gvar(struct parser_params *p, const enum lex_state_e last_state)
c = nextc(p);
switch (c) {
case '_': /* $_: last read line string */
- c = nextc(p);
- if (parser_is_identchar(p)) {
- tokadd(p, '$');
- tokadd(p, '_');
- break;
- }
- pushback(p, c);
- c = '_';
- /* fall through */
- case '~': /* $~: match-data */
- case '*': /* $*: argv */
- case '$': /* $$: pid */
- case '?': /* $?: last status */
- case '!': /* $!: error string */
- case '@': /* $@: error position */
- case '/': /* $/: input record separator */
- case '\\': /* $\: output record separator */
- case ';': /* $;: field separator */
- case ',': /* $,: output field separator */
- case '.': /* $.: last read line number */
- case '=': /* $=: ignorecase */
- case ':': /* $:: load path */
- case '<': /* $<: default input handle */
- case '>': /* $>: default output handle */
- case '\"': /* $": already loaded files */
- tokadd(p, '$');
- tokadd(p, c);
- goto gvar;
+ c = nextc(p);
+ if (parser_is_identchar(p)) {
+ tokadd(p, '$');
+ tokadd(p, '_');
+ break;
+ }
+ pushback(p, c);
+ c = '_';
+ /* fall through */
+ case '~': /* $~: match-data */
+ case '*': /* $*: argv */
+ case '$': /* $$: pid */
+ case '?': /* $?: last status */
+ case '!': /* $!: error string */
+ case '@': /* $@: error position */
+ case '/': /* $/: input record separator */
+ case '\\': /* $\: output record separator */
+ case ';': /* $;: field separator */
+ case ',': /* $,: output field separator */
+ case '.': /* $.: last read line number */
+ case '=': /* $=: ignorecase */
+ case ':': /* $:: load path */
+ case '<': /* $<: reading filename */
+ case '>': /* $>: default output handle */
+ case '\"': /* $": already loaded files */
+ tokadd(p, '$');
+ tokadd(p, c);
+ goto gvar;
case '-':
- tokadd(p, '$');
- tokadd(p, c);
- c = nextc(p);
- if (parser_is_identchar(p)) {
- if (tokadd_mbchar(p, c) == -1) return 0;
- }
- else {
- pushback(p, c);
- pushback(p, '-');
- return '$';
- }
+ tokadd(p, '$');
+ tokadd(p, c);
+ c = nextc(p);
+ if (parser_is_identchar(p)) {
+ if (tokadd_mbchar(p, c) == -1) return 0;
+ }
+ else {
+ pushback(p, c);
+ pushback(p, '-');
+ return '$';
+ }
gvar:
- tokenize_ident(p);
- return tGVAR;
-
- case '&': /* $&: last match */
- case '`': /* $`: string before last match */
- case '\'': /* $': string after last match */
- case '+': /* $+: string matches last paren. */
- if (IS_lex_state_for(last_state, EXPR_FNAME)) {
- tokadd(p, '$');
- tokadd(p, c);
- goto gvar;
- }
- set_yylval_node(NEW_BACK_REF(c, &_cur_loc));
- return tBACK_REF;
+ set_yylval_name(TOK_INTERN());
+ return tGVAR;
+
+ case '&': /* $&: last match */
+ case '`': /* $`: string before last match */
+ case '\'': /* $': string after last match */
+ case '+': /* $+: string matches last paren. */
+ if (IS_lex_state_for(last_state, EXPR_FNAME)) {
+ tokadd(p, '$');
+ tokadd(p, c);
+ goto gvar;
+ }
+ set_yylval_node(NEW_BACK_REF(c, &_cur_loc));
+ return tBACK_REF;
case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
- tokadd(p, '$');
- do {
- tokadd(p, c);
- c = nextc(p);
- } while (c != -1 && ISDIGIT(c));
- pushback(p, c);
- if (IS_lex_state_for(last_state, EXPR_FNAME)) goto gvar;
- tokfix(p);
- c = parse_numvar(p);
- set_yylval_node(NEW_NTH_REF(c, &_cur_loc));
- return tNTH_REF;
+ tokadd(p, '$');
+ do {
+ tokadd(p, c);
+ c = nextc(p);
+ } while (c != -1 && ISDIGIT(c));
+ pushback(p, c);
+ if (IS_lex_state_for(last_state, EXPR_FNAME)) goto gvar;
+ tokfix(p);
+ c = parse_numvar(p);
+ set_yylval_node(NEW_NTH_REF(c, &_cur_loc));
+ return tNTH_REF;
default:
- if (!parser_is_identchar(p)) {
- YYLTYPE loc = RUBY_INIT_YYLLOC();
- if (c == -1 || ISSPACE(c)) {
- compile_error(p, "'$' without identifiers is not allowed as a global variable name");
- }
- else {
- pushback(p, c);
- compile_error(p, "'$%c' is not allowed as a global variable name", c);
- }
- parser_show_error_line(p, &loc);
- set_yylval_noname();
- return tGVAR;
- }
- /* fall through */
+ if (!parser_is_identchar(p)) {
+ YYLTYPE loc = RUBY_INIT_YYLLOC();
+ if (c == -1 || ISSPACE(c)) {
+ compile_error(p, "`$' without identifiers is not allowed as a global variable name");
+ }
+ else {
+ pushback(p, c);
+ compile_error(p, "`$%c' is not allowed as a global variable name", c);
+ }
+ parser_show_error_line(p, &loc);
+ set_yylval_noname();
+ return tGVAR;
+ }
+ /* fall through */
case '0':
- tokadd(p, '$');
+ tokadd(p, '$');
}
if (tokadd_ident(p, c)) return 0;
SET_LEX_STATE(EXPR_END);
- if (VALID_SYMNAME_P(tok(p), toklen(p), p->enc, ID_GLOBAL)) {
- tokenize_ident(p);
- }
- else {
- compile_error(p, "'%.*s' is not allowed as a global variable name", toklen(p), tok(p));
- set_yylval_noname();
- }
+ tokenize_ident(p, last_state);
return tGVAR;
}
+#ifndef RIPPER
static bool
parser_numbered_param(struct parser_params *p, int n)
{
if (n < 0) return false;
if (DVARS_TERMINAL_P(p->lvtbl->args) || DVARS_TERMINAL_P(p->lvtbl->args->prev)) {
- return false;
+ return false;
}
if (p->max_numparam == ORDINAL_PARAM) {
- compile_error(p, "ordinary parameter is defined");
- return false;
+ compile_error(p, "ordinary parameter is defined");
+ return false;
}
struct vtable *args = p->lvtbl->args;
if (p->max_numparam < n) {
- p->max_numparam = n;
+ p->max_numparam = n;
}
while (n > args->pos) {
- vtable_add(args, NUMPARAM_IDX_TO_ID(args->pos+1));
+ vtable_add(args, NUMPARAM_IDX_TO_ID(args->pos+1));
}
return true;
}
+#endif
static enum yytokentype
parse_atmark(struct parser_params *p, const enum lex_state_e last_state)
@@ -10404,42 +9649,42 @@ parse_atmark(struct parser_params *p, const enum lex_state_e last_state)
newtok(p);
tokadd(p, '@');
if (c == '@') {
- result = tCVAR;
- tokadd(p, '@');
- c = nextc(p);
+ result = tCVAR;
+ tokadd(p, '@');
+ c = nextc(p);
}
SET_LEX_STATE(IS_lex_state_for(last_state, EXPR_FNAME) ? EXPR_ENDFN : EXPR_END);
if (c == -1 || !parser_is_identchar(p)) {
- pushback(p, c);
- RUBY_SET_YYLLOC(loc);
- if (result == tIVAR) {
- compile_error(p, "'@' without identifiers is not allowed as an instance variable name");
- }
- else {
- compile_error(p, "'@@' without identifiers is not allowed as a class variable name");
- }
- parser_show_error_line(p, &loc);
- set_yylval_noname();
- SET_LEX_STATE(EXPR_END);
- return result;
+ pushback(p, c);
+ RUBY_SET_YYLLOC(loc);
+ if (result == tIVAR) {
+ compile_error(p, "`@' without identifiers is not allowed as an instance variable name");
+ }
+ else {
+ compile_error(p, "`@@' without identifiers is not allowed as a class variable name");
+ }
+ parser_show_error_line(p, &loc);
+ set_yylval_noname();
+ SET_LEX_STATE(EXPR_END);
+ return result;
}
else if (ISDIGIT(c)) {
- pushback(p, c);
- RUBY_SET_YYLLOC(loc);
- if (result == tIVAR) {
- compile_error(p, "'@%c' is not allowed as an instance variable name", c);
- }
- else {
- compile_error(p, "'@@%c' is not allowed as a class variable name", c);
- }
- parser_show_error_line(p, &loc);
- set_yylval_noname();
- SET_LEX_STATE(EXPR_END);
- return result;
+ pushback(p, c);
+ RUBY_SET_YYLLOC(loc);
+ if (result == tIVAR) {
+ compile_error(p, "`@%c' is not allowed as an instance variable name", c);
+ }
+ else {
+ compile_error(p, "`@@%c' is not allowed as a class variable name", c);
+ }
+ parser_show_error_line(p, &loc);
+ set_yylval_noname();
+ SET_LEX_STATE(EXPR_END);
+ return result;
}
if (tokadd_ident(p, c)) return 0;
- tokenize_ident(p);
+ tokenize_ident(p, last_state);
return result;
}
@@ -10447,118 +9692,118 @@ static enum yytokentype
parse_ident(struct parser_params *p, int c, int cmd_state)
{
enum yytokentype result;
- bool is_ascii = true;
+ int mb = ENC_CODERANGE_7BIT;
const enum lex_state_e last_state = p->lex.state;
ID ident;
int enforce_keyword_end = 0;
do {
- if (!ISASCII(c)) is_ascii = false;
- if (tokadd_mbchar(p, c) == -1) return 0;
- c = nextc(p);
+ if (!ISASCII(c)) mb = ENC_CODERANGE_UNKNOWN;
+ if (tokadd_mbchar(p, c) == -1) return 0;
+ c = nextc(p);
} while (parser_is_identchar(p));
if ((c == '!' || c == '?') && !peek(p, '=')) {
- result = tFID;
- tokadd(p, c);
+ result = tFID;
+ tokadd(p, c);
}
else if (c == '=' && IS_lex_state(EXPR_FNAME) &&
- (!peek(p, '~') && !peek(p, '>') && (!peek(p, '=') || (peek_n(p, '>', 1))))) {
- result = tIDENTIFIER;
- tokadd(p, c);
+ (!peek(p, '~') && !peek(p, '>') && (!peek(p, '=') || (peek_n(p, '>', 1))))) {
+ result = tIDENTIFIER;
+ tokadd(p, c);
}
else {
- result = tCONSTANT; /* assume provisionally */
- pushback(p, c);
+ result = tCONSTANT; /* assume provisionally */
+ pushback(p, c);
}
tokfix(p);
if (IS_LABEL_POSSIBLE()) {
- if (IS_LABEL_SUFFIX(0)) {
- SET_LEX_STATE(EXPR_ARG|EXPR_LABELED);
- nextc(p);
- tokenize_ident(p);
- return tLABEL;
- }
+ if (IS_LABEL_SUFFIX(0)) {
+ SET_LEX_STATE(EXPR_ARG|EXPR_LABELED);
+ nextc(p);
+ set_yylval_name(TOK_INTERN());
+ return tLABEL;
+ }
}
#ifndef RIPPER
- if (peek_end_expect_token_locations(p)) {
- const rb_code_position_t *end_pos;
- int lineno, column;
- int beg_pos = (int)(p->lex.ptok - p->lex.pbeg);
-
- end_pos = peek_end_expect_token_locations(p)->pos;
- lineno = end_pos->lineno;
- column = end_pos->column;
-
- if (p->debug) {
- rb_parser_printf(p, "enforce_keyword_end check. current: (%d, %d), peek: (%d, %d)\n",
- p->ruby_sourceline, beg_pos, lineno, column);
- }
+ if (!NIL_P(peek_end_expect_token_locations(p))) {
+ VALUE end_loc;
+ int lineno, column;
+ int beg_pos = (int)(p->lex.ptok - p->lex.pbeg);
- if ((p->ruby_sourceline > lineno) && (beg_pos <= column)) {
- const struct kwtable *kw;
+ end_loc = peek_end_expect_token_locations(p);
+ lineno = NUM2INT(rb_ary_entry(end_loc, 0));
+ column = NUM2INT(rb_ary_entry(end_loc, 1));
- if ((IS_lex_state(EXPR_DOT)) && (kw = rb_reserved_word(tok(p), toklen(p))) && (kw && kw->id[0] == keyword_end)) {
- if (p->debug) rb_parser_printf(p, "enforce_keyword_end is enabled\n");
- enforce_keyword_end = 1;
- }
- }
+ if (p->debug) {
+ rb_parser_printf(p, "enforce_keyword_end check. current: (%d, %d), peek: (%d, %d)\n",
+ p->ruby_sourceline, beg_pos, lineno, column);
+ }
+
+ if ((p->ruby_sourceline > lineno) && (beg_pos <= column)) {
+ const struct kwtable *kw;
+
+ if ((IS_lex_state(EXPR_DOT)) && (kw = rb_reserved_word(tok(p), toklen(p))) && (kw && kw->id[0] == keyword_end)) {
+ if (p->debug) rb_parser_printf(p, "enforce_keyword_end is enabled\n");
+ enforce_keyword_end = 1;
+ }
+ }
}
#endif
- if (is_ascii && (!IS_lex_state(EXPR_DOT) || enforce_keyword_end)) {
- const struct kwtable *kw;
-
- /* See if it is a reserved word. */
- kw = rb_reserved_word(tok(p), toklen(p));
- if (kw) {
- enum lex_state_e state = p->lex.state;
- if (IS_lex_state_for(state, EXPR_FNAME)) {
- SET_LEX_STATE(EXPR_ENDFN);
- set_yylval_name(rb_intern2(tok(p), toklen(p)));
- return kw->id[0];
- }
- SET_LEX_STATE(kw->state);
- if (IS_lex_state(EXPR_BEG)) {
- p->command_start = TRUE;
- }
- if (kw->id[0] == keyword_do) {
- if (lambda_beginning_p()) {
- p->lex.lpar_beg = -1; /* make lambda_beginning_p() == FALSE in the body of "-> do ... end" */
- return keyword_do_LAMBDA;
- }
- if (COND_P()) return keyword_do_cond;
- if (CMDARG_P() && !IS_lex_state_for(state, EXPR_CMDARG))
- return keyword_do_block;
- return keyword_do;
- }
- if (IS_lex_state_for(state, (EXPR_BEG | EXPR_LABELED | EXPR_CLASS)))
- return kw->id[0];
- else {
- if (kw->id[0] != kw->id[1])
- SET_LEX_STATE(EXPR_BEG | EXPR_LABEL);
- return kw->id[1];
- }
- }
+ if (mb == ENC_CODERANGE_7BIT && (!IS_lex_state(EXPR_DOT) || enforce_keyword_end)) {
+ const struct kwtable *kw;
+
+ /* See if it is a reserved word. */
+ kw = rb_reserved_word(tok(p), toklen(p));
+ if (kw) {
+ enum lex_state_e state = p->lex.state;
+ if (IS_lex_state_for(state, EXPR_FNAME)) {
+ SET_LEX_STATE(EXPR_ENDFN);
+ set_yylval_name(rb_intern2(tok(p), toklen(p)));
+ return kw->id[0];
+ }
+ SET_LEX_STATE(kw->state);
+ if (IS_lex_state(EXPR_BEG)) {
+ p->command_start = TRUE;
+ }
+ if (kw->id[0] == keyword_do) {
+ if (lambda_beginning_p()) {
+ p->lex.lpar_beg = -1; /* make lambda_beginning_p() == FALSE in the body of "-> do ... end" */
+ return keyword_do_LAMBDA;
+ }
+ if (COND_P()) return keyword_do_cond;
+ if (CMDARG_P() && !IS_lex_state_for(state, EXPR_CMDARG))
+ return keyword_do_block;
+ return keyword_do;
+ }
+ if (IS_lex_state_for(state, (EXPR_BEG | EXPR_LABELED | EXPR_CLASS)))
+ return kw->id[0];
+ else {
+ if (kw->id[0] != kw->id[1])
+ SET_LEX_STATE(EXPR_BEG | EXPR_LABEL);
+ return kw->id[1];
+ }
+ }
}
if (IS_lex_state(EXPR_BEG_ANY | EXPR_ARG_ANY | EXPR_DOT)) {
- if (cmd_state) {
- SET_LEX_STATE(EXPR_CMDARG);
- }
- else {
- SET_LEX_STATE(EXPR_ARG);
- }
+ if (cmd_state) {
+ SET_LEX_STATE(EXPR_CMDARG);
+ }
+ else {
+ SET_LEX_STATE(EXPR_ARG);
+ }
}
else if (p->lex.state == EXPR_FNAME) {
- SET_LEX_STATE(EXPR_ENDFN);
+ SET_LEX_STATE(EXPR_ENDFN);
}
else {
- SET_LEX_STATE(EXPR_END);
+ SET_LEX_STATE(EXPR_END);
}
- ident = tokenize_ident(p);
+ ident = tokenize_ident(p, last_state);
if (result == tCONSTANT && is_local_id(ident)) result = tIDENTIFIER;
if (!IS_lex_state_for(last_state, EXPR_DOT|EXPR_FNAME) &&
(result == tIDENTIFIER) && /* not EXPR_FNAME, not attrasgn */
@@ -10572,9 +9817,9 @@ static void
warn_cr(struct parser_params *p)
{
if (!p->cr_seen) {
- p->cr_seen = TRUE;
- /* carried over with p->lex.nextline for nextc() */
- rb_warn0("encountered \\r in middle of line, treated as a mere space");
+ p->cr_seen = TRUE;
+ /* carried over with p->lex.nextline for nextc() */
+ rb_warn0("encountered \\r in middle of line, treated as a mere space");
}
}
@@ -10590,14 +9835,14 @@ parser_yylex(struct parser_params *p)
int token_seen = p->token_seen;
if (p->lex.strterm) {
- if (strterm_is_heredoc(p->lex.strterm)) {
- token_flush(p);
- return here_document(p, &p->lex.strterm->u.heredoc);
- }
- else {
- token_flush(p);
- return parse_string(p, &p->lex.strterm->u.literal);
- }
+ if (p->lex.strterm->flags & STRTERM_HEREDOC) {
+ token_flush(p);
+ return here_document(p, &p->lex.strterm->u.heredoc);
+ }
+ else {
+ token_flush(p);
+ return parse_string(p, &p->lex.strterm->u.literal);
+ }
}
cmd_state = p->command_start;
p->command_start = FALSE;
@@ -10612,690 +9857,686 @@ parser_yylex(struct parser_params *p)
case '\004': /* ^D */
case '\032': /* ^Z */
case -1: /* end of script. */
- p->eofp = 1;
+ p->eofp = 1;
#ifndef RIPPER
- if (p->end_expect_token_locations) {
- pop_end_expect_token_locations(p);
- RUBY_SET_YYLLOC_OF_DUMMY_END(*p->yylloc);
- return tDUMNY_END;
- }
+ if (!NIL_P(p->end_expect_token_locations) && RARRAY_LEN(p->end_expect_token_locations) > 0) {
+ pop_end_expect_token_locations(p);
+ RUBY_SET_YYLLOC_OF_DUMMY_END(*p->yylloc);
+ return tDUMNY_END;
+ }
#endif
- /* Set location for end-of-input because dispatch_scan_event is not called. */
- RUBY_SET_YYLLOC(*p->yylloc);
- return END_OF_INPUT;
+ /* Set location for end-of-input because dispatch_scan_event is not called. */
+ RUBY_SET_YYLLOC(*p->yylloc);
+ return 0;
- /* white spaces */
+ /* white spaces */
case '\r':
- warn_cr(p);
- /* fall through */
+ warn_cr(p);
+ /* fall through */
case ' ': case '\t': case '\f':
case '\13': /* '\v' */
- space_seen = 1;
- while ((c = nextc(p))) {
- switch (c) {
- case '\r':
- warn_cr(p);
- /* fall through */
- case ' ': case '\t': case '\f':
- case '\13': /* '\v' */
- break;
- default:
- goto outofloop;
- }
- }
+ space_seen = 1;
+ while ((c = nextc(p))) {
+ switch (c) {
+ case '\r':
+ warn_cr(p);
+ /* fall through */
+ case ' ': case '\t': case '\f':
+ case '\13': /* '\v' */
+ break;
+ default:
+ goto outofloop;
+ }
+ }
outofloop:
- pushback(p, c);
- dispatch_scan_event(p, tSP);
+ pushback(p, c);
+ dispatch_scan_event(p, tSP);
#ifndef RIPPER
- token_flush(p);
+ token_flush(p);
#endif
- goto retry;
+ goto retry;
case '#': /* it's a comment */
- p->token_seen = token_seen;
- const char *const pcur = p->lex.pcur, *const ptok = p->lex.ptok;
- /* no magic_comment in shebang line */
- if (!parser_magic_comment(p, p->lex.pcur, p->lex.pend - p->lex.pcur)) {
- if (comment_at_top(p)) {
- set_file_encoding(p, p->lex.pcur, p->lex.pend);
- }
- }
- p->lex.pcur = pcur, p->lex.ptok = ptok;
- lex_goto_eol(p);
+ p->token_seen = token_seen;
+ /* no magic_comment in shebang line */
+ if (!parser_magic_comment(p, p->lex.pcur, p->lex.pend - p->lex.pcur)) {
+ if (comment_at_top(p)) {
+ set_file_encoding(p, p->lex.pcur, p->lex.pend);
+ }
+ }
+ lex_goto_eol(p);
dispatch_scan_event(p, tCOMMENT);
fallthru = TRUE;
- /* fall through */
+ /* fall through */
case '\n':
- p->token_seen = token_seen;
- rb_parser_string_t *prevline = p->lex.lastline;
- c = (IS_lex_state(EXPR_BEG|EXPR_CLASS|EXPR_FNAME|EXPR_DOT) &&
- !IS_lex_state(EXPR_LABELED));
- if (c || IS_lex_state_all(EXPR_ARG|EXPR_LABELED)) {
+ p->token_seen = token_seen;
+ c = (IS_lex_state(EXPR_BEG|EXPR_CLASS|EXPR_FNAME|EXPR_DOT) &&
+ !IS_lex_state(EXPR_LABELED));
+ if (c || IS_lex_state_all(EXPR_ARG|EXPR_LABELED)) {
if (!fallthru) {
dispatch_scan_event(p, tIGNORED_NL);
}
fallthru = FALSE;
- if (!c && p->ctxt.in_kwarg) {
- goto normal_newline;
- }
- goto retry;
- }
- while (1) {
- switch (c = nextc(p)) {
- case ' ': case '\t': case '\f': case '\r':
- case '\13': /* '\v' */
- space_seen = 1;
- break;
- case '#':
- pushback(p, c);
- if (space_seen) {
- dispatch_scan_event(p, tSP);
- token_flush(p);
- }
- goto retry;
- case '&':
- case '.': {
- dispatch_delayed_token(p, tIGNORED_NL);
- if (peek(p, '.') == (c == '&')) {
- pushback(p, c);
- dispatch_scan_event(p, tSP);
- goto retry;
- }
- }
- default:
- p->ruby_sourceline--;
- p->lex.nextline = p->lex.lastline;
- set_lastline(p, prevline);
- case -1: /* EOF no decrement*/
- if (c == -1 && space_seen) {
- dispatch_scan_event(p, tSP);
- }
- lex_goto_eol(p);
- if (c != -1) {
- token_flush(p);
- RUBY_SET_YYLLOC(*p->yylloc);
- }
- goto normal_newline;
- }
- }
+ if (!c && p->ctxt.in_kwarg) {
+ goto normal_newline;
+ }
+ goto retry;
+ }
+ while (1) {
+ switch (c = nextc(p)) {
+ case ' ': case '\t': case '\f': case '\r':
+ case '\13': /* '\v' */
+ space_seen = 1;
+ break;
+ case '#':
+ pushback(p, c);
+ if (space_seen) {
+ dispatch_scan_event(p, tSP);
+ token_flush(p);
+ }
+ goto retry;
+ case '&':
+ case '.': {
+ dispatch_delayed_token(p, tIGNORED_NL);
+ if (peek(p, '.') == (c == '&')) {
+ pushback(p, c);
+ dispatch_scan_event(p, tSP);
+ goto retry;
+ }
+ }
+ default:
+ p->ruby_sourceline--;
+ p->lex.nextline = p->lex.lastline;
+ case -1: /* EOF no decrement*/
+ lex_goto_eol(p);
+ if (c != -1) {
+ p->lex.ptok = p->lex.pcur;
+ }
+ goto normal_newline;
+ }
+ }
normal_newline:
- p->command_start = TRUE;
- SET_LEX_STATE(EXPR_BEG);
- return '\n';
+ p->command_start = TRUE;
+ SET_LEX_STATE(EXPR_BEG);
+ return '\n';
case '*':
- if ((c = nextc(p)) == '*') {
- if ((c = nextc(p)) == '=') {
- set_yylval_id(idPow);
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- if (IS_SPCARG(c)) {
- rb_warning0("'**' interpreted as argument prefix");
- c = tDSTAR;
- }
- else if (IS_BEG()) {
- c = tDSTAR;
- }
- else {
- c = warn_balanced((enum ruby_method_ids)tPOW, "**", "argument prefix");
- }
- }
- else {
- if (c == '=') {
+ if ((c = nextc(p)) == '*') {
+ if ((c = nextc(p)) == '=') {
+ set_yylval_id(idPow);
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ if (IS_SPCARG(c)) {
+ rb_warning0("`**' interpreted as argument prefix");
+ c = tDSTAR;
+ }
+ else if (IS_BEG()) {
+ c = tDSTAR;
+ }
+ else {
+ c = warn_balanced((enum ruby_method_ids)tPOW, "**", "argument prefix");
+ }
+ }
+ else {
+ if (c == '=') {
set_yylval_id('*');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- if (IS_SPCARG(c)) {
- rb_warning0("'*' interpreted as argument prefix");
- c = tSTAR;
- }
- else if (IS_BEG()) {
- c = tSTAR;
- }
- else {
- c = warn_balanced('*', "*", "argument prefix");
- }
- }
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
- return c;
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ if (IS_SPCARG(c)) {
+ rb_warning0("`*' interpreted as argument prefix");
+ c = tSTAR;
+ }
+ else if (IS_BEG()) {
+ c = tSTAR;
+ }
+ else {
+ c = warn_balanced('*', "*", "argument prefix");
+ }
+ }
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
+ return c;
case '!':
- c = nextc(p);
- if (IS_AFTER_OPERATOR()) {
- SET_LEX_STATE(EXPR_ARG);
- if (c == '@') {
- return '!';
- }
- }
- else {
- SET_LEX_STATE(EXPR_BEG);
- }
- if (c == '=') {
- return tNEQ;
- }
- if (c == '~') {
- return tNMATCH;
- }
- pushback(p, c);
- return '!';
+ c = nextc(p);
+ if (IS_AFTER_OPERATOR()) {
+ SET_LEX_STATE(EXPR_ARG);
+ if (c == '@') {
+ return '!';
+ }
+ }
+ else {
+ SET_LEX_STATE(EXPR_BEG);
+ }
+ if (c == '=') {
+ return tNEQ;
+ }
+ if (c == '~') {
+ return tNMATCH;
+ }
+ pushback(p, c);
+ return '!';
case '=':
- if (was_bol(p)) {
- /* skip embedded rd document */
- if (word_match_p(p, "begin", 5)) {
- int first_p = TRUE;
-
- lex_goto_eol(p);
- dispatch_scan_event(p, tEMBDOC_BEG);
- for (;;) {
- lex_goto_eol(p);
- if (!first_p) {
- dispatch_scan_event(p, tEMBDOC);
- }
- first_p = FALSE;
- c = nextc(p);
- if (c == -1) {
- compile_error(p, "embedded document meets end of file");
- return END_OF_INPUT;
- }
- if (c == '=' && word_match_p(p, "end", 3)) {
- break;
- }
- pushback(p, c);
- }
- lex_goto_eol(p);
- dispatch_scan_event(p, tEMBDOC_END);
- goto retry;
- }
- }
-
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
- if ((c = nextc(p)) == '=') {
- if ((c = nextc(p)) == '=') {
- return tEQQ;
- }
- pushback(p, c);
- return tEQ;
- }
- if (c == '~') {
- return tMATCH;
- }
- else if (c == '>') {
- return tASSOC;
- }
- pushback(p, c);
- return '=';
+ if (was_bol(p)) {
+ /* skip embedded rd document */
+ if (word_match_p(p, "begin", 5)) {
+ int first_p = TRUE;
+
+ lex_goto_eol(p);
+ dispatch_scan_event(p, tEMBDOC_BEG);
+ for (;;) {
+ lex_goto_eol(p);
+ if (!first_p) {
+ dispatch_scan_event(p, tEMBDOC);
+ }
+ first_p = FALSE;
+ c = nextc(p);
+ if (c == -1) {
+ compile_error(p, "embedded document meets end of file");
+ return 0;
+ }
+ if (c == '=' && word_match_p(p, "end", 3)) {
+ break;
+ }
+ pushback(p, c);
+ }
+ lex_goto_eol(p);
+ dispatch_scan_event(p, tEMBDOC_END);
+ goto retry;
+ }
+ }
+
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
+ if ((c = nextc(p)) == '=') {
+ if ((c = nextc(p)) == '=') {
+ return tEQQ;
+ }
+ pushback(p, c);
+ return tEQ;
+ }
+ if (c == '~') {
+ return tMATCH;
+ }
+ else if (c == '>') {
+ return tASSOC;
+ }
+ pushback(p, c);
+ return '=';
case '<':
- c = nextc(p);
- if (c == '<' &&
- !IS_lex_state(EXPR_DOT | EXPR_CLASS) &&
- !IS_END() &&
- (!IS_ARG() || IS_lex_state(EXPR_LABELED) || space_seen)) {
- enum yytokentype token = heredoc_identifier(p);
- if (token) return token < 0 ? 0 : token;
- }
- if (IS_AFTER_OPERATOR()) {
- SET_LEX_STATE(EXPR_ARG);
- }
- else {
- if (IS_lex_state(EXPR_CLASS))
- p->command_start = TRUE;
- SET_LEX_STATE(EXPR_BEG);
- }
- if (c == '=') {
- if ((c = nextc(p)) == '>') {
- return tCMP;
- }
- pushback(p, c);
- return tLEQ;
- }
- if (c == '<') {
- if ((c = nextc(p)) == '=') {
- set_yylval_id(idLTLT);
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- return warn_balanced((enum ruby_method_ids)tLSHFT, "<<", "here document");
- }
- pushback(p, c);
- return '<';
+ c = nextc(p);
+ if (c == '<' &&
+ !IS_lex_state(EXPR_DOT | EXPR_CLASS) &&
+ !IS_END() &&
+ (!IS_ARG() || IS_lex_state(EXPR_LABELED) || space_seen)) {
+ int token = heredoc_identifier(p);
+ if (token) return token < 0 ? 0 : token;
+ }
+ if (IS_AFTER_OPERATOR()) {
+ SET_LEX_STATE(EXPR_ARG);
+ }
+ else {
+ if (IS_lex_state(EXPR_CLASS))
+ p->command_start = TRUE;
+ SET_LEX_STATE(EXPR_BEG);
+ }
+ if (c == '=') {
+ if ((c = nextc(p)) == '>') {
+ return tCMP;
+ }
+ pushback(p, c);
+ return tLEQ;
+ }
+ if (c == '<') {
+ if ((c = nextc(p)) == '=') {
+ set_yylval_id(idLTLT);
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ return warn_balanced((enum ruby_method_ids)tLSHFT, "<<", "here document");
+ }
+ pushback(p, c);
+ return '<';
case '>':
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
- if ((c = nextc(p)) == '=') {
- return tGEQ;
- }
- if (c == '>') {
- if ((c = nextc(p)) == '=') {
- set_yylval_id(idGTGT);
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- return tRSHFT;
- }
- pushback(p, c);
- return '>';
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
+ if ((c = nextc(p)) == '=') {
+ return tGEQ;
+ }
+ if (c == '>') {
+ if ((c = nextc(p)) == '=') {
+ set_yylval_id(idGTGT);
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ return tRSHFT;
+ }
+ pushback(p, c);
+ return '>';
case '"':
- label = (IS_LABEL_POSSIBLE() ? str_label : 0);
- p->lex.strterm = NEW_STRTERM(str_dquote | label, '"', 0);
- p->lex.ptok = p->lex.pcur-1;
- return tSTRING_BEG;
+ label = (IS_LABEL_POSSIBLE() ? str_label : 0);
+ p->lex.strterm = NEW_STRTERM(str_dquote | label, '"', 0);
+ p->lex.ptok = p->lex.pcur-1;
+ return tSTRING_BEG;
case '`':
- if (IS_lex_state(EXPR_FNAME)) {
- SET_LEX_STATE(EXPR_ENDFN);
- return c;
- }
- if (IS_lex_state(EXPR_DOT)) {
- if (cmd_state)
- SET_LEX_STATE(EXPR_CMDARG);
- else
- SET_LEX_STATE(EXPR_ARG);
- return c;
- }
- p->lex.strterm = NEW_STRTERM(str_xquote, '`', 0);
- return tXSTRING_BEG;
+ if (IS_lex_state(EXPR_FNAME)) {
+ SET_LEX_STATE(EXPR_ENDFN);
+ return c;
+ }
+ if (IS_lex_state(EXPR_DOT)) {
+ if (cmd_state)
+ SET_LEX_STATE(EXPR_CMDARG);
+ else
+ SET_LEX_STATE(EXPR_ARG);
+ return c;
+ }
+ p->lex.strterm = NEW_STRTERM(str_xquote, '`', 0);
+ return tXSTRING_BEG;
case '\'':
- label = (IS_LABEL_POSSIBLE() ? str_label : 0);
- p->lex.strterm = NEW_STRTERM(str_squote | label, '\'', 0);
- p->lex.ptok = p->lex.pcur-1;
- return tSTRING_BEG;
+ label = (IS_LABEL_POSSIBLE() ? str_label : 0);
+ p->lex.strterm = NEW_STRTERM(str_squote | label, '\'', 0);
+ p->lex.ptok = p->lex.pcur-1;
+ return tSTRING_BEG;
case '?':
- return parse_qmark(p, space_seen);
+ return parse_qmark(p, space_seen);
case '&':
- if ((c = nextc(p)) == '&') {
- SET_LEX_STATE(EXPR_BEG);
- if ((c = nextc(p)) == '=') {
+ if ((c = nextc(p)) == '&') {
+ SET_LEX_STATE(EXPR_BEG);
+ if ((c = nextc(p)) == '=') {
set_yylval_id(idANDOP);
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- return tANDOP;
- }
- else if (c == '=') {
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ return tANDOP;
+ }
+ else if (c == '=') {
set_yylval_id('&');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- else if (c == '.') {
- set_yylval_id(idANDDOT);
- SET_LEX_STATE(EXPR_DOT);
- return tANDDOT;
- }
- pushback(p, c);
- if (IS_SPCARG(c)) {
- if ((c != ':') ||
- (c = peekc_n(p, 1)) == -1 ||
- !(c == '\'' || c == '"' ||
- is_identchar(p, (p->lex.pcur+1), p->lex.pend, p->enc))) {
- rb_warning0("'&' interpreted as argument prefix");
- }
- c = tAMPER;
- }
- else if (IS_BEG()) {
- c = tAMPER;
- }
- else {
- c = warn_balanced('&', "&", "argument prefix");
- }
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
- return c;
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ else if (c == '.') {
+ set_yylval_id(idANDDOT);
+ SET_LEX_STATE(EXPR_DOT);
+ return tANDDOT;
+ }
+ pushback(p, c);
+ if (IS_SPCARG(c)) {
+ if ((c != ':') ||
+ (c = peekc_n(p, 1)) == -1 ||
+ !(c == '\'' || c == '"' ||
+ is_identchar((p->lex.pcur+1), p->lex.pend, p->enc))) {
+ rb_warning0("`&' interpreted as argument prefix");
+ }
+ c = tAMPER;
+ }
+ else if (IS_BEG()) {
+ c = tAMPER;
+ }
+ else {
+ c = warn_balanced('&', "&", "argument prefix");
+ }
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
+ return c;
case '|':
- if ((c = nextc(p)) == '|') {
- SET_LEX_STATE(EXPR_BEG);
- if ((c = nextc(p)) == '=') {
+ if ((c = nextc(p)) == '|') {
+ SET_LEX_STATE(EXPR_BEG);
+ if ((c = nextc(p)) == '=') {
set_yylval_id(idOROP);
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- if (IS_lex_state_for(last_state, EXPR_BEG)) {
- c = '|';
- pushback(p, '|');
- return c;
- }
- return tOROP;
- }
- if (c == '=') {
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ if (IS_lex_state_for(last_state, EXPR_BEG)) {
+ c = '|';
+ pushback(p, '|');
+ return c;
+ }
+ return tOROP;
+ }
+ if (c == '=') {
set_yylval_id('|');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG|EXPR_LABEL);
- pushback(p, c);
- return '|';
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG|EXPR_LABEL);
+ pushback(p, c);
+ return '|';
case '+':
- c = nextc(p);
- if (IS_AFTER_OPERATOR()) {
- SET_LEX_STATE(EXPR_ARG);
- if (c == '@') {
- return tUPLUS;
- }
- pushback(p, c);
- return '+';
- }
- if (c == '=') {
+ c = nextc(p);
+ if (IS_AFTER_OPERATOR()) {
+ SET_LEX_STATE(EXPR_ARG);
+ if (c == '@') {
+ return tUPLUS;
+ }
+ pushback(p, c);
+ return '+';
+ }
+ if (c == '=') {
set_yylval_id('+');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p, '+'))) {
- SET_LEX_STATE(EXPR_BEG);
- pushback(p, c);
- if (c != -1 && ISDIGIT(c)) {
- return parse_numeric(p, '+');
- }
- return tUPLUS;
- }
- SET_LEX_STATE(EXPR_BEG);
- pushback(p, c);
- return warn_balanced('+', "+", "unary operator");
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p, '+'))) {
+ SET_LEX_STATE(EXPR_BEG);
+ pushback(p, c);
+ if (c != -1 && ISDIGIT(c)) {
+ return parse_numeric(p, '+');
+ }
+ return tUPLUS;
+ }
+ SET_LEX_STATE(EXPR_BEG);
+ pushback(p, c);
+ return warn_balanced('+', "+", "unary operator");
case '-':
- c = nextc(p);
- if (IS_AFTER_OPERATOR()) {
- SET_LEX_STATE(EXPR_ARG);
- if (c == '@') {
- return tUMINUS;
- }
- pushback(p, c);
- return '-';
- }
- if (c == '=') {
+ c = nextc(p);
+ if (IS_AFTER_OPERATOR()) {
+ SET_LEX_STATE(EXPR_ARG);
+ if (c == '@') {
+ return tUMINUS;
+ }
+ pushback(p, c);
+ return '-';
+ }
+ if (c == '=') {
set_yylval_id('-');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- if (c == '>') {
- SET_LEX_STATE(EXPR_ENDFN);
- yylval.num = p->lex.lpar_beg;
- p->lex.lpar_beg = p->lex.paren_nest;
- return tLAMBDA;
- }
- if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p, '-'))) {
- SET_LEX_STATE(EXPR_BEG);
- pushback(p, c);
- if (c != -1 && ISDIGIT(c)) {
- return tUMINUS_NUM;
- }
- return tUMINUS;
- }
- SET_LEX_STATE(EXPR_BEG);
- pushback(p, c);
- return warn_balanced('-', "-", "unary operator");
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ if (c == '>') {
+ SET_LEX_STATE(EXPR_ENDFN);
+ return tLAMBDA;
+ }
+ if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p, '-'))) {
+ SET_LEX_STATE(EXPR_BEG);
+ pushback(p, c);
+ if (c != -1 && ISDIGIT(c)) {
+ return tUMINUS_NUM;
+ }
+ return tUMINUS;
+ }
+ SET_LEX_STATE(EXPR_BEG);
+ pushback(p, c);
+ return warn_balanced('-', "-", "unary operator");
case '.': {
int is_beg = IS_BEG();
- SET_LEX_STATE(EXPR_BEG);
- if ((c = nextc(p)) == '.') {
- if ((c = nextc(p)) == '.') {
- if (p->ctxt.in_argdef || IS_LABEL_POSSIBLE() || lambda_beginning_p()) {
- SET_LEX_STATE(EXPR_ENDARG);
- return tBDOT3;
- }
- if (p->lex.paren_nest == 0 && looking_at_eol_p(p)) {
- rb_warn0("... at EOL, should be parenthesized?");
- }
- return is_beg ? tBDOT3 : tDOT3;
- }
- pushback(p, c);
- return is_beg ? tBDOT2 : tDOT2;
- }
- pushback(p, c);
- if (c != -1 && ISDIGIT(c)) {
- char prev = p->lex.pcur-1 > p->lex.pbeg ? *(p->lex.pcur-2) : 0;
- parse_numeric(p, '.');
- if (ISDIGIT(prev)) {
- yyerror0("unexpected fraction part after numeric literal");
- }
- else {
- yyerror0("no .<digit> floating literal anymore; put 0 before dot");
- }
- SET_LEX_STATE(EXPR_END);
- p->lex.ptok = p->lex.pcur;
- goto retry;
- }
- set_yylval_id('.');
- SET_LEX_STATE(EXPR_DOT);
- return '.';
+ SET_LEX_STATE(EXPR_BEG);
+ if ((c = nextc(p)) == '.') {
+ if ((c = nextc(p)) == '.') {
+ if (p->ctxt.in_argdef) {
+ SET_LEX_STATE(EXPR_ENDARG);
+ return tBDOT3;
+ }
+ if (p->lex.paren_nest == 0 && looking_at_eol_p(p)) {
+ rb_warn0("... at EOL, should be parenthesized?");
+ }
+ else if (p->lex.lpar_beg >= 0 && p->lex.lpar_beg+1 == p->lex.paren_nest) {
+ if (IS_lex_state_for(last_state, EXPR_LABEL))
+ return tDOT3;
+ }
+ return is_beg ? tBDOT3 : tDOT3;
+ }
+ pushback(p, c);
+ return is_beg ? tBDOT2 : tDOT2;
+ }
+ pushback(p, c);
+ if (c != -1 && ISDIGIT(c)) {
+ char prev = p->lex.pcur-1 > p->lex.pbeg ? *(p->lex.pcur-2) : 0;
+ parse_numeric(p, '.');
+ if (ISDIGIT(prev)) {
+ yyerror0("unexpected fraction part after numeric literal");
+ }
+ else {
+ yyerror0("no .<digit> floating literal anymore; put 0 before dot");
+ }
+ SET_LEX_STATE(EXPR_END);
+ p->lex.ptok = p->lex.pcur;
+ goto retry;
+ }
+ set_yylval_id('.');
+ SET_LEX_STATE(EXPR_DOT);
+ return '.';
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- return parse_numeric(p, c);
+ return parse_numeric(p, c);
case ')':
- COND_POP();
- CMDARG_POP();
- SET_LEX_STATE(EXPR_ENDFN);
- p->lex.paren_nest--;
- return c;
+ COND_POP();
+ CMDARG_POP();
+ SET_LEX_STATE(EXPR_ENDFN);
+ p->lex.paren_nest--;
+ return c;
case ']':
- COND_POP();
- CMDARG_POP();
- SET_LEX_STATE(EXPR_END);
- p->lex.paren_nest--;
- return c;
+ COND_POP();
+ CMDARG_POP();
+ SET_LEX_STATE(EXPR_END);
+ p->lex.paren_nest--;
+ return c;
case '}':
- /* tSTRING_DEND does COND_POP and CMDARG_POP in the yacc's rule */
- if (!p->lex.brace_nest--) return tSTRING_DEND;
- COND_POP();
- CMDARG_POP();
- SET_LEX_STATE(EXPR_END);
- p->lex.paren_nest--;
- return c;
+ /* tSTRING_DEND does COND_POP and CMDARG_POP in the yacc's rule */
+ if (!p->lex.brace_nest--) return tSTRING_DEND;
+ COND_POP();
+ CMDARG_POP();
+ SET_LEX_STATE(EXPR_END);
+ p->lex.paren_nest--;
+ return c;
case ':':
- c = nextc(p);
- if (c == ':') {
- if (IS_BEG() || IS_lex_state(EXPR_CLASS) || IS_SPCARG(-1)) {
- SET_LEX_STATE(EXPR_BEG);
- return tCOLON3;
- }
- set_yylval_id(idCOLON2);
- SET_LEX_STATE(EXPR_DOT);
- return tCOLON2;
- }
- if (IS_END() || ISSPACE(c) || c == '#') {
- pushback(p, c);
- c = warn_balanced(':', ":", "symbol literal");
- SET_LEX_STATE(EXPR_BEG);
- return c;
- }
- switch (c) {
- case '\'':
- p->lex.strterm = NEW_STRTERM(str_ssym, c, 0);
- break;
- case '"':
- p->lex.strterm = NEW_STRTERM(str_dsym, c, 0);
- break;
- default:
- pushback(p, c);
- break;
- }
- SET_LEX_STATE(EXPR_FNAME);
- return tSYMBEG;
+ c = nextc(p);
+ if (c == ':') {
+ if (IS_BEG() || IS_lex_state(EXPR_CLASS) || IS_SPCARG(-1)) {
+ SET_LEX_STATE(EXPR_BEG);
+ return tCOLON3;
+ }
+ set_yylval_id(idCOLON2);
+ SET_LEX_STATE(EXPR_DOT);
+ return tCOLON2;
+ }
+ if (IS_END() || ISSPACE(c) || c == '#') {
+ pushback(p, c);
+ c = warn_balanced(':', ":", "symbol literal");
+ SET_LEX_STATE(EXPR_BEG);
+ return c;
+ }
+ switch (c) {
+ case '\'':
+ p->lex.strterm = NEW_STRTERM(str_ssym, c, 0);
+ break;
+ case '"':
+ p->lex.strterm = NEW_STRTERM(str_dsym, c, 0);
+ break;
+ default:
+ pushback(p, c);
+ break;
+ }
+ SET_LEX_STATE(EXPR_FNAME);
+ return tSYMBEG;
case '/':
- if (IS_BEG()) {
- p->lex.strterm = NEW_STRTERM(str_regexp, '/', 0);
- return tREGEXP_BEG;
- }
- if ((c = nextc(p)) == '=') {
+ if (IS_BEG()) {
+ p->lex.strterm = NEW_STRTERM(str_regexp, '/', 0);
+ return tREGEXP_BEG;
+ }
+ if ((c = nextc(p)) == '=') {
set_yylval_id('/');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- pushback(p, c);
- if (IS_SPCARG(c)) {
- arg_ambiguous(p, '/');
- p->lex.strterm = NEW_STRTERM(str_regexp, '/', 0);
- return tREGEXP_BEG;
- }
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
- return warn_balanced('/', "/", "regexp literal");
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ pushback(p, c);
+ if (IS_SPCARG(c)) {
+ arg_ambiguous(p, '/');
+ p->lex.strterm = NEW_STRTERM(str_regexp, '/', 0);
+ return tREGEXP_BEG;
+ }
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
+ return warn_balanced('/', "/", "regexp literal");
case '^':
- if ((c = nextc(p)) == '=') {
+ if ((c = nextc(p)) == '=') {
set_yylval_id('^');
- SET_LEX_STATE(EXPR_BEG);
- return tOP_ASGN;
- }
- SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
- pushback(p, c);
- return '^';
+ SET_LEX_STATE(EXPR_BEG);
+ return tOP_ASGN;
+ }
+ SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG);
+ pushback(p, c);
+ return '^';
case ';':
- SET_LEX_STATE(EXPR_BEG);
- p->command_start = TRUE;
- return ';';
+ SET_LEX_STATE(EXPR_BEG);
+ p->command_start = TRUE;
+ return ';';
case ',':
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- return ',';
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ return ',';
case '~':
- if (IS_AFTER_OPERATOR()) {
- if ((c = nextc(p)) != '@') {
- pushback(p, c);
- }
- SET_LEX_STATE(EXPR_ARG);
- }
- else {
- SET_LEX_STATE(EXPR_BEG);
- }
- return '~';
+ if (IS_AFTER_OPERATOR()) {
+ if ((c = nextc(p)) != '@') {
+ pushback(p, c);
+ }
+ SET_LEX_STATE(EXPR_ARG);
+ }
+ else {
+ SET_LEX_STATE(EXPR_BEG);
+ }
+ return '~';
case '(':
- if (IS_BEG()) {
- c = tLPAREN;
- }
- else if (!space_seen) {
- /* foo( ... ) => method call, no ambiguity */
- }
- else if (IS_ARG() || IS_lex_state_all(EXPR_END|EXPR_LABEL)) {
- c = tLPAREN_ARG;
- }
- else if (IS_lex_state(EXPR_ENDFN) && !lambda_beginning_p()) {
- rb_warning0("parentheses after method name is interpreted as "
- "an argument list, not a decomposed argument");
- }
- p->lex.paren_nest++;
- COND_PUSH(0);
- CMDARG_PUSH(0);
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- return c;
+ if (IS_BEG()) {
+ c = tLPAREN;
+ }
+ else if (!space_seen) {
+ /* foo( ... ) => method call, no ambiguity */
+ }
+ else if (IS_ARG() || IS_lex_state_all(EXPR_END|EXPR_LABEL)) {
+ c = tLPAREN_ARG;
+ }
+ else if (IS_lex_state(EXPR_ENDFN) && !lambda_beginning_p()) {
+ rb_warning0("parentheses after method name is interpreted as "
+ "an argument list, not a decomposed argument");
+ }
+ p->lex.paren_nest++;
+ COND_PUSH(0);
+ CMDARG_PUSH(0);
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ return c;
case '[':
- p->lex.paren_nest++;
- if (IS_AFTER_OPERATOR()) {
- if ((c = nextc(p)) == ']') {
- p->lex.paren_nest--;
- SET_LEX_STATE(EXPR_ARG);
- if ((c = nextc(p)) == '=') {
- return tASET;
- }
- pushback(p, c);
- return tAREF;
- }
- pushback(p, c);
- SET_LEX_STATE(EXPR_ARG|EXPR_LABEL);
- return '[';
- }
- else if (IS_BEG()) {
- c = tLBRACK;
- }
- else if (IS_ARG() && (space_seen || IS_lex_state(EXPR_LABELED))) {
- c = tLBRACK;
- }
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- COND_PUSH(0);
- CMDARG_PUSH(0);
- return c;
+ p->lex.paren_nest++;
+ if (IS_AFTER_OPERATOR()) {
+ if ((c = nextc(p)) == ']') {
+ p->lex.paren_nest--;
+ SET_LEX_STATE(EXPR_ARG);
+ if ((c = nextc(p)) == '=') {
+ return tASET;
+ }
+ pushback(p, c);
+ return tAREF;
+ }
+ pushback(p, c);
+ SET_LEX_STATE(EXPR_ARG|EXPR_LABEL);
+ return '[';
+ }
+ else if (IS_BEG()) {
+ c = tLBRACK;
+ }
+ else if (IS_ARG() && (space_seen || IS_lex_state(EXPR_LABELED))) {
+ c = tLBRACK;
+ }
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ COND_PUSH(0);
+ CMDARG_PUSH(0);
+ return c;
case '{':
- ++p->lex.brace_nest;
- if (lambda_beginning_p())
- c = tLAMBEG;
- else if (IS_lex_state(EXPR_LABELED))
- c = tLBRACE; /* hash */
- else if (IS_lex_state(EXPR_ARG_ANY | EXPR_END | EXPR_ENDFN))
- c = '{'; /* block (primary) */
- else if (IS_lex_state(EXPR_ENDARG))
- c = tLBRACE_ARG; /* block (expr) */
- else
- c = tLBRACE; /* hash */
- if (c != tLBRACE) {
- p->command_start = TRUE;
- SET_LEX_STATE(EXPR_BEG);
- }
- else {
- SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
- }
- ++p->lex.paren_nest; /* after lambda_beginning_p() */
- COND_PUSH(0);
- CMDARG_PUSH(0);
- return c;
+ ++p->lex.brace_nest;
+ if (lambda_beginning_p())
+ c = tLAMBEG;
+ else if (IS_lex_state(EXPR_LABELED))
+ c = tLBRACE; /* hash */
+ else if (IS_lex_state(EXPR_ARG_ANY | EXPR_END | EXPR_ENDFN))
+ c = '{'; /* block (primary) */
+ else if (IS_lex_state(EXPR_ENDARG))
+ c = tLBRACE_ARG; /* block (expr) */
+ else
+ c = tLBRACE; /* hash */
+ if (c != tLBRACE) {
+ p->command_start = TRUE;
+ SET_LEX_STATE(EXPR_BEG);
+ }
+ else {
+ SET_LEX_STATE(EXPR_BEG|EXPR_LABEL);
+ }
+ ++p->lex.paren_nest; /* after lambda_beginning_p() */
+ COND_PUSH(0);
+ CMDARG_PUSH(0);
+ return c;
case '\\':
- c = nextc(p);
- if (c == '\n') {
- space_seen = 1;
- dispatch_scan_event(p, tSP);
- goto retry; /* skip \\n */
- }
- if (c == ' ') return tSP;
- if (ISSPACE(c)) return c;
- pushback(p, c);
- return '\\';
+ c = nextc(p);
+ if (c == '\n') {
+ space_seen = 1;
+ dispatch_scan_event(p, tSP);
+ goto retry; /* skip \\n */
+ }
+ if (c == ' ') return tSP;
+ if (ISSPACE(c)) return c;
+ pushback(p, c);
+ return '\\';
case '%':
- return parse_percent(p, space_seen, last_state);
+ return parse_percent(p, space_seen, last_state);
case '$':
- return parse_gvar(p, last_state);
+ return parse_gvar(p, last_state);
case '@':
- return parse_atmark(p, last_state);
+ return parse_atmark(p, last_state);
case '_':
- if (was_bol(p) && whole_match_p(p, "__END__", 7, 0)) {
- p->ruby__end__seen = 1;
- p->eofp = 1;
-#ifdef RIPPER
+ if (was_bol(p) && whole_match_p(p, "__END__", 7, 0)) {
+ p->ruby__end__seen = 1;
+ p->eofp = 1;
+#ifndef RIPPER
+ return -1;
+#else
lex_goto_eol(p);
dispatch_scan_event(p, k__END__);
+ return 0;
#endif
- return END_OF_INPUT;
- }
- newtok(p);
- break;
+ }
+ newtok(p);
+ break;
default:
- if (!parser_is_identchar(p)) {
- compile_error(p, "Invalid char '\\x%02X' in expression", c);
+ if (!parser_is_identchar(p)) {
+ compile_error(p, "Invalid char `\\x%02X' in expression", c);
token_flush(p);
- goto retry;
- }
+ goto retry;
+ }
- newtok(p);
- break;
+ newtok(p);
+ break;
}
return parse_ident(p, c, cmd_state);
@@ -11307,15 +10548,15 @@ yylex(YYSTYPE *lval, YYLTYPE *yylloc, struct parser_params *p)
enum yytokentype t;
p->lval = lval;
- lval->node = 0;
+ lval->val = Qundef;
p->yylloc = yylloc;
t = parser_yylex(p);
if (has_delayed_token(p))
- dispatch_delayed_token(p, t);
- else if (t != END_OF_INPUT)
- dispatch_scan_event(p, t);
+ dispatch_delayed_token(p, t);
+ else if (t != 0)
+ dispatch_scan_event(p, t);
return t;
}
@@ -11323,1205 +10564,30 @@ yylex(YYSTYPE *lval, YYLTYPE *yylloc, struct parser_params *p)
#define LVAR_USED ((ID)1 << (sizeof(ID) * CHAR_BIT - 1))
static NODE*
-node_new_internal(struct parser_params *p, enum node_type type, size_t size, size_t alignment)
+node_new_temporal(struct parser_params *p, enum node_type type, VALUE a0, VALUE a1, VALUE a2)
{
- NODE *n = rb_ast_newnode(p->ast, type, size, alignment);
+ NODE *n = rb_ast_newnode(p->ast, type);
- rb_node_init(n, type);
+ rb_node_init(n, type, a0, a1, a2);
return n;
}
-static NODE *
-nd_set_loc(NODE *nd, const YYLTYPE *loc)
-{
- nd->nd_loc = *loc;
- nd_set_line(nd, loc->beg_pos.lineno);
- return nd;
-}
-
static NODE*
-node_newnode(struct parser_params *p, enum node_type type, size_t size, size_t alignment, const rb_code_location_t *loc)
+node_newnode(struct parser_params *p, enum node_type type, VALUE a0, VALUE a1, VALUE a2, const rb_code_location_t *loc)
{
- NODE *n = node_new_internal(p, type, size, alignment);
+ NODE *n = node_new_temporal(p, type, a0, a1, a2);
nd_set_loc(n, loc);
nd_set_node_id(n, parser_get_node_id(p));
return n;
}
-#define NODE_NEWNODE(node_type, type, loc) (type *)(node_newnode(p, node_type, sizeof(type), RUBY_ALIGNOF(type), loc))
-
-static rb_node_scope_t *
-rb_node_scope_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_ast_id_table_t *nd_tbl;
- nd_tbl = local_tbl(p);
- rb_node_scope_t *n = NODE_NEWNODE(NODE_SCOPE, rb_node_scope_t, loc);
- n->nd_tbl = nd_tbl;
- n->nd_body = nd_body;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_scope_t *
-rb_node_scope_new2(struct parser_params *p, rb_ast_id_table_t *nd_tbl, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_scope_t *n = NODE_NEWNODE(NODE_SCOPE, rb_node_scope_t, loc);
- n->nd_tbl = nd_tbl;
- n->nd_body = nd_body;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_defn_t *
-rb_node_defn_new(struct parser_params *p, ID nd_mid, NODE *nd_defn, const YYLTYPE *loc)
-{
- rb_node_defn_t *n = NODE_NEWNODE(NODE_DEFN, rb_node_defn_t, loc);
- n->nd_mid = nd_mid;
- n->nd_defn = nd_defn;
-
- return n;
-}
-
-static rb_node_defs_t *
-rb_node_defs_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_defn, const YYLTYPE *loc)
-{
- rb_node_defs_t *n = NODE_NEWNODE(NODE_DEFS, rb_node_defs_t, loc);
- n->nd_recv = nd_recv;
- n->nd_mid = nd_mid;
- n->nd_defn = nd_defn;
-
- return n;
-}
-
-static rb_node_block_t *
-rb_node_block_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc)
-{
- rb_node_block_t *n = NODE_NEWNODE(NODE_BLOCK, rb_node_block_t, loc);
- n->nd_head = nd_head;
- n->nd_end = (NODE *)n;
- n->nd_next = 0;
-
- return n;
-}
-
-static rb_node_for_t *
-rb_node_for_new(struct parser_params *p, NODE *nd_iter, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_for_t *n = NODE_NEWNODE(NODE_FOR, rb_node_for_t, loc);
- n->nd_body = nd_body;
- n->nd_iter = nd_iter;
-
- return n;
-}
-
-static rb_node_for_masgn_t *
-rb_node_for_masgn_new(struct parser_params *p, NODE *nd_var, const YYLTYPE *loc)
-{
- rb_node_for_masgn_t *n = NODE_NEWNODE(NODE_FOR_MASGN, rb_node_for_masgn_t, loc);
- n->nd_var = nd_var;
-
- return n;
-}
-
-static rb_node_retry_t *
-rb_node_retry_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_retry_t *n = NODE_NEWNODE(NODE_RETRY, rb_node_retry_t, loc);
-
- return n;
-}
-
-static rb_node_begin_t *
-rb_node_begin_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_begin_t *n = NODE_NEWNODE(NODE_BEGIN, rb_node_begin_t, loc);
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_rescue_t *
-rb_node_rescue_new(struct parser_params *p, NODE *nd_head, NODE *nd_resq, NODE *nd_else, const YYLTYPE *loc)
-{
- rb_node_rescue_t *n = NODE_NEWNODE(NODE_RESCUE, rb_node_rescue_t, loc);
- n->nd_head = nd_head;
- n->nd_resq = nd_resq;
- n->nd_else = nd_else;
-
- return n;
-}
-
-static rb_node_resbody_t *
-rb_node_resbody_new(struct parser_params *p, NODE *nd_args, NODE *nd_exc_var, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc)
-{
- rb_node_resbody_t *n = NODE_NEWNODE(NODE_RESBODY, rb_node_resbody_t, loc);
- n->nd_args = nd_args;
- n->nd_exc_var = nd_exc_var;
- n->nd_body = nd_body;
- n->nd_next = nd_next;
-
- return n;
-}
-
-static rb_node_ensure_t *
-rb_node_ensure_new(struct parser_params *p, NODE *nd_head, NODE *nd_ensr, const YYLTYPE *loc)
-{
- rb_node_ensure_t *n = NODE_NEWNODE(NODE_ENSURE, rb_node_ensure_t, loc);
- n->nd_head = nd_head;
- n->nd_ensr = nd_ensr;
-
- return n;
-}
-
-static rb_node_and_t *
-rb_node_and_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc, const YYLTYPE *operator_loc)
-{
- rb_node_and_t *n = NODE_NEWNODE(NODE_AND, rb_node_and_t, loc);
- n->nd_1st = nd_1st;
- n->nd_2nd = nd_2nd;
- n->operator_loc = *operator_loc;
-
- return n;
-}
-
-static rb_node_or_t *
-rb_node_or_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc, const YYLTYPE *operator_loc)
-{
- rb_node_or_t *n = NODE_NEWNODE(NODE_OR, rb_node_or_t, loc);
- n->nd_1st = nd_1st;
- n->nd_2nd = nd_2nd;
- n->operator_loc = *operator_loc;
-
- return n;
-}
-
-static rb_node_return_t *
-rb_node_return_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc, const YYLTYPE *keyword_loc)
-{
- rb_node_return_t *n = NODE_NEWNODE(NODE_RETURN, rb_node_return_t, loc);
- n->nd_stts = nd_stts;
- n->keyword_loc = *keyword_loc;
- return n;
-}
-
-static rb_node_yield_t *
-rb_node_yield_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc)
-{
- rb_node_yield_t *n = NODE_NEWNODE(NODE_YIELD, rb_node_yield_t, loc);
- n->nd_head = nd_head;
-
- return n;
-}
-
-static rb_node_if_t *
-rb_node_if_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_else, const YYLTYPE *loc)
-{
- rb_node_if_t *n = NODE_NEWNODE(NODE_IF, rb_node_if_t, loc);
- n->nd_cond = nd_cond;
- n->nd_body = nd_body;
- n->nd_else = nd_else;
-
- return n;
-}
-
-static rb_node_unless_t *
-rb_node_unless_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_else, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *then_keyword_loc, const YYLTYPE *end_keyword_loc)
-{
- rb_node_unless_t *n = NODE_NEWNODE(NODE_UNLESS, rb_node_unless_t, loc);
- n->nd_cond = nd_cond;
- n->nd_body = nd_body;
- n->nd_else = nd_else;
- n->keyword_loc = *keyword_loc;
- n->then_keyword_loc = *then_keyword_loc;
- n->end_keyword_loc = *end_keyword_loc;
-
- return n;
-}
-
-static rb_node_class_t *
-rb_node_class_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, NODE *nd_super, const YYLTYPE *loc)
-{
- /* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(0, nd_body, loc);
- rb_node_class_t *n = NODE_NEWNODE(NODE_CLASS, rb_node_class_t, loc);
- n->nd_cpath = nd_cpath;
- n->nd_body = scope;
- n->nd_super = nd_super;
-
- return n;
-}
-
-static rb_node_sclass_t *
-rb_node_sclass_new(struct parser_params *p, NODE *nd_recv, NODE *nd_body, const YYLTYPE *loc)
-{
- /* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(0, nd_body, loc);
- rb_node_sclass_t *n = NODE_NEWNODE(NODE_SCLASS, rb_node_sclass_t, loc);
- n->nd_recv = nd_recv;
- n->nd_body = scope;
-
- return n;
-}
-
-static rb_node_module_t *
-rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc)
-{
- /* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(0, nd_body, loc);
- rb_node_module_t *n = NODE_NEWNODE(NODE_MODULE, rb_node_module_t, loc);
- n->nd_cpath = nd_cpath;
- n->nd_body = scope;
-
- return n;
-}
-
-static rb_node_iter_t *
-rb_node_iter_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc)
-{
- /* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(nd_args, nd_body, loc);
- rb_node_iter_t *n = NODE_NEWNODE(NODE_ITER, rb_node_iter_t, loc);
- n->nd_body = scope;
- n->nd_iter = 0;
-
- return n;
-}
-
-static rb_node_lambda_t *
-rb_node_lambda_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc)
-{
- /* Keep the order of node creation */
- NODE *scope = NEW_SCOPE(nd_args, nd_body, loc);
- rb_node_lambda_t *n = NODE_NEWNODE(NODE_LAMBDA, rb_node_lambda_t, loc);
- n->nd_body = scope;
-
- return n;
-}
-
-static rb_node_case_t *
-rb_node_case_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *case_keyword_loc, const YYLTYPE *end_keyword_loc)
-{
- rb_node_case_t *n = NODE_NEWNODE(NODE_CASE, rb_node_case_t, loc);
- n->nd_head = nd_head;
- n->nd_body = nd_body;
- n->case_keyword_loc = *case_keyword_loc;
- n->end_keyword_loc = *end_keyword_loc;
-
- return n;
-}
-
-static rb_node_case2_t *
-rb_node_case2_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *case_keyword_loc, const YYLTYPE *end_keyword_loc)
-{
- rb_node_case2_t *n = NODE_NEWNODE(NODE_CASE2, rb_node_case2_t, loc);
- n->nd_head = 0;
- n->nd_body = nd_body;
- n->case_keyword_loc = *case_keyword_loc;
- n->end_keyword_loc = *end_keyword_loc;
-
- return n;
-}
-
-static rb_node_case3_t *
-rb_node_case3_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *case_keyword_loc, const YYLTYPE *end_keyword_loc)
-{
- rb_node_case3_t *n = NODE_NEWNODE(NODE_CASE3, rb_node_case3_t, loc);
- n->nd_head = nd_head;
- n->nd_body = nd_body;
- n->case_keyword_loc = *case_keyword_loc;
- n->end_keyword_loc = *end_keyword_loc;
-
- return n;
-}
-
-static rb_node_when_t *
-rb_node_when_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *then_keyword_loc)
-{
- rb_node_when_t *n = NODE_NEWNODE(NODE_WHEN, rb_node_when_t, loc);
- n->nd_head = nd_head;
- n->nd_body = nd_body;
- n->nd_next = nd_next;
- n->keyword_loc = *keyword_loc;
- n->then_keyword_loc = *then_keyword_loc;
-
- return n;
-}
-
-static rb_node_in_t *
-rb_node_in_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc)
-{
- rb_node_in_t *n = NODE_NEWNODE(NODE_IN, rb_node_in_t, loc);
- n->nd_head = nd_head;
- n->nd_body = nd_body;
- n->nd_next = nd_next;
-
- return n;
-}
-
-static rb_node_while_t *
-rb_node_while_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, long nd_state, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *closing_loc)
-{
- rb_node_while_t *n = NODE_NEWNODE(NODE_WHILE, rb_node_while_t, loc);
- n->nd_cond = nd_cond;
- n->nd_body = nd_body;
- n->nd_state = nd_state;
- n->keyword_loc = *keyword_loc;
- n->closing_loc = *closing_loc;
-
- return n;
-}
-
-static rb_node_until_t *
-rb_node_until_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, long nd_state, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *closing_loc)
-{
- rb_node_until_t *n = NODE_NEWNODE(NODE_UNTIL, rb_node_until_t, loc);
- n->nd_cond = nd_cond;
- n->nd_body = nd_body;
- n->nd_state = nd_state;
- n->keyword_loc = *keyword_loc;
- n->closing_loc = *closing_loc;
-
- return n;
-}
-
-static rb_node_colon2_t *
-rb_node_colon2_new(struct parser_params *p, NODE *nd_head, ID nd_mid, const YYLTYPE *loc)
-{
- rb_node_colon2_t *n = NODE_NEWNODE(NODE_COLON2, rb_node_colon2_t, loc);
- n->nd_head = nd_head;
- n->nd_mid = nd_mid;
-
- return n;
-}
-
-static rb_node_colon3_t *
-rb_node_colon3_new(struct parser_params *p, ID nd_mid, const YYLTYPE *loc)
-{
- rb_node_colon3_t *n = NODE_NEWNODE(NODE_COLON3, rb_node_colon3_t, loc);
- n->nd_mid = nd_mid;
-
- return n;
-}
-
-static rb_node_dot2_t *
-rb_node_dot2_new(struct parser_params *p, NODE *nd_beg, NODE *nd_end, const YYLTYPE *loc)
-{
- rb_node_dot2_t *n = NODE_NEWNODE(NODE_DOT2, rb_node_dot2_t, loc);
- n->nd_beg = nd_beg;
- n->nd_end = nd_end;
-
- return n;
-}
-
-static rb_node_dot3_t *
-rb_node_dot3_new(struct parser_params *p, NODE *nd_beg, NODE *nd_end, const YYLTYPE *loc)
-{
- rb_node_dot3_t *n = NODE_NEWNODE(NODE_DOT3, rb_node_dot3_t, loc);
- n->nd_beg = nd_beg;
- n->nd_end = nd_end;
-
- return n;
-}
-
-static rb_node_self_t *
-rb_node_self_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_self_t *n = NODE_NEWNODE(NODE_SELF, rb_node_self_t, loc);
- n->nd_state = 1;
-
- return n;
-}
-
-static rb_node_nil_t *
-rb_node_nil_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_nil_t *n = NODE_NEWNODE(NODE_NIL, rb_node_nil_t, loc);
-
- return n;
-}
-
-static rb_node_true_t *
-rb_node_true_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_true_t *n = NODE_NEWNODE(NODE_TRUE, rb_node_true_t, loc);
-
- return n;
-}
-
-static rb_node_false_t *
-rb_node_false_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_false_t *n = NODE_NEWNODE(NODE_FALSE, rb_node_false_t, loc);
-
- return n;
-}
-
-static rb_node_super_t *
-rb_node_super_new(struct parser_params *p, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_super_t *n = NODE_NEWNODE(NODE_SUPER, rb_node_super_t, loc);
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_zsuper_t *
-rb_node_zsuper_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_zsuper_t *n = NODE_NEWNODE(NODE_ZSUPER, rb_node_zsuper_t, loc);
-
- return n;
-}
-
-static rb_node_match2_t *
-rb_node_match2_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_match2_t *n = NODE_NEWNODE(NODE_MATCH2, rb_node_match2_t, loc);
- n->nd_recv = nd_recv;
- n->nd_value = nd_value;
- n->nd_args = 0;
-
- return n;
-}
-
-static rb_node_match3_t *
-rb_node_match3_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_match3_t *n = NODE_NEWNODE(NODE_MATCH3, rb_node_match3_t, loc);
- n->nd_recv = nd_recv;
- n->nd_value = nd_value;
-
- return n;
-}
-
-/* TODO: Use union for NODE_LIST2 */
-static rb_node_list_t *
-rb_node_list_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc)
-{
- rb_node_list_t *n = NODE_NEWNODE(NODE_LIST, rb_node_list_t, loc);
- n->nd_head = nd_head;
- n->as.nd_alen = 1;
- n->nd_next = 0;
-
- return n;
-}
-
-static rb_node_list_t *
-rb_node_list_new2(struct parser_params *p, NODE *nd_head, long nd_alen, NODE *nd_next, const YYLTYPE *loc)
-{
- rb_node_list_t *n = NODE_NEWNODE(NODE_LIST, rb_node_list_t, loc);
- n->nd_head = nd_head;
- n->as.nd_alen = nd_alen;
- n->nd_next = nd_next;
-
- return n;
-}
-
-static rb_node_zlist_t *
-rb_node_zlist_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_zlist_t *n = NODE_NEWNODE(NODE_ZLIST, rb_node_zlist_t, loc);
-
- return n;
-}
-
-static rb_node_hash_t *
-rb_node_hash_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc)
-{
- rb_node_hash_t *n = NODE_NEWNODE(NODE_HASH, rb_node_hash_t, loc);
- n->nd_head = nd_head;
- n->nd_brace = 0;
-
- return n;
-}
-
-static rb_node_masgn_t *
-rb_node_masgn_new(struct parser_params *p, NODE *nd_head, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_masgn_t *n = NODE_NEWNODE(NODE_MASGN, rb_node_masgn_t, loc);
- n->nd_head = nd_head;
- n->nd_value = 0;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_gasgn_t *
-rb_node_gasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_gasgn_t *n = NODE_NEWNODE(NODE_GASGN, rb_node_gasgn_t, loc);
- n->nd_vid = nd_vid;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_lasgn_t *
-rb_node_lasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_lasgn_t *n = NODE_NEWNODE(NODE_LASGN, rb_node_lasgn_t, loc);
- n->nd_vid = nd_vid;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_dasgn_t *
-rb_node_dasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_dasgn_t *n = NODE_NEWNODE(NODE_DASGN, rb_node_dasgn_t, loc);
- n->nd_vid = nd_vid;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_iasgn_t *
-rb_node_iasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_iasgn_t *n = NODE_NEWNODE(NODE_IASGN, rb_node_iasgn_t, loc);
- n->nd_vid = nd_vid;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_cvasgn_t *
-rb_node_cvasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_cvasgn_t *n = NODE_NEWNODE(NODE_CVASGN, rb_node_cvasgn_t, loc);
- n->nd_vid = nd_vid;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_op_asgn1_t *
-rb_node_op_asgn1_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *index, NODE *rvalue, const YYLTYPE *loc, const YYLTYPE *call_operator_loc, const YYLTYPE *opening_loc, const YYLTYPE *closing_loc, const YYLTYPE *binary_operator_loc)
-{
- rb_node_op_asgn1_t *n = NODE_NEWNODE(NODE_OP_ASGN1, rb_node_op_asgn1_t, loc);
- n->nd_recv = nd_recv;
- n->nd_mid = nd_mid;
- n->nd_index = index;
- n->nd_rvalue = rvalue;
- n->call_operator_loc = *call_operator_loc;
- n->opening_loc = *opening_loc;
- n->closing_loc = *closing_loc;
- n->binary_operator_loc = *binary_operator_loc;
-
- return n;
-}
-
-static rb_node_op_asgn2_t *
-rb_node_op_asgn2_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, ID nd_vid, ID nd_mid, bool nd_aid, const YYLTYPE *loc, const YYLTYPE *call_operator_loc, const YYLTYPE *message_loc, const YYLTYPE *binary_operator_loc)
-{
- rb_node_op_asgn2_t *n = NODE_NEWNODE(NODE_OP_ASGN2, rb_node_op_asgn2_t, loc);
- n->nd_recv = nd_recv;
- n->nd_value = nd_value;
- n->nd_vid = nd_vid;
- n->nd_mid = nd_mid;
- n->nd_aid = nd_aid;
- n->call_operator_loc = *call_operator_loc;
- n->message_loc = *message_loc;
- n->binary_operator_loc = *binary_operator_loc;
-
- return n;
-}
-
-static rb_node_op_asgn_or_t *
-rb_node_op_asgn_or_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_op_asgn_or_t *n = NODE_NEWNODE(NODE_OP_ASGN_OR, rb_node_op_asgn_or_t, loc);
- n->nd_head = nd_head;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_op_asgn_and_t *
-rb_node_op_asgn_and_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, const YYLTYPE *loc)
-{
- rb_node_op_asgn_and_t *n = NODE_NEWNODE(NODE_OP_ASGN_AND, rb_node_op_asgn_and_t, loc);
- n->nd_head = nd_head;
- n->nd_value = nd_value;
-
- return n;
-}
-
-static rb_node_gvar_t *
-rb_node_gvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc)
-{
- rb_node_gvar_t *n = NODE_NEWNODE(NODE_GVAR, rb_node_gvar_t, loc);
- n->nd_vid = nd_vid;
-
- return n;
-}
-
-static rb_node_lvar_t *
-rb_node_lvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc)
-{
- rb_node_lvar_t *n = NODE_NEWNODE(NODE_LVAR, rb_node_lvar_t, loc);
- n->nd_vid = nd_vid;
-
- return n;
-}
-
-static rb_node_dvar_t *
-rb_node_dvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc)
-{
- rb_node_dvar_t *n = NODE_NEWNODE(NODE_DVAR, rb_node_dvar_t, loc);
- n->nd_vid = nd_vid;
-
- return n;
-}
-
-static rb_node_ivar_t *
-rb_node_ivar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc)
-{
- rb_node_ivar_t *n = NODE_NEWNODE(NODE_IVAR, rb_node_ivar_t, loc);
- n->nd_vid = nd_vid;
-
- return n;
-}
-
-static rb_node_const_t *
-rb_node_const_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc)
-{
- rb_node_const_t *n = NODE_NEWNODE(NODE_CONST, rb_node_const_t, loc);
- n->nd_vid = nd_vid;
-
- return n;
-}
-
-static rb_node_cvar_t *
-rb_node_cvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc)
-{
- rb_node_cvar_t *n = NODE_NEWNODE(NODE_CVAR, rb_node_cvar_t, loc);
- n->nd_vid = nd_vid;
-
- return n;
-}
-
-static rb_node_nth_ref_t *
-rb_node_nth_ref_new(struct parser_params *p, long nd_nth, const YYLTYPE *loc)
-{
- rb_node_nth_ref_t *n = NODE_NEWNODE(NODE_NTH_REF, rb_node_nth_ref_t, loc);
- n->nd_nth = nd_nth;
-
- return n;
-}
-
-static rb_node_back_ref_t *
-rb_node_back_ref_new(struct parser_params *p, long nd_nth, const YYLTYPE *loc)
-{
- rb_node_back_ref_t *n = NODE_NEWNODE(NODE_BACK_REF, rb_node_back_ref_t, loc);
- n->nd_nth = nd_nth;
-
- return n;
-}
-
-static rb_node_integer_t *
-rb_node_integer_new(struct parser_params *p, char* val, int base, const YYLTYPE *loc)
-{
- rb_node_integer_t *n = NODE_NEWNODE(NODE_INTEGER, rb_node_integer_t, loc);
- n->val = val;
- n->minus = FALSE;
- n->base = base;
-
- return n;
-}
-
-static rb_node_float_t *
-rb_node_float_new(struct parser_params *p, char* val, const YYLTYPE *loc)
-{
- rb_node_float_t *n = NODE_NEWNODE(NODE_FLOAT, rb_node_float_t, loc);
- n->val = val;
- n->minus = FALSE;
-
- return n;
-}
-
-static rb_node_rational_t *
-rb_node_rational_new(struct parser_params *p, char* val, int base, int seen_point, const YYLTYPE *loc)
-{
- rb_node_rational_t *n = NODE_NEWNODE(NODE_RATIONAL, rb_node_rational_t, loc);
- n->val = val;
- n->minus = FALSE;
- n->base = base;
- n->seen_point = seen_point;
-
- return n;
-}
-
-static rb_node_imaginary_t *
-rb_node_imaginary_new(struct parser_params *p, char* val, int base, int seen_point, enum rb_numeric_type numeric_type, const YYLTYPE *loc)
-{
- rb_node_imaginary_t *n = NODE_NEWNODE(NODE_IMAGINARY, rb_node_imaginary_t, loc);
- n->val = val;
- n->minus = FALSE;
- n->base = base;
- n->seen_point = seen_point;
- n->type = numeric_type;
-
- return n;
-}
-
-static rb_node_str_t *
-rb_node_str_new(struct parser_params *p, rb_parser_string_t *string, const YYLTYPE *loc)
-{
- rb_node_str_t *n = NODE_NEWNODE(NODE_STR, rb_node_str_t, loc);
- n->string = string;
-
- return n;
-}
-
-/* TODO; Use union for NODE_DSTR2 */
-static rb_node_dstr_t *
-rb_node_dstr_new0(struct parser_params *p, rb_parser_string_t *string, long nd_alen, NODE *nd_next, const YYLTYPE *loc)
-{
- rb_node_dstr_t *n = NODE_NEWNODE(NODE_DSTR, rb_node_dstr_t, loc);
- n->string = string;
- n->as.nd_alen = nd_alen;
- n->nd_next = (rb_node_list_t *)nd_next;
-
- return n;
-}
-
-static rb_node_dstr_t *
-rb_node_dstr_new(struct parser_params *p, rb_parser_string_t *string, const YYLTYPE *loc)
-{
- return rb_node_dstr_new0(p, string, 1, 0, loc);
-}
-
-static rb_node_xstr_t *
-rb_node_xstr_new(struct parser_params *p, rb_parser_string_t *string, const YYLTYPE *loc)
-{
- rb_node_xstr_t *n = NODE_NEWNODE(NODE_XSTR, rb_node_xstr_t, loc);
- n->string = string;
-
- return n;
-}
-
-static rb_node_dxstr_t *
-rb_node_dxstr_new(struct parser_params *p, rb_parser_string_t *string, long nd_alen, NODE *nd_next, const YYLTYPE *loc)
-{
- rb_node_dxstr_t *n = NODE_NEWNODE(NODE_DXSTR, rb_node_dxstr_t, loc);
- n->string = string;
- n->as.nd_alen = nd_alen;
- n->nd_next = (rb_node_list_t *)nd_next;
-
- return n;
-}
-
-static rb_node_sym_t *
-rb_node_sym_new(struct parser_params *p, VALUE str, const YYLTYPE *loc)
-{
- rb_node_sym_t *n = NODE_NEWNODE(NODE_SYM, rb_node_sym_t, loc);
- n->string = rb_str_to_parser_string(p, str);
-
- return n;
-}
-
-static rb_node_dsym_t *
-rb_node_dsym_new(struct parser_params *p, rb_parser_string_t *string, long nd_alen, NODE *nd_next, const YYLTYPE *loc)
-{
- rb_node_dsym_t *n = NODE_NEWNODE(NODE_DSYM, rb_node_dsym_t, loc);
- n->string = string;
- n->as.nd_alen = nd_alen;
- n->nd_next = (rb_node_list_t *)nd_next;
-
- return n;
-}
-
-static rb_node_evstr_t *
-rb_node_evstr_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_evstr_t *n = NODE_NEWNODE(NODE_EVSTR, rb_node_evstr_t, loc);
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_regx_t *
-rb_node_regx_new(struct parser_params *p, rb_parser_string_t *string, int options, const YYLTYPE *loc)
-{
- rb_node_regx_t *n = NODE_NEWNODE(NODE_REGX, rb_node_regx_t, loc);
- n->string = string;
- n->options = options & RE_OPTION_MASK;
-
- return n;
-}
-
-static rb_node_call_t *
-rb_node_call_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_call_t *n = NODE_NEWNODE(NODE_CALL, rb_node_call_t, loc);
- n->nd_recv = nd_recv;
- n->nd_mid = nd_mid;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_opcall_t *
-rb_node_opcall_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_opcall_t *n = NODE_NEWNODE(NODE_OPCALL, rb_node_opcall_t, loc);
- n->nd_recv = nd_recv;
- n->nd_mid = nd_mid;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_fcall_t *
-rb_node_fcall_new(struct parser_params *p, ID nd_mid, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_fcall_t *n = NODE_NEWNODE(NODE_FCALL, rb_node_fcall_t, loc);
- n->nd_mid = nd_mid;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_qcall_t *
-rb_node_qcall_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_qcall_t *n = NODE_NEWNODE(NODE_QCALL, rb_node_qcall_t, loc);
- n->nd_recv = nd_recv;
- n->nd_mid = nd_mid;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_vcall_t *
-rb_node_vcall_new(struct parser_params *p, ID nd_mid, const YYLTYPE *loc)
-{
- rb_node_vcall_t *n = NODE_NEWNODE(NODE_VCALL, rb_node_vcall_t, loc);
- n->nd_mid = nd_mid;
-
- return n;
-}
-
-static rb_node_once_t *
-rb_node_once_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_once_t *n = NODE_NEWNODE(NODE_ONCE, rb_node_once_t, loc);
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_args_t *
-rb_node_args_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_args_t *n = NODE_NEWNODE(NODE_ARGS, rb_node_args_t, loc);
- MEMZERO(&n->nd_ainfo, struct rb_args_info, 1);
-
- return n;
-}
-
-static rb_node_args_aux_t *
-rb_node_args_aux_new(struct parser_params *p, ID nd_pid, int nd_plen, const YYLTYPE *loc)
-{
- rb_node_args_aux_t *n = NODE_NEWNODE(NODE_ARGS_AUX, rb_node_args_aux_t, loc);
- n->nd_pid = nd_pid;
- n->nd_plen = nd_plen;
- n->nd_next = 0;
-
- return n;
-}
-
-static rb_node_opt_arg_t *
-rb_node_opt_arg_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_opt_arg_t *n = NODE_NEWNODE(NODE_OPT_ARG, rb_node_opt_arg_t, loc);
- n->nd_body = nd_body;
- n->nd_next = 0;
-
- return n;
-}
-
-static rb_node_kw_arg_t *
-rb_node_kw_arg_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_kw_arg_t *n = NODE_NEWNODE(NODE_KW_ARG, rb_node_kw_arg_t, loc);
- n->nd_body = nd_body;
- n->nd_next = 0;
-
- return n;
-}
-
-static rb_node_postarg_t *
-rb_node_postarg_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc)
-{
- rb_node_postarg_t *n = NODE_NEWNODE(NODE_POSTARG, rb_node_postarg_t, loc);
- n->nd_1st = nd_1st;
- n->nd_2nd = nd_2nd;
-
- return n;
-}
-
-static rb_node_argscat_t *
-rb_node_argscat_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_argscat_t *n = NODE_NEWNODE(NODE_ARGSCAT, rb_node_argscat_t, loc);
- n->nd_head = nd_head;
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_argspush_t *
-rb_node_argspush_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_argspush_t *n = NODE_NEWNODE(NODE_ARGSPUSH, rb_node_argspush_t, loc);
- n->nd_head = nd_head;
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_splat_t *
-rb_node_splat_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc, const YYLTYPE *operator_loc)
-{
- rb_node_splat_t *n = NODE_NEWNODE(NODE_SPLAT, rb_node_splat_t, loc);
- n->nd_head = nd_head;
- n->operator_loc = *operator_loc;
-
- return n;
-}
-
-static rb_node_block_pass_t *
-rb_node_block_pass_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *operator_loc)
-{
- rb_node_block_pass_t *n = NODE_NEWNODE(NODE_BLOCK_PASS, rb_node_block_pass_t, loc);
- n->forwarding = 0;
- n->nd_head = 0;
- n->nd_body = nd_body;
- n->operator_loc = *operator_loc;
-
- return n;
-}
-
-static rb_node_alias_t *
-rb_node_alias_new(struct parser_params *p, NODE *nd_1st, NODE *nd_2nd, const YYLTYPE *loc, const YYLTYPE *keyword_loc)
-{
- rb_node_alias_t *n = NODE_NEWNODE(NODE_ALIAS, rb_node_alias_t, loc);
- n->nd_1st = nd_1st;
- n->nd_2nd = nd_2nd;
- n->keyword_loc = *keyword_loc;
-
- return n;
-}
-
-static rb_node_valias_t *
-rb_node_valias_new(struct parser_params *p, ID nd_alias, ID nd_orig, const YYLTYPE *loc, const YYLTYPE *keyword_loc)
-{
- rb_node_valias_t *n = NODE_NEWNODE(NODE_VALIAS, rb_node_valias_t, loc);
- n->nd_alias = nd_alias;
- n->nd_orig = nd_orig;
- n->keyword_loc = *keyword_loc;
-
- return n;
-}
-
-static rb_node_undef_t *
-rb_node_undef_new(struct parser_params *p, NODE *nd_undef, const YYLTYPE *loc)
-{
- rb_node_undef_t *n = NODE_NEWNODE(NODE_UNDEF, rb_node_undef_t, loc);
- n->nd_undefs = rb_parser_ary_new_capa_for_node(p, 1);
- n->keyword_loc = NULL_LOC;
- rb_parser_ary_push_node(p, n->nd_undefs, nd_undef);
-
- return n;
-}
-
-static rb_node_errinfo_t *
-rb_node_errinfo_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_errinfo_t *n = NODE_NEWNODE(NODE_ERRINFO, rb_node_errinfo_t, loc);
-
- return n;
-}
-
-static rb_node_defined_t *
-rb_node_defined_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc)
-{
- rb_node_defined_t *n = NODE_NEWNODE(NODE_DEFINED, rb_node_defined_t, loc);
- n->nd_head = nd_head;
-
- return n;
-}
-
-static rb_node_postexe_t *
-rb_node_postexe_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc)
-{
- rb_node_postexe_t *n = NODE_NEWNODE(NODE_POSTEXE, rb_node_postexe_t, loc);
- n->nd_body = nd_body;
-
- return n;
-}
-
-static rb_node_attrasgn_t *
-rb_node_attrasgn_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc)
-{
- rb_node_attrasgn_t *n = NODE_NEWNODE(NODE_ATTRASGN, rb_node_attrasgn_t, loc);
- n->nd_recv = nd_recv;
- n->nd_mid = nd_mid;
- n->nd_args = nd_args;
-
- return n;
-}
-
-static rb_node_aryptn_t *
-rb_node_aryptn_new(struct parser_params *p, NODE *pre_args, NODE *rest_arg, NODE *post_args, const YYLTYPE *loc)
-{
- rb_node_aryptn_t *n = NODE_NEWNODE(NODE_ARYPTN, rb_node_aryptn_t, loc);
- n->nd_pconst = 0;
- n->pre_args = pre_args;
- n->rest_arg = rest_arg;
- n->post_args = post_args;
-
- return n;
-}
-
-static rb_node_hshptn_t *
-rb_node_hshptn_new(struct parser_params *p, NODE *nd_pconst, NODE *nd_pkwargs, NODE *nd_pkwrestarg, const YYLTYPE *loc)
-{
- rb_node_hshptn_t *n = NODE_NEWNODE(NODE_HSHPTN, rb_node_hshptn_t, loc);
- n->nd_pconst = nd_pconst;
- n->nd_pkwargs = nd_pkwargs;
- n->nd_pkwrestarg = nd_pkwrestarg;
-
- return n;
-}
-
-static rb_node_fndptn_t *
-rb_node_fndptn_new(struct parser_params *p, NODE *pre_rest_arg, NODE *args, NODE *post_rest_arg, const YYLTYPE *loc)
-{
- rb_node_fndptn_t *n = NODE_NEWNODE(NODE_FNDPTN, rb_node_fndptn_t, loc);
- n->nd_pconst = 0;
- n->pre_rest_arg = pre_rest_arg;
- n->args = args;
- n->post_rest_arg = post_rest_arg;
-
- return n;
-}
-
-static rb_node_line_t *
-rb_node_line_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_line_t *n = NODE_NEWNODE(NODE_LINE, rb_node_line_t, loc);
-
- return n;
-}
-
-static rb_node_file_t *
-rb_node_file_new(struct parser_params *p, VALUE str, const YYLTYPE *loc)
-{
- rb_node_file_t *n = NODE_NEWNODE(NODE_FILE, rb_node_file_t, loc);
- n->path = rb_str_to_parser_string(p, str);
-
- return n;
-}
-
-static rb_node_encoding_t *
-rb_node_encoding_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_encoding_t *n = NODE_NEWNODE(NODE_ENCODING, rb_node_encoding_t, loc);
- n->enc = p->enc;
-
- return n;
-}
-
-static rb_node_cdecl_t *
-rb_node_cdecl_new(struct parser_params *p, ID nd_vid, NODE *nd_value, NODE *nd_else, enum rb_parser_shareability shareability, const YYLTYPE *loc)
-{
- rb_node_cdecl_t *n = NODE_NEWNODE(NODE_CDECL, rb_node_cdecl_t, loc);
- n->nd_vid = nd_vid;
- n->nd_value = nd_value;
- n->nd_else = nd_else;
- n->shareability = shareability;
-
- return n;
-}
-
-static rb_node_op_cdecl_t *
-rb_node_op_cdecl_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, ID nd_aid, enum rb_parser_shareability shareability, const YYLTYPE *loc)
-{
- rb_node_op_cdecl_t *n = NODE_NEWNODE(NODE_OP_CDECL, rb_node_op_cdecl_t, loc);
- n->nd_head = nd_head;
- n->nd_value = nd_value;
- n->nd_aid = nd_aid;
- n->shareability = shareability;
-
- return n;
-}
-
-static rb_node_error_t *
-rb_node_error_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_error_t *n = NODE_NEWNODE(NODE_ERROR, rb_node_error_t, loc);
-
- return n;
-}
-
-static rb_node_break_t *
-rb_node_break_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc, const YYLTYPE *keyword_loc)
-{
- rb_node_break_t *n = NODE_NEWNODE(NODE_BREAK, rb_node_break_t, loc);
- n->nd_stts = nd_stts;
- n->nd_chain = 0;
- n->keyword_loc = *keyword_loc;
-
- return n;
-}
-
-static rb_node_next_t *
-rb_node_next_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc, const YYLTYPE *keyword_loc)
-{
- rb_node_next_t *n = NODE_NEWNODE(NODE_NEXT, rb_node_next_t, loc);
- n->nd_stts = nd_stts;
- n->nd_chain = 0;
- n->keyword_loc = *keyword_loc;
-
- return n;
-}
-
-static rb_node_redo_t *
-rb_node_redo_new(struct parser_params *p, const YYLTYPE *loc, const YYLTYPE *keyword_loc)
-{
- rb_node_redo_t *n = NODE_NEWNODE(NODE_REDO, rb_node_redo_t, loc);
- n->nd_chain = 0;
- n->keyword_loc = *keyword_loc;
-
- return n;
-}
-
-static rb_node_def_temp_t *
-rb_node_def_temp_new(struct parser_params *p, const YYLTYPE *loc)
-{
- rb_node_def_temp_t *n = NODE_NEWNODE((enum node_type)NODE_DEF_TEMP, rb_node_def_temp_t, loc);
- n->save.numparam_save = 0;
- n->save.max_numparam = 0;
- n->save.ctxt = p->ctxt;
- n->nd_def = 0;
- n->nd_mid = 0;
-
- return n;
-}
-
-static rb_node_def_temp_t *
-def_head_save(struct parser_params *p, rb_node_def_temp_t *n)
+static NODE *
+nd_set_loc(NODE *nd, const YYLTYPE *loc)
{
- n->save.numparam_save = numparam_push(p);
- n->save.max_numparam = p->max_numparam;
- return n;
+ nd->nd_loc = *loc;
+ nd_set_line(nd, loc->beg_pos.lineno);
+ return nd;
}
#ifndef RIPPER
@@ -12536,14 +10602,13 @@ nodeline(NODE *node)
{
return nd_line(node);
}
-#endif
static NODE*
newline_node(NODE *node)
{
if (node) {
- node = remove_begin(node);
- nd_set_fl_newline(node);
+ node = remove_begin(node);
+ node->flags |= NODE_FL_NEWLINE;
}
return node;
}
@@ -12556,6 +10621,18 @@ fixpos(NODE *node, NODE *orig)
nd_set_line(node, nd_line(orig));
}
+static void
+parser_warning(struct parser_params *p, NODE *node, const char *mesg)
+{
+ rb_compile_warning(p->ruby_sourcefile, nd_line(node), "%s", mesg);
+}
+
+static void
+parser_warn(struct parser_params *p, NODE *node, const char *mesg)
+{
+ rb_compile_warn(p->ruby_sourcefile, nd_line(node), "%s", mesg);
+}
+
static NODE*
block_append(struct parser_params *p, NODE *head, NODE *tail)
{
@@ -12565,34 +10642,46 @@ block_append(struct parser_params *p, NODE *head, NODE *tail)
if (h == 0) return tail;
switch (nd_type(h)) {
+ case NODE_LIT:
+ case NODE_STR:
+ case NODE_SELF:
+ case NODE_TRUE:
+ case NODE_FALSE:
+ case NODE_NIL:
+ parser_warning(p, h, "unused literal ignored");
+ return tail;
default:
- h = end = NEW_BLOCK(head, &head->nd_loc);
- head = end;
- break;
+ h = end = NEW_BLOCK(head, &head->nd_loc);
+ end->nd_end = end;
+ head = end;
+ break;
case NODE_BLOCK:
- end = RNODE_BLOCK(h)->nd_end;
- break;
+ end = h->nd_end;
+ break;
}
- nd = RNODE_BLOCK(end)->nd_head;
+ nd = end->nd_head;
switch (nd_type(nd)) {
case NODE_RETURN:
case NODE_BREAK:
case NODE_NEXT:
case NODE_REDO:
case NODE_RETRY:
- rb_warning0L(nd_line(tail), "statement not reached");
- break;
+ if (RTEST(ruby_verbose)) {
+ parser_warning(p, tail, "statement not reached");
+ }
+ break;
default:
- break;
+ break;
}
if (!nd_type_p(tail, NODE_BLOCK)) {
- tail = NEW_BLOCK(tail, &tail->nd_loc);
+ tail = NEW_BLOCK(tail, &tail->nd_loc);
+ tail->nd_end = tail;
}
- RNODE_BLOCK(end)->nd_next = tail;
- RNODE_BLOCK(h)->nd_end = RNODE_BLOCK(tail)->nd_end;
+ end->nd_next = tail;
+ h->nd_end = tail->nd_end;
nd_set_last_loc(head, nd_last_loc(tail));
return head;
}
@@ -12604,16 +10693,16 @@ list_append(struct parser_params *p, NODE *list, NODE *item)
NODE *last;
if (list == 0) return NEW_LIST(item, &item->nd_loc);
- if (RNODE_LIST(list)->nd_next) {
- last = RNODE_LIST(RNODE_LIST(list)->nd_next)->as.nd_end;
+ if (list->nd_next) {
+ last = list->nd_next->nd_end;
}
else {
- last = list;
+ last = list;
}
- RNODE_LIST(list)->as.nd_alen += 1;
- RNODE_LIST(last)->nd_next = NEW_LIST(item, &item->nd_loc);
- RNODE_LIST(RNODE_LIST(list)->nd_next)->as.nd_end = RNODE_LIST(last)->nd_next;
+ list->nd_alen += 1;
+ last->nd_next = NEW_LIST(item, &item->nd_loc);
+ list->nd_next->nd_end = last->nd_next;
nd_set_last_loc(list, nd_last_loc(item));
@@ -12626,20 +10715,20 @@ list_concat(NODE *head, NODE *tail)
{
NODE *last;
- if (RNODE_LIST(head)->nd_next) {
- last = RNODE_LIST(RNODE_LIST(head)->nd_next)->as.nd_end;
+ if (head->nd_next) {
+ last = head->nd_next->nd_end;
}
else {
- last = head;
+ last = head;
}
- RNODE_LIST(head)->as.nd_alen += RNODE_LIST(tail)->as.nd_alen;
- RNODE_LIST(last)->nd_next = tail;
- if (RNODE_LIST(tail)->nd_next) {
- RNODE_LIST(RNODE_LIST(head)->nd_next)->as.nd_end = RNODE_LIST(RNODE_LIST(tail)->nd_next)->as.nd_end;
+ head->nd_alen += tail->nd_alen;
+ last->nd_next = tail;
+ if (tail->nd_next) {
+ head->nd_next->nd_end = tail->nd_next->nd_end;
}
else {
- RNODE_LIST(RNODE_LIST(head)->nd_next)->as.nd_end = tail;
+ head->nd_next->nd_end = tail;
}
nd_set_last_loc(head, nd_last_loc(tail));
@@ -12648,179 +10737,128 @@ list_concat(NODE *head, NODE *tail)
}
static int
-literal_concat0(struct parser_params *p, rb_parser_string_t *head, rb_parser_string_t *tail)
-{
- if (!tail) return 1;
- if (!rb_parser_enc_compatible(p, head, tail)) {
- compile_error(p, "string literal encodings differ (%s / %s)",
- rb_enc_name(rb_parser_str_get_encoding(head)),
- rb_enc_name(rb_parser_str_get_encoding(tail)));
- rb_parser_str_resize(p, head, 0);
- rb_parser_str_resize(p, tail, 0);
- return 0;
- }
- rb_parser_str_buf_append(p, head, tail);
+literal_concat0(struct parser_params *p, VALUE head, VALUE tail)
+{
+ if (NIL_P(tail)) return 1;
+ if (!rb_enc_compatible(head, tail)) {
+ compile_error(p, "string literal encodings differ (%s / %s)",
+ rb_enc_name(rb_enc_get(head)),
+ rb_enc_name(rb_enc_get(tail)));
+ rb_str_resize(head, 0);
+ rb_str_resize(tail, 0);
+ return 0;
+ }
+ rb_str_buf_append(head, tail);
return 1;
}
-static rb_parser_string_t *
-string_literal_head(struct parser_params *p, enum node_type htype, NODE *head)
+static VALUE
+string_literal_head(enum node_type htype, NODE *head)
{
- if (htype != NODE_DSTR) return NULL;
- if (RNODE_DSTR(head)->nd_next) {
- head = RNODE_LIST(RNODE_LIST(RNODE_DSTR(head)->nd_next)->as.nd_end)->nd_head;
- if (!head || !nd_type_p(head, NODE_STR)) return NULL;
+ if (htype != NODE_DSTR) return Qfalse;
+ if (head->nd_next) {
+ head = head->nd_next->nd_end->nd_head;
+ if (!head || !nd_type_p(head, NODE_STR)) return Qfalse;
}
- rb_parser_string_t *lit = RNODE_DSTR(head)->string;
- ASSUME(lit);
+ const VALUE lit = head->nd_lit;
+ ASSUME(lit != Qfalse);
return lit;
}
-#ifndef RIPPER
-static rb_parser_string_t *
-rb_parser_string_deep_copy(struct parser_params *p, const rb_parser_string_t *orig)
-{
- rb_parser_string_t *copy;
- if (!orig) return NULL;
- copy = rb_parser_string_new(p, PARSER_STRING_PTR(orig), PARSER_STRING_LEN(orig));
- copy->coderange = orig->coderange;
- copy->enc = orig->enc;
- return copy;
-}
-#endif
-
/* concat two string literals */
static NODE *
literal_concat(struct parser_params *p, NODE *head, NODE *tail, const YYLTYPE *loc)
{
enum node_type htype;
- rb_parser_string_t *lit;
+ VALUE lit;
if (!head) return tail;
if (!tail) return head;
htype = nd_type(head);
if (htype == NODE_EVSTR) {
- head = new_dstr(p, head, loc);
- htype = NODE_DSTR;
+ head = new_dstr(p, head, loc);
+ htype = NODE_DSTR;
}
if (p->heredoc_indent > 0) {
- switch (htype) {
- case NODE_STR:
- head = str2dstr(p, head);
- case NODE_DSTR:
- return list_append(p, head, tail);
- default:
- break;
- }
+ switch (htype) {
+ case NODE_STR:
+ nd_set_type(head, NODE_DSTR);
+ case NODE_DSTR:
+ return list_append(p, head, tail);
+ default:
+ break;
+ }
}
switch (nd_type(tail)) {
case NODE_STR:
- if ((lit = string_literal_head(p, htype, head)) != false) {
- htype = NODE_STR;
- }
- else {
- lit = RNODE_DSTR(head)->string;
- }
- if (htype == NODE_STR) {
- if (!literal_concat0(p, lit, RNODE_STR(tail)->string)) {
- error:
- rb_discard_node(p, head);
- rb_discard_node(p, tail);
- return 0;
- }
- rb_discard_node(p, tail);
- }
- else {
- list_append(p, head, tail);
- }
- break;
+ if ((lit = string_literal_head(htype, head)) != Qfalse) {
+ htype = NODE_STR;
+ }
+ else {
+ lit = head->nd_lit;
+ }
+ if (htype == NODE_STR) {
+ if (!literal_concat0(p, lit, tail->nd_lit)) {
+ error:
+ rb_discard_node(p, head);
+ rb_discard_node(p, tail);
+ return 0;
+ }
+ rb_discard_node(p, tail);
+ }
+ else {
+ list_append(p, head, tail);
+ }
+ break;
case NODE_DSTR:
- if (htype == NODE_STR) {
- if (!literal_concat0(p, RNODE_STR(head)->string, RNODE_DSTR(tail)->string))
- goto error;
- rb_parser_string_free(p, RNODE_DSTR(tail)->string);
- RNODE_DSTR(tail)->string = RNODE_STR(head)->string;
- RNODE_STR(head)->string = NULL;
- rb_discard_node(p, head);
- head = tail;
- }
- else if (!RNODE_DSTR(tail)->string) {
- append:
- RNODE_DSTR(head)->as.nd_alen += RNODE_DSTR(tail)->as.nd_alen - 1;
- if (!RNODE_DSTR(head)->nd_next) {
- RNODE_DSTR(head)->nd_next = RNODE_DSTR(tail)->nd_next;
- }
- else if (RNODE_DSTR(tail)->nd_next) {
- RNODE_DSTR(RNODE_DSTR(RNODE_DSTR(head)->nd_next)->as.nd_end)->nd_next = RNODE_DSTR(tail)->nd_next;
- RNODE_DSTR(RNODE_DSTR(head)->nd_next)->as.nd_end = RNODE_DSTR(RNODE_DSTR(tail)->nd_next)->as.nd_end;
- }
- rb_discard_node(p, tail);
- }
- else if ((lit = string_literal_head(p, htype, head)) != false) {
- if (!literal_concat0(p, lit, RNODE_DSTR(tail)->string))
- goto error;
- rb_parser_string_free(p, RNODE_DSTR(tail)->string);
- RNODE_DSTR(tail)->string = 0;
- goto append;
- }
- else {
- list_concat(head, NEW_LIST2(NEW_STR(RNODE_DSTR(tail)->string, loc), RNODE_DSTR(tail)->as.nd_alen, (NODE *)RNODE_DSTR(tail)->nd_next, loc));
- RNODE_DSTR(tail)->string = 0;
- }
- break;
+ if (htype == NODE_STR) {
+ if (!literal_concat0(p, head->nd_lit, tail->nd_lit))
+ goto error;
+ tail->nd_lit = head->nd_lit;
+ rb_discard_node(p, head);
+ head = tail;
+ }
+ else if (NIL_P(tail->nd_lit)) {
+ append:
+ head->nd_alen += tail->nd_alen - 1;
+ if (!head->nd_next) {
+ head->nd_next = tail->nd_next;
+ }
+ else if (tail->nd_next) {
+ head->nd_next->nd_end->nd_next = tail->nd_next;
+ head->nd_next->nd_end = tail->nd_next->nd_end;
+ }
+ rb_discard_node(p, tail);
+ }
+ else if ((lit = string_literal_head(htype, head)) != Qfalse) {
+ if (!literal_concat0(p, lit, tail->nd_lit))
+ goto error;
+ tail->nd_lit = Qnil;
+ goto append;
+ }
+ else {
+ list_concat(head, NEW_NODE(NODE_LIST, NEW_STR(tail->nd_lit, loc), tail->nd_alen, tail->nd_next, loc));
+ }
+ break;
case NODE_EVSTR:
- if (htype == NODE_STR) {
- head = str2dstr(p, head);
- RNODE_DSTR(head)->as.nd_alen = 1;
- }
- list_append(p, head, tail);
- break;
+ if (htype == NODE_STR) {
+ nd_set_type(head, NODE_DSTR);
+ head->nd_alen = 1;
+ }
+ list_append(p, head, tail);
+ break;
}
return head;
}
-static void
-nd_copy_flag(NODE *new_node, NODE *old_node)
-{
- if (nd_fl_newline(old_node)) nd_set_fl_newline(new_node);
- nd_set_line(new_node, nd_line(old_node));
- new_node->nd_loc = old_node->nd_loc;
- new_node->node_id = old_node->node_id;
-}
-
-static NODE *
-str2dstr(struct parser_params *p, NODE *node)
-{
- NODE *new_node = (NODE *)NODE_NEW_INTERNAL(NODE_DSTR, rb_node_dstr_t);
- nd_copy_flag(new_node, node);
- RNODE_DSTR(new_node)->string = RNODE_STR(node)->string;
- RNODE_DSTR(new_node)->as.nd_alen = 0;
- RNODE_DSTR(new_node)->nd_next = 0;
- RNODE_STR(node)->string = 0;
-
- return new_node;
-}
-
-static NODE *
-str2regx(struct parser_params *p, NODE *node, int options)
-{
- NODE *new_node = (NODE *)NODE_NEW_INTERNAL(NODE_REGX, rb_node_regx_t);
- nd_copy_flag(new_node, node);
- RNODE_REGX(new_node)->string = RNODE_STR(node)->string;
- RNODE_REGX(new_node)->options = options;
- RNODE_STR(node)->string = 0;
-
- return new_node;
-}
-
static NODE *
evstr2dstr(struct parser_params *p, NODE *node)
{
if (nd_type_p(node, NODE_EVSTR)) {
- node = new_dstr(p, node, &node->nd_loc);
+ node = new_dstr(p, node, &node->nd_loc);
}
return node;
}
@@ -12831,14 +10869,15 @@ new_evstr(struct parser_params *p, NODE *node, const YYLTYPE *loc)
NODE *head = node;
if (node) {
- switch (nd_type(node)) {
- case NODE_STR:
- return str2dstr(p, node);
+ switch (nd_type(node)) {
+ case NODE_STR:
+ nd_set_type(node, NODE_DSTR);
+ return node;
case NODE_DSTR:
break;
case NODE_EVSTR:
- return node;
- }
+ return node;
+ }
}
return NEW_EVSTR(head, loc);
}
@@ -12846,13 +10885,15 @@ new_evstr(struct parser_params *p, NODE *node, const YYLTYPE *loc)
static NODE *
new_dstr(struct parser_params *p, NODE *node, const YYLTYPE *loc)
{
- NODE *dstr = NEW_DSTR(STRING_NEW0(), loc);
+ VALUE lit = STR_NEW0();
+ NODE *dstr = NEW_DSTR(lit, loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, lit);
return list_append(p, dstr, node);
}
static NODE *
call_bin_op(struct parser_params *p, NODE *recv, ID id, NODE *arg1,
- const YYLTYPE *op_loc, const YYLTYPE *loc)
+ const YYLTYPE *op_loc, const YYLTYPE *loc)
{
NODE *expr;
value_expr(recv);
@@ -12891,15 +10932,7 @@ new_command_qcall(struct parser_params* p, ID atype, NODE *recv, ID mid, NODE *a
return ret;
}
-#define nd_once_body(node) (nd_type_p((node), NODE_ONCE) ? RNODE_ONCE(node)->nd_body : node)
-
-static NODE*
-last_expr_once_body(NODE *node)
-{
- if (!node) return 0;
- return nd_once_body(node);
-}
-
+#define nd_once_body(node) (nd_type_p((node), NODE_ONCE) ? (node)->nd_body : node)
static NODE*
match_op(struct parser_params *p, NODE *node1, NODE *node2, const YYLTYPE *op_loc, const YYLTYPE *loc)
{
@@ -12908,37 +10941,37 @@ match_op(struct parser_params *p, NODE *node1, NODE *node2, const YYLTYPE *op_lo
value_expr(node1);
value_expr(node2);
-
- if ((n = last_expr_once_body(node1)) != 0) {
- switch (nd_type(n)) {
- case NODE_DREGX:
- {
- NODE *match = NEW_MATCH2(node1, node2, loc);
- nd_set_line(match, line);
- return match;
- }
-
- case NODE_REGX:
- {
- const VALUE lit = rb_node_regx_string_val(n);
- if (!NIL_P(lit)) {
- NODE *match = NEW_MATCH2(node1, node2, loc);
- RNODE_MATCH2(match)->nd_args = reg_named_capture_assign(p, lit, loc);
- nd_set_line(match, line);
- return match;
- }
- }
- }
- }
-
- if ((n = last_expr_once_body(node2)) != 0) {
+ if (node1 && (n = nd_once_body(node1)) != 0) {
+ switch (nd_type(n)) {
+ case NODE_DREGX:
+ {
+ NODE *match = NEW_MATCH2(node1, node2, loc);
+ nd_set_line(match, line);
+ return match;
+ }
+
+ case NODE_LIT:
+ if (RB_TYPE_P(n->nd_lit, T_REGEXP)) {
+ const VALUE lit = n->nd_lit;
+ NODE *match = NEW_MATCH2(node1, node2, loc);
+ match->nd_args = reg_named_capture_assign(p, lit, loc);
+ nd_set_line(match, line);
+ return match;
+ }
+ }
+ }
+
+ if (node2 && (n = nd_once_body(node2)) != 0) {
NODE *match3;
- switch (nd_type(n)) {
- case NODE_DREGX:
- match3 = NEW_MATCH3(node2, node1, loc);
- return match3;
- }
+ switch (nd_type(n)) {
+ case NODE_LIT:
+ if (!RB_TYPE_P(n->nd_lit, T_REGEXP)) break;
+ /* fallthru */
+ case NODE_DREGX:
+ match3 = NEW_MATCH3(node2, node1, loc);
+ return match3;
+ }
}
n = NEW_CALL(node1, tMATCH, NEW_LIST(node2, &node2->nd_loc), loc);
@@ -12952,8 +10985,8 @@ past_dvar_p(struct parser_params *p, ID id)
{
struct vtable *past = p->lvtbl->past;
while (past) {
- if (vtable_included(past, id)) return 1;
- past = past->prev;
+ if (vtable_included(past, id)) return 1;
+ past = past->prev;
}
return 0;
}
@@ -12966,41 +10999,13 @@ numparam_nested_p(struct parser_params *p)
NODE *outer = local->numparam.outer;
NODE *inner = local->numparam.inner;
if (outer || inner) {
- NODE *used = outer ? outer : inner;
- compile_error(p, "numbered parameter is already used in\n"
- "%s:%d: %s block here",
- p->ruby_sourcefile, nd_line(used),
- outer ? "outer" : "inner");
- parser_show_error_line(p, &used->nd_loc);
- return 1;
- }
- return 0;
-}
-
-static int
-numparam_used_p(struct parser_params *p)
-{
- NODE *numparam = p->lvtbl->numparam.current;
- if (numparam) {
- compile_error(p, "numbered parameter is already used in\n"
- "%s:%d: current block here",
- p->ruby_sourcefile, nd_line(numparam));
- parser_show_error_line(p, &numparam->nd_loc);
- return 1;
- }
- return 0;
-}
-
-static int
-it_used_p(struct parser_params *p)
-{
- NODE *it = p->lvtbl->it;
- if (it) {
- compile_error(p, "'it' is already used in\n"
- "%s:%d: current block here",
- p->ruby_sourcefile, nd_line(it));
- parser_show_error_line(p, &it->nd_loc);
- return 1;
+ NODE *used = outer ? outer : inner;
+ compile_error(p, "numbered parameter is already used in\n"
+ "%s:%d: %s block here",
+ p->ruby_sourcefile, nd_line(used),
+ outer ? "outer" : "inner");
+ parser_show_error_line(p, &used->nd_loc);
+ return 1;
}
return 0;
}
@@ -13012,103 +11017,101 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
NODE *node;
switch (id) {
case keyword_self:
- return NEW_SELF(loc);
+ return NEW_SELF(loc);
case keyword_nil:
- return NEW_NIL(loc);
+ return NEW_NIL(loc);
case keyword_true:
- return NEW_TRUE(loc);
+ return NEW_TRUE(loc);
case keyword_false:
- return NEW_FALSE(loc);
+ return NEW_FALSE(loc);
case keyword__FILE__:
- {
- VALUE file = p->ruby_sourcefile_string;
- if (NIL_P(file))
- file = rb_str_new(0, 0);
- node = NEW_FILE(file, loc);
- }
- return node;
+ {
+ VALUE file = p->ruby_sourcefile_string;
+ if (NIL_P(file))
+ file = rb_str_new(0, 0);
+ else
+ file = rb_str_dup(file);
+ node = NEW_STR(file, loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, file);
+ }
+ return node;
case keyword__LINE__:
- return NEW_LINE(loc);
+ return NEW_LIT(INT2FIX(p->tokline), loc);
case keyword__ENCODING__:
- return NEW_ENCODING(loc);
+ node = NEW_LIT(rb_enc_from_encoding(p->enc), loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, node->nd_lit);
+ return node;
}
switch (id_type(id)) {
case ID_LOCAL:
- if (dyna_in_block(p) && dvar_defined_ref(p, id, &vidp)) {
- if (NUMPARAM_ID_P(id) && (numparam_nested_p(p) || it_used_p(p))) return 0;
- if (vidp) *vidp |= LVAR_USED;
- node = NEW_DVAR(id, loc);
- return node;
- }
- if (local_id_ref(p, id, &vidp)) {
- if (vidp) *vidp |= LVAR_USED;
- node = NEW_LVAR(id, loc);
- return node;
- }
- if (dyna_in_block(p) && NUMPARAM_ID_P(id) &&
- parser_numbered_param(p, NUMPARAM_ID_TO_IDX(id))) {
- if (numparam_nested_p(p) || it_used_p(p)) return 0;
- node = NEW_DVAR(id, loc);
- struct local_vars *local = p->lvtbl;
- if (!local->numparam.current) local->numparam.current = node;
- return node;
- }
+ if (dyna_in_block(p) && dvar_defined_ref(p, id, &vidp)) {
+ if (NUMPARAM_ID_P(id) && numparam_nested_p(p)) return 0;
+ if (id == p->cur_arg) {
+ compile_error(p, "circular argument reference - %"PRIsWARN, rb_id2str(id));
+ return 0;
+ }
+ if (vidp) *vidp |= LVAR_USED;
+ node = NEW_DVAR(id, loc);
+ return node;
+ }
+ if (local_id_ref(p, id, &vidp)) {
+ if (id == p->cur_arg) {
+ compile_error(p, "circular argument reference - %"PRIsWARN, rb_id2str(id));
+ return 0;
+ }
+ if (vidp) *vidp |= LVAR_USED;
+ node = NEW_LVAR(id, loc);
+ return node;
+ }
+ if (dyna_in_block(p) && NUMPARAM_ID_P(id) &&
+ parser_numbered_param(p, NUMPARAM_ID_TO_IDX(id))) {
+ if (numparam_nested_p(p)) return 0;
+ node = NEW_DVAR(id, loc);
+ struct local_vars *local = p->lvtbl;
+ if (!local->numparam.current) local->numparam.current = node;
+ return node;
+ }
# if WARN_PAST_SCOPE
- if (!p->ctxt.in_defined && RTEST(ruby_verbose) && past_dvar_p(p, id)) {
- rb_warning1("possible reference to past scope - %"PRIsWARN, rb_id2str(id));
- }
+ if (!p->ctxt.in_defined && RTEST(ruby_verbose) && past_dvar_p(p, id)) {
+ rb_warning1("possible reference to past scope - %"PRIsWARN, rb_id2str(id));
+ }
# endif
- /* method call without arguments */
- if (dyna_in_block(p) && id == rb_intern("it") && !(DVARS_TERMINAL_P(p->lvtbl->args) || DVARS_TERMINAL_P(p->lvtbl->args->prev))) {
- if (numparam_used_p(p)) return 0;
- if (p->max_numparam == ORDINAL_PARAM) {
- compile_error(p, "ordinary parameter is defined");
- return 0;
- }
- if (!p->it_id) {
- p->it_id = internal_id(p);
- vtable_add(p->lvtbl->args, p->it_id);
- }
- NODE *node = NEW_DVAR(p->it_id, loc);
- if (!p->lvtbl->it) p->lvtbl->it = node;
- return node;
- }
- return NEW_VCALL(id, loc);
+ /* method call without arguments */
+ return NEW_VCALL(id, loc);
case ID_GLOBAL:
- return NEW_GVAR(id, loc);
+ return NEW_GVAR(id, loc);
case ID_INSTANCE:
- return NEW_IVAR(id, loc);
+ return NEW_IVAR(id, loc);
case ID_CONST:
- return NEW_CONST(id, loc);
+ return NEW_CONST(id, loc);
case ID_CLASS:
- return NEW_CVAR(id, loc);
+ return NEW_CVAR(id, loc);
}
compile_error(p, "identifier %"PRIsVALUE" is not valid to get", rb_id2str(id));
return 0;
}
-static rb_node_opt_arg_t *
-opt_arg_append(rb_node_opt_arg_t *opt_list, rb_node_opt_arg_t *opt)
+static NODE *
+opt_arg_append(NODE *opt_list, NODE *opt)
{
- rb_node_opt_arg_t *opts = opt_list;
- RNODE(opts)->nd_loc.end_pos = RNODE(opt)->nd_loc.end_pos;
+ NODE *opts = opt_list;
+ opts->nd_loc.end_pos = opt->nd_loc.end_pos;
while (opts->nd_next) {
- opts = opts->nd_next;
- RNODE(opts)->nd_loc.end_pos = RNODE(opt)->nd_loc.end_pos;
+ opts = opts->nd_next;
+ opts->nd_loc.end_pos = opt->nd_loc.end_pos;
}
opts->nd_next = opt;
return opt_list;
}
-static rb_node_kw_arg_t *
-kwd_append(rb_node_kw_arg_t *kwlist, rb_node_kw_arg_t *kw)
+static NODE *
+kwd_append(NODE *kwlist, NODE *kw)
{
if (kwlist) {
- /* Assume rb_node_kw_arg_t and rb_node_opt_arg_t has same structure */
- opt_arg_append(RNODE_OPT_ARG(kwlist), RNODE_OPT_ARG(kw));
+ opt_arg_append(kwlist, kw);
}
return kwlist;
}
@@ -13116,34 +11119,7 @@ kwd_append(rb_node_kw_arg_t *kwlist, rb_node_kw_arg_t *kw)
static NODE *
new_defined(struct parser_params *p, NODE *expr, const YYLTYPE *loc)
{
- NODE *n = expr;
- while (n) {
- if (nd_type_p(n, NODE_BEGIN)) {
- n = RNODE_BEGIN(n)->nd_body;
- }
- else if (nd_type_p(n, NODE_BLOCK) && RNODE_BLOCK(n)->nd_end == n) {
- n = RNODE_BLOCK(n)->nd_head;
- }
- else {
- break;
- }
- }
- return NEW_DEFINED(n, loc);
-}
-
-static NODE*
-str_to_sym_node(struct parser_params *p, NODE *node, const YYLTYPE *loc)
-{
- VALUE lit;
- rb_parser_string_t *str = RNODE_STR(node)->string;
- if (rb_parser_enc_str_coderange(p, str) == RB_PARSER_ENC_CODERANGE_BROKEN) {
- yyerror1(loc, "invalid symbol");
- lit = STR_NEW0();
- }
- else {
- lit = rb_str_new_parser_string(str);
- }
- return NEW_SYM(lit, loc);
+ return NEW_DEFINED(remove_begin_all(expr), loc);
}
static NODE*
@@ -13152,13 +11128,14 @@ symbol_append(struct parser_params *p, NODE *symbols, NODE *symbol)
enum node_type type = nd_type(symbol);
switch (type) {
case NODE_DSTR:
- nd_set_type(symbol, NODE_DSYM);
- break;
+ nd_set_type(symbol, NODE_DSYM);
+ break;
case NODE_STR:
- symbol = str_to_sym_node(p, symbol, &RNODE(symbol)->nd_loc);
- break;
+ nd_set_type(symbol, NODE_LIT);
+ RB_OBJ_WRITTEN(p->ast, Qnil, symbol->nd_lit = rb_str_intern(symbol->nd_lit));
+ break;
default:
- compile_error(p, "unexpected node as symbol: %s", parser_node_name(type));
+ compile_error(p, "unexpected node as symbol: %s", ruby_node_name(type));
}
return list_append(p, symbols, symbol);
}
@@ -13166,175 +11143,180 @@ symbol_append(struct parser_params *p, NODE *symbols, NODE *symbol)
static NODE *
new_regexp(struct parser_params *p, NODE *node, int options, const YYLTYPE *loc)
{
- struct RNode_LIST *list;
- NODE *prev;
+ NODE *list, *prev;
+ VALUE lit;
if (!node) {
- /* Check string is valid regex */
- rb_parser_string_t *str = STRING_NEW0();
- reg_compile(p, str, options);
- node = NEW_REGX(str, options, loc);
+ node = NEW_LIT(reg_compile(p, STR_NEW0(), options), loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, node->nd_lit);
return node;
}
switch (nd_type(node)) {
case NODE_STR:
- {
- /* Check string is valid regex */
- reg_compile(p, RNODE_STR(node)->string, options);
- node = str2regx(p, node, options);
- }
- break;
+ {
+ VALUE src = node->nd_lit;
+ nd_set_type(node, NODE_LIT);
+ nd_set_loc(node, loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, node->nd_lit = reg_compile(p, src, options));
+ }
+ break;
default:
- node = NEW_DSTR0(STRING_NEW0(), 1, NEW_LIST(node, loc), loc);
- /* fall through */
+ lit = STR_NEW0();
+ node = NEW_NODE(NODE_DSTR, lit, 1, NEW_LIST(node, loc), loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, lit);
+ /* fall through */
case NODE_DSTR:
- nd_set_type(node, NODE_DREGX);
- nd_set_loc(node, loc);
- rb_node_dregx_t *const dreg = RNODE_DREGX(node);
- dreg->as.nd_cflag = options & RE_OPTION_MASK;
- if (dreg->string) reg_fragment_check(p, dreg->string, options);
- prev = node;
- for (list = dreg->nd_next; list; list = RNODE_LIST(list->nd_next)) {
- NODE *frag = list->nd_head;
- enum node_type type = nd_type(frag);
- if (type == NODE_STR || (type == NODE_DSTR && !RNODE_DSTR(frag)->nd_next)) {
- rb_parser_string_t *tail = RNODE_STR(frag)->string;
- if (reg_fragment_check(p, tail, options) && prev && RNODE_DREGX(prev)->string) {
- rb_parser_string_t *lit = prev == node ? dreg->string : RNODE_STR(RNODE_LIST(prev)->nd_head)->string;
- if (!literal_concat0(p, lit, tail)) {
- return NEW_NIL(loc); /* dummy node on error */
- }
- rb_parser_str_resize(p, tail, 0);
- RNODE_LIST(prev)->nd_next = list->nd_next;
- rb_discard_node(p, list->nd_head);
- rb_discard_node(p, (NODE *)list);
- list = RNODE_LIST(prev);
- }
- else {
- prev = (NODE *)list;
- }
- }
- else {
- prev = 0;
- }
- }
- if (!dreg->nd_next) {
- /* Check string is valid regex */
- reg_compile(p, dreg->string, options);
- }
- if (options & RE_OPTION_ONCE) {
- node = NEW_ONCE(node, loc);
- }
- break;
+ nd_set_type(node, NODE_DREGX);
+ nd_set_loc(node, loc);
+ node->nd_cflag = options & RE_OPTION_MASK;
+ if (!NIL_P(node->nd_lit)) reg_fragment_check(p, node->nd_lit, options);
+ for (list = (prev = node)->nd_next; list; list = list->nd_next) {
+ NODE *frag = list->nd_head;
+ enum node_type type = nd_type(frag);
+ if (type == NODE_STR || (type == NODE_DSTR && !frag->nd_next)) {
+ VALUE tail = frag->nd_lit;
+ if (reg_fragment_check(p, tail, options) && prev && !NIL_P(prev->nd_lit)) {
+ VALUE lit = prev == node ? prev->nd_lit : prev->nd_head->nd_lit;
+ if (!literal_concat0(p, lit, tail)) {
+ return NEW_NIL(loc); /* dummy node on error */
+ }
+ rb_str_resize(tail, 0);
+ prev->nd_next = list->nd_next;
+ rb_discard_node(p, list->nd_head);
+ rb_discard_node(p, list);
+ list = prev;
+ }
+ else {
+ prev = list;
+ }
+ }
+ else {
+ prev = 0;
+ }
+ }
+ if (!node->nd_next) {
+ VALUE src = node->nd_lit;
+ nd_set_type(node, NODE_LIT);
+ RB_OBJ_WRITTEN(p->ast, Qnil, node->nd_lit = reg_compile(p, src, options));
+ }
+ if (options & RE_OPTION_ONCE) {
+ node = NEW_NODE(NODE_ONCE, 0, node, 0, loc);
+ }
+ break;
}
return node;
}
-static rb_node_kw_arg_t *
+static NODE *
new_kw_arg(struct parser_params *p, NODE *k, const YYLTYPE *loc)
{
if (!k) return 0;
- return NEW_KW_ARG((k), loc);
+ return NEW_KW_ARG(0, (k), loc);
}
static NODE *
new_xstring(struct parser_params *p, NODE *node, const YYLTYPE *loc)
{
if (!node) {
- NODE *xstr = NEW_XSTR(STRING_NEW0(), loc);
- return xstr;
+ VALUE lit = STR_NEW0();
+ NODE *xstr = NEW_XSTR(lit, loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, lit);
+ return xstr;
}
switch (nd_type(node)) {
case NODE_STR:
- nd_set_type(node, NODE_XSTR);
- nd_set_loc(node, loc);
- break;
+ nd_set_type(node, NODE_XSTR);
+ nd_set_loc(node, loc);
+ break;
case NODE_DSTR:
- nd_set_type(node, NODE_DXSTR);
- nd_set_loc(node, loc);
- break;
+ nd_set_type(node, NODE_DXSTR);
+ nd_set_loc(node, loc);
+ break;
default:
- node = NEW_DXSTR(0, 1, NEW_LIST(node, loc), loc);
- break;
+ node = NEW_NODE(NODE_DXSTR, Qnil, 1, NEW_LIST(node, loc), loc);
+ break;
}
return node;
}
-static const
-struct st_hash_type literal_type = {
- literal_cmp,
- literal_hash,
-};
-
-static int nd_type_st_key_enable_p(NODE *node);
-
static void
check_literal_when(struct parser_params *p, NODE *arg, const YYLTYPE *loc)
{
- /* See https://bugs.ruby-lang.org/issues/20331 for discussion about what is warned. */
+ VALUE lit;
+
if (!arg || !p->case_labels) return;
- if (!nd_type_st_key_enable_p(arg)) return;
- if (p->case_labels == CHECK_LITERAL_WHEN) {
- p->case_labels = st_init_table(&literal_type);
+ lit = rb_node_case_when_optimizable_literal(arg);
+ if (UNDEF_P(lit)) return;
+ if (nd_type_p(arg, NODE_STR)) {
+ RB_OBJ_WRITTEN(p->ast, Qnil, arg->nd_lit = lit);
+ }
+
+ if (NIL_P(p->case_labels)) {
+ p->case_labels = rb_obj_hide(rb_hash_new());
}
else {
- st_data_t line;
- if (st_lookup(p->case_labels, (st_data_t)arg, &line)) {
- rb_warning2("'when' clause on line %d duplicates 'when' clause on line %d and is ignored",
- WARN_I((int)nd_line(arg)), WARN_I((int)line));
- return;
- }
+ VALUE line = rb_hash_lookup(p->case_labels, lit);
+ if (!NIL_P(line)) {
+ rb_warning1("duplicated `when' clause with line %d is ignored",
+ WARN_IVAL(line));
+ return;
+ }
}
- st_insert(p->case_labels, (st_data_t)arg, (st_data_t)p->ruby_sourceline);
+ rb_hash_aset(p->case_labels, lit, INT2NUM(p->ruby_sourceline));
}
-#ifdef RIPPER
+#else /* !RIPPER */
static int
id_is_var(struct parser_params *p, ID id)
{
if (is_notop_id(id)) {
- switch (id & ID_SCOPE_MASK) {
- case ID_GLOBAL: case ID_INSTANCE: case ID_CONST: case ID_CLASS:
- return 1;
- case ID_LOCAL:
- if (dyna_in_block(p)) {
- if (NUMPARAM_ID_P(id) || dvar_defined(p, id)) return 1;
- }
- if (local_id(p, id)) return 1;
- /* method call without arguments */
- return 0;
- }
+ switch (id & ID_SCOPE_MASK) {
+ case ID_GLOBAL: case ID_INSTANCE: case ID_CONST: case ID_CLASS:
+ return 1;
+ case ID_LOCAL:
+ if (dyna_in_block(p)) {
+ if (NUMPARAM_ID_P(id) || dvar_defined(p, id)) return 1;
+ }
+ if (local_id(p, id)) return 1;
+ /* method call without arguments */
+ return 0;
+ }
}
compile_error(p, "identifier %"PRIsVALUE" is not valid to get", rb_id2str(id));
return 0;
}
-#endif
+
+static VALUE
+new_regexp(struct parser_params *p, VALUE re, VALUE opt, const YYLTYPE *loc)
+{
+ VALUE src = 0, err;
+ int options = 0;
+ if (ripper_is_node_yylval(re)) {
+ src = RNODE(re)->nd_cval;
+ re = RNODE(re)->nd_rval;
+ }
+ if (ripper_is_node_yylval(opt)) {
+ options = (int)RNODE(opt)->nd_tag;
+ opt = RNODE(opt)->nd_rval;
+ }
+ if (src && NIL_P(parser_reg_compile(p, src, options, &err))) {
+ compile_error(p, "%"PRIsVALUE, err);
+ }
+ return dispatch2(regexp_literal, re, opt);
+}
+#endif /* !RIPPER */
static inline enum lex_state_e
parser_set_lex_state(struct parser_params *p, enum lex_state_e ls, int line)
{
if (p->debug) {
- ls = rb_parser_trace_lex_state(p, p->lex.state, ls, line);
+ ls = rb_parser_trace_lex_state(p, p->lex.state, ls, line);
}
return p->lex.state = ls;
}
#ifndef RIPPER
-static void
-flush_debug_buffer(struct parser_params *p, VALUE out, VALUE str)
-{
- VALUE mesg = p->debug_buffer;
-
- if (!NIL_P(mesg) && RSTRING_LEN(mesg)) {
- p->debug_buffer = Qnil;
- rb_io_puts(1, &mesg, out);
- }
- if (!NIL_P(str) && RSTRING_LEN(str)) {
- rb_io_write(p->debug_output, str);
- }
-}
-
static const char rb_parser_lex_state_names[][8] = {
"BEG", "END", "ENDARG", "ENDFN", "ARG",
"CMDARG", "MID", "FNAME", "DOT", "CLASS",
@@ -13342,66 +11324,80 @@ static const char rb_parser_lex_state_names[][8] = {
};
static VALUE
-append_lex_state_name(struct parser_params *p, enum lex_state_e state, VALUE buf)
+append_lex_state_name(enum lex_state_e state, VALUE buf)
{
int i, sep = 0;
unsigned int mask = 1;
static const char none[] = "NONE";
for (i = 0; i < EXPR_MAX_STATE; ++i, mask <<= 1) {
- if ((unsigned)state & mask) {
- if (sep) {
- rb_str_cat(buf, "|", 1);
- }
- sep = 1;
- rb_str_cat_cstr(buf, rb_parser_lex_state_names[i]);
- }
+ if ((unsigned)state & mask) {
+ if (sep) {
+ rb_str_cat(buf, "|", 1);
+ }
+ sep = 1;
+ rb_str_cat_cstr(buf, rb_parser_lex_state_names[i]);
+ }
}
if (!sep) {
- rb_str_cat(buf, none, sizeof(none)-1);
+ rb_str_cat(buf, none, sizeof(none)-1);
}
return buf;
}
+static void
+flush_debug_buffer(struct parser_params *p, VALUE out, VALUE str)
+{
+ VALUE mesg = p->debug_buffer;
+
+ if (!NIL_P(mesg) && RSTRING_LEN(mesg)) {
+ p->debug_buffer = Qnil;
+ rb_io_puts(1, &mesg, out);
+ }
+ if (!NIL_P(str) && RSTRING_LEN(str)) {
+ rb_io_write(p->debug_output, str);
+ }
+}
+
enum lex_state_e
rb_parser_trace_lex_state(struct parser_params *p, enum lex_state_e from,
- enum lex_state_e to, int line)
+ enum lex_state_e to, int line)
{
VALUE mesg;
mesg = rb_str_new_cstr("lex_state: ");
- append_lex_state_name(p, from, mesg);
+ append_lex_state_name(from, mesg);
rb_str_cat_cstr(mesg, " -> ");
- append_lex_state_name(p, to, mesg);
+ append_lex_state_name(to, mesg);
rb_str_catf(mesg, " at line %d\n", line);
flush_debug_buffer(p, p->debug_output, mesg);
return to;
}
VALUE
-rb_parser_lex_state_name(struct parser_params *p, enum lex_state_e state)
+rb_parser_lex_state_name(enum lex_state_e state)
{
- return rb_str_to_interned_str(append_lex_state_name(p, state, rb_str_new(0, 0)));
+ return rb_fstring(append_lex_state_name(state, rb_str_new(0, 0)));
}
static void
-append_bitstack_value(struct parser_params *p, stack_type stack, VALUE mesg)
+append_bitstack_value(stack_type stack, VALUE mesg)
{
if (stack == 0) {
- rb_str_cat_cstr(mesg, "0");
+ rb_str_cat_cstr(mesg, "0");
}
else {
- stack_type mask = (stack_type)1U << (CHAR_BIT * sizeof(stack_type) - 1);
- for (; mask && !(stack & mask); mask >>= 1) continue;
- for (; mask; mask >>= 1) rb_str_cat(mesg, stack & mask ? "1" : "0", 1);
+ stack_type mask = (stack_type)1U << (CHAR_BIT * sizeof(stack_type) - 1);
+ for (; mask && !(stack & mask); mask >>= 1) continue;
+ for (; mask; mask >>= 1) rb_str_cat(mesg, stack & mask ? "1" : "0", 1);
}
}
void
rb_parser_show_bitstack(struct parser_params *p, stack_type stack,
- const char *name, int line)
+ const char *name, int line)
{
VALUE mesg = rb_sprintf("%s: ", name);
- append_bitstack_value(p, stack, mesg);
+ append_bitstack_value(stack, mesg);
rb_str_catf(mesg, " at line %d\n", line);
flush_debug_buffer(p, p->debug_output, mesg);
}
@@ -13419,16 +11415,16 @@ rb_parser_fatal(struct parser_params *p, const char *fmt, ...)
RB_GC_GUARD(mesg);
mesg = rb_str_new(0, 0);
- append_lex_state_name(p, p->lex.state, mesg);
+ append_lex_state_name(p->lex.state, mesg);
compile_error(p, "lex.state: %"PRIsVALUE, mesg);
rb_str_resize(mesg, 0);
- append_bitstack_value(p, p->cond_stack, mesg);
+ append_bitstack_value(p->cond_stack, mesg);
compile_error(p, "cond_stack: %"PRIsVALUE, mesg);
rb_str_resize(mesg, 0);
- append_bitstack_value(p, p->cmdarg_stack, mesg);
+ append_bitstack_value(p->cmdarg_stack, mesg);
compile_error(p, "cmdarg_stack: %"PRIsVALUE, mesg);
if (p->debug_output == rb_ractor_stdout())
- p->debug_output = rb_ractor_stderr();
+ p->debug_output = rb_ractor_stderr();
p->debug = TRUE;
}
@@ -13447,7 +11443,7 @@ rb_parser_set_location_from_strterm_heredoc(struct parser_params *p, rb_strterm_
{
int sourceline = here->sourceline;
int beg_pos = (int)here->offset - here->quote
- - (rb_strlen_lit("<<-") - !(here->func & STR_FUNC_INDENT));
+ - (rb_strlen_lit("<<-") - !(here->func & STR_FUNC_INDENT));
int end_pos = (int)here->offset + here->length + here->quote;
return rb_parser_set_pos(yylloc, sourceline, beg_pos, end_pos);
@@ -13506,59 +11502,60 @@ assignable0(struct parser_params *p, ID id, const char **err)
if (!id) return -1;
switch (id) {
case keyword_self:
- *err = "Can't change the value of self";
- return -1;
+ *err = "Can't change the value of self";
+ return -1;
case keyword_nil:
- *err = "Can't assign to nil";
- return -1;
+ *err = "Can't assign to nil";
+ return -1;
case keyword_true:
- *err = "Can't assign to true";
- return -1;
+ *err = "Can't assign to true";
+ return -1;
case keyword_false:
- *err = "Can't assign to false";
- return -1;
+ *err = "Can't assign to false";
+ return -1;
case keyword__FILE__:
- *err = "Can't assign to __FILE__";
- return -1;
+ *err = "Can't assign to __FILE__";
+ return -1;
case keyword__LINE__:
- *err = "Can't assign to __LINE__";
- return -1;
+ *err = "Can't assign to __LINE__";
+ return -1;
case keyword__ENCODING__:
- *err = "Can't assign to __ENCODING__";
- return -1;
+ *err = "Can't assign to __ENCODING__";
+ return -1;
}
switch (id_type(id)) {
case ID_LOCAL:
- if (dyna_in_block(p)) {
- if (p->max_numparam > NO_PARAM && NUMPARAM_ID_P(id)) {
- compile_error(p, "Can't assign to numbered parameter _%d",
- NUMPARAM_ID_TO_IDX(id));
- return -1;
- }
- if (dvar_curr(p, id)) return NODE_DASGN;
- if (dvar_defined(p, id)) return NODE_DASGN;
- if (local_id(p, id)) return NODE_LASGN;
- dyna_var(p, id);
- return NODE_DASGN;
- }
- else {
- if (!local_id(p, id)) local_var(p, id);
- return NODE_LASGN;
- }
- break;
+ if (dyna_in_block(p)) {
+ if (p->max_numparam > NO_PARAM && NUMPARAM_ID_P(id)) {
+ compile_error(p, "Can't assign to numbered parameter _%d",
+ NUMPARAM_ID_TO_IDX(id));
+ return -1;
+ }
+ if (dvar_curr(p, id)) return NODE_DASGN;
+ if (dvar_defined(p, id)) return NODE_DASGN;
+ if (local_id(p, id)) return NODE_LASGN;
+ dyna_var(p, id);
+ return NODE_DASGN;
+ }
+ else {
+ if (!local_id(p, id)) local_var(p, id);
+ return NODE_LASGN;
+ }
+ break;
case ID_GLOBAL: return NODE_GASGN;
case ID_INSTANCE: return NODE_IASGN;
case ID_CONST:
- if (!p->ctxt.in_def) return NODE_CDECL;
- *err = "dynamic constant assignment";
- return -1;
+ if (!p->ctxt.in_def) return NODE_CDECL;
+ *err = "dynamic constant assignment";
+ return -1;
case ID_CLASS: return NODE_CVASGN;
default:
- compile_error(p, "identifier %"PRIsVALUE" is not valid to set", rb_id2str(id));
+ compile_error(p, "identifier %"PRIsVALUE" is not valid to set", rb_id2str(id));
}
return -1;
}
+#ifndef RIPPER
static NODE*
assignable(struct parser_params *p, ID id, NODE *val, const YYLTYPE *loc)
{
@@ -13569,20 +11566,25 @@ assignable(struct parser_params *p, ID id, NODE *val, const YYLTYPE *loc)
case NODE_LASGN: return NEW_LASGN(id, val, loc);
case NODE_GASGN: return NEW_GASGN(id, val, loc);
case NODE_IASGN: return NEW_IASGN(id, val, loc);
- case NODE_CDECL: return NEW_CDECL(id, val, 0, p->ctxt.shareable_constant_value, loc);
+ case NODE_CDECL: return NEW_CDECL(id, val, 0, loc);
case NODE_CVASGN: return NEW_CVASGN(id, val, loc);
}
-/* TODO: FIXME */
-#ifndef RIPPER
if (err) yyerror1(loc, err);
+ return NEW_BEGIN(0, loc);
+}
#else
- if (err) set_value(assign_error(p, err, p->s_lvalue));
-#endif
- return NEW_ERROR(loc);
+static VALUE
+assignable(struct parser_params *p, VALUE lhs)
+{
+ const char *err = 0;
+ assignable0(p, get_id(lhs), &err);
+ if (err) lhs = assign_error(p, err, lhs);
+ return lhs;
}
+#endif
static int
-is_private_local_id(struct parser_params *p, ID name)
+is_private_local_id(ID name)
{
VALUE s;
if (name == idUScore) return 1;
@@ -13596,23 +11598,23 @@ static int
shadowing_lvar_0(struct parser_params *p, ID name)
{
if (dyna_in_block(p)) {
- if (dvar_curr(p, name)) {
- if (is_private_local_id(p, name)) return 1;
- yyerror0("duplicated argument name");
- }
- else if (dvar_defined(p, name) || local_id(p, name)) {
- vtable_add(p->lvtbl->vars, name);
- if (p->lvtbl->used) {
- vtable_add(p->lvtbl->used, (ID)p->ruby_sourceline | LVAR_USED);
- }
- return 0;
- }
+ if (dvar_curr(p, name)) {
+ if (is_private_local_id(name)) return 1;
+ yyerror0("duplicated argument name");
+ }
+ else if (dvar_defined(p, name) || local_id(p, name)) {
+ vtable_add(p->lvtbl->vars, name);
+ if (p->lvtbl->used) {
+ vtable_add(p->lvtbl->used, (ID)p->ruby_sourceline | LVAR_USED);
+ }
+ return 0;
+ }
}
else {
- if (local_id(p, name)) {
- if (is_private_local_id(p, name)) return 1;
- yyerror0("duplicated argument name");
- }
+ if (local_id(p, name)) {
+ if (is_private_local_id(name)) return 1;
+ yyerror0("duplicated argument name");
+ }
}
return 1;
}
@@ -13629,50 +11631,18 @@ new_bv(struct parser_params *p, ID name)
{
if (!name) return;
if (!is_local_id(name)) {
- compile_error(p, "invalid local variable - %"PRIsVALUE,
- rb_id2str(name));
- return;
+ compile_error(p, "invalid local variable - %"PRIsVALUE,
+ rb_id2str(name));
+ return;
}
if (!shadowing_lvar_0(p, name)) return;
dyna_var(p, name);
- ID *vidp = 0;
- if (dvar_defined_ref(p, name, &vidp)) {
- if (vidp) *vidp |= LVAR_USED;
- }
-}
-
-static void
-aryset_check(struct parser_params *p, NODE *args)
-{
- NODE *block = 0, *kwds = 0;
- if (args && nd_type_p(args, NODE_BLOCK_PASS)) {
- block = RNODE_BLOCK_PASS(args)->nd_body;
- args = RNODE_BLOCK_PASS(args)->nd_head;
- }
- if (args && nd_type_p(args, NODE_ARGSCAT)) {
- args = RNODE_ARGSCAT(args)->nd_body;
- }
- if (args && nd_type_p(args, NODE_ARGSPUSH)) {
- kwds = RNODE_ARGSPUSH(args)->nd_body;
- }
- else {
- for (NODE *next = args; next && nd_type_p(next, NODE_LIST);
- next = RNODE_LIST(next)->nd_next) {
- kwds = RNODE_LIST(next)->nd_head;
- }
- }
- if (kwds && nd_type_p(kwds, NODE_HASH) && !RNODE_HASH(kwds)->nd_brace) {
- yyerror1(&kwds->nd_loc, "keyword arg given in index assignment");
- }
- if (block) {
- yyerror1(&block->nd_loc, "block arg given in index assignment");
- }
}
+#ifndef RIPPER
static NODE *
aryset(struct parser_params *p, NODE *recv, NODE *idx, const YYLTYPE *loc)
{
- aryset_check(p, idx);
return NEW_ATTRASGN(recv, tASET, idx, loc);
}
@@ -13680,7 +11650,7 @@ static void
block_dup_check(struct parser_params *p, NODE *node1, NODE *node2)
{
if (node2 && node1 && nd_type_p(node1, NODE_BLOCK_PASS)) {
- compile_error(p, "both block arg and actual block given");
+ compile_error(p, "both block arg and actual block given");
}
}
@@ -13691,44 +11661,49 @@ attrset(struct parser_params *p, NODE *recv, ID atype, ID id, const YYLTYPE *loc
return NEW_ATTRASGN(recv, id, 0, loc);
}
-static VALUE
+static void
rb_backref_error(struct parser_params *p, NODE *node)
{
-#ifndef RIPPER
-# define ERR(...) (compile_error(p, __VA_ARGS__), Qtrue)
-#else
-# define ERR(...) rb_sprintf(__VA_ARGS__)
-#endif
switch (nd_type(node)) {
case NODE_NTH_REF:
- return ERR("Can't set variable $%ld", RNODE_NTH_REF(node)->nd_nth);
+ compile_error(p, "Can't set variable $%ld", node->nd_nth);
+ break;
case NODE_BACK_REF:
- return ERR("Can't set variable $%c", (int)RNODE_BACK_REF(node)->nd_nth);
+ compile_error(p, "Can't set variable $%c", (int)node->nd_nth);
+ break;
}
-#undef ERR
- UNREACHABLE_RETURN(Qfalse); /* only called on syntax error */
}
+#else
+static VALUE
+backref_error(struct parser_params *p, NODE *ref, VALUE expr)
+{
+ VALUE mesg = rb_str_new_cstr("Can't set variable ");
+ rb_str_append(mesg, ref->nd_cval);
+ return dispatch2(assign_error, mesg, expr);
+}
+#endif
+#ifndef RIPPER
static NODE *
arg_append(struct parser_params *p, NODE *node1, NODE *node2, const YYLTYPE *loc)
{
if (!node1) return NEW_LIST(node2, &node2->nd_loc);
switch (nd_type(node1)) {
case NODE_LIST:
- return list_append(p, node1, node2);
+ return list_append(p, node1, node2);
case NODE_BLOCK_PASS:
- RNODE_BLOCK_PASS(node1)->nd_head = arg_append(p, RNODE_BLOCK_PASS(node1)->nd_head, node2, loc);
- node1->nd_loc.end_pos = RNODE_BLOCK_PASS(node1)->nd_head->nd_loc.end_pos;
- return node1;
+ node1->nd_head = arg_append(p, node1->nd_head, node2, loc);
+ node1->nd_loc.end_pos = node1->nd_head->nd_loc.end_pos;
+ return node1;
case NODE_ARGSPUSH:
- RNODE_ARGSPUSH(node1)->nd_body = list_append(p, NEW_LIST(RNODE_ARGSPUSH(node1)->nd_body, &RNODE_ARGSPUSH(node1)->nd_body->nd_loc), node2);
- node1->nd_loc.end_pos = RNODE_ARGSPUSH(node1)->nd_body->nd_loc.end_pos;
- nd_set_type(node1, NODE_ARGSCAT);
- return node1;
+ node1->nd_body = list_append(p, NEW_LIST(node1->nd_body, &node1->nd_body->nd_loc), node2);
+ node1->nd_loc.end_pos = node1->nd_body->nd_loc.end_pos;
+ nd_set_type(node1, NODE_ARGSCAT);
+ return node1;
case NODE_ARGSCAT:
- if (!nd_type_p(RNODE_ARGSCAT(node1)->nd_body, NODE_LIST)) break;
- RNODE_ARGSCAT(node1)->nd_body = list_append(p, RNODE_ARGSCAT(node1)->nd_body, node2);
- node1->nd_loc.end_pos = RNODE_ARGSCAT(node1)->nd_body->nd_loc.end_pos;
+ if (!nd_type_p(node1->nd_body, NODE_LIST)) break;
+ node1->nd_body = list_append(p, node1->nd_body, node2);
+ node1->nd_loc.end_pos = node1->nd_body->nd_loc.end_pos;
return node1;
}
return NEW_ARGSPUSH(node1, node2, loc);
@@ -13740,21 +11715,21 @@ arg_concat(struct parser_params *p, NODE *node1, NODE *node2, const YYLTYPE *loc
if (!node2) return node1;
switch (nd_type(node1)) {
case NODE_BLOCK_PASS:
- if (RNODE_BLOCK_PASS(node1)->nd_head)
- RNODE_BLOCK_PASS(node1)->nd_head = arg_concat(p, RNODE_BLOCK_PASS(node1)->nd_head, node2, loc);
- else
- RNODE_LIST(node1)->nd_head = NEW_LIST(node2, loc);
- return node1;
+ if (node1->nd_head)
+ node1->nd_head = arg_concat(p, node1->nd_head, node2, loc);
+ else
+ node1->nd_head = NEW_LIST(node2, loc);
+ return node1;
case NODE_ARGSPUSH:
- if (!nd_type_p(node2, NODE_LIST)) break;
- RNODE_ARGSPUSH(node1)->nd_body = list_concat(NEW_LIST(RNODE_ARGSPUSH(node1)->nd_body, loc), node2);
- nd_set_type(node1, NODE_ARGSCAT);
- return node1;
+ if (!nd_type_p(node2, NODE_LIST)) break;
+ node1->nd_body = list_concat(NEW_LIST(node1->nd_body, loc), node2);
+ nd_set_type(node1, NODE_ARGSCAT);
+ return node1;
case NODE_ARGSCAT:
- if (!nd_type_p(node2, NODE_LIST) ||
- !nd_type_p(RNODE_ARGSCAT(node1)->nd_body, NODE_LIST)) break;
- RNODE_ARGSCAT(node1)->nd_body = list_concat(RNODE_ARGSCAT(node1)->nd_body, node2);
- return node1;
+ if (!nd_type_p(node2, NODE_LIST) ||
+ !nd_type_p(node1->nd_body, NODE_LIST)) break;
+ node1->nd_body = list_concat(node1->nd_body, node2);
+ return node1;
}
return NEW_ARGSCAT(node1, node2, loc);
}
@@ -13764,7 +11739,7 @@ last_arg_append(struct parser_params *p, NODE *args, NODE *last_arg, const YYLTY
{
NODE *n1;
if ((n1 = splat_array(args)) != 0) {
- return list_append(p, n1, last_arg);
+ return list_append(p, n1, last_arg);
}
return arg_append(p, args, last_arg, loc);
}
@@ -13774,7 +11749,7 @@ rest_arg_append(struct parser_params *p, NODE *args, NODE *rest_arg, const YYLTY
{
NODE *n1;
if ((nd_type_p(rest_arg, NODE_LIST)) && (n1 = splat_array(args)) != 0) {
- return list_concat(n1, rest_arg);
+ return list_concat(n1, rest_arg);
}
return arg_concat(p, args, rest_arg, loc);
}
@@ -13782,7 +11757,7 @@ rest_arg_append(struct parser_params *p, NODE *args, NODE *rest_arg, const YYLTY
static NODE *
splat_array(NODE* node)
{
- if (nd_type_p(node, NODE_SPLAT)) node = RNODE_SPLAT(node)->nd_head;
+ if (nd_type_p(node, NODE_SPLAT)) node = node->nd_head;
if (nd_type_p(node, NODE_LIST)) return node;
return 0;
}
@@ -13794,27 +11769,271 @@ mark_lvar_used(struct parser_params *p, NODE *rhs)
if (!rhs) return;
switch (nd_type(rhs)) {
case NODE_LASGN:
- if (local_id_ref(p, RNODE_LASGN(rhs)->nd_vid, &vidp)) {
- if (vidp) *vidp |= LVAR_USED;
- }
- break;
+ if (local_id_ref(p, rhs->nd_vid, &vidp)) {
+ if (vidp) *vidp |= LVAR_USED;
+ }
+ break;
case NODE_DASGN:
- if (dvar_defined_ref(p, RNODE_DASGN(rhs)->nd_vid, &vidp)) {
- if (vidp) *vidp |= LVAR_USED;
- }
- break;
+ if (dvar_defined_ref(p, rhs->nd_vid, &vidp)) {
+ if (vidp) *vidp |= LVAR_USED;
+ }
+ break;
#if 0
case NODE_MASGN:
- for (rhs = rhs->nd_head; rhs; rhs = rhs->nd_next) {
- mark_lvar_used(p, rhs->nd_head);
- }
- break;
+ for (rhs = rhs->nd_head; rhs; rhs = rhs->nd_next) {
+ mark_lvar_used(p, rhs->nd_head);
+ }
+ break;
#endif
}
}
+static NODE *
+const_decl_path(struct parser_params *p, NODE **dest)
+{
+ NODE *n = *dest;
+ if (!nd_type_p(n, NODE_CALL)) {
+ const YYLTYPE *loc = &n->nd_loc;
+ VALUE path;
+ if (n->nd_vid) {
+ path = rb_id2str(n->nd_vid);
+ }
+ else {
+ n = n->nd_else;
+ path = rb_ary_new();
+ for (; n && nd_type_p(n, NODE_COLON2); n = n->nd_head) {
+ rb_ary_push(path, rb_id2str(n->nd_mid));
+ }
+ if (n && nd_type_p(n, NODE_CONST)) {
+ // Const::Name
+ rb_ary_push(path, rb_id2str(n->nd_vid));
+ }
+ else if (n && nd_type_p(n, NODE_COLON3)) {
+ // ::Const::Name
+ rb_ary_push(path, rb_str_new(0, 0));
+ }
+ else {
+ // expression::Name
+ rb_ary_push(path, rb_str_new_cstr("..."));
+ }
+ path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
+ path = rb_fstring(path);
+ }
+ *dest = n = NEW_LIT(path, loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, n->nd_lit);
+ }
+ return n;
+}
+
+extern VALUE rb_mRubyVMFrozenCore;
+
+static NODE *
+make_shareable_node(struct parser_params *p, NODE *value, bool copy, const YYLTYPE *loc)
+{
+ NODE *fcore = NEW_LIT(rb_mRubyVMFrozenCore, loc);
+
+ if (copy) {
+ return NEW_CALL(fcore, rb_intern("make_shareable_copy"),
+ NEW_LIST(value, loc), loc);
+ }
+ else {
+ return NEW_CALL(fcore, rb_intern("make_shareable"),
+ NEW_LIST(value, loc), loc);
+ }
+}
+
+static NODE *
+ensure_shareable_node(struct parser_params *p, NODE **dest, NODE *value, const YYLTYPE *loc)
+{
+ NODE *fcore = NEW_LIT(rb_mRubyVMFrozenCore, loc);
+ NODE *args = NEW_LIST(value, loc);
+ args = list_append(p, args, const_decl_path(p, dest));
+ return NEW_CALL(fcore, rb_intern("ensure_shareable"), args, loc);
+}
+
static int is_static_content(NODE *node);
+static VALUE
+shareable_literal_value(NODE *node)
+{
+ if (!node) return Qnil;
+ enum node_type type = nd_type(node);
+ switch (type) {
+ case NODE_TRUE:
+ return Qtrue;
+ case NODE_FALSE:
+ return Qfalse;
+ case NODE_NIL:
+ return Qnil;
+ case NODE_LIT:
+ return node->nd_lit;
+ default:
+ return Qundef;
+ }
+}
+
+#ifndef SHAREABLE_BARE_EXPRESSION
+#define SHAREABLE_BARE_EXPRESSION 1
+#endif
+
+static NODE *
+shareable_literal_constant(struct parser_params *p, enum shareability shareable,
+ NODE **dest, NODE *value, const YYLTYPE *loc, size_t level)
+{
+# define shareable_literal_constant_next(n) \
+ shareable_literal_constant(p, shareable, dest, (n), &(n)->nd_loc, level+1)
+ VALUE lit = Qnil;
+
+ if (!value) return 0;
+ enum node_type type = nd_type(value);
+ switch (type) {
+ case NODE_TRUE:
+ case NODE_FALSE:
+ case NODE_NIL:
+ case NODE_LIT:
+ return value;
+
+ case NODE_DSTR:
+ if (shareable == shareable_literal) {
+ value = NEW_CALL(value, idUMinus, 0, loc);
+ }
+ return value;
+
+ case NODE_STR:
+ lit = rb_fstring(value->nd_lit);
+ nd_set_type(value, NODE_LIT);
+ RB_OBJ_WRITE(p->ast, &value->nd_lit, lit);
+ return value;
+
+ case NODE_ZLIST:
+ lit = rb_ary_new();
+ OBJ_FREEZE_RAW(lit);
+ NODE *n = NEW_LIT(lit, loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, n->nd_lit);
+ return n;
+
+ case NODE_LIST:
+ lit = rb_ary_new();
+ for (NODE *n = value; n; n = n->nd_next) {
+ NODE *elt = n->nd_head;
+ if (elt) {
+ elt = shareable_literal_constant_next(elt);
+ if (elt) {
+ n->nd_head = elt;
+ }
+ else if (RTEST(lit)) {
+ rb_ary_clear(lit);
+ lit = Qfalse;
+ }
+ }
+ if (RTEST(lit)) {
+ VALUE e = shareable_literal_value(elt);
+ if (!UNDEF_P(e)) {
+ rb_ary_push(lit, e);
+ }
+ else {
+ rb_ary_clear(lit);
+ lit = Qnil; /* make shareable at runtime */
+ }
+ }
+ }
+ break;
+
+ case NODE_HASH:
+ if (!value->nd_brace) return 0;
+ lit = rb_hash_new();
+ for (NODE *n = value->nd_head; n; n = n->nd_next->nd_next) {
+ NODE *key = n->nd_head;
+ NODE *val = n->nd_next->nd_head;
+ if (key) {
+ key = shareable_literal_constant_next(key);
+ if (key) {
+ n->nd_head = key;
+ }
+ else if (RTEST(lit)) {
+ rb_hash_clear(lit);
+ lit = Qfalse;
+ }
+ }
+ if (val) {
+ val = shareable_literal_constant_next(val);
+ if (val) {
+ n->nd_next->nd_head = val;
+ }
+ else if (RTEST(lit)) {
+ rb_hash_clear(lit);
+ lit = Qfalse;
+ }
+ }
+ if (RTEST(lit)) {
+ VALUE k = shareable_literal_value(key);
+ VALUE v = shareable_literal_value(val);
+ if (!UNDEF_P(k) && !UNDEF_P(v)) {
+ rb_hash_aset(lit, k, v);
+ }
+ else {
+ rb_hash_clear(lit);
+ lit = Qnil; /* make shareable at runtime */
+ }
+ }
+ }
+ break;
+
+ default:
+ if (shareable == shareable_literal &&
+ (SHAREABLE_BARE_EXPRESSION || level > 0)) {
+ return ensure_shareable_node(p, dest, value, loc);
+ }
+ return 0;
+ }
+
+ /* Array or Hash */
+ if (!lit) return 0;
+ if (NIL_P(lit)) {
+ // if shareable_literal, all elements should have been ensured
+ // as shareable
+ value = make_shareable_node(p, value, false, loc);
+ }
+ else {
+ value = NEW_LIT(rb_ractor_make_shareable(lit), loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, value->nd_lit);
+ }
+
+ return value;
+# undef shareable_literal_constant_next
+}
+
+static NODE *
+shareable_constant_value(struct parser_params *p, enum shareability shareable,
+ NODE *lhs, NODE *value, const YYLTYPE *loc)
+{
+ if (!value) return 0;
+ switch (shareable) {
+ case shareable_none:
+ return value;
+
+ case shareable_literal:
+ {
+ NODE *lit = shareable_literal_constant(p, shareable, &lhs, value, loc, 0);
+ if (lit) return lit;
+ return value;
+ }
+ break;
+
+ case shareable_copy:
+ case shareable_everything:
+ {
+ NODE *lit = shareable_literal_constant(p, shareable, &lhs, value, loc, 0);
+ if (lit) return lit;
+ return make_shareable_node(p, value, shareable == shareable_copy, loc);
+ }
+ break;
+
+ default:
+ UNREACHABLE_RETURN(0);
+ }
+}
+
static NODE *
node_assign(struct parser_params *p, NODE *lhs, NODE *rhs, struct lex_context ctxt, const YYLTYPE *loc)
{
@@ -13822,24 +12041,27 @@ node_assign(struct parser_params *p, NODE *lhs, NODE *rhs, struct lex_context ct
switch (nd_type(lhs)) {
case NODE_CDECL:
+ rhs = shareable_constant_value(p, ctxt.shareable_constant_value, lhs, rhs, loc);
+ /* fallthru */
+
case NODE_GASGN:
case NODE_IASGN:
case NODE_LASGN:
case NODE_DASGN:
case NODE_MASGN:
case NODE_CVASGN:
- set_nd_value(p, lhs, rhs);
- nd_set_loc(lhs, loc);
- break;
+ lhs->nd_value = rhs;
+ nd_set_loc(lhs, loc);
+ break;
case NODE_ATTRASGN:
- RNODE_ATTRASGN(lhs)->nd_args = arg_append(p, RNODE_ATTRASGN(lhs)->nd_args, rhs, loc);
- nd_set_loc(lhs, loc);
- break;
+ lhs->nd_args = arg_append(p, lhs->nd_args, rhs, loc);
+ nd_set_loc(lhs, loc);
+ break;
default:
- /* should not happen */
- break;
+ /* should not happen */
+ break;
}
return lhs;
@@ -13851,103 +12073,70 @@ value_expr_check(struct parser_params *p, NODE *node)
NODE *void_node = 0, *vn;
if (!node) {
- rb_warning0("empty expression");
+ rb_warning0("empty expression");
}
while (node) {
- switch (nd_type(node)) {
- case NODE_ENSURE:
- vn = RNODE_ENSURE(node)->nd_head;
- node = RNODE_ENSURE(node)->nd_ensr;
- /* nd_ensr should not be NULL, check it out next */
- if (vn && (vn = value_expr_check(p, vn))) {
- goto found;
- }
- break;
-
- case NODE_RESCUE:
- /* void only if all children are void */
- vn = RNODE_RESCUE(node)->nd_head;
- if (!vn || !(vn = value_expr_check(p, vn))) return NULL;
- if (!void_node) void_node = vn;
- for (NODE *r = RNODE_RESCUE(node)->nd_resq; r; r = RNODE_RESBODY(r)->nd_next) {
- if (!nd_type_p(r, NODE_RESBODY)) {
- compile_error(p, "unexpected node");
- return NULL;
- }
- if (!(vn = value_expr_check(p, RNODE_RESBODY(r)->nd_body))) {
- void_node = 0;
- break;
- }
- if (!void_node) void_node = vn;
- }
- node = RNODE_RESCUE(node)->nd_else;
- if (!node) return void_node;
- break;
-
- case NODE_RETURN:
- case NODE_BREAK:
- case NODE_NEXT:
- case NODE_REDO:
- case NODE_RETRY:
- goto found;
-
- case NODE_CASE3:
- if (!RNODE_CASE3(node)->nd_body || !nd_type_p(RNODE_CASE3(node)->nd_body, NODE_IN)) {
- compile_error(p, "unexpected node");
- return NULL;
- }
- if (RNODE_IN(RNODE_CASE3(node)->nd_body)->nd_body) {
- return NULL;
- }
- /* single line pattern matching with "=>" operator */
- goto found;
-
- case NODE_BLOCK:
- while (RNODE_BLOCK(node)->nd_next) {
- node = RNODE_BLOCK(node)->nd_next;
- }
- node = RNODE_BLOCK(node)->nd_head;
- break;
-
- case NODE_BEGIN:
- node = RNODE_BEGIN(node)->nd_body;
- break;
-
- case NODE_IF:
- case NODE_UNLESS:
- if (!RNODE_IF(node)->nd_body) {
- return NULL;
- }
- else if (!RNODE_IF(node)->nd_else) {
- return NULL;
- }
- vn = value_expr_check(p, RNODE_IF(node)->nd_body);
- if (!vn) return NULL;
- if (!void_node) void_node = vn;
- node = RNODE_IF(node)->nd_else;
- break;
-
- case NODE_AND:
- case NODE_OR:
- node = RNODE_AND(node)->nd_1st;
- break;
-
- case NODE_LASGN:
- case NODE_DASGN:
- case NODE_MASGN:
- mark_lvar_used(p, node);
- return NULL;
-
- default:
- return NULL;
- }
+ switch (nd_type(node)) {
+ case NODE_RETURN:
+ case NODE_BREAK:
+ case NODE_NEXT:
+ case NODE_REDO:
+ case NODE_RETRY:
+ return void_node ? void_node : node;
+
+ case NODE_CASE3:
+ if (!node->nd_body || !nd_type_p(node->nd_body, NODE_IN)) {
+ compile_error(p, "unexpected node");
+ return NULL;
+ }
+ if (node->nd_body->nd_body) {
+ return NULL;
+ }
+ /* single line pattern matching */
+ return void_node ? void_node : node;
+
+ case NODE_BLOCK:
+ while (node->nd_next) {
+ node = node->nd_next;
+ }
+ node = node->nd_head;
+ break;
+
+ case NODE_BEGIN:
+ node = node->nd_body;
+ break;
+
+ case NODE_IF:
+ case NODE_UNLESS:
+ if (!node->nd_body) {
+ return NULL;
+ }
+ else if (!node->nd_else) {
+ return NULL;
+ }
+ vn = value_expr_check(p, node->nd_body);
+ if (!vn) return NULL;
+ if (!void_node) void_node = vn;
+ node = node->nd_else;
+ break;
+
+ case NODE_AND:
+ case NODE_OR:
+ node = node->nd_1st;
+ break;
+
+ case NODE_LASGN:
+ case NODE_DASGN:
+ case NODE_MASGN:
+ mark_lvar_used(p, node);
+ return NULL;
+
+ default:
+ return NULL;
+ }
}
return NULL;
-
- found:
- /* return the first found node */
- return void_node ? void_node : node;
}
static int
@@ -13955,13 +12144,12 @@ value_expr_gen(struct parser_params *p, NODE *node)
{
NODE *void_node = value_expr_check(p, node);
if (void_node) {
- yyerror1(&void_node->nd_loc, "void value expression");
- /* or "control never reach"? */
- return FALSE;
+ yyerror1(&void_node->nd_loc, "void value expression");
+ /* or "control never reach"? */
+ return FALSE;
}
return TRUE;
}
-
static void
void_expr(struct parser_params *p, NODE *node)
{
@@ -13972,29 +12160,29 @@ void_expr(struct parser_params *p, NODE *node)
if (!node || !(node = nd_once_body(node))) return;
switch (nd_type(node)) {
case NODE_OPCALL:
- switch (RNODE_OPCALL(node)->nd_mid) {
- case '+':
- case '-':
- case '*':
- case '/':
- case '%':
- case tPOW:
- case tUPLUS:
- case tUMINUS:
- case '|':
- case '^':
- case '&':
- case tCMP:
- case '>':
- case tGEQ:
- case '<':
- case tLEQ:
- case tEQ:
- case tNEQ:
- useless = rb_id2name(RNODE_OPCALL(node)->nd_mid);
- break;
- }
- break;
+ switch (node->nd_mid) {
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '%':
+ case tPOW:
+ case tUPLUS:
+ case tUMINUS:
+ case '|':
+ case '^':
+ case '&':
+ case tCMP:
+ case '>':
+ case tGEQ:
+ case '<':
+ case tLEQ:
+ case tEQ:
+ case tNEQ:
+ useless = rb_id2name(node->nd_mid);
+ break;
+ }
+ break;
case NODE_LVAR:
case NODE_DVAR:
@@ -14003,58 +12191,49 @@ void_expr(struct parser_params *p, NODE *node)
case NODE_CVAR:
case NODE_NTH_REF:
case NODE_BACK_REF:
- useless = "a variable";
- break;
+ useless = "a variable";
+ break;
case NODE_CONST:
- useless = "a constant";
- break;
- case NODE_SYM:
- case NODE_LINE:
- case NODE_FILE:
- case NODE_ENCODING:
- case NODE_INTEGER:
- case NODE_FLOAT:
- case NODE_RATIONAL:
- case NODE_IMAGINARY:
+ useless = "a constant";
+ break;
+ case NODE_LIT:
case NODE_STR:
case NODE_DSTR:
- case NODE_REGX:
case NODE_DREGX:
- useless = "a literal";
- break;
+ useless = "a literal";
+ break;
case NODE_COLON2:
case NODE_COLON3:
- useless = "::";
- break;
+ useless = "::";
+ break;
case NODE_DOT2:
- useless = "..";
- break;
+ useless = "..";
+ break;
case NODE_DOT3:
- useless = "...";
- break;
+ useless = "...";
+ break;
case NODE_SELF:
- useless = "self";
- break;
+ useless = "self";
+ break;
case NODE_NIL:
- useless = "nil";
- break;
+ useless = "nil";
+ break;
case NODE_TRUE:
- useless = "true";
- break;
+ useless = "true";
+ break;
case NODE_FALSE:
- useless = "false";
- break;
+ useless = "false";
+ break;
case NODE_DEFINED:
- useless = "defined?";
- break;
+ useless = "defined?";
+ break;
}
if (useless) {
- rb_warn1L(nd_line(node), "possibly useless use of %s in void context", WARN_S(useless));
+ rb_warn1L(nd_line(node), "possibly useless use of %s in void context", WARN_S(useless));
}
}
-/* warns useless use of block and returns the last statement node */
static NODE *
void_stmts(struct parser_params *p, NODE *node)
{
@@ -14063,19 +12242,29 @@ void_stmts(struct parser_params *p, NODE *node)
if (!node) return n;
if (!nd_type_p(node, NODE_BLOCK)) return n;
- while (RNODE_BLOCK(node)->nd_next) {
- void_expr(p, RNODE_BLOCK(node)->nd_head);
- node = RNODE_BLOCK(node)->nd_next;
+ while (node->nd_next) {
+ void_expr(p, node->nd_head);
+ node = node->nd_next;
}
- return RNODE_BLOCK(node)->nd_head;
+ return n;
}
static NODE *
remove_begin(NODE *node)
{
NODE **n = &node, *n1 = node;
- while (n1 && nd_type_p(n1, NODE_BEGIN) && RNODE_BEGIN(n1)->nd_body) {
- *n = n1 = RNODE_BEGIN(n1)->nd_body;
+ while (n1 && nd_type_p(n1, NODE_BEGIN) && n1->nd_body) {
+ *n = n1 = n1->nd_body;
+ }
+ return node;
+}
+
+static NODE *
+remove_begin_all(NODE *node)
+{
+ NODE **n = &node, *n1 = node;
+ while (n1 && nd_type_p(n1, NODE_BEGIN)) {
+ *n = n1 = n1->nd_body;
}
return node;
}
@@ -14086,54 +12275,57 @@ reduce_nodes(struct parser_params *p, NODE **body)
NODE *node = *body;
if (!node) {
- *body = NEW_NIL(&NULL_LOC);
- return;
+ *body = NEW_NIL(&NULL_LOC);
+ return;
}
-#define subnodes(type, n1, n2) \
- ((!type(node)->n1) ? (type(node)->n2 ? (body = &type(node)->n2, 1) : 0) : \
- (!type(node)->n2) ? (body = &type(node)->n1, 1) : \
- (reduce_nodes(p, &type(node)->n1), body = &type(node)->n2, 1))
+#define subnodes(n1, n2) \
+ ((!node->n1) ? (node->n2 ? (body = &node->n2, 1) : 0) : \
+ (!node->n2) ? (body = &node->n1, 1) : \
+ (reduce_nodes(p, &node->n1), body = &node->n2, 1))
while (node) {
- int newline = (int)nd_fl_newline(node);
- switch (nd_type(node)) {
- end:
- case NODE_NIL:
- *body = 0;
- return;
- case NODE_BEGIN:
- *body = node = RNODE_BEGIN(node)->nd_body;
- if (newline && node) nd_set_fl_newline(node);
- continue;
- case NODE_BLOCK:
- body = &RNODE_BLOCK(RNODE_BLOCK(node)->nd_end)->nd_head;
- break;
- case NODE_IF:
- case NODE_UNLESS:
- if (subnodes(RNODE_IF, nd_body, nd_else)) break;
- return;
- case NODE_CASE:
- body = &RNODE_CASE(node)->nd_body;
- break;
- case NODE_WHEN:
- if (!subnodes(RNODE_WHEN, nd_body, nd_next)) goto end;
- break;
- case NODE_ENSURE:
- body = &RNODE_ENSURE(node)->nd_head;
- break;
- case NODE_RESCUE:
- newline = 0; // RESBODY should not be a NEWLINE
- if (RNODE_RESCUE(node)->nd_else) {
- body = &RNODE_RESCUE(node)->nd_resq;
- break;
- }
- if (!subnodes(RNODE_RESCUE, nd_head, nd_resq)) goto end;
- break;
- default:
- return;
- }
- node = *body;
- if (newline && node) nd_set_fl_newline(node);
+ int newline = (int)(node->flags & NODE_FL_NEWLINE);
+ switch (nd_type(node)) {
+ end:
+ case NODE_NIL:
+ *body = 0;
+ return;
+ case NODE_RETURN:
+ *body = node = node->nd_stts;
+ if (newline && node) node->flags |= NODE_FL_NEWLINE;
+ continue;
+ case NODE_BEGIN:
+ *body = node = node->nd_body;
+ if (newline && node) node->flags |= NODE_FL_NEWLINE;
+ continue;
+ case NODE_BLOCK:
+ body = &node->nd_end->nd_head;
+ break;
+ case NODE_IF:
+ case NODE_UNLESS:
+ if (subnodes(nd_body, nd_else)) break;
+ return;
+ case NODE_CASE:
+ body = &node->nd_body;
+ break;
+ case NODE_WHEN:
+ if (!subnodes(nd_body, nd_next)) goto end;
+ break;
+ case NODE_ENSURE:
+ if (!subnodes(nd_head, nd_resq)) goto end;
+ break;
+ case NODE_RESCUE:
+ if (node->nd_else) {
+ body = &node->nd_resq;
+ break;
+ }
+ if (!subnodes(nd_head, nd_resq)) goto end;
+ break;
+ default:
+ return;
+ }
+ node = *body;
+ if (newline && node) node->flags |= NODE_FL_NEWLINE;
}
#undef subnodes
@@ -14145,28 +12337,20 @@ is_static_content(NODE *node)
if (!node) return 1;
switch (nd_type(node)) {
case NODE_HASH:
- if (!(node = RNODE_HASH(node)->nd_head)) break;
+ if (!(node = node->nd_head)) break;
case NODE_LIST:
- do {
- if (!is_static_content(RNODE_LIST(node)->nd_head)) return 0;
- } while ((node = RNODE_LIST(node)->nd_next) != 0);
- case NODE_SYM:
- case NODE_REGX:
- case NODE_LINE:
- case NODE_FILE:
- case NODE_ENCODING:
- case NODE_INTEGER:
- case NODE_FLOAT:
- case NODE_RATIONAL:
- case NODE_IMAGINARY:
+ do {
+ if (!is_static_content(node->nd_head)) return 0;
+ } while ((node = node->nd_next) != 0);
+ case NODE_LIT:
case NODE_STR:
case NODE_NIL:
case NODE_TRUE:
case NODE_FALSE:
case NODE_ZLIST:
- break;
+ break;
default:
- return 0;
+ return 0;
}
return 1;
}
@@ -14180,18 +12364,16 @@ assign_in_cond(struct parser_params *p, NODE *node)
case NODE_DASGN:
case NODE_GASGN:
case NODE_IASGN:
- case NODE_CVASGN:
- case NODE_CDECL:
- break;
+ break;
default:
- return 0;
+ return 0;
}
- if (!get_nd_value(p, node)) return 1;
- if (is_static_content(get_nd_value(p, node))) {
- /* reports always */
- rb_warn0L(nd_line(get_nd_value(p, node)), "found '= literal' in conditional, should be ==");
+ if (!node->nd_value) return 1;
+ if (is_static_content(node->nd_value)) {
+ /* reports always */
+ parser_warn(p, node->nd_value, "found `= literal' in conditional, should be ==");
}
return 1;
}
@@ -14202,15 +12384,14 @@ enum cond_type {
COND_IN_FF
};
-#define SWITCH_BY_COND_TYPE(t, w, arg) do { \
+#define SWITCH_BY_COND_TYPE(t, w, arg) \
switch (t) { \
case COND_IN_OP: break; \
case COND_IN_COND: rb_##w##0(arg "literal in condition"); break; \
case COND_IN_FF: rb_##w##0(arg "literal in flip-flop"); break; \
- } \
-} while (0)
+ }
-static NODE *cond0(struct parser_params*,NODE*,enum cond_type,const YYLTYPE*,bool);
+static NODE *cond0(struct parser_params*,NODE*,enum cond_type,const YYLTYPE*);
static NODE*
range_op(struct parser_params *p, NODE *node, const YYLTYPE *loc)
@@ -14221,99 +12402,69 @@ range_op(struct parser_params *p, NODE *node, const YYLTYPE *loc)
type = nd_type(node);
value_expr(node);
- if (type == NODE_INTEGER) {
- if (!e_option_supplied(p)) rb_warn0L(nd_line(node), "integer literal in flip-flop");
- ID lineno = rb_intern("$.");
- return NEW_CALL(node, tEQ, NEW_LIST(NEW_GVAR(lineno, loc), loc), loc);
+ if (type == NODE_LIT && FIXNUM_P(node->nd_lit)) {
+ if (!e_option_supplied(p)) parser_warn(p, node, "integer literal in flip-flop");
+ ID lineno = rb_intern("$.");
+ return NEW_CALL(node, tEQ, NEW_LIST(NEW_GVAR(lineno, loc), loc), loc);
}
- return cond0(p, node, COND_IN_FF, loc, true);
+ return cond0(p, node, COND_IN_FF, loc);
}
static NODE*
-cond0(struct parser_params *p, NODE *node, enum cond_type type, const YYLTYPE *loc, bool top)
+cond0(struct parser_params *p, NODE *node, enum cond_type type, const YYLTYPE *loc)
{
if (node == 0) return 0;
if (!(node = nd_once_body(node))) return 0;
assign_in_cond(p, node);
switch (nd_type(node)) {
- case NODE_BEGIN:
- RNODE_BEGIN(node)->nd_body = cond0(p, RNODE_BEGIN(node)->nd_body, type, loc, top);
- break;
-
case NODE_DSTR:
case NODE_EVSTR:
case NODE_STR:
- case NODE_FILE:
- SWITCH_BY_COND_TYPE(type, warn, "string ");
- break;
-
- case NODE_REGX:
- if (!e_option_supplied(p)) SWITCH_BY_COND_TYPE(type, warn, "regex ");
- nd_set_type(node, NODE_MATCH);
- break;
+ SWITCH_BY_COND_TYPE(type, warn, "string ")
+ break;
case NODE_DREGX:
- if (!e_option_supplied(p)) SWITCH_BY_COND_TYPE(type, warning, "regex ");
+ if (!e_option_supplied(p)) SWITCH_BY_COND_TYPE(type, warning, "regex ")
- return NEW_MATCH2(node, NEW_GVAR(idLASTLINE, loc), loc);
-
- case NODE_BLOCK:
- {
- NODE *end = RNODE_BLOCK(node)->nd_end;
- NODE **expr = &RNODE_BLOCK(end)->nd_head;
- if (top) top = node == end;
- *expr = cond0(p, *expr, type, loc, top);
- }
- break;
+ return NEW_MATCH2(node, NEW_GVAR(idLASTLINE, loc), loc);
case NODE_AND:
case NODE_OR:
- RNODE_AND(node)->nd_1st = cond0(p, RNODE_AND(node)->nd_1st, COND_IN_COND, loc, true);
- RNODE_AND(node)->nd_2nd = cond0(p, RNODE_AND(node)->nd_2nd, COND_IN_COND, loc, true);
- break;
+ node->nd_1st = cond0(p, node->nd_1st, COND_IN_COND, loc);
+ node->nd_2nd = cond0(p, node->nd_2nd, COND_IN_COND, loc);
+ break;
case NODE_DOT2:
case NODE_DOT3:
- if (!top) break;
- RNODE_DOT2(node)->nd_beg = range_op(p, RNODE_DOT2(node)->nd_beg, loc);
- RNODE_DOT2(node)->nd_end = range_op(p, RNODE_DOT2(node)->nd_end, loc);
- switch (nd_type(node)) {
- case NODE_DOT2:
- nd_set_type(node,NODE_FLIP2);
- rb_node_flip2_t *flip2 = RNODE_FLIP2(node); /* for debug info */
- (void)flip2;
- break;
- case NODE_DOT3:
- nd_set_type(node, NODE_FLIP3);
- rb_node_flip3_t *flip3 = RNODE_FLIP3(node); /* for debug info */
- (void)flip3;
- break;
- }
- break;
+ node->nd_beg = range_op(p, node->nd_beg, loc);
+ node->nd_end = range_op(p, node->nd_end, loc);
+ if (nd_type_p(node, NODE_DOT2)) nd_set_type(node,NODE_FLIP2);
+ else if (nd_type_p(node, NODE_DOT3)) nd_set_type(node, NODE_FLIP3);
+ break;
- case NODE_SYM:
case NODE_DSYM:
- SWITCH_BY_COND_TYPE(type, warning, "symbol ");
- break;
-
- case NODE_LINE:
- SWITCH_BY_COND_TYPE(type, warning, "");
- break;
-
- case NODE_ENCODING:
- SWITCH_BY_COND_TYPE(type, warning, "");
- break;
-
- case NODE_INTEGER:
- case NODE_FLOAT:
- case NODE_RATIONAL:
- case NODE_IMAGINARY:
- SWITCH_BY_COND_TYPE(type, warning, "");
- break;
-
+ warn_symbol:
+ SWITCH_BY_COND_TYPE(type, warning, "symbol ")
+ break;
+
+ case NODE_LIT:
+ if (RB_TYPE_P(node->nd_lit, T_REGEXP)) {
+ if (!e_option_supplied(p)) SWITCH_BY_COND_TYPE(type, warn, "regex ")
+ nd_set_type(node, NODE_MATCH);
+ }
+ else if (node->nd_lit == Qtrue ||
+ node->nd_lit == Qfalse) {
+ /* booleans are OK, e.g., while true */
+ }
+ else if (SYMBOL_P(node->nd_lit)) {
+ goto warn_symbol;
+ }
+ else {
+ SWITCH_BY_COND_TYPE(type, warning, "")
+ }
default:
- break;
+ break;
}
return node;
}
@@ -14322,14 +12473,14 @@ static NODE*
cond(struct parser_params *p, NODE *node, const YYLTYPE *loc)
{
if (node == 0) return 0;
- return cond0(p, node, COND_IN_COND, loc, true);
+ return cond0(p, node, COND_IN_COND, loc);
}
static NODE*
method_cond(struct parser_params *p, NODE *node, const YYLTYPE *loc)
{
if (node == 0) return 0;
- return cond0(p, node, COND_IN_OP, loc, true);
+ return cond0(p, node, COND_IN_OP, loc);
}
static NODE*
@@ -14343,49 +12494,45 @@ static NODE*
new_if(struct parser_params *p, NODE *cc, NODE *left, NODE *right, const YYLTYPE *loc)
{
if (!cc) return right;
- cc = cond0(p, cc, COND_IN_COND, loc, true);
+ cc = cond0(p, cc, COND_IN_COND, loc);
return newline_node(NEW_IF(cc, left, right, loc));
}
static NODE*
-new_unless(struct parser_params *p, NODE *cc, NODE *left, NODE *right, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *then_keyword_loc, const YYLTYPE *end_keyword_loc)
+new_unless(struct parser_params *p, NODE *cc, NODE *left, NODE *right, const YYLTYPE *loc)
{
if (!cc) return right;
- cc = cond0(p, cc, COND_IN_COND, loc, true);
- return newline_node(NEW_UNLESS(cc, left, right, loc, keyword_loc, then_keyword_loc, end_keyword_loc));
+ cc = cond0(p, cc, COND_IN_COND, loc);
+ return newline_node(NEW_UNLESS(cc, left, right, loc));
}
-#define NEW_AND_OR(type, f, s, loc, op_loc) (type == NODE_AND ? NEW_AND(f,s,loc,op_loc) : NEW_OR(f,s,loc,op_loc))
-
static NODE*
logop(struct parser_params *p, ID id, NODE *left, NODE *right,
- const YYLTYPE *op_loc, const YYLTYPE *loc)
+ const YYLTYPE *op_loc, const YYLTYPE *loc)
{
enum node_type type = id == idAND || id == idANDOP ? NODE_AND : NODE_OR;
NODE *op;
value_expr(left);
if (left && nd_type_p(left, type)) {
- NODE *node = left, *second;
- while ((second = RNODE_AND(node)->nd_2nd) != 0 && nd_type_p(second, type)) {
- node = second;
- }
- RNODE_AND(node)->nd_2nd = NEW_AND_OR(type, second, right, loc, op_loc);
- nd_set_line(RNODE_AND(node)->nd_2nd, op_loc->beg_pos.lineno);
- left->nd_loc.end_pos = loc->end_pos;
- return left;
- }
- op = NEW_AND_OR(type, left, right, loc, op_loc);
+ NODE *node = left, *second;
+ while ((second = node->nd_2nd) != 0 && nd_type_p(second, type)) {
+ node = second;
+ }
+ node->nd_2nd = NEW_NODE(type, second, right, 0, loc);
+ nd_set_line(node->nd_2nd, op_loc->beg_pos.lineno);
+ left->nd_loc.end_pos = loc->end_pos;
+ return left;
+ }
+ op = NEW_NODE(type, left, right, 0, loc);
nd_set_line(op, op_loc->beg_pos.lineno);
return op;
}
-#undef NEW_AND_OR
-
static void
no_blockarg(struct parser_params *p, NODE *node)
{
if (nd_type_p(node, NODE_BLOCK_PASS)) {
- compile_error(p, "block argument should not be given");
+ compile_error(p, "block argument should not be given");
}
}
@@ -14393,10 +12540,15 @@ static NODE *
ret_args(struct parser_params *p, NODE *node)
{
if (node) {
- no_blockarg(p, node);
- if (nd_type_p(node, NODE_LIST) && !RNODE_LIST(node)->nd_next) {
- node = RNODE_LIST(node)->nd_head;
- }
+ no_blockarg(p, node);
+ if (nd_type_p(node, NODE_LIST)) {
+ if (node->nd_next == 0) {
+ node = node->nd_head;
+ }
+ else {
+ nd_set_type(node, NODE_VALUES);
+ }
+ }
}
return node;
}
@@ -14409,35 +12561,53 @@ new_yield(struct parser_params *p, NODE *node, const YYLTYPE *loc)
return NEW_YIELD(node, loc);
}
-static NODE*
-negate_lit(struct parser_params *p, NODE* node)
+static VALUE
+negate_lit(struct parser_params *p, VALUE lit)
{
- switch (nd_type(node)) {
- case NODE_INTEGER:
- RNODE_INTEGER(node)->minus = TRUE;
- break;
- case NODE_FLOAT:
- RNODE_FLOAT(node)->minus = TRUE;
- break;
- case NODE_RATIONAL:
- RNODE_RATIONAL(node)->minus = TRUE;
- break;
- case NODE_IMAGINARY:
- RNODE_IMAGINARY(node)->minus = TRUE;
- break;
+ if (FIXNUM_P(lit)) {
+ return LONG2FIX(-FIX2LONG(lit));
}
- return node;
+ if (SPECIAL_CONST_P(lit)) {
+#if USE_FLONUM
+ if (FLONUM_P(lit)) {
+ return DBL2NUM(-RFLOAT_VALUE(lit));
+ }
+#endif
+ goto unknown;
+ }
+ switch (BUILTIN_TYPE(lit)) {
+ case T_BIGNUM:
+ BIGNUM_NEGATE(lit);
+ lit = rb_big_norm(lit);
+ break;
+ case T_RATIONAL:
+ RATIONAL_SET_NUM(lit, negate_lit(p, RRATIONAL(lit)->num));
+ break;
+ case T_COMPLEX:
+ RCOMPLEX_SET_REAL(lit, negate_lit(p, RCOMPLEX(lit)->real));
+ RCOMPLEX_SET_IMAG(lit, negate_lit(p, RCOMPLEX(lit)->imag));
+ break;
+ case T_FLOAT:
+ lit = DBL2NUM(-RFLOAT_VALUE(lit));
+ break;
+ unknown:
+ default:
+ rb_parser_fatal(p, "unknown literal type (%s) passed to negate_lit",
+ rb_builtin_class_name(lit));
+ break;
+ }
+ return lit;
}
static NODE *
-arg_blk_pass(NODE *node1, rb_node_block_pass_t *node2)
+arg_blk_pass(NODE *node1, NODE *node2)
{
if (node2) {
- if (!node1) return (NODE *)node2;
- node2->nd_head = node1;
- nd_set_first_lineno(node2, nd_first_lineno(node1));
- nd_set_first_column(node2, nd_first_column(node1));
- return (NODE *)node2;
+ if (!node1) return node2;
+ node2->nd_head = node1;
+ nd_set_first_lineno(node2, nd_first_lineno(node1));
+ nd_set_first_column(node2, nd_first_column(node1));
+ return node2;
}
return node1;
}
@@ -14455,23 +12625,24 @@ args_info_empty_p(struct rb_args_info *args)
return true;
}
-static rb_node_args_t *
-new_args(struct parser_params *p, rb_node_args_aux_t *pre_args, rb_node_opt_arg_t *opt_args, ID rest_arg, rb_node_args_aux_t *post_args, rb_node_args_t *tail, const YYLTYPE *loc)
+static NODE*
+new_args(struct parser_params *p, NODE *pre_args, NODE *opt_args, ID rest_arg, NODE *post_args, NODE *tail, const YYLTYPE *loc)
{
- struct rb_args_info *args = &tail->nd_ainfo;
+ int saved_line = p->ruby_sourceline;
+ struct rb_args_info *args = tail->nd_ainfo;
if (args->forwarding) {
- if (rest_arg) {
- yyerror1(&RNODE(tail)->nd_loc, "... after rest argument");
- return tail;
- }
- rest_arg = idFWD_REST;
+ if (rest_arg) {
+ yyerror1(&tail->nd_loc, "... after rest argument");
+ return tail;
+ }
+ rest_arg = idFWD_REST;
}
- args->pre_args_num = pre_args ? pre_args->nd_plen : 0;
+ args->pre_args_num = pre_args ? rb_long2int(pre_args->nd_plen) : 0;
args->pre_init = pre_args ? pre_args->nd_next : 0;
- args->post_args_num = post_args ? post_args->nd_plen : 0;
+ args->post_args_num = post_args ? rb_long2int(post_args->nd_plen) : 0;
args->post_init = post_args ? post_args->nd_next : 0;
args->first_post_arg = post_args ? post_args->nd_pid : 0;
@@ -14485,78 +12656,87 @@ new_args(struct parser_params *p, rb_node_args_aux_t *pre_args, rb_node_opt_arg_
args->ruby2_keywords = 0;
#endif
- nd_set_loc(RNODE(tail), loc);
+ p->ruby_sourceline = saved_line;
+ nd_set_loc(tail, loc);
return tail;
}
-static rb_node_args_t *
-new_args_tail(struct parser_params *p, rb_node_kw_arg_t *kw_args, ID kw_rest_arg, ID block, const YYLTYPE *kw_rest_loc)
+static NODE*
+new_args_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, ID block, const YYLTYPE *kw_rest_loc)
{
- rb_node_args_t *node = NEW_ARGS(&NULL_LOC);
- struct rb_args_info *args = &node->nd_ainfo;
+ int saved_line = p->ruby_sourceline;
+ NODE *node;
+ VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
+ struct rb_args_info *args = ZALLOC(struct rb_args_info);
+ rb_imemo_tmpbuf_set_ptr(tmpbuf, args);
+ args->imemo = tmpbuf;
+ node = NEW_NODE(NODE_ARGS, 0, 0, args, &NULL_LOC);
+ RB_OBJ_WRITTEN(p->ast, Qnil, tmpbuf);
if (p->error_p) return node;
args->block_arg = block;
args->kw_args = kw_args;
if (kw_args) {
- /*
- * def foo(k1: 1, kr1:, k2: 2, **krest, &b)
- * variable order: k1, kr1, k2, &b, internal_id, krest
- * #=> <reorder>
- * variable order: kr1, k1, k2, internal_id, krest, &b
- */
- ID kw_bits = internal_id(p), *required_kw_vars, *kw_vars;
- struct vtable *vtargs = p->lvtbl->args;
- rb_node_kw_arg_t *kwn = kw_args;
+ /*
+ * def foo(k1: 1, kr1:, k2: 2, **krest, &b)
+ * variable order: k1, kr1, k2, &b, internal_id, krest
+ * #=> <reorder>
+ * variable order: kr1, k1, k2, internal_id, krest, &b
+ */
+ ID kw_bits = internal_id(p), *required_kw_vars, *kw_vars;
+ struct vtable *vtargs = p->lvtbl->args;
+ NODE *kwn = kw_args;
if (block) block = vtargs->tbl[vtargs->pos-1];
- vtable_pop(vtargs, !!block + !!kw_rest_arg);
- required_kw_vars = kw_vars = &vtargs->tbl[vtargs->pos];
- while (kwn) {
- if (!NODE_REQUIRED_KEYWORD_P(get_nd_value(p, kwn->nd_body)))
- --kw_vars;
- --required_kw_vars;
- kwn = kwn->nd_next;
- }
-
- for (kwn = kw_args; kwn; kwn = kwn->nd_next) {
- ID vid = get_nd_vid(p, kwn->nd_body);
- if (NODE_REQUIRED_KEYWORD_P(get_nd_value(p, kwn->nd_body))) {
- *required_kw_vars++ = vid;
- }
- else {
- *kw_vars++ = vid;
- }
- }
-
- arg_var(p, kw_bits);
- if (kw_rest_arg) arg_var(p, kw_rest_arg);
- if (block) arg_var(p, block);
-
- args->kw_rest_arg = NEW_DVAR(kw_rest_arg, kw_rest_loc);
+ vtable_pop(vtargs, !!block + !!kw_rest_arg);
+ required_kw_vars = kw_vars = &vtargs->tbl[vtargs->pos];
+ while (kwn) {
+ if (!NODE_REQUIRED_KEYWORD_P(kwn->nd_body))
+ --kw_vars;
+ --required_kw_vars;
+ kwn = kwn->nd_next;
+ }
+
+ for (kwn = kw_args; kwn; kwn = kwn->nd_next) {
+ ID vid = kwn->nd_body->nd_vid;
+ if (NODE_REQUIRED_KEYWORD_P(kwn->nd_body)) {
+ *required_kw_vars++ = vid;
+ }
+ else {
+ *kw_vars++ = vid;
+ }
+ }
+
+ arg_var(p, kw_bits);
+ if (kw_rest_arg) arg_var(p, kw_rest_arg);
+ if (block) arg_var(p, block);
+
+ args->kw_rest_arg = NEW_DVAR(kw_rest_arg, kw_rest_loc);
+ args->kw_rest_arg->nd_cflag = kw_bits;
}
else if (kw_rest_arg == idNil) {
- args->no_kwarg = 1;
+ args->no_kwarg = 1;
}
else if (kw_rest_arg) {
- args->kw_rest_arg = NEW_DVAR(kw_rest_arg, kw_rest_loc);
+ args->kw_rest_arg = NEW_DVAR(kw_rest_arg, kw_rest_loc);
}
+ p->ruby_sourceline = saved_line;
return node;
}
-static rb_node_args_t *
-args_with_numbered(struct parser_params *p, rb_node_args_t *args, int max_numparam, ID it_id)
+static NODE *
+args_with_numbered(struct parser_params *p, NODE *args, int max_numparam)
{
- if (max_numparam > NO_PARAM || it_id) {
- if (!args) {
- YYLTYPE loc = RUBY_INIT_YYLLOC();
- args = new_args_tail(p, 0, 0, 0, 0);
- nd_set_loc(RNODE(args), &loc);
- }
- args->nd_ainfo.pre_args_num = it_id ? 1 : max_numparam;
+ if (max_numparam > NO_PARAM) {
+ if (!args) {
+ YYLTYPE loc = RUBY_INIT_YYLLOC();
+ args = new_args_tail(p, 0, 0, 0, 0);
+ nd_set_loc(args, &loc);
+ }
+ args->nd_ainfo->pre_args_num = max_numparam;
}
return args;
}
@@ -14564,202 +12744,242 @@ args_with_numbered(struct parser_params *p, rb_node_args_t *args, int max_numpar
static NODE*
new_array_pattern(struct parser_params *p, NODE *constant, NODE *pre_arg, NODE *aryptn, const YYLTYPE *loc)
{
- RNODE_ARYPTN(aryptn)->nd_pconst = constant;
+ struct rb_ary_pattern_info *apinfo = aryptn->nd_apinfo;
+
+ aryptn->nd_pconst = constant;
if (pre_arg) {
- NODE *pre_args = NEW_LIST(pre_arg, loc);
- if (RNODE_ARYPTN(aryptn)->pre_args) {
- RNODE_ARYPTN(aryptn)->pre_args = list_concat(pre_args, RNODE_ARYPTN(aryptn)->pre_args);
- }
- else {
- RNODE_ARYPTN(aryptn)->pre_args = pre_args;
- }
+ NODE *pre_args = NEW_LIST(pre_arg, loc);
+ if (apinfo->pre_args) {
+ apinfo->pre_args = list_concat(pre_args, apinfo->pre_args);
+ }
+ else {
+ apinfo->pre_args = pre_args;
+ }
}
return aryptn;
}
static NODE*
-new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, NODE *rest_arg, NODE *post_args, const YYLTYPE *loc)
+new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, ID rest_arg, NODE *post_args, const YYLTYPE *loc)
{
+ int saved_line = p->ruby_sourceline;
+ NODE *node;
+ VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
+ struct rb_ary_pattern_info *apinfo = ZALLOC(struct rb_ary_pattern_info);
+ rb_imemo_tmpbuf_set_ptr(tmpbuf, apinfo);
+ node = NEW_NODE(NODE_ARYPTN, 0, tmpbuf, apinfo, loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, tmpbuf);
+
+ apinfo->pre_args = pre_args;
+
if (has_rest) {
- rest_arg = rest_arg ? rest_arg : NODE_SPECIAL_NO_NAME_REST;
+ if (rest_arg) {
+ apinfo->rest_arg = assignable(p, rest_arg, 0, loc);
+ }
+ else {
+ apinfo->rest_arg = NODE_SPECIAL_NO_NAME_REST;
+ }
}
else {
- rest_arg = NULL;
+ apinfo->rest_arg = NULL;
}
- NODE *node = NEW_ARYPTN(pre_args, rest_arg, post_args, loc);
+ apinfo->post_args = post_args;
+
+ p->ruby_sourceline = saved_line;
return node;
}
static NODE*
new_find_pattern(struct parser_params *p, NODE *constant, NODE *fndptn, const YYLTYPE *loc)
{
- RNODE_FNDPTN(fndptn)->nd_pconst = constant;
+ fndptn->nd_pconst = constant;
return fndptn;
}
static NODE*
-new_find_pattern_tail(struct parser_params *p, NODE *pre_rest_arg, NODE *args, NODE *post_rest_arg, const YYLTYPE *loc)
+new_find_pattern_tail(struct parser_params *p, ID pre_rest_arg, NODE *args, ID post_rest_arg, const YYLTYPE *loc)
{
- pre_rest_arg = pre_rest_arg ? pre_rest_arg : NODE_SPECIAL_NO_NAME_REST;
- post_rest_arg = post_rest_arg ? post_rest_arg : NODE_SPECIAL_NO_NAME_REST;
- NODE *node = NEW_FNDPTN(pre_rest_arg, args, post_rest_arg, loc);
+ int saved_line = p->ruby_sourceline;
+ NODE *node;
+ VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
+ struct rb_fnd_pattern_info *fpinfo = ZALLOC(struct rb_fnd_pattern_info);
+ rb_imemo_tmpbuf_set_ptr(tmpbuf, fpinfo);
+ node = NEW_NODE(NODE_FNDPTN, 0, tmpbuf, fpinfo, loc);
+ RB_OBJ_WRITTEN(p->ast, Qnil, tmpbuf);
+
+ fpinfo->pre_rest_arg = pre_rest_arg ? assignable(p, pre_rest_arg, 0, loc) : NODE_SPECIAL_NO_NAME_REST;
+ fpinfo->args = args;
+ fpinfo->post_rest_arg = post_rest_arg ? assignable(p, post_rest_arg, 0, loc) : NODE_SPECIAL_NO_NAME_REST;
+ p->ruby_sourceline = saved_line;
return node;
}
static NODE*
new_hash_pattern(struct parser_params *p, NODE *constant, NODE *hshptn, const YYLTYPE *loc)
{
- RNODE_HSHPTN(hshptn)->nd_pconst = constant;
+ hshptn->nd_pconst = constant;
return hshptn;
}
static NODE*
new_hash_pattern_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, const YYLTYPE *loc)
{
+ int saved_line = p->ruby_sourceline;
NODE *node, *kw_rest_arg_node;
if (kw_rest_arg == idNil) {
- kw_rest_arg_node = NODE_SPECIAL_NO_REST_KEYWORD;
+ kw_rest_arg_node = NODE_SPECIAL_NO_REST_KEYWORD;
}
else if (kw_rest_arg) {
- kw_rest_arg_node = assignable(p, kw_rest_arg, 0, loc);
+ kw_rest_arg_node = assignable(p, kw_rest_arg, 0, loc);
}
else {
- kw_rest_arg_node = NULL;
+ kw_rest_arg_node = NULL;
}
- node = NEW_HSHPTN(0, kw_args, kw_rest_arg_node, loc);
+ node = NEW_NODE(NODE_HSHPTN, 0, kw_args, kw_rest_arg_node, loc);
+ p->ruby_sourceline = saved_line;
return node;
}
static NODE*
dsym_node(struct parser_params *p, NODE *node, const YYLTYPE *loc)
{
+ VALUE lit;
+
if (!node) {
- return NEW_SYM(STR_NEW0(), loc);
+ return NEW_LIT(ID2SYM(idNULL), loc);
}
switch (nd_type(node)) {
case NODE_DSTR:
- nd_set_type(node, NODE_DSYM);
- nd_set_loc(node, loc);
- break;
+ nd_set_type(node, NODE_DSYM);
+ nd_set_loc(node, loc);
+ break;
case NODE_STR:
- node = str_to_sym_node(p, node, loc);
- break;
+ lit = node->nd_lit;
+ RB_OBJ_WRITTEN(p->ast, Qnil, node->nd_lit = ID2SYM(rb_intern_str(lit)));
+ nd_set_type(node, NODE_LIT);
+ nd_set_loc(node, loc);
+ break;
default:
- node = NEW_DSYM(0, 1, NEW_LIST(node, loc), loc);
- break;
+ node = NEW_NODE(NODE_DSYM, Qnil, 1, NEW_LIST(node, loc), loc);
+ break;
}
return node;
}
static int
-nd_type_st_key_enable_p(NODE *node)
+append_literal_keys(st_data_t k, st_data_t v, st_data_t h)
+{
+ NODE *node = (NODE *)v;
+ NODE **result = (NODE **)h;
+ node->nd_alen = 2;
+ node->nd_next->nd_end = node->nd_next;
+ node->nd_next->nd_next = 0;
+ if (*result)
+ list_concat(*result, node);
+ else
+ *result = node;
+ return ST_CONTINUE;
+}
+
+static bool
+hash_literal_key_p(VALUE k)
{
- switch (nd_type(node)) {
- case NODE_INTEGER:
- case NODE_FLOAT:
- case NODE_RATIONAL:
- case NODE_IMAGINARY:
- case NODE_STR:
- case NODE_SYM:
- case NODE_REGX:
- case NODE_LINE:
- case NODE_FILE:
- case NODE_ENCODING:
- return true;
+ switch (OBJ_BUILTIN_TYPE(k)) {
+ case T_NODE:
+ return false;
default:
- return false;
+ return true;
}
}
-static VALUE
-nd_value(struct parser_params *p, NODE *node)
+static int
+literal_cmp(VALUE val, VALUE lit)
{
- switch (nd_type(node)) {
- case NODE_STR:
- return rb_node_str_string_val(node);
- case NODE_INTEGER:
- return rb_node_integer_literal_val(node);
- case NODE_FLOAT:
- return rb_node_float_literal_val(node);
- case NODE_RATIONAL:
- return rb_node_rational_literal_val(node);
- case NODE_IMAGINARY:
- return rb_node_imaginary_literal_val(node);
- case NODE_SYM:
- return rb_node_sym_string_val(node);
- case NODE_REGX:
- return rb_node_regx_string_val(node);
- case NODE_LINE:
- return rb_node_line_lineno_val(node);
- case NODE_ENCODING:
- return rb_node_encoding_val(node);
- case NODE_FILE:
- return rb_node_file_path_val(node);
- default:
- rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
- UNREACHABLE_RETURN(0);
- }
+ if (val == lit) return 0;
+ if (!hash_literal_key_p(val) || !hash_literal_key_p(lit)) return -1;
+ return rb_iseq_cdhash_cmp(val, lit);
}
-static void
-warn_duplicate_keys(struct parser_params *p, NODE *hash)
-{
- /* See https://bugs.ruby-lang.org/issues/20331 for discussion about what is warned. */
- p->warn_duplicate_keys_table = st_init_table_with_size(&literal_type, RNODE_LIST(hash)->as.nd_alen / 2);
- while (hash && RNODE_LIST(hash)->nd_next) {
- NODE *head = RNODE_LIST(hash)->nd_head;
- NODE *value = RNODE_LIST(hash)->nd_next;
- NODE *next = RNODE_LIST(value)->nd_next;
- st_data_t key;
- st_data_t data;
-
- /* keyword splat, e.g. {k: 1, **z, k: 2} */
- if (!head) {
- head = value;
- }
+static st_index_t
+literal_hash(VALUE a)
+{
+ if (!hash_literal_key_p(a)) return (st_index_t)a;
+ return rb_iseq_cdhash_hash(a);
+}
- if (nd_type_st_key_enable_p(head)) {
- key = (st_data_t)head;
+static const struct st_hash_type literal_type = {
+ literal_cmp,
+ literal_hash,
+};
- if (st_delete(p->warn_duplicate_keys_table, &key, &data)) {
- rb_warn2L(nd_line((NODE *)data),
- "key %+"PRIsWARN" is duplicated and overwritten on line %d",
- nd_value(p, head), WARN_I(nd_line(head)));
- }
- st_insert(p->warn_duplicate_keys_table, (st_data_t)key, (st_data_t)hash);
- }
- hash = next;
- }
- st_free_table(p->warn_duplicate_keys_table);
- p->warn_duplicate_keys_table = NULL;
+static NODE *
+remove_duplicate_keys(struct parser_params *p, NODE *hash)
+{
+ st_table *literal_keys = st_init_table_with_size(&literal_type, hash->nd_alen / 2);
+ NODE *result = 0;
+ NODE *last_expr = 0;
+ rb_code_location_t loc = hash->nd_loc;
+ while (hash && hash->nd_head && hash->nd_next) {
+ NODE *head = hash->nd_head;
+ NODE *value = hash->nd_next;
+ NODE *next = value->nd_next;
+ st_data_t key = (st_data_t)head;
+ st_data_t data;
+ value->nd_next = 0;
+ if (nd_type_p(head, NODE_LIT) &&
+ st_delete(literal_keys, (key = (st_data_t)head->nd_lit, &key), &data)) {
+ NODE *dup_value = ((NODE *)data)->nd_next;
+ rb_compile_warn(p->ruby_sourcefile, nd_line((NODE *)data),
+ "key %+"PRIsVALUE" is duplicated and overwritten on line %d",
+ head->nd_lit, nd_line(head));
+ if (dup_value == last_expr) {
+ value->nd_head = block_append(p, dup_value->nd_head, value->nd_head);
+ }
+ else {
+ last_expr->nd_head = block_append(p, dup_value->nd_head, last_expr->nd_head);
+ }
+ }
+ st_insert(literal_keys, (st_data_t)key, (st_data_t)hash);
+ last_expr = nd_type_p(head, NODE_LIT) ? value : head;
+ hash = next;
+ }
+ st_foreach(literal_keys, append_literal_keys, (st_data_t)&result);
+ st_free_table(literal_keys);
+ if (hash) {
+ if (!result) result = hash;
+ else list_concat(result, hash);
+ }
+ result->nd_loc = loc;
+ return result;
}
static NODE *
new_hash(struct parser_params *p, NODE *hash, const YYLTYPE *loc)
{
- if (hash) warn_duplicate_keys(p, hash);
+ if (hash) hash = remove_duplicate_keys(p, hash);
return NEW_HASH(hash, loc);
}
+#endif
static void
error_duplicate_pattern_variable(struct parser_params *p, ID id, const YYLTYPE *loc)
{
- if (is_private_local_id(p, id)) {
- return;
+ if (is_private_local_id(id)) {
+ return;
}
if (st_is_member(p->pvtbl, id)) {
- yyerror1(loc, "duplicated variable name");
+ yyerror1(loc, "duplicated variable name");
}
else {
- st_insert(p->pvtbl, (st_data_t)id, 0);
+ st_insert(p->pvtbl, (st_data_t)id, 0);
}
}
@@ -14767,74 +12987,107 @@ static void
error_duplicate_pattern_key(struct parser_params *p, VALUE key, const YYLTYPE *loc)
{
if (!p->pktbl) {
- p->pktbl = st_init_numtable();
+ p->pktbl = st_init_numtable();
}
else if (st_is_member(p->pktbl, key)) {
- yyerror1(loc, "duplicated key name");
- return;
+ yyerror1(loc, "duplicated key name");
+ return;
}
st_insert(p->pktbl, (st_data_t)key, 0);
}
+#ifndef RIPPER
static NODE *
new_unique_key_hash(struct parser_params *p, NODE *hash, const YYLTYPE *loc)
{
return NEW_HASH(hash, loc);
}
+#endif /* !RIPPER */
+#ifndef RIPPER
static NODE *
new_op_assign(struct parser_params *p, NODE *lhs, ID op, NODE *rhs, struct lex_context ctxt, const YYLTYPE *loc)
{
NODE *asgn;
if (lhs) {
- ID vid = get_nd_vid(p, lhs);
- YYLTYPE lhs_loc = lhs->nd_loc;
- if (op == tOROP) {
- set_nd_value(p, lhs, rhs);
- nd_set_loc(lhs, loc);
- asgn = NEW_OP_ASGN_OR(gettable(p, vid, &lhs_loc), lhs, loc);
- }
- else if (op == tANDOP) {
- set_nd_value(p, lhs, rhs);
- nd_set_loc(lhs, loc);
- asgn = NEW_OP_ASGN_AND(gettable(p, vid, &lhs_loc), lhs, loc);
- }
- else {
- asgn = lhs;
- rhs = NEW_CALL(gettable(p, vid, &lhs_loc), op, NEW_LIST(rhs, &rhs->nd_loc), loc);
- set_nd_value(p, asgn, rhs);
- nd_set_loc(asgn, loc);
- }
+ ID vid = lhs->nd_vid;
+ YYLTYPE lhs_loc = lhs->nd_loc;
+ int shareable = ctxt.shareable_constant_value;
+ if (shareable) {
+ switch (nd_type(lhs)) {
+ case NODE_CDECL:
+ case NODE_COLON2:
+ case NODE_COLON3:
+ break;
+ default:
+ shareable = 0;
+ break;
+ }
+ }
+ if (op == tOROP) {
+ rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
+ lhs->nd_value = rhs;
+ nd_set_loc(lhs, loc);
+ asgn = NEW_OP_ASGN_OR(gettable(p, vid, &lhs_loc), lhs, loc);
+ if (is_notop_id(vid)) {
+ switch (id_type(vid)) {
+ case ID_GLOBAL:
+ case ID_INSTANCE:
+ case ID_CLASS:
+ asgn->nd_aid = vid;
+ }
+ }
+ }
+ else if (op == tANDOP) {
+ if (shareable) {
+ rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
+ }
+ lhs->nd_value = rhs;
+ nd_set_loc(lhs, loc);
+ asgn = NEW_OP_ASGN_AND(gettable(p, vid, &lhs_loc), lhs, loc);
+ }
+ else {
+ asgn = lhs;
+ rhs = NEW_CALL(gettable(p, vid, &lhs_loc), op, NEW_LIST(rhs, &rhs->nd_loc), loc);
+ if (shareable) {
+ rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
+ }
+ asgn->nd_value = rhs;
+ nd_set_loc(asgn, loc);
+ }
}
else {
- asgn = NEW_ERROR(loc);
+ asgn = NEW_BEGIN(0, loc);
}
return asgn;
}
static NODE *
new_ary_op_assign(struct parser_params *p, NODE *ary,
- NODE *args, ID op, NODE *rhs, const YYLTYPE *args_loc, const YYLTYPE *loc,
- const YYLTYPE *call_operator_loc, const YYLTYPE *opening_loc, const YYLTYPE *closing_loc, const YYLTYPE *binary_operator_loc)
+ NODE *args, ID op, NODE *rhs, const YYLTYPE *args_loc, const YYLTYPE *loc)
{
NODE *asgn;
- aryset_check(p, args);
args = make_list(args, args_loc);
- asgn = NEW_OP_ASGN1(ary, op, args, rhs, loc, call_operator_loc, opening_loc, closing_loc, binary_operator_loc);
+ if (nd_type_p(args, NODE_BLOCK_PASS)) {
+ args = NEW_ARGSCAT(args, rhs, loc);
+ }
+ else {
+ args = arg_concat(p, args, rhs, loc);
+ }
+ asgn = NEW_OP_ASGN1(ary, op, args, loc);
fixpos(asgn, ary);
return asgn;
}
static NODE *
new_attr_op_assign(struct parser_params *p, NODE *lhs,
- ID atype, ID attr, ID op, NODE *rhs, const YYLTYPE *loc,
- const YYLTYPE *call_operator_loc, const YYLTYPE *message_loc, const YYLTYPE *binary_operator_loc)
+ ID atype, ID attr, ID op, NODE *rhs, const YYLTYPE *loc)
{
NODE *asgn;
- asgn = NEW_OP_ASGN2(lhs, CALL_Q_P(atype), attr, op, rhs, loc, call_operator_loc, message_loc, binary_operator_loc);
+ asgn = NEW_OP_ASGN2(lhs, CALL_Q_P(atype), attr, op, rhs, loc);
fixpos(asgn, lhs);
return asgn;
}
@@ -14845,10 +13098,11 @@ new_const_op_assign(struct parser_params *p, NODE *lhs, ID op, NODE *rhs, struct
NODE *asgn;
if (lhs) {
- asgn = NEW_OP_CDECL(lhs, op, rhs, ctxt.shareable_constant_value, loc);
+ rhs = shareable_constant_value(p, ctxt.shareable_constant_value, lhs, rhs, loc);
+ asgn = NEW_OP_CDECL(lhs, op, rhs, loc);
}
else {
- asgn = NEW_ERROR(loc);
+ asgn = NEW_BEGIN(0, loc);
}
fixpos(asgn, lhs);
return asgn;
@@ -14858,16 +13112,20 @@ static NODE *
const_decl(struct parser_params *p, NODE *path, const YYLTYPE *loc)
{
if (p->ctxt.in_def) {
-#ifndef RIPPER
- yyerror1(loc, "dynamic constant assignment");
+ yyerror1(loc, "dynamic constant assignment");
+ }
+ return NEW_CDECL(0, 0, (path), loc);
+}
#else
- set_value(assign_error(p, "dynamic constant assignment", p->s_lvalue));
-#endif
+static VALUE
+const_decl(struct parser_params *p, VALUE path)
+{
+ if (p->ctxt.in_def) {
+ path = assign_error(p, "dynamic constant assignment", path);
}
- return NEW_CDECL(0, 0, (path), p->ctxt.shareable_constant_value, loc);
+ return path;
}
-#ifdef RIPPER
static VALUE
assign_error(struct parser_params *p, const char *mesg, VALUE a)
{
@@ -14875,8 +13133,15 @@ assign_error(struct parser_params *p, const char *mesg, VALUE a)
ripper_error(p);
return a;
}
+
+static VALUE
+var_field(struct parser_params *p, VALUE a)
+{
+ return ripper_new_yylval(p, get_id(a), dispatch1(var_field, a), 0);
+}
#endif
+#ifndef RIPPER
static NODE *
new_bodystmt(struct parser_params *p, NODE *head, NODE *rescue, NODE *rescue_else, NODE *ensure, const YYLTYPE *loc)
{
@@ -14888,12 +13153,16 @@ new_bodystmt(struct parser_params *p, NODE *head, NODE *rescue, NODE *rescue_els
result = NEW_RESCUE(head, rescue, rescue_else, &rescue_loc);
nd_set_line(result, rescue->nd_loc.beg_pos.lineno);
}
+ else if (rescue_else) {
+ result = block_append(p, result, rescue_else);
+ }
if (ensure) {
result = NEW_ENSURE(result, ensure, loc);
}
fixpos(result, head);
return result;
}
+#endif
static void
warn_unused_var(struct parser_params *p, struct local_vars *local)
@@ -14903,15 +13172,15 @@ warn_unused_var(struct parser_params *p, struct local_vars *local)
if (!local->used) return;
cnt = local->used->pos;
if (cnt != local->vars->pos) {
- rb_parser_fatal(p, "local->used->pos != local->vars->pos");
+ rb_parser_fatal(p, "local->used->pos != local->vars->pos");
}
#ifndef RIPPER
ID *v = local->vars->tbl;
ID *u = local->used->tbl;
for (int i = 0; i < cnt; ++i) {
- if (!v[i] || (u[i] & LVAR_USED)) continue;
- if (is_private_local_id(p, v[i])) continue;
- rb_warn1L((int)u[i], "assigned but unused variable - %"PRIsWARN, rb_id2str(v[i]));
+ if (!v[i] || (u[i] & LVAR_USED)) continue;
+ if (is_private_local_id(v[i])) continue;
+ rb_warn1L((int)u[i], "assigned but unused variable - %"PRIsWARN, rb_id2str(v[i]));
}
#endif
}
@@ -14930,11 +13199,10 @@ local_push(struct parser_params *p, int toplevel_scope)
#ifndef RIPPER
if (toplevel_scope && compile_for_eval) warn_unused_vars = 0;
if (toplevel_scope && e_option_supplied(p)) warn_unused_vars = 0;
-#endif
local->numparam.outer = 0;
local->numparam.inner = 0;
local->numparam.current = 0;
- local->it = 0;
+#endif
local->used = warn_unused_vars ? vtable_alloc(0) : 0;
# if WARN_PAST_SCOPE
@@ -14985,6 +13253,7 @@ local_pop(struct parser_params *p)
COND_POP();
}
+#ifndef RIPPER
static rb_ast_id_table_t *
local_tbl(struct parser_params *p)
{
@@ -14999,10 +13268,10 @@ local_tbl(struct parser_params *p)
MEMCPY(tbl->ids, p->lvtbl->args->tbl, ID, cnt_args);
/* remove IDs duplicated to warn shadowing */
for (i = 0, j = cnt_args; i < cnt_vars; ++i) {
- ID id = p->lvtbl->vars->tbl[i];
- if (!vtable_included(p->lvtbl->args, id)) {
- tbl->ids[j++] = id;
- }
+ ID id = p->lvtbl->vars->tbl[i];
+ if (!vtable_included(p->lvtbl->args, id)) {
+ tbl->ids[j++] = id;
+ }
}
if (j < cnt) {
tbl = rb_ast_resize_latest_local_table(p->ast, j);
@@ -15011,6 +13280,19 @@ local_tbl(struct parser_params *p)
return tbl;
}
+static NODE*
+node_newnode_with_locals(struct parser_params *p, enum node_type type, VALUE a1, VALUE a2, const rb_code_location_t *loc)
+{
+ rb_ast_id_table_t *a0;
+ NODE *n;
+
+ a0 = local_tbl(p);
+ n = NEW_NODE(type, a0, a1, a2, loc);
+ return n;
+}
+
+#endif
+
static void
numparam_name(struct parser_params *p, ID id)
{
@@ -15032,18 +13314,10 @@ local_var(struct parser_params *p, ID id)
numparam_name(p, id);
vtable_add(p->lvtbl->vars, id);
if (p->lvtbl->used) {
- vtable_add(p->lvtbl->used, (ID)p->ruby_sourceline);
+ vtable_add(p->lvtbl->used, (ID)p->ruby_sourceline);
}
}
-#ifndef RIPPER
-int
-rb_parser_local_defined(struct parser_params *p, ID id, const struct rb_iseq_struct *iseq)
-{
- return rb_local_defined(id, iseq);
-}
-#endif
-
static int
local_id_ref(struct parser_params *p, ID id, ID **vidrefp)
{
@@ -15054,21 +13328,21 @@ local_id_ref(struct parser_params *p, ID id, ID **vidrefp)
used = p->lvtbl->used;
while (vars && !DVARS_TERMINAL_P(vars->prev)) {
- vars = vars->prev;
- args = args->prev;
- if (used) used = used->prev;
+ vars = vars->prev;
+ args = args->prev;
+ if (used) used = used->prev;
}
if (vars && vars->prev == DVARS_INHERIT) {
- return rb_parser_local_defined(p, id, p->parent_iseq);
+ return rb_local_defined(id, p->parent_iseq);
}
else if (vtable_included(args, id)) {
- return 1;
+ return 1;
}
else {
- int i = vtable_included(vars, id);
- if (i && used && vidrefp) *vidrefp = &used->tbl[i-1];
- return i != 0;
+ int i = vtable_included(vars, id);
+ if (i && used && vidrefp) *vidrefp = &used->tbl[i-1];
+ return i != 0;
}
}
@@ -15097,40 +13371,7 @@ add_forwarding_args(struct parser_params *p)
arg_var(p, idFWD_ALL);
}
-static void
-forwarding_arg_check(struct parser_params *p, ID arg, ID all, const char *var)
-{
- bool conflict = false;
-
- struct vtable *vars, *args;
-
- vars = p->lvtbl->vars;
- args = p->lvtbl->args;
-
- while (vars && !DVARS_TERMINAL_P(vars->prev)) {
- conflict |= (vtable_included(args, arg) && !(all && vtable_included(args, all)));
- vars = vars->prev;
- args = args->prev;
- }
-
- bool found = false;
- if (vars && vars->prev == DVARS_INHERIT && !found) {
- found = (rb_parser_local_defined(p, arg, p->parent_iseq) &&
- !(all && rb_parser_local_defined(p, all, p->parent_iseq)));
- }
- else {
- found = (vtable_included(args, arg) &&
- !(all && vtable_included(args, all)));
- }
-
- if (!found) {
- compile_error(p, "no anonymous %s parameter", var);
- }
- else if (conflict) {
- compile_error(p, "anonymous %s parameter is also used within block", var);
- }
-}
-
+#ifndef RIPPER
static NODE *
new_args_forward_call(struct parser_params *p, NODE *leading, const YYLTYPE *loc, const YYLTYPE *argsloc)
{
@@ -15138,51 +13379,55 @@ new_args_forward_call(struct parser_params *p, NODE *leading, const YYLTYPE *loc
#ifndef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
NODE *kwrest = list_append(p, NEW_LIST(0, loc), NEW_LVAR(idFWD_KWREST, loc));
#endif
- rb_node_block_pass_t *block = NEW_BLOCK_PASS(NEW_LVAR(idFWD_BLOCK, loc), argsloc, &NULL_LOC);
- NODE *args = leading ? rest_arg_append(p, leading, rest, argsloc) : NEW_SPLAT(rest, loc, &NULL_LOC);
- block->forwarding = TRUE;
+ NODE *block = NEW_BLOCK_PASS(NEW_LVAR(idFWD_BLOCK, loc), loc);
+ NODE *args = leading ? rest_arg_append(p, leading, rest, argsloc) : NEW_SPLAT(rest, loc);
#ifndef FORWARD_ARGS_WITH_RUBY2_KEYWORDS
- args = arg_append(p, args, new_hash(p, kwrest, loc), argsloc);
+ args = arg_append(p, args, new_hash(p, kwrest, loc), loc);
#endif
return arg_blk_pass(args, block);
}
+#endif
static NODE *
numparam_push(struct parser_params *p)
{
+#ifndef RIPPER
struct local_vars *local = p->lvtbl;
NODE *inner = local->numparam.inner;
if (!local->numparam.outer) {
- local->numparam.outer = local->numparam.current;
+ local->numparam.outer = local->numparam.current;
}
local->numparam.inner = 0;
local->numparam.current = 0;
- local->it = 0;
return inner;
+#else
+ return 0;
+#endif
}
static void
numparam_pop(struct parser_params *p, NODE *prev_inner)
{
+#ifndef RIPPER
struct local_vars *local = p->lvtbl;
if (prev_inner) {
- /* prefer first one */
- local->numparam.inner = prev_inner;
+ /* prefer first one */
+ local->numparam.inner = prev_inner;
}
else if (local->numparam.current) {
- /* current and inner are exclusive */
- local->numparam.inner = local->numparam.current;
+ /* current and inner are exclusive */
+ local->numparam.inner = local->numparam.current;
}
if (p->max_numparam > NO_PARAM) {
- /* current and outer are exclusive */
- local->numparam.current = local->numparam.outer;
- local->numparam.outer = 0;
+ /* current and outer are exclusive */
+ local->numparam.current = local->numparam.outer;
+ local->numparam.outer = 0;
}
else {
- /* no numbered parameter */
- local->numparam.current = 0;
+ /* no numbered parameter */
+ local->numparam.current = 0;
}
- local->it = 0;
+#endif
}
static const struct vtable *
@@ -15191,7 +13436,7 @@ dyna_push(struct parser_params *p)
p->lvtbl->args = vtable_alloc(p->lvtbl->args);
p->lvtbl->vars = vtable_alloc(p->lvtbl->vars);
if (p->lvtbl->used) {
- p->lvtbl->used = vtable_alloc(p->lvtbl->used);
+ p->lvtbl->used = vtable_alloc(p->lvtbl->used);
}
return p->lvtbl->args;
}
@@ -15203,9 +13448,9 @@ dyna_pop_vtable(struct parser_params *p, struct vtable **vtblp)
*vtblp = tmp->prev;
# if WARN_PAST_SCOPE
if (p->past_scope_enabled) {
- tmp->prev = p->lvtbl->past;
- p->lvtbl->past = tmp;
- return;
+ tmp->prev = p->lvtbl->past;
+ p->lvtbl->past = tmp;
+ return;
}
# endif
vtable_free(tmp);
@@ -15217,9 +13462,9 @@ dyna_pop_1(struct parser_params *p)
struct vtable *tmp;
if ((tmp = p->lvtbl->used) != 0) {
- warn_unused_var(p, p->lvtbl);
- p->lvtbl->used = p->lvtbl->used->prev;
- vtable_free(tmp);
+ warn_unused_var(p, p->lvtbl);
+ p->lvtbl->used = p->lvtbl->used->prev;
+ vtable_free(tmp);
}
dyna_pop_vtable(p, &p->lvtbl->args);
dyna_pop_vtable(p, &p->lvtbl->vars);
@@ -15229,12 +13474,12 @@ static void
dyna_pop(struct parser_params *p, const struct vtable *lvargs)
{
while (p->lvtbl->args != lvargs) {
- dyna_pop_1(p);
- if (!p->lvtbl->args) {
- struct local_vars *local = p->lvtbl->prev;
- ruby_sized_xfree(p->lvtbl, sizeof(*p->lvtbl));
- p->lvtbl = local;
- }
+ dyna_pop_1(p);
+ if (!p->lvtbl->args) {
+ struct local_vars *local = p->lvtbl->prev;
+ ruby_sized_xfree(p->lvtbl, sizeof(*p->lvtbl));
+ p->lvtbl = local;
+ }
}
dyna_pop_1(p);
}
@@ -15245,8 +13490,7 @@ dyna_in_block(struct parser_params *p)
return !DVARS_TERMINAL_P(p->lvtbl->vars) && p->lvtbl->vars->prev != DVARS_TOPSCOPE;
}
-#ifndef RIPPER
-int
+static int
dvar_defined_ref(struct parser_params *p, ID id, ID **vidrefp)
{
struct vtable *vars, *args, *used;
@@ -15257,17 +13501,17 @@ dvar_defined_ref(struct parser_params *p, ID id, ID **vidrefp)
used = p->lvtbl->used;
while (!DVARS_TERMINAL_P(vars)) {
- if (vtable_included(args, id)) {
- return 1;
- }
- if ((i = vtable_included(vars, id)) != 0) {
- if (used && vidrefp) *vidrefp = &used->tbl[i-1];
- return 1;
- }
- args = args->prev;
- vars = vars->prev;
- if (!vidrefp) used = 0;
- if (used) used = used->prev;
+ if (vtable_included(args, id)) {
+ return 1;
+ }
+ if ((i = vtable_included(vars, id)) != 0) {
+ if (used && vidrefp) *vidrefp = &used->tbl[i-1];
+ return 1;
+ }
+ args = args->prev;
+ vars = vars->prev;
+ if (!vidrefp) used = 0;
+ if (used) used = used->prev;
}
if (vars == DVARS_INHERIT && !NUMPARAM_ID_P(id)) {
@@ -15276,7 +13520,6 @@ dvar_defined_ref(struct parser_params *p, ID id, ID **vidrefp)
return 0;
}
-#endif
static int
dvar_defined(struct parser_params *p, ID id)
@@ -15288,122 +13531,76 @@ static int
dvar_curr(struct parser_params *p, ID id)
{
return (vtable_included(p->lvtbl->args, id) ||
- vtable_included(p->lvtbl->vars, id));
+ vtable_included(p->lvtbl->vars, id));
}
static void
-reg_fragment_enc_error(struct parser_params* p, rb_parser_string_t *str, int c)
+reg_fragment_enc_error(struct parser_params* p, VALUE str, int c)
{
compile_error(p,
"regexp encoding option '%c' differs from source encoding '%s'",
- c, rb_enc_name(rb_parser_str_get_encoding(str)));
+ c, rb_enc_name(rb_enc_get(str)));
}
#ifndef RIPPER
-static rb_encoding *
-find_enc(struct parser_params* p, const char *name)
-{
- int idx = rb_enc_find_index(name);
- if (idx < 0) {
- rb_bug("unknown encoding name: %s", name);
- }
-
- return rb_enc_from_index(idx);
-}
-
-static rb_encoding *
-kcode_to_enc(struct parser_params* p, int kcode)
-{
- rb_encoding *enc;
-
- switch (kcode) {
- case ENC_ASCII8BIT:
- enc = rb_ascii8bit_encoding();
- break;
- case ENC_EUC_JP:
- enc = find_enc(p, "EUC-JP");
- break;
- case ENC_Windows_31J:
- enc = find_enc(p, "Windows-31J");
- break;
- case ENC_UTF8:
- enc = rb_utf8_encoding();
- break;
- default:
- enc = NULL;
- break;
- }
-
- return enc;
-}
-
int
-rb_reg_fragment_setenc(struct parser_params* p, rb_parser_string_t *str, int options)
+rb_reg_fragment_setenc(struct parser_params* p, VALUE str, int options)
{
int c = RE_OPTION_ENCODING_IDX(options);
if (c) {
- int opt, idx;
- rb_encoding *enc;
-
- char_to_option_kcode(c, &opt, &idx);
- enc = kcode_to_enc(p, idx);
- if (enc != rb_parser_str_get_encoding(str) &&
- !rb_parser_is_ascii_string(p, str)) {
+ int opt, idx;
+ rb_char_to_option_kcode(c, &opt, &idx);
+ if (idx != ENCODING_GET(str) &&
+ !is_ascii_string(str)) {
goto error;
- }
- rb_parser_string_set_encoding(str, enc);
+ }
+ ENCODING_SET(str, idx);
}
else if (RE_OPTION_ENCODING_NONE(options)) {
- if (!PARSER_ENCODING_IS_ASCII8BIT(p, str) &&
- !rb_parser_is_ascii_string(p, str)) {
+ if (!ENCODING_IS_ASCII8BIT(str) &&
+ !is_ascii_string(str)) {
c = 'n';
goto error;
}
- rb_parser_enc_associate(p, str, rb_ascii8bit_encoding());
+ rb_enc_associate(str, rb_ascii8bit_encoding());
}
else if (rb_is_usascii_enc(p->enc)) {
- if (!rb_parser_is_ascii_string(p, str)) {
- /* raise in re.c */
- rb_parser_enc_associate(p, str, rb_usascii_encoding());
- }
- else {
- rb_parser_enc_associate(p, str, rb_ascii8bit_encoding());
- }
+ if (!is_ascii_string(str)) {
+ /* raise in re.c */
+ rb_enc_associate(str, rb_usascii_encoding());
+ }
+ else {
+ rb_enc_associate(str, rb_ascii8bit_encoding());
+ }
}
return 0;
error:
return c;
}
-#endif
static void
-reg_fragment_setenc(struct parser_params* p, rb_parser_string_t *str, int options)
+reg_fragment_setenc(struct parser_params* p, VALUE str, int options)
{
int c = rb_reg_fragment_setenc(p, str, options);
if (c) reg_fragment_enc_error(p, str, c);
}
-#ifndef RIPPER
-int
-reg_fragment_check(struct parser_params* p, rb_parser_string_t *str, int options)
+static int
+reg_fragment_check(struct parser_params* p, VALUE str, int options)
{
- VALUE err, str2;
+ VALUE err;
reg_fragment_setenc(p, str, options);
- /* TODO */
- str2 = rb_str_new_parser_string(str);
- err = rb_reg_check_preprocess(str2);
+ err = rb_reg_check_preprocess(str);
if (err != Qnil) {
err = rb_obj_as_string(err);
compile_error(p, "%"PRIsVALUE, err);
- return 0;
+ return 0;
}
return 1;
}
-#endif
-#ifndef UNIVERSAL_PARSER
typedef struct {
struct parser_params* parser;
rb_encoding *enc;
@@ -15420,8 +13617,23 @@ reg_named_capture_assign_iter(const OnigUChar *name, const OnigUChar *name_end,
rb_encoding *enc = arg->enc;
long len = name_end - name;
const char *s = (const char *)name;
+ ID var;
+ NODE *node, *succ;
- return rb_reg_named_capture_assign_iter_impl(p, s, len, enc, &arg->succ_block, arg->loc);
+ if (!len) return ST_CONTINUE;
+ if (rb_enc_symname_type(s, len, enc, (1U<<ID_LOCAL)) != ID_LOCAL)
+ return ST_CONTINUE;
+
+ var = intern_cstr(s, len, enc);
+ if (len < MAX_WORD_LENGTH && rb_reserved_word(s, (int)len)) {
+ if (!lvar_defined(p, var)) return ST_CONTINUE;
+ }
+ node = node_assign(p, assignable(p, var, 0, arg->loc), NEW_LIT(ID2SYM(var), arg->loc), NO_LEX_CTXT, arg->loc);
+ succ = arg->succ_block;
+ if (!succ) succ = NEW_BEGIN(0, arg->loc);
+ succ = block_append(p, succ, node);
+ arg->succ_block = succ;
+ return ST_CONTINUE;
}
static NODE *
@@ -15436,54 +13648,24 @@ reg_named_capture_assign(struct parser_params* p, VALUE regexp, const YYLTYPE *l
onig_foreach_name(RREGEXP_PTR(regexp), reg_named_capture_assign_iter, &arg);
if (!arg.succ_block) return 0;
- return RNODE_BLOCK(arg.succ_block)->nd_next;
-}
-#endif
-
-#ifndef RIPPER
-int
-rb_reg_named_capture_assign_iter_impl(struct parser_params *p, const char *s, long len,
- rb_encoding *enc, NODE **succ_block, const rb_code_location_t *loc)
-{
- ID var;
- NODE *node, *succ;
-
- if (!len) return ST_CONTINUE;
- if (!VALID_SYMNAME_P(s, len, enc, ID_LOCAL))
- return ST_CONTINUE;
-
- var = intern_cstr(s, len, enc);
- if (len < MAX_WORD_LENGTH && rb_reserved_word(s, (int)len)) {
- if (!lvar_defined(p, var)) return ST_CONTINUE;
- }
- node = node_assign(p, assignable(p, var, 0, loc), NEW_SYM(rb_id2str(var), loc), NO_LEX_CTXT, loc);
- succ = *succ_block;
- if (!succ) succ = NEW_ERROR(loc);
- succ = block_append(p, succ, node);
- *succ_block = succ;
- return ST_CONTINUE;
+ return arg.succ_block->nd_next;
}
-#endif
static VALUE
-parser_reg_compile(struct parser_params* p, rb_parser_string_t *str, int options)
+parser_reg_compile(struct parser_params* p, VALUE str, int options)
{
- VALUE str2;
reg_fragment_setenc(p, str, options);
- str2 = rb_str_new_parser_string(str);
- return rb_parser_reg_compile(p, str2, options);
+ return rb_parser_reg_compile(p, str, options);
}
-#ifndef RIPPER
VALUE
rb_parser_reg_compile(struct parser_params* p, VALUE str, int options)
{
return rb_reg_compile(str, options & RE_OPTION_MASK, p->ruby_sourcefile, p->ruby_sourceline);
}
-#endif
static VALUE
-reg_compile(struct parser_params* p, rb_parser_string_t *str, int options)
+reg_compile(struct parser_params* p, VALUE str, int options)
{
VALUE re;
VALUE err;
@@ -15491,18 +13673,37 @@ reg_compile(struct parser_params* p, rb_parser_string_t *str, int options)
err = rb_errinfo();
re = parser_reg_compile(p, str, options);
if (NIL_P(re)) {
- VALUE m = rb_attr_get(rb_errinfo(), idMesg);
- rb_set_errinfo(err);
- compile_error(p, "%"PRIsVALUE, m);
- return Qnil;
+ VALUE m = rb_attr_get(rb_errinfo(), idMesg);
+ rb_set_errinfo(err);
+ compile_error(p, "%"PRIsVALUE, m);
+ return Qnil;
}
return re;
}
+#else
+static VALUE
+parser_reg_compile(struct parser_params* p, VALUE str, int options, VALUE *errmsg)
+{
+ VALUE err = rb_errinfo();
+ VALUE re;
+ str = ripper_is_node_yylval(str) ? RNODE(str)->nd_cval : str;
+ int c = rb_reg_fragment_setenc(p, str, options);
+ if (c) reg_fragment_enc_error(p, str, c);
+ re = rb_parser_reg_compile(p, str, options);
+ if (NIL_P(re)) {
+ *errmsg = rb_attr_get(rb_errinfo(), idMesg);
+ rb_set_errinfo(err);
+ }
+ return re;
+}
+#endif
#ifndef RIPPER
void
-rb_ruby_parser_set_options(struct parser_params *p, int print, int loop, int chomp, int split)
+rb_parser_set_options(VALUE vparser, int print, int loop, int chomp, int split)
{
+ struct parser_params *p;
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
p->do_print = print;
p->do_loop = loop;
p->do_chomp = chomp;
@@ -15516,32 +13717,32 @@ parser_append_options(struct parser_params *p, NODE *node)
const YYLTYPE *const LOC = &default_location;
if (p->do_print) {
- NODE *print = (NODE *)NEW_FCALL(rb_intern("print"),
- NEW_LIST(NEW_GVAR(idLASTLINE, LOC), LOC),
- LOC);
- node = block_append(p, node, print);
+ NODE *print = NEW_FCALL(rb_intern("print"),
+ NEW_LIST(NEW_GVAR(idLASTLINE, LOC), LOC),
+ LOC);
+ node = block_append(p, node, print);
}
if (p->do_loop) {
- NODE *irs = NEW_LIST(NEW_GVAR(rb_intern("$/"), LOC), LOC);
-
- if (p->do_split) {
- ID ifs = rb_intern("$;");
- ID fields = rb_intern("$F");
- NODE *args = NEW_LIST(NEW_GVAR(ifs, LOC), LOC);
- NODE *split = NEW_GASGN(fields,
- NEW_CALL(NEW_GVAR(idLASTLINE, LOC),
- rb_intern("split"), args, LOC),
- LOC);
- node = block_append(p, split, node);
- }
- if (p->do_chomp) {
- NODE *chomp = NEW_SYM(rb_str_new_cstr("chomp"), LOC);
- chomp = list_append(p, NEW_LIST(chomp, LOC), NEW_TRUE(LOC));
- irs = list_append(p, irs, NEW_HASH(chomp, LOC));
- }
-
- node = NEW_WHILE((NODE *)NEW_FCALL(idGets, irs, LOC), node, 1, LOC, &NULL_LOC, &NULL_LOC);
+ NODE *irs = NEW_LIST(NEW_GVAR(rb_intern("$/"), LOC), LOC);
+
+ if (p->do_split) {
+ ID ifs = rb_intern("$;");
+ ID fields = rb_intern("$F");
+ NODE *args = NEW_LIST(NEW_GVAR(ifs, LOC), LOC);
+ NODE *split = NEW_GASGN(fields,
+ NEW_CALL(NEW_GVAR(idLASTLINE, LOC),
+ rb_intern("split"), args, LOC),
+ LOC);
+ node = block_append(p, split, node);
+ }
+ if (p->do_chomp) {
+ NODE *chomp = NEW_LIT(ID2SYM(rb_intern("chomp")), LOC);
+ chomp = list_append(p, NEW_LIST(chomp, LOC), NEW_TRUE(LOC));
+ irs = list_append(p, irs, NEW_HASH(chomp, LOC));
+ }
+
+ node = NEW_WHILE(NEW_FCALL(idGets, irs, LOC), node, 1, LOC);
}
return node;
@@ -15555,7 +13756,7 @@ rb_init_parse(void)
(void)nodeline;
}
-ID
+static ID
internal_id(struct parser_params *p)
{
return rb_make_temporary_id(vtable_size(p->lvtbl->args) + vtable_size(p->lvtbl->vars));
@@ -15569,74 +13770,64 @@ parser_initialize(struct parser_params *p)
p->command_start = TRUE;
p->ruby_sourcefile_string = Qnil;
p->lex.lpar_beg = -1; /* make lambda_beginning_p() == FALSE at first */
- string_buffer_init(p);
p->node_id = 0;
- p->delayed.token = NULL;
- p->frozen_string_literal = -1; /* not specified */
-#ifndef RIPPER
- p->error_buffer = Qfalse;
- p->end_expect_token_locations = NULL;
- p->token_id = 0;
- p->tokens = NULL;
-#else
+ p->delayed.token = Qnil;
+#ifdef RIPPER
p->result = Qnil;
p->parsing_thread = Qnil;
- p->s_value = Qnil;
- p->s_lvalue = Qnil;
- p->s_value_stack = rb_ary_new();
+#else
+ p->error_buffer = Qfalse;
+ p->end_expect_token_locations = Qnil;
+ p->token_id = 0;
+ p->tokens = Qnil;
#endif
p->debug_buffer = Qnil;
p->debug_output = rb_ractor_stdout();
p->enc = rb_utf8_encoding();
- p->exits = 0;
}
#ifdef RIPPER
-#define rb_ruby_parser_mark ripper_parser_mark
-#define rb_ruby_parser_free ripper_parser_free
-#define rb_ruby_parser_memsize ripper_parser_memsize
+#define parser_mark ripper_parser_mark
+#define parser_free ripper_parser_free
#endif
-void
-rb_ruby_parser_mark(void *ptr)
+static void
+parser_mark(void *ptr)
{
struct parser_params *p = (struct parser_params*)ptr;
+ rb_gc_mark(p->lex.input);
+ rb_gc_mark(p->lex.lastline);
+ rb_gc_mark(p->lex.nextline);
rb_gc_mark(p->ruby_sourcefile_string);
+ rb_gc_mark((VALUE)p->lex.strterm);
+ rb_gc_mark((VALUE)p->ast);
+ rb_gc_mark(p->case_labels);
+ rb_gc_mark(p->delayed.token);
#ifndef RIPPER
+ rb_gc_mark(p->debug_lines);
+ rb_gc_mark(p->compile_option);
rb_gc_mark(p->error_buffer);
+ rb_gc_mark(p->end_expect_token_locations);
+ rb_gc_mark(p->tokens);
#else
rb_gc_mark(p->value);
rb_gc_mark(p->result);
rb_gc_mark(p->parsing_thread);
- rb_gc_mark(p->s_value);
- rb_gc_mark(p->s_lvalue);
- rb_gc_mark(p->s_value_stack);
#endif
rb_gc_mark(p->debug_buffer);
rb_gc_mark(p->debug_output);
+#ifdef YYMALLOC
+ rb_gc_mark((VALUE)p->heap);
+#endif
}
-void
-rb_ruby_parser_free(void *ptr)
+static void
+parser_free(void *ptr)
{
struct parser_params *p = (struct parser_params*)ptr;
struct local_vars *local, *prev;
- if (p->ast) {
- rb_ast_free(p->ast);
- }
-
- if (p->warn_duplicate_keys_table) {
- st_free_table(p->warn_duplicate_keys_table);
- }
-
-#ifndef RIPPER
- if (p->tokens) {
- rb_parser_ary_free(p, p->tokens);
- }
-#endif
-
if (p->tokenbuf) {
ruby_sized_xfree(p->tokenbuf, p->toksiz);
}
@@ -15651,26 +13842,13 @@ rb_ruby_parser_free(void *ptr)
while ((ptinfo = p->token_info) != 0) {
p->token_info = ptinfo->next;
xfree(ptinfo);
- }
+ }
}
- string_buffer_free(p);
-
- if (p->pvtbl) {
- st_free_table(p->pvtbl);
- }
-
- if (CASE_LABELS_ENABLED_P(p->case_labels)) {
- st_free_table(p->case_labels);
- }
-
- xfree(p->lex.strterm);
- p->lex.strterm = 0;
-
xfree(ptr);
}
-size_t
-rb_ruby_parser_memsize(const void *ptr)
+static size_t
+parser_memsize(const void *ptr)
{
struct parser_params *p = (struct parser_params*)ptr;
struct local_vars *local;
@@ -15678,12 +13856,26 @@ rb_ruby_parser_memsize(const void *ptr)
size += p->toksiz;
for (local = p->lvtbl; local; local = local->prev) {
- size += sizeof(*local);
- if (local->vars) size += local->vars->capa * sizeof(ID);
+ size += sizeof(*local);
+ if (local->vars) size += local->vars->capa * sizeof(ID);
}
return size;
}
+static const rb_data_type_t parser_data_type = {
+#ifndef RIPPER
+ "parser",
+#else
+ "ripper",
+#endif
+ {
+ parser_mark,
+ parser_free,
+ parser_memsize,
+ },
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
+};
+
#ifndef RIPPER
#undef rb_reserved_word
@@ -15693,246 +13885,245 @@ rb_reserved_word(const char *str, unsigned int len)
return reserved_word(str, len);
}
-#ifdef UNIVERSAL_PARSER
-rb_parser_t *
-rb_ruby_parser_allocate(const rb_parser_config_t *config)
-{
- /* parser_initialize expects fields to be set to 0 */
- rb_parser_t *p = (rb_parser_t *)config->calloc(1, sizeof(rb_parser_t));
- p->config = config;
- return p;
-}
-
-rb_parser_t *
-rb_ruby_parser_new(const rb_parser_config_t *config)
+VALUE
+rb_parser_new(void)
{
- /* parser_initialize expects fields to be set to 0 */
- rb_parser_t *p = rb_ruby_parser_allocate(config);
+ struct parser_params *p;
+ VALUE parser = TypedData_Make_Struct(0, struct parser_params,
+ &parser_data_type, p);
parser_initialize(p);
- return p;
-}
-#else
-rb_parser_t *
-rb_ruby_parser_allocate(void)
-{
- /* parser_initialize expects fields to be set to 0 */
- rb_parser_t *p = (rb_parser_t *)ruby_xcalloc(1, sizeof(rb_parser_t));
- return p;
+ return parser;
}
-rb_parser_t *
-rb_ruby_parser_new(void)
+VALUE
+rb_parser_set_context(VALUE vparser, const struct rb_iseq_struct *base, int main)
{
- /* parser_initialize expects fields to be set to 0 */
- rb_parser_t *p = rb_ruby_parser_allocate();
- parser_initialize(p);
- return p;
-}
-#endif
+ struct parser_params *p;
-rb_parser_t *
-rb_ruby_parser_set_context(rb_parser_t *p, const struct rb_iseq_struct *base, int main)
-{
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
p->error_buffer = main ? Qfalse : Qnil;
p->parent_iseq = base;
- return p;
+ return vparser;
}
void
-rb_ruby_parser_set_script_lines(rb_parser_t *p)
+rb_parser_keep_script_lines(VALUE vparser)
{
- p->debug_lines = rb_parser_ary_new_capa_for_script_line(p, 10);
+ struct parser_params *p;
+
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
+ p->keep_script_lines = 1;
}
void
-rb_ruby_parser_error_tolerant(rb_parser_t *p)
+rb_parser_error_tolerant(VALUE vparser)
{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
p->error_tolerant = 1;
+ p->end_expect_token_locations = rb_ary_new();
}
void
-rb_ruby_parser_keep_tokens(rb_parser_t *p)
+rb_parser_keep_tokens(VALUE vparser)
{
- p->keep_tokens = 1;
- p->tokens = rb_parser_ary_new_capa_for_ast_token(p, 10);
-}
+ struct parser_params *p;
-rb_encoding *
-rb_ruby_parser_encoding(rb_parser_t *p)
-{
- return p->enc;
-}
-
-int
-rb_ruby_parser_end_seen_p(rb_parser_t *p)
-{
- return p->ruby__end__seen;
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
+ p->keep_tokens = 1;
+ p->tokens = rb_ary_new();
}
-int
-rb_ruby_parser_set_yydebug(rb_parser_t *p, int flag)
-{
- p->debug = flag;
- return flag;
-}
-#endif /* !RIPPER */
+#endif
#ifdef RIPPER
-int
-rb_ruby_parser_get_yydebug(rb_parser_t *p)
-{
- return p->debug;
-}
+#define rb_parser_end_seen_p ripper_parser_end_seen_p
+#define rb_parser_encoding ripper_parser_encoding
+#define rb_parser_get_yydebug ripper_parser_get_yydebug
+#define rb_parser_set_yydebug ripper_parser_set_yydebug
+#define rb_parser_get_debug_output ripper_parser_get_debug_output
+#define rb_parser_set_debug_output ripper_parser_set_debug_output
+static VALUE ripper_parser_end_seen_p(VALUE vparser);
+static VALUE ripper_parser_encoding(VALUE vparser);
+static VALUE ripper_parser_get_yydebug(VALUE self);
+static VALUE ripper_parser_set_yydebug(VALUE self, VALUE flag);
+static VALUE ripper_parser_get_debug_output(VALUE self);
+static VALUE ripper_parser_set_debug_output(VALUE self, VALUE output);
-void
-rb_ruby_parser_set_value(rb_parser_t *p, VALUE value)
+/*
+ * call-seq:
+ * ripper.error? -> Boolean
+ *
+ * Return true if parsed source has errors.
+ */
+static VALUE
+ripper_error_p(VALUE vparser)
{
- p->value = value;
-}
+ struct parser_params *p;
-int
-rb_ruby_parser_error_p(rb_parser_t *p)
-{
- return p->error_p;
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
+ return RBOOL(p->error_p);
}
+#endif
+/*
+ * call-seq:
+ * ripper.end_seen? -> Boolean
+ *
+ * Return true if parsed source ended by +\_\_END\_\_+.
+ */
VALUE
-rb_ruby_parser_debug_output(rb_parser_t *p)
+rb_parser_end_seen_p(VALUE vparser)
{
- return p->debug_output;
-}
+ struct parser_params *p;
-void
-rb_ruby_parser_set_debug_output(rb_parser_t *p, VALUE output)
-{
- p->debug_output = output;
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
+ return RBOOL(p->ruby__end__seen);
}
+/*
+ * call-seq:
+ * ripper.encoding -> encoding
+ *
+ * Return encoding of the source.
+ */
VALUE
-rb_ruby_parser_parsing_thread(rb_parser_t *p)
+rb_parser_encoding(VALUE vparser)
{
- return p->parsing_thread;
-}
+ struct parser_params *p;
-void
-rb_ruby_parser_set_parsing_thread(rb_parser_t *p, VALUE parsing_thread)
-{
- p->parsing_thread = parsing_thread;
+ TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
+ return rb_enc_from_encoding(p->enc);
}
-void
-rb_ruby_parser_ripper_initialize(rb_parser_t *p, rb_parser_lex_gets_func *gets, rb_parser_input_data input, VALUE sourcefile_string, const char *sourcefile, int sourceline)
+#ifdef RIPPER
+/*
+ * call-seq:
+ * ripper.yydebug -> true or false
+ *
+ * Get yydebug.
+ */
+VALUE
+rb_parser_get_yydebug(VALUE self)
{
- p->lex.gets = gets;
- p->lex.input = input;
- p->eofp = 0;
- p->ruby_sourcefile_string = sourcefile_string;
- p->ruby_sourcefile = sourcefile;
- p->ruby_sourceline = sourceline;
+ struct parser_params *p;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ return RBOOL(p->debug);
}
+#endif
+/*
+ * call-seq:
+ * ripper.yydebug = flag
+ *
+ * Set yydebug.
+ */
VALUE
-rb_ruby_parser_result(rb_parser_t *p)
+rb_parser_set_yydebug(VALUE self, VALUE flag)
{
- return p->result;
-}
+ struct parser_params *p;
-rb_encoding *
-rb_ruby_parser_enc(rb_parser_t *p)
-{
- return p->enc;
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ p->debug = RTEST(flag);
+ return flag;
}
+/*
+ * call-seq:
+ * ripper.debug_output -> obj
+ *
+ * Get debug output.
+ */
VALUE
-rb_ruby_parser_ruby_sourcefile_string(rb_parser_t *p)
+rb_parser_get_debug_output(VALUE self)
{
- return p->ruby_sourcefile_string;
-}
+ struct parser_params *p;
-int
-rb_ruby_parser_ruby_sourceline(rb_parser_t *p)
-{
- return p->ruby_sourceline;
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ return p->debug_output;
}
-int
-rb_ruby_parser_lex_state(rb_parser_t *p)
+/*
+ * call-seq:
+ * ripper.debug_output = obj
+ *
+ * Set debug output.
+ */
+VALUE
+rb_parser_set_debug_output(VALUE self, VALUE output)
{
- return p->lex.state;
-}
+ struct parser_params *p;
-void
-rb_ruby_ripper_parse0(rb_parser_t *p)
-{
- parser_prepare(p);
- p->ast = rb_ast_new();
- ripper_yyparse((void*)p);
- rb_ast_free(p->ast);
- p->ast = 0;
- p->eval_tree = 0;
- p->eval_tree_begin = 0;
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ return p->debug_output = output;
}
-int
-rb_ruby_ripper_dedent_string(rb_parser_t *p, rb_parser_string_t *string, int width)
-{
- return dedent_string(p, string, width);
-}
+#ifndef RIPPER
+#ifdef YYMALLOC
+#define HEAPCNT(n, size) ((n) * (size) / sizeof(YYSTYPE))
+/* Keep the order; NEWHEAP then xmalloc and ADD2HEAP to get rid of
+ * potential memory leak */
+#define NEWHEAP() rb_imemo_tmpbuf_parser_heap(0, p->heap, 0)
+#define ADD2HEAP(new, cnt, ptr) ((p->heap = (new))->ptr = (ptr), \
+ (new)->cnt = (cnt), (ptr))
-int
-rb_ruby_ripper_initialized_p(rb_parser_t *p)
+void *
+rb_parser_malloc(struct parser_params *p, size_t size)
{
- return p->lex.input != 0;
-}
+ size_t cnt = HEAPCNT(1, size);
+ rb_imemo_tmpbuf_t *n = NEWHEAP();
+ void *ptr = xmalloc(size);
-void
-rb_ruby_ripper_parser_initialize(rb_parser_t *p)
-{
- parser_initialize(p);
+ return ADD2HEAP(n, cnt, ptr);
}
-long
-rb_ruby_ripper_column(rb_parser_t *p)
+void *
+rb_parser_calloc(struct parser_params *p, size_t nelem, size_t size)
{
- return p->lex.ptok - p->lex.pbeg;
-}
+ size_t cnt = HEAPCNT(nelem, size);
+ rb_imemo_tmpbuf_t *n = NEWHEAP();
+ void *ptr = xcalloc(nelem, size);
-long
-rb_ruby_ripper_token_len(rb_parser_t *p)
-{
- return p->lex.pcur - p->lex.ptok;
+ return ADD2HEAP(n, cnt, ptr);
}
-rb_parser_string_t *
-rb_ruby_ripper_lex_lastline(rb_parser_t *p)
+void *
+rb_parser_realloc(struct parser_params *p, void *ptr, size_t size)
{
- return p->lex.lastline;
-}
+ rb_imemo_tmpbuf_t *n;
+ size_t cnt = HEAPCNT(1, size);
-VALUE
-rb_ruby_ripper_lex_state_name(struct parser_params *p, int state)
-{
- return rb_parser_lex_state_name(p, (enum lex_state_e)state);
+ if (ptr && (n = p->heap) != NULL) {
+ do {
+ if (n->ptr == ptr) {
+ n->ptr = ptr = xrealloc(ptr, size);
+ if (n->cnt) n->cnt = cnt;
+ return ptr;
+ }
+ } while ((n = n->next) != NULL);
+ }
+ n = NEWHEAP();
+ ptr = xrealloc(ptr, size);
+ return ADD2HEAP(n, cnt, ptr);
}
-#ifdef UNIVERSAL_PARSER
-rb_parser_t *
-rb_ripper_parser_params_allocate(const rb_parser_config_t *config)
+void
+rb_parser_free(struct parser_params *p, void *ptr)
{
- rb_parser_t *p = (rb_parser_t *)config->calloc(1, sizeof(rb_parser_t));
- p->config = config;
- return p;
-}
-#endif
+ rb_imemo_tmpbuf_t **prev = &p->heap, *n;
-struct parser_params*
-rb_ruby_ripper_parser_allocate(void)
-{
- return (struct parser_params *)ruby_xcalloc(1, sizeof(struct parser_params));
+ while ((n = *prev) != NULL) {
+ if (n->ptr == ptr) {
+ *prev = n->next;
+ break;
+ }
+ prev = &n->next;
+ }
}
-#endif /* RIPPER */
+#endif
-#ifndef RIPPER
void
rb_parser_printf(struct parser_params *p, const char *fmt, ...)
{
@@ -15943,35 +14134,26 @@ rb_parser_printf(struct parser_params *p, const char *fmt, ...)
va_start(ap, fmt);
rb_str_vcatf(mesg, fmt, ap);
va_end(ap);
- if (char_at_end(p, mesg, 0) == '\n') {
- rb_io_write(p->debug_output, mesg);
- p->debug_buffer = Qnil;
+ if (RSTRING_END(mesg)[-1] == '\n') {
+ rb_io_write(p->debug_output, mesg);
+ p->debug_buffer = Qnil;
}
}
static void
-parser_compile_error(struct parser_params *p, const rb_code_location_t *loc, const char *fmt, ...)
+parser_compile_error(struct parser_params *p, const char *fmt, ...)
{
va_list ap;
- int lineno, column;
-
- if (loc) {
- lineno = loc->end_pos.lineno;
- column = loc->end_pos.column;
- }
- else {
- lineno = p->ruby_sourceline;
- column = rb_long2int(p->lex.pcur - p->lex.pbeg);
- }
rb_io_flush(p->debug_output);
p->error_p = 1;
va_start(ap, fmt);
p->error_buffer =
- rb_syntax_error_append(p->error_buffer,
- p->ruby_sourcefile_string,
- lineno, column,
- p->enc, fmt, ap);
+ rb_syntax_error_append(p->error_buffer,
+ p->ruby_sourcefile_string,
+ p->ruby_sourceline,
+ rb_long2int(p->lex.pcur - p->lex.pbeg),
+ p->enc, fmt, ap);
va_end(ap);
}
@@ -15989,60 +14171,62 @@ count_char(const char *str, int c)
*
* "\"`class' keyword\"" => "`class' keyword"
*/
-size_t
+RUBY_FUNC_EXPORTED size_t
rb_yytnamerr(struct parser_params *p, char *yyres, const char *yystr)
{
if (*yystr == '"') {
- size_t yyn = 0, bquote = 0;
- const char *yyp = yystr;
-
- while (*++yyp) {
- switch (*yyp) {
- case '\'':
- if (!bquote) {
- bquote = count_char(yyp+1, '\'') + 1;
- if (yyres) memcpy(&yyres[yyn], yyp, bquote);
- yyn += bquote;
- yyp += bquote - 1;
- break;
- }
- else {
- if (bquote && count_char(yyp+1, '\'') + 1 == bquote) {
- if (yyres) memcpy(yyres + yyn, yyp, bquote);
- yyn += bquote;
- yyp += bquote - 1;
- bquote = 0;
- break;
- }
- if (yyp[1] && yyp[1] != '\'' && yyp[2] == '\'') {
- if (yyres) memcpy(yyres + yyn, yyp, 3);
- yyn += 3;
- yyp += 2;
- break;
- }
- goto do_not_strip_quotes;
- }
-
- case ',':
- goto do_not_strip_quotes;
-
- case '\\':
- if (*++yyp != '\\')
- goto do_not_strip_quotes;
- /* Fall through. */
- default:
- if (yyres)
- yyres[yyn] = *yyp;
- yyn++;
- break;
-
- case '"':
- case '\0':
- if (yyres)
- yyres[yyn] = '\0';
- return yyn;
- }
- }
+ size_t yyn = 0, bquote = 0;
+ const char *yyp = yystr;
+
+ while (*++yyp) {
+ switch (*yyp) {
+ case '`':
+ if (!bquote) {
+ bquote = count_char(yyp+1, '`') + 1;
+ if (yyres) memcpy(&yyres[yyn], yyp, bquote);
+ yyn += bquote;
+ yyp += bquote - 1;
+ break;
+ }
+ goto default_char;
+
+ case '\'':
+ if (bquote && count_char(yyp+1, '\'') + 1 == bquote) {
+ if (yyres) memcpy(yyres + yyn, yyp, bquote);
+ yyn += bquote;
+ yyp += bquote - 1;
+ bquote = 0;
+ break;
+ }
+ if (yyp[1] && yyp[1] != '\'' && yyp[2] == '\'') {
+ if (yyres) memcpy(yyres + yyn, yyp, 3);
+ yyn += 3;
+ yyp += 2;
+ break;
+ }
+ goto do_not_strip_quotes;
+
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default_char:
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ case '\0':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ }
do_not_strip_quotes: ;
}
@@ -16053,7 +14237,46 @@ rb_yytnamerr(struct parser_params *p, char *yyres, const char *yystr)
#endif
#ifdef RIPPER
-#define validate(x) (void)(x)
+#ifdef RIPPER_DEBUG
+/* :nodoc: */
+static VALUE
+ripper_validate_object(VALUE self, VALUE x)
+{
+ if (x == Qfalse) return x;
+ if (x == Qtrue) return x;
+ if (NIL_P(x)) return x;
+ if (UNDEF_P(x))
+ rb_raise(rb_eArgError, "Qundef given");
+ if (FIXNUM_P(x)) return x;
+ if (SYMBOL_P(x)) return x;
+ switch (BUILTIN_TYPE(x)) {
+ case T_STRING:
+ case T_OBJECT:
+ case T_ARRAY:
+ case T_BIGNUM:
+ case T_FLOAT:
+ case T_COMPLEX:
+ case T_RATIONAL:
+ break;
+ case T_NODE:
+ if (!nd_type_p((NODE *)x, NODE_RIPPER)) {
+ rb_raise(rb_eArgError, "NODE given: %p", (void *)x);
+ }
+ x = ((NODE *)x)->nd_rval;
+ break;
+ default:
+ rb_raise(rb_eArgError, "wrong type of ruby object: %p (%s)",
+ (void *)x, rb_obj_classname(x));
+ }
+ if (!RBASIC_CLASS(x)) {
+ rb_raise(rb_eArgError, "hidden ruby object: %p (%s)",
+ (void *)x, rb_builtin_type_name(TYPE(x)));
+ }
+ return x;
+}
+#endif
+
+#define validate(x) ((x) = get_value(x))
static VALUE
ripper_dispatch0(struct parser_params *p, ID mid)
@@ -16119,21 +14342,377 @@ ripper_dispatch7(struct parser_params *p, ID mid, VALUE a, VALUE b, VALUE c, VAL
return rb_funcall(p->value, mid, 7, a, b, c, d, e, f, g);
}
-void
+static ID
+ripper_get_id(VALUE v)
+{
+ NODE *nd;
+ if (!RB_TYPE_P(v, T_NODE)) return 0;
+ nd = (NODE *)v;
+ if (!nd_type_p(nd, NODE_RIPPER)) return 0;
+ return nd->nd_vid;
+}
+
+static VALUE
+ripper_get_value(VALUE v)
+{
+ NODE *nd;
+ if (UNDEF_P(v)) return Qnil;
+ if (!RB_TYPE_P(v, T_NODE)) return v;
+ nd = (NODE *)v;
+ if (!nd_type_p(nd, NODE_RIPPER)) return Qnil;
+ return nd->nd_rval;
+}
+
+static void
ripper_error(struct parser_params *p)
{
p->error_p = TRUE;
}
-VALUE
-ripper_value(struct parser_params *p)
+static void
+ripper_compile_error(struct parser_params *p, const char *fmt, ...)
+{
+ VALUE str;
+ va_list args;
+
+ va_start(args, fmt);
+ str = rb_vsprintf(fmt, args);
+ va_end(args);
+ rb_funcall(p->value, rb_intern("compile_error"), 1, str);
+ ripper_error(p);
+}
+
+static VALUE
+ripper_lex_get_generic(struct parser_params *p, VALUE src)
+{
+ VALUE line = rb_funcallv_public(src, id_gets, 0, 0);
+ if (!NIL_P(line) && !RB_TYPE_P(line, T_STRING)) {
+ rb_raise(rb_eTypeError,
+ "gets returned %"PRIsVALUE" (expected String or nil)",
+ rb_obj_class(line));
+ }
+ return line;
+}
+
+static VALUE
+ripper_lex_io_get(struct parser_params *p, VALUE src)
+{
+ return rb_io_gets(src);
+}
+
+static VALUE
+ripper_s_allocate(VALUE klass)
+{
+ struct parser_params *p;
+ VALUE self = TypedData_Make_Struct(klass, struct parser_params,
+ &parser_data_type, p);
+ p->value = self;
+ return self;
+}
+
+#define ripper_initialized_p(r) ((r)->lex.input != 0)
+
+/*
+ * call-seq:
+ * Ripper.new(src, filename="(ripper)", lineno=1) -> ripper
+ *
+ * Create a new Ripper object.
+ * _src_ must be a String, an IO, or an Object which has #gets method.
+ *
+ * This method does not starts parsing.
+ * See also Ripper#parse and Ripper.parse.
+ */
+static VALUE
+ripper_initialize(int argc, VALUE *argv, VALUE self)
{
+ struct parser_params *p;
+ VALUE src, fname, lineno;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ rb_scan_args(argc, argv, "12", &src, &fname, &lineno);
+ if (RB_TYPE_P(src, T_FILE)) {
+ p->lex.gets = ripper_lex_io_get;
+ }
+ else if (rb_respond_to(src, id_gets)) {
+ p->lex.gets = ripper_lex_get_generic;
+ }
+ else {
+ StringValue(src);
+ p->lex.gets = lex_get_str;
+ }
+ p->lex.input = src;
+ p->eofp = 0;
+ if (NIL_P(fname)) {
+ fname = STR_NEW2("(ripper)");
+ OBJ_FREEZE(fname);
+ }
+ else {
+ StringValueCStr(fname);
+ fname = rb_str_new_frozen(fname);
+ }
+ parser_initialize(p);
+
+ p->ruby_sourcefile_string = fname;
+ p->ruby_sourcefile = RSTRING_PTR(fname);
+ p->ruby_sourceline = NIL_P(lineno) ? 0 : NUM2INT(lineno) - 1;
+
+ return Qnil;
+}
+
+static VALUE
+ripper_parse0(VALUE parser_v)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(parser_v, struct parser_params, &parser_data_type, p);
+ parser_prepare(p);
+ p->ast = rb_ast_new();
+ ripper_yyparse((void*)p);
+ rb_ast_dispose(p->ast);
+ p->ast = 0;
+ return p->result;
+}
+
+static VALUE
+ripper_ensure(VALUE parser_v)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(parser_v, struct parser_params, &parser_data_type, p);
+ p->parsing_thread = Qnil;
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * ripper.parse
+ *
+ * Start parsing and returns the value of the root action.
+ */
+static VALUE
+ripper_parse(VALUE self)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ if (!ripper_initialized_p(p)) {
+ rb_raise(rb_eArgError, "method called for uninitialized object");
+ }
+ if (!NIL_P(p->parsing_thread)) {
+ if (p->parsing_thread == rb_thread_current())
+ rb_raise(rb_eArgError, "Ripper#parse is not reentrant");
+ else
+ rb_raise(rb_eArgError, "Ripper#parse is not multithread-safe");
+ }
+ p->parsing_thread = rb_thread_current();
+ rb_ensure(ripper_parse0, self, ripper_ensure, self);
+
+ return p->result;
+}
+
+/*
+ * call-seq:
+ * ripper.column -> Integer
+ *
+ * Return column number of current parsing line.
+ * This number starts from 0.
+ */
+static VALUE
+ripper_column(VALUE self)
+{
+ struct parser_params *p;
+ long col;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ if (!ripper_initialized_p(p)) {
+ rb_raise(rb_eArgError, "method called for uninitialized object");
+ }
+ if (NIL_P(p->parsing_thread)) return Qnil;
+ col = p->lex.ptok - p->lex.pbeg;
+ return LONG2NUM(col);
+}
+
+/*
+ * call-seq:
+ * ripper.filename -> String
+ *
+ * Return current parsing filename.
+ */
+static VALUE
+ripper_filename(VALUE self)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ if (!ripper_initialized_p(p)) {
+ rb_raise(rb_eArgError, "method called for uninitialized object");
+ }
+ return p->ruby_sourcefile_string;
+}
+
+/*
+ * call-seq:
+ * ripper.lineno -> Integer
+ *
+ * Return line number of current parsing line.
+ * This number starts from 1.
+ */
+static VALUE
+ripper_lineno(VALUE self)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ if (!ripper_initialized_p(p)) {
+ rb_raise(rb_eArgError, "method called for uninitialized object");
+ }
+ if (NIL_P(p->parsing_thread)) return Qnil;
+ return INT2NUM(p->ruby_sourceline);
+}
+
+/*
+ * call-seq:
+ * ripper.state -> Integer
+ *
+ * Return scanner state of current token.
+ */
+static VALUE
+ripper_state(VALUE self)
+{
+ struct parser_params *p;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ if (!ripper_initialized_p(p)) {
+ rb_raise(rb_eArgError, "method called for uninitialized object");
+ }
+ if (NIL_P(p->parsing_thread)) return Qnil;
+ return INT2NUM(p->lex.state);
+}
+
+/*
+ * call-seq:
+ * ripper.token -> String
+ *
+ * Return the current token string.
+ */
+static VALUE
+ripper_token(VALUE self)
+{
+ struct parser_params *p;
+ long pos, len;
+
+ TypedData_Get_Struct(self, struct parser_params, &parser_data_type, p);
+ if (!ripper_initialized_p(p)) {
+ rb_raise(rb_eArgError, "method called for uninitialized object");
+ }
+ if (NIL_P(p->parsing_thread)) return Qnil;
+ pos = p->lex.ptok - p->lex.pbeg;
+ len = p->lex.pcur - p->lex.ptok;
+ return rb_str_subseq(p->lex.lastline, pos, len);
+}
+
+#ifdef RIPPER_DEBUG
+/* :nodoc: */
+static VALUE
+ripper_assert_Qundef(VALUE self, VALUE obj, VALUE msg)
+{
+ StringValue(msg);
+ if (UNDEF_P(obj)) {
+ rb_raise(rb_eArgError, "%"PRIsVALUE, msg);
+ }
+ return Qnil;
+}
+
+/* :nodoc: */
+static VALUE
+ripper_value(VALUE self, VALUE obj)
+{
+ return ULONG2NUM(obj);
+}
+#endif
+
+/*
+ * call-seq:
+ * Ripper.lex_state_name(integer) -> string
+ *
+ * Returns a string representation of lex_state.
+ */
+static VALUE
+ripper_lex_state_name(VALUE self, VALUE state)
+{
+ return rb_parser_lex_state_name(NUM2INT(state));
+}
+
+void
+Init_ripper(void)
+{
+ ripper_init_eventids1();
+ ripper_init_eventids2();
+ id_warn = rb_intern_const("warn");
+ id_warning = rb_intern_const("warning");
+ id_gets = rb_intern_const("gets");
+ id_assoc = rb_intern_const("=>");
+
(void)yystpcpy; /* may not used in newer bison */
- return p->value;
+ InitVM(ripper);
}
+void
+InitVM_ripper(void)
+{
+ VALUE Ripper;
+
+ Ripper = rb_define_class("Ripper", rb_cObject);
+ /* version of Ripper */
+ rb_define_const(Ripper, "Version", rb_usascii_str_new2(RIPPER_VERSION));
+ rb_define_alloc_func(Ripper, ripper_s_allocate);
+ rb_define_method(Ripper, "initialize", ripper_initialize, -1);
+ rb_define_method(Ripper, "parse", ripper_parse, 0);
+ rb_define_method(Ripper, "column", ripper_column, 0);
+ rb_define_method(Ripper, "filename", ripper_filename, 0);
+ rb_define_method(Ripper, "lineno", ripper_lineno, 0);
+ rb_define_method(Ripper, "state", ripper_state, 0);
+ rb_define_method(Ripper, "token", ripper_token, 0);
+ rb_define_method(Ripper, "end_seen?", rb_parser_end_seen_p, 0);
+ rb_define_method(Ripper, "encoding", rb_parser_encoding, 0);
+ rb_define_method(Ripper, "yydebug", rb_parser_get_yydebug, 0);
+ rb_define_method(Ripper, "yydebug=", rb_parser_set_yydebug, 1);
+ rb_define_method(Ripper, "debug_output", rb_parser_get_debug_output, 0);
+ rb_define_method(Ripper, "debug_output=", rb_parser_set_debug_output, 1);
+ rb_define_method(Ripper, "error?", ripper_error_p, 0);
+#ifdef RIPPER_DEBUG
+ rb_define_method(Ripper, "assert_Qundef", ripper_assert_Qundef, 2);
+ rb_define_method(Ripper, "rawVALUE", ripper_value, 1);
+ rb_define_method(Ripper, "validate_object", ripper_validate_object, 1);
+#endif
+
+ rb_define_singleton_method(Ripper, "dedent_string", parser_dedent_string, 2);
+ rb_define_private_method(Ripper, "dedent_string", parser_dedent_string, 2);
+
+ rb_define_singleton_method(Ripper, "lex_state_name", ripper_lex_state_name, 1);
+
+<% @exprs.each do |expr, desc| -%>
+ /* <%=desc%> */
+ rb_define_const(Ripper, "<%=expr%>", INT2NUM(<%=expr%>));
+<% end %>
+ ripper_init_eventids1_table(Ripper);
+ ripper_init_eventids2_table(Ripper);
+
+# if 0
+ /* Hack to let RDoc document SCRIPT_LINES__ */
+
+ /*
+ * When a Hash is assigned to +SCRIPT_LINES__+ the contents of files loaded
+ * after the assignment will be added as an Array of lines with the file
+ * name as the key.
+ */
+ rb_define_global_const("SCRIPT_LINES__", Qnil);
+#endif
+
+}
#endif /* RIPPER */
+
/*
* Local variables:
* mode: c
diff --git a/parser_bits.h b/parser_bits.h
deleted file mode 100644
index ca7535280e..0000000000
--- a/parser_bits.h
+++ /dev/null
@@ -1,564 +0,0 @@
-#ifndef INTERNAL_BITS2_H /*-*-C-*-vi:se ft=c:*/
-#define INTERNAL_BITS2_H
-/**
- * @author Ruby developers <ruby-core@ruby-lang.org>
- * @copyright This file is a part of the programming language Ruby.
- * Permission is hereby granted, to either redistribute and/or
- * modify this file, provided that the conditions mentioned in the
- * file COPYING are met. Consult the file for details.
- * @brief Internal header for bitwise integer algorithms.
- * @see Henry S. Warren Jr., "Hacker's Delight" (2nd ed.), 2013.
- * @see SEI CERT C Coding Standard INT32-C. "Ensure that operations on
- * signed integers do not result in overflow"
- * @see https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
- * @see https://clang.llvm.org/docs/LanguageExtensions.html#builtin-rotateleft
- * @see https://clang.llvm.org/docs/LanguageExtensions.html#builtin-rotateright
- * @see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/byteswap-uint64-byteswap-ulong-byteswap-ushort
- * @see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/rotl-rotl64-rotr-rotr64
- * @see https://docs.microsoft.com/en-us/cpp/intrinsics/bitscanforward-bitscanforward64
- * @see https://docs.microsoft.com/en-us/cpp/intrinsics/bitscanreverse-bitscanreverse64
- * @see https://docs.microsoft.com/en-us/cpp/intrinsics/lzcnt16-lzcnt-lzcnt64
- * @see https://docs.microsoft.com/en-us/cpp/intrinsics/popcnt16-popcnt-popcnt64
- * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_lzcnt_u32
- * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_tzcnt_u32
- * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_rotl64
- * @see https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_rotr64
- * @see https://stackoverflow.com/a/776523
- */
-#include "ruby/internal/config.h"
-#include <limits.h> /* for CHAR_BITS */
-#include <stdint.h> /* for uintptr_t */
-#include "internal/compilers.h" /* for MSC_VERSION_SINCE */
-
-#if MSC_VERSION_SINCE(1310)
-# include <stdlib.h> /* for _byteswap_uint64 */
-#endif
-
-#if defined(HAVE_X86INTRIN_H)
-# include <x86intrin.h> /* for _lzcnt_u64 */
-#elif MSC_VERSION_SINCE(1310)
-# include <intrin.h> /* for the following intrinsics */
-#endif
-
-#if defined(_MSC_VER) && defined(__AVX__)
-# pragma intrinsic(__popcnt)
-# pragma intrinsic(__popcnt64)
-#endif
-
-#if defined(_MSC_VER) && defined(__AVX2__)
-# pragma intrinsic(__lzcnt)
-# pragma intrinsic(__lzcnt64)
-#endif
-
-#if MSC_VERSION_SINCE(1310)
-# pragma intrinsic(_rotl)
-# pragma intrinsic(_rotr)
-# ifdef _WIN64
-# pragma intrinsic(_rotl64)
-# pragma intrinsic(_rotr64)
-# endif
-#endif
-
-#if MSC_VERSION_SINCE(1400)
-# pragma intrinsic(_BitScanForward)
-# pragma intrinsic(_BitScanReverse)
-# ifdef _WIN64
-# pragma intrinsic(_BitScanForward64)
-# pragma intrinsic(_BitScanReverse64)
-# endif
-#endif
-
-#include "parser_value.h" /* for VALUE */
-#include "internal/static_assert.h" /* for STATIC_ASSERT */
-
-/* The most significant bit of the lower part of half-long integer.
- * If sizeof(long) == 4, this is 0x8000.
- * If sizeof(long) == 8, this is 0x80000000.
- */
-#define HALF_LONG_MSB ((SIGNED_VALUE)1<<((SIZEOF_LONG*CHAR_BIT-1)/2))
-
-#define SIGNED_INTEGER_TYPE_P(T) (0 > ((T)0)-1)
-
-#define SIGNED_INTEGER_MIN(T) \
- ((sizeof(T) == sizeof(int8_t)) ? ((T)INT8_MIN) : \
- ((sizeof(T) == sizeof(int16_t)) ? ((T)INT16_MIN) : \
- ((sizeof(T) == sizeof(int32_t)) ? ((T)INT32_MIN) : \
- ((sizeof(T) == sizeof(int64_t)) ? ((T)INT64_MIN) : \
- 0))))
-
-#define SIGNED_INTEGER_MAX(T) ((T)(SIGNED_INTEGER_MIN(T) ^ ((T)~(T)0)))
-
-#define UNSIGNED_INTEGER_MAX(T) ((T)~(T)0)
-
-#if __has_builtin(__builtin_mul_overflow_p)
-# define MUL_OVERFLOW_P(a, b) \
- __builtin_mul_overflow_p((a), (b), (__typeof__(a * b))0)
-#elif __has_builtin(__builtin_mul_overflow)
-# define MUL_OVERFLOW_P(a, b) \
- __extension__ ({ __typeof__(a) c; __builtin_mul_overflow((a), (b), &c); })
-#endif
-
-#define MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, min, max) ( \
- (a) == 0 ? 0 : \
- (a) == -1 ? (b) < -(max) : \
- (a) > 0 ? \
- ((b) > 0 ? (max) / (a) < (b) : (min) / (a) > (b)) : \
- ((b) > 0 ? (min) / (a) < (b) : (max) / (a) > (b)))
-
-#if __has_builtin(__builtin_mul_overflow_p)
-/* __builtin_mul_overflow_p can take bitfield */
-/* and GCC permits bitfields for integers other than int */
-# define MUL_OVERFLOW_FIXNUM_P(a, b) \
- __extension__ ({ \
- struct { long fixnum : sizeof(long) * CHAR_BIT - 1; } c = { 0 }; \
- __builtin_mul_overflow_p((a), (b), c.fixnum); \
- })
-#else
-# define MUL_OVERFLOW_FIXNUM_P(a, b) \
- MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, FIXNUM_MIN, FIXNUM_MAX)
-#endif
-
-#ifdef MUL_OVERFLOW_P
-# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_P(a, b)
-# define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_P(a, b)
-# define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_P(a, b)
-#else
-# define MUL_OVERFLOW_LONG_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LLONG_MIN, LLONG_MAX)
-# define MUL_OVERFLOW_LONG_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, LONG_MIN, LONG_MAX)
-# define MUL_OVERFLOW_INT_P(a, b) MUL_OVERFLOW_SIGNED_INTEGER_P(a, b, INT_MIN, INT_MAX)
-#endif
-
-#ifdef HAVE_UINT128_T
-# define bit_length(x) \
- (unsigned int) \
- (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \
- sizeof(x) <= sizeof(int64_t) ? 64 - nlz_int64((uint64_t)(x)) : \
- 128 - nlz_int128((uint128_t)(x)))
-#else
-# define bit_length(x) \
- (unsigned int) \
- (sizeof(x) <= sizeof(int32_t) ? 32 - nlz_int32((uint32_t)(x)) : \
- 64 - nlz_int64((uint64_t)(x)))
-#endif
-
-#ifndef swap16
-# define swap16 ruby_swap16
-#endif
-
-#ifndef swap32
-# define swap32 ruby_swap32
-#endif
-
-#ifndef swap64
-# define swap64 ruby_swap64
-#endif
-
-static inline uint16_t ruby_swap16(uint16_t);
-static inline uint32_t ruby_swap32(uint32_t);
-static inline uint64_t ruby_swap64(uint64_t);
-static inline unsigned nlz_int(unsigned x);
-static inline unsigned nlz_long(unsigned long x);
-static inline unsigned nlz_long_long(unsigned long long x);
-static inline unsigned nlz_intptr(uintptr_t x);
-static inline unsigned nlz_int32(uint32_t x);
-static inline unsigned nlz_int64(uint64_t x);
-#ifdef HAVE_UINT128_T
-static inline unsigned nlz_int128(uint128_t x);
-#endif
-static inline unsigned rb_popcount32(uint32_t x);
-static inline unsigned rb_popcount64(uint64_t x);
-static inline unsigned rb_popcount_intptr(uintptr_t x);
-static inline int ntz_int32(uint32_t x);
-static inline int ntz_int64(uint64_t x);
-static inline int ntz_intptr(uintptr_t x);
-static inline VALUE RUBY_BIT_ROTL(VALUE, int);
-static inline VALUE RUBY_BIT_ROTR(VALUE, int);
-
-static inline uint16_t
-ruby_swap16(uint16_t x)
-{
-#if __has_builtin(__builtin_bswap16)
- return __builtin_bswap16(x);
-
-#elif MSC_VERSION_SINCE(1310)
- return _byteswap_ushort(x);
-
-#else
- return (x << 8) | (x >> 8);
-
-#endif
-}
-
-static inline uint32_t
-ruby_swap32(uint32_t x)
-{
-#if __has_builtin(__builtin_bswap32)
- return __builtin_bswap32(x);
-
-#elif MSC_VERSION_SINCE(1310)
- return _byteswap_ulong(x);
-
-#else
- x = ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16);
- x = ((x & 0x00FF00FF) << 8) | ((x & 0xFF00FF00) >> 8);
- return x;
-
-#endif
-}
-
-static inline uint64_t
-ruby_swap64(uint64_t x)
-{
-#if __has_builtin(__builtin_bswap64)
- return __builtin_bswap64(x);
-
-#elif MSC_VERSION_SINCE(1310)
- return _byteswap_uint64(x);
-
-#else
- x = ((x & 0x00000000FFFFFFFFULL) << 32) | ((x & 0xFFFFFFFF00000000ULL) >> 32);
- x = ((x & 0x0000FFFF0000FFFFULL) << 16) | ((x & 0xFFFF0000FFFF0000ULL) >> 16);
- x = ((x & 0x00FF00FF00FF00FFULL) << 8) | ((x & 0xFF00FF00FF00FF00ULL) >> 8);
- return x;
-
-#endif
-}
-
-static inline unsigned int
-nlz_int32(uint32_t x)
-{
-#if defined(_MSC_VER) && defined(__AVX2__)
- /* Note: It seems there is no such thing like __LZCNT__ predefined in MSVC.
- * AMD CPUs have had this instruction for decades (since K10) but for
- * Intel, Haswell is the oldest one. We need to use __AVX2__ for maximum
- * safety. */
- return (unsigned int)__lzcnt(x);
-
-#elif defined(__x86_64__) && defined(__LZCNT__)
- return (unsigned int)_lzcnt_u32(x);
-
-#elif MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
- unsigned long r;
- return _BitScanReverse(&r, x) ? (31 - (int)r) : 32;
-
-#elif __has_builtin(__builtin_clz)
- STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT == 32);
- return x ? (unsigned int)__builtin_clz(x) : 32;
-
-#else
- uint32_t y;
- unsigned n = 32;
- y = x >> 16; if (y) {n -= 16; x = y;}
- y = x >> 8; if (y) {n -= 8; x = y;}
- y = x >> 4; if (y) {n -= 4; x = y;}
- y = x >> 2; if (y) {n -= 2; x = y;}
- y = x >> 1; if (y) {return n - 2;}
- return (unsigned int)(n - x);
-#endif
-}
-
-static inline unsigned int
-nlz_int64(uint64_t x)
-{
-#if defined(_MSC_VER) && defined(__AVX2__)
- return (unsigned int)__lzcnt64(x);
-
-#elif defined(__x86_64__) && defined(__LZCNT__)
- return (unsigned int)_lzcnt_u64(x);
-
-#elif defined(_WIN64) && MSC_VERSION_SINCE(1400) /* &&! defined(__AVX2__) */
- unsigned long r;
- return _BitScanReverse64(&r, x) ? (63u - (unsigned int)r) : 64;
-
-#elif __has_builtin(__builtin_clzl)
- if (x == 0) {
- return 64;
- }
- else if (sizeof(long) * CHAR_BIT == 64) {
- return (unsigned int)__builtin_clzl((unsigned long)x);
- }
- else if (sizeof(long long) * CHAR_BIT == 64) {
- return (unsigned int)__builtin_clzll((unsigned long long)x);
- }
- else {
- /* :FIXME: Is there a way to make this branch a compile-time error? */
- UNREACHABLE_RETURN(~0);
- }
-
-#else
- uint64_t y;
- unsigned int n = 64;
- y = x >> 32; if (y) {n -= 32; x = y;}
- y = x >> 16; if (y) {n -= 16; x = y;}
- y = x >> 8; if (y) {n -= 8; x = y;}
- y = x >> 4; if (y) {n -= 4; x = y;}
- y = x >> 2; if (y) {n -= 2; x = y;}
- y = x >> 1; if (y) {return n - 2;}
- return (unsigned int)(n - x);
-
-#endif
-}
-
-#ifdef HAVE_UINT128_T
-static inline unsigned int
-nlz_int128(uint128_t x)
-{
- uint64_t y = (uint64_t)(x >> 64);
-
- if (x == 0) {
- return 128;
- }
- else if (y == 0) {
- return (unsigned int)nlz_int64(x) + 64;
- }
- else {
- return (unsigned int)nlz_int64(y);
- }
-}
-#endif
-
-static inline unsigned int
-nlz_int(unsigned int x)
-{
- if (sizeof(unsigned int) * CHAR_BIT == 32) {
- return nlz_int32((uint32_t)x);
- }
- else if (sizeof(unsigned int) * CHAR_BIT == 64) {
- return nlz_int64((uint64_t)x);
- }
- else {
- UNREACHABLE_RETURN(~0);
- }
-}
-
-static inline unsigned int
-nlz_long(unsigned long x)
-{
- if (sizeof(unsigned long) * CHAR_BIT == 32) {
- return nlz_int32((uint32_t)x);
- }
- else if (sizeof(unsigned long) * CHAR_BIT == 64) {
- return nlz_int64((uint64_t)x);
- }
- else {
- UNREACHABLE_RETURN(~0);
- }
-}
-
-static inline unsigned int
-nlz_long_long(unsigned long long x)
-{
- if (sizeof(unsigned long long) * CHAR_BIT == 64) {
- return nlz_int64((uint64_t)x);
- }
-#ifdef HAVE_UINT128_T
- else if (sizeof(unsigned long long) * CHAR_BIT == 128) {
- return nlz_int128((uint128_t)x);
- }
-#endif
- else {
- UNREACHABLE_RETURN(~0);
- }
-}
-
-static inline unsigned int
-nlz_intptr(uintptr_t x)
-{
- if (sizeof(uintptr_t) == sizeof(unsigned int)) {
- return nlz_int((unsigned int)x);
- }
- if (sizeof(uintptr_t) == sizeof(unsigned long)) {
- return nlz_long((unsigned long)x);
- }
- if (sizeof(uintptr_t) == sizeof(unsigned long long)) {
- return nlz_long_long((unsigned long long)x);
- }
- else {
- UNREACHABLE_RETURN(~0);
- }
-}
-
-static inline unsigned int
-rb_popcount32(uint32_t x)
-{
-#if defined(_MSC_VER) && defined(__AVX__)
- /* Note: CPUs since Nehalem and Barcelona have had this instruction so SSE
- * 4.2 should suffice, but it seems there is no such thing like __SSE_4_2__
- * predefined macro in MSVC. They do have __AVX__ so use it instead. */
- return (unsigned int)__popcnt(x);
-
-#elif __has_builtin(__builtin_popcount)
- STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT >= 32);
- return (unsigned int)__builtin_popcount(x);
-
-#else
- x = (x & 0x55555555) + (x >> 1 & 0x55555555);
- x = (x & 0x33333333) + (x >> 2 & 0x33333333);
- x = (x & 0x0f0f0f0f) + (x >> 4 & 0x0f0f0f0f);
- x = (x & 0x001f001f) + (x >> 8 & 0x001f001f);
- x = (x & 0x0000003f) + (x >>16 & 0x0000003f);
- return (unsigned int)x;
-
-#endif
-}
-
-static inline unsigned int
-rb_popcount64(uint64_t x)
-{
-#if defined(_MSC_VER) && defined(__AVX__)
- return (unsigned int)__popcnt64(x);
-
-#elif __has_builtin(__builtin_popcount)
- if (sizeof(long) * CHAR_BIT == 64) {
- return (unsigned int)__builtin_popcountl((unsigned long)x);
- }
- else if (sizeof(long long) * CHAR_BIT == 64) {
- return (unsigned int)__builtin_popcountll((unsigned long long)x);
- }
- else {
- /* :FIXME: Is there a way to make this branch a compile-time error? */
- UNREACHABLE_RETURN(~0);
- }
-
-#else
- x = (x & 0x5555555555555555) + (x >> 1 & 0x5555555555555555);
- x = (x & 0x3333333333333333) + (x >> 2 & 0x3333333333333333);
- x = (x & 0x0707070707070707) + (x >> 4 & 0x0707070707070707);
- x = (x & 0x001f001f001f001f) + (x >> 8 & 0x001f001f001f001f);
- x = (x & 0x0000003f0000003f) + (x >>16 & 0x0000003f0000003f);
- x = (x & 0x000000000000007f) + (x >>32 & 0x000000000000007f);
- return (unsigned int)x;
-
-#endif
-}
-
-static inline unsigned int
-rb_popcount_intptr(uintptr_t x)
-{
- if (sizeof(uintptr_t) * CHAR_BIT == 64) {
- return rb_popcount64((uint64_t)x);
- }
- else if (sizeof(uintptr_t) * CHAR_BIT == 32) {
- return rb_popcount32((uint32_t)x);
- }
- else {
- UNREACHABLE_RETURN(~0);
- }
-}
-
-static inline int
-ntz_int32(uint32_t x)
-{
-#if defined(__x86_64__) && defined(__BMI__)
- return (unsigned)_tzcnt_u32(x);
-
-#elif MSC_VERSION_SINCE(1400)
- /* :FIXME: Is there any way to issue TZCNT instead of BSF, apart from using
- * assembly? Because issuing LZCNT seems possible (see nlz.h). */
- unsigned long r;
- return _BitScanForward(&r, x) ? (int)r : 32;
-
-#elif __has_builtin(__builtin_ctz)
- STATIC_ASSERT(sizeof_int, sizeof(int) * CHAR_BIT == 32);
- return x ? (unsigned)__builtin_ctz(x) : 32;
-
-#else
- return rb_popcount32((~x) & (x-1));
-
-#endif
-}
-
-static inline int
-ntz_int64(uint64_t x)
-{
-#if defined(__x86_64__) && defined(__BMI__)
- return (unsigned)_tzcnt_u64(x);
-
-#elif defined(_WIN64) && MSC_VERSION_SINCE(1400)
- unsigned long r;
- return _BitScanForward64(&r, x) ? (int)r : 64;
-
-#elif __has_builtin(__builtin_ctzl)
- if (x == 0) {
- return 64;
- }
- else if (sizeof(long) * CHAR_BIT == 64) {
- return (unsigned)__builtin_ctzl((unsigned long)x);
- }
- else if (sizeof(long long) * CHAR_BIT == 64) {
- return (unsigned)__builtin_ctzll((unsigned long long)x);
- }
- else {
- /* :FIXME: Is there a way to make this branch a compile-time error? */
- UNREACHABLE_RETURN(~0);
- }
-
-#else
- return rb_popcount64((~x) & (x-1));
-
-#endif
-}
-
-static inline int
-ntz_intptr(uintptr_t x)
-{
- if (sizeof(uintptr_t) * CHAR_BIT == 64) {
- return ntz_int64((uint64_t)x);
- }
- else if (sizeof(uintptr_t) * CHAR_BIT == 32) {
- return ntz_int32((uint32_t)x);
- }
- else {
- UNREACHABLE_RETURN(~0);
- }
-}
-
-static inline VALUE
-RUBY_BIT_ROTL(VALUE v, int n)
-{
-#if __has_builtin(__builtin_rotateleft32) && (SIZEOF_VALUE * CHAR_BIT == 32)
- return __builtin_rotateleft32(v, n);
-
-#elif __has_builtin(__builtin_rotateleft64) && (SIZEOF_VALUE * CHAR_BIT == 64)
- return __builtin_rotateleft64(v, n);
-
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 32)
- return _rotl(v, n);
-
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64)
- return _rotl64(v, n);
-
-#elif defined(_lrotl) && (SIZEOF_VALUE == SIZEOF_LONG)
- return _lrotl(v, n);
-
-#else
- const int m = (sizeof(VALUE) * CHAR_BIT) - 1;
- return (v << (n & m)) | (v >> (-n & m));
-#endif
-}
-
-static inline VALUE
-RUBY_BIT_ROTR(VALUE v, int n)
-{
-#if __has_builtin(__builtin_rotateright32) && (SIZEOF_VALUE * CHAR_BIT == 32)
- return __builtin_rotateright32(v, n);
-
-#elif __has_builtin(__builtin_rotateright64) && (SIZEOF_VALUE * CHAR_BIT == 64)
- return __builtin_rotateright64(v, n);
-
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 32)
- return _rotr(v, n);
-
-#elif MSC_VERSION_SINCE(1310) && (SIZEOF_VALUE * CHAR_BIT == 64)
- return _rotr64(v, n);
-
-#elif defined(_lrotr) && (SIZEOF_VALUE == SIZEOF_LONG)
- return _lrotr(v, n);
-
-#else
- const int m = (sizeof(VALUE) * CHAR_BIT) - 1;
- return (v << (-n & m)) | (v >> (n & m));
-#endif
-}
-
-#endif /* INTERNAL_BITS2_H */
diff --git a/parser_node.h b/parser_node.h
deleted file mode 100644
index 2955720676..0000000000
--- a/parser_node.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef RUBY_PARSER_NODE_H
-#define RUBY_PARSER_NODE_H 1
-/*
- * This is a header file used by only "parse.y"
- */
-#include "rubyparser.h"
-#include "internal/compilers.h"
-
-#if defined(__cplusplus)
-extern "C" {
-#if 0
-} /* satisfy cc-mode */
-#endif
-#endif
-
-static inline rb_code_location_t
-code_loc_gen(const rb_code_location_t *loc1, const rb_code_location_t *loc2)
-{
- rb_code_location_t loc;
- loc.beg_pos = loc1->beg_pos;
- loc.end_pos = loc2->end_pos;
- return loc;
-}
-
-#if defined(__cplusplus)
-#if 0
-{ /* satisfy cc-mode */
-#endif
-} /* extern "C" { */
-#endif
-
-#endif /* RUBY_PARSER_NODE_H */
diff --git a/parser_st.c b/parser_st.c
deleted file mode 100644
index 17f669e763..0000000000
--- a/parser_st.c
+++ /dev/null
@@ -1,164 +0,0 @@
-#include "parser_st.h"
-#include "parser_bits.h"
-
-#ifndef TRUE
-# define TRUE 1
-#endif
-
-#ifndef FALSE
-# define FALSE 0
-#endif
-
-#undef NOT_RUBY
-#undef RUBY
-#undef RUBY_EXPORT
-
-#undef MEMCPY
-#define MEMCPY(p1,p2,type,n) nonempty_memcpy((p1), (p2), (sizeof(type) * (n)))
-/* The multiplication should not overflow since this macro is used
- * only with the already allocated size. */
-static inline void *
-nonempty_memcpy(void *dest, const void *src, size_t n)
-{
- if (n) {
- return memcpy(dest, src, n);
- }
- else {
- return dest;
- }
-}
-
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#include <string.h>
-#include <assert.h>
-
-#ifdef __GNUC__
-#define PREFETCH(addr, write_p) __builtin_prefetch(addr, write_p)
-#define EXPECT(expr, val) __builtin_expect(expr, val)
-#define ATTRIBUTE_UNUSED __attribute__((unused))
-#else
-#define PREFETCH(addr, write_p)
-#define EXPECT(expr, val) (expr)
-#define ATTRIBUTE_UNUSED
-#endif
-
-
-#define st_index_t parser_st_index_t
-#define st_hash_t parser_st_hash_t
-#define st_data_t parser_st_data_t
-#define st_hash_type parser_st_hash_type
-#define st_table parser_st_table
-#define st_table_entry parser_st_table_entry
-#define st_update_callback_func parser_st_update_callback_func
-#define st_foreach_check_callback_func parser_st_foreach_check_callback_func
-#define st_foreach_callback_func parser_st_foreach_callback_func
-#define st_retval parser_st_retval
-
-#define ST_CONTINUE ST2_CONTINUE
-#define ST_STOP ST2_STOP
-#define ST_DELETE ST2_DELETE
-#define ST_CHECK ST2_CHECK
-#define ST_REPLACE ST2_REPLACE
-
-#undef st_numcmp
-#define st_numcmp rb_parser_st_numcmp
-#undef st_numhash
-#define st_numhash rb_parser_st_numhash
-#undef st_free_table
-#define st_free_table rb_parser_st_free_table
-#define rb_st_hash_start rb_parser_st_hash_start
-#undef st_delete
-#define st_delete rb_parser_st_delete
-#undef st_foreach
-#define st_foreach rb_parser_st_foreach
-#undef st_init_numtable
-#define st_init_numtable rb_parser_st_init_numtable
-#undef st_init_table_with_size
-#define st_init_table_with_size rb_parser_st_init_table_with_size
-#undef st_init_existing_table_with_size
-#define st_init_existing_table_with_size rb_parser_st_init_existing_table_with_size
-#undef st_insert
-#define st_insert rb_parser_st_insert
-#undef st_lookup
-#define st_lookup rb_parser_st_lookup
-
-#undef st_table_size
-#define st_table_size rb_parser_st_table_size
-#undef st_clear
-#define st_clear rb_parser_st_clear
-#undef st_init_strtable
-#define st_init_strtable rb_parser_st_init_strtable
-#undef st_init_table
-#define st_init_table rb_parser_st_init_table
-#undef st_init_strcasetable
-#define st_init_strcasetable rb_parser_st_init_strcasetable
-#undef st_init_strtable_with_size
-#define st_init_strtable_with_size rb_parser_st_init_strtable_with_size
-#undef st_init_numtable_with_size
-#define st_init_numtable_with_size rb_parser_st_init_numtable_with_size
-#undef st_init_strcasetable_with_size
-#define st_init_strcasetable_with_size rb_parser_st_init_strcasetable_with_size
-#undef st_memsize
-#define st_memsize rb_parser_st_memsize
-#undef st_get_key
-#define st_get_key rb_parser_st_get_key
-#undef st_add_direct
-#define st_add_direct rb_parser_st_add_direct
-#define rb_st_add_direct_with_hash rb_parser_st_add_direct_with_hash
-#undef st_insert2
-#define st_insert2 rb_parser_st_insert2
-#undef st_replace
-#define st_replace rb_parser_st_replace
-#undef st_copy
-#define st_copy rb_parser_st_copy
-#undef st_delete_safe
-#define st_delete_safe rb_parser_st_delete_safe
-#undef st_shift
-#define st_shift rb_parser_st_shift
-#undef st_cleanup_safe
-#define st_cleanup_safe rb_parser_st_cleanup_safe
-#undef st_update
-#define st_update rb_parser_st_update
-#undef st_foreach_with_replace
-#define st_foreach_with_replace rb_parser_st_foreach_with_replace
-#undef st_foreach_check
-#define st_foreach_check rb_parser_st_foreach_check
-#undef st_keys
-#define st_keys rb_parser_st_keys
-#undef st_keys_check
-#define st_keys_check rb_parser_st_keys_check
-#undef st_values
-#define st_values rb_parser_st_values
-#undef st_values_check
-#define st_values_check rb_parser_st_values_check
-#undef st_hash
-#define st_hash rb_parser_st_hash
-#undef st_hash_uint32
-#define st_hash_uint32 rb_parser_st_hash_uint32
-#undef st_hash_uint
-#define st_hash_uint rb_parser_st_hash_uint
-#undef st_hash_end
-#define st_hash_end rb_parser_st_hash_end
-#undef st_locale_insensitive_strcasecmp
-#define st_locale_insensitive_strcasecmp rb_parser_st_locale_insensitive_strcasecmp
-#undef st_locale_insensitive_strncasecmp
-#define st_locale_insensitive_strncasecmp rb_parser_st_locale_insensitive_strncasecmp
-
-#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
-/* GCC warns about unknown sanitizer, which is annoying. */
-# undef NO_SANITIZE
-# define NO_SANITIZE(x, y) \
- _Pragma("GCC diagnostic push") \
- _Pragma("GCC diagnostic ignored \"-Wattributes\"") \
- __attribute__((__no_sanitize__(x))) y; \
- _Pragma("GCC diagnostic pop")
-#endif
-
-#ifndef NO_SANITIZE
-# define NO_SANITIZE(x, y) y
-#endif
-
-#include "st.c"
diff --git a/parser_st.h b/parser_st.h
deleted file mode 100644
index 877b1e9051..0000000000
--- a/parser_st.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/* This is a public domain general purpose hash table package
- originally written by Peter Moore @ UCB.
-
- The hash table data structures were redesigned and the package was
- rewritten by Vladimir Makarov <vmakarov@redhat.com>. */
-
-#ifndef RUBY_ST2_H
-#define RUBY_ST2_H 1
-
-#if defined(__cplusplus)
-extern "C" {
-#if 0
-} /* satisfy cc-mode */
-#endif
-#endif
-
-#include <stddef.h>
-#include <stdint.h>
-#include "ruby/config.h"
-#include "ruby/backward/2/long_long.h"
-#include "ruby/defines.h"
-
-RUBY_SYMBOL_EXPORT_BEGIN
-
-#if SIZEOF_LONG == SIZEOF_VOIDP
-typedef unsigned long parser_st_data_t;
-#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
-typedef unsigned LONG_LONG parser_st_data_t;
-#else
-# error ---->> parser_st.c requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<----
-#endif
-#define ST2_DATA_T_DEFINED
-
-#ifndef CHAR_BIT
-# ifdef HAVE_LIMITS_H
-# include <limits.h>
-# else
-# define CHAR_BIT 8
-# endif
-#endif
-#ifndef _
-# define _(args) args
-#endif
-#ifndef ANYARGS
-# ifdef __cplusplus
-# define ANYARGS ...
-# else
-# define ANYARGS
-# endif
-#endif
-
-typedef struct parser_st_table parser_st_table;
-
-typedef parser_st_data_t parser_st_index_t;
-
-/* Maximal value of unsigned integer type parser_st_index_t. */
-#define MAX_ST2_INDEX_VAL (~(parser_st_index_t) 0)
-
-typedef int parser_st_compare_func(parser_st_data_t, parser_st_data_t);
-typedef parser_st_index_t parser_st_hash_func(parser_st_data_t);
-
-typedef char st_check_for_sizeof_parser_st_index_t[SIZEOF_VOIDP == (int)sizeof(parser_st_index_t) ? 1 : -1];
-#define SIZEOF_ST_INDEX_T SIZEOF_VOIDP
-
-struct parser_st_hash_type {
- int (*compare)(parser_st_data_t, parser_st_data_t); /* parser_st_compare_func* */
- parser_st_index_t (*hash)(parser_st_data_t); /* parser_st_hash_func* */
-};
-
-#define ST_INDEX_BITS (SIZEOF_ST_INDEX_T * CHAR_BIT)
-
-#if defined(HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR) && defined(HAVE_BUILTIN___BUILTIN_TYPES_COMPATIBLE_P)
-# define ST2_DATA_COMPATIBLE_P(type) \
- __builtin_choose_expr(__builtin_types_compatible_p(type, parser_st_data_t), 1, 0)
-#else
-# define ST2_DATA_COMPATIBLE_P(type) 0
-#endif
-
-typedef struct parser_st_table_entry parser_st_table_entry;
-
-struct parser_st_table_entry; /* defined in parser_st.c */
-
-struct parser_st_table {
- /* Cached features of the table -- see st.c for more details. */
- unsigned char entry_power, bin_power, size_ind;
- /* How many times the table was rebuilt. */
- unsigned int rebuilds_num;
- const struct parser_st_hash_type *type;
- /* Number of entries currently in the table. */
- parser_st_index_t num_entries;
- /* Array of bins used for access by keys. */
- parser_st_index_t *bins;
- /* Start and bound index of entries in array entries.
- entries_starts and entries_bound are in interval
- [0,allocated_entries]. */
- parser_st_index_t entries_start, entries_bound;
- /* Array of size 2^entry_power. */
- parser_st_table_entry *entries;
-};
-
-#define parser_st_is_member(table,key) rb_parser_st_lookup((table),(key),(parser_st_data_t *)0)
-
-enum parser_st_retval {ST2_CONTINUE, ST2_STOP, ST2_DELETE, ST2_CHECK, ST2_REPLACE};
-
-size_t rb_parser_st_table_size(const struct parser_st_table *tbl);
-parser_st_table *rb_parser_st_init_table(const struct parser_st_hash_type *);
-parser_st_table *rb_parser_st_init_table_with_size(const struct parser_st_hash_type *, parser_st_index_t);
-parser_st_table *rb_parser_st_init_existing_table_with_size(parser_st_table *, const struct parser_st_hash_type *, parser_st_index_t);
-parser_st_table *rb_parser_st_init_numtable(void);
-parser_st_table *rb_parser_st_init_numtable_with_size(parser_st_index_t);
-parser_st_table *rb_parser_st_init_strtable(void);
-parser_st_table *rb_parser_st_init_strtable_with_size(parser_st_index_t);
-parser_st_table *rb_parser_st_init_strcasetable(void);
-parser_st_table *rb_parser_st_init_strcasetable_with_size(parser_st_index_t);
-int rb_parser_st_delete(parser_st_table *, parser_st_data_t *, parser_st_data_t *); /* returns 0:notfound 1:deleted */
-int rb_parser_st_delete_safe(parser_st_table *, parser_st_data_t *, parser_st_data_t *, parser_st_data_t);
-int rb_parser_st_shift(parser_st_table *, parser_st_data_t *, parser_st_data_t *); /* returns 0:notfound 1:deleted */
-int rb_parser_st_insert(parser_st_table *, parser_st_data_t, parser_st_data_t);
-int rb_parser_st_insert2(parser_st_table *, parser_st_data_t, parser_st_data_t, parser_st_data_t (*)(parser_st_data_t));
-int rb_parser_st_lookup(parser_st_table *, parser_st_data_t, parser_st_data_t *);
-int rb_parser_st_get_key(parser_st_table *, parser_st_data_t, parser_st_data_t *);
-typedef int parser_st_update_callback_func(parser_st_data_t *key, parser_st_data_t *value, parser_st_data_t arg, int existing);
-/* *key may be altered, but must equal to the old key, i.e., the
- * results of hash() are same and compare() returns 0, otherwise the
- * behavior is undefined */
-int rb_parser_st_update(parser_st_table *table, parser_st_data_t key, parser_st_update_callback_func *func, parser_st_data_t arg);
-typedef int parser_st_foreach_callback_func(parser_st_data_t, parser_st_data_t, parser_st_data_t);
-typedef int parser_st_foreach_check_callback_func(parser_st_data_t, parser_st_data_t, parser_st_data_t, int);
-int rb_parser_st_foreach_with_replace(parser_st_table *tab, parser_st_foreach_check_callback_func *func, parser_st_update_callback_func *replace, parser_st_data_t arg);
-int rb_parser_st_foreach(parser_st_table *, parser_st_foreach_callback_func *, parser_st_data_t);
-int rb_parser_st_foreach_check(parser_st_table *, parser_st_foreach_check_callback_func *, parser_st_data_t, parser_st_data_t);
-parser_st_index_t rb_parser_st_keys(parser_st_table *table, parser_st_data_t *keys, parser_st_index_t size);
-parser_st_index_t rb_parser_st_keys_check(parser_st_table *table, parser_st_data_t *keys, parser_st_index_t size, parser_st_data_t never);
-parser_st_index_t rb_parser_st_values(parser_st_table *table, parser_st_data_t *values, parser_st_index_t size);
-parser_st_index_t rb_parser_st_values_check(parser_st_table *table, parser_st_data_t *values, parser_st_index_t size, parser_st_data_t never);
-void rb_parser_st_add_direct(parser_st_table *, parser_st_data_t, parser_st_data_t);
-void rb_parser_st_free_table(parser_st_table *);
-void rb_parser_st_cleanup_safe(parser_st_table *, parser_st_data_t);
-void rb_parser_st_clear(parser_st_table *);
-parser_st_table *rb_parser_st_replace(parser_st_table *, parser_st_table *);
-parser_st_table *rb_parser_st_copy(parser_st_table *);
-CONSTFUNC(int rb_parser_st_numcmp(parser_st_data_t, parser_st_data_t));
-CONSTFUNC(parser_st_index_t rb_parser_st_numhash(parser_st_data_t));
-PUREFUNC(int rb_parser_st_locale_insensitive_strcasecmp(const char *s1, const char *s2));
-PUREFUNC(int rb_parser_st_locale_insensitive_strncasecmp(const char *s1, const char *s2, size_t n));
-PUREFUNC(size_t rb_parser_st_memsize(const parser_st_table *));
-PUREFUNC(parser_st_index_t rb_parser_st_hash(const void *ptr, size_t len, parser_st_index_t h));
-CONSTFUNC(parser_st_index_t rb_parser_st_hash_uint32(parser_st_index_t h, uint32_t i));
-CONSTFUNC(parser_st_index_t rb_parser_st_hash_uint(parser_st_index_t h, parser_st_index_t i));
-CONSTFUNC(parser_st_index_t rb_parser_st_hash_end(parser_st_index_t h));
-CONSTFUNC(parser_st_index_t rb_parser_st_hash_start(parser_st_index_t h));
-
-RUBY_SYMBOL_EXPORT_END
-
-#if defined(__cplusplus)
-#if 0
-{ /* satisfy cc-mode */
-#endif
-} /* extern "C" { */
-#endif
-
-#endif /* RUBY_ST2_H */
diff --git a/parser_value.h b/parser_value.h
deleted file mode 100644
index 4fe444e82f..0000000000
--- a/parser_value.h
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef EXTERNAL_VALUE_H
-#define EXTERNAL_VALUE_H
-
-#include "ruby/config.h"
-
-#if defined(__DOXYGEN__)
-
-/**
- * Type that represents a Ruby object. It is an unsigned integer of some kind,
- * depending on platforms.
- *
- * ```CXX
- * VALUE value = rb_eval_string("ARGF.readlines.map.with_index");
- * ```
- *
- * @warning ::VALUE is not a pointer.
- * @warning ::VALUE can be wider than `long`.
- */
-typedef uintptr_t VALUE;
-
-/**
- * Type that represents a Ruby identifier such as a variable name.
- *
- * ```CXX
- * ID method = rb_intern("method");
- * VALUE result = rb_funcall(obj, method, 0);
- * ```
- *
- * @note ::rb_cSymbol is a Ruby-level data type for the same thing.
- */
-typedef uintptr_t ID;
-
-/**
- * A signed integer type that has the same width with ::VALUE.
- *
- * @internal
- *
- * @shyouhei wonders: is it guaranteed that `uintptr_t` and `intptr_t` are the
- * same width? As far as I read ISO/IEC 9899:2018 section 7.20.1.4 paragraph 1
- * no such description is given... or defined elsewhere?
- */
-typedef intptr_t SIGNED_VALUE;
-
-/**
- * Identical to `sizeof(VALUE)`, except it is a macro that can also be used
- * inside of preprocessor directives such as `#if`. Handy on occasions.
- */
-#define SIZEOF_VALUE SIZEOF_UINTPTR_T
-
-/**
- * @private
- *
- * A compile-time constant of type ::VALUE whose value is 0.
- */
-#define RBIMPL_VALUE_NULL UINTPTR_C(0)
-
-/**
- * @private
- *
- * A compile-time constant of type ::VALUE whose value is 1.
- */
-#define RBIMPL_VALUE_ONE UINTPTR_C(1)
-
-/**
- * @private
- *
- * Maximum possible value that a ::VALUE can take.
- */
-#define RBIMPL_VALUE_FULL UINTPTR_MAX
-
-#elif defined HAVE_UINTPTR_T && 0
-typedef uintptr_t VALUE;
-typedef uintptr_t ID;
-# define SIGNED_VALUE intptr_t
-# define SIZEOF_VALUE SIZEOF_UINTPTR_T
-# undef PRI_VALUE_PREFIX
-# define RBIMPL_VALUE_NULL UINTPTR_C(0)
-# define RBIMPL_VALUE_ONE UINTPTR_C(1)
-# define RBIMPL_VALUE_FULL UINTPTR_MAX
-
-#elif SIZEOF_LONG == SIZEOF_VOIDP
-typedef unsigned long VALUE;
-typedef unsigned long ID;
-# define SIGNED_VALUE long
-# define SIZEOF_VALUE SIZEOF_LONG
-# define PRI_VALUE_PREFIX "l"
-# define RBIMPL_VALUE_NULL 0UL
-# define RBIMPL_VALUE_ONE 1UL
-# define RBIMPL_VALUE_FULL ULONG_MAX
-
-#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
-typedef unsigned LONG_LONG VALUE;
-typedef unsigned LONG_LONG ID;
-# define SIGNED_VALUE LONG_LONG
-# define LONG_LONG_VALUE 1
-# define SIZEOF_VALUE SIZEOF_LONG_LONG
-# define PRI_VALUE_PREFIX PRI_LL_PREFIX
-# define RBIMPL_VALUE_NULL 0ULL
-# define RBIMPL_VALUE_ONE 1ULL
-# define RBIMPL_VALUE_FULL ULLONG_MAX
-
-#else
-# error ---->> ruby requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<----
-#endif
-
-#endif /* EXTERNAL_VALUE_H */
diff --git a/prelude.rb b/prelude.rb
index 55b42f06c4..8fd6e6cb77 100644
--- a/prelude.rb
+++ b/prelude.rb
@@ -1,49 +1,12 @@
class Binding
# :nodoc:
def irb
- begin
- require 'irb'
- rescue LoadError, Gem::LoadError
- force_activate 'irb'
- retry
- end
+ require 'irb'
irb
end
# suppress redefinition warning
alias irb irb # :nodoc:
-
- private def force_activate(gem)
- Bundler.reset!
-
- builder = Bundler::Dsl.new
- if Bundler.definition.gemfiles.empty? # bundler/inline
- Bundler.definition.locked_gems.specs.each{|spec| builder.gem spec.name, spec.version.to_s }
- else
- Bundler.definition.gemfiles.each{|gemfile| builder.eval_gemfile(gemfile) }
- end
- builder.gem gem
-
- definition = builder.to_definition(nil, true)
- definition.validate_runtime!
-
- begin
- orig_ui = Bundler.ui
- orig_no_lock = Bundler::Definition.no_lock
-
- ui = Bundler::UI::Shell.new
- ui.level = "silent"
- Bundler.ui = ui
- Bundler::Definition.no_lock = true
-
- Bundler::Runtime.new(nil, definition).setup
- rescue Bundler::GemNotFound
- warn "Failed to activate #{gem}, please install it with 'gem install #{gem}'"
- ensure
- Bundler.ui = orig_ui
- Bundler::Definition.no_lock = orig_no_lock
- end
- end
end
module Kernel
@@ -64,5 +27,5 @@ module Enumerable
# Makes a set from the enumerable object with given arguments.
def to_set(klass = Set, *args, &block)
klass.new(self, *args, &block)
- end unless instance_methods.include?(:to_set) # RJIT could already load this from builtin prelude
+ end
end
diff --git a/prism/api_pack.c b/prism/api_pack.c
deleted file mode 100644
index 98509ae65c..0000000000
--- a/prism/api_pack.c
+++ /dev/null
@@ -1,276 +0,0 @@
-#include "prism/extension.h"
-
-#ifdef PRISM_EXCLUDE_PACK
-
-void
-Init_prism_pack(void) {}
-
-#else
-
-static VALUE rb_cPrism;
-static VALUE rb_cPrismPack;
-static VALUE rb_cPrismPackDirective;
-static VALUE rb_cPrismPackFormat;
-
-static VALUE v3_2_0_symbol;
-static VALUE pack_symbol;
-static VALUE unpack_symbol;
-
-#if SIZEOF_UINT64_T == SIZEOF_LONG_LONG
-# define UINT64T2NUM(x) ULL2NUM(x)
-# define NUM2UINT64T(x) (uint64_t)NUM2ULL(x)
-#elif SIZEOF_UINT64_T == SIZEOF_LONG
-# define UINT64T2NUM(x) ULONG2NUM(x)
-# define NUM2UINT64T(x) (uint64_t)NUM2ULONG(x)
-#else
-// error No uint64_t conversion
-#endif
-
-static VALUE
-pack_type_to_symbol(pm_pack_type type) {
- switch (type) {
- case PM_PACK_SPACE:
- return ID2SYM(rb_intern("SPACE"));
- case PM_PACK_COMMENT:
- return ID2SYM(rb_intern("COMMENT"));
- case PM_PACK_INTEGER:
- return ID2SYM(rb_intern("INTEGER"));
- case PM_PACK_UTF8:
- return ID2SYM(rb_intern("UTF8"));
- case PM_PACK_BER:
- return ID2SYM(rb_intern("BER"));
- case PM_PACK_FLOAT:
- return ID2SYM(rb_intern("FLOAT"));
- case PM_PACK_STRING_SPACE_PADDED:
- return ID2SYM(rb_intern("STRING_SPACE_PADDED"));
- case PM_PACK_STRING_NULL_PADDED:
- return ID2SYM(rb_intern("STRING_NULL_PADDED"));
- case PM_PACK_STRING_NULL_TERMINATED:
- return ID2SYM(rb_intern("STRING_NULL_TERMINATED"));
- case PM_PACK_STRING_MSB:
- return ID2SYM(rb_intern("STRING_MSB"));
- case PM_PACK_STRING_LSB:
- return ID2SYM(rb_intern("STRING_LSB"));
- case PM_PACK_STRING_HEX_HIGH:
- return ID2SYM(rb_intern("STRING_HEX_HIGH"));
- case PM_PACK_STRING_HEX_LOW:
- return ID2SYM(rb_intern("STRING_HEX_LOW"));
- case PM_PACK_STRING_UU:
- return ID2SYM(rb_intern("STRING_UU"));
- case PM_PACK_STRING_MIME:
- return ID2SYM(rb_intern("STRING_MIME"));
- case PM_PACK_STRING_BASE64:
- return ID2SYM(rb_intern("STRING_BASE64"));
- case PM_PACK_STRING_FIXED:
- return ID2SYM(rb_intern("STRING_FIXED"));
- case PM_PACK_STRING_POINTER:
- return ID2SYM(rb_intern("STRING_POINTER"));
- case PM_PACK_MOVE:
- return ID2SYM(rb_intern("MOVE"));
- case PM_PACK_BACK:
- return ID2SYM(rb_intern("BACK"));
- case PM_PACK_NULL:
- return ID2SYM(rb_intern("NULL"));
- default:
- return Qnil;
- }
-}
-
-static VALUE
-pack_signed_to_symbol(pm_pack_signed signed_type) {
- switch (signed_type) {
- case PM_PACK_UNSIGNED:
- return ID2SYM(rb_intern("UNSIGNED"));
- case PM_PACK_SIGNED:
- return ID2SYM(rb_intern("SIGNED"));
- case PM_PACK_SIGNED_NA:
- return ID2SYM(rb_intern("SIGNED_NA"));
- default:
- return Qnil;
- }
-}
-
-static VALUE
-pack_endian_to_symbol(pm_pack_endian endian) {
- switch (endian) {
- case PM_PACK_AGNOSTIC_ENDIAN:
- return ID2SYM(rb_intern("AGNOSTIC_ENDIAN"));
- case PM_PACK_LITTLE_ENDIAN:
- return ID2SYM(rb_intern("LITTLE_ENDIAN"));
- case PM_PACK_BIG_ENDIAN:
- return ID2SYM(rb_intern("BIG_ENDIAN"));
- case PM_PACK_NATIVE_ENDIAN:
- return ID2SYM(rb_intern("NATIVE_ENDIAN"));
- case PM_PACK_ENDIAN_NA:
- return ID2SYM(rb_intern("ENDIAN_NA"));
- default:
- return Qnil;
- }
-}
-
-static VALUE
-pack_size_to_symbol(pm_pack_size size) {
- switch (size) {
- case PM_PACK_SIZE_SHORT:
- return ID2SYM(rb_intern("SIZE_SHORT"));
- case PM_PACK_SIZE_INT:
- return ID2SYM(rb_intern("SIZE_INT"));
- case PM_PACK_SIZE_LONG:
- return ID2SYM(rb_intern("SIZE_LONG"));
- case PM_PACK_SIZE_LONG_LONG:
- return ID2SYM(rb_intern("SIZE_LONG_LONG"));
- case PM_PACK_SIZE_8:
- return ID2SYM(rb_intern("SIZE_8"));
- case PM_PACK_SIZE_16:
- return ID2SYM(rb_intern("SIZE_16"));
- case PM_PACK_SIZE_32:
- return ID2SYM(rb_intern("SIZE_32"));
- case PM_PACK_SIZE_64:
- return ID2SYM(rb_intern("SIZE_64"));
- case PM_PACK_SIZE_P:
- return ID2SYM(rb_intern("SIZE_P"));
- case PM_PACK_SIZE_NA:
- return ID2SYM(rb_intern("SIZE_NA"));
- default:
- return Qnil;
- }
-}
-
-static VALUE
-pack_length_type_to_symbol(pm_pack_length_type length_type) {
- switch (length_type) {
- case PM_PACK_LENGTH_FIXED:
- return ID2SYM(rb_intern("LENGTH_FIXED"));
- case PM_PACK_LENGTH_MAX:
- return ID2SYM(rb_intern("LENGTH_MAX"));
- case PM_PACK_LENGTH_RELATIVE:
- return ID2SYM(rb_intern("LENGTH_RELATIVE"));
- case PM_PACK_LENGTH_NA:
- return ID2SYM(rb_intern("LENGTH_NA"));
- default:
- return Qnil;
- }
-}
-
-static VALUE
-pack_encoding_to_ruby(pm_pack_encoding encoding) {
- int index;
- switch (encoding) {
- case PM_PACK_ENCODING_ASCII_8BIT:
- index = rb_ascii8bit_encindex();
- break;
- case PM_PACK_ENCODING_US_ASCII:
- index = rb_usascii_encindex();
- break;
- case PM_PACK_ENCODING_UTF_8:
- index = rb_utf8_encindex();
- break;
- default:
- return Qnil;
- }
- return rb_enc_from_encoding(rb_enc_from_index(index));
-}
-
-/**
- * call-seq:
- * Pack::parse(version, variant, source) -> Format
- *
- * Parse the given source and return a format object.
- */
-static VALUE
-pack_parse(VALUE self, VALUE version_symbol, VALUE variant_symbol, VALUE format_string) {
- if (version_symbol != v3_2_0_symbol) {
- rb_raise(rb_eArgError, "invalid version");
- }
-
- pm_pack_variant variant;
- if (variant_symbol == pack_symbol) {
- variant = PM_PACK_VARIANT_PACK;
- } else if (variant_symbol == unpack_symbol) {
- variant = PM_PACK_VARIANT_UNPACK;
- } else {
- rb_raise(rb_eArgError, "invalid variant");
- }
-
- StringValue(format_string);
-
- const char *format = RSTRING_PTR(format_string);
- const char *format_end = format + RSTRING_LEN(format_string);
- pm_pack_encoding encoding = PM_PACK_ENCODING_START;
-
- VALUE directives_array = rb_ary_new();
-
- while (format < format_end) {
- pm_pack_type type;
- pm_pack_signed signed_type;
- pm_pack_endian endian;
- pm_pack_size size;
- pm_pack_length_type length_type;
- uint64_t length;
-
- const char *directive_start = format;
-
- pm_pack_result parse_result = pm_pack_parse(variant, &format, format_end, &type, &signed_type, &endian,
- &size, &length_type, &length, &encoding);
-
- const char *directive_end = format;
-
- switch (parse_result) {
- case PM_PACK_OK:
- break;
- case PM_PACK_ERROR_UNSUPPORTED_DIRECTIVE:
- rb_raise(rb_eArgError, "unsupported directive");
- case PM_PACK_ERROR_UNKNOWN_DIRECTIVE:
- rb_raise(rb_eArgError, "unsupported directive");
- case PM_PACK_ERROR_LENGTH_TOO_BIG:
- rb_raise(rb_eRangeError, "pack length too big");
- case PM_PACK_ERROR_BANG_NOT_ALLOWED:
- rb_raise(rb_eRangeError, "bang not allowed");
- case PM_PACK_ERROR_DOUBLE_ENDIAN:
- rb_raise(rb_eRangeError, "double endian");
- default:
- rb_bug("parse result");
- }
-
- if (type == PM_PACK_END) {
- break;
- }
-
- VALUE directive_args[9] = {
- version_symbol,
- variant_symbol,
- rb_usascii_str_new(directive_start, directive_end - directive_start),
- pack_type_to_symbol(type),
- pack_signed_to_symbol(signed_type),
- pack_endian_to_symbol(endian),
- pack_size_to_symbol(size),
- pack_length_type_to_symbol(length_type),
- UINT64T2NUM(length)
- };
-
- rb_ary_push(directives_array, rb_class_new_instance(9, directive_args, rb_cPrismPackDirective));
- }
-
- VALUE format_args[2];
- format_args[0] = directives_array;
- format_args[1] = pack_encoding_to_ruby(encoding);
- return rb_class_new_instance(2, format_args, rb_cPrismPackFormat);
-}
-
-/**
- * The function that gets called when Ruby initializes the prism extension.
- */
-void
-Init_prism_pack(void) {
- rb_cPrism = rb_define_module("Prism");
- rb_cPrismPack = rb_define_module_under(rb_cPrism, "Pack");
- rb_cPrismPackDirective = rb_define_class_under(rb_cPrismPack, "Directive", rb_cObject);
- rb_cPrismPackFormat = rb_define_class_under(rb_cPrismPack, "Format", rb_cObject);
- rb_define_singleton_method(rb_cPrismPack, "parse", pack_parse, 3);
-
- v3_2_0_symbol = ID2SYM(rb_intern("v3_2_0"));
- pack_symbol = ID2SYM(rb_intern("pack"));
- unpack_symbol = ID2SYM(rb_intern("unpack"));
-}
-
-#endif
diff --git a/prism/config.yml b/prism/config.yml
deleted file mode 100644
index 972f1e8e69..0000000000
--- a/prism/config.yml
+++ /dev/null
@@ -1,4058 +0,0 @@
-errors:
- - ALIAS_ARGUMENT
- - ALIAS_ARGUMENT_NUMBERED_REFERENCE
- - AMPAMPEQ_MULTI_ASSIGN
- - ARGUMENT_AFTER_BLOCK
- - ARGUMENT_AFTER_FORWARDING_ELLIPSES
- - ARGUMENT_BARE_HASH
- - ARGUMENT_BLOCK_FORWARDING
- - ARGUMENT_BLOCK_MULTI
- - ARGUMENT_CONFLICT_AMPERSAND
- - ARGUMENT_CONFLICT_STAR
- - ARGUMENT_CONFLICT_STAR_STAR
- - ARGUMENT_FORMAL_CLASS
- - ARGUMENT_FORMAL_CONSTANT
- - ARGUMENT_FORMAL_GLOBAL
- - ARGUMENT_FORMAL_IVAR
- - ARGUMENT_FORWARDING_UNBOUND
- - ARGUMENT_NO_FORWARDING_AMPERSAND
- - ARGUMENT_NO_FORWARDING_ELLIPSES
- - ARGUMENT_NO_FORWARDING_STAR
- - ARGUMENT_NO_FORWARDING_STAR_STAR
- - ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT
- - ARGUMENT_SPLAT_AFTER_SPLAT
- - ARGUMENT_TERM_PAREN
- - ARGUMENT_UNEXPECTED_BLOCK
- - ARRAY_ELEMENT
- - ARRAY_EXPRESSION
- - ARRAY_EXPRESSION_AFTER_STAR
- - ARRAY_SEPARATOR
- - ARRAY_TERM
- - BEGIN_LONELY_ELSE
- - BEGIN_TERM
- - BEGIN_UPCASE_BRACE
- - BEGIN_UPCASE_TERM
- - BEGIN_UPCASE_TOPLEVEL
- - BLOCK_PARAM_LOCAL_VARIABLE
- - BLOCK_PARAM_PIPE_TERM
- - BLOCK_TERM_BRACE
- - BLOCK_TERM_END
- - CANNOT_PARSE_EXPRESSION
- - CANNOT_PARSE_STRING_PART
- - CASE_EXPRESSION_AFTER_CASE
- - CASE_EXPRESSION_AFTER_WHEN
- - CASE_MATCH_MISSING_PREDICATE
- - CASE_MISSING_CONDITIONS
- - CASE_TERM
- - CLASS_IN_METHOD
- - CLASS_NAME
- - CLASS_SUPERCLASS
- - CLASS_TERM
- - CLASS_UNEXPECTED_END
- - CLASS_VARIABLE_BARE
- - CONDITIONAL_ELSIF_PREDICATE
- - CONDITIONAL_IF_PREDICATE
- - CONDITIONAL_PREDICATE_TERM
- - CONDITIONAL_TERM
- - CONDITIONAL_TERM_ELSE
- - CONDITIONAL_UNLESS_PREDICATE
- - CONDITIONAL_UNTIL_PREDICATE
- - CONDITIONAL_WHILE_PREDICATE
- - CONSTANT_PATH_COLON_COLON_CONSTANT
- - DEF_ENDLESS
- - DEF_ENDLESS_SETTER
- - DEF_NAME
- - DEF_PARAMS_TERM
- - DEF_PARAMS_TERM_PAREN
- - DEF_RECEIVER
- - DEF_RECEIVER_TERM
- - DEF_TERM
- - DEFINED_EXPRESSION
- - EMBDOC_TERM
- - EMBEXPR_END
- - EMBVAR_INVALID
- - END_UPCASE_BRACE
- - END_UPCASE_TERM
- - ESCAPE_INVALID_CONTROL
- - ESCAPE_INVALID_CONTROL_REPEAT
- - ESCAPE_INVALID_HEXADECIMAL
- - ESCAPE_INVALID_META
- - ESCAPE_INVALID_META_REPEAT
- - ESCAPE_INVALID_UNICODE
- - ESCAPE_INVALID_UNICODE_CM_FLAGS
- - ESCAPE_INVALID_UNICODE_LIST
- - ESCAPE_INVALID_UNICODE_LITERAL
- - ESCAPE_INVALID_UNICODE_LONG
- - ESCAPE_INVALID_UNICODE_SHORT
- - ESCAPE_INVALID_UNICODE_TERM
- - EXPECT_ARGUMENT
- - EXPECT_EOL_AFTER_STATEMENT
- - EXPECT_EXPRESSION_AFTER_AMPAMPEQ
- - EXPECT_EXPRESSION_AFTER_COMMA
- - EXPECT_EXPRESSION_AFTER_EQUAL
- - EXPECT_EXPRESSION_AFTER_LESS_LESS
- - EXPECT_EXPRESSION_AFTER_LPAREN
- - EXPECT_EXPRESSION_AFTER_OPERATOR
- - EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ
- - EXPECT_EXPRESSION_AFTER_QUESTION
- - EXPECT_EXPRESSION_AFTER_SPLAT
- - EXPECT_EXPRESSION_AFTER_SPLAT_HASH
- - EXPECT_EXPRESSION_AFTER_STAR
- - EXPECT_FOR_DELIMITER
- - EXPECT_IDENT_REQ_PARAMETER
- - EXPECT_IN_DELIMITER
- - EXPECT_LPAREN_REQ_PARAMETER
- - EXPECT_MESSAGE
- - EXPECT_RBRACKET
- - EXPECT_RPAREN
- - EXPECT_RPAREN_AFTER_MULTI
- - EXPECT_RPAREN_REQ_PARAMETER
- - EXPECT_SINGLETON_CLASS_DELIMITER
- - EXPECT_STRING_CONTENT
- - EXPECT_WHEN_DELIMITER
- - EXPRESSION_BARE_HASH
- - EXPRESSION_NOT_WRITABLE
- - EXPRESSION_NOT_WRITABLE_ENCODING
- - EXPRESSION_NOT_WRITABLE_FALSE
- - EXPRESSION_NOT_WRITABLE_FILE
- - EXPRESSION_NOT_WRITABLE_LINE
- - EXPRESSION_NOT_WRITABLE_NIL
- - EXPRESSION_NOT_WRITABLE_NUMBERED
- - EXPRESSION_NOT_WRITABLE_SELF
- - EXPRESSION_NOT_WRITABLE_TRUE
- - FLOAT_PARSE
- - FOR_COLLECTION
- - FOR_IN
- - FOR_INDEX
- - FOR_TERM
- - GLOBAL_VARIABLE_BARE
- - HASH_EXPRESSION_AFTER_LABEL
- - HASH_KEY
- - HASH_ROCKET
- - HASH_TERM
- - HASH_VALUE
- - HEREDOC_IDENTIFIER
- - HEREDOC_TERM
- - INCOMPLETE_QUESTION_MARK
- - INCOMPLETE_VARIABLE_CLASS
- - INCOMPLETE_VARIABLE_CLASS_3_3
- - INCOMPLETE_VARIABLE_INSTANCE
- - INCOMPLETE_VARIABLE_INSTANCE_3_3
- - INSTANCE_VARIABLE_BARE
- - INVALID_BLOCK_EXIT
- - INVALID_CHARACTER
- - INVALID_ENCODING_MAGIC_COMMENT
- - INVALID_ESCAPE_CHARACTER
- - INVALID_FLOAT_EXPONENT
- - INVALID_LOCAL_VARIABLE_READ
- - INVALID_LOCAL_VARIABLE_WRITE
- - INVALID_MULTIBYTE_CHAR
- - INVALID_MULTIBYTE_CHARACTER
- - INVALID_MULTIBYTE_ESCAPE
- - INVALID_NUMBER_BINARY
- - INVALID_NUMBER_DECIMAL
- - INVALID_NUMBER_FRACTION
- - INVALID_NUMBER_HEXADECIMAL
- - INVALID_NUMBER_OCTAL
- - INVALID_NUMBER_UNDERSCORE_INNER
- - INVALID_NUMBER_UNDERSCORE_TRAILING
- - INVALID_PERCENT
- - INVALID_PERCENT_EOF
- - INVALID_PRINTABLE_CHARACTER
- - INVALID_RETRY_AFTER_ELSE
- - INVALID_RETRY_AFTER_ENSURE
- - INVALID_RETRY_WITHOUT_RESCUE
- - INVALID_SYMBOL
- - INVALID_VARIABLE_GLOBAL
- - INVALID_VARIABLE_GLOBAL_3_3
- - INVALID_YIELD
- - IT_NOT_ALLOWED_NUMBERED
- - IT_NOT_ALLOWED_ORDINARY
- - LAMBDA_OPEN
- - LAMBDA_TERM_BRACE
- - LAMBDA_TERM_END
- - LIST_I_LOWER_ELEMENT
- - LIST_I_LOWER_TERM
- - LIST_I_UPPER_ELEMENT
- - LIST_I_UPPER_TERM
- - LIST_W_LOWER_ELEMENT
- - LIST_W_LOWER_TERM
- - LIST_W_UPPER_ELEMENT
- - LIST_W_UPPER_TERM
- - MALLOC_FAILED
- - MIXED_ENCODING
- - MODULE_IN_METHOD
- - MODULE_NAME
- - MODULE_TERM
- - MULTI_ASSIGN_MULTI_SPLATS
- - MULTI_ASSIGN_UNEXPECTED_REST
- - NESTING_TOO_DEEP
- - NO_LOCAL_VARIABLE
- - NON_ASSOCIATIVE_OPERATOR
- - NOT_EXPRESSION
- - NUMBER_LITERAL_UNDERSCORE
- - NUMBERED_PARAMETER_INNER_BLOCK
- - NUMBERED_PARAMETER_IT
- - NUMBERED_PARAMETER_ORDINARY
- - NUMBERED_PARAMETER_OUTER_BLOCK
- - OPERATOR_MULTI_ASSIGN
- - OPERATOR_WRITE_ARGUMENTS
- - OPERATOR_WRITE_BLOCK
- - PARAMETER_ASSOC_SPLAT_MULTI
- - PARAMETER_BLOCK_MULTI
- - PARAMETER_CIRCULAR
- - PARAMETER_FORWARDING_AFTER_REST
- - PARAMETER_METHOD_NAME
- - PARAMETER_NAME_DUPLICATED
- - PARAMETER_NO_DEFAULT
- - PARAMETER_NO_DEFAULT_KW
- - PARAMETER_NUMBERED_RESERVED
- - PARAMETER_ORDER
- - PARAMETER_SPLAT_MULTI
- - PARAMETER_STAR
- - PARAMETER_UNEXPECTED_FWD
- - PARAMETER_UNEXPECTED_NO_KW
- - PARAMETER_WILD_LOOSE_COMMA
- - PATTERN_ARRAY_MULTIPLE_RESTS
- - PATTERN_CAPTURE_DUPLICATE
- - PATTERN_EXPRESSION_AFTER_BRACKET
- - PATTERN_EXPRESSION_AFTER_COMMA
- - PATTERN_EXPRESSION_AFTER_HROCKET
- - PATTERN_EXPRESSION_AFTER_IN
- - PATTERN_EXPRESSION_AFTER_KEY
- - PATTERN_EXPRESSION_AFTER_PAREN
- - PATTERN_EXPRESSION_AFTER_PIN
- - PATTERN_EXPRESSION_AFTER_PIPE
- - PATTERN_EXPRESSION_AFTER_RANGE
- - PATTERN_EXPRESSION_AFTER_REST
- - PATTERN_FIND_MISSING_INNER
- - PATTERN_HASH_IMPLICIT
- - PATTERN_HASH_KEY
- - PATTERN_HASH_KEY_DUPLICATE
- - PATTERN_HASH_KEY_INTERPOLATED
- - PATTERN_HASH_KEY_LABEL
- - PATTERN_HASH_KEY_LOCALS
- - PATTERN_IDENT_AFTER_HROCKET
- - PATTERN_LABEL_AFTER_COMMA
- - PATTERN_REST
- - PATTERN_TERM_BRACE
- - PATTERN_TERM_BRACKET
- - PATTERN_TERM_PAREN
- - PIPEPIPEEQ_MULTI_ASSIGN
- - REGEXP_ENCODING_OPTION_MISMATCH
- - REGEXP_INCOMPAT_CHAR_ENCODING
- - REGEXP_INVALID_UNICODE_RANGE
- - REGEXP_NON_ESCAPED_MBC
- - REGEXP_PARSE_ERROR
- - REGEXP_TERM
- - REGEXP_UNKNOWN_OPTIONS
- - REGEXP_UTF8_CHAR_NON_UTF8_REGEXP
- - RESCUE_EXPRESSION
- - RESCUE_MODIFIER_VALUE
- - RESCUE_TERM
- - RESCUE_VARIABLE
- - RETURN_INVALID
- - SCRIPT_NOT_FOUND
- - SINGLETON_FOR_LITERALS
- - STATEMENT_ALIAS
- - STATEMENT_POSTEXE_END
- - STATEMENT_PREEXE_BEGIN
- - STATEMENT_UNDEF
- - STRING_CONCATENATION
- - STRING_INTERPOLATED_TERM
- - STRING_LITERAL_EOF
- - STRING_LITERAL_TERM
- - SYMBOL_INVALID
- - SYMBOL_TERM_DYNAMIC
- - SYMBOL_TERM_INTERPOLATED
- - TERNARY_COLON
- - TERNARY_EXPRESSION_FALSE
- - TERNARY_EXPRESSION_TRUE
- - UNARY_DISALLOWED
- - UNARY_RECEIVER
- - UNDEF_ARGUMENT
- - UNEXPECTED_BLOCK_ARGUMENT
- - UNEXPECTED_INDEX_BLOCK
- - UNEXPECTED_INDEX_KEYWORDS
- - UNEXPECTED_LABEL
- - UNEXPECTED_MULTI_WRITE
- - UNEXPECTED_RANGE_OPERATOR
- - UNEXPECTED_SAFE_NAVIGATION
- - UNEXPECTED_TOKEN_CLOSE_CONTEXT
- - UNEXPECTED_TOKEN_IGNORE
- - UNTIL_TERM
- - VOID_EXPRESSION
- - WHILE_TERM
- - WRITE_TARGET_IN_METHOD
- - WRITE_TARGET_READONLY
- - WRITE_TARGET_UNEXPECTED
- - XSTRING_TERM
-warnings:
- - AMBIGUOUS_BINARY_OPERATOR
- - AMBIGUOUS_FIRST_ARGUMENT_MINUS
- - AMBIGUOUS_FIRST_ARGUMENT_PLUS
- - AMBIGUOUS_PREFIX_AMPERSAND
- - AMBIGUOUS_PREFIX_STAR
- - AMBIGUOUS_PREFIX_STAR_STAR
- - AMBIGUOUS_SLASH
- - COMPARISON_AFTER_COMPARISON
- - DOT_DOT_DOT_EOL
- - EQUAL_IN_CONDITIONAL
- - EQUAL_IN_CONDITIONAL_3_3
- - END_IN_METHOD
- - DUPLICATED_HASH_KEY
- - DUPLICATED_WHEN_CLAUSE
- - FLOAT_OUT_OF_RANGE
- - IGNORED_FROZEN_STRING_LITERAL
- - INDENTATION_MISMATCH
- - INTEGER_IN_FLIP_FLOP
- - INVALID_CHARACTER
- - INVALID_MAGIC_COMMENT_VALUE
- - INVALID_NUMBERED_REFERENCE
- - KEYWORD_EOL
- - LITERAL_IN_CONDITION_DEFAULT
- - LITERAL_IN_CONDITION_VERBOSE
- - SHAREABLE_CONSTANT_VALUE_LINE
- - SHEBANG_CARRIAGE_RETURN
- - UNEXPECTED_CARRIAGE_RETURN
- - UNREACHABLE_STATEMENT
- - UNUSED_LOCAL_VARIABLE
- - VOID_STATEMENT
-tokens:
- - name: EOF
- value: 1
- comment: final token in the file
- - name: MISSING
- comment: "a token that was expected but not found"
- - name: NOT_PROVIDED
- comment: "a token that was not present but it is okay"
- - name: AMPERSAND
- comment: "&"
- - name: AMPERSAND_AMPERSAND
- comment: "&&"
- - name: AMPERSAND_AMPERSAND_EQUAL
- comment: "&&="
- - name: AMPERSAND_DOT
- comment: "&."
- - name: AMPERSAND_EQUAL
- comment: "&="
- - name: BACKTICK
- comment: "`"
- - name: BACK_REFERENCE
- comment: "a back reference"
- - name: BANG
- comment: "! or !@"
- - name: BANG_EQUAL
- comment: "!="
- - name: BANG_TILDE
- comment: "!~"
- - name: BRACE_LEFT
- comment: "{"
- - name: BRACE_RIGHT
- comment: "}"
- - name: BRACKET_LEFT
- comment: "["
- - name: BRACKET_LEFT_ARRAY
- comment: "[ for the beginning of an array"
- - name: BRACKET_LEFT_RIGHT
- comment: "[]"
- - name: BRACKET_LEFT_RIGHT_EQUAL
- comment: "[]="
- - name: BRACKET_RIGHT
- comment: "]"
- - name: CARET
- comment: "^"
- - name: CARET_EQUAL
- comment: "^="
- - name: CHARACTER_LITERAL
- comment: "a character literal"
- - name: CLASS_VARIABLE
- comment: "a class variable"
- - name: COLON
- comment: ":"
- - name: COLON_COLON
- comment: "::"
- - name: COMMA
- comment: ","
- - name: COMMENT
- comment: "a comment"
- - name: CONSTANT
- comment: "a constant"
- - name: DOT
- comment: "the . call operator"
- - name: DOT_DOT
- comment: "the .. range operator"
- - name: DOT_DOT_DOT
- comment: "the ... range operator or forwarding parameter"
- - name: EMBDOC_BEGIN
- comment: "=begin"
- - name: EMBDOC_END
- comment: "=end"
- - name: EMBDOC_LINE
- comment: "a line inside of embedded documentation"
- - name: EMBEXPR_BEGIN
- comment: "#{"
- - name: EMBEXPR_END
- comment: "}"
- - name: EMBVAR
- comment: "#"
- - name: EQUAL
- comment: "="
- - name: EQUAL_EQUAL
- comment: "=="
- - name: EQUAL_EQUAL_EQUAL
- comment: "==="
- - name: EQUAL_GREATER
- comment: "=>"
- - name: EQUAL_TILDE
- comment: "=~"
- - name: FLOAT
- comment: "a floating point number"
- - name: FLOAT_IMAGINARY
- comment: "a floating pointer number with an imaginary suffix"
- - name: FLOAT_RATIONAL
- comment: "a floating pointer number with a rational suffix"
- - name: FLOAT_RATIONAL_IMAGINARY
- comment: "a floating pointer number with a rational and imaginary suffix"
- - name: GLOBAL_VARIABLE
- comment: "a global variable"
- - name: GREATER
- comment: ">"
- - name: GREATER_EQUAL
- comment: ">="
- - name: GREATER_GREATER
- comment: ">>"
- - name: GREATER_GREATER_EQUAL
- comment: ">>="
- - name: HEREDOC_END
- comment: "the end of a heredoc"
- - name: HEREDOC_START
- comment: "the start of a heredoc"
- - name: IDENTIFIER
- comment: "an identifier"
- - name: IGNORED_NEWLINE
- comment: "an ignored newline"
- - name: INSTANCE_VARIABLE
- comment: "an instance variable"
- - name: INTEGER
- comment: "an integer (any base)"
- - name: INTEGER_IMAGINARY
- comment: "an integer with an imaginary suffix"
- - name: INTEGER_RATIONAL
- comment: "an integer with a rational suffix"
- - name: INTEGER_RATIONAL_IMAGINARY
- comment: "an integer with a rational and imaginary suffix"
- - name: KEYWORD_ALIAS
- comment: "alias"
- - name: KEYWORD_AND
- comment: "and"
- - name: KEYWORD_BEGIN
- comment: "begin"
- - name: KEYWORD_BEGIN_UPCASE
- comment: "BEGIN"
- - name: KEYWORD_BREAK
- comment: "break"
- - name: KEYWORD_CASE
- comment: "case"
- - name: KEYWORD_CLASS
- comment: "class"
- - name: KEYWORD_DEF
- comment: "def"
- - name: KEYWORD_DEFINED
- comment: "defined?"
- - name: KEYWORD_DO
- comment: "do"
- - name: KEYWORD_DO_LOOP
- comment: "do keyword for a predicate in a while, until, or for loop"
- - name: KEYWORD_ELSE
- comment: "else"
- - name: KEYWORD_ELSIF
- comment: "elsif"
- - name: KEYWORD_END
- comment: "end"
- - name: KEYWORD_END_UPCASE
- comment: "END"
- - name: KEYWORD_ENSURE
- comment: "ensure"
- - name: KEYWORD_FALSE
- comment: "false"
- - name: KEYWORD_FOR
- comment: "for"
- - name: KEYWORD_IF
- comment: "if"
- - name: KEYWORD_IF_MODIFIER
- comment: "if in the modifier form"
- - name: KEYWORD_IN
- comment: "in"
- - name: KEYWORD_MODULE
- comment: "module"
- - name: KEYWORD_NEXT
- comment: "next"
- - name: KEYWORD_NIL
- comment: "nil"
- - name: KEYWORD_NOT
- comment: "not"
- - name: KEYWORD_OR
- comment: "or"
- - name: KEYWORD_REDO
- comment: "redo"
- - name: KEYWORD_RESCUE
- comment: "rescue"
- - name: KEYWORD_RESCUE_MODIFIER
- comment: "rescue in the modifier form"
- - name: KEYWORD_RETRY
- comment: "retry"
- - name: KEYWORD_RETURN
- comment: "return"
- - name: KEYWORD_SELF
- comment: "self"
- - name: KEYWORD_SUPER
- comment: "super"
- - name: KEYWORD_THEN
- comment: "then"
- - name: KEYWORD_TRUE
- comment: "true"
- - name: KEYWORD_UNDEF
- comment: "undef"
- - name: KEYWORD_UNLESS
- comment: "unless"
- - name: KEYWORD_UNLESS_MODIFIER
- comment: "unless in the modifier form"
- - name: KEYWORD_UNTIL
- comment: "until"
- - name: KEYWORD_UNTIL_MODIFIER
- comment: "until in the modifier form"
- - name: KEYWORD_WHEN
- comment: "when"
- - name: KEYWORD_WHILE
- comment: "while"
- - name: KEYWORD_WHILE_MODIFIER
- comment: "while in the modifier form"
- - name: KEYWORD_YIELD
- comment: "yield"
- - name: KEYWORD___ENCODING__
- comment: "__ENCODING__"
- - name: KEYWORD___FILE__
- comment: "__FILE__"
- - name: KEYWORD___LINE__
- comment: "__LINE__"
- - name: LABEL
- comment: "a label"
- - name: LABEL_END
- comment: "the end of a label"
- - name: LAMBDA_BEGIN
- comment: "{"
- - name: LESS
- comment: "<"
- - name: LESS_EQUAL
- comment: "<="
- - name: LESS_EQUAL_GREATER
- comment: "<=>"
- - name: LESS_LESS
- comment: "<<"
- - name: LESS_LESS_EQUAL
- comment: "<<="
- - name: METHOD_NAME
- comment: "a method name"
- - name: MINUS
- comment: "-"
- - name: MINUS_EQUAL
- comment: "-="
- - name: MINUS_GREATER
- comment: "->"
- - name: NEWLINE
- comment: "a newline character outside of other tokens"
- - name: NUMBERED_REFERENCE
- comment: "a numbered reference to a capture group in the previous regular expression match"
- - name: PARENTHESIS_LEFT
- comment: "("
- - name: PARENTHESIS_LEFT_PARENTHESES
- comment: "( for a parentheses node"
- - name: PARENTHESIS_RIGHT
- comment: ")"
- - name: PERCENT
- comment: "%"
- - name: PERCENT_EQUAL
- comment: "%="
- - name: PERCENT_LOWER_I
- comment: "%i"
- - name: PERCENT_LOWER_W
- comment: "%w"
- - name: PERCENT_LOWER_X
- comment: "%x"
- - name: PERCENT_UPPER_I
- comment: "%I"
- - name: PERCENT_UPPER_W
- comment: "%W"
- - name: PIPE
- comment: "|"
- - name: PIPE_EQUAL
- comment: "|="
- - name: PIPE_PIPE
- comment: "||"
- - name: PIPE_PIPE_EQUAL
- comment: "||="
- - name: PLUS
- comment: "+"
- - name: PLUS_EQUAL
- comment: "+="
- - name: QUESTION_MARK
- comment: "?"
- - name: REGEXP_BEGIN
- comment: "the beginning of a regular expression"
- - name: REGEXP_END
- comment: "the end of a regular expression"
- - name: SEMICOLON
- comment: ";"
- - name: SLASH
- comment: "/"
- - name: SLASH_EQUAL
- comment: "/="
- - name: STAR
- comment: "*"
- - name: STAR_EQUAL
- comment: "*="
- - name: STAR_STAR
- comment: "**"
- - name: STAR_STAR_EQUAL
- comment: "**="
- - name: STRING_BEGIN
- comment: "the beginning of a string"
- - name: STRING_CONTENT
- comment: "the contents of a string"
- - name: STRING_END
- comment: "the end of a string"
- - name: SYMBOL_BEGIN
- comment: "the beginning of a symbol"
- - name: TILDE
- comment: "~ or ~@"
- - name: UAMPERSAND
- comment: "unary &"
- - name: UCOLON_COLON
- comment: "unary ::"
- - name: UDOT_DOT
- comment: "unary .. operator"
- - name: UDOT_DOT_DOT
- comment: "unary ... operator"
- - name: UMINUS
- comment: "-@"
- - name: UMINUS_NUM
- comment: "-@ for a number"
- - name: UPLUS
- comment: "+@"
- - name: USTAR
- comment: "unary *"
- - name: USTAR_STAR
- comment: "unary **"
- - name: WORDS_SEP
- comment: "a separator between words in a list"
- - name: __END__
- comment: "marker for the point in the file at which the parser should stop"
-flags:
- - name: ArgumentsNodeFlags
- values:
- - name: CONTAINS_FORWARDING
- comment: "if the arguments contain forwarding"
- - name: CONTAINS_KEYWORDS
- comment: "if the arguments contain keywords"
- - name: CONTAINS_KEYWORD_SPLAT
- comment: "if the arguments contain a keyword splat"
- - name: CONTAINS_SPLAT
- comment: "if the arguments contain a splat"
- - name: CONTAINS_MULTIPLE_SPLATS
- comment: "if the arguments contain multiple splats"
- comment: Flags for arguments nodes.
- - name: ArrayNodeFlags
- values:
- - name: CONTAINS_SPLAT
- comment: "if array contains splat nodes"
- comment: Flags for array nodes.
- - name: CallNodeFlags
- values:
- - name: SAFE_NAVIGATION
- comment: "&. operator"
- - name: VARIABLE_CALL
- comment: "a call that could have been a local variable"
- - name: ATTRIBUTE_WRITE
- comment: "a call that is an attribute write, so the value being written should be returned"
- - name: IGNORE_VISIBILITY
- comment: "a call that ignores method visibility"
- comment: Flags for call nodes.
- - name: EncodingFlags
- values:
- - name: FORCED_UTF8_ENCODING
- comment: "internal bytes forced the encoding to UTF-8"
- - name: FORCED_BINARY_ENCODING
- comment: "internal bytes forced the encoding to binary"
- comment: Flags for nodes that have unescaped content.
- - name: IntegerBaseFlags
- values:
- - name: BINARY
- comment: "0b prefix"
- - name: DECIMAL
- comment: "0d or no prefix"
- - name: OCTAL
- comment: "0o or 0 prefix"
- - name: HEXADECIMAL
- comment: "0x prefix"
- comment: Flags for integer nodes that correspond to the base of the integer.
- - name: InterpolatedStringNodeFlags
- values:
- - name: FROZEN
- comment: "frozen by virtue of a `frozen_string_literal: true` comment or `--enable-frozen-string-literal`; only for adjacent string literals like `'a' 'b'`"
- - name: MUTABLE
- comment: "mutable by virtue of a `frozen_string_literal: false` comment or `--disable-frozen-string-literal`; only for adjacent string literals like `'a' 'b'`"
- comment: Flags for interpolated string nodes that indicated mutability if they are also marked as literals.
- - name: KeywordHashNodeFlags
- values:
- - name: SYMBOL_KEYS
- comment: "a keyword hash which only has `AssocNode` elements all with symbol keys, which means the elements can be treated as keyword arguments"
- comment: Flags for keyword hash nodes.
- - name: LoopFlags
- values:
- - name: BEGIN_MODIFIER
- comment: "a loop after a begin statement, so the body is executed first before the condition"
- comment: Flags for while and until loop nodes.
- - name: ParameterFlags
- values:
- - name: REPEATED_PARAMETER
- comment: "a parameter name that has been repeated in the method signature"
- comment: Flags for parameter nodes.
- - name: RangeFlags
- values:
- - name: EXCLUDE_END
- comment: "... operator"
- comment: Flags for range and flip-flop nodes.
- - name: RegularExpressionFlags
- values:
- - name: IGNORE_CASE
- comment: "i - ignores the case of characters when matching"
- - name: EXTENDED
- comment: "x - ignores whitespace and allows comments in regular expressions"
- - name: MULTI_LINE
- comment: "m - allows $ to match the end of lines within strings"
- - name: ONCE
- comment: "o - only interpolates values into the regular expression once"
- - name: EUC_JP
- comment: "e - forces the EUC-JP encoding"
- - name: ASCII_8BIT
- comment: "n - forces the ASCII-8BIT encoding"
- - name: WINDOWS_31J
- comment: "s - forces the Windows-31J encoding"
- - name: UTF_8
- comment: "u - forces the UTF-8 encoding"
- - name: FORCED_UTF8_ENCODING
- comment: "internal bytes forced the encoding to UTF-8"
- - name: FORCED_BINARY_ENCODING
- comment: "internal bytes forced the encoding to binary"
- - name: FORCED_US_ASCII_ENCODING
- comment: "internal bytes forced the encoding to US-ASCII"
- comment: Flags for regular expression and match last line nodes.
- - name: ShareableConstantNodeFlags
- values:
- - name: LITERAL
- comment: "constant writes that should be modified with shareable constant value literal"
- - name: EXPERIMENTAL_EVERYTHING
- comment: "constant writes that should be modified with shareable constant value experimental everything"
- - name: EXPERIMENTAL_COPY
- comment: "constant writes that should be modified with shareable constant value experimental copy"
- comment: Flags for shareable constant nodes.
- - name: StringFlags
- values:
- - name: FORCED_UTF8_ENCODING
- comment: "internal bytes forced the encoding to UTF-8"
- - name: FORCED_BINARY_ENCODING
- comment: "internal bytes forced the encoding to binary"
- - name: FROZEN
- comment: "frozen by virtue of a `frozen_string_literal: true` comment or `--enable-frozen-string-literal`"
- - name: MUTABLE
- comment: "mutable by virtue of a `frozen_string_literal: false` comment or `--disable-frozen-string-literal`"
- comment: Flags for string nodes.
- - name: SymbolFlags
- values:
- - name: FORCED_UTF8_ENCODING
- comment: "internal bytes forced the encoding to UTF-8"
- - name: FORCED_BINARY_ENCODING
- comment: "internal bytes forced the encoding to binary"
- - name: FORCED_US_ASCII_ENCODING
- comment: "internal bytes forced the encoding to US-ASCII"
- comment: Flags for symbol nodes.
-nodes:
- - name: AliasGlobalVariableNode
- fields:
- - name: new_name
- type: node
- kind:
- - GlobalVariableReadNode
- - BackReferenceReadNode
- - NumberedReferenceReadNode
- comment: |
- Represents the new name of the global variable that can be used after aliasing.
-
- alias $foo $bar
- ^^^^
- - name: old_name
- type: node
- kind:
- - GlobalVariableReadNode
- - BackReferenceReadNode
- - NumberedReferenceReadNode
- - on error: SymbolNode # alias $a b
- - on error: MissingNode # alias $a 42
- comment: |
- Represents the old name of the global variable that can be used before aliasing.
-
- alias $foo $bar
- ^^^^
- - name: keyword_loc
- type: location
- comment: |
- The location of the `alias` keyword.
-
- alias $foo $bar
- ^^^^^
- comment: |
- Represents the use of the `alias` keyword to alias a global variable.
-
- alias $foo $bar
- ^^^^^^^^^^^^^^^
- - name: AliasMethodNode
- fields:
- - name: new_name
- type: node
- kind:
- - SymbolNode
- - InterpolatedSymbolNode
- comment: |
- Represents the new name of the method that will be aliased.
-
- alias foo bar
- ^^^
-
- alias :foo :bar
- ^^^^
-
- alias :"#{foo}" :"#{bar}"
- ^^^^^^^^^
- - name: old_name
- type: node
- kind:
- - SymbolNode
- - InterpolatedSymbolNode
- - on error: GlobalVariableReadNode # alias a $b
- - on error: MissingNode # alias a 42
- comment: |
- Represents the old name of the method that will be aliased.
-
- alias foo bar
- ^^^
-
- alias :foo :bar
- ^^^^
-
- alias :"#{foo}" :"#{bar}"
- ^^^^^^^^^
- - name: keyword_loc
- type: location
- comment: |
- Represents the use of the `alias` keyword to alias a method.
-
- alias foo bar
- ^^^^^^^^^^^^^
- - name: AlternationPatternNode
- fields:
- - name: left
- type: node
- kind: pattern expression
- comment: |
- Represents the left side of the expression.
-
- foo => bar | baz
- ^^^
- - name: right
- type: node
- kind: pattern expression
- comment: |
- Represents the right side of the expression.
-
- foo => bar | baz
- ^^^
- - name: operator_loc
- type: location
- comment: |
- Represents the alternation operator location.
-
- foo => bar | baz
- ^
- comment: |
- Represents an alternation pattern in pattern matching.
-
- foo => bar | baz
- ^^^^^^^^^
- - name: AndNode
- fields:
- - name: left
- type: node
- kind: non-void expression
- comment: |
- Represents the left side of the expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- left and right
- ^^^^
-
- 1 && 2
- ^
- - name: right
- type: node
- kind: Node
- comment: |
- Represents the right side of the expression.
-
- left && right
- ^^^^^
-
- 1 and 2
- ^
- - name: operator_loc
- type: location
- comment: |
- The location of the `and` keyword or the `&&` operator.
-
- left and right
- ^^^
- comment: |
- Represents the use of the `&&` operator or the `and` keyword.
-
- left and right
- ^^^^^^^^^^^^^^
- - name: ArgumentsNode
- flags: ArgumentsNodeFlags
- fields:
- - name: arguments
- type: node[]
- kind: non-void expression
- comment: |
- Represents a set of arguments to a method or a keyword.
-
- return foo, bar, baz
- ^^^^^^^^^^^^^
- - name: ArrayNode
- flags: ArrayNodeFlags
- fields:
- - name: elements
- type: node[]
- kind: non-void expression
- comment: Represent the list of zero or more [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression) within the array.
- - name: opening_loc
- type: location?
- comment: |
- Represents the optional source location for the opening token.
-
- [1,2,3] # "["
- %w[foo bar baz] # "%w["
- %I(apple orange banana) # "%I("
- foo = 1, 2, 3 # nil
- - name: closing_loc
- type: location?
- comment: |
- Represents the optional source location for the closing token.
-
- [1,2,3] # "]"
- %w[foo bar baz] # "]"
- %I(apple orange banana) # ")"
- foo = 1, 2, 3 # nil
- comment: |
- Represents an array literal. This can be a regular array using brackets or a special array using % like %w or %i.
-
- [1, 2, 3]
- ^^^^^^^^^
- - name: ArrayPatternNode
- fields:
- - name: constant
- type: node?
- kind:
- - ConstantReadNode
- - ConstantPathNode
- - name: requireds
- type: node[]
- kind: pattern expression
- - name: rest
- type: node?
- kind: pattern expression
- - name: posts
- type: node[]
- kind: pattern expression
- - name: opening_loc
- type: location?
- - name: closing_loc
- type: location?
- comment: |
- Represents an array pattern in pattern matching.
-
- foo in 1, 2
- ^^^^^^^^^^^
-
- foo in [1, 2]
- ^^^^^^^^^^^^^
-
- foo in *1
- ^^^^^^^^^
-
- foo in Bar[]
- ^^^^^^^^^^^^
-
- foo in Bar[1, 2, 3]
- ^^^^^^^^^^^^^^^^^^^
- - name: AssocNode
- fields:
- - name: key
- type: node
- kind: non-void expression
- comment: |
- The key of the association. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- { a: b }
- ^
-
- { foo => bar }
- ^^^
-
- { def a; end => 1 }
- ^^^^^^^^^^
- - name: value
- type: node
- kind: non-void expression
- comment: |
- The value of the association, if present. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- { foo => bar }
- ^^^
-
- { x: 1 }
- ^
- - name: operator_loc
- type: location?
- comment: |
- The location of the `=>` operator, if present.
-
- { foo => bar }
- ^^
- comment: |
- Represents a hash key/value pair.
-
- { a => b }
- ^^^^^^
- - name: AssocSplatNode
- fields:
- - name: value
- type: node?
- kind: non-void expression
- comment: |
- The value to be splatted, if present. Will be missing when keyword rest argument forwarding is used.
-
- { **foo }
- ^^^
- - name: operator_loc
- type: location
- comment: |
- The location of the `**` operator.
-
- { **x }
- ^^
- comment: |
- Represents a splat in a hash literal.
-
- { **foo }
- ^^^^^
- - name: BackReferenceReadNode
- fields:
- - name: name
- type: constant
- comment: |
- The name of the back-reference variable, including the leading `$`.
-
- $& # name `:$&`
-
- $+ # name `:$+`
- comment: |
- Represents reading a reference to a field in the previous match.
-
- $'
- ^^
- - name: BeginNode
- fields:
- - name: begin_keyword_loc
- type: location?
- - name: statements
- type: node?
- kind: StatementsNode
- - name: rescue_clause
- type: node?
- kind: RescueNode
- - name: else_clause
- type: node?
- kind: ElseNode
- - name: ensure_clause
- type: node?
- kind: EnsureNode
- - name: end_keyword_loc
- type: location?
- newline: false
- comment: |
- Represents a begin statement.
-
- begin
- foo
- end
- ^^^^^
- - name: BlockArgumentNode
- fields:
- - name: expression
- type: node?
- kind: non-void expression
- - name: operator_loc
- type: location
- comment: |
- Represents a block argument using `&`.
-
- bar(&args)
- ^^^^^^^^^^
- - name: BlockLocalVariableNode
- flags: ParameterFlags
- fields:
- - name: name
- type: constant
- comment: |
- Represents a block local variable.
-
- a { |; b| }
- ^
- - name: BlockNode
- fields:
- - name: locals
- type: constant[]
- - name: parameters
- type: node?
- kind:
- - BlockParametersNode
- - NumberedParametersNode
- - ItParametersNode
- - name: body
- type: node?
- kind:
- - StatementsNode
- - BeginNode
- - name: opening_loc
- type: location
- - name: closing_loc
- type: location
- comment: |
- Represents a block of ruby code.
-
- [1, 2, 3].each { |i| puts x }
- ^^^^^^^^^^^^^^
- - name: BlockParameterNode
- flags: ParameterFlags
- fields:
- - name: name
- type: constant?
- - name: name_loc
- type: location?
- - name: operator_loc
- type: location
- comment: |
- Represents a block parameter of a method, block, or lambda definition.
-
- def a(&b)
- ^^
- end
- - name: BlockParametersNode
- fields:
- - name: parameters
- type: node?
- kind: ParametersNode
- - name: locals
- type: node[]
- kind: BlockLocalVariableNode
- - name: opening_loc
- type: location?
- - name: closing_loc
- type: location?
- comment: |
- Represents a block's parameters declaration.
-
- -> (a, b = 1; local) { }
- ^^^^^^^^^^^^^^^^^
-
- foo do |a, b = 1; local|
- ^^^^^^^^^^^^^^^^^
- end
- - name: BreakNode
- fields:
- - name: arguments
- type: node?
- kind: ArgumentsNode
- comment: |
- The arguments to the break statement, if present. These can be any [non-void expressions](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- break foo
- ^^^
- - name: keyword_loc
- type: location
- comment: |
- The location of the `break` keyword.
-
- break foo
- ^^^^^
- comment: |
- Represents the use of the `break` keyword.
-
- break foo
- ^^^^^^^^^
- - name: CallAndWriteNode
- flags: CallNodeFlags
- fields:
- - name: receiver
- type: node?
- kind: non-void expression
- - name: call_operator_loc
- type: location?
- - name: message_loc
- type: location?
- - name: read_name
- type: constant
- - name: write_name
- type: constant
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `&&=` operator on a call.
-
- foo.bar &&= value
- ^^^^^^^^^^^^^^^^^
- - name: CallNode
- flags: CallNodeFlags
- fields:
- - name: receiver
- type: node?
- kind: non-void expression
- comment: |
- The object that the method is being called on. This can be either `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- foo.bar
- ^^^
-
- +foo
- ^^^
-
- foo + bar
- ^^^
- - name: call_operator_loc
- type: location?
- - name: name
- type: constant
- - name: message_loc
- type: location?
- - name: opening_loc
- type: location?
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: closing_loc
- type: location?
- - name: block
- type: node?
- kind:
- - BlockNode
- - BlockArgumentNode
- comment: |
- Represents a method call, in all of the various forms that can take.
-
- foo
- ^^^
-
- foo()
- ^^^^^
-
- +foo
- ^^^^
-
- foo + bar
- ^^^^^^^^^
-
- foo.bar
- ^^^^^^^
-
- foo&.bar
- ^^^^^^^^
- - name: CallOperatorWriteNode
- flags: CallNodeFlags
- fields:
- - name: receiver
- type: node?
- kind: non-void expression
- - name: call_operator_loc
- type: location?
- - name: message_loc
- type: location?
- - name: read_name
- type: constant
- - name: write_name
- type: constant
- - name: binary_operator
- type: constant
- - name: binary_operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of an assignment operator on a call.
-
- foo.bar += baz
- ^^^^^^^^^^^^^^
- - name: CallOrWriteNode
- flags: CallNodeFlags
- fields:
- - name: receiver
- type: node?
- kind: non-void expression
- - name: call_operator_loc
- type: location?
- - name: message_loc
- type: location?
- - name: read_name
- type: constant
- - name: write_name
- type: constant
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `||=` operator on a call.
-
- foo.bar ||= value
- ^^^^^^^^^^^^^^^^^
- - name: CallTargetNode
- flags: CallNodeFlags
- fields:
- - name: receiver
- type: node
- kind: non-void expression
- - name: call_operator_loc
- type: location
- - name: name
- type: constant
- - name: message_loc
- type: location
- comment: |
- Represents assigning to a method call.
-
- foo.bar, = 1
- ^^^^^^^
-
- begin
- rescue => foo.bar
- ^^^^^^^
- end
-
- for foo.bar in baz do end
- ^^^^^^^
- - name: CapturePatternNode
- fields:
- - name: value
- type: node
- kind: pattern expression
- - name: target
- type: node
- kind: LocalVariableTargetNode
- - name: operator_loc
- type: location
- comment: |
- Represents assigning to a local variable in pattern matching.
-
- foo => [bar => baz]
- ^^^^^^^^^^^^
- - name: CaseMatchNode
- fields:
- - name: predicate
- type: node?
- kind: non-void expression
- - name: conditions
- type: node[]
- kind: InNode
- - name: else_clause
- type: node?
- kind: ElseNode
- - name: case_keyword_loc
- type: location
- - name: end_keyword_loc
- type: location
- comment: |
- Represents the use of a case statement for pattern matching.
-
- case true
- in false
- end
- ^^^^^^^^^
- - name: CaseNode
- fields:
- - name: predicate
- type: node?
- kind: non-void expression
- - name: conditions
- type: node[]
- kind: WhenNode
- - name: else_clause
- type: node?
- kind: ElseNode
- - name: case_keyword_loc
- type: location
- - name: end_keyword_loc
- type: location
- comment: |
- Represents the use of a case statement.
-
- case true
- when false
- end
- ^^^^^^^^^^
- - name: ClassNode
- fields:
- - name: locals
- type: constant[]
- - name: class_keyword_loc
- type: location
- - name: constant_path
- type: node
- kind:
- - ConstantReadNode
- - ConstantPathNode
- - on error: CallNode # class 0.X end
- - name: inheritance_operator_loc
- type: location?
- - name: superclass
- type: node?
- kind: non-void expression
- - name: body
- type: node?
- kind:
- - StatementsNode
- - BeginNode
- - name: end_keyword_loc
- type: location
- - name: name
- type: constant
- comment: |
- Represents a class declaration involving the `class` keyword.
-
- class Foo end
- ^^^^^^^^^^^^^
- - name: ClassVariableAndWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `&&=` operator for assignment to a class variable.
-
- @@target &&= value
- ^^^^^^^^^^^^^^^^^^
- - name: ClassVariableOperatorWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: binary_operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- - name: binary_operator
- type: constant
- comment: |
- Represents assigning to a class variable using an operator that isn't `=`.
-
- @@target += value
- ^^^^^^^^^^^^^^^^^
- - name: ClassVariableOrWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `||=` operator for assignment to a class variable.
-
- @@target ||= value
- ^^^^^^^^^^^^^^^^^^
- - name: ClassVariableReadNode
- fields:
- - name: name
- type: constant
- comment: |
- The name of the class variable, which is a `@@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
-
- @@abc # name `:@@abc`
-
- @@_test # name `:@@_test`
- comment: |
- Represents referencing a class variable.
-
- @@foo
- ^^^^^
- - name: ClassVariableTargetNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents writing to a class variable in a context that doesn't have an explicit value.
-
- @@foo, @@bar = baz
- ^^^^^ ^^^^^
- - name: ClassVariableWriteNode
- fields:
- - name: name
- type: constant
- comment: |
- The name of the class variable, which is a `@@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
-
- @@abc = 123 # name `@@abc`
-
- @@_test = :test # name `@@_test`
- - name: name_loc
- type: location
- comment: |
- The location of the variable name.
-
- @@foo = :bar
- ^^^^^
- - name: value
- type: node
- kind: non-void expression
- comment: |
- The value to write to the class variable. This can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- @@foo = :bar
- ^^^^
-
- @@_xyz = 123
- ^^^
- - name: operator_loc
- type: location
- comment: |
- The location of the `=` operator.
-
- @@foo = :bar
- ^
- comment: |
- Represents writing to a class variable.
-
- @@foo = 1
- ^^^^^^^^^
- - name: ConstantAndWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `&&=` operator for assignment to a constant.
-
- Target &&= value
- ^^^^^^^^^^^^^^^^
- - name: ConstantOperatorWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: binary_operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- - name: binary_operator
- type: constant
- comment: |
- Represents assigning to a constant using an operator that isn't `=`.
-
- Target += value
- ^^^^^^^^^^^^^^^
- - name: ConstantOrWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `||=` operator for assignment to a constant.
-
- Target ||= value
- ^^^^^^^^^^^^^^^^
- - name: ConstantPathAndWriteNode
- fields:
- - name: target
- type: node
- kind: ConstantPathNode
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `&&=` operator for assignment to a constant path.
-
- Parent::Child &&= value
- ^^^^^^^^^^^^^^^^^^^^^^^
- - name: ConstantPathNode
- fields:
- - name: parent
- type: node?
- kind: non-void expression
- comment: |
- The left-hand node of the path, if present. It can be `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression). It will be `nil` when the constant lookup is at the root of the module tree.
-
- Foo::Bar
- ^^^
-
- self::Test
- ^^^^
-
- a.b::C
- ^^^
- - name: name
- type: constant?
- comment: The name of the constant being accessed. This could be `nil` in the event of a syntax error.
- - name: delimiter_loc
- type: location
- comment: |
- The location of the `::` delimiter.
-
- ::Foo
- ^^
-
- One::Two
- ^^
- - name: name_loc
- type: location
- comment: |
- The location of the name of the constant.
-
- ::Foo
- ^^^
-
- One::Two
- ^^^
- comment: |
- Represents accessing a constant through a path of `::` operators.
-
- Foo::Bar
- ^^^^^^^^
- - name: ConstantPathOperatorWriteNode
- fields:
- - name: target
- type: node
- kind: ConstantPathNode
- - name: binary_operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- - name: binary_operator
- type: constant
- comment: |
- Represents assigning to a constant path using an operator that isn't `=`.
-
- Parent::Child += value
- ^^^^^^^^^^^^^^^^^^^^^^
- - name: ConstantPathOrWriteNode
- fields:
- - name: target
- type: node
- kind: ConstantPathNode
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `||=` operator for assignment to a constant path.
-
- Parent::Child ||= value
- ^^^^^^^^^^^^^^^^^^^^^^^
- - name: ConstantPathTargetNode
- fields:
- - name: parent
- type: node?
- kind: non-void expression
- - name: name
- type: constant?
- - name: delimiter_loc
- type: location
- - name: name_loc
- type: location
- comment: |
- Represents writing to a constant path in a context that doesn't have an explicit value.
-
- Foo::Foo, Bar::Bar = baz
- ^^^^^^^^ ^^^^^^^^
- - name: ConstantPathWriteNode
- fields:
- - name: target
- type: node
- kind: ConstantPathNode
- comment: |
- A node representing the constant path being written to.
-
- Foo::Bar = 1
- ^^^^^^^^
-
- ::Foo = :abc
- ^^^^^
- - name: operator_loc
- type: location
- comment: |
- The location of the `=` operator.
-
- ::ABC = 123
- ^
- - name: value
- type: node
- kind: non-void expression
- comment: |
- The value to write to the constant path. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- FOO::BAR = :abc
- ^^^^
- comment: |
- Represents writing to a constant path.
-
- ::Foo = 1
- ^^^^^^^^^
-
- Foo::Bar = 1
- ^^^^^^^^^^^^
-
- ::Foo::Bar = 1
- ^^^^^^^^^^^^^^
- - name: ConstantReadNode
- fields:
- - name: name
- type: constant
- comment: |
- The name of the [constant](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#constants).
-
- X # name `:X`
-
- SOME_CONSTANT # name `:SOME_CONSTANT`
- comment: |
- Represents referencing a constant.
-
- Foo
- ^^^
- - name: ConstantTargetNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents writing to a constant in a context that doesn't have an explicit value.
-
- Foo, Bar = baz
- ^^^ ^^^
- - name: ConstantWriteNode
- fields:
- - name: name
- type: constant
- comment: |
- The name of the [constant](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#constants).
-
- Foo = :bar # name `:Foo`
-
- XYZ = 1 # name `:XYZ`
- - name: name_loc
- type: location
- comment: |
- The location of the constant name.
-
- FOO = 1
- ^^^
- - name: value
- type: node
- kind: non-void expression
- comment: |
- The value to write to the constant. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- FOO = :bar
- ^^^^
-
- MyClass = Class.new
- ^^^^^^^^^
- - name: operator_loc
- type: location
- comment: |
- The location of the `=` operator.
-
- FOO = :bar
- ^
- comment: |
- Represents writing to a constant.
-
- Foo = 1
- ^^^^^^^
- - name: DefNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: receiver
- type: node?
- kind: non-void expression
- - name: parameters
- type: node?
- kind: ParametersNode
- - name: body
- type: node?
- kind:
- - StatementsNode
- - BeginNode
- - name: locals
- type: constant[]
- - name: def_keyword_loc
- type: location
- - name: operator_loc
- type: location?
- - name: lparen_loc
- type: location?
- - name: rparen_loc
- type: location?
- - name: equal_loc
- type: location?
- - name: end_keyword_loc
- type: location?
- comment: |
- Represents a method definition.
-
- def method
- end
- ^^^^^^^^^^
- - name: DefinedNode
- fields:
- - name: lparen_loc
- type: location?
- - name: value
- type: node
- kind: Node # More than non-void expression as defined?(return) is allowed, yet defined?(BEGIN{}) is SyntaxError
- - name: rparen_loc
- type: location?
- - name: keyword_loc
- type: location
- comment: |
- Represents the use of the `defined?` keyword.
-
- defined?(a)
- ^^^^^^^^^^^
- - name: ElseNode
- fields:
- - name: else_keyword_loc
- type: location
- - name: statements
- type: node?
- kind: StatementsNode
- - name: end_keyword_loc
- type: location?
- comment: |
- Represents an `else` clause in a `case`, `if`, or `unless` statement.
-
- if a then b else c end
- ^^^^^^^^^^
- - name: EmbeddedStatementsNode
- fields:
- - name: opening_loc
- type: location
- - name: statements
- type: node?
- kind: StatementsNode
- - name: closing_loc
- type: location
- comment: |
- Represents an interpolated set of statements.
-
- "foo #{bar}"
- ^^^^^^
- - name: EmbeddedVariableNode
- fields:
- - name: operator_loc
- type: location
- - name: variable
- type: node
- kind:
- - InstanceVariableReadNode
- - ClassVariableReadNode
- - GlobalVariableReadNode
- - BackReferenceReadNode
- - NumberedReferenceReadNode
- comment: |
- Represents an interpolated variable.
-
- "foo #@bar"
- ^^^^^
- - name: EnsureNode
- fields:
- - name: ensure_keyword_loc
- type: location
- - name: statements
- type: node?
- kind: StatementsNode
- - name: end_keyword_loc
- type: location
- comment: |
- Represents an `ensure` clause in a `begin` statement.
-
- begin
- foo
- ensure
- ^^^^^^
- bar
- end
- - name: FalseNode
- comment: |
- Represents the use of the literal `false` keyword.
-
- false
- ^^^^^
- - name: FindPatternNode
- fields:
- - name: constant
- type: node?
- kind:
- - ConstantReadNode
- - ConstantPathNode
- - name: left
- type: node
- kind: SplatNode
- - name: requireds
- type: node[]
- kind: pattern expression
- - name: right
- type: node
- kind:
- - SplatNode
- - on error: MissingNode
- - name: opening_loc
- type: location?
- - name: closing_loc
- type: location?
- comment: |
- Represents a find pattern in pattern matching.
-
- foo in *bar, baz, *qux
- ^^^^^^^^^^^^^^^
-
- foo in [*bar, baz, *qux]
- ^^^^^^^^^^^^^^^^^
-
- foo in Foo(*bar, baz, *qux)
- ^^^^^^^^^^^^^^^^^^^^
- - name: FlipFlopNode
- flags: RangeFlags
- fields:
- - name: left
- type: node?
- kind: non-void expression
- - name: right
- type: node?
- kind: non-void expression
- - name: operator_loc
- type: location
- comment: |
- Represents the use of the `..` or `...` operators to create flip flops.
-
- baz if foo .. bar
- ^^^^^^^^^^
- - name: FloatNode
- fields:
- - name: value
- type: double
- comment: The value of the floating point number as a Float.
- comment: |
- Represents a floating point number literal.
-
- 1.0
- ^^^
- - name: ForNode
- fields:
- - name: index
- type: node
- kind:
- - LocalVariableTargetNode
- - InstanceVariableTargetNode
- - ClassVariableTargetNode
- - GlobalVariableTargetNode
- - ConstantTargetNode
- - ConstantPathTargetNode
- - CallTargetNode
- - IndexTargetNode
- - MultiTargetNode
- - on error: BackReferenceReadNode # for $& in a end
- - on error: NumberedReferenceReadNode # for $1 in a end
- - on error: MissingNode # for in 1..10; end
- comment: |
- The index expression for `for` loops.
-
- for i in a end
- ^
- - name: collection
- type: node
- kind: non-void expression
- comment: |
- The collection to iterate over.
-
- for i in a end
- ^
- - name: statements
- type: node?
- kind: StatementsNode
- comment: |
- Represents the body of statements to execute for each iteration of the loop.
-
- for i in a
- foo(i)
- ^^^^^^
- end
- - name: for_keyword_loc
- type: location
- comment: |
- The location of the `for` keyword.
-
- for i in a end
- ^^^
- - name: in_keyword_loc
- type: location
- comment: |
- The location of the `in` keyword.
-
- for i in a end
- ^^
- - name: do_keyword_loc
- type: location?
- comment: |
- The location of the `do` keyword, if present.
-
- for i in a do end
- ^^
- - name: end_keyword_loc
- type: location
- comment: |
- The location of the `end` keyword.
-
- for i in a end
- ^^^
- comment: |
- Represents the use of the `for` keyword.
-
- for i in a end
- ^^^^^^^^^^^^^^
- - name: ForwardingArgumentsNode
- comment: |
- Represents forwarding all arguments to this method to another method.
-
- def foo(...)
- bar(...)
- ^^^
- end
- - name: ForwardingParameterNode
- comment: |
- Represents the use of the forwarding parameter in a method, block, or lambda declaration.
-
- def foo(...)
- ^^^
- end
- - name: ForwardingSuperNode
- fields:
- - name: block
- type: node?
- kind: BlockNode
- comment: |
- Represents the use of the `super` keyword without parentheses or arguments.
-
- super
- ^^^^^
- - name: GlobalVariableAndWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `&&=` operator for assignment to a global variable.
-
- $target &&= value
- ^^^^^^^^^^^^^^^^^
- - name: GlobalVariableOperatorWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: binary_operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- - name: binary_operator
- type: constant
- comment: |
- Represents assigning to a global variable using an operator that isn't `=`.
-
- $target += value
- ^^^^^^^^^^^^^^^^
- - name: GlobalVariableOrWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `||=` operator for assignment to a global variable.
-
- $target ||= value
- ^^^^^^^^^^^^^^^^^
- - name: GlobalVariableReadNode
- fields:
- - name: name
- type: constant
- comment: |
- The name of the global variable, which is a `$` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifier). Alternatively, it can be one of the special global variables designated by a symbol.
-
- $foo # name `:$foo`
-
- $_Test # name `:$_Test`
- comment: |
- Represents referencing a global variable.
-
- $foo
- ^^^^
- - name: GlobalVariableTargetNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents writing to a global variable in a context that doesn't have an explicit value.
-
- $foo, $bar = baz
- ^^^^ ^^^^
- - name: GlobalVariableWriteNode
- fields:
- - name: name
- type: constant
- comment: |
- The name of the global variable, which is a `$` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifier). Alternatively, it can be one of the special global variables designated by a symbol.
-
- $foo = :bar # name `:$foo`
-
- $_Test = 123 # name `:$_Test`
- - name: name_loc
- type: location
- comment: |
- The location of the global variable's name.
-
- $foo = :bar
- ^^^^
- - name: value
- type: node
- kind: non-void expression
- comment: |
- The value to write to the global variable. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- $foo = :bar
- ^^^^
-
- $-xyz = 123
- ^^^
- - name: operator_loc
- type: location
- comment: |
- The location of the `=` operator.
-
- $foo = :bar
- ^
- comment: |
- Represents writing to a global variable.
-
- $foo = 1
- ^^^^^^^^
- - name: HashNode
- fields:
- - name: opening_loc
- type: location
- comment: |
- The location of the opening brace.
-
- { a => b }
- ^
- - name: elements
- type: node[]
- kind:
- - AssocNode
- - AssocSplatNode
- comment: |
- The elements of the hash. These can be either `AssocNode`s or `AssocSplatNode`s.
-
- { a: b }
- ^^^^
-
- { **foo }
- ^^^^^
- - name: closing_loc
- type: location
- comment: |
- The location of the closing brace.
-
- { a => b }
- ^
- comment: |
- Represents a hash literal.
-
- { a => b }
- ^^^^^^^^^^
- - name: HashPatternNode
- fields:
- - name: constant
- type: node?
- kind:
- - ConstantReadNode
- - ConstantPathNode
- - name: elements
- type: node[]
- kind: AssocNode
- - name: rest
- type: node?
- kind:
- - AssocSplatNode
- - NoKeywordsParameterNode
- - name: opening_loc
- type: location?
- - name: closing_loc
- type: location?
- comment: |
- Represents a hash pattern in pattern matching.
-
- foo => { a: 1, b: 2 }
- ^^^^^^^^^^^^^^
-
- foo => { a: 1, b: 2, **c }
- ^^^^^^^^^^^^^^^^^^^
- - name: IfNode
- fields:
- - name: if_keyword_loc
- type: location?
- comment: |
- The location of the `if` keyword if present.
-
- bar if foo
- ^^
-
- The `if_keyword_loc` field will be `nil` when the `IfNode` represents a ternary expression.
- - name: predicate
- type: node
- kind: non-void expression
- comment: |
- The node for the condition the `IfNode` is testing.
-
- if foo
- ^^^
- bar
- end
-
- bar if foo
- ^^^
-
- foo ? bar : baz
- ^^^
- - name: then_keyword_loc
- type: location?
- comment: |
- The location of the `then` keyword (if present) or the `?` in a ternary expression, `nil` otherwise.
-
- if foo then bar end
- ^^^^
-
- a ? b : c
- ^
- - name: statements
- type: node?
- kind: StatementsNode
- comment: |
- Represents the body of statements that will be executed when the predicate is evaluated as truthy. Will be `nil` when no body is provided.
-
- if foo
- bar
- ^^^
- baz
- ^^^
- end
- - name: subsequent
- type: node?
- kind:
- - ElseNode
- - IfNode
- comment: |
- Represents an `ElseNode` or an `IfNode` when there is an `else` or an `elsif` in the `if` statement.
-
- if foo
- bar
- elsif baz
- ^^^^^^^^^
- qux
- ^^^
- end
- ^^^
-
- if foo then bar else baz end
- ^^^^^^^^^^^^
- - name: end_keyword_loc
- type: location?
- comment: |
- The location of the `end` keyword if present, `nil` otherwise.
-
- if foo
- bar
- end
- ^^^
- newline: predicate
- comment: |
- Represents the use of the `if` keyword, either in the block form or the modifier form, or a ternary expression.
-
- bar if foo
- ^^^^^^^^^^
-
- if foo then bar end
- ^^^^^^^^^^^^^^^^^^^
-
- foo ? bar : baz
- ^^^^^^^^^^^^^^^
- - name: ImaginaryNode
- fields:
- - name: numeric
- type: node
- kind:
- - FloatNode
- - IntegerNode
- - RationalNode
- comment: |
- Represents an imaginary number literal.
-
- 1.0i
- ^^^^
- - name: ImplicitNode
- fields:
- - name: value
- type: node
- kind:
- - LocalVariableReadNode
- - CallNode
- - ConstantReadNode
- - LocalVariableTargetNode
- comment: |
- Represents a node that is implicitly being added to the tree but doesn't correspond directly to a node in the source.
-
- { foo: }
- ^^^^
-
- { Foo: }
- ^^^^
-
- foo in { bar: }
- ^^^^
- - name: ImplicitRestNode
- comment: |
- Represents using a trailing comma to indicate an implicit rest parameter.
-
- foo { |bar,| }
- ^
-
- foo in [bar,]
- ^
-
- for foo, in bar do end
- ^
-
- foo, = bar
- ^
- - name: InNode
- fields:
- - name: pattern
- type: node
- kind: pattern expression
- - name: statements
- type: node?
- kind: StatementsNode
- - name: in_loc
- type: location
- - name: then_loc
- type: location?
- comment: |
- Represents the use of the `in` keyword in a case statement.
-
- case a; in b then c end
- ^^^^^^^^^^^
- - name: IndexAndWriteNode
- flags: CallNodeFlags
- fields:
- - name: receiver
- type: node?
- kind: non-void expression
- - name: call_operator_loc
- type: location?
- - name: opening_loc
- type: location
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: closing_loc
- type: location
- - name: block
- type: node?
- kind: BlockArgumentNode # foo[&b] &&= value, only valid on Ruby < 3.4
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `&&=` operator on a call to the `[]` method.
-
- foo.bar[baz] &&= value
- ^^^^^^^^^^^^^^^^^^^^^^
- - name: IndexOperatorWriteNode
- flags: CallNodeFlags
- fields:
- - name: receiver
- type: node?
- kind: non-void expression
- - name: call_operator_loc
- type: location?
- - name: opening_loc
- type: location
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: closing_loc
- type: location
- - name: block
- type: node?
- kind: BlockArgumentNode # foo[&b] += value, only valid on Ruby < 3.4
- - name: binary_operator
- type: constant
- - name: binary_operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of an assignment operator on a call to `[]`.
-
- foo.bar[baz] += value
- ^^^^^^^^^^^^^^^^^^^^^
- - name: IndexOrWriteNode
- flags: CallNodeFlags
- fields:
- - name: receiver
- type: node?
- kind: non-void expression
- - name: call_operator_loc
- type: location?
- - name: opening_loc
- type: location
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: closing_loc
- type: location
- - name: block
- type: node?
- kind: BlockArgumentNode # foo[&b] ||= value, only valid on Ruby < 3.4
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `||=` operator on a call to `[]`.
-
- foo.bar[baz] ||= value
- ^^^^^^^^^^^^^^^^^^^^^^
- - name: IndexTargetNode
- flags: CallNodeFlags
- fields:
- - name: receiver
- type: node
- kind: non-void expression
- - name: opening_loc
- type: location
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: closing_loc
- type: location
- - name: block
- type: node?
- kind: BlockArgumentNode # foo[&b], = 1, only valid on Ruby < 3.4
- comment: |
- Represents assigning to an index.
-
- foo[bar], = 1
- ^^^^^^^^
-
- begin
- rescue => foo[bar]
- ^^^^^^^^
- end
-
- for foo[bar] in baz do end
- ^^^^^^^^
- - name: InstanceVariableAndWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `&&=` operator for assignment to an instance variable.
-
- @target &&= value
- ^^^^^^^^^^^^^^^^^
- - name: InstanceVariableOperatorWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: binary_operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- - name: binary_operator
- type: constant
- comment: |
- Represents assigning to an instance variable using an operator that isn't `=`.
-
- @target += value
- ^^^^^^^^^^^^^^^^
- - name: InstanceVariableOrWriteNode
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents the use of the `||=` operator for assignment to an instance variable.
-
- @target ||= value
- ^^^^^^^^^^^^^^^^^
- - name: InstanceVariableReadNode
- fields:
- - name: name
- type: constant
- comment: |
- The name of the instance variable, which is a `@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
-
- @x # name `:@x`
-
- @_test # name `:@_test`
- comment: |
- Represents referencing an instance variable.
-
- @foo
- ^^^^
- - name: InstanceVariableTargetNode
- fields:
- - name: name
- type: constant
- comment: |
- Represents writing to an instance variable in a context that doesn't have an explicit value.
-
- @foo, @bar = baz
- ^^^^ ^^^^
- - name: InstanceVariableWriteNode
- fields:
- - name: name
- type: constant
- comment: |
- The name of the instance variable, which is a `@` followed by an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
-
- @x = :y # name `:@x`
-
- @_foo = "bar" # name `@_foo`
- - name: name_loc
- type: location
- comment: |
- The location of the variable name.
-
- @_x = 1
- ^^^
- - name: value
- type: node
- kind: non-void expression
- comment: |
- The value to write to the instance variable. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- @foo = :bar
- ^^^^
-
- @_x = 1234
- ^^^^
- - name: operator_loc
- type: location
- comment: |
- The location of the `=` operator.
-
- @x = y
- ^
- comment: |
- Represents writing to an instance variable.
-
- @foo = 1
- ^^^^^^^^
- - name: IntegerNode
- flags: IntegerBaseFlags
- fields:
- - name: value
- type: integer
- comment: The value of the integer literal as a number.
- comment: |
- Represents an integer number literal.
-
- 1
- ^
- - name: InterpolatedMatchLastLineNode
- flags: RegularExpressionFlags
- fields:
- - name: opening_loc
- type: location
- - name: parts
- type: node[]
- kind:
- - StringNode
- - EmbeddedStatementsNode
- - EmbeddedVariableNode
- - name: closing_loc
- type: location
- newline: parts
- comment: |
- Represents a regular expression literal that contains interpolation that is being used in the predicate of a conditional to implicitly match against the last line read by an IO object.
-
- if /foo #{bar} baz/ then end
- ^^^^^^^^^^^^^^^^
- - name: InterpolatedRegularExpressionNode
- flags: RegularExpressionFlags
- fields:
- - name: opening_loc
- type: location
- - name: parts
- type: node[]
- kind:
- - StringNode
- - EmbeddedStatementsNode
- - EmbeddedVariableNode
- - name: closing_loc
- type: location
- newline: parts
- comment: |
- Represents a regular expression literal that contains interpolation.
-
- /foo #{bar} baz/
- ^^^^^^^^^^^^^^^^
- - name: InterpolatedStringNode
- flags: InterpolatedStringNodeFlags
- fields:
- - name: opening_loc
- type: location?
- - name: parts
- type: node[]
- kind:
- - StringNode
- - EmbeddedStatementsNode
- - EmbeddedVariableNode
- - InterpolatedStringNode # `"a" "#{b}"`
- - name: closing_loc
- type: location?
- newline: parts
- comment: |
- Represents a string literal that contains interpolation.
-
- "foo #{bar} baz"
- ^^^^^^^^^^^^^^^^
- - name: InterpolatedSymbolNode
- fields:
- - name: opening_loc
- type: location?
- - name: parts
- type: node[]
- kind:
- - StringNode
- - EmbeddedStatementsNode
- - EmbeddedVariableNode
- - name: closing_loc
- type: location?
- newline: parts
- comment: |
- Represents a symbol literal that contains interpolation.
-
- :"foo #{bar} baz"
- ^^^^^^^^^^^^^^^^^
- - name: InterpolatedXStringNode
- fields:
- - name: opening_loc
- type: location
- - name: parts
- type: node[]
- kind:
- - StringNode
- - EmbeddedStatementsNode
- - EmbeddedVariableNode
- - name: closing_loc
- type: location
- newline: parts
- comment: |
- Represents an xstring literal that contains interpolation.
-
- `foo #{bar} baz`
- ^^^^^^^^^^^^^^^^
- - name: ItLocalVariableReadNode
- comment: |
- Represents reading from the implicit `it` local variable.
-
- -> { it }
- ^^
- - name: ItParametersNode
- comment: |
- Represents an implicit set of parameters through the use of the `it` keyword within a block or lambda.
-
- -> { it + it }
- ^^^^^^^^^^^^^^
- - name: KeywordHashNode
- flags: KeywordHashNodeFlags
- fields:
- - name: elements
- type: node[]
- kind:
- - AssocNode
- - AssocSplatNode
- comment: |
- Represents a hash literal without opening and closing braces.
-
- foo(a: b)
- ^^^^
- - name: KeywordRestParameterNode
- flags: ParameterFlags
- fields:
- - name: name
- type: constant?
- - name: name_loc
- type: location?
- - name: operator_loc
- type: location
- comment: |
- Represents a keyword rest parameter to a method, block, or lambda definition.
-
- def a(**b)
- ^^^
- end
- - name: LambdaNode
- fields:
- - name: locals
- type: constant[]
- - name: operator_loc
- type: location
- - name: opening_loc
- type: location
- - name: closing_loc
- type: location
- - name: parameters
- type: node?
- kind:
- - BlockParametersNode
- - NumberedParametersNode
- - ItParametersNode
- - name: body
- type: node?
- kind:
- - StatementsNode
- - BeginNode
- comment: |
- Represents using a lambda literal (not the lambda method call).
-
- ->(value) { value * 2 }
- ^^^^^^^^^^^^^^^^^^^^^^^
- - name: LocalVariableAndWriteNode
- fields:
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- - name: name
- type: constant
- - name: depth
- type: uint32
- comment: |
- Represents the use of the `&&=` operator for assignment to a local variable.
-
- target &&= value
- ^^^^^^^^^^^^^^^^
- - name: LocalVariableOperatorWriteNode
- fields:
- - name: name_loc
- type: location
- - name: binary_operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- - name: name
- type: constant
- - name: binary_operator
- type: constant
- - name: depth
- type: uint32
- comment: |
- Represents assigning to a local variable using an operator that isn't `=`.
-
- target += value
- ^^^^^^^^^^^^^^^
- - name: LocalVariableOrWriteNode
- fields:
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- - name: name
- type: constant
- - name: depth
- type: uint32
- comment: |
- Represents the use of the `||=` operator for assignment to a local variable.
-
- target ||= value
- ^^^^^^^^^^^^^^^^
- - name: LocalVariableReadNode
- fields:
- - name: name
- type: constant
- comment: |
- The name of the local variable, which is an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
-
- x # name `:x`
-
- _Test # name `:_Test`
-
- Note that this can also be an underscore followed by a number for the default block parameters.
-
- _1 # name `:_1`
-
- - name: depth
- type: uint32
- comment: |
- The number of visible scopes that should be searched to find the origin of this local variable.
-
- foo = 1; foo # depth 0
-
- bar = 2; tap { bar } # depth 1
-
- The specific rules for calculating the depth may differ from individual Ruby implementations, as they are not specified by the language. For more information, see [the Prism documentation](https://github.com/ruby/prism/blob/main/docs/local_variable_depth.md).
- comment: |
- Represents reading a local variable. Note that this requires that a local variable of the same name has already been written to in the same scope, otherwise it is parsed as a method call.
-
- foo
- ^^^
- - name: LocalVariableTargetNode
- fields:
- - name: name
- type: constant
- - name: depth
- type: uint32
- comment: |
- Represents writing to a local variable in a context that doesn't have an explicit value.
-
- foo, bar = baz
- ^^^ ^^^
- - name: LocalVariableWriteNode
- fields:
- - name: name
- type: constant
- comment: |
- The name of the local variable, which is an [identifier](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#identifiers).
-
- foo = :bar # name `:foo`
-
- abc = 123 # name `:abc`
- - name: depth
- type: uint32
- comment: |
- The number of semantic scopes we have to traverse to find the declaration of this variable.
-
- foo = 1 # depth 0
-
- tap { foo = 1 } # depth 1
-
- The specific rules for calculating the depth may differ from individual Ruby implementations, as they are not specified by the language. For more information, see [the Prism documentation](https://github.com/ruby/prism/blob/main/docs/local_variable_depth.md).
- - name: name_loc
- type: location
- comment: |
- The location of the variable name.
-
- foo = :bar
- ^^^
- - name: value
- type: node
- kind: non-void expression
- comment: |
- The value to write to the local variable. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- foo = :bar
- ^^^^
-
- abc = 1234
- ^^^^
-
- Note that since the name of a local variable is known before the value is parsed, it is valid for a local variable to appear within the value of its own write.
-
- foo = foo
- - name: operator_loc
- type: location
- comment: |
- The location of the `=` operator.
-
- x = :y
- ^
- comment: |
- Represents writing to a local variable.
-
- foo = 1
- ^^^^^^^
- - name: MatchLastLineNode
- flags: RegularExpressionFlags
- fields:
- - name: opening_loc
- type: location
- - name: content_loc
- type: location
- - name: closing_loc
- type: location
- - name: unescaped
- type: string
- comment: |
- Represents a regular expression literal used in the predicate of a conditional to implicitly match against the last line read by an IO object.
-
- if /foo/i then end
- ^^^^^^
- - name: MatchPredicateNode
- fields:
- - name: value
- type: node
- kind: non-void expression
- - name: pattern
- type: node
- kind: pattern expression
- - name: operator_loc
- type: location
- comment: |
- Represents the use of the modifier `in` operator.
-
- foo in bar
- ^^^^^^^^^^
- - name: MatchRequiredNode
- fields:
- - name: value
- type: node
- kind: non-void expression
- - name: pattern
- type: node
- kind: pattern expression
- - name: operator_loc
- type: location
- comment: |
- Represents the use of the `=>` operator.
-
- foo => bar
- ^^^^^^^^^^
- - name: MatchWriteNode
- fields:
- - name: call
- type: node
- kind: CallNode
- - name: targets
- type: node[]
- kind: LocalVariableTargetNode
- comment: |
- Represents writing local variables using a regular expression match with named capture groups.
-
- /(?<foo>bar)/ =~ baz
- ^^^^^^^^^^^^^^^^^^^^
- - name: MissingNode
- comment: |
- Represents a node that is missing from the source and results in a syntax error.
- - name: ModuleNode
- fields:
- - name: locals
- type: constant[]
- - name: module_keyword_loc
- type: location
- - name: constant_path
- type: node
- kind:
- - ConstantReadNode
- - ConstantPathNode
- - on error: MissingNode # module Parent module end
- - name: body
- type: node?
- kind:
- - StatementsNode
- - BeginNode
- - name: end_keyword_loc
- type: location
- - name: name
- type: constant
- comment: |
- Represents a module declaration involving the `module` keyword.
-
- module Foo end
- ^^^^^^^^^^^^^^
- - name: MultiTargetNode
- fields:
- - name: lefts
- type: node[]
- kind:
- - LocalVariableTargetNode
- - InstanceVariableTargetNode
- - ClassVariableTargetNode
- - GlobalVariableTargetNode
- - ConstantTargetNode
- - ConstantPathTargetNode
- - CallTargetNode
- - IndexTargetNode
- - MultiTargetNode
- - RequiredParameterNode # def m((a,b)); end
- - on error: BackReferenceReadNode # a, (b, $&) = z
- - on error: NumberedReferenceReadNode # a, (b, $1) = z
- comment: |
- Represents the targets expressions before a splat node.
-
- a, (b, c, *) = 1, 2, 3, 4, 5
- ^^^^
-
- The splat node can be absent, in that case all target expressions are in the left field.
-
- a, (b, c) = 1, 2, 3, 4, 5
- ^^^^
- - name: rest
- type: node?
- kind:
- - ImplicitRestNode
- - SplatNode
- comment: |
- Represents a splat node in the target expression.
-
- a, (b, *c) = 1, 2, 3, 4
- ^^
-
- The variable can be empty, this results in a `SplatNode` with a `nil` expression field.
-
- a, (b, *) = 1, 2, 3, 4
- ^
-
- If the `*` is omitted, this field will contain an `ImplicitRestNode`
-
- a, (b,) = 1, 2, 3, 4
- ^
- - name: rights
- type: node[]
- kind:
- - LocalVariableTargetNode
- - InstanceVariableTargetNode
- - ClassVariableTargetNode
- - GlobalVariableTargetNode
- - ConstantTargetNode
- - ConstantPathTargetNode
- - CallTargetNode
- - IndexTargetNode
- - MultiTargetNode
- - RequiredParameterNode # def m((*,b)); end
- - on error: BackReferenceReadNode # a, (*, $&) = z
- - on error: NumberedReferenceReadNode # a, (*, $1) = z
- comment: |
- Represents the targets expressions after a splat node.
-
- a, (*, b, c) = 1, 2, 3, 4, 5
- ^^^^
- - name: lparen_loc
- type: location?
- comment: |
- The location of the opening parenthesis.
-
- a, (b, c) = 1, 2, 3
- ^
- - name: rparen_loc
- type: location?
- comment: |
- The location of the closing parenthesis.
-
- a, (b, c) = 1, 2, 3
- ^
- comment: |
- Represents a multi-target expression.
-
- a, (b, c) = 1, 2, 3
- ^^^^^^
-
- This can be a part of `MultiWriteNode` as above, or the target of a `for` loop
-
- for a, b in [[1, 2], [3, 4]]
- ^^^^
- - name: MultiWriteNode
- fields:
- - name: lefts
- type: node[]
- kind:
- - LocalVariableTargetNode
- - InstanceVariableTargetNode
- - ClassVariableTargetNode
- - GlobalVariableTargetNode
- - ConstantTargetNode
- - ConstantPathTargetNode
- - CallTargetNode
- - IndexTargetNode
- - MultiTargetNode
- - on error: BackReferenceReadNode # $&, = z
- - on error: NumberedReferenceReadNode # $1, = z
- comment: |
- Represents the targets expressions before a splat node.
-
- a, b, * = 1, 2, 3, 4, 5
- ^^^^
-
- The splat node can be absent, in that case all target expressions are in the left field.
-
- a, b, c = 1, 2, 3, 4, 5
- ^^^^^^^
- - name: rest
- type: node?
- kind:
- - ImplicitRestNode
- - SplatNode
- comment: |
- Represents a splat node in the target expression.
-
- a, b, *c = 1, 2, 3, 4
- ^^
-
- The variable can be empty, this results in a `SplatNode` with a `nil` expression field.
-
- a, b, * = 1, 2, 3, 4
- ^
-
- If the `*` is omitted, this field will contain an `ImplicitRestNode`
-
- a, b, = 1, 2, 3, 4
- ^
- - name: rights
- type: node[]
- kind:
- - LocalVariableTargetNode
- - InstanceVariableTargetNode
- - ClassVariableTargetNode
- - GlobalVariableTargetNode
- - ConstantTargetNode
- - ConstantPathTargetNode
- - CallTargetNode
- - IndexTargetNode
- - MultiTargetNode
- - on error: BackReferenceReadNode # *, $& = z
- - on error: NumberedReferenceReadNode # *, $1 = z
- comment: |
- Represents the targets expressions after a splat node.
-
- a, *, b, c = 1, 2, 3, 4, 5
- ^^^^
- - name: lparen_loc
- type: location?
- comment: |
- The location of the opening parenthesis.
-
- (a, b, c) = 1, 2, 3
- ^
- - name: rparen_loc
- type: location?
- comment: |
- The location of the closing parenthesis.
-
- (a, b, c) = 1, 2, 3
- ^
- - name: operator_loc
- type: location
- comment: |
- The location of the operator.
-
- a, b, c = 1, 2, 3
- ^
- - name: value
- type: node
- kind: non-void expression
- comment: |
- The value to write to the targets. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- a, b, c = 1, 2, 3
- ^^^^^^^
- comment: |
- Represents a write to a multi-target expression.
-
- a, b, c = 1, 2, 3
- ^^^^^^^^^^^^^^^^^
- - name: NextNode
- fields:
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: keyword_loc
- type: location
- comment: |
- Represents the use of the `next` keyword.
-
- next 1
- ^^^^^^
- - name: NilNode
- comment: |
- Represents the use of the `nil` keyword.
-
- nil
- ^^^
- - name: NoKeywordsParameterNode
- fields:
- - name: operator_loc
- type: location
- - name: keyword_loc
- type: location
- comment: |
- Represents the use of `**nil` inside method arguments.
-
- def a(**nil)
- ^^^^^
- end
- - name: NumberedParametersNode
- fields:
- - name: maximum
- type: uint8
- comment: |
- Represents an implicit set of parameters through the use of numbered parameters within a block or lambda.
-
- -> { _1 + _2 }
- ^^^^^^^^^^^^^^
- - name: NumberedReferenceReadNode
- fields:
- - name: number
- type: uint32
- comment: |
- The (1-indexed, from the left) number of the capture group. Numbered references that are too large result in this value being `0`.
-
- $1 # number `1`
-
- $5432 # number `5432`
-
- $4294967296 # number `0`
- comment: |
- Represents reading a numbered reference to a capture in the previous match.
-
- $1
- ^^
- - name: OptionalKeywordParameterNode
- flags: ParameterFlags
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents an optional keyword parameter to a method, block, or lambda definition.
-
- def a(b: 1)
- ^^^^
- end
- - name: OptionalParameterNode
- flags: ParameterFlags
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- - name: operator_loc
- type: location
- - name: value
- type: node
- kind: non-void expression
- comment: |
- Represents an optional parameter to a method, block, or lambda definition.
-
- def a(b = 1)
- ^^^^^
- end
- - name: OrNode
- fields:
- - name: left
- type: node
- kind: non-void expression
- comment: |
- Represents the left side of the expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- left or right
- ^^^^
-
- 1 || 2
- ^
- - name: right
- type: node
- kind: Node
- comment: |
- Represents the right side of the expression.
-
- left || right
- ^^^^^
-
- 1 or 2
- ^
- - name: operator_loc
- type: location
- comment: |
- The location of the `or` keyword or the `||` operator.
-
- left or right
- ^^
- comment: |
- Represents the use of the `||` operator or the `or` keyword.
-
- left or right
- ^^^^^^^^^^^^^
- - name: ParametersNode
- fields:
- - name: requireds
- type: node[]
- kind:
- - RequiredParameterNode
- - MultiTargetNode
- - name: optionals
- type: node[]
- kind: OptionalParameterNode
- - name: rest
- type: node?
- kind:
- - RestParameterNode
- - ImplicitRestNode # Only in block parameters
- - name: posts
- type: node[]
- kind:
- - RequiredParameterNode
- - MultiTargetNode
- # On parsing error of `f(**kwargs, ...)` or `f(**nil, ...)`, the keyword_rest value is moved here:
- - on error: KeywordRestParameterNode
- - on error: NoKeywordsParameterNode
- # On parsing error of `f(..., ...)`, the first forwarding parameter is moved here:
- - on error: ForwardingParameterNode
- - name: keywords
- type: node[]
- kind:
- - RequiredKeywordParameterNode
- - OptionalKeywordParameterNode
- - name: keyword_rest
- type: node?
- kind:
- - KeywordRestParameterNode
- - ForwardingParameterNode
- - NoKeywordsParameterNode
- - name: block
- type: node?
- kind: BlockParameterNode
- comment: |
- Represents the list of parameters on a method, block, or lambda definition.
-
- def a(b, c, d)
- ^^^^^^^
- end
- - name: ParenthesesNode
- fields:
- - name: body
- type: node?
- kind: non-void expression # Usually a StatementsNode but not always e.g. `1 in (..10)`
- - name: opening_loc
- type: location
- - name: closing_loc
- type: location
- newline: false
- comment: |
- Represents a parenthesized expression
-
- (10 + 34)
- ^^^^^^^^^
- - name: PinnedExpressionNode
- fields:
- - name: expression
- type: node
- kind: non-void expression
- - name: operator_loc
- type: location
- - name: lparen_loc
- type: location
- - name: rparen_loc
- type: location
- comment: |
- Represents the use of the `^` operator for pinning an expression in a pattern matching expression.
-
- foo in ^(bar)
- ^^^^^^
- - name: PinnedVariableNode
- fields:
- - name: variable
- type: node
- kind:
- - LocalVariableReadNode
- - InstanceVariableReadNode
- - ClassVariableReadNode
- - GlobalVariableReadNode # foo in ^$a
- - BackReferenceReadNode # foo in ^$&
- - NumberedReferenceReadNode # foo in ^$1
- - ItLocalVariableReadNode # proc { 1 in ^it }
- - on error: MissingNode # foo in ^Bar
- - name: operator_loc
- type: location
- comment: |
- Represents the use of the `^` operator for pinning a variable in a pattern matching expression.
-
- foo in ^bar
- ^^^^
- - name: PostExecutionNode
- fields:
- - name: statements
- type: node?
- kind: StatementsNode
- - name: keyword_loc
- type: location
- - name: opening_loc
- type: location
- - name: closing_loc
- type: location
- comment: |
- Represents the use of the `END` keyword.
-
- END { foo }
- ^^^^^^^^^^^
- - name: PreExecutionNode
- fields:
- - name: statements
- type: node?
- kind: StatementsNode
- - name: keyword_loc
- type: location
- - name: opening_loc
- type: location
- - name: closing_loc
- type: location
- comment: |
- Represents the use of the `BEGIN` keyword.
-
- BEGIN { foo }
- ^^^^^^^^^^^^^
- - name: ProgramNode
- fields:
- - name: locals
- type: constant[]
- - name: statements
- type: node
- kind: StatementsNode
- comment: The top level node of any parse tree.
- - name: RangeNode
- flags: RangeFlags
- fields:
- - name: left
- type: node?
- kind: non-void expression
- comment: |
- The left-hand side of the range, if present. It can be either `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- 1...
- ^
-
- hello...goodbye
- ^^^^^
- - name: right
- type: node?
- kind: non-void expression
- comment: |
- The right-hand side of the range, if present. It can be either `nil` or any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- ..5
- ^
-
- 1...foo
- ^^^
- If neither right-hand or left-hand side was included, this will be a MissingNode.
- - name: operator_loc
- type: location
- comment: |
- The location of the `..` or `...` operator.
- comment: |
- Represents the use of the `..` or `...` operators.
-
- 1..2
- ^^^^
-
- c if a =~ /left/ ... b =~ /right/
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- - name: RationalNode
- flags: IntegerBaseFlags
- fields:
- - name: numerator
- type: integer
- comment: |
- The numerator of the rational number.
-
- 1.5r # numerator 3
- - name: denominator
- type: integer
- comment: |
- The denominator of the rational number.
-
- 1.5r # denominator 2
- comment: |
- Represents a rational number literal.
-
- 1.0r
- ^^^^
- - name: RedoNode
- comment: |
- Represents the use of the `redo` keyword.
-
- redo
- ^^^^
- - name: RegularExpressionNode
- flags: RegularExpressionFlags
- fields:
- - name: opening_loc
- type: location
- - name: content_loc
- type: location
- - name: closing_loc
- type: location
- - name: unescaped
- type: string
- comment: |
- Represents a regular expression literal with no interpolation.
-
- /foo/i
- ^^^^^^
- - name: RequiredKeywordParameterNode
- flags: ParameterFlags
- fields:
- - name: name
- type: constant
- - name: name_loc
- type: location
- comment: |
- Represents a required keyword parameter to a method, block, or lambda definition.
-
- def a(b: )
- ^^
- end
- - name: RequiredParameterNode
- flags: ParameterFlags
- fields:
- - name: name
- type: constant
- comment: |
- Represents a required parameter to a method, block, or lambda definition.
-
- def a(b)
- ^
- end
- - name: RescueModifierNode
- fields:
- - name: expression
- type: node
- kind: Node
- - name: keyword_loc
- type: location
- - name: rescue_expression
- type: node
- kind: Node
- newline: expression
- comment: |
- Represents an expression modified with a rescue.
-
- foo rescue nil
- ^^^^^^^^^^^^^^
- - name: RescueNode
- fields:
- - name: keyword_loc
- type: location
- - name: exceptions
- type: node[]
- kind: non-void expression
- - name: operator_loc
- type: location?
- - name: reference
- type: node?
- kind:
- - LocalVariableTargetNode
- - InstanceVariableTargetNode
- - ClassVariableTargetNode
- - GlobalVariableTargetNode
- - ConstantTargetNode
- - ConstantPathTargetNode
- - CallTargetNode
- - IndexTargetNode
- - on error: BackReferenceReadNode # => begin; rescue => $&; end
- - on error: NumberedReferenceReadNode # => begin; rescue => $1; end
- - on error: MissingNode # begin; rescue =>; end
- - name: statements
- type: node?
- kind: StatementsNode
- - name: subsequent
- type: node?
- kind: RescueNode
- comment: |
- Represents a rescue statement.
-
- begin
- rescue Foo, *splat, Bar => ex
- foo
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- end
-
- `Foo, *splat, Bar` are in the `exceptions` field. `ex` is in the `exception` field.
- - name: RestParameterNode
- flags: ParameterFlags
- fields:
- - name: name
- type: constant?
- - name: name_loc
- type: location?
- - name: operator_loc
- type: location
- comment: |
- Represents a rest parameter to a method, block, or lambda definition.
-
- def a(*b)
- ^^
- end
- - name: RetryNode
- comment: |
- Represents the use of the `retry` keyword.
-
- retry
- ^^^^^
- - name: ReturnNode
- fields:
- - name: keyword_loc
- type: location
- - name: arguments
- type: node?
- kind: ArgumentsNode
- comment: |
- Represents the use of the `return` keyword.
-
- return 1
- ^^^^^^^^
- - name: SelfNode
- comment: |
- Represents the `self` keyword.
-
- self
- ^^^^
- - name: ShareableConstantNode
- flags: ShareableConstantNodeFlags
- fields:
- - name: write
- type: node
- kind:
- - ConstantWriteNode
- - ConstantAndWriteNode
- - ConstantOrWriteNode
- - ConstantOperatorWriteNode
- - ConstantPathWriteNode
- - ConstantPathAndWriteNode
- - ConstantPathOrWriteNode
- - ConstantPathOperatorWriteNode
- comment: The constant write that should be modified with the shareability state.
- comment: |
- This node wraps a constant write to indicate that when the value is written, it should have its shareability state modified.
-
- # shareable_constant_value: literal
- C = { a: 1 }
- ^^^^^^^^^^^^
- - name: SingletonClassNode
- fields:
- - name: locals
- type: constant[]
- - name: class_keyword_loc
- type: location
- - name: operator_loc
- type: location
- - name: expression
- type: node
- kind: non-void expression
- - name: body
- type: node?
- kind:
- - StatementsNode
- - BeginNode
- - name: end_keyword_loc
- type: location
- comment: |
- Represents a singleton class declaration involving the `class` keyword.
-
- class << self end
- ^^^^^^^^^^^^^^^^^
- - name: SourceEncodingNode
- comment: |
- Represents the use of the `__ENCODING__` keyword.
-
- __ENCODING__
- ^^^^^^^^^^^^
- - name: SourceFileNode
- flags: StringFlags
- fields:
- - name: filepath
- type: string
- comment: Represents the file path being parsed. This corresponds directly to the `filepath` option given to the various `Prism::parse*` APIs.
- comment: |
- Represents the use of the `__FILE__` keyword.
-
- __FILE__
- ^^^^^^^^
- - name: SourceLineNode
- comment: |
- Represents the use of the `__LINE__` keyword.
-
- __LINE__
- ^^^^^^^^
- - name: SplatNode
- fields:
- - name: operator_loc
- type: location
- - name: expression
- type: node?
- kind: non-void expression
- comment: |
- Represents the use of the splat operator.
-
- [*a]
- ^^
- - name: StatementsNode
- fields:
- - name: body
- type: node[]
- kind: Node
- comment: |
- Represents a set of statements contained within some scope.
-
- foo; bar; baz
- ^^^^^^^^^^^^^
- - name: StringNode
- flags: StringFlags
- fields:
- - name: opening_loc
- type: location?
- - name: content_loc
- type: location
- - name: closing_loc
- type: location?
- - name: unescaped
- type: string
- comment: |
- Represents a string literal, a string contained within a `%w` list, or plain string content within an interpolated string.
-
- "foo"
- ^^^^^
-
- %w[foo]
- ^^^
-
- "foo #{bar} baz"
- ^^^^ ^^^^
- - name: SuperNode
- fields:
- - name: keyword_loc
- type: location
- - name: lparen_loc
- type: location?
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: rparen_loc
- type: location?
- - name: block
- type: node?
- kind:
- - BlockNode
- - BlockArgumentNode
- comment: |
- Represents the use of the `super` keyword with parentheses or arguments.
-
- super()
- ^^^^^^^
-
- super foo, bar
- ^^^^^^^^^^^^^^
- - name: SymbolNode
- flags: SymbolFlags
- fields:
- - name: opening_loc
- type: location?
- - name: value_loc
- type: location?
- - name: closing_loc
- type: location?
- - name: unescaped
- type: string
- comment: |
- Represents a symbol literal or a symbol contained within a `%i` list.
-
- :foo
- ^^^^
-
- %i[foo]
- ^^^
- - name: TrueNode
- comment: |
- Represents the use of the literal `true` keyword.
-
- true
- ^^^^
- - name: UndefNode
- fields:
- - name: names
- type: node[]
- kind:
- - SymbolNode
- - InterpolatedSymbolNode
- - name: keyword_loc
- type: location
- comment: |
- Represents the use of the `undef` keyword.
-
- undef :foo, :bar, :baz
- ^^^^^^^^^^^^^^^^^^^^^^
- - name: UnlessNode
- fields:
- - name: keyword_loc
- type: location
- comment: |
- The location of the `unless` keyword.
-
- unless cond then bar end
- ^^^^^^
-
- bar unless cond
- ^^^^^^
- - name: predicate
- type: node
- kind: non-void expression
- comment: |
- The condition to be evaluated for the unless expression. It can be any [non-void expression](https://github.com/ruby/prism/blob/main/docs/parsing_rules.md#non-void-expression).
-
- unless cond then bar end
- ^^^^
-
- bar unless cond
- ^^^^
- - name: then_keyword_loc
- type: location?
- comment: |
- The location of the `then` keyword, if present.
-
- unless cond then bar end
- ^^^^
- - name: statements
- type: node?
- kind: StatementsNode
- comment: |
- The body of statements that will executed if the unless condition is
- falsey. Will be `nil` if no body is provided.
-
- unless cond then bar end
- ^^^
- - name: else_clause
- type: node?
- kind: ElseNode
- comment: |
- The else clause of the unless expression, if present.
-
- unless cond then bar else baz end
- ^^^^^^^^
- - name: end_keyword_loc
- type: location?
- comment: |
- The location of the `end` keyword, if present.
-
- unless cond then bar end
- ^^^
- newline: predicate
- comment: |
- Represents the use of the `unless` keyword, either in the block form or the modifier form.
-
- bar unless foo
- ^^^^^^^^^^^^^^
-
- unless foo then bar end
- ^^^^^^^^^^^^^^^^^^^^^^^
- - name: UntilNode
- flags: LoopFlags
- fields:
- - name: keyword_loc
- type: location
- - name: closing_loc
- type: location?
- - name: predicate
- type: node
- kind: non-void expression
- - name: statements
- type: node?
- kind: StatementsNode
- newline: predicate
- comment: |
- Represents the use of the `until` keyword, either in the block form or the modifier form.
-
- bar until foo
- ^^^^^^^^^^^^^
-
- until foo do bar end
- ^^^^^^^^^^^^^^^^^^^^
- - name: WhenNode
- fields:
- - name: keyword_loc
- type: location
- - name: conditions
- type: node[]
- kind: non-void expression
- - name: then_keyword_loc
- type: location?
- - name: statements
- type: node?
- kind: StatementsNode
- comment: |
- Represents the use of the `when` keyword within a case statement.
-
- case true
- when true
- ^^^^^^^^^
- end
- - name: WhileNode
- flags: LoopFlags
- fields:
- - name: keyword_loc
- type: location
- - name: closing_loc
- type: location?
- - name: predicate
- type: node
- kind: non-void expression
- - name: statements
- type: node?
- kind: StatementsNode
- newline: predicate
- comment: |
- Represents the use of the `while` keyword, either in the block form or the modifier form.
-
- bar while foo
- ^^^^^^^^^^^^^
-
- while foo do bar end
- ^^^^^^^^^^^^^^^^^^^^
- - name: XStringNode
- flags: EncodingFlags
- fields:
- - name: opening_loc
- type: location
- - name: content_loc
- type: location
- - name: closing_loc
- type: location
- - name: unescaped
- type: string
- comment: |
- Represents an xstring literal with no interpolation.
-
- `foo`
- ^^^^^
- - name: YieldNode
- fields:
- - name: keyword_loc
- type: location
- - name: lparen_loc
- type: location?
- - name: arguments
- type: node?
- kind: ArgumentsNode
- - name: rparen_loc
- type: location?
- comment: |
- Represents the use of the `yield` keyword.
-
- yield 1
- ^^^^^^^
diff --git a/prism/defines.h b/prism/defines.h
deleted file mode 100644
index e78c7dd75c..0000000000
--- a/prism/defines.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/**
- * @file defines.h
- *
- * Macro definitions used throughout the prism library.
- *
- * This file should be included first by any *.h or *.c in prism for consistency
- * and to ensure that the macros are defined before they are used.
- */
-#ifndef PRISM_DEFINES_H
-#define PRISM_DEFINES_H
-
-#include <ctype.h>
-#include <limits.h>
-#include <math.h>
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
-/**
- * We want to be able to use the PRI* macros for printing out integers, but on
- * some platforms they aren't included unless this is already defined.
- */
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-
-/**
- * When we are parsing using recursive descent, we want to protect against
- * malicious payloads that could attempt to crash our parser. We do this by
- * specifying a maximum depth to which we are allowed to recurse.
- */
-#ifndef PRISM_DEPTH_MAXIMUM
- #define PRISM_DEPTH_MAXIMUM 1000
-#endif
-
-/**
- * By default, we compile with -fvisibility=hidden. When this is enabled, we
- * need to mark certain functions as being publically-visible. This macro does
- * that in a compiler-agnostic way.
- */
-#ifndef PRISM_EXPORTED_FUNCTION
-# ifdef PRISM_EXPORT_SYMBOLS
-# ifdef _WIN32
-# define PRISM_EXPORTED_FUNCTION __declspec(dllexport) extern
-# else
-# define PRISM_EXPORTED_FUNCTION __attribute__((__visibility__("default"))) extern
-# endif
-# else
-# define PRISM_EXPORTED_FUNCTION
-# endif
-#endif
-
-/**
- * Certain compilers support specifying that a function accepts variadic
- * parameters that look like printf format strings to provide a better developer
- * experience when someone is using the function. This macro does that in a
- * compiler-agnostic way.
- */
-#if defined(__GNUC__)
-# if defined(__MINGW_PRINTF_FORMAT)
-# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((format(__MINGW_PRINTF_FORMAT, string_index, argument_index)))
-# else
-# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((format(printf, string_index, argument_index)))
-# endif
-#elif defined(__clang__)
-# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((__format__(__printf__, string_index, argument_index)))
-#else
-# define PRISM_ATTRIBUTE_FORMAT(string_index, argument_index)
-#endif
-
-/**
- * GCC will warn if you specify a function or parameter that is unused at
- * runtime. This macro allows you to mark a function or parameter as unused in a
- * compiler-agnostic way.
- */
-#if defined(__GNUC__)
-# define PRISM_ATTRIBUTE_UNUSED __attribute__((unused))
-#else
-# define PRISM_ATTRIBUTE_UNUSED
-#endif
-
-/**
- * Old Visual Studio versions do not support the inline keyword, so we need to
- * define it to be __inline.
- */
-#if defined(_MSC_VER) && !defined(inline)
-# define inline __inline
-#endif
-
-/**
- * Old Visual Studio versions before 2015 do not implement sprintf, but instead
- * implement _snprintf. We standard that here.
- */
-#if !defined(snprintf) && defined(_MSC_VER) && (_MSC_VER < 1900)
-# define snprintf _snprintf
-#endif
-
-/**
- * A simple utility macro to concatenate two tokens together, necessary when one
- * of the tokens is itself a macro.
- */
-#define PM_CONCATENATE(left, right) left ## right
-
-/**
- * We want to be able to use static assertions, but they weren't standardized
- * until C11. As such, we polyfill it here by making a hacky typedef that will
- * fail to compile due to a negative array size if the condition is false.
- */
-#if defined(_Static_assert)
-# define PM_STATIC_ASSERT(line, condition, message) _Static_assert(condition, message)
-#else
-# define PM_STATIC_ASSERT(line, condition, message) typedef char PM_CONCATENATE(static_assert_, line)[(condition) ? 1 : -1]
-#endif
-
-/**
- * In general, libc for embedded systems does not support memory-mapped files.
- * If the target platform is POSIX or Windows, we can map a file in memory and
- * read it in a more efficient manner.
- */
-#ifdef _WIN32
-# define PRISM_HAS_MMAP
-#else
-# include <unistd.h>
-# ifdef _POSIX_MAPPED_FILES
-# define PRISM_HAS_MMAP
-# endif
-#endif
-
-/**
- * If PRISM_HAS_NO_FILESYSTEM is defined, then we want to exclude all filesystem
- * related code from the library. All filesystem related code should be guarded
- * by PRISM_HAS_FILESYSTEM.
- */
-#ifndef PRISM_HAS_NO_FILESYSTEM
-# define PRISM_HAS_FILESYSTEM
-#endif
-
-/**
- * isinf on Windows is defined as accepting a float, but on POSIX systems it
- * accepts a float, a double, or a long double. We want to mirror this behavior
- * on windows.
- */
-#ifdef _WIN32
-# include <float.h>
-# undef isinf
-# define isinf(x) (sizeof(x) == sizeof(float) ? !_finitef(x) : !_finite(x))
-#endif
-
-/**
- * If you build prism with a custom allocator, configure it with
- * "-D PRISM_XALLOCATOR" to use your own allocator that defines xmalloc,
- * xrealloc, xcalloc, and xfree.
- *
- * For example, your `prism_xallocator.h` file could look like this:
- *
- * ```
- * #ifndef PRISM_XALLOCATOR_H
- * #define PRISM_XALLOCATOR_H
- * #define xmalloc my_malloc
- * #define xrealloc my_realloc
- * #define xcalloc my_calloc
- * #define xfree my_free
- * #endif
- * ```
- */
-#ifdef PRISM_XALLOCATOR
- #include "prism_xallocator.h"
-#else
- #ifndef xmalloc
- /**
- * The malloc function that should be used. This can be overridden with
- * the PRISM_XALLOCATOR define.
- */
- #define xmalloc malloc
- #endif
-
- #ifndef xrealloc
- /**
- * The realloc function that should be used. This can be overridden with
- * the PRISM_XALLOCATOR define.
- */
- #define xrealloc realloc
- #endif
-
- #ifndef xcalloc
- /**
- * The calloc function that should be used. This can be overridden with
- * the PRISM_XALLOCATOR define.
- */
- #define xcalloc calloc
- #endif
-
- #ifndef xfree
- /**
- * The free function that should be used. This can be overridden with the
- * PRISM_XALLOCATOR define.
- */
- #define xfree free
- #endif
-#endif
-
-/**
- * If PRISM_BUILD_MINIMAL is defined, then we're going to define every possible
- * switch that will turn off certain features of prism.
- */
-#ifdef PRISM_BUILD_MINIMAL
- /** Exclude the serialization API. */
- #define PRISM_EXCLUDE_SERIALIZATION
-
- /** Exclude the JSON serialization API. */
- #define PRISM_EXCLUDE_JSON
-
- /** Exclude the Array#pack parser API. */
- #define PRISM_EXCLUDE_PACK
-
- /** Exclude the prettyprint API. */
- #define PRISM_EXCLUDE_PRETTYPRINT
-
- /** Exclude the full set of encodings, using the minimal only. */
- #define PRISM_ENCODING_EXCLUDE_FULL
-#endif
-
-/**
- * Support PRISM_LIKELY and PRISM_UNLIKELY to help the compiler optimize its
- * branch predication.
- */
-#if defined(__GNUC__) || defined(__clang__)
- /** The compiler should predicate that this branch will be taken. */
- #define PRISM_LIKELY(x) __builtin_expect(!!(x), 1)
-
- /** The compiler should predicate that this branch will not be taken. */
- #define PRISM_UNLIKELY(x) __builtin_expect(!!(x), 0)
-#else
- /** Void because this platform does not support branch prediction hints. */
- #define PRISM_LIKELY(x) (x)
-
- /** Void because this platform does not support branch prediction hints. */
- #define PRISM_UNLIKELY(x) (x)
-#endif
-
-#endif
diff --git a/prism/encoding.c b/prism/encoding.c
deleted file mode 100644
index a4aeed104f..0000000000
--- a/prism/encoding.c
+++ /dev/null
@@ -1,5235 +0,0 @@
-#include "prism/encoding.h"
-
-typedef uint32_t pm_unicode_codepoint_t;
-
-#define UNICODE_ALPHA_CODEPOINTS_LENGTH 1450
-static const pm_unicode_codepoint_t unicode_alpha_codepoints[UNICODE_ALPHA_CODEPOINTS_LENGTH] = {
- 0x100, 0x2C1,
- 0x2C6, 0x2D1,
- 0x2E0, 0x2E4,
- 0x2EC, 0x2EC,
- 0x2EE, 0x2EE,
- 0x345, 0x345,
- 0x370, 0x374,
- 0x376, 0x377,
- 0x37A, 0x37D,
- 0x37F, 0x37F,
- 0x386, 0x386,
- 0x388, 0x38A,
- 0x38C, 0x38C,
- 0x38E, 0x3A1,
- 0x3A3, 0x3F5,
- 0x3F7, 0x481,
- 0x48A, 0x52F,
- 0x531, 0x556,
- 0x559, 0x559,
- 0x560, 0x588,
- 0x5B0, 0x5BD,
- 0x5BF, 0x5BF,
- 0x5C1, 0x5C2,
- 0x5C4, 0x5C5,
- 0x5C7, 0x5C7,
- 0x5D0, 0x5EA,
- 0x5EF, 0x5F2,
- 0x610, 0x61A,
- 0x620, 0x657,
- 0x659, 0x65F,
- 0x66E, 0x6D3,
- 0x6D5, 0x6DC,
- 0x6E1, 0x6E8,
- 0x6ED, 0x6EF,
- 0x6FA, 0x6FC,
- 0x6FF, 0x6FF,
- 0x710, 0x73F,
- 0x74D, 0x7B1,
- 0x7CA, 0x7EA,
- 0x7F4, 0x7F5,
- 0x7FA, 0x7FA,
- 0x800, 0x817,
- 0x81A, 0x82C,
- 0x840, 0x858,
- 0x860, 0x86A,
- 0x870, 0x887,
- 0x889, 0x88E,
- 0x8A0, 0x8C9,
- 0x8D4, 0x8DF,
- 0x8E3, 0x8E9,
- 0x8F0, 0x93B,
- 0x93D, 0x94C,
- 0x94E, 0x950,
- 0x955, 0x963,
- 0x971, 0x983,
- 0x985, 0x98C,
- 0x98F, 0x990,
- 0x993, 0x9A8,
- 0x9AA, 0x9B0,
- 0x9B2, 0x9B2,
- 0x9B6, 0x9B9,
- 0x9BD, 0x9C4,
- 0x9C7, 0x9C8,
- 0x9CB, 0x9CC,
- 0x9CE, 0x9CE,
- 0x9D7, 0x9D7,
- 0x9DC, 0x9DD,
- 0x9DF, 0x9E3,
- 0x9F0, 0x9F1,
- 0x9FC, 0x9FC,
- 0xA01, 0xA03,
- 0xA05, 0xA0A,
- 0xA0F, 0xA10,
- 0xA13, 0xA28,
- 0xA2A, 0xA30,
- 0xA32, 0xA33,
- 0xA35, 0xA36,
- 0xA38, 0xA39,
- 0xA3E, 0xA42,
- 0xA47, 0xA48,
- 0xA4B, 0xA4C,
- 0xA51, 0xA51,
- 0xA59, 0xA5C,
- 0xA5E, 0xA5E,
- 0xA70, 0xA75,
- 0xA81, 0xA83,
- 0xA85, 0xA8D,
- 0xA8F, 0xA91,
- 0xA93, 0xAA8,
- 0xAAA, 0xAB0,
- 0xAB2, 0xAB3,
- 0xAB5, 0xAB9,
- 0xABD, 0xAC5,
- 0xAC7, 0xAC9,
- 0xACB, 0xACC,
- 0xAD0, 0xAD0,
- 0xAE0, 0xAE3,
- 0xAF9, 0xAFC,
- 0xB01, 0xB03,
- 0xB05, 0xB0C,
- 0xB0F, 0xB10,
- 0xB13, 0xB28,
- 0xB2A, 0xB30,
- 0xB32, 0xB33,
- 0xB35, 0xB39,
- 0xB3D, 0xB44,
- 0xB47, 0xB48,
- 0xB4B, 0xB4C,
- 0xB56, 0xB57,
- 0xB5C, 0xB5D,
- 0xB5F, 0xB63,
- 0xB71, 0xB71,
- 0xB82, 0xB83,
- 0xB85, 0xB8A,
- 0xB8E, 0xB90,
- 0xB92, 0xB95,
- 0xB99, 0xB9A,
- 0xB9C, 0xB9C,
- 0xB9E, 0xB9F,
- 0xBA3, 0xBA4,
- 0xBA8, 0xBAA,
- 0xBAE, 0xBB9,
- 0xBBE, 0xBC2,
- 0xBC6, 0xBC8,
- 0xBCA, 0xBCC,
- 0xBD0, 0xBD0,
- 0xBD7, 0xBD7,
- 0xC00, 0xC0C,
- 0xC0E, 0xC10,
- 0xC12, 0xC28,
- 0xC2A, 0xC39,
- 0xC3D, 0xC44,
- 0xC46, 0xC48,
- 0xC4A, 0xC4C,
- 0xC55, 0xC56,
- 0xC58, 0xC5A,
- 0xC5D, 0xC5D,
- 0xC60, 0xC63,
- 0xC80, 0xC83,
- 0xC85, 0xC8C,
- 0xC8E, 0xC90,
- 0xC92, 0xCA8,
- 0xCAA, 0xCB3,
- 0xCB5, 0xCB9,
- 0xCBD, 0xCC4,
- 0xCC6, 0xCC8,
- 0xCCA, 0xCCC,
- 0xCD5, 0xCD6,
- 0xCDD, 0xCDE,
- 0xCE0, 0xCE3,
- 0xCF1, 0xCF3,
- 0xD00, 0xD0C,
- 0xD0E, 0xD10,
- 0xD12, 0xD3A,
- 0xD3D, 0xD44,
- 0xD46, 0xD48,
- 0xD4A, 0xD4C,
- 0xD4E, 0xD4E,
- 0xD54, 0xD57,
- 0xD5F, 0xD63,
- 0xD7A, 0xD7F,
- 0xD81, 0xD83,
- 0xD85, 0xD96,
- 0xD9A, 0xDB1,
- 0xDB3, 0xDBB,
- 0xDBD, 0xDBD,
- 0xDC0, 0xDC6,
- 0xDCF, 0xDD4,
- 0xDD6, 0xDD6,
- 0xDD8, 0xDDF,
- 0xDF2, 0xDF3,
- 0xE01, 0xE3A,
- 0xE40, 0xE46,
- 0xE4D, 0xE4D,
- 0xE81, 0xE82,
- 0xE84, 0xE84,
- 0xE86, 0xE8A,
- 0xE8C, 0xEA3,
- 0xEA5, 0xEA5,
- 0xEA7, 0xEB9,
- 0xEBB, 0xEBD,
- 0xEC0, 0xEC4,
- 0xEC6, 0xEC6,
- 0xECD, 0xECD,
- 0xEDC, 0xEDF,
- 0xF00, 0xF00,
- 0xF40, 0xF47,
- 0xF49, 0xF6C,
- 0xF71, 0xF83,
- 0xF88, 0xF97,
- 0xF99, 0xFBC,
- 0x1000, 0x1036,
- 0x1038, 0x1038,
- 0x103B, 0x103F,
- 0x1050, 0x108F,
- 0x109A, 0x109D,
- 0x10A0, 0x10C5,
- 0x10C7, 0x10C7,
- 0x10CD, 0x10CD,
- 0x10D0, 0x10FA,
- 0x10FC, 0x1248,
- 0x124A, 0x124D,
- 0x1250, 0x1256,
- 0x1258, 0x1258,
- 0x125A, 0x125D,
- 0x1260, 0x1288,
- 0x128A, 0x128D,
- 0x1290, 0x12B0,
- 0x12B2, 0x12B5,
- 0x12B8, 0x12BE,
- 0x12C0, 0x12C0,
- 0x12C2, 0x12C5,
- 0x12C8, 0x12D6,
- 0x12D8, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x135A,
- 0x1380, 0x138F,
- 0x13A0, 0x13F5,
- 0x13F8, 0x13FD,
- 0x1401, 0x166C,
- 0x166F, 0x167F,
- 0x1681, 0x169A,
- 0x16A0, 0x16EA,
- 0x16EE, 0x16F8,
- 0x1700, 0x1713,
- 0x171F, 0x1733,
- 0x1740, 0x1753,
- 0x1760, 0x176C,
- 0x176E, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17B3,
- 0x17B6, 0x17C8,
- 0x17D7, 0x17D7,
- 0x17DC, 0x17DC,
- 0x1820, 0x1878,
- 0x1880, 0x18AA,
- 0x18B0, 0x18F5,
- 0x1900, 0x191E,
- 0x1920, 0x192B,
- 0x1930, 0x1938,
- 0x1950, 0x196D,
- 0x1970, 0x1974,
- 0x1980, 0x19AB,
- 0x19B0, 0x19C9,
- 0x1A00, 0x1A1B,
- 0x1A20, 0x1A5E,
- 0x1A61, 0x1A74,
- 0x1AA7, 0x1AA7,
- 0x1ABF, 0x1AC0,
- 0x1ACC, 0x1ACE,
- 0x1B00, 0x1B33,
- 0x1B35, 0x1B43,
- 0x1B45, 0x1B4C,
- 0x1B80, 0x1BA9,
- 0x1BAC, 0x1BAF,
- 0x1BBA, 0x1BE5,
- 0x1BE7, 0x1BF1,
- 0x1C00, 0x1C36,
- 0x1C4D, 0x1C4F,
- 0x1C5A, 0x1C7D,
- 0x1C80, 0x1C88,
- 0x1C90, 0x1CBA,
- 0x1CBD, 0x1CBF,
- 0x1CE9, 0x1CEC,
- 0x1CEE, 0x1CF3,
- 0x1CF5, 0x1CF6,
- 0x1CFA, 0x1CFA,
- 0x1D00, 0x1DBF,
- 0x1DE7, 0x1DF4,
- 0x1E00, 0x1F15,
- 0x1F18, 0x1F1D,
- 0x1F20, 0x1F45,
- 0x1F48, 0x1F4D,
- 0x1F50, 0x1F57,
- 0x1F59, 0x1F59,
- 0x1F5B, 0x1F5B,
- 0x1F5D, 0x1F5D,
- 0x1F5F, 0x1F7D,
- 0x1F80, 0x1FB4,
- 0x1FB6, 0x1FBC,
- 0x1FBE, 0x1FBE,
- 0x1FC2, 0x1FC4,
- 0x1FC6, 0x1FCC,
- 0x1FD0, 0x1FD3,
- 0x1FD6, 0x1FDB,
- 0x1FE0, 0x1FEC,
- 0x1FF2, 0x1FF4,
- 0x1FF6, 0x1FFC,
- 0x2071, 0x2071,
- 0x207F, 0x207F,
- 0x2090, 0x209C,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210A, 0x2113,
- 0x2115, 0x2115,
- 0x2119, 0x211D,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212A, 0x212D,
- 0x212F, 0x2139,
- 0x213C, 0x213F,
- 0x2145, 0x2149,
- 0x214E, 0x214E,
- 0x2160, 0x2188,
- 0x24B6, 0x24E9,
- 0x2C00, 0x2CE4,
- 0x2CEB, 0x2CEE,
- 0x2CF2, 0x2CF3,
- 0x2D00, 0x2D25,
- 0x2D27, 0x2D27,
- 0x2D2D, 0x2D2D,
- 0x2D30, 0x2D67,
- 0x2D6F, 0x2D6F,
- 0x2D80, 0x2D96,
- 0x2DA0, 0x2DA6,
- 0x2DA8, 0x2DAE,
- 0x2DB0, 0x2DB6,
- 0x2DB8, 0x2DBE,
- 0x2DC0, 0x2DC6,
- 0x2DC8, 0x2DCE,
- 0x2DD0, 0x2DD6,
- 0x2DD8, 0x2DDE,
- 0x2DE0, 0x2DFF,
- 0x2E2F, 0x2E2F,
- 0x3005, 0x3007,
- 0x3021, 0x3029,
- 0x3031, 0x3035,
- 0x3038, 0x303C,
- 0x3041, 0x3096,
- 0x309D, 0x309F,
- 0x30A1, 0x30FA,
- 0x30FC, 0x30FF,
- 0x3105, 0x312F,
- 0x3131, 0x318E,
- 0x31A0, 0x31BF,
- 0x31F0, 0x31FF,
- 0x3400, 0x4DBF,
- 0x4E00, 0xA48C,
- 0xA4D0, 0xA4FD,
- 0xA500, 0xA60C,
- 0xA610, 0xA61F,
- 0xA62A, 0xA62B,
- 0xA640, 0xA66E,
- 0xA674, 0xA67B,
- 0xA67F, 0xA6EF,
- 0xA717, 0xA71F,
- 0xA722, 0xA788,
- 0xA78B, 0xA7CA,
- 0xA7D0, 0xA7D1,
- 0xA7D3, 0xA7D3,
- 0xA7D5, 0xA7D9,
- 0xA7F2, 0xA805,
- 0xA807, 0xA827,
- 0xA840, 0xA873,
- 0xA880, 0xA8C3,
- 0xA8C5, 0xA8C5,
- 0xA8F2, 0xA8F7,
- 0xA8FB, 0xA8FB,
- 0xA8FD, 0xA8FF,
- 0xA90A, 0xA92A,
- 0xA930, 0xA952,
- 0xA960, 0xA97C,
- 0xA980, 0xA9B2,
- 0xA9B4, 0xA9BF,
- 0xA9CF, 0xA9CF,
- 0xA9E0, 0xA9EF,
- 0xA9FA, 0xA9FE,
- 0xAA00, 0xAA36,
- 0xAA40, 0xAA4D,
- 0xAA60, 0xAA76,
- 0xAA7A, 0xAABE,
- 0xAAC0, 0xAAC0,
- 0xAAC2, 0xAAC2,
- 0xAADB, 0xAADD,
- 0xAAE0, 0xAAEF,
- 0xAAF2, 0xAAF5,
- 0xAB01, 0xAB06,
- 0xAB09, 0xAB0E,
- 0xAB11, 0xAB16,
- 0xAB20, 0xAB26,
- 0xAB28, 0xAB2E,
- 0xAB30, 0xAB5A,
- 0xAB5C, 0xAB69,
- 0xAB70, 0xABEA,
- 0xAC00, 0xD7A3,
- 0xD7B0, 0xD7C6,
- 0xD7CB, 0xD7FB,
- 0xF900, 0xFA6D,
- 0xFA70, 0xFAD9,
- 0xFB00, 0xFB06,
- 0xFB13, 0xFB17,
- 0xFB1D, 0xFB28,
- 0xFB2A, 0xFB36,
- 0xFB38, 0xFB3C,
- 0xFB3E, 0xFB3E,
- 0xFB40, 0xFB41,
- 0xFB43, 0xFB44,
- 0xFB46, 0xFBB1,
- 0xFBD3, 0xFD3D,
- 0xFD50, 0xFD8F,
- 0xFD92, 0xFDC7,
- 0xFDF0, 0xFDFB,
- 0xFE70, 0xFE74,
- 0xFE76, 0xFEFC,
- 0xFF21, 0xFF3A,
- 0xFF41, 0xFF5A,
- 0xFF66, 0xFFBE,
- 0xFFC2, 0xFFC7,
- 0xFFCA, 0xFFCF,
- 0xFFD2, 0xFFD7,
- 0xFFDA, 0xFFDC,
- 0x10000, 0x1000B,
- 0x1000D, 0x10026,
- 0x10028, 0x1003A,
- 0x1003C, 0x1003D,
- 0x1003F, 0x1004D,
- 0x10050, 0x1005D,
- 0x10080, 0x100FA,
- 0x10140, 0x10174,
- 0x10280, 0x1029C,
- 0x102A0, 0x102D0,
- 0x10300, 0x1031F,
- 0x1032D, 0x1034A,
- 0x10350, 0x1037A,
- 0x10380, 0x1039D,
- 0x103A0, 0x103C3,
- 0x103C8, 0x103CF,
- 0x103D1, 0x103D5,
- 0x10400, 0x1049D,
- 0x104B0, 0x104D3,
- 0x104D8, 0x104FB,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x10570, 0x1057A,
- 0x1057C, 0x1058A,
- 0x1058C, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105A1,
- 0x105A3, 0x105B1,
- 0x105B3, 0x105B9,
- 0x105BB, 0x105BC,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10780, 0x10785,
- 0x10787, 0x107B0,
- 0x107B2, 0x107BA,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080A, 0x10835,
- 0x10837, 0x10838,
- 0x1083C, 0x1083C,
- 0x1083F, 0x10855,
- 0x10860, 0x10876,
- 0x10880, 0x1089E,
- 0x108E0, 0x108F2,
- 0x108F4, 0x108F5,
- 0x10900, 0x10915,
- 0x10920, 0x10939,
- 0x10980, 0x109B7,
- 0x109BE, 0x109BF,
- 0x10A00, 0x10A03,
- 0x10A05, 0x10A06,
- 0x10A0C, 0x10A13,
- 0x10A15, 0x10A17,
- 0x10A19, 0x10A35,
- 0x10A60, 0x10A7C,
- 0x10A80, 0x10A9C,
- 0x10AC0, 0x10AC7,
- 0x10AC9, 0x10AE4,
- 0x10B00, 0x10B35,
- 0x10B40, 0x10B55,
- 0x10B60, 0x10B72,
- 0x10B80, 0x10B91,
- 0x10C00, 0x10C48,
- 0x10C80, 0x10CB2,
- 0x10CC0, 0x10CF2,
- 0x10D00, 0x10D27,
- 0x10E80, 0x10EA9,
- 0x10EAB, 0x10EAC,
- 0x10EB0, 0x10EB1,
- 0x10F00, 0x10F1C,
- 0x10F27, 0x10F27,
- 0x10F30, 0x10F45,
- 0x10F70, 0x10F81,
- 0x10FB0, 0x10FC4,
- 0x10FE0, 0x10FF6,
- 0x11000, 0x11045,
- 0x11071, 0x11075,
- 0x11080, 0x110B8,
- 0x110C2, 0x110C2,
- 0x110D0, 0x110E8,
- 0x11100, 0x11132,
- 0x11144, 0x11147,
- 0x11150, 0x11172,
- 0x11176, 0x11176,
- 0x11180, 0x111BF,
- 0x111C1, 0x111C4,
- 0x111CE, 0x111CF,
- 0x111DA, 0x111DA,
- 0x111DC, 0x111DC,
- 0x11200, 0x11211,
- 0x11213, 0x11234,
- 0x11237, 0x11237,
- 0x1123E, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128A, 0x1128D,
- 0x1128F, 0x1129D,
- 0x1129F, 0x112A8,
- 0x112B0, 0x112E8,
- 0x11300, 0x11303,
- 0x11305, 0x1130C,
- 0x1130F, 0x11310,
- 0x11313, 0x11328,
- 0x1132A, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133D, 0x11344,
- 0x11347, 0x11348,
- 0x1134B, 0x1134C,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135D, 0x11363,
- 0x11400, 0x11441,
- 0x11443, 0x11445,
- 0x11447, 0x1144A,
- 0x1145F, 0x11461,
- 0x11480, 0x114C1,
- 0x114C4, 0x114C5,
- 0x114C7, 0x114C7,
- 0x11580, 0x115B5,
- 0x115B8, 0x115BE,
- 0x115D8, 0x115DD,
- 0x11600, 0x1163E,
- 0x11640, 0x11640,
- 0x11644, 0x11644,
- 0x11680, 0x116B5,
- 0x116B8, 0x116B8,
- 0x11700, 0x1171A,
- 0x1171D, 0x1172A,
- 0x11740, 0x11746,
- 0x11800, 0x11838,
- 0x118A0, 0x118DF,
- 0x118FF, 0x11906,
- 0x11909, 0x11909,
- 0x1190C, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193B, 0x1193C,
- 0x1193F, 0x11942,
- 0x119A0, 0x119A7,
- 0x119AA, 0x119D7,
- 0x119DA, 0x119DF,
- 0x119E1, 0x119E1,
- 0x119E3, 0x119E4,
- 0x11A00, 0x11A32,
- 0x11A35, 0x11A3E,
- 0x11A50, 0x11A97,
- 0x11A9D, 0x11A9D,
- 0x11AB0, 0x11AF8,
- 0x11C00, 0x11C08,
- 0x11C0A, 0x11C36,
- 0x11C38, 0x11C3E,
- 0x11C40, 0x11C40,
- 0x11C72, 0x11C8F,
- 0x11C92, 0x11CA7,
- 0x11CA9, 0x11CB6,
- 0x11D00, 0x11D06,
- 0x11D08, 0x11D09,
- 0x11D0B, 0x11D36,
- 0x11D3A, 0x11D3A,
- 0x11D3C, 0x11D3D,
- 0x11D3F, 0x11D41,
- 0x11D43, 0x11D43,
- 0x11D46, 0x11D47,
- 0x11D60, 0x11D65,
- 0x11D67, 0x11D68,
- 0x11D6A, 0x11D8E,
- 0x11D90, 0x11D91,
- 0x11D93, 0x11D96,
- 0x11D98, 0x11D98,
- 0x11EE0, 0x11EF6,
- 0x11F00, 0x11F10,
- 0x11F12, 0x11F3A,
- 0x11F3E, 0x11F40,
- 0x11FB0, 0x11FB0,
- 0x12000, 0x12399,
- 0x12400, 0x1246E,
- 0x12480, 0x12543,
- 0x12F90, 0x12FF0,
- 0x13000, 0x1342F,
- 0x13441, 0x13446,
- 0x14400, 0x14646,
- 0x16800, 0x16A38,
- 0x16A40, 0x16A5E,
- 0x16A70, 0x16ABE,
- 0x16AD0, 0x16AED,
- 0x16B00, 0x16B2F,
- 0x16B40, 0x16B43,
- 0x16B63, 0x16B77,
- 0x16B7D, 0x16B8F,
- 0x16E40, 0x16E7F,
- 0x16F00, 0x16F4A,
- 0x16F4F, 0x16F87,
- 0x16F8F, 0x16F9F,
- 0x16FE0, 0x16FE1,
- 0x16FE3, 0x16FE3,
- 0x16FF0, 0x16FF1,
- 0x17000, 0x187F7,
- 0x18800, 0x18CD5,
- 0x18D00, 0x18D08,
- 0x1AFF0, 0x1AFF3,
- 0x1AFF5, 0x1AFFB,
- 0x1AFFD, 0x1AFFE,
- 0x1B000, 0x1B122,
- 0x1B132, 0x1B132,
- 0x1B150, 0x1B152,
- 0x1B155, 0x1B155,
- 0x1B164, 0x1B167,
- 0x1B170, 0x1B2FB,
- 0x1BC00, 0x1BC6A,
- 0x1BC70, 0x1BC7C,
- 0x1BC80, 0x1BC88,
- 0x1BC90, 0x1BC99,
- 0x1BC9E, 0x1BC9E,
- 0x1D400, 0x1D454,
- 0x1D456, 0x1D49C,
- 0x1D49E, 0x1D49F,
- 0x1D4A2, 0x1D4A2,
- 0x1D4A5, 0x1D4A6,
- 0x1D4A9, 0x1D4AC,
- 0x1D4AE, 0x1D4B9,
- 0x1D4BB, 0x1D4BB,
- 0x1D4BD, 0x1D4C3,
- 0x1D4C5, 0x1D505,
- 0x1D507, 0x1D50A,
- 0x1D50D, 0x1D514,
- 0x1D516, 0x1D51C,
- 0x1D51E, 0x1D539,
- 0x1D53B, 0x1D53E,
- 0x1D540, 0x1D544,
- 0x1D546, 0x1D546,
- 0x1D54A, 0x1D550,
- 0x1D552, 0x1D6A5,
- 0x1D6A8, 0x1D6C0,
- 0x1D6C2, 0x1D6DA,
- 0x1D6DC, 0x1D6FA,
- 0x1D6FC, 0x1D714,
- 0x1D716, 0x1D734,
- 0x1D736, 0x1D74E,
- 0x1D750, 0x1D76E,
- 0x1D770, 0x1D788,
- 0x1D78A, 0x1D7A8,
- 0x1D7AA, 0x1D7C2,
- 0x1D7C4, 0x1D7CB,
- 0x1DF00, 0x1DF1E,
- 0x1DF25, 0x1DF2A,
- 0x1E000, 0x1E006,
- 0x1E008, 0x1E018,
- 0x1E01B, 0x1E021,
- 0x1E023, 0x1E024,
- 0x1E026, 0x1E02A,
- 0x1E030, 0x1E06D,
- 0x1E08F, 0x1E08F,
- 0x1E100, 0x1E12C,
- 0x1E137, 0x1E13D,
- 0x1E14E, 0x1E14E,
- 0x1E290, 0x1E2AD,
- 0x1E2C0, 0x1E2EB,
- 0x1E4D0, 0x1E4EB,
- 0x1E7E0, 0x1E7E6,
- 0x1E7E8, 0x1E7EB,
- 0x1E7ED, 0x1E7EE,
- 0x1E7F0, 0x1E7FE,
- 0x1E800, 0x1E8C4,
- 0x1E900, 0x1E943,
- 0x1E947, 0x1E947,
- 0x1E94B, 0x1E94B,
- 0x1EE00, 0x1EE03,
- 0x1EE05, 0x1EE1F,
- 0x1EE21, 0x1EE22,
- 0x1EE24, 0x1EE24,
- 0x1EE27, 0x1EE27,
- 0x1EE29, 0x1EE32,
- 0x1EE34, 0x1EE37,
- 0x1EE39, 0x1EE39,
- 0x1EE3B, 0x1EE3B,
- 0x1EE42, 0x1EE42,
- 0x1EE47, 0x1EE47,
- 0x1EE49, 0x1EE49,
- 0x1EE4B, 0x1EE4B,
- 0x1EE4D, 0x1EE4F,
- 0x1EE51, 0x1EE52,
- 0x1EE54, 0x1EE54,
- 0x1EE57, 0x1EE57,
- 0x1EE59, 0x1EE59,
- 0x1EE5B, 0x1EE5B,
- 0x1EE5D, 0x1EE5D,
- 0x1EE5F, 0x1EE5F,
- 0x1EE61, 0x1EE62,
- 0x1EE64, 0x1EE64,
- 0x1EE67, 0x1EE6A,
- 0x1EE6C, 0x1EE72,
- 0x1EE74, 0x1EE77,
- 0x1EE79, 0x1EE7C,
- 0x1EE7E, 0x1EE7E,
- 0x1EE80, 0x1EE89,
- 0x1EE8B, 0x1EE9B,
- 0x1EEA1, 0x1EEA3,
- 0x1EEA5, 0x1EEA9,
- 0x1EEAB, 0x1EEBB,
- 0x1F130, 0x1F149,
- 0x1F150, 0x1F169,
- 0x1F170, 0x1F189,
- 0x20000, 0x2A6DF,
- 0x2A700, 0x2B739,
- 0x2B740, 0x2B81D,
- 0x2B820, 0x2CEA1,
- 0x2CEB0, 0x2EBE0,
- 0x2F800, 0x2FA1D,
- 0x30000, 0x3134A,
- 0x31350, 0x323AF,
-};
-
-#define UNICODE_ALNUM_CODEPOINTS_LENGTH 1528
-static const pm_unicode_codepoint_t unicode_alnum_codepoints[UNICODE_ALNUM_CODEPOINTS_LENGTH] = {
- 0x100, 0x2C1,
- 0x2C6, 0x2D1,
- 0x2E0, 0x2E4,
- 0x2EC, 0x2EC,
- 0x2EE, 0x2EE,
- 0x345, 0x345,
- 0x370, 0x374,
- 0x376, 0x377,
- 0x37A, 0x37D,
- 0x37F, 0x37F,
- 0x386, 0x386,
- 0x388, 0x38A,
- 0x38C, 0x38C,
- 0x38E, 0x3A1,
- 0x3A3, 0x3F5,
- 0x3F7, 0x481,
- 0x48A, 0x52F,
- 0x531, 0x556,
- 0x559, 0x559,
- 0x560, 0x588,
- 0x5B0, 0x5BD,
- 0x5BF, 0x5BF,
- 0x5C1, 0x5C2,
- 0x5C4, 0x5C5,
- 0x5C7, 0x5C7,
- 0x5D0, 0x5EA,
- 0x5EF, 0x5F2,
- 0x610, 0x61A,
- 0x620, 0x657,
- 0x659, 0x669,
- 0x66E, 0x6D3,
- 0x6D5, 0x6DC,
- 0x6E1, 0x6E8,
- 0x6ED, 0x6FC,
- 0x6FF, 0x6FF,
- 0x710, 0x73F,
- 0x74D, 0x7B1,
- 0x7C0, 0x7EA,
- 0x7F4, 0x7F5,
- 0x7FA, 0x7FA,
- 0x800, 0x817,
- 0x81A, 0x82C,
- 0x840, 0x858,
- 0x860, 0x86A,
- 0x870, 0x887,
- 0x889, 0x88E,
- 0x8A0, 0x8C9,
- 0x8D4, 0x8DF,
- 0x8E3, 0x8E9,
- 0x8F0, 0x93B,
- 0x93D, 0x94C,
- 0x94E, 0x950,
- 0x955, 0x963,
- 0x966, 0x96F,
- 0x971, 0x983,
- 0x985, 0x98C,
- 0x98F, 0x990,
- 0x993, 0x9A8,
- 0x9AA, 0x9B0,
- 0x9B2, 0x9B2,
- 0x9B6, 0x9B9,
- 0x9BD, 0x9C4,
- 0x9C7, 0x9C8,
- 0x9CB, 0x9CC,
- 0x9CE, 0x9CE,
- 0x9D7, 0x9D7,
- 0x9DC, 0x9DD,
- 0x9DF, 0x9E3,
- 0x9E6, 0x9F1,
- 0x9FC, 0x9FC,
- 0xA01, 0xA03,
- 0xA05, 0xA0A,
- 0xA0F, 0xA10,
- 0xA13, 0xA28,
- 0xA2A, 0xA30,
- 0xA32, 0xA33,
- 0xA35, 0xA36,
- 0xA38, 0xA39,
- 0xA3E, 0xA42,
- 0xA47, 0xA48,
- 0xA4B, 0xA4C,
- 0xA51, 0xA51,
- 0xA59, 0xA5C,
- 0xA5E, 0xA5E,
- 0xA66, 0xA75,
- 0xA81, 0xA83,
- 0xA85, 0xA8D,
- 0xA8F, 0xA91,
- 0xA93, 0xAA8,
- 0xAAA, 0xAB0,
- 0xAB2, 0xAB3,
- 0xAB5, 0xAB9,
- 0xABD, 0xAC5,
- 0xAC7, 0xAC9,
- 0xACB, 0xACC,
- 0xAD0, 0xAD0,
- 0xAE0, 0xAE3,
- 0xAE6, 0xAEF,
- 0xAF9, 0xAFC,
- 0xB01, 0xB03,
- 0xB05, 0xB0C,
- 0xB0F, 0xB10,
- 0xB13, 0xB28,
- 0xB2A, 0xB30,
- 0xB32, 0xB33,
- 0xB35, 0xB39,
- 0xB3D, 0xB44,
- 0xB47, 0xB48,
- 0xB4B, 0xB4C,
- 0xB56, 0xB57,
- 0xB5C, 0xB5D,
- 0xB5F, 0xB63,
- 0xB66, 0xB6F,
- 0xB71, 0xB71,
- 0xB82, 0xB83,
- 0xB85, 0xB8A,
- 0xB8E, 0xB90,
- 0xB92, 0xB95,
- 0xB99, 0xB9A,
- 0xB9C, 0xB9C,
- 0xB9E, 0xB9F,
- 0xBA3, 0xBA4,
- 0xBA8, 0xBAA,
- 0xBAE, 0xBB9,
- 0xBBE, 0xBC2,
- 0xBC6, 0xBC8,
- 0xBCA, 0xBCC,
- 0xBD0, 0xBD0,
- 0xBD7, 0xBD7,
- 0xBE6, 0xBEF,
- 0xC00, 0xC0C,
- 0xC0E, 0xC10,
- 0xC12, 0xC28,
- 0xC2A, 0xC39,
- 0xC3D, 0xC44,
- 0xC46, 0xC48,
- 0xC4A, 0xC4C,
- 0xC55, 0xC56,
- 0xC58, 0xC5A,
- 0xC5D, 0xC5D,
- 0xC60, 0xC63,
- 0xC66, 0xC6F,
- 0xC80, 0xC83,
- 0xC85, 0xC8C,
- 0xC8E, 0xC90,
- 0xC92, 0xCA8,
- 0xCAA, 0xCB3,
- 0xCB5, 0xCB9,
- 0xCBD, 0xCC4,
- 0xCC6, 0xCC8,
- 0xCCA, 0xCCC,
- 0xCD5, 0xCD6,
- 0xCDD, 0xCDE,
- 0xCE0, 0xCE3,
- 0xCE6, 0xCEF,
- 0xCF1, 0xCF3,
- 0xD00, 0xD0C,
- 0xD0E, 0xD10,
- 0xD12, 0xD3A,
- 0xD3D, 0xD44,
- 0xD46, 0xD48,
- 0xD4A, 0xD4C,
- 0xD4E, 0xD4E,
- 0xD54, 0xD57,
- 0xD5F, 0xD63,
- 0xD66, 0xD6F,
- 0xD7A, 0xD7F,
- 0xD81, 0xD83,
- 0xD85, 0xD96,
- 0xD9A, 0xDB1,
- 0xDB3, 0xDBB,
- 0xDBD, 0xDBD,
- 0xDC0, 0xDC6,
- 0xDCF, 0xDD4,
- 0xDD6, 0xDD6,
- 0xDD8, 0xDDF,
- 0xDE6, 0xDEF,
- 0xDF2, 0xDF3,
- 0xE01, 0xE3A,
- 0xE40, 0xE46,
- 0xE4D, 0xE4D,
- 0xE50, 0xE59,
- 0xE81, 0xE82,
- 0xE84, 0xE84,
- 0xE86, 0xE8A,
- 0xE8C, 0xEA3,
- 0xEA5, 0xEA5,
- 0xEA7, 0xEB9,
- 0xEBB, 0xEBD,
- 0xEC0, 0xEC4,
- 0xEC6, 0xEC6,
- 0xECD, 0xECD,
- 0xED0, 0xED9,
- 0xEDC, 0xEDF,
- 0xF00, 0xF00,
- 0xF20, 0xF29,
- 0xF40, 0xF47,
- 0xF49, 0xF6C,
- 0xF71, 0xF83,
- 0xF88, 0xF97,
- 0xF99, 0xFBC,
- 0x1000, 0x1036,
- 0x1038, 0x1038,
- 0x103B, 0x1049,
- 0x1050, 0x109D,
- 0x10A0, 0x10C5,
- 0x10C7, 0x10C7,
- 0x10CD, 0x10CD,
- 0x10D0, 0x10FA,
- 0x10FC, 0x1248,
- 0x124A, 0x124D,
- 0x1250, 0x1256,
- 0x1258, 0x1258,
- 0x125A, 0x125D,
- 0x1260, 0x1288,
- 0x128A, 0x128D,
- 0x1290, 0x12B0,
- 0x12B2, 0x12B5,
- 0x12B8, 0x12BE,
- 0x12C0, 0x12C0,
- 0x12C2, 0x12C5,
- 0x12C8, 0x12D6,
- 0x12D8, 0x1310,
- 0x1312, 0x1315,
- 0x1318, 0x135A,
- 0x1380, 0x138F,
- 0x13A0, 0x13F5,
- 0x13F8, 0x13FD,
- 0x1401, 0x166C,
- 0x166F, 0x167F,
- 0x1681, 0x169A,
- 0x16A0, 0x16EA,
- 0x16EE, 0x16F8,
- 0x1700, 0x1713,
- 0x171F, 0x1733,
- 0x1740, 0x1753,
- 0x1760, 0x176C,
- 0x176E, 0x1770,
- 0x1772, 0x1773,
- 0x1780, 0x17B3,
- 0x17B6, 0x17C8,
- 0x17D7, 0x17D7,
- 0x17DC, 0x17DC,
- 0x17E0, 0x17E9,
- 0x1810, 0x1819,
- 0x1820, 0x1878,
- 0x1880, 0x18AA,
- 0x18B0, 0x18F5,
- 0x1900, 0x191E,
- 0x1920, 0x192B,
- 0x1930, 0x1938,
- 0x1946, 0x196D,
- 0x1970, 0x1974,
- 0x1980, 0x19AB,
- 0x19B0, 0x19C9,
- 0x19D0, 0x19D9,
- 0x1A00, 0x1A1B,
- 0x1A20, 0x1A5E,
- 0x1A61, 0x1A74,
- 0x1A80, 0x1A89,
- 0x1A90, 0x1A99,
- 0x1AA7, 0x1AA7,
- 0x1ABF, 0x1AC0,
- 0x1ACC, 0x1ACE,
- 0x1B00, 0x1B33,
- 0x1B35, 0x1B43,
- 0x1B45, 0x1B4C,
- 0x1B50, 0x1B59,
- 0x1B80, 0x1BA9,
- 0x1BAC, 0x1BE5,
- 0x1BE7, 0x1BF1,
- 0x1C00, 0x1C36,
- 0x1C40, 0x1C49,
- 0x1C4D, 0x1C7D,
- 0x1C80, 0x1C88,
- 0x1C90, 0x1CBA,
- 0x1CBD, 0x1CBF,
- 0x1CE9, 0x1CEC,
- 0x1CEE, 0x1CF3,
- 0x1CF5, 0x1CF6,
- 0x1CFA, 0x1CFA,
- 0x1D00, 0x1DBF,
- 0x1DE7, 0x1DF4,
- 0x1E00, 0x1F15,
- 0x1F18, 0x1F1D,
- 0x1F20, 0x1F45,
- 0x1F48, 0x1F4D,
- 0x1F50, 0x1F57,
- 0x1F59, 0x1F59,
- 0x1F5B, 0x1F5B,
- 0x1F5D, 0x1F5D,
- 0x1F5F, 0x1F7D,
- 0x1F80, 0x1FB4,
- 0x1FB6, 0x1FBC,
- 0x1FBE, 0x1FBE,
- 0x1FC2, 0x1FC4,
- 0x1FC6, 0x1FCC,
- 0x1FD0, 0x1FD3,
- 0x1FD6, 0x1FDB,
- 0x1FE0, 0x1FEC,
- 0x1FF2, 0x1FF4,
- 0x1FF6, 0x1FFC,
- 0x2071, 0x2071,
- 0x207F, 0x207F,
- 0x2090, 0x209C,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210A, 0x2113,
- 0x2115, 0x2115,
- 0x2119, 0x211D,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212A, 0x212D,
- 0x212F, 0x2139,
- 0x213C, 0x213F,
- 0x2145, 0x2149,
- 0x214E, 0x214E,
- 0x2160, 0x2188,
- 0x24B6, 0x24E9,
- 0x2C00, 0x2CE4,
- 0x2CEB, 0x2CEE,
- 0x2CF2, 0x2CF3,
- 0x2D00, 0x2D25,
- 0x2D27, 0x2D27,
- 0x2D2D, 0x2D2D,
- 0x2D30, 0x2D67,
- 0x2D6F, 0x2D6F,
- 0x2D80, 0x2D96,
- 0x2DA0, 0x2DA6,
- 0x2DA8, 0x2DAE,
- 0x2DB0, 0x2DB6,
- 0x2DB8, 0x2DBE,
- 0x2DC0, 0x2DC6,
- 0x2DC8, 0x2DCE,
- 0x2DD0, 0x2DD6,
- 0x2DD8, 0x2DDE,
- 0x2DE0, 0x2DFF,
- 0x2E2F, 0x2E2F,
- 0x3005, 0x3007,
- 0x3021, 0x3029,
- 0x3031, 0x3035,
- 0x3038, 0x303C,
- 0x3041, 0x3096,
- 0x309D, 0x309F,
- 0x30A1, 0x30FA,
- 0x30FC, 0x30FF,
- 0x3105, 0x312F,
- 0x3131, 0x318E,
- 0x31A0, 0x31BF,
- 0x31F0, 0x31FF,
- 0x3400, 0x4DBF,
- 0x4E00, 0xA48C,
- 0xA4D0, 0xA4FD,
- 0xA500, 0xA60C,
- 0xA610, 0xA62B,
- 0xA640, 0xA66E,
- 0xA674, 0xA67B,
- 0xA67F, 0xA6EF,
- 0xA717, 0xA71F,
- 0xA722, 0xA788,
- 0xA78B, 0xA7CA,
- 0xA7D0, 0xA7D1,
- 0xA7D3, 0xA7D3,
- 0xA7D5, 0xA7D9,
- 0xA7F2, 0xA805,
- 0xA807, 0xA827,
- 0xA840, 0xA873,
- 0xA880, 0xA8C3,
- 0xA8C5, 0xA8C5,
- 0xA8D0, 0xA8D9,
- 0xA8F2, 0xA8F7,
- 0xA8FB, 0xA8FB,
- 0xA8FD, 0xA92A,
- 0xA930, 0xA952,
- 0xA960, 0xA97C,
- 0xA980, 0xA9B2,
- 0xA9B4, 0xA9BF,
- 0xA9CF, 0xA9D9,
- 0xA9E0, 0xA9FE,
- 0xAA00, 0xAA36,
- 0xAA40, 0xAA4D,
- 0xAA50, 0xAA59,
- 0xAA60, 0xAA76,
- 0xAA7A, 0xAABE,
- 0xAAC0, 0xAAC0,
- 0xAAC2, 0xAAC2,
- 0xAADB, 0xAADD,
- 0xAAE0, 0xAAEF,
- 0xAAF2, 0xAAF5,
- 0xAB01, 0xAB06,
- 0xAB09, 0xAB0E,
- 0xAB11, 0xAB16,
- 0xAB20, 0xAB26,
- 0xAB28, 0xAB2E,
- 0xAB30, 0xAB5A,
- 0xAB5C, 0xAB69,
- 0xAB70, 0xABEA,
- 0xABF0, 0xABF9,
- 0xAC00, 0xD7A3,
- 0xD7B0, 0xD7C6,
- 0xD7CB, 0xD7FB,
- 0xF900, 0xFA6D,
- 0xFA70, 0xFAD9,
- 0xFB00, 0xFB06,
- 0xFB13, 0xFB17,
- 0xFB1D, 0xFB28,
- 0xFB2A, 0xFB36,
- 0xFB38, 0xFB3C,
- 0xFB3E, 0xFB3E,
- 0xFB40, 0xFB41,
- 0xFB43, 0xFB44,
- 0xFB46, 0xFBB1,
- 0xFBD3, 0xFD3D,
- 0xFD50, 0xFD8F,
- 0xFD92, 0xFDC7,
- 0xFDF0, 0xFDFB,
- 0xFE70, 0xFE74,
- 0xFE76, 0xFEFC,
- 0xFF10, 0xFF19,
- 0xFF21, 0xFF3A,
- 0xFF41, 0xFF5A,
- 0xFF66, 0xFFBE,
- 0xFFC2, 0xFFC7,
- 0xFFCA, 0xFFCF,
- 0xFFD2, 0xFFD7,
- 0xFFDA, 0xFFDC,
- 0x10000, 0x1000B,
- 0x1000D, 0x10026,
- 0x10028, 0x1003A,
- 0x1003C, 0x1003D,
- 0x1003F, 0x1004D,
- 0x10050, 0x1005D,
- 0x10080, 0x100FA,
- 0x10140, 0x10174,
- 0x10280, 0x1029C,
- 0x102A0, 0x102D0,
- 0x10300, 0x1031F,
- 0x1032D, 0x1034A,
- 0x10350, 0x1037A,
- 0x10380, 0x1039D,
- 0x103A0, 0x103C3,
- 0x103C8, 0x103CF,
- 0x103D1, 0x103D5,
- 0x10400, 0x1049D,
- 0x104A0, 0x104A9,
- 0x104B0, 0x104D3,
- 0x104D8, 0x104FB,
- 0x10500, 0x10527,
- 0x10530, 0x10563,
- 0x10570, 0x1057A,
- 0x1057C, 0x1058A,
- 0x1058C, 0x10592,
- 0x10594, 0x10595,
- 0x10597, 0x105A1,
- 0x105A3, 0x105B1,
- 0x105B3, 0x105B9,
- 0x105BB, 0x105BC,
- 0x10600, 0x10736,
- 0x10740, 0x10755,
- 0x10760, 0x10767,
- 0x10780, 0x10785,
- 0x10787, 0x107B0,
- 0x107B2, 0x107BA,
- 0x10800, 0x10805,
- 0x10808, 0x10808,
- 0x1080A, 0x10835,
- 0x10837, 0x10838,
- 0x1083C, 0x1083C,
- 0x1083F, 0x10855,
- 0x10860, 0x10876,
- 0x10880, 0x1089E,
- 0x108E0, 0x108F2,
- 0x108F4, 0x108F5,
- 0x10900, 0x10915,
- 0x10920, 0x10939,
- 0x10980, 0x109B7,
- 0x109BE, 0x109BF,
- 0x10A00, 0x10A03,
- 0x10A05, 0x10A06,
- 0x10A0C, 0x10A13,
- 0x10A15, 0x10A17,
- 0x10A19, 0x10A35,
- 0x10A60, 0x10A7C,
- 0x10A80, 0x10A9C,
- 0x10AC0, 0x10AC7,
- 0x10AC9, 0x10AE4,
- 0x10B00, 0x10B35,
- 0x10B40, 0x10B55,
- 0x10B60, 0x10B72,
- 0x10B80, 0x10B91,
- 0x10C00, 0x10C48,
- 0x10C80, 0x10CB2,
- 0x10CC0, 0x10CF2,
- 0x10D00, 0x10D27,
- 0x10D30, 0x10D39,
- 0x10E80, 0x10EA9,
- 0x10EAB, 0x10EAC,
- 0x10EB0, 0x10EB1,
- 0x10F00, 0x10F1C,
- 0x10F27, 0x10F27,
- 0x10F30, 0x10F45,
- 0x10F70, 0x10F81,
- 0x10FB0, 0x10FC4,
- 0x10FE0, 0x10FF6,
- 0x11000, 0x11045,
- 0x11066, 0x1106F,
- 0x11071, 0x11075,
- 0x11080, 0x110B8,
- 0x110C2, 0x110C2,
- 0x110D0, 0x110E8,
- 0x110F0, 0x110F9,
- 0x11100, 0x11132,
- 0x11136, 0x1113F,
- 0x11144, 0x11147,
- 0x11150, 0x11172,
- 0x11176, 0x11176,
- 0x11180, 0x111BF,
- 0x111C1, 0x111C4,
- 0x111CE, 0x111DA,
- 0x111DC, 0x111DC,
- 0x11200, 0x11211,
- 0x11213, 0x11234,
- 0x11237, 0x11237,
- 0x1123E, 0x11241,
- 0x11280, 0x11286,
- 0x11288, 0x11288,
- 0x1128A, 0x1128D,
- 0x1128F, 0x1129D,
- 0x1129F, 0x112A8,
- 0x112B0, 0x112E8,
- 0x112F0, 0x112F9,
- 0x11300, 0x11303,
- 0x11305, 0x1130C,
- 0x1130F, 0x11310,
- 0x11313, 0x11328,
- 0x1132A, 0x11330,
- 0x11332, 0x11333,
- 0x11335, 0x11339,
- 0x1133D, 0x11344,
- 0x11347, 0x11348,
- 0x1134B, 0x1134C,
- 0x11350, 0x11350,
- 0x11357, 0x11357,
- 0x1135D, 0x11363,
- 0x11400, 0x11441,
- 0x11443, 0x11445,
- 0x11447, 0x1144A,
- 0x11450, 0x11459,
- 0x1145F, 0x11461,
- 0x11480, 0x114C1,
- 0x114C4, 0x114C5,
- 0x114C7, 0x114C7,
- 0x114D0, 0x114D9,
- 0x11580, 0x115B5,
- 0x115B8, 0x115BE,
- 0x115D8, 0x115DD,
- 0x11600, 0x1163E,
- 0x11640, 0x11640,
- 0x11644, 0x11644,
- 0x11650, 0x11659,
- 0x11680, 0x116B5,
- 0x116B8, 0x116B8,
- 0x116C0, 0x116C9,
- 0x11700, 0x1171A,
- 0x1171D, 0x1172A,
- 0x11730, 0x11739,
- 0x11740, 0x11746,
- 0x11800, 0x11838,
- 0x118A0, 0x118E9,
- 0x118FF, 0x11906,
- 0x11909, 0x11909,
- 0x1190C, 0x11913,
- 0x11915, 0x11916,
- 0x11918, 0x11935,
- 0x11937, 0x11938,
- 0x1193B, 0x1193C,
- 0x1193F, 0x11942,
- 0x11950, 0x11959,
- 0x119A0, 0x119A7,
- 0x119AA, 0x119D7,
- 0x119DA, 0x119DF,
- 0x119E1, 0x119E1,
- 0x119E3, 0x119E4,
- 0x11A00, 0x11A32,
- 0x11A35, 0x11A3E,
- 0x11A50, 0x11A97,
- 0x11A9D, 0x11A9D,
- 0x11AB0, 0x11AF8,
- 0x11C00, 0x11C08,
- 0x11C0A, 0x11C36,
- 0x11C38, 0x11C3E,
- 0x11C40, 0x11C40,
- 0x11C50, 0x11C59,
- 0x11C72, 0x11C8F,
- 0x11C92, 0x11CA7,
- 0x11CA9, 0x11CB6,
- 0x11D00, 0x11D06,
- 0x11D08, 0x11D09,
- 0x11D0B, 0x11D36,
- 0x11D3A, 0x11D3A,
- 0x11D3C, 0x11D3D,
- 0x11D3F, 0x11D41,
- 0x11D43, 0x11D43,
- 0x11D46, 0x11D47,
- 0x11D50, 0x11D59,
- 0x11D60, 0x11D65,
- 0x11D67, 0x11D68,
- 0x11D6A, 0x11D8E,
- 0x11D90, 0x11D91,
- 0x11D93, 0x11D96,
- 0x11D98, 0x11D98,
- 0x11DA0, 0x11DA9,
- 0x11EE0, 0x11EF6,
- 0x11F00, 0x11F10,
- 0x11F12, 0x11F3A,
- 0x11F3E, 0x11F40,
- 0x11F50, 0x11F59,
- 0x11FB0, 0x11FB0,
- 0x12000, 0x12399,
- 0x12400, 0x1246E,
- 0x12480, 0x12543,
- 0x12F90, 0x12FF0,
- 0x13000, 0x1342F,
- 0x13441, 0x13446,
- 0x14400, 0x14646,
- 0x16800, 0x16A38,
- 0x16A40, 0x16A5E,
- 0x16A60, 0x16A69,
- 0x16A70, 0x16ABE,
- 0x16AC0, 0x16AC9,
- 0x16AD0, 0x16AED,
- 0x16B00, 0x16B2F,
- 0x16B40, 0x16B43,
- 0x16B50, 0x16B59,
- 0x16B63, 0x16B77,
- 0x16B7D, 0x16B8F,
- 0x16E40, 0x16E7F,
- 0x16F00, 0x16F4A,
- 0x16F4F, 0x16F87,
- 0x16F8F, 0x16F9F,
- 0x16FE0, 0x16FE1,
- 0x16FE3, 0x16FE3,
- 0x16FF0, 0x16FF1,
- 0x17000, 0x187F7,
- 0x18800, 0x18CD5,
- 0x18D00, 0x18D08,
- 0x1AFF0, 0x1AFF3,
- 0x1AFF5, 0x1AFFB,
- 0x1AFFD, 0x1AFFE,
- 0x1B000, 0x1B122,
- 0x1B132, 0x1B132,
- 0x1B150, 0x1B152,
- 0x1B155, 0x1B155,
- 0x1B164, 0x1B167,
- 0x1B170, 0x1B2FB,
- 0x1BC00, 0x1BC6A,
- 0x1BC70, 0x1BC7C,
- 0x1BC80, 0x1BC88,
- 0x1BC90, 0x1BC99,
- 0x1BC9E, 0x1BC9E,
- 0x1D400, 0x1D454,
- 0x1D456, 0x1D49C,
- 0x1D49E, 0x1D49F,
- 0x1D4A2, 0x1D4A2,
- 0x1D4A5, 0x1D4A6,
- 0x1D4A9, 0x1D4AC,
- 0x1D4AE, 0x1D4B9,
- 0x1D4BB, 0x1D4BB,
- 0x1D4BD, 0x1D4C3,
- 0x1D4C5, 0x1D505,
- 0x1D507, 0x1D50A,
- 0x1D50D, 0x1D514,
- 0x1D516, 0x1D51C,
- 0x1D51E, 0x1D539,
- 0x1D53B, 0x1D53E,
- 0x1D540, 0x1D544,
- 0x1D546, 0x1D546,
- 0x1D54A, 0x1D550,
- 0x1D552, 0x1D6A5,
- 0x1D6A8, 0x1D6C0,
- 0x1D6C2, 0x1D6DA,
- 0x1D6DC, 0x1D6FA,
- 0x1D6FC, 0x1D714,
- 0x1D716, 0x1D734,
- 0x1D736, 0x1D74E,
- 0x1D750, 0x1D76E,
- 0x1D770, 0x1D788,
- 0x1D78A, 0x1D7A8,
- 0x1D7AA, 0x1D7C2,
- 0x1D7C4, 0x1D7CB,
- 0x1D7CE, 0x1D7FF,
- 0x1DF00, 0x1DF1E,
- 0x1DF25, 0x1DF2A,
- 0x1E000, 0x1E006,
- 0x1E008, 0x1E018,
- 0x1E01B, 0x1E021,
- 0x1E023, 0x1E024,
- 0x1E026, 0x1E02A,
- 0x1E030, 0x1E06D,
- 0x1E08F, 0x1E08F,
- 0x1E100, 0x1E12C,
- 0x1E137, 0x1E13D,
- 0x1E140, 0x1E149,
- 0x1E14E, 0x1E14E,
- 0x1E290, 0x1E2AD,
- 0x1E2C0, 0x1E2EB,
- 0x1E2F0, 0x1E2F9,
- 0x1E4D0, 0x1E4EB,
- 0x1E4F0, 0x1E4F9,
- 0x1E7E0, 0x1E7E6,
- 0x1E7E8, 0x1E7EB,
- 0x1E7ED, 0x1E7EE,
- 0x1E7F0, 0x1E7FE,
- 0x1E800, 0x1E8C4,
- 0x1E900, 0x1E943,
- 0x1E947, 0x1E947,
- 0x1E94B, 0x1E94B,
- 0x1E950, 0x1E959,
- 0x1EE00, 0x1EE03,
- 0x1EE05, 0x1EE1F,
- 0x1EE21, 0x1EE22,
- 0x1EE24, 0x1EE24,
- 0x1EE27, 0x1EE27,
- 0x1EE29, 0x1EE32,
- 0x1EE34, 0x1EE37,
- 0x1EE39, 0x1EE39,
- 0x1EE3B, 0x1EE3B,
- 0x1EE42, 0x1EE42,
- 0x1EE47, 0x1EE47,
- 0x1EE49, 0x1EE49,
- 0x1EE4B, 0x1EE4B,
- 0x1EE4D, 0x1EE4F,
- 0x1EE51, 0x1EE52,
- 0x1EE54, 0x1EE54,
- 0x1EE57, 0x1EE57,
- 0x1EE59, 0x1EE59,
- 0x1EE5B, 0x1EE5B,
- 0x1EE5D, 0x1EE5D,
- 0x1EE5F, 0x1EE5F,
- 0x1EE61, 0x1EE62,
- 0x1EE64, 0x1EE64,
- 0x1EE67, 0x1EE6A,
- 0x1EE6C, 0x1EE72,
- 0x1EE74, 0x1EE77,
- 0x1EE79, 0x1EE7C,
- 0x1EE7E, 0x1EE7E,
- 0x1EE80, 0x1EE89,
- 0x1EE8B, 0x1EE9B,
- 0x1EEA1, 0x1EEA3,
- 0x1EEA5, 0x1EEA9,
- 0x1EEAB, 0x1EEBB,
- 0x1F130, 0x1F149,
- 0x1F150, 0x1F169,
- 0x1F170, 0x1F189,
- 0x1FBF0, 0x1FBF9,
- 0x20000, 0x2A6DF,
- 0x2A700, 0x2B739,
- 0x2B740, 0x2B81D,
- 0x2B820, 0x2CEA1,
- 0x2CEB0, 0x2EBE0,
- 0x2F800, 0x2FA1D,
- 0x30000, 0x3134A,
- 0x31350, 0x323AF,
-};
-
-#define UNICODE_ISUPPER_CODEPOINTS_LENGTH 1302
-static const pm_unicode_codepoint_t unicode_isupper_codepoints[UNICODE_ISUPPER_CODEPOINTS_LENGTH] = {
- 0x100, 0x100,
- 0x102, 0x102,
- 0x104, 0x104,
- 0x106, 0x106,
- 0x108, 0x108,
- 0x10A, 0x10A,
- 0x10C, 0x10C,
- 0x10E, 0x10E,
- 0x110, 0x110,
- 0x112, 0x112,
- 0x114, 0x114,
- 0x116, 0x116,
- 0x118, 0x118,
- 0x11A, 0x11A,
- 0x11C, 0x11C,
- 0x11E, 0x11E,
- 0x120, 0x120,
- 0x122, 0x122,
- 0x124, 0x124,
- 0x126, 0x126,
- 0x128, 0x128,
- 0x12A, 0x12A,
- 0x12C, 0x12C,
- 0x12E, 0x12E,
- 0x130, 0x130,
- 0x132, 0x132,
- 0x134, 0x134,
- 0x136, 0x136,
- 0x139, 0x139,
- 0x13B, 0x13B,
- 0x13D, 0x13D,
- 0x13F, 0x13F,
- 0x141, 0x141,
- 0x143, 0x143,
- 0x145, 0x145,
- 0x147, 0x147,
- 0x14A, 0x14A,
- 0x14C, 0x14C,
- 0x14E, 0x14E,
- 0x150, 0x150,
- 0x152, 0x152,
- 0x154, 0x154,
- 0x156, 0x156,
- 0x158, 0x158,
- 0x15A, 0x15A,
- 0x15C, 0x15C,
- 0x15E, 0x15E,
- 0x160, 0x160,
- 0x162, 0x162,
- 0x164, 0x164,
- 0x166, 0x166,
- 0x168, 0x168,
- 0x16A, 0x16A,
- 0x16C, 0x16C,
- 0x16E, 0x16E,
- 0x170, 0x170,
- 0x172, 0x172,
- 0x174, 0x174,
- 0x176, 0x176,
- 0x178, 0x179,
- 0x17B, 0x17B,
- 0x17D, 0x17D,
- 0x181, 0x182,
- 0x184, 0x184,
- 0x186, 0x187,
- 0x189, 0x18B,
- 0x18E, 0x191,
- 0x193, 0x194,
- 0x196, 0x198,
- 0x19C, 0x19D,
- 0x19F, 0x1A0,
- 0x1A2, 0x1A2,
- 0x1A4, 0x1A4,
- 0x1A6, 0x1A7,
- 0x1A9, 0x1A9,
- 0x1AC, 0x1AC,
- 0x1AE, 0x1AF,
- 0x1B1, 0x1B3,
- 0x1B5, 0x1B5,
- 0x1B7, 0x1B8,
- 0x1BC, 0x1BC,
- 0x1C4, 0x1C5,
- 0x1C7, 0x1C8,
- 0x1CA, 0x1CB,
- 0x1CD, 0x1CD,
- 0x1CF, 0x1CF,
- 0x1D1, 0x1D1,
- 0x1D3, 0x1D3,
- 0x1D5, 0x1D5,
- 0x1D7, 0x1D7,
- 0x1D9, 0x1D9,
- 0x1DB, 0x1DB,
- 0x1DE, 0x1DE,
- 0x1E0, 0x1E0,
- 0x1E2, 0x1E2,
- 0x1E4, 0x1E4,
- 0x1E6, 0x1E6,
- 0x1E8, 0x1E8,
- 0x1EA, 0x1EA,
- 0x1EC, 0x1EC,
- 0x1EE, 0x1EE,
- 0x1F1, 0x1F2,
- 0x1F4, 0x1F4,
- 0x1F6, 0x1F8,
- 0x1FA, 0x1FA,
- 0x1FC, 0x1FC,
- 0x1FE, 0x1FE,
- 0x200, 0x200,
- 0x202, 0x202,
- 0x204, 0x204,
- 0x206, 0x206,
- 0x208, 0x208,
- 0x20A, 0x20A,
- 0x20C, 0x20C,
- 0x20E, 0x20E,
- 0x210, 0x210,
- 0x212, 0x212,
- 0x214, 0x214,
- 0x216, 0x216,
- 0x218, 0x218,
- 0x21A, 0x21A,
- 0x21C, 0x21C,
- 0x21E, 0x21E,
- 0x220, 0x220,
- 0x222, 0x222,
- 0x224, 0x224,
- 0x226, 0x226,
- 0x228, 0x228,
- 0x22A, 0x22A,
- 0x22C, 0x22C,
- 0x22E, 0x22E,
- 0x230, 0x230,
- 0x232, 0x232,
- 0x23A, 0x23B,
- 0x23D, 0x23E,
- 0x241, 0x241,
- 0x243, 0x246,
- 0x248, 0x248,
- 0x24A, 0x24A,
- 0x24C, 0x24C,
- 0x24E, 0x24E,
- 0x370, 0x370,
- 0x372, 0x372,
- 0x376, 0x376,
- 0x37F, 0x37F,
- 0x386, 0x386,
- 0x388, 0x38A,
- 0x38C, 0x38C,
- 0x38E, 0x38F,
- 0x391, 0x3A1,
- 0x3A3, 0x3AB,
- 0x3CF, 0x3CF,
- 0x3D2, 0x3D4,
- 0x3D8, 0x3D8,
- 0x3DA, 0x3DA,
- 0x3DC, 0x3DC,
- 0x3DE, 0x3DE,
- 0x3E0, 0x3E0,
- 0x3E2, 0x3E2,
- 0x3E4, 0x3E4,
- 0x3E6, 0x3E6,
- 0x3E8, 0x3E8,
- 0x3EA, 0x3EA,
- 0x3EC, 0x3EC,
- 0x3EE, 0x3EE,
- 0x3F4, 0x3F4,
- 0x3F7, 0x3F7,
- 0x3F9, 0x3FA,
- 0x3FD, 0x42F,
- 0x460, 0x460,
- 0x462, 0x462,
- 0x464, 0x464,
- 0x466, 0x466,
- 0x468, 0x468,
- 0x46A, 0x46A,
- 0x46C, 0x46C,
- 0x46E, 0x46E,
- 0x470, 0x470,
- 0x472, 0x472,
- 0x474, 0x474,
- 0x476, 0x476,
- 0x478, 0x478,
- 0x47A, 0x47A,
- 0x47C, 0x47C,
- 0x47E, 0x47E,
- 0x480, 0x480,
- 0x48A, 0x48A,
- 0x48C, 0x48C,
- 0x48E, 0x48E,
- 0x490, 0x490,
- 0x492, 0x492,
- 0x494, 0x494,
- 0x496, 0x496,
- 0x498, 0x498,
- 0x49A, 0x49A,
- 0x49C, 0x49C,
- 0x49E, 0x49E,
- 0x4A0, 0x4A0,
- 0x4A2, 0x4A2,
- 0x4A4, 0x4A4,
- 0x4A6, 0x4A6,
- 0x4A8, 0x4A8,
- 0x4AA, 0x4AA,
- 0x4AC, 0x4AC,
- 0x4AE, 0x4AE,
- 0x4B0, 0x4B0,
- 0x4B2, 0x4B2,
- 0x4B4, 0x4B4,
- 0x4B6, 0x4B6,
- 0x4B8, 0x4B8,
- 0x4BA, 0x4BA,
- 0x4BC, 0x4BC,
- 0x4BE, 0x4BE,
- 0x4C0, 0x4C1,
- 0x4C3, 0x4C3,
- 0x4C5, 0x4C5,
- 0x4C7, 0x4C7,
- 0x4C9, 0x4C9,
- 0x4CB, 0x4CB,
- 0x4CD, 0x4CD,
- 0x4D0, 0x4D0,
- 0x4D2, 0x4D2,
- 0x4D4, 0x4D4,
- 0x4D6, 0x4D6,
- 0x4D8, 0x4D8,
- 0x4DA, 0x4DA,
- 0x4DC, 0x4DC,
- 0x4DE, 0x4DE,
- 0x4E0, 0x4E0,
- 0x4E2, 0x4E2,
- 0x4E4, 0x4E4,
- 0x4E6, 0x4E6,
- 0x4E8, 0x4E8,
- 0x4EA, 0x4EA,
- 0x4EC, 0x4EC,
- 0x4EE, 0x4EE,
- 0x4F0, 0x4F0,
- 0x4F2, 0x4F2,
- 0x4F4, 0x4F4,
- 0x4F6, 0x4F6,
- 0x4F8, 0x4F8,
- 0x4FA, 0x4FA,
- 0x4FC, 0x4FC,
- 0x4FE, 0x4FE,
- 0x500, 0x500,
- 0x502, 0x502,
- 0x504, 0x504,
- 0x506, 0x506,
- 0x508, 0x508,
- 0x50A, 0x50A,
- 0x50C, 0x50C,
- 0x50E, 0x50E,
- 0x510, 0x510,
- 0x512, 0x512,
- 0x514, 0x514,
- 0x516, 0x516,
- 0x518, 0x518,
- 0x51A, 0x51A,
- 0x51C, 0x51C,
- 0x51E, 0x51E,
- 0x520, 0x520,
- 0x522, 0x522,
- 0x524, 0x524,
- 0x526, 0x526,
- 0x528, 0x528,
- 0x52A, 0x52A,
- 0x52C, 0x52C,
- 0x52E, 0x52E,
- 0x531, 0x556,
- 0x10A0, 0x10C5,
- 0x10C7, 0x10C7,
- 0x10CD, 0x10CD,
- 0x13A0, 0x13F5,
- 0x1C90, 0x1CBA,
- 0x1CBD, 0x1CBF,
- 0x1E00, 0x1E00,
- 0x1E02, 0x1E02,
- 0x1E04, 0x1E04,
- 0x1E06, 0x1E06,
- 0x1E08, 0x1E08,
- 0x1E0A, 0x1E0A,
- 0x1E0C, 0x1E0C,
- 0x1E0E, 0x1E0E,
- 0x1E10, 0x1E10,
- 0x1E12, 0x1E12,
- 0x1E14, 0x1E14,
- 0x1E16, 0x1E16,
- 0x1E18, 0x1E18,
- 0x1E1A, 0x1E1A,
- 0x1E1C, 0x1E1C,
- 0x1E1E, 0x1E1E,
- 0x1E20, 0x1E20,
- 0x1E22, 0x1E22,
- 0x1E24, 0x1E24,
- 0x1E26, 0x1E26,
- 0x1E28, 0x1E28,
- 0x1E2A, 0x1E2A,
- 0x1E2C, 0x1E2C,
- 0x1E2E, 0x1E2E,
- 0x1E30, 0x1E30,
- 0x1E32, 0x1E32,
- 0x1E34, 0x1E34,
- 0x1E36, 0x1E36,
- 0x1E38, 0x1E38,
- 0x1E3A, 0x1E3A,
- 0x1E3C, 0x1E3C,
- 0x1E3E, 0x1E3E,
- 0x1E40, 0x1E40,
- 0x1E42, 0x1E42,
- 0x1E44, 0x1E44,
- 0x1E46, 0x1E46,
- 0x1E48, 0x1E48,
- 0x1E4A, 0x1E4A,
- 0x1E4C, 0x1E4C,
- 0x1E4E, 0x1E4E,
- 0x1E50, 0x1E50,
- 0x1E52, 0x1E52,
- 0x1E54, 0x1E54,
- 0x1E56, 0x1E56,
- 0x1E58, 0x1E58,
- 0x1E5A, 0x1E5A,
- 0x1E5C, 0x1E5C,
- 0x1E5E, 0x1E5E,
- 0x1E60, 0x1E60,
- 0x1E62, 0x1E62,
- 0x1E64, 0x1E64,
- 0x1E66, 0x1E66,
- 0x1E68, 0x1E68,
- 0x1E6A, 0x1E6A,
- 0x1E6C, 0x1E6C,
- 0x1E6E, 0x1E6E,
- 0x1E70, 0x1E70,
- 0x1E72, 0x1E72,
- 0x1E74, 0x1E74,
- 0x1E76, 0x1E76,
- 0x1E78, 0x1E78,
- 0x1E7A, 0x1E7A,
- 0x1E7C, 0x1E7C,
- 0x1E7E, 0x1E7E,
- 0x1E80, 0x1E80,
- 0x1E82, 0x1E82,
- 0x1E84, 0x1E84,
- 0x1E86, 0x1E86,
- 0x1E88, 0x1E88,
- 0x1E8A, 0x1E8A,
- 0x1E8C, 0x1E8C,
- 0x1E8E, 0x1E8E,
- 0x1E90, 0x1E90,
- 0x1E92, 0x1E92,
- 0x1E94, 0x1E94,
- 0x1E9E, 0x1E9E,
- 0x1EA0, 0x1EA0,
- 0x1EA2, 0x1EA2,
- 0x1EA4, 0x1EA4,
- 0x1EA6, 0x1EA6,
- 0x1EA8, 0x1EA8,
- 0x1EAA, 0x1EAA,
- 0x1EAC, 0x1EAC,
- 0x1EAE, 0x1EAE,
- 0x1EB0, 0x1EB0,
- 0x1EB2, 0x1EB2,
- 0x1EB4, 0x1EB4,
- 0x1EB6, 0x1EB6,
- 0x1EB8, 0x1EB8,
- 0x1EBA, 0x1EBA,
- 0x1EBC, 0x1EBC,
- 0x1EBE, 0x1EBE,
- 0x1EC0, 0x1EC0,
- 0x1EC2, 0x1EC2,
- 0x1EC4, 0x1EC4,
- 0x1EC6, 0x1EC6,
- 0x1EC8, 0x1EC8,
- 0x1ECA, 0x1ECA,
- 0x1ECC, 0x1ECC,
- 0x1ECE, 0x1ECE,
- 0x1ED0, 0x1ED0,
- 0x1ED2, 0x1ED2,
- 0x1ED4, 0x1ED4,
- 0x1ED6, 0x1ED6,
- 0x1ED8, 0x1ED8,
- 0x1EDA, 0x1EDA,
- 0x1EDC, 0x1EDC,
- 0x1EDE, 0x1EDE,
- 0x1EE0, 0x1EE0,
- 0x1EE2, 0x1EE2,
- 0x1EE4, 0x1EE4,
- 0x1EE6, 0x1EE6,
- 0x1EE8, 0x1EE8,
- 0x1EEA, 0x1EEA,
- 0x1EEC, 0x1EEC,
- 0x1EEE, 0x1EEE,
- 0x1EF0, 0x1EF0,
- 0x1EF2, 0x1EF2,
- 0x1EF4, 0x1EF4,
- 0x1EF6, 0x1EF6,
- 0x1EF8, 0x1EF8,
- 0x1EFA, 0x1EFA,
- 0x1EFC, 0x1EFC,
- 0x1EFE, 0x1EFE,
- 0x1F08, 0x1F0F,
- 0x1F18, 0x1F1D,
- 0x1F28, 0x1F2F,
- 0x1F38, 0x1F3F,
- 0x1F48, 0x1F4D,
- 0x1F59, 0x1F59,
- 0x1F5B, 0x1F5B,
- 0x1F5D, 0x1F5D,
- 0x1F5F, 0x1F5F,
- 0x1F68, 0x1F6F,
- 0x1F88, 0x1F8F,
- 0x1F98, 0x1F9F,
- 0x1FA8, 0x1FAF,
- 0x1FB8, 0x1FBC,
- 0x1FC8, 0x1FCC,
- 0x1FD8, 0x1FDB,
- 0x1FE8, 0x1FEC,
- 0x1FF8, 0x1FFC,
- 0x2102, 0x2102,
- 0x2107, 0x2107,
- 0x210B, 0x210D,
- 0x2110, 0x2112,
- 0x2115, 0x2115,
- 0x2119, 0x211D,
- 0x2124, 0x2124,
- 0x2126, 0x2126,
- 0x2128, 0x2128,
- 0x212A, 0x212D,
- 0x2130, 0x2133,
- 0x213E, 0x213F,
- 0x2145, 0x2145,
- 0x2160, 0x216F,
- 0x2183, 0x2183,
- 0x24B6, 0x24CF,
- 0x2C00, 0x2C2F,
- 0x2C60, 0x2C60,
- 0x2C62, 0x2C64,
- 0x2C67, 0x2C67,
- 0x2C69, 0x2C69,
- 0x2C6B, 0x2C6B,
- 0x2C6D, 0x2C70,
- 0x2C72, 0x2C72,
- 0x2C75, 0x2C75,
- 0x2C7E, 0x2C80,
- 0x2C82, 0x2C82,
- 0x2C84, 0x2C84,
- 0x2C86, 0x2C86,
- 0x2C88, 0x2C88,
- 0x2C8A, 0x2C8A,
- 0x2C8C, 0x2C8C,
- 0x2C8E, 0x2C8E,
- 0x2C90, 0x2C90,
- 0x2C92, 0x2C92,
- 0x2C94, 0x2C94,
- 0x2C96, 0x2C96,
- 0x2C98, 0x2C98,
- 0x2C9A, 0x2C9A,
- 0x2C9C, 0x2C9C,
- 0x2C9E, 0x2C9E,
- 0x2CA0, 0x2CA0,
- 0x2CA2, 0x2CA2,
- 0x2CA4, 0x2CA4,
- 0x2CA6, 0x2CA6,
- 0x2CA8, 0x2CA8,
- 0x2CAA, 0x2CAA,
- 0x2CAC, 0x2CAC,
- 0x2CAE, 0x2CAE,
- 0x2CB0, 0x2CB0,
- 0x2CB2, 0x2CB2,
- 0x2CB4, 0x2CB4,
- 0x2CB6, 0x2CB6,
- 0x2CB8, 0x2CB8,
- 0x2CBA, 0x2CBA,
- 0x2CBC, 0x2CBC,
- 0x2CBE, 0x2CBE,
- 0x2CC0, 0x2CC0,
- 0x2CC2, 0x2CC2,
- 0x2CC4, 0x2CC4,
- 0x2CC6, 0x2CC6,
- 0x2CC8, 0x2CC8,
- 0x2CCA, 0x2CCA,
- 0x2CCC, 0x2CCC,
- 0x2CCE, 0x2CCE,
- 0x2CD0, 0x2CD0,
- 0x2CD2, 0x2CD2,
- 0x2CD4, 0x2CD4,
- 0x2CD6, 0x2CD6,
- 0x2CD8, 0x2CD8,
- 0x2CDA, 0x2CDA,
- 0x2CDC, 0x2CDC,
- 0x2CDE, 0x2CDE,
- 0x2CE0, 0x2CE0,
- 0x2CE2, 0x2CE2,
- 0x2CEB, 0x2CEB,
- 0x2CED, 0x2CED,
- 0x2CF2, 0x2CF2,
- 0xA640, 0xA640,
- 0xA642, 0xA642,
- 0xA644, 0xA644,
- 0xA646, 0xA646,
- 0xA648, 0xA648,
- 0xA64A, 0xA64A,
- 0xA64C, 0xA64C,
- 0xA64E, 0xA64E,
- 0xA650, 0xA650,
- 0xA652, 0xA652,
- 0xA654, 0xA654,
- 0xA656, 0xA656,
- 0xA658, 0xA658,
- 0xA65A, 0xA65A,
- 0xA65C, 0xA65C,
- 0xA65E, 0xA65E,
- 0xA660, 0xA660,
- 0xA662, 0xA662,
- 0xA664, 0xA664,
- 0xA666, 0xA666,
- 0xA668, 0xA668,
- 0xA66A, 0xA66A,
- 0xA66C, 0xA66C,
- 0xA680, 0xA680,
- 0xA682, 0xA682,
- 0xA684, 0xA684,
- 0xA686, 0xA686,
- 0xA688, 0xA688,
- 0xA68A, 0xA68A,
- 0xA68C, 0xA68C,
- 0xA68E, 0xA68E,
- 0xA690, 0xA690,
- 0xA692, 0xA692,
- 0xA694, 0xA694,
- 0xA696, 0xA696,
- 0xA698, 0xA698,
- 0xA69A, 0xA69A,
- 0xA722, 0xA722,
- 0xA724, 0xA724,
- 0xA726, 0xA726,
- 0xA728, 0xA728,
- 0xA72A, 0xA72A,
- 0xA72C, 0xA72C,
- 0xA72E, 0xA72E,
- 0xA732, 0xA732,
- 0xA734, 0xA734,
- 0xA736, 0xA736,
- 0xA738, 0xA738,
- 0xA73A, 0xA73A,
- 0xA73C, 0xA73C,
- 0xA73E, 0xA73E,
- 0xA740, 0xA740,
- 0xA742, 0xA742,
- 0xA744, 0xA744,
- 0xA746, 0xA746,
- 0xA748, 0xA748,
- 0xA74A, 0xA74A,
- 0xA74C, 0xA74C,
- 0xA74E, 0xA74E,
- 0xA750, 0xA750,
- 0xA752, 0xA752,
- 0xA754, 0xA754,
- 0xA756, 0xA756,
- 0xA758, 0xA758,
- 0xA75A, 0xA75A,
- 0xA75C, 0xA75C,
- 0xA75E, 0xA75E,
- 0xA760, 0xA760,
- 0xA762, 0xA762,
- 0xA764, 0xA764,
- 0xA766, 0xA766,
- 0xA768, 0xA768,
- 0xA76A, 0xA76A,
- 0xA76C, 0xA76C,
- 0xA76E, 0xA76E,
- 0xA779, 0xA779,
- 0xA77B, 0xA77B,
- 0xA77D, 0xA77E,
- 0xA780, 0xA780,
- 0xA782, 0xA782,
- 0xA784, 0xA784,
- 0xA786, 0xA786,
- 0xA78B, 0xA78B,
- 0xA78D, 0xA78D,
- 0xA790, 0xA790,
- 0xA792, 0xA792,
- 0xA796, 0xA796,
- 0xA798, 0xA798,
- 0xA79A, 0xA79A,
- 0xA79C, 0xA79C,
- 0xA79E, 0xA79E,
- 0xA7A0, 0xA7A0,
- 0xA7A2, 0xA7A2,
- 0xA7A4, 0xA7A4,
- 0xA7A6, 0xA7A6,
- 0xA7A8, 0xA7A8,
- 0xA7AA, 0xA7AE,
- 0xA7B0, 0xA7B4,
- 0xA7B6, 0xA7B6,
- 0xA7B8, 0xA7B8,
- 0xA7BA, 0xA7BA,
- 0xA7BC, 0xA7BC,
- 0xA7BE, 0xA7BE,
- 0xA7C0, 0xA7C0,
- 0xA7C2, 0xA7C2,
- 0xA7C4, 0xA7C7,
- 0xA7C9, 0xA7C9,
- 0xA7D0, 0xA7D0,
- 0xA7D6, 0xA7D6,
- 0xA7D8, 0xA7D8,
- 0xA7F5, 0xA7F5,
- 0xFF21, 0xFF3A,
- 0x10400, 0x10427,
- 0x104B0, 0x104D3,
- 0x10570, 0x1057A,
- 0x1057C, 0x1058A,
- 0x1058C, 0x10592,
- 0x10594, 0x10595,
- 0x10C80, 0x10CB2,
- 0x118A0, 0x118BF,
- 0x16E40, 0x16E5F,
- 0x1D400, 0x1D419,
- 0x1D434, 0x1D44D,
- 0x1D468, 0x1D481,
- 0x1D49C, 0x1D49C,
- 0x1D49E, 0x1D49F,
- 0x1D4A2, 0x1D4A2,
- 0x1D4A5, 0x1D4A6,
- 0x1D4A9, 0x1D4AC,
- 0x1D4AE, 0x1D4B5,
- 0x1D4D0, 0x1D4E9,
- 0x1D504, 0x1D505,
- 0x1D507, 0x1D50A,
- 0x1D50D, 0x1D514,
- 0x1D516, 0x1D51C,
- 0x1D538, 0x1D539,
- 0x1D53B, 0x1D53E,
- 0x1D540, 0x1D544,
- 0x1D546, 0x1D546,
- 0x1D54A, 0x1D550,
- 0x1D56C, 0x1D585,
- 0x1D5A0, 0x1D5B9,
- 0x1D5D4, 0x1D5ED,
- 0x1D608, 0x1D621,
- 0x1D63C, 0x1D655,
- 0x1D670, 0x1D689,
- 0x1D6A8, 0x1D6C0,
- 0x1D6E2, 0x1D6FA,
- 0x1D71C, 0x1D734,
- 0x1D756, 0x1D76E,
- 0x1D790, 0x1D7A8,
- 0x1D7CA, 0x1D7CA,
- 0x1E900, 0x1E921,
- 0x1F130, 0x1F149,
- 0x1F150, 0x1F169,
- 0x1F170, 0x1F189,
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding unicode codepoint. Note that
- * this table is different from other encodings where we used a lookup table
- * because the indices of those tables are the byte representations, not the
- * codepoints themselves.
- */
-const uint8_t pm_encoding_unicode_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Binary search through the given list of codepoints to see if the given
- * codepoint is in the list.
- */
-static bool
-pm_unicode_codepoint_match(pm_unicode_codepoint_t codepoint, const pm_unicode_codepoint_t *codepoints, size_t size) {
- size_t start = 0;
- size_t end = size;
-
- while (start < end) {
- size_t middle = start + (end - start) / 2;
- if ((middle % 2) != 0) middle--;
-
- if (codepoint >= codepoints[middle] && codepoint <= codepoints[middle + 1]) {
- return true;
- }
-
- if (codepoint < codepoints[middle]) {
- end = middle;
- } else {
- start = middle + 2;
- }
- }
-
- return false;
-}
-
-/**
- * A state transition table for decoding UTF-8.
- *
- * Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-static const uint8_t pm_utf_8_dfa[] = {
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
- 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
- 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
- 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
- 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
- 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
- 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
- 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
-};
-
-/**
- * Given a pointer to a string and the number of bytes remaining in the string,
- * decode the next UTF-8 codepoint and return it. The number of bytes consumed
- * is returned in the width out parameter.
- */
-static pm_unicode_codepoint_t
-pm_utf_8_codepoint(const uint8_t *b, ptrdiff_t n, size_t *width) {
- assert(n >= 0);
-
- size_t maximum = (n > 4) ? 4 : ((size_t) n);
- uint32_t codepoint;
- uint32_t state = 0;
-
- for (size_t index = 0; index < maximum; index++) {
- uint32_t byte = b[index];
- uint32_t type = pm_utf_8_dfa[byte];
-
- codepoint = (state != 0) ?
- (byte & 0x3fu) | (codepoint << 6) :
- (0xffu >> type) & (byte);
-
- state = pm_utf_8_dfa[256 + (state * 16) + type];
- if (state == 0) {
- *width = index + 1;
- return (pm_unicode_codepoint_t) codepoint;
- }
- }
-
- *width = 0;
- return 0;
-}
-
-/**
- * Return the size of the next character in the UTF-8 encoding.
- */
-size_t
-pm_encoding_utf_8_char_width(const uint8_t *b, ptrdiff_t n) {
- assert(n >= 0);
-
- size_t maximum = (n > 4) ? 4 : ((size_t) n);
- uint32_t state = 0;
-
- for (size_t index = 0; index < maximum; index++) {
- state = pm_utf_8_dfa[256 + (state * 16) + pm_utf_8_dfa[b[index]]];
- if (state == 0) return index + 1;
- }
-
- return 0;
-}
-
-/**
- * Return the size of the next character in the UTF-8 encoding if it is an
- * alphabetical character.
- */
-size_t
-pm_encoding_utf_8_alpha_char(const uint8_t *b, ptrdiff_t n) {
- if (*b < 0x80) {
- return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT) ? 1 : 0;
- }
-
- size_t width;
- pm_unicode_codepoint_t codepoint = pm_utf_8_codepoint(b, n, &width);
-
- if (codepoint <= 0xFF) {
- return (pm_encoding_unicode_table[(uint8_t) codepoint] & PRISM_ENCODING_ALPHABETIC_BIT) ? width : 0;
- } else {
- return pm_unicode_codepoint_match(codepoint, unicode_alpha_codepoints, UNICODE_ALPHA_CODEPOINTS_LENGTH) ? width : 0;
- }
-}
-
-/**
- * Return the size of the next character in the UTF-8 encoding if it is an
- * alphanumeric character.
- */
-size_t
-pm_encoding_utf_8_alnum_char(const uint8_t *b, ptrdiff_t n) {
- if (*b < 0x80) {
- return (pm_encoding_unicode_table[*b] & (PRISM_ENCODING_ALPHANUMERIC_BIT)) ? 1 : 0;
- }
-
- size_t width;
- pm_unicode_codepoint_t codepoint = pm_utf_8_codepoint(b, n, &width);
-
- if (codepoint <= 0xFF) {
- return (pm_encoding_unicode_table[(uint8_t) codepoint] & (PRISM_ENCODING_ALPHANUMERIC_BIT)) ? width : 0;
- } else {
- return pm_unicode_codepoint_match(codepoint, unicode_alnum_codepoints, UNICODE_ALNUM_CODEPOINTS_LENGTH) ? width : 0;
- }
-}
-
-/**
- * Return true if the next character in the UTF-8 encoding if it is an uppercase
- * character.
- */
-bool
-pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n) {
- if (*b < 0x80) {
- return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_UPPERCASE_BIT) ? true : false;
- }
-
- size_t width;
- pm_unicode_codepoint_t codepoint = pm_utf_8_codepoint(b, n, &width);
-
- if (codepoint <= 0xFF) {
- return (pm_encoding_unicode_table[(uint8_t) codepoint] & PRISM_ENCODING_UPPERCASE_BIT) ? true : false;
- } else {
- return pm_unicode_codepoint_match(codepoint, unicode_isupper_codepoints, UNICODE_ISUPPER_CODEPOINTS_LENGTH) ? true : false;
- }
-}
-
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
-
-static pm_unicode_codepoint_t
-pm_cesu_8_codepoint(const uint8_t *b, ptrdiff_t n, size_t *width) {
- if (b[0] < 0x80) {
- *width = 1;
- return (pm_unicode_codepoint_t) b[0];
- }
-
- if (n > 1 && b[0] >= 0xC2 && b[0] <= 0xDF && b[1] >= 0x80 && b[1] <= 0xBF) {
- *width = 2;
-
- // 110xxxxx 10xxxxxx
- return (pm_unicode_codepoint_t) (((b[0] & 0x1F) << 6) | (b[1] & 0x3F));
- }
-
- if (n > 5 && b[0] == 0xED && b[1] >= 0xA0 && b[1] <= 0xAF && b[2] >= 0x80 && b[2] <= 0xBF && b[3] == 0xED && b[4] >= 0xB0 && b[4] <= 0xBF && b[5] >= 0x80 && b[5] <= 0xBF) {
- *width = 6;
-
- // 11101101 1010xxxx 10xxxxxx 11101101 1011xxxx 10xxxxxx
- return (pm_unicode_codepoint_t) (0x10000 + (((b[1] & 0xF) << 16) | ((b[2] & 0x3F) << 10) | ((b[4] & 0xF) << 6) | (b[5] & 0x3F)));
- }
-
- if (n > 2 && b[0] == 0xED && b[1] >= 0xA0 && b[1] <= 0xBF) {
- *width = 3;
-
- // 11101101 1010xxxx 10xxxxx
- return (pm_unicode_codepoint_t) (0x10000 + (((b[0] & 0x03) << 16) | ((b[1] & 0x3F) << 10) | (b[2] & 0x3F)));
- }
-
- if (n > 2 && ((b[0] == 0xE0 && b[1] >= 0xA0) || (b[0] >= 0xE1 && b[0] <= 0xEF && b[1] >= 0x80)) && b[1] <= 0xBF && b[2] >= 0x80 && b[2] <= 0xBF) {
- *width = 3;
-
- // 1110xxxx 10xxxxxx 10xxxxx
- return (pm_unicode_codepoint_t) (((b[0] & 0xF) << 12) | ((b[1] & 0x3F) << 6) | (b[2] & 0x3F));
- }
-
- *width = 0;
- return 0;
-}
-
-static size_t
-pm_encoding_cesu_8_char_width(const uint8_t *b, ptrdiff_t n) {
- size_t width;
- pm_cesu_8_codepoint(b, n, &width);
- return width;
-}
-
-static size_t
-pm_encoding_cesu_8_alpha_char(const uint8_t *b, ptrdiff_t n) {
- if (*b < 0x80) {
- return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT) ? 1 : 0;
- }
-
- size_t width;
- pm_unicode_codepoint_t codepoint = pm_cesu_8_codepoint(b, n, &width);
-
- if (codepoint <= 0xFF) {
- return (pm_encoding_unicode_table[(uint8_t) codepoint] & PRISM_ENCODING_ALPHABETIC_BIT) ? width : 0;
- } else {
- return pm_unicode_codepoint_match(codepoint, unicode_alpha_codepoints, UNICODE_ALPHA_CODEPOINTS_LENGTH) ? width : 0;
- }
-}
-
-static size_t
-pm_encoding_cesu_8_alnum_char(const uint8_t *b, ptrdiff_t n) {
- if (*b < 0x80) {
- return (pm_encoding_unicode_table[*b] & (PRISM_ENCODING_ALPHANUMERIC_BIT)) ? 1 : 0;
- }
-
- size_t width;
- pm_unicode_codepoint_t codepoint = pm_cesu_8_codepoint(b, n, &width);
-
- if (codepoint <= 0xFF) {
- return (pm_encoding_unicode_table[(uint8_t) codepoint] & (PRISM_ENCODING_ALPHANUMERIC_BIT)) ? width : 0;
- } else {
- return pm_unicode_codepoint_match(codepoint, unicode_alnum_codepoints, UNICODE_ALNUM_CODEPOINTS_LENGTH) ? width : 0;
- }
-}
-
-static bool
-pm_encoding_cesu_8_isupper_char(const uint8_t *b, ptrdiff_t n) {
- if (*b < 0x80) {
- return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_UPPERCASE_BIT) ? true : false;
- }
-
- size_t width;
- pm_unicode_codepoint_t codepoint = pm_cesu_8_codepoint(b, n, &width);
-
- if (codepoint <= 0xFF) {
- return (pm_encoding_unicode_table[(uint8_t) codepoint] & PRISM_ENCODING_UPPERCASE_BIT) ? true : false;
- } else {
- return pm_unicode_codepoint_match(codepoint, unicode_isupper_codepoints, UNICODE_ISUPPER_CODEPOINTS_LENGTH) ? true : false;
- }
-}
-
-#endif
-
-#undef UNICODE_ALPHA_CODEPOINTS_LENGTH
-#undef UNICODE_ALNUM_CODEPOINTS_LENGTH
-#undef UNICODE_ISUPPER_CODEPOINTS_LENGTH
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding US-ASCII character.
- */
-static const uint8_t pm_encoding_ascii_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding CP850 character.
- */
-static const uint8_t pm_encoding_cp850_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding CP852 character.
- */
-static const uint8_t pm_encoding_cp852_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding CP855 character.
- */
-static const uint8_t pm_encoding_cp855_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding GB1988 character.
- */
-static const uint8_t pm_encoding_gb1988_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM437 character.
- */
-static const uint8_t pm_encoding_ibm437_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM720 character.
- */
-static const uint8_t pm_encoding_ibm720_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM737 character.
- */
-static const uint8_t pm_encoding_ibm737_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM775 character.
- */
-static const uint8_t pm_encoding_ibm775_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM852 character.
- */
-static const uint8_t pm_encoding_ibm852_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM855 character.
- */
-static const uint8_t pm_encoding_ibm855_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM857 character.
- */
-static const uint8_t pm_encoding_ibm857_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM860 character.
- */
-static const uint8_t pm_encoding_ibm860_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM861 character.
- */
-static const uint8_t pm_encoding_ibm861_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM862 character.
- */
-static const uint8_t pm_encoding_ibm862_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM863 character.
- */
-static const uint8_t pm_encoding_ibm863_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM864 character.
- */
-static const uint8_t pm_encoding_ibm864_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM865 character.
- */
-static const uint8_t pm_encoding_ibm865_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM866 character.
- */
-static const uint8_t pm_encoding_ibm866_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding IBM869 character.
- */
-static const uint8_t pm_encoding_ibm869_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-1 character.
- */
-static const uint8_t pm_encoding_iso_8859_1_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-2 character.
- */
-static const uint8_t pm_encoding_iso_8859_2_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 0, 7, 0, 7, 7, 0, 0, 7, 7, 7, 7, 0, 7, 7, // Ax
- 0, 3, 0, 3, 0, 3, 3, 0, 0, 3, 3, 3, 3, 0, 3, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-3 character.
- */
-static const uint8_t pm_encoding_iso_8859_3_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 0, 0, 0, 0, 7, 0, 0, 7, 7, 7, 7, 0, 0, 7, // Ax
- 0, 3, 0, 0, 0, 3, 3, 0, 0, 3, 3, 3, 3, 0, 0, 3, // Bx
- 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 0, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-4 character.
- */
-static const uint8_t pm_encoding_iso_8859_4_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 3, 7, 0, 7, 7, 0, 0, 7, 7, 7, 7, 0, 7, 0, // Ax
- 0, 3, 0, 3, 0, 3, 3, 0, 0, 3, 3, 3, 3, 7, 3, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-5 character.
- */
-static const uint8_t pm_encoding_iso_8859_5_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, // Ax
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-6 character.
- */
-static const uint8_t pm_encoding_iso_8859_6_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Cx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-7 character.
- */
-static const uint8_t pm_encoding_iso_8859_7_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 7, 0, 7, 7, 7, 0, 7, 0, 7, 7, // Bx
- 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-8 character.
- */
-static const uint8_t pm_encoding_iso_8859_8_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-9 character.
- */
-static const uint8_t pm_encoding_iso_8859_9_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-10 character.
- */
-static const uint8_t pm_encoding_iso_8859_10_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 0, 7, 7, // Ax
- 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 0, 3, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-11 character.
- */
-static const uint8_t pm_encoding_iso_8859_11_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ax
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Bx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Cx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-13 character.
- */
-static const uint8_t pm_encoding_iso_8859_13_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 0, 0, 0, 7, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 3, 0, 0, 0, 0, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-14 character.
- */
-static const uint8_t pm_encoding_iso_8859_14_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 3, 0, 7, 3, 7, 0, 7, 0, 7, 3, 7, 0, 0, 7, // Ax
- 7, 3, 7, 3, 7, 3, 0, 7, 3, 3, 3, 7, 3, 7, 3, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-15 character.
- */
-static const uint8_t pm_encoding_iso_8859_15_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 7, 0, 3, 0, 3, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 7, 3, 0, 0, 3, 0, 3, 0, 7, 3, 7, 0, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding ISO-8859-16 character.
- */
-static const uint8_t pm_encoding_iso_8859_16_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 7, 3, 7, 0, 0, 7, 0, 3, 0, 7, 0, 7, 0, 3, 7, // Ax
- 0, 0, 7, 3, 7, 0, 0, 0, 3, 3, 3, 0, 7, 3, 7, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding KOI8-R character.
- */
-static const uint8_t pm_encoding_koi8_r_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Cx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Dx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Ex
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding KOI8-U character.
- */
-static const uint8_t pm_encoding_koi8_u_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 3, 3, 0, 3, 3, 0, 0, 0, 0, 0, 3, 0, 0, // Ax
- 0, 0, 0, 7, 7, 0, 7, 7, 0, 0, 0, 0, 0, 7, 0, 0, // Bx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Cx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Dx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Ex
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding macCentEuro character.
- */
-static const uint8_t pm_encoding_mac_cent_euro_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding macCroatian character.
- */
-static const uint8_t pm_encoding_mac_croatian_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
- /**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding macCyrillic character.
- */
-static const uint8_t pm_encoding_mac_cyrillic_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding macGreek character.
- */
-static const uint8_t pm_encoding_mac_greek_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding macIceland character.
- */
-static const uint8_t pm_encoding_mac_iceland_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding macRoman character.
- */
-static const uint8_t pm_encoding_mac_roman_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding macRomania character.
- */
-static const uint8_t pm_encoding_mac_romania_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding macThai character.
- */
-static const uint8_t pm_encoding_mac_thai_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding TIS-620 character.
- */
-static const uint8_t pm_encoding_tis_620_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ax
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Bx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Cx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding macTurkish character.
- */
-static const uint8_t pm_encoding_mac_turkish_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding macUkraine character.
- */
-static const uint8_t pm_encoding_mac_ukraine_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-1250 character.
- */
-static const uint8_t pm_encoding_windows_1250_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 7, 7, 7, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 3, 3, 3, // 9x
- 0, 0, 0, 7, 0, 7, 0, 0, 0, 0, 7, 0, 0, 0, 0, 7, // Ax
- 0, 0, 0, 3, 0, 3, 0, 0, 0, 3, 3, 0, 7, 0, 3, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-1251 character.
- */
-static const uint8_t pm_encoding_windows_1251_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 7, 7, 0, 3, 0, 0, 0, 0, 0, 0, 7, 0, 7, 7, 7, 7, // 8x
- 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 3, 3, 3, // 9x
- 0, 7, 3, 7, 0, 7, 0, 0, 7, 0, 7, 0, 0, 0, 0, 7, // Ax
- 0, 0, 7, 3, 3, 3, 0, 0, 3, 0, 3, 0, 3, 7, 3, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-1252 character.
- */
-static const uint8_t pm_encoding_windows_1252_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 7, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 3, 7, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-1253 character.
- */
-static const uint8_t pm_encoding_windows_1253_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 7, 0, 7, 7, 7, 0, 7, 0, 7, 7, // Bx
- 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-1254 character.
- */
-static const uint8_t pm_encoding_windows_1254_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 7, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-1255 character.
- */
-static const uint8_t pm_encoding_windows_1255_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-1256 character.
- */
-static const uint8_t pm_encoding_windows_1256_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Cx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-1257 character.
- */
-static const uint8_t pm_encoding_windows_1257_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 0, 0, 0, 7, // Ax
- 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 3, 0, 0, 0, 0, 3, // Bx
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // Cx
- 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 3, // Dx
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // Ex
- 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-1258 character.
- */
-static const uint8_t pm_encoding_windows_1258_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-/**
- * Each element of the following table contains a bitfield that indicates a
- * piece of information about the corresponding windows-874 character.
- */
-static const uint8_t pm_encoding_windows_874_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, // 3x
- 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 4x
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, // 5x
- 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 6x
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-#define PRISM_ENCODING_TABLE(name) \
- static size_t pm_encoding_ ##name ## _alpha_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) { \
- return (pm_encoding_ ##name ## _table[*b] & PRISM_ENCODING_ALPHABETIC_BIT); \
- } \
- static size_t pm_encoding_ ##name ## _alnum_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) { \
- return (pm_encoding_ ##name ## _table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT) ? 1 : 0; \
- } \
- static bool pm_encoding_ ##name ## _isupper_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) { \
- return (pm_encoding_ ##name ## _table[*b] & PRISM_ENCODING_UPPERCASE_BIT); \
- }
-
-PRISM_ENCODING_TABLE(cp850)
-PRISM_ENCODING_TABLE(cp852)
-PRISM_ENCODING_TABLE(cp855)
-PRISM_ENCODING_TABLE(gb1988)
-PRISM_ENCODING_TABLE(ibm437)
-PRISM_ENCODING_TABLE(ibm720)
-PRISM_ENCODING_TABLE(ibm737)
-PRISM_ENCODING_TABLE(ibm775)
-PRISM_ENCODING_TABLE(ibm852)
-PRISM_ENCODING_TABLE(ibm855)
-PRISM_ENCODING_TABLE(ibm857)
-PRISM_ENCODING_TABLE(ibm860)
-PRISM_ENCODING_TABLE(ibm861)
-PRISM_ENCODING_TABLE(ibm862)
-PRISM_ENCODING_TABLE(ibm863)
-PRISM_ENCODING_TABLE(ibm864)
-PRISM_ENCODING_TABLE(ibm865)
-PRISM_ENCODING_TABLE(ibm866)
-PRISM_ENCODING_TABLE(ibm869)
-PRISM_ENCODING_TABLE(iso_8859_1)
-PRISM_ENCODING_TABLE(iso_8859_2)
-PRISM_ENCODING_TABLE(iso_8859_3)
-PRISM_ENCODING_TABLE(iso_8859_4)
-PRISM_ENCODING_TABLE(iso_8859_5)
-PRISM_ENCODING_TABLE(iso_8859_6)
-PRISM_ENCODING_TABLE(iso_8859_7)
-PRISM_ENCODING_TABLE(iso_8859_8)
-PRISM_ENCODING_TABLE(iso_8859_9)
-PRISM_ENCODING_TABLE(iso_8859_10)
-PRISM_ENCODING_TABLE(iso_8859_11)
-PRISM_ENCODING_TABLE(iso_8859_13)
-PRISM_ENCODING_TABLE(iso_8859_14)
-PRISM_ENCODING_TABLE(iso_8859_15)
-PRISM_ENCODING_TABLE(iso_8859_16)
-PRISM_ENCODING_TABLE(koi8_r)
-PRISM_ENCODING_TABLE(koi8_u)
-PRISM_ENCODING_TABLE(mac_cent_euro)
-PRISM_ENCODING_TABLE(mac_croatian)
-PRISM_ENCODING_TABLE(mac_cyrillic)
-PRISM_ENCODING_TABLE(mac_greek)
-PRISM_ENCODING_TABLE(mac_iceland)
-PRISM_ENCODING_TABLE(mac_roman)
-PRISM_ENCODING_TABLE(mac_romania)
-PRISM_ENCODING_TABLE(mac_thai)
-PRISM_ENCODING_TABLE(mac_turkish)
-PRISM_ENCODING_TABLE(mac_ukraine)
-PRISM_ENCODING_TABLE(tis_620)
-PRISM_ENCODING_TABLE(windows_1250)
-PRISM_ENCODING_TABLE(windows_1251)
-PRISM_ENCODING_TABLE(windows_1252)
-PRISM_ENCODING_TABLE(windows_1253)
-PRISM_ENCODING_TABLE(windows_1254)
-PRISM_ENCODING_TABLE(windows_1255)
-PRISM_ENCODING_TABLE(windows_1256)
-PRISM_ENCODING_TABLE(windows_1257)
-PRISM_ENCODING_TABLE(windows_1258)
-PRISM_ENCODING_TABLE(windows_874)
-
-#undef PRISM_ENCODING_TABLE
-#endif
-
-/**
- * Returns the size of the next character in the ASCII encoding. This basically
- * means that if the top bit is not set, the character is 1 byte long.
- */
-static size_t
-pm_encoding_ascii_char_width(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) {
- return *b < 0x80 ? 1 : 0;
-}
-
-/**
- * Return the size of the next character in the ASCII encoding if it is an
- * alphabetical character.
- */
-static size_t
-pm_encoding_ascii_alpha_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) {
- return (pm_encoding_ascii_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT);
-}
-
-/**
- * Certain encodings are equivalent to ASCII below 0x80, so it works for our
- * purposes to have a function here that first checks the bounds and then falls
- * back to checking the ASCII lookup table.
- */
-static size_t
-pm_encoding_ascii_alpha_char_7bit(const uint8_t *b, ptrdiff_t n) {
- return (*b < 0x80) ? pm_encoding_ascii_alpha_char(b, n) : 0;
-}
-
-/**
- * Return the size of the next character in the ASCII encoding if it is an
- * alphanumeric character.
- */
-static size_t
-pm_encoding_ascii_alnum_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) {
- return (pm_encoding_ascii_table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT) ? 1 : 0;
-}
-
-/**
- * Certain encodings are equivalent to ASCII below 0x80, so it works for our
- * purposes to have a function here that first checks the bounds and then falls
- * back to checking the ASCII lookup table.
- */
-static size_t
-pm_encoding_ascii_alnum_char_7bit(const uint8_t *b, ptrdiff_t n) {
- return (*b < 0x80) ? pm_encoding_ascii_alnum_char(b, n) : 0;
-}
-
-/**
- * Return true if the next character in the ASCII encoding if it is an uppercase
- * character.
- */
-static bool
-pm_encoding_ascii_isupper_char(const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) {
- return (pm_encoding_ascii_table[*b] & PRISM_ENCODING_UPPERCASE_BIT);
-}
-
-/**
- * For a lot of encodings the default is that they are a single byte long no
- * matter what the codepoint, so this function is shared between them.
- */
-static size_t
-pm_encoding_single_char_width(PRISM_ATTRIBUTE_UNUSED const uint8_t *b, PRISM_ATTRIBUTE_UNUSED ptrdiff_t n) {
- return 1;
-}
-
-/**
- * Returns the size of the next character in the EUC-JP encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_euc_jp_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the single byte characters.
- if (*b < 0x80) {
- return 1;
- }
-
- // These are the double byte characters.
- if ((n > 1) && ((b[0] == 0x8E) || (b[0] >= 0xA1 && b[0] <= 0xFE)) && (b[1] >= 0xA1 && b[1] <= 0xFE)) {
- return 2;
- }
-
- // These are the triple byte characters.
- if ((n > 2) && (b[0] == 0x8F) && (b[1] >= 0xA1 && b[2] <= 0xFE) && (b[2] >= 0xA1 && b[2] <= 0xFE)) {
- return 3;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the EUC-JP encoding if it is an
- * uppercase character.
- */
-static bool
-pm_encoding_euc_jp_isupper_char(const uint8_t *b, ptrdiff_t n) {
- size_t width = pm_encoding_euc_jp_char_width(b, n);
-
- if (width == 1) {
- return pm_encoding_ascii_isupper_char(b, n);
- } else if (width == 2) {
- return (
- (b[0] == 0xA3 && b[1] >= 0xC1 && b[1] <= 0xDA) ||
- (b[0] == 0xA6 && b[1] >= 0xA1 && b[1] <= 0xB8) ||
- (b[0] == 0xA7 && b[1] >= 0xA1 && b[1] <= 0xC1)
- );
- } else {
- return false;
- }
-}
-
-/**
- * Returns the size of the next character in the Shift_JIS encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_shift_jis_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the single byte characters.
- if (b[0] < 0x80 || (b[0] >= 0xA1 && b[0] <= 0xDF)) {
- return 1;
- }
-
- // These are the double byte characters.
- if ((n > 1) && ((b[0] >= 0x81 && b[0] <= 0x9F) || (b[0] >= 0xE0 && b[0] <= 0xFC)) && (b[1] >= 0x40 && b[1] <= 0xFC && b[1] != 0x7F)) {
- return 2;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the Shift_JIS encoding if it is an
- * alphanumeric character.
- */
-static size_t
-pm_encoding_shift_jis_alnum_char(const uint8_t *b, ptrdiff_t n) {
- size_t width = pm_encoding_shift_jis_char_width(b, n);
- return width == 1 ? ((b[0] >= 0x80) || pm_encoding_ascii_alnum_char(b, n)) : width;
-}
-
-/**
- * Returns the size of the next character in the Shift_JIS encoding if it is an
- * alphabetical character.
- */
-static size_t
-pm_encoding_shift_jis_alpha_char(const uint8_t *b, ptrdiff_t n) {
- size_t width = pm_encoding_shift_jis_char_width(b, n);
- return width == 1 ? ((b[0] >= 0x80) || pm_encoding_ascii_alpha_char(b, n)) : width;
-}
-
-/**
- * Returns the size of the next character in the Shift_JIS encoding if it is an
- * uppercase character.
- */
-static bool
-pm_encoding_shift_jis_isupper_char(const uint8_t *b, ptrdiff_t n) {
- size_t width = pm_encoding_shift_jis_char_width(b, n);
-
- if (width == 1) {
- return pm_encoding_ascii_isupper_char(b, n);
- } else if (width == 2) {
- return (
- ((b[0] == 0x82) && (b[1] >= 0x60 && b[1] <= 0x79)) ||
- ((b[0] == 0x83) && (b[1] >= 0x9F && b[1] <= 0xB6)) ||
- ((b[0] == 0x84) && (b[1] >= 0x40 && b[1] <= 0x60))
- );
- } else {
- return width;
- }
-}
-
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
-
-/**
- * Certain encodings are equivalent to ASCII below 0x80, so it works for our
- * purposes to have a function here that first checks the bounds and then falls
- * back to checking the ASCII lookup table.
- */
-static bool
-pm_encoding_ascii_isupper_char_7bit(const uint8_t *b, ptrdiff_t n) {
- return (*b < 0x80) && pm_encoding_ascii_isupper_char(b, n);
-}
-
-/**
- * Returns the size of the next character in the Big5 encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_big5_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the single byte characters.
- if (*b < 0x80) {
- return 1;
- }
-
- // These are the double byte characters.
- if ((n > 1) && (b[0] >= 0xA1 && b[0] <= 0xFE) && ((b[1] >= 0x40 && b[1] <= 0x7E) || (b[1] >= 0xA1 && b[1] <= 0xFE))) {
- return 2;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the CP949 encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_cp949_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the single byte characters
- if (*b <= 0x80) {
- return 1;
- }
-
- // These are the double byte characters
- if ((n > 1) && (b[0] >= 0x81 && b[0] <= 0xFE) && ((b[1] >= 0x41 && b[1] <= 0x5A) || (b[1] >= 0x61 && b[1] <= 0x7A) || (b[1] >= 0x81 && b[1] <= 0xFE))) {
- return 2;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the Emacs MULE encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_emacs_mule_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the 1 byte characters.
- if (*b < 0x80) {
- return 1;
- }
-
- // These are the 2 byte characters.
- if ((n > 1) && (b[0] >= 0x81 && b[0] <= 0x8F) && (b[1] >= 0xA0)) {
- return 2;
- }
-
- // These are the 3 byte characters.
- if (
- (n > 2) &&
- (
- ((b[0] >= 0x90 && b[0] <= 0x99) && (b[1] >= 0xA0)) ||
- ((b[0] == 0x9A || b[0] == 0x9B) && (b[1] >= 0xE0 && b[1] <= 0xEF))
- ) &&
- (b[2] >= 0xA0)
- ) {
- return 3;
- }
-
- // These are the 4 byte characters.
- if (
- (n > 3) &&
- (
- ((b[0] == 0x9C) && (b[1] >= 0xF0) && (b[1] <= 0xF4)) ||
- ((b[0] == 0x9D) && (b[1] >= 0xF5) && (b[1] <= 0xFE))
- ) &&
- (b[2] >= 0xA0) && (b[3] >= 0xA0)
- ) {
- return 4;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the EUC-KR encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_euc_kr_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the single byte characters.
- if (*b < 0x80) {
- return 1;
- }
-
- // These are the double byte characters.
- if ((n > 1) && (b[0] >= 0xA1 && b[0] <= 0xFE) && (b[1] >= 0xA1 && b[1] <= 0xFE)) {
- return 2;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the EUC-TW encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_euc_tw_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the single byte characters.
- if (*b < 0x80) {
- return 1;
- }
-
- // These are the double byte characters.
- if ((n > 1) && (b[0] >= 0xA1) && (b[0] <= 0xFE) && (b[1] >= 0xA1) && (b[1] <= 0xFE)) {
- return 2;
- }
-
- // These are the quadruple byte characters.
- if ((n > 3) && (b[0] == 0x8E) && (b[1] >= 0xA1) && (b[1] <= 0xB0) && (b[2] >= 0xA1) && (b[2] <= 0xFE) && (b[3] >= 0xA1) && (b[3] <= 0xFE)) {
- return 4;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the GB18030 encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_gb18030_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the 1 byte characters.
- if (*b < 0x80) {
- return 1;
- }
-
- // These are the 2 byte characters.
- if ((n > 1) && (b[0] >= 0x81 && b[0] <= 0xFE) && (b[1] >= 0x40 && b[1] <= 0xFE && b[1] != 0x7F)) {
- return 2;
- }
-
- // These are the 4 byte characters.
- if ((n > 3) && ((b[0] >= 0x81 && b[0] <= 0xFE) && (b[1] >= 0x30 && b[1] <= 0x39) && (b[2] >= 0x81 && b[2] <= 0xFE) && (b[3] >= 0x30 && b[3] <= 0x39))) {
- return 4;
- }
-
- return 0;
-}
-
-/**
- * Returns the size of the next character in the GBK encoding, or 0 if a
- * character cannot be decoded from the given bytes.
- */
-static size_t
-pm_encoding_gbk_char_width(const uint8_t *b, ptrdiff_t n) {
- // These are the single byte characters.
- if (*b <= 0x80) {
- return 1;
- }
-
- // These are the double byte characters.
- if (
- (n > 1) &&
- (
- ((b[0] >= 0xA1 && b[0] <= 0xA9) && (b[1] >= 0xA1 && b[1] <= 0xFE)) || // GBK/1
- ((b[0] >= 0xB0 && b[0] <= 0xF7) && (b[1] >= 0xA1 && b[1] <= 0xFE)) || // GBK/2
- ((b[0] >= 0x81 && b[0] <= 0xA0) && (b[1] >= 0x40 && b[1] <= 0xFE) && (b[1] != 0x7F)) || // GBK/3
- ((b[0] >= 0xAA && b[0] <= 0xFE) && (b[1] >= 0x40 && b[1] <= 0xA0) && (b[1] != 0x7F)) || // GBK/4
- ((b[0] >= 0xA8 && b[0] <= 0xA9) && (b[1] >= 0x40 && b[1] <= 0xA0) && (b[1] != 0x7F)) || // GBK/5
- ((b[0] >= 0xAA && b[0] <= 0xAF) && (b[1] >= 0xA1 && b[1] <= 0xFE)) || // user-defined 1
- ((b[0] >= 0xF8 && b[0] <= 0xFE) && (b[1] >= 0xA1 && b[1] <= 0xFE)) || // user-defined 2
- ((b[0] >= 0xA1 && b[0] <= 0xA7) && (b[1] >= 0x40 && b[1] <= 0xA0) && (b[1] != 0x7F)) // user-defined 3
- )
- ) {
- return 2;
- }
-
- return 0;
-}
-
-#endif
-
-/**
- * This is the table of all of the encodings that prism supports.
- */
-const pm_encoding_t pm_encodings[] = {
- [PM_ENCODING_UTF_8] = {
- .name = "UTF-8",
- .char_width = pm_encoding_utf_8_char_width,
- .alnum_char = pm_encoding_utf_8_alnum_char,
- .alpha_char = pm_encoding_utf_8_alpha_char,
- .isupper_char = pm_encoding_utf_8_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_US_ASCII] = {
- .name = "US-ASCII",
- .char_width = pm_encoding_ascii_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char,
- .alpha_char = pm_encoding_ascii_alpha_char,
- .isupper_char = pm_encoding_ascii_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ASCII_8BIT] = {
- .name = "ASCII-8BIT",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char,
- .alpha_char = pm_encoding_ascii_alpha_char,
- .isupper_char = pm_encoding_ascii_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_EUC_JP] = {
- .name = "EUC-JP",
- .char_width = pm_encoding_euc_jp_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_euc_jp_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_WINDOWS_31J] = {
- .name = "Windows-31J",
- .char_width = pm_encoding_shift_jis_char_width,
- .alnum_char = pm_encoding_shift_jis_alnum_char,
- .alpha_char = pm_encoding_shift_jis_alpha_char,
- .isupper_char = pm_encoding_shift_jis_isupper_char,
- .multibyte = true
- },
-
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- [PM_ENCODING_BIG5] = {
- .name = "Big5",
- .char_width = pm_encoding_big5_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_BIG5_HKSCS] = {
- .name = "Big5-HKSCS",
- .char_width = pm_encoding_big5_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_BIG5_UAO] = {
- .name = "Big5-UAO",
- .char_width = pm_encoding_big5_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_CESU_8] = {
- .name = "CESU-8",
- .char_width = pm_encoding_cesu_8_char_width,
- .alnum_char = pm_encoding_cesu_8_alnum_char,
- .alpha_char = pm_encoding_cesu_8_alpha_char,
- .isupper_char = pm_encoding_cesu_8_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_CP51932] = {
- .name = "CP51932",
- .char_width = pm_encoding_euc_jp_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_euc_jp_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_CP850] = {
- .name = "CP850",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_cp850_alnum_char,
- .alpha_char = pm_encoding_cp850_alpha_char,
- .isupper_char = pm_encoding_cp850_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_CP852] = {
- .name = "CP852",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_cp852_alnum_char,
- .alpha_char = pm_encoding_cp852_alpha_char,
- .isupper_char = pm_encoding_cp852_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_CP855] = {
- .name = "CP855",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_cp855_alnum_char,
- .alpha_char = pm_encoding_cp855_alpha_char,
- .isupper_char = pm_encoding_cp855_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_CP949] = {
- .name = "CP949",
- .char_width = pm_encoding_cp949_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_CP950] = {
- .name = "CP950",
- .char_width = pm_encoding_big5_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_CP951] = {
- .name = "CP951",
- .char_width = pm_encoding_big5_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_EMACS_MULE] = {
- .name = "Emacs-Mule",
- .char_width = pm_encoding_emacs_mule_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_EUC_JP_MS] = {
- .name = "eucJP-ms",
- .char_width = pm_encoding_euc_jp_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_euc_jp_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_EUC_JIS_2004] = {
- .name = "EUC-JIS-2004",
- .char_width = pm_encoding_euc_jp_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_euc_jp_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_EUC_KR] = {
- .name = "EUC-KR",
- .char_width = pm_encoding_euc_kr_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_EUC_TW] = {
- .name = "EUC-TW",
- .char_width = pm_encoding_euc_tw_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_GB12345] = {
- .name = "GB12345",
- .char_width = pm_encoding_euc_kr_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_GB18030] = {
- .name = "GB18030",
- .char_width = pm_encoding_gb18030_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_GB1988] = {
- .name = "GB1988",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_gb1988_alnum_char,
- .alpha_char = pm_encoding_gb1988_alpha_char,
- .isupper_char = pm_encoding_gb1988_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_GB2312] = {
- .name = "GB2312",
- .char_width = pm_encoding_euc_kr_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_GBK] = {
- .name = "GBK",
- .char_width = pm_encoding_gbk_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_IBM437] = {
- .name = "IBM437",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm437_alnum_char,
- .alpha_char = pm_encoding_ibm437_alpha_char,
- .isupper_char = pm_encoding_ibm437_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM720] = {
- .name = "IBM720",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm720_alnum_char,
- .alpha_char = pm_encoding_ibm720_alpha_char,
- .isupper_char = pm_encoding_ibm720_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM737] = {
- .name = "IBM737",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm737_alnum_char,
- .alpha_char = pm_encoding_ibm737_alpha_char,
- .isupper_char = pm_encoding_ibm737_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM775] = {
- .name = "IBM775",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm775_alnum_char,
- .alpha_char = pm_encoding_ibm775_alpha_char,
- .isupper_char = pm_encoding_ibm775_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM852] = {
- .name = "IBM852",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm852_alnum_char,
- .alpha_char = pm_encoding_ibm852_alpha_char,
- .isupper_char = pm_encoding_ibm852_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM855] = {
- .name = "IBM855",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm855_alnum_char,
- .alpha_char = pm_encoding_ibm855_alpha_char,
- .isupper_char = pm_encoding_ibm855_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM857] = {
- .name = "IBM857",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm857_alnum_char,
- .alpha_char = pm_encoding_ibm857_alpha_char,
- .isupper_char = pm_encoding_ibm857_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM860] = {
- .name = "IBM860",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm860_alnum_char,
- .alpha_char = pm_encoding_ibm860_alpha_char,
- .isupper_char = pm_encoding_ibm860_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM861] = {
- .name = "IBM861",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm861_alnum_char,
- .alpha_char = pm_encoding_ibm861_alpha_char,
- .isupper_char = pm_encoding_ibm861_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM862] = {
- .name = "IBM862",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm862_alnum_char,
- .alpha_char = pm_encoding_ibm862_alpha_char,
- .isupper_char = pm_encoding_ibm862_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM863] = {
- .name = "IBM863",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm863_alnum_char,
- .alpha_char = pm_encoding_ibm863_alpha_char,
- .isupper_char = pm_encoding_ibm863_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM864] = {
- .name = "IBM864",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm864_alnum_char,
- .alpha_char = pm_encoding_ibm864_alpha_char,
- .isupper_char = pm_encoding_ibm864_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM865] = {
- .name = "IBM865",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm865_alnum_char,
- .alpha_char = pm_encoding_ibm865_alpha_char,
- .isupper_char = pm_encoding_ibm865_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM866] = {
- .name = "IBM866",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm866_alnum_char,
- .alpha_char = pm_encoding_ibm866_alpha_char,
- .isupper_char = pm_encoding_ibm866_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_IBM869] = {
- .name = "IBM869",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_ibm869_alnum_char,
- .alpha_char = pm_encoding_ibm869_alpha_char,
- .isupper_char = pm_encoding_ibm869_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_1] = {
- .name = "ISO-8859-1",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_1_alnum_char,
- .alpha_char = pm_encoding_iso_8859_1_alpha_char,
- .isupper_char = pm_encoding_iso_8859_1_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_2] = {
- .name = "ISO-8859-2",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_2_alnum_char,
- .alpha_char = pm_encoding_iso_8859_2_alpha_char,
- .isupper_char = pm_encoding_iso_8859_2_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_3] = {
- .name = "ISO-8859-3",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_3_alnum_char,
- .alpha_char = pm_encoding_iso_8859_3_alpha_char,
- .isupper_char = pm_encoding_iso_8859_3_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_4] = {
- .name = "ISO-8859-4",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_4_alnum_char,
- .alpha_char = pm_encoding_iso_8859_4_alpha_char,
- .isupper_char = pm_encoding_iso_8859_4_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_5] = {
- .name = "ISO-8859-5",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_5_alnum_char,
- .alpha_char = pm_encoding_iso_8859_5_alpha_char,
- .isupper_char = pm_encoding_iso_8859_5_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_6] = {
- .name = "ISO-8859-6",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_6_alnum_char,
- .alpha_char = pm_encoding_iso_8859_6_alpha_char,
- .isupper_char = pm_encoding_iso_8859_6_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_7] = {
- .name = "ISO-8859-7",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_7_alnum_char,
- .alpha_char = pm_encoding_iso_8859_7_alpha_char,
- .isupper_char = pm_encoding_iso_8859_7_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_8] = {
- .name = "ISO-8859-8",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_8_alnum_char,
- .alpha_char = pm_encoding_iso_8859_8_alpha_char,
- .isupper_char = pm_encoding_iso_8859_8_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_9] = {
- .name = "ISO-8859-9",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_9_alnum_char,
- .alpha_char = pm_encoding_iso_8859_9_alpha_char,
- .isupper_char = pm_encoding_iso_8859_9_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_10] = {
- .name = "ISO-8859-10",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_10_alnum_char,
- .alpha_char = pm_encoding_iso_8859_10_alpha_char,
- .isupper_char = pm_encoding_iso_8859_10_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_11] = {
- .name = "ISO-8859-11",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_11_alnum_char,
- .alpha_char = pm_encoding_iso_8859_11_alpha_char,
- .isupper_char = pm_encoding_iso_8859_11_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_13] = {
- .name = "ISO-8859-13",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_13_alnum_char,
- .alpha_char = pm_encoding_iso_8859_13_alpha_char,
- .isupper_char = pm_encoding_iso_8859_13_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_14] = {
- .name = "ISO-8859-14",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_14_alnum_char,
- .alpha_char = pm_encoding_iso_8859_14_alpha_char,
- .isupper_char = pm_encoding_iso_8859_14_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_15] = {
- .name = "ISO-8859-15",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_15_alnum_char,
- .alpha_char = pm_encoding_iso_8859_15_alpha_char,
- .isupper_char = pm_encoding_iso_8859_15_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_ISO_8859_16] = {
- .name = "ISO-8859-16",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_iso_8859_16_alnum_char,
- .alpha_char = pm_encoding_iso_8859_16_alpha_char,
- .isupper_char = pm_encoding_iso_8859_16_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_KOI8_R] = {
- .name = "KOI8-R",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_koi8_r_alnum_char,
- .alpha_char = pm_encoding_koi8_r_alpha_char,
- .isupper_char = pm_encoding_koi8_r_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_KOI8_U] = {
- .name = "KOI8-U",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_koi8_u_alnum_char,
- .alpha_char = pm_encoding_koi8_u_alpha_char,
- .isupper_char = pm_encoding_koi8_u_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_CENT_EURO] = {
- .name = "macCentEuro",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_cent_euro_alnum_char,
- .alpha_char = pm_encoding_mac_cent_euro_alpha_char,
- .isupper_char = pm_encoding_mac_cent_euro_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_CROATIAN] = {
- .name = "macCroatian",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_croatian_alnum_char,
- .alpha_char = pm_encoding_mac_croatian_alpha_char,
- .isupper_char = pm_encoding_mac_croatian_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_CYRILLIC] = {
- .name = "macCyrillic",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_cyrillic_alnum_char,
- .alpha_char = pm_encoding_mac_cyrillic_alpha_char,
- .isupper_char = pm_encoding_mac_cyrillic_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_GREEK] = {
- .name = "macGreek",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_greek_alnum_char,
- .alpha_char = pm_encoding_mac_greek_alpha_char,
- .isupper_char = pm_encoding_mac_greek_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_ICELAND] = {
- .name = "macIceland",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_iceland_alnum_char,
- .alpha_char = pm_encoding_mac_iceland_alpha_char,
- .isupper_char = pm_encoding_mac_iceland_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_JAPANESE] = {
- .name = "MacJapanese",
- .char_width = pm_encoding_shift_jis_char_width,
- .alnum_char = pm_encoding_shift_jis_alnum_char,
- .alpha_char = pm_encoding_shift_jis_alpha_char,
- .isupper_char = pm_encoding_shift_jis_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_MAC_ROMAN] = {
- .name = "macRoman",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_roman_alnum_char,
- .alpha_char = pm_encoding_mac_roman_alpha_char,
- .isupper_char = pm_encoding_mac_roman_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_ROMANIA] = {
- .name = "macRomania",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_romania_alnum_char,
- .alpha_char = pm_encoding_mac_romania_alpha_char,
- .isupper_char = pm_encoding_mac_romania_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_THAI] = {
- .name = "macThai",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_thai_alnum_char,
- .alpha_char = pm_encoding_mac_thai_alpha_char,
- .isupper_char = pm_encoding_mac_thai_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_TURKISH] = {
- .name = "macTurkish",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_turkish_alnum_char,
- .alpha_char = pm_encoding_mac_turkish_alpha_char,
- .isupper_char = pm_encoding_mac_turkish_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_MAC_UKRAINE] = {
- .name = "macUkraine",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_mac_ukraine_alnum_char,
- .alpha_char = pm_encoding_mac_ukraine_alpha_char,
- .isupper_char = pm_encoding_mac_ukraine_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_SHIFT_JIS] = {
- .name = "Shift_JIS",
- .char_width = pm_encoding_shift_jis_char_width,
- .alnum_char = pm_encoding_shift_jis_alnum_char,
- .alpha_char = pm_encoding_shift_jis_alpha_char,
- .isupper_char = pm_encoding_shift_jis_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_SJIS_DOCOMO] = {
- .name = "SJIS-DoCoMo",
- .char_width = pm_encoding_shift_jis_char_width,
- .alnum_char = pm_encoding_shift_jis_alnum_char,
- .alpha_char = pm_encoding_shift_jis_alpha_char,
- .isupper_char = pm_encoding_shift_jis_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_SJIS_KDDI] = {
- .name = "SJIS-KDDI",
- .char_width = pm_encoding_shift_jis_char_width,
- .alnum_char = pm_encoding_shift_jis_alnum_char,
- .alpha_char = pm_encoding_shift_jis_alpha_char,
- .isupper_char = pm_encoding_shift_jis_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_SJIS_SOFTBANK] = {
- .name = "SJIS-SoftBank",
- .char_width = pm_encoding_shift_jis_char_width,
- .alnum_char = pm_encoding_shift_jis_alnum_char,
- .alpha_char = pm_encoding_shift_jis_alpha_char,
- .isupper_char = pm_encoding_shift_jis_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_STATELESS_ISO_2022_JP] = {
- .name = "stateless-ISO-2022-JP",
- .char_width = pm_encoding_emacs_mule_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_STATELESS_ISO_2022_JP_KDDI] = {
- .name = "stateless-ISO-2022-JP-KDDI",
- .char_width = pm_encoding_emacs_mule_char_width,
- .alnum_char = pm_encoding_ascii_alnum_char_7bit,
- .alpha_char = pm_encoding_ascii_alpha_char_7bit,
- .isupper_char = pm_encoding_ascii_isupper_char_7bit,
- .multibyte = true
- },
- [PM_ENCODING_TIS_620] = {
- .name = "TIS-620",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_tis_620_alnum_char,
- .alpha_char = pm_encoding_tis_620_alpha_char,
- .isupper_char = pm_encoding_tis_620_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_UTF8_MAC] = {
- .name = "UTF8-MAC",
- .char_width = pm_encoding_utf_8_char_width,
- .alnum_char = pm_encoding_utf_8_alnum_char,
- .alpha_char = pm_encoding_utf_8_alpha_char,
- .isupper_char = pm_encoding_utf_8_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_UTF8_DOCOMO] = {
- .name = "UTF8-DoCoMo",
- .char_width = pm_encoding_utf_8_char_width,
- .alnum_char = pm_encoding_utf_8_alnum_char,
- .alpha_char = pm_encoding_utf_8_alpha_char,
- .isupper_char = pm_encoding_utf_8_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_UTF8_KDDI] = {
- .name = "UTF8-KDDI",
- .char_width = pm_encoding_utf_8_char_width,
- .alnum_char = pm_encoding_utf_8_alnum_char,
- .alpha_char = pm_encoding_utf_8_alpha_char,
- .isupper_char = pm_encoding_utf_8_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_UTF8_SOFTBANK] = {
- .name = "UTF8-SoftBank",
- .char_width = pm_encoding_utf_8_char_width,
- .alnum_char = pm_encoding_utf_8_alnum_char,
- .alpha_char = pm_encoding_utf_8_alpha_char,
- .isupper_char = pm_encoding_utf_8_isupper_char,
- .multibyte = true
- },
- [PM_ENCODING_WINDOWS_1250] = {
- .name = "Windows-1250",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1250_alnum_char,
- .alpha_char = pm_encoding_windows_1250_alpha_char,
- .isupper_char = pm_encoding_windows_1250_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_1251] = {
- .name = "Windows-1251",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1251_alnum_char,
- .alpha_char = pm_encoding_windows_1251_alpha_char,
- .isupper_char = pm_encoding_windows_1251_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_1252] = {
- .name = "Windows-1252",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1252_alnum_char,
- .alpha_char = pm_encoding_windows_1252_alpha_char,
- .isupper_char = pm_encoding_windows_1252_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_1253] = {
- .name = "Windows-1253",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1253_alnum_char,
- .alpha_char = pm_encoding_windows_1253_alpha_char,
- .isupper_char = pm_encoding_windows_1253_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_1254] = {
- .name = "Windows-1254",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1254_alnum_char,
- .alpha_char = pm_encoding_windows_1254_alpha_char,
- .isupper_char = pm_encoding_windows_1254_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_1255] = {
- .name = "Windows-1255",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1255_alnum_char,
- .alpha_char = pm_encoding_windows_1255_alpha_char,
- .isupper_char = pm_encoding_windows_1255_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_1256] = {
- .name = "Windows-1256",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1256_alnum_char,
- .alpha_char = pm_encoding_windows_1256_alpha_char,
- .isupper_char = pm_encoding_windows_1256_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_1257] = {
- .name = "Windows-1257",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1257_alnum_char,
- .alpha_char = pm_encoding_windows_1257_alpha_char,
- .isupper_char = pm_encoding_windows_1257_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_1258] = {
- .name = "Windows-1258",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_1258_alnum_char,
- .alpha_char = pm_encoding_windows_1258_alpha_char,
- .isupper_char = pm_encoding_windows_1258_isupper_char,
- .multibyte = false
- },
- [PM_ENCODING_WINDOWS_874] = {
- .name = "Windows-874",
- .char_width = pm_encoding_single_char_width,
- .alnum_char = pm_encoding_windows_874_alnum_char,
- .alpha_char = pm_encoding_windows_874_alpha_char,
- .isupper_char = pm_encoding_windows_874_isupper_char,
- .multibyte = false
- }
-#endif
-};
-
-/**
- * Parse the given name of an encoding and return a pointer to the corresponding
- * encoding struct if one can be found, otherwise return NULL.
- */
-const pm_encoding_t *
-pm_encoding_find(const uint8_t *start, const uint8_t *end) {
- size_t width = (size_t) (end - start);
-
- // First, we're going to check for UTF-8. This is the most common encoding.
- // UTF-8 can contain extra information at the end about the platform it is
- // encoded on, such as UTF-8-MAC or UTF-8-UNIX. We'll ignore those suffixes.
- if ((start + 5 <= end) && (pm_strncasecmp(start, (const uint8_t *) "UTF-8", 5) == 0)) {
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- // We need to explicitly handle UTF-8-HFS, as that one needs to switch
- // over to being UTF8-MAC.
- if (width == 9 && (pm_strncasecmp(start + 5, (const uint8_t *) "-HFS", 4) == 0)) {
- return &pm_encodings[PM_ENCODING_UTF8_MAC];
- }
-#endif
-
- // Otherwise we'll return the default UTF-8 encoding.
- return PM_ENCODING_UTF_8_ENTRY;
- }
-
- // Next, we're going to loop through each of the encodings that we handle
- // explicitly. If we found one that we understand, we'll use that value.
-#define ENCODING1(name, encoding) if (width == sizeof(name) - 1 && pm_strncasecmp(start, (const uint8_t *) name, width) == 0) return &pm_encodings[encoding];
-#define ENCODING2(name1, name2, encoding) ENCODING1(name1, encoding) ENCODING1(name2, encoding)
-
- if (width >= 3) {
- switch (*start) {
- case 'A': case 'a':
- ENCODING1("ASCII", PM_ENCODING_US_ASCII);
- ENCODING1("ASCII-8BIT", PM_ENCODING_ASCII_8BIT);
- ENCODING1("ANSI_X3.4-1968", PM_ENCODING_US_ASCII);
- break;
- case 'B': case 'b':
- ENCODING1("BINARY", PM_ENCODING_ASCII_8BIT);
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- ENCODING1("Big5", PM_ENCODING_BIG5);
- ENCODING2("Big5-HKSCS", "Big5-HKSCS:2008", PM_ENCODING_BIG5_HKSCS);
- ENCODING1("Big5-UAO", PM_ENCODING_BIG5_UAO);
-#endif
- break;
- case 'C': case 'c':
- ENCODING1("CP65001", PM_ENCODING_UTF_8);
- ENCODING2("CP932", "csWindows31J", PM_ENCODING_WINDOWS_31J);
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- ENCODING1("CESU-8", PM_ENCODING_CESU_8);
- ENCODING1("CP437", PM_ENCODING_IBM437);
- ENCODING1("CP720", PM_ENCODING_IBM720);
- ENCODING1("CP737", PM_ENCODING_IBM737);
- ENCODING1("CP775", PM_ENCODING_IBM775);
- ENCODING1("CP850", PM_ENCODING_CP850);
- ENCODING1("CP852", PM_ENCODING_CP852);
- ENCODING1("CP855", PM_ENCODING_CP855);
- ENCODING1("CP857", PM_ENCODING_IBM857);
- ENCODING1("CP860", PM_ENCODING_IBM860);
- ENCODING1("CP861", PM_ENCODING_IBM861);
- ENCODING1("CP862", PM_ENCODING_IBM862);
- ENCODING1("CP864", PM_ENCODING_IBM864);
- ENCODING1("CP865", PM_ENCODING_IBM865);
- ENCODING1("CP866", PM_ENCODING_IBM866);
- ENCODING1("CP869", PM_ENCODING_IBM869);
- ENCODING1("CP874", PM_ENCODING_WINDOWS_874);
- ENCODING1("CP878", PM_ENCODING_KOI8_R);
- ENCODING1("CP863", PM_ENCODING_IBM863);
- ENCODING1("CP936", PM_ENCODING_GBK);
- ENCODING1("CP949", PM_ENCODING_CP949);
- ENCODING1("CP950", PM_ENCODING_CP950);
- ENCODING1("CP951", PM_ENCODING_CP951);
- ENCODING1("CP1250", PM_ENCODING_WINDOWS_1250);
- ENCODING1("CP1251", PM_ENCODING_WINDOWS_1251);
- ENCODING1("CP1252", PM_ENCODING_WINDOWS_1252);
- ENCODING1("CP1253", PM_ENCODING_WINDOWS_1253);
- ENCODING1("CP1254", PM_ENCODING_WINDOWS_1254);
- ENCODING1("CP1255", PM_ENCODING_WINDOWS_1255);
- ENCODING1("CP1256", PM_ENCODING_WINDOWS_1256);
- ENCODING1("CP1257", PM_ENCODING_WINDOWS_1257);
- ENCODING1("CP1258", PM_ENCODING_WINDOWS_1258);
- ENCODING1("CP51932", PM_ENCODING_CP51932);
-#endif
- break;
- case 'E': case 'e':
- ENCODING2("EUC-JP", "eucJP", PM_ENCODING_EUC_JP);
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- ENCODING2("eucJP-ms", "euc-jp-ms", PM_ENCODING_EUC_JP_MS);
- ENCODING2("EUC-JIS-2004", "EUC-JISX0213", PM_ENCODING_EUC_JIS_2004);
- ENCODING2("EUC-KR", "eucKR", PM_ENCODING_EUC_KR);
- ENCODING2("EUC-CN", "eucCN", PM_ENCODING_GB2312);
- ENCODING2("EUC-TW", "eucTW", PM_ENCODING_EUC_TW);
- ENCODING1("Emacs-Mule", PM_ENCODING_EMACS_MULE);
-#endif
- break;
- case 'G': case 'g':
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- ENCODING1("GBK", PM_ENCODING_GBK);
- ENCODING1("GB12345", PM_ENCODING_GB12345);
- ENCODING1("GB18030", PM_ENCODING_GB18030);
- ENCODING1("GB1988", PM_ENCODING_GB1988);
- ENCODING1("GB2312", PM_ENCODING_GB2312);
-#endif
- break;
- case 'I': case 'i':
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- ENCODING1("IBM437", PM_ENCODING_IBM437);
- ENCODING1("IBM720", PM_ENCODING_IBM720);
- ENCODING1("IBM737", PM_ENCODING_IBM737);
- ENCODING1("IBM775", PM_ENCODING_IBM775);
- ENCODING1("IBM850", PM_ENCODING_CP850);
- ENCODING1("IBM852", PM_ENCODING_IBM852);
- ENCODING1("IBM855", PM_ENCODING_IBM855);
- ENCODING1("IBM857", PM_ENCODING_IBM857);
- ENCODING1("IBM860", PM_ENCODING_IBM860);
- ENCODING1("IBM861", PM_ENCODING_IBM861);
- ENCODING1("IBM862", PM_ENCODING_IBM862);
- ENCODING1("IBM863", PM_ENCODING_IBM863);
- ENCODING1("IBM864", PM_ENCODING_IBM864);
- ENCODING1("IBM865", PM_ENCODING_IBM865);
- ENCODING1("IBM866", PM_ENCODING_IBM866);
- ENCODING1("IBM869", PM_ENCODING_IBM869);
- ENCODING2("ISO-8859-1", "ISO8859-1", PM_ENCODING_ISO_8859_1);
- ENCODING2("ISO-8859-2", "ISO8859-2", PM_ENCODING_ISO_8859_2);
- ENCODING2("ISO-8859-3", "ISO8859-3", PM_ENCODING_ISO_8859_3);
- ENCODING2("ISO-8859-4", "ISO8859-4", PM_ENCODING_ISO_8859_4);
- ENCODING2("ISO-8859-5", "ISO8859-5", PM_ENCODING_ISO_8859_5);
- ENCODING2("ISO-8859-6", "ISO8859-6", PM_ENCODING_ISO_8859_6);
- ENCODING2("ISO-8859-7", "ISO8859-7", PM_ENCODING_ISO_8859_7);
- ENCODING2("ISO-8859-8", "ISO8859-8", PM_ENCODING_ISO_8859_8);
- ENCODING2("ISO-8859-9", "ISO8859-9", PM_ENCODING_ISO_8859_9);
- ENCODING2("ISO-8859-10", "ISO8859-10", PM_ENCODING_ISO_8859_10);
- ENCODING2("ISO-8859-11", "ISO8859-11", PM_ENCODING_ISO_8859_11);
- ENCODING2("ISO-8859-13", "ISO8859-13", PM_ENCODING_ISO_8859_13);
- ENCODING2("ISO-8859-14", "ISO8859-14", PM_ENCODING_ISO_8859_14);
- ENCODING2("ISO-8859-15", "ISO8859-15", PM_ENCODING_ISO_8859_15);
- ENCODING2("ISO-8859-16", "ISO8859-16", PM_ENCODING_ISO_8859_16);
-#endif
- break;
- case 'K': case 'k':
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- ENCODING1("KOI8-R", PM_ENCODING_KOI8_R);
- ENCODING1("KOI8-U", PM_ENCODING_KOI8_U);
-#endif
- break;
- case 'M': case 'm':
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- ENCODING1("macCentEuro", PM_ENCODING_MAC_CENT_EURO);
- ENCODING1("macCroatian", PM_ENCODING_MAC_CROATIAN);
- ENCODING1("macCyrillic", PM_ENCODING_MAC_CYRILLIC);
- ENCODING1("macGreek", PM_ENCODING_MAC_GREEK);
- ENCODING1("macIceland", PM_ENCODING_MAC_ICELAND);
- ENCODING1("MacJapanese", PM_ENCODING_MAC_JAPANESE);
- ENCODING1("MacJapan", PM_ENCODING_MAC_JAPANESE);
- ENCODING1("macRoman", PM_ENCODING_MAC_ROMAN);
- ENCODING1("macRomania", PM_ENCODING_MAC_ROMANIA);
- ENCODING1("macThai", PM_ENCODING_MAC_THAI);
- ENCODING1("macTurkish", PM_ENCODING_MAC_TURKISH);
- ENCODING1("macUkraine", PM_ENCODING_MAC_UKRAINE);
-#endif
- break;
- case 'P': case 'p':
- ENCODING1("PCK", PM_ENCODING_WINDOWS_31J);
- break;
- case 'S': case 's':
- ENCODING1("SJIS", PM_ENCODING_WINDOWS_31J);
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- ENCODING1("Shift_JIS", PM_ENCODING_SHIFT_JIS);
- ENCODING1("SJIS-DoCoMo", PM_ENCODING_SJIS_DOCOMO);
- ENCODING1("SJIS-KDDI", PM_ENCODING_SJIS_KDDI);
- ENCODING1("SJIS-SoftBank", PM_ENCODING_SJIS_SOFTBANK);
- ENCODING1("stateless-ISO-2022-JP", PM_ENCODING_STATELESS_ISO_2022_JP);
- ENCODING1("stateless-ISO-2022-JP-KDDI", PM_ENCODING_STATELESS_ISO_2022_JP_KDDI);
-#endif
- break;
- case 'T': case 't':
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- ENCODING1("TIS-620", PM_ENCODING_TIS_620);
-#endif
- break;
- case 'U': case 'u':
- ENCODING1("US-ASCII", PM_ENCODING_US_ASCII);
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- ENCODING2("UTF8-MAC", "UTF-8-HFS", PM_ENCODING_UTF8_MAC);
- ENCODING1("UTF8-DoCoMo", PM_ENCODING_UTF8_DOCOMO);
- ENCODING1("UTF8-KDDI", PM_ENCODING_UTF8_KDDI);
- ENCODING1("UTF8-SoftBank", PM_ENCODING_UTF8_SOFTBANK);
-#endif
- break;
- case 'W': case 'w':
- ENCODING1("Windows-31J", PM_ENCODING_WINDOWS_31J);
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- ENCODING1("Windows-874", PM_ENCODING_WINDOWS_874);
- ENCODING1("Windows-1250", PM_ENCODING_WINDOWS_1250);
- ENCODING1("Windows-1251", PM_ENCODING_WINDOWS_1251);
- ENCODING1("Windows-1252", PM_ENCODING_WINDOWS_1252);
- ENCODING1("Windows-1253", PM_ENCODING_WINDOWS_1253);
- ENCODING1("Windows-1254", PM_ENCODING_WINDOWS_1254);
- ENCODING1("Windows-1255", PM_ENCODING_WINDOWS_1255);
- ENCODING1("Windows-1256", PM_ENCODING_WINDOWS_1256);
- ENCODING1("Windows-1257", PM_ENCODING_WINDOWS_1257);
- ENCODING1("Windows-1258", PM_ENCODING_WINDOWS_1258);
-#endif
- break;
- case '6':
- ENCODING1("646", PM_ENCODING_US_ASCII);
- break;
- }
- }
-
-#undef ENCODING2
-#undef ENCODING1
-
- // If we didn't match any encodings, return NULL.
- return NULL;
-}
diff --git a/prism/encoding.h b/prism/encoding.h
deleted file mode 100644
index 5f7724821f..0000000000
--- a/prism/encoding.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/**
- * @file encoding.h
- *
- * The encoding interface and implementations used by the parser.
- */
-#ifndef PRISM_ENCODING_H
-#define PRISM_ENCODING_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_strncasecmp.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-/**
- * This struct defines the functions necessary to implement the encoding
- * interface so we can determine how many bytes the subsequent character takes.
- * Each callback should return the number of bytes, or 0 if the next bytes are
- * invalid for the encoding and type.
- */
-typedef struct {
- /**
- * Return the number of bytes that the next character takes if it is valid
- * in the encoding. Does not read more than n bytes. It is assumed that n is
- * at least 1.
- */
- size_t (*char_width)(const uint8_t *b, ptrdiff_t n);
-
- /**
- * Return the number of bytes that the next character takes if it is valid
- * in the encoding and is alphabetical. Does not read more than n bytes. It
- * is assumed that n is at least 1.
- */
- size_t (*alpha_char)(const uint8_t *b, ptrdiff_t n);
-
- /**
- * Return the number of bytes that the next character takes if it is valid
- * in the encoding and is alphanumeric. Does not read more than n bytes. It
- * is assumed that n is at least 1.
- */
- size_t (*alnum_char)(const uint8_t *b, ptrdiff_t n);
-
- /**
- * Return true if the next character is valid in the encoding and is an
- * uppercase character. Does not read more than n bytes. It is assumed that
- * n is at least 1.
- */
- bool (*isupper_char)(const uint8_t *b, ptrdiff_t n);
-
- /**
- * The name of the encoding. This should correspond to a value that can be
- * passed to Encoding.find in Ruby.
- */
- const char *name;
-
- /**
- * Return true if the encoding is a multibyte encoding.
- */
- bool multibyte;
-} pm_encoding_t;
-
-/**
- * All of the lookup tables use the first bit of each embedded byte to indicate
- * whether the codepoint is alphabetical.
- */
-#define PRISM_ENCODING_ALPHABETIC_BIT 1 << 0
-
-/**
- * All of the lookup tables use the second bit of each embedded byte to indicate
- * whether the codepoint is alphanumeric.
- */
-#define PRISM_ENCODING_ALPHANUMERIC_BIT 1 << 1
-
-/**
- * All of the lookup tables use the third bit of each embedded byte to indicate
- * whether the codepoint is uppercase.
- */
-#define PRISM_ENCODING_UPPERCASE_BIT 1 << 2
-
-/**
- * Return the size of the next character in the UTF-8 encoding.
- *
- * @param b The bytes to read.
- * @param n The number of bytes that can be read.
- * @returns The number of bytes that the next character takes if it is valid in
- * the encoding, or 0 if it is not.
- */
-size_t pm_encoding_utf_8_char_width(const uint8_t *b, ptrdiff_t n);
-
-/**
- * Return the size of the next character in the UTF-8 encoding if it is an
- * alphabetical character.
- *
- * @param b The bytes to read.
- * @param n The number of bytes that can be read.
- * @returns The number of bytes that the next character takes if it is valid in
- * the encoding, or 0 if it is not.
- */
-size_t pm_encoding_utf_8_alpha_char(const uint8_t *b, ptrdiff_t n);
-
-/**
- * Return the size of the next character in the UTF-8 encoding if it is an
- * alphanumeric character.
- *
- * @param b The bytes to read.
- * @param n The number of bytes that can be read.
- * @returns The number of bytes that the next character takes if it is valid in
- * the encoding, or 0 if it is not.
- */
-size_t pm_encoding_utf_8_alnum_char(const uint8_t *b, ptrdiff_t n);
-
-/**
- * Return true if the next character in the UTF-8 encoding if it is an uppercase
- * character.
- *
- * @param b The bytes to read.
- * @param n The number of bytes that can be read.
- * @returns True if the next character is valid in the encoding and is an
- * uppercase character, or false if it is not.
- */
-bool pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n);
-
-/**
- * This lookup table is referenced in both the UTF-8 encoding file and the
- * parser directly in order to speed up the default encoding processing. It is
- * used to indicate whether a character is alphabetical, alphanumeric, or
- * uppercase in unicode mappings.
- */
-extern const uint8_t pm_encoding_unicode_table[256];
-
-/**
- * These are all of the encodings that prism supports.
- */
-typedef enum {
- PM_ENCODING_UTF_8 = 0,
- PM_ENCODING_US_ASCII,
- PM_ENCODING_ASCII_8BIT,
- PM_ENCODING_EUC_JP,
- PM_ENCODING_WINDOWS_31J,
-
-// We optionally support excluding the full set of encodings to only support the
-// minimum necessary to process Ruby code without encoding comments.
-#ifndef PRISM_ENCODING_EXCLUDE_FULL
- PM_ENCODING_BIG5,
- PM_ENCODING_BIG5_HKSCS,
- PM_ENCODING_BIG5_UAO,
- PM_ENCODING_CESU_8,
- PM_ENCODING_CP51932,
- PM_ENCODING_CP850,
- PM_ENCODING_CP852,
- PM_ENCODING_CP855,
- PM_ENCODING_CP949,
- PM_ENCODING_CP950,
- PM_ENCODING_CP951,
- PM_ENCODING_EMACS_MULE,
- PM_ENCODING_EUC_JP_MS,
- PM_ENCODING_EUC_JIS_2004,
- PM_ENCODING_EUC_KR,
- PM_ENCODING_EUC_TW,
- PM_ENCODING_GB12345,
- PM_ENCODING_GB18030,
- PM_ENCODING_GB1988,
- PM_ENCODING_GB2312,
- PM_ENCODING_GBK,
- PM_ENCODING_IBM437,
- PM_ENCODING_IBM720,
- PM_ENCODING_IBM737,
- PM_ENCODING_IBM775,
- PM_ENCODING_IBM852,
- PM_ENCODING_IBM855,
- PM_ENCODING_IBM857,
- PM_ENCODING_IBM860,
- PM_ENCODING_IBM861,
- PM_ENCODING_IBM862,
- PM_ENCODING_IBM863,
- PM_ENCODING_IBM864,
- PM_ENCODING_IBM865,
- PM_ENCODING_IBM866,
- PM_ENCODING_IBM869,
- PM_ENCODING_ISO_8859_1,
- PM_ENCODING_ISO_8859_2,
- PM_ENCODING_ISO_8859_3,
- PM_ENCODING_ISO_8859_4,
- PM_ENCODING_ISO_8859_5,
- PM_ENCODING_ISO_8859_6,
- PM_ENCODING_ISO_8859_7,
- PM_ENCODING_ISO_8859_8,
- PM_ENCODING_ISO_8859_9,
- PM_ENCODING_ISO_8859_10,
- PM_ENCODING_ISO_8859_11,
- PM_ENCODING_ISO_8859_13,
- PM_ENCODING_ISO_8859_14,
- PM_ENCODING_ISO_8859_15,
- PM_ENCODING_ISO_8859_16,
- PM_ENCODING_KOI8_R,
- PM_ENCODING_KOI8_U,
- PM_ENCODING_MAC_CENT_EURO,
- PM_ENCODING_MAC_CROATIAN,
- PM_ENCODING_MAC_CYRILLIC,
- PM_ENCODING_MAC_GREEK,
- PM_ENCODING_MAC_ICELAND,
- PM_ENCODING_MAC_JAPANESE,
- PM_ENCODING_MAC_ROMAN,
- PM_ENCODING_MAC_ROMANIA,
- PM_ENCODING_MAC_THAI,
- PM_ENCODING_MAC_TURKISH,
- PM_ENCODING_MAC_UKRAINE,
- PM_ENCODING_SHIFT_JIS,
- PM_ENCODING_SJIS_DOCOMO,
- PM_ENCODING_SJIS_KDDI,
- PM_ENCODING_SJIS_SOFTBANK,
- PM_ENCODING_STATELESS_ISO_2022_JP,
- PM_ENCODING_STATELESS_ISO_2022_JP_KDDI,
- PM_ENCODING_TIS_620,
- PM_ENCODING_UTF8_MAC,
- PM_ENCODING_UTF8_DOCOMO,
- PM_ENCODING_UTF8_KDDI,
- PM_ENCODING_UTF8_SOFTBANK,
- PM_ENCODING_WINDOWS_1250,
- PM_ENCODING_WINDOWS_1251,
- PM_ENCODING_WINDOWS_1252,
- PM_ENCODING_WINDOWS_1253,
- PM_ENCODING_WINDOWS_1254,
- PM_ENCODING_WINDOWS_1255,
- PM_ENCODING_WINDOWS_1256,
- PM_ENCODING_WINDOWS_1257,
- PM_ENCODING_WINDOWS_1258,
- PM_ENCODING_WINDOWS_874,
-#endif
-
- PM_ENCODING_MAXIMUM
-} pm_encoding_type_t;
-
-/**
- * This is the table of all of the encodings that prism supports.
- */
-extern const pm_encoding_t pm_encodings[PM_ENCODING_MAXIMUM];
-
-/**
- * This is the default UTF-8 encoding. We need a reference to it to quickly
- * create parsers.
- */
-#define PM_ENCODING_UTF_8_ENTRY (&pm_encodings[PM_ENCODING_UTF_8])
-
-/**
- * This is the US-ASCII encoding. We need a reference to it to be able to
- * compare against it when a string is being created because it could possibly
- * need to fall back to ASCII-8BIT.
- */
-#define PM_ENCODING_US_ASCII_ENTRY (&pm_encodings[PM_ENCODING_US_ASCII])
-
-/**
- * This is the ASCII-8BIT encoding. We need a reference to it so that pm_strpbrk
- * can compare against it because invalid multibyte characters are not a thing
- * in this encoding. It is also needed for handling Regexp encoding flags.
- */
-#define PM_ENCODING_ASCII_8BIT_ENTRY (&pm_encodings[PM_ENCODING_ASCII_8BIT])
-
-/**
- * This is the EUC-JP encoding. We need a reference to it to quickly process
- * regular expression modifiers.
- */
-#define PM_ENCODING_EUC_JP_ENTRY (&pm_encodings[PM_ENCODING_EUC_JP])
-
-/**
- * This is the Windows-31J encoding. We need a reference to it to quickly
- * process regular expression modifiers.
- */
-#define PM_ENCODING_WINDOWS_31J_ENTRY (&pm_encodings[PM_ENCODING_WINDOWS_31J])
-
-/**
- * Parse the given name of an encoding and return a pointer to the corresponding
- * encoding struct if one can be found, otherwise return NULL.
- *
- * @param start A pointer to the first byte of the name.
- * @param end A pointer to the last byte of the name.
- * @returns A pointer to the encoding struct if one is found, otherwise NULL.
- */
-const pm_encoding_t * pm_encoding_find(const uint8_t *start, const uint8_t *end);
-
-#endif
diff --git a/prism/extension.c b/prism/extension.c
deleted file mode 100644
index 93fa7b0989..0000000000
--- a/prism/extension.c
+++ /dev/null
@@ -1,1217 +0,0 @@
-#include "prism/extension.h"
-
-#ifdef _WIN32
-#include <ruby/win32.h>
-#endif
-
-// NOTE: this file should contain only bindings. All non-trivial logic should be
-// in libprism so it can be shared its the various callers.
-
-VALUE rb_cPrism;
-VALUE rb_cPrismNode;
-VALUE rb_cPrismSource;
-VALUE rb_cPrismToken;
-VALUE rb_cPrismLocation;
-
-VALUE rb_cPrismComment;
-VALUE rb_cPrismInlineComment;
-VALUE rb_cPrismEmbDocComment;
-VALUE rb_cPrismMagicComment;
-VALUE rb_cPrismParseError;
-VALUE rb_cPrismParseWarning;
-VALUE rb_cPrismResult;
-VALUE rb_cPrismParseResult;
-VALUE rb_cPrismLexResult;
-VALUE rb_cPrismParseLexResult;
-
-VALUE rb_cPrismDebugEncoding;
-
-ID rb_id_option_command_line;
-ID rb_id_option_encoding;
-ID rb_id_option_filepath;
-ID rb_id_option_frozen_string_literal;
-ID rb_id_option_line;
-ID rb_id_option_main_script;
-ID rb_id_option_partial_script;
-ID rb_id_option_scopes;
-ID rb_id_option_version;
-ID rb_id_source_for;
-
-/******************************************************************************/
-/* IO of Ruby code */
-/******************************************************************************/
-
-/**
- * Check if the given VALUE is a string. If it's not a string, then raise a
- * TypeError. Otherwise return the VALUE as a C string.
- */
-static const char *
-check_string(VALUE value) {
- // Check if the value is a string. If it's not, then raise a type error.
- if (!RB_TYPE_P(value, T_STRING)) {
- rb_raise(rb_eTypeError, "wrong argument type %" PRIsVALUE " (expected String)", rb_obj_class(value));
- }
-
- // Otherwise, return the value as a C string.
- return RSTRING_PTR(value);
-}
-
-/**
- * Load the contents and size of the given string into the given pm_string_t.
- */
-static void
-input_load_string(pm_string_t *input, VALUE string) {
- // Check if the string is a string. If it's not, then raise a type error.
- if (!RB_TYPE_P(string, T_STRING)) {
- rb_raise(rb_eTypeError, "wrong argument type %" PRIsVALUE " (expected String)", rb_obj_class(string));
- }
-
- pm_string_constant_init(input, RSTRING_PTR(string), RSTRING_LEN(string));
-}
-
-/******************************************************************************/
-/* Building C options from Ruby options */
-/******************************************************************************/
-
-/**
- * Build the scopes associated with the provided Ruby keyword value.
- */
-static void
-build_options_scopes(pm_options_t *options, VALUE scopes) {
- // Check if the value is an array. If it's not, then raise a type error.
- if (!RB_TYPE_P(scopes, T_ARRAY)) {
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Array)", rb_obj_class(scopes));
- }
-
- // Initialize the scopes array.
- size_t scopes_count = RARRAY_LEN(scopes);
- if (!pm_options_scopes_init(options, scopes_count)) {
- rb_raise(rb_eNoMemError, "failed to allocate memory");
- }
-
- // Iterate over the scopes and add them to the options.
- for (size_t scope_index = 0; scope_index < scopes_count; scope_index++) {
- VALUE scope = rb_ary_entry(scopes, scope_index);
-
- // Check that the scope is an array. If it's not, then raise a type
- // error.
- if (!RB_TYPE_P(scope, T_ARRAY)) {
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Array)", rb_obj_class(scope));
- }
-
- // Initialize the scope array.
- size_t locals_count = RARRAY_LEN(scope);
- pm_options_scope_t *options_scope = &options->scopes[scope_index];
- if (!pm_options_scope_init(options_scope, locals_count)) {
- rb_raise(rb_eNoMemError, "failed to allocate memory");
- }
-
- // Iterate over the locals and add them to the scope.
- for (size_t local_index = 0; local_index < locals_count; local_index++) {
- VALUE local = rb_ary_entry(scope, local_index);
-
- // Check that the local is a symbol. If it's not, then raise a
- // type error.
- if (!RB_TYPE_P(local, T_SYMBOL)) {
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Symbol)", rb_obj_class(local));
- }
-
- // Add the local to the scope.
- pm_string_t *scope_local = &options_scope->locals[local_index];
- const char *name = rb_id2name(SYM2ID(local));
- pm_string_constant_init(scope_local, name, strlen(name));
- }
- }
-}
-
-/**
- * An iterator function that is called for each key-value in the keywords hash.
- */
-static int
-build_options_i(VALUE key, VALUE value, VALUE argument) {
- pm_options_t *options = (pm_options_t *) argument;
- ID key_id = SYM2ID(key);
-
- if (key_id == rb_id_option_filepath) {
- if (!NIL_P(value)) pm_options_filepath_set(options, check_string(value));
- } else if (key_id == rb_id_option_encoding) {
- if (!NIL_P(value)) {
- if (value == Qfalse) {
- pm_options_encoding_locked_set(options, true);
- } else {
- pm_options_encoding_set(options, rb_enc_name(rb_to_encoding(value)));
- }
- }
- } else if (key_id == rb_id_option_line) {
- if (!NIL_P(value)) pm_options_line_set(options, NUM2INT(value));
- } else if (key_id == rb_id_option_frozen_string_literal) {
- if (!NIL_P(value)) pm_options_frozen_string_literal_set(options, RTEST(value));
- } else if (key_id == rb_id_option_version) {
- if (!NIL_P(value)) {
- const char *version = check_string(value);
-
- if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
- rb_raise(rb_eArgError, "invalid version: %" PRIsVALUE, value);
- }
- }
- } else if (key_id == rb_id_option_scopes) {
- if (!NIL_P(value)) build_options_scopes(options, value);
- } else if (key_id == rb_id_option_command_line) {
- if (!NIL_P(value)) {
- const char *string = check_string(value);
- uint8_t command_line = 0;
-
- for (size_t index = 0; index < strlen(string); index++) {
- switch (string[index]) {
- case 'a': command_line |= PM_OPTIONS_COMMAND_LINE_A; break;
- case 'e': command_line |= PM_OPTIONS_COMMAND_LINE_E; break;
- case 'l': command_line |= PM_OPTIONS_COMMAND_LINE_L; break;
- case 'n': command_line |= PM_OPTIONS_COMMAND_LINE_N; break;
- case 'p': command_line |= PM_OPTIONS_COMMAND_LINE_P; break;
- case 'x': command_line |= PM_OPTIONS_COMMAND_LINE_X; break;
- default: rb_raise(rb_eArgError, "invalid command line flag: '%c'", string[index]); break;
- }
- }
-
- pm_options_command_line_set(options, command_line);
- }
- } else if (key_id == rb_id_option_main_script) {
- if (!NIL_P(value)) pm_options_main_script_set(options, RTEST(value));
- } else if (key_id == rb_id_option_partial_script) {
- if (!NIL_P(value)) pm_options_partial_script_set(options, RTEST(value));
- } else {
- rb_raise(rb_eArgError, "unknown keyword: %" PRIsVALUE, key);
- }
-
- return ST_CONTINUE;
-}
-
-/**
- * We need a struct here to pass through rb_protect and it has to be a single
- * value. Because the sizeof(VALUE) == sizeof(void *), we're going to pass this
- * through as an opaque pointer and cast it on both sides.
- */
-struct build_options_data {
- pm_options_t *options;
- VALUE keywords;
-};
-
-/**
- * Build the set of options from the given keywords. Note that this can raise a
- * Ruby error if the options are not valid.
- */
-static VALUE
-build_options(VALUE argument) {
- struct build_options_data *data = (struct build_options_data *) argument;
- rb_hash_foreach(data->keywords, build_options_i, (VALUE) data->options);
- return Qnil;
-}
-
-/**
- * Extract the options from the given keyword arguments.
- */
-static void
-extract_options(pm_options_t *options, VALUE filepath, VALUE keywords) {
- options->line = 1; // default
-
- if (!NIL_P(keywords)) {
- struct build_options_data data = { .options = options, .keywords = keywords };
- struct build_options_data *argument = &data;
-
- int state = 0;
- rb_protect(build_options, (VALUE) argument, &state);
-
- if (state != 0) {
- pm_options_free(options);
- rb_jump_tag(state);
- }
- }
-
- if (!NIL_P(filepath)) {
- if (!RB_TYPE_P(filepath, T_STRING)) {
- pm_options_free(options);
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected String)", rb_obj_class(filepath));
- }
-
- pm_options_filepath_set(options, RSTRING_PTR(filepath));
- }
-}
-
-/**
- * Read options for methods that look like (source, **options).
- */
-static void
-string_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options) {
- VALUE string;
- VALUE keywords;
- rb_scan_args(argc, argv, "1:", &string, &keywords);
-
- extract_options(options, Qnil, keywords);
- input_load_string(input, string);
-}
-
-/**
- * Read options for methods that look like (filepath, **options).
- */
-static void
-file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, VALUE *encoded_filepath) {
- VALUE filepath;
- VALUE keywords;
- rb_scan_args(argc, argv, "1:", &filepath, &keywords);
-
- Check_Type(filepath, T_STRING);
- *encoded_filepath = rb_str_encode_ospath(filepath);
- extract_options(options, *encoded_filepath, keywords);
-
- const char *source = (const char *) pm_string_source(&options->filepath);
- pm_string_init_result_t result;
-
- switch (result = pm_string_file_init(input, source)) {
- case PM_STRING_INIT_SUCCESS:
- break;
- case PM_STRING_INIT_ERROR_GENERIC: {
- pm_options_free(options);
-
-#ifdef _WIN32
- int e = rb_w32_map_errno(GetLastError());
-#else
- int e = errno;
-#endif
-
- rb_syserr_fail(e, source);
- break;
- }
- case PM_STRING_INIT_ERROR_DIRECTORY:
- pm_options_free(options);
- rb_syserr_fail(EISDIR, source);
- break;
- default:
- pm_options_free(options);
- rb_raise(rb_eRuntimeError, "Unknown error (%d) initializing file: %s", result, source);
- break;
- }
-}
-
-#ifndef PRISM_EXCLUDE_SERIALIZATION
-
-/******************************************************************************/
-/* Serializing the AST */
-/******************************************************************************/
-
-/**
- * Dump the AST corresponding to the given input to a string.
- */
-static VALUE
-dump_input(pm_string_t *input, const pm_options_t *options) {
- pm_buffer_t buffer;
- if (!pm_buffer_init(&buffer)) {
- rb_raise(rb_eNoMemError, "failed to allocate memory");
- }
-
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
-
- pm_node_t *node = pm_parse(&parser);
- pm_serialize(&parser, node, &buffer);
-
- VALUE result = rb_str_new(pm_buffer_value(&buffer), pm_buffer_length(&buffer));
- pm_node_destroy(&parser, node);
- pm_buffer_free(&buffer);
- pm_parser_free(&parser);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::dump(source, **options) -> String
- *
- * Dump the AST corresponding to the given string to a string. For supported
- * options, see Prism::parse.
- */
-static VALUE
-dump(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- string_options(argc, argv, &input, &options);
-
-#ifdef PRISM_BUILD_DEBUG
- size_t length = pm_string_length(&input);
- char* dup = xmalloc(length);
- memcpy(dup, pm_string_source(&input), length);
- pm_string_constant_init(&input, dup, length);
-#endif
-
- VALUE value = dump_input(&input, &options);
-
-#ifdef PRISM_BUILD_DEBUG
- xfree(dup);
-#endif
-
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-/**
- * call-seq:
- * Prism::dump_file(filepath, **options) -> String
- *
- * Dump the AST corresponding to the given file to a string. For supported
- * options, see Prism::parse.
- */
-static VALUE
-dump_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
-
- VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
-
- VALUE value = dump_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-#endif
-
-/******************************************************************************/
-/* Extracting values for the parse result */
-/******************************************************************************/
-
-/**
- * Extract the comments out of the parser into an array.
- */
-static VALUE
-parser_comments(pm_parser_t *parser, VALUE source) {
- VALUE comments = rb_ary_new_capa(parser->comment_list.size);
-
- for (pm_comment_t *comment = (pm_comment_t *) parser->comment_list.head; comment != NULL; comment = (pm_comment_t *) comment->node.next) {
- VALUE location_argv[] = {
- source,
- LONG2FIX(comment->location.start - parser->start),
- LONG2FIX(comment->location.end - comment->location.start)
- };
-
- VALUE type = (comment->type == PM_COMMENT_EMBDOC) ? rb_cPrismEmbDocComment : rb_cPrismInlineComment;
- VALUE comment_argv[] = { rb_class_new_instance(3, location_argv, rb_cPrismLocation) };
- rb_ary_push(comments, rb_class_new_instance(1, comment_argv, type));
- }
-
- return comments;
-}
-
-/**
- * Extract the magic comments out of the parser into an array.
- */
-static VALUE
-parser_magic_comments(pm_parser_t *parser, VALUE source) {
- VALUE magic_comments = rb_ary_new_capa(parser->magic_comment_list.size);
-
- for (pm_magic_comment_t *magic_comment = (pm_magic_comment_t *) parser->magic_comment_list.head; magic_comment != NULL; magic_comment = (pm_magic_comment_t *) magic_comment->node.next) {
- VALUE key_loc_argv[] = {
- source,
- LONG2FIX(magic_comment->key_start - parser->start),
- LONG2FIX(magic_comment->key_length)
- };
-
- VALUE value_loc_argv[] = {
- source,
- LONG2FIX(magic_comment->value_start - parser->start),
- LONG2FIX(magic_comment->value_length)
- };
-
- VALUE magic_comment_argv[] = {
- rb_class_new_instance(3, key_loc_argv, rb_cPrismLocation),
- rb_class_new_instance(3, value_loc_argv, rb_cPrismLocation)
- };
-
- rb_ary_push(magic_comments, rb_class_new_instance(2, magic_comment_argv, rb_cPrismMagicComment));
- }
-
- return magic_comments;
-}
-
-/**
- * Extract out the data location from the parser into a Location instance if one
- * exists.
- */
-static VALUE
-parser_data_loc(const pm_parser_t *parser, VALUE source) {
- if (parser->data_loc.end == NULL) {
- return Qnil;
- } else {
- VALUE argv[] = {
- source,
- LONG2FIX(parser->data_loc.start - parser->start),
- LONG2FIX(parser->data_loc.end - parser->data_loc.start)
- };
-
- return rb_class_new_instance(3, argv, rb_cPrismLocation);
- }
-}
-
-/**
- * Extract the errors out of the parser into an array.
- */
-static VALUE
-parser_errors(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
- VALUE errors = rb_ary_new_capa(parser->error_list.size);
- pm_diagnostic_t *error;
-
- for (error = (pm_diagnostic_t *) parser->error_list.head; error != NULL; error = (pm_diagnostic_t *) error->node.next) {
- VALUE location_argv[] = {
- source,
- LONG2FIX(error->location.start - parser->start),
- LONG2FIX(error->location.end - error->location.start)
- };
-
- VALUE level = Qnil;
- switch (error->level) {
- case PM_ERROR_LEVEL_SYNTAX:
- level = ID2SYM(rb_intern("syntax"));
- break;
- case PM_ERROR_LEVEL_ARGUMENT:
- level = ID2SYM(rb_intern("argument"));
- break;
- case PM_ERROR_LEVEL_LOAD:
- level = ID2SYM(rb_intern("load"));
- break;
- default:
- rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, error->level);
- }
-
- VALUE error_argv[] = {
- ID2SYM(rb_intern(pm_diagnostic_id_human(error->diag_id))),
- rb_enc_str_new_cstr(error->message, encoding),
- rb_class_new_instance(3, location_argv, rb_cPrismLocation),
- level
- };
-
- rb_ary_push(errors, rb_class_new_instance(4, error_argv, rb_cPrismParseError));
- }
-
- return errors;
-}
-
-/**
- * Extract the warnings out of the parser into an array.
- */
-static VALUE
-parser_warnings(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
- VALUE warnings = rb_ary_new_capa(parser->warning_list.size);
- pm_diagnostic_t *warning;
-
- for (warning = (pm_diagnostic_t *) parser->warning_list.head; warning != NULL; warning = (pm_diagnostic_t *) warning->node.next) {
- VALUE location_argv[] = {
- source,
- LONG2FIX(warning->location.start - parser->start),
- LONG2FIX(warning->location.end - warning->location.start)
- };
-
- VALUE level = Qnil;
- switch (warning->level) {
- case PM_WARNING_LEVEL_DEFAULT:
- level = ID2SYM(rb_intern("default"));
- break;
- case PM_WARNING_LEVEL_VERBOSE:
- level = ID2SYM(rb_intern("verbose"));
- break;
- default:
- rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, warning->level);
- }
-
- VALUE warning_argv[] = {
- ID2SYM(rb_intern(pm_diagnostic_id_human(warning->diag_id))),
- rb_enc_str_new_cstr(warning->message, encoding),
- rb_class_new_instance(3, location_argv, rb_cPrismLocation),
- level
- };
-
- rb_ary_push(warnings, rb_class_new_instance(4, warning_argv, rb_cPrismParseWarning));
- }
-
- return warnings;
-}
-
-/**
- * Create a new parse result from the given parser, value, encoding, and source.
- */
-static VALUE
-parse_result_create(VALUE class, pm_parser_t *parser, VALUE value, rb_encoding *encoding, VALUE source) {
- VALUE result_argv[] = {
- value,
- parser_comments(parser, source),
- parser_magic_comments(parser, source),
- parser_data_loc(parser, source),
- parser_errors(parser, encoding, source),
- parser_warnings(parser, encoding, source),
- source
- };
-
- return rb_class_new_instance(7, result_argv, class);
-}
-
-/******************************************************************************/
-/* Lexing Ruby code */
-/******************************************************************************/
-
-/**
- * This struct gets stored in the parser and passed in to the lex callback any
- * time a new token is found. We use it to store the necessary information to
- * initialize a Token instance.
- */
-typedef struct {
- VALUE source;
- VALUE tokens;
- rb_encoding *encoding;
-} parse_lex_data_t;
-
-/**
- * This is passed as a callback to the parser. It gets called every time a new
- * token is found. Once found, we initialize a new instance of Token and push it
- * onto the tokens array.
- */
-static void
-parse_lex_token(void *data, pm_parser_t *parser, pm_token_t *token) {
- parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) parser->lex_callback->data;
-
- VALUE yields = rb_assoc_new(
- pm_token_new(parser, token, parse_lex_data->encoding, parse_lex_data->source),
- INT2FIX(parser->lex_state)
- );
-
- rb_ary_push(parse_lex_data->tokens, yields);
-}
-
-/**
- * This is called whenever the encoding changes based on the magic comment at
- * the top of the file. We use it to update the encoding that we are using to
- * create tokens.
- */
-static void
-parse_lex_encoding_changed_callback(pm_parser_t *parser) {
- parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) parser->lex_callback->data;
- parse_lex_data->encoding = rb_enc_find(parser->encoding->name);
-
- // Since the encoding changed, we need to go back and change the encoding of
- // the tokens that were already lexed. This is only going to end up being
- // one or two tokens, since the encoding can only change at the top of the
- // file.
- VALUE tokens = parse_lex_data->tokens;
- for (long index = 0; index < RARRAY_LEN(tokens); index++) {
- VALUE yields = rb_ary_entry(tokens, index);
- VALUE token = rb_ary_entry(yields, 0);
-
- VALUE value = rb_ivar_get(token, rb_intern("@value"));
- rb_enc_associate(value, parse_lex_data->encoding);
- ENC_CODERANGE_CLEAR(value);
- }
-}
-
-/**
- * Parse the given input and return a ParseResult containing just the tokens or
- * the nodes and tokens.
- */
-static VALUE
-parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nodes) {
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
- pm_parser_register_encoding_changed_callback(&parser, parse_lex_encoding_changed_callback);
-
- VALUE source_string = rb_str_new((const char *) pm_string_source(input), pm_string_length(input));
- VALUE offsets = rb_ary_new_capa(parser.newline_list.size);
- VALUE source = rb_funcall(rb_cPrismSource, rb_id_source_for, 3, source_string, LONG2NUM(parser.start_line), offsets);
-
- parse_lex_data_t parse_lex_data = {
- .source = source,
- .tokens = rb_ary_new(),
- .encoding = rb_utf8_encoding()
- };
-
- parse_lex_data_t *data = &parse_lex_data;
- pm_lex_callback_t lex_callback = (pm_lex_callback_t) {
- .data = (void *) data,
- .callback = parse_lex_token,
- };
-
- parser.lex_callback = &lex_callback;
- pm_node_t *node = pm_parse(&parser);
-
- // Here we need to update the Source object to have the correct
- // encoding for the source string and the correct newline offsets.
- // We do it here because we've already created the Source object and given
- // it over to all of the tokens, and both of these are only set after pm_parse().
- rb_encoding *encoding = rb_enc_find(parser.encoding->name);
- rb_enc_associate(source_string, encoding);
-
- for (size_t index = 0; index < parser.newline_list.size; index++) {
- rb_ary_push(offsets, ULONG2NUM(parser.newline_list.offsets[index]));
- }
-
- VALUE result;
- if (return_nodes) {
- VALUE value = rb_ary_new_capa(2);
- rb_ary_push(value, pm_ast_new(&parser, node, parse_lex_data.encoding, source));
- rb_ary_push(value, parse_lex_data.tokens);
- result = parse_result_create(rb_cPrismParseLexResult, &parser, value, parse_lex_data.encoding, source);
- } else {
- result = parse_result_create(rb_cPrismLexResult, &parser, parse_lex_data.tokens, parse_lex_data.encoding, source);
- }
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::lex(source, **options) -> LexResult
- *
- * Return a LexResult instance that contains an array of Token instances
- * corresponding to the given string. For supported options, see Prism::parse.
- */
-static VALUE
-lex(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- string_options(argc, argv, &input, &options);
-
- VALUE result = parse_lex_input(&input, &options, false);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::lex_file(filepath, **options) -> LexResult
- *
- * Return a LexResult instance that contains an array of Token instances
- * corresponding to the given file. For supported options, see Prism::parse.
- */
-static VALUE
-lex_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
-
- VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
-
- VALUE value = parse_lex_input(&input, &options, false);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-/******************************************************************************/
-/* Parsing Ruby code */
-/******************************************************************************/
-
-/**
- * Parse the given input and return a ParseResult instance.
- */
-static VALUE
-parse_input(pm_string_t *input, const pm_options_t *options) {
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
-
- pm_node_t *node = pm_parse(&parser);
- rb_encoding *encoding = rb_enc_find(parser.encoding->name);
-
- VALUE source = pm_source_new(&parser, encoding);
- VALUE value = pm_ast_new(&parser, node, encoding, source);
- VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source) ;
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::parse(source, **options) -> ParseResult
- *
- * Parse the given string and return a ParseResult instance. The options that
- * are supported are:
- *
- * * `command_line` - either nil or a string of the various options that were
- * set on the command line. Valid values are combinations of "a", "l",
- * "n", "p", and "x".
- * * `encoding` - the encoding of the source being parsed. This should be an
- * encoding or nil.
- * * `filepath` - the filepath of the source being parsed. This should be a
- * string or nil.
- * * `frozen_string_literal` - whether or not the frozen string literal pragma
- * has been set. This should be a boolean or nil.
- * * `line` - the line number that the parse starts on. This should be an
- * integer or nil. Note that this is 1-indexed.
- * * `main_script` - a boolean indicating whether or not the source being parsed
- * is the main script being run by the interpreter. This controls whether
- * or not shebangs are parsed for additional flags and whether or not the
- * parser will attempt to find a matching shebang if the first one does
- * not contain the word "ruby".
- * * `partial_script` - when the file being parsed is considered a "partial"
- * script, jumps will not be marked as errors if they are not contained
- * within loops/blocks. This is used in the case that you're parsing a
- * script that you know will be embedded inside another script later, but
- * you do not have that context yet. For example, when parsing an ERB
- * template that will be evaluated inside another script.
- * * `scopes` - the locals that are in scope surrounding the code that is being
- * parsed. This should be an array of arrays of symbols or nil. Scopes are
- * ordered from the outermost scope to the innermost one.
- * * `version` - the version of Ruby syntax that prism should used to parse Ruby
- * code. By default prism assumes you want to parse with the latest version
- * of Ruby syntax (which you can trigger with `nil` or `"latest"`). You
- * may also restrict the syntax to a specific version of Ruby, e.g., with `"3.3.0"`.
- * To parse with the same syntax version that the current Ruby is running
- * use `version: RUBY_VERSION`. Raises ArgumentError if the version is not
- * currently supported by Prism.
- */
-static VALUE
-parse(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- string_options(argc, argv, &input, &options);
-
-#ifdef PRISM_BUILD_DEBUG
- size_t length = pm_string_length(&input);
- char* dup = xmalloc(length);
- memcpy(dup, pm_string_source(&input), length);
- pm_string_constant_init(&input, dup, length);
-#endif
-
- VALUE value = parse_input(&input, &options);
-
-#ifdef PRISM_BUILD_DEBUG
- xfree(dup);
-#endif
-
- pm_string_free(&input);
- pm_options_free(&options);
- return value;
-}
-
-/**
- * call-seq:
- * Prism::parse_file(filepath, **options) -> ParseResult
- *
- * Parse the given file and return a ParseResult instance. For supported
- * options, see Prism::parse.
- */
-static VALUE
-parse_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
-
- VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
-
- VALUE value = parse_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-/**
- * Parse the given input and return nothing.
- */
-static void
-profile_input(pm_string_t *input, const pm_options_t *options) {
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
-
- pm_node_t *node = pm_parse(&parser);
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
-}
-
-/**
- * call-seq:
- * Prism::profile(source, **options) -> nil
- *
- * Parse the given string and return nothing. This method is meant to allow
- * profilers to avoid the overhead of reifying the AST to Ruby. For supported
- * options, see Prism::parse.
- */
-static VALUE
-profile(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
-
- string_options(argc, argv, &input, &options);
- profile_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return Qnil;
-}
-
-/**
- * call-seq:
- * Prism::profile_file(filepath, **options) -> nil
- *
- * Parse the given file and return nothing. This method is meant to allow
- * profilers to avoid the overhead of reifying the AST to Ruby. For supported
- * options, see Prism::parse.
- */
-static VALUE
-profile_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
-
- VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
-
- profile_input(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return Qnil;
-}
-
-/**
- * An implementation of fgets that is suitable for use with Ruby IO objects.
- */
-static char *
-parse_stream_fgets(char *string, int size, void *stream) {
- RUBY_ASSERT(size > 0);
-
- VALUE line = rb_funcall((VALUE) stream, rb_intern("gets"), 1, INT2FIX(size - 1));
- if (NIL_P(line)) {
- return NULL;
- }
-
- const char *cstr = RSTRING_PTR(line);
- long length = RSTRING_LEN(line);
-
- memcpy(string, cstr, length);
- string[length] = '\0';
-
- return string;
-}
-
-/**
- * call-seq:
- * Prism::parse_stream(stream, **options) -> ParseResult
- *
- * Parse the given object that responds to `gets` and return a ParseResult
- * instance. The options that are supported are the same as Prism::parse.
- */
-static VALUE
-parse_stream(int argc, VALUE *argv, VALUE self) {
- VALUE stream;
- VALUE keywords;
- rb_scan_args(argc, argv, "1:", &stream, &keywords);
-
- pm_options_t options = { 0 };
- extract_options(&options, Qnil, keywords);
-
- pm_parser_t parser;
- pm_buffer_t buffer;
-
- pm_node_t *node = pm_parse_stream(&parser, &buffer, (void *) stream, parse_stream_fgets, &options);
- rb_encoding *encoding = rb_enc_find(parser.encoding->name);
-
- VALUE source = pm_source_new(&parser, encoding);
- VALUE value = pm_ast_new(&parser, node, encoding, source);
- VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source);
-
- pm_node_destroy(&parser, node);
- pm_buffer_free(&buffer);
- pm_parser_free(&parser);
-
- return result;
-}
-
-/**
- * Parse the given input and return an array of Comment objects.
- */
-static VALUE
-parse_input_comments(pm_string_t *input, const pm_options_t *options) {
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
-
- pm_node_t *node = pm_parse(&parser);
- rb_encoding *encoding = rb_enc_find(parser.encoding->name);
-
- VALUE source = pm_source_new(&parser, encoding);
- VALUE comments = parser_comments(&parser, source);
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
-
- return comments;
-}
-
-/**
- * call-seq:
- * Prism::parse_comments(source, **options) -> Array
- *
- * Parse the given string and return an array of Comment objects. For supported
- * options, see Prism::parse.
- */
-static VALUE
-parse_comments(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- string_options(argc, argv, &input, &options);
-
- VALUE result = parse_input_comments(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::parse_file_comments(filepath, **options) -> Array
- *
- * Parse the given file and return an array of Comment objects. For supported
- * options, see Prism::parse.
- */
-static VALUE
-parse_file_comments(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
-
- VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
-
- VALUE value = parse_input_comments(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-/**
- * call-seq:
- * Prism::parse_lex(source, **options) -> ParseLexResult
- *
- * Parse the given string and return a ParseLexResult instance that contains a
- * 2-element array, where the first element is the AST and the second element is
- * an array of Token instances.
- *
- * This API is only meant to be used in the case where you need both the AST and
- * the tokens. If you only need one or the other, use either Prism::parse or
- * Prism::lex.
- *
- * For supported options, see Prism::parse.
- */
-static VALUE
-parse_lex(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- string_options(argc, argv, &input, &options);
-
- VALUE value = parse_lex_input(&input, &options, true);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-/**
- * call-seq:
- * Prism::parse_lex_file(filepath, **options) -> ParseLexResult
- *
- * Parse the given file and return a ParseLexResult instance that contains a
- * 2-element array, where the first element is the AST and the second element is
- * an array of Token instances.
- *
- * This API is only meant to be used in the case where you need both the AST and
- * the tokens. If you only need one or the other, use either Prism::parse_file
- * or Prism::lex_file.
- *
- * For supported options, see Prism::parse.
- */
-static VALUE
-parse_lex_file(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
-
- VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
-
- VALUE value = parse_lex_input(&input, &options, true);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return value;
-}
-
-/**
- * Parse the given input and return true if it parses without errors.
- */
-static VALUE
-parse_input_success_p(pm_string_t *input, const pm_options_t *options) {
- pm_parser_t parser;
- pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
-
- pm_node_t *node = pm_parse(&parser);
- pm_node_destroy(&parser, node);
-
- VALUE result = parser.error_list.size == 0 ? Qtrue : Qfalse;
- pm_parser_free(&parser);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::parse_success?(source, **options) -> bool
- *
- * Parse the given string and return true if it parses without errors. For
- * supported options, see Prism::parse.
- */
-static VALUE
-parse_success_p(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
- string_options(argc, argv, &input, &options);
-
- VALUE result = parse_input_success_p(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::parse_failure?(source, **options) -> bool
- *
- * Parse the given string and return true if it parses with errors. For
- * supported options, see Prism::parse.
- */
-static VALUE
-parse_failure_p(int argc, VALUE *argv, VALUE self) {
- return RTEST(parse_success_p(argc, argv, self)) ? Qfalse : Qtrue;
-}
-
-/**
- * call-seq:
- * Prism::parse_file_success?(filepath, **options) -> bool
- *
- * Parse the given file and return true if it parses without errors. For
- * supported options, see Prism::parse.
- */
-static VALUE
-parse_file_success_p(int argc, VALUE *argv, VALUE self) {
- pm_string_t input;
- pm_options_t options = { 0 };
-
- VALUE encoded_filepath;
- file_options(argc, argv, &input, &options, &encoded_filepath);
-
- VALUE result = parse_input_success_p(&input, &options);
- pm_string_free(&input);
- pm_options_free(&options);
-
- return result;
-}
-
-/**
- * call-seq:
- * Prism::parse_file_failure?(filepath, **options) -> bool
- *
- * Parse the given file and return true if it parses with errors. For
- * supported options, see Prism::parse.
- */
-static VALUE
-parse_file_failure_p(int argc, VALUE *argv, VALUE self) {
- return RTEST(parse_file_success_p(argc, argv, self)) ? Qfalse : Qtrue;
-}
-
-/******************************************************************************/
-/* Initialization of the extension */
-/******************************************************************************/
-
-/**
- * The init function that Ruby calls when loading this extension.
- */
-RUBY_FUNC_EXPORTED void
-Init_prism(void) {
- // Make sure that the prism library version matches the expected version.
- // Otherwise something was compiled incorrectly.
- if (strcmp(pm_version(), EXPECTED_PRISM_VERSION) != 0) {
- rb_raise(
- rb_eRuntimeError,
- "The prism library version (%s) does not match the expected version (%s)",
- pm_version(),
- EXPECTED_PRISM_VERSION
- );
- }
-
- // Grab up references to all of the constants that we're going to need to
- // reference throughout this extension.
- rb_cPrism = rb_define_module("Prism");
- rb_cPrismNode = rb_define_class_under(rb_cPrism, "Node", rb_cObject);
- rb_cPrismSource = rb_define_class_under(rb_cPrism, "Source", rb_cObject);
- rb_cPrismToken = rb_define_class_under(rb_cPrism, "Token", rb_cObject);
- rb_cPrismLocation = rb_define_class_under(rb_cPrism, "Location", rb_cObject);
- rb_cPrismComment = rb_define_class_under(rb_cPrism, "Comment", rb_cObject);
- rb_cPrismInlineComment = rb_define_class_under(rb_cPrism, "InlineComment", rb_cPrismComment);
- rb_cPrismEmbDocComment = rb_define_class_under(rb_cPrism, "EmbDocComment", rb_cPrismComment);
- rb_cPrismMagicComment = rb_define_class_under(rb_cPrism, "MagicComment", rb_cObject);
- rb_cPrismParseError = rb_define_class_under(rb_cPrism, "ParseError", rb_cObject);
- rb_cPrismParseWarning = rb_define_class_under(rb_cPrism, "ParseWarning", rb_cObject);
- rb_cPrismResult = rb_define_class_under(rb_cPrism, "Result", rb_cObject);
- rb_cPrismParseResult = rb_define_class_under(rb_cPrism, "ParseResult", rb_cPrismResult);
- rb_cPrismLexResult = rb_define_class_under(rb_cPrism, "LexResult", rb_cPrismResult);
- rb_cPrismParseLexResult = rb_define_class_under(rb_cPrism, "ParseLexResult", rb_cPrismResult);
-
- // Intern all of the IDs eagerly that we support so that we don't have to do
- // it every time we parse.
- rb_id_option_command_line = rb_intern_const("command_line");
- rb_id_option_encoding = rb_intern_const("encoding");
- rb_id_option_filepath = rb_intern_const("filepath");
- rb_id_option_frozen_string_literal = rb_intern_const("frozen_string_literal");
- rb_id_option_line = rb_intern_const("line");
- rb_id_option_main_script = rb_intern_const("main_script");
- rb_id_option_partial_script = rb_intern_const("partial_script");
- rb_id_option_scopes = rb_intern_const("scopes");
- rb_id_option_version = rb_intern_const("version");
- rb_id_source_for = rb_intern("for");
-
- /**
- * The version of the prism library.
- */
- rb_define_const(rb_cPrism, "VERSION", rb_str_new2(EXPECTED_PRISM_VERSION));
-
- // First, the functions that have to do with lexing and parsing.
- rb_define_singleton_method(rb_cPrism, "lex", lex, -1);
- rb_define_singleton_method(rb_cPrism, "lex_file", lex_file, -1);
- rb_define_singleton_method(rb_cPrism, "parse", parse, -1);
- rb_define_singleton_method(rb_cPrism, "parse_file", parse_file, -1);
- rb_define_singleton_method(rb_cPrism, "profile", profile, -1);
- rb_define_singleton_method(rb_cPrism, "profile_file", profile_file, -1);
- rb_define_singleton_method(rb_cPrism, "parse_stream", parse_stream, -1);
- rb_define_singleton_method(rb_cPrism, "parse_comments", parse_comments, -1);
- rb_define_singleton_method(rb_cPrism, "parse_file_comments", parse_file_comments, -1);
- rb_define_singleton_method(rb_cPrism, "parse_lex", parse_lex, -1);
- rb_define_singleton_method(rb_cPrism, "parse_lex_file", parse_lex_file, -1);
- rb_define_singleton_method(rb_cPrism, "parse_success?", parse_success_p, -1);
- rb_define_singleton_method(rb_cPrism, "parse_failure?", parse_failure_p, -1);
- rb_define_singleton_method(rb_cPrism, "parse_file_success?", parse_file_success_p, -1);
- rb_define_singleton_method(rb_cPrism, "parse_file_failure?", parse_file_failure_p, -1);
-
-#ifndef PRISM_EXCLUDE_SERIALIZATION
- rb_define_singleton_method(rb_cPrism, "dump", dump, -1);
- rb_define_singleton_method(rb_cPrism, "dump_file", dump_file, -1);
-#endif
-
- // Next, initialize the other APIs.
- Init_prism_api_node();
- Init_prism_pack();
-}
diff --git a/prism/extension.h b/prism/extension.h
deleted file mode 100644
index d7ee0b7042..0000000000
--- a/prism/extension.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef PRISM_EXT_NODE_H
-#define PRISM_EXT_NODE_H
-
-#define EXPECTED_PRISM_VERSION "1.0.0"
-
-#include <ruby.h>
-#include <ruby/encoding.h>
-#include "prism.h"
-
-VALUE pm_source_new(const pm_parser_t *parser, rb_encoding *encoding);
-VALUE pm_token_new(const pm_parser_t *parser, const pm_token_t *token, rb_encoding *encoding, VALUE source);
-VALUE pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encoding, VALUE source);
-VALUE pm_integer_new(const pm_integer_t *integer);
-
-void Init_prism_api_node(void);
-void Init_prism_pack(void);
-RUBY_FUNC_EXPORTED void Init_prism(void);
-
-#endif
diff --git a/prism/node.h b/prism/node.h
deleted file mode 100644
index e8686a327c..0000000000
--- a/prism/node.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/**
- * @file node.h
- *
- * Functions related to nodes in the AST.
- */
-#ifndef PRISM_NODE_H
-#define PRISM_NODE_H
-
-#include "prism/defines.h"
-#include "prism/parser.h"
-#include "prism/util/pm_buffer.h"
-
-/**
- * Loop through each node in the node list, writing each node to the given
- * pm_node_t pointer.
- */
-#define PM_NODE_LIST_FOREACH(list, index, node) \
- for (size_t index = 0; index < (list)->size && ((node) = (list)->nodes[index]); index++)
-
-/**
- * Append a new node onto the end of the node list.
- *
- * @param list The list to append to.
- * @param node The node to append.
- */
-void pm_node_list_append(pm_node_list_t *list, pm_node_t *node);
-
-/**
- * Prepend a new node onto the beginning of the node list.
- *
- * @param list The list to prepend to.
- * @param node The node to prepend.
- */
-void pm_node_list_prepend(pm_node_list_t *list, pm_node_t *node);
-
-/**
- * Concatenate the given node list onto the end of the other node list.
- *
- * @param list The list to concatenate onto.
- * @param other The list to concatenate.
- */
-void pm_node_list_concat(pm_node_list_t *list, pm_node_list_t *other);
-
-/**
- * Free the internal memory associated with the given node list.
- *
- * @param list The list to free.
- */
-void pm_node_list_free(pm_node_list_t *list);
-
-/**
- * Deallocate a node and all of its children.
- *
- * @param parser The parser that owns the node.
- * @param node The node to deallocate.
- */
-PRISM_EXPORTED_FUNCTION void pm_node_destroy(pm_parser_t *parser, struct pm_node *node);
-
-/**
- * Returns a string representation of the given node type.
- *
- * @param node_type The node type to convert to a string.
- * @return A string representation of the given node type.
- */
-PRISM_EXPORTED_FUNCTION const char * pm_node_type_to_str(pm_node_type_t node_type);
-
-/**
- * Visit each of the nodes in this subtree using the given visitor callback. The
- * callback function will be called for each node in the subtree. If it returns
- * false, then that node's children will not be visited. If it returns true,
- * then the children will be visited. The data parameter is treated as an opaque
- * pointer and is passed to the visitor callback for consumers to use as they
- * see fit.
- *
- * As an example:
- *
- * ```c
- * #include "prism.h"
- *
- * bool visit(const pm_node_t *node, void *data) {
- * size_t *indent = (size_t *) data;
- * for (size_t i = 0; i < *indent * 2; i++) putc(' ', stdout);
- * printf("%s\n", pm_node_type_to_str(node->type));
- *
- * size_t next_indent = *indent + 1;
- * size_t *next_data = &next_indent;
- * pm_visit_child_nodes(node, visit, next_data);
- *
- * return false;
- * }
- *
- * int main(void) {
- * const char *source = "1 + 2; 3 + 4";
- * size_t size = strlen(source);
- *
- * pm_parser_t parser;
- * pm_options_t options = { 0 };
- * pm_parser_init(&parser, (const uint8_t *) source, size, &options);
- *
- * size_t indent = 0;
- * pm_node_t *node = pm_parse(&parser);
- *
- * size_t *data = &indent;
- * pm_visit_node(node, visit, data);
- *
- * pm_node_destroy(&parser, node);
- * pm_parser_free(&parser);
- * return EXIT_SUCCESS;
- * }
- * ```
- *
- * @param node The root node to start visiting from.
- * @param visitor The callback to call for each node in the subtree.
- * @param data An opaque pointer that is passed to the visitor callback.
- */
-PRISM_EXPORTED_FUNCTION void pm_visit_node(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data);
-
-/**
- * Visit the children of the given node with the given callback. This is the
- * default behavior for walking the tree that is called from pm_visit_node if
- * the callback returns true.
- *
- * @param node The node to visit the children of.
- * @param visitor The callback to call for each child node.
- * @param data An opaque pointer that is passed to the visitor callback.
- */
-PRISM_EXPORTED_FUNCTION void pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data);
-
-#endif
diff --git a/prism/options.c b/prism/options.c
deleted file mode 100644
index 6b52b2f296..0000000000
--- a/prism/options.c
+++ /dev/null
@@ -1,297 +0,0 @@
-#include "prism/options.h"
-
-/**
- * Set the shebang callback option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data) {
- options->shebang_callback = shebang_callback;
- options->shebang_callback_data = shebang_callback_data;
-}
-
-/**
- * Set the filepath option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_filepath_set(pm_options_t *options, const char *filepath) {
- pm_string_constant_init(&options->filepath, filepath, strlen(filepath));
-}
-
-/**
- * Set the encoding option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_encoding_set(pm_options_t *options, const char *encoding) {
- pm_string_constant_init(&options->encoding, encoding, strlen(encoding));
-}
-
-/**
- * Set the encoding_locked option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked) {
- options->encoding_locked = encoding_locked;
-}
-
-/**
- * Set the line option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_line_set(pm_options_t *options, int32_t line) {
- options->line = line;
-}
-
-/**
- * Set the frozen string literal option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal) {
- options->frozen_string_literal = frozen_string_literal ? PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED : PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED;
-}
-
-/**
- * Sets the command line option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_command_line_set(pm_options_t *options, uint8_t command_line) {
- options->command_line = command_line;
-}
-
-/**
- * Checks if the given slice represents a number.
- */
-static inline bool
-is_number(const char *string, size_t length) {
- return pm_strspn_decimal_digit((const uint8_t *) string, (ptrdiff_t) length) == length;
-}
-
-/**
- * Set the version option on the given options struct by parsing the given
- * string. If the string contains an invalid option, this returns false.
- * Otherwise, it returns true.
- */
-PRISM_EXPORTED_FUNCTION bool
-pm_options_version_set(pm_options_t *options, const char *version, size_t length) {
- if (version == NULL) {
- options->version = PM_OPTIONS_VERSION_LATEST;
- return true;
- }
-
- if (length == 3) {
- if (strncmp(version, "3.3", 3) == 0) {
- options->version = PM_OPTIONS_VERSION_CRUBY_3_3;
- return true;
- }
-
- if (strncmp(version, "3.4", 3) == 0) {
- options->version = PM_OPTIONS_VERSION_LATEST;
- return true;
- }
-
- return false;
- }
-
- if (length >= 4) {
- if (strncmp(version, "3.3.", 4) == 0 && is_number(version + 4, length - 4)) {
- options->version = PM_OPTIONS_VERSION_CRUBY_3_3;
- return true;
- }
-
- if (strncmp(version, "3.4.", 4) == 0 && is_number(version + 4, length - 4)) {
- options->version = PM_OPTIONS_VERSION_LATEST;
- return true;
- }
- }
-
- if (length >= 6) {
- if (strncmp(version, "latest", 7) == 0) { // 7 to compare the \0 as well
- options->version = PM_OPTIONS_VERSION_LATEST;
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * Set the main script option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_main_script_set(pm_options_t *options, bool main_script) {
- options->main_script = main_script;
-}
-
-/**
- * Set the partial script option on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_partial_script_set(pm_options_t *options, bool partial_script) {
- options->partial_script = partial_script;
-}
-
-// For some reason, GCC analyzer thinks we're leaking allocated scopes and
-// locals here, even though we definitely aren't. This is a false positive.
-// Ideally we wouldn't need to suppress this.
-#if defined(__GNUC__) && (__GNUC__ >= 10)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
-#endif
-
-/**
- * Allocate and zero out the scopes array on the given options struct.
- */
-PRISM_EXPORTED_FUNCTION bool
-pm_options_scopes_init(pm_options_t *options, size_t scopes_count) {
- options->scopes_count = scopes_count;
- options->scopes = xcalloc(scopes_count, sizeof(pm_options_scope_t));
- return options->scopes != NULL;
-}
-
-/**
- * Return a pointer to the scope at the given index within the given options.
- */
-PRISM_EXPORTED_FUNCTION const pm_options_scope_t *
-pm_options_scope_get(const pm_options_t *options, size_t index) {
- return &options->scopes[index];
-}
-
-/**
- * Create a new options scope struct. This will hold a set of locals that are in
- * scope surrounding the code that is being parsed.
- */
-PRISM_EXPORTED_FUNCTION bool
-pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count) {
- scope->locals_count = locals_count;
- scope->locals = xcalloc(locals_count, sizeof(pm_string_t));
- return scope->locals != NULL;
-}
-
-/**
- * Return a pointer to the local at the given index within the given scope.
- */
-PRISM_EXPORTED_FUNCTION const pm_string_t *
-pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index) {
- return &scope->locals[index];
-}
-
-/**
- * Free the internal memory associated with the options.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_options_free(pm_options_t *options) {
- pm_string_free(&options->filepath);
- pm_string_free(&options->encoding);
-
- for (size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
- pm_options_scope_t *scope = &options->scopes[scope_index];
-
- for (size_t local_index = 0; local_index < scope->locals_count; local_index++) {
- pm_string_free(&scope->locals[local_index]);
- }
-
- xfree(scope->locals);
- }
-
- xfree(options->scopes);
-}
-
-/**
- * Read a 32-bit unsigned integer from a pointer. This function is used to read
- * the options that are passed into the parser from the Ruby implementation. It
- * handles aligned and unaligned reads.
- */
-static uint32_t
-pm_options_read_u32(const char *data) {
- if (((uintptr_t) data) % sizeof(uint32_t) == 0) {
- return *((uint32_t *) data);
- } else {
- uint32_t value;
- memcpy(&value, data, sizeof(uint32_t));
- return value;
- }
-}
-
-/**
- * Read a 32-bit signed integer from a pointer. This function is used to read
- * the options that are passed into the parser from the Ruby implementation. It
- * handles aligned and unaligned reads.
- */
-static int32_t
-pm_options_read_s32(const char *data) {
- if (((uintptr_t) data) % sizeof(int32_t) == 0) {
- return *((int32_t *) data);
- } else {
- int32_t value;
- memcpy(&value, data, sizeof(int32_t));
- return value;
- }
-}
-
-/**
- * Deserialize an options struct from the given binary string. This is used to
- * pass options to the parser from an FFI call so that consumers of the library
- * from an FFI perspective don't have to worry about the structure of our
- * options structs. Since the source of these calls will be from Ruby
- * implementation internals we assume it is from a trusted source.
- */
-void
-pm_options_read(pm_options_t *options, const char *data) {
- options->line = 1; // default
- if (data == NULL) return;
-
- uint32_t filepath_length = pm_options_read_u32(data);
- data += 4;
-
- if (filepath_length > 0) {
- pm_string_constant_init(&options->filepath, data, filepath_length);
- data += filepath_length;
- }
-
- options->line = pm_options_read_s32(data);
- data += 4;
-
- uint32_t encoding_length = pm_options_read_u32(data);
- data += 4;
-
- if (encoding_length > 0) {
- pm_string_constant_init(&options->encoding, data, encoding_length);
- data += encoding_length;
- }
-
- options->frozen_string_literal = (int8_t) *data++;
- options->command_line = (uint8_t) *data++;
- options->version = (pm_options_version_t) *data++;
- options->encoding_locked = ((uint8_t) *data++) > 0;
- options->main_script = ((uint8_t) *data++) > 0;
- options->partial_script = ((uint8_t) *data++) > 0;
-
- uint32_t scopes_count = pm_options_read_u32(data);
- data += 4;
-
- if (scopes_count > 0) {
- if (!pm_options_scopes_init(options, scopes_count)) return;
-
- for (size_t scope_index = 0; scope_index < scopes_count; scope_index++) {
- uint32_t locals_count = pm_options_read_u32(data);
- data += 4;
-
- pm_options_scope_t *scope = &options->scopes[scope_index];
- if (!pm_options_scope_init(scope, locals_count)) {
- pm_options_free(options);
- return;
- }
-
- for (size_t local_index = 0; local_index < locals_count; local_index++) {
- uint32_t local_length = pm_options_read_u32(data);
- data += 4;
-
- pm_string_constant_init(&scope->locals[local_index], data, local_length);
- data += local_length;
- }
- }
- }
-}
-
-#if defined(__GNUC__) && (__GNUC__ >= 10)
-#pragma GCC diagnostic pop
-#endif
diff --git a/prism/options.h b/prism/options.h
deleted file mode 100644
index c96fa684ac..0000000000
--- a/prism/options.h
+++ /dev/null
@@ -1,396 +0,0 @@
-/**
- * @file options.h
- *
- * The options that can be passed to parsing.
- */
-#ifndef PRISM_OPTIONS_H
-#define PRISM_OPTIONS_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_char.h"
-#include "prism/util/pm_string.h"
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-/**
- * String literals should be made frozen.
- */
-#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED ((int8_t) -1)
-
-/**
- * String literals may be frozen or mutable depending on the implementation
- * default.
- */
-#define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET ((int8_t) 0)
-
-/**
- * String literals should be made mutable.
- */
-#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED ((int8_t) 1)
-
-/**
- * A scope of locals surrounding the code that is being parsed.
- */
-typedef struct pm_options_scope {
- /** The number of locals in the scope. */
- size_t locals_count;
-
- /** The names of the locals in the scope. */
- pm_string_t *locals;
-} pm_options_scope_t;
-
-// Forward declaration needed by the callback typedef.
-struct pm_options;
-
-/**
- * The callback called when additional switches are found in a shebang comment
- * that need to be processed by the runtime.
- *
- * @param options The options struct that may be updated by this callback.
- * Certain fields will be checked for changes, specifically encoding,
- * command_line, and frozen_string_literal.
- * @param source The source of the shebang comment.
- * @param length The length of the source.
- * @param shebang_callback_data Any additional data that should be passed along
- * to the callback.
- */
-typedef void (*pm_options_shebang_callback_t)(struct pm_options *options, const uint8_t *source, size_t length, void *shebang_callback_data);
-
-/**
- * The version of Ruby syntax that we should be parsing with. This is used to
- * allow consumers to specify which behavior they want in case they need to
- * parse in the same way as a specific version of CRuby would have.
- */
-typedef enum {
- /** The current version of prism. */
- PM_OPTIONS_VERSION_LATEST = 0,
-
- /** The vendored version of prism in CRuby 3.3.x. */
- PM_OPTIONS_VERSION_CRUBY_3_3 = 1
-} pm_options_version_t;
-
-/**
- * The options that can be passed to the parser.
- */
-typedef struct pm_options {
- /**
- * The callback to call when additional switches are found in a shebang
- * comment.
- */
- pm_options_shebang_callback_t shebang_callback;
-
- /**
- * Any additional data that should be passed along to the shebang callback
- * if one was set.
- */
- void *shebang_callback_data;
-
- /** The name of the file that is currently being parsed. */
- pm_string_t filepath;
-
- /**
- * The line within the file that the parse starts on. This value is
- * 1-indexed.
- */
- int32_t line;
-
- /**
- * The name of the encoding that the source file is in. Note that this must
- * correspond to a name that can be found with Encoding.find in Ruby.
- */
- pm_string_t encoding;
-
- /**
- * The number of scopes surrounding the code that is being parsed.
- */
- size_t scopes_count;
-
- /**
- * The scopes surrounding the code that is being parsed. For most parses
- * this will be NULL, but for evals it will be the locals that are in scope
- * surrounding the eval. Scopes are ordered from the outermost scope to the
- * innermost one.
- */
- pm_options_scope_t *scopes;
-
- /**
- * The version of prism that we should be parsing with. This is used to
- * allow consumers to specify which behavior they want in case they need to
- * parse exactly as a specific version of CRuby.
- */
- pm_options_version_t version;
-
- /** A bitset of the various options that were set on the command line. */
- uint8_t command_line;
-
- /**
- * Whether or not the frozen string literal option has been set.
- * May be:
- * - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
- * - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
- * - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
- */
- int8_t frozen_string_literal;
-
- /**
- * Whether or not the encoding magic comments should be respected. This is a
- * niche use-case where you want to parse a file with a specific encoding
- * but ignore any encoding magic comments at the top of the file.
- */
- bool encoding_locked;
-
- /**
- * When the file being parsed is the main script, the shebang will be
- * considered for command-line flags (or for implicit -x). The caller needs
- * to pass this information to the parser so that it can behave correctly.
- */
- bool main_script;
-
- /**
- * When the file being parsed is considered a "partial" script, jumps will
- * not be marked as errors if they are not contained within loops/blocks.
- * This is used in the case that you're parsing a script that you know will
- * be embedded inside another script later, but you do not have that context
- * yet. For example, when parsing an ERB template that will be evaluated
- * inside another script.
- */
- bool partial_script;
-} pm_options_t;
-
-/**
- * A bit representing whether or not the command line -a option was set. -a
- * splits the input line $_ into $F.
- */
-static const uint8_t PM_OPTIONS_COMMAND_LINE_A = 0x1;
-
-/**
- * A bit representing whether or not the command line -e option was set. -e
- * allow the user to specify a script to be executed. This is necessary for
- * prism to know because certain warnings are not generated when -e is used.
- */
-static const uint8_t PM_OPTIONS_COMMAND_LINE_E = 0x2;
-
-/**
- * A bit representing whether or not the command line -l option was set. -l
- * chomps the input line by default.
- */
-static const uint8_t PM_OPTIONS_COMMAND_LINE_L = 0x4;
-
-/**
- * A bit representing whether or not the command line -n option was set. -n
- * wraps the script in a while gets loop.
- */
-static const uint8_t PM_OPTIONS_COMMAND_LINE_N = 0x8;
-
-/**
- * A bit representing whether or not the command line -p option was set. -p
- * prints the value of $_ at the end of each loop.
- */
-static const uint8_t PM_OPTIONS_COMMAND_LINE_P = 0x10;
-
-/**
- * A bit representing whether or not the command line -x option was set. -x
- * searches the input file for a shebang that matches the current Ruby engine.
- */
-static const uint8_t PM_OPTIONS_COMMAND_LINE_X = 0x20;
-
-/**
- * Set the shebang callback option on the given options struct.
- *
- * @param options The options struct to set the shebang callback on.
- * @param shebang_callback The shebang callback to set.
- * @param shebang_callback_data Any additional data that should be passed along
- * to the callback.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data);
-
-/**
- * Set the filepath option on the given options struct.
- *
- * @param options The options struct to set the filepath on.
- * @param filepath The filepath to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_filepath_set(pm_options_t *options, const char *filepath);
-
-/**
- * Set the line option on the given options struct.
- *
- * @param options The options struct to set the line on.
- * @param line The line to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_line_set(pm_options_t *options, int32_t line);
-
-/**
- * Set the encoding option on the given options struct.
- *
- * @param options The options struct to set the encoding on.
- * @param encoding The encoding to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_encoding_set(pm_options_t *options, const char *encoding);
-
-/**
- * Set the encoding_locked option on the given options struct.
- *
- * @param options The options struct to set the encoding_locked value on.
- * @param encoding_locked The encoding_locked value to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked);
-
-/**
- * Set the frozen string literal option on the given options struct.
- *
- * @param options The options struct to set the frozen string literal value on.
- * @param frozen_string_literal The frozen string literal value to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal);
-
-/**
- * Sets the command line option on the given options struct.
- *
- * @param options The options struct to set the command line option on.
- * @param command_line The command_line value to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_command_line_set(pm_options_t *options, uint8_t command_line);
-
-/**
- * Set the version option on the given options struct by parsing the given
- * string. If the string contains an invalid option, this returns false.
- * Otherwise, it returns true.
- *
- * @param options The options struct to set the version on.
- * @param version The version to set.
- * @param length The length of the version string.
- * @return Whether or not the version was parsed successfully.
- */
-PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const char *version, size_t length);
-
-/**
- * Set the main script option on the given options struct.
- *
- * @param options The options struct to set the main script value on.
- * @param main_script The main script value to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_main_script_set(pm_options_t *options, bool main_script);
-
-/**
- * Set the partial script option on the given options struct.
- *
- * @param options The options struct to set the partial script value on.
- * @param partial_script The partial script value to set.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_partial_script_set(pm_options_t *options, bool partial_script);
-
-/**
- * Allocate and zero out the scopes array on the given options struct.
- *
- * @param options The options struct to initialize the scopes array on.
- * @param scopes_count The number of scopes to allocate.
- * @return Whether or not the scopes array was initialized successfully.
- */
-PRISM_EXPORTED_FUNCTION bool pm_options_scopes_init(pm_options_t *options, size_t scopes_count);
-
-/**
- * Return a pointer to the scope at the given index within the given options.
- *
- * @param options The options struct to get the scope from.
- * @param index The index of the scope to get.
- * @return A pointer to the scope at the given index.
- */
-PRISM_EXPORTED_FUNCTION const pm_options_scope_t * pm_options_scope_get(const pm_options_t *options, size_t index);
-
-/**
- * Create a new options scope struct. This will hold a set of locals that are in
- * scope surrounding the code that is being parsed.
- *
- * @param scope The scope struct to initialize.
- * @param locals_count The number of locals to allocate.
- * @return Whether or not the scope was initialized successfully.
- */
-PRISM_EXPORTED_FUNCTION bool pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count);
-
-/**
- * Return a pointer to the local at the given index within the given scope.
- *
- * @param scope The scope struct to get the local from.
- * @param index The index of the local to get.
- * @return A pointer to the local at the given index.
- */
-PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index);
-
-/**
- * Free the internal memory associated with the options.
- *
- * @param options The options struct whose internal memory should be freed.
- */
-PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options);
-
-/**
- * Deserialize an options struct from the given binary string. This is used to
- * pass options to the parser from an FFI call so that consumers of the library
- * from an FFI perspective don't have to worry about the structure of our
- * options structs. Since the source of these calls will be from Ruby
- * implementation internals we assume it is from a trusted source.
- *
- * `data` is assumed to be a valid pointer pointing to well-formed data. The
- * layout of this data should be the same every time, and is described below:
- *
- * | # bytes | field |
- * | ------- | -------------------------- |
- * | `4` | the length of the filepath |
- * | ... | the filepath bytes |
- * | `4` | the line number |
- * | `4` | the length the encoding |
- * | ... | the encoding bytes |
- * | `1` | frozen string literal |
- * | `1` | -p command line option |
- * | `1` | -n command line option |
- * | `1` | -l command line option |
- * | `1` | -a command line option |
- * | `1` | the version |
- * | `1` | encoding locked |
- * | `1` | main script |
- * | `1` | partial script |
- * | `4` | the number of scopes |
- * | ... | the scopes |
- *
- * The version field is an enum, so it should be one of the following values:
- *
- * | value | version |
- * | ----- | ------------------------- |
- * | `0` | use the latest version of prism |
- * | `1` | use the version of prism that is vendored in CRuby 3.3.0 |
- *
- * Each scope is laid out as follows:
- *
- * | # bytes | field |
- * | ------- | -------------------------- |
- * | `4` | the number of locals |
- * | ... | the locals |
- *
- * Each local is laid out as follows:
- *
- * | # bytes | field |
- * | ------- | -------------------------- |
- * | `4` | the length of the local |
- * | ... | the local bytes |
- *
- * Some additional things to note about this layout:
- *
- * * The filepath can have a length of 0, in which case we'll consider it an
- * empty string.
- * * The line number should be 0-indexed.
- * * The encoding can have a length of 0, in which case we'll use the default
- * encoding (UTF-8). If it's not 0, it should correspond to a name of an
- * encoding that can be passed to `Encoding.find` in Ruby.
- * * The frozen string literal, encoding locked, main script, and partial script
- * fields are booleans, so their values should be either 0 or 1.
- * * The number of scopes can be 0.
- *
- * @param options The options struct to deserialize into.
- * @param data The binary string to deserialize from.
- */
-void pm_options_read(pm_options_t *options, const char *data);
-
-#endif
diff --git a/prism/pack.c b/prism/pack.c
deleted file mode 100644
index 1388ca8a3b..0000000000
--- a/prism/pack.c
+++ /dev/null
@@ -1,509 +0,0 @@
-#include "prism/pack.h"
-
-// We optionally support parsing String#pack templates. For systems that don't
-// want or need this functionality, it can be turned off with the
-// PRISM_EXCLUDE_PACK define.
-#ifdef PRISM_EXCLUDE_PACK
-
-void pm_pack_parse(void) {}
-
-#else
-
-#include <stdbool.h>
-#include <errno.h>
-
-static uintmax_t
-strtoumaxc(const char **format) {
- uintmax_t value = 0;
- while (**format >= '0' && **format <= '9') {
- if (value > UINTMAX_MAX / 10) {
- errno = ERANGE;
- }
- value = value * 10 + ((uintmax_t) (**format - '0'));
- (*format)++;
- }
- return value;
-}
-
-PRISM_EXPORTED_FUNCTION pm_pack_result
-pm_pack_parse(
- pm_pack_variant variant,
- const char **format,
- const char *format_end,
- pm_pack_type *type,
- pm_pack_signed *signed_type,
- pm_pack_endian *endian,
- pm_pack_size *size,
- pm_pack_length_type *length_type,
- uint64_t *length,
- pm_pack_encoding *encoding
-) {
- if (*encoding == PM_PACK_ENCODING_START) {
- *encoding = PM_PACK_ENCODING_US_ASCII;
- }
-
- if (*format == format_end) {
- *type = PM_PACK_END;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- *length_type = PM_PACK_LENGTH_NA;
- return PM_PACK_OK;
- }
-
- *length_type = PM_PACK_LENGTH_FIXED;
- *length = 1;
- bool length_changed_allowed = true;
-
- char directive = **format;
- (*format)++;
- switch (directive) {
- case ' ':
- case '\t':
- case '\n':
- case '\v':
- case '\f':
- case '\r':
- *type = PM_PACK_SPACE;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- *length_type = PM_PACK_LENGTH_NA;
- *length = 0;
- return PM_PACK_OK;
- case '#':
- while ((*format < format_end) && (**format != '\n')) {
- (*format)++;
- }
- *type = PM_PACK_COMMENT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- *length_type = PM_PACK_LENGTH_NA;
- *length = 0;
- return PM_PACK_OK;
- case 'C':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_AGNOSTIC_ENDIAN;
- *size = PM_PACK_SIZE_8;
- break;
- case 'S':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_16;
- break;
- case 'L':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_32;
- break;
- case 'Q':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_64;
- break;
- case 'J':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_P;
- break;
- case 'c':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_SIGNED;
- *endian = PM_PACK_AGNOSTIC_ENDIAN;
- *size = PM_PACK_SIZE_8;
- break;
- case 's':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_SIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_16;
- break;
- case 'l':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_SIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_32;
- break;
- case 'q':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_SIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_64;
- break;
- case 'j':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_SIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_P;
- break;
- case 'I':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_INT;
- break;
- case 'i':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_SIGNED;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_INT;
- break;
- case 'n':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_BIG_ENDIAN;
- *size = PM_PACK_SIZE_16;
- length_changed_allowed = false;
- break;
- case 'N':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_BIG_ENDIAN;
- *size = PM_PACK_SIZE_32;
- length_changed_allowed = false;
- break;
- case 'v':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_LITTLE_ENDIAN;
- *size = PM_PACK_SIZE_16;
- length_changed_allowed = false;
- break;
- case 'V':
- *type = PM_PACK_INTEGER;
- *signed_type = PM_PACK_UNSIGNED;
- *endian = PM_PACK_LITTLE_ENDIAN;
- *size = PM_PACK_SIZE_32;
- length_changed_allowed = false;
- break;
- case 'U':
- *type = PM_PACK_UTF8;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'w':
- *type = PM_PACK_BER;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'D':
- case 'd':
- *type = PM_PACK_FLOAT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_64;
- break;
- case 'F':
- case 'f':
- *type = PM_PACK_FLOAT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_NATIVE_ENDIAN;
- *size = PM_PACK_SIZE_32;
- break;
- case 'E':
- *type = PM_PACK_FLOAT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_LITTLE_ENDIAN;
- *size = PM_PACK_SIZE_64;
- break;
- case 'e':
- *type = PM_PACK_FLOAT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_LITTLE_ENDIAN;
- *size = PM_PACK_SIZE_32;
- break;
- case 'G':
- *type = PM_PACK_FLOAT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_BIG_ENDIAN;
- *size = PM_PACK_SIZE_64;
- break;
- case 'g':
- *type = PM_PACK_FLOAT;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_BIG_ENDIAN;
- *size = PM_PACK_SIZE_32;
- break;
- case 'A':
- *type = PM_PACK_STRING_SPACE_PADDED;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'a':
- *type = PM_PACK_STRING_NULL_PADDED;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'Z':
- *type = PM_PACK_STRING_NULL_TERMINATED;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'B':
- *type = PM_PACK_STRING_MSB;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'b':
- *type = PM_PACK_STRING_LSB;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'H':
- *type = PM_PACK_STRING_HEX_HIGH;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'h':
- *type = PM_PACK_STRING_HEX_LOW;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'u':
- *type = PM_PACK_STRING_UU;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'M':
- *type = PM_PACK_STRING_MIME;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'm':
- *type = PM_PACK_STRING_BASE64;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'P':
- *type = PM_PACK_STRING_FIXED;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'p':
- *type = PM_PACK_STRING_POINTER;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case '@':
- *type = PM_PACK_MOVE;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'X':
- *type = PM_PACK_BACK;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case 'x':
- *type = PM_PACK_NULL;
- *signed_type = PM_PACK_SIGNED_NA;
- *endian = PM_PACK_ENDIAN_NA;
- *size = PM_PACK_SIZE_NA;
- break;
- case '%':
- return PM_PACK_ERROR_UNSUPPORTED_DIRECTIVE;
- default:
- return PM_PACK_ERROR_UNKNOWN_DIRECTIVE;
- }
-
- bool explicit_endian = false;
-
- while (*format < format_end) {
- switch (**format) {
- case '_':
- case '!':
- (*format)++;
- if (*type != PM_PACK_INTEGER || !length_changed_allowed) {
- return PM_PACK_ERROR_BANG_NOT_ALLOWED;
- }
- switch (*size) {
- case PM_PACK_SIZE_SHORT:
- case PM_PACK_SIZE_INT:
- case PM_PACK_SIZE_LONG:
- case PM_PACK_SIZE_LONG_LONG:
- break;
- case PM_PACK_SIZE_16:
- *size = PM_PACK_SIZE_SHORT;
- break;
- case PM_PACK_SIZE_32:
- *size = PM_PACK_SIZE_LONG;
- break;
- case PM_PACK_SIZE_64:
- *size = PM_PACK_SIZE_LONG_LONG;
- break;
- case PM_PACK_SIZE_P:
- break;
- default:
- return PM_PACK_ERROR_BANG_NOT_ALLOWED;
- }
- break;
- case '<':
- (*format)++;
- if (explicit_endian) {
- return PM_PACK_ERROR_DOUBLE_ENDIAN;
- }
- *endian = PM_PACK_LITTLE_ENDIAN;
- explicit_endian = true;
- break;
- case '>':
- (*format)++;
- if (explicit_endian) {
- return PM_PACK_ERROR_DOUBLE_ENDIAN;
- }
- *endian = PM_PACK_BIG_ENDIAN;
- explicit_endian = true;
- break;
- default:
- goto exit_modifier_loop;
- }
- }
-
-exit_modifier_loop:
-
- if (variant == PM_PACK_VARIANT_UNPACK && *type == PM_PACK_MOVE) {
- *length = 0;
- }
-
- if (*format < format_end) {
- if (**format == '*') {
- switch (*type) {
- case PM_PACK_NULL:
- case PM_PACK_BACK:
- switch (variant) {
- case PM_PACK_VARIANT_PACK:
- *length_type = PM_PACK_LENGTH_FIXED;
- break;
- case PM_PACK_VARIANT_UNPACK:
- *length_type = PM_PACK_LENGTH_MAX;
- break;
- }
- *length = 0;
- break;
-
- case PM_PACK_MOVE:
- switch (variant) {
- case PM_PACK_VARIANT_PACK:
- *length_type = PM_PACK_LENGTH_FIXED;
- break;
- case PM_PACK_VARIANT_UNPACK:
- *length_type = PM_PACK_LENGTH_RELATIVE;
- break;
- }
- *length = 0;
- break;
-
- case PM_PACK_STRING_UU:
- *length_type = PM_PACK_LENGTH_FIXED;
- *length = 0;
- break;
-
- case PM_PACK_STRING_FIXED:
- switch (variant) {
- case PM_PACK_VARIANT_PACK:
- *length_type = PM_PACK_LENGTH_FIXED;
- *length = 1;
- break;
- case PM_PACK_VARIANT_UNPACK:
- *length_type = PM_PACK_LENGTH_MAX;
- *length = 0;
- break;
- }
- break;
-
- case PM_PACK_STRING_MIME:
- case PM_PACK_STRING_BASE64:
- *length_type = PM_PACK_LENGTH_FIXED;
- *length = 1;
- break;
-
- default:
- *length_type = PM_PACK_LENGTH_MAX;
- *length = 0;
- break;
- }
-
- (*format)++;
- } else if (**format >= '0' && **format <= '9') {
- errno = 0;
- *length_type = PM_PACK_LENGTH_FIXED;
- #if UINTMAX_MAX < UINT64_MAX
- #error "prism's design assumes uintmax_t is at least as large as uint64_t"
- #endif
- uintmax_t length_max = strtoumaxc(format);
- if (errno || length_max > UINT64_MAX) {
- return PM_PACK_ERROR_LENGTH_TOO_BIG;
- }
- *length = (uint64_t) length_max;
- }
- }
-
- switch (*type) {
- case PM_PACK_UTF8:
- /* if encoding is US-ASCII, upgrade to UTF-8 */
- if (*encoding == PM_PACK_ENCODING_US_ASCII) {
- *encoding = PM_PACK_ENCODING_UTF_8;
- }
- break;
- case PM_PACK_STRING_MIME:
- case PM_PACK_STRING_BASE64:
- case PM_PACK_STRING_UU:
- /* keep US-ASCII (do nothing) */
- break;
- default:
- /* fall back to BINARY */
- *encoding = PM_PACK_ENCODING_ASCII_8BIT;
- break;
- }
-
- return PM_PACK_OK;
-}
-
-PRISM_EXPORTED_FUNCTION size_t
-pm_size_to_native(pm_pack_size size) {
- switch (size) {
- case PM_PACK_SIZE_SHORT:
- return sizeof(short);
- case PM_PACK_SIZE_INT:
- return sizeof(int);
- case PM_PACK_SIZE_LONG:
- return sizeof(long);
- case PM_PACK_SIZE_LONG_LONG:
- return sizeof(long long);
- case PM_PACK_SIZE_8:
- return 1;
- case PM_PACK_SIZE_16:
- return 2;
- case PM_PACK_SIZE_32:
- return 4;
- case PM_PACK_SIZE_64:
- return 8;
- case PM_PACK_SIZE_P:
- return sizeof(void *);
- default:
- return 0;
- }
-}
-
-#endif
diff --git a/prism/pack.h b/prism/pack.h
deleted file mode 100644
index 0b0b4b19cc..0000000000
--- a/prism/pack.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/**
- * @file pack.h
- *
- * A pack template string parser.
- */
-#ifndef PRISM_PACK_H
-#define PRISM_PACK_H
-
-#include "prism/defines.h"
-
-// We optionally support parsing String#pack templates. For systems that don't
-// want or need this functionality, it can be turned off with the
-// PRISM_EXCLUDE_PACK define.
-#ifdef PRISM_EXCLUDE_PACK
-
-void pm_pack_parse(void);
-
-#else
-
-#include <stdint.h>
-#include <stdlib.h>
-
-/** The version of the pack template language that we are parsing. */
-typedef enum pm_pack_version {
- PM_PACK_VERSION_3_2_0
-} pm_pack_version;
-
-/** The type of pack template we are parsing. */
-typedef enum pm_pack_variant {
- PM_PACK_VARIANT_PACK,
- PM_PACK_VARIANT_UNPACK
-} pm_pack_variant;
-
-/** A directive within the pack template. */
-typedef enum pm_pack_type {
- PM_PACK_SPACE,
- PM_PACK_COMMENT,
- PM_PACK_INTEGER,
- PM_PACK_UTF8,
- PM_PACK_BER,
- PM_PACK_FLOAT,
- PM_PACK_STRING_SPACE_PADDED,
- PM_PACK_STRING_NULL_PADDED,
- PM_PACK_STRING_NULL_TERMINATED,
- PM_PACK_STRING_MSB,
- PM_PACK_STRING_LSB,
- PM_PACK_STRING_HEX_HIGH,
- PM_PACK_STRING_HEX_LOW,
- PM_PACK_STRING_UU,
- PM_PACK_STRING_MIME,
- PM_PACK_STRING_BASE64,
- PM_PACK_STRING_FIXED,
- PM_PACK_STRING_POINTER,
- PM_PACK_MOVE,
- PM_PACK_BACK,
- PM_PACK_NULL,
- PM_PACK_END
-} pm_pack_type;
-
-/** The signness of a pack directive. */
-typedef enum pm_pack_signed {
- PM_PACK_UNSIGNED,
- PM_PACK_SIGNED,
- PM_PACK_SIGNED_NA
-} pm_pack_signed;
-
-/** The endianness of a pack directive. */
-typedef enum pm_pack_endian {
- PM_PACK_AGNOSTIC_ENDIAN,
- PM_PACK_LITTLE_ENDIAN, // aka 'VAX', or 'V'
- PM_PACK_BIG_ENDIAN, // aka 'network', or 'N'
- PM_PACK_NATIVE_ENDIAN,
- PM_PACK_ENDIAN_NA
-} pm_pack_endian;
-
-/** The size of an integer pack directive. */
-typedef enum pm_pack_size {
- PM_PACK_SIZE_SHORT,
- PM_PACK_SIZE_INT,
- PM_PACK_SIZE_LONG,
- PM_PACK_SIZE_LONG_LONG,
- PM_PACK_SIZE_8,
- PM_PACK_SIZE_16,
- PM_PACK_SIZE_32,
- PM_PACK_SIZE_64,
- PM_PACK_SIZE_P,
- PM_PACK_SIZE_NA
-} pm_pack_size;
-
-/** The type of length of a pack directive. */
-typedef enum pm_pack_length_type {
- PM_PACK_LENGTH_FIXED,
- PM_PACK_LENGTH_MAX,
- PM_PACK_LENGTH_RELATIVE, // special case for unpack @*
- PM_PACK_LENGTH_NA
-} pm_pack_length_type;
-
-/** The type of encoding for a pack template string. */
-typedef enum pm_pack_encoding {
- PM_PACK_ENCODING_START,
- PM_PACK_ENCODING_ASCII_8BIT,
- PM_PACK_ENCODING_US_ASCII,
- PM_PACK_ENCODING_UTF_8
-} pm_pack_encoding;
-
-/** The result of parsing a pack template. */
-typedef enum pm_pack_result {
- PM_PACK_OK,
- PM_PACK_ERROR_UNSUPPORTED_DIRECTIVE,
- PM_PACK_ERROR_UNKNOWN_DIRECTIVE,
- PM_PACK_ERROR_LENGTH_TOO_BIG,
- PM_PACK_ERROR_BANG_NOT_ALLOWED,
- PM_PACK_ERROR_DOUBLE_ENDIAN
-} pm_pack_result;
-
-/**
- * Parse a single directive from a pack or unpack format string.
- *
- * @param variant (in) pack or unpack
- * @param format (in, out) the start of the next directive to parse on calling,
- * and advanced beyond the parsed directive on return, or as much of it as
- * was consumed until an error was encountered
- * @param format_end (in) the end of the format string
- * @param type (out) the type of the directive
- * @param signed_type (out) whether the value is signed
- * @param endian (out) the endianness of the value
- * @param size (out) the size of the value
- * @param length_type (out) what kind of length is specified
- * @param length (out) the length of the directive
- * @param encoding (in, out) takes the current encoding of the string which
- * would result from parsing the whole format string, and returns a possibly
- * changed directive - the encoding should be `PM_PACK_ENCODING_START` when
- * pm_pack_parse is called for the first directive in a format string
- *
- * @return `PM_PACK_OK` on success or `PM_PACK_ERROR_*` on error
- * @note Consult Ruby documentation for the meaning of directives.
- */
-PRISM_EXPORTED_FUNCTION pm_pack_result
-pm_pack_parse(
- pm_pack_variant variant,
- const char **format,
- const char *format_end,
- pm_pack_type *type,
- pm_pack_signed *signed_type,
- pm_pack_endian *endian,
- pm_pack_size *size,
- pm_pack_length_type *length_type,
- uint64_t *length,
- pm_pack_encoding *encoding
-);
-
-/**
- * Prism abstracts sizes away from the native system - this converts an abstract
- * size to a native size.
- *
- * @param size The abstract size to convert.
- * @return The native size.
- */
-PRISM_EXPORTED_FUNCTION size_t pm_size_to_native(pm_pack_size size);
-
-#endif
-
-#endif
diff --git a/prism/parser.h b/prism/parser.h
deleted file mode 100644
index 992729d655..0000000000
--- a/prism/parser.h
+++ /dev/null
@@ -1,933 +0,0 @@
-/**
- * @file parser.h
- *
- * The parser used to parse Ruby source.
- */
-#ifndef PRISM_PARSER_H
-#define PRISM_PARSER_H
-
-#include "prism/defines.h"
-#include "prism/ast.h"
-#include "prism/encoding.h"
-#include "prism/options.h"
-#include "prism/static_literals.h"
-#include "prism/util/pm_constant_pool.h"
-#include "prism/util/pm_list.h"
-#include "prism/util/pm_newline_list.h"
-#include "prism/util/pm_string.h"
-
-#include <stdbool.h>
-
-/**
- * This enum provides various bits that represent different kinds of states that
- * the lexer can track. This is used to determine which kind of token to return
- * based on the context of the parser.
- */
-typedef enum {
- PM_LEX_STATE_BIT_BEG,
- PM_LEX_STATE_BIT_END,
- PM_LEX_STATE_BIT_ENDARG,
- PM_LEX_STATE_BIT_ENDFN,
- PM_LEX_STATE_BIT_ARG,
- PM_LEX_STATE_BIT_CMDARG,
- PM_LEX_STATE_BIT_MID,
- PM_LEX_STATE_BIT_FNAME,
- PM_LEX_STATE_BIT_DOT,
- PM_LEX_STATE_BIT_CLASS,
- PM_LEX_STATE_BIT_LABEL,
- PM_LEX_STATE_BIT_LABELED,
- PM_LEX_STATE_BIT_FITEM
-} pm_lex_state_bit_t;
-
-/**
- * This enum combines the various bits from the above enum into individual
- * values that represent the various states of the lexer.
- */
-typedef enum {
- PM_LEX_STATE_NONE = 0,
- PM_LEX_STATE_BEG = (1 << PM_LEX_STATE_BIT_BEG),
- PM_LEX_STATE_END = (1 << PM_LEX_STATE_BIT_END),
- PM_LEX_STATE_ENDARG = (1 << PM_LEX_STATE_BIT_ENDARG),
- PM_LEX_STATE_ENDFN = (1 << PM_LEX_STATE_BIT_ENDFN),
- PM_LEX_STATE_ARG = (1 << PM_LEX_STATE_BIT_ARG),
- PM_LEX_STATE_CMDARG = (1 << PM_LEX_STATE_BIT_CMDARG),
- PM_LEX_STATE_MID = (1 << PM_LEX_STATE_BIT_MID),
- PM_LEX_STATE_FNAME = (1 << PM_LEX_STATE_BIT_FNAME),
- PM_LEX_STATE_DOT = (1 << PM_LEX_STATE_BIT_DOT),
- PM_LEX_STATE_CLASS = (1 << PM_LEX_STATE_BIT_CLASS),
- PM_LEX_STATE_LABEL = (1 << PM_LEX_STATE_BIT_LABEL),
- PM_LEX_STATE_LABELED = (1 << PM_LEX_STATE_BIT_LABELED),
- PM_LEX_STATE_FITEM = (1 << PM_LEX_STATE_BIT_FITEM),
- PM_LEX_STATE_BEG_ANY = PM_LEX_STATE_BEG | PM_LEX_STATE_MID | PM_LEX_STATE_CLASS,
- PM_LEX_STATE_ARG_ANY = PM_LEX_STATE_ARG | PM_LEX_STATE_CMDARG,
- PM_LEX_STATE_END_ANY = PM_LEX_STATE_END | PM_LEX_STATE_ENDARG | PM_LEX_STATE_ENDFN
-} pm_lex_state_t;
-
-/**
- * The type of quote that a heredoc uses.
- */
-typedef enum {
- PM_HEREDOC_QUOTE_NONE,
- PM_HEREDOC_QUOTE_SINGLE = '\'',
- PM_HEREDOC_QUOTE_DOUBLE = '"',
- PM_HEREDOC_QUOTE_BACKTICK = '`',
-} pm_heredoc_quote_t;
-
-/**
- * The type of indentation that a heredoc uses.
- */
-typedef enum {
- PM_HEREDOC_INDENT_NONE,
- PM_HEREDOC_INDENT_DASH,
- PM_HEREDOC_INDENT_TILDE,
-} pm_heredoc_indent_t;
-
-/**
- * All of the information necessary to store to lexing a heredoc.
- */
-typedef struct {
- /** A pointer to the start of the heredoc identifier. */
- const uint8_t *ident_start;
-
- /** The length of the heredoc identifier. */
- size_t ident_length;
-
- /** The type of quote that the heredoc uses. */
- pm_heredoc_quote_t quote;
-
- /** The type of indentation that the heredoc uses. */
- pm_heredoc_indent_t indent;
-} pm_heredoc_lex_mode_t;
-
-/**
- * When lexing Ruby source, the lexer has a small amount of state to tell which
- * kind of token it is currently lexing. For example, when we find the start of
- * a string, the first token that we return is a TOKEN_STRING_BEGIN token. After
- * that the lexer is now in the PM_LEX_STRING mode, and will return tokens that
- * are found as part of a string.
- */
-typedef struct pm_lex_mode {
- /** The type of this lex mode. */
- enum {
- /** This state is used when any given token is being lexed. */
- PM_LEX_DEFAULT,
-
- /**
- * This state is used when we're lexing as normal but inside an embedded
- * expression of a string.
- */
- PM_LEX_EMBEXPR,
-
- /**
- * This state is used when we're lexing a variable that is embedded
- * directly inside of a string with the # shorthand.
- */
- PM_LEX_EMBVAR,
-
- /** This state is used when you are inside the content of a heredoc. */
- PM_LEX_HEREDOC,
-
- /**
- * This state is used when we are lexing a list of tokens, as in a %w
- * word list literal or a %i symbol list literal.
- */
- PM_LEX_LIST,
-
- /**
- * This state is used when a regular expression has been begun and we
- * are looking for the terminator.
- */
- PM_LEX_REGEXP,
-
- /**
- * This state is used when we are lexing a string or a string-like
- * token, as in string content with either quote or an xstring.
- */
- PM_LEX_STRING
- } mode;
-
- /** The data associated with this type of lex mode. */
- union {
- struct {
- /** This keeps track of the nesting level of the list. */
- size_t nesting;
-
- /** Whether or not interpolation is allowed in this list. */
- bool interpolation;
-
- /**
- * When lexing a list, it takes into account balancing the
- * terminator if the terminator is one of (), [], {}, or <>.
- */
- uint8_t incrementor;
-
- /** This is the terminator of the list literal. */
- uint8_t terminator;
-
- /**
- * This is the character set that should be used to delimit the
- * tokens within the list.
- */
- uint8_t breakpoints[11];
- } list;
-
- struct {
- /**
- * This keeps track of the nesting level of the regular expression.
- */
- size_t nesting;
-
- /**
- * When lexing a regular expression, it takes into account balancing
- * the terminator if the terminator is one of (), [], {}, or <>.
- */
- uint8_t incrementor;
-
- /** This is the terminator of the regular expression. */
- uint8_t terminator;
-
- /**
- * This is the character set that should be used to delimit the
- * tokens within the regular expression.
- */
- uint8_t breakpoints[7];
- } regexp;
-
- struct {
- /** This keeps track of the nesting level of the string. */
- size_t nesting;
-
- /** Whether or not interpolation is allowed in this string. */
- bool interpolation;
-
- /**
- * Whether or not at the end of the string we should allow a :,
- * which would indicate this was a dynamic symbol instead of a
- * string.
- */
- bool label_allowed;
-
- /**
- * When lexing a string, it takes into account balancing the
- * terminator if the terminator is one of (), [], {}, or <>.
- */
- uint8_t incrementor;
-
- /**
- * This is the terminator of the string. It is typically either a
- * single or double quote.
- */
- uint8_t terminator;
-
- /**
- * This is the character set that should be used to delimit the
- * tokens within the string.
- */
- uint8_t breakpoints[7];
- } string;
-
- struct {
- /**
- * All of the data necessary to lex a heredoc.
- */
- pm_heredoc_lex_mode_t base;
-
- /**
- * This is the pointer to the character where lexing should resume
- * once the heredoc has been completely processed.
- */
- const uint8_t *next_start;
-
- /**
- * This is used to track the amount of common whitespace on each
- * line so that we know how much to dedent each line in the case of
- * a tilde heredoc.
- */
- size_t *common_whitespace;
-
- /** True if the previous token ended with a line continuation. */
- bool line_continuation;
- } heredoc;
- } as;
-
- /** The previous lex state so that it knows how to pop. */
- struct pm_lex_mode *prev;
-} pm_lex_mode_t;
-
-/**
- * We pre-allocate a certain number of lex states in order to avoid having to
- * call malloc too many times while parsing. You really shouldn't need more than
- * this because you only really nest deeply when doing string interpolation.
- */
-#define PM_LEX_STACK_SIZE 4
-
-/**
- * The parser used to parse Ruby source.
- */
-typedef struct pm_parser pm_parser_t;
-
-/**
- * While parsing, we keep track of a stack of contexts. This is helpful for
- * error recovery so that we can pop back to a previous context when we hit a
- * token that is understood by a parent context but not by the current context.
- */
-typedef enum {
- /** a null context, used for returning a value from a function */
- PM_CONTEXT_NONE = 0,
-
- /** a begin statement */
- PM_CONTEXT_BEGIN,
-
- /** an ensure statement with an explicit begin */
- PM_CONTEXT_BEGIN_ENSURE,
-
- /** a rescue else statement with an explicit begin */
- PM_CONTEXT_BEGIN_ELSE,
-
- /** a rescue statement with an explicit begin */
- PM_CONTEXT_BEGIN_RESCUE,
-
- /** expressions in block arguments using braces */
- PM_CONTEXT_BLOCK_BRACES,
-
- /** expressions in block arguments using do..end */
- PM_CONTEXT_BLOCK_KEYWORDS,
-
- /** an ensure statement within a do..end block */
- PM_CONTEXT_BLOCK_ENSURE,
-
- /** a rescue else statement within a do..end block */
- PM_CONTEXT_BLOCK_ELSE,
-
- /** a rescue statement within a do..end block */
- PM_CONTEXT_BLOCK_RESCUE,
-
- /** a case when statements */
- PM_CONTEXT_CASE_WHEN,
-
- /** a case in statements */
- PM_CONTEXT_CASE_IN,
-
- /** a class declaration */
- PM_CONTEXT_CLASS,
-
- /** an ensure statement within a class statement */
- PM_CONTEXT_CLASS_ENSURE,
-
- /** a rescue else statement within a class statement */
- PM_CONTEXT_CLASS_ELSE,
-
- /** a rescue statement within a class statement */
- PM_CONTEXT_CLASS_RESCUE,
-
- /** a method definition */
- PM_CONTEXT_DEF,
-
- /** an ensure statement within a method definition */
- PM_CONTEXT_DEF_ENSURE,
-
- /** a rescue else statement within a method definition */
- PM_CONTEXT_DEF_ELSE,
-
- /** a rescue statement within a method definition */
- PM_CONTEXT_DEF_RESCUE,
-
- /** a method definition's parameters */
- PM_CONTEXT_DEF_PARAMS,
-
- /** a defined? expression */
- PM_CONTEXT_DEFINED,
-
- /** a method definition's default parameter */
- PM_CONTEXT_DEFAULT_PARAMS,
-
- /** an else clause */
- PM_CONTEXT_ELSE,
-
- /** an elsif clause */
- PM_CONTEXT_ELSIF,
-
- /** an interpolated expression */
- PM_CONTEXT_EMBEXPR,
-
- /** a for loop */
- PM_CONTEXT_FOR,
-
- /** a for loop's index */
- PM_CONTEXT_FOR_INDEX,
-
- /** an if statement */
- PM_CONTEXT_IF,
-
- /** a lambda expression with braces */
- PM_CONTEXT_LAMBDA_BRACES,
-
- /** a lambda expression with do..end */
- PM_CONTEXT_LAMBDA_DO_END,
-
- /** an ensure statement within a lambda expression */
- PM_CONTEXT_LAMBDA_ENSURE,
-
- /** a rescue else statement within a lambda expression */
- PM_CONTEXT_LAMBDA_ELSE,
-
- /** a rescue statement within a lambda expression */
- PM_CONTEXT_LAMBDA_RESCUE,
-
- /** the predicate clause of a loop statement */
- PM_CONTEXT_LOOP_PREDICATE,
-
- /** the top level context */
- PM_CONTEXT_MAIN,
-
- /** a module declaration */
- PM_CONTEXT_MODULE,
-
- /** an ensure statement within a module statement */
- PM_CONTEXT_MODULE_ENSURE,
-
- /** a rescue else statement within a module statement */
- PM_CONTEXT_MODULE_ELSE,
-
- /** a rescue statement within a module statement */
- PM_CONTEXT_MODULE_RESCUE,
-
- /** a multiple target expression */
- PM_CONTEXT_MULTI_TARGET,
-
- /** a parenthesized expression */
- PM_CONTEXT_PARENS,
-
- /** an END block */
- PM_CONTEXT_POSTEXE,
-
- /** a predicate inside an if/elsif/unless statement */
- PM_CONTEXT_PREDICATE,
-
- /** a BEGIN block */
- PM_CONTEXT_PREEXE,
-
- /** a modifier rescue clause */
- PM_CONTEXT_RESCUE_MODIFIER,
-
- /** a singleton class definition */
- PM_CONTEXT_SCLASS,
-
- /** an ensure statement with a singleton class */
- PM_CONTEXT_SCLASS_ENSURE,
-
- /** a rescue else statement with a singleton class */
- PM_CONTEXT_SCLASS_ELSE,
-
- /** a rescue statement with a singleton class */
- PM_CONTEXT_SCLASS_RESCUE,
-
- /** a ternary expression */
- PM_CONTEXT_TERNARY,
-
- /** an unless statement */
- PM_CONTEXT_UNLESS,
-
- /** an until statement */
- PM_CONTEXT_UNTIL,
-
- /** a while statement */
- PM_CONTEXT_WHILE,
-} pm_context_t;
-
-/** This is a node in a linked list of contexts. */
-typedef struct pm_context_node {
- /** The context that this node represents. */
- pm_context_t context;
-
- /** A pointer to the previous context in the linked list. */
- struct pm_context_node *prev;
-} pm_context_node_t;
-
-/** This is the type of a comment that we've found while parsing. */
-typedef enum {
- PM_COMMENT_INLINE,
- PM_COMMENT_EMBDOC
-} pm_comment_type_t;
-
-/**
- * This is a node in the linked list of comments that we've found while parsing.
- *
- * @extends pm_list_node_t
- */
-typedef struct pm_comment {
- /** The embedded base node. */
- pm_list_node_t node;
-
- /** The location of the comment in the source. */
- pm_location_t location;
-
- /** The type of comment that we've found. */
- pm_comment_type_t type;
-} pm_comment_t;
-
-/**
- * This is a node in the linked list of magic comments that we've found while
- * parsing.
- *
- * @extends pm_list_node_t
- */
-typedef struct {
- /** The embedded base node. */
- pm_list_node_t node;
-
- /** A pointer to the start of the key in the source. */
- const uint8_t *key_start;
-
- /** A pointer to the start of the value in the source. */
- const uint8_t *value_start;
-
- /** The length of the key in the source. */
- uint32_t key_length;
-
- /** The length of the value in the source. */
- uint32_t value_length;
-} pm_magic_comment_t;
-
-/**
- * When the encoding that is being used to parse the source is changed by prism,
- * we provide the ability here to call out to a user-defined function.
- */
-typedef void (*pm_encoding_changed_callback_t)(pm_parser_t *parser);
-
-/**
- * When you are lexing through a file, the lexer needs all of the information
- * that the parser additionally provides (for example, the local table). So if
- * you want to properly lex Ruby, you need to actually lex it in the context of
- * the parser. In order to provide this functionality, we optionally allow a
- * struct to be attached to the parser that calls back out to a user-provided
- * callback when each token is lexed.
- */
-typedef struct {
- /**
- * This opaque pointer is used to provide whatever information the user
- * deemed necessary to the callback. In our case we use it to pass the array
- * that the tokens get appended into.
- */
- void *data;
-
- /**
- * This is the callback that is called when a token is lexed. It is passed
- * the opaque data pointer, the parser, and the token that was lexed.
- */
- void (*callback)(void *data, pm_parser_t *parser, pm_token_t *token);
-} pm_lex_callback_t;
-
-/** The type of shareable constant value that can be set. */
-typedef uint8_t pm_shareable_constant_value_t;
-static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_NONE = 0x0;
-static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_LITERAL = PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL;
-static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING;
-static const pm_shareable_constant_value_t PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY = PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY;
-
-/**
- * This tracks an individual local variable in a certain lexical context, as
- * well as the number of times is it read.
- */
-typedef struct {
- /** The name of the local variable. */
- pm_constant_id_t name;
-
- /** The location of the local variable in the source. */
- pm_location_t location;
-
- /** The index of the local variable in the local table. */
- uint32_t index;
-
- /** The number of times the local variable is read. */
- uint32_t reads;
-
- /** The hash of the local variable. */
- uint32_t hash;
-} pm_local_t;
-
-/**
- * This is a set of local variables in a certain lexical context (method, class,
- * module, etc.). We need to track how many times these variables are read in
- * order to warn if they only get written.
- */
-typedef struct pm_locals {
- /** The number of local variables in the set. */
- uint32_t size;
-
- /** The capacity of the local variables set. */
- uint32_t capacity;
-
- /** The nullable allocated memory for the local variables in the set. */
- pm_local_t *locals;
-} pm_locals_t;
-
-/** The flags about scope parameters that can be set. */
-typedef uint8_t pm_scope_parameters_t;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NONE = 0x0;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS = 0x1;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS = 0x2;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_BLOCK = 0x4;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_FORWARDING_ALL = 0x8;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED = 0x10;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NUMBERED_INNER = 0x20;
-static const pm_scope_parameters_t PM_SCOPE_PARAMETERS_NUMBERED_FOUND = 0x40;
-
-/**
- * This struct represents a node in a linked list of scopes. Some scopes can see
- * into their parent scopes, while others cannot.
- */
-typedef struct pm_scope {
- /** A pointer to the previous scope in the linked list. */
- struct pm_scope *previous;
-
- /** The IDs of the locals in the given scope. */
- pm_locals_t locals;
-
- /**
- * This is a list of the implicit parameters contained within the block.
- * These will be processed after the block is parsed to determine the kind
- * of parameters node that should be used and to check if any errors need to
- * be added.
- */
- pm_node_list_t implicit_parameters;
-
- /**
- * This is a bitfield that indicates the parameters that are being used in
- * this scope. It is a combination of the PM_SCOPE_PARAMETERS_* constants.
- * There are three different kinds of parameters that can be used in a
- * scope:
- *
- * - Ordinary parameters (e.g., def foo(bar); end)
- * - Numbered parameters (e.g., def foo; _1; end)
- * - The it parameter (e.g., def foo; it; end)
- *
- * If ordinary parameters are being used, then certain parameters can be
- * forwarded to another method/structure. Those are indicated by four
- * additional bits in the params field. For example, some combinations of:
- *
- * - def foo(*); end
- * - def foo(**); end
- * - def foo(&); end
- * - def foo(...); end
- */
- pm_scope_parameters_t parameters;
-
- /**
- * The current state of constant shareability for this scope. This is
- * changed by magic shareable_constant_value comments.
- */
- pm_shareable_constant_value_t shareable_constant;
-
- /**
- * A boolean indicating whether or not this scope can see into its parent.
- * If closed is true, then the scope cannot see into its parent.
- */
- bool closed;
-} pm_scope_t;
-
-/**
- * A struct that represents a stack of boolean values.
- */
-typedef uint32_t pm_state_stack_t;
-
-/**
- * This struct represents the overall parser. It contains a reference to the
- * source file, as well as pointers that indicate where in the source it's
- * currently parsing. It also contains the most recent and current token that
- * it's considering.
- */
-struct pm_parser {
- /**
- * The next node identifier that will be assigned. This is a unique
- * identifier used to track nodes such that the syntax tree can be dropped
- * but the node can be found through another parse.
- */
- uint32_t node_id;
-
- /** The current state of the lexer. */
- pm_lex_state_t lex_state;
-
- /** Tracks the current nesting of (), [], and {}. */
- int enclosure_nesting;
-
- /**
- * Used to temporarily track the nesting of enclosures to determine if a {
- * is the beginning of a lambda following the parameters of a lambda.
- */
- int lambda_enclosure_nesting;
-
- /**
- * Used to track the nesting of braces to ensure we get the correct value
- * when we are interpolating blocks with braces.
- */
- int brace_nesting;
-
- /**
- * The stack used to determine if a do keyword belongs to the predicate of a
- * while, until, or for loop.
- */
- pm_state_stack_t do_loop_stack;
-
- /**
- * The stack used to determine if a do keyword belongs to the beginning of a
- * block.
- */
- pm_state_stack_t accepts_block_stack;
-
- /** A stack of lex modes. */
- struct {
- /** The current mode of the lexer. */
- pm_lex_mode_t *current;
-
- /** The stack of lexer modes. */
- pm_lex_mode_t stack[PM_LEX_STACK_SIZE];
-
- /** The current index into the lexer mode stack. */
- size_t index;
- } lex_modes;
-
- /** The pointer to the start of the source. */
- const uint8_t *start;
-
- /** The pointer to the end of the source. */
- const uint8_t *end;
-
- /** The previous token we were considering. */
- pm_token_t previous;
-
- /** The current token we're considering. */
- pm_token_t current;
-
- /**
- * This is a special field set on the parser when we need the parser to jump
- * to a specific location when lexing the next token, as opposed to just
- * using the end of the previous token. Normally this is NULL.
- */
- const uint8_t *next_start;
-
- /**
- * This field indicates the end of a heredoc whose identifier was found on
- * the current line. If another heredoc is found on the same line, then this
- * will be moved forward to the end of that heredoc. If no heredocs are
- * found on a line then this is NULL.
- */
- const uint8_t *heredoc_end;
-
- /** The list of comments that have been found while parsing. */
- pm_list_t comment_list;
-
- /** The list of magic comments that have been found while parsing. */
- pm_list_t magic_comment_list;
-
- /**
- * An optional location that represents the location of the __END__ marker
- * and the rest of the content of the file. This content is loaded into the
- * DATA constant when the file being parsed is the main file being executed.
- */
- pm_location_t data_loc;
-
- /** The list of warnings that have been found while parsing. */
- pm_list_t warning_list;
-
- /** The list of errors that have been found while parsing. */
- pm_list_t error_list;
-
- /** The current local scope. */
- pm_scope_t *current_scope;
-
- /** The current parsing context. */
- pm_context_node_t *current_context;
-
- /**
- * The hash keys for the hash that is currently being parsed. This is not
- * usually necessary because it can pass it down the various call chains,
- * but in the event that you're parsing a hash that is being directly
- * pushed into another hash with **, we need to share the hash keys so that
- * we can warn for the nested hash as well.
- */
- pm_static_literals_t *current_hash_keys;
-
- /**
- * The encoding functions for the current file is attached to the parser as
- * it's parsing so that it can change with a magic comment.
- */
- const pm_encoding_t *encoding;
-
- /**
- * When the encoding that is being used to parse the source is changed by
- * prism, we provide the ability here to call out to a user-defined
- * function.
- */
- pm_encoding_changed_callback_t encoding_changed_callback;
-
- /**
- * This pointer indicates where a comment must start if it is to be
- * considered an encoding comment.
- */
- const uint8_t *encoding_comment_start;
-
- /**
- * This is an optional callback that can be attached to the parser that will
- * be called whenever a new token is lexed by the parser.
- */
- pm_lex_callback_t *lex_callback;
-
- /**
- * This is the path of the file being parsed. We use the filepath when
- * constructing SourceFileNodes.
- */
- pm_string_t filepath;
-
- /**
- * This constant pool keeps all of the constants defined throughout the file
- * so that we can reference them later.
- */
- pm_constant_pool_t constant_pool;
-
- /** This is the list of newline offsets in the source file. */
- pm_newline_list_t newline_list;
-
- /**
- * We want to add a flag to integer nodes that indicates their base. We only
- * want to parse these once, but we don't have space on the token itself to
- * communicate this information. So we store it here and pass it through
- * when we find tokens that we need it for.
- */
- pm_node_flags_t integer_base;
-
- /**
- * This string is used to pass information from the lexer to the parser. It
- * is particularly necessary because of escape sequences.
- */
- pm_string_t current_string;
-
- /**
- * The line number at the start of the parse. This will be used to offset
- * the line numbers of all of the locations.
- */
- int32_t start_line;
-
- /**
- * When a string-like expression is being lexed, any byte or escape sequence
- * that resolves to a value whose top bit is set (i.e., >= 0x80) will
- * explicitly set the encoding to the same encoding as the source.
- * Alternatively, if a unicode escape sequence is used (e.g., \\u{80}) that
- * resolves to a value whose top bit is set, then the encoding will be
- * explicitly set to UTF-8.
- *
- * The _next_ time this happens, if the encoding that is about to become the
- * explicitly set encoding does not match the previously set explicit
- * encoding, a mixed encoding error will be emitted.
- *
- * When the expression is finished being lexed, the explicit encoding
- * controls the encoding of the expression. For the most part this means
- * that the expression will either be encoded in the source encoding or
- * UTF-8. This holds for all encodings except US-ASCII. If the source is
- * US-ASCII and an explicit encoding was set that was _not_ UTF-8, then the
- * expression will be encoded as ASCII-8BIT.
- *
- * Note that if the expression is a list, different elements within the same
- * list can have different encodings, so this will get reset between each
- * element. Furthermore all of this only applies to lists that support
- * interpolation, because otherwise escapes that could change the encoding
- * are ignored.
- *
- * At first glance, it may make more sense for this to live on the lexer
- * mode, but we need it here to communicate back to the parser for character
- * literals that do not push a new lexer mode.
- */
- const pm_encoding_t *explicit_encoding;
-
- /**
- * When parsing block exits (e.g., break, next, redo), we need to validate
- * that they are in correct contexts. For the most part we can do this by
- * looking at our parent contexts. However, modifier while and until
- * expressions can change that context to make block exits valid. In these
- * cases, we need to keep track of the block exits and then validate them
- * after the expression has been parsed.
- *
- * We use a pointer here because we don't want to keep a whole list attached
- * since this will only be used in the context of begin/end expressions.
- */
- pm_node_list_t *current_block_exits;
-
- /** The version of prism that we should use to parse. */
- pm_options_version_t version;
-
- /** The command line flags given from the options. */
- uint8_t command_line;
-
- /**
- * Whether or not we have found a frozen_string_literal magic comment with
- * a true or false value.
- * May be:
- * - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
- * - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
- * - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
- */
- int8_t frozen_string_literal;
-
- /**
- * Whether or not we are parsing an eval string. This impacts whether or not
- * we should evaluate if block exits/yields are valid.
- */
- bool parsing_eval;
-
- /**
- * Whether or not we are parsing a "partial" script, which is a script that
- * will be evaluated in the context of another script, so we should not
- * check jumps (next/break/etc.) for validity.
- */
- bool partial_script;
-
- /** Whether or not we're at the beginning of a command. */
- bool command_start;
-
- /** Whether or not we're currently recovering from a syntax error. */
- bool recovering;
-
- /**
- * This is very specialized behavior for when you want to parse in a context
- * that does not respect encoding comments. Its main use case is translating
- * into the whitequark/parser AST which re-encodes source files in UTF-8
- * before they are parsed and ignores encoding comments.
- */
- bool encoding_locked;
-
- /**
- * Whether or not the encoding has been changed by a magic comment. We use
- * this to provide a fast path for the lexer instead of going through the
- * function pointer.
- */
- bool encoding_changed;
-
- /**
- * This flag indicates that we are currently parsing a pattern matching
- * expression and impacts that calculation of newlines.
- */
- bool pattern_matching_newlines;
-
- /** This flag indicates that we are currently parsing a keyword argument. */
- bool in_keyword_arg;
-
- /**
- * Whether or not the parser has seen a token that has semantic meaning
- * (i.e., a token that is not a comment or whitespace).
- */
- bool semantic_token_seen;
-
- /**
- * True if the current regular expression being lexed contains only ASCII
- * characters.
- */
- bool current_regular_expression_ascii_only;
-
- /**
- * By default, Ruby always warns about mismatched indentation. This can be
- * toggled with a magic comment.
- */
- bool warn_mismatched_indentation;
-};
-
-#endif
diff --git a/prism/prettyprint.h b/prism/prettyprint.h
deleted file mode 100644
index 5a52b2b6b8..0000000000
--- a/prism/prettyprint.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * @file prettyprint.h
- *
- * An AST node pretty-printer.
- */
-#ifndef PRISM_PRETTYPRINT_H
-#define PRISM_PRETTYPRINT_H
-
-#include "prism/defines.h"
-
-#ifdef PRISM_EXCLUDE_PRETTYPRINT
-
-void pm_prettyprint(void);
-
-#else
-
-#include <stdio.h>
-
-#include "prism/ast.h"
-#include "prism/parser.h"
-#include "prism/util/pm_buffer.h"
-
-/**
- * Pretty-prints the AST represented by the given node to the given buffer.
- *
- * @param output_buffer The buffer to write the pretty-printed AST to.
- * @param parser The parser that parsed the AST.
- * @param node The root node of the AST to pretty-print.
- */
-PRISM_EXPORTED_FUNCTION void pm_prettyprint(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node);
-
-#endif
-
-#endif
diff --git a/prism/prism.c b/prism/prism.c
deleted file mode 100644
index 24023525e5..0000000000
--- a/prism/prism.c
+++ /dev/null
@@ -1,22584 +0,0 @@
-#include "prism.h"
-
-/**
- * The prism version and the serialization format.
- */
-const char *
-pm_version(void) {
- return PRISM_VERSION;
-}
-
-/**
- * In heredocs, tabs automatically complete up to the next 8 spaces. This is
- * defined in CRuby as TAB_WIDTH.
- */
-#define PM_TAB_WHITESPACE_SIZE 8
-
-// Macros for min/max.
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#define MAX(a,b) (((a)>(b))?(a):(b))
-
-/******************************************************************************/
-/* Lex mode manipulations */
-/******************************************************************************/
-
-/**
- * Returns the incrementor character that should be used to increment the
- * nesting count if one is possible.
- */
-static inline uint8_t
-lex_mode_incrementor(const uint8_t start) {
- switch (start) {
- case '(':
- case '[':
- case '{':
- case '<':
- return start;
- default:
- return '\0';
- }
-}
-
-/**
- * Returns the matching character that should be used to terminate a list
- * beginning with the given character.
- */
-static inline uint8_t
-lex_mode_terminator(const uint8_t start) {
- switch (start) {
- case '(':
- return ')';
- case '[':
- return ']';
- case '{':
- return '}';
- case '<':
- return '>';
- default:
- return start;
- }
-}
-
-/**
- * Push a new lex state onto the stack. If we're still within the pre-allocated
- * space of the lex state stack, then we'll just use a new slot. Otherwise we'll
- * allocate a new pointer and use that.
- */
-static bool
-lex_mode_push(pm_parser_t *parser, pm_lex_mode_t lex_mode) {
- lex_mode.prev = parser->lex_modes.current;
- parser->lex_modes.index++;
-
- if (parser->lex_modes.index > PM_LEX_STACK_SIZE - 1) {
- parser->lex_modes.current = (pm_lex_mode_t *) xmalloc(sizeof(pm_lex_mode_t));
- if (parser->lex_modes.current == NULL) return false;
-
- *parser->lex_modes.current = lex_mode;
- } else {
- parser->lex_modes.stack[parser->lex_modes.index] = lex_mode;
- parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
- }
-
- return true;
-}
-
-/**
- * Push on a new list lex mode.
- */
-static inline bool
-lex_mode_push_list(pm_parser_t *parser, bool interpolation, uint8_t delimiter) {
- uint8_t incrementor = lex_mode_incrementor(delimiter);
- uint8_t terminator = lex_mode_terminator(delimiter);
-
- pm_lex_mode_t lex_mode = {
- .mode = PM_LEX_LIST,
- .as.list = {
- .nesting = 0,
- .interpolation = interpolation,
- .incrementor = incrementor,
- .terminator = terminator
- }
- };
-
- // These are the places where we need to split up the content of the list.
- // We'll use strpbrk to find the first of these characters.
- uint8_t *breakpoints = lex_mode.as.list.breakpoints;
- memcpy(breakpoints, "\\ \t\f\r\v\n\0\0\0", sizeof(lex_mode.as.list.breakpoints));
- size_t index = 7;
-
- // Now we'll add the terminator to the list of breakpoints. If the
- // terminator is not already a NULL byte, add it to the list.
- if (terminator != '\0') {
- breakpoints[index++] = terminator;
- }
-
- // If interpolation is allowed, then we're going to check for the #
- // character. Otherwise we'll only look for escapes and the terminator.
- if (interpolation) {
- breakpoints[index++] = '#';
- }
-
- // If there is an incrementor, then we'll check for that as well.
- if (incrementor != '\0') {
- breakpoints[index++] = incrementor;
- }
-
- parser->explicit_encoding = NULL;
- return lex_mode_push(parser, lex_mode);
-}
-
-/**
- * Push on a new list lex mode that is only used for compatibility. This is
- * called when we're at the end of the file. We want the parser to be able to
- * perform its normal error tolerance.
- */
-static inline bool
-lex_mode_push_list_eof(pm_parser_t *parser) {
- return lex_mode_push_list(parser, false, '\0');
-}
-
-/**
- * Push on a new regexp lex mode.
- */
-static inline bool
-lex_mode_push_regexp(pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
- pm_lex_mode_t lex_mode = {
- .mode = PM_LEX_REGEXP,
- .as.regexp = {
- .nesting = 0,
- .incrementor = incrementor,
- .terminator = terminator
- }
- };
-
- // These are the places where we need to split up the content of the
- // regular expression. We'll use strpbrk to find the first of these
- // characters.
- uint8_t *breakpoints = lex_mode.as.regexp.breakpoints;
- memcpy(breakpoints, "\r\n\\#\0\0", sizeof(lex_mode.as.regexp.breakpoints));
- size_t index = 4;
-
- // First we'll add the terminator.
- if (terminator != '\0') {
- breakpoints[index++] = terminator;
- }
-
- // Next, if there is an incrementor, then we'll check for that as well.
- if (incrementor != '\0') {
- breakpoints[index++] = incrementor;
- }
-
- parser->explicit_encoding = NULL;
- return lex_mode_push(parser, lex_mode);
-}
-
-/**
- * Push on a new string lex mode.
- */
-static inline bool
-lex_mode_push_string(pm_parser_t *parser, bool interpolation, bool label_allowed, uint8_t incrementor, uint8_t terminator) {
- pm_lex_mode_t lex_mode = {
- .mode = PM_LEX_STRING,
- .as.string = {
- .nesting = 0,
- .interpolation = interpolation,
- .label_allowed = label_allowed,
- .incrementor = incrementor,
- .terminator = terminator
- }
- };
-
- // These are the places where we need to split up the content of the
- // string. We'll use strpbrk to find the first of these characters.
- uint8_t *breakpoints = lex_mode.as.string.breakpoints;
- memcpy(breakpoints, "\r\n\\\0\0\0", sizeof(lex_mode.as.string.breakpoints));
- size_t index = 3;
-
- // Now add in the terminator. If the terminator is not already a NULL byte,
- // then we'll add it.
- if (terminator != '\0') {
- breakpoints[index++] = terminator;
- }
-
- // If interpolation is allowed, then we're going to check for the #
- // character. Otherwise we'll only look for escapes and the terminator.
- if (interpolation) {
- breakpoints[index++] = '#';
- }
-
- // If we have an incrementor, then we'll add that in as a breakpoint as
- // well.
- if (incrementor != '\0') {
- breakpoints[index++] = incrementor;
- }
-
- parser->explicit_encoding = NULL;
- return lex_mode_push(parser, lex_mode);
-}
-
-/**
- * Push on a new string lex mode that is only used for compatibility. This is
- * called when we're at the end of the file. We want the parser to be able to
- * perform its normal error tolerance.
- */
-static inline bool
-lex_mode_push_string_eof(pm_parser_t *parser) {
- return lex_mode_push_string(parser, false, false, '\0', '\0');
-}
-
-/**
- * Pop the current lex state off the stack. If we're within the pre-allocated
- * space of the lex state stack, then we'll just decrement the index. Otherwise
- * we'll free the current pointer and use the previous pointer.
- */
-static void
-lex_mode_pop(pm_parser_t *parser) {
- if (parser->lex_modes.index == 0) {
- parser->lex_modes.current->mode = PM_LEX_DEFAULT;
- } else if (parser->lex_modes.index < PM_LEX_STACK_SIZE) {
- parser->lex_modes.index--;
- parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
- } else {
- parser->lex_modes.index--;
- pm_lex_mode_t *prev = parser->lex_modes.current->prev;
- xfree(parser->lex_modes.current);
- parser->lex_modes.current = prev;
- }
-}
-
-/**
- * This is the equivalent of IS_lex_state is CRuby.
- */
-static inline bool
-lex_state_p(const pm_parser_t *parser, pm_lex_state_t state) {
- return parser->lex_state & state;
-}
-
-typedef enum {
- PM_IGNORED_NEWLINE_NONE = 0,
- PM_IGNORED_NEWLINE_ALL,
- PM_IGNORED_NEWLINE_PATTERN
-} pm_ignored_newline_type_t;
-
-static inline pm_ignored_newline_type_t
-lex_state_ignored_p(pm_parser_t *parser) {
- bool ignored = lex_state_p(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_CLASS | PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT) && !lex_state_p(parser, PM_LEX_STATE_LABELED);
-
- if (ignored) {
- return PM_IGNORED_NEWLINE_ALL;
- } else if ((parser->lex_state & ~((unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
- return PM_IGNORED_NEWLINE_PATTERN;
- } else {
- return PM_IGNORED_NEWLINE_NONE;
- }
-}
-
-static inline bool
-lex_state_beg_p(pm_parser_t *parser) {
- return lex_state_p(parser, PM_LEX_STATE_BEG_ANY) || ((parser->lex_state & (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED));
-}
-
-static inline bool
-lex_state_arg_p(pm_parser_t *parser) {
- return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
-}
-
-static inline bool
-lex_state_spcarg_p(pm_parser_t *parser, bool space_seen) {
- if (parser->current.end >= parser->end) {
- return false;
- }
- return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->current.end);
-}
-
-static inline bool
-lex_state_end_p(pm_parser_t *parser) {
- return lex_state_p(parser, PM_LEX_STATE_END_ANY);
-}
-
-/**
- * This is the equivalent of IS_AFTER_OPERATOR in CRuby.
- */
-static inline bool
-lex_state_operator_p(pm_parser_t *parser) {
- return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
-}
-
-/**
- * Set the state of the lexer. This is defined as a function to be able to put a
- * breakpoint in it.
- */
-static inline void
-lex_state_set(pm_parser_t *parser, pm_lex_state_t state) {
- parser->lex_state = state;
-}
-
-#ifndef PM_DEBUG_LOGGING
-/**
- * Debugging logging will print additional information to stdout whenever the
- * lexer state changes.
- */
-#define PM_DEBUG_LOGGING 0
-#endif
-
-#if PM_DEBUG_LOGGING
-PRISM_ATTRIBUTE_UNUSED static void
-debug_state(pm_parser_t *parser) {
- fprintf(stderr, "STATE: ");
- bool first = true;
-
- if (parser->lex_state == PM_LEX_STATE_NONE) {
- fprintf(stderr, "NONE\n");
- return;
- }
-
-#define CHECK_STATE(state) \
- if (parser->lex_state & state) { \
- if (!first) fprintf(stderr, "|"); \
- fprintf(stderr, "%s", #state); \
- first = false; \
- }
-
- CHECK_STATE(PM_LEX_STATE_BEG)
- CHECK_STATE(PM_LEX_STATE_END)
- CHECK_STATE(PM_LEX_STATE_ENDARG)
- CHECK_STATE(PM_LEX_STATE_ENDFN)
- CHECK_STATE(PM_LEX_STATE_ARG)
- CHECK_STATE(PM_LEX_STATE_CMDARG)
- CHECK_STATE(PM_LEX_STATE_MID)
- CHECK_STATE(PM_LEX_STATE_FNAME)
- CHECK_STATE(PM_LEX_STATE_DOT)
- CHECK_STATE(PM_LEX_STATE_CLASS)
- CHECK_STATE(PM_LEX_STATE_LABEL)
- CHECK_STATE(PM_LEX_STATE_LABELED)
- CHECK_STATE(PM_LEX_STATE_FITEM)
-
-#undef CHECK_STATE
-
- fprintf(stderr, "\n");
-}
-
-static void
-debug_lex_state_set(pm_parser_t *parser, pm_lex_state_t state, char const * caller_name, int line_number) {
- fprintf(stderr, "Caller: %s:%d\nPrevious: ", caller_name, line_number);
- debug_state(parser);
- lex_state_set(parser, state);
- fprintf(stderr, "Now: ");
- debug_state(parser);
- fprintf(stderr, "\n");
-}
-
-#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
-#endif
-
-/******************************************************************************/
-/* Command-line macro helpers */
-/******************************************************************************/
-
-/** True if the parser has the given command-line option. */
-#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
-
-/** True if the -a command line option was given. */
-#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
-
-/** True if the -e command line option was given. */
-#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
-
-/** True if the -l command line option was given. */
-#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
-
-/** True if the -n command line option was given. */
-#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
-
-/** True if the -p command line option was given. */
-#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
-
-/** True if the -x command line option was given. */
-#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
-
-/******************************************************************************/
-/* Diagnostic-related functions */
-/******************************************************************************/
-
-/**
- * Append an error to the list of errors on the parser.
- */
-static inline void
-pm_parser_err(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id) {
- pm_diagnostic_list_append(&parser->error_list, start, end, diag_id);
-}
-
-/**
- * Append an error to the list of errors on the parser using a format string.
- */
-#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
- pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
-
-/**
- * Append an error to the list of errors on the parser using the location of the
- * current token.
- */
-static inline void
-pm_parser_err_current(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
- pm_parser_err(parser, parser->current.start, parser->current.end, diag_id);
-}
-
-/**
- * Append an error to the list of errors on the parser using the given location
- * using a format string.
- */
-#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
- PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
-
-/**
- * Append an error to the list of errors on the parser using the location of the
- * given node.
- */
-static inline void
-pm_parser_err_node(pm_parser_t *parser, const pm_node_t *node, pm_diagnostic_id_t diag_id) {
- pm_parser_err(parser, node->location.start, node->location.end, diag_id);
-}
-
-/**
- * Append an error to the list of errors on the parser using the location of the
- * given node and a format string.
- */
-#define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) \
- PM_PARSER_ERR_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
-
-/**
- * Append an error to the list of errors on the parser using the location of the
- * given node and a format string, and add on the content of the node.
- */
-#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, diag_id) \
- PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, (int) ((node)->location.end - (node)->location.start), (const char *) (node)->location.start)
-
-/**
- * Append an error to the list of errors on the parser using the location of the
- * previous token.
- */
-static inline void
-pm_parser_err_previous(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
- pm_parser_err(parser, parser->previous.start, parser->previous.end, diag_id);
-}
-
-/**
- * Append an error to the list of errors on the parser using the location of the
- * given token.
- */
-static inline void
-pm_parser_err_token(pm_parser_t *parser, const pm_token_t *token, pm_diagnostic_id_t diag_id) {
- pm_parser_err(parser, token->start, token->end, diag_id);
-}
-
-/**
- * Append an error to the list of errors on the parser using the location of the
- * given token and a format string.
- */
-#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) \
- PM_PARSER_ERR_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
-
-/**
- * Append an error to the list of errors on the parser using the location of the
- * given token and a format string, and add on the content of the token.
- */
-#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
- PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
-
-/**
- * Append a warning to the list of warnings on the parser.
- */
-static inline void
-pm_parser_warn(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id) {
- pm_diagnostic_list_append(&parser->warning_list, start, end, diag_id);
-}
-
-/**
- * Append a warning to the list of warnings on the parser using the location of
- * the given token.
- */
-static inline void
-pm_parser_warn_token(pm_parser_t *parser, const pm_token_t *token, pm_diagnostic_id_t diag_id) {
- pm_parser_warn(parser, token->start, token->end, diag_id);
-}
-
-/**
- * Append a warning to the list of warnings on the parser using the location of
- * the given node.
- */
-static inline void
-pm_parser_warn_node(pm_parser_t *parser, const pm_node_t *node, pm_diagnostic_id_t diag_id) {
- pm_parser_warn(parser, node->location.start, node->location.end, diag_id);
-}
-
-/**
- * Append a warning to the list of warnings on the parser using a format string.
- */
-#define PM_PARSER_WARN_FORMAT(parser, start, end, diag_id, ...) \
- pm_diagnostic_list_append_format(&parser->warning_list, start, end, diag_id, __VA_ARGS__)
-
-/**
- * Append a warning to the list of warnings on the parser using the location of
- * the given token and a format string.
- */
-#define PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, ...) \
- PM_PARSER_WARN_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
-
-/**
- * Append a warning to the list of warnings on the parser using the location of
- * the given token and a format string, and add on the content of the token.
- */
-#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
- PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
-
-/**
- * Append a warning to the list of warnings on the parser using the location of
- * the given node and a format string.
- */
-#define PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, ...) \
- PM_PARSER_WARN_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
-
-/**
- * Add an error for an expected heredoc terminator. This is a special function
- * only because it grabs its location off of a lex mode instead of a node or a
- * token.
- */
-static void
-pm_parser_err_heredoc_term(pm_parser_t *parser, const uint8_t *ident_start, size_t ident_length) {
- PM_PARSER_ERR_FORMAT(
- parser,
- ident_start,
- ident_start + ident_length,
- PM_ERR_HEREDOC_TERM,
- (int) ident_length,
- (const char *) ident_start
- );
-}
-
-/******************************************************************************/
-/* Scope-related functions */
-/******************************************************************************/
-
-/**
- * Allocate and initialize a new scope. Push it onto the scope stack.
- */
-static bool
-pm_parser_scope_push(pm_parser_t *parser, bool closed) {
- pm_scope_t *scope = (pm_scope_t *) xmalloc(sizeof(pm_scope_t));
- if (scope == NULL) return false;
-
- *scope = (pm_scope_t) {
- .previous = parser->current_scope,
- .locals = { 0 },
- .parameters = PM_SCOPE_PARAMETERS_NONE,
- .implicit_parameters = { 0 },
- .shareable_constant = parser->current_scope == NULL ? PM_SCOPE_SHAREABLE_CONSTANT_NONE : parser->current_scope->shareable_constant,
- .closed = closed
- };
-
- parser->current_scope = scope;
- return true;
-}
-
-/**
- * Determine if the current scope is at the top level. This means it is either
- * the top-level scope or it is open to the top-level.
- */
-static bool
-pm_parser_scope_toplevel_p(pm_parser_t *parser) {
- pm_scope_t *scope = parser->current_scope;
-
- do {
- if (scope->previous == NULL) return true;
- if (scope->closed) return false;
- } while ((scope = scope->previous) != NULL);
-
- assert(false && "unreachable");
- return true;
-}
-
-/**
- * Retrieve the scope at the given depth.
- */
-static pm_scope_t *
-pm_parser_scope_find(pm_parser_t *parser, uint32_t depth) {
- pm_scope_t *scope = parser->current_scope;
-
- while (depth-- > 0) {
- assert(scope != NULL);
- scope = scope->previous;
- }
-
- return scope;
-}
-
-typedef enum {
- PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
- PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
- PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
-} pm_scope_forwarding_param_check_result_t;
-
-static pm_scope_forwarding_param_check_result_t
-pm_parser_scope_forwarding_param_check(pm_parser_t *parser, const uint8_t mask) {
- pm_scope_t *scope = parser->current_scope;
- bool conflict = false;
-
- while (scope != NULL) {
- if (scope->parameters & mask) {
- if (scope->closed) {
- if (conflict) {
- return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
- } else {
- return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
- }
- }
-
- conflict = true;
- }
-
- if (scope->closed) break;
- scope = scope->previous;
- }
-
- return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
-}
-
-static void
-pm_parser_scope_forwarding_block_check(pm_parser_t *parser, const pm_token_t * token) {
- switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
- case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
- // Pass.
- break;
- case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
- pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
- break;
- case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
- pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
- break;
- }
-}
-
-static void
-pm_parser_scope_forwarding_positionals_check(pm_parser_t *parser, const pm_token_t * token) {
- switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
- case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
- // Pass.
- break;
- case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
- pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
- break;
- case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
- pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
- break;
- }
-}
-
-static void
-pm_parser_scope_forwarding_all_check(pm_parser_t *parser, const pm_token_t *token) {
- switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
- case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
- // Pass.
- break;
- case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
- // This shouldn't happen, because ... is not allowed in the
- // declaration of blocks. If we get here, we assume we already have
- // an error for this.
- break;
- case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
- pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
- break;
- }
-}
-
-static void
-pm_parser_scope_forwarding_keywords_check(pm_parser_t *parser, const pm_token_t * token) {
- switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
- case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
- // Pass.
- break;
- case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
- pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
- break;
- case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
- pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
- break;
- }
-}
-
-/**
- * Get the current state of constant shareability.
- */
-static inline pm_shareable_constant_value_t
-pm_parser_scope_shareable_constant_get(pm_parser_t *parser) {
- return parser->current_scope->shareable_constant;
-}
-
-/**
- * Set the current state of constant shareability. We'll set it on all of the
- * open scopes so that reads are quick.
- */
-static void
-pm_parser_scope_shareable_constant_set(pm_parser_t *parser, pm_shareable_constant_value_t shareable_constant) {
- pm_scope_t *scope = parser->current_scope;
-
- do {
- scope->shareable_constant = shareable_constant;
- } while (!scope->closed && (scope = scope->previous) != NULL);
-}
-
-/******************************************************************************/
-/* Local variable-related functions */
-/******************************************************************************/
-
-/**
- * The point at which the set of locals switches from being a list to a hash.
- */
-#define PM_LOCALS_HASH_THRESHOLD 9
-
-static void
-pm_locals_free(pm_locals_t *locals) {
- if (locals->capacity > 0) {
- xfree(locals->locals);
- }
-}
-
-/**
- * Use as simple and fast a hash function as we can that still properly mixes
- * the bits.
- */
-static uint32_t
-pm_locals_hash(pm_constant_id_t name) {
- name = ((name >> 16) ^ name) * 0x45d9f3b;
- name = ((name >> 16) ^ name) * 0x45d9f3b;
- name = (name >> 16) ^ name;
- return name;
-}
-
-/**
- * Resize the locals list to be twice its current size. If the next capacity is
- * above the threshold for switching to a hash, then we'll switch to a hash.
- */
-static void
-pm_locals_resize(pm_locals_t *locals) {
- uint32_t next_capacity = locals->capacity == 0 ? 4 : (locals->capacity * 2);
- assert(next_capacity > locals->capacity);
-
- pm_local_t *next_locals = xcalloc(next_capacity, sizeof(pm_local_t));
- if (next_locals == NULL) abort();
-
- if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
- if (locals->size > 0) {
- memcpy(next_locals, locals->locals, locals->size * sizeof(pm_local_t));
- }
- } else {
- // If we just switched from a list to a hash, then we need to fill in
- // the hash values of all of the locals.
- bool hash_needed = (locals->capacity <= PM_LOCALS_HASH_THRESHOLD);
- uint32_t mask = next_capacity - 1;
-
- for (uint32_t index = 0; index < locals->capacity; index++) {
- pm_local_t *local = &locals->locals[index];
-
- if (local->name != PM_CONSTANT_ID_UNSET) {
- if (hash_needed) local->hash = pm_locals_hash(local->name);
-
- uint32_t hash = local->hash;
- while (next_locals[hash & mask].name != PM_CONSTANT_ID_UNSET) hash++;
- next_locals[hash & mask] = *local;
- }
- }
- }
-
- pm_locals_free(locals);
- locals->locals = next_locals;
- locals->capacity = next_capacity;
-}
-
-/**
- * Add a new local to the set of locals. This will automatically rehash the
- * locals if the size is greater than 3/4 of the capacity.
- *
- * @param locals The set of locals to add to.
- * @param name The name of the local.
- * @param start The source location that represents the start of the local. This
- * is used for the location of the warning in case this local is not read.
- * @param end The source location that represents the end of the local. This is
- * used for the location of the warning in case this local is not read.
- * @param reads The initial number of reads for this local. Usually this is set
- * to 0, but for some locals (like parameters) we want to initialize it with
- * 1 so that we never warn on unused parameters.
- * @return True if the local was added, and false if the local already exists.
- */
-static bool
-pm_locals_write(pm_locals_t *locals, pm_constant_id_t name, const uint8_t *start, const uint8_t *end, uint32_t reads) {
- if (locals->size >= (locals->capacity / 4 * 3)) {
- pm_locals_resize(locals);
- }
-
- if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
- for (uint32_t index = 0; index < locals->capacity; index++) {
- pm_local_t *local = &locals->locals[index];
-
- if (local->name == PM_CONSTANT_ID_UNSET) {
- *local = (pm_local_t) {
- .name = name,
- .location = { .start = start, .end = end },
- .index = locals->size++,
- .reads = reads,
- .hash = 0
- };
- return true;
- } else if (local->name == name) {
- return false;
- }
- }
- } else {
- uint32_t mask = locals->capacity - 1;
- uint32_t hash = pm_locals_hash(name);
- uint32_t initial_hash = hash;
-
- do {
- pm_local_t *local = &locals->locals[hash & mask];
-
- if (local->name == PM_CONSTANT_ID_UNSET) {
- *local = (pm_local_t) {
- .name = name,
- .location = { .start = start, .end = end },
- .index = locals->size++,
- .reads = reads,
- .hash = initial_hash
- };
- return true;
- } else if (local->name == name) {
- return false;
- } else {
- hash++;
- }
- } while ((hash & mask) != initial_hash);
- }
-
- assert(false && "unreachable");
- return true;
-}
-
-/**
- * Finds the index of a local variable in the locals set. If it is not found,
- * this returns UINT32_MAX.
- */
-static uint32_t
-pm_locals_find(pm_locals_t *locals, pm_constant_id_t name) {
- if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
- for (uint32_t index = 0; index < locals->size; index++) {
- pm_local_t *local = &locals->locals[index];
- if (local->name == name) return index;
- }
- } else {
- uint32_t mask = locals->capacity - 1;
- uint32_t hash = pm_locals_hash(name);
- uint32_t initial_hash = hash & mask;
-
- do {
- pm_local_t *local = &locals->locals[hash & mask];
-
- if (local->name == PM_CONSTANT_ID_UNSET) {
- return UINT32_MAX;
- } else if (local->name == name) {
- return hash & mask;
- } else {
- hash++;
- }
- } while ((hash & mask) != initial_hash);
- }
-
- return UINT32_MAX;
-}
-
-/**
- * Called when a variable is read in a certain lexical context. Tracks the read
- * by adding to the reads count.
- */
-static void
-pm_locals_read(pm_locals_t *locals, pm_constant_id_t name) {
- uint32_t index = pm_locals_find(locals, name);
- assert(index != UINT32_MAX);
-
- pm_local_t *local = &locals->locals[index];
- assert(local->reads < UINT32_MAX);
-
- local->reads++;
-}
-
-/**
- * Called when a variable read is transformed into a variable write, because a
- * write operator is found after the variable name.
- */
-static void
-pm_locals_unread(pm_locals_t *locals, pm_constant_id_t name) {
- uint32_t index = pm_locals_find(locals, name);
- assert(index != UINT32_MAX);
-
- pm_local_t *local = &locals->locals[index];
- assert(local->reads > 0);
-
- local->reads--;
-}
-
-/**
- * Returns the current number of reads for a local variable.
- */
-static uint32_t
-pm_locals_reads(pm_locals_t *locals, pm_constant_id_t name) {
- uint32_t index = pm_locals_find(locals, name);
- assert(index != UINT32_MAX);
-
- return locals->locals[index].reads;
-}
-
-/**
- * Write out the locals into the given list of constant ids in the correct
- * order. This is used to set the list of locals on the nodes in the tree once
- * we're sure no additional locals will be added to the set.
- *
- * This function is also responsible for warning when a local variable has been
- * written but not read in certain contexts.
- */
-static void
-pm_locals_order(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, pm_locals_t *locals, pm_constant_id_list_t *list, bool toplevel) {
- pm_constant_id_list_init_capacity(list, locals->size);
-
- // If we're still below the threshold for switching to a hash, then we only
- // need to loop over the locals until we hit the size because the locals are
- // stored in a list.
- uint32_t capacity = locals->capacity < PM_LOCALS_HASH_THRESHOLD ? locals->size : locals->capacity;
-
- // We will only warn for unused variables if we're not at the top level, or
- // if we're parsing a file outside of eval or -e.
- bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
-
- for (uint32_t index = 0; index < capacity; index++) {
- pm_local_t *local = &locals->locals[index];
-
- if (local->name != PM_CONSTANT_ID_UNSET) {
- pm_constant_id_list_insert(list, (size_t) local->index, local->name);
-
- if (warn_unused && local->reads == 0) {
- pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->name);
-
- if (constant->length >= 1 && *constant->start != '_') {
- PM_PARSER_WARN_FORMAT(
- parser,
- local->location.start,
- local->location.end,
- PM_WARN_UNUSED_LOCAL_VARIABLE,
- (int) constant->length,
- (const char *) constant->start
- );
- }
- }
- }
- }
-}
-
-/******************************************************************************/
-/* Node-related functions */
-/******************************************************************************/
-
-/**
- * Retrieve the constant pool id for the given location.
- */
-static inline pm_constant_id_t
-pm_parser_constant_id_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- return pm_constant_pool_insert_shared(&parser->constant_pool, start, (size_t) (end - start));
-}
-
-/**
- * Retrieve the constant pool id for the given string.
- */
-static inline pm_constant_id_t
-pm_parser_constant_id_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
- return pm_constant_pool_insert_owned(&parser->constant_pool, start, length);
-}
-
-/**
- * Retrieve the constant pool id for the given static literal C string.
- */
-static inline pm_constant_id_t
-pm_parser_constant_id_constant(pm_parser_t *parser, const char *start, size_t length) {
- return pm_constant_pool_insert_constant(&parser->constant_pool, (const uint8_t *) start, length);
-}
-
-/**
- * Retrieve the constant pool id for the given token.
- */
-static inline pm_constant_id_t
-pm_parser_constant_id_token(pm_parser_t *parser, const pm_token_t *token) {
- return pm_parser_constant_id_location(parser, token->start, token->end);
-}
-
-/**
- * Retrieve the constant pool id for the given token. If the token is not
- * provided, then return 0.
- */
-static inline pm_constant_id_t
-pm_parser_optional_constant_id_token(pm_parser_t *parser, const pm_token_t *token) {
- return token->type == PM_TOKEN_NOT_PROVIDED ? 0 : pm_parser_constant_id_token(parser, token);
-}
-
-/**
- * Check whether or not the given node is value expression.
- * If the node is value node, it returns NULL.
- * If not, it returns the pointer to the node to be inspected as "void expression".
- */
-static pm_node_t *
-pm_check_value_expression(pm_parser_t *parser, pm_node_t *node) {
- pm_node_t *void_node = NULL;
-
- while (node != NULL) {
- switch (PM_NODE_TYPE(node)) {
- case PM_RETURN_NODE:
- case PM_BREAK_NODE:
- case PM_NEXT_NODE:
- case PM_REDO_NODE:
- case PM_RETRY_NODE:
- case PM_MATCH_REQUIRED_NODE:
- return void_node != NULL ? void_node : node;
- case PM_MATCH_PREDICATE_NODE:
- return NULL;
- case PM_BEGIN_NODE: {
- pm_begin_node_t *cast = (pm_begin_node_t *) node;
-
- if (cast->ensure_clause != NULL) {
- if (cast->rescue_clause != NULL) {
- pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->rescue_clause);
- if (vn != NULL) return vn;
- }
-
- if (cast->statements != NULL) {
- pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->statements);
- if (vn != NULL) return vn;
- }
-
- node = (pm_node_t *) cast->ensure_clause;
- } else if (cast->rescue_clause != NULL) {
- if (cast->statements == NULL) return NULL;
-
- pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->statements);
- if (vn == NULL) return NULL;
- if (void_node == NULL) void_node = vn;
-
- for (pm_rescue_node_t *rescue_clause = cast->rescue_clause; rescue_clause != NULL; rescue_clause = rescue_clause->subsequent) {
- pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) rescue_clause->statements);
- if (vn == NULL) {
- void_node = NULL;
- break;
- }
- if (void_node == NULL) {
- void_node = vn;
- }
- }
-
- if (cast->else_clause != NULL) {
- node = (pm_node_t *) cast->else_clause;
- } else {
- return void_node;
- }
- } else {
- node = (pm_node_t *) cast->statements;
- }
-
- break;
- }
- case PM_ENSURE_NODE: {
- pm_ensure_node_t *cast = (pm_ensure_node_t *) node;
- node = (pm_node_t *) cast->statements;
- break;
- }
- case PM_PARENTHESES_NODE: {
- pm_parentheses_node_t *cast = (pm_parentheses_node_t *) node;
- node = (pm_node_t *) cast->body;
- break;
- }
- case PM_STATEMENTS_NODE: {
- pm_statements_node_t *cast = (pm_statements_node_t *) node;
- node = cast->body.nodes[cast->body.size - 1];
- break;
- }
- case PM_IF_NODE: {
- pm_if_node_t *cast = (pm_if_node_t *) node;
- if (cast->statements == NULL || cast->subsequent == NULL) {
- return NULL;
- }
- pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->statements);
- if (vn == NULL) {
- return NULL;
- }
- if (void_node == NULL) {
- void_node = vn;
- }
- node = cast->subsequent;
- break;
- }
- case PM_UNLESS_NODE: {
- pm_unless_node_t *cast = (pm_unless_node_t *) node;
- if (cast->statements == NULL || cast->else_clause == NULL) {
- return NULL;
- }
- pm_node_t *vn = pm_check_value_expression(parser, (pm_node_t *) cast->statements);
- if (vn == NULL) {
- return NULL;
- }
- if (void_node == NULL) {
- void_node = vn;
- }
- node = (pm_node_t *) cast->else_clause;
- break;
- }
- case PM_ELSE_NODE: {
- pm_else_node_t *cast = (pm_else_node_t *) node;
- node = (pm_node_t *) cast->statements;
- break;
- }
- case PM_AND_NODE: {
- pm_and_node_t *cast = (pm_and_node_t *) node;
- node = cast->left;
- break;
- }
- case PM_OR_NODE: {
- pm_or_node_t *cast = (pm_or_node_t *) node;
- node = cast->left;
- break;
- }
- case PM_LOCAL_VARIABLE_WRITE_NODE: {
- pm_local_variable_write_node_t *cast = (pm_local_variable_write_node_t *) node;
-
- pm_scope_t *scope = parser->current_scope;
- for (uint32_t depth = 0; depth < cast->depth; depth++) scope = scope->previous;
-
- pm_locals_read(&scope->locals, cast->name);
- return NULL;
- }
- default:
- return NULL;
- }
- }
-
- return NULL;
-}
-
-static inline void
-pm_assert_value_expression(pm_parser_t *parser, pm_node_t *node) {
- pm_node_t *void_node = pm_check_value_expression(parser, node);
- if (void_node != NULL) {
- pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
- }
-}
-
-/**
- * Warn if the given node is a "void" statement.
- */
-static void
-pm_void_statement_check(pm_parser_t *parser, const pm_node_t *node) {
- const char *type = NULL;
- int length = 0;
-
- switch (PM_NODE_TYPE(node)) {
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_CLASS_VARIABLE_READ_NODE:
- case PM_GLOBAL_VARIABLE_READ_NODE:
- case PM_INSTANCE_VARIABLE_READ_NODE:
- case PM_LOCAL_VARIABLE_READ_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- type = "a variable";
- length = 10;
- break;
- case PM_CALL_NODE: {
- const pm_call_node_t *cast = (const pm_call_node_t *) node;
- if (cast->call_operator_loc.start != NULL || cast->message_loc.start == NULL) break;
-
- const pm_constant_t *message = pm_constant_pool_id_to_constant(&parser->constant_pool, cast->name);
- switch (message->length) {
- case 1:
- switch (message->start[0]) {
- case '+':
- case '-':
- case '*':
- case '/':
- case '%':
- case '|':
- case '^':
- case '&':
- case '>':
- case '<':
- type = (const char *) message->start;
- length = 1;
- break;
- }
- break;
- case 2:
- switch (message->start[1]) {
- case '=':
- if (message->start[0] == '<' || message->start[0] == '>' || message->start[0] == '!' || message->start[0] == '=') {
- type = (const char *) message->start;
- length = 2;
- }
- break;
- case '@':
- if (message->start[0] == '+' || message->start[0] == '-') {
- type = (const char *) message->start;
- length = 2;
- }
- break;
- case '*':
- if (message->start[0] == '*') {
- type = (const char *) message->start;
- length = 2;
- }
- break;
- }
- break;
- case 3:
- if (memcmp(message->start, "<=>", 3) == 0) {
- type = "<=>";
- length = 3;
- }
- break;
- }
-
- break;
- }
- case PM_CONSTANT_PATH_NODE:
- type = "::";
- length = 2;
- break;
- case PM_CONSTANT_READ_NODE:
- type = "a constant";
- length = 10;
- break;
- case PM_DEFINED_NODE:
- type = "defined?";
- length = 8;
- break;
- case PM_FALSE_NODE:
- type = "false";
- length = 5;
- break;
- case PM_FLOAT_NODE:
- case PM_IMAGINARY_NODE:
- case PM_INTEGER_NODE:
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
- case PM_INTERPOLATED_STRING_NODE:
- case PM_RATIONAL_NODE:
- case PM_REGULAR_EXPRESSION_NODE:
- case PM_SOURCE_ENCODING_NODE:
- case PM_SOURCE_FILE_NODE:
- case PM_SOURCE_LINE_NODE:
- case PM_STRING_NODE:
- case PM_SYMBOL_NODE:
- type = "a literal";
- length = 9;
- break;
- case PM_NIL_NODE:
- type = "nil";
- length = 3;
- break;
- case PM_RANGE_NODE: {
- const pm_range_node_t *cast = (const pm_range_node_t *) node;
-
- if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
- type = "...";
- length = 3;
- } else {
- type = "..";
- length = 2;
- }
-
- break;
- }
- case PM_SELF_NODE:
- type = "self";
- length = 4;
- break;
- case PM_TRUE_NODE:
- type = "true";
- length = 4;
- break;
- default:
- break;
- }
-
- if (type != NULL) {
- PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length, type);
- }
-}
-
-/**
- * Warn if any of the statements that are not the last statement in the list are
- * a "void" statement.
- */
-static void
-pm_void_statements_check(pm_parser_t *parser, const pm_statements_node_t *node, bool last_value) {
- assert(node->body.size > 0);
- const size_t size = node->body.size - (last_value ? 1 : 0);
- for (size_t index = 0; index < size; index++) {
- pm_void_statement_check(parser, node->body.nodes[index]);
- }
-}
-
-/**
- * When we're handling the predicate of a conditional, we need to know our
- * context in order to determine the kind of warning we should deliver to the
- * user.
- */
-typedef enum {
- PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
- PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
- PM_CONDITIONAL_PREDICATE_TYPE_NOT
-} pm_conditional_predicate_type_t;
-
-/**
- * Add a warning to the parser if the predicate of a conditional is a literal.
- */
-static void
-pm_parser_warn_conditional_predicate_literal(pm_parser_t *parser, pm_node_t *node, pm_conditional_predicate_type_t type, pm_diagnostic_id_t diag_id, const char *prefix) {
- switch (type) {
- case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
- PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix, "condition");
- break;
- case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
- PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix, "flip-flop");
- break;
- case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
- break;
- }
-}
-
-/**
- * Return true if the value being written within the predicate of a conditional
- * is a literal value.
- */
-static bool
-pm_conditional_predicate_warn_write_literal_p(const pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- case PM_ARRAY_NODE: {
- if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) return true;
-
- const pm_array_node_t *cast = (const pm_array_node_t *) node;
- for (size_t index = 0; index < cast->elements.size; index++) {
- if (!pm_conditional_predicate_warn_write_literal_p(cast->elements.nodes[index])) return false;
- }
-
- return true;
- }
- case PM_HASH_NODE: {
- if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) return true;
-
- const pm_hash_node_t *cast = (const pm_hash_node_t *) node;
- for (size_t index = 0; index < cast->elements.size; index++) {
- const pm_node_t *element = cast->elements.nodes[index];
- if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE)) return false;
-
- const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) element;
- if (!pm_conditional_predicate_warn_write_literal_p(assoc->key) || !pm_conditional_predicate_warn_write_literal_p(assoc->value)) return false;
- }
-
- return true;
- }
- case PM_FALSE_NODE:
- case PM_FLOAT_NODE:
- case PM_IMAGINARY_NODE:
- case PM_INTEGER_NODE:
- case PM_NIL_NODE:
- case PM_RATIONAL_NODE:
- case PM_REGULAR_EXPRESSION_NODE:
- case PM_SOURCE_ENCODING_NODE:
- case PM_SOURCE_FILE_NODE:
- case PM_SOURCE_LINE_NODE:
- case PM_STRING_NODE:
- case PM_SYMBOL_NODE:
- case PM_TRUE_NODE:
- return true;
- default:
- return false;
- }
-}
-
-/**
- * Add a warning to the parser if the value that is being written inside of a
- * predicate to a conditional is a literal.
- */
-static inline void
-pm_conditional_predicate_warn_write_literal(pm_parser_t *parser, const pm_node_t *node) {
- if (pm_conditional_predicate_warn_write_literal_p(node)) {
- pm_parser_warn_node(parser, node, parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_WARN_EQUAL_IN_CONDITIONAL_3_3 : PM_WARN_EQUAL_IN_CONDITIONAL);
- }
-}
-
-/**
- * The predicate of conditional nodes can change what would otherwise be regular
- * nodes into specialized nodes. For example:
- *
- * if foo .. bar => RangeNode becomes FlipFlopNode
- * if foo and bar .. baz => RangeNode becomes FlipFlopNode
- * if /foo/ => RegularExpressionNode becomes MatchLastLineNode
- * if /foo #{bar}/ => InterpolatedRegularExpressionNode becomes InterpolatedMatchLastLineNode
- *
- * We also want to warn the user if they're using a static literal as a
- * predicate or writing a static literal as the predicate.
- */
-static void
-pm_conditional_predicate(pm_parser_t *parser, pm_node_t *node, pm_conditional_predicate_type_t type) {
- switch (PM_NODE_TYPE(node)) {
- case PM_AND_NODE: {
- pm_and_node_t *cast = (pm_and_node_t *) node;
- pm_conditional_predicate(parser, cast->left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- pm_conditional_predicate(parser, cast->right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- break;
- }
- case PM_OR_NODE: {
- pm_or_node_t *cast = (pm_or_node_t *) node;
- pm_conditional_predicate(parser, cast->left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- pm_conditional_predicate(parser, cast->right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- break;
- }
- case PM_PARENTHESES_NODE: {
- pm_parentheses_node_t *cast = (pm_parentheses_node_t *) node;
-
- if ((cast->body != NULL) && PM_NODE_TYPE_P(cast->body, PM_STATEMENTS_NODE)) {
- pm_statements_node_t *statements = (pm_statements_node_t *) cast->body;
- if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0], type);
- }
-
- break;
- }
- case PM_BEGIN_NODE: {
- pm_begin_node_t *cast = (pm_begin_node_t *) node;
- if (cast->statements != NULL) {
- pm_statements_node_t *statements = cast->statements;
- if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0], type);
- }
- break;
- }
- case PM_RANGE_NODE: {
- pm_range_node_t *cast = (pm_range_node_t *) node;
-
- if (cast->left != NULL) pm_conditional_predicate(parser, cast->left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
- if (cast->right != NULL) pm_conditional_predicate(parser, cast->right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
-
- // Here we change the range node into a flip flop node. We can do
- // this since the nodes are exactly the same except for the type.
- // We're only asserting against the size when we should probably
- // assert against the entire layout, but we'll assume tests will
- // catch this.
- assert(sizeof(pm_range_node_t) == sizeof(pm_flip_flop_node_t));
- node->type = PM_FLIP_FLOP_NODE;
-
- break;
- }
- case PM_REGULAR_EXPRESSION_NODE:
- // Here we change the regular expression node into a match last line
- // node. We can do this since the nodes are exactly the same except
- // for the type.
- assert(sizeof(pm_regular_expression_node_t) == sizeof(pm_match_last_line_node_t));
- node->type = PM_MATCH_LAST_LINE_NODE;
-
- if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
- pm_parser_warn_conditional_predicate_literal(parser, node, type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT, "regex ");
- }
-
- break;
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
- // Here we change the interpolated regular expression node into an
- // interpolated match last line node. We can do this since the nodes
- // are exactly the same except for the type.
- assert(sizeof(pm_interpolated_regular_expression_node_t) == sizeof(pm_interpolated_match_last_line_node_t));
- node->type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
-
- if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
- pm_parser_warn_conditional_predicate_literal(parser, node, type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE, "regex ");
- }
-
- break;
- case PM_INTEGER_NODE:
- if (type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
- if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
- pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
- }
- } else {
- pm_parser_warn_conditional_predicate_literal(parser, node, type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE, "");
- }
- break;
- case PM_STRING_NODE:
- case PM_SOURCE_FILE_NODE:
- case PM_INTERPOLATED_STRING_NODE:
- pm_parser_warn_conditional_predicate_literal(parser, node, type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT, "string ");
- break;
- case PM_SYMBOL_NODE:
- case PM_INTERPOLATED_SYMBOL_NODE:
- pm_parser_warn_conditional_predicate_literal(parser, node, type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE, "symbol ");
- break;
- case PM_SOURCE_LINE_NODE:
- case PM_SOURCE_ENCODING_NODE:
- case PM_FLOAT_NODE:
- case PM_RATIONAL_NODE:
- case PM_IMAGINARY_NODE:
- pm_parser_warn_conditional_predicate_literal(parser, node, type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE, "");
- break;
- case PM_CLASS_VARIABLE_WRITE_NODE:
- pm_conditional_predicate_warn_write_literal(parser, ((pm_class_variable_write_node_t *) node)->value);
- break;
- case PM_CONSTANT_WRITE_NODE:
- pm_conditional_predicate_warn_write_literal(parser, ((pm_constant_write_node_t *) node)->value);
- break;
- case PM_GLOBAL_VARIABLE_WRITE_NODE:
- pm_conditional_predicate_warn_write_literal(parser, ((pm_global_variable_write_node_t *) node)->value);
- break;
- case PM_INSTANCE_VARIABLE_WRITE_NODE:
- pm_conditional_predicate_warn_write_literal(parser, ((pm_instance_variable_write_node_t *) node)->value);
- break;
- case PM_LOCAL_VARIABLE_WRITE_NODE:
- pm_conditional_predicate_warn_write_literal(parser, ((pm_local_variable_write_node_t *) node)->value);
- break;
- case PM_MULTI_WRITE_NODE:
- pm_conditional_predicate_warn_write_literal(parser, ((pm_multi_write_node_t *) node)->value);
- break;
- default:
- break;
- }
-}
-
-/**
- * In a lot of places in the tree you can have tokens that are not provided but
- * that do not cause an error. For example, this happens in a method call
- * without parentheses. In these cases we set the token to the "not provided" type.
- * For example:
- *
- * pm_token_t token = not_provided(parser);
- */
-static inline pm_token_t
-not_provided(pm_parser_t *parser) {
- return (pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->start, .end = parser->start };
-}
-
-#define PM_LOCATION_NULL_VALUE(parser) ((pm_location_t) { .start = (parser)->start, .end = (parser)->start })
-#define PM_LOCATION_TOKEN_VALUE(token) ((pm_location_t) { .start = (token)->start, .end = (token)->end })
-#define PM_LOCATION_NODE_VALUE(node) ((pm_location_t) { .start = (node)->location.start, .end = (node)->location.end })
-#define PM_LOCATION_NODE_BASE_VALUE(node) ((pm_location_t) { .start = (node)->base.location.start, .end = (node)->base.location.end })
-#define PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE ((pm_location_t) { .start = NULL, .end = NULL })
-#define PM_OPTIONAL_LOCATION_TOKEN_VALUE(token) ((token)->type == PM_TOKEN_NOT_PROVIDED ? PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE : PM_LOCATION_TOKEN_VALUE(token))
-
-/**
- * This is a special out parameter to the parse_arguments_list function that
- * includes opening and closing parentheses in addition to the arguments since
- * it's so common. It is handy to use when passing argument information to one
- * of the call node creation functions.
- */
-typedef struct {
- /** The optional location of the opening parenthesis or bracket. */
- pm_location_t opening_loc;
-
- /** The lazily-allocated optional arguments node. */
- pm_arguments_node_t *arguments;
-
- /** The optional location of the closing parenthesis or bracket. */
- pm_location_t closing_loc;
-
- /** The optional block attached to the call. */
- pm_node_t *block;
-
- /** The flag indicating whether this arguments list has forwarding argument. */
- bool has_forwarding;
-} pm_arguments_t;
-
-/**
- * Retrieve the end location of a `pm_arguments_t` object.
- */
-static inline const uint8_t *
-pm_arguments_end(pm_arguments_t *arguments) {
- if (arguments->block != NULL) {
- const uint8_t *end = arguments->block->location.end;
- if (arguments->closing_loc.start != NULL && arguments->closing_loc.end > end) {
- end = arguments->closing_loc.end;
- }
- return end;
- }
- if (arguments->closing_loc.start != NULL) {
- return arguments->closing_loc.end;
- }
- if (arguments->arguments != NULL) {
- return arguments->arguments->base.location.end;
- }
- return arguments->closing_loc.end;
-}
-
-/**
- * Check that we're not about to attempt to attach a brace block to a call that
- * has arguments without parentheses.
- */
-static void
-pm_arguments_validate_block(pm_parser_t *parser, pm_arguments_t *arguments, pm_block_node_t *block) {
- // First, check that we have arguments and that we don't have a closing
- // location for them.
- if (arguments->arguments == NULL || arguments->closing_loc.start != NULL) {
- return;
- }
-
- // Next, check that we don't have a single parentheses argument. This would
- // look like:
- //
- // foo (1) {}
- //
- // In this case, it's actually okay for the block to be attached to the
- // call, even though it looks like it's attached to the argument.
- if (arguments->arguments->arguments.size == 1 && PM_NODE_TYPE_P(arguments->arguments->arguments.nodes[0], PM_PARENTHESES_NODE)) {
- return;
- }
-
- // If we didn't hit a case before this check, then at this point we need to
- // add a syntax error.
- pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
-}
-
-/******************************************************************************/
-/* Basic character checks */
-/******************************************************************************/
-
-/**
- * This function is used extremely frequently to lex all of the identifiers in a
- * source file, so it's important that it be as fast as possible. For this
- * reason we have the encoding_changed boolean to check if we need to go through
- * the function pointer or can just directly use the UTF-8 functions.
- */
-static inline size_t
-char_is_identifier_start(const pm_parser_t *parser, const uint8_t *b) {
- if (parser->encoding_changed) {
- size_t width;
- if ((width = parser->encoding->alpha_char(b, parser->end - b)) != 0) {
- return width;
- } else if (*b == '_') {
- return 1;
- } else if (*b >= 0x80) {
- return parser->encoding->char_width(b, parser->end - b);
- } else {
- return 0;
- }
- } else if (*b < 0x80) {
- return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT ? 1 : 0) || (*b == '_');
- } else {
- return pm_encoding_utf_8_char_width(b, parser->end - b);
- }
-}
-
-/**
- * Similar to char_is_identifier but this function assumes that the encoding
- * has not been changed.
- */
-static inline size_t
-char_is_identifier_utf8(const uint8_t *b, const uint8_t *end) {
- if (*b < 0x80) {
- return (*b == '_') || (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT ? 1 : 0);
- } else {
- return pm_encoding_utf_8_char_width(b, end - b);
- }
-}
-
-/**
- * Like the above, this function is also used extremely frequently to lex all of
- * the identifiers in a source file once the first character has been found. So
- * it's important that it be as fast as possible.
- */
-static inline size_t
-char_is_identifier(const pm_parser_t *parser, const uint8_t *b) {
- if (parser->encoding_changed) {
- size_t width;
- if ((width = parser->encoding->alnum_char(b, parser->end - b)) != 0) {
- return width;
- } else if (*b == '_') {
- return 1;
- } else if (*b >= 0x80) {
- return parser->encoding->char_width(b, parser->end - b);
- } else {
- return 0;
- }
- }
- return char_is_identifier_utf8(b, parser->end);
-}
-
-// Here we're defining a perfect hash for the characters that are allowed in
-// global names. This is used to quickly check the next character after a $ to
-// see if it's a valid character for a global name.
-#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
-#define PUNCT(idx) ( \
- BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
- BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
- BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
- BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
- BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
- BIT('0', idx))
-
-const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
-
-#undef BIT
-#undef PUNCT
-
-static inline bool
-char_is_global_name_punctuation(const uint8_t b) {
- const unsigned int i = (const unsigned int) b;
- if (i <= 0x20 || 0x7e < i) return false;
-
- return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
-}
-
-static inline bool
-token_is_setter_name(pm_token_t *token) {
- return (
- (token->type == PM_TOKEN_IDENTIFIER) &&
- (token->end - token->start >= 2) &&
- (token->end[-1] == '=')
- );
-}
-
-/**
- * Returns true if the given local variable is a keyword.
- */
-static bool
-pm_local_is_keyword(const char *source, size_t length) {
-#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
-
- switch (length) {
- case 2:
- switch (source[0]) {
- case 'd': KEYWORD("do"); return false;
- case 'i': KEYWORD("if"); KEYWORD("in"); return false;
- case 'o': KEYWORD("or"); return false;
- default: return false;
- }
- case 3:
- switch (source[0]) {
- case 'a': KEYWORD("and"); return false;
- case 'd': KEYWORD("def"); return false;
- case 'e': KEYWORD("end"); return false;
- case 'f': KEYWORD("for"); return false;
- case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
- default: return false;
- }
- case 4:
- switch (source[0]) {
- case 'c': KEYWORD("case"); return false;
- case 'e': KEYWORD("else"); return false;
- case 'n': KEYWORD("next"); return false;
- case 'r': KEYWORD("redo"); return false;
- case 's': KEYWORD("self"); return false;
- case 't': KEYWORD("then"); KEYWORD("true"); return false;
- case 'w': KEYWORD("when"); return false;
- default: return false;
- }
- case 5:
- switch (source[0]) {
- case 'a': KEYWORD("alias"); return false;
- case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
- case 'c': KEYWORD("class"); return false;
- case 'e': KEYWORD("elsif"); return false;
- case 'f': KEYWORD("false"); return false;
- case 'r': KEYWORD("retry"); return false;
- case 's': KEYWORD("super"); return false;
- case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
- case 'w': KEYWORD("while"); return false;
- case 'y': KEYWORD("yield"); return false;
- default: return false;
- }
- case 6:
- switch (source[0]) {
- case 'e': KEYWORD("ensure"); return false;
- case 'm': KEYWORD("module"); return false;
- case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
- case 'u': KEYWORD("unless"); return false;
- default: return false;
- }
- case 8:
- KEYWORD("__LINE__");
- KEYWORD("__FILE__");
- return false;
- case 12:
- KEYWORD("__ENCODING__");
- return false;
- default:
- return false;
- }
-
-#undef KEYWORD
-}
-
-/******************************************************************************/
-/* Node flag handling functions */
-/******************************************************************************/
-
-/**
- * Set the given flag on the given node.
- */
-static inline void
-pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
- node->flags |= flag;
-}
-
-/**
- * Remove the given flag from the given node.
- */
-static inline void
-pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
- node->flags &= (pm_node_flags_t) ~flag;
-}
-
-/**
- * Set the repeated parameter flag on the given node.
- */
-static inline void
-pm_node_flag_set_repeated_parameter(pm_node_t *node) {
- assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
- PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
- PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
- PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
- PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
- PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
- PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
- PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
-
- pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
-}
-
-/******************************************************************************/
-/* Node creation functions */
-/******************************************************************************/
-
-/**
- * When you have an encoding flag on a regular expression, it takes precedence
- * over all of the previously set encoding flags. So we need to mask off any
- * previously set encoding flags before setting the new one.
- */
-#define PM_REGULAR_EXPRESSION_ENCODING_MASK ~(PM_REGULAR_EXPRESSION_FLAGS_EUC_JP | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J | PM_REGULAR_EXPRESSION_FLAGS_UTF_8)
-
-/**
- * Parse out the options for a regular expression.
- */
-static inline pm_node_flags_t
-pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
- pm_node_flags_t flags = 0;
-
- if (closing->type == PM_TOKEN_REGEXP_END) {
- pm_buffer_t unknown_flags = { 0 };
-
- for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
- switch (*flag) {
- case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
- case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
- case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
- case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
-
- case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
- case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
- case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
- case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
-
- default: pm_buffer_append_byte(&unknown_flags, *flag);
- }
- }
-
- size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
- if (unknown_flags_length != 0) {
- const char *word = unknown_flags_length >= 2 ? "options" : "option";
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
- }
- pm_buffer_free(&unknown_flags);
- }
-
- return flags;
-}
-
-#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
-
-static pm_statements_node_t *
-pm_statements_node_create(pm_parser_t *parser);
-
-static void
-pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
-
-static size_t
-pm_statements_node_body_length(pm_statements_node_t *node);
-
-/**
- * This function is here to allow us a place to extend in the future when we
- * implement our own arena allocation.
- */
-static inline void *
-pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
- void *memory = xcalloc(1, size);
- if (memory == NULL) {
- fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
- abort();
- }
- return memory;
-}
-
-#define PM_NODE_ALLOC(parser, type) (type *) pm_node_alloc(parser, sizeof(type))
-#define PM_NODE_IDENTIFY(parser) (++parser->node_id)
-
-/**
- * Allocate a new MissingNode node.
- */
-static pm_missing_node_t *
-pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- pm_missing_node_t *node = PM_NODE_ALLOC(parser, pm_missing_node_t);
-
- *node = (pm_missing_node_t) {{
- .type = PM_MISSING_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = { .start = start, .end = end }
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new AliasGlobalVariableNode node.
- */
-static pm_alias_global_variable_node_t *
-pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
- assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
- pm_alias_global_variable_node_t *node = PM_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
-
- *node = (pm_alias_global_variable_node_t) {
- {
- .type = PM_ALIAS_GLOBAL_VARIABLE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = old_name->location.end
- },
- },
- .new_name = new_name,
- .old_name = old_name,
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new AliasMethodNode node.
- */
-static pm_alias_method_node_t *
-pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
- assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
- pm_alias_method_node_t *node = PM_NODE_ALLOC(parser, pm_alias_method_node_t);
-
- *node = (pm_alias_method_node_t) {
- {
- .type = PM_ALIAS_METHOD_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = old_name->location.end
- },
- },
- .new_name = new_name,
- .old_name = old_name,
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate a new AlternationPatternNode node.
- */
-static pm_alternation_pattern_node_t *
-pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
- pm_alternation_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
-
- *node = (pm_alternation_pattern_node_t) {
- {
- .type = PM_ALTERNATION_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = left->location.start,
- .end = right->location.end
- },
- },
- .left = left,
- .right = right,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new and node.
- */
-static pm_and_node_t *
-pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
- pm_assert_value_expression(parser, left);
-
- pm_and_node_t *node = PM_NODE_ALLOC(parser, pm_and_node_t);
-
- *node = (pm_and_node_t) {
- {
- .type = PM_AND_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = left->location.start,
- .end = right->location.end
- },
- },
- .left = left,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .right = right
- };
-
- return node;
-}
-
-/**
- * Allocate an initialize a new arguments node.
- */
-static pm_arguments_node_t *
-pm_arguments_node_create(pm_parser_t *parser) {
- pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
-
- *node = (pm_arguments_node_t) {
- {
- .type = PM_ARGUMENTS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .arguments = { 0 }
- };
-
- return node;
-}
-
-/**
- * Return the size of the given arguments node.
- */
-static size_t
-pm_arguments_node_size(pm_arguments_node_t *node) {
- return node->arguments.size;
-}
-
-/**
- * Append an argument to an arguments node.
- */
-static void
-pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
- if (pm_arguments_node_size(node) == 0) {
- node->base.location.start = argument->location.start;
- }
-
- node->base.location.end = argument->location.end;
- pm_node_list_append(&node->arguments, argument);
-
- if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
- if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
- pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
- } else {
- pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
- }
- }
-}
-
-/**
- * Allocate and initialize a new ArrayNode node.
- */
-static pm_array_node_t *
-pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
- pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
-
- *node = (pm_array_node_t) {
- {
- .type = PM_ARRAY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(opening)
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .elements = { 0 }
- };
-
- return node;
-}
-
-/**
- * Return the size of the given array node.
- */
-static inline size_t
-pm_array_node_size(pm_array_node_t *node) {
- return node->elements.size;
-}
-
-/**
- * Append an argument to an array node.
- */
-static inline void
-pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
- if (!node->elements.size && !node->opening_loc.start) {
- node->base.location.start = element->location.start;
- }
-
- pm_node_list_append(&node->elements, element);
- node->base.location.end = element->location.end;
-
- // If the element is not a static literal, then the array is not a static
- // literal. Turn that flag off.
- if (PM_NODE_TYPE_P(element, PM_ARRAY_NODE) || PM_NODE_TYPE_P(element, PM_HASH_NODE) || PM_NODE_TYPE_P(element, PM_RANGE_NODE) || !PM_NODE_FLAG_P(element, PM_NODE_FLAG_STATIC_LITERAL)) {
- pm_node_flag_unset((pm_node_t *)node, PM_NODE_FLAG_STATIC_LITERAL);
- }
-
- if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
- pm_node_flag_set((pm_node_t *)node, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
- }
-}
-
-/**
- * Set the closing token and end location of an array node.
- */
-static void
-pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
- assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
- node->base.location.end = closing->end;
- node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
-}
-
-/**
- * Allocate and initialize a new array pattern node. The node list given in the
- * nodes parameter is guaranteed to have at least two nodes.
- */
-static pm_array_pattern_node_t *
-pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
- pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
-
- *node = (pm_array_pattern_node_t) {
- {
- .type = PM_ARRAY_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = nodes->nodes[0]->location.start,
- .end = nodes->nodes[nodes->size - 1]->location.end
- },
- },
- .constant = NULL,
- .rest = NULL,
- .requireds = { 0 },
- .posts = { 0 },
- .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- // For now we're going to just copy over each pointer manually. This could be
- // much more efficient, as we could instead resize the node list.
- bool found_rest = false;
- pm_node_t *child;
-
- PM_NODE_LIST_FOREACH(nodes, index, child) {
- if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
- node->rest = child;
- found_rest = true;
- } else if (found_rest) {
- pm_node_list_append(&node->posts, child);
- } else {
- pm_node_list_append(&node->requireds, child);
- }
- }
-
- return node;
-}
-
-/**
- * Allocate and initialize a new array pattern node from a single rest node.
- */
-static pm_array_pattern_node_t *
-pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
- pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
-
- *node = (pm_array_pattern_node_t) {
- {
- .type = PM_ARRAY_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = rest->location,
- },
- .constant = NULL,
- .rest = rest,
- .requireds = { 0 },
- .posts = { 0 },
- .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new array pattern node from a constant and opening
- * and closing tokens.
- */
-static pm_array_pattern_node_t *
-pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
- pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
-
- *node = (pm_array_pattern_node_t) {
- {
- .type = PM_ARRAY_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = constant->location.start,
- .end = closing->end
- },
- },
- .constant = constant,
- .rest = NULL,
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
- .requireds = { 0 },
- .posts = { 0 }
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new array pattern node from an opening and closing
- * token.
- */
-static pm_array_pattern_node_t *
-pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
- pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
-
- *node = (pm_array_pattern_node_t) {
- {
- .type = PM_ARRAY_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = opening->start,
- .end = closing->end
- },
- },
- .constant = NULL,
- .rest = NULL,
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
- .requireds = { 0 },
- .posts = { 0 }
- };
-
- return node;
-}
-
-static inline void
-pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
- pm_node_list_append(&node->requireds, inner);
-}
-
-/**
- * Allocate and initialize a new assoc node.
- */
-static pm_assoc_node_t *
-pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
- pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
- const uint8_t *end;
-
- if (value != NULL && value->location.end > key->location.end) {
- end = value->location.end;
- } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
- end = operator->end;
- } else {
- end = key->location.end;
- }
-
- // Hash string keys will be frozen, so we can mark them as frozen here so
- // that the compiler picks them up and also when we check for static literal
- // on the keys it gets factored in.
- if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
- key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
- }
-
- // If the key and value of this assoc node are both static literals, then
- // we can mark this node as a static literal.
- pm_node_flags_t flags = 0;
- if (
- !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
- value && !PM_NODE_TYPE_P(value, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(value, PM_HASH_NODE) && !PM_NODE_TYPE_P(value, PM_RANGE_NODE)
- ) {
- flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
- }
-
- *node = (pm_assoc_node_t) {
- {
- .type = PM_ASSOC_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = key->location.start,
- .end = end
- },
- },
- .key = key,
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new assoc splat node.
- */
-static pm_assoc_splat_node_t *
-pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
- assert(operator->type == PM_TOKEN_USTAR_STAR);
- pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
-
- *node = (pm_assoc_splat_node_t) {
- {
- .type = PM_ASSOC_SPLAT_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = value == NULL ? operator->end : value->location.end
- },
- },
- .value = value,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate a new BackReferenceReadNode node.
- */
-static pm_back_reference_read_node_t *
-pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
- assert(name->type == PM_TOKEN_BACK_REFERENCE);
- pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
-
- *node = (pm_back_reference_read_node_t) {
- {
- .type = PM_BACK_REFERENCE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name),
- },
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize new a begin node.
- */
-static pm_begin_node_t *
-pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
- pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
-
- *node = (pm_begin_node_t) {
- {
- .type = PM_BEGIN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = begin_keyword->start,
- .end = statements == NULL ? begin_keyword->end : statements->base.location.end
- },
- },
- .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
- .statements = statements,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-}
-
-/**
- * Set the rescue clause, optionally start, and end location of a begin node.
- */
-static void
-pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
- // If the begin keyword doesn't exist, we set the start on the begin_node
- if (!node->begin_keyword_loc.start) {
- node->base.location.start = rescue_clause->base.location.start;
- }
- node->base.location.end = rescue_clause->base.location.end;
- node->rescue_clause = rescue_clause;
-}
-
-/**
- * Set the else clause and end location of a begin node.
- */
-static void
-pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
- node->base.location.end = else_clause->base.location.end;
- node->else_clause = else_clause;
-}
-
-/**
- * Set the ensure clause and end location of a begin node.
- */
-static void
-pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
- node->base.location.end = ensure_clause->base.location.end;
- node->ensure_clause = ensure_clause;
-}
-
-/**
- * Set the end keyword and end location of a begin node.
- */
-static void
-pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
- assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
-
- node->base.location.end = end_keyword->end;
- node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
-}
-
-/**
- * Allocate and initialize a new BlockArgumentNode node.
- */
-static pm_block_argument_node_t *
-pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
- pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
-
- *node = (pm_block_argument_node_t) {
- {
- .type = PM_BLOCK_ARGUMENT_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = expression == NULL ? operator->end : expression->location.end
- },
- },
- .expression = expression,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new BlockNode node.
- */
-static pm_block_node_t *
-pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *opening, pm_node_t *parameters, pm_node_t *body, const pm_token_t *closing) {
- pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
-
- *node = (pm_block_node_t) {
- {
- .type = PM_BLOCK_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = { .start = opening->start, .end = closing->end },
- },
- .locals = *locals,
- .parameters = parameters,
- .body = body,
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new BlockParameterNode node.
- */
-static pm_block_parameter_node_t *
-pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
- assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
- pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
-
- *node = (pm_block_parameter_node_t) {
- {
- .type = PM_BLOCK_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
- },
- },
- .name = pm_parser_optional_constant_id_token(parser, name),
- .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new BlockParametersNode node.
- */
-static pm_block_parameters_node_t *
-pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
- pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
-
- const uint8_t *start;
- if (opening->type != PM_TOKEN_NOT_PROVIDED) {
- start = opening->start;
- } else if (parameters != NULL) {
- start = parameters->base.location.start;
- } else {
- start = NULL;
- }
-
- const uint8_t *end;
- if (parameters != NULL) {
- end = parameters->base.location.end;
- } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
- end = opening->end;
- } else {
- end = NULL;
- }
-
- *node = (pm_block_parameters_node_t) {
- {
- .type = PM_BLOCK_PARAMETERS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = start,
- .end = end
- }
- },
- .parameters = parameters,
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .locals = { 0 }
- };
-
- return node;
-}
-
-/**
- * Set the closing location of a BlockParametersNode node.
- */
-static void
-pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
- assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
-
- node->base.location.end = closing->end;
- node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
-}
-
-/**
- * Allocate and initialize a new BlockLocalVariableNode node.
- */
-static pm_block_local_variable_node_t *
-pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
- pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
-
- *node = (pm_block_local_variable_node_t) {
- {
- .type = PM_BLOCK_LOCAL_VARIABLE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name),
- },
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
-}
-
-/**
- * Append a new block-local variable to a BlockParametersNode node.
- */
-static void
-pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
- pm_node_list_append(&node->locals, (pm_node_t *) local);
-
- if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
- node->base.location.end = local->base.location.end;
-}
-
-/**
- * Allocate and initialize a new BreakNode node.
- */
-static pm_break_node_t *
-pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
- assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
- pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
-
- *node = (pm_break_node_t) {
- {
- .type = PM_BREAK_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
- },
- },
- .arguments = arguments,
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
- };
-
- return node;
-}
-
-// There are certain flags that we want to use internally but don't want to
-// expose because they are not relevant beyond parsing. Therefore we'll define
-// them here and not define them in config.yml/a header file.
-static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = 0x4;
-static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = 0x40;
-static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = 0x80;
-static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = 0x100;
-
-/**
- * Allocate and initialize a new CallNode node. This sets everything to NULL or
- * PM_TOKEN_NOT_PROVIDED as appropriate such that its values can be overridden
- * in the various specializations of this function.
- */
-static pm_call_node_t *
-pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
- pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
-
- *node = (pm_call_node_t) {
- {
- .type = PM_CALL_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NULL_VALUE(parser),
- },
- .receiver = NULL,
- .call_operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .message_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .arguments = NULL,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .block = NULL,
- .name = 0
- };
-
- return node;
-}
-
-/**
- * Returns the value that the ignore visibility flag should be set to for the
- * given receiver.
- */
-static inline pm_node_flags_t
-pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
- return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
-}
-
-/**
- * Allocate and initialize a new CallNode node from an aref or an aset
- * expression.
- */
-static pm_call_node_t *
-pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
- pm_assert_value_expression(parser, receiver);
-
- pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
- if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
- flags |= PM_CALL_NODE_FLAGS_INDEX;
- }
-
- pm_call_node_t *node = pm_call_node_create(parser, flags);
-
- node->base.location.start = receiver->location.start;
- node->base.location.end = pm_arguments_end(arguments);
-
- node->receiver = receiver;
- node->message_loc.start = arguments->opening_loc.start;
- node->message_loc.end = arguments->closing_loc.end;
-
- node->opening_loc = arguments->opening_loc;
- node->arguments = arguments->arguments;
- node->closing_loc = arguments->closing_loc;
- node->block = arguments->block;
-
- node->name = pm_parser_constant_id_constant(parser, "[]", 2);
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a binary expression.
- */
-static pm_call_node_t *
-pm_call_node_binary_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_node_t *argument, pm_node_flags_t flags) {
- pm_assert_value_expression(parser, receiver);
- pm_assert_value_expression(parser, argument);
-
- pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
-
- node->base.location.start = MIN(receiver->location.start, argument->location.start);
- node->base.location.end = MAX(receiver->location.end, argument->location.end);
-
- node->receiver = receiver;
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
-
- pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
- pm_arguments_node_arguments_append(arguments, argument);
- node->arguments = arguments;
-
- node->name = pm_parser_constant_id_token(parser, operator);
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a call expression.
- */
-static pm_call_node_t *
-pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
- pm_assert_value_expression(parser, receiver);
-
- pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
-
- node->base.location.start = receiver->location.start;
- const uint8_t *end = pm_arguments_end(arguments);
- if (end == NULL) {
- end = message->end;
- }
- node->base.location.end = end;
-
- node->receiver = receiver;
- node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
- node->opening_loc = arguments->opening_loc;
- node->arguments = arguments->arguments;
- node->closing_loc = arguments->closing_loc;
- node->block = arguments->block;
-
- if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
- pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
- }
-
- node->name = pm_parser_constant_id_token(parser, message);
- return node;
-}
-
-/**
- * Allocate and initialize a new synthesized CallNode node from a call expression.
- */
-static pm_call_node_t *
-pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
- pm_call_node_t *node = pm_call_node_create(parser, 0);
- node->base.location.start = parser->start;
- node->base.location.end = parser->end;
-
- node->receiver = receiver;
- node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
- node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
- node->arguments = arguments;
-
- node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a call to a method name
- * without a receiver that could not have been a local variable read.
- */
-static pm_call_node_t *
-pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
- pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
-
- node->base.location.start = message->start;
- node->base.location.end = pm_arguments_end(arguments);
-
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
- node->opening_loc = arguments->opening_loc;
- node->arguments = arguments->arguments;
- node->closing_loc = arguments->closing_loc;
- node->block = arguments->block;
-
- node->name = pm_parser_constant_id_token(parser, message);
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a synthesized call to a
- * method name with the given arguments.
- */
-static pm_call_node_t *
-pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
- pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
-
- node->base.location = PM_LOCATION_NULL_VALUE(parser);
- node->arguments = arguments;
-
- node->name = name;
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a not expression.
- */
-static pm_call_node_t *
-pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
- pm_assert_value_expression(parser, receiver);
- if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
-
- pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
-
- node->base.location.start = message->start;
- if (arguments->closing_loc.start != NULL) {
- node->base.location.end = arguments->closing_loc.end;
- } else {
- assert(receiver != NULL);
- node->base.location.end = receiver->location.end;
- }
-
- node->receiver = receiver;
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
- node->opening_loc = arguments->opening_loc;
- node->arguments = arguments->arguments;
- node->closing_loc = arguments->closing_loc;
-
- node->name = pm_parser_constant_id_constant(parser, "!", 1);
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a call shorthand expression.
- */
-static pm_call_node_t *
-pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
- pm_assert_value_expression(parser, receiver);
-
- pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
-
- node->base.location.start = receiver->location.start;
- node->base.location.end = pm_arguments_end(arguments);
-
- node->receiver = receiver;
- node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
- node->opening_loc = arguments->opening_loc;
- node->arguments = arguments->arguments;
- node->closing_loc = arguments->closing_loc;
- node->block = arguments->block;
-
- if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
- pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
- }
-
- node->name = pm_parser_constant_id_constant(parser, "call", 4);
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a unary operator expression.
- */
-static pm_call_node_t *
-pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
- pm_assert_value_expression(parser, receiver);
-
- pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
-
- node->base.location.start = operator->start;
- node->base.location.end = receiver->location.end;
-
- node->receiver = receiver;
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
-
- node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
- return node;
-}
-
-/**
- * Allocate and initialize a new CallNode node from a call to a method name
- * without a receiver that could also have been a local variable read.
- */
-static pm_call_node_t *
-pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
- pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
-
- node->base.location = PM_LOCATION_TOKEN_VALUE(message);
- node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
-
- node->name = pm_parser_constant_id_token(parser, message);
- return node;
-}
-
-/**
- * Returns whether or not this call can be used on the left-hand side of an
- * operator assignment.
- */
-static inline bool
-pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
- return (
- (node->message_loc.start != NULL) &&
- (node->message_loc.end[-1] != '!') &&
- (node->message_loc.end[-1] != '?') &&
- char_is_identifier_start(parser, node->message_loc.start) &&
- (node->opening_loc.start == NULL) &&
- (node->arguments == NULL) &&
- (node->block == NULL)
- );
-}
-
-/**
- * Initialize the read name by reading the write name and chopping off the '='.
- */
-static void
-pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
- pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
-
- if (write_constant->length > 0) {
- size_t length = write_constant->length - 1;
-
- void *memory = xmalloc(length);
- memcpy(memory, write_constant->start, length);
-
- *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
- } else {
- // We can get here if the message was missing because of a syntax error.
- *read_name = pm_parser_constant_id_constant(parser, "", 0);
- }
-}
-
-/**
- * Allocate and initialize a new CallAndWriteNode node.
- */
-static pm_call_and_write_node_t *
-pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(target->block == NULL);
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
-
- *node = (pm_call_and_write_node_t) {
- {
- .type = PM_CALL_AND_WRITE_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .message_loc = target->message_loc,
- .read_name = 0,
- .write_name = target->name,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- xfree(target);
-
- return node;
-}
-
-/**
- * Validate that index expressions do not have keywords or blocks if we are
- * parsing as Ruby 3.4+.
- */
-static void
-pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
- if (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) {
- if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
- pm_node_t *node;
- PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
- if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
- pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
- break;
- }
- }
- }
-
- if (block != NULL) {
- pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
- }
- }
-}
-
-/**
- * Allocate and initialize a new IndexAndWriteNode node.
- */
-static pm_index_and_write_node_t *
-pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
-
- pm_index_arguments_check(parser, target->arguments, target->block);
-
- assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
- *node = (pm_index_and_write_node_t) {
- {
- .type = PM_INDEX_AND_WRITE_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .opening_loc = target->opening_loc,
- .arguments = target->arguments,
- .closing_loc = target->closing_loc,
- .block = (pm_block_argument_node_t *) target->block,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- xfree(target);
-
- return node;
-}
-
-/**
- * Allocate a new CallOperatorWriteNode node.
- */
-static pm_call_operator_write_node_t *
-pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(target->block == NULL);
- pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
-
- *node = (pm_call_operator_write_node_t) {
- {
- .type = PM_CALL_OPERATOR_WRITE_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .message_loc = target->message_loc,
- .read_name = 0,
- .write_name = target->name,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- xfree(target);
-
- return node;
-}
-
-/**
- * Allocate a new IndexOperatorWriteNode node.
- */
-static pm_index_operator_write_node_t *
-pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
-
- pm_index_arguments_check(parser, target->arguments, target->block);
-
- assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
- *node = (pm_index_operator_write_node_t) {
- {
- .type = PM_INDEX_OPERATOR_WRITE_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .opening_loc = target->opening_loc,
- .arguments = target->arguments,
- .closing_loc = target->closing_loc,
- .block = (pm_block_argument_node_t *) target->block,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- xfree(target);
-
- return node;
-}
-
-/**
- * Allocate and initialize a new CallOrWriteNode node.
- */
-static pm_call_or_write_node_t *
-pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(target->block == NULL);
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
-
- *node = (pm_call_or_write_node_t) {
- {
- .type = PM_CALL_OR_WRITE_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .message_loc = target->message_loc,
- .read_name = 0,
- .write_name = target->name,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- xfree(target);
-
- return node;
-}
-
-/**
- * Allocate and initialize a new IndexOrWriteNode node.
- */
-static pm_index_or_write_node_t *
-pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
-
- pm_index_arguments_check(parser, target->arguments, target->block);
-
- assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
- *node = (pm_index_or_write_node_t) {
- {
- .type = PM_INDEX_OR_WRITE_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .opening_loc = target->opening_loc,
- .arguments = target->arguments,
- .closing_loc = target->closing_loc,
- .block = (pm_block_argument_node_t *) target->block,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- xfree(target);
-
- return node;
-}
-
-/**
- * Allocate and initialize a new CallTargetNode node from an existing call
- * node.
- */
-static pm_call_target_node_t *
-pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
- pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
-
- *node = (pm_call_target_node_t) {
- {
- .type = PM_CALL_TARGET_NODE,
- .flags = target->base.flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = target->base.location
- },
- .receiver = target->receiver,
- .call_operator_loc = target->call_operator_loc,
- .name = target->name,
- .message_loc = target->message_loc
- };
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- xfree(target);
-
- return node;
-}
-
-/**
- * Allocate and initialize a new IndexTargetNode node from an existing call
- * node.
- */
-static pm_index_target_node_t *
-pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
- pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
- pm_node_flags_t flags = target->base.flags;
-
- pm_index_arguments_check(parser, target->arguments, target->block);
-
- assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
- *node = (pm_index_target_node_t) {
- {
- .type = PM_INDEX_TARGET_NODE,
- .flags = flags | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = target->base.location
- },
- .receiver = target->receiver,
- .opening_loc = target->opening_loc,
- .arguments = target->arguments,
- .closing_loc = target->closing_loc,
- .block = (pm_block_argument_node_t *) target->block,
- };
-
- // Here we're going to free the target, since it is no longer necessary.
- // However, we don't want to call `pm_node_destroy` because we want to keep
- // around all of its children since we just reused them.
- xfree(target);
-
- return node;
-}
-
-/**
- * Allocate and initialize a new CapturePatternNode node.
- */
-static pm_capture_pattern_node_t *
-pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
- pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
-
- *node = (pm_capture_pattern_node_t) {
- {
- .type = PM_CAPTURE_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = value->location.start,
- .end = target->base.location.end
- },
- },
- .value = value,
- .target = target,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new CaseNode node.
- */
-static pm_case_node_t *
-pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
- pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
-
- *node = (pm_case_node_t) {
- {
- .type = PM_CASE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = case_keyword->start,
- .end = end_keyword->end
- },
- },
- .predicate = predicate,
- .else_clause = NULL,
- .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
- .conditions = { 0 }
- };
-
- return node;
-}
-
-/**
- * Append a new condition to a CaseNode node.
- */
-static void
-pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
- assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
-
- pm_node_list_append(&node->conditions, condition);
- node->base.location.end = condition->location.end;
-}
-
-/**
- * Set the else clause of a CaseNode node.
- */
-static void
-pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
- node->else_clause = else_clause;
- node->base.location.end = else_clause->base.location.end;
-}
-
-/**
- * Set the end location for a CaseNode node.
- */
-static void
-pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
- node->base.location.end = end_keyword->end;
- node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
-}
-
-/**
- * Allocate and initialize a new CaseMatchNode node.
- */
-static pm_case_match_node_t *
-pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
- pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
-
- *node = (pm_case_match_node_t) {
- {
- .type = PM_CASE_MATCH_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = case_keyword->start,
- .end = end_keyword->end
- },
- },
- .predicate = predicate,
- .else_clause = NULL,
- .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
- .conditions = { 0 }
- };
-
- return node;
-}
-
-/**
- * Append a new condition to a CaseMatchNode node.
- */
-static void
-pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
- assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
-
- pm_node_list_append(&node->conditions, condition);
- node->base.location.end = condition->location.end;
-}
-
-/**
- * Set the else clause of a CaseMatchNode node.
- */
-static void
-pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
- node->else_clause = else_clause;
- node->base.location.end = else_clause->base.location.end;
-}
-
-/**
- * Set the end location for a CaseMatchNode node.
- */
-static void
-pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
- node->base.location.end = end_keyword->end;
- node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
-}
-
-/**
- * Allocate a new ClassNode node.
- */
-static pm_class_node_t *
-pm_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *class_keyword, pm_node_t *constant_path, const pm_token_t *name, const pm_token_t *inheritance_operator, pm_node_t *superclass, pm_node_t *body, const pm_token_t *end_keyword) {
- pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
-
- *node = (pm_class_node_t) {
- {
- .type = PM_CLASS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = { .start = class_keyword->start, .end = end_keyword->end },
- },
- .locals = *locals,
- .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
- .constant_path = constant_path,
- .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
- .superclass = superclass,
- .body = body,
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ClassVariableAndWriteNode node.
- */
-static pm_class_variable_and_write_node_t *
-pm_class_variable_and_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
-
- *node = (pm_class_variable_and_write_node_t) {
- {
- .type = PM_CLASS_VARIABLE_AND_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ClassVariableOperatorWriteNode node.
- */
-static pm_class_variable_operator_write_node_t *
-pm_class_variable_operator_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
-
- *node = (pm_class_variable_operator_write_node_t) {
- {
- .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ClassVariableOrWriteNode node.
- */
-static pm_class_variable_or_write_node_t *
-pm_class_variable_or_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
-
- *node = (pm_class_variable_or_write_node_t) {
- {
- .type = PM_CLASS_VARIABLE_OR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ClassVariableReadNode node.
- */
-static pm_class_variable_read_node_t *
-pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_CLASS_VARIABLE);
- pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
-
- *node = (pm_class_variable_read_node_t) {
- {
- .type = PM_CLASS_VARIABLE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .name = pm_parser_constant_id_token(parser, token)
- };
-
- return node;
-}
-
-/**
- * True if the given node is an implicit array node on a write, as in:
- *
- * a = *b
- * a = 1, 2, 3
- */
-static inline pm_node_flags_t
-pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
- if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
- return flags;
- }
- return 0;
-}
-
-/**
- * Initialize a new ClassVariableWriteNode node from a ClassVariableRead node.
- */
-static pm_class_variable_write_node_t *
-pm_class_variable_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
- pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
-
- *node = (pm_class_variable_write_node_t) {
- {
- .type = PM_CLASS_VARIABLE_WRITE_NODE,
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = read_node->base.location.start,
- .end = value->location.end
- },
- },
- .name = read_node->name,
- .name_loc = PM_LOCATION_NODE_VALUE((pm_node_t *) read_node),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantPathAndWriteNode node.
- */
-static pm_constant_path_and_write_node_t *
-pm_constant_path_and_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
-
- *node = (pm_constant_path_and_write_node_t) {
- {
- .type = PM_CONSTANT_PATH_AND_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .target = target,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantPathOperatorWriteNode node.
- */
-static pm_constant_path_operator_write_node_t *
-pm_constant_path_operator_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
-
- *node = (pm_constant_path_operator_write_node_t) {
- {
- .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .target = target,
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantPathOrWriteNode node.
- */
-static pm_constant_path_or_write_node_t *
-pm_constant_path_or_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
-
- *node = (pm_constant_path_or_write_node_t) {
- {
- .type = PM_CONSTANT_PATH_OR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .target = target,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantPathNode node.
- */
-static pm_constant_path_node_t *
-pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
- pm_assert_value_expression(parser, parent);
- pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
-
- pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
- if (name_token->type == PM_TOKEN_CONSTANT) {
- name = pm_parser_constant_id_token(parser, name_token);
- }
-
- *node = (pm_constant_path_node_t) {
- {
- .type = PM_CONSTANT_PATH_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = parent == NULL ? delimiter->start : parent->location.start,
- .end = name_token->end
- },
- },
- .parent = parent,
- .name = name,
- .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
- .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
- };
-
- return node;
-}
-
-/**
- * Allocate a new ConstantPathWriteNode node.
- */
-static pm_constant_path_write_node_t *
-pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
-
- *node = (pm_constant_path_write_node_t) {
- {
- .type = PM_CONSTANT_PATH_WRITE_NODE,
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- },
- },
- .target = target,
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantAndWriteNode node.
- */
-static pm_constant_and_write_node_t *
-pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
-
- *node = (pm_constant_and_write_node_t) {
- {
- .type = PM_CONSTANT_AND_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantOperatorWriteNode node.
- */
-static pm_constant_operator_write_node_t *
-pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
-
- *node = (pm_constant_operator_write_node_t) {
- {
- .type = PM_CONSTANT_OPERATOR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantOrWriteNode node.
- */
-static pm_constant_or_write_node_t *
-pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
-
- *node = (pm_constant_or_write_node_t) {
- {
- .type = PM_CONSTANT_OR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ConstantReadNode node.
- */
-static pm_constant_read_node_t *
-pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
- assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
- pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
-
- *node = (pm_constant_read_node_t) {
- {
- .type = PM_CONSTANT_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name)
- },
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
-}
-
-/**
- * Allocate a new ConstantWriteNode node.
- */
-static pm_constant_write_node_t *
-pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
-
- *node = (pm_constant_write_node_t) {
- {
- .type = PM_CONSTANT_WRITE_NODE,
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Check if the receiver of a `def` node is allowed.
- */
-static void
-pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- case PM_BEGIN_NODE: {
- const pm_begin_node_t *cast = (pm_begin_node_t *) node;
- if (cast->statements != NULL) pm_def_node_receiver_check(parser, (pm_node_t *) cast->statements);
- break;
- }
- case PM_PARENTHESES_NODE: {
- const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
- if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
- break;
- }
- case PM_STATEMENTS_NODE: {
- const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
- pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
- break;
- }
- case PM_ARRAY_NODE:
- case PM_FLOAT_NODE:
- case PM_IMAGINARY_NODE:
- case PM_INTEGER_NODE:
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
- case PM_INTERPOLATED_STRING_NODE:
- case PM_INTERPOLATED_SYMBOL_NODE:
- case PM_INTERPOLATED_X_STRING_NODE:
- case PM_RATIONAL_NODE:
- case PM_REGULAR_EXPRESSION_NODE:
- case PM_SOURCE_ENCODING_NODE:
- case PM_SOURCE_FILE_NODE:
- case PM_SOURCE_LINE_NODE:
- case PM_STRING_NODE:
- case PM_SYMBOL_NODE:
- case PM_X_STRING_NODE:
- pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
- break;
- default:
- break;
- }
-}
-
-/**
- * Allocate and initialize a new DefNode node.
- */
-static pm_def_node_t *
-pm_def_node_create(
- pm_parser_t *parser,
- pm_constant_id_t name,
- const pm_token_t *name_loc,
- pm_node_t *receiver,
- pm_parameters_node_t *parameters,
- pm_node_t *body,
- pm_constant_id_list_t *locals,
- const pm_token_t *def_keyword,
- const pm_token_t *operator,
- const pm_token_t *lparen,
- const pm_token_t *rparen,
- const pm_token_t *equal,
- const pm_token_t *end_keyword
-) {
- pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
- const uint8_t *end;
-
- if (end_keyword->type == PM_TOKEN_NOT_PROVIDED) {
- end = body->location.end;
- } else {
- end = end_keyword->end;
- }
-
- if ((receiver != NULL) && PM_NODE_TYPE_P(receiver, PM_PARENTHESES_NODE)) {
- pm_def_node_receiver_check(parser, receiver);
- }
-
- *node = (pm_def_node_t) {
- {
- .type = PM_DEF_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = { .start = def_keyword->start, .end = end },
- },
- .name = name,
- .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
- .receiver = receiver,
- .parameters = parameters,
- .body = body,
- .locals = *locals,
- .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
- .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
- .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
- .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate a new DefinedNode node.
- */
-static pm_defined_node_t *
-pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_location_t *keyword_loc) {
- pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
-
- *node = (pm_defined_node_t) {
- {
- .type = PM_DEFINED_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword_loc->start,
- .end = (rparen->type == PM_TOKEN_NOT_PROVIDED ? value->location.end : rparen->end)
- },
- },
- .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
- .value = value,
- .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
- .keyword_loc = *keyword_loc
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ElseNode node.
- */
-static pm_else_node_t *
-pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
- pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
- const uint8_t *end = NULL;
- if ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL)) {
- end = statements->base.location.end;
- } else {
- end = end_keyword->end;
- }
-
- *node = (pm_else_node_t) {
- {
- .type = PM_ELSE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = else_keyword->start,
- .end = end,
- },
- },
- .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
- .statements = statements,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new EmbeddedStatementsNode node.
- */
-static pm_embedded_statements_node_t *
-pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
- pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
-
- *node = (pm_embedded_statements_node_t) {
- {
- .type = PM_EMBEDDED_STATEMENTS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = opening->start,
- .end = closing->end
- }
- },
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .statements = statements,
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new EmbeddedVariableNode node.
- */
-static pm_embedded_variable_node_t *
-pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
- pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
-
- *node = (pm_embedded_variable_node_t) {
- {
- .type = PM_EMBEDDED_VARIABLE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = variable->location.end
- }
- },
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .variable = variable
- };
-
- return node;
-}
-
-/**
- * Allocate a new EnsureNode node.
- */
-static pm_ensure_node_t *
-pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
- pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
-
- *node = (pm_ensure_node_t) {
- {
- .type = PM_ENSURE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = ensure_keyword->start,
- .end = end_keyword->end
- },
- },
- .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
- .statements = statements,
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new FalseNode node.
- */
-static pm_false_node_t *
-pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_FALSE);
- pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
-
- *node = (pm_false_node_t) {{
- .type = PM_FALSE_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new find pattern node. The node list given in the
- * nodes parameter is guaranteed to have at least two nodes.
- */
-static pm_find_pattern_node_t *
-pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
- pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
-
- pm_node_t *left = nodes->nodes[0];
- assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
- pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
-
- pm_node_t *right;
-
- if (nodes->size == 1) {
- right = (pm_node_t *) pm_missing_node_create(parser, left->location.end, left->location.end);
- } else {
- right = nodes->nodes[nodes->size - 1];
- assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
- }
-
-#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
- // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
- // The resulting AST will anyway be ignored, but this file still needs to compile.
- pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
-#else
- pm_node_t *right_splat_node = right;
-#endif
- *node = (pm_find_pattern_node_t) {
- {
- .type = PM_FIND_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = left->location.start,
- .end = right->location.end,
- },
- },
- .constant = NULL,
- .left = left_splat_node,
- .right = right_splat_node,
- .requireds = { 0 },
- .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- // For now we're going to just copy over each pointer manually. This could be
- // much more efficient, as we could instead resize the node list to only point
- // to 1...-1.
- for (size_t index = 1; index < nodes->size - 1; index++) {
- pm_node_list_append(&node->requireds, nodes->nodes[index]);
- }
-
- return node;
-}
-
-/**
- * Parse the value of a double, add appropriate errors if there is an issue, and
- * return the value that should be saved on the PM_FLOAT_NODE node.
- */
-static double
-pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
- ptrdiff_t diff = token->end - token->start;
- if (diff <= 0) return 0.0;
-
- // First, get a buffer of the content.
- size_t length = (size_t) diff;
- char *buffer = xmalloc(sizeof(char) * (length + 1));
- memcpy((void *) buffer, token->start, length);
-
- // Next, determine if we need to replace the decimal point because of
- // locale-specific options, and then normalize them if we have to.
- char decimal_point = *localeconv()->decimal_point;
- if (decimal_point != '.') {
- for (size_t index = 0; index < length; index++) {
- if (buffer[index] == '.') buffer[index] = decimal_point;
- }
- }
-
- // Next, handle underscores by removing them from the buffer.
- for (size_t index = 0; index < length; index++) {
- if (buffer[index] == '_') {
- memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
- length--;
- }
- }
-
- // Null-terminate the buffer so that strtod cannot read off the end.
- buffer[length] = '\0';
-
- // Now, call strtod to parse the value. Note that CRuby has their own
- // version of strtod which avoids locales. We're okay using the locale-aware
- // version because we've already validated through the parser that the token
- // is in a valid format.
- errno = 0;
- char *eptr;
- double value = strtod(buffer, &eptr);
-
- // This should never happen, because we've already checked that the token
- // is in a valid format. However it's good to be safe.
- if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
- xfree((void *) buffer);
- return 0.0;
- }
-
- // If errno is set, then it should only be ERANGE. At this point we need to
- // check if it's infinity (it should be).
- if (errno == ERANGE && isinf(value)) {
- int warn_width;
- const char *ellipsis;
-
- if (length > 20) {
- warn_width = 20;
- ellipsis = "...";
- } else {
- warn_width = (int) length;
- ellipsis = "";
- }
-
- pm_diagnostic_list_append_format(&parser->warning_list, token->start, token->end, PM_WARN_FLOAT_OUT_OF_RANGE, warn_width, (const char *) token->start, ellipsis);
- value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
- }
-
- // Finally we can free the buffer and return the value.
- xfree((void *) buffer);
- return value;
-}
-
-/**
- * Allocate and initialize a new FloatNode node.
- */
-static pm_float_node_t *
-pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_FLOAT);
- pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
-
- *node = (pm_float_node_t) {
- {
- .type = PM_FLOAT_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .value = pm_double_parse(parser, token)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new FloatNode node from a FLOAT_IMAGINARY token.
- */
-static pm_imaginary_node_t *
-pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
-
- pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
- *node = (pm_imaginary_node_t) {
- {
- .type = PM_IMAGINARY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
- .type = PM_TOKEN_FLOAT,
- .start = token->start,
- .end = token->end - 1
- }))
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new RationalNode node from a FLOAT_RATIONAL token.
- */
-static pm_rational_node_t *
-pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
-
- pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
- *node = (pm_rational_node_t) {
- {
- .type = PM_RATIONAL_NODE,
- .flags = PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numerator = { 0 },
- .denominator = { 0 }
- };
-
- const uint8_t *start = token->start;
- const uint8_t *end = token->end - 1; // r
-
- while (start < end && *start == '0') start++; // 0.1 -> .1
- while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
-
- size_t length = (size_t) (end - start);
- if (length == 1) {
- node->denominator.value = 1;
- return node;
- }
-
- const uint8_t *point = memchr(start, '.', length);
- assert(point && "should have a decimal point");
-
- uint8_t *digits = malloc(length);
- if (digits == NULL) {
- fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
- abort();
- }
-
- memcpy(digits, start, (unsigned long) (point - start));
- memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
- pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
-
- digits[0] = '1';
- if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
- pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
- free(digits);
-
- pm_integers_reduce(&node->numerator, &node->denominator);
- return node;
-}
-
-/**
- * Allocate and initialize a new FloatNode node from a FLOAT_RATIONAL_IMAGINARY
- * token.
- */
-static pm_imaginary_node_t *
-pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
-
- pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
- *node = (pm_imaginary_node_t) {
- {
- .type = PM_IMAGINARY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
- .type = PM_TOKEN_FLOAT_RATIONAL,
- .start = token->start,
- .end = token->end - 1
- }))
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ForNode node.
- */
-static pm_for_node_t *
-pm_for_node_create(
- pm_parser_t *parser,
- pm_node_t *index,
- pm_node_t *collection,
- pm_statements_node_t *statements,
- const pm_token_t *for_keyword,
- const pm_token_t *in_keyword,
- const pm_token_t *do_keyword,
- const pm_token_t *end_keyword
-) {
- pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
-
- *node = (pm_for_node_t) {
- {
- .type = PM_FOR_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = for_keyword->start,
- .end = end_keyword->end
- },
- },
- .index = index,
- .collection = collection,
- .statements = statements,
- .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
- .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
- .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ForwardingArgumentsNode node.
- */
-static pm_forwarding_arguments_node_t *
-pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
- pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
-
- *node = (pm_forwarding_arguments_node_t) {{
- .type = PM_FORWARDING_ARGUMENTS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ForwardingParameterNode node.
- */
-static pm_forwarding_parameter_node_t *
-pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
- pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
-
- *node = (pm_forwarding_parameter_node_t) {{
- .type = PM_FORWARDING_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ForwardingSuper node.
- */
-static pm_forwarding_super_node_t *
-pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
- assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
- assert(token->type == PM_TOKEN_KEYWORD_SUPER);
- pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
-
- pm_block_node_t *block = NULL;
- if (arguments->block != NULL) {
- block = (pm_block_node_t *) arguments->block;
- }
-
- *node = (pm_forwarding_super_node_t) {
- {
- .type = PM_FORWARDING_SUPER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = token->start,
- .end = block != NULL ? block->base.location.end : token->end
- },
- },
- .block = block
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new hash pattern node from an opening and closing
- * token.
- */
-static pm_hash_pattern_node_t *
-pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
- pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
-
- *node = (pm_hash_pattern_node_t) {
- {
- .type = PM_HASH_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = opening->start,
- .end = closing->end
- },
- },
- .constant = NULL,
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
- .elements = { 0 },
- .rest = NULL
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new hash pattern node.
- */
-static pm_hash_pattern_node_t *
-pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
- pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
-
- const uint8_t *start;
- const uint8_t *end;
-
- if (elements->size > 0) {
- if (rest) {
- start = elements->nodes[0]->location.start;
- end = rest->location.end;
- } else {
- start = elements->nodes[0]->location.start;
- end = elements->nodes[elements->size - 1]->location.end;
- }
- } else {
- assert(rest != NULL);
- start = rest->location.start;
- end = rest->location.end;
- }
-
- *node = (pm_hash_pattern_node_t) {
- {
- .type = PM_HASH_PATTERN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = start,
- .end = end
- },
- },
- .constant = NULL,
- .elements = { 0 },
- .rest = rest,
- .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- pm_node_t *element;
- PM_NODE_LIST_FOREACH(elements, index, element) {
- pm_node_list_append(&node->elements, element);
- }
-
- return node;
-}
-
-/**
- * Retrieve the name from a node that will become a global variable write node.
- */
-static pm_constant_id_t
-pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
- switch (PM_NODE_TYPE(target)) {
- case PM_GLOBAL_VARIABLE_READ_NODE:
- return ((pm_global_variable_read_node_t *) target)->name;
- case PM_BACK_REFERENCE_READ_NODE:
- return ((pm_back_reference_read_node_t *) target)->name;
- case PM_NUMBERED_REFERENCE_READ_NODE:
- // This will only ever happen in the event of a syntax error, but we
- // still need to provide something for the node.
- return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
- default:
- assert(false && "unreachable");
- return (pm_constant_id_t) -1;
- }
-}
-
-/**
- * Allocate and initialize a new GlobalVariableAndWriteNode node.
- */
-static pm_global_variable_and_write_node_t *
-pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
-
- *node = (pm_global_variable_and_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name = pm_global_variable_write_name(parser, target),
- .name_loc = target->location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new GlobalVariableOperatorWriteNode node.
- */
-static pm_global_variable_operator_write_node_t *
-pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
-
- *node = (pm_global_variable_operator_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name = pm_global_variable_write_name(parser, target),
- .name_loc = target->location,
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new GlobalVariableOrWriteNode node.
- */
-static pm_global_variable_or_write_node_t *
-pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
-
- *node = (pm_global_variable_or_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name = pm_global_variable_write_name(parser, target),
- .name_loc = target->location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate a new GlobalVariableReadNode node.
- */
-static pm_global_variable_read_node_t *
-pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
- pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
-
- *node = (pm_global_variable_read_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name),
- },
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new synthesized GlobalVariableReadNode node.
- */
-static pm_global_variable_read_node_t *
-pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
- pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
-
- *node = (pm_global_variable_read_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .name = name
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new GlobalVariableWriteNode node.
- */
-static pm_global_variable_write_node_t *
-pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
-
- *node = (pm_global_variable_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .location = {
- .start = target->location.start,
- .end = value->location.end
- },
- },
- .name = pm_global_variable_write_name(parser, target),
- .name_loc = PM_LOCATION_NODE_VALUE(target),
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new synthesized GlobalVariableWriteNode node.
- */
-static pm_global_variable_write_node_t *
-pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
- pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
-
- *node = (pm_global_variable_write_node_t) {
- {
- .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .name = name,
- .name_loc = PM_LOCATION_NULL_VALUE(parser),
- .operator_loc = PM_LOCATION_NULL_VALUE(parser),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate a new HashNode node.
- */
-static pm_hash_node_t *
-pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
- assert(opening != NULL);
- pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
-
- *node = (pm_hash_node_t) {
- {
- .type = PM_HASH_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(opening)
- },
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_NULL_VALUE(parser),
- .elements = { 0 }
- };
-
- return node;
-}
-
-/**
- * Append a new element to a hash node.
- */
-static inline void
-pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
- pm_node_list_append(&hash->elements, element);
-
- bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
- if (static_literal) {
- pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
- static_literal = !PM_NODE_TYPE_P(assoc->key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_HASH_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_RANGE_NODE);
- static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
- static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
- }
-
- if (!static_literal) {
- pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
- }
-}
-
-static inline void
-pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
- hash->base.location.end = token->end;
- hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
-}
-
-/**
- * Allocate a new IfNode node.
- */
-static pm_if_node_t *
-pm_if_node_create(pm_parser_t *parser,
- const pm_token_t *if_keyword,
- pm_node_t *predicate,
- const pm_token_t *then_keyword,
- pm_statements_node_t *statements,
- pm_node_t *subsequent,
- const pm_token_t *end_keyword
-) {
- pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
-
- const uint8_t *end;
- if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
- end = end_keyword->end;
- } else if (subsequent != NULL) {
- end = subsequent->location.end;
- } else if (pm_statements_node_body_length(statements) != 0) {
- end = statements->base.location.end;
- } else {
- end = predicate->location.end;
- }
-
- *node = (pm_if_node_t) {
- {
- .type = PM_IF_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = if_keyword->start,
- .end = end
- },
- },
- .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
- .predicate = predicate,
- .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
- .statements = statements,
- .subsequent = subsequent,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize new IfNode node in the modifier form.
- */
-static pm_if_node_t *
-pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
- pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
-
- pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(parser, statements, statement, true);
-
- *node = (pm_if_node_t) {
- {
- .type = PM_IF_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = statement->location.start,
- .end = predicate->location.end
- },
- },
- .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
- .predicate = predicate,
- .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .statements = statements,
- .subsequent = NULL,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize an if node from a ternary expression.
- */
-static pm_if_node_t *
-pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, const pm_token_t *qmark, pm_node_t *true_expression, const pm_token_t *colon, pm_node_t *false_expression) {
- pm_assert_value_expression(parser, predicate);
- pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
-
- pm_statements_node_t *if_statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(parser, if_statements, true_expression, true);
-
- pm_statements_node_t *else_statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(parser, else_statements, false_expression, true);
-
- pm_token_t end_keyword = not_provided(parser);
- pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
-
- pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
-
- *node = (pm_if_node_t) {
- {
- .type = PM_IF_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = predicate->location.start,
- .end = false_expression->location.end,
- },
- },
- .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .predicate = predicate,
- .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
- .statements = if_statements,
- .subsequent = (pm_node_t *) else_node,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-
-}
-
-static inline void
-pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
- node->base.location.end = keyword->end;
- node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
-}
-
-static inline void
-pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
- node->base.location.end = keyword->end;
- node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
-}
-
-/**
- * Allocate and initialize a new ImplicitNode node.
- */
-static pm_implicit_node_t *
-pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
- pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
-
- *node = (pm_implicit_node_t) {
- {
- .type = PM_IMPLICIT_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = value->location
- },
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ImplicitRestNode node.
- */
-static pm_implicit_rest_node_t *
-pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_COMMA);
-
- pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
-
- *node = (pm_implicit_rest_node_t) {
- {
- .type = PM_IMPLICIT_REST_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new IntegerNode node.
- */
-static pm_integer_node_t *
-pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_INTEGER);
- pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
-
- *node = (pm_integer_node_t) {
- {
- .type = PM_INTEGER_NODE,
- .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .value = { 0 }
- };
-
- pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
- switch (base) {
- case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
- case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
- case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
- case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
- default: assert(false && "unreachable"); break;
- }
-
- pm_integer_parse(&node->value, integer_base, token->start, token->end);
- return node;
-}
-
-/**
- * Allocate and initialize a new IntegerNode node from an INTEGER_IMAGINARY
- * token.
- */
-static pm_imaginary_node_t *
-pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
-
- pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
- *node = (pm_imaginary_node_t) {
- {
- .type = PM_IMAGINARY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
- .type = PM_TOKEN_INTEGER,
- .start = token->start,
- .end = token->end - 1
- }))
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new RationalNode node from an INTEGER_RATIONAL
- * token.
- */
-static pm_rational_node_t *
-pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
-
- pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
- *node = (pm_rational_node_t) {
- {
- .type = PM_RATIONAL_NODE,
- .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numerator = { 0 },
- .denominator = { .value = 1, 0 }
- };
-
- pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
- switch (base) {
- case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
- case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
- case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
- case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
- default: assert(false && "unreachable"); break;
- }
-
- pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
-
- return node;
-}
-
-/**
- * Allocate and initialize a new IntegerNode node from an
- * INTEGER_RATIONAL_IMAGINARY token.
- */
-static pm_imaginary_node_t *
-pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
-
- pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
- *node = (pm_imaginary_node_t) {
- {
- .type = PM_IMAGINARY_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
- .type = PM_TOKEN_INTEGER_RATIONAL,
- .start = token->start,
- .end = token->end - 1
- }))
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new InNode node.
- */
-static pm_in_node_t *
-pm_in_node_create(pm_parser_t *parser, pm_node_t *pattern, pm_statements_node_t *statements, const pm_token_t *in_keyword, const pm_token_t *then_keyword) {
- pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
-
- const uint8_t *end;
- if (statements != NULL) {
- end = statements->base.location.end;
- } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
- end = then_keyword->end;
- } else {
- end = pattern->location.end;
- }
-
- *node = (pm_in_node_t) {
- {
- .type = PM_IN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = in_keyword->start,
- .end = end
- },
- },
- .pattern = pattern,
- .statements = statements,
- .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
- .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new InstanceVariableAndWriteNode node.
- */
-static pm_instance_variable_and_write_node_t *
-pm_instance_variable_and_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
-
- *node = (pm_instance_variable_and_write_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new InstanceVariableOperatorWriteNode node.
- */
-static pm_instance_variable_operator_write_node_t *
-pm_instance_variable_operator_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
-
- *node = (pm_instance_variable_operator_write_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new InstanceVariableOrWriteNode node.
- */
-static pm_instance_variable_or_write_node_t *
-pm_instance_variable_or_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
-
- *node = (pm_instance_variable_or_write_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .name = target->name,
- .name_loc = target->base.location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new InstanceVariableReadNode node.
- */
-static pm_instance_variable_read_node_t *
-pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
- pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
-
- *node = (pm_instance_variable_read_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .name = pm_parser_constant_id_token(parser, token)
- };
-
- return node;
-}
-
-/**
- * Initialize a new InstanceVariableWriteNode node from an InstanceVariableRead
- * node.
- */
-static pm_instance_variable_write_node_t *
-pm_instance_variable_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
- pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
- *node = (pm_instance_variable_write_node_t) {
- {
- .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = read_node->base.location.start,
- .end = value->location.end
- }
- },
- .name = read_node->name,
- .name_loc = PM_LOCATION_NODE_BASE_VALUE(read_node),
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Append a part into a list of string parts. Importantly this handles nested
- * interpolated strings by not necessarily removing the marker for static
- * literals.
- */
-static void
-pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
- switch (PM_NODE_TYPE(part)) {
- case PM_STRING_NODE:
- pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
- break;
- case PM_EMBEDDED_STATEMENTS_NODE: {
- pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
- pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
-
- if (embedded == NULL) {
- // If there are no statements or more than one statement, then
- // we lose the static literal flag.
- pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
- } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
- // If the embedded statement is a string, then we can keep the
- // static literal flag and mark the string as frozen.
- pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
- } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
- // If the embedded statement is an interpolated string and it's
- // a static literal, then we can keep the static literal flag.
- } else {
- // Otherwise we lose the static literal flag.
- pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
- }
-
- break;
- }
- case PM_EMBEDDED_VARIABLE_NODE:
- pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
- break;
- default:
- assert(false && "unexpected node type");
- break;
- }
-
- pm_node_list_append(parts, part);
-}
-
-/**
- * Allocate a new InterpolatedRegularExpressionNode node.
- */
-static pm_interpolated_regular_expression_node_t *
-pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
- pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
-
- *node = (pm_interpolated_regular_expression_node_t) {
- {
- .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = opening->start,
- .end = NULL,
- },
- },
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .parts = { 0 }
- };
-
- return node;
-}
-
-static inline void
-pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
- if (node->base.location.start > part->location.start) {
- node->base.location.start = part->location.start;
- }
- if (node->base.location.end < part->location.end) {
- node->base.location.end = part->location.end;
- }
-
- pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
-}
-
-static inline void
-pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
- node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
- node->base.location.end = closing->end;
- pm_node_flag_set((pm_node_t *) node, pm_regular_expression_flags_create(parser, closing));
-}
-
-/**
- * Append a part to an InterpolatedStringNode node.
- *
- * This has some somewhat complicated semantics, because we need to update
- * multiple flags that have somewhat confusing interactions.
- *
- * PM_NODE_FLAG_STATIC_LITERAL indicates that the node should be treated as a
- * single static literal string that can be pushed onto the stack on its own.
- * Note that this doesn't necessarily mean that the string will be frozen or
- * not; the instructions in CRuby will be either putobject or putstring,
- * depending on the combination of `--enable-frozen-string-literal`,
- * `# frozen_string_literal: true`, and whether or not there is interpolation.
- *
- * PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN indicates that the string should be
- * explicitly frozen. This will only happen if the string is comprised entirely
- * of string parts that are themselves static literals and frozen.
- *
- * PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE indicates that the string should
- * be explicitly marked as mutable. This will happen from
- * `--disable-frozen-string-literal` or `# frozen_string_literal: false`. This
- * is necessary to indicate that the string should be left up to the runtime,
- * which could potentially use a chilled string otherwise.
- */
-static inline void
-pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
-#define CLEAR_FLAGS(node) \
- node->base.flags = (pm_node_flags_t) (node->base.flags & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE))
-
-#define MUTABLE_FLAGS(node) \
- node->base.flags = (pm_node_flags_t) ((node->base.flags | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
-
- if (node->parts.size == 0 && node->opening_loc.start == NULL) {
- node->base.location.start = part->location.start;
- }
-
- node->base.location.end = MAX(node->base.location.end, part->location.end);
-
- switch (PM_NODE_TYPE(part)) {
- case PM_STRING_NODE:
- part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
- break;
- case PM_INTERPOLATED_STRING_NODE:
- if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
- // If the string that we're concatenating is a static literal,
- // then we can keep the static literal flag for this string.
- } else {
- // Otherwise, we lose the static literal flag here and we should
- // also clear the mutability flags.
- CLEAR_FLAGS(node);
- }
- break;
- case PM_EMBEDDED_STATEMENTS_NODE: {
- pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
- pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
-
- if (embedded == NULL) {
- // If we're embedding multiple statements or no statements, then
- // the string is not longer a static literal.
- CLEAR_FLAGS(node);
- } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
- // If the embedded statement is a string, then we can make that
- // string as frozen and static literal, and not touch the static
- // literal status of this string.
- embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
-
- if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
- MUTABLE_FLAGS(node);
- }
- } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
- // If the embedded statement is an interpolated string, but that
- // string is marked as static literal, then we can keep our
- // static literal status for this string.
- if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
- MUTABLE_FLAGS(node);
- }
- } else {
- // In all other cases, we lose the static literal flag here and
- // become mutable.
- CLEAR_FLAGS(node);
- }
-
- break;
- }
- case PM_EMBEDDED_VARIABLE_NODE:
- // Embedded variables clear static literal, which means we also
- // should clear the mutability flags.
- CLEAR_FLAGS(node);
- break;
- default:
- assert(false && "unexpected node type");
- break;
- }
-
- pm_node_list_append(&node->parts, part);
-
-#undef CLEAR_FLAGS
-#undef MUTABLE_FLAGS
-}
-
-/**
- * Allocate and initialize a new InterpolatedStringNode node.
- */
-static pm_interpolated_string_node_t *
-pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
- pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
- pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
-
- switch (parser->frozen_string_literal) {
- case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
- flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
- break;
- case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
- flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
- break;
- }
-
- *node = (pm_interpolated_string_node_t) {
- {
- .type = PM_INTERPOLATED_STRING_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = opening->start,
- .end = closing->end,
- },
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .parts = { 0 }
- };
-
- if (parts != NULL) {
- pm_node_t *part;
- PM_NODE_LIST_FOREACH(parts, index, part) {
- pm_interpolated_string_node_append(node, part);
- }
- }
-
- return node;
-}
-
-/**
- * Set the closing token of the given InterpolatedStringNode node.
- */
-static void
-pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
- node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
- node->base.location.end = closing->end;
-}
-
-static void
-pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
- if (node->parts.size == 0 && node->opening_loc.start == NULL) {
- node->base.location.start = part->location.start;
- }
-
- pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
- node->base.location.end = MAX(node->base.location.end, part->location.end);
-}
-
-static void
-pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
- node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
- node->base.location.end = closing->end;
-}
-
-/**
- * Allocate and initialize a new InterpolatedSymbolNode node.
- */
-static pm_interpolated_symbol_node_t *
-pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
- pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
-
- *node = (pm_interpolated_symbol_node_t) {
- {
- .type = PM_INTERPOLATED_SYMBOL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = opening->start,
- .end = closing->end,
- },
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .parts = { 0 }
- };
-
- if (parts != NULL) {
- pm_node_t *part;
- PM_NODE_LIST_FOREACH(parts, index, part) {
- pm_interpolated_symbol_node_append(node, part);
- }
- }
-
- return node;
-}
-
-/**
- * Allocate a new InterpolatedXStringNode node.
- */
-static pm_interpolated_x_string_node_t *
-pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
- pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
-
- *node = (pm_interpolated_x_string_node_t) {
- {
- .type = PM_INTERPOLATED_X_STRING_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = opening->start,
- .end = closing->end
- },
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .parts = { 0 }
- };
-
- return node;
-}
-
-static inline void
-pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
- pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
- node->base.location.end = part->location.end;
-}
-
-static inline void
-pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
- node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
- node->base.location.end = closing->end;
-}
-
-/**
- * Create a local variable read that is reading the implicit 'it' variable.
- */
-static pm_it_local_variable_read_node_t *
-pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
- pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
-
- *node = (pm_it_local_variable_read_node_t) {
- {
- .type = PM_IT_LOCAL_VARIABLE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name)
- }
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ItParametersNode node.
- */
-static pm_it_parameters_node_t *
-pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
- pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
-
- *node = (pm_it_parameters_node_t) {
- {
- .type = PM_IT_PARAMETERS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = opening->start,
- .end = closing->end
- }
- }
- };
-
- return node;
-}
-
-/**
- * Allocate a new KeywordHashNode node.
- */
-static pm_keyword_hash_node_t *
-pm_keyword_hash_node_create(pm_parser_t *parser) {
- pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
-
- *node = (pm_keyword_hash_node_t) {
- .base = {
- .type = PM_KEYWORD_HASH_NODE,
- .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- },
- .elements = { 0 }
- };
-
- return node;
-}
-
-/**
- * Append an element to a KeywordHashNode node.
- */
-static void
-pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
- // If the element being added is not an AssocNode or does not have a symbol
- // key, then we want to turn the SYMBOL_KEYS flag off.
- if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
- pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
- }
-
- pm_node_list_append(&hash->elements, element);
- if (hash->base.location.start == NULL) {
- hash->base.location.start = element->location.start;
- }
- hash->base.location.end = element->location.end;
-}
-
-/**
- * Allocate and initialize a new RequiredKeywordParameterNode node.
- */
-static pm_required_keyword_parameter_node_t *
-pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
- pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
-
- *node = (pm_required_keyword_parameter_node_t) {
- {
- .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = name->start,
- .end = name->end
- },
- },
- .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
- .name_loc = PM_LOCATION_TOKEN_VALUE(name),
- };
-
- return node;
-}
-
-/**
- * Allocate a new OptionalKeywordParameterNode node.
- */
-static pm_optional_keyword_parameter_node_t *
-pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
- pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
-
- *node = (pm_optional_keyword_parameter_node_t) {
- {
- .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = name->start,
- .end = value->location.end
- },
- },
- .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
- .name_loc = PM_LOCATION_TOKEN_VALUE(name),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate a new KeywordRestParameterNode node.
- */
-static pm_keyword_rest_parameter_node_t *
-pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
- pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
-
- *node = (pm_keyword_rest_parameter_node_t) {
- {
- .type = PM_KEYWORD_REST_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
- },
- },
- .name = pm_parser_optional_constant_id_token(parser, name),
- .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate a new LambdaNode node.
- */
-static pm_lambda_node_t *
-pm_lambda_node_create(
- pm_parser_t *parser,
- pm_constant_id_list_t *locals,
- const pm_token_t *operator,
- const pm_token_t *opening,
- const pm_token_t *closing,
- pm_node_t *parameters,
- pm_node_t *body
-) {
- pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
-
- *node = (pm_lambda_node_t) {
- {
- .type = PM_LAMBDA_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = closing->end
- },
- },
- .locals = *locals,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
- .parameters = parameters,
- .body = body
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new LocalVariableAndWriteNode node.
- */
-static pm_local_variable_and_write_node_t *
-pm_local_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
- assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
- assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
-
- *node = (pm_local_variable_and_write_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name_loc = target->location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .name = name,
- .depth = depth
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new LocalVariableOperatorWriteNode node.
- */
-static pm_local_variable_operator_write_node_t *
-pm_local_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
- pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
-
- *node = (pm_local_variable_operator_write_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name_loc = target->location,
- .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .name = name,
- .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
- .depth = depth
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new LocalVariableOrWriteNode node.
- */
-static pm_local_variable_or_write_node_t *
-pm_local_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
- assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
- assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
- pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
-
- *node = (pm_local_variable_or_write_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->location.start,
- .end = value->location.end
- }
- },
- .name_loc = target->location,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value,
- .name = name,
- .depth = depth
- };
-
- return node;
-}
-
-/**
- * Allocate a new LocalVariableReadNode node with constant_id.
- */
-static pm_local_variable_read_node_t *
-pm_local_variable_read_node_create_constant_id(pm_parser_t *parser, const pm_token_t *name, pm_constant_id_t name_id, uint32_t depth, bool missing) {
- if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
-
- pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
-
- *node = (pm_local_variable_read_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name)
- },
- .name = name_id,
- .depth = depth
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new LocalVariableReadNode node.
- */
-static pm_local_variable_read_node_t *
-pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
- pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
- return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
-}
-
-/**
- * Allocate and initialize a new LocalVariableReadNode node for a missing local
- * variable. (This will only happen when there is a syntax error.)
- */
-static pm_local_variable_read_node_t *
-pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
- pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
- return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
-}
-
-/**
- * Allocate and initialize a new LocalVariableWriteNode node.
- */
-static pm_local_variable_write_node_t *
-pm_local_variable_write_node_create(pm_parser_t *parser, pm_constant_id_t name, uint32_t depth, pm_node_t *value, const pm_location_t *name_loc, const pm_token_t *operator) {
- pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
-
- *node = (pm_local_variable_write_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_WRITE_NODE,
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = name_loc->start,
- .end = value->location.end
- }
- },
- .name = name,
- .depth = depth,
- .value = value,
- .name_loc = *name_loc,
- .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Returns true if the given bounds comprise `it`.
- */
-static inline bool
-pm_token_is_it(const uint8_t *start, const uint8_t *end) {
- return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
-}
-
-/**
- * Returns true if the given bounds comprise a numbered parameter (i.e., they
- * are of the form /^_\d$/).
- */
-static inline bool
-pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
- return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
-}
-
-/**
- * Ensure the given bounds do not comprise a numbered parameter. If they do, add
- * an appropriate error message to the parser.
- */
-static inline void
-pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- if (pm_token_is_numbered_parameter(start, end)) {
- PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
- }
-}
-
-/**
- * Allocate and initialize a new LocalVariableTargetNode node with the given
- * name and depth.
- */
-static pm_local_variable_target_node_t *
-pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
- pm_refute_numbered_parameter(parser, location->start, location->end);
- pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
-
- *node = (pm_local_variable_target_node_t) {
- {
- .type = PM_LOCAL_VARIABLE_TARGET_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = *location
- },
- .name = name,
- .depth = depth
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new MatchPredicateNode node.
- */
-static pm_match_predicate_node_t *
-pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
- pm_assert_value_expression(parser, value);
-
- pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
-
- *node = (pm_match_predicate_node_t) {
- {
- .type = PM_MATCH_PREDICATE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = value->location.start,
- .end = pattern->location.end
- }
- },
- .value = value,
- .pattern = pattern,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new MatchRequiredNode node.
- */
-static pm_match_required_node_t *
-pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
- pm_assert_value_expression(parser, value);
-
- pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
-
- *node = (pm_match_required_node_t) {
- {
- .type = PM_MATCH_REQUIRED_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = value->location.start,
- .end = pattern->location.end
- }
- },
- .value = value,
- .pattern = pattern,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new MatchWriteNode node.
- */
-static pm_match_write_node_t *
-pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
- pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
-
- *node = (pm_match_write_node_t) {
- {
- .type = PM_MATCH_WRITE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = call->base.location
- },
- .call = call,
- .targets = { 0 }
- };
-
- return node;
-}
-
-/**
- * Allocate a new ModuleNode node.
- */
-static pm_module_node_t *
-pm_module_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *module_keyword, pm_node_t *constant_path, const pm_token_t *name, pm_node_t *body, const pm_token_t *end_keyword) {
- pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
-
- *node = (pm_module_node_t) {
- {
- .type = PM_MODULE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = module_keyword->start,
- .end = end_keyword->end
- }
- },
- .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
- .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
- .constant_path = constant_path,
- .body = body,
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
- .name = pm_parser_constant_id_token(parser, name)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize new MultiTargetNode node.
- */
-static pm_multi_target_node_t *
-pm_multi_target_node_create(pm_parser_t *parser) {
- pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
-
- *node = (pm_multi_target_node_t) {
- {
- .type = PM_MULTI_TARGET_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = { .start = NULL, .end = NULL }
- },
- .lefts = { 0 },
- .rest = NULL,
- .rights = { 0 },
- .lparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .rparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-}
-
-/**
- * Append a target to a MultiTargetNode node.
- */
-static void
-pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
- if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
- if (node->rest == NULL) {
- node->rest = target;
- } else {
- pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
- pm_node_list_append(&node->rights, target);
- }
- } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
- if (node->rest == NULL) {
- node->rest = target;
- } else {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
- pm_node_list_append(&node->rights, target);
- }
- } else if (node->rest == NULL) {
- pm_node_list_append(&node->lefts, target);
- } else {
- pm_node_list_append(&node->rights, target);
- }
-
- if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
- node->base.location.start = target->location.start;
- }
-
- if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
- node->base.location.end = target->location.end;
- }
-}
-
-/**
- * Set the opening of a MultiTargetNode node.
- */
-static void
-pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
- node->base.location.start = lparen->start;
- node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
-}
-
-/**
- * Set the closing of a MultiTargetNode node.
- */
-static void
-pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
- node->base.location.end = rparen->end;
- node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
-}
-
-/**
- * Allocate a new MultiWriteNode node.
- */
-static pm_multi_write_node_t *
-pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
- pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
-
- *node = (pm_multi_write_node_t) {
- {
- .type = PM_MULTI_WRITE_NODE,
- .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = target->base.location.start,
- .end = value->location.end
- }
- },
- .lefts = target->lefts,
- .rest = target->rest,
- .rights = target->rights,
- .lparen_loc = target->lparen_loc,
- .rparen_loc = target->rparen_loc,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- // Explicitly do not call pm_node_destroy here because we want to keep
- // around all of the information within the MultiWriteNode node.
- xfree(target);
-
- return node;
-}
-
-/**
- * Allocate and initialize a new NextNode node.
- */
-static pm_next_node_t *
-pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
- assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
- pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
-
- *node = (pm_next_node_t) {
- {
- .type = PM_NEXT_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
- }
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .arguments = arguments
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new NilNode node.
- */
-static pm_nil_node_t *
-pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_NIL);
- pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
-
- *node = (pm_nil_node_t) {{
- .type = PM_NIL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new NoKeywordsParameterNode node.
- */
-static pm_no_keywords_parameter_node_t *
-pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
- assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
- assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
- pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
-
- *node = (pm_no_keywords_parameter_node_t) {
- {
- .type = PM_NO_KEYWORDS_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = keyword->end
- }
- },
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new NumberedParametersNode node.
- */
-static pm_numbered_parameters_node_t *
-pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
- pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
-
- *node = (pm_numbered_parameters_node_t) {
- {
- .type = PM_NUMBERED_PARAMETERS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = *location
- },
- .maximum = maximum
- };
-
- return node;
-}
-
-/**
- * The maximum numbered reference value is defined as the maximum value that an
- * integer can hold minus 1 bit for CRuby instruction sequence operand tagging.
- */
-#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
-
-/**
- * Parse the decimal number represented by the range of bytes. Returns
- * 0 if the number fails to parse or if the number is greater than the maximum
- * value representable by a numbered reference. This function assumes that the
- * range of bytes has already been validated to contain only decimal digits.
- */
-static uint32_t
-pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
- const uint8_t *start = token->start + 1;
- const uint8_t *end = token->end;
-
- ptrdiff_t diff = end - start;
- assert(diff > 0 && ((unsigned long) diff < SIZE_MAX));
- size_t length = (size_t) diff;
-
- char *digits = xcalloc(length + 1, sizeof(char));
- memcpy(digits, start, length);
- digits[length] = '\0';
-
- char *endptr;
- errno = 0;
- unsigned long value = strtoul(digits, &endptr, 10);
-
- if ((digits == endptr) || (*endptr != '\0')) {
- pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
- value = 0;
- }
-
- xfree(digits);
-
- if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
- PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
- value = 0;
- }
-
- return (uint32_t) value;
-}
-
-#undef NTH_REF_MAX
-
-/**
- * Allocate and initialize a new NthReferenceReadNode node.
- */
-static pm_numbered_reference_read_node_t *
-pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
- assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
- pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
-
- *node = (pm_numbered_reference_read_node_t) {
- {
- .type = PM_NUMBERED_REFERENCE_READ_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(name),
- },
- .number = pm_numbered_reference_read_node_number(parser, name)
- };
-
- return node;
-}
-
-/**
- * Allocate a new OptionalParameterNode node.
- */
-static pm_optional_parameter_node_t *
-pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
- pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
-
- *node = (pm_optional_parameter_node_t) {
- {
- .type = PM_OPTIONAL_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = name->start,
- .end = value->location.end
- }
- },
- .name = pm_parser_constant_id_token(parser, name),
- .name_loc = PM_LOCATION_TOKEN_VALUE(name),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .value = value
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new OrNode node.
- */
-static pm_or_node_t *
-pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
- pm_assert_value_expression(parser, left);
-
- pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
-
- *node = (pm_or_node_t) {
- {
- .type = PM_OR_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = left->location.start,
- .end = right->location.end
- }
- },
- .left = left,
- .right = right,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ParametersNode node.
- */
-static pm_parameters_node_t *
-pm_parameters_node_create(pm_parser_t *parser) {
- pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
-
- *node = (pm_parameters_node_t) {
- {
- .type = PM_PARAMETERS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
- },
- .rest = NULL,
- .keyword_rest = NULL,
- .block = NULL,
- .requireds = { 0 },
- .optionals = { 0 },
- .posts = { 0 },
- .keywords = { 0 }
- };
-
- return node;
-}
-
-/**
- * Set the location properly for the parameters node.
- */
-static void
-pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
- if (params->base.location.start == NULL) {
- params->base.location.start = param->location.start;
- } else {
- params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
- }
-
- if (params->base.location.end == NULL) {
- params->base.location.end = param->location.end;
- } else {
- params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
- }
-}
-
-/**
- * Append a required parameter to a ParametersNode node.
- */
-static void
-pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
- pm_parameters_node_location_set(params, param);
- pm_node_list_append(&params->requireds, param);
-}
-
-/**
- * Append an optional parameter to a ParametersNode node.
- */
-static void
-pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
- pm_parameters_node_location_set(params, (pm_node_t *) param);
- pm_node_list_append(&params->optionals, (pm_node_t *) param);
-}
-
-/**
- * Append a post optional arguments parameter to a ParametersNode node.
- */
-static void
-pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
- pm_parameters_node_location_set(params, param);
- pm_node_list_append(&params->posts, param);
-}
-
-/**
- * Set the rest parameter on a ParametersNode node.
- */
-static void
-pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
- pm_parameters_node_location_set(params, param);
- params->rest = param;
-}
-
-/**
- * Append a keyword parameter to a ParametersNode node.
- */
-static void
-pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
- pm_parameters_node_location_set(params, param);
- pm_node_list_append(&params->keywords, param);
-}
-
-/**
- * Set the keyword rest parameter on a ParametersNode node.
- */
-static void
-pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
- assert(params->keyword_rest == NULL);
- pm_parameters_node_location_set(params, param);
- params->keyword_rest = param;
-}
-
-/**
- * Set the block parameter on a ParametersNode node.
- */
-static void
-pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
- assert(params->block == NULL);
- pm_parameters_node_location_set(params, (pm_node_t *) param);
- params->block = param;
-}
-
-/**
- * Allocate a new ProgramNode node.
- */
-static pm_program_node_t *
-pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
- pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
-
- *node = (pm_program_node_t) {
- {
- .type = PM_PROGRAM_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = statements == NULL ? parser->start : statements->base.location.start,
- .end = statements == NULL ? parser->end : statements->base.location.end
- }
- },
- .locals = *locals,
- .statements = statements
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize new ParenthesesNode node.
- */
-static pm_parentheses_node_t *
-pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing) {
- pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
-
- *node = (pm_parentheses_node_t) {
- {
- .type = PM_PARENTHESES_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = opening->start,
- .end = closing->end
- }
- },
- .body = body,
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new PinnedExpressionNode node.
- */
-static pm_pinned_expression_node_t *
-pm_pinned_expression_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *operator, const pm_token_t *lparen, const pm_token_t *rparen) {
- pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
-
- *node = (pm_pinned_expression_node_t) {
- {
- .type = PM_PINNED_EXPRESSION_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = rparen->end
- }
- },
- .expression = expression,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
- .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new PinnedVariableNode node.
- */
-static pm_pinned_variable_node_t *
-pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
- pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
-
- *node = (pm_pinned_variable_node_t) {
- {
- .type = PM_PINNED_VARIABLE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = variable->location.end
- }
- },
- .variable = variable,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new PostExecutionNode node.
- */
-static pm_post_execution_node_t *
-pm_post_execution_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
- pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
-
- *node = (pm_post_execution_node_t) {
- {
- .type = PM_POST_EXECUTION_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = closing->end
- }
- },
- .statements = statements,
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new PreExecutionNode node.
- */
-static pm_pre_execution_node_t *
-pm_pre_execution_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
- pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
-
- *node = (pm_pre_execution_node_t) {
- {
- .type = PM_PRE_EXECUTION_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = closing->end
- }
- },
- .statements = statements,
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize new RangeNode node.
- */
-static pm_range_node_t *
-pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
- pm_assert_value_expression(parser, left);
- pm_assert_value_expression(parser, right);
-
- pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
- pm_node_flags_t flags = 0;
-
- // Indicate that this node is an exclusive range if the operator is `...`.
- if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
- flags |= PM_RANGE_FLAGS_EXCLUDE_END;
- }
-
- // Indicate that this node is a static literal (i.e., can be compiled with
- // a putobject in CRuby) if the left and right are implicit nil, explicit
- // nil, or integers.
- if (
- (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
- (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
- ) {
- flags |= PM_NODE_FLAG_STATIC_LITERAL;
- }
-
- *node = (pm_range_node_t) {
- {
- .type = PM_RANGE_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = (left == NULL ? operator->start : left->location.start),
- .end = (right == NULL ? operator->end : right->location.end)
- }
- },
- .left = left,
- .right = right,
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new RedoNode node.
- */
-static pm_redo_node_t *
-pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_REDO);
- pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
-
- *node = (pm_redo_node_t) {{
- .type = PM_REDO_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate a new initialize a new RegularExpressionNode node with the given
- * unescaped string.
- */
-static pm_regular_expression_node_t *
-pm_regular_expression_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *unescaped) {
- pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
-
- *node = (pm_regular_expression_node_t) {
- {
- .type = PM_REGULAR_EXPRESSION_NODE,
- .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = MIN(opening->start, closing->start),
- .end = MAX(opening->end, closing->end)
- }
- },
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .content_loc = PM_LOCATION_TOKEN_VALUE(content),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
- .unescaped = *unescaped
- };
-
- return node;
-}
-
-/**
- * Allocate a new initialize a new RegularExpressionNode node.
- */
-static inline pm_regular_expression_node_t *
-pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
- return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
-}
-
-/**
- * Allocate a new RequiredParameterNode node.
- */
-static pm_required_parameter_node_t *
-pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
- pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
-
- *node = (pm_required_parameter_node_t) {
- {
- .type = PM_REQUIRED_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- },
- .name = pm_parser_constant_id_token(parser, token)
- };
-
- return node;
-}
-
-/**
- * Allocate a new RescueModifierNode node.
- */
-static pm_rescue_modifier_node_t *
-pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
- pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
-
- *node = (pm_rescue_modifier_node_t) {
- {
- .type = PM_RESCUE_MODIFIER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = expression->location.start,
- .end = rescue_expression->location.end
- }
- },
- .expression = expression,
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .rescue_expression = rescue_expression
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new RescueNode node.
- */
-static pm_rescue_node_t *
-pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
- pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
-
- *node = (pm_rescue_node_t) {
- {
- .type = PM_RESCUE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(keyword)
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .reference = NULL,
- .statements = NULL,
- .subsequent = NULL,
- .exceptions = { 0 }
- };
-
- return node;
-}
-
-static inline void
-pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
- node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
-}
-
-/**
- * Set the reference of a rescue node, and update the location of the node.
- */
-static void
-pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
- node->reference = reference;
- node->base.location.end = reference->location.end;
-}
-
-/**
- * Set the statements of a rescue node, and update the location of the node.
- */
-static void
-pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
- node->statements = statements;
- if (pm_statements_node_body_length(statements) > 0) {
- node->base.location.end = statements->base.location.end;
- }
-}
-
-/**
- * Set the subsequent of a rescue node, and update the location.
- */
-static void
-pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
- node->subsequent = subsequent;
- node->base.location.end = subsequent->base.location.end;
-}
-
-/**
- * Append an exception node to a rescue node, and update the location.
- */
-static void
-pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
- pm_node_list_append(&node->exceptions, exception);
- node->base.location.end = exception->location.end;
-}
-
-/**
- * Allocate a new RestParameterNode node.
- */
-static pm_rest_parameter_node_t *
-pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
- pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
-
- *node = (pm_rest_parameter_node_t) {
- {
- .type = PM_REST_PARAMETER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
- }
- },
- .name = pm_parser_optional_constant_id_token(parser, name),
- .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new RetryNode node.
- */
-static pm_retry_node_t *
-pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_RETRY);
- pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
-
- *node = (pm_retry_node_t) {{
- .type = PM_RETRY_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate a new ReturnNode node.
- */
-static pm_return_node_t *
-pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
- pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
-
- *node = (pm_return_node_t) {
- {
- .type = PM_RETURN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
- }
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .arguments = arguments
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new SelfNode node.
- */
-static pm_self_node_t *
-pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_SELF);
- pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
-
- *node = (pm_self_node_t) {{
- .type = PM_SELF_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new ShareableConstantNode node.
- */
-static pm_shareable_constant_node_t *
-pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
- pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
-
- *node = (pm_shareable_constant_node_t) {
- {
- .type = PM_SHAREABLE_CONSTANT_NODE,
- .flags = (pm_node_flags_t) value,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NODE_VALUE(write)
- },
- .write = write
- };
-
- return node;
-}
-
-/**
- * Allocate a new SingletonClassNode node.
- */
-static pm_singleton_class_node_t *
-pm_singleton_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *class_keyword, const pm_token_t *operator, pm_node_t *expression, pm_node_t *body, const pm_token_t *end_keyword) {
- pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
-
- *node = (pm_singleton_class_node_t) {
- {
- .type = PM_SINGLETON_CLASS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = class_keyword->start,
- .end = end_keyword->end
- }
- },
- .locals = *locals,
- .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .expression = expression,
- .body = body,
- .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new SourceEncodingNode node.
- */
-static pm_source_encoding_node_t *
-pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
- pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
-
- *node = (pm_source_encoding_node_t) {{
- .type = PM_SOURCE_ENCODING_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new SourceFileNode node.
- */
-static pm_source_file_node_t*
-pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
- pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
- assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
-
- pm_node_flags_t flags = 0;
-
- switch (parser->frozen_string_literal) {
- case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
- flags |= PM_STRING_FLAGS_MUTABLE;
- break;
- case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
- flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
- break;
- }
-
- *node = (pm_source_file_node_t) {
- {
- .type = PM_SOURCE_FILE_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
- },
- .filepath = parser->filepath
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new SourceLineNode node.
- */
-static pm_source_line_node_t *
-pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD___LINE__);
- pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
-
- *node = (pm_source_line_node_t) {{
- .type = PM_SOURCE_LINE_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate a new SplatNode node.
- */
-static pm_splat_node_t *
-pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
- pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
-
- *node = (pm_splat_node_t) {
- {
- .type = PM_SPLAT_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = operator->start,
- .end = (expression == NULL ? operator->end : expression->location.end)
- }
- },
- .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
- .expression = expression
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new StatementsNode node.
- */
-static pm_statements_node_t *
-pm_statements_node_create(pm_parser_t *parser) {
- pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
-
- *node = (pm_statements_node_t) {
- {
- .type = PM_STATEMENTS_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .body = { 0 }
- };
-
- return node;
-}
-
-/**
- * Get the length of the given StatementsNode node's body.
- */
-static size_t
-pm_statements_node_body_length(pm_statements_node_t *node) {
- return node && node->body.size;
-}
-
-/**
- * Set the location of the given StatementsNode.
- */
-static void
-pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
- node->base.location = (pm_location_t) { .start = start, .end = end };
-}
-
-/**
- * Update the location of the statements node based on the statement that is
- * being added to the list.
- */
-static inline void
-pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
- if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
- node->base.location.start = statement->location.start;
- }
-
- if (statement->location.end > node->base.location.end) {
- node->base.location.end = statement->location.end;
- }
-}
-
-/**
- * Append a new node to the given StatementsNode node's body.
- */
-static void
-pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
- pm_statements_node_body_update(node, statement);
-
- if (node->body.size > 0) {
- const pm_node_t *previous = node->body.nodes[node->body.size - 1];
-
- switch (PM_NODE_TYPE(previous)) {
- case PM_BREAK_NODE:
- case PM_NEXT_NODE:
- case PM_REDO_NODE:
- case PM_RETRY_NODE:
- case PM_RETURN_NODE:
- pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
- break;
- default:
- break;
- }
- }
-
- pm_node_list_append(&node->body, statement);
- if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
-}
-
-/**
- * Prepend a new node to the given StatementsNode node's body.
- */
-static void
-pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
- pm_statements_node_body_update(node, statement);
- pm_node_list_prepend(&node->body, statement);
- pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
-}
-
-/**
- * Allocate a new StringNode node with the current string on the parser.
- */
-static inline pm_string_node_t *
-pm_string_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *string) {
- pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
- pm_node_flags_t flags = 0;
-
- switch (parser->frozen_string_literal) {
- case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
- flags = PM_STRING_FLAGS_MUTABLE;
- break;
- case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
- flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
- break;
- }
-
- *node = (pm_string_node_t) {
- {
- .type = PM_STRING_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start),
- .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end)
- }
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .content_loc = PM_LOCATION_TOKEN_VALUE(content),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .unescaped = *string
- };
-
- return node;
-}
-
-/**
- * Allocate a new StringNode node.
- */
-static pm_string_node_t *
-pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
- return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
-}
-
-/**
- * Allocate a new StringNode node and create it using the current string on the
- * parser.
- */
-static pm_string_node_t *
-pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
- pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
- parser->current_string = PM_STRING_EMPTY;
- return node;
-}
-
-/**
- * Allocate and initialize a new SuperNode node.
- */
-static pm_super_node_t *
-pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
- assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
- pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
-
- const uint8_t *end = pm_arguments_end(arguments);
- if (end == NULL) {
- assert(false && "unreachable");
- }
-
- *node = (pm_super_node_t) {
- {
- .type = PM_SUPER_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = end,
- }
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .lparen_loc = arguments->opening_loc,
- .arguments = arguments->arguments,
- .rparen_loc = arguments->closing_loc,
- .block = arguments->block
- };
-
- return node;
-}
-
-/**
- * Read through the contents of a string and check if it consists solely of
- * US-ASCII code points.
- */
-static bool
-pm_ascii_only_p(const pm_string_t *contents) {
- const size_t length = pm_string_length(contents);
- const uint8_t *source = pm_string_source(contents);
-
- for (size_t index = 0; index < length; index++) {
- if (source[index] & 0x80) return false;
- }
-
- return true;
-}
-
-/**
- * Validate that the contents of the given symbol are all valid UTF-8.
- */
-static void
-parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
- for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
- size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
-
- if (width == 0) {
- pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
- break;
- }
-
- cursor += width;
- }
-}
-
-/**
- * Validate that the contents of the given symbol are all valid in the encoding
- * of the parser.
- */
-static void
-parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
- const pm_encoding_t *encoding = parser->encoding;
-
- for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
- size_t width = encoding->char_width(cursor, end - cursor);
-
- if (width == 0) {
- pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
- break;
- }
-
- cursor += width;
- }
-}
-
-/**
- * Ruby "downgrades" the encoding of Symbols to US-ASCII if the associated
- * encoding is ASCII-compatible and the Symbol consists only of US-ASCII code
- * points. Otherwise, the encoding may be explicitly set with an escape
- * sequence.
- *
- * If the validate flag is set, then it will check the contents of the symbol
- * to ensure that all characters are valid in the encoding.
- */
-static inline pm_node_flags_t
-parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
- if (parser->explicit_encoding != NULL) {
- // A Symbol may optionally have its encoding explicitly set. This will
- // happen if an escape sequence results in a non-ASCII code point.
- if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
- if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
- return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
- } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
- return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
- } else if (validate) {
- parse_symbol_encoding_validate_other(parser, location, contents);
- }
- } else if (pm_ascii_only_p(contents)) {
- // Ruby stipulates that all source files must use an ASCII-compatible
- // encoding. Thus, all symbols appearing in source are eligible for
- // "downgrading" to US-ASCII.
- return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
- } else if (validate) {
- parse_symbol_encoding_validate_other(parser, location, contents);
- }
-
- return 0;
-}
-
-static pm_node_flags_t
-parse_and_validate_regular_expression_encoding_modifier(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags, char modifier, const pm_encoding_t *modifier_encoding) {
- assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
- (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
- (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
- (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
-
- // There's special validation logic used if a string does not contain any character escape sequences.
- if (parser->explicit_encoding == NULL) {
- // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
- // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
- // the US-ASCII encoding.
- if (ascii_only) {
- return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
- }
-
- if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
- if (!ascii_only) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
- }
- } else if (parser->encoding != modifier_encoding) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
-
- if (modifier == 'n' && !ascii_only) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_NON_ESCAPED_MBC, (int) pm_string_length(source), (const char *) pm_string_source(source));
- }
- }
-
- return flags;
- }
-
- // TODO (nirvdrum 21-Feb-2024): To validate regexp sources with character escape sequences we need to know whether hex or Unicode escape sequences were used and Prism doesn't currently provide that data. We handle a subset of unambiguous cases in the meanwhile.
- bool mixed_encoding = false;
-
- if (mixed_encoding) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
- } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
- // TODO (nirvdrum 21-Feb-2024): Validate the content is valid in the modifier encoding. Do this on-demand so we don't pay the cost of computation unnecessarily.
- bool valid_string_in_modifier_encoding = true;
-
- if (!valid_string_in_modifier_encoding) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
- }
- } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
- // TODO (nirvdrum 21-Feb-2024): There's currently no way to tell if the source used hex or Unicode character escapes from `explicit_encoding` alone. If the source encoding was already UTF-8, both character escape types would set `explicit_encoding` to UTF-8, but need to be processed differently. Skip for now.
- if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING, (int) pm_string_length(source), (const char *) pm_string_source(source));
- }
- }
-
- // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
- return flags;
-}
-
-/**
- * Ruby "downgrades" the encoding of Regexps to US-ASCII if the associated encoding is ASCII-compatible and
- * the unescaped representation of a Regexp source consists only of US-ASCII code points. This is true even
- * when the Regexp is explicitly given an ASCII-8BIT encoding via the (/n) modifier. Otherwise, the encoding
- * may be explicitly set with an escape sequence.
- */
-static pm_node_flags_t
-parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
- // TODO (nirvdrum 22-Feb-2024): CRuby reports a special Regexp-specific error for invalid Unicode ranges. We either need to scan again or modify the "invalid Unicode escape sequence" message we already report.
- bool valid_unicode_range = true;
- if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_INVALID_UNICODE_RANGE, (int) pm_string_length(source), (const char *) pm_string_source(source));
- return flags;
- }
-
- // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
- // to multi-byte characters are allowed.
- if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
- // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
- // following error message appearing twice. We do the same for compatibility.
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
- }
-
- /**
- * Start checking modifier flags. We need to process these before considering any explicit encodings that may have
- * been set by character literals. The order in which the encoding modifiers is checked does not matter. In the
- * event that both an encoding modifier and an explicit encoding would result in the same encoding we do not set
- * the corresponding "forced_<encoding>" flag. Instead, the caller should check the encoding modifier flag and
- * determine the encoding that way.
- */
-
- if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
- return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
- }
-
- if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
- return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
- }
-
- if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
- return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
- }
-
- if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
- return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
- }
-
- // At this point no encoding modifiers will be present on the regular expression as they would have already
- // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
- // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
- if (ascii_only) {
- return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
- }
-
- // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
- // or by specifying a modifier.
- //
- // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
- if (parser->explicit_encoding != NULL) {
- if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
- return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
- } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
- return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
- }
- }
-
- return 0;
-}
-
-/**
- * Allocate and initialize a new SymbolNode node with the given unescaped
- * string.
- */
-static pm_symbol_node_t *
-pm_symbol_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing, const pm_string_t *unescaped, pm_node_flags_t flags) {
- pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
-
- *node = (pm_symbol_node_t) {
- {
- .type = PM_SYMBOL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL | flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start),
- .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end)
- }
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .value_loc = PM_LOCATION_TOKEN_VALUE(value),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .unescaped = *unescaped
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new SymbolNode node.
- */
-static inline pm_symbol_node_t *
-pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
- return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
-}
-
-/**
- * Allocate and initialize a new SymbolNode node with the current string.
- */
-static pm_symbol_node_t *
-pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
- pm_symbol_node_t *node = pm_symbol_node_create_unescaped(parser, opening, value, closing, &parser->current_string, parse_symbol_encoding(parser, value, &parser->current_string, false));
- parser->current_string = PM_STRING_EMPTY;
- return node;
-}
-
-/**
- * Allocate and initialize a new SymbolNode node from a label.
- */
-static pm_symbol_node_t *
-pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
- pm_symbol_node_t *node;
-
- switch (token->type) {
- case PM_TOKEN_LABEL: {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
-
- pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
- node = pm_symbol_node_create(parser, &opening, &label, &closing);
-
- assert((label.end - label.start) >= 0);
- pm_string_shared_init(&node->unescaped, label.start, label.end);
- pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
-
- break;
- }
- case PM_TOKEN_MISSING: {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
-
- pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
- node = pm_symbol_node_create(parser, &opening, &label, &closing);
- break;
- }
- default:
- assert(false && "unreachable");
- node = NULL;
- break;
- }
-
- return node;
-}
-
-/**
- * Allocate and initialize a new synthesized SymbolNode node.
- */
-static pm_symbol_node_t *
-pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
- pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
-
- *node = (pm_symbol_node_t) {
- {
- .type = PM_SYMBOL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .value_loc = PM_LOCATION_NULL_VALUE(parser),
- .unescaped = { 0 }
- };
-
- pm_string_constant_init(&node->unescaped, content, strlen(content));
- return node;
-}
-
-/**
- * Check if the given node is a label in a hash.
- */
-static bool
-pm_symbol_node_label_p(pm_node_t *node) {
- const uint8_t *end = NULL;
-
- switch (PM_NODE_TYPE(node)) {
- case PM_SYMBOL_NODE:
- end = ((pm_symbol_node_t *) node)->closing_loc.end;
- break;
- case PM_INTERPOLATED_SYMBOL_NODE:
- end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
- break;
- default:
- return false;
- }
-
- return (end != NULL) && (end[-1] == ':');
-}
-
-/**
- * Convert the given StringNode node to a SymbolNode node.
- */
-static pm_symbol_node_t *
-pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
- pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
-
- *new_node = (pm_symbol_node_t) {
- {
- .type = PM_SYMBOL_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = opening->start,
- .end = closing->end
- }
- },
- .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
- .value_loc = node->content_loc,
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .unescaped = node->unescaped
- };
-
- pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
- pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true));
-
- // We are explicitly _not_ using pm_node_destroy here because we don't want
- // to trash the unescaped string. We could instead copy the string if we
- // know that it is owned, but we're taking the fast path for now.
- xfree(node);
-
- return new_node;
-}
-
-/**
- * Convert the given SymbolNode node to a StringNode node.
- */
-static pm_string_node_t *
-pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
- pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
- pm_node_flags_t flags = 0;
-
- switch (parser->frozen_string_literal) {
- case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
- flags = PM_STRING_FLAGS_MUTABLE;
- break;
- case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
- flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
- break;
- }
-
- *new_node = (pm_string_node_t) {
- {
- .type = PM_STRING_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = node->base.location
- },
- .opening_loc = node->opening_loc,
- .content_loc = node->value_loc,
- .closing_loc = node->closing_loc,
- .unescaped = node->unescaped
- };
-
- // We are explicitly _not_ using pm_node_destroy here because we don't want
- // to trash the unescaped string. We could instead copy the string if we
- // know that it is owned, but we're taking the fast path for now.
- xfree(node);
-
- return new_node;
-}
-
-/**
- * Allocate and initialize a new TrueNode node.
- */
-static pm_true_node_t *
-pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_TRUE);
- pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
-
- *node = (pm_true_node_t) {{
- .type = PM_TRUE_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token)
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new synthesized TrueNode node.
- */
-static pm_true_node_t *
-pm_true_node_synthesized_create(pm_parser_t *parser) {
- pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
-
- *node = (pm_true_node_t) {{
- .type = PM_TRUE_NODE,
- .flags = PM_NODE_FLAG_STATIC_LITERAL,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = { .start = parser->start, .end = parser->end }
- }};
-
- return node;
-}
-
-/**
- * Allocate and initialize a new UndefNode node.
- */
-static pm_undef_node_t *
-pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
- assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
- pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
-
- *node = (pm_undef_node_t) {
- {
- .type = PM_UNDEF_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_TOKEN_VALUE(token),
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
- .names = { 0 }
- };
-
- return node;
-}
-
-/**
- * Append a name to an undef node.
- */
-static void
-pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
- node->base.location.end = name->location.end;
- pm_node_list_append(&node->names, name);
-}
-
-/**
- * Allocate a new UnlessNode node.
- */
-static pm_unless_node_t *
-pm_unless_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, const pm_token_t *then_keyword, pm_statements_node_t *statements) {
- pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
-
- const uint8_t *end;
- if (statements != NULL) {
- end = statements->base.location.end;
- } else {
- end = predicate->location.end;
- }
-
- *node = (pm_unless_node_t) {
- {
- .type = PM_UNLESS_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = end
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .predicate = predicate,
- .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
- .statements = statements,
- .else_clause = NULL,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize new UnlessNode node in the modifier form.
- */
-static pm_unless_node_t *
-pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
- pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
-
- pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(parser, statements, statement, true);
-
- *node = (pm_unless_node_t) {
- {
- .type = PM_UNLESS_NODE,
- .flags = PM_NODE_FLAG_NEWLINE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = statement->location.start,
- .end = predicate->location.end
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
- .predicate = predicate,
- .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .statements = statements,
- .else_clause = NULL,
- .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
- };
-
- return node;
-}
-
-static inline void
-pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
- node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
- node->base.location.end = end_keyword->end;
-}
-
-/**
- * Loop modifiers could potentially modify an expression that contains block
- * exits. In this case we need to loop through them and remove them from the
- * list of block exits so that they do not later get marked as invalid.
- */
-static void
-pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
- assert(parser->current_block_exits != NULL);
-
- // All of the block exits that we want to remove should be within the
- // statements, and since we are modifying the statements, we shouldn't have
- // to check the end location.
- const uint8_t *start = statements->base.location.start;
-
- for (size_t index = parser->current_block_exits->size; index > 0; index--) {
- pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
- if (block_exit->location.start < start) break;
-
- // Implicitly remove from the list by lowering the size.
- parser->current_block_exits->size--;
- }
-}
-
-/**
- * Allocate a new UntilNode node.
- */
-static pm_until_node_t *
-pm_until_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *closing, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
- pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
- pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
-
- *node = (pm_until_node_t) {
- {
- .type = PM_UNTIL_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = closing->end,
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
-}
-
-/**
- * Allocate a new UntilNode node.
- */
-static pm_until_node_t *
-pm_until_node_modifier_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
- pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
- pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- pm_loop_modifier_block_exits(parser, statements);
-
- *node = (pm_until_node_t) {
- {
- .type = PM_UNTIL_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = statements->base.location.start,
- .end = predicate->location.end,
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new WhenNode node.
- */
-static pm_when_node_t *
-pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
- pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
-
- *node = (pm_when_node_t) {
- {
- .type = PM_WHEN_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = NULL
- }
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .statements = NULL,
- .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .conditions = { 0 }
- };
-
- return node;
-}
-
-/**
- * Append a new condition to a when node.
- */
-static void
-pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
- node->base.location.end = condition->location.end;
- pm_node_list_append(&node->conditions, condition);
-}
-
-/**
- * Set the location of the then keyword of a when node.
- */
-static inline void
-pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
- node->base.location.end = then_keyword->end;
- node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
-}
-
-/**
- * Set the statements list of a when node.
- */
-static void
-pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
- if (statements->base.location.end > node->base.location.end) {
- node->base.location.end = statements->base.location.end;
- }
-
- node->statements = statements;
-}
-
-/**
- * Allocate a new WhileNode node.
- */
-static pm_while_node_t *
-pm_while_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *closing, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
- pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
- pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
-
- *node = (pm_while_node_t) {
- {
- .type = PM_WHILE_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = closing->end
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
-}
-
-/**
- * Allocate a new WhileNode node.
- */
-static pm_while_node_t *
-pm_while_node_modifier_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
- pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
- pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
- pm_loop_modifier_block_exits(parser, statements);
-
- *node = (pm_while_node_t) {
- {
- .type = PM_WHILE_NODE,
- .flags = flags,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = statements->base.location.start,
- .end = predicate->location.end
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new synthesized while loop.
- */
-static pm_while_node_t *
-pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
- pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
-
- *node = (pm_while_node_t) {
- {
- .type = PM_WHILE_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = PM_LOCATION_NULL_VALUE(parser)
- },
- .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
- .closing_loc = PM_LOCATION_NULL_VALUE(parser),
- .predicate = predicate,
- .statements = statements
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new XStringNode node with the given unescaped
- * string.
- */
-static pm_x_string_node_t *
-pm_xstring_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *unescaped) {
- pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
-
- *node = (pm_x_string_node_t) {
- {
- .type = PM_X_STRING_NODE,
- .flags = PM_STRING_FLAGS_FROZEN,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = opening->start,
- .end = closing->end
- },
- },
- .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
- .content_loc = PM_LOCATION_TOKEN_VALUE(content),
- .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
- .unescaped = *unescaped
- };
-
- return node;
-}
-
-/**
- * Allocate and initialize a new XStringNode node.
- */
-static inline pm_x_string_node_t *
-pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
- return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
-}
-
-/**
- * Allocate a new YieldNode node.
- */
-static pm_yield_node_t *
-pm_yield_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_location_t *lparen_loc, pm_arguments_node_t *arguments, const pm_location_t *rparen_loc) {
- pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
-
- const uint8_t *end;
- if (rparen_loc->start != NULL) {
- end = rparen_loc->end;
- } else if (arguments != NULL) {
- end = arguments->base.location.end;
- } else if (lparen_loc->start != NULL) {
- end = lparen_loc->end;
- } else {
- end = keyword->end;
- }
-
- *node = (pm_yield_node_t) {
- {
- .type = PM_YIELD_NODE,
- .node_id = PM_NODE_IDENTIFY(parser),
- .location = {
- .start = keyword->start,
- .end = end
- },
- },
- .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
- .lparen_loc = *lparen_loc,
- .arguments = arguments,
- .rparen_loc = *rparen_loc
- };
-
- return node;
-}
-
-#undef PM_NODE_ALLOC
-#undef PM_NODE_IDENTIFY
-
-/**
- * Check if any of the currently visible scopes contain a local variable
- * described by the given constant id.
- */
-static int
-pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
- pm_scope_t *scope = parser->current_scope;
- int depth = 0;
-
- while (scope != NULL) {
- if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
- if (scope->closed) break;
-
- scope = scope->previous;
- depth++;
- }
-
- return -1;
-}
-
-/**
- * Check if any of the currently visible scopes contain a local variable
- * described by the given token. This function implicitly inserts a constant
- * into the constant pool.
- */
-static inline int
-pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
- return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
-}
-
-/**
- * Add a constant id to the local table of the current scope.
- */
-static inline void
-pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
- pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
-}
-
-/**
- * Add a local variable from a location to the current scope.
- */
-static pm_constant_id_t
-pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
- pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
- if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
- return constant_id;
-}
-
-/**
- * Add a local variable from a token to the current scope.
- */
-static inline pm_constant_id_t
-pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
- return pm_parser_local_add_location(parser, token->start, token->end, reads);
-}
-
-/**
- * Add a local variable from an owned string to the current scope.
- */
-static pm_constant_id_t
-pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
- pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
- if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
- return constant_id;
-}
-
-/**
- * Add a local variable from a constant string to the current scope.
- */
-static pm_constant_id_t
-pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
- pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
- if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
- return constant_id;
-}
-
-/**
- * Add a parameter name to the current scope and check whether the name of the
- * parameter is unique or not.
- *
- * Returns `true` if this is a duplicate parameter name, otherwise returns
- * false.
- */
-static bool
-pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
- // We want to check whether the parameter name is a numbered parameter or
- // not.
- pm_refute_numbered_parameter(parser, name->start, name->end);
-
- // Otherwise we'll fetch the constant id for the parameter name and check
- // whether it's already in the current scope.
- pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
-
- if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
- // Add an error if the parameter doesn't start with _ and has been seen before
- if ((name->start < name->end) && (*name->start != '_')) {
- pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
- }
- return true;
- }
- return false;
-}
-
-/**
- * Pop the current scope off the scope stack.
- */
-static void
-pm_parser_scope_pop(pm_parser_t *parser) {
- pm_scope_t *scope = parser->current_scope;
- parser->current_scope = scope->previous;
- pm_locals_free(&scope->locals);
- pm_node_list_free(&scope->implicit_parameters);
- xfree(scope);
-}
-
-/******************************************************************************/
-/* Stack helpers */
-/******************************************************************************/
-
-/**
- * Pushes a value onto the stack.
- */
-static inline void
-pm_state_stack_push(pm_state_stack_t *stack, bool value) {
- *stack = (*stack << 1) | (value & 1);
-}
-
-/**
- * Pops a value off the stack.
- */
-static inline void
-pm_state_stack_pop(pm_state_stack_t *stack) {
- *stack >>= 1;
-}
-
-/**
- * Returns the value at the top of the stack.
- */
-static inline bool
-pm_state_stack_p(const pm_state_stack_t *stack) {
- return *stack & 1;
-}
-
-static inline void
-pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
- // Use the negation of the value to prevent stack overflow.
- pm_state_stack_push(&parser->accepts_block_stack, !value);
-}
-
-static inline void
-pm_accepts_block_stack_pop(pm_parser_t *parser) {
- pm_state_stack_pop(&parser->accepts_block_stack);
-}
-
-static inline bool
-pm_accepts_block_stack_p(pm_parser_t *parser) {
- return !pm_state_stack_p(&parser->accepts_block_stack);
-}
-
-static inline void
-pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
- pm_state_stack_push(&parser->do_loop_stack, value);
-}
-
-static inline void
-pm_do_loop_stack_pop(pm_parser_t *parser) {
- pm_state_stack_pop(&parser->do_loop_stack);
-}
-
-static inline bool
-pm_do_loop_stack_p(pm_parser_t *parser) {
- return pm_state_stack_p(&parser->do_loop_stack);
-}
-
-/******************************************************************************/
-/* Lexer check helpers */
-/******************************************************************************/
-
-/**
- * Get the next character in the source starting from +cursor+. If that position
- * is beyond the end of the source then return '\0'.
- */
-static inline uint8_t
-peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
- if (cursor < parser->end) {
- return *cursor;
- } else {
- return '\0';
- }
-}
-
-/**
- * Get the next character in the source starting from parser->current.end and
- * adding the given offset. If that position is beyond the end of the source
- * then return '\0'.
- */
-static inline uint8_t
-peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
- return peek_at(parser, parser->current.end + offset);
-}
-
-/**
- * Get the next character in the source starting from parser->current.end. If
- * that position is beyond the end of the source then return '\0'.
- */
-static inline uint8_t
-peek(const pm_parser_t *parser) {
- return peek_at(parser, parser->current.end);
-}
-
-/**
- * If the character to be read matches the given value, then returns true and
- * advances the current pointer.
- */
-static inline bool
-match(pm_parser_t *parser, uint8_t value) {
- if (peek(parser) == value) {
- parser->current.end++;
- return true;
- }
- return false;
-}
-
-/**
- * Return the length of the line ending string starting at +cursor+, or 0 if it
- * is not a line ending. This function is intended to be CRLF/LF agnostic.
- */
-static inline size_t
-match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
- if (peek_at(parser, cursor) == '\n') {
- return 1;
- }
- if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
- return 2;
- }
- return 0;
-}
-
-/**
- * Return the length of the line ending string starting at
- * `parser->current.end + offset`, or 0 if it is not a line ending. This
- * function is intended to be CRLF/LF agnostic.
- */
-static inline size_t
-match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
- return match_eol_at(parser, parser->current.end + offset);
-}
-
-/**
- * Return the length of the line ending string starting at parser->current.end,
- * or 0 if it is not a line ending. This function is intended to be CRLF/LF
- * agnostic.
- */
-static inline size_t
-match_eol(pm_parser_t *parser) {
- return match_eol_at(parser, parser->current.end);
-}
-
-/**
- * Skip to the next newline character or NUL byte.
- */
-static inline const uint8_t *
-next_newline(const uint8_t *cursor, ptrdiff_t length) {
- assert(length >= 0);
-
- // Note that it's okay for us to use memchr here to look for \n because none
- // of the encodings that we support have \n as a component of a multi-byte
- // character.
- return memchr(cursor, '\n', (size_t) length);
-}
-
-/**
- * This is equivalent to the predicate of warn_balanced in CRuby.
- */
-static inline bool
-ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
- return !lex_state_p(parser, PM_LEX_STATE_CLASS | PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME | PM_LEX_STATE_ENDFN) && space_seen && !pm_char_is_whitespace(peek(parser));
-}
-
-/**
- * Here we're going to check if this is a "magic" comment, and perform whatever
- * actions are necessary for it here.
- */
-static bool
-parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- const pm_encoding_t *encoding = pm_encoding_find(start, end);
-
- if (encoding != NULL) {
- if (parser->encoding != encoding) {
- parser->encoding = encoding;
- if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
- }
-
- parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
- return true;
- }
-
- return false;
-}
-
-/**
- * Look for a specific pattern of "coding" and potentially set the encoding on
- * the parser.
- */
-static void
-parser_lex_magic_comment_encoding(pm_parser_t *parser) {
- const uint8_t *cursor = parser->current.start + 1;
- const uint8_t *end = parser->current.end;
-
- bool separator = false;
- while (true) {
- if (end - cursor <= 6) return;
- switch (cursor[6]) {
- case 'C': case 'c': cursor += 6; continue;
- case 'O': case 'o': cursor += 5; continue;
- case 'D': case 'd': cursor += 4; continue;
- case 'I': case 'i': cursor += 3; continue;
- case 'N': case 'n': cursor += 2; continue;
- case 'G': case 'g': cursor += 1; continue;
- case '=': case ':':
- separator = true;
- cursor += 6;
- break;
- default:
- cursor += 6;
- if (pm_char_is_whitespace(*cursor)) break;
- continue;
- }
- if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
- separator = false;
- }
-
- while (true) {
- do {
- if (++cursor >= end) return;
- } while (pm_char_is_whitespace(*cursor));
-
- if (separator) break;
- if (*cursor != '=' && *cursor != ':') return;
-
- separator = true;
- cursor++;
- }
-
- const uint8_t *value_start = cursor;
- while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
-
- if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
- // If we were unable to parse the encoding value, then we've got an
- // issue because we didn't understand the encoding that the user was
- // trying to use. In this case we'll keep using the default encoding but
- // add an error to the parser to indicate an unsuccessful parse.
- pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
- }
-}
-
-typedef enum {
- PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
- PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
- PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
-} pm_magic_comment_boolean_value_t;
-
-/**
- * Check if this is a magic comment that includes the frozen_string_literal
- * pragma. If it does, set that field on the parser.
- */
-static pm_magic_comment_boolean_value_t
-parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
- if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
- return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
- } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
- return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
- } else {
- return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
- }
-}
-
-static inline bool
-pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
- return b == '\'' || b == '"' || b == ':' || b == ';';
-}
-
-/**
- * Find an emacs magic comment marker (-*-) within the given bounds. If one is
- * found, it returns a pointer to the start of the marker. Otherwise it returns
- * NULL.
- */
-static inline const uint8_t *
-parser_lex_magic_comment_emacs_marker(pm_parser_t *parser, const uint8_t *cursor, const uint8_t *end) {
- while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor, '-', (size_t) (end - cursor), parser->encoding_changed, parser->encoding)) != NULL) {
- if (cursor + 3 <= end && cursor[1] == '*' && cursor[2] == '-') {
- return cursor;
- }
- cursor++;
- }
- return NULL;
-}
-
-/**
- * Parse the current token on the parser to see if it's a magic comment and
- * potentially perform some action based on that. A regular expression that this
- * function is effectively matching is:
- *
- * %r"([^\\s\'\":;]+)\\s*:\\s*(\"(?:\\\\.|[^\"])*\"|[^\"\\s;]+)[\\s;]*"
- *
- * It returns true if it consumes the entire comment. Otherwise it returns
- * false.
- */
-static inline bool
-parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
- bool result = true;
-
- const uint8_t *start = parser->current.start + 1;
- const uint8_t *end = parser->current.end;
- if (end - start <= 7) return false;
-
- const uint8_t *cursor;
- bool indicator = false;
-
- if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
- start = cursor + 3;
-
- if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
- end = cursor;
- indicator = true;
- } else {
- // If we have a start marker but not an end marker, then we cannot
- // have a magic comment.
- return false;
- }
- }
-
- cursor = start;
- while (cursor < end) {
- while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
-
- const uint8_t *key_start = cursor;
- while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
-
- const uint8_t *key_end = cursor;
- while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
- if (cursor == end) break;
-
- if (*cursor == ':') {
- cursor++;
- } else {
- if (!indicator) return false;
- continue;
- }
-
- while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
- if (cursor == end) break;
-
- const uint8_t *value_start;
- const uint8_t *value_end;
-
- if (*cursor == '"') {
- value_start = ++cursor;
- for (; cursor < end && *cursor != '"'; cursor++) {
- if (*cursor == '\\' && (cursor + 1 < end)) cursor++;
- }
- value_end = cursor;
- if (*cursor == '"') cursor++;
- } else {
- value_start = cursor;
- while (cursor < end && *cursor != '"' && *cursor != ';' && !pm_char_is_whitespace(*cursor)) cursor++;
- value_end = cursor;
- }
-
- if (indicator) {
- while (cursor < end && (*cursor == ';' || pm_char_is_whitespace(*cursor))) cursor++;
- } else {
- while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
- if (cursor != end) return false;
- }
-
- // Here, we need to do some processing on the key to swap out dashes for
- // underscores. We only need to do this if there _is_ a dash in the key.
- pm_string_t key;
- const size_t key_length = (size_t) (key_end - key_start);
- const uint8_t *dash = pm_memchr(key_start, '-', key_length, parser->encoding_changed, parser->encoding);
-
- if (dash == NULL) {
- pm_string_shared_init(&key, key_start, key_end);
- } else {
- uint8_t *buffer = xmalloc(key_length);
- if (buffer == NULL) break;
-
- memcpy(buffer, key_start, key_length);
- buffer[dash - key_start] = '_';
-
- while ((dash = pm_memchr(dash + 1, '-', (size_t) (key_end - dash - 1), parser->encoding_changed, parser->encoding)) != NULL) {
- buffer[dash - key_start] = '_';
- }
-
- pm_string_owned_init(&key, buffer, key_length);
- }
-
- // Finally, we can start checking the key against the list of known
- // magic comment keys, and potentially change state based on that.
- const uint8_t *key_source = pm_string_source(&key);
- uint32_t value_length = (uint32_t) (value_end - value_start);
-
- // We only want to attempt to compare against encoding comments if it's
- // the first line in the file (or the second in the case of a shebang).
- if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
- if (
- (key_length == 8 && pm_strncasecmp(key_source, (const uint8_t *) "encoding", 8) == 0) ||
- (key_length == 6 && pm_strncasecmp(key_source, (const uint8_t *) "coding", 6) == 0)
- ) {
- result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
- }
- }
-
- if (key_length == 11) {
- if (pm_strncasecmp(key_source, (const uint8_t *) "warn_indent", 11) == 0) {
- switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
- case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
- PM_PARSER_WARN_TOKEN_FORMAT(
- parser,
- parser->current,
- PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
- (int) key_length,
- (const char *) key_source,
- (int) value_length,
- (const char *) value_start
- );
- break;
- case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
- parser->warn_mismatched_indentation = false;
- break;
- case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
- parser->warn_mismatched_indentation = true;
- break;
- }
- }
- } else if (key_length == 21) {
- if (pm_strncasecmp(key_source, (const uint8_t *) "frozen_string_literal", 21) == 0) {
- // We only want to handle frozen string literal comments if it's
- // before any semantic tokens have been seen.
- if (semantic_token_seen) {
- pm_parser_warn_token(parser, &parser->current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
- } else {
- switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
- case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
- PM_PARSER_WARN_TOKEN_FORMAT(
- parser,
- parser->current,
- PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
- (int) key_length,
- (const char *) key_source,
- (int) value_length,
- (const char *) value_start
- );
- break;
- case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
- parser->frozen_string_literal = PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED;
- break;
- case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
- parser->frozen_string_literal = PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED;
- break;
- }
- }
- }
- } else if (key_length == 24) {
- if (pm_strncasecmp(key_source, (const uint8_t *) "shareable_constant_value", 24) == 0) {
- const uint8_t *cursor = parser->current.start;
- while ((cursor > parser->start) && ((cursor[-1] == ' ') || (cursor[-1] == '\t'))) cursor--;
-
- if (!((cursor == parser->start) || (cursor[-1] == '\n'))) {
- pm_parser_warn_token(parser, &parser->current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
- } else if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "none", 4) == 0) {
- pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
- } else if (value_length == 7 && pm_strncasecmp(value_start, (const uint8_t *) "literal", 7) == 0) {
- pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
- } else if (value_length == 23 && pm_strncasecmp(value_start, (const uint8_t *) "experimental_everything", 23) == 0) {
- pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
- } else if (value_length == 17 && pm_strncasecmp(value_start, (const uint8_t *) "experimental_copy", 17) == 0) {
- pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
- } else {
- PM_PARSER_WARN_TOKEN_FORMAT(
- parser,
- parser->current,
- PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
- (int) key_length,
- (const char *) key_source,
- (int) value_length,
- (const char *) value_start
- );
- }
- }
- }
-
- // When we're done, we want to free the string in case we had to
- // allocate memory for it.
- pm_string_free(&key);
-
- // Allocate a new magic comment node to append to the parser's list.
- pm_magic_comment_t *magic_comment;
- if ((magic_comment = (pm_magic_comment_t *) xcalloc(1, sizeof(pm_magic_comment_t))) != NULL) {
- magic_comment->key_start = key_start;
- magic_comment->value_start = value_start;
- magic_comment->key_length = (uint32_t) key_length;
- magic_comment->value_length = value_length;
- pm_list_append(&parser->magic_comment_list, (pm_list_node_t *) magic_comment);
- }
- }
-
- return result;
-}
-
-/******************************************************************************/
-/* Context manipulations */
-/******************************************************************************/
-
-static bool
-context_terminator(pm_context_t context, pm_token_t *token) {
- switch (context) {
- case PM_CONTEXT_MAIN:
- case PM_CONTEXT_DEF_PARAMS:
- case PM_CONTEXT_DEFINED:
- case PM_CONTEXT_MULTI_TARGET:
- case PM_CONTEXT_TERNARY:
- case PM_CONTEXT_RESCUE_MODIFIER:
- return token->type == PM_TOKEN_EOF;
- case PM_CONTEXT_DEFAULT_PARAMS:
- return token->type == PM_TOKEN_COMMA || token->type == PM_TOKEN_PARENTHESIS_RIGHT;
- case PM_CONTEXT_PREEXE:
- case PM_CONTEXT_POSTEXE:
- return token->type == PM_TOKEN_BRACE_RIGHT;
- case PM_CONTEXT_MODULE:
- case PM_CONTEXT_CLASS:
- case PM_CONTEXT_SCLASS:
- case PM_CONTEXT_LAMBDA_DO_END:
- case PM_CONTEXT_DEF:
- case PM_CONTEXT_BLOCK_KEYWORDS:
- return token->type == PM_TOKEN_KEYWORD_END || token->type == PM_TOKEN_KEYWORD_RESCUE || token->type == PM_TOKEN_KEYWORD_ENSURE;
- case PM_CONTEXT_WHILE:
- case PM_CONTEXT_UNTIL:
- case PM_CONTEXT_ELSE:
- case PM_CONTEXT_FOR:
- case PM_CONTEXT_BEGIN_ENSURE:
- case PM_CONTEXT_BLOCK_ENSURE:
- case PM_CONTEXT_CLASS_ENSURE:
- case PM_CONTEXT_DEF_ENSURE:
- case PM_CONTEXT_LAMBDA_ENSURE:
- case PM_CONTEXT_MODULE_ENSURE:
- case PM_CONTEXT_SCLASS_ENSURE:
- return token->type == PM_TOKEN_KEYWORD_END;
- case PM_CONTEXT_LOOP_PREDICATE:
- return token->type == PM_TOKEN_KEYWORD_DO || token->type == PM_TOKEN_KEYWORD_THEN;
- case PM_CONTEXT_FOR_INDEX:
- return token->type == PM_TOKEN_KEYWORD_IN;
- case PM_CONTEXT_CASE_WHEN:
- return token->type == PM_TOKEN_KEYWORD_WHEN || token->type == PM_TOKEN_KEYWORD_END || token->type == PM_TOKEN_KEYWORD_ELSE;
- case PM_CONTEXT_CASE_IN:
- return token->type == PM_TOKEN_KEYWORD_IN || token->type == PM_TOKEN_KEYWORD_END || token->type == PM_TOKEN_KEYWORD_ELSE;
- case PM_CONTEXT_IF:
- case PM_CONTEXT_ELSIF:
- return token->type == PM_TOKEN_KEYWORD_ELSE || token->type == PM_TOKEN_KEYWORD_ELSIF || token->type == PM_TOKEN_KEYWORD_END;
- case PM_CONTEXT_UNLESS:
- return token->type == PM_TOKEN_KEYWORD_ELSE || token->type == PM_TOKEN_KEYWORD_END;
- case PM_CONTEXT_EMBEXPR:
- return token->type == PM_TOKEN_EMBEXPR_END;
- case PM_CONTEXT_BLOCK_BRACES:
- return token->type == PM_TOKEN_BRACE_RIGHT;
- case PM_CONTEXT_PARENS:
- return token->type == PM_TOKEN_PARENTHESIS_RIGHT;
- case PM_CONTEXT_BEGIN:
- case PM_CONTEXT_BEGIN_RESCUE:
- case PM_CONTEXT_BLOCK_RESCUE:
- case PM_CONTEXT_CLASS_RESCUE:
- case PM_CONTEXT_DEF_RESCUE:
- case PM_CONTEXT_LAMBDA_RESCUE:
- case PM_CONTEXT_MODULE_RESCUE:
- case PM_CONTEXT_SCLASS_RESCUE:
- return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_RESCUE || token->type == PM_TOKEN_KEYWORD_ELSE || token->type == PM_TOKEN_KEYWORD_END;
- case PM_CONTEXT_BEGIN_ELSE:
- case PM_CONTEXT_BLOCK_ELSE:
- case PM_CONTEXT_CLASS_ELSE:
- case PM_CONTEXT_DEF_ELSE:
- case PM_CONTEXT_LAMBDA_ELSE:
- case PM_CONTEXT_MODULE_ELSE:
- case PM_CONTEXT_SCLASS_ELSE:
- return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_END;
- case PM_CONTEXT_LAMBDA_BRACES:
- return token->type == PM_TOKEN_BRACE_RIGHT;
- case PM_CONTEXT_PREDICATE:
- return token->type == PM_TOKEN_KEYWORD_THEN || token->type == PM_TOKEN_NEWLINE || token->type == PM_TOKEN_SEMICOLON;
- case PM_CONTEXT_NONE:
- return false;
- }
-
- return false;
-}
-
-/**
- * Returns the context that the given token is found to be terminating, or
- * returns PM_CONTEXT_NONE.
- */
-static pm_context_t
-context_recoverable(const pm_parser_t *parser, pm_token_t *token) {
- pm_context_node_t *context_node = parser->current_context;
-
- while (context_node != NULL) {
- if (context_terminator(context_node->context, token)) return context_node->context;
- context_node = context_node->prev;
- }
-
- return PM_CONTEXT_NONE;
-}
-
-static bool
-context_push(pm_parser_t *parser, pm_context_t context) {
- pm_context_node_t *context_node = (pm_context_node_t *) xmalloc(sizeof(pm_context_node_t));
- if (context_node == NULL) return false;
-
- *context_node = (pm_context_node_t) { .context = context, .prev = NULL };
-
- if (parser->current_context == NULL) {
- parser->current_context = context_node;
- } else {
- context_node->prev = parser->current_context;
- parser->current_context = context_node;
- }
-
- return true;
-}
-
-static void
-context_pop(pm_parser_t *parser) {
- pm_context_node_t *prev = parser->current_context->prev;
- xfree(parser->current_context);
- parser->current_context = prev;
-}
-
-static bool
-context_p(const pm_parser_t *parser, pm_context_t context) {
- pm_context_node_t *context_node = parser->current_context;
-
- while (context_node != NULL) {
- if (context_node->context == context) return true;
- context_node = context_node->prev;
- }
-
- return false;
-}
-
-static bool
-context_def_p(const pm_parser_t *parser) {
- pm_context_node_t *context_node = parser->current_context;
-
- while (context_node != NULL) {
- switch (context_node->context) {
- case PM_CONTEXT_DEF:
- case PM_CONTEXT_DEF_PARAMS:
- case PM_CONTEXT_DEF_ENSURE:
- case PM_CONTEXT_DEF_RESCUE:
- case PM_CONTEXT_DEF_ELSE:
- return true;
- case PM_CONTEXT_CLASS:
- case PM_CONTEXT_CLASS_ENSURE:
- case PM_CONTEXT_CLASS_RESCUE:
- case PM_CONTEXT_CLASS_ELSE:
- case PM_CONTEXT_MODULE:
- case PM_CONTEXT_MODULE_ENSURE:
- case PM_CONTEXT_MODULE_RESCUE:
- case PM_CONTEXT_MODULE_ELSE:
- case PM_CONTEXT_SCLASS:
- case PM_CONTEXT_SCLASS_ENSURE:
- case PM_CONTEXT_SCLASS_RESCUE:
- case PM_CONTEXT_SCLASS_ELSE:
- return false;
- default:
- context_node = context_node->prev;
- }
- }
-
- return false;
-}
-
-/**
- * Returns a human readable string for the given context, used in error
- * messages.
- */
-static const char *
-context_human(pm_context_t context) {
- switch (context) {
- case PM_CONTEXT_NONE:
- assert(false && "unreachable");
- return "";
- case PM_CONTEXT_BEGIN: return "begin statement";
- case PM_CONTEXT_BLOCK_BRACES: return "'{'..'}' block";
- case PM_CONTEXT_BLOCK_KEYWORDS: return "'do'..'end' block";
- case PM_CONTEXT_CASE_WHEN: return "'when' clause";
- case PM_CONTEXT_CASE_IN: return "'in' clause";
- case PM_CONTEXT_CLASS: return "class definition";
- case PM_CONTEXT_DEF: return "method definition";
- case PM_CONTEXT_DEF_PARAMS: return "method parameters";
- case PM_CONTEXT_DEFAULT_PARAMS: return "parameter default value";
- case PM_CONTEXT_DEFINED: return "'defined?' expression";
- case PM_CONTEXT_ELSE:
- case PM_CONTEXT_BEGIN_ELSE:
- case PM_CONTEXT_BLOCK_ELSE:
- case PM_CONTEXT_CLASS_ELSE:
- case PM_CONTEXT_DEF_ELSE:
- case PM_CONTEXT_LAMBDA_ELSE:
- case PM_CONTEXT_MODULE_ELSE:
- case PM_CONTEXT_SCLASS_ELSE: return "'else' clause";
- case PM_CONTEXT_ELSIF: return "'elsif' clause";
- case PM_CONTEXT_EMBEXPR: return "embedded expression";
- case PM_CONTEXT_BEGIN_ENSURE:
- case PM_CONTEXT_BLOCK_ENSURE:
- case PM_CONTEXT_CLASS_ENSURE:
- case PM_CONTEXT_DEF_ENSURE:
- case PM_CONTEXT_LAMBDA_ENSURE:
- case PM_CONTEXT_MODULE_ENSURE:
- case PM_CONTEXT_SCLASS_ENSURE: return "'ensure' clause";
- case PM_CONTEXT_FOR: return "for loop";
- case PM_CONTEXT_FOR_INDEX: return "for loop index";
- case PM_CONTEXT_IF: return "if statement";
- case PM_CONTEXT_LAMBDA_BRACES: return "'{'..'}' lambda block";
- case PM_CONTEXT_LAMBDA_DO_END: return "'do'..'end' lambda block";
- case PM_CONTEXT_LOOP_PREDICATE: return "loop predicate";
- case PM_CONTEXT_MAIN: return "top level context";
- case PM_CONTEXT_MODULE: return "module definition";
- case PM_CONTEXT_MULTI_TARGET: return "multiple targets";
- case PM_CONTEXT_PARENS: return "parentheses";
- case PM_CONTEXT_POSTEXE: return "'END' block";
- case PM_CONTEXT_PREDICATE: return "predicate";
- case PM_CONTEXT_PREEXE: return "'BEGIN' block";
- case PM_CONTEXT_BEGIN_RESCUE:
- case PM_CONTEXT_BLOCK_RESCUE:
- case PM_CONTEXT_CLASS_RESCUE:
- case PM_CONTEXT_DEF_RESCUE:
- case PM_CONTEXT_LAMBDA_RESCUE:
- case PM_CONTEXT_MODULE_RESCUE:
- case PM_CONTEXT_RESCUE_MODIFIER:
- case PM_CONTEXT_SCLASS_RESCUE: return "'rescue' clause";
- case PM_CONTEXT_SCLASS: return "singleton class definition";
- case PM_CONTEXT_TERNARY: return "ternary expression";
- case PM_CONTEXT_UNLESS: return "unless statement";
- case PM_CONTEXT_UNTIL: return "until statement";
- case PM_CONTEXT_WHILE: return "while statement";
- }
-
- assert(false && "unreachable");
- return "";
-}
-
-/******************************************************************************/
-/* Specific token lexers */
-/******************************************************************************/
-
-static inline void
-pm_strspn_number_validate(pm_parser_t *parser, const uint8_t *string, size_t length, const uint8_t *invalid) {
- if (invalid != NULL) {
- pm_diagnostic_id_t diag_id = (invalid == (string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
- pm_parser_err(parser, invalid, invalid + 1, diag_id);
- }
-}
-
-static size_t
-pm_strspn_binary_number_validate(pm_parser_t *parser, const uint8_t *string) {
- const uint8_t *invalid = NULL;
- size_t length = pm_strspn_binary_number(string, parser->end - string, &invalid);
- pm_strspn_number_validate(parser, string, length, invalid);
- return length;
-}
-
-static size_t
-pm_strspn_octal_number_validate(pm_parser_t *parser, const uint8_t *string) {
- const uint8_t *invalid = NULL;
- size_t length = pm_strspn_octal_number(string, parser->end - string, &invalid);
- pm_strspn_number_validate(parser, string, length, invalid);
- return length;
-}
-
-static size_t
-pm_strspn_decimal_number_validate(pm_parser_t *parser, const uint8_t *string) {
- const uint8_t *invalid = NULL;
- size_t length = pm_strspn_decimal_number(string, parser->end - string, &invalid);
- pm_strspn_number_validate(parser, string, length, invalid);
- return length;
-}
-
-static size_t
-pm_strspn_hexadecimal_number_validate(pm_parser_t *parser, const uint8_t *string) {
- const uint8_t *invalid = NULL;
- size_t length = pm_strspn_hexadecimal_number(string, parser->end - string, &invalid);
- pm_strspn_number_validate(parser, string, length, invalid);
- return length;
-}
-
-static pm_token_type_t
-lex_optional_float_suffix(pm_parser_t *parser, bool* seen_e) {
- pm_token_type_t type = PM_TOKEN_INTEGER;
-
- // Here we're going to attempt to parse the optional decimal portion of a
- // float. If it's not there, then it's okay and we'll just continue on.
- if (peek(parser) == '.') {
- if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
- parser->current.end += 2;
- parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
- type = PM_TOKEN_FLOAT;
- } else {
- // If we had a . and then something else, then it's not a float
- // suffix on a number it's a method call or something else.
- return type;
- }
- }
-
- // Here we're going to attempt to parse the optional exponent portion of a
- // float. If it's not there, it's okay and we'll just continue on.
- if ((peek(parser) == 'e') || (peek(parser) == 'E')) {
- if ((peek_offset(parser, 1) == '+') || (peek_offset(parser, 1) == '-')) {
- parser->current.end += 2;
-
- if (pm_char_is_decimal_digit(peek(parser))) {
- parser->current.end++;
- parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
- } else {
- pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
- }
- } else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
- parser->current.end++;
- parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
- } else {
- return type;
- }
-
- *seen_e = true;
- type = PM_TOKEN_FLOAT;
- }
-
- return type;
-}
-
-static pm_token_type_t
-lex_numeric_prefix(pm_parser_t *parser, bool* seen_e) {
- pm_token_type_t type = PM_TOKEN_INTEGER;
- *seen_e = false;
-
- if (peek_offset(parser, -1) == '0') {
- switch (*parser->current.end) {
- // 0d1111 is a decimal number
- case 'd':
- case 'D':
- parser->current.end++;
- if (pm_char_is_decimal_digit(peek(parser))) {
- parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
- } else {
- match(parser, '_');
- pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
- }
-
- break;
-
- // 0b1111 is a binary number
- case 'b':
- case 'B':
- parser->current.end++;
- if (pm_char_is_binary_digit(peek(parser))) {
- parser->current.end += pm_strspn_binary_number_validate(parser, parser->current.end);
- } else {
- match(parser, '_');
- pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
- }
-
- parser->integer_base = PM_INTEGER_BASE_FLAGS_BINARY;
- break;
-
- // 0o1111 is an octal number
- case 'o':
- case 'O':
- parser->current.end++;
- if (pm_char_is_octal_digit(peek(parser))) {
- parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
- } else {
- match(parser, '_');
- pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
- }
-
- parser->integer_base = PM_INTEGER_BASE_FLAGS_OCTAL;
- break;
-
- // 01111 is an octal number
- case '_':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
- parser->integer_base = PM_INTEGER_BASE_FLAGS_OCTAL;
- break;
-
- // 0x1111 is a hexadecimal number
- case 'x':
- case 'X':
- parser->current.end++;
- if (pm_char_is_hexadecimal_digit(peek(parser))) {
- parser->current.end += pm_strspn_hexadecimal_number_validate(parser, parser->current.end);
- } else {
- match(parser, '_');
- pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
- }
-
- parser->integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
- break;
-
- // 0.xxx is a float
- case '.': {
- type = lex_optional_float_suffix(parser, seen_e);
- break;
- }
-
- // 0exxx is a float
- case 'e':
- case 'E': {
- type = lex_optional_float_suffix(parser, seen_e);
- break;
- }
- }
- } else {
- // If it didn't start with a 0, then we'll lex as far as we can into a
- // decimal number.
- parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
-
- // Afterward, we'll lex as far as we can into an optional float suffix.
- type = lex_optional_float_suffix(parser, seen_e);
- }
-
- // At this point we have a completed number, but we want to provide the user
- // with a good experience if they put an additional .xxx fractional
- // component on the end, so we'll check for that here.
- if (peek_offset(parser, 0) == '.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
- const uint8_t *fraction_start = parser->current.end;
- const uint8_t *fraction_end = parser->current.end + 2;
- fraction_end += pm_strspn_decimal_digit(fraction_end, parser->end - fraction_end);
- pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
- }
-
- return type;
-}
-
-static pm_token_type_t
-lex_numeric(pm_parser_t *parser) {
- pm_token_type_t type = PM_TOKEN_INTEGER;
- parser->integer_base = PM_INTEGER_BASE_FLAGS_DECIMAL;
-
- if (parser->current.end < parser->end) {
- bool seen_e = false;
- type = lex_numeric_prefix(parser, &seen_e);
-
- const uint8_t *end = parser->current.end;
- pm_token_type_t suffix_type = type;
-
- if (type == PM_TOKEN_INTEGER) {
- if (match(parser, 'r')) {
- suffix_type = PM_TOKEN_INTEGER_RATIONAL;
-
- if (match(parser, 'i')) {
- suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
- }
- } else if (match(parser, 'i')) {
- suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
- }
- } else {
- if (!seen_e && match(parser, 'r')) {
- suffix_type = PM_TOKEN_FLOAT_RATIONAL;
-
- if (match(parser, 'i')) {
- suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
- }
- } else if (match(parser, 'i')) {
- suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
- }
- }
-
- const uint8_t b = peek(parser);
- if (b != '\0' && (b >= 0x80 || ((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z')) || b == '_')) {
- parser->current.end = end;
- } else {
- type = suffix_type;
- }
- }
-
- return type;
-}
-
-static pm_token_type_t
-lex_global_variable(pm_parser_t *parser) {
- if (parser->current.end >= parser->end) {
- pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
- return PM_TOKEN_GLOBAL_VARIABLE;
- }
-
- // True if multiple characters are allowed after the declaration of the
- // global variable. Not true when it starts with "$-".
- bool allow_multiple = true;
-
- switch (*parser->current.end) {
- case '~': // $~: match-data
- case '*': // $*: argv
- case '$': // $$: pid
- case '?': // $?: last status
- case '!': // $!: error string
- case '@': // $@: error position
- case '/': // $/: input record separator
- case '\\': // $\: output record separator
- case ';': // $;: field separator
- case ',': // $,: output field separator
- case '.': // $.: last read line number
- case '=': // $=: ignorecase
- case ':': // $:: load path
- case '<': // $<: reading filename
- case '>': // $>: default output handle
- case '\"': // $": already loaded files
- parser->current.end++;
- return PM_TOKEN_GLOBAL_VARIABLE;
-
- case '&': // $&: last match
- case '`': // $`: string before last match
- case '\'': // $': string after last match
- case '+': // $+: string matches last paren.
- parser->current.end++;
- return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
-
- case '0': {
- parser->current.end++;
- size_t width;
-
- if (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0) {
- do {
- parser->current.end += width;
- } while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0);
-
- // $0 isn't allowed to be followed by anything.
- pm_diagnostic_id_t diag_id = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, diag_id);
- }
-
- return PM_TOKEN_GLOBAL_VARIABLE;
- }
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- parser->current.end += pm_strspn_decimal_digit(parser->current.end, parser->end - parser->current.end);
- return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
-
- case '-':
- parser->current.end++;
- allow_multiple = false;
- /* fallthrough */
- default: {
- size_t width;
-
- if ((width = char_is_identifier(parser, parser->current.end)) > 0) {
- do {
- parser->current.end += width;
- } while (allow_multiple && parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0);
- } else if (pm_char_is_whitespace(peek(parser))) {
- // If we get here, then we have a $ followed by whitespace,
- // which is not allowed.
- pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
- } else {
- // If we get here, then we have a $ followed by something that
- // isn't recognized as a global variable.
- pm_diagnostic_id_t diag_id = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
- const uint8_t *end = parser->current.end + parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- PM_PARSER_ERR_FORMAT(parser, parser->current.start, end, diag_id, (int) (end - parser->current.start), (const char *) parser->current.start);
- }
-
- return PM_TOKEN_GLOBAL_VARIABLE;
- }
- }
-}
-
-/**
- * This function checks if the current token matches a keyword. If it does, it
- * returns the token type. Otherwise, it returns PM_TOKEN_EOF. The arguments are as follows:
- *
- * * `parser` - the parser object
- * * `current_start` - pointer to the start of the current token
- * * `value` - the literal string that we're checking for
- * * `vlen` - the length of the token
- * * `state` - the state that we should transition to if the token matches
- * * `type` - the expected token type
- * * `modifier_type` - the expected modifier token type
- */
-static inline pm_token_type_t
-lex_keyword(pm_parser_t *parser, const uint8_t *current_start, const char *value, size_t vlen, pm_lex_state_t state, pm_token_type_t type, pm_token_type_t modifier_type) {
- if (memcmp(current_start, value, vlen) == 0) {
- pm_lex_state_t last_state = parser->lex_state;
-
- if (parser->lex_state & PM_LEX_STATE_FNAME) {
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- } else {
- lex_state_set(parser, state);
- if (state == PM_LEX_STATE_BEG) {
- parser->command_start = true;
- }
-
- if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- return modifier_type;
- }
- }
-
- return type;
- }
-
- return PM_TOKEN_EOF;
-}
-
-static pm_token_type_t
-lex_identifier(pm_parser_t *parser, bool previous_command_start) {
- // Lex as far as we can into the current identifier.
- size_t width;
- const uint8_t *end = parser->end;
- const uint8_t *current_start = parser->current.start;
- const uint8_t *current_end = parser->current.end;
- bool encoding_changed = parser->encoding_changed;
-
- if (encoding_changed) {
- while (current_end < end && (width = char_is_identifier(parser, current_end)) > 0) {
- current_end += width;
- }
- } else {
- while (current_end < end && (width = char_is_identifier_utf8(current_end, end)) > 0) {
- current_end += width;
- }
- }
- parser->current.end = current_end;
-
- // Now cache the length of the identifier so that we can quickly compare it
- // against known keywords.
- width = (size_t) (current_end - current_start);
-
- if (current_end < end) {
- if (((current_end + 1 >= end) || (current_end[1] != '=')) && (match(parser, '!') || match(parser, '?'))) {
- // First we'll attempt to extend the identifier by a ! or ?. Then we'll
- // check if we're returning the defined? keyword or just an identifier.
- width++;
-
- if (
- ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
- (peek(parser) == ':') && (peek_offset(parser, 1) != ':')
- ) {
- // If we're in a position where we can accept a : at the end of an
- // identifier, then we'll optionally accept it.
- lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
- (void) match(parser, ':');
- return PM_TOKEN_LABEL;
- }
-
- if (parser->lex_state != PM_LEX_STATE_DOT) {
- if (width == 8 && (lex_keyword(parser, current_start, "defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
- return PM_TOKEN_KEYWORD_DEFINED;
- }
- }
-
- return PM_TOKEN_METHOD_NAME;
- }
-
- if (lex_state_p(parser, PM_LEX_STATE_FNAME) && peek_offset(parser, 1) != '~' && peek_offset(parser, 1) != '>' && (peek_offset(parser, 1) != '=' || peek_offset(parser, 2) == '>') && match(parser, '=')) {
- // If we're in a position where we can accept a = at the end of an
- // identifier, then we'll optionally accept it.
- return PM_TOKEN_IDENTIFIER;
- }
-
- if (
- ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
- peek(parser) == ':' && peek_offset(parser, 1) != ':'
- ) {
- // If we're in a position where we can accept a : at the end of an
- // identifier, then we'll optionally accept it.
- lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
- (void) match(parser, ':');
- return PM_TOKEN_LABEL;
- }
- }
-
- if (parser->lex_state != PM_LEX_STATE_DOT) {
- pm_token_type_t type;
- switch (width) {
- case 2:
- if (lex_keyword(parser, current_start, "do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
- if (pm_do_loop_stack_p(parser)) {
- return PM_TOKEN_KEYWORD_DO_LOOP;
- }
- return PM_TOKEN_KEYWORD_DO;
- }
-
- if ((type = lex_keyword(parser, current_start, "if", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IF, PM_TOKEN_KEYWORD_IF_MODIFIER)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "in", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "or", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_OR, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- break;
- case 3:
- if ((type = lex_keyword(parser, current_start, "and", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_AND, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "def", width, PM_LEX_STATE_FNAME, PM_TOKEN_KEYWORD_DEF, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "end", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "END", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "for", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_FOR, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "nil", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_NIL, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "not", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_NOT, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- break;
- case 4:
- if ((type = lex_keyword(parser, current_start, "case", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_CASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "else", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "next", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_NEXT, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "redo", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_REDO, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "self", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_SELF, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "then", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "true", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_TRUE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "when", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- break;
- case 5:
- if ((type = lex_keyword(parser, current_start, "alias", width, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_ALIAS, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "begin", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_BEGIN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "BEGIN", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_BEGIN_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "break", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_BREAK, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "class", width, PM_LEX_STATE_CLASS, PM_TOKEN_KEYWORD_CLASS, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "elsif", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "false", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_FALSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "retry", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_RETRY, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "super", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_SUPER, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "undef", width, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_UNDEF, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "until", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNTIL, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "while", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHILE, PM_TOKEN_KEYWORD_WHILE_MODIFIER)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "yield", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_YIELD, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- break;
- case 6:
- if ((type = lex_keyword(parser, current_start, "ensure", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "module", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_MODULE, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "rescue", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "return", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RETURN, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "unless", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNLESS, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) != PM_TOKEN_EOF) return type;
- break;
- case 8:
- if ((type = lex_keyword(parser, current_start, "__LINE__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___LINE__, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- if ((type = lex_keyword(parser, current_start, "__FILE__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___FILE__, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- break;
- case 12:
- if ((type = lex_keyword(parser, current_start, "__ENCODING__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___ENCODING__, PM_TOKEN_EOF)) != PM_TOKEN_EOF) return type;
- break;
- }
- }
-
- if (encoding_changed) {
- return parser->encoding->isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
- }
- return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
-}
-
-/**
- * Returns true if the current token that the parser is considering is at the
- * beginning of a line or the beginning of the source.
- */
-static bool
-current_token_starts_line(pm_parser_t *parser) {
- return (parser->current.start == parser->start) || (parser->current.start[-1] == '\n');
-}
-
-/**
- * When we hit a # while lexing something like a string, we need to potentially
- * handle interpolation. This function performs that check. It returns a token
- * type representing what it found. Those cases are:
- *
- * * PM_TOKEN_NOT_PROVIDED - No interpolation was found at this point. The
- * caller should keep lexing.
- * * PM_TOKEN_STRING_CONTENT - No interpolation was found at this point. The
- * caller should return this token type.
- * * PM_TOKEN_EMBEXPR_BEGIN - An embedded expression was found. The caller
- * should return this token type.
- * * PM_TOKEN_EMBVAR - An embedded variable was found. The caller should return
- * this token type.
- */
-static pm_token_type_t
-lex_interpolation(pm_parser_t *parser, const uint8_t *pound) {
- // If there is no content following this #, then we're at the end of
- // the string and we can safely return string content.
- if (pound + 1 >= parser->end) {
- parser->current.end = pound + 1;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- // Now we'll check against the character that follows the #. If it constitutes
- // valid interplation, we'll handle that, otherwise we'll return
- // PM_TOKEN_NOT_PROVIDED.
- switch (pound[1]) {
- case '@': {
- // In this case we may have hit an embedded instance or class variable.
- if (pound + 2 >= parser->end) {
- parser->current.end = pound + 1;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- // If we're looking at a @ and there's another @, then we'll skip past the
- // second @.
- const uint8_t *variable = pound + 2;
- if (*variable == '@' && pound + 3 < parser->end) variable++;
-
- if (char_is_identifier_start(parser, variable)) {
- // At this point we're sure that we've either hit an embedded instance
- // or class variable. In this case we'll first need to check if we've
- // already consumed content.
- if (pound > parser->current.start) {
- parser->current.end = pound;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- // Otherwise we need to return the embedded variable token
- // and then switch to the embedded variable lex mode.
- lex_mode_push(parser, (pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
- parser->current.end = pound + 1;
- return PM_TOKEN_EMBVAR;
- }
-
- // If we didn't get a valid interpolation, then this is just regular
- // string content. This is like if we get "#@-". In this case the caller
- // should keep lexing.
- parser->current.end = pound + 1;
- return PM_TOKEN_NOT_PROVIDED;
- }
- case '$':
- // In this case we may have hit an embedded global variable. If there's
- // not enough room, then we'll just return string content.
- if (pound + 2 >= parser->end) {
- parser->current.end = pound + 1;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- // This is the character that we're going to check to see if it is the
- // start of an identifier that would indicate that this is a global
- // variable.
- const uint8_t *check = pound + 2;
-
- if (pound[2] == '-') {
- if (pound + 3 >= parser->end) {
- parser->current.end = pound + 2;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- check++;
- }
-
- // If the character that we're going to check is the start of an
- // identifier, or we don't have a - and the character is a decimal number
- // or a global name punctuation character, then we've hit an embedded
- // global variable.
- if (
- char_is_identifier_start(parser, check) ||
- (pound[2] != '-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
- ) {
- // In this case we've hit an embedded global variable. First check to
- // see if we've already consumed content. If we have, then we need to
- // return that content as string content first.
- if (pound > parser->current.start) {
- parser->current.end = pound;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- // Otherwise, we need to return the embedded variable token and switch
- // to the embedded variable lex mode.
- lex_mode_push(parser, (pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
- parser->current.end = pound + 1;
- return PM_TOKEN_EMBVAR;
- }
-
- // In this case we've hit a #$ that does not indicate a global variable.
- // In this case we'll continue lexing past it.
- parser->current.end = pound + 1;
- return PM_TOKEN_NOT_PROVIDED;
- case '{':
- // In this case it's the start of an embedded expression. If we have
- // already consumed content, then we need to return that content as string
- // content first.
- if (pound > parser->current.start) {
- parser->current.end = pound;
- return PM_TOKEN_STRING_CONTENT;
- }
-
- parser->enclosure_nesting++;
-
- // Otherwise we'll skip past the #{ and begin lexing the embedded
- // expression.
- lex_mode_push(parser, (pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
- parser->current.end = pound + 2;
- parser->command_start = true;
- pm_do_loop_stack_push(parser, false);
- return PM_TOKEN_EMBEXPR_BEGIN;
- default:
- // In this case we've hit a # that doesn't constitute interpolation. We'll
- // mark that by returning the not provided token type. This tells the
- // consumer to keep lexing forward.
- parser->current.end = pound + 1;
- return PM_TOKEN_NOT_PROVIDED;
- }
-}
-
-static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
-static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
-static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
-static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
-static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
-
-/**
- * This is a lookup table for whether or not an ASCII character is printable.
- */
-static const bool ascii_printable_chars[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
-};
-
-static inline bool
-char_is_ascii_printable(const uint8_t b) {
- return (b < 0x80) && ascii_printable_chars[b];
-}
-
-/**
- * Return the value that a hexadecimal digit character represents. For example,
- * transform 'a' into 10, 'b' into 11, etc.
- */
-static inline uint8_t
-escape_hexadecimal_digit(const uint8_t value) {
- return (uint8_t) ((value <= '9') ? (value - '0') : (value & 0x7) + 9);
-}
-
-/**
- * Scan the 4 digits of a Unicode escape into the value. Returns the number of
- * digits scanned. This function assumes that the characters have already been
- * validated.
- */
-static inline uint32_t
-escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length) {
- uint32_t value = 0;
- for (size_t index = 0; index < length; index++) {
- if (index != 0) value <<= 4;
- value |= escape_hexadecimal_digit(string[index]);
- }
-
- // Here we're going to verify that the value is actually a valid Unicode
- // codepoint and not a surrogate pair.
- if (value >= 0xD800 && value <= 0xDFFF) {
- pm_parser_err(parser, string, string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
- return 0xFFFD;
- }
-
- return value;
-}
-
-/**
- * Escape a single character value based on the given flags.
- */
-static inline uint8_t
-escape_byte(uint8_t value, const uint8_t flags) {
- if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
- if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
- return value;
-}
-
-/**
- * Write a unicode codepoint to the given buffer.
- */
-static inline void
-escape_write_unicode(pm_parser_t *parser, pm_buffer_t *buffer, const uint8_t flags, const uint8_t *start, const uint8_t *end, uint32_t value) {
- // \u escape sequences in string-like structures implicitly change the
- // encoding to UTF-8 if they are >= 0x80 or if they are used in a character
- // literal.
- if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
- if (parser->explicit_encoding != NULL && parser->explicit_encoding != PM_ENCODING_UTF_8_ENTRY) {
- PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_MIXED_ENCODING, parser->explicit_encoding->name);
- }
-
- parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
- }
-
- if (value <= 0x7F) { // 0xxxxxxx
- pm_buffer_append_byte(buffer, (uint8_t) value);
- } else if (value <= 0x7FF) { // 110xxxxx 10xxxxxx
- pm_buffer_append_byte(buffer, (uint8_t) (0xC0 | (value >> 6)));
- pm_buffer_append_byte(buffer, (uint8_t) (0x80 | (value & 0x3F)));
- } else if (value <= 0xFFFF) { // 1110xxxx 10xxxxxx 10xxxxxx
- pm_buffer_append_byte(buffer, (uint8_t) (0xE0 | (value >> 12)));
- pm_buffer_append_byte(buffer, (uint8_t) (0x80 | ((value >> 6) & 0x3F)));
- pm_buffer_append_byte(buffer, (uint8_t) (0x80 | (value & 0x3F)));
- } else if (value <= 0x10FFFF) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- pm_buffer_append_byte(buffer, (uint8_t) (0xF0 | (value >> 18)));
- pm_buffer_append_byte(buffer, (uint8_t) (0x80 | ((value >> 12) & 0x3F)));
- pm_buffer_append_byte(buffer, (uint8_t) (0x80 | ((value >> 6) & 0x3F)));
- pm_buffer_append_byte(buffer, (uint8_t) (0x80 | (value & 0x3F)));
- } else {
- pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
- pm_buffer_append_byte(buffer, 0xEF);
- pm_buffer_append_byte(buffer, 0xBF);
- pm_buffer_append_byte(buffer, 0xBD);
- }
-}
-
-/**
- * When you're writing a byte to the unescape buffer, if the byte is non-ASCII
- * (i.e., the top bit is set) then it locks in the encoding.
- */
-static inline void
-escape_write_byte_encoded(pm_parser_t *parser, pm_buffer_t *buffer, uint8_t byte) {
- if (byte >= 0x80) {
- if (parser->explicit_encoding != NULL && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_MIXED_ENCODING, parser->encoding->name);
- }
-
- parser->explicit_encoding = parser->encoding;
- }
-
- pm_buffer_append_byte(buffer, byte);
-}
-
-/**
- * Write each byte of the given escaped character into the buffer.
- */
-static inline void
-escape_write_escape_encoded(pm_parser_t *parser, pm_buffer_t *buffer) {
- size_t width;
- if (parser->encoding_changed) {
- width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- } else {
- width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
- }
-
- // TODO: If the character is invalid in the given encoding, then we'll just
- // push one byte into the buffer. This should actually be an error.
- width = (width == 0) ? 1 : width;
-
- for (size_t index = 0; index < width; index++) {
- escape_write_byte_encoded(parser, buffer, *parser->current.end);
- parser->current.end++;
- }
-}
-
-/**
- * The regular expression engine doesn't support the same escape sequences as
- * Ruby does. So first we have to read the escape sequence, and then we have to
- * format it like the regular expression engine expects it. For example, in Ruby
- * if we have:
- *
- * /\M-\C-?/
- *
- * then the first byte is actually 255, so we have to rewrite this as:
- *
- * /\xFF/
- *
- * Note that in this case there is a literal \ byte in the regular expression
- * source so that the regular expression engine will perform its own unescaping.
- */
-static inline void
-escape_write_byte(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expression_buffer, uint8_t flags, uint8_t byte) {
- if (flags & PM_ESCAPE_FLAG_REGEXP) {
- pm_buffer_append_format(regular_expression_buffer, "\\x%02X", byte);
- }
-
- escape_write_byte_encoded(parser, buffer, byte);
-}
-
-/**
- * Warn about using a space or a tab character in an escape, as opposed to using
- * \\s or \\t. Note that we can quite copy the source because the warning
- * message replaces \\c with \\C.
- */
-static void
-escape_read_warn(pm_parser_t *parser, uint8_t flags, uint8_t flag, const char *type) {
-#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
-
- PM_PARSER_WARN_TOKEN_FORMAT(
- parser,
- parser->current,
- PM_WARN_INVALID_CHARACTER,
- FLAG(flags),
- FLAG(flag),
- type
- );
-
-#undef FLAG
-}
-
-/**
- * Read the value of an escape into the buffer.
- */
-static void
-escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expression_buffer, uint8_t flags) {
- switch (peek(parser)) {
- case '\\': {
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte('\\', flags));
- return;
- }
- case '\'': {
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte('\'', flags));
- return;
- }
- case 'a': {
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte('\a', flags));
- return;
- }
- case 'b': {
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte('\b', flags));
- return;
- }
- case 'e': {
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte('\033', flags));
- return;
- }
- case 'f': {
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte('\f', flags));
- return;
- }
- case 'n': {
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte('\n', flags));
- return;
- }
- case 'r': {
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte('\r', flags));
- return;
- }
- case 's': {
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(' ', flags));
- return;
- }
- case 't': {
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte('\t', flags));
- return;
- }
- case 'v': {
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte('\v', flags));
- return;
- }
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': {
- uint8_t value = (uint8_t) (*parser->current.end - '0');
- parser->current.end++;
-
- if (pm_char_is_octal_digit(peek(parser))) {
- value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end - '0'));
- parser->current.end++;
-
- if (pm_char_is_octal_digit(peek(parser))) {
- value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end - '0'));
- parser->current.end++;
- }
- }
-
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
- return;
- }
- case 'x': {
- const uint8_t *start = parser->current.end - 1;
-
- parser->current.end++;
- uint8_t byte = peek(parser);
-
- if (pm_char_is_hexadecimal_digit(byte)) {
- uint8_t value = escape_hexadecimal_digit(byte);
- parser->current.end++;
-
- byte = peek(parser);
- if (pm_char_is_hexadecimal_digit(byte)) {
- value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(byte));
- parser->current.end++;
- }
-
- value = escape_byte(value, flags);
- if (flags & PM_ESCAPE_FLAG_REGEXP) {
- if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
- pm_buffer_append_format(regular_expression_buffer, "\\x%02X", value);
- } else {
- pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end - start));
- }
- }
-
- escape_write_byte_encoded(parser, buffer, value);
- } else {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
- }
-
- return;
- }
- case 'u': {
- const uint8_t *start = parser->current.end - 1;
- parser->current.end++;
-
- if (parser->current.end == parser->end) {
- const uint8_t *start = parser->current.end - 2;
- PM_PARSER_ERR_FORMAT(parser, start, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
- } else if (peek(parser) == '{') {
- const uint8_t *unicode_codepoints_start = parser->current.end - 2;
- parser->current.end++;
-
- size_t whitespace;
- while (true) {
- if ((whitespace = pm_strspn_whitespace(parser->current.end, parser->end - parser->current.end)) > 0) {
- parser->current.end += whitespace;
- } else if (peek(parser) == '\\' && peek_offset(parser, 1) == 'n') {
- // This is super hacky, but it gets us nicer error
- // messages because we can still pass it off to the
- // regular expression engine even if we hit an
- // unterminated regular expression.
- parser->current.end += 2;
- } else {
- break;
- }
- }
-
- const uint8_t *extra_codepoints_start = NULL;
- int codepoints_count = 0;
-
- while ((parser->current.end < parser->end) && (*parser->current.end != '}')) {
- const uint8_t *unicode_start = parser->current.end;
- size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->current.end, parser->end - parser->current.end);
-
- if (hexadecimal_length > 6) {
- // \u{nnnn} character literal allows only 1-6 hexadecimal digits
- pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
- } else if (hexadecimal_length == 0) {
- // there are not hexadecimal characters
-
- if (flags & PM_ESCAPE_FLAG_REGEXP) {
- // If this is a regular expression, we are going to
- // let the regular expression engine handle this
- // error instead of us.
- pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end - start));
- } else {
- pm_parser_err(parser, parser->current.end, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
- pm_parser_err(parser, parser->current.end, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
- }
-
- return;
- }
-
- parser->current.end += hexadecimal_length;
- codepoints_count++;
- if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
- extra_codepoints_start = unicode_start;
- }
-
- uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
- escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value);
-
- parser->current.end += pm_strspn_whitespace(parser->current.end, parser->end - parser->current.end);
- }
-
- // ?\u{nnnn} character literal should contain only one codepoint
- // and cannot be like ?\u{nnnn mmmm}.
- if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
- pm_parser_err(parser, extra_codepoints_start, parser->current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
- }
-
- if (parser->current.end == parser->end) {
- PM_PARSER_ERR_FORMAT(parser, start, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (int) (parser->current.end - start), start);
- } else if (peek(parser) == '}') {
- parser->current.end++;
- } else {
- if (flags & PM_ESCAPE_FLAG_REGEXP) {
- // If this is a regular expression, we are going to let
- // the regular expression engine handle this error
- // instead of us.
- pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end - start));
- } else {
- pm_parser_err(parser, unicode_codepoints_start, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
- }
- }
-
- if (flags & PM_ESCAPE_FLAG_REGEXP) {
- pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (size_t) (parser->current.end - unicode_codepoints_start));
- }
- } else {
- size_t length = pm_strspn_hexadecimal_digit(parser->current.end, MIN(parser->end - parser->current.end, 4));
-
- if (length == 0) {
- if (flags & PM_ESCAPE_FLAG_REGEXP) {
- pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end - start));
- } else {
- const uint8_t *start = parser->current.end - 2;
- PM_PARSER_ERR_FORMAT(parser, start, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
- }
- } else if (length == 4) {
- uint32_t value = escape_unicode(parser, parser->current.end, 4);
-
- if (flags & PM_ESCAPE_FLAG_REGEXP) {
- pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end + 4 - start));
- }
-
- escape_write_unicode(parser, buffer, flags, start, parser->current.end + 4, value);
- parser->current.end += 4;
- } else {
- parser->current.end += length;
-
- if (flags & PM_ESCAPE_FLAG_REGEXP) {
- // If this is a regular expression, we are going to let
- // the regular expression engine handle this error
- // instead of us.
- pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end - start));
- } else {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
- }
- }
- }
-
- return;
- }
- case 'c': {
- parser->current.end++;
- if (parser->current.end == parser->end) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
- return;
- }
-
- uint8_t peeked = peek(parser);
- switch (peeked) {
- case '?': {
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
- return;
- }
- case '\\':
- if (flags & PM_ESCAPE_FLAG_CONTROL) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
- return;
- }
- parser->current.end++;
-
- if (match(parser, 'u') || match(parser, 'U')) {
- pm_parser_err(parser, parser->current.start, parser->current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
- return;
- }
-
- escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
- return;
- case ' ':
- parser->current.end++;
- escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL, "\\s");
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
- return;
- case '\t':
- parser->current.end++;
- escape_read_warn(parser, flags, 0, "\\t");
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
- return;
- default: {
- if (!char_is_ascii_printable(peeked)) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
- return;
- }
-
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
- return;
- }
- }
- }
- case 'C': {
- parser->current.end++;
- if (peek(parser) != '-') {
- size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- pm_parser_err(parser, parser->current.start, parser->current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
- return;
- }
-
- parser->current.end++;
- if (parser->current.end == parser->end) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
- return;
- }
-
- uint8_t peeked = peek(parser);
- switch (peeked) {
- case '?': {
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
- return;
- }
- case '\\':
- if (flags & PM_ESCAPE_FLAG_CONTROL) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
- return;
- }
- parser->current.end++;
-
- if (match(parser, 'u') || match(parser, 'U')) {
- pm_parser_err(parser, parser->current.start, parser->current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
- return;
- }
-
- escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
- return;
- case ' ':
- parser->current.end++;
- escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL, "\\s");
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
- return;
- case '\t':
- parser->current.end++;
- escape_read_warn(parser, flags, 0, "\\t");
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
- return;
- default: {
- if (!char_is_ascii_printable(peeked)) {
- size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- pm_parser_err(parser, parser->current.start, parser->current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
- return;
- }
-
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
- return;
- }
- }
- }
- case 'M': {
- parser->current.end++;
- if (peek(parser) != '-') {
- size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- pm_parser_err(parser, parser->current.start, parser->current.end + width, PM_ERR_ESCAPE_INVALID_META);
- return;
- }
-
- parser->current.end++;
- if (parser->current.end == parser->end) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
- return;
- }
-
- uint8_t peeked = peek(parser);
- switch (peeked) {
- case '\\':
- if (flags & PM_ESCAPE_FLAG_META) {
- pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
- return;
- }
- parser->current.end++;
-
- if (match(parser, 'u') || match(parser, 'U')) {
- pm_parser_err(parser, parser->current.start, parser->current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
- return;
- }
-
- escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
- return;
- case ' ':
- parser->current.end++;
- escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META, "\\s");
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
- return;
- case '\t':
- parser->current.end++;
- escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META, "\\t");
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
- return;
- default:
- if (!char_is_ascii_printable(peeked)) {
- size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- pm_parser_err(parser, parser->current.start, parser->current.end + width, PM_ERR_ESCAPE_INVALID_META);
- return;
- }
-
- parser->current.end++;
- escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
- return;
- }
- }
- case '\r': {
- if (peek_offset(parser, 1) == '\n') {
- parser->current.end += 2;
- escape_write_byte_encoded(parser, buffer, escape_byte('\n', flags));
- return;
- }
- }
- /* fallthrough */
- default: {
- if (parser->current.end < parser->end) {
- escape_write_escape_encoded(parser, buffer);
- }
- return;
- }
- }
-}
-
-/**
- * This function is responsible for lexing either a character literal or the ?
- * operator. The supported character literals are described below.
- *
- * \\a bell, ASCII 07h (BEL)
- * \\b backspace, ASCII 08h (BS)
- * \t horizontal tab, ASCII 09h (TAB)
- * \\n newline (line feed), ASCII 0Ah (LF)
- * \v vertical tab, ASCII 0Bh (VT)
- * \f form feed, ASCII 0Ch (FF)
- * \r carriage return, ASCII 0Dh (CR)
- * \\e escape, ASCII 1Bh (ESC)
- * \s space, ASCII 20h (SPC)
- * \\ backslash
- * \nnn octal bit pattern, where nnn is 1-3 octal digits ([0-7])
- * \xnn hexadecimal bit pattern, where nn is 1-2 hexadecimal digits ([0-9a-fA-F])
- * \unnnn Unicode character, where nnnn is exactly 4 hexadecimal digits ([0-9a-fA-F])
- * \u{nnnn ...} Unicode character(s), where each nnnn is 1-6 hexadecimal digits ([0-9a-fA-F])
- * \cx or \C-x control character, where x is an ASCII printable character
- * \M-x meta character, where x is an ASCII printable character
- * \M-\C-x meta control character, where x is an ASCII printable character
- * \M-\cx same as above
- * \\c\M-x same as above
- * \\c? or \C-? delete, ASCII 7Fh (DEL)
- */
-static pm_token_type_t
-lex_question_mark(pm_parser_t *parser) {
- if (lex_state_end_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- return PM_TOKEN_QUESTION_MARK;
- }
-
- if (parser->current.end >= parser->end) {
- pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
- pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
- return PM_TOKEN_CHARACTER_LITERAL;
- }
-
- if (pm_char_is_whitespace(*parser->current.end)) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- return PM_TOKEN_QUESTION_MARK;
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
-
- if (match(parser, '\\')) {
- lex_state_set(parser, PM_LEX_STATE_END);
-
- pm_buffer_t buffer;
- pm_buffer_init_capacity(&buffer, 3);
-
- escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
- pm_string_owned_init(&parser->current_string, (uint8_t *) buffer.value, buffer.length);
-
- return PM_TOKEN_CHARACTER_LITERAL;
- } else {
- size_t encoding_width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
-
- // Ternary operators can have a ? immediately followed by an identifier
- // which starts with an underscore. We check for this case here.
- if (
- !(parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end) || peek(parser) == '_') ||
- (
- (parser->current.end + encoding_width >= parser->end) ||
- !char_is_identifier(parser, parser->current.end + encoding_width)
- )
- ) {
- lex_state_set(parser, PM_LEX_STATE_END);
- parser->current.end += encoding_width;
- pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
- return PM_TOKEN_CHARACTER_LITERAL;
- }
- }
-
- return PM_TOKEN_QUESTION_MARK;
-}
-
-/**
- * Lex a variable that starts with an @ sign (either an instance or class
- * variable).
- */
-static pm_token_type_t
-lex_at_variable(pm_parser_t *parser) {
- pm_token_type_t type = match(parser, '@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
- size_t width;
-
- if (parser->current.end < parser->end && (width = char_is_identifier_start(parser, parser->current.end)) > 0) {
- parser->current.end += width;
-
- while (parser->current.end < parser->end && (width = char_is_identifier(parser, parser->current.end)) > 0) {
- parser->current.end += width;
- }
- } else if (parser->current.end < parser->end && pm_char_is_decimal_digit(*parser->current.end)) {
- pm_diagnostic_id_t diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
- if (parser->version == PM_OPTIONS_VERSION_CRUBY_3_3) {
- diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
- }
-
- size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, diag_id, (int) ((parser->current.end + width) - parser->current.start), (const char *) parser->current.start);
- } else {
- pm_diagnostic_id_t diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
- pm_parser_err_token(parser, &parser->current, diag_id);
- }
-
- // If we're lexing an embedded variable, then we need to pop back into the
- // parent lex context.
- if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
- lex_mode_pop(parser);
- }
-
- return type;
-}
-
-/**
- * Optionally call out to the lex callback if one is provided.
- */
-static inline void
-parser_lex_callback(pm_parser_t *parser) {
- if (parser->lex_callback) {
- parser->lex_callback->callback(parser->lex_callback->data, parser, &parser->current);
- }
-}
-
-/**
- * Return a new comment node of the specified type.
- */
-static inline pm_comment_t *
-parser_comment(pm_parser_t *parser, pm_comment_type_t type) {
- pm_comment_t *comment = (pm_comment_t *) xcalloc(1, sizeof(pm_comment_t));
- if (comment == NULL) return NULL;
-
- *comment = (pm_comment_t) {
- .type = type,
- .location = { parser->current.start, parser->current.end }
- };
-
- return comment;
-}
-
-/**
- * Lex out embedded documentation, and return when we have either hit the end of
- * the file or the end of the embedded documentation. This calls the callback
- * manually because only the lexer should see these tokens, not the parser.
- */
-static pm_token_type_t
-lex_embdoc(pm_parser_t *parser) {
- // First, lex out the EMBDOC_BEGIN token.
- const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
-
- if (newline == NULL) {
- parser->current.end = parser->end;
- } else {
- pm_newline_list_append(&parser->newline_list, newline);
- parser->current.end = newline + 1;
- }
-
- parser->current.type = PM_TOKEN_EMBDOC_BEGIN;
- parser_lex_callback(parser);
-
- // Now, create a comment that is going to be attached to the parser.
- pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
- if (comment == NULL) return PM_TOKEN_EOF;
-
- // Now, loop until we find the end of the embedded documentation or the end
- // of the file.
- while (parser->current.end + 4 <= parser->end) {
- parser->current.start = parser->current.end;
-
- // If we've hit the end of the embedded documentation then we'll return
- // that token here.
- if (
- (memcmp(parser->current.end, "=end", 4) == 0) &&
- (
- (parser->current.end + 4 == parser->end) || // end of file
- pm_char_is_whitespace(parser->current.end[4]) || // whitespace
- (parser->current.end[4] == '\0') || // NUL or end of script
- (parser->current.end[4] == '\004') || // ^D
- (parser->current.end[4] == '\032') // ^Z
- )
- ) {
- const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
-
- if (newline == NULL) {
- parser->current.end = parser->end;
- } else {
- pm_newline_list_append(&parser->newline_list, newline);
- parser->current.end = newline + 1;
- }
-
- parser->current.type = PM_TOKEN_EMBDOC_END;
- parser_lex_callback(parser);
-
- comment->location.end = parser->current.end;
- pm_list_append(&parser->comment_list, (pm_list_node_t *) comment);
-
- return PM_TOKEN_EMBDOC_END;
- }
-
- // Otherwise, we'll parse until the end of the line and return a line of
- // embedded documentation.
- const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
-
- if (newline == NULL) {
- parser->current.end = parser->end;
- } else {
- pm_newline_list_append(&parser->newline_list, newline);
- parser->current.end = newline + 1;
- }
-
- parser->current.type = PM_TOKEN_EMBDOC_LINE;
- parser_lex_callback(parser);
- }
-
- pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
-
- comment->location.end = parser->current.end;
- pm_list_append(&parser->comment_list, (pm_list_node_t *) comment);
-
- return PM_TOKEN_EOF;
-}
-
-/**
- * Set the current type to an ignored newline and then call the lex callback.
- * This happens in a couple places depending on whether or not we have already
- * lexed a comment.
- */
-static inline void
-parser_lex_ignored_newline(pm_parser_t *parser) {
- parser->current.type = PM_TOKEN_IGNORED_NEWLINE;
- parser_lex_callback(parser);
-}
-
-/**
- * This function will be called when a newline is encountered. In some newlines,
- * we need to check if there is a heredoc or heredocs that we have already lexed
- * the body of that we need to now skip past. That will be indicated by the
- * heredoc_end field on the parser.
- *
- * If it is set, then we need to skip past the heredoc body and then clear the
- * heredoc_end field.
- */
-static inline void
-parser_flush_heredoc_end(pm_parser_t *parser) {
- assert(parser->heredoc_end <= parser->end);
- parser->next_start = parser->heredoc_end;
- parser->heredoc_end = NULL;
-}
-
-/**
- * Returns true if the parser has lexed the last token on the current line.
-*/
-static bool
-parser_end_of_line_p(const pm_parser_t *parser) {
- const uint8_t *cursor = parser->current.end;
-
- while (cursor < parser->end && *cursor != '\n' && *cursor != '#') {
- if (!pm_char_is_inline_whitespace(*cursor++)) return false;
- }
-
- return true;
-}
-
-/**
- * When we're lexing certain types (strings, symbols, lists, etc.) we have
- * string content associated with the tokens. For example:
- *
- * "foo"
- *
- * In this case, the string content is foo. Since there is no escaping, there's
- * no need to track additional information and the token can be returned as
- * normal. However, if we have escape sequences:
- *
- * "foo\n"
- *
- * then the bytes in the string are "f", "o", "o", "\", "n", but we want to
- * provide our consumers with the string content "f", "o", "o", "\n". In these
- * cases, when we find the first escape sequence, we initialize a pm_buffer_t
- * to keep track of the string content. Then in the parser, it will
- * automatically attach the string content to the node that it belongs to.
- */
-typedef struct {
- /**
- * The buffer that we're using to keep track of the string content. It will
- * only be initialized if we receive an escape sequence.
- */
- pm_buffer_t buffer;
-
- /**
- * The cursor into the source string that points to how far we have
- * currently copied into the buffer.
- */
- const uint8_t *cursor;
-} pm_token_buffer_t;
-
-/**
- * In order to properly set a regular expression's encoding and to validate
- * the byte sequence for the underlying encoding we must process any escape
- * sequences. The unescaped byte sequence will be stored in `buffer` just like
- * for other string-like types. However, we also need to store the regular
- * expression's source string. That string may be different from what we see
- * during lexing because some escape sequences rewrite the source.
- *
- * This value will only be initialized for regular expressions and only if we
- * receive an escape sequence. It will contain the regular expression's source
- * string's byte sequence.
- */
-typedef struct {
- /** The embedded base buffer. */
- pm_token_buffer_t base;
-
- /** The buffer holding the regexp source. */
- pm_buffer_t regexp_buffer;
-} pm_regexp_token_buffer_t;
-
-/**
- * Push the given byte into the token buffer.
- */
-static inline void
-pm_token_buffer_push_byte(pm_token_buffer_t *token_buffer, uint8_t byte) {
- pm_buffer_append_byte(&token_buffer->buffer, byte);
-}
-
-static inline void
-pm_regexp_token_buffer_push_byte(pm_regexp_token_buffer_t *token_buffer, uint8_t byte) {
- pm_buffer_append_byte(&token_buffer->regexp_buffer, byte);
-}
-
-/**
- * Return the width of the character at the end of the current token.
- */
-static inline size_t
-parser_char_width(const pm_parser_t *parser) {
- size_t width;
- if (parser->encoding_changed) {
- width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
- } else {
- width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
- }
-
- // TODO: If the character is invalid in the given encoding, then we'll just
- // push one byte into the buffer. This should actually be an error.
- return (width == 0 ? 1 : width);
-}
-
-/**
- * Push an escaped character into the token buffer.
- */
-static void
-pm_token_buffer_push_escaped(pm_token_buffer_t *token_buffer, pm_parser_t *parser) {
- size_t width = parser_char_width(parser);
- pm_buffer_append_bytes(&token_buffer->buffer, parser->current.end, width);
- parser->current.end += width;
-}
-
-static void
-pm_regexp_token_buffer_push_escaped(pm_regexp_token_buffer_t *token_buffer, pm_parser_t *parser) {
- size_t width = parser_char_width(parser);
- pm_buffer_append_bytes(&token_buffer->base.buffer, parser->current.end, width);
- pm_buffer_append_bytes(&token_buffer->regexp_buffer, parser->current.end, width);
- parser->current.end += width;
-}
-
-static bool
-pm_slice_ascii_only_p(const uint8_t *value, size_t length) {
- for (size_t index = 0; index < length; index++) {
- if (value[index] & 0x80) return false;
- }
-
- return true;
-}
-
-/**
- * When we're about to return from lexing the current token and we know for sure
- * that we have found an escape sequence, this function is called to copy the
- * contents of the token buffer into the current string on the parser so that it
- * can be attached to the correct node.
- */
-static inline void
-pm_token_buffer_copy(pm_parser_t *parser, pm_token_buffer_t *token_buffer) {
- pm_string_owned_init(&parser->current_string, (uint8_t *) pm_buffer_value(&token_buffer->buffer), pm_buffer_length(&token_buffer->buffer));
-}
-
-static inline void
-pm_regexp_token_buffer_copy(pm_parser_t *parser, pm_regexp_token_buffer_t *token_buffer) {
- pm_string_owned_init(&parser->current_string, (uint8_t *) pm_buffer_value(&token_buffer->base.buffer), pm_buffer_length(&token_buffer->base.buffer));
- parser->current_regular_expression_ascii_only = pm_slice_ascii_only_p((const uint8_t *) pm_buffer_value(&token_buffer->regexp_buffer), pm_buffer_length(&token_buffer->regexp_buffer));
- pm_buffer_free(&token_buffer->regexp_buffer);
-}
-
-/**
- * When we're about to return from lexing the current token, we need to flush
- * all of the content that we have pushed into the buffer into the current
- * string. If we haven't pushed anything into the buffer, this means that we
- * never found an escape sequence, so we can directly reference the bounds of
- * the current string. Either way, at the return of this function it is expected
- * that parser->current_string is established in such a way that it can be
- * attached to a node.
- */
-static void
-pm_token_buffer_flush(pm_parser_t *parser, pm_token_buffer_t *token_buffer) {
- if (token_buffer->cursor == NULL) {
- pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
- } else {
- pm_buffer_append_bytes(&token_buffer->buffer, token_buffer->cursor, (size_t) (parser->current.end - token_buffer->cursor));
- pm_token_buffer_copy(parser, token_buffer);
- }
-}
-
-static void
-pm_regexp_token_buffer_flush(pm_parser_t *parser, pm_regexp_token_buffer_t *token_buffer) {
- if (token_buffer->base.cursor == NULL) {
- pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
- parser->current_regular_expression_ascii_only = pm_slice_ascii_only_p(parser->current.start, (size_t) (parser->current.end - parser->current.start));
- } else {
- pm_buffer_append_bytes(&token_buffer->base.buffer, token_buffer->base.cursor, (size_t) (parser->current.end - token_buffer->base.cursor));
- pm_buffer_append_bytes(&token_buffer->regexp_buffer, token_buffer->base.cursor, (size_t) (parser->current.end - token_buffer->base.cursor));
- pm_regexp_token_buffer_copy(parser, token_buffer);
- }
-}
-
-#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
-
-/**
- * When we've found an escape sequence, we need to copy everything up to this
- * point into the buffer because we're about to provide a string that has
- * different content than a direct slice of the source.
- *
- * It is expected that the parser's current token end will be pointing at one
- * byte past the backslash that starts the escape sequence.
- */
-static void
-pm_token_buffer_escape(pm_parser_t *parser, pm_token_buffer_t *token_buffer) {
- const uint8_t *start;
- if (token_buffer->cursor == NULL) {
- pm_buffer_init_capacity(&token_buffer->buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
- start = parser->current.start;
- } else {
- start = token_buffer->cursor;
- }
-
- const uint8_t *end = parser->current.end - 1;
- pm_buffer_append_bytes(&token_buffer->buffer, start, (size_t) (end - start));
-
- token_buffer->cursor = end;
-}
-
-static void
-pm_regexp_token_buffer_escape(pm_parser_t *parser, pm_regexp_token_buffer_t *token_buffer) {
- const uint8_t *start;
- if (token_buffer->base.cursor == NULL) {
- pm_buffer_init_capacity(&token_buffer->base.buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
- pm_buffer_init_capacity(&token_buffer->regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
- start = parser->current.start;
- } else {
- start = token_buffer->base.cursor;
- }
-
- const uint8_t *end = parser->current.end - 1;
- pm_buffer_append_bytes(&token_buffer->base.buffer, start, (size_t) (end - start));
- pm_buffer_append_bytes(&token_buffer->regexp_buffer, start, (size_t) (end - start));
-
- token_buffer->base.cursor = end;
-}
-
-#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
-
-/**
- * Effectively the same thing as pm_strspn_inline_whitespace, but in the case of
- * a tilde heredoc expands out tab characters to the nearest tab boundaries.
- */
-static inline size_t
-pm_heredoc_strspn_inline_whitespace(pm_parser_t *parser, const uint8_t **cursor, pm_heredoc_indent_t indent) {
- size_t whitespace = 0;
-
- switch (indent) {
- case PM_HEREDOC_INDENT_NONE:
- // Do nothing, we can't match a terminator with
- // indentation and there's no need to calculate common
- // whitespace.
- break;
- case PM_HEREDOC_INDENT_DASH:
- // Skip past inline whitespace.
- *cursor += pm_strspn_inline_whitespace(*cursor, parser->end - *cursor);
- break;
- case PM_HEREDOC_INDENT_TILDE:
- // Skip past inline whitespace and calculate common
- // whitespace.
- while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
- if (**cursor == '\t') {
- whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
- } else {
- whitespace++;
- }
- (*cursor)++;
- }
-
- break;
- }
-
- return whitespace;
-}
-
-/**
- * Lex past the delimiter of a percent literal. Handle newlines and heredocs
- * appropriately.
- */
-static uint8_t
-pm_lex_percent_delimiter(pm_parser_t *parser) {
- size_t eol_length = match_eol(parser);
-
- if (eol_length) {
- if (parser->heredoc_end) {
- // If we have already lexed a heredoc, then the newline has already
- // been added to the list. In this case we want to just flush the
- // heredoc end.
- parser_flush_heredoc_end(parser);
- } else {
- // Otherwise, we'll add the newline to the list of newlines.
- pm_newline_list_append(&parser->newline_list, parser->current.end + eol_length - 1);
- }
-
- const uint8_t delimiter = *parser->current.end;
- parser->current.end += eol_length;
-
- return delimiter;
- }
-
- return *parser->current.end++;
-}
-
-/**
- * This is a convenience macro that will set the current token type, call the
- * lex callback, and then return from the parser_lex function.
- */
-#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
-
-/**
- * Called when the parser requires a new token. The parser maintains a moving
- * window of two tokens at a time: parser.previous and parser.current. This
- * function will move the current token into the previous token and then
- * lex a new token into the current token.
- */
-static void
-parser_lex(pm_parser_t *parser) {
- assert(parser->current.end <= parser->end);
- parser->previous = parser->current;
-
- // This value mirrors cmd_state from CRuby.
- bool previous_command_start = parser->command_start;
- parser->command_start = false;
-
- // This is used to communicate to the newline lexing function that we've
- // already seen a comment.
- bool lexed_comment = false;
-
- // Here we cache the current value of the semantic token seen flag. This is
- // used to reset it in case we find a token that shouldn't flip this flag.
- unsigned int semantic_token_seen = parser->semantic_token_seen;
- parser->semantic_token_seen = true;
-
- switch (parser->lex_modes.current->mode) {
- case PM_LEX_DEFAULT:
- case PM_LEX_EMBEXPR:
- case PM_LEX_EMBVAR:
-
- // We have a specific named label here because we are going to jump back to
- // this location in the event that we have lexed a token that should not be
- // returned to the parser. This includes comments, ignored newlines, and
- // invalid tokens of some form.
- lex_next_token: {
- // If we have the special next_start pointer set, then we're going to jump
- // to that location and start lexing from there.
- if (parser->next_start != NULL) {
- parser->current.end = parser->next_start;
- parser->next_start = NULL;
- }
-
- // This value mirrors space_seen from CRuby. It tracks whether or not
- // space has been eaten before the start of the next token.
- bool space_seen = false;
-
- // First, we're going to skip past any whitespace at the front of the next
- // token.
- bool chomping = true;
- while (parser->current.end < parser->end && chomping) {
- switch (*parser->current.end) {
- case ' ':
- case '\t':
- case '\f':
- case '\v':
- parser->current.end++;
- space_seen = true;
- break;
- case '\r':
- if (match_eol_offset(parser, 1)) {
- chomping = false;
- } else {
- pm_parser_warn(parser, parser->current.end, parser->current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
- parser->current.end++;
- space_seen = true;
- }
- break;
- case '\\': {
- size_t eol_length = match_eol_offset(parser, 1);
- if (eol_length) {
- if (parser->heredoc_end) {
- parser->current.end = parser->heredoc_end;
- parser->heredoc_end = NULL;
- } else {
- parser->current.end += eol_length + 1;
- pm_newline_list_append(&parser->newline_list, parser->current.end - 1);
- space_seen = true;
- }
- } else if (pm_char_is_inline_whitespace(*parser->current.end)) {
- parser->current.end += 2;
- } else {
- chomping = false;
- }
-
- break;
- }
- default:
- chomping = false;
- break;
- }
- }
-
- // Next, we'll set to start of this token to be the current end.
- parser->current.start = parser->current.end;
-
- // We'll check if we're at the end of the file. If we are, then we
- // need to return the EOF token.
- if (parser->current.end >= parser->end) {
- LEX(PM_TOKEN_EOF);
- }
-
- // Finally, we'll check the current character to determine the next
- // token.
- switch (*parser->current.end++) {
- case '\0': // NUL or end of script
- case '\004': // ^D
- case '\032': // ^Z
- parser->current.end--;
- LEX(PM_TOKEN_EOF);
-
- case '#': { // comments
- const uint8_t *ending = next_newline(parser->current.end, parser->end - parser->current.end);
- parser->current.end = ending == NULL ? parser->end : ending;
-
- // If we found a comment while lexing, then we're going to
- // add it to the list of comments in the file and keep
- // lexing.
- pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
- pm_list_append(&parser->comment_list, (pm_list_node_t *) comment);
-
- if (ending) parser->current.end++;
- parser->current.type = PM_TOKEN_COMMENT;
- parser_lex_callback(parser);
-
- // Here, parse the comment to see if it's a magic comment
- // and potentially change state on the parser.
- if (!parser_lex_magic_comment(parser, semantic_token_seen) && (parser->current.start == parser->encoding_comment_start)) {
- ptrdiff_t length = parser->current.end - parser->current.start;
-
- // If we didn't find a magic comment within the first
- // pass and we're at the start of the file, then we need
- // to do another pass to potentially find other patterns
- // for encoding comments.
- if (length >= 10 && !parser->encoding_locked) {
- parser_lex_magic_comment_encoding(parser);
- }
- }
-
- lexed_comment = true;
- }
- /* fallthrough */
- case '\r':
- case '\n': {
- parser->semantic_token_seen = semantic_token_seen & 0x1;
- size_t eol_length = match_eol_at(parser, parser->current.end - 1);
-
- if (eol_length) {
- // The only way you can have carriage returns in this
- // particular loop is if you have a carriage return
- // followed by a newline. In that case we'll just skip
- // over the carriage return and continue lexing, in
- // order to make it so that the newline token
- // encapsulates both the carriage return and the
- // newline. Note that we need to check that we haven't
- // already lexed a comment here because that falls
- // through into here as well.
- if (!lexed_comment) {
- parser->current.end += eol_length - 1; // skip CR
- }
-
- if (parser->heredoc_end == NULL) {
- pm_newline_list_append(&parser->newline_list, parser->current.end - 1);
- }
- }
-
- if (parser->heredoc_end) {
- parser_flush_heredoc_end(parser);
- }
-
- // If this is an ignored newline, then we can continue lexing after
- // calling the callback with the ignored newline token.
- switch (lex_state_ignored_p(parser)) {
- case PM_IGNORED_NEWLINE_NONE:
- break;
- case PM_IGNORED_NEWLINE_PATTERN:
- if (parser->pattern_matching_newlines || parser->in_keyword_arg) {
- if (!lexed_comment) parser_lex_ignored_newline(parser);
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser->command_start = true;
- parser->current.type = PM_TOKEN_NEWLINE;
- return;
- }
- /* fallthrough */
- case PM_IGNORED_NEWLINE_ALL:
- if (!lexed_comment) parser_lex_ignored_newline(parser);
- lexed_comment = false;
- goto lex_next_token;
- }
-
- // Here we need to look ahead and see if there is a call operator
- // (either . or &.) that starts the next line. If there is, then this
- // is going to become an ignored newline and we're going to instead
- // return the call operator.
- const uint8_t *next_content = parser->next_start == NULL ? parser->current.end : parser->next_start;
- next_content += pm_strspn_inline_whitespace(next_content, parser->end - next_content);
-
- if (next_content < parser->end) {
- // If we hit a comment after a newline, then we're going to check
- // if it's ignored or if it's followed by a method call ('.').
- // If it is, then we're going to call the
- // callback with an ignored newline and then continue lexing.
- // Otherwise we'll return a regular newline.
- if (next_content[0] == '#') {
- // Here we look for a "." or "&." following a "\n".
- const uint8_t *following = next_newline(next_content, parser->end - next_content);
-
- while (following && (following + 1 < parser->end)) {
- following++;
- following += pm_strspn_inline_whitespace(following, parser->end - following);
-
- // If this is not followed by a comment, then we can break out
- // of this loop.
- if (peek_at(parser, following) != '#') break;
-
- // If there is a comment, then we need to find the end of the
- // comment and continue searching from there.
- following = next_newline(following, parser->end - following);
- }
-
- // If the lex state was ignored, or we hit a '.' or a '&.',
- // we will lex the ignored newline
- if (
- lex_state_ignored_p(parser) ||
- (following && (
- (peek_at(parser, following) == '.') ||
- (peek_at(parser, following) == '&' && peek_at(parser, following + 1) == '.')
- ))
- ) {
- if (!lexed_comment) parser_lex_ignored_newline(parser);
- lexed_comment = false;
- goto lex_next_token;
- }
- }
-
- // If we hit a . after a newline, then we're in a call chain and
- // we need to return the call operator.
- if (next_content[0] == '.') {
- // To match ripper, we need to emit an ignored newline even though
- // it's a real newline in the case that we have a beginless range
- // on a subsequent line.
- if (peek_at(parser, next_content + 1) == '.') {
- if (!lexed_comment) parser_lex_ignored_newline(parser);
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser->command_start = true;
- parser->current.type = PM_TOKEN_NEWLINE;
- return;
- }
-
- if (!lexed_comment) parser_lex_ignored_newline(parser);
- lex_state_set(parser, PM_LEX_STATE_DOT);
- parser->current.start = next_content;
- parser->current.end = next_content + 1;
- parser->next_start = NULL;
- LEX(PM_TOKEN_DOT);
- }
-
- // If we hit a &. after a newline, then we're in a call chain and
- // we need to return the call operator.
- if (peek_at(parser, next_content) == '&' && peek_at(parser, next_content + 1) == '.') {
- if (!lexed_comment) parser_lex_ignored_newline(parser);
- lex_state_set(parser, PM_LEX_STATE_DOT);
- parser->current.start = next_content;
- parser->current.end = next_content + 2;
- parser->next_start = NULL;
- LEX(PM_TOKEN_AMPERSAND_DOT);
- }
- }
-
- // At this point we know this is a regular newline, and we can set the
- // necessary state and return the token.
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser->command_start = true;
- parser->current.type = PM_TOKEN_NEWLINE;
- if (!lexed_comment) parser_lex_callback(parser);
- return;
- }
-
- // ,
- case ',':
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- LEX(PM_TOKEN_COMMA);
-
- // (
- case '(': {
- pm_token_type_t type = PM_TOKEN_PARENTHESIS_LEFT;
-
- if (space_seen && (lex_state_arg_p(parser) || parser->lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
- type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
- }
-
- parser->enclosure_nesting++;
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- pm_do_loop_stack_push(parser, false);
- LEX(type);
- }
-
- // )
- case ')':
- parser->enclosure_nesting--;
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- pm_do_loop_stack_pop(parser);
- LEX(PM_TOKEN_PARENTHESIS_RIGHT);
-
- // ;
- case ';':
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser->command_start = true;
- LEX(PM_TOKEN_SEMICOLON);
-
- // [ [] []=
- case '[':
- parser->enclosure_nesting++;
- pm_token_type_t type = PM_TOKEN_BRACKET_LEFT;
-
- if (lex_state_operator_p(parser)) {
- if (match(parser, ']')) {
- parser->enclosure_nesting--;
- lex_state_set(parser, PM_LEX_STATE_ARG);
- LEX(match(parser, '=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
- }
-
- lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
- LEX(type);
- }
-
- if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
- type = PM_TOKEN_BRACKET_LEFT_ARRAY;
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- pm_do_loop_stack_push(parser, false);
- LEX(type);
-
- // ]
- case ']':
- parser->enclosure_nesting--;
- lex_state_set(parser, PM_LEX_STATE_END);
- pm_do_loop_stack_pop(parser);
- LEX(PM_TOKEN_BRACKET_RIGHT);
-
- // {
- case '{': {
- pm_token_type_t type = PM_TOKEN_BRACE_LEFT;
-
- if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
- // This { begins a lambda
- parser->command_start = true;
- lex_state_set(parser, PM_LEX_STATE_BEG);
- type = PM_TOKEN_LAMBDA_BEGIN;
- } else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
- // This { begins a hash literal
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- } else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
- // This { begins a block
- parser->command_start = true;
- lex_state_set(parser, PM_LEX_STATE_BEG);
- } else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
- // This { begins a block on a command
- parser->command_start = true;
- lex_state_set(parser, PM_LEX_STATE_BEG);
- } else {
- // This { begins a hash literal
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- }
-
- parser->enclosure_nesting++;
- parser->brace_nesting++;
- pm_do_loop_stack_push(parser, false);
-
- LEX(type);
- }
-
- // }
- case '}':
- parser->enclosure_nesting--;
- pm_do_loop_stack_pop(parser);
-
- if ((parser->lex_modes.current->mode == PM_LEX_EMBEXPR) && (parser->brace_nesting == 0)) {
- lex_mode_pop(parser);
- LEX(PM_TOKEN_EMBEXPR_END);
- }
-
- parser->brace_nesting--;
- lex_state_set(parser, PM_LEX_STATE_END);
- LEX(PM_TOKEN_BRACE_RIGHT);
-
- // * ** **= *=
- case '*': {
- if (match(parser, '*')) {
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_STAR_STAR_EQUAL);
- }
-
- pm_token_type_t type = PM_TOKEN_STAR_STAR;
-
- if (lex_state_spcarg_p(parser, space_seen)) {
- pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
- type = PM_TOKEN_USTAR_STAR;
- } else if (lex_state_beg_p(parser)) {
- type = PM_TOKEN_USTAR_STAR;
- } else if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "**", "argument prefix");
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(type);
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_STAR_EQUAL);
- }
-
- pm_token_type_t type = PM_TOKEN_STAR;
-
- if (lex_state_spcarg_p(parser, space_seen)) {
- pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
- type = PM_TOKEN_USTAR;
- } else if (lex_state_beg_p(parser)) {
- type = PM_TOKEN_USTAR;
- } else if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "*", "argument prefix");
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(type);
- }
-
- // ! != !~ !@
- case '!':
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- if (match(parser, '@')) {
- LEX(PM_TOKEN_BANG);
- }
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- if (match(parser, '=')) {
- LEX(PM_TOKEN_BANG_EQUAL);
- }
-
- if (match(parser, '~')) {
- LEX(PM_TOKEN_BANG_TILDE);
- }
-
- LEX(PM_TOKEN_BANG);
-
- // = => =~ == === =begin
- case '=':
- if (
- current_token_starts_line(parser) &&
- (parser->current.end + 5 <= parser->end) &&
- memcmp(parser->current.end, "begin", 5) == 0 &&
- (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) == '\0'))
- ) {
- pm_token_type_t type = lex_embdoc(parser);
- if (type == PM_TOKEN_EOF) {
- LEX(type);
- }
-
- goto lex_next_token;
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- if (match(parser, '>')) {
- LEX(PM_TOKEN_EQUAL_GREATER);
- }
-
- if (match(parser, '~')) {
- LEX(PM_TOKEN_EQUAL_TILDE);
- }
-
- if (match(parser, '=')) {
- LEX(match(parser, '=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
- }
-
- LEX(PM_TOKEN_EQUAL);
-
- // < << <<= <= <=>
- case '<':
- if (match(parser, '<')) {
- if (
- !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
- !lex_state_end_p(parser) &&
- (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
- ) {
- const uint8_t *end = parser->current.end;
-
- pm_heredoc_quote_t quote = PM_HEREDOC_QUOTE_NONE;
- pm_heredoc_indent_t indent = PM_HEREDOC_INDENT_NONE;
-
- if (match(parser, '-')) {
- indent = PM_HEREDOC_INDENT_DASH;
- }
- else if (match(parser, '~')) {
- indent = PM_HEREDOC_INDENT_TILDE;
- }
-
- if (match(parser, '`')) {
- quote = PM_HEREDOC_QUOTE_BACKTICK;
- }
- else if (match(parser, '"')) {
- quote = PM_HEREDOC_QUOTE_DOUBLE;
- }
- else if (match(parser, '\'')) {
- quote = PM_HEREDOC_QUOTE_SINGLE;
- }
-
- const uint8_t *ident_start = parser->current.end;
- size_t width = 0;
-
- if (parser->current.end >= parser->end) {
- parser->current.end = end;
- } else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->current.end)) == 0) {
- parser->current.end = end;
- } else {
- if (quote == PM_HEREDOC_QUOTE_NONE) {
- parser->current.end += width;
-
- while ((parser->current.end < parser->end) && (width = char_is_identifier(parser, parser->current.end))) {
- parser->current.end += width;
- }
- } else {
- // If we have quotes, then we're going to go until we find the
- // end quote.
- while ((parser->current.end < parser->end) && quote != (pm_heredoc_quote_t) (*parser->current.end)) {
- if (*parser->current.end == '\r' || *parser->current.end == '\n') break;
- parser->current.end++;
- }
- }
-
- size_t ident_length = (size_t) (parser->current.end - ident_start);
- bool ident_error = false;
-
- if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
- pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
- ident_error = true;
- }
-
- parser->explicit_encoding = NULL;
- lex_mode_push(parser, (pm_lex_mode_t) {
- .mode = PM_LEX_HEREDOC,
- .as.heredoc = {
- .base = {
- .ident_start = ident_start,
- .ident_length = ident_length,
- .quote = quote,
- .indent = indent
- },
- .next_start = parser->current.end,
- .common_whitespace = NULL,
- .line_continuation = false
- }
- });
-
- if (parser->heredoc_end == NULL) {
- const uint8_t *body_start = next_newline(parser->current.end, parser->end - parser->current.end);
-
- if (body_start == NULL) {
- // If there is no newline after the heredoc identifier, then
- // this is not a valid heredoc declaration. In this case we
- // will add an error, but we will still return a heredoc
- // start.
- if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
- body_start = parser->end;
- } else {
- // Otherwise, we want to indicate that the body of the
- // heredoc starts on the character after the next newline.
- pm_newline_list_append(&parser->newline_list, body_start);
- body_start++;
- }
-
- parser->next_start = body_start;
- } else {
- parser->next_start = parser->heredoc_end;
- }
-
- LEX(PM_TOKEN_HEREDOC_START);
- }
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_LESS_LESS_EQUAL);
- }
-
- if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "<<", "here document");
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start = true;
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(PM_TOKEN_LESS_LESS);
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start = true;
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- if (match(parser, '=')) {
- if (match(parser, '>')) {
- LEX(PM_TOKEN_LESS_EQUAL_GREATER);
- }
-
- LEX(PM_TOKEN_LESS_EQUAL);
- }
-
- LEX(PM_TOKEN_LESS);
-
- // > >> >>= >=
- case '>':
- if (match(parser, '>')) {
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
- LEX(match(parser, '=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(match(parser, '=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
-
- // double-quoted string literal
- case '"': {
- bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
- lex_mode_push_string(parser, true, label_allowed, '\0', '"');
- LEX(PM_TOKEN_STRING_BEGIN);
- }
-
- // xstring literal
- case '`': {
- if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- LEX(PM_TOKEN_BACKTICK);
- }
-
- if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
- if (previous_command_start) {
- lex_state_set(parser, PM_LEX_STATE_CMDARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- }
-
- LEX(PM_TOKEN_BACKTICK);
- }
-
- lex_mode_push_string(parser, true, false, '\0', '`');
- LEX(PM_TOKEN_BACKTICK);
- }
-
- // single-quoted string literal
- case '\'': {
- bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
- lex_mode_push_string(parser, false, label_allowed, '\0', '\'');
- LEX(PM_TOKEN_STRING_BEGIN);
- }
-
- // ? character literal
- case '?':
- LEX(lex_question_mark(parser));
-
- // & && &&= &=
- case '&': {
- if (match(parser, '&')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
-
- if (match(parser, '=')) {
- LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
- }
-
- LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_AMPERSAND_EQUAL);
- }
-
- if (match(parser, '.')) {
- lex_state_set(parser, PM_LEX_STATE_DOT);
- LEX(PM_TOKEN_AMPERSAND_DOT);
- }
-
- pm_token_type_t type = PM_TOKEN_AMPERSAND;
- if (lex_state_spcarg_p(parser, space_seen)) {
- if ((peek(parser) != ':') || (peek_offset(parser, 1) == '\0')) {
- pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
- } else {
- const uint8_t delim = peek_offset(parser, 1);
-
- if ((delim != '\'') && (delim != '"') && !char_is_identifier(parser, parser->current.end + 1)) {
- pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
- }
- }
-
- type = PM_TOKEN_UAMPERSAND;
- } else if (lex_state_beg_p(parser)) {
- type = PM_TOKEN_UAMPERSAND;
- } else if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "&", "argument prefix");
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(type);
- }
-
- // | || ||= |=
- case '|':
- if (match(parser, '|')) {
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
- }
-
- if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
- parser->current.end--;
- LEX(PM_TOKEN_PIPE);
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PIPE_PIPE);
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PIPE_EQUAL);
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- }
-
- LEX(PM_TOKEN_PIPE);
-
- // + += +@
- case '+': {
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
-
- if (match(parser, '@')) {
- LEX(PM_TOKEN_UPLUS);
- }
-
- LEX(PM_TOKEN_PLUS);
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PLUS_EQUAL);
- }
-
- if (
- lex_state_beg_p(parser) ||
- (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS), true) : false)
- ) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
-
- if (pm_char_is_decimal_digit(peek(parser))) {
- parser->current.end++;
- pm_token_type_t type = lex_numeric(parser);
- lex_state_set(parser, PM_LEX_STATE_END);
- LEX(type);
- }
-
- LEX(PM_TOKEN_UPLUS);
- }
-
- if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "+", "unary operator");
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PLUS);
- }
-
- // - -= -@
- case '-': {
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
-
- if (match(parser, '@')) {
- LEX(PM_TOKEN_UMINUS);
- }
-
- LEX(PM_TOKEN_MINUS);
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_MINUS_EQUAL);
- }
-
- if (match(parser, '>')) {
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- LEX(PM_TOKEN_MINUS_GREATER);
- }
-
- bool spcarg = lex_state_spcarg_p(parser, space_seen);
- bool is_beg = lex_state_beg_p(parser);
- if (!is_beg && spcarg) {
- pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
- }
-
- if (is_beg || spcarg) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
- }
-
- if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "-", "unary operator");
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_MINUS);
- }
-
- // . .. ...
- case '.': {
- bool beg_p = lex_state_beg_p(parser);
-
- if (match(parser, '.')) {
- if (match(parser, '.')) {
- // If we're _not_ inside a range within default parameters
- if (!context_p(parser, PM_CONTEXT_DEFAULT_PARAMS) && context_p(parser, PM_CONTEXT_DEF_PARAMS)) {
- if (lex_state_p(parser, PM_LEX_STATE_END)) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_ENDARG);
- }
- LEX(PM_TOKEN_UDOT_DOT_DOT);
- }
-
- if (parser->enclosure_nesting == 0 && parser_end_of_line_p(parser)) {
- pm_parser_warn_token(parser, &parser->current, PM_WARN_DOT_DOT_DOT_EOL);
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
- }
-
- lex_state_set(parser, PM_LEX_STATE_DOT);
- LEX(PM_TOKEN_DOT);
- }
-
- // integer
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': {
- pm_token_type_t type = lex_numeric(parser);
- lex_state_set(parser, PM_LEX_STATE_END);
- LEX(type);
- }
-
- // :: symbol
- case ':':
- if (match(parser, ':')) {
- if (lex_state_beg_p(parser) || lex_state_p(parser, PM_LEX_STATE_CLASS) || (lex_state_p(parser, PM_LEX_STATE_ARG_ANY) && space_seen)) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_UCOLON_COLON);
- }
-
- lex_state_set(parser, PM_LEX_STATE_DOT);
- LEX(PM_TOKEN_COLON_COLON);
- }
-
- if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) == '#') {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_COLON);
- }
-
- if (peek(parser) == '"' || peek(parser) == '\'') {
- lex_mode_push_string(parser, peek(parser) == '"', false, '\0', *parser->current.end);
- parser->current.end++;
- }
-
- lex_state_set(parser, PM_LEX_STATE_FNAME);
- LEX(PM_TOKEN_SYMBOL_BEGIN);
-
- // / /=
- case '/':
- if (lex_state_beg_p(parser)) {
- lex_mode_push_regexp(parser, '\0', '/');
- LEX(PM_TOKEN_REGEXP_BEGIN);
- }
-
- if (match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_SLASH_EQUAL);
- }
-
- if (lex_state_spcarg_p(parser, space_seen)) {
- pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_SLASH);
- lex_mode_push_regexp(parser, '\0', '/');
- LEX(PM_TOKEN_REGEXP_BEGIN);
- }
-
- if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "/", "regexp literal");
- }
-
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(PM_TOKEN_SLASH);
-
- // ^ ^=
- case '^':
- if (lex_state_operator_p(parser)) {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
- LEX(match(parser, '=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
-
- // ~ ~@
- case '~':
- if (lex_state_operator_p(parser)) {
- (void) match(parser, '@');
- lex_state_set(parser, PM_LEX_STATE_ARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- }
-
- LEX(PM_TOKEN_TILDE);
-
- // % %= %i %I %q %Q %w %W
- case '%': {
- // If there is no subsequent character then we have an
- // invalid token. We're going to say it's the percent
- // operator because we don't want to move into the string
- // lex mode unnecessarily.
- if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) {
- pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
- LEX(PM_TOKEN_PERCENT);
- }
-
- if (!lex_state_beg_p(parser) && match(parser, '=')) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PERCENT_EQUAL);
- } else if (
- lex_state_beg_p(parser) ||
- (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) == 's')) ||
- lex_state_spcarg_p(parser, space_seen)
- ) {
- if (!parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end)) {
- if (*parser->current.end >= 0x80) {
- pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
- }
-
- const uint8_t delimiter = pm_lex_percent_delimiter(parser);
- lex_mode_push_string(parser, true, false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
- LEX(PM_TOKEN_STRING_BEGIN);
- }
-
- // Delimiters for %-literals cannot be alphanumeric. We
- // validate that here.
- uint8_t delimiter = peek_offset(parser, 1);
- if (delimiter >= 0x80 || parser->encoding->alnum_char(&delimiter, 1)) {
- pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
- goto lex_next_token;
- }
-
- switch (peek(parser)) {
- case 'i': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- lex_mode_push_list(parser, false, pm_lex_percent_delimiter(parser));
- } else {
- lex_mode_push_list_eof(parser);
- }
-
- LEX(PM_TOKEN_PERCENT_LOWER_I);
- }
- case 'I': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- lex_mode_push_list(parser, true, pm_lex_percent_delimiter(parser));
- } else {
- lex_mode_push_list_eof(parser);
- }
-
- LEX(PM_TOKEN_PERCENT_UPPER_I);
- }
- case 'r': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- const uint8_t delimiter = pm_lex_percent_delimiter(parser);
- lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
- } else {
- lex_mode_push_regexp(parser, '\0', '\0');
- }
-
- LEX(PM_TOKEN_REGEXP_BEGIN);
- }
- case 'q': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- const uint8_t delimiter = pm_lex_percent_delimiter(parser);
- lex_mode_push_string(parser, false, false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
- } else {
- lex_mode_push_string_eof(parser);
- }
-
- LEX(PM_TOKEN_STRING_BEGIN);
- }
- case 'Q': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- const uint8_t delimiter = pm_lex_percent_delimiter(parser);
- lex_mode_push_string(parser, true, false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
- } else {
- lex_mode_push_string_eof(parser);
- }
-
- LEX(PM_TOKEN_STRING_BEGIN);
- }
- case 's': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- const uint8_t delimiter = pm_lex_percent_delimiter(parser);
- lex_mode_push_string(parser, false, false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
- lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
- } else {
- lex_mode_push_string_eof(parser);
- }
-
- LEX(PM_TOKEN_SYMBOL_BEGIN);
- }
- case 'w': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- lex_mode_push_list(parser, false, pm_lex_percent_delimiter(parser));
- } else {
- lex_mode_push_list_eof(parser);
- }
-
- LEX(PM_TOKEN_PERCENT_LOWER_W);
- }
- case 'W': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- lex_mode_push_list(parser, true, pm_lex_percent_delimiter(parser));
- } else {
- lex_mode_push_list_eof(parser);
- }
-
- LEX(PM_TOKEN_PERCENT_UPPER_W);
- }
- case 'x': {
- parser->current.end++;
-
- if (parser->current.end < parser->end) {
- const uint8_t delimiter = pm_lex_percent_delimiter(parser);
- lex_mode_push_string(parser, true, false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
- } else {
- lex_mode_push_string_eof(parser);
- }
-
- LEX(PM_TOKEN_PERCENT_LOWER_X);
- }
- default:
- // If we get to this point, then we have a % that is completely
- // unparsable. In this case we'll just drop it from the parser
- // and skip past it and hope that the next token is something
- // that we can parse.
- pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
- goto lex_next_token;
- }
- }
-
- if (ambiguous_operator_p(parser, space_seen)) {
- PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR, "%", "string literal");
- }
-
- lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
- LEX(PM_TOKEN_PERCENT);
- }
-
- // global variable
- case '$': {
- pm_token_type_t type = lex_global_variable(parser);
-
- // If we're lexing an embedded variable, then we need to pop back into
- // the parent lex context.
- if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
- lex_mode_pop(parser);
- }
-
- lex_state_set(parser, PM_LEX_STATE_END);
- LEX(type);
- }
-
- // instance variable, class variable
- case '@':
- lex_state_set(parser, parser->lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
- LEX(lex_at_variable(parser));
-
- default: {
- if (*parser->current.start != '_') {
- size_t width = char_is_identifier_start(parser, parser->current.start);
-
- // If this isn't the beginning of an identifier, then
- // it's an invalid token as we've exhausted all of the
- // other options. We'll skip past it and return the next
- // token after adding an appropriate error message.
- if (!width) {
- if (*parser->current.start >= 0x80) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->current.start);
- } else if (*parser->current.start == '\\') {
- switch (peek_at(parser, parser->current.start + 1)) {
- case ' ':
- parser->current.end++;
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped space");
- break;
- case '\f':
- parser->current.end++;
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped form feed");
- break;
- case '\t':
- parser->current.end++;
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped horizontal tab");
- break;
- case '\v':
- parser->current.end++;
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped vertical tab");
- break;
- case '\r':
- if (peek_at(parser, parser->current.start + 2) != '\n') {
- parser->current.end++;
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "escaped carriage return");
- break;
- }
- /* fallthrough */
- default:
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, "backslash");
- break;
- }
- } else if (char_is_ascii_printable(*parser->current.start)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->current.start);
- } else {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_CHARACTER, *parser->current.start);
- }
-
- goto lex_next_token;
- }
-
- parser->current.end = parser->current.start + width;
- }
-
- pm_token_type_t type = lex_identifier(parser, previous_command_start);
-
- // If we've hit a __END__ and it was at the start of the
- // line or the start of the file and it is followed by
- // either a \n or a \r\n, then this is the last token of the
- // file.
- if (
- ((parser->current.end - parser->current.start) == 7) &&
- current_token_starts_line(parser) &&
- (memcmp(parser->current.start, "__END__", 7) == 0) &&
- (parser->current.end == parser->end || match_eol(parser))
- ) {
- // Since we know we're about to add an __END__ comment,
- // we know we need to add all of the newlines to get the
- // correct column information for it.
- const uint8_t *cursor = parser->current.end;
- while ((cursor = next_newline(cursor, parser->end - cursor)) != NULL) {
- pm_newline_list_append(&parser->newline_list, cursor++);
- }
-
- parser->current.end = parser->end;
- parser->current.type = PM_TOKEN___END__;
- parser_lex_callback(parser);
-
- parser->data_loc.start = parser->current.start;
- parser->data_loc.end = parser->current.end;
-
- LEX(PM_TOKEN_EOF);
- }
-
- pm_lex_state_t last_state = parser->lex_state;
-
- if (type == PM_TOKEN_IDENTIFIER || type == PM_TOKEN_CONSTANT || type == PM_TOKEN_METHOD_NAME) {
- if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
- if (previous_command_start) {
- lex_state_set(parser, PM_LEX_STATE_CMDARG);
- } else {
- lex_state_set(parser, PM_LEX_STATE_ARG);
- }
- } else if (parser->lex_state == PM_LEX_STATE_FNAME) {
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- } else {
- lex_state_set(parser, PM_LEX_STATE_END);
- }
- }
-
- if (
- !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
- (type == PM_TOKEN_IDENTIFIER) &&
- ((pm_parser_local_depth(parser, &parser->current) != -1) ||
- pm_token_is_numbered_parameter(parser->current.start, parser->current.end))
- ) {
- lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
- }
-
- LEX(type);
- }
- }
- }
- case PM_LEX_LIST: {
- if (parser->next_start != NULL) {
- parser->current.end = parser->next_start;
- parser->next_start = NULL;
- }
-
- // First we'll set the beginning of the token.
- parser->current.start = parser->current.end;
-
- // If there's any whitespace at the start of the list, then we're
- // going to trim it off the beginning and create a new token.
- size_t whitespace;
-
- if (parser->heredoc_end) {
- whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
- if (peek_offset(parser, (ptrdiff_t)whitespace) == '\n') {
- whitespace += 1;
- }
- } else {
- whitespace = pm_strspn_whitespace_newlines(parser->current.end, parser->end - parser->current.end, &parser->newline_list);
- }
-
- if (whitespace > 0) {
- parser->current.end += whitespace;
- if (peek_offset(parser, -1) == '\n') {
- // mutates next_start
- parser_flush_heredoc_end(parser);
- }
- LEX(PM_TOKEN_WORDS_SEP);
- }
-
- // We'll check if we're at the end of the file. If we are, then we
- // need to return the EOF token.
- if (parser->current.end >= parser->end) {
- LEX(PM_TOKEN_EOF);
- }
-
- // Here we'll get a list of the places where strpbrk should break,
- // and then find the first one.
- pm_lex_mode_t *lex_mode = parser->lex_modes.current;
- const uint8_t *breakpoints = lex_mode->as.list.breakpoints;
- const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
-
- // If we haven't found an escape yet, then this buffer will be
- // unallocated since we can refer directly to the source string.
- pm_token_buffer_t token_buffer = { 0 };
-
- while (breakpoint != NULL) {
- // If we hit whitespace, then we must have received content by
- // now, so we can return an element of the list.
- if (pm_char_is_whitespace(*breakpoint)) {
- parser->current.end = breakpoint;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // If we hit the terminator, we need to check which token to
- // return.
- if (*breakpoint == lex_mode->as.list.terminator) {
- // If this terminator doesn't actually close the list, then
- // we need to continue on past it.
- if (lex_mode->as.list.nesting > 0) {
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- lex_mode->as.list.nesting--;
- continue;
- }
-
- // If we've hit the terminator and we've already skipped
- // past content, then we can return a list node.
- if (breakpoint > parser->current.start) {
- parser->current.end = breakpoint;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // Otherwise, switch back to the default state and return
- // the end of the list.
- parser->current.end = breakpoint + 1;
- lex_mode_pop(parser);
- lex_state_set(parser, PM_LEX_STATE_END);
- LEX(PM_TOKEN_STRING_END);
- }
-
- // If we hit a null byte, skip directly past it.
- if (*breakpoint == '\0') {
- breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1), true);
- continue;
- }
-
- // If we hit escapes, then we need to treat the next token
- // literally. In this case we'll skip past the next character
- // and find the next breakpoint.
- if (*breakpoint == '\\') {
- parser->current.end = breakpoint + 1;
-
- // If we've hit the end of the file, then break out of the
- // loop by setting the breakpoint to NULL.
- if (parser->current.end == parser->end) {
- breakpoint = NULL;
- continue;
- }
-
- pm_token_buffer_escape(parser, &token_buffer);
- uint8_t peeked = peek(parser);
-
- switch (peeked) {
- case ' ':
- case '\f':
- case '\t':
- case '\v':
- case '\\':
- pm_token_buffer_push_byte(&token_buffer, peeked);
- parser->current.end++;
- break;
- case '\r':
- parser->current.end++;
- if (peek(parser) != '\n') {
- pm_token_buffer_push_byte(&token_buffer, '\r');
- break;
- }
- /* fallthrough */
- case '\n':
- pm_token_buffer_push_byte(&token_buffer, '\n');
-
- if (parser->heredoc_end) {
- // ... if we are on the same line as a heredoc,
- // flush the heredoc and continue parsing after
- // heredoc_end.
- parser_flush_heredoc_end(parser);
- pm_token_buffer_copy(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- } else {
- // ... else track the newline.
- pm_newline_list_append(&parser->newline_list, parser->current.end);
- }
-
- parser->current.end++;
- break;
- default:
- if (peeked == lex_mode->as.list.incrementor || peeked == lex_mode->as.list.terminator) {
- pm_token_buffer_push_byte(&token_buffer, peeked);
- parser->current.end++;
- } else if (lex_mode->as.list.interpolation) {
- escape_read(parser, &token_buffer.buffer, NULL, PM_ESCAPE_FLAG_NONE);
- } else {
- pm_token_buffer_push_byte(&token_buffer, '\\');
- pm_token_buffer_push_escaped(&token_buffer, parser);
- }
-
- break;
- }
-
- token_buffer.cursor = parser->current.end;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- continue;
- }
-
- // If we hit a #, then we will attempt to lex interpolation.
- if (*breakpoint == '#') {
- pm_token_type_t type = lex_interpolation(parser, breakpoint);
-
- if (type == PM_TOKEN_NOT_PROVIDED) {
- // If we haven't returned at this point then we had something
- // that looked like an interpolated class or instance variable
- // like "#@" but wasn't actually. In this case we'll just skip
- // to the next breakpoint.
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- continue;
- }
-
- if (type == PM_TOKEN_STRING_CONTENT) {
- pm_token_buffer_flush(parser, &token_buffer);
- }
-
- LEX(type);
- }
-
- // If we've hit the incrementor, then we need to skip past it
- // and find the next breakpoint.
- assert(*breakpoint == lex_mode->as.list.incrementor);
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- lex_mode->as.list.nesting++;
- continue;
- }
-
- if (parser->current.end > parser->current.start) {
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // If we were unable to find a breakpoint, then this token hits the
- // end of the file.
- parser->current.end = parser->end;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
- case PM_LEX_REGEXP: {
- // First, we'll set to start of this token to be the current end.
- if (parser->next_start == NULL) {
- parser->current.start = parser->current.end;
- } else {
- parser->current.start = parser->next_start;
- parser->current.end = parser->next_start;
- parser->next_start = NULL;
- }
-
- // We'll check if we're at the end of the file. If we are, then we
- // need to return the EOF token.
- if (parser->current.end >= parser->end) {
- LEX(PM_TOKEN_EOF);
- }
-
- // Get a reference to the current mode.
- pm_lex_mode_t *lex_mode = parser->lex_modes.current;
-
- // These are the places where we need to split up the content of the
- // regular expression. We'll use strpbrk to find the first of these
- // characters.
- const uint8_t *breakpoints = lex_mode->as.regexp.breakpoints;
- const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
- pm_regexp_token_buffer_t token_buffer = { 0 };
-
- while (breakpoint != NULL) {
- // If we hit the terminator, we need to determine what kind of
- // token to return.
- if (*breakpoint == lex_mode->as.regexp.terminator) {
- if (lex_mode->as.regexp.nesting > 0) {
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
- lex_mode->as.regexp.nesting--;
- continue;
- }
-
- // Here we've hit the terminator. If we have already consumed
- // content then we need to return that content as string content
- // first.
- if (breakpoint > parser->current.start) {
- parser->current.end = breakpoint;
- pm_regexp_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // Check here if we need to track the newline.
- size_t eol_length = match_eol_at(parser, breakpoint);
- if (eol_length) {
- parser->current.end = breakpoint + eol_length;
- pm_newline_list_append(&parser->newline_list, parser->current.end - 1);
- } else {
- parser->current.end = breakpoint + 1;
- }
-
- // Since we've hit the terminator of the regular expression,
- // we now need to parse the options.
- parser->current.end += pm_strspn_regexp_option(parser->current.end, parser->end - parser->current.end);
-
- lex_mode_pop(parser);
- lex_state_set(parser, PM_LEX_STATE_END);
- LEX(PM_TOKEN_REGEXP_END);
- }
-
- // If we've hit the incrementor, then we need to skip past it
- // and find the next breakpoint.
- if (*breakpoint && *breakpoint == lex_mode->as.regexp.incrementor) {
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
- lex_mode->as.regexp.nesting++;
- continue;
- }
-
- switch (*breakpoint) {
- case '\0':
- // If we hit a null byte, skip directly past it.
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
- break;
- case '\r':
- if (peek_at(parser, breakpoint + 1) != '\n') {
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
- break;
- }
-
- breakpoint++;
- parser->current.end = breakpoint;
- pm_regexp_token_buffer_escape(parser, &token_buffer);
- token_buffer.base.cursor = breakpoint;
-
- /* fallthrough */
- case '\n':
- // If we've hit a newline, then we need to track that in
- // the list of newlines.
- if (parser->heredoc_end == NULL) {
- pm_newline_list_append(&parser->newline_list, breakpoint);
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
- break;
- }
-
- parser->current.end = breakpoint + 1;
- parser_flush_heredoc_end(parser);
- pm_regexp_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- case '\\': {
- // If we hit escapes, then we need to treat the next
- // token literally. In this case we'll skip past the
- // next character and find the next breakpoint.
- parser->current.end = breakpoint + 1;
-
- // If we've hit the end of the file, then break out of
- // the loop by setting the breakpoint to NULL.
- if (parser->current.end == parser->end) {
- breakpoint = NULL;
- break;
- }
-
- pm_regexp_token_buffer_escape(parser, &token_buffer);
- uint8_t peeked = peek(parser);
-
- switch (peeked) {
- case '\r':
- parser->current.end++;
- if (peek(parser) != '\n') {
- if (lex_mode->as.regexp.terminator != '\r') {
- pm_token_buffer_push_byte(&token_buffer.base, '\\');
- }
- pm_regexp_token_buffer_push_byte(&token_buffer, '\r');
- pm_token_buffer_push_byte(&token_buffer.base, '\r');
- break;
- }
- /* fallthrough */
- case '\n':
- if (parser->heredoc_end) {
- // ... if we are on the same line as a heredoc,
- // flush the heredoc and continue parsing after
- // heredoc_end.
- parser_flush_heredoc_end(parser);
- pm_regexp_token_buffer_copy(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- } else {
- // ... else track the newline.
- pm_newline_list_append(&parser->newline_list, parser->current.end);
- }
-
- parser->current.end++;
- break;
- case 'c':
- case 'C':
- case 'M':
- case 'u':
- case 'x':
- escape_read(parser, &token_buffer.regexp_buffer, &token_buffer.base.buffer, PM_ESCAPE_FLAG_REGEXP);
- break;
- default:
- if (lex_mode->as.regexp.terminator == peeked) {
- // Some characters when they are used as the
- // terminator also receive an escape. They are
- // enumerated here.
- switch (peeked) {
- case '$': case ')': case '*': case '+':
- case '.': case '>': case '?': case ']':
- case '^': case '|': case '}':
- pm_token_buffer_push_byte(&token_buffer.base, '\\');
- break;
- default:
- break;
- }
-
- pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
- pm_token_buffer_push_byte(&token_buffer.base, peeked);
- parser->current.end++;
- break;
- }
-
- if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.base, '\\');
- pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
- break;
- }
-
- token_buffer.base.cursor = parser->current.end;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
- break;
- }
- case '#': {
- // If we hit a #, then we will attempt to lex
- // interpolation.
- pm_token_type_t type = lex_interpolation(parser, breakpoint);
-
- if (type == PM_TOKEN_NOT_PROVIDED) {
- // If we haven't returned at this point then we had
- // something that looked like an interpolated class or
- // instance variable like "#@" but wasn't actually. In
- // this case we'll just skip to the next breakpoint.
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, false);
- break;
- }
-
- if (type == PM_TOKEN_STRING_CONTENT) {
- pm_regexp_token_buffer_flush(parser, &token_buffer);
- }
-
- LEX(type);
- }
- default:
- assert(false && "unreachable");
- break;
- }
- }
-
- if (parser->current.end > parser->current.start) {
- pm_regexp_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // If we were unable to find a breakpoint, then this token hits the
- // end of the file.
- parser->current.end = parser->end;
- pm_regexp_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
- case PM_LEX_STRING: {
- // First, we'll set to start of this token to be the current end.
- if (parser->next_start == NULL) {
- parser->current.start = parser->current.end;
- } else {
- parser->current.start = parser->next_start;
- parser->current.end = parser->next_start;
- parser->next_start = NULL;
- }
-
- // We'll check if we're at the end of the file. If we are, then we need to
- // return the EOF token.
- if (parser->current.end >= parser->end) {
- LEX(PM_TOKEN_EOF);
- }
-
- // These are the places where we need to split up the content of the
- // string. We'll use strpbrk to find the first of these characters.
- pm_lex_mode_t *lex_mode = parser->lex_modes.current;
- const uint8_t *breakpoints = lex_mode->as.string.breakpoints;
- const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
-
- // If we haven't found an escape yet, then this buffer will be
- // unallocated since we can refer directly to the source string.
- pm_token_buffer_t token_buffer = { 0 };
-
- while (breakpoint != NULL) {
- // If we hit the incrementor, then we'll increment then nesting and
- // continue lexing.
- if (lex_mode->as.string.incrementor != '\0' && *breakpoint == lex_mode->as.string.incrementor) {
- lex_mode->as.string.nesting++;
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- continue;
- }
-
- // Note that we have to check the terminator here first because we could
- // potentially be parsing a % string that has a # character as the
- // terminator.
- if (*breakpoint == lex_mode->as.string.terminator) {
- // If this terminator doesn't actually close the string, then we need
- // to continue on past it.
- if (lex_mode->as.string.nesting > 0) {
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- lex_mode->as.string.nesting--;
- continue;
- }
-
- // Here we've hit the terminator. If we have already consumed content
- // then we need to return that content as string content first.
- if (breakpoint > parser->current.start) {
- parser->current.end = breakpoint;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // Otherwise we need to switch back to the parent lex mode and
- // return the end of the string.
- size_t eol_length = match_eol_at(parser, breakpoint);
- if (eol_length) {
- parser->current.end = breakpoint + eol_length;
- pm_newline_list_append(&parser->newline_list, parser->current.end - 1);
- } else {
- parser->current.end = breakpoint + 1;
- }
-
- if (lex_mode->as.string.label_allowed && (peek(parser) == ':') && (peek_offset(parser, 1) != ':')) {
- parser->current.end++;
- lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
- lex_mode_pop(parser);
- LEX(PM_TOKEN_LABEL_END);
- }
-
- lex_state_set(parser, PM_LEX_STATE_END);
- lex_mode_pop(parser);
- LEX(PM_TOKEN_STRING_END);
- }
-
- switch (*breakpoint) {
- case '\0':
- // Skip directly past the null character.
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- break;
- case '\r':
- if (peek_at(parser, breakpoint + 1) != '\n') {
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- break;
- }
-
- // If we hit a \r\n sequence, then we need to treat it
- // as a newline.
- breakpoint++;
- parser->current.end = breakpoint;
- pm_token_buffer_escape(parser, &token_buffer);
- token_buffer.cursor = breakpoint;
-
- /* fallthrough */
- case '\n':
- // When we hit a newline, we need to flush any potential
- // heredocs. Note that this has to happen after we check
- // for the terminator in case the terminator is a
- // newline character.
- if (parser->heredoc_end == NULL) {
- pm_newline_list_append(&parser->newline_list, breakpoint);
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- break;
- }
-
- parser->current.end = breakpoint + 1;
- parser_flush_heredoc_end(parser);
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- case '\\': {
- // Here we hit escapes.
- parser->current.end = breakpoint + 1;
-
- // If we've hit the end of the file, then break out of
- // the loop by setting the breakpoint to NULL.
- if (parser->current.end == parser->end) {
- breakpoint = NULL;
- continue;
- }
-
- pm_token_buffer_escape(parser, &token_buffer);
- uint8_t peeked = peek(parser);
-
- switch (peeked) {
- case '\\':
- pm_token_buffer_push_byte(&token_buffer, '\\');
- parser->current.end++;
- break;
- case '\r':
- parser->current.end++;
- if (peek(parser) != '\n') {
- if (!lex_mode->as.string.interpolation) {
- pm_token_buffer_push_byte(&token_buffer, '\\');
- }
- pm_token_buffer_push_byte(&token_buffer, '\r');
- break;
- }
- /* fallthrough */
- case '\n':
- if (!lex_mode->as.string.interpolation) {
- pm_token_buffer_push_byte(&token_buffer, '\\');
- pm_token_buffer_push_byte(&token_buffer, '\n');
- }
-
- if (parser->heredoc_end) {
- // ... if we are on the same line as a heredoc,
- // flush the heredoc and continue parsing after
- // heredoc_end.
- parser_flush_heredoc_end(parser);
- pm_token_buffer_copy(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- } else {
- // ... else track the newline.
- pm_newline_list_append(&parser->newline_list, parser->current.end);
- }
-
- parser->current.end++;
- break;
- default:
- if (lex_mode->as.string.incrementor != '\0' && peeked == lex_mode->as.string.incrementor) {
- pm_token_buffer_push_byte(&token_buffer, peeked);
- parser->current.end++;
- } else if (lex_mode->as.string.terminator != '\0' && peeked == lex_mode->as.string.terminator) {
- pm_token_buffer_push_byte(&token_buffer, peeked);
- parser->current.end++;
- } else if (lex_mode->as.string.interpolation) {
- escape_read(parser, &token_buffer.buffer, NULL, PM_ESCAPE_FLAG_NONE);
- } else {
- pm_token_buffer_push_byte(&token_buffer, '\\');
- pm_token_buffer_push_escaped(&token_buffer, parser);
- }
-
- break;
- }
-
- token_buffer.cursor = parser->current.end;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- break;
- }
- case '#': {
- pm_token_type_t type = lex_interpolation(parser, breakpoint);
-
- if (type == PM_TOKEN_NOT_PROVIDED) {
- // If we haven't returned at this point then we had something that
- // looked like an interpolated class or instance variable like "#@"
- // but wasn't actually. In this case we'll just skip to the next
- // breakpoint.
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- break;
- }
-
- if (type == PM_TOKEN_STRING_CONTENT) {
- pm_token_buffer_flush(parser, &token_buffer);
- }
-
- LEX(type);
- }
- default:
- assert(false && "unreachable");
- }
- }
-
- if (parser->current.end > parser->current.start) {
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // If we've hit the end of the string, then this is an unterminated
- // string. In that case we'll return a string content token.
- parser->current.end = parser->end;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
- case PM_LEX_HEREDOC: {
- // First, we'll set to start of this token.
- if (parser->next_start == NULL) {
- parser->current.start = parser->current.end;
- } else {
- parser->current.start = parser->next_start;
- parser->current.end = parser->next_start;
- parser->heredoc_end = NULL;
- parser->next_start = NULL;
- }
-
- // Now let's grab the information about the identifier off of the
- // current lex mode.
- pm_lex_mode_t *lex_mode = parser->lex_modes.current;
- pm_heredoc_lex_mode_t *heredoc_lex_mode = &lex_mode->as.heredoc.base;
-
- bool line_continuation = lex_mode->as.heredoc.line_continuation;
- lex_mode->as.heredoc.line_continuation = false;
-
- // We'll check if we're at the end of the file. If we are, then we
- // will add an error (because we weren't able to find the
- // terminator) but still continue parsing so that content after the
- // declaration of the heredoc can be parsed.
- if (parser->current.end >= parser->end) {
- pm_parser_err_heredoc_term(parser, heredoc_lex_mode->ident_start, heredoc_lex_mode->ident_length);
- parser->next_start = lex_mode->as.heredoc.next_start;
- parser->heredoc_end = parser->current.end;
- lex_state_set(parser, PM_LEX_STATE_END);
- lex_mode_pop(parser);
- LEX(PM_TOKEN_HEREDOC_END);
- }
-
- const uint8_t *ident_start = heredoc_lex_mode->ident_start;
- size_t ident_length = heredoc_lex_mode->ident_length;
-
- // If we are immediately following a newline and we have hit the
- // terminator, then we need to return the ending of the heredoc.
- if (current_token_starts_line(parser)) {
- const uint8_t *start = parser->current.start;
-
- if (!line_continuation && (start + ident_length <= parser->end)) {
- const uint8_t *newline = next_newline(start, parser->end - start);
- const uint8_t *ident_end = newline;
- const uint8_t *terminator_end = newline;
-
- if (newline == NULL) {
- terminator_end = parser->end;
- ident_end = parser->end;
- } else {
- terminator_end++;
- if (newline[-1] == '\r') {
- ident_end--; // Remove \r
- }
- }
-
- const uint8_t *terminator_start = ident_end - ident_length;
- const uint8_t *cursor = start;
-
- if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
- while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
- cursor++;
- }
- }
-
- if (
- (cursor == terminator_start) &&
- (memcmp(terminator_start, ident_start, ident_length) == 0)
- ) {
- if (newline != NULL) {
- pm_newline_list_append(&parser->newline_list, newline);
- }
-
- parser->current.end = terminator_end;
- if (*lex_mode->as.heredoc.next_start == '\\') {
- parser->next_start = NULL;
- } else {
- parser->next_start = lex_mode->as.heredoc.next_start;
- parser->heredoc_end = parser->current.end;
- }
-
- lex_state_set(parser, PM_LEX_STATE_END);
- lex_mode_pop(parser);
- LEX(PM_TOKEN_HEREDOC_END);
- }
- }
-
- size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->indent);
- if (
- heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE &&
- lex_mode->as.heredoc.common_whitespace != NULL &&
- (*lex_mode->as.heredoc.common_whitespace > whitespace) &&
- peek_at(parser, start) != '\n'
- ) {
- *lex_mode->as.heredoc.common_whitespace = whitespace;
- }
- }
-
- // Otherwise we'll be parsing string content. These are the places
- // where we need to split up the content of the heredoc. We'll use
- // strpbrk to find the first of these characters.
- uint8_t breakpoints[] = "\r\n\\#";
-
- pm_heredoc_quote_t quote = heredoc_lex_mode->quote;
- if (quote == PM_HEREDOC_QUOTE_SINGLE) {
- breakpoints[3] = '\0';
- }
-
- const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- pm_token_buffer_t token_buffer = { 0 };
- bool was_line_continuation = false;
-
- while (breakpoint != NULL) {
- switch (*breakpoint) {
- case '\0':
- // Skip directly past the null character.
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- break;
- case '\r':
- parser->current.end = breakpoint + 1;
-
- if (peek_at(parser, breakpoint + 1) != '\n') {
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- break;
- }
-
- // If we hit a \r\n sequence, then we want to replace it
- // with a single \n character in the final string.
- breakpoint++;
- pm_token_buffer_escape(parser, &token_buffer);
- token_buffer.cursor = breakpoint;
-
- /* fallthrough */
- case '\n': {
- if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
- parser_flush_heredoc_end(parser);
- parser->current.end = breakpoint + 1;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- pm_newline_list_append(&parser->newline_list, breakpoint);
-
- // If we have a - or ~ heredoc, then we can match after
- // some leading whitespace.
- const uint8_t *start = breakpoint + 1;
-
- if (!was_line_continuation && (start + ident_length <= parser->end)) {
- // We want to match the terminator starting from the end of the line in case
- // there is whitespace in the ident such as <<-' DOC' or <<~' DOC'.
- const uint8_t *newline = next_newline(start, parser->end - start);
-
- if (newline == NULL) {
- newline = parser->end;
- } else if (newline[-1] == '\r') {
- newline--; // Remove \r
- }
-
- // Start of a possible terminator.
- const uint8_t *terminator_start = newline - ident_length;
-
- // Cursor to check for the leading whitespace. We skip the
- // leading whitespace if we have a - or ~ heredoc.
- const uint8_t *cursor = start;
-
- if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
- while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
- cursor++;
- }
- }
-
- if (
- cursor == terminator_start &&
- (memcmp(terminator_start, ident_start, ident_length) == 0)
- ) {
- parser->current.end = breakpoint + 1;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
- }
-
- size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.base.indent);
-
- // If we have hit a newline that is followed by a valid
- // terminator, then we need to return the content of the
- // heredoc here as string content. Then, the next time a
- // token is lexed, it will match again and return the
- // end of the heredoc.
- if (lex_mode->as.heredoc.base.indent == PM_HEREDOC_INDENT_TILDE) {
- if ((lex_mode->as.heredoc.common_whitespace != NULL) && (*lex_mode->as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) != '\n') {
- *lex_mode->as.heredoc.common_whitespace = whitespace;
- }
-
- parser->current.end = breakpoint + 1;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // Otherwise we hit a newline and it wasn't followed by
- // a terminator, so we can continue parsing.
- parser->current.end = breakpoint + 1;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- break;
- }
- case '\\': {
- // If we hit an escape, then we need to skip past
- // however many characters the escape takes up. However
- // it's important that if \n or \r\n are escaped, we
- // stop looping before the newline and not after the
- // newline so that we can still potentially find the
- // terminator of the heredoc.
- parser->current.end = breakpoint + 1;
-
- // If we've hit the end of the file, then break out of
- // the loop by setting the breakpoint to NULL.
- if (parser->current.end == parser->end) {
- breakpoint = NULL;
- continue;
- }
-
- pm_token_buffer_escape(parser, &token_buffer);
- uint8_t peeked = peek(parser);
-
- if (quote == PM_HEREDOC_QUOTE_SINGLE) {
- switch (peeked) {
- case '\r':
- parser->current.end++;
- if (peek(parser) != '\n') {
- pm_token_buffer_push_byte(&token_buffer, '\\');
- pm_token_buffer_push_byte(&token_buffer, '\r');
- break;
- }
- /* fallthrough */
- case '\n':
- pm_token_buffer_push_byte(&token_buffer, '\\');
- pm_token_buffer_push_byte(&token_buffer, '\n');
- token_buffer.cursor = parser->current.end + 1;
- breakpoint = parser->current.end;
- continue;
- default:
- pm_token_buffer_push_byte(&token_buffer, '\\');
- pm_token_buffer_push_escaped(&token_buffer, parser);
- break;
- }
- } else {
- switch (peeked) {
- case '\r':
- parser->current.end++;
- if (peek(parser) != '\n') {
- pm_token_buffer_push_byte(&token_buffer, '\r');
- break;
- }
- /* fallthrough */
- case '\n':
- // If we are in a tilde here, we should
- // break out of the loop and return the
- // string content.
- if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
- const uint8_t *end = parser->current.end;
- pm_newline_list_append(&parser->newline_list, end);
-
- // Here we want the buffer to only
- // include up to the backslash.
- parser->current.end = breakpoint;
- pm_token_buffer_flush(parser, &token_buffer);
-
- // Now we can advance the end of the
- // token past the newline.
- parser->current.end = end + 1;
- lex_mode->as.heredoc.line_continuation = true;
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- was_line_continuation = true;
- token_buffer.cursor = parser->current.end + 1;
- breakpoint = parser->current.end;
- continue;
- default:
- escape_read(parser, &token_buffer.buffer, NULL, PM_ESCAPE_FLAG_NONE);
- break;
- }
- }
-
- token_buffer.cursor = parser->current.end;
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- break;
- }
- case '#': {
- pm_token_type_t type = lex_interpolation(parser, breakpoint);
-
- if (type == PM_TOKEN_NOT_PROVIDED) {
- // If we haven't returned at this point then we had
- // something that looked like an interpolated class
- // or instance variable like "#@" but wasn't
- // actually. In this case we'll just skip to the
- // next breakpoint.
- breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end, true);
- break;
- }
-
- if (type == PM_TOKEN_STRING_CONTENT) {
- pm_token_buffer_flush(parser, &token_buffer);
- }
-
- LEX(type);
- }
- default:
- assert(false && "unreachable");
- }
-
- was_line_continuation = false;
- }
-
- if (parser->current.end > parser->current.start) {
- parser->current.end = parser->end;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
-
- // If we've hit the end of the string, then this is an unterminated
- // heredoc. In that case we'll return a string content token.
- parser->current.end = parser->end;
- pm_token_buffer_flush(parser, &token_buffer);
- LEX(PM_TOKEN_STRING_CONTENT);
- }
- }
-
- assert(false && "unreachable");
-}
-
-#undef LEX
-
-/******************************************************************************/
-/* Parse functions */
-/******************************************************************************/
-
-/**
- * These are the various precedence rules. Because we are using a Pratt parser,
- * they are named binding power to represent the manner in which nodes are bound
- * together in the stack.
- *
- * We increment by 2 because we want to leave room for the infix operators to
- * specify their associativity by adding or subtracting one.
- */
-typedef enum {
- PM_BINDING_POWER_UNSET = 0, // used to indicate this token cannot be used as an infix operator
- PM_BINDING_POWER_STATEMENT = 2,
- PM_BINDING_POWER_MODIFIER_RESCUE = 4, // rescue
- PM_BINDING_POWER_MODIFIER = 6, // if unless until while
- PM_BINDING_POWER_COMPOSITION = 8, // and or
- PM_BINDING_POWER_NOT = 10, // not
- PM_BINDING_POWER_MATCH = 12, // => in
- PM_BINDING_POWER_DEFINED = 14, // defined?
- PM_BINDING_POWER_MULTI_ASSIGNMENT = 16, // =
- PM_BINDING_POWER_ASSIGNMENT = 18, // = += -= *= /= %= &= |= ^= &&= ||= <<= >>= **=
- PM_BINDING_POWER_TERNARY = 20, // ?:
- PM_BINDING_POWER_RANGE = 22, // .. ...
- PM_BINDING_POWER_LOGICAL_OR = 24, // ||
- PM_BINDING_POWER_LOGICAL_AND = 26, // &&
- PM_BINDING_POWER_EQUALITY = 28, // <=> == === != =~ !~
- PM_BINDING_POWER_COMPARISON = 30, // > >= < <=
- PM_BINDING_POWER_BITWISE_OR = 32, // | ^
- PM_BINDING_POWER_BITWISE_AND = 34, // &
- PM_BINDING_POWER_SHIFT = 36, // << >>
- PM_BINDING_POWER_TERM = 38, // + -
- PM_BINDING_POWER_FACTOR = 40, // * / %
- PM_BINDING_POWER_UMINUS = 42, // -@
- PM_BINDING_POWER_EXPONENT = 44, // **
- PM_BINDING_POWER_UNARY = 46, // ! ~ +@
- PM_BINDING_POWER_INDEX = 48, // [] []=
- PM_BINDING_POWER_CALL = 50, // :: .
- PM_BINDING_POWER_MAX = 52
-} pm_binding_power_t;
-
-/**
- * This struct represents a set of binding powers used for a given token. They
- * are combined in this way to make it easier to represent associativity.
- */
-typedef struct {
- /** The left binding power. */
- pm_binding_power_t left;
-
- /** The right binding power. */
- pm_binding_power_t right;
-
- /** Whether or not this token can be used as a binary operator. */
- bool binary;
-
- /**
- * Whether or not this token can be used as non-associative binary operator.
- * Non-associative operators (e.g. in and =>) need special treatment in parse_expression.
- */
- bool nonassoc;
-} pm_binding_powers_t;
-
-#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
-#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
-#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
-#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
-#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
-
-pm_binding_powers_t pm_binding_powers[PM_TOKEN_MAXIMUM] = {
- // rescue
- [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER_RESCUE),
-
- // if unless until while
- [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
- [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
- [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
- [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
-
- // and or
- [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
- [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
-
- // => in
- [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
- [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
-
- // &&= &= ^= = >>= <<= -= %= |= ||= += /= *= **=
- [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
- [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
-
- // ?:
- [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
-
- // .. ...
- [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
- [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
- [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
- [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
-
- // ||
- [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
-
- // &&
- [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
-
- // != !~ == === =~ <=>
- [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
- [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
-
- // > >= < <=
- [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
- [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
- [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
- [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
-
- // ^ |
- [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
- [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
-
- // &
- [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
-
- // >> <<
- [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
- [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
-
- // - +
- [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
- [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
-
- // % / *
- [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
- [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
- [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
- [PM_TOKEN_USTAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
-
- // -@
- [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
- [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX, false, false },
-
- // **
- [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
- [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
-
- // ! ~ +@
- [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
- [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
- [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
-
- // [
- [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
-
- // :: . &.
- [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
- [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
- [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
-};
-
-#undef BINDING_POWER_ASSIGNMENT
-#undef LEFT_ASSOCIATIVE
-#undef RIGHT_ASSOCIATIVE
-#undef RIGHT_ASSOCIATIVE_UNARY
-
-/**
- * Returns true if the current token is of the given type.
- */
-static inline bool
-match1(const pm_parser_t *parser, pm_token_type_t type) {
- return parser->current.type == type;
-}
-
-/**
- * Returns true if the current token is of either of the given types.
- */
-static inline bool
-match2(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
- return match1(parser, type1) || match1(parser, type2);
-}
-
-/**
- * Returns true if the current token is any of the three given types.
- */
-static inline bool
-match3(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
- return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
-}
-
-/**
- * Returns true if the current token is any of the four given types.
- */
-static inline bool
-match4(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4) {
- return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
-}
-
-/**
- * Returns true if the current token is any of the six given types.
- */
-static inline bool
-match6(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6) {
- return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6);
-}
-
-/**
- * Returns true if the current token is any of the seven given types.
- */
-static inline bool
-match7(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6, pm_token_type_t type7) {
- return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
-}
-
-/**
- * Returns true if the current token is any of the eight given types.
- */
-static inline bool
-match8(const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6, pm_token_type_t type7, pm_token_type_t type8) {
- return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7) || match1(parser, type8);
-}
-
-/**
- * If the current token is of the specified type, lex forward by one token and
- * return true. Otherwise, return false. For example:
- *
- * if (accept1(parser, PM_TOKEN_COLON)) { ... }
- */
-static bool
-accept1(pm_parser_t *parser, pm_token_type_t type) {
- if (match1(parser, type)) {
- parser_lex(parser);
- return true;
- }
- return false;
-}
-
-/**
- * If the current token is either of the two given types, lex forward by one
- * token and return true. Otherwise return false.
- */
-static inline bool
-accept2(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
- if (match2(parser, type1, type2)) {
- parser_lex(parser);
- return true;
- }
- return false;
-}
-
-/**
- * If the current token is any of the three given types, lex forward by one
- * token and return true. Otherwise return false.
- */
-static inline bool
-accept3(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
- if (match3(parser, type1, type2, type3)) {
- parser_lex(parser);
- return true;
- }
- return false;
-}
-
-/**
- * This function indicates that the parser expects a token in a specific
- * position. For example, if you're parsing a BEGIN block, you know that a { is
- * expected immediately after the keyword. In that case you would call this
- * function to indicate that that token should be found.
- *
- * If we didn't find the token that we were expecting, then we're going to add
- * an error to the parser's list of errors (to indicate that the tree is not
- * valid) and create an artificial token instead. This allows us to recover from
- * the fact that the token isn't present and continue parsing.
- */
-static void
-expect1(pm_parser_t *parser, pm_token_type_t type, pm_diagnostic_id_t diag_id) {
- if (accept1(parser, type)) return;
-
- const uint8_t *location = parser->previous.end;
- pm_parser_err(parser, location, location, diag_id);
-
- parser->previous.start = location;
- parser->previous.type = PM_TOKEN_MISSING;
-}
-
-/**
- * This function is the same as expect1, but it expects either of two token
- * types.
- */
-static void
-expect2(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_diagnostic_id_t diag_id) {
- if (accept2(parser, type1, type2)) return;
-
- const uint8_t *location = parser->previous.end;
- pm_parser_err(parser, location, location, diag_id);
-
- parser->previous.start = location;
- parser->previous.type = PM_TOKEN_MISSING;
-}
-
-/**
- * This function is the same as expect2, but it expects one of three token types.
- */
-static void
-expect3(pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_diagnostic_id_t diag_id) {
- if (accept3(parser, type1, type2, type3)) return;
-
- const uint8_t *location = parser->previous.end;
- pm_parser_err(parser, location, location, diag_id);
-
- parser->previous.start = location;
- parser->previous.type = PM_TOKEN_MISSING;
-}
-
-/**
- * A special expect1 that expects a heredoc terminator and handles popping the
- * lex mode accordingly.
- */
-static void
-expect1_heredoc_term(pm_parser_t *parser, const uint8_t *ident_start, size_t ident_length) {
- if (match1(parser, PM_TOKEN_HEREDOC_END)) {
- parser_lex(parser);
- } else {
- pm_parser_err_heredoc_term(parser, ident_start, ident_length);
- parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
- }
-}
-
-static pm_node_t *
-parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth);
-
-/**
- * This is a wrapper of parse_expression, which also checks whether the
- * resulting node is a value expression.
- */
-static pm_node_t *
-parse_value_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth) {
- pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
- pm_assert_value_expression(parser, node);
- return node;
-}
-
-/**
- * This function controls whether or not we will attempt to parse an expression
- * beginning at the subsequent token. It is used when we are in a context where
- * an expression is optional.
- *
- * For example, looking at a range object when we've already lexed the operator,
- * we need to know if we should attempt to parse an expression on the right.
- *
- * For another example, if we've parsed an identifier or a method call and we do
- * not have parentheses, then the next token may be the start of an argument or
- * it may not.
- *
- * CRuby parsers that are generated would resolve this by using a lookahead and
- * potentially backtracking. We attempt to do this by just looking at the next
- * token and making a decision based on that. I am not sure if this is going to
- * work in all cases, it may need to be refactored later. But it appears to work
- * for now.
- */
-static inline bool
-token_begins_expression_p(pm_token_type_t type) {
- switch (type) {
- case PM_TOKEN_EQUAL_GREATER:
- case PM_TOKEN_KEYWORD_IN:
- // We need to special case this because it is a binary operator that
- // should not be marked as beginning an expression.
- return false;
- case PM_TOKEN_BRACE_RIGHT:
- case PM_TOKEN_BRACKET_RIGHT:
- case PM_TOKEN_COLON:
- case PM_TOKEN_COMMA:
- case PM_TOKEN_EMBEXPR_END:
- case PM_TOKEN_EOF:
- case PM_TOKEN_LAMBDA_BEGIN:
- case PM_TOKEN_KEYWORD_DO:
- case PM_TOKEN_KEYWORD_DO_LOOP:
- case PM_TOKEN_KEYWORD_END:
- case PM_TOKEN_KEYWORD_ELSE:
- case PM_TOKEN_KEYWORD_ELSIF:
- case PM_TOKEN_KEYWORD_ENSURE:
- case PM_TOKEN_KEYWORD_THEN:
- case PM_TOKEN_KEYWORD_RESCUE:
- case PM_TOKEN_KEYWORD_WHEN:
- case PM_TOKEN_NEWLINE:
- case PM_TOKEN_PARENTHESIS_RIGHT:
- case PM_TOKEN_SEMICOLON:
- // The reason we need this short-circuit is because we're using the
- // binding powers table to tell us if the subsequent token could
- // potentially be the start of an expression. If there _is_ a binding
- // power for one of these tokens, then we should remove it from this list
- // and let it be handled by the default case below.
- assert(pm_binding_powers[type].left == PM_BINDING_POWER_UNSET);
- return false;
- case PM_TOKEN_UAMPERSAND:
- // This is a special case because this unary operator cannot appear
- // as a general operator, it only appears in certain circumstances.
- return false;
- case PM_TOKEN_UCOLON_COLON:
- case PM_TOKEN_UMINUS:
- case PM_TOKEN_UMINUS_NUM:
- case PM_TOKEN_UPLUS:
- case PM_TOKEN_BANG:
- case PM_TOKEN_TILDE:
- case PM_TOKEN_UDOT_DOT:
- case PM_TOKEN_UDOT_DOT_DOT:
- // These unary tokens actually do have binding power associated with them
- // so that we can correctly place them into the precedence order. But we
- // want them to be marked as beginning an expression, so we need to
- // special case them here.
- return true;
- default:
- return pm_binding_powers[type].left == PM_BINDING_POWER_UNSET;
- }
-}
-
-/**
- * Parse an expression with the given binding power that may be optionally
- * prefixed by the * operator.
- */
-static pm_node_t *
-parse_starred_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id, uint16_t depth) {
- if (accept1(parser, PM_TOKEN_USTAR)) {
- pm_token_t operator = parser->previous;
- pm_node_t *expression = parse_value_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
- }
-
- return parse_value_expression(parser, binding_power, accepts_command_call, false, diag_id, depth);
-}
-
-/**
- * Convert the name of a method into the corresponding write method name. For
- * example, foo would be turned into foo=.
- */
-static void
-parse_write_name(pm_parser_t *parser, pm_constant_id_t *name_field) {
- // The method name needs to change. If we previously had
- // foo, we now need foo=. In this case we'll allocate a new
- // owned string, copy the previous method name in, and
- // append an =.
- pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *name_field);
- size_t length = constant->length;
- uint8_t *name = xcalloc(length + 1, sizeof(uint8_t));
- if (name == NULL) return;
-
- memcpy(name, constant->start, length);
- name[length] = '=';
-
- // Now switch the name to the new string.
- // This silences clang analyzer warning about leak of memory pointed by `name`.
- // NOLINTNEXTLINE(clang-analyzer-*)
- *name_field = pm_constant_pool_insert_owned(&parser->constant_pool, name, length + 1);
-}
-
-/**
- * Certain expressions are not targetable, but in order to provide a better
- * experience we give a specific error message. In order to maintain as much
- * information in the tree as possible, we replace them with local variable
- * writes.
- */
-static pm_node_t *
-parse_unwriteable_target(pm_parser_t *parser, pm_node_t *target) {
- switch (PM_NODE_TYPE(target)) {
- case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING); break;
- case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE); break;
- case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE); break;
- case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE); break;
- case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL); break;
- case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF); break;
- case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE); break;
- default: break;
- }
-
- pm_constant_id_t name = pm_parser_constant_id_location(parser, target->location.start, target->location.end);
- pm_local_variable_target_node_t *result = pm_local_variable_target_node_create(parser, &target->location, name, 0);
-
- pm_node_destroy(parser, target);
- return (pm_node_t *) result;
-}
-
-/**
- * When an implicit local variable is written to or targeted, it becomes a
- * regular, named local variable. This function removes it from the list of
- * implicit parameters when that happens.
- */
-static void
-parse_target_implicit_parameter(pm_parser_t *parser, pm_node_t *node) {
- pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
-
- for (size_t index = 0; index < implicit_parameters->size; index++) {
- if (implicit_parameters->nodes[index] == node) {
- // If the node is not the last one in the list, we need to shift the
- // remaining nodes down to fill the gap. This is extremely unlikely
- // to happen.
- if (index != implicit_parameters->size - 1) {
- memcpy(&implicit_parameters->nodes[index], &implicit_parameters->nodes[index + 1], (implicit_parameters->size - index - 1) * sizeof(pm_node_t *));
- }
-
- implicit_parameters->size--;
- break;
- }
- }
-}
-
-/**
- * Convert the given node into a valid target node.
- *
- * @param multiple Whether or not this target is part of a larger set of
- * targets. If it is, then the &. operator is not allowed.
- * @param splat Whether or not this target is a child of a splat target. If it
- * is, then fewer patterns are allowed.
- */
-static pm_node_t *
-parse_target(pm_parser_t *parser, pm_node_t *target, bool multiple, bool splat_parent) {
- switch (PM_NODE_TYPE(target)) {
- case PM_MISSING_NODE:
- return target;
- case PM_SOURCE_ENCODING_NODE:
- case PM_FALSE_NODE:
- case PM_SOURCE_FILE_NODE:
- case PM_SOURCE_LINE_NODE:
- case PM_NIL_NODE:
- case PM_SELF_NODE:
- case PM_TRUE_NODE: {
- // In these special cases, we have specific error messages and we
- // will replace them with local variable writes.
- return parse_unwriteable_target(parser, target);
- }
- case PM_CLASS_VARIABLE_READ_NODE:
- assert(sizeof(pm_class_variable_target_node_t) == sizeof(pm_class_variable_read_node_t));
- target->type = PM_CLASS_VARIABLE_TARGET_NODE;
- return target;
- case PM_CONSTANT_PATH_NODE:
- if (context_def_p(parser)) {
- pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
- }
-
- assert(sizeof(pm_constant_path_target_node_t) == sizeof(pm_constant_path_node_t));
- target->type = PM_CONSTANT_PATH_TARGET_NODE;
-
- return target;
- case PM_CONSTANT_READ_NODE:
- if (context_def_p(parser)) {
- pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
- }
-
- assert(sizeof(pm_constant_target_node_t) == sizeof(pm_constant_read_node_t));
- target->type = PM_CONSTANT_TARGET_NODE;
-
- return target;
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
- return target;
- case PM_GLOBAL_VARIABLE_READ_NODE:
- assert(sizeof(pm_global_variable_target_node_t) == sizeof(pm_global_variable_read_node_t));
- target->type = PM_GLOBAL_VARIABLE_TARGET_NODE;
- return target;
- case PM_LOCAL_VARIABLE_READ_NODE: {
- if (pm_token_is_numbered_parameter(target->location.start, target->location.end)) {
- PM_PARSER_ERR_FORMAT(parser, target->location.start, target->location.end, PM_ERR_PARAMETER_NUMBERED_RESERVED, target->location.start);
- parse_target_implicit_parameter(parser, target);
- }
-
- const pm_local_variable_read_node_t *cast = (const pm_local_variable_read_node_t *) target;
- uint32_t name = cast->name;
- uint32_t depth = cast->depth;
- pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
-
- assert(sizeof(pm_local_variable_target_node_t) == sizeof(pm_local_variable_read_node_t));
- target->type = PM_LOCAL_VARIABLE_TARGET_NODE;
-
- return target;
- }
- case PM_IT_LOCAL_VARIABLE_READ_NODE: {
- pm_constant_id_t name = pm_parser_local_add_constant(parser, "it", 2);
- pm_node_t *node = (pm_node_t *) pm_local_variable_target_node_create(parser, &target->location, name, 0);
-
- parse_target_implicit_parameter(parser, target);
- pm_node_destroy(parser, target);
-
- return node;
- }
- case PM_INSTANCE_VARIABLE_READ_NODE:
- assert(sizeof(pm_instance_variable_target_node_t) == sizeof(pm_instance_variable_read_node_t));
- target->type = PM_INSTANCE_VARIABLE_TARGET_NODE;
- return target;
- case PM_MULTI_TARGET_NODE:
- if (splat_parent) {
- // Multi target is not accepted in all positions. If this is one
- // of them, then we need to add an error.
- pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
-
- return target;
- case PM_SPLAT_NODE: {
- pm_splat_node_t *splat = (pm_splat_node_t *) target;
-
- if (splat->expression != NULL) {
- splat->expression = parse_target(parser, splat->expression, multiple, true);
- }
-
- return (pm_node_t *) splat;
- }
- case PM_CALL_NODE: {
- pm_call_node_t *call = (pm_call_node_t *) target;
-
- // If we have no arguments to the call node and we need this to be a
- // target then this is either a method call or a local variable
- // write.
- if (
- (call->message_loc.start != NULL) &&
- (call->message_loc.end[-1] != '!') &&
- (call->message_loc.end[-1] != '?') &&
- (call->opening_loc.start == NULL) &&
- (call->arguments == NULL) &&
- (call->block == NULL)
- ) {
- if (call->receiver == NULL) {
- // When we get here, we have a local variable write, because it
- // was previously marked as a method call but now we have an =.
- // This looks like:
- //
- // foo = 1
- //
- // When it was parsed in the prefix position, foo was seen as a
- // method call with no receiver and no arguments. Now we have an
- // =, so we know it's a local variable write.
- const pm_location_t message_loc = call->message_loc;
-
- pm_constant_id_t name = pm_parser_local_add_location(parser, message_loc.start, message_loc.end, 0);
- pm_node_destroy(parser, target);
-
- return (pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
- }
-
- if (*call->message_loc.start == '_' || parser->encoding->alnum_char(call->message_loc.start, call->message_loc.end - call->message_loc.start)) {
- if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- pm_parser_err_node(parser, (const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
- }
-
- parse_write_name(parser, &call->name);
- return (pm_node_t *) pm_call_target_node_create(parser, call);
- }
- }
-
- // If there is no call operator and the message is "[]" then this is
- // an aref expression, and we can transform it into an aset
- // expression.
- if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
- return (pm_node_t *) pm_index_target_node_create(parser, call);
- }
- }
- /* fallthrough */
- default:
- // In this case we have a node that we don't know how to convert
- // into a target. We need to treat it as an error. For now, we'll
- // mark it as an error and just skip right past it.
- pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
- return target;
- }
-}
-
-/**
- * Parse a write target and validate that it is in a valid position for
- * assignment.
- */
-static pm_node_t *
-parse_target_validate(pm_parser_t *parser, pm_node_t *target, bool multiple) {
- pm_node_t *result = parse_target(parser, target, multiple, false);
-
- // Ensure that we have one of an =, an 'in' in for indexes, and a ')' in
- // parens after the targets.
- if (
- !match1(parser, PM_TOKEN_EQUAL) &&
- !(context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) &&
- !(context_p(parser, PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
- ) {
- pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
-
- return result;
-}
-
-/**
- * Potentially wrap a constant write node in a shareable constant node depending
- * on the current state.
- */
-static pm_node_t *
-parse_shareable_constant_write(pm_parser_t *parser, pm_node_t *write) {
- pm_shareable_constant_value_t shareable_constant = pm_parser_scope_shareable_constant_get(parser);
-
- if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
- return (pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
- }
-
- return write;
-}
-
-/**
- * Convert the given node into a valid write node.
- */
-static pm_node_t *
-parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_node_t *value) {
- switch (PM_NODE_TYPE(target)) {
- case PM_MISSING_NODE:
- pm_node_destroy(parser, value);
- return target;
- case PM_CLASS_VARIABLE_READ_NODE: {
- pm_class_variable_write_node_t *node = pm_class_variable_write_node_create(parser, (pm_class_variable_read_node_t *) target, operator, value);
- pm_node_destroy(parser, target);
- return (pm_node_t *) node;
- }
- case PM_CONSTANT_PATH_NODE: {
- pm_node_t *node = (pm_node_t *) pm_constant_path_write_node_create(parser, (pm_constant_path_node_t *) target, operator, value);
-
- if (context_def_p(parser)) {
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
- }
-
- return parse_shareable_constant_write(parser, node);
- }
- case PM_CONSTANT_READ_NODE: {
- pm_node_t *node = (pm_node_t *) pm_constant_write_node_create(parser, (pm_constant_read_node_t *) target, operator, value);
-
- if (context_def_p(parser)) {
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
- }
-
- pm_node_destroy(parser, target);
- return parse_shareable_constant_write(parser, node);
- }
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
- /* fallthrough */
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- pm_global_variable_write_node_t *node = pm_global_variable_write_node_create(parser, target, operator, value);
- pm_node_destroy(parser, target);
- return (pm_node_t *) node;
- }
- case PM_LOCAL_VARIABLE_READ_NODE: {
- pm_local_variable_read_node_t *local_read = (pm_local_variable_read_node_t *) target;
-
- pm_constant_id_t name = local_read->name;
- pm_location_t name_loc = target->location;
-
- uint32_t depth = local_read->depth;
- pm_scope_t *scope = pm_parser_scope_find(parser, depth);
-
- if (pm_token_is_numbered_parameter(target->location.start, target->location.end)) {
- pm_diagnostic_id_t diag_id = (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
- PM_PARSER_ERR_FORMAT(parser, target->location.start, target->location.end, diag_id, target->location.start);
- parse_target_implicit_parameter(parser, target);
- }
-
- pm_locals_unread(&scope->locals, name);
- pm_node_destroy(parser, target);
-
- return (pm_node_t *) pm_local_variable_write_node_create(parser, name, depth, value, &name_loc, operator);
- }
- case PM_IT_LOCAL_VARIABLE_READ_NODE: {
- pm_constant_id_t name = pm_parser_local_add_constant(parser, "it", 2);
- pm_node_t *node = (pm_node_t *) pm_local_variable_write_node_create(parser, name, 0, value, &target->location, operator);
-
- parse_target_implicit_parameter(parser, target);
- pm_node_destroy(parser, target);
-
- return node;
- }
- case PM_INSTANCE_VARIABLE_READ_NODE: {
- pm_node_t *write_node = (pm_node_t *) pm_instance_variable_write_node_create(parser, (pm_instance_variable_read_node_t *) target, operator, value);
- pm_node_destroy(parser, target);
- return write_node;
- }
- case PM_MULTI_TARGET_NODE:
- return (pm_node_t *) pm_multi_write_node_create(parser, (pm_multi_target_node_t *) target, operator, value);
- case PM_SPLAT_NODE: {
- pm_splat_node_t *splat = (pm_splat_node_t *) target;
-
- if (splat->expression != NULL) {
- splat->expression = parse_write(parser, splat->expression, operator, value);
- }
-
- pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
- pm_multi_target_node_targets_append(parser, multi_target, (pm_node_t *) splat);
-
- return (pm_node_t *) pm_multi_write_node_create(parser, multi_target, operator, value);
- }
- case PM_CALL_NODE: {
- pm_call_node_t *call = (pm_call_node_t *) target;
-
- // If we have no arguments to the call node and we need this to be a
- // target then this is either a method call or a local variable
- // write.
- if (
- (call->message_loc.start != NULL) &&
- (call->message_loc.end[-1] != '!') &&
- (call->message_loc.end[-1] != '?') &&
- (call->opening_loc.start == NULL) &&
- (call->arguments == NULL) &&
- (call->block == NULL)
- ) {
- if (call->receiver == NULL) {
- // When we get here, we have a local variable write, because it
- // was previously marked as a method call but now we have an =.
- // This looks like:
- //
- // foo = 1
- //
- // When it was parsed in the prefix position, foo was seen as a
- // method call with no receiver and no arguments. Now we have an
- // =, so we know it's a local variable write.
- const pm_location_t message = call->message_loc;
-
- pm_parser_local_add_location(parser, message.start, message.end, 0);
- pm_node_destroy(parser, target);
-
- pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, message.start, message.end);
- target = (pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, 0, value, &message, operator);
-
- pm_refute_numbered_parameter(parser, message.start, message.end);
- return target;
- }
-
- if (char_is_identifier_start(parser, call->message_loc.start)) {
- // When we get here, we have a method call, because it was
- // previously marked as a method call but now we have an =. This
- // looks like:
- //
- // foo.bar = 1
- //
- // When it was parsed in the prefix position, foo.bar was seen as a
- // method call with no arguments. Now we have an =, so we know it's
- // a method call with an argument. In this case we will create the
- // arguments node, parse the argument, and add it to the list.
- pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
- call->arguments = arguments;
-
- pm_arguments_node_arguments_append(arguments, value);
- call->base.location.end = arguments->base.location.end;
-
- parse_write_name(parser, &call->name);
- pm_node_flag_set((pm_node_t *) call, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
-
- return (pm_node_t *) call;
- }
- }
-
- // If there is no call operator and the message is "[]" then this is
- // an aref expression, and we can transform it into an aset
- // expression.
- if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
- if (call->arguments == NULL) {
- call->arguments = pm_arguments_node_create(parser);
- }
-
- pm_arguments_node_arguments_append(call->arguments, value);
- target->location.end = value->location.end;
-
- // Replace the name with "[]=".
- call->name = pm_parser_constant_id_constant(parser, "[]=", 3);
- pm_node_flag_set((pm_node_t *) call, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
-
- return target;
- }
-
- // If there are arguments on the call node, then it can't be a method
- // call ending with = or a local variable write, so it must be a
- // syntax error. In this case we'll fall through to our default
- // handling. We need to free the value that we parsed because there
- // is no way for us to attach it to the tree at this point.
- pm_node_destroy(parser, value);
- }
- /* fallthrough */
- default:
- // In this case we have a node that we don't know how to convert into a
- // target. We need to treat it as an error. For now, we'll mark it as an
- // error and just skip right past it.
- pm_parser_err_token(parser, operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
- return target;
- }
-}
-
-/**
- * Certain expressions are not writable, but in order to provide a better
- * experience we give a specific error message. In order to maintain as much
- * information in the tree as possible, we replace them with local variable
- * writes.
- */
-static pm_node_t *
-parse_unwriteable_write(pm_parser_t *parser, pm_node_t *target, const pm_token_t *equals, pm_node_t *value) {
- switch (PM_NODE_TYPE(target)) {
- case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING); break;
- case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE); break;
- case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE); break;
- case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE); break;
- case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL); break;
- case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF); break;
- case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE); break;
- default: break;
- }
-
- pm_constant_id_t name = pm_parser_local_add_location(parser, target->location.start, target->location.end, 1);
- pm_local_variable_write_node_t *result = pm_local_variable_write_node_create(parser, name, 0, value, &target->location, equals);
-
- pm_node_destroy(parser, target);
- return (pm_node_t *) result;
-}
-
-/**
- * Parse a list of targets for assignment. This is used in the case of a for
- * loop or a multi-assignment. For example, in the following code:
- *
- * for foo, bar in baz
- * ^^^^^^^^
- *
- * The targets are `foo` and `bar`. This function will either return a single
- * target node or a multi-target node.
- */
-static pm_node_t *
-parse_targets(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
- bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
-
- pm_multi_target_node_t *result = pm_multi_target_node_create(parser);
- pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target, true, false));
-
- while (accept1(parser, PM_TOKEN_COMMA)) {
- if (accept1(parser, PM_TOKEN_USTAR)) {
- // Here we have a splat operator. It can have a name or be
- // anonymous. It can be the final target or be in the middle if
- // there haven't been any others yet.
- if (has_rest) {
- pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
- }
-
- pm_token_t star_operator = parser->previous;
- pm_node_t *name = NULL;
-
- if (token_begins_expression_p(parser->current.type)) {
- name = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
- name = parse_target(parser, name, true, true);
- }
-
- pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
- pm_multi_target_node_targets_append(parser, result, splat);
- has_rest = true;
- } else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
- context_push(parser, PM_CONTEXT_MULTI_TARGET);
- pm_node_t *target = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
- target = parse_target(parser, target, true, false);
-
- pm_multi_target_node_targets_append(parser, result, target);
- context_pop(parser);
- } else if (token_begins_expression_p(parser->current.type)) {
- pm_node_t *target = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
- target = parse_target(parser, target, true, false);
-
- pm_multi_target_node_targets_append(parser, result, target);
- } else if (!match1(parser, PM_TOKEN_EOF)) {
- // If we get here, then we have a trailing , in a multi target node.
- // We'll add an implicit rest node to represent this.
- pm_node_t *rest = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
- pm_multi_target_node_targets_append(parser, result, rest);
- break;
- }
- }
-
- return (pm_node_t *) result;
-}
-
-/**
- * Parse a list of targets and validate that it is in a valid position for
- * assignment.
- */
-static pm_node_t *
-parse_targets_validate(pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
- pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
- accept1(parser, PM_TOKEN_NEWLINE);
-
- // Ensure that we have either an = or a ) after the targets.
- if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
- pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
-
- return result;
-}
-
-/**
- * Parse a list of statements separated by newlines or semicolons.
- */
-static pm_statements_node_t *
-parse_statements(pm_parser_t *parser, pm_context_t context, uint16_t depth) {
- // First, skip past any optional terminators that might be at the beginning
- // of the statements.
- while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
-
- // If we have a terminator, then we can just return NULL.
- if (context_terminator(context, &parser->current)) return NULL;
-
- pm_statements_node_t *statements = pm_statements_node_create(parser);
-
- // At this point we know we have at least one statement, and that it
- // immediately follows the current token.
- context_push(parser, context);
-
- while (true) {
- pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
- pm_statements_node_body_append(parser, statements, node, true);
-
- // If we're recovering from a syntax error, then we need to stop parsing
- // the statements now.
- if (parser->recovering) {
- // If this is the level of context where the recovery has happened,
- // then we can mark the parser as done recovering.
- if (context_terminator(context, &parser->current)) parser->recovering = false;
- break;
- }
-
- // If we have a terminator, then we will parse all consecutive
- // terminators and then continue parsing the statements list.
- if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- // If we have a terminator, then we will continue parsing the
- // statements list.
- while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
- if (context_terminator(context, &parser->current)) break;
-
- // Now we can continue parsing the list of statements.
- continue;
- }
-
- // At this point we have a list of statements that are not terminated by
- // a newline or semicolon. At this point we need to check if we're at
- // the end of the statements list. If we are, then we should break out
- // of the loop.
- if (context_terminator(context, &parser->current)) break;
-
- // At this point, we have a syntax error, because the statement was not
- // terminated by a newline or semicolon, and we're not at the end of the
- // statements list. Ideally we should scan forward to determine if we
- // should insert a missing terminator or break out of parsing the
- // statements list at this point.
- //
- // We don't have that yet, so instead we'll do a more naive approach. If
- // we were unable to parse an expression, then we will skip past this
- // token and continue parsing the statements list. Otherwise we'll add
- // an error and continue parsing the statements list.
- if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
- parser_lex(parser);
-
- while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
- if (context_terminator(context, &parser->current)) break;
- } else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
- // This is an inlined version of accept1 because the error that we
- // want to add has varargs. If this happens again, we should
- // probably extract a helper function.
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type));
- parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
- }
- }
-
- context_pop(parser);
- bool last_value = true;
- switch (context) {
- case PM_CONTEXT_BEGIN_ENSURE:
- case PM_CONTEXT_DEF_ENSURE:
- last_value = false;
- break;
- default:
- break;
- }
- pm_void_statements_check(parser, statements, last_value);
-
- return statements;
-}
-
-/**
- * Add a node to a set of static literals that holds a set of hash keys. If the
- * node is a duplicate, then add an appropriate warning.
- */
-static void
-pm_hash_key_static_literals_add(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node) {
- const pm_node_t *duplicated = pm_static_literals_add(&parser->newline_list, parser->start_line, literals, node, true);
-
- if (duplicated != NULL) {
- pm_buffer_t buffer = { 0 };
- pm_static_literal_inspect(&buffer, &parser->newline_list, parser->start_line, parser->encoding->name, duplicated);
-
- pm_diagnostic_list_append_format(
- &parser->warning_list,
- duplicated->location.start,
- duplicated->location.end,
- PM_WARN_DUPLICATED_HASH_KEY,
- (int) pm_buffer_length(&buffer),
- pm_buffer_value(&buffer),
- pm_newline_list_line_column(&parser->newline_list, node->location.start, parser->start_line).line
- );
-
- pm_buffer_free(&buffer);
- }
-}
-
-/**
- * Add a node to a set of static literals that holds a set of hash keys. If the
- * node is a duplicate, then add an appropriate warning.
- */
-static void
-pm_when_clause_static_literals_add(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node) {
- pm_node_t *previous;
-
- if ((previous = pm_static_literals_add(&parser->newline_list, parser->start_line, literals, node, false)) != NULL) {
- pm_diagnostic_list_append_format(
- &parser->warning_list,
- node->location.start,
- node->location.end,
- PM_WARN_DUPLICATED_WHEN_CLAUSE,
- pm_newline_list_line_column(&parser->newline_list, node->location.start, parser->start_line).line,
- pm_newline_list_line_column(&parser->newline_list, previous->location.start, parser->start_line).line
- );
- }
-}
-
-/**
- * Parse all of the elements of a hash. Return true if a double splat was found.
- */
-static bool
-parse_assocs(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node, uint16_t depth) {
- assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
- bool contains_keyword_splat = false;
-
- while (true) {
- pm_node_t *element;
-
- switch (parser->current.type) {
- case PM_TOKEN_USTAR_STAR: {
- parser_lex(parser);
- pm_token_t operator = parser->previous;
- pm_node_t *value = NULL;
-
- if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
- // If we're about to parse a nested hash that is being
- // pushed into this hash directly with **, then we want the
- // inner hash to share the static literals with the outer
- // hash.
- parser->current_hash_keys = literals;
- value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
- } else if (token_begins_expression_p(parser->current.type)) {
- value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
- } else {
- pm_parser_scope_forwarding_keywords_check(parser, &operator);
- }
-
- element = (pm_node_t *) pm_assoc_splat_node_create(parser, value, &operator);
- contains_keyword_splat = true;
- break;
- }
- case PM_TOKEN_LABEL: {
- pm_token_t label = parser->current;
- parser_lex(parser);
-
- pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &label);
- pm_hash_key_static_literals_add(parser, literals, key);
-
- pm_token_t operator = not_provided(parser);
- pm_node_t *value = NULL;
-
- if (token_begins_expression_p(parser->current.type)) {
- value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
- } else {
- if (parser->encoding->isupper_char(label.start, (label.end - 1) - label.start)) {
- pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.start, .end = label.end - 1 };
- value = (pm_node_t *) pm_constant_read_node_create(parser, &constant);
- } else {
- int depth = -1;
- pm_token_t identifier = { .type = PM_TOKEN_IDENTIFIER, .start = label.start, .end = label.end - 1 };
-
- if (identifier.end[-1] == '!' || identifier.end[-1] == '?') {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
- } else {
- depth = pm_parser_local_depth(parser, &identifier);
- }
-
- if (depth == -1) {
- value = (pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
- } else {
- value = (pm_node_t *) pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth);
- }
- }
-
- value->location.end++;
- value = (pm_node_t *) pm_implicit_node_create(parser, value);
- }
-
- element = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value);
- break;
- }
- default: {
- pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
-
- // Hash keys that are strings are automatically frozen. We will
- // mark that here.
- if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
- pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
- }
-
- pm_hash_key_static_literals_add(parser, literals, key);
-
- pm_token_t operator;
- if (pm_symbol_node_label_p(key)) {
- operator = not_provided(parser);
- } else {
- expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
- operator = parser->previous;
- }
-
- pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
- element = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value);
- break;
- }
- }
-
- if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
- pm_hash_node_elements_append((pm_hash_node_t *) node, element);
- } else {
- pm_keyword_hash_node_elements_append((pm_keyword_hash_node_t *) node, element);
- }
-
- // If there's no comma after the element, then we're done.
- if (!accept1(parser, PM_TOKEN_COMMA)) break;
-
- // If the next element starts with a label or a **, then we know we have
- // another element in the hash, so we'll continue parsing.
- if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)) continue;
-
- // Otherwise we need to check if the subsequent token begins an expression.
- // If it does, then we'll continue parsing.
- if (token_begins_expression_p(parser->current.type)) continue;
-
- // Otherwise by default we will exit out of this loop.
- break;
- }
-
- return contains_keyword_splat;
-}
-
-/**
- * Append an argument to a list of arguments.
- */
-static inline void
-parse_arguments_append(pm_parser_t *parser, pm_arguments_t *arguments, pm_node_t *argument) {
- if (arguments->arguments == NULL) {
- arguments->arguments = pm_arguments_node_create(parser);
- }
-
- pm_arguments_node_arguments_append(arguments->arguments, argument);
-}
-
-/**
- * Parse a list of arguments.
- */
-static void
-parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) {
- pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].left;
-
- // First we need to check if the next token is one that could be the start of
- // an argument. If it's not, then we can just return.
- if (
- match2(parser, terminator, PM_TOKEN_EOF) ||
- (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
- context_terminator(parser->current_context->context, &parser->current)
- ) {
- return;
- }
-
- bool parsed_first_argument = false;
- bool parsed_bare_hash = false;
- bool parsed_block_argument = false;
- bool parsed_forwarding_arguments = false;
-
- while (!match1(parser, PM_TOKEN_EOF)) {
- if (parsed_block_argument) {
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
- }
- if (parsed_forwarding_arguments) {
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
- }
-
- pm_node_t *argument = NULL;
-
- switch (parser->current.type) {
- case PM_TOKEN_USTAR_STAR:
- case PM_TOKEN_LABEL: {
- if (parsed_bare_hash) {
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
- }
-
- pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
- argument = (pm_node_t *) hash;
-
- pm_static_literals_t hash_keys = { 0 };
- bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (pm_node_t *) hash, (uint16_t) (depth + 1));
-
- parse_arguments_append(parser, arguments, argument);
-
- pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
- if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
- pm_node_flag_set((pm_node_t *) arguments->arguments, flags);
-
- pm_static_literals_free(&hash_keys);
- parsed_bare_hash = true;
-
- break;
- }
- case PM_TOKEN_UAMPERSAND: {
- parser_lex(parser);
- pm_token_t operator = parser->previous;
- pm_node_t *expression = NULL;
-
- if (token_begins_expression_p(parser->current.type)) {
- expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
- } else {
- pm_parser_scope_forwarding_block_check(parser, &operator);
- }
-
- argument = (pm_node_t *) pm_block_argument_node_create(parser, &operator, expression);
- if (parsed_block_argument) {
- parse_arguments_append(parser, arguments, argument);
- } else {
- arguments->block = argument;
- }
-
- parsed_block_argument = true;
- break;
- }
- case PM_TOKEN_USTAR: {
- parser_lex(parser);
- pm_token_t operator = parser->previous;
-
- if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
- pm_parser_scope_forwarding_positionals_check(parser, &operator);
- argument = (pm_node_t *) pm_splat_node_create(parser, &operator, NULL);
- } else {
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
-
- if (parsed_bare_hash) {
- pm_parser_err(parser, operator.start, expression->location.end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
- }
-
- argument = (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
- }
-
- parse_arguments_append(parser, arguments, argument);
- break;
- }
- case PM_TOKEN_UDOT_DOT_DOT: {
- if (accepts_forwarding) {
- parser_lex(parser);
-
- if (token_begins_expression_p(parser->current.type)) {
- // If the token begins an expression then this ... was
- // not actually argument forwarding but was instead a
- // range.
- pm_token_t operator = parser->previous;
- pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
-
- // If we parse a range, we need to validate that we
- // didn't accidentally violate the nonassoc rules of the
- // ... operator.
- if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
- pm_range_node_t *range = (pm_range_node_t *) right;
- pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
- }
-
- argument = (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
- } else {
- pm_parser_scope_forwarding_all_check(parser, &parser->previous);
- if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
- pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
- }
-
- argument = (pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->previous);
- parse_arguments_append(parser, arguments, argument);
- pm_node_flag_set((pm_node_t *) arguments->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
- arguments->has_forwarding = true;
- parsed_forwarding_arguments = true;
- break;
- }
- }
- }
- /* fallthrough */
- default: {
- if (argument == NULL) {
- argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument, true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
- }
-
- bool contains_keywords = false;
- bool contains_keyword_splat = false;
-
- if (pm_symbol_node_label_p(argument) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
- if (parsed_bare_hash) {
- pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
- }
-
- pm_token_t operator;
- if (parser->previous.type == PM_TOKEN_EQUAL_GREATER) {
- operator = parser->previous;
- } else {
- operator = not_provided(parser);
- }
-
- pm_keyword_hash_node_t *bare_hash = pm_keyword_hash_node_create(parser);
- contains_keywords = true;
-
- // Create the set of static literals for this hash.
- pm_static_literals_t hash_keys = { 0 };
- pm_hash_key_static_literals_add(parser, &hash_keys, argument);
-
- // Finish parsing the one we are part way through.
- pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
- argument = (pm_node_t *) pm_assoc_node_create(parser, argument, &operator, value);
-
- pm_keyword_hash_node_elements_append(bare_hash, argument);
- argument = (pm_node_t *) bare_hash;
-
- // Then parse more if we have a comma
- if (accept1(parser, PM_TOKEN_COMMA) && (
- token_begins_expression_p(parser->current.type) ||
- match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
- )) {
- contains_keyword_splat = parse_assocs(parser, &hash_keys, (pm_node_t *) bare_hash, (uint16_t) (depth + 1));
- }
-
- pm_static_literals_free(&hash_keys);
- parsed_bare_hash = true;
- }
-
- parse_arguments_append(parser, arguments, argument);
-
- pm_node_flags_t flags = 0;
- if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
- if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
- pm_node_flag_set((pm_node_t *) arguments->arguments, flags);
-
- break;
- }
- }
-
- parsed_first_argument = true;
-
- // If parsing the argument failed, we need to stop parsing arguments.
- if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->recovering) break;
-
- // If the terminator of these arguments is not EOF, then we have a specific
- // token we're looking for. In that case we can accept a newline here
- // because it is not functioning as a statement terminator.
- if (terminator != PM_TOKEN_EOF) accept1(parser, PM_TOKEN_NEWLINE);
-
- if (parser->previous.type == PM_TOKEN_COMMA && parsed_bare_hash) {
- // If we previously were on a comma and we just parsed a bare hash, then
- // we want to continue parsing arguments. This is because the comma was
- // grabbed up by the hash parser.
- } else {
- // If there is no comma at the end of the argument list then we're done
- // parsing arguments and can break out of this loop.
- if (!accept1(parser, PM_TOKEN_COMMA)) break;
- }
-
- // If we hit the terminator, then that means we have a trailing comma so we
- // can accept that output as well.
- if (match1(parser, terminator)) break;
- }
-}
-
-/**
- * Required parameters on method, block, and lambda declarations can be
- * destructured using parentheses. This looks like:
- *
- * def foo((bar, baz))
- * end
- *
- *
- * It can recurse infinitely down, and splats are allowed to group arguments.
- */
-static pm_multi_target_node_t *
-parse_required_destructured_parameter(pm_parser_t *parser) {
- expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
-
- pm_multi_target_node_t *node = pm_multi_target_node_create(parser);
- pm_multi_target_node_opening_set(node, &parser->previous);
-
- do {
- pm_node_t *param;
-
- // If we get here then we have a trailing comma, which isn't allowed in
- // the grammar. In other places, multi targets _do_ allow trailing
- // commas, so here we'll assume this is a mistake of the user not
- // knowing it's not allowed here.
- if (node->lefts.size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- param = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
- pm_multi_target_node_targets_append(parser, node, param);
- pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
- break;
- }
-
- if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
- param = (pm_node_t *) parse_required_destructured_parameter(parser);
- } else if (accept1(parser, PM_TOKEN_USTAR)) {
- pm_token_t star = parser->previous;
- pm_node_t *value = NULL;
-
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- pm_token_t name = parser->previous;
- value = (pm_node_t *) pm_required_parameter_node_create(parser, &name);
- if (pm_parser_parameter_name_check(parser, &name)) {
- pm_node_flag_set_repeated_parameter(value);
- }
- pm_parser_local_add_token(parser, &name, 1);
- }
-
- param = (pm_node_t *) pm_splat_node_create(parser, &star, value);
- } else {
- expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
- pm_token_t name = parser->previous;
-
- param = (pm_node_t *) pm_required_parameter_node_create(parser, &name);
- if (pm_parser_parameter_name_check(parser, &name)) {
- pm_node_flag_set_repeated_parameter(param);
- }
- pm_parser_local_add_token(parser, &name, 1);
- }
-
- pm_multi_target_node_targets_append(parser, node, param);
- } while (accept1(parser, PM_TOKEN_COMMA));
-
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
- pm_multi_target_node_closing_set(node, &parser->previous);
-
- return node;
-}
-
-/**
- * This represents the different order states we can be in when parsing
- * method parameters.
- */
-typedef enum {
- PM_PARAMETERS_NO_CHANGE = 0, // Extra state for tokens that should not change the state
- PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
- PM_PARAMETERS_ORDER_KEYWORDS_REST,
- PM_PARAMETERS_ORDER_KEYWORDS,
- PM_PARAMETERS_ORDER_REST,
- PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
- PM_PARAMETERS_ORDER_OPTIONAL,
- PM_PARAMETERS_ORDER_NAMED,
- PM_PARAMETERS_ORDER_NONE,
-} pm_parameters_order_t;
-
-/**
- * This matches parameters tokens with parameters state.
- */
-static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
- [0] = PM_PARAMETERS_NO_CHANGE,
- [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
- [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
- [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
- [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
- [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
- [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
- [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
- [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
- [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
- [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
- [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
-};
-
-/**
- * Check if current parameter follows valid parameters ordering. If not it adds
- * an error to the list without stopping the parsing, otherwise sets the
- * parameters state to the one corresponding to the current parameter.
- *
- * It returns true if it was successful, and false otherwise.
- */
-static bool
-update_parameter_state(pm_parser_t *parser, pm_token_t *token, pm_parameters_order_t *current) {
- pm_parameters_order_t state = parameters_ordering[token->type];
- if (state == PM_PARAMETERS_NO_CHANGE) return true;
-
- // If we see another ordered argument after a optional argument
- // we only continue parsing ordered arguments until we stop seeing ordered arguments.
- if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
- *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
- return true;
- } else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
- return true;
- }
-
- if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
- pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
- return false;
- } else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
- pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
- return false;
- } else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
- // We know what transition we failed on, so we can provide a better error here.
- pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
- return false;
- }
-
- if (state < *current) *current = state;
- return true;
-}
-
-/**
- * Parse a list of parameters on a method definition.
- */
-static pm_parameters_node_t *
-parse_parameters(
- pm_parser_t *parser,
- pm_binding_power_t binding_power,
- bool uses_parentheses,
- bool allows_trailing_comma,
- bool allows_forwarding_parameters,
- bool accepts_blocks_in_defaults,
- uint16_t depth
-) {
- pm_parameters_node_t *params = pm_parameters_node_create(parser);
- bool looping = true;
-
- pm_do_loop_stack_push(parser, false);
- pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
-
- do {
- switch (parser->current.type) {
- case PM_TOKEN_PARENTHESIS_LEFT: {
- update_parameter_state(parser, &parser->current, &order);
- pm_node_t *param = (pm_node_t *) parse_required_destructured_parameter(parser);
-
- if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
- pm_parameters_node_requireds_append(params, param);
- } else {
- pm_parameters_node_posts_append(params, param);
- }
- break;
- }
- case PM_TOKEN_UAMPERSAND:
- case PM_TOKEN_AMPERSAND: {
- update_parameter_state(parser, &parser->current, &order);
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_token_t name;
-
- bool repeated = false;
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- name = parser->previous;
- repeated = pm_parser_parameter_name_check(parser, &name);
- pm_parser_local_add_token(parser, &name, 1);
- } else {
- name = not_provided(parser);
- parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
- }
-
- pm_block_parameter_node_t *param = pm_block_parameter_node_create(parser, &name, &operator);
- if (repeated) {
- pm_node_flag_set_repeated_parameter((pm_node_t *)param);
- }
- if (params->block == NULL) {
- pm_parameters_node_block_set(params, param);
- } else {
- pm_parser_err_node(parser, (pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
- pm_parameters_node_posts_append(params, (pm_node_t *) param);
- }
-
- break;
- }
- case PM_TOKEN_UDOT_DOT_DOT: {
- if (!allows_forwarding_parameters) {
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
- }
-
- bool succeeded = update_parameter_state(parser, &parser->current, &order);
- parser_lex(parser);
-
- parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL;
- pm_forwarding_parameter_node_t *param = pm_forwarding_parameter_node_create(parser, &parser->previous);
-
- if (params->keyword_rest != NULL) {
- // If we already have a keyword rest parameter, then we replace it with the
- // forwarding parameter and move the keyword rest parameter to the posts list.
- pm_node_t *keyword_rest = params->keyword_rest;
- pm_parameters_node_posts_append(params, keyword_rest);
- if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
- params->keyword_rest = NULL;
- }
-
- pm_parameters_node_keyword_rest_set(params, (pm_node_t *) param);
- break;
- }
- case PM_TOKEN_CLASS_VARIABLE:
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_INSTANCE_VARIABLE:
- case PM_TOKEN_GLOBAL_VARIABLE:
- case PM_TOKEN_METHOD_NAME: {
- parser_lex(parser);
- switch (parser->previous.type) {
- case PM_TOKEN_CONSTANT:
- pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
- break;
- case PM_TOKEN_INSTANCE_VARIABLE:
- pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
- break;
- case PM_TOKEN_GLOBAL_VARIABLE:
- pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
- break;
- case PM_TOKEN_CLASS_VARIABLE:
- pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
- break;
- case PM_TOKEN_METHOD_NAME:
- pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
- break;
- default: break;
- }
-
- if (parser->current.type == PM_TOKEN_EQUAL) {
- update_parameter_state(parser, &parser->current, &order);
- } else {
- update_parameter_state(parser, &parser->previous, &order);
- }
-
- pm_token_t name = parser->previous;
- bool repeated = pm_parser_parameter_name_check(parser, &name);
- pm_parser_local_add_token(parser, &name, 1);
-
- if (match1(parser, PM_TOKEN_EQUAL)) {
- pm_token_t operator = parser->current;
- context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
- parser_lex(parser);
-
- pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &name);
- uint32_t reads = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
-
- if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser, true);
- pm_node_t *value = parse_value_expression(parser, binding_power, false, false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
- if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
-
- pm_optional_parameter_node_t *param = pm_optional_parameter_node_create(parser, &name, &operator, value);
-
- if (repeated) {
- pm_node_flag_set_repeated_parameter((pm_node_t *) param);
- }
- pm_parameters_node_optionals_append(params, param);
-
- // If the value of the parameter increased the number of
- // reads of that parameter, then we need to warn that we
- // have a circular definition.
- if ((parser->version == PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
- }
-
- context_pop(parser);
-
- // If parsing the value of the parameter resulted in error recovery,
- // then we can put a missing node in its place and stop parsing the
- // parameters entirely now.
- if (parser->recovering) {
- looping = false;
- break;
- }
- } else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
- pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
- if (repeated) {
- pm_node_flag_set_repeated_parameter((pm_node_t *)param);
- }
- pm_parameters_node_requireds_append(params, (pm_node_t *) param);
- } else {
- pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
- if (repeated) {
- pm_node_flag_set_repeated_parameter((pm_node_t *)param);
- }
- pm_parameters_node_posts_append(params, (pm_node_t *) param);
- }
-
- break;
- }
- case PM_TOKEN_LABEL: {
- if (!uses_parentheses) parser->in_keyword_arg = true;
- update_parameter_state(parser, &parser->current, &order);
-
- context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
- parser_lex(parser);
-
- pm_token_t name = parser->previous;
- pm_token_t local = name;
- local.end -= 1;
-
- if (parser->encoding_changed ? parser->encoding->isupper_char(local.start, local.end - local.start) : pm_encoding_utf_8_isupper_char(local.start, local.end - local.start)) {
- pm_parser_err(parser, local.start, local.end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
- } else if (local.end[-1] == '!' || local.end[-1] == '?') {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
- }
-
- bool repeated = pm_parser_parameter_name_check(parser, &local);
- pm_parser_local_add_token(parser, &local, 1);
-
- switch (parser->current.type) {
- case PM_TOKEN_COMMA:
- case PM_TOKEN_PARENTHESIS_RIGHT:
- case PM_TOKEN_PIPE: {
- context_pop(parser);
-
- pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
- if (repeated) {
- pm_node_flag_set_repeated_parameter(param);
- }
-
- pm_parameters_node_keywords_append(params, param);
- break;
- }
- case PM_TOKEN_SEMICOLON:
- case PM_TOKEN_NEWLINE: {
- context_pop(parser);
-
- if (uses_parentheses) {
- looping = false;
- break;
- }
-
- pm_node_t *param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
- if (repeated) {
- pm_node_flag_set_repeated_parameter(param);
- }
-
- pm_parameters_node_keywords_append(params, param);
- break;
- }
- default: {
- pm_node_t *param;
-
- if (token_begins_expression_p(parser->current.type)) {
- pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &local);
- uint32_t reads = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
-
- if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser, true);
- pm_node_t *value = parse_value_expression(parser, binding_power, false, false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
- if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
-
- if (parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
- }
-
- param = (pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
- }
- else {
- param = (pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
- }
-
- if (repeated) {
- pm_node_flag_set_repeated_parameter(param);
- }
-
- context_pop(parser);
- pm_parameters_node_keywords_append(params, param);
-
- // If parsing the value of the parameter resulted in error recovery,
- // then we can put a missing node in its place and stop parsing the
- // parameters entirely now.
- if (parser->recovering) {
- looping = false;
- break;
- }
- }
- }
-
- parser->in_keyword_arg = false;
- break;
- }
- case PM_TOKEN_USTAR:
- case PM_TOKEN_STAR: {
- update_parameter_state(parser, &parser->current, &order);
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_token_t name;
- bool repeated = false;
-
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- name = parser->previous;
- repeated = pm_parser_parameter_name_check(parser, &name);
- pm_parser_local_add_token(parser, &name, 1);
- } else {
- name = not_provided(parser);
- parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS;
- }
-
- pm_node_t *param = (pm_node_t *) pm_rest_parameter_node_create(parser, &operator, &name);
- if (repeated) {
- pm_node_flag_set_repeated_parameter(param);
- }
-
- if (params->rest == NULL) {
- pm_parameters_node_rest_set(params, param);
- } else {
- pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
- pm_parameters_node_posts_append(params, param);
- }
-
- break;
- }
- case PM_TOKEN_STAR_STAR:
- case PM_TOKEN_USTAR_STAR: {
- pm_parameters_order_t previous_order = order;
- update_parameter_state(parser, &parser->current, &order);
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *param;
-
- if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
- if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
- pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
- }
-
- param = (pm_node_t *) pm_no_keywords_parameter_node_create(parser, &operator, &parser->previous);
- } else {
- pm_token_t name;
-
- bool repeated = false;
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- name = parser->previous;
- repeated = pm_parser_parameter_name_check(parser, &name);
- pm_parser_local_add_token(parser, &name, 1);
- } else {
- name = not_provided(parser);
- parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS;
- }
-
- param = (pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &operator, &name);
- if (repeated) {
- pm_node_flag_set_repeated_parameter(param);
- }
- }
-
- if (params->keyword_rest == NULL) {
- pm_parameters_node_keyword_rest_set(params, param);
- } else {
- pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
- pm_parameters_node_posts_append(params, param);
- }
-
- break;
- }
- default:
- if (parser->previous.type == PM_TOKEN_COMMA) {
- if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
- // If we get here, then we have a trailing comma in a
- // block parameter list.
- pm_node_t *param = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
-
- if (params->rest == NULL) {
- pm_parameters_node_rest_set(params, param);
- } else {
- pm_parser_err_node(parser, (pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
- pm_parameters_node_posts_append(params, (pm_node_t *) param);
- }
- } else {
- pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
- }
- }
-
- looping = false;
- break;
- }
-
- if (looping && uses_parentheses) {
- accept1(parser, PM_TOKEN_NEWLINE);
- }
- } while (looping && accept1(parser, PM_TOKEN_COMMA));
-
- pm_do_loop_stack_pop(parser);
-
- // If we don't have any parameters, return `NULL` instead of an empty `ParametersNode`.
- if (params->base.location.start == params->base.location.end) {
- pm_node_destroy(parser, (pm_node_t *) params);
- return NULL;
- }
-
- return params;
-}
-
-/**
- * Accepts a parser returns the index of the last newline in the file that was
- * ecorded before the current token within the newline list.
- */
-static size_t
-token_newline_index(const pm_parser_t *parser) {
- if (parser->heredoc_end == NULL) {
- // This is the common case. In this case we can look at the previously
- // recorded newline in the newline list and subtract from the current
- // offset.
- return parser->newline_list.size - 1;
- } else {
- // This is unlikely. This is the case that we have already parsed the
- // start of a heredoc, so we cannot rely on looking at the previous
- // offset of the newline list, and instead must go through the whole
- // process of a binary search for the line number.
- return (size_t) pm_newline_list_line(&parser->newline_list, parser->current.start, 0);
- }
-}
-
-/**
- * Accepts a parser, a newline index, and a token and returns the column. The
- * important piece of this is that it expands tabs out to the next tab stop.
- */
-static int64_t
-token_column(const pm_parser_t *parser, size_t newline_index, const pm_token_t *token, bool break_on_non_space) {
- const uint8_t *cursor = parser->start + parser->newline_list.offsets[newline_index];
- const uint8_t *end = token->start;
-
- // Skip over the BOM if it is present.
- if (
- newline_index == 0 &&
- parser->start[0] == 0xef &&
- parser->start[1] == 0xbb &&
- parser->start[2] == 0xbf
- ) cursor += 3;
-
- int64_t column = 0;
- for (; cursor < end; cursor++) {
- switch (*cursor) {
- case '\t':
- column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
- break;
- case ' ':
- column++;
- break;
- default:
- column++;
- if (break_on_non_space) return -1;
- break;
- }
- }
-
- return column;
-}
-
-/**
- * Accepts a parser, two newline indices, and pointers to two tokens. This
- * function warns if the indentation of the two tokens does not match.
- */
-static void
-parser_warn_indentation_mismatch(pm_parser_t *parser, size_t opening_newline_index, const pm_token_t *opening_token, bool if_after_else, bool allow_indent) {
- // If these warnings are disabled (unlikely), then we can just return.
- if (!parser->warn_mismatched_indentation) return;
-
- // If the tokens are on the same line, we do not warn.
- size_t closing_newline_index = token_newline_index(parser);
- if (opening_newline_index == closing_newline_index) return;
-
- // If the opening token has anything other than spaces or tabs before it,
- // then we do not warn. This is unless we are matching up an `if`/`end` pair
- // and the `if` immediately follows an `else` keyword.
- int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
- if (!if_after_else && (opening_column == -1)) return;
-
- // Get a reference to the closing token off the current parser. This assumes
- // that the caller has placed this in the correct position.
- pm_token_t *closing_token = &parser->current;
-
- // If the tokens are at the same indentation, we do not warn.
- int64_t closing_column = token_column(parser, closing_newline_index, closing_token, true);
- if ((closing_column == -1) || (opening_column == closing_column)) return;
-
- // If the closing column is greater than the opening column and we are
- // allowing indentation, then we do not warn.
- if (allow_indent && (closing_column > opening_column)) return;
-
- // Otherwise, add a warning.
- PM_PARSER_WARN_FORMAT(
- parser,
- closing_token->start,
- closing_token->end,
- PM_WARN_INDENTATION_MISMATCH,
- (int) (closing_token->end - closing_token->start),
- (const char *) closing_token->start,
- (int) (opening_token->end - opening_token->start),
- (const char *) opening_token->start,
- ((int32_t) opening_newline_index) + parser->start_line
- );
-}
-
-typedef enum {
- PM_RESCUES_BEGIN = 1,
- PM_RESCUES_BLOCK,
- PM_RESCUES_CLASS,
- PM_RESCUES_DEF,
- PM_RESCUES_LAMBDA,
- PM_RESCUES_MODULE,
- PM_RESCUES_SCLASS
-} pm_rescues_type_t;
-
-/**
- * Parse any number of rescue clauses. This will form a linked list of if
- * nodes pointing to each other from the top.
- */
-static inline void
-parse_rescues(pm_parser_t *parser, size_t opening_newline_index, const pm_token_t *opening, pm_begin_node_t *parent_node, pm_rescues_type_t type, uint16_t depth) {
- pm_rescue_node_t *current = NULL;
-
- while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
- if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening, false, false);
- parser_lex(parser);
-
- pm_rescue_node_t *rescue = pm_rescue_node_create(parser, &parser->previous);
-
- switch (parser->current.type) {
- case PM_TOKEN_EQUAL_GREATER: {
- // Here we have an immediate => after the rescue keyword, in which case
- // we're going to have an empty list of exceptions to rescue (which
- // implies StandardError).
- parser_lex(parser);
- pm_rescue_node_operator_set(rescue, &parser->previous);
-
- pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
- reference = parse_target(parser, reference, false, false);
-
- pm_rescue_node_reference_set(rescue, reference);
- break;
- }
- case PM_TOKEN_NEWLINE:
- case PM_TOKEN_SEMICOLON:
- case PM_TOKEN_KEYWORD_THEN:
- // Here we have a terminator for the rescue keyword, in which case we're
- // going to just continue on.
- break;
- default: {
- if (token_begins_expression_p(parser->current.type) || match1(parser, PM_TOKEN_USTAR)) {
- // Here we have something that could be an exception expression, so
- // we'll attempt to parse it here and any others delimited by commas.
-
- do {
- pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED, false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
- pm_rescue_node_exceptions_append(rescue, expression);
-
- // If we hit a newline, then this is the end of the rescue expression. We
- // can continue on to parse the statements.
- if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN)) break;
-
- // If we hit a `=>` then we're going to parse the exception variable. Once
- // we've done that, we'll break out of the loop and parse the statements.
- if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
- pm_rescue_node_operator_set(rescue, &parser->previous);
-
- pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
- reference = parse_target(parser, reference, false, false);
-
- pm_rescue_node_reference_set(rescue, reference);
- break;
- }
- } while (accept1(parser, PM_TOKEN_COMMA));
- }
- }
- }
-
- if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- accept1(parser, PM_TOKEN_KEYWORD_THEN);
- } else {
- expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
- }
-
- if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- pm_context_t context;
-
- switch (type) {
- case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_RESCUE; break;
- case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_RESCUE; break;
- case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_RESCUE; break;
- case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_RESCUE; break;
- case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_RESCUE; break;
- case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_RESCUE; break;
- case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_RESCUE; break;
- default: assert(false && "unreachable"); context = PM_CONTEXT_BEGIN_RESCUE; break;
- }
-
- pm_statements_node_t *statements = parse_statements(parser, context, (uint16_t) (depth + 1));
- if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
-
- pm_accepts_block_stack_pop(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- if (current == NULL) {
- pm_begin_node_rescue_clause_set(parent_node, rescue);
- } else {
- pm_rescue_node_subsequent_set(current, rescue);
- }
-
- current = rescue;
- }
-
- // The end node locations on rescue nodes will not be set correctly
- // since we won't know the end until we've found all subsequent
- // clauses. This sets the end location on all rescues once we know it.
- if (current != NULL) {
- const uint8_t *end_to_set = current->base.location.end;
- pm_rescue_node_t *clause = parent_node->rescue_clause;
-
- while (clause != NULL) {
- clause->base.location.end = end_to_set;
- clause = clause->subsequent;
- }
- }
-
- pm_token_t else_keyword;
- if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
- if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening, false, false);
- opening_newline_index = token_newline_index(parser);
-
- else_keyword = parser->current;
- opening = &else_keyword;
-
- parser_lex(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
-
- pm_statements_node_t *else_statements = NULL;
- if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
- pm_accepts_block_stack_push(parser, true);
- pm_context_t context;
-
- switch (type) {
- case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ELSE; break;
- case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ELSE; break;
- case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ELSE; break;
- case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ELSE; break;
- case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ELSE; break;
- case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ELSE; break;
- case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ELSE; break;
- default: assert(false && "unreachable"); context = PM_CONTEXT_BEGIN_RESCUE; break;
- }
-
- else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
-
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->current);
- pm_begin_node_else_clause_set(parent_node, else_clause);
-
- // If we don't have a `current` rescue node, then this is a dangling
- // else, and it's an error.
- if (current == NULL) pm_parser_err_node(parser, (pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
- }
-
- if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
- if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening, false, false);
- pm_token_t ensure_keyword = parser->current;
-
- parser_lex(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
-
- pm_statements_node_t *ensure_statements = NULL;
- if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- pm_context_t context;
-
- switch (type) {
- case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ENSURE; break;
- case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ENSURE; break;
- case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ENSURE; break;
- case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ENSURE; break;
- case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ENSURE; break;
- case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ENSURE; break;
- case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ENSURE; break;
- default: assert(false && "unreachable"); context = PM_CONTEXT_BEGIN_RESCUE; break;
- }
-
- ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
-
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->current);
- pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
- }
-
- if (match1(parser, PM_TOKEN_KEYWORD_END)) {
- if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening, false, false);
- pm_begin_node_end_keyword_set(parent_node, &parser->current);
- } else {
- pm_token_t end_keyword = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- pm_begin_node_end_keyword_set(parent_node, &end_keyword);
- }
-}
-
-/**
- * Parse a set of rescue clauses with an implicit begin (for example when on a
- * class, module, def, etc.).
- */
-static pm_begin_node_t *
-parse_rescues_implicit_begin(pm_parser_t *parser, size_t opening_newline_index, const pm_token_t *opening, const uint8_t *start, pm_statements_node_t *statements, pm_rescues_type_t type, uint16_t depth) {
- pm_token_t begin_keyword = not_provided(parser);
- pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
-
- parse_rescues(parser, opening_newline_index, opening, node, type, (uint16_t) (depth + 1));
- node->base.location.start = start;
-
- return node;
-}
-
-/**
- * Parse a list of parameters and local on a block definition.
- */
-static pm_block_parameters_node_t *
-parse_block_parameters(
- pm_parser_t *parser,
- bool allows_trailing_comma,
- const pm_token_t *opening,
- bool is_lambda_literal,
- bool accepts_blocks_in_defaults,
- uint16_t depth
-) {
- pm_parameters_node_t *parameters = NULL;
- if (!match1(parser, PM_TOKEN_SEMICOLON)) {
- parameters = parse_parameters(
- parser,
- is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
- false,
- allows_trailing_comma,
- false,
- accepts_blocks_in_defaults,
- (uint16_t) (depth + 1)
- );
- }
-
- pm_block_parameters_node_t *block_parameters = pm_block_parameters_node_create(parser, parameters, opening);
- if ((opening->type != PM_TOKEN_NOT_PROVIDED)) {
- accept1(parser, PM_TOKEN_NEWLINE);
-
- if (accept1(parser, PM_TOKEN_SEMICOLON)) {
- do {
- switch (parser->current.type) {
- case PM_TOKEN_CONSTANT:
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
- parser_lex(parser);
- break;
- case PM_TOKEN_INSTANCE_VARIABLE:
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
- parser_lex(parser);
- break;
- case PM_TOKEN_GLOBAL_VARIABLE:
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
- parser_lex(parser);
- break;
- case PM_TOKEN_CLASS_VARIABLE:
- pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
- parser_lex(parser);
- break;
- default:
- expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
- break;
- }
-
- bool repeated = pm_parser_parameter_name_check(parser, &parser->previous);
- pm_parser_local_add_token(parser, &parser->previous, 1);
-
- pm_block_local_variable_node_t *local = pm_block_local_variable_node_create(parser, &parser->previous);
- if (repeated) pm_node_flag_set_repeated_parameter((pm_node_t *) local);
-
- pm_block_parameters_node_append_local(block_parameters, local);
- } while (accept1(parser, PM_TOKEN_COMMA));
- }
- }
-
- return block_parameters;
-}
-
-/**
- * Return true if any of the visible scopes to the current context are using
- * numbered parameters.
- */
-static bool
-outer_scope_using_numbered_parameters_p(pm_parser_t *parser) {
- for (pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
- if (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) return true;
- }
-
- return false;
-}
-
-/**
- * These are the names of the various numbered parameters. We have them here so
- * that when we insert them into the constant pool we can use a constant string
- * and not have to allocate.
- */
-static const char * const pm_numbered_parameter_names[] = {
- "_1", "_2", "_3", "_4", "_5", "_6", "_7", "_8", "_9"
-};
-
-/**
- * Return the node that should be used in the parameters field of a block-like
- * (block or lambda) node, depending on the kind of parameters that were
- * declared in the current scope.
- */
-static pm_node_t *
-parse_blocklike_parameters(pm_parser_t *parser, pm_node_t *parameters, const pm_token_t *opening, const pm_token_t *closing) {
- pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
-
- // If we have ordinary parameters, then we will return them as the set of
- // parameters.
- if (parameters != NULL) {
- // If we also have implicit parameters, then this is an error.
- if (implicit_parameters->size > 0) {
- pm_node_t *node = implicit_parameters->nodes[0];
-
- if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
- pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
- } else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
- pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
- } else {
- assert(false && "unreachable");
- }
- }
-
- return parameters;
- }
-
- // If we don't have any implicit parameters, then the set of parameters is
- // NULL.
- if (implicit_parameters->size == 0) {
- return NULL;
- }
-
- // If we don't have ordinary parameters, then we now must validate our set
- // of implicit parameters. We can only have numbered parameters or it, but
- // they cannot be mixed.
- uint8_t numbered_parameter = 0;
- bool it_parameter = false;
-
- for (size_t index = 0; index < implicit_parameters->size; index++) {
- pm_node_t *node = implicit_parameters->nodes[index];
-
- if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
- if (it_parameter) {
- pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
- } else if (outer_scope_using_numbered_parameters_p(parser)) {
- pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
- } else if (parser->current_scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_INNER) {
- pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
- } else if (pm_token_is_numbered_parameter(node->location.start, node->location.end)) {
- numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->location.start[1] - '0'));
- } else {
- assert(false && "unreachable");
- }
- } else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
- if (numbered_parameter > 0) {
- pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
- } else {
- it_parameter = true;
- }
- }
- }
-
- if (numbered_parameter > 0) {
- // Go through the parent scopes and mark them as being disallowed from
- // using numbered parameters because this inner scope is using them.
- for (pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
- scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
- }
-
- const pm_location_t location = { .start = opening->start, .end = closing->end };
- return (pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
- }
-
- if (it_parameter) {
- return (pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
- }
-
- return NULL;
-}
-
-/**
- * Parse a block.
- */
-static pm_block_node_t *
-parse_block(pm_parser_t *parser, uint16_t depth) {
- pm_token_t opening = parser->previous;
- accept1(parser, PM_TOKEN_NEWLINE);
-
- pm_accepts_block_stack_push(parser, true);
- pm_parser_scope_push(parser, false);
-
- pm_block_parameters_node_t *block_parameters = NULL;
-
- if (accept1(parser, PM_TOKEN_PIPE)) {
- pm_token_t block_parameters_opening = parser->previous;
- if (match1(parser, PM_TOKEN_PIPE)) {
- block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
- parser->command_start = true;
- parser_lex(parser);
- } else {
- block_parameters = parse_block_parameters(parser, true, &block_parameters_opening, false, true, (uint16_t) (depth + 1));
- accept1(parser, PM_TOKEN_NEWLINE);
- parser->command_start = true;
- expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
- }
-
- pm_block_parameters_node_closing_set(block_parameters, &parser->previous);
- }
-
- accept1(parser, PM_TOKEN_NEWLINE);
- pm_node_t *statements = NULL;
-
- if (opening.type == PM_TOKEN_BRACE_LEFT) {
- if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1));
- }
-
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE);
- } else {
- if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
- if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_BLOCK_KEYWORDS, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
- assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_implicit_begin(parser, 0, NULL, opening.start, (pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1));
- }
- }
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END);
- }
-
- pm_constant_id_list_t locals;
- pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
- pm_node_t *parameters = parse_blocklike_parameters(parser, (pm_node_t *) block_parameters, &opening, &parser->previous);
-
- pm_parser_scope_pop(parser);
- pm_accepts_block_stack_pop(parser);
-
- return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->previous);
-}
-
-/**
- * Parse a list of arguments and their surrounding parentheses if they are
- * present. It returns true if it found any pieces of arguments (parentheses,
- * arguments, or blocks).
- */
-static bool
-parse_arguments_list(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_block, bool accepts_command_call, uint16_t depth) {
- bool found = false;
-
- if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
- found |= true;
- arguments->opening_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
-
- if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
- } else {
- pm_accepts_block_stack_push(parser, true);
- parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
-
- if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_type_human(parser->current.type));
- parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
- }
-
- pm_accepts_block_stack_pop(parser);
- arguments->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
- }
- } else if (accepts_command_call && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)) && !match1(parser, PM_TOKEN_BRACE_LEFT)) {
- found |= true;
- pm_accepts_block_stack_push(parser, false);
-
- // If we get here, then the subsequent token cannot be used as an infix
- // operator. In this case we assume the subsequent token is part of an
- // argument to this method call.
- parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1));
-
- // If we have done with the arguments and still not consumed the comma,
- // then we have a trailing comma where we need to check whether it is
- // allowed or not.
- if (parser->previous.type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_type_human(parser->current.type));
- }
-
- pm_accepts_block_stack_pop(parser);
- }
-
- // If we're at the end of the arguments, we can now check if there is a block
- // node that starts with a {. If there is, then we can parse it and add it to
- // the arguments.
- if (accepts_block) {
- pm_block_node_t *block = NULL;
-
- if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
- found |= true;
- block = parse_block(parser, (uint16_t) (depth + 1));
- pm_arguments_validate_block(parser, arguments, block);
- } else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
- found |= true;
- block = parse_block(parser, (uint16_t) (depth + 1));
- }
-
- if (block != NULL) {
- if (arguments->block == NULL && !arguments->has_forwarding) {
- arguments->block = (pm_node_t *) block;
- } else {
- pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
-
- if (arguments->block != NULL) {
- if (arguments->arguments == NULL) {
- arguments->arguments = pm_arguments_node_create(parser);
- }
- pm_arguments_node_arguments_append(arguments->arguments, arguments->block);
- }
- arguments->block = (pm_node_t *) block;
- }
- }
- }
-
- return found;
-}
-
-/**
- * Check that the return is allowed in the current context. If it isn't, add an
- * error to the parser.
- */
-static void
-parse_return(pm_parser_t *parser, pm_node_t *node) {
- bool in_sclass = false;
- for (pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
- switch (context_node->context) {
- case PM_CONTEXT_BEGIN_ELSE:
- case PM_CONTEXT_BEGIN_ENSURE:
- case PM_CONTEXT_BEGIN_RESCUE:
- case PM_CONTEXT_BEGIN:
- case PM_CONTEXT_CASE_IN:
- case PM_CONTEXT_CASE_WHEN:
- case PM_CONTEXT_DEFAULT_PARAMS:
- case PM_CONTEXT_DEFINED:
- case PM_CONTEXT_ELSE:
- case PM_CONTEXT_ELSIF:
- case PM_CONTEXT_EMBEXPR:
- case PM_CONTEXT_FOR_INDEX:
- case PM_CONTEXT_FOR:
- case PM_CONTEXT_IF:
- case PM_CONTEXT_LOOP_PREDICATE:
- case PM_CONTEXT_MAIN:
- case PM_CONTEXT_MULTI_TARGET:
- case PM_CONTEXT_PARENS:
- case PM_CONTEXT_POSTEXE:
- case PM_CONTEXT_PREDICATE:
- case PM_CONTEXT_PREEXE:
- case PM_CONTEXT_RESCUE_MODIFIER:
- case PM_CONTEXT_TERNARY:
- case PM_CONTEXT_UNLESS:
- case PM_CONTEXT_UNTIL:
- case PM_CONTEXT_WHILE:
- // Keep iterating up the lists of contexts, because returns can
- // see through these.
- continue;
- case PM_CONTEXT_SCLASS_ELSE:
- case PM_CONTEXT_SCLASS_ENSURE:
- case PM_CONTEXT_SCLASS_RESCUE:
- case PM_CONTEXT_SCLASS:
- in_sclass = true;
- continue;
- case PM_CONTEXT_CLASS_ELSE:
- case PM_CONTEXT_CLASS_ENSURE:
- case PM_CONTEXT_CLASS_RESCUE:
- case PM_CONTEXT_CLASS:
- case PM_CONTEXT_MODULE_ELSE:
- case PM_CONTEXT_MODULE_ENSURE:
- case PM_CONTEXT_MODULE_RESCUE:
- case PM_CONTEXT_MODULE:
- // These contexts are invalid for a return.
- pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
- return;
- case PM_CONTEXT_BLOCK_BRACES:
- case PM_CONTEXT_BLOCK_ELSE:
- case PM_CONTEXT_BLOCK_ENSURE:
- case PM_CONTEXT_BLOCK_KEYWORDS:
- case PM_CONTEXT_BLOCK_RESCUE:
- case PM_CONTEXT_DEF_ELSE:
- case PM_CONTEXT_DEF_ENSURE:
- case PM_CONTEXT_DEF_PARAMS:
- case PM_CONTEXT_DEF_RESCUE:
- case PM_CONTEXT_DEF:
- case PM_CONTEXT_LAMBDA_BRACES:
- case PM_CONTEXT_LAMBDA_DO_END:
- case PM_CONTEXT_LAMBDA_ELSE:
- case PM_CONTEXT_LAMBDA_ENSURE:
- case PM_CONTEXT_LAMBDA_RESCUE:
- // These contexts are valid for a return, and we should not
- // continue to loop.
- return;
- case PM_CONTEXT_NONE:
- // This case should never happen.
- assert(false && "unreachable");
- break;
- }
- }
- if (in_sclass) {
- pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
- }
-}
-
-/**
- * Check that the block exit (next, break, redo) is allowed in the current
- * context. If it isn't, add an error to the parser.
- */
-static void
-parse_block_exit(pm_parser_t *parser, pm_node_t *node) {
- for (pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
- switch (context_node->context) {
- case PM_CONTEXT_BLOCK_BRACES:
- case PM_CONTEXT_BLOCK_KEYWORDS:
- case PM_CONTEXT_BLOCK_ELSE:
- case PM_CONTEXT_BLOCK_ENSURE:
- case PM_CONTEXT_BLOCK_RESCUE:
- case PM_CONTEXT_DEFINED:
- case PM_CONTEXT_FOR:
- case PM_CONTEXT_LAMBDA_BRACES:
- case PM_CONTEXT_LAMBDA_DO_END:
- case PM_CONTEXT_LAMBDA_ELSE:
- case PM_CONTEXT_LAMBDA_ENSURE:
- case PM_CONTEXT_LAMBDA_RESCUE:
- case PM_CONTEXT_LOOP_PREDICATE:
- case PM_CONTEXT_POSTEXE:
- case PM_CONTEXT_UNTIL:
- case PM_CONTEXT_WHILE:
- // These are the good cases. We're allowed to have a block exit
- // in these contexts.
- return;
- case PM_CONTEXT_DEF:
- case PM_CONTEXT_DEF_PARAMS:
- case PM_CONTEXT_DEF_ELSE:
- case PM_CONTEXT_DEF_ENSURE:
- case PM_CONTEXT_DEF_RESCUE:
- case PM_CONTEXT_MAIN:
- case PM_CONTEXT_PREEXE:
- case PM_CONTEXT_SCLASS:
- case PM_CONTEXT_SCLASS_ELSE:
- case PM_CONTEXT_SCLASS_ENSURE:
- case PM_CONTEXT_SCLASS_RESCUE:
- // These are the bad cases. We're not allowed to have a block
- // exit in these contexts.
- //
- // If we get here, then we're about to mark this block exit
- // as invalid. However, it could later _become_ valid if we
- // find a trailing while/until on the expression. In this
- // case instead of adding the error here, we'll add the
- // block exit to the list of exits for the expression, and
- // the node parsing will handle validating it instead.
- assert(parser->current_block_exits != NULL);
- pm_node_list_append(parser->current_block_exits, node);
- return;
- case PM_CONTEXT_BEGIN_ELSE:
- case PM_CONTEXT_BEGIN_ENSURE:
- case PM_CONTEXT_BEGIN_RESCUE:
- case PM_CONTEXT_BEGIN:
- case PM_CONTEXT_CASE_IN:
- case PM_CONTEXT_CASE_WHEN:
- case PM_CONTEXT_CLASS_ELSE:
- case PM_CONTEXT_CLASS_ENSURE:
- case PM_CONTEXT_CLASS_RESCUE:
- case PM_CONTEXT_CLASS:
- case PM_CONTEXT_DEFAULT_PARAMS:
- case PM_CONTEXT_ELSE:
- case PM_CONTEXT_ELSIF:
- case PM_CONTEXT_EMBEXPR:
- case PM_CONTEXT_FOR_INDEX:
- case PM_CONTEXT_IF:
- case PM_CONTEXT_MODULE_ELSE:
- case PM_CONTEXT_MODULE_ENSURE:
- case PM_CONTEXT_MODULE_RESCUE:
- case PM_CONTEXT_MODULE:
- case PM_CONTEXT_MULTI_TARGET:
- case PM_CONTEXT_PARENS:
- case PM_CONTEXT_PREDICATE:
- case PM_CONTEXT_RESCUE_MODIFIER:
- case PM_CONTEXT_TERNARY:
- case PM_CONTEXT_UNLESS:
- // In these contexts we should continue walking up the list of
- // contexts.
- break;
- case PM_CONTEXT_NONE:
- // This case should never happen.
- assert(false && "unreachable");
- break;
- }
- }
-}
-
-/**
- * When we hit an expression that could contain block exits, we need to stash
- * the previous set and create a new one.
- */
-static pm_node_list_t *
-push_block_exits(pm_parser_t *parser, pm_node_list_t *current_block_exits) {
- pm_node_list_t *previous_block_exits = parser->current_block_exits;
- parser->current_block_exits = current_block_exits;
- return previous_block_exits;
-}
-
-/**
- * If we did not match a trailing while/until and this was the last chance to do
- * so, then all of the block exits in the list are invalid and we need to add an
- * error for each of them.
- */
-static void
-flush_block_exits(pm_parser_t *parser, pm_node_list_t *previous_block_exits) {
- pm_node_t *block_exit;
- PM_NODE_LIST_FOREACH(parser->current_block_exits, index, block_exit) {
- const char *type;
-
- switch (PM_NODE_TYPE(block_exit)) {
- case PM_BREAK_NODE: type = "break"; break;
- case PM_NEXT_NODE: type = "next"; break;
- case PM_REDO_NODE: type = "redo"; break;
- default: assert(false && "unreachable"); type = ""; break;
- }
-
- PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT, type);
- }
-
- parser->current_block_exits = previous_block_exits;
-}
-
-/**
- * Pop the current level of block exits from the parser, and add errors to the
- * parser if any of them are deemed to be invalid.
- */
-static void
-pop_block_exits(pm_parser_t *parser, pm_node_list_t *previous_block_exits) {
- if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
- // If we matched a trailing while/until, then all of the block exits in
- // the contained list are valid. In this case we do not need to do
- // anything.
- parser->current_block_exits = previous_block_exits;
- } else if (previous_block_exits != NULL) {
- // If we did not matching a trailing while/until, then all of the block
- // exits contained in the list are invalid for this specific context.
- // However, they could still become valid in a higher level context if
- // there is another list above this one. In this case we'll push all of
- // the block exits up to the previous list.
- pm_node_list_concat(previous_block_exits, parser->current_block_exits);
- parser->current_block_exits = previous_block_exits;
- } else {
- // If we did not match a trailing while/until and this was the last
- // chance to do so, then all of the block exits in the list are invalid
- // and we need to add an error for each of them.
- flush_block_exits(parser, previous_block_exits);
- }
-}
-
-static inline pm_node_t *
-parse_predicate(pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context, pm_token_t *then_keyword, uint16_t depth) {
- context_push(parser, PM_CONTEXT_PREDICATE);
- pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE;
- pm_node_t *predicate = parse_value_expression(parser, binding_power, true, false, error_id, (uint16_t) (depth + 1));
-
- // Predicates are closed by a term, a "then", or a term and then a "then".
- bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
-
- if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
- predicate_closed = true;
- *then_keyword = parser->previous;
- }
-
- if (!predicate_closed) {
- pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
- }
-
- context_pop(parser);
- return predicate;
-}
-
-static inline pm_node_t *
-parse_conditional(pm_parser_t *parser, pm_context_t context, size_t opening_newline_index, bool if_after_else, uint16_t depth) {
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- pm_token_t keyword = parser->previous;
- pm_token_t then_keyword = not_provided(parser);
-
- pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
- pm_statements_node_t *statements = NULL;
-
- if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = parse_statements(parser, context, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- pm_token_t end_keyword = not_provided(parser);
- pm_node_t *parent = NULL;
-
- switch (context) {
- case PM_CONTEXT_IF:
- parent = (pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
- break;
- case PM_CONTEXT_UNLESS:
- parent = (pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
- break;
- default:
- assert(false && "unreachable");
- break;
- }
-
- pm_node_t *current = parent;
-
- // Parse any number of elsif clauses. This will form a linked list of if
- // nodes pointing to each other from the top.
- if (context == PM_CONTEXT_IF) {
- while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
- if (parser_end_of_line_p(parser)) {
- PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_WARN_KEYWORD_EOL);
- }
-
- parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false);
- pm_token_t elsif_keyword = parser->current;
- parser_lex(parser);
-
- pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
- pm_accepts_block_stack_push(parser, true);
-
- pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
-
- pm_node_t *elsif = (pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
- ((pm_if_node_t *) current)->subsequent = elsif;
- current = elsif;
- }
- }
-
- if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false);
- opening_newline_index = token_newline_index(parser);
-
- parser_lex(parser);
- pm_token_t else_keyword = parser->previous;
-
- pm_accepts_block_stack_push(parser, true);
- pm_statements_node_t *else_statements = parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
-
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword, false, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE);
-
- pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous);
-
- switch (context) {
- case PM_CONTEXT_IF:
- ((pm_if_node_t *) current)->subsequent = (pm_node_t *) else_node;
- break;
- case PM_CONTEXT_UNLESS:
- ((pm_unless_node_t *) parent)->else_clause = else_node;
- break;
- default:
- assert(false && "unreachable");
- break;
- }
- } else {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM);
- }
-
- // Set the appropriate end location for all of the nodes in the subtree.
- switch (context) {
- case PM_CONTEXT_IF: {
- pm_node_t *current = parent;
- bool recursing = true;
-
- while (recursing) {
- switch (PM_NODE_TYPE(current)) {
- case PM_IF_NODE:
- pm_if_node_end_keyword_loc_set((pm_if_node_t *) current, &parser->previous);
- current = ((pm_if_node_t *) current)->subsequent;
- recursing = current != NULL;
- break;
- case PM_ELSE_NODE:
- pm_else_node_end_keyword_loc_set((pm_else_node_t *) current, &parser->previous);
- recursing = false;
- break;
- default: {
- recursing = false;
- break;
- }
- }
- }
- break;
- }
- case PM_CONTEXT_UNLESS:
- pm_unless_node_end_keyword_loc_set((pm_unless_node_t *) parent, &parser->previous);
- break;
- default:
- assert(false && "unreachable");
- break;
- }
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return parent;
-}
-
-/**
- * This macro allows you to define a case statement for all of the keywords.
- * It's meant to be used in a switch statement.
- */
-#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
- case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
- case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
- case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
- case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
- case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
- case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
- case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
- case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
- case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
- case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
-
-/**
- * This macro allows you to define a case statement for all of the operators.
- * It's meant to be used in a switch statement.
- */
-#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
- case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
- case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
- case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
- case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
- case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
- case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
- case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
-
-/**
- * This macro allows you to define a case statement for all of the token types
- * that represent the beginning of nodes that are "primitives" in a pattern
- * matching expression.
- */
-#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
- case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
- case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
- case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
- case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
- case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
- case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
- case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
- case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
-
-/**
- * This macro allows you to define a case statement for all of the token types
- * that could begin a parameter.
- */
-#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
- case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
- case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
- case PM_TOKEN_CLASS_VARIABLE
-
-/**
- * This macro allows you to define a case statement for all of the nodes that
- * can be transformed into write targets.
- */
-#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
- case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
- case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
- case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
-
-// Assert here that the flags are the same so that we can safely switch the type
-// of the node without having to move the flags.
-PM_STATIC_ASSERT(__LINE__, ((int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING), "Expected the flags to match.");
-
-/**
- * If the encoding was explicitly set through the lexing process, then we need
- * to potentially mark the string's flags to indicate how to encode it.
- */
-static inline pm_node_flags_t
-parse_unescaped_encoding(const pm_parser_t *parser) {
- if (parser->explicit_encoding != NULL) {
- if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
- // If the there's an explicit encoding and it's using a UTF-8 escape
- // sequence, then mark the string as UTF-8.
- return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
- } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
- // If there's a non-UTF-8 escape sequence being used, then the
- // string uses the source encoding, unless the source is marked as
- // US-ASCII. In that case the string is forced as ASCII-8BIT in
- // order to keep the string valid.
- return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
- }
- }
- return 0;
-}
-
-/**
- * Parse a node that is part of a string. If the subsequent tokens cannot be
- * parsed as a string part, then NULL is returned.
- */
-static pm_node_t *
-parse_string_part(pm_parser_t *parser, uint16_t depth) {
- switch (parser->current.type) {
- // Here the lexer has returned to us plain string content. In this case
- // we'll create a string node that has no opening or closing and return that
- // as the part. These kinds of parts look like:
- //
- // "aaa #{bbb} #@ccc ddd"
- // ^^^^ ^ ^^^^
- case PM_TOKEN_STRING_CONTENT: {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
-
- pm_node_t *node = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->current, &closing);
- pm_node_flag_set(node, parse_unescaped_encoding(parser));
-
- parser_lex(parser);
- return node;
- }
- // Here the lexer has returned the beginning of an embedded expression. In
- // that case we'll parse the inner statements and return that as the part.
- // These kinds of parts look like:
- //
- // "aaa #{bbb} #@ccc ddd"
- // ^^^^^^
- case PM_TOKEN_EMBEXPR_BEGIN: {
- // Ruby disallows seeing encoding around interpolation in strings,
- // even though it is known at parse time.
- parser->explicit_encoding = NULL;
-
- pm_lex_state_t state = parser->lex_state;
- int brace_nesting = parser->brace_nesting;
-
- parser->brace_nesting = 0;
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser_lex(parser);
-
- pm_token_t opening = parser->previous;
- pm_statements_node_t *statements = NULL;
-
- if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = parse_statements(parser, PM_CONTEXT_EMBEXPR, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- }
-
- parser->brace_nesting = brace_nesting;
- lex_state_set(parser, state);
-
- expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
- pm_token_t closing = parser->previous;
-
- // If this set of embedded statements only contains a single
- // statement, then Ruby does not consider it as a possible statement
- // that could emit a line event.
- if (statements != NULL && statements->body.size == 1) {
- pm_node_flag_unset(statements->body.nodes[0], PM_NODE_FLAG_NEWLINE);
- }
-
- return (pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
- }
-
- // Here the lexer has returned the beginning of an embedded variable.
- // In that case we'll parse the variable and create an appropriate node
- // for it and then return that node. These kinds of parts look like:
- //
- // "aaa #{bbb} #@ccc ddd"
- // ^^^^^
- case PM_TOKEN_EMBVAR: {
- // Ruby disallows seeing encoding around interpolation in strings,
- // even though it is known at parse time.
- parser->explicit_encoding = NULL;
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *variable;
-
- switch (parser->current.type) {
- // In this case a back reference is being interpolated. We'll
- // create a global variable read node.
- case PM_TOKEN_BACK_REFERENCE:
- parser_lex(parser);
- variable = (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->previous);
- break;
- // In this case an nth reference is being interpolated. We'll
- // create a global variable read node.
- case PM_TOKEN_NUMBERED_REFERENCE:
- parser_lex(parser);
- variable = (pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->previous);
- break;
- // In this case a global variable is being interpolated. We'll
- // create a global variable read node.
- case PM_TOKEN_GLOBAL_VARIABLE:
- parser_lex(parser);
- variable = (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->previous);
- break;
- // In this case an instance variable is being interpolated.
- // We'll create an instance variable read node.
- case PM_TOKEN_INSTANCE_VARIABLE:
- parser_lex(parser);
- variable = (pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->previous);
- break;
- // In this case a class variable is being interpolated. We'll
- // create a class variable read node.
- case PM_TOKEN_CLASS_VARIABLE:
- parser_lex(parser);
- variable = (pm_node_t *) pm_class_variable_read_node_create(parser, &parser->previous);
- break;
- // We can hit here if we got an invalid token. In that case
- // we'll not attempt to lex this token and instead just return a
- // missing node.
- default:
- expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
- variable = (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
- break;
- }
-
- return (pm_node_t *) pm_embedded_variable_node_create(parser, &operator, variable);
- }
- default:
- parser_lex(parser);
- pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
- return NULL;
- }
-}
-
-/**
- * When creating a symbol, unary operators that cannot be binary operators
- * automatically drop trailing `@` characters. This happens at the parser level,
- * such that `~@` is parsed as `~` and `!@` is parsed as `!`. We do that here.
- */
-static const uint8_t *
-parse_operator_symbol_name(const pm_token_t *name) {
- switch (name->type) {
- case PM_TOKEN_TILDE:
- case PM_TOKEN_BANG:
- if (name->end[-1] == '@') return name->end - 1;
- /* fallthrough */
- default:
- return name->end;
- }
-}
-
-static pm_node_t *
-parse_operator_symbol(pm_parser_t *parser, const pm_token_t *opening, pm_lex_state_t next_state) {
- pm_token_t closing = not_provided(parser);
- pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->current, &closing);
-
- const uint8_t *end = parse_operator_symbol_name(&parser->current);
-
- if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
- parser_lex(parser);
-
- pm_string_shared_init(&symbol->unescaped, parser->previous.start, end);
- pm_node_flag_set((pm_node_t *) symbol, PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
-
- return (pm_node_t *) symbol;
-}
-
-/**
- * Parse a symbol node. This function will get called immediately after finding
- * a symbol opening token. This handles parsing bare symbols and interpolated
- * symbols.
- */
-static pm_node_t *
-parse_symbol(pm_parser_t *parser, pm_lex_mode_t *lex_mode, pm_lex_state_t next_state, uint16_t depth) {
- const pm_token_t opening = parser->previous;
-
- if (lex_mode->mode != PM_LEX_STRING) {
- if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
-
- switch (parser->current.type) {
- case PM_CASE_OPERATOR:
- return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_INSTANCE_VARIABLE:
- case PM_TOKEN_METHOD_NAME:
- case PM_TOKEN_CLASS_VARIABLE:
- case PM_TOKEN_GLOBAL_VARIABLE:
- case PM_TOKEN_NUMBERED_REFERENCE:
- case PM_TOKEN_BACK_REFERENCE:
- case PM_CASE_KEYWORD:
- parser_lex(parser);
- break;
- default:
- expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
- break;
- }
-
- pm_token_t closing = not_provided(parser);
- pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, &closing);
-
- pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.end);
- pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
-
- return (pm_node_t *) symbol;
- }
-
- if (lex_mode->as.string.interpolation) {
- // If we have the end of the symbol, then we can return an empty symbol.
- if (match1(parser, PM_TOKEN_STRING_END)) {
- if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
- parser_lex(parser);
-
- pm_token_t content = not_provided(parser);
- pm_token_t closing = parser->previous;
- return (pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
- }
-
- // Now we can parse the first part of the symbol.
- pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
-
- // If we got a string part, then it's possible that we could transform
- // what looks like an interpolated symbol into a regular symbol.
- if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
-
- return (pm_node_t *) pm_string_node_to_symbol_node(parser, (pm_string_node_t *) part, &opening, &parser->previous);
- }
-
- pm_interpolated_symbol_node_t *symbol = pm_interpolated_symbol_node_create(parser, &opening, NULL, &opening);
- if (part) pm_interpolated_symbol_node_append(symbol, part);
-
- while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
- pm_interpolated_symbol_node_append(symbol, part);
- }
- }
-
- if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
- }
-
- pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->previous);
- return (pm_node_t *) symbol;
- }
-
- pm_token_t content;
- pm_string_t unescaped;
-
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- content = parser->current;
- unescaped = parser->current_string;
- parser_lex(parser);
-
- // If we have two string contents in a row, then the content of this
- // symbol is split because of heredoc contents. This looks like:
- //
- // <<A; :'a
- // A
- // b'
- //
- // In this case, the best way we have to represent this is as an
- // interpolated string node, so that's what we'll do here.
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- pm_interpolated_symbol_node_t *symbol = pm_interpolated_symbol_node_create(parser, &opening, NULL, &opening);
- pm_token_t bounds = not_provided(parser);
-
- pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
- pm_interpolated_symbol_node_append(symbol, part);
-
- part = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &parser->current, &bounds, &parser->current_string);
- pm_interpolated_symbol_node_append(symbol, part);
-
- if (next_state != PM_LEX_STATE_NONE) {
- lex_state_set(parser, next_state);
- }
-
- parser_lex(parser);
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
-
- pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->previous);
- return (pm_node_t *) symbol;
- }
- } else {
- content = (pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.end, .end = parser->previous.end };
- pm_string_shared_init(&unescaped, content.start, content.end);
- }
-
- if (next_state != PM_LEX_STATE_NONE) {
- lex_state_set(parser, next_state);
- }
-
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
- }
-
- return (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, false));
-}
-
-/**
- * Parse an argument to undef which can either be a bare word, a symbol, a
- * constant, or an interpolated symbol.
- */
-static inline pm_node_t *
-parse_undef_argument(pm_parser_t *parser, uint16_t depth) {
- switch (parser->current.type) {
- case PM_CASE_OPERATOR: {
- const pm_token_t opening = not_provided(parser);
- return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
- }
- case PM_CASE_KEYWORD:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_METHOD_NAME: {
- parser_lex(parser);
-
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, &closing);
-
- pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.end);
- pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
-
- return (pm_node_t *) symbol;
- }
- case PM_TOKEN_SYMBOL_BEGIN: {
- pm_lex_mode_t lex_mode = *parser->lex_modes.current;
- parser_lex(parser);
-
- return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
- }
- default:
- pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
- return (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
- }
-}
-
-/**
- * Parse an argument to alias which can either be a bare word, a symbol, an
- * interpolated symbol or a global variable. If this is the first argument, then
- * we need to set the lex state to PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM
- * between the first and second arguments.
- */
-static inline pm_node_t *
-parse_alias_argument(pm_parser_t *parser, bool first, uint16_t depth) {
- switch (parser->current.type) {
- case PM_CASE_OPERATOR: {
- const pm_token_t opening = not_provided(parser);
- return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
- }
- case PM_CASE_KEYWORD:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_METHOD_NAME: {
- if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
- parser_lex(parser);
-
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, &closing);
-
- pm_string_shared_init(&symbol->unescaped, parser->previous.start, parser->previous.end);
- pm_node_flag_set((pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->previous, &symbol->unescaped, false));
-
- return (pm_node_t *) symbol;
- }
- case PM_TOKEN_SYMBOL_BEGIN: {
- pm_lex_mode_t lex_mode = *parser->lex_modes.current;
- parser_lex(parser);
-
- return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
- }
- case PM_TOKEN_BACK_REFERENCE:
- parser_lex(parser);
- return (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->previous);
- case PM_TOKEN_NUMBERED_REFERENCE:
- parser_lex(parser);
- return (pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->previous);
- case PM_TOKEN_GLOBAL_VARIABLE:
- parser_lex(parser);
- return (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->previous);
- default:
- pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
- return (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
- }
-}
-
-/**
- * Parse an identifier into either a local variable read. If the local variable
- * is not found, it returns NULL instead.
- */
-static pm_node_t *
-parse_variable(pm_parser_t *parser) {
- pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &parser->previous);
- int depth;
-
- if ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1) {
- return (pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, (uint32_t) depth, false);
- }
-
- pm_scope_t *current_scope = parser->current_scope;
- if (!current_scope->closed && !(current_scope->parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
- if (pm_token_is_numbered_parameter(parser->previous.start, parser->previous.end)) {
- // When you use a numbered parameter, it implies the existence of
- // all of the locals that exist before it. For example, referencing
- // _2 means that _1 must exist. Therefore here we loop through all
- // of the possibilities and add them into the constant pool.
- uint8_t maximum = (uint8_t) (parser->previous.start[1] - '0');
- for (uint8_t number = 1; number <= maximum; number++) {
- pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
- }
-
- if (!match1(parser, PM_TOKEN_EQUAL)) {
- parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_FOUND;
- }
-
- pm_node_t *node = (pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0, false);
- pm_node_list_append(&current_scope->implicit_parameters, node);
-
- return node;
- } else if ((parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) && pm_token_is_it(parser->previous.start, parser->previous.end)) {
- pm_node_t *node = (pm_node_t *) pm_it_local_variable_read_node_create(parser, &parser->previous);
- pm_node_list_append(&current_scope->implicit_parameters, node);
-
- return node;
- }
- }
-
- return NULL;
-}
-
-/**
- * Parse an identifier into either a local variable read or a call.
- */
-static pm_node_t *
-parse_variable_call(pm_parser_t *parser) {
- pm_node_flags_t flags = 0;
-
- if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->previous.end[-1] != '!') && (parser->previous.end[-1] != '?')) {
- pm_node_t *node = parse_variable(parser);
- if (node != NULL) return node;
- flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
- }
-
- pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->previous);
- pm_node_flag_set((pm_node_t *)node, flags);
-
- return (pm_node_t *) node;
-}
-
-/**
- * Parse the method definition name based on the current token available on the
- * parser. If it does not match a valid method definition name, then a missing
- * token is returned.
- */
-static inline pm_token_t
-parse_method_definition_name(pm_parser_t *parser) {
- switch (parser->current.type) {
- case PM_CASE_KEYWORD:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_METHOD_NAME:
- parser_lex(parser);
- return parser->previous;
- case PM_TOKEN_IDENTIFIER:
- pm_refute_numbered_parameter(parser, parser->current.start, parser->current.end);
- parser_lex(parser);
- return parser->previous;
- case PM_CASE_OPERATOR:
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- parser_lex(parser);
- return parser->previous;
- default:
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_DEF_NAME, pm_token_type_human(parser->current.type));
- return (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->current.start, .end = parser->current.end };
- }
-}
-
-static void
-parse_heredoc_dedent_string(pm_string_t *string, size_t common_whitespace) {
- // Get a reference to the string struct that is being held by the string
- // node. This is the value we're going to actually manipulate.
- pm_string_ensure_owned(string);
-
- // Now get the bounds of the existing string. We'll use this as a
- // destination to move bytes into. We'll also use it for bounds checking
- // since we don't require that these strings be null terminated.
- size_t dest_length = pm_string_length(string);
- const uint8_t *source_cursor = (uint8_t *) string->source;
- const uint8_t *source_end = source_cursor + dest_length;
-
- // We're going to move bytes backward in the string when we get leading
- // whitespace, so we'll maintain a pointer to the current position in the
- // string that we're writing to.
- size_t trimmed_whitespace = 0;
-
- // While we haven't reached the amount of common whitespace that we need to
- // trim and we haven't reached the end of the string, we'll keep trimming
- // whitespace. Trimming in this context means skipping over these bytes such
- // that they aren't copied into the new string.
- while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
- if (*source_cursor == '\t') {
- trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
- if (trimmed_whitespace > common_whitespace) break;
- } else {
- trimmed_whitespace++;
- }
-
- source_cursor++;
- dest_length--;
- }
-
- memmove((uint8_t *) string->source, source_cursor, (size_t) (source_end - source_cursor));
- string->length = dest_length;
-}
-
-/**
- * Take a heredoc node that is indented by a ~ and trim the leading whitespace.
- */
-static void
-parse_heredoc_dedent(pm_parser_t *parser, pm_node_list_t *nodes, size_t common_whitespace) {
- // The next node should be dedented if it's the first node in the list or if
- // it follows a string node.
- bool dedent_next = true;
-
- // Iterate over all nodes, and trim whitespace accordingly. We're going to
- // keep around two indices: a read and a write. If we end up trimming all of
- // the whitespace from a node, then we'll drop it from the list entirely.
- size_t write_index = 0;
-
- pm_node_t *node;
- PM_NODE_LIST_FOREACH(nodes, read_index, node) {
- // We're not manipulating child nodes that aren't strings. In this case
- // we'll skip past it and indicate that the subsequent node should not
- // be dedented.
- if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
- nodes->nodes[write_index++] = node;
- dedent_next = false;
- continue;
- }
-
- pm_string_node_t *string_node = ((pm_string_node_t *) node);
- if (dedent_next) {
- parse_heredoc_dedent_string(&string_node->unescaped, common_whitespace);
- }
-
- if (string_node->unescaped.length == 0) {
- pm_node_destroy(parser, node);
- } else {
- nodes->nodes[write_index++] = node;
- }
-
- // We always dedent the next node if it follows a string node.
- dedent_next = true;
- }
-
- nodes->size = write_index;
-}
-
-/**
- * Return a string content token at a particular location that is empty.
- */
-static pm_token_t
-parse_strings_empty_content(const uint8_t *location) {
- return (pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
-}
-
-/**
- * Parse a set of strings that could be concatenated together.
- */
-static inline pm_node_t *
-parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint16_t depth) {
- assert(parser->current.type == PM_TOKEN_STRING_BEGIN);
- bool concating = false;
-
- while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
- pm_node_t *node = NULL;
-
- // Here we have found a string literal. We'll parse it and add it to
- // the list of strings.
- const pm_lex_mode_t *lex_mode = parser->lex_modes.current;
- assert(lex_mode->mode == PM_LEX_STRING);
- bool lex_interpolation = lex_mode->as.string.interpolation;
- bool label_allowed = lex_mode->as.string.label_allowed && accepts_label;
-
- pm_token_t opening = parser->current;
- parser_lex(parser);
-
- if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
- // If we get here, then we have an end immediately after a
- // start. In that case we'll create an empty content token and
- // return an uninterpolated string.
- pm_token_t content = parse_strings_empty_content(parser->previous.start);
- pm_string_node_t *string = pm_string_node_create(parser, &opening, &content, &parser->previous);
-
- pm_string_shared_init(&string->unescaped, content.start, content.end);
- node = (pm_node_t *) string;
- } else if (accept1(parser, PM_TOKEN_LABEL_END)) {
- // If we get here, then we have an end of a label immediately
- // after a start. In that case we'll create an empty symbol
- // node.
- pm_token_t content = parse_strings_empty_content(parser->previous.start);
- pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &content, &parser->previous);
-
- pm_string_shared_init(&symbol->unescaped, content.start, content.end);
- node = (pm_node_t *) symbol;
-
- if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
- } else if (!lex_interpolation) {
- // If we don't accept interpolation then we expect the string to
- // start with a single string content node.
- pm_string_t unescaped;
- pm_token_t content;
-
- if (match1(parser, PM_TOKEN_EOF)) {
- unescaped = PM_STRING_EMPTY;
- content = not_provided(parser);
- } else {
- unescaped = parser->current_string;
- expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
- content = parser->previous;
- }
-
- // It is unfortunately possible to have multiple string content
- // nodes in a row in the case that there's heredoc content in
- // the middle of the string, like this cursed example:
- //
- // <<-END+'b
- // a
- // END
- // c'+'d'
- //
- // In that case we need to switch to an interpolated string to
- // be able to contain all of the parts.
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- pm_node_list_t parts = { 0 };
-
- pm_token_t delimiters = not_provided(parser);
- pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
- pm_node_list_append(&parts, part);
-
- do {
- part = (pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->current, &delimiters);
- pm_node_list_append(&parts, part);
- parser_lex(parser);
- } while (match1(parser, PM_TOKEN_STRING_CONTENT));
-
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
- node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous);
-
- pm_node_list_free(&parts);
- } else if (accept1(parser, PM_TOKEN_LABEL_END)) {
- node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, true));
- if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
- } else if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
- node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped);
- } else if (accept1(parser, PM_TOKEN_STRING_END)) {
- node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
- } else {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_type_human(parser->previous.type));
- parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
- node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
- }
- } else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- // In this case we've hit string content so we know the string
- // at least has something in it. We'll need to check if the
- // following token is the end (in which case we can return a
- // plain string) or if it's not then it has interpolation.
- pm_token_t content = parser->current;
- pm_string_t unescaped = parser->current_string;
- parser_lex(parser);
-
- if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped);
- pm_node_flag_set(node, parse_unescaped_encoding(parser));
-
- // Kind of odd behavior, but basically if we have an
- // unterminated string and it ends in a newline, we back up one
- // character so that the error message is on the last line of
- // content in the string.
- if (!accept1(parser, PM_TOKEN_STRING_END)) {
- const uint8_t *location = parser->previous.end;
- if (location > parser->start && location[-1] == '\n') location--;
- pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
-
- parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
- }
- } else if (accept1(parser, PM_TOKEN_LABEL_END)) {
- node = (pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped, true));
- if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
- } else {
- // If we get here, then we have interpolation so we'll need
- // to create a string or symbol node with interpolation.
- pm_node_list_t parts = { 0 };
- pm_token_t string_opening = not_provided(parser);
- pm_token_t string_closing = not_provided(parser);
-
- pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->previous, &string_closing, &unescaped);
- pm_node_flag_set(part, parse_unescaped_encoding(parser));
- pm_node_list_append(&parts, part);
-
- while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
- if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
- pm_node_list_append(&parts, part);
- }
- }
-
- if (accept1(parser, PM_TOKEN_LABEL_END)) {
- node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous);
- if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
- } else if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
- node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current);
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
- node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous);
- }
-
- pm_node_list_free(&parts);
- }
- } else {
- // If we get here, then the first part of the string is not plain
- // string content, in which case we need to parse the string as an
- // interpolated string.
- pm_node_list_t parts = { 0 };
- pm_node_t *part;
-
- while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
- if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
- pm_node_list_append(&parts, part);
- }
- }
-
- if (accept1(parser, PM_TOKEN_LABEL_END)) {
- node = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous);
- if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
- } else if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
- node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current);
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
- node = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous);
- }
-
- pm_node_list_free(&parts);
- }
-
- if (current == NULL) {
- // If the node we just parsed is a symbol node, then we can't
- // concatenate it with anything else, so we can now return that
- // node.
- if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
- return node;
- }
-
- // If we don't already have a node, then it's fine and we can just
- // set the result to be the node we just parsed.
- current = node;
- } else {
- // Otherwise we need to check the type of the node we just parsed.
- // If it cannot be concatenated with the previous node, then we'll
- // need to add a syntax error.
- if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
- pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
- }
-
- // If we haven't already created our container for concatenation,
- // we'll do that now.
- if (!concating) {
- concating = true;
- pm_token_t bounds = not_provided(parser);
-
- pm_interpolated_string_node_t *container = pm_interpolated_string_node_create(parser, &bounds, NULL, &bounds);
- pm_interpolated_string_node_append(container, current);
- current = (pm_node_t *) container;
- }
-
- pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, node);
- }
- }
-
- return current;
-}
-
-#define PM_PARSE_PATTERN_SINGLE 0
-#define PM_PARSE_PATTERN_TOP 1
-#define PM_PARSE_PATTERN_MULTI 2
-
-static pm_node_t *
-parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth);
-
-/**
- * Add the newly created local to the list of captures for this pattern matching
- * expression. If it is duplicated from a previous local, then we'll need to add
- * an error to the parser.
- */
-static void
-parse_pattern_capture(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_constant_id_t capture, const pm_location_t *location) {
- // Skip this capture if it starts with an underscore.
- if (*location->start == '_') return;
-
- if (pm_constant_id_list_includes(captures, capture)) {
- pm_parser_err(parser, location->start, location->end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
- } else {
- pm_constant_id_list_append(captures, capture);
- }
-}
-
-/**
- * Accept any number of constants joined by :: delimiters.
- */
-static pm_node_t *
-parse_pattern_constant_path(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *node, uint16_t depth) {
- // Now, if there are any :: operators that follow, parse them as constant
- // path nodes.
- while (accept1(parser, PM_TOKEN_COLON_COLON)) {
- pm_token_t delimiter = parser->previous;
- expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- node = (pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->previous);
- }
-
- // If there is a [ or ( that follows, then this is part of a larger pattern
- // expression. We'll parse the inner pattern here, then modify the returned
- // inner pattern with our constant path attached.
- if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
- return node;
- }
-
- pm_token_t opening;
- pm_token_t closing;
- pm_node_t *inner = NULL;
-
- if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
- opening = parser->previous;
- accept1(parser, PM_TOKEN_NEWLINE);
-
- if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
- }
-
- closing = parser->previous;
- } else {
- parser_lex(parser);
- opening = parser->previous;
- accept1(parser, PM_TOKEN_NEWLINE);
-
- if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
- }
-
- closing = parser->previous;
- }
-
- if (!inner) {
- // If there was no inner pattern, then we have something like Foo() or
- // Foo[]. In that case we'll create an array pattern with no requireds.
- return (pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
- }
-
- // Now that we have the inner pattern, check to see if it's an array, find,
- // or hash pattern. If it is, then we'll attach our constant path to it if
- // it doesn't already have a constant. If it's not one of those node types
- // or it does have a constant, then we'll create an array pattern.
- switch (PM_NODE_TYPE(inner)) {
- case PM_ARRAY_PATTERN_NODE: {
- pm_array_pattern_node_t *pattern_node = (pm_array_pattern_node_t *) inner;
-
- if (pattern_node->constant == NULL && pattern_node->opening_loc.start == NULL) {
- pattern_node->base.location.start = node->location.start;
- pattern_node->base.location.end = closing.end;
-
- pattern_node->constant = node;
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
-
- return (pm_node_t *) pattern_node;
- }
-
- break;
- }
- case PM_FIND_PATTERN_NODE: {
- pm_find_pattern_node_t *pattern_node = (pm_find_pattern_node_t *) inner;
-
- if (pattern_node->constant == NULL && pattern_node->opening_loc.start == NULL) {
- pattern_node->base.location.start = node->location.start;
- pattern_node->base.location.end = closing.end;
-
- pattern_node->constant = node;
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
-
- return (pm_node_t *) pattern_node;
- }
-
- break;
- }
- case PM_HASH_PATTERN_NODE: {
- pm_hash_pattern_node_t *pattern_node = (pm_hash_pattern_node_t *) inner;
-
- if (pattern_node->constant == NULL && pattern_node->opening_loc.start == NULL) {
- pattern_node->base.location.start = node->location.start;
- pattern_node->base.location.end = closing.end;
-
- pattern_node->constant = node;
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
-
- return (pm_node_t *) pattern_node;
- }
-
- break;
- }
- default:
- break;
- }
-
- // If we got here, then we didn't return one of the inner patterns by
- // attaching its constant. In this case we'll create an array pattern and
- // attach our constant to it.
- pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
- pm_array_pattern_node_requireds_append(pattern_node, inner);
- return (pm_node_t *) pattern_node;
-}
-
-/**
- * Parse a rest pattern.
- */
-static pm_splat_node_t *
-parse_pattern_rest(pm_parser_t *parser, pm_constant_id_list_t *captures) {
- assert(parser->previous.type == PM_TOKEN_USTAR);
- pm_token_t operator = parser->previous;
- pm_node_t *name = NULL;
-
- // Rest patterns don't necessarily have a name associated with them. So we
- // will check for that here. If they do, then we'll add it to the local
- // table since this pattern will cause it to become a local variable.
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- pm_token_t identifier = parser->previous;
- pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
-
- int depth;
- if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
- pm_parser_local_add(parser, constant_id, identifier.start, identifier.end, 0);
- }
-
- parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
- name = (pm_node_t *) pm_local_variable_target_node_create(
- parser,
- &PM_LOCATION_TOKEN_VALUE(&identifier),
- constant_id,
- (uint32_t) (depth == -1 ? 0 : depth)
- );
- }
-
- // Finally we can return the created node.
- return pm_splat_node_create(parser, &operator, name);
-}
-
-/**
- * Parse a keyword rest node.
- */
-static pm_node_t *
-parse_pattern_keyword_rest(pm_parser_t *parser, pm_constant_id_list_t *captures) {
- assert(parser->current.type == PM_TOKEN_USTAR_STAR);
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *value = NULL;
-
- if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
- return (pm_node_t *) pm_no_keywords_parameter_node_create(parser, &operator, &parser->previous);
- }
-
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
-
- int depth;
- if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
- pm_parser_local_add(parser, constant_id, parser->previous.start, parser->previous.end, 0);
- }
-
- parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous));
- value = (pm_node_t *) pm_local_variable_target_node_create(
- parser,
- &PM_LOCATION_TOKEN_VALUE(&parser->previous),
- constant_id,
- (uint32_t) (depth == -1 ? 0 : depth)
- );
- }
-
- return (pm_node_t *) pm_assoc_splat_node_create(parser, value, &operator);
-}
-
-/**
- * Check that the slice of the source given by the bounds parameters constitutes
- * a valid local variable name.
- */
-static bool
-pm_slice_is_valid_local(const pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- ptrdiff_t length = end - start;
- if (length == 0) return false;
-
- // First ensure that it starts with a valid identifier starting character.
- size_t width = char_is_identifier_start(parser, start);
- if (width == 0) return false;
-
- // Next, ensure that it's not an uppercase character.
- if (parser->encoding_changed) {
- if (parser->encoding->isupper_char(start, length)) return false;
- } else {
- if (pm_encoding_utf_8_isupper_char(start, length)) return false;
- }
-
- // Next, iterate through all of the bytes of the string to ensure that they
- // are all valid identifier characters.
- const uint8_t *cursor = start + width;
- while ((cursor < end) && (width = char_is_identifier(parser, cursor))) cursor += width;
- return cursor == end;
-}
-
-/**
- * Create an implicit node for the value of a hash pattern that has omitted the
- * value. This will use an implicit local variable target.
- */
-static pm_node_t *
-parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_symbol_node_t *key) {
- const pm_location_t *value_loc = &((pm_symbol_node_t *) key)->value_loc;
-
- pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, value_loc->start, value_loc->end);
- int depth = -1;
-
- if (pm_slice_is_valid_local(parser, value_loc->start, value_loc->end)) {
- depth = pm_parser_local_depth_constant_id(parser, constant_id);
- } else {
- pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
-
- if ((value_loc->end > value_loc->start) && ((value_loc->end[-1] == '!') || (value_loc->end[-1] == '?'))) {
- PM_PARSER_ERR_LOCATION_FORMAT(parser, value_loc, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (int) (value_loc->end - value_loc->start), (const char *) value_loc->start);
- }
- }
-
- if (depth == -1) {
- pm_parser_local_add(parser, constant_id, value_loc->start, value_loc->end, 0);
- }
-
- parse_pattern_capture(parser, captures, constant_id, value_loc);
- pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
- parser,
- value_loc,
- constant_id,
- (uint32_t) (depth == -1 ? 0 : depth)
- );
-
- return (pm_node_t *) pm_implicit_node_create(parser, (pm_node_t *) target);
-}
-
-/**
- * Add a node to the list of keys for a hash pattern, and if it is a duplicate
- * then add an error to the parser.
- */
-static void
-parse_pattern_hash_key(pm_parser_t *parser, pm_static_literals_t *keys, pm_node_t *node) {
- if (pm_static_literals_add(&parser->newline_list, parser->start_line, keys, node, true) != NULL) {
- pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
- }
-}
-
-/**
- * Parse a hash pattern.
- */
-static pm_hash_pattern_node_t *
-parse_pattern_hash(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *first_node, uint16_t depth) {
- pm_node_list_t assocs = { 0 };
- pm_static_literals_t keys = { 0 };
- pm_node_t *rest = NULL;
-
- switch (PM_NODE_TYPE(first_node)) {
- case PM_ASSOC_SPLAT_NODE:
- case PM_NO_KEYWORDS_PARAMETER_NODE:
- rest = first_node;
- break;
- case PM_SYMBOL_NODE: {
- if (pm_symbol_node_label_p(first_node)) {
- parse_pattern_hash_key(parser, &keys, first_node);
- pm_node_t *value;
-
- if (match8(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF)) {
- // Otherwise, we will create an implicit local variable
- // target for the value.
- value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) first_node);
- } else {
- // Here we have a value for the first assoc in the list, so
- // we will parse it now.
- value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
- }
-
- pm_token_t operator = not_provided(parser);
- pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, first_node, &operator, value);
-
- pm_node_list_append(&assocs, assoc);
- break;
- }
- }
- /* fallthrough */
- default: {
- // If we get anything else, then this is an error. For this we'll
- // create a missing node for the value and create an assoc node for
- // the first node in the list.
- pm_diagnostic_id_t diag_id = PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE) ? PM_ERR_PATTERN_HASH_KEY_INTERPOLATED : PM_ERR_PATTERN_HASH_KEY_LABEL;
- pm_parser_err_node(parser, first_node, diag_id);
-
- pm_token_t operator = not_provided(parser);
- pm_node_t *value = (pm_node_t *) pm_missing_node_create(parser, first_node->location.start, first_node->location.end);
- pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, first_node, &operator, value);
-
- pm_node_list_append(&assocs, assoc);
- break;
- }
- }
-
- // If there are any other assocs, then we'll parse them now.
- while (accept1(parser, PM_TOKEN_COMMA)) {
- // Here we need to break to support trailing commas.
- if (match7(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF)) {
- // Trailing commas are not allowed to follow a rest pattern.
- if (rest != NULL) {
- pm_parser_err_token(parser, &parser->current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
- }
-
- break;
- }
-
- if (match1(parser, PM_TOKEN_USTAR_STAR)) {
- pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
-
- if (rest == NULL) {
- rest = assoc;
- } else {
- pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
- pm_node_list_append(&assocs, assoc);
- }
- } else {
- pm_node_t *key;
-
- if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
- key = parse_strings(parser, NULL, true, (uint16_t) (depth + 1));
-
- if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
- pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
- } else if (!pm_symbol_node_label_p(key)) {
- pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
- }
- } else {
- expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
- key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
- }
-
- parse_pattern_hash_key(parser, &keys, key);
- pm_node_t *value = NULL;
-
- if (match7(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key);
- } else {
- value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
- }
-
- pm_token_t operator = not_provided(parser);
- pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, key, &operator, value);
-
- if (rest != NULL) {
- pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
- }
-
- pm_node_list_append(&assocs, assoc);
- }
- }
-
- pm_hash_pattern_node_t *node = pm_hash_pattern_node_node_list_create(parser, &assocs, rest);
- xfree(assocs.nodes);
-
- pm_static_literals_free(&keys);
- return node;
-}
-
-/**
- * Parse a pattern expression primitive.
- */
-static pm_node_t *
-parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_diagnostic_id_t diag_id, uint16_t depth) {
- switch (parser->current.type) {
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_METHOD_NAME: {
- parser_lex(parser);
- pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
-
- int depth;
- if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
- pm_parser_local_add(parser, constant_id, parser->previous.start, parser->previous.end, 0);
- }
-
- parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous));
- return (pm_node_t *) pm_local_variable_target_node_create(
- parser,
- &PM_LOCATION_TOKEN_VALUE(&parser->previous),
- constant_id,
- (uint32_t) (depth == -1 ? 0 : depth)
- );
- }
- case PM_TOKEN_BRACKET_LEFT_ARRAY: {
- pm_token_t opening = parser->current;
- parser_lex(parser);
-
- if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- // If we have an empty array pattern, then we'll just return a new
- // array pattern node.
- return (pm_node_t *) pm_array_pattern_node_empty_create(parser, &opening, &parser->previous);
- }
-
- // Otherwise, we'll parse the inner pattern, then deal with it depending
- // on the type it returns.
- pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
-
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET);
- pm_token_t closing = parser->previous;
-
- switch (PM_NODE_TYPE(inner)) {
- case PM_ARRAY_PATTERN_NODE: {
- pm_array_pattern_node_t *pattern_node = (pm_array_pattern_node_t *) inner;
- if (pattern_node->opening_loc.start == NULL) {
- pattern_node->base.location.start = opening.start;
- pattern_node->base.location.end = closing.end;
-
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
-
- return (pm_node_t *) pattern_node;
- }
-
- break;
- }
- case PM_FIND_PATTERN_NODE: {
- pm_find_pattern_node_t *pattern_node = (pm_find_pattern_node_t *) inner;
- if (pattern_node->opening_loc.start == NULL) {
- pattern_node->base.location.start = opening.start;
- pattern_node->base.location.end = closing.end;
-
- pattern_node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pattern_node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
-
- return (pm_node_t *) pattern_node;
- }
-
- break;
- }
- default:
- break;
- }
-
- pm_array_pattern_node_t *node = pm_array_pattern_node_empty_create(parser, &opening, &closing);
- pm_array_pattern_node_requireds_append(node, inner);
- return (pm_node_t *) node;
- }
- case PM_TOKEN_BRACE_LEFT: {
- bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
- parser->pattern_matching_newlines = false;
-
- pm_hash_pattern_node_t *node;
- pm_token_t opening = parser->current;
- parser_lex(parser);
-
- if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
- // If we have an empty hash pattern, then we'll just return a new hash
- // pattern node.
- node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->previous);
- } else {
- pm_node_t *first_node;
-
- switch (parser->current.type) {
- case PM_TOKEN_LABEL:
- parser_lex(parser);
- first_node = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
- break;
- case PM_TOKEN_USTAR_STAR:
- first_node = parse_pattern_keyword_rest(parser, captures);
- break;
- case PM_TOKEN_STRING_BEGIN:
- first_node = parse_expression(parser, PM_BINDING_POWER_MAX, false, true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
- break;
- default: {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_type_human(parser->current.type));
- parser_lex(parser);
-
- first_node = (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
- break;
- }
- }
-
- node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
-
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE);
- pm_token_t closing = parser->previous;
-
- node->base.location.start = opening.start;
- node->base.location.end = closing.end;
-
- node->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- node->closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
- }
-
- parser->pattern_matching_newlines = previous_pattern_matching_newlines;
- return (pm_node_t *) node;
- }
- case PM_TOKEN_UDOT_DOT:
- case PM_TOKEN_UDOT_DOT_DOT: {
- pm_token_t operator = parser->current;
- parser_lex(parser);
-
- // Since we have a unary range operator, we need to parse the subsequent
- // expression as the right side of the range.
- switch (parser->current.type) {
- case PM_CASE_PRIMITIVE: {
- pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, false, false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
- }
- default: {
- pm_parser_err_token(parser, &operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
- pm_node_t *right = (pm_node_t *) pm_missing_node_create(parser, operator.start, operator.end);
- return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
- }
- }
- }
- case PM_CASE_PRIMITIVE: {
- pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX, false, true, diag_id, (uint16_t) (depth + 1));
-
- // If we found a label, we need to immediately return to the caller.
- if (pm_symbol_node_label_p(node)) return node;
-
- // Now that we have a primitive, we need to check if it's part of a range.
- if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
- pm_token_t operator = parser->previous;
-
- // Now that we have the operator, we need to check if this is followed
- // by another expression. If it is, then we will create a full range
- // node. Otherwise, we'll create an endless range.
- switch (parser->current.type) {
- case PM_CASE_PRIMITIVE: {
- pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, false, false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_range_node_create(parser, node, &operator, right);
- }
- default:
- return (pm_node_t *) pm_range_node_create(parser, node, &operator, NULL);
- }
- }
-
- return node;
- }
- case PM_TOKEN_CARET: {
- parser_lex(parser);
- pm_token_t operator = parser->previous;
-
- // At this point we have a pin operator. We need to check the subsequent
- // expression to determine if it's a variable or an expression.
- switch (parser->current.type) {
- case PM_TOKEN_IDENTIFIER: {
- parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) parse_variable(parser);
-
- if (variable == NULL) {
- PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
- variable = (pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->previous, 0);
- }
-
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- case PM_TOKEN_INSTANCE_VARIABLE: {
- parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->previous);
-
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- case PM_TOKEN_CLASS_VARIABLE: {
- parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) pm_class_variable_read_node_create(parser, &parser->previous);
-
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- case PM_TOKEN_GLOBAL_VARIABLE: {
- parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->previous);
-
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- case PM_TOKEN_NUMBERED_REFERENCE: {
- parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->previous);
-
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- case PM_TOKEN_BACK_REFERENCE: {
- parser_lex(parser);
- pm_node_t *variable = (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->previous);
-
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- case PM_TOKEN_PARENTHESIS_LEFT: {
- bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
- parser->pattern_matching_newlines = false;
-
- pm_token_t lparen = parser->current;
- parser_lex(parser);
-
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT, true, false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
- parser->pattern_matching_newlines = previous_pattern_matching_newlines;
-
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
- return (pm_node_t *) pm_pinned_expression_node_create(parser, expression, &operator, &lparen, &parser->previous);
- }
- default: {
- // If we get here, then we have a pin operator followed by something
- // not understood. We'll create a missing node and return that.
- pm_parser_err_token(parser, &operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
- pm_node_t *variable = (pm_node_t *) pm_missing_node_create(parser, operator.start, operator.end);
- return (pm_node_t *) pm_pinned_variable_node_create(parser, &operator, variable);
- }
- }
- }
- case PM_TOKEN_UCOLON_COLON: {
- pm_token_t delimiter = parser->current;
- parser_lex(parser);
-
- expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- pm_constant_path_node_t *node = pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous);
-
- return parse_pattern_constant_path(parser, captures, (pm_node_t *) node, (uint16_t) (depth + 1));
- }
- case PM_TOKEN_CONSTANT: {
- pm_token_t constant = parser->current;
- parser_lex(parser);
-
- pm_node_t *node = (pm_node_t *) pm_constant_read_node_create(parser, &constant);
- return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
- }
- default:
- pm_parser_err_current(parser, diag_id);
- return (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
- }
-}
-
-/**
- * Parse any number of primitives joined by alternation and ended optionally by
- * assignment.
- */
-static pm_node_t *
-parse_pattern_primitives(pm_parser_t *parser, pm_constant_id_list_t *captures, pm_node_t *first_node, pm_diagnostic_id_t diag_id, uint16_t depth) {
- pm_node_t *node = first_node;
-
- while ((node == NULL) || accept1(parser, PM_TOKEN_PIPE)) {
- pm_token_t operator = parser->previous;
-
- switch (parser->current.type) {
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_BRACKET_LEFT_ARRAY:
- case PM_TOKEN_BRACE_LEFT:
- case PM_TOKEN_CARET:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_UCOLON_COLON:
- case PM_TOKEN_UDOT_DOT:
- case PM_TOKEN_UDOT_DOT_DOT:
- case PM_CASE_PRIMITIVE: {
- if (node == NULL) {
- node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
- } else {
- pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
- node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &operator);
- }
-
- break;
- }
- case PM_TOKEN_PARENTHESIS_LEFT:
- case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
- pm_token_t opening = parser->current;
- parser_lex(parser);
-
- pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN);
- pm_node_t *right = (pm_node_t *) pm_parentheses_node_create(parser, &opening, body, &parser->previous);
-
- if (node == NULL) {
- node = right;
- } else {
- node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &operator);
- }
-
- break;
- }
- default: {
- pm_parser_err_current(parser, diag_id);
- pm_node_t *right = (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
-
- if (node == NULL) {
- node = right;
- } else {
- node = (pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &operator);
- }
-
- break;
- }
- }
- }
-
- // If we have an =>, then we are assigning this pattern to a variable.
- // In this case we should create an assignment node.
- while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
- pm_token_t operator = parser->previous;
- expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
-
- pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
- int depth;
-
- if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
- pm_parser_local_add(parser, constant_id, parser->previous.start, parser->previous.end, 0);
- }
-
- parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->previous));
- pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
- parser,
- &PM_LOCATION_TOKEN_VALUE(&parser->previous),
- constant_id,
- (uint32_t) (depth == -1 ? 0 : depth)
- );
-
- node = (pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &operator);
- }
-
- return node;
-}
-
-/**
- * Parse a pattern matching expression.
- */
-static pm_node_t *
-parse_pattern(pm_parser_t *parser, pm_constant_id_list_t *captures, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
- pm_node_t *node = NULL;
-
- bool leading_rest = false;
- bool trailing_rest = false;
-
- switch (parser->current.type) {
- case PM_TOKEN_LABEL: {
- parser_lex(parser);
- pm_node_t *key = (pm_node_t *) pm_symbol_node_label_create(parser, &parser->previous);
- node = (pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
-
- if (!(flags & PM_PARSE_PATTERN_TOP)) {
- pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
- }
-
- return node;
- }
- case PM_TOKEN_USTAR_STAR: {
- node = parse_pattern_keyword_rest(parser, captures);
- node = (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
-
- if (!(flags & PM_PARSE_PATTERN_TOP)) {
- pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
- }
-
- return node;
- }
- case PM_TOKEN_STRING_BEGIN: {
- // We need special handling for string beginnings because they could
- // be dynamic symbols leading to hash patterns.
- node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
-
- if (pm_symbol_node_label_p(node)) {
- node = (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
-
- if (!(flags & PM_PARSE_PATTERN_TOP)) {
- pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
- }
-
- return node;
- }
-
- node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
- break;
- }
- case PM_TOKEN_USTAR: {
- if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
- parser_lex(parser);
- node = (pm_node_t *) parse_pattern_rest(parser, captures);
- leading_rest = true;
- break;
- }
- }
- /* fallthrough */
- default:
- node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
- break;
- }
-
- // If we got a dynamic label symbol, then we need to treat it like the
- // beginning of a hash pattern.
- if (pm_symbol_node_label_p(node)) {
- return (pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
- }
-
- if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
- // If we have a comma, then we are now parsing either an array pattern
- // or a find pattern. We need to parse all of the patterns, put them
- // into a big list, and then determine which type of node we have.
- pm_node_list_t nodes = { 0 };
- pm_node_list_append(&nodes, node);
-
- // Gather up all of the patterns into the list.
- while (accept1(parser, PM_TOKEN_COMMA)) {
- // Break early here in case we have a trailing comma.
- if (match6(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
- node = (pm_node_t *) pm_implicit_rest_node_create(parser, &parser->previous);
- pm_node_list_append(&nodes, node);
- trailing_rest = true;
- break;
- }
-
- if (accept1(parser, PM_TOKEN_USTAR)) {
- node = (pm_node_t *) parse_pattern_rest(parser, captures);
-
- // If we have already parsed a splat pattern, then this is an
- // error. We will continue to parse the rest of the patterns,
- // but we will indicate it as an error.
- if (trailing_rest) {
- pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
- }
-
- trailing_rest = true;
- } else {
- node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
- }
-
- pm_node_list_append(&nodes, node);
- }
-
- // If the first pattern and the last pattern are rest patterns, then we
- // will call this a find pattern, regardless of how many rest patterns
- // are in between because we know we already added the appropriate
- // errors. Otherwise we will create an array pattern.
- if (leading_rest && PM_NODE_TYPE_P(nodes.nodes[nodes.size - 1], PM_SPLAT_NODE)) {
- node = (pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
-
- if (nodes.size == 2) {
- pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
- }
- } else {
- node = (pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
-
- if (leading_rest && trailing_rest) {
- pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
- }
- }
-
- xfree(nodes.nodes);
- } else if (leading_rest) {
- // Otherwise, if we parsed a single splat pattern, then we know we have
- // an array pattern, so we can go ahead and create that node.
- node = (pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
- }
-
- return node;
-}
-
-/**
- * Incorporate a negative sign into a numeric node by subtracting 1 character
- * from its start bounds. If it's a compound node, then we will recursively
- * apply this function to its value.
- */
-static inline void
-parse_negative_numeric(pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- case PM_INTEGER_NODE: {
- pm_integer_node_t *cast = (pm_integer_node_t *) node;
- cast->base.location.start--;
- cast->value.negative = true;
- break;
- }
- case PM_FLOAT_NODE: {
- pm_float_node_t *cast = (pm_float_node_t *) node;
- cast->base.location.start--;
- cast->value = -cast->value;
- break;
- }
- case PM_RATIONAL_NODE: {
- pm_rational_node_t *cast = (pm_rational_node_t *) node;
- cast->base.location.start--;
- cast->numerator.negative = true;
- break;
- }
- case PM_IMAGINARY_NODE:
- node->location.start--;
- parse_negative_numeric(((pm_imaginary_node_t *) node)->numeric);
- break;
- default:
- assert(false && "unreachable");
- break;
- }
-}
-
-/**
- * Append an error to the error list on the parser using the given diagnostic
- * ID. This function is a specialization that handles formatting the specific
- * kind of error that is being appended.
- */
-static void
-pm_parser_err_prefix(pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
- switch (diag_id) {
- case PM_ERR_HASH_KEY: {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, diag_id, pm_token_type_human(parser->previous.type));
- break;
- }
- case PM_ERR_HASH_VALUE:
- case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, diag_id, pm_token_type_human(parser->current.type));
- break;
- }
- case PM_ERR_UNARY_RECEIVER: {
- const char *human = (parser->current.type == PM_TOKEN_EOF ? "end-of-input" : pm_token_type_human(parser->current.type));
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, diag_id, human, parser->previous.start[0]);
- break;
- }
- case PM_ERR_UNARY_DISALLOWED:
- case PM_ERR_EXPECT_ARGUMENT: {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, diag_id, pm_token_type_human(parser->current.type));
- break;
- }
- default:
- pm_parser_err_previous(parser, diag_id);
- break;
- }
-}
-
-/**
- * Ensures that the current retry token is valid in the current context.
- */
-static void
-parse_retry(pm_parser_t *parser, const pm_node_t *node) {
-#define CONTEXT_NONE 0
-#define CONTEXT_THROUGH_ENSURE 1
-#define CONTEXT_THROUGH_ELSE 2
-
- pm_context_node_t *context_node = parser->current_context;
- int context = CONTEXT_NONE;
-
- while (context_node != NULL) {
- switch (context_node->context) {
- case PM_CONTEXT_BEGIN_RESCUE:
- case PM_CONTEXT_BLOCK_RESCUE:
- case PM_CONTEXT_CLASS_RESCUE:
- case PM_CONTEXT_DEF_RESCUE:
- case PM_CONTEXT_LAMBDA_RESCUE:
- case PM_CONTEXT_MODULE_RESCUE:
- case PM_CONTEXT_SCLASS_RESCUE:
- case PM_CONTEXT_DEFINED:
- case PM_CONTEXT_RESCUE_MODIFIER:
- // These are the good cases. We're allowed to have a retry here.
- return;
- case PM_CONTEXT_CLASS:
- case PM_CONTEXT_DEF:
- case PM_CONTEXT_DEF_PARAMS:
- case PM_CONTEXT_MAIN:
- case PM_CONTEXT_MODULE:
- case PM_CONTEXT_PREEXE:
- case PM_CONTEXT_SCLASS:
- // These are the bad cases. We're not allowed to have a retry in
- // these contexts.
- if (context == CONTEXT_NONE) {
- pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
- } else if (context == CONTEXT_THROUGH_ENSURE) {
- pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
- } else if (context == CONTEXT_THROUGH_ELSE) {
- pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
- }
- return;
- case PM_CONTEXT_BEGIN_ELSE:
- case PM_CONTEXT_BLOCK_ELSE:
- case PM_CONTEXT_CLASS_ELSE:
- case PM_CONTEXT_DEF_ELSE:
- case PM_CONTEXT_LAMBDA_ELSE:
- case PM_CONTEXT_MODULE_ELSE:
- case PM_CONTEXT_SCLASS_ELSE:
- // These are also bad cases, but with a more specific error
- // message indicating the else.
- context = CONTEXT_THROUGH_ELSE;
- break;
- case PM_CONTEXT_BEGIN_ENSURE:
- case PM_CONTEXT_BLOCK_ENSURE:
- case PM_CONTEXT_CLASS_ENSURE:
- case PM_CONTEXT_DEF_ENSURE:
- case PM_CONTEXT_LAMBDA_ENSURE:
- case PM_CONTEXT_MODULE_ENSURE:
- case PM_CONTEXT_SCLASS_ENSURE:
- // These are also bad cases, but with a more specific error
- // message indicating the ensure.
- context = CONTEXT_THROUGH_ENSURE;
- break;
- case PM_CONTEXT_NONE:
- // This case should never happen.
- assert(false && "unreachable");
- break;
- case PM_CONTEXT_BEGIN:
- case PM_CONTEXT_BLOCK_BRACES:
- case PM_CONTEXT_BLOCK_KEYWORDS:
- case PM_CONTEXT_CASE_IN:
- case PM_CONTEXT_CASE_WHEN:
- case PM_CONTEXT_DEFAULT_PARAMS:
- case PM_CONTEXT_ELSE:
- case PM_CONTEXT_ELSIF:
- case PM_CONTEXT_EMBEXPR:
- case PM_CONTEXT_FOR_INDEX:
- case PM_CONTEXT_FOR:
- case PM_CONTEXT_IF:
- case PM_CONTEXT_LAMBDA_BRACES:
- case PM_CONTEXT_LAMBDA_DO_END:
- case PM_CONTEXT_LOOP_PREDICATE:
- case PM_CONTEXT_MULTI_TARGET:
- case PM_CONTEXT_PARENS:
- case PM_CONTEXT_POSTEXE:
- case PM_CONTEXT_PREDICATE:
- case PM_CONTEXT_TERNARY:
- case PM_CONTEXT_UNLESS:
- case PM_CONTEXT_UNTIL:
- case PM_CONTEXT_WHILE:
- // In these contexts we should continue walking up the list of
- // contexts.
- break;
- }
-
- context_node = context_node->prev;
- }
-
-#undef CONTEXT_NONE
-#undef CONTEXT_ENSURE
-#undef CONTEXT_ELSE
-}
-
-/**
- * Ensures that the current yield token is valid in the current context.
- */
-static void
-parse_yield(pm_parser_t *parser, const pm_node_t *node) {
- pm_context_node_t *context_node = parser->current_context;
-
- while (context_node != NULL) {
- switch (context_node->context) {
- case PM_CONTEXT_DEF:
- case PM_CONTEXT_DEF_PARAMS:
- case PM_CONTEXT_DEFINED:
- case PM_CONTEXT_DEF_ENSURE:
- case PM_CONTEXT_DEF_RESCUE:
- case PM_CONTEXT_DEF_ELSE:
- // These are the good cases. We're allowed to have a block exit
- // in these contexts.
- return;
- case PM_CONTEXT_CLASS:
- case PM_CONTEXT_CLASS_ENSURE:
- case PM_CONTEXT_CLASS_RESCUE:
- case PM_CONTEXT_CLASS_ELSE:
- case PM_CONTEXT_MAIN:
- case PM_CONTEXT_MODULE:
- case PM_CONTEXT_MODULE_ENSURE:
- case PM_CONTEXT_MODULE_RESCUE:
- case PM_CONTEXT_MODULE_ELSE:
- case PM_CONTEXT_SCLASS:
- case PM_CONTEXT_SCLASS_RESCUE:
- case PM_CONTEXT_SCLASS_ENSURE:
- case PM_CONTEXT_SCLASS_ELSE:
- // These are the bad cases. We're not allowed to have a retry in
- // these contexts.
- pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
- return;
- case PM_CONTEXT_NONE:
- // This case should never happen.
- assert(false && "unreachable");
- break;
- case PM_CONTEXT_BEGIN:
- case PM_CONTEXT_BEGIN_ELSE:
- case PM_CONTEXT_BEGIN_ENSURE:
- case PM_CONTEXT_BEGIN_RESCUE:
- case PM_CONTEXT_BLOCK_BRACES:
- case PM_CONTEXT_BLOCK_KEYWORDS:
- case PM_CONTEXT_BLOCK_ELSE:
- case PM_CONTEXT_BLOCK_ENSURE:
- case PM_CONTEXT_BLOCK_RESCUE:
- case PM_CONTEXT_CASE_IN:
- case PM_CONTEXT_CASE_WHEN:
- case PM_CONTEXT_DEFAULT_PARAMS:
- case PM_CONTEXT_ELSE:
- case PM_CONTEXT_ELSIF:
- case PM_CONTEXT_EMBEXPR:
- case PM_CONTEXT_FOR_INDEX:
- case PM_CONTEXT_FOR:
- case PM_CONTEXT_IF:
- case PM_CONTEXT_LAMBDA_BRACES:
- case PM_CONTEXT_LAMBDA_DO_END:
- case PM_CONTEXT_LAMBDA_ELSE:
- case PM_CONTEXT_LAMBDA_ENSURE:
- case PM_CONTEXT_LAMBDA_RESCUE:
- case PM_CONTEXT_LOOP_PREDICATE:
- case PM_CONTEXT_MULTI_TARGET:
- case PM_CONTEXT_PARENS:
- case PM_CONTEXT_POSTEXE:
- case PM_CONTEXT_PREDICATE:
- case PM_CONTEXT_PREEXE:
- case PM_CONTEXT_RESCUE_MODIFIER:
- case PM_CONTEXT_TERNARY:
- case PM_CONTEXT_UNLESS:
- case PM_CONTEXT_UNTIL:
- case PM_CONTEXT_WHILE:
- // In these contexts we should continue walking up the list of
- // contexts.
- break;
- }
-
- context_node = context_node->prev;
- }
-}
-
-/**
- * This struct is used to pass information between the regular expression parser
- * and the error callback.
- */
-typedef struct {
- /** The parser that we are parsing the regular expression for. */
- pm_parser_t *parser;
-
- /** The start of the regular expression. */
- const uint8_t *start;
-
- /** The end of the regular expression. */
- const uint8_t *end;
-
- /**
- * Whether or not the source of the regular expression is shared. This
- * impacts the location of error messages, because if it is shared then we
- * can use the location directly and if it is not, then we use the bounds of
- * the regular expression itself.
- */
- bool shared;
-} parse_regular_expression_error_data_t;
-
-/**
- * This callback is called when the regular expression parser encounters a
- * syntax error.
- */
-static void
-parse_regular_expression_error(const uint8_t *start, const uint8_t *end, const char *message, void *data) {
- parse_regular_expression_error_data_t *callback_data = (parse_regular_expression_error_data_t *) data;
- pm_location_t location;
-
- if (callback_data->shared) {
- location = (pm_location_t) { .start = start, .end = end };
- } else {
- location = (pm_location_t) { .start = callback_data->start, .end = callback_data->end };
- }
-
- PM_PARSER_ERR_FORMAT(callback_data->parser, location.start, location.end, PM_ERR_REGEXP_PARSE_ERROR, message);
-}
-
-/**
- * Parse the errors for the regular expression and add them to the parser.
- */
-static void
-parse_regular_expression_errors(pm_parser_t *parser, pm_regular_expression_node_t *node) {
- const pm_string_t *unescaped = &node->unescaped;
- parse_regular_expression_error_data_t error_data = {
- .parser = parser,
- .start = node->base.location.start,
- .end = node->base.location.end,
- .shared = unescaped->type == PM_STRING_SHARED
- };
-
- pm_regexp_parse(parser, pm_string_source(unescaped), pm_string_length(unescaped), PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED), NULL, NULL, parse_regular_expression_error, &error_data);
-}
-
-/**
- * Parse an expression that begins with the previous node that we just lexed.
- */
-static inline pm_node_t *
-parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth) {
- switch (parser->current.type) {
- case PM_TOKEN_BRACKET_LEFT_ARRAY: {
- parser_lex(parser);
-
- pm_array_node_t *array = pm_array_node_create(parser, &parser->previous);
- pm_accepts_block_stack_push(parser, true);
- bool parsed_bare_hash = false;
-
- while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
- // Handle the case where we don't have a comma and we have a
- // newline followed by a right bracket.
- if (accept1(parser, PM_TOKEN_NEWLINE) && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- break;
- }
-
- // Ensure that we have a comma between elements in the array.
- if ((pm_array_node_size(array) != 0) && !accept1(parser, PM_TOKEN_COMMA)) {
- const uint8_t *location = parser->previous.end;
- PM_PARSER_ERR_FORMAT(parser, location, location, PM_ERR_ARRAY_SEPARATOR, pm_token_type_human(parser->current.type));
-
- parser->previous.start = location;
- parser->previous.type = PM_TOKEN_MISSING;
- }
-
- // If we have a right bracket immediately following a comma,
- // this is allowed since it's a trailing comma. In this case we
- // can break out of the loop.
- if (match1(parser, PM_TOKEN_BRACKET_RIGHT)) break;
-
- pm_node_t *element;
-
- if (accept1(parser, PM_TOKEN_USTAR)) {
- pm_token_t operator = parser->previous;
- pm_node_t *expression = NULL;
-
- if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
- pm_parser_scope_forwarding_positionals_check(parser, &operator);
- } else {
- expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
- }
-
- element = (pm_node_t *) pm_splat_node_create(parser, &operator, expression);
- } else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
- if (parsed_bare_hash) {
- pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
- }
-
- element = (pm_node_t *) pm_keyword_hash_node_create(parser);
- pm_static_literals_t hash_keys = { 0 };
-
- if (!match8(parser, PM_TOKEN_EOF, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_PARENTHESIS_RIGHT)) {
- parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
- }
-
- pm_static_literals_free(&hash_keys);
- parsed_bare_hash = true;
- } else {
- element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
-
- if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
- if (parsed_bare_hash) {
- pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
- }
-
- pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
- pm_static_literals_t hash_keys = { 0 };
- pm_hash_key_static_literals_add(parser, &hash_keys, element);
-
- pm_token_t operator;
- if (parser->previous.type == PM_TOKEN_EQUAL_GREATER) {
- operator = parser->previous;
- } else {
- operator = not_provided(parser);
- }
-
- pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
- pm_node_t *assoc = (pm_node_t *) pm_assoc_node_create(parser, element, &operator, value);
- pm_keyword_hash_node_elements_append(hash, assoc);
-
- element = (pm_node_t *) hash;
- if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
- }
-
- pm_static_literals_free(&hash_keys);
- parsed_bare_hash = true;
- }
- }
-
- pm_array_node_elements_append(array, element);
- if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break;
- }
-
- accept1(parser, PM_TOKEN_NEWLINE);
-
- if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_ARRAY_TERM, pm_token_type_human(parser->current.type));
- parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
- }
-
- pm_array_node_close_set(array, &parser->previous);
- pm_accepts_block_stack_pop(parser);
-
- return (pm_node_t *) array;
- }
- case PM_TOKEN_PARENTHESIS_LEFT:
- case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
- pm_token_t opening = parser->current;
-
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- parser_lex(parser);
- while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
-
- // If this is the end of the file or we match a right parenthesis, then
- // we have an empty parentheses node, and we can immediately return.
- if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->previous);
- }
-
- // Otherwise, we're going to parse the first statement in the list
- // of statements within the parentheses.
- pm_accepts_block_stack_push(parser, true);
- context_push(parser, PM_CONTEXT_PARENS);
- pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
- context_pop(parser);
-
- // Determine if this statement is followed by a terminator. In the
- // case of a single statement, this is fine. But in the case of
- // multiple statements it's required.
- bool terminator_found = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- if (terminator_found) {
- while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
- }
-
- // If we hit a right parenthesis, then we're done parsing the
- // parentheses node, and we can check which kind of node we should
- // return.
- if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- if (opening.type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
- lex_state_set(parser, PM_LEX_STATE_ENDARG);
- }
-
- parser_lex(parser);
- pm_accepts_block_stack_pop(parser);
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
- // If we have a single statement and are ending on a right
- // parenthesis, then we need to check if this is possibly a
- // multiple target node.
- pm_multi_target_node_t *multi_target;
-
- if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((pm_multi_target_node_t *) statement)->lparen_loc.start == NULL) {
- multi_target = (pm_multi_target_node_t *) statement;
- } else {
- multi_target = pm_multi_target_node_create(parser);
- pm_multi_target_node_targets_append(parser, multi_target, statement);
- }
-
- pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- pm_location_t rparen_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
-
- multi_target->lparen_loc = lparen_loc;
- multi_target->rparen_loc = rparen_loc;
- multi_target->base.location.start = lparen_loc.start;
- multi_target->base.location.end = rparen_loc.end;
-
- pm_node_t *result;
- if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
- result = parse_targets(parser, (pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- accept1(parser, PM_TOKEN_NEWLINE);
- } else {
- result = (pm_node_t *) multi_target;
- }
-
- if (context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
- // All set, this is explicitly allowed by the parent
- // context.
- } else if (context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) {
- // All set, we're inside a for loop and we're parsing
- // multiple targets.
- } else if (binding_power != PM_BINDING_POWER_STATEMENT) {
- // Multi targets are not allowed when it's not a
- // statement level.
- pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
- } else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
- // Multi targets must be followed by an equal sign in
- // order to be valid (or a right parenthesis if they are
- // nested).
- pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
-
- return result;
- }
-
- // If we have a single statement and are ending on a right parenthesis
- // and we didn't return a multiple assignment node, then we can return a
- // regular parentheses node now.
- pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(parser, statements, statement, true);
-
- return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous);
- }
-
- // If we have more than one statement in the set of parentheses,
- // then we are going to parse all of them as a list of statements.
- // We'll do that here.
- context_push(parser, PM_CONTEXT_PARENS);
- pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(parser, statements, statement, true);
-
- // If we didn't find a terminator and we didn't find a right
- // parenthesis, then this is a syntax error.
- if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type));
- }
-
- // Parse each statement within the parentheses.
- while (true) {
- pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, true, false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
- pm_statements_node_body_append(parser, statements, node, true);
-
- // If we're recovering from a syntax error, then we need to stop
- // parsing the statements now.
- if (parser->recovering) {
- // If this is the level of context where the recovery has
- // happened, then we can mark the parser as done recovering.
- if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->recovering = false;
- break;
- }
-
- // If we couldn't parse an expression at all, then we need to
- // bail out of the loop.
- if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) break;
-
- // If we successfully parsed a statement, then we are going to
- // need terminator to delimit them.
- if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
- if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) break;
- } else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- break;
- } else if (!match1(parser, PM_TOKEN_EOF)) {
- // If we're at the end of the file, then we're going to add
- // an error after this for the ) anyway.
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_type_human(parser->current.type));
- }
- }
-
- // When we're parsing multi targets, we allow them to be followed by
- // a right parenthesis if they are at the statement level. This is
- // only possible if they are the final statement in a parentheses.
- // We need to explicitly reject that here.
- {
- const pm_node_t *statement = statements->body.nodes[statements->body.size - 1];
- if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
- pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
- }
-
- context_pop(parser);
- pm_accepts_block_stack_pop(parser);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- pm_void_statements_check(parser, statements, true);
- return (pm_node_t *) pm_parentheses_node_create(parser, &opening, (pm_node_t *) statements, &parser->previous);
- }
- case PM_TOKEN_BRACE_LEFT: {
- // If we were passed a current_hash_keys via the parser, then that
- // means we're already parsing a hash and we want to share the set
- // of hash keys with this inner hash we're about to parse for the
- // sake of warnings. We'll set it to NULL after we grab it to make
- // sure subsequent expressions don't use it. Effectively this is a
- // way of getting around passing it to every call to
- // parse_expression.
- pm_static_literals_t *current_hash_keys = parser->current_hash_keys;
- parser->current_hash_keys = NULL;
-
- pm_accepts_block_stack_push(parser, true);
- parser_lex(parser);
-
- pm_hash_node_t *node = pm_hash_node_create(parser, &parser->previous);
-
- if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
- if (current_hash_keys != NULL) {
- parse_assocs(parser, current_hash_keys, (pm_node_t *) node, (uint16_t) (depth + 1));
- } else {
- pm_static_literals_t hash_keys = { 0 };
- parse_assocs(parser, &hash_keys, (pm_node_t *) node, (uint16_t) (depth + 1));
- pm_static_literals_free(&hash_keys);
- }
-
- accept1(parser, PM_TOKEN_NEWLINE);
- }
-
- pm_accepts_block_stack_pop(parser);
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM);
- pm_hash_node_closing_loc_set(node, &parser->previous);
-
- return (pm_node_t *) node;
- }
- case PM_TOKEN_CHARACTER_LITERAL: {
- parser_lex(parser);
-
- pm_token_t opening = parser->previous;
- opening.type = PM_TOKEN_STRING_BEGIN;
- opening.end = opening.start + 1;
-
- pm_token_t content = parser->previous;
- content.type = PM_TOKEN_STRING_CONTENT;
- content.start = content.start + 1;
-
- pm_token_t closing = not_provided(parser);
- pm_node_t *node = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &content, &closing);
- pm_node_flag_set(node, parse_unescaped_encoding(parser));
-
- // Characters can be followed by strings in which case they are
- // automatically concatenated.
- if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
- return parse_strings(parser, node, false, (uint16_t) (depth + 1));
- }
-
- return node;
- }
- case PM_TOKEN_CLASS_VARIABLE: {
- parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_class_variable_read_node_create(parser, &parser->previous);
-
- if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- }
-
- return node;
- }
- case PM_TOKEN_CONSTANT: {
- parser_lex(parser);
- pm_token_t constant = parser->previous;
-
- // If a constant is immediately followed by parentheses, then this is in
- // fact a method call, not a constant read.
- if (
- match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
- (accepts_command_call && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
- (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
- match1(parser, PM_TOKEN_BRACE_LEFT)
- ) {
- pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
- }
-
- pm_node_t *node = (pm_node_t *) pm_constant_read_node_create(parser, &parser->previous);
-
- if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
- // If we get here, then we have a comma immediately following a
- // constant, so we're going to parse this as a multiple assignment.
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- }
-
- return node;
- }
- case PM_TOKEN_UCOLON_COLON: {
- parser_lex(parser);
- pm_token_t delimiter = parser->previous;
-
- expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- pm_node_t *node = (pm_node_t *) pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous);
-
- if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- }
-
- return node;
- }
- case PM_TOKEN_UDOT_DOT:
- case PM_TOKEN_UDOT_DOT_DOT: {
- pm_token_t operator = parser->current;
- parser_lex(parser);
-
- pm_node_t *right = parse_expression(parser, pm_binding_powers[operator.type].left, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
-
- // Unary .. and ... are special because these are non-associative
- // operators that can also be unary operators. In this case we need
- // to explicitly reject code that has a .. or ... that follows this
- // expression.
- if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
- pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
- }
-
- return (pm_node_t *) pm_range_node_create(parser, NULL, &operator, right);
- }
- case PM_TOKEN_FLOAT:
- parser_lex(parser);
- return (pm_node_t *) pm_float_node_create(parser, &parser->previous);
- case PM_TOKEN_FLOAT_IMAGINARY:
- parser_lex(parser);
- return (pm_node_t *) pm_float_node_imaginary_create(parser, &parser->previous);
- case PM_TOKEN_FLOAT_RATIONAL:
- parser_lex(parser);
- return (pm_node_t *) pm_float_node_rational_create(parser, &parser->previous);
- case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
- parser_lex(parser);
- return (pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->previous);
- case PM_TOKEN_NUMBERED_REFERENCE: {
- parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->previous);
-
- if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- }
-
- return node;
- }
- case PM_TOKEN_GLOBAL_VARIABLE: {
- parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_global_variable_read_node_create(parser, &parser->previous);
-
- if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- }
-
- return node;
- }
- case PM_TOKEN_BACK_REFERENCE: {
- parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_back_reference_read_node_create(parser, &parser->previous);
-
- if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- }
-
- return node;
- }
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_METHOD_NAME: {
- parser_lex(parser);
- pm_token_t identifier = parser->previous;
- pm_node_t *node = parse_variable_call(parser);
-
- if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
- // If parse_variable_call returned with a call node, then we
- // know the identifier is not in the local table. In that case
- // we need to check if there are arguments following the
- // identifier.
- pm_call_node_t *call = (pm_call_node_t *) node;
- pm_arguments_t arguments = { 0 };
-
- if (parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1))) {
- // Since we found arguments, we need to turn off the
- // variable call bit in the flags.
- pm_node_flag_unset((pm_node_t *)call, PM_CALL_NODE_FLAGS_VARIABLE_CALL);
-
- call->opening_loc = arguments.opening_loc;
- call->arguments = arguments.arguments;
- call->closing_loc = arguments.closing_loc;
- call->block = arguments.block;
-
- if (arguments.block != NULL) {
- call->base.location.end = arguments.block->location.end;
- } else if (arguments.closing_loc.start == NULL) {
- if (arguments.arguments != NULL) {
- call->base.location.end = arguments.arguments->base.location.end;
- } else {
- call->base.location.end = call->message_loc.end;
- }
- } else {
- call->base.location.end = arguments.closing_loc.end;
- }
- }
- } else {
- // Otherwise, we know the identifier is in the local table. This
- // can still be a method call if it is followed by arguments or
- // a block, so we need to check for that here.
- if (
- (accepts_command_call && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
- (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
- match1(parser, PM_TOKEN_BRACE_LEFT)
- ) {
- pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1));
- pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
-
- if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
- // If we're about to convert an 'it' implicit local
- // variable read into a method call, we need to remove
- // it from the list of implicit local variables.
- parse_target_implicit_parameter(parser, node);
- } else {
- // Otherwise, we're about to convert a regular local
- // variable read into a method call, in which case we
- // need to indicate that this was not a read for the
- // purposes of warnings.
- assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
-
- if (pm_token_is_numbered_parameter(identifier.start, identifier.end)) {
- parse_target_implicit_parameter(parser, node);
- } else {
- pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
- pm_locals_unread(&pm_parser_scope_find(parser, cast->depth)->locals, cast->name);
- }
- }
-
- pm_node_destroy(parser, node);
- return (pm_node_t *) fcall;
- }
- }
-
- if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- }
-
- return node;
- }
- case PM_TOKEN_HEREDOC_START: {
- // Here we have found a heredoc. We'll parse it and add it to the
- // list of strings.
- assert(parser->lex_modes.current->mode == PM_LEX_HEREDOC);
- pm_heredoc_lex_mode_t lex_mode = parser->lex_modes.current->as.heredoc.base;
-
- size_t common_whitespace = (size_t) -1;
- parser->lex_modes.current->as.heredoc.common_whitespace = &common_whitespace;
-
- parser_lex(parser);
- pm_token_t opening = parser->previous;
-
- pm_node_t *node;
- pm_node_t *part;
-
- if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
- // If we get here, then we have an empty heredoc. We'll create
- // an empty content token and return an empty string node.
- expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
- pm_token_t content = parse_strings_empty_content(parser->previous.start);
-
- if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
- node = (pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY);
- } else {
- node = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY);
- }
-
- node->location.end = opening.end;
- } else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
- // If we get here, then we tried to find something in the
- // heredoc but couldn't actually parse anything, so we'll just
- // return a missing node.
- //
- // parse_string_part handles its own errors, so there is no need
- // for us to add one here.
- node = (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
- } else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
- // If we get here, then the part that we parsed was plain string
- // content and we're at the end of the heredoc, so we can return
- // just a string node with the heredoc opening and closing as
- // its opening and closing.
- pm_node_flag_set(part, parse_unescaped_encoding(parser));
- pm_string_node_t *cast = (pm_string_node_t *) part;
-
- cast->opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
- cast->closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->current);
- cast->base.location = cast->opening_loc;
-
- if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
- assert(sizeof(pm_string_node_t) == sizeof(pm_x_string_node_t));
- cast->base.type = PM_X_STRING_NODE;
- }
-
- if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (size_t) -1) && (common_whitespace != 0)) {
- parse_heredoc_dedent_string(&cast->unescaped, common_whitespace);
- }
-
- node = (pm_node_t *) cast;
- expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
- } else {
- // If we get here, then we have multiple parts in the heredoc,
- // so we'll need to create an interpolated string node to hold
- // them all.
- pm_node_list_t parts = { 0 };
- pm_node_list_append(&parts, part);
-
- while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
- if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
- pm_node_list_append(&parts, part);
- }
- }
-
- // Now that we have all of the parts, create the correct type of
- // interpolated node.
- if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
- pm_interpolated_x_string_node_t *cast = pm_interpolated_xstring_node_create(parser, &opening, &opening);
- cast->parts = parts;
-
- expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
- pm_interpolated_xstring_node_closing_set(cast, &parser->previous);
-
- cast->base.location = cast->opening_loc;
- node = (pm_node_t *) cast;
- } else {
- pm_interpolated_string_node_t *cast = pm_interpolated_string_node_create(parser, &opening, &parts, &opening);
- pm_node_list_free(&parts);
-
- expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
- pm_interpolated_string_node_closing_set(cast, &parser->previous);
-
- cast->base.location = cast->opening_loc;
- node = (pm_node_t *) cast;
- }
-
- // If this is a heredoc that is indented with a ~, then we need
- // to dedent each line by the common leading whitespace.
- if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (size_t) -1) && (common_whitespace != 0)) {
- pm_node_list_t *nodes;
- if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
- nodes = &((pm_interpolated_x_string_node_t *) node)->parts;
- } else {
- nodes = &((pm_interpolated_string_node_t *) node)->parts;
- }
-
- parse_heredoc_dedent(parser, nodes, common_whitespace);
- }
- }
-
- if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
- return parse_strings(parser, node, false, (uint16_t) (depth + 1));
- }
-
- return node;
- }
- case PM_TOKEN_INSTANCE_VARIABLE: {
- parser_lex(parser);
- pm_node_t *node = (pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->previous);
-
- if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- }
-
- return node;
- }
- case PM_TOKEN_INTEGER: {
- pm_node_flags_t base = parser->integer_base;
- parser_lex(parser);
- return (pm_node_t *) pm_integer_node_create(parser, base, &parser->previous);
- }
- case PM_TOKEN_INTEGER_IMAGINARY: {
- pm_node_flags_t base = parser->integer_base;
- parser_lex(parser);
- return (pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->previous);
- }
- case PM_TOKEN_INTEGER_RATIONAL: {
- pm_node_flags_t base = parser->integer_base;
- parser_lex(parser);
- return (pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->previous);
- }
- case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
- pm_node_flags_t base = parser->integer_base;
- parser_lex(parser);
- return (pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->previous);
- }
- case PM_TOKEN_KEYWORD___ENCODING__:
- parser_lex(parser);
- return (pm_node_t *) pm_source_encoding_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD___FILE__:
- parser_lex(parser);
- return (pm_node_t *) pm_source_file_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD___LINE__:
- parser_lex(parser);
- return (pm_node_t *) pm_source_line_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD_ALIAS: {
- if (binding_power != PM_BINDING_POWER_STATEMENT) {
- pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
- }
-
- parser_lex(parser);
- pm_token_t keyword = parser->previous;
-
- pm_node_t *new_name = parse_alias_argument(parser, true, (uint16_t) (depth + 1));
- pm_node_t *old_name = parse_alias_argument(parser, false, (uint16_t) (depth + 1));
-
- switch (PM_NODE_TYPE(new_name)) {
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- if (PM_NODE_TYPE_P(old_name, PM_BACK_REFERENCE_READ_NODE) || PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE) || PM_NODE_TYPE_P(old_name, PM_GLOBAL_VARIABLE_READ_NODE)) {
- if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
- pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
- }
- } else {
- pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
- }
-
- return (pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
- }
- case PM_SYMBOL_NODE:
- case PM_INTERPOLATED_SYMBOL_NODE: {
- if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
- pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
- }
- }
- /* fallthrough */
- default:
- return (pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
- }
- }
- case PM_TOKEN_KEYWORD_CASE: {
- size_t opening_newline_index = token_newline_index(parser);
- parser_lex(parser);
-
- pm_token_t case_keyword = parser->previous;
- pm_node_t *predicate = NULL;
-
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
- predicate = NULL;
- } else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
- predicate = NULL;
- } else if (!token_begins_expression_p(parser->current.type)) {
- predicate = NULL;
- } else {
- predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
- while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
- }
-
- if (match1(parser, PM_TOKEN_KEYWORD_END)) {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, false);
- parser_lex(parser);
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
- return (pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->previous);
- }
-
- // At this point we can create a case node, though we don't yet know
- // if it is a case-in or case-when node.
- pm_token_t end_keyword = not_provided(parser);
- pm_node_t *node;
-
- if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
- pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
- pm_static_literals_t literals = { 0 };
-
- // At this point we've seen a when keyword, so we know this is a
- // case-when node. We will continue to parse the when nodes
- // until we hit the end of the list.
- while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, true);
- parser_lex(parser);
-
- pm_token_t when_keyword = parser->previous;
- pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
-
- do {
- if (accept1(parser, PM_TOKEN_USTAR)) {
- pm_token_t operator = parser->previous;
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
-
- pm_splat_node_t *splat_node = pm_splat_node_create(parser, &operator, expression);
- pm_when_node_conditions_append(when_node, (pm_node_t *) splat_node);
-
- if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE)) break;
- } else {
- pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
- pm_when_node_conditions_append(when_node, condition);
-
- // If we found a missing node, then this is a syntax
- // error and we should stop looping.
- if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE)) break;
-
- // If this is a string node, then we need to mark it
- // as frozen because when clause strings are frozen.
- if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
- pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
- } else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
- pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
- }
-
- pm_when_clause_static_literals_add(parser, &literals, condition);
- }
- } while (accept1(parser, PM_TOKEN_COMMA));
-
- if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
- pm_when_node_then_keyword_loc_set(when_node, &parser->previous);
- }
- } else {
- expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
- pm_when_node_then_keyword_loc_set(when_node, &parser->previous);
- }
-
- if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_CASE_WHEN, (uint16_t) (depth + 1));
- if (statements != NULL) {
- pm_when_node_statements_set(when_node, statements);
- }
- }
-
- pm_case_node_condition_append(case_node, (pm_node_t *) when_node);
- }
-
- // If we didn't parse any conditions (in or when) then we need
- // to indicate that we have an error.
- if (case_node->conditions.size == 0) {
- pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
- }
-
- pm_static_literals_free(&literals);
- node = (pm_node_t *) case_node;
- } else {
- pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
-
- // If this is a case-match node (i.e., it is a pattern matching
- // case statement) then we must have a predicate.
- if (predicate == NULL) {
- pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
- }
-
- // At this point we expect that we're parsing a case-in node. We
- // will continue to parse the in nodes until we hit the end of
- // the list.
- while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, true);
-
- bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
- parser->pattern_matching_newlines = true;
-
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- parser->command_start = false;
- parser_lex(parser);
-
- pm_token_t in_keyword = parser->previous;
-
- pm_constant_id_list_t captures = { 0 };
- pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN, (uint16_t) (depth + 1));
-
- parser->pattern_matching_newlines = previous_pattern_matching_newlines;
- pm_constant_id_list_free(&captures);
-
- // Since we're in the top-level of the case-in node we need
- // to check for guard clauses in the form of `if` or
- // `unless` statements.
- if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
- pm_token_t keyword = parser->previous;
- pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
- pattern = (pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
- } else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
- pm_token_t keyword = parser->previous;
- pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
- pattern = (pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
- }
-
- // Now we need to check for the terminator of the in node's
- // pattern. It can be a newline or semicolon optionally
- // followed by a `then` keyword.
- pm_token_t then_keyword;
- if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
- then_keyword = parser->previous;
- } else {
- then_keyword = not_provided(parser);
- }
- } else {
- expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
- then_keyword = parser->previous;
- }
-
- // Now we can actually parse the statements associated with
- // the in node.
- pm_statements_node_t *statements;
- if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- statements = NULL;
- } else {
- statements = parse_statements(parser, PM_CONTEXT_CASE_IN, (uint16_t) (depth + 1));
- }
-
- // Now that we have the full pattern and statements, we can
- // create the node and attach it to the case node.
- pm_node_t *condition = (pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
- pm_case_match_node_condition_append(case_node, condition);
- }
-
- // If we didn't parse any conditions (in or when) then we need
- // to indicate that we have an error.
- if (case_node->conditions.size == 0) {
- pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
- }
-
- node = (pm_node_t *) case_node;
- }
-
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
- pm_token_t else_keyword = parser->previous;
- pm_else_node_t *else_node;
-
- if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
- else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->current);
- } else {
- else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->current);
- }
-
- if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
- pm_case_node_else_clause_set((pm_case_node_t *) node, else_node);
- } else {
- pm_case_match_node_else_clause_set((pm_case_match_node_t *) node, else_node);
- }
- }
-
- parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword, false, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM);
-
- if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
- pm_case_node_end_keyword_loc_set((pm_case_node_t *) node, &parser->previous);
- } else {
- pm_case_match_node_end_keyword_loc_set((pm_case_match_node_t *) node, &parser->previous);
- }
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return node;
- }
- case PM_TOKEN_KEYWORD_BEGIN: {
- size_t opening_newline_index = token_newline_index(parser);
- parser_lex(parser);
-
- pm_token_t begin_keyword = parser->previous;
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
-
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
- pm_statements_node_t *begin_statements = NULL;
-
- if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- begin_statements = parse_statements(parser, PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
- parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM);
-
- begin_node->base.location.end = parser->previous.end;
- pm_begin_node_end_keyword_set(begin_node, &parser->previous);
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) begin_node;
- }
- case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- if (binding_power != PM_BINDING_POWER_STATEMENT) {
- pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
- }
-
- parser_lex(parser);
- pm_token_t keyword = parser->previous;
-
- expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
- pm_token_t opening = parser->previous;
- pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
-
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM);
- pm_context_t context = parser->current_context->context;
- if ((context != PM_CONTEXT_MAIN) && (context != PM_CONTEXT_PREEXE)) {
- pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
- }
-
- flush_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous);
- }
- case PM_TOKEN_KEYWORD_BREAK:
- case PM_TOKEN_KEYWORD_NEXT:
- case PM_TOKEN_KEYWORD_RETURN: {
- parser_lex(parser);
-
- pm_token_t keyword = parser->previous;
- pm_arguments_t arguments = { 0 };
-
- if (
- token_begins_expression_p(parser->current.type) ||
- match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
- ) {
- pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].left;
-
- if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
- parse_arguments(parser, &arguments, false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
- }
- }
-
- switch (keyword.type) {
- case PM_TOKEN_KEYWORD_BREAK: {
- pm_node_t *node = (pm_node_t *) pm_break_node_create(parser, &keyword, arguments.arguments);
- if (!parser->partial_script) parse_block_exit(parser, node);
- return node;
- }
- case PM_TOKEN_KEYWORD_NEXT: {
- pm_node_t *node = (pm_node_t *) pm_next_node_create(parser, &keyword, arguments.arguments);
- if (!parser->partial_script) parse_block_exit(parser, node);
- return node;
- }
- case PM_TOKEN_KEYWORD_RETURN: {
- pm_node_t *node = (pm_node_t *) pm_return_node_create(parser, &keyword, arguments.arguments);
- parse_return(parser, node);
- return node;
- }
- default:
- assert(false && "unreachable");
- return (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
- }
- }
- case PM_TOKEN_KEYWORD_SUPER: {
- parser_lex(parser);
-
- pm_token_t keyword = parser->previous;
- pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1));
-
- if (
- arguments.opening_loc.start == NULL &&
- arguments.arguments == NULL &&
- ((arguments.block == NULL) || PM_NODE_TYPE_P(arguments.block, PM_BLOCK_NODE))
- ) {
- return (pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
- }
-
- return (pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
- }
- case PM_TOKEN_KEYWORD_YIELD: {
- parser_lex(parser);
-
- pm_token_t keyword = parser->previous;
- pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, false, accepts_command_call, (uint16_t) (depth + 1));
-
- // It's possible that we've parsed a block argument through our
- // call to parse_arguments_list. If we found one, we should mark it
- // as invalid and destroy it, as we don't have a place for it on the
- // yield node.
- if (arguments.block != NULL) {
- pm_parser_err_node(parser, arguments.block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
- pm_node_destroy(parser, arguments.block);
- arguments.block = NULL;
- }
-
- pm_node_t *node = (pm_node_t *) pm_yield_node_create(parser, &keyword, &arguments.opening_loc, arguments.arguments, &arguments.closing_loc);
- if (!parser->parsing_eval && !parser->partial_script) parse_yield(parser, node);
-
- return node;
- }
- case PM_TOKEN_KEYWORD_CLASS: {
- size_t opening_newline_index = token_newline_index(parser);
- parser_lex(parser);
-
- pm_token_t class_keyword = parser->previous;
- pm_do_loop_stack_push(parser, false);
-
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- if (accept1(parser, PM_TOKEN_LESS_LESS)) {
- pm_token_t operator = parser->previous;
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS, (uint16_t) (depth + 1));
-
- pm_parser_scope_push(parser, true);
- if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_type_human(parser->current.type));
- }
-
- pm_node_t *statements = NULL;
- if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_SCLASS, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
- assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_SCLASS, (uint16_t) (depth + 1));
- } else {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, false);
- }
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
-
- pm_constant_id_list_t locals;
- pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
-
- pm_parser_scope_pop(parser);
- pm_do_loop_stack_pop(parser);
-
- flush_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous);
- }
-
- pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
- pm_token_t name = parser->previous;
- if (name.type != PM_TOKEN_CONSTANT) {
- pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
- }
-
- pm_token_t inheritance_operator;
- pm_node_t *superclass;
-
- if (match1(parser, PM_TOKEN_LESS)) {
- inheritance_operator = parser->current;
- lex_state_set(parser, PM_LEX_STATE_BEG);
-
- parser->command_start = true;
- parser_lex(parser);
-
- superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
- } else {
- inheritance_operator = not_provided(parser);
- superclass = NULL;
- }
-
- pm_parser_scope_push(parser, true);
-
- if (inheritance_operator.type != PM_TOKEN_NOT_PROVIDED) {
- expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
- } else {
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
- pm_node_t *statements = NULL;
-
- if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_CLASS, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
- assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_CLASS, (uint16_t) (depth + 1));
- } else {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword, false, false);
- }
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM);
-
- if (context_def_p(parser)) {
- pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
- }
-
- pm_constant_id_list_t locals;
- pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
-
- pm_parser_scope_pop(parser);
- pm_do_loop_stack_pop(parser);
-
- if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
- pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
- }
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->previous);
- }
- case PM_TOKEN_KEYWORD_DEF: {
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- pm_token_t def_keyword = parser->current;
- size_t opening_newline_index = token_newline_index(parser);
-
- pm_node_t *receiver = NULL;
- pm_token_t operator = not_provided(parser);
- pm_token_t name;
-
- // This context is necessary for lexing `...` in a bare params
- // correctly. It must be pushed before lexing the first param, so it
- // is here.
- context_push(parser, PM_CONTEXT_DEF_PARAMS);
- parser_lex(parser);
-
- switch (parser->current.type) {
- case PM_CASE_OPERATOR:
- pm_parser_scope_push(parser, true);
- lex_state_set(parser, PM_LEX_STATE_ENDFN);
- parser_lex(parser);
-
- name = parser->previous;
- break;
- case PM_TOKEN_IDENTIFIER: {
- parser_lex(parser);
-
- if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
- receiver = parse_variable_call(parser);
-
- pm_parser_scope_push(parser, true);
- lex_state_set(parser, PM_LEX_STATE_FNAME);
- parser_lex(parser);
-
- operator = parser->previous;
- name = parse_method_definition_name(parser);
- } else {
- pm_refute_numbered_parameter(parser, parser->previous.start, parser->previous.end);
- pm_parser_scope_push(parser, true);
-
- name = parser->previous;
- }
-
- break;
- }
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_INSTANCE_VARIABLE:
- case PM_TOKEN_CLASS_VARIABLE:
- case PM_TOKEN_GLOBAL_VARIABLE:
- case PM_TOKEN_KEYWORD_NIL:
- case PM_TOKEN_KEYWORD_SELF:
- case PM_TOKEN_KEYWORD_TRUE:
- case PM_TOKEN_KEYWORD_FALSE:
- case PM_TOKEN_KEYWORD___FILE__:
- case PM_TOKEN_KEYWORD___LINE__:
- case PM_TOKEN_KEYWORD___ENCODING__: {
- pm_parser_scope_push(parser, true);
- parser_lex(parser);
-
- pm_token_t identifier = parser->previous;
-
- if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
- lex_state_set(parser, PM_LEX_STATE_FNAME);
- parser_lex(parser);
- operator = parser->previous;
-
- switch (identifier.type) {
- case PM_TOKEN_CONSTANT:
- receiver = (pm_node_t *) pm_constant_read_node_create(parser, &identifier);
- break;
- case PM_TOKEN_INSTANCE_VARIABLE:
- receiver = (pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
- break;
- case PM_TOKEN_CLASS_VARIABLE:
- receiver = (pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
- break;
- case PM_TOKEN_GLOBAL_VARIABLE:
- receiver = (pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD_NIL:
- receiver = (pm_node_t *) pm_nil_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD_SELF:
- receiver = (pm_node_t *) pm_self_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD_TRUE:
- receiver = (pm_node_t *) pm_true_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD_FALSE:
- receiver = (pm_node_t *) pm_false_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD___FILE__:
- receiver = (pm_node_t *) pm_source_file_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD___LINE__:
- receiver = (pm_node_t *) pm_source_line_node_create(parser, &identifier);
- break;
- case PM_TOKEN_KEYWORD___ENCODING__:
- receiver = (pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
- break;
- default:
- break;
- }
-
- name = parse_method_definition_name(parser);
- } else {
- name = identifier;
- }
- break;
- }
- case PM_TOKEN_PARENTHESIS_LEFT: {
- // The current context is `PM_CONTEXT_DEF_PARAMS`, however
- // the inner expression of this parenthesis should not be
- // processed under this context. Thus, the context is popped
- // here.
- context_pop(parser);
- parser_lex(parser);
-
- pm_token_t lparen = parser->previous;
- pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
-
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
- pm_token_t rparen = parser->previous;
-
- lex_state_set(parser, PM_LEX_STATE_FNAME);
- expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
-
- operator = parser->previous;
- receiver = (pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen);
-
- // To push `PM_CONTEXT_DEF_PARAMS` again is for the same
- // reason as described the above.
- pm_parser_scope_push(parser, true);
- context_push(parser, PM_CONTEXT_DEF_PARAMS);
- name = parse_method_definition_name(parser);
- break;
- }
- default:
- pm_parser_scope_push(parser, true);
- name = parse_method_definition_name(parser);
- break;
- }
-
- pm_token_t lparen;
- pm_token_t rparen;
- pm_parameters_node_t *params;
-
- switch (parser->current.type) {
- case PM_TOKEN_PARENTHESIS_LEFT: {
- parser_lex(parser);
- lparen = parser->previous;
-
- if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- params = NULL;
- } else {
- params = parse_parameters(parser, PM_BINDING_POWER_DEFINED, true, false, true, true, (uint16_t) (depth + 1));
- }
-
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser->command_start = true;
-
- context_pop(parser);
- if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_type_human(parser->current.type));
- parser->previous.start = parser->previous.end;
- parser->previous.type = PM_TOKEN_MISSING;
- }
-
- rparen = parser->previous;
- break;
- }
- case PM_CASE_PARAMETER: {
- // If we're about to lex a label, we need to add the label
- // state to make sure the next newline is ignored.
- if (parser->current.type == PM_TOKEN_LABEL) {
- lex_state_set(parser, parser->lex_state | PM_LEX_STATE_LABEL);
- }
-
- lparen = not_provided(parser);
- rparen = not_provided(parser);
- params = parse_parameters(parser, PM_BINDING_POWER_DEFINED, false, false, true, true, (uint16_t) (depth + 1));
-
- context_pop(parser);
- break;
- }
- default: {
- lparen = not_provided(parser);
- rparen = not_provided(parser);
- params = NULL;
-
- context_pop(parser);
- break;
- }
- }
-
- pm_node_t *statements = NULL;
- pm_token_t equal;
- pm_token_t end_keyword;
-
- if (accept1(parser, PM_TOKEN_EQUAL)) {
- if (token_is_setter_name(&name)) {
- pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
- }
- equal = parser->previous;
-
- context_push(parser, PM_CONTEXT_DEF);
- pm_do_loop_stack_push(parser, false);
- statements = (pm_node_t *) pm_statements_node_create(parser);
-
- pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, binding_power < PM_BINDING_POWER_COMPOSITION, false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
-
- if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
- context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
-
- pm_token_t rescue_keyword = parser->previous;
- pm_node_t *value = parse_expression(parser, binding_power, false, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
- context_pop(parser);
-
- statement = (pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
- }
-
- pm_statements_node_body_append(parser, (pm_statements_node_t *) statements, statement, false);
- pm_do_loop_stack_pop(parser);
- context_pop(parser);
- end_keyword = not_provided(parser);
- } else {
- equal = not_provided(parser);
-
- if (lparen.type == PM_TOKEN_NOT_PROVIDED) {
- lex_state_set(parser, PM_LEX_STATE_BEG);
- parser->command_start = true;
- expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
- } else {
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- pm_accepts_block_stack_push(parser, true);
- pm_do_loop_stack_push(parser, false);
-
- if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_DEF, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
- assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &def_keyword, def_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_DEF, (uint16_t) (depth + 1));
- } else {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword, false, false);
- }
-
- pm_accepts_block_stack_pop(parser);
- pm_do_loop_stack_pop(parser);
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM);
- end_keyword = parser->previous;
- }
-
- pm_constant_id_list_t locals;
- pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
- pm_parser_scope_pop(parser);
-
- /**
- * If the final character is @. As is the case when defining
- * methods to override the unary operators, we should ignore
- * the @ in the same way we do for symbols.
- */
- pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.start, parse_operator_symbol_name(&name));
-
- flush_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_def_node_create(
- parser,
- name_id,
- &name,
- receiver,
- params,
- statements,
- &locals,
- &def_keyword,
- &operator,
- &lparen,
- &rparen,
- &equal,
- &end_keyword
- );
- }
- case PM_TOKEN_KEYWORD_DEFINED: {
- parser_lex(parser);
- pm_token_t keyword = parser->previous;
-
- pm_token_t lparen;
- pm_token_t rparen;
- pm_node_t *expression;
- context_push(parser, PM_CONTEXT_DEFINED);
-
- if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
- lparen = parser->previous;
- expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
-
- if (parser->recovering) {
- rparen = not_provided(parser);
- } else {
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
- rparen = parser->previous;
- }
- } else {
- lparen = not_provided(parser);
- rparen = not_provided(parser);
- expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
- }
-
- context_pop(parser);
- return (pm_node_t *) pm_defined_node_create(
- parser,
- &lparen,
- expression,
- &rparen,
- &PM_LOCATION_TOKEN_VALUE(&keyword)
- );
- }
- case PM_TOKEN_KEYWORD_END_UPCASE: {
- if (binding_power != PM_BINDING_POWER_STATEMENT) {
- pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
- }
-
- parser_lex(parser);
- pm_token_t keyword = parser->previous;
-
- if (context_def_p(parser)) {
- pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
- }
-
- expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
- pm_token_t opening = parser->previous;
- pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
-
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM);
- return (pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous);
- }
- case PM_TOKEN_KEYWORD_FALSE:
- parser_lex(parser);
- return (pm_node_t *) pm_false_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD_FOR: {
- size_t opening_newline_index = token_newline_index(parser);
- parser_lex(parser);
-
- pm_token_t for_keyword = parser->previous;
- pm_node_t *index;
-
- context_push(parser, PM_CONTEXT_FOR_INDEX);
-
- // First, parse out the first index expression.
- if (accept1(parser, PM_TOKEN_USTAR)) {
- pm_token_t star_operator = parser->previous;
- pm_node_t *name = NULL;
-
- if (token_begins_expression_p(parser->current.type)) {
- name = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
- }
-
- index = (pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
- } else if (token_begins_expression_p(parser->current.type)) {
- index = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
- } else {
- pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
- index = (pm_node_t *) pm_missing_node_create(parser, for_keyword.start, for_keyword.end);
- }
-
- // Now, if there are multiple index expressions, parse them out.
- if (match1(parser, PM_TOKEN_COMMA)) {
- index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- } else {
- index = parse_target(parser, index, false, false);
- }
-
- context_pop(parser);
- pm_do_loop_stack_push(parser, true);
-
- expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
- pm_token_t in_keyword = parser->previous;
-
- pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
- pm_do_loop_stack_pop(parser);
-
- pm_token_t do_keyword;
- if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
- do_keyword = parser->previous;
- } else {
- do_keyword = not_provided(parser);
- if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_type_human(parser->current.type));
- }
- }
-
- pm_statements_node_t *statements = NULL;
- if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
- statements = parse_statements(parser, PM_CONTEXT_FOR, (uint16_t) (depth + 1));
- }
-
- parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword, false, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
-
- return (pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->previous);
- }
- case PM_TOKEN_KEYWORD_IF:
- if (parser_end_of_line_p(parser)) {
- PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_WARN_KEYWORD_EOL);
- }
-
- size_t opening_newline_index = token_newline_index(parser);
- bool if_after_else = parser->previous.type == PM_TOKEN_KEYWORD_ELSE;
- parser_lex(parser);
-
- return parse_conditional(parser, PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
- case PM_TOKEN_KEYWORD_UNDEF: {
- if (binding_power != PM_BINDING_POWER_STATEMENT) {
- pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
- }
-
- parser_lex(parser);
- pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->previous);
- pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
-
- if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
- pm_node_destroy(parser, name);
- } else {
- pm_undef_node_append(undef, name);
-
- while (match1(parser, PM_TOKEN_COMMA)) {
- lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
- parser_lex(parser);
- name = parse_undef_argument(parser, (uint16_t) (depth + 1));
-
- if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
- pm_node_destroy(parser, name);
- break;
- }
-
- pm_undef_node_append(undef, name);
- }
- }
-
- return (pm_node_t *) undef;
- }
- case PM_TOKEN_KEYWORD_NOT: {
- parser_lex(parser);
-
- pm_token_t message = parser->previous;
- pm_arguments_t arguments = { 0 };
- pm_node_t *receiver = NULL;
-
- accept1(parser, PM_TOKEN_NEWLINE);
-
- if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
- arguments.opening_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
-
- if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- arguments.closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
- } else {
- receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
-
- if (!parser->recovering) {
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
- arguments.closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
- }
- }
- } else {
- receiver = parse_expression(parser, PM_BINDING_POWER_NOT, true, false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
- }
-
- return (pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
- }
- case PM_TOKEN_KEYWORD_UNLESS: {
- size_t opening_newline_index = token_newline_index(parser);
- parser_lex(parser);
-
- return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index, false, (uint16_t) (depth + 1));
- }
- case PM_TOKEN_KEYWORD_MODULE: {
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- size_t opening_newline_index = token_newline_index(parser);
- parser_lex(parser);
- pm_token_t module_keyword = parser->previous;
-
- pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
- pm_token_t name;
-
- // If we can recover from a syntax error that occurred while parsing
- // the name of the module, then we'll handle that here.
- if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- pm_token_t missing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- return (pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
- }
-
- while (accept1(parser, PM_TOKEN_COLON_COLON)) {
- pm_token_t double_colon = parser->previous;
-
- expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- constant_path = (pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->previous);
- }
-
- // Here we retrieve the name of the module. If it wasn't a constant,
- // then it's possible that `module foo` was passed, which is a
- // syntax error. We handle that here as well.
- name = parser->previous;
- if (name.type != PM_TOKEN_CONSTANT) {
- pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
- }
-
- pm_parser_scope_push(parser, true);
- accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
- pm_node_t *statements = NULL;
-
- if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = (pm_node_t *) parse_statements(parser, PM_CONTEXT_MODULE, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
- assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
- statements = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &module_keyword, module_keyword.start, (pm_statements_node_t *) statements, PM_RESCUES_MODULE, (uint16_t) (depth + 1));
- } else {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword, false, false);
- }
-
- pm_constant_id_list_t locals;
- pm_locals_order(parser, &parser->current_scope->locals, &locals, false);
-
- pm_parser_scope_pop(parser);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM);
-
- if (context_def_p(parser)) {
- pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
- }
-
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous);
- }
- case PM_TOKEN_KEYWORD_NIL:
- parser_lex(parser);
- return (pm_node_t *) pm_nil_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD_REDO: {
- parser_lex(parser);
-
- pm_node_t *node = (pm_node_t *) pm_redo_node_create(parser, &parser->previous);
- if (!parser->partial_script) parse_block_exit(parser, node);
-
- return node;
- }
- case PM_TOKEN_KEYWORD_RETRY: {
- parser_lex(parser);
-
- pm_node_t *node = (pm_node_t *) pm_retry_node_create(parser, &parser->previous);
- parse_retry(parser, node);
-
- return node;
- }
- case PM_TOKEN_KEYWORD_SELF:
- parser_lex(parser);
- return (pm_node_t *) pm_self_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD_TRUE:
- parser_lex(parser);
- return (pm_node_t *) pm_true_node_create(parser, &parser->previous);
- case PM_TOKEN_KEYWORD_UNTIL: {
- size_t opening_newline_index = token_newline_index(parser);
-
- context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
- pm_do_loop_stack_push(parser, true);
-
- parser_lex(parser);
- pm_token_t keyword = parser->previous;
- pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
-
- pm_do_loop_stack_pop(parser);
- context_pop(parser);
-
- expect3(parser, PM_TOKEN_KEYWORD_DO_LOOP, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
- pm_statements_node_t *statements = NULL;
-
- if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = parse_statements(parser, PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM);
-
- return (pm_node_t *) pm_until_node_create(parser, &keyword, &parser->previous, predicate, statements, 0);
- }
- case PM_TOKEN_KEYWORD_WHILE: {
- size_t opening_newline_index = token_newline_index(parser);
-
- context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
- pm_do_loop_stack_push(parser, true);
-
- parser_lex(parser);
- pm_token_t keyword = parser->previous;
- pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, true, false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
-
- pm_do_loop_stack_pop(parser);
- context_pop(parser);
-
- expect3(parser, PM_TOKEN_KEYWORD_DO_LOOP, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
- pm_statements_node_t *statements = NULL;
-
- if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
- pm_accepts_block_stack_push(parser, true);
- statements = parse_statements(parser, PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
- }
-
- parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, false, false);
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM);
-
- return (pm_node_t *) pm_while_node_create(parser, &keyword, &parser->previous, predicate, statements, 0);
- }
- case PM_TOKEN_PERCENT_LOWER_I: {
- parser_lex(parser);
- pm_token_t opening = parser->previous;
- pm_array_node_t *array = pm_array_node_create(parser, &opening);
-
- while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- accept1(parser, PM_TOKEN_WORDS_SEP);
- if (match1(parser, PM_TOKEN_STRING_END)) break;
-
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_array_node_elements_append(array, (pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->current, &closing));
- }
-
- expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
- }
-
- pm_token_t closing = parser->current;
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
- }
- pm_array_node_close_set(array, &closing);
-
- return (pm_node_t *) array;
- }
- case PM_TOKEN_PERCENT_UPPER_I: {
- parser_lex(parser);
- pm_token_t opening = parser->previous;
- pm_array_node_t *array = pm_array_node_create(parser, &opening);
-
- // This is the current node that we are parsing that will be added to the
- // list of elements.
- pm_node_t *current = NULL;
-
- while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- switch (parser->current.type) {
- case PM_TOKEN_WORDS_SEP: {
- if (current == NULL) {
- // If we hit a separator before we have any content, then we don't
- // need to do anything.
- } else {
- // If we hit a separator after we've hit content, then we need to
- // append that content to the list and reset the current node.
- pm_array_node_elements_append(array, current);
- current = NULL;
- }
-
- parser_lex(parser);
- break;
- }
- case PM_TOKEN_STRING_CONTENT: {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
-
- if (current == NULL) {
- // If we hit content and the current node is NULL, then this is
- // the first string content we've seen. In that case we're going
- // to create a new string node and set that to the current.
- current = (pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->current, &closing);
- parser_lex(parser);
- } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
- // If we hit string content and the current node is an
- // interpolated string, then we need to append the string content
- // to the list of child nodes.
- pm_node_t *string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->current, &closing);
- parser_lex(parser);
-
- pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, string);
- } else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
- // If we hit string content and the current node is a symbol node,
- // then we need to convert the current node into an interpolated
- // string and add the string content to the list of child nodes.
- pm_symbol_node_t *cast = (pm_symbol_node_t *) current;
- pm_token_t bounds = not_provided(parser);
-
- pm_token_t content = { .type = PM_TOKEN_STRING_CONTENT, .start = cast->value_loc.start, .end = cast->value_loc.end };
- pm_node_t *first_string = (pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &cast->unescaped);
- pm_node_t *second_string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->previous, &closing);
- parser_lex(parser);
-
- pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
- pm_interpolated_symbol_node_append(interpolated, first_string);
- pm_interpolated_symbol_node_append(interpolated, second_string);
-
- xfree(current);
- current = (pm_node_t *) interpolated;
- } else {
- assert(false && "unreachable");
- }
-
- break;
- }
- case PM_TOKEN_EMBVAR: {
- bool start_location_set = false;
- if (current == NULL) {
- // If we hit an embedded variable and the current node is NULL,
- // then this is the start of a new string. We'll set the current
- // node to a new interpolated string.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- current = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
- } else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
- // If we hit an embedded variable and the current node is a string
- // node, then we'll convert the current into an interpolated
- // string and add the string node to the list of parts.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
-
- current = (pm_node_t *) pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current);
- pm_interpolated_symbol_node_append(interpolated, current);
- interpolated->base.location.start = current->location.start;
- start_location_set = true;
- current = (pm_node_t *) interpolated;
- } else {
- // If we hit an embedded variable and the current node is an
- // interpolated string, then we'll just add the embedded variable.
- }
-
- pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
- pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part);
- if (!start_location_set) {
- current->location.start = part->location.start;
- }
- break;
- }
- case PM_TOKEN_EMBEXPR_BEGIN: {
- bool start_location_set = false;
- if (current == NULL) {
- // If we hit an embedded expression and the current node is NULL,
- // then this is the start of a new string. We'll set the current
- // node to a new interpolated string.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- current = (pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
- } else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
- // If we hit an embedded expression and the current node is a
- // string node, then we'll convert the current into an
- // interpolated string and add the string node to the list of
- // parts.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
-
- current = (pm_node_t *) pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current);
- pm_interpolated_symbol_node_append(interpolated, current);
- interpolated->base.location.start = current->location.start;
- start_location_set = true;
- current = (pm_node_t *) interpolated;
- } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
- // If we hit an embedded expression and the current node is an
- // interpolated string, then we'll just continue on.
- } else {
- assert(false && "unreachable");
- }
-
- pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
- pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part);
- if (!start_location_set) {
- current->location.start = part->location.start;
- }
- break;
- }
- default:
- expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
- parser_lex(parser);
- break;
- }
- }
-
- // If we have a current node, then we need to append it to the list.
- if (current) {
- pm_array_node_elements_append(array, current);
- }
-
- pm_token_t closing = parser->current;
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
- }
- pm_array_node_close_set(array, &closing);
-
- return (pm_node_t *) array;
- }
- case PM_TOKEN_PERCENT_LOWER_W: {
- parser_lex(parser);
- pm_token_t opening = parser->previous;
- pm_array_node_t *array = pm_array_node_create(parser, &opening);
-
- // skip all leading whitespaces
- accept1(parser, PM_TOKEN_WORDS_SEP);
-
- while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- accept1(parser, PM_TOKEN_WORDS_SEP);
- if (match1(parser, PM_TOKEN_STRING_END)) break;
-
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
-
- pm_node_t *string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->current, &closing);
- pm_array_node_elements_append(array, string);
- }
-
- expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
- }
-
- pm_token_t closing = parser->current;
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
- }
-
- pm_array_node_close_set(array, &closing);
- return (pm_node_t *) array;
- }
- case PM_TOKEN_PERCENT_UPPER_W: {
- parser_lex(parser);
- pm_token_t opening = parser->previous;
- pm_array_node_t *array = pm_array_node_create(parser, &opening);
-
- // This is the current node that we are parsing that will be added
- // to the list of elements.
- pm_node_t *current = NULL;
-
- while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- switch (parser->current.type) {
- case PM_TOKEN_WORDS_SEP: {
- // Reset the explicit encoding if we hit a separator
- // since each element can have its own encoding.
- parser->explicit_encoding = NULL;
-
- if (current == NULL) {
- // If we hit a separator before we have any content,
- // then we don't need to do anything.
- } else {
- // If we hit a separator after we've hit content,
- // then we need to append that content to the list
- // and reset the current node.
- pm_array_node_elements_append(array, current);
- current = NULL;
- }
-
- parser_lex(parser);
- break;
- }
- case PM_TOKEN_STRING_CONTENT: {
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
-
- pm_node_t *string = (pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->current, &closing);
- pm_node_flag_set(string, parse_unescaped_encoding(parser));
- parser_lex(parser);
-
- if (current == NULL) {
- // If we hit content and the current node is NULL,
- // then this is the first string content we've seen.
- // In that case we're going to create a new string
- // node and set that to the current.
- current = string;
- } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
- // If we hit string content and the current node is
- // an interpolated string, then we need to append
- // the string content to the list of child nodes.
- pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, string);
- } else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
- // If we hit string content and the current node is
- // a string node, then we need to convert the
- // current node into an interpolated string and add
- // the string content to the list of child nodes.
- pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
- pm_interpolated_string_node_append(interpolated, current);
- pm_interpolated_string_node_append(interpolated, string);
- current = (pm_node_t *) interpolated;
- } else {
- assert(false && "unreachable");
- }
-
- break;
- }
- case PM_TOKEN_EMBVAR: {
- if (current == NULL) {
- // If we hit an embedded variable and the current
- // node is NULL, then this is the start of a new
- // string. We'll set the current node to a new
- // interpolated string.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- current = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
- } else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
- // If we hit an embedded variable and the current
- // node is a string node, then we'll convert the
- // current into an interpolated string and add the
- // string node to the list of parts.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
- pm_interpolated_string_node_append(interpolated, current);
- current = (pm_node_t *) interpolated;
- } else {
- // If we hit an embedded variable and the current
- // node is an interpolated string, then we'll just
- // add the embedded variable.
- }
-
- pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
- pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part);
- break;
- }
- case PM_TOKEN_EMBEXPR_BEGIN: {
- if (current == NULL) {
- // If we hit an embedded expression and the current
- // node is NULL, then this is the start of a new
- // string. We'll set the current node to a new
- // interpolated string.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- current = (pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
- } else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
- // If we hit an embedded expression and the current
- // node is a string node, then we'll convert the
- // current into an interpolated string and add the
- // string node to the list of parts.
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
- pm_interpolated_string_node_append(interpolated, current);
- current = (pm_node_t *) interpolated;
- } else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
- // If we hit an embedded expression and the current
- // node is an interpolated string, then we'll just
- // continue on.
- } else {
- assert(false && "unreachable");
- }
-
- pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
- pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part);
- break;
- }
- default:
- expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
- parser_lex(parser);
- break;
- }
- }
-
- // If we have a current node, then we need to append it to the list.
- if (current) {
- pm_array_node_elements_append(array, current);
- }
-
- pm_token_t closing = parser->current;
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
- }
-
- pm_array_node_close_set(array, &closing);
- return (pm_node_t *) array;
- }
- case PM_TOKEN_REGEXP_BEGIN: {
- pm_token_t opening = parser->current;
- parser_lex(parser);
-
- if (match1(parser, PM_TOKEN_REGEXP_END)) {
- // If we get here, then we have an end immediately after a start. In
- // that case we'll create an empty content token and return an
- // uninterpolated regular expression.
- pm_token_t content = (pm_token_t) {
- .type = PM_TOKEN_STRING_CONTENT,
- .start = parser->previous.end,
- .end = parser->previous.end
- };
-
- parser_lex(parser);
-
- pm_node_t *node = (pm_node_t *) pm_regular_expression_node_create(parser, &opening, &content, &parser->previous);
- pm_node_flag_set(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING);
-
- return node;
- }
-
- pm_interpolated_regular_expression_node_t *interpolated;
-
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- // In this case we've hit string content so we know the regular
- // expression at least has something in it. We'll need to check if the
- // following token is the end (in which case we can return a plain
- // regular expression) or if it's not then it has interpolation.
- pm_string_t unescaped = parser->current_string;
- pm_token_t content = parser->current;
- bool ascii_only = parser->current_regular_expression_ascii_only;
- parser_lex(parser);
-
- // If we hit an end, then we can create a regular expression
- // node without interpolation, which can be represented more
- // succinctly and more easily compiled.
- if (accept1(parser, PM_TOKEN_REGEXP_END)) {
- pm_regular_expression_node_t *node = (pm_regular_expression_node_t *) pm_regular_expression_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped);
-
- // If we're not immediately followed by a =~, then we want
- // to parse all of the errors at this point. If it is
- // followed by a =~, then it will get parsed higher up while
- // parsing the named captures as well.
- if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
- parse_regular_expression_errors(parser, node);
- }
-
- pm_node_flag_set((pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.flags));
- return (pm_node_t *) node;
- }
-
- // If we get here, then we have interpolation so we'll need to create
- // a regular expression node with interpolation.
- interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
-
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
- pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &parser->previous, &closing, &unescaped);
-
- if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
- // This is extremely strange, but the first string part of a
- // regular expression will always be tagged as binary if we
- // are in a US-ASCII file, no matter its contents.
- pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
- }
-
- pm_interpolated_regular_expression_node_append(interpolated, part);
- } else {
- // If the first part of the body of the regular expression is not a
- // string content, then we have interpolation and we need to create an
- // interpolated regular expression node.
- interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
- }
-
- // Now that we're here and we have interpolation, we'll parse all of the
- // parts into the list.
- pm_node_t *part;
- while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
- if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
- pm_interpolated_regular_expression_node_append(interpolated, part);
- }
- }
-
- pm_token_t closing = parser->current;
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- } else {
- expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
- }
-
- pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
- return (pm_node_t *) interpolated;
- }
- case PM_TOKEN_BACKTICK:
- case PM_TOKEN_PERCENT_LOWER_X: {
- parser_lex(parser);
- pm_token_t opening = parser->previous;
-
- // When we get here, we don't know if this string is going to have
- // interpolation or not, even though it is allowed. Still, we want to be
- // able to return a string node without interpolation if we can since
- // it'll be faster.
- if (match1(parser, PM_TOKEN_STRING_END)) {
- // If we get here, then we have an end immediately after a start. In
- // that case we'll create an empty content token and return an
- // uninterpolated string.
- pm_token_t content = (pm_token_t) {
- .type = PM_TOKEN_STRING_CONTENT,
- .start = parser->previous.end,
- .end = parser->previous.end
- };
-
- parser_lex(parser);
- return (pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->previous);
- }
-
- pm_interpolated_x_string_node_t *node;
-
- if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
- // In this case we've hit string content so we know the string
- // at least has something in it. We'll need to check if the
- // following token is the end (in which case we can return a
- // plain string) or if it's not then it has interpolation.
- pm_string_t unescaped = parser->current_string;
- pm_token_t content = parser->current;
- parser_lex(parser);
-
- if (match1(parser, PM_TOKEN_STRING_END)) {
- pm_node_t *node = (pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped);
- pm_node_flag_set(node, parse_unescaped_encoding(parser));
- parser_lex(parser);
- return node;
- }
-
- // If we get here, then we have interpolation so we'll need to
- // create a string node with interpolation.
- node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
-
- pm_token_t opening = not_provided(parser);
- pm_token_t closing = not_provided(parser);
-
- pm_node_t *part = (pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &parser->previous, &closing, &unescaped);
- pm_node_flag_set(part, parse_unescaped_encoding(parser));
-
- pm_interpolated_xstring_node_append(node, part);
- } else {
- // If the first part of the body of the string is not a string
- // content, then we have interpolation and we need to create an
- // interpolated string node.
- node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
- }
-
- pm_node_t *part;
- while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
- if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
- pm_interpolated_xstring_node_append(node, part);
- }
- }
-
- pm_token_t closing = parser->current;
- if (match1(parser, PM_TOKEN_EOF)) {
- pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
- closing = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- } else {
- expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
- }
- pm_interpolated_xstring_node_closing_set(node, &closing);
-
- return (pm_node_t *) node;
- }
- case PM_TOKEN_USTAR: {
- parser_lex(parser);
-
- // * operators at the beginning of expressions are only valid in the
- // context of a multiple assignment. We enforce that here. We'll
- // still lex past it though and create a missing node place.
- if (binding_power != PM_BINDING_POWER_STATEMENT) {
- pm_parser_err_prefix(parser, diag_id);
- return (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
- }
-
- pm_token_t operator = parser->previous;
- pm_node_t *name = NULL;
-
- if (token_begins_expression_p(parser->current.type)) {
- name = parse_expression(parser, PM_BINDING_POWER_INDEX, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
- }
-
- pm_node_t *splat = (pm_node_t *) pm_splat_node_create(parser, &operator, name);
-
- if (match1(parser, PM_TOKEN_COMMA)) {
- return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- } else {
- return parse_target_validate(parser, splat, true);
- }
- }
- case PM_TOKEN_BANG: {
- if (binding_power > PM_BINDING_POWER_UNARY) {
- pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
- }
-
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, binding_power < PM_BINDING_POWER_MATCH, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
- pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "!");
-
- pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
- return (pm_node_t *) node;
- }
- case PM_TOKEN_TILDE: {
- if (binding_power > PM_BINDING_POWER_UNARY) {
- pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
- }
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
- pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "~");
-
- return (pm_node_t *) node;
- }
- case PM_TOKEN_UMINUS: {
- if (binding_power > PM_BINDING_POWER_UNARY) {
- pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
- }
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
- pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "-@");
-
- return (pm_node_t *) node;
- }
- case PM_TOKEN_UMINUS_NUM: {
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
-
- if (accept1(parser, PM_TOKEN_STAR_STAR)) {
- pm_token_t exponent_operator = parser->previous;
- pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.type].right, false, false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
- node = (pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
- node = (pm_node_t *) pm_call_node_unary_create(parser, &operator, node, "-@");
- } else {
- switch (PM_NODE_TYPE(node)) {
- case PM_INTEGER_NODE:
- case PM_FLOAT_NODE:
- case PM_RATIONAL_NODE:
- case PM_IMAGINARY_NODE:
- parse_negative_numeric(node);
- break;
- default:
- node = (pm_node_t *) pm_call_node_unary_create(parser, &operator, node, "-@");
- break;
- }
- }
-
- return node;
- }
- case PM_TOKEN_MINUS_GREATER: {
- int previous_lambda_enclosure_nesting = parser->lambda_enclosure_nesting;
- parser->lambda_enclosure_nesting = parser->enclosure_nesting;
-
- size_t opening_newline_index = token_newline_index(parser);
- pm_accepts_block_stack_push(parser, true);
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_parser_scope_push(parser, false);
-
- pm_block_parameters_node_t *block_parameters;
-
- switch (parser->current.type) {
- case PM_TOKEN_PARENTHESIS_LEFT: {
- pm_token_t opening = parser->current;
- parser_lex(parser);
-
- if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
- block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
- } else {
- block_parameters = parse_block_parameters(parser, false, &opening, true, true, (uint16_t) (depth + 1));
- }
-
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
-
- pm_block_parameters_node_closing_set(block_parameters, &parser->previous);
- break;
- }
- case PM_CASE_PARAMETER: {
- pm_accepts_block_stack_push(parser, false);
- pm_token_t opening = not_provided(parser);
- block_parameters = parse_block_parameters(parser, false, &opening, true, false, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- break;
- }
- default: {
- block_parameters = NULL;
- break;
- }
- }
-
- pm_token_t opening;
- pm_node_t *body = NULL;
- parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
-
- if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
- opening = parser->previous;
-
- if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
- body = (pm_node_t *) parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES, (uint16_t) (depth + 1));
- }
-
- parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false);
- expect1(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE);
- } else {
- expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
- opening = parser->previous;
-
- if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
- pm_accepts_block_stack_push(parser, true);
- body = (pm_node_t *) parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- }
-
- if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
- assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
- body = (pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &operator, opening.start, (pm_statements_node_t *) body, PM_RESCUES_LAMBDA, (uint16_t) (depth + 1));
- } else {
- parser_warn_indentation_mismatch(parser, opening_newline_index, &operator, false, false);
- }
-
- expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END);
- }
-
- pm_constant_id_list_t locals;
- pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
- pm_node_t *parameters = parse_blocklike_parameters(parser, (pm_node_t *) block_parameters, &operator, &parser->previous);
-
- pm_parser_scope_pop(parser);
- pm_accepts_block_stack_pop(parser);
-
- return (pm_node_t *) pm_lambda_node_create(parser, &locals, &operator, &opening, &parser->previous, parameters, body);
- }
- case PM_TOKEN_UPLUS: {
- if (binding_power > PM_BINDING_POWER_UNARY) {
- pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
- }
- parser_lex(parser);
-
- pm_token_t operator = parser->previous;
- pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.type].right, false, false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
- pm_call_node_t *node = pm_call_node_unary_create(parser, &operator, receiver, "+@");
-
- return (pm_node_t *) node;
- }
- case PM_TOKEN_STRING_BEGIN:
- return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
- case PM_TOKEN_SYMBOL_BEGIN: {
- pm_lex_mode_t lex_mode = *parser->lex_modes.current;
- parser_lex(parser);
-
- return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
- }
- default: {
- pm_context_t recoverable = context_recoverable(parser, &parser->current);
-
- if (recoverable != PM_CONTEXT_NONE) {
- parser->recovering = true;
-
- // If the given error is not the generic one, then we'll add it
- // here because it will provide more context in addition to the
- // recoverable error that we will also add.
- if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
- pm_parser_err_prefix(parser, diag_id);
- }
-
- // If we get here, then we are assuming this token is closing a
- // parent context, so we'll indicate that to the user so that
- // they know how we behaved.
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_type_human(parser->current.type), context_human(recoverable));
- } else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
- // We're going to make a special case here, because "cannot
- // parse expression" is pretty generic, and we know here that we
- // have an unexpected token.
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_type_human(parser->current.type));
- } else {
- pm_parser_err_prefix(parser, diag_id);
- }
-
- return (pm_node_t *) pm_missing_node_create(parser, parser->previous.start, parser->previous.end);
- }
- }
-}
-
-/**
- * Parse a value that is going to be written to some kind of variable or method
- * call. We need to handle this separately because the rescue modifier is
- * permitted on the end of the these expressions, which is a deviation from its
- * normal binding power.
- *
- * Note that this will only be called after an operator write, as in &&=, ||=,
- * or any of the binary operators that can be written to a variable.
- */
-static pm_node_t *
-parse_assignment_value(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id, uint16_t depth) {
- pm_node_t *value = parse_value_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, false, diag_id, (uint16_t) (depth + 1));
-
- // Contradicting binding powers, the right-hand-side value of the assignment
- // allows the `rescue` modifier.
- if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
- context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
-
- pm_token_t rescue = parser->current;
- parser_lex(parser);
-
- pm_node_t *right = parse_expression(parser, binding_power, false, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
- context_pop(parser);
-
- return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
- }
-
- return value;
-}
-
-/**
- * When a local variable write node is the value being written in a different
- * write, the local variable is considered "used".
- */
-static void
-parse_assignment_value_local(pm_parser_t *parser, const pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- case PM_BEGIN_NODE: {
- const pm_begin_node_t *cast = (const pm_begin_node_t *) node;
- if (cast->statements != NULL) parse_assignment_value_local(parser, (const pm_node_t *) cast->statements);
- break;
- }
- case PM_LOCAL_VARIABLE_WRITE_NODE: {
- const pm_local_variable_write_node_t *cast = (const pm_local_variable_write_node_t *) node;
- pm_locals_read(&pm_parser_scope_find(parser, cast->depth)->locals, cast->name);
- break;
- }
- case PM_PARENTHESES_NODE: {
- const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
- if (cast->body != NULL) parse_assignment_value_local(parser, cast->body);
- break;
- }
- case PM_STATEMENTS_NODE: {
- const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
- const pm_node_t *statement;
-
- PM_NODE_LIST_FOREACH(&cast->body, index, statement) {
- parse_assignment_value_local(parser, statement);
- }
- break;
- }
- default:
- break;
- }
-}
-
-/**
- * Parse the value (or values, through an implicit array) that is going to be
- * written to some kind of variable or method call. We need to handle this
- * separately because the rescue modifier is permitted on the end of the these
- * expressions, which is a deviation from its normal binding power.
- *
- * Additionally, if the value is a local variable write node (e.g., a = a = 1),
- * the "a" is marked as being used so the parser should not warn on it.
- *
- * Note that this will only be called after an = operator, as that is the only
- * operator that allows multiple values after it.
- */
-static pm_node_t *
-parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, pm_diagnostic_id_t diag_id, uint16_t depth) {
- bool permitted = true;
- if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted = false;
-
- pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, diag_id, (uint16_t) (depth + 1));
- if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
-
- parse_assignment_value_local(parser, value);
- bool single_value = true;
-
- if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
- single_value = false;
-
- pm_token_t opening = not_provided(parser);
- pm_array_node_t *array = pm_array_node_create(parser, &opening);
-
- pm_array_node_elements_append(array, value);
- value = (pm_node_t *) array;
-
- while (accept1(parser, PM_TOKEN_COMMA)) {
- pm_node_t *element = parse_starred_expression(parser, binding_power, false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
-
- pm_array_node_elements_append(array, element);
- if (PM_NODE_TYPE_P(element, PM_MISSING_NODE)) break;
-
- parse_assignment_value_local(parser, element);
- }
- }
-
- // Contradicting binding powers, the right-hand-side value of the assignment
- // allows the `rescue` modifier.
- if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
- context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
-
- pm_token_t rescue = parser->current;
- parser_lex(parser);
-
- bool accepts_command_call_inner = false;
-
- // RHS can accept command call iff the value is a call with arguments
- // but without parenthesis.
- if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
- pm_call_node_t *call_node = (pm_call_node_t *) value;
- if ((call_node->arguments != NULL) && (call_node->opening_loc.start == NULL)) {
- accepts_command_call_inner = true;
- }
- }
-
- pm_node_t *right = parse_expression(parser, binding_power, accepts_command_call_inner, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
- context_pop(parser);
-
- return (pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
- }
-
- return value;
-}
-
-/**
- * Ensure a call node that is about to become a call operator node does not
- * have arguments or a block attached. If it does, then we'll need to add an
- * error message and destroy the arguments/block. Ideally we would keep the node
- * around so that consumers would still have access to it, but we don't have a
- * great structure for that at the moment.
- */
-static void
-parse_call_operator_write(pm_parser_t *parser, pm_call_node_t *call_node, const pm_token_t *operator) {
- if (call_node->arguments != NULL) {
- pm_parser_err_token(parser, operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
- pm_node_destroy(parser, (pm_node_t *) call_node->arguments);
- call_node->arguments = NULL;
- }
-
- if (call_node->block != NULL) {
- pm_parser_err_token(parser, operator, PM_ERR_OPERATOR_WRITE_BLOCK);
- pm_node_destroy(parser, (pm_node_t *) call_node->block);
- call_node->block = NULL;
- }
-}
-
-/**
- * This struct is used to pass information between the regular expression parser
- * and the named capture callback.
- */
-typedef struct {
- /** The parser that is parsing the regular expression. */
- pm_parser_t *parser;
-
- /** The call node wrapping the regular expression node. */
- pm_call_node_t *call;
-
- /** The match write node that is being created. */
- pm_match_write_node_t *match;
-
- /** The list of names that have been parsed. */
- pm_constant_id_list_t names;
-
- /**
- * Whether the content of the regular expression is shared. This impacts
- * whether or not we used owned constants or shared constants in the
- * constant pool for the names of the captures.
- */
- bool shared;
-} parse_regular_expression_named_capture_data_t;
-
-/**
- * This callback is called when the regular expression parser encounters a named
- * capture group.
- */
-static void
-parse_regular_expression_named_capture(const pm_string_t *capture, void *data) {
- parse_regular_expression_named_capture_data_t *callback_data = (parse_regular_expression_named_capture_data_t *) data;
-
- pm_parser_t *parser = callback_data->parser;
- pm_call_node_t *call = callback_data->call;
- pm_constant_id_list_t *names = &callback_data->names;
-
- const uint8_t *source = pm_string_source(capture);
- size_t length = pm_string_length(capture);
-
- pm_location_t location;
- pm_constant_id_t name;
-
- // If the name of the capture group isn't a valid identifier, we do
- // not add it to the local table.
- if (!pm_slice_is_valid_local(parser, source, source + length)) return;
-
- if (callback_data->shared) {
- // If the unescaped string is a slice of the source, then we can
- // copy the names directly. The pointers will line up.
- location = (pm_location_t) { .start = source, .end = source + length };
- name = pm_parser_constant_id_location(parser, location.start, location.end);
- } else {
- // Otherwise, the name is a slice of the malloc-ed owned string,
- // in which case we need to copy it out into a new string.
- location = (pm_location_t) { .start = call->receiver->location.start, .end = call->receiver->location.end };
-
- void *memory = xmalloc(length);
- if (memory == NULL) abort();
-
- memcpy(memory, source, length);
- name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
- }
-
- // Add this name to the list of constants if it is valid, not duplicated,
- // and not a keyword.
- if (name != 0 && !pm_constant_id_list_includes(names, name)) {
- pm_constant_id_list_append(names, name);
-
- int depth;
- if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
- // If the local is not already a local but it is a keyword, then we
- // do not want to add a capture for this.
- if (pm_local_is_keyword((const char *) source, length)) return;
-
- // If the identifier is not already a local, then we will add it to
- // the local table.
- pm_parser_local_add(parser, name, location.start, location.end, 0);
- }
-
- // Here we lazily create the MatchWriteNode since we know we're
- // about to add a target.
- if (callback_data->match == NULL) {
- callback_data->match = pm_match_write_node_create(parser, call);
- }
-
- // Next, create the local variable target and add it to the list of
- // targets for the match.
- pm_node_t *target = (pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
- pm_node_list_append(&callback_data->match->targets, target);
- }
-}
-
-/**
- * Potentially change a =~ with a regular expression with named captures into a
- * match write node.
- */
-static pm_node_t *
-parse_regular_expression_named_captures(pm_parser_t *parser, const pm_string_t *content, pm_call_node_t *call, bool extended_mode) {
- parse_regular_expression_named_capture_data_t callback_data = {
- .parser = parser,
- .call = call,
- .names = { 0 },
- .shared = content->type == PM_STRING_SHARED
- };
-
- parse_regular_expression_error_data_t error_data = {
- .parser = parser,
- .start = call->receiver->location.start,
- .end = call->receiver->location.end,
- .shared = content->type == PM_STRING_SHARED
- };
-
- pm_regexp_parse(parser, pm_string_source(content), pm_string_length(content), extended_mode, parse_regular_expression_named_capture, &callback_data, parse_regular_expression_error, &error_data);
- pm_constant_id_list_free(&callback_data.names);
-
- if (callback_data.match != NULL) {
- return (pm_node_t *) callback_data.match;
- } else {
- return (pm_node_t *) call;
- }
-}
-
-static inline pm_node_t *
-parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, bool accepts_command_call, uint16_t depth) {
- pm_token_t token = parser->current;
-
- switch (token.type) {
- case PM_TOKEN_EQUAL: {
- switch (PM_NODE_TYPE(node)) {
- case PM_CALL_NODE: {
- // If we have no arguments to the call node and we need this
- // to be a target then this is either a method call or a
- // local variable write. This _must_ happen before the value
- // is parsed because it could be referenced in the value.
- pm_call_node_t *call_node = (pm_call_node_t *) node;
- if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- pm_parser_local_add_location(parser, call_node->message_loc.start, call_node->message_loc.end, 0);
- }
- }
- /* fallthrough */
- case PM_CASE_WRITABLE: {
- parser_lex(parser);
- pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) ? PM_BINDING_POWER_MULTI_ASSIGNMENT + 1 : binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
-
- if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
- pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
- }
-
- return parse_write(parser, node, &token, value);
- }
- case PM_SPLAT_NODE: {
- pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
- pm_multi_target_node_targets_append(parser, multi_target, node);
-
- parser_lex(parser);
- pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
- return parse_write(parser, (pm_node_t *) multi_target, &token, value);
- }
- case PM_SOURCE_ENCODING_NODE:
- case PM_FALSE_NODE:
- case PM_SOURCE_FILE_NODE:
- case PM_SOURCE_LINE_NODE:
- case PM_NIL_NODE:
- case PM_SELF_NODE:
- case PM_TRUE_NODE: {
- // In these special cases, we have specific error messages
- // and we will replace them with local variable writes.
- parser_lex(parser);
- pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
- return parse_unwriteable_write(parser, node, &token, value);
- }
- default:
- // In this case we have an = sign, but we don't know what
- // it's for. We need to treat it as an error. We'll mark it
- // as an error and skip past it.
- parser_lex(parser);
- pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
- return node;
- }
- }
- case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
- switch (PM_NODE_TYPE(node)) {
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
- /* fallthrough */
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CLASS_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_class_variable_and_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CONSTANT_PATH_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
- pm_node_t *write = (pm_node_t *) pm_constant_path_and_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
-
- return parse_shareable_constant_write(parser, write);
- }
- case PM_CONSTANT_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
- pm_node_t *write = (pm_node_t *) pm_constant_and_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return parse_shareable_constant_write(parser, write);
- }
- case PM_INSTANCE_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_instance_variable_and_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_LOCAL_VARIABLE_READ_NODE: {
- pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, cast->name, cast->depth);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CALL_NODE: {
- pm_call_node_t *cast = (pm_call_node_t *) node;
-
- // If we have a vcall (a method with no arguments and no
- // receiver that could have been a local variable) then we
- // will transform it into a local variable write.
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- pm_location_t *message_loc = &cast->message_loc;
- pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
-
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 1);
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_local_variable_and_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
-
- pm_node_destroy(parser, (pm_node_t *) cast);
- return result;
- }
-
- // Move past the token here so that we have already added
- // the local variable by this point.
- parser_lex(parser);
-
- // If there is no call operator and the message is "[]" then
- // this is an aref expression, and we can transform it into
- // an aset expression.
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
- }
-
- // If this node cannot be writable, then we have an error.
- if (pm_call_node_writable_p(parser, cast)) {
- parse_write_name(parser, &cast->name);
- } else {
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
-
- parse_call_operator_write(parser, cast, &token);
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
- }
- case PM_MULTI_WRITE_NODE: {
- parser_lex(parser);
- pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
- return node;
- }
- default:
- parser_lex(parser);
-
- // In this case we have an &&= sign, but we don't know what it's for.
- // We need to treat it as an error. For now, we'll mark it as an error
- // and just skip right past it.
- pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
- return node;
- }
- }
- case PM_TOKEN_PIPE_PIPE_EQUAL: {
- switch (PM_NODE_TYPE(node)) {
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
- /* fallthrough */
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CLASS_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_class_variable_or_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CONSTANT_PATH_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
- pm_node_t *write = (pm_node_t *) pm_constant_path_or_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
-
- return parse_shareable_constant_write(parser, write);
- }
- case PM_CONSTANT_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
- pm_node_t *write = (pm_node_t *) pm_constant_or_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return parse_shareable_constant_write(parser, write);
- }
- case PM_INSTANCE_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_instance_variable_or_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_LOCAL_VARIABLE_READ_NODE: {
- pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, cast->name, cast->depth);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CALL_NODE: {
- pm_call_node_t *cast = (pm_call_node_t *) node;
-
- // If we have a vcall (a method with no arguments and no
- // receiver that could have been a local variable) then we
- // will transform it into a local variable write.
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- pm_location_t *message_loc = &cast->message_loc;
- pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
-
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 1);
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_local_variable_or_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
-
- pm_node_destroy(parser, (pm_node_t *) cast);
- return result;
- }
-
- // Move past the token here so that we have already added
- // the local variable by this point.
- parser_lex(parser);
-
- // If there is no call operator and the message is "[]" then
- // this is an aref expression, and we can transform it into
- // an aset expression.
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
- }
-
- // If this node cannot be writable, then we have an error.
- if (pm_call_node_writable_p(parser, cast)) {
- parse_write_name(parser, &cast->name);
- } else {
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
-
- parse_call_operator_write(parser, cast, &token);
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
- }
- case PM_MULTI_WRITE_NODE: {
- parser_lex(parser);
- pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
- return node;
- }
- default:
- parser_lex(parser);
-
- // In this case we have an ||= sign, but we don't know what it's for.
- // We need to treat it as an error. For now, we'll mark it as an error
- // and just skip right past it.
- pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
- return node;
- }
- }
- case PM_TOKEN_AMPERSAND_EQUAL:
- case PM_TOKEN_CARET_EQUAL:
- case PM_TOKEN_GREATER_GREATER_EQUAL:
- case PM_TOKEN_LESS_LESS_EQUAL:
- case PM_TOKEN_MINUS_EQUAL:
- case PM_TOKEN_PERCENT_EQUAL:
- case PM_TOKEN_PIPE_EQUAL:
- case PM_TOKEN_PLUS_EQUAL:
- case PM_TOKEN_SLASH_EQUAL:
- case PM_TOKEN_STAR_EQUAL:
- case PM_TOKEN_STAR_STAR_EQUAL: {
- switch (PM_NODE_TYPE(node)) {
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
- /* fallthrough */
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CLASS_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_class_variable_operator_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CONSTANT_PATH_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- pm_node_t *write = (pm_node_t *) pm_constant_path_operator_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value);
-
- return parse_shareable_constant_write(parser, write);
- }
- case PM_CONSTANT_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- pm_node_t *write = (pm_node_t *) pm_constant_operator_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return parse_shareable_constant_write(parser, write);
- }
- case PM_INSTANCE_VARIABLE_READ_NODE: {
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_instance_variable_operator_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_LOCAL_VARIABLE_READ_NODE: {
- pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
- parser_lex(parser);
-
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->name, cast->depth);
-
- pm_node_destroy(parser, node);
- return result;
- }
- case PM_CALL_NODE: {
- parser_lex(parser);
- pm_call_node_t *cast = (pm_call_node_t *) node;
-
- // If we have a vcall (a method with no arguments and no
- // receiver that could have been a local variable) then we
- // will transform it into a local variable write.
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- pm_location_t *message_loc = &cast->message_loc;
- pm_refute_numbered_parameter(parser, message_loc->start, message_loc->end);
-
- pm_constant_id_t constant_id = pm_parser_local_add_location(parser, message_loc->start, message_loc->end, 1);
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- pm_node_t *result = (pm_node_t *) pm_local_variable_operator_write_node_create(parser, (pm_node_t *) cast, &token, value, constant_id, 0);
-
- pm_node_destroy(parser, (pm_node_t *) cast);
- return result;
- }
-
- // If there is no call operator and the message is "[]" then
- // this is an aref expression, and we can transform it into
- // an aset expression.
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
- }
-
- // If this node cannot be writable, then we have an error.
- if (pm_call_node_writable_p(parser, cast)) {
- parse_write_name(parser, &cast->name);
- } else {
- pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
- }
-
- parse_call_operator_write(parser, cast, &token);
- pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
- }
- case PM_MULTI_WRITE_NODE: {
- parser_lex(parser);
- pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
- return node;
- }
- default:
- parser_lex(parser);
-
- // In this case we have an operator but we don't know what it's for.
- // We need to treat it as an error. For now, we'll mark it as an error
- // and just skip right past it.
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_type_human(parser->current.type));
- return node;
- }
- }
- case PM_TOKEN_AMPERSAND_AMPERSAND:
- case PM_TOKEN_KEYWORD_AND: {
- parser_lex(parser);
-
- pm_node_t *right = parse_expression(parser, binding_power, parser->previous.type == PM_TOKEN_KEYWORD_AND, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_and_node_create(parser, node, &token, right);
- }
- case PM_TOKEN_KEYWORD_OR:
- case PM_TOKEN_PIPE_PIPE: {
- parser_lex(parser);
-
- pm_node_t *right = parse_expression(parser, binding_power, parser->previous.type == PM_TOKEN_KEYWORD_OR, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_or_node_create(parser, node, &token, right);
- }
- case PM_TOKEN_EQUAL_TILDE: {
- // Note that we _must_ parse the value before adding the local
- // variables in order to properly mirror the behavior of Ruby. For
- // example,
- //
- // /(?<foo>bar)/ =~ foo
- //
- // In this case, `foo` should be a method call and not a local yet.
- parser_lex(parser);
- pm_node_t *argument = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
-
- // By default, we're going to create a call node and then return it.
- pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
- pm_node_t *result = (pm_node_t *) call;
-
- // If the receiver of this =~ is a regular expression node, then we
- // need to introduce local variables for it based on its named
- // capture groups.
- if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
- // It's possible to have an interpolated regular expression node
- // that only contains strings. This is because it can be split
- // up by a heredoc. In this case we need to concat the unescaped
- // strings together and then parse them as a regular expression.
- pm_node_list_t *parts = &((pm_interpolated_regular_expression_node_t *) node)->parts;
-
- bool interpolated = false;
- size_t total_length = 0;
-
- pm_node_t *part;
- PM_NODE_LIST_FOREACH(parts, index, part) {
- if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
- total_length += pm_string_length(&((pm_string_node_t *) part)->unescaped);
- } else {
- interpolated = true;
- break;
- }
- }
-
- if (!interpolated && total_length > 0) {
- void *memory = xmalloc(total_length);
- if (!memory) abort();
-
- uint8_t *cursor = memory;
- PM_NODE_LIST_FOREACH(parts, index, part) {
- pm_string_t *unescaped = &((pm_string_node_t *) part)->unescaped;
- size_t length = pm_string_length(unescaped);
-
- memcpy(cursor, pm_string_source(unescaped), length);
- cursor += length;
- }
-
- pm_string_t owned;
- pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
-
- result = parse_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
- pm_string_free(&owned);
- }
- } else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
- // If we have a regular expression node, then we can just parse
- // the named captures directly off the unescaped string.
- const pm_string_t *content = &((pm_regular_expression_node_t *) node)->unescaped;
- result = parse_regular_expression_named_captures(parser, content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
- }
-
- return result;
- }
- case PM_TOKEN_UAMPERSAND:
- case PM_TOKEN_USTAR:
- case PM_TOKEN_USTAR_STAR:
- // The only times this will occur are when we are in an error state,
- // but we'll put them in here so that errors can propagate.
- case PM_TOKEN_BANG_EQUAL:
- case PM_TOKEN_BANG_TILDE:
- case PM_TOKEN_EQUAL_EQUAL:
- case PM_TOKEN_EQUAL_EQUAL_EQUAL:
- case PM_TOKEN_LESS_EQUAL_GREATER:
- case PM_TOKEN_CARET:
- case PM_TOKEN_PIPE:
- case PM_TOKEN_AMPERSAND:
- case PM_TOKEN_GREATER_GREATER:
- case PM_TOKEN_LESS_LESS:
- case PM_TOKEN_MINUS:
- case PM_TOKEN_PLUS:
- case PM_TOKEN_PERCENT:
- case PM_TOKEN_SLASH:
- case PM_TOKEN_STAR:
- case PM_TOKEN_STAR_STAR: {
- parser_lex(parser);
- pm_node_t *argument = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
- }
- case PM_TOKEN_GREATER:
- case PM_TOKEN_GREATER_EQUAL:
- case PM_TOKEN_LESS:
- case PM_TOKEN_LESS_EQUAL: {
- if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
- PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_WARN_COMPARISON_AFTER_COMPARISON);
- }
-
- parser_lex(parser);
- pm_node_t *argument = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
- }
- case PM_TOKEN_AMPERSAND_DOT:
- case PM_TOKEN_DOT: {
- parser_lex(parser);
- pm_token_t operator = parser->previous;
- pm_arguments_t arguments = { 0 };
-
- // This if statement handles the foo.() syntax.
- if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
- parse_arguments_list(parser, &arguments, true, false, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &operator, &arguments);
- }
-
- pm_token_t message;
-
- switch (parser->current.type) {
- case PM_CASE_OPERATOR:
- case PM_CASE_KEYWORD:
- case PM_TOKEN_CONSTANT:
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_METHOD_NAME: {
- parser_lex(parser);
- message = parser->previous;
- break;
- }
- default: {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_type_human(parser->current.type));
- message = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- }
- }
-
- parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1));
- pm_call_node_t *call = pm_call_node_call_create(parser, node, &operator, &message, &arguments);
-
- if (
- (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
- arguments.arguments == NULL &&
- arguments.opening_loc.start == NULL &&
- match1(parser, PM_TOKEN_COMMA)
- ) {
- return parse_targets_validate(parser, (pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- } else {
- return (pm_node_t *) call;
- }
- }
- case PM_TOKEN_DOT_DOT:
- case PM_TOKEN_DOT_DOT_DOT: {
- parser_lex(parser);
-
- pm_node_t *right = NULL;
- if (token_begins_expression_p(parser->current.type)) {
- right = parse_expression(parser, binding_power, false, false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
- }
-
- return (pm_node_t *) pm_range_node_create(parser, node, &token, right);
- }
- case PM_TOKEN_KEYWORD_IF_MODIFIER: {
- pm_token_t keyword = parser->current;
- parser_lex(parser);
-
- pm_node_t *predicate = parse_value_expression(parser, binding_power, true, false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
- }
- case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
- pm_token_t keyword = parser->current;
- parser_lex(parser);
-
- pm_node_t *predicate = parse_value_expression(parser, binding_power, true, false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
- }
- case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
- parser_lex(parser);
- pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(parser, statements, node, true);
-
- pm_node_t *predicate = parse_value_expression(parser, binding_power, true, false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
- }
- case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
- parser_lex(parser);
- pm_statements_node_t *statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(parser, statements, node, true);
-
- pm_node_t *predicate = parse_value_expression(parser, binding_power, true, false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
- return (pm_node_t *) pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0);
- }
- case PM_TOKEN_QUESTION_MARK: {
- context_push(parser, PM_CONTEXT_TERNARY);
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- pm_token_t qmark = parser->current;
- parser_lex(parser);
-
- pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
-
- if (parser->recovering) {
- // If parsing the true expression of this ternary resulted in a syntax
- // error that we can recover from, then we're going to put missing nodes
- // and tokens into the remaining places. We want to be sure to do this
- // before the `expect` function call to make sure it doesn't
- // accidentally move past a ':' token that occurs after the syntax
- // error.
- pm_token_t colon = (pm_token_t) { .type = PM_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
- pm_node_t *false_expression = (pm_node_t *) pm_missing_node_create(parser, colon.start, colon.end);
-
- context_pop(parser);
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
- }
-
- accept1(parser, PM_TOKEN_NEWLINE);
- expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
-
- pm_token_t colon = parser->previous;
- pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, false, false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
-
- context_pop(parser);
- pop_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
-
- return (pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
- }
- case PM_TOKEN_COLON_COLON: {
- parser_lex(parser);
- pm_token_t delimiter = parser->previous;
-
- switch (parser->current.type) {
- case PM_TOKEN_CONSTANT: {
- parser_lex(parser);
- pm_node_t *path;
-
- if (
- (parser->current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
- (accepts_command_call && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
- ) {
- // If we have a constant immediately following a '::' operator, then
- // this can either be a constant path or a method call, depending on
- // what follows the constant.
- //
- // If we have parentheses, then this is a method call. That would
- // look like Foo::Bar().
- pm_token_t message = parser->previous;
- pm_arguments_t arguments = { 0 };
-
- parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1));
- path = (pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
- } else {
- // Otherwise, this is a constant path. That would look like Foo::Bar.
- path = (pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->previous);
- }
-
- // If this is followed by a comma then it is a multiple assignment.
- if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- }
-
- return path;
- }
- case PM_CASE_OPERATOR:
- case PM_CASE_KEYWORD:
- case PM_TOKEN_IDENTIFIER:
- case PM_TOKEN_METHOD_NAME: {
- parser_lex(parser);
- pm_token_t message = parser->previous;
-
- // If we have an identifier following a '::' operator, then it is for
- // sure a method call.
- pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true, accepts_command_call, (uint16_t) (depth + 1));
- pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
-
- // If this is followed by a comma then it is a multiple assignment.
- if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- return parse_targets_validate(parser, (pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- }
-
- return (pm_node_t *) call;
- }
- case PM_TOKEN_PARENTHESIS_LEFT: {
- // If we have a parenthesis following a '::' operator, then it is the
- // method call shorthand. That would look like Foo::(bar).
- pm_arguments_t arguments = { 0 };
- parse_arguments_list(parser, &arguments, true, false, (uint16_t) (depth + 1));
-
- return (pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
- }
- default: {
- expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
- return (pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->previous);
- }
- }
- }
- case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
- context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
- parser_lex(parser);
- accept1(parser, PM_TOKEN_NEWLINE);
-
- pm_node_t *value = parse_expression(parser, binding_power, true, false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
- context_pop(parser);
-
- return (pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
- }
- case PM_TOKEN_BRACKET_LEFT: {
- parser_lex(parser);
-
- pm_arguments_t arguments = { 0 };
- arguments.opening_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
-
- if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
- pm_accepts_block_stack_push(parser, true);
- parse_arguments(parser, &arguments, false, PM_TOKEN_BRACKET_RIGHT, (uint16_t) (depth + 1));
- pm_accepts_block_stack_pop(parser);
- expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
- }
-
- arguments.closing_loc = PM_LOCATION_TOKEN_VALUE(&parser->previous);
-
- // If we have a comma after the closing bracket then this is a multiple
- // assignment and we should parse the targets.
- if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
- pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
- return parse_targets_validate(parser, (pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
- }
-
- // If we're at the end of the arguments, we can now check if there is a
- // block node that starts with a {. If there is, then we can parse it and
- // add it to the arguments.
- pm_block_node_t *block = NULL;
- if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
- block = parse_block(parser, (uint16_t) (depth + 1));
- pm_arguments_validate_block(parser, &arguments, block);
- } else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
- block = parse_block(parser, (uint16_t) (depth + 1));
- }
-
- if (block != NULL) {
- if (arguments.block != NULL) {
- pm_parser_err_node(parser, (pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
- if (arguments.arguments == NULL) {
- arguments.arguments = pm_arguments_node_create(parser);
- }
- pm_arguments_node_arguments_append(arguments.arguments, arguments.block);
- }
-
- arguments.block = (pm_node_t *) block;
- }
-
- return (pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
- }
- case PM_TOKEN_KEYWORD_IN: {
- bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
- parser->pattern_matching_newlines = true;
-
- pm_token_t operator = parser->current;
- parser->command_start = false;
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- parser_lex(parser);
-
- pm_constant_id_list_t captures = { 0 };
- pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN, (uint16_t) (depth + 1));
-
- parser->pattern_matching_newlines = previous_pattern_matching_newlines;
- pm_constant_id_list_free(&captures);
-
- return (pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &operator);
- }
- case PM_TOKEN_EQUAL_GREATER: {
- bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
- parser->pattern_matching_newlines = true;
-
- pm_token_t operator = parser->current;
- parser->command_start = false;
- lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
- parser_lex(parser);
-
- pm_constant_id_list_t captures = { 0 };
- pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET, (uint16_t) (depth + 1));
-
- parser->pattern_matching_newlines = previous_pattern_matching_newlines;
- pm_constant_id_list_free(&captures);
-
- return (pm_node_t *) pm_match_required_node_create(parser, node, pattern, &operator);
- }
- default:
- assert(false && "unreachable");
- return NULL;
- }
-}
-
-#undef PM_PARSE_PATTERN_SINGLE
-#undef PM_PARSE_PATTERN_TOP
-#undef PM_PARSE_PATTERN_MULTI
-
-/**
- * Determine if a given call node looks like a "command", which means it has
- * arguments but does not have parentheses.
- */
-static inline bool
-pm_call_node_command_p(const pm_call_node_t *node) {
- return (
- (node->opening_loc.start == NULL) &&
- (node->block == NULL || PM_NODE_TYPE_P(node->block, PM_BLOCK_ARGUMENT_NODE)) &&
- (node->arguments != NULL || node->block != NULL)
- );
-}
-
-/**
- * Parse an expression at the given point of the parser using the given binding
- * power to parse subsequent chains. If this function finds a syntax error, it
- * will append the error message to the parser's error list.
- *
- * Consumers of this function should always check parser->recovering to
- * determine if they need to perform additional cleanup.
- */
-static pm_node_t *
-parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool accepts_command_call, bool accepts_label, pm_diagnostic_id_t diag_id, uint16_t depth) {
- if (PRISM_UNLIKELY(depth >= PRISM_DEPTH_MAXIMUM)) {
- pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
- return (pm_node_t *) pm_missing_node_create(parser, parser->current.start, parser->current.end);
- }
-
- pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
-
- switch (PM_NODE_TYPE(node)) {
- case PM_MISSING_NODE:
- // If we found a syntax error, then the type of node returned by
- // parse_expression_prefix is going to be a missing node.
- return node;
- case PM_PRE_EXECUTION_NODE:
- case PM_POST_EXECUTION_NODE:
- case PM_ALIAS_GLOBAL_VARIABLE_NODE:
- case PM_ALIAS_METHOD_NODE:
- case PM_MULTI_WRITE_NODE:
- case PM_UNDEF_NODE:
- // These expressions are statements, and cannot be followed by
- // operators (except modifiers).
- if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
- return node;
- }
- break;
- case PM_CALL_NODE:
- // If we have a call node, then we need to check if it looks like a
- // method call without parentheses that contains arguments. If it
- // does, then it has different rules for parsing infix operators,
- // namely that it only accepts composition (and/or) and modifiers
- // (if/unless/etc.).
- if ((pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((pm_call_node_t *) node)) {
- return node;
- }
- break;
- case PM_SYMBOL_NODE:
- // If we have a symbol node that is being parsed as a label, then we
- // need to immediately return, because there should never be an
- // infix operator following this node.
- if (pm_symbol_node_label_p(node)) {
- return node;
- }
- default:
- break;
- }
-
- // Otherwise we'll look and see if the next token can be parsed as an infix
- // operator. If it can, then we'll parse it using parse_expression_infix.
- pm_binding_powers_t current_binding_powers;
- while (
- current_binding_powers = pm_binding_powers[parser->current.type],
- binding_power <= current_binding_powers.left &&
- current_binding_powers.binary
- ) {
- node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right, accepts_command_call, (uint16_t) (depth + 1));
-
- switch (PM_NODE_TYPE(node)) {
- case PM_MULTI_WRITE_NODE:
- // Multi-write nodes are statements, and cannot be followed by
- // operators except modifiers.
- if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
- return node;
- }
- break;
- case PM_CLASS_VARIABLE_WRITE_NODE:
- case PM_CONSTANT_PATH_WRITE_NODE:
- case PM_CONSTANT_WRITE_NODE:
- case PM_GLOBAL_VARIABLE_WRITE_NODE:
- case PM_INSTANCE_VARIABLE_WRITE_NODE:
- case PM_LOCAL_VARIABLE_WRITE_NODE:
- // These expressions are statements, by virtue of the right-hand
- // side of their write being an implicit array.
- if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
- return node;
- }
- break;
- case PM_CALL_NODE:
- // These expressions are also statements, by virtue of the
- // right-hand side of the expression (i.e., the last argument to
- // the call node) being an implicit array.
- if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
- return node;
- }
- break;
- default:
- break;
- }
-
- // If the operator is nonassoc and we should not be able to parse the
- // upcoming infix operator, break.
- if (current_binding_powers.nonassoc) {
- // If this is an endless range, then we need to reject a couple of
- // additional operators because it violates the normal operator
- // precedence rules. Those patterns are:
- //
- // 1.. & 2
- // 1.. * 2
- //
- if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((pm_range_node_t *) node)->right == NULL) {
- if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
- PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_type_human(parser->current.type), pm_token_type_human(parser->previous.type));
- break;
- }
-
- if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->current.type].left) {
- break;
- }
- } else if (current_binding_powers.left <= pm_binding_powers[parser->current.type].left) {
- break;
- }
- }
-
- if (accepts_command_call) {
- // A command-style method call is only accepted on method chains.
- // Thus, we check whether the parsed node can continue method chains.
- // The method chain can continue if the parsed node is one of the following five kinds:
- // (1) index access: foo[1]
- // (2) attribute access: foo.bar
- // (3) method call with parenthesis: foo.bar(1)
- // (4) method call with a block: foo.bar do end
- // (5) constant path: foo::Bar
- switch (node->type) {
- case PM_CALL_NODE: {
- pm_call_node_t *cast = (pm_call_node_t *)node;
- if (
- // (1) foo[1]
- !(
- cast->call_operator_loc.start == NULL &&
- cast->message_loc.start != NULL &&
- cast->message_loc.start[0] == '[' &&
- cast->message_loc.end[-1] == ']'
- ) &&
- // (2) foo.bar
- !(
- cast->call_operator_loc.start != NULL &&
- cast->arguments == NULL &&
- cast->block == NULL &&
- cast->opening_loc.start == NULL
- ) &&
- // (3) foo.bar(1)
- !(
- cast->call_operator_loc.start != NULL &&
- cast->opening_loc.start != NULL
- ) &&
- // (4) foo.bar do end
- !(
- cast->block != NULL && PM_NODE_TYPE_P(cast->block, PM_BLOCK_NODE)
- )
- ) {
- accepts_command_call = false;
- }
- break;
- }
- // (5) foo::Bar
- case PM_CONSTANT_PATH_NODE:
- break;
- default:
- accepts_command_call = false;
- break;
- }
- }
- }
-
- return node;
-}
-
-/**
- * ruby -p, ruby -n, ruby -a, and ruby -l options will mutate the AST. We
- * perform that mutation here.
- */
-static pm_statements_node_t *
-wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) {
- if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
- pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
- pm_arguments_node_arguments_append(
- arguments,
- (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$_", 2))
- );
-
- pm_statements_node_body_append(parser, statements, (pm_node_t *) pm_call_node_fcall_synthesized_create(
- parser,
- arguments,
- pm_parser_constant_id_constant(parser, "print", 5)
- ), true);
- }
-
- if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
- if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
- pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
- pm_arguments_node_arguments_append(
- arguments,
- (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$;", 2))
- );
-
- pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$_", 2));
- pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (pm_node_t *) receiver, "split", arguments);
-
- pm_global_variable_write_node_t *write = pm_global_variable_write_node_synthesized_create(
- parser,
- pm_parser_constant_id_constant(parser, "$F", 2),
- (pm_node_t *) call
- );
-
- pm_statements_node_body_prepend(statements, (pm_node_t *) write);
- }
-
- pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
- pm_arguments_node_arguments_append(
- arguments,
- (pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$/", 2))
- );
-
- if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
- pm_keyword_hash_node_t *keywords = pm_keyword_hash_node_create(parser);
- pm_keyword_hash_node_elements_append(keywords, (pm_node_t *) pm_assoc_node_create(
- parser,
- (pm_node_t *) pm_symbol_node_synthesized_create(parser, "chomp"),
- &(pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->start, .end = parser->start },
- (pm_node_t *) pm_true_node_synthesized_create(parser)
- ));
-
- pm_arguments_node_arguments_append(arguments, (pm_node_t *) keywords);
- }
-
- pm_statements_node_t *wrapped_statements = pm_statements_node_create(parser);
- pm_statements_node_body_append(parser, wrapped_statements, (pm_node_t *) pm_while_node_synthesized_create(
- parser,
- (pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser, "gets", 4)),
- statements
- ), true);
-
- statements = wrapped_statements;
- }
-
- return statements;
-}
-
-/**
- * Parse the top-level program node.
- */
-static pm_node_t *
-parse_program(pm_parser_t *parser) {
- // If the current scope is NULL, then we want to push a new top level scope.
- // The current scope could exist in the event that we are parsing an eval
- // and the user has passed into scopes that already exist.
- if (parser->current_scope == NULL) {
- pm_parser_scope_push(parser, true);
- }
-
- pm_node_list_t current_block_exits = { 0 };
- pm_node_list_t *previous_block_exits = push_block_exits(parser, &current_block_exits);
-
- parser_lex(parser);
- pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_MAIN, 0);
-
- if (statements == NULL) {
- statements = pm_statements_node_create(parser);
- } else if (!parser->parsing_eval) {
- // If we have statements, then the top-level statement should be
- // explicitly checked as well. We have to do this here because
- // everywhere else we check all but the last statement.
- assert(statements->body.size > 0);
- pm_void_statement_check(parser, statements->body.nodes[statements->body.size - 1]);
- }
-
- pm_constant_id_list_t locals;
- pm_locals_order(parser, &parser->current_scope->locals, &locals, true);
- pm_parser_scope_pop(parser);
-
- // If this is an empty file, then we're still going to parse all of the
- // statements in order to gather up all of the comments and such. Here we'll
- // correct the location information.
- if (pm_statements_node_body_length(statements) == 0) {
- pm_statements_node_location_set(statements, parser->start, parser->start);
- }
-
- // At the top level, see if we need to wrap the statements in a program
- // node with a while loop based on the options.
- if (parser->command_line & (PM_OPTIONS_COMMAND_LINE_P | PM_OPTIONS_COMMAND_LINE_N)) {
- statements = wrap_statements(parser, statements);
- } else {
- flush_block_exits(parser, previous_block_exits);
- pm_node_list_free(&current_block_exits);
- }
-
- return (pm_node_t *) pm_program_node_create(parser, &locals, statements);
-}
-
-/******************************************************************************/
-/* External functions */
-/******************************************************************************/
-
-/**
- * A vendored version of strnstr that is used to find a substring within a
- * string with a given length. This function is used to search for the Ruby
- * engine name within a shebang when the -x option is passed to Ruby.
- *
- * The only modification that we made here is that we don't do NULL byte checks
- * because we know the little parameter will not have a NULL byte and we allow
- * the big parameter to have them.
- */
-static const char *
-pm_strnstr(const char *big, const char *little, size_t big_length) {
- size_t little_length = strlen(little);
-
- for (const char *big_end = big + big_length; big < big_end; big++) {
- if (*big == *little && memcmp(big, little, little_length) == 0) return big;
- }
-
- return NULL;
-}
-
-#ifdef _WIN32
-#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
-#else
-/**
- * Potentially warn the user if the shebang that has been found to include
- * "ruby" has a carriage return at the end, as that can cause problems on some
- * platforms.
- */
-static void
-pm_parser_warn_shebang_carriage_return(pm_parser_t *parser, const uint8_t *start, size_t length) {
- if (length > 2 && start[length - 2] == '\r' && start[length - 1] == '\n') {
- pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
- }
-}
-#endif
-
-/**
- * Process the shebang when initializing the parser. This function assumes that
- * the shebang_callback option has already been checked for nullability.
- */
-static void
-pm_parser_init_shebang(pm_parser_t *parser, const pm_options_t *options, const char *engine, size_t length) {
- const char *switches = pm_strnstr(engine, " -", length);
- if (switches == NULL) return;
-
- pm_options_t next_options = *options;
- options->shebang_callback(
- &next_options,
- (const uint8_t *) (switches + 1),
- length - ((size_t) (switches - engine)) - 1,
- options->shebang_callback_data
- );
-
- size_t encoding_length;
- if ((encoding_length = pm_string_length(&next_options.encoding)) > 0) {
- const uint8_t *encoding_source = pm_string_source(&next_options.encoding);
- parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
- }
-
- parser->command_line = next_options.command_line;
- parser->frozen_string_literal = next_options.frozen_string_literal;
-}
-
-/**
- * Initialize a parser with the given start and end pointers.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options) {
- assert(source != NULL);
-
- *parser = (pm_parser_t) {
- .node_id = 0,
- .lex_state = PM_LEX_STATE_BEG,
- .enclosure_nesting = 0,
- .lambda_enclosure_nesting = -1,
- .brace_nesting = 0,
- .do_loop_stack = 0,
- .accepts_block_stack = 0,
- .lex_modes = {
- .index = 0,
- .stack = {{ .mode = PM_LEX_DEFAULT }},
- .current = &parser->lex_modes.stack[0],
- },
- .start = source,
- .end = source + size,
- .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
- .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
- .next_start = NULL,
- .heredoc_end = NULL,
- .data_loc = { .start = NULL, .end = NULL },
- .comment_list = { 0 },
- .magic_comment_list = { 0 },
- .warning_list = { 0 },
- .error_list = { 0 },
- .current_scope = NULL,
- .current_context = NULL,
- .encoding = PM_ENCODING_UTF_8_ENTRY,
- .encoding_changed_callback = NULL,
- .encoding_comment_start = source,
- .lex_callback = NULL,
- .filepath = { 0 },
- .constant_pool = { 0 },
- .newline_list = { 0 },
- .integer_base = 0,
- .current_string = PM_STRING_EMPTY,
- .start_line = 1,
- .explicit_encoding = NULL,
- .command_line = 0,
- .parsing_eval = false,
- .partial_script = false,
- .command_start = true,
- .recovering = false,
- .encoding_locked = false,
- .encoding_changed = false,
- .pattern_matching_newlines = false,
- .in_keyword_arg = false,
- .current_block_exits = NULL,
- .semantic_token_seen = false,
- .frozen_string_literal = PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET,
- .current_regular_expression_ascii_only = false,
- .warn_mismatched_indentation = true
- };
-
- // Initialize the constant pool. We're going to completely guess as to the
- // number of constants that we'll need based on the size of the input. The
- // ratio we chose here is actually less arbitrary than you might think.
- //
- // We took ~50K Ruby files and measured the size of the file versus the
- // number of constants that were found in those files. Then we found the
- // average and standard deviation of the ratios of constants/bytesize. Then
- // we added 1.34 standard deviations to the average to get a ratio that
- // would fit 75% of the files (for a two-tailed distribution). This works
- // because there was about a 0.77 correlation and the distribution was
- // roughly normal.
- //
- // This ratio will need to change if we add more constants to the constant
- // pool for another node type.
- uint32_t constant_size = ((uint32_t) size) / 95;
- pm_constant_pool_init(&parser->constant_pool, constant_size < 4 ? 4 : constant_size);
-
- // Initialize the newline list. Similar to the constant pool, we're going to
- // guess at the number of newlines that we'll need based on the size of the
- // input.
- size_t newline_size = size / 22;
- pm_newline_list_init(&parser->newline_list, source, newline_size < 4 ? 4 : newline_size);
-
- // If options were provided to this parse, establish them here.
- if (options != NULL) {
- // filepath option
- parser->filepath = options->filepath;
-
- // line option
- parser->start_line = options->line;
-
- // encoding option
- size_t encoding_length = pm_string_length(&options->encoding);
- if (encoding_length > 0) {
- const uint8_t *encoding_source = pm_string_source(&options->encoding);
- parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
- }
-
- // encoding_locked option
- parser->encoding_locked = options->encoding_locked;
-
- // frozen_string_literal option
- parser->frozen_string_literal = options->frozen_string_literal;
-
- // command_line option
- parser->command_line = options->command_line;
-
- // version option
- parser->version = options->version;
-
- // partial_script
- parser->partial_script = options->partial_script;
-
- // scopes option
- parser->parsing_eval = options->scopes_count > 0;
- if (parser->parsing_eval) parser->warn_mismatched_indentation = false;
-
- for (size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
- const pm_options_scope_t *scope = pm_options_scope_get(options, scope_index);
- pm_parser_scope_push(parser, scope_index == 0);
-
- // Scopes given from the outside are not allowed to have numbered
- // parameters.
- parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED;
-
- for (size_t local_index = 0; local_index < scope->locals_count; local_index++) {
- const pm_string_t *local = pm_options_scope_local_get(scope, local_index);
-
- const uint8_t *source = pm_string_source(local);
- size_t length = pm_string_length(local);
-
- void *allocated = xmalloc(length);
- if (allocated == NULL) continue;
-
- memcpy(allocated, source, length);
- pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
- }
- }
- }
-
- pm_accepts_block_stack_push(parser, true);
-
- // Skip past the UTF-8 BOM if it exists.
- if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
- parser->current.end += 3;
- parser->encoding_comment_start += 3;
-
- if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
- parser->encoding = PM_ENCODING_UTF_8_ENTRY;
- if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
- }
- }
-
- // If the -x command line flag is set, or the first shebang of the file does
- // not include "ruby", then we'll search for a shebang that does include
- // "ruby" and start parsing from there.
- bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
-
- // If the first two bytes of the source are a shebang, then we will do a bit
- // of extra processing.
- //
- // First, we'll indicate that the encoding comment is at the end of the
- // shebang. This means that when a shebang is present the encoding comment
- // can begin on the second line.
- //
- // Second, we will check if the shebang includes "ruby". If it does, then we
- // we will start parsing from there. We will also potentially warning the
- // user if there is a carriage return at the end of the shebang. We will
- // also potentially call the shebang callback if this is the main script to
- // allow the caller to parse the shebang and find any command-line options.
- // If the shebang does not include "ruby" and this is the main script being
- // parsed, then we will start searching the file for a shebang that does
- // contain "ruby" as if -x were passed on the command line.
- const uint8_t *newline = next_newline(parser->start, parser->end - parser->start);
- size_t length = (size_t) ((newline != NULL ? newline : parser->end) - parser->start);
-
- if (length > 2 && parser->current.end[0] == '#' && parser->current.end[1] == '!') {
- const char *engine;
-
- if ((engine = pm_strnstr((const char *) parser->start, "ruby", length)) != NULL) {
- if (newline != NULL) {
- parser->encoding_comment_start = newline + 1;
-
- if (options == NULL || options->main_script) {
- pm_parser_warn_shebang_carriage_return(parser, parser->start, length + 1);
- }
- }
-
- if (options != NULL && options->main_script && options->shebang_callback != NULL) {
- pm_parser_init_shebang(parser, options, engine, length - ((size_t) (engine - (const char *) parser->start)));
- }
-
- search_shebang = false;
- } else if (options->main_script && !parser->parsing_eval) {
- search_shebang = true;
- }
- }
-
- // Here we're going to find the first shebang that includes "ruby" and start
- // parsing from there.
- if (search_shebang) {
- // If a shebang that includes "ruby" is not found, then we're going to a
- // a load error to the list of errors on the parser.
- bool found_shebang = false;
-
- // This is going to point to the start of each line as we check it.
- // We'll maintain a moving window looking at each line at they come.
- const uint8_t *cursor = parser->start;
-
- // The newline pointer points to the end of the current line that we're
- // considering. If it is NULL, then we're at the end of the file.
- const uint8_t *newline = next_newline(cursor, parser->end - cursor);
-
- while (newline != NULL) {
- pm_newline_list_append(&parser->newline_list, newline);
-
- cursor = newline + 1;
- newline = next_newline(cursor, parser->end - cursor);
-
- size_t length = (size_t) ((newline != NULL ? newline : parser->end) - cursor);
- if (length > 2 && cursor[0] == '#' && cursor[1] == '!') {
- const char *engine;
- if ((engine = pm_strnstr((const char *) cursor, "ruby", length)) != NULL) {
- found_shebang = true;
-
- if (newline != NULL) {
- pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
- parser->encoding_comment_start = newline + 1;
- }
-
- if (options != NULL && options->shebang_callback != NULL) {
- pm_parser_init_shebang(parser, options, engine, length - ((size_t) (engine - (const char *) cursor)));
- }
-
- break;
- }
- }
- }
-
- if (found_shebang) {
- parser->previous = (pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
- parser->current = (pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
- } else {
- pm_parser_err(parser, parser->start, parser->start, PM_ERR_SCRIPT_NOT_FOUND);
- pm_newline_list_clear(&parser->newline_list);
- }
- }
-
- // The encoding comment can start after any amount of inline whitespace, so
- // here we'll advance it to the first non-inline-whitespace character so
- // that it is ready for future comparisons.
- parser->encoding_comment_start += pm_strspn_inline_whitespace(parser->encoding_comment_start, parser->end - parser->encoding_comment_start);
-}
-
-/**
- * Register a callback that will be called whenever prism changes the encoding
- * it is using to parse based on the magic comment.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_parser_register_encoding_changed_callback(pm_parser_t *parser, pm_encoding_changed_callback_t callback) {
- parser->encoding_changed_callback = callback;
-}
-
-/**
- * Free all of the memory associated with the comment list.
- */
-static inline void
-pm_comment_list_free(pm_list_t *list) {
- pm_list_node_t *node, *next;
-
- for (node = list->head; node != NULL; node = next) {
- next = node->next;
-
- pm_comment_t *comment = (pm_comment_t *) node;
- xfree(comment);
- }
-}
-
-/**
- * Free all of the memory associated with the magic comment list.
- */
-static inline void
-pm_magic_comment_list_free(pm_list_t *list) {
- pm_list_node_t *node, *next;
-
- for (node = list->head; node != NULL; node = next) {
- next = node->next;
-
- pm_magic_comment_t *magic_comment = (pm_magic_comment_t *) node;
- xfree(magic_comment);
- }
-}
-
-/**
- * Free any memory associated with the given parser.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_parser_free(pm_parser_t *parser) {
- pm_string_free(&parser->filepath);
- pm_diagnostic_list_free(&parser->error_list);
- pm_diagnostic_list_free(&parser->warning_list);
- pm_comment_list_free(&parser->comment_list);
- pm_magic_comment_list_free(&parser->magic_comment_list);
- pm_constant_pool_free(&parser->constant_pool);
- pm_newline_list_free(&parser->newline_list);
-
- while (parser->current_scope != NULL) {
- // Normally, popping the scope doesn't free the locals since it is
- // assumed that ownership has transferred to the AST. However if we have
- // scopes while we're freeing the parser, it's likely they came from
- // eval scopes and we need to free them explicitly here.
- pm_parser_scope_pop(parser);
- }
-
- while (parser->lex_modes.index >= PM_LEX_STACK_SIZE) {
- lex_mode_pop(parser);
- }
-}
-
-/**
- * Parse the Ruby source associated with the given parser and return the tree.
- */
-PRISM_EXPORTED_FUNCTION pm_node_t *
-pm_parse(pm_parser_t *parser) {
- return parse_program(parser);
-}
-
-/**
- * Read into the stream until the gets callback returns false. If the last read
- * line from the stream matches an __END__ marker, then halt and return false,
- * otherwise return true.
- */
-static bool
-pm_parse_stream_read(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *fgets) {
-#define LINE_SIZE 4096
- char line[LINE_SIZE];
-
- while (memset(line, '\n', LINE_SIZE), fgets(line, LINE_SIZE, stream) != NULL) {
- size_t length = LINE_SIZE;
- while (length > 0 && line[length - 1] == '\n') length--;
-
- if (length == LINE_SIZE) {
- // If we read a line that is the maximum size and it doesn't end
- // with a newline, then we'll just append it to the buffer and
- // continue reading.
- length--;
- pm_buffer_append_string(buffer, line, length);
- continue;
- }
-
- // Append the line to the buffer.
- length--;
- pm_buffer_append_string(buffer, line, length);
-
- // Check if the line matches the __END__ marker. If it does, then stop
- // reading and return false. In most circumstances, this means we should
- // stop reading from the stream so that the DATA constant can pick it
- // up.
- switch (length) {
- case 7:
- if (strncmp(line, "__END__", 7) == 0) return false;
- break;
- case 8:
- if (strncmp(line, "__END__\n", 8) == 0) return false;
- break;
- case 9:
- if (strncmp(line, "__END__\r\n", 9) == 0) return false;
- break;
- }
- }
-
- return true;
-#undef LINE_SIZE
-}
-
-/**
- * Determine if there was an unterminated heredoc at the end of the input, which
- * would mean the stream isn't finished and we should keep reading.
- *
- * For the other lex modes we can check if the lex mode has been closed, but for
- * heredocs when we hit EOF we close the lex mode and then go back to parse the
- * rest of the line after the heredoc declaration so that we get more of the
- * syntax tree.
- */
-static bool
-pm_parse_stream_unterminated_heredoc_p(pm_parser_t *parser) {
- pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) parser->error_list.head;
-
- for (; diagnostic != NULL; diagnostic = (pm_diagnostic_t *) diagnostic->node.next) {
- if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * Parse a stream of Ruby source and return the tree.
- *
- * Prism is designed around having the entire source in memory at once, but you
- * can stream stdin in to Ruby so we need to support a streaming API.
- */
-PRISM_EXPORTED_FUNCTION pm_node_t *
-pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *fgets, const pm_options_t *options) {
- pm_buffer_init(buffer);
-
- bool eof = pm_parse_stream_read(buffer, stream, fgets);
- pm_parser_init(parser, (const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
- pm_node_t *node = pm_parse(parser);
-
- while (!eof && parser->error_list.size > 0 && (parser->lex_modes.index > 0 || pm_parse_stream_unterminated_heredoc_p(parser))) {
- pm_node_destroy(parser, node);
- eof = pm_parse_stream_read(buffer, stream, fgets);
-
- pm_parser_free(parser);
- pm_parser_init(parser, (const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
- node = pm_parse(parser);
- }
-
- return node;
-}
-
-/**
- * Parse the source and return true if it parses without errors or warnings.
- */
-PRISM_EXPORTED_FUNCTION bool
-pm_parse_success_p(const uint8_t *source, size_t size, const char *data) {
- pm_options_t options = { 0 };
- pm_options_read(&options, data);
-
- pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
-
- pm_node_t *node = pm_parse(&parser);
- pm_node_destroy(&parser, node);
-
- bool result = parser.error_list.size == 0;
- pm_parser_free(&parser);
- pm_options_free(&options);
-
- return result;
-}
-
-#undef PM_CASE_KEYWORD
-#undef PM_CASE_OPERATOR
-#undef PM_CASE_WRITABLE
-#undef PM_STRING_EMPTY
-#undef PM_LOCATION_NODE_BASE_VALUE
-#undef PM_LOCATION_NODE_VALUE
-#undef PM_LOCATION_NULL_VALUE
-#undef PM_LOCATION_TOKEN_VALUE
-
-// We optionally support serializing to a binary string. For systems that don't
-// want or need this functionality, it can be turned off with the
-// PRISM_EXCLUDE_SERIALIZATION define.
-#ifndef PRISM_EXCLUDE_SERIALIZATION
-
-static inline void
-pm_serialize_header(pm_buffer_t *buffer) {
- pm_buffer_append_string(buffer, "PRISM", 5);
- pm_buffer_append_byte(buffer, PRISM_VERSION_MAJOR);
- pm_buffer_append_byte(buffer, PRISM_VERSION_MINOR);
- pm_buffer_append_byte(buffer, PRISM_VERSION_PATCH);
- pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
-}
-
-/**
- * Serialize the AST represented by the given node to the given buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_serialize(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
- pm_serialize_header(buffer);
- pm_serialize_content(parser, node, buffer);
- pm_buffer_append_byte(buffer, '\0');
-}
-
-/**
- * Parse and serialize the AST represented by the given source to the given
- * buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
- pm_options_t options = { 0 };
- pm_options_read(&options, data);
-
- pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
-
- pm_node_t *node = pm_parse(&parser);
-
- pm_serialize_header(buffer);
- pm_serialize_content(&parser, node, buffer);
- pm_buffer_append_byte(buffer, '\0');
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- pm_options_free(&options);
-}
-
-/**
- * Parse and serialize the AST represented by the source that is read out of the
- * given stream into to the given buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_serialize_parse_stream(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *fgets, const char *data) {
- pm_parser_t parser;
- pm_options_t options = { 0 };
- pm_options_read(&options, data);
-
- pm_buffer_t parser_buffer;
- pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, fgets, &options);
- pm_serialize_header(buffer);
- pm_serialize_content(&parser, node, buffer);
- pm_buffer_append_byte(buffer, '\0');
-
- pm_node_destroy(&parser, node);
- pm_buffer_free(&parser_buffer);
- pm_parser_free(&parser);
- pm_options_free(&options);
-}
-
-/**
- * Parse and serialize the comments in the given source to the given buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
- pm_options_t options = { 0 };
- pm_options_read(&options, data);
-
- pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
-
- pm_node_t *node = pm_parse(&parser);
- pm_serialize_header(buffer);
- pm_serialize_encoding(parser.encoding, buffer);
- pm_buffer_append_varsint(buffer, parser.start_line);
- pm_serialize_comment_list(&parser, &parser.comment_list, buffer);
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- pm_options_free(&options);
-}
-
-#endif
diff --git a/prism/prism.h b/prism/prism.h
deleted file mode 100644
index 755c38fca2..0000000000
--- a/prism/prism.h
+++ /dev/null
@@ -1,336 +0,0 @@
-/**
- * @file prism.h
- *
- * The main header file for the prism parser.
- */
-#ifndef PRISM_H
-#define PRISM_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_buffer.h"
-#include "prism/util/pm_char.h"
-#include "prism/util/pm_integer.h"
-#include "prism/util/pm_memchr.h"
-#include "prism/util/pm_strncasecmp.h"
-#include "prism/util/pm_strpbrk.h"
-#include "prism/ast.h"
-#include "prism/diagnostic.h"
-#include "prism/node.h"
-#include "prism/options.h"
-#include "prism/pack.h"
-#include "prism/parser.h"
-#include "prism/prettyprint.h"
-#include "prism/regexp.h"
-#include "prism/static_literals.h"
-#include "prism/version.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <locale.h>
-#include <math.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef _WIN32
-#include <strings.h>
-#endif
-
-/**
- * The prism version and the serialization format.
- *
- * @returns The prism version as a constant string.
- */
-PRISM_EXPORTED_FUNCTION const char * pm_version(void);
-
-/**
- * Initialize a parser with the given start and end pointers.
- *
- * @param parser The parser to initialize.
- * @param source The source to parse.
- * @param size The size of the source.
- * @param options The optional options to use when parsing.
- */
-PRISM_EXPORTED_FUNCTION void pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options);
-
-/**
- * Register a callback that will be called whenever prism changes the encoding
- * it is using to parse based on the magic comment.
- *
- * @param parser The parser to register the callback with.
- * @param callback The callback to register.
- */
-PRISM_EXPORTED_FUNCTION void pm_parser_register_encoding_changed_callback(pm_parser_t *parser, pm_encoding_changed_callback_t callback);
-
-/**
- * Free any memory associated with the given parser.
- *
- * @param parser The parser to free.
- */
-PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser);
-
-/**
- * Initiate the parser with the given parser.
- *
- * @param parser The parser to use.
- * @return The AST representing the source.
- */
-PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser);
-
-/**
- * This function is used in pm_parse_stream to retrieve a line of input from a
- * stream. It closely mirrors that of fgets so that fgets can be used as the
- * default implementation.
- */
-typedef char * (pm_parse_stream_fgets_t)(char *string, int size, void *stream);
-
-/**
- * Parse a stream of Ruby source and return the tree.
- *
- * @param parser The parser to use.
- * @param buffer The buffer to use.
- * @param stream The stream to parse.
- * @param fgets The function to use to read from the stream.
- * @param options The optional options to use when parsing.
- * @return The AST representing the source.
- */
-PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *fgets, const pm_options_t *options);
-
-// We optionally support serializing to a binary string. For systems that don't
-// want or need this functionality, it can be turned off with the
-// PRISM_EXCLUDE_SERIALIZATION define.
-#ifndef PRISM_EXCLUDE_SERIALIZATION
-
-/**
- * Parse and serialize the AST represented by the source that is read out of the
- * given stream into to the given buffer.
- *
- * @param buffer The buffer to serialize to.
- * @param stream The stream to parse.
- * @param fgets The function to use to read from the stream.
- * @param data The optional data to pass to the parser.
- */
-PRISM_EXPORTED_FUNCTION void pm_serialize_parse_stream(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *fgets, const char *data);
-
-/**
- * Serialize the given list of comments to the given buffer.
- *
- * @param parser The parser to serialize.
- * @param list The list of comments to serialize.
- * @param buffer The buffer to serialize to.
- */
-void pm_serialize_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer);
-
-/**
- * Serialize the name of the encoding to the buffer.
- *
- * @param encoding The encoding to serialize.
- * @param buffer The buffer to serialize to.
- */
-void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer);
-
-/**
- * Serialize the encoding, metadata, nodes, and constant pool.
- *
- * @param parser The parser to serialize.
- * @param node The node to serialize.
- * @param buffer The buffer to serialize to.
- */
-void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer);
-
-/**
- * Serialize the AST represented by the given node to the given buffer.
- *
- * @param parser The parser to serialize.
- * @param node The node to serialize.
- * @param buffer The buffer to serialize to.
- */
-PRISM_EXPORTED_FUNCTION void pm_serialize(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer);
-
-/**
- * Parse the given source to the AST and dump the AST to the given buffer.
- *
- * @param buffer The buffer to serialize to.
- * @param source The source to parse.
- * @param size The size of the source.
- * @param data The optional data to pass to the parser.
- */
-PRISM_EXPORTED_FUNCTION void pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data);
-
-/**
- * Parse and serialize the comments in the given source to the given buffer.
- *
- * @param buffer The buffer to serialize to.
- * @param source The source to parse.
- * @param size The size of the source.
- * @param data The optional data to pass to the parser.
- */
-PRISM_EXPORTED_FUNCTION void pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data);
-
-/**
- * Lex the given source and serialize to the given buffer.
- *
- * @param source The source to lex.
- * @param size The size of the source.
- * @param buffer The buffer to serialize to.
- * @param data The optional data to pass to the lexer.
- */
-PRISM_EXPORTED_FUNCTION void pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data);
-
-/**
- * Parse and serialize both the AST and the tokens represented by the given
- * source to the given buffer.
- *
- * @param buffer The buffer to serialize to.
- * @param source The source to parse.
- * @param size The size of the source.
- * @param data The optional data to pass to the parser.
- */
-PRISM_EXPORTED_FUNCTION void pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data);
-
-#endif
-
-/**
- * Parse the source and return true if it parses without errors or warnings.
- *
- * @param source The source to parse.
- * @param size The size of the source.
- * @param data The optional data to pass to the parser.
- * @return True if the source parses without errors or warnings.
- */
-PRISM_EXPORTED_FUNCTION bool pm_parse_success_p(const uint8_t *source, size_t size, const char *data);
-
-/**
- * Returns a string representation of the given token type.
- *
- * @param token_type The token type to convert to a string.
- * @return A string representation of the given token type.
- */
-PRISM_EXPORTED_FUNCTION const char * pm_token_type_name(pm_token_type_t token_type);
-
-/**
- * Returns the human name of the given token type.
- *
- * @param token_type The token type to convert to a human name.
- * @return The human name of the given token type.
- */
-const char * pm_token_type_human(pm_token_type_t token_type);
-
-// We optionally support dumping to JSON. For systems that don't want or need
-// this functionality, it can be turned off with the PRISM_EXCLUDE_JSON define.
-#ifndef PRISM_EXCLUDE_JSON
-
-/**
- * Dump JSON to the given buffer.
- *
- * @param buffer The buffer to serialize to.
- * @param parser The parser that parsed the node.
- * @param node The node to serialize.
- */
-PRISM_EXPORTED_FUNCTION void pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node);
-
-#endif
-
-/**
- * @mainpage
- *
- * Prism is a parser for the Ruby programming language. It is designed to be
- * portable, error tolerant, and maintainable. It is written in C99 and has no
- * dependencies. It is currently being integrated into
- * [CRuby](https://github.com/ruby/ruby),
- * [JRuby](https://github.com/jruby/jruby),
- * [TruffleRuby](https://github.com/oracle/truffleruby),
- * [Sorbet](https://github.com/sorbet/sorbet), and
- * [Syntax Tree](https://github.com/ruby-syntax-tree/syntax_tree).
- *
- * @section getting-started Getting started
- *
- * If you're vendoring this project and compiling it statically then as long as
- * you have a C99 compiler you will be fine. If you're linking against it as
- * shared library, then you should compile with `-fvisibility=hidden` and
- * `-DPRISM_EXPORT_SYMBOLS` to tell prism to make only its public interface
- * visible.
- *
- * @section parsing Parsing
- *
- * In order to parse Ruby code, the structures and functions that you're going
- * to want to use and be aware of are:
- *
- * * `pm_parser_t` - the main parser structure
- * * `pm_parser_init` - initialize a parser
- * * `pm_parse` - parse and return the root node
- * * `pm_node_destroy` - deallocate the root node returned by `pm_parse`
- * * `pm_parser_free` - free the internal memory of the parser
- *
- * Putting all of this together would look something like:
- *
- * ```c
- * void parse(const uint8_t *source, size_t length) {
- * pm_parser_t parser;
- * pm_parser_init(&parser, source, length, NULL);
- *
- * pm_node_t *root = pm_parse(&parser);
- * printf("PARSED!\n");
- *
- * pm_node_destroy(&parser, root);
- * pm_parser_free(&parser);
- * }
- * ```
- *
- * All of the nodes "inherit" from `pm_node_t` by embedding those structures as
- * their first member. This means you can downcast and upcast any node in the
- * tree to a `pm_node_t`.
- *
- * @section serializing Serializing
- *
- * Prism provides the ability to serialize the AST and its related metadata into
- * a binary format. This format is designed to be portable to different
- * languages and runtimes so that you only need to make one FFI call in order to
- * parse Ruby code. The structures and functions that you're going to want to
- * use and be aware of are:
- *
- * * `pm_buffer_t` - a small buffer object that will hold the serialized AST
- * * `pm_buffer_free` - free the memory associated with the buffer
- * * `pm_serialize` - serialize the AST into a buffer
- * * `pm_serialize_parse` - parse and serialize the AST into a buffer
- *
- * Putting all of this together would look something like:
- *
- * ```c
- * void serialize(const uint8_t *source, size_t length) {
- * pm_buffer_t buffer = { 0 };
- *
- * pm_serialize_parse(&buffer, source, length, NULL);
- * printf("SERIALIZED!\n");
- *
- * pm_buffer_free(&buffer);
- * }
- * ```
- *
- * @section inspecting Inspecting
- *
- * Prism provides the ability to inspect the AST by pretty-printing nodes. You
- * can do this with the `pm_prettyprint` function, which you would use like:
- *
- * ```c
- * void prettyprint(const uint8_t *source, size_t length) {
- * pm_parser_t parser;
- * pm_parser_init(&parser, source, length, NULL);
- *
- * pm_node_t *root = pm_parse(&parser);
- * pm_buffer_t buffer = { 0 };
- *
- * pm_prettyprint(&buffer, &parser, root);
- * printf("%*.s\n", (int) buffer.length, buffer.value);
- *
- * pm_buffer_free(&buffer);
- * pm_node_destroy(&parser, root);
- * pm_parser_free(&parser);
- * }
- * ```
- */
-
-#endif
diff --git a/prism/regexp.c b/prism/regexp.c
deleted file mode 100644
index e4bf74c142..0000000000
--- a/prism/regexp.c
+++ /dev/null
@@ -1,786 +0,0 @@
-#include "prism/regexp.h"
-
-#define PM_REGEXP_PARSE_DEPTH_MAX 4096
-
-/**
- * This is the parser that is going to handle parsing regular expressions.
- */
-typedef struct {
- /** The parser that is currently being used. */
- pm_parser_t *parser;
-
- /** A pointer to the start of the source that we are parsing. */
- const uint8_t *start;
-
- /** A pointer to the current position in the source. */
- const uint8_t *cursor;
-
- /** A pointer to the end of the source that we are parsing. */
- const uint8_t *end;
-
- /**
- * Whether or not the regular expression currently being parsed is in
- * extended mode, wherein whitespace is ignored and comments are allowed.
- */
- bool extended_mode;
-
- /** Whether the encoding has changed from the default. */
- bool encoding_changed;
-
- /** The encoding of the source. */
- const pm_encoding_t *encoding;
-
- /** The callback to call when a named capture group is found. */
- pm_regexp_name_callback_t name_callback;
-
- /** The data to pass to the name callback. */
- void *name_data;
-
- /** The callback to call when a parse error is found. */
- pm_regexp_error_callback_t error_callback;
-
- /** The data to pass to the error callback. */
- void *error_data;
-} pm_regexp_parser_t;
-
-/**
- * Append an error to the parser.
- */
-static inline void
-pm_regexp_parse_error(pm_regexp_parser_t *parser, const uint8_t *start, const uint8_t *end, const char *message) {
- parser->error_callback(start, end, message, parser->error_data);
-}
-
-/**
- * This appends a new string to the list of named captures. This function
- * assumes the caller has already checked the validity of the name callback.
- */
-static void
-pm_regexp_parser_named_capture(pm_regexp_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- pm_string_t string;
- pm_string_shared_init(&string, start, end);
- parser->name_callback(&string, parser->name_data);
- pm_string_free(&string);
-}
-
-/**
- * Returns true if the next character is the end of the source.
- */
-static inline bool
-pm_regexp_char_is_eof(pm_regexp_parser_t *parser) {
- return parser->cursor >= parser->end;
-}
-
-/**
- * Optionally accept a char and consume it if it exists.
- */
-static inline bool
-pm_regexp_char_accept(pm_regexp_parser_t *parser, uint8_t value) {
- if (!pm_regexp_char_is_eof(parser) && *parser->cursor == value) {
- parser->cursor++;
- return true;
- }
- return false;
-}
-
-/**
- * Expect a character to be present and consume it.
- */
-static inline bool
-pm_regexp_char_expect(pm_regexp_parser_t *parser, uint8_t value) {
- if (!pm_regexp_char_is_eof(parser) && *parser->cursor == value) {
- parser->cursor++;
- return true;
- }
- return false;
-}
-
-/**
- * This advances the current token to the next instance of the given character.
- */
-static bool
-pm_regexp_char_find(pm_regexp_parser_t *parser, uint8_t value) {
- if (pm_regexp_char_is_eof(parser)) {
- return false;
- }
-
- const uint8_t *end = (const uint8_t *) pm_memchr(parser->cursor, value, (size_t) (parser->end - parser->cursor), parser->encoding_changed, parser->encoding);
- if (end == NULL) {
- return false;
- }
-
- parser->cursor = end + 1;
- return true;
-}
-
-/**
- * Range quantifiers are a special class of quantifiers that look like
- *
- * * {digit}
- * * {digit,}
- * * {digit,digit}
- * * {,digit}
- *
- * Unfortunately, if there are any spaces in between, then this just becomes a
- * regular character match expression and we have to backtrack. So when this
- * function first starts running, we'll create a "save" point and then attempt
- * to parse the quantifier. If it fails, we'll restore the save point and
- * return.
- *
- * The properly track everything, we're going to build a little state machine.
- * It looks something like the following:
- *
- * +-------+ +---------+ ------------+
- * ---- lbrace ---> | start | ---- digit ---> | minimum | |
- * +-------+ +---------+ <--- digit -+
- * | | |
- * +-------+ | | rbrace
- * | comma | <----- comma +---- comma -------+ |
- * +-------+ V V
- * | +---------+ +---------+
- * +-- digit --> | maximum | -- rbrace --> || final ||
- * +---------+ +---------+
- * | ^
- * +- digit -+
- *
- * Note that by the time we've hit this function, the lbrace has already been
- * consumed so we're in the start state.
- */
-static bool
-pm_regexp_parse_range_quantifier(pm_regexp_parser_t *parser) {
- const uint8_t *savepoint = parser->cursor;
-
- enum {
- PM_REGEXP_RANGE_QUANTIFIER_STATE_START,
- PM_REGEXP_RANGE_QUANTIFIER_STATE_MINIMUM,
- PM_REGEXP_RANGE_QUANTIFIER_STATE_MAXIMUM,
- PM_REGEXP_RANGE_QUANTIFIER_STATE_COMMA
- } state = PM_REGEXP_RANGE_QUANTIFIER_STATE_START;
-
- while (1) {
- switch (state) {
- case PM_REGEXP_RANGE_QUANTIFIER_STATE_START:
- switch (*parser->cursor) {
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
- parser->cursor++;
- state = PM_REGEXP_RANGE_QUANTIFIER_STATE_MINIMUM;
- break;
- case ',':
- parser->cursor++;
- state = PM_REGEXP_RANGE_QUANTIFIER_STATE_COMMA;
- break;
- default:
- parser->cursor = savepoint;
- return true;
- }
- break;
- case PM_REGEXP_RANGE_QUANTIFIER_STATE_MINIMUM:
- switch (*parser->cursor) {
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
- parser->cursor++;
- break;
- case ',':
- parser->cursor++;
- state = PM_REGEXP_RANGE_QUANTIFIER_STATE_MAXIMUM;
- break;
- case '}':
- parser->cursor++;
- return true;
- default:
- parser->cursor = savepoint;
- return true;
- }
- break;
- case PM_REGEXP_RANGE_QUANTIFIER_STATE_COMMA:
- switch (*parser->cursor) {
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
- parser->cursor++;
- state = PM_REGEXP_RANGE_QUANTIFIER_STATE_MAXIMUM;
- break;
- default:
- parser->cursor = savepoint;
- return true;
- }
- break;
- case PM_REGEXP_RANGE_QUANTIFIER_STATE_MAXIMUM:
- switch (*parser->cursor) {
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
- parser->cursor++;
- break;
- case '}':
- parser->cursor++;
- return true;
- default:
- parser->cursor = savepoint;
- return true;
- }
- break;
- }
- }
-
- return true;
-}
-
-/**
- * quantifier : star-quantifier
- * | plus-quantifier
- * | optional-quantifier
- * | range-quantifier
- * | <empty>
- * ;
- */
-static bool
-pm_regexp_parse_quantifier(pm_regexp_parser_t *parser) {
- while (!pm_regexp_char_is_eof(parser)) {
- switch (*parser->cursor) {
- case '*':
- case '+':
- case '?':
- parser->cursor++;
- break;
- case '{':
- parser->cursor++;
- if (!pm_regexp_parse_range_quantifier(parser)) return false;
- break;
- default:
- // In this case there is no quantifier.
- return true;
- }
- }
-
- return true;
-}
-
-/**
- * match-posix-class : '[' '[' ':' '^'? CHAR+ ':' ']' ']'
- * ;
- */
-static bool
-pm_regexp_parse_posix_class(pm_regexp_parser_t *parser) {
- if (!pm_regexp_char_expect(parser, ':')) {
- return false;
- }
-
- pm_regexp_char_accept(parser, '^');
-
- return (
- pm_regexp_char_find(parser, ':') &&
- pm_regexp_char_expect(parser, ']') &&
- pm_regexp_char_expect(parser, ']')
- );
-}
-
-// Forward declaration because character sets can be nested.
-static bool
-pm_regexp_parse_lbracket(pm_regexp_parser_t *parser, uint16_t depth);
-
-/**
- * match-char-set : '[' '^'? (match-range | match-char)* ']'
- * ;
- */
-static bool
-pm_regexp_parse_character_set(pm_regexp_parser_t *parser, uint16_t depth) {
- pm_regexp_char_accept(parser, '^');
-
- while (!pm_regexp_char_is_eof(parser) && *parser->cursor != ']') {
- switch (*parser->cursor++) {
- case '[':
- pm_regexp_parse_lbracket(parser, (uint16_t) (depth + 1));
- break;
- case '\\':
- if (!pm_regexp_char_is_eof(parser)) {
- parser->cursor++;
- }
- break;
- default:
- // do nothing, we've already advanced the cursor
- break;
- }
- }
-
- return pm_regexp_char_expect(parser, ']');
-}
-
-/**
- * A left bracket can either mean a POSIX class or a character set.
- */
-static bool
-pm_regexp_parse_lbracket(pm_regexp_parser_t *parser, uint16_t depth) {
- if (depth >= PM_REGEXP_PARSE_DEPTH_MAX) {
- pm_regexp_parse_error(parser, parser->start, parser->end, "parse depth limit over");
- return false;
- }
-
- if ((parser->cursor < parser->end) && parser->cursor[0] == ']') {
- parser->cursor++;
- pm_regexp_parse_error(parser, parser->cursor - 1, parser->cursor, "empty char-class");
- return true;
- }
-
- const uint8_t *reset = parser->cursor;
-
- if ((parser->cursor + 2 < parser->end) && parser->cursor[0] == '[' && parser->cursor[1] == ':') {
- parser->cursor++;
- if (pm_regexp_parse_posix_class(parser)) return true;
-
- parser->cursor = reset;
- }
-
- return pm_regexp_parse_character_set(parser, depth);
-}
-
-// Forward declaration here since parsing groups needs to go back up the grammar
-// to parse expressions within them.
-static bool
-pm_regexp_parse_expression(pm_regexp_parser_t *parser, uint16_t depth);
-
-/**
- * These are the states of the options that are configurable on the regular
- * expression (or from within a group).
- */
-typedef enum {
- PM_REGEXP_OPTION_STATE_INVALID,
- PM_REGEXP_OPTION_STATE_TOGGLEABLE,
- PM_REGEXP_OPTION_STATE_ADDABLE,
- PM_REGEXP_OPTION_STATE_ADDED,
- PM_REGEXP_OPTION_STATE_REMOVED
-} pm_regexp_option_state_t;
-
-// These are the options that are configurable on the regular expression (or
-// from within a group).
-
-#define PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM 'a'
-#define PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM 'x'
-#define PRISM_REGEXP_OPTION_STATE_SLOTS (PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM + 1)
-
-/**
- * This is the set of options that are configurable on the regular expression.
- */
-typedef struct {
- /** The current state of each option. */
- uint8_t values[PRISM_REGEXP_OPTION_STATE_SLOTS];
-} pm_regexp_options_t;
-
-/**
- * Initialize a new set of options to their default values.
- */
-static void
-pm_regexp_options_init(pm_regexp_options_t *options) {
- memset(options, PM_REGEXP_OPTION_STATE_INVALID, sizeof(uint8_t) * PRISM_REGEXP_OPTION_STATE_SLOTS);
- options->values['i' - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM] = PM_REGEXP_OPTION_STATE_TOGGLEABLE;
- options->values['m' - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM] = PM_REGEXP_OPTION_STATE_TOGGLEABLE;
- options->values['x' - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM] = PM_REGEXP_OPTION_STATE_TOGGLEABLE;
- options->values['d' - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM] = PM_REGEXP_OPTION_STATE_ADDABLE;
- options->values['a' - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM] = PM_REGEXP_OPTION_STATE_ADDABLE;
- options->values['u' - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM] = PM_REGEXP_OPTION_STATE_ADDABLE;
-}
-
-/**
- * Attempt to add the given option to the set of options. Returns true if it was
- * added, false if it was already present.
- */
-static bool
-pm_regexp_options_add(pm_regexp_options_t *options, uint8_t key) {
- if (key >= PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM && key <= PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM) {
- key = (uint8_t) (key - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM);
-
- switch (options->values[key]) {
- case PM_REGEXP_OPTION_STATE_INVALID:
- case PM_REGEXP_OPTION_STATE_REMOVED:
- return false;
- case PM_REGEXP_OPTION_STATE_TOGGLEABLE:
- case PM_REGEXP_OPTION_STATE_ADDABLE:
- options->values[key] = PM_REGEXP_OPTION_STATE_ADDED;
- return true;
- case PM_REGEXP_OPTION_STATE_ADDED:
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * Attempt to remove the given option from the set of options. Returns true if
- * it was removed, false if it was already absent.
- */
-static bool
-pm_regexp_options_remove(pm_regexp_options_t *options, uint8_t key) {
- if (key >= PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM && key <= PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM) {
- key = (uint8_t) (key - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM);
-
- switch (options->values[key]) {
- case PM_REGEXP_OPTION_STATE_INVALID:
- case PM_REGEXP_OPTION_STATE_ADDABLE:
- return false;
- case PM_REGEXP_OPTION_STATE_TOGGLEABLE:
- case PM_REGEXP_OPTION_STATE_ADDED:
- case PM_REGEXP_OPTION_STATE_REMOVED:
- options->values[key] = PM_REGEXP_OPTION_STATE_REMOVED;
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * True if the given key is set in the options.
- */
-static uint8_t
-pm_regexp_options_state(pm_regexp_options_t *options, uint8_t key) {
- if (key >= PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM && key <= PRISM_REGEXP_OPTION_STATE_SLOT_MAXIMUM) {
- key = (uint8_t) (key - PRISM_REGEXP_OPTION_STATE_SLOT_MINIMUM);
- return options->values[key];
- }
-
- return false;
-}
-
-/**
- * Groups can have quite a few different patterns for syntax. They basically
- * just wrap a set of expressions, but they can potentially have options after a
- * question mark. If there _isn't_ a question mark, then it's just a set of
- * expressions. If there _is_, then here are the options:
- *
- * * (?#...) - inline comments
- * * (?:subexp) - non-capturing group
- * * (?=subexp) - positive lookahead
- * * (?!subexp) - negative lookahead
- * * (?>subexp) - atomic group
- * * (?~subexp) - absence operator
- * * (?<=subexp) - positive lookbehind
- * * (?<!subexp) - negative lookbehind
- * * (?<name>subexp) - named capturing group
- * * (?'name'subexp) - named capturing group
- * * (?(cond)yes-subexp) - conditional expression
- * * (?(cond)yes-subexp|no-subexp) - conditional expression
- * * (?imxdau-imx) - turn on and off configuration
- * * (?imxdau-imx:subexp) - turn on and off configuration for an expression
- */
-static bool
-pm_regexp_parse_group(pm_regexp_parser_t *parser, uint16_t depth) {
- const uint8_t *group_start = parser->cursor;
-
- pm_regexp_options_t options;
- pm_regexp_options_init(&options);
-
- // First, parse any options for the group.
- if (pm_regexp_char_accept(parser, '?')) {
- if (pm_regexp_char_is_eof(parser)) {
- pm_regexp_parse_error(parser, group_start, parser->cursor, "end pattern in group");
- return false;
- }
-
- switch (*parser->cursor) {
- case '#': { // inline comments
- parser->cursor++;
- if (pm_regexp_char_is_eof(parser)) {
- pm_regexp_parse_error(parser, group_start, parser->cursor, "end pattern in group");
- return false;
- }
-
- if (parser->encoding_changed && parser->encoding->multibyte) {
- bool escaped = false;
-
- // Here we're going to take a slow path and iterate through
- // each multibyte character to find the close paren. We do
- // this because \ can be a trailing byte in some encodings.
- while (parser->cursor < parser->end) {
- if (!escaped && *parser->cursor == ')') {
- parser->cursor++;
- return true;
- }
-
- size_t width = parser->encoding->char_width(parser->cursor, (ptrdiff_t) (parser->end - parser->cursor));
- if (width == 0) return false;
-
- escaped = (width == 1) && (*parser->cursor == '\\');
- parser->cursor += width;
- }
-
- return false;
- } else {
- // Here we can take the fast path and use memchr to find the
- // next ) because we are safe checking backward for \ since
- // it cannot be a trailing character.
- bool found = pm_regexp_char_find(parser, ')');
-
- while (found && (parser->start <= parser->cursor - 2) && (*(parser->cursor - 2) == '\\')) {
- found = pm_regexp_char_find(parser, ')');
- }
-
- return found;
- }
- }
- case ':': // non-capturing group
- case '=': // positive lookahead
- case '!': // negative lookahead
- case '>': // atomic group
- case '~': // absence operator
- parser->cursor++;
- break;
- case '<':
- parser->cursor++;
- if (pm_regexp_char_is_eof(parser)) {
- pm_regexp_parse_error(parser, group_start, parser->cursor, "end pattern with unmatched parenthesis");
- return false;
- }
-
- switch (*parser->cursor) {
- case '=': // positive lookbehind
- case '!': // negative lookbehind
- parser->cursor++;
- break;
- default: { // named capture group
- const uint8_t *start = parser->cursor;
- if (!pm_regexp_char_find(parser, '>')) {
- return false;
- }
-
- if (parser->cursor - start == 1) {
- pm_regexp_parse_error(parser, start, parser->cursor, "group name is empty");
- }
-
- if (parser->name_callback != NULL) {
- pm_regexp_parser_named_capture(parser, start, parser->cursor - 1);
- }
-
- break;
- }
- }
- break;
- case '\'': { // named capture group
- const uint8_t *start = ++parser->cursor;
- if (!pm_regexp_char_find(parser, '\'')) {
- return false;
- }
-
- if (parser->name_callback != NULL) {
- pm_regexp_parser_named_capture(parser, start, parser->cursor - 1);
- }
-
- break;
- }
- case '(': // conditional expression
- if (!pm_regexp_char_find(parser, ')')) {
- return false;
- }
- break;
- case 'i': case 'm': case 'x': case 'd': case 'a': case 'u': // options
- while (!pm_regexp_char_is_eof(parser) && *parser->cursor != '-' && *parser->cursor != ':' && *parser->cursor != ')') {
- if (!pm_regexp_options_add(&options, *parser->cursor)) {
- return false;
- }
- parser->cursor++;
- }
-
- if (pm_regexp_char_is_eof(parser)) {
- return false;
- }
-
- // If we are at the end of the group of options and there is no
- // subexpression, then we are going to be setting the options
- // for the parent group. In this case we are safe to return now.
- if (*parser->cursor == ')') {
- if (pm_regexp_options_state(&options, 'x') == PM_REGEXP_OPTION_STATE_ADDED) {
- parser->extended_mode = true;
- }
-
- parser->cursor++;
- return true;
- }
-
- // If we hit a -, then we're done parsing options.
- if (*parser->cursor != '-') break;
-
- // Otherwise, fallthrough to the - case.
- /* fallthrough */
- case '-':
- parser->cursor++;
- while (!pm_regexp_char_is_eof(parser) && *parser->cursor != ':' && *parser->cursor != ')') {
- if (!pm_regexp_options_remove(&options, *parser->cursor)) {
- return false;
- }
- parser->cursor++;
- }
-
- if (pm_regexp_char_is_eof(parser)) {
- return false;
- }
-
- // If we are at the end of the group of options and there is no
- // subexpression, then we are going to be setting the options
- // for the parent group. In this case we are safe to return now.
- if (*parser->cursor == ')') {
- switch (pm_regexp_options_state(&options, 'x')) {
- case PM_REGEXP_OPTION_STATE_ADDED:
- parser->extended_mode = true;
- break;
- case PM_REGEXP_OPTION_STATE_REMOVED:
- parser->extended_mode = false;
- break;
- }
-
- parser->cursor++;
- return true;
- }
-
- break;
- default:
- parser->cursor++;
- pm_regexp_parse_error(parser, parser->cursor - 1, parser->cursor, "undefined group option");
- break;
- }
- }
-
- bool extended_mode = parser->extended_mode;
- switch (pm_regexp_options_state(&options, 'x')) {
- case PM_REGEXP_OPTION_STATE_ADDED:
- parser->extended_mode = true;
- break;
- case PM_REGEXP_OPTION_STATE_REMOVED:
- parser->extended_mode = false;
- break;
- }
-
- // Now, parse the expressions within this group.
- while (!pm_regexp_char_is_eof(parser) && *parser->cursor != ')') {
- if (!pm_regexp_parse_expression(parser, (uint16_t) (depth + 1))) {
- parser->extended_mode = extended_mode;
- return false;
- }
- pm_regexp_char_accept(parser, '|');
- }
-
- // Finally, make sure we have a closing parenthesis.
- parser->extended_mode = extended_mode;
- if (pm_regexp_char_expect(parser, ')')) return true;
-
- pm_regexp_parse_error(parser, group_start, parser->cursor, "end pattern with unmatched parenthesis");
- return false;
-}
-
-/**
- * item : anchor
- * | match-posix-class
- * | match-char-set
- * | match-char-class
- * | match-char-prop
- * | match-char
- * | match-any
- * | group
- * | quantified
- * ;
- */
-static bool
-pm_regexp_parse_item(pm_regexp_parser_t *parser, uint16_t depth) {
- switch (*parser->cursor) {
- case '^':
- case '$':
- parser->cursor++;
- return pm_regexp_parse_quantifier(parser);
- case '\\':
- parser->cursor++;
- if (!pm_regexp_char_is_eof(parser)) {
- parser->cursor++;
- }
- return pm_regexp_parse_quantifier(parser);
- case '(':
- parser->cursor++;
- return pm_regexp_parse_group(parser, depth) && pm_regexp_parse_quantifier(parser);
- case '[':
- parser->cursor++;
- return pm_regexp_parse_lbracket(parser, depth) && pm_regexp_parse_quantifier(parser);
- case '*':
- case '?':
- case '+':
- parser->cursor++;
- pm_regexp_parse_error(parser, parser->cursor - 1, parser->cursor, "target of repeat operator is not specified");
- return true;
- case ')':
- parser->cursor++;
- pm_regexp_parse_error(parser, parser->cursor - 1, parser->cursor, "unmatched close parenthesis");
- return true;
- case '#':
- if (parser->extended_mode) {
- if (!pm_regexp_char_find(parser, '\n')) parser->cursor = parser->end;
- return true;
- }
- /* fallthrough */
- default: {
- size_t width;
- if (!parser->encoding_changed) {
- width = pm_encoding_utf_8_char_width(parser->cursor, (ptrdiff_t) (parser->end - parser->cursor));
- } else {
- width = parser->encoding->char_width(parser->cursor, (ptrdiff_t) (parser->end - parser->cursor));
- }
-
- if (width == 0) return false; // TODO: add appropriate error
- parser->cursor += width;
-
- return pm_regexp_parse_quantifier(parser);
- }
- }
-}
-
-/**
- * expression : item+
- * ;
- */
-static bool
-pm_regexp_parse_expression(pm_regexp_parser_t *parser, uint16_t depth) {
- if (depth >= PM_REGEXP_PARSE_DEPTH_MAX) {
- pm_regexp_parse_error(parser, parser->start, parser->end, "parse depth limit over");
- return false;
- }
-
- if (!pm_regexp_parse_item(parser, depth)) {
- return false;
- }
-
- while (!pm_regexp_char_is_eof(parser) && *parser->cursor != ')' && *parser->cursor != '|') {
- if (!pm_regexp_parse_item(parser, depth)) {
- return false;
- }
- }
-
- return true;
-}
-
-/**
- * pattern : EOF
- * | expression EOF
- * | expression '|' pattern
- * ;
- */
-static bool
-pm_regexp_parse_pattern(pm_regexp_parser_t *parser) {
- do {
- if (pm_regexp_char_is_eof(parser)) return true;
- if (!pm_regexp_parse_expression(parser, 0)) return false;
- } while (pm_regexp_char_accept(parser, '|'));
-
- return pm_regexp_char_is_eof(parser);
-}
-
-/**
- * Parse a regular expression and extract the names of all of the named capture
- * groups.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_regexp_parse(pm_parser_t *parser, const uint8_t *source, size_t size, bool extended_mode, pm_regexp_name_callback_t name_callback, void *name_data, pm_regexp_error_callback_t error_callback, void *error_data) {
- pm_regexp_parse_pattern(&(pm_regexp_parser_t) {
- .parser = parser,
- .start = source,
- .cursor = source,
- .end = source + size,
- .extended_mode = extended_mode,
- .encoding_changed = parser->encoding_changed,
- .encoding = parser->encoding,
- .name_callback = name_callback,
- .name_data = name_data,
- .error_callback = error_callback,
- .error_data = error_data
- });
-}
diff --git a/prism/regexp.h b/prism/regexp.h
deleted file mode 100644
index c0b3163e93..0000000000
--- a/prism/regexp.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * @file regexp.h
- *
- * A regular expression parser.
- */
-#ifndef PRISM_REGEXP_H
-#define PRISM_REGEXP_H
-
-#include "prism/defines.h"
-#include "prism/parser.h"
-#include "prism/encoding.h"
-#include "prism/util/pm_memchr.h"
-#include "prism/util/pm_string.h"
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <string.h>
-
-/**
- * This callback is called when a named capture group is found.
- */
-typedef void (*pm_regexp_name_callback_t)(const pm_string_t *name, void *data);
-
-/**
- * This callback is called when a parse error is found.
- */
-typedef void (*pm_regexp_error_callback_t)(const uint8_t *start, const uint8_t *end, const char *message, void *data);
-
-/**
- * Parse a regular expression.
- *
- * @param parser The parser that is currently being used.
- * @param source The source code to parse.
- * @param size The size of the source code.
- * @param extended_mode Whether to parse the regular expression in extended mode.
- * @param name_callback The optional callback to call when a named capture group is found.
- * @param name_data The optional data to pass to the name callback.
- * @param error_callback The callback to call when a parse error is found.
- * @param error_data The data to pass to the error callback.
- */
-PRISM_EXPORTED_FUNCTION void pm_regexp_parse(pm_parser_t *parser, const uint8_t *source, size_t size, bool extended_mode, pm_regexp_name_callback_t name_callback, void *name_data, pm_regexp_error_callback_t error_callback, void *error_data);
-
-#endif
diff --git a/prism/static_literals.c b/prism/static_literals.c
deleted file mode 100644
index b8604321c9..0000000000
--- a/prism/static_literals.c
+++ /dev/null
@@ -1,617 +0,0 @@
-#include "prism/static_literals.h"
-
-/**
- * A small struct used for passing around a subset of the information that is
- * stored on the parser. We use this to avoid having static literals explicitly
- * depend on the parser struct.
- */
-typedef struct {
- /** The list of newline offsets to use to calculate line numbers. */
- const pm_newline_list_t *newline_list;
-
- /** The line number that the parser starts on. */
- int32_t start_line;
-
- /** The name of the encoding that the parser is using. */
- const char *encoding_name;
-} pm_static_literals_metadata_t;
-
-static inline uint32_t
-murmur_scramble(uint32_t value) {
- value *= 0xcc9e2d51;
- value = (value << 15) | (value >> 17);
- value *= 0x1b873593;
- return value;
-}
-
-/**
- * Murmur hash (https://en.wikipedia.org/wiki/MurmurHash) is a non-cryptographic
- * general-purpose hash function. It is fast, which is what we care about in
- * this case.
- */
-static uint32_t
-murmur_hash(const uint8_t *key, size_t length) {
- uint32_t hash = 0x9747b28c;
- uint32_t segment;
-
- for (size_t index = length >> 2; index; index--) {
- memcpy(&segment, key, sizeof(uint32_t));
- key += sizeof(uint32_t);
- hash ^= murmur_scramble(segment);
- hash = (hash << 13) | (hash >> 19);
- hash = hash * 5 + 0xe6546b64;
- }
-
- segment = 0;
- for (size_t index = length & 3; index; index--) {
- segment <<= 8;
- segment |= key[index - 1];
- }
-
- hash ^= murmur_scramble(segment);
- hash ^= (uint32_t) length;
- hash ^= hash >> 16;
- hash *= 0x85ebca6b;
- hash ^= hash >> 13;
- hash *= 0xc2b2ae35;
- hash ^= hash >> 16;
- return hash;
-}
-
-/**
- * Hash the value of an integer and return it.
- */
-static uint32_t
-integer_hash(const pm_integer_t *integer) {
- uint32_t hash;
- if (integer->values) {
- hash = murmur_hash((const uint8_t *) integer->values, sizeof(uint32_t) * integer->length);
- } else {
- hash = murmur_hash((const uint8_t *) &integer->value, sizeof(uint32_t));
- }
-
- if (integer->negative) {
- hash ^= murmur_scramble((uint32_t) 1);
- }
-
- return hash;
-}
-
-/**
- * Return the hash of the given node. It is important that nodes that have
- * equivalent static literal values have the same hash. This is because we use
- * these hashes to look for duplicates.
- */
-static uint32_t
-node_hash(const pm_static_literals_metadata_t *metadata, const pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- case PM_INTEGER_NODE: {
- // Integers hash their value.
- const pm_integer_node_t *cast = (const pm_integer_node_t *) node;
- return integer_hash(&cast->value);
- }
- case PM_SOURCE_LINE_NODE: {
- // Source lines hash their line number.
- const pm_line_column_t line_column = pm_newline_list_line_column(metadata->newline_list, node->location.start, metadata->start_line);
- const int32_t *value = &line_column.line;
- return murmur_hash((const uint8_t *) value, sizeof(int32_t));
- }
- case PM_FLOAT_NODE: {
- // Floats hash their value.
- const double *value = &((const pm_float_node_t *) node)->value;
- return murmur_hash((const uint8_t *) value, sizeof(double));
- }
- case PM_RATIONAL_NODE: {
- // Rationals hash their numerator and denominator.
- const pm_rational_node_t *cast = (const pm_rational_node_t *) node;
- return integer_hash(&cast->numerator) ^ integer_hash(&cast->denominator) ^ murmur_scramble((uint32_t) cast->base.type);
- }
- case PM_IMAGINARY_NODE: {
- // Imaginaries hash their numeric value. Because their numeric value
- // is stored as a subnode, we hash that node and then mix in the
- // fact that this is an imaginary node.
- const pm_node_t *numeric = ((const pm_imaginary_node_t *) node)->numeric;
- return node_hash(metadata, numeric) ^ murmur_scramble((uint32_t) node->type);
- }
- case PM_STRING_NODE: {
- // Strings hash their value and mix in their flags so that different
- // encodings are not considered equal.
- const pm_string_t *value = &((const pm_string_node_t *) node)->unescaped;
-
- pm_node_flags_t flags = node->flags;
- flags &= (PM_STRING_FLAGS_FORCED_BINARY_ENCODING | PM_STRING_FLAGS_FORCED_UTF8_ENCODING);
-
- return murmur_hash(pm_string_source(value), pm_string_length(value) * sizeof(uint8_t)) ^ murmur_scramble((uint32_t) flags);
- }
- case PM_SOURCE_FILE_NODE: {
- // Source files hash their value and mix in their flags so that
- // different encodings are not considered equal.
- const pm_string_t *value = &((const pm_source_file_node_t *) node)->filepath;
- return murmur_hash(pm_string_source(value), pm_string_length(value) * sizeof(uint8_t));
- }
- case PM_REGULAR_EXPRESSION_NODE: {
- // Regular expressions hash their value and mix in their flags so
- // that different encodings are not considered equal.
- const pm_string_t *value = &((const pm_regular_expression_node_t *) node)->unescaped;
- return murmur_hash(pm_string_source(value), pm_string_length(value) * sizeof(uint8_t)) ^ murmur_scramble((uint32_t) node->flags);
- }
- case PM_SYMBOL_NODE: {
- // Symbols hash their value and mix in their flags so that different
- // encodings are not considered equal.
- const pm_string_t *value = &((const pm_symbol_node_t *) node)->unescaped;
- return murmur_hash(pm_string_source(value), pm_string_length(value) * sizeof(uint8_t)) ^ murmur_scramble((uint32_t) node->flags);
- }
- default:
- assert(false && "unreachable");
- return 0;
- }
-}
-
-/**
- * Insert a node into the node hash. It accepts the hash that should hold the
- * new node, the parser that generated the node, the node to insert, and a
- * comparison function. The comparison function is used for collision detection,
- * and must be able to compare all node types that will be stored in this hash.
- */
-static pm_node_t *
-pm_node_hash_insert(pm_node_hash_t *hash, const pm_static_literals_metadata_t *metadata, pm_node_t *node, bool replace, int (*compare)(const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right)) {
- // If we are out of space, we need to resize the hash. This will cause all
- // of the nodes to be rehashed and reinserted into the new hash.
- if (hash->size * 2 >= hash->capacity) {
- // First, allocate space for the new node list.
- uint32_t new_capacity = hash->capacity == 0 ? 4 : hash->capacity * 2;
- pm_node_t **new_nodes = xcalloc(new_capacity, sizeof(pm_node_t *));
- if (new_nodes == NULL) return NULL;
-
- // It turns out to be more efficient to mask the hash value than to use
- // the modulo operator. Because our capacities are always powers of two,
- // we can use a bitwise AND to get the same result as the modulo
- // operator.
- uint32_t mask = new_capacity - 1;
-
- // Now, rehash all of the nodes into the new list.
- for (uint32_t index = 0; index < hash->capacity; index++) {
- pm_node_t *node = hash->nodes[index];
-
- if (node != NULL) {
- uint32_t index = node_hash(metadata, node) & mask;
- new_nodes[index] = node;
- }
- }
-
- // Finally, free the old node list and update the hash.
- xfree(hash->nodes);
- hash->nodes = new_nodes;
- hash->capacity = new_capacity;
- }
-
- // Now, insert the node into the hash.
- uint32_t mask = hash->capacity - 1;
- uint32_t index = node_hash(metadata, node) & mask;
-
- // We use linear probing to resolve collisions. This means that if the
- // current index is occupied, we will move to the next index and try again.
- // We are guaranteed that this will eventually find an empty slot because we
- // resize the hash when it gets too full.
- while (hash->nodes[index] != NULL) {
- if (compare(metadata, hash->nodes[index], node) == 0) break;
- index = (index + 1) & mask;
- }
-
- // If the current index is occupied, we need to return the node that was
- // already in the hash. Otherwise, we can just increment the size and insert
- // the new node.
- pm_node_t *result = hash->nodes[index];
-
- if (result == NULL) {
- hash->size++;
- hash->nodes[index] = node;
- } else if (replace) {
- hash->nodes[index] = node;
- }
-
- return result;
-}
-
-/**
- * Free the internal memory associated with the given node hash.
- */
-static void
-pm_node_hash_free(pm_node_hash_t *hash) {
- if (hash->capacity > 0) xfree(hash->nodes);
-}
-
-/**
- * Compare two values that can be compared with a simple numeric comparison.
- */
-#define PM_NUMERIC_COMPARISON(left, right) ((left < right) ? -1 : (left > right) ? 1 : 0)
-
-/**
- * Return the integer value of the given node as an int64_t.
- */
-static int64_t
-pm_int64_value(const pm_static_literals_metadata_t *metadata, const pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- case PM_INTEGER_NODE: {
- const pm_integer_t *integer = &((const pm_integer_node_t *) node)->value;
- if (integer->values) return integer->negative ? INT64_MIN : INT64_MAX;
-
- int64_t value = (int64_t) integer->value;
- return integer->negative ? -value : value;
- }
- case PM_SOURCE_LINE_NODE:
- return (int64_t) pm_newline_list_line_column(metadata->newline_list, node->location.start, metadata->start_line).line;
- default:
- assert(false && "unreachable");
- return 0;
- }
-}
-
-/**
- * A comparison function for comparing two IntegerNode or SourceLineNode
- * instances.
- */
-static int
-pm_compare_integer_nodes(const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
- if (PM_NODE_TYPE_P(left, PM_SOURCE_LINE_NODE) || PM_NODE_TYPE_P(right, PM_SOURCE_LINE_NODE)) {
- int64_t left_value = pm_int64_value(metadata, left);
- int64_t right_value = pm_int64_value(metadata, right);
- return PM_NUMERIC_COMPARISON(left_value, right_value);
- }
-
- const pm_integer_t *left_integer = &((const pm_integer_node_t *) left)->value;
- const pm_integer_t *right_integer = &((const pm_integer_node_t *) right)->value;
- return pm_integer_compare(left_integer, right_integer);
-}
-
-/**
- * A comparison function for comparing two FloatNode instances.
- */
-static int
-pm_compare_float_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
- const double left_value = ((const pm_float_node_t *) left)->value;
- const double right_value = ((const pm_float_node_t *) right)->value;
- return PM_NUMERIC_COMPARISON(left_value, right_value);
-}
-
-/**
- * A comparison function for comparing two nodes that have attached numbers.
- */
-static int
-pm_compare_number_nodes(const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
- if (PM_NODE_TYPE(left) != PM_NODE_TYPE(right)) {
- return PM_NUMERIC_COMPARISON(PM_NODE_TYPE(left), PM_NODE_TYPE(right));
- }
-
- switch (PM_NODE_TYPE(left)) {
- case PM_IMAGINARY_NODE:
- return pm_compare_number_nodes(metadata, ((const pm_imaginary_node_t *) left)->numeric, ((const pm_imaginary_node_t *) right)->numeric);
- case PM_RATIONAL_NODE: {
- const pm_rational_node_t *left_rational = (const pm_rational_node_t *) left;
- const pm_rational_node_t *right_rational = (const pm_rational_node_t *) right;
-
- int result = pm_integer_compare(&left_rational->denominator, &right_rational->denominator);
- if (result != 0) return result;
-
- return pm_integer_compare(&left_rational->numerator, &right_rational->numerator);
- }
- case PM_INTEGER_NODE:
- return pm_compare_integer_nodes(metadata, left, right);
- case PM_FLOAT_NODE:
- return pm_compare_float_nodes(metadata, left, right);
- default:
- assert(false && "unreachable");
- return 0;
- }
-}
-
-/**
- * Return a pointer to the string value of the given node.
- */
-static const pm_string_t *
-pm_string_value(const pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- case PM_STRING_NODE:
- return &((const pm_string_node_t *) node)->unescaped;
- case PM_SOURCE_FILE_NODE:
- return &((const pm_source_file_node_t *) node)->filepath;
- case PM_SYMBOL_NODE:
- return &((const pm_symbol_node_t *) node)->unescaped;
- default:
- assert(false && "unreachable");
- return NULL;
- }
-}
-
-/**
- * A comparison function for comparing two nodes that have attached strings.
- */
-static int
-pm_compare_string_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
- const pm_string_t *left_string = pm_string_value(left);
- const pm_string_t *right_string = pm_string_value(right);
- return pm_string_compare(left_string, right_string);
-}
-
-/**
- * A comparison function for comparing two RegularExpressionNode instances.
- */
-static int
-pm_compare_regular_expression_nodes(PRISM_ATTRIBUTE_UNUSED const pm_static_literals_metadata_t *metadata, const pm_node_t *left, const pm_node_t *right) {
- const pm_regular_expression_node_t *left_regexp = (const pm_regular_expression_node_t *) left;
- const pm_regular_expression_node_t *right_regexp = (const pm_regular_expression_node_t *) right;
-
- int result = pm_string_compare(&left_regexp->unescaped, &right_regexp->unescaped);
- if (result != 0) return result;
-
- return PM_NUMERIC_COMPARISON(left_regexp->base.flags, right_regexp->base.flags);
-}
-
-#undef PM_NUMERIC_COMPARISON
-
-/**
- * Add a node to the set of static literals.
- */
-pm_node_t *
-pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line, pm_static_literals_t *literals, pm_node_t *node, bool replace) {
- switch (PM_NODE_TYPE(node)) {
- case PM_INTEGER_NODE:
- case PM_SOURCE_LINE_NODE:
- return pm_node_hash_insert(
- &literals->integer_nodes,
- &(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
- .start_line = start_line,
- .encoding_name = NULL
- },
- node,
- replace,
- pm_compare_integer_nodes
- );
- case PM_FLOAT_NODE:
- return pm_node_hash_insert(
- &literals->float_nodes,
- &(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
- .start_line = start_line,
- .encoding_name = NULL
- },
- node,
- replace,
- pm_compare_float_nodes
- );
- case PM_RATIONAL_NODE:
- case PM_IMAGINARY_NODE:
- return pm_node_hash_insert(
- &literals->number_nodes,
- &(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
- .start_line = start_line,
- .encoding_name = NULL
- },
- node,
- replace,
- pm_compare_number_nodes
- );
- case PM_STRING_NODE:
- case PM_SOURCE_FILE_NODE:
- return pm_node_hash_insert(
- &literals->string_nodes,
- &(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
- .start_line = start_line,
- .encoding_name = NULL
- },
- node,
- replace,
- pm_compare_string_nodes
- );
- case PM_REGULAR_EXPRESSION_NODE:
- return pm_node_hash_insert(
- &literals->regexp_nodes,
- &(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
- .start_line = start_line,
- .encoding_name = NULL
- },
- node,
- replace,
- pm_compare_regular_expression_nodes
- );
- case PM_SYMBOL_NODE:
- return pm_node_hash_insert(
- &literals->symbol_nodes,
- &(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
- .start_line = start_line,
- .encoding_name = NULL
- },
- node,
- replace,
- pm_compare_string_nodes
- );
- case PM_TRUE_NODE: {
- pm_node_t *duplicated = literals->true_node;
- if ((duplicated == NULL) || replace) literals->true_node = node;
- return duplicated;
- }
- case PM_FALSE_NODE: {
- pm_node_t *duplicated = literals->false_node;
- if ((duplicated == NULL) || replace) literals->false_node = node;
- return duplicated;
- }
- case PM_NIL_NODE: {
- pm_node_t *duplicated = literals->nil_node;
- if ((duplicated == NULL) || replace) literals->nil_node = node;
- return duplicated;
- }
- case PM_SOURCE_ENCODING_NODE: {
- pm_node_t *duplicated = literals->source_encoding_node;
- if ((duplicated == NULL) || replace) literals->source_encoding_node = node;
- return duplicated;
- }
- default:
- return NULL;
- }
-}
-
-/**
- * Free the internal memory associated with the given static literals set.
- */
-void
-pm_static_literals_free(pm_static_literals_t *literals) {
- pm_node_hash_free(&literals->integer_nodes);
- pm_node_hash_free(&literals->float_nodes);
- pm_node_hash_free(&literals->number_nodes);
- pm_node_hash_free(&literals->string_nodes);
- pm_node_hash_free(&literals->regexp_nodes);
- pm_node_hash_free(&literals->symbol_nodes);
-}
-
-/**
- * A helper to determine if the given node is a static literal that is positive.
- * This is used for formatting imaginary nodes.
- */
-static bool
-pm_static_literal_positive_p(const pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- case PM_FLOAT_NODE:
- return ((const pm_float_node_t *) node)->value > 0;
- case PM_INTEGER_NODE:
- return !((const pm_integer_node_t *) node)->value.negative;
- case PM_RATIONAL_NODE:
- return !((const pm_rational_node_t *) node)->numerator.negative;
- case PM_IMAGINARY_NODE:
- return pm_static_literal_positive_p(((const pm_imaginary_node_t *) node)->numeric);
- default:
- assert(false && "unreachable");
- return false;
- }
-}
-
-/**
- * Create a string-based representation of the given static literal.
- */
-static inline void
-pm_static_literal_inspect_node(pm_buffer_t *buffer, const pm_static_literals_metadata_t *metadata, const pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- case PM_FALSE_NODE:
- pm_buffer_append_string(buffer, "false", 5);
- break;
- case PM_FLOAT_NODE: {
- const double value = ((const pm_float_node_t *) node)->value;
-
- if (isinf(value)) {
- if (*node->location.start == '-') {
- pm_buffer_append_byte(buffer, '-');
- }
- pm_buffer_append_string(buffer, "Infinity", 8);
- } else if (value == 0.0) {
- if (*node->location.start == '-') {
- pm_buffer_append_byte(buffer, '-');
- }
- pm_buffer_append_string(buffer, "0.0", 3);
- } else {
- pm_buffer_append_format(buffer, "%g", value);
-
- // %g will not insert a .0 for 1e100 (we'll get back 1e+100). So
- // we check for the decimal point and add it in here if it's not
- // present.
- if (pm_buffer_index(buffer, '.') == SIZE_MAX) {
- size_t exponent_index = pm_buffer_index(buffer, 'e');
- size_t index = exponent_index == SIZE_MAX ? pm_buffer_length(buffer) : exponent_index;
- pm_buffer_insert(buffer, index, ".0", 2);
- }
- }
-
- break;
- }
- case PM_IMAGINARY_NODE: {
- const pm_node_t *numeric = ((const pm_imaginary_node_t *) node)->numeric;
- pm_buffer_append_string(buffer, "(0", 2);
- if (pm_static_literal_positive_p(numeric)) pm_buffer_append_byte(buffer, '+');
- pm_static_literal_inspect_node(buffer, metadata, numeric);
- if (PM_NODE_TYPE_P(numeric, PM_RATIONAL_NODE)) {
- pm_buffer_append_byte(buffer, '*');
- }
- pm_buffer_append_string(buffer, "i)", 2);
- break;
- }
- case PM_INTEGER_NODE:
- pm_integer_string(buffer, &((const pm_integer_node_t *) node)->value);
- break;
- case PM_NIL_NODE:
- pm_buffer_append_string(buffer, "nil", 3);
- break;
- case PM_RATIONAL_NODE: {
- const pm_rational_node_t *rational = (const pm_rational_node_t *) node;
- pm_buffer_append_byte(buffer, '(');
- pm_integer_string(buffer, &rational->numerator);
- pm_buffer_append_byte(buffer, '/');
- pm_integer_string(buffer, &rational->denominator);
- pm_buffer_append_byte(buffer, ')');
- break;
- }
- case PM_REGULAR_EXPRESSION_NODE: {
- const pm_string_t *unescaped = &((const pm_regular_expression_node_t *) node)->unescaped;
- pm_buffer_append_byte(buffer, '/');
- pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
- pm_buffer_append_byte(buffer, '/');
-
- if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) pm_buffer_append_string(buffer, "m", 1);
- if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) pm_buffer_append_string(buffer, "i", 1);
- if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) pm_buffer_append_string(buffer, "x", 1);
- if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) pm_buffer_append_string(buffer, "n", 1);
-
- break;
- }
- case PM_SOURCE_ENCODING_NODE:
- pm_buffer_append_format(buffer, "#<Encoding:%s>", metadata->encoding_name);
- break;
- case PM_SOURCE_FILE_NODE: {
- const pm_string_t *filepath = &((const pm_source_file_node_t *) node)->filepath;
- pm_buffer_append_byte(buffer, '"');
- pm_buffer_append_source(buffer, pm_string_source(filepath), pm_string_length(filepath), PM_BUFFER_ESCAPING_RUBY);
- pm_buffer_append_byte(buffer, '"');
- break;
- }
- case PM_SOURCE_LINE_NODE:
- pm_buffer_append_format(buffer, "%d", pm_newline_list_line_column(metadata->newline_list, node->location.start, metadata->start_line).line);
- break;
- case PM_STRING_NODE: {
- const pm_string_t *unescaped = &((const pm_string_node_t *) node)->unescaped;
- pm_buffer_append_byte(buffer, '"');
- pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
- pm_buffer_append_byte(buffer, '"');
- break;
- }
- case PM_SYMBOL_NODE: {
- const pm_string_t *unescaped = &((const pm_symbol_node_t *) node)->unescaped;
- pm_buffer_append_byte(buffer, ':');
- pm_buffer_append_source(buffer, pm_string_source(unescaped), pm_string_length(unescaped), PM_BUFFER_ESCAPING_RUBY);
- break;
- }
- case PM_TRUE_NODE:
- pm_buffer_append_string(buffer, "true", 4);
- break;
- default:
- assert(false && "unreachable");
- break;
- }
-}
-
-/**
- * Create a string-based representation of the given static literal.
- */
-void
-pm_static_literal_inspect(pm_buffer_t *buffer, const pm_newline_list_t *newline_list, int32_t start_line, const char *encoding_name, const pm_node_t *node) {
- pm_static_literal_inspect_node(
- buffer,
- &(pm_static_literals_metadata_t) {
- .newline_list = newline_list,
- .start_line = start_line,
- .encoding_name = encoding_name
- },
- node
- );
-}
diff --git a/prism/static_literals.h b/prism/static_literals.h
deleted file mode 100644
index bd29761899..0000000000
--- a/prism/static_literals.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * @file static_literals.h
- *
- * A set of static literal nodes that can be checked for duplicates.
- */
-#ifndef PRISM_STATIC_LITERALS_H
-#define PRISM_STATIC_LITERALS_H
-
-#include "prism/defines.h"
-#include "prism/ast.h"
-#include "prism/util/pm_newline_list.h"
-
-#include <assert.h>
-#include <stdbool.h>
-
-/**
- * An internal hash table for a set of nodes.
- */
-typedef struct {
- /** The array of nodes in the hash table. */
- pm_node_t **nodes;
-
- /** The size of the hash table. */
- uint32_t size;
-
- /** The space that has been allocated in the hash table. */
- uint32_t capacity;
-} pm_node_hash_t;
-
-/**
- * Certain sets of nodes (hash keys and when clauses) check for duplicate nodes
- * to alert the user of potential issues. To do this, we keep a set of the nodes
- * that have been seen so far, and compare whenever we find a new node.
- *
- * We bucket the nodes based on their type to minimize the number of comparisons
- * that need to be performed.
- */
-typedef struct {
- /**
- * This is the set of IntegerNode and SourceLineNode instances.
- */
- pm_node_hash_t integer_nodes;
-
- /**
- * This is the set of FloatNode instances.
- */
- pm_node_hash_t float_nodes;
-
- /**
- * This is the set of RationalNode and ImaginaryNode instances.
- */
- pm_node_hash_t number_nodes;
-
- /**
- * This is the set of StringNode and SourceFileNode instances.
- */
- pm_node_hash_t string_nodes;
-
- /**
- * This is the set of RegularExpressionNode instances.
- */
- pm_node_hash_t regexp_nodes;
-
- /**
- * This is the set of SymbolNode instances.
- */
- pm_node_hash_t symbol_nodes;
-
- /**
- * A pointer to the last TrueNode instance that was inserted, or NULL.
- */
- pm_node_t *true_node;
-
- /**
- * A pointer to the last FalseNode instance that was inserted, or NULL.
- */
- pm_node_t *false_node;
-
- /**
- * A pointer to the last NilNode instance that was inserted, or NULL.
- */
- pm_node_t *nil_node;
-
- /**
- * A pointer to the last SourceEncodingNode instance that was inserted, or
- * NULL.
- */
- pm_node_t *source_encoding_node;
-} pm_static_literals_t;
-
-/**
- * Add a node to the set of static literals.
- *
- * @param newline_list The list of newline offsets to use to calculate lines.
- * @param start_line The line number that the parser starts on.
- * @param literals The set of static literals to add the node to.
- * @param node The node to add to the set.
- * @param replace Whether to replace the previous node if one already exists.
- * @return A pointer to the node that is being overwritten, if there is one.
- */
-pm_node_t * pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line, pm_static_literals_t *literals, pm_node_t *node, bool replace);
-
-/**
- * Free the internal memory associated with the given static literals set.
- *
- * @param literals The set of static literals to free.
- */
-void pm_static_literals_free(pm_static_literals_t *literals);
-
-/**
- * Create a string-based representation of the given static literal.
- *
- * @param buffer The buffer to write the string to.
- * @param newline_list The list of newline offsets to use to calculate lines.
- * @param start_line The line number that the parser starts on.
- * @param encoding_name The name of the encoding of the source being parsed.
- * @param node The node to create a string representation of.
- */
-void pm_static_literal_inspect(pm_buffer_t *buffer, const pm_newline_list_t *newline_list, int32_t start_line, const char *encoding_name, const pm_node_t *node);
-
-#endif
diff --git a/prism/templates/ext/prism/api_node.c.erb b/prism/templates/ext/prism/api_node.c.erb
deleted file mode 100644
index 03615b0ae2..0000000000
--- a/prism/templates/ext/prism/api_node.c.erb
+++ /dev/null
@@ -1,259 +0,0 @@
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
-#include "prism/extension.h"
-
-extern VALUE rb_cPrism;
-extern VALUE rb_cPrismNode;
-extern VALUE rb_cPrismSource;
-extern VALUE rb_cPrismToken;
-extern VALUE rb_cPrismLocation;
-
-<%- nodes.each do |node| -%>
-static VALUE rb_cPrism<%= node.name %>;
-<%- end -%>
-
-static VALUE
-pm_location_new(const pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- uint64_t value = ((((uint64_t) (start - parser->start)) << 32) | ((uint32_t) (end - start)));
- return ULL2NUM(value);
-}
-
-VALUE
-pm_token_new(const pm_parser_t *parser, const pm_token_t *token, rb_encoding *encoding, VALUE source) {
- ID type = rb_intern(pm_token_type_name(token->type));
- VALUE location = pm_location_new(parser, token->start, token->end);
-
- VALUE argv[] = {
- source,
- ID2SYM(type),
- rb_enc_str_new((const char *) token->start, token->end - token->start, encoding),
- location
- };
-
- return rb_class_new_instance(4, argv, rb_cPrismToken);
-}
-
-static VALUE
-pm_string_new(const pm_string_t *string, rb_encoding *encoding) {
- return rb_enc_str_new((const char *) pm_string_source(string), pm_string_length(string), encoding);
-}
-
-VALUE
-pm_integer_new(const pm_integer_t *integer) {
- VALUE result;
- if (integer->values == NULL) {
- result = UINT2NUM(integer->value);
- } else {
- VALUE string = rb_str_new(NULL, integer->length * 8);
- unsigned char *bytes = (unsigned char *) RSTRING_PTR(string);
-
- size_t offset = integer->length * 8;
- for (size_t value_index = 0; value_index < integer->length; value_index++) {
- uint32_t value = integer->values[value_index];
-
- for (int index = 0; index < 8; index++) {
- int byte = (value >> (4 * index)) & 0xf;
- bytes[--offset] = byte < 10 ? byte + '0' : byte - 10 + 'a';
- }
- }
-
- result = rb_funcall(string, rb_intern("to_i"), 1, UINT2NUM(16));
- }
-
- if (integer->negative) {
- result = rb_funcall(result, rb_intern("-@"), 0);
- }
-
- return result;
-}
-
-// Create a Prism::Source object from the given parser, after pm_parse() was called.
-VALUE
-pm_source_new(const pm_parser_t *parser, rb_encoding *encoding) {
- VALUE source_string = rb_enc_str_new((const char *) parser->start, parser->end - parser->start, encoding);
-
- VALUE offsets = rb_ary_new_capa(parser->newline_list.size);
- for (size_t index = 0; index < parser->newline_list.size; index++) {
- rb_ary_push(offsets, ULONG2NUM(parser->newline_list.offsets[index]));
- }
-
- return rb_funcall(rb_cPrismSource, rb_intern("for"), 3, source_string, LONG2NUM(parser->start_line), offsets);
-}
-
-typedef struct pm_node_stack_node {
- struct pm_node_stack_node *prev;
- const pm_node_t *visit;
- bool visited;
-} pm_node_stack_node_t;
-
-static void
-pm_node_stack_push(pm_node_stack_node_t **stack, const pm_node_t *visit) {
- pm_node_stack_node_t *node = xmalloc(sizeof(pm_node_stack_node_t));
- node->prev = *stack;
- node->visit = visit;
- node->visited = false;
- *stack = node;
-}
-
-static const pm_node_t *
-pm_node_stack_pop(pm_node_stack_node_t **stack) {
- pm_node_stack_node_t *current = *stack;
- const pm_node_t *visit = current->visit;
-
- *stack = current->prev;
- xfree(current);
-
- return visit;
-}
-
-VALUE
-pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encoding, VALUE source) {
- VALUE constants = rb_ary_new_capa(parser->constant_pool.size);
-
- for (uint32_t index = 0; index < parser->constant_pool.size; index++) {
- pm_constant_t *constant = &parser->constant_pool.constants[index];
- int state = 0;
-
- VALUE string = rb_enc_str_new((const char *) constant->start, constant->length, encoding);
- VALUE value = rb_protect(rb_str_intern, string, &state);
-
- if (state != 0) {
- value = ID2SYM(rb_intern_const("?"));
- rb_set_errinfo(Qnil);
- }
-
- rb_ary_push(constants, value);
- }
-
- pm_node_stack_node_t *node_stack = NULL;
- pm_node_stack_push(&node_stack, node);
- VALUE value_stack = rb_ary_new();
-
- while (node_stack != NULL) {
- if (!node_stack->visited) {
- if (node_stack->visit == NULL) {
- pm_node_stack_pop(&node_stack);
- rb_ary_push(value_stack, Qnil);
- continue;
- }
-
- const pm_node_t *node = node_stack->visit;
- node_stack->visited = true;
-
- switch (PM_NODE_TYPE(node)) {
- <%- nodes.each do |node| -%>
- <%- if node.fields.any? { |field| [Prism::Template::NodeField, Prism::Template::OptionalNodeField, Prism::Template::NodeListField].include?(field.class) } -%>
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- case <%= node.type %>: {
- pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node;
- <%- node.fields.each do |field| -%>
- <%- case field -%>
- <%- when Prism::Template::NodeField, Prism::Template::OptionalNodeField -%>
- pm_node_stack_push(&node_stack, (pm_node_t *) cast-><%= field.name %>);
- <%- when Prism::Template::NodeListField -%>
- for (size_t index = 0; index < cast-><%= field.name %>.size; index++) {
- pm_node_stack_push(&node_stack, (pm_node_t *) cast-><%= field.name %>.nodes[index]);
- }
- <%- end -%>
- <%- end -%>
- break;
- }
- <%- end -%>
- <%- end -%>
- default:
- break;
- }
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- } else {
- const pm_node_t *node = pm_node_stack_pop(&node_stack);
-
- switch (PM_NODE_TYPE(node)) {
- <%- nodes.each do |node| -%>
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- case <%= node.type %>: {
- <%- if node.fields.any? { |field| ![Prism::Template::NodeField, Prism::Template::OptionalNodeField].include?(field.class) } -%>
- pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node;
- <%- end -%>
- VALUE argv[<%= node.fields.length + 4 %>];
-
- // source
- argv[0] = source;
-
- // node_id
- argv[1] = ULONG2NUM(node->node_id);
-
- // location
- argv[2] = pm_location_new(parser, node->location.start, node->location.end);
-
- // flags
- argv[3] = ULONG2NUM(node->flags);
- <%- node.fields.each.with_index(4) do |field, index| -%>
-
- // <%= field.name %>
- <%- case field -%>
- <%- when Prism::Template::NodeField, Prism::Template::OptionalNodeField -%>
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = rb_ary_pop(value_stack);
- <%- when Prism::Template::NodeListField -%>
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = rb_ary_new_capa(cast-><%= field.name %>.size);
- for (size_t index = 0; index < cast-><%= field.name %>.size; index++) {
- rb_ary_push(argv[<%= index %>], rb_ary_pop(value_stack));
- }
- <%- when Prism::Template::StringField -%>
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = pm_string_new(&cast-><%= field.name %>, encoding);
- <%- when Prism::Template::ConstantField -%>
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- assert(cast-><%= field.name %> != 0);
- argv[<%= index %>] = RARRAY_AREF(constants, cast-><%= field.name %> - 1);
- <%- when Prism::Template::OptionalConstantField -%>
- argv[<%= index %>] = cast-><%= field.name %> == 0 ? Qnil : RARRAY_AREF(constants, cast-><%= field.name %> - 1);
- <%- when Prism::Template::ConstantListField -%>
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = rb_ary_new_capa(cast-><%= field.name %>.size);
- for (size_t index = 0; index < cast-><%= field.name %>.size; index++) {
- assert(cast-><%= field.name %>.ids[index] != 0);
- rb_ary_push(argv[<%= index %>], RARRAY_AREF(constants, cast-><%= field.name %>.ids[index] - 1));
- }
- <%- when Prism::Template::LocationField -%>
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = pm_location_new(parser, cast-><%= field.name %>.start, cast-><%= field.name %>.end);
- <%- when Prism::Template::OptionalLocationField -%>
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = cast-><%= field.name %>.start == NULL ? Qnil : pm_location_new(parser, cast-><%= field.name %>.start, cast-><%= field.name %>.end);
- <%- when Prism::Template::UInt8Field -%>
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = UINT2NUM(cast-><%= field.name %>);
- <%- when Prism::Template::UInt32Field -%>
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = ULONG2NUM(cast-><%= field.name %>);
- <%- when Prism::Template::IntegerField -%>
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = pm_integer_new(&cast-><%= field.name %>);
- <%- when Prism::Template::DoubleField -%>
-#line <%= __LINE__ + 1 %> "prism/templates/ext/prism/<%= File.basename(__FILE__) %>"
- argv[<%= index %>] = DBL2NUM(cast-><%= field.name %>);
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- <%- end -%>
-
- rb_ary_push(value_stack, rb_class_new_instance(<%= node.fields.length + 4 %>, argv, rb_cPrism<%= node.name %>));
- break;
- }
- <%- end -%>
- default:
- rb_raise(rb_eRuntimeError, "unknown node type: %d", PM_NODE_TYPE(node));
- }
- }
- }
-
- return rb_ary_pop(value_stack);
-}
-
-void
-Init_prism_api_node(void) {
- <%- nodes.each do |node| -%>
- rb_cPrism<%= node.name %> = rb_define_class_under(rb_cPrism, "<%= node.name %>", rb_cPrismNode);
- <%- end -%>
-}
diff --git a/prism/templates/include/prism/ast.h.erb b/prism/templates/include/prism/ast.h.erb
deleted file mode 100644
index 751c0b43c2..0000000000
--- a/prism/templates/include/prism/ast.h.erb
+++ /dev/null
@@ -1,224 +0,0 @@
-/**
- * @file ast.h
- *
- * The abstract syntax tree.
- */
-#ifndef PRISM_AST_H
-#define PRISM_AST_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_constant_pool.h"
-#include "prism/util/pm_integer.h"
-#include "prism/util/pm_string.h"
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdint.h>
-
-/**
- * This enum represents every type of token in the Ruby source.
- */
-typedef enum pm_token_type {
-<%- tokens.each do |token| -%>
- /** <%= token.comment %> */
- PM_TOKEN_<%= token.name %><%= " = #{token.value}" if token.value %>,
-
-<%- end -%>
- /** The maximum token value. */
- PM_TOKEN_MAXIMUM,
-} pm_token_type_t;
-
-/**
- * This struct represents a token in the Ruby source. We use it to track both
- * type and location information.
- */
-typedef struct {
- /** The type of the token. */
- pm_token_type_t type;
-
- /** A pointer to the start location of the token in the source. */
- const uint8_t *start;
-
- /** A pointer to the end location of the token in the source. */
- const uint8_t *end;
-} pm_token_t;
-
-/**
- * This represents a range of bytes in the source string to which a node or
- * token corresponds.
- */
-typedef struct {
- /** A pointer to the start location of the range in the source. */
- const uint8_t *start;
-
- /** A pointer to the end location of the range in the source. */
- const uint8_t *end;
-} pm_location_t;
-
-struct pm_node;
-
-/**
- * A list of nodes in the source, most often used for lists of children.
- */
-typedef struct pm_node_list {
- /** The number of nodes in the list. */
- size_t size;
-
- /** The capacity of the list that has been allocated. */
- size_t capacity;
-
- /** The nodes in the list. */
- struct pm_node **nodes;
-} pm_node_list_t;
-
-/**
- * This enum represents every type of node in the Ruby syntax tree.
- */
-enum pm_node_type {
-<%- nodes.each_with_index do |node, index| -%>
- /** <%= node.name %> */
- <%= node.type %> = <%= index + 1 %>,
-
-<%- end -%>
- /** A special kind of node used for compilation. */
- PM_SCOPE_NODE
-};
-
-/**
- * This is the type of node embedded in the node struct. We explicitly control
- * the size of it here to avoid having the variable-width enum.
- */
-typedef uint16_t pm_node_type_t;
-
-/**
- * These are the flags embedded in the node struct. We explicitly control the
- * size of it here to avoid having the variable-width enum.
- */
-typedef uint16_t pm_node_flags_t;
-
-/**
- * We store the flags enum in every node in the tree. Some flags are common to
- * all nodes (the ones listed below). Others are specific to certain node types.
- */
-static const pm_node_flags_t PM_NODE_FLAG_NEWLINE = 0x1;
-static const pm_node_flags_t PM_NODE_FLAG_STATIC_LITERAL = 0x2;
-
-/**
- * Cast the type to an enum to allow the compiler to provide exhaustiveness
- * checking.
- */
-#define PM_NODE_TYPE(node) ((enum pm_node_type) (node)->type)
-
-/**
- * Return true if the type of the given node matches the given type.
- */
-#define PM_NODE_TYPE_P(node, type) (PM_NODE_TYPE(node) == (type))
-
-/**
- * Return true if the given flag is set on the given node.
- */
-#define PM_NODE_FLAG_P(node, flag) ((((pm_node_t *)(node))->flags & (flag)) != 0)
-
-/**
- * This is the base structure that represents a node in the syntax tree. It is
- * embedded into every node type.
- */
-typedef struct pm_node {
- /**
- * This represents the type of the node. It somewhat maps to the nodes that
- * existed in the original grammar and ripper, but it's not a 1:1 mapping.
- */
- pm_node_type_t type;
-
- /**
- * This represents any flags on the node. Some are common to all nodes, and
- * some are specific to the type of node.
- */
- pm_node_flags_t flags;
-
- /**
- * The unique identifier for this node, which is deterministic based on the
- * source. It is used to identify unique nodes across parses.
- */
- uint32_t node_id;
-
- /**
- * This is the location of the node in the source. It's a range of bytes
- * containing a start and an end.
- */
- pm_location_t location;
-} pm_node_t;
-<%- nodes.each do |node| -%>
-
-/**
- * <%= node.name %>
- *
-<%- node.each_comment_line do |line| -%>
- *<%= line %>
-<%- end -%>
- *
- * Type: ::<%= node.type %>
-<% if (node_flags = node.flags) %>
- * Flags (#pm_<%= node_flags.human %>):
-<%- node_flags.values.each do |value| -%>
- * * ::PM_<%= node_flags.human.upcase %>_<%= value.name %>
-<%- end -%>
-<%- end -%>
- *
- * @extends pm_node_t
- */
-typedef struct pm_<%= node.human %> {
- /** The embedded base node. */
- pm_node_t base;
-
-<%- node.fields.each do |field| -%>
-
- /**
- * <%= node.name %>#<%= field.name %>
- <%- if field.comment -%>
- *
- <%- field.each_comment_line do |line| -%>
- *<%= line %>
- <%- end -%>
- <%- end -%>
- */
- <%= case field
- when Prism::Template::NodeField, Prism::Template::OptionalNodeField then "struct #{field.c_type} *#{field.name}"
- when Prism::Template::NodeListField then "struct pm_node_list #{field.name}"
- when Prism::Template::ConstantField, Prism::Template::OptionalConstantField then "pm_constant_id_t #{field.name}"
- when Prism::Template::ConstantListField then "pm_constant_id_list_t #{field.name}"
- when Prism::Template::StringField then "pm_string_t #{field.name}"
- when Prism::Template::LocationField, Prism::Template::OptionalLocationField then "pm_location_t #{field.name}"
- when Prism::Template::UInt8Field then "uint8_t #{field.name}"
- when Prism::Template::UInt32Field then "uint32_t #{field.name}"
- when Prism::Template::IntegerField then "pm_integer_t #{field.name}"
- when Prism::Template::DoubleField then "double #{field.name}"
- else raise field.class.name
- end
- %>;
-<%- end -%>
-} pm_<%= node.human %>_t;
-<%- end -%>
-<%- flags.each do |flag| -%>
-
-/**
- * <%= flag.comment %>
- */
-typedef enum pm_<%= flag.human %> {
- <%- flag.values.each_with_index do |value, index| -%>
-<%= "\n" if index > 0 -%>
- /** <%= value.comment %> */
- PM_<%= flag.human.upcase %>_<%= value.name %> = <%= 1 << (index + Prism::Template::COMMON_FLAGS_COUNT) %>,
- <%- end -%>
-} pm_<%= flag.human %>_t;
-<%- end -%>
-
-/**
- * When we're serializing to Java, we want to skip serializing the location
- * fields as they won't be used by JRuby or TruffleRuby. This boolean allows us
- * to specify that through the environment. It will never be true except for in
- * those build systems.
- */
-#define PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS <%= Prism::Template::SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0 %>
-
-#endif
diff --git a/prism/templates/include/prism/diagnostic.h.erb b/prism/templates/include/prism/diagnostic.h.erb
deleted file mode 100644
index 07bbc8fae7..0000000000
--- a/prism/templates/include/prism/diagnostic.h.erb
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * @file diagnostic.h
- *
- * A list of diagnostics generated during parsing.
- */
-#ifndef PRISM_DIAGNOSTIC_H
-#define PRISM_DIAGNOSTIC_H
-
-#include "prism/ast.h"
-#include "prism/defines.h"
-#include "prism/util/pm_list.h"
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <assert.h>
-
-/**
- * The diagnostic IDs of all of the diagnostics, used to communicate the types
- * of errors between the parser and the user.
- */
-typedef enum {
- // These are the error diagnostics.
- <%- errors.each do |error| -%>
- PM_ERR_<%= error.name %>,
- <%- end -%>
-
- // These are the warning diagnostics.
- <%- warnings.each do |warning| -%>
- PM_WARN_<%= warning.name %>,
- <%- end -%>
-} pm_diagnostic_id_t;
-
-/**
- * This struct represents a diagnostic generated during parsing.
- *
- * @extends pm_list_node_t
- */
-typedef struct {
- /** The embedded base node. */
- pm_list_node_t node;
-
- /** The location of the diagnostic in the source. */
- pm_location_t location;
-
- /** The ID of the diagnostic. */
- pm_diagnostic_id_t diag_id;
-
- /** The message associated with the diagnostic. */
- const char *message;
-
- /**
- * Whether or not the memory related to the message of this diagnostic is
- * owned by this diagnostic. If it is, it needs to be freed when the
- * diagnostic is freed.
- */
- bool owned;
-
- /**
- * The level of the diagnostic, see `pm_error_level_t` and
- * `pm_warning_level_t` for possible values.
- */
- uint8_t level;
-} pm_diagnostic_t;
-
-/**
- * The levels of errors generated during parsing.
- */
-typedef enum {
- /** For errors that should raise a syntax error. */
- PM_ERROR_LEVEL_SYNTAX = 0,
-
- /** For errors that should raise an argument error. */
- PM_ERROR_LEVEL_ARGUMENT = 1,
-
- /** For errors that should raise a load error. */
- PM_ERROR_LEVEL_LOAD = 2
-} pm_error_level_t;
-
-/**
- * The levels of warnings generated during parsing.
- */
-typedef enum {
- /** For warnings which should be emitted if $VERBOSE != nil. */
- PM_WARNING_LEVEL_DEFAULT = 0,
-
- /** For warnings which should be emitted if $VERBOSE == true. */
- PM_WARNING_LEVEL_VERBOSE = 1
-} pm_warning_level_t;
-
-/**
- * Get the human-readable name of the given diagnostic ID.
- *
- * @param diag_id The diagnostic ID.
- * @return The human-readable name of the diagnostic ID.
- */
-const char * pm_diagnostic_id_human(pm_diagnostic_id_t diag_id);
-
-/**
- * Append a diagnostic to the given list of diagnostics that is using shared
- * memory for its message.
- *
- * @param list The list to append to.
- * @param start The start of the diagnostic.
- * @param end The end of the diagnostic.
- * @param diag_id The diagnostic ID.
- * @return Whether the diagnostic was successfully appended.
- */
-bool pm_diagnostic_list_append(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id);
-
-/**
- * Append a diagnostic to the given list of diagnostics that is using a format
- * string for its message.
- *
- * @param list The list to append to.
- * @param start The start of the diagnostic.
- * @param end The end of the diagnostic.
- * @param diag_id The diagnostic ID.
- * @param ... The arguments to the format string for the message.
- * @return Whether the diagnostic was successfully appended.
- */
-bool pm_diagnostic_list_append_format(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id, ...);
-
-/**
- * Deallocate the internal state of the given diagnostic list.
- *
- * @param list The list to deallocate.
- */
-void pm_diagnostic_list_free(pm_list_t *list);
-
-#endif
diff --git a/prism/templates/lib/prism/compiler.rb.erb b/prism/templates/lib/prism/compiler.rb.erb
deleted file mode 100644
index 45ed88d8de..0000000000
--- a/prism/templates/lib/prism/compiler.rb.erb
+++ /dev/null
@@ -1,41 +0,0 @@
-module Prism
- # A compiler is a visitor that returns the value of each node as it visits.
- # This is as opposed to a visitor which will only walk the tree. This can be
- # useful when you are trying to compile a tree into a different format.
- #
- # For example, to build a representation of the tree as s-expressions, you
- # could write:
- #
- # class SExpressions < Prism::Compiler
- # def visit_arguments_node(node) = [:arguments, super]
- # def visit_call_node(node) = [:call, super]
- # def visit_integer_node(node) = [:integer]
- # def visit_program_node(node) = [:program, super]
- # end
- #
- # Prism.parse("1 + 2").value.accept(SExpressions.new)
- # # => [:program, [[[:call, [[:integer], [:arguments, [[:integer]]]]]]]]
- #
- class Compiler < Visitor
- # Visit an individual node.
- def visit(node)
- node&.accept(self)
- end
-
- # Visit a list of nodes.
- def visit_all(nodes)
- nodes.map { |node| node&.accept(self) }
- end
-
- # Visit the child nodes of the given node.
- def visit_child_nodes(node)
- node.compact_child_nodes.map { |node| node.accept(self) }
- end
-
- <%- nodes.each_with_index do |node, index| -%>
-<%= "\n" if index != 0 -%>
- # Compile a <%= node.name %> node
- alias visit_<%= node.human %> visit_child_nodes
- <%- end -%>
- end
-end
diff --git a/prism/templates/lib/prism/dispatcher.rb.erb b/prism/templates/lib/prism/dispatcher.rb.erb
deleted file mode 100644
index 0db0003464..0000000000
--- a/prism/templates/lib/prism/dispatcher.rb.erb
+++ /dev/null
@@ -1,90 +0,0 @@
-module Prism
- # The dispatcher class fires events for nodes that are found while walking an
- # AST to all registered listeners. It's useful for performing different types
- # of analysis on the AST while only having to walk the tree once.
- #
- # To use the dispatcher, you would first instantiate it and register listeners
- # for the events you're interested in:
- #
- # class OctalListener
- # def on_integer_node_enter(node)
- # if node.octal? && !node.slice.start_with?("0o")
- # warn("Octal integers should be written with the 0o prefix")
- # end
- # end
- # end
- #
- # listener = OctalListener.new
- # dispatcher = Prism::Dispatcher.new
- # dispatcher.register(listener, :on_integer_node_enter)
- #
- # Then, you can walk any number of trees and dispatch events to the listeners:
- #
- # result = Prism.parse("001 + 002 + 003")
- # dispatcher.dispatch(result.value)
- #
- # Optionally, you can also use `#dispatch_once` to dispatch enter and leave
- # events for a single node without recursing further down the tree. This can
- # be useful in circumstances where you want to reuse the listeners you already
- # have registers but want to stop walking the tree at a certain point.
- #
- # integer = result.value.statements.body.first.receiver.receiver
- # dispatcher.dispatch_once(integer)
- #
- class Dispatcher < Visitor
- # attr_reader listeners: Hash[Symbol, Array[Listener]]
- attr_reader :listeners
-
- # Initialize a new dispatcher.
- def initialize
- @listeners = {}
- end
-
- # Register a listener for one or more events.
- #
- # def register: (Listener, *Symbol) -> void
- def register(listener, *events)
- events.each { |event| (listeners[event] ||= []) << listener }
- end
-
- # Walks `root` dispatching events to all registered listeners.
- #
- # def dispatch: (Node) -> void
- alias dispatch visit
-
- # Dispatches a single event for `node` to all registered listeners.
- #
- # def dispatch_once: (Node) -> void
- def dispatch_once(node)
- node.accept(DispatchOnce.new(listeners))
- end
- <%- nodes.each do |node| -%>
-
- # Dispatch enter and leave events for <%= node.name %> nodes and continue
- # walking the tree.
- def visit_<%= node.human %>(node)
- listeners[:on_<%= node.human %>_enter]&.each { |listener| listener.on_<%= node.human %>_enter(node) }
- super
- listeners[:on_<%= node.human %>_leave]&.each { |listener| listener.on_<%= node.human %>_leave(node) }
- end
- <%- end -%>
-
- class DispatchOnce < Visitor # :nodoc:
- attr_reader :listeners
-
- def initialize(listeners)
- @listeners = listeners
- end
- <%- nodes.each do |node| -%>
-
- # Dispatch enter and leave events for <%= node.name %> nodes.
- def visit_<%= node.human %>(node)
- listeners[:on_<%= node.human %>_enter]&.each { |listener| listener.on_<%= node.human %>_enter(node) }
- listeners[:on_<%= node.human %>_leave]&.each { |listener| listener.on_<%= node.human %>_leave(node) }
- end
- <%- end -%>
- end
-
- private_constant :DispatchOnce
- end
-end
diff --git a/prism/templates/lib/prism/dot_visitor.rb.erb b/prism/templates/lib/prism/dot_visitor.rb.erb
deleted file mode 100644
index e9c81e4545..0000000000
--- a/prism/templates/lib/prism/dot_visitor.rb.erb
+++ /dev/null
@@ -1,188 +0,0 @@
-require "cgi"
-
-module Prism
- # This visitor provides the ability to call Node#to_dot, which converts a
- # subtree into a graphviz dot graph.
- class DotVisitor < Visitor
- class Field # :nodoc:
- attr_reader :name, :value, :port
-
- def initialize(name, value, port)
- @name = name
- @value = value
- @port = port
- end
-
- def to_dot
- if port
- "<tr><td align=\"left\" colspan=\"2\" port=\"#{name}\">#{name}</td></tr>"
- else
- "<tr><td align=\"left\">#{name}</td><td>#{CGI.escapeHTML(value || raise)}</td></tr>"
- end
- end
- end
-
- class Table # :nodoc:
- attr_reader :name, :fields
-
- def initialize(name)
- @name = name
- @fields = []
- end
-
- def field(name, value = nil, port: false)
- fields << Field.new(name, value, port)
- end
-
- def to_dot
- dot = <<~DOT
- <table border="0" cellborder="1" cellspacing="0" cellpadding="4">
- <tr><td colspan="2"><b>#{name}</b></td></tr>
- DOT
-
- if fields.any?
- "#{dot} #{fields.map(&:to_dot).join("\n ")}\n</table>"
- else
- "#{dot}</table>"
- end
- end
- end
-
- class Digraph # :nodoc:
- attr_reader :nodes, :waypoints, :edges
-
- def initialize
- @nodes = []
- @waypoints = []
- @edges = []
- end
-
- def node(value)
- nodes << value
- end
-
- def waypoint(value)
- waypoints << value
- end
-
- def edge(value)
- edges << value
- end
-
- def to_dot
- <<~DOT
- digraph "Prism" {
- node [
- fontname=\"Courier New\"
- shape=plain
- style=filled
- fillcolor=gray95
- ];
-
- #{nodes.map { |node| node.gsub(/\n/, "\n ") }.join("\n ")}
- node [shape=point];
- #{waypoints.join("\n ")}
-
- #{edges.join("\n ")}
- }
- DOT
- end
- end
-
- private_constant :Field, :Table, :Digraph
-
- # The digraph that is being built.
- attr_reader :digraph
-
- # Initialize a new dot visitor.
- def initialize
- @digraph = Digraph.new
- end
-
- # Convert this visitor into a graphviz dot graph string.
- def to_dot
- digraph.to_dot
- end
- <%- nodes.each do |node| -%>
-
- # Visit a <%= node.name %> node.
- def visit_<%= node.human %>(node)
- table = Table.new("<%= node.name %>")
- id = node_id(node)
- <%- if (node_flags = node.flags) -%>
-
- # flags
- table.field("flags", <%= node_flags.human %>_inspect(node))
- <%- end -%>
- <%- node.fields.each do |field| -%>
-
- # <%= field.name %>
- <%- case field -%>
- <%- when Prism::Template::NodeField -%>
- table.field("<%= field.name %>", port: true)
- digraph.edge("#{id}:<%= field.name %> -> #{node_id(node.<%= field.name %>)};")
- <%- when Prism::Template::OptionalNodeField -%>
- unless (<%= field.name %> = node.<%= field.name %>).nil?
- table.field("<%= field.name %>", port: true)
- digraph.edge("#{id}:<%= field.name %> -> #{node_id(<%= field.name %>)};")
- end
- <%- when Prism::Template::NodeListField -%>
- if node.<%= field.name %>.any?
- table.field("<%= field.name %>", port: true)
-
- waypoint = "#{id}_<%= field.name %>"
- digraph.waypoint("#{waypoint};")
-
- digraph.edge("#{id}:<%= field.name %> -> #{waypoint};")
- node.<%= field.name %>.each { |child| digraph.edge("#{waypoint} -> #{node_id(child)};") }
- else
- table.field("<%= field.name %>", "[]")
- end
- <%- when Prism::Template::StringField, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantListField, Prism::Template::IntegerField, Prism::Template::DoubleField -%>
- table.field("<%= field.name %>", node.<%= field.name %>.inspect)
- <%- when Prism::Template::LocationField -%>
- table.field("<%= field.name %>", location_inspect(node.<%= field.name %>))
- <%- when Prism::Template::OptionalLocationField -%>
- unless (<%= field.name %> = node.<%= field.name %>).nil?
- table.field("<%= field.name %>", location_inspect(<%= field.name %>))
- end
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- <%- end -%>
-
- digraph.nodes << <<~DOT
- #{id} [
- label=<#{table.to_dot.gsub(/\n/, "\n ")}>
- ];
- DOT
-
- super
- end
- <%- end -%>
-
- private
-
- # Generate a unique node ID for a node throughout the digraph.
- def node_id(node)
- "Node_#{node.object_id}"
- end
-
- # Inspect a location to display the start and end line and column numbers.
- def location_inspect(location)
- "(#{location.start_line},#{location.start_column})-(#{location.end_line},#{location.end_column})"
- end
- <%- flags.each do |flag| -%>
-
- # Inspect a node that has <%= flag.human %> flags to display the flags as a
- # comma-separated list.
- def <%= flag.human %>_inspect(node)
- flags = [] #: Array[String]
- <%- flag.values.each do |value| -%>
- flags << "<%= value.name.downcase %>" if node.<%= value.name.downcase %>?
- <%- end -%>
- flags.join(", ")
- end
- <%- end -%>
- end
-end
diff --git a/prism/templates/lib/prism/dsl.rb.erb b/prism/templates/lib/prism/dsl.rb.erb
deleted file mode 100644
index e16ebb7110..0000000000
--- a/prism/templates/lib/prism/dsl.rb.erb
+++ /dev/null
@@ -1,133 +0,0 @@
-module Prism
- # The DSL module provides a set of methods that can be used to create prism
- # nodes in a more concise manner. For example, instead of writing:
- #
- # source = Prism::Source.for("[1]")
- #
- # Prism::ArrayNode.new(
- # source,
- # 0,
- # Prism::Location.new(source, 0, 3),
- # 0,
- # [
- # Prism::IntegerNode.new(
- # source,
- # 0,
- # Prism::Location.new(source, 1, 1),
- # Prism::IntegerBaseFlags::DECIMAL,
- # 1
- # )
- # ],
- # Prism::Location.new(source, 0, 1),
- # Prism::Location.new(source, 2, 1)
- # )
- #
- # you could instead write:
- #
- # class Builder
- # include Prism::DSL
- #
- # attr_reader :default_source
- #
- # def initialize
- # @default_source = source("[1]")
- # end
- #
- # def build
- # array_node(
- # location: location(start_offset: 0, length: 3),
- # elements: [
- # integer_node(
- # location: location(start_offset: 1, length: 1),
- # flags: integer_base_flag(:decimal),
- # value: 1
- # )
- # ],
- # opening_loc: location(start_offset: 0, length: 1),
- # closing_loc: location(start_offset: 2, length: 1)
- # )
- # end
- # end
- #
- # This is mostly helpful in the context of generating trees programmatically.
- module DSL
- # Provide all of these methods as module methods as well, to allow for
- # building nodes like Prism::DSL.nil_node.
- extend self
-
- # Create a new Source object.
- def source(string)
- Source.for(string)
- end
-
- # Create a new Location object.
- def location(source: default_source, start_offset: 0, length: 0)
- Location.new(source, start_offset, length)
- end
- <%- nodes.each do |node| -%>
-
- # Create a new <%= node.name %> node.
- def <%= node.human %>(<%= ["source: default_source", "node_id: 0", "location: default_location", "flags: 0", *node.fields.map { |field|
- case field
- when Prism::Template::NodeField
- kind = field.specific_kind || field.union_kind&.first
- if kind.nil?
- "#{field.name}: default_node(source, location)"
- else
- "#{field.name}: #{kind.gsub(/(?<=.)[A-Z]/, "_\\0").downcase}(source: source)"
- end
- when Prism::Template::ConstantField
- "#{field.name}: :\"\""
- when Prism::Template::OptionalNodeField, Prism::Template::OptionalConstantField, Prism::Template::OptionalLocationField
- "#{field.name}: nil"
- when Prism::Template::NodeListField, Prism::Template::ConstantListField
- "#{field.name}: []"
- when Prism::Template::StringField
- "#{field.name}: \"\""
- when Prism::Template::LocationField
- "#{field.name}: location"
- when Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::IntegerField
- "#{field.name}: 0"
- when Prism::Template::DoubleField
- "#{field.name}: 0.0"
- else
- raise
- end
- }].join(", ") %>)
- <%= node.name %>.new(<%= ["source", "node_id", "location", "flags", *node.fields.map(&:name)].join(", ") %>)
- end
- <%- end -%>
- <%- flags.each do |flag| -%>
-
- # Retrieve the value of one of the <%= flag.name %> flags.
- def <%= flag.human.chomp("s") %>(name)
- case name
- <%- flag.values.each do |value| -%>
- when :<%= value.name.downcase %> then <%= flag.name %>::<%= value.name %>
- <%- end -%>
- else Kernel.raise ArgumentError, "invalid <%= flag.name %> flag: #{name.inspect}"
- end
- end
- <%- end -%>
-
- private
-
- # The default source object that gets attached to nodes and locations if no
- # source is specified.
- def default_source
- Source.for("")
- end
-
- # The default location object that gets attached to nodes if no location is
- # specified, which uses the given source.
- def default_location
- Location.new(default_source, 0, 0)
- end
-
- # The default node that gets attached to nodes if no node is specified for a
- # required node field.
- def default_node(source, location)
- MissingNode.new(source, -1, location, 0)
- end
- end
-end
diff --git a/prism/templates/lib/prism/inspect_visitor.rb.erb b/prism/templates/lib/prism/inspect_visitor.rb.erb
deleted file mode 100644
index 3cfe615d85..0000000000
--- a/prism/templates/lib/prism/inspect_visitor.rb.erb
+++ /dev/null
@@ -1,131 +0,0 @@
-module Prism
- # This visitor is responsible for composing the strings that get returned by
- # the various #inspect methods defined on each of the nodes.
- class InspectVisitor < Visitor
- # Most of the time, we can simply pass down the indent to the next node.
- # However, when we are inside a list we want some extra special formatting
- # when we hit an element in that list. In this case, we have a special
- # command that replaces the subsequent indent with the given value.
- class Replace # :nodoc:
- attr_reader :value
-
- def initialize(value)
- @value = value
- end
- end
-
- private_constant :Replace
-
- # The current prefix string.
- attr_reader :indent
-
- # The list of commands that we need to execute in order to compose the
- # final string.
- attr_reader :commands
-
- # Initializes a new instance of the InspectVisitor.
- def initialize(indent = +"")
- @indent = indent
- @commands = []
- end
-
- # Compose an inspect string for the given node.
- def self.compose(node)
- visitor = new
- node.accept(visitor)
- visitor.compose
- end
-
- # Compose the final string.
- def compose
- buffer = +""
- replace = nil
-
- until commands.empty?
- # @type var command: String | node | Replace
- # @type var indent: String
- command, indent = *commands.shift
-
- case command
- when String
- buffer << (replace || indent)
- buffer << command
- replace = nil
- when Node
- visitor = InspectVisitor.new(indent)
- command.accept(visitor)
- @commands = [*visitor.commands, *@commands]
- when Replace
- replace = command.value
- else
- raise "Unknown command: #{command.inspect}"
- end
- end
-
- buffer
- end
- <%- nodes.each do |node| -%>
-
- # Inspect a <%= node.name %> node.
- def visit_<%= node.human %>(node)
- commands << [inspect_node(<%= node.name.inspect %>, node), indent]
- <%- (fields = [node.flags || Prism::Template::Flags.empty, *node.fields]).each_with_index do |field, index| -%>
- <%- pointer = index == fields.length - 1 ? "└── " : "├── " -%>
- <%- preadd = index == fields.length - 1 ? " " : "│ " -%>
- <%- case field -%>
- <%- when Prism::Template::Flags -%>
- flags = [("newline" if node.newline?), ("static_literal" if node.static_literal?), <%= field.values.map { |value| "(\"#{value.name.downcase}\" if node.#{value.name.downcase}?)" }.join(", ") %>].compact
- commands << ["<%= pointer %>flags: #{flags.empty? ? "∅" : flags.join(", ")}\n", indent]
- <%- when Prism::Template::NodeListField -%>
- commands << ["<%= pointer %><%= field.name %>: (length: #{(<%= field.name %> = node.<%= field.name %>).length})\n", indent]
- if <%= field.name %>.any?
- <%= field.name %>[0...-1].each do |child|
- commands << [Replace.new("#{indent}<%= preadd %>├── "), indent]
- commands << [child, "#{indent}<%= preadd %>│ "]
- end
- commands << [Replace.new("#{indent}<%= preadd %>└── "), indent]
- commands << [<%= field.name %>[-1], "#{indent}<%= preadd %> "]
- end
- <%- when Prism::Template::NodeField -%>
- commands << ["<%= pointer %><%= field.name %>:\n", indent]
- commands << [node.<%= field.name %>, "#{indent}<%= preadd %>"]
- <%- when Prism::Template::OptionalNodeField -%>
- if (<%= field.name %> = node.<%= field.name %>).nil?
- commands << ["<%= pointer %><%= field.name %>: ∅\n", indent]
- else
- commands << ["<%= pointer %><%= field.name %>:\n", indent]
- commands << [<%= field.name %>, "#{indent}<%= preadd %>"]
- end
- <%- when Prism::Template::ConstantField, Prism::Template::ConstantListField, Prism::Template::StringField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::IntegerField, Prism::Template::DoubleField -%>
- commands << ["<%= pointer %><%= field.name %>: #{node.<%= field.name %>.inspect}\n", indent]
- <%- when Prism::Template::OptionalConstantField -%>
- if (<%= field.name %> = node.<%= field.name %>).nil?
- commands << ["<%= pointer %><%= field.name %>: ∅\n", indent]
- else
- commands << ["<%= pointer %><%= field.name %>: #{<%= field.name %>.inspect}\n", indent]
- end
- <%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField -%>
- commands << ["<%= pointer %><%= field.name %>: #{inspect_location(node.<%= field.name %>)}\n", indent]
- <%- end -%>
- <%- end -%>
- end
- <%- end -%>
-
- private
-
- # Compose a header for the given node.
- def inspect_node(name, node)
- location = node.location
- "@ #{name} (location: (#{location.start_line},#{location.start_column})-(#{location.end_line},#{location.end_column}))\n"
- end
-
- # Compose a string representing the given inner location field.
- def inspect_location(location)
- if location
- "(#{location.start_line},#{location.start_column})-(#{location.end_line},#{location.end_column}) = #{location.slice.inspect}"
- else
- "∅"
- end
- end
- end
-end
diff --git a/prism/templates/lib/prism/mutation_compiler.rb.erb b/prism/templates/lib/prism/mutation_compiler.rb.erb
deleted file mode 100644
index 565ee4e315..0000000000
--- a/prism/templates/lib/prism/mutation_compiler.rb.erb
+++ /dev/null
@@ -1,19 +0,0 @@
-module Prism
- # This visitor walks through the tree and copies each node as it is being
- # visited. This is useful for consumers that want to mutate the tree, as you
- # can change subtrees in place without effecting the rest of the tree.
- class MutationCompiler < Compiler
- <%- nodes.each_with_index do |node, index| -%>
-<%= "\n" if index != 0 -%>
- # Copy a <%= node.name %> node
- def visit_<%= node.human %>(node)
- <%- fields = node.fields.select { |field| [Prism::Template::NodeField, Prism::Template::OptionalNodeField, Prism::Template::NodeListField].include?(field.class) } -%>
- <%- if fields.any? -%>
- node.copy(<%= fields.map { |field| "#{field.name}: #{field.is_a?(Prism::Template::NodeListField) ? "visit_all" : "visit"}(node.#{field.name})" }.join(", ") %>)
- <%- else -%>
- node.copy
- <%- end -%>
- end
- <%- end -%>
- end
-end
diff --git a/prism/templates/lib/prism/node.rb.erb b/prism/templates/lib/prism/node.rb.erb
deleted file mode 100644
index f033cdea9b..0000000000
--- a/prism/templates/lib/prism/node.rb.erb
+++ /dev/null
@@ -1,414 +0,0 @@
-module Prism
- # This represents a node in the tree. It is the parent class of all of the
- # various node types.
- class Node
- # A pointer to the source that this node was created from.
- attr_reader :source
- private :source
-
- # A unique identifier for this node. This is used in a very specific
- # use case where you want to keep around a reference to a node without
- # having to keep around the syntax tree in memory. This unique identifier
- # will be consistent across multiple parses of the same source code.
- attr_reader :node_id
-
- # A Location instance that represents the location of this node in the
- # source.
- def location
- location = @location
- return location if location.is_a?(Location)
- @location = Location.new(source, location >> 32, location & 0xFFFFFFFF)
- end
-
- # The start offset of the node in the source. This method is effectively a
- # delegate method to the location object.
- def start_offset
- location = @location
- location.is_a?(Location) ? location.start_offset : location >> 32
- end
-
- # The end offset of the node in the source. This method is effectively a
- # delegate method to the location object.
- def end_offset
- location = @location
- location.is_a?(Location) ? location.end_offset : ((location >> 32) + (location & 0xFFFFFFFF))
- end
-
- # Returns all of the lines of the source code associated with this node.
- def source_lines
- location.source_lines
- end
-
- # An alias for source_lines, used to mimic the API from
- # RubyVM::AbstractSyntaxTree to make it easier to migrate.
- alias script_lines source_lines
-
- # Slice the location of the node from the source.
- def slice
- location.slice
- end
-
- # Slice the location of the node from the source, starting at the beginning
- # of the line that the location starts on, ending at the end of the line
- # that the location ends on.
- def slice_lines
- location.slice_lines
- end
-
- # An bitset of flags for this node. There are certain flags that are common
- # for all nodes, and then some nodes have specific flags.
- attr_reader :flags
- protected :flags
-
- # Returns true if the node has the newline flag set.
- def newline?
- flags.anybits?(NodeFlags::NEWLINE)
- end
-
- # Returns true if the node has the static literal flag set.
- def static_literal?
- flags.anybits?(NodeFlags::STATIC_LITERAL)
- end
-
- # Similar to inspect, but respects the current level of indentation given by
- # the pretty print object.
- def pretty_print(q)
- q.seplist(inspect.chomp.each_line, -> { q.breakable }) do |line|
- q.text(line.chomp)
- end
- q.current_group.break
- end
-
- # Convert this node into a graphviz dot graph string.
- def to_dot
- # @type self: node
- DotVisitor.new.tap { |visitor| accept(visitor) }.to_dot
- end
-
- # Returns a list of nodes that are descendants of this node that contain the
- # given line and column. This is useful for locating a node that is selected
- # based on the line and column of the source code.
- #
- # Important to note is that the column given to this method should be in
- # bytes, as opposed to characters or code units.
- def tunnel(line, column)
- queue = [self] #: Array[Prism::node]
- result = []
-
- while (node = queue.shift)
- result << node
-
- node.compact_child_nodes.each do |child_node|
- child_location = child_node.location
-
- start_line = child_location.start_line
- end_line = child_location.end_line
-
- if start_line == end_line
- if line == start_line && column >= child_location.start_column && column < child_location.end_column
- queue << child_node
- break
- end
- elsif (line == start_line && column >= child_location.start_column) || (line == end_line && column < child_location.end_column)
- queue << child_node
- break
- elsif line > start_line && line < end_line
- queue << child_node
- break
- end
- end
- end
-
- result
- end
-
- # Returns the first node that matches the given block when visited in a
- # depth-first search. This is useful for finding a node that matches a
- # particular condition.
- #
- # node.breadth_first_search { |node| node.node_id == node_id }
- #
- def breadth_first_search(&block)
- queue = [self] #: Array[Prism::node]
-
- while (node = queue.shift)
- return node if yield node
- queue.concat(node.compact_child_nodes)
- end
-
- nil
- end
-
- # Returns a list of the fields that exist for this node class. Fields
- # describe the structure of the node. This kind of reflection is useful for
- # things like recursively visiting each node _and_ field in the tree.
- def self.fields
- # This method should only be called on subclasses of Node, not Node
- # itself.
- raise NoMethodError, "undefined method `fields' for #{inspect}" if self == Node
-
- Reflection.fields_for(self)
- end
-
- # --------------------------------------------------------------------------
- # :section: Node interface
- # These methods are effectively abstract methods that must be implemented by
- # the various subclasses of Node. They are here to make it easier to work
- # with typecheckers.
- # --------------------------------------------------------------------------
-
- # Accepts a visitor and calls back into the specialized visit function.
- def accept(visitor)
- raise NoMethodError, "undefined method `accept' for #{inspect}"
- end
-
- # Returns an array of child nodes, including `nil`s in the place of optional
- # nodes that were not present.
- def child_nodes
- raise NoMethodError, "undefined method `child_nodes' for #{inspect}"
- end
-
- alias deconstruct child_nodes
-
- # Returns an array of child nodes, excluding any `nil`s in the place of
- # optional nodes that were not present.
- def compact_child_nodes
- raise NoMethodError, "undefined method `compact_child_nodes' for #{inspect}"
- end
-
- # Returns an array of child nodes and locations that could potentially have
- # comments attached to them.
- def comment_targets
- raise NoMethodError, "undefined method `comment_targets' for #{inspect}"
- end
-
- # Returns a string representation of the node.
- def inspect
- raise NoMethodError, "undefined method `inspect' for #{inspect}"
- end
-
- # Sometimes you want to check an instance of a node against a list of
- # classes to see what kind of behavior to perform. Usually this is done by
- # calling `[cls1, cls2].include?(node.class)` or putting the node into a
- # case statement and doing `case node; when cls1; when cls2; end`. Both of
- # these approaches are relatively slow because of the constant lookups,
- # method calls, and/or array allocations.
- #
- # Instead, you can call #type, which will return to you a symbol that you
- # can use for comparison. This is faster than the other approaches because
- # it uses a single integer comparison, but also because if you're on CRuby
- # you can take advantage of the fact that case statements with all symbol
- # keys will use a jump table.
- def type
- raise NoMethodError, "undefined method `type' for #{inspect}"
- end
-
- # Similar to #type, this method returns a symbol that you can use for
- # splitting on the type of the node without having to do a long === chain.
- # Note that like #type, it will still be slower than using == for a single
- # class, but should be faster in a case statement or an array comparison.
- def self.type
- raise NoMethodError, "undefined method `type' for #{inspect}"
- end
- end
- <%- nodes.each do |node| -%>
-
- <%- node.each_comment_line do |line| -%>
- #<%= line %>
- <%- end -%>
- class <%= node.name -%> < Node
- # Initialize a new <%= node.name %> node.
- def initialize(<%= ["source", "node_id", "location", "flags", *node.fields.map(&:name)].join(", ") %>)
- @source = source
- @node_id = node_id
- @location = location
- @flags = flags
- <%- node.fields.each do |field| -%>
- <%- if Prism::Template::CHECK_FIELD_KIND && field.respond_to?(:check_field_kind) -%>
- raise "<%= node.name %>#<%= field.name %> was of unexpected type:\n#{<%= field.name %>.inspect}" unless <%= field.check_field_kind %>
- <%- end -%>
- @<%= field.name %> = <%= field.name %>
- <%- end -%>
- end
-
- # def accept: (Visitor visitor) -> void
- def accept(visitor)
- visitor.visit_<%= node.human %>(self)
- end
-
- # def child_nodes: () -> Array[nil | Node]
- def child_nodes
- [<%= node.fields.map { |field|
- case field
- when Prism::Template::NodeField, Prism::Template::OptionalNodeField then field.name
- when Prism::Template::NodeListField then "*#{field.name}"
- end
- }.compact.join(", ") %>]
- end
-
- # def compact_child_nodes: () -> Array[Node]
- def compact_child_nodes
- <%- if node.fields.any? { |field| field.is_a?(Prism::Template::OptionalNodeField) } -%>
- compact = [] #: Array[Prism::node]
- <%- node.fields.each do |field| -%>
- <%- case field -%>
- <%- when Prism::Template::NodeField -%>
- compact << <%= field.name %>
- <%- when Prism::Template::OptionalNodeField -%>
- compact << <%= field.name %> if <%= field.name %>
- <%- when Prism::Template::NodeListField -%>
- compact.concat(<%= field.name %>)
- <%- end -%>
- <%- end -%>
- compact
- <%- else -%>
- [<%= node.fields.map { |field|
- case field
- when Prism::Template::NodeField then field.name
- when Prism::Template::NodeListField then "*#{field.name}"
- end
- }.compact.join(", ") %>]
- <%- end -%>
- end
-
- # def comment_targets: () -> Array[Node | Location]
- def comment_targets
- [<%= node.fields.map { |field|
- case field
- when Prism::Template::NodeField, Prism::Template::LocationField then field.name
- when Prism::Template::OptionalNodeField, Prism::Template::NodeListField, Prism::Template::OptionalLocationField then "*#{field.name}"
- end
- }.compact.join(", ") %>] #: Array[Prism::node | Location]
- end
-
- # def copy: (<%= (["?node_id: Integer", "?location: Location", "?flags: Integer"] + node.fields.map { |field| "?#{field.name}: #{field.rbs_class}" }).join(", ") %>) -> <%= node.name %>
- def copy(<%= (["node_id", "location", "flags"] + node.fields.map(&:name)).map { |field| "#{field}: self.#{field}" }.join(", ") %>)
- <%= node.name %>.new(<%= ["source", "node_id", "location", "flags", *node.fields.map(&:name)].join(", ") %>)
- end
-
- # def deconstruct: () -> Array[nil | Node]
- alias deconstruct child_nodes
-
- # def deconstruct_keys: (Array[Symbol] keys) -> { <%= (["node_id: Integer", "location: Location"] + node.fields.map { |field| "#{field.name}: #{field.rbs_class}" }).join(", ") %> }
- def deconstruct_keys(keys)
- { <%= (["node_id: node_id", "location: location"] + node.fields.map { |field| "#{field.name}: #{field.name}" }).join(", ") %> }
- end
- <%- if (node_flags = node.flags) -%>
- <%- node_flags.values.each do |value| -%>
-
- # def <%= value.name.downcase %>?: () -> bool
- def <%= value.name.downcase %>?
- flags.anybits?(<%= node_flags.name %>::<%= value.name %>)
- end
- <%- end -%>
- <%- end -%>
- <%- node.fields.each do |field| -%>
-
- <%- if field.comment.nil? -%>
- # attr_reader <%= field.name %>: <%= field.rbs_class %>
- <%- else -%>
- <%- field.each_comment_line do |line| -%>
- #<%= line %>
- <%- end -%>
- <%- end -%>
- <%- case field -%>
- <%- when Prism::Template::LocationField -%>
- def <%= field.name %>
- location = @<%= field.name %>
- return location if location.is_a?(Location)
- @<%= field.name %> = Location.new(source, location >> 32, location & 0xFFFFFFFF)
- end
- <%- when Prism::Template::OptionalLocationField -%>
- def <%= field.name %>
- location = @<%= field.name %>
- case location
- when nil
- nil
- when Location
- location
- else
- @<%= field.name %> = Location.new(source, location >> 32, location & 0xFFFFFFFF)
- end
- end
- <%- else -%>
- attr_reader :<%= field.name %>
- <%- end -%>
- <%- end -%>
- <%- node.fields.each do |field| -%>
- <%- case field -%>
- <%- when Prism::Template::LocationField -%>
- <%- raise unless field.name.end_with?("_loc") -%>
- <%- next if node.fields.any? { |other| other.name == field.name.delete_suffix("_loc") } -%>
-
- # def <%= field.name.delete_suffix("_loc") %>: () -> String
- def <%= field.name.delete_suffix("_loc") %>
- <%= field.name %>.slice
- end
- <%- when Prism::Template::OptionalLocationField -%>
- <%- raise unless field.name.end_with?("_loc") -%>
- <%- next if node.fields.any? { |other| other.name == field.name.delete_suffix("_loc") } -%>
-
- # def <%= field.name.delete_suffix("_loc") %>: () -> String?
- def <%= field.name.delete_suffix("_loc") %>
- <%= field.name %>&.slice
- end
- <%- end -%>
- <%- end -%>
-
- # def inspect -> String
- def inspect
- InspectVisitor.compose(self)
- end
-
- # Return a symbol representation of this node type. See `Node#type`.
- def type
- :<%= node.human %>
- end
-
- # Return a symbol representation of this node type. See `Node::type`.
- def self.type
- :<%= node.human %>
- end
-
- # Implements case-equality for the node. This is effectively == but without
- # comparing the value of locations. Locations are checked only for presence.
- def ===(other)
- other.is_a?(<%= node.name %>)<%= " &&" if (fields = [*node.flags, *node.fields]).any? %>
- <%- fields.each_with_index do |field, index| -%>
- <%- if field.is_a?(Prism::Template::LocationField) || field.is_a?(Prism::Template::OptionalLocationField) -%>
- (<%= field.name %>.nil? == other.<%= field.name %>.nil?)<%= " &&" if index != fields.length - 1 %>
- <%- elsif field.is_a?(Prism::Template::NodeListField) || field.is_a?(Prism::Template::ConstantListField) -%>
- (<%= field.name %>.length == other.<%= field.name %>.length) &&
- <%= field.name %>.zip(other.<%= field.name %>).all? { |left, right| left === right }<%= " &&" if index != fields.length - 1 %>
- <%- elsif field.is_a?(Prism::Template::Flags) -%>
- (flags === other.flags)<%= " &&" if index != fields.length - 1 %>
- <%- else -%>
- (<%= field.name %> === other.<%= field.name %>)<%= " &&" if index != fields.length - 1 %>
- <%- end -%>
- <%- end -%>
- end
- end
- <%- end -%>
- <%- flags.each do |flag| -%>
-
- # <%= flag.comment %>
- module <%= flag.name %>
- <%- flag.values.each_with_index do |value, index| -%>
- # <%= value.comment %>
- <%= value.name %> = 1 << <%= index + Prism::Template::COMMON_FLAGS_COUNT %>
-<%= "\n" if value != flag.values.last -%>
- <%- end -%>
- end
- <%- end -%>
-
- # The flags that are common to all nodes.
- module NodeFlags
- # A flag to indicate that the node is a candidate to emit a :line event
- # through tracepoint when compiled.
- NEWLINE = 1
-
- # A flag to indicate that the value that the node represents is a value that
- # can be determined at parse-time.
- STATIC_LITERAL = 2
- end
-end
diff --git a/prism/templates/lib/prism/reflection.rb.erb b/prism/templates/lib/prism/reflection.rb.erb
deleted file mode 100644
index 6c8b2f4d25..0000000000
--- a/prism/templates/lib/prism/reflection.rb.erb
+++ /dev/null
@@ -1,136 +0,0 @@
-module Prism
- # The Reflection module provides the ability to reflect on the structure of
- # the syntax tree itself, as opposed to looking at a single syntax tree. This
- # is useful in metaprogramming contexts.
- module Reflection
- # A field represents a single piece of data on a node. It is the base class
- # for all other field types.
- class Field
- # The name of the field.
- attr_reader :name
-
- # Initializes the field with the given name.
- def initialize(name)
- @name = name
- end
- end
-
- # A node field represents a single child node in the syntax tree. It
- # resolves to a Prism::Node in Ruby.
- class NodeField < Field
- end
-
- # An optional node field represents a single child node in the syntax tree
- # that may or may not be present. It resolves to either a Prism::Node or nil
- # in Ruby.
- class OptionalNodeField < Field
- end
-
- # A node list field represents a list of child nodes in the syntax tree. It
- # resolves to an array of Prism::Node instances in Ruby.
- class NodeListField < Field
- end
-
- # A constant field represents a constant value on a node. Effectively, it
- # represents an identifier found within the source. It resolves to a symbol
- # in Ruby.
- class ConstantField < Field
- end
-
- # An optional constant field represents a constant value on a node that may
- # or may not be present. It resolves to either a symbol or nil in Ruby.
- class OptionalConstantField < Field
- end
-
- # A constant list field represents a list of constant values on a node. It
- # resolves to an array of symbols in Ruby.
- class ConstantListField < Field
- end
-
- # A string field represents a string value on a node. It almost always
- # represents the unescaped value of a string-like literal. It resolves to a
- # string in Ruby.
- class StringField < Field
- end
-
- # A location field represents the location of some part of the node in the
- # source code. For example, the location of a keyword or an operator. It
- # resolves to a Prism::Location in Ruby.
- class LocationField < Field
- end
-
- # An optional location field represents the location of some part of the
- # node in the source code that may or may not be present. It resolves to
- # either a Prism::Location or nil in Ruby.
- class OptionalLocationField < Field
- end
-
- # An integer field represents an integer value. It is used to represent the
- # value of an integer literal, the depth of local variables, and the number
- # of a numbered reference. It resolves to an Integer in Ruby.
- class IntegerField < Field
- end
-
- # A float field represents a double-precision floating point value. It is
- # used exclusively to represent the value of a floating point literal. It
- # resolves to a Float in Ruby.
- class FloatField < Field
- end
-
- # A flags field represents a bitset of flags on a node. It resolves to an
- # integer in Ruby. Note that the flags cannot be accessed directly on the
- # node because the integer is kept private. Instead, the various flags in
- # the bitset should be accessed through their query methods.
- class FlagsField < Field
- # The names of the flags in the bitset.
- attr_reader :flags
-
- # Initializes the flags field with the given name and flags.
- def initialize(name, flags)
- super(name)
- @flags = flags
- end
- end
-
- # Returns the fields for the given node.
- def self.fields_for(node)
- case node.type
- <%- nodes.each do |node| -%>
- when :<%= node.human %>
- [<%= [*node.flags, *node.fields].map { |field|
- case field
- when Prism::Template::NodeField
- "NodeField.new(:#{field.name})"
- when Prism::Template::OptionalNodeField
- "OptionalNodeField.new(:#{field.name})"
- when Prism::Template::NodeListField
- "NodeListField.new(:#{field.name})"
- when Prism::Template::ConstantField
- "ConstantField.new(:#{field.name})"
- when Prism::Template::OptionalConstantField
- "OptionalConstantField.new(:#{field.name})"
- when Prism::Template::ConstantListField
- "ConstantListField.new(:#{field.name})"
- when Prism::Template::StringField
- "StringField.new(:#{field.name})"
- when Prism::Template::LocationField
- "LocationField.new(:#{field.name})"
- when Prism::Template::OptionalLocationField
- "OptionalLocationField.new(:#{field.name})"
- when Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::IntegerField
- "IntegerField.new(:#{field.name})"
- when Prism::Template::DoubleField
- "FloatField.new(:#{field.name})"
- when Prism::Template::Flags
- "FlagsField.new(:flags, [#{field.values.map { |value| ":#{value.name.downcase}?" }.join(", ")}])"
- else
- raise field.class.name
- end
- }.join(", ") %>]
- <%- end -%>
- else
- raise "Unknown node type: #{node.type.inspect}"
- end
- end
- end
-end
diff --git a/prism/templates/lib/prism/serialize.rb.erb b/prism/templates/lib/prism/serialize.rb.erb
deleted file mode 100644
index 62108ec28a..0000000000
--- a/prism/templates/lib/prism/serialize.rb.erb
+++ /dev/null
@@ -1,404 +0,0 @@
-require "stringio"
-require_relative "polyfill/unpack1"
-
-module Prism
- # A module responsible for deserializing parse results.
- module Serialize
- # The major version of prism that we are expecting to find in the serialized
- # strings.
- MAJOR_VERSION = 1
-
- # The minor version of prism that we are expecting to find in the serialized
- # strings.
- MINOR_VERSION = 0
-
- # The patch version of prism that we are expecting to find in the serialized
- # strings.
- PATCH_VERSION = 0
-
- # Deserialize the AST represented by the given string into a parse result.
- def self.load(input, serialized)
- input = input.dup
- source = Source.for(input)
- loader = Loader.new(source, serialized)
- result = loader.load_result
-
- input.force_encoding(loader.encoding)
- result
- end
-
- # Deserialize the tokens represented by the given string into a parse
- # result.
- def self.load_tokens(source, serialized)
- Loader.new(source, serialized).load_tokens_result
- end
-
- class Loader # :nodoc:
- if RUBY_ENGINE == "truffleruby"
- # StringIO is synchronized and that adds a high overhead on TruffleRuby.
- class FastStringIO # :nodoc:
- attr_accessor :pos
-
- def initialize(string)
- @string = string
- @pos = 0
- end
-
- def getbyte
- byte = @string.getbyte(@pos)
- @pos += 1
- byte
- end
-
- def read(n)
- slice = @string.byteslice(@pos, n)
- @pos += n
- slice
- end
-
- def eof?
- @pos >= @string.bytesize
- end
- end
- else
- FastStringIO = ::StringIO
- end
- private_constant :FastStringIO
-
- attr_reader :encoding, :input, :serialized, :io
- attr_reader :constant_pool_offset, :constant_pool, :source
- attr_reader :start_line
-
- def initialize(source, serialized)
- @encoding = Encoding::UTF_8
-
- @input = source.source.dup
- raise unless serialized.encoding == Encoding::BINARY
- @serialized = serialized
- @io = FastStringIO.new(serialized)
-
- @constant_pool_offset = nil
- @constant_pool = nil
-
- @source = source
- define_load_node_lambdas unless RUBY_ENGINE == "ruby"
- end
-
- def load_header
- raise "Invalid serialization" if io.read(5) != "PRISM"
- raise "Invalid serialization" if io.read(3).unpack("C3") != [MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION]
- only_semantic_fields = io.getbyte
- unless only_semantic_fields == 0
- raise "Invalid serialization (location fields must be included but are not)"
- end
- end
-
- def load_encoding
- @encoding = Encoding.find(io.read(load_varuint))
- @input = input.force_encoding(@encoding).freeze
- @encoding
- end
-
- def load_start_line
- source.instance_variable_set :@start_line, load_varsint
- end
-
- def load_line_offsets
- source.instance_variable_set :@offsets, Array.new(load_varuint) { load_varuint }
- end
-
- def load_comments
- Array.new(load_varuint) do
- case load_varuint
- when 0 then InlineComment.new(load_location_object)
- when 1 then EmbDocComment.new(load_location_object)
- end
- end
- end
-
- DIAGNOSTIC_TYPES = [
- <%- errors.each do |error| -%>
- <%= error.name.downcase.to_sym.inspect %>,
- <%- end -%>
- <%- warnings.each do |warning| -%>
- <%= warning.name.downcase.to_sym.inspect %>,
- <%- end -%>
- ].freeze
-
- private_constant :DIAGNOSTIC_TYPES
-
- def load_metadata
- comments = load_comments
- magic_comments = Array.new(load_varuint) { MagicComment.new(load_location_object, load_location_object) }
- data_loc = load_optional_location_object
- errors = Array.new(load_varuint) { ParseError.new(DIAGNOSTIC_TYPES.fetch(load_varuint), load_embedded_string, load_location_object, load_error_level) }
- warnings = Array.new(load_varuint) { ParseWarning.new(DIAGNOSTIC_TYPES.fetch(load_varuint), load_embedded_string, load_location_object, load_warning_level) }
- [comments, magic_comments, data_loc, errors, warnings]
- end
-
- def load_tokens
- tokens = []
- while type = TOKEN_TYPES.fetch(load_varuint)
- start = load_varuint
- length = load_varuint
- lex_state = load_varuint
- location = Location.new(@source, start, length)
- tokens << [Token.new(source, type, location.slice, location), lex_state]
- end
-
- tokens
- end
-
- def load_tokens_result
- tokens = load_tokens
- encoding = load_encoding
- load_start_line
- load_line_offsets
- comments, magic_comments, data_loc, errors, warnings = load_metadata
- tokens.each { |token,| token.value.force_encoding(encoding) }
-
- raise "Expected to consume all bytes while deserializing" unless @io.eof?
- LexResult.new(tokens, comments, magic_comments, data_loc, errors, warnings, @source)
- end
-
- def load_nodes
- load_header
- load_encoding
- load_start_line
- load_line_offsets
-
- comments, magic_comments, data_loc, errors, warnings = load_metadata
-
- @constant_pool_offset = load_uint32
- @constant_pool = Array.new(load_varuint, nil)
-
- [load_node, comments, magic_comments, data_loc, errors, warnings]
- end
-
- def load_result
- node, comments, magic_comments, data_loc, errors, warnings = load_nodes
- ParseResult.new(node, comments, magic_comments, data_loc, errors, warnings, @source)
- end
-
- private
-
- # variable-length integer using https://en.wikipedia.org/wiki/LEB128
- # This is also what protobuf uses: https://protobuf.dev/programming-guides/encoding/#varints
- def load_varuint
- n = io.getbyte
- if n < 128
- n
- else
- n -= 128
- shift = 0
- while (b = io.getbyte) >= 128
- n += (b - 128) << (shift += 7)
- end
- n + (b << (shift + 7))
- end
- end
-
- def load_varsint
- n = load_varuint
- (n >> 1) ^ (-(n & 1))
- end
-
- def load_integer
- negative = io.getbyte != 0
- length = load_varuint
-
- value = 0
- length.times { |index| value |= (load_varuint << (index * 32)) }
-
- value = -value if negative
- value
- end
-
- def load_double
- io.read(8).unpack1("D")
- end
-
- def load_uint32
- io.read(4).unpack1("L")
- end
-
- def load_optional_node
- if io.getbyte != 0
- io.pos -= 1
- load_node
- end
- end
-
- def load_embedded_string
- io.read(load_varuint).force_encoding(encoding)
- end
-
- def load_string
- type = io.getbyte
- case type
- when 1
- input.byteslice(load_varuint, load_varuint).force_encoding(encoding)
- when 2
- load_embedded_string
- else
- raise "Unknown serialized string type: #{type}"
- end
- end
-
- def load_location
- (load_varuint << 32) | load_varuint
- end
-
- def load_location_object
- Location.new(source, load_varuint, load_varuint)
- end
-
- def load_optional_location
- load_location if io.getbyte != 0
- end
-
- def load_optional_location_object
- load_location_object if io.getbyte != 0
- end
-
- def load_constant(index)
- constant = constant_pool[index]
-
- unless constant
- offset = constant_pool_offset + index * 8
- start = @serialized.unpack1("L", offset: offset)
- length = @serialized.unpack1("L", offset: offset + 4)
-
- constant =
- if start.nobits?(1 << 31)
- input.byteslice(start, length).force_encoding(@encoding).to_sym
- else
- @serialized.byteslice(start & ((1 << 31) - 1), length).force_encoding(@encoding).to_sym
- end
-
- constant_pool[index] = constant
- end
-
- constant
- end
-
- def load_required_constant
- load_constant(load_varuint - 1)
- end
-
- def load_optional_constant
- index = load_varuint
- load_constant(index - 1) if index != 0
- end
-
- def load_error_level
- level = io.getbyte
-
- case level
- when 0
- :syntax
- when 1
- :argument
- when 2
- :load
- else
- raise "Unknown level: #{level}"
- end
- end
-
- def load_warning_level
- level = io.getbyte
-
- case level
- when 0
- :default
- when 1
- :verbose
- else
- raise "Unknown level: #{level}"
- end
- end
-
- if RUBY_ENGINE == "ruby"
- def load_node
- type = io.getbyte
- node_id = load_varuint
- location = load_location
-
- case type
- <%- nodes.each_with_index do |node, index| -%>
- when <%= index + 1 %> then
- <%- if node.needs_serialized_length? -%>
- load_uint32
- <%- end -%>
- <%= node.name %>.new(<%= ["source", "node_id", "location", "load_varuint", *node.fields.map { |field|
- case field
- when Prism::Template::NodeField then "load_node"
- when Prism::Template::OptionalNodeField then "load_optional_node"
- when Prism::Template::StringField then "load_string"
- when Prism::Template::NodeListField then "Array.new(load_varuint) { load_node }"
- when Prism::Template::ConstantField then "load_required_constant"
- when Prism::Template::OptionalConstantField then "load_optional_constant"
- when Prism::Template::ConstantListField then "Array.new(load_varuint) { load_required_constant }"
- when Prism::Template::LocationField then "load_location"
- when Prism::Template::OptionalLocationField then "load_optional_location"
- when Prism::Template::UInt8Field then "io.getbyte"
- when Prism::Template::UInt32Field then "load_varuint"
- when Prism::Template::IntegerField then "load_integer"
- when Prism::Template::DoubleField then "load_double"
- else raise
- end
- }].join(", ") -%>)
- <%- end -%>
- end
- end
- else
- def load_node
- type = io.getbyte
- @load_node_lambdas[type].call
- end
-
- def define_load_node_lambdas
- @load_node_lambdas = [
- nil,
- <%- nodes.each do |node| -%>
- -> {
- node_id = load_varuint
- location = load_location
- <%- if node.needs_serialized_length? -%>
- load_uint32
- <%- end -%>
- <%= node.name %>.new(<%= ["source", "node_id", "location", "load_varuint", *node.fields.map { |field|
- case field
- when Prism::Template::NodeField then "load_node"
- when Prism::Template::OptionalNodeField then "load_optional_node"
- when Prism::Template::StringField then "load_string"
- when Prism::Template::NodeListField then "Array.new(load_varuint) { load_node }"
- when Prism::Template::ConstantField then "load_required_constant"
- when Prism::Template::OptionalConstantField then "load_optional_constant"
- when Prism::Template::ConstantListField then "Array.new(load_varuint) { load_required_constant }"
- when Prism::Template::LocationField then "load_location"
- when Prism::Template::OptionalLocationField then "load_optional_location"
- when Prism::Template::UInt8Field then "io.getbyte"
- when Prism::Template::UInt32Field then "load_varuint"
- when Prism::Template::IntegerField then "load_integer"
- when Prism::Template::DoubleField then "load_double"
- else raise
- end
- }].join(", ") -%>)
- },
- <%- end -%>
- ]
- end
- end
- end
-
- # The token types that can be indexed by their enum values.
- TOKEN_TYPES = [
- nil,
- <%- tokens.each do |token| -%>
- <%= token.name.to_sym.inspect %>,
- <%- end -%>
- ]
- end
-end
diff --git a/prism/templates/lib/prism/visitor.rb.erb b/prism/templates/lib/prism/visitor.rb.erb
deleted file mode 100644
index 4b30a1815b..0000000000
--- a/prism/templates/lib/prism/visitor.rb.erb
+++ /dev/null
@@ -1,53 +0,0 @@
-module Prism
- # A class that knows how to walk down the tree. None of the individual visit
- # methods are implemented on this visitor, so it forces the consumer to
- # implement each one that they need. For a default implementation that
- # continues walking the tree, see the Visitor class.
- class BasicVisitor
- # Calls `accept` on the given node if it is not `nil`, which in turn should
- # call back into this visitor by calling the appropriate `visit_*` method.
- def visit(node)
- # @type self: _Visitor
- node&.accept(self)
- end
-
- # Visits each node in `nodes` by calling `accept` on each one.
- def visit_all(nodes)
- # @type self: _Visitor
- nodes.each { |node| node&.accept(self) }
- end
-
- # Visits the child nodes of `node` by calling `accept` on each one.
- def visit_child_nodes(node)
- # @type self: _Visitor
- node.compact_child_nodes.each { |node| node.accept(self) }
- end
- end
-
- # A visitor is a class that provides a default implementation for every accept
- # method defined on the nodes. This means it can walk a tree without the
- # caller needing to define any special handling. This allows you to handle a
- # subset of the tree, while still walking the whole tree.
- #
- # For example, to find all of the method calls that call the `foo` method, you
- # could write:
- #
- # class FooCalls < Prism::Visitor
- # def visit_call_node(node)
- # if node.name == "foo"
- # # Do something with the node
- # end
- #
- # # Call super so that the visitor continues walking the tree
- # super
- # end
- # end
- #
- class Visitor < BasicVisitor
- <%- nodes.each_with_index do |node, index| -%>
-<%= "\n" if index != 0 -%>
- # Visit a <%= node.name %> node
- alias visit_<%= node.human %> visit_child_nodes
- <%- end -%>
- end
-end
diff --git a/prism/templates/src/diagnostic.c.erb b/prism/templates/src/diagnostic.c.erb
deleted file mode 100644
index d2b7b4f691..0000000000
--- a/prism/templates/src/diagnostic.c.erb
+++ /dev/null
@@ -1,520 +0,0 @@
-#include "prism/diagnostic.h"
-
-#define PM_DIAGNOSTIC_ID_MAX <%= errors.length + warnings.length %>
-
-/** This struct holds the data for each diagnostic. */
-typedef struct {
- /** The message associated with the diagnostic. */
- const char* message;
-
- /** The level associated with the diagnostic. */
- uint8_t level;
-} pm_diagnostic_data_t;
-
-/**
- * ## Message composition
- *
- * When composing an error message, use sentence fragments.
- *
- * Try describing the property of the code that caused the error, rather than
- * the rule that is being violated. It may help to use a fragment that completes
- * a sentence beginning, "the parser encountered (a) ...". If appropriate, add a
- * description of the rule violation (or other helpful context) after a
- * semicolon.
- *
- * For example:, instead of "control escape sequence cannot be doubled", prefer:
- *
- * > "invalid control escape sequence; control cannot be repeated"
- *
- * In some cases, where the failure is more general or syntax expectations are
- * violated, it may make more sense to use a fragment that completes a sentence
- * beginning, "the parser ...".
- *
- * For example:
- *
- * > "expected an expression after `(`"
- * > "cannot parse the expression"
- *
- * ## Message style guide
- *
- * - Use articles like "a", "an", and "the" when appropriate.
- * - e.g., prefer "cannot parse the expression" to "cannot parse expression".
- * - Use the common name for tokens and nodes.
- * - e.g., prefer "keyword splat" to "assoc splat"
- * - e.g., prefer "embedded document" to "embdoc"
- * - Do not capitalize the initial word of the message.
- * - Use back ticks around token literals
- * - e.g., "Expected a `=>` between the hash key and value"
- * - Do not use `.` or other punctuation at the end of the message.
- * - Do not use contractions like "can't". Prefer "cannot" to "can not".
- * - For tokens that can have multiple meanings, reference the token and its meaning.
- * - e.g., "`*` splat argument" is clearer and more complete than "splat argument" or "`*` argument"
- *
- * ## Error names (PM_ERR_*)
- *
- * - When appropriate, prefer node name to token name.
- * - e.g., prefer "SPLAT" to "STAR" in the context of argument parsing.
- * - Prefer token name to common name.
- * - e.g., prefer "STAR" to "ASTERISK".
- * - Try to order the words in the name from more general to more specific,
- * - e.g., "INVALID_NUMBER_DECIMAL" is better than "DECIMAL_INVALID_NUMBER".
- * - When in doubt, look for similar patterns and name them so that they are grouped when lexically
- * sorted. See PM_ERR_ARGUMENT_NO_FORWARDING_* for an example.
- *
- * ## Level
- *
- * For errors, they are:
- *
- * * `PM_ERROR_LEVEL_SYNTAX` - Errors that should raise SyntaxError.
- * * `PM_ERROR_LEVEL_ARGUMENT` - Errors that should raise ArgumentError.
- * * `PM_ERROR_LEVEL_LOAD` - Errors that should raise LoadError.
- *
- * For warnings, they are:
- *
- * * `PM_WARNING_LEVEL_DEFAULT` - Warnings that appear for `ruby -c -e 'code'`.
- * * `PM_WARNING_LEVEL_VERBOSE` - Warnings that appear with `-w`, as in `ruby -w -c -e 'code'`.
- */
-static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
- // Special error that can be replaced
- [PM_ERR_CANNOT_PARSE_EXPRESSION] = { "cannot parse the expression", PM_ERROR_LEVEL_SYNTAX },
-
- // Errors that should raise argument errors
- [PM_ERR_INVALID_ENCODING_MAGIC_COMMENT] = { "unknown or invalid encoding in the magic comment", PM_ERROR_LEVEL_ARGUMENT },
-
- // Errors that should raise load errors
- [PM_ERR_SCRIPT_NOT_FOUND] = { "no Ruby script found in input", PM_ERROR_LEVEL_LOAD },
-
- // Errors that should raise syntax errors
- [PM_ERR_ALIAS_ARGUMENT] = { "invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE] = { "invalid argument being passed to `alias`; can't make alias for the number variables", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_AMPAMPEQ_MULTI_ASSIGN] = { "unexpected `&&=` in a multiple assignment", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_AFTER_BLOCK] = { "unexpected argument after a block argument", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES] = { "unexpected argument after `...`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_BARE_HASH] = { "unexpected bare hash argument", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_BLOCK_MULTI] = { "both block arg and actual block given; only one block is allowed", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_CONFLICT_AMPERSAND] = { "unexpected `&`; anonymous block parameter is also used within block", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_CONFLICT_STAR] = { "unexpected `*`; anonymous rest parameter is also used within block", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_CONFLICT_STAR_STAR] = { "unexpected `**`; anonymous keyword rest parameter is also used within block", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_FORMAL_CLASS] = { "invalid formal argument; formal argument cannot be a class variable", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_FORMAL_CONSTANT] = { "invalid formal argument; formal argument cannot be a constant", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_FORMAL_GLOBAL] = { "invalid formal argument; formal argument cannot be a global variable", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_FORMAL_IVAR] = { "invalid formal argument; formal argument cannot be an instance variable", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_FORWARDING_UNBOUND] = { "unexpected `...` in an non-parenthesized call", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND] = { "unexpected `&`; no anonymous block parameter", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES] = { "unexpected ... when the parent method is not forwarding", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_NO_FORWARDING_STAR] = { "unexpected `*`; no anonymous rest parameter", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR] = { "unexpected `**`; no anonymous keyword rest parameter", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT] = { "unexpected `*` splat argument after a `**` keyword splat argument", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_SPLAT_AFTER_SPLAT] = { "unexpected `*` splat argument after a `*` splat argument", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_TERM_PAREN] = { "unexpected %s; expected a `)` to close the arguments", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_UNEXPECTED_BLOCK] = { "unexpected '{' after a method call without parenthesis", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARRAY_ELEMENT] = { "expected an element for the array", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARRAY_EXPRESSION] = { "expected an expression for the array element", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARRAY_EXPRESSION_AFTER_STAR] = { "expected an expression after `*` in the array", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARRAY_SEPARATOR] = { "unexpected %s; expected a `,` separator for the array elements", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARRAY_TERM] = { "unexpected %s; expected a `]` to close the array", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_BEGIN_LONELY_ELSE] = { "unexpected `else` in `begin` block; else without rescue is useless", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_BEGIN_TERM] = { "expected an `end` to close the `begin` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_BEGIN_UPCASE_BRACE] = { "expected a `{` after `BEGIN`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_BEGIN_UPCASE_TERM] = { "expected a `}` to close the `BEGIN` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_BEGIN_UPCASE_TOPLEVEL] = { "BEGIN is permitted only at toplevel", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE] = { "expected a local variable name in the block parameters", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_BLOCK_PARAM_PIPE_TERM] = { "expected the block parameters to end with `|`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_BLOCK_TERM_BRACE] = { "expected a block beginning with `{` to end with `}`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_BLOCK_TERM_END] = { "expected a block beginning with `do` to end with `end`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CANNOT_PARSE_STRING_PART] = { "cannot parse the string part", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CASE_EXPRESSION_AFTER_CASE] = { "expected an expression after `case`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CASE_EXPRESSION_AFTER_WHEN] = { "expected an expression after `when`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CASE_MATCH_MISSING_PREDICATE] = { "expected a predicate for a case matching statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CASE_MISSING_CONDITIONS] = { "expected a `when` or `in` clause after `case`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CASE_TERM] = { "expected an `end` to close the `case` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CLASS_IN_METHOD] = { "unexpected class definition in method body", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CLASS_NAME] = { "unexpected constant path after `class`; class/module name must be CONSTANT", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CLASS_SUPERCLASS] = { "expected a superclass after `<`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CLASS_TERM] = { "expected an `end` to close the `class` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CLASS_UNEXPECTED_END] = { "unexpected `end`, expecting ';' or '\\n'", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CLASS_VARIABLE_BARE] = { "'@@' without identifiers is not allowed as a class variable name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CONDITIONAL_ELSIF_PREDICATE] = { "expected a predicate expression for the `elsif` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CONDITIONAL_IF_PREDICATE] = { "expected a predicate expression for the `if` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CONDITIONAL_PREDICATE_TERM] = { "expected `then` or `;` or '\\n'", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CONDITIONAL_TERM] = { "expected an `end` to close the conditional clause", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CONDITIONAL_TERM_ELSE] = { "expected an `end` to close the `else` clause", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CONDITIONAL_UNLESS_PREDICATE] = { "expected a predicate expression for the `unless` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CONDITIONAL_UNTIL_PREDICATE] = { "expected a predicate expression for the `until` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CONDITIONAL_WHILE_PREDICATE] = { "expected a predicate expression for the `while` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT] = { "expected a constant after the `::` operator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_DEF_ENDLESS] = { "could not parse the endless method body", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_DEF_ENDLESS_SETTER] = { "invalid method name; a setter method cannot be defined in an endless method definition", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_DEF_NAME] = { "unexpected %s; expected a method name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_DEF_PARAMS_TERM] = { "expected a delimiter to close the parameters", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_DEF_PARAMS_TERM_PAREN] = { "unexpected %s; expected a `)` to close the parameters", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_DEF_RECEIVER] = { "expected a receiver for the method definition", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_DEF_RECEIVER_TERM] = { "expected a `.` or `::` after the receiver in a method definition", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_DEF_TERM] = { "expected an `end` to close the `def` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_DEFINED_EXPRESSION] = { "expected an expression after `defined?`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EMBDOC_TERM] = { "embedded document meets end of file", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EMBEXPR_END] = { "expected a `}` to close the embedded expression", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EMBVAR_INVALID] = { "invalid embedded variable", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_END_UPCASE_BRACE] = { "expected a `{` after `END`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_END_UPCASE_TERM] = { "expected a `}` to close the `END` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_CONTROL] = { "Invalid escape character syntax", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT] = { "invalid control escape sequence; control cannot be repeated", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_HEXADECIMAL] = { "invalid hex escape sequence", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_META] = { "Invalid escape character syntax", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_META_REPEAT] = { "invalid meta escape sequence; meta cannot be repeated", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_UNICODE] = { "invalid Unicode escape sequence", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_UNICODE_CM_FLAGS] = { "invalid Unicode escape sequence; Unicode cannot be combined with control or meta flags", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_UNICODE_LIST] = { "invalid Unicode list: %.*s", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL] = { "invalid Unicode escape sequence; Multiple codepoints at single character literal are disallowed", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_UNICODE_LONG] = { "invalid Unicode escape sequence; maximum length is 6 digits", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_UNICODE_SHORT] = { "too short escape sequence: %.*s", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ESCAPE_INVALID_UNICODE_TERM] = { "unterminated Unicode escape", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_ARGUMENT] = { "unexpected %s; expected an argument", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_EOL_AFTER_STATEMENT] = { "unexpected %s, expecting end-of-input", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ] = { "expected an expression after `&&=`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ] = { "expected an expression after `||=`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA] = { "expected an expression after `,`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL] = { "expected an expression after `=`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS] = { "expected an expression after `<<`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_EXPRESSION_AFTER_LPAREN] = { "expected an expression after `(`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR] = { "unexpected %s; expected an expression after the operator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT] = { "expected an expression after `*` splat in an argument", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH] = { "expected an expression after `**` in a hash", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_EXPRESSION_AFTER_STAR] = { "expected an expression after `*`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_FOR_DELIMITER] = { "unexpected %s; expected a 'do', newline, or ';' after the 'for' loop collection", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_IDENT_REQ_PARAMETER] = { "expected an identifier for the required parameter", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_IN_DELIMITER] = { "expected a delimiter after the patterns of an `in` clause", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_LPAREN_REQ_PARAMETER] = { "expected a `(` to start a required parameter", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_MESSAGE] = { "unexpected %s; expecting a message to send to the receiver", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_RBRACKET] = { "expected a matching `]`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_RPAREN] = { "expected a matching `)`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_RPAREN_AFTER_MULTI] = { "expected a `)` after multiple assignment", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_RPAREN_REQ_PARAMETER] = { "expected a `)` to end a required parameter", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER] = { "unexpected %s; expected a newline or a ';' after the singleton class", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_STRING_CONTENT] = { "expected string content after opening string delimiter", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPECT_WHEN_DELIMITER] = { "expected a delimiter after the predicates of a `when` clause", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPRESSION_BARE_HASH] = { "unexpected bare hash in expression", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPRESSION_NOT_WRITABLE] = { "unexpected '='; target cannot be written", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING] = { "Can't assign to __ENCODING__", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE] = { "Can't assign to false", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPRESSION_NOT_WRITABLE_FILE] = { "Can't assign to __FILE__", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPRESSION_NOT_WRITABLE_LINE] = { "Can't assign to __LINE__", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPRESSION_NOT_WRITABLE_NIL] = { "Can't assign to nil", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED] = { "Can't assign to numbered parameter %.2s", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPRESSION_NOT_WRITABLE_SELF] = { "Can't change the value of self", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE] = { "Can't assign to true", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_FLOAT_PARSE] = { "could not parse the float '%.*s'", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_FOR_COLLECTION] = { "expected a collection after the `in` in a `for` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_FOR_INDEX] = { "expected an index after `for`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_FOR_IN] = { "expected an `in` after the index in a `for` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_FOR_TERM] = { "expected an `end` to close the `for` loop", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_GLOBAL_VARIABLE_BARE] = { "'$' without identifiers is not allowed as a global variable name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_HASH_EXPRESSION_AFTER_LABEL] = { "expected an expression after the label in a hash", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_HASH_KEY] = { "unexpected %s, expecting '}' or a key in the hash literal", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_HASH_ROCKET] = { "expected a `=>` between the hash key and value", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_HASH_TERM] = { "expected a `}` to close the hash literal", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_HASH_VALUE] = { "unexpected %s; expected a value in the hash literal", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_HEREDOC_IDENTIFIER] = { "unterminated here document identifier", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_HEREDOC_TERM] = { "unterminated heredoc; can't find string \"%.*s\" anywhere before EOF", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INCOMPLETE_QUESTION_MARK] = { "incomplete expression at `?`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3] = { "`%.*s' is not allowed as a class variable name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INCOMPLETE_VARIABLE_CLASS] = { "'%.*s' is not allowed as a class variable name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3] = { "`%.*s' is not allowed as an instance variable name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INCOMPLETE_VARIABLE_INSTANCE] = { "'%.*s' is not allowed as an instance variable name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INSTANCE_VARIABLE_BARE] = { "'@' without identifiers is not allowed as an instance variable name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_BLOCK_EXIT] = { "Invalid %s", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_ESCAPE_CHARACTER] = { "Invalid escape character syntax", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_FLOAT_EXPONENT] = { "invalid exponent", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_LOCAL_VARIABLE_READ] = { "identifier %.*s is not valid to get", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_LOCAL_VARIABLE_WRITE] = { "identifier %.*s is not valid to set", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_NUMBER_BINARY] = { "invalid binary number; numeric literal without digits", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_NUMBER_DECIMAL] = { "invalid decimal number; numeric literal without digits", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_NUMBER_FRACTION] = { "unexpected fraction part after numeric literal", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_NUMBER_HEXADECIMAL] = { "invalid hexadecimal number; numeric literal without digits", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_NUMBER_OCTAL] = { "invalid octal number; numeric literal without digits", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER] = { "invalid underscore placement in number", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING] = { "trailing '_' in number", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_CHARACTER] = { "Invalid char '\\x%02X' in expression", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_MULTIBYTE_CHAR] = { "invalid multibyte char (%s)", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_MULTIBYTE_CHARACTER] = { "invalid multibyte character 0x%X", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_MULTIBYTE_ESCAPE] = { "invalid multibyte escape: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_PRINTABLE_CHARACTER] = { "invalid character `%c`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_PERCENT] = { "unknown type of %string", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_PERCENT_EOF] = { "unterminated quoted string meets end of file", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_RETRY_AFTER_ELSE] = { "Invalid retry after else", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_RETRY_AFTER_ENSURE] = { "Invalid retry after ensure", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_RETRY_WITHOUT_RESCUE] = { "Invalid retry without rescue", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_SYMBOL] = { "invalid symbol", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_VARIABLE_GLOBAL_3_3] = { "`%.*s' is not allowed as a global variable name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_VARIABLE_GLOBAL] = { "'%.*s' is not allowed as a global variable name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_INVALID_YIELD] = { "Invalid yield", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_IT_NOT_ALLOWED_NUMBERED] = { "`it` is not allowed when a numbered parameter is already used", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_IT_NOT_ALLOWED_ORDINARY] = { "`it` is not allowed when an ordinary parameter is defined", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LAMBDA_OPEN] = { "expected a `do` keyword or a `{` to open the lambda block", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LAMBDA_TERM_BRACE] = { "expected a lambda block beginning with `{` to end with `}`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LAMBDA_TERM_END] = { "expected a lambda block beginning with `do` to end with `end`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LIST_I_LOWER_ELEMENT] = { "expected a symbol in a `%i` list", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LIST_I_LOWER_TERM] = { "unterminated list; expected a closing delimiter for the `%i`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LIST_I_UPPER_ELEMENT] = { "expected a symbol in a `%I` list", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LIST_I_UPPER_TERM] = { "unterminated list; expected a closing delimiter for the `%I`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LIST_W_LOWER_ELEMENT] = { "expected a string in a `%w` list", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LIST_W_LOWER_TERM] = { "unterminated list; expected a closing delimiter for the `%w`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LIST_W_UPPER_ELEMENT] = { "expected a string in a `%W` list", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_LIST_W_UPPER_TERM] = { "unterminated list; expected a closing delimiter for the `%W`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_MALLOC_FAILED] = { "failed to allocate memory", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_MIXED_ENCODING] = { "UTF-8 mixed within %s source", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_MODULE_IN_METHOD] = { "unexpected module definition in method body", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_MODULE_NAME] = { "unexpected constant path after `module`; class/module name must be CONSTANT", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_MODULE_TERM] = { "expected an `end` to close the `module` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_MULTI_ASSIGN_MULTI_SPLATS] = { "multiple splats in multiple assignment", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST] = { "unexpected '%.*s' resulting in multiple splats in multiple assignment", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_NESTING_TOO_DEEP] = { "nesting too deep", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_NO_LOCAL_VARIABLE] = { "%.*s: no such local variable", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_NON_ASSOCIATIVE_OPERATOR] = { "unexpected %s; %s is a non-associative operator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_NOT_EXPRESSION] = { "expected an expression after `not`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_NUMBER_LITERAL_UNDERSCORE] = { "number literal ending with a `_`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK] = { "numbered parameter is already used in inner block", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_NUMBERED_PARAMETER_IT] = { "numbered parameters are not allowed when 'it' is already used", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_NUMBERED_PARAMETER_ORDINARY] = { "numbered parameters are not allowed when an ordinary parameter is defined", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK] = { "numbered parameter is already used in outer block", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_OPERATOR_MULTI_ASSIGN] = { "unexpected operator for a multiple assignment", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_OPERATOR_WRITE_ARGUMENTS] = { "unexpected operator after a call with arguments", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_OPERATOR_WRITE_BLOCK] = { "unexpected operator after a call with a block", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI] = { "unexpected multiple `**` splat parameters", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_BLOCK_MULTI] = { "multiple block parameters; only one block is allowed", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_CIRCULAR] = { "circular argument reference - %.*s", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_FORWARDING_AFTER_REST] = { "... after rest argument", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_METHOD_NAME] = { "unexpected name for a parameter", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_NAME_DUPLICATED] = { "duplicated argument name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_NO_DEFAULT] = { "expected a default value for the parameter", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_NO_DEFAULT_KW] = { "expected a default value for the keyword parameter", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_NUMBERED_RESERVED] = { "%.2s is reserved for numbered parameters", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_ORDER] = { "unexpected parameter order", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_SPLAT_MULTI] = { "unexpected multiple `*` splat parameters", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_STAR] = { "unexpected parameter `*`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_UNEXPECTED_FWD] = { "unexpected `...` in parameters", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_WILD_LOOSE_COMMA] = { "unexpected `,` in parameters", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PARAMETER_UNEXPECTED_NO_KW] = { "unexpected **nil; no keywords marker disallowed after keywords", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS] = { "unexpected multiple '*' rest patterns in an array pattern", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_CAPTURE_DUPLICATE] = { "duplicated variable name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET] = { "expected a pattern expression after the `[` operator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA] = { "expected a pattern expression after `,`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET] = { "expected a pattern expression after `=>`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_EXPRESSION_AFTER_IN] = { "expected a pattern expression after the `in` keyword", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_EXPRESSION_AFTER_KEY] = { "expected a pattern expression after the key", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN] = { "expected a pattern expression after the `(` operator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_EXPRESSION_AFTER_PIN] = { "expected a pattern expression after the `^` pin operator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE] = { "expected a pattern expression after the `|` operator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE] = { "expected a pattern expression after the range operator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_EXPRESSION_AFTER_REST] = { "unexpected pattern expression after the `**` expression", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_FIND_MISSING_INNER] = { "find patterns need at least one required inner pattern", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_HASH_IMPLICIT] = { "unexpected implicit hash in pattern; use '{' to delineate", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_HASH_KEY] = { "unexpected %s; expected a key in the hash pattern", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_HASH_KEY_DUPLICATE] = { "duplicated key name", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_HASH_KEY_INTERPOLATED] = { "symbol literal with interpolation is not allowed", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_HASH_KEY_LABEL] = { "expected a label as the key in the hash pattern", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_HASH_KEY_LOCALS] = { "key must be valid as local variables", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_IDENT_AFTER_HROCKET] = { "expected an identifier after the `=>` operator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_LABEL_AFTER_COMMA] = { "expected a label after the `,` in the hash pattern", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_REST] = { "unexpected rest pattern", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_TERM_BRACE] = { "expected a `}` to close the pattern expression", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_TERM_BRACKET] = { "expected a `]` to close the pattern expression", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PATTERN_TERM_PAREN] = { "expected a `)` to close the pattern expression", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN] = { "unexpected `||=` in a multiple assignment", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH] = { "regexp encoding option '%c' differs from source encoding '%s'", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING] = { "incompatible character encoding: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_REGEXP_NON_ESCAPED_MBC] = { "/.../n has a non escaped non ASCII character in non ASCII-8BIT script: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_REGEXP_INVALID_UNICODE_RANGE] = { "invalid Unicode range: /%.*s/", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_REGEXP_PARSE_ERROR] = { "%s", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_REGEXP_UNKNOWN_OPTIONS] = { "unknown regexp %s - %.*s", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_REGEXP_TERM] = { "unterminated regexp meets end of file; expected a closing delimiter", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_REGEXP_UTF8_CHAR_NON_UTF8_REGEXP] = { "UTF-8 character in non UTF-8 regexp: /%s/", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_RESCUE_EXPRESSION] = { "expected a rescued expression", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_RESCUE_MODIFIER_VALUE] = { "expected a value after the `rescue` modifier", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_RESCUE_TERM] = { "expected a closing delimiter for the `rescue` clause", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_RESCUE_VARIABLE] = { "expected an exception variable after `=>` in a rescue statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_RETURN_INVALID] = { "Invalid return in class/module body", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_SINGLETON_FOR_LITERALS] = { "cannot define singleton method for literals", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_STATEMENT_ALIAS] = { "unexpected an `alias` at a non-statement position", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_STATEMENT_POSTEXE_END] = { "unexpected an `END` at a non-statement position", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_STATEMENT_PREEXE_BEGIN] = { "unexpected a `BEGIN` at a non-statement position", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_STATEMENT_UNDEF] = { "unexpected an `undef` at a non-statement position", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_STRING_CONCATENATION] = { "expected a string for concatenation", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_STRING_INTERPOLATED_TERM] = { "unterminated string; expected a closing delimiter for the interpolated string", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_STRING_LITERAL_EOF] = { "unterminated string meets end of file", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_STRING_LITERAL_TERM] = { "unexpected %s, expected a string literal terminator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_SYMBOL_INVALID] = { "invalid symbol", PM_ERROR_LEVEL_SYNTAX }, // TODO expected symbol? prism.c ~9719
- [PM_ERR_SYMBOL_TERM_DYNAMIC] = { "unterminated quoted string; expected a closing delimiter for the dynamic symbol", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_SYMBOL_TERM_INTERPOLATED] = { "unterminated symbol; expected a closing delimiter for the interpolated symbol", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_TERNARY_COLON] = { "expected a `:` after the true expression of a ternary operator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_TERNARY_EXPRESSION_FALSE] = { "expected an expression after `:` in the ternary operator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_TERNARY_EXPRESSION_TRUE] = { "expected an expression after `?` in the ternary operator", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_UNARY_RECEIVER] = { "unexpected %s, expected a receiver for unary `%c`", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_UNARY_DISALLOWED] = { "unexpected %s; unary calls are not allowed in this context", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_UNDEF_ARGUMENT] = { "invalid argument being passed to `undef`; expected a bare word, constant, or symbol argument", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_UNEXPECTED_BLOCK_ARGUMENT] = { "block argument should not be given", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_UNEXPECTED_INDEX_BLOCK] = { "unexpected block arg given in index assignment; blocks are not allowed in index assignment expressions", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_UNEXPECTED_INDEX_KEYWORDS] = { "unexpected keyword arg given in index assignment; keywords are not allowed in index assignment expressions", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_UNEXPECTED_LABEL] = { "unexpected label", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_UNEXPECTED_MULTI_WRITE] = { "unexpected multiple assignment; multiple assignment is not allowed in this context", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_UNEXPECTED_RANGE_OPERATOR] = { "unexpected range operator; .. and ... are non-associative and cannot be chained", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_UNEXPECTED_SAFE_NAVIGATION] = { "&. inside multiple assignment destination", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT] = { "unexpected %s, assuming it is closing the parent %s", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_UNEXPECTED_TOKEN_IGNORE] = { "unexpected %s, ignoring it", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_UNTIL_TERM] = { "expected an `end` to close the `until` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_VOID_EXPRESSION] = { "unexpected void value expression", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_WHILE_TERM] = { "expected an `end` to close the `while` statement", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_WRITE_TARGET_IN_METHOD] = { "dynamic constant assignment", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_WRITE_TARGET_READONLY] = { "Can't set variable %.*s", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_WRITE_TARGET_UNEXPECTED] = { "unexpected write target", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_XSTRING_TERM] = { "expected a closing delimiter for the `%x` or backtick string", PM_ERROR_LEVEL_SYNTAX },
-
- // Warnings
- [PM_WARN_AMBIGUOUS_BINARY_OPERATOR] = { "'%s' after local variable or literal is interpreted as binary operator even though it seems like %s", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS] = { "ambiguous first argument; put parentheses or a space even after `-` operator", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS] = { "ambiguous first argument; put parentheses or a space even after `+` operator", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND] = { "ambiguous `&` has been interpreted as an argument prefix", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_AMBIGUOUS_PREFIX_STAR] = { "ambiguous `*` has been interpreted as an argument prefix", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR] = { "ambiguous `**` has been interpreted as an argument prefix", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_AMBIGUOUS_SLASH] = { "ambiguous `/`; wrap regexp in parentheses or add a space after `/` operator", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_COMPARISON_AFTER_COMPARISON] = { "comparison '%.*s' after comparison", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_DOT_DOT_DOT_EOL] = { "... at EOL, should be parenthesized?", PM_WARNING_LEVEL_DEFAULT },
- [PM_WARN_DUPLICATED_HASH_KEY] = { "key %.*s is duplicated and overwritten on line %" PRIi32, PM_WARNING_LEVEL_DEFAULT },
- [PM_WARN_DUPLICATED_WHEN_CLAUSE] = { "'when' clause on line %" PRIi32 " duplicates 'when' clause on line %" PRIi32 " and is ignored", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_EQUAL_IN_CONDITIONAL_3_3] = { "found `= literal' in conditional, should be ==", PM_WARNING_LEVEL_DEFAULT },
- [PM_WARN_EQUAL_IN_CONDITIONAL] = { "found '= literal' in conditional, should be ==", PM_WARNING_LEVEL_DEFAULT },
- [PM_WARN_END_IN_METHOD] = { "END in method; use at_exit", PM_WARNING_LEVEL_DEFAULT },
- [PM_WARN_FLOAT_OUT_OF_RANGE] = { "Float %.*s%s out of range", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_IGNORED_FROZEN_STRING_LITERAL] = { "'frozen_string_literal' is ignored after any tokens", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_INDENTATION_MISMATCH] = { "mismatched indentations at '%.*s' with '%.*s' at %" PRIi32, PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_INTEGER_IN_FLIP_FLOP] = { "integer literal in flip-flop", PM_WARNING_LEVEL_DEFAULT },
- [PM_WARN_INVALID_CHARACTER] = { "invalid character syntax; use %s%s%s", PM_WARNING_LEVEL_DEFAULT },
- [PM_WARN_INVALID_MAGIC_COMMENT_VALUE] = { "invalid value for %.*s: %.*s", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_INVALID_NUMBERED_REFERENCE] = { "'%.*s' is too big for a number variable, always nil", PM_WARNING_LEVEL_DEFAULT },
- [PM_WARN_KEYWORD_EOL] = { "`%.*s` at the end of line without an expression", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_LITERAL_IN_CONDITION_DEFAULT] = { "%sliteral in %s", PM_WARNING_LEVEL_DEFAULT },
- [PM_WARN_LITERAL_IN_CONDITION_VERBOSE] = { "%sliteral in %s", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE] = { "'shareable_constant_value' is ignored unless in comment-only line", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_SHEBANG_CARRIAGE_RETURN] = { "shebang line ending with \\r may cause problems", PM_WARNING_LEVEL_DEFAULT },
- [PM_WARN_UNEXPECTED_CARRIAGE_RETURN] = { "encountered \\r in middle of line, treated as a mere space", PM_WARNING_LEVEL_DEFAULT },
- [PM_WARN_UNREACHABLE_STATEMENT] = { "statement not reached", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_UNUSED_LOCAL_VARIABLE] = { "assigned but unused variable - %.*s", PM_WARNING_LEVEL_VERBOSE },
- [PM_WARN_VOID_STATEMENT] = { "possibly useless use of %.*s in void context", PM_WARNING_LEVEL_VERBOSE }
-};
-
-/**
- * Get the human-readable name of the given diagnostic ID.
- */
-const char *
-pm_diagnostic_id_human(pm_diagnostic_id_t diag_id) {
- switch (diag_id) {
- <%- errors.each do |error| -%>
- case PM_ERR_<%= error.name %>: return "<%= error.name.downcase %>";
- <%- end -%>
- <%- warnings.each do |warning| -%>
- case PM_WARN_<%= warning.name %>: return "<%= warning.name.downcase %>";
- <%- end -%>
- }
-
- assert(false && "unreachable");
- return "";
-}
-
-static inline const char *
-pm_diagnostic_message(pm_diagnostic_id_t diag_id) {
- assert(diag_id < PM_DIAGNOSTIC_ID_MAX);
-
- const char *message = diagnostic_messages[diag_id].message;
- assert(message);
-
- return message;
-}
-
-static inline uint8_t
-pm_diagnostic_level(pm_diagnostic_id_t diag_id) {
- assert(diag_id < PM_DIAGNOSTIC_ID_MAX);
-
- return (uint8_t) diagnostic_messages[diag_id].level;
-}
-
-/**
- * Append an error to the given list of diagnostic.
- */
-bool
-pm_diagnostic_list_append(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id) {
- pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) xcalloc(1, sizeof(pm_diagnostic_t));
- if (diagnostic == NULL) return false;
-
- *diagnostic = (pm_diagnostic_t) {
- .location = { start, end },
- .diag_id = diag_id,
- .message = pm_diagnostic_message(diag_id),
- .owned = false,
- .level = pm_diagnostic_level(diag_id)
- };
-
- pm_list_append(list, (pm_list_node_t *) diagnostic);
- return true;
-}
-
-/**
- * Append a diagnostic to the given list of diagnostics that is using a format
- * string for its message.
- */
-bool
-pm_diagnostic_list_append_format(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id, ...) {
- va_list arguments;
- va_start(arguments, diag_id);
-
- const char *format = pm_diagnostic_message(diag_id);
- int result = vsnprintf(NULL, 0, format, arguments);
- va_end(arguments);
-
- if (result < 0) {
- return false;
- }
-
- pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) xcalloc(1, sizeof(pm_diagnostic_t));
- if (diagnostic == NULL) {
- return false;
- }
-
- size_t length = (size_t) (result + 1);
- char *message = (char *) xmalloc(length);
- if (message == NULL) {
- xfree(diagnostic);
- return false;
- }
-
- va_start(arguments, diag_id);
- vsnprintf(message, length, format, arguments);
- va_end(arguments);
-
- *diagnostic = (pm_diagnostic_t) {
- .location = { start, end },
- .diag_id = diag_id,
- .message = message,
- .owned = true,
- .level = pm_diagnostic_level(diag_id)
- };
-
- pm_list_append(list, (pm_list_node_t *) diagnostic);
- return true;
-}
-
-/**
- * Deallocate the internal state of the given diagnostic list.
- */
-void
-pm_diagnostic_list_free(pm_list_t *list) {
- pm_diagnostic_t *node = (pm_diagnostic_t *) list->head;
-
- while (node != NULL) {
- pm_diagnostic_t *next = (pm_diagnostic_t *) node->node.next;
-
- if (node->owned) xfree((void *) node->message);
- xfree(node);
-
- node = next;
- }
-}
diff --git a/prism/templates/src/node.c.erb b/prism/templates/src/node.c.erb
deleted file mode 100644
index 2357e55200..0000000000
--- a/prism/templates/src/node.c.erb
+++ /dev/null
@@ -1,333 +0,0 @@
-#line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>"
-#include "prism/node.h"
-
-/**
- * Attempts to grow the node list to the next size. If there is already
- * capacity in the list, this function does nothing. Otherwise it reallocates
- * the list to be twice as large as it was before. If the reallocation fails,
- * this function returns false, otherwise it returns true.
- */
-static bool
-pm_node_list_grow(pm_node_list_t *list, size_t size) {
- size_t requested_size = list->size + size;
-
- // If the requested size caused overflow, return false.
- if (requested_size < list->size) return false;
-
- // If the requested size is within the existing capacity, return true.
- if (requested_size < list->capacity) return true;
-
- // Otherwise, reallocate the list to be twice as large as it was before.
- size_t next_capacity = list->capacity == 0 ? 4 : list->capacity * 2;
-
- // If multiplying by 2 caused overflow, return false.
- if (next_capacity < list->capacity) return false;
-
- // If we didn't get enough by doubling, keep doubling until we do.
- while (requested_size > next_capacity) {
- size_t double_capacity = next_capacity * 2;
-
- // Ensure we didn't overflow by multiplying by 2.
- if (double_capacity < next_capacity) return false;
- next_capacity = double_capacity;
- }
-
- pm_node_t **nodes = (pm_node_t **) xrealloc(list->nodes, sizeof(pm_node_t *) * next_capacity);
- if (nodes == NULL) return false;
-
- list->nodes = nodes;
- list->capacity = next_capacity;
- return true;
-}
-
-/**
- * Append a new node onto the end of the node list.
- */
-void
-pm_node_list_append(pm_node_list_t *list, pm_node_t *node) {
- if (pm_node_list_grow(list, 1)) {
- list->nodes[list->size++] = node;
- }
-}
-
-/**
- * Prepend a new node onto the beginning of the node list.
- */
-void
-pm_node_list_prepend(pm_node_list_t *list, pm_node_t *node) {
- if (pm_node_list_grow(list, 1)) {
- memmove(list->nodes + 1, list->nodes, list->size * sizeof(pm_node_t *));
- list->nodes[0] = node;
- list->size++;
- }
-}
-
-/**
- * Concatenate the given node list onto the end of the other node list.
- */
-void
-pm_node_list_concat(pm_node_list_t *list, pm_node_list_t *other) {
- if (other->size > 0 && pm_node_list_grow(list, other->size)) {
- memcpy(list->nodes + list->size, other->nodes, other->size * sizeof(pm_node_t *));
- list->size += other->size;
- }
-}
-
-/**
- * Free the internal memory associated with the given node list.
- */
-void
-pm_node_list_free(pm_node_list_t *list) {
- if (list->capacity > 0) {
- xfree(list->nodes);
- *list = (pm_node_list_t) { 0 };
- }
-}
-
-PRISM_EXPORTED_FUNCTION void
-pm_node_destroy(pm_parser_t *parser, pm_node_t *node);
-
-/**
- * Destroy the nodes that are contained within the given node list.
- */
-static void
-pm_node_list_destroy(pm_parser_t *parser, pm_node_list_t *list) {
- pm_node_t *node;
- PM_NODE_LIST_FOREACH(list, index, node) pm_node_destroy(parser, node);
- pm_node_list_free(list);
-}
-
-/**
- * Deallocate the space for a pm_node_t. Similarly to pm_node_alloc, we're not
- * using the parser argument, but it's there to allow for the future possibility
- * of pre-allocating larger memory pools.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_node_destroy(pm_parser_t *parser, pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- <%- nodes.each do |node| -%>
-#line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>"
- case <%= node.type %>: {
- <%- if node.fields.any? { |field| ![Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField].include?(field.class) } -%>
- pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node;
- <%- end -%>
- <%- node.fields.each do |field| -%>
- <%- case field -%>
- <%- when Prism::Template::LocationField, Prism::Template::OptionalLocationField, Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::ConstantField, Prism::Template::OptionalConstantField, Prism::Template::DoubleField -%>
- <%- when Prism::Template::NodeField -%>
- pm_node_destroy(parser, (pm_node_t *)cast-><%= field.name %>);
- <%- when Prism::Template::OptionalNodeField -%>
- if (cast-><%= field.name %> != NULL) {
- pm_node_destroy(parser, (pm_node_t *)cast-><%= field.name %>);
- }
- <%- when Prism::Template::StringField -%>
- pm_string_free(&cast-><%= field.name %>);
- <%- when Prism::Template::NodeListField -%>
- pm_node_list_destroy(parser, &cast-><%= field.name %>);
- <%- when Prism::Template::ConstantListField -%>
- pm_constant_id_list_free(&cast-><%= field.name %>);
- <%- when Prism::Template::IntegerField -%>
- pm_integer_free(&cast-><%= field.name %>);
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- <%- end -%>
- break;
- }
- <%- end -%>
-#line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>"
- default:
- assert(false && "unreachable");
- break;
- }
- xfree(node);
-}
-
-/**
- * Returns a string representation of the given node type.
- */
-PRISM_EXPORTED_FUNCTION const char *
-pm_node_type_to_str(pm_node_type_t node_type)
-{
- switch (node_type) {
-<%- nodes.each do |node| -%>
- case <%= node.type %>:
- return "<%= node.type %>";
-<%- end -%>
- }
- return "";
-}
-
-/**
- * Visit each of the nodes in this subtree using the given visitor callback. The
- * callback function will be called for each node in the subtree. If it returns
- * false, then that node's children will not be visited. If it returns true,
- * then the children will be visited. The data parameter is treated as an opaque
- * pointer and is passed to the visitor callback for consumers to use as they
- * see fit.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_visit_node(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data) {
- if (visitor(node, data)) pm_visit_child_nodes(node, visitor, data);
-}
-
-/**
- * Visit the children of the given node with the given callback. This is the
- * default behavior for walking the tree that is called from pm_visit_node if
- * the callback returns true.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_visit_child_nodes(const pm_node_t *node, bool (*visitor)(const pm_node_t *node, void *data), void *data) {
- switch (PM_NODE_TYPE(node)) {
- <%- nodes.each do |node| -%>
- <%- if (fields = node.fields.select { |field| field.is_a?(Prism::Template::NodeField) || field.is_a?(Prism::Template::OptionalNodeField) || field.is_a?(Prism::Template::NodeListField) }).any? -%>
- case <%= node.type %>: {
- const pm_<%= node.human %>_t *cast = (const pm_<%= node.human %>_t *) node;
- <%- fields.each do |field| -%>
-
- // Visit the <%= field.name %> field
- <%- case field -%>
- <%- when Prism::Template::NodeField -%>
- pm_visit_node((const pm_node_t *) cast-><%= field.name %>, visitor, data);
- <%- when Prism::Template::OptionalNodeField -%>
- if (cast-><%= field.name %> != NULL) {
- pm_visit_node((const pm_node_t *) cast-><%= field.name %>, visitor, data);
- }
- <%- when Prism::Template::NodeListField -%>
- const pm_node_list_t *<%= field.name %> = &cast-><%= field.name %>;
- for (size_t index = 0; index < <%= field.name %>->size; index++) {
- pm_visit_node(<%= field.name %>->nodes[index], visitor, data);
- }
- <%- end -%>
- <%- end -%>
-
- break;
- }
- <%- else -%>
- case <%= node.type %>:
- break;
- <%- end -%>
- <%- end -%>
- case PM_SCOPE_NODE:
- break;
- }
-}
-
-// We optionally support dumping to JSON. For systems that don't want or need
-// this functionality, it can be turned off with the PRISM_EXCLUDE_JSON define.
-#ifndef PRISM_EXCLUDE_JSON
-
-static void
-pm_dump_json_constant(pm_buffer_t *buffer, const pm_parser_t *parser, pm_constant_id_t constant_id) {
- const pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id);
- pm_buffer_append_byte(buffer, '"');
- pm_buffer_append_source(buffer, constant->start, constant->length, PM_BUFFER_ESCAPING_JSON);
- pm_buffer_append_byte(buffer, '"');
-}
-
-static void
-pm_dump_json_location(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_location_t *location) {
- uint32_t start = (uint32_t) (location->start - parser->start);
- uint32_t end = (uint32_t) (location->end - parser->start);
- pm_buffer_append_format(buffer, "{\"start\":%" PRIu32 ",\"end\":%" PRIu32 "}", start, end);
-}
-
-/**
- * Dump JSON to the given buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_dump_json(pm_buffer_t *buffer, const pm_parser_t *parser, const pm_node_t *node) {
- switch (PM_NODE_TYPE(node)) {
- <%- nodes.each do |node| -%>
- case <%= node.type %>: {
- pm_buffer_append_string(buffer, "{\"type\":\"<%= node.name %>\",\"location\":", <%= node.name.bytesize + 22 %>);
-
- const pm_<%= node.human %>_t *cast = (const pm_<%= node.human %>_t *) node;
- pm_dump_json_location(buffer, parser, &cast->base.location);
- <%- [*node.flags, *node.fields].each_with_index do |field, index| -%>
-
- // Dump the <%= field.name %> field
- pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"<%= field.name %>\":", <%= field.name.bytesize + 3 %>);
- <%- case field -%>
- <%- when Prism::Template::NodeField -%>
- pm_dump_json(buffer, parser, (const pm_node_t *) cast-><%= field.name %>);
- <%- when Prism::Template::OptionalNodeField -%>
- if (cast-><%= field.name %> != NULL) {
- pm_dump_json(buffer, parser, (const pm_node_t *) cast-><%= field.name %>);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
- <%- when Prism::Template::NodeListField -%>
- const pm_node_list_t *<%= field.name %> = &cast-><%= field.name %>;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < <%= field.name %>->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json(buffer, parser, <%= field.name %>->nodes[index]);
- }
- pm_buffer_append_byte(buffer, ']');
- <%- when Prism::Template::StringField -%>
- const pm_string_t *<%= field.name %> = &cast-><%= field.name %>;
- pm_buffer_append_byte(buffer, '"');
- pm_buffer_append_source(buffer, pm_string_source(<%= field.name %>), pm_string_length(<%= field.name %>), PM_BUFFER_ESCAPING_JSON);
- pm_buffer_append_byte(buffer, '"');
- <%- when Prism::Template::ConstantField -%>
- pm_dump_json_constant(buffer, parser, cast-><%= field.name %>);
- <%- when Prism::Template::OptionalConstantField -%>
- if (cast-><%= field.name %> != PM_CONSTANT_ID_UNSET) {
- pm_dump_json_constant(buffer, parser, cast-><%= field.name %>);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
- <%- when Prism::Template::ConstantListField -%>
- const pm_constant_id_list_t *<%= field.name %> = &cast-><%= field.name %>;
- pm_buffer_append_byte(buffer, '[');
-
- for (size_t index = 0; index < <%= field.name %>->size; index++) {
- if (index != 0) pm_buffer_append_byte(buffer, ',');
- pm_dump_json_constant(buffer, parser, <%= field.name %>->ids[index]);
- }
- pm_buffer_append_byte(buffer, ']');
- <%- when Prism::Template::LocationField -%>
- pm_dump_json_location(buffer, parser, &cast-><%= field.name %>);
- <%- when Prism::Template::OptionalLocationField -%>
- if (cast-><%= field.name %>.start != NULL) {
- pm_dump_json_location(buffer, parser, &cast-><%= field.name %>);
- } else {
- pm_buffer_append_string(buffer, "null", 4);
- }
- <%- when Prism::Template::UInt8Field -%>
- pm_buffer_append_format(buffer, "%" PRIu8, cast-><%= field.name %>);
- <%- when Prism::Template::UInt32Field -%>
- pm_buffer_append_format(buffer, "%" PRIu32, cast-><%= field.name %>);
- <%- when Prism::Template::Flags -%>
- size_t flags = 0;
- pm_buffer_append_byte(buffer, '[');
- <%- node.flags.values.each_with_index do |value, index| -%>
- if (PM_NODE_FLAG_P(cast, PM_<%= node.flags.human.upcase %>_<%= value.name %>)) {
- if (flags != 0) pm_buffer_append_byte(buffer, ',');
- pm_buffer_append_string(buffer, "\"<%= value.name %>\"", <%= value.name.bytesize + 2 %>);
- flags++;
- }
- <%- end -%>
- pm_buffer_append_byte(buffer, ']');
- <%- when Prism::Template::IntegerField -%>
- pm_integer_string(buffer, &cast-><%= field.name %>);
- <%- when Prism::Template::DoubleField -%>
- pm_buffer_append_format(buffer, "%f", cast-><%= field.name %>);
- <%- else -%>
- <%- raise %>
- <%- end -%>
- <%- end -%>
-
- pm_buffer_append_byte(buffer, '}');
- break;
- }
- <%- end -%>
- case PM_SCOPE_NODE:
- break;
- }
-}
-
-#endif
diff --git a/prism/templates/src/prettyprint.c.erb b/prism/templates/src/prettyprint.c.erb
deleted file mode 100644
index 639c2fecf3..0000000000
--- a/prism/templates/src/prettyprint.c.erb
+++ /dev/null
@@ -1,166 +0,0 @@
-<%# encoding: ASCII -%>
-#include "prism/prettyprint.h"
-
-// We optionally support pretty printing nodes. For systems that don't want or
-// need this functionality, it can be turned off with the
-// PRISM_EXCLUDE_PRETTYPRINT define.
-#ifdef PRISM_EXCLUDE_PRETTYPRINT
-
-void pm_prettyprint(void) {}
-
-#else
-
-static inline void
-prettyprint_location(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_location_t *location) {
- pm_line_column_t start = pm_newline_list_line_column(&parser->newline_list, location->start, parser->start_line);
- pm_line_column_t end = pm_newline_list_line_column(&parser->newline_list, location->end, parser->start_line);
- pm_buffer_append_format(output_buffer, "(%" PRIi32 ",%" PRIu32 ")-(%" PRIi32 ",%" PRIu32 ")", start.line, start.column, end.line, end.column);
-}
-
-static inline void
-prettyprint_constant(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_constant_id_t constant_id) {
- pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, constant_id);
- pm_buffer_append_format(output_buffer, ":%.*s", (int) constant->length, constant->start);
-}
-
-static void
-prettyprint_node(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node, pm_buffer_t *prefix_buffer) {
- switch (PM_NODE_TYPE(node)) {
- case PM_SCOPE_NODE:
- // We do not need to print a ScopeNode as it's not part of the AST.
- return;
- <%- nodes.each do |node| -%>
- case <%= node.type %>: {
- <%- if !node.flags.nil? || node.fields.any? -%>
- pm_<%= node.human %>_t *cast = (pm_<%= node.human %>_t *) node;
- <%- end -%>
- pm_buffer_append_string(output_buffer, "@ <%= node.name %> (location: ", <%= node.name.length + 14 %>);
- prettyprint_location(output_buffer, parser, &node->location);
- pm_buffer_append_string(output_buffer, ")\n", 2);
- <%- (fields = [*node.flags, *node.fields]).each_with_index do |field, index| -%>
- <%- preadd = index == fields.length - 1 ? " " : "| " -%>
-
- // <%= field.name %>
- {
- pm_buffer_concat(output_buffer, prefix_buffer);
- pm_buffer_append_string(output_buffer, "+-- <%= field.name %>:", <%= 4 + field.name.length + 1 %>);
- <%- case field -%>
- <%- when Prism::Template::NodeField -%>
- pm_buffer_append_byte(output_buffer, '\n');
-
- size_t prefix_length = prefix_buffer->length;
- pm_buffer_append_string(prefix_buffer, "<%= preadd %>", 4);
- pm_buffer_concat(output_buffer, prefix_buffer);
- prettyprint_node(output_buffer, parser, (pm_node_t *) cast-><%= field.name %>, prefix_buffer);
- prefix_buffer->length = prefix_length;
- <%- when Prism::Template::OptionalNodeField -%>
- if (cast-><%= field.name %> == NULL) {
- pm_buffer_append_string(output_buffer, " nil\n", 5);
- } else {
- pm_buffer_append_byte(output_buffer, '\n');
-
- size_t prefix_length = prefix_buffer->length;
- pm_buffer_append_string(prefix_buffer, "<%= preadd %>", 4);
- pm_buffer_concat(output_buffer, prefix_buffer);
- prettyprint_node(output_buffer, parser, (pm_node_t *) cast-><%= field.name %>, prefix_buffer);
- prefix_buffer->length = prefix_length;
- }
- <%- when Prism::Template::StringField -%>
- pm_buffer_append_string(output_buffer, " \"", 2);
- pm_buffer_append_source(output_buffer, pm_string_source(&cast-><%= field.name %>), pm_string_length(&cast-><%= field.name %>), PM_BUFFER_ESCAPING_RUBY);
- pm_buffer_append_string(output_buffer, "\"\n", 2);
- <%- when Prism::Template::NodeListField -%>
- pm_buffer_append_format(output_buffer, " (length: %lu)\n", (unsigned long) (cast-><%= field.name %>.size));
-
- size_t last_index = cast-><%= field.name %>.size;
- for (uint32_t index = 0; index < last_index; index++) {
- size_t prefix_length = prefix_buffer->length;
- pm_buffer_append_string(prefix_buffer, "<%= preadd %>", 4);
- pm_buffer_concat(output_buffer, prefix_buffer);
- pm_buffer_append_string(output_buffer, "+-- ", 4);
- pm_buffer_append_string(prefix_buffer, (index == last_index - 1) ? " " : "| ", 4);
- prettyprint_node(output_buffer, parser, (pm_node_t *) cast-><%= field.name %>.nodes[index], prefix_buffer);
- prefix_buffer->length = prefix_length;
- }
- <%- when Prism::Template::ConstantField -%>
- pm_buffer_append_byte(output_buffer, ' ');
- prettyprint_constant(output_buffer, parser, cast-><%= field.name %>);
- pm_buffer_append_byte(output_buffer, '\n');
- <%- when Prism::Template::OptionalConstantField -%>
- if (cast-><%= field.name %> == 0) {
- pm_buffer_append_string(output_buffer, " nil\n", 5);
- } else {
- pm_buffer_append_byte(output_buffer, ' ');
- prettyprint_constant(output_buffer, parser, cast-><%= field.name %>);
- pm_buffer_append_byte(output_buffer, '\n');
- }
- <%- when Prism::Template::ConstantListField -%>
- pm_buffer_append_string(output_buffer, " [", 2);
- for (uint32_t index = 0; index < cast-><%= field.name %>.size; index++) {
- if (index != 0) pm_buffer_append_string(output_buffer, ", ", 2);
- prettyprint_constant(output_buffer, parser, cast-><%= field.name %>.ids[index]);
- }
- pm_buffer_append_string(output_buffer, "]\n", 2);
- <%- when Prism::Template::LocationField -%>
- pm_location_t *location = &cast-><%= field.name %>;
- pm_buffer_append_byte(output_buffer, ' ');
- prettyprint_location(output_buffer, parser, location);
- pm_buffer_append_string(output_buffer, " = \"", 4);
- pm_buffer_append_source(output_buffer, location->start, (size_t) (location->end - location->start), PM_BUFFER_ESCAPING_RUBY);
- pm_buffer_append_string(output_buffer, "\"\n", 2);
- <%- when Prism::Template::OptionalLocationField -%>
- pm_location_t *location = &cast-><%= field.name %>;
- if (location->start == NULL) {
- pm_buffer_append_string(output_buffer, " nil\n", 5);
- } else {
- pm_buffer_append_byte(output_buffer, ' ');
- prettyprint_location(output_buffer, parser, location);
- pm_buffer_append_string(output_buffer, " = \"", 4);
- pm_buffer_append_source(output_buffer, location->start, (size_t) (location->end - location->start), PM_BUFFER_ESCAPING_RUBY);
- pm_buffer_append_string(output_buffer, "\"\n", 2);
- }
- <%- when Prism::Template::UInt8Field -%>
- pm_buffer_append_format(output_buffer, " %" PRIu8 "\n", cast-><%= field.name %>);
- <%- when Prism::Template::UInt32Field -%>
- pm_buffer_append_format(output_buffer, " %" PRIu32 "\n", cast-><%= field.name %>);
- <%- when Prism::Template::Flags -%>
- bool found = false;
- <%- field.values.each do |value| -%>
- if (cast->base.flags & PM_<%= field.human.upcase %>_<%= value.name %>) {
- if (found) pm_buffer_append_byte(output_buffer, ',');
- pm_buffer_append_string(output_buffer, " <%= value.name.downcase %>", <%= value.name.bytesize + 1 %>);
- found = true;
- }
- <%- end -%>
- if (!found) pm_buffer_append_string(output_buffer, " nil", 4);
- pm_buffer_append_byte(output_buffer, '\n');
- <%- when Prism::Template::IntegerField -%>
- const pm_integer_t *integer = &cast-><%= field.name %>;
- pm_buffer_append_byte(output_buffer, ' ');
- pm_integer_string(output_buffer, integer);
- pm_buffer_append_byte(output_buffer, '\n');
- <%- when Prism::Template::DoubleField -%>
- pm_buffer_append_format(output_buffer, " %f\n", cast-><%= field.name %>);
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- }
- <%- end -%>
-
- break;
- }
- <%- end -%>
- }
-}
-
-/**
- * Pretty-prints the AST represented by the given node to the given buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_prettyprint(pm_buffer_t *output_buffer, const pm_parser_t *parser, const pm_node_t *node) {
- pm_buffer_t prefix_buffer = { 0 };
- prettyprint_node(output_buffer, parser, node, &prefix_buffer);
- pm_buffer_free(&prefix_buffer);
-}
-
-#endif
diff --git a/prism/templates/src/serialize.c.erb b/prism/templates/src/serialize.c.erb
deleted file mode 100644
index 9f8f0cbd07..0000000000
--- a/prism/templates/src/serialize.c.erb
+++ /dev/null
@@ -1,406 +0,0 @@
-#include "prism.h"
-
-// We optionally support serializing to a binary string. For systems that don't
-// want or need this functionality, it can be turned off with the
-// PRISM_EXCLUDE_SERIALIZATION define.
-#ifndef PRISM_EXCLUDE_SERIALIZATION
-
-#include <stdio.h>
-
-static inline uint32_t
-pm_ptrdifft_to_u32(ptrdiff_t value) {
- assert(value >= 0 && ((unsigned long) value) < UINT32_MAX);
- return (uint32_t) value;
-}
-
-static inline uint32_t
-pm_sizet_to_u32(size_t value) {
- assert(value < UINT32_MAX);
- return (uint32_t) value;
-}
-
-static void
-pm_serialize_location(const pm_parser_t *parser, const pm_location_t *location, pm_buffer_t *buffer) {
- assert(location->start);
- assert(location->end);
- assert(location->start <= location->end);
-
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(location->start - parser->start));
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(location->end - location->start));
-}
-
-static void
-pm_serialize_string(const pm_parser_t *parser, const pm_string_t *string, pm_buffer_t *buffer) {
- switch (string->type) {
- case PM_STRING_SHARED: {
- pm_buffer_append_byte(buffer, 1);
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(pm_string_source(string) - parser->start));
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(pm_string_length(string)));
- break;
- }
- case PM_STRING_OWNED:
- case PM_STRING_CONSTANT: {
- uint32_t length = pm_sizet_to_u32(pm_string_length(string));
- pm_buffer_append_byte(buffer, 2);
- pm_buffer_append_varuint(buffer, length);
- pm_buffer_append_bytes(buffer, pm_string_source(string), length);
- break;
- }
-#ifdef PRISM_HAS_MMAP
- case PM_STRING_MAPPED:
- assert(false && "Cannot serialize mapped strings.");
- break;
-#endif
- }
-}
-
-static void
-pm_serialize_integer(const pm_integer_t *integer, pm_buffer_t *buffer) {
- pm_buffer_append_byte(buffer, integer->negative ? 1 : 0);
- if (integer->values == NULL) {
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(1));
- pm_buffer_append_varuint(buffer, integer->value);
- } else {
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(integer->length));
- for (size_t i = 0; i < integer->length; i++) {
- pm_buffer_append_varuint(buffer, integer->values[i]);
- }
- }
-}
-
-static void
-pm_serialize_node(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
- pm_buffer_append_byte(buffer, (uint8_t) PM_NODE_TYPE(node));
-
- size_t offset = buffer->length;
-
- <%- unless Prism::Template::SERIALIZE_ONLY_SEMANTICS_FIELDS -%>
- pm_buffer_append_varuint(buffer, node->node_id);
- <%- end -%>
- pm_serialize_location(parser, &node->location, buffer);
-
- switch (PM_NODE_TYPE(node)) {
- // We do not need to serialize a ScopeNode ever as
- // it is not part of the AST
- case PM_SCOPE_NODE:
- return;
- <%- nodes.each do |node| -%>
- case <%= node.type %>: {
- <%- if node.needs_serialized_length? -%>
- // serialize length
- // encoding of location u32s make us need to save this offset.
- size_t length_offset = buffer->length;
- pm_buffer_append_string(buffer, "\0\0\0\0", 4); /* consume 4 bytes, updated below */
- <%- end -%>
- <%- unless Prism::Template::SERIALIZE_ONLY_SEMANTICS_FIELDS && !node.flags -%>
- pm_buffer_append_varuint(buffer, (uint32_t) node->flags);
- <%- end -%>
- <%- node.fields.each do |field| -%>
- <%- case field -%>
- <%- when Prism::Template::NodeField -%>
- pm_serialize_node(parser, (pm_node_t *)((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
- <%- when Prism::Template::OptionalNodeField -%>
- if (((pm_<%= node.human %>_t *)node)-><%= field.name %> == NULL) {
- pm_buffer_append_byte(buffer, 0);
- } else {
- pm_serialize_node(parser, (pm_node_t *)((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
- }
- <%- when Prism::Template::StringField -%>
- pm_serialize_string(parser, &((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
- <%- when Prism::Template::NodeListField -%>
- uint32_t <%= field.name %>_size = pm_sizet_to_u32(((pm_<%= node.human %>_t *)node)-><%= field.name %>.size);
- pm_buffer_append_varuint(buffer, <%= field.name %>_size);
- for (uint32_t index = 0; index < <%= field.name %>_size; index++) {
- pm_serialize_node(parser, (pm_node_t *) ((pm_<%= node.human %>_t *)node)-><%= field.name %>.nodes[index], buffer);
- }
- <%- when Prism::Template::ConstantField, Prism::Template::OptionalConstantField -%>
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_<%= node.human %>_t *)node)-><%= field.name %>));
- <%- when Prism::Template::ConstantListField -%>
- uint32_t <%= field.name %>_size = pm_sizet_to_u32(((pm_<%= node.human %>_t *)node)-><%= field.name %>.size);
- pm_buffer_append_varuint(buffer, <%= field.name %>_size);
- for (uint32_t index = 0; index < <%= field.name %>_size; index++) {
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(((pm_<%= node.human %>_t *)node)-><%= field.name %>.ids[index]));
- }
- <%- when Prism::Template::LocationField -%>
- <%- if field.should_be_serialized? -%>
- pm_serialize_location(parser, &((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
- <%- end -%>
- <%- when Prism::Template::OptionalLocationField -%>
- <%- if field.should_be_serialized? -%>
- if (((pm_<%= node.human %>_t *)node)-><%= field.name %>.start == NULL) {
- pm_buffer_append_byte(buffer, 0);
- } else {
- pm_buffer_append_byte(buffer, 1);
- pm_serialize_location(parser, &((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
- }
- <%- end -%>
- <%- when Prism::Template::UInt8Field -%>
- pm_buffer_append_byte(buffer, ((pm_<%= node.human %>_t *)node)-><%= field.name %>);
- <%- when Prism::Template::UInt32Field -%>
- pm_buffer_append_varuint(buffer, ((pm_<%= node.human %>_t *)node)-><%= field.name %>);
- <%- when Prism::Template::IntegerField -%>
- pm_serialize_integer(&((pm_<%= node.human %>_t *)node)-><%= field.name %>, buffer);
- <%- when Prism::Template::DoubleField -%>
- pm_buffer_append_double(buffer, ((pm_<%= node.human %>_t *)node)-><%= field.name %>);
- <%- else -%>
- <%- raise -%>
- <%- end -%>
- <%- end -%>
- <%- if node.needs_serialized_length? -%>
- // serialize length
- uint32_t length = pm_sizet_to_u32(buffer->length - offset - sizeof(uint32_t));
- memcpy(buffer->value + length_offset, &length, sizeof(uint32_t));
- <%- end -%>
- break;
- }
- <%- end -%>
- }
-}
-
-static void
-pm_serialize_newline_list(pm_newline_list_t *list, pm_buffer_t *buffer) {
- uint32_t size = pm_sizet_to_u32(list->size);
- pm_buffer_append_varuint(buffer, size);
-
- for (uint32_t i = 0; i < size; i++) {
- uint32_t offset = pm_sizet_to_u32(list->offsets[i]);
- pm_buffer_append_varuint(buffer, offset);
- }
-}
-
-static void
-pm_serialize_comment(pm_parser_t *parser, pm_comment_t *comment, pm_buffer_t *buffer) {
- // serialize type
- pm_buffer_append_byte(buffer, (uint8_t) comment->type);
-
- // serialize location
- pm_serialize_location(parser, &comment->location, buffer);
-}
-
-/**
- * Serialize the given list of comments to the given buffer.
- */
-void
-pm_serialize_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer) {
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(pm_list_size(list)));
-
- pm_comment_t *comment;
- for (comment = (pm_comment_t *) list->head; comment != NULL; comment = (pm_comment_t *) comment->node.next) {
- pm_serialize_comment(parser, comment, buffer);
- }
-}
-
-static void
-pm_serialize_magic_comment(pm_parser_t *parser, pm_magic_comment_t *magic_comment, pm_buffer_t *buffer) {
- // serialize key location
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(magic_comment->key_start - parser->start));
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(magic_comment->key_length));
-
- // serialize value location
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(magic_comment->value_start - parser->start));
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(magic_comment->value_length));
-}
-
-static void
-pm_serialize_magic_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer) {
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(pm_list_size(list)));
-
- pm_magic_comment_t *magic_comment;
- for (magic_comment = (pm_magic_comment_t *) list->head; magic_comment != NULL; magic_comment = (pm_magic_comment_t *) magic_comment->node.next) {
- pm_serialize_magic_comment(parser, magic_comment, buffer);
- }
-}
-
-static void
-pm_serialize_data_loc(const pm_parser_t *parser, pm_buffer_t *buffer) {
- if (parser->data_loc.end == NULL) {
- pm_buffer_append_byte(buffer, 0);
- } else {
- pm_buffer_append_byte(buffer, 1);
- pm_serialize_location(parser, &parser->data_loc, buffer);
- }
-}
-
-static void
-pm_serialize_diagnostic(pm_parser_t *parser, pm_diagnostic_t *diagnostic, pm_buffer_t *buffer) {
- // serialize the type
- pm_buffer_append_varuint(buffer, (uint32_t) diagnostic->diag_id);
-
- // serialize message
- size_t message_length = strlen(diagnostic->message);
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(message_length));
- pm_buffer_append_string(buffer, diagnostic->message, message_length);
-
- // serialize location
- pm_serialize_location(parser, &diagnostic->location, buffer);
-
- pm_buffer_append_byte(buffer, diagnostic->level);
-}
-
-static void
-pm_serialize_diagnostic_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer) {
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(pm_list_size(list)));
-
- pm_diagnostic_t *diagnostic;
- for (diagnostic = (pm_diagnostic_t *) list->head; diagnostic != NULL; diagnostic = (pm_diagnostic_t *) diagnostic->node.next) {
- pm_serialize_diagnostic(parser, diagnostic, buffer);
- }
-}
-
-/**
- * Serialize the name of the encoding to the buffer.
- */
-void
-pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer) {
- size_t encoding_length = strlen(encoding->name);
- pm_buffer_append_varuint(buffer, pm_sizet_to_u32(encoding_length));
- pm_buffer_append_string(buffer, encoding->name, encoding_length);
-}
-
-static void
-pm_serialize_metadata(pm_parser_t *parser, pm_buffer_t *buffer) {
- pm_serialize_encoding(parser->encoding, buffer);
- pm_buffer_append_varsint(buffer, parser->start_line);
- pm_serialize_newline_list(&parser->newline_list, buffer);
-<%- unless Prism::Template::SERIALIZE_ONLY_SEMANTICS_FIELDS -%>
- pm_serialize_comment_list(parser, &parser->comment_list, buffer);
-<%- end -%>
- pm_serialize_magic_comment_list(parser, &parser->magic_comment_list, buffer);
- pm_serialize_data_loc(parser, buffer);
- pm_serialize_diagnostic_list(parser, &parser->error_list, buffer);
- pm_serialize_diagnostic_list(parser, &parser->warning_list, buffer);
-}
-
-#line <%= __LINE__ + 1 %> "prism/templates/src/<%= File.basename(__FILE__) %>"
-/**
- * Serialize the metadata, nodes, and constant pool.
- */
-void
-pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
- pm_serialize_metadata(parser, buffer);
-
- // Here we're going to leave space for the offset of the constant pool in
- // the buffer.
- size_t offset = buffer->length;
- pm_buffer_append_zeroes(buffer, 4);
-
- // Next, encode the length of the constant pool.
- pm_buffer_append_varuint(buffer, parser->constant_pool.size);
-
- // Now we're going to serialize the content of the node.
- pm_serialize_node(parser, node, buffer);
-
- // Now we're going to serialize the offset of the constant pool back where
- // we left space for it.
- uint32_t length = pm_sizet_to_u32(buffer->length);
- memcpy(buffer->value + offset, &length, sizeof(uint32_t));
-
- // Now we're going to serialize the constant pool.
- offset = buffer->length;
- pm_buffer_append_zeroes(buffer, parser->constant_pool.size * 8);
-
- for (uint32_t index = 0; index < parser->constant_pool.capacity; index++) {
- pm_constant_pool_bucket_t *bucket = &parser->constant_pool.buckets[index];
-
- // If we find a constant at this index, serialize it at the correct
- // index in the buffer.
- if (bucket->id != 0) {
- pm_constant_t *constant = &parser->constant_pool.constants[bucket->id - 1];
- size_t buffer_offset = offset + ((((size_t)bucket->id) - 1) * 8);
-
- if (bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED || bucket->type == PM_CONSTANT_POOL_BUCKET_CONSTANT) {
- // Since this is an owned or constant constant, we are going to
- // write its contents into the buffer after the constant pool.
- // So effectively in place of the source offset, we have a
- // buffer offset. We will add a leading 1 to indicate that this
- // is a buffer offset.
- uint32_t content_offset = pm_sizet_to_u32(buffer->length);
- uint32_t owned_mask = (uint32_t) (1 << 31);
-
- assert(content_offset < owned_mask);
- content_offset |= owned_mask;
-
- memcpy(buffer->value + buffer_offset, &content_offset, 4);
- pm_buffer_append_bytes(buffer, constant->start, constant->length);
- } else {
- // Since this is a shared constant, we are going to write its
- // source offset directly into the buffer.
- uint32_t source_offset = pm_ptrdifft_to_u32(constant->start - parser->start);
- memcpy(buffer->value + buffer_offset, &source_offset, 4);
- }
-
- // Now we can write the length of the constant into the buffer.
- uint32_t constant_length = pm_sizet_to_u32(constant->length);
- memcpy(buffer->value + buffer_offset + 4, &constant_length, 4);
- }
- }
-}
-
-static void
-serialize_token(void *data, pm_parser_t *parser, pm_token_t *token) {
- pm_buffer_t *buffer = (pm_buffer_t *) data;
-
- pm_buffer_append_varuint(buffer, token->type);
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(token->start - parser->start));
- pm_buffer_append_varuint(buffer, pm_ptrdifft_to_u32(token->end - token->start));
- pm_buffer_append_varuint(buffer, parser->lex_state);
-}
-
-/**
- * Lex the given source and serialize to the given buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
- pm_options_t options = { 0 };
- pm_options_read(&options, data);
-
- pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
-
- pm_lex_callback_t lex_callback = (pm_lex_callback_t) {
- .data = (void *) buffer,
- .callback = serialize_token,
- };
-
- parser.lex_callback = &lex_callback;
- pm_node_t *node = pm_parse(&parser);
-
- // Append 0 to mark end of tokens.
- pm_buffer_append_byte(buffer, 0);
-
- pm_serialize_metadata(&parser, buffer);
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- pm_options_free(&options);
-}
-
-/**
- * Parse and serialize both the AST and the tokens represented by the given
- * source to the given buffer.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
- pm_options_t options = { 0 };
- pm_options_read(&options, data);
-
- pm_parser_t parser;
- pm_parser_init(&parser, source, size, &options);
-
- pm_lex_callback_t lex_callback = (pm_lex_callback_t) {
- .data = (void *) buffer,
- .callback = serialize_token,
- };
-
- parser.lex_callback = &lex_callback;
- pm_node_t *node = pm_parse(&parser);
-
- pm_buffer_append_byte(buffer, 0);
- pm_serialize(&parser, node, buffer);
-
- pm_node_destroy(&parser, node);
- pm_parser_free(&parser);
- pm_options_free(&options);
-}
-
-#endif
diff --git a/prism/templates/src/token_type.c.erb b/prism/templates/src/token_type.c.erb
deleted file mode 100644
index f196393ee1..0000000000
--- a/prism/templates/src/token_type.c.erb
+++ /dev/null
@@ -1,369 +0,0 @@
-#include <string.h>
-
-#include "prism/ast.h"
-
-/**
- * Returns a string representation of the given token type.
- */
-PRISM_EXPORTED_FUNCTION const char *
-pm_token_type_name(pm_token_type_t token_type) {
- switch (token_type) {
-<%- tokens.each do |token| -%>
- case PM_TOKEN_<%= token.name %>:
- return "<%= token.name %>";
-<%- end -%>
- case PM_TOKEN_MAXIMUM:
- assert(false && "unreachable");
- return "";
- }
-
- // Provide a default, because some compilers can't determine that the above
- // switch is exhaustive.
- assert(false && "unreachable");
- return "";
-}
-
-/**
- * Returns the human name of the given token type.
- */
-const char *
-pm_token_type_human(pm_token_type_t token_type) {
- switch (token_type) {
- case PM_TOKEN_EOF:
- return "end-of-input";
- case PM_TOKEN_MISSING:
- return "missing token";
- case PM_TOKEN_NOT_PROVIDED:
- return "not provided token";
- case PM_TOKEN_AMPERSAND:
- return "'&'";
- case PM_TOKEN_AMPERSAND_AMPERSAND:
- return "'&&'";
- case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL:
- return "'&&='";
- case PM_TOKEN_AMPERSAND_DOT:
- return "'&.'";
- case PM_TOKEN_AMPERSAND_EQUAL:
- return "'&='";
- case PM_TOKEN_BACKTICK:
- return "'`'";
- case PM_TOKEN_BACK_REFERENCE:
- return "back reference";
- case PM_TOKEN_BANG:
- return "'!'";
- case PM_TOKEN_BANG_EQUAL:
- return "'!='";
- case PM_TOKEN_BANG_TILDE:
- return "'!~'";
- case PM_TOKEN_BRACE_LEFT:
- return "'{'";
- case PM_TOKEN_BRACE_RIGHT:
- return "'}'";
- case PM_TOKEN_BRACKET_LEFT:
- return "'['";
- case PM_TOKEN_BRACKET_LEFT_ARRAY:
- return "'['";
- case PM_TOKEN_BRACKET_LEFT_RIGHT:
- return "'[]'";
- case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL:
- return "'[]='";
- case PM_TOKEN_BRACKET_RIGHT:
- return "']'";
- case PM_TOKEN_CARET:
- return "'^'";
- case PM_TOKEN_CARET_EQUAL:
- return "'^='";
- case PM_TOKEN_CHARACTER_LITERAL:
- return "character literal";
- case PM_TOKEN_CLASS_VARIABLE:
- return "class variable";
- case PM_TOKEN_COLON:
- return "':'";
- case PM_TOKEN_COLON_COLON:
- return "'::'";
- case PM_TOKEN_COMMA:
- return "','";
- case PM_TOKEN_COMMENT:
- return "comment";
- case PM_TOKEN_CONSTANT:
- return "constant";
- case PM_TOKEN_DOT:
- return "'.'";
- case PM_TOKEN_DOT_DOT:
- return "..";
- case PM_TOKEN_DOT_DOT_DOT:
- return "...";
- case PM_TOKEN_EMBDOC_BEGIN:
- return "'=begin'";
- case PM_TOKEN_EMBDOC_END:
- return "'=end'";
- case PM_TOKEN_EMBDOC_LINE:
- return "embedded documentation line";
- case PM_TOKEN_EMBEXPR_BEGIN:
- return "'#{'";
- case PM_TOKEN_EMBEXPR_END:
- return "'}'";
- case PM_TOKEN_EMBVAR:
- return "'#'";
- case PM_TOKEN_EQUAL:
- return "'='";
- case PM_TOKEN_EQUAL_EQUAL:
- return "'=='";
- case PM_TOKEN_EQUAL_EQUAL_EQUAL:
- return "'==='";
- case PM_TOKEN_EQUAL_GREATER:
- return "'=>'";
- case PM_TOKEN_EQUAL_TILDE:
- return "'=~'";
- case PM_TOKEN_FLOAT:
- return "float";
- case PM_TOKEN_FLOAT_IMAGINARY:
- return "imaginary";
- case PM_TOKEN_FLOAT_RATIONAL:
- return "rational";
- case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
- return "imaginary";
- case PM_TOKEN_GLOBAL_VARIABLE:
- return "global variable";
- case PM_TOKEN_GREATER:
- return "'>'";
- case PM_TOKEN_GREATER_EQUAL:
- return "'>='";
- case PM_TOKEN_GREATER_GREATER:
- return ">>";
- case PM_TOKEN_GREATER_GREATER_EQUAL:
- return ">>=";
- case PM_TOKEN_HEREDOC_END:
- return "heredoc ending";
- case PM_TOKEN_HEREDOC_START:
- return "heredoc beginning";
- case PM_TOKEN_IDENTIFIER:
- return "local variable or method";
- case PM_TOKEN_IGNORED_NEWLINE:
- return "ignored newline";
- case PM_TOKEN_INSTANCE_VARIABLE:
- return "instance variable";
- case PM_TOKEN_INTEGER:
- return "integer";
- case PM_TOKEN_INTEGER_IMAGINARY:
- return "imaginary";
- case PM_TOKEN_INTEGER_RATIONAL:
- return "rational";
- case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY:
- return "imaginary";
- case PM_TOKEN_KEYWORD_ALIAS:
- return "'alias'";
- case PM_TOKEN_KEYWORD_AND:
- return "'and'";
- case PM_TOKEN_KEYWORD_BEGIN:
- return "'begin'";
- case PM_TOKEN_KEYWORD_BEGIN_UPCASE:
- return "'BEGIN'";
- case PM_TOKEN_KEYWORD_BREAK:
- return "'break'";
- case PM_TOKEN_KEYWORD_CASE:
- return "'case'";
- case PM_TOKEN_KEYWORD_CLASS:
- return "'class'";
- case PM_TOKEN_KEYWORD_DEF:
- return "'def'";
- case PM_TOKEN_KEYWORD_DEFINED:
- return "'defined?'";
- case PM_TOKEN_KEYWORD_DO:
- return "'do'";
- case PM_TOKEN_KEYWORD_DO_LOOP:
- return "'do'";
- case PM_TOKEN_KEYWORD_ELSE:
- return "'else'";
- case PM_TOKEN_KEYWORD_ELSIF:
- return "'elsif'";
- case PM_TOKEN_KEYWORD_END:
- return "'end'";
- case PM_TOKEN_KEYWORD_END_UPCASE:
- return "'END'";
- case PM_TOKEN_KEYWORD_ENSURE:
- return "'ensure'";
- case PM_TOKEN_KEYWORD_FALSE:
- return "'false'";
- case PM_TOKEN_KEYWORD_FOR:
- return "'for'";
- case PM_TOKEN_KEYWORD_IF:
- return "'if'";
- case PM_TOKEN_KEYWORD_IF_MODIFIER:
- return "'if'";
- case PM_TOKEN_KEYWORD_IN:
- return "'in'";
- case PM_TOKEN_KEYWORD_MODULE:
- return "'module'";
- case PM_TOKEN_KEYWORD_NEXT:
- return "'next'";
- case PM_TOKEN_KEYWORD_NIL:
- return "'nil'";
- case PM_TOKEN_KEYWORD_NOT:
- return "'not'";
- case PM_TOKEN_KEYWORD_OR:
- return "'or'";
- case PM_TOKEN_KEYWORD_REDO:
- return "'redo'";
- case PM_TOKEN_KEYWORD_RESCUE:
- return "'rescue'";
- case PM_TOKEN_KEYWORD_RESCUE_MODIFIER:
- return "'rescue' modifier";
- case PM_TOKEN_KEYWORD_RETRY:
- return "'retry'";
- case PM_TOKEN_KEYWORD_RETURN:
- return "'return'";
- case PM_TOKEN_KEYWORD_SELF:
- return "'self'";
- case PM_TOKEN_KEYWORD_SUPER:
- return "'super'";
- case PM_TOKEN_KEYWORD_THEN:
- return "'then'";
- case PM_TOKEN_KEYWORD_TRUE:
- return "'true'";
- case PM_TOKEN_KEYWORD_UNDEF:
- return "'undef'";
- case PM_TOKEN_KEYWORD_UNLESS:
- return "'unless'";
- case PM_TOKEN_KEYWORD_UNLESS_MODIFIER:
- return "'unless'";
- case PM_TOKEN_KEYWORD_UNTIL:
- return "'until'";
- case PM_TOKEN_KEYWORD_UNTIL_MODIFIER:
- return "'until'";
- case PM_TOKEN_KEYWORD_WHEN:
- return "'when'";
- case PM_TOKEN_KEYWORD_WHILE:
- return "'while'";
- case PM_TOKEN_KEYWORD_WHILE_MODIFIER:
- return "'while'";
- case PM_TOKEN_KEYWORD_YIELD:
- return "'yield'";
- case PM_TOKEN_KEYWORD___ENCODING__:
- return "'__ENCODING__'";
- case PM_TOKEN_KEYWORD___FILE__:
- return "'__FILE__'";
- case PM_TOKEN_KEYWORD___LINE__:
- return "'__LINE__'";
- case PM_TOKEN_LABEL:
- return "label";
- case PM_TOKEN_LABEL_END:
- return "label terminator";
- case PM_TOKEN_LAMBDA_BEGIN:
- return "'{'";
- case PM_TOKEN_LESS:
- return "'<'";
- case PM_TOKEN_LESS_EQUAL:
- return "'<='";
- case PM_TOKEN_LESS_EQUAL_GREATER:
- return "'<=>'";
- case PM_TOKEN_LESS_LESS:
- return "<<";
- case PM_TOKEN_LESS_LESS_EQUAL:
- return "<<=";
- case PM_TOKEN_METHOD_NAME:
- return "method name";
- case PM_TOKEN_MINUS:
- return "'-'";
- case PM_TOKEN_MINUS_EQUAL:
- return "'-='";
- case PM_TOKEN_MINUS_GREATER:
- return "'->'";
- case PM_TOKEN_NEWLINE:
- return "newline";
- case PM_TOKEN_NUMBERED_REFERENCE:
- return "numbered reference";
- case PM_TOKEN_PARENTHESIS_LEFT:
- return "'('";
- case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES:
- return "'('";
- case PM_TOKEN_PARENTHESIS_RIGHT:
- return "')'";
- case PM_TOKEN_PERCENT:
- return "'%'";
- case PM_TOKEN_PERCENT_EQUAL:
- return "'%='";
- case PM_TOKEN_PERCENT_LOWER_I:
- return "'%i'";
- case PM_TOKEN_PERCENT_LOWER_W:
- return "'%w'";
- case PM_TOKEN_PERCENT_LOWER_X:
- return "'%x'";
- case PM_TOKEN_PERCENT_UPPER_I:
- return "'%I'";
- case PM_TOKEN_PERCENT_UPPER_W:
- return "'%W'";
- case PM_TOKEN_PIPE:
- return "'|'";
- case PM_TOKEN_PIPE_EQUAL:
- return "'|='";
- case PM_TOKEN_PIPE_PIPE:
- return "'||'";
- case PM_TOKEN_PIPE_PIPE_EQUAL:
- return "'||='";
- case PM_TOKEN_PLUS:
- return "'+'";
- case PM_TOKEN_PLUS_EQUAL:
- return "'+='";
- case PM_TOKEN_QUESTION_MARK:
- return "'?'";
- case PM_TOKEN_REGEXP_BEGIN:
- return "regular expression beginning";
- case PM_TOKEN_REGEXP_END:
- return "regular expression ending";
- case PM_TOKEN_SEMICOLON:
- return "';'";
- case PM_TOKEN_SLASH:
- return "'/'";
- case PM_TOKEN_SLASH_EQUAL:
- return "'/='";
- case PM_TOKEN_STAR:
- return "'*'";
- case PM_TOKEN_STAR_EQUAL:
- return "'*='";
- case PM_TOKEN_STAR_STAR:
- return "'**'";
- case PM_TOKEN_STAR_STAR_EQUAL:
- return "'**='";
- case PM_TOKEN_STRING_BEGIN:
- return "string literal";
- case PM_TOKEN_STRING_CONTENT:
- return "string content";
- case PM_TOKEN_STRING_END:
- return "string ending";
- case PM_TOKEN_SYMBOL_BEGIN:
- return "symbol literal";
- case PM_TOKEN_TILDE:
- return "'~'";
- case PM_TOKEN_UAMPERSAND:
- return "'&'";
- case PM_TOKEN_UCOLON_COLON:
- return "'::'";
- case PM_TOKEN_UDOT_DOT:
- return "'..'";
- case PM_TOKEN_UDOT_DOT_DOT:
- return "'...'";
- case PM_TOKEN_UMINUS:
- return "'-'";
- case PM_TOKEN_UMINUS_NUM:
- return "'-'";
- case PM_TOKEN_UPLUS:
- return "'+'";
- case PM_TOKEN_USTAR:
- return "*";
- case PM_TOKEN_USTAR_STAR:
- return "**";
- case PM_TOKEN_WORDS_SEP:
- return "string separator";
- case PM_TOKEN___END__:
- return "'__END__'";
- case PM_TOKEN_MAXIMUM:
- assert(false && "unreachable");
- return "";
- }
-
- // Provide a default, because some compilers can't determine that the above
- // switch is exhaustive.
- assert(false && "unreachable");
- return "";
-}
diff --git a/prism/templates/template.rb b/prism/templates/template.rb
deleted file mode 100755
index 7068c098d3..0000000000
--- a/prism/templates/template.rb
+++ /dev/null
@@ -1,683 +0,0 @@
-#!/usr/bin/env ruby
-# typed: ignore
-
-require "erb"
-require "fileutils"
-require "yaml"
-
-module Prism
- module Template
- SERIALIZE_ONLY_SEMANTICS_FIELDS = ENV.fetch("PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS", false)
- REMOVE_ON_ERROR_TYPES = SERIALIZE_ONLY_SEMANTICS_FIELDS
- CHECK_FIELD_KIND = ENV.fetch("CHECK_FIELD_KIND", false)
-
- JAVA_BACKEND = ENV["PRISM_JAVA_BACKEND"] || "truffleruby"
- JAVA_STRING_TYPE = JAVA_BACKEND == "jruby" ? "org.jruby.RubySymbol" : "String"
-
- COMMON_FLAGS_COUNT = 2
-
- class Error
- attr_reader :name
-
- def initialize(name)
- @name = name
- end
- end
-
- class Warning
- attr_reader :name
-
- def initialize(name)
- @name = name
- end
- end
-
- # This module contains methods for escaping characters in JavaDoc comments.
- module JavaDoc
- ESCAPES = {
- "'" => "&#39;",
- "\"" => "&quot;",
- "@" => "&#64;",
- "&" => "&amp;",
- "<" => "&lt;",
- ">" => "&gt;"
- }.freeze
-
- def self.escape(value)
- value.gsub(/['&"<>@]/, ESCAPES)
- end
- end
-
- # A comment attached to a field or node.
- class ConfigComment
- attr_reader :value
-
- def initialize(value)
- @value = value
- end
-
- def each_line(&block)
- value.each_line { |line| yield line.prepend(" ").rstrip }
- end
-
- def each_java_line(&block)
- ConfigComment.new(JavaDoc.escape(value)).each_line(&block)
- end
- end
-
- # This represents a field on a node. It contains all of the necessary
- # information to template out the code for that field.
- class Field
- attr_reader :name, :comment, :options
-
- def initialize(name:, comment: nil, **options)
- @name = name
- @comment = comment
- @options = options
- end
-
- def each_comment_line(&block)
- ConfigComment.new(comment).each_line(&block) if comment
- end
-
- def each_comment_java_line(&block)
- ConfigComment.new(comment).each_java_line(&block) if comment
- end
-
- def semantic_field?
- true
- end
-
- def should_be_serialized?
- SERIALIZE_ONLY_SEMANTICS_FIELDS ? semantic_field? : true
- end
- end
-
- # Some node fields can be specialized if they point to a specific kind of
- # node and not just a generic node.
- class NodeKindField < Field
- def initialize(kind:, **options)
- @kind = kind
- super(**options)
- end
-
- def c_type
- if specific_kind
- "pm_#{specific_kind.gsub(/(?<=.)[A-Z]/, "_\\0").downcase}"
- else
- "pm_node"
- end
- end
-
- def ruby_type
- specific_kind || "Node"
- end
-
- def java_type
- specific_kind || "Node"
- end
-
- def java_cast
- if specific_kind
- "(Nodes.#{@kind}) "
- else
- ""
- end
- end
-
- def specific_kind
- @kind unless @kind.is_a?(Array)
- end
-
- def union_kind
- @kind if @kind.is_a?(Array)
- end
- end
-
- # This represents a field on a node that is itself a node. We pass them as
- # references and store them as references.
- class NodeField < NodeKindField
- def rbs_class
- if specific_kind
- specific_kind
- elsif union_kind
- union_kind.join(" | ")
- else
- "Prism::node"
- end
- end
-
- def rbi_class
- if specific_kind
- "Prism::#{specific_kind}"
- elsif union_kind
- "T.any(#{union_kind.map { |kind| "Prism::#{kind}" }.join(", ")})"
- else
- "Prism::Node"
- end
- end
-
- def check_field_kind
- if union_kind
- "[#{union_kind.join(', ')}].include?(#{name}.class)"
- else
- "#{name}.is_a?(#{ruby_type})"
- end
- end
- end
-
- # This represents a field on a node that is itself a node and can be
- # optionally null. We pass them as references and store them as references.
- class OptionalNodeField < NodeKindField
- def rbs_class
- if specific_kind
- "#{specific_kind}?"
- elsif union_kind
- [*union_kind, "nil"].join(" | ")
- else
- "Prism::node?"
- end
- end
-
- def rbi_class
- if specific_kind
- "T.nilable(Prism::#{specific_kind})"
- elsif union_kind
- "T.nilable(T.any(#{union_kind.map { |kind| "Prism::#{kind}" }.join(", ")}))"
- else
- "T.nilable(Prism::Node)"
- end
- end
-
- def check_field_kind
- if union_kind
- "[#{union_kind.join(', ')}, NilClass].include?(#{name}.class)"
- else
- "#{name}.nil? || #{name}.is_a?(#{ruby_type})"
- end
- end
- end
-
- # This represents a field on a node that is a list of nodes. We pass them as
- # references and store them directly on the struct.
- class NodeListField < NodeKindField
- def rbs_class
- if specific_kind
- "Array[#{specific_kind}]"
- elsif union_kind
- "Array[#{union_kind.join(" | ")}]"
- else
- "Array[Prism::node]"
- end
- end
-
- def rbi_class
- if specific_kind
- "T::Array[Prism::#{specific_kind}]"
- elsif union_kind
- "T::Array[T.any(#{union_kind.map { |kind| "Prism::#{kind}" }.join(", ")})]"
- else
- "T::Array[Prism::Node]"
- end
- end
-
- def java_type
- "#{super}[]"
- end
-
- def check_field_kind
- if union_kind
- "#{name}.all? { |n| [#{union_kind.join(', ')}].include?(n.class) }"
- else
- "#{name}.all? { |n| n.is_a?(#{ruby_type}) }"
- end
- end
- end
-
- # This represents a field on a node that is the ID of a string interned
- # through the parser's constant pool.
- class ConstantField < Field
- def rbs_class
- "Symbol"
- end
-
- def rbi_class
- "Symbol"
- end
-
- def java_type
- JAVA_STRING_TYPE
- end
- end
-
- # This represents a field on a node that is the ID of a string interned
- # through the parser's constant pool and can be optionally null.
- class OptionalConstantField < Field
- def rbs_class
- "Symbol?"
- end
-
- def rbi_class
- "T.nilable(Symbol)"
- end
-
- def java_type
- JAVA_STRING_TYPE
- end
- end
-
- # This represents a field on a node that is a list of IDs that are associated
- # with strings interned through the parser's constant pool.
- class ConstantListField < Field
- def rbs_class
- "Array[Symbol]"
- end
-
- def rbi_class
- "T::Array[Symbol]"
- end
-
- def java_type
- "#{JAVA_STRING_TYPE}[]"
- end
- end
-
- # This represents a field on a node that is a string.
- class StringField < Field
- def rbs_class
- "String"
- end
-
- def rbi_class
- "String"
- end
-
- def java_type
- "byte[]"
- end
- end
-
- # This represents a field on a node that is a location.
- class LocationField < Field
- def semantic_field?
- false
- end
-
- def rbs_class
- "Location"
- end
-
- def rbi_class
- "Prism::Location"
- end
-
- def java_type
- "Location"
- end
- end
-
- # This represents a field on a node that is a location that is optional.
- class OptionalLocationField < Field
- def semantic_field?
- false
- end
-
- def rbs_class
- "Location?"
- end
-
- def rbi_class
- "T.nilable(Prism::Location)"
- end
-
- def java_type
- "Location"
- end
- end
-
- # This represents an integer field.
- class UInt8Field < Field
- def rbs_class
- "Integer"
- end
-
- def rbi_class
- "Integer"
- end
-
- def java_type
- "int"
- end
- end
-
- # This represents an integer field.
- class UInt32Field < Field
- def rbs_class
- "Integer"
- end
-
- def rbi_class
- "Integer"
- end
-
- def java_type
- "int"
- end
- end
-
- # This represents an arbitrarily-sized integer. When it gets to Ruby it will
- # be an Integer.
- class IntegerField < Field
- def rbs_class
- "Integer"
- end
-
- def rbi_class
- "Integer"
- end
-
- def java_type
- "Object"
- end
- end
-
- # This represents a double-precision floating point number. When it gets to
- # Ruby it will be a Float.
- class DoubleField < Field
- def rbs_class
- "Float"
- end
-
- def rbi_class
- "Float"
- end
-
- def java_type
- "double"
- end
- end
-
- # This class represents a node in the tree, configured by the config.yml file
- # in YAML format. It contains information about the name of the node and the
- # various child nodes it contains.
- class NodeType
- attr_reader :name, :type, :human, :flags, :fields, :newline, :comment
-
- def initialize(config, flags)
- @name = config.fetch("name")
-
- type = @name.gsub(/(?<=.)[A-Z]/, "_\\0")
- @type = "PM_#{type.upcase}"
- @human = type.downcase
-
- @fields =
- config.fetch("fields", []).map do |field|
- type = field_type_for(field.fetch("type"))
-
- options = field.transform_keys(&:to_sym)
- options.delete(:type)
-
- # If/when we have documentation on every field, this should be
- # changed to use fetch instead of delete.
- comment = options.delete(:comment)
-
- if kinds = options[:kind]
- kinds = [kinds] unless kinds.is_a?(Array)
- kinds = kinds.map do |kind|
- case kind
- when "non-void expression"
- # the actual list of types would be way too long
- "Node"
- when "pattern expression"
- # the list of all possible types is too long with 37+ different classes
- "Node"
- when Hash
- kind = kind.fetch("on error")
- REMOVE_ON_ERROR_TYPES ? nil : kind
- else
- kind
- end
- end.compact
- if kinds.size == 1
- kinds = kinds.first
- kinds = nil if kinds == "Node"
- end
- options[:kind] = kinds
- else
- if type < NodeKindField
- raise "Missing kind in config.yml for field #{@name}##{options.fetch(:name)}"
- end
- end
-
- type.new(comment: comment, **options)
- end
-
- @flags = config.key?("flags") ? flags.fetch(config.fetch("flags")) : nil
- @newline = config.fetch("newline", true)
- @comment = config.fetch("comment")
- end
-
- def each_comment_line(&block)
- ConfigComment.new(comment).each_line(&block)
- end
-
- def each_comment_java_line(&block)
- ConfigComment.new(comment).each_java_line(&block)
- end
-
- def semantic_fields
- @semantic_fields ||= @fields.select(&:semantic_field?)
- end
-
- # Should emit serialized length of node so implementations can skip
- # the node to enable lazy parsing.
- def needs_serialized_length?
- name == "DefNode"
- end
-
- private
-
- def field_type_for(name)
- case name
- when "node" then NodeField
- when "node?" then OptionalNodeField
- when "node[]" then NodeListField
- when "string" then StringField
- when "constant" then ConstantField
- when "constant?" then OptionalConstantField
- when "constant[]" then ConstantListField
- when "location" then LocationField
- when "location?" then OptionalLocationField
- when "uint8" then UInt8Field
- when "uint32" then UInt32Field
- when "integer" then IntegerField
- when "double" then DoubleField
- else raise("Unknown field type: #{name.inspect}")
- end
- end
- end
-
- # This represents a token in the lexer.
- class Token
- attr_reader :name, :value, :comment
-
- def initialize(config)
- @name = config.fetch("name")
- @value = config["value"]
- @comment = config.fetch("comment")
- end
- end
-
- # Represents a set of flags that should be internally represented with an enum.
- class Flags
- # Represents an individual flag within a set of flags.
- class Flag
- attr_reader :name, :camelcase, :comment
-
- def initialize(config)
- @name = config.fetch("name")
- @camelcase = @name.split("_").map(&:capitalize).join
- @comment = config.fetch("comment")
- end
- end
-
- attr_reader :name, :human, :values, :comment
-
- def initialize(config)
- @name = config.fetch("name")
- @human = @name.gsub(/(?<=.)[A-Z]/, "_\\0").downcase
- @values = config.fetch("values").map { |flag| Flag.new(flag) }
- @comment = config.fetch("comment")
- end
-
- def self.empty
- new("name" => "", "values" => [], "comment" => "")
- end
- end
-
- class << self
- # This templates out a file using ERB with the given locals. The locals are
- # derived from the config.yml file.
- def render(name, write_to: nil)
- filepath = "templates/#{name}.erb"
- template = File.expand_path("../#{filepath}", __dir__)
-
- erb = read_template(template)
- extension = File.extname(filepath.gsub(".erb", ""))
-
- heading =
- case extension
- when ".rb"
- <<~HEADING
- # frozen_string_literal: true
-
- =begin
- This file is generated by the templates/template.rb script and should not be
- modified manually. See #{filepath}
- if you are looking to modify the template
- =end
-
- HEADING
- when ".rbs"
- <<~HEADING
- # This file is generated by the templates/template.rb script and should not be
- # modified manually. See #{filepath}
- # if you are looking to modify the template
-
- HEADING
- when ".rbi"
- <<~HEADING
- # typed: strict
-
- =begin
- This file is generated by the templates/template.rb script and should not be
- modified manually. See #{filepath}
- if you are looking to modify the template
- =end
-
- HEADING
- else
- <<~HEADING
- /*----------------------------------------------------------------------------*/
- /* This file is generated by the templates/template.rb script and should not */
- /* be modified manually. See */
- /* #{filepath + " " * (74 - filepath.size) } */
- /* if you are looking to modify the */
- /* template */
- /*----------------------------------------------------------------------------*/
-
- HEADING
- end
-
- write_to ||= File.expand_path("../#{name}", __dir__)
- contents = heading + erb.result_with_hash(locals)
-
- if (extension == ".c" || extension == ".h") && !contents.ascii_only?
- # Enforce that we only have ASCII characters here. This is necessary
- # for non-UTF-8 locales that only allow ASCII characters in C source
- # files.
- contents.each_line.with_index(1) do |line, line_number|
- raise "Non-ASCII character on line #{line_number} of #{write_to}" unless line.ascii_only?
- end
- end
-
- FileUtils.mkdir_p(File.dirname(write_to))
- File.write(write_to, contents)
- end
-
- private
-
- def read_template(filepath)
- template = File.read(filepath, encoding: Encoding::UTF_8)
- erb = erb(template)
- erb.filename = filepath
- erb
- end
-
- def erb(template)
- ERB.new(template, trim_mode: "-")
- end
-
- def locals
- @locals ||=
- begin
- config = YAML.load_file(File.expand_path("../config.yml", __dir__))
- flags = config.fetch("flags").to_h { |flags| [flags["name"], Flags.new(flags)] }
-
- {
- errors: config.fetch("errors").map { |name| Error.new(name) },
- warnings: config.fetch("warnings").map { |name| Warning.new(name) },
- nodes: config.fetch("nodes").map { |node| NodeType.new(node, flags) }.sort_by(&:name),
- tokens: config.fetch("tokens").map { |token| Token.new(token) },
- flags: flags.values
- }
- end
- end
- end
-
- TEMPLATES = [
- "ext/prism/api_node.c",
- "include/prism/ast.h",
- "include/prism/diagnostic.h",
- "javascript/src/deserialize.js",
- "javascript/src/nodes.js",
- "javascript/src/visitor.js",
- "java/org/prism/Loader.java",
- "java/org/prism/Nodes.java",
- "java/org/prism/AbstractNodeVisitor.java",
- "lib/prism/compiler.rb",
- "lib/prism/dispatcher.rb",
- "lib/prism/dot_visitor.rb",
- "lib/prism/dsl.rb",
- "lib/prism/inspect_visitor.rb",
- "lib/prism/mutation_compiler.rb",
- "lib/prism/node.rb",
- "lib/prism/reflection.rb",
- "lib/prism/serialize.rb",
- "lib/prism/visitor.rb",
- "src/diagnostic.c",
- "src/node.c",
- "src/prettyprint.c",
- "src/serialize.c",
- "src/token_type.c",
- "rbi/prism/dsl.rbi",
- "rbi/prism/node.rbi",
- "rbi/prism/visitor.rbi",
- "sig/prism.rbs",
- "sig/prism/dsl.rbs",
- "sig/prism/mutation_compiler.rbs",
- "sig/prism/node.rbs",
- "sig/prism/visitor.rbs",
- "sig/prism/_private/dot_visitor.rbs"
- ]
- end
-end
-
-if __FILE__ == $0
- if ARGV.empty?
- Prism::Template::TEMPLATES.each { |filepath| Prism::Template.render(filepath) }
- else # ruby/ruby
- name, write_to = ARGV
- Prism::Template.render(name, write_to: write_to)
- end
-end
diff --git a/prism/util/pm_buffer.c b/prism/util/pm_buffer.c
deleted file mode 100644
index 1e79e46718..0000000000
--- a/prism/util/pm_buffer.c
+++ /dev/null
@@ -1,317 +0,0 @@
-#include "prism/util/pm_buffer.h"
-
-/**
- * Return the size of the pm_buffer_t struct.
- */
-size_t
-pm_buffer_sizeof(void) {
- return sizeof(pm_buffer_t);
-}
-
-/**
- * Initialize a pm_buffer_t with the given capacity.
- */
-bool
-pm_buffer_init_capacity(pm_buffer_t *buffer, size_t capacity) {
- buffer->length = 0;
- buffer->capacity = capacity;
-
- buffer->value = (char *) xmalloc(capacity);
- return buffer->value != NULL;
-}
-
-/**
- * Initialize a pm_buffer_t with its default values.
- */
-bool
-pm_buffer_init(pm_buffer_t *buffer) {
- return pm_buffer_init_capacity(buffer, 1024);
-}
-
-/**
- * Return the value of the buffer.
- */
-char *
-pm_buffer_value(const pm_buffer_t *buffer) {
- return buffer->value;
-}
-
-/**
- * Return the length of the buffer.
- */
-size_t
-pm_buffer_length(const pm_buffer_t *buffer) {
- return buffer->length;
-}
-
-/**
- * Append the given amount of space to the buffer.
- */
-static inline bool
-pm_buffer_append_length(pm_buffer_t *buffer, size_t length) {
- size_t next_length = buffer->length + length;
-
- if (next_length > buffer->capacity) {
- if (buffer->capacity == 0) {
- buffer->capacity = 1;
- }
-
- while (next_length > buffer->capacity) {
- buffer->capacity *= 2;
- }
-
- buffer->value = xrealloc(buffer->value, buffer->capacity);
- if (buffer->value == NULL) return false;
- }
-
- buffer->length = next_length;
- return true;
-}
-
-/**
- * Append a generic pointer to memory to the buffer.
- */
-static inline void
-pm_buffer_append(pm_buffer_t *buffer, const void *source, size_t length) {
- size_t cursor = buffer->length;
- if (pm_buffer_append_length(buffer, length)) {
- memcpy(buffer->value + cursor, source, length);
- }
-}
-
-/**
- * Append the given amount of space as zeroes to the buffer.
- */
-void
-pm_buffer_append_zeroes(pm_buffer_t *buffer, size_t length) {
- size_t cursor = buffer->length;
- if (pm_buffer_append_length(buffer, length)) {
- memset(buffer->value + cursor, 0, length);
- }
-}
-
-/**
- * Append a formatted string to the buffer.
- */
-void
-pm_buffer_append_format(pm_buffer_t *buffer, const char *format, ...) {
- va_list arguments;
- va_start(arguments, format);
- int result = vsnprintf(NULL, 0, format, arguments);
- va_end(arguments);
-
- if (result < 0) return;
- size_t length = (size_t) (result + 1);
-
- size_t cursor = buffer->length;
- if (pm_buffer_append_length(buffer, length)) {
- va_start(arguments, format);
- vsnprintf(buffer->value + cursor, length, format, arguments);
- va_end(arguments);
- buffer->length--;
- }
-}
-
-/**
- * Append a string to the buffer.
- */
-void
-pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t length) {
- pm_buffer_append(buffer, value, length);
-}
-
-/**
- * Append a list of bytes to the buffer.
- */
-void
-pm_buffer_append_bytes(pm_buffer_t *buffer, const uint8_t *value, size_t length) {
- pm_buffer_append(buffer, (const char *) value, length);
-}
-
-/**
- * Append a single byte to the buffer.
- */
-void
-pm_buffer_append_byte(pm_buffer_t *buffer, uint8_t value) {
- const void *source = &value;
- pm_buffer_append(buffer, source, sizeof(uint8_t));
-}
-
-/**
- * Append a 32-bit unsigned integer to the buffer as a variable-length integer.
- */
-void
-pm_buffer_append_varuint(pm_buffer_t *buffer, uint32_t value) {
- if (value < 128) {
- pm_buffer_append_byte(buffer, (uint8_t) value);
- } else {
- uint32_t n = value;
- while (n >= 128) {
- pm_buffer_append_byte(buffer, (uint8_t) (n | 128));
- n >>= 7;
- }
- pm_buffer_append_byte(buffer, (uint8_t) n);
- }
-}
-
-/**
- * Append a 32-bit signed integer to the buffer as a variable-length integer.
- */
-void
-pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value) {
- uint32_t unsigned_int = ((uint32_t)(value) << 1) ^ ((uint32_t)(value >> 31));
- pm_buffer_append_varuint(buffer, unsigned_int);
-}
-
-/**
- * Append a double to the buffer.
- */
-void
-pm_buffer_append_double(pm_buffer_t *buffer, double value) {
- const void *source = &value;
- pm_buffer_append(buffer, source, sizeof(double));
-}
-
-/**
- * Append a slice of source code to the buffer.
- */
-void
-pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping) {
- for (size_t index = 0; index < length; index++) {
- const uint8_t byte = source[index];
-
- if ((byte <= 0x06) || (byte >= 0x0E && byte <= 0x1F) || (byte >= 0x7F)) {
- if (escaping == PM_BUFFER_ESCAPING_RUBY) {
- pm_buffer_append_format(buffer, "\\x%02X", byte);
- } else {
- pm_buffer_append_format(buffer, "\\u%04X", byte);
- }
- } else {
- switch (byte) {
- case '\a':
- if (escaping == PM_BUFFER_ESCAPING_RUBY) {
- pm_buffer_append_string(buffer, "\\a", 2);
- } else {
- pm_buffer_append_format(buffer, "\\u%04X", byte);
- }
- break;
- case '\b':
- pm_buffer_append_string(buffer, "\\b", 2);
- break;
- case '\t':
- pm_buffer_append_string(buffer, "\\t", 2);
- break;
- case '\n':
- pm_buffer_append_string(buffer, "\\n", 2);
- break;
- case '\v':
- if (escaping == PM_BUFFER_ESCAPING_RUBY) {
- pm_buffer_append_string(buffer, "\\v", 2);
- } else {
- pm_buffer_append_format(buffer, "\\u%04X", byte);
- }
- break;
- case '\f':
- pm_buffer_append_string(buffer, "\\f", 2);
- break;
- case '\r':
- pm_buffer_append_string(buffer, "\\r", 2);
- break;
- case '"':
- pm_buffer_append_string(buffer, "\\\"", 2);
- break;
- case '#': {
- if (escaping == PM_BUFFER_ESCAPING_RUBY && index + 1 < length) {
- const uint8_t next_byte = source[index + 1];
- if (next_byte == '{' || next_byte == '@' || next_byte == '$') {
- pm_buffer_append_byte(buffer, '\\');
- }
- }
-
- pm_buffer_append_byte(buffer, '#');
- break;
- }
- case '\\':
- pm_buffer_append_string(buffer, "\\\\", 2);
- break;
- default:
- pm_buffer_append_byte(buffer, byte);
- break;
- }
- }
- }
-}
-
-/**
- * Prepend the given string to the buffer.
- */
-void
-pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length) {
- size_t cursor = buffer->length;
- if (pm_buffer_append_length(buffer, length)) {
- memmove(buffer->value + length, buffer->value, cursor);
- memcpy(buffer->value, value, length);
- }
-}
-
-/**
- * Concatenate one buffer onto another.
- */
-void
-pm_buffer_concat(pm_buffer_t *destination, const pm_buffer_t *source) {
- if (source->length > 0) {
- pm_buffer_append(destination, source->value, source->length);
- }
-}
-
-/**
- * Clear the buffer by reducing its size to 0. This does not free the allocated
- * memory, but it does allow the buffer to be reused.
- */
-void
-pm_buffer_clear(pm_buffer_t *buffer) {
- buffer->length = 0;
-}
-
-/**
- * Strip the whitespace from the end of the buffer.
- */
-void
-pm_buffer_rstrip(pm_buffer_t *buffer) {
- while (buffer->length > 0 && pm_char_is_whitespace((uint8_t) buffer->value[buffer->length - 1])) {
- buffer->length--;
- }
-}
-
-/**
- * Checks if the buffer includes the given value.
- */
-size_t
-pm_buffer_index(const pm_buffer_t *buffer, char value) {
- const char *first = memchr(buffer->value, value, buffer->length);
- return (first == NULL) ? SIZE_MAX : (size_t) (first - buffer->value);
-}
-
-/**
- * Insert the given string into the buffer at the given index.
- */
-void
-pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length) {
- assert(index <= buffer->length);
-
- if (index == buffer->length) {
- pm_buffer_append_string(buffer, value, length);
- } else {
- pm_buffer_append_zeroes(buffer, length);
- memmove(buffer->value + index + length, buffer->value + index, buffer->length - length - index);
- memcpy(buffer->value + index, value, length);
- }
-}
-
-/**
- * Free the memory associated with the buffer.
- */
-void
-pm_buffer_free(pm_buffer_t *buffer) {
- xfree(buffer->value);
-}
diff --git a/prism/util/pm_buffer.h b/prism/util/pm_buffer.h
deleted file mode 100644
index 58f7b506cf..0000000000
--- a/prism/util/pm_buffer.h
+++ /dev/null
@@ -1,218 +0,0 @@
-/**
- * @file pm_buffer.h
- *
- * A wrapper around a contiguous block of allocated memory.
- */
-#ifndef PRISM_BUFFER_H
-#define PRISM_BUFFER_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_char.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-/**
- * A pm_buffer_t is a simple memory buffer that stores data in a contiguous
- * block of memory.
- */
-typedef struct {
- /** The length of the buffer in bytes. */
- size_t length;
-
- /** The capacity of the buffer in bytes that has been allocated. */
- size_t capacity;
-
- /** A pointer to the start of the buffer. */
- char *value;
-} pm_buffer_t;
-
-/**
- * Return the size of the pm_buffer_t struct.
- *
- * @returns The size of the pm_buffer_t struct.
- */
-PRISM_EXPORTED_FUNCTION size_t pm_buffer_sizeof(void);
-
-/**
- * Initialize a pm_buffer_t with the given capacity.
- *
- * @param buffer The buffer to initialize.
- * @param capacity The capacity of the buffer.
- * @returns True if the buffer was initialized successfully, false otherwise.
- */
-bool pm_buffer_init_capacity(pm_buffer_t *buffer, size_t capacity);
-
-/**
- * Initialize a pm_buffer_t with its default values.
- *
- * @param buffer The buffer to initialize.
- * @returns True if the buffer was initialized successfully, false otherwise.
- */
-PRISM_EXPORTED_FUNCTION bool pm_buffer_init(pm_buffer_t *buffer);
-
-/**
- * Return the value of the buffer.
- *
- * @param buffer The buffer to get the value of.
- * @returns The value of the buffer.
- */
-PRISM_EXPORTED_FUNCTION char * pm_buffer_value(const pm_buffer_t *buffer);
-
-/**
- * Return the length of the buffer.
- *
- * @param buffer The buffer to get the length of.
- * @returns The length of the buffer.
- */
-PRISM_EXPORTED_FUNCTION size_t pm_buffer_length(const pm_buffer_t *buffer);
-
-/**
- * Append the given amount of space as zeroes to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param length The amount of space to append and zero.
- */
-void pm_buffer_append_zeroes(pm_buffer_t *buffer, size_t length);
-
-/**
- * Append a formatted string to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param format The format string to append.
- * @param ... The arguments to the format string.
- */
-void pm_buffer_append_format(pm_buffer_t *buffer, const char *format, ...) PRISM_ATTRIBUTE_FORMAT(2, 3);
-
-/**
- * Append a string to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param value The string to append.
- * @param length The length of the string to append.
- */
-void pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t length);
-
-/**
- * Append a list of bytes to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param value The bytes to append.
- * @param length The length of the bytes to append.
- */
-void pm_buffer_append_bytes(pm_buffer_t *buffer, const uint8_t *value, size_t length);
-
-/**
- * Append a single byte to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param value The byte to append.
- */
-void pm_buffer_append_byte(pm_buffer_t *buffer, uint8_t value);
-
-/**
- * Append a 32-bit unsigned integer to the buffer as a variable-length integer.
- *
- * @param buffer The buffer to append to.
- * @param value The integer to append.
- */
-void pm_buffer_append_varuint(pm_buffer_t *buffer, uint32_t value);
-
-/**
- * Append a 32-bit signed integer to the buffer as a variable-length integer.
- *
- * @param buffer The buffer to append to.
- * @param value The integer to append.
- */
-void pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value);
-
-/**
- * Append a double to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param value The double to append.
- */
-void pm_buffer_append_double(pm_buffer_t *buffer, double value);
-
-/**
- * The different types of escaping that can be performed by the buffer when
- * appending a slice of Ruby source code.
- */
-typedef enum {
- PM_BUFFER_ESCAPING_RUBY,
- PM_BUFFER_ESCAPING_JSON
-} pm_buffer_escaping_t;
-
-/**
- * Append a slice of source code to the buffer.
- *
- * @param buffer The buffer to append to.
- * @param source The source code to append.
- * @param length The length of the source code to append.
- * @param escaping The type of escaping to perform.
- */
-void pm_buffer_append_source(pm_buffer_t *buffer, const uint8_t *source, size_t length, pm_buffer_escaping_t escaping);
-
-/**
- * Prepend the given string to the buffer.
- *
- * @param buffer The buffer to prepend to.
- * @param value The string to prepend.
- * @param length The length of the string to prepend.
- */
-void pm_buffer_prepend_string(pm_buffer_t *buffer, const char *value, size_t length);
-
-/**
- * Concatenate one buffer onto another.
- *
- * @param destination The buffer to concatenate onto.
- * @param source The buffer to concatenate.
- */
-void pm_buffer_concat(pm_buffer_t *destination, const pm_buffer_t *source);
-
-/**
- * Clear the buffer by reducing its size to 0. This does not free the allocated
- * memory, but it does allow the buffer to be reused.
- *
- * @param buffer The buffer to clear.
- */
-void pm_buffer_clear(pm_buffer_t *buffer);
-
-/**
- * Strip the whitespace from the end of the buffer.
- *
- * @param buffer The buffer to strip.
- */
-void pm_buffer_rstrip(pm_buffer_t *buffer);
-
-/**
- * Checks if the buffer includes the given value.
- *
- * @param buffer The buffer to check.
- * @param value The value to check for.
- * @returns The index of the first occurrence of the value in the buffer, or
- * SIZE_MAX if the value is not found.
- */
-size_t pm_buffer_index(const pm_buffer_t *buffer, char value);
-
-/**
- * Insert the given string into the buffer at the given index.
- *
- * @param buffer The buffer to insert into.
- * @param index The index to insert at.
- * @param value The string to insert.
- * @param length The length of the string to insert.
- */
-void pm_buffer_insert(pm_buffer_t *buffer, size_t index, const char *value, size_t length);
-
-/**
- * Free the memory associated with the buffer.
- *
- * @param buffer The buffer to free.
- */
-PRISM_EXPORTED_FUNCTION void pm_buffer_free(pm_buffer_t *buffer);
-
-#endif
diff --git a/prism/util/pm_char.c b/prism/util/pm_char.c
deleted file mode 100644
index dce19abd1b..0000000000
--- a/prism/util/pm_char.c
+++ /dev/null
@@ -1,318 +0,0 @@
-#include "prism/util/pm_char.h"
-
-#define PRISM_CHAR_BIT_WHITESPACE (1 << 0)
-#define PRISM_CHAR_BIT_INLINE_WHITESPACE (1 << 1)
-#define PRISM_CHAR_BIT_REGEXP_OPTION (1 << 2)
-
-#define PRISM_NUMBER_BIT_BINARY_DIGIT (1 << 0)
-#define PRISM_NUMBER_BIT_BINARY_NUMBER (1 << 1)
-#define PRISM_NUMBER_BIT_OCTAL_DIGIT (1 << 2)
-#define PRISM_NUMBER_BIT_OCTAL_NUMBER (1 << 3)
-#define PRISM_NUMBER_BIT_DECIMAL_DIGIT (1 << 4)
-#define PRISM_NUMBER_BIT_DECIMAL_NUMBER (1 << 5)
-#define PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT (1 << 6)
-#define PRISM_NUMBER_BIT_HEXADECIMAL_NUMBER (1 << 7)
-
-static const uint8_t pm_byte_table[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 3, 3, 3, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3x
- 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 4x
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 5x
- 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 6x
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Fx
-};
-
-static const uint8_t pm_number_table[256] = {
- // 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 1x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 2x
- 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 3x
- 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 4x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, // 5x
- 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 6x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 7x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9x
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Ax
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Bx
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Cx
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Dx
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Ex
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Fx
-};
-
-/**
- * Returns the number of characters at the start of the string that match the
- * given kind. Disallows searching past the given maximum number of characters.
- */
-static inline size_t
-pm_strspn_char_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) {
- if (length <= 0) return 0;
-
- size_t size = 0;
- size_t maximum = (size_t) length;
-
- while (size < maximum && (pm_byte_table[string[size]] & kind)) size++;
- return size;
-}
-
-/**
- * Returns the number of characters at the start of the string that are
- * whitespace. Disallows searching past the given maximum number of characters.
- */
-size_t
-pm_strspn_whitespace(const uint8_t *string, ptrdiff_t length) {
- return pm_strspn_char_kind(string, length, PRISM_CHAR_BIT_WHITESPACE);
-}
-
-/**
- * Returns the number of characters at the start of the string that are
- * whitespace while also tracking the location of each newline. Disallows
- * searching past the given maximum number of characters.
- */
-size_t
-pm_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, pm_newline_list_t *newline_list) {
- if (length <= 0) return 0;
-
- size_t size = 0;
- size_t maximum = (size_t) length;
-
- while (size < maximum && (pm_byte_table[string[size]] & PRISM_CHAR_BIT_WHITESPACE)) {
- if (string[size] == '\n') {
- pm_newline_list_append(newline_list, string + size);
- }
-
- size++;
- }
-
- return size;
-}
-
-/**
- * Returns the number of characters at the start of the string that are inline
- * whitespace. Disallows searching past the given maximum number of characters.
- */
-size_t
-pm_strspn_inline_whitespace(const uint8_t *string, ptrdiff_t length) {
- return pm_strspn_char_kind(string, length, PRISM_CHAR_BIT_INLINE_WHITESPACE);
-}
-
-/**
- * Returns the number of characters at the start of the string that are regexp
- * options. Disallows searching past the given maximum number of characters.
- */
-size_t
-pm_strspn_regexp_option(const uint8_t *string, ptrdiff_t length) {
- return pm_strspn_char_kind(string, length, PRISM_CHAR_BIT_REGEXP_OPTION);
-}
-
-/**
- * Returns true if the given character matches the given kind.
- */
-static inline bool
-pm_char_is_char_kind(const uint8_t b, uint8_t kind) {
- return (pm_byte_table[b] & kind) != 0;
-}
-
-/**
- * Returns true if the given character is a whitespace character.
- */
-bool
-pm_char_is_whitespace(const uint8_t b) {
- return pm_char_is_char_kind(b, PRISM_CHAR_BIT_WHITESPACE);
-}
-
-/**
- * Returns true if the given character is an inline whitespace character.
- */
-bool
-pm_char_is_inline_whitespace(const uint8_t b) {
- return pm_char_is_char_kind(b, PRISM_CHAR_BIT_INLINE_WHITESPACE);
-}
-
-/**
- * Scan through the string and return the number of characters at the start of
- * the string that match the given kind. Disallows searching past the given
- * maximum number of characters.
- */
-static inline size_t
-pm_strspn_number_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) {
- if (length <= 0) return 0;
-
- size_t size = 0;
- size_t maximum = (size_t) length;
-
- while (size < maximum && (pm_number_table[string[size]] & kind)) size++;
- return size;
-}
-
-/**
- * Scan through the string and return the number of characters at the start of
- * the string that match the given kind. Disallows searching past the given
- * maximum number of characters.
- *
- * Additionally, report the location of the last invalid underscore character
- * found in the string through the out invalid parameter.
- */
-static inline size_t
-pm_strspn_number_kind_underscores(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid, uint8_t kind) {
- if (length <= 0) return 0;
-
- size_t size = 0;
- size_t maximum = (size_t) length;
-
- bool underscore = false;
- while (size < maximum && (pm_number_table[string[size]] & kind)) {
- if (string[size] == '_') {
- if (underscore) *invalid = string + size;
- underscore = true;
- } else {
- underscore = false;
- }
-
- size++;
- }
-
- if (string[size - 1] == '_') *invalid = string + size - 1;
- return size;
-}
-
-/**
- * Returns the number of characters at the start of the string that are binary
- * digits or underscores. Disallows searching past the given maximum number of
- * characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- */
-size_t
-pm_strspn_binary_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
- return pm_strspn_number_kind_underscores(string, length, invalid, PRISM_NUMBER_BIT_BINARY_NUMBER);
-}
-
-/**
- * Returns the number of characters at the start of the string that are octal
- * digits or underscores. Disallows searching past the given maximum number of
- * characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- */
-size_t
-pm_strspn_octal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
- return pm_strspn_number_kind_underscores(string, length, invalid, PRISM_NUMBER_BIT_OCTAL_NUMBER);
-}
-
-/**
- * Returns the number of characters at the start of the string that are decimal
- * digits. Disallows searching past the given maximum number of characters.
- */
-size_t
-pm_strspn_decimal_digit(const uint8_t *string, ptrdiff_t length) {
- return pm_strspn_number_kind(string, length, PRISM_NUMBER_BIT_DECIMAL_DIGIT);
-}
-
-/**
- * Returns the number of characters at the start of the string that are decimal
- * digits or underscores. Disallows searching past the given maximum number of
- * characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore
- */
-size_t
-pm_strspn_decimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
- return pm_strspn_number_kind_underscores(string, length, invalid, PRISM_NUMBER_BIT_DECIMAL_NUMBER);
-}
-
-/**
- * Returns the number of characters at the start of the string that are
- * hexadecimal digits. Disallows searching past the given maximum number of
- * characters.
- */
-size_t
-pm_strspn_hexadecimal_digit(const uint8_t *string, ptrdiff_t length) {
- return pm_strspn_number_kind(string, length, PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT);
-}
-
-/**
- * Returns the number of characters at the start of the string that are
- * hexadecimal digits or underscores. Disallows searching past the given maximum
- * number of characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- */
-size_t
-pm_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
- return pm_strspn_number_kind_underscores(string, length, invalid, PRISM_NUMBER_BIT_HEXADECIMAL_NUMBER);
-}
-
-/**
- * Returns true if the given character matches the given kind.
- */
-static inline bool
-pm_char_is_number_kind(const uint8_t b, uint8_t kind) {
- return (pm_number_table[b] & kind) != 0;
-}
-
-/**
- * Returns true if the given character is a binary digit.
- */
-bool
-pm_char_is_binary_digit(const uint8_t b) {
- return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_BINARY_DIGIT);
-}
-
-/**
- * Returns true if the given character is an octal digit.
- */
-bool
-pm_char_is_octal_digit(const uint8_t b) {
- return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_OCTAL_DIGIT);
-}
-
-/**
- * Returns true if the given character is a decimal digit.
- */
-bool
-pm_char_is_decimal_digit(const uint8_t b) {
- return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_DECIMAL_DIGIT);
-}
-
-/**
- * Returns true if the given character is a hexadecimal digit.
- */
-bool
-pm_char_is_hexadecimal_digit(const uint8_t b) {
- return pm_char_is_number_kind(b, PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT);
-}
-
-#undef PRISM_CHAR_BIT_WHITESPACE
-#undef PRISM_CHAR_BIT_INLINE_WHITESPACE
-#undef PRISM_CHAR_BIT_REGEXP_OPTION
-
-#undef PRISM_NUMBER_BIT_BINARY_DIGIT
-#undef PRISM_NUMBER_BIT_BINARY_NUMBER
-#undef PRISM_NUMBER_BIT_OCTAL_DIGIT
-#undef PRISM_NUMBER_BIT_OCTAL_NUMBER
-#undef PRISM_NUMBER_BIT_DECIMAL_DIGIT
-#undef PRISM_NUMBER_BIT_DECIMAL_NUMBER
-#undef PRISM_NUMBER_BIT_HEXADECIMAL_NUMBER
-#undef PRISM_NUMBER_BIT_HEXADECIMAL_DIGIT
diff --git a/prism/util/pm_char.h b/prism/util/pm_char.h
deleted file mode 100644
index deeafd6321..0000000000
--- a/prism/util/pm_char.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/**
- * @file pm_char.h
- *
- * Functions for working with characters and strings.
- */
-#ifndef PRISM_CHAR_H
-#define PRISM_CHAR_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_newline_list.h"
-
-#include <stdbool.h>
-#include <stddef.h>
-
-/**
- * Returns the number of characters at the start of the string that are
- * whitespace. Disallows searching past the given maximum number of characters.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @return The number of characters at the start of the string that are
- * whitespace.
- */
-size_t pm_strspn_whitespace(const uint8_t *string, ptrdiff_t length);
-
-/**
- * Returns the number of characters at the start of the string that are
- * whitespace while also tracking the location of each newline. Disallows
- * searching past the given maximum number of characters.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @param newline_list The list of newlines to populate.
- * @return The number of characters at the start of the string that are
- * whitespace.
- */
-size_t pm_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, pm_newline_list_t *newline_list);
-
-/**
- * Returns the number of characters at the start of the string that are inline
- * whitespace. Disallows searching past the given maximum number of characters.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @return The number of characters at the start of the string that are inline
- * whitespace.
- */
-size_t pm_strspn_inline_whitespace(const uint8_t *string, ptrdiff_t length);
-
-/**
- * Returns the number of characters at the start of the string that are decimal
- * digits. Disallows searching past the given maximum number of characters.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @return The number of characters at the start of the string that are decimal
- * digits.
- */
-size_t pm_strspn_decimal_digit(const uint8_t *string, ptrdiff_t length);
-
-/**
- * Returns the number of characters at the start of the string that are
- * hexadecimal digits. Disallows searching past the given maximum number of
- * characters.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @return The number of characters at the start of the string that are
- * hexadecimal digits.
- */
-size_t pm_strspn_hexadecimal_digit(const uint8_t *string, ptrdiff_t length);
-
-/**
- * Returns the number of characters at the start of the string that are octal
- * digits or underscores. Disallows searching past the given maximum number of
- * characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @param invalid The pointer to set to the index of the first invalid
- * underscore.
- * @return The number of characters at the start of the string that are octal
- * digits or underscores.
- */
-size_t pm_strspn_octal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid);
-
-/**
- * Returns the number of characters at the start of the string that are decimal
- * digits or underscores. Disallows searching past the given maximum number of
- * characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @param invalid The pointer to set to the index of the first invalid
- * underscore.
- * @return The number of characters at the start of the string that are decimal
- * digits or underscores.
- */
-size_t pm_strspn_decimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid);
-
-/**
- * Returns the number of characters at the start of the string that are
- * hexadecimal digits or underscores. Disallows searching past the given maximum
- * number of characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @param invalid The pointer to set to the index of the first invalid
- * underscore.
- * @return The number of characters at the start of the string that are
- * hexadecimal digits or underscores.
- */
-size_t pm_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid);
-
-/**
- * Returns the number of characters at the start of the string that are regexp
- * options. Disallows searching past the given maximum number of characters.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @return The number of characters at the start of the string that are regexp
- * options.
- */
-size_t pm_strspn_regexp_option(const uint8_t *string, ptrdiff_t length);
-
-/**
- * Returns the number of characters at the start of the string that are binary
- * digits or underscores. Disallows searching past the given maximum number of
- * characters.
- *
- * If multiple underscores are found in a row or if an underscore is
- * found at the end of the number, then the invalid pointer is set to the index
- * of the first invalid underscore.
- *
- * @param string The string to search.
- * @param length The maximum number of characters to search.
- * @param invalid The pointer to set to the index of the first invalid
- * underscore.
- * @return The number of characters at the start of the string that are binary
- * digits or underscores.
- */
-size_t pm_strspn_binary_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid);
-
-/**
- * Returns true if the given character is a whitespace character.
- *
- * @param b The character to check.
- * @return True if the given character is a whitespace character.
- */
-bool pm_char_is_whitespace(const uint8_t b);
-
-/**
- * Returns true if the given character is an inline whitespace character.
- *
- * @param b The character to check.
- * @return True if the given character is an inline whitespace character.
- */
-bool pm_char_is_inline_whitespace(const uint8_t b);
-
-/**
- * Returns true if the given character is a binary digit.
- *
- * @param b The character to check.
- * @return True if the given character is a binary digit.
- */
-bool pm_char_is_binary_digit(const uint8_t b);
-
-/**
- * Returns true if the given character is an octal digit.
- *
- * @param b The character to check.
- * @return True if the given character is an octal digit.
- */
-bool pm_char_is_octal_digit(const uint8_t b);
-
-/**
- * Returns true if the given character is a decimal digit.
- *
- * @param b The character to check.
- * @return True if the given character is a decimal digit.
- */
-bool pm_char_is_decimal_digit(const uint8_t b);
-
-/**
- * Returns true if the given character is a hexadecimal digit.
- *
- * @param b The character to check.
- * @return True if the given character is a hexadecimal digit.
- */
-bool pm_char_is_hexadecimal_digit(const uint8_t b);
-
-#endif
diff --git a/prism/util/pm_constant_pool.c b/prism/util/pm_constant_pool.c
deleted file mode 100644
index 624002cec9..0000000000
--- a/prism/util/pm_constant_pool.c
+++ /dev/null
@@ -1,338 +0,0 @@
-#include "prism/util/pm_constant_pool.h"
-
-/**
- * Initialize a list of constant ids.
- */
-void
-pm_constant_id_list_init(pm_constant_id_list_t *list) {
- list->ids = NULL;
- list->size = 0;
- list->capacity = 0;
-}
-
-/**
- * Initialize a list of constant ids with a given capacity.
- */
-void
-pm_constant_id_list_init_capacity(pm_constant_id_list_t *list, size_t capacity) {
- list->ids = xcalloc(capacity, sizeof(pm_constant_id_t));
- if (list->ids == NULL) abort();
-
- list->size = 0;
- list->capacity = capacity;
-}
-
-/**
- * Append a constant id to a list of constant ids. Returns false if any
- * potential reallocations fail.
- */
-bool
-pm_constant_id_list_append(pm_constant_id_list_t *list, pm_constant_id_t id) {
- if (list->size >= list->capacity) {
- list->capacity = list->capacity == 0 ? 8 : list->capacity * 2;
- list->ids = (pm_constant_id_t *) xrealloc(list->ids, sizeof(pm_constant_id_t) * list->capacity);
- if (list->ids == NULL) return false;
- }
-
- list->ids[list->size++] = id;
- return true;
-}
-
-/**
- * Insert a constant id into a list of constant ids at the specified index.
- */
-void
-pm_constant_id_list_insert(pm_constant_id_list_t *list, size_t index, pm_constant_id_t id) {
- assert(index < list->capacity);
- assert(list->ids[index] == PM_CONSTANT_ID_UNSET);
-
- list->ids[index] = id;
- list->size++;
-}
-
-/**
- * Checks if the current constant id list includes the given constant id.
- */
-bool
-pm_constant_id_list_includes(pm_constant_id_list_t *list, pm_constant_id_t id) {
- for (size_t index = 0; index < list->size; index++) {
- if (list->ids[index] == id) return true;
- }
- return false;
-}
-
-/**
- * Free the memory associated with a list of constant ids.
- */
-void
-pm_constant_id_list_free(pm_constant_id_list_t *list) {
- if (list->ids != NULL) {
- xfree(list->ids);
- }
-}
-
-/**
- * A relatively simple hash function (djb2) that is used to hash strings. We are
- * optimizing here for simplicity and speed.
- */
-static inline uint32_t
-pm_constant_pool_hash(const uint8_t *start, size_t length) {
- // This is a prime number used as the initial value for the hash function.
- uint32_t value = 5381;
-
- for (size_t index = 0; index < length; index++) {
- value = ((value << 5) + value) + start[index];
- }
-
- return value;
-}
-
-/**
- * https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
- */
-static uint32_t
-next_power_of_two(uint32_t v) {
- // Avoid underflow in subtraction on next line.
- if (v == 0) {
- // 1 is the nearest power of 2 to 0 (2^0)
- return 1;
- }
- v--;
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
- v |= v >> 8;
- v |= v >> 16;
- v++;
- return v;
-}
-
-#ifndef NDEBUG
-static bool
-is_power_of_two(uint32_t size) {
- return (size & (size - 1)) == 0;
-}
-#endif
-
-/**
- * Resize a constant pool to a given capacity.
- */
-static inline bool
-pm_constant_pool_resize(pm_constant_pool_t *pool) {
- assert(is_power_of_two(pool->capacity));
-
- uint32_t next_capacity = pool->capacity * 2;
- if (next_capacity < pool->capacity) return false;
-
- const uint32_t mask = next_capacity - 1;
- const size_t element_size = sizeof(pm_constant_pool_bucket_t) + sizeof(pm_constant_t);
-
- void *next = xcalloc(next_capacity, element_size);
- if (next == NULL) return false;
-
- pm_constant_pool_bucket_t *next_buckets = next;
- pm_constant_t *next_constants = (void *)(((char *) next) + next_capacity * sizeof(pm_constant_pool_bucket_t));
-
- // For each bucket in the current constant pool, find the index in the
- // next constant pool, and insert it.
- for (uint32_t index = 0; index < pool->capacity; index++) {
- pm_constant_pool_bucket_t *bucket = &pool->buckets[index];
-
- // If an id is set on this constant, then we know we have content here.
- // In this case we need to insert it into the next constant pool.
- if (bucket->id != PM_CONSTANT_ID_UNSET) {
- uint32_t next_index = bucket->hash & mask;
-
- // This implements linear scanning to find the next available slot
- // in case this index is already taken. We don't need to bother
- // comparing the values since we know that the hash is unique.
- while (next_buckets[next_index].id != PM_CONSTANT_ID_UNSET) {
- next_index = (next_index + 1) & mask;
- }
-
- // Here we copy over the entire bucket, which includes the id so
- // that they are consistent between resizes.
- next_buckets[next_index] = *bucket;
- }
- }
-
- // The constants are stable with respect to hash table resizes.
- memcpy(next_constants, pool->constants, pool->size * sizeof(pm_constant_t));
-
- // pool->constants and pool->buckets are allocated out of the same chunk
- // of memory, with the buckets coming first.
- xfree(pool->buckets);
- pool->constants = next_constants;
- pool->buckets = next_buckets;
- pool->capacity = next_capacity;
- return true;
-}
-
-/**
- * Initialize a new constant pool with a given capacity.
- */
-bool
-pm_constant_pool_init(pm_constant_pool_t *pool, uint32_t capacity) {
- const uint32_t maximum = (~((uint32_t) 0));
- if (capacity >= ((maximum / 2) + 1)) return false;
-
- capacity = next_power_of_two(capacity);
- const size_t element_size = sizeof(pm_constant_pool_bucket_t) + sizeof(pm_constant_t);
- void *memory = xcalloc(capacity, element_size);
- if (memory == NULL) return false;
-
- pool->buckets = memory;
- pool->constants = (void *)(((char *)memory) + capacity * sizeof(pm_constant_pool_bucket_t));
- pool->size = 0;
- pool->capacity = capacity;
- return true;
-}
-
-/**
- * Return a pointer to the constant indicated by the given constant id.
- */
-pm_constant_t *
-pm_constant_pool_id_to_constant(const pm_constant_pool_t *pool, pm_constant_id_t constant_id) {
- assert(constant_id != PM_CONSTANT_ID_UNSET && constant_id <= pool->size);
- return &pool->constants[constant_id - 1];
-}
-
-/**
- * Find a constant in a constant pool. Returns the id of the constant, or 0 if
- * the constant is not found.
- */
-pm_constant_id_t
-pm_constant_pool_find(const pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
- assert(is_power_of_two(pool->capacity));
- const uint32_t mask = pool->capacity - 1;
-
- uint32_t hash = pm_constant_pool_hash(start, length);
- uint32_t index = hash & mask;
- pm_constant_pool_bucket_t *bucket;
-
- while (bucket = &pool->buckets[index], bucket->id != PM_CONSTANT_ID_UNSET) {
- pm_constant_t *constant = &pool->constants[bucket->id - 1];
- if ((constant->length == length) && memcmp(constant->start, start, length) == 0) {
- return bucket->id;
- }
-
- index = (index + 1) & mask;
- }
-
- return PM_CONSTANT_ID_UNSET;
-}
-
-/**
- * Insert a constant into a constant pool and return its index in the pool.
- */
-static inline pm_constant_id_t
-pm_constant_pool_insert(pm_constant_pool_t *pool, const uint8_t *start, size_t length, pm_constant_pool_bucket_type_t type) {
- if (pool->size >= (pool->capacity / 4 * 3)) {
- if (!pm_constant_pool_resize(pool)) return PM_CONSTANT_ID_UNSET;
- }
-
- assert(is_power_of_two(pool->capacity));
- const uint32_t mask = pool->capacity - 1;
-
- uint32_t hash = pm_constant_pool_hash(start, length);
- uint32_t index = hash & mask;
- pm_constant_pool_bucket_t *bucket;
-
- while (bucket = &pool->buckets[index], bucket->id != PM_CONSTANT_ID_UNSET) {
- // If there is a collision, then we need to check if the content is the
- // same as the content we are trying to insert. If it is, then we can
- // return the id of the existing constant.
- pm_constant_t *constant = &pool->constants[bucket->id - 1];
-
- if ((constant->length == length) && memcmp(constant->start, start, length) == 0) {
- // Since we have found a match, we need to check if this is
- // attempting to insert a shared or an owned constant. We want to
- // prefer shared constants since they don't require allocations.
- if (type == PM_CONSTANT_POOL_BUCKET_OWNED) {
- // If we're attempting to insert an owned constant and we have
- // an existing constant, then either way we don't want the given
- // memory. Either it's duplicated with the existing constant or
- // it's not necessary because we have a shared version.
- xfree((void *) start);
- } else if (bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED) {
- // If we're attempting to insert a shared constant and the
- // existing constant is owned, then we can free the owned
- // constant and replace it with the shared constant.
- xfree((void *) constant->start);
- constant->start = start;
- bucket->type = (unsigned int) (PM_CONSTANT_POOL_BUCKET_DEFAULT & 0x3);
- }
-
- return bucket->id;
- }
-
- index = (index + 1) & mask;
- }
-
- // IDs are allocated starting at 1, since the value 0 denotes a non-existent
- // constant.
- uint32_t id = ++pool->size;
- assert(pool->size < ((uint32_t) (1 << 30)));
-
- *bucket = (pm_constant_pool_bucket_t) {
- .id = (unsigned int) (id & 0x3fffffff),
- .type = (unsigned int) (type & 0x3),
- .hash = hash
- };
-
- pool->constants[id - 1] = (pm_constant_t) {
- .start = start,
- .length = length,
- };
-
- return id;
-}
-
-/**
- * Insert a constant into a constant pool. Returns the id of the constant, or
- * PM_CONSTANT_ID_UNSET if any potential calls to resize fail.
- */
-pm_constant_id_t
-pm_constant_pool_insert_shared(pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
- return pm_constant_pool_insert(pool, start, length, PM_CONSTANT_POOL_BUCKET_DEFAULT);
-}
-
-/**
- * Insert a constant into a constant pool from memory that is now owned by the
- * constant pool. Returns the id of the constant, or PM_CONSTANT_ID_UNSET if any
- * potential calls to resize fail.
- */
-pm_constant_id_t
-pm_constant_pool_insert_owned(pm_constant_pool_t *pool, uint8_t *start, size_t length) {
- return pm_constant_pool_insert(pool, start, length, PM_CONSTANT_POOL_BUCKET_OWNED);
-}
-
-/**
- * Insert a constant into a constant pool from memory that is constant. Returns
- * the id of the constant, or PM_CONSTANT_ID_UNSET if any potential calls to
- * resize fail.
- */
-pm_constant_id_t
-pm_constant_pool_insert_constant(pm_constant_pool_t *pool, const uint8_t *start, size_t length) {
- return pm_constant_pool_insert(pool, start, length, PM_CONSTANT_POOL_BUCKET_CONSTANT);
-}
-
-/**
- * Free the memory associated with a constant pool.
- */
-void
-pm_constant_pool_free(pm_constant_pool_t *pool) {
- // For each constant in the current constant pool, free the contents if the
- // contents are owned.
- for (uint32_t index = 0; index < pool->capacity; index++) {
- pm_constant_pool_bucket_t *bucket = &pool->buckets[index];
-
- // If an id is set on this constant, then we know we have content here.
- if (bucket->id != PM_CONSTANT_ID_UNSET && bucket->type == PM_CONSTANT_POOL_BUCKET_OWNED) {
- pm_constant_t *constant = &pool->constants[bucket->id - 1];
- xfree((void *) constant->start);
- }
- }
-
- xfree(pool->buckets);
-}
diff --git a/prism/util/pm_constant_pool.h b/prism/util/pm_constant_pool.h
deleted file mode 100644
index 6df23f8f50..0000000000
--- a/prism/util/pm_constant_pool.h
+++ /dev/null
@@ -1,218 +0,0 @@
-/**
- * @file pm_constant_pool.h
- *
- * A data structure that stores a set of strings.
- *
- * Each string is assigned a unique id, which can be used to compare strings for
- * equality. This comparison ends up being much faster than strcmp, since it
- * only requires a single integer comparison.
- */
-#ifndef PRISM_CONSTANT_POOL_H
-#define PRISM_CONSTANT_POOL_H
-
-#include "prism/defines.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-/**
- * When we allocate constants into the pool, we reserve 0 to mean that the slot
- * is not yet filled. This constant is reused in other places to indicate the
- * lack of a constant id.
- */
-#define PM_CONSTANT_ID_UNSET 0
-
-/**
- * A constant id is a unique identifier for a constant in the constant pool.
- */
-typedef uint32_t pm_constant_id_t;
-
-/**
- * A list of constant IDs. Usually used to represent a set of locals.
- */
-typedef struct {
- /** The number of constant ids in the list. */
- size_t size;
-
- /** The number of constant ids that have been allocated in the list. */
- size_t capacity;
-
- /** The constant ids in the list. */
- pm_constant_id_t *ids;
-} pm_constant_id_list_t;
-
-/**
- * Initialize a list of constant ids.
- *
- * @param list The list to initialize.
- */
-void pm_constant_id_list_init(pm_constant_id_list_t *list);
-
-/**
- * Initialize a list of constant ids with a given capacity.
- *
- * @param list The list to initialize.
- * @param capacity The initial capacity of the list.
- */
-void pm_constant_id_list_init_capacity(pm_constant_id_list_t *list, size_t capacity);
-
-/**
- * Append a constant id to a list of constant ids. Returns false if any
- * potential reallocations fail.
- *
- * @param list The list to append to.
- * @param id The id to append.
- * @return Whether the append succeeded.
- */
-bool pm_constant_id_list_append(pm_constant_id_list_t *list, pm_constant_id_t id);
-
-/**
- * Insert a constant id into a list of constant ids at the specified index.
- *
- * @param list The list to insert into.
- * @param index The index at which to insert.
- * @param id The id to insert.
- */
-void pm_constant_id_list_insert(pm_constant_id_list_t *list, size_t index, pm_constant_id_t id);
-
-/**
- * Checks if the current constant id list includes the given constant id.
- *
- * @param list The list to check.
- * @param id The id to check for.
- * @return Whether the list includes the given id.
- */
-bool pm_constant_id_list_includes(pm_constant_id_list_t *list, pm_constant_id_t id);
-
-/**
- * Free the memory associated with a list of constant ids.
- *
- * @param list The list to free.
- */
-void pm_constant_id_list_free(pm_constant_id_list_t *list);
-
-/**
- * The type of bucket in the constant pool hash map. This determines how the
- * bucket should be freed.
- */
-typedef unsigned int pm_constant_pool_bucket_type_t;
-
-/** By default, each constant is a slice of the source. */
-static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_DEFAULT = 0;
-
-/** An owned constant is one for which memory has been allocated. */
-static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_OWNED = 1;
-
-/** A constant constant is known at compile time. */
-static const pm_constant_pool_bucket_type_t PM_CONSTANT_POOL_BUCKET_CONSTANT = 2;
-
-/** A bucket in the hash map. */
-typedef struct {
- /** The incremental ID used for indexing back into the pool. */
- unsigned int id: 30;
-
- /** The type of the bucket, which determines how to free it. */
- pm_constant_pool_bucket_type_t type: 2;
-
- /** The hash of the bucket. */
- uint32_t hash;
-} pm_constant_pool_bucket_t;
-
-/** A constant in the pool which effectively stores a string. */
-typedef struct {
- /** A pointer to the start of the string. */
- const uint8_t *start;
-
- /** The length of the string. */
- size_t length;
-} pm_constant_t;
-
-/** The overall constant pool, which stores constants found while parsing. */
-typedef struct {
- /** The buckets in the hash map. */
- pm_constant_pool_bucket_t *buckets;
-
- /** The constants that are stored in the buckets. */
- pm_constant_t *constants;
-
- /** The number of buckets in the hash map. */
- uint32_t size;
-
- /** The number of buckets that have been allocated in the hash map. */
- uint32_t capacity;
-} pm_constant_pool_t;
-
-/**
- * Initialize a new constant pool with a given capacity.
- *
- * @param pool The pool to initialize.
- * @param capacity The initial capacity of the pool.
- * @return Whether the initialization succeeded.
- */
-bool pm_constant_pool_init(pm_constant_pool_t *pool, uint32_t capacity);
-
-/**
- * Return a pointer to the constant indicated by the given constant id.
- *
- * @param pool The pool to get the constant from.
- * @param constant_id The id of the constant to get.
- * @return A pointer to the constant.
- */
-pm_constant_t * pm_constant_pool_id_to_constant(const pm_constant_pool_t *pool, pm_constant_id_t constant_id);
-
-/**
- * Find a constant in a constant pool. Returns the id of the constant, or 0 if
- * the constant is not found.
- *
- * @param pool The pool to find the constant in.
- * @param start A pointer to the start of the constant.
- * @param length The length of the constant.
- * @return The id of the constant.
- */
-pm_constant_id_t pm_constant_pool_find(const pm_constant_pool_t *pool, const uint8_t *start, size_t length);
-
-/**
- * Insert a constant into a constant pool that is a slice of a source string.
- * Returns the id of the constant, or 0 if any potential calls to resize fail.
- *
- * @param pool The pool to insert the constant into.
- * @param start A pointer to the start of the constant.
- * @param length The length of the constant.
- * @return The id of the constant.
- */
-pm_constant_id_t pm_constant_pool_insert_shared(pm_constant_pool_t *pool, const uint8_t *start, size_t length);
-
-/**
- * Insert a constant into a constant pool from memory that is now owned by the
- * constant pool. Returns the id of the constant, or 0 if any potential calls to
- * resize fail.
- *
- * @param pool The pool to insert the constant into.
- * @param start A pointer to the start of the constant.
- * @param length The length of the constant.
- * @return The id of the constant.
- */
-pm_constant_id_t pm_constant_pool_insert_owned(pm_constant_pool_t *pool, uint8_t *start, size_t length);
-
-/**
- * Insert a constant into a constant pool from memory that is constant. Returns
- * the id of the constant, or 0 if any potential calls to resize fail.
- *
- * @param pool The pool to insert the constant into.
- * @param start A pointer to the start of the constant.
- * @param length The length of the constant.
- * @return The id of the constant.
- */
-pm_constant_id_t pm_constant_pool_insert_constant(pm_constant_pool_t *pool, const uint8_t *start, size_t length);
-
-/**
- * Free the memory associated with a constant pool.
- *
- * @param pool The pool to free.
- */
-void pm_constant_pool_free(pm_constant_pool_t *pool);
-
-#endif
diff --git a/prism/util/pm_integer.c b/prism/util/pm_integer.c
deleted file mode 100644
index 4170ecc58d..0000000000
--- a/prism/util/pm_integer.c
+++ /dev/null
@@ -1,670 +0,0 @@
-#include "prism/util/pm_integer.h"
-
-/**
- * Pull out the length and values from the integer, regardless of the form in
- * which the length/values are stored.
- */
-#define INTEGER_EXTRACT(integer, length_variable, values_variable) \
- if ((integer)->values == NULL) { \
- length_variable = 1; \
- values_variable = &(integer)->value; \
- } else { \
- length_variable = (integer)->length; \
- values_variable = (integer)->values; \
- }
-
-/**
- * Adds two positive pm_integer_t with the given base.
- * Return pm_integer_t with values allocated. Not normalized.
- */
-static void
-big_add(pm_integer_t *destination, pm_integer_t *left, pm_integer_t *right, uint64_t base) {
- size_t left_length;
- uint32_t *left_values;
- INTEGER_EXTRACT(left, left_length, left_values)
-
- size_t right_length;
- uint32_t *right_values;
- INTEGER_EXTRACT(right, right_length, right_values)
-
- size_t length = left_length < right_length ? right_length : left_length;
- uint32_t *values = (uint32_t *) xmalloc(sizeof(uint32_t) * (length + 1));
- if (values == NULL) return;
-
- uint64_t carry = 0;
- for (size_t index = 0; index < length; index++) {
- uint64_t sum = carry + (index < left_length ? left_values[index] : 0) + (index < right_length ? right_values[index] : 0);
- values[index] = (uint32_t) (sum % base);
- carry = sum / base;
- }
-
- if (carry > 0) {
- values[length] = (uint32_t) carry;
- length++;
- }
-
- *destination = (pm_integer_t) { length, values, 0, false };
-}
-
-/**
- * Internal use for karatsuba_multiply. Calculates `a - b - c` with the given
- * base. Assume a, b, c, a - b - c all to be positive.
- * Return pm_integer_t with values allocated. Not normalized.
- */
-static void
-big_sub2(pm_integer_t *destination, pm_integer_t *a, pm_integer_t *b, pm_integer_t *c, uint64_t base) {
- size_t a_length;
- uint32_t *a_values;
- INTEGER_EXTRACT(a, a_length, a_values)
-
- size_t b_length;
- uint32_t *b_values;
- INTEGER_EXTRACT(b, b_length, b_values)
-
- size_t c_length;
- uint32_t *c_values;
- INTEGER_EXTRACT(c, c_length, c_values)
-
- uint32_t *values = (uint32_t*) xmalloc(sizeof(uint32_t) * a_length);
- int64_t carry = 0;
-
- for (size_t index = 0; index < a_length; index++) {
- int64_t sub = (
- carry +
- a_values[index] -
- (index < b_length ? b_values[index] : 0) -
- (index < c_length ? c_values[index] : 0)
- );
-
- if (sub >= 0) {
- values[index] = (uint32_t) sub;
- carry = 0;
- } else {
- sub += 2 * (int64_t) base;
- values[index] = (uint32_t) ((uint64_t) sub % base);
- carry = sub / (int64_t) base - 2;
- }
- }
-
- while (a_length > 1 && values[a_length - 1] == 0) a_length--;
- *destination = (pm_integer_t) { a_length, values, 0, false };
-}
-
-/**
- * Multiply two positive integers with the given base using karatsuba algorithm.
- * Return pm_integer_t with values allocated. Not normalized.
- */
-static void
-karatsuba_multiply(pm_integer_t *destination, pm_integer_t *left, pm_integer_t *right, uint64_t base) {
- size_t left_length;
- uint32_t *left_values;
- INTEGER_EXTRACT(left, left_length, left_values)
-
- size_t right_length;
- uint32_t *right_values;
- INTEGER_EXTRACT(right, right_length, right_values)
-
- if (left_length > right_length) {
- size_t temporary_length = left_length;
- left_length = right_length;
- right_length = temporary_length;
-
- uint32_t *temporary_values = left_values;
- left_values = right_values;
- right_values = temporary_values;
- }
-
- if (left_length <= 10) {
- size_t length = left_length + right_length;
- uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t));
- if (values == NULL) return;
-
- for (size_t left_index = 0; left_index < left_length; left_index++) {
- uint32_t carry = 0;
- for (size_t right_index = 0; right_index < right_length; right_index++) {
- uint64_t product = (uint64_t) left_values[left_index] * right_values[right_index] + values[left_index + right_index] + carry;
- values[left_index + right_index] = (uint32_t) (product % base);
- carry = (uint32_t) (product / base);
- }
- values[left_index + right_length] = carry;
- }
-
- while (length > 1 && values[length - 1] == 0) length--;
- *destination = (pm_integer_t) { length, values, 0, false };
- return;
- }
-
- if (left_length * 2 <= right_length) {
- uint32_t *values = (uint32_t *) xcalloc(left_length + right_length, sizeof(uint32_t));
-
- for (size_t start_offset = 0; start_offset < right_length; start_offset += left_length) {
- size_t end_offset = start_offset + left_length;
- if (end_offset > right_length) end_offset = right_length;
-
- pm_integer_t sliced_left = {
- .length = left_length,
- .values = left_values,
- .value = 0,
- .negative = false
- };
-
- pm_integer_t sliced_right = {
- .length = end_offset - start_offset,
- .values = right_values + start_offset,
- .value = 0,
- .negative = false
- };
-
- pm_integer_t product;
- karatsuba_multiply(&product, &sliced_left, &sliced_right, base);
-
- uint32_t carry = 0;
- for (size_t index = 0; index < product.length; index++) {
- uint64_t sum = (uint64_t) values[start_offset + index] + product.values[index] + carry;
- values[start_offset + index] = (uint32_t) (sum % base);
- carry = (uint32_t) (sum / base);
- }
-
- if (carry > 0) values[start_offset + product.length] += carry;
- pm_integer_free(&product);
- }
-
- *destination = (pm_integer_t) { left_length + right_length, values, 0, false };
- return;
- }
-
- size_t half = left_length / 2;
- pm_integer_t x0 = { half, left_values, 0, false };
- pm_integer_t x1 = { left_length - half, left_values + half, 0, false };
- pm_integer_t y0 = { half, right_values, 0, false };
- pm_integer_t y1 = { right_length - half, right_values + half, 0, false };
-
- pm_integer_t z0 = { 0 };
- karatsuba_multiply(&z0, &x0, &y0, base);
-
- pm_integer_t z2 = { 0 };
- karatsuba_multiply(&z2, &x1, &y1, base);
-
- // For simplicity to avoid considering negative values,
- // use `z1 = (x0 + x1) * (y0 + y1) - z0 - z2` instead of original karatsuba algorithm.
- pm_integer_t x01 = { 0 };
- big_add(&x01, &x0, &x1, base);
-
- pm_integer_t y01 = { 0 };
- big_add(&y01, &y0, &y1, base);
-
- pm_integer_t xy = { 0 };
- karatsuba_multiply(&xy, &x01, &y01, base);
-
- pm_integer_t z1;
- big_sub2(&z1, &xy, &z0, &z2, base);
-
- size_t length = left_length + right_length;
- uint32_t *values = (uint32_t*) xcalloc(length, sizeof(uint32_t));
-
- assert(z0.values != NULL);
- memcpy(values, z0.values, sizeof(uint32_t) * z0.length);
-
- assert(z2.values != NULL);
- memcpy(values + 2 * half, z2.values, sizeof(uint32_t) * z2.length);
-
- uint32_t carry = 0;
- for(size_t index = 0; index < z1.length; index++) {
- uint64_t sum = (uint64_t) carry + values[index + half] + z1.values[index];
- values[index + half] = (uint32_t) (sum % base);
- carry = (uint32_t) (sum / base);
- }
-
- for(size_t index = half + z1.length; carry > 0; index++) {
- uint64_t sum = (uint64_t) carry + values[index];
- values[index] = (uint32_t) (sum % base);
- carry = (uint32_t) (sum / base);
- }
-
- while (length > 1 && values[length - 1] == 0) length--;
- pm_integer_free(&z0);
- pm_integer_free(&z1);
- pm_integer_free(&z2);
- pm_integer_free(&x01);
- pm_integer_free(&y01);
- pm_integer_free(&xy);
-
- *destination = (pm_integer_t) { length, values, 0, false };
-}
-
-/**
- * The values of a hexadecimal digit, where the index is the ASCII character.
- * Note that there's an odd exception here where _ is mapped to 0. This is
- * because it's possible for us to end up trying to parse a number that has
- * already had an error attached to it, and we want to provide _something_ to
- * the user.
- */
-static const int8_t pm_integer_parse_digit_values[256] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2x
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 3x
- -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, // 5x
- -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 8x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 9x
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ax
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Bx
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Cx
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Dx
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ex
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Fx
-};
-
-/**
- * Return the value of a hexadecimal digit in a uint8_t.
- */
-static uint8_t
-pm_integer_parse_digit(const uint8_t character) {
- int8_t value = pm_integer_parse_digit_values[character];
- assert(value != -1 && "invalid digit");
-
- return (uint8_t) value;
-}
-
-/**
- * Create a pm_integer_t from uint64_t with the given base. It is assumed that
- * the memory for the pm_integer_t pointer has been zeroed.
- */
-static void
-pm_integer_from_uint64(pm_integer_t *integer, uint64_t value, uint64_t base) {
- if (value < base) {
- integer->value = (uint32_t) value;
- return;
- }
-
- size_t length = 0;
- uint64_t length_value = value;
- while (length_value > 0) {
- length++;
- length_value /= base;
- }
-
- uint32_t *values = (uint32_t *) xmalloc(sizeof(uint32_t) * length);
- if (values == NULL) return;
-
- for (size_t value_index = 0; value_index < length; value_index++) {
- values[value_index] = (uint32_t) (value % base);
- value /= base;
- }
-
- integer->length = length;
- integer->values = values;
-}
-
-/**
- * Normalize pm_integer_t.
- * Heading zero values will be removed. If the integer fits into uint32_t,
- * values is set to NULL, length is set to 0, and value field will be used.
- */
-static void
-pm_integer_normalize(pm_integer_t *integer) {
- if (integer->values == NULL) {
- return;
- }
-
- while (integer->length > 1 && integer->values[integer->length - 1] == 0) {
- integer->length--;
- }
-
- if (integer->length > 1) {
- return;
- }
-
- uint32_t value = integer->values[0];
- bool negative = integer->negative && value != 0;
-
- pm_integer_free(integer);
- *integer = (pm_integer_t) { .values = NULL, .value = value, .length = 0, .negative = negative };
-}
-
-/**
- * Convert base of the integer.
- * In practice, it converts 10**9 to 1<<32 or 1<<32 to 10**9.
- */
-static void
-pm_integer_convert_base(pm_integer_t *destination, const pm_integer_t *source, uint64_t base_from, uint64_t base_to) {
- size_t source_length;
- const uint32_t *source_values;
- INTEGER_EXTRACT(source, source_length, source_values)
-
- size_t bigints_length = (source_length + 1) / 2;
- assert(bigints_length > 0);
-
- pm_integer_t *bigints = (pm_integer_t *) xcalloc(bigints_length, sizeof(pm_integer_t));
- if (bigints == NULL) return;
-
- for (size_t index = 0; index < source_length; index += 2) {
- uint64_t value = source_values[index] + base_from * (index + 1 < source_length ? source_values[index + 1] : 0);
- pm_integer_from_uint64(&bigints[index / 2], value, base_to);
- }
-
- pm_integer_t base = { 0 };
- pm_integer_from_uint64(&base, base_from, base_to);
-
- while (bigints_length > 1) {
- pm_integer_t next_base;
- karatsuba_multiply(&next_base, &base, &base, base_to);
-
- pm_integer_free(&base);
- base = next_base;
-
- size_t next_length = (bigints_length + 1) / 2;
- pm_integer_t *next_bigints = (pm_integer_t *) xcalloc(next_length, sizeof(pm_integer_t));
-
- for (size_t bigints_index = 0; bigints_index < bigints_length; bigints_index += 2) {
- if (bigints_index + 1 == bigints_length) {
- next_bigints[bigints_index / 2] = bigints[bigints_index];
- } else {
- pm_integer_t multiplied = { 0 };
- karatsuba_multiply(&multiplied, &base, &bigints[bigints_index + 1], base_to);
-
- big_add(&next_bigints[bigints_index / 2], &bigints[bigints_index], &multiplied, base_to);
- pm_integer_free(&bigints[bigints_index]);
- pm_integer_free(&bigints[bigints_index + 1]);
- pm_integer_free(&multiplied);
- }
- }
-
- xfree(bigints);
- bigints = next_bigints;
- bigints_length = next_length;
- }
-
- *destination = bigints[0];
- destination->negative = source->negative;
- pm_integer_normalize(destination);
-
- xfree(bigints);
- pm_integer_free(&base);
-}
-
-#undef INTEGER_EXTRACT
-
-/**
- * Convert digits to integer with the given power-of-two base.
- */
-static void
-pm_integer_parse_powof2(pm_integer_t *integer, uint32_t base, const uint8_t *digits, size_t digits_length) {
- size_t bit = 1;
- while (base > (uint32_t) (1 << bit)) bit++;
-
- size_t length = (digits_length * bit + 31) / 32;
- uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t));
-
- for (size_t digit_index = 0; digit_index < digits_length; digit_index++) {
- size_t bit_position = bit * (digits_length - digit_index - 1);
- uint32_t value = digits[digit_index];
-
- size_t index = bit_position / 32;
- size_t shift = bit_position % 32;
-
- values[index] |= value << shift;
- if (32 - shift < bit) values[index + 1] |= value >> (32 - shift);
- }
-
- while (length > 1 && values[length - 1] == 0) length--;
- *integer = (pm_integer_t) { .length = length, .values = values, .value = 0, .negative = false };
- pm_integer_normalize(integer);
-}
-
-/**
- * Convert decimal digits to pm_integer_t.
- */
-static void
-pm_integer_parse_decimal(pm_integer_t *integer, const uint8_t *digits, size_t digits_length) {
- const size_t batch = 9;
- size_t length = (digits_length + batch - 1) / batch;
-
- uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t));
- uint32_t value = 0;
-
- for (size_t digits_index = 0; digits_index < digits_length; digits_index++) {
- value = value * 10 + digits[digits_index];
-
- size_t reverse_index = digits_length - digits_index - 1;
- if (reverse_index % batch == 0) {
- values[reverse_index / batch] = value;
- value = 0;
- }
- }
-
- // Convert base from 10**9 to 1<<32.
- pm_integer_convert_base(integer, &((pm_integer_t) { .length = length, .values = values, .value = 0, .negative = false }), 1000000000, ((uint64_t) 1 << 32));
- xfree(values);
-}
-
-/**
- * Parse a large integer from a string that does not fit into uint32_t.
- */
-static void
-pm_integer_parse_big(pm_integer_t *integer, uint32_t multiplier, const uint8_t *start, const uint8_t *end) {
- // Allocate an array to store digits.
- uint8_t *digits = xmalloc(sizeof(uint8_t) * (size_t) (end - start));
- size_t digits_length = 0;
-
- for (; start < end; start++) {
- if (*start == '_') continue;
- digits[digits_length++] = pm_integer_parse_digit(*start);
- }
-
- // Construct pm_integer_t from the digits.
- if (multiplier == 10) {
- pm_integer_parse_decimal(integer, digits, digits_length);
- } else {
- pm_integer_parse_powof2(integer, multiplier, digits, digits_length);
- }
-
- xfree(digits);
-}
-
-/**
- * Parse an integer from a string. This assumes that the format of the integer
- * has already been validated, as internal validation checks are not performed
- * here.
- */
-void
-pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end) {
- // Ignore unary +. Unary - is parsed differently and will not end up here.
- // Instead, it will modify the parsed integer later.
- if (*start == '+') start++;
-
- // Determine the multiplier from the base, and skip past any prefixes.
- uint32_t multiplier = 10;
- switch (base) {
- case PM_INTEGER_BASE_DEFAULT:
- while (*start == '0') start++; // 01 -> 1
- break;
- case PM_INTEGER_BASE_BINARY:
- start += 2; // 0b
- multiplier = 2;
- break;
- case PM_INTEGER_BASE_OCTAL:
- start++; // 0
- if (*start == '_' || *start == 'o' || *start == 'O') start++; // o
- multiplier = 8;
- break;
- case PM_INTEGER_BASE_DECIMAL:
- if (*start == '0' && (end - start) > 1) start += 2; // 0d
- break;
- case PM_INTEGER_BASE_HEXADECIMAL:
- start += 2; // 0x
- multiplier = 16;
- break;
- case PM_INTEGER_BASE_UNKNOWN:
- if (*start == '0' && (end - start) > 1) {
- switch (start[1]) {
- case '_': start += 2; multiplier = 8; break;
- case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': start++; multiplier = 8; break;
- case 'b': case 'B': start += 2; multiplier = 2; break;
- case 'o': case 'O': start += 2; multiplier = 8; break;
- case 'd': case 'D': start += 2; break;
- case 'x': case 'X': start += 2; multiplier = 16; break;
- default: assert(false && "unreachable"); break;
- }
- }
- break;
- }
-
- // It's possible that we've consumed everything at this point if there is an
- // invalid integer. If this is the case, we'll just return 0.
- if (start >= end) return;
-
- const uint8_t *cursor = start;
- uint64_t value = (uint64_t) pm_integer_parse_digit(*cursor++);
-
- for (; cursor < end; cursor++) {
- if (*cursor == '_') continue;
- value = value * multiplier + (uint64_t) pm_integer_parse_digit(*cursor);
-
- if (value > UINT32_MAX) {
- // If the integer is too large to fit into a single uint32_t, then
- // we'll parse it as a big integer.
- pm_integer_parse_big(integer, multiplier, start, end);
- return;
- }
- }
-
- integer->value = (uint32_t) value;
-}
-
-/**
- * Compare two integers. This function returns -1 if the left integer is less
- * than the right integer, 0 if they are equal, and 1 if the left integer is
- * greater than the right integer.
- */
-int
-pm_integer_compare(const pm_integer_t *left, const pm_integer_t *right) {
- if (left->negative != right->negative) return left->negative ? -1 : 1;
- int negative = left->negative ? -1 : 1;
-
- if (left->values == NULL && right->values == NULL) {
- if (left->value < right->value) return -1 * negative;
- if (left->value > right->value) return 1 * negative;
- return 0;
- }
-
- if (left->values == NULL || left->length < right->length) return -1 * negative;
- if (right->values == NULL || left->length > right->length) return 1 * negative;
-
- for (size_t index = 0; index < left->length; index++) {
- size_t value_index = left->length - index - 1;
- uint32_t left_value = left->values[value_index];
- uint32_t right_value = right->values[value_index];
-
- if (left_value < right_value) return -1 * negative;
- if (left_value > right_value) return 1 * negative;
- }
-
- return 0;
-}
-
-/**
- * Reduce a ratio of integers to its simplest form.
- */
-void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator) {
- // If either the numerator or denominator do not fit into a 32-bit integer,
- // then this function is a no-op. In the future, we may consider reducing
- // even the larger numbers, but for now we're going to keep it simple.
- if (
- // If the numerator doesn't fit into a 32-bit integer, return early.
- numerator->length != 0 ||
- // If the denominator doesn't fit into a 32-bit integer, return early.
- denominator->length != 0 ||
- // If the numerator is 0, then return early.
- numerator->value == 0 ||
- // If the denominator is 1, then return early.
- denominator->value == 1
- ) return;
-
- // Find the greatest common divisor of the numerator and denominator.
- uint32_t divisor = numerator->value;
- uint32_t remainder = denominator->value;
-
- while (remainder != 0) {
- uint32_t temporary = remainder;
- remainder = divisor % remainder;
- divisor = temporary;
- }
-
- // Divide the numerator and denominator by the greatest common divisor.
- numerator->value /= divisor;
- denominator->value /= divisor;
-}
-
-/**
- * Convert an integer to a decimal string.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer) {
- if (integer->negative) {
- pm_buffer_append_byte(buffer, '-');
- }
-
- // If the integer fits into a single uint32_t, then we can just append the
- // value directly to the buffer.
- if (integer->values == NULL) {
- pm_buffer_append_format(buffer, "%" PRIu32, integer->value);
- return;
- }
-
- // If the integer is two uint32_t values, then we can | them together and
- // append the result to the buffer.
- if (integer->length == 2) {
- const uint64_t value = ((uint64_t) integer->values[0]) | ((uint64_t) integer->values[1] << 32);
- pm_buffer_append_format(buffer, "%" PRIu64, value);
- return;
- }
-
- // Otherwise, first we'll convert the base from 1<<32 to 10**9.
- pm_integer_t converted = { 0 };
- pm_integer_convert_base(&converted, integer, (uint64_t) 1 << 32, 1000000000);
-
- if (converted.values == NULL) {
- pm_buffer_append_format(buffer, "%" PRIu32, converted.value);
- pm_integer_free(&converted);
- return;
- }
-
- // Allocate a buffer that we'll copy the decimal digits into.
- size_t digits_length = converted.length * 9;
- char *digits = xcalloc(digits_length, sizeof(char));
- if (digits == NULL) return;
-
- // Pack bigdecimal to digits.
- for (size_t value_index = 0; value_index < converted.length; value_index++) {
- uint32_t value = converted.values[value_index];
-
- for (size_t digit_index = 0; digit_index < 9; digit_index++) {
- digits[digits_length - 9 * value_index - digit_index - 1] = (char) ('0' + value % 10);
- value /= 10;
- }
- }
-
- size_t start_offset = 0;
- while (start_offset < digits_length - 1 && digits[start_offset] == '0') start_offset++;
-
- // Finally, append the string to the buffer and free the digits.
- pm_buffer_append_string(buffer, digits + start_offset, digits_length - start_offset);
- xfree(digits);
- pm_integer_free(&converted);
-}
-
-/**
- * Free the internal memory of an integer. This memory will only be allocated if
- * the integer exceeds the size of a single uint32_t.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_integer_free(pm_integer_t *integer) {
- if (integer->values) {
- xfree(integer->values);
- }
-}
diff --git a/prism/util/pm_integer.h b/prism/util/pm_integer.h
deleted file mode 100644
index a9e2966703..0000000000
--- a/prism/util/pm_integer.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/**
- * @file pm_integer.h
- *
- * This module provides functions for working with arbitrary-sized integers.
- */
-#ifndef PRISM_NUMBER_H
-#define PRISM_NUMBER_H
-
-#include "prism/defines.h"
-#include "prism/util/pm_buffer.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-/**
- * A structure represents an arbitrary-sized integer.
- */
-typedef struct {
- /**
- * The number of allocated values. length is set to 0 if the integer fits
- * into uint32_t.
- */
- size_t length;
-
- /**
- * List of 32-bit integers. Set to NULL if the integer fits into uint32_t.
- */
- uint32_t *values;
-
- /**
- * Embedded value for small integer. This value is set to 0 if the value
- * does not fit into uint32_t.
- */
- uint32_t value;
-
- /**
- * Whether or not the integer is negative. It is stored this way so that a
- * zeroed pm_integer_t is always positive zero.
- */
- bool negative;
-} pm_integer_t;
-
-/**
- * An enum controlling the base of an integer. It is expected that the base is
- * already known before parsing the integer, even though it could be derived
- * from the string itself.
- */
-typedef enum {
- /** The default decimal base, with no prefix. Leading 0s will be ignored. */
- PM_INTEGER_BASE_DEFAULT,
-
- /** The binary base, indicated by a 0b or 0B prefix. */
- PM_INTEGER_BASE_BINARY,
-
- /** The octal base, indicated by a 0, 0o, or 0O prefix. */
- PM_INTEGER_BASE_OCTAL,
-
- /** The decimal base, indicated by a 0d, 0D, or empty prefix. */
- PM_INTEGER_BASE_DECIMAL,
-
- /** The hexadecimal base, indicated by a 0x or 0X prefix. */
- PM_INTEGER_BASE_HEXADECIMAL,
-
- /**
- * An unknown base, in which case pm_integer_parse will derive it based on
- * the content of the string. This is less efficient and does more
- * comparisons, so if callers know the base ahead of time, they should use
- * that instead.
- */
- PM_INTEGER_BASE_UNKNOWN
-} pm_integer_base_t;
-
-/**
- * Parse an integer from a string. This assumes that the format of the integer
- * has already been validated, as internal validation checks are not performed
- * here.
- *
- * @param integer The integer to parse into.
- * @param base The base of the integer.
- * @param start The start of the string.
- * @param end The end of the string.
- */
-void pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end);
-
-/**
- * Compare two integers. This function returns -1 if the left integer is less
- * than the right integer, 0 if they are equal, and 1 if the left integer is
- * greater than the right integer.
- *
- * @param left The left integer to compare.
- * @param right The right integer to compare.
- * @return The result of the comparison.
- */
-int pm_integer_compare(const pm_integer_t *left, const pm_integer_t *right);
-
-/**
- * Reduce a ratio of integers to its simplest form.
- *
- * If either the numerator or denominator do not fit into a 32-bit integer, then
- * this function is a no-op. In the future, we may consider reducing even the
- * larger numbers, but for now we're going to keep it simple.
- *
- * @param numerator The numerator of the ratio.
- * @param denominator The denominator of the ratio.
- */
-void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator);
-
-/**
- * Convert an integer to a decimal string.
- *
- * @param buffer The buffer to append the string to.
- * @param integer The integer to convert to a string.
- */
-PRISM_EXPORTED_FUNCTION void pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer);
-
-/**
- * Free the internal memory of an integer. This memory will only be allocated if
- * the integer exceeds the size of a single node in the linked list.
- *
- * @param integer The integer to free.
- */
-PRISM_EXPORTED_FUNCTION void pm_integer_free(pm_integer_t *integer);
-
-#endif
diff --git a/prism/util/pm_list.c b/prism/util/pm_list.c
deleted file mode 100644
index ad2294cd60..0000000000
--- a/prism/util/pm_list.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include "prism/util/pm_list.h"
-
-/**
- * Returns true if the given list is empty.
- */
-PRISM_EXPORTED_FUNCTION bool
-pm_list_empty_p(pm_list_t *list) {
- return list->head == NULL;
-}
-
-/**
- * Returns the size of the list.
- */
-PRISM_EXPORTED_FUNCTION size_t
-pm_list_size(pm_list_t *list) {
- return list->size;
-}
-
-/**
- * Append a node to the given list.
- */
-void
-pm_list_append(pm_list_t *list, pm_list_node_t *node) {
- if (list->head == NULL) {
- list->head = node;
- } else {
- list->tail->next = node;
- }
-
- list->tail = node;
- list->size++;
-}
-
-/**
- * Deallocate the internal state of the given list.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_list_free(pm_list_t *list) {
- pm_list_node_t *node = list->head;
- pm_list_node_t *next;
-
- while (node != NULL) {
- next = node->next;
- xfree(node);
- node = next;
- }
-
- list->size = 0;
-}
diff --git a/prism/util/pm_list.h b/prism/util/pm_list.h
deleted file mode 100644
index 3512dee979..0000000000
--- a/prism/util/pm_list.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * @file pm_list.h
- *
- * An abstract linked list.
- */
-#ifndef PRISM_LIST_H
-#define PRISM_LIST_H
-
-#include "prism/defines.h"
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-/**
- * This struct represents an abstract linked list that provides common
- * functionality. It is meant to be used any time a linked list is necessary to
- * store data.
- *
- * The linked list itself operates off a set of pointers. Because the pointers
- * are not necessarily sequential, they can be of any size. We use this fact to
- * allow the consumer of this linked list to extend the node struct to include
- * any data they want. This is done by using the pm_list_node_t as the first
- * member of the struct.
- *
- * For example, if we want to store a list of integers, we can do the following:
- *
- * ```c
- * typedef struct {
- * pm_list_node_t node;
- * int value;
- * } pm_int_node_t;
- *
- * pm_list_t list = { 0 };
- * pm_int_node_t *node = xmalloc(sizeof(pm_int_node_t));
- * node->value = 5;
- *
- * pm_list_append(&list, &node->node);
- * ```
- *
- * The pm_list_t struct is used to represent the overall linked list. It
- * contains a pointer to the head and tail of the list. This allows for easy
- * iteration and appending of new nodes.
- */
-typedef struct pm_list_node {
- /** A pointer to the next node in the list. */
- struct pm_list_node *next;
-} pm_list_node_t;
-
-/**
- * This represents the overall linked list. It keeps a pointer to the head and
- * tail so that iteration is easy and pushing new nodes is easy.
- */
-typedef struct {
- /** The size of the list. */
- size_t size;
-
- /** A pointer to the head of the list. */
- pm_list_node_t *head;
-
- /** A pointer to the tail of the list. */
- pm_list_node_t *tail;
-} pm_list_t;
-
-/**
- * Returns true if the given list is empty.
- *
- * @param list The list to check.
- * @return True if the given list is empty, otherwise false.
- */
-PRISM_EXPORTED_FUNCTION bool pm_list_empty_p(pm_list_t *list);
-
-/**
- * Returns the size of the list.
- *
- * @param list The list to check.
- * @return The size of the list.
- */
-PRISM_EXPORTED_FUNCTION size_t pm_list_size(pm_list_t *list);
-
-/**
- * Append a node to the given list.
- *
- * @param list The list to append to.
- * @param node The node to append.
- */
-void pm_list_append(pm_list_t *list, pm_list_node_t *node);
-
-/**
- * Deallocate the internal state of the given list.
- *
- * @param list The list to free.
- */
-PRISM_EXPORTED_FUNCTION void pm_list_free(pm_list_t *list);
-
-#endif
diff --git a/prism/util/pm_memchr.c b/prism/util/pm_memchr.c
deleted file mode 100644
index 7ea20ace6d..0000000000
--- a/prism/util/pm_memchr.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "prism/util/pm_memchr.h"
-
-#define PRISM_MEMCHR_TRAILING_BYTE_MINIMUM 0x40
-
-/**
- * We need to roll our own memchr to handle cases where the encoding changes and
- * we need to search for a character in a buffer that could be the trailing byte
- * of a multibyte character.
- */
-void *
-pm_memchr(const void *memory, int character, size_t number, bool encoding_changed, const pm_encoding_t *encoding) {
- if (encoding_changed && encoding->multibyte && character >= PRISM_MEMCHR_TRAILING_BYTE_MINIMUM) {
- const uint8_t *source = (const uint8_t *) memory;
- size_t index = 0;
-
- while (index < number) {
- if (source[index] == character) {
- return (void *) (source + index);
- }
-
- size_t width = encoding->char_width(source + index, (ptrdiff_t) (number - index));
- if (width == 0) {
- return NULL;
- }
-
- index += width;
- }
-
- return NULL;
- } else {
- return memchr(memory, character, number);
- }
-}
-
-#undef PRISM_MEMCHR_TRAILING_BYTE_MINIMUM
diff --git a/prism/util/pm_memchr.h b/prism/util/pm_memchr.h
deleted file mode 100644
index e0671eaed3..0000000000
--- a/prism/util/pm_memchr.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * @file pm_memchr.h
- *
- * A custom memchr implementation.
- */
-#ifndef PRISM_MEMCHR_H
-#define PRISM_MEMCHR_H
-
-#include "prism/defines.h"
-#include "prism/encoding.h"
-
-#include <stddef.h>
-
-/**
- * We need to roll our own memchr to handle cases where the encoding changes and
- * we need to search for a character in a buffer that could be the trailing byte
- * of a multibyte character.
- *
- * @param source The source string.
- * @param character The character to search for.
- * @param number The maximum number of bytes to search.
- * @param encoding_changed Whether the encoding changed.
- * @param encoding A pointer to the encoding.
- * @return A pointer to the first occurrence of the character in the source
- * string, or NULL if no such character exists.
- */
-void * pm_memchr(const void *source, int character, size_t number, bool encoding_changed, const pm_encoding_t *encoding);
-
-#endif
diff --git a/prism/util/pm_newline_list.c b/prism/util/pm_newline_list.c
deleted file mode 100644
index 8331618f54..0000000000
--- a/prism/util/pm_newline_list.c
+++ /dev/null
@@ -1,125 +0,0 @@
-#include "prism/util/pm_newline_list.h"
-
-/**
- * Initialize a new newline list with the given capacity. Returns true if the
- * allocation of the offsets succeeds, otherwise returns false.
- */
-bool
-pm_newline_list_init(pm_newline_list_t *list, const uint8_t *start, size_t capacity) {
- list->offsets = (size_t *) xcalloc(capacity, sizeof(size_t));
- if (list->offsets == NULL) return false;
-
- list->start = start;
-
- // This is 1 instead of 0 because we want to include the first line of the
- // file as having offset 0, which is set because of calloc.
- list->size = 1;
- list->capacity = capacity;
-
- return true;
-}
-
-/**
- * Clear out the newlines that have been appended to the list.
- */
-void
-pm_newline_list_clear(pm_newline_list_t *list) {
- list->size = 1;
-}
-
-/**
- * Append a new offset to the newline list. Returns true if the reallocation of
- * the offsets succeeds (if one was necessary), otherwise returns false.
- */
-bool
-pm_newline_list_append(pm_newline_list_t *list, const uint8_t *cursor) {
- if (list->size == list->capacity) {
- size_t *original_offsets = list->offsets;
-
- list->capacity = (list->capacity * 3) / 2;
- list->offsets = (size_t *) xcalloc(list->capacity, sizeof(size_t));
- if (list->offsets == NULL) return false;
-
- memcpy(list->offsets, original_offsets, list->size * sizeof(size_t));
- xfree(original_offsets);
- }
-
- assert(*cursor == '\n');
- assert(cursor >= list->start);
- size_t newline_offset = (size_t) (cursor - list->start + 1);
-
- assert(list->size == 0 || newline_offset > list->offsets[list->size - 1]);
- list->offsets[list->size++] = newline_offset;
-
- return true;
-}
-
-/**
- * Returns the line of the given offset. If the offset is not in the list, the
- * line of the closest offset less than the given offset is returned.
- */
-int32_t
-pm_newline_list_line(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line) {
- assert(cursor >= list->start);
- size_t offset = (size_t) (cursor - list->start);
-
- size_t left = 0;
- size_t right = list->size - 1;
-
- while (left <= right) {
- size_t mid = left + (right - left) / 2;
-
- if (list->offsets[mid] == offset) {
- return ((int32_t) mid) + start_line;
- }
-
- if (list->offsets[mid] < offset) {
- left = mid + 1;
- } else {
- right = mid - 1;
- }
- }
-
- return ((int32_t) left) + start_line - 1;
-}
-
-/**
- * Returns the line and column of the given offset. If the offset is not in the
- * list, the line and column of the closest offset less than the given offset
- * are returned.
- */
-pm_line_column_t
-pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line) {
- assert(cursor >= list->start);
- size_t offset = (size_t) (cursor - list->start);
-
- size_t left = 0;
- size_t right = list->size - 1;
-
- while (left <= right) {
- size_t mid = left + (right - left) / 2;
-
- if (list->offsets[mid] == offset) {
- return ((pm_line_column_t) { ((int32_t) mid) + start_line, 0 });
- }
-
- if (list->offsets[mid] < offset) {
- left = mid + 1;
- } else {
- right = mid - 1;
- }
- }
-
- return ((pm_line_column_t) {
- .line = ((int32_t) left) + start_line - 1,
- .column = (uint32_t) (offset - list->offsets[left - 1])
- });
-}
-
-/**
- * Free the internal memory allocated for the newline list.
- */
-void
-pm_newline_list_free(pm_newline_list_t *list) {
- xfree(list->offsets);
-}
diff --git a/prism/util/pm_newline_list.h b/prism/util/pm_newline_list.h
deleted file mode 100644
index 406abe8ba5..0000000000
--- a/prism/util/pm_newline_list.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/**
- * @file pm_newline_list.h
- *
- * A list of byte offsets of newlines in a string.
- *
- * When compiling the syntax tree, it's necessary to know the line and column
- * of many nodes. This is necessary to support things like error messages,
- * tracepoints, etc.
- *
- * It's possible that we could store the start line, start column, end line, and
- * end column on every node in addition to the offsets that we already store,
- * but that would be quite a lot of memory overhead.
- */
-#ifndef PRISM_NEWLINE_LIST_H
-#define PRISM_NEWLINE_LIST_H
-
-#include "prism/defines.h"
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-
-/**
- * A list of offsets of newlines in a string. The offsets are assumed to be
- * sorted/inserted in ascending order.
- */
-typedef struct {
- /** A pointer to the start of the source string. */
- const uint8_t *start;
-
- /** The number of offsets in the list. */
- size_t size;
-
- /** The capacity of the list that has been allocated. */
- size_t capacity;
-
- /** The list of offsets. */
- size_t *offsets;
-} pm_newline_list_t;
-
-/**
- * A line and column in a string.
- */
-typedef struct {
- /** The line number. */
- int32_t line;
-
- /** The column number. */
- uint32_t column;
-} pm_line_column_t;
-
-/**
- * Initialize a new newline list with the given capacity. Returns true if the
- * allocation of the offsets succeeds, otherwise returns false.
- *
- * @param list The list to initialize.
- * @param start A pointer to the start of the source string.
- * @param capacity The initial capacity of the list.
- * @return True if the allocation of the offsets succeeds, otherwise false.
- */
-bool pm_newline_list_init(pm_newline_list_t *list, const uint8_t *start, size_t capacity);
-
-/**
- * Clear out the newlines that have been appended to the list.
- *
- * @param list The list to clear.
- */
-void
-pm_newline_list_clear(pm_newline_list_t *list);
-
-/**
- * Append a new offset to the newline list. Returns true if the reallocation of
- * the offsets succeeds (if one was necessary), otherwise returns false.
- *
- * @param list The list to append to.
- * @param cursor A pointer to the offset to append.
- * @return True if the reallocation of the offsets succeeds (if one was
- * necessary), otherwise false.
- */
-bool pm_newline_list_append(pm_newline_list_t *list, const uint8_t *cursor);
-
-/**
- * Returns the line of the given offset. If the offset is not in the list, the
- * line of the closest offset less than the given offset is returned.
- *
- * @param list The list to search.
- * @param cursor A pointer to the offset to search for.
- * @param start_line The line to start counting from.
- * @return The line of the given offset.
- */
-int32_t pm_newline_list_line(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line);
-
-/**
- * Returns the line and column of the given offset. If the offset is not in the
- * list, the line and column of the closest offset less than the given offset
- * are returned.
- *
- * @param list The list to search.
- * @param cursor A pointer to the offset to search for.
- * @param start_line The line to start counting from.
- * @return The line and column of the given offset.
- */
-pm_line_column_t pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line);
-
-/**
- * Free the internal memory allocated for the newline list.
- *
- * @param list The list to free.
- */
-void pm_newline_list_free(pm_newline_list_t *list);
-
-#endif
diff --git a/prism/util/pm_string.c b/prism/util/pm_string.c
deleted file mode 100644
index 7e56dec9f7..0000000000
--- a/prism/util/pm_string.c
+++ /dev/null
@@ -1,382 +0,0 @@
-#include "prism/util/pm_string.h"
-
-/**
- * Returns the size of the pm_string_t struct. This is necessary to allocate the
- * correct amount of memory in the FFI backend.
- */
-PRISM_EXPORTED_FUNCTION size_t
-pm_string_sizeof(void) {
- return sizeof(pm_string_t);
-}
-
-/**
- * Initialize a shared string that is based on initial input.
- */
-void
-pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end) {
- assert(start <= end);
-
- *string = (pm_string_t) {
- .type = PM_STRING_SHARED,
- .source = start,
- .length = (size_t) (end - start)
- };
-}
-
-/**
- * Initialize an owned string that is responsible for freeing allocated memory.
- */
-void
-pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length) {
- *string = (pm_string_t) {
- .type = PM_STRING_OWNED,
- .source = source,
- .length = length
- };
-}
-
-/**
- * Initialize a constant string that doesn't own its memory source.
- */
-void
-pm_string_constant_init(pm_string_t *string, const char *source, size_t length) {
- *string = (pm_string_t) {
- .type = PM_STRING_CONSTANT,
- .source = (const uint8_t *) source,
- .length = length
- };
-}
-
-#ifdef _WIN32
-/**
- * Represents a file handle on Windows, where the path will need to be freed
- * when the file is closed.
- */
-typedef struct {
- /** The path to the file, which will become allocated memory. */
- WCHAR *path;
-
- /** The handle to the file, which will start as uninitialized memory. */
- HANDLE file;
-} pm_string_file_handle_t;
-
-/**
- * Open the file indicated by the filepath parameter for reading on Windows.
- * Perform any kind of normalization that needs to happen on the filepath.
- */
-static pm_string_init_result_t
-pm_string_file_handle_open(pm_string_file_handle_t *handle, const char *filepath) {
- int length = MultiByteToWideChar(CP_UTF8, 0, filepath, -1, NULL, 0);
- if (length == 0) return PM_STRING_INIT_ERROR_GENERIC;
-
- handle->path = xmalloc(sizeof(WCHAR) * ((size_t) length));
- if ((handle->path == NULL) || (MultiByteToWideChar(CP_UTF8, 0, filepath, -1, handle->path, length) == 0)) {
- xfree(handle->path);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- handle->file = CreateFileW(handle->path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
- if (handle->file == INVALID_HANDLE_VALUE) {
- pm_string_init_result_t result = PM_STRING_INIT_ERROR_GENERIC;
-
- if (GetLastError() == ERROR_ACCESS_DENIED) {
- DWORD attributes = GetFileAttributesW(handle->path);
- if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
- result = PM_STRING_INIT_ERROR_DIRECTORY;
- }
- }
-
- xfree(handle->path);
- return result;
- }
-
- return PM_STRING_INIT_SUCCESS;
-}
-
-/**
- * Close the file handle and free the path.
- */
-static void
-pm_string_file_handle_close(pm_string_file_handle_t *handle) {
- xfree(handle->path);
- CloseHandle(handle->file);
-}
-#endif
-
-/**
- * Read the file indicated by the filepath parameter into source and load its
- * contents and size into the given `pm_string_t`. The given `pm_string_t`
- * should be freed using `pm_string_free` when it is no longer used.
- *
- * We want to use demand paging as much as possible in order to avoid having to
- * read the entire file into memory (which could be detrimental to performance
- * for large files). This means that if we're on windows we'll use
- * `MapViewOfFile`, on POSIX systems that have access to `mmap` we'll use
- * `mmap`, and on other POSIX systems we'll use `read`.
- */
-PRISM_EXPORTED_FUNCTION pm_string_init_result_t
-pm_string_mapped_init(pm_string_t *string, const char *filepath) {
-#ifdef _WIN32
- // Open the file for reading.
- pm_string_file_handle_t handle;
- pm_string_init_result_t result = pm_string_file_handle_open(&handle, filepath);
- if (result != PM_STRING_INIT_SUCCESS) return result;
-
- // Get the file size.
- DWORD file_size = GetFileSize(handle.file, NULL);
- if (file_size == INVALID_FILE_SIZE) {
- pm_string_file_handle_close(&handle);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // If the file is empty, then we don't need to do anything else, we'll set
- // the source to a constant empty string and return.
- if (file_size == 0) {
- pm_string_file_handle_close(&handle);
- const uint8_t source[] = "";
- *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
- return PM_STRING_INIT_SUCCESS;
- }
-
- // Create a mapping of the file.
- HANDLE mapping = CreateFileMapping(handle.file, NULL, PAGE_READONLY, 0, 0, NULL);
- if (mapping == NULL) {
- pm_string_file_handle_close(&handle);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Map the file into memory.
- uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
- CloseHandle(mapping);
- pm_string_file_handle_close(&handle);
-
- if (source == NULL) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = (size_t) file_size };
- return PM_STRING_INIT_SUCCESS;
-#elif defined(_POSIX_MAPPED_FILES)
- // Open the file for reading
- int fd = open(filepath, O_RDONLY);
- if (fd == -1) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Stat the file to get the file size
- struct stat sb;
- if (fstat(fd, &sb) == -1) {
- close(fd);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Ensure it is a file and not a directory
- if (S_ISDIR(sb.st_mode)) {
- close(fd);
- return PM_STRING_INIT_ERROR_DIRECTORY;
- }
-
- // mmap the file descriptor to virtually get the contents
- size_t size = (size_t) sb.st_size;
- uint8_t *source = NULL;
-
- if (size == 0) {
- close(fd);
- const uint8_t source[] = "";
- *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
- return PM_STRING_INIT_SUCCESS;
- }
-
- source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (source == MAP_FAILED) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- close(fd);
- *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = size };
- return PM_STRING_INIT_SUCCESS;
-#else
- return pm_string_file_init(string, filepath);
-#endif
-}
-
-/**
- * Read the file indicated by the filepath parameter into source and load its
- * contents and size into the given `pm_string_t`. The given `pm_string_t`
- * should be freed using `pm_string_free` when it is no longer used.
- */
-PRISM_EXPORTED_FUNCTION pm_string_init_result_t
-pm_string_file_init(pm_string_t *string, const char *filepath) {
-#ifdef _WIN32
- // Open the file for reading.
- pm_string_file_handle_t handle;
- pm_string_init_result_t result = pm_string_file_handle_open(&handle, filepath);
- if (result != PM_STRING_INIT_SUCCESS) return result;
-
- // Get the file size.
- DWORD file_size = GetFileSize(handle.file, NULL);
- if (file_size == INVALID_FILE_SIZE) {
- pm_string_file_handle_close(&handle);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // If the file is empty, then we don't need to do anything else, we'll set
- // the source to a constant empty string and return.
- if (file_size == 0) {
- pm_string_file_handle_close(&handle);
- const uint8_t source[] = "";
- *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
- return PM_STRING_INIT_SUCCESS;
- }
-
- // Create a buffer to read the file into.
- uint8_t *source = xmalloc(file_size);
- if (source == NULL) {
- pm_string_file_handle_close(&handle);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Read the contents of the file
- DWORD bytes_read;
- if (!ReadFile(handle.file, source, file_size, &bytes_read, NULL)) {
- pm_string_file_handle_close(&handle);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Check the number of bytes read
- if (bytes_read != file_size) {
- xfree(source);
- pm_string_file_handle_close(&handle);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- pm_string_file_handle_close(&handle);
- *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = (size_t) file_size };
- return PM_STRING_INIT_SUCCESS;
-#elif defined(PRISM_HAS_FILESYSTEM)
- // Open the file for reading
- int fd = open(filepath, O_RDONLY);
- if (fd == -1) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Stat the file to get the file size
- struct stat sb;
- if (fstat(fd, &sb) == -1) {
- close(fd);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Ensure it is a file and not a directory
- if (S_ISDIR(sb.st_mode)) {
- close(fd);
- return PM_STRING_INIT_ERROR_DIRECTORY;
- }
-
- // Check the size to see if it's empty
- size_t size = (size_t) sb.st_size;
- if (size == 0) {
- close(fd);
- const uint8_t source[] = "";
- *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
- return PM_STRING_INIT_SUCCESS;
- }
-
- size_t length = (size_t) size;
- uint8_t *source = xmalloc(length);
- if (source == NULL) {
- close(fd);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- long bytes_read = (long) read(fd, source, length);
- close(fd);
-
- if (bytes_read == -1) {
- xfree(source);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = length };
- return PM_STRING_INIT_SUCCESS;
-#else
- (void) string;
- (void) filepath;
- perror("pm_string_file_init is not implemented for this platform");
- return PM_STRING_INIT_ERROR_GENERIC;
-#endif
-}
-
-/**
- * Ensure the string is owned. If it is not, then reinitialize it as owned and
- * copy over the previous source.
- */
-void
-pm_string_ensure_owned(pm_string_t *string) {
- if (string->type == PM_STRING_OWNED) return;
-
- size_t length = pm_string_length(string);
- const uint8_t *source = pm_string_source(string);
-
- uint8_t *memory = xmalloc(length);
- if (!memory) return;
-
- pm_string_owned_init(string, memory, length);
- memcpy((void *) string->source, source, length);
-}
-
-/**
- * Compare the underlying lengths and bytes of two strings. Returns 0 if the
- * strings are equal, a negative number if the left string is less than the
- * right string, and a positive number if the left string is greater than the
- * right string.
- */
-int
-pm_string_compare(const pm_string_t *left, const pm_string_t *right) {
- size_t left_length = pm_string_length(left);
- size_t right_length = pm_string_length(right);
-
- if (left_length < right_length) {
- return -1;
- } else if (left_length > right_length) {
- return 1;
- }
-
- return memcmp(pm_string_source(left), pm_string_source(right), left_length);
-}
-
-/**
- * Returns the length associated with the string.
- */
-PRISM_EXPORTED_FUNCTION size_t
-pm_string_length(const pm_string_t *string) {
- return string->length;
-}
-
-/**
- * Returns the start pointer associated with the string.
- */
-PRISM_EXPORTED_FUNCTION const uint8_t *
-pm_string_source(const pm_string_t *string) {
- return string->source;
-}
-
-/**
- * Free the associated memory of the given string.
- */
-PRISM_EXPORTED_FUNCTION void
-pm_string_free(pm_string_t *string) {
- void *memory = (void *) string->source;
-
- if (string->type == PM_STRING_OWNED) {
- xfree(memory);
-#ifdef PRISM_HAS_MMAP
- } else if (string->type == PM_STRING_MAPPED && string->length) {
-#if defined(_WIN32)
- UnmapViewOfFile(memory);
-#elif defined(_POSIX_MAPPED_FILES)
- munmap(memory, string->length);
-#endif
-#endif /* PRISM_HAS_MMAP */
- }
-}
diff --git a/prism/util/pm_string.h b/prism/util/pm_string.h
deleted file mode 100644
index f99f1abdf3..0000000000
--- a/prism/util/pm_string.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/**
- * @file pm_string.h
- *
- * A generic string type that can have various ownership semantics.
- */
-#ifndef PRISM_STRING_H
-#define PRISM_STRING_H
-
-#include "prism/defines.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-
-// The following headers are necessary to read files using demand paging.
-#ifdef _WIN32
-#include <windows.h>
-#elif defined(_POSIX_MAPPED_FILES)
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#elif defined(PRISM_HAS_FILESYSTEM)
-#include <fcntl.h>
-#include <sys/stat.h>
-#endif
-
-/**
- * A generic string type that can have various ownership semantics.
- */
-typedef struct {
- /** A pointer to the start of the string. */
- const uint8_t *source;
-
- /** The length of the string in bytes of memory. */
- size_t length;
-
- /** The type of the string. This field determines how the string should be freed. */
- enum {
- /** This string is a constant string, and should not be freed. */
- PM_STRING_CONSTANT,
-
- /** This is a slice of another string, and should not be freed. */
- PM_STRING_SHARED,
-
- /** This string owns its memory, and should be freed using `pm_string_free`. */
- PM_STRING_OWNED,
-
-#ifdef PRISM_HAS_MMAP
- /** This string is a memory-mapped file, and should be freed using `pm_string_free`. */
- PM_STRING_MAPPED
-#endif
- } type;
-} pm_string_t;
-
-/**
- * Returns the size of the pm_string_t struct. This is necessary to allocate the
- * correct amount of memory in the FFI backend.
- *
- * @return The size of the pm_string_t struct.
- */
-PRISM_EXPORTED_FUNCTION size_t pm_string_sizeof(void);
-
-/**
- * Defines an empty string. This is useful for initializing a string that will
- * be filled in later.
- */
-#define PM_STRING_EMPTY ((pm_string_t) { .type = PM_STRING_CONSTANT, .source = NULL, .length = 0 })
-
-/**
- * Initialize a shared string that is based on initial input.
- *
- * @param string The string to initialize.
- * @param start The start of the string.
- * @param end The end of the string.
- */
-void pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end);
-
-/**
- * Initialize an owned string that is responsible for freeing allocated memory.
- *
- * @param string The string to initialize.
- * @param source The source of the string.
- * @param length The length of the string.
- */
-void pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length);
-
-/**
- * Initialize a constant string that doesn't own its memory source.
- *
- * @param string The string to initialize.
- * @param source The source of the string.
- * @param length The length of the string.
- */
-void pm_string_constant_init(pm_string_t *string, const char *source, size_t length);
-
-/**
- * Represents the result of calling pm_string_mapped_init or
- * pm_string_file_init. We need this additional information because there is
- * not a platform-agnostic way to indicate that the file that was attempted to
- * be opened was a directory.
- */
-typedef enum {
- /** Indicates that the string was successfully initialized. */
- PM_STRING_INIT_SUCCESS = 0,
- /**
- * Indicates a generic error from a string_*_init function, where the type
- * of error should be read from `errno` or `GetLastError()`.
- */
- PM_STRING_INIT_ERROR_GENERIC = 1,
- /**
- * Indicates that the file that was attempted to be opened was a directory.
- */
- PM_STRING_INIT_ERROR_DIRECTORY = 2
-} pm_string_init_result_t;
-
-/**
- * Read the file indicated by the filepath parameter into source and load its
- * contents and size into the given `pm_string_t`. The given `pm_string_t`
- * should be freed using `pm_string_free` when it is no longer used.
- *
- * We want to use demand paging as much as possible in order to avoid having to
- * read the entire file into memory (which could be detrimental to performance
- * for large files). This means that if we're on windows we'll use
- * `MapViewOfFile`, on POSIX systems that have access to `mmap` we'll use
- * `mmap`, and on other POSIX systems we'll use `read`.
- *
- * @param string The string to initialize.
- * @param filepath The filepath to read.
- * @return The success of the read, indicated by the value of the enum.
- */
-PRISM_EXPORTED_FUNCTION pm_string_init_result_t pm_string_mapped_init(pm_string_t *string, const char *filepath);
-
-/**
- * Read the file indicated by the filepath parameter into source and load its
- * contents and size into the given `pm_string_t`. The given `pm_string_t`
- * should be freed using `pm_string_free` when it is no longer used.
- *
- * @param string The string to initialize.
- * @param filepath The filepath to read.
- * @return The success of the read, indicated by the value of the enum.
- */
-PRISM_EXPORTED_FUNCTION pm_string_init_result_t pm_string_file_init(pm_string_t *string, const char *filepath);
-
-/**
- * Ensure the string is owned. If it is not, then reinitialize it as owned and
- * copy over the previous source.
- *
- * @param string The string to ensure is owned.
- */
-void pm_string_ensure_owned(pm_string_t *string);
-
-/**
- * Compare the underlying lengths and bytes of two strings. Returns 0 if the
- * strings are equal, a negative number if the left string is less than the
- * right string, and a positive number if the left string is greater than the
- * right string.
- *
- * @param left The left string to compare.
- * @param right The right string to compare.
- * @return The comparison result.
- */
-int pm_string_compare(const pm_string_t *left, const pm_string_t *right);
-
-/**
- * Returns the length associated with the string.
- *
- * @param string The string to get the length of.
- * @return The length of the string.
- */
-PRISM_EXPORTED_FUNCTION size_t pm_string_length(const pm_string_t *string);
-
-/**
- * Returns the start pointer associated with the string.
- *
- * @param string The string to get the start pointer of.
- * @return The start pointer of the string.
- */
-PRISM_EXPORTED_FUNCTION const uint8_t * pm_string_source(const pm_string_t *string);
-
-/**
- * Free the associated memory of the given string.
- *
- * @param string The string to free.
- */
-PRISM_EXPORTED_FUNCTION void pm_string_free(pm_string_t *string);
-
-#endif
diff --git a/prism/util/pm_strncasecmp.c b/prism/util/pm_strncasecmp.c
deleted file mode 100644
index 2240bf8110..0000000000
--- a/prism/util/pm_strncasecmp.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "prism/util/pm_strncasecmp.h"
-
-/**
- * Compare two strings, ignoring case, up to the given length. Returns 0 if the
- * strings are equal, a negative number if string1 is less than string2, or a
- * positive number if string1 is greater than string2.
- *
- * Note that this is effectively our own implementation of strncasecmp, but it's
- * not available on all of the platforms we want to support so we're rolling it
- * here.
- */
-int
-pm_strncasecmp(const uint8_t *string1, const uint8_t *string2, size_t length) {
- size_t offset = 0;
- int difference = 0;
-
- while (offset < length && string1[offset] != '\0') {
- if (string2[offset] == '\0') return string1[offset];
- if ((difference = tolower(string1[offset]) - tolower(string2[offset])) != 0) return difference;
- offset++;
- }
-
- return difference;
-}
diff --git a/prism/util/pm_strncasecmp.h b/prism/util/pm_strncasecmp.h
deleted file mode 100644
index 5cb88cb5eb..0000000000
--- a/prism/util/pm_strncasecmp.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * @file pm_strncasecmp.h
- *
- * A custom strncasecmp implementation.
- */
-#ifndef PRISM_STRNCASECMP_H
-#define PRISM_STRNCASECMP_H
-
-#include "prism/defines.h"
-
-#include <ctype.h>
-#include <stddef.h>
-#include <stdint.h>
-
-/**
- * Compare two strings, ignoring case, up to the given length. Returns 0 if the
- * strings are equal, a negative number if string1 is less than string2, or a
- * positive number if string1 is greater than string2.
- *
- * Note that this is effectively our own implementation of strncasecmp, but it's
- * not available on all of the platforms we want to support so we're rolling it
- * here.
- *
- * @param string1 The first string to compare.
- * @param string2 The second string to compare
- * @param length The maximum number of characters to compare.
- * @return 0 if the strings are equal, a negative number if string1 is less than
- * string2, or a positive number if string1 is greater than string2.
- */
-int pm_strncasecmp(const uint8_t *string1, const uint8_t *string2, size_t length);
-
-#endif
diff --git a/prism/util/pm_strpbrk.c b/prism/util/pm_strpbrk.c
deleted file mode 100644
index 916a4cc3fd..0000000000
--- a/prism/util/pm_strpbrk.c
+++ /dev/null
@@ -1,206 +0,0 @@
-#include "prism/util/pm_strpbrk.h"
-
-/**
- * Add an invalid multibyte character error to the parser.
- */
-static inline void
-pm_strpbrk_invalid_multibyte_character(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
- pm_diagnostic_list_append_format(&parser->error_list, start, end, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *start);
-}
-
-/**
- * Set the explicit encoding for the parser to the current encoding.
- */
-static inline void
-pm_strpbrk_explicit_encoding_set(pm_parser_t *parser, const uint8_t *source, size_t width) {
- if (parser->explicit_encoding != NULL) {
- if (parser->explicit_encoding == parser->encoding) {
- // Okay, we already locked to this encoding.
- } else if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
- // Not okay, we already found a Unicode escape sequence and this
- // conflicts.
- pm_diagnostic_list_append_format(&parser->error_list, source, source + width, PM_ERR_MIXED_ENCODING, parser->encoding->name);
- } else {
- // Should not be anything else.
- assert(false && "unreachable");
- }
- }
-
- parser->explicit_encoding = parser->encoding;
-}
-
-/**
- * This is the default path.
- */
-static inline const uint8_t *
-pm_strpbrk_utf8(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum, bool validate) {
- size_t index = 0;
-
- while (index < maximum) {
- if (strchr((const char *) charset, source[index]) != NULL) {
- return source + index;
- }
-
- if (source[index] < 0x80) {
- index++;
- } else {
- size_t width = pm_encoding_utf_8_char_width(source + index, (ptrdiff_t) (maximum - index));
-
- if (width > 0) {
- index += width;
- } else if (!validate) {
- index++;
- } else {
- // At this point we know we have an invalid multibyte character.
- // We'll walk forward as far as we can until we find the next
- // valid character so that we don't spam the user with a ton of
- // the same kind of error.
- const size_t start = index;
-
- do {
- index++;
- } while (index < maximum && pm_encoding_utf_8_char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
-
- pm_strpbrk_invalid_multibyte_character(parser, source + start, source + index);
- }
- }
- }
-
- return NULL;
-}
-
-/**
- * This is the path when the encoding is ASCII-8BIT.
- */
-static inline const uint8_t *
-pm_strpbrk_ascii_8bit(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum, bool validate) {
- size_t index = 0;
-
- while (index < maximum) {
- if (strchr((const char *) charset, source[index]) != NULL) {
- return source + index;
- }
-
- if (validate && source[index] >= 0x80) pm_strpbrk_explicit_encoding_set(parser, source, 1);
- index++;
- }
-
- return NULL;
-}
-
-/**
- * This is the slow path that does care about the encoding.
- */
-static inline const uint8_t *
-pm_strpbrk_multi_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum, bool validate) {
- size_t index = 0;
- const pm_encoding_t *encoding = parser->encoding;
-
- while (index < maximum) {
- if (strchr((const char *) charset, source[index]) != NULL) {
- return source + index;
- }
-
- if (source[index] < 0x80) {
- index++;
- } else {
- size_t width = encoding->char_width(source + index, (ptrdiff_t) (maximum - index));
- if (validate) pm_strpbrk_explicit_encoding_set(parser, source, width);
-
- if (width > 0) {
- index += width;
- } else if (!validate) {
- index++;
- } else {
- // At this point we know we have an invalid multibyte character.
- // We'll walk forward as far as we can until we find the next
- // valid character so that we don't spam the user with a ton of
- // the same kind of error.
- const size_t start = index;
-
- do {
- index++;
- } while (index < maximum && encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
-
- pm_strpbrk_invalid_multibyte_character(parser, source + start, source + index);
- }
- }
- }
-
- return NULL;
-}
-
-/**
- * This is the fast path that does not care about the encoding because we know
- * the encoding only supports single-byte characters.
- */
-static inline const uint8_t *
-pm_strpbrk_single_byte(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, size_t maximum, bool validate) {
- size_t index = 0;
- const pm_encoding_t *encoding = parser->encoding;
-
- while (index < maximum) {
- if (strchr((const char *) charset, source[index]) != NULL) {
- return source + index;
- }
-
- if (source[index] < 0x80 || !validate) {
- index++;
- } else {
- size_t width = encoding->char_width(source + index, (ptrdiff_t) (maximum - index));
- pm_strpbrk_explicit_encoding_set(parser, source, width);
-
- if (width > 0) {
- index += width;
- } else {
- // At this point we know we have an invalid multibyte character.
- // We'll walk forward as far as we can until we find the next
- // valid character so that we don't spam the user with a ton of
- // the same kind of error.
- const size_t start = index;
-
- do {
- index++;
- } while (index < maximum && encoding->char_width(source + index, (ptrdiff_t) (maximum - index)) == 0);
-
- pm_strpbrk_invalid_multibyte_character(parser, source + start, source + index);
- }
- }
- }
-
- return NULL;
-}
-
-/**
- * Here we have rolled our own version of strpbrk. The standard library strpbrk
- * has undefined behavior when the source string is not null-terminated. We want
- * to support strings that are not null-terminated because pm_parse does not
- * have the contract that the string is null-terminated. (This is desirable
- * because it means the extension can call pm_parse with the result of a call to
- * mmap).
- *
- * The standard library strpbrk also does not support passing a maximum length
- * to search. We want to support this for the reason mentioned above, but we
- * also don't want it to stop on null bytes. Ruby actually allows null bytes
- * within strings, comments, regular expressions, etc. So we need to be able to
- * skip past them.
- *
- * Finally, we want to support encodings wherein the charset could contain
- * characters that are trailing bytes of multi-byte characters. For example, in
- * Shift_JIS, the backslash character can be a trailing byte. In that case we
- * need to take a slower path and iterate one multi-byte character at a time.
- */
-const uint8_t *
-pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length, bool validate) {
- if (length <= 0) {
- return NULL;
- } else if (!parser->encoding_changed) {
- return pm_strpbrk_utf8(parser, source, charset, (size_t) length, validate);
- } else if (parser->encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
- return pm_strpbrk_ascii_8bit(parser, source, charset, (size_t) length, validate);
- } else if (parser->encoding->multibyte) {
- return pm_strpbrk_multi_byte(parser, source, charset, (size_t) length, validate);
- } else {
- return pm_strpbrk_single_byte(parser, source, charset, (size_t) length, validate);
- }
-}
diff --git a/prism/util/pm_strpbrk.h b/prism/util/pm_strpbrk.h
deleted file mode 100644
index f387bd5782..0000000000
--- a/prism/util/pm_strpbrk.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * @file pm_strpbrk.h
- *
- * A custom strpbrk implementation.
- */
-#ifndef PRISM_STRPBRK_H
-#define PRISM_STRPBRK_H
-
-#include "prism/defines.h"
-#include "prism/diagnostic.h"
-#include "prism/parser.h"
-
-#include <stddef.h>
-#include <string.h>
-
-/**
- * Here we have rolled our own version of strpbrk. The standard library strpbrk
- * has undefined behavior when the source string is not null-terminated. We want
- * to support strings that are not null-terminated because pm_parse does not
- * have the contract that the string is null-terminated. (This is desirable
- * because it means the extension can call pm_parse with the result of a call to
- * mmap).
- *
- * The standard library strpbrk also does not support passing a maximum length
- * to search. We want to support this for the reason mentioned above, but we
- * also don't want it to stop on null bytes. Ruby actually allows null bytes
- * within strings, comments, regular expressions, etc. So we need to be able to
- * skip past them.
- *
- * Finally, we want to support encodings wherein the charset could contain
- * characters that are trailing bytes of multi-byte characters. For example, in
- * Shift-JIS, the backslash character can be a trailing byte. In that case we
- * need to take a slower path and iterate one multi-byte character at a time.
- *
- * @param parser The parser.
- * @param source The source to search.
- * @param charset The charset to search for.
- * @param length The maximum number of bytes to search.
- * @param validate Whether to validate that the source string is valid in the
- * current encoding of the parser.
- * @return A pointer to the first character in the source string that is in the
- * charset, or NULL if no such character exists.
- */
-const uint8_t * pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length, bool validate);
-
-#endif
diff --git a/prism/version.h b/prism/version.h
deleted file mode 100644
index 3cca648996..0000000000
--- a/prism/version.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * @file version.h
- *
- * The version of the Prism library.
- */
-#ifndef PRISM_VERSION_H
-#define PRISM_VERSION_H
-
-/**
- * The major version of the Prism library as an int.
- */
-#define PRISM_VERSION_MAJOR 1
-
-/**
- * The minor version of the Prism library as an int.
- */
-#define PRISM_VERSION_MINOR 0
-
-/**
- * The patch version of the Prism library as an int.
- */
-#define PRISM_VERSION_PATCH 0
-
-/**
- * The version of the Prism library as a constant string.
- */
-#define PRISM_VERSION "1.0.0"
-
-#endif
diff --git a/prism_compile.c b/prism_compile.c
deleted file mode 100644
index 5f5e0aa6fe..0000000000
--- a/prism_compile.c
+++ /dev/null
@@ -1,11072 +0,0 @@
-#include "prism.h"
-
-/**
- * This compiler defines its own concept of the location of a node. We do this
- * because we want to pair line information with node identifier so that we can
- * have reproducible parses.
- */
-typedef struct {
- /** This is the line number of a node. */
- int32_t line;
-
- /** This is a unique identifier for the node. */
- uint32_t node_id;
-} pm_node_location_t;
-
-/******************************************************************************/
-/* These macros operate on pm_node_location_t structs as opposed to NODE*s. */
-/******************************************************************************/
-
-#define PUSH_ADJUST(seq, location, label) \
- ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), (int) (location).line))
-
-#define PUSH_ADJUST_RESTORE(seq, label) \
- ADD_ELEM((seq), (LINK_ELEMENT *) new_adjust_body(iseq, (label), -1))
-
-#define PUSH_INSN(seq, location, insn) \
- ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (int) (location).line, (int) (location).node_id, BIN(insn), 0))
-
-#define PUSH_INSN1(seq, location, insn, op1) \
- ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (int) (location).line, (int) (location).node_id, BIN(insn), 1, (VALUE)(op1)))
-
-#define PUSH_INSN2(seq, location, insn, op1, op2) \
- ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (int) (location).line, (int) (location).node_id, BIN(insn), 2, (VALUE)(op1), (VALUE)(op2)))
-
-#define PUSH_INSN3(seq, location, insn, op1, op2, op3) \
- ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_body(iseq, (int) (location).line, (int) (location).node_id, BIN(insn), 3, (VALUE)(op1), (VALUE)(op2), (VALUE)(op3)))
-
-#define PUSH_INSNL(seq, location, insn, label) \
- (PUSH_INSN1(seq, location, insn, label), LABEL_REF(label))
-
-#define PUSH_LABEL(seq, label) \
- ADD_ELEM((seq), (LINK_ELEMENT *) (label))
-
-#define PUSH_SEND_R(seq, location, id, argc, block, flag, keywords) \
- ADD_ELEM((seq), (LINK_ELEMENT *) new_insn_send(iseq, (int) (location).line, (int) (location).node_id, (id), (VALUE)(argc), (block), (VALUE)(flag), (keywords)))
-
-#define PUSH_SEND(seq, location, id, argc) \
- PUSH_SEND_R((seq), location, (id), (argc), NULL, (VALUE)INT2FIX(0), NULL)
-
-#define PUSH_SEND_WITH_FLAG(seq, location, id, argc, flag) \
- PUSH_SEND_R((seq), location, (id), (argc), NULL, (VALUE)(flag), NULL)
-
-#define PUSH_SEND_WITH_BLOCK(seq, location, id, argc, block) \
- PUSH_SEND_R((seq), location, (id), (argc), (block), (VALUE)INT2FIX(0), NULL)
-
-#define PUSH_CALL(seq, location, id, argc) \
- PUSH_SEND_R((seq), location, (id), (argc), NULL, (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
-
-#define PUSH_CALL_WITH_BLOCK(seq, location, id, argc, block) \
- PUSH_SEND_R((seq), location, (id), (argc), (block), (VALUE)INT2FIX(VM_CALL_FCALL), NULL)
-
-#define PUSH_TRACE(seq, event) \
- ADD_ELEM((seq), (LINK_ELEMENT *) new_trace_body(iseq, (event), 0))
-
-#define PUSH_CATCH_ENTRY(type, ls, le, iseqv, lc) \
- ADD_CATCH_ENTRY((type), (ls), (le), (iseqv), (lc))
-
-#define PUSH_SEQ(seq1, seq2) \
- APPEND_LIST((seq1), (seq2))
-
-#define PUSH_SYNTHETIC_PUTNIL(seq, iseq) \
- do { \
- int lineno = ISEQ_COMPILE_DATA(iseq)->last_line; \
- if (lineno == 0) lineno = FIX2INT(rb_iseq_first_lineno(iseq)); \
- ADD_SYNTHETIC_INSN(seq, lineno, -1, putnil); \
- } while (0)
-
-/******************************************************************************/
-/* These functions compile getlocal/setlocal instructions but operate on */
-/* prism locations instead of NODEs. */
-/******************************************************************************/
-
-static void
-pm_iseq_add_getlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int node_id, int idx, int level)
-{
- if (iseq_local_block_param_p(iseq, idx, level)) {
- ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line, node_id, BIN(getblockparam), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level)));
- }
- else {
- ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line, node_id, BIN(getlocal), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level)));
- }
- if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qfalse);
-}
-
-static void
-pm_iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, int line, int node_id, int idx, int level)
-{
- if (iseq_local_block_param_p(iseq, idx, level)) {
- ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line, node_id, BIN(setblockparam), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level)));
- }
- else {
- ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line, node_id, BIN(setlocal), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level)));
- }
- if (level > 0) access_outer_variables(iseq, level, iseq_lvar_id(iseq, idx, level), Qtrue);
-}
-
-#define PUSH_GETLOCAL(seq, location, idx, level) \
- pm_iseq_add_getlocal(iseq, (seq), (int) (location).line, (int) (location).node_id, (idx), (level))
-
-#define PUSH_SETLOCAL(seq, location, idx, level) \
- pm_iseq_add_setlocal(iseq, (seq), (int) (location).line, (int) (location).node_id, (idx), (level))
-
-/******************************************************************************/
-/* These are helper macros for the compiler. */
-/******************************************************************************/
-
-#define OLD_ISEQ NEW_ISEQ
-#undef NEW_ISEQ
-
-#define NEW_ISEQ(node, name, type, line_no) \
- pm_new_child_iseq(iseq, (node), rb_fstring(name), 0, (type), (line_no))
-
-#define OLD_CHILD_ISEQ NEW_CHILD_ISEQ
-#undef NEW_CHILD_ISEQ
-
-#define NEW_CHILD_ISEQ(node, name, type, line_no) \
- pm_new_child_iseq(iseq, (node), rb_fstring(name), iseq, (type), (line_no))
-
-#define PM_COMPILE(node) \
- pm_compile_node(iseq, (node), ret, popped, scope_node)
-
-#define PM_COMPILE_INTO_ANCHOR(_ret, node) \
- pm_compile_node(iseq, (node), _ret, popped, scope_node)
-
-#define PM_COMPILE_POPPED(node) \
- pm_compile_node(iseq, (node), ret, true, scope_node)
-
-#define PM_COMPILE_NOT_POPPED(node) \
- pm_compile_node(iseq, (node), ret, false, scope_node)
-
-#define PM_SPECIAL_CONSTANT_FLAG ((pm_constant_id_t)(1 << 31))
-#define PM_CONSTANT_AND ((pm_constant_id_t)(idAnd | PM_SPECIAL_CONSTANT_FLAG))
-#define PM_CONSTANT_DOT3 ((pm_constant_id_t)(idDot3 | PM_SPECIAL_CONSTANT_FLAG))
-#define PM_CONSTANT_MULT ((pm_constant_id_t)(idMULT | PM_SPECIAL_CONSTANT_FLAG))
-#define PM_CONSTANT_POW ((pm_constant_id_t)(idPow | PM_SPECIAL_CONSTANT_FLAG))
-
-#define PM_NODE_START_LOCATION(parser, node) \
- ((pm_node_location_t) { .line = pm_newline_list_line(&(parser)->newline_list, ((const pm_node_t *) (node))->location.start, (parser)->start_line), .node_id = ((const pm_node_t *) (node))->node_id })
-
-#define PM_NODE_END_LOCATION(parser, node) \
- ((pm_node_location_t) { .line = pm_newline_list_line(&(parser)->newline_list, ((const pm_node_t *) (node))->location.end, (parser)->start_line), .node_id = ((const pm_node_t *) (node))->node_id })
-
-#define PM_LOCATION_START_LOCATION(parser, location, id) \
- ((pm_node_location_t) { .line = pm_newline_list_line(&(parser)->newline_list, (location)->start, (parser)->start_line), .node_id = id })
-
-#define PM_NODE_START_LINE_COLUMN(parser, node) \
- pm_newline_list_line_column(&(parser)->newline_list, ((const pm_node_t *) (node))->location.start, (parser)->start_line)
-
-#define PM_NODE_END_LINE_COLUMN(parser, node) \
- pm_newline_list_line_column(&(parser)->newline_list, ((const pm_node_t *) (node))->location.end, (parser)->start_line)
-
-#define PM_LOCATION_START_LINE_COLUMN(parser, location) \
- pm_newline_list_line_column(&(parser)->newline_list, (location)->start, (parser)->start_line)
-
-static int
-pm_node_line_number(const pm_parser_t *parser, const pm_node_t *node)
-{
- return (int) pm_newline_list_line(&parser->newline_list, node->location.start, parser->start_line);
-}
-
-static int
-pm_location_line_number(const pm_parser_t *parser, const pm_location_t *location) {
- return (int) pm_newline_list_line(&parser->newline_list, location->start, parser->start_line);
-}
-
-/**
- * Parse the value of a pm_integer_t into a Ruby Integer.
- */
-static VALUE
-parse_integer_value(const pm_integer_t *integer)
-{
- VALUE result;
-
- if (integer->values == NULL) {
- result = UINT2NUM(integer->value);
- }
- else {
- VALUE string = rb_str_new(NULL, integer->length * 8);
- unsigned char *bytes = (unsigned char *) RSTRING_PTR(string);
-
- size_t offset = integer->length * 8;
- for (size_t value_index = 0; value_index < integer->length; value_index++) {
- uint32_t value = integer->values[value_index];
-
- for (int index = 0; index < 8; index++) {
- int byte = (value >> (4 * index)) & 0xf;
- bytes[--offset] = byte < 10 ? byte + '0' : byte - 10 + 'a';
- }
- }
-
- result = rb_funcall(string, rb_intern("to_i"), 1, UINT2NUM(16));
- }
-
- if (integer->negative) {
- result = rb_funcall(result, rb_intern("-@"), 0);
- }
-
- return result;
-}
-
-/**
- * Convert the value of an integer node into a Ruby Integer.
- */
-static inline VALUE
-parse_integer(const pm_integer_node_t *node)
-{
- return parse_integer_value(&node->value);
-}
-
-/**
- * Convert the value of a float node into a Ruby Float.
- */
-static VALUE
-parse_float(const pm_float_node_t *node)
-{
- return DBL2NUM(node->value);
-}
-
-/**
- * Convert the value of a rational node into a Ruby Rational. Rational nodes can
- * either be wrapping an integer node or a float node. If it's an integer node,
- * we can reuse our parsing. If it's not, then we'll parse the numerator and
- * then parse the denominator and create the rational from those two values.
- */
-static VALUE
-parse_rational(const pm_rational_node_t *node)
-{
- VALUE numerator = parse_integer_value(&node->numerator);
- VALUE denominator = parse_integer_value(&node->denominator);
- return rb_rational_new(numerator, denominator);
-}
-
-/**
- * Convert the value of an imaginary node into a Ruby Complex. Imaginary nodes
- * can be wrapping an integer node, a float node, or a rational node. In all
- * cases we will reuse parsing functions seen above to get the inner value, and
- * then convert into an imaginary with rb_complex_raw.
- */
-static VALUE
-parse_imaginary(const pm_imaginary_node_t *node)
-{
- VALUE imaginary_part;
- switch (PM_NODE_TYPE(node->numeric)) {
- case PM_FLOAT_NODE: {
- imaginary_part = parse_float((const pm_float_node_t *) node->numeric);
- break;
- }
- case PM_INTEGER_NODE: {
- imaginary_part = parse_integer((const pm_integer_node_t *) node->numeric);
- break;
- }
- case PM_RATIONAL_NODE: {
- imaginary_part = parse_rational((const pm_rational_node_t *) node->numeric);
- break;
- }
- default:
- rb_bug("Unexpected numeric type on imaginary number %s\n", pm_node_type_to_str(PM_NODE_TYPE(node->numeric)));
- }
-
- return rb_complex_raw(INT2FIX(0), imaginary_part);
-}
-
-static inline VALUE
-parse_string(const pm_scope_node_t *scope_node, const pm_string_t *string)
-{
- return rb_enc_str_new((const char *) pm_string_source(string), pm_string_length(string), scope_node->encoding);
-}
-
-/**
- * Certain strings can have their encoding differ from the parser's encoding due
- * to bytes or escape sequences that have the top bit set. This function handles
- * creating those strings based on the flags set on the owning node.
- */
-static inline VALUE
-parse_string_encoded(const pm_node_t *node, const pm_string_t *string, rb_encoding *default_encoding)
-{
- rb_encoding *encoding;
-
- if (node->flags & PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING) {
- encoding = rb_ascii8bit_encoding();
- }
- else if (node->flags & PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING) {
- encoding = rb_utf8_encoding();
- }
- else {
- encoding = default_encoding;
- }
-
- return rb_enc_str_new((const char *) pm_string_source(string), pm_string_length(string), encoding);
-}
-
-static inline VALUE
-parse_static_literal_string(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, const pm_string_t *string)
-{
- rb_encoding *encoding;
-
- if (node->flags & PM_STRING_FLAGS_FORCED_BINARY_ENCODING) {
- encoding = rb_ascii8bit_encoding();
- }
- else if (node->flags & PM_STRING_FLAGS_FORCED_UTF8_ENCODING) {
- encoding = rb_utf8_encoding();
- }
- else {
- encoding = scope_node->encoding;
- }
-
- VALUE value = rb_enc_literal_str((const char *) pm_string_source(string), pm_string_length(string), encoding);
- rb_enc_str_coderange(value);
-
- if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
- int line_number = pm_node_line_number(scope_node->parser, node);
- VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line_number));
- value = rb_str_dup(value);
- rb_ivar_set(value, id_debug_created_info, rb_ary_freeze(debug_info));
- rb_str_freeze(value);
- }
-
- return value;
-}
-
-static inline ID
-parse_string_symbol(const pm_scope_node_t *scope_node, const pm_symbol_node_t *symbol)
-{
- rb_encoding *encoding;
- if (symbol->base.flags & PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING) {
- encoding = rb_utf8_encoding();
- }
- else if (symbol->base.flags & PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING) {
- encoding = rb_ascii8bit_encoding();
- }
- else if (symbol->base.flags & PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING) {
- encoding = rb_usascii_encoding();
- }
- else {
- encoding = scope_node->encoding;
- }
-
- return rb_intern3((const char *) pm_string_source(&symbol->unescaped), pm_string_length(&symbol->unescaped), encoding);
-}
-
-static int
-pm_optimizable_range_item_p(const pm_node_t *node)
-{
- return (!node || PM_NODE_TYPE_P(node, PM_INTEGER_NODE) || PM_NODE_TYPE_P(node, PM_NIL_NODE));
-}
-
-/** Raise an error corresponding to the invalid regular expression. */
-static VALUE
-parse_regexp_error(rb_iseq_t *iseq, int32_t line_number, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- VALUE error = rb_syntax_error_append(Qnil, rb_iseq_path(iseq), line_number, -1, NULL, "%" PRIsVALUE, args);
- va_end(args);
- rb_exc_raise(error);
-}
-
-static VALUE
-parse_regexp_string_part(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, const pm_string_t *unescaped, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding)
-{
- // If we were passed an explicit regexp encoding, then we need to double
- // check that it's okay here for this fragment of the string.
- rb_encoding *encoding;
-
- if (explicit_regexp_encoding != NULL) {
- encoding = explicit_regexp_encoding;
- }
- else if (node->flags & PM_STRING_FLAGS_FORCED_BINARY_ENCODING) {
- encoding = rb_ascii8bit_encoding();
- }
- else if (node->flags & PM_STRING_FLAGS_FORCED_UTF8_ENCODING) {
- encoding = rb_utf8_encoding();
- }
- else {
- encoding = implicit_regexp_encoding;
- }
-
- VALUE string = rb_enc_str_new((const char *) pm_string_source(unescaped), pm_string_length(unescaped), encoding);
- VALUE error = rb_reg_check_preprocess(string);
-
- if (error != Qnil) parse_regexp_error(iseq, pm_node_line_number(scope_node->parser, node), "%" PRIsVALUE, rb_obj_as_string(error));
- return string;
-}
-
-static VALUE
-pm_static_literal_concat(rb_iseq_t *iseq, const pm_node_list_t *nodes, const pm_scope_node_t *scope_node, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding, bool top)
-{
- VALUE current = Qnil;
-
- for (size_t index = 0; index < nodes->size; index++) {
- const pm_node_t *part = nodes->nodes[index];
- VALUE string;
-
- switch (PM_NODE_TYPE(part)) {
- case PM_STRING_NODE:
- if (implicit_regexp_encoding != NULL) {
- if (top) {
- string = parse_regexp_string_part(iseq, scope_node, part, &((const pm_string_node_t *) part)->unescaped, implicit_regexp_encoding, explicit_regexp_encoding);
- }
- else {
- string = parse_string_encoded(part, &((const pm_string_node_t *) part)->unescaped, scope_node->encoding);
- VALUE error = rb_reg_check_preprocess(string);
- if (error != Qnil) parse_regexp_error(iseq, pm_node_line_number(scope_node->parser, part), "%" PRIsVALUE, rb_obj_as_string(error));
- }
- }
- else {
- string = parse_string_encoded(part, &((const pm_string_node_t *) part)->unescaped, scope_node->encoding);
- }
- break;
- case PM_INTERPOLATED_STRING_NODE:
- string = pm_static_literal_concat(iseq, &((const pm_interpolated_string_node_t *) part)->parts, scope_node, implicit_regexp_encoding, explicit_regexp_encoding, false);
- break;
- case PM_EMBEDDED_STATEMENTS_NODE: {
- const pm_embedded_statements_node_t *cast = (const pm_embedded_statements_node_t *) part;
- string = pm_static_literal_concat(iseq, &cast->statements->body, scope_node, implicit_regexp_encoding, explicit_regexp_encoding, false);
- break;
- }
- default:
- RUBY_ASSERT(false && "unexpected node type in pm_static_literal_concat");
- return Qnil;
- }
-
- if (current != Qnil) {
- current = rb_str_concat(current, string);
- }
- else {
- current = string;
- }
- }
-
- return top ? rb_fstring(current) : current;
-}
-
-#define RE_OPTION_ENCODING_SHIFT 8
-#define RE_OPTION_ENCODING(encoding) (((encoding) & 0xFF) << RE_OPTION_ENCODING_SHIFT)
-#define ARG_ENCODING_NONE 32
-#define ARG_ENCODING_FIXED 16
-#define ENC_ASCII8BIT 1
-#define ENC_EUC_JP 2
-#define ENC_Windows_31J 3
-#define ENC_UTF8 4
-
-/**
- * Check the prism flags of a regular expression-like node and return the flags
- * that are expected by the CRuby VM.
- */
-static int
-parse_regexp_flags(const pm_node_t *node)
-{
- int flags = 0;
-
- // Check "no encoding" first so that flags don't get clobbered
- // We're calling `rb_char_to_option_kcode` in this case so that
- // we don't need to have access to `ARG_ENCODING_NONE`
- if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) {
- flags |= ARG_ENCODING_NONE;
- }
-
- if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) {
- flags |= (ARG_ENCODING_FIXED | RE_OPTION_ENCODING(ENC_EUC_JP));
- }
-
- if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) {
- flags |= (ARG_ENCODING_FIXED | RE_OPTION_ENCODING(ENC_Windows_31J));
- }
-
- if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) {
- flags |= (ARG_ENCODING_FIXED | RE_OPTION_ENCODING(ENC_UTF8));
- }
-
- if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE)) {
- flags |= ONIG_OPTION_IGNORECASE;
- }
-
- if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE)) {
- flags |= ONIG_OPTION_MULTILINE;
- }
-
- if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED)) {
- flags |= ONIG_OPTION_EXTEND;
- }
-
- return flags;
-}
-
-#undef RE_OPTION_ENCODING_SHIFT
-#undef RE_OPTION_ENCODING
-#undef ARG_ENCODING_FIXED
-#undef ARG_ENCODING_NONE
-#undef ENC_ASCII8BIT
-#undef ENC_EUC_JP
-#undef ENC_Windows_31J
-#undef ENC_UTF8
-
-static rb_encoding *
-parse_regexp_encoding(const pm_scope_node_t *scope_node, const pm_node_t *node)
-{
- if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING) || PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT)) {
- return rb_ascii8bit_encoding();
- }
- else if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_UTF_8)) {
- return rb_utf8_encoding();
- }
- else if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EUC_JP)) {
- return rb_enc_get_from_index(ENCINDEX_EUC_JP);
- }
- else if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J)) {
- return rb_enc_get_from_index(ENCINDEX_Windows_31J);
- }
- else {
- return NULL;
- }
-}
-
-static VALUE
-parse_regexp(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, VALUE string)
-{
- VALUE errinfo = rb_errinfo();
-
- int32_t line_number = pm_node_line_number(scope_node->parser, node);
- VALUE regexp = rb_reg_compile(string, parse_regexp_flags(node), (const char *) pm_string_source(&scope_node->parser->filepath), line_number);
-
- if (NIL_P(regexp)) {
- VALUE message = rb_attr_get(rb_errinfo(), idMesg);
- rb_set_errinfo(errinfo);
-
- parse_regexp_error(iseq, line_number, "%" PRIsVALUE, message);
- return Qnil;
- }
-
- rb_obj_freeze(regexp);
- return regexp;
-}
-
-static inline VALUE
-parse_regexp_literal(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, const pm_string_t *unescaped)
-{
- rb_encoding *regexp_encoding = parse_regexp_encoding(scope_node, node);
- if (regexp_encoding == NULL) regexp_encoding = scope_node->encoding;
-
- VALUE string = rb_enc_str_new((const char *) pm_string_source(unescaped), pm_string_length(unescaped), regexp_encoding);
- return parse_regexp(iseq, scope_node, node, string);
-}
-
-static inline VALUE
-parse_regexp_concat(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, const pm_node_list_t *parts)
-{
- rb_encoding *explicit_regexp_encoding = parse_regexp_encoding(scope_node, node);
- rb_encoding *implicit_regexp_encoding = explicit_regexp_encoding != NULL ? explicit_regexp_encoding : scope_node->encoding;
-
- VALUE string = pm_static_literal_concat(iseq, parts, scope_node, implicit_regexp_encoding, explicit_regexp_encoding, false);
- return parse_regexp(iseq, scope_node, node, string);
-}
-
-static void pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node);
-
-static int
-pm_interpolated_node_compile(rb_iseq_t *iseq, const pm_node_list_t *parts, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, rb_encoding *implicit_regexp_encoding, rb_encoding *explicit_regexp_encoding)
-{
- int stack_size = 0;
- size_t parts_size = parts->size;
- bool interpolated = false;
-
- if (parts_size > 0) {
- VALUE current_string = Qnil;
- pm_node_location_t current_location = *node_location;
-
- for (size_t index = 0; index < parts_size; index++) {
- const pm_node_t *part = parts->nodes[index];
-
- if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
- const pm_string_node_t *string_node = (const pm_string_node_t *) part;
- VALUE string_value;
-
- if (implicit_regexp_encoding == NULL) {
- string_value = parse_string_encoded(part, &string_node->unescaped, scope_node->encoding);
- }
- else {
- string_value = parse_regexp_string_part(iseq, scope_node, (const pm_node_t *) string_node, &string_node->unescaped, implicit_regexp_encoding, explicit_regexp_encoding);
- }
-
- if (RTEST(current_string)) {
- current_string = rb_str_concat(current_string, string_value);
- }
- else {
- current_string = string_value;
- if (index != 0) current_location = PM_NODE_END_LOCATION(scope_node->parser, part);
- }
- }
- else {
- interpolated = true;
-
- if (
- PM_NODE_TYPE_P(part, PM_EMBEDDED_STATEMENTS_NODE) &&
- ((const pm_embedded_statements_node_t *) part)->statements != NULL &&
- ((const pm_embedded_statements_node_t *) part)->statements->body.size == 1 &&
- PM_NODE_TYPE_P(((const pm_embedded_statements_node_t *) part)->statements->body.nodes[0], PM_STRING_NODE)
- ) {
- const pm_string_node_t *string_node = (const pm_string_node_t *) ((const pm_embedded_statements_node_t *) part)->statements->body.nodes[0];
- VALUE string_value;
-
- if (implicit_regexp_encoding == NULL) {
- string_value = parse_string_encoded(part, &string_node->unescaped, scope_node->encoding);
- }
- else {
- string_value = parse_regexp_string_part(iseq, scope_node, (const pm_node_t *) string_node, &string_node->unescaped, implicit_regexp_encoding, explicit_regexp_encoding);
- }
-
- if (RTEST(current_string)) {
- current_string = rb_str_concat(current_string, string_value);
- }
- else {
- current_string = string_value;
- current_location = PM_NODE_START_LOCATION(scope_node->parser, part);
- }
- }
- else {
- if (!RTEST(current_string)) {
- rb_encoding *encoding;
-
- if (implicit_regexp_encoding != NULL) {
- if (explicit_regexp_encoding != NULL) {
- encoding = explicit_regexp_encoding;
- }
- else if (scope_node->parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
- encoding = rb_ascii8bit_encoding();
- }
- else {
- encoding = implicit_regexp_encoding;
- }
- }
- else {
- encoding = scope_node->encoding;
- }
-
- if (parts_size == 1) {
- current_string = rb_enc_str_new(NULL, 0, encoding);
- }
- }
-
- if (RTEST(current_string)) {
- VALUE operand = rb_fstring(current_string);
- PUSH_INSN1(ret, current_location, putobject, operand);
- stack_size++;
- }
-
- PM_COMPILE_NOT_POPPED(part);
-
- const pm_node_location_t current_location = PM_NODE_START_LOCATION(scope_node->parser, part);
- PUSH_INSN(ret, current_location, dup);
-
- {
- const struct rb_callinfo *callinfo = new_callinfo(iseq, idTo_s, 0, VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE, NULL, FALSE);
- PUSH_INSN1(ret, current_location, objtostring, callinfo);
- }
-
- PUSH_INSN(ret, current_location, anytostring);
-
- current_string = Qnil;
- stack_size++;
- }
- }
- }
-
- if (RTEST(current_string)) {
- current_string = rb_fstring(current_string);
-
- if (stack_size == 0 && interpolated) {
- PUSH_INSN1(ret, current_location, putstring, current_string);
- }
- else {
- PUSH_INSN1(ret, current_location, putobject, current_string);
- }
-
- current_string = Qnil;
- stack_size++;
- }
- }
- else {
- PUSH_INSN(ret, *node_location, putnil);
- }
-
- return stack_size;
-}
-
-static void
-pm_compile_regexp_dynamic(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list_t *parts, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- rb_encoding *explicit_regexp_encoding = parse_regexp_encoding(scope_node, node);
- rb_encoding *implicit_regexp_encoding = explicit_regexp_encoding != NULL ? explicit_regexp_encoding : scope_node->encoding;
-
- int length = pm_interpolated_node_compile(iseq, parts, node_location, ret, popped, scope_node, implicit_regexp_encoding, explicit_regexp_encoding);
- PUSH_INSN2(ret, *node_location, toregexp, INT2FIX(parse_regexp_flags(node) & 0xFF), INT2FIX(length));
-}
-
-static VALUE
-pm_source_file_value(const pm_source_file_node_t *node, const pm_scope_node_t *scope_node)
-{
- const pm_string_t *filepath = &node->filepath;
- size_t length = pm_string_length(filepath);
-
- if (length > 0) {
- rb_encoding *filepath_encoding = scope_node->filepath_encoding != NULL ? scope_node->filepath_encoding : rb_utf8_encoding();
- return rb_enc_interned_str((const char *) pm_string_source(filepath), length, filepath_encoding);
- }
- else {
- return rb_fstring_lit("<compiled>");
- }
-}
-
-/**
- * Return a static literal string, optionally with attached debugging
- * information.
- */
-static VALUE
-pm_static_literal_string(rb_iseq_t *iseq, VALUE string, int line_number)
-{
- if (ISEQ_COMPILE_DATA(iseq)->option->debug_frozen_string_literal || RTEST(ruby_debug)) {
- VALUE debug_info = rb_ary_new_from_args(2, rb_iseq_path(iseq), INT2FIX(line_number));
- rb_ivar_set(string, id_debug_created_info, rb_ary_freeze(debug_info));
- return rb_str_freeze(string);
- }
- else {
- return rb_fstring(string);
- }
-}
-
-/**
- * Certain nodes can be compiled literally. This function returns the literal
- * value described by the given node. For example, an array node with all static
- * literal values can be compiled into a literal array.
- */
-static VALUE
-pm_static_literal_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_node_t *scope_node)
-{
- // Every node that comes into this function should already be marked as
- // static literal. If it's not, then we have a bug somewhere.
- RUBY_ASSERT(PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL));
-
- switch (PM_NODE_TYPE(node)) {
- case PM_ARRAY_NODE: {
- const pm_array_node_t *cast = (const pm_array_node_t *) node;
- const pm_node_list_t *elements = &cast->elements;
-
- VALUE value = rb_ary_hidden_new(elements->size);
- for (size_t index = 0; index < elements->size; index++) {
- rb_ary_push(value, pm_static_literal_value(iseq, elements->nodes[index], scope_node));
- }
-
- OBJ_FREEZE(value);
- return value;
- }
- case PM_FALSE_NODE:
- return Qfalse;
- case PM_FLOAT_NODE:
- return parse_float((const pm_float_node_t *) node);
- case PM_HASH_NODE: {
- const pm_hash_node_t *cast = (const pm_hash_node_t *) node;
- const pm_node_list_t *elements = &cast->elements;
-
- VALUE array = rb_ary_hidden_new(elements->size * 2);
- for (size_t index = 0; index < elements->size; index++) {
- RUBY_ASSERT(PM_NODE_TYPE_P(elements->nodes[index], PM_ASSOC_NODE));
- const pm_assoc_node_t *cast = (const pm_assoc_node_t *) elements->nodes[index];
- VALUE pair[2] = { pm_static_literal_value(iseq, cast->key, scope_node), pm_static_literal_value(iseq, cast->value, scope_node) };
- rb_ary_cat(array, pair, 2);
- }
-
- VALUE value = rb_hash_new_with_size(elements->size);
- rb_hash_bulk_insert(RARRAY_LEN(array), RARRAY_CONST_PTR(array), value);
-
- value = rb_obj_hide(value);
- OBJ_FREEZE(value);
- return value;
- }
- case PM_IMAGINARY_NODE:
- return parse_imaginary((const pm_imaginary_node_t *) node);
- case PM_INTEGER_NODE:
- return parse_integer((const pm_integer_node_t *) node);
- case PM_INTERPOLATED_MATCH_LAST_LINE_NODE: {
- const pm_interpolated_match_last_line_node_t *cast = (const pm_interpolated_match_last_line_node_t *) node;
- return parse_regexp_concat(iseq, scope_node, (const pm_node_t *) cast, &cast->parts);
- }
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
- const pm_interpolated_regular_expression_node_t *cast = (const pm_interpolated_regular_expression_node_t *) node;
- return parse_regexp_concat(iseq, scope_node, (const pm_node_t *) cast, &cast->parts);
- }
- case PM_INTERPOLATED_STRING_NODE: {
- VALUE string = pm_static_literal_concat(iseq, &((const pm_interpolated_string_node_t *) node)->parts, scope_node, NULL, NULL, false);
- int line_number = pm_node_line_number(scope_node->parser, node);
- return pm_static_literal_string(iseq, string, line_number);
- }
- case PM_INTERPOLATED_SYMBOL_NODE: {
- const pm_interpolated_symbol_node_t *cast = (const pm_interpolated_symbol_node_t *) node;
- VALUE string = pm_static_literal_concat(iseq, &cast->parts, scope_node, NULL, NULL, true);
-
- return ID2SYM(rb_intern_str(string));
- }
- case PM_MATCH_LAST_LINE_NODE: {
- const pm_match_last_line_node_t *cast = (const pm_match_last_line_node_t *) node;
- return parse_regexp_literal(iseq, scope_node, (const pm_node_t *) cast, &cast->unescaped);
- }
- case PM_NIL_NODE:
- return Qnil;
- case PM_RATIONAL_NODE:
- return parse_rational((const pm_rational_node_t *) node);
- case PM_REGULAR_EXPRESSION_NODE: {
- const pm_regular_expression_node_t *cast = (const pm_regular_expression_node_t *) node;
- return parse_regexp_literal(iseq, scope_node, (const pm_node_t *) cast, &cast->unescaped);
- }
- case PM_SOURCE_ENCODING_NODE:
- return rb_enc_from_encoding(scope_node->encoding);
- case PM_SOURCE_FILE_NODE: {
- const pm_source_file_node_t *cast = (const pm_source_file_node_t *) node;
- return pm_source_file_value(cast, scope_node);
- }
- case PM_SOURCE_LINE_NODE:
- return INT2FIX(pm_node_line_number(scope_node->parser, node));
- case PM_STRING_NODE: {
- const pm_string_node_t *cast = (const pm_string_node_t *) node;
- return parse_static_literal_string(iseq, scope_node, node, &cast->unescaped);
- }
- case PM_SYMBOL_NODE:
- return ID2SYM(parse_string_symbol(scope_node, (const pm_symbol_node_t *) node));
- case PM_TRUE_NODE:
- return Qtrue;
- default:
- rb_bug("Don't have a literal value for node type %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
- return Qfalse;
- }
-}
-
-/**
- * A helper for converting a pm_location_t into a rb_code_location_t.
- */
-static rb_code_location_t
-pm_code_location(const pm_scope_node_t *scope_node, const pm_node_t *node)
-{
- const pm_line_column_t start_location = PM_NODE_START_LINE_COLUMN(scope_node->parser, node);
- const pm_line_column_t end_location = PM_NODE_END_LINE_COLUMN(scope_node->parser, node);
-
- return (rb_code_location_t) {
- .beg_pos = { .lineno = start_location.line, .column = start_location.column },
- .end_pos = { .lineno = end_location.line, .column = end_location.column }
- };
-}
-
-/**
- * A macro for determining if we should go through the work of adding branch
- * coverage to the current iseq. We check this manually each time because we
- * want to avoid the overhead of creating rb_code_location_t objects.
- */
-#define PM_BRANCH_COVERAGE_P(iseq) (ISEQ_COVERAGE(iseq) && ISEQ_BRANCH_COVERAGE(iseq))
-
-static void
-pm_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_node_t *cond,
- LABEL *then_label, LABEL *else_label, bool popped, pm_scope_node_t *scope_node);
-
-static void
-pm_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_node_t *cond, LABEL *then_label, LABEL *else_label, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, cond);
-
- DECL_ANCHOR(seq);
- INIT_ANCHOR(seq);
-
- LABEL *label = NEW_LABEL(location.line);
- if (!then_label) then_label = label;
- else if (!else_label) else_label = label;
-
- pm_compile_branch_condition(iseq, seq, cond, then_label, else_label, popped, scope_node);
-
- if (LIST_INSN_SIZE_ONE(seq)) {
- INSN *insn = (INSN *) ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
- if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label) return;
- }
-
- if (!label->refcnt) {
- if (popped) PUSH_INSN(ret, location, putnil);
- }
- else {
- PUSH_LABEL(seq, label);
- }
-
- PUSH_SEQ(ret, seq);
- return;
-}
-
-static void
-pm_compile_flip_flop_bound(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = { .line = ISEQ_BODY(iseq)->location.first_lineno, .node_id = -1 };
-
- if (PM_NODE_TYPE_P(node, PM_INTEGER_NODE)) {
- PM_COMPILE_NOT_POPPED(node);
-
- VALUE operand = ID2SYM(rb_intern("$."));
- PUSH_INSN1(ret, location, getglobal, operand);
-
- PUSH_SEND(ret, location, idEq, INT2FIX(1));
- if (popped) PUSH_INSN(ret, location, pop);
- }
- else {
- PM_COMPILE(node);
- }
-}
-
-static void
-pm_compile_flip_flop(const pm_flip_flop_node_t *flip_flop_node, LABEL *else_label, LABEL *then_label, rb_iseq_t *iseq, const int lineno, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = { .line = ISEQ_BODY(iseq)->location.first_lineno, .node_id = -1 };
- LABEL *lend = NEW_LABEL(location.line);
-
- int again = !(flip_flop_node->base.flags & PM_RANGE_FLAGS_EXCLUDE_END);
-
- rb_num_t count = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq) + VM_SVAR_FLIPFLOP_START;
- VALUE key = INT2FIX(count);
-
- PUSH_INSN2(ret, location, getspecial, key, INT2FIX(0));
- PUSH_INSNL(ret, location, branchif, lend);
-
- if (flip_flop_node->left) {
- pm_compile_flip_flop_bound(iseq, flip_flop_node->left, ret, popped, scope_node);
- }
- else {
- PUSH_INSN(ret, location, putnil);
- }
-
- PUSH_INSNL(ret, location, branchunless, else_label);
- PUSH_INSN1(ret, location, putobject, Qtrue);
- PUSH_INSN1(ret, location, setspecial, key);
- if (!again) {
- PUSH_INSNL(ret, location, jump, then_label);
- }
-
- PUSH_LABEL(ret, lend);
- if (flip_flop_node->right) {
- pm_compile_flip_flop_bound(iseq, flip_flop_node->right, ret, popped, scope_node);
- }
- else {
- PUSH_INSN(ret, location, putnil);
- }
-
- PUSH_INSNL(ret, location, branchunless, then_label);
- PUSH_INSN1(ret, location, putobject, Qfalse);
- PUSH_INSN1(ret, location, setspecial, key);
- PUSH_INSNL(ret, location, jump, then_label);
-}
-
-static void pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, bool in_condition);
-
-static void
-pm_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_node_t *cond, LABEL *then_label, LABEL *else_label, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, cond);
-
-again:
- switch (PM_NODE_TYPE(cond)) {
- case PM_AND_NODE: {
- const pm_and_node_t *cast = (const pm_and_node_t *) cond;
- pm_compile_logical(iseq, ret, cast->left, NULL, else_label, popped, scope_node);
-
- cond = cast->right;
- goto again;
- }
- case PM_OR_NODE: {
- const pm_or_node_t *cast = (const pm_or_node_t *) cond;
- pm_compile_logical(iseq, ret, cast->left, then_label, NULL, popped, scope_node);
-
- cond = cast->right;
- goto again;
- }
- case PM_FALSE_NODE:
- case PM_NIL_NODE:
- PUSH_INSNL(ret, location, jump, else_label);
- return;
- case PM_FLOAT_NODE:
- case PM_IMAGINARY_NODE:
- case PM_INTEGER_NODE:
- case PM_LAMBDA_NODE:
- case PM_RATIONAL_NODE:
- case PM_REGULAR_EXPRESSION_NODE:
- case PM_STRING_NODE:
- case PM_SYMBOL_NODE:
- case PM_TRUE_NODE:
- PUSH_INSNL(ret, location, jump, then_label);
- return;
- case PM_FLIP_FLOP_NODE:
- pm_compile_flip_flop((const pm_flip_flop_node_t *) cond, else_label, then_label, iseq, location.line, ret, popped, scope_node);
- return;
- case PM_DEFINED_NODE: {
- const pm_defined_node_t *cast = (const pm_defined_node_t *) cond;
- pm_compile_defined_expr(iseq, cast->value, &location, ret, popped, scope_node, true);
- break;
- }
- default: {
- DECL_ANCHOR(cond_seq);
- INIT_ANCHOR(cond_seq);
- pm_compile_node(iseq, cond, cond_seq, false, scope_node);
-
- if (LIST_INSN_SIZE_ONE(cond_seq)) {
- INSN *insn = (INSN *) ELEM_FIRST_INSN(FIRST_ELEMENT(cond_seq));
-
- if (insn->insn_id == BIN(putobject)) {
- if (RTEST(insn->operands[0])) {
- PUSH_INSNL(ret, location, jump, then_label);
- // maybe unreachable
- return;
- }
- else {
- PUSH_INSNL(ret, location, jump, else_label);
- return;
- }
- }
- }
-
- PUSH_SEQ(ret, cond_seq);
- break;
- }
- }
-
- PUSH_INSNL(ret, location, branchunless, else_label);
- PUSH_INSNL(ret, location, jump, then_label);
-}
-
-/**
- * Compile an if or unless node.
- */
-static void
-pm_compile_conditional(rb_iseq_t *iseq, const pm_node_location_t *node_location, pm_node_type_t type, const pm_node_t *node, const pm_statements_node_t *statements, const pm_node_t *subsequent, const pm_node_t *predicate, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = *node_location;
- LABEL *then_label = NEW_LABEL(location.line);
- LABEL *else_label = NEW_LABEL(location.line);
- LABEL *end_label = NULL;
-
- DECL_ANCHOR(cond_seq);
- INIT_ANCHOR(cond_seq);
- pm_compile_branch_condition(iseq, cond_seq, predicate, then_label, else_label, false, scope_node);
- PUSH_SEQ(ret, cond_seq);
-
- rb_code_location_t conditional_location = { 0 };
- VALUE branches = Qfalse;
-
- if (then_label->refcnt && else_label->refcnt && PM_BRANCH_COVERAGE_P(iseq)) {
- conditional_location = pm_code_location(scope_node, node);
- branches = decl_branch_base(iseq, PTR2NUM(node), &conditional_location, type == PM_IF_NODE ? "if" : "unless");
- }
-
- if (then_label->refcnt) {
- PUSH_LABEL(ret, then_label);
-
- DECL_ANCHOR(then_seq);
- INIT_ANCHOR(then_seq);
-
- if (statements != NULL) {
- pm_compile_node(iseq, (const pm_node_t *) statements, then_seq, popped, scope_node);
- }
- else if (!popped) {
- PUSH_SYNTHETIC_PUTNIL(then_seq, iseq);
- }
-
- if (else_label->refcnt) {
- // Establish branch coverage for the then block.
- if (PM_BRANCH_COVERAGE_P(iseq)) {
- rb_code_location_t branch_location;
-
- if (statements != NULL) {
- branch_location = pm_code_location(scope_node, (const pm_node_t *) statements);
- } else if (type == PM_IF_NODE) {
- pm_line_column_t predicate_end = PM_NODE_END_LINE_COLUMN(scope_node->parser, predicate);
- branch_location = (rb_code_location_t) {
- .beg_pos = { .lineno = predicate_end.line, .column = predicate_end.column },
- .end_pos = { .lineno = predicate_end.line, .column = predicate_end.column }
- };
- } else {
- branch_location = conditional_location;
- }
-
- add_trace_branch_coverage(iseq, ret, &branch_location, branch_location.beg_pos.column, 0, type == PM_IF_NODE ? "then" : "else", branches);
- }
-
- end_label = NEW_LABEL(location.line);
- PUSH_INSNL(then_seq, location, jump, end_label);
- if (!popped) PUSH_INSN(then_seq, location, pop);
- }
-
- PUSH_SEQ(ret, then_seq);
- }
-
- if (else_label->refcnt) {
- PUSH_LABEL(ret, else_label);
-
- DECL_ANCHOR(else_seq);
- INIT_ANCHOR(else_seq);
-
- if (subsequent != NULL) {
- pm_compile_node(iseq, subsequent, else_seq, popped, scope_node);
- }
- else if (!popped) {
- PUSH_SYNTHETIC_PUTNIL(else_seq, iseq);
- }
-
- // Establish branch coverage for the else block.
- if (then_label->refcnt && PM_BRANCH_COVERAGE_P(iseq)) {
- rb_code_location_t branch_location;
-
- if (subsequent == NULL) {
- branch_location = conditional_location;
- } else if (PM_NODE_TYPE_P(subsequent, PM_ELSE_NODE)) {
- const pm_else_node_t *else_node = (const pm_else_node_t *) subsequent;
- branch_location = pm_code_location(scope_node, else_node->statements != NULL ? ((const pm_node_t *) else_node->statements) : (const pm_node_t *) else_node);
- } else {
- branch_location = pm_code_location(scope_node, (const pm_node_t *) subsequent);
- }
-
- add_trace_branch_coverage(iseq, ret, &branch_location, branch_location.beg_pos.column, 1, type == PM_IF_NODE ? "else" : "then", branches);
- }
-
- PUSH_SEQ(ret, else_seq);
- }
-
- if (end_label) {
- PUSH_LABEL(ret, end_label);
- }
-
- return;
-}
-
-/**
- * Compile a while or until loop.
- */
-static void
-pm_compile_loop(rb_iseq_t *iseq, const pm_node_location_t *node_location, pm_node_flags_t flags, enum pm_node_type type, const pm_node_t *node, const pm_statements_node_t *statements, const pm_node_t *predicate, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = *node_location;
-
- LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
- LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
- LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
-
- LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(location.line); /* next */
- LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(location.line); /* redo */
- LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(location.line); /* break */
- LABEL *end_label = NEW_LABEL(location.line);
- LABEL *adjust_label = NEW_LABEL(location.line);
-
- LABEL *next_catch_label = NEW_LABEL(location.line);
- LABEL *tmp_label = NULL;
-
- // We're pushing onto the ensure stack because breaks need to break out of
- // this loop and not break into the ensure statements within the same
- // lexical scope.
- struct iseq_compile_data_ensure_node_stack enl;
- push_ensure_entry(iseq, &enl, NULL, NULL);
-
- // begin; end while true
- if (flags & PM_LOOP_FLAGS_BEGIN_MODIFIER) {
- tmp_label = NEW_LABEL(location.line);
- PUSH_INSNL(ret, location, jump, tmp_label);
- }
- else {
- // while true; end
- PUSH_INSNL(ret, location, jump, next_label);
- }
-
- PUSH_LABEL(ret, adjust_label);
- PUSH_INSN(ret, location, putnil);
- PUSH_LABEL(ret, next_catch_label);
- PUSH_INSN(ret, location, pop);
- PUSH_INSNL(ret, location, jump, next_label);
- if (tmp_label) PUSH_LABEL(ret, tmp_label);
-
- PUSH_LABEL(ret, redo_label);
-
- // Establish branch coverage for the loop.
- if (PM_BRANCH_COVERAGE_P(iseq)) {
- rb_code_location_t loop_location = pm_code_location(scope_node, node);
- VALUE branches = decl_branch_base(iseq, PTR2NUM(node), &loop_location, type == PM_WHILE_NODE ? "while" : "until");
-
- rb_code_location_t branch_location = statements != NULL ? pm_code_location(scope_node, (const pm_node_t *) statements) : loop_location;
- add_trace_branch_coverage(iseq, ret, &branch_location, branch_location.beg_pos.column, 0, "body", branches);
- }
-
- if (statements != NULL) PM_COMPILE_POPPED((const pm_node_t *) statements);
- PUSH_LABEL(ret, next_label);
-
- if (type == PM_WHILE_NODE) {
- pm_compile_branch_condition(iseq, ret, predicate, redo_label, end_label, popped, scope_node);
- }
- else if (type == PM_UNTIL_NODE) {
- pm_compile_branch_condition(iseq, ret, predicate, end_label, redo_label, popped, scope_node);
- }
-
- PUSH_LABEL(ret, end_label);
- PUSH_ADJUST_RESTORE(ret, adjust_label);
- PUSH_INSN(ret, location, putnil);
-
- PUSH_LABEL(ret, break_label);
- if (popped) PUSH_INSN(ret, location, pop);
-
- PUSH_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL, break_label);
- PUSH_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL, next_catch_label);
- PUSH_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL, ISEQ_COMPILE_DATA(iseq)->redo_label);
-
- ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
- ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
- ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
- ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->prev;
-
- return;
-}
-
-// This recurses through scopes and finds the local index at any scope level
-// It also takes a pointer to depth, and increments depth appropriately
-// according to the depth of the local.
-static pm_local_index_t
-pm_lookup_local_index(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, pm_constant_id_t constant_id, int start_depth)
-{
- pm_local_index_t lindex = { 0 };
- st_data_t local_index;
-
- int level;
- for (level = 0; level < start_depth; level++) {
- scope_node = scope_node->previous;
- }
-
- while (!st_lookup(scope_node->index_lookup_table, constant_id, &local_index)) {
- level++;
-
- if (scope_node->previous) {
- scope_node = scope_node->previous;
- }
- else {
- // We have recursed up all scope nodes
- // and have not found the local yet
- rb_bug("Local with constant_id %u does not exist", (unsigned int) constant_id);
- }
- }
-
- lindex.level = level;
- lindex.index = scope_node->local_table_for_iseq_size - (int) local_index;
- return lindex;
-}
-
-// This returns the CRuby ID which maps to the pm_constant_id_t
-//
-// Constant_ids in prism are indexes of the constants in prism's constant pool.
-// We add a constants mapping on the scope_node which is a mapping from
-// these constant_id indexes to the CRuby IDs that they represent.
-// This helper method allows easy access to those IDs
-static ID
-pm_constant_id_lookup(const pm_scope_node_t *scope_node, pm_constant_id_t constant_id)
-{
- if (constant_id < 1 || constant_id > scope_node->parser->constant_pool.size) {
- rb_bug("constant_id out of range: %u", (unsigned int)constant_id);
- }
- return scope_node->constants[constant_id - 1];
-}
-
-static rb_iseq_t *
-pm_new_child_iseq(rb_iseq_t *iseq, pm_scope_node_t *node, VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
-{
- debugs("[new_child_iseq]> ---------------------------------------\n");
- int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
- rb_iseq_t *ret_iseq = pm_iseq_new_with_opt(node, name,
- rb_iseq_path(iseq), rb_iseq_realpath(iseq),
- line_no, parent,
- isolated_depth ? isolated_depth + 1 : 0,
- type, ISEQ_COMPILE_DATA(iseq)->option);
- debugs("[new_child_iseq]< ---------------------------------------\n");
- return ret_iseq;
-}
-
-static int
-pm_compile_class_path(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- if (PM_NODE_TYPE_P(node, PM_CONSTANT_PATH_NODE)) {
- const pm_node_t *parent = ((const pm_constant_path_node_t *) node)->parent;
-
- if (parent) {
- /* Bar::Foo */
- PM_COMPILE(parent);
- return VM_DEFINECLASS_FLAG_SCOPED;
- }
- else {
- /* toplevel class ::Foo */
- PUSH_INSN1(ret, *node_location, putobject, rb_cObject);
- return VM_DEFINECLASS_FLAG_SCOPED;
- }
- }
- else {
- /* class at cbase Foo */
- PUSH_INSN1(ret, *node_location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- return 0;
- }
-}
-
-/**
- * Compile either a call and write node or a call or write node. These look like
- * method calls that are followed by a ||= or &&= operator.
- */
-static void
-pm_compile_call_and_or_write_node(rb_iseq_t *iseq, bool and_node, const pm_node_t *receiver, const pm_node_t *value, pm_constant_id_t write_name, pm_constant_id_t read_name, bool safe_nav, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = *node_location;
- LABEL *lfin = NEW_LABEL(location.line);
- LABEL *lcfin = NEW_LABEL(location.line);
- LABEL *lskip = NULL;
-
- int flag = PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? VM_CALL_FCALL : 0;
- ID id_read_name = pm_constant_id_lookup(scope_node, read_name);
-
- PM_COMPILE_NOT_POPPED(receiver);
- if (safe_nav) {
- lskip = NEW_LABEL(location.line);
- PUSH_INSN(ret, location, dup);
- PUSH_INSNL(ret, location, branchnil, lskip);
- }
-
- PUSH_INSN(ret, location, dup);
- PUSH_SEND_WITH_FLAG(ret, location, id_read_name, INT2FIX(0), INT2FIX(flag));
- if (!popped) PUSH_INSN(ret, location, dup);
-
- if (and_node) {
- PUSH_INSNL(ret, location, branchunless, lcfin);
- }
- else {
- PUSH_INSNL(ret, location, branchif, lcfin);
- }
-
- if (!popped) PUSH_INSN(ret, location, pop);
- PM_COMPILE_NOT_POPPED(value);
-
- if (!popped) {
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- }
-
- ID id_write_name = pm_constant_id_lookup(scope_node, write_name);
- PUSH_SEND_WITH_FLAG(ret, location, id_write_name, INT2FIX(1), INT2FIX(flag));
- PUSH_INSNL(ret, location, jump, lfin);
-
- PUSH_LABEL(ret, lcfin);
- if (!popped) PUSH_INSN(ret, location, swap);
-
- PUSH_LABEL(ret, lfin);
-
- if (lskip && popped) PUSH_LABEL(ret, lskip);
- PUSH_INSN(ret, location, pop);
- if (lskip && !popped) PUSH_LABEL(ret, lskip);
-}
-
-/**
- * This function compiles a hash onto the stack. It is used to compile hash
- * literals and keyword arguments. It is assumed that if we get here that the
- * contents of the hash are not popped.
- */
-static void
-pm_compile_hash_elements(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list_t *elements, bool argument, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
-
- // If this element is not popped, then we need to create the hash on the
- // stack. Neighboring plain assoc nodes should be grouped together (either
- // by newhash or hash merge). Double splat nodes should be merged using the
- // merge_kwd method call.
- const int max_stack_length = 0x100;
- const unsigned int min_tmp_hash_length = 0x800;
-
- int stack_length = 0;
- bool first_chunk = true;
-
- // This is an optimization wherein we keep track of whether or not the
- // previous element was a static literal. If it was, then we do not attempt
- // to check if we have a subhash that can be optimized. If it was not, then
- // we do check.
- bool static_literal = false;
-
- DECL_ANCHOR(anchor);
- INIT_ANCHOR(anchor);
-
- // Convert pushed elements to a hash, and merge if needed.
-#define FLUSH_CHUNK \
- if (stack_length) { \
- if (first_chunk) { \
- PUSH_SEQ(ret, anchor); \
- PUSH_INSN1(ret, location, newhash, INT2FIX(stack_length)); \
- first_chunk = false; \
- } \
- else { \
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); \
- PUSH_INSN(ret, location, swap); \
- PUSH_SEQ(ret, anchor); \
- PUSH_SEND(ret, location, id_core_hash_merge_ptr, INT2FIX(stack_length + 1)); \
- } \
- INIT_ANCHOR(anchor); \
- stack_length = 0; \
- }
-
- for (size_t index = 0; index < elements->size; index++) {
- const pm_node_t *element = elements->nodes[index];
-
-
- switch (PM_NODE_TYPE(element)) {
- case PM_ASSOC_NODE: {
- // Pre-allocation check (this branch can be omitted).
- if (
- PM_NODE_FLAG_P(element, PM_NODE_FLAG_STATIC_LITERAL) && (
- (!static_literal && ((index + min_tmp_hash_length) < elements->size)) ||
- (first_chunk && stack_length == 0)
- )
- ) {
- // Count the elements that are statically-known.
- size_t count = 1;
- while (index + count < elements->size && PM_NODE_FLAG_P(elements->nodes[index + count], PM_NODE_FLAG_STATIC_LITERAL)) count++;
-
- if ((first_chunk && stack_length == 0) || count >= min_tmp_hash_length) {
- // The subsequence of elements in this hash is long enough
- // to merit its own hash.
- VALUE ary = rb_ary_hidden_new(count);
-
- // Create a hidden hash.
- for (size_t tmp_end = index + count; index < tmp_end; index++) {
- const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) elements->nodes[index];
-
- VALUE elem[2] = {
- pm_static_literal_value(iseq, assoc->key, scope_node),
- pm_static_literal_value(iseq, assoc->value, scope_node)
- };
-
- rb_ary_cat(ary, elem, 2);
- }
- index --;
-
- VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2);
- rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash);
- hash = rb_obj_hide(hash);
- OBJ_FREEZE(hash);
-
- // Emit optimized code.
- FLUSH_CHUNK;
- if (first_chunk) {
- PUSH_INSN1(ret, location, duphash, hash);
- first_chunk = false;
- }
- else {
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, putobject, hash);
- PUSH_SEND(ret, location, id_core_hash_merge_kwd, INT2FIX(2));
- }
-
- break;
- }
- else {
- static_literal = true;
- }
- }
- else {
- static_literal = false;
- }
-
- // If this is a plain assoc node, then we can compile it directly
- // and then add the total number of values on the stack.
- pm_compile_node(iseq, element, anchor, false, scope_node);
- if ((stack_length += 2) >= max_stack_length) FLUSH_CHUNK;
- break;
- }
- case PM_ASSOC_SPLAT_NODE: {
- FLUSH_CHUNK;
-
- const pm_assoc_splat_node_t *assoc_splat = (const pm_assoc_splat_node_t *) element;
- bool empty_hash = assoc_splat->value != NULL && (
- (PM_NODE_TYPE_P(assoc_splat->value, PM_HASH_NODE) && ((const pm_hash_node_t *) assoc_splat->value)->elements.size == 0) ||
- PM_NODE_TYPE_P(assoc_splat->value, PM_NIL_NODE)
- );
-
- bool first_element = first_chunk && stack_length == 0;
- bool last_element = index == elements->size - 1;
- bool only_element = first_element && last_element;
-
- if (empty_hash) {
- if (only_element && argument) {
- // **{} appears at the only keyword argument in method call,
- // so it won't be modified.
- //
- // This is only done for method calls and not for literal
- // hashes, because literal hashes should always result in a
- // new hash.
- PUSH_INSN(ret, location, putnil);
- }
- else if (first_element) {
- // **{} appears as the first keyword argument, so it may be
- // modified. We need to create a fresh hash object.
- PUSH_INSN1(ret, location, newhash, INT2FIX(0));
- }
- // Any empty keyword splats that are not the first can be
- // ignored since merging an empty hash into the existing hash is
- // the same as not merging it.
- }
- else {
- if (only_element && argument) {
- // ** is only keyword argument in the method call. Use it
- // directly. This will be not be flagged as mutable. This is
- // only done for method calls and not for literal hashes,
- // because literal hashes should always result in a new
- // hash.
- PM_COMPILE_NOT_POPPED(element);
- }
- else {
- // There is more than one keyword argument, or this is not a
- // method call. In that case, we need to add an empty hash
- // (if first keyword), or merge the hash to the accumulated
- // hash (if not the first keyword).
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
-
- if (first_element) {
- PUSH_INSN1(ret, location, newhash, INT2FIX(0));
- }
- else {
- PUSH_INSN(ret, location, swap);
- }
-
- PM_COMPILE_NOT_POPPED(element);
- PUSH_SEND(ret, location, id_core_hash_merge_kwd, INT2FIX(2));
- }
- }
-
- first_chunk = false;
- static_literal = false;
- break;
- }
- default:
- RUBY_ASSERT("Invalid node type for hash" && false);
- break;
- }
- }
-
- FLUSH_CHUNK;
-#undef FLUSH_CHUNK
-}
-
-#define SPLATARRAY_FALSE 0
-#define SPLATARRAY_TRUE 1
-#define DUP_SINGLE_KW_SPLAT 2
-
-// This is details. Users should call pm_setup_args() instead.
-static int
-pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *block, int *flags, const bool has_regular_blockarg, struct rb_callinfo_kwarg **kw_arg, int *dup_rest, rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, const pm_node_location_t *node_location)
-{
- const pm_node_location_t location = *node_location;
-
- int orig_argc = 0;
- bool has_splat = false;
- bool has_keyword_splat = false;
-
- if (arguments_node == NULL) {
- if (*flags & VM_CALL_FCALL) {
- *flags |= VM_CALL_VCALL;
- }
- }
- else {
- const pm_node_list_t *arguments = &arguments_node->arguments;
- has_keyword_splat = PM_NODE_FLAG_P(arguments_node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT);
-
- // We count the number of elements post the splat node that are not keyword elements to
- // eventually pass as an argument to newarray
- int post_splat_counter = 0;
- const pm_node_t *argument;
-
- PM_NODE_LIST_FOREACH(arguments, index, argument) {
- switch (PM_NODE_TYPE(argument)) {
- // A keyword hash node contains all keyword arguments as AssocNodes and AssocSplatNodes
- case PM_KEYWORD_HASH_NODE: {
- const pm_keyword_hash_node_t *keyword_arg = (const pm_keyword_hash_node_t *) argument;
- const pm_node_list_t *elements = &keyword_arg->elements;
-
- if (has_keyword_splat || has_splat) {
- *flags |= VM_CALL_KW_SPLAT;
- has_keyword_splat = true;
-
- if (elements->size > 1 || !(elements->size == 1 && PM_NODE_TYPE_P(elements->nodes[0], PM_ASSOC_SPLAT_NODE))) {
- // A new hash will be created for the keyword arguments
- // in this case, so mark the method as passing mutable
- // keyword splat.
- *flags |= VM_CALL_KW_SPLAT_MUT;
- pm_compile_hash_elements(iseq, argument, elements, true, ret, scope_node);
- }
- else if (*dup_rest & DUP_SINGLE_KW_SPLAT) {
- *flags |= VM_CALL_KW_SPLAT_MUT;
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_INSN1(ret, location, newhash, INT2FIX(0));
- pm_compile_hash_elements(iseq, argument, elements, true, ret, scope_node);
- PUSH_SEND(ret, location, id_core_hash_merge_kwd, INT2FIX(2));
- }
- else {
- pm_compile_hash_elements(iseq, argument, elements, true, ret, scope_node);
- }
- }
- else {
- // We need to first figure out if all elements of the
- // KeywordHashNode are AssocNodes with symbol keys.
- if (PM_NODE_FLAG_P(keyword_arg, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS)) {
- // If they are all symbol keys then we can pass them as
- // keyword arguments. The first thing we need to do is
- // deduplicate. We'll do this using the combination of a
- // Ruby hash and a Ruby array.
- VALUE stored_indices = rb_hash_new();
- VALUE keyword_indices = rb_ary_new_capa(elements->size);
-
- size_t size = 0;
- for (size_t element_index = 0; element_index < elements->size; element_index++) {
- const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) elements->nodes[element_index];
-
- // Retrieve the stored index from the hash for this
- // keyword.
- VALUE keyword = pm_static_literal_value(iseq, assoc->key, scope_node);
- VALUE stored_index = rb_hash_aref(stored_indices, keyword);
-
- // If this keyword was already seen in the hash,
- // then mark the array at that index as false and
- // decrement the keyword size.
- if (!NIL_P(stored_index)) {
- rb_ary_store(keyword_indices, NUM2LONG(stored_index), Qfalse);
- size--;
- }
-
- // Store (and possibly overwrite) the index for this
- // keyword in the hash, mark the array at that index
- // as true, and increment the keyword size.
- rb_hash_aset(stored_indices, keyword, ULONG2NUM(element_index));
- rb_ary_store(keyword_indices, (long) element_index, Qtrue);
- size++;
- }
-
- *kw_arg = rb_xmalloc_mul_add(size, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
- *flags |= VM_CALL_KWARG;
-
- VALUE *keywords = (*kw_arg)->keywords;
- (*kw_arg)->references = 0;
- (*kw_arg)->keyword_len = (int) size;
-
- size_t keyword_index = 0;
- for (size_t element_index = 0; element_index < elements->size; element_index++) {
- const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) elements->nodes[element_index];
- bool popped = true;
-
- if (rb_ary_entry(keyword_indices, (long) element_index) == Qtrue) {
- keywords[keyword_index++] = pm_static_literal_value(iseq, assoc->key, scope_node);
- popped = false;
- }
-
- PM_COMPILE(assoc->value);
- }
-
- RUBY_ASSERT(keyword_index == size);
- }
- else {
- // If they aren't all symbol keys then we need to
- // construct a new hash and pass that as an argument.
- orig_argc++;
- *flags |= VM_CALL_KW_SPLAT;
-
- size_t size = elements->size;
- if (size > 1) {
- // A new hash will be created for the keyword
- // arguments in this case, so mark the method as
- // passing mutable keyword splat.
- *flags |= VM_CALL_KW_SPLAT_MUT;
- }
-
- for (size_t element_index = 0; element_index < size; element_index++) {
- const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) elements->nodes[element_index];
- PM_COMPILE_NOT_POPPED(assoc->key);
- PM_COMPILE_NOT_POPPED(assoc->value);
- }
-
- PUSH_INSN1(ret, location, newhash, INT2FIX(size * 2));
- }
- }
- break;
- }
- case PM_SPLAT_NODE: {
- *flags |= VM_CALL_ARGS_SPLAT;
- const pm_splat_node_t *splat_node = (const pm_splat_node_t *) argument;
-
- if (splat_node->expression) {
- PM_COMPILE_NOT_POPPED(splat_node->expression);
- }
- else {
- pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_MULT, 0);
- PUSH_GETLOCAL(ret, location, index.index, index.level);
- }
-
- bool first_splat = !has_splat;
-
- if (first_splat) {
- // If this is the first splat array seen and it's not the
- // last parameter, we want splatarray to dup it.
- //
- // foo(a, *b, c)
- // ^^
- if (index + 1 < arguments->size || has_regular_blockarg) {
- PUSH_INSN1(ret, location, splatarray, (*dup_rest & SPLATARRAY_TRUE) ? Qtrue : Qfalse);
- if (*dup_rest & SPLATARRAY_TRUE) *dup_rest &= ~SPLATARRAY_TRUE;
- }
- // If this is the first spalt array seen and it's the last
- // parameter, we don't want splatarray to dup it.
- //
- // foo(a, *b)
- // ^^
- else {
- PUSH_INSN1(ret, location, splatarray, Qfalse);
- }
- }
- else {
- // If this is not the first splat array seen and it is also
- // the last parameter, we don't want splatarray to dup it
- // and we need to concat the array.
- //
- // foo(a, *b, *c)
- // ^^
- PUSH_INSN(ret, location, concattoarray);
- }
-
- has_splat = true;
- post_splat_counter = 0;
-
- break;
- }
- case PM_FORWARDING_ARGUMENTS_NODE: { // not counted in argc return value
- if (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
- *flags |= VM_CALL_FORWARDING;
-
- pm_local_index_t mult_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_DOT3, 0);
- PUSH_GETLOCAL(ret, location, mult_local.index, mult_local.level);
-
- break;
- }
-
- orig_argc += 2;
-
- *flags |= VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_SPLAT_MUT | VM_CALL_ARGS_BLOCKARG | VM_CALL_KW_SPLAT;
-
- // Forwarding arguments nodes are treated as foo(*, **, &)
- // So foo(...) equals foo(*, **, &) and as such the local
- // table for this method is known in advance
- //
- // Push the *
- pm_local_index_t mult_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_MULT, 0);
- PUSH_GETLOCAL(ret, location, mult_local.index, mult_local.level);
- PUSH_INSN1(ret, location, splatarray, Qtrue);
-
- // Push the **
- pm_local_index_t pow_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_POW, 0);
- PUSH_GETLOCAL(ret, location, pow_local.index, pow_local.level);
-
- // Push the &
- pm_local_index_t and_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_AND, 0);
- PUSH_INSN2(ret, location, getblockparamproxy, INT2FIX(and_local.index + VM_ENV_DATA_SIZE - 1), INT2FIX(and_local.level));
- PUSH_INSN(ret, location, splatkw);
-
- break;
- }
- default: {
- post_splat_counter++;
- PM_COMPILE_NOT_POPPED(argument);
-
- // If we have a splat and we've seen a splat, we need to process
- // everything after the splat.
- if (has_splat) {
- // Stack items are turned into an array and concatenated in
- // the following cases:
- //
- // If the next node is a splat:
- //
- // foo(*a, b, *c)
- //
- // If the next node is a kwarg or kwarg splat:
- //
- // foo(*a, b, c: :d)
- // foo(*a, b, **c)
- //
- // If the next node is NULL (we have hit the end):
- //
- // foo(*a, b)
- if (index == arguments->size - 1) {
- RUBY_ASSERT(post_splat_counter > 0);
- PUSH_INSN1(ret, location, pushtoarray, INT2FIX(post_splat_counter));
- }
- else {
- pm_node_t *next_arg = arguments->nodes[index + 1];
-
- switch (PM_NODE_TYPE(next_arg)) {
- // A keyword hash node contains all keyword arguments as AssocNodes and AssocSplatNodes
- case PM_KEYWORD_HASH_NODE: {
- PUSH_INSN1(ret, location, newarray, INT2FIX(post_splat_counter));
- PUSH_INSN(ret, location, concatarray);
- break;
- }
- case PM_SPLAT_NODE: {
- PUSH_INSN1(ret, location, newarray, INT2FIX(post_splat_counter));
- PUSH_INSN(ret, location, concatarray);
- break;
- }
- default:
- break;
- }
- }
- }
- else {
- orig_argc++;
- }
- }
- }
- }
- }
-
- if (has_splat) orig_argc++;
- if (has_keyword_splat) orig_argc++;
- return orig_argc;
-}
-
-/**
- * True if the given kind of node could potentially mutate the array that is
- * being splatted in a set of call arguments.
- */
-static inline bool
-pm_setup_args_dup_rest_p(const pm_node_t *node)
-{
- switch (PM_NODE_TYPE(node)) {
- case PM_BACK_REFERENCE_READ_NODE:
- case PM_CLASS_VARIABLE_READ_NODE:
- case PM_CONSTANT_PATH_NODE:
- case PM_CONSTANT_READ_NODE:
- case PM_FALSE_NODE:
- case PM_FLOAT_NODE:
- case PM_GLOBAL_VARIABLE_READ_NODE:
- case PM_IMAGINARY_NODE:
- case PM_INSTANCE_VARIABLE_READ_NODE:
- case PM_INTEGER_NODE:
- case PM_LAMBDA_NODE:
- case PM_LOCAL_VARIABLE_READ_NODE:
- case PM_NIL_NODE:
- case PM_NUMBERED_REFERENCE_READ_NODE:
- case PM_RATIONAL_NODE:
- case PM_REGULAR_EXPRESSION_NODE:
- case PM_SELF_NODE:
- case PM_STRING_NODE:
- case PM_SYMBOL_NODE:
- case PM_TRUE_NODE:
- return false;
- case PM_IMPLICIT_NODE:
- return pm_setup_args_dup_rest_p(((const pm_implicit_node_t *) node)->value);
- default:
- return true;
- }
-}
-
-/**
- * Compile the argument parts of a call.
- */
-static int
-pm_setup_args(const pm_arguments_node_t *arguments_node, const pm_node_t *block, int *flags, struct rb_callinfo_kwarg **kw_arg, rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, const pm_node_location_t *node_location)
-{
- int dup_rest = SPLATARRAY_TRUE;
-
- const pm_node_list_t *arguments;
- size_t arguments_size;
-
- // Calls like foo(1, *f, **hash) that use splat and kwsplat could be
- // eligible for eliding duping the rest array (dup_reset=false).
- if (
- arguments_node != NULL &&
- (arguments = &arguments_node->arguments, arguments_size = arguments->size) >= 2 &&
- PM_NODE_FLAG_P(arguments_node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT) &&
- !PM_NODE_FLAG_P(arguments_node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS) &&
- PM_NODE_TYPE_P(arguments->nodes[arguments_size - 1], PM_KEYWORD_HASH_NODE)
- ) {
- // Start by assuming that dup_rest=false, then check each element of the
- // hash to ensure we don't need to flip it back to true (in case one of
- // the elements could potentially mutate the array).
- dup_rest = SPLATARRAY_FALSE;
-
- const pm_keyword_hash_node_t *keyword_hash = (const pm_keyword_hash_node_t *) arguments->nodes[arguments_size - 1];
- const pm_node_list_t *elements = &keyword_hash->elements;
-
- for (size_t index = 0; dup_rest == SPLATARRAY_FALSE && index < elements->size; index++) {
- const pm_node_t *element = elements->nodes[index];
-
- switch (PM_NODE_TYPE(element)) {
- case PM_ASSOC_NODE: {
- const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) element;
- if (pm_setup_args_dup_rest_p(assoc->key) || pm_setup_args_dup_rest_p(assoc->value)) dup_rest = SPLATARRAY_TRUE;
- break;
- }
- case PM_ASSOC_SPLAT_NODE: {
- const pm_assoc_splat_node_t *assoc = (const pm_assoc_splat_node_t *) element;
- if (assoc->value != NULL && pm_setup_args_dup_rest_p(assoc->value)) dup_rest = SPLATARRAY_TRUE;
- break;
- }
- default:
- break;
- }
- }
- }
-
- int initial_dup_rest = dup_rest;
- int argc;
-
- if (block && PM_NODE_TYPE_P(block, PM_BLOCK_ARGUMENT_NODE)) {
- // We compile the `&block_arg` expression first and stitch it later
- // since the nature of the expression influences whether splat should
- // duplicate the array.
- bool regular_block_arg = true;
- const pm_node_t *block_expr = ((const pm_block_argument_node_t *)block)->expression;
-
- if (block_expr && pm_setup_args_dup_rest_p(block_expr)) {
- dup_rest = SPLATARRAY_TRUE | DUP_SINGLE_KW_SPLAT;
- initial_dup_rest = dup_rest;
- }
-
- DECL_ANCHOR(block_arg);
- INIT_ANCHOR(block_arg);
- pm_compile_node(iseq, block, block_arg, false, scope_node);
-
- *flags |= VM_CALL_ARGS_BLOCKARG;
-
- if (LIST_INSN_SIZE_ONE(block_arg)) {
- LINK_ELEMENT *elem = FIRST_ELEMENT(block_arg);
- if (IS_INSN(elem)) {
- INSN *iobj = (INSN *) elem;
- if (iobj->insn_id == BIN(getblockparam)) {
- iobj->insn_id = BIN(getblockparamproxy);
- }
-
- // Allow splat without duplication for simple one-instruction
- // block arguments like `&arg`. It is known that this
- // optimization can be too aggressive in some cases. See
- // [Bug #16504].
- regular_block_arg = false;
- }
- }
-
- argc = pm_setup_args_core(arguments_node, block, flags, regular_block_arg, kw_arg, &dup_rest, iseq, ret, scope_node, node_location);
- PUSH_SEQ(ret, block_arg);
- }
- else {
- argc = pm_setup_args_core(arguments_node, block, flags, false, kw_arg, &dup_rest, iseq, ret, scope_node, node_location);
- }
-
- // If the dup_rest flag was consumed while compiling the arguments (which
- // effectively means we found the splat node), then it would have changed
- // during the call to pm_setup_args_core. In this case, we want to add the
- // VM_CALL_ARGS_SPLAT_MUT flag.
- if (*flags & VM_CALL_ARGS_SPLAT && dup_rest != initial_dup_rest) {
- *flags |= VM_CALL_ARGS_SPLAT_MUT;
- }
-
- return argc;
-}
-
-/**
- * Compile an index operator write node, which is a node that is writing a value
- * using the [] and []= methods. It looks like:
- *
- * foo[bar] += baz
- *
- * This breaks down to caching the receiver and arguments on the stack, calling
- * the [] method, calling the operator method with the result of the [] method,
- * and then calling the []= method with the result of the operator method.
- */
-static void
-pm_compile_index_operator_write_node(rb_iseq_t *iseq, const pm_index_operator_write_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = *node_location;
- if (!popped) PUSH_INSN(ret, location, putnil);
-
- PM_COMPILE_NOT_POPPED(node->receiver);
-
- int boff = (node->block == NULL ? 0 : 1);
- int flag = PM_NODE_TYPE_P(node->receiver, PM_SELF_NODE) ? VM_CALL_FCALL : 0;
- struct rb_callinfo_kwarg *keywords = NULL;
- int argc = pm_setup_args(node->arguments, (const pm_node_t *) node->block, &flag, &keywords, iseq, ret, scope_node, node_location);
-
- if ((argc > 0 || boff) && (flag & VM_CALL_KW_SPLAT)) {
- if (boff) {
- PUSH_INSN(ret, location, splatkw);
- }
- else {
- PUSH_INSN(ret, location, dup);
- PUSH_INSN(ret, location, splatkw);
- PUSH_INSN(ret, location, pop);
- }
- }
-
- int dup_argn = argc + 1 + boff;
- int keyword_len = 0;
-
- if (keywords) {
- keyword_len = keywords->keyword_len;
- dup_argn += keyword_len;
- }
-
- PUSH_INSN1(ret, location, dupn, INT2FIX(dup_argn));
- PUSH_SEND_R(ret, location, idAREF, INT2FIX(argc), NULL, INT2FIX(flag & ~(VM_CALL_ARGS_SPLAT_MUT | VM_CALL_KW_SPLAT_MUT)), keywords);
- PM_COMPILE_NOT_POPPED(node->value);
-
- ID id_operator = pm_constant_id_lookup(scope_node, node->binary_operator);
- PUSH_SEND(ret, location, id_operator, INT2FIX(1));
-
- if (!popped) {
- PUSH_INSN1(ret, location, setn, INT2FIX(dup_argn + 1));
- }
- if (flag & VM_CALL_ARGS_SPLAT) {
- if (flag & VM_CALL_KW_SPLAT) {
- PUSH_INSN1(ret, location, topn, INT2FIX(2 + boff));
-
- if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
- PUSH_INSN1(ret, location, splatarray, Qtrue);
- flag |= VM_CALL_ARGS_SPLAT_MUT;
- }
-
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, pushtoarray, INT2FIX(1));
- PUSH_INSN1(ret, location, setn, INT2FIX(2 + boff));
- PUSH_INSN(ret, location, pop);
- }
- else {
- if (boff > 0) {
- PUSH_INSN1(ret, location, dupn, INT2FIX(3));
- PUSH_INSN(ret, location, swap);
- PUSH_INSN(ret, location, pop);
- }
- if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, splatarray, Qtrue);
- PUSH_INSN(ret, location, swap);
- flag |= VM_CALL_ARGS_SPLAT_MUT;
- }
- PUSH_INSN1(ret, location, pushtoarray, INT2FIX(1));
- if (boff > 0) {
- PUSH_INSN1(ret, location, setn, INT2FIX(3));
- PUSH_INSN(ret, location, pop);
- PUSH_INSN(ret, location, pop);
- }
- }
-
- PUSH_SEND_R(ret, location, idASET, INT2FIX(argc), NULL, INT2FIX(flag), keywords);
- }
- else if (flag & VM_CALL_KW_SPLAT) {
- if (boff > 0) {
- PUSH_INSN1(ret, location, topn, INT2FIX(2));
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, setn, INT2FIX(3));
- PUSH_INSN(ret, location, pop);
- }
- PUSH_INSN(ret, location, swap);
- PUSH_SEND_R(ret, location, idASET, INT2FIX(argc + 1), NULL, INT2FIX(flag), keywords);
- }
- else if (keyword_len) {
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, opt_reverse, INT2FIX(keyword_len + boff + 2));
- PUSH_INSN1(ret, location, opt_reverse, INT2FIX(keyword_len + boff + 1));
- PUSH_INSN(ret, location, pop);
- PUSH_SEND_R(ret, location, idASET, INT2FIX(argc + 1), NULL, INT2FIX(flag), keywords);
- }
- else {
- if (boff > 0) {
- PUSH_INSN(ret, location, swap);
- }
- PUSH_SEND_R(ret, location, idASET, INT2FIX(argc + 1), NULL, INT2FIX(flag), keywords);
- }
-
- PUSH_INSN(ret, location, pop);
-}
-
-/**
- * Compile an index control flow write node, which is a node that is writing a
- * value using the [] and []= methods and the &&= and ||= operators. It looks
- * like:
- *
- * foo[bar] ||= baz
- *
- * This breaks down to caching the receiver and arguments on the stack, calling
- * the [] method, checking the result and then changing control flow based on
- * it. If the value would result in a write, then the value is written using the
- * []= method.
- */
-static void
-pm_compile_index_control_flow_write_node(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_t *receiver, const pm_arguments_node_t *arguments, const pm_block_argument_node_t *block, const pm_node_t *value, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = *node_location;
- if (!popped) PUSH_INSN(ret, location, putnil);
- PM_COMPILE_NOT_POPPED(receiver);
-
- int boff = (block == NULL ? 0 : 1);
- int flag = PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? VM_CALL_FCALL : 0;
- struct rb_callinfo_kwarg *keywords = NULL;
- int argc = pm_setup_args(arguments, (const pm_node_t *) block, &flag, &keywords, iseq, ret, scope_node, node_location);
-
- if ((argc > 0 || boff) && (flag & VM_CALL_KW_SPLAT)) {
- if (boff) {
- PUSH_INSN(ret, location, splatkw);
- }
- else {
- PUSH_INSN(ret, location, dup);
- PUSH_INSN(ret, location, splatkw);
- PUSH_INSN(ret, location, pop);
- }
- }
-
- int dup_argn = argc + 1 + boff;
- int keyword_len = 0;
-
- if (keywords) {
- keyword_len = keywords->keyword_len;
- dup_argn += keyword_len;
- }
-
- PUSH_INSN1(ret, location, dupn, INT2FIX(dup_argn));
- PUSH_SEND_R(ret, location, idAREF, INT2FIX(argc), NULL, INT2FIX(flag & ~(VM_CALL_ARGS_SPLAT_MUT | VM_CALL_KW_SPLAT_MUT)), keywords);
-
- LABEL *label = NEW_LABEL(location.line);
- LABEL *lfin = NEW_LABEL(location.line);
-
- PUSH_INSN(ret, location, dup);
- if (PM_NODE_TYPE_P(node, PM_INDEX_AND_WRITE_NODE)) {
- PUSH_INSNL(ret, location, branchunless, label);
- }
- else {
- PUSH_INSNL(ret, location, branchif, label);
- }
-
- PUSH_INSN(ret, location, pop);
- PM_COMPILE_NOT_POPPED(value);
-
- if (!popped) {
- PUSH_INSN1(ret, location, setn, INT2FIX(dup_argn + 1));
- }
-
- if (flag & VM_CALL_ARGS_SPLAT) {
- if (flag & VM_CALL_KW_SPLAT) {
- PUSH_INSN1(ret, location, topn, INT2FIX(2 + boff));
- if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
- PUSH_INSN1(ret, location, splatarray, Qtrue);
- flag |= VM_CALL_ARGS_SPLAT_MUT;
- }
-
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, pushtoarray, INT2FIX(1));
- PUSH_INSN1(ret, location, setn, INT2FIX(2 + boff));
- PUSH_INSN(ret, location, pop);
- }
- else {
- if (boff > 0) {
- PUSH_INSN1(ret, location, dupn, INT2FIX(3));
- PUSH_INSN(ret, location, swap);
- PUSH_INSN(ret, location, pop);
- }
- if (!(flag & VM_CALL_ARGS_SPLAT_MUT)) {
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, splatarray, Qtrue);
- PUSH_INSN(ret, location, swap);
- flag |= VM_CALL_ARGS_SPLAT_MUT;
- }
- PUSH_INSN1(ret, location, pushtoarray, INT2FIX(1));
- if (boff > 0) {
- PUSH_INSN1(ret, location, setn, INT2FIX(3));
- PUSH_INSN(ret, location, pop);
- PUSH_INSN(ret, location, pop);
- }
- }
-
- PUSH_SEND_R(ret, location, idASET, INT2FIX(argc), NULL, INT2FIX(flag), keywords);
- }
- else if (flag & VM_CALL_KW_SPLAT) {
- if (boff > 0) {
- PUSH_INSN1(ret, location, topn, INT2FIX(2));
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, setn, INT2FIX(3));
- PUSH_INSN(ret, location, pop);
- }
-
- PUSH_INSN(ret, location, swap);
- PUSH_SEND_R(ret, location, idASET, INT2FIX(argc + 1), NULL, INT2FIX(flag), keywords);
- }
- else if (keyword_len) {
- PUSH_INSN1(ret, location, opt_reverse, INT2FIX(keyword_len + boff + 1));
- PUSH_INSN1(ret, location, opt_reverse, INT2FIX(keyword_len + boff + 0));
- PUSH_SEND_R(ret, location, idASET, INT2FIX(argc + 1), NULL, INT2FIX(flag), keywords);
- }
- else {
- if (boff > 0) {
- PUSH_INSN(ret, location, swap);
- }
- PUSH_SEND_R(ret, location, idASET, INT2FIX(argc + 1), NULL, INT2FIX(flag), keywords);
- }
-
- PUSH_INSN(ret, location, pop);
- PUSH_INSNL(ret, location, jump, lfin);
- PUSH_LABEL(ret, label);
- if (!popped) {
- PUSH_INSN1(ret, location, setn, INT2FIX(dup_argn + 1));
- }
- PUSH_INSN1(ret, location, adjuststack, INT2FIX(dup_argn + 1));
- PUSH_LABEL(ret, lfin);
-}
-
-// When we compile a pattern matching expression, we use the stack as a scratch
-// space to store lots of different values (consider it like we have a pattern
-// matching function and we need space for a bunch of different local
-// variables). The "base index" refers to the index on the stack where we
-// started compiling the pattern matching expression. These offsets from that
-// base index indicate the location of the various locals we need.
-#define PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE 0
-#define PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING 1
-#define PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P 2
-#define PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_MATCHEE 3
-#define PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_KEY 4
-
-// A forward declaration because this is the recursive function that handles
-// compiling a pattern. It can be reentered by nesting patterns, as in the case
-// of arrays or hashes.
-static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index);
-
-/**
- * This function generates the code to set up the error string and error_p
- * locals depending on whether or not the pattern matched.
- */
-static int
-pm_compile_pattern_generic_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, VALUE message, unsigned int base_index)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
- LABEL *match_succeeded_label = NEW_LABEL(location.line);
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSNL(ret, location, branchif, match_succeeded_label);
-
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_INSN1(ret, location, putobject, message);
- PUSH_INSN1(ret, location, topn, INT2FIX(3));
- PUSH_SEND(ret, location, id_core_sprintf, INT2FIX(2));
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
-
- PUSH_INSN1(ret, location, putobject, Qfalse);
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
-
- PUSH_INSN(ret, location, pop);
- PUSH_INSN(ret, location, pop);
- PUSH_LABEL(ret, match_succeeded_label);
-
- return COMPILE_OK;
-}
-
-/**
- * This function generates the code to set up the error string and error_p
- * locals depending on whether or not the pattern matched when the value needs
- * to match a specific deconstructed length.
- */
-static int
-pm_compile_pattern_length_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, VALUE message, VALUE length, unsigned int base_index)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
- LABEL *match_succeeded_label = NEW_LABEL(location.line);
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSNL(ret, location, branchif, match_succeeded_label);
-
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_INSN1(ret, location, putobject, message);
- PUSH_INSN1(ret, location, topn, INT2FIX(3));
- PUSH_INSN(ret, location, dup);
- PUSH_SEND(ret, location, idLength, INT2FIX(0));
- PUSH_INSN1(ret, location, putobject, length);
- PUSH_SEND(ret, location, id_core_sprintf, INT2FIX(4));
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
-
- PUSH_INSN1(ret, location, putobject, Qfalse);
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
-
- PUSH_INSN(ret, location, pop);
- PUSH_INSN(ret, location, pop);
- PUSH_LABEL(ret, match_succeeded_label);
-
- return COMPILE_OK;
-}
-
-/**
- * This function generates the code to set up the error string and error_p
- * locals depending on whether or not the pattern matched when the value needs
- * to pass a specific #=== method call.
- */
-static int
-pm_compile_pattern_eqq_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, unsigned int base_index)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
- LABEL *match_succeeded_label = NEW_LABEL(location.line);
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSNL(ret, location, branchif, match_succeeded_label);
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
-
- VALUE operand = rb_fstring_lit("%p === %p does not return true");
- PUSH_INSN1(ret, location, putobject, operand);
-
- PUSH_INSN1(ret, location, topn, INT2FIX(3));
- PUSH_INSN1(ret, location, topn, INT2FIX(5));
- PUSH_SEND(ret, location, id_core_sprintf, INT2FIX(3));
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
- PUSH_INSN1(ret, location, putobject, Qfalse);
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
- PUSH_INSN(ret, location, pop);
- PUSH_INSN(ret, location, pop);
-
- PUSH_LABEL(ret, match_succeeded_label);
- PUSH_INSN1(ret, location, setn, INT2FIX(2));
- PUSH_INSN(ret, location, pop);
- PUSH_INSN(ret, location, pop);
-
- return COMPILE_OK;
-}
-
-/**
- * This is a variation on compiling a pattern matching expression that is used
- * to have the pattern matching instructions fall through to immediately after
- * the pattern if it passes. Otherwise it jumps to the given unmatched_label
- * label.
- */
-static int
-pm_compile_pattern_match(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index)
-{
- LABEL *matched_label = NEW_LABEL(pm_node_line_number(scope_node->parser, node));
- CHECK(pm_compile_pattern(iseq, scope_node, node, ret, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index));
- PUSH_LABEL(ret, matched_label);
- return COMPILE_OK;
-}
-
-/**
- * This function compiles in the code necessary to call #deconstruct on the
- * value to match against. It raises appropriate errors if the method does not
- * exist or if it returns the wrong type.
- */
-static int
-pm_compile_pattern_deconstruct(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *deconstruct_label, LABEL *match_failed_label, LABEL *deconstructed_label, LABEL *type_error_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
-
- if (use_deconstructed_cache) {
- PUSH_INSN1(ret, location, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE));
- PUSH_INSNL(ret, location, branchnil, deconstruct_label);
-
- PUSH_INSN1(ret, location, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE));
- PUSH_INSNL(ret, location, branchunless, match_failed_label);
-
- PUSH_INSN(ret, location, pop);
- PUSH_INSN1(ret, location, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE - 1));
- PUSH_INSNL(ret, location, jump, deconstructed_label);
- }
- else {
- PUSH_INSNL(ret, location, jump, deconstruct_label);
- }
-
- PUSH_LABEL(ret, deconstruct_label);
- PUSH_INSN(ret, location, dup);
-
- VALUE operand = ID2SYM(rb_intern("deconstruct"));
- PUSH_INSN1(ret, location, putobject, operand);
- PUSH_SEND(ret, location, idRespond_to, INT2FIX(1));
-
- if (use_deconstructed_cache) {
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE + 1));
- }
-
- if (in_single_pattern) {
- CHECK(pm_compile_pattern_generic_error(iseq, scope_node, node, ret, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1));
- }
-
- PUSH_INSNL(ret, location, branchunless, match_failed_label);
- PUSH_SEND(ret, location, rb_intern("deconstruct"), INT2FIX(0));
-
- if (use_deconstructed_cache) {
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE));
- }
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, checktype, INT2FIX(T_ARRAY));
- PUSH_INSNL(ret, location, branchunless, type_error_label);
- PUSH_LABEL(ret, deconstructed_label);
-
- return COMPILE_OK;
-}
-
-/**
- * This function compiles in the code necessary to match against the optional
- * constant path that is attached to an array, find, or hash pattern.
- */
-static int
-pm_compile_pattern_constant(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *match_failed_label, bool in_single_pattern, unsigned int base_index)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
-
- PUSH_INSN(ret, location, dup);
- PM_COMPILE_NOT_POPPED(node);
-
- if (in_single_pattern) {
- PUSH_INSN1(ret, location, dupn, INT2FIX(2));
- }
- PUSH_INSN1(ret, location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
- if (in_single_pattern) {
- CHECK(pm_compile_pattern_eqq_error(iseq, scope_node, node, ret, base_index + 3));
- }
- PUSH_INSNL(ret, location, branchunless, match_failed_label);
- return COMPILE_OK;
-}
-
-/**
- * When matching fails, an appropriate error must be raised. This function is
- * responsible for compiling in those error raising instructions.
- */
-static void
-pm_compile_pattern_error_handler(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *done_label, bool popped)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
- LABEL *key_error_label = NEW_LABEL(location.line);
- LABEL *cleanup_label = NEW_LABEL(location.line);
-
- struct rb_callinfo_kwarg *kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
- kw_arg->references = 0;
- kw_arg->keyword_len = 2;
- kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
- kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
-
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_INSN1(ret, location, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
- PUSH_INSNL(ret, location, branchif, key_error_label);
-
- PUSH_INSN1(ret, location, putobject, rb_eNoMatchingPatternError);
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
-
- {
- VALUE operand = rb_fstring_lit("%p: %s");
- PUSH_INSN1(ret, location, putobject, operand);
- }
-
- PUSH_INSN1(ret, location, topn, INT2FIX(4));
- PUSH_INSN1(ret, location, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 6));
- PUSH_SEND(ret, location, id_core_sprintf, INT2FIX(3));
- PUSH_SEND(ret, location, id_core_raise, INT2FIX(2));
- PUSH_INSNL(ret, location, jump, cleanup_label);
-
- PUSH_LABEL(ret, key_error_label);
- PUSH_INSN1(ret, location, putobject, rb_eNoMatchingPatternKeyError);
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
-
- {
- VALUE operand = rb_fstring_lit("%p: %s");
- PUSH_INSN1(ret, location, putobject, operand);
- }
-
- PUSH_INSN1(ret, location, topn, INT2FIX(4));
- PUSH_INSN1(ret, location, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 6));
- PUSH_SEND(ret, location, id_core_sprintf, INT2FIX(3));
- PUSH_INSN1(ret, location, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_MATCHEE + 4));
- PUSH_INSN1(ret, location, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_KEY + 5));
- PUSH_SEND_R(ret, location, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
- PUSH_SEND(ret, location, id_core_raise, INT2FIX(1));
- PUSH_LABEL(ret, cleanup_label);
-
- PUSH_INSN1(ret, location, adjuststack, INT2FIX(7));
- if (!popped) PUSH_INSN(ret, location, putnil);
- PUSH_INSNL(ret, location, jump, done_label);
- PUSH_INSN1(ret, location, dupn, INT2FIX(5));
- if (popped) PUSH_INSN(ret, location, putnil);
-}
-
-/**
- * Compile a pattern matching expression.
- */
-static int
-pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
-
- switch (PM_NODE_TYPE(node)) {
- case PM_ARRAY_PATTERN_NODE: {
- // Array patterns in pattern matching are triggered by using commas in
- // a pattern or wrapping it in braces. They are represented by a
- // ArrayPatternNode. This looks like:
- //
- // foo => [1, 2, 3]
- //
- // It can optionally have a splat in the middle of it, which can
- // optionally have a name attached.
- const pm_array_pattern_node_t *cast = (const pm_array_pattern_node_t *) node;
-
- const size_t requireds_size = cast->requireds.size;
- const size_t posts_size = cast->posts.size;
- const size_t minimum_size = requireds_size + posts_size;
-
- bool rest_named = false;
- bool use_rest_size = false;
-
- if (cast->rest != NULL) {
- rest_named = (PM_NODE_TYPE_P(cast->rest, PM_SPLAT_NODE) && ((const pm_splat_node_t *) cast->rest)->expression != NULL);
- use_rest_size = (rest_named || (!rest_named && posts_size > 0));
- }
-
- LABEL *match_failed_label = NEW_LABEL(location.line);
- LABEL *type_error_label = NEW_LABEL(location.line);
- LABEL *deconstruct_label = NEW_LABEL(location.line);
- LABEL *deconstructed_label = NEW_LABEL(location.line);
-
- if (use_rest_size) {
- PUSH_INSN1(ret, location, putobject, INT2FIX(0));
- PUSH_INSN(ret, location, swap);
- base_index++;
- }
-
- if (cast->constant != NULL) {
- CHECK(pm_compile_pattern_constant(iseq, scope_node, cast->constant, ret, match_failed_label, in_single_pattern, base_index));
- }
-
- CHECK(pm_compile_pattern_deconstruct(iseq, scope_node, node, ret, deconstruct_label, match_failed_label, deconstructed_label, type_error_label, in_single_pattern, use_deconstructed_cache, base_index));
-
- PUSH_INSN(ret, location, dup);
- PUSH_SEND(ret, location, idLength, INT2FIX(0));
- PUSH_INSN1(ret, location, putobject, INT2FIX(minimum_size));
- PUSH_SEND(ret, location, cast->rest == NULL ? idEq : idGE, INT2FIX(1));
- if (in_single_pattern) {
- VALUE message = cast->rest == NULL ? rb_fstring_lit("%p length mismatch (given %p, expected %p)") : rb_fstring_lit("%p length mismatch (given %p, expected %p+)");
- CHECK(pm_compile_pattern_length_error(iseq, scope_node, node, ret, message, INT2FIX(minimum_size), base_index + 1));
- }
- PUSH_INSNL(ret, location, branchunless, match_failed_label);
-
- for (size_t index = 0; index < requireds_size; index++) {
- const pm_node_t *required = cast->requireds.nodes[index];
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putobject, INT2FIX(index));
- PUSH_SEND(ret, location, idAREF, INT2FIX(1));
- CHECK(pm_compile_pattern_match(iseq, scope_node, required, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
- }
-
- if (cast->rest != NULL) {
- if (rest_named) {
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putobject, INT2FIX(requireds_size));
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- PUSH_SEND(ret, location, idLength, INT2FIX(0));
- PUSH_INSN1(ret, location, putobject, INT2FIX(minimum_size));
- PUSH_SEND(ret, location, idMINUS, INT2FIX(1));
- PUSH_INSN1(ret, location, setn, INT2FIX(4));
- PUSH_SEND(ret, location, idAREF, INT2FIX(2));
- CHECK(pm_compile_pattern_match(iseq, scope_node, ((const pm_splat_node_t *) cast->rest)->expression, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
- }
- else if (posts_size > 0) {
- PUSH_INSN(ret, location, dup);
- PUSH_SEND(ret, location, idLength, INT2FIX(0));
- PUSH_INSN1(ret, location, putobject, INT2FIX(minimum_size));
- PUSH_SEND(ret, location, idMINUS, INT2FIX(1));
- PUSH_INSN1(ret, location, setn, INT2FIX(2));
- PUSH_INSN(ret, location, pop);
- }
- }
-
- for (size_t index = 0; index < posts_size; index++) {
- const pm_node_t *post = cast->posts.nodes[index];
- PUSH_INSN(ret, location, dup);
-
- PUSH_INSN1(ret, location, putobject, INT2FIX(requireds_size + index));
- PUSH_INSN1(ret, location, topn, INT2FIX(3));
- PUSH_SEND(ret, location, idPLUS, INT2FIX(1));
- PUSH_SEND(ret, location, idAREF, INT2FIX(1));
- CHECK(pm_compile_pattern_match(iseq, scope_node, post, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
- }
-
- PUSH_INSN(ret, location, pop);
- if (use_rest_size) {
- PUSH_INSN(ret, location, pop);
- }
-
- PUSH_INSNL(ret, location, jump, matched_label);
- PUSH_INSN(ret, location, putnil);
- if (use_rest_size) {
- PUSH_INSN(ret, location, putnil);
- }
-
- PUSH_LABEL(ret, type_error_label);
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_INSN1(ret, location, putobject, rb_eTypeError);
-
- {
- VALUE operand = rb_fstring_lit("deconstruct must return Array");
- PUSH_INSN1(ret, location, putobject, operand);
- }
-
- PUSH_SEND(ret, location, id_core_raise, INT2FIX(2));
- PUSH_INSN(ret, location, pop);
-
- PUSH_LABEL(ret, match_failed_label);
- PUSH_INSN(ret, location, pop);
- if (use_rest_size) {
- PUSH_INSN(ret, location, pop);
- }
-
- PUSH_INSNL(ret, location, jump, unmatched_label);
- break;
- }
- case PM_FIND_PATTERN_NODE: {
- // Find patterns in pattern matching are triggered by using commas in
- // a pattern or wrapping it in braces and using a splat on both the left
- // and right side of the pattern. This looks like:
- //
- // foo => [*, 1, 2, 3, *]
- //
- // There can be any number of requireds in the middle. The splats on
- // both sides can optionally have names attached.
- const pm_find_pattern_node_t *cast = (const pm_find_pattern_node_t *) node;
- const size_t size = cast->requireds.size;
-
- LABEL *match_failed_label = NEW_LABEL(location.line);
- LABEL *type_error_label = NEW_LABEL(location.line);
- LABEL *deconstruct_label = NEW_LABEL(location.line);
- LABEL *deconstructed_label = NEW_LABEL(location.line);
-
- if (cast->constant) {
- CHECK(pm_compile_pattern_constant(iseq, scope_node, cast->constant, ret, match_failed_label, in_single_pattern, base_index));
- }
-
- CHECK(pm_compile_pattern_deconstruct(iseq, scope_node, node, ret, deconstruct_label, match_failed_label, deconstructed_label, type_error_label, in_single_pattern, use_deconstructed_cache, base_index));
-
- PUSH_INSN(ret, location, dup);
- PUSH_SEND(ret, location, idLength, INT2FIX(0));
- PUSH_INSN1(ret, location, putobject, INT2FIX(size));
- PUSH_SEND(ret, location, idGE, INT2FIX(1));
- if (in_single_pattern) {
- CHECK(pm_compile_pattern_length_error(iseq, scope_node, node, ret, rb_fstring_lit("%p length mismatch (given %p, expected %p+)"), INT2FIX(size), base_index + 1));
- }
- PUSH_INSNL(ret, location, branchunless, match_failed_label);
-
- {
- LABEL *while_begin_label = NEW_LABEL(location.line);
- LABEL *next_loop_label = NEW_LABEL(location.line);
- LABEL *find_succeeded_label = NEW_LABEL(location.line);
- LABEL *find_failed_label = NEW_LABEL(location.line);
-
- PUSH_INSN(ret, location, dup);
- PUSH_SEND(ret, location, idLength, INT2FIX(0));
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putobject, INT2FIX(size));
- PUSH_SEND(ret, location, idMINUS, INT2FIX(1));
- PUSH_INSN1(ret, location, putobject, INT2FIX(0));
- PUSH_LABEL(ret, while_begin_label);
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, topn, INT2FIX(2));
- PUSH_SEND(ret, location, idLE, INT2FIX(1));
- PUSH_INSNL(ret, location, branchunless, find_failed_label);
-
- for (size_t index = 0; index < size; index++) {
- PUSH_INSN1(ret, location, topn, INT2FIX(3));
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
-
- if (index != 0) {
- PUSH_INSN1(ret, location, putobject, INT2FIX(index));
- PUSH_SEND(ret, location, idPLUS, INT2FIX(1));
- }
-
- PUSH_SEND(ret, location, idAREF, INT2FIX(1));
- CHECK(pm_compile_pattern_match(iseq, scope_node, cast->requireds.nodes[index], ret, next_loop_label, in_single_pattern, in_alternation_pattern, false, base_index + 4));
- }
-
- const pm_splat_node_t *left = cast->left;
-
- if (left->expression != NULL) {
- PUSH_INSN1(ret, location, topn, INT2FIX(3));
- PUSH_INSN1(ret, location, putobject, INT2FIX(0));
- PUSH_INSN1(ret, location, topn, INT2FIX(2));
- PUSH_SEND(ret, location, idAREF, INT2FIX(2));
- CHECK(pm_compile_pattern_match(iseq, scope_node, left->expression, ret, find_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 4));
- }
-
- RUBY_ASSERT(PM_NODE_TYPE_P(cast->right, PM_SPLAT_NODE));
- const pm_splat_node_t *right = (const pm_splat_node_t *) cast->right;
-
- if (right->expression != NULL) {
- PUSH_INSN1(ret, location, topn, INT2FIX(3));
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- PUSH_INSN1(ret, location, putobject, INT2FIX(size));
- PUSH_SEND(ret, location, idPLUS, INT2FIX(1));
- PUSH_INSN1(ret, location, topn, INT2FIX(3));
- PUSH_SEND(ret, location, idAREF, INT2FIX(2));
- pm_compile_pattern_match(iseq, scope_node, right->expression, ret, find_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 4);
- }
-
- PUSH_INSNL(ret, location, jump, find_succeeded_label);
-
- PUSH_LABEL(ret, next_loop_label);
- PUSH_INSN1(ret, location, putobject, INT2FIX(1));
- PUSH_SEND(ret, location, idPLUS, INT2FIX(1));
- PUSH_INSNL(ret, location, jump, while_begin_label);
-
- PUSH_LABEL(ret, find_failed_label);
- PUSH_INSN1(ret, location, adjuststack, INT2FIX(3));
- if (in_single_pattern) {
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
-
- {
- VALUE operand = rb_fstring_lit("%p does not match to find pattern");
- PUSH_INSN1(ret, location, putobject, operand);
- }
-
- PUSH_INSN1(ret, location, topn, INT2FIX(2));
- PUSH_SEND(ret, location, id_core_sprintf, INT2FIX(2));
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
-
- PUSH_INSN1(ret, location, putobject, Qfalse);
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
-
- PUSH_INSN(ret, location, pop);
- PUSH_INSN(ret, location, pop);
- }
- PUSH_INSNL(ret, location, jump, match_failed_label);
- PUSH_INSN1(ret, location, dupn, INT2FIX(3));
-
- PUSH_LABEL(ret, find_succeeded_label);
- PUSH_INSN1(ret, location, adjuststack, INT2FIX(3));
- }
-
- PUSH_INSN(ret, location, pop);
- PUSH_INSNL(ret, location, jump, matched_label);
- PUSH_INSN(ret, location, putnil);
-
- PUSH_LABEL(ret, type_error_label);
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_INSN1(ret, location, putobject, rb_eTypeError);
-
- {
- VALUE operand = rb_fstring_lit("deconstruct must return Array");
- PUSH_INSN1(ret, location, putobject, operand);
- }
-
- PUSH_SEND(ret, location, id_core_raise, INT2FIX(2));
- PUSH_INSN(ret, location, pop);
-
- PUSH_LABEL(ret, match_failed_label);
- PUSH_INSN(ret, location, pop);
- PUSH_INSNL(ret, location, jump, unmatched_label);
-
- break;
- }
- case PM_HASH_PATTERN_NODE: {
- // Hash patterns in pattern matching are triggered by using labels and
- // values in a pattern or by using the ** operator. They are represented
- // by the HashPatternNode. This looks like:
- //
- // foo => { a: 1, b: 2, **bar }
- //
- // It can optionally have an assoc splat in the middle of it, which can
- // optionally have a name.
- const pm_hash_pattern_node_t *cast = (const pm_hash_pattern_node_t *) node;
-
- // We don't consider it a "rest" parameter if it's a ** that is unnamed.
- bool has_rest = cast->rest != NULL && !(PM_NODE_TYPE_P(cast->rest, PM_ASSOC_SPLAT_NODE) && ((const pm_assoc_splat_node_t *) cast->rest)->value == NULL);
- bool has_keys = cast->elements.size > 0 || cast->rest != NULL;
-
- LABEL *match_failed_label = NEW_LABEL(location.line);
- LABEL *type_error_label = NEW_LABEL(location.line);
- VALUE keys = Qnil;
-
- if (has_keys && !has_rest) {
- keys = rb_ary_new_capa(cast->elements.size);
-
- for (size_t index = 0; index < cast->elements.size; index++) {
- const pm_node_t *element = cast->elements.nodes[index];
- RUBY_ASSERT(PM_NODE_TYPE_P(element, PM_ASSOC_NODE));
-
- const pm_node_t *key = ((const pm_assoc_node_t *) element)->key;
- RUBY_ASSERT(PM_NODE_TYPE_P(key, PM_SYMBOL_NODE));
-
- VALUE symbol = ID2SYM(parse_string_symbol(scope_node, (const pm_symbol_node_t *) key));
- rb_ary_push(keys, symbol);
- }
- }
-
- if (cast->constant) {
- CHECK(pm_compile_pattern_constant(iseq, scope_node, cast->constant, ret, match_failed_label, in_single_pattern, base_index));
- }
-
- PUSH_INSN(ret, location, dup);
-
- {
- VALUE operand = ID2SYM(rb_intern("deconstruct_keys"));
- PUSH_INSN1(ret, location, putobject, operand);
- }
-
- PUSH_SEND(ret, location, idRespond_to, INT2FIX(1));
- if (in_single_pattern) {
- CHECK(pm_compile_pattern_generic_error(iseq, scope_node, node, ret, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1));
- }
- PUSH_INSNL(ret, location, branchunless, match_failed_label);
-
- if (NIL_P(keys)) {
- PUSH_INSN(ret, location, putnil);
- }
- else {
- PUSH_INSN1(ret, location, duparray, keys);
- RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
- }
- PUSH_SEND(ret, location, rb_intern("deconstruct_keys"), INT2FIX(1));
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, checktype, INT2FIX(T_HASH));
- PUSH_INSNL(ret, location, branchunless, type_error_label);
-
- if (has_rest) {
- PUSH_SEND(ret, location, rb_intern("dup"), INT2FIX(0));
- }
-
- if (has_keys) {
- DECL_ANCHOR(match_values);
- INIT_ANCHOR(match_values);
-
- for (size_t index = 0; index < cast->elements.size; index++) {
- const pm_node_t *element = cast->elements.nodes[index];
- RUBY_ASSERT(PM_NODE_TYPE_P(element, PM_ASSOC_NODE));
-
- const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) element;
- const pm_node_t *key = assoc->key;
- RUBY_ASSERT(PM_NODE_TYPE_P(key, PM_SYMBOL_NODE));
-
- VALUE symbol = ID2SYM(parse_string_symbol(scope_node, (const pm_symbol_node_t *) key));
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putobject, symbol);
- PUSH_SEND(ret, location, rb_intern("key?"), INT2FIX(1));
-
- if (in_single_pattern) {
- LABEL *match_succeeded_label = NEW_LABEL(location.line);
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSNL(ret, location, branchif, match_succeeded_label);
-
- {
- VALUE operand = rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, symbol));
- PUSH_INSN1(ret, location, putobject, operand);
- }
-
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 2));
- PUSH_INSN1(ret, location, putobject, Qtrue);
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 3));
- PUSH_INSN1(ret, location, topn, INT2FIX(3));
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_MATCHEE + 4));
- PUSH_INSN1(ret, location, putobject, symbol);
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_KEY + 5));
-
- PUSH_INSN1(ret, location, adjuststack, INT2FIX(4));
- PUSH_LABEL(ret, match_succeeded_label);
- }
-
- PUSH_INSNL(ret, location, branchunless, match_failed_label);
- PUSH_INSN(match_values, location, dup);
- PUSH_INSN1(match_values, location, putobject, symbol);
- PUSH_SEND(match_values, location, has_rest ? rb_intern("delete") : idAREF, INT2FIX(1));
-
- const pm_node_t *value = assoc->value;
- if (PM_NODE_TYPE_P(value, PM_IMPLICIT_NODE)) {
- value = ((const pm_implicit_node_t *) value)->value;
- }
-
- CHECK(pm_compile_pattern_match(iseq, scope_node, value, match_values, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
- }
-
- PUSH_SEQ(ret, match_values);
- }
- else {
- PUSH_INSN(ret, location, dup);
- PUSH_SEND(ret, location, idEmptyP, INT2FIX(0));
- if (in_single_pattern) {
- CHECK(pm_compile_pattern_generic_error(iseq, scope_node, node, ret, rb_fstring_lit("%p is not empty"), base_index + 1));
- }
- PUSH_INSNL(ret, location, branchunless, match_failed_label);
- }
-
- if (has_rest) {
- switch (PM_NODE_TYPE(cast->rest)) {
- case PM_NO_KEYWORDS_PARAMETER_NODE: {
- PUSH_INSN(ret, location, dup);
- PUSH_SEND(ret, location, idEmptyP, INT2FIX(0));
- if (in_single_pattern) {
- pm_compile_pattern_generic_error(iseq, scope_node, node, ret, rb_fstring_lit("rest of %p is not empty"), base_index + 1);
- }
- PUSH_INSNL(ret, location, branchunless, match_failed_label);
- break;
- }
- case PM_ASSOC_SPLAT_NODE: {
- const pm_assoc_splat_node_t *splat = (const pm_assoc_splat_node_t *) cast->rest;
- PUSH_INSN(ret, location, dup);
- pm_compile_pattern_match(iseq, scope_node, splat->value, ret, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1);
- break;
- }
- default:
- rb_bug("unreachable");
- break;
- }
- }
-
- PUSH_INSN(ret, location, pop);
- PUSH_INSNL(ret, location, jump, matched_label);
- PUSH_INSN(ret, location, putnil);
-
- PUSH_LABEL(ret, type_error_label);
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_INSN1(ret, location, putobject, rb_eTypeError);
-
- {
- VALUE operand = rb_fstring_lit("deconstruct_keys must return Hash");
- PUSH_INSN1(ret, location, putobject, operand);
- }
-
- PUSH_SEND(ret, location, id_core_raise, INT2FIX(2));
- PUSH_INSN(ret, location, pop);
-
- PUSH_LABEL(ret, match_failed_label);
- PUSH_INSN(ret, location, pop);
- PUSH_INSNL(ret, location, jump, unmatched_label);
- break;
- }
- case PM_CAPTURE_PATTERN_NODE: {
- // Capture patterns allow you to pattern match against an element in a
- // pattern and also capture the value into a local variable. This looks
- // like:
- //
- // [1] => [Integer => foo]
- //
- // In this case the `Integer => foo` will be represented by a
- // CapturePatternNode, which has both a value (the pattern to match
- // against) and a target (the place to write the variable into).
- const pm_capture_pattern_node_t *cast = (const pm_capture_pattern_node_t *) node;
-
- LABEL *match_failed_label = NEW_LABEL(location.line);
-
- PUSH_INSN(ret, location, dup);
- CHECK(pm_compile_pattern_match(iseq, scope_node, cast->value, ret, match_failed_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index + 1));
- CHECK(pm_compile_pattern(iseq, scope_node, (const pm_node_t *) cast->target, ret, matched_label, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index));
- PUSH_INSN(ret, location, putnil);
-
- PUSH_LABEL(ret, match_failed_label);
- PUSH_INSN(ret, location, pop);
- PUSH_INSNL(ret, location, jump, unmatched_label);
-
- break;
- }
- case PM_LOCAL_VARIABLE_TARGET_NODE: {
- // Local variables can be targeted by placing identifiers in the place
- // of a pattern. For example, foo in bar. This results in the value
- // being matched being written to that local variable.
- const pm_local_variable_target_node_t *cast = (const pm_local_variable_target_node_t *) node;
- pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, cast->name, cast->depth);
-
- // If this local variable is being written from within an alternation
- // pattern, then it cannot actually be added to the local table since
- // it's ambiguous which value should be used. So instead we indicate
- // this with a compile error.
- if (in_alternation_pattern) {
- ID id = pm_constant_id_lookup(scope_node, cast->name);
- const char *name = rb_id2name(id);
-
- if (name && strlen(name) > 0 && name[0] != '_') {
- COMPILE_ERROR(iseq, location.line, "illegal variable in alternative pattern (%"PRIsVALUE")", rb_id2str(id));
- return COMPILE_NG;
- }
- }
-
- PUSH_SETLOCAL(ret, location, index.index, index.level);
- PUSH_INSNL(ret, location, jump, matched_label);
- break;
- }
- case PM_ALTERNATION_PATTERN_NODE: {
- // Alternation patterns allow you to specify multiple patterns in a
- // single expression using the | operator.
- const pm_alternation_pattern_node_t *cast = (const pm_alternation_pattern_node_t *) node;
-
- LABEL *matched_left_label = NEW_LABEL(location.line);
- LABEL *unmatched_left_label = NEW_LABEL(location.line);
-
- // First, we're going to attempt to match against the left pattern. If
- // that pattern matches, then we'll skip matching the right pattern.
- PUSH_INSN(ret, location, dup);
- CHECK(pm_compile_pattern(iseq, scope_node, cast->left, ret, matched_left_label, unmatched_left_label, in_single_pattern, true, true, base_index + 1));
-
- // If we get here, then we matched on the left pattern. In this case we
- // should pop out the duplicate value that we preemptively added to
- // match against the right pattern and then jump to the match label.
- PUSH_LABEL(ret, matched_left_label);
- PUSH_INSN(ret, location, pop);
- PUSH_INSNL(ret, location, jump, matched_label);
- PUSH_INSN(ret, location, putnil);
-
- // If we get here, then we didn't match on the left pattern. In this
- // case we attempt to match against the right pattern.
- PUSH_LABEL(ret, unmatched_left_label);
- CHECK(pm_compile_pattern(iseq, scope_node, cast->right, ret, matched_label, unmatched_label, in_single_pattern, true, true, base_index));
- break;
- }
- case PM_PARENTHESES_NODE:
- // Parentheses are allowed to wrap expressions in pattern matching and
- // they do nothing since they can only wrap individual expressions and
- // not groups. In this case we'll recurse back into this same function
- // with the body of the parentheses.
- return pm_compile_pattern(iseq, scope_node, ((const pm_parentheses_node_t *) node)->body, ret, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index);
- case PM_PINNED_EXPRESSION_NODE:
- // Pinned expressions are a way to match against the value of an
- // expression that should be evaluated at runtime. This looks like:
- // foo in ^(bar). To compile these, we compile the expression as if it
- // were a literal value by falling through to the literal case.
- node = ((const pm_pinned_expression_node_t *) node)->expression;
- /* fallthrough */
- case PM_ARRAY_NODE:
- case PM_CLASS_VARIABLE_READ_NODE:
- case PM_CONSTANT_PATH_NODE:
- case PM_CONSTANT_READ_NODE:
- case PM_FALSE_NODE:
- case PM_FLOAT_NODE:
- case PM_GLOBAL_VARIABLE_READ_NODE:
- case PM_IMAGINARY_NODE:
- case PM_INSTANCE_VARIABLE_READ_NODE:
- case PM_INTEGER_NODE:
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
- case PM_INTERPOLATED_STRING_NODE:
- case PM_INTERPOLATED_SYMBOL_NODE:
- case PM_INTERPOLATED_X_STRING_NODE:
- case PM_LAMBDA_NODE:
- case PM_LOCAL_VARIABLE_READ_NODE:
- case PM_NIL_NODE:
- case PM_SOURCE_ENCODING_NODE:
- case PM_SOURCE_FILE_NODE:
- case PM_SOURCE_LINE_NODE:
- case PM_RANGE_NODE:
- case PM_RATIONAL_NODE:
- case PM_REGULAR_EXPRESSION_NODE:
- case PM_SELF_NODE:
- case PM_STRING_NODE:
- case PM_SYMBOL_NODE:
- case PM_TRUE_NODE:
- case PM_X_STRING_NODE: {
- // These nodes are all simple patterns, which means we'll use the
- // checkmatch instruction to match against them, which is effectively a
- // VM-level === operator.
- PM_COMPILE_NOT_POPPED(node);
- if (in_single_pattern) {
- PUSH_INSN1(ret, location, dupn, INT2FIX(2));
- }
-
- PUSH_INSN1(ret, location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
-
- if (in_single_pattern) {
- pm_compile_pattern_eqq_error(iseq, scope_node, node, ret, base_index + 2);
- }
-
- PUSH_INSNL(ret, location, branchif, matched_label);
- PUSH_INSNL(ret, location, jump, unmatched_label);
- break;
- }
- case PM_PINNED_VARIABLE_NODE: {
- // Pinned variables are a way to match against the value of a variable
- // without it looking like you're trying to write to the variable. This
- // looks like: foo in ^@bar. To compile these, we compile the variable
- // that they hold.
- const pm_pinned_variable_node_t *cast = (const pm_pinned_variable_node_t *) node;
- CHECK(pm_compile_pattern(iseq, scope_node, cast->variable, ret, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, true, base_index));
- break;
- }
- case PM_IF_NODE:
- case PM_UNLESS_NODE: {
- // If and unless nodes can show up here as guards on `in` clauses. This
- // looks like:
- //
- // case foo
- // in bar if baz?
- // qux
- // end
- //
- // Because we know they're in the modifier form and they can't have any
- // variation on this pattern, we compile them differently (more simply)
- // here than we would in the normal compilation path.
- const pm_node_t *predicate;
- const pm_node_t *statement;
-
- if (PM_NODE_TYPE_P(node, PM_IF_NODE)) {
- const pm_if_node_t *cast = (const pm_if_node_t *) node;
- predicate = cast->predicate;
-
- RUBY_ASSERT(cast->statements != NULL && cast->statements->body.size == 1);
- statement = cast->statements->body.nodes[0];
- }
- else {
- const pm_unless_node_t *cast = (const pm_unless_node_t *) node;
- predicate = cast->predicate;
-
- RUBY_ASSERT(cast->statements != NULL && cast->statements->body.size == 1);
- statement = cast->statements->body.nodes[0];
- }
-
- CHECK(pm_compile_pattern_match(iseq, scope_node, statement, ret, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index));
- PM_COMPILE_NOT_POPPED(predicate);
-
- if (in_single_pattern) {
- LABEL *match_succeeded_label = NEW_LABEL(location.line);
-
- PUSH_INSN(ret, location, dup);
- if (PM_NODE_TYPE_P(node, PM_IF_NODE)) {
- PUSH_INSNL(ret, location, branchif, match_succeeded_label);
- }
- else {
- PUSH_INSNL(ret, location, branchunless, match_succeeded_label);
- }
-
- {
- VALUE operand = rb_fstring_lit("guard clause does not return true");
- PUSH_INSN1(ret, location, putobject, operand);
- }
-
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
- PUSH_INSN1(ret, location, putobject, Qfalse);
- PUSH_INSN1(ret, location, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
-
- PUSH_INSN(ret, location, pop);
- PUSH_INSN(ret, location, pop);
-
- PUSH_LABEL(ret, match_succeeded_label);
- }
-
- if (PM_NODE_TYPE_P(node, PM_IF_NODE)) {
- PUSH_INSNL(ret, location, branchunless, unmatched_label);
- }
- else {
- PUSH_INSNL(ret, location, branchif, unmatched_label);
- }
-
- PUSH_INSNL(ret, location, jump, matched_label);
- break;
- }
- default:
- // If we get here, then we have a node type that should not be in this
- // position. This would be a bug in the parser, because a different node
- // type should never have been created in this position in the tree.
- rb_bug("Unexpected node type in pattern matching expression: %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
- break;
- }
-
- return COMPILE_OK;
-}
-
-#undef PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE
-#undef PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING
-#undef PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P
-#undef PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_MATCHEE
-#undef PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_KEY
-
-// Generate a scope node from the given node.
-void
-pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_t *previous)
-{
- // This is very important, otherwise the scope node could be seen as having
- // certain flags set that _should not_ be set.
- memset(scope, 0, sizeof(pm_scope_node_t));
-
- scope->base.type = PM_SCOPE_NODE;
- scope->base.location.start = node->location.start;
- scope->base.location.end = node->location.end;
-
- scope->previous = previous;
- scope->ast_node = (pm_node_t *) node;
-
- if (previous) {
- scope->parser = previous->parser;
- scope->encoding = previous->encoding;
- scope->filepath_encoding = previous->filepath_encoding;
- scope->constants = previous->constants;
- scope->coverage_enabled = previous->coverage_enabled;
- scope->script_lines = previous->script_lines;
- }
-
- switch (PM_NODE_TYPE(node)) {
- case PM_BLOCK_NODE: {
- const pm_block_node_t *cast = (const pm_block_node_t *) node;
- scope->body = cast->body;
- scope->locals = cast->locals;
- scope->parameters = cast->parameters;
- break;
- }
- case PM_CLASS_NODE: {
- const pm_class_node_t *cast = (const pm_class_node_t *) node;
- scope->body = cast->body;
- scope->locals = cast->locals;
- break;
- }
- case PM_DEF_NODE: {
- const pm_def_node_t *cast = (const pm_def_node_t *) node;
- scope->parameters = (pm_node_t *) cast->parameters;
- scope->body = cast->body;
- scope->locals = cast->locals;
- break;
- }
- case PM_ENSURE_NODE: {
- const pm_ensure_node_t *cast = (const pm_ensure_node_t *) node;
- scope->body = (pm_node_t *) node;
-
- if (cast->statements != NULL) {
- scope->base.location.start = cast->statements->base.location.start;
- scope->base.location.end = cast->statements->base.location.end;
- }
-
- break;
- }
- case PM_FOR_NODE: {
- const pm_for_node_t *cast = (const pm_for_node_t *) node;
- scope->body = (pm_node_t *) cast->statements;
- break;
- }
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
- RUBY_ASSERT(node->flags & PM_REGULAR_EXPRESSION_FLAGS_ONCE);
- scope->body = (pm_node_t *) node;
- break;
- }
- case PM_LAMBDA_NODE: {
- const pm_lambda_node_t *cast = (const pm_lambda_node_t *) node;
- scope->parameters = cast->parameters;
- scope->body = cast->body;
- scope->locals = cast->locals;
-
- if (cast->parameters != NULL) {
- scope->base.location.start = cast->parameters->location.start;
- }
- else {
- scope->base.location.start = cast->operator_loc.end;
- }
- break;
- }
- case PM_MODULE_NODE: {
- const pm_module_node_t *cast = (const pm_module_node_t *) node;
- scope->body = cast->body;
- scope->locals = cast->locals;
- break;
- }
- case PM_POST_EXECUTION_NODE: {
- const pm_post_execution_node_t *cast = (const pm_post_execution_node_t *) node;
- scope->body = (pm_node_t *) cast->statements;
- break;
- }
- case PM_PROGRAM_NODE: {
- const pm_program_node_t *cast = (const pm_program_node_t *) node;
- scope->body = (pm_node_t *) cast->statements;
- scope->locals = cast->locals;
- break;
- }
- case PM_RESCUE_NODE: {
- const pm_rescue_node_t *cast = (const pm_rescue_node_t *) node;
- scope->body = (pm_node_t *) cast->statements;
- break;
- }
- case PM_RESCUE_MODIFIER_NODE: {
- const pm_rescue_modifier_node_t *cast = (const pm_rescue_modifier_node_t *) node;
- scope->body = (pm_node_t *) cast->rescue_expression;
- break;
- }
- case PM_SINGLETON_CLASS_NODE: {
- const pm_singleton_class_node_t *cast = (const pm_singleton_class_node_t *) node;
- scope->body = cast->body;
- scope->locals = cast->locals;
- break;
- }
- case PM_STATEMENTS_NODE: {
- const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
- scope->body = (pm_node_t *) cast;
- break;
- }
- default:
- rb_bug("unreachable");
- break;
- }
-}
-
-void
-pm_scope_node_destroy(pm_scope_node_t *scope_node)
-{
- if (scope_node->index_lookup_table) {
- st_free_table(scope_node->index_lookup_table);
- }
-}
-
-/**
- * We need to put the label "retry_end_l" immediately after the last "send"
- * instruction. This because vm_throw checks if the break cont is equal to the
- * index of next insn of the "send". (Otherwise, it is considered
- * "break from proc-closure". See "TAG_BREAK" handling in "vm_throw_start".)
- *
- * Normally, "send" instruction is at the last. However, qcall under branch
- * coverage measurement adds some instructions after the "send".
- *
- * Note that "invokesuper", "invokesuperforward" appears instead of "send".
- */
-static void
-pm_compile_retry_end_label(rb_iseq_t *iseq, LINK_ANCHOR *const ret, LABEL *retry_end_l)
-{
- INSN *iobj;
- LINK_ELEMENT *last_elem = LAST_ELEMENT(ret);
- iobj = IS_INSN(last_elem) ? (INSN*) last_elem : (INSN*) get_prev_insn((INSN*) last_elem);
- while (!IS_INSN_ID(iobj, send) && !IS_INSN_ID(iobj, invokesuper) && !IS_INSN_ID(iobj, sendforward) && !IS_INSN_ID(iobj, invokesuperforward)) {
- iobj = (INSN*) get_prev_insn(iobj);
- }
- ELEM_INSERT_NEXT(&iobj->link, (LINK_ELEMENT*) retry_end_l);
-
- // LINK_ANCHOR has a pointer to the last element, but
- // ELEM_INSERT_NEXT does not update it even if we add an insn to the
- // last of LINK_ANCHOR. So this updates it manually.
- if (&iobj->link == LAST_ELEMENT(ret)) {
- ret->last = (LINK_ELEMENT*) retry_end_l;
- }
-}
-
-static const char *
-pm_iseq_builtin_function_name(const pm_scope_node_t *scope_node, const pm_node_t *receiver, ID method_id)
-{
- const char *name = rb_id2name(method_id);
- static const char prefix[] = "__builtin_";
- const size_t prefix_len = sizeof(prefix) - 1;
-
- if (receiver == NULL) {
- if (UNLIKELY(strncmp(prefix, name, prefix_len) == 0)) {
- // __builtin_foo
- return &name[prefix_len];
- }
- }
- else if (PM_NODE_TYPE_P(receiver, PM_CALL_NODE)) {
- if (PM_NODE_FLAG_P(receiver, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- const pm_call_node_t *cast = (const pm_call_node_t *) receiver;
- if (pm_constant_id_lookup(scope_node, cast->name) == rb_intern_const("__builtin")) {
- // __builtin.foo
- return name;
- }
- }
- }
- else if (PM_NODE_TYPE_P(receiver, PM_CONSTANT_READ_NODE)) {
- const pm_constant_read_node_t *cast = (const pm_constant_read_node_t *) receiver;
- if (pm_constant_id_lookup(scope_node, cast->name) == rb_intern_const("Primitive")) {
- // Primitive.foo
- return name;
- }
- }
-
- return NULL;
-}
-
-// Compile Primitive.attr! :leaf, ...
-static int
-pm_compile_builtin_attr(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_arguments_node_t *arguments, const pm_node_location_t *node_location)
-{
- if (arguments == NULL) {
- COMPILE_ERROR(iseq, node_location->line, "attr!: no argument");
- return COMPILE_NG;
- }
-
- const pm_node_t *argument;
- PM_NODE_LIST_FOREACH(&arguments->arguments, index, argument) {
- if (!PM_NODE_TYPE_P(argument, PM_SYMBOL_NODE)) {
- COMPILE_ERROR(iseq, node_location->line, "non symbol argument to attr!: %s", pm_node_type_to_str(PM_NODE_TYPE(argument)));
- return COMPILE_NG;
- }
-
- VALUE symbol = pm_static_literal_value(iseq, argument, scope_node);
- VALUE string = rb_sym_to_s(symbol);
-
- if (strcmp(RSTRING_PTR(string), "leaf") == 0) {
- ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_LEAF;
- }
- else if (strcmp(RSTRING_PTR(string), "inline_block") == 0) {
- ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE_BLOCK;
- }
- else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
- iseq_set_use_block(iseq);
- }
- else {
- COMPILE_ERROR(iseq, node_location->line, "unknown argument to attr!: %s", RSTRING_PTR(string));
- return COMPILE_NG;
- }
- }
-
- return COMPILE_OK;
-}
-
-static int
-pm_compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node, const pm_arguments_node_t *arguments, const pm_node_location_t *node_location, int popped)
-{
- if (arguments == NULL) {
- COMPILE_ERROR(iseq, node_location->line, "arg!: no argument");
- return COMPILE_NG;
- }
-
- if (arguments->arguments.size != 1) {
- COMPILE_ERROR(iseq, node_location->line, "arg!: too many argument");
- return COMPILE_NG;
- }
-
- const pm_node_t *argument = arguments->arguments.nodes[0];
- if (!PM_NODE_TYPE_P(argument, PM_SYMBOL_NODE)) {
- COMPILE_ERROR(iseq, node_location->line, "non symbol argument to arg!: %s", pm_node_type_to_str(PM_NODE_TYPE(argument)));
- return COMPILE_NG;
- }
-
- if (!popped) {
- ID name = parse_string_symbol(scope_node, ((const pm_symbol_node_t *) argument));
- int index = ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->local_table_size - get_local_var_idx(iseq, name);
-
- debugs("id: %s idx: %d\n", rb_id2name(name), index);
- PUSH_GETLOCAL(ret, *node_location, index, get_lvar_level(iseq));
- }
-
- return COMPILE_OK;
-}
-
-static int
-pm_compile_builtin_mandatory_only_method(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_call_node_t *call_node, const pm_node_location_t *node_location)
-{
- const pm_node_t *ast_node = scope_node->ast_node;
- if (!PM_NODE_TYPE_P(ast_node, PM_DEF_NODE)) {
- rb_bug("mandatory_only?: not in method definition");
- return COMPILE_NG;
- }
-
- const pm_def_node_t *def_node = (const pm_def_node_t *) ast_node;
- const pm_parameters_node_t *parameters_node = def_node->parameters;
- if (parameters_node == NULL) {
- rb_bug("mandatory_only?: in method definition with no parameters");
- return COMPILE_NG;
- }
-
- const pm_node_t *body_node = def_node->body;
- if (body_node == NULL || !PM_NODE_TYPE_P(body_node, PM_STATEMENTS_NODE) || (((const pm_statements_node_t *) body_node)->body.size != 1) || !PM_NODE_TYPE_P(((const pm_statements_node_t *) body_node)->body.nodes[0], PM_IF_NODE)) {
- rb_bug("mandatory_only?: not in method definition with plain statements");
- return COMPILE_NG;
- }
-
- const pm_if_node_t *if_node = (const pm_if_node_t *) ((const pm_statements_node_t *) body_node)->body.nodes[0];
- if (if_node->predicate != ((const pm_node_t *) call_node)) {
- rb_bug("mandatory_only?: can't find mandatory node");
- return COMPILE_NG;
- }
-
- pm_parameters_node_t parameters = {
- .base = parameters_node->base,
- .requireds = parameters_node->requireds
- };
-
- const pm_def_node_t def = {
- .base = def_node->base,
- .name = def_node->name,
- .receiver = def_node->receiver,
- .parameters = &parameters,
- .body = (pm_node_t *) if_node->statements,
- .locals = {
- .ids = def_node->locals.ids,
- .size = parameters_node->requireds.size,
- .capacity = def_node->locals.capacity
- }
- };
-
- pm_scope_node_t next_scope_node;
- pm_scope_node_init(&def.base, &next_scope_node, scope_node);
-
- ISEQ_BODY(iseq)->mandatory_only_iseq = pm_iseq_new_with_opt(
- &next_scope_node,
- rb_iseq_base_label(iseq),
- rb_iseq_path(iseq),
- rb_iseq_realpath(iseq),
- node_location->line,
- NULL,
- 0,
- ISEQ_TYPE_METHOD,
- ISEQ_COMPILE_DATA(iseq)->option
- );
-
- pm_scope_node_destroy(&next_scope_node);
- return COMPILE_OK;
-}
-
-static int
-pm_compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, const pm_call_node_t *call_node, const pm_node_location_t *node_location, int popped, const rb_iseq_t *parent_block, const char *builtin_func)
-{
- const pm_arguments_node_t *arguments = call_node->arguments;
-
- if (parent_block != NULL) {
- COMPILE_ERROR(iseq, node_location->line, "should not call builtins here.");
- return COMPILE_NG;
- }
-
-#define BUILTIN_INLINE_PREFIX "_bi"
- char inline_func[sizeof(BUILTIN_INLINE_PREFIX) + DECIMAL_SIZE_OF(int)];
- bool cconst = false;
-retry:;
- const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
-
- if (bf == NULL) {
- if (strcmp("cstmt!", builtin_func) == 0 || strcmp("cexpr!", builtin_func) == 0) {
- // ok
- }
- else if (strcmp("cconst!", builtin_func) == 0) {
- cconst = true;
- }
- else if (strcmp("cinit!", builtin_func) == 0) {
- // ignore
- return COMPILE_OK;
- }
- else if (strcmp("attr!", builtin_func) == 0) {
- return pm_compile_builtin_attr(iseq, scope_node, arguments, node_location);
- }
- else if (strcmp("arg!", builtin_func) == 0) {
- return pm_compile_builtin_arg(iseq, ret, scope_node, arguments, node_location, popped);
- }
- else if (strcmp("mandatory_only?", builtin_func) == 0) {
- if (popped) {
- rb_bug("mandatory_only? should be in if condition");
- }
- else if (!LIST_INSN_SIZE_ZERO(ret)) {
- rb_bug("mandatory_only? should be put on top");
- }
-
- PUSH_INSN1(ret, *node_location, putobject, Qfalse);
- return pm_compile_builtin_mandatory_only_method(iseq, scope_node, call_node, node_location);
- }
- else if (1) {
- rb_bug("can't find builtin function:%s", builtin_func);
- }
- else {
- COMPILE_ERROR(iseq, node_location->line, "can't find builtin function:%s", builtin_func);
- return COMPILE_NG;
- }
-
- int inline_index = node_location->line;
- snprintf(inline_func, sizeof(inline_func), BUILTIN_INLINE_PREFIX "%d", inline_index);
- builtin_func = inline_func;
- arguments = NULL;
- goto retry;
- }
-
- if (cconst) {
- typedef VALUE(*builtin_func0)(void *, VALUE);
- VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil);
- PUSH_INSN1(ret, *node_location, putobject, const_val);
- return COMPILE_OK;
- }
-
- // fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
-
- DECL_ANCHOR(args_seq);
- INIT_ANCHOR(args_seq);
-
- int flags = 0;
- struct rb_callinfo_kwarg *keywords = NULL;
- int argc = pm_setup_args(arguments, call_node->block, &flags, &keywords, iseq, args_seq, scope_node, node_location);
-
- if (argc != bf->argc) {
- COMPILE_ERROR(iseq, node_location->line, "argc is not match for builtin function:%s (expect %d but %d)", builtin_func, bf->argc, argc);
- return COMPILE_NG;
- }
-
- unsigned int start_index;
- if (delegate_call_p(iseq, argc, args_seq, &start_index)) {
- PUSH_INSN2(ret, *node_location, opt_invokebuiltin_delegate, bf, INT2FIX(start_index));
- }
- else {
- PUSH_SEQ(ret, args_seq);
- PUSH_INSN1(ret, *node_location, invokebuiltin, bf);
- }
-
- if (popped) PUSH_INSN(ret, *node_location, pop);
- return COMPILE_OK;
-}
-
-/**
- * Compile a call node into the given iseq.
- */
-static void
-pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, ID method_id, LABEL *start)
-{
- const pm_location_t *message_loc = &call_node->message_loc;
- if (message_loc->start == NULL) message_loc = &call_node->base.location;
-
- const pm_node_location_t location = PM_LOCATION_START_LOCATION(scope_node->parser, message_loc, call_node->base.node_id);
- LABEL *else_label = NEW_LABEL(location.line);
- LABEL *end_label = NEW_LABEL(location.line);
- LABEL *retry_end_l = NEW_LABEL(location.line);
-
- VALUE branches = Qfalse;
- rb_code_location_t code_location = { 0 };
- int node_id = location.node_id;
-
- if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- if (PM_BRANCH_COVERAGE_P(iseq)) {
- const uint8_t *cursors[3] = {
- call_node->closing_loc.end,
- call_node->arguments == NULL ? NULL : call_node->arguments->base.location.end,
- call_node->message_loc.end
- };
-
- const uint8_t *end_cursor = cursors[0];
- end_cursor = (end_cursor == NULL || cursors[1] == NULL) ? cursors[1] : (end_cursor > cursors[1] ? end_cursor : cursors[1]);
- end_cursor = (end_cursor == NULL || cursors[2] == NULL) ? cursors[2] : (end_cursor > cursors[2] ? end_cursor : cursors[2]);
-
- const pm_line_column_t start_location = PM_NODE_START_LINE_COLUMN(scope_node->parser, call_node);
- const pm_line_column_t end_location = pm_newline_list_line_column(&scope_node->parser->newline_list, end_cursor, scope_node->parser->start_line);
-
- code_location = (rb_code_location_t) {
- .beg_pos = { .lineno = start_location.line, .column = start_location.column },
- .end_pos = { .lineno = end_location.line, .column = end_location.column }
- };
-
- branches = decl_branch_base(iseq, PTR2NUM(call_node), &code_location, "&.");
- }
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSNL(ret, location, branchnil, else_label);
-
- add_trace_branch_coverage(iseq, ret, &code_location, node_id, 0, "then", branches);
- }
-
- int flags = 0;
- struct rb_callinfo_kwarg *kw_arg = NULL;
-
- int orig_argc = pm_setup_args(call_node->arguments, call_node->block, &flags, &kw_arg, iseq, ret, scope_node, &location);
- const rb_iseq_t *previous_block = ISEQ_COMPILE_DATA(iseq)->current_block;
- const rb_iseq_t *block_iseq = NULL;
-
- if (call_node->block != NULL && PM_NODE_TYPE_P(call_node->block, PM_BLOCK_NODE)) {
- // Scope associated with the block
- pm_scope_node_t next_scope_node;
- pm_scope_node_init(call_node->block, &next_scope_node, scope_node);
-
- block_iseq = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, pm_node_line_number(scope_node->parser, call_node->block));
- pm_scope_node_destroy(&next_scope_node);
- ISEQ_COMPILE_DATA(iseq)->current_block = block_iseq;
- }
- else {
- if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
- flags |= VM_CALL_VCALL;
- }
-
- if (!flags) {
- flags |= VM_CALL_ARGS_SIMPLE;
- }
- }
-
- if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) {
- flags |= VM_CALL_FCALL;
- }
-
- if (!popped && PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE)) {
- if (flags & VM_CALL_ARGS_BLOCKARG) {
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- if (flags & VM_CALL_ARGS_SPLAT) {
- PUSH_INSN1(ret, location, putobject, INT2FIX(-1));
- PUSH_SEND_WITH_FLAG(ret, location, idAREF, INT2FIX(1), INT2FIX(0));
- }
- PUSH_INSN1(ret, location, setn, INT2FIX(orig_argc + 3));
- PUSH_INSN(ret, location, pop);
- }
- else if (flags & VM_CALL_ARGS_SPLAT) {
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putobject, INT2FIX(-1));
- PUSH_SEND_WITH_FLAG(ret, location, idAREF, INT2FIX(1), INT2FIX(0));
- PUSH_INSN1(ret, location, setn, INT2FIX(orig_argc + 2));
- PUSH_INSN(ret, location, pop);
- }
- else {
- PUSH_INSN1(ret, location, setn, INT2FIX(orig_argc + 1));
- }
- }
-
- if ((flags & VM_CALL_KW_SPLAT) && (flags & VM_CALL_ARGS_BLOCKARG) && !(flags & VM_CALL_KW_SPLAT_MUT)) {
- PUSH_INSN(ret, location, splatkw);
- }
-
- PUSH_SEND_R(ret, location, method_id, INT2FIX(orig_argc), block_iseq, INT2FIX(flags), kw_arg);
-
- if (block_iseq && ISEQ_BODY(block_iseq)->catch_table) {
- pm_compile_retry_end_label(iseq, ret, retry_end_l);
- PUSH_CATCH_ENTRY(CATCH_TYPE_BREAK, start, retry_end_l, block_iseq, retry_end_l);
- }
-
- if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- PUSH_INSNL(ret, location, jump, end_label);
- PUSH_LABEL(ret, else_label);
- add_trace_branch_coverage(iseq, ret, &code_location, node_id, 1, "else", branches);
- PUSH_LABEL(ret, end_label);
- }
-
- if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) && !popped) {
- PUSH_INSN(ret, location, pop);
- }
-
- if (popped) PUSH_INSN(ret, location, pop);
- ISEQ_COMPILE_DATA(iseq)->current_block = previous_block;
-}
-
-static void
-pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, bool in_condition, LABEL **lfinish, bool explicit_receiver)
-{
- // in_condition is the same as compile.c's needstr
- enum defined_type dtype = DEFINED_NOT_DEFINED;
- const pm_node_location_t location = *node_location;
-
- switch (PM_NODE_TYPE(node)) {
- case PM_ARGUMENTS_NODE: {
- const pm_arguments_node_t *cast = (const pm_arguments_node_t *) node;
- const pm_node_list_t *arguments = &cast->arguments;
- for (size_t idx = 0; idx < arguments->size; idx++) {
- const pm_node_t *argument = arguments->nodes[idx];
- pm_compile_defined_expr0(iseq, argument, node_location, ret, popped, scope_node, in_condition, lfinish, explicit_receiver);
-
- if (!lfinish[1]) {
- lfinish[1] = NEW_LABEL(location.line);
- }
- PUSH_INSNL(ret, location, branchunless, lfinish[1]);
- }
- dtype = DEFINED_TRUE;
- break;
- }
- case PM_NIL_NODE:
- dtype = DEFINED_NIL;
- break;
- case PM_PARENTHESES_NODE: {
- const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
-
- if (cast->body == NULL) {
- // If we have empty parentheses, then we want to return "nil".
- dtype = DEFINED_NIL;
- }
- else if (PM_NODE_TYPE_P(cast->body, PM_STATEMENTS_NODE) && ((const pm_statements_node_t *) cast->body)->body.size == 1) {
- // If we have a parentheses node that is wrapping a single statement
- // then we want to recurse down to that statement and compile it.
- pm_compile_defined_expr0(iseq, ((const pm_statements_node_t *) cast->body)->body.nodes[0], node_location, ret, popped, scope_node, in_condition, lfinish, explicit_receiver);
- return;
- }
- else {
- // Otherwise, we have parentheses wrapping multiple statements, in
- // which case this is defined as "expression".
- dtype = DEFINED_EXPR;
- }
-
- break;
- }
- case PM_SELF_NODE:
- dtype = DEFINED_SELF;
- break;
- case PM_TRUE_NODE:
- dtype = DEFINED_TRUE;
- break;
- case PM_FALSE_NODE:
- dtype = DEFINED_FALSE;
- break;
- case PM_ARRAY_NODE: {
- const pm_array_node_t *cast = (const pm_array_node_t *) node;
-
- if (cast->elements.size > 0 && !lfinish[1]) {
- lfinish[1] = NEW_LABEL(location.line);
- }
-
- for (size_t index = 0; index < cast->elements.size; index++) {
- pm_compile_defined_expr0(iseq, cast->elements.nodes[index], node_location, ret, popped, scope_node, true, lfinish, false);
- PUSH_INSNL(ret, location, branchunless, lfinish[1]);
- }
-
- dtype = DEFINED_EXPR;
- break;
- }
- case PM_HASH_NODE:
- case PM_KEYWORD_HASH_NODE: {
- const pm_node_list_t *elements;
-
- if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
- elements = &((const pm_hash_node_t *) node)->elements;
- }
- else {
- elements = &((const pm_keyword_hash_node_t *) node)->elements;
- }
-
- if (elements->size > 0 && !lfinish[1]) {
- lfinish[1] = NEW_LABEL(location.line);
- }
-
- for (size_t index = 0; index < elements->size; index++) {
- const pm_node_t *element = elements->nodes[index];
-
- switch (PM_NODE_TYPE(element)) {
- case PM_ASSOC_NODE: {
- const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) element;
-
- pm_compile_defined_expr0(iseq, assoc->key, node_location, ret, popped, scope_node, true, lfinish, false);
- PUSH_INSNL(ret, location, branchunless, lfinish[1]);
-
- pm_compile_defined_expr0(iseq, assoc->value, node_location, ret, popped, scope_node, true, lfinish, false);
- PUSH_INSNL(ret, location, branchunless, lfinish[1]);
-
- break;
- }
- case PM_ASSOC_SPLAT_NODE: {
- const pm_assoc_splat_node_t *assoc_splat = (const pm_assoc_splat_node_t *) element;
-
- pm_compile_defined_expr0(iseq, assoc_splat->value, node_location, ret, popped, scope_node, true, lfinish, false);
- PUSH_INSNL(ret, location, branchunless, lfinish[1]);
-
- break;
- }
- default:
- rb_bug("unexpected node type in hash node: %s", pm_node_type_to_str(PM_NODE_TYPE(element)));
- break;
- }
- }
-
- dtype = DEFINED_EXPR;
- break;
- }
- case PM_SPLAT_NODE: {
- const pm_splat_node_t *cast = (const pm_splat_node_t *) node;
- pm_compile_defined_expr0(iseq, cast->expression, node_location, ret, popped, scope_node, in_condition, lfinish, false);
-
- if (!lfinish[1]) {
- lfinish[1] = NEW_LABEL(location.line);
- }
-
- PUSH_INSNL(ret, location, branchunless, lfinish[1]);
- dtype = DEFINED_EXPR;
- break;
- }
- case PM_IMPLICIT_NODE: {
- const pm_implicit_node_t *cast = (const pm_implicit_node_t *) node;
- pm_compile_defined_expr0(iseq, cast->value, node_location, ret, popped, scope_node, in_condition, lfinish, explicit_receiver);
- return;
- }
- case PM_AND_NODE:
- case PM_BEGIN_NODE:
- case PM_BREAK_NODE:
- case PM_CASE_NODE:
- case PM_CASE_MATCH_NODE:
- case PM_CLASS_NODE:
- case PM_DEF_NODE:
- case PM_DEFINED_NODE:
- case PM_FLOAT_NODE:
- case PM_FOR_NODE:
- case PM_IF_NODE:
- case PM_IMAGINARY_NODE:
- case PM_INTEGER_NODE:
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
- case PM_INTERPOLATED_STRING_NODE:
- case PM_INTERPOLATED_SYMBOL_NODE:
- case PM_INTERPOLATED_X_STRING_NODE:
- case PM_LAMBDA_NODE:
- case PM_MATCH_PREDICATE_NODE:
- case PM_MATCH_REQUIRED_NODE:
- case PM_MATCH_WRITE_NODE:
- case PM_MODULE_NODE:
- case PM_NEXT_NODE:
- case PM_OR_NODE:
- case PM_RANGE_NODE:
- case PM_RATIONAL_NODE:
- case PM_REDO_NODE:
- case PM_REGULAR_EXPRESSION_NODE:
- case PM_RETRY_NODE:
- case PM_RETURN_NODE:
- case PM_SINGLETON_CLASS_NODE:
- case PM_SOURCE_ENCODING_NODE:
- case PM_SOURCE_FILE_NODE:
- case PM_SOURCE_LINE_NODE:
- case PM_STRING_NODE:
- case PM_SYMBOL_NODE:
- case PM_UNLESS_NODE:
- case PM_UNTIL_NODE:
- case PM_WHILE_NODE:
- case PM_X_STRING_NODE:
- dtype = DEFINED_EXPR;
- break;
- case PM_LOCAL_VARIABLE_READ_NODE:
- dtype = DEFINED_LVAR;
- break;
-
-#define PUSH_VAL(type) (in_condition ? Qtrue : rb_iseq_defined_string(type))
-
- case PM_INSTANCE_VARIABLE_READ_NODE: {
- const pm_instance_variable_read_node_t *cast = (const pm_instance_variable_read_node_t *) node;
-
- ID name = pm_constant_id_lookup(scope_node, cast->name);
- PUSH_INSN3(ret, location, definedivar, ID2SYM(name), get_ivar_ic_value(iseq, name), PUSH_VAL(DEFINED_IVAR));
-
- return;
- }
- case PM_BACK_REFERENCE_READ_NODE: {
- const char *char_ptr = (const char *) (node->location.start + 1);
- ID backref_val = INT2FIX(rb_intern2(char_ptr, 1)) << 1 | 1;
-
- PUSH_INSN(ret, location, putnil);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_REF), backref_val, PUSH_VAL(DEFINED_GVAR));
-
- return;
- }
- case PM_NUMBERED_REFERENCE_READ_NODE: {
- uint32_t reference_number = ((const pm_numbered_reference_read_node_t *) node)->number;
-
- PUSH_INSN(ret, location, putnil);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_REF), INT2FIX(reference_number << 1), PUSH_VAL(DEFINED_GVAR));
-
- return;
- }
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- const pm_global_variable_read_node_t *cast = (const pm_global_variable_read_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
-
- PUSH_INSN(ret, location, putnil);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_GVAR), name, PUSH_VAL(DEFINED_GVAR));
-
- return;
- }
- case PM_CLASS_VARIABLE_READ_NODE: {
- const pm_class_variable_read_node_t *cast = (const pm_class_variable_read_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
-
- PUSH_INSN(ret, location, putnil);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_CVAR), name, PUSH_VAL(DEFINED_CVAR));
-
- return;
- }
- case PM_CONSTANT_READ_NODE: {
- const pm_constant_read_node_t *cast = (const pm_constant_read_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
-
- PUSH_INSN(ret, location, putnil);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_CONST), name, PUSH_VAL(DEFINED_CONST));
-
- return;
- }
- case PM_CONSTANT_PATH_NODE: {
- const pm_constant_path_node_t *cast = (const pm_constant_path_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
-
- if (cast->parent != NULL) {
- if (!lfinish[1]) lfinish[1] = NEW_LABEL(location.line);
- pm_compile_defined_expr0(iseq, cast->parent, node_location, ret, popped, scope_node, true, lfinish, false);
-
- PUSH_INSNL(ret, location, branchunless, lfinish[1]);
- PM_COMPILE(cast->parent);
- }
- else {
- PUSH_INSN1(ret, location, putobject, rb_cObject);
- }
-
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_CONST_FROM), name, PUSH_VAL(DEFINED_CONST));
- return;
- }
- case PM_CALL_NODE: {
- const pm_call_node_t *cast = ((const pm_call_node_t *) node);
-
- if (cast->block != NULL && PM_NODE_TYPE_P(cast->block, PM_BLOCK_NODE)) {
- dtype = DEFINED_EXPR;
- break;
- }
-
- ID method_id = pm_constant_id_lookup(scope_node, cast->name);
-
- if (cast->receiver || cast->arguments) {
- if (!lfinish[1]) lfinish[1] = NEW_LABEL(location.line);
- if (!lfinish[2]) lfinish[2] = NEW_LABEL(location.line);
- }
-
- if (cast->arguments) {
- pm_compile_defined_expr0(iseq, (const pm_node_t *) cast->arguments, node_location, ret, popped, scope_node, true, lfinish, false);
- PUSH_INSNL(ret, location, branchunless, lfinish[1]);
- }
-
- if (cast->receiver) {
- pm_compile_defined_expr0(iseq, cast->receiver, node_location, ret, popped, scope_node, true, lfinish, true);
-
- if (PM_NODE_TYPE_P(cast->receiver, PM_CALL_NODE)) {
- PUSH_INSNL(ret, location, branchunless, lfinish[2]);
-
- const pm_call_node_t *receiver = (const pm_call_node_t *) cast->receiver;
- ID method_id = pm_constant_id_lookup(scope_node, receiver->name);
- pm_compile_call(iseq, receiver, ret, popped, scope_node, method_id, NULL);
- }
- else {
- PUSH_INSNL(ret, location, branchunless, lfinish[1]);
- PM_COMPILE(cast->receiver);
- }
-
- if (explicit_receiver) PUSH_INSN(ret, location, dup);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_METHOD), rb_id2sym(method_id), PUSH_VAL(DEFINED_METHOD));
- }
- else {
- PUSH_INSN(ret, location, putself);
- if (explicit_receiver) PUSH_INSN(ret, location, dup);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_FUNC), rb_id2sym(method_id), PUSH_VAL(DEFINED_METHOD));
- }
-
- return;
- }
- case PM_YIELD_NODE:
- PUSH_INSN(ret, location, putnil);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_YIELD), 0, PUSH_VAL(DEFINED_YIELD));
- iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
- return;
- case PM_SUPER_NODE:
- case PM_FORWARDING_SUPER_NODE:
- PUSH_INSN(ret, location, putnil);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_ZSUPER), 0, PUSH_VAL(DEFINED_ZSUPER));
- return;
- case PM_CALL_AND_WRITE_NODE:
- case PM_CALL_OPERATOR_WRITE_NODE:
- case PM_CALL_OR_WRITE_NODE:
-
- case PM_CONSTANT_WRITE_NODE:
- case PM_CONSTANT_OPERATOR_WRITE_NODE:
- case PM_CONSTANT_AND_WRITE_NODE:
- case PM_CONSTANT_OR_WRITE_NODE:
-
- case PM_CONSTANT_PATH_AND_WRITE_NODE:
- case PM_CONSTANT_PATH_OPERATOR_WRITE_NODE:
- case PM_CONSTANT_PATH_OR_WRITE_NODE:
- case PM_CONSTANT_PATH_WRITE_NODE:
-
- case PM_GLOBAL_VARIABLE_WRITE_NODE:
- case PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE:
- case PM_GLOBAL_VARIABLE_AND_WRITE_NODE:
- case PM_GLOBAL_VARIABLE_OR_WRITE_NODE:
-
- case PM_CLASS_VARIABLE_WRITE_NODE:
- case PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE:
- case PM_CLASS_VARIABLE_AND_WRITE_NODE:
- case PM_CLASS_VARIABLE_OR_WRITE_NODE:
-
- case PM_INDEX_AND_WRITE_NODE:
- case PM_INDEX_OPERATOR_WRITE_NODE:
- case PM_INDEX_OR_WRITE_NODE:
-
- case PM_INSTANCE_VARIABLE_WRITE_NODE:
- case PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE:
- case PM_INSTANCE_VARIABLE_AND_WRITE_NODE:
- case PM_INSTANCE_VARIABLE_OR_WRITE_NODE:
-
- case PM_LOCAL_VARIABLE_WRITE_NODE:
- case PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE:
- case PM_LOCAL_VARIABLE_AND_WRITE_NODE:
- case PM_LOCAL_VARIABLE_OR_WRITE_NODE:
-
- case PM_MULTI_WRITE_NODE:
- dtype = DEFINED_ASGN;
- break;
- default:
- rb_bug("Unsupported node %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
- }
-
- RUBY_ASSERT(dtype != DEFINED_NOT_DEFINED);
- PUSH_INSN1(ret, location, putobject, PUSH_VAL(dtype));
-#undef PUSH_VAL
-}
-
-static void
-pm_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, bool in_condition, LABEL **lfinish, bool explicit_receiver)
-{
- LINK_ELEMENT *lcur = ret->last;
- pm_compile_defined_expr0(iseq, node, node_location, ret, popped, scope_node, in_condition, lfinish, false);
-
- if (lfinish[1]) {
- LABEL *lstart = NEW_LABEL(node_location->line);
- LABEL *lend = NEW_LABEL(node_location->line);
-
- struct rb_iseq_new_with_callback_callback_func *ifunc =
- rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
-
- const rb_iseq_t *rescue = new_child_iseq_with_callback(
- iseq,
- ifunc,
- rb_str_concat(rb_str_new2("defined guard in "), ISEQ_BODY(iseq)->location.label),
- iseq,
- ISEQ_TYPE_RESCUE,
- 0
- );
-
- lstart->rescued = LABEL_RESCUE_BEG;
- lend->rescued = LABEL_RESCUE_END;
-
- APPEND_LABEL(ret, lcur, lstart);
- PUSH_LABEL(ret, lend);
- PUSH_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
- }
-}
-
-static void
-pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node, bool in_condition)
-{
- LABEL *lfinish[3];
- LINK_ELEMENT *last = ret->last;
-
- lfinish[0] = NEW_LABEL(node_location->line);
- lfinish[1] = 0;
- lfinish[2] = 0;
-
- if (!popped) {
- pm_defined_expr(iseq, node, node_location, ret, popped, scope_node, in_condition, lfinish, false);
- }
-
- if (lfinish[1]) {
- ELEM_INSERT_NEXT(last, &new_insn_body(iseq, node_location->line, node_location->node_id, BIN(putnil), 0)->link);
- PUSH_INSN(ret, *node_location, swap);
-
- if (lfinish[2]) PUSH_LABEL(ret, lfinish[2]);
- PUSH_INSN(ret, *node_location, pop);
- PUSH_LABEL(ret, lfinish[1]);
-
- }
-
- PUSH_LABEL(ret, lfinish[0]);
-}
-
-// This is exactly the same as add_ensure_iseq, except it compiled
-// the node as a Prism node, and not a CRuby node
-static void
-pm_add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return, pm_scope_node_t *scope_node)
-{
- RUBY_ASSERT(can_add_ensure_iseq(iseq));
-
- struct iseq_compile_data_ensure_node_stack *enlp =
- ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
- struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
- DECL_ANCHOR(ensure);
-
- INIT_ANCHOR(ensure);
- while (enlp) {
- if (enlp->erange != NULL) {
- DECL_ANCHOR(ensure_part);
- LABEL *lstart = NEW_LABEL(0);
- LABEL *lend = NEW_LABEL(0);
- INIT_ANCHOR(ensure_part);
-
- add_ensure_range(iseq, enlp->erange, lstart, lend);
-
- ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
- PUSH_LABEL(ensure_part, lstart);
- bool popped = true;
- PM_COMPILE_INTO_ANCHOR(ensure_part, (const pm_node_t *) enlp->ensure_node);
- PUSH_LABEL(ensure_part, lend);
- PUSH_SEQ(ensure, ensure_part);
- }
- else {
- if (!is_return) {
- break;
- }
- }
- enlp = enlp->prev;
- }
- ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
- PUSH_SEQ(ret, ensure);
-}
-
-struct pm_local_table_insert_ctx {
- pm_scope_node_t *scope_node;
- rb_ast_id_table_t *local_table_for_iseq;
- int local_index;
-};
-
-static int
-pm_local_table_insert_func(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
-{
- if (!existing) {
- pm_constant_id_t constant_id = (pm_constant_id_t) *key;
- struct pm_local_table_insert_ctx * ctx = (struct pm_local_table_insert_ctx *) arg;
-
- pm_scope_node_t *scope_node = ctx->scope_node;
- rb_ast_id_table_t *local_table_for_iseq = ctx->local_table_for_iseq;
- int local_index = ctx->local_index;
-
- ID local = pm_constant_id_lookup(scope_node, constant_id);
- local_table_for_iseq->ids[local_index] = local;
-
- *value = (st_data_t)local_index;
-
- ctx->local_index++;
- }
-
- return ST_CONTINUE;
-}
-
-/**
- * Insert a local into the local table for the iseq. This is used to create the
- * local table in the correct order while compiling the scope. The locals being
- * inserted are regular named locals, as opposed to special forwarding locals.
- */
-static void
-pm_insert_local_index(pm_constant_id_t constant_id, int local_index, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node)
-{
- RUBY_ASSERT((constant_id & PM_SPECIAL_CONSTANT_FLAG) == 0);
-
- ID local = pm_constant_id_lookup(scope_node, constant_id);
- local_table_for_iseq->ids[local_index] = local;
- st_insert(index_lookup_table, (st_data_t) constant_id, (st_data_t) local_index);
-}
-
-/**
- * Insert a local into the local table for the iseq that is a special forwarding
- * local variable.
- */
-static void
-pm_insert_local_special(ID local_name, int local_index, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq)
-{
- local_table_for_iseq->ids[local_index] = local_name;
- st_insert(index_lookup_table, (st_data_t) (local_name | PM_SPECIAL_CONSTANT_FLAG), (st_data_t) local_index);
-}
-
-/**
- * Compile the locals of a multi target node that is used as a positional
- * parameter in a method, block, or lambda definition. Note that this doesn't
- * actually add any instructions to the iseq. Instead, it adds locals to the
- * local and index lookup tables and increments the local index as necessary.
- */
-static int
-pm_compile_destructured_param_locals(const pm_multi_target_node_t *node, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node, int local_index)
-{
- for (size_t index = 0; index < node->lefts.size; index++) {
- const pm_node_t *left = node->lefts.nodes[index];
-
- if (PM_NODE_TYPE_P(left, PM_REQUIRED_PARAMETER_NODE)) {
- if (!PM_NODE_FLAG_P(left, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- pm_insert_local_index(((const pm_required_parameter_node_t *) left)->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- local_index++;
- }
- }
- else {
- RUBY_ASSERT(PM_NODE_TYPE_P(left, PM_MULTI_TARGET_NODE));
- local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) left, index_lookup_table, local_table_for_iseq, scope_node, local_index);
- }
- }
-
- if (node->rest != NULL && PM_NODE_TYPE_P(node->rest, PM_SPLAT_NODE)) {
- const pm_splat_node_t *rest = (const pm_splat_node_t *) node->rest;
-
- if (rest->expression != NULL) {
- RUBY_ASSERT(PM_NODE_TYPE_P(rest->expression, PM_REQUIRED_PARAMETER_NODE));
-
- if (!PM_NODE_FLAG_P(rest->expression, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- pm_insert_local_index(((const pm_required_parameter_node_t *) rest->expression)->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- local_index++;
- }
- }
- }
-
- for (size_t index = 0; index < node->rights.size; index++) {
- const pm_node_t *right = node->rights.nodes[index];
-
- if (PM_NODE_TYPE_P(right, PM_REQUIRED_PARAMETER_NODE)) {
- if (!PM_NODE_FLAG_P(right, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- pm_insert_local_index(((const pm_required_parameter_node_t *) right)->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- local_index++;
- }
- }
- else {
- RUBY_ASSERT(PM_NODE_TYPE_P(right, PM_MULTI_TARGET_NODE));
- local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) right, index_lookup_table, local_table_for_iseq, scope_node, local_index);
- }
- }
-
- return local_index;
-}
-
-/**
- * Compile a required parameter node that is part of a destructure that is used
- * as a positional parameter in a method, block, or lambda definition.
- */
-static inline void
-pm_compile_destructured_param_write(rb_iseq_t *iseq, const pm_required_parameter_node_t *node, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
- pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, node->name, 0);
- PUSH_SETLOCAL(ret, location, index.index, index.level);
-}
-
-/**
- * Compile a multi target node that is used as a positional parameter in a
- * method, block, or lambda definition. Note that this is effectively the same
- * as a multi write, but with the added context that all of the targets
- * contained in the write are required parameter nodes. With this context, we
- * know they won't have any parent expressions so we build a separate code path
- * for this simplified case.
- */
-static void
-pm_compile_destructured_param_writes(rb_iseq_t *iseq, const pm_multi_target_node_t *node, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
- bool has_rest = (node->rest && PM_NODE_TYPE_P(node->rest, PM_SPLAT_NODE) && (((const pm_splat_node_t *) node->rest)->expression) != NULL);
- bool has_rights = node->rights.size > 0;
-
- int flag = (has_rest || has_rights) ? 1 : 0;
- PUSH_INSN2(ret, location, expandarray, INT2FIX(node->lefts.size), INT2FIX(flag));
-
- for (size_t index = 0; index < node->lefts.size; index++) {
- const pm_node_t *left = node->lefts.nodes[index];
-
- if (PM_NODE_TYPE_P(left, PM_REQUIRED_PARAMETER_NODE)) {
- pm_compile_destructured_param_write(iseq, (const pm_required_parameter_node_t *) left, ret, scope_node);
- }
- else {
- RUBY_ASSERT(PM_NODE_TYPE_P(left, PM_MULTI_TARGET_NODE));
- pm_compile_destructured_param_writes(iseq, (const pm_multi_target_node_t *) left, ret, scope_node);
- }
- }
-
- if (has_rest) {
- if (has_rights) {
- PUSH_INSN2(ret, location, expandarray, INT2FIX(node->rights.size), INT2FIX(3));
- }
-
- const pm_node_t *rest = ((const pm_splat_node_t *) node->rest)->expression;
- RUBY_ASSERT(PM_NODE_TYPE_P(rest, PM_REQUIRED_PARAMETER_NODE));
-
- pm_compile_destructured_param_write(iseq, (const pm_required_parameter_node_t *) rest, ret, scope_node);
- }
-
- if (has_rights) {
- if (!has_rest) {
- PUSH_INSN2(ret, location, expandarray, INT2FIX(node->rights.size), INT2FIX(2));
- }
-
- for (size_t index = 0; index < node->rights.size; index++) {
- const pm_node_t *right = node->rights.nodes[index];
-
- if (PM_NODE_TYPE_P(right, PM_REQUIRED_PARAMETER_NODE)) {
- pm_compile_destructured_param_write(iseq, (const pm_required_parameter_node_t *) right, ret, scope_node);
- }
- else {
- RUBY_ASSERT(PM_NODE_TYPE_P(right, PM_MULTI_TARGET_NODE));
- pm_compile_destructured_param_writes(iseq, (const pm_multi_target_node_t *) right, ret, scope_node);
- }
- }
- }
-}
-
-/**
- * This is a node in the multi target state linked list. It tracks the
- * information for a particular target that necessarily has a parent expression.
- */
-typedef struct pm_multi_target_state_node {
- // The pointer to the topn instruction that will need to be modified after
- // we know the total stack size of all of the targets.
- INSN *topn;
-
- // The index of the stack from the base of the entire multi target at which
- // the parent expression is located.
- size_t stack_index;
-
- // The number of slots in the stack that this node occupies.
- size_t stack_size;
-
- // The position of the node in the list of targets.
- size_t position;
-
- // A pointer to the next node in this linked list.
- struct pm_multi_target_state_node *next;
-} pm_multi_target_state_node_t;
-
-/**
- * As we're compiling a multi target, we need to track additional information
- * whenever there is a parent expression on the left hand side of the target.
- * This is because we need to go back and tell the expression where to fetch its
- * parent expression from the stack. We use a linked list of nodes to track this
- * information.
- */
-typedef struct {
- // The total number of slots in the stack that this multi target occupies.
- size_t stack_size;
-
- // The position of the current node being compiled. This is forwarded to
- // nodes when they are allocated.
- size_t position;
-
- // A pointer to the head of this linked list.
- pm_multi_target_state_node_t *head;
-
- // A pointer to the tail of this linked list.
- pm_multi_target_state_node_t *tail;
-} pm_multi_target_state_t;
-
-/**
- * Push a new state node onto the multi target state.
- */
-static void
-pm_multi_target_state_push(pm_multi_target_state_t *state, INSN *topn, size_t stack_size)
-{
- pm_multi_target_state_node_t *node = ALLOC(pm_multi_target_state_node_t);
- node->topn = topn;
- node->stack_index = state->stack_size + 1;
- node->stack_size = stack_size;
- node->position = state->position;
- node->next = NULL;
-
- if (state->head == NULL) {
- state->head = node;
- state->tail = node;
- }
- else {
- state->tail->next = node;
- state->tail = node;
- }
-
- state->stack_size += stack_size;
-}
-
-/**
- * Walk through a multi target state's linked list and update the topn
- * instructions that were inserted into the write sequence to make sure they can
- * correctly retrieve their parent expressions.
- */
-static void
-pm_multi_target_state_update(pm_multi_target_state_t *state)
-{
- // If nothing was ever pushed onto the stack, then we don't need to do any
- // kind of updates.
- if (state->stack_size == 0) return;
-
- pm_multi_target_state_node_t *current = state->head;
- pm_multi_target_state_node_t *previous;
-
- while (current != NULL) {
- VALUE offset = INT2FIX(state->stack_size - current->stack_index + current->position);
- current->topn->operands[0] = offset;
-
- // stack_size will be > 1 in the case that we compiled an index target
- // and it had arguments. In this case, we use multiple topn instructions
- // to grab up all of the arguments as well, so those offsets need to be
- // updated as well.
- if (current->stack_size > 1) {
- INSN *insn = current->topn;
-
- for (size_t index = 1; index < current->stack_size; index += 1) {
- LINK_ELEMENT *element = get_next_insn(insn);
- RUBY_ASSERT(IS_INSN(element));
-
- insn = (INSN *) element;
- RUBY_ASSERT(insn->insn_id == BIN(topn));
-
- insn->operands[0] = offset;
- }
- }
-
- previous = current;
- current = current->next;
-
- xfree(previous);
- }
-}
-
-static void
-pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const parents, LINK_ANCHOR *const writes, LINK_ANCHOR *const cleanup, pm_scope_node_t *scope_node, pm_multi_target_state_t *state);
-
-/**
- * A target node represents an indirect write to a variable or a method call to
- * a method ending in =. Compiling one of these nodes requires three sequences:
- *
- * * The first is to compile retrieving the parent expression if there is one.
- * This could be the object that owns a constant or the receiver of a method
- * call.
- * * The second is to compile the writes to the targets. This could be writing
- * to variables, or it could be performing method calls.
- * * The third is to compile any cleanup that needs to happen, i.e., popping the
- * appropriate number of values off the stack.
- *
- * When there is a parent expression and this target is part of a multi write, a
- * topn instruction will be inserted into the write sequence. This is to move
- * the parent expression to the top of the stack so that it can be used as the
- * receiver of the method call or the owner of the constant. To facilitate this,
- * we return a pointer to the topn instruction that was used to be later
- * modified with the correct offset.
- *
- * These nodes can appear in a couple of places, but most commonly:
- *
- * * For loops - the index variable is a target node
- * * Rescue clauses - the exception reference variable is a target node
- * * Multi writes - the left hand side contains a list of target nodes
- *
- * For the comments with examples within this function, we'll use for loops as
- * the containing node.
- */
-static void
-pm_compile_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const parents, LINK_ANCHOR *const writes, LINK_ANCHOR *const cleanup, pm_scope_node_t *scope_node, pm_multi_target_state_t *state)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
-
- switch (PM_NODE_TYPE(node)) {
- case PM_LOCAL_VARIABLE_TARGET_NODE: {
- // Local variable targets have no parent expression, so they only need
- // to compile the write.
- //
- // for i in []; end
- //
- const pm_local_variable_target_node_t *cast = (const pm_local_variable_target_node_t *) node;
- pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, cast->name, cast->depth);
-
- PUSH_SETLOCAL(writes, location, index.index, index.level);
- break;
- }
- case PM_CLASS_VARIABLE_TARGET_NODE: {
- // Class variable targets have no parent expression, so they only need
- // to compile the write.
- //
- // for @@i in []; end
- //
- const pm_class_variable_target_node_t *cast = (const pm_class_variable_target_node_t *) node;
- ID name = pm_constant_id_lookup(scope_node, cast->name);
-
- VALUE operand = ID2SYM(name);
- PUSH_INSN2(writes, location, setclassvariable, operand, get_cvar_ic_value(iseq, name));
- break;
- }
- case PM_CONSTANT_TARGET_NODE: {
- // Constant targets have no parent expression, so they only need to
- // compile the write.
- //
- // for I in []; end
- //
- const pm_constant_target_node_t *cast = (const pm_constant_target_node_t *) node;
- ID name = pm_constant_id_lookup(scope_node, cast->name);
-
- VALUE operand = ID2SYM(name);
- PUSH_INSN1(writes, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- PUSH_INSN1(writes, location, setconstant, operand);
- break;
- }
- case PM_GLOBAL_VARIABLE_TARGET_NODE: {
- // Global variable targets have no parent expression, so they only need
- // to compile the write.
- //
- // for $i in []; end
- //
- const pm_global_variable_target_node_t *cast = (const pm_global_variable_target_node_t *) node;
- ID name = pm_constant_id_lookup(scope_node, cast->name);
-
- VALUE operand = ID2SYM(name);
- PUSH_INSN1(writes, location, setglobal, operand);
- break;
- }
- case PM_INSTANCE_VARIABLE_TARGET_NODE: {
- // Instance variable targets have no parent expression, so they only
- // need to compile the write.
- //
- // for @i in []; end
- //
- const pm_instance_variable_target_node_t *cast = (const pm_instance_variable_target_node_t *) node;
- ID name = pm_constant_id_lookup(scope_node, cast->name);
-
- VALUE operand = ID2SYM(name);
- PUSH_INSN2(writes, location, setinstancevariable, operand, get_ivar_ic_value(iseq, name));
- break;
- }
- case PM_CONSTANT_PATH_TARGET_NODE: {
- // Constant path targets have a parent expression that is the object
- // that owns the constant. This needs to be compiled first into the
- // parents sequence. If no parent is found, then it represents using the
- // unary :: operator to indicate a top-level constant. In that case we
- // need to push Object onto the stack.
- //
- // for I::J in []; end
- //
- const pm_constant_path_target_node_t *cast = (const pm_constant_path_target_node_t *) node;
- ID name = pm_constant_id_lookup(scope_node, cast->name);
-
- if (cast->parent != NULL) {
- pm_compile_node(iseq, cast->parent, parents, false, scope_node);
- }
- else {
- PUSH_INSN1(parents, location, putobject, rb_cObject);
- }
-
- if (state == NULL) {
- PUSH_INSN(writes, location, swap);
- }
- else {
- PUSH_INSN1(writes, location, topn, INT2FIX(1));
- pm_multi_target_state_push(state, (INSN *) LAST_ELEMENT(writes), 1);
- }
-
- VALUE operand = ID2SYM(name);
- PUSH_INSN1(writes, location, setconstant, operand);
-
- if (state != NULL) {
- PUSH_INSN(cleanup, location, pop);
- }
-
- break;
- }
- case PM_CALL_TARGET_NODE: {
- // Call targets have a parent expression that is the receiver of the
- // method being called. This needs to be compiled first into the parents
- // sequence. These nodes cannot have arguments, so the method call is
- // compiled with a single argument which represents the value being
- // written.
- //
- // for i.j in []; end
- //
- const pm_call_target_node_t *cast = (const pm_call_target_node_t *) node;
- ID method_id = pm_constant_id_lookup(scope_node, cast->name);
-
- pm_compile_node(iseq, cast->receiver, parents, false, scope_node);
-
- LABEL *safe_label = NULL;
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- safe_label = NEW_LABEL(location.line);
- PUSH_INSN(parents, location, dup);
- PUSH_INSNL(parents, location, branchnil, safe_label);
- }
-
- if (state != NULL) {
- PUSH_INSN1(writes, location, topn, INT2FIX(1));
- pm_multi_target_state_push(state, (INSN *) LAST_ELEMENT(writes), 1);
- PUSH_INSN(writes, location, swap);
- }
-
- int flags = VM_CALL_ARGS_SIMPLE;
- if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) flags |= VM_CALL_FCALL;
-
- PUSH_SEND_WITH_FLAG(writes, location, method_id, INT2FIX(1), INT2FIX(flags));
- if (safe_label != NULL && state == NULL) PUSH_LABEL(writes, safe_label);
- PUSH_INSN(writes, location, pop);
- if (safe_label != NULL && state != NULL) PUSH_LABEL(writes, safe_label);
-
- if (state != NULL) {
- PUSH_INSN(cleanup, location, pop);
- }
-
- break;
- }
- case PM_INDEX_TARGET_NODE: {
- // Index targets have a parent expression that is the receiver of the
- // method being called and any additional arguments that are being
- // passed along with the value being written. The receiver and arguments
- // both need to be on the stack. Note that this is even more complicated
- // by the fact that these nodes can hold a block using the unary &
- // operator.
- //
- // for i[:j] in []; end
- //
- const pm_index_target_node_t *cast = (const pm_index_target_node_t *) node;
-
- pm_compile_node(iseq, cast->receiver, parents, false, scope_node);
-
- int flags = 0;
- struct rb_callinfo_kwarg *kwargs = NULL;
- int argc = pm_setup_args(cast->arguments, (const pm_node_t *) cast->block, &flags, &kwargs, iseq, parents, scope_node, &location);
-
- if (state != NULL) {
- PUSH_INSN1(writes, location, topn, INT2FIX(argc + 1));
- pm_multi_target_state_push(state, (INSN *) LAST_ELEMENT(writes), argc + 1);
-
- if (argc == 0) {
- PUSH_INSN(writes, location, swap);
- }
- else {
- for (int index = 0; index < argc; index++) {
- PUSH_INSN1(writes, location, topn, INT2FIX(argc + 1));
- }
- PUSH_INSN1(writes, location, topn, INT2FIX(argc + 1));
- }
- }
-
- // The argc that we're going to pass to the send instruction is the
- // number of arguments + 1 for the value being written. If there's a
- // splat, then we need to insert newarray and concatarray instructions
- // after the arguments have been written.
- int ci_argc = argc + 1;
- if (flags & VM_CALL_ARGS_SPLAT) {
- ci_argc--;
- PUSH_INSN1(writes, location, newarray, INT2FIX(1));
- PUSH_INSN(writes, location, concatarray);
- }
-
- PUSH_SEND_R(writes, location, idASET, INT2NUM(ci_argc), NULL, INT2FIX(flags), kwargs);
- PUSH_INSN(writes, location, pop);
-
- if (state != NULL) {
- if (argc != 0) {
- PUSH_INSN(writes, location, pop);
- }
-
- for (int index = 0; index < argc + 1; index++) {
- PUSH_INSN(cleanup, location, pop);
- }
- }
-
- break;
- }
- case PM_MULTI_TARGET_NODE: {
- // Multi target nodes represent a set of writes to multiple variables.
- // The parent expressions are the combined set of the parent expressions
- // of its inner target nodes.
- //
- // for i, j in []; end
- //
- size_t before_position;
- if (state != NULL) {
- before_position = state->position;
- state->position--;
- }
-
- pm_compile_multi_target_node(iseq, node, parents, writes, cleanup, scope_node, state);
- if (state != NULL) state->position = before_position;
-
- break;
- }
- default:
- rb_bug("Unexpected node type: %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
- break;
- }
-}
-
-/**
- * Compile a multi target or multi write node. It returns the number of values
- * on the stack that correspond to the parent expressions of the various
- * targets.
- */
-static void
-pm_compile_multi_target_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const parents, LINK_ANCHOR *const writes, LINK_ANCHOR *const cleanup, pm_scope_node_t *scope_node, pm_multi_target_state_t *state)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
- const pm_node_list_t *lefts;
- const pm_node_t *rest;
- const pm_node_list_t *rights;
-
- switch (PM_NODE_TYPE(node)) {
- case PM_MULTI_TARGET_NODE: {
- const pm_multi_target_node_t *cast = (const pm_multi_target_node_t *) node;
- lefts = &cast->lefts;
- rest = cast->rest;
- rights = &cast->rights;
- break;
- }
- case PM_MULTI_WRITE_NODE: {
- const pm_multi_write_node_t *cast = (const pm_multi_write_node_t *) node;
- lefts = &cast->lefts;
- rest = cast->rest;
- rights = &cast->rights;
- break;
- }
- default:
- rb_bug("Unsupported node %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
- break;
- }
-
- bool has_rest = (rest != NULL) && PM_NODE_TYPE_P(rest, PM_SPLAT_NODE) && ((const pm_splat_node_t *) rest)->expression != NULL;
- bool has_posts = rights->size > 0;
-
- // The first instruction in the writes sequence is going to spread the
- // top value of the stack onto the number of values that we're going to
- // write.
- PUSH_INSN2(writes, location, expandarray, INT2FIX(lefts->size), INT2FIX((has_rest || has_posts) ? 1 : 0));
-
- // We need to keep track of some additional state information as we're
- // going through the targets because we will need to revisit them once
- // we know how many values are being pushed onto the stack.
- pm_multi_target_state_t target_state = { 0 };
- if (state == NULL) state = &target_state;
-
- size_t base_position = state->position;
- size_t splat_position = (has_rest || has_posts) ? 1 : 0;
-
- // Next, we'll iterate through all of the leading targets.
- for (size_t index = 0; index < lefts->size; index++) {
- const pm_node_t *target = lefts->nodes[index];
- state->position = lefts->size - index + splat_position + base_position;
- pm_compile_target_node(iseq, target, parents, writes, cleanup, scope_node, state);
- }
-
- // Next, we'll compile the rest target if there is one.
- if (has_rest) {
- const pm_node_t *target = ((const pm_splat_node_t *) rest)->expression;
- state->position = 1 + rights->size + base_position;
-
- if (has_posts) {
- PUSH_INSN2(writes, location, expandarray, INT2FIX(rights->size), INT2FIX(3));
- }
-
- pm_compile_target_node(iseq, target, parents, writes, cleanup, scope_node, state);
- }
-
- // Finally, we'll compile the trailing targets.
- if (has_posts) {
- if (!has_rest && rest != NULL) {
- PUSH_INSN2(writes, location, expandarray, INT2FIX(rights->size), INT2FIX(2));
- }
-
- for (size_t index = 0; index < rights->size; index++) {
- const pm_node_t *target = rights->nodes[index];
- state->position = rights->size - index + base_position;
- pm_compile_target_node(iseq, target, parents, writes, cleanup, scope_node, state);
- }
- }
-}
-
-/**
- * When compiling a for loop, we need to write the iteration variable to
- * whatever expression exists in the index slot. This function performs that
- * compilation.
- */
-static void
-pm_compile_for_node_index(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
-
- switch (PM_NODE_TYPE(node)) {
- case PM_LOCAL_VARIABLE_TARGET_NODE: {
- // For local variables, all we have to do is retrieve the value and then
- // compile the index node.
- PUSH_GETLOCAL(ret, location, 1, 0);
- pm_compile_target_node(iseq, node, ret, ret, ret, scope_node, NULL);
- break;
- }
- case PM_CLASS_VARIABLE_TARGET_NODE:
- case PM_CONSTANT_TARGET_NODE:
- case PM_GLOBAL_VARIABLE_TARGET_NODE:
- case PM_INSTANCE_VARIABLE_TARGET_NODE:
- case PM_CONSTANT_PATH_TARGET_NODE:
- case PM_CALL_TARGET_NODE:
- case PM_INDEX_TARGET_NODE: {
- // For other targets, we need to potentially compile the parent or
- // owning expression of this target, then retrieve the value, expand it,
- // and then compile the necessary writes.
- DECL_ANCHOR(writes);
- INIT_ANCHOR(writes);
-
- DECL_ANCHOR(cleanup);
- INIT_ANCHOR(cleanup);
-
- pm_multi_target_state_t state = { 0 };
- state.position = 1;
- pm_compile_target_node(iseq, node, ret, writes, cleanup, scope_node, &state);
-
- PUSH_GETLOCAL(ret, location, 1, 0);
- PUSH_INSN2(ret, location, expandarray, INT2FIX(1), INT2FIX(0));
-
- PUSH_SEQ(ret, writes);
- PUSH_SEQ(ret, cleanup);
-
- pm_multi_target_state_update(&state);
- break;
- }
- case PM_MULTI_TARGET_NODE: {
- DECL_ANCHOR(writes);
- INIT_ANCHOR(writes);
-
- DECL_ANCHOR(cleanup);
- INIT_ANCHOR(cleanup);
-
- pm_compile_target_node(iseq, node, ret, writes, cleanup, scope_node, NULL);
-
- LABEL *not_single = NEW_LABEL(location.line);
- LABEL *not_ary = NEW_LABEL(location.line);
-
- // When there are multiple targets, we'll do a bunch of work to convert
- // the value into an array before we expand it. Effectively we're trying
- // to accomplish:
- //
- // (args.length == 1 && Array.try_convert(args[0])) || args
- //
- PUSH_GETLOCAL(ret, location, 1, 0);
- PUSH_INSN(ret, location, dup);
- PUSH_CALL(ret, location, idLength, INT2FIX(0));
- PUSH_INSN1(ret, location, putobject, INT2FIX(1));
- PUSH_CALL(ret, location, idEq, INT2FIX(1));
- PUSH_INSNL(ret, location, branchunless, not_single);
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putobject, INT2FIX(0));
- PUSH_CALL(ret, location, idAREF, INT2FIX(1));
- PUSH_INSN1(ret, location, putobject, rb_cArray);
- PUSH_INSN(ret, location, swap);
- PUSH_CALL(ret, location, rb_intern("try_convert"), INT2FIX(1));
- PUSH_INSN(ret, location, dup);
- PUSH_INSNL(ret, location, branchunless, not_ary);
- PUSH_INSN(ret, location, swap);
-
- PUSH_LABEL(ret, not_ary);
- PUSH_INSN(ret, location, pop);
-
- PUSH_LABEL(ret, not_single);
- PUSH_SEQ(ret, writes);
- PUSH_SEQ(ret, cleanup);
- break;
- }
- default:
- rb_bug("Unexpected node type for index in for node: %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
- break;
- }
-}
-
-static void
-pm_compile_rescue(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_parser_t *parser = scope_node->parser;
-
- LABEL *lstart = NEW_LABEL(node_location->line);
- LABEL *lend = NEW_LABEL(node_location->line);
- LABEL *lcont = NEW_LABEL(node_location->line);
-
- pm_scope_node_t rescue_scope_node;
- pm_scope_node_init((const pm_node_t *) cast->rescue_clause, &rescue_scope_node, scope_node);
-
- rb_iseq_t *rescue_iseq = NEW_CHILD_ISEQ(
- &rescue_scope_node,
- rb_str_concat(rb_str_new2("rescue in "), ISEQ_BODY(iseq)->location.label),
- ISEQ_TYPE_RESCUE,
- pm_node_line_number(parser, (const pm_node_t *) cast->rescue_clause)
- );
-
- pm_scope_node_destroy(&rescue_scope_node);
-
- lstart->rescued = LABEL_RESCUE_BEG;
- lend->rescued = LABEL_RESCUE_END;
- PUSH_LABEL(ret, lstart);
-
- bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
- ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
-
- if (cast->statements != NULL) {
- PM_COMPILE_NOT_POPPED((const pm_node_t *) cast->statements);
- }
- else {
- const pm_node_location_t location = PM_NODE_START_LOCATION(parser, cast->rescue_clause);
- PUSH_INSN(ret, location, putnil);
- }
-
- ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
- PUSH_LABEL(ret, lend);
-
- if (cast->else_clause != NULL) {
- if (!popped) PUSH_INSN(ret, *node_location, pop);
- PM_COMPILE((const pm_node_t *) cast->else_clause);
- }
-
- PUSH_INSN(ret, *node_location, nop);
- PUSH_LABEL(ret, lcont);
-
- if (popped) PUSH_INSN(ret, *node_location, pop);
- PUSH_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue_iseq, lcont);
- PUSH_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
-}
-
-static void
-pm_compile_ensure(rb_iseq_t *iseq, const pm_begin_node_t *cast, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_parser_t *parser = scope_node->parser;
- const pm_statements_node_t *statements = cast->ensure_clause->statements;
-
- pm_node_location_t location;
- if (statements != NULL) {
- location = PM_NODE_START_LOCATION(parser, statements);
- }
- else {
- location = *node_location;
- }
-
- LABEL *lstart = NEW_LABEL(location.line);
- LABEL *lend = NEW_LABEL(location.line);
- LABEL *lcont = NEW_LABEL(location.line);
-
- struct ensure_range er;
- struct iseq_compile_data_ensure_node_stack enl;
- struct ensure_range *erange;
-
- DECL_ANCHOR(ensr);
- INIT_ANCHOR(ensr);
- if (statements != NULL) {
- pm_compile_node(iseq, (const pm_node_t *) statements, ensr, true, scope_node);
- }
-
- LINK_ELEMENT *last = ensr->last;
- bool last_leave = last && IS_INSN(last) && IS_INSN_ID(last, leave);
-
- er.begin = lstart;
- er.end = lend;
- er.next = 0;
- push_ensure_entry(iseq, &enl, &er, (void *) cast->ensure_clause);
-
- PUSH_LABEL(ret, lstart);
- if (cast->rescue_clause != NULL) {
- pm_compile_rescue(iseq, cast, node_location, ret, popped | last_leave, scope_node);
- }
- else if (cast->statements != NULL) {
- pm_compile_node(iseq, (const pm_node_t *) cast->statements, ret, popped | last_leave, scope_node);
- }
- else if (!(popped | last_leave)) {
- PUSH_SYNTHETIC_PUTNIL(ret, iseq);
- }
-
- PUSH_LABEL(ret, lend);
- PUSH_SEQ(ret, ensr);
- if (!popped && last_leave) PUSH_INSN(ret, *node_location, putnil);
- PUSH_LABEL(ret, lcont);
- if (last_leave) PUSH_INSN(ret, *node_location, pop);
-
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((const pm_node_t *) cast->ensure_clause, &next_scope_node, scope_node);
-
- rb_iseq_t *child_iseq = NEW_CHILD_ISEQ(
- &next_scope_node,
- rb_str_concat(rb_str_new2("ensure in "), ISEQ_BODY(iseq)->location.label),
- ISEQ_TYPE_ENSURE,
- location.line
- );
-
- pm_scope_node_destroy(&next_scope_node);
-
- erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
- if (lstart->link.next != &lend->link) {
- while (erange) {
- PUSH_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end, child_iseq, lcont);
- erange = erange->next;
- }
- }
- ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enl.prev;
-}
-
-/**
- * Returns true if the given call node can use the opt_str_uminus or
- * opt_str_freeze instructions as an optimization with the current iseq options.
- */
-static inline bool
-pm_opt_str_freeze_p(const rb_iseq_t *iseq, const pm_call_node_t *node)
-{
- return (
- !PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) &&
- node->receiver != NULL &&
- PM_NODE_TYPE_P(node->receiver, PM_STRING_NODE) &&
- node->arguments == NULL &&
- node->block == NULL &&
- ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction
- );
-}
-
-/**
- * Returns true if the given call node can use the opt_aref_with optimization
- * with the current iseq options.
- */
-static inline bool
-pm_opt_aref_with_p(const rb_iseq_t *iseq, const pm_call_node_t *node)
-{
- return (
- !PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) &&
- node->arguments != NULL &&
- PM_NODE_TYPE_P((const pm_node_t *) node->arguments, PM_ARGUMENTS_NODE) &&
- ((const pm_arguments_node_t *) node->arguments)->arguments.size == 1 &&
- PM_NODE_TYPE_P(((const pm_arguments_node_t *) node->arguments)->arguments.nodes[0], PM_STRING_NODE) &&
- node->block == NULL &&
- !PM_NODE_FLAG_P(((const pm_arguments_node_t *) node->arguments)->arguments.nodes[0], PM_STRING_FLAGS_FROZEN) &&
- ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction
- );
-}
-
-/**
- * Returns true if the given call node can use the opt_aset_with optimization
- * with the current iseq options.
- */
-static inline bool
-pm_opt_aset_with_p(const rb_iseq_t *iseq, const pm_call_node_t *node)
-{
- return (
- !PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) &&
- node->arguments != NULL &&
- PM_NODE_TYPE_P((const pm_node_t *) node->arguments, PM_ARGUMENTS_NODE) &&
- ((const pm_arguments_node_t *) node->arguments)->arguments.size == 2 &&
- PM_NODE_TYPE_P(((const pm_arguments_node_t *) node->arguments)->arguments.nodes[0], PM_STRING_NODE) &&
- node->block == NULL &&
- !PM_NODE_FLAG_P(((const pm_arguments_node_t *) node->arguments)->arguments.nodes[0], PM_STRING_FLAGS_FROZEN) &&
- ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction
- );
-}
-
-/**
- * Compile the instructions necessary to read a constant, based on the options
- * of the current iseq.
- */
-static void
-pm_compile_constant_read(rb_iseq_t *iseq, VALUE name, const pm_location_t *name_loc, uint32_t node_id, LINK_ANCHOR *const ret, const pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = PM_LOCATION_START_LOCATION(scope_node->parser, name_loc, node_id);
-
- if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
- ISEQ_BODY(iseq)->ic_size++;
- VALUE segments = rb_ary_new_from_args(1, name);
- PUSH_INSN1(ret, location, opt_getconstant_path, segments);
- }
- else {
- PUSH_INSN(ret, location, putnil);
- PUSH_INSN1(ret, location, putobject, Qtrue);
- PUSH_INSN1(ret, location, getconstant, name);
- }
-}
-
-/**
- * Returns a Ruby array of the parts of the constant path node if it is constant
- * reads all of the way down. If it isn't, then Qnil is returned.
- */
-static VALUE
-pm_constant_path_parts(const pm_node_t *node, const pm_scope_node_t *scope_node)
-{
- VALUE parts = rb_ary_new();
-
- while (true) {
- switch (PM_NODE_TYPE(node)) {
- case PM_CONSTANT_READ_NODE: {
- const pm_constant_read_node_t *cast = (const pm_constant_read_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
-
- rb_ary_unshift(parts, name);
- return parts;
- }
- case PM_CONSTANT_PATH_NODE: {
- const pm_constant_path_node_t *cast = (const pm_constant_path_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
-
- rb_ary_unshift(parts, name);
- if (cast->parent == NULL) {
- rb_ary_unshift(parts, ID2SYM(idNULL));
- return parts;
- }
-
- node = cast->parent;
- break;
- }
- default:
- return Qnil;
- }
- }
-}
-
-/**
- * Compile a constant path into two sequences of instructions, one for the
- * owning expression if there is one (prefix) and one for the constant reads
- * (body).
- */
-static void
-pm_compile_constant_path(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const prefix, LINK_ANCHOR *const body, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
-
- switch (PM_NODE_TYPE(node)) {
- case PM_CONSTANT_READ_NODE: {
- const pm_constant_read_node_t *cast = (const pm_constant_read_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
-
- PUSH_INSN1(body, location, putobject, Qtrue);
- PUSH_INSN1(body, location, getconstant, name);
- break;
- }
- case PM_CONSTANT_PATH_NODE: {
- const pm_constant_path_node_t *cast = (const pm_constant_path_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
-
- if (cast->parent == NULL) {
- PUSH_INSN(body, location, pop);
- PUSH_INSN1(body, location, putobject, rb_cObject);
- PUSH_INSN1(body, location, putobject, Qtrue);
- PUSH_INSN1(body, location, getconstant, name);
- }
- else {
- pm_compile_constant_path(iseq, cast->parent, prefix, body, false, scope_node);
- PUSH_INSN1(body, location, putobject, Qfalse);
- PUSH_INSN1(body, location, getconstant, name);
- }
- break;
- }
- default:
- PM_COMPILE_INTO_ANCHOR(prefix, node);
- break;
- }
-}
-
-/**
- * Return the object that will be pushed onto the stack for the given node.
- */
-static VALUE
-pm_compile_shareable_constant_literal(rb_iseq_t *iseq, const pm_node_t *node, const pm_scope_node_t *scope_node)
-{
- switch (PM_NODE_TYPE(node)) {
- case PM_TRUE_NODE:
- case PM_FALSE_NODE:
- case PM_NIL_NODE:
- case PM_SYMBOL_NODE:
- case PM_REGULAR_EXPRESSION_NODE:
- case PM_SOURCE_LINE_NODE:
- case PM_INTEGER_NODE:
- case PM_FLOAT_NODE:
- case PM_RATIONAL_NODE:
- case PM_IMAGINARY_NODE:
- case PM_SOURCE_ENCODING_NODE:
- return pm_static_literal_value(iseq, node, scope_node);
- case PM_STRING_NODE:
- return parse_static_literal_string(iseq, scope_node, node, &((const pm_string_node_t *) node)->unescaped);
- case PM_SOURCE_FILE_NODE:
- return pm_source_file_value((const pm_source_file_node_t *) node, scope_node);
- case PM_ARRAY_NODE: {
- const pm_array_node_t *cast = (const pm_array_node_t *) node;
- VALUE result = rb_ary_new_capa(cast->elements.size);
-
- for (size_t index = 0; index < cast->elements.size; index++) {
- VALUE element = pm_compile_shareable_constant_literal(iseq, cast->elements.nodes[index], scope_node);
- if (element == Qundef) return Qundef;
-
- rb_ary_push(result, element);
- }
-
- return rb_ractor_make_shareable(result);
- }
- case PM_HASH_NODE: {
- const pm_hash_node_t *cast = (const pm_hash_node_t *) node;
- VALUE result = rb_hash_new_capa(cast->elements.size);
-
- for (size_t index = 0; index < cast->elements.size; index++) {
- const pm_node_t *element = cast->elements.nodes[index];
- if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE)) return Qundef;
-
- const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) element;
-
- VALUE key = pm_compile_shareable_constant_literal(iseq, assoc->key, scope_node);
- if (key == Qundef) return Qundef;
-
- VALUE value = pm_compile_shareable_constant_literal(iseq, assoc->value, scope_node);
- if (value == Qundef) return Qundef;
-
- rb_hash_aset(result, key, value);
- }
-
- return rb_ractor_make_shareable(result);
- }
- default:
- return Qundef;
- }
-}
-
-/**
- * Compile the instructions for pushing the value that will be written to a
- * shared constant.
- */
-static void
-pm_compile_shareable_constant_value(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_flags_t shareability, VALUE path, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, bool top)
-{
- VALUE literal = pm_compile_shareable_constant_literal(iseq, node, scope_node);
- if (literal != Qundef) {
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
- PUSH_INSN1(ret, location, putobject, literal);
- return;
- }
-
- const pm_node_location_t location = PM_NODE_START_LOCATION(scope_node->parser, node);
- switch (PM_NODE_TYPE(node)) {
- case PM_ARRAY_NODE: {
- const pm_array_node_t *cast = (const pm_array_node_t *) node;
-
- if (top) {
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- }
-
- for (size_t index = 0; index < cast->elements.size; index++) {
- pm_compile_shareable_constant_value(iseq, cast->elements.nodes[index], shareability, path, ret, scope_node, false);
- }
-
- PUSH_INSN1(ret, location, newarray, INT2FIX(cast->elements.size));
-
- if (top) {
- ID method_id = (shareability & PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY) ? rb_intern("make_shareable_copy") : rb_intern("make_shareable");
- PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
- }
-
- return;
- }
- case PM_HASH_NODE: {
- const pm_hash_node_t *cast = (const pm_hash_node_t *) node;
-
- if (top) {
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- }
-
- for (size_t index = 0; index < cast->elements.size; index++) {
- const pm_node_t *element = cast->elements.nodes[index];
-
- if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE)) {
- COMPILE_ERROR(iseq, location.line, "Ractor constant writes do not support **");
- }
-
- const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) element;
- pm_compile_shareable_constant_value(iseq, assoc->key, shareability, path, ret, scope_node, false);
- pm_compile_shareable_constant_value(iseq, assoc->value, shareability, path, ret, scope_node, false);
- }
-
- PUSH_INSN1(ret, location, newhash, INT2FIX(cast->elements.size * 2));
-
- if (top) {
- ID method_id = (shareability & PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY) ? rb_intern("make_shareable_copy") : rb_intern("make_shareable");
- PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
- }
-
- return;
- }
- default: {
- DECL_ANCHOR(value_seq);
- INIT_ANCHOR(value_seq);
-
- pm_compile_node(iseq, node, value_seq, false, scope_node);
- if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
- PUSH_SEND_WITH_FLAG(value_seq, location, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
- }
-
- if (shareability & PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL) {
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_SEQ(ret, value_seq);
- PUSH_INSN1(ret, location, putobject, path);
- PUSH_SEND_WITH_FLAG(ret, location, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
- }
- else if (shareability & PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY) {
- if (top) PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_SEQ(ret, value_seq);
- if (top) PUSH_SEND_WITH_FLAG(ret, location, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
- }
- else if (shareability & PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING) {
- if (top) PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_SEQ(ret, value_seq);
- if (top) PUSH_SEND_WITH_FLAG(ret, location, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
- }
-
- break;
- }
- }
-}
-
-/**
- * Compile a constant write node, either in the context of a ractor pragma or
- * not.
- */
-static void
-pm_compile_constant_write_node(rb_iseq_t *iseq, const pm_constant_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = *node_location;
- ID name_id = pm_constant_id_lookup(scope_node, node->name);
-
- if (shareability != 0) {
- pm_compile_shareable_constant_value(iseq, node->value, shareability, rb_id2str(name_id), ret, scope_node, true);
- }
- else {
- PM_COMPILE_NOT_POPPED(node->value);
- }
-
- if (!popped) PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
-
- VALUE operand = ID2SYM(name_id);
- PUSH_INSN1(ret, location, setconstant, operand);
-}
-
-/**
- * Compile a constant and write node, either in the context of a ractor pragma
- * or not.
- */
-static void
-pm_compile_constant_and_write_node(rb_iseq_t *iseq, const pm_constant_and_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = *node_location;
-
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, node->name));
- LABEL *end_label = NEW_LABEL(location.line);
-
- pm_compile_constant_read(iseq, name, &node->name_loc, location.node_id, ret, scope_node);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSNL(ret, location, branchunless, end_label);
- if (!popped) PUSH_INSN(ret, location, pop);
-
- if (shareability != 0) {
- pm_compile_shareable_constant_value(iseq, node->value, shareability, name, ret, scope_node, true);
- }
- else {
- PM_COMPILE_NOT_POPPED(node->value);
- }
-
- if (!popped) PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- PUSH_INSN1(ret, location, setconstant, name);
- PUSH_LABEL(ret, end_label);
-}
-
-/**
- * Compile a constant or write node, either in the context of a ractor pragma or
- * not.
- */
-static void
-pm_compile_constant_or_write_node(rb_iseq_t *iseq, const pm_constant_or_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = *node_location;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, node->name));
-
- LABEL *set_label = NEW_LABEL(location.line);
- LABEL *end_label = NEW_LABEL(location.line);
-
- PUSH_INSN(ret, location, putnil);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_CONST), name, Qtrue);
- PUSH_INSNL(ret, location, branchunless, set_label);
-
- pm_compile_constant_read(iseq, name, &node->name_loc, location.node_id, ret, scope_node);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSNL(ret, location, branchif, end_label);
- if (!popped) PUSH_INSN(ret, location, pop);
- PUSH_LABEL(ret, set_label);
-
- if (shareability != 0) {
- pm_compile_shareable_constant_value(iseq, node->value, shareability, name, ret, scope_node, true);
- }
- else {
- PM_COMPILE_NOT_POPPED(node->value);
- }
-
- if (!popped) PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- PUSH_INSN1(ret, location, setconstant, name);
- PUSH_LABEL(ret, end_label);
-}
-
-/**
- * Compile a constant operator write node, either in the context of a ractor
- * pragma or not.
- */
-static void
-pm_compile_constant_operator_write_node(rb_iseq_t *iseq, const pm_constant_operator_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = *node_location;
-
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, node->name));
- ID method_id = pm_constant_id_lookup(scope_node, node->binary_operator);
-
- pm_compile_constant_read(iseq, name, &node->name_loc, location.node_id, ret, scope_node);
-
- if (shareability != 0) {
- pm_compile_shareable_constant_value(iseq, node->value, shareability, name, ret, scope_node, true);
- }
- else {
- PM_COMPILE_NOT_POPPED(node->value);
- }
-
- PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2NUM(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- PUSH_INSN1(ret, location, setconstant, name);
-}
-
-/**
- * Creates a string that is used in ractor error messages to describe the
- * constant path being written.
- */
-static VALUE
-pm_constant_path_path(const pm_constant_path_node_t *node, const pm_scope_node_t *scope_node)
-{
- VALUE parts = rb_ary_new();
- rb_ary_push(parts, rb_id2str(pm_constant_id_lookup(scope_node, node->name)));
-
- const pm_node_t *current = node->parent;
- while (current != NULL && PM_NODE_TYPE_P(current, PM_CONSTANT_PATH_NODE)) {
- const pm_constant_path_node_t *cast = (const pm_constant_path_node_t *) current;
- rb_ary_unshift(parts, rb_id2str(pm_constant_id_lookup(scope_node, cast->name)));
- current = cast->parent;
- }
-
- if (current == NULL) {
- rb_ary_unshift(parts, rb_id2str(idNULL));
- }
- else if (PM_NODE_TYPE_P(current, PM_CONSTANT_READ_NODE)) {
- rb_ary_unshift(parts, rb_id2str(pm_constant_id_lookup(scope_node, ((const pm_constant_read_node_t *) current)->name)));
- }
- else {
- rb_ary_unshift(parts, rb_str_new_cstr("..."));
- }
-
- return rb_ary_join(parts, rb_str_new_cstr("::"));
-}
-
-/**
- * Compile a constant path write node, either in the context of a ractor pragma
- * or not.
- */
-static void
-pm_compile_constant_path_write_node(rb_iseq_t *iseq, const pm_constant_path_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = *node_location;
- const pm_constant_path_node_t *target = node->target;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, target->name));
-
- if (target->parent) {
- PM_COMPILE_NOT_POPPED((const pm_node_t *) target->parent);
- }
- else {
- PUSH_INSN1(ret, location, putobject, rb_cObject);
- }
-
- if (shareability != 0) {
- pm_compile_shareable_constant_value(iseq, node->value, shareability, pm_constant_path_path(node->target, scope_node), ret, scope_node, true);
- }
- else {
- PM_COMPILE_NOT_POPPED(node->value);
- }
-
- if (!popped) {
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- }
-
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, setconstant, name);
-}
-
-/**
- * Compile a constant path and write node, either in the context of a ractor
- * pragma or not.
- */
-static void
-pm_compile_constant_path_and_write_node(rb_iseq_t *iseq, const pm_constant_path_and_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = *node_location;
- const pm_constant_path_node_t *target = node->target;
-
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, target->name));
- LABEL *lfin = NEW_LABEL(location.line);
-
- if (target->parent) {
- PM_COMPILE_NOT_POPPED(target->parent);
- }
- else {
- PUSH_INSN1(ret, location, putobject, rb_cObject);
- }
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putobject, Qtrue);
- PUSH_INSN1(ret, location, getconstant, name);
-
- if (!popped) PUSH_INSN(ret, location, dup);
- PUSH_INSNL(ret, location, branchunless, lfin);
-
- if (!popped) PUSH_INSN(ret, location, pop);
-
- if (shareability != 0) {
- pm_compile_shareable_constant_value(iseq, node->value, shareability, pm_constant_path_path(node->target, scope_node), ret, scope_node, true);
- }
- else {
- PM_COMPILE_NOT_POPPED(node->value);
- }
-
- if (popped) {
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- }
- else {
- PUSH_INSN1(ret, location, dupn, INT2FIX(2));
- PUSH_INSN(ret, location, swap);
- }
-
- PUSH_INSN1(ret, location, setconstant, name);
- PUSH_LABEL(ret, lfin);
-
- if (!popped) PUSH_INSN(ret, location, swap);
- PUSH_INSN(ret, location, pop);
-}
-
-/**
- * Compile a constant path or write node, either in the context of a ractor
- * pragma or not.
- */
-static void
-pm_compile_constant_path_or_write_node(rb_iseq_t *iseq, const pm_constant_path_or_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = *node_location;
- const pm_constant_path_node_t *target = node->target;
-
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, target->name));
- LABEL *lassign = NEW_LABEL(location.line);
- LABEL *lfin = NEW_LABEL(location.line);
-
- if (target->parent) {
- PM_COMPILE_NOT_POPPED(target->parent);
- }
- else {
- PUSH_INSN1(ret, location, putobject, rb_cObject);
- }
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_CONST_FROM), name, Qtrue);
- PUSH_INSNL(ret, location, branchunless, lassign);
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putobject, Qtrue);
- PUSH_INSN1(ret, location, getconstant, name);
-
- if (!popped) PUSH_INSN(ret, location, dup);
- PUSH_INSNL(ret, location, branchif, lfin);
-
- if (!popped) PUSH_INSN(ret, location, pop);
- PUSH_LABEL(ret, lassign);
-
- if (shareability != 0) {
- pm_compile_shareable_constant_value(iseq, node->value, shareability, pm_constant_path_path(node->target, scope_node), ret, scope_node, true);
- }
- else {
- PM_COMPILE_NOT_POPPED(node->value);
- }
-
- if (popped) {
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- }
- else {
- PUSH_INSN1(ret, location, dupn, INT2FIX(2));
- PUSH_INSN(ret, location, swap);
- }
-
- PUSH_INSN1(ret, location, setconstant, name);
- PUSH_LABEL(ret, lfin);
-
- if (!popped) PUSH_INSN(ret, location, swap);
- PUSH_INSN(ret, location, pop);
-}
-
-/**
- * Compile a constant path operator write node, either in the context of a
- * ractor pragma or not.
- */
-static void
-pm_compile_constant_path_operator_write_node(rb_iseq_t *iseq, const pm_constant_path_operator_write_node_t *node, const pm_node_flags_t shareability, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_node_location_t location = *node_location;
- const pm_constant_path_node_t *target = node->target;
-
- ID method_id = pm_constant_id_lookup(scope_node, node->binary_operator);
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, target->name));
-
- if (target->parent) {
- PM_COMPILE_NOT_POPPED(target->parent);
- }
- else {
- PUSH_INSN1(ret, location, putobject, rb_cObject);
- }
-
- PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, putobject, Qtrue);
- PUSH_INSN1(ret, location, getconstant, name);
-
- if (shareability != 0) {
- pm_compile_shareable_constant_value(iseq, node->value, shareability, pm_constant_path_path(node->target, scope_node), ret, scope_node, true);
- }
- else {
- PM_COMPILE_NOT_POPPED(node->value);
- }
-
- PUSH_CALL(ret, location, method_id, INT2FIX(1));
- PUSH_INSN(ret, location, swap);
-
- if (!popped) {
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- PUSH_INSN(ret, location, swap);
- }
-
- PUSH_INSN1(ret, location, setconstant, name);
-}
-
-/**
- * Many nodes in Prism can be marked as a static literal, which means slightly
- * different things depending on which node it is. Occasionally we need to omit
- * container nodes from static literal checks, which is where this macro comes
- * in.
- */
-#define PM_CONTAINER_P(node) (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) || PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_RANGE_NODE))
-
-/**
- * Compile a scope node, which is a special kind of node that represents a new
- * lexical scope, attached to a node in the AST.
- */
-static inline void
-pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped)
-{
- const pm_node_location_t location = *node_location;
- struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
-
- pm_constant_id_list_t *locals = &scope_node->locals;
- pm_parameters_node_t *parameters_node = NULL;
- pm_node_list_t *keywords_list = NULL;
- pm_node_list_t *optionals_list = NULL;
- pm_node_list_t *posts_list = NULL;
- pm_node_list_t *requireds_list = NULL;
- pm_node_list_t *block_locals = NULL;
- bool trailing_comma = false;
-
- if (PM_NODE_TYPE_P(scope_node->ast_node, PM_CLASS_NODE) || PM_NODE_TYPE_P(scope_node->ast_node, PM_MODULE_NODE)) {
- PUSH_TRACE(ret, RUBY_EVENT_CLASS);
- }
-
- if (scope_node->parameters != NULL) {
- switch (PM_NODE_TYPE(scope_node->parameters)) {
- case PM_BLOCK_PARAMETERS_NODE: {
- pm_block_parameters_node_t *cast = (pm_block_parameters_node_t *) scope_node->parameters;
- parameters_node = cast->parameters;
- block_locals = &cast->locals;
-
- if (parameters_node) {
- if (parameters_node->rest && PM_NODE_TYPE_P(parameters_node->rest, PM_IMPLICIT_REST_NODE)) {
- trailing_comma = true;
- }
- }
- break;
- }
- case PM_PARAMETERS_NODE: {
- parameters_node = (pm_parameters_node_t *) scope_node->parameters;
- break;
- }
- case PM_NUMBERED_PARAMETERS_NODE: {
- uint32_t maximum = ((const pm_numbered_parameters_node_t *) scope_node->parameters)->maximum;
- body->param.lead_num = maximum;
- body->param.flags.ambiguous_param0 = maximum == 1;
- break;
- }
- case PM_IT_PARAMETERS_NODE:
- body->param.lead_num = 1;
- body->param.flags.ambiguous_param0 = true;
- break;
- default:
- rb_bug("Unexpected node type for parameters: %s", pm_node_type_to_str(PM_NODE_TYPE(scope_node->parameters)));
- }
- }
-
- struct rb_iseq_param_keyword *keyword = NULL;
-
- if (parameters_node) {
- optionals_list = &parameters_node->optionals;
- requireds_list = &parameters_node->requireds;
- keywords_list = &parameters_node->keywords;
- posts_list = &parameters_node->posts;
- }
- else if (scope_node->parameters && (PM_NODE_TYPE_P(scope_node->parameters, PM_NUMBERED_PARAMETERS_NODE) || PM_NODE_TYPE_P(scope_node->parameters, PM_IT_PARAMETERS_NODE))) {
- body->param.opt_num = 0;
- }
- else {
- body->param.lead_num = 0;
- body->param.opt_num = 0;
- }
-
- //********STEP 1**********
- // Goal: calculate the table size for the locals, accounting for
- // hidden variables and multi target nodes
- size_t locals_size = locals->size;
-
- // Index lookup table buffer size is only the number of the locals
- st_table *index_lookup_table = st_init_numtable();
-
- int table_size = (int) locals_size;
-
- // For nodes have a hidden iteration variable. We add that to the local
- // table size here.
- if (PM_NODE_TYPE_P(scope_node->ast_node, PM_FOR_NODE)) table_size++;
-
- if (keywords_list && keywords_list->size) {
- table_size++;
- }
-
- if (requireds_list) {
- for (size_t i = 0; i < requireds_list->size; i++) {
- // For each MultiTargetNode, we're going to have one
- // additional anonymous local not represented in the locals table
- // We want to account for this in our table size
- pm_node_t *required = requireds_list->nodes[i];
- if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) {
- table_size++;
- }
- else if (PM_NODE_TYPE_P(required, PM_REQUIRED_PARAMETER_NODE)) {
- if (PM_NODE_FLAG_P(required, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- table_size++;
- }
- }
- }
- }
-
- // If we have the `it` implicit local variable, we need to account for
- // it in the local table size.
- if (scope_node->parameters != NULL && PM_NODE_TYPE_P(scope_node->parameters, PM_IT_PARAMETERS_NODE)) {
- table_size++;
- }
-
- // Ensure there is enough room in the local table for any
- // parameters that have been repeated
- // ex: def underscore_parameters(_, _ = 1, _ = 2); _; end
- // ^^^^^^^^^^^^
- if (optionals_list && optionals_list->size) {
- for (size_t i = 0; i < optionals_list->size; i++) {
- pm_node_t * node = optionals_list->nodes[i];
- if (PM_NODE_FLAG_P(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- table_size++;
- }
- }
- }
-
- // If we have an anonymous "rest" node, we'll need to increase the local
- // table size to take it in to account.
- // def m(foo, *, bar)
- // ^
- if (parameters_node) {
- if (parameters_node->rest) {
- if (!(PM_NODE_TYPE_P(parameters_node->rest, PM_IMPLICIT_REST_NODE))) {
- if (!((const pm_rest_parameter_node_t *) parameters_node->rest)->name || PM_NODE_FLAG_P(parameters_node->rest, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- table_size++;
- }
- }
- }
-
- // def foo(_, **_); _; end
- // ^^^
- if (parameters_node->keyword_rest) {
- // def foo(...); end
- // ^^^
- // When we have a `...` as the keyword_rest, it's a forwarding_parameter_node and
- // we need to leave space for 4 locals: *, **, &, ...
- if (PM_NODE_TYPE_P(parameters_node->keyword_rest, PM_FORWARDING_PARAMETER_NODE)) {
- // Only optimize specifically methods like this: `foo(...)`
- if (requireds_list->size == 0 && optionals_list->size == 0 && keywords_list->size == 0) {
- ISEQ_BODY(iseq)->param.flags.use_block = TRUE;
- ISEQ_BODY(iseq)->param.flags.forwardable = TRUE;
- table_size += 1;
- }
- else {
- table_size += 4;
- }
- }
- else {
- const pm_keyword_rest_parameter_node_t *kw_rest = (const pm_keyword_rest_parameter_node_t *) parameters_node->keyword_rest;
-
- // If it's anonymous or repeated, then we need to allocate stack space
- if (!kw_rest->name || PM_NODE_FLAG_P(kw_rest, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- table_size++;
- }
- }
- }
- }
-
- if (posts_list) {
- for (size_t i = 0; i < posts_list->size; i++) {
- // For each MultiTargetNode, we're going to have one
- // additional anonymous local not represented in the locals table
- // We want to account for this in our table size
- pm_node_t *required = posts_list->nodes[i];
- if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE) || PM_NODE_FLAG_P(required, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- table_size++;
- }
- }
- }
-
- if (keywords_list && keywords_list->size) {
- for (size_t i = 0; i < keywords_list->size; i++) {
- pm_node_t *keyword_parameter_node = keywords_list->nodes[i];
- if (PM_NODE_FLAG_P(keyword_parameter_node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- table_size++;
- }
- }
- }
-
- if (parameters_node && parameters_node->block) {
- const pm_block_parameter_node_t *block_node = (const pm_block_parameter_node_t *) parameters_node->block;
-
- if (PM_NODE_FLAG_P(block_node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER) || !block_node->name) {
- table_size++;
- }
- }
-
- // We can create local_table_for_iseq with the correct size
- VALUE idtmp = 0;
- rb_ast_id_table_t *local_table_for_iseq = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
- local_table_for_iseq->size = table_size;
-
- //********END OF STEP 1**********
-
- //********STEP 2**********
- // Goal: populate iv index table as well as local table, keeping the
- // layout of the local table consistent with the layout of the
- // stack when calling the method
- //
- // Do a first pass on all of the parameters, setting their values in
- // the local_table_for_iseq, _except_ for Multis who get a hidden
- // variable in this step, and will get their names inserted in step 3
-
- // local_index is a cursor that keeps track of the current
- // index into local_table_for_iseq. The local table is actually a list,
- // and the order of that list must match the order of the items pushed
- // on the stack. We need to take in to account things pushed on the
- // stack that _might not have a name_ (for example array destructuring).
- // This index helps us know which item we're dealing with and also give
- // those anonymous items temporary names (as below)
- int local_index = 0;
-
- // Here we figure out local table indices and insert them in to the
- // index lookup table and local tables.
- //
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^^^^^^^^^^
- if (requireds_list && requireds_list->size) {
- for (size_t i = 0; i < requireds_list->size; i++, local_index++) {
- ID local;
-
- // For each MultiTargetNode, we're going to have one additional
- // anonymous local not represented in the locals table. We want
- // to account for this in our table size.
- pm_node_t *required = requireds_list->nodes[i];
-
- switch (PM_NODE_TYPE(required)) {
- case PM_MULTI_TARGET_NODE: {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^^^^^^^
- local = rb_make_temporary_id(local_index);
- local_table_for_iseq->ids[local_index] = local;
- break;
- }
- case PM_REQUIRED_PARAMETER_NODE: {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^
- const pm_required_parameter_node_t *param = (const pm_required_parameter_node_t *) required;
-
- if (PM_NODE_FLAG_P(required, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- ID local = pm_constant_id_lookup(scope_node, param->name);
- local_table_for_iseq->ids[local_index] = local;
- }
- else {
- pm_insert_local_index(param->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
-
- break;
- }
- default:
- rb_bug("Unsupported node in requireds in parameters %s", pm_node_type_to_str(PM_NODE_TYPE(required)));
- }
- }
-
- body->param.lead_num = (int) requireds_list->size;
- body->param.flags.has_lead = true;
- }
-
- if (scope_node->parameters != NULL && PM_NODE_TYPE_P(scope_node->parameters, PM_IT_PARAMETERS_NODE)) {
- ID local = rb_make_temporary_id(local_index);
- local_table_for_iseq->ids[local_index++] = local;
- }
-
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^^
- if (optionals_list && optionals_list->size) {
- body->param.opt_num = (int) optionals_list->size;
- body->param.flags.has_opt = true;
-
- for (size_t i = 0; i < optionals_list->size; i++, local_index++) {
- pm_node_t * node = optionals_list->nodes[i];
- pm_constant_id_t name = ((const pm_optional_parameter_node_t *) node)->name;
-
- if (PM_NODE_FLAG_P(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- ID local = pm_constant_id_lookup(scope_node, name);
- local_table_for_iseq->ids[local_index] = local;
- }
- else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- }
- }
-
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^
- if (parameters_node && parameters_node->rest) {
- body->param.rest_start = local_index;
-
- // If there's a trailing comma, we'll have an implicit rest node,
- // and we don't want it to impact the rest variables on param
- if (!(PM_NODE_TYPE_P(parameters_node->rest, PM_IMPLICIT_REST_NODE))) {
- body->param.flags.has_rest = true;
- RUBY_ASSERT(body->param.rest_start != -1);
-
- pm_constant_id_t name = ((const pm_rest_parameter_node_t *) parameters_node->rest)->name;
-
- if (name) {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^
- if (PM_NODE_FLAG_P(parameters_node->rest, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- ID local = pm_constant_id_lookup(scope_node, name);
- local_table_for_iseq->ids[local_index] = local;
- }
- else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- }
- else {
- // def foo(a, (b, *c, d), e = 1, *, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^
- body->param.flags.anon_rest = true;
- pm_insert_local_special(idMULT, local_index, index_lookup_table, local_table_for_iseq);
- }
-
- local_index++;
- }
- }
-
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^^^^^^^^^^
- if (posts_list && posts_list->size) {
- body->param.post_num = (int) posts_list->size;
- body->param.post_start = local_index;
- body->param.flags.has_post = true;
-
- for (size_t i = 0; i < posts_list->size; i++, local_index++) {
- ID local;
-
- // For each MultiTargetNode, we're going to have one additional
- // anonymous local not represented in the locals table. We want
- // to account for this in our table size.
- const pm_node_t *post_node = posts_list->nodes[i];
-
- switch (PM_NODE_TYPE(post_node)) {
- case PM_MULTI_TARGET_NODE: {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^^^^^^^
- local = rb_make_temporary_id(local_index);
- local_table_for_iseq->ids[local_index] = local;
- break;
- }
- case PM_REQUIRED_PARAMETER_NODE: {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^
- const pm_required_parameter_node_t *param = (const pm_required_parameter_node_t *) post_node;
-
- if (PM_NODE_FLAG_P(param, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- ID local = pm_constant_id_lookup(scope_node, param->name);
- local_table_for_iseq->ids[local_index] = local;
- }
- else {
- pm_insert_local_index(param->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- break;
- }
- default:
- rb_bug("Unsupported node in posts in parameters %s", pm_node_type_to_str(PM_NODE_TYPE(post_node)));
- }
- }
- }
-
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^^^^^
- // Keywords create an internal variable on the parse tree
- if (keywords_list && keywords_list->size) {
- body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
- keyword->num = (int) keywords_list->size;
-
- body->param.flags.has_kw = true;
- const VALUE default_values = rb_ary_hidden_new(1);
- const VALUE complex_mark = rb_str_tmp_new(0);
-
- ID *ids = xcalloc(keywords_list->size, sizeof(ID));
-
- size_t kw_index = 0;
-
- for (size_t i = 0; i < keywords_list->size; i++) {
- pm_node_t *keyword_parameter_node = keywords_list->nodes[i];
- pm_constant_id_t name;
-
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^
- if (PM_NODE_TYPE_P(keyword_parameter_node, PM_REQUIRED_KEYWORD_PARAMETER_NODE)) {
- name = ((const pm_required_keyword_parameter_node_t *) keyword_parameter_node)->name;
- keyword->required_num++;
- ID local = pm_constant_id_lookup(scope_node, name);
-
- if (PM_NODE_FLAG_P(keyword_parameter_node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- local_table_for_iseq->ids[local_index] = local;
- }
- else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- local_index++;
- ids[kw_index++] = local;
- }
- }
-
- for (size_t i = 0; i < keywords_list->size; i++) {
- pm_node_t *keyword_parameter_node = keywords_list->nodes[i];
- pm_constant_id_t name;
-
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^
- if (PM_NODE_TYPE_P(keyword_parameter_node, PM_OPTIONAL_KEYWORD_PARAMETER_NODE)) {
- const pm_optional_keyword_parameter_node_t *cast = ((const pm_optional_keyword_parameter_node_t *) keyword_parameter_node);
-
- pm_node_t *value = cast->value;
- name = cast->name;
-
- if (PM_NODE_FLAG_P(value, PM_NODE_FLAG_STATIC_LITERAL) && !PM_CONTAINER_P(value)) {
- rb_ary_push(default_values, pm_static_literal_value(iseq, value, scope_node));
- }
- else {
- rb_ary_push(default_values, complex_mark);
- }
-
- ID local = pm_constant_id_lookup(scope_node, name);
- if (PM_NODE_FLAG_P(keyword_parameter_node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- local_table_for_iseq->ids[local_index] = local;
- }
- else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- ids[kw_index++] = local;
- local_index++;
- }
-
- }
-
- keyword->bits_start = local_index;
- keyword->table = ids;
-
- if (RARRAY_LEN(default_values)) {
- VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
-
- for (int i = 0; i < RARRAY_LEN(default_values); i++) {
- VALUE dv = RARRAY_AREF(default_values, i);
- if (dv == complex_mark) dv = Qundef;
- RB_OBJ_WRITE(iseq, &dvs[i], dv);
- }
-
- keyword->default_values = dvs;
- }
-
- // Hidden local for keyword arguments
- ID local = rb_make_temporary_id(local_index);
- local_table_for_iseq->ids[local_index] = local;
- local_index++;
- }
-
- if (body->type == ISEQ_TYPE_BLOCK && local_index == 1 && requireds_list && requireds_list->size == 1 && !trailing_comma) {
- body->param.flags.ambiguous_param0 = true;
- }
-
- if (parameters_node) {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^
- if (parameters_node->keyword_rest) {
- switch (PM_NODE_TYPE(parameters_node->keyword_rest)) {
- case PM_NO_KEYWORDS_PARAMETER_NODE: {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **nil, &n)
- // ^^^^^
- body->param.flags.accepts_no_kwarg = true;
- break;
- }
- case PM_KEYWORD_REST_PARAMETER_NODE: {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^
- const pm_keyword_rest_parameter_node_t *kw_rest_node = (const pm_keyword_rest_parameter_node_t *) parameters_node->keyword_rest;
- if (!body->param.flags.has_kw) {
- body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
- }
-
- keyword->rest_start = local_index;
- body->param.flags.has_kwrest = true;
-
- pm_constant_id_t constant_id = kw_rest_node->name;
- if (constant_id) {
- if (PM_NODE_FLAG_P(kw_rest_node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- ID local = pm_constant_id_lookup(scope_node, constant_id);
- local_table_for_iseq->ids[local_index] = local;
- }
- else {
- pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- }
- else {
- body->param.flags.anon_kwrest = true;
- pm_insert_local_special(idPow, local_index, index_lookup_table, local_table_for_iseq);
- }
-
- local_index++;
- break;
- }
- case PM_FORWARDING_PARAMETER_NODE: {
- // def foo(...)
- // ^^^
- if (!ISEQ_BODY(iseq)->param.flags.forwardable) {
- // Add the anonymous *
- body->param.rest_start = local_index;
- body->param.flags.has_rest = true;
- body->param.flags.anon_rest = true;
- pm_insert_local_special(idMULT, local_index++, index_lookup_table, local_table_for_iseq);
-
- // Add the anonymous **
- RUBY_ASSERT(!body->param.flags.has_kw);
- body->param.flags.has_kw = false;
- body->param.flags.has_kwrest = true;
- body->param.flags.anon_kwrest = true;
- body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
- keyword->rest_start = local_index;
- pm_insert_local_special(idPow, local_index++, index_lookup_table, local_table_for_iseq);
-
- // Add the anonymous &
- body->param.block_start = local_index;
- body->param.flags.has_block = true;
- pm_insert_local_special(idAnd, local_index++, index_lookup_table, local_table_for_iseq);
- }
-
- // Add the ...
- pm_insert_local_special(idDot3, local_index++, index_lookup_table, local_table_for_iseq);
- break;
- }
- default:
- rb_bug("node type %s not expected as keyword_rest", pm_node_type_to_str(PM_NODE_TYPE(parameters_node->keyword_rest)));
- }
- }
-
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^
- if (parameters_node->block) {
- body->param.block_start = local_index;
- body->param.flags.has_block = true;
- iseq_set_use_block(iseq);
-
- pm_constant_id_t name = ((const pm_block_parameter_node_t *) parameters_node->block)->name;
-
- if (name) {
- if (PM_NODE_FLAG_P(parameters_node->block, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- ID local = pm_constant_id_lookup(scope_node, name);
- local_table_for_iseq->ids[local_index] = local;
- }
- else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- }
- else {
- pm_insert_local_special(idAnd, local_index, index_lookup_table, local_table_for_iseq);
- }
-
- local_index++;
- }
- }
-
- //********END OF STEP 2**********
- // The local table is now consistent with expected
- // stack layout
-
- // If there's only one required element in the parameters
- // CRuby needs to recognize it as an ambiguous parameter
-
- //********STEP 3**********
- // Goal: fill in the names of the parameters in MultiTargetNodes
- //
- // Go through requireds again to set the multis
-
- if (requireds_list && requireds_list->size) {
- for (size_t i = 0; i < requireds_list->size; i++) {
- // For each MultiTargetNode, we're going to have one
- // additional anonymous local not represented in the locals table
- // We want to account for this in our table size
- const pm_node_t *required = requireds_list->nodes[i];
-
- if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) {
- local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) required, index_lookup_table, local_table_for_iseq, scope_node, local_index);
- }
- }
- }
-
- // Go through posts again to set the multis
- if (posts_list && posts_list->size) {
- for (size_t i = 0; i < posts_list->size; i++) {
- // For each MultiTargetNode, we're going to have one
- // additional anonymous local not represented in the locals table
- // We want to account for this in our table size
- const pm_node_t *post = posts_list->nodes[i];
-
- if (PM_NODE_TYPE_P(post, PM_MULTI_TARGET_NODE)) {
- local_index = pm_compile_destructured_param_locals((const pm_multi_target_node_t *) post, index_lookup_table, local_table_for_iseq, scope_node, local_index);
- }
- }
- }
-
- // Set any anonymous locals for the for node
- if (PM_NODE_TYPE_P(scope_node->ast_node, PM_FOR_NODE)) {
- if (PM_NODE_TYPE_P(((const pm_for_node_t *) scope_node->ast_node)->index, PM_LOCAL_VARIABLE_TARGET_NODE)) {
- body->param.lead_num++;
- }
- else {
- body->param.rest_start = local_index;
- body->param.flags.has_rest = true;
- }
-
- ID local = rb_make_temporary_id(local_index);
- local_table_for_iseq->ids[local_index] = local;
- local_index++;
- }
-
- // Fill in any NumberedParameters, if they exist
- if (scope_node->parameters && PM_NODE_TYPE_P(scope_node->parameters, PM_NUMBERED_PARAMETERS_NODE)) {
- int maximum = ((const pm_numbered_parameters_node_t *) scope_node->parameters)->maximum;
- RUBY_ASSERT(0 < maximum && maximum <= 9);
- for (int i = 0; i < maximum; i++, local_index++) {
- const uint8_t param_name[] = { '_', '1' + i };
- pm_constant_id_t constant_id = pm_constant_pool_find(&scope_node->parser->constant_pool, param_name, 2);
- RUBY_ASSERT(constant_id && "parser should fill in any gaps in numbered parameters");
- pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- body->param.lead_num = maximum;
- body->param.flags.has_lead = true;
- }
-
- //********END OF STEP 3**********
-
- //********STEP 4**********
- // Goal: fill in the method body locals
- // To be explicit, these are the non-parameter locals
- // We fill in the block_locals, if they exist
- // lambda { |x; y| y }
- // ^
- if (block_locals && block_locals->size) {
- for (size_t i = 0; i < block_locals->size; i++, local_index++) {
- pm_constant_id_t constant_id = ((const pm_block_local_variable_node_t *) block_locals->nodes[i])->name;
- pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
- }
- }
-
- // Fill in any locals we missed
- if (scope_node->locals.size) {
- for (size_t i = 0; i < scope_node->locals.size; i++) {
- pm_constant_id_t constant_id = locals->ids[i];
- if (constant_id) {
- struct pm_local_table_insert_ctx ctx;
- ctx.scope_node = scope_node;
- ctx.local_table_for_iseq = local_table_for_iseq;
- ctx.local_index = local_index;
-
- st_update(index_lookup_table, (st_data_t)constant_id, pm_local_table_insert_func, (st_data_t)&ctx);
-
- local_index = ctx.local_index;
- }
- }
- }
-
- //********END OF STEP 4**********
-
- // We set the index_lookup_table on the scope node so we can
- // refer to the parameters correctly
- if (scope_node->index_lookup_table) {
- st_free_table(scope_node->index_lookup_table);
- }
- scope_node->index_lookup_table = index_lookup_table;
- iseq_calc_param_size(iseq);
-
- if (ISEQ_BODY(iseq)->param.flags.forwardable) {
- // We're treating `...` as a parameter so that frame
- // pushing won't clobber it.
- ISEQ_BODY(iseq)->param.size += 1;
- }
-
- // FIXME: args?
- iseq_set_local_table(iseq, local_table_for_iseq, 0);
- scope_node->local_table_for_iseq_size = local_table_for_iseq->size;
-
- //********STEP 5************
- // Goal: compile anything that needed to be compiled
- if (optionals_list && optionals_list->size) {
- LABEL **opt_table = (LABEL **) ALLOC_N(VALUE, optionals_list->size + 1);
- LABEL *label;
-
- // TODO: Should we make an api for NEW_LABEL where you can pass
- // a pointer to the label it should fill out? We already
- // have a list of labels allocated above so it seems wasteful
- // to do the copies.
- for (size_t i = 0; i < optionals_list->size; i++) {
- label = NEW_LABEL(location.line);
- opt_table[i] = label;
- PUSH_LABEL(ret, label);
- pm_node_t *optional_node = optionals_list->nodes[i];
- PM_COMPILE_NOT_POPPED(optional_node);
- }
-
- // Set the last label
- label = NEW_LABEL(location.line);
- opt_table[optionals_list->size] = label;
- PUSH_LABEL(ret, label);
-
- body->param.opt_table = (const VALUE *) opt_table;
- }
-
- if (keywords_list && keywords_list->size) {
- size_t optional_index = 0;
- for (size_t i = 0; i < keywords_list->size; i++) {
- pm_node_t *keyword_parameter_node = keywords_list->nodes[i];
- pm_constant_id_t name;
-
- switch (PM_NODE_TYPE(keyword_parameter_node)) {
- case PM_OPTIONAL_KEYWORD_PARAMETER_NODE: {
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^^^
- const pm_optional_keyword_parameter_node_t *cast = ((const pm_optional_keyword_parameter_node_t *) keyword_parameter_node);
-
- pm_node_t *value = cast->value;
- name = cast->name;
-
- if (!PM_NODE_FLAG_P(value, PM_NODE_FLAG_STATIC_LITERAL) || PM_CONTAINER_P(value)) {
- LABEL *end_label = NEW_LABEL(location.line);
-
- pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, name, 0);
- int kw_bits_idx = table_size - body->param.keyword->bits_start;
- PUSH_INSN2(ret, location, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(optional_index));
- PUSH_INSNL(ret, location, branchif, end_label);
- PM_COMPILE(value);
- PUSH_SETLOCAL(ret, location, index.index, index.level);
- PUSH_LABEL(ret, end_label);
- }
- optional_index++;
- break;
- }
- case PM_REQUIRED_KEYWORD_PARAMETER_NODE:
- // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
- // ^^
- break;
- default:
- rb_bug("Unexpected keyword parameter node type %s", pm_node_type_to_str(PM_NODE_TYPE(keyword_parameter_node)));
- }
- }
- }
-
- if (requireds_list && requireds_list->size) {
- for (size_t i = 0; i < requireds_list->size; i++) {
- // For each MultiTargetNode, we're going to have one additional
- // anonymous local not represented in the locals table. We want
- // to account for this in our table size.
- const pm_node_t *required = requireds_list->nodes[i];
-
- if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) {
- PUSH_GETLOCAL(ret, location, table_size - (int)i, 0);
- pm_compile_destructured_param_writes(iseq, (const pm_multi_target_node_t *) required, ret, scope_node);
- }
- }
- }
-
- if (posts_list && posts_list->size) {
- for (size_t i = 0; i < posts_list->size; i++) {
- // For each MultiTargetNode, we're going to have one additional
- // anonymous local not represented in the locals table. We want
- // to account for this in our table size.
- const pm_node_t *post = posts_list->nodes[i];
-
- if (PM_NODE_TYPE_P(post, PM_MULTI_TARGET_NODE)) {
- PUSH_GETLOCAL(ret, location, table_size - body->param.post_start - (int) i, 0);
- pm_compile_destructured_param_writes(iseq, (const pm_multi_target_node_t *) post, ret, scope_node);
- }
- }
- }
-
- switch (body->type) {
- case ISEQ_TYPE_PLAIN: {
- RUBY_ASSERT(PM_NODE_TYPE_P(scope_node->ast_node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE));
-
- const pm_interpolated_regular_expression_node_t *cast = (const pm_interpolated_regular_expression_node_t *) scope_node->ast_node;
- pm_compile_regexp_dynamic(iseq, (const pm_node_t *) cast, &cast->parts, &location, ret, popped, scope_node);
-
- break;
- }
- case ISEQ_TYPE_BLOCK: {
- LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
- LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
- const pm_node_location_t block_location = { .line = body->location.first_lineno, .node_id = -1 };
-
- start->rescued = LABEL_RESCUE_BEG;
- end->rescued = LABEL_RESCUE_END;
-
- // For nodes automatically assign the iteration variable to whatever
- // index variable. We need to handle that write here because it has
- // to happen in the context of the block. Note that this happens
- // before the B_CALL tracepoint event.
- if (PM_NODE_TYPE_P(scope_node->ast_node, PM_FOR_NODE)) {
- pm_compile_for_node_index(iseq, ((const pm_for_node_t *) scope_node->ast_node)->index, ret, scope_node);
- }
-
- PUSH_TRACE(ret, RUBY_EVENT_B_CALL);
- PUSH_INSN(ret, block_location, nop);
- PUSH_LABEL(ret, start);
-
- if (scope_node->body != NULL) {
- switch (PM_NODE_TYPE(scope_node->ast_node)) {
- case PM_POST_EXECUTION_NODE: {
- const pm_post_execution_node_t *cast = (const pm_post_execution_node_t *) scope_node->ast_node;
- PUSH_INSN1(ret, block_location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
-
- // We create another ScopeNode from the statements within the PostExecutionNode
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((const pm_node_t *) cast->statements, &next_scope_node, scope_node);
-
- const rb_iseq_t *block = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(body->parent_iseq), ISEQ_TYPE_BLOCK, location.line);
- pm_scope_node_destroy(&next_scope_node);
-
- PUSH_CALL_WITH_BLOCK(ret, block_location, id_core_set_postexe, INT2FIX(0), block);
- break;
- }
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
- const pm_interpolated_regular_expression_node_t *cast = (const pm_interpolated_regular_expression_node_t *) scope_node->ast_node;
- pm_compile_regexp_dynamic(iseq, (const pm_node_t *) cast, &cast->parts, &location, ret, popped, scope_node);
- break;
- }
- default:
- pm_compile_node(iseq, scope_node->body, ret, popped, scope_node);
- break;
- }
- }
- else {
- PUSH_INSN(ret, block_location, putnil);
- }
-
- PUSH_LABEL(ret, end);
- PUSH_TRACE(ret, RUBY_EVENT_B_RETURN);
- ISEQ_COMPILE_DATA(iseq)->last_line = body->location.code_location.end_pos.lineno;
-
- /* wide range catch handler must put at last */
- PUSH_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
- PUSH_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
- break;
- }
- case ISEQ_TYPE_ENSURE: {
- const pm_node_location_t statements_location = (scope_node->body != NULL ? PM_NODE_START_LOCATION(scope_node->parser, scope_node->body) : location);
- iseq_set_exception_local_table(iseq);
-
- if (scope_node->body != NULL) {
- PM_COMPILE_POPPED((const pm_node_t *) scope_node->body);
- }
-
- PUSH_GETLOCAL(ret, statements_location, 1, 0);
- PUSH_INSN1(ret, statements_location, throw, INT2FIX(0));
- return;
- }
- case ISEQ_TYPE_METHOD: {
- ISEQ_COMPILE_DATA(iseq)->root_node = (const void *) scope_node->body;
- PUSH_TRACE(ret, RUBY_EVENT_CALL);
-
- if (scope_node->body) {
- PM_COMPILE((const pm_node_t *) scope_node->body);
- }
- else {
- PUSH_INSN(ret, location, putnil);
- }
-
- ISEQ_COMPILE_DATA(iseq)->root_node = (const void *) scope_node->body;
- PUSH_TRACE(ret, RUBY_EVENT_RETURN);
-
- ISEQ_COMPILE_DATA(iseq)->last_line = body->location.code_location.end_pos.lineno;
- break;
- }
- case ISEQ_TYPE_RESCUE: {
- iseq_set_exception_local_table(iseq);
- if (PM_NODE_TYPE_P(scope_node->ast_node, PM_RESCUE_MODIFIER_NODE)) {
- LABEL *lab = NEW_LABEL(location.line);
- LABEL *rescue_end = NEW_LABEL(location.line);
- PUSH_GETLOCAL(ret, location, LVAR_ERRINFO, 0);
- PUSH_INSN1(ret, location, putobject, rb_eStandardError);
- PUSH_INSN1(ret, location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
- PUSH_INSNL(ret, location, branchif, lab);
- PUSH_INSNL(ret, location, jump, rescue_end);
- PUSH_LABEL(ret, lab);
- PUSH_TRACE(ret, RUBY_EVENT_RESCUE);
- PM_COMPILE((const pm_node_t *) scope_node->body);
- PUSH_INSN(ret, location, leave);
- PUSH_LABEL(ret, rescue_end);
- PUSH_GETLOCAL(ret, location, LVAR_ERRINFO, 0);
- }
- else {
- PM_COMPILE((const pm_node_t *) scope_node->ast_node);
- }
- PUSH_INSN1(ret, location, throw, INT2FIX(0));
-
- return;
- }
- default:
- if (scope_node->body) {
- PM_COMPILE((const pm_node_t *) scope_node->body);
- }
- else {
- PUSH_INSN(ret, location, putnil);
- }
- break;
- }
-
- if (PM_NODE_TYPE_P(scope_node->ast_node, PM_CLASS_NODE) || PM_NODE_TYPE_P(scope_node->ast_node, PM_MODULE_NODE)) {
- const pm_node_location_t end_location = PM_NODE_END_LOCATION(scope_node->parser, scope_node->ast_node);
- PUSH_TRACE(ret, RUBY_EVENT_END);
- ISEQ_COMPILE_DATA(iseq)->last_line = end_location.line;
- }
-
- if (!PM_NODE_TYPE_P(scope_node->ast_node, PM_ENSURE_NODE)) {
- const pm_node_location_t location = { .line = ISEQ_COMPILE_DATA(iseq)->last_line, .node_id = -1 };
- PUSH_INSN(ret, location, leave);
- }
-}
-
-static inline void
-pm_compile_alias_global_variable_node(rb_iseq_t *iseq, const pm_alias_global_variable_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- // alias $foo $bar
- // ^^^^^^^^^^^^^^^
- PUSH_INSN1(ret, *location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
-
- {
- const pm_location_t *name_loc = &node->new_name->location;
- VALUE operand = ID2SYM(rb_intern3((const char *) name_loc->start, name_loc->end - name_loc->start, scope_node->encoding));
- PUSH_INSN1(ret, *location, putobject, operand);
- }
-
- {
- const pm_location_t *name_loc = &node->old_name->location;
- VALUE operand = ID2SYM(rb_intern3((const char *) name_loc->start, name_loc->end - name_loc->start, scope_node->encoding));
- PUSH_INSN1(ret, *location, putobject, operand);
- }
-
- PUSH_SEND(ret, *location, id_core_set_variable_alias, INT2FIX(2));
- if (popped) PUSH_INSN(ret, *location, pop);
-}
-
-static inline void
-pm_compile_alias_method_node(rb_iseq_t *iseq, const pm_alias_method_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- PUSH_INSN1(ret, *location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_INSN1(ret, *location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
- PM_COMPILE_NOT_POPPED(node->new_name);
- PM_COMPILE_NOT_POPPED(node->old_name);
-
- PUSH_SEND(ret, *location, id_core_set_method_alias, INT2FIX(3));
- if (popped) PUSH_INSN(ret, *location, pop);
-}
-
-static inline void
-pm_compile_and_node(rb_iseq_t *iseq, const pm_and_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- LABEL *end_label = NEW_LABEL(location->line);
-
- PM_COMPILE_NOT_POPPED(node->left);
- if (!popped) PUSH_INSN(ret, *location, dup);
- PUSH_INSNL(ret, *location, branchunless, end_label);
-
- if (!popped) PUSH_INSN(ret, *location, pop);
- PM_COMPILE(node->right);
- PUSH_LABEL(ret, end_label);
-}
-
-static inline void
-pm_compile_array_node(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_list_t *elements, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- // If every node in the array is static, then we can compile the entire
- // array now instead of later.
- if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
- // We're only going to compile this node if it's not popped. If it
- // is popped, then we know we don't need to do anything since it's
- // statically known.
- if (!popped) {
- if (elements->size) {
- VALUE value = pm_static_literal_value(iseq, node, scope_node);
- PUSH_INSN1(ret, *location, duparray, value);
- }
- else {
- PUSH_INSN1(ret, *location, newarray, INT2FIX(0));
- }
- }
- return;
- }
-
- // Here since we know there are possible side-effects inside the
- // array contents, we're going to build it entirely at runtime.
- // We'll do this by pushing all of the elements onto the stack and
- // then combining them with newarray.
- //
- // If this array is popped, then this serves only to ensure we enact
- // all side-effects (like method calls) that are contained within
- // the array contents.
- //
- // We treat all sequences of non-splat elements as their
- // own arrays, followed by a newarray, and then continually
- // concat the arrays with the SplatNode nodes.
- const int max_new_array_size = 0x100;
- const unsigned int min_tmp_array_size = 0x40;
-
- int new_array_size = 0;
- bool first_chunk = true;
-
- // This is an optimization wherein we keep track of whether or not
- // the previous element was a static literal. If it was, then we do
- // not attempt to check if we have a subarray that can be optimized.
- // If it was not, then we do check.
- bool static_literal = false;
-
- // Either create a new array, or push to the existing array.
-#define FLUSH_CHUNK \
- if (new_array_size) { \
- if (first_chunk) PUSH_INSN1(ret, *location, newarray, INT2FIX(new_array_size)); \
- else PUSH_INSN1(ret, *location, pushtoarray, INT2FIX(new_array_size)); \
- first_chunk = false; \
- new_array_size = 0; \
- }
-
- for (size_t index = 0; index < elements->size; index++) {
- const pm_node_t *element = elements->nodes[index];
-
- if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
- FLUSH_CHUNK;
-
- const pm_splat_node_t *splat_element = (const pm_splat_node_t *) element;
- if (splat_element->expression) {
- PM_COMPILE_NOT_POPPED(splat_element->expression);
- }
- else {
- pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_MULT, 0);
- PUSH_GETLOCAL(ret, *location, index.index, index.level);
- }
-
- if (first_chunk) {
- // If this is the first element of the array then we
- // need to splatarray the elements into the list.
- PUSH_INSN1(ret, *location, splatarray, Qtrue);
- first_chunk = false;
- }
- else {
- PUSH_INSN(ret, *location, concattoarray);
- }
-
- static_literal = false;
- }
- else if (PM_NODE_TYPE_P(element, PM_KEYWORD_HASH_NODE)) {
- if (new_array_size == 0 && first_chunk) {
- PUSH_INSN1(ret, *location, newarray, INT2FIX(0));
- first_chunk = false;
- }
- else {
- FLUSH_CHUNK;
- }
-
- // If we get here, then this is the last element of the
- // array/arguments, because it cannot be followed by
- // anything else without a syntax error. This looks like:
- //
- // [foo, bar, baz: qux]
- // ^^^^^^^^
- //
- // [foo, bar, **baz]
- // ^^^^^
- //
- const pm_keyword_hash_node_t *keyword_hash = (const pm_keyword_hash_node_t *) element;
- pm_compile_hash_elements(iseq, element, &keyword_hash->elements, false, ret, scope_node);
-
- // This boolean controls the manner in which we push the
- // hash onto the array. If it's all keyword splats, then we
- // can use the very specialized pushtoarraykwsplat
- // instruction to check if it's empty before we push it.
- size_t splats = 0;
- while (splats < keyword_hash->elements.size && PM_NODE_TYPE_P(keyword_hash->elements.nodes[splats], PM_ASSOC_SPLAT_NODE)) splats++;
-
- if (keyword_hash->elements.size == splats) {
- PUSH_INSN(ret, *location, pushtoarraykwsplat);
- }
- else {
- new_array_size++;
- }
- }
- else if (
- PM_NODE_FLAG_P(element, PM_NODE_FLAG_STATIC_LITERAL) &&
- !PM_CONTAINER_P(element) &&
- !static_literal &&
- ((index + min_tmp_array_size) < elements->size)
- ) {
- // If we have a static literal, then there's the potential
- // to group a bunch of them together with a literal array
- // and then concat them together.
- size_t right_index = index + 1;
- while (
- right_index < elements->size &&
- PM_NODE_FLAG_P(elements->nodes[right_index], PM_NODE_FLAG_STATIC_LITERAL) &&
- !PM_CONTAINER_P(elements->nodes[right_index])
- ) right_index++;
-
- size_t tmp_array_size = right_index - index;
- if (tmp_array_size >= min_tmp_array_size) {
- VALUE tmp_array = rb_ary_hidden_new(tmp_array_size);
-
- // Create the temporary array.
- for (; tmp_array_size; tmp_array_size--)
- rb_ary_push(tmp_array, pm_static_literal_value(iseq, elements->nodes[index++], scope_node));
-
- index--; // about to be incremented by for loop
- OBJ_FREEZE(tmp_array);
-
- // Emit the optimized code.
- FLUSH_CHUNK;
- if (first_chunk) {
- PUSH_INSN1(ret, *location, duparray, tmp_array);
- first_chunk = false;
- }
- else {
- PUSH_INSN1(ret, *location, putobject, tmp_array);
- PUSH_INSN(ret, *location, concattoarray);
- }
- }
- else {
- PM_COMPILE_NOT_POPPED(element);
- if (++new_array_size >= max_new_array_size) FLUSH_CHUNK;
- static_literal = true;
- }
- } else {
- PM_COMPILE_NOT_POPPED(element);
- if (++new_array_size >= max_new_array_size) FLUSH_CHUNK;
- static_literal = false;
- }
- }
-
- FLUSH_CHUNK;
- if (popped) PUSH_INSN(ret, *location, pop);
-
-#undef FLUSH_CHUNK
-}
-
-static inline void
-pm_compile_break_node(rb_iseq_t *iseq, const pm_break_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- unsigned long throw_flag = 0;
-
- if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
- /* while/until */
- LABEL *splabel = NEW_LABEL(0);
- PUSH_LABEL(ret, splabel);
- PUSH_ADJUST(ret, *location, ISEQ_COMPILE_DATA(iseq)->redo_label);
-
- if (node->arguments != NULL) {
- PM_COMPILE_NOT_POPPED((const pm_node_t *) node->arguments);
- }
- else {
- PUSH_INSN(ret, *location, putnil);
- }
-
- pm_add_ensure_iseq(ret, iseq, 0, scope_node);
- PUSH_INSNL(ret, *location, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
- PUSH_ADJUST_RESTORE(ret, splabel);
- if (!popped) PUSH_INSN(ret, *location, putnil);
- }
- else {
- const rb_iseq_t *ip = iseq;
-
- while (ip) {
- if (!ISEQ_COMPILE_DATA(ip)) {
- ip = 0;
- break;
- }
-
- if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
- throw_flag = VM_THROW_NO_ESCAPE_FLAG;
- }
- else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
- throw_flag = 0;
- }
- else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
- COMPILE_ERROR(iseq, location->line, "Invalid break");
- return;
- }
- else {
- ip = ISEQ_BODY(ip)->parent_iseq;
- continue;
- }
-
- /* escape from block */
- if (node->arguments != NULL) {
- PM_COMPILE_NOT_POPPED((const pm_node_t *) node->arguments);
- }
- else {
- PUSH_INSN(ret, *location, putnil);
- }
-
- PUSH_INSN1(ret, *location, throw, INT2FIX(throw_flag | TAG_BREAK));
- if (popped) PUSH_INSN(ret, *location, pop);
-
- return;
- }
-
- COMPILE_ERROR(iseq, location->line, "Invalid break");
- }
-}
-
-static inline void
-pm_compile_call_node(rb_iseq_t *iseq, const pm_call_node_t *node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- ID method_id = pm_constant_id_lookup(scope_node, node->name);
-
- const pm_location_t *message_loc = &node->message_loc;
- if (message_loc->start == NULL) message_loc = &node->base.location;
-
- const pm_node_location_t location = PM_LOCATION_START_LOCATION(scope_node->parser, message_loc, node->base.node_id);
- const char *builtin_func;
-
- if (UNLIKELY(iseq_has_builtin_function_table(iseq)) && (builtin_func = pm_iseq_builtin_function_name(scope_node, node->receiver, method_id)) != NULL) {
- pm_compile_builtin_function_call(iseq, ret, scope_node, node, &location, popped, ISEQ_COMPILE_DATA(iseq)->current_block, builtin_func);
- return;
- }
-
- LABEL *start = NEW_LABEL(location.line);
- if (node->block) PUSH_LABEL(ret, start);
-
- switch (method_id) {
- case idUMinus: {
- if (pm_opt_str_freeze_p(iseq, node)) {
- VALUE value = parse_static_literal_string(iseq, scope_node, node->receiver, &((const pm_string_node_t * ) node->receiver)->unescaped);
- const struct rb_callinfo *callinfo = new_callinfo(iseq, idUMinus, 0, 0, NULL, FALSE);
- PUSH_INSN2(ret, location, opt_str_uminus, value, callinfo);
- return;
- }
- break;
- }
- case idFreeze: {
- if (pm_opt_str_freeze_p(iseq, node)) {
- VALUE value = parse_static_literal_string(iseq, scope_node, node->receiver, &((const pm_string_node_t * ) node->receiver)->unescaped);
- const struct rb_callinfo *callinfo = new_callinfo(iseq, idFreeze, 0, 0, NULL, FALSE);
- PUSH_INSN2(ret, location, opt_str_freeze, value, callinfo);
- return;
- }
- break;
- }
- case idAREF: {
- if (pm_opt_aref_with_p(iseq, node)) {
- const pm_string_node_t *string = (const pm_string_node_t *) ((const pm_arguments_node_t *) node->arguments)->arguments.nodes[0];
- VALUE value = parse_static_literal_string(iseq, scope_node, (const pm_node_t *) string, &string->unescaped);
-
- PM_COMPILE_NOT_POPPED(node->receiver);
-
- const struct rb_callinfo *callinfo = new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE);
- PUSH_INSN2(ret, location, opt_aref_with, value, callinfo);
-
- if (popped) {
- PUSH_INSN(ret, location, pop);
- }
-
- return;
- }
- break;
- }
- case idASET: {
- if (pm_opt_aset_with_p(iseq, node)) {
- const pm_string_node_t *string = (const pm_string_node_t *) ((const pm_arguments_node_t *) node->arguments)->arguments.nodes[0];
- VALUE value = parse_static_literal_string(iseq, scope_node, (const pm_node_t *) string, &string->unescaped);
-
- PM_COMPILE_NOT_POPPED(node->receiver);
- PM_COMPILE_NOT_POPPED(((const pm_arguments_node_t *) node->arguments)->arguments.nodes[1]);
-
- if (!popped) {
- PUSH_INSN(ret, location, swap);
- PUSH_INSN1(ret, location, topn, INT2FIX(1));
- }
-
- const struct rb_callinfo *callinfo = new_callinfo(iseq, idASET, 2, 0, NULL, FALSE);
- PUSH_INSN2(ret, location, opt_aset_with, value, callinfo);
- PUSH_INSN(ret, location, pop);
- return;
- }
- break;
- }
- }
-
- if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) && !popped) {
- PUSH_INSN(ret, location, putnil);
- }
-
- if (node->receiver == NULL) {
- PUSH_INSN(ret, location, putself);
- }
- else {
- if (method_id == idCall && PM_NODE_TYPE_P(node->receiver, PM_LOCAL_VARIABLE_READ_NODE)) {
- const pm_local_variable_read_node_t *read_node_cast = (const pm_local_variable_read_node_t *) node->receiver;
- uint32_t node_id = node->receiver->node_id;
- int idx, level;
-
- if (iseq_block_param_id_p(iseq, pm_constant_id_lookup(scope_node, read_node_cast->name), &idx, &level)) {
- ADD_ELEM(ret, (LINK_ELEMENT *) new_insn_body(iseq, location.line, node_id, BIN(getblockparamproxy), 2, INT2FIX((idx) + VM_ENV_DATA_SIZE - 1), INT2FIX(level)));
- }
- else {
- PM_COMPILE_NOT_POPPED(node->receiver);
- }
- }
- else {
- PM_COMPILE_NOT_POPPED(node->receiver);
- }
- }
-
- pm_compile_call(iseq, node, ret, popped, scope_node, method_id, start);
- return;
-}
-
-static inline void
-pm_compile_call_operator_write_node(rb_iseq_t *iseq, const pm_call_operator_write_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- int flag = 0;
-
- if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY)) {
- flag = VM_CALL_FCALL;
- }
-
- PM_COMPILE_NOT_POPPED(node->receiver);
-
- LABEL *safe_label = NULL;
- if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
- safe_label = NEW_LABEL(location->line);
- PUSH_INSN(ret, *location, dup);
- PUSH_INSNL(ret, *location, branchnil, safe_label);
- }
-
- PUSH_INSN(ret, *location, dup);
-
- ID id_read_name = pm_constant_id_lookup(scope_node, node->read_name);
- PUSH_SEND_WITH_FLAG(ret, *location, id_read_name, INT2FIX(0), INT2FIX(flag));
-
- PM_COMPILE_NOT_POPPED(node->value);
- ID id_operator = pm_constant_id_lookup(scope_node, node->binary_operator);
- PUSH_SEND(ret, *location, id_operator, INT2FIX(1));
-
- if (!popped) {
- PUSH_INSN(ret, *location, swap);
- PUSH_INSN1(ret, *location, topn, INT2FIX(1));
- }
-
- ID id_write_name = pm_constant_id_lookup(scope_node, node->write_name);
- PUSH_SEND_WITH_FLAG(ret, *location, id_write_name, INT2FIX(1), INT2FIX(flag));
-
- if (safe_label != NULL && popped) PUSH_LABEL(ret, safe_label);
- PUSH_INSN(ret, *location, pop);
- if (safe_label != NULL && !popped) PUSH_LABEL(ret, safe_label);
-}
-
-/**
- * When we're compiling a case node, it's possible that we can speed it up using
- * a dispatch hash, which will allow us to jump directly to the correct when
- * clause body based on a hash lookup of the value. This can only happen when
- * the conditions are literals that can be compiled into a hash key.
- *
- * This function accepts a dispatch hash and the condition of a when clause. It
- * is responsible for compiling the condition into a hash key and then adding it
- * to the dispatch hash.
- *
- * If the value can be successfully compiled into the hash, then this function
- * returns the dispatch hash with the new key added. If the value cannot be
- * compiled into the hash, then this function returns Qundef. In the case of
- * Qundef, this function is signaling that the caller should abandon the
- * optimization entirely.
- */
-static VALUE
-pm_compile_case_node_dispatch(rb_iseq_t *iseq, VALUE dispatch, const pm_node_t *node, LABEL *label, const pm_scope_node_t *scope_node)
-{
- VALUE key = Qundef;
-
- switch (PM_NODE_TYPE(node)) {
- case PM_FLOAT_NODE: {
- key = pm_static_literal_value(iseq, node, scope_node);
- double intptr;
-
- if (modf(RFLOAT_VALUE(key), &intptr) == 0.0) {
- key = (FIXABLE(intptr) ? LONG2FIX((long) intptr) : rb_dbl2big(intptr));
- }
-
- break;
- }
- case PM_FALSE_NODE:
- case PM_INTEGER_NODE:
- case PM_NIL_NODE:
- case PM_SOURCE_FILE_NODE:
- case PM_SOURCE_LINE_NODE:
- case PM_SYMBOL_NODE:
- case PM_TRUE_NODE:
- key = pm_static_literal_value(iseq, node, scope_node);
- break;
- case PM_STRING_NODE: {
- const pm_string_node_t *cast = (const pm_string_node_t *) node;
- key = parse_static_literal_string(iseq, scope_node, node, &cast->unescaped);
- break;
- }
- default:
- return Qundef;
- }
-
- if (NIL_P(rb_hash_lookup(dispatch, key))) {
- rb_hash_aset(dispatch, key, ((VALUE) label) | 1);
- }
-
- return dispatch;
-}
-
-/**
- * Compile a case node, representing a case statement with when clauses.
- */
-static inline void
-pm_compile_case_node(rb_iseq_t *iseq, const pm_case_node_t *cast, const pm_node_location_t *node_location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_parser_t *parser = scope_node->parser;
- const pm_node_location_t location = *node_location;
- const pm_node_list_t *conditions = &cast->conditions;
-
- // This is the anchor that we will compile the conditions of the various
- // `when` nodes into. If a match is found, they will need to jump into
- // the body_seq anchor to the correct spot.
- DECL_ANCHOR(cond_seq);
- INIT_ANCHOR(cond_seq);
-
- // This is the anchor that we will compile the bodies of the various
- // `when` nodes into. We'll make sure that the clauses that are compiled
- // jump into the correct spots within this anchor.
- DECL_ANCHOR(body_seq);
- INIT_ANCHOR(body_seq);
-
- // This is the label where all of the when clauses will jump to if they
- // have matched and are done executing their bodies.
- LABEL *end_label = NEW_LABEL(location.line);
-
- // If we have a predicate on this case statement, then it's going to
- // compare all of the various when clauses to the predicate. If we
- // don't, then it's basically an if-elsif-else chain.
- if (cast->predicate == NULL) {
- // Establish branch coverage for the case node.
- VALUE branches = Qfalse;
- rb_code_location_t case_location = { 0 };
- int branch_id = 0;
-
- if (PM_BRANCH_COVERAGE_P(iseq)) {
- case_location = pm_code_location(scope_node, (const pm_node_t *) cast);
- branches = decl_branch_base(iseq, PTR2NUM(cast), &case_location, "case");
- }
-
- // Loop through each clauses in the case node and compile each of
- // the conditions within them into cond_seq. If they match, they
- // should jump into their respective bodies in body_seq.
- for (size_t clause_index = 0; clause_index < conditions->size; clause_index++) {
- const pm_when_node_t *clause = (const pm_when_node_t *) conditions->nodes[clause_index];
- const pm_node_list_t *conditions = &clause->conditions;
-
- int clause_lineno = pm_node_line_number(parser, (const pm_node_t *) clause);
- LABEL *label = NEW_LABEL(clause_lineno);
- PUSH_LABEL(body_seq, label);
-
- // Establish branch coverage for the when clause.
- if (PM_BRANCH_COVERAGE_P(iseq)) {
- rb_code_location_t branch_location = pm_code_location(scope_node, clause->statements != NULL ? ((const pm_node_t *) clause->statements) : ((const pm_node_t *) clause));
- add_trace_branch_coverage(iseq, body_seq, &branch_location, branch_location.beg_pos.column, branch_id++, "when", branches);
- }
-
- if (clause->statements != NULL) {
- pm_compile_node(iseq, (const pm_node_t *) clause->statements, body_seq, popped, scope_node);
- }
- else if (!popped) {
- PUSH_SYNTHETIC_PUTNIL(body_seq, iseq);
- }
-
- PUSH_INSNL(body_seq, location, jump, end_label);
-
- // Compile each of the conditions for the when clause into the
- // cond_seq. Each one should have a unique condition and should
- // jump to the subsequent one if it doesn't match.
- for (size_t condition_index = 0; condition_index < conditions->size; condition_index++) {
- const pm_node_t *condition = conditions->nodes[condition_index];
-
- if (PM_NODE_TYPE_P(condition, PM_SPLAT_NODE)) {
- pm_node_location_t cond_location = PM_NODE_START_LOCATION(parser, condition);
- PUSH_INSN(cond_seq, cond_location, putnil);
- pm_compile_node(iseq, condition, cond_seq, false, scope_node);
- PUSH_INSN1(cond_seq, cond_location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_WHEN | VM_CHECKMATCH_ARRAY));
- PUSH_INSNL(cond_seq, cond_location, branchif, label);
- }
- else {
- LABEL *next_label = NEW_LABEL(pm_node_line_number(parser, condition));
- pm_compile_branch_condition(iseq, cond_seq, condition, label, next_label, false, scope_node);
- PUSH_LABEL(cond_seq, next_label);
- }
- }
- }
-
- // Establish branch coverage for the else clause (implicit or
- // explicit).
- if (PM_BRANCH_COVERAGE_P(iseq)) {
- rb_code_location_t branch_location;
-
- if (cast->else_clause == NULL) {
- branch_location = case_location;
- } else if (cast->else_clause->statements == NULL) {
- branch_location = pm_code_location(scope_node, (const pm_node_t *) cast->else_clause);
- } else {
- branch_location = pm_code_location(scope_node, (const pm_node_t *) cast->else_clause->statements);
- }
-
- add_trace_branch_coverage(iseq, cond_seq, &branch_location, branch_location.beg_pos.column, branch_id, "else", branches);
- }
-
- // Compile the else clause if there is one.
- if (cast->else_clause != NULL) {
- pm_compile_node(iseq, (const pm_node_t *) cast->else_clause, cond_seq, popped, scope_node);
- }
- else if (!popped) {
- PUSH_SYNTHETIC_PUTNIL(cond_seq, iseq);
- }
-
- // Finally, jump to the end label if none of the other conditions
- // have matched.
- PUSH_INSNL(cond_seq, location, jump, end_label);
- PUSH_SEQ(ret, cond_seq);
- }
- else {
- // Establish branch coverage for the case node.
- VALUE branches = Qfalse;
- rb_code_location_t case_location = { 0 };
- int branch_id = 0;
-
- if (PM_BRANCH_COVERAGE_P(iseq)) {
- case_location = pm_code_location(scope_node, (const pm_node_t *) cast);
- branches = decl_branch_base(iseq, PTR2NUM(cast), &case_location, "case");
- }
-
- // This is the label where everything will fall into if none of the
- // conditions matched.
- LABEL *else_label = NEW_LABEL(location.line);
-
- // It's possible for us to speed up the case node by using a
- // dispatch hash. This is a hash that maps the conditions of the
- // various when clauses to the labels of their bodies. If we can
- // compile the conditions into a hash key, then we can use a hash
- // lookup to jump directly to the correct when clause body.
- VALUE dispatch = Qundef;
- if (ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
- dispatch = rb_hash_new();
- RHASH_TBL_RAW(dispatch)->type = &cdhash_type;
- }
-
- // We're going to loop through each of the conditions in the case
- // node and compile each of their contents into both the cond_seq
- // and the body_seq. Each condition will use its own label to jump
- // from its conditions into its body.
- //
- // Note that none of the code in the loop below should be adding
- // anything to ret, as we're going to be laying out the entire case
- // node instructions later.
- for (size_t clause_index = 0; clause_index < conditions->size; clause_index++) {
- const pm_when_node_t *clause = (const pm_when_node_t *) conditions->nodes[clause_index];
- pm_node_location_t clause_location = PM_NODE_START_LOCATION(parser, (const pm_node_t *) clause);
-
- const pm_node_list_t *conditions = &clause->conditions;
- LABEL *label = NEW_LABEL(clause_location.line);
-
- // Compile each of the conditions for the when clause into the
- // cond_seq. Each one should have a unique comparison that then
- // jumps into the body if it matches.
- for (size_t condition_index = 0; condition_index < conditions->size; condition_index++) {
- const pm_node_t *condition = conditions->nodes[condition_index];
- const pm_node_location_t condition_location = PM_NODE_START_LOCATION(parser, condition);
-
- // If we haven't already abandoned the optimization, then
- // we're going to try to compile the condition into the
- // dispatch hash.
- if (dispatch != Qundef) {
- dispatch = pm_compile_case_node_dispatch(iseq, dispatch, condition, label, scope_node);
- }
-
- if (PM_NODE_TYPE_P(condition, PM_SPLAT_NODE)) {
- PUSH_INSN(cond_seq, condition_location, dup);
- pm_compile_node(iseq, condition, cond_seq, false, scope_node);
- PUSH_INSN1(cond_seq, condition_location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE | VM_CHECKMATCH_ARRAY));
- }
- else {
- if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
- const pm_string_node_t *string = (const pm_string_node_t *) condition;
- VALUE value = parse_static_literal_string(iseq, scope_node, condition, &string->unescaped);
- PUSH_INSN1(cond_seq, condition_location, putobject, value);
- }
- else {
- pm_compile_node(iseq, condition, cond_seq, false, scope_node);
- }
-
- PUSH_INSN1(cond_seq, condition_location, topn, INT2FIX(1));
- PUSH_SEND_WITH_FLAG(cond_seq, condition_location, idEqq, INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));
- }
-
- PUSH_INSNL(cond_seq, condition_location, branchif, label);
- }
-
- // Now, add the label to the body and compile the body of the
- // when clause. This involves popping the predicate, compiling
- // the statements to be executed, and then compiling a jump to
- // the end of the case node.
- PUSH_LABEL(body_seq, label);
- PUSH_INSN(body_seq, clause_location, pop);
-
- // Establish branch coverage for the when clause.
- if (PM_BRANCH_COVERAGE_P(iseq)) {
- rb_code_location_t branch_location = pm_code_location(scope_node, clause->statements != NULL ? ((const pm_node_t *) clause->statements) : ((const pm_node_t *) clause));
- add_trace_branch_coverage(iseq, body_seq, &branch_location, branch_location.beg_pos.column, branch_id++, "when", branches);
- }
-
- if (clause->statements != NULL) {
- pm_compile_node(iseq, (const pm_node_t *) clause->statements, body_seq, popped, scope_node);
- }
- else if (!popped) {
- PUSH_SYNTHETIC_PUTNIL(body_seq, iseq);
- }
-
- PUSH_INSNL(body_seq, clause_location, jump, end_label);
- }
-
- // Now that we have compiled the conditions and the bodies of the
- // various when clauses, we can compile the predicate, lay out the
- // conditions, compile the fallback subsequent if there is one, and
- // finally put in the bodies of the when clauses.
- PM_COMPILE_NOT_POPPED(cast->predicate);
-
- // If we have a dispatch hash, then we'll use it here to create the
- // optimization.
- if (dispatch != Qundef) {
- PUSH_INSN(ret, location, dup);
- PUSH_INSN2(ret, location, opt_case_dispatch, dispatch, else_label);
- LABEL_REF(else_label);
- }
-
- PUSH_SEQ(ret, cond_seq);
-
- // Compile either the explicit else clause or an implicit else
- // clause.
- PUSH_LABEL(ret, else_label);
-
- if (cast->else_clause != NULL) {
- pm_node_location_t else_location = PM_NODE_START_LOCATION(parser, cast->else_clause->statements != NULL ? ((const pm_node_t *) cast->else_clause->statements) : ((const pm_node_t *) cast->else_clause));
- PUSH_INSN(ret, else_location, pop);
-
- // Establish branch coverage for the else clause.
- if (PM_BRANCH_COVERAGE_P(iseq)) {
- rb_code_location_t branch_location = pm_code_location(scope_node, cast->else_clause->statements != NULL ? ((const pm_node_t *) cast->else_clause->statements) : ((const pm_node_t *) cast->else_clause));
- add_trace_branch_coverage(iseq, ret, &branch_location, branch_location.beg_pos.column, branch_id, "else", branches);
- }
-
- PM_COMPILE((const pm_node_t *) cast->else_clause);
- PUSH_INSNL(ret, else_location, jump, end_label);
- }
- else {
- PUSH_INSN(ret, location, pop);
-
- // Establish branch coverage for the implicit else clause.
- if (PM_BRANCH_COVERAGE_P(iseq)) {
- add_trace_branch_coverage(iseq, ret, &case_location, case_location.beg_pos.column, branch_id, "else", branches);
- }
-
- if (!popped) PUSH_INSN(ret, location, putnil);
- PUSH_INSNL(ret, location, jump, end_label);
- }
- }
-
- PUSH_SEQ(ret, body_seq);
- PUSH_LABEL(ret, end_label);
-}
-
-static inline void
-pm_compile_case_match_node(rb_iseq_t *iseq, const pm_case_match_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- // This is the anchor that we will compile the bodies of the various
- // `in` nodes into. We'll make sure that the patterns that are compiled
- // jump into the correct spots within this anchor.
- DECL_ANCHOR(body_seq);
- INIT_ANCHOR(body_seq);
-
- // This is the anchor that we will compile the patterns of the various
- // `in` nodes into. If a match is found, they will need to jump into the
- // body_seq anchor to the correct spot.
- DECL_ANCHOR(cond_seq);
- INIT_ANCHOR(cond_seq);
-
- // This label is used to indicate the end of the entire node. It is
- // jumped to after the entire stack is cleaned up.
- LABEL *end_label = NEW_LABEL(location->line);
-
- // This label is used as the fallback for the case match. If no match is
- // found, then we jump to this label. This is either an `else` clause or
- // an error handler.
- LABEL *else_label = NEW_LABEL(location->line);
-
- // We're going to use this to uniquely identify each branch so that we
- // can track coverage information.
- rb_code_location_t case_location = { 0 };
- VALUE branches = Qfalse;
- int branch_id = 0;
-
- if (PM_BRANCH_COVERAGE_P(iseq)) {
- case_location = pm_code_location(scope_node, (const pm_node_t *) node);
- branches = decl_branch_base(iseq, PTR2NUM(node), &case_location, "case");
- }
-
- // If there is only one pattern, then the behavior changes a bit. It
- // effectively gets treated as a match required node (this is how it is
- // represented in the other parser).
- bool in_single_pattern = node->else_clause == NULL && node->conditions.size == 1;
-
- // First, we're going to push a bunch of stuff onto the stack that is
- // going to serve as our scratch space.
- if (in_single_pattern) {
- PUSH_INSN(ret, *location, putnil); // key error key
- PUSH_INSN(ret, *location, putnil); // key error matchee
- PUSH_INSN1(ret, *location, putobject, Qfalse); // key error?
- PUSH_INSN(ret, *location, putnil); // error string
- }
-
- // Now we're going to compile the value to match against.
- PUSH_INSN(ret, *location, putnil); // deconstruct cache
- PM_COMPILE_NOT_POPPED(node->predicate);
-
- // Next, we'll loop through every in clause and compile its body into
- // the body_seq anchor and its pattern into the cond_seq anchor. We'll
- // make sure the pattern knows how to jump correctly into the body if it
- // finds a match.
- for (size_t index = 0; index < node->conditions.size; index++) {
- const pm_node_t *condition = node->conditions.nodes[index];
- RUBY_ASSERT(PM_NODE_TYPE_P(condition, PM_IN_NODE));
-
- const pm_in_node_t *in_node = (const pm_in_node_t *) condition;
- const pm_node_location_t in_location = PM_NODE_START_LOCATION(scope_node->parser, in_node);
- const pm_node_location_t pattern_location = PM_NODE_START_LOCATION(scope_node->parser, in_node->pattern);
-
- if (branch_id) {
- PUSH_INSN(body_seq, in_location, putnil);
- }
-
- LABEL *body_label = NEW_LABEL(in_location.line);
- PUSH_LABEL(body_seq, body_label);
- PUSH_INSN1(body_seq, in_location, adjuststack, INT2FIX(in_single_pattern ? 6 : 2));
-
- // Establish branch coverage for the in clause.
- if (PM_BRANCH_COVERAGE_P(iseq)) {
- rb_code_location_t branch_location = pm_code_location(scope_node, in_node->statements != NULL ? ((const pm_node_t *) in_node->statements) : ((const pm_node_t *) in_node));
- add_trace_branch_coverage(iseq, body_seq, &branch_location, branch_location.beg_pos.column, branch_id++, "in", branches);
- }
-
- if (in_node->statements != NULL) {
- PM_COMPILE_INTO_ANCHOR(body_seq, (const pm_node_t *) in_node->statements);
- }
- else if (!popped) {
- PUSH_SYNTHETIC_PUTNIL(body_seq, iseq);
- }
-
- PUSH_INSNL(body_seq, in_location, jump, end_label);
- LABEL *next_pattern_label = NEW_LABEL(pattern_location.line);
-
- PUSH_INSN(cond_seq, pattern_location, dup);
- pm_compile_pattern(iseq, scope_node, in_node->pattern, cond_seq, body_label, next_pattern_label, in_single_pattern, false, true, 2);
- PUSH_LABEL(cond_seq, next_pattern_label);
- LABEL_UNREMOVABLE(next_pattern_label);
- }
-
- if (node->else_clause != NULL) {
- // If we have an `else` clause, then this becomes our fallback (and
- // there is no need to compile in code to potentially raise an
- // error).
- const pm_else_node_t *else_node = node->else_clause;
-
- PUSH_LABEL(cond_seq, else_label);
- PUSH_INSN(cond_seq, *location, pop);
- PUSH_INSN(cond_seq, *location, pop);
-
- // Establish branch coverage for the else clause.
- if (PM_BRANCH_COVERAGE_P(iseq)) {
- rb_code_location_t branch_location = pm_code_location(scope_node, else_node->statements != NULL ? ((const pm_node_t *) else_node->statements) : ((const pm_node_t *) else_node));
- add_trace_branch_coverage(iseq, cond_seq, &branch_location, branch_location.beg_pos.column, branch_id, "else", branches);
- }
-
- PM_COMPILE_INTO_ANCHOR(cond_seq, (const pm_node_t *) else_node);
- PUSH_INSNL(cond_seq, *location, jump, end_label);
- PUSH_INSN(cond_seq, *location, putnil);
- if (popped) PUSH_INSN(cond_seq, *location, putnil);
- }
- else {
- // Otherwise, if we do not have an `else` clause, we will compile in
- // the code to handle raising an appropriate error.
- PUSH_LABEL(cond_seq, else_label);
-
- // Establish branch coverage for the implicit else clause.
- add_trace_branch_coverage(iseq, cond_seq, &case_location, case_location.beg_pos.column, branch_id, "else", branches);
-
- if (in_single_pattern) {
- pm_compile_pattern_error_handler(iseq, scope_node, (const pm_node_t *) node, cond_seq, end_label, popped);
- }
- else {
- PUSH_INSN1(cond_seq, *location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_INSN1(cond_seq, *location, putobject, rb_eNoMatchingPatternError);
- PUSH_INSN1(cond_seq, *location, topn, INT2FIX(2));
- PUSH_SEND(cond_seq, *location, id_core_raise, INT2FIX(2));
-
- PUSH_INSN1(cond_seq, *location, adjuststack, INT2FIX(3));
- if (!popped) PUSH_INSN(cond_seq, *location, putnil);
- PUSH_INSNL(cond_seq, *location, jump, end_label);
- PUSH_INSN1(cond_seq, *location, dupn, INT2FIX(1));
- if (popped) PUSH_INSN(cond_seq, *location, putnil);
- }
- }
-
- // At the end of all of this compilation, we will add the code for the
- // conditions first, then the various bodies, then mark the end of the
- // entire sequence with the end label.
- PUSH_SEQ(ret, cond_seq);
- PUSH_SEQ(ret, body_seq);
- PUSH_LABEL(ret, end_label);
-}
-
-static inline void
-pm_compile_forwarding_super_node(rb_iseq_t *iseq, const pm_forwarding_super_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const rb_iseq_t *block = NULL;
- const rb_iseq_t *previous_block = NULL;
- LABEL *retry_label = NULL;
- LABEL *retry_end_l = NULL;
-
- if (node->block != NULL) {
- previous_block = ISEQ_COMPILE_DATA(iseq)->current_block;
- ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
-
- retry_label = NEW_LABEL(location->line);
- retry_end_l = NEW_LABEL(location->line);
-
- PUSH_LABEL(ret, retry_label);
- }
- else {
- iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
- }
-
- PUSH_INSN(ret, *location, putself);
- int flag = VM_CALL_ZSUPER | VM_CALL_SUPER | VM_CALL_FCALL;
-
- if (node->block != NULL) {
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((const pm_node_t *) node->block, &next_scope_node, scope_node);
-
- ISEQ_COMPILE_DATA(iseq)->current_block = block = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, location->line);
- pm_scope_node_destroy(&next_scope_node);
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE) block);
- }
-
- DECL_ANCHOR(args);
- INIT_ANCHOR(args);
-
- struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
- const rb_iseq_t *local_iseq = body->local_iseq;
- const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(local_iseq);
-
- int argc = 0;
- int depth = get_lvar_level(iseq);
-
- if (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
- flag |= VM_CALL_FORWARDING;
- pm_local_index_t mult_local = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_DOT3, 0);
- PUSH_GETLOCAL(ret, *location, mult_local.index, mult_local.level);
-
- const struct rb_callinfo *callinfo = new_callinfo(iseq, 0, 0, flag, NULL, block != NULL);
- PUSH_INSN2(ret, *location, invokesuperforward, callinfo, block);
-
- if (popped) PUSH_INSN(ret, *location, pop);
- if (node->block) {
- ISEQ_COMPILE_DATA(iseq)->current_block = previous_block;
- }
- return;
- }
-
- if (local_body->param.flags.has_lead) {
- /* required arguments */
- for (int i = 0; i < local_body->param.lead_num; i++) {
- int idx = local_body->local_table_size - i;
- PUSH_GETLOCAL(args, *location, idx, depth);
- }
- argc += local_body->param.lead_num;
- }
-
- if (local_body->param.flags.has_opt) {
- /* optional arguments */
- for (int j = 0; j < local_body->param.opt_num; j++) {
- int idx = local_body->local_table_size - (argc + j);
- PUSH_GETLOCAL(args, *location, idx, depth);
- }
- argc += local_body->param.opt_num;
- }
-
- if (local_body->param.flags.has_rest) {
- /* rest argument */
- int idx = local_body->local_table_size - local_body->param.rest_start;
- PUSH_GETLOCAL(args, *location, idx, depth);
- PUSH_INSN1(args, *location, splatarray, Qfalse);
-
- argc = local_body->param.rest_start + 1;
- flag |= VM_CALL_ARGS_SPLAT;
- }
-
- if (local_body->param.flags.has_post) {
- /* post arguments */
- int post_len = local_body->param.post_num;
- int post_start = local_body->param.post_start;
-
- int j = 0;
- for (; j < post_len; j++) {
- int idx = local_body->local_table_size - (post_start + j);
- PUSH_GETLOCAL(args, *location, idx, depth);
- }
-
- if (local_body->param.flags.has_rest) {
- // argc remains unchanged from rest branch
- PUSH_INSN1(args, *location, newarray, INT2FIX(j));
- PUSH_INSN(args, *location, concatarray);
- }
- else {
- argc = post_len + post_start;
- }
- }
-
- const struct rb_iseq_param_keyword *const local_keyword = local_body->param.keyword;
- if (local_body->param.flags.has_kw) {
- int local_size = local_body->local_table_size;
- argc++;
-
- PUSH_INSN1(args, *location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
-
- if (local_body->param.flags.has_kwrest) {
- int idx = local_body->local_table_size - local_keyword->rest_start;
- PUSH_GETLOCAL(args, *location, idx, depth);
- RUBY_ASSERT(local_keyword->num > 0);
- PUSH_SEND(args, *location, rb_intern("dup"), INT2FIX(0));
- }
- else {
- PUSH_INSN1(args, *location, newhash, INT2FIX(0));
- }
- int i = 0;
- for (; i < local_keyword->num; ++i) {
- ID id = local_keyword->table[i];
- int idx = local_size - get_local_var_idx(local_iseq, id);
-
- {
- VALUE operand = ID2SYM(id);
- PUSH_INSN1(args, *location, putobject, operand);
- }
-
- PUSH_GETLOCAL(args, *location, idx, depth);
- }
-
- PUSH_SEND(args, *location, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
- flag |= VM_CALL_KW_SPLAT| VM_CALL_KW_SPLAT_MUT;
- }
- else if (local_body->param.flags.has_kwrest) {
- int idx = local_body->local_table_size - local_keyword->rest_start;
- PUSH_GETLOCAL(args, *location, idx, depth);
- argc++;
- flag |= VM_CALL_KW_SPLAT;
- }
-
- PUSH_SEQ(ret, args);
-
- {
- const struct rb_callinfo *callinfo = new_callinfo(iseq, 0, argc, flag, NULL, block != NULL);
- PUSH_INSN2(ret, *location, invokesuper, callinfo, block);
- }
-
- if (node->block != NULL) {
- pm_compile_retry_end_label(iseq, ret, retry_end_l);
- PUSH_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, block, retry_end_l);
- ISEQ_COMPILE_DATA(iseq)->current_block = previous_block;
- }
-
- if (popped) PUSH_INSN(ret, *location, pop);
-}
-
-static inline void
-pm_compile_match_required_node(rb_iseq_t *iseq, const pm_match_required_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- LABEL *matched_label = NEW_LABEL(location->line);
- LABEL *unmatched_label = NEW_LABEL(location->line);
- LABEL *done_label = NEW_LABEL(location->line);
-
- // First, we're going to push a bunch of stuff onto the stack that is
- // going to serve as our scratch space.
- PUSH_INSN(ret, *location, putnil); // key error key
- PUSH_INSN(ret, *location, putnil); // key error matchee
- PUSH_INSN1(ret, *location, putobject, Qfalse); // key error?
- PUSH_INSN(ret, *location, putnil); // error string
- PUSH_INSN(ret, *location, putnil); // deconstruct cache
-
- // Next we're going to compile the value expression such that it's on
- // the stack.
- PM_COMPILE_NOT_POPPED(node->value);
-
- // Here we'll dup it so that it can be used for comparison, but also be
- // used for error handling.
- PUSH_INSN(ret, *location, dup);
-
- // Next we'll compile the pattern. We indicate to the pm_compile_pattern
- // function that this is the only pattern that will be matched against
- // through the in_single_pattern parameter. We also indicate that the
- // value to compare against is 2 slots from the top of the stack (the
- // base_index parameter).
- pm_compile_pattern(iseq, scope_node, node->pattern, ret, matched_label, unmatched_label, true, false, true, 2);
-
- // If the pattern did not match the value, then we're going to compile
- // in our error handler code. This will determine which error to raise
- // and raise it.
- PUSH_LABEL(ret, unmatched_label);
- pm_compile_pattern_error_handler(iseq, scope_node, (const pm_node_t *) node, ret, done_label, popped);
-
- // If the pattern did match, we'll clean up the values we've pushed onto
- // the stack and then push nil onto the stack if it's not popped.
- PUSH_LABEL(ret, matched_label);
- PUSH_INSN1(ret, *location, adjuststack, INT2FIX(6));
- if (!popped) PUSH_INSN(ret, *location, putnil);
- PUSH_INSNL(ret, *location, jump, done_label);
-
- PUSH_LABEL(ret, done_label);
-}
-
-static inline void
-pm_compile_match_write_node(rb_iseq_t *iseq, const pm_match_write_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- LABEL *fail_label = NEW_LABEL(location->line);
- LABEL *end_label = NEW_LABEL(location->line);
-
- // First, we'll compile the call so that all of its instructions are
- // present. Then we'll compile all of the local variable targets.
- PM_COMPILE_NOT_POPPED((const pm_node_t *) node->call);
-
- // Now, check if the match was successful. If it was, then we'll
- // continue on and assign local variables. Otherwise we'll skip over the
- // assignment code.
- {
- VALUE operand = rb_id2sym(idBACKREF);
- PUSH_INSN1(ret, *location, getglobal, operand);
- }
-
- PUSH_INSN(ret, *location, dup);
- PUSH_INSNL(ret, *location, branchunless, fail_label);
-
- // If there's only a single local variable target, we can skip some of
- // the bookkeeping, so we'll put a special branch here.
- size_t targets_count = node->targets.size;
-
- if (targets_count == 1) {
- const pm_node_t *target = node->targets.nodes[0];
- RUBY_ASSERT(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_TARGET_NODE));
-
- const pm_local_variable_target_node_t *local_target = (const pm_local_variable_target_node_t *) target;
- pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, local_target->name, local_target->depth);
-
- {
- VALUE operand = rb_id2sym(pm_constant_id_lookup(scope_node, local_target->name));
- PUSH_INSN1(ret, *location, putobject, operand);
- }
-
- PUSH_SEND(ret, *location, idAREF, INT2FIX(1));
- PUSH_LABEL(ret, fail_label);
- PUSH_SETLOCAL(ret, *location, index.index, index.level);
- if (popped) PUSH_INSN(ret, *location, pop);
- return;
- }
-
- DECL_ANCHOR(fail_anchor);
- INIT_ANCHOR(fail_anchor);
-
- // Otherwise there is more than one local variable target, so we'll need
- // to do some bookkeeping.
- for (size_t targets_index = 0; targets_index < targets_count; targets_index++) {
- const pm_node_t *target = node->targets.nodes[targets_index];
- RUBY_ASSERT(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_TARGET_NODE));
-
- const pm_local_variable_target_node_t *local_target = (const pm_local_variable_target_node_t *) target;
- pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, local_target->name, local_target->depth);
-
- if (((size_t) targets_index) < (targets_count - 1)) {
- PUSH_INSN(ret, *location, dup);
- }
-
- {
- VALUE operand = rb_id2sym(pm_constant_id_lookup(scope_node, local_target->name));
- PUSH_INSN1(ret, *location, putobject, operand);
- }
-
- PUSH_SEND(ret, *location, idAREF, INT2FIX(1));
- PUSH_SETLOCAL(ret, *location, index.index, index.level);
-
- PUSH_INSN(fail_anchor, *location, putnil);
- PUSH_SETLOCAL(fail_anchor, *location, index.index, index.level);
- }
-
- // Since we matched successfully, now we'll jump to the end.
- PUSH_INSNL(ret, *location, jump, end_label);
-
- // In the case that the match failed, we'll loop through each local
- // variable target and set all of them to `nil`.
- PUSH_LABEL(ret, fail_label);
- PUSH_INSN(ret, *location, pop);
- PUSH_SEQ(ret, fail_anchor);
-
- // Finally, we can push the end label for either case.
- PUSH_LABEL(ret, end_label);
- if (popped) PUSH_INSN(ret, *location, pop);
-}
-
-static inline void
-pm_compile_next_node(rb_iseq_t *iseq, const pm_next_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
- LABEL *splabel = NEW_LABEL(0);
- PUSH_LABEL(ret, splabel);
-
- if (node->arguments) {
- PM_COMPILE_NOT_POPPED((const pm_node_t *) node->arguments);
- }
- else {
- PUSH_INSN(ret, *location, putnil);
- }
- pm_add_ensure_iseq(ret, iseq, 0, scope_node);
-
- PUSH_ADJUST(ret, *location, ISEQ_COMPILE_DATA(iseq)->redo_label);
- PUSH_INSNL(ret, *location, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
-
- PUSH_ADJUST_RESTORE(ret, splabel);
- if (!popped) PUSH_INSN(ret, *location, putnil);
- }
- else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
- LABEL *splabel = NEW_LABEL(0);
-
- PUSH_LABEL(ret, splabel);
- PUSH_ADJUST(ret, *location, ISEQ_COMPILE_DATA(iseq)->start_label);
-
- if (node->arguments != NULL) {
- PM_COMPILE_NOT_POPPED((const pm_node_t *) node->arguments);
- }
- else {
- PUSH_INSN(ret, *location, putnil);
- }
-
- pm_add_ensure_iseq(ret, iseq, 0, scope_node);
- PUSH_INSNL(ret, *location, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
- PUSH_ADJUST_RESTORE(ret, splabel);
- splabel->unremovable = FALSE;
-
- if (!popped) PUSH_INSN(ret, *location, putnil);
- }
- else {
- const rb_iseq_t *ip = iseq;
- unsigned long throw_flag = 0;
-
- while (ip) {
- if (!ISEQ_COMPILE_DATA(ip)) {
- ip = 0;
- break;
- }
-
- throw_flag = VM_THROW_NO_ESCAPE_FLAG;
- if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
- /* while loop */
- break;
- }
- else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
- break;
- }
- else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
- COMPILE_ERROR(iseq, location->line, "Invalid next");
- return;
- }
-
- ip = ISEQ_BODY(ip)->parent_iseq;
- }
-
- if (ip != 0) {
- if (node->arguments) {
- PM_COMPILE_NOT_POPPED((const pm_node_t *) node->arguments);
- }
- else {
- PUSH_INSN(ret, *location, putnil);
- }
-
- PUSH_INSN1(ret, *location, throw, INT2FIX(throw_flag | TAG_NEXT));
- if (popped) PUSH_INSN(ret, *location, pop);
- }
- else {
- COMPILE_ERROR(iseq, location->line, "Invalid next");
- }
- }
-}
-
-static inline void
-pm_compile_redo_node(rb_iseq_t *iseq, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
- LABEL *splabel = NEW_LABEL(0);
-
- PUSH_LABEL(ret, splabel);
- PUSH_ADJUST(ret, *location, ISEQ_COMPILE_DATA(iseq)->redo_label);
- pm_add_ensure_iseq(ret, iseq, 0, scope_node);
-
- PUSH_INSNL(ret, *location, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
- PUSH_ADJUST_RESTORE(ret, splabel);
- if (!popped) PUSH_INSN(ret, *location, putnil);
- }
- else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
- LABEL *splabel = NEW_LABEL(0);
-
- PUSH_LABEL(ret, splabel);
- pm_add_ensure_iseq(ret, iseq, 0, scope_node);
- PUSH_ADJUST(ret, *location, ISEQ_COMPILE_DATA(iseq)->start_label);
-
- PUSH_INSNL(ret, *location, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
- PUSH_ADJUST_RESTORE(ret, splabel);
- if (!popped) PUSH_INSN(ret, *location, putnil);
- }
- else {
- const rb_iseq_t *ip = iseq;
-
- while (ip) {
- if (!ISEQ_COMPILE_DATA(ip)) {
- ip = 0;
- break;
- }
-
- if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
- break;
- }
- else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
- break;
- }
- else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
- COMPILE_ERROR(iseq, location->line, "Invalid redo");
- return;
- }
-
- ip = ISEQ_BODY(ip)->parent_iseq;
- }
-
- if (ip != 0) {
- PUSH_INSN(ret, *location, putnil);
- PUSH_INSN1(ret, *location, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
- if (popped) PUSH_INSN(ret, *location, pop);
- }
- else {
- COMPILE_ERROR(iseq, location->line, "Invalid redo");
- }
- }
-}
-
-static inline void
-pm_compile_rescue_node(rb_iseq_t *iseq, const pm_rescue_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- iseq_set_exception_local_table(iseq);
-
- // First, establish the labels that we need to be able to jump to within
- // this compilation block.
- LABEL *exception_match_label = NEW_LABEL(location->line);
- LABEL *rescue_end_label = NEW_LABEL(location->line);
-
- // Next, compile each of the exceptions that we're going to be
- // handling. For each one, we'll add instructions to check if the
- // exception matches the raised one, and if it does then jump to the
- // exception_match_label label. Otherwise it will fall through to the
- // subsequent check. If there are no exceptions, we'll only check
- // StandardError.
- const pm_node_list_t *exceptions = &node->exceptions;
-
- if (exceptions->size > 0) {
- for (size_t index = 0; index < exceptions->size; index++) {
- PUSH_GETLOCAL(ret, *location, LVAR_ERRINFO, 0);
- PM_COMPILE(exceptions->nodes[index]);
- int checkmatch_flags = VM_CHECKMATCH_TYPE_RESCUE;
- if (PM_NODE_TYPE_P(exceptions->nodes[index], PM_SPLAT_NODE)) {
- checkmatch_flags |= VM_CHECKMATCH_ARRAY;
- }
- PUSH_INSN1(ret, *location, checkmatch, INT2FIX(checkmatch_flags));
- PUSH_INSNL(ret, *location, branchif, exception_match_label);
- }
- }
- else {
- PUSH_GETLOCAL(ret, *location, LVAR_ERRINFO, 0);
- PUSH_INSN1(ret, *location, putobject, rb_eStandardError);
- PUSH_INSN1(ret, *location, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
- PUSH_INSNL(ret, *location, branchif, exception_match_label);
- }
-
- // If none of the exceptions that we are matching against matched, then
- // we'll jump straight to the rescue_end_label label.
- PUSH_INSNL(ret, *location, jump, rescue_end_label);
-
- // Here we have the exception_match_label, which is where the
- // control-flow goes in the case that one of the exceptions matched.
- // Here we will compile the instructions to handle the exception.
- PUSH_LABEL(ret, exception_match_label);
- PUSH_TRACE(ret, RUBY_EVENT_RESCUE);
-
- // If we have a reference to the exception, then we'll compile the write
- // into the instruction sequence. This can look quite different
- // depending on the kind of write being performed.
- if (node->reference) {
- DECL_ANCHOR(writes);
- INIT_ANCHOR(writes);
-
- DECL_ANCHOR(cleanup);
- INIT_ANCHOR(cleanup);
-
- pm_compile_target_node(iseq, node->reference, ret, writes, cleanup, scope_node, NULL);
- PUSH_GETLOCAL(ret, *location, LVAR_ERRINFO, 0);
-
- PUSH_SEQ(ret, writes);
- PUSH_SEQ(ret, cleanup);
- }
-
- // If we have statements to execute, we'll compile them here. Otherwise
- // we'll push nil onto the stack.
- if (node->statements != NULL) {
- // We'll temporarily remove the end_label location from the iseq
- // when compiling the statements so that next/redo statements
- // inside the body will throw to the correct place instead of
- // jumping straight to the end of this iseq
- LABEL *prev_end = ISEQ_COMPILE_DATA(iseq)->end_label;
- ISEQ_COMPILE_DATA(iseq)->end_label = NULL;
-
- PM_COMPILE((const pm_node_t *) node->statements);
-
- // Now restore the end_label
- ISEQ_COMPILE_DATA(iseq)->end_label = prev_end;
- }
- else {
- PUSH_INSN(ret, *location, putnil);
- }
-
- PUSH_INSN(ret, *location, leave);
-
- // Here we'll insert the rescue_end_label label, which is jumped to if
- // none of the exceptions matched. It will cause the control-flow to
- // either jump to the next rescue clause or it will fall through to the
- // subsequent instruction returning the raised error.
- PUSH_LABEL(ret, rescue_end_label);
- if (node->subsequent != NULL) {
- PM_COMPILE((const pm_node_t *) node->subsequent);
- }
- else {
- PUSH_GETLOCAL(ret, *location, 1, 0);
- }
-}
-
-static inline void
-pm_compile_return_node(rb_iseq_t *iseq, const pm_return_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_arguments_node_t *arguments = node->arguments;
- enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
- LABEL *splabel = 0;
-
- const rb_iseq_t *parent_iseq = iseq;
- enum rb_iseq_type parent_type = ISEQ_BODY(parent_iseq)->type;
- while (parent_type == ISEQ_TYPE_RESCUE || parent_type == ISEQ_TYPE_ENSURE) {
- if (!(parent_iseq = ISEQ_BODY(parent_iseq)->parent_iseq)) break;
- parent_type = ISEQ_BODY(parent_iseq)->type;
- }
-
- switch (parent_type) {
- case ISEQ_TYPE_TOP:
- case ISEQ_TYPE_MAIN:
- if (arguments) {
- rb_warn("argument of top-level return is ignored");
- }
- if (parent_iseq == iseq) {
- type = ISEQ_TYPE_METHOD;
- }
- break;
- default:
- break;
- }
-
- if (type == ISEQ_TYPE_METHOD) {
- splabel = NEW_LABEL(0);
- PUSH_LABEL(ret, splabel);
- PUSH_ADJUST(ret, *location, 0);
- }
-
- if (arguments != NULL) {
- PM_COMPILE_NOT_POPPED((const pm_node_t *) arguments);
- }
- else {
- PUSH_INSN(ret, *location, putnil);
- }
-
- if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
- pm_add_ensure_iseq(ret, iseq, 1, scope_node);
- PUSH_TRACE(ret, RUBY_EVENT_RETURN);
- PUSH_INSN(ret, *location, leave);
- PUSH_ADJUST_RESTORE(ret, splabel);
- if (!popped) PUSH_INSN(ret, *location, putnil);
- }
- else {
- PUSH_INSN1(ret, *location, throw, INT2FIX(TAG_RETURN));
- if (popped) PUSH_INSN(ret, *location, pop);
- }
-}
-
-static inline void
-pm_compile_super_node(rb_iseq_t *iseq, const pm_super_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- DECL_ANCHOR(args);
- INIT_ANCHOR(args);
-
- LABEL *retry_label = NEW_LABEL(location->line);
- LABEL *retry_end_l = NEW_LABEL(location->line);
-
- const rb_iseq_t *previous_block = ISEQ_COMPILE_DATA(iseq)->current_block;
- const rb_iseq_t *current_block;
- ISEQ_COMPILE_DATA(iseq)->current_block = current_block = NULL;
-
- PUSH_LABEL(ret, retry_label);
- PUSH_INSN(ret, *location, putself);
-
- int flags = 0;
- struct rb_callinfo_kwarg *keywords = NULL;
- int argc = pm_setup_args(node->arguments, node->block, &flags, &keywords, iseq, ret, scope_node, location);
- bool is_forwardable = (node->arguments != NULL) && PM_NODE_FLAG_P(node->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
- flags |= VM_CALL_SUPER | VM_CALL_FCALL;
-
- if (node->block && PM_NODE_TYPE_P(node->block, PM_BLOCK_NODE)) {
- pm_scope_node_t next_scope_node;
- pm_scope_node_init(node->block, &next_scope_node, scope_node);
-
- ISEQ_COMPILE_DATA(iseq)->current_block = current_block = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, location->line);
- pm_scope_node_destroy(&next_scope_node);
- }
-
- if (!node->block) {
- iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
- }
-
- if ((flags & VM_CALL_ARGS_BLOCKARG) && (flags & VM_CALL_KW_SPLAT) && !(flags & VM_CALL_KW_SPLAT_MUT)) {
- PUSH_INSN(args, *location, splatkw);
- }
-
- PUSH_SEQ(ret, args);
- if (is_forwardable && ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->param.flags.forwardable) {
- flags |= VM_CALL_FORWARDING;
-
- {
- const struct rb_callinfo *callinfo = new_callinfo(iseq, 0, argc, flags, keywords, current_block != NULL);
- PUSH_INSN2(ret, *location, invokesuperforward, callinfo, current_block);
- }
- }
- else {
- {
- const struct rb_callinfo *callinfo = new_callinfo(iseq, 0, argc, flags, keywords, current_block != NULL);
- PUSH_INSN2(ret, *location, invokesuper, callinfo, current_block);
- }
-
- }
-
- pm_compile_retry_end_label(iseq, ret, retry_end_l);
-
- if (popped) PUSH_INSN(ret, *location, pop);
- ISEQ_COMPILE_DATA(iseq)->current_block = previous_block;
- PUSH_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, current_block, retry_end_l);
-}
-
-static inline void
-pm_compile_yield_node(rb_iseq_t *iseq, const pm_yield_node_t *node, const pm_node_location_t *location, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- switch (ISEQ_BODY(ISEQ_BODY(iseq)->local_iseq)->type) {
- case ISEQ_TYPE_TOP:
- case ISEQ_TYPE_MAIN:
- case ISEQ_TYPE_CLASS:
- COMPILE_ERROR(iseq, location->line, "Invalid yield");
- return;
- default: /* valid */;
- }
-
- int argc = 0;
- int flags = 0;
- struct rb_callinfo_kwarg *keywords = NULL;
-
- if (node->arguments) {
- argc = pm_setup_args(node->arguments, NULL, &flags, &keywords, iseq, ret, scope_node, location);
- }
-
- const struct rb_callinfo *callinfo = new_callinfo(iseq, 0, argc, flags, keywords, FALSE);
- PUSH_INSN1(ret, *location, invokeblock, callinfo);
-
- iseq_set_use_block(ISEQ_BODY(iseq)->local_iseq);
- if (popped) PUSH_INSN(ret, *location, pop);
-
- int level = 0;
- for (const rb_iseq_t *tmp_iseq = iseq; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++) {
- tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
- }
-
- if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
-}
-
-/**
- * Compiles a prism node into instruction sequences.
- *
- * iseq - The current instruction sequence object (used for locals)
- * node - The prism node to compile
- * ret - The linked list of instructions to append instructions onto
- * popped - True if compiling something with no side effects, so instructions don't
- * need to be added
- * scope_node - Stores parser and local information
- */
-static void
-pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, bool popped, pm_scope_node_t *scope_node)
-{
- const pm_parser_t *parser = scope_node->parser;
- const pm_node_location_t location = PM_NODE_START_LOCATION(parser, node);
- int lineno = (int) location.line;
-
- if (PM_NODE_TYPE_P(node, PM_BEGIN_NODE) && (((const pm_begin_node_t *) node)->statements == NULL) && (((const pm_begin_node_t *) node)->rescue_clause != NULL)) {
- // If this node is a begin node and it has empty statements and also
- // has a rescue clause, then the other parser considers it as
- // starting on the same line as the rescue, as opposed to the
- // location of the begin keyword. We replicate that behavior here.
- lineno = (int) PM_NODE_START_LINE_COLUMN(parser, ((const pm_begin_node_t *) node)->rescue_clause).line;
- }
-
- if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_NEWLINE) && ISEQ_COMPILE_DATA(iseq)->last_line != lineno) {
- // If this node has the newline flag set and it is on a new line
- // from the previous nodes that have been compiled for this ISEQ,
- // then we need to emit a newline event.
- int event = RUBY_EVENT_LINE;
-
- ISEQ_COMPILE_DATA(iseq)->last_line = lineno;
- if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
- event |= RUBY_EVENT_COVERAGE_LINE;
- }
- PUSH_TRACE(ret, event);
- }
-
- switch (PM_NODE_TYPE(node)) {
- case PM_ALIAS_GLOBAL_VARIABLE_NODE:
- // alias $foo $bar
- // ^^^^^^^^^^^^^^^
- pm_compile_alias_global_variable_node(iseq, (const pm_alias_global_variable_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_ALIAS_METHOD_NODE:
- // alias foo bar
- // ^^^^^^^^^^^^^
- pm_compile_alias_method_node(iseq, (const pm_alias_method_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_AND_NODE:
- // a and b
- // ^^^^^^^
- pm_compile_and_node(iseq, (const pm_and_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_ARGUMENTS_NODE: {
- // break foo
- // ^^^
- //
- // These are ArgumentsNodes that are not compiled directly by their
- // parent call nodes, used in the cases of NextNodes, ReturnNodes, and
- // BreakNodes. They can create an array like ArrayNode.
- const pm_arguments_node_t *cast = (const pm_arguments_node_t *) node;
- const pm_node_list_t *elements = &cast->arguments;
-
- if (elements->size == 1) {
- // If we are only returning a single element through one of the jump
- // nodes, then we will only compile that node directly.
- PM_COMPILE(elements->nodes[0]);
- }
- else {
- pm_compile_array_node(iseq, (const pm_node_t *) cast, elements, &location, ret, popped, scope_node);
- }
- return;
- }
- case PM_ARRAY_NODE: {
- // [foo, bar, baz]
- // ^^^^^^^^^^^^^^^
- const pm_array_node_t *cast = (const pm_array_node_t *) node;
- pm_compile_array_node(iseq, (const pm_node_t *) cast, &cast->elements, &location, ret, popped, scope_node);
- return;
- }
- case PM_ASSOC_NODE: {
- // { foo: 1 }
- // ^^^^^^
- //
- // foo(bar: 1)
- // ^^^^^^
- const pm_assoc_node_t *cast = (const pm_assoc_node_t *) node;
-
- PM_COMPILE(cast->key);
- PM_COMPILE(cast->value);
-
- return;
- }
- case PM_ASSOC_SPLAT_NODE: {
- // { **foo }
- // ^^^^^
- //
- // def foo(**); bar(**); end
- // ^^
- const pm_assoc_splat_node_t *cast = (const pm_assoc_splat_node_t *) node;
-
- if (cast->value != NULL) {
- PM_COMPILE(cast->value);
- }
- else if (!popped) {
- pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_POW, 0);
- PUSH_GETLOCAL(ret, location, index.index, index.level);
- }
-
- return;
- }
- case PM_BACK_REFERENCE_READ_NODE: {
- // $+
- // ^^
- if (!popped) {
- // Since a back reference is `$<char>`, ruby represents the ID as the
- // an rb_intern on the value after the `$`.
- char *char_ptr = (char *)(node->location.start) + 1;
- ID backref_val = INT2FIX(rb_intern2(char_ptr, 1)) << 1 | 1;
- PUSH_INSN2(ret, location, getspecial, INT2FIX(1), backref_val);
- }
- return;
- }
- case PM_BEGIN_NODE: {
- // begin end
- // ^^^^^^^^^
- const pm_begin_node_t *cast = (const pm_begin_node_t *) node;
-
- if (cast->ensure_clause) {
- // Compiling the ensure clause will compile the rescue clause (if
- // there is one), which will compile the begin statements.
- pm_compile_ensure(iseq, cast, &location, ret, popped, scope_node);
- }
- else if (cast->rescue_clause) {
- // Compiling rescue will compile begin statements (if applicable).
- pm_compile_rescue(iseq, cast, &location, ret, popped, scope_node);
- }
- else {
- // If there is neither ensure or rescue, the just compile the
- // statements.
- if (cast->statements != NULL) {
- PM_COMPILE((const pm_node_t *) cast->statements);
- }
- else if (!popped) {
- PUSH_SYNTHETIC_PUTNIL(ret, iseq);
- }
- }
- return;
- }
- case PM_BLOCK_ARGUMENT_NODE: {
- // foo(&bar)
- // ^^^^
- const pm_block_argument_node_t *cast = (const pm_block_argument_node_t *) node;
-
- if (cast->expression != NULL) {
- PM_COMPILE(cast->expression);
- }
- else {
- // If there's no expression, this must be block forwarding.
- pm_local_index_t local_index = pm_lookup_local_index(iseq, scope_node, PM_CONSTANT_AND, 0);
- PUSH_INSN2(ret, location, getblockparamproxy, INT2FIX(local_index.index + VM_ENV_DATA_SIZE - 1), INT2FIX(local_index.level));
- }
- return;
- }
- case PM_BREAK_NODE:
- // break
- // ^^^^^
- //
- // break foo
- // ^^^^^^^^^
- pm_compile_break_node(iseq, (const pm_break_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_CALL_NODE:
- // foo
- // ^^^
- //
- // foo.bar
- // ^^^^^^^
- //
- // foo.bar() {}
- // ^^^^^^^^^^^^
- pm_compile_call_node(iseq, (const pm_call_node_t *) node, ret, popped, scope_node);
- return;
- case PM_CALL_AND_WRITE_NODE: {
- // foo.bar &&= baz
- // ^^^^^^^^^^^^^^^
- const pm_call_and_write_node_t *cast = (const pm_call_and_write_node_t *) node;
- pm_compile_call_and_or_write_node(iseq, true, cast->receiver, cast->value, cast->write_name, cast->read_name, PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION), &location, ret, popped, scope_node);
- return;
- }
- case PM_CALL_OR_WRITE_NODE: {
- // foo.bar ||= baz
- // ^^^^^^^^^^^^^^^
- const pm_call_or_write_node_t *cast = (const pm_call_or_write_node_t *) node;
- pm_compile_call_and_or_write_node(iseq, false, cast->receiver, cast->value, cast->write_name, cast->read_name, PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION), &location, ret, popped, scope_node);
- return;
- }
- case PM_CALL_OPERATOR_WRITE_NODE:
- // foo.bar += baz
- // ^^^^^^^^^^^^^^^
- //
- // Call operator writes occur when you have a call node on the left-hand
- // side of a write operator that is not `=`. As an example,
- // `foo.bar *= 1`. This breaks down to caching the receiver on the
- // stack and then performing three method calls, one to read the value,
- // one to compute the result, and one to write the result back to the
- // receiver.
- pm_compile_call_operator_write_node(iseq, (const pm_call_operator_write_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_CASE_NODE:
- // case foo; when bar; end
- // ^^^^^^^^^^^^^^^^^^^^^^^
- pm_compile_case_node(iseq, (const pm_case_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_CASE_MATCH_NODE:
- // case foo; in bar; end
- // ^^^^^^^^^^^^^^^^^^^^^
- //
- // If you use the `case` keyword to create a case match node, it will
- // match against all of the `in` clauses until it finds one that
- // matches. If it doesn't find one, it can optionally fall back to an
- // `else` clause. If none is present and a match wasn't found, it will
- // raise an appropriate error.
- pm_compile_case_match_node(iseq, (const pm_case_match_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_CLASS_NODE: {
- // class Foo; end
- // ^^^^^^^^^^^^^^
- const pm_class_node_t *cast = (const pm_class_node_t *) node;
-
- ID class_id = pm_constant_id_lookup(scope_node, cast->name);
- VALUE class_name = rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(class_id)));
-
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((const pm_node_t *) cast, &next_scope_node, scope_node);
-
- const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(&next_scope_node, class_name, ISEQ_TYPE_CLASS, location.line);
- pm_scope_node_destroy(&next_scope_node);
-
- // TODO: Once we merge constant path nodes correctly, fix this flag
- const int flags = VM_DEFINECLASS_TYPE_CLASS |
- (cast->superclass ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
- pm_compile_class_path(iseq, cast->constant_path, &location, ret, false, scope_node);
-
- if (cast->superclass) {
- PM_COMPILE_NOT_POPPED(cast->superclass);
- }
- else {
- PUSH_INSN(ret, location, putnil);
- }
-
- {
- VALUE operand = ID2SYM(class_id);
- PUSH_INSN3(ret, location, defineclass, operand, class_iseq, INT2FIX(flags));
- }
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
-
- if (popped) PUSH_INSN(ret, location, pop);
- return;
- }
- case PM_CLASS_VARIABLE_AND_WRITE_NODE: {
- // @@foo &&= bar
- // ^^^^^^^^^^^^^
- const pm_class_variable_and_write_node_t *cast = (const pm_class_variable_and_write_node_t *) node;
- LABEL *end_label = NEW_LABEL(location.line);
-
- ID name_id = pm_constant_id_lookup(scope_node, cast->name);
- VALUE name = ID2SYM(name_id);
-
- PUSH_INSN2(ret, location, getclassvariable, name, get_cvar_ic_value(iseq, name_id));
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSNL(ret, location, branchunless, end_label);
- if (!popped) PUSH_INSN(ret, location, pop);
-
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSN2(ret, location, setclassvariable, name, get_cvar_ic_value(iseq, name_id));
- PUSH_LABEL(ret, end_label);
-
- return;
- }
- case PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE: {
- // @@foo += bar
- // ^^^^^^^^^^^^
- const pm_class_variable_operator_write_node_t *cast = (const pm_class_variable_operator_write_node_t *) node;
-
- ID name_id = pm_constant_id_lookup(scope_node, cast->name);
- VALUE name = ID2SYM(name_id);
-
- PUSH_INSN2(ret, location, getclassvariable, name, get_cvar_ic_value(iseq, name_id));
- PM_COMPILE_NOT_POPPED(cast->value);
-
- ID method_id = pm_constant_id_lookup(scope_node, cast->binary_operator);
- int flags = VM_CALL_ARGS_SIMPLE;
- PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2NUM(1), INT2FIX(flags));
-
- if (!popped) PUSH_INSN(ret, location, dup);
- PUSH_INSN2(ret, location, setclassvariable, name, get_cvar_ic_value(iseq, name_id));
-
- return;
- }
- case PM_CLASS_VARIABLE_OR_WRITE_NODE: {
- // @@foo ||= bar
- // ^^^^^^^^^^^^^
- const pm_class_variable_or_write_node_t *cast = (const pm_class_variable_or_write_node_t *) node;
- LABEL *end_label = NEW_LABEL(location.line);
- LABEL *start_label = NEW_LABEL(location.line);
-
- ID name_id = pm_constant_id_lookup(scope_node, cast->name);
- VALUE name = ID2SYM(name_id);
-
- PUSH_INSN(ret, location, putnil);
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_CVAR), name, Qtrue);
- PUSH_INSNL(ret, location, branchunless, start_label);
-
- PUSH_INSN2(ret, location, getclassvariable, name, get_cvar_ic_value(iseq, name_id));
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSNL(ret, location, branchif, end_label);
- if (!popped) PUSH_INSN(ret, location, pop);
-
- PUSH_LABEL(ret, start_label);
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSN2(ret, location, setclassvariable, name, get_cvar_ic_value(iseq, name_id));
- PUSH_LABEL(ret, end_label);
-
- return;
- }
- case PM_CLASS_VARIABLE_READ_NODE: {
- // @@foo
- // ^^^^^
- if (!popped) {
- const pm_class_variable_read_node_t *cast = (const pm_class_variable_read_node_t *) node;
- ID name = pm_constant_id_lookup(scope_node, cast->name);
- PUSH_INSN2(ret, location, getclassvariable, ID2SYM(name), get_cvar_ic_value(iseq, name));
- }
- return;
- }
- case PM_CLASS_VARIABLE_WRITE_NODE: {
- // @@foo = 1
- // ^^^^^^^^^
- const pm_class_variable_write_node_t *cast = (const pm_class_variable_write_node_t *) node;
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- ID name = pm_constant_id_lookup(scope_node, cast->name);
- PUSH_INSN2(ret, location, setclassvariable, ID2SYM(name), get_cvar_ic_value(iseq, name));
-
- return;
- }
- case PM_CONSTANT_PATH_NODE: {
- // Foo::Bar
- // ^^^^^^^^
- VALUE parts;
-
- if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache && ((parts = pm_constant_path_parts(node, scope_node)) != Qnil)) {
- ISEQ_BODY(iseq)->ic_size++;
- PUSH_INSN1(ret, location, opt_getconstant_path, parts);
- }
- else {
- DECL_ANCHOR(prefix);
- INIT_ANCHOR(prefix);
-
- DECL_ANCHOR(body);
- INIT_ANCHOR(body);
-
- pm_compile_constant_path(iseq, node, prefix, body, popped, scope_node);
- if (LIST_INSN_SIZE_ZERO(prefix)) {
- PUSH_INSN(ret, location, putnil);
- }
- else {
- PUSH_SEQ(ret, prefix);
- }
-
- PUSH_SEQ(ret, body);
- }
-
- if (popped) PUSH_INSN(ret, location, pop);
- return;
- }
- case PM_CONSTANT_PATH_AND_WRITE_NODE: {
- // Foo::Bar &&= baz
- // ^^^^^^^^^^^^^^^^
- const pm_constant_path_and_write_node_t *cast = (const pm_constant_path_and_write_node_t *) node;
- pm_compile_constant_path_and_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
- return;
- }
- case PM_CONSTANT_PATH_OR_WRITE_NODE: {
- // Foo::Bar ||= baz
- // ^^^^^^^^^^^^^^^^
- const pm_constant_path_or_write_node_t *cast = (const pm_constant_path_or_write_node_t *) node;
- pm_compile_constant_path_or_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
- return;
- }
- case PM_CONSTANT_PATH_OPERATOR_WRITE_NODE: {
- // Foo::Bar += baz
- // ^^^^^^^^^^^^^^^
- const pm_constant_path_operator_write_node_t *cast = (const pm_constant_path_operator_write_node_t *) node;
- pm_compile_constant_path_operator_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
- return;
- }
- case PM_CONSTANT_PATH_WRITE_NODE: {
- // Foo::Bar = 1
- // ^^^^^^^^^^^^
- const pm_constant_path_write_node_t *cast = (const pm_constant_path_write_node_t *) node;
- pm_compile_constant_path_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
- return;
- }
- case PM_CONSTANT_READ_NODE: {
- // Foo
- // ^^^
- const pm_constant_read_node_t *cast = (const pm_constant_read_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
-
- pm_compile_constant_read(iseq, name, &cast->base.location, location.node_id, ret, scope_node);
- if (popped) PUSH_INSN(ret, location, pop);
-
- return;
- }
- case PM_CONSTANT_AND_WRITE_NODE: {
- // Foo &&= bar
- // ^^^^^^^^^^^
- const pm_constant_and_write_node_t *cast = (const pm_constant_and_write_node_t *) node;
- pm_compile_constant_and_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
- return;
- }
- case PM_CONSTANT_OR_WRITE_NODE: {
- // Foo ||= bar
- // ^^^^^^^^^^^
- const pm_constant_or_write_node_t *cast = (const pm_constant_or_write_node_t *) node;
- pm_compile_constant_or_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
- return;
- }
- case PM_CONSTANT_OPERATOR_WRITE_NODE: {
- // Foo += bar
- // ^^^^^^^^^^
- const pm_constant_operator_write_node_t *cast = (const pm_constant_operator_write_node_t *) node;
- pm_compile_constant_operator_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
- return;
- }
- case PM_CONSTANT_WRITE_NODE: {
- // Foo = 1
- // ^^^^^^^
- const pm_constant_write_node_t *cast = (const pm_constant_write_node_t *) node;
- pm_compile_constant_write_node(iseq, cast, 0, &location, ret, popped, scope_node);
- return;
- }
- case PM_DEF_NODE: {
- // def foo; end
- // ^^^^^^^^^^^^
- //
- // def self.foo; end
- // ^^^^^^^^^^^^^^^^^
- const pm_def_node_t *cast = (const pm_def_node_t *) node;
- ID method_name = pm_constant_id_lookup(scope_node, cast->name);
-
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((const pm_node_t *) cast, &next_scope_node, scope_node);
-
- rb_iseq_t *method_iseq = NEW_ISEQ(&next_scope_node, rb_id2str(method_name), ISEQ_TYPE_METHOD, location.line);
- pm_scope_node_destroy(&next_scope_node);
-
- if (cast->receiver) {
- PM_COMPILE_NOT_POPPED(cast->receiver);
- PUSH_INSN2(ret, location, definesmethod, ID2SYM(method_name), method_iseq);
- }
- else {
- PUSH_INSN2(ret, location, definemethod, ID2SYM(method_name), method_iseq);
- }
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE) method_iseq);
-
- if (!popped) {
- PUSH_INSN1(ret, location, putobject, ID2SYM(method_name));
- }
-
- return;
- }
- case PM_DEFINED_NODE: {
- // defined?(a)
- // ^^^^^^^^^^^
- const pm_defined_node_t *cast = (const pm_defined_node_t *) node;
- pm_compile_defined_expr(iseq, cast->value, &location, ret, popped, scope_node, false);
- return;
- }
- case PM_EMBEDDED_STATEMENTS_NODE: {
- // "foo #{bar}"
- // ^^^^^^
- const pm_embedded_statements_node_t *cast = (const pm_embedded_statements_node_t *) node;
-
- if (cast->statements != NULL) {
- PM_COMPILE((const pm_node_t *) (cast->statements));
- }
- else {
- PUSH_SYNTHETIC_PUTNIL(ret, iseq);
- }
-
- if (popped) PUSH_INSN(ret, location, pop);
- return;
- }
- case PM_EMBEDDED_VARIABLE_NODE: {
- // "foo #@bar"
- // ^^^^^
- const pm_embedded_variable_node_t *cast = (const pm_embedded_variable_node_t *) node;
- PM_COMPILE(cast->variable);
- return;
- }
- case PM_FALSE_NODE: {
- // false
- // ^^^^^
- if (!popped) {
- PUSH_INSN1(ret, location, putobject, Qfalse);
- }
- return;
- }
- case PM_ENSURE_NODE: {
- const pm_ensure_node_t *cast = (const pm_ensure_node_t *) node;
-
- if (cast->statements != NULL) {
- LABEL *start = NEW_LABEL(location.line);
- LABEL *end = NEW_LABEL(location.line);
- PUSH_LABEL(ret, start);
-
- LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
- ISEQ_COMPILE_DATA(iseq)->end_label = end;
-
- PM_COMPILE((const pm_node_t *) cast->statements);
- ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
- PUSH_LABEL(ret, end);
- }
-
- return;
- }
- case PM_ELSE_NODE: {
- // if foo then bar else baz end
- // ^^^^^^^^^^^^
- const pm_else_node_t *cast = (const pm_else_node_t *) node;
-
- if (cast->statements != NULL) {
- PM_COMPILE((const pm_node_t *) cast->statements);
- }
- else if (!popped) {
- PUSH_SYNTHETIC_PUTNIL(ret, iseq);
- }
-
- return;
- }
- case PM_FLIP_FLOP_NODE: {
- // if foo .. bar; end
- // ^^^^^^^^^^
- const pm_flip_flop_node_t *cast = (const pm_flip_flop_node_t *) node;
-
- LABEL *final_label = NEW_LABEL(location.line);
- LABEL *then_label = NEW_LABEL(location.line);
- LABEL *else_label = NEW_LABEL(location.line);
-
- pm_compile_flip_flop(cast, else_label, then_label, iseq, location.line, ret, popped, scope_node);
-
- PUSH_LABEL(ret, then_label);
- PUSH_INSN1(ret, location, putobject, Qtrue);
- PUSH_INSNL(ret, location, jump, final_label);
- PUSH_LABEL(ret, else_label);
- PUSH_INSN1(ret, location, putobject, Qfalse);
- PUSH_LABEL(ret, final_label);
-
- return;
- }
- case PM_FLOAT_NODE: {
- // 1.0
- // ^^^
- if (!popped) {
- VALUE operand = parse_float((const pm_float_node_t *) node);
- PUSH_INSN1(ret, location, putobject, operand);
- }
- return;
- }
- case PM_FOR_NODE: {
- // for foo in bar do end
- // ^^^^^^^^^^^^^^^^^^^^^
- const pm_for_node_t *cast = (const pm_for_node_t *) node;
-
- LABEL *retry_label = NEW_LABEL(location.line);
- LABEL *retry_end_l = NEW_LABEL(location.line);
-
- // First, compile the collection that we're going to be iterating over.
- PUSH_LABEL(ret, retry_label);
- PM_COMPILE_NOT_POPPED(cast->collection);
-
- // Next, create the new scope that is going to contain the block that
- // will be passed to the each method.
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((const pm_node_t *) cast, &next_scope_node, scope_node);
-
- const rb_iseq_t *child_iseq = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, location.line);
- pm_scope_node_destroy(&next_scope_node);
-
- const rb_iseq_t *prev_block = ISEQ_COMPILE_DATA(iseq)->current_block;
- ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq;
-
- // Now, create the method call to each that will be used to iterate over
- // the collection, and pass the newly created iseq as the block.
- PUSH_SEND_WITH_BLOCK(ret, location, idEach, INT2FIX(0), child_iseq);
- pm_compile_retry_end_label(iseq, ret, retry_end_l);
-
- if (popped) PUSH_INSN(ret, location, pop);
- ISEQ_COMPILE_DATA(iseq)->current_block = prev_block;
- PUSH_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
- return;
- }
- case PM_FORWARDING_ARGUMENTS_NODE:
- rb_bug("Cannot compile a ForwardingArgumentsNode directly\n");
- return;
- case PM_FORWARDING_SUPER_NODE:
- // super
- // ^^^^^
- //
- // super {}
- // ^^^^^^^^
- pm_compile_forwarding_super_node(iseq, (const pm_forwarding_super_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_GLOBAL_VARIABLE_AND_WRITE_NODE: {
- // $foo &&= bar
- // ^^^^^^^^^^^^
- const pm_global_variable_and_write_node_t *cast = (const pm_global_variable_and_write_node_t *) node;
- LABEL *end_label = NEW_LABEL(location.line);
-
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
- PUSH_INSN1(ret, location, getglobal, name);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSNL(ret, location, branchunless, end_label);
- if (!popped) PUSH_INSN(ret, location, pop);
-
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSN1(ret, location, setglobal, name);
- PUSH_LABEL(ret, end_label);
-
- return;
- }
- case PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE: {
- // $foo += bar
- // ^^^^^^^^^^^
- const pm_global_variable_operator_write_node_t *cast = (const pm_global_variable_operator_write_node_t *) node;
-
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
- PUSH_INSN1(ret, location, getglobal, name);
- PM_COMPILE_NOT_POPPED(cast->value);
-
- ID method_id = pm_constant_id_lookup(scope_node, cast->binary_operator);
- int flags = VM_CALL_ARGS_SIMPLE;
- PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2NUM(1), INT2FIX(flags));
-
- if (!popped) PUSH_INSN(ret, location, dup);
- PUSH_INSN1(ret, location, setglobal, name);
-
- return;
- }
- case PM_GLOBAL_VARIABLE_OR_WRITE_NODE: {
- // $foo ||= bar
- // ^^^^^^^^^^^^
- const pm_global_variable_or_write_node_t *cast = (const pm_global_variable_or_write_node_t *) node;
- LABEL *set_label = NEW_LABEL(location.line);
- LABEL *end_label = NEW_LABEL(location.line);
-
- PUSH_INSN(ret, location, putnil);
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
-
- PUSH_INSN3(ret, location, defined, INT2FIX(DEFINED_GVAR), name, Qtrue);
- PUSH_INSNL(ret, location, branchunless, set_label);
-
- PUSH_INSN1(ret, location, getglobal, name);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSNL(ret, location, branchif, end_label);
- if (!popped) PUSH_INSN(ret, location, pop);
-
- PUSH_LABEL(ret, set_label);
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSN1(ret, location, setglobal, name);
- PUSH_LABEL(ret, end_label);
-
- return;
- }
- case PM_GLOBAL_VARIABLE_READ_NODE: {
- // $foo
- // ^^^^
- const pm_global_variable_read_node_t *cast = (const pm_global_variable_read_node_t *) node;
- VALUE name = ID2SYM(pm_constant_id_lookup(scope_node, cast->name));
-
- PUSH_INSN1(ret, location, getglobal, name);
- if (popped) PUSH_INSN(ret, location, pop);
-
- return;
- }
- case PM_GLOBAL_VARIABLE_WRITE_NODE: {
- // $foo = 1
- // ^^^^^^^^
- const pm_global_variable_write_node_t *cast = (const pm_global_variable_write_node_t *) node;
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- ID name = pm_constant_id_lookup(scope_node, cast->name);
- PUSH_INSN1(ret, location, setglobal, ID2SYM(name));
-
- return;
- }
- case PM_HASH_NODE: {
- // {}
- // ^^
- //
- // If every node in the hash is static, then we can compile the entire
- // hash now instead of later.
- if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
- // We're only going to compile this node if it's not popped. If it
- // is popped, then we know we don't need to do anything since it's
- // statically known.
- if (!popped) {
- const pm_hash_node_t *cast = (const pm_hash_node_t *) node;
-
- if (cast->elements.size == 0) {
- PUSH_INSN1(ret, location, newhash, INT2FIX(0));
- }
- else {
- VALUE value = pm_static_literal_value(iseq, node, scope_node);
- PUSH_INSN1(ret, location, duphash, value);
- RB_OBJ_WRITTEN(iseq, Qundef, value);
- }
- }
- }
- else {
- // Here since we know there are possible side-effects inside the
- // hash contents, we're going to build it entirely at runtime. We'll
- // do this by pushing all of the key-value pairs onto the stack and
- // then combining them with newhash.
- //
- // If this hash is popped, then this serves only to ensure we enact
- // all side-effects (like method calls) that are contained within
- // the hash contents.
- const pm_hash_node_t *cast = (const pm_hash_node_t *) node;
- const pm_node_list_t *elements = &cast->elements;
-
- if (popped) {
- // If this hash is popped, then we can iterate through each
- // element and compile it. The result of each compilation will
- // only include the side effects of the element itself.
- for (size_t index = 0; index < elements->size; index++) {
- PM_COMPILE_POPPED(elements->nodes[index]);
- }
- }
- else {
- pm_compile_hash_elements(iseq, node, elements, false, ret, scope_node);
- }
- }
-
- return;
- }
- case PM_IF_NODE: {
- // if foo then bar end
- // ^^^^^^^^^^^^^^^^^^^
- //
- // bar if foo
- // ^^^^^^^^^^
- //
- // foo ? bar : baz
- // ^^^^^^^^^^^^^^^
- const pm_if_node_t *cast = (const pm_if_node_t *) node;
- pm_compile_conditional(iseq, &location, PM_IF_NODE, (const pm_node_t *) cast, cast->statements, cast->subsequent, cast->predicate, ret, popped, scope_node);
- return;
- }
- case PM_IMAGINARY_NODE: {
- // 1i
- // ^^
- if (!popped) {
- VALUE operand = parse_imaginary((const pm_imaginary_node_t *) node);
- PUSH_INSN1(ret, location, putobject, operand);
- }
- return;
- }
- case PM_IMPLICIT_NODE: {
- // Implicit nodes mark places in the syntax tree where explicit syntax
- // was omitted, but implied. For example,
- //
- // { foo: }
- //
- // In this case a method call/local variable read is implied by virtue
- // of the missing value. To compile these nodes, we simply compile the
- // value that is implied, which is helpfully supplied by the parser.
- const pm_implicit_node_t *cast = (const pm_implicit_node_t *) node;
- PM_COMPILE(cast->value);
- return;
- }
- case PM_IN_NODE: {
- // In nodes are handled by the case match node directly, so we should
- // never end up hitting them through this path.
- rb_bug("Should not ever enter an in node directly");
- return;
- }
- case PM_INDEX_OPERATOR_WRITE_NODE: {
- // foo[bar] += baz
- // ^^^^^^^^^^^^^^^
- const pm_index_operator_write_node_t *cast = (const pm_index_operator_write_node_t *) node;
- pm_compile_index_operator_write_node(iseq, cast, &location, ret, popped, scope_node);
- return;
- }
- case PM_INDEX_AND_WRITE_NODE: {
- // foo[bar] &&= baz
- // ^^^^^^^^^^^^^^^^
- const pm_index_and_write_node_t *cast = (const pm_index_and_write_node_t *) node;
- pm_compile_index_control_flow_write_node(iseq, node, cast->receiver, cast->arguments, cast->block, cast->value, &location, ret, popped, scope_node);
- return;
- }
- case PM_INDEX_OR_WRITE_NODE: {
- // foo[bar] ||= baz
- // ^^^^^^^^^^^^^^^^
- const pm_index_or_write_node_t *cast = (const pm_index_or_write_node_t *) node;
- pm_compile_index_control_flow_write_node(iseq, node, cast->receiver, cast->arguments, cast->block, cast->value, &location, ret, popped, scope_node);
- return;
- }
- case PM_INSTANCE_VARIABLE_AND_WRITE_NODE: {
- // @foo &&= bar
- // ^^^^^^^^^^^^
- const pm_instance_variable_and_write_node_t *cast = (const pm_instance_variable_and_write_node_t *) node;
- LABEL *end_label = NEW_LABEL(location.line);
-
- ID name_id = pm_constant_id_lookup(scope_node, cast->name);
- VALUE name = ID2SYM(name_id);
-
- PUSH_INSN2(ret, location, getinstancevariable, name, get_ivar_ic_value(iseq, name_id));
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSNL(ret, location, branchunless, end_label);
- if (!popped) PUSH_INSN(ret, location, pop);
-
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSN2(ret, location, setinstancevariable, name, get_ivar_ic_value(iseq, name_id));
- PUSH_LABEL(ret, end_label);
-
- return;
- }
- case PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE: {
- // @foo += bar
- // ^^^^^^^^^^^
- const pm_instance_variable_operator_write_node_t *cast = (const pm_instance_variable_operator_write_node_t *) node;
-
- ID name_id = pm_constant_id_lookup(scope_node, cast->name);
- VALUE name = ID2SYM(name_id);
-
- PUSH_INSN2(ret, location, getinstancevariable, name, get_ivar_ic_value(iseq, name_id));
- PM_COMPILE_NOT_POPPED(cast->value);
-
- ID method_id = pm_constant_id_lookup(scope_node, cast->binary_operator);
- int flags = VM_CALL_ARGS_SIMPLE;
- PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2NUM(1), INT2FIX(flags));
-
- if (!popped) PUSH_INSN(ret, location, dup);
- PUSH_INSN2(ret, location, setinstancevariable, name, get_ivar_ic_value(iseq, name_id));
-
- return;
- }
- case PM_INSTANCE_VARIABLE_OR_WRITE_NODE: {
- // @foo ||= bar
- // ^^^^^^^^^^^^
- const pm_instance_variable_or_write_node_t *cast = (const pm_instance_variable_or_write_node_t *) node;
- LABEL *end_label = NEW_LABEL(location.line);
-
- ID name_id = pm_constant_id_lookup(scope_node, cast->name);
- VALUE name = ID2SYM(name_id);
-
- PUSH_INSN2(ret, location, getinstancevariable, name, get_ivar_ic_value(iseq, name_id));
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSNL(ret, location, branchif, end_label);
- if (!popped) PUSH_INSN(ret, location, pop);
-
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSN2(ret, location, setinstancevariable, name, get_ivar_ic_value(iseq, name_id));
- PUSH_LABEL(ret, end_label);
-
- return;
- }
- case PM_INSTANCE_VARIABLE_READ_NODE: {
- // @foo
- // ^^^^
- if (!popped) {
- const pm_instance_variable_read_node_t *cast = (const pm_instance_variable_read_node_t *) node;
- ID name = pm_constant_id_lookup(scope_node, cast->name);
- PUSH_INSN2(ret, location, getinstancevariable, ID2SYM(name), get_ivar_ic_value(iseq, name));
- }
- return;
- }
- case PM_INSTANCE_VARIABLE_WRITE_NODE: {
- // @foo = 1
- // ^^^^^^^^
- const pm_instance_variable_write_node_t *cast = (const pm_instance_variable_write_node_t *) node;
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- ID name = pm_constant_id_lookup(scope_node, cast->name);
- PUSH_INSN2(ret, location, setinstancevariable, ID2SYM(name), get_ivar_ic_value(iseq, name));
-
- return;
- }
- case PM_INTEGER_NODE: {
- // 1
- // ^
- if (!popped) {
- VALUE operand = parse_integer((const pm_integer_node_t *) node);
- PUSH_INSN1(ret, location, putobject, operand);
- }
- return;
- }
- case PM_INTERPOLATED_MATCH_LAST_LINE_NODE: {
- // if /foo #{bar}/ then end
- // ^^^^^^^^^^^^
- if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
- if (!popped) {
- VALUE regexp = pm_static_literal_value(iseq, node, scope_node);
- PUSH_INSN1(ret, location, putobject, regexp);
- }
- }
- else {
- pm_compile_regexp_dynamic(iseq, node, &((const pm_interpolated_match_last_line_node_t *) node)->parts, &location, ret, popped, scope_node);
- }
-
- PUSH_INSN1(ret, location, getglobal, rb_id2sym(idLASTLINE));
- PUSH_SEND(ret, location, idEqTilde, INT2NUM(1));
- if (popped) PUSH_INSN(ret, location, pop);
-
- return;
- }
- case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
- // /foo #{bar}/
- // ^^^^^^^^^^^^
- if (PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_ONCE)) {
- const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
- const rb_iseq_t *block_iseq = NULL;
- int ise_index = ISEQ_BODY(iseq)->ise_size++;
-
- pm_scope_node_t next_scope_node;
- pm_scope_node_init(node, &next_scope_node, scope_node);
-
- block_iseq = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, location.line);
- pm_scope_node_destroy(&next_scope_node);
-
- ISEQ_COMPILE_DATA(iseq)->current_block = block_iseq;
- PUSH_INSN2(ret, location, once, block_iseq, INT2FIX(ise_index));
- ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
-
- if (popped) PUSH_INSN(ret, location, pop);
- return;
- }
-
- if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
- if (!popped) {
- VALUE regexp = pm_static_literal_value(iseq, node, scope_node);
- PUSH_INSN1(ret, location, putobject, regexp);
- }
- }
- else {
- pm_compile_regexp_dynamic(iseq, node, &((const pm_interpolated_regular_expression_node_t *) node)->parts, &location, ret, popped, scope_node);
- if (popped) PUSH_INSN(ret, location, pop);
- }
-
- return;
- }
- case PM_INTERPOLATED_STRING_NODE: {
- // "foo #{bar}"
- // ^^^^^^^^^^^^
- if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
- if (!popped) {
- VALUE string = pm_static_literal_value(iseq, node, scope_node);
-
- if (PM_NODE_FLAG_P(node, PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN)) {
- PUSH_INSN1(ret, location, putobject, string);
- }
- else if (PM_NODE_FLAG_P(node, PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE)) {
- PUSH_INSN1(ret, location, putstring, string);
- }
- else {
- PUSH_INSN1(ret, location, putchilledstring, string);
- }
- }
- }
- else {
- const pm_interpolated_string_node_t *cast = (const pm_interpolated_string_node_t *) node;
- int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL);
- if (length > 1) PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
- if (popped) PUSH_INSN(ret, location, pop);
- }
-
- return;
- }
- case PM_INTERPOLATED_SYMBOL_NODE: {
- // :"foo #{bar}"
- // ^^^^^^^^^^^^^
- const pm_interpolated_symbol_node_t *cast = (const pm_interpolated_symbol_node_t *) node;
- int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, popped, scope_node, NULL, NULL);
-
- if (length > 1) {
- PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
- }
-
- if (!popped) {
- PUSH_INSN(ret, location, intern);
- }
- else {
- PUSH_INSN(ret, location, pop);
- }
-
- return;
- }
- case PM_INTERPOLATED_X_STRING_NODE: {
- // `foo #{bar}`
- // ^^^^^^^^^^^^
- const pm_interpolated_x_string_node_t *cast = (const pm_interpolated_x_string_node_t *) node;
-
- PUSH_INSN(ret, location, putself);
-
- int length = pm_interpolated_node_compile(iseq, &cast->parts, &location, ret, false, scope_node, NULL, NULL);
- if (length > 1) PUSH_INSN1(ret, location, concatstrings, INT2FIX(length));
-
- PUSH_SEND_WITH_FLAG(ret, location, idBackquote, INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));
- if (popped) PUSH_INSN(ret, location, pop);
-
- return;
- }
- case PM_IT_LOCAL_VARIABLE_READ_NODE: {
- // -> { it }
- // ^^
- if (!popped) {
- PUSH_GETLOCAL(ret, location, scope_node->local_table_for_iseq_size, 0);
- }
-
- return;
- }
- case PM_KEYWORD_HASH_NODE: {
- // foo(bar: baz)
- // ^^^^^^^^
- const pm_keyword_hash_node_t *cast = (const pm_keyword_hash_node_t *) node;
- const pm_node_list_t *elements = &cast->elements;
-
- const pm_node_t *element;
- PM_NODE_LIST_FOREACH(elements, index, element) {
- PM_COMPILE(element);
- }
-
- if (!popped) PUSH_INSN1(ret, location, newhash, INT2FIX(elements->size * 2));
- return;
- }
- case PM_LAMBDA_NODE: {
- // -> {}
- // ^^^^^
- const pm_lambda_node_t *cast = (const pm_lambda_node_t *) node;
-
- pm_scope_node_t next_scope_node;
- pm_scope_node_init(node, &next_scope_node, scope_node);
-
- int opening_lineno = pm_location_line_number(parser, &cast->opening_loc);
- const rb_iseq_t *block = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, opening_lineno);
- pm_scope_node_destroy(&next_scope_node);
-
- VALUE argc = INT2FIX(0);
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_CALL_WITH_BLOCK(ret, location, idLambda, argc, block);
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE) block);
-
- if (popped) PUSH_INSN(ret, location, pop);
- return;
- }
- case PM_LOCAL_VARIABLE_AND_WRITE_NODE: {
- // foo &&= bar
- // ^^^^^^^^^^^
- const pm_local_variable_and_write_node_t *cast = (const pm_local_variable_and_write_node_t *) node;
- LABEL *end_label = NEW_LABEL(location.line);
-
- pm_local_index_t local_index = pm_lookup_local_index(iseq, scope_node, cast->name, cast->depth);
- PUSH_GETLOCAL(ret, location, local_index.index, local_index.level);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSNL(ret, location, branchunless, end_label);
- if (!popped) PUSH_INSN(ret, location, pop);
-
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_SETLOCAL(ret, location, local_index.index, local_index.level);
- PUSH_LABEL(ret, end_label);
-
- return;
- }
- case PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE: {
- // foo += bar
- // ^^^^^^^^^^
- const pm_local_variable_operator_write_node_t *cast = (const pm_local_variable_operator_write_node_t *) node;
-
- pm_local_index_t local_index = pm_lookup_local_index(iseq, scope_node, cast->name, cast->depth);
- PUSH_GETLOCAL(ret, location, local_index.index, local_index.level);
-
- PM_COMPILE_NOT_POPPED(cast->value);
-
- ID method_id = pm_constant_id_lookup(scope_node, cast->binary_operator);
- PUSH_SEND_WITH_FLAG(ret, location, method_id, INT2NUM(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
-
- if (!popped) PUSH_INSN(ret, location, dup);
- PUSH_SETLOCAL(ret, location, local_index.index, local_index.level);
-
- return;
- }
- case PM_LOCAL_VARIABLE_OR_WRITE_NODE: {
- // foo ||= bar
- // ^^^^^^^^^^^
- const pm_local_variable_or_write_node_t *cast = (const pm_local_variable_or_write_node_t *) node;
-
- LABEL *set_label = NEW_LABEL(location.line);
- LABEL *end_label = NEW_LABEL(location.line);
-
- PUSH_INSN1(ret, location, putobject, Qtrue);
- PUSH_INSNL(ret, location, branchunless, set_label);
-
- pm_local_index_t local_index = pm_lookup_local_index(iseq, scope_node, cast->name, cast->depth);
- PUSH_GETLOCAL(ret, location, local_index.index, local_index.level);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_INSNL(ret, location, branchif, end_label);
- if (!popped) PUSH_INSN(ret, location, pop);
-
- PUSH_LABEL(ret, set_label);
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_SETLOCAL(ret, location, local_index.index, local_index.level);
- PUSH_LABEL(ret, end_label);
-
- return;
- }
- case PM_LOCAL_VARIABLE_READ_NODE: {
- // foo
- // ^^^
- if (!popped) {
- const pm_local_variable_read_node_t *cast = (const pm_local_variable_read_node_t *) node;
- pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, cast->name, cast->depth);
- PUSH_GETLOCAL(ret, location, index.index, index.level);
- }
-
- return;
- }
- case PM_LOCAL_VARIABLE_WRITE_NODE: {
- // foo = 1
- // ^^^^^^^
- const pm_local_variable_write_node_t *cast = (const pm_local_variable_write_node_t *) node;
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, cast->name, cast->depth);
- PUSH_SETLOCAL(ret, location, index.index, index.level);
- return;
- }
- case PM_MATCH_LAST_LINE_NODE: {
- // if /foo/ then end
- // ^^^^^
- VALUE regexp = pm_static_literal_value(iseq, node, scope_node);
-
- PUSH_INSN1(ret, location, putobject, regexp);
- PUSH_INSN2(ret, location, getspecial, INT2FIX(0), INT2FIX(0));
- PUSH_SEND(ret, location, idEqTilde, INT2NUM(1));
- if (popped) PUSH_INSN(ret, location, pop);
-
- return;
- }
- case PM_MATCH_PREDICATE_NODE: {
- // foo in bar
- // ^^^^^^^^^^
- const pm_match_predicate_node_t *cast = (const pm_match_predicate_node_t *) node;
-
- // First, allocate some stack space for the cached return value of any
- // calls to #deconstruct.
- PUSH_INSN(ret, location, putnil);
-
- // Next, compile the expression that we're going to match against.
- PM_COMPILE_NOT_POPPED(cast->value);
- PUSH_INSN(ret, location, dup);
-
- // Now compile the pattern that is going to be used to match against the
- // expression.
- LABEL *matched_label = NEW_LABEL(location.line);
- LABEL *unmatched_label = NEW_LABEL(location.line);
- LABEL *done_label = NEW_LABEL(location.line);
- pm_compile_pattern(iseq, scope_node, cast->pattern, ret, matched_label, unmatched_label, false, false, true, 2);
-
- // If the pattern did not match, then compile the necessary instructions
- // to handle pushing false onto the stack, then jump to the end.
- PUSH_LABEL(ret, unmatched_label);
- PUSH_INSN(ret, location, pop);
- PUSH_INSN(ret, location, pop);
-
- if (!popped) PUSH_INSN1(ret, location, putobject, Qfalse);
- PUSH_INSNL(ret, location, jump, done_label);
- PUSH_INSN(ret, location, putnil);
-
- // If the pattern did match, then compile the necessary instructions to
- // handle pushing true onto the stack, then jump to the end.
- PUSH_LABEL(ret, matched_label);
- PUSH_INSN1(ret, location, adjuststack, INT2FIX(2));
- if (!popped) PUSH_INSN1(ret, location, putobject, Qtrue);
- PUSH_INSNL(ret, location, jump, done_label);
-
- PUSH_LABEL(ret, done_label);
- return;
- }
- case PM_MATCH_REQUIRED_NODE:
- // foo => bar
- // ^^^^^^^^^^
- //
- // A match required node represents pattern matching against a single
- // pattern using the => operator. For example,
- //
- // foo => bar
- //
- // This is somewhat analogous to compiling a case match statement with a
- // single pattern. In both cases, if the pattern fails it should
- // immediately raise an error.
- pm_compile_match_required_node(iseq, (const pm_match_required_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_MATCH_WRITE_NODE:
- // /(?<foo>foo)/ =~ bar
- // ^^^^^^^^^^^^^^^^^^^^
- //
- // Match write nodes are specialized call nodes that have a regular
- // expression with valid named capture groups on the left, the =~
- // operator, and some value on the right. The nodes themselves simply
- // wrap the call with the local variable targets that will be written
- // when the call is executed.
- pm_compile_match_write_node(iseq, (const pm_match_write_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_MISSING_NODE:
- rb_bug("A pm_missing_node_t should not exist in prism's AST.");
- return;
- case PM_MODULE_NODE: {
- // module Foo; end
- // ^^^^^^^^^^^^^^^
- const pm_module_node_t *cast = (const pm_module_node_t *) node;
-
- ID module_id = pm_constant_id_lookup(scope_node, cast->name);
- VALUE module_name = rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(module_id)));
-
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((const pm_node_t *) cast, &next_scope_node, scope_node);
-
- const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(&next_scope_node, module_name, ISEQ_TYPE_CLASS, location.line);
- pm_scope_node_destroy(&next_scope_node);
-
- const int flags = VM_DEFINECLASS_TYPE_MODULE | pm_compile_class_path(iseq, cast->constant_path, &location, ret, false, scope_node);
- PUSH_INSN(ret, location, putnil);
- PUSH_INSN3(ret, location, defineclass, ID2SYM(module_id), module_iseq, INT2FIX(flags));
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE) module_iseq);
-
- if (popped) PUSH_INSN(ret, location, pop);
- return;
- }
- case PM_REQUIRED_PARAMETER_NODE: {
- // def foo(bar); end
- // ^^^
- const pm_required_parameter_node_t *cast = (const pm_required_parameter_node_t *) node;
- pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, cast->name, 0);
-
- PUSH_SETLOCAL(ret, location, index.index, index.level);
- return;
- }
- case PM_MULTI_WRITE_NODE: {
- // foo, bar = baz
- // ^^^^^^^^^^^^^^
- //
- // A multi write node represents writing to multiple values using an =
- // operator. Importantly these nodes are only parsed when the left-hand
- // side of the operator has multiple targets. The right-hand side of the
- // operator having multiple targets represents an implicit array
- // instead.
- const pm_multi_write_node_t *cast = (const pm_multi_write_node_t *) node;
-
- DECL_ANCHOR(writes);
- INIT_ANCHOR(writes);
-
- DECL_ANCHOR(cleanup);
- INIT_ANCHOR(cleanup);
-
- pm_multi_target_state_t state = { 0 };
- state.position = popped ? 0 : 1;
- pm_compile_multi_target_node(iseq, node, ret, writes, cleanup, scope_node, &state);
-
- PM_COMPILE_NOT_POPPED(cast->value);
- if (!popped) PUSH_INSN(ret, location, dup);
-
- PUSH_SEQ(ret, writes);
- if (!popped && state.stack_size >= 1) {
- // Make sure the value on the right-hand side of the = operator is
- // being returned before we pop the parent expressions.
- PUSH_INSN1(ret, location, setn, INT2FIX(state.stack_size));
- }
-
- // Now, we need to go back and modify the topn instructions in order to
- // ensure they can correctly retrieve the parent expressions.
- pm_multi_target_state_update(&state);
-
- PUSH_SEQ(ret, cleanup);
- return;
- }
- case PM_NEXT_NODE:
- // next
- // ^^^^
- //
- // next foo
- // ^^^^^^^^
- pm_compile_next_node(iseq, (const pm_next_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_NIL_NODE: {
- // nil
- // ^^^
- if (!popped) {
- PUSH_INSN(ret, location, putnil);
- }
-
- return;
- }
- case PM_NO_KEYWORDS_PARAMETER_NODE: {
- // def foo(**nil); end
- // ^^^^^
- ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg = TRUE;
- return;
- }
- case PM_NUMBERED_REFERENCE_READ_NODE: {
- // $1
- // ^^
- if (!popped) {
- uint32_t reference_number = ((const pm_numbered_reference_read_node_t *) node)->number;
-
- if (reference_number > 0) {
- PUSH_INSN2(ret, location, getspecial, INT2FIX(1), INT2FIX(reference_number << 1));
- }
- else {
- PUSH_INSN(ret, location, putnil);
- }
- }
-
- return;
- }
- case PM_OR_NODE: {
- // a or b
- // ^^^^^^
- const pm_or_node_t *cast = (const pm_or_node_t *) node;
-
- LABEL *end_label = NEW_LABEL(location.line);
- PM_COMPILE_NOT_POPPED(cast->left);
-
- if (!popped) PUSH_INSN(ret, location, dup);
- PUSH_INSNL(ret, location, branchif, end_label);
-
- if (!popped) PUSH_INSN(ret, location, pop);
- PM_COMPILE(cast->right);
- PUSH_LABEL(ret, end_label);
-
- return;
- }
- case PM_OPTIONAL_PARAMETER_NODE: {
- // def foo(bar = 1); end
- // ^^^^^^^
- const pm_optional_parameter_node_t *cast = (const pm_optional_parameter_node_t *) node;
- PM_COMPILE_NOT_POPPED(cast->value);
-
- pm_local_index_t index = pm_lookup_local_index(iseq, scope_node, cast->name, 0);
- PUSH_SETLOCAL(ret, location, index.index, index.level);
-
- return;
- }
- case PM_PARENTHESES_NODE: {
- // ()
- // ^^
- //
- // (1)
- // ^^^
- const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
-
- if (cast->body != NULL) {
- PM_COMPILE(cast->body);
- }
- else if (!popped) {
- PUSH_INSN(ret, location, putnil);
- }
-
- return;
- }
- case PM_PRE_EXECUTION_NODE: {
- // BEGIN {}
- // ^^^^^^^^
- const pm_pre_execution_node_t *cast = (const pm_pre_execution_node_t *) node;
-
- LINK_ANCHOR *outer_pre = scope_node->pre_execution_anchor;
- RUBY_ASSERT(outer_pre != NULL);
-
- // BEGIN{} nodes can be nested, so here we're going to do the same thing
- // that we did for the top-level compilation where we create two
- // anchors and then join them in the correct order into the resulting
- // anchor.
- DECL_ANCHOR(inner_pre);
- INIT_ANCHOR(inner_pre);
- scope_node->pre_execution_anchor = inner_pre;
-
- DECL_ANCHOR(inner_body);
- INIT_ANCHOR(inner_body);
-
- if (cast->statements != NULL) {
- const pm_node_list_t *body = &cast->statements->body;
-
- for (size_t index = 0; index < body->size; index++) {
- pm_compile_node(iseq, body->nodes[index], inner_body, true, scope_node);
- }
- }
-
- if (!popped) {
- PUSH_INSN(inner_body, location, putnil);
- }
-
- // Now that everything has been compiled, join both anchors together
- // into the correct outer pre execution anchor, and reset the value so
- // that subsequent BEGIN{} nodes can be compiled correctly.
- PUSH_SEQ(outer_pre, inner_pre);
- PUSH_SEQ(outer_pre, inner_body);
- scope_node->pre_execution_anchor = outer_pre;
-
- return;
- }
- case PM_POST_EXECUTION_NODE: {
- // END {}
- // ^^^^^^
- const rb_iseq_t *child_iseq;
- const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
-
- pm_scope_node_t next_scope_node;
- pm_scope_node_init(node, &next_scope_node, scope_node);
- child_iseq = NEW_CHILD_ISEQ(&next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
- pm_scope_node_destroy(&next_scope_node);
-
- ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq;
-
- int is_index = ISEQ_BODY(iseq)->ise_size++;
- PUSH_INSN2(ret, location, once, child_iseq, INT2FIX(is_index));
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE) child_iseq);
- if (popped) PUSH_INSN(ret, location, pop);
-
- ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
-
- return;
- }
- case PM_RANGE_NODE: {
- // 0..5
- // ^^^^
- const pm_range_node_t *cast = (const pm_range_node_t *) node;
- bool exclude_end = PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END);
-
- if (pm_optimizable_range_item_p(cast->left) && pm_optimizable_range_item_p(cast->right)) {
- if (!popped) {
- const pm_node_t *left = cast->left;
- const pm_node_t *right = cast->right;
-
- VALUE val = rb_range_new(
- (left && PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) ? parse_integer((const pm_integer_node_t *) left) : Qnil,
- (right && PM_NODE_TYPE_P(right, PM_INTEGER_NODE)) ? parse_integer((const pm_integer_node_t *) right) : Qnil,
- exclude_end
- );
-
- PUSH_INSN1(ret, location, putobject, val);
- }
- }
- else {
- if (cast->left != NULL) {
- PM_COMPILE(cast->left);
- }
- else if (!popped) {
- PUSH_INSN(ret, location, putnil);
- }
-
- if (cast->right != NULL) {
- PM_COMPILE(cast->right);
- }
- else if (!popped) {
- PUSH_INSN(ret, location, putnil);
- }
-
- if (!popped) {
- PUSH_INSN1(ret, location, newrange, INT2FIX(exclude_end ? 1 : 0));
- }
- }
- return;
- }
- case PM_RATIONAL_NODE: {
- // 1r
- // ^^
- if (!popped) {
- PUSH_INSN1(ret, location, putobject, parse_rational((const pm_rational_node_t *) node));
- }
- return;
- }
- case PM_REDO_NODE:
- // redo
- // ^^^^
- pm_compile_redo_node(iseq, &location, ret, popped, scope_node);
- return;
- case PM_REGULAR_EXPRESSION_NODE: {
- // /foo/
- // ^^^^^
- if (!popped) {
- VALUE regexp = pm_static_literal_value(iseq, node, scope_node);
- PUSH_INSN1(ret, location, putobject, regexp);
- }
- return;
- }
- case PM_RESCUE_NODE:
- // begin; rescue; end
- // ^^^^^^^
- pm_compile_rescue_node(iseq, (const pm_rescue_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_RESCUE_MODIFIER_NODE: {
- // foo rescue bar
- // ^^^^^^^^^^^^^^
- const pm_rescue_modifier_node_t *cast = (const pm_rescue_modifier_node_t *) node;
-
- pm_scope_node_t rescue_scope_node;
- pm_scope_node_init((const pm_node_t *) cast, &rescue_scope_node, scope_node);
-
- rb_iseq_t *rescue_iseq = NEW_CHILD_ISEQ(
- &rescue_scope_node,
- rb_str_concat(rb_str_new2("rescue in "), ISEQ_BODY(iseq)->location.label),
- ISEQ_TYPE_RESCUE,
- pm_node_line_number(parser, cast->rescue_expression)
- );
-
- pm_scope_node_destroy(&rescue_scope_node);
-
- LABEL *lstart = NEW_LABEL(location.line);
- LABEL *lend = NEW_LABEL(location.line);
- LABEL *lcont = NEW_LABEL(location.line);
-
- lstart->rescued = LABEL_RESCUE_BEG;
- lend->rescued = LABEL_RESCUE_END;
-
- PUSH_LABEL(ret, lstart);
- PM_COMPILE_NOT_POPPED(cast->expression);
- PUSH_LABEL(ret, lend);
-
- PUSH_INSN(ret, location, nop);
- PUSH_LABEL(ret, lcont);
- if (popped) PUSH_INSN(ret, location, pop);
-
- PUSH_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue_iseq, lcont);
- PUSH_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
- return;
- }
- case PM_RETURN_NODE:
- // return
- // ^^^^^^
- //
- // return 1
- // ^^^^^^^^
- pm_compile_return_node(iseq, (const pm_return_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_RETRY_NODE: {
- // retry
- // ^^^^^
- if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
- PUSH_INSN(ret, location, putnil);
- PUSH_INSN1(ret, location, throw, INT2FIX(TAG_RETRY));
- if (popped) PUSH_INSN(ret, location, pop);
- }
- else {
- COMPILE_ERROR(iseq, location.line, "Invalid retry");
- return;
- }
- return;
- }
- case PM_SCOPE_NODE:
- pm_compile_scope_node(iseq, (pm_scope_node_t *) node, &location, ret, popped);
- return;
- case PM_SELF_NODE: {
- // self
- // ^^^^
- if (!popped) {
- PUSH_INSN(ret, location, putself);
- }
- return;
- }
- case PM_SHAREABLE_CONSTANT_NODE: {
- // A value that is being written to a constant that is being marked as
- // shared depending on the current lexical context.
- const pm_shareable_constant_node_t *cast = (const pm_shareable_constant_node_t *) node;
- pm_node_flags_t shareability = (cast->base.flags & (PM_SHAREABLE_CONSTANT_NODE_FLAGS_LITERAL | PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_EVERYTHING | PM_SHAREABLE_CONSTANT_NODE_FLAGS_EXPERIMENTAL_COPY));
-
- switch (PM_NODE_TYPE(cast->write)) {
- case PM_CONSTANT_WRITE_NODE:
- pm_compile_constant_write_node(iseq, (const pm_constant_write_node_t *) cast->write, shareability, &location, ret, popped, scope_node);
- break;
- case PM_CONSTANT_AND_WRITE_NODE:
- pm_compile_constant_and_write_node(iseq, (const pm_constant_and_write_node_t *) cast->write, shareability, &location, ret, popped, scope_node);
- break;
- case PM_CONSTANT_OR_WRITE_NODE:
- pm_compile_constant_or_write_node(iseq, (const pm_constant_or_write_node_t *) cast->write, shareability, &location, ret, popped, scope_node);
- break;
- case PM_CONSTANT_OPERATOR_WRITE_NODE:
- pm_compile_constant_operator_write_node(iseq, (const pm_constant_operator_write_node_t *) cast->write, shareability, &location, ret, popped, scope_node);
- break;
- case PM_CONSTANT_PATH_WRITE_NODE:
- pm_compile_constant_path_write_node(iseq, (const pm_constant_path_write_node_t *) cast->write, shareability, &location, ret, popped, scope_node);
- break;
- case PM_CONSTANT_PATH_AND_WRITE_NODE:
- pm_compile_constant_path_and_write_node(iseq, (const pm_constant_path_and_write_node_t *) cast->write, shareability, &location, ret, popped, scope_node);
- break;
- case PM_CONSTANT_PATH_OR_WRITE_NODE:
- pm_compile_constant_path_or_write_node(iseq, (const pm_constant_path_or_write_node_t *) cast->write, shareability, &location, ret, popped, scope_node);
- break;
- case PM_CONSTANT_PATH_OPERATOR_WRITE_NODE:
- pm_compile_constant_path_operator_write_node(iseq, (const pm_constant_path_operator_write_node_t *) cast->write, shareability, &location, ret, popped, scope_node);
- break;
- default:
- rb_bug("Unexpected node type for shareable constant write: %s", pm_node_type_to_str(PM_NODE_TYPE(cast->write)));
- break;
- }
-
- return;
- }
- case PM_SINGLETON_CLASS_NODE: {
- // class << self; end
- // ^^^^^^^^^^^^^^^^^^
- const pm_singleton_class_node_t *cast = (const pm_singleton_class_node_t *) node;
-
- pm_scope_node_t next_scope_node;
- pm_scope_node_init((const pm_node_t *) cast, &next_scope_node, scope_node);
- const rb_iseq_t *child_iseq = NEW_ISEQ(&next_scope_node, rb_fstring_lit("singleton class"), ISEQ_TYPE_CLASS, location.line);
- pm_scope_node_destroy(&next_scope_node);
-
- PM_COMPILE_NOT_POPPED(cast->expression);
- PUSH_INSN(ret, location, putnil);
-
- ID singletonclass;
- CONST_ID(singletonclass, "singletonclass");
- PUSH_INSN3(ret, location, defineclass, ID2SYM(singletonclass), child_iseq, INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
-
- if (popped) PUSH_INSN(ret, location, pop);
- RB_OBJ_WRITTEN(iseq, Qundef, (VALUE) child_iseq);
-
- return;
- }
- case PM_SOURCE_ENCODING_NODE: {
- // __ENCODING__
- // ^^^^^^^^^^^^
- if (!popped) {
- VALUE value = pm_static_literal_value(iseq, node, scope_node);
- PUSH_INSN1(ret, location, putobject, value);
- }
- return;
- }
- case PM_SOURCE_FILE_NODE: {
- // __FILE__
- // ^^^^^^^^
- if (!popped) {
- const pm_source_file_node_t *cast = (const pm_source_file_node_t *) node;
- VALUE string = pm_source_file_value(cast, scope_node);
-
- if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_FROZEN)) {
- PUSH_INSN1(ret, location, putobject, string);
- }
- else if (PM_NODE_FLAG_P(cast, PM_STRING_FLAGS_MUTABLE)) {
- PUSH_INSN1(ret, location, putstring, string);
- }
- else {
- PUSH_INSN1(ret, location, putchilledstring, string);
- }
- }
- return;
- }
- case PM_SOURCE_LINE_NODE: {
- // __LINE__
- // ^^^^^^^^
- if (!popped) {
- VALUE value = pm_static_literal_value(iseq, node, scope_node);
- PUSH_INSN1(ret, location, putobject, value);
- }
- return;
- }
- case PM_SPLAT_NODE: {
- // foo(*bar)
- // ^^^^
- const pm_splat_node_t *cast = (const pm_splat_node_t *) node;
- if (cast->expression) {
- PM_COMPILE(cast->expression);
- }
-
- if (!popped) {
- PUSH_INSN1(ret, location, splatarray, Qtrue);
- }
- return;
- }
- case PM_STATEMENTS_NODE: {
- // A list of statements.
- const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
- const pm_node_list_t *body = &cast->body;
-
- if (body->size > 0) {
- for (size_t index = 0; index < body->size - 1; index++) {
- PM_COMPILE_POPPED(body->nodes[index]);
- }
- PM_COMPILE(body->nodes[body->size - 1]);
- }
- else {
- PUSH_INSN(ret, location, putnil);
- }
- return;
- }
- case PM_STRING_NODE: {
- // "foo"
- // ^^^^^
- if (!popped) {
- const pm_string_node_t *cast = (const pm_string_node_t *) node;
- VALUE value = parse_static_literal_string(iseq, scope_node, node, &cast->unescaped);
-
- if (PM_NODE_FLAG_P(node, PM_STRING_FLAGS_FROZEN)) {
- PUSH_INSN1(ret, location, putobject, value);
- }
- else if (PM_NODE_FLAG_P(node, PM_STRING_FLAGS_MUTABLE)) {
- PUSH_INSN1(ret, location, putstring, value);
- }
- else {
- PUSH_INSN1(ret, location, putchilledstring, value);
- }
- }
- return;
- }
- case PM_SUPER_NODE:
- // super()
- // super(foo)
- // super(...)
- pm_compile_super_node(iseq, (const pm_super_node_t *) node, &location, ret, popped, scope_node);
- return;
- case PM_SYMBOL_NODE: {
- // :foo
- // ^^^^
- if (!popped) {
- VALUE value = pm_static_literal_value(iseq, node, scope_node);
- PUSH_INSN1(ret, location, putobject, value);
- }
- return;
- }
- case PM_TRUE_NODE: {
- // true
- // ^^^^
- if (!popped) {
- PUSH_INSN1(ret, location, putobject, Qtrue);
- }
- return;
- }
- case PM_UNDEF_NODE: {
- // undef foo
- // ^^^^^^^^^
- const pm_undef_node_t *cast = (const pm_undef_node_t *) node;
- const pm_node_list_t *names = &cast->names;
-
- for (size_t index = 0; index < names->size; index++) {
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- PUSH_INSN1(ret, location, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
-
- PM_COMPILE_NOT_POPPED(names->nodes[index]);
- PUSH_SEND(ret, location, id_core_undef_method, INT2NUM(2));
-
- if (index < names->size - 1) {
- PUSH_INSN(ret, location, pop);
- }
- }
-
- if (popped) PUSH_INSN(ret, location, pop);
- return;
- }
- case PM_UNLESS_NODE: {
- // unless foo; bar end
- // ^^^^^^^^^^^^^^^^^^^
- //
- // bar unless foo
- // ^^^^^^^^^^^^^^
- const pm_unless_node_t *cast = (const pm_unless_node_t *) node;
- const pm_statements_node_t *statements = NULL;
- if (cast->else_clause != NULL) {
- statements = ((const pm_else_node_t *) cast->else_clause)->statements;
- }
-
- pm_compile_conditional(iseq, &location, PM_UNLESS_NODE, (const pm_node_t *) cast, statements, (const pm_node_t *) cast->statements, cast->predicate, ret, popped, scope_node);
- return;
- }
- case PM_UNTIL_NODE: {
- // until foo; bar end
- // ^^^^^^^^^^^^^^^^^
- //
- // bar until foo
- // ^^^^^^^^^^^^^
- const pm_until_node_t *cast = (const pm_until_node_t *) node;
- pm_compile_loop(iseq, &location, cast->base.flags, PM_UNTIL_NODE, (const pm_node_t *) cast, cast->statements, cast->predicate, ret, popped, scope_node);
- return;
- }
- case PM_WHILE_NODE: {
- // while foo; bar end
- // ^^^^^^^^^^^^^^^^^^
- //
- // bar while foo
- // ^^^^^^^^^^^^^
- const pm_while_node_t *cast = (const pm_while_node_t *) node;
- pm_compile_loop(iseq, &location, cast->base.flags, PM_WHILE_NODE, (const pm_node_t *) cast, cast->statements, cast->predicate, ret, popped, scope_node);
- return;
- }
- case PM_X_STRING_NODE: {
- // `foo`
- // ^^^^^
- const pm_x_string_node_t *cast = (const pm_x_string_node_t *) node;
- VALUE value = parse_static_literal_string(iseq, scope_node, node, &cast->unescaped);
-
- PUSH_INSN(ret, location, putself);
- PUSH_INSN1(ret, location, putobject, value);
- PUSH_SEND_WITH_FLAG(ret, location, idBackquote, INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));
- if (popped) PUSH_INSN(ret, location, pop);
-
- return;
- }
- case PM_YIELD_NODE:
- // yield
- // ^^^^^
- //
- // yield 1
- // ^^^^^^^
- pm_compile_yield_node(iseq, (const pm_yield_node_t *) node, &location, ret, popped, scope_node);
- return;
- default:
- rb_raise(rb_eNotImpError, "node type %s not implemented", pm_node_type_to_str(PM_NODE_TYPE(node)));
- return;
- }
-}
-
-#undef PM_CONTAINER_P
-
-/** True if the given iseq can have pre execution blocks. */
-static inline bool
-pm_iseq_pre_execution_p(rb_iseq_t *iseq)
-{
- switch (ISEQ_BODY(iseq)->type) {
- case ISEQ_TYPE_TOP:
- case ISEQ_TYPE_EVAL:
- case ISEQ_TYPE_MAIN:
- return true;
- default:
- return false;
- }
-}
-
-/**
- * This is the main entry-point into the prism compiler. It accepts the iseq
- * that it should be compiling instruction into and a pointer to the scope node
- * that it should be compiling. It returns the established instruction sequence.
- * Note that this function could raise Ruby errors if it encounters compilation
- * errors or if there is a bug in the compiler.
- */
-VALUE
-pm_iseq_compile_node(rb_iseq_t *iseq, pm_scope_node_t *node)
-{
- DECL_ANCHOR(ret);
- INIT_ANCHOR(ret);
-
- if (pm_iseq_pre_execution_p(iseq)) {
- // Because these ISEQs can have BEGIN{}, we're going to create two
- // anchors to compile them, a "pre" and a "body". We'll mark the "pre"
- // on the scope node so that when BEGIN{} is found, its contents will be
- // added to the "pre" anchor.
- DECL_ANCHOR(pre);
- INIT_ANCHOR(pre);
- node->pre_execution_anchor = pre;
-
- // Now we'll compile the body as normal. We won't compile directly into
- // the "ret" anchor yet because we want to add the "pre" anchor to the
- // beginning of the "ret" anchor first.
- DECL_ANCHOR(body);
- INIT_ANCHOR(body);
- pm_compile_node(iseq, (const pm_node_t *) node, body, false, node);
-
- // Now we'll join both anchors together so that the content is in the
- // correct order.
- PUSH_SEQ(ret, pre);
- PUSH_SEQ(ret, body);
- }
- else {
- // In other circumstances, we can just compile the node directly into
- // the "ret" anchor.
- pm_compile_node(iseq, (const pm_node_t *) node, ret, false, node);
- }
-
- CHECK(iseq_setup_insn(iseq, ret));
- return iseq_setup(iseq, ret);
-}
-
-/**
- * Free the internal memory associated with a pm_parse_result_t struct.
- * Importantly this does not free the struct itself.
- */
-void
-pm_parse_result_free(pm_parse_result_t *result)
-{
- if (result->parsed) {
- pm_node_destroy(&result->parser, result->node.ast_node);
-
- xfree(result->node.constants);
- pm_scope_node_destroy(&result->node);
- }
-
- pm_parser_free(&result->parser);
- pm_string_free(&result->input);
- pm_options_free(&result->options);
-}
-
-/** An error that is going to be formatted into the output. */
-typedef struct {
- /** A pointer to the diagnostic that was generated during parsing. */
- pm_diagnostic_t *error;
-
- /** The start line of the diagnostic message. */
- int32_t line;
-
- /** The column start of the diagnostic message. */
- uint32_t column_start;
-
- /** The column end of the diagnostic message. */
- uint32_t column_end;
-} pm_parse_error_t;
-
-/** The format that will be used to format the errors into the output. */
-typedef struct {
- /** The prefix that will be used for line numbers. */
- const char *number_prefix;
-
- /** The prefix that will be used for blank lines. */
- const char *blank_prefix;
-
- /** The divider that will be used between sections of source code. */
- const char *divider;
-
- /** The length of the blank prefix. */
- size_t blank_prefix_length;
-
- /** The length of the divider. */
- size_t divider_length;
-} pm_parse_error_format_t;
-
-#define PM_COLOR_GRAY "\033[38;5;102m"
-#define PM_COLOR_RED "\033[1;31m"
-#define PM_COLOR_RESET "\033[m"
-#define PM_ERROR_TRUNCATE 30
-
-static inline pm_parse_error_t *
-pm_parse_errors_format_sort(const pm_parser_t *parser, const pm_list_t *error_list, const pm_newline_list_t *newline_list) {
- pm_parse_error_t *errors = xcalloc(error_list->size, sizeof(pm_parse_error_t));
- if (errors == NULL) return NULL;
-
- int32_t start_line = parser->start_line;
- for (pm_diagnostic_t *error = (pm_diagnostic_t *) error_list->head; error != NULL; error = (pm_diagnostic_t *) error->node.next) {
- pm_line_column_t start = pm_newline_list_line_column(newline_list, error->location.start, start_line);
- pm_line_column_t end = pm_newline_list_line_column(newline_list, error->location.end, start_line);
-
- // We're going to insert this error into the array in sorted order. We
- // do this by finding the first error that has a line number greater
- // than the current error and then inserting the current error before
- // that one.
- size_t index = 0;
- while (
- (index < error_list->size) &&
- (errors[index].error != NULL) &&
- (
- (errors[index].line < start.line) ||
- ((errors[index].line == start.line) && (errors[index].column_start < start.column))
- )
- ) index++;
-
- // Now we're going to shift all of the errors after this one down one
- // index to make room for the new error.
- if (index + 1 < error_list->size) {
- memmove(&errors[index + 1], &errors[index], sizeof(pm_parse_error_t) * (error_list->size - index - 1));
- }
-
- // Finally, we'll insert the error into the array.
- uint32_t column_end;
- if (start.line == end.line) {
- column_end = end.column;
- } else {
- column_end = (uint32_t) (newline_list->offsets[start.line - start_line + 1] - newline_list->offsets[start.line - start_line] - 1);
- }
-
- // Ensure we have at least one column of error.
- if (start.column == column_end) column_end++;
-
- errors[index] = (pm_parse_error_t) {
- .error = error,
- .line = start.line,
- .column_start = start.column,
- .column_end = column_end
- };
- }
-
- return errors;
-}
-
-static inline void
-pm_parse_errors_format_line(const pm_parser_t *parser, const pm_newline_list_t *newline_list, const char *number_prefix, int32_t line, uint32_t column_start, uint32_t column_end, pm_buffer_t *buffer) {
- int32_t line_delta = line - parser->start_line;
- assert(line_delta >= 0);
-
- size_t index = (size_t) line_delta;
- assert(index < newline_list->size);
-
- const uint8_t *start = &parser->start[newline_list->offsets[index]];
- const uint8_t *end;
-
- if (index >= newline_list->size - 1) {
- end = parser->end;
- } else {
- end = &parser->start[newline_list->offsets[index + 1]];
- }
-
- pm_buffer_append_format(buffer, number_prefix, line);
-
- // Here we determine if we should truncate the end of the line.
- bool truncate_end = false;
- if ((column_end != 0) && ((end - (start + column_end)) >= PM_ERROR_TRUNCATE)) {
- end = start + column_end + PM_ERROR_TRUNCATE;
- truncate_end = true;
- }
-
- // Here we determine if we should truncate the start of the line.
- if (column_start >= PM_ERROR_TRUNCATE) {
- pm_buffer_append_string(buffer, "... ", 4);
- start += column_start;
- }
-
- pm_buffer_append_string(buffer, (const char *) start, (size_t) (end - start));
-
- if (truncate_end) {
- pm_buffer_append_string(buffer, " ...\n", 5);
- } else if (end == parser->end && end[-1] != '\n') {
- pm_buffer_append_string(buffer, "\n", 1);
- }
-}
-
-/**
- * Format the errors on the parser into the given buffer.
- */
-static void
-pm_parse_errors_format(const pm_parser_t *parser, const pm_list_t *error_list, pm_buffer_t *buffer, bool colorize, bool inline_messages) {
- assert(error_list->size != 0);
-
- // First, we're going to sort all of the errors by line number using an
- // insertion sort into a newly allocated array.
- const int32_t start_line = parser->start_line;
- const pm_newline_list_t *newline_list = &parser->newline_list;
-
- pm_parse_error_t *errors = pm_parse_errors_format_sort(parser, error_list, newline_list);
- if (errors == NULL) return;
-
- // Now we're going to determine how we're going to format line numbers and
- // blank lines based on the maximum number of digits in the line numbers
- // that are going to be displaid.
- pm_parse_error_format_t error_format;
- int32_t first_line_number = errors[0].line;
- int32_t last_line_number = errors[error_list->size - 1].line;
-
- // If we have a maximum line number that is negative, then we're going to
- // use the absolute value for comparison but multiple by 10 to additionally
- // have a column for the negative sign.
- if (first_line_number < 0) first_line_number = (-first_line_number) * 10;
- if (last_line_number < 0) last_line_number = (-last_line_number) * 10;
- int32_t max_line_number = first_line_number > last_line_number ? first_line_number : last_line_number;
-
- if (max_line_number < 10) {
- if (colorize) {
- error_format = (pm_parse_error_format_t) {
- .number_prefix = PM_COLOR_GRAY "%1" PRIi32 " | " PM_COLOR_RESET,
- .blank_prefix = PM_COLOR_GRAY " | " PM_COLOR_RESET,
- .divider = PM_COLOR_GRAY " ~~~~~" PM_COLOR_RESET "\n"
- };
- } else {
- error_format = (pm_parse_error_format_t) {
- .number_prefix = "%1" PRIi32 " | ",
- .blank_prefix = " | ",
- .divider = " ~~~~~\n"
- };
- }
- } else if (max_line_number < 100) {
- if (colorize) {
- error_format = (pm_parse_error_format_t) {
- .number_prefix = PM_COLOR_GRAY "%2" PRIi32 " | " PM_COLOR_RESET,
- .blank_prefix = PM_COLOR_GRAY " | " PM_COLOR_RESET,
- .divider = PM_COLOR_GRAY " ~~~~~~" PM_COLOR_RESET "\n"
- };
- } else {
- error_format = (pm_parse_error_format_t) {
- .number_prefix = "%2" PRIi32 " | ",
- .blank_prefix = " | ",
- .divider = " ~~~~~~\n"
- };
- }
- } else if (max_line_number < 1000) {
- if (colorize) {
- error_format = (pm_parse_error_format_t) {
- .number_prefix = PM_COLOR_GRAY "%3" PRIi32 " | " PM_COLOR_RESET,
- .blank_prefix = PM_COLOR_GRAY " | " PM_COLOR_RESET,
- .divider = PM_COLOR_GRAY " ~~~~~~~" PM_COLOR_RESET "\n"
- };
- } else {
- error_format = (pm_parse_error_format_t) {
- .number_prefix = "%3" PRIi32 " | ",
- .blank_prefix = " | ",
- .divider = " ~~~~~~~\n"
- };
- }
- } else if (max_line_number < 10000) {
- if (colorize) {
- error_format = (pm_parse_error_format_t) {
- .number_prefix = PM_COLOR_GRAY "%4" PRIi32 " | " PM_COLOR_RESET,
- .blank_prefix = PM_COLOR_GRAY " | " PM_COLOR_RESET,
- .divider = PM_COLOR_GRAY " ~~~~~~~~" PM_COLOR_RESET "\n"
- };
- } else {
- error_format = (pm_parse_error_format_t) {
- .number_prefix = "%4" PRIi32 " | ",
- .blank_prefix = " | ",
- .divider = " ~~~~~~~~\n"
- };
- }
- } else {
- if (colorize) {
- error_format = (pm_parse_error_format_t) {
- .number_prefix = PM_COLOR_GRAY "%5" PRIi32 " | " PM_COLOR_RESET,
- .blank_prefix = PM_COLOR_GRAY " | " PM_COLOR_RESET,
- .divider = PM_COLOR_GRAY " ~~~~~~~~" PM_COLOR_RESET "\n"
- };
- } else {
- error_format = (pm_parse_error_format_t) {
- .number_prefix = "%5" PRIi32 " | ",
- .blank_prefix = " | ",
- .divider = " ~~~~~~~~\n"
- };
- }
- }
-
- error_format.blank_prefix_length = strlen(error_format.blank_prefix);
- error_format.divider_length = strlen(error_format.divider);
-
- // Now we're going to iterate through every error in our error list and
- // display it. While we're iterating, we will display some padding lines of
- // the source before the error to give some context. We'll be careful not to
- // display the same line twice in case the errors are close enough in the
- // source.
- int32_t last_line = parser->start_line - 1;
- uint32_t last_column_start = 0;
- const pm_encoding_t *encoding = parser->encoding;
-
- for (size_t index = 0; index < error_list->size; index++) {
- pm_parse_error_t *error = &errors[index];
-
- // Here we determine how many lines of padding of the source to display,
- // based on the difference from the last line that was displaid.
- if (error->line - last_line > 1) {
- if (error->line - last_line > 2) {
- if ((index != 0) && (error->line - last_line > 3)) {
- pm_buffer_append_string(buffer, error_format.divider, error_format.divider_length);
- }
-
- pm_buffer_append_string(buffer, " ", 2);
- pm_parse_errors_format_line(parser, newline_list, error_format.number_prefix, error->line - 2, 0, 0, buffer);
- }
-
- pm_buffer_append_string(buffer, " ", 2);
- pm_parse_errors_format_line(parser, newline_list, error_format.number_prefix, error->line - 1, 0, 0, buffer);
- }
-
- // If this is the first error or we're on a new line, then we'll display
- // the line that has the error in it.
- if ((index == 0) || (error->line != last_line)) {
- if (colorize) {
- pm_buffer_append_string(buffer, PM_COLOR_RED "> " PM_COLOR_RESET, 12);
- } else {
- pm_buffer_append_string(buffer, "> ", 2);
- }
-
- last_column_start = error->column_start;
-
- // Find the maximum column end of all the errors on this line.
- uint32_t column_end = error->column_end;
- for (size_t next_index = index + 1; next_index < error_list->size; next_index++) {
- if (errors[next_index].line != error->line) break;
- if (errors[next_index].column_end > column_end) column_end = errors[next_index].column_end;
- }
-
- pm_parse_errors_format_line(parser, newline_list, error_format.number_prefix, error->line, error->column_start, column_end, buffer);
- }
-
- const uint8_t *start = &parser->start[newline_list->offsets[error->line - start_line]];
- if (start == parser->end) pm_buffer_append_byte(buffer, '\n');
-
- // Now we'll display the actual error message. We'll do this by first
- // putting the prefix to the line, then a bunch of blank spaces
- // depending on the column, then as many carets as we need to display
- // the width of the error, then the error message itself.
- //
- // Note that this doesn't take into account the width of the actual
- // character when displaid in the terminal. For some east-asian
- // languages or emoji, this means it can be thrown off pretty badly. We
- // will need to solve this eventually.
- pm_buffer_append_string(buffer, " ", 2);
- pm_buffer_append_string(buffer, error_format.blank_prefix, error_format.blank_prefix_length);
-
- size_t column = 0;
- if (last_column_start >= PM_ERROR_TRUNCATE) {
- pm_buffer_append_string(buffer, " ", 4);
- column = last_column_start;
- }
-
- while (column < error->column_start) {
- pm_buffer_append_byte(buffer, ' ');
-
- size_t char_width = encoding->char_width(start + column, parser->end - (start + column));
- column += (char_width == 0 ? 1 : char_width);
- }
-
- if (colorize) pm_buffer_append_string(buffer, PM_COLOR_RED, 7);
- pm_buffer_append_byte(buffer, '^');
-
- size_t char_width = encoding->char_width(start + column, parser->end - (start + column));
- column += (char_width == 0 ? 1 : char_width);
-
- while (column < error->column_end) {
- pm_buffer_append_byte(buffer, '~');
-
- size_t char_width = encoding->char_width(start + column, parser->end - (start + column));
- column += (char_width == 0 ? 1 : char_width);
- }
-
- if (colorize) pm_buffer_append_string(buffer, PM_COLOR_RESET, 3);
-
- if (inline_messages) {
- pm_buffer_append_byte(buffer, ' ');
- assert(error->error != NULL);
-
- const char *message = error->error->message;
- pm_buffer_append_string(buffer, message, strlen(message));
- }
-
- pm_buffer_append_byte(buffer, '\n');
-
- // Here we determine how many lines of padding to display after the
- // error, depending on where the next error is in source.
- last_line = error->line;
- int32_t next_line = (index == error_list->size - 1) ? (((int32_t) newline_list->size) + parser->start_line) : errors[index + 1].line;
-
- if (next_line - last_line > 1) {
- pm_buffer_append_string(buffer, " ", 2);
- pm_parse_errors_format_line(parser, newline_list, error_format.number_prefix, ++last_line, 0, 0, buffer);
- }
-
- if (next_line - last_line > 1) {
- pm_buffer_append_string(buffer, " ", 2);
- pm_parse_errors_format_line(parser, newline_list, error_format.number_prefix, ++last_line, 0, 0, buffer);
- }
- }
-
- // Finally, we'll free the array of errors that we allocated.
- xfree(errors);
-}
-
-#undef PM_ERROR_TRUNCATE
-#undef PM_COLOR_GRAY
-#undef PM_COLOR_RED
-#undef PM_COLOR_RESET
-
-/**
- * Check if the given source slice is valid UTF-8. The location represents the
- * location of the error, but the slice of the source will include the content
- * of all of the lines that the error touches, so we need to check those parts
- * as well.
- */
-static bool
-pm_parse_process_error_utf8_p(const pm_parser_t *parser, const pm_location_t *location)
-{
- const size_t start_line = pm_newline_list_line_column(&parser->newline_list, location->start, 1).line;
- const size_t end_line = pm_newline_list_line_column(&parser->newline_list, location->end, 1).line;
-
- const uint8_t *start = parser->start + parser->newline_list.offsets[start_line - 1];
- const uint8_t *end = ((end_line == parser->newline_list.size) ? parser->end : (parser->start + parser->newline_list.offsets[end_line]));
- size_t width;
-
- while (start < end) {
- if ((width = pm_encoding_utf_8_char_width(start, end - start)) == 0) return false;
- start += width;
- }
-
- return true;
-}
-
-/**
- * Generate an error object from the given parser that contains as much
- * information as possible about the errors that were encountered.
- */
-static VALUE
-pm_parse_process_error(const pm_parse_result_t *result)
-{
- const pm_parser_t *parser = &result->parser;
- const pm_diagnostic_t *head = (const pm_diagnostic_t *) parser->error_list.head;
- bool valid_utf8 = true;
-
- pm_buffer_t buffer = { 0 };
- const pm_string_t *filepath = &parser->filepath;
-
- for (const pm_diagnostic_t *error = head; error != NULL; error = (const pm_diagnostic_t *) error->node.next) {
- switch (error->level) {
- case PM_ERROR_LEVEL_SYNTAX:
- // It is implicitly assumed that the error messages will be
- // encodeable as UTF-8. Because of this, we can't include source
- // examples that contain invalid byte sequences. So if any source
- // examples include invalid UTF-8 byte sequences, we will skip
- // showing source examples entirely.
- if (valid_utf8 && !pm_parse_process_error_utf8_p(parser, &error->location)) {
- valid_utf8 = false;
- }
- break;
- case PM_ERROR_LEVEL_ARGUMENT: {
- // Any errors with the level PM_ERROR_LEVEL_ARGUMENT take over as
- // the only argument that gets raised. This is to allow priority
- // messages that should be handled before anything else.
- int32_t line_number = (int32_t) pm_location_line_number(parser, &error->location);
-
- pm_buffer_append_format(
- &buffer,
- "%.*s:%" PRIi32 ": %s",
- (int) pm_string_length(filepath),
- pm_string_source(filepath),
- line_number,
- error->message
- );
-
- if (pm_parse_process_error_utf8_p(parser, &error->location)) {
- pm_buffer_append_byte(&buffer, '\n');
-
- pm_list_node_t *list_node = (pm_list_node_t *) error;
- pm_list_t error_list = { .size = 1, .head = list_node, .tail = list_node };
-
- pm_parse_errors_format(parser, &error_list, &buffer, rb_stderr_tty_p(), false);
- }
-
- VALUE value = rb_exc_new(rb_eArgError, pm_buffer_value(&buffer), pm_buffer_length(&buffer));
- pm_buffer_free(&buffer);
-
- return value;
- }
- case PM_ERROR_LEVEL_LOAD: {
- // Load errors are much simpler, because they don't include any of
- // the source in them. We create the error directly from the
- // message.
- VALUE message = rb_enc_str_new_cstr(error->message, rb_locale_encoding());
- VALUE value = rb_exc_new3(rb_eLoadError, message);
- rb_ivar_set(value, rb_intern_const("@path"), Qnil);
- return value;
- }
- }
- }
-
- pm_buffer_append_format(
- &buffer,
- "%.*s:%" PRIi32 ": syntax error%s found\n",
- (int) pm_string_length(filepath),
- pm_string_source(filepath),
- (int32_t) pm_location_line_number(parser, &head->location),
- (parser->error_list.size > 1) ? "s" : ""
- );
-
- if (valid_utf8) {
- pm_parse_errors_format(parser, &parser->error_list, &buffer, rb_stderr_tty_p(), true);
- }
- else {
- for (const pm_diagnostic_t *error = head; error != NULL; error = (const pm_diagnostic_t *) error->node.next) {
- if (error != head) pm_buffer_append_byte(&buffer, '\n');
- pm_buffer_append_format(&buffer, "%.*s:%" PRIi32 ": %s", (int) pm_string_length(filepath), pm_string_source(filepath), (int32_t) pm_location_line_number(parser, &error->location), error->message);
- }
- }
-
- VALUE message = rb_enc_str_new(pm_buffer_value(&buffer), pm_buffer_length(&buffer), result->node.encoding);
- VALUE error = rb_exc_new_str(rb_eSyntaxError, message);
-
- rb_encoding *filepath_encoding = result->node.filepath_encoding != NULL ? result->node.filepath_encoding : rb_utf8_encoding();
- VALUE path = rb_enc_str_new((const char *) pm_string_source(filepath), pm_string_length(filepath), filepath_encoding);
-
- rb_ivar_set(error, rb_intern_const("@path"), path);
- pm_buffer_free(&buffer);
-
- return error;
-}
-
-/**
- * Parse the parse result and raise a Ruby error if there are any syntax errors.
- * It returns an error if one should be raised. It is assumed that the parse
- * result object is zeroed out.
- */
-static VALUE
-pm_parse_process(pm_parse_result_t *result, pm_node_t *node, VALUE *script_lines)
-{
- pm_parser_t *parser = &result->parser;
-
- // First, set up the scope node so that the AST node is attached and can be
- // freed regardless of whether or we return an error.
- pm_scope_node_t *scope_node = &result->node;
- rb_encoding *filepath_encoding = scope_node->filepath_encoding;
- int coverage_enabled = scope_node->coverage_enabled;
-
- pm_scope_node_init(node, scope_node, NULL);
- scope_node->filepath_encoding = filepath_encoding;
-
- scope_node->encoding = rb_enc_find(parser->encoding->name);
- if (!scope_node->encoding) rb_bug("Encoding not found %s!", parser->encoding->name);
-
- scope_node->coverage_enabled = coverage_enabled;
-
- // If RubyVM.keep_script_lines is set to true, then we need to create that
- // array of script lines here.
- if (script_lines != NULL) {
- *script_lines = rb_ary_new_capa(parser->newline_list.size);
-
- for (size_t index = 0; index < parser->newline_list.size; index++) {
- size_t offset = parser->newline_list.offsets[index];
- size_t length = index == parser->newline_list.size - 1 ? ((size_t) (parser->end - (parser->start + offset))) : (parser->newline_list.offsets[index + 1] - offset);
- rb_ary_push(*script_lines, rb_enc_str_new((const char *) parser->start + offset, length, scope_node->encoding));
- }
-
- scope_node->script_lines = script_lines;
- }
-
- // Emit all of the various warnings from the parse.
- const pm_diagnostic_t *warning;
- const char *warning_filepath = (const char *) pm_string_source(&parser->filepath);
-
- for (warning = (const pm_diagnostic_t *) parser->warning_list.head; warning != NULL; warning = (const pm_diagnostic_t *) warning->node.next) {
- int line = pm_location_line_number(parser, &warning->location);
-
- if (warning->level == PM_WARNING_LEVEL_VERBOSE) {
- rb_enc_compile_warning(scope_node->encoding, warning_filepath, line, "%s", warning->message);
- }
- else {
- rb_enc_compile_warn(scope_node->encoding, warning_filepath, line, "%s", warning->message);
- }
- }
-
- // If there are errors, raise an appropriate error and free the result.
- if (parser->error_list.size > 0) {
- VALUE error = pm_parse_process_error(result);
-
- // TODO: We need to set the backtrace.
- // rb_funcallv(error, rb_intern("set_backtrace"), 1, &path);
- return error;
- }
-
- // Now set up the constant pool and intern all of the various constants into
- // their corresponding IDs.
- scope_node->parser = parser;
- scope_node->constants = xcalloc(parser->constant_pool.size, sizeof(ID));
-
- for (uint32_t index = 0; index < parser->constant_pool.size; index++) {
- pm_constant_t *constant = &parser->constant_pool.constants[index];
- scope_node->constants[index] = rb_intern3((const char *) constant->start, constant->length, scope_node->encoding);
- }
-
- scope_node->index_lookup_table = st_init_numtable();
- pm_constant_id_list_t *locals = &scope_node->locals;
- for (size_t index = 0; index < locals->size; index++) {
- st_insert(scope_node->index_lookup_table, locals->ids[index], index);
- }
-
- // If we got here, this is a success and we can return Qnil to indicate that
- // no error should be raised.
- result->parsed = true;
- return Qnil;
-}
-
-/**
- * Set the frozen_string_literal option based on the default value used by the
- * CRuby compiler.
- */
-static void
-pm_options_frozen_string_literal_init(pm_options_t *options)
-{
- int frozen_string_literal = rb_iseq_opt_frozen_string_literal();
-
- switch (frozen_string_literal) {
- case ISEQ_FROZEN_STRING_LITERAL_UNSET:
- break;
- case ISEQ_FROZEN_STRING_LITERAL_DISABLED:
- pm_options_frozen_string_literal_set(options, false);
- break;
- case ISEQ_FROZEN_STRING_LITERAL_ENABLED:
- pm_options_frozen_string_literal_set(options, true);
- break;
- default:
- rb_bug("pm_options_frozen_string_literal_init: invalid frozen_string_literal=%d", frozen_string_literal);
- break;
- }
-}
-
-/**
- * Returns an array of ruby String objects that represent the lines of the
- * source file that the given parser parsed.
- */
-static inline VALUE
-pm_parse_file_script_lines(const pm_scope_node_t *scope_node, const pm_parser_t *parser)
-{
- const pm_newline_list_t *newline_list = &parser->newline_list;
- const char *start = (const char *) parser->start;
- const char *end = (const char *) parser->end;
-
- // If we end exactly on a newline, then there's no need to push on a final
- // segment. If we don't, then we need to push on the last offset up to the
- // end of the string.
- size_t last_offset = newline_list->offsets[newline_list->size - 1];
- bool last_push = start + last_offset != end;
-
- // Create the ruby strings that represent the lines of the source.
- VALUE lines = rb_ary_new_capa(newline_list->size - (last_push ? 0 : 1));
-
- for (size_t index = 0; index < newline_list->size - 1; index++) {
- size_t offset = newline_list->offsets[index];
- size_t length = newline_list->offsets[index + 1] - offset;
-
- rb_ary_push(lines, rb_enc_str_new(start + offset, length, scope_node->encoding));
- }
-
- // Push on the last line if we need to.
- if (last_push) {
- rb_ary_push(lines, rb_enc_str_new(start + last_offset, end - (start + last_offset), scope_node->encoding));
- }
-
- return lines;
-}
-
-// This is essentially pm_string_mapped_init(), preferring to memory map the
-// file, with additional handling for files that require blocking to properly
-// read (e.g. pipes).
-static pm_string_init_result_t
-pm_read_file(pm_string_t *string, const char *filepath)
-{
-#ifdef _WIN32
- // Open the file for reading.
- int length = MultiByteToWideChar(CP_UTF8, 0, filepath, -1, NULL, 0);
- if (length == 0) return PM_STRING_INIT_ERROR_GENERIC;
-
- WCHAR *wfilepath = xmalloc(sizeof(WCHAR) * ((size_t) length));
- if ((wfilepath == NULL) || (MultiByteToWideChar(CP_UTF8, 0, filepath, -1, wfilepath, length) == 0)) {
- xfree(wfilepath);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- HANDLE file = CreateFileW(wfilepath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
- if (file == INVALID_HANDLE_VALUE) {
- pm_string_init_result_t result = PM_STRING_INIT_ERROR_GENERIC;
-
- if (GetLastError() == ERROR_ACCESS_DENIED) {
- DWORD attributes = GetFileAttributesW(wfilepath);
- if ((attributes != INVALID_FILE_ATTRIBUTES) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
- result = PM_STRING_INIT_ERROR_DIRECTORY;
- }
- }
-
- xfree(wfilepath);
- return result;
- }
-
- // Get the file size.
- DWORD file_size = GetFileSize(file, NULL);
- if (file_size == INVALID_FILE_SIZE) {
- CloseHandle(file);
- xfree(wfilepath);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // If the file is empty, then we don't need to do anything else, we'll set
- // the source to a constant empty string and return.
- if (file_size == 0) {
- CloseHandle(file);
- xfree(wfilepath);
- const uint8_t source[] = "";
- *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
- return PM_STRING_INIT_SUCCESS;
- }
-
- // Create a mapping of the file.
- HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
- if (mapping == NULL) {
- CloseHandle(file);
- xfree(wfilepath);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Map the file into memory.
- uint8_t *source = (uint8_t *) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
- CloseHandle(mapping);
- CloseHandle(file);
- xfree(wfilepath);
-
- if (source == NULL) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = (size_t) file_size };
- return PM_STRING_INIT_SUCCESS;
-#elif defined(_POSIX_MAPPED_FILES)
- // Open the file for reading
- const int open_mode = O_RDONLY | O_NONBLOCK;
- int fd = open(filepath, open_mode);
- if (fd == -1) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Stat the file to get the file size
- struct stat sb;
- if (fstat(fd, &sb) == -1) {
- close(fd);
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- // Ensure it is a file and not a directory
- if (S_ISDIR(sb.st_mode)) {
- close(fd);
- return PM_STRING_INIT_ERROR_DIRECTORY;
- }
-
- // We need to wait for data first before reading from pipes and character
- // devices. To not block the entire VM, we need to release the GVL while
- // reading. Use IO#read to do this and let the GC handle closing the FD.
- if (S_ISFIFO(sb.st_mode) || S_ISCHR(sb.st_mode)) {
- VALUE io = rb_io_fdopen((int) fd, open_mode, filepath);
- rb_io_wait(io, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
- VALUE contents = rb_funcall(io, rb_intern("read"), 0);
-
- if (!RB_TYPE_P(contents, T_STRING)) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- long len = RSTRING_LEN(contents);
- if (len < 0) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- size_t length = (size_t) len;
- uint8_t *source = xmalloc(length);
- memcpy(source, RSTRING_PTR(contents), length);
- *string = (pm_string_t) { .type = PM_STRING_OWNED, .source = source, .length = length };
-
- return PM_STRING_INIT_SUCCESS;
- }
-
- // mmap the file descriptor to virtually get the contents
- size_t size = (size_t) sb.st_size;
- uint8_t *source = NULL;
-
- if (size == 0) {
- close(fd);
- const uint8_t source[] = "";
- *string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
- return PM_STRING_INIT_SUCCESS;
- }
-
- source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (source == MAP_FAILED) {
- return PM_STRING_INIT_ERROR_GENERIC;
- }
-
- close(fd);
- *string = (pm_string_t) { .type = PM_STRING_MAPPED, .source = source, .length = size };
- return PM_STRING_INIT_SUCCESS;
-#else
- return pm_string_file_init(string, filepath);
-#endif
-}
-
-/**
- * Attempt to load the file into memory. Return a Ruby error if the file cannot
- * be read.
- */
-VALUE
-pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error)
-{
- pm_string_init_result_t init_result = pm_read_file(&result->input, RSTRING_PTR(filepath));
-
- if (init_result == PM_STRING_INIT_SUCCESS) {
- pm_options_frozen_string_literal_init(&result->options);
- return Qnil;
- }
-
- int err;
- if (init_result == PM_STRING_INIT_ERROR_DIRECTORY) {
- err = EISDIR;
- } else {
-#ifdef _WIN32
- err = rb_w32_map_errno(GetLastError());
-#else
- err = errno;
-#endif
- }
-
- VALUE error;
- if (load_error) {
- VALUE message = rb_str_buf_new_cstr(strerror(err));
- rb_str_cat2(message, " -- ");
- rb_str_append(message, filepath);
-
- error = rb_exc_new3(rb_eLoadError, message);
- rb_ivar_set(error, rb_intern_const("@path"), filepath);
- } else {
- error = rb_syserr_new(err, RSTRING_PTR(filepath));
- RB_GC_GUARD(filepath);
- }
-
- return error;
-}
-
-/**
- * Parse the given filepath and store the resulting scope node in the given
- * parse result struct. It returns a Ruby error if the file cannot be read or
- * if it cannot be parsed properly. It is assumed that the parse result object
- * is zeroed out.
- */
-VALUE
-pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines)
-{
- result->node.filepath_encoding = rb_enc_get(filepath);
- pm_options_filepath_set(&result->options, RSTRING_PTR(filepath));
- RB_GC_GUARD(filepath);
-
- pm_parser_init(&result->parser, pm_string_source(&result->input), pm_string_length(&result->input), &result->options);
- pm_node_t *node = pm_parse(&result->parser);
-
- VALUE error = pm_parse_process(result, node, script_lines);
-
- // If we're parsing a filepath, then we need to potentially support the
- // SCRIPT_LINES__ constant, which can be a hash that has an array of lines
- // of every read file.
- ID id_script_lines = rb_intern("SCRIPT_LINES__");
-
- if (rb_const_defined_at(rb_cObject, id_script_lines)) {
- VALUE constant_script_lines = rb_const_get_at(rb_cObject, id_script_lines);
-
- if (RB_TYPE_P(constant_script_lines, T_HASH)) {
- rb_hash_aset(constant_script_lines, filepath, pm_parse_file_script_lines(&result->node, &result->parser));
- }
- }
-
- return error;
-}
-
-/**
- * Load and then parse the given filepath. It returns a Ruby error if the file
- * cannot be read or if it cannot be parsed properly.
- */
-VALUE
-pm_load_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines)
-{
- VALUE error = pm_load_file(result, filepath, false);
- if (NIL_P(error)) {
- error = pm_parse_file(result, filepath, script_lines);
- }
-
- return error;
-}
-
-/**
- * Parse the given source that corresponds to the given filepath and store the
- * resulting scope node in the given parse result struct. It is assumed that the
- * parse result object is zeroed out. If the string fails to parse, then a Ruby
- * error is returned.
- */
-VALUE
-pm_parse_string(pm_parse_result_t *result, VALUE source, VALUE filepath, VALUE *script_lines)
-{
- rb_encoding *encoding = rb_enc_get(source);
- if (!rb_enc_asciicompat(encoding)) {
- return rb_exc_new_cstr(rb_eArgError, "invalid source encoding");
- }
-
- pm_options_frozen_string_literal_init(&result->options);
- pm_string_constant_init(&result->input, RSTRING_PTR(source), RSTRING_LEN(source));
- pm_options_encoding_set(&result->options, rb_enc_name(encoding));
-
- result->node.filepath_encoding = rb_enc_get(filepath);
- pm_options_filepath_set(&result->options, RSTRING_PTR(filepath));
- RB_GC_GUARD(filepath);
-
- pm_parser_init(&result->parser, pm_string_source(&result->input), pm_string_length(&result->input), &result->options);
- pm_node_t *node = pm_parse(&result->parser);
-
- return pm_parse_process(result, node, script_lines);
-}
-
-/**
- * An implementation of fgets that is suitable for use with Ruby IO objects.
- */
-static char *
-pm_parse_stdin_fgets(char *string, int size, void *stream)
-{
- RUBY_ASSERT(size > 0);
-
- VALUE line = rb_funcall((VALUE) stream, rb_intern("gets"), 1, INT2FIX(size - 1));
- if (NIL_P(line)) {
- return NULL;
- }
-
- const char *cstr = RSTRING_PTR(line);
- long length = RSTRING_LEN(line);
-
- memcpy(string, cstr, length);
- string[length] = '\0';
-
- return string;
-}
-
-// We need access to this function when we're done parsing stdin.
-void rb_reset_argf_lineno(long n);
-
-/**
- * Parse the source off STDIN and store the resulting scope node in the given
- * parse result struct. It is assumed that the parse result object is zeroed
- * out. If the stream fails to parse, then a Ruby error is returned.
- */
-VALUE
-pm_parse_stdin(pm_parse_result_t *result)
-{
- pm_options_frozen_string_literal_init(&result->options);
-
- pm_buffer_t buffer;
- pm_node_t *node = pm_parse_stream(&result->parser, &buffer, (void *) rb_stdin, pm_parse_stdin_fgets, &result->options);
-
- // Copy the allocated buffer contents into the input string so that it gets
- // freed. At this point we've handed over ownership, so we don't need to
- // free the buffer itself.
- pm_string_owned_init(&result->input, (uint8_t *) pm_buffer_value(&buffer), pm_buffer_length(&buffer));
-
- // When we're done parsing, we reset $. because we don't want the fact that
- // we went through an IO object to be visible to the user.
- rb_reset_argf_lineno(0);
-
- return pm_parse_process(result, node, NULL);
-}
-
-#undef NEW_ISEQ
-#define NEW_ISEQ OLD_ISEQ
-
-#undef NEW_CHILD_ISEQ
-#define NEW_CHILD_ISEQ OLD_CHILD_ISEQ
diff --git a/prism_compile.h b/prism_compile.h
deleted file mode 100644
index 4015091fc1..0000000000
--- a/prism_compile.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#include "prism/prism.h"
-#include "ruby/encoding.h"
-
-/**
- * the getlocal and setlocal instructions require two parameters. level is how
- * many hops up the iseq stack one needs to go before finding the correct local
- * table. The index is the index in that table where our variable is.
- *
- * Because these are always calculated and used together, we'll bind them
- * together as a tuple.
- */
-typedef struct pm_local_index_struct {
- int index, level;
-} pm_local_index_t;
-
-// A declaration for the struct that lives in compile.c.
-struct iseq_link_anchor;
-
-// ScopeNodes are helper nodes, and will never be part of the AST. We manually
-// declare them here to avoid generating them.
-typedef struct pm_scope_node {
- pm_node_t base;
- struct pm_scope_node *previous;
- pm_node_t *ast_node;
- pm_node_t *parameters;
- pm_node_t *body;
- pm_constant_id_list_t locals;
-
- const pm_parser_t *parser;
- rb_encoding *encoding;
-
- /**
- * This is a pointer to the list of script lines for the ISEQs that will be
- * associated with this scope node. It is only set if
- * RubyVM.keep_script_lines is true. If it is set, it will be set to a
- * pointer to an array that is always stack allocated (so no GC marking is
- * needed by this struct). If it is not set, it will be NULL. It is
- * inherited by all child scopes.
- */
- VALUE *script_lines;
-
- /**
- * This is the encoding of the actual filepath object that will be used when
- * a __FILE__ node is compiled or when the path has to be set on a syntax
- * error.
- */
- rb_encoding *filepath_encoding;
-
- // The size of the local table on the iseq which includes locals and hidden
- // variables.
- int local_table_for_iseq_size;
-
- ID *constants;
- st_table *index_lookup_table;
-
- // The current coverage setting, passed down through the various scopes.
- int coverage_enabled;
-
- /**
- * This will only be set on the top-level scope node. It will contain all of
- * the instructions pertaining to BEGIN{} nodes.
- */
- struct iseq_link_anchor *pre_execution_anchor;
-} pm_scope_node_t;
-
-void pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_t *previous);
-void pm_scope_node_destroy(pm_scope_node_t *scope_node);
-
-typedef struct {
- /** The parser that will do the actual parsing. */
- pm_parser_t parser;
-
- /** The options that will be passed to the parser. */
- pm_options_t options;
-
- /** The input that represents the source to be parsed. */
- pm_string_t input;
-
- /** The resulting scope node that will hold the generated AST. */
- pm_scope_node_t node;
-
- /** Whether or not this parse result has performed its parsing yet. */
- bool parsed;
-} pm_parse_result_t;
-
-VALUE pm_load_file(pm_parse_result_t *result, VALUE filepath, bool load_error);
-VALUE pm_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines);
-VALUE pm_load_parse_file(pm_parse_result_t *result, VALUE filepath, VALUE *script_lines);
-VALUE pm_parse_string(pm_parse_result_t *result, VALUE source, VALUE filepath, VALUE *script_lines);
-VALUE pm_parse_stdin(pm_parse_result_t *result);
-void pm_parse_result_free(pm_parse_result_t *result);
-
-rb_iseq_t *pm_iseq_new(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent, enum rb_iseq_type);
-rb_iseq_t *pm_iseq_new_top(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent);
-rb_iseq_t *pm_iseq_new_main(pm_scope_node_t *node, VALUE path, VALUE realpath, const rb_iseq_t *parent, int opt);
-rb_iseq_t *pm_iseq_new_eval(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth);
-rb_iseq_t *pm_iseq_new_with_opt(pm_scope_node_t *node, VALUE name, VALUE path, VALUE realpath, int first_lineno, const rb_iseq_t *parent, int isolated_depth, enum rb_iseq_type, const rb_compile_option_t*);
-
-VALUE pm_iseq_compile_node(rb_iseq_t *iseq, pm_scope_node_t *node);
diff --git a/prism_init.c b/prism_init.c
deleted file mode 100644
index ddc87fad85..0000000000
--- a/prism_init.c
+++ /dev/null
@@ -1,9 +0,0 @@
-#include "prism/extension.h"
-
-void ruby_init_ext(const char *name, void (*init)(void));
-
-void
-Init_Prism(void)
-{
- ruby_init_ext("prism/prism.so", Init_prism);
-}
diff --git a/probes_helper.h b/probes_helper.h
index 16d81b9ffb..0003e96dd8 100644
--- a/probes_helper.h
+++ b/probes_helper.h
@@ -12,7 +12,9 @@ struct ruby_dtrace_method_hook_args {
volatile VALUE name;
};
+MJIT_SYMBOL_EXPORT_BEGIN
NOINLINE(int rb_dtrace_setup(rb_execution_context_t *, VALUE, ID, struct ruby_dtrace_method_hook_args *));
+MJIT_SYMBOL_EXPORT_END
#define RUBY_DTRACE_METHOD_HOOK(name, ec, klazz, id) \
do { \
diff --git a/proc.c b/proc.c
index 8e82c13720..bb0ad89851 100644
--- a/proc.c
+++ b/proc.c
@@ -10,11 +10,12 @@
**********************************************************************/
#include "eval_intern.h"
+#include "gc.h"
#include "internal.h"
#include "internal/class.h"
#include "internal/error.h"
#include "internal/eval.h"
-#include "internal/gc.h"
+#include "internal/hash.h"
#include "internal/object.h"
#include "internal/proc.h"
#include "internal/symbol.h"
@@ -23,6 +24,15 @@
#include "vm_core.h"
#include "yjit.h"
+#if !defined(__GNUC__) || __GNUC__ < 5 || defined(__MINGW32__)
+# define NO_CLOBBERED(v) (*(volatile VALUE *)&(v))
+#else
+# define NO_CLOBBERED(v) (v)
+#endif
+
+#define UPDATE_TYPED_REFERENCE(_type, _ref) *(_type*)&_ref = (_type)rb_gc_location((VALUE)_ref)
+#define UPDATE_REFERENCE(_ref) UPDATE_TYPED_REFERENCE(VALUE, _ref)
+
const rb_cref_t *rb_vm_cref_in_context(VALUE self, VALUE cbase);
struct METHOD {
@@ -47,39 +57,87 @@ static int method_arity(VALUE);
static int method_min_max_arity(VALUE, int *max);
static VALUE proc_binding(VALUE self);
+#define attached id__attached__
+
/* Proc */
#define IS_METHOD_PROC_IFUNC(ifunc) ((ifunc)->func == bmcall)
+/* :FIXME: The way procs are cloned has been historically different from the
+ * way everything else are. @shyouhei is not sure for the intention though.
+ */
+#undef CLONESETUP
+static inline void
+CLONESETUP(VALUE clone, VALUE obj)
+{
+ RBIMPL_ASSERT_OR_ASSUME(! RB_SPECIAL_CONST_P(obj));
+ RBIMPL_ASSERT_OR_ASSUME(! RB_SPECIAL_CONST_P(clone));
+
+ const VALUE flags = RUBY_FL_PROMOTED0 | RUBY_FL_PROMOTED1 | RUBY_FL_FINALIZE;
+ rb_obj_setup(clone, rb_singleton_class_clone(obj),
+ RB_FL_TEST_RAW(obj, ~flags));
+ rb_singleton_class_attached(RBASIC_CLASS(clone), clone);
+ if (RB_FL_TEST(obj, RUBY_FL_EXIVAR)) rb_copy_generic_ivar(clone, obj);
+}
+
static void
-block_mark_and_move(struct rb_block *block)
+block_mark(const struct rb_block *block)
+{
+ switch (vm_block_type(block)) {
+ case block_type_iseq:
+ case block_type_ifunc:
+ {
+ const struct rb_captured_block *captured = &block->as.captured;
+ RUBY_MARK_MOVABLE_UNLESS_NULL(captured->self);
+ RUBY_MARK_MOVABLE_UNLESS_NULL((VALUE)captured->code.val);
+ if (captured->ep && !UNDEF_P(captured->ep[VM_ENV_DATA_INDEX_ENV]) /* cfunc_proc_t */) {
+ rb_gc_mark(VM_ENV_ENVVAL(captured->ep));
+ }
+ }
+ break;
+ case block_type_symbol:
+ RUBY_MARK_MOVABLE_UNLESS_NULL(block->as.symbol);
+ break;
+ case block_type_proc:
+ RUBY_MARK_MOVABLE_UNLESS_NULL(block->as.proc);
+ break;
+ }
+}
+
+static void
+block_compact(struct rb_block *block)
{
switch (block->type) {
case block_type_iseq:
case block_type_ifunc:
{
struct rb_captured_block *captured = &block->as.captured;
- rb_gc_mark_and_move(&captured->self);
- rb_gc_mark_and_move(&captured->code.val);
- if (captured->ep) {
- rb_gc_mark_and_move((VALUE *)&captured->ep[VM_ENV_DATA_INDEX_ENV]);
- }
+ captured->self = rb_gc_location(captured->self);
+ captured->code.val = rb_gc_location(captured->code.val);
}
break;
case block_type_symbol:
- rb_gc_mark_and_move(&block->as.symbol);
+ block->as.symbol = rb_gc_location(block->as.symbol);
break;
case block_type_proc:
- rb_gc_mark_and_move(&block->as.proc);
+ block->as.proc = rb_gc_location(block->as.proc);
break;
}
}
static void
-proc_mark_and_move(void *ptr)
+proc_compact(void *ptr)
{
rb_proc_t *proc = ptr;
- block_mark_and_move((struct rb_block *)&proc->block);
+ block_compact((struct rb_block *)&proc->block);
+}
+
+static void
+proc_mark(void *ptr)
+{
+ rb_proc_t *proc = ptr;
+ block_mark(&proc->block);
+ RUBY_MARK_LEAVE("proc");
}
typedef struct {
@@ -99,10 +157,10 @@ proc_memsize(const void *ptr)
static const rb_data_type_t proc_data_type = {
"proc",
{
- proc_mark_and_move,
+ proc_mark,
RUBY_TYPED_DEFAULT_FREE,
proc_memsize,
- proc_mark_and_move,
+ proc_compact,
},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};
@@ -125,15 +183,8 @@ static VALUE
proc_clone(VALUE self)
{
VALUE procval = rb_proc_dup(self);
- return rb_obj_clone_setup(self, procval, Qnil);
-}
-
-/* :nodoc: */
-static VALUE
-proc_dup(VALUE self)
-{
- VALUE procval = rb_proc_dup(self);
- return rb_obj_dup_setup(self, procval);
+ CLONESETUP(procval, self);
+ return procval;
}
/*
@@ -259,12 +310,23 @@ binding_free(void *ptr)
}
static void
-binding_mark_and_move(void *ptr)
+binding_mark(void *ptr)
{
rb_binding_t *bind = ptr;
- block_mark_and_move((struct rb_block *)&bind->block);
- rb_gc_mark_and_move((VALUE *)&bind->pathobj);
+ RUBY_MARK_ENTER("binding");
+ block_mark(&bind->block);
+ rb_gc_mark_movable(bind->pathobj);
+ RUBY_MARK_LEAVE("binding");
+}
+
+static void
+binding_compact(void *ptr)
+{
+ rb_binding_t *bind = ptr;
+
+ block_compact((struct rb_block *)&bind->block);
+ UPDATE_REFERENCE(bind->pathobj);
}
static size_t
@@ -276,10 +338,10 @@ binding_memsize(const void *ptr)
const rb_data_type_t ruby_binding_data_type = {
"binding",
{
- binding_mark_and_move,
+ binding_mark,
binding_free,
binding_memsize,
- binding_mark_and_move,
+ binding_compact,
},
0, 0, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY
};
@@ -308,7 +370,7 @@ binding_dup(VALUE self)
rb_vm_block_copy(bindval, &dst->block, &src->block);
RB_OBJ_WRITE(bindval, &dst->pathobj, src->pathobj);
dst->first_lineno = src->first_lineno;
- return rb_obj_dup_setup(self, bindval);
+ return bindval;
}
/* :nodoc: */
@@ -316,7 +378,8 @@ static VALUE
binding_clone(VALUE self)
{
VALUE bindval = binding_dup(self);
- return rb_obj_clone_setup(self, bindval, Qnil);
+ CLONESETUP(bindval, self);
+ return bindval;
}
VALUE
@@ -330,44 +393,16 @@ rb_binding_new(void)
* call-seq:
* binding -> a_binding
*
- * Returns a Binding object, describing the variable and
+ * Returns a +Binding+ object, describing the variable and
* method bindings at the point of call. This object can be used when
- * calling Binding#eval to execute the evaluated command in this
- * environment, or extracting its local variables.
- *
- * class User
- * def initialize(name, position)
- * @name = name
- * @position = position
- * end
- *
- * def get_binding
- * binding
- * end
- * end
- *
- * user = User.new('Joan', 'manager')
- * template = '{name: @name, position: @position}'
- *
- * # evaluate template in context of the object
- * eval(template, user.get_binding)
- * #=> {:name=>"Joan", :position=>"manager"}
- *
- * Binding#local_variable_get can be used to access the variables
- * whose names are reserved Ruby keywords:
- *
- * # This is valid parameter declaration, but `if` parameter can't
- * # be accessed by name, because it is a reserved word.
- * def validate(field, validation, if: nil)
- * condition = binding.local_variable_get('if')
- * return unless condition
+ * calling +eval+ to execute the evaluated command in this
+ * environment. See also the description of class +Binding+.
*
- * # ...Some implementation ...
+ * def get_binding(param)
+ * binding
* end
- *
- * validate(:name, :empty?, if: false) # skips validation
- * validate(:name, :empty?, if: true) # performs validation
- *
+ * b = get_binding("hello")
+ * eval("param", b) #=> "hello"
*/
static VALUE
@@ -457,13 +492,13 @@ check_local_id(VALUE bindval, volatile VALUE *pname)
if (lid) {
if (!rb_is_local_id(lid)) {
- rb_name_err_raise("wrong local variable name '%1$s' for %2$s",
+ rb_name_err_raise("wrong local variable name `%1$s' for %2$s",
bindval, ID2SYM(lid));
}
}
else {
if (!rb_is_local_name(name)) {
- rb_name_err_raise("wrong local variable name '%1$s' for %2$s",
+ rb_name_err_raise("wrong local variable name `%1$s' for %2$s",
bindval, name);
}
return 0;
@@ -536,7 +571,7 @@ bind_local_variable_get(VALUE bindval, VALUE sym)
sym = ID2SYM(lid);
undefined:
- rb_name_err_raise("local variable '%1$s' is not defined for %2$s",
+ rb_name_err_raise("local variable `%1$s' is not defined for %2$s",
bindval, sym);
UNREACHABLE_RETURN(Qundef);
}
@@ -718,24 +753,18 @@ rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int m
}
arity.argc.min = min_argc;
arity.argc.max = max_argc;
- rb_execution_context_t *ec = GET_EC();
-
- struct vm_ifunc *ifunc = IMEMO_NEW(struct vm_ifunc, imemo_ifunc, (VALUE)rb_vm_svar_lep(ec, ec->cfp));
- ifunc->func = func;
- ifunc->data = data;
- ifunc->argc = arity.argc;
-
- return ifunc;
+ VALUE ret = rb_imemo_new(imemo_ifunc, (VALUE)func, (VALUE)data, arity.packed, 0);
+ return (struct vm_ifunc *)ret;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_func_proc_new(rb_block_call_func_t func, VALUE val)
{
struct vm_ifunc *ifunc = rb_vm_ifunc_proc_new(func, (void *)val);
return cfunc_proc_new(rb_cProc, (VALUE)ifunc);
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_argc)
{
struct vm_ifunc *ifunc = rb_vm_ifunc_new(func, (void *)val, min_argc, max_argc);
@@ -745,7 +774,7 @@ rb_func_lambda_new(rb_block_call_func_t func, VALUE val, int min_argc, int max_a
static const char proc_without_block[] = "tried to create Proc object without a block";
static VALUE
-proc_new(VALUE klass, int8_t is_lambda)
+proc_new(VALUE klass, int8_t is_lambda, int8_t kernel)
{
VALUE procval;
const rb_execution_context_t *ec = GET_EC();
@@ -778,8 +807,16 @@ proc_new(VALUE klass, int8_t is_lambda)
break;
case block_handler_type_ifunc:
- case block_handler_type_iseq:
return rb_vm_make_proc_lambda(ec, VM_BH_TO_CAPT_BLOCK(block_handler), klass, is_lambda);
+ case block_handler_type_iseq:
+ {
+ const struct rb_captured_block *captured = VM_BH_TO_CAPT_BLOCK(block_handler);
+ rb_control_frame_t *last_ruby_cfp = rb_vm_get_ruby_level_next_cfp(ec, cfp);
+ if (is_lambda && last_ruby_cfp && vm_cfp_forwarded_bh_p(last_ruby_cfp, block_handler)) {
+ is_lambda = false;
+ }
+ return rb_vm_make_proc_lambda(ec, captured, klass, is_lambda);
+ }
}
VM_UNREACHABLE(proc_new);
return Qnil;
@@ -802,7 +839,7 @@ proc_new(VALUE klass, int8_t is_lambda)
static VALUE
rb_proc_s_new(int argc, VALUE *argv, VALUE klass)
{
- VALUE block = proc_new(klass, FALSE);
+ VALUE block = proc_new(klass, FALSE, FALSE);
rb_obj_call_init_kw(block, argc, argv, RB_PASS_CALLED_KEYWORDS);
return block;
@@ -811,7 +848,7 @@ rb_proc_s_new(int argc, VALUE *argv, VALUE klass)
VALUE
rb_block_proc(void)
{
- return proc_new(rb_cProc, FALSE);
+ return proc_new(rb_cProc, FALSE, FALSE);
}
/*
@@ -824,44 +861,41 @@ rb_block_proc(void)
static VALUE
f_proc(VALUE _)
{
- return proc_new(rb_cProc, FALSE);
+ return proc_new(rb_cProc, FALSE, TRUE);
}
VALUE
rb_block_lambda(void)
{
- return proc_new(rb_cProc, TRUE);
+ return proc_new(rb_cProc, TRUE, FALSE);
}
static void
-f_lambda_filter_non_literal(void)
+f_lambda_warn(void)
{
rb_control_frame_t *cfp = GET_EC()->cfp;
VALUE block_handler = rb_vm_frame_block_handler(cfp);
- if (block_handler == VM_BLOCK_HANDLER_NONE) {
- // no block error raised else where
- return;
- }
-
- switch (vm_block_handler_type(block_handler)) {
- case block_handler_type_iseq:
- if (RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)->ep == VM_BH_TO_ISEQ_BLOCK(block_handler)->ep) {
- return;
- }
- break;
- case block_handler_type_symbol:
- return;
- case block_handler_type_proc:
- if (rb_proc_lambda_p(VM_BH_TO_PROC(block_handler))) {
+ if (block_handler != VM_BLOCK_HANDLER_NONE) {
+ switch (vm_block_handler_type(block_handler)) {
+ case block_handler_type_iseq:
+ if (RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)->ep == VM_BH_TO_ISEQ_BLOCK(block_handler)->ep) {
+ return;
+ }
+ break;
+ case block_handler_type_symbol:
return;
+ case block_handler_type_proc:
+ if (rb_proc_lambda_p(VM_BH_TO_PROC(block_handler))) {
+ return;
+ }
+ break;
+ case block_handler_type_ifunc:
+ break;
}
- break;
- case block_handler_type_ifunc:
- break;
}
- rb_raise(rb_eArgError, "the lambda method requires a literal block");
+ rb_warn_deprecated("lambda without a literal block", "the proc without lambda");
}
/*
@@ -875,7 +909,7 @@ f_lambda_filter_non_literal(void)
static VALUE
f_lambda(VALUE _)
{
- f_lambda_filter_non_literal();
+ f_lambda_warn();
return rb_block_lambda();
}
@@ -1050,7 +1084,7 @@ rb_iseq_min_max_arity(const rb_iseq_t *iseq, int *max)
{
*max = ISEQ_BODY(iseq)->param.flags.has_rest == FALSE ?
ISEQ_BODY(iseq)->param.lead_num + ISEQ_BODY(iseq)->param.opt_num + ISEQ_BODY(iseq)->param.post_num +
- (ISEQ_BODY(iseq)->param.flags.has_kw == TRUE || ISEQ_BODY(iseq)->param.flags.has_kwrest == TRUE || ISEQ_BODY(iseq)->param.flags.forwardable == TRUE)
+ (ISEQ_BODY(iseq)->param.flags.has_kw == TRUE || ISEQ_BODY(iseq)->param.flags.has_kwrest == TRUE)
: UNLIMITED_ARGUMENTS;
return ISEQ_BODY(iseq)->param.lead_num + ISEQ_BODY(iseq)->param.post_num + (ISEQ_BODY(iseq)->param.flags.has_kw && ISEQ_BODY(iseq)->param.keyword->required_num > 0);
}
@@ -1159,12 +1193,6 @@ rb_block_pair_yield_optimizable(void)
return min > 1;
}
- case block_handler_type_ifunc:
- {
- const struct vm_ifunc *ifunc = block.as.captured.code.ifunc;
- if (ifunc->flags & IFUNC_YIELD_OPTIMIZABLE) return 1;
- }
-
default:
return min > 1;
}
@@ -1345,7 +1373,7 @@ iseq_location(const rb_iseq_t *iseq)
return rb_ary_new4(2, loc);
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_iseq_location(const rb_iseq_t *iseq)
{
return iseq_location(iseq);
@@ -1437,8 +1465,24 @@ rb_hash_proc(st_index_t hash, VALUE prc)
{
rb_proc_t *proc;
GetProcPtr(prc, proc);
- hash = rb_hash_uint(hash, (st_index_t)proc->block.as.captured.code.val);
- hash = rb_hash_uint(hash, (st_index_t)proc->block.as.captured.self);
+
+ switch (vm_block_type(&proc->block)) {
+ case block_type_iseq:
+ hash = rb_st_hash_uint(hash, (st_index_t)proc->block.as.captured.code.iseq->body);
+ break;
+ case block_type_ifunc:
+ hash = rb_st_hash_uint(hash, (st_index_t)proc->block.as.captured.code.ifunc->func);
+ break;
+ case block_type_symbol:
+ hash = rb_st_hash_uint(hash, rb_any_hash(proc->block.as.symbol));
+ break;
+ case block_type_proc:
+ hash = rb_st_hash_uint(hash, rb_any_hash(proc->block.as.proc));
+ break;
+ default:
+ rb_bug("rb_hash_proc: unknown block type %d", vm_block_type(&proc->block));
+ }
+
return rb_hash_uint(hash, (st_index_t)proc->block.as.captured.ep);
}
@@ -1457,7 +1501,7 @@ rb_hash_proc(st_index_t hash, VALUE prc)
*
*/
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_sym_to_proc(VALUE sym)
{
static VALUE sym_proc_cache = Qfalse;
@@ -1468,7 +1512,7 @@ rb_sym_to_proc(VALUE sym)
if (!sym_proc_cache) {
sym_proc_cache = rb_ary_hidden_new(SYM_PROC_CACHE_SIZE * 2);
- rb_vm_register_global_object(sym_proc_cache);
+ rb_gc_register_mark_object(sym_proc_cache);
rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil);
}
@@ -1568,25 +1612,42 @@ proc_to_proc(VALUE self)
}
static void
-bm_mark_and_move(void *ptr)
+bm_mark(void *ptr)
{
struct METHOD *data = ptr;
- rb_gc_mark_and_move((VALUE *)&data->recv);
- rb_gc_mark_and_move((VALUE *)&data->klass);
- rb_gc_mark_and_move((VALUE *)&data->iclass);
- rb_gc_mark_and_move((VALUE *)&data->owner);
- rb_gc_mark_and_move_ptr((rb_method_entry_t **)&data->me);
+ rb_gc_mark_movable(data->recv);
+ rb_gc_mark_movable(data->klass);
+ rb_gc_mark_movable(data->iclass);
+ rb_gc_mark_movable(data->owner);
+ rb_gc_mark_movable((VALUE)data->me);
+}
+
+static void
+bm_compact(void *ptr)
+{
+ struct METHOD *data = ptr;
+ UPDATE_REFERENCE(data->recv);
+ UPDATE_REFERENCE(data->klass);
+ UPDATE_REFERENCE(data->iclass);
+ UPDATE_REFERENCE(data->owner);
+ UPDATE_TYPED_REFERENCE(rb_method_entry_t *, data->me);
+}
+
+static size_t
+bm_memsize(const void *ptr)
+{
+ return sizeof(struct METHOD);
}
static const rb_data_type_t method_data_type = {
"method",
{
- bm_mark_and_move,
+ bm_mark,
RUBY_TYPED_DEFAULT_FREE,
- NULL, // No external memory to report,
- bm_mark_and_move,
+ bm_memsize,
+ bm_compact,
},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
VALUE
@@ -1680,7 +1741,7 @@ mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass,
method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data);
- if (UNDEF_P(obj)) {
+ if (obj == Qundef) {
RB_OBJ_WRITE(method, &data->recv, Qundef);
RB_OBJ_WRITE(method, &data->klass, Qundef);
}
@@ -1780,8 +1841,8 @@ method_eq(VALUE method, VALUE other)
return Qfalse;
Check_TypedStruct(method, &method_data_type);
- m1 = (struct METHOD *)RTYPEDDATA_GET_DATA(method);
- m2 = (struct METHOD *)RTYPEDDATA_GET_DATA(other);
+ m1 = (struct METHOD *)DATA_PTR(method);
+ m2 = (struct METHOD *)DATA_PTR(other);
klass1 = method_entry_defined_class(m1->me);
klass2 = method_entry_defined_class(m2->me);
@@ -1947,12 +2008,12 @@ method_owner(VALUE obj)
void
rb_method_name_error(VALUE klass, VALUE str)
{
-#define MSG(s) rb_fstring_lit("undefined method '%1$s' for"s" '%2$s'")
+#define MSG(s) rb_fstring_lit("undefined method `%1$s' for"s" `%2$s'")
VALUE c = klass;
VALUE s = Qundef;
- if (RCLASS_SINGLETON_P(c)) {
- VALUE obj = RCLASS_ATTACHED_OBJECT(klass);
+ if (FL_TEST(c, FL_SINGLETON)) {
+ VALUE obj = rb_ivar_get(klass, attached);
switch (BUILTIN_TYPE(obj)) {
case T_MODULE:
@@ -2046,19 +2107,6 @@ rb_obj_public_method(VALUE obj, VALUE vid)
return obj_method(obj, vid, TRUE);
}
-static VALUE
-rb_obj_singleton_method_lookup(VALUE arg)
-{
- VALUE *args = (VALUE *)arg;
- return rb_obj_method(args[0], args[1]);
-}
-
-static VALUE
-rb_obj_singleton_method_lookup_fail(VALUE arg1, VALUE arg2)
-{
- return Qfalse;
-}
-
/*
* call-seq:
* obj.singleton_method(sym) -> method
@@ -2086,13 +2134,13 @@ rb_obj_singleton_method_lookup_fail(VALUE arg1, VALUE arg2)
VALUE
rb_obj_singleton_method(VALUE obj, VALUE vid)
{
- VALUE sc = rb_singleton_class_get(obj);
- VALUE klass;
+ VALUE klass = rb_singleton_class_get(obj);
ID id = rb_check_id(&vid);
- if (NIL_P(sc) ||
- NIL_P(klass = RCLASS_ORIGIN(sc)) ||
- !NIL_P(rb_special_singleton_class(obj))) {
+ if (NIL_P(klass)) {
+ /* goto undef; */
+ }
+ else if (NIL_P(klass = RCLASS_ORIGIN(klass))) {
/* goto undef; */
}
else if (! id) {
@@ -2101,27 +2149,22 @@ rb_obj_singleton_method(VALUE obj, VALUE vid)
/* else goto undef; */
}
else {
- VALUE args[2] = {obj, vid};
- VALUE ruby_method = rb_rescue(rb_obj_singleton_method_lookup, (VALUE)args, rb_obj_singleton_method_lookup_fail, Qfalse);
- if (ruby_method) {
- struct METHOD *method = (struct METHOD *)RTYPEDDATA_GET_DATA(ruby_method);
- VALUE lookup_class = RBASIC_CLASS(obj);
- VALUE stop_class = rb_class_superclass(sc);
- VALUE method_class = method->iclass;
-
- /* Determine if method is in singleton class, or module included in or prepended to it */
- do {
- if (lookup_class == method_class) {
- return ruby_method;
- }
- lookup_class = RCLASS_SUPER(lookup_class);
- } while (lookup_class && lookup_class != stop_class);
+ const rb_method_entry_t *me = rb_method_entry_at(klass, id);
+ vid = ID2SYM(id);
+
+ if (UNDEFINED_METHOD_ENTRY_P(me)) {
+ /* goto undef; */
+ }
+ else if (UNDEFINED_REFINED_METHOD_P(me->def)) {
+ /* goto undef; */
+ }
+ else {
+ return mnew_from_me(me, klass, klass, obj, id, rb_cMethod, FALSE);
}
}
/* undef: */
- vid = ID2SYM(id);
- rb_name_err_raise("undefined singleton method '%1$s' for '%2$s'",
+ rb_name_err_raise("undefined singleton method `%1$s' for `%2$s'",
obj, vid);
UNREACHABLE_RETURN(Qundef);
}
@@ -2216,10 +2259,10 @@ rb_mod_define_method_with_visibility(int argc, VALUE *argv, VALUE mod, const str
if (!id) id = rb_to_id(name);
if (is_method) {
- struct METHOD *method = (struct METHOD *)RTYPEDDATA_GET_DATA(body);
+ struct METHOD *method = (struct METHOD *)DATA_PTR(body);
if (method->me->owner != mod && !RB_TYPE_P(method->me->owner, T_MODULE) &&
!RTEST(rb_class_inherited_p(mod, method->me->owner))) {
- if (RCLASS_SINGLETON_P(method->me->owner)) {
+ if (FL_TEST(method->me->owner, FL_SINGLETON)) {
rb_raise(rb_eTypeError,
"can't bind singleton method to a different class");
}
@@ -2384,25 +2427,7 @@ method_clone(VALUE self)
TypedData_Get_Struct(self, struct METHOD, &method_data_type, orig);
clone = TypedData_Make_Struct(CLASS_OF(self), struct METHOD, &method_data_type, data);
- rb_obj_clone_setup(self, clone, Qnil);
- RB_OBJ_WRITE(clone, &data->recv, orig->recv);
- RB_OBJ_WRITE(clone, &data->klass, orig->klass);
- RB_OBJ_WRITE(clone, &data->iclass, orig->iclass);
- RB_OBJ_WRITE(clone, &data->owner, orig->owner);
- RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me));
- return clone;
-}
-
-/* :nodoc: */
-static VALUE
-method_dup(VALUE self)
-{
- VALUE clone;
- struct METHOD *orig, *data;
-
- TypedData_Get_Struct(self, struct METHOD, &method_data_type, orig);
- clone = TypedData_Make_Struct(CLASS_OF(self), struct METHOD, &method_data_type, data);
- rb_obj_dup_setup(self, clone);
+ CLONESETUP(clone, self);
RB_OBJ_WRITE(clone, &data->recv, orig->recv);
RB_OBJ_WRITE(clone, &data->klass, orig->klass);
RB_OBJ_WRITE(clone, &data->iclass, orig->iclass);
@@ -2576,7 +2601,7 @@ convert_umethod_to_method_components(const struct METHOD *data, VALUE recv, VALU
if (!NIL_P(refined_class)) methclass = refined_class;
}
if (!RB_TYPE_P(methclass, T_MODULE) && !RTEST(rb_obj_is_kind_of(recv, methclass))) {
- if (RCLASS_SINGLETON_P(methclass)) {
+ if (FL_TEST(methclass, FL_SINGLETON)) {
rb_raise(rb_eTypeError,
"singleton method called for a different object");
}
@@ -3143,12 +3168,12 @@ method_inspect(VALUE method)
defined_class = RBASIC_CLASS(defined_class);
}
- if (UNDEF_P(data->recv)) {
+ if (data->recv == Qundef) {
// UnboundMethod
rb_str_buf_append(str, rb_inspect(defined_class));
}
- else if (RCLASS_SINGLETON_P(mklass)) {
- VALUE v = RCLASS_ATTACHED_OBJECT(mklass);
+ else if (FL_TEST(mklass, FL_SINGLETON)) {
+ VALUE v = rb_ivar_get(mklass, attached);
if (UNDEF_P(data->recv)) {
rb_str_buf_append(str, rb_inspect(mklass));
@@ -3167,8 +3192,8 @@ method_inspect(VALUE method)
}
else {
mklass = data->klass;
- if (RCLASS_SINGLETON_P(mklass)) {
- VALUE v = RCLASS_ATTACHED_OBJECT(mklass);
+ if (FL_TEST(mklass, FL_SINGLETON)) {
+ VALUE v = rb_ivar_get(mklass, attached);
if (!(RB_TYPE_P(v, T_CLASS) || RB_TYPE_P(v, T_MODULE))) {
do {
mklass = RCLASS_SUPER(mklass);
@@ -3427,15 +3452,9 @@ env_clone(const rb_env_t *env, const rb_cref_t *cref)
}
new_body = ALLOC_N(VALUE, env->env_size);
+ MEMCPY(new_body, env->env, VALUE, env->env_size);
new_ep = &new_body[env->ep - env->env];
new_env = vm_env_new(new_ep, new_body, env->env_size, env->iseq);
-
- /* The memcpy has to happen after the vm_env_new because it can trigger a
- * GC compaction which can move the objects in the env. */
- MEMCPY(new_body, env->env, VALUE, env->env_size);
- /* VM_ENV_DATA_INDEX_ENV is set in vm_env_new but will get overwritten
- * by the memcpy above. */
- new_ep[VM_ENV_DATA_INDEX_ENV] = (VALUE)new_env;
RB_OBJ_WRITE(new_env, &new_ep[VM_ENV_DATA_INDEX_ME_CREF], (VALUE)cref);
VM_ASSERT(VM_ENV_ESCAPED_P(new_ep));
return new_env;
@@ -3492,7 +3511,7 @@ proc_binding(VALUE self)
env = VM_ENV_ENVVAL_PTR(block->as.captured.ep);
env = env_clone(env, method_cref(method));
/* set empty iseq */
- empty = rb_iseq_new(Qnil, name, name, Qnil, 0, ISEQ_TYPE_TOP);
+ empty = rb_iseq_new(NULL, name, name, Qnil, 0, ISEQ_TYPE_TOP);
RB_OBJ_WRITE(env, &env->iseq, empty);
break;
}
@@ -4276,7 +4295,7 @@ Init_Proc(void)
rb_define_method(rb_cProc, "to_proc", proc_to_proc, 0);
rb_define_method(rb_cProc, "arity", proc_arity, 0);
rb_define_method(rb_cProc, "clone", proc_clone, 0);
- rb_define_method(rb_cProc, "dup", proc_dup, 0);
+ rb_define_method(rb_cProc, "dup", rb_proc_dup, 0);
rb_define_method(rb_cProc, "hash", proc_hash, 0);
rb_define_method(rb_cProc, "to_s", proc_to_s, 0);
rb_define_alias(rb_cProc, "inspect", "to_s");
@@ -4312,7 +4331,6 @@ Init_Proc(void)
rb_define_method(rb_cMethod, "eql?", method_eq, 1);
rb_define_method(rb_cMethod, "hash", method_hash, 0);
rb_define_method(rb_cMethod, "clone", method_clone, 0);
- rb_define_method(rb_cMethod, "dup", method_dup, 0);
rb_define_method(rb_cMethod, "call", rb_method_call_pass_called_kw, -1);
rb_define_method(rb_cMethod, "===", rb_method_call_pass_called_kw, -1);
rb_define_method(rb_cMethod, "curry", rb_method_curry, -1);
@@ -4343,7 +4361,6 @@ Init_Proc(void)
rb_define_method(rb_cUnboundMethod, "eql?", unbound_method_eq, 1);
rb_define_method(rb_cUnboundMethod, "hash", method_hash, 0);
rb_define_method(rb_cUnboundMethod, "clone", method_clone, 0);
- rb_define_method(rb_cUnboundMethod, "dup", method_dup, 0);
rb_define_method(rb_cUnboundMethod, "arity", method_arity_m, 0);
rb_define_method(rb_cUnboundMethod, "inspect", method_inspect, 0);
rb_define_method(rb_cUnboundMethod, "to_s", method_inspect, 0);
diff --git a/process.c b/process.c
index ef4757ab23..c317a4cc2c 100644
--- a/process.c
+++ b/process.c
@@ -103,20 +103,18 @@ int initgroups(const char *, rb_gid_t);
#include "internal/error.h"
#include "internal/eval.h"
#include "internal/hash.h"
-#include "internal/io.h"
#include "internal/numeric.h"
#include "internal/object.h"
#include "internal/process.h"
#include "internal/thread.h"
#include "internal/variable.h"
#include "internal/warnings.h"
-#include "rjit.h"
+#include "mjit.h"
#include "ruby/io.h"
#include "ruby/st.h"
#include "ruby/thread.h"
#include "ruby/util.h"
#include "vm_core.h"
-#include "vm_sync.h"
#include "ruby/ractor.h"
/* define system APIs */
@@ -361,8 +359,6 @@ static ID id_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC;
#endif
static ID id_hertz;
-static rb_pid_t cached_pid;
-
/* execv and execl are async-signal-safe since SUSv4 (POSIX.1-2008, XPG7) */
#if defined(__sun) && !defined(_XPG7) /* Solaris 10, 9, ... */
#define execv(path, argv) (rb_async_bug_errno("unreachable: async-signal-unsafe execv() is called", 0))
@@ -498,32 +494,38 @@ parent_redirect_close(int fd)
#define parent_redirect_close(fd) close_unless_reserved(fd)
#endif
+/*
+ * Document-module: Process
+ *
+ * The module contains several groups of functionality for handling OS processes:
+ *
+ * * Low-level property introspection and management of the current process, like
+ * Process.argv0, Process.pid;
+ * * Low-level introspection of other processes, like Process.getpgid, Process.getpriority;
+ * * Management of the current process: Process.abort, Process.exit, Process.daemon, etc.
+ * (for convenience, most of those are also available as global functions
+ * and module functions of Kernel);
+ * * Creation and management of child processes: Process.fork, Process.spawn, and
+ * related methods;
+ * * Management of low-level system clock: Process.times and Process.clock_gettime,
+ * which could be important for proper benchmarking and other elapsed
+ * time measurement tasks.
+ */
+
static VALUE
get_pid(void)
{
- if (UNLIKELY(!cached_pid)) { /* 0 is not a valid pid */
- cached_pid = getpid();
- }
- /* pid should be likely POSFIXABLE() */
- return PIDT2NUM(cached_pid);
-}
-
-#if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
-static void
-clear_pid_cache(void)
-{
- cached_pid = 0;
+ return PIDT2NUM(getpid());
}
-#endif
/*
* call-seq:
- * Process.pid -> integer
+ * Process.pid -> integer
*
- * Returns the process ID of the current process:
- *
- * Process.pid # => 15668
+ * Returns the process id of this process. Not available on all
+ * platforms.
*
+ * Process.pid #=> 27415
*/
static VALUE
@@ -540,19 +542,18 @@ get_ppid(void)
/*
* call-seq:
- * Process.ppid -> integer
- *
- * Returns the process ID of the parent of the current process:
+ * Process.ppid -> integer
*
- * puts "Pid is #{Process.pid}."
- * fork { puts "Parent pid is #{Process.ppid}." }
+ * Returns the process id of the parent of this process. Returns
+ * untrustworthy value on Win32/64. Not available on all platforms.
*
- * Output:
+ * puts "I am #{Process.pid}"
+ * Process.fork { puts "Dad is #{Process.ppid}" }
*
- * Pid is 271290.
- * Parent pid is 271290.
+ * <em>produces:</em>
*
- * May not return a trustworthy value on certain platforms.
+ * I am 27417
+ * Dad is 27417
*/
static VALUE
@@ -566,20 +567,30 @@ proc_get_ppid(VALUE _)
*
* Document-class: Process::Status
*
- * A Process::Status contains information about a system process.
- *
- * Thread-local variable <tt>$?</tt> is initially +nil+.
- * Some methods assign to it a Process::Status object
- * that represents a system process (either running or terminated):
- *
- * `ruby -e "exit 99"`
- * stat = $? # => #<Process::Status: pid 1262862 exit 99>
- * stat.class # => Process::Status
- * stat.to_i # => 25344
- * stat.stopped? # => false
- * stat.exited? # => true
- * stat.exitstatus # => 99
- *
+ * Process::Status encapsulates the information on the
+ * status of a running or terminated system process. The built-in
+ * variable <code>$?</code> is either +nil+ or a
+ * Process::Status object.
+ *
+ * fork { exit 99 } #=> 26557
+ * Process.wait #=> 26557
+ * $?.class #=> Process::Status
+ * $?.to_i #=> 25344
+ * $? >> 8 #=> 99
+ * $?.stopped? #=> false
+ * $?.exited? #=> true
+ * $?.exitstatus #=> 99
+ *
+ * Posix systems record information on processes using a 16-bit
+ * integer. The lower bits record the process status (stopped,
+ * exited, signaled) and the upper bits possibly contain additional
+ * information (for example the program's return code in the case of
+ * exited processes). Pre Ruby 1.8, these bits were exposed directly
+ * to the Ruby program. Ruby now encapsulates these in a
+ * Process::Status object. To maximize compatibility,
+ * however, these objects retain a bit-oriented interface. In the
+ * descriptions that follow, when we talk about the integer value of
+ * _stat_, we're referring to this 16 bit value.
*/
static VALUE rb_cProcessStatus;
@@ -593,17 +604,17 @@ struct rb_process_status {
static const rb_data_type_t rb_process_status_type = {
.wrap_struct_name = "Process::Status",
.function = {
- .dmark = NULL,
.dfree = RUBY_DEFAULT_FREE,
- .dsize = NULL,
},
- .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
+ .data = NULL,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
};
static VALUE
rb_process_status_allocate(VALUE klass)
{
- struct rb_process_status *data;
+ struct rb_process_status *data = NULL;
+
return TypedData_Make_Struct(klass, struct rb_process_status, &rb_process_status_type, data);
}
@@ -615,25 +626,18 @@ rb_last_status_get(void)
/*
* call-seq:
- * Process.last_status -> Process::Status or nil
- *
- * Returns a Process::Status object representing the most recently exited
- * child process in the current thread, or +nil+ if none:
+ * Process.last_status -> Process::Status or nil
*
- * Process.spawn('ruby', '-e', 'exit 13')
- * Process.wait
- * Process.last_status # => #<Process::Status: pid 14396 exit 13>
+ * Returns the status of the last executed child process in the
+ * current thread.
*
- * Process.spawn('ruby', '-e', 'exit 14')
- * Process.wait
- * Process.last_status # => #<Process::Status: pid 4692 exit 14>
+ * Process.wait Process.spawn("ruby", "-e", "exit 13")
+ * Process.last_status #=> #<Process::Status: pid 4825 exit 13>
*
- * Process.spawn('ruby', '-e', 'exit 15')
- * # 'exit 15' has not been reaped by #wait.
- * Process.last_status # => #<Process::Status: pid 4692 exit 14>
- * Process.wait
- * Process.last_status # => #<Process::Status: pid 1380 exit 15>
+ * If no child process has ever been executed in the current
+ * thread, this returns +nil+.
*
+ * Process.last_status #=> nil
*/
static VALUE
proc_s_last_status(VALUE mod)
@@ -645,7 +649,8 @@ VALUE
rb_process_status_new(rb_pid_t pid, int status, int error)
{
VALUE last_status = rb_process_status_allocate(rb_cProcessStatus);
- struct rb_process_status *data = RTYPEDDATA_GET_DATA(last_status);
+
+ struct rb_process_status *data = RTYPEDDATA_DATA(last_status);
data->pid = pid;
data->status = status;
data->error = error;
@@ -658,8 +663,7 @@ static VALUE
process_status_dump(VALUE status)
{
VALUE dump = rb_class_new_instance(0, 0, rb_cObject);
- struct rb_process_status *data;
- TypedData_Get_Struct(status, struct rb_process_status, &rb_process_status_type, data);
+ struct rb_process_status *data = RTYPEDDATA_DATA(status);
if (data->pid) {
rb_ivar_set(dump, id_status, INT2NUM(data->status));
rb_ivar_set(dump, id_pid, PIDT2NUM(data->pid));
@@ -684,42 +688,36 @@ rb_last_status_set(int status, rb_pid_t pid)
GET_THREAD()->last_status = rb_process_status_new(pid, status, 0);
}
-static void
-last_status_clear(rb_thread_t *th)
-{
- th->last_status = Qnil;
-}
-
void
rb_last_status_clear(void)
{
- last_status_clear(GET_THREAD());
+ GET_THREAD()->last_status = Qnil;
}
static rb_pid_t
-pst_pid(VALUE status)
+pst_pid(VALUE pst)
{
- struct rb_process_status *data;
- TypedData_Get_Struct(status, struct rb_process_status, &rb_process_status_type, data);
+ struct rb_process_status *data = RTYPEDDATA_DATA(pst);
return data->pid;
}
static int
-pst_status(VALUE status)
+pst_status(VALUE pst)
{
- struct rb_process_status *data;
- TypedData_Get_Struct(status, struct rb_process_status, &rb_process_status_type, data);
+ struct rb_process_status *data = RTYPEDDATA_DATA(pst);
return data->status;
}
/*
* call-seq:
- * to_i -> integer
+ * stat.to_i -> integer
*
- * Returns the system-dependent integer status of +self+:
+ * Returns the bits in _stat_ as an Integer. Poking
+ * around in these bits is platform dependent.
*
- * `cat /nop`
- * $?.to_i # => 256
+ * fork { exit 0xab } #=> 26566
+ * Process.wait #=> 26566
+ * sprintf('%04x', $?.to_i) #=> "ab00"
*/
static VALUE
@@ -733,13 +731,13 @@ pst_to_i(VALUE self)
/*
* call-seq:
- * pid -> integer
+ * stat.pid -> integer
*
- * Returns the process ID of the process:
- *
- * system("false")
- * $?.pid # => 1247002
+ * Returns the process ID that this status object represents.
*
+ * fork { exit } #=> 26569
+ * Process.wait #=> 26569
+ * $?.pid #=> 26569
*/
static VALUE
@@ -795,13 +793,12 @@ pst_message_status(VALUE str, int status)
/*
* call-seq:
- * to_s -> string
- *
- * Returns a string representation of +self+:
+ * stat.to_s -> string
*
- * `cat /nop`
- * $?.to_s # => "pid 1262141 exit 1"
+ * Show pid and exit status as a string.
*
+ * system("false")
+ * p $?.to_s #=> "pid 12766 exit 1"
*
*/
@@ -823,12 +820,12 @@ pst_to_s(VALUE st)
/*
* call-seq:
- * inspect -> string
+ * stat.inspect -> string
*
- * Returns a string representation of +self+:
+ * Override the inspection method.
*
* system("false")
- * $?.inspect # => "#<Process::Status: pid 1303494 exit 1>"
+ * p $?.inspect #=> "#<Process::Status: pid 12861 exit 1>"
*
*/
@@ -854,15 +851,10 @@ pst_inspect(VALUE st)
/*
* call-seq:
- * stat == other -> true or false
- *
- * Returns whether the value of #to_i == +other+:
- *
- * `cat /nop`
- * stat = $? # => #<Process::Status: pid 1170366 exit 1>
- * sprintf('%x', stat.to_i) # => "100"
- * stat == 0x100 # => true
+ * stat == other -> true or false
*
+ * Returns +true+ if the integer value of _stat_
+ * equals <em>other</em>.
*/
static VALUE
@@ -875,53 +867,20 @@ pst_equal(VALUE st1, VALUE st2)
/*
* call-seq:
- * stat & mask -> integer
- *
- * This method is deprecated as #to_i value is system-specific; use
- * predicate methods like #exited? or #stopped?, or getters like #exitstatus
- * or #stopsig.
- *
- * Returns the logical AND of the value of #to_i with +mask+:
+ * stat & num -> integer
*
- * `cat /nop`
- * stat = $? # => #<Process::Status: pid 1155508 exit 1>
- * sprintf('%x', stat.to_i) # => "100"
- * stat & 0x00 # => 0
+ * Logical AND of the bits in _stat_ with <em>num</em>.
*
- * ArgumentError is raised if +mask+ is negative.
+ * fork { exit 0x37 }
+ * Process.wait
+ * sprintf('%04x', $?.to_i) #=> "3700"
+ * sprintf('%04x', $? & 0x1e00) #=> "1600"
*/
static VALUE
pst_bitand(VALUE st1, VALUE st2)
{
- int status = PST2INT(st1);
- int mask = NUM2INT(st2);
-
- if (mask < 0) {
- rb_raise(rb_eArgError, "negative mask value: %d", mask);
- }
-#define WARN_SUGGEST(suggest) \
- rb_warn_deprecated_to_remove_at(3.5, "Process::Status#&", suggest)
-
- switch (mask) {
- case 0x80:
- WARN_SUGGEST("Process::Status#coredump?");
- break;
- case 0x7f:
- WARN_SUGGEST("Process::Status#signaled? or Process::Status#termsig");
- break;
- case 0xff:
- WARN_SUGGEST("Process::Status#exited?, Process::Status#stopped? or Process::Status#coredump?");
- break;
- case 0xff00:
- WARN_SUGGEST("Process::Status#exitstatus or Process::Status#stopsig");
- break;
- default:
- WARN_SUGGEST("other Process::Status predicates");
- break;
- }
-#undef WARN_SUGGEST
- status &= mask;
+ int status = PST2INT(st1) & NUM2INT(st2);
return INT2NUM(status);
}
@@ -929,48 +888,20 @@ pst_bitand(VALUE st1, VALUE st2)
/*
* call-seq:
- * stat >> places -> integer
- *
- * This method is deprecated as #to_i value is system-specific; use
- * predicate methods like #exited? or #stopped?, or getters like #exitstatus
- * or #stopsig.
- *
- * Returns the value of #to_i, shifted +places+ to the right:
+ * stat >> num -> integer
*
- * `cat /nop`
- * stat = $? # => #<Process::Status: pid 1155508 exit 1>
- * stat.to_i # => 256
- * stat >> 1 # => 128
- * stat >> 2 # => 64
+ * Shift the bits in _stat_ right <em>num</em> places.
*
- * ArgumentError is raised if +places+ is negative.
+ * fork { exit 99 } #=> 26563
+ * Process.wait #=> 26563
+ * $?.to_i #=> 25344
+ * $? >> 8 #=> 99
*/
static VALUE
pst_rshift(VALUE st1, VALUE st2)
{
- int status = PST2INT(st1);
- int places = NUM2INT(st2);
-
- if (places < 0) {
- rb_raise(rb_eArgError, "negative shift value: %d", places);
- }
-#define WARN_SUGGEST(suggest) \
- rb_warn_deprecated_to_remove_at(3.5, "Process::Status#>>", suggest)
-
- switch (places) {
- case 7:
- WARN_SUGGEST("Process::Status#coredump?");
- break;
- case 8:
- WARN_SUGGEST("Process::Status#exitstatus or Process::Status#stopsig");
- break;
- default:
- WARN_SUGGEST("other Process::Status attributes");
- break;
- }
-#undef WARN_SUGGEST
- status >>= places;
+ int status = PST2INT(st1) >> NUM2INT(st2);
return INT2NUM(status);
}
@@ -978,11 +909,11 @@ pst_rshift(VALUE st1, VALUE st2)
/*
* call-seq:
- * stopped? -> true or false
+ * stat.stopped? -> true or false
*
- * Returns +true+ if this process is stopped,
- * and if the corresponding #wait call had the Process::WUNTRACED flag set,
- * +false+ otherwise.
+ * Returns +true+ if this process is stopped. This is only returned
+ * if the corresponding #wait call had the Process::WUNTRACED flag
+ * set.
*/
static VALUE
@@ -996,10 +927,10 @@ pst_wifstopped(VALUE st)
/*
* call-seq:
- * stopsig -> integer or nil
+ * stat.stopsig -> integer or nil
*
- * Returns the number of the signal that caused the process to stop,
- * or +nil+ if the process is not stopped.
+ * Returns the number of the signal that caused _stat_ to stop
+ * (or +nil+ if self is not stopped).
*/
static VALUE
@@ -1015,10 +946,10 @@ pst_wstopsig(VALUE st)
/*
* call-seq:
- * signaled? -> true or false
+ * stat.signaled? -> true or false
*
- * Returns +true+ if the process terminated because of an uncaught signal,
- * +false+ otherwise.
+ * Returns +true+ if _stat_ terminated because of
+ * an uncaught signal.
*/
static VALUE
@@ -1032,10 +963,11 @@ pst_wifsignaled(VALUE st)
/*
* call-seq:
- * termsig -> integer or nil
+ * stat.termsig -> integer or nil
*
- * Returns the number of the signal that caused the process to terminate
- * or +nil+ if the process was not terminated by an uncaught signal.
+ * Returns the number of the signal that caused _stat_ to
+ * terminate (or +nil+ if self was not terminated by an
+ * uncaught signal).
*/
static VALUE
@@ -1051,11 +983,11 @@ pst_wtermsig(VALUE st)
/*
* call-seq:
- * exited? -> true or false
+ * stat.exited? -> true or false
*
- * Returns +true+ if the process exited normally
- * (for example using an <code>exit()</code> call or finishing the
- * program), +false+ if not.
+ * Returns +true+ if _stat_ exited normally (for
+ * example using an <code>exit()</code> call or finishing the
+ * program).
*/
static VALUE
@@ -1069,15 +1001,20 @@ pst_wifexited(VALUE st)
/*
* call-seq:
- * exitstatus -> integer or nil
+ * stat.exitstatus -> integer or nil
*
- * Returns the least significant eight bits of the return code
- * of the process if it has exited;
- * +nil+ otherwise:
+ * Returns the least significant eight bits of the return code of
+ * _stat_. Only available if #exited? is +true+.
*
- * `exit 99`
- * $?.exitstatus # => 99
+ * fork { } #=> 26572
+ * Process.wait #=> 26572
+ * $?.exited? #=> true
+ * $?.exitstatus #=> 0
*
+ * fork { exit 99 } #=> 26573
+ * Process.wait #=> 26573
+ * $?.exited? #=> true
+ * $?.exitstatus #=> 99
*/
static VALUE
@@ -1093,14 +1030,10 @@ pst_wexitstatus(VALUE st)
/*
* call-seq:
- * success? -> true, false, or nil
- *
- * Returns:
- *
- * - +true+ if the process has completed successfully and exited.
- * - +false+ if the process has completed unsuccessfully and exited.
- * - +nil+ if the process has not exited.
+ * stat.success? -> true, false or nil
*
+ * Returns +true+ if _stat_ is successful, +false+ if not.
+ * Returns +nil+ if #exited? is not +true+.
*/
static VALUE
@@ -1116,12 +1049,10 @@ pst_success_p(VALUE st)
/*
* call-seq:
- * coredump? -> true or false
+ * stat.coredump? -> true or false
*
- * Returns +true+ if the process generated a coredump
- * when it terminated, +false+ if not.
- *
- * Not available on all platforms.
+ * Returns +true+ if _stat_ generated a coredump
+ * when it terminated. Not available on all platforms.
*/
static VALUE
@@ -1148,6 +1079,8 @@ do_waitpid(rb_pid_t pid, int *st, int flags)
#endif
}
+#define WAITPID_LOCK_ONLY ((struct waitpid_state *)-1)
+
struct waitpid_state {
struct ccan_list_node wnode;
rb_execution_context_t *ec;
@@ -1159,6 +1092,129 @@ struct waitpid_state {
int errnum;
};
+int rb_sigwait_fd_get(const rb_thread_t *);
+void rb_sigwait_sleep(const rb_thread_t *, int fd, const rb_hrtime_t *);
+void rb_sigwait_fd_put(const rb_thread_t *, int fd);
+void rb_thread_sleep_interruptible(void);
+
+#if USE_MJIT
+static struct waitpid_state mjit_waitpid_state;
+
+// variables shared with thread.c
+// TODO: implement the same thing with postponed_job and obviate these variables
+bool mjit_waitpid_finished = false;
+int mjit_waitpid_status = 0;
+#endif
+
+static int
+waitpid_signal(struct waitpid_state *w)
+{
+ if (w->ec) { /* rb_waitpid */
+ rb_threadptr_interrupt(rb_ec_thread_ptr(w->ec));
+ return TRUE;
+ }
+#if USE_MJIT
+ else if (w == &mjit_waitpid_state && w->ret) { /* mjit_add_waiting_pid */
+ mjit_waitpid_finished = true;
+ mjit_waitpid_status = w->status;
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+// Used for VM memsize reporting. Returns the size of a list of waitpid_state
+// structs. Defined here because the struct definition lives here as well.
+size_t
+rb_vm_memsize_waiting_list(struct ccan_list_head *waiting_list)
+{
+ struct waitpid_state *waitpid = 0;
+ size_t size = 0;
+
+ ccan_list_for_each(waiting_list, waitpid, wnode) {
+ size += sizeof(struct waitpid_state);
+ }
+
+ return size;
+}
+
+/*
+ * When a thread is done using sigwait_fd and there are other threads
+ * sleeping on waitpid, we must kick one of the threads out of
+ * rb_native_cond_wait so it can switch to rb_sigwait_sleep
+ */
+static void
+sigwait_fd_migrate_sleeper(rb_vm_t *vm)
+{
+ struct waitpid_state *w = 0;
+
+ ccan_list_for_each(&vm->waiting_pids, w, wnode) {
+ if (waitpid_signal(w)) return;
+ }
+ ccan_list_for_each(&vm->waiting_grps, w, wnode) {
+ if (waitpid_signal(w)) return;
+ }
+}
+
+void
+rb_sigwait_fd_migrate(rb_vm_t *vm)
+{
+ rb_native_mutex_lock(&vm->waitpid_lock);
+ sigwait_fd_migrate_sleeper(vm);
+ rb_native_mutex_unlock(&vm->waitpid_lock);
+}
+
+#if RUBY_SIGCHLD
+extern volatile unsigned int ruby_nocldwait; /* signal.c */
+/* called by timer thread or thread which acquired sigwait_fd */
+static void
+waitpid_each(rb_vm_t *vm, struct ccan_list_head *head)
+{
+ struct waitpid_state *w = 0, *next;
+
+ ccan_list_for_each_safe(head, w, next, wnode) {
+ rb_pid_t ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
+
+ if (!ret) continue;
+ if (ret == -1) w->errnum = errno;
+
+ if (w->pid <= 0) {
+ /* when waiting for a group of processes, make sure a waiter for a
+ * specific pid is given that event in preference */
+ struct waitpid_state *w_inner = 0, *next_inner;
+ ccan_list_for_each_safe(&vm->waiting_pids, w_inner, next_inner, wnode) {
+ if (w_inner->pid == ret) {
+ /* signal this one instead */
+ w = w_inner;
+ }
+ }
+ }
+
+ w->ret = ret;
+ ccan_list_del_init(&w->wnode);
+ waitpid_signal(w);
+ }
+}
+#else
+# define ruby_nocldwait 0
+#endif
+
+void
+ruby_waitpid_all(rb_vm_t *vm)
+{
+#if RUBY_SIGCHLD
+ rb_native_mutex_lock(&vm->waitpid_lock);
+ waitpid_each(vm, &vm->waiting_pids);
+ waitpid_each(vm, &vm->waiting_grps);
+ /* emulate SA_NOCLDWAIT */
+ if (ccan_list_empty(&vm->waiting_pids) && ccan_list_empty(&vm->waiting_grps)) {
+ while (ruby_nocldwait && do_waitpid(-1, 0, WNOHANG) > 0)
+ ; /* keep looping */
+ }
+ rb_native_mutex_unlock(&vm->waitpid_lock);
+#endif
+}
+
static void
waitpid_state_init(struct waitpid_state *w, rb_pid_t pid, int options)
{
@@ -1169,6 +1225,99 @@ waitpid_state_init(struct waitpid_state *w, rb_pid_t pid, int options)
w->status = 0;
}
+#if USE_MJIT
+/*
+ * must be called with vm->waitpid_lock held, this is not interruptible
+ */
+void
+mjit_add_waiting_pid(rb_vm_t *vm, rb_pid_t pid)
+{
+ waitpid_state_init(&mjit_waitpid_state, pid, 0);
+ mjit_waitpid_state.ec = 0; // switch the behavior of waitpid_signal
+ ccan_list_add(&vm->waiting_pids, &mjit_waitpid_state.wnode);
+}
+#endif
+
+static VALUE
+waitpid_sleep(VALUE x)
+{
+ struct waitpid_state *w = (struct waitpid_state *)x;
+
+ while (!w->ret) {
+ rb_thread_sleep_interruptible();
+ }
+
+ return Qfalse;
+}
+
+static VALUE
+waitpid_cleanup(VALUE x)
+{
+ struct waitpid_state *w = (struct waitpid_state *)x;
+
+ /*
+ * XXX w->ret is sometimes set but ccan_list_del is still needed, here,
+ * Not sure why, so we unconditionally do ccan_list_del here:
+ */
+ if (TRUE || w->ret == 0) {
+ rb_vm_t *vm = rb_ec_vm_ptr(w->ec);
+
+ rb_native_mutex_lock(&vm->waitpid_lock);
+ ccan_list_del(&w->wnode);
+ rb_native_mutex_unlock(&vm->waitpid_lock);
+ }
+
+ return Qfalse;
+}
+
+#if RUBY_SIGCHLD
+static void
+waitpid_wait(struct waitpid_state *w)
+{
+ rb_vm_t *vm = rb_ec_vm_ptr(w->ec);
+ int need_sleep = FALSE;
+
+ /*
+ * Lock here to prevent do_waitpid from stealing work from the
+ * ruby_waitpid_locked done by mjit workers since mjit works
+ * outside of GVL
+ */
+ rb_native_mutex_lock(&vm->waitpid_lock);
+
+ if (w->options & WNOHANG && w->pid <= 0) {
+ /* In the case of WNOHANG wait for a group, make sure there isn't a zombie child
+ * whose PID we are directly waiting for in another call to waitpid. If there is,
+ * we will reap it via a call to waitpid($pid) with this call to waitpid_each. */
+ waitpid_each(vm, &vm->waiting_pids);
+ /* _now_ it's safe to call do_waitpid, without risk of stealing the wait from
+ * another directed call. */
+ }
+
+ w->ret = do_waitpid(w->pid, &w->status, w->options | WNOHANG);
+
+ if (w->ret) {
+ if (w->ret == -1) w->errnum = errno;
+ }
+ else if (w->options & WNOHANG) {
+ }
+ else {
+ need_sleep = TRUE;
+ }
+
+ if (need_sleep) {
+ w->cond = 0;
+ /* order matters, favor specified PIDs rather than -1 or 0 */
+ ccan_list_add(w->pid > 0 ? &vm->waiting_pids : &vm->waiting_grps, &w->wnode);
+ }
+
+ rb_native_mutex_unlock(&vm->waitpid_lock);
+
+ if (need_sleep) {
+ rb_ensure(waitpid_sleep, (VALUE)w, waitpid_cleanup, (VALUE)w);
+ }
+}
+#endif
+
static void *
waitpid_blocking_no_SIGCHLD(void *x)
{
@@ -1187,7 +1336,8 @@ waitpid_no_SIGCHLD(struct waitpid_state *w)
}
else {
do {
- rb_thread_call_without_gvl(waitpid_blocking_no_SIGCHLD, w, RUBY_UBF_PROCESS, 0);
+ rb_thread_call_without_gvl(waitpid_blocking_no_SIGCHLD, w,
+ RUBY_UBF_PROCESS, 0);
} while (w->ret < 0 && errno == EINTR && (RUBY_VM_CHECK_INTS(w->ec),1));
}
if (w->ret == -1)
@@ -1209,44 +1359,67 @@ rb_process_status_wait(rb_pid_t pid, int flags)
waitpid_state_init(&waitpid_state, pid, flags);
waitpid_state.ec = GET_EC();
+#if WAITPID_USE_SIGCHLD
+ waitpid_wait(&waitpid_state);
+#else
waitpid_no_SIGCHLD(&waitpid_state);
+#endif
if (waitpid_state.ret == 0) return Qnil;
+ if (waitpid_state.ret > 0 && ruby_nocldwait) {
+ waitpid_state.ret = -1;
+ waitpid_state.errnum = ECHILD;
+ }
+
return rb_process_status_new(waitpid_state.ret, waitpid_state.status, waitpid_state.errnum);
}
/*
* call-seq:
- * Process::Status.wait(pid = -1, flags = 0) -> Process::Status
+ * Process::Status.wait(pid=-1, flags=0) -> Process::Status
*
- * Like Process.wait, but returns a Process::Status object
- * (instead of an integer pid or nil);
- * see Process.wait for the values of +pid+ and +flags+.
+ * Waits for a child process to exit and returns a Process::Status object
+ * containing information on that process. Which child it waits on
+ * depends on the value of _pid_:
*
- * If there are child processes,
- * waits for a child process to exit and returns a Process::Status object
- * containing information on that process;
- * sets thread-local variable <tt>$?</tt>:
+ * > 0:: Waits for the child whose process ID equals _pid_.
*
- * Process.spawn('cat /nop') # => 1155880
- * Process::Status.wait # => #<Process::Status: pid 1155880 exit 1>
- * $? # => #<Process::Status: pid 1155508 exit 1>
+ * 0:: Waits for any child whose process group ID equals that of the
+ * calling process.
*
- * If there is no child process,
- * returns an "empty" Process::Status object
- * that does not represent an actual process;
- * does not set thread-local variable <tt>$?</tt>:
+ * -1:: Waits for any child process (the default if no _pid_ is
+ * given).
*
- * Process::Status.wait # => #<Process::Status: pid -1 exit 0>
- * $? # => #<Process::Status: pid 1155508 exit 1> # Unchanged.
+ * < -1:: Waits for any child whose process group ID equals the absolute
+ * value of _pid_.
*
- * May invoke the scheduler hook Fiber::Scheduler#process_wait.
+ * The _flags_ argument may be a logical or of the flag values
+ * Process::WNOHANG (do not block if no child available)
+ * or Process::WUNTRACED (return stopped children that
+ * haven't been reported). Not all flags are available on all
+ * platforms, but a flag value of zero will work on all platforms.
*
+ * Returns +nil+ if there are no child processes.
* Not available on all platforms.
+ *
+ * May invoke the scheduler hook _process_wait_.
+ *
+ * fork { exit 99 } #=> 27429
+ * Process::Status.wait #=> pid 27429 exit 99
+ * $? #=> nil
+ *
+ * pid = fork { sleep 3 } #=> 27440
+ * Time.now #=> 2008-03-08 19:56:16 +0900
+ * Process::Status.wait(pid, Process::WNOHANG) #=> nil
+ * Time.now #=> 2008-03-08 19:56:16 +0900
+ * Process::Status.wait(pid, 0) #=> pid 27440 exit 99
+ * Time.now #=> 2008-03-08 19:56:19 +0900
+ *
+ * This is an EXPERIMENTAL FEATURE.
*/
-static VALUE
+VALUE
rb_process_status_waitv(int argc, VALUE *argv, VALUE _)
{
rb_check_arity(argc, 0, 2);
@@ -1331,155 +1504,69 @@ proc_wait(int argc, VALUE *argv)
/*
* call-seq:
- * Process.wait(pid = -1, flags = 0) -> integer
- *
- * Waits for a suitable child process to exit, returns its process ID,
- * and sets <tt>$?</tt> to a Process::Status object
- * containing information on that process.
- * Which child it waits for depends on the value of the given +pid+:
- *
- * - Positive integer: Waits for the child process whose process ID is +pid+:
- *
- * pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 230866
- * pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 230891
- * Process.wait(pid0) # => 230866
- * $? # => #<Process::Status: pid 230866 exit 13>
- * Process.wait(pid1) # => 230891
- * $? # => #<Process::Status: pid 230891 exit 14>
- * Process.wait(pid0) # Raises Errno::ECHILD
- *
- * - <tt>0</tt>: Waits for any child process whose group ID
- * is the same as that of the current process:
- *
- * parent_pgpid = Process.getpgid(Process.pid)
- * puts "Parent process group ID is #{parent_pgpid}."
- * child0_pid = fork do
- * puts "Child 0 pid is #{Process.pid}"
- * child0_pgid = Process.getpgid(Process.pid)
- * puts "Child 0 process group ID is #{child0_pgid} (same as parent's)."
- * end
- * child1_pid = fork do
- * puts "Child 1 pid is #{Process.pid}"
- * Process.setpgid(0, Process.pid)
- * child1_pgid = Process.getpgid(Process.pid)
- * puts "Child 1 process group ID is #{child1_pgid} (different from parent's)."
- * end
- * retrieved_pid = Process.wait(0)
- * puts "Process.wait(0) returned pid #{retrieved_pid}, which is child 0 pid."
- * begin
- * Process.wait(0)
- * rescue Errno::ECHILD => x
- * puts "Raised #{x.class}, because child 1 process group ID differs from parent process group ID."
- * end
- *
- * Output:
- *
- * Parent process group ID is 225764.
- * Child 0 pid is 225788
- * Child 0 process group ID is 225764 (same as parent's).
- * Child 1 pid is 225789
- * Child 1 process group ID is 225789 (different from parent's).
- * Process.wait(0) returned pid 225788, which is child 0 pid.
- * Raised Errno::ECHILD, because child 1 process group ID differs from parent process group ID.
- *
- * - <tt>-1</tt> (default): Waits for any child process:
- *
- * parent_pgpid = Process.getpgid(Process.pid)
- * puts "Parent process group ID is #{parent_pgpid}."
- * child0_pid = fork do
- * puts "Child 0 pid is #{Process.pid}"
- * child0_pgid = Process.getpgid(Process.pid)
- * puts "Child 0 process group ID is #{child0_pgid} (same as parent's)."
- * end
- * child1_pid = fork do
- * puts "Child 1 pid is #{Process.pid}"
- * Process.setpgid(0, Process.pid)
- * child1_pgid = Process.getpgid(Process.pid)
- * puts "Child 1 process group ID is #{child1_pgid} (different from parent's)."
- * sleep 3 # To force child 1 to exit later than child 0 exit.
- * end
- * child_pids = [child0_pid, child1_pid]
- * retrieved_pid = Process.wait(-1)
- * puts child_pids.include?(retrieved_pid)
- * retrieved_pid = Process.wait(-1)
- * puts child_pids.include?(retrieved_pid)
- *
- * Output:
- *
- * Parent process group ID is 228736.
- * Child 0 pid is 228758
- * Child 0 process group ID is 228736 (same as parent's).
- * Child 1 pid is 228759
- * Child 1 process group ID is 228759 (different from parent's).
- * true
- * true
- *
- * - Less than <tt>-1</tt>: Waits for any child whose process group ID is <tt>-pid</tt>:
- *
- * parent_pgpid = Process.getpgid(Process.pid)
- * puts "Parent process group ID is #{parent_pgpid}."
- * child0_pid = fork do
- * puts "Child 0 pid is #{Process.pid}"
- * child0_pgid = Process.getpgid(Process.pid)
- * puts "Child 0 process group ID is #{child0_pgid} (same as parent's)."
- * end
- * child1_pid = fork do
- * puts "Child 1 pid is #{Process.pid}"
- * Process.setpgid(0, Process.pid)
- * child1_pgid = Process.getpgid(Process.pid)
- * puts "Child 1 process group ID is #{child1_pgid} (different from parent's)."
- * end
- * sleep 1
- * retrieved_pid = Process.wait(-child1_pid)
- * puts "Process.wait(-child1_pid) returned pid #{retrieved_pid}, which is child 1 pid."
- * begin
- * Process.wait(-child1_pid)
- * rescue Errno::ECHILD => x
- * puts "Raised #{x.class}, because there's no longer a child with process group id #{child1_pid}."
- * end
- *
- * Output:
- *
- * Parent process group ID is 230083.
- * Child 0 pid is 230108
- * Child 0 process group ID is 230083 (same as parent's).
- * Child 1 pid is 230109
- * Child 1 process group ID is 230109 (different from parent's).
- * Process.wait(-child1_pid) returned pid 230109, which is child 1 pid.
- * Raised Errno::ECHILD, because there's no longer a child with process group id 230109.
- *
- * Argument +flags+ should be given as one of the following constants,
- * or as the logical OR of both:
- *
- * - Process::WNOHANG: Does not block if no child process is available.
- * - Process::WUNTRACED: May return a stopped child process, even if not yet reported.
- *
- * Not all flags are available on all platforms.
- *
- * Raises Errno::ECHILD if there is no suitable child process.
- *
- * Not available on all platforms.
- *
- * Process.waitpid is an alias for Process.wait.
+ * Process.wait() -> integer
+ * Process.wait(pid=-1, flags=0) -> integer
+ * Process.waitpid(pid=-1, flags=0) -> integer
+ *
+ * Waits for a child process to exit, returns its process id, and
+ * sets <code>$?</code> to a Process::Status object
+ * containing information on that process. Which child it waits on
+ * depends on the value of _pid_:
+ *
+ * > 0:: Waits for the child whose process ID equals _pid_.
+ *
+ * 0:: Waits for any child whose process group ID equals that of the
+ * calling process.
+ *
+ * -1:: Waits for any child process (the default if no _pid_ is
+ * given).
+ *
+ * < -1:: Waits for any child whose process group ID equals the absolute
+ * value of _pid_.
+ *
+ * The _flags_ argument may be a logical or of the flag values
+ * Process::WNOHANG (do not block if no child available)
+ * or Process::WUNTRACED (return stopped children that
+ * haven't been reported). Not all flags are available on all
+ * platforms, but a flag value of zero will work on all platforms.
+ *
+ * Calling this method raises a SystemCallError if there are no child
+ * processes. Not available on all platforms.
+ *
+ * include Process
+ * fork { exit 99 } #=> 27429
+ * wait #=> 27429
+ * $?.exitstatus #=> 99
+ *
+ * pid = fork { sleep 3 } #=> 27440
+ * Time.now #=> 2008-03-08 19:56:16 +0900
+ * waitpid(pid, Process::WNOHANG) #=> nil
+ * Time.now #=> 2008-03-08 19:56:16 +0900
+ * waitpid(pid, 0) #=> 27440
+ * Time.now #=> 2008-03-08 19:56:19 +0900
*/
+
static VALUE
proc_m_wait(int c, VALUE *v, VALUE _)
{
return proc_wait(c, v);
}
+
/*
* call-seq:
- * Process.wait2(pid = -1, flags = 0) -> [pid, status]
- *
- * Like Process.waitpid, but returns an array
- * containing the child process +pid+ and Process::Status +status+:
- *
- * pid = Process.spawn('ruby', '-e', 'exit 13') # => 309581
- * Process.wait2(pid)
- * # => [309581, #<Process::Status: pid 309581 exit 13>]
- *
- * Process.waitpid2 is an alias for Process.wait2.
+ * Process.wait2(pid=-1, flags=0) -> [pid, status]
+ * Process.waitpid2(pid=-1, flags=0) -> [pid, status]
+ *
+ * Waits for a child process to exit (see Process::waitpid for exact
+ * semantics) and returns an array containing the process id and the
+ * exit status (a Process::Status object) of that
+ * child. Raises a SystemCallError if there are no child processes.
+ *
+ * Process.fork { exit 99 } #=> 27437
+ * pid, status = Process.wait2
+ * pid #=> 27437
+ * status.exitstatus #=> 99
*/
static VALUE
@@ -1493,17 +1580,22 @@ proc_wait2(int argc, VALUE *argv, VALUE _)
/*
* call-seq:
- * Process.waitall -> array
+ * Process.waitall -> [ [pid1,status1], ...]
*
- * Waits for all children, returns an array of 2-element arrays;
- * each subarray contains the integer pid and Process::Status status
- * for one of the reaped child processes:
+ * Waits for all children, returning an array of
+ * _pid_/_status_ pairs (where _status_ is a
+ * Process::Status object).
*
- * pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 325470
- * pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 325495
- * Process.waitall
- * # => [[325470, #<Process::Status: pid 325470 exit 13>], [325495, #<Process::Status: pid 325495 exit 14>]]
+ * fork { sleep 0.2; exit 2 } #=> 27432
+ * fork { sleep 0.1; exit 1 } #=> 27433
+ * fork { exit 0 } #=> 27434
+ * p Process.waitall
*
+ * <em>produces</em>:
+ *
+ * [[30982, #<Process::Status: pid 30982 exit 0>],
+ * [30979, #<Process::Status: pid 30979 exit 1>],
+ * [30976, #<Process::Status: pid 30976 exit 2>]]
*/
static VALUE
@@ -1561,41 +1653,48 @@ rb_detach_process(rb_pid_t pid)
/*
* call-seq:
- * Process.detach(pid) -> thread
- *
- * Avoids the potential for a child process to become a
- * {zombie process}[https://en.wikipedia.org/wiki/Zombie_process].
- * Process.detach prevents this by setting up a separate Ruby thread
- * whose sole job is to reap the status of the process _pid_ when it terminates.
+ * Process.detach(pid) -> thread
*
- * This method is needed only when the parent process will never wait
- * for the child process.
+ * Some operating systems retain the status of terminated child
+ * processes until the parent collects that status (normally using
+ * some variant of <code>wait()</code>). If the parent never collects
+ * this status, the child stays around as a <em>zombie</em> process.
+ * Process::detach prevents this by setting up a separate Ruby thread
+ * whose sole job is to reap the status of the process _pid_ when it
+ * terminates. Use #detach only when you do not intend to explicitly
+ * wait for the child to terminate.
*
- * This example does not reap the second child process;
- * that process appears as a zombie in the process status (+ps+) output:
+ * The waiting thread returns the exit status of the detached process
+ * when it terminates, so you can use Thread#join to
+ * know the result. If specified _pid_ is not a valid child process
+ * ID, the thread returns +nil+ immediately.
*
- * pid = Process.spawn('ruby', '-e', 'exit 13') # => 312691
- * sleep(1)
- * # Find zombies.
- * system("ps -ho pid,state -p #{pid}")
+ * The waiting thread has #pid method which returns the pid.
*
- * Output:
+ * In this first example, we don't reap the first child process, so
+ * it appears as a zombie in the process status display.
*
- * 312716 Z
+ * p1 = fork { sleep 0.1 }
+ * p2 = fork { sleep 0.2 }
+ * Process.waitpid(p2)
+ * sleep 2
+ * system("ps -ho pid,state -p #{p1}")
*
- * This example also does not reap the second child process,
- * but it does detach the process so that it does not become a zombie:
+ * <em>produces:</em>
*
- * pid = Process.spawn('ruby', '-e', 'exit 13') # => 313213
- * thread = Process.detach(pid)
- * sleep(1)
- * # => #<Process::Waiter:0x00007f038f48b838 run>
- * system("ps -ho pid,state -p #{pid}") # Finds no zombies.
+ * 27389 Z
*
- * The waiting thread can return the pid of the detached child process:
+ * In the next example, Process::detach is used to reap
+ * the child automatically.
*
- * thread.join.pid # => 313262
+ * p1 = fork { sleep 0.1 }
+ * p2 = fork { sleep 0.2 }
+ * Process.detach(p1)
+ * Process.waitpid(p2)
+ * sleep 2
+ * system("ps -ho pid,state -p #{p1}")
*
+ * <em>(produces no output)</em>
*/
static VALUE
@@ -1665,13 +1764,26 @@ before_exec(void)
before_exec_async_signal_safe();
}
+/* This function should be async-signal-safe. Actually it is. */
static void
-after_exec(void)
+after_exec_async_signal_safe(void)
+{
+}
+
+static void
+after_exec_non_async_signal_safe(void)
{
rb_thread_reset_timer_thread();
rb_thread_start_timer_thread();
}
+static void
+after_exec(void)
+{
+ after_exec_async_signal_safe();
+ after_exec_non_async_signal_safe();
+}
+
#if defined HAVE_WORKING_FORK || defined HAVE_DAEMON
static void
before_fork_ruby(void)
@@ -1680,33 +1792,14 @@ before_fork_ruby(void)
}
static void
-after_fork_ruby(rb_pid_t pid)
+after_fork_ruby(void)
{
- if (pid == 0) {
- // child
- clear_pid_cache();
- rb_thread_atfork();
- }
- else {
- // parent
- after_exec();
- }
+ after_exec();
}
#endif
#if defined(HAVE_WORKING_FORK)
-COMPILER_WARNING_PUSH
-#if __has_warning("-Wdeprecated-declarations") || RBIMPL_COMPILER_IS(GCC)
-COMPILER_WARNING_IGNORED(-Wdeprecated-declarations)
-#endif
-static inline rb_pid_t
-rb_fork(void)
-{
- return fork();
-}
-COMPILER_WARNING_POP
-
/* try_with_sh and exec_with_sh should be async-signal-safe. Actually it is.*/
#define try_with_sh(err, prog, argv, envp) ((err == ENOEXEC) ? exec_with_sh((prog), (argv), (envp)) : (void)0)
static void
@@ -1838,7 +1931,7 @@ memsize_exec_arg(const void *ptr)
static const rb_data_type_t exec_arg_data_type = {
"exec_arg",
{mark_exec_arg, RUBY_TYPED_DEFAULT_FREE, memsize_exec_arg},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
#ifdef _WIN32
@@ -2481,12 +2574,12 @@ rb_check_argv(int argc, VALUE *argv)
}
prog = RARRAY_AREF(tmp, 0);
argv[0] = RARRAY_AREF(tmp, 1);
- StringValue(prog);
+ SafeStringValue(prog);
StringValueCStr(prog);
prog = rb_str_new_frozen(prog);
}
for (i = 0; i < argc; i++) {
- StringValue(argv[i]);
+ SafeStringValue(argv[i]);
argv[i] = rb_str_new_frozen(argv[i]);
StringValueCStr(argv[i]);
}
@@ -2782,7 +2875,6 @@ rb_execarg_setenv(VALUE execarg_obj, VALUE env)
struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
env = !NIL_P(env) ? rb_check_exec_env(env, &eargp->path_env) : Qfalse;
eargp->env_modification = env;
- RB_GC_GUARD(execarg_obj);
}
static int
@@ -2980,7 +3072,6 @@ execarg_parent_end(VALUE execarg_obj)
}
errno = err;
- RB_GC_GUARD(execarg_obj);
return execarg_obj;
}
@@ -3022,6 +3113,7 @@ rb_f_exec(int argc, const VALUE *argv)
execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
eargp = rb_execarg_get(execarg_obj);
+ if (mjit_enabled) mjit_finish(false); // avoid leaking resources, and do not leave files. XXX: JIT-ed handle can leak after exec error is rescued.
before_exec(); /* stop timer thread before redirects */
rb_protect(rb_execarg_parent_start1, execarg_obj, &state);
@@ -3046,91 +3138,77 @@ NORETURN(static VALUE f_exec(int c, const VALUE *a, VALUE _));
/*
* call-seq:
- * exec([env, ] command_line, options = {})
- * exec([env, ] exe_path, *args, options = {})
+ * exec([env,] command... [,options])
*
- * Replaces the current process by doing one of the following:
+ * Replaces the current process by running the given external _command_, which
+ * can take one of the following forms:
*
- * - Passing string +command_line+ to the shell.
- * - Invoking the executable at +exe_path+.
+ * [<code>exec(commandline)</code>]
+ * command line string which is passed to the standard shell
+ * [<code>exec(cmdname, arg1, ...)</code>]
+ * command name and one or more arguments (no shell)
+ * [<code>exec([cmdname, argv0], arg1, ...)</code>]
+ * command name, +argv[0]+ and zero or more arguments (no shell)
*
- * This method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
- *
- * The new process is created using the
- * {exec system call}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/execve.html];
- * it may inherit some of its environment from the calling program
- * (possibly including open file descriptors).
- *
- * Argument +env+, if given, is a hash that affects +ENV+ for the new process;
- * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- *
- * Argument +options+ is a hash of options for the new process;
- * see {Execution Options}[rdoc-ref:Process@Execution+Options].
- *
- * The first required argument is one of the following:
- *
- * - +command_line+ if it is a string,
- * and if it begins with a shell reserved word or special built-in,
- * or if it contains one or more meta characters.
- * - +exe_path+ otherwise.
- *
- * <b>Argument +command_line+</b>
- *
- * \String argument +command_line+ is a command line to be passed to a shell;
- * it must begin with a shell reserved word, begin with a special built-in,
- * or contain meta characters:
- *
- * exec('if true; then echo "Foo"; fi') # Shell reserved word.
- * exec('exit') # Built-in.
- * exec('date > date.tmp') # Contains meta character.
+ * In the first form, the string is taken as a command line that is subject to
+ * shell expansion before being executed.
*
- * The command line may also contain arguments and options for the command:
+ * The standard shell always means <code>"/bin/sh"</code> on Unix-like systems,
+ * otherwise, <code>ENV["RUBYSHELL"]</code> or <code>ENV["COMSPEC"]</code> on
+ * Windows and similar. The command is passed as an argument to the
+ * <code>"-c"</code> switch to the shell, except in the case of +COMSPEC+.
*
- * exec('echo "Foo"')
+ * If the string from the first form (<code>exec("command")</code>) follows
+ * these simple rules:
*
- * Output:
+ * * no meta characters,
+ * * not starting with shell reserved word or special built-in,
*
- * Foo
+ * Ruby invokes the command directly without shell.
*
- * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
+ * You can force shell invocation by adding ";" to the string (because ";" is
+ * a meta character).
*
- * Raises an exception if the new process could not execute.
+ * Note that this behavior is observable by pid obtained
+ * (return value of spawn() and IO#pid for IO.popen) is the pid of the invoked
+ * command, not shell.
*
- * <b>Argument +exe_path+</b>
+ * In the second form (<code>exec("command1", "arg1", ...)</code>), the first
+ * is taken as a command name and the rest are passed as parameters to command
+ * with no shell expansion.
*
- * Argument +exe_path+ is one of the following:
+ * In the third form (<code>exec(["command", "argv0"], "arg1", ...)</code>),
+ * starting a two-element array at the beginning of the command, the first
+ * element is the command to be executed, and the second argument is used as
+ * the <code>argv[0]</code> value, which may show up in process listings.
*
- * - The string path to an executable to be called.
- * - A 2-element array containing the path to an executable
- * and the string to be used as the name of the executing process.
+ * In order to execute the command, one of the <code>exec(2)</code> system
+ * calls are used, so the running command may inherit some of the environment
+ * of the original program (including open file descriptors).
*
- * Example:
+ * This behavior is modified by the given +env+ and +options+ parameters. See
+ * ::spawn for details.
*
- * exec('/usr/bin/date')
+ * If the command fails to execute (typically Errno::ENOENT when
+ * it was not found) a SystemCallError exception is raised.
*
- * Output:
+ * This method modifies process attributes according to given +options+ before
+ * <code>exec(2)</code> system call. See ::spawn for more details about the
+ * given +options+.
*
- * Sat Aug 26 09:38:00 AM CDT 2023
+ * The modified attributes may be retained when <code>exec(2)</code> system
+ * call fails.
*
- * Ruby invokes the executable directly.
- * This form does not use the shell;
- * see {Arguments args}[rdoc-ref:Process@Arguments+args] for caveats.
+ * For example, hard resource limits are not restorable.
*
- * exec('doesnt_exist') # Raises Errno::ENOENT
+ * Consider to create a child process using ::spawn or Kernel#system if this
+ * is not acceptable.
*
- * If one or more +args+ is given, each is an argument or option
- * to be passed to the executable:
+ * exec "echo *" # echoes list of files in current directory
+ * # never get here
*
- * exec('echo', 'C*')
- * exec('echo', 'hello', 'world')
- *
- * Output:
- *
- * C*
- * hello world
- *
- * Raises an exception if the new process could not execute.
+ * exec "echo", "*" # echoes an asterisk
+ * # never get here
*/
static VALUE
@@ -3140,13 +3218,9 @@ f_exec(int c, const VALUE *a, VALUE _)
UNREACHABLE_RETURN(Qnil);
}
-#define ERRMSG(str) \
- ((errmsg && 0 < errmsg_buflen) ? \
- (void)strlcpy(errmsg, (str), errmsg_buflen) : (void)0)
-
-#define ERRMSG_FMT(...) \
- ((errmsg && 0 < errmsg_buflen) ? \
- (void)snprintf(errmsg, errmsg_buflen, __VA_ARGS__) : (void)0)
+#define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
+#define ERRMSG1(str, a) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a)); } while (0)
+#define ERRMSG2(str, a, b) do { if (errmsg && 0 < errmsg_buflen) snprintf(errmsg, errmsg_buflen, (str), (a), (b)); } while (0)
static int fd_get_cloexec(int fd, char *errmsg, size_t errmsg_buflen);
static int fd_set_cloexec(int fd, char *errmsg, size_t errmsg_buflen);
@@ -3359,13 +3433,6 @@ run_exec_dup2(VALUE ary, VALUE tmpbuf, struct rb_execarg *sargp, char *errmsg, s
ERRMSG("dup");
goto fail;
}
- // without this, kqueue timer_th.event_fd fails with a reserved FD did not have close-on-exec
- // in #assert_close_on_exec because the FD_CLOEXEC is not dup'd by default
- if (fd_get_cloexec(pairs[i].oldfd, errmsg, errmsg_buflen)) {
- if (fd_set_cloexec(extra_fd, errmsg, errmsg_buflen)) {
- goto fail;
- }
- }
rb_update_max_fd(extra_fd);
}
else {
@@ -4104,10 +4171,16 @@ retry_fork_async_signal_safe(struct rb_process_status *status, int *ep,
volatile int try_gc = 1;
struct child_handler_disabler_state old;
int err;
+ rb_nativethread_lock_t *const volatile waitpid_lock_init =
+ (w && WAITPID_USE_SIGCHLD) ? &GET_VM()->waitpid_lock : 0;
while (1) {
+ rb_nativethread_lock_t *waitpid_lock = waitpid_lock_init;
prefork();
disable_child_handler_before_fork(&old);
+ if (waitpid_lock) {
+ rb_native_mutex_lock(waitpid_lock);
+ }
#ifdef HAVE_WORKING_VFORK
if (!has_privilege())
pid = vfork();
@@ -4132,6 +4205,14 @@ retry_fork_async_signal_safe(struct rb_process_status *status, int *ep,
#endif
}
err = errno;
+ waitpid_lock = waitpid_lock_init;
+ if (waitpid_lock) {
+ if (pid > 0 && w != WAITPID_LOCK_ONLY) {
+ w->pid = pid;
+ ccan_list_add(&GET_VM()->waiting_pids, &w->wnode);
+ }
+ rb_native_mutex_unlock(waitpid_lock);
+ }
disable_child_handler_fork_parent(&old);
if (0 < pid) /* fork succeed, parent process */
return pid;
@@ -4141,6 +4222,30 @@ retry_fork_async_signal_safe(struct rb_process_status *status, int *ep,
}
}
+#if USE_MJIT
+// This is used to create MJIT's child Ruby process
+pid_t
+rb_mjit_fork(void)
+{
+ struct child_handler_disabler_state old;
+ rb_vm_t *vm = GET_VM();
+ prefork();
+ disable_child_handler_before_fork(&old);
+ before_fork_ruby();
+
+ rb_native_mutex_lock(&vm->waitpid_lock);
+ pid_t pid = rb_fork();
+ if (pid > 0) mjit_add_waiting_pid(vm, pid);
+ rb_native_mutex_unlock(&vm->waitpid_lock);
+
+ after_fork_ruby();
+ disable_child_handler_fork_parent(&old);
+ if (pid == 0) rb_thread_atfork();
+
+ return pid;
+}
+#endif
+
static rb_pid_t
fork_check_err(struct rb_process_status *status, int (*chfunc)(void*, char *, size_t), void *charg,
VALUE fds, char *errmsg, size_t errmsg_buflen,
@@ -4176,12 +4281,13 @@ fork_check_err(struct rb_process_status *status, int (*chfunc)(void*, char *, si
int state = 0;
status->error = err;
- VM_ASSERT((w == 0) && "only used by extensions");
+ VM_ASSERT((w == 0 || w == WAITPID_LOCK_ONLY) &&
+ "only used by extensions");
rb_protect(proc_syswait, (VALUE)pid, &state);
status->status = state;
}
- else if (!w) {
+ else if (!w || w == WAITPID_LOCK_ONLY) {
rb_syswait(pid);
}
@@ -4196,7 +4302,7 @@ fork_check_err(struct rb_process_status *status, int (*chfunc)(void*, char *, si
* The "async_signal_safe" name is a lie, but it is used by pty.c and
* maybe other exts. fork() is not async-signal-safe due to pthread_atfork
* and future POSIX revisions will remove it from a list of signal-safe
- * functions. rb_waitpid is not async-signal-safe since RJIT, either.
+ * functions. rb_waitpid is not async-signal-safe since MJIT, either.
* For our purposes, we do not need async-signal-safety, here
*/
rb_pid_t
@@ -4215,41 +4321,51 @@ rb_fork_async_signal_safe(int *status,
return result;
}
-rb_pid_t
-rb_fork_ruby(int *status)
+static rb_pid_t
+rb_fork_ruby2(struct rb_process_status *status)
{
- struct rb_process_status child = {.status = 0};
rb_pid_t pid;
int try_gc = 1, err;
struct child_handler_disabler_state old;
- do {
- prefork();
+ if (status) status->status = 0;
- before_fork_ruby();
- rb_thread_acquire_fork_lock();
+ while (1) {
+ prefork();
+ if (mjit_enabled) mjit_pause(false); // Don't leave locked mutex to child. Note: child_handler must be enabled to pause MJIT.
disable_child_handler_before_fork(&old);
+ before_fork_ruby();
+ pid = rb_fork();
+ err = errno;
+ if (status) {
+ status->pid = pid;
+ status->error = err;
+ }
+ after_fork_ruby();
+ disable_child_handler_fork_parent(&old); /* yes, bad name */
- child.pid = pid = rb_fork();
- child.error = err = errno;
+ if (mjit_enabled && pid > 0) mjit_resume(); /* child (pid == 0) is cared by rb_thread_atfork */
- disable_child_handler_fork_parent(&old); /* yes, bad name */
- if (
-#if defined(__FreeBSD__)
- pid != 0 &&
-#endif
- true) {
- rb_thread_release_fork_lock();
+ if (pid >= 0) { /* fork succeed */
+ if (pid == 0) rb_thread_atfork();
+ return pid;
}
- if (pid == 0) {
- rb_thread_reset_fork_lock();
+
+ /* fork failed */
+ if (handle_fork_error(err, status, NULL, &try_gc)) {
+ return -1;
}
- after_fork_ruby(pid);
+ }
+}
+
+rb_pid_t
+rb_fork_ruby(int *status)
+{
+ struct rb_process_status process_status = {0};
- /* repeat while fork failed but retryable */
- } while (pid < 0 && handle_fork_error(err, &child, NULL, &try_gc) == 0);
+ rb_pid_t pid = rb_fork_ruby2(&process_status);
- if (status) *status = child.status;
+ if (status) *status = process_status.status;
return pid;
}
@@ -4310,62 +4426,27 @@ rb_proc__fork(VALUE _obj)
/*
* call-seq:
- * Process.fork { ... } -> integer or nil
- * Process.fork -> integer or nil
- *
- * Creates a child process.
- *
- * With a block given, runs the block in the child process;
- * on block exit, the child terminates with a status of zero:
- *
- * puts "Before the fork: #{Process.pid}"
- * fork do
- * puts "In the child process: #{Process.pid}"
- * end # => 382141
- * puts "After the fork: #{Process.pid}"
- *
- * Output:
- *
- * Before the fork: 420496
- * After the fork: 420496
- * In the child process: 420520
- *
- * With no block given, the +fork+ call returns twice:
- *
- * - Once in the parent process, returning the pid of the child process.
- * - Once in the child process, returning +nil+.
- *
- * Example:
- *
- * puts "This is the first line before the fork (pid #{Process.pid})"
- * puts fork
- * puts "This is the second line after the fork (pid #{Process.pid})"
- *
- * Output:
- *
- * This is the first line before the fork (pid 420199)
- * 420223
- * This is the second line after the fork (pid 420199)
- *
- * This is the second line after the fork (pid 420223)
- *
- * In either case, the child process may exit using
- * Kernel.exit! to avoid the call to Kernel#at_exit.
- *
- * To avoid zombie processes, the parent process should call either:
- *
- * - Process.wait, to collect the termination statuses of its children.
- * - Process.detach, to register disinterest in their status.
- *
- * The thread calling +fork+ is the only thread in the created child process;
- * +fork+ doesn't copy other threads.
- *
- * Note that method +fork+ is available on some platforms,
- * but not on others:
- *
- * Process.respond_to?(:fork) # => true # Would be false on some.
- *
- * If not, you may use ::spawn instead of +fork+.
+ * Kernel.fork [{ block }] -> integer or nil
+ * Process.fork [{ block }] -> integer or nil
+ *
+ * Creates a subprocess. If a block is specified, that block is run
+ * in the subprocess, and the subprocess terminates with a status of
+ * zero. Otherwise, the +fork+ call returns twice, once in the
+ * parent, returning the process ID of the child, and once in the
+ * child, returning _nil_. The child process can exit using
+ * Kernel.exit! to avoid running any <code>at_exit</code>
+ * functions. The parent process should use Process.wait to collect
+ * the termination statuses of its children or use Process.detach to
+ * register disinterest in their status; otherwise, the operating
+ * system may accumulate zombie processes.
+ *
+ * The thread calling fork is the only thread in the created child process.
+ * fork doesn't copy other threads.
+ *
+ * If fork is not usable, Process.respond_to?(:fork) returns false.
+ *
+ * Note that fork(2) is not available on some platforms like Windows and NetBSD 4.
+ * Therefore you should use spawn() instead of fork().
*/
static VALUE
@@ -4417,18 +4498,13 @@ exit_status_code(VALUE status)
NORETURN(static VALUE rb_f_exit_bang(int argc, VALUE *argv, VALUE obj));
/*
* call-seq:
- * exit!(status = false)
- * Process.exit!(status = false)
+ * Process.exit!(status=false)
*
- * Exits the process immediately; no exit handlers are called.
- * Returns exit status +status+ to the underlying operating system.
+ * Exits the process immediately. No exit handlers are
+ * run. <em>status</em> is returned to the underlying system as the
+ * exit status.
*
* Process.exit!(true)
- *
- * Values +true+ and +false+ for argument +status+
- * indicate, respectively, success and failure;
- * The meanings of integer values are system-dependent.
- *
*/
static VALUE
@@ -4479,47 +4555,43 @@ rb_f_exit(int argc, const VALUE *argv)
NORETURN(static VALUE f_exit(int c, const VALUE *a, VALUE _));
/*
* call-seq:
- * exit(status = true)
- * Process.exit(status = true)
- *
- * Initiates termination of the Ruby script by raising SystemExit;
- * the exception may be caught.
- * Returns exit status +status+ to the underlying operating system.
- *
- * Values +true+ and +false+ for argument +status+
- * indicate, respectively, success and failure;
- * The meanings of integer values are system-dependent.
- *
- * Example:
- *
- * begin
- * exit
- * puts 'Never get here.'
- * rescue SystemExit
- * puts 'Rescued a SystemExit exception.'
- * end
- * puts 'After begin block.'
- *
- * Output:
- *
- * Rescued a SystemExit exception.
- * After begin block.
- *
- * Just prior to final termination,
- * Ruby executes any at-exit procedures (see Kernel::at_exit)
- * and any object finalizers (see ObjectSpace::define_finalizer).
- *
- * Example:
- *
- * at_exit { puts 'In at_exit function.' }
- * ObjectSpace.define_finalizer('string', proc { puts 'In finalizer.' })
- * exit
- *
- * Output:
- *
- * In at_exit function.
- * In finalizer.
- *
+ * exit(status=true)
+ * Kernel::exit(status=true)
+ * Process::exit(status=true)
+ *
+ * Initiates the termination of the Ruby script by raising the
+ * SystemExit exception. This exception may be caught. The
+ * optional parameter is used to return a status code to the invoking
+ * environment.
+ * +true+ and +FALSE+ of _status_ means success and failure
+ * respectively. The interpretation of other integer values are
+ * system dependent.
+ *
+ * begin
+ * exit
+ * puts "never get here"
+ * rescue SystemExit
+ * puts "rescued a SystemExit exception"
+ * end
+ * puts "after begin block"
+ *
+ * <em>produces:</em>
+ *
+ * rescued a SystemExit exception
+ * after begin block
+ *
+ * Just prior to termination, Ruby executes any <code>at_exit</code>
+ * functions (see Kernel::at_exit) and runs any object finalizers
+ * (see ObjectSpace::define_finalizer).
+ *
+ * at_exit { puts "at_exit function" }
+ * ObjectSpace.define_finalizer("string", proc { puts "in finalizer" })
+ * exit
+ *
+ * <em>produces:</em>
+ *
+ * at_exit function
+ * in finalizer
*/
static VALUE
@@ -4558,16 +4630,13 @@ NORETURN(static VALUE f_abort(int c, const VALUE *a, VALUE _));
/*
* call-seq:
- * abort
- * Process.abort(msg = nil)
+ * abort
+ * Kernel::abort([msg])
+ * Process.abort([msg])
*
- * Terminates execution immediately, effectively by calling
- * <tt>Kernel.exit(false)</tt>.
- *
- * If string argument +msg+ is given,
- * it is written to STDERR prior to termination;
- * otherwise, if an exception was raised,
- * prints its message and backtrace.
+ * Terminate execution immediately, effectively by calling
+ * <code>Kernel.exit(false)</code>. If _msg_ is given, it is written
+ * to STDERR prior to terminating.
*/
static VALUE
@@ -4651,7 +4720,7 @@ rb_spawn_process(struct rb_execarg *eargp, char *errmsg, size_t errmsg_buflen)
rb_last_status_set((status & 0xff) << 8, pid);
# endif
- if (eargp->waitpid_state) {
+ if (eargp->waitpid_state && eargp->waitpid_state != WAITPID_LOCK_ONLY) {
eargp->waitpid_state->pid = pid;
}
@@ -4673,28 +4742,30 @@ static VALUE
do_spawn_process(VALUE arg)
{
struct spawn_args *argp = (struct spawn_args *)arg;
-
rb_execarg_parent_start1(argp->execarg);
-
- return (VALUE)rb_spawn_process(rb_execarg_get(argp->execarg),
+ return (VALUE)rb_spawn_process(DATA_PTR(argp->execarg),
argp->errmsg.ptr, argp->errmsg.buflen);
}
-NOINLINE(static rb_pid_t
- rb_execarg_spawn(VALUE execarg_obj, char *errmsg, size_t errmsg_buflen));
-
static rb_pid_t
rb_execarg_spawn(VALUE execarg_obj, char *errmsg, size_t errmsg_buflen)
{
struct spawn_args args;
+ struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
+
+ /*
+ * Prevent a race with MJIT where the compiler process where
+ * can hold an FD of ours in between vfork + execve
+ */
+ if (!eargp->waitpid_state && mjit_enabled) {
+ eargp->waitpid_state = WAITPID_LOCK_ONLY;
+ }
args.execarg = execarg_obj;
args.errmsg.ptr = errmsg;
args.errmsg.buflen = errmsg_buflen;
-
- rb_pid_t r = (rb_pid_t)rb_ensure(do_spawn_process, (VALUE)&args,
- execarg_parent_end, execarg_obj);
- return r;
+ return (rb_pid_t)rb_ensure(do_spawn_process, (VALUE)&args,
+ execarg_parent_end, execarg_obj);
}
static rb_pid_t
@@ -4720,133 +4791,68 @@ rb_spawn(int argc, const VALUE *argv)
/*
* call-seq:
- * system([env, ] command_line, options = {}, exception: false) -> true, false, or nil
- * system([env, ] exe_path, *args, options = {}, exception: false) -> true, false, or nil
- *
- * Creates a new child process by doing one of the following
- * in that process:
+ * system([env,] command... [,options], exception: false) -> true, false or nil
*
- * - Passing string +command_line+ to the shell.
- * - Invoking the executable at +exe_path+.
+ * Executes _command..._ in a subshell.
+ * _command..._ is one of following forms.
*
* This method has potential security vulnerabilities if called with untrusted input;
* see {Command Injection}[rdoc-ref:command_injection.rdoc].
*
- * Returns:
- *
- * - +true+ if the command exits with status zero.
- * - +false+ if the exit status is a non-zero integer.
- * - +nil+ if the command could not execute.
- *
- * Raises an exception (instead of returning +false+ or +nil+)
- * if keyword argument +exception+ is set to +true+.
- *
- * Assigns the command's error status to <tt>$?</tt>.
- *
- * The new process is created using the
- * {system system call}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/system.html];
- * it may inherit some of its environment from the calling program
- * (possibly including open file descriptors).
- *
- * Argument +env+, if given, is a hash that affects +ENV+ for the new process;
- * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- *
- * Argument +options+ is a hash of options for the new process;
- * see {Execution Options}[rdoc-ref:Process@Execution+Options].
- *
- * The first required argument is one of the following:
- *
- * - +command_line+ if it is a string,
- * and if it begins with a shell reserved word or special built-in,
- * or if it contains one or more meta characters.
- * - +exe_path+ otherwise.
- *
- * <b>Argument +command_line+</b>
- *
- * \String argument +command_line+ is a command line to be passed to a shell;
- * it must begin with a shell reserved word, begin with a special built-in,
- * or contain meta characters:
- *
- * system('if true; then echo "Foo"; fi') # => true # Shell reserved word.
- * system('exit') # => true # Built-in.
- * system('date > /tmp/date.tmp') # => true # Contains meta character.
- * system('date > /nop/date.tmp') # => false
- * system('date > /nop/date.tmp', exception: true) # Raises RuntimeError.
- *
- * Assigns the command's error status to <tt>$?</tt>:
- *
- * system('exit') # => true # Built-in.
- * $? # => #<Process::Status: pid 640610 exit 0>
- * system('date > /nop/date.tmp') # => false
- * $? # => #<Process::Status: pid 640742 exit 2>
- *
- * The command line may also contain arguments and options for the command:
+ * [<code>commandline</code>]
+ * command line string which is passed to the standard shell
+ * [<code>cmdname, arg1, ...</code>]
+ * command name and one or more arguments (no shell)
+ * [<code>[cmdname, argv0], arg1, ...</code>]
+ * command name, <code>argv[0]</code> and zero or more arguments (no shell)
*
- * system('echo "Foo"') # => true
+ * system returns +true+ if the command gives zero exit status,
+ * +false+ for non zero exit status.
+ * Returns +nil+ if command execution fails.
+ * An error status is available in <code>$?</code>.
*
- * Output:
+ * If the <code>exception: true</code> argument is passed, the method
+ * raises an exception instead of returning +false+ or +nil+.
*
- * Foo
+ * The arguments are processed in the same way as
+ * for Kernel#spawn.
*
- * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
+ * The hash arguments, env and options, are same as #exec and #spawn.
+ * See Kernel#spawn for details.
*
- * Raises an exception if the new process could not execute.
+ * system("echo *")
+ * system("echo", "*")
*
- * <b>Argument +exe_path+</b>
+ * <em>produces:</em>
*
- * Argument +exe_path+ is one of the following:
+ * config.h main.rb
+ * *
*
- * - The string path to an executable to be called.
- * - A 2-element array containing the path to an executable
- * and the string to be used as the name of the executing process.
+ * Error handling:
*
- * Example:
+ * system("cat nonexistent.txt")
+ * # => false
+ * system("catt nonexistent.txt")
+ * # => nil
*
- * system('/usr/bin/date') # => true # Path to date on Unix-style system.
- * system('foo') # => nil # Command failed.
+ * system("cat nonexistent.txt", exception: true)
+ * # RuntimeError (Command failed with exit 1: cat)
+ * system("catt nonexistent.txt", exception: true)
+ * # Errno::ENOENT (No such file or directory - catt)
*
- * Output:
- *
- * Mon Aug 28 11:43:10 AM CDT 2023
- *
- * Assigns the command's error status to <tt>$?</tt>:
- *
- * system('/usr/bin/date') # => true
- * $? # => #<Process::Status: pid 645605 exit 0>
- * system('foo') # => nil
- * $? # => #<Process::Status: pid 645608 exit 127>
- *
- * Ruby invokes the executable directly.
- * This form does not use the shell;
- * see {Arguments args}[rdoc-ref:Process@Arguments+args] for caveats.
- *
- * system('doesnt_exist') # => nil
- *
- * If one or more +args+ is given, each is an argument or option
- * to be passed to the executable:
- *
- * system('echo', 'C*') # => true
- * system('echo', 'hello', 'world') # => true
- *
- * Output:
- *
- * C*
- * hello world
- *
- * Raises an exception if the new process could not execute.
+ * See Kernel#exec for the standard shell.
*/
static VALUE
rb_f_system(int argc, VALUE *argv, VALUE _)
{
- rb_thread_t *th = GET_THREAD();
VALUE execarg_obj = rb_execarg_new(argc, argv, TRUE, TRUE);
struct rb_execarg *eargp = rb_execarg_get(execarg_obj);
struct rb_process_status status = {0};
eargp->status = &status;
- last_status_clear(th);
+ rb_last_status_clear();
// This function can set the thread's last status.
// May be different from waitpid_state.pid on exec failure.
@@ -4854,10 +4860,12 @@ rb_f_system(int argc, VALUE *argv, VALUE _)
if (pid > 0) {
VALUE status = rb_process_status_wait(pid, 0);
+
struct rb_process_status *data = rb_check_typeddata(status, &rb_process_status_type);
+
// Set the last status:
rb_obj_freeze(status);
- th->last_status = status;
+ GET_THREAD()->last_status = status;
if (data->status == EXIT_SUCCESS) {
return Qtrue;
@@ -4900,105 +4908,271 @@ rb_f_system(int argc, VALUE *argv, VALUE _)
/*
* call-seq:
- * spawn([env, ] command_line, options = {}) -> pid
- * spawn([env, ] exe_path, *args, options = {}) -> pid
- *
- * Creates a new child process by doing one of the following
- * in that process:
- *
- * - Passing string +command_line+ to the shell.
- * - Invoking the executable at +exe_path+.
- *
- * This method has potential security vulnerabilities if called with untrusted input;
- * see {Command Injection}[rdoc-ref:command_injection.rdoc].
- *
- * Returns the process ID (pid) of the new process,
- * without waiting for it to complete.
+ * spawn([env,] command... [,options]) -> pid
+ * Process.spawn([env,] command... [,options]) -> pid
+ *
+ * spawn executes specified command and return its pid.
+ *
+ * pid = spawn("tar xf ruby-2.0.0-p195.tar.bz2")
+ * Process.wait pid
+ *
+ * pid = spawn(RbConfig.ruby, "-eputs'Hello, world!'")
+ * Process.wait pid
+ *
+ * This method is similar to Kernel#system but it doesn't wait for the command
+ * to finish.
+ *
+ * The parent process should
+ * use Process.wait to collect
+ * the termination status of its child or
+ * use Process.detach to register
+ * disinterest in their status;
+ * otherwise, the operating system may accumulate zombie processes.
+ *
+ * spawn has bunch of options to specify process attributes:
+ *
+ * env: hash
+ * name => val : set the environment variable
+ * name => nil : unset the environment variable
+ *
+ * the keys and the values except for +nil+ must be strings.
+ * command...:
+ * commandline : command line string which is passed to the standard shell
+ * cmdname, arg1, ... : command name and one or more arguments (This form does not use the shell. See below for caveats.)
+ * [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)
+ * options: hash
+ * clearing environment variables:
+ * :unsetenv_others => true : clear environment variables except specified by env
+ * :unsetenv_others => false : don't clear (default)
+ * process group:
+ * :pgroup => true or 0 : make a new process group
+ * :pgroup => pgid : join the specified process group
+ * :pgroup => nil : don't change the process group (default)
+ * create new process group: Windows only
+ * :new_pgroup => true : the new process is the root process of a new process group
+ * :new_pgroup => false : don't create a new process group (default)
+ * resource limit: resourcename is core, cpu, data, etc. See Process.setrlimit.
+ * :rlimit_resourcename => limit
+ * :rlimit_resourcename => [cur_limit, max_limit]
+ * umask:
+ * :umask => int
+ * redirection:
+ * key:
+ * FD : single file descriptor in child process
+ * [FD, FD, ...] : multiple file descriptor in child process
+ * value:
+ * FD : redirect to the file descriptor in parent process
+ * string : redirect to file with open(string, "r" or "w")
+ * [string] : redirect to file with open(string, File::RDONLY)
+ * [string, open_mode] : redirect to file with open(string, open_mode, 0644)
+ * [string, open_mode, perm] : redirect to file with open(string, open_mode, perm)
+ * [:child, FD] : redirect to the redirected file descriptor
+ * :close : close the file descriptor in child process
+ * FD is one of follows
+ * :in : the file descriptor 0 which is the standard input
+ * :out : the file descriptor 1 which is the standard output
+ * :err : the file descriptor 2 which is the standard error
+ * integer : the file descriptor of specified the integer
+ * io : the file descriptor specified as io.fileno
+ * file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not
+ * :close_others => false : inherit
+ * current directory:
+ * :chdir => str
+ *
+ * The <code>cmdname, arg1, ...</code> form does not use the shell.
+ * However, on different OSes, different things are provided as
+ * built-in commands. An example of this is +'echo'+, which is a
+ * built-in on Windows, but is a normal program on Linux and Mac OS X.
+ * This means that <code>Process.spawn 'echo', '%Path%'</code> will
+ * display the contents of the <tt>%Path%</tt> environment variable
+ * on Windows, but <code>Process.spawn 'echo', '$PATH'</code> prints
+ * the literal <tt>$PATH</tt>.
+ *
+ * If a hash is given as +env+, the environment is
+ * updated by +env+ before <code>exec(2)</code> in the child process.
+ * If a pair in +env+ has nil as the value, the variable is deleted.
+ *
+ * # set FOO as BAR and unset BAZ.
+ * pid = spawn({"FOO"=>"BAR", "BAZ"=>nil}, command)
+ *
+ * If a hash is given as +options+,
+ * it specifies
+ * process group,
+ * create new process group,
+ * resource limit,
+ * current directory,
+ * umask and
+ * redirects for the child process.
+ * Also, it can be specified to clear environment variables.
+ *
+ * The <code>:unsetenv_others</code> key in +options+ specifies
+ * to clear environment variables, other than specified by +env+.
+ *
+ * pid = spawn(command, :unsetenv_others=>true) # no environment variable
+ * pid = spawn({"FOO"=>"BAR"}, command, :unsetenv_others=>true) # FOO only
+ *
+ * The <code>:pgroup</code> key in +options+ specifies a process group.
+ * The corresponding value should be true, zero, a positive integer, or nil.
+ * true and zero cause the process to be a process leader of a new process group.
+ * A non-zero positive integer causes the process to join the provided process group.
+ * The default value, nil, causes the process to remain in the same process group.
+ *
+ * pid = spawn(command, :pgroup=>true) # process leader
+ * pid = spawn(command, :pgroup=>10) # belongs to the process group 10
+ *
+ * The <code>:new_pgroup</code> key in +options+ specifies to pass
+ * +CREATE_NEW_PROCESS_GROUP+ flag to <code>CreateProcessW()</code> that is
+ * Windows API. This option is only for Windows.
+ * true means the new process is the root process of the new process group.
+ * The new process has CTRL+C disabled. This flag is necessary for
+ * <code>Process.kill(:SIGINT, pid)</code> on the subprocess.
+ * :new_pgroup is false by default.
+ *
+ * pid = spawn(command, :new_pgroup=>true) # new process group
+ * pid = spawn(command, :new_pgroup=>false) # same process group
+ *
+ * The <code>:rlimit_</code><em>foo</em> key specifies a resource limit.
+ * <em>foo</em> should be one of resource types such as <code>core</code>.
+ * The corresponding value should be an integer or an array which have one or
+ * two integers: same as cur_limit and max_limit arguments for
+ * Process.setrlimit.
+ *
+ * cur, max = Process.getrlimit(:CORE)
+ * pid = spawn(command, :rlimit_core=>[0,max]) # disable core temporary.
+ * pid = spawn(command, :rlimit_core=>max) # enable core dump
+ * pid = spawn(command, :rlimit_core=>0) # never dump core.
+ *
+ * The <code>:umask</code> key in +options+ specifies the umask.
+ *
+ * pid = spawn(command, :umask=>077)
+ *
+ * The :in, :out, :err, an integer, an IO and an array key specifies a redirection.
+ * The redirection maps a file descriptor in the child process.
+ *
+ * For example, stderr can be merged into stdout as follows:
+ *
+ * pid = spawn(command, :err=>:out)
+ * pid = spawn(command, 2=>1)
+ * pid = spawn(command, STDERR=>:out)
+ * pid = spawn(command, STDERR=>STDOUT)
+ *
+ * The hash keys specifies a file descriptor in the child process
+ * started by #spawn.
+ * :err, 2 and STDERR specifies the standard error stream (stderr).
+ *
+ * The hash values specifies a file descriptor in the parent process
+ * which invokes #spawn.
+ * :out, 1 and STDOUT specifies the standard output stream (stdout).
+ *
+ * In the above example,
+ * the standard output in the child process is not specified.
+ * So it is inherited from the parent process.
+ *
+ * The standard input stream (stdin) can be specified by :in, 0 and STDIN.
+ *
+ * A filename can be specified as a hash value.
+ *
+ * pid = spawn(command, :in=>"/dev/null") # read mode
+ * pid = spawn(command, :out=>"/dev/null") # write mode
+ * pid = spawn(command, :err=>"log") # write mode
+ * pid = spawn(command, [:out, :err]=>"/dev/null") # write mode
+ * pid = spawn(command, 3=>"/dev/null") # read mode
*
- * To avoid zombie processes, the parent process should call either:
+ * For stdout and stderr (and combination of them),
+ * it is opened in write mode.
+ * Otherwise read mode is used.
*
- * - Process.wait, to collect the termination statuses of its children.
- * - Process.detach, to register disinterest in their status.
+ * For specifying flags and permission of file creation explicitly,
+ * an array is used instead.
*
- * The new process is created using the
- * {exec system call}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/execve.html];
- * it may inherit some of its environment from the calling program
- * (possibly including open file descriptors).
+ * pid = spawn(command, :in=>["file"]) # read mode is assumed
+ * pid = spawn(command, :in=>["file", "r"])
+ * pid = spawn(command, :out=>["log", "w"]) # 0644 assumed
+ * pid = spawn(command, :out=>["log", "w", 0600])
+ * pid = spawn(command, :out=>["log", File::WRONLY|File::EXCL|File::CREAT, 0600])
*
- * Argument +env+, if given, is a hash that affects +ENV+ for the new process;
- * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ * The array specifies a filename, flags and permission.
+ * The flags can be a string or an integer.
+ * If the flags is omitted or nil, File::RDONLY is assumed.
+ * The permission should be an integer.
+ * If the permission is omitted or nil, 0644 is assumed.
*
- * Argument +options+ is a hash of options for the new process;
- * see {Execution Options}[rdoc-ref:Process@Execution+Options].
+ * If an array of IOs and integers are specified as a hash key,
+ * all the elements are redirected.
*
- * The first required argument is one of the following:
+ * # stdout and stderr is redirected to log file.
+ * # The file "log" is opened just once.
+ * pid = spawn(command, [:out, :err]=>["log", "w"])
*
- * - +command_line+ if it is a string,
- * and if it begins with a shell reserved word or special built-in,
- * or if it contains one or more meta characters.
- * - +exe_path+ otherwise.
+ * Another way to merge multiple file descriptors is [:child, fd].
+ * \[:child, fd] means the file descriptor in the child process.
+ * This is different from fd.
+ * For example, :err=>:out means redirecting child stderr to parent stdout.
+ * But :err=>[:child, :out] means redirecting child stderr to child stdout.
+ * They differ if stdout is redirected in the child process as follows.
*
- * <b>Argument +command_line+</b>
+ * # stdout and stderr is redirected to log file.
+ * # The file "log" is opened just once.
+ * pid = spawn(command, :out=>["log", "w"], :err=>[:child, :out])
*
- * \String argument +command_line+ is a command line to be passed to a shell;
- * it must begin with a shell reserved word, begin with a special built-in,
- * or contain meta characters:
+ * \[:child, :out] can be used to merge stderr into stdout in IO.popen.
+ * In this case, IO.popen redirects stdout to a pipe in the child process
+ * and [:child, :out] refers the redirected stdout.
*
- * spawn('if true; then echo "Foo"; fi') # => 798847 # Shell reserved word.
- * Process.wait # => 798847
- * spawn('exit') # => 798848 # Built-in.
- * Process.wait # => 798848
- * spawn('date > /tmp/date.tmp') # => 798879 # Contains meta character.
- * Process.wait # => 798849
- * spawn('date > /nop/date.tmp') # => 798882 # Issues error message.
- * Process.wait # => 798882
+ * io = IO.popen(["sh", "-c", "echo out; echo err >&2", :err=>[:child, :out]])
+ * p io.read #=> "out\nerr\n"
*
- * The command line may also contain arguments and options for the command:
+ * The <code>:chdir</code> key in +options+ specifies the current directory.
*
- * spawn('echo "Foo"') # => 799031
- * Process.wait # => 799031
+ * pid = spawn(command, :chdir=>"/var/tmp")
*
- * Output:
+ * spawn closes all non-standard unspecified descriptors by default.
+ * The "standard" descriptors are 0, 1 and 2.
+ * This behavior is specified by :close_others option.
+ * :close_others doesn't affect the standard descriptors which are
+ * closed only if :close is specified explicitly.
*
- * Foo
+ * pid = spawn(command, :close_others=>true) # close 3,4,5,... (default)
+ * pid = spawn(command, :close_others=>false) # don't close 3,4,5,...
*
- * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
+ * :close_others is false by default for spawn and IO.popen.
*
- * Raises an exception if the new process could not execute.
+ * Note that fds which close-on-exec flag is already set are closed
+ * regardless of :close_others option.
*
- * <b>Argument +exe_path+</b>
+ * So IO.pipe and spawn can be used as IO.popen.
*
- * Argument +exe_path+ is one of the following:
+ * # similar to r = IO.popen(command)
+ * r, w = IO.pipe
+ * pid = spawn(command, :out=>w) # r, w is closed in the child process.
+ * w.close
*
- * - The string path to an executable to be called.
- * - A 2-element array containing the path to an executable to be called,
- * and the string to be used as the name of the executing process.
+ * :close is specified as a hash value to close a fd individually.
*
- * spawn('/usr/bin/date') # Path to date on Unix-style system.
- * Process.wait
+ * f = open(foo)
+ * system(command, f=>:close) # don't inherit f.
*
- * Output:
+ * If a file descriptor need to be inherited,
+ * io=>io can be used.
*
- * Mon Aug 28 11:43:10 AM CDT 2023
+ * # valgrind has --log-fd option for log destination.
+ * # log_w=>log_w indicates log_w.fileno inherits to child process.
+ * log_r, log_w = IO.pipe
+ * pid = spawn("valgrind", "--log-fd=#{log_w.fileno}", "echo", "a", log_w=>log_w)
+ * log_w.close
+ * p log_r.read
*
- * Ruby invokes the executable directly.
- * This form does not use the shell;
- * see {Arguments args}[rdoc-ref:Process@Arguments+args] for caveats.
+ * It is also possible to exchange file descriptors.
*
- * If one or more +args+ is given, each is an argument or option
- * to be passed to the executable:
+ * pid = spawn(command, :out=>:err, :err=>:out)
*
- * spawn('echo', 'C*') # => 799392
- * Process.wait # => 799392
- * spawn('echo', 'hello', 'world') # => 799393
- * Process.wait # => 799393
+ * The hash keys specify file descriptors in the child process.
+ * The hash values specifies file descriptors in the parent process.
+ * So the above specifies exchanging stdout and stderr.
+ * Internally, +spawn+ uses an extra file descriptor to resolve such cyclic
+ * file descriptor mapping.
*
- * Output:
- *
- * C*
- * hello world
- *
- * Raises an exception if the new process could not execute.
+ * See Kernel.exec for the standard shell.
*/
static VALUE
@@ -5030,18 +5204,19 @@ rb_f_spawn(int argc, VALUE *argv, VALUE _)
/*
* call-seq:
- * sleep(secs = nil) -> slept_secs
- *
- * Suspends execution of the current thread for the number of seconds
- * specified by numeric argument +secs+, or forever if +secs+ is +nil+;
- * returns the integer number of seconds suspended (rounded).
- *
- * Time.new # => 2008-03-08 19:56:19 +0900
- * sleep 1.2 # => 1
- * Time.new # => 2008-03-08 19:56:20 +0900
- * sleep 1.9 # => 2
- * Time.new # => 2008-03-08 19:56:22 +0900
- *
+ * sleep([duration]) -> integer
+ *
+ * Suspends the current thread for _duration_ seconds (which may be any number,
+ * including a +Float+ with fractional seconds). Returns the actual number of
+ * seconds slept (rounded), which may be less than that asked for if another
+ * thread calls Thread#run. Called without an argument, sleep()
+ * will sleep forever.
+ *
+ * Time.new #=> 2008-03-08 19:56:19 +0900
+ * sleep 1.2 #=> 1
+ * Time.new #=> 2008-03-08 19:56:20 +0900
+ * sleep 1.9 #=> 2
+ * Time.new #=> 2008-03-08 19:56:22 +0900
*/
static VALUE
@@ -5054,7 +5229,7 @@ rb_f_sleep(int argc, VALUE *argv, VALUE _)
rb_fiber_scheduler_kernel_sleepv(scheduler, argc, argv);
}
else {
- if (argc == 0 || (argc == 1 && NIL_P(argv[0]))) {
+ if (argc == 0) {
rb_thread_sleep_forever();
}
else {
@@ -5072,13 +5247,13 @@ rb_f_sleep(int argc, VALUE *argv, VALUE _)
#if (defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)) || defined(HAVE_GETPGID)
/*
* call-seq:
- * Process.getpgrp -> integer
+ * Process.getpgrp -> integer
*
- * Returns the process group ID for the current process:
- *
- * Process.getpgid(0) # => 25527
- * Process.getpgrp # => 25527
+ * Returns the process group ID for this process. Not available on
+ * all platforms.
*
+ * Process.getpgid(0) #=> 25527
+ * Process.getpgrp #=> 25527
*/
static VALUE
@@ -5104,11 +5279,10 @@ proc_getpgrp(VALUE _)
#if defined(HAVE_SETPGID) || (defined(HAVE_SETPGRP) && defined(SETPGRP_VOID))
/*
* call-seq:
- * Process.setpgrp -> 0
- *
- * Equivalent to <tt>setpgid(0, 0)</tt>.
+ * Process.setpgrp -> 0
*
- * Not available on all platforms.
+ * Equivalent to <code>setpgid(0,0)</code>. Not available on all
+ * platforms.
*/
static VALUE
@@ -5133,13 +5307,12 @@ proc_setpgrp(VALUE _)
#if defined(HAVE_GETPGID)
/*
* call-seq:
- * Process.getpgid(pid) -> integer
+ * Process.getpgid(pid) -> integer
*
- * Returns the process group ID for the given process ID +pid+:
- *
- * Process.getpgid(Process.ppid) # => 25527
+ * Returns the process group ID for the given process id. Not
+ * available on all platforms.
*
- * Not available on all platforms.
+ * Process.getpgid(Process.ppid()) #=> 25527
*/
static VALUE
@@ -5159,12 +5332,10 @@ proc_getpgid(VALUE obj, VALUE pid)
#ifdef HAVE_SETPGID
/*
* call-seq:
- * Process.setpgid(pid, pgid) -> 0
+ * Process.setpgid(pid, integer) -> 0
*
- * Sets the process group ID for the process given by process ID +pid+
- * to +pgid+.
- *
- * Not available on all platforms.
+ * Sets the process group ID of _pid_ (0 indicates this
+ * process) to <em>integer</em>. Not available on all platforms.
*/
static VALUE
@@ -5186,16 +5357,15 @@ proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
#ifdef HAVE_GETSID
/*
* call-seq:
- * Process.getsid(pid = nil) -> integer
- *
- * Returns the session ID of the given process ID +pid+,
- * or of the current process if not given:
+ * Process.getsid() -> integer
+ * Process.getsid(pid) -> integer
*
- * Process.getsid # => 27422
- * Process.getsid(0) # => 27422
- * Process.getsid(Process.pid()) # => 27422
+ * Returns the session ID for the given process id. If not given,
+ * return current process sid. Not available on all platforms.
*
- * Not available on all platforms.
+ * Process.getsid() #=> 27422
+ * Process.getsid(0) #=> 27422
+ * Process.getsid(Process.pid()) #=> 27422
*/
static VALUE
proc_getsid(int argc, VALUE *argv, VALUE _)
@@ -5222,15 +5392,13 @@ static rb_pid_t ruby_setsid(void);
#endif
/*
* call-seq:
- * Process.setsid -> integer
- *
- * Establishes the current process as a new session and process group leader,
- * with no controlling tty;
- * returns the session ID:
+ * Process.setsid -> integer
*
- * Process.setsid # => 27422
+ * Establishes this process as a new session and process group
+ * leader, with no controlling tty. Returns the session id. Not
+ * available on all platforms.
*
- * Not available on all platforms.
+ * Process.setsid #=> 27422
*/
static VALUE
@@ -5249,7 +5417,7 @@ static rb_pid_t
ruby_setsid(void)
{
rb_pid_t pid;
- int ret, fd;
+ int ret;
pid = getpid();
#if defined(SETPGRP_VOID)
@@ -5278,26 +5446,19 @@ ruby_setsid(void)
#ifdef HAVE_GETPRIORITY
/*
* call-seq:
- * Process.getpriority(kind, id) -> integer
- *
- * Returns the scheduling priority for specified process, process group,
- * or user.
- *
- * Argument +kind+ is one of:
- *
- * - Process::PRIO_PROCESS: return priority for process.
- * - Process::PRIO_PGRP: return priority for process group.
- * - Process::PRIO_USER: return priority for user.
- *
- * Argument +id+ is the ID for the process, process group, or user;
- * zero specified the current ID for +kind+.
- *
- * Examples:
- *
- * Process.getpriority(Process::PRIO_USER, 0) # => 19
- * Process.getpriority(Process::PRIO_PROCESS, 0) # => 19
- *
- * Not available on all platforms.
+ * Process.getpriority(kind, integer) -> integer
+ *
+ * Gets the scheduling priority for specified process, process group,
+ * or user. <em>kind</em> indicates the kind of entity to find: one
+ * of Process::PRIO_PGRP,
+ * Process::PRIO_USER, or
+ * Process::PRIO_PROCESS. _integer_ is an id
+ * indicating the particular process, process group, or user (an id
+ * of 0 means _current_). Lower priorities are more favorable
+ * for scheduling. Not available on all platforms.
+ *
+ * Process.getpriority(Process::PRIO_USER, 0) #=> 19
+ * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
*/
static VALUE
@@ -5321,18 +5482,14 @@ proc_getpriority(VALUE obj, VALUE which, VALUE who)
#ifdef HAVE_GETPRIORITY
/*
* call-seq:
- * Process.setpriority(kind, integer, priority) -> 0
+ * Process.setpriority(kind, integer, priority) -> 0
*
* See Process.getpriority.
*
- * Examples:
- *
- * Process.setpriority(Process::PRIO_USER, 0, 19) # => 0
- * Process.setpriority(Process::PRIO_PROCESS, 0, 19) # => 0
- * Process.getpriority(Process::PRIO_USER, 0) # => 19
- * Process.getpriority(Process::PRIO_PROCESS, 0) # => 19
- *
- * Not available on all platforms.
+ * Process.setpriority(Process::PRIO_USER, 0, 19) #=> 0
+ * Process.setpriority(Process::PRIO_PROCESS, 0, 19) #=> 0
+ * Process.getpriority(Process::PRIO_USER, 0) #=> 19
+ * Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19
*/
static VALUE
@@ -5580,24 +5737,22 @@ rlimit_resource_value(VALUE rval)
#if defined(HAVE_GETRLIMIT) && defined(RLIM2NUM)
/*
* call-seq:
- * Process.getrlimit(resource) -> [cur_limit, max_limit]
- *
- * Returns a 2-element array of the current (soft) limit
- * and maximum (hard) limit for the given +resource+.
- *
- * Argument +resource+ specifies the resource whose limits are to be returned;
- * see Process.setrlimit.
- *
- * Each of the returned values +cur_limit+ and +max_limit+ is an integer;
- * see Process.setrlimit.
- *
- * Example:
- *
- * Process.getrlimit(:CORE) # => [0, 18446744073709551615]
- *
- * See Process.setrlimit.
- *
- * Not available on all platforms.
+ * Process.getrlimit(resource) -> [cur_limit, max_limit]
+ *
+ * Gets the resource limit of the process.
+ * _cur_limit_ means current (soft) limit and
+ * _max_limit_ means maximum (hard) limit.
+ *
+ * _resource_ indicates the kind of resource to limit.
+ * It is specified as a symbol such as <code>:CORE</code>,
+ * a string such as <code>"CORE"</code> or
+ * a constant such as Process::RLIMIT_CORE.
+ * See Process.setrlimit for details.
+ *
+ * _cur_limit_ and _max_limit_ may be Process::RLIM_INFINITY,
+ * Process::RLIM_SAVED_MAX or
+ * Process::RLIM_SAVED_CUR.
+ * See Process.setrlimit and the system getrlimit(2) manual for details.
*/
static VALUE
@@ -5617,54 +5772,54 @@ proc_getrlimit(VALUE obj, VALUE resource)
#if defined(HAVE_SETRLIMIT) && defined(NUM2RLIM)
/*
* call-seq:
- * Process.setrlimit(resource, cur_limit, max_limit = cur_limit) -> nil
- *
- * Sets limits for the current process for the given +resource+
- * to +cur_limit+ (soft limit) and +max_limit+ (hard limit);
- * returns +nil+.
- *
- * Argument +resource+ specifies the resource whose limits are to be set;
- * the argument may be given as a symbol, as a string, or as a constant
- * beginning with <tt>Process::RLIMIT_</tt>
- * (e.g., +:CORE+, <tt>'CORE'</tt>, or <tt>Process::RLIMIT_CORE</tt>.
- *
- * The resources available and supported are system-dependent,
- * and may include (here expressed as symbols):
- *
- * - +:AS+: Total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD except 4.4BSD-Lite).
- * - +:CORE+: Core size (bytes) (SUSv3).
- * - +:CPU+: CPU time (seconds) (SUSv3).
- * - +:DATA+: Data segment (bytes) (SUSv3).
- * - +:FSIZE+: File size (bytes) (SUSv3).
- * - +:MEMLOCK+: Total size for mlock(2) (bytes) (4.4BSD, GNU/Linux).
- * - +:MSGQUEUE+: Allocation for POSIX message queues (bytes) (GNU/Linux).
- * - +:NICE+: Ceiling on process's nice(2) value (number) (GNU/Linux).
- * - +:NOFILE+: File descriptors (number) (SUSv3).
- * - +:NPROC+: Number of processes for the user (number) (4.4BSD, GNU/Linux).
- * - +:NPTS+: Number of pseudo terminals (number) (FreeBSD).
- * - +:RSS+: Resident memory size (bytes) (4.2BSD, GNU/Linux).
- * - +:RTPRIO+: Ceiling on the process's real-time priority (number) (GNU/Linux).
- * - +:RTTIME+: CPU time for real-time process (us) (GNU/Linux).
- * - +:SBSIZE+: All socket buffers (bytes) (NetBSD, FreeBSD).
- * - +:SIGPENDING+: Number of queued signals allowed (signals) (GNU/Linux).
- * - +:STACK+: Stack size (bytes) (SUSv3).
- *
- * Arguments +cur_limit+ and +max_limit+ may be:
- *
- * - Integers (+max_limit+ should not be smaller than +cur_limit+).
- * - Symbol +:SAVED_MAX+, string <tt>'SAVED_MAX'</tt>,
- * or constant <tt>Process::RLIM_SAVED_MAX</tt>: saved maximum limit.
- * - Symbol +:SAVED_CUR+, string <tt>'SAVED_CUR'</tt>,
- * or constant <tt>Process::RLIM_SAVED_CUR</tt>: saved current limit.
- * - Symbol +:INFINITY+, string <tt>'INFINITY'</tt>,
- * or constant <tt>Process::RLIM_INFINITY</tt>: no limit on resource.
- *
- * This example raises the soft limit of core size to
- * the hard limit to try to make core dump possible:
+ * Process.setrlimit(resource, cur_limit, max_limit) -> nil
+ * Process.setrlimit(resource, cur_limit) -> nil
+ *
+ * Sets the resource limit of the process.
+ * _cur_limit_ means current (soft) limit and
+ * _max_limit_ means maximum (hard) limit.
+ *
+ * If _max_limit_ is not given, _cur_limit_ is used.
+ *
+ * _resource_ indicates the kind of resource to limit.
+ * It should be a symbol such as <code>:CORE</code>,
+ * a string such as <code>"CORE"</code> or
+ * a constant such as Process::RLIMIT_CORE.
+ * The available resources are OS dependent.
+ * Ruby may support following resources.
+ *
+ * [AS] total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but 4.4BSD-Lite)
+ * [CORE] core size (bytes) (SUSv3)
+ * [CPU] CPU time (seconds) (SUSv3)
+ * [DATA] data segment (bytes) (SUSv3)
+ * [FSIZE] file size (bytes) (SUSv3)
+ * [MEMLOCK] total size for mlock(2) (bytes) (4.4BSD, GNU/Linux)
+ * [MSGQUEUE] allocation for POSIX message queues (bytes) (GNU/Linux)
+ * [NICE] ceiling on process's nice(2) value (number) (GNU/Linux)
+ * [NOFILE] file descriptors (number) (SUSv3)
+ * [NPROC] number of processes for the user (number) (4.4BSD, GNU/Linux)
+ * [NPTS] number of pseudo terminals (number) (FreeBSD)
+ * [RSS] resident memory size (bytes) (4.2BSD, GNU/Linux)
+ * [RTPRIO] ceiling on the process's real-time priority (number) (GNU/Linux)
+ * [RTTIME] CPU time for real-time process (us) (GNU/Linux)
+ * [SBSIZE] all socket buffers (bytes) (NetBSD, FreeBSD)
+ * [SIGPENDING] number of queued signals allowed (signals) (GNU/Linux)
+ * [STACK] stack size (bytes) (SUSv3)
+ *
+ * _cur_limit_ and _max_limit_ may be
+ * <code>:INFINITY</code>, <code>"INFINITY"</code> or
+ * Process::RLIM_INFINITY,
+ * which means that the resource is not limited.
+ * They may be Process::RLIM_SAVED_MAX,
+ * Process::RLIM_SAVED_CUR and
+ * corresponding symbols and strings too.
+ * See system setrlimit(2) manual for details.
+ *
+ * The following example raises the soft limit of core size to
+ * the hard limit to try to make core dump possible.
*
* Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
*
- * Not available on all platforms.
*/
static VALUE
@@ -5711,12 +5866,6 @@ check_gid_switch(void)
#if defined(HAVE_PWD_H)
-static inline bool
-login_not_found(int err)
-{
- return (err == ENOTTY || err == ENXIO || err == ENOENT);
-}
-
/**
* Best-effort attempt to obtain the name of the login user, if any,
* associated with the process. Processes not descended from login(1) (or
@@ -5725,18 +5874,18 @@ login_not_found(int err)
VALUE
rb_getlogin(void)
{
-# if !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN)
+#if ( !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN) )
return Qnil;
-# else
+#else
char MAYBE_UNUSED(*login) = NULL;
# ifdef USE_GETLOGIN_R
-# if defined(__FreeBSD__)
+#if defined(__FreeBSD__)
typedef int getlogin_r_size_t;
-# else
+#else
typedef size_t getlogin_r_size_t;
-# endif
+#endif
long loginsize = GETLOGIN_R_SIZE_INIT; /* maybe -1 */
@@ -5750,8 +5899,10 @@ rb_getlogin(void)
rb_str_set_len(maybe_result, loginsize);
int gle;
+ errno = 0;
while ((gle = getlogin_r(login, (getlogin_r_size_t)loginsize)) != 0) {
- if (login_not_found(gle)) {
+
+ if (gle == ENOTTY || gle == ENXIO || gle == ENOENT) {
rb_str_resize(maybe_result, 0);
return Qnil;
}
@@ -5771,19 +5922,17 @@ rb_getlogin(void)
return Qnil;
}
- rb_str_set_len(maybe_result, strlen(login));
return maybe_result;
-# elif defined(USE_GETLOGIN)
+# elif USE_GETLOGIN
errno = 0;
login = getlogin();
- int err = errno;
- if (err) {
- if (login_not_found(err)) {
+ if (errno) {
+ if (errno == ENOTTY || errno == ENXIO || errno == ENOENT) {
return Qnil;
}
- rb_syserr_fail(err, "getlogin");
+ rb_syserr_fail(errno, "getlogin");
}
return login ? rb_str_new_cstr(login) : Qnil;
@@ -5792,46 +5941,10 @@ rb_getlogin(void)
#endif
}
-/* avoid treating as errors errno values that indicate "not found" */
-static inline bool
-pwd_not_found(int err)
-{
- switch (err) {
- case 0:
- case ENOENT:
- case ESRCH:
- case EBADF:
- case EPERM:
- return true;
- default:
- return false;
- }
-}
-
-# if defined(USE_GETPWNAM_R)
-struct getpwnam_r_args {
- const char *login;
- char *buf;
- size_t bufsize;
- struct passwd *result;
- struct passwd pwstore;
-};
-
-# define GETPWNAM_R_ARGS(login_, buf_, bufsize_) (struct getpwnam_r_args) \
- {.login = login_, .buf = buf_, .bufsize = bufsize_, .result = NULL}
-
-static void *
-nogvl_getpwnam_r(void *args)
-{
- struct getpwnam_r_args *arg = args;
- return (void *)(VALUE)getpwnam_r(arg->login, &arg->pwstore, arg->buf, arg->bufsize, &arg->result);
-}
-# endif
-
VALUE
rb_getpwdirnam_for_login(VALUE login_name)
{
-#if !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM)
+#if ( !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM) )
return Qnil;
#else
@@ -5840,11 +5953,13 @@ rb_getpwdirnam_for_login(VALUE login_name)
return Qnil;
}
- const char *login = RSTRING_PTR(login_name);
+ char *login = RSTRING_PTR(login_name);
+ struct passwd *pwptr;
# ifdef USE_GETPWNAM_R
+ struct passwd pwdnm;
char *bufnm;
long bufsizenm = GETPW_R_SIZE_INIT; /* maybe -1 */
@@ -5856,77 +5971,58 @@ rb_getpwdirnam_for_login(VALUE login_name)
bufnm = RSTRING_PTR(getpwnm_tmp);
bufsizenm = rb_str_capacity(getpwnm_tmp);
rb_str_set_len(getpwnm_tmp, bufsizenm);
- struct getpwnam_r_args args = GETPWNAM_R_ARGS(login, bufnm, (size_t)bufsizenm);
int enm;
- while ((enm = IO_WITHOUT_GVL_INT(nogvl_getpwnam_r, &args)) != 0) {
- if (pwd_not_found(enm)) {
+ errno = 0;
+ while ((enm = getpwnam_r(login, &pwdnm, bufnm, bufsizenm, &pwptr)) != 0) {
+
+ if (enm == ENOENT || enm== ESRCH || enm == EBADF || enm == EPERM) {
+ /* not found; non-errors */
rb_str_resize(getpwnm_tmp, 0);
return Qnil;
}
- if (enm != ERANGE || args.bufsize >= GETPW_R_SIZE_LIMIT) {
+ if (enm != ERANGE || bufsizenm >= GETPW_R_SIZE_LIMIT) {
rb_str_resize(getpwnm_tmp, 0);
rb_syserr_fail(enm, "getpwnam_r");
}
- rb_str_modify_expand(getpwnm_tmp, (long)args.bufsize);
- args.buf = RSTRING_PTR(getpwnm_tmp);
- args.bufsize = (size_t)rb_str_capacity(getpwnm_tmp);
+ rb_str_modify_expand(getpwnm_tmp, bufsizenm);
+ bufnm = RSTRING_PTR(getpwnm_tmp);
+ bufsizenm = rb_str_capacity(getpwnm_tmp);
}
- if (args.result == NULL) {
+ if (pwptr == NULL) {
/* no record in the password database for the login name */
rb_str_resize(getpwnm_tmp, 0);
return Qnil;
}
/* found it */
- VALUE result = rb_str_new_cstr(args.result->pw_dir);
+ VALUE result = rb_str_new_cstr(pwptr->pw_dir);
rb_str_resize(getpwnm_tmp, 0);
return result;
-# elif defined(USE_GETPWNAM)
+# elif USE_GETPWNAM
- struct passwd *pwptr;
errno = 0;
- if (!(pwptr = getpwnam(login))) {
- int err = errno;
-
- if (pwd_not_found(err)) {
- return Qnil;
- }
-
- rb_syserr_fail(err, "getpwnam");
+ pwptr = getpwnam(login);
+ if (pwptr) {
+ /* found it */
+ return rb_str_new_cstr(pwptr->pw_dir);
+ }
+ if (errno
+ /* avoid treating as errors errno values that indicate "not found" */
+ && ( errno != ENOENT && errno != ESRCH && errno != EBADF && errno != EPERM)) {
+ rb_syserr_fail(errno, "getpwnam");
}
- /* found it */
- return rb_str_new_cstr(pwptr->pw_dir);
+ return Qnil; /* not found */
# endif
#endif
}
-# if defined(USE_GETPWUID_R)
-struct getpwuid_r_args {
- uid_t uid;
- char *buf;
- size_t bufsize;
- struct passwd *result;
- struct passwd pwstore;
-};
-
-# define GETPWUID_R_ARGS(uid_, buf_, bufsize_) (struct getpwuid_r_args) \
- {.uid = uid_, .buf = buf_, .bufsize = bufsize_, .result = NULL}
-
-static void *
-nogvl_getpwuid_r(void *args)
-{
- struct getpwuid_r_args *arg = args;
- return (void *)(VALUE)getpwuid_r(arg->uid, &arg->pwstore, arg->buf, arg->bufsize, &arg->result);
-}
-# endif
-
/**
* Look up the user's dflt home dir in the password db, by uid.
*/
@@ -5939,8 +6035,11 @@ rb_getpwdiruid(void)
# else
uid_t ruid = getuid();
+ struct passwd *pwptr;
+
# ifdef USE_GETPWUID_R
+ struct passwd pwdid;
char *bufid;
long bufsizeid = GETPW_R_SIZE_INIT; /* maybe -1 */
@@ -5952,52 +6051,53 @@ rb_getpwdiruid(void)
bufid = RSTRING_PTR(getpwid_tmp);
bufsizeid = rb_str_capacity(getpwid_tmp);
rb_str_set_len(getpwid_tmp, bufsizeid);
- struct getpwuid_r_args args = GETPWUID_R_ARGS(ruid, bufid, (size_t)bufsizeid);
int eid;
- while ((eid = IO_WITHOUT_GVL_INT(nogvl_getpwuid_r, &args)) != 0) {
- if (pwd_not_found(eid)) {
+ errno = 0;
+ while ((eid = getpwuid_r(ruid, &pwdid, bufid, bufsizeid, &pwptr)) != 0) {
+
+ if (eid == ENOENT || eid== ESRCH || eid == EBADF || eid == EPERM) {
+ /* not found; non-errors */
rb_str_resize(getpwid_tmp, 0);
return Qnil;
}
- if (eid != ERANGE || args.bufsize >= GETPW_R_SIZE_LIMIT) {
+ if (eid != ERANGE || bufsizeid >= GETPW_R_SIZE_LIMIT) {
rb_str_resize(getpwid_tmp, 0);
rb_syserr_fail(eid, "getpwuid_r");
}
- rb_str_modify_expand(getpwid_tmp, (long)args.bufsize);
- args.buf = RSTRING_PTR(getpwid_tmp);
- args.bufsize = (size_t)rb_str_capacity(getpwid_tmp);
+ rb_str_modify_expand(getpwid_tmp, bufsizeid);
+ bufid = RSTRING_PTR(getpwid_tmp);
+ bufsizeid = rb_str_capacity(getpwid_tmp);
}
- if (args.result == NULL) {
+ if (pwptr == NULL) {
/* no record in the password database for the uid */
rb_str_resize(getpwid_tmp, 0);
return Qnil;
}
/* found it */
- VALUE result = rb_str_new_cstr(args.result->pw_dir);
+ VALUE result = rb_str_new_cstr(pwptr->pw_dir);
rb_str_resize(getpwid_tmp, 0);
return result;
# elif defined(USE_GETPWUID)
- struct passwd *pwptr;
errno = 0;
- if (!(pwptr = getpwuid(ruid))) {
- int err = errno;
-
- if (pwd_not_found(err)) {
- return Qnil;
- }
-
- rb_syserr_fail(err, "getpwuid");
+ pwptr = getpwuid(ruid);
+ if (pwptr) {
+ /* found it */
+ return rb_str_new_cstr(pwptr->pw_dir);
+ }
+ if (errno
+ /* avoid treating as errors errno values that indicate "not found" */
+ && ( errno == ENOENT || errno == ESRCH || errno == EBADF || errno == EPERM)) {
+ rb_syserr_fail(errno, "getpwuid");
}
- /* found it */
- return rb_str_new_cstr(pwptr->pw_dir);
+ return Qnil; /* not found */
# endif
#endif /* !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID) */
@@ -6033,6 +6133,7 @@ obj2uid(VALUE id
const char *usrname = StringValueCStr(id);
struct passwd *pwptr;
#ifdef USE_GETPWNAM_R
+ struct passwd pwbuf;
char *getpw_buf;
long getpw_buf_len;
int e;
@@ -6045,18 +6146,15 @@ obj2uid(VALUE id
getpw_buf_len = rb_str_capacity(*getpw_tmp);
rb_str_set_len(*getpw_tmp, getpw_buf_len);
errno = 0;
- struct getpwnam_r_args args = GETPWNAM_R_ARGS((char *)usrname, getpw_buf, (size_t)getpw_buf_len);
-
- while ((e = IO_WITHOUT_GVL_INT(nogvl_getpwnam_r, &args)) != 0) {
- if (e != ERANGE || args.bufsize >= GETPW_R_SIZE_LIMIT) {
+ while ((e = getpwnam_r(usrname, &pwbuf, getpw_buf, getpw_buf_len, &pwptr)) != 0) {
+ if (e != ERANGE || getpw_buf_len >= GETPW_R_SIZE_LIMIT) {
rb_str_resize(*getpw_tmp, 0);
rb_syserr_fail(e, "getpwnam_r");
}
- rb_str_modify_expand(*getpw_tmp, (long)args.bufsize);
- args.buf = RSTRING_PTR(*getpw_tmp);
- args.bufsize = (size_t)rb_str_capacity(*getpw_tmp);
+ rb_str_modify_expand(*getpw_tmp, getpw_buf_len);
+ getpw_buf = RSTRING_PTR(*getpw_tmp);
+ getpw_buf_len = rb_str_capacity(*getpw_tmp);
}
- pwptr = args.result;
#else
pwptr = getpwnam(usrname);
#endif
@@ -6095,26 +6193,6 @@ p_uid_from_name(VALUE self, VALUE id)
#endif
#if defined(HAVE_GRP_H)
-# if defined(USE_GETGRNAM_R)
-struct getgrnam_r_args {
- const char *name;
- char *buf;
- size_t bufsize;
- struct group *result;
- struct group grp;
-};
-
-# define GETGRNAM_R_ARGS(name_, buf_, bufsize_) (struct getgrnam_r_args) \
- {.name = name_, .buf = buf_, .bufsize = bufsize_, .result = NULL}
-
-static void *
-nogvl_getgrnam_r(void *args)
-{
- struct getgrnam_r_args *arg = args;
- return (void *)(VALUE)getgrnam_r(arg->name, &arg->grp, arg->buf, arg->bufsize, &arg->result);
-}
-# endif
-
static rb_gid_t
obj2gid(VALUE id
# ifdef USE_GETGRNAM_R
@@ -6132,6 +6210,7 @@ obj2gid(VALUE id
const char *grpname = StringValueCStr(id);
struct group *grptr;
#ifdef USE_GETGRNAM_R
+ struct group grbuf;
char *getgr_buf;
long getgr_buf_len;
int e;
@@ -6144,18 +6223,15 @@ obj2gid(VALUE id
getgr_buf_len = rb_str_capacity(*getgr_tmp);
rb_str_set_len(*getgr_tmp, getgr_buf_len);
errno = 0;
- struct getgrnam_r_args args = GETGRNAM_R_ARGS(grpname, getgr_buf, (size_t)getgr_buf_len);
-
- while ((e = IO_WITHOUT_GVL_INT(nogvl_getgrnam_r, &args)) != 0) {
- if (e != ERANGE || args.bufsize >= GETGR_R_SIZE_LIMIT) {
+ while ((e = getgrnam_r(grpname, &grbuf, getgr_buf, getgr_buf_len, &grptr)) != 0) {
+ if (e != ERANGE || getgr_buf_len >= GETGR_R_SIZE_LIMIT) {
rb_str_resize(*getgr_tmp, 0);
rb_syserr_fail(e, "getgrnam_r");
}
- rb_str_modify_expand(*getgr_tmp, (long)args.bufsize);
- args.buf = RSTRING_PTR(*getgr_tmp);
- args.bufsize = (size_t)rb_str_capacity(*getgr_tmp);
+ rb_str_modify_expand(*getgr_tmp, getgr_buf_len);
+ getgr_buf = RSTRING_PTR(*getgr_tmp);
+ getgr_buf_len = rb_str_capacity(*getgr_tmp);
}
- grptr = args.result;
#elif defined(HAVE_GETGRNAM)
grptr = getgrnam(grpname);
#else
@@ -6322,14 +6398,13 @@ p_sys_setresuid(VALUE obj, VALUE rid, VALUE eid, VALUE sid)
/*
* call-seq:
- * Process.uid -> integer
- * Process::UID.rid -> integer
- * Process::Sys.getuid -> integer
- *
- * Returns the (real) user ID of the current process.
+ * Process.uid -> integer
+ * Process::UID.rid -> integer
+ * Process::Sys.getuid -> integer
*
- * Process.uid # => 1000
+ * Returns the (real) user ID of this process.
*
+ * Process.uid #=> 501
*/
static VALUE
@@ -6343,13 +6418,10 @@ proc_getuid(VALUE obj)
#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRUID) || defined(HAVE_SETUID)
/*
* call-seq:
- * Process.uid = new_uid -> new_uid
- *
- * Sets the (user) user ID for the current process to +new_uid+:
- *
- * Process.uid = 1000 # => 1000
+ * Process.uid= user -> numeric
*
- * Not available on all platforms.
+ * Sets the (user) user ID for this process. Not available on all
+ * platforms.
*/
static VALUE
@@ -6724,14 +6796,13 @@ p_sys_issetugid(VALUE obj)
/*
* call-seq:
- * Process.gid -> integer
- * Process::GID.rid -> integer
- * Process::Sys.getgid -> integer
- *
- * Returns the (real) group ID for the current process:
+ * Process.gid -> integer
+ * Process::GID.rid -> integer
+ * Process::Sys.getgid -> integer
*
- * Process.gid # => 1000
+ * Returns the (real) group ID for this process.
*
+ * Process.gid #=> 500
*/
static VALUE
@@ -6745,12 +6816,9 @@ proc_getgid(VALUE obj)
#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETRGID) || defined(HAVE_SETGID)
/*
* call-seq:
- * Process.gid = new_gid -> new_gid
- *
- * Sets the group ID for the current process to +new_gid+:
- *
- * Process.gid = 1000 # => 1000
+ * Process.gid= integer -> integer
*
+ * Sets the group ID for this process.
*/
static VALUE
@@ -6834,23 +6902,26 @@ maxgroups(void)
#ifdef HAVE_GETGROUPS
/*
* call-seq:
- * Process.groups -> array
+ * Process.groups -> array
*
- * Returns an array of the group IDs
- * in the supplemental group access list for the current process:
+ * Get an Array of the group IDs in the
+ * supplemental group access list for this process.
*
- * Process.groups # => [4, 24, 27, 30, 46, 122, 135, 136, 1000]
+ * Process.groups #=> [27, 6, 10, 11]
*
- * These properties of the returned array are system-dependent:
+ * Note that this method is just a wrapper of getgroups(2).
+ * This means that the following characteristics of
+ * the result completely depend on your system:
*
- * - Whether (and how) the array is sorted.
- * - Whether the array includes effective group IDs.
- * - Whether the array includes duplicate group IDs.
- * - Whether the array size exceeds the value of Process.maxgroups.
+ * - the result is sorted
+ * - the result includes effective GIDs
+ * - the result does not include duplicated GIDs
+ * - the result size does not exceed the value of Process.maxgroups
*
- * Use this call to get a sorted and unique array:
+ * You can make sure to get a sorted unique GID list of
+ * the current process by this expression:
*
- * Process.groups.uniq.sort
+ * Process.groups.uniq.sort
*
*/
@@ -6887,14 +6958,14 @@ proc_getgroups(VALUE obj)
#ifdef HAVE_SETGROUPS
/*
* call-seq:
- * Process.groups = new_groups -> new_groups
+ * Process.groups= array -> array
*
- * Sets the supplemental group access list to the given
- * array of group IDs.
+ * Set the supplemental group access list to the given
+ * Array of group IDs.
*
- * Process.groups # => [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
- * Process.groups = [27, 6, 10, 11] # => [27, 6, 10, 11]
- * Process.groups # => [27, 6, 10, 11]
+ * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
+ * Process.groups = [27, 6, 10, 11] #=> [27, 6, 10, 11]
+ * Process.groups #=> [27, 6, 10, 11]
*
*/
@@ -6936,21 +7007,19 @@ proc_setgroups(VALUE obj, VALUE ary)
#ifdef HAVE_INITGROUPS
/*
* call-seq:
- * Process.initgroups(username, gid) -> array
- *
- * Sets the supplemental group access list;
- * the new list includes:
+ * Process.initgroups(username, gid) -> array
*
- * - The group IDs of those groups to which the user given by +username+ belongs.
- * - The group ID +gid+.
+ * Initializes the supplemental group access list by reading the
+ * system group database and using all groups of which the given user
+ * is a member. The group with the specified _gid_ is also added to
+ * the list. Returns the resulting Array of the GIDs of all the
+ * groups in the supplementary group access list. Not available on
+ * all platforms.
*
- * Example:
+ * Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
+ * Process.initgroups( "mgranger", 30 ) #=> [30, 6, 10, 11]
+ * Process.groups #=> [30, 6, 10, 11]
*
- * Process.groups # => [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
- * Process.initgroups('me', 30) # => [30, 6, 10, 11]
- * Process.groups # => [30, 6, 10, 11]
- *
- * Not available on all platforms.
*/
static VALUE
@@ -6968,13 +7037,12 @@ proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
#if defined(_SC_NGROUPS_MAX) || defined(NGROUPS_MAX)
/*
* call-seq:
- * Process.maxgroups -> integer
- *
- * Returns the maximum number of group IDs allowed
- * in the supplemental group access list:
+ * Process.maxgroups -> integer
*
- * Process.maxgroups # => 32
+ * Returns the maximum number of GIDs allowed in the supplemental
+ * group access list.
*
+ * Process.maxgroups #=> 32
*/
static VALUE
@@ -6989,10 +7057,10 @@ proc_getmaxgroups(VALUE obj)
#ifdef HAVE_SETGROUPS
/*
* call-seq:
- * Process.maxgroups = new_max -> new_max
+ * Process.maxgroups= integer -> integer
*
- * Sets the maximum number of group IDs allowed
- * in the supplemental group access list.
+ * Sets the maximum number of GIDs allowed in the supplemental group
+ * access list.
*/
static VALUE
@@ -7023,22 +7091,16 @@ static int rb_daemon(int nochdir, int noclose);
/*
* call-seq:
- * Process.daemon(nochdir = nil, noclose = nil) -> 0
- *
- * Detaches the current process from its controlling terminal
- * and runs it in the background as system daemon;
- * returns zero.
- *
- * By default:
- *
- * - Changes the current working directory to the root directory.
- * - Redirects $stdin, $stdout, and $stderr to the null device.
- *
- * If optional argument +nochdir+ is +true+,
- * does not change the current working directory.
- *
- * If optional argument +noclose+ is +true+,
- * does not redirect $stdin, $stdout, or $stderr.
+ * Process.daemon() -> 0
+ * Process.daemon(nochdir=nil,noclose=nil) -> 0
+ *
+ * Detach the process from controlling terminal and run in
+ * the background as system daemon. Unless the argument
+ * nochdir is true (i.e. non false), it changes the current
+ * working directory to the root ("/"). Unless the argument
+ * noclose is true, daemon() will redirect standard input,
+ * standard output and standard error to /dev/null.
+ * Return zero on success, or raise one of Errno::*.
*/
static VALUE
@@ -7057,16 +7119,16 @@ proc_daemon(int argc, VALUE *argv, VALUE _)
return INT2FIX(n);
}
-extern const char ruby_null_device[];
-
static int
rb_daemon(int nochdir, int noclose)
{
int err = 0;
#ifdef HAVE_DAEMON
+ if (mjit_enabled) mjit_pause(false); // Don't leave locked mutex to child.
before_fork_ruby();
err = daemon(nochdir, noclose);
- after_fork_ruby(0);
+ after_fork_ruby();
+ rb_thread_atfork(); /* calls mjit_resume() */
#else
int n;
@@ -7082,7 +7144,7 @@ rb_daemon(int nochdir, int noclose)
if (!nochdir)
err = chdir("/");
- if (!noclose && (n = rb_cloexec_open(ruby_null_device, O_RDWR, 0)) != -1) {
+ if (!noclose && (n = rb_cloexec_open("/dev/null", O_RDWR, 0)) != -1) {
rb_update_max_fd(n);
(void)dup2(n, 0);
(void)dup2(n, 1);
@@ -7295,14 +7357,13 @@ p_gid_change_privilege(VALUE obj, VALUE id)
/*
* call-seq:
- * Process.euid -> integer
- * Process::UID.eid -> integer
- * Process::Sys.geteuid -> integer
- *
- * Returns the effective user ID for the current process.
+ * Process.euid -> integer
+ * Process::UID.eid -> integer
+ * Process::Sys.geteuid -> integer
*
- * Process.euid # => 501
+ * Returns the effective user ID for this process.
*
+ * Process.euid #=> 501
*/
static VALUE
@@ -7338,11 +7399,10 @@ proc_seteuid(rb_uid_t uid)
#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) || defined(HAVE_SETUID)
/*
* call-seq:
- * Process.euid = new_euid -> new_euid
+ * Process.euid= user
*
- * Sets the effective user ID for the current process.
- *
- * Not available on all platforms.
+ * Sets the effective user ID for this process. Not available on all
+ * platforms.
*/
static VALUE
@@ -7420,15 +7480,14 @@ p_uid_grant_privilege(VALUE obj, VALUE id)
/*
* call-seq:
- * Process.egid -> integer
- * Process::GID.eid -> integer
- * Process::Sys.geteid -> integer
- *
- * Returns the effective group ID for the current process:
+ * Process.egid -> integer
+ * Process::GID.eid -> integer
+ * Process::Sys.geteid -> integer
*
- * Process.egid # => 500
+ * Returns the effective group ID for this process. Not available on
+ * all platforms.
*
- * Not available on all platforms.
+ * Process.egid #=> 500
*/
static VALUE
@@ -7442,11 +7501,10 @@ proc_getegid(VALUE obj)
#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID) || defined(_POSIX_SAVED_IDS)
/*
* call-seq:
- * Process.egid = new_egid -> new_egid
- *
- * Sets the effective group ID for the current process.
+ * Process.egid = integer -> integer
*
- * Not available on all platforms.
+ * Sets the effective group ID for this process. Not available on all
+ * platforms.
*/
static VALUE
@@ -7919,15 +7977,14 @@ get_clk_tck(void)
/*
* call-seq:
- * Process.times -> process_tms
- *
- * Returns a Process::Tms structure that contains user and system CPU times
- * for the current process, and for its children processes:
+ * Process.times -> aProcessTms
*
- * Process.times
- * # => #<struct Process::Tms utime=55.122118, stime=35.533068, cutime=0.0, cstime=0.002846>
+ * Returns a <code>Tms</code> structure (see Process::Tms)
+ * that contains user and system CPU times for this process,
+ * and also for children processes.
*
- * The precision is platform-defined.
+ * t = Process.times
+ * [ t.utime, t.stime, t.cutime, t.cstime ] #=> [0.0, 0.02, 0.00, 0.00]
*/
VALUE
@@ -8182,174 +8239,132 @@ ruby_real_ms_time(void)
# define NUM2CLOCKID(x) 0
#endif
-#define clock_failed(name, err, arg) do { \
- int clock_error = (err); \
- rb_syserr_fail_str(clock_error, rb_sprintf("clock_" name "(%+"PRIsVALUE")", (arg))); \
- } while (0)
-
/*
* call-seq:
- * Process.clock_gettime(clock_id, unit = :float_second) -> number
- *
- * Returns a clock time as determined by POSIX function
- * {clock_gettime()}[https://man7.org/linux/man-pages/man3/clock_gettime.3.html]:
- *
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID) # => 198.650379677
- *
- * Argument +clock_id+ should be a symbol or a constant that specifies
- * the clock whose time is to be returned;
- * see below.
- *
- * Optional argument +unit+ should be a symbol that specifies
- * the unit to be used in the returned clock time;
- * see below.
- *
- * <b>Argument +clock_id+</b>
- *
- * Argument +clock_id+ specifies the clock whose time is to be returned;
- * it may be a constant such as <tt>Process::CLOCK_REALTIME</tt>,
- * or a symbol shorthand such as +:CLOCK_REALTIME+.
- *
- * The supported clocks depend on the underlying operating system;
- * this method supports the following clocks on the indicated platforms
- * (raises Errno::EINVAL if called with an unsupported clock):
- *
- * - +:CLOCK_BOOTTIME+: Linux 2.6.39.
- * - +:CLOCK_BOOTTIME_ALARM+: Linux 3.0.
- * - +:CLOCK_MONOTONIC+: SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12, Windows-2000.
- * - +:CLOCK_MONOTONIC_COARSE+: Linux 2.6.32.
- * - +:CLOCK_MONOTONIC_FAST+: FreeBSD 8.1.
- * - +:CLOCK_MONOTONIC_PRECISE+: FreeBSD 8.1.
- * - +:CLOCK_MONOTONIC_RAW+: Linux 2.6.28, macOS 10.12.
- * - +:CLOCK_MONOTONIC_RAW_APPROX+: macOS 10.12.
- * - +:CLOCK_PROCESS_CPUTIME_ID+: SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12.
- * - +:CLOCK_PROF+: FreeBSD 3.0, OpenBSD 2.1.
- * - +:CLOCK_REALTIME+: SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1, macOS 10.12, Windows-8/Server-2012.
- * Time.now is recommended over +:CLOCK_REALTIME:.
- * - +:CLOCK_REALTIME_ALARM+: Linux 3.0.
- * - +:CLOCK_REALTIME_COARSE+: Linux 2.6.32.
- * - +:CLOCK_REALTIME_FAST+: FreeBSD 8.1.
- * - +:CLOCK_REALTIME_PRECISE+: FreeBSD 8.1.
- * - +:CLOCK_SECOND+: FreeBSD 8.1.
- * - +:CLOCK_TAI+: Linux 3.10.
- * - +:CLOCK_THREAD_CPUTIME_ID+: SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12.
- * - +:CLOCK_UPTIME+: FreeBSD 7.0, OpenBSD 5.5.
- * - +:CLOCK_UPTIME_FAST+: FreeBSD 8.1.
- * - +:CLOCK_UPTIME_PRECISE+: FreeBSD 8.1.
- * - +:CLOCK_UPTIME_RAW+: macOS 10.12.
- * - +:CLOCK_UPTIME_RAW_APPROX+: macOS 10.12.
- * - +:CLOCK_VIRTUAL+: FreeBSD 3.0, OpenBSD 2.1.
+ * Process.clock_gettime(clock_id [, unit]) -> number
+ *
+ * Returns a time returned by POSIX clock_gettime() function.
+ *
+ * p Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ * #=> 896053.968060096
+ *
+ * +clock_id+ specifies a kind of clock.
+ * It is specified as a constant which begins with <code>Process::CLOCK_</code>
+ * such as Process::CLOCK_REALTIME and Process::CLOCK_MONOTONIC.
+ *
+ * The supported constants depends on OS and version.
+ * Ruby provides following types of +clock_id+ if available.
+ *
+ * [CLOCK_REALTIME] SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1, macOS 10.12, Windows-8/Server-2012
+ * [CLOCK_MONOTONIC] SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12, Windows-2000
+ * [CLOCK_PROCESS_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12
+ * [CLOCK_THREAD_CPUTIME_ID] SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12
+ * [CLOCK_VIRTUAL] FreeBSD 3.0, OpenBSD 2.1
+ * [CLOCK_PROF] FreeBSD 3.0, OpenBSD 2.1
+ * [CLOCK_REALTIME_FAST] FreeBSD 8.1
+ * [CLOCK_REALTIME_PRECISE] FreeBSD 8.1
+ * [CLOCK_REALTIME_COARSE] Linux 2.6.32
+ * [CLOCK_REALTIME_ALARM] Linux 3.0
+ * [CLOCK_MONOTONIC_FAST] FreeBSD 8.1
+ * [CLOCK_MONOTONIC_PRECISE] FreeBSD 8.1
+ * [CLOCK_MONOTONIC_COARSE] Linux 2.6.32
+ * [CLOCK_MONOTONIC_RAW] Linux 2.6.28, macOS 10.12
+ * [CLOCK_MONOTONIC_RAW_APPROX] macOS 10.12
+ * [CLOCK_BOOTTIME] Linux 2.6.39
+ * [CLOCK_BOOTTIME_ALARM] Linux 3.0
+ * [CLOCK_UPTIME] FreeBSD 7.0, OpenBSD 5.5
+ * [CLOCK_UPTIME_FAST] FreeBSD 8.1
+ * [CLOCK_UPTIME_RAW] macOS 10.12
+ * [CLOCK_UPTIME_RAW_APPROX] macOS 10.12
+ * [CLOCK_UPTIME_PRECISE] FreeBSD 8.1
+ * [CLOCK_SECOND] FreeBSD 8.1
+ * [CLOCK_TAI] Linux 3.10
*
* Note that SUS stands for Single Unix Specification.
* SUS contains POSIX and clock_gettime is defined in the POSIX part.
- * SUS defines +:CLOCK_REALTIME+ as mandatory but
- * +:CLOCK_MONOTONIC+, +:CLOCK_PROCESS_CPUTIME_ID+,
- * and +:CLOCK_THREAD_CPUTIME_ID+ are optional.
- *
- * Certain emulations are used when the given +clock_id+
- * is not supported directly:
- *
- * - Emulations for +:CLOCK_REALTIME+:
- *
- * - +:GETTIMEOFDAY_BASED_CLOCK_REALTIME+:
- * Use gettimeofday() defined by SUS (deprecated in SUSv4).
- * The resolution is 1 microsecond.
- * - +:TIME_BASED_CLOCK_REALTIME+:
- * Use time() defined by ISO C.
- * The resolution is 1 second.
- *
- * - Emulations for +:CLOCK_MONOTONIC+:
- *
- * - +:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC+:
- * Use mach_absolute_time(), available on Darwin.
- * The resolution is CPU dependent.
- * - +:TIMES_BASED_CLOCK_MONOTONIC+:
- * Use the result value of times() defined by POSIX, thus:
- * >>>
- * Upon successful completion, times() shall return the elapsed real time,
- * in clock ticks, since an arbitrary point in the past
- * (for example, system start-up time).
- *
- * For example, GNU/Linux returns a value based on jiffies and it is monotonic.
- * However, 4.4BSD uses gettimeofday() and it is not monotonic.
- * (FreeBSD uses +:CLOCK_MONOTONIC+ instead, though.)
- *
- * The resolution is the clock tick.
- * "getconf CLK_TCK" command shows the clock ticks per second.
- * (The clock ticks-per-second is defined by HZ macro in older systems.)
- * If it is 100 and clock_t is 32 bits integer type,
- * the resolution is 10 millisecond and cannot represent over 497 days.
- *
- * - Emulations for +:CLOCK_PROCESS_CPUTIME_ID+:
- *
- * - +:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID+:
- * Use getrusage() defined by SUS.
- * getrusage() is used with RUSAGE_SELF to obtain the time only for
- * the calling process (excluding the time for child processes).
- * The result is addition of user time (ru_utime) and system time (ru_stime).
- * The resolution is 1 microsecond.
- * - +:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID+:
- * Use times() defined by POSIX.
- * The result is addition of user time (tms_utime) and system time (tms_stime).
- * tms_cutime and tms_cstime are ignored to exclude the time for child processes.
- * The resolution is the clock tick.
- * "getconf CLK_TCK" command shows the clock ticks per second.
- * (The clock ticks per second is defined by HZ macro in older systems.)
- * If it is 100, the resolution is 10 millisecond.
- * - +:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID+:
- * Use clock() defined by ISO C.
- * The resolution is <tt>1/CLOCKS_PER_SEC</tt>.
- * +CLOCKS_PER_SEC+ is the C-level macro defined by time.h.
- * SUS defines +CLOCKS_PER_SEC+ as 1000000;
- * other systems may define it differently.
- * If +CLOCKS_PER_SEC+ is 1000000 (as in SUS),
- * the resolution is 1 microsecond.
- * If +CLOCKS_PER_SEC+ is 1000000 and clock_t is a 32-bit integer type,
- * it cannot represent over 72 minutes.
- *
- * <b>Argument +unit+</b>
- *
- * Optional argument +unit+ (default +:float_second+)
- * specifies the unit for the returned value.
- *
- * - +:float_microsecond+: Number of microseconds as a float.
- * - +:float_millisecond+: Number of milliseconds as a float.
- * - +:float_second+: Number of seconds as a float.
- * - +:microsecond+: Number of microseconds as an integer.
- * - +:millisecond+: Number of milliseconds as an integer.
- * - +:nanosecond+: Number of nanoseconds as an integer.
- * - +::second+: Number of seconds as an integer.
- *
- * Examples:
- *
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_microsecond)
- * # => 203605054.825
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_millisecond)
- * # => 203643.696848
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_second)
- * # => 203.762181929
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :microsecond)
- * # => 204123212
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :millisecond)
- * # => 204298
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :nanosecond)
- * # => 204602286036
- * Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :second)
- * # => 204
+ * SUS defines CLOCK_REALTIME mandatory but
+ * CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID are optional.
+ *
+ * Also, several symbols are accepted as +clock_id+.
+ * There are emulations for clock_gettime().
+ *
+ * For example, Process::CLOCK_REALTIME is defined as
+ * +:GETTIMEOFDAY_BASED_CLOCK_REALTIME+ when clock_gettime() is not available.
+ *
+ * Emulations for +CLOCK_REALTIME+:
+ * [:GETTIMEOFDAY_BASED_CLOCK_REALTIME]
+ * Use gettimeofday() defined by SUS.
+ * (SUSv4 obsoleted it, though.)
+ * The resolution is 1 microsecond.
+ * [:TIME_BASED_CLOCK_REALTIME]
+ * Use time() defined by ISO C.
+ * The resolution is 1 second.
+ *
+ * Emulations for +CLOCK_MONOTONIC+:
+ * [:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC]
+ * Use mach_absolute_time(), available on Darwin.
+ * The resolution is CPU dependent.
+ * [:TIMES_BASED_CLOCK_MONOTONIC]
+ * Use the result value of times() defined by POSIX.
+ * POSIX defines it as "times() shall return the elapsed real time, in clock ticks, since an arbitrary point in the past (for example, system start-up time)".
+ * For example, GNU/Linux returns a value based on jiffies and it is monotonic.
+ * However, 4.4BSD uses gettimeofday() and it is not monotonic.
+ * (FreeBSD uses clock_gettime(CLOCK_MONOTONIC) instead, though.)
+ * The resolution is the clock tick.
+ * "getconf CLK_TCK" command shows the clock ticks per second.
+ * (The clock ticks per second is defined by HZ macro in older systems.)
+ * If it is 100 and clock_t is 32 bits integer type, the resolution is 10 millisecond and
+ * cannot represent over 497 days.
+ *
+ * Emulations for +CLOCK_PROCESS_CPUTIME_ID+:
+ * [:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID]
+ * Use getrusage() defined by SUS.
+ * getrusage() is used with RUSAGE_SELF to obtain the time only for
+ * the calling process (excluding the time for child processes).
+ * The result is addition of user time (ru_utime) and system time (ru_stime).
+ * The resolution is 1 microsecond.
+ * [:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID]
+ * Use times() defined by POSIX.
+ * The result is addition of user time (tms_utime) and system time (tms_stime).
+ * tms_cutime and tms_cstime are ignored to exclude the time for child processes.
+ * The resolution is the clock tick.
+ * "getconf CLK_TCK" command shows the clock ticks per second.
+ * (The clock ticks per second is defined by HZ macro in older systems.)
+ * If it is 100, the resolution is 10 millisecond.
+ * [:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID]
+ * Use clock() defined by ISO C.
+ * The resolution is 1/CLOCKS_PER_SEC.
+ * CLOCKS_PER_SEC is the C-level macro defined by time.h.
+ * SUS defines CLOCKS_PER_SEC is 1000000.
+ * Non-Unix systems may define it a different value, though.
+ * If CLOCKS_PER_SEC is 1000000 as SUS, the resolution is 1 microsecond.
+ * If CLOCKS_PER_SEC is 1000000 and clock_t is 32 bits integer type, it cannot represent over 72 minutes.
+ *
+ * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
+ *
+ * +unit+ specifies a type of the return value.
+ *
+ * [:float_second] number of seconds as a float (default)
+ * [:float_millisecond] number of milliseconds as a float
+ * [:float_microsecond] number of microseconds as a float
+ * [:second] number of seconds as an integer
+ * [:millisecond] number of milliseconds as an integer
+ * [:microsecond] number of microseconds as an integer
+ * [:nanosecond] number of nanoseconds as an integer
*
* The underlying function, clock_gettime(), returns a number of nanoseconds.
* Float object (IEEE 754 double) is not enough to represent
- * the return value for +:CLOCK_REALTIME+.
+ * the return value for CLOCK_REALTIME.
* If the exact nanoseconds value is required, use +:nanosecond+ as the +unit+.
*
- * The origin (time zero) of the returned value is system-dependent,
- * and may be, for example, system start up time,
- * process start up time, the Epoch, etc.
+ * The origin (zero) of the returned value varies.
+ * For example, system start up time, process start up time, the Epoch, etc.
*
- * The origin in +:CLOCK_REALTIME+ is defined as the Epoch:
- * <tt>1970-01-01 00:00:00 UTC</tt>;
- * some systems count leap seconds and others don't,
- * so the result may vary across systems.
+ * The origin in CLOCK_REALTIME is defined as the Epoch
+ * (1970-01-01 00:00:00 UTC).
+ * But some systems count leap seconds and others doesn't.
+ * So the result can be interpreted differently across systems.
+ * Time.now is recommended over CLOCK_REALTIME.
*/
static VALUE
rb_clock_gettime(int argc, VALUE *argv, VALUE _)
@@ -8526,17 +8541,15 @@ rb_clock_gettime(int argc, VALUE *argv, VALUE _)
gettime:
ret = clock_gettime(c, &ts);
if (ret == -1)
- clock_failed("gettime", errno, clk_id);
+ rb_sys_fail("clock_gettime");
tt.count = (int32_t)ts.tv_nsec;
tt.giga_count = ts.tv_sec;
denominators[num_denominators++] = 1000000000;
goto success;
#endif
}
- else {
- rb_unexpected_type(clk_id, T_SYMBOL);
- }
- clock_failed("gettime", EINVAL, clk_id);
+ /* EINVAL emulates clock_gettime behavior when clock_id is invalid. */
+ rb_syserr_fail(EINVAL, 0);
success:
return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
@@ -8544,39 +8557,45 @@ rb_clock_gettime(int argc, VALUE *argv, VALUE _)
/*
* call-seq:
- * Process.clock_getres(clock_id, unit = :float_second) -> number
+ * Process.clock_getres(clock_id [, unit]) -> number
+ *
+ * Returns an estimate of the resolution of a +clock_id+ using the POSIX
+ * <code>clock_getres()</code> function.
+ *
+ * Note the reported resolution is often inaccurate on most platforms due to
+ * underlying bugs for this function and therefore the reported resolution
+ * often differs from the actual resolution of the clock in practice.
+ * Inaccurate reported resolutions have been observed for various clocks including
+ * CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW when using Linux, macOS, BSD or AIX
+ * platforms, when using ARM processors, or when using virtualization.
+ *
+ * +clock_id+ specifies a kind of clock.
+ * See the document of +Process.clock_gettime+ for details.
+ * +clock_id+ can be a symbol as for +Process.clock_gettime+.
*
- * Returns a clock resolution as determined by POSIX function
- * {clock_getres()}[https://man7.org/linux/man-pages/man3/clock_getres.3.html]:
+ * If the given +clock_id+ is not supported, Errno::EINVAL is raised.
*
- * Process.clock_getres(:CLOCK_REALTIME) # => 1.0e-09
+ * +unit+ specifies the type of the return value.
+ * +Process.clock_getres+ accepts +unit+ as +Process.clock_gettime+.
+ * The default value, +:float_second+, is also the same as
+ * +Process.clock_gettime+.
*
- * See Process.clock_gettime for the values of +clock_id+ and +unit+.
+ * +Process.clock_getres+ also accepts +:hertz+ as +unit+.
+ * +:hertz+ means the reciprocal of +:float_second+.
*
- * Examples:
+ * +:hertz+ can be used to obtain the exact value of
+ * the clock ticks per second for the times() function and
+ * CLOCKS_PER_SEC for the clock() function.
*
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_microsecond) # => 0.001
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_millisecond) # => 1.0e-06
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_second) # => 1.0e-09
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :microsecond) # => 0
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :millisecond) # => 0
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :nanosecond) # => 1
- * Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :second) # => 0
+ * <code>Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
+ * returns the clock ticks per second.
*
- * In addition to the values for +unit+ supported in Process.clock_gettime,
- * this method supports +:hertz+, the integer number of clock ticks per second
- * (which is the reciprocal of +:float_second+):
+ * <code>Process.clock_getres(:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)</code>
+ * returns CLOCKS_PER_SEC.
*
- * Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz) # => 100.0
- * Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :float_second) # => 0.01
+ * p Process.clock_getres(Process::CLOCK_MONOTONIC)
+ * #=> 1.0e-09
*
- * <b>Accuracy</b>:
- * Note that the returned resolution may be inaccurate on some platforms
- * due to underlying bugs.
- * Inaccurate resolutions have been reported for various clocks including
- * +:CLOCK_MONOTONIC+ and +:CLOCK_MONOTONIC_RAW+
- * on Linux, macOS, BSD or AIX platforms, when using ARM processors,
- * or when using virtualization.
*/
static VALUE
rb_clock_getres(int argc, VALUE *argv, VALUE _)
@@ -8697,17 +8716,15 @@ rb_clock_getres(int argc, VALUE *argv, VALUE _)
getres:
ret = clock_getres(c, &ts);
if (ret == -1)
- clock_failed("getres", errno, clk_id);
+ rb_sys_fail("clock_getres");
tt.count = (int32_t)ts.tv_nsec;
tt.giga_count = ts.tv_sec;
denominators[num_denominators++] = 1000000000;
goto success;
#endif
}
- else {
- rb_unexpected_type(clk_id, T_SYMBOL);
- }
- clock_failed("getres", EINVAL, clk_id);
+ /* EINVAL emulates clock_getres behavior when clock_id is invalid. */
+ rb_syserr_fail(EINVAL, 0);
success:
if (unit == ID2SYM(id_hertz)) {
@@ -8732,82 +8749,38 @@ get_PROCESS_ID(ID _x, VALUE *_y)
/*
* call-seq:
- * Process.kill(signal, *ids) -> count
- *
- * Sends a signal to each process specified by +ids+
- * (which must specify at least one ID);
- * returns the count of signals sent.
- *
- * For each given +id+, if +id+ is:
- *
- * - Positive, sends the signal to the process whose process ID is +id+.
- * - Zero, send the signal to all processes in the current process group.
- * - Negative, sends the signal to a system-dependent collection of processes.
- *
- * Argument +signal+ specifies the signal to be sent;
- * the argument may be:
- *
- * - An integer signal number: e.g., +-29+, +0+, +29+.
- * - A signal name (string), with or without leading <tt>'SIG'</tt>,
- * and with or without a further prefixed minus sign (<tt>'-'</tt>):
- * e.g.:
- *
- * - <tt>'SIGPOLL'</tt>.
- * - <tt>'POLL'</tt>,
- * - <tt>'-SIGPOLL'</tt>.
- * - <tt>'-POLL'</tt>.
- *
- * - A signal symbol, with or without leading <tt>'SIG'</tt>,
- * and with or without a further prefixed minus sign (<tt>'-'</tt>):
- * e.g.:
- *
- * - +:SIGPOLL+.
- * - +:POLL+.
- * - <tt>:'-SIGPOLL'</tt>.
- * - <tt>:'-POLL'</tt>.
- *
- * If +signal+ is:
- *
- * - A non-negative integer, or a signal name or symbol
- * without prefixed <tt>'-'</tt>,
- * each process with process ID +id+ is signalled.
- * - A negative integer, or a signal name or symbol
- * with prefixed <tt>'-'</tt>,
- * each process group with group ID +id+ is signalled.
- *
- * Use method Signal.list to see which signals are supported
- * by Ruby on the underlying platform;
- * the method returns a hash of the string names
- * and non-negative integer values of the supported signals.
- * The size and content of the returned hash varies widely
- * among platforms.
- *
- * Additionally, signal +0+ is useful to determine if the process exists.
- *
- * Example:
- *
- * pid = fork do
- * Signal.trap('HUP') { puts 'Ouch!'; exit }
- * # ... do some work ...
- * end
- * # ...
- * Process.kill('HUP', pid)
- * Process.wait
- *
- * Output:
+ * Process.kill(signal, pid, *pids) -> integer
+ *
+ * Sends the given signal to the specified process id(s) if _pid_ is positive.
+ * If _pid_ is zero, _signal_ is sent to all processes whose group ID is equal
+ * to the group ID of the process. If _pid_ is negative, results are dependent
+ * on the operating system. _signal_ may be an integer signal number or
+ * a POSIX signal name (either with or without a +SIG+ prefix). If _signal_ is
+ * negative (or starts with a minus sign), kills process groups instead of
+ * processes. Not all signals are available on all platforms.
+ * The keys and values of Signal.list are known signal names and numbers,
+ * respectively.
+ *
+ * pid = fork do
+ * Signal.trap("HUP") { puts "Ouch!"; exit }
+ * # ... do some work ...
+ * end
+ * # ...
+ * Process.kill("HUP", pid)
+ * Process.wait
+ *
+ * <em>produces:</em>
*
* Ouch!
*
- * Exceptions:
- *
- * - Raises Errno::EINVAL or RangeError if +signal+ is an integer
- * but invalid.
- * - Raises ArgumentError if +signal+ is a string or symbol
- * but invalid.
- * - Raises Errno::ESRCH or RangeError if one of +ids+ is invalid.
- * - Raises Errno::EPERM if needed permissions are not in force.
+ * If _signal_ is an integer but wrong for signal, Errno::EINVAL or
+ * RangeError will be raised. Otherwise unless _signal_ is a String
+ * or a Symbol, and a known signal name, ArgumentError will be
+ * raised.
*
- * In the last two cases, signals may have been sent to some processes.
+ * Also, Errno::ESRCH or RangeError for invalid _pid_, Errno::EPERM
+ * when failed because of no privilege, will be raised. In these
+ * cases, signals may have been sent to preceding processes.
*/
static VALUE
@@ -8821,456 +8794,10 @@ static VALUE rb_mProcUID;
static VALUE rb_mProcGID;
static VALUE rb_mProcID_Syscall;
-/*
- * call-seq:
- * Process.warmup -> true
- *
- * Notify the Ruby virtual machine that the boot sequence is finished,
- * and that now is a good time to optimize the application. This is useful
- * for long running applications.
- *
- * This method is expected to be called at the end of the application boot.
- * If the application is deployed using a pre-forking model, +Process.warmup+
- * should be called in the original process before the first fork.
- *
- * The actual optimizations performed are entirely implementation specific
- * and may change in the future without notice.
- *
- * On CRuby, +Process.warmup+:
- *
- * * Performs a major GC.
- * * Compacts the heap.
- * * Promotes all surviving objects to the old generation.
- * * Precomputes the coderange of all strings.
- * * Frees all empty heap pages and increments the allocatable pages counter
- * by the number of pages freed.
- * * Invoke +malloc_trim+ if available to free empty malloc pages.
- */
-
-static VALUE
-proc_warmup(VALUE _)
-{
- RB_VM_LOCK_ENTER();
- rb_gc_prepare_heap();
- RB_VM_LOCK_LEAVE();
- return Qtrue;
-}
/*
- * Document-module: Process
- *
- * \Module +Process+ represents a process in the underlying operating system.
- * Its methods support management of the current process and its child processes.
- *
- * == \Process Creation
- *
- * Each of the following methods executes a given command in a new process or subshell,
- * or multiple commands in new processes and/or subshells.
- * The choice of process or subshell depends on the form of the command;
- * see {Argument command_line or exe_path}[rdoc-ref:Process@Argument+command_line+or+exe_path].
- *
- * - Process.spawn, Kernel#spawn: Executes the command;
- * returns the new pid without waiting for completion.
- * - Process.exec: Replaces the current process by executing the command.
- *
- * In addition:
- *
- * - \Method Kernel#system executes a given command-line (string) in a subshell;
- * returns +true+, +false+, or +nil+.
- * - \Method Kernel#` executes a given command-line (string) in a subshell;
- * returns its $stdout string.
- * - \Module Open3 supports creating child processes
- * with access to their $stdin, $stdout, and $stderr streams.
- *
- * === Execution Environment
- *
- * Optional leading argument +env+ is a hash of name/value pairs,
- * where each name is a string and each value is a string or +nil+;
- * each name/value pair is added to ENV in the new process.
- *
- * Process.spawn( 'ruby -e "p ENV[\"Foo\"]"')
- * Process.spawn({'Foo' => '0'}, 'ruby -e "p ENV[\"Foo\"]"')
- *
- * Output:
- *
- * "0"
- *
- * The effect is usually similar to that of calling ENV#update with argument +env+,
- * where each named environment variable is created or updated
- * (if the value is non-+nil+),
- * or deleted (if the value is +nil+).
- *
- * However, some modifications to the calling process may remain
- * if the new process fails.
- * For example, hard resource limits are not restored.
- *
- * === Argument +command_line+ or +exe_path+
- *
- * The required string argument is one of the following:
- *
- * - +command_line+ if it begins with a shell reserved word or special built-in,
- * or if it contains one or more meta characters.
- * - +exe_path+ otherwise.
- *
- * ==== Argument +command_line+
- *
- * \String argument +command_line+ is a command line to be passed to a shell;
- * it must begin with a shell reserved word, begin with a special built-in,
- * or contain meta characters:
- *
- * system('if true; then echo "Foo"; fi') # => true # Shell reserved word.
- * system('exit') # => true # Built-in.
- * system('date > /tmp/date.tmp') # => true # Contains meta character.
- * system('date > /nop/date.tmp') # => false
- * system('date > /nop/date.tmp', exception: true) # Raises RuntimeError.
- *
- * The command line may also contain arguments and options for the command:
- *
- * system('echo "Foo"') # => true
- *
- * Output:
- *
- * Foo
- *
- * See {Execution Shell}[rdoc-ref:Process@Execution+Shell] for details about the shell.
- *
- * ==== Argument +exe_path+
- *
- * Argument +exe_path+ is one of the following:
- *
- * - The string path to an executable file to be called:
- *
- * Example:
- *
- * system('/usr/bin/date') # => true # Path to date on Unix-style system.
- * system('foo') # => nil # Command execlution failed.
- *
- * Output:
- *
- * Thu Aug 31 10:06:48 AM CDT 2023
- *
- * A path or command name containing spaces without arguments cannot
- * be distinguished from +command_line+ above, so you must quote or
- * escape the entire command name using a shell in platform
- * dependent manner, or use the array form below.
- *
- * If +exe_path+ does not contain any path separator, an executable
- * file is searched from directories specified with the +PATH+
- * environment variable. What the word "executable" means here is
- * depending on platforms.
- *
- * Even if the file considered "executable", its content may not be
- * in proper executable format. In that case, Ruby tries to run it
- * by using <tt>/bin/sh</tt> on a Unix-like system, like system(3)
- * does.
- *
- * File.write('shell_command', 'echo $SHELL', perm: 0o755)
- * system('./shell_command') # prints "/bin/sh" or something.
- *
- * - A 2-element array containing the path to an executable
- * and the string to be used as the name of the executing process:
- *
- * Example:
- *
- * pid = spawn(['sleep', 'Hello!'], '1') # 2-element array.
- * p `ps -p #{pid} -o command=`
- *
- * Output:
- *
- * "Hello! 1\n"
- *
- * === Arguments +args+
- *
- * If +command_line+ does not contain shell meta characters except for
- * spaces and tabs, or +exe_path+ is given, Ruby invokes the
- * executable directly. This form does not use the shell:
- *
- * spawn("doesnt_exist") # Raises Errno::ENOENT
- * spawn("doesnt_exist", "\n") # Raises Errno::ENOENT
- *
- * spawn("doesnt_exist\n") # => false
- * # sh: 1: doesnot_exist: not found
- *
- * The error message is from a shell and would vary depending on your
- * system.
- *
- * If one or more +args+ is given after +exe_path+, each is an
- * argument or option to be passed to the executable:
- *
- * Example:
- *
- * system('echo', '<', 'C*', '|', '$SHELL', '>') # => true
- *
- * Output:
- *
- * < C* | $SHELL >
- *
- * However, there are exceptions on Windows. See {Execution Shell on
- * Windows}[rdoc-ref:Process@Execution+Shell+on+Windows].
- *
- * If you want to invoke a path containing spaces with no arguments
- * without shell, you will need to use a 2-element array +exe_path+.
- *
- * Example:
- *
- * path = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
- * spawn(path) # Raises Errno::ENOENT; No such file or directory - /Applications/Google
- * spawn([path] * 2)
- *
- * === Execution Options
- *
- * Optional trailing argument +options+ is a hash of execution options.
- *
- * ==== Working Directory (+:chdir+)
- *
- * By default, the working directory for the new process is the same as
- * that of the current process:
- *
- * Dir.chdir('/var')
- * Process.spawn('ruby -e "puts Dir.pwd"')
- *
- * Output:
- *
- * /var
- *
- * Use option +:chdir+ to set the working directory for the new process:
- *
- * Process.spawn('ruby -e "puts Dir.pwd"', {chdir: '/tmp'})
- *
- * Output:
- *
- * /tmp
- *
- * The working directory of the current process is not changed:
- *
- * Dir.pwd # => "/var"
- *
- * ==== \File Redirection (\File Descriptor)
- *
- * Use execution options for file redirection in the new process.
- *
- * The key for such an option may be an integer file descriptor (fd),
- * specifying a source,
- * or an array of fds, specifying multiple sources.
- *
- * An integer source fd may be specified as:
- *
- * - _n_: Specifies file descriptor _n_.
- *
- * There are these shorthand symbols for fds:
- *
- * - +:in+: Specifies file descriptor 0 (STDIN).
- * - +:out+: Specifies file descriptor 1 (STDOUT).
- * - +:err+: Specifies file descriptor 2 (STDERR).
- *
- * The value given with a source is one of:
- *
- * - _n_:
- * Redirects to fd _n_ in the parent process.
- * - +filepath+:
- * Redirects from or to the file at +filepath+ via <tt>open(filepath, mode, 0644)</tt>,
- * where +mode+ is <tt>'r'</tt> for source +:in+,
- * or <tt>'w'</tt> for source +:out+ or +:err+.
- * - <tt>[filepath]</tt>:
- * Redirects from the file at +filepath+ via <tt>open(filepath, 'r', 0644)</tt>.
- * - <tt>[filepath, mode]</tt>:
- * Redirects from or to the file at +filepath+ via <tt>open(filepath, mode, 0644)</tt>.
- * - <tt>[filepath, mode, perm]</tt>:
- * Redirects from or to the file at +filepath+ via <tt>open(filepath, mode, perm)</tt>.
- * - <tt>[:child, fd]</tt>:
- * Redirects to the redirected +fd+.
- * - +:close+: Closes the file descriptor in child process.
- *
- * See {Access Modes}[rdoc-ref:File@Access+Modes]
- * and {File Permissions}[rdoc-ref:File@File+Permissions].
- *
- * ==== Environment Variables (+:unsetenv_others+)
- *
- * By default, the new process inherits environment variables
- * from the parent process;
- * use execution option key +:unsetenv_others+ with value +true+
- * to clear environment variables in the new process.
- *
- * Any changes specified by execution option +env+ are made after the new process
- * inherits or clears its environment variables;
- * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
- *
- * ==== \File-Creation Access (+:umask+)
- *
- * Use execution option +:umask+ to set the file-creation access
- * for the new process;
- * see {Access Modes}[rdoc-ref:File@Access+Modes]:
- *
- * command = 'ruby -e "puts sprintf(\"0%o\", File.umask)"'
- * options = {:umask => 0644}
- * Process.spawn(command, options)
- *
- * Output:
- *
- * 0644
- *
- * ==== \Process Groups (+:pgroup+ and +:new_pgroup+)
- *
- * By default, the new process belongs to the same
- * {process group}[https://en.wikipedia.org/wiki/Process_group]
- * as the parent process.
- *
- * To specify a different process group.
- * use execution option +:pgroup+ with one of the following values:
- *
- * - +true+: Create a new process group for the new process.
- * - _pgid_: Create the new process in the process group
- * whose id is _pgid_.
- *
- * On Windows only, use execution option +:new_pgroup+ with value +true+
- * to create a new process group for the new process.
- *
- * ==== Resource Limits
- *
- * Use execution options to set resource limits.
- *
- * The keys for these options are symbols of the form
- * <tt>:rlimit_<i>resource_name</i></tt>,
- * where _resource_name_ is the downcased form of one of the string
- * resource names described at method Process.setrlimit.
- * For example, key +:rlimit_cpu+ corresponds to resource limit <tt>'CPU'</tt>.
- *
- * The value for such as key is one of:
- *
- * - An integer, specifying both the current and maximum limits.
- * - A 2-element array of integers, specifying the current and maximum limits.
- *
- * ==== \File Descriptor Inheritance
- *
- * By default, the new process inherits file descriptors from the parent process.
- *
- * Use execution option <tt>:close_others => true</tt> to modify that inheritance
- * by closing non-standard fds (3 and greater) that are not otherwise redirected.
- *
- * === Execution Shell
- *
- * On a Unix-like system, the shell invoked is <tt>/bin/sh</tt>;
- * the entire string +command_line+ is passed as an argument
- * to {shell option -c}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/sh.html].
- *
- * The shell performs normal shell expansion on the command line:
- *
- * Example:
- *
- * system('echo $SHELL: C*') # => true
- *
- * Output:
- *
- * /bin/bash: CONTRIBUTING.md COPYING COPYING.ja
- *
- * ==== Execution Shell on Windows
- *
- * On Windows, the shell invoked is determined by environment variable
- * +RUBYSHELL+, if defined, or +COMSPEC+ otherwise; the entire string
- * +command_line+ is passed as an argument to <tt>-c</tt> option for
- * +RUBYSHELL+, as well as <tt>/bin/sh</tt>, and {/c
- * option}[https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/cmd]
- * for +COMSPEC+. The shell is invoked automatically in the following
- * cases:
- *
- * - The command is a built-in of +cmd.exe+, such as +echo+.
- * - The executable file is a batch file; its name ends with +.bat+ or
- * +.cmd+.
- *
- * Note that the command will still be invoked as +command_line+ form
- * even when called in +exe_path+ form, because +cmd.exe+ does not
- * accept a script name like <tt>/bin/sh</tt> does but only works with
- * <tt>/c</tt> option.
- *
- * The standard shell +cmd.exe+ performs environment variable
- * expansion but does not have globbing functionality:
- *
- * Example:
- *
- * system("echo %COMSPEC%: C*")' # => true
- *
- * Output:
- *
- * C:\WINDOWS\system32\cmd.exe: C*
- *
- * == What's Here
- *
- * === Current-Process Getters
- *
- * - ::argv0: Returns the process name as a frozen string.
- * - ::egid: Returns the effective group ID.
- * - ::euid: Returns the effective user ID.
- * - ::getpgrp: Return the process group ID.
- * - ::getrlimit: Returns the resource limit.
- * - ::gid: Returns the (real) group ID.
- * - ::pid: Returns the process ID.
- * - ::ppid: Returns the process ID of the parent process.
- * - ::uid: Returns the (real) user ID.
- *
- * === Current-Process Setters
- *
- * - ::egid=: Sets the effective group ID.
- * - ::euid=: Sets the effective user ID.
- * - ::gid=: Sets the (real) group ID.
- * - ::setproctitle: Sets the process title.
- * - ::setpgrp: Sets the process group ID of the process to zero.
- * - ::setrlimit: Sets a resource limit.
- * - ::setsid: Establishes the process as a new session and process group leader,
- * with no controlling tty.
- * - ::uid=: Sets the user ID.
- *
- * === Current-Process Execution
- *
- * - ::abort: Immediately terminates the process.
- * - ::daemon: Detaches the process from its controlling terminal
- * and continues running it in the background as system daemon.
- * - ::exec: Replaces the process by running a given external command.
- * - ::exit: Initiates process termination by raising exception SystemExit
- * (which may be caught).
- * - ::exit!: Immediately exits the process.
- * - ::warmup: Notifies the Ruby virtual machine that the boot sequence
- * for the application is completed,
- * and that the VM may begin optimizing the application.
- *
- * === Child Processes
- *
- * - ::detach: Guards against a child process becoming a zombie.
- * - ::fork: Creates a child process.
- * - ::kill: Sends a given signal to processes.
- * - ::spawn: Creates a child process.
- * - ::wait, ::waitpid: Waits for a child process to exit; returns its process ID.
- * - ::wait2, ::waitpid2: Waits for a child process to exit; returns its process ID and status.
- * - ::waitall: Waits for all child processes to exit;
- * returns their process IDs and statuses.
- *
- * === \Process Groups
- *
- * - ::getpgid: Returns the process group ID for a process.
- * - ::getpriority: Returns the scheduling priority
- * for a process, process group, or user.
- * - ::getsid: Returns the session ID for a process.
- * - ::groups: Returns an array of the group IDs
- * in the supplemental group access list for this process.
- * - ::groups=: Sets the supplemental group access list
- * to the given array of group IDs.
- * - ::initgroups: Initializes the supplemental group access list.
- * - ::last_status: Returns the status of the last executed child process
- * in the current thread.
- * - ::maxgroups: Returns the maximum number of group IDs allowed
- * in the supplemental group access list.
- * - ::maxgroups=: Sets the maximum number of group IDs allowed
- * in the supplemental group access list.
- * - ::setpgid: Sets the process group ID of a process.
- * - ::setpriority: Sets the scheduling priority
- * for a process, process group, or user.
- *
- * === Timing
- *
- * - ::clock_getres: Returns the resolution of a system clock.
- * - ::clock_gettime: Returns the time from a system clock.
- * - ::times: Returns a Process::Tms object containing times
- * for the current process and its child processes.
- *
+ * The Process module is a collection of methods used to
+ * manipulate processes.
*/
void
@@ -9371,8 +8898,6 @@ InitVM_process(void)
rb_define_module_function(rb_mProcess, "getpriority", proc_getpriority, 2);
rb_define_module_function(rb_mProcess, "setpriority", proc_setpriority, 3);
- rb_define_module_function(rb_mProcess, "warmup", proc_warmup, 0);
-
#ifdef HAVE_GETPRIORITY
/* see Process.setpriority */
rb_define_const(rb_mProcess, "PRIO_PROCESS", INT2FIX(PRIO_PROCESS));
diff --git a/ractor.c b/ractor.c
index 9d34dd1b7d..8fb563fa11 100644
--- a/ractor.c
+++ b/ractor.c
@@ -5,22 +5,21 @@
#include "ruby/ractor.h"
#include "ruby/thread_native.h"
#include "vm_core.h"
-#include "eval_intern.h"
#include "vm_sync.h"
#include "ractor_core.h"
#include "internal/complex.h"
#include "internal/error.h"
-#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/rational.h"
#include "internal/struct.h"
#include "internal/thread.h"
#include "variable.h"
+#include "gc.h"
+#include "transient_heap.h"
#include "yjit.h"
-#include "rjit.h"
+#include "mjit.h"
VALUE rb_cRactor;
-static VALUE rb_cRactorSelector;
VALUE rb_eRactorUnsafeError;
VALUE rb_eRactorIsolationError;
@@ -32,13 +31,11 @@ static VALUE rb_cRactorMovedObject;
static void vm_ractor_blocking_cnt_inc(rb_vm_t *vm, rb_ractor_t *r, const char *file, int line);
-// Ractor locking
-
static void
ASSERT_ractor_unlocking(rb_ractor_t *r)
{
#if RACTOR_CHECK_MODE > 0
- // GET_EC is NULL in an RJIT worker
+ // GET_EC is NULL in an MJIT worker
if (rb_current_execution_context(false) != NULL && r->sync.locked_by == rb_ractor_self(GET_RACTOR())) {
rb_bug("recursive ractor locking");
}
@@ -49,7 +46,7 @@ static void
ASSERT_ractor_locking(rb_ractor_t *r)
{
#if RACTOR_CHECK_MODE > 0
- // GET_EC is NULL in an RJIT worker
+ // GET_EC is NULL in an MJIT worker
if (rb_current_execution_context(false) != NULL && r->sync.locked_by != rb_ractor_self(GET_RACTOR())) {
rp(r->sync.locked_by);
rb_bug("ractor lock is not acquired.");
@@ -60,19 +57,18 @@ ASSERT_ractor_locking(rb_ractor_t *r)
static void
ractor_lock(rb_ractor_t *r, const char *file, int line)
{
- RUBY_DEBUG_LOG2(file, line, "locking r:%u%s", r->pub.id, rb_current_ractor_raw(false) == r ? " (self)" : "");
+ RUBY_DEBUG_LOG2(file, line, "locking r:%u%s", r->pub.id, GET_RACTOR() == r ? " (self)" : "");
ASSERT_ractor_unlocking(r);
rb_native_mutex_lock(&r->sync.lock);
#if RACTOR_CHECK_MODE > 0
- if (rb_current_execution_context(false) != NULL) { // GET_EC is NULL in an RJIT worker
- rb_ractor_t *cr = rb_current_ractor_raw(false);
- r->sync.locked_by = cr ? rb_ractor_self(cr) : Qundef;
+ if (rb_current_execution_context(false) != NULL) { // GET_EC is NULL in an MJIT worker
+ r->sync.locked_by = rb_ractor_self(GET_RACTOR());
}
#endif
- RUBY_DEBUG_LOG2(file, line, "locked r:%u%s", r->pub.id, rb_current_ractor_raw(false) == r ? " (self)" : "");
+ RUBY_DEBUG_LOG2(file, line, "locked r:%u%s", r->pub.id, GET_RACTOR() == r ? " (self)" : "");
}
static void
@@ -94,7 +90,7 @@ ractor_unlock(rb_ractor_t *r, const char *file, int line)
#endif
rb_native_mutex_unlock(&r->sync.lock);
- RUBY_DEBUG_LOG2(file, line, "r:%u%s", r->pub.id, rb_current_ractor_raw(false) == r ? " (self)" : "");
+ RUBY_DEBUG_LOG2(file, line, "r:%u%s", r->pub.id, GET_RACTOR() == r ? " (self)" : "");
}
static void
@@ -112,20 +108,20 @@ ractor_unlock_self(rb_ractor_t *cr, const char *file, int line)
#define RACTOR_LOCK_SELF(r) ractor_lock_self(r, __FILE__, __LINE__)
#define RACTOR_UNLOCK_SELF(r) ractor_unlock_self(r, __FILE__, __LINE__)
-void
-rb_ractor_lock_self(rb_ractor_t *r)
+static void
+ractor_cond_wait(rb_ractor_t *r)
{
- RACTOR_LOCK_SELF(r);
-}
+#if RACTOR_CHECK_MODE > 0
+ VALUE locked_by = r->sync.locked_by;
+ r->sync.locked_by = Qnil;
+#endif
+ rb_native_cond_wait(&r->sync.cond, &r->sync.lock);
-void
-rb_ractor_unlock_self(rb_ractor_t *r)
-{
- RACTOR_UNLOCK_SELF(r);
+#if RACTOR_CHECK_MODE > 0
+ r->sync.locked_by = locked_by;
+#endif
}
-// Ractor status
-
static const char *
ractor_status_str(enum ractor_status status)
{
@@ -162,7 +158,7 @@ ractor_status_set(rb_ractor_t *r, enum ractor_status status)
VM_ASSERT(status == ractor_running);
break;
case ractor_terminated:
- rb_bug("unreachable");
+ VM_ASSERT(0); // unreachable
break;
}
@@ -175,40 +171,31 @@ ractor_status_p(rb_ractor_t *r, enum ractor_status status)
return rb_ractor_status_p(r, status);
}
-// Ractor data/mark/free
-
-static struct rb_ractor_basket *ractor_queue_at(rb_ractor_t *r, struct rb_ractor_queue *rq, int i);
-static void ractor_local_storage_mark(rb_ractor_t *r);
-static void ractor_local_storage_free(rb_ractor_t *r);
+static struct rb_ractor_basket *ractor_queue_at(struct rb_ractor_queue *rq, int i);
static void
ractor_queue_mark(struct rb_ractor_queue *rq)
{
for (int i=0; i<rq->cnt; i++) {
- struct rb_ractor_basket *b = ractor_queue_at(NULL, rq, i);
+ struct rb_ractor_basket *b = ractor_queue_at(rq, i);
+ rb_gc_mark(b->v);
rb_gc_mark(b->sender);
-
- switch (b->type.e) {
- case basket_type_yielding:
- case basket_type_take_basket:
- case basket_type_deleted:
- case basket_type_reserved:
- // ignore
- break;
- default:
- rb_gc_mark(b->p.send.v);
- }
}
}
+static void ractor_local_storage_mark(rb_ractor_t *r);
+static void ractor_local_storage_free(rb_ractor_t *r);
+
static void
ractor_mark(void *ptr)
{
rb_ractor_t *r = (rb_ractor_t *)ptr;
- ractor_queue_mark(&r->sync.recv_queue);
- ractor_queue_mark(&r->sync.takers_queue);
-
+ ractor_queue_mark(&r->sync.incoming_queue);
+ rb_gc_mark(r->sync.wait.taken_basket.v);
+ rb_gc_mark(r->sync.wait.taken_basket.sender);
+ rb_gc_mark(r->sync.wait.yielded_basket.v);
+ rb_gc_mark(r->sync.wait.yielded_basket.sender);
rb_gc_mark(r->receiving_mutex);
rb_gc_mark(r->loc);
@@ -236,26 +223,21 @@ ractor_queue_free(struct rb_ractor_queue *rq)
}
static void
+ractor_waiting_list_free(struct rb_ractor_waiting_list *wl)
+{
+ free(wl->ractors);
+}
+
+static void
ractor_free(void *ptr)
{
rb_ractor_t *r = (rb_ractor_t *)ptr;
- RUBY_DEBUG_LOG("free r:%d", rb_ractor_id(r));
rb_native_mutex_destroy(&r->sync.lock);
-#ifdef RUBY_THREAD_WIN32_H
rb_native_cond_destroy(&r->sync.cond);
-#endif
- ractor_queue_free(&r->sync.recv_queue);
- ractor_queue_free(&r->sync.takers_queue);
+ ractor_queue_free(&r->sync.incoming_queue);
+ ractor_waiting_list_free(&r->sync.taking_ractors);
ractor_local_storage_free(r);
rb_hook_list_free(&r->pub.hooks);
-
- if (r->newobj_cache) {
- RUBY_ASSERT(r == ruby_single_main_ractor);
-
- rb_gc_ractor_cache_free(r->newobj_cache);
- r->newobj_cache = NULL;
- }
-
ruby_xfree(r);
}
@@ -266,14 +248,20 @@ ractor_queue_memsize(const struct rb_ractor_queue *rq)
}
static size_t
+ractor_waiting_list_memsize(const struct rb_ractor_waiting_list *wl)
+{
+ return sizeof(rb_ractor_t *) * wl->size;
+}
+
+static size_t
ractor_memsize(const void *ptr)
{
rb_ractor_t *r = (rb_ractor_t *)ptr;
- // TODO: more correct?
+ // TODO
return sizeof(rb_ractor_t) +
- ractor_queue_memsize(&r->sync.recv_queue) +
- ractor_queue_memsize(&r->sync.takers_queue);
+ ractor_queue_memsize(&r->sync.incoming_queue) +
+ ractor_waiting_list_memsize(&r->sync.taking_ractors);
}
static const rb_data_type_t ractor_data_type = {
@@ -302,14 +290,16 @@ static inline rb_ractor_t *
RACTOR_PTR(VALUE self)
{
VM_ASSERT(rb_ractor_p(self));
+
rb_ractor_t *r = DATA_PTR(self);
+ // TODO: check
return r;
}
static rb_atomic_t ractor_last_id;
#if RACTOR_CHECK_MODE > 0
-uint32_t
+MJIT_FUNC_EXPORTED uint32_t
rb_ractor_current_id(void)
{
if (GET_THREAD()->ractor == NULL) {
@@ -321,8 +311,6 @@ rb_ractor_current_id(void)
}
#endif
-// Ractor queue
-
static void
ractor_queue_setup(struct rb_ractor_queue *rq)
{
@@ -333,23 +321,15 @@ ractor_queue_setup(struct rb_ractor_queue *rq)
}
static struct rb_ractor_basket *
-ractor_queue_head(rb_ractor_t *r, struct rb_ractor_queue *rq)
+ractor_queue_at(struct rb_ractor_queue *rq, int i)
{
- if (r != NULL) ASSERT_ractor_locking(r);
- return &rq->baskets[rq->start];
-}
-
-static struct rb_ractor_basket *
-ractor_queue_at(rb_ractor_t *r, struct rb_ractor_queue *rq, int i)
-{
- if (r != NULL) ASSERT_ractor_locking(r);
return &rq->baskets[(rq->start + i) % rq->size];
}
static void
-ractor_queue_advance(rb_ractor_t *r, struct rb_ractor_queue *rq)
+ractor_queue_advance(struct rb_ractor_queue *rq)
{
- ASSERT_ractor_locking(r);
+ ASSERT_ractor_locking(GET_RACTOR());
if (rq->reserved_cnt == 0) {
rq->cnt--;
@@ -357,16 +337,16 @@ ractor_queue_advance(rb_ractor_t *r, struct rb_ractor_queue *rq)
rq->serial++;
}
else {
- ractor_queue_at(r, rq, 0)->type.e = basket_type_deleted;
+ ractor_queue_at(rq, 0)->type = basket_type_deleted;
}
}
static bool
-ractor_queue_skip_p(rb_ractor_t *r, struct rb_ractor_queue *rq, int i)
+ractor_queue_skip_p(struct rb_ractor_queue *rq, int i)
{
- struct rb_ractor_basket *b = ractor_queue_at(r, rq, i);
- return basket_type_p(b, basket_type_deleted) ||
- basket_type_p(b, basket_type_reserved);
+ struct rb_ractor_basket *b = ractor_queue_at(rq, i);
+ return b->type == basket_type_deleted ||
+ b->type == basket_type_reserved;
}
static void
@@ -374,8 +354,8 @@ ractor_queue_compact(rb_ractor_t *r, struct rb_ractor_queue *rq)
{
ASSERT_ractor_locking(r);
- while (rq->cnt > 0 && basket_type_p(ractor_queue_at(r, rq, 0), basket_type_deleted)) {
- ractor_queue_advance(r, rq);
+ while (rq->cnt > 0 && ractor_queue_at(rq, 0)->type == basket_type_deleted) {
+ ractor_queue_advance(rq);
}
}
@@ -391,7 +371,7 @@ ractor_queue_empty_p(rb_ractor_t *r, struct rb_ractor_queue *rq)
ractor_queue_compact(r, rq);
for (int i=0; i<rq->cnt; i++) {
- if (!ractor_queue_skip_p(r, rq, i)) {
+ if (!ractor_queue_skip_p(rq, i)) {
return false;
}
}
@@ -402,21 +382,28 @@ ractor_queue_empty_p(rb_ractor_t *r, struct rb_ractor_queue *rq)
static bool
ractor_queue_deq(rb_ractor_t *r, struct rb_ractor_queue *rq, struct rb_ractor_basket *basket)
{
- ASSERT_ractor_locking(r);
-
- for (int i=0; i<rq->cnt; i++) {
- if (!ractor_queue_skip_p(r, rq, i)) {
- struct rb_ractor_basket *b = ractor_queue_at(r, rq, i);
- *basket = *b;
+ bool found = false;
- // remove from queue
- b->type.e = basket_type_deleted;
- ractor_queue_compact(r, rq);
- return true;
+ RACTOR_LOCK(r);
+ {
+ if (!ractor_queue_empty_p(r, rq)) {
+ for (int i=0; i<rq->cnt; i++) {
+ if (!ractor_queue_skip_p(rq, i)) {
+ struct rb_ractor_basket *b = ractor_queue_at(rq, i);
+ *basket = *b;
+
+ // remove from queue
+ b->type = basket_type_deleted;
+ ractor_queue_compact(r, rq);
+ found = true;
+ break;
+ }
+ }
}
}
+ RACTOR_UNLOCK(r);
- return false;
+ return found;
}
static void
@@ -436,32 +423,32 @@ ractor_queue_enq(rb_ractor_t *r, struct rb_ractor_queue *rq, struct rb_ractor_ba
}
static void
-ractor_queue_delete(rb_ractor_t *r, struct rb_ractor_queue *rq, struct rb_ractor_basket *basket)
+ractor_basket_clear(struct rb_ractor_basket *b)
{
- basket->type.e = basket_type_deleted;
+ b->type = basket_type_none;
+ b->v = Qfalse;
+ b->sender = Qfalse;
}
-// Ractor basket
-
static VALUE ractor_reset_belonging(VALUE obj); // in this file
static VALUE
ractor_basket_value(struct rb_ractor_basket *b)
{
- switch (b->type.e) {
+ switch (b->type) {
case basket_type_ref:
break;
case basket_type_copy:
case basket_type_move:
case basket_type_will:
- b->type.e = basket_type_ref;
- b->p.send.v = ractor_reset_belonging(b->p.send.v);
+ b->type = basket_type_ref;
+ b->v = ractor_reset_belonging(b->v);
break;
default:
rb_bug("unreachable");
}
- return b->p.send.v;
+ return b->v;
}
static VALUE
@@ -469,69 +456,46 @@ ractor_basket_accept(struct rb_ractor_basket *b)
{
VALUE v = ractor_basket_value(b);
- if (b->p.send.exception) {
+ if (b->exception) {
VALUE cause = v;
VALUE err = rb_exc_new_cstr(rb_eRactorRemoteError, "thrown by remote Ractor.");
rb_ivar_set(err, rb_intern("@ractor"), b->sender);
+ ractor_basket_clear(b);
rb_ec_setup_exception(NULL, err, cause);
rb_exc_raise(err);
}
+ ractor_basket_clear(b);
return v;
}
-// Ractor synchronizations
-
-#if USE_RUBY_DEBUG_LOG
-static const char *
-wait_status_str(enum rb_ractor_wait_status wait_status)
+static void
+ractor_recursive_receive_if(rb_ractor_t *r)
{
- switch ((int)wait_status) {
- case wait_none: return "none";
- case wait_receiving: return "receiving";
- case wait_taking: return "taking";
- case wait_yielding: return "yielding";
- case wait_receiving|wait_taking: return "receiving|taking";
- case wait_receiving|wait_yielding: return "receiving|yielding";
- case wait_taking|wait_yielding: return "taking|yielding";
- case wait_receiving|wait_taking|wait_yielding: return "receiving|taking|yielding";
+ if (r->receiving_mutex && rb_mutex_owned_p(r->receiving_mutex)) {
+ rb_raise(rb_eRactorError, "can not call receive/receive_if recursively");
}
- rb_bug("unreachable");
}
-static const char *
-wakeup_status_str(enum rb_ractor_wakeup_status wakeup_status)
+static VALUE
+ractor_try_receive(rb_execution_context_t *ec, rb_ractor_t *r)
{
- switch (wakeup_status) {
- case wakeup_none: return "none";
- case wakeup_by_send: return "by_send";
- case wakeup_by_yield: return "by_yield";
- case wakeup_by_take: return "by_take";
- case wakeup_by_close: return "by_close";
- case wakeup_by_interrupt: return "by_interrupt";
- case wakeup_by_retry: return "by_retry";
+ struct rb_ractor_queue *rq = &r->sync.incoming_queue;
+ struct rb_ractor_basket basket;
+
+ ractor_recursive_receive_if(r);
+
+ if (ractor_queue_deq(r, rq, &basket) == false) {
+ if (r->sync.incoming_port_closed) {
+ rb_raise(rb_eRactorClosedError, "The incoming port is already closed");
+ }
+ else {
+ return Qundef;
+ }
}
- rb_bug("unreachable");
-}
-static const char *
-basket_type_name(enum rb_ractor_basket_type type)
-{
- switch (type) {
- case basket_type_none: return "none";
- case basket_type_ref: return "ref";
- case basket_type_copy: return "copy";
- case basket_type_move: return "move";
- case basket_type_will: return "will";
- case basket_type_deleted: return "deleted";
- case basket_type_reserved: return "reserved";
- case basket_type_take_basket: return "take_basket";
- case basket_type_yielding: return "yielding";
- }
- VM_ASSERT(0);
- return NULL;
+ return ractor_basket_accept(&basket);
}
-#endif // USE_RUBY_DEBUG_LOG
static bool
ractor_sleeping_by(const rb_ractor_t *r, enum rb_ractor_wait_status wait_status)
@@ -539,33 +503,18 @@ ractor_sleeping_by(const rb_ractor_t *r, enum rb_ractor_wait_status wait_status)
return (r->sync.wait.status & wait_status) && r->sync.wait.wakeup_status == wakeup_none;
}
-#ifdef RUBY_THREAD_PTHREAD_H
-// thread_*.c
-void rb_ractor_sched_wakeup(rb_ractor_t *r);
-#else
-
-static void
-rb_ractor_sched_wakeup(rb_ractor_t *r)
-{
- rb_native_cond_broadcast(&r->sync.cond);
-}
-#endif
-
-
static bool
ractor_wakeup(rb_ractor_t *r, enum rb_ractor_wait_status wait_status, enum rb_ractor_wakeup_status wakeup_status)
{
ASSERT_ractor_locking(r);
- RUBY_DEBUG_LOG("r:%u wait_by:%s -> wait:%s wakeup:%s",
- rb_ractor_id(r),
- wait_status_str(r->sync.wait.status),
- wait_status_str(wait_status),
- wakeup_status_str(wakeup_status));
+ // fprintf(stderr, "%s r:%p status:%s/%s wakeup_status:%s/%s\n", RUBY_FUNCTION_NAME_STRING, (void *)r,
+ // wait_status_str(r->sync.wait.status), wait_status_str(wait_status),
+ // wakeup_status_str(r->sync.wait.wakeup_status), wakeup_status_str(wakeup_status));
if (ractor_sleeping_by(r, wait_status)) {
r->sync.wait.wakeup_status = wakeup_status;
- rb_ractor_sched_wakeup(r);
+ rb_native_cond_signal(&r->sync.cond);
return true;
}
else {
@@ -573,6 +522,22 @@ ractor_wakeup(rb_ractor_t *r, enum rb_ractor_wait_status wait_status, enum rb_ra
}
}
+static void *
+ractor_sleep_wo_gvl(void *ptr)
+{
+ rb_ractor_t *cr = ptr;
+ RACTOR_LOCK_SELF(cr);
+ {
+ VM_ASSERT(cr->sync.wait.status != wait_none);
+ if (cr->sync.wait.wakeup_status == wakeup_none) {
+ ractor_cond_wait(cr);
+ }
+ cr->sync.wait.status = wait_none;
+ }
+ RACTOR_UNLOCK_SELF(cr);
+ return NULL;
+}
+
static void
ractor_sleep_interrupt(void *ptr)
{
@@ -585,175 +550,174 @@ ractor_sleep_interrupt(void *ptr)
RACTOR_UNLOCK(r);
}
-typedef void (*ractor_sleep_cleanup_function)(rb_ractor_t *cr, void *p);
-
-static void
-ractor_check_ints(rb_execution_context_t *ec, rb_ractor_t *cr, ractor_sleep_cleanup_function cf_func, void *cf_data)
+#if USE_RUBY_DEBUG_LOG
+static const char *
+wait_status_str(enum rb_ractor_wait_status wait_status)
{
- if (cr->sync.wait.status != wait_none) {
- enum rb_ractor_wait_status prev_wait_status = cr->sync.wait.status;
- cr->sync.wait.status = wait_none;
- cr->sync.wait.wakeup_status = wakeup_by_interrupt;
-
- RACTOR_UNLOCK(cr);
- {
- if (cf_func) {
- enum ruby_tag_type state;
- EC_PUSH_TAG(ec);
- if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- rb_thread_check_ints();
- }
- EC_POP_TAG();
-
- if (state) {
- (*cf_func)(cr, cf_data);
- EC_JUMP_TAG(ec, state);
- }
- }
- else {
- rb_thread_check_ints();
- }
- }
-
- // reachable?
- RACTOR_LOCK(cr);
- cr->sync.wait.status = prev_wait_status;
+ switch ((int)wait_status) {
+ case wait_none: return "none";
+ case wait_receiving: return "receiving";
+ case wait_taking: return "taking";
+ case wait_yielding: return "yielding";
+ case wait_receiving|wait_taking: return "receiving|taking";
+ case wait_receiving|wait_yielding: return "receiving|yielding";
+ case wait_taking|wait_yielding: return "taking|yielding";
+ case wait_receiving|wait_taking|wait_yielding: return "receiving|taking|yielding";
}
+ rb_bug("unreachable");
}
-#ifdef RUBY_THREAD_PTHREAD_H
-void rb_ractor_sched_sleep(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_function_t *ubf);
-#else
-
-// win32
-static void
-ractor_cond_wait(rb_ractor_t *r)
-{
-#if RACTOR_CHECK_MODE > 0
- VALUE locked_by = r->sync.locked_by;
- r->sync.locked_by = Qnil;
-#endif
- rb_native_cond_wait(&r->sync.cond, &r->sync.lock);
-
-#if RACTOR_CHECK_MODE > 0
- r->sync.locked_by = locked_by;
-#endif
-}
-
-static void *
-ractor_sleep_wo_gvl(void *ptr)
+static const char *
+wakeup_status_str(enum rb_ractor_wakeup_status wakeup_status)
{
- rb_ractor_t *cr = ptr;
- RACTOR_LOCK_SELF(cr);
- {
- VM_ASSERT(cr->sync.wait.status != wait_none);
- if (cr->sync.wait.wakeup_status == wakeup_none) {
- ractor_cond_wait(cr);
- }
- cr->sync.wait.status = wait_none;
+ switch (wakeup_status) {
+ case wakeup_none: return "none";
+ case wakeup_by_send: return "by_send";
+ case wakeup_by_yield: return "by_yield";
+ case wakeup_by_take: return "by_take";
+ case wakeup_by_close: return "by_close";
+ case wakeup_by_interrupt: return "by_interrupt";
+ case wakeup_by_retry: return "by_retry";
}
- RACTOR_UNLOCK_SELF(cr);
- return NULL;
+ rb_bug("unreachable");
}
+#endif // USE_RUBY_DEBUG_LOG
static void
-rb_ractor_sched_sleep(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_function_t *ubf)
+ractor_sleep(rb_execution_context_t *ec, rb_ractor_t *cr)
{
+ VM_ASSERT(GET_RACTOR() == cr);
+ VM_ASSERT(cr->sync.wait.status != wait_none);
+ // fprintf(stderr, "%s r:%p status:%s, wakeup_status:%s\n", RUBY_FUNCTION_NAME_STRING, (void *)cr,
+ // wait_status_str(cr->sync.wait.status), wakeup_status_str(cr->sync.wait.wakeup_status));
+
RACTOR_UNLOCK(cr);
{
rb_nogvl(ractor_sleep_wo_gvl, cr,
- ubf, cr,
+ ractor_sleep_interrupt, cr,
RB_NOGVL_UBF_ASYNC_SAFE | RB_NOGVL_INTR_FAIL);
}
RACTOR_LOCK(cr);
-}
-#endif
-
-static enum rb_ractor_wakeup_status
-ractor_sleep_with_cleanup(rb_execution_context_t *ec, rb_ractor_t *cr, enum rb_ractor_wait_status wait_status,
- ractor_sleep_cleanup_function cf_func, void *cf_data)
-{
- enum rb_ractor_wakeup_status wakeup_status;
- VM_ASSERT(GET_RACTOR() == cr);
-
- // TODO: multi-threads
- VM_ASSERT(cr->sync.wait.status == wait_none);
- VM_ASSERT(wait_status != wait_none);
- cr->sync.wait.status = wait_status;
- cr->sync.wait.wakeup_status = wakeup_none;
-
- // fprintf(stderr, "%s r:%p status:%s, wakeup_status:%s\n", RUBY_FUNCTION_NAME_STRING, (void *)cr,
- // wait_status_str(cr->sync.wait.status), wakeup_status_str(cr->sync.wait.wakeup_status));
- RUBY_DEBUG_LOG("sleep by %s", wait_status_str(wait_status));
+ // rb_nogvl() can be canceled by interrupts
+ if (cr->sync.wait.status != wait_none) {
+ cr->sync.wait.status = wait_none;
+ cr->sync.wait.wakeup_status = wakeup_by_interrupt;
- while (cr->sync.wait.wakeup_status == wakeup_none) {
- rb_ractor_sched_sleep(ec, cr, ractor_sleep_interrupt);
- ractor_check_ints(ec, cr, cf_func, cf_data);
+ RACTOR_UNLOCK(cr);
+ rb_thread_check_ints();
+ RACTOR_LOCK(cr); // reachable?
}
+}
- cr->sync.wait.status = wait_none;
+static void
+ractor_register_taking(rb_ractor_t *r, rb_ractor_t *cr)
+{
+ VM_ASSERT(cr == GET_RACTOR());
+ bool retry_try = false;
- // TODO: multi-thread
- wakeup_status = cr->sync.wait.wakeup_status;
- cr->sync.wait.wakeup_status = wakeup_none;
+ RACTOR_LOCK(r);
+ {
+ if (ractor_sleeping_by(r, wait_yielding)) {
+ // already waiting for yielding. retry try_take.
+ retry_try = true;
+ }
+ else {
+ // insert cr into taking list
+ struct rb_ractor_waiting_list *wl = &r->sync.taking_ractors;
+
+ for (int i=0; i<wl->cnt; i++) {
+ if (wl->ractors[i] == cr) {
+ // TODO: make it clean code.
+ rb_native_mutex_unlock(&r->sync.lock);
+ rb_raise(rb_eRuntimeError, "Already another thread of same ractor is waiting.");
+ }
+ }
- RUBY_DEBUG_LOG("wakeup %s", wakeup_status_str(wakeup_status));
+ if (wl->size == 0) {
+ wl->size = 1;
+ wl->ractors = malloc(sizeof(rb_ractor_t *) * wl->size);
+ if (wl->ractors == NULL) rb_bug("can't allocate buffer");
+ }
+ else if (wl->size <= wl->cnt + 1) {
+ wl->size *= 2;
+ wl->ractors = realloc(wl->ractors, sizeof(rb_ractor_t *) * wl->size);
+ if (wl->ractors == NULL) rb_bug("can't re-allocate buffer");
+ }
+ wl->ractors[wl->cnt++] = cr;
+ }
+ }
+ RACTOR_UNLOCK(r);
- return wakeup_status;
-}
+ if (retry_try) {
+ RACTOR_LOCK(cr);
+ {
+ if (cr->sync.wait.wakeup_status == wakeup_none) {
+ VM_ASSERT(cr->sync.wait.status != wait_none);
-static enum rb_ractor_wakeup_status
-ractor_sleep(rb_execution_context_t *ec, rb_ractor_t *cr, enum rb_ractor_wait_status wait_status)
-{
- return ractor_sleep_with_cleanup(ec, cr, wait_status, 0, NULL);
+ cr->sync.wait.wakeup_status = wakeup_by_retry;
+ cr->sync.wait.status = wait_none;
+ }
+ }
+ RACTOR_UNLOCK(cr);
+ }
}
-// Ractor.receive
-
static void
-ractor_recursive_receive_if(rb_ractor_t *r)
+ractor_waiting_list_del(rb_ractor_t *r, struct rb_ractor_waiting_list *wl, rb_ractor_t *wr)
{
- if (r->receiving_mutex && rb_mutex_owned_p(r->receiving_mutex)) {
- rb_raise(rb_eRactorError, "can not call receive/receive_if recursively");
+ RACTOR_LOCK(r);
+ {
+ int pos = -1;
+ for (int i=0; i<wl->cnt; i++) {
+ if (wl->ractors[i] == wr) {
+ pos = i;
+ break;
+ }
+ }
+ if (pos >= 0) { // found
+ wl->cnt--;
+ for (int i=pos; i<wl->cnt; i++) {
+ wl->ractors[i] = wl->ractors[i+1];
+ }
+ }
}
+ RACTOR_UNLOCK(r);
}
-static VALUE
-ractor_try_receive(rb_execution_context_t *ec, rb_ractor_t *cr, struct rb_ractor_queue *rq)
+static rb_ractor_t *
+ractor_waiting_list_shift(rb_ractor_t *r, struct rb_ractor_waiting_list *wl)
{
- struct rb_ractor_basket basket;
- ractor_recursive_receive_if(cr);
- bool received = false;
-
- RACTOR_LOCK_SELF(cr);
- {
- RUBY_DEBUG_LOG("rq->cnt:%d", rq->cnt);
- received = ractor_queue_deq(cr, rq, &basket);
- }
- RACTOR_UNLOCK_SELF(cr);
+ ASSERT_ractor_locking(r);
+ VM_ASSERT(&r->sync.taking_ractors == wl);
- if (!received) {
- if (cr->sync.incoming_port_closed) {
- rb_raise(rb_eRactorClosedError, "The incoming port is already closed");
+ if (wl->cnt > 0) {
+ rb_ractor_t *tr = wl->ractors[0];
+ for (int i=1; i<wl->cnt; i++) {
+ wl->ractors[i-1] = wl->ractors[i];
}
- return Qundef;
+ wl->cnt--;
+ return tr;
}
else {
- return ractor_basket_accept(&basket);
+ return NULL;
}
}
static void
-ractor_wait_receive(rb_execution_context_t *ec, rb_ractor_t *cr, struct rb_ractor_queue *rq)
+ractor_receive_wait(rb_execution_context_t *ec, rb_ractor_t *cr)
{
VM_ASSERT(cr == rb_ec_ractor_ptr(ec));
ractor_recursive_receive_if(cr);
RACTOR_LOCK(cr);
{
- while (ractor_queue_empty_p(cr, rq)) {
- ractor_sleep(ec, cr, wait_receiving);
+ if (ractor_queue_empty_p(cr, &cr->sync.incoming_queue)) {
+ VM_ASSERT(cr->sync.wait.status == wait_none);
+ cr->sync.wait.status = wait_receiving;
+ cr->sync.wait.wakeup_status = wakeup_none;
+ ractor_sleep(ec, cr);
+ cr->sync.wait.wakeup_status = wakeup_none;
}
}
RACTOR_UNLOCK(cr);
@@ -764,25 +728,41 @@ ractor_receive(rb_execution_context_t *ec, rb_ractor_t *cr)
{
VM_ASSERT(cr == rb_ec_ractor_ptr(ec));
VALUE v;
- struct rb_ractor_queue *rq = &cr->sync.recv_queue;
- while (UNDEF_P(v = ractor_try_receive(ec, cr, rq))) {
- ractor_wait_receive(ec, cr, rq);
+ while (UNDEF_P(v = ractor_try_receive(ec, cr))) {
+ ractor_receive_wait(ec, cr);
}
return v;
}
#if 0
+// for debug
+static const char *
+basket_type_name(enum rb_ractor_basket_type type)
+{
+ switch (type) {
+#define T(t) case basket_type_##t: return #t
+ T(none);
+ T(ref);
+ T(copy);
+ T(move);
+ T(will);
+ T(deleted);
+ T(reserved);
+ default: rb_bug("unreachable");
+ }
+}
+
static void
rq_dump(struct rb_ractor_queue *rq)
{
bool bug = false;
for (int i=0; i<rq->cnt; i++) {
- struct rb_ractor_basket *b = ractor_queue_at(NULL, rq, i);
+ struct rb_ractor_basket *b = ractor_queue_at(rq, i);
fprintf(stderr, "%d (start:%d) type:%s %p %s\n", i, rq->start, basket_type_name(b->type),
(void *)b, RSTRING_PTR(RARRAY_AREF(b->v, 1)));
- if (basket_type_p(b, basket_type_reserved) bug = true;
+ if (b->type == basket_type_reserved) bug = true;
}
if (bug) rb_bug("!!");
}
@@ -813,23 +793,22 @@ receive_if_body(VALUE ptr)
ractor_receive_if_lock(data->cr);
VALUE block_result = rb_yield(data->v);
- rb_ractor_t *cr = data->cr;
- RACTOR_LOCK_SELF(cr);
+ RACTOR_LOCK_SELF(data->cr);
{
- struct rb_ractor_basket *b = ractor_queue_at(cr, data->rq, data->index);
- VM_ASSERT(basket_type_p(b, basket_type_reserved));
+ struct rb_ractor_basket *b = ractor_queue_at(data->rq, data->index);
+ VM_ASSERT(b->type == basket_type_reserved);
data->rq->reserved_cnt--;
if (RTEST(block_result)) {
- ractor_queue_delete(cr, data->rq, b);
- ractor_queue_compact(cr, data->rq);
+ b->type = basket_type_deleted;
+ ractor_queue_compact(data->cr, data->rq);
}
else {
- b->type.e = basket_type_ref;
+ b->type = basket_type_ref;
}
}
- RACTOR_UNLOCK_SELF(cr);
+ RACTOR_UNLOCK_SELF(data->cr);
data->success = true;
@@ -845,20 +824,19 @@ static VALUE
receive_if_ensure(VALUE v)
{
struct receive_block_data *data = (struct receive_block_data *)v;
- rb_ractor_t *cr = data->cr;
if (!data->success) {
- RACTOR_LOCK_SELF(cr);
+ RACTOR_LOCK_SELF(data->cr);
{
- struct rb_ractor_basket *b = ractor_queue_at(cr, data->rq, data->index);
- VM_ASSERT(basket_type_p(b, basket_type_reserved));
- b->type.e = basket_type_deleted;
+ struct rb_ractor_basket *b = ractor_queue_at(data->rq, data->index);
+ VM_ASSERT(b->type == basket_type_reserved);
+ b->type = basket_type_deleted;
data->rq->reserved_cnt--;
}
- RACTOR_UNLOCK_SELF(cr);
+ RACTOR_UNLOCK_SELF(data->cr);
}
- rb_mutex_unlock(cr->receiving_mutex);
+ rb_mutex_unlock(data->cr->receiving_mutex);
return Qnil;
}
@@ -870,12 +848,12 @@ ractor_receive_if(rb_execution_context_t *ec, VALUE crv, VALUE b)
rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
unsigned int serial = (unsigned int)-1;
int index = 0;
- struct rb_ractor_queue *rq = &cr->sync.recv_queue;
+ struct rb_ractor_queue *rq = &cr->sync.incoming_queue;
while (1) {
VALUE v = Qundef;
- ractor_wait_receive(ec, cr, rq);
+ ractor_receive_wait(ec, cr);
RACTOR_LOCK_SELF(cr);
{
@@ -886,10 +864,10 @@ ractor_receive_if(rb_execution_context_t *ec, VALUE crv, VALUE b)
// check newer version
for (int i=index; i<rq->cnt; i++) {
- if (!ractor_queue_skip_p(cr, rq, i)) {
- struct rb_ractor_basket *b = ractor_queue_at(cr, rq, i);
+ if (!ractor_queue_skip_p(rq, i)) {
+ struct rb_ractor_basket *b = ractor_queue_at(rq, i);
v = ractor_basket_value(b);
- b->type.e = basket_type_reserved;
+ b->type = basket_type_reserved;
rq->reserved_cnt++;
index = i;
break;
@@ -922,6 +900,7 @@ static void
ractor_send_basket(rb_execution_context_t *ec, rb_ractor_t *r, struct rb_ractor_basket *b)
{
bool closed = false;
+ struct rb_ractor_queue *rq = &r->sync.incoming_queue;
RACTOR_LOCK(r);
{
@@ -929,8 +908,10 @@ ractor_send_basket(rb_execution_context_t *ec, rb_ractor_t *r, struct rb_ractor_
closed = true;
}
else {
- ractor_queue_enq(r, &r->sync.recv_queue, b);
- ractor_wakeup(r, wait_receiving, wakeup_by_send);
+ ractor_queue_enq(r, rq, b);
+ if (ractor_wakeup(r, wait_receiving, wakeup_by_send)) {
+ RUBY_DEBUG_LOG("wakeup");
+ }
}
}
RACTOR_UNLOCK(r);
@@ -940,896 +921,430 @@ ractor_send_basket(rb_execution_context_t *ec, rb_ractor_t *r, struct rb_ractor_
}
}
-// Ractor#send
-
static VALUE ractor_move(VALUE obj); // in this file
static VALUE ractor_copy(VALUE obj); // in this file
static void
-ractor_basket_prepare_contents(VALUE obj, VALUE move, volatile VALUE *pobj, enum rb_ractor_basket_type *ptype)
+ractor_basket_setup(rb_execution_context_t *ec, struct rb_ractor_basket *basket, VALUE obj, VALUE move, bool exc, bool is_will, bool is_yield)
{
- VALUE v;
- enum rb_ractor_basket_type type;
+ basket->sender = rb_ec_ractor_ptr(ec)->pub.self;
+ basket->exception = exc;
- if (rb_ractor_shareable_p(obj)) {
- type = basket_type_ref;
- v = obj;
+ if (is_will) {
+ basket->type = basket_type_will;
+ basket->v = obj;
+ }
+ else if (rb_ractor_shareable_p(obj)) {
+ basket->type = basket_type_ref;
+ basket->v = obj;
}
else if (!RTEST(move)) {
- v = ractor_copy(obj);
- type = basket_type_copy;
+ basket->v = ractor_copy(obj);
+ basket->type = basket_type_copy;
}
else {
- type = basket_type_move;
- v = ractor_move(obj);
- }
+ basket->type = basket_type_move;
- *pobj = v;
- *ptype = type;
-}
-
-static void
-ractor_basket_fill_(rb_ractor_t *cr, struct rb_ractor_basket *basket, VALUE obj, bool exc)
-{
- VM_ASSERT(cr == GET_RACTOR());
-
- basket->sender = cr->pub.self;
- basket->p.send.exception = exc;
- basket->p.send.v = obj;
-}
-
-static void
-ractor_basket_fill(rb_ractor_t *cr, struct rb_ractor_basket *basket, VALUE obj, VALUE move, bool exc)
-{
- VALUE v;
- enum rb_ractor_basket_type type;
- ractor_basket_prepare_contents(obj, move, &v, &type);
- ractor_basket_fill_(cr, basket, v, exc);
- basket->type.e = type;
-}
-
-static void
-ractor_basket_fill_will(rb_ractor_t *cr, struct rb_ractor_basket *basket, VALUE obj, bool exc)
-{
- ractor_basket_fill_(cr, basket, obj, exc);
- basket->type.e = basket_type_will;
+ if (is_yield) {
+ basket->v = obj; // call ractor_move() when yielding timing.
+ }
+ else {
+ basket->v = ractor_move(obj);
+ }
+ }
}
static VALUE
ractor_send(rb_execution_context_t *ec, rb_ractor_t *r, VALUE obj, VALUE move)
{
struct rb_ractor_basket basket;
- // TODO: Ractor local GC
- ractor_basket_fill(rb_ec_ractor_ptr(ec), &basket, obj, move, false);
+ ractor_basket_setup(ec, &basket, obj, move, false, false, false);
ractor_send_basket(ec, r, &basket);
return r->pub.self;
}
-// Ractor#take
-
-static bool
-ractor_take_has_will(rb_ractor_t *r)
-{
- ASSERT_ractor_locking(r);
-
- return basket_type_p(&r->sync.will_basket, basket_type_will);
-}
-
-static bool
-ractor_take_will(rb_ractor_t *r, struct rb_ractor_basket *b)
-{
- ASSERT_ractor_locking(r);
-
- if (ractor_take_has_will(r)) {
- *b = r->sync.will_basket;
- r->sync.will_basket.type.e = basket_type_none;
- return true;
- }
- else {
- VM_ASSERT(basket_type_p(&r->sync.will_basket, basket_type_none));
- return false;
- }
-}
-
-static bool
-ractor_take_will_lock(rb_ractor_t *r, struct rb_ractor_basket *b)
+static VALUE
+ractor_try_take(rb_execution_context_t *ec, rb_ractor_t *r)
{
- ASSERT_ractor_unlocking(r);
- bool taken;
-
- RACTOR_LOCK(r);
- {
- taken = ractor_take_will(r, b);
- }
- RACTOR_UNLOCK(r);
-
- return taken;
-}
-
-static bool
-ractor_register_take(rb_ractor_t *cr, rb_ractor_t *r, struct rb_ractor_basket *take_basket,
- bool is_take, struct rb_ractor_selector_take_config *config, bool ignore_error)
-{
- struct rb_ractor_basket b = {
- .type.e = basket_type_take_basket,
- .sender = cr->pub.self,
- .p = {
- .take = {
- .basket = take_basket,
- .config = config,
- },
- },
+ struct rb_ractor_basket basket = {
+ .type = basket_type_none,
};
bool closed = false;
RACTOR_LOCK(r);
{
- if (is_take && ractor_take_will(r, take_basket)) {
- RUBY_DEBUG_LOG("take over a will of r:%d", rb_ractor_id(r));
- }
- else if (!is_take && ractor_take_has_will(r)) {
- RUBY_DEBUG_LOG("has_will");
- VM_ASSERT(config != NULL);
- config->closed = true;
+ if (ractor_sleeping_by(r, wait_yielding)) {
+ MAYBE_UNUSED(bool) wakeup_result;
+ VM_ASSERT(r->sync.wait.yielded_basket.type != basket_type_none);
+
+ if (r->sync.wait.yielded_basket.type == basket_type_move) {
+ wakeup_result = ractor_wakeup(r, wait_yielding, wakeup_by_retry);
+ }
+ else {
+ wakeup_result = ractor_wakeup(r, wait_yielding, wakeup_by_take);
+ basket = r->sync.wait.yielded_basket;
+ ractor_basket_clear(&r->sync.wait.yielded_basket);
+ }
+ VM_ASSERT(wakeup_result);
}
else if (r->sync.outgoing_port_closed) {
closed = true;
}
- else {
- RUBY_DEBUG_LOG("register in r:%d", rb_ractor_id(r));
- ractor_queue_enq(r, &r->sync.takers_queue, &b);
-
- if (basket_none_p(take_basket)) {
- ractor_wakeup(r, wait_yielding, wakeup_by_take);
- }
- }
}
RACTOR_UNLOCK(r);
- if (closed) {
- if (!ignore_error) rb_raise(rb_eRactorClosedError, "The outgoing-port is already closed");
- return false;
- }
- else {
- return true;
- }
-}
-
-static bool
-ractor_deregister_take(rb_ractor_t *r, struct rb_ractor_basket *take_basket)
-{
- struct rb_ractor_queue *ts = &r->sync.takers_queue;
- bool deleted = false;
-
- RACTOR_LOCK(r);
- {
- if (r->sync.outgoing_port_closed) {
- // ok
+ if (basket.type == basket_type_none) {
+ if (closed) {
+ rb_raise(rb_eRactorClosedError, "The outgoing-port is already closed");
}
else {
- for (int i=0; i<ts->cnt; i++) {
- struct rb_ractor_basket *b = ractor_queue_at(r, ts, i);
- if (basket_type_p(b, basket_type_take_basket) && b->p.take.basket == take_basket) {
- ractor_queue_delete(r, ts, b);
- deleted = true;
- }
- }
- if (deleted) {
- ractor_queue_compact(r, ts);
- }
+ return Qundef;
}
}
- RACTOR_UNLOCK(r);
-
- return deleted;
+ else {
+ return ractor_basket_accept(&basket);
+ }
}
static VALUE
-ractor_try_take(rb_ractor_t *cr, rb_ractor_t *r, struct rb_ractor_basket *take_basket)
+ractor_yield_move_body(VALUE v)
{
- bool taken;
-
- RACTOR_LOCK_SELF(cr);
- {
- if (basket_none_p(take_basket) || basket_type_p(take_basket, basket_type_yielding)) {
- taken = false;
- }
- else {
- taken = true;
- }
- }
- RACTOR_UNLOCK_SELF(cr);
-
- if (taken) {
- RUBY_DEBUG_LOG("taken");
- if (basket_type_p(take_basket, basket_type_deleted)) {
- VM_ASSERT(r->sync.outgoing_port_closed);
- rb_raise(rb_eRactorClosedError, "The outgoing-port is already closed");
- }
- return ractor_basket_accept(take_basket);
- }
- else {
- RUBY_DEBUG_LOG("not taken");
- return Qundef;
- }
+ return ractor_move(v);
}
-
-#if VM_CHECK_MODE > 0
static bool
-ractor_check_specific_take_basket_lock(rb_ractor_t *r, struct rb_ractor_basket *tb)
+ractor_try_yield(rb_execution_context_t *ec, rb_ractor_t *cr, struct rb_ractor_basket *basket)
{
- bool ret = false;
- struct rb_ractor_queue *ts = &r->sync.takers_queue;
+ ASSERT_ractor_unlocking(cr);
+ VM_ASSERT(basket->type != basket_type_none);
- RACTOR_LOCK(r);
- {
- for (int i=0; i<ts->cnt; i++) {
- struct rb_ractor_basket *b = ractor_queue_at(r, ts, i);
- if (basket_type_p(b, basket_type_take_basket) && b->p.take.basket == tb) {
- ret = true;
- break;
- }
- }
+ if (cr->sync.outgoing_port_closed) {
+ rb_raise(rb_eRactorClosedError, "The outgoing-port is already closed");
}
- RACTOR_UNLOCK(r);
- return ret;
-}
-#endif
-
-static void
-ractor_take_cleanup(rb_ractor_t *cr, rb_ractor_t *r, struct rb_ractor_basket *tb)
-{
- retry:
- if (basket_none_p(tb)) { // not yielded yet
- if (!ractor_deregister_take(r, tb)) {
- // not in r's takers queue
- rb_thread_sleep(0);
- goto retry;
- }
- }
- else {
- VM_ASSERT(!ractor_check_specific_take_basket_lock(r, tb));
- }
-}
-
-struct take_wait_take_cleanup_data {
rb_ractor_t *r;
- struct rb_ractor_basket *tb;
-};
-static void
-ractor_wait_take_cleanup(rb_ractor_t *cr, void *ptr)
-{
- struct take_wait_take_cleanup_data *data = (struct take_wait_take_cleanup_data *)ptr;
- ractor_take_cleanup(cr, data->r, data->tb);
-}
-
-static void
-ractor_wait_take(rb_execution_context_t *ec, rb_ractor_t *cr, rb_ractor_t *r, struct rb_ractor_basket *take_basket)
-{
- struct take_wait_take_cleanup_data data = {
- .r = r,
- .tb = take_basket,
- };
-
- RACTOR_LOCK_SELF(cr);
+ retry_shift:
+ RACTOR_LOCK(cr);
{
- if (basket_none_p(take_basket) || basket_type_p(take_basket, basket_type_yielding)) {
- ractor_sleep_with_cleanup(ec, cr, wait_taking, ractor_wait_take_cleanup, &data);
- }
- }
- RACTOR_UNLOCK_SELF(cr);
-}
-
-static VALUE
-ractor_take(rb_execution_context_t *ec, rb_ractor_t *r)
-{
- RUBY_DEBUG_LOG("from r:%u", rb_ractor_id(r));
- VALUE v;
- rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
-
- struct rb_ractor_basket take_basket = {
- .type.e = basket_type_none,
- .sender = 0,
- };
-
- ractor_register_take(cr, r, &take_basket, true, NULL, false);
-
- while (UNDEF_P(v = ractor_try_take(cr, r, &take_basket))) {
- ractor_wait_take(ec, cr, r, &take_basket);
+ r = ractor_waiting_list_shift(cr, &cr->sync.taking_ractors);
}
+ RACTOR_UNLOCK(cr);
- VM_ASSERT(!basket_none_p(&take_basket));
- VM_ASSERT(!ractor_check_specific_take_basket_lock(r, &take_basket));
-
- return v;
-}
-
-// Ractor.yield
-
-static bool
-ractor_check_take_basket(rb_ractor_t *cr, struct rb_ractor_queue *rs)
-{
- ASSERT_ractor_locking(cr);
-
- for (int i=0; i<rs->cnt; i++) {
- struct rb_ractor_basket *b = ractor_queue_at(cr, rs, i);
- if (basket_type_p(b, basket_type_take_basket) &&
- basket_none_p(b->p.take.basket)) {
- return true;
- }
- }
-
- return false;
-}
-
-static bool
-ractor_deq_take_basket(rb_ractor_t *cr, struct rb_ractor_queue *rs, struct rb_ractor_basket *b)
-{
- ASSERT_ractor_unlocking(cr);
- struct rb_ractor_basket *first_tb = NULL;
- bool found = false;
+ if (r) {
+ bool retry_shift = false;
- RACTOR_LOCK_SELF(cr);
- {
- while (ractor_queue_deq(cr, rs, b)) {
- if (basket_type_p(b, basket_type_take_basket)) {
- struct rb_ractor_basket *tb = b->p.take.basket;
+ RACTOR_LOCK(r);
+ {
+ if (ractor_sleeping_by(r, wait_taking)) {
+ VM_ASSERT(r->sync.wait.taken_basket.type == basket_type_none);
+
+ if (basket->type == basket_type_move) {
+ enum rb_ractor_wait_status prev_wait_status = r->sync.wait.status;
+ r->sync.wait.status = wait_moving;
+
+ RACTOR_UNLOCK(r);
+ {
+ int state;
+ VALUE moved_value = rb_protect(ractor_yield_move_body, basket->v, &state);
+ if (state) {
+ r->sync.wait.status = prev_wait_status;
+ rb_jump_tag(state);
+ }
+ else {
+ basket->v = moved_value;
+ }
+ }
+ RACTOR_LOCK(r);
- if (RUBY_ATOMIC_CAS(tb->type.atomic, basket_type_none, basket_type_yielding) == basket_type_none) {
- found = true;
- break;
+ if (!ractor_wakeup(r, wait_moving, wakeup_by_yield)) {
+ // terminating?
+ }
}
else {
- ractor_queue_enq(cr, rs, b);
- if (first_tb == NULL) first_tb = tb;
- struct rb_ractor_basket *head = ractor_queue_head(cr, rs);
- VM_ASSERT(head != NULL);
- if (basket_type_p(head, basket_type_take_basket) && head->p.take.basket == first_tb) {
- break; // loop detected
- }
+ ractor_wakeup(r, wait_taking, wakeup_by_yield);
}
+ r->sync.wait.taken_basket = *basket;
}
else {
- VM_ASSERT(basket_none_p(b));
+ retry_shift = true;
}
}
+ RACTOR_UNLOCK(r);
- if (found && b->p.take.config && !b->p.take.config->oneshot) {
- ractor_queue_enq(cr, rs, b);
- }
- }
- RACTOR_UNLOCK_SELF(cr);
-
- return found;
-}
-
-static bool
-ractor_try_yield(rb_execution_context_t *ec, rb_ractor_t *cr, struct rb_ractor_queue *ts, volatile VALUE obj, VALUE move, bool exc, bool is_will)
-{
- ASSERT_ractor_unlocking(cr);
-
- struct rb_ractor_basket b;
-
- if (ractor_deq_take_basket(cr, ts, &b)) {
- VM_ASSERT(basket_type_p(&b, basket_type_take_basket));
- VM_ASSERT(basket_type_p(b.p.take.basket, basket_type_yielding));
-
- rb_ractor_t *tr = RACTOR_PTR(b.sender);
- struct rb_ractor_basket *tb = b.p.take.basket;
- enum rb_ractor_basket_type type;
-
- RUBY_DEBUG_LOG("basket from r:%u", rb_ractor_id(tr));
-
- if (is_will) {
- type = basket_type_will;
+ if (retry_shift) {
+ // get candidate take-waiting ractor, but already woke up by another reason.
+ // retry to check another ractor.
+ goto retry_shift;
}
else {
- enum ruby_tag_type state;
-
- // begin
- EC_PUSH_TAG(ec);
- if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- // TODO: Ractor local GC
- ractor_basket_prepare_contents(obj, move, &obj, &type);
- }
- EC_POP_TAG();
- // rescue
- if (state) {
- RACTOR_LOCK_SELF(cr);
- {
- b.p.take.basket->type.e = basket_type_none;
- ractor_queue_enq(cr, ts, &b);
- }
- RACTOR_UNLOCK_SELF(cr);
- EC_JUMP_TAG(ec, state);
- }
- }
-
- RACTOR_LOCK(tr);
- {
- VM_ASSERT(basket_type_p(tb, basket_type_yielding));
- // fill atomic
- RUBY_DEBUG_LOG("fill %sbasket from r:%u", is_will ? "will " : "", rb_ractor_id(tr));
- ractor_basket_fill_(cr, tb, obj, exc);
- if (RUBY_ATOMIC_CAS(tb->type.atomic, basket_type_yielding, type) != basket_type_yielding) {
- rb_bug("unreachable");
- }
- ractor_wakeup(tr, wait_taking, wakeup_by_yield);
+ return true;
}
- RACTOR_UNLOCK(tr);
-
- return true;
}
else {
- RUBY_DEBUG_LOG("no take basket");
return false;
}
}
-static void
-ractor_wait_yield(rb_execution_context_t *ec, rb_ractor_t *cr, struct rb_ractor_queue *ts)
-{
- RACTOR_LOCK_SELF(cr);
- {
- while (!ractor_check_take_basket(cr, ts)) {
- ractor_sleep(ec, cr, wait_yielding);
- }
- }
- RACTOR_UNLOCK_SELF(cr);
-}
-
-static VALUE
-ractor_yield(rb_execution_context_t *ec, rb_ractor_t *cr, VALUE obj, VALUE move)
-{
- struct rb_ractor_queue *ts = &cr->sync.takers_queue;
-
- while (!ractor_try_yield(ec, cr, ts, obj, move, false, false)) {
- ractor_wait_yield(ec, cr, ts);
- }
-
- return Qnil;
-}
-
-// Ractor::Selector
-
-struct rb_ractor_selector {
- rb_ractor_t *r;
- struct rb_ractor_basket take_basket;
- st_table *take_ractors; // rb_ractor_t * => (struct rb_ractor_selector_take_config *)
-};
-
-static int
-ractor_selector_mark_ractors_i(st_data_t key, st_data_t value, st_data_t data)
-{
- const rb_ractor_t *r = (rb_ractor_t *)key;
- rb_gc_mark(r->pub.self);
- return ST_CONTINUE;
-}
-
-static void
-ractor_selector_mark(void *ptr)
-{
- struct rb_ractor_selector *s = ptr;
-
- if (s->take_ractors) {
- st_foreach(s->take_ractors, ractor_selector_mark_ractors_i, 0);
- }
-
- switch (s->take_basket.type.e) {
- case basket_type_ref:
- case basket_type_copy:
- case basket_type_move:
- case basket_type_will:
- rb_gc_mark(s->take_basket.sender);
- rb_gc_mark(s->take_basket.p.send.v);
- break;
- default:
- break;
- }
-}
-
-static int
-ractor_selector_release_i(st_data_t key, st_data_t val, st_data_t data)
-{
- struct rb_ractor_selector *s = (struct rb_ractor_selector *)data;
- struct rb_ractor_selector_take_config *config = (struct rb_ractor_selector_take_config *)val;
-
- if (!config->closed) {
- ractor_deregister_take((rb_ractor_t *)key, &s->take_basket);
- }
- free(config);
- return ST_CONTINUE;
-}
-
-static void
-ractor_selector_free(void *ptr)
-{
- struct rb_ractor_selector *s = ptr;
- st_foreach(s->take_ractors, ractor_selector_release_i, (st_data_t)s);
- st_free_table(s->take_ractors);
- ruby_xfree(ptr);
-}
-
-static size_t
-ractor_selector_memsize(const void *ptr)
-{
- const struct rb_ractor_selector *s = ptr;
- return sizeof(struct rb_ractor_selector) +
- st_memsize(s->take_ractors) +
- s->take_ractors->num_entries * sizeof(struct rb_ractor_selector_take_config);
-}
-
-static const rb_data_type_t ractor_selector_data_type = {
- "ractor/selector",
- {
- ractor_selector_mark,
- ractor_selector_free,
- ractor_selector_memsize,
- NULL, // update
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
-};
-
-static struct rb_ractor_selector *
-RACTOR_SELECTOR_PTR(VALUE selv)
-{
- VM_ASSERT(rb_typeddata_is_kind_of(selv, &ractor_selector_data_type));
-
- return (struct rb_ractor_selector *)DATA_PTR(selv);
-}
-
-// Ractor::Selector.new
-
+// select(r1, r2, r3, receive: true, yield: obj)
static VALUE
-ractor_selector_create(VALUE klass)
+ractor_select(rb_execution_context_t *ec, const VALUE *rs, const int rs_len, VALUE yielded_value, bool move, VALUE *ret_r)
{
- struct rb_ractor_selector *s;
- VALUE selv = TypedData_Make_Struct(klass, struct rb_ractor_selector, &ractor_selector_data_type, s);
- s->take_basket.type.e = basket_type_reserved;
- s->take_ractors = st_init_numtable(); // ractor (ptr) -> take_config
- return selv;
-}
-
-// Ractor::Selector#add(r)
-
-static VALUE
-ractor_selector_add(VALUE selv, VALUE rv)
-{
- if (!rb_ractor_p(rv)) {
- rb_raise(rb_eArgError, "Not a ractor object");
- }
-
- rb_ractor_t *r = RACTOR_PTR(rv);
- struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
-
- if (st_lookup(s->take_ractors, (st_data_t)r, NULL)) {
- rb_raise(rb_eArgError, "already added");
- }
-
- struct rb_ractor_selector_take_config *config = malloc(sizeof(struct rb_ractor_selector_take_config));
- VM_ASSERT(config != NULL);
- config->closed = false;
- config->oneshot = false;
-
- if (ractor_register_take(GET_RACTOR(), r, &s->take_basket, false, config, true)) {
- st_insert(s->take_ractors, (st_data_t)r, (st_data_t)config);
- }
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ VALUE crv = cr->pub.self;
+ VALUE ret = Qundef;
+ int i;
+ bool interrupted = false;
+ enum rb_ractor_wait_status wait_status = 0;
+ bool yield_p = !UNDEF_P(yielded_value) ? true : false;
+ const int alen = rs_len + (yield_p ? 1 : 0);
+
+ struct ractor_select_action {
+ enum ractor_select_action_type {
+ ractor_select_action_take,
+ ractor_select_action_receive,
+ ractor_select_action_yield,
+ } type;
+ VALUE v;
+ } *actions = ALLOCA_N(struct ractor_select_action, alen);
- return rv;
-}
+ VM_ASSERT(cr->sync.wait.status == wait_none);
+ VM_ASSERT(cr->sync.wait.wakeup_status == wakeup_none);
+ VM_ASSERT(cr->sync.wait.taken_basket.type == basket_type_none);
+ VM_ASSERT(cr->sync.wait.yielded_basket.type == basket_type_none);
-// Ractor::Selector#remove(r)
+ // setup actions
+ for (i=0; i<rs_len; i++) {
+ VALUE v = rs[i];
-static VALUE
-ractor_selector_remove(VALUE selv, VALUE rv)
-{
- if (!rb_ractor_p(rv)) {
- rb_raise(rb_eArgError, "Not a ractor object");
+ if (v == crv) {
+ actions[i].type = ractor_select_action_receive;
+ actions[i].v = Qnil;
+ wait_status |= wait_receiving;
+ }
+ else if (rb_ractor_p(v)) {
+ actions[i].type = ractor_select_action_take;
+ actions[i].v = v;
+ wait_status |= wait_taking;
+ }
+ else {
+ rb_raise(rb_eArgError, "should be a ractor object, but %"PRIsVALUE, v);
+ }
}
+ rs = NULL;
- rb_ractor_t *r = RACTOR_PTR(rv);
- struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
-
- RUBY_DEBUG_LOG("r:%u", rb_ractor_id(r));
+ restart:
- if (!st_lookup(s->take_ractors, (st_data_t)r, NULL)) {
- rb_raise(rb_eArgError, "not added yet");
+ if (yield_p) {
+ actions[rs_len].type = ractor_select_action_yield;
+ actions[rs_len].v = Qundef;
+ wait_status |= wait_yielding;
+ ractor_basket_setup(ec, &cr->sync.wait.yielded_basket, yielded_value, move, false, false, true);
}
- ractor_deregister_take(r, &s->take_basket);
- struct rb_ractor_selector_take_config *config;
- st_delete(s->take_ractors, (st_data_t *)&r, (st_data_t *)&config);
- free(config);
-
- return rv;
-}
-
-// Ractor::Selector#clear
-
-struct ractor_selector_clear_data {
- VALUE selv;
- rb_execution_context_t *ec;
-};
-
-static int
-ractor_selector_clear_i(st_data_t key, st_data_t val, st_data_t data)
-{
- VALUE selv = (VALUE)data;
- rb_ractor_t *r = (rb_ractor_t *)key;
- ractor_selector_remove(selv, r->pub.self);
- return ST_CONTINUE;
-}
-
-static VALUE
-ractor_selector_clear(VALUE selv)
-{
- struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
-
- st_foreach(s->take_ractors, ractor_selector_clear_i, (st_data_t)selv);
- st_clear(s->take_ractors);
- return selv;
-}
-
-static VALUE
-ractor_selector_empty_p(VALUE selv)
-{
- struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
- return s->take_ractors->num_entries == 0 ? Qtrue : Qfalse;
-}
+ // TODO: shuffle actions
-static int
-ractor_selector_wait_i(st_data_t key, st_data_t val, st_data_t dat)
-{
- rb_ractor_t *r = (rb_ractor_t *)key;
- struct rb_ractor_basket *tb = (struct rb_ractor_basket *)dat;
- int ret;
+ while (1) {
+ RUBY_DEBUG_LOG("try actions (%s)", wait_status_str(wait_status));
+
+ for (i=0; i<alen; i++) {
+ VALUE v, rv;
+ switch (actions[i].type) {
+ case ractor_select_action_take:
+ rv = actions[i].v;
+ v = ractor_try_take(ec, RACTOR_PTR(rv));
+ if (!UNDEF_P(v)) {
+ *ret_r = rv;
+ ret = v;
+ goto cleanup;
+ }
+ break;
+ case ractor_select_action_receive:
+ v = ractor_try_receive(ec, cr);
+ if (!UNDEF_P(v)) {
+ *ret_r = ID2SYM(rb_intern("receive"));
+ ret = v;
+ goto cleanup;
+ }
+ break;
+ case ractor_select_action_yield:
+ {
+ if (ractor_try_yield(ec, cr, &cr->sync.wait.yielded_basket)) {
+ *ret_r = ID2SYM(rb_intern("yield"));
+ ret = Qnil;
+ goto cleanup;
+ }
+ }
+ break;
+ }
+ }
- if (!basket_none_p(tb)) {
- RUBY_DEBUG_LOG("already taken:%s", basket_type_name(tb->type.e));
- return ST_STOP;
- }
+ RUBY_DEBUG_LOG("wait actions (%s)", wait_status_str(wait_status));
- RACTOR_LOCK(r);
- {
- if (basket_type_p(&r->sync.will_basket, basket_type_will)) {
- RUBY_DEBUG_LOG("r:%u has will", rb_ractor_id(r));
+ RACTOR_LOCK(cr);
+ {
+ VM_ASSERT(cr->sync.wait.status == wait_none);
+ cr->sync.wait.status = wait_status;
+ cr->sync.wait.wakeup_status = wakeup_none;
+ }
+ RACTOR_UNLOCK(cr);
- if (RUBY_ATOMIC_CAS(tb->type.atomic, basket_type_none, basket_type_will) == basket_type_none) {
- ractor_take_will(r, tb);
- ret = ST_STOP;
- }
- else {
- RUBY_DEBUG_LOG("has will, but already taken (%s)", basket_type_name(tb->type.e));
- ret = ST_CONTINUE;
+ // prepare waiting
+ for (i=0; i<alen; i++) {
+ rb_ractor_t *r;
+ switch (actions[i].type) {
+ case ractor_select_action_take:
+ r = RACTOR_PTR(actions[i].v);
+ ractor_register_taking(r, cr);
+ break;
+ case ractor_select_action_yield:
+ case ractor_select_action_receive:
+ break;
}
}
- else if (r->sync.outgoing_port_closed) {
- RUBY_DEBUG_LOG("r:%u is closed", rb_ractor_id(r));
- if (RUBY_ATOMIC_CAS(tb->type.atomic, basket_type_none, basket_type_deleted) == basket_type_none) {
- tb->sender = r->pub.self;
- ret = ST_STOP;
+ // wait
+ RACTOR_LOCK(cr);
+ {
+ if (cr->sync.wait.wakeup_status == wakeup_none) {
+ for (i=0; i<alen; i++) {
+ rb_ractor_t *r;
+
+ switch (actions[i].type) {
+ case ractor_select_action_take:
+ r = RACTOR_PTR(actions[i].v);
+ if (ractor_sleeping_by(r, wait_yielding)) {
+ RUBY_DEBUG_LOG("wakeup_none, but r:%u is waiting for yielding", r->pub.id);
+ cr->sync.wait.wakeup_status = wakeup_by_retry;
+ goto skip_sleep;
+ }
+ break;
+ case ractor_select_action_receive:
+ if (cr->sync.incoming_queue.cnt > 0) {
+ RUBY_DEBUG_LOG("wakeup_none, but incoming_queue has %u messages", cr->sync.incoming_queue.cnt);
+ cr->sync.wait.wakeup_status = wakeup_by_retry;
+ goto skip_sleep;
+ }
+ break;
+ case ractor_select_action_yield:
+ if (cr->sync.taking_ractors.cnt > 0) {
+ RUBY_DEBUG_LOG("wakeup_none, but %u taking_ractors are waiting", cr->sync.taking_ractors.cnt);
+ cr->sync.wait.wakeup_status = wakeup_by_retry;
+ goto skip_sleep;
+ }
+ else if (cr->sync.outgoing_port_closed) {
+ cr->sync.wait.wakeup_status = wakeup_by_close;
+ goto skip_sleep;
+ }
+ break;
+ }
+ }
+
+ RUBY_DEBUG_LOG("sleep %s", wait_status_str(cr->sync.wait.status));
+ ractor_sleep(ec, cr);
+ RUBY_DEBUG_LOG("awaken %s", wakeup_status_str(cr->sync.wait.wakeup_status));
}
else {
- RUBY_DEBUG_LOG("closed, but already taken (%s)", basket_type_name(tb->type.e));
- ret = ST_CONTINUE;
+ skip_sleep:
+ RUBY_DEBUG_LOG("no need to sleep %s->%s",
+ wait_status_str(cr->sync.wait.status),
+ wakeup_status_str(cr->sync.wait.wakeup_status));
+ cr->sync.wait.status = wait_none;
}
}
- else {
- RUBY_DEBUG_LOG("wakeup r:%u", rb_ractor_id(r));
- ractor_wakeup(r, wait_yielding, wakeup_by_take);
- ret = ST_CONTINUE;
- }
- }
- RACTOR_UNLOCK(r);
-
- return ret;
-}
-
-// Ractor::Selector#wait
-
-static void
-ractor_selector_wait_cleaup(rb_ractor_t *cr, void *ptr)
-{
- struct rb_ractor_basket *tb = (struct rb_ractor_basket *)ptr;
-
- RACTOR_LOCK_SELF(cr);
- {
- while (basket_type_p(tb, basket_type_yielding)) rb_thread_sleep(0);
- // if tb->type is not none, taking is succeeded, but interruption ignore it unfortunately.
- tb->type.e = basket_type_reserved;
- }
- RACTOR_UNLOCK_SELF(cr);
-}
-
-static VALUE
-ractor_selector__wait(VALUE selv, VALUE do_receivev, VALUE do_yieldv, VALUE yield_value, VALUE move)
-{
- rb_execution_context_t *ec = GET_EC();
- struct rb_ractor_selector *s = RACTOR_SELECTOR_PTR(selv);
- struct rb_ractor_basket *tb = &s->take_basket;
- struct rb_ractor_basket taken_basket;
- rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
- bool do_receive = !!RTEST(do_receivev);
- bool do_yield = !!RTEST(do_yieldv);
- VALUE ret_v, ret_r;
- enum rb_ractor_wait_status wait_status;
- struct rb_ractor_queue *rq = &cr->sync.recv_queue;
- struct rb_ractor_queue *ts = &cr->sync.takers_queue;
-
- RUBY_DEBUG_LOG("start");
-
- retry:
- RUBY_DEBUG_LOG("takers:%ld", s->take_ractors->num_entries);
-
- // setup wait_status
- wait_status = wait_none;
- if (s->take_ractors->num_entries > 0) wait_status |= wait_taking;
- if (do_receive) wait_status |= wait_receiving;
- if (do_yield) wait_status |= wait_yielding;
-
- RUBY_DEBUG_LOG("wait:%s", wait_status_str(wait_status));
-
- if (wait_status == wait_none) {
- rb_raise(rb_eRactorError, "no taking ractors");
- }
-
- // check recv_queue
- if (do_receive && !UNDEF_P(ret_v = ractor_try_receive(ec, cr, rq))) {
- ret_r = ID2SYM(rb_intern("receive"));
- goto success;
- }
-
- // check takers
- if (do_yield && ractor_try_yield(ec, cr, ts, yield_value, move, false, false)) {
- ret_v = Qnil;
- ret_r = ID2SYM(rb_intern("yield"));
- goto success;
- }
-
- // check take_basket
- VM_ASSERT(basket_type_p(&s->take_basket, basket_type_reserved));
- s->take_basket.type.e = basket_type_none;
- // kick all take target ractors
- st_foreach(s->take_ractors, ractor_selector_wait_i, (st_data_t)tb);
+ RACTOR_UNLOCK(cr);
- RACTOR_LOCK_SELF(cr);
- {
- retry_waiting:
- while (1) {
- if (!basket_none_p(tb)) {
- RUBY_DEBUG_LOG("taken:%s from r:%u", basket_type_name(tb->type.e),
- tb->sender ? rb_ractor_id(RACTOR_PTR(tb->sender)) : 0);
- break;
- }
- if (do_receive && !ractor_queue_empty_p(cr, rq)) {
- RUBY_DEBUG_LOG("can receive (%d)", rq->cnt);
+ // cleanup waiting
+ for (i=0; i<alen; i++) {
+ rb_ractor_t *r;
+ switch (actions[i].type) {
+ case ractor_select_action_take:
+ r = RACTOR_PTR(actions[i].v);
+ ractor_waiting_list_del(r, &r->sync.taking_ractors, cr);
break;
- }
- if (do_yield && ractor_check_take_basket(cr, ts)) {
- RUBY_DEBUG_LOG("can yield");
+ case ractor_select_action_receive:
+ case ractor_select_action_yield:
break;
}
-
- ractor_sleep_with_cleanup(ec, cr, wait_status, ractor_selector_wait_cleaup, tb);
}
- taken_basket = *tb;
-
- // ensure
- // tb->type.e = basket_type_reserved # do it atomic in the following code
- if (taken_basket.type.e == basket_type_yielding ||
- RUBY_ATOMIC_CAS(tb->type.atomic, taken_basket.type.e, basket_type_reserved) != taken_basket.type.e) {
+ // check results
+ enum rb_ractor_wakeup_status wakeup_status = cr->sync.wait.wakeup_status;
+ cr->sync.wait.wakeup_status = wakeup_none;
- if (basket_type_p(tb, basket_type_yielding)) {
- RACTOR_UNLOCK_SELF(cr);
- {
- rb_thread_sleep(0);
- }
- RACTOR_LOCK_SELF(cr);
- }
- goto retry_waiting;
+ switch (wakeup_status) {
+ case wakeup_none:
+ // OK. something happens.
+ // retry loop.
+ break;
+ case wakeup_by_retry:
+ // Retry request.
+ break;
+ case wakeup_by_send:
+ // OK.
+ // retry loop and try_receive will succss.
+ break;
+ case wakeup_by_yield:
+ // take was succeeded!
+ // cr.wait.taken_basket contains passed block
+ VM_ASSERT(cr->sync.wait.taken_basket.type != basket_type_none);
+ *ret_r = cr->sync.wait.taken_basket.sender;
+ VM_ASSERT(rb_ractor_p(*ret_r));
+ ret = ractor_basket_accept(&cr->sync.wait.taken_basket);
+ goto cleanup;
+ case wakeup_by_take:
+ *ret_r = ID2SYM(rb_intern("yield"));
+ ret = Qnil;
+ goto cleanup;
+ case wakeup_by_close:
+ // OK.
+ // retry loop and will get CloseError.
+ break;
+ case wakeup_by_interrupt:
+ ret = Qundef;
+ interrupted = true;
+ goto cleanup;
}
}
- RACTOR_UNLOCK_SELF(cr);
-
- // check the taken resutl
- switch (taken_basket.type.e) {
- case basket_type_none:
- VM_ASSERT(do_receive || do_yield);
- goto retry;
- case basket_type_yielding:
- rb_bug("unreachable");
- case basket_type_deleted: {
- ractor_selector_remove(selv, taken_basket.sender);
-
- rb_ractor_t *r = RACTOR_PTR(taken_basket.sender);
- if (ractor_take_will_lock(r, &taken_basket)) {
- RUBY_DEBUG_LOG("has_will");
- }
- else {
- RUBY_DEBUG_LOG("no will");
- // rb_raise(rb_eRactorClosedError, "The outgoing-port is already closed");
- // remove and retry wait
- goto retry;
- }
- break;
- }
- case basket_type_will:
- // no more messages
- ractor_selector_remove(selv, taken_basket.sender);
- break;
- default:
- break;
- }
- RUBY_DEBUG_LOG("taken_basket:%s", basket_type_name(taken_basket.type.e));
+ cleanup:
+ RUBY_DEBUG_LOG("cleanup actions (%s)", wait_status_str(wait_status));
- ret_v = ractor_basket_accept(&taken_basket);
- ret_r = taken_basket.sender;
- success:
- return rb_ary_new_from_args(2, ret_r, ret_v);
-}
+ if (cr->sync.wait.yielded_basket.type != basket_type_none) {
+ ractor_basket_clear(&cr->sync.wait.yielded_basket);
+ }
-static VALUE
-ractor_selector_wait(int argc, VALUE *argv, VALUE selector)
-{
- VALUE options;
- ID keywords[3];
- VALUE values[3];
+ VM_ASSERT(cr->sync.wait.status == wait_none);
+ VM_ASSERT(cr->sync.wait.wakeup_status == wakeup_none);
+ VM_ASSERT(cr->sync.wait.taken_basket.type == basket_type_none);
+ VM_ASSERT(cr->sync.wait.yielded_basket.type == basket_type_none);
- keywords[0] = rb_intern("receive");
- keywords[1] = rb_intern("yield_value");
- keywords[2] = rb_intern("move");
+ if (interrupted) {
+ rb_vm_check_ints_blocking(ec);
+ interrupted = false;
+ goto restart;
+ }
- rb_scan_args(argc, argv, "0:", &options);
- rb_get_kwargs(options, keywords, 0, numberof(values), values);
- return ractor_selector__wait(selector,
- values[0] == Qundef ? Qfalse : RTEST(values[0]),
- values[1] != Qundef, values[1], values[2]);
+ VM_ASSERT(!UNDEF_P(ret));
+ return ret;
}
static VALUE
-ractor_selector_new(int argc, VALUE *ractors, VALUE klass)
+ractor_yield(rb_execution_context_t *ec, rb_ractor_t *r, VALUE obj, VALUE move)
{
- VALUE selector = ractor_selector_create(klass);
-
- for (int i=0; i<argc; i++) {
- ractor_selector_add(selector, ractors[i]);
- }
-
- return selector;
+ VALUE ret_r;
+ ractor_select(ec, NULL, 0, obj, RTEST(move) ? true : false, &ret_r);
+ return Qnil;
}
static VALUE
-ractor_select_internal(rb_execution_context_t *ec, VALUE self, VALUE ractors, VALUE do_receive, VALUE do_yield, VALUE yield_value, VALUE move)
+ractor_take(rb_execution_context_t *ec, rb_ractor_t *r)
{
- VALUE selector = ractor_selector_new(RARRAY_LENINT(ractors), (VALUE *)RARRAY_CONST_PTR(ractors), rb_cRactorSelector);
- VALUE result;
- int state;
-
- EC_PUSH_TAG(ec);
- if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- result = ractor_selector__wait(selector, do_receive, do_yield, yield_value, move);
- }
- EC_POP_TAG();
- if (state != TAG_NONE) {
- // ensure
- ractor_selector_clear(selector);
-
- // jump
- EC_JUMP_TAG(ec, state);
- }
-
- RB_GC_GUARD(ractors);
- return result;
+ VALUE ret_r;
+ VALUE v = ractor_select(ec, &r->pub.self, 1, Qundef, false, &ret_r);
+ return v;
}
-// Ractor#close_incoming
-
static VALUE
ractor_close_incoming(rb_execution_context_t *ec, rb_ractor_t *r)
{
@@ -1841,7 +1356,7 @@ ractor_close_incoming(rb_execution_context_t *ec, rb_ractor_t *r)
prev = Qfalse;
r->sync.incoming_port_closed = true;
if (ractor_wakeup(r, wait_receiving, wakeup_by_close)) {
- VM_ASSERT(ractor_queue_empty_p(r, &r->sync.recv_queue));
+ VM_ASSERT(r->sync.incoming_queue.cnt == 0);
RUBY_DEBUG_LOG("cancel receiving");
}
}
@@ -1853,8 +1368,6 @@ ractor_close_incoming(rb_execution_context_t *ec, rb_ractor_t *r)
return prev;
}
-// Ractor#close_outgoing
-
static VALUE
ractor_close_outgoing(rb_execution_context_t *ec, rb_ractor_t *r)
{
@@ -1862,50 +1375,27 @@ ractor_close_outgoing(rb_execution_context_t *ec, rb_ractor_t *r)
RACTOR_LOCK(r);
{
- struct rb_ractor_queue *ts = &r->sync.takers_queue;
- rb_ractor_t *tr;
- struct rb_ractor_basket b;
-
if (!r->sync.outgoing_port_closed) {
prev = Qfalse;
r->sync.outgoing_port_closed = true;
}
else {
- VM_ASSERT(ractor_queue_empty_p(r, ts));
prev = Qtrue;
}
// wakeup all taking ractors
- while (ractor_queue_deq(r, ts, &b)) {
- if (basket_type_p(&b, basket_type_take_basket)) {
- tr = RACTOR_PTR(b.sender);
- struct rb_ractor_basket *tb = b.p.take.basket;
-
- if (RUBY_ATOMIC_CAS(tb->type.atomic, basket_type_none, basket_type_yielding) == basket_type_none) {
- b.p.take.basket->sender = r->pub.self;
- if (RUBY_ATOMIC_CAS(tb->type.atomic, basket_type_yielding, basket_type_deleted) != basket_type_yielding) {
- rb_bug("unreachable");
- }
- RUBY_DEBUG_LOG("set delete for r:%u", rb_ractor_id(RACTOR_PTR(b.sender)));
- }
-
- if (b.p.take.config) {
- b.p.take.config->closed = true;
- }
-
- // TODO: deadlock-able?
- RACTOR_LOCK(tr);
- {
- ractor_wakeup(tr, wait_taking, wakeup_by_close);
- }
- RACTOR_UNLOCK(tr);
- }
+ rb_ractor_t *taking_ractor;
+ while ((taking_ractor = ractor_waiting_list_shift(r, &r->sync.taking_ractors)) != NULL) {
+ RACTOR_LOCK(taking_ractor);
+ ractor_wakeup(taking_ractor, wait_taking, wakeup_by_close);
+ RACTOR_UNLOCK(taking_ractor);
}
// raising yielding Ractor
- ractor_wakeup(r, wait_yielding, wakeup_by_close);
-
- VM_ASSERT(ractor_queue_empty_p(r, ts));
+ if (!r->yield_atexit &&
+ ractor_wakeup(r, wait_yielding, wakeup_by_close)) {
+ RUBY_DEBUG_LOG("cancel yielding");
+ }
}
RACTOR_UNLOCK(r);
return prev;
@@ -1931,13 +1421,6 @@ vm_insert_ractor0(rb_vm_t *vm, rb_ractor_t *r, bool single_ractor_mode)
ccan_list_add_tail(&vm->ractor.set, &r->vmlr_node);
vm->ractor.cnt++;
-
- if (r->newobj_cache) {
- VM_ASSERT(r == ruby_single_main_ractor);
- }
- else {
- r->newobj_cache = rb_gc_ractor_cache_alloc();
- }
}
static void
@@ -1949,6 +1432,7 @@ cancel_single_ractor_mode(void)
VALUE was_disabled = rb_gc_enable();
rb_gc_start();
+ rb_transient_heap_evacuate();
if (was_disabled) {
rb_gc_disable();
@@ -2005,8 +1489,8 @@ vm_remove_ractor(rb_vm_t *vm, rb_ractor_t *cr)
}
vm->ractor.cnt--;
- rb_gc_ractor_cache_free(cr->newobj_cache);
- cr->newobj_cache = NULL;
+ /* Clear the cached freelist to prevent a memory leak. */
+ rb_gc_ractor_newobj_cache_clear(&cr->newobj_cache);
ractor_status_set(cr, ractor_terminated);
}
@@ -2027,16 +1511,16 @@ ractor_alloc(VALUE klass)
rb_ractor_t *
rb_ractor_main_alloc(void)
{
- rb_ractor_t *r = ruby_mimcalloc(1, sizeof(rb_ractor_t));
+ rb_ractor_t *r = ruby_mimmalloc(sizeof(rb_ractor_t));
if (r == NULL) {
fprintf(stderr, "[FATAL] failed to allocate memory for main ractor\n");
exit(EXIT_FAILURE);
}
+ MEMZERO(r, rb_ractor_t, 1);
r->pub.id = ++ractor_last_id;
r->loc = Qnil;
r->name = Qnil;
r->pub.self = Qnil;
- r->newobj_cache = rb_gc_ractor_cache_alloc();
ruby_single_main_ractor = r;
return r;
@@ -2060,7 +1544,7 @@ rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th)
}
#endif
-void rb_thread_sched_init(struct rb_thread_sched *, bool atfork);
+void rb_thread_sched_init(struct rb_thread_sched *);
void
rb_ractor_living_threads_init(rb_ractor_t *r)
@@ -2073,18 +1557,13 @@ rb_ractor_living_threads_init(rb_ractor_t *r)
static void
ractor_init(rb_ractor_t *r, VALUE name, VALUE loc)
{
- ractor_queue_setup(&r->sync.recv_queue);
- ractor_queue_setup(&r->sync.takers_queue);
+ ractor_queue_setup(&r->sync.incoming_queue);
rb_native_mutex_initialize(&r->sync.lock);
- rb_native_cond_initialize(&r->barrier_wait_cond);
-
-#ifdef RUBY_THREAD_WIN32_H
rb_native_cond_initialize(&r->sync.cond);
rb_native_cond_initialize(&r->barrier_wait_cond);
-#endif
// thread management
- rb_thread_sched_init(&r->threads.sched, false);
+ rb_thread_sched_init(&r->threads.sched);
rb_ractor_living_threads_init(r);
// naming
@@ -2128,7 +1607,7 @@ ractor_create(rb_execution_context_t *ec, VALUE self, VALUE loc, VALUE name, VAL
r->debug = cr->debug;
rb_yjit_before_ractor_spawn();
- rb_rjit_before_ractor_spawn();
+ rb_mjit_before_ractor_spawn();
rb_thread_create_ractor(r, args, block);
RB_GC_GUARD(rv);
@@ -2144,23 +1623,28 @@ ractor_yield_atexit(rb_execution_context_t *ec, rb_ractor_t *cr, VALUE v, bool e
ASSERT_ractor_unlocking(cr);
- struct rb_ractor_queue *ts = &cr->sync.takers_queue;
+ struct rb_ractor_basket basket;
+ ractor_basket_setup(ec, &basket, v, Qfalse, exc, true, true /* this flag is ignored because move is Qfalse */);
retry:
- if (ractor_try_yield(ec, cr, ts, v, Qfalse, exc, true)) {
+ if (ractor_try_yield(ec, cr, &basket)) {
// OK.
}
else {
bool retry = false;
RACTOR_LOCK(cr);
{
- if (!ractor_check_take_basket(cr, ts)) {
+ if (cr->sync.taking_ractors.cnt == 0) {
+ cr->sync.wait.yielded_basket = basket;
+
VM_ASSERT(cr->sync.wait.status == wait_none);
- RUBY_DEBUG_LOG("leave a will");
- ractor_basket_fill_will(cr, &cr->sync.will_basket, v, exc);
+ cr->sync.wait.status = wait_yielding;
+ cr->sync.wait.wakeup_status = wakeup_none;
+
+ VM_ASSERT(cr->yield_atexit == false);
+ cr->yield_atexit = true;
}
else {
- RUBY_DEBUG_LOG("rare timing!");
retry = true; // another ractor is waiting for the yield.
}
}
@@ -2171,20 +1655,6 @@ ractor_yield_atexit(rb_execution_context_t *ec, rb_ractor_t *cr, VALUE v, bool e
}
void
-rb_ractor_atexit(rb_execution_context_t *ec, VALUE result)
-{
- rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
- ractor_yield_atexit(ec, cr, result, false);
-}
-
-void
-rb_ractor_atexit_exception(rb_execution_context_t *ec)
-{
- rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
- ractor_yield_atexit(ec, cr, ec->errinfo, true);
-}
-
-void
rb_ractor_teardown(rb_execution_context_t *ec)
{
rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
@@ -2201,6 +1671,20 @@ rb_ractor_teardown(rb_execution_context_t *ec)
}
void
+rb_ractor_atexit(rb_execution_context_t *ec, VALUE result)
+{
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ ractor_yield_atexit(ec, cr, result, false);
+}
+
+void
+rb_ractor_atexit_exception(rb_execution_context_t *ec)
+{
+ rb_ractor_t *cr = rb_ec_ractor_ptr(ec);
+ ractor_yield_atexit(ec, cr, ec->errinfo, true);
+}
+
+void
rb_ractor_receive_parameters(rb_execution_context_t *ec, rb_ractor_t *r, int len, VALUE *ptr)
{
for (int i=0; i<len; i++) {
@@ -2217,7 +1701,7 @@ rb_ractor_send_parameters(rb_execution_context_t *ec, rb_ractor_t *r, VALUE args
}
}
-bool
+MJIT_FUNC_EXPORTED bool
rb_ractor_main_p_(void)
{
VM_ASSERT(rb_multi_ractor_p());
@@ -2239,24 +1723,35 @@ rb_ractor_living_thread_num(const rb_ractor_t *r)
return r->threads.cnt;
}
-// only for current ractor
VALUE
-rb_ractor_thread_list(void)
+rb_ractor_thread_list(rb_ractor_t *r)
{
- rb_ractor_t *r = GET_RACTOR();
rb_thread_t *th = 0;
- VALUE ary = rb_ary_new();
+ VALUE *ts;
+ int ts_cnt;
- ccan_list_for_each(&r->threads.set, th, lt_node) {
- switch (th->status) {
- case THREAD_RUNNABLE:
- case THREAD_STOPPED:
- case THREAD_STOPPED_FOREVER:
- rb_ary_push(ary, th->self);
- default:
- break;
+ RACTOR_LOCK(r);
+ {
+ ts = ALLOCA_N(VALUE, r->threads.cnt);
+ ts_cnt = 0;
+
+ ccan_list_for_each(&r->threads.set, th, lt_node) {
+ switch (th->status) {
+ case THREAD_RUNNABLE:
+ case THREAD_STOPPED:
+ case THREAD_STOPPED_FOREVER:
+ ts[ts_cnt++] = th->self;
+ default:
+ break;
+ }
}
}
+ RACTOR_UNLOCK(r);
+
+ VALUE ary = rb_ary_new();
+ for (int i=0; i<ts_cnt; i++) {
+ rb_ary_push(ary, ts[i]);
+ }
return ary;
}
@@ -2339,8 +1834,6 @@ ractor_check_blocking(rb_ractor_t *cr, unsigned int remained_thread_cnt, const c
}
}
-void rb_threadptr_remove(rb_thread_t *th);
-
void
rb_ractor_living_threads_remove(rb_ractor_t *cr, rb_thread_t *th)
{
@@ -2348,8 +1841,6 @@ rb_ractor_living_threads_remove(rb_ractor_t *cr, rb_thread_t *th)
RUBY_DEBUG_LOG("r->threads.cnt:%d--", cr->threads.cnt);
ractor_check_blocking(cr, cr->threads.cnt - 1, __FILE__, __LINE__);
- rb_threadptr_remove(th);
-
if (cr->threads.cnt == 1) {
vm_remove_ractor(th->vm, cr);
}
@@ -2445,31 +1936,23 @@ ractor_terminal_interrupt_all(rb_vm_t *vm)
rb_ractor_t *r = 0;
ccan_list_for_each(&vm->ractor.set, r, vmlr_node) {
if (r != vm->ractor.main_ractor) {
- RUBY_DEBUG_LOG("r:%d", rb_ractor_id(r));
rb_ractor_terminate_interrupt_main_thread(r);
}
}
}
}
-void rb_add_running_thread(rb_thread_t *th);
-void rb_del_running_thread(rb_thread_t *th);
-
void
rb_ractor_terminate_all(void)
{
rb_vm_t *vm = GET_VM();
rb_ractor_t *cr = vm->ractor.main_ractor;
- RUBY_DEBUG_LOG("ractor.cnt:%d", (int)vm->ractor.cnt);
-
VM_ASSERT(cr == GET_RACTOR()); // only main-ractor's main-thread should kick it.
if (vm->ractor.cnt > 1) {
RB_VM_LOCK();
- {
- ractor_terminal_interrupt_all(vm); // kill all ractors
- }
+ ractor_terminal_interrupt_all(vm); // kill all ractors
RB_VM_UNLOCK();
}
rb_thread_terminate_all(GET_THREAD()); // kill other threads in main-ractor and wait
@@ -2482,9 +1965,7 @@ rb_ractor_terminate_all(void)
// wait for 1sec
rb_vm_ractor_blocking_cnt_inc(vm, cr, __FILE__, __LINE__);
- rb_del_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
rb_vm_cond_timedwait(vm, &vm->ractor.sync.terminate_cond, 1000 /* ms */);
- rb_add_running_thread(rb_ec_thread_ptr(cr->threads.running_ec));
rb_vm_ractor_blocking_cnt_dec(vm, cr, __FILE__, __LINE__);
ractor_terminal_interrupt_all(vm);
@@ -2496,23 +1977,7 @@ rb_ractor_terminate_all(void)
rb_execution_context_t *
rb_vm_main_ractor_ec(rb_vm_t *vm)
{
- /* This code needs to carefully work around two bugs:
- * - Bug #20016: When M:N threading is enabled, running_ec is NULL if no thread is
- * actually currently running (as opposed to without M:N threading, when
- * running_ec will still point to the _last_ thread which ran)
- * - Bug #20197: If the main thread is sleeping, setting its postponed job
- * interrupt flag is pointless; it won't look at the flag until it stops sleeping
- * for some reason. It would be better to set the flag on the running ec, which
- * will presumably look at it soon.
- *
- * Solution: use running_ec if it's set, otherwise fall back to the main thread ec.
- * This is still susceptible to some rare race conditions (what if the last thread
- * to run just entered a long-running sleep?), but seems like the best balance of
- * robustness and complexity.
- */
- rb_execution_context_t *running_ec = vm->ractor.main_ractor->threads.running_ec;
- if (running_ec) { return running_ec; }
- return vm->ractor.main_thread->ec;
+ return vm->ractor.main_ractor->threads.running_ec;
}
static VALUE
@@ -2521,29 +1986,6 @@ ractor_moved_missing(int argc, VALUE *argv, VALUE self)
rb_raise(rb_eRactorMovedError, "can not send any methods to a moved object");
}
-#ifndef USE_RACTOR_SELECTOR
-#define USE_RACTOR_SELECTOR 0
-#endif
-
-RUBY_SYMBOL_EXPORT_BEGIN
-void rb_init_ractor_selector(void);
-RUBY_SYMBOL_EXPORT_END
-
-void
-rb_init_ractor_selector(void)
-{
- rb_cRactorSelector = rb_define_class_under(rb_cRactor, "Selector", rb_cObject);
- rb_undef_alloc_func(rb_cRactorSelector);
-
- rb_define_singleton_method(rb_cRactorSelector, "new", ractor_selector_new , -1);
- rb_define_method(rb_cRactorSelector, "add", ractor_selector_add, 1);
- rb_define_method(rb_cRactorSelector, "remove", ractor_selector_remove, 1);
- rb_define_method(rb_cRactorSelector, "clear", ractor_selector_clear, 0);
- rb_define_method(rb_cRactorSelector, "empty?", ractor_selector_empty_p, 0);
- rb_define_method(rb_cRactorSelector, "wait", ractor_selector_wait, -1);
- rb_define_method(rb_cRactorSelector, "_wait", ractor_selector__wait, 4);
-}
-
/*
* Document-class: Ractor::ClosedError
*
@@ -2663,10 +2105,6 @@ Init_Ractor(void)
rb_define_method(rb_cRactorMovedObject, "equal?", ractor_moved_missing, -1);
rb_define_method(rb_cRactorMovedObject, "instance_eval", ractor_moved_missing, -1);
rb_define_method(rb_cRactorMovedObject, "instance_exec", ractor_moved_missing, -1);
-
-#if USE_RACTOR_SELECTOR
- rb_init_ractor_selector();
-#endif
}
void
@@ -2812,6 +2250,19 @@ obj_hash_traverse_i(VALUE key, VALUE val, VALUE ptr)
return ST_CONTINUE;
}
+static int
+obj_hash_iv_traverse_i(st_data_t key, st_data_t val, st_data_t ptr)
+{
+ struct obj_traverse_callback_data *d = (struct obj_traverse_callback_data *)ptr;
+
+ if (obj_traverse_i((VALUE)val, d->data)) {
+ d->stop = true;
+ return ST_STOP;
+ }
+
+ return ST_CONTINUE;
+}
+
static void
obj_traverse_reachable_i(VALUE obj, void *ptr)
{
@@ -2827,25 +2278,12 @@ obj_traverse_rec(struct obj_traverse_data *data)
{
if (UNLIKELY(!data->rec)) {
data->rec_hash = rb_ident_hash_new();
- data->rec = RHASH_ST_TABLE(data->rec_hash);
+ data->rec = rb_hash_st_table(data->rec_hash);
}
return data->rec;
}
static int
-obj_traverse_ivar_foreach_i(ID key, VALUE val, st_data_t ptr)
-{
- struct obj_traverse_callback_data *d = (struct obj_traverse_callback_data *)ptr;
-
- if (obj_traverse_i(val, d->data)) {
- d->stop = true;
- return ST_STOP;
- }
-
- return ST_CONTINUE;
-}
-
-static int
obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
{
if (RB_SPECIAL_CONST_P(obj)) return 0;
@@ -2861,12 +2299,14 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
return 0;
}
- struct obj_traverse_callback_data d = {
- .stop = false,
- .data = data,
- };
- rb_ivar_foreach(obj, obj_traverse_ivar_foreach_i, (st_data_t)&d);
- if (d.stop) return 1;
+ if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
+ struct gen_ivtbl *ivtbl;
+ rb_ivar_generic_ivtbl_lookup(obj, &ivtbl);
+ for (uint32_t i = 0; i < ivtbl->numiv; i++) {
+ VALUE val = ivtbl->ivptr[i];
+ if (!UNDEF_P(val) && obj_traverse_i(val, data)) return 1;
+ }
+ }
switch (BUILTIN_TYPE(obj)) {
// no child node
@@ -2880,7 +2320,25 @@ obj_traverse_i(VALUE obj, struct obj_traverse_data *data)
break;
case T_OBJECT:
- /* Instance variables already traversed. */
+ {
+ if (rb_shape_obj_too_complex(obj)) {
+ struct obj_traverse_callback_data d = {
+ .stop = false,
+ .data = data,
+ };
+ rb_st_foreach(ROBJECT_IV_HASH(obj), obj_hash_iv_traverse_i, (st_data_t)&d);
+ if (d.stop) return 1;
+ }
+ else {
+ uint32_t len = ROBJECT_IV_COUNT(obj);
+ VALUE *ptr = ROBJECT_IVPTR(obj);
+
+ for (uint32_t i=0; i<len; i++) {
+ VALUE val = ptr[i];
+ if (!UNDEF_P(val) && obj_traverse_i(val, data)) return 1;
+ }
+ }
+ }
break;
case T_ARRAY:
@@ -3029,7 +2487,7 @@ make_shareable_check_shareable(VALUE obj)
if (rb_ractor_shareable_p(obj)) {
return traverse_skip;
}
- if (!frozen_shareable_p(obj, &made_shareable)) {
+ else if (!frozen_shareable_p(obj, &made_shareable)) {
if (made_shareable) {
return traverse_skip;
}
@@ -3073,7 +2531,10 @@ VALUE
rb_ractor_make_shareable_copy(VALUE obj)
{
VALUE copy = ractor_copy(obj);
- return rb_ractor_make_shareable(copy);
+ rb_obj_traverse(copy,
+ make_shareable_check_shareable,
+ null_leave, mark_shareable);
+ return copy;
}
VALUE
@@ -3116,7 +2577,7 @@ shareable_p_enter(VALUE obj)
return traverse_stop; // fail
}
-bool
+MJIT_FUNC_EXPORTED bool
rb_ractor_shareable_p_continue(VALUE obj)
{
if (rb_obj_traverse(obj,
@@ -3130,12 +2591,6 @@ rb_ractor_shareable_p_continue(VALUE obj)
}
#if RACTOR_CHECK_MODE > 0
-void
-rb_ractor_setup_belonging(VALUE obj)
-{
- rb_ractor_setup_belonging_to(obj, rb_ractor_current_id());
-}
-
static enum obj_traverse_iterator_result
reset_belonging_enter(VALUE obj)
{
@@ -3255,18 +2710,25 @@ obj_traverse_replace_rec(struct obj_traverse_replace_data *data)
{
if (UNLIKELY(!data->rec)) {
data->rec_hash = rb_ident_hash_new();
- data->rec = RHASH_ST_TABLE(data->rec_hash);
+ data->rec = rb_hash_st_table(data->rec_hash);
}
return data->rec;
}
+#if USE_TRANSIENT_HEAP
+void rb_ary_transient_heap_evacuate(VALUE ary, int promote);
+void rb_obj_transient_heap_evacuate(VALUE obj, int promote);
+void rb_hash_transient_heap_evacuate(VALUE hash, int promote);
+void rb_struct_transient_heap_evacuate(VALUE st, int promote);
+#endif
+
static void
obj_refer_only_shareables_p_i(VALUE obj, void *ptr)
{
int *pcnt = (int *)ptr;
if (!rb_ractor_shareable_p(obj)) {
- ++*pcnt;
+ *pcnt++;
}
}
@@ -3321,26 +2783,9 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
if (UNLIKELY(FL_TEST_RAW(obj, FL_EXIVAR))) {
struct gen_ivtbl *ivtbl;
rb_ivar_generic_ivtbl_lookup(obj, &ivtbl);
-
- if (UNLIKELY(rb_shape_obj_too_complex(obj))) {
- struct obj_traverse_replace_callback_data d = {
- .stop = false,
- .data = data,
- .src = obj,
- };
- rb_st_foreach_with_replace(
- ivtbl->as.complex.table,
- obj_iv_hash_traverse_replace_foreach_i,
- obj_iv_hash_traverse_replace_i,
- (st_data_t)&d
- );
- if (d.stop) return 1;
- }
- else {
- for (uint32_t i = 0; i < ivtbl->as.shape.numiv; i++) {
- if (!UNDEF_P(ivtbl->as.shape.ivptr[i])) {
- CHECK_AND_REPLACE(ivtbl->as.shape.ivptr[i]);
- }
+ for (uint32_t i = 0; i < ivtbl->numiv; i++) {
+ if (!UNDEF_P(ivtbl->ivptr[i])) {
+ CHECK_AND_REPLACE(ivtbl->ivptr[i]);
}
}
}
@@ -3361,25 +2806,30 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_OBJECT:
{
if (rb_shape_obj_too_complex(obj)) {
+ st_table * table = ROBJECT_IV_HASH(obj);
struct obj_traverse_replace_callback_data d = {
.stop = false,
.data = data,
.src = obj,
};
rb_st_foreach_with_replace(
- ROBJECT_IV_HASH(obj),
- obj_iv_hash_traverse_replace_foreach_i,
- obj_iv_hash_traverse_replace_i,
- (st_data_t)&d
- );
- if (d.stop) return 1;
+ table,
+ obj_iv_hash_traverse_replace_foreach_i,
+ obj_iv_hash_traverse_replace_i,
+ (st_data_t)&d);
}
else {
+#if USE_TRANSIENT_HEAP
+ if (data->move) rb_obj_transient_heap_evacuate(obj, TRUE);
+#endif
+
uint32_t len = ROBJECT_IV_COUNT(obj);
VALUE *ptr = ROBJECT_IVPTR(obj);
- for (uint32_t i = 0; i < len; i++) {
- CHECK_AND_REPLACE(ptr[i]);
+ for (uint32_t i=0; i<len; i++) {
+ if (!UNDEF_P(ptr[i])) {
+ CHECK_AND_REPLACE(ptr[i]);
+ }
}
}
}
@@ -3388,6 +2838,9 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_ARRAY:
{
rb_ary_cancel_sharing(obj);
+#if USE_TRANSIENT_HEAP
+ if (data->move) rb_ary_transient_heap_evacuate(obj, TRUE);
+#endif
for (int i = 0; i < RARRAY_LENINT(obj); i++) {
VALUE e = rb_ary_entry(obj, i);
@@ -3402,8 +2855,12 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
RB_GC_GUARD(obj);
}
break;
+
case T_HASH:
{
+#if USE_TRANSIENT_HEAP
+ if (data->move) rb_hash_transient_heap_evacuate(obj, TRUE);
+#endif
struct obj_traverse_replace_callback_data d = {
.stop = false,
.data = data,
@@ -3428,6 +2885,9 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
case T_STRUCT:
{
+#if USE_TRANSIENT_HEAP
+ if (data->move) rb_struct_transient_heap_evacuate(obj, TRUE);
+#endif
long len = RSTRUCT_LEN(obj);
const VALUE *ptr = RSTRUCT_CONST_PTR(obj);
@@ -3528,8 +2988,6 @@ ractor_moved_bang(VALUE obj)
rv->v3 = 0;
rv->flags = rv->flags & ~fl_users;
- if (BUILTIN_TYPE(obj) == T_OBJECT) ROBJECT_SET_SHAPE_ID(obj, ROOT_SHAPE_ID);
-
// TODO: record moved location
}
@@ -3541,9 +2999,7 @@ move_enter(VALUE obj, struct obj_traverse_replace_data *data)
return traverse_skip;
}
else {
- VALUE moved = rb_obj_alloc(RBASIC_CLASS(obj));
- rb_shape_set_shape(moved, rb_shape_get_shape(obj));
- data->replacement = moved;
+ data->replacement = rb_obj_alloc(RBASIC_CLASS(obj));
return traverse_cont;
}
}
diff --git a/ractor.rb b/ractor.rb
index d18062ca07..1031fe499b 100644
--- a/ractor.rb
+++ b/ractor.rb
@@ -1,56 +1,51 @@
-# \Ractor is an Actor-model abstraction for Ruby that provides thread-safe parallel execution.
+# Ractor is an Actor-model abstraction for Ruby that provides thread-safe parallel execution.
#
-# Ractor.new makes a new \Ractor, which can run in parallel.
+# Ractor.new can make a new Ractor, and it will run in parallel.
#
# # The simplest ractor
# r = Ractor.new {puts "I am in Ractor!"}
# r.take # wait for it to finish
-# # Here, "I am in Ractor!" is printed
+# # here "I am in Ractor!" would be printed
#
-# Ractors do not share all objects with each other. There are two main benefits to this: across ractors, thread-safety
-# concerns such as data-races and race-conditions are not possible. The other benefit is parallelism.
+# Ractors do not share usual objects, so the same kinds of thread-safety concerns such as data-race,
+# race-conditions are not available on multi-ractor programming.
#
-# To achieve this, object sharing is limited across ractors.
-# For example, unlike in threads, ractors can't access all the objects available in other ractors. Even objects normally
-# available through variables in the outer scope are prohibited from being used across ractors.
+# To achieve this, ractors severely limit object sharing between different ractors.
+# For example, unlike threads, ractors can't access each other's objects, nor any objects through
+# variables of the outer scope.
#
# a = 1
# r = Ractor.new {puts "I am in Ractor! a=#{a}"}
# # fails immediately with
# # ArgumentError (can not isolate a Proc because it accesses outer variables (a).)
#
-# The object must be explicitly shared:
-# a = 1
-# r = Ractor.new(a) { |a1| puts "I am in Ractor! a=#{a1}"}
-#
# On CRuby (the default implementation), Global Virtual Machine Lock (GVL) is held per ractor, so
-# ractors can perform in parallel without locking each other. This is unlike the situation with threads
-# on CRuby.
+# ractors are performed in parallel without locking each other.
#
-# Instead of accessing shared state, objects should be passed to and from ractors by
-# sending and receiving them as messages.
+# Instead of accessing the shared state, the objects should be passed to and from ractors via
+# sending and receiving objects as messages.
#
# a = 1
# r = Ractor.new do
-# a_in_ractor = receive # receive blocks until somebody passes a message
+# a_in_ractor = receive # receive blocks till somebody will pass message
# puts "I am in Ractor! a=#{a_in_ractor}"
# end
# r.send(a) # pass it
# r.take
-# # Here, "I am in Ractor! a=1" is printed
+# # here "I am in Ractor! a=1" would be printed
#
# There are two pairs of methods for sending/receiving messages:
#
# * Ractor#send and Ractor.receive for when the _sender_ knows the receiver (push);
# * Ractor.yield and Ractor#take for when the _receiver_ knows the sender (pull);
#
-# In addition to that, any arguments passed to Ractor.new are passed to the block and available there
-# as if received by Ractor.receive, and the last block value is sent outside of the
+# In addition to that, an argument to Ractor.new would be passed to block and available there
+# as if received by Ractor.receive, and the last block value would be sent outside of the
# ractor as if sent by Ractor.yield.
#
-# A little demonstration of a classic ping-pong:
+# A little demonstration on a classic ping-pong:
#
-# server = Ractor.new(name: "server") do
+# server = Ractor.new do
# puts "Server starts: #{self.inspect}"
# puts "Server sends: ping"
# Ractor.yield 'ping' # The server doesn't know the receiver and sends to whoever interested
@@ -58,48 +53,44 @@
# puts "Server received: #{received}"
# end
#
-# client = Ractor.new(server) do |srv| # The server is sent to the client, and available as srv
+# client = Ractor.new(server) do |srv| # The server is sent inside client, and available as srv
# puts "Client starts: #{self.inspect}"
-# received = srv.take # The client takes a message from the server
+# received = srv.take # The Client takes a message specifically from the server
# puts "Client received from " \
# "#{srv.inspect}: #{received}"
# puts "Client sends to " \
# "#{srv.inspect}: pong"
-# srv.send 'pong' # The client sends a message to the server
+# srv.send 'pong' # The client sends a message specifically to the server
# end
#
-# [client, server].each(&:take) # Wait until they both finish
+# [client, server].each(&:take) # Wait till they both finish
#
-# This will output something like:
+# This will output:
#
-# Server starts: #<Ractor:#2 server test.rb:1 running>
+# Server starts: #<Ractor:#2 test.rb:1 running>
# Server sends: ping
# Client starts: #<Ractor:#3 test.rb:8 running>
-# Client received from #<Ractor:#2 server test.rb:1 blocking>: ping
-# Client sends to #<Ractor:#2 server test.rb:1 blocking>: pong
+# Client received from #<Ractor:#2 rac.rb:1 blocking>: ping
+# Client sends to #<Ractor:#2 rac.rb:1 blocking>: pong
# Server received: pong
#
-# Ractors receive their messages via the <em>incoming port</em>, and send them
+# It is said that Ractor receives messages via the <em>incoming port</em>, and sends them
# to the <em>outgoing port</em>. Either one can be disabled with Ractor#close_incoming and
-# Ractor#close_outgoing, respectively. When a ractor terminates, its ports are closed
+# Ractor#close_outgoing respectively. If a ractor terminated, its ports will be closed
# automatically.
#
# == Shareable and unshareable objects
#
-# When an object is sent to and from a ractor, it's important to understand whether the
-# object is shareable or unshareable. Most Ruby objects are unshareable objects. Even
-# frozen objects can be unshareable if they contain (through their instance variables) unfrozen
-# objects.
+# When the object is sent to and from the ractor, it is important to understand whether the
+# object is shareable or unshareable. Most of objects are unshareable objects.
#
-# Shareable objects are those which can be used by several threads without compromising
-# thread-safety, for example numbers, +true+ and +false+. Ractor.shareable? allows you to check this,
-# and Ractor.make_shareable tries to make the object shareable if it's not already, and gives an error
-# if it can't do it.
+# Shareable objects are basically those which can be used by several threads without compromising
+# thread-safety; e.g. immutable ones. Ractor.shareable? allows to check this, and Ractor.make_shareable
+# tries to make object shareable if it is not.
#
-# Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are shareable
-# Ractor.shareable?('foo') #=> false, unless the string is frozen due to # frozen_string_literal: true
+# Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are
+# Ractor.shareable?('foo') #=> false, unless the string is frozen due to # freeze_string_literals: true
# Ractor.shareable?('foo'.freeze) #=> true
-# Ractor.shareable?([Object.new].freeze) #=> false, inner object is unfrozen
#
# ary = ['hello', 'world']
# ary.frozen? #=> false
@@ -109,10 +100,10 @@
# ary[0].frozen? #=> true
# ary[1].frozen? #=> true
#
-# When a shareable object is sent (via #send or Ractor.yield), no additional processing occurs
-# on it. It just becomes usable by both ractors. When an unshareable object is sent, it can be
-# either _copied_ or _moved_. The first is the default, and it copies the object fully by
-# deep cloning (Object#clone) the non-shareable parts of its structure.
+# When a shareable object is sent (via #send or Ractor.yield), no additional processing happens,
+# and it just becomes usable by both ractors. When an unshareable object is sent, it can be
+# either _copied_ or _moved_. The first is the default, and it makes the object's full copy by
+# deep cloning of non-shareable parts of its structure.
#
# data = ['foo', 'bar'.freeze]
# r = Ractor.new do
@@ -123,18 +114,18 @@
# r.take
# puts "Outside : #{data.object_id}, #{data[0].object_id}, #{data[1].object_id}"
#
-# This will output something like:
+# This will output:
#
# In ractor: 340, 360, 320
# Outside : 380, 400, 320
#
-# Note that the object ids of the array and the non-frozen string inside the array have changed in
-# the ractor because they are different objects. The second array's element, which is a
-# shareable frozen string, is the same object.
+# (Note that object id of both array and non-frozen string inside array have changed inside
+# the ractor, showing it is different objects. But the second array's element, which is a
+# shareable frozen string, has the same object_id.)
#
-# Deep cloning of objects may be slow, and sometimes impossible. Alternatively, <tt>move: true</tt> may
-# be used during sending. This will <em>move</em> the unshareable object to the receiving ractor, making it
-# inaccessible to the sending ractor.
+# Deep cloning of the objects may be slow, and sometimes impossible. Alternatively,
+# <tt>move: true</tt> may be used on sending. This will <em>move</em> the object to the
+# receiving ractor, making it inaccessible for a sending ractor.
#
# data = ['foo', 'bar']
# r = Ractor.new do
@@ -155,14 +146,13 @@
# Notice that even +inspect+ (and more basic methods like <tt>__id__</tt>) is inaccessible
# on a moved object.
#
-# Class and Module objects are shareable so the class/module definitions are shared between ractors.
-# \Ractor objects are also shareable. All operations on shareable objects are thread-safe, so the thread-safety property
+# Besides frozen objects, there are shareable objects. Class and Module objects are shareable so
+# the Class/Module definitions are shared between ractors. Ractor objects are also shareable objects.
+# All operations for the shareable mutable objects are thread-safe, so the thread-safety property
# will be kept. We can not define mutable shareable objects in Ruby, but C extensions can introduce them.
#
-# It is prohibited to access (get) instance variables of shareable objects in other ractors if the values of the
-# variables aren't shareable. This can occur because modules/classes are shareable, but they can have
-# instance variables whose values are not. In non-main ractors, it's also prohibited to set instance
-# variables on classes/modules (even if the value is shareable).
+# It is prohibited to access instance variables of mutable shareable objects (especially Modules and classes)
+# from ractors other than main:
#
# class C
# class << self
@@ -170,22 +160,21 @@
# end
# end
#
-# C.tricky = "unshareable".dup
+# C.tricky = 'test'
#
# r = Ractor.new(C) do |cls|
# puts "I see #{cls}"
# puts "I can't see #{cls.tricky}"
-# cls.tricky = true # doesn't get here, but this would also raise an error
# end
# r.take
# # I see C
# # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
#
-# Ractors can access constants if they are shareable. The main \Ractor is the only one that can
+# Ractors can access constants if they are shareable. The main Ractor is the only one that can
# access non-shareable constants.
#
# GOOD = 'good'.freeze
-# BAD = 'bad'.dup
+# BAD = 'bad'
#
# r = Ractor.new do
# puts "GOOD=#{GOOD}"
@@ -210,8 +199,8 @@
#
# == Ractors vs threads
#
-# Each ractor has its own main Thread. New threads can be created from inside ractors
-# (and, on CRuby, they share the GVL with other threads of this ractor).
+# Each ractor creates its own thread. New threads can be created from inside ractor
+# (and, on CRuby, sharing GVL with other threads of this ractor).
#
# r = Ractor.new do
# a = 1
@@ -222,15 +211,15 @@
#
# == Note on code examples
#
-# In the examples below, sometimes we use the following method to wait for ractors that
-# are not currently blocked to finish (or to make progress).
+# In examples below, sometimes we use the following method to wait till ractors that
+# are not currently blocked will finish (or process till next blocking) method.
#
# def wait
# sleep(0.1)
# end
#
# It is **only for demonstration purposes** and shouldn't be used in a real code.
-# Most of the time, #take is used to wait for ractors to finish.
+# Most of the times, just #take is used to wait till ractor will finish.
#
# == Reference
#
@@ -241,17 +230,17 @@ class Ractor
# call-seq:
# Ractor.new(*args, name: nil) {|*args| block } -> ractor
#
- # Create a new \Ractor with args and a block.
+ # Create a new Ractor with args and a block.
#
- # The given block (Proc) will be isolated (can't access any outer variables). +self+
- # inside the block will refer to the current \Ractor.
+ # A block (Proc) will be isolated (can't access to outer variables). +self+
+ # inside the block will refer to the current Ractor.
#
# r = Ractor.new { puts "Hi, I am #{self.inspect}" }
# r.take
# # Prints "Hi, I am #<Ractor:#2 test.rb:1 running>"
#
- # Any +args+ passed are propagated to the block arguments by the same rules as
- # objects sent via #send/Ractor.receive. If an argument in +args+ is not shareable, it
+ # +args+ passed to the method would be propagated to block args by the same rules as
+ # objects passed through #send/Ractor.receive: if +args+ are not shareable, they
# will be copied (via deep cloning, which might be inefficient).
#
# arg = [1, 2, 3]
@@ -266,7 +255,7 @@ class Ractor
#
# Ractor's +name+ can be set for debugging purposes:
#
- # r = Ractor.new(name: 'my ractor') {}; r.take
+ # r = Ractor.new(name: 'my ractor') {}
# p r
# #=> #<Ractor:#3 my ractor test.rb:1 terminated>
#
@@ -291,13 +280,13 @@ class Ractor
}
end
- # Returns the number of Ractors currently running or blocking (waiting).
+ # Returns total count of Ractors currently running.
#
# Ractor.count #=> 1
# r = Ractor.new(name: 'example') { Ractor.yield(1) }
# Ractor.count #=> 2 (main + example ractor)
# r.take # wait for Ractor.yield(1)
- # r.take # wait until r will finish
+ # r.take # wait till r will finish
# Ractor.count #=> 1
def self.count
__builtin_cexpr! %q{
@@ -309,8 +298,8 @@ class Ractor
# call-seq:
# Ractor.select(*ractors, [yield_value:, move: false]) -> [ractor or symbol, obj]
#
- # Wait for any ractor to have something in its outgoing port, read from this ractor, and
- # then return that ractor and the object received.
+ # Waits for the first ractor to have something in its outgoing port, reads from this ractor, and
+ # returns that ractor and the object received.
#
# r1 = Ractor.new {Ractor.yield 'from 1'}
# r2 = Ractor.new {Ractor.yield 'from 2'}
@@ -319,10 +308,9 @@ class Ractor
#
# puts "received #{obj.inspect} from #{r.inspect}"
# # Prints: received "from 1" from #<Ractor:#2 test.rb:1 running>
- # # But could just as well print "from r2" here, either prints could be first.
#
- # If one of the given ractors is the current ractor, and it is selected, +r+ will contain
- # the +:receive+ symbol instead of the ractor object.
+ # If one of the given ractors is the current ractor, and it would be selected, +r+ will contain
+ # +:receive+ symbol instead of the ractor object.
#
# r1 = Ractor.new(Ractor.current) do |main|
# main.send 'to main'
@@ -334,10 +322,10 @@ class Ractor
#
# r, obj = Ractor.select(r1, r2, Ractor.current)
# puts "received #{obj.inspect} from #{r.inspect}"
- # # Could print: received "to main" from :receive
+ # # Prints: received "to main" from :receive
#
- # If +yield_value+ is provided, that value may be yielded if another ractor is calling #take.
- # In this case, the pair <tt>[:yield, nil]</tt> is returned:
+ # If +yield_value+ is provided, that value may be yielded if another Ractor is calling #take.
+ # In this case, the pair <tt>[:yield, nil]</tt> would be returned:
#
# r1 = Ractor.new(Ractor.current) do |main|
# puts "Received from main: #{main.take}"
@@ -354,25 +342,26 @@ class Ractor
# Received from main: 123
# Received nil from :yield
#
- # +move+ boolean flag defines whether yielded value will be copied (default) or moved.
+ # +move+ boolean flag defines whether yielded value should be copied (default) or moved.
def self.select(*ractors, yield_value: yield_unspecified = true, move: false)
raise ArgumentError, 'specify at least one ractor or `yield_value`' if yield_unspecified && ractors.empty?
- if ractors.delete Ractor.current
- do_receive = true
- else
- do_receive = false
- end
-
- __builtin_ractor_select_internal ractors, do_receive, !yield_unspecified, yield_value, move
+ __builtin_cstmt! %q{
+ const VALUE *rs = RARRAY_CONST_PTR_TRANSIENT(ractors);
+ VALUE rv;
+ VALUE v = ractor_select(ec, rs, RARRAY_LENINT(ractors),
+ yield_unspecified == Qtrue ? Qundef : yield_value,
+ (bool)RTEST(move) ? true : false, &rv);
+ return rb_ary_new_from_args(2, rv, v);
+ }
end
#
# call-seq:
# Ractor.receive -> msg
#
- # Receive a message from the incoming port of the current ractor (which was
- # sent there by #send from another ractor).
+ # Receive an incoming message from the current Ractor's incoming port's queue, which was
+ # sent there by #send.
#
# r = Ractor.new do
# v1 = Ractor.receive
@@ -382,7 +371,7 @@ class Ractor
# r.take
# # Here will be printed: "Received: message1"
#
- # Alternatively, the private instance method +receive+ may be used:
+ # Alternatively, private instance method +receive+ may be used:
#
# r = Ractor.new do
# v1 = receive
@@ -390,7 +379,7 @@ class Ractor
# end
# r.send('message1')
# r.take
- # # This prints: "Received: message1"
+ # # Here will be printed: "Received: message1"
#
# The method blocks if the queue is empty.
#
@@ -418,7 +407,7 @@ class Ractor
# Received: message2
#
# If close_incoming was called on the ractor, the method raises Ractor::ClosedError
- # if there are no more messages in the incoming queue:
+ # if there are no more messages in incoming queue:
#
# Ractor.new do
# close_incoming
@@ -451,9 +440,8 @@ class Ractor
#
# Receive only a specific message.
#
- # Instead of Ractor.receive, Ractor.receive_if can be given a pattern (or any
- # filter) in a block and you can choose the messages to accept that are available in
- # your ractor's incoming queue.
+ # Instead of Ractor.receive, Ractor.receive_if can provide a pattern
+ # by a block and you can choose the receiving message.
#
# r = Ractor.new do
# p Ractor.receive_if{|msg| msg.match?(/foo/)} #=> "foo3"
@@ -471,10 +459,10 @@ class Ractor
# bar1
# baz2
#
- # If the block returns a truthy value, the message is removed from the incoming queue
+ # If the block returns a truthy value, the message will be removed from the incoming queue
# and returned.
- # Otherwise, the message remains in the incoming queue and the next messages are checked
- # by the given block.
+ # Otherwise, the message remains in the incoming queue and the following received
+ # messages are checked by the given block.
#
# If there are no messages left in the incoming queue, the method will
# block until new messages arrive.
@@ -500,7 +488,7 @@ class Ractor
# Received successfully: [1, 2, 3]
#
# Note that you can not call receive/receive_if in the given block recursively.
- # You should not do any tasks in the block other than message filtration.
+ # It means that you should not do any tasks in the block.
#
# Ractor.current << true
# Ractor.receive_if{|msg| Ractor.receive}
@@ -510,7 +498,6 @@ class Ractor
Primitive.ractor_receive_if b
end
- # same as Ractor.receive_if
private def receive_if &b
Primitive.ractor_receive_if b
end
@@ -519,7 +506,7 @@ class Ractor
# call-seq:
# ractor.send(msg, move: false) -> self
#
- # Send a message to a Ractor's incoming queue to be accepted by Ractor.receive.
+ # Send a message to a Ractor's incoming queue to be consumed by Ractor.receive.
#
# r = Ractor.new do
# value = Ractor.receive
@@ -536,7 +523,7 @@ class Ractor
# puts "Sent successfully"
# # Prints: "Sent successfully" immediately
#
- # An attempt to send to a ractor which already finished its execution will raise Ractor::ClosedError.
+ # Attempt to send to ractor which already finished its execution will raise Ractor::ClosedError.
#
# r = Ractor.new {}
# r.take
@@ -554,11 +541,11 @@ class Ractor
# r.close_incoming
# r.send('test')
# # Ractor::ClosedError (The incoming-port is already closed)
- # # The error is raised immediately, not when the ractor tries to receive
+ # # The error would be raised immediately, not when ractor will try to receive
#
- # If the +obj+ is unshareable, by default it will be copied into the receiving ractor by deep cloning.
- # If <tt>move: true</tt> is passed, the object is _moved_ into the receiving ractor and becomes
- # inaccessible to the sender.
+ # If the +obj+ is unshareable, by default it would be copied into ractor by deep cloning.
+ # If the <tt>move: true</tt> is passed, object is _moved_ into ractor and becomes
+ # inaccessible to sender.
#
# r = Ractor.new {puts "Received: #{receive}"}
# msg = 'message'
@@ -571,7 +558,7 @@ class Ractor
# Received: message
# in `p': undefined method `inspect' for #<Ractor::MovedObject:0x000055c99b9b69b8>
#
- # All references to the object and its parts will become invalid to the sender.
+ # All references to the object and its parts will become invalid in sender.
#
# r = Ractor.new {puts "Received: #{receive}"}
# s = 'message'
@@ -589,7 +576,7 @@ class Ractor
# # Ractor::MovedError (can not send any methods to a moved object)
# # ...but its item was still a reference to `s`, which was moved
#
- # If the object is shareable, <tt>move: true</tt> has no effect on it:
+ # If the object was shareable, <tt>move: true</tt> has no effect on it:
#
# r = Ractor.new {puts "Received: #{receive}"}
# s = 'message'.freeze
@@ -607,13 +594,13 @@ class Ractor
# call-seq:
# Ractor.yield(msg, move: false) -> nil
#
- # Send a message to the current ractor's outgoing port to be accepted by #take.
+ # Send a message to the current ractor's outgoing port to be consumed by #take.
#
# r = Ractor.new {Ractor.yield 'Hello from ractor'}
# puts r.take
# # Prints: "Hello from ractor"
#
- # This method is blocking, and will return only when somebody consumes the
+ # The method is blocking, and will return only when somebody consumes the
# sent message.
#
# r = Ractor.new do
@@ -639,7 +626,7 @@ class Ractor
# wait
# # `yield': The outgoing-port is already closed (Ractor::ClosedError)
#
- # The meaning of the +move+ argument is the same as for #send.
+ # The meaning of +move+ argument is the same as for #send.
def self.yield(obj, move: false)
__builtin_cexpr! %q{
ractor_yield(ec, rb_ec_ractor_ptr(ec), obj, move)
@@ -650,8 +637,8 @@ class Ractor
# call-seq:
# ractor.take -> msg
#
- # Get a message from the ractor's outgoing port, which was put there by Ractor.yield or at ractor's
- # termination.
+ # Take a message from ractor's outgoing port, which was put there by Ractor.yield or at ractor's
+ # finalization.
#
# r = Ractor.new do
# Ractor.yield 'explicit yield'
@@ -661,9 +648,9 @@ class Ractor
# puts r.take #=> 'last value'
# puts r.take # Ractor::ClosedError (The outgoing-port is already closed)
#
- # The fact that the last value is also sent to the outgoing port means that +take+ can be used
- # as an analog of Thread#join ("just wait until ractor finishes"). However, it will raise if
- # somebody has already consumed that message.
+ # The fact that the last value is also put to outgoing port means that +take+ can be used
+ # as some analog of Thread#join ("just wait till ractor finishes"), but don't forget it
+ # will raise if somebody had already consumed everything ractor have produced.
#
# If the outgoing port was closed with #close_outgoing, the method will raise Ractor::ClosedError.
#
@@ -676,7 +663,7 @@ class Ractor
# # Ractor::ClosedError (The outgoing-port is already closed)
# # The error would be raised immediately, not when ractor will try to receive
#
- # If an uncaught exception is raised in the Ractor, it is propagated by take as a
+ # If an uncaught exception is raised in the Ractor, it is propagated on take as a
# Ractor::RemoteError.
#
# r = Ractor.new {raise "Something weird happened"}
@@ -689,8 +676,8 @@ class Ractor
# p e.cause # => #<RuntimeError: Something weird happened>
# end
#
- # Ractor::ClosedError is a descendant of StopIteration, so the termination of the ractor will break
- # out of any loops that receive this message without propagating the error:
+ # Ractor::ClosedError is a descendant of StopIteration, so the closing of the ractor will break
+ # the loops without propagating the error:
#
# r = Ractor.new do
# 3.times {|i| Ractor.yield "message #{i}"}
@@ -738,8 +725,9 @@ class Ractor
# call-seq:
# ractor.close_incoming -> true | false
#
- # Closes the incoming port and returns whether it was already closed. All further attempts
- # to Ractor.receive in the ractor, and #send to the ractor will fail with Ractor::ClosedError.
+ # Closes the incoming port and returns its previous state.
+ # All further attempts to Ractor.receive in the ractor, and #send to the ractor
+ # will fail with Ractor::ClosedError.
#
# r = Ractor.new {sleep(500)}
# r.close_incoming #=> false
@@ -756,8 +744,9 @@ class Ractor
# call-seq:
# ractor.close_outgoing -> true | false
#
- # Closes the outgoing port and returns whether it was already closed. All further attempts
- # to Ractor.yield in the ractor, and #take from the ractor will fail with Ractor::ClosedError.
+ # Closes the outgoing port and returns its previous state.
+ # All further attempts to Ractor.yield in the ractor, and #take from the ractor
+ # will fail with Ractor::ClosedError.
#
# r = Ractor.new {sleep(500)}
# r.close_outgoing #=> false
@@ -777,10 +766,10 @@ class Ractor
# Checks if the object is shareable by ractors.
#
# Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are frozen
- # Ractor.shareable?('foo') #=> false, unless the string is frozen due to # frozen_string_literal: true
+ # Ractor.shareable?('foo') #=> false, unless the string is frozen due to # freeze_string_literals: true
# Ractor.shareable?('foo'.freeze) #=> true
#
- # See also the "Shareable and unshareable objects" section in the \Ractor class docs.
+ # See also the "Shareable and unshareable objects" section in the Ractor class docs.
def self.shareable? obj
__builtin_cexpr! %q{
RBOOL(rb_ractor_shareable_p(obj));
@@ -796,8 +785,8 @@ class Ractor
# +obj+ and all the objects it refers to will be frozen, unless they are
# already shareable.
#
- # If +copy+ keyword is +true+, it will copy objects before freezing them, and will not
- # modify +obj+ or its internal objects.
+ # If +copy+ keyword is +true+, the method will copy objects before freezing them
+ # This is safer option but it can take be slower.
#
# Note that the specification and implementation of this method are not
# mature and may be changed in the future.
diff --git a/ractor_core.h b/ractor_core.h
index fd3cba3a1f..968c12d291 100644
--- a/ractor_core.h
+++ b/ractor_core.h
@@ -1,4 +1,3 @@
-#include "internal/gc.h"
#include "ruby/ruby.h"
#include "ruby/ractor.h"
#include "vm_core.h"
@@ -10,66 +9,22 @@
#endif
enum rb_ractor_basket_type {
- // basket is empty
basket_type_none,
-
- // value is available
basket_type_ref,
basket_type_copy,
basket_type_move,
basket_type_will,
-
- // basket should be deleted
basket_type_deleted,
-
- // basket is reserved
basket_type_reserved,
-
- // take_basket is available
- basket_type_take_basket,
-
- // basket is keeping by yielding ractor
- basket_type_yielding,
-};
-
-// per ractor taking configuration
-struct rb_ractor_selector_take_config {
- bool closed;
- bool oneshot;
};
struct rb_ractor_basket {
- union {
- enum rb_ractor_basket_type e;
- rb_atomic_t atomic;
- } type;
+ bool exception;
+ enum rb_ractor_basket_type type;
+ VALUE v;
VALUE sender;
-
- union {
- struct {
- VALUE v;
- bool exception;
- } send;
-
- struct {
- struct rb_ractor_basket *basket;
- struct rb_ractor_selector_take_config *config;
- } take;
- } p; // payload
};
-static inline bool
-basket_type_p(struct rb_ractor_basket *b, enum rb_ractor_basket_type type)
-{
- return b->type.e == type;
-}
-
-static inline bool
-basket_none_p(struct rb_ractor_basket *b)
-{
- return basket_type_p(b, basket_type_none);
-}
-
struct rb_ractor_queue {
struct rb_ractor_basket *baskets;
int start;
@@ -79,6 +34,12 @@ struct rb_ractor_queue {
unsigned int reserved_cnt;
};
+struct rb_ractor_waiting_list {
+ int cnt;
+ int size;
+ rb_ractor_t **ractors;
+};
+
enum rb_ractor_wait_status {
wait_none = 0x00,
wait_receiving = 0x01,
@@ -103,28 +64,21 @@ struct rb_ractor_sync {
#if RACTOR_CHECK_MODE > 0
VALUE locked_by;
#endif
+ rb_nativethread_cond_t cond;
+
+ // communication
+ struct rb_ractor_queue incoming_queue;
+ struct rb_ractor_waiting_list taking_ractors;
bool incoming_port_closed;
bool outgoing_port_closed;
- // All sent messages will be pushed into recv_queue
- struct rb_ractor_queue recv_queue;
-
- // The following ractors waiting for the yielding by this ractor
- struct rb_ractor_queue takers_queue;
-
- // Enabled if the ractor already terminated and not taken yet.
- struct rb_ractor_basket will_basket;
-
struct ractor_wait {
enum rb_ractor_wait_status status;
enum rb_ractor_wakeup_status wakeup_status;
- rb_thread_t *waiting_thread;
+ struct rb_ractor_basket yielded_basket;
+ struct rb_ractor_basket taken_basket;
} wait;
-
-#ifndef RUBY_THREAD_PTHREAD_H
- rb_nativethread_cond_t cond;
-#endif
};
// created
@@ -153,6 +107,7 @@ struct rb_ractor_struct {
struct rb_ractor_sync sync;
VALUE receiving_mutex;
+ bool yield_atexit;
// vm wide barrier synchronization
rb_nativethread_cond_t barrier_wait_cond;
@@ -187,7 +142,13 @@ struct rb_ractor_struct {
VALUE verbose;
VALUE debug;
- void *newobj_cache;
+ rb_ractor_newobj_cache_t newobj_cache;
+
+ // gc.c rb_objspace_reachable_objects_from
+ struct gc_mark_func_data_struct {
+ void *data;
+ void (*mark_func)(VALUE v, void *data);
+ } *mfd;
}; // rb_ractor_t is defined in vm_core.h
@@ -208,7 +169,7 @@ void rb_ractor_send_parameters(rb_execution_context_t *ec, rb_ractor_t *g, VALUE
VALUE rb_thread_create_ractor(rb_ractor_t *g, VALUE args, VALUE proc); // defined in thread.c
int rb_ractor_living_thread_num(const rb_ractor_t *);
-VALUE rb_ractor_thread_list(void);
+VALUE rb_ractor_thread_list(rb_ractor_t *r);
bool rb_ractor_p(VALUE rv);
void rb_ractor_living_threads_init(rb_ractor_t *r);
@@ -221,13 +182,12 @@ void rb_ractor_vm_barrier_interrupt_running_thread(rb_ractor_t *r);
void rb_ractor_terminate_interrupt_main_thread(rb_ractor_t *r);
void rb_ractor_terminate_all(void);
bool rb_ractor_main_p_(void);
+void rb_ractor_finish_marking(void);
void rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th);
VALUE rb_ractor_ensure_shareable(VALUE obj, VALUE name);
RUBY_SYMBOL_EXPORT_BEGIN
-void rb_ractor_finish_marking(void);
-
bool rb_ractor_shareable_p_continue(VALUE obj);
// THIS FUNCTION SHOULD NOT CALL WHILE INCREMENTAL MARKING!!
@@ -280,10 +240,6 @@ rb_ractor_sleeper_thread_num(rb_ractor_t *r)
static inline void
rb_ractor_thread_switch(rb_ractor_t *cr, rb_thread_t *th)
{
- RUBY_DEBUG_LOG("th:%d->%u%s",
- cr->threads.running_ec ? (int)rb_th_serial(cr->threads.running_ec->thread_ptr) : -1,
- rb_th_serial(th), cr->threads.running_ec == th->ec ? " (same)" : "");
-
if (cr->threads.running_ec != th->ec) {
if (0) {
ruby_debug_printf("rb_ractor_thread_switch ec:%p->%p\n",
@@ -309,18 +265,16 @@ static inline void
rb_ractor_set_current_ec_(rb_ractor_t *cr, rb_execution_context_t *ec, const char *file, int line)
{
#ifdef RB_THREAD_LOCAL_SPECIFIER
-
-# ifdef __APPLE__
+ #ifdef __APPLE__
rb_current_ec_set(ec);
-# else
+ #else
ruby_current_ec = ec;
-# endif
-
+ #endif
#else
native_tls_set(ruby_current_ec_key, ec);
#endif
RUBY_DEBUG_LOG2(file, line, "ec:%p->%p", (void *)cr->threads.running_ec, (void *)ec);
- VM_ASSERT(ec == NULL || cr->threads.running_ec != ec);
+ VM_ASSERT(cr->threads.running_ec != ec);
cr->threads.running_ec = ec;
}
@@ -344,6 +298,12 @@ rb_ractor_setup_belonging_to(VALUE obj, uint32_t rid)
RACTOR_BELONGING_ID(obj) = rid;
}
+static inline void
+rb_ractor_setup_belonging(VALUE obj)
+{
+ rb_ractor_setup_belonging_to(obj, rb_ractor_current_id());
+}
+
static inline uint32_t
rb_ractor_belonging(VALUE obj)
{
diff --git a/random.c b/random.c
index 3619ad6e6e..4b5b7ab6c4 100644
--- a/random.c
+++ b/random.c
@@ -73,7 +73,7 @@
#include "ruby/random.h"
#include "ruby/ractor.h"
-STATIC_ASSERT(int_must_be_32bit_at_least, sizeof(int) * CHAR_BIT >= 32);
+typedef int int_must_be_32bit_at_least[sizeof(int) * CHAR_BIT < 32 ? -1 : 1];
#include "missing/mt19937.c"
@@ -131,9 +131,8 @@ typedef struct {
static VALUE rand_init(const rb_random_interface_t *, rb_random_t *, VALUE);
static VALUE random_seed(VALUE);
-static void fill_random_seed(uint32_t *seed, size_t cnt, bool try_bytes);
+static void fill_random_seed(uint32_t *seed, size_t cnt);
static VALUE make_seed_value(uint32_t *ptr, size_t len);
-#define fill_random_bytes ruby_fill_random_bytes
RB_RANDOM_INTERFACE_DECLARE(rand_mt);
static const rb_random_interface_t random_mt_if = {
@@ -158,12 +157,6 @@ rand_start(rb_random_mt_t *r)
static rb_ractor_local_key_t default_rand_key;
-void
-rb_free_default_rand_key(void)
-{
- xfree(default_rand_key);
-}
-
static void
default_rand_mark(void *ptr)
{
@@ -355,7 +348,7 @@ rand_init_default(const rb_random_interface_t *rng, rb_random_t *rnd)
size_t len = roomof(rng->default_seed_bits, 32);
uint32_t *buf = ALLOCV_N(uint32_t, buf0, len+1);
- fill_random_seed(buf, len, true);
+ fill_random_seed(buf, len);
rng->init(rnd, buf, len);
seed = make_seed_value(buf, len);
explicit_bzero(buf, len * sizeof(*buf));
@@ -567,6 +560,8 @@ fill_random_bytes_syscall(void *buf, size_t size, int unused)
#endif
# if defined(CRYPT_VERIFYCONTEXT)
+STATIC_ASSERT(sizeof_HCRYPTPROV, sizeof(HCRYPTPROV) == sizeof(size_t));
+
/* Although HCRYPTPROV is not a HANDLE, it looks like
* INVALID_HANDLE_VALUE is not a valid value */
static const HCRYPTPROV INVALID_HCRYPTPROV = (HCRYPTPROV)INVALID_HANDLE_VALUE;
@@ -575,33 +570,27 @@ static void
release_crypt(void *p)
{
HCRYPTPROV *ptr = p;
- HCRYPTPROV prov = (HCRYPTPROV)ATOMIC_PTR_EXCHANGE(*ptr, INVALID_HCRYPTPROV);
+ HCRYPTPROV prov = (HCRYPTPROV)ATOMIC_SIZE_EXCHANGE(*ptr, INVALID_HCRYPTPROV);
if (prov && prov != INVALID_HCRYPTPROV) {
CryptReleaseContext(prov, 0);
}
}
-static const rb_data_type_t crypt_prov_type = {
- "HCRYPTPROV",
- {0, release_crypt,},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE
-};
-
static int
fill_random_bytes_crypt(void *seed, size_t size)
{
static HCRYPTPROV perm_prov;
HCRYPTPROV prov = perm_prov, old_prov;
if (!prov) {
- VALUE wrapper = TypedData_Wrap_Struct(0, &crypt_prov_type, 0);
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
prov = INVALID_HCRYPTPROV;
}
- old_prov = (HCRYPTPROV)ATOMIC_PTR_CAS(perm_prov, 0, prov);
+ old_prov = (HCRYPTPROV)ATOMIC_SIZE_CAS(perm_prov, 0, prov);
if (LIKELY(!old_prov)) { /* no other threads acquired */
if (prov != INVALID_HCRYPTPROV) {
- DATA_PTR(wrapper) = (void *)prov;
- rb_vm_register_global_object(wrapper);
+#undef RUBY_UNTYPED_DATA_WARNING
+#define RUBY_UNTYPED_DATA_WARNING 0
+ rb_gc_register_mark_object(Data_Wrap_Struct(0, 0, release_crypt, &perm_prov));
}
}
else { /* another thread acquired */
@@ -678,9 +667,11 @@ ruby_fill_random_bytes(void *seed, size_t size, int need_secure)
return fill_random_bytes_urandom(seed, size);
}
+#define fill_random_bytes ruby_fill_random_bytes
+
/* cnt must be 4 or more */
static void
-fill_random_seed(uint32_t *seed, size_t cnt, bool try_bytes)
+fill_random_seed(uint32_t *seed, size_t cnt)
{
static rb_atomic_t n = 0;
#if defined HAVE_CLOCK_GETTIME
@@ -690,12 +681,10 @@ fill_random_seed(uint32_t *seed, size_t cnt, bool try_bytes)
#endif
size_t len = cnt * sizeof(*seed);
- if (try_bytes) {
- fill_random_bytes(seed, len, FALSE);
- return;
- }
-
memset(seed, 0, len);
+
+ fill_random_bytes(seed, len, FALSE);
+
#if defined HAVE_CLOCK_GETTIME
clock_gettime(CLOCK_REALTIME, &tv);
seed[0] ^= tv.tv_nsec;
@@ -730,8 +719,8 @@ make_seed_value(uint32_t *ptr, size_t len)
return seed;
}
-#define with_random_seed(size, add, try_bytes) \
- for (uint32_t seedbuf[(size)+(add)], loop = (fill_random_seed(seedbuf, (size), try_bytes), 1); \
+#define with_random_seed(size, add) \
+ for (uint32_t seedbuf[(size)+(add)], loop = (fill_random_seed(seedbuf, (size)), 1); \
loop; explicit_bzero(seedbuf, (size)*sizeof(seedbuf[0])), loop = 0)
/*
@@ -746,7 +735,7 @@ static VALUE
random_seed(VALUE _)
{
VALUE v;
- with_random_seed(DEFAULT_SEED_CNT, 1, true) {
+ with_random_seed(DEFAULT_SEED_CNT, 1) {
v = make_seed_value(seedbuf, DEFAULT_SEED_CNT);
}
return v;
@@ -1775,7 +1764,7 @@ Init_RandomSeedCore(void)
*/
struct MT mt;
- with_random_seed(DEFAULT_SEED_CNT, 0, false) {
+ with_random_seed(DEFAULT_SEED_CNT, 0) {
init_by_array(&mt, seedbuf, DEFAULT_SEED_CNT);
}
diff --git a/range.c b/range.c
index 4af5d4943e..dbc37c1410 100644
--- a/range.c
+++ b/range.c
@@ -34,7 +34,6 @@ static ID id_beg, id_end, id_excl;
#define id_succ idSucc
#define id_min idMin
#define id_max idMax
-#define id_plus '+'
static VALUE r_cover_p(VALUE, VALUE, VALUE, VALUE);
@@ -79,7 +78,7 @@ range_modify(VALUE range)
rb_check_frozen(range);
/* Ranges are immutable, so that they should be initialized only once. */
if (RANGE_EXCL(range) != Qnil) {
- rb_name_err_raise("'initialize' called twice", range, ID2SYM(idInitialize));
+ rb_name_err_raise("`initialize' called twice", range, ID2SYM(idInitialize));
}
}
@@ -225,8 +224,8 @@ recursive_eql(VALUE range, VALUE obj, int recur)
* Returns +true+ if and only if:
*
* - +other+ is a range.
- * - <tt>other.begin.eql?(self.begin)</tt>.
- * - <tt>other.end.eql?(self.end)</tt>.
+ * - <tt>other.begin eql? self.begin</tt>.
+ * - <tt>other.end eql? self.end</tt>.
* - <tt>other.exclude_end? == self.exclude_end?</tt>.
*
* Otherwise returns +false+.
@@ -309,9 +308,6 @@ range_each_func(VALUE range, int (*func)(VALUE, VALUE), VALUE arg)
}
}
-// NB: Two functions below (step_i_iter, sym_step_i and step_i) are used only to maintain the
-// backward-compatible behavior for string and symbol ranges with integer steps. If that branch
-// will be removed from range_step, these two can go, too.
static bool
step_i_iter(VALUE arg)
{
@@ -404,137 +400,72 @@ range_step_size(VALUE range, VALUE args, VALUE eobj)
/*
* call-seq:
- * step(s = 1) {|element| ... } -> self
- * step(s = 1) -> enumerator/arithmetic_sequence
+ * step(n = 1) {|element| ... } -> self
+ * step(n = 1) -> enumerator
*
- * Iterates over the elements of range in steps of +s+. The iteration is performed
- * by <tt>+</tt> operator:
+ * Iterates over the elements of +self+.
*
- * (0..6).step(2) { puts _1 } #=> 1..5
- * # Prints: 0, 2, 4, 6
+ * With a block given and no argument,
+ * calls the block each element of the range; returns +self+:
*
- * # Iterate between two dates in step of 1 day (24 hours)
- * (Time.utc(2022, 2, 24)..Time.utc(2022, 3, 1)).step(24*60*60) { puts _1 }
- * # Prints:
- * # 2022-02-24 00:00:00 UTC
- * # 2022-02-25 00:00:00 UTC
- * # 2022-02-26 00:00:00 UTC
- * # 2022-02-27 00:00:00 UTC
- * # 2022-02-28 00:00:00 UTC
- * # 2022-03-01 00:00:00 UTC
- *
- * If <tt> + step</tt> decreases the value, iteration is still performed when
- * step +begin+ is higher than the +end+:
- *
- * (0..6).step(-2) { puts _1 }
- * # Prints nothing
- *
- * (6..0).step(-2) { puts _1 }
- * # Prints: 6, 4, 2, 0
- *
- * (Time.utc(2022, 3, 1)..Time.utc(2022, 2, 24)).step(-24*60*60) { puts _1 }
- * # Prints:
- * # 2022-03-01 00:00:00 UTC
- * # 2022-02-28 00:00:00 UTC
- * # 2022-02-27 00:00:00 UTC
- * # 2022-02-26 00:00:00 UTC
- * # 2022-02-25 00:00:00 UTC
- * # 2022-02-24 00:00:00 UTC
- *
- * When the block is not provided, and range boundaries and step are Numeric,
- * the method returns Enumerator::ArithmeticSequence.
- *
- * (1..5).step(2) # => ((1..5).step(2))
- * (1.0..).step(1.5) #=> ((1.0..).step(1.5))
- * (..3r).step(1/3r) #=> ((..3/1).step((1/3)))
- *
- * Enumerator::ArithmeticSequence can be further used as a value object for iteration
- * or slicing of collections (see Array#[]). There is a convenience method #% with
- * behavior similar to +step+ to produce arithmetic sequences more expressively:
- *
- * # Same as (1..5).step(2)
- * (1..5) % 2 # => ((1..5).%(2))
- *
- * In a generic case, when the block is not provided, Enumerator is returned:
- *
- * ('a'..).step('b') #=> #<Enumerator: "a"..:step("b")>
- * ('a'..).step('b').take(3) #=> ["a", "ab", "abb"]
- *
- * If +s+ is not provided, it is considered +1+ for ranges with numeric +begin+:
- *
- * (1..5).step { p _1 }
- * # Prints: 1, 2, 3, 4, 5
+ * a = []
+ * (1..5).step {|element| a.push(element) } # => 1..5
+ * a # => [1, 2, 3, 4, 5]
+ * a = []
+ * ('a'..'e').step {|element| a.push(element) } # => "a".."e"
+ * a # => ["a", "b", "c", "d", "e"]
*
- * For non-Numeric ranges, step absence is an error:
+ * With a block given and a positive integer argument +n+ given,
+ * calls the block with element +0+, element +n+, element <tt>2n</tt>, and so on:
*
- * (Time.utc(2022, 3, 1)..Time.utc(2022, 2, 24)).step { p _1 }
- * # raises: step is required for non-numeric ranges (ArgumentError)
+ * a = []
+ * (1..5).step(2) {|element| a.push(element) } # => 1..5
+ * a # => [1, 3, 5]
+ * a = []
+ * ('a'..'e').step(2) {|element| a.push(element) } # => "a".."e"
+ * a # => ["a", "c", "e"]
*
- * For backward compatibility reasons, String ranges support the iteration both with
- * string step and with integer step. In the latter case, the iteration is performed
- * by calculating the next values with String#succ:
+ * With no block given, returns an enumerator,
+ * which will be of class Enumerator::ArithmeticSequence if +self+ is numeric;
+ * otherwise of class Enumerator:
*
- * ('a'..'e').step(2) { p _1 }
- * # Prints: a, c, e
- * ('a'..'e').step { p _1 }
- * # Default step 1; prints: a, b, c, d, e
+ * e = (1..5).step(2) # => ((1..5).step(2))
+ * e.class # => Enumerator::ArithmeticSequence
+ * ('a'..'e').step # => #<Enumerator: ...>
*
+ * Related: Range#%.
*/
static VALUE
range_step(int argc, VALUE *argv, VALUE range)
{
- VALUE b, e, v, step;
- int c, dir;
+ VALUE b, e, step, tmp;
b = RANGE_BEG(range);
e = RANGE_END(range);
-
- const VALUE b_num_p = rb_obj_is_kind_of(b, rb_cNumeric);
- const VALUE e_num_p = rb_obj_is_kind_of(e, rb_cNumeric);
- // For backward compatibility reasons (conforming to behavior before 3.4), String/Symbol
- // supports both old behavior ('a'..).step(1) and new behavior ('a'..).step('a')
- // Hence the additional conversion/addional checks.
- const VALUE str_b = rb_check_string_type(b);
- const VALUE sym_b = SYMBOL_P(b) ? rb_sym2str(b) : Qnil;
-
- if (rb_check_arity(argc, 0, 1))
- step = argv[0];
- else {
- if (b_num_p || !NIL_P(str_b) || !NIL_P(sym_b) || (NIL_P(b) && e_num_p))
- step = INT2FIX(1);
- else
- rb_raise(rb_eArgError, "step is required for non-numeric ranges");
- }
-
- const VALUE step_num_p = rb_obj_is_kind_of(step, rb_cNumeric);
-
- if (step_num_p && b_num_p && rb_equal(step, INT2FIX(0))) {
- rb_raise(rb_eArgError, "step can't be 0");
- }
+ step = (!rb_check_arity(argc, 0, 1) ? INT2FIX(1) : argv[0]);
if (!rb_block_given_p()) {
- // This code is allowed to create even beginless ArithmeticSequence, which can be useful,
- // e.g., for array slicing:
- // ary[(..-1) % 3]
- if (step_num_p && ((b_num_p && (NIL_P(e) || e_num_p)) || (NIL_P(b) && e_num_p))) {
- return rb_arith_seq_new(range, ID2SYM(rb_frame_this_func()), argc, argv,
- range_step_size, b, e, step, EXCL(range));
+ if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
+ step = rb_to_int(step);
+ }
+ if (rb_equal(step, INT2FIX(0))) {
+ rb_raise(rb_eArgError, "step can't be 0");
}
- // ...but generic Enumerator from beginless range is useless and probably an error.
- if (NIL_P(b)) {
- rb_raise(rb_eArgError, "#step for non-numeric beginless ranges is meaningless");
+ const VALUE b_num_p = rb_obj_is_kind_of(b, rb_cNumeric);
+ const VALUE e_num_p = rb_obj_is_kind_of(e, rb_cNumeric);
+ if ((b_num_p && (NIL_P(e) || e_num_p)) || (NIL_P(b) && e_num_p)) {
+ return rb_arith_seq_new(range, ID2SYM(rb_frame_this_func()), argc, argv,
+ range_step_size, b, e, step, EXCL(range));
}
- RETURN_SIZED_ENUMERATOR(range, argc, argv, 0);
+ RETURN_SIZED_ENUMERATOR(range, argc, argv, range_step_size);
}
- if (NIL_P(b)) {
- rb_raise(rb_eArgError, "#step iteration for beginless ranges is meaningless");
- }
+ step = check_step_domain(step);
+ VALUE iter[2] = {INT2FIX(1), step};
if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(step)) {
- /* perform summation of numbers in C until their reach Fixnum limit */
long i = FIX2LONG(b), unit = FIX2LONG(step);
do {
rb_yield(LONG2FIX(i));
@@ -542,99 +473,71 @@ range_step(int argc, VALUE *argv, VALUE range)
} while (FIXABLE(i));
b = LONG2NUM(i);
- /* then switch to Bignum API */
for (;; b = rb_big_plus(b, step))
rb_yield(b);
}
- else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) {
- /* fixnums are special: summation is performed in C for performance */
+ else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */
long end = FIX2LONG(e);
long i, unit = FIX2LONG(step);
- if (unit < 0) {
- if (!EXCL(range))
- end -= 1;
- i = FIX2LONG(b);
- while (i > end) {
- rb_yield(LONG2NUM(i));
- i += unit;
- }
- } else {
- if (!EXCL(range))
- end += 1;
- i = FIX2LONG(b);
- while (i < end) {
- rb_yield(LONG2NUM(i));
- i += unit;
- }
+ if (!EXCL(range))
+ end += 1;
+ i = FIX2LONG(b);
+ while (i < end) {
+ rb_yield(LONG2NUM(i));
+ if (i + unit < i) break;
+ i += unit;
}
- }
- else if (b_num_p && step_num_p && ruby_float_step(b, e, step, EXCL(range), TRUE)) {
- /* done */
- } else if (!NIL_P(str_b) && FIXNUM_P(step)) {
- // backwards compatibility behavior for String only, when no step/Integer step is passed
- // See discussion in https://bugs.ruby-lang.org/issues/18368
-
- VALUE iter[2] = {INT2FIX(1), step};
+ }
+ else if (SYMBOL_P(b) && (NIL_P(e) || SYMBOL_P(e))) { /* symbols are special */
+ b = rb_sym2str(b);
if (NIL_P(e)) {
- rb_str_upto_endless_each(str_b, step_i, (VALUE)iter);
+ rb_str_upto_endless_each(b, sym_step_i, (VALUE)iter);
}
else {
- rb_str_upto_each(str_b, e, EXCL(range), step_i, (VALUE)iter);
+ rb_str_upto_each(b, rb_sym2str(e), EXCL(range), sym_step_i, (VALUE)iter);
}
- } else if (!NIL_P(sym_b) && FIXNUM_P(step)) {
- // same as above: backward compatibility for symbols
-
- VALUE iter[2] = {INT2FIX(1), step};
+ }
+ else if (ruby_float_step(b, e, step, EXCL(range), TRUE)) {
+ /* done */
+ }
+ else if (rb_obj_is_kind_of(b, rb_cNumeric) ||
+ !NIL_P(rb_check_to_integer(b, "to_int")) ||
+ !NIL_P(rb_check_to_integer(e, "to_int"))) {
+ ID op = EXCL(range) ? '<' : idLE;
+ VALUE v = b;
+ int i = 0;
+
+ while (NIL_P(e) || RTEST(rb_funcall(v, op, 1, e))) {
+ rb_yield(v);
+ i++;
+ v = rb_funcall(b, '+', 1, rb_funcall(INT2NUM(i), '*', 1, step));
+ }
+ }
+ else {
+ tmp = rb_check_string_type(b);
- if (NIL_P(e)) {
- rb_str_upto_endless_each(sym_b, sym_step_i, (VALUE)iter);
+ if (!NIL_P(tmp)) {
+ b = tmp;
+ if (NIL_P(e)) {
+ rb_str_upto_endless_each(b, step_i, (VALUE)iter);
+ }
+ else {
+ rb_str_upto_each(b, e, EXCL(range), step_i, (VALUE)iter);
+ }
}
else {
- rb_str_upto_each(sym_b, rb_sym2str(e), EXCL(range), sym_step_i, (VALUE)iter);
- }
- } else {
- v = b;
- if (!NIL_P(e)) {
- if (b_num_p && step_num_p && r_less(step, INT2FIX(0)) < 0) {
- // iterate backwards, for consistency with ArithmeticSequence
- if (EXCL(range)) {
- for (; r_less(e, v) < 0; v = rb_funcall(v, id_plus, 1, step))
- rb_yield(v);
- }
- else {
- for (; (c = r_less(e, v)) <= 0; v = rb_funcall(v, id_plus, 1, step)) {
- rb_yield(v);
- if (!c) break;
- }
- }
-
- } else {
- // Direction of the comparison. We use it as a comparison operator in cycle:
- // if begin < end, the cycle performs while value < end (iterating forward)
- // if begin > end, the cycle performs while value > end (iterating backward with
- // a negative step)
- dir = r_less(b, e);
- // One preliminary addition to check the step moves iteration in the same direction as
- // from begin to end; otherwise, the iteration should be empty.
- if (r_less(b, rb_funcall(b, id_plus, 1, step)) == dir) {
- if (EXCL(range)) {
- for (; r_less(v, e) == dir; v = rb_funcall(v, id_plus, 1, step))
- rb_yield(v);
- }
- else {
- for (; (c = r_less(v, e)) == dir || c == 0; v = rb_funcall(v, id_plus, 1, step)) {
- rb_yield(v);
- if (!c) break;
- }
- }
- }
+ if (!discrete_object_p(b)) {
+ rb_raise(rb_eTypeError, "can't iterate from %s",
+ rb_obj_classname(b));
}
+ if (!NIL_P(e))
+ range_each_func(range, step_i, (VALUE)iter);
+ else
+ for (;; b = rb_funcallv(b, id_succ, 0, 0))
+ step_i(b, (VALUE)iter);
}
- else
- for (;; v = rb_funcall(v, id_plus, 1, step))
- rb_yield(v);
}
return range;
}
@@ -642,24 +545,29 @@ range_step(int argc, VALUE *argv, VALUE range)
/*
* call-seq:
* %(n) {|element| ... } -> self
- * %(n) -> enumerator or arithmetic_sequence
+ * %(n) -> enumerator
+ *
+ * Iterates over the elements of +self+.
*
- * Same as #step (but doesn't provide default value for +n+).
- * The method is convenient for experssive producing of Enumerator::ArithmeticSequence.
+ * With a block given, calls the block with selected elements of the range;
+ * returns +self+:
*
- * array = [0, 1, 2, 3, 4, 5, 6]
+ * a = []
+ * (1..5).%(2) {|element| a.push(element) } # => 1..5
+ * a # => [1, 3, 5]
+ * a = []
+ * ('a'..'e').%(2) {|element| a.push(element) } # => "a".."e"
+ * a # => ["a", "c", "e"]
*
- * # slice each second element:
- * seq = (0..) % 2 #=> ((0..).%(2))
- * array[seq] #=> [0, 2, 4, 6]
- * # or just
- * array[(0..) % 2] #=> [0, 2, 4, 6]
+ * With no block given, returns an enumerator,
+ * which will be of class Enumerator::ArithmeticSequence if +self+ is numeric;
+ * otherwise of class Enumerator:
*
- * Note that due to operator precedence in Ruby, parentheses are mandatory around range
- * in this case:
+ * e = (1..5) % 2 # => ((1..5).%(2))
+ * e.class # => Enumerator::ArithmeticSequence
+ * ('a'..'e') % 2 # => #<Enumerator: ...>
*
- * (0..7) % 2 #=> ((0..7).%(2)) -- as expected
- * 0..7 % 2 #=> 0..1 -- parsed as 0..(7 % 2)
+ * Related: Range#step.
*/
static VALUE
range_percent_step(VALUE range, VALUE step)
@@ -699,10 +607,6 @@ double_as_int64(double d)
static int
is_integer_p(VALUE v)
{
- if (rb_integer_type_p(v)) {
- return true;
- }
-
ID id_integer_p;
VALUE is_int;
CONST_ID(id_integer_p, "integer?");
@@ -745,30 +649,27 @@ bsearch_integer_range(VALUE beg, VALUE end, int excl)
VALUE low = rb_to_int(beg);
VALUE high = rb_to_int(end);
- VALUE mid;
+ VALUE mid, org_high;
ID id_div;
CONST_ID(id_div, "div");
- if (!excl) high = rb_funcall(high, '+', 1, INT2FIX(1));
- low = rb_funcall(low, '-', 1, INT2FIX(1));
+ if (excl) high = rb_funcall(high, '-', 1, INT2FIX(1));
+ org_high = high;
- /*
- * This loop must continue while low + 1 < high.
- * Instead of checking low + 1 < high, check low < mid, where mid = (low + high) / 2.
- * This is to avoid the cost of calculating low + 1 on each iteration.
- * Note that this condition replacement is valid because Integer#div always rounds
- * towards negative infinity.
- */
- while (mid = rb_funcall(rb_funcall(high, '+', 1, low), id_div, 1, INT2FIX(2)),
- rb_cmpint(rb_funcall(low, id_cmp, 1, mid), low, mid) < 0) {
+ while (rb_cmpint(rb_funcall(low, id_cmp, 1, high), low, high) < 0) {
+ mid = rb_funcall(rb_funcall(high, '+', 1, low), id_div, 1, INT2FIX(2));
BSEARCH_CHECK(mid);
if (smaller) {
high = mid;
}
else {
- low = mid;
+ low = rb_funcall(mid, '+', 1, INT2FIX(1));
}
}
+ if (rb_equal(low, org_high)) {
+ BSEARCH_CHECK(low);
+ if (!smaller) return Qnil;
+ }
return satisfied;
}
@@ -795,58 +696,52 @@ range_bsearch(VALUE range)
* by the mantissa. This is true with or without implicit bit.
*
* Finding the average of two ints needs to be careful about
- * potential overflow (since float to long can use 64 bits).
- *
- * The half-open interval (low, high] indicates where the target is located.
- * The loop continues until low and high are adjacent.
- *
- * -1/2 can be either 0 or -1 in C89. However, when low and high are not adjacent,
- * the rounding direction of mid = (low + high) / 2 does not affect the result of
- * the binary search.
+ * potential overflow (since float to long can use 64 bits)
+ * as well as the fact that -1/2 can be 0 or -1 in C89.
*
* Note that -0.0 is mapped to the same int as 0.0 as we don't want
* (-1...0.0).bsearch to yield -0.0.
*/
-#define BSEARCH(conv, excl) \
+#define BSEARCH(conv) \
do { \
RETURN_ENUMERATOR(range, 0, 0); \
- if (!(excl)) high++; \
- low--; \
- while (low + 1 < high) { \
+ if (EXCL(range)) high--; \
+ org_high = high; \
+ while (low < high) { \
mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
- : (low + high) / 2; \
+ : (low < -high) ? -((-1 - low - high)/2 + 1) : (low + high) / 2; \
BSEARCH_CHECK(conv(mid)); \
if (smaller) { \
high = mid; \
} \
else { \
- low = mid; \
+ low = mid + 1; \
} \
} \
+ if (low == org_high) { \
+ BSEARCH_CHECK(conv(low)); \
+ if (!smaller) return Qnil; \
+ } \
return satisfied; \
} while (0)
-#define BSEARCH_FIXNUM(beg, end, excl) \
- do { \
- long low = FIX2LONG(beg); \
- long high = FIX2LONG(end); \
- long mid; \
- BSEARCH(INT2FIX, (excl)); \
- } while (0)
beg = RANGE_BEG(range);
end = RANGE_END(range);
if (FIXNUM_P(beg) && FIXNUM_P(end)) {
- BSEARCH_FIXNUM(beg, end, EXCL(range));
+ long low = FIX2LONG(beg);
+ long high = FIX2LONG(end);
+ long mid, org_high;
+ BSEARCH(INT2FIX);
}
#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
else if (RB_FLOAT_TYPE_P(beg) || RB_FLOAT_TYPE_P(end)) {
int64_t low = double_as_int64(NIL_P(beg) ? -HUGE_VAL : RFLOAT_VALUE(rb_Float(beg)));
int64_t high = double_as_int64(NIL_P(end) ? HUGE_VAL : RFLOAT_VALUE(rb_Float(end)));
- int64_t mid;
- BSEARCH(int64_as_double_to_num, EXCL(range));
+ int64_t mid, org_high;
+ BSEARCH(int64_as_double_to_num);
}
#endif
else if (is_integer_p(beg) && is_integer_p(end)) {
@@ -860,15 +755,9 @@ range_bsearch(VALUE range)
VALUE mid = rb_funcall(beg, '+', 1, diff);
BSEARCH_CHECK(mid);
if (smaller) {
- if (FIXNUM_P(beg) && FIXNUM_P(mid)) {
- BSEARCH_FIXNUM(beg, mid, false);
- }
- else {
- return bsearch_integer_range(beg, mid, false);
- }
+ return bsearch_integer_range(beg, mid, 0);
}
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
- beg = mid;
}
}
else if (NIL_P(beg) && is_integer_p(end)) {
@@ -878,15 +767,9 @@ range_bsearch(VALUE range)
VALUE mid = rb_funcall(end, '+', 1, diff);
BSEARCH_CHECK(mid);
if (!smaller) {
- if (FIXNUM_P(mid) && FIXNUM_P(end)) {
- BSEARCH_FIXNUM(mid, end, false);
- }
- else {
- return bsearch_integer_range(mid, end, false);
- }
+ return bsearch_integer_range(mid, end, 0);
}
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
- end = mid;
}
}
else {
@@ -919,12 +802,7 @@ sym_each_i(VALUE v, VALUE arg)
* (1..4).size # => 4
* (1...4).size # => 3
* (1..).size # => Infinity
- * ('a'..'z').size # => nil
- *
- * If +self+ is not iterable, raises an exception:
- *
- * (0.5..2.5).size # TypeError
- * (..1).size # TypeError
+ * ('a'..'z').size #=> nil
*
* Related: Range#count.
*/
@@ -933,8 +811,7 @@ static VALUE
range_size(VALUE range)
{
VALUE b = RANGE_BEG(range), e = RANGE_END(range);
-
- if (RB_INTEGER_TYPE_P(b)) {
+ if (rb_obj_is_kind_of(b, rb_cNumeric)) {
if (rb_obj_is_kind_of(e, rb_cNumeric)) {
return ruby_num_interval_step_size(b, e, INT2FIX(1), EXCL(range));
}
@@ -942,10 +819,10 @@ range_size(VALUE range)
return DBL2NUM(HUGE_VAL);
}
}
-
- if (!discrete_object_p(b)) {
- rb_raise(rb_eTypeError, "can't iterate from %s",
- rb_obj_classname(b));
+ else if (NIL_P(b)) {
+ if (rb_obj_is_kind_of(e, rb_cNumeric)) {
+ return DBL2NUM(HUGE_VAL);
+ }
}
return Qnil;
@@ -962,6 +839,7 @@ range_size(VALUE range)
* (1...4).to_a # => [1, 2, 3]
* ('a'..'d').to_a # => ["a", "b", "c", "d"]
*
+ * Range#entries is an alias for Range#to_a.
*/
static VALUE
@@ -1122,144 +1000,6 @@ range_each(VALUE range)
return range;
}
-RBIMPL_ATTR_NORETURN()
-static void
-range_reverse_each_bignum_beginless(VALUE end)
-{
- RUBY_ASSERT(RBIGNUM_NEGATIVE_P(end));
-
- for (;; end = rb_big_minus(end, INT2FIX(1))) {
- rb_yield(end);
- }
- UNREACHABLE;
-}
-
-static void
-range_reverse_each_bignum(VALUE beg, VALUE end)
-{
- RUBY_ASSERT(RBIGNUM_POSITIVE_P(beg) == RBIGNUM_POSITIVE_P(end));
-
- VALUE c;
- while ((c = rb_big_cmp(beg, end)) != INT2FIX(1)) {
- rb_yield(end);
- if (c == INT2FIX(0)) break;
- end = rb_big_minus(end, INT2FIX(1));
- }
-}
-
-static void
-range_reverse_each_positive_bignum_section(VALUE beg, VALUE end)
-{
- RUBY_ASSERT(!NIL_P(end));
-
- if (FIXNUM_P(end) || RBIGNUM_NEGATIVE_P(end)) return;
-
- if (NIL_P(beg) || FIXNUM_P(beg) || RBIGNUM_NEGATIVE_P(beg)) {
- beg = LONG2NUM(FIXNUM_MAX + 1);
- }
-
- range_reverse_each_bignum(beg, end);
-}
-
-static void
-range_reverse_each_fixnum_section(VALUE beg, VALUE end)
-{
- RUBY_ASSERT(!NIL_P(end));
-
- if (!FIXNUM_P(beg)) {
- if (!NIL_P(beg) && RBIGNUM_POSITIVE_P(beg)) return;
-
- beg = LONG2FIX(FIXNUM_MIN);
- }
-
- if (!FIXNUM_P(end)) {
- if (RBIGNUM_NEGATIVE_P(end)) return;
-
- end = LONG2FIX(FIXNUM_MAX);
- }
-
- long b = FIX2LONG(beg);
- long e = FIX2LONG(end);
- for (long i = e; i >= b; --i) {
- rb_yield(LONG2FIX(i));
- }
-}
-
-static void
-range_reverse_each_negative_bignum_section(VALUE beg, VALUE end)
-{
- RUBY_ASSERT(!NIL_P(end));
-
- if (FIXNUM_P(end) || RBIGNUM_POSITIVE_P(end)) {
- end = LONG2NUM(FIXNUM_MIN - 1);
- }
-
- if (NIL_P(beg)) {
- range_reverse_each_bignum_beginless(end);
- }
-
- if (FIXNUM_P(beg) || RBIGNUM_POSITIVE_P(beg)) return;
-
- range_reverse_each_bignum(beg, end);
-}
-
-/*
- * call-seq:
- * reverse_each {|element| ... } -> self
- * reverse_each -> an_enumerator
- *
- * With a block given, passes each element of +self+ to the block in reverse order:
- *
- * a = []
- * (1..4).reverse_each {|element| a.push(element) } # => 1..4
- * a # => [4, 3, 2, 1]
- *
- * a = []
- * (1...4).reverse_each {|element| a.push(element) } # => 1...4
- * a # => [3, 2, 1]
- *
- * With no block given, returns an enumerator.
- *
- */
-
-static VALUE
-range_reverse_each(VALUE range)
-{
- RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size);
-
- VALUE beg = RANGE_BEG(range);
- VALUE end = RANGE_END(range);
- int excl = EXCL(range);
-
- if (NIL_P(end)) {
- rb_raise(rb_eTypeError, "can't iterate from %s",
- rb_obj_classname(end));
- }
-
- if (FIXNUM_P(beg) && FIXNUM_P(end)) {
- if (excl) {
- if (end == LONG2FIX(FIXNUM_MIN)) return range;
-
- end = rb_int_minus(end, INT2FIX(1));
- }
-
- range_reverse_each_fixnum_section(beg, end);
- }
- else if ((NIL_P(beg) || RB_INTEGER_TYPE_P(beg)) && RB_INTEGER_TYPE_P(end)) {
- if (excl) {
- end = rb_int_minus(end, INT2FIX(1));
- }
- range_reverse_each_positive_bignum_section(beg, end);
- range_reverse_each_fixnum_section(beg, end);
- range_reverse_each_negative_bignum_section(beg, end);
- }
- else {
- return rb_call_super(0, NULL);
- }
-
- return range;
-}
-
/*
* call-seq:
* self.begin -> object
@@ -1364,11 +1104,11 @@ rb_int_range_last(int argc, VALUE *argv, VALUE range)
int x;
long n;
- RUBY_ASSERT(argc > 0);
+ assert(argc > 0);
b = RANGE_BEG(range);
e = RANGE_END(range);
- RUBY_ASSERT(RB_INTEGER_TYPE_P(b) && RB_INTEGER_TYPE_P(e));
+ assert(RB_INTEGER_TYPE_P(b) && RB_INTEGER_TYPE_P(e));
x = EXCL(range);
@@ -1471,7 +1211,7 @@ range_last(int argc, VALUE *argv, VALUE range)
* min(n) {|a, b| ... } -> array
*
* Returns the minimum value in +self+,
- * using method <tt>#<=></tt> or a given block for comparison.
+ * using method <tt><=></tt> or a given block for comparison.
*
* With no argument and no block given,
* returns the minimum-valued element of +self+.
@@ -1579,7 +1319,7 @@ range_min(int argc, VALUE *argv, VALUE range)
* max(n) {|a, b| ... } -> array
*
* Returns the maximum value in +self+,
- * using method <tt>#<=></tt> or a given block for comparison.
+ * using method <tt><=></tt> or a given block for comparison.
*
* With no argument and no block given,
* returns the maximum-valued element of +self+.
@@ -1698,10 +1438,10 @@ range_max(int argc, VALUE *argv, VALUE range)
* minmax {|a, b| ... } -> [object, object]
*
* Returns a 2-element array containing the minimum and maximum value in +self+,
- * either according to comparison method <tt>#<=></tt> or a given block.
+ * either according to comparison method <tt><=></tt> or a given block.
*
* With no block given, returns the minimum and maximum values,
- * using <tt>#<=></tt> for comparison:
+ * using <tt><=></tt> for comparison:
*
* (1..4).minmax # => [1, 4]
* (1...4).minmax # => [1, 3]
@@ -1942,6 +1682,7 @@ range_inspect(VALUE range)
}
static VALUE range_include_internal(VALUE range, VALUE val);
+static VALUE range_string_cover_internal(VALUE range, VALUE val);
VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive);
/*
@@ -1986,6 +1727,8 @@ VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive);
static VALUE
range_eqq(VALUE range, VALUE val)
{
+ VALUE ret = range_string_cover_internal(range, val);
+ if (!UNDEF_P(ret)) return ret;
return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val);
}
@@ -2017,6 +1760,8 @@ range_eqq(VALUE range, VALUE val)
* ('a'..'d').cover?('cc') # => true
*
* Related: Range#cover?.
+ *
+ * Range#member? is an alias for Range#include?.
*/
static VALUE
@@ -2035,6 +1780,12 @@ range_integer_edge_p(VALUE beg, VALUE end)
}
static inline bool
+range_string_edge_p(VALUE beg, VALUE end)
+{
+ return RB_TYPE_P(beg, T_STRING) || RB_TYPE_P(end, T_STRING);
+}
+
+static inline bool
range_string_range_p(VALUE beg, VALUE end)
{
return RB_TYPE_P(beg, T_STRING) && RB_TYPE_P(end, T_STRING);
@@ -2055,6 +1806,48 @@ range_include_fallback(VALUE beg, VALUE end, VALUE val)
}
static VALUE
+range_string_cover_internal(VALUE range, VALUE val)
+{
+ VALUE beg = RANGE_BEG(range);
+ VALUE end = RANGE_END(range);
+ int nv = FIXNUM_P(beg) || FIXNUM_P(end) ||
+ linear_object_p(beg) || linear_object_p(end);
+
+ if (nv || range_integer_edge_p(beg, end)) {
+ return r_cover_p(range, beg, end, val);
+ }
+ else if (range_string_edge_p(beg, end)) {
+ if (range_string_range_p(beg, end)) {
+ return r_cover_p(range, beg, end, val);
+ }
+ if (NIL_P(beg)) {
+unbounded_begin:;
+ VALUE r = rb_funcall(val, id_cmp, 1, end);
+ if (NIL_P(r)) return Qfalse;
+ if (RANGE_EXCL(range)) {
+ return RBOOL(rb_cmpint(r, val, end) < 0);
+ }
+ return RBOOL(rb_cmpint(r, val, end) <= 0);
+ }
+ else if (NIL_P(end)) {
+unbounded_end:;
+ VALUE r = rb_funcall(beg, id_cmp, 1, val);
+ if (NIL_P(r)) return Qfalse;
+ return RBOOL(rb_cmpint(r, beg, val) <= 0);
+ }
+ }
+
+ if (!NIL_P(beg) && NIL_P(end)) {
+ goto unbounded_end;
+ }
+ if (NIL_P(beg) && !NIL_P(end)) {
+ goto unbounded_begin;
+ }
+
+ return range_include_fallback(beg, end, val);
+}
+
+static VALUE
range_include_internal(VALUE range, VALUE val)
{
VALUE beg = RANGE_BEG(range);
@@ -2096,7 +1889,7 @@ static int r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val);
* r.cover?(0) # => false
* r.cover?(5) # => false
* r.cover?('foo') # => false
- *
+
* r = ('a'..'d')
* r.cover?('a') # => true
* r.cover?('d') # => true
@@ -2117,7 +1910,7 @@ static int r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val);
* r.cover?(0) # => false
* r.cover?(4) # => false
* r.cover?('foo') # => false
- *
+
* r = ('a'...'d')
* r.cover?('a') # => true
* r.cover?('c') # => true
@@ -2133,7 +1926,7 @@ static int r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val);
* r.cover?(0..4) # => false
* r.cover?(1..5) # => false
* r.cover?('a'..'d') # => false
- *
+
* r = (1...4)
* r.cover?(1..3) # => true
* r.cover?(1..4) # => false
@@ -2151,7 +1944,7 @@ static int r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val);
* Returns +false+ if either:
*
* - The begin value of +self+ is larger than its end value.
- * - An internal call to <tt>#<=></tt> returns +nil+;
+ * - An internal call to <tt><=></tt> returns +nil+;
* that is, the operands are not comparable.
*
* Beginless ranges cover all values of the same type before the end,
@@ -2355,137 +2148,17 @@ range_count(int argc, VALUE *argv, VALUE range)
* Infinity. Just let it loop. */
return rb_call_super(argc, argv);
}
-
- VALUE beg = RANGE_BEG(range), end = RANGE_END(range);
-
- if (NIL_P(beg) || NIL_P(end)) {
+ else if (NIL_P(RANGE_END(range))) {
/* We are confident that the answer is Infinity. */
return DBL2NUM(HUGE_VAL);
}
-
- if (is_integer_p(beg)) {
- VALUE size = range_size(range);
- if (!NIL_P(size)) {
- return size;
- }
- }
-
- return rb_call_super(argc, argv);
-}
-
-static bool
-empty_region_p(VALUE beg, VALUE end, int excl)
-{
- if (NIL_P(beg)) return false;
- if (NIL_P(end)) return false;
- int less = r_less(beg, end);
- /* empty range */
- if (less > 0) return true;
- if (excl && less == 0) return true;
- return false;
-}
-
-/*
- * call-seq:
- * overlap?(range) -> true or false
- *
- * Returns +true+ if +range+ overlaps with +self+, +false+ otherwise:
- *
- * (0..2).overlap?(1..3) #=> true
- * (0..2).overlap?(3..4) #=> false
- * (0..).overlap?(..0) #=> true
- *
- * With non-range argument, raises TypeError.
- *
- * (1..3).overlap?(1) # TypeError
- *
- * Returns +false+ if an internal call to <tt>#<=></tt> returns +nil+;
- * that is, the operands are not comparable.
- *
- * (1..3).overlap?('a'..'d') # => false
- *
- * Returns +false+ if +self+ or +range+ is empty. "Empty range" means
- * that its begin value is larger than, or equal for an exclusive
- * range, its end value.
- *
- * (4..1).overlap?(2..3) # => false
- * (4..1).overlap?(..3) # => false
- * (4..1).overlap?(2..) # => false
- * (2...2).overlap?(1..2) # => false
- *
- * (1..4).overlap?(3..2) # => false
- * (..4).overlap?(3..2) # => false
- * (1..).overlap?(3..2) # => false
- * (1..2).overlap?(2...2) # => false
- *
- * Returns +false+ if the begin value one of +self+ and +range+ is
- * larger than, or equal if the other is an exclusive range, the end
- * value of the other:
- *
- * (4..5).overlap?(2..3) # => false
- * (4..5).overlap?(2...4) # => false
- *
- * (1..2).overlap?(3..4) # => false
- * (1...3).overlap?(3..4) # => false
- *
- * Returns +false+ if the end value one of +self+ and +range+ is
- * larger than, or equal for an exclusive range, the end value of the
- * other:
- *
- * (4..5).overlap?(2..3) # => false
- * (4..5).overlap?(2...4) # => false
- *
- * (1..2).overlap?(3..4) # => false
- * (1...3).overlap?(3..4) # => false
- *
- * Note that the method wouldn't make any assumptions about the beginless
- * range being actually empty, even if its upper bound is the minimum
- * possible value of its type, so all this would return +true+:
- *
- * (...-Float::INFINITY).overlap?(...-Float::INFINITY) # => true
- * (..."").overlap?(..."") # => true
- * (...[]).overlap?(...[]) # => true
- *
- * Even if those ranges are effectively empty (no number can be smaller than
- * <tt>-Float::INFINITY</tt>), they are still considered overlapping
- * with themselves.
- *
- * Related: Range#cover?.
- */
-
-static VALUE
-range_overlap(VALUE range, VALUE other)
-{
- if (!rb_obj_is_kind_of(other, rb_cRange)) {
- rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Range)",
- rb_class_name(rb_obj_class(other)));
- }
-
- VALUE self_beg = RANGE_BEG(range);
- VALUE self_end = RANGE_END(range);
- int self_excl = EXCL(range);
- VALUE other_beg = RANGE_BEG(other);
- VALUE other_end = RANGE_END(other);
- int other_excl = EXCL(other);
-
- if (empty_region_p(self_beg, other_end, other_excl)) return Qfalse;
- if (empty_region_p(other_beg, self_end, self_excl)) return Qfalse;
-
- if (!NIL_P(self_beg) && !NIL_P(other_beg)) {
- VALUE cmp = rb_funcall(self_beg, id_cmp, 1, other_beg);
- if (NIL_P(cmp)) return Qfalse;
- /* if both begin values are equal, no more comparisons needed */
- if (rb_cmpint(cmp, self_beg, other_beg) == 0) return Qtrue;
+ else if (NIL_P(RANGE_BEG(range))) {
+ /* We are confident that the answer is Infinity. */
+ return DBL2NUM(HUGE_VAL);
}
- else if (NIL_P(self_beg) && !NIL_P(self_end) && NIL_P(other_beg)) {
- VALUE cmp = rb_funcall(self_end, id_cmp, 1, other_end);
- return RBOOL(!NIL_P(cmp));
+ else {
+ return rb_call_super(argc, argv);
}
-
- if (empty_region_p(self_beg, self_end, self_excl)) return Qfalse;
- if (empty_region_p(other_beg, other_end, other_excl)) return Qfalse;
-
- return Qtrue;
}
/* A \Range object represents a collection of values
@@ -2502,7 +2175,7 @@ range_overlap(VALUE range, VALUE other)
* (1...4).to_a # => [1, 2, 3]
* ('a'...'d').to_a # => ["a", "b", "c"]
*
- * - Method Range.new:
+ * A range may be created using method Range.new:
*
* # Ranges that by default include the given end value.
* Range.new(1, 4).to_a # => [1, 2, 3, 4]
@@ -2530,12 +2203,8 @@ range_overlap(VALUE range, VALUE other)
* A beginless range may be used to slice an array:
*
* a = [1, 2, 3, 4]
- * # Include the third array element in the slice
- * r = (..2) # => nil..2
- * a[r] # => [1, 2, 3]
- * # Exclude the third array element from the slice
- * r = (...2) # => nil...2
- * a[r] # => [1, 2]
+ * r = (..2) # => nil...2
+ * a[r] # => [1, 2]
*
* \Method +each+ for a beginless range raises an exception.
*
@@ -2589,7 +2258,7 @@ range_overlap(VALUE range, VALUE other)
* == Ranges and Other Classes
*
* An object may be put into a range if its class implements
- * instance method <tt>#<=></tt>.
+ * instance method <tt><=></tt>.
* Ruby core classes that do so include Array, Complex, File::Stat,
* Float, Integer, Kernel, Module, Numeric, Rational, String, Symbol, and Time.
*
@@ -2621,15 +2290,15 @@ range_overlap(VALUE range, VALUE other)
* == Ranges and User-Defined Classes
*
* A user-defined class that is to be used in a range
- * must implement instance method <tt>#<=></tt>;
+ * must implement instance <tt><=></tt>;
* see Integer#<=>.
* To make iteration available, it must also implement
* instance method +succ+; see Integer#succ.
*
- * The class below implements both <tt>#<=></tt> and +succ+,
+ * The class below implements both <tt><=></tt> and +succ+,
* and so can be used both to construct ranges and to iterate over them.
* Note that the Comparable module is included
- * so the <tt>==</tt> method is defined in terms of <tt>#<=></tt>.
+ * so the <tt>==</tt> method is defined in terms of <tt><=></tt>.
*
* # Represent a string of 'X' characters.
* class Xs
@@ -2672,7 +2341,6 @@ range_overlap(VALUE range, VALUE other)
* - {Comparing}[rdoc-ref:Range@Methods+for+Comparing]
* - {Iterating}[rdoc-ref:Range@Methods+for+Iterating]
* - {Converting}[rdoc-ref:Range@Methods+for+Converting]
- * - {Methods for Working with JSON}[rdoc-ref:Range@Methods+for+Working+with+JSON]
*
* === Methods for Creating a \Range
*
@@ -2707,7 +2375,7 @@ range_overlap(VALUE range, VALUE other)
* - #%: Requires argument +n+; calls the block with each +n+-th element of +self+.
* - #each: Calls the block with each element of +self+.
* - #step: Takes optional argument +n+ (defaults to 1);
- * calls the block with each +n+-th element of +self+.
+ calls the block with each +n+-th element of +self+.
*
* === Methods for Converting
*
@@ -2715,16 +2383,6 @@ range_overlap(VALUE range, VALUE other)
* - #to_a (aliased as #entries): Returns elements of +self+ in an array.
* - #to_s: Returns a string representation of +self+ (uses #to_s).
*
- * === Methods for Working with \JSON
- *
- * - ::json_create: Returns a new \Range object constructed from the given object.
- * - #as_json: Returns a 2-element hash representing +self+.
- * - #to_json: Returns a \JSON string representing +self+.
- *
- * To make these methods available:
- *
- * require 'json/add/range'
- *
*/
void
@@ -2749,7 +2407,6 @@ Init_Range(void)
rb_define_method(rb_cRange, "each", range_each, 0);
rb_define_method(rb_cRange, "step", range_step, -1);
rb_define_method(rb_cRange, "%", range_percent_step, 1);
- rb_define_method(rb_cRange, "reverse_each", range_reverse_each, 0);
rb_define_method(rb_cRange, "bsearch", range_bsearch, 0);
rb_define_method(rb_cRange, "begin", range_begin, 0);
rb_define_method(rb_cRange, "end", range_end, 0);
@@ -2770,5 +2427,4 @@ Init_Range(void)
rb_define_method(rb_cRange, "include?", range_include, 1);
rb_define_method(rb_cRange, "cover?", range_cover, 1);
rb_define_method(rb_cRange, "count", range_count, -1);
- rb_define_method(rb_cRange, "overlap?", range_overlap, 1);
}
diff --git a/rational.c b/rational.c
index 1b162e7b56..dfe2ad74eb 100644
--- a/rational.c
+++ b/rational.c
@@ -22,6 +22,9 @@
# define USE_GMP 0
#endif
#endif
+#if USE_GMP
+#include <gmp.h>
+#endif
#include "id.h"
#include "internal.h"
@@ -33,15 +36,6 @@
#include "internal/rational.h"
#include "ruby_assert.h"
-#if USE_GMP
-RBIMPL_WARNING_PUSH()
-# ifdef _MSC_VER
-RBIMPL_WARNING_IGNORED(4146) /* for mpn_neg() */
-# endif
-# include <gmp.h>
-RBIMPL_WARNING_POP()
-#endif
-
#define ZERO INT2FIX(0)
#define ONE INT2FIX(1)
#define TWO INT2FIX(2)
@@ -395,8 +389,8 @@ f_gcd(VALUE x, VALUE y)
{
VALUE r = f_gcd_orig(x, y);
if (f_nonzero_p(r)) {
- RUBY_ASSERT(f_zero_p(f_mod(x, r)));
- RUBY_ASSERT(f_zero_p(f_mod(y, r)));
+ assert(f_zero_p(f_mod(x, r)));
+ assert(f_zero_p(f_mod(y, r)));
}
return r;
}
@@ -419,12 +413,11 @@ f_lcm(VALUE x, VALUE y)
inline static VALUE
nurat_s_new_internal(VALUE klass, VALUE num, VALUE den)
{
- NEWOBJ_OF(obj, struct RRational, klass, T_RATIONAL | (RGENGC_WB_PROTECTED_RATIONAL ? FL_WB_PROTECTED : 0),
- sizeof(struct RRational), 0);
+ NEWOBJ_OF(obj, struct RRational, klass, T_RATIONAL | (RGENGC_WB_PROTECTED_RATIONAL ? FL_WB_PROTECTED : 0));
RATIONAL_SET_NUM((VALUE)obj, num);
RATIONAL_SET_DEN((VALUE)obj, den);
- OBJ_FREEZE((VALUE)obj);
+ OBJ_FREEZE_RAW((VALUE)obj);
return (VALUE)obj;
}
@@ -462,8 +455,8 @@ nurat_int_value(VALUE num)
static void
nurat_canonicalize(VALUE *num, VALUE *den)
{
- RUBY_ASSERT(num); RUBY_ASSERT(RB_INTEGER_TYPE_P(*num));
- RUBY_ASSERT(den); RUBY_ASSERT(RB_INTEGER_TYPE_P(*den));
+ assert(num); assert(RB_INTEGER_TYPE_P(*num));
+ assert(den); assert(RB_INTEGER_TYPE_P(*den));
if (INT_NEGATIVE_P(*den)) {
*num = rb_int_uminus(*num);
*den = rb_int_uminus(*den);
@@ -503,16 +496,16 @@ nurat_s_canonicalize_internal_no_reduce(VALUE klass, VALUE num, VALUE den)
inline static VALUE
f_rational_new2(VALUE klass, VALUE x, VALUE y)
{
- RUBY_ASSERT(!k_rational_p(x));
- RUBY_ASSERT(!k_rational_p(y));
+ assert(!k_rational_p(x));
+ assert(!k_rational_p(y));
return nurat_s_canonicalize_internal(klass, x, y);
}
inline static VALUE
f_rational_new_no_reduce2(VALUE klass, VALUE x, VALUE y)
{
- RUBY_ASSERT(!k_rational_p(x));
- RUBY_ASSERT(!k_rational_p(y));
+ assert(!k_rational_p(x));
+ assert(!k_rational_p(y));
return nurat_s_canonicalize_internal_no_reduce(klass, x, y);
}
@@ -616,7 +609,7 @@ nurat_denominator(VALUE self)
VALUE
rb_rational_uminus(VALUE self)
{
- const int unused = (RUBY_ASSERT(RB_TYPE_P(self, T_RATIONAL)), 0);
+ const int unused = (assert(RB_TYPE_P(self, T_RATIONAL)), 0);
get_dat1(self);
(void)unused;
return f_rational_new2(CLASS_OF(self), rb_int_uminus(dat->num), dat->den);
@@ -652,7 +645,7 @@ inline static VALUE
f_imul(long x, long y)
{
VALUE r = f_imul_orig(x, y);
- RUBY_ASSERT(f_eqeq_p(r, f_mul(LONG2NUM(x), LONG2NUM(y))));
+ assert(f_eqeq_p(r, f_mul(LONG2NUM(x), LONG2NUM(y))));
return r;
}
#endif
@@ -801,7 +794,7 @@ f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
{
VALUE num, den;
- RUBY_ASSERT(RB_TYPE_P(self, T_RATIONAL));
+ assert(RB_TYPE_P(self, T_RATIONAL));
/* Integer#** can return Rational with Float right now */
if (RB_FLOAT_TYPE_P(anum) || RB_FLOAT_TYPE_P(aden) ||
@@ -812,10 +805,10 @@ f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k)
return DBL2NUM(x);
}
- RUBY_ASSERT(RB_INTEGER_TYPE_P(anum));
- RUBY_ASSERT(RB_INTEGER_TYPE_P(aden));
- RUBY_ASSERT(RB_INTEGER_TYPE_P(bnum));
- RUBY_ASSERT(RB_INTEGER_TYPE_P(bden));
+ assert(RB_INTEGER_TYPE_P(anum));
+ assert(RB_INTEGER_TYPE_P(aden));
+ assert(RB_INTEGER_TYPE_P(bnum));
+ assert(RB_INTEGER_TYPE_P(bden));
if (k == '/') {
VALUE t;
@@ -1239,6 +1232,7 @@ nurat_negative_p(VALUE self)
* (1/2r).abs #=> (1/2)
* (-1/2r).abs #=> (1/2)
*
+ * Rational#magnitude is an alias for Rational#abs.
*/
VALUE
@@ -1853,7 +1847,7 @@ nurat_loader(VALUE self, VALUE a)
nurat_canonicalize(&num, &den);
RATIONAL_SET_NUM((VALUE)dat, num);
RATIONAL_SET_DEN((VALUE)dat, den);
- OBJ_FREEZE(self);
+ OBJ_FREEZE_RAW(self);
return self;
}
@@ -2110,12 +2104,9 @@ rb_float_denominator(VALUE self)
/*
* call-seq:
- * to_r -> (0/1)
- *
- * Returns zero as a Rational:
- *
- * nil.to_r # => (0/1)
+ * nil.to_r -> (0/1)
*
+ * Returns zero as a rational.
*/
static VALUE
nilclass_to_r(VALUE self)
@@ -2125,14 +2116,10 @@ nilclass_to_r(VALUE self)
/*
* call-seq:
- * rationalize(eps = nil) -> (0/1)
- *
- * Returns zero as a Rational:
- *
- * nil.rationalize # => (0/1)
- *
- * Argument +eps+ is ignored.
+ * nil.rationalize([eps]) -> (0/1)
*
+ * Returns zero as a rational. The optional argument +eps+ is always
+ * ignored.
*/
static VALUE
nilclass_rationalize(int argc, VALUE *argv, VALUE self)
@@ -2565,7 +2552,7 @@ nurat_convert(VALUE klass, VALUE numv, VALUE denv, int raise)
VALUE a1 = numv, a2 = denv;
int state;
- RUBY_ASSERT(!UNDEF_P(a1));
+ assert(!UNDEF_P(a1));
if (NIL_P(a1) || NIL_P(a2)) {
if (!raise) return Qnil;
diff --git a/re.c b/re.c
index 215098ba21..f357d38c63 100644
--- a/re.c
+++ b/re.c
@@ -88,9 +88,6 @@ static const char casetable[] = {
# error >>> "You lose. You will need a translation table for your character set." <<<
#endif
-// The process-global timeout for regexp matching
-rb_hrtime_t rb_reg_match_time_limit = 0;
-
int
rb_memcicmp(const void *x, const void *y, long len)
{
@@ -285,6 +282,7 @@ rb_memsearch(const void *x0, long m, const void *y0, long n, rb_encoding *enc)
return rb_memsearch_qs(x0, m, y0, n);
}
+#define REG_LITERAL FL_USER5
#define REG_ENCODING_NONE FL_USER6
#define KCODE_FIXED FL_USER4
@@ -453,7 +451,7 @@ rb_reg_expr_str(VALUE str, const char *s, long len,
}
static VALUE
-rb_reg_desc(VALUE re)
+rb_reg_desc(const char *s, long len, VALUE re)
{
rb_encoding *enc = rb_enc_get(re);
VALUE str = rb_str_buf_new2("/");
@@ -466,11 +464,7 @@ rb_reg_desc(VALUE re)
else {
rb_enc_associate(str, rb_usascii_encoding());
}
-
- VALUE src_str = RREGEXP_SRC(re);
- rb_reg_expr_str(str, RSTRING_PTR(src_str), RSTRING_LEN(src_str), enc, resenc, '/');
- RB_GC_GUARD(src_str);
-
+ rb_reg_expr_str(str, s, len, enc, resenc, '/');
rb_str_buf_cat2(str, "/");
if (re) {
char opts[OPTBUF_SIZE];
@@ -529,7 +523,7 @@ rb_reg_inspect(VALUE re)
if (!RREGEXP_PTR(re) || !RREGEXP_SRC(re) || !RREGEXP_SRC_PTR(re)) {
return rb_any_to_s(re);
}
- return rb_reg_desc(re);
+ return rb_reg_desc(RREGEXP_SRC_PTR(re), RREGEXP_SRC_LEN(re), re);
}
static VALUE rb_reg_str_with_term(VALUE re, int term);
@@ -545,7 +539,7 @@ static VALUE rb_reg_str_with_term(VALUE re, int term);
*
* The returned string may be used as an argument to Regexp.new,
* or as interpolated text for a
- * {Regexp interpolation}[rdoc-ref:Regexp@Interpolation+Mode]:
+ * {Regexp literal}[rdoc-ref:regexp.rdoc@Regexp+Literal]:
*
* r1 = Regexp.new(s0) # => /(?ix-m:ab+c)/
* r2 = /#{s0}/ # => /(?ix-m:ab+c)/
@@ -572,6 +566,8 @@ rb_reg_str_with_term(VALUE re, int term)
{
int options, opt;
const int embeddable = ONIG_OPTION_MULTILINE|ONIG_OPTION_IGNORECASE|ONIG_OPTION_EXTEND;
+ long len;
+ const UChar* ptr;
VALUE str = rb_str_buf_new2("(?");
char optbuf[OPTBUF_SIZE + 1]; /* for '-' */
rb_encoding *enc = rb_enc_get(re);
@@ -580,9 +576,8 @@ rb_reg_str_with_term(VALUE re, int term)
rb_enc_copy(str, re);
options = RREGEXP_PTR(re)->options;
- VALUE src_str = RREGEXP_SRC(re);
- const UChar *ptr = (UChar *)RSTRING_PTR(src_str);
- long len = RSTRING_LEN(src_str);
+ ptr = (UChar*)RREGEXP_SRC_PTR(re);
+ len = RREGEXP_SRC_LEN(re);
again:
if (len >= 4 && ptr[0] == '(' && ptr[1] == '?') {
int err = 1;
@@ -672,17 +667,15 @@ rb_reg_str_with_term(VALUE re, int term)
}
rb_enc_copy(str, re);
- RB_GC_GUARD(src_str);
-
return str;
}
-NORETURN(static void rb_reg_raise(const char *err, VALUE re));
+NORETURN(static void rb_reg_raise(const char *s, long len, const char *err, VALUE re));
static void
-rb_reg_raise(const char *err, VALUE re)
+rb_reg_raise(const char *s, long len, const char *err, VALUE re)
{
- VALUE desc = rb_reg_desc(re);
+ VALUE desc = rb_reg_desc(s, len, re);
rb_raise(rb_eRegexpError, "%s: %"PRIsVALUE, err, desc);
}
@@ -770,8 +763,8 @@ rb_reg_casefold_p(VALUE re)
* /foo/mix.options # => 7
*
* Note that additional bits may be set in the returned integer;
- * these are maintained internally in +self+, are ignored if passed
- * to Regexp.new, and may be ignored by the caller:
+ * these are maintained internally internally in +self+,
+ * are ignored if passed to Regexp.new, and may be ignored by the caller:
*
* Returns the set of bits corresponding to the options used when
* creating this regexp (see Regexp::new for details). Note that
@@ -969,13 +962,12 @@ VALUE rb_cMatch;
static VALUE
match_alloc(VALUE klass)
{
- size_t alloc_size = sizeof(struct RMatch) + sizeof(rb_matchext_t);
- VALUE flags = T_MATCH | (RGENGC_WB_PROTECTED_MATCH ? FL_WB_PROTECTED : 0);
- NEWOBJ_OF(match, struct RMatch, klass, flags, alloc_size, 0);
+ NEWOBJ_OF(match, struct RMatch, klass, T_MATCH);
- match->str = Qfalse;
- match->regexp = Qfalse;
- memset(RMATCH_EXT(match), 0, sizeof(rb_matchext_t));
+ match->str = 0;
+ match->rmatch = 0;
+ match->regexp = 0;
+ match->rmatch = ZALLOC(struct rmatch);
return (VALUE)match;
}
@@ -1010,7 +1002,7 @@ pair_byte_cmp(const void *pair1, const void *pair2)
static void
update_char_offset(VALUE match)
{
- rb_matchext_t *rm = RMATCH_EXT(match);
+ struct rmatch *rm = RMATCH(match)->rmatch;
struct re_registers *regs;
int i, num_regs, num_pos;
long c;
@@ -1088,23 +1080,23 @@ match_check(VALUE match)
static VALUE
match_init_copy(VALUE obj, VALUE orig)
{
- rb_matchext_t *rm;
+ struct rmatch *rm;
if (!OBJ_INIT_COPY(obj, orig)) return obj;
- RB_OBJ_WRITE(obj, &RMATCH(obj)->str, RMATCH(orig)->str);
- RB_OBJ_WRITE(obj, &RMATCH(obj)->regexp, RMATCH(orig)->regexp);
+ RMATCH(obj)->str = RMATCH(orig)->str;
+ RMATCH(obj)->regexp = RMATCH(orig)->regexp;
- rm = RMATCH_EXT(obj);
+ rm = RMATCH(obj)->rmatch;
if (rb_reg_region_copy(&rm->regs, RMATCH_REGS(orig)))
rb_memerror();
- if (RMATCH_EXT(orig)->char_offset_num_allocated) {
+ if (RMATCH(orig)->rmatch->char_offset_num_allocated) {
if (rm->char_offset_num_allocated < rm->regs.num_regs) {
REALLOC_N(rm->char_offset, struct rmatch_offset, rm->regs.num_regs);
rm->char_offset_num_allocated = rm->regs.num_regs;
}
- MEMCPY(rm->char_offset, RMATCH_EXT(orig)->char_offset,
+ MEMCPY(rm->char_offset, RMATCH(orig)->rmatch->char_offset,
struct rmatch_offset, rm->regs.num_regs);
RB_GC_GUARD(orig);
}
@@ -1133,7 +1125,7 @@ match_regexp(VALUE match)
if (NIL_P(regexp)) {
VALUE str = rb_reg_nth_match(0, match);
regexp = rb_reg_regcomp(rb_reg_quote(str));
- RB_OBJ_WRITE(match, &RMATCH(match)->regexp, regexp);
+ RMATCH(match)->regexp = regexp;
}
return regexp;
}
@@ -1178,6 +1170,8 @@ match_names(VALUE match)
* # => #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
* m.size # => 5
*
+ * MatchData#length is an alias for MatchData.size.
+ *
*/
static VALUE
@@ -1259,8 +1253,8 @@ match_offset(VALUE match, VALUE n)
return rb_assoc_new(Qnil, Qnil);
update_char_offset(match);
- return rb_assoc_new(LONG2NUM(RMATCH_EXT(match)->char_offset[i].beg),
- LONG2NUM(RMATCH_EXT(match)->char_offset[i].end));
+ return rb_assoc_new(LONG2NUM(RMATCH(match)->rmatch->char_offset[i].beg),
+ LONG2NUM(RMATCH(match)->rmatch->char_offset[i].end));
}
/*
@@ -1298,54 +1292,6 @@ match_byteoffset(VALUE match, VALUE n)
/*
* call-seq:
- * bytebegin(n) -> integer
- * bytebegin(name) -> integer
- *
- * :include: doc/matchdata/bytebegin.rdoc
- *
- */
-
-static VALUE
-match_bytebegin(VALUE match, VALUE n)
-{
- int i = match_backref_number(match, n);
- struct re_registers *regs = RMATCH_REGS(match);
-
- match_check(match);
- backref_number_check(regs, i);
-
- if (BEG(i) < 0)
- return Qnil;
- return LONG2NUM(BEG(i));
-}
-
-
-/*
- * call-seq:
- * byteend(n) -> integer
- * byteend(name) -> integer
- *
- * :include: doc/matchdata/byteend.rdoc
- *
- */
-
-static VALUE
-match_byteend(VALUE match, VALUE n)
-{
- int i = match_backref_number(match, n);
- struct re_registers *regs = RMATCH_REGS(match);
-
- match_check(match);
- backref_number_check(regs, i);
-
- if (BEG(i) < 0)
- return Qnil;
- return LONG2NUM(END(i));
-}
-
-
-/*
- * call-seq:
* begin(n) -> integer
* begin(name) -> integer
*
@@ -1366,7 +1312,7 @@ match_begin(VALUE match, VALUE n)
return Qnil;
update_char_offset(match);
- return LONG2NUM(RMATCH_EXT(match)->char_offset[i].beg);
+ return LONG2NUM(RMATCH(match)->rmatch->char_offset[i].beg);
}
@@ -1392,7 +1338,7 @@ match_end(VALUE match, VALUE n)
return Qnil;
update_char_offset(match);
- return LONG2NUM(RMATCH_EXT(match)->char_offset[i].end);
+ return LONG2NUM(RMATCH(match)->rmatch->char_offset[i].end);
}
/*
@@ -1479,7 +1425,7 @@ match_nth_length(VALUE match, VALUE n)
update_char_offset(match);
const struct rmatch_offset *const ofs =
- &RMATCH_EXT(match)->char_offset[i];
+ &RMATCH(match)->rmatch->char_offset[i];
return LONG2NUM(ofs->end - ofs->beg);
}
@@ -1507,14 +1453,31 @@ rb_match_count(VALUE match)
return regs->num_regs;
}
+int
+rb_match_nth_defined(int nth, VALUE match)
+{
+ struct re_registers *regs;
+ if (NIL_P(match)) return FALSE;
+ regs = RMATCH_REGS(match);
+ if (!regs) return FALSE;
+ if (nth >= regs->num_regs) {
+ return FALSE;
+ }
+ if (nth < 0) {
+ nth += regs->num_regs;
+ if (nth <= 0) return FALSE;
+ }
+ return (BEG(nth) != -1);
+}
+
static void
match_set_string(VALUE m, VALUE string, long pos, long len)
{
struct RMatch *match = (struct RMatch *)m;
- rb_matchext_t *rmatch = RMATCH_EXT(match);
+ struct rmatch *rmatch = match->rmatch;
- RB_OBJ_WRITE(match, &RMATCH(match)->str, string);
- RB_OBJ_WRITE(match, &RMATCH(match)->regexp, Qnil);
+ match->str = string;
+ match->regexp = Qnil;
int err = onig_region_resize(&rmatch->regs, 1);
if (err) rb_memerror();
rmatch->regs.beg[0] = pos;
@@ -1578,8 +1541,8 @@ reg_enc_error(VALUE re, VALUE str)
{
rb_raise(rb_eEncCompatError,
"incompatible encoding regexp match (%s regexp with %s string)",
- rb_enc_inspect_name(rb_enc_get(re)),
- rb_enc_inspect_name(rb_enc_get(str)));
+ rb_enc_name(rb_enc_get(re)),
+ rb_enc_name(rb_enc_get(str)));
}
static inline int
@@ -1632,25 +1595,24 @@ rb_reg_prepare_enc(VALUE re, VALUE str, int warn)
}
regex_t *
-rb_reg_prepare_re(VALUE re, VALUE str)
+rb_reg_prepare_re0(VALUE re, VALUE str, onig_errmsg_buffer err)
{
+ regex_t *reg = RREGEXP_PTR(re);
int r;
OnigErrorInfo einfo;
+ const char *pattern;
VALUE unescaped;
rb_encoding *fixed_enc = 0;
rb_encoding *enc = rb_reg_prepare_enc(re, str, 1);
- regex_t *reg = RREGEXP_PTR(re);
if (reg->enc == enc) return reg;
rb_reg_check(re);
+ reg = RREGEXP_PTR(re);
+ pattern = RREGEXP_SRC_PTR(re);
- VALUE src_str = RREGEXP_SRC(re);
- const char *pattern = RSTRING_PTR(src_str);
-
- onig_errmsg_buffer err = "";
unescaped = rb_reg_preprocess(
- pattern, pattern + RSTRING_LEN(src_str), enc,
+ pattern, pattern + RREGEXP_SRC_LEN(re), enc,
&fixed_enc, err, 0);
if (NIL_P(unescaped)) {
@@ -1663,76 +1625,25 @@ rb_reg_prepare_re(VALUE re, VALUE str)
const char *ptr;
long len;
RSTRING_GETMEM(unescaped, ptr, len);
-
- /* If there are no other users of this regex, then we can directly overwrite it. */
- if (RREGEXP(re)->usecnt == 0) {
- regex_t tmp_reg;
- r = onig_new_without_alloc(&tmp_reg, (UChar *)ptr, (UChar *)(ptr + len),
- reg->options, enc,
- OnigDefaultSyntax, &einfo);
-
- if (r) {
- /* There was an error so perform cleanups. */
- onig_free_body(&tmp_reg);
- }
- else {
- onig_free_body(reg);
- /* There are no errors so set reg to tmp_reg. */
- *reg = tmp_reg;
- }
- }
- else {
- r = onig_new(&reg, (UChar *)ptr, (UChar *)(ptr + len),
- reg->options, enc,
- OnigDefaultSyntax, &einfo);
- }
-
+ r = onig_new(&reg, (UChar *)ptr, (UChar *)(ptr + len),
+ reg->options, enc,
+ OnigDefaultSyntax, &einfo);
if (r) {
onig_error_code_to_str((UChar*)err, r, &einfo);
- rb_reg_raise(err, re);
+ rb_reg_raise(pattern, RREGEXP_SRC_LEN(re), err, re);
}
reg->timelimit = timelimit;
RB_GC_GUARD(unescaped);
- RB_GC_GUARD(src_str);
return reg;
}
-OnigPosition
-rb_reg_onig_match(VALUE re, VALUE str,
- OnigPosition (*match)(regex_t *reg, VALUE str, struct re_registers *regs, void *args),
- void *args, struct re_registers *regs)
+regex_t *
+rb_reg_prepare_re(VALUE re, VALUE str)
{
- regex_t *reg = rb_reg_prepare_re(re, str);
-
- bool tmpreg = reg != RREGEXP_PTR(re);
- if (!tmpreg) RREGEXP(re)->usecnt++;
-
- OnigPosition result = match(reg, str, regs, args);
-
- if (!tmpreg) RREGEXP(re)->usecnt--;
- if (tmpreg) {
- onig_free(reg);
- }
-
- if (result < 0) {
- onig_region_free(regs, 0);
-
- switch (result) {
- case ONIG_MISMATCH:
- break;
- case ONIGERR_TIMEOUT:
- rb_raise(rb_eRegexpTimeoutError, "regexp match timeout");
- default: {
- onig_errmsg_buffer err = "";
- onig_error_code_to_str((UChar*)err, (int)result);
- rb_reg_raise(err, re);
- }
- }
- }
-
- return result;
+ onig_errmsg_buffer err = "";
+ return rb_reg_prepare_re0(re, str, err);
}
long
@@ -1766,58 +1677,68 @@ rb_reg_adjust_startpos(VALUE re, VALUE str, long pos, int reverse)
return pos;
}
-struct reg_onig_search_args {
- long pos;
- long range;
-};
-
-static OnigPosition
-reg_onig_search(regex_t *reg, VALUE str, struct re_registers *regs, void *args_ptr)
-{
- struct reg_onig_search_args *args = (struct reg_onig_search_args *)args_ptr;
- const char *ptr;
- long len;
- RSTRING_GETMEM(str, ptr, len);
-
- return onig_search(
- reg,
- (UChar *)ptr,
- (UChar *)(ptr + len),
- (UChar *)(ptr + args->pos),
- (UChar *)(ptr + args->range),
- regs,
- ONIG_OPTION_NONE);
-}
-
/* returns byte offset */
static long
rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_backref_str, VALUE *set_match)
{
- long len = RSTRING_LEN(str);
+ long result;
+ VALUE match;
+ struct re_registers regi, *regs = &regi;
+ char *start, *range;
+ long len;
+ regex_t *reg;
+ int tmpreg;
+ onig_errmsg_buffer err = "";
+
+ RSTRING_GETMEM(str, start, len);
+ range = start;
if (pos > len || pos < 0) {
rb_backref_set(Qnil);
return -1;
}
- struct reg_onig_search_args args = {
- .pos = pos,
- .range = reverse ? 0 : len,
- };
- struct re_registers regs = {0};
-
- OnigPosition result = rb_reg_onig_match(re, str, reg_onig_search, &args, &regs);
+ reg = rb_reg_prepare_re0(re, str, err);
+ tmpreg = reg != RREGEXP_PTR(re);
+ if (!tmpreg) RREGEXP(re)->usecnt++;
- if (result == ONIG_MISMATCH) {
- rb_backref_set(Qnil);
- return ONIG_MISMATCH;
+ MEMZERO(regs, struct re_registers, 1);
+ if (!reverse) {
+ range += len;
+ }
+ result = onig_search(reg,
+ (UChar*)start,
+ ((UChar*)(start + len)),
+ ((UChar*)(start + pos)),
+ ((UChar*)range),
+ regs, ONIG_OPTION_NONE);
+ if (!tmpreg) RREGEXP(re)->usecnt--;
+ if (tmpreg) {
+ if (RREGEXP(re)->usecnt) {
+ onig_free(reg);
+ }
+ else {
+ onig_free(RREGEXP_PTR(re));
+ RREGEXP_PTR(re) = reg;
+ }
+ }
+ if (result < 0) {
+ if (regs == &regi)
+ onig_region_free(regs, 0);
+ if (result == ONIG_MISMATCH) {
+ rb_backref_set(Qnil);
+ return result;
+ }
+ else {
+ onig_error_code_to_str((UChar*)err, (int)result);
+ rb_reg_raise(RREGEXP_SRC_PTR(re), RREGEXP_SRC_LEN(re), err, re);
+ }
}
- VALUE match = match_alloc(rb_cMatch);
- rb_matchext_t *rm = RMATCH_EXT(match);
- rm->regs = regs;
+ match = match_alloc(rb_cMatch);
+ memcpy(RMATCH_REGS(match), regs, sizeof(struct re_registers));
if (set_backref_str) {
- RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
+ RMATCH(match)->str = rb_str_new4(str);
}
else {
/* Note that a MatchData object with RMATCH(match)->str == 0 is incomplete!
@@ -1827,7 +1748,7 @@ rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_back
rb_obj_hide(match);
}
- RB_OBJ_WRITE(match, &RMATCH(match)->regexp, re);
+ RMATCH(match)->regexp = re;
rb_backref_set(match);
if (set_match) *set_match = match;
@@ -1846,39 +1767,74 @@ rb_reg_search(VALUE re, VALUE str, long pos, int reverse)
return rb_reg_search0(re, str, pos, reverse, 1);
}
-static OnigPosition
-reg_onig_match(regex_t *reg, VALUE str, struct re_registers *regs, void *_)
+bool
+rb_reg_start_with_p(VALUE re, VALUE str)
{
+ long result;
+ VALUE match;
+ struct re_registers regi, *regs = &regi;
+ regex_t *reg;
+ int tmpreg;
+ onig_errmsg_buffer err = "";
+
+ reg = rb_reg_prepare_re0(re, str, err);
+ tmpreg = reg != RREGEXP_PTR(re);
+ if (!tmpreg) RREGEXP(re)->usecnt++;
+
+ match = rb_backref_get();
+ if (!NIL_P(match)) {
+ if (FL_TEST(match, MATCH_BUSY)) {
+ match = Qnil;
+ }
+ else {
+ regs = RMATCH_REGS(match);
+ }
+ }
+ if (NIL_P(match)) {
+ MEMZERO(regs, struct re_registers, 1);
+ }
const char *ptr;
long len;
RSTRING_GETMEM(str, ptr, len);
+ result = onig_match(reg,
+ (UChar*)(ptr),
+ ((UChar*)(ptr + len)),
+ (UChar*)(ptr),
+ regs, ONIG_OPTION_NONE);
+ if (!tmpreg) RREGEXP(re)->usecnt--;
+ if (tmpreg) {
+ if (RREGEXP(re)->usecnt) {
+ onig_free(reg);
+ }
+ else {
+ onig_free(RREGEXP_PTR(re));
+ RREGEXP_PTR(re) = reg;
+ }
+ }
+ if (result < 0) {
+ if (regs == &regi)
+ onig_region_free(regs, 0);
+ if (result == ONIG_MISMATCH) {
+ rb_backref_set(Qnil);
+ return false;
+ }
+ else {
+ onig_error_code_to_str((UChar*)err, (int)result);
+ rb_reg_raise(RREGEXP_SRC_PTR(re), RREGEXP_SRC_LEN(re), err, re);
+ }
+ }
- return onig_match(
- reg,
- (UChar *)ptr,
- (UChar *)(ptr + len),
- (UChar *)ptr,
- regs,
- ONIG_OPTION_NONE);
-}
-
-bool
-rb_reg_start_with_p(VALUE re, VALUE str)
-{
- VALUE match = rb_backref_get();
- if (NIL_P(match) || FL_TEST(match, MATCH_BUSY)) {
+ if (NIL_P(match)) {
+ int err;
match = match_alloc(rb_cMatch);
+ err = rb_reg_region_copy(RMATCH_REGS(match), regs);
+ onig_region_free(regs, 0);
+ if (err) rb_memerror();
}
- struct re_registers *regs = RMATCH_REGS(match);
-
- if (rb_reg_onig_match(re, str, reg_onig_match, NULL, regs) == ONIG_MISMATCH) {
- rb_backref_set(Qnil);
- return false;
- }
+ RMATCH(match)->str = rb_str_new4(str);
- RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
- RB_OBJ_WRITE(match, &RMATCH(match)->regexp, re);
+ RMATCH(match)->regexp = re;
rb_backref_set(match);
return true;
@@ -2000,37 +1956,21 @@ rb_reg_match_post(VALUE match)
return str;
}
-static int
-match_last_index(VALUE match)
+VALUE
+rb_reg_match_last(VALUE match)
{
int i;
struct re_registers *regs;
- if (NIL_P(match)) return -1;
+ if (NIL_P(match)) return Qnil;
match_check(match);
regs = RMATCH_REGS(match);
- if (BEG(0) == -1) return -1;
+ if (BEG(0) == -1) return Qnil;
for (i=regs->num_regs-1; BEG(i) == -1 && i > 0; i--)
;
- return i;
-}
-
-VALUE
-rb_reg_match_last(VALUE match)
-{
- int i = match_last_index(match);
- if (i <= 0) return Qnil;
- struct re_registers *regs = RMATCH_REGS(match);
- return rb_str_subseq(RMATCH(match)->str, BEG(i), END(i) - BEG(i));
-}
-
-VALUE
-rb_reg_last_defined(VALUE match)
-{
- int i = match_last_index(match);
- if (i < 0) return Qnil;
- return RBOOL(i);
+ if (i == 0) return Qnil;
+ return rb_reg_nth_match(i, match);
}
static VALUE
@@ -2218,17 +2158,6 @@ match_ary_aref(VALUE match, VALUE idx, VALUE result)
* m['foo'] # => "h"
* m[:bar] # => "ge"
*
- * If multiple captures have the same name, returns the last matched
- * substring.
- *
- * m = /(?<foo>.)(?<foo>.+)/.match("hoge")
- * # => #<MatchData "hoge" foo:"h" foo:"oge">
- * m[:foo] #=> "oge"
- *
- * m = /\W(?<foo>.+)|\w(?<foo>.+)|(?<foo>.+)/.match("hoge")
- * #<MatchData "hoge" foo:nil foo:"oge" foo:nil>
- * m[:foo] #=> "oge"
- *
*/
static VALUE
@@ -2391,7 +2320,7 @@ match_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
/*
* call-seq:
- * named_captures(symbolize_names: false) -> hash
+ * named_captures -> hash
*
* Returns a hash of the named captures;
* each key is a capture name; each value is its captured string or +nil+:
@@ -2412,17 +2341,10 @@ match_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
* # => #<MatchData "01" a:"0" a:"1">
* m.named_captures #=> {"a" => "1"}
*
- * If keyword argument +symbolize_names+ is given
- * a true value, the keys in the resulting hash are Symbols:
- *
- * m = /(?<a>.)(?<a>.)/.match("01")
- * # => #<MatchData "01" a:"0" a:"1">
- * m.named_captures(symbolize_names: true) #=> {:a => "1"}
- *
*/
static VALUE
-match_named_captures(int argc, VALUE *argv, VALUE match)
+match_named_captures(VALUE match)
{
VALUE hash;
struct MEMO *memo;
@@ -2431,27 +2353,8 @@ match_named_captures(int argc, VALUE *argv, VALUE match)
if (NIL_P(RMATCH(match)->regexp))
return rb_hash_new();
- VALUE opt;
- VALUE symbolize_names = 0;
-
- rb_scan_args(argc, argv, "0:", &opt);
-
- if (!NIL_P(opt)) {
- static ID keyword_ids[1];
-
- VALUE symbolize_names_val;
-
- if (!keyword_ids[0]) {
- keyword_ids[0] = rb_intern_const("symbolize_names");
- }
- rb_get_kwargs(opt, keyword_ids, 0, 1, &symbolize_names_val);
- if (!UNDEF_P(symbolize_names_val) && RTEST(symbolize_names_val)) {
- symbolize_names = 1;
- }
- }
-
hash = rb_hash_new();
- memo = MEMO_NEW(hash, match, symbolize_names);
+ memo = MEMO_NEW(hash, match, 0);
onig_foreach_name(RREGEXP(RMATCH(match)->regexp)->ptr, match_named_captures_iter, (void*)memo);
@@ -2468,7 +2371,7 @@ match_named_captures(int argc, VALUE *argv, VALUE match)
* m.deconstruct_keys([:hours, :minutes]) # => {:hours => "18", :minutes => "37"}
* m.deconstruct_keys(nil) # => {:hours => "18", :minutes => "37", :seconds => "22"}
*
- * Returns an empty hash if no named captures were defined:
+ * Returns an empty hash of no named captures were defined:
*
* m = /(\d{2}):(\d{2}):(\d{2})/.match("18:37:22")
* m.deconstruct_keys(nil) # => {}
@@ -2567,10 +2470,10 @@ match_inspect_name_iter(const OnigUChar *name, const OnigUChar *name_end,
}
/*
- * call-seq:
- * inspect -> string
+ * call-seq:
+ * inspect -> string
*
- * Returns a string representation of +self+:
+ * Returns a string representation of +self+:
*
* m = /.$/.match("foo")
* # => #<MatchData "o">
@@ -2585,6 +2488,7 @@ match_inspect_name_iter(const OnigUChar *name, const OnigUChar *name_end,
* m.inspect # => "#<MatchData \"fo\" 1:\"f\" 2:nil 3:\"o\">"
*
* Related: MatchData#to_s.
+ *
*/
static VALUE
@@ -3097,55 +3001,55 @@ escape_asis:
parens++;
}
- for (s = p+1; s < end; s++) {
+ for(s = p+1; s < end; s++) {
switch(*s) {
- case 'x':
- local_extend = invert ? -1 : 1;
- break;
- case '-':
- invert = 1;
- break;
- case ':':
- case ')':
- if (local_extend == 0 ||
- (local_extend == -1 && !extended_mode) ||
- (local_extend == 1 && extended_mode)) {
- /* no changes to extended flag */
- goto fallthrough;
- }
+ case 'x':
+ local_extend = invert ? -1 : 1;
+ break;
+ case '-':
+ invert = 1;
+ break;
+ case ':':
+ case ')':
+ if (local_extend == 0 ||
+ (local_extend == -1 && !extended_mode) ||
+ (local_extend == 1 && extended_mode)) {
+ /* no changes to extended flag */
+ goto fallthrough;
+ }
- if (*s == ':') {
- /* change extended flag until ')' */
- int local_options = options;
- if (local_extend == 1) {
- local_options |= ONIG_OPTION_EXTEND;
+ if (*s == ':') {
+ /* change extended flag until ')' */
+ int local_options = options;
+ if (local_extend == 1) {
+ local_options |= ONIG_OPTION_EXTEND;
+ }
+ else {
+ local_options &= ~ONIG_OPTION_EXTEND;
+ }
+
+ rb_str_buf_cat(buf, (char *)&c, 1);
+ int ret = unescape_nonascii0(&p, end, enc, buf, encp,
+ has_property, err,
+ local_options, 1);
+ if (ret < 0) return ret;
+ goto begin_scan;
}
else {
- local_options &= ~ONIG_OPTION_EXTEND;
+ /* change extended flag for rest of expression */
+ extended_mode = local_extend == 1;
+ goto fallthrough;
}
-
- rb_str_buf_cat(buf, (char *)&c, 1);
- int ret = unescape_nonascii0(&p, end, enc, buf, encp,
- has_property, err,
- local_options, 1);
- if (ret < 0) return ret;
- goto begin_scan;
- }
- else {
- /* change extended flag for rest of expression */
- extended_mode = local_extend == 1;
+ case 'i':
+ case 'm':
+ case 'a':
+ case 'd':
+ case 'u':
+ /* other option flags, ignored during scanning */
+ break;
+ default:
+ /* other character, no extended flag change*/
goto fallthrough;
- }
- case 'i':
- case 'm':
- case 'a':
- case 'd':
- case 'u':
- /* other option flags, ignored during scanning */
- break;
- default:
- /* other character, no extended flag change*/
- goto fallthrough;
}
}
}
@@ -3287,15 +3191,6 @@ rb_reg_preprocess_dregexp(VALUE ary, int options)
return result;
}
-static void
-rb_reg_initialize_check(VALUE obj)
-{
- rb_check_frozen(obj);
- if (RREGEXP_PTR(obj)) {
- rb_raise(rb_eTypeError, "already initialized regexp");
- }
-}
-
static int
rb_reg_initialize(VALUE obj, const char *s, long len, rb_encoding *enc,
int options, onig_errmsg_buffer err,
@@ -3306,7 +3201,12 @@ rb_reg_initialize(VALUE obj, const char *s, long len, rb_encoding *enc,
rb_encoding *fixed_enc = 0;
rb_encoding *a_enc = rb_ascii8bit_encoding();
- rb_reg_initialize_check(obj);
+ rb_check_frozen(obj);
+ if (FL_TEST(obj, REG_LITERAL))
+ rb_raise(rb_eSecurityError, "can't modify literal regexp");
+ if (re->ptr)
+ rb_raise(rb_eTypeError, "already initialized regexp");
+ re->ptr = 0;
if (rb_enc_dummy_p(enc)) {
errcpy(err, "can't make regexp with dummy encoding");
@@ -3383,7 +3283,7 @@ rb_reg_initialize_str(VALUE obj, VALUE str, int options, onig_errmsg_buffer err,
static VALUE
rb_reg_s_alloc(VALUE klass)
{
- NEWOBJ_OF(re, struct RRegexp, klass, T_REGEXP | (RGENGC_WB_PROTECTED_REGEXP ? FL_WB_PROTECTED : 0), sizeof(struct RRegexp), 0);
+ NEWOBJ_OF(re, struct RRegexp, klass, T_REGEXP | (RGENGC_WB_PROTECTED_REGEXP ? FL_WB_PROTECTED : 0));
re->ptr = 0;
RB_OBJ_WRITE(re, &re->src, 0);
@@ -3430,7 +3330,7 @@ rb_reg_init_str_enc(VALUE re, VALUE s, rb_encoding *enc, int options)
return re;
}
-VALUE
+MJIT_FUNC_EXPORTED VALUE
rb_reg_new_ary(VALUE ary, int opt)
{
VALUE re = rb_reg_new_str(rb_reg_preprocess_dregexp(ary, opt), opt);
@@ -3469,6 +3369,7 @@ rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline)
rb_set_errinfo(rb_reg_error_desc(str, options, err));
return Qnil;
}
+ FL_SET(re, REG_LITERAL);
rb_obj_freeze(re);
return re;
}
@@ -3528,6 +3429,8 @@ reg_hash(VALUE re)
* /foo/ == Regexp.new('food') # => false
* /foo/ == Regexp.new("abc".force_encoding("euc-jp")) # => false
*
+ * Regexp#eql? is an alias for Regexp#==.
+ *
*/
VALUE
@@ -3578,6 +3481,9 @@ match_hash(VALUE match)
* Returns +true+ if +object+ is another \MatchData object
* whose target string, regexp, match, and captures
* are the same as +self+, +false+ otherwise.
+ *
+ * MatchData#eql? is an alias for MatchData#==.
+ *
*/
static VALUE
@@ -3642,7 +3548,7 @@ reg_match_pos(VALUE re, VALUE *strp, long pos, VALUE* set_match)
* Returns the integer index (in characters) of the first match
* for +self+ and +string+, or +nil+ if none;
* also sets the
- * {rdoc-ref:Regexp global variables}[rdoc-ref:Regexp@Global+Variables]:
+ * {rdoc-ref:Regexp Global Variables}[rdoc-ref:Regexp@Regexp+Global+Variables]:
*
* /at/ =~ 'input data' # => 7
* $~ # => #<MatchData "at">
@@ -3655,7 +3561,7 @@ reg_match_pos(VALUE re, VALUE *strp, long pos, VALUE* set_match)
* - Is a regexp literal;
* see {Regexp Literals}[rdoc-ref:literals.rdoc@Regexp+Literals].
* - Does not contain interpolations;
- * see {Regexp interpolation}[rdoc-ref:Regexp@Interpolation+Mode].
+ * see {Regexp Interpolation}[rdoc-ref:Regexp@Regexp+Interpolation].
* - Is at the left of the expression.
*
* Example:
@@ -3858,6 +3764,12 @@ rb_reg_match_m_p(int argc, VALUE *argv, VALUE re)
VALUE
rb_reg_match_p(VALUE re, VALUE str, long pos)
{
+ regex_t *reg;
+ onig_errmsg_buffer err = "";
+ OnigPosition result;
+ const UChar *start, *end;
+ int tmpreg;
+
if (NIL_P(str)) return Qfalse;
str = SYMBOL_P(str) ? rb_sym2str(str) : StringValue(str);
if (pos) {
@@ -3872,13 +3784,33 @@ rb_reg_match_p(VALUE re, VALUE str, long pos)
pos = beg - RSTRING_PTR(str);
}
}
-
- struct reg_onig_search_args args = {
- .pos = pos,
- .range = RSTRING_LEN(str),
- };
-
- return rb_reg_onig_match(re, str, reg_onig_search, &args, NULL) == ONIG_MISMATCH ? Qfalse : Qtrue;
+ reg = rb_reg_prepare_re0(re, str, err);
+ tmpreg = reg != RREGEXP_PTR(re);
+ if (!tmpreg) RREGEXP(re)->usecnt++;
+ start = ((UChar*)RSTRING_PTR(str));
+ end = start + RSTRING_LEN(str);
+ result = onig_search(reg, start, end, start + pos, end,
+ NULL, ONIG_OPTION_NONE);
+ if (!tmpreg) RREGEXP(re)->usecnt--;
+ if (tmpreg) {
+ if (RREGEXP(re)->usecnt) {
+ onig_free(reg);
+ }
+ else {
+ onig_free(RREGEXP_PTR(re));
+ RREGEXP_PTR(re) = reg;
+ }
+ }
+ if (result < 0) {
+ if (result == ONIG_MISMATCH) {
+ return Qfalse;
+ }
+ else {
+ onig_error_code_to_str((UChar*)err, (int)result);
+ rb_reg_raise(RREGEXP_SRC_PTR(re), RREGEXP_SRC_LEN(re), err, re);
+ }
+ }
+ return Qtrue;
}
/*
@@ -3916,26 +3848,6 @@ set_timeout(rb_hrtime_t *hrt, VALUE timeout)
double2hrtime(hrt, timeout_d);
}
-static VALUE
-reg_copy(VALUE copy, VALUE orig)
-{
- int r;
- regex_t *re;
-
- rb_reg_initialize_check(copy);
- if ((r = onig_reg_copy(&re, RREGEXP_PTR(orig))) != 0) {
- /* ONIGERR_MEMORY only */
- rb_raise(rb_eRegexpError, "%s", onig_error_code_to_format(r));
- }
- RREGEXP_PTR(copy) = re;
- RB_OBJ_WRITE(copy, &RREGEXP(copy)->src, RREGEXP(orig)->src);
- RREGEXP_PTR(copy)->timelimit = RREGEXP_PTR(orig)->timelimit;
- rb_enc_copy(copy, orig);
- FL_SET_RAW(copy, FL_TEST_RAW(orig, KCODE_FIXED|REG_ENCODING_NONE));
-
- return copy;
-}
-
struct reg_init_args {
VALUE str;
VALUE timeout;
@@ -3966,7 +3878,7 @@ void rb_warn_deprecated_to_remove(const char *removal, const char *fmt, const ch
* Regexp.new('foo', 'i') # => /foo/i
* Regexp.new('foo', 'im') # => /foo/im
*
- * - The bit-wise OR of one or more of the constants
+ * - The logical OR of one or more of the constants
* Regexp::EXTENDED, Regexp::IGNORECASE, Regexp::MULTILINE, and
* Regexp::NOENCODING:
*
@@ -3978,8 +3890,6 @@ void rb_warn_deprecated_to_remove(const char *removal, const char *fmt, const ch
* Regexp.new('foo', flags) # => /foo/mix
*
* - +nil+ or +false+, which is ignored.
- * - Any other truthy value, in which case the regexp will be
- * case-insensitive.
*
* If optional keyword argument +timeout+ is given,
* its float value overrides the timeout interval for the class,
@@ -3999,20 +3909,17 @@ void rb_warn_deprecated_to_remove(const char *removal, const char *fmt, const ch
* r3 = Regexp.new(r, timeout: 3.14) # => /foo/m
* r3.timeout # => 3.14
*
+ * Regexp.compile is an alias for Regexp.new.
+ *
*/
static VALUE
rb_reg_initialize_m(int argc, VALUE *argv, VALUE self)
{
struct reg_init_args args;
- VALUE re = reg_extract_args(argc, argv, &args);
- if (NIL_P(re)) {
- reg_init_args(self, args.str, args.enc, args.flags);
- }
- else {
- reg_copy(self, re);
- }
+ reg_extract_args(argc, argv, &args);
+ reg_init_args(self, args.str, args.enc, args.flags);
set_timeout(&RREGEXP_PTR(self)->timelimit, args.timeout);
@@ -4024,10 +3931,10 @@ reg_extract_args(int argc, VALUE *argv, struct reg_init_args *args)
{
int flags = 0;
rb_encoding *enc = 0;
- VALUE str, src, opts = Qundef, kwargs;
+ VALUE str, src, opts = Qundef, n_flag = Qundef, kwargs;
VALUE re = Qnil;
- rb_scan_args(argc, argv, "11:", &src, &opts, &kwargs);
+ argc = rb_scan_args(argc, argv, "12:", &src, &opts, &n_flag, &kwargs);
args->timeout = Qnil;
if (!NIL_P(kwargs)) {
@@ -4038,6 +3945,10 @@ reg_extract_args(int argc, VALUE *argv, struct reg_init_args *args)
rb_get_kwargs(kwargs, keywords, 0, 1, &args->timeout);
}
+ if (argc == 3) {
+ rb_warn_deprecated_to_remove("3.3", "3rd argument to Regexp.new", "2nd argument");
+ }
+
if (RB_TYPE_P(src, T_REGEXP)) {
re = src;
@@ -4049,13 +3960,20 @@ reg_extract_args(int argc, VALUE *argv, struct reg_init_args *args)
str = RREGEXP_SRC(re);
}
else {
- if (!NIL_P(opts)) {
+ if (!UNDEF_P(opts)) {
int f;
if (FIXNUM_P(opts)) flags = FIX2INT(opts);
else if ((f = str_to_option(opts)) >= 0) flags = f;
- else if (rb_bool_expected(opts, "ignorecase", FALSE))
+ else if (!NIL_P(opts) && rb_bool_expected(opts, "ignorecase", FALSE))
flags = ONIG_OPTION_IGNORECASE;
}
+ if (!NIL_OR_UNDEF_P(n_flag)) {
+ char *kcode = StringValuePtr(n_flag);
+ if (kcode[0] == 'n' || kcode[0] == 'N') {
+ enc = rb_ascii8bit_encoding();
+ flags |= ARG_ENCODING_NONE;
+ }
+ }
str = StringValue(src);
}
args->str = str;
@@ -4186,6 +4104,8 @@ rb_reg_quote(VALUE str)
* r = Regexp.new(Regexp.escape(s)) # => /\\\\\\\*\\\?\\\{\\\}\\\./
* r.match(s) # => #<MatchData "\\\\\\*\\?\\{\\}\\.">
*
+ * Regexp.quote is an alias for Regexp.escape.
+ *
*/
static VALUE
@@ -4435,7 +4355,7 @@ rb_reg_init_copy(VALUE copy, VALUE re)
{
if (!OBJ_INIT_COPY(copy, re)) return copy;
rb_reg_check(re);
- return reg_copy(copy, re);
+ return rb_reg_init_str(copy, RREGEXP_SRC(re), rb_reg_options(re));
}
VALUE
@@ -4607,9 +4527,9 @@ match_setter(VALUE val, ID _x, VALUE *_y)
* Regexp.last_match(n) -> string or nil
* Regexp.last_match(name) -> string or nil
*
- * With no argument, returns the value of <tt>$~</tt>,
+ * With no argument, returns the value of <tt>$!</tt>,
* which is the result of the most recent pattern match
- * (see {Regexp global variables}[rdoc-ref:Regexp@Global+Variables]):
+ * (see {Regexp Global Variables}[rdoc-ref:Regexp@Regexp+Global+Variables]):
*
* /c(.)t/ =~ 'cat' # => 0
* Regexp.last_match # => #<MatchData "cat" 1:"a">
@@ -4658,9 +4578,12 @@ re_warn(const char *s)
rb_warn("%s", s);
}
+// The process-global timeout for regexp matching
+rb_hrtime_t rb_reg_match_time_limit = 0;
+
// This function is periodically called during regexp matching
-bool
-rb_reg_timeout_p(regex_t *reg, void *end_time_)
+void
+rb_reg_check_timeout(regex_t *reg, void *end_time_)
{
rb_hrtime_t *end_time = (rb_hrtime_t *)end_time_;
@@ -4685,12 +4608,10 @@ rb_reg_timeout_p(regex_t *reg, void *end_time_)
}
else {
if (*end_time < rb_hrtime_now()) {
- // Timeout has exceeded
- return true;
+ // timeout is exceeded
+ rb_raise(rb_eRegexpTimeoutError, "regexp match timeout");
}
}
-
- return false;
}
/*
@@ -4771,7 +4692,7 @@ rb_reg_timeout_get(VALUE re)
/*
* Document-class: Regexp
*
- * :include: doc/_regexp.rdoc
+ * :include: doc/regexp.rdoc
*/
void
@@ -4857,8 +4778,6 @@ Init_Regexp(void)
rb_define_method(rb_cMatch, "length", match_size, 0);
rb_define_method(rb_cMatch, "offset", match_offset, 1);
rb_define_method(rb_cMatch, "byteoffset", match_byteoffset, 1);
- rb_define_method(rb_cMatch, "bytebegin", match_bytebegin, 1);
- rb_define_method(rb_cMatch, "byteend", match_byteend, 1);
rb_define_method(rb_cMatch, "begin", match_begin, 1);
rb_define_method(rb_cMatch, "end", match_end, 1);
rb_define_method(rb_cMatch, "match", match_nth, 1);
@@ -4867,7 +4786,7 @@ Init_Regexp(void)
rb_define_method(rb_cMatch, "[]", match_aref, -1);
rb_define_method(rb_cMatch, "captures", match_captures, 0);
rb_define_alias(rb_cMatch, "deconstruct", "captures");
- rb_define_method(rb_cMatch, "named_captures", match_named_captures, -1);
+ rb_define_method(rb_cMatch, "named_captures", match_named_captures, 0);
rb_define_method(rb_cMatch, "deconstruct_keys", match_deconstruct_keys, 1);
rb_define_method(rb_cMatch, "values_at", match_values_at, -1);
rb_define_method(rb_cMatch, "pre_match", rb_reg_match_pre, 0);
diff --git a/regcomp.c b/regcomp.c
index 38bfed5631..be85d85f93 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -195,7 +195,8 @@ unset_addr_list_init(UnsetAddrList* uslist, int size)
static void
unset_addr_list_end(UnsetAddrList* uslist)
{
- xfree(uslist->us);
+ if (IS_NOT_NULL(uslist->us))
+ xfree(uslist->us);
}
static int
@@ -1273,10 +1274,6 @@ compile_length_enclose_node(EncloseNode* node, regex_t* reg)
break;
case ENCLOSE_STOP_BACKTRACK:
- /* Disable POP_STOP_BT optimization for simple repeat under the match cache */
- /* optimization because the match cache optimization pushes an extra item to */
- /* the stack and it breaks the assumption for this optimization. */
-#ifndef USE_MATCH_CACHE
if (IS_ENCLOSE_STOP_BT_SIMPLE_REPEAT(node)) {
QtfrNode* qn = NQTFR(node->target);
tlen = compile_length_tree(qn->target, reg);
@@ -1286,11 +1283,8 @@ compile_length_enclose_node(EncloseNode* node, regex_t* reg)
+ SIZE_OP_PUSH + tlen + SIZE_OP_POP + SIZE_OP_JUMP;
}
else {
-#endif
len = SIZE_OP_PUSH_STOP_BT + tlen + SIZE_OP_POP_STOP_BT;
-#ifndef USE_MATCH_CACHE
}
-#endif
break;
case ENCLOSE_CONDITION:
@@ -1402,10 +1396,6 @@ compile_enclose_node(EncloseNode* node, regex_t* reg)
break;
case ENCLOSE_STOP_BACKTRACK:
- /* Disable POP_STOP_BT optimization for simple repeat under the match cache */
- /* optimization because the match cache optimization pushes an extra item to */
- /* the stack and it breaks the assumption for this optimization. */
-#ifndef USE_MATCH_CACHE
if (IS_ENCLOSE_STOP_BT_SIMPLE_REPEAT(node)) {
QtfrNode* qn = NQTFR(node->target);
r = compile_tree_n_times(qn->target, qn->lower, reg);
@@ -1424,15 +1414,12 @@ compile_enclose_node(EncloseNode* node, regex_t* reg)
-((int )SIZE_OP_PUSH + len + (int )SIZE_OP_POP + (int )SIZE_OP_JUMP));
}
else {
-#endif
r = add_opcode(reg, OP_PUSH_STOP_BT);
if (r) return r;
r = compile_tree(node->target, reg);
if (r) return r;
r = add_opcode(reg, OP_POP_STOP_BT);
-#ifndef USE_MATCH_CACHE
}
-#endif
break;
case ENCLOSE_CONDITION:
@@ -3395,7 +3382,7 @@ next_setup(Node* node, Node* next_node, regex_t* reg)
}
else if (type == NT_ENCLOSE) {
EncloseNode* en = NENCLOSE(node);
- if (en->type == ENCLOSE_MEMORY && !IS_ENCLOSE_CALLED(en)) {
+ if (en->type == ENCLOSE_MEMORY) {
node = en->target;
goto retry;
}
@@ -5496,8 +5483,10 @@ clear_optimize_info(regex_t* reg)
reg->sub_anchor = 0;
reg->exact_end = (UChar* )NULL;
reg->threshold_len = 0;
- xfree(reg->exact);
- reg->exact = (UChar* )NULL;
+ if (IS_NOT_NULL(reg->exact)) {
+ xfree(reg->exact);
+ reg->exact = (UChar* )NULL;
+ }
}
#ifdef ONIG_DEBUG
@@ -5660,12 +5649,12 @@ extern void
onig_free_body(regex_t* reg)
{
if (IS_NOT_NULL(reg)) {
- xfree(reg->p);
- xfree(reg->exact);
- xfree(reg->int_map);
- xfree(reg->int_map_backward);
- xfree(reg->repeat_range);
- onig_free(reg->chain);
+ if (IS_NOT_NULL(reg->p)) xfree(reg->p);
+ if (IS_NOT_NULL(reg->exact)) xfree(reg->exact);
+ if (IS_NOT_NULL(reg->int_map)) xfree(reg->int_map);
+ if (IS_NOT_NULL(reg->int_map_backward)) xfree(reg->int_map_backward);
+ if (IS_NOT_NULL(reg->repeat_range)) xfree(reg->repeat_range);
+ if (IS_NOT_NULL(reg->chain)) onig_free(reg->chain);
#ifdef USE_NAMED_GROUP
onig_names_free(reg);
@@ -5682,80 +5671,6 @@ onig_free(regex_t* reg)
}
}
-static void*
-dup_copy(const void *ptr, size_t size)
-{
- void *newptr = xmalloc(size);
- if (IS_NOT_NULL(newptr)) {
- memcpy(newptr, ptr, size);
- }
- return newptr;
-}
-
-extern int
-onig_reg_copy(regex_t** nreg, regex_t* oreg)
-{
- if (IS_NOT_NULL(oreg)) {
- regex_t *reg = *nreg = (regex_t* )xmalloc(sizeof(regex_t));
- if (IS_NULL(reg)) return ONIGERR_MEMORY;
-
- *reg = *oreg;
-
-# define COPY_FAILED(mem, size) IS_NULL(reg->mem = dup_copy(reg->mem, size))
-
- if (IS_NOT_NULL(reg->exact)) {
- size_t exact_size = reg->exact_end - reg->exact;
- if (COPY_FAILED(exact, exact_size))
- goto err;
- (reg)->exact_end = (reg)->exact + exact_size;
- }
-
- if (IS_NOT_NULL(reg->int_map)) {
- if (COPY_FAILED(int_map, sizeof(int) * ONIG_CHAR_TABLE_SIZE))
- goto err_int_map;
- }
- if (IS_NOT_NULL(reg->int_map_backward)) {
- if (COPY_FAILED(int_map_backward, sizeof(int) * ONIG_CHAR_TABLE_SIZE))
- goto err_int_map_backward;
- }
- if (IS_NOT_NULL(reg->p)) {
- if (COPY_FAILED(p, reg->alloc))
- goto err_p;
- }
- if (IS_NOT_NULL(reg->repeat_range)) {
- if (COPY_FAILED(repeat_range, reg->repeat_range_alloc * sizeof(OnigRepeatRange)))
- goto err_repeat_range;
- }
- if (IS_NOT_NULL(reg->name_table)) {
- if (onig_names_copy(reg, oreg))
- goto err_name_table;
- }
- if (IS_NOT_NULL(reg->chain)) {
- if (onig_reg_copy(&reg->chain, reg->chain))
- goto err_chain;
- }
- return 0;
-# undef COPY_FAILED
-
- err_chain:
- onig_names_free(reg);
- err_name_table:
- xfree(reg->repeat_range);
- err_repeat_range:
- xfree(reg->p);
- err_p:
- xfree(reg->int_map_backward);
- err_int_map_backward:
- xfree(reg->int_map);
- err_int_map:
- xfree(reg->exact);
- err:
- xfree(reg);
- return ONIGERR_MEMORY;
- }
- return 0;
-}
-
#ifdef RUBY
size_t
onig_memsize(const regex_t *reg)
@@ -6012,8 +5927,8 @@ onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end,
}
onig_node_free(root);
- xfree(scan_env.mem_nodes_dynamic);
-
+ if (IS_NOT_NULL(scan_env.mem_nodes_dynamic))
+ xfree(scan_env.mem_nodes_dynamic);
return r;
}
@@ -6085,15 +6000,20 @@ onig_new(regex_t** reg, const UChar* pattern, const UChar* pattern_end,
OnigOptionType option, OnigEncoding enc, const OnigSyntaxType* syntax,
OnigErrorInfo* einfo)
{
+ int r;
+
*reg = (regex_t* )xmalloc(sizeof(regex_t));
if (IS_NULL(*reg)) return ONIGERR_MEMORY;
- int r = onig_new_without_alloc(*reg, pattern, pattern_end, option, enc, syntax, einfo);
+ r = onig_reg_init(*reg, option, ONIGENC_CASE_FOLD_DEFAULT, enc, syntax);
+ if (r) goto err;
+
+ r = onig_compile(*reg, pattern, pattern_end, einfo);
if (r) {
+ err:
onig_free(*reg);
*reg = NULL;
}
-
return r;
}
diff --git a/regenc.h b/regenc.h
index 352a8d7980..4b4d21a715 100644
--- a/regenc.h
+++ b/regenc.h
@@ -118,6 +118,11 @@ typedef struct {
typedef struct {
short int len;
+#if defined(__has_attribute)
+# if __has_attribute(nonstring)
+ __attribute__((nonstring))
+# endif
+#endif
const UChar name[6];
int ctype;
} PosixBracketEntryType;
diff --git a/regexec.c b/regexec.c
index 8c6bccf546..47fc88c9c2 100644
--- a/regexec.c
+++ b/regexec.c
@@ -231,46 +231,22 @@ onig_get_capture_tree(OnigRegion* region)
}
#endif /* USE_CAPTURE_HISTORY */
-#ifdef USE_MATCH_CACHE
-
-/*
-Glossary for "match cache"
-
-"match cache" or "match cache optimization"
-The `Regexp#match` optimization by using a cache.
-
-"cache opcode"
-A cachable opcode (e.g. `OP_PUSH`, `OP_REPEAT`, etc).
-It is corresponding to some cache points.
-
-"cache point"
-A cachable point on matching.
-Usually, one-to-one corresponding between a cache opcode and a cache point exists,
-but cache opcodes between `OP_REPEAT` and `OP_REPEAT_INC` have some corresponding
-cache points depending on repetition counts.
-
-"match cache point"
-A pair of a cache point and a position on an input string.
-We encode a match cache point to an integer value by the following equation:
-"match cache point" = "position on input string" * "total number of cache points" + "cache point"
-
-"match cache buffer"
-A bit-array for memoizing (recording) match cache points once backtracked.
-*/
-
-static OnigPosition count_num_cache_opcodes_inner(
- const regex_t* reg,
- MemNumType current_repeat_mem, int lookaround_nesting,
- UChar** pp, long* num_cache_opcodes_ptr
-)
+#ifdef USE_CACHE_MATCH_OPT
+
+/* count number of jump-like opcodes for allocation of cache memory. */
+static OnigPosition
+count_num_cache_opcode(regex_t* reg, long* num, long* table_size)
{
- UChar* p = *pp;
- UChar* pend = reg->p + reg->used;
+ UChar* p = reg->p;
+ UChar* pend = p + reg->used;
LengthType len;
- MemNumType repeat_mem;
+ MemNumType mem;
+ MemNumType current_mem = -1;
+ long current_mem_num = 0;
OnigEncoding enc = reg->enc;
- long num_cache_opcodes = *num_cache_opcodes_ptr;
- OnigPosition result;
+
+ *num = 0;
+ *table_size = 0;
while (p < pend) {
switch (*p++) {
@@ -284,7 +260,7 @@ static OnigPosition count_num_cache_opcodes_inner(
case OP_EXACT4: p += 4; break;
case OP_EXACT5: p += 5; break;
case OP_EXACTN:
- GET_LENGTH_INC(len, p); p += len; break;
+ GET_LENGTH_INC(len, p); p += len; break;
case OP_EXACTMB2N1: p += 2; break;
case OP_EXACTMB2N2: p += 4; break;
case OP_EXACTMB2N3: p += 6; break;
@@ -299,7 +275,7 @@ static OnigPosition count_num_cache_opcodes_inner(
GET_LENGTH_INC(len, p);
p += mb_len * len;
}
- break;
+ break;
case OP_EXACT1_IC:
len = enclen(enc, p, pend); p += len; break;
@@ -308,7 +284,7 @@ static OnigPosition count_num_cache_opcodes_inner(
case OP_CCLASS:
case OP_CCLASS_NOT:
- p += SIZE_BITSET; break;
+ p += SIZE_BITSET; break;
case OP_CCLASS_MB:
case OP_CCLASS_MB_NOT:
GET_LENGTH_INC(len, p); p += len; break;
@@ -324,10 +300,10 @@ static OnigPosition count_num_cache_opcodes_inner(
break;
case OP_ANYCHAR_STAR:
case OP_ANYCHAR_ML_STAR:
- num_cache_opcodes++; break;
+ *num += 1; *table_size += 1; break;
case OP_ANYCHAR_STAR_PEEK_NEXT:
case OP_ANYCHAR_ML_STAR_PEEK_NEXT:
- p++; num_cache_opcodes++; break;
+ p++; *num += 1; *table_size += 1; break;
case OP_WORD:
case OP_NOT_WORD:
@@ -360,7 +336,7 @@ static OnigPosition count_num_cache_opcodes_inner(
case OP_BACKREF_MULTI:
case OP_BACKREF_MULTI_IC:
case OP_BACKREF_WITH_LEVEL:
- goto impossible;
+ goto fail;
case OP_MEMORY_START:
case OP_MEMORY_START_PUSH:
@@ -368,12 +344,7 @@ static OnigPosition count_num_cache_opcodes_inner(
case OP_MEMORY_END_PUSH_REC:
case OP_MEMORY_END:
case OP_MEMORY_END_REC:
- p += SIZE_MEMNUM;
- // A memory (capture) in look-around is found.
- if (lookaround_nesting != 0) {
- goto impossible;
- }
- break;
+ p += SIZE_MEMNUM; break;
case OP_KEEP:
break;
@@ -381,131 +352,91 @@ static OnigPosition count_num_cache_opcodes_inner(
case OP_FAIL:
break;
case OP_JUMP:
- p += SIZE_RELADDR;
+ p += SIZE_RELADDR;
break;
case OP_PUSH:
- p += SIZE_RELADDR;
- num_cache_opcodes++;
+ p += SIZE_RELADDR;
+ *num += 1;
+ *table_size += 1;
break;
case OP_POP:
break;
case OP_PUSH_OR_JUMP_EXACT1:
case OP_PUSH_IF_PEEK_NEXT:
- p += SIZE_RELADDR + 1; num_cache_opcodes++; break;
+ p += SIZE_RELADDR + 1; *num += 1; *table_size += 1; break;
case OP_REPEAT:
case OP_REPEAT_NG:
- if (current_repeat_mem != -1) {
+ if (current_mem != -1) {
// A nested OP_REPEAT is not yet supported.
- goto impossible;
+ goto fail;
}
- GET_MEMNUM_INC(repeat_mem, p);
+ GET_MEMNUM_INC(mem, p);
p += SIZE_RELADDR;
- if (reg->repeat_range[repeat_mem].lower == 0) {
- num_cache_opcodes++;
- }
- result = count_num_cache_opcodes_inner(reg, repeat_mem, lookaround_nesting, &p, &num_cache_opcodes);
- if (result < 0 || num_cache_opcodes < 0) {
- goto fail;
+ if (reg->repeat_range[mem].lower == 0) {
+ *num += 1;
+ *table_size += 1;
}
- {
- OnigRepeatRange *repeat_range = &reg->repeat_range[repeat_mem];
- if (repeat_range->lower < repeat_range->upper) {
- num_cache_opcodes++;
- }
- }
+ reg->repeat_range[mem].base_num = *num;
+ current_mem = mem;
+ current_mem_num = *num;
break;
case OP_REPEAT_INC:
case OP_REPEAT_INC_NG:
- GET_MEMNUM_INC(repeat_mem, p);
- if (repeat_mem != current_repeat_mem) {
+ GET_MEMNUM_INC(mem, p);
+ if (mem != current_mem) {
// A lone or invalid OP_REPEAT_INC is found.
- goto impossible;
+ goto fail;
+ }
+ {
+ long inner_num = *num - current_mem_num;
+ OnigRepeatRange *repeat_range = &reg->repeat_range[mem];
+ repeat_range->inner_num = inner_num;
+ *num -= inner_num;
+ *num += inner_num * repeat_range->lower + (inner_num + 1) * (repeat_range->upper == 0x7fffffff ? 1 : repeat_range->upper - repeat_range->lower);
+ if (repeat_range->lower < repeat_range->upper) {
+ *table_size += 1;
+ }
+ current_mem = -1;
+ current_mem_num = 0;
}
- goto exit;
+ break;
case OP_REPEAT_INC_SG:
case OP_REPEAT_INC_NG_SG:
- goto impossible;
+ // TODO: Support nested OP_REPEAT.
+ goto fail;
case OP_NULL_CHECK_START:
- p += SIZE_MEMNUM;
- break;
case OP_NULL_CHECK_END:
- case OP_NULL_CHECK_END_MEMST_PUSH:
- p += SIZE_MEMNUM;
- break;
case OP_NULL_CHECK_END_MEMST:
- p += SIZE_MEMNUM;
- break;
+ case OP_NULL_CHECK_END_MEMST_PUSH:
+ p += SIZE_MEMNUM; break;
case OP_PUSH_POS:
- if (lookaround_nesting < 0) {
- // A look-around nested in a atomic grouping is found.
- goto impossible;
- }
- result = count_num_cache_opcodes_inner(reg, current_repeat_mem, lookaround_nesting + 1, &p, &num_cache_opcodes);
- if (result < 0 || num_cache_opcodes < 0) {
- goto fail;
- }
- break;
- case OP_PUSH_POS_NOT:
- if (lookaround_nesting < 0) {
- // A look-around nested in a atomic grouping is found.
- goto impossible;
- }
- p += SIZE_RELADDR;
- result = count_num_cache_opcodes_inner(reg, current_repeat_mem, lookaround_nesting + 1, &p, &num_cache_opcodes);
- if (result < 0 || num_cache_opcodes < 0) {
- goto fail;
- }
- break;
- case OP_PUSH_LOOK_BEHIND_NOT:
- if (lookaround_nesting < 0) {
- // A look-around nested in a atomic grouping is found.
- goto impossible;
- }
- p += SIZE_RELADDR;
- p += SIZE_LENGTH;
- result = count_num_cache_opcodes_inner(reg, current_repeat_mem, lookaround_nesting + 1, &p, &num_cache_opcodes);
- if (result < 0 || num_cache_opcodes < 0) {
- goto fail;
- }
- break;
- case OP_PUSH_STOP_BT:
- if (lookaround_nesting != 0) {
- // A nested atomic grouping is found.
- goto impossible;
- }
- result = count_num_cache_opcodes_inner(reg, current_repeat_mem, -1, &p, &num_cache_opcodes);
- if (result < 0 || num_cache_opcodes < 0) {
- goto fail;
- }
- break;
case OP_POP_POS:
+ case OP_PUSH_POS_NOT:
case OP_FAIL_POS:
- case OP_FAIL_LOOK_BEHIND_NOT:
+ case OP_PUSH_STOP_BT:
case OP_POP_STOP_BT:
- goto exit;
case OP_LOOK_BEHIND:
- p += SIZE_LENGTH;
- break;
-
+ case OP_PUSH_LOOK_BEHIND_NOT:
+ case OP_FAIL_LOOK_BEHIND_NOT:
case OP_PUSH_ABSENT_POS:
case OP_ABSENT_END:
case OP_ABSENT:
- goto impossible;
+ goto fail;
case OP_CALL:
case OP_RETURN:
- goto impossible;
+ goto fail;
case OP_CONDITION:
- goto impossible;
+ goto fail;
case OP_STATE_CHECK_PUSH:
case OP_STATE_CHECK_PUSH_OR_JUMP:
case OP_STATE_CHECK:
case OP_STATE_CHECK_ANYCHAR_STAR:
case OP_STATE_CHECK_ANYCHAR_ML_STAR:
- goto impossible;
+ goto fail;
case OP_SET_OPTION_PUSH:
case OP_SET_OPTION:
@@ -513,69 +444,32 @@ static OnigPosition count_num_cache_opcodes_inner(
break;
default:
- goto bytecode_error;
+ goto bytecode_error;
}
}
-exit:
- *pp = p;
- *num_cache_opcodes_ptr = num_cache_opcodes;
return 0;
fail:
- *num_cache_opcodes_ptr = num_cache_opcodes;
- return result;
-
-impossible:
- *num_cache_opcodes_ptr = NUM_CACHE_OPCODES_IMPOSSIBLE;
+ *num = NUM_CACHE_OPCODE_FAIL;
return 0;
bytecode_error:
return ONIGERR_UNDEFINED_BYTECODE;
}
-/* count the total number of cache opcodes for allocating a match cache buffer. */
-static OnigPosition
-count_num_cache_opcodes(const regex_t* reg, long* num_cache_opcodes_ptr)
-{
- UChar* p = reg->p;
- *num_cache_opcodes_ptr = 0;
- OnigPosition result = count_num_cache_opcodes_inner(reg, -1, 0, &p, num_cache_opcodes_ptr);
- if (result == 0 && *num_cache_opcodes_ptr >= 0 && p != reg->p + reg->used) {
- return ONIGERR_UNDEFINED_BYTECODE;
- }
-
- return result;
-}
-
static OnigPosition
-init_cache_opcodes_inner(
- const regex_t* reg,
- MemNumType current_repeat_mem, int lookaround_nesting,
- OnigCacheOpcode** cache_opcodes_ptr, UChar** pp, long* num_cache_points_ptr
-)
+init_cache_index_table(regex_t* reg, OnigCacheIndex *table)
{
- UChar* p = *pp;
- UChar* pend = reg->p + reg->used;
UChar* pbegin;
+ UChar* p = reg->p;
+ UChar* pend = p + reg->used;
LengthType len;
- MemNumType repeat_mem;
+ MemNumType mem;
+ MemNumType current_mem = -1;
+ long num = 0;
+ long current_mem_num = 0;
OnigEncoding enc = reg->enc;
- long cache_point = *num_cache_points_ptr;
- OnigCacheOpcode *cache_opcodes = *cache_opcodes_ptr;
- OnigPosition result;
-
-# define INC_CACHE_OPCODES do {\
- cache_opcodes->addr = pbegin;\
- cache_opcodes->cache_point = cache_point;\
- cache_opcodes->outer_repeat_mem = current_repeat_mem;\
- cache_opcodes->num_cache_points_at_outer_repeat = 0;\
- cache_opcodes->num_cache_points_in_outer_repeat = 0;\
- cache_opcodes->lookaround_nesting = lookaround_nesting;\
- cache_opcodes->match_addr = NULL;\
- cache_point += lookaround_nesting != 0 ? 2 : 1;\
- cache_opcodes++;\
- } while (0)
while (p < pend) {
pbegin = p;
@@ -590,7 +484,7 @@ init_cache_opcodes_inner(
case OP_EXACT4: p += 4; break;
case OP_EXACT5: p += 5; break;
case OP_EXACTN:
- GET_LENGTH_INC(len, p); p += len; break;
+ GET_LENGTH_INC(len, p); p += len; break;
case OP_EXACTMB2N1: p += 2; break;
case OP_EXACTMB2N2: p += 4; break;
case OP_EXACTMB2N3: p += 6; break;
@@ -605,7 +499,7 @@ init_cache_opcodes_inner(
GET_LENGTH_INC(len, p);
p += mb_len * len;
}
- break;
+ break;
case OP_EXACT1_IC:
len = enclen(enc, p, pend); p += len; break;
@@ -614,7 +508,7 @@ init_cache_opcodes_inner(
case OP_CCLASS:
case OP_CCLASS_NOT:
- p += SIZE_BITSET; break;
+ p += SIZE_BITSET; break;
case OP_CCLASS_MB:
case OP_CCLASS_MB_NOT:
GET_LENGTH_INC(len, p); p += len; break;
@@ -630,12 +524,20 @@ init_cache_opcodes_inner(
break;
case OP_ANYCHAR_STAR:
case OP_ANYCHAR_ML_STAR:
- INC_CACHE_OPCODES;
+ table->addr = pbegin;
+ table->num = num - current_mem_num;
+ table->outer_repeat = current_mem;
+ num++;
+ table++;
break;
case OP_ANYCHAR_STAR_PEEK_NEXT:
case OP_ANYCHAR_ML_STAR_PEEK_NEXT:
p++;
- INC_CACHE_OPCODES;
+ table->addr = pbegin;
+ table->num = num - current_mem_num;
+ table->outer_repeat = current_mem;
+ num++;
+ table++;
break;
case OP_WORD:
@@ -677,11 +579,7 @@ init_cache_opcodes_inner(
case OP_MEMORY_END_PUSH_REC:
case OP_MEMORY_END:
case OP_MEMORY_END_REC:
- p += SIZE_MEMNUM;
- if (lookaround_nesting != 0) {
- goto unexpected_bytecode_error;
- }
- break;
+ p += SIZE_MEMNUM; break;
case OP_KEEP:
break;
@@ -689,112 +587,79 @@ init_cache_opcodes_inner(
case OP_FAIL:
break;
case OP_JUMP:
- p += SIZE_RELADDR;
+ p += SIZE_RELADDR;
break;
case OP_PUSH:
- p += SIZE_RELADDR;
- INC_CACHE_OPCODES;
+ p += SIZE_RELADDR;
+ table->addr = pbegin;
+ table->num = num - current_mem_num;
+ table->outer_repeat = current_mem;
+ num++;
+ table++;
break;
case OP_POP:
break;
case OP_PUSH_OR_JUMP_EXACT1:
case OP_PUSH_IF_PEEK_NEXT:
p += SIZE_RELADDR + 1;
- INC_CACHE_OPCODES;
+ table->addr = pbegin;
+ table->num = num - current_mem_num;
+ table->outer_repeat = current_mem;
+ num++;
+ table++;
break;
case OP_REPEAT:
case OP_REPEAT_NG:
- GET_MEMNUM_INC(repeat_mem, p);
+ GET_MEMNUM_INC(mem, p);
p += SIZE_RELADDR;
- if (reg->repeat_range[repeat_mem].lower == 0) {
- INC_CACHE_OPCODES;
+ if (reg->repeat_range[mem].lower == 0) {
+ table->addr = pbegin;
+ table->num = num - current_mem_num;
+ table->outer_repeat = -1;
+ num++;
+ table++;
}
+ current_mem = mem;
+ current_mem_num = num;
+ break;
+ case OP_REPEAT_INC:
+ case OP_REPEAT_INC_NG:
+ GET_MEMNUM_INC(mem, p);
{
- long num_cache_points_in_repeat = 0;
- long num_cache_points_at_repeat = cache_point;
- OnigCacheOpcode* cache_opcodes_in_repeat = cache_opcodes;
- result = init_cache_opcodes_inner(reg, repeat_mem, lookaround_nesting, &cache_opcodes, &p, &num_cache_points_in_repeat);
- if (result != 0) {
- goto fail;
- }
- OnigRepeatRange *repeat_range = &reg->repeat_range[repeat_mem];
+ long inner_num = num - current_mem_num;
+ OnigRepeatRange *repeat_range = &reg->repeat_range[mem];
if (repeat_range->lower < repeat_range->upper) {
- INC_CACHE_OPCODES;
- cache_point -= lookaround_nesting != 0 ? 2 : 1;
- }
- int repeat_bounds = repeat_range->upper == 0x7fffffff ? 1 : repeat_range->upper - repeat_range->lower;
- cache_point += num_cache_points_in_repeat * repeat_range->lower + (num_cache_points_in_repeat + (lookaround_nesting != 0 ? 2 : 1)) * repeat_bounds;
- for (; cache_opcodes_in_repeat < cache_opcodes; cache_opcodes_in_repeat++) {
- cache_opcodes_in_repeat->num_cache_points_at_outer_repeat = num_cache_points_at_repeat;
- cache_opcodes_in_repeat->num_cache_points_in_outer_repeat = num_cache_points_in_repeat;
+ table->addr = pbegin;
+ table->num = num - current_mem_num;
+ table->outer_repeat = mem;
+ table++;
}
+ num -= inner_num;
+ num += inner_num * repeat_range->lower + (inner_num + 1) * (repeat_range->upper == 0x7fffffff ? 1 : repeat_range->upper - repeat_range->lower);
+ current_mem = -1;
+ current_mem_num = 0;
}
break;
- case OP_REPEAT_INC:
- case OP_REPEAT_INC_NG:
- p += SIZE_MEMNUM;
- goto exit;
case OP_REPEAT_INC_SG:
case OP_REPEAT_INC_NG_SG:
+ // TODO: support OP_REPEAT opcodes.
goto unexpected_bytecode_error;
case OP_NULL_CHECK_START:
- p += SIZE_MEMNUM;
- break;
case OP_NULL_CHECK_END:
- case OP_NULL_CHECK_END_MEMST_PUSH:
- p += SIZE_MEMNUM;
- break;
case OP_NULL_CHECK_END_MEMST:
- p += SIZE_MEMNUM;
- break;
+ case OP_NULL_CHECK_END_MEMST_PUSH:
+ p += SIZE_MEMNUM; break;
case OP_PUSH_POS:
- lookaround:
- {
- OnigCacheOpcode* cache_opcodes_in_lookaround = cache_opcodes;
- result = init_cache_opcodes_inner(reg, current_repeat_mem, lookaround_nesting + 1, &cache_opcodes, &p, &cache_point);
- if (result != 0) {
- goto fail;
- }
- UChar* match_addr = p - 1;
- for (; cache_opcodes_in_lookaround < cache_opcodes; cache_opcodes_in_lookaround++) {
- if (cache_opcodes_in_lookaround->match_addr == NULL) {
- cache_opcodes_in_lookaround->match_addr = match_addr;
- }
- }
- }
- break;
- case OP_PUSH_POS_NOT:
- p += SIZE_RELADDR;
- goto lookaround;
- case OP_PUSH_LOOK_BEHIND_NOT:
- p += SIZE_RELADDR;
- p += SIZE_LENGTH;
- goto lookaround;
- case OP_PUSH_STOP_BT:
- {
- OnigCacheOpcode* cache_opcodes_in_atomic = cache_opcodes;
- result = init_cache_opcodes_inner(reg, current_repeat_mem, -1, &cache_opcodes, &p, &cache_point);
- if (result != 0) {
- goto fail;
- }
- UChar* match_addr = p - 1;
- for (; cache_opcodes_in_atomic < cache_opcodes; cache_opcodes_in_atomic++) {
- if (cache_opcodes_in_atomic->match_addr == NULL) {
- cache_opcodes_in_atomic->match_addr = match_addr;
- }
- }
- }
- break;
case OP_POP_POS:
+ case OP_PUSH_POS_NOT:
case OP_FAIL_POS:
- case OP_FAIL_LOOK_BEHIND_NOT:
+ case OP_PUSH_STOP_BT:
case OP_POP_STOP_BT:
- goto exit;
case OP_LOOK_BEHIND:
- p += SIZE_LENGTH;
- break;
-
+ case OP_PUSH_LOOK_BEHIND_NOT:
+ case OP_FAIL_LOOK_BEHIND_NOT:
+ case OP_PUSH_ABSENT_POS:
case OP_ABSENT_END:
case OP_ABSENT:
goto unexpected_bytecode_error;
@@ -819,54 +684,33 @@ init_cache_opcodes_inner(
break;
default:
- goto bytecode_error;
+ goto bytecode_error;
}
}
-exit:
- *cache_opcodes_ptr = cache_opcodes;
- *pp = p;
- *num_cache_points_ptr = cache_point;
return 0;
-fail:
- return result;
-
unexpected_bytecode_error:
return ONIGERR_UNEXPECTED_BYTECODE;
bytecode_error:
return ONIGERR_UNDEFINED_BYTECODE;
}
-
-/* collect cache opcodes from the given regex program, and compute the total number of cache points. */
+#else /* USE_MATCH_CACHE */
static OnigPosition
-init_cache_opcodes(const regex_t* reg, OnigCacheOpcode* cache_opcodes_ptr, long* num_cache_points_ptr)
+count_num_cache_opcode(regex_t* reg, long* num, long* table_size)
{
- UChar* p = reg->p;
- *num_cache_points_ptr = 0;
- OnigPosition result = init_cache_opcodes_inner(reg, -1, 0, &cache_opcodes_ptr, &p, num_cache_points_ptr);
- if (result == 0 && p != reg->p + reg->used) {
- return ONIGERR_UNDEFINED_BYTECODE;
- }
-
- return result;
-}
-#else
-static OnigPosition
-count_num_cache_opcodes(regex_t* reg, long* num_cache_opcodes)
-{
- *num_cache_opcodes = NUM_CACHE_OPCODES_IMPOSSIBLE;
+ *num = NUM_CACHE_OPCODE_FAIL;
return 0;
}
-#endif /* USE_MATCH_CACHE */
+#endif
extern int
onig_check_linear_time(OnigRegexType* reg)
{
- long num_cache_opcodes = 0;
- count_num_cache_opcodes(reg, &num_cache_opcodes);
- return num_cache_opcodes != NUM_CACHE_OPCODES_IMPOSSIBLE;
+ long num = 0, table_size = 0;
+ count_num_cache_opcode(reg, &num, &table_size);
+ return num != NUM_CACHE_OPCODE_FAIL;
}
extern void
@@ -982,18 +826,14 @@ onig_region_free(OnigRegion* r, int free_self)
{
if (r) {
if (r->allocated > 0) {
- xfree(r->beg);
- xfree(r->end);
+ if (r->beg) xfree(r->beg);
+ if (r->end) xfree(r->end);
+ r->allocated = 0;
}
#ifdef USE_CAPTURE_HISTORY
history_root_free(r);
#endif
- if (free_self) {
- xfree(r);
- }
- else {
- memset(r, 0, sizeof(OnigRegion));
- }
+ if (free_self) xfree(r);
}
}
@@ -1029,52 +869,48 @@ onig_region_copy(OnigRegion* to, const OnigRegion* from)
/* stack type */
/* used by normal-POP */
-#define STK_ALT 0x0001
-#define STK_LOOK_BEHIND_NOT 0x0002
-#define STK_POS_NOT 0x0003
+#define STK_ALT 0x0001
+#define STK_LOOK_BEHIND_NOT 0x0002
+#define STK_POS_NOT 0x0003
/* handled by normal-POP */
-#define STK_MEM_START 0x0100
-#define STK_MEM_END 0x8200
-#define STK_REPEAT_INC 0x0300
-#define STK_STATE_CHECK_MARK 0x1000
+#define STK_MEM_START 0x0100
+#define STK_MEM_END 0x8200
+#define STK_REPEAT_INC 0x0300
+#define STK_STATE_CHECK_MARK 0x1000
/* avoided by normal-POP */
-#define STK_NULL_CHECK_START 0x3000
-#define STK_NULL_CHECK_END 0x5000 /* for recursive call */
-#define STK_MEM_END_MARK 0x8400
-#define STK_POS 0x0500 /* used when POP-POS */
-#define STK_STOP_BT 0x0600 /* mark for "(?>...)" */
-#define STK_REPEAT 0x0700
-#define STK_CALL_FRAME 0x0800
-#define STK_RETURN 0x0900
-#define STK_VOID 0x0a00 /* for fill a blank */
-#define STK_ABSENT_POS 0x0b00 /* for absent */
-#define STK_ABSENT 0x0c00 /* absent inner loop marker */
-#define STK_MATCH_CACHE_POINT 0x0d00 /* for the match cache optimization */
-#define STK_ATOMIC_MATCH_CACHE_POINT 0x0e00
+#define STK_NULL_CHECK_START 0x3000
+#define STK_NULL_CHECK_END 0x5000 /* for recursive call */
+#define STK_MEM_END_MARK 0x8400
+#define STK_POS 0x0500 /* used when POP-POS */
+#define STK_STOP_BT 0x0600 /* mark for "(?>...)" */
+#define STK_REPEAT 0x0700
+#define STK_CALL_FRAME 0x0800
+#define STK_RETURN 0x0900
+#define STK_VOID 0x0a00 /* for fill a blank */
+#define STK_ABSENT_POS 0x0b00 /* for absent */
+#define STK_ABSENT 0x0c00 /* absent inner loop marker */
/* stack type check mask */
-#define STK_MASK_POP_USED 0x00ff
-#define STK_MASK_TO_VOID_TARGET 0x10ff
-#define STK_MASK_MEM_END_OR_MARK 0x8000 /* MEM_END or MEM_END_MARK */
-
-#ifdef USE_MATCH_CACHE
-#define MATCH_ARG_INIT_MATCH_CACHE(msa) do {\
- (msa).match_cache_status = MATCH_CACHE_STATUS_UNINIT;\
- (msa).num_fails = 0;\
- (msa).num_cache_opcodes = NUM_CACHE_OPCODES_UNINIT;\
- (msa).cache_opcodes = (OnigCacheOpcode*)NULL;\
- (msa).num_cache_points = 0;\
- (msa).match_cache_buf = (uint8_t*)NULL;\
+#define STK_MASK_POP_USED 0x00ff
+#define STK_MASK_TO_VOID_TARGET 0x10ff
+#define STK_MASK_MEM_END_OR_MARK 0x8000 /* MEM_END or MEM_END_MARK */
+
+#ifdef USE_CACHE_MATCH_OPT
+#define MATCH_ARG_INIT_CACHE_MATCH_OPT(msa) do {\
+ (msa).enable_cache_match_opt = 0;\
+ (msa).num_fail = 0;\
+ (msa).num_cache_opcode = NUM_CACHE_OPCODE_UNINIT;\
+ (msa).num_cache_table = 0;\
+ (msa).cache_index_table = (OnigCacheIndex *)0;\
+ (msa).match_cache = (uint8_t *)0;\
} while(0)
-#define MATCH_ARG_FREE_MATCH_CACHE(msa) do {\
- xfree((msa).cache_opcodes);\
- xfree((msa).match_cache_buf);\
- (msa).cache_opcodes = (OnigCacheOpcode*)NULL;\
- (msa).match_cache_buf = (uint8_t*)NULL;\
+#define MATCH_ARG_FREE_CACHE_MATCH_OPT(msa) do {\
+ if ((msa).cache_index_table) xfree((msa).cache_index_table);\
+ if ((msa).match_cache) xfree((msa).match_cache);\
} while(0)
#else
-#define MATCH_ARG_INIT_MATCH_CACHE(msa)
-#define MATCH_ARG_FREE_MATCH_CACHE(msa)
+#define MATCH_ARG_INIT_CACHE_MATCH_OPT(msa)
+#define MATCH_ARG_FREE_CACHE_MATCH_OPT(msa)
#endif
#ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
@@ -1087,7 +923,7 @@ onig_region_copy(OnigRegion* to, const OnigRegion* from)
(msa).best_len = ONIG_MISMATCH;\
(msa).counter = 0;\
(msa).end_time = 0;\
- MATCH_ARG_INIT_MATCH_CACHE(msa);\
+ MATCH_ARG_INIT_CACHE_MATCH_OPT(msa);\
} while(0)
#else
# define MATCH_ARG_INIT(msa, arg_option, arg_region, arg_start, arg_gpos) do {\
@@ -1098,7 +934,7 @@ onig_region_copy(OnigRegion* to, const OnigRegion* from)
(msa).gpos = (arg_gpos);\
(msa).counter = 0;\
(msa).end_time = 0;\
- MATCH_ARG_INIT_MATCH_CACHE(msa);\
+ MATCH_ARG_INIT_CACHE_MATCH_OPT(msa);\
} while(0)
#endif
@@ -1133,16 +969,16 @@ onig_region_copy(OnigRegion* to, const OnigRegion* from)
} while(0)
# define MATCH_ARG_FREE(msa) do {\
- xfree((msa).stack_p);\
+ if ((msa).stack_p) xfree((msa).stack_p);\
if ((msa).state_check_buff_size >= STATE_CHECK_BUFF_MALLOC_THRESHOLD_SIZE) { \
- xfree((msa).state_check_buff);\
+ if ((msa).state_check_buff) xfree((msa).state_check_buff);\
}\
- MATCH_ARG_FREE_MATCH_CACHE(msa);\
+ MATCH_ARG_FREE_CACHE_MATCH_OPT(msa);\
} while(0)
#else /* USE_COMBINATION_EXPLOSION_CHECK */
# define MATCH_ARG_FREE(msa) do {\
- xfree((msa).stack_p);\
- MATCH_ARG_FREE_MATCH_CACHE(msa);\
+ if ((msa).stack_p) xfree((msa).stack_p);\
+ MATCH_ARG_FREE_CACHE_MATCH_OPT(msa);\
} while (0)
#endif /* USE_COMBINATION_EXPLOSION_CHECK */
@@ -1253,7 +1089,7 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
int r = stack_double(&stk_base, &stk_end, &stk, stk_alloc, msa);\
if (r != 0) {\
STACK_SAVE;\
- xfree(xmalloc_base);\
+ if (xmalloc_base) xfree(xmalloc_base);\
return r;\
}\
}\
@@ -1359,6 +1195,129 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
#define STACK_PUSH_LOOK_BEHIND_NOT(pat,s,sprev,keep) \
STACK_PUSH(STK_LOOK_BEHIND_NOT,pat,s,sprev,keep)
+#ifdef USE_CACHE_MATCH_OPT
+
+#define DO_CACHE_MATCH_OPT(reg,stk,repeat_stk,enable,p,num_cache_table,num_cache_size,table,pos,match_cache) do {\
+ if (enable) {\
+ long cache_index = find_cache_index_table((reg), (stk), (repeat_stk), (table), (num_cache_table), (p));\
+ if (cache_index >= 0) {\
+ long key = (num_cache_size) * (long)(pos) + cache_index;\
+ long index = key >> 3;\
+ long mask = 1 << (key & 7);\
+ if ((match_cache)[index] & mask) {\
+ goto fail;\
+ }\
+ (match_cache)[index] |= mask;\
+ }\
+ }\
+} while (0)
+
+static long
+find_cache_index_table(regex_t* reg, OnigStackType *stk, OnigStackIndex *repeat_stk, OnigCacheIndex* table, long num_cache_table, UChar* p)
+{
+ long l = 0, r = num_cache_table - 1, m = 0;
+ OnigCacheIndex* item;
+ OnigRepeatRange* range;
+ OnigStackType *stkp;
+ int count = 0;
+ int is_inc = *p == OP_REPEAT_INC || *p == OP_REPEAT_INC_NG;
+
+ while (l <= r) {
+ m = (l + r) / 2;
+ if (table[m].addr == p) break;
+ if (table[m].addr < p) l = m + 1;
+ else r = m - 1;
+ }
+
+ if (!(0 <= m && m < num_cache_table && table[m].addr == p)) {
+ return -1;
+ }
+
+ item = &table[m];
+ if (item->outer_repeat == -1) {
+ return item->num;
+ }
+
+ range = &reg->repeat_range[item->outer_repeat];
+
+ stkp = &stk[repeat_stk[item->outer_repeat]];
+ count = is_inc ? stkp->u.repeat.count - 1 : stkp->u.repeat.count;
+
+ if (count < range->lower) {
+ return range->base_num + range->inner_num * count + item->num;
+ }
+
+ if (range->upper == 0x7fffffff) {
+ return range->base_num + range->inner_num * (range->lower - (is_inc ? 1 : 0)) + (is_inc ? 0 : 1) + item->num;
+ }
+
+ return range->base_num + range->inner_num * (range->lower - 1) + (range->inner_num + 1) * (count - range->lower + 1) + item->num;
+}
+
+static void
+reset_match_cache(regex_t* reg, UChar* pbegin, UChar* pend, long pos, uint8_t* match_cache, OnigCacheIndex *table, long num_cache_size, long num_cache_table)
+{
+ long l = 0, r = num_cache_table - 1, m1 = 0, m2 = 0;
+ int is_inc = *pend == OP_REPEAT_INC || *pend == OP_REPEAT_INC_NG;
+ OnigCacheIndex *item1, *item2;
+ long k1, k2, base;
+
+ while (l <= r) {
+ m1 = (l + r) / 2;
+ if (table[m1].addr == pbegin) break;
+ if (table[m1].addr < pbegin) l = m1 + 1;
+ else r = m1 - 1;
+ }
+
+ l = 0, r = num_cache_table - 1;
+ while (l <= r) {
+ m2 = (l + r) / 2;
+ if (table[m2].addr == pend) break;
+ if (table[m2].addr < pend) l = m2 + 1;
+ else r = m2 - 1;
+ }
+
+ if (table[m1].addr < pbegin && m1 + 1 < num_cache_table) m1++;
+ if (table[m2].addr > pend && m2 - 1 > 0) m2--;
+
+ item1 = &table[m1];
+ item2 = &table[m2];
+
+ if (item1->outer_repeat < 0) k1 = item1->num;
+ else k1 = reg->repeat_range[item1->outer_repeat].base_num + item1->num;
+
+ if (item2->outer_repeat < 0) k2 = item2->num;
+ else {
+ OnigRepeatRange *range = &reg->repeat_range[item2->outer_repeat];
+ if (range->upper == 0x7fffffff) k2 = range->base_num + range->inner_num * range->lower + (is_inc ? 0 : 1) + item2->num;
+ else k2 = range->base_num + range->inner_num * range->lower + (range->inner_num + 1) * (range->upper - range->lower - (is_inc ? 1 : 0)) + item2->num;
+ }
+
+ base = pos * num_cache_size;
+ k1 += base;
+ k2 += base;
+
+ if ((k1 >> 3) == (k2 >> 3)) {
+ match_cache[k1 >> 3] &= (((1 << (8 - (k2 & 7) - 1)) - 1) << ((k2 & 7) + 1)) | ((1 << (k1 & 7)) - 1);
+ } else {
+ long i = k1 >> 3;
+ if (k1 & 7) {
+ match_cache[k1 >> 3] &= (1 << ((k1 & 7) - 1)) - 1;
+ i++;
+ }
+ if (i < (k2 >> 3)) {
+ xmemset(&match_cache[i], 0, (k2 >> 3) - i);
+ if (k2 & 7) {
+ match_cache[k2 >> 3] &= (((1 << (8 - (k2 & 7) - 1)) - 1) << ((k2 & 7) + 1));
+ }
+ }
+ }
+}
+
+#else
+#define DO_CACHE_MATCH_OPT(reg,stk,repeat_stk,enable,p,num_cache_table,num_cache_size,table,pos,match_cache)
+#endif /* USE_CACHE_MATCH_OPT */
+
#define STACK_PUSH_REPEAT(id, pat) do {\
STACK_ENSURE(1);\
stk->type = STK_REPEAT;\
@@ -1485,15 +1444,6 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
STACK_INC;\
} while(0)
-#define STACK_PUSH_MATCH_CACHE_POINT(match_cache_point_index, match_cache_point_mask) do {\
- STACK_ENSURE(1);\
- stk->type = STK_MATCH_CACHE_POINT;\
- stk->null_check = stk == stk_base ? 0 : (stk-1)->null_check;\
- stk->u.match_cache_point.index = (match_cache_point_index);\
- stk->u.match_cache_point.mask = (match_cache_point_mask);\
- STACK_INC;\
-} while(0)
-
#ifdef ONIG_DEBUG
# define STACK_BASE_CHECK(p, at) \
@@ -1505,42 +1455,6 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
# define STACK_BASE_CHECK(p, at)
#endif
-#ifdef ONIG_DEBUG_MATCH_CACHE
-# define MATCH_CACHE_DEBUG_MEMOIZE(stkp) fprintf(stderr, "MATCH CACHE: memoize (index=%ld mask=%d)\n", stkp->u.match_cache_point.index, stkp->u.match_cache_point.mask);
-#else
-# define MATCH_CACHE_DEBUG_MEMOIZE(stkp) ((void) 0)
-#endif
-
-#ifdef USE_MATCH_CACHE
-# define INC_NUM_FAILS msa->num_fails++
-# define MEMOIZE_MATCH_CACHE_POINT do {\
- if (stk->type == STK_MATCH_CACHE_POINT) {\
- msa->match_cache_buf[stk->u.match_cache_point.index] |= stk->u.match_cache_point.mask;\
- MATCH_CACHE_DEBUG_MEMOIZE(stk);\
- } else if (stk->type == STK_ATOMIC_MATCH_CACHE_POINT) {\
- memoize_extended_match_cache_point(msa->match_cache_buf, stk->u.match_cache_point.index, stk->u.match_cache_point.mask);\
- MATCH_CACHE_DEBUG_MEMOIZE(stkp);\
- }\
- } while(0)
-# define MEMOIZE_LOOKAROUND_MATCH_CACHE_POINT(stkp) do {\
- if (stkp->type == STK_MATCH_CACHE_POINT) {\
- stkp->type = STK_VOID;\
- memoize_extended_match_cache_point(msa->match_cache_buf, stkp->u.match_cache_point.index, stkp->u.match_cache_point.mask);\
- MATCH_CACHE_DEBUG_MEMOIZE(stkp);\
- }\
- } while(0)
-# define MEMOIZE_ATOMIC_MATCH_CACHE_POINT do {\
- if (stk->type == STK_MATCH_CACHE_POINT) {\
- memoize_extended_match_cache_point(msa->match_cache_buf, stk->u.match_cache_point.index, stk->u.match_cache_point.mask);\
- MATCH_CACHE_DEBUG_MEMOIZE(stkp);\
- }\
- } while(0)
-#else
-# define INC_NUM_FAILS ((void) 0)
-# define MEMOIZE_MATCH_CACHE_POINT ((void) 0)
-# define MEMOIZE_LOOKAROUND_MATCH_CACHE_POINT ((void) 0)
-#endif
-
#define STACK_POP_ONE do {\
stk--;\
STACK_BASE_CHECK(stk, "STACK_POP_ONE"); \
@@ -1554,7 +1468,6 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
STACK_BASE_CHECK(stk, "STACK_POP"); \
if ((stk->type & STK_MASK_POP_USED) != 0) break;\
ELSE_IF_STATE_CHECK_MARK(stk);\
- MEMOIZE_MATCH_CACHE_POINT;\
}\
break;\
case STACK_POP_LEVEL_MEM_START:\
@@ -1567,7 +1480,6 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
mem_end_stk[stk->u.mem.num] = stk->u.mem.end;\
}\
ELSE_IF_STATE_CHECK_MARK(stk);\
- MEMOIZE_MATCH_CACHE_POINT;\
}\
break;\
default:\
@@ -1587,7 +1499,6 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
mem_end_stk[stk->u.mem.num] = stk->u.mem.end;\
}\
ELSE_IF_STATE_CHECK_MARK(stk);\
- MEMOIZE_MATCH_CACHE_POINT;\
}\
break;\
}\
@@ -1609,11 +1520,7 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
mem_start_stk[stk->u.mem.num] = stk->u.mem.start;\
mem_end_stk[stk->u.mem.num] = stk->u.mem.end;\
}\
- else if (IS_TO_VOID_TARGET(stk)) {\
- INC_NUM_FAILS;\
- }\
ELSE_IF_STATE_CHECK_MARK(stk);\
- MEMOIZE_LOOKAROUND_MATCH_CACHE_POINT(stk);\
}\
} while(0)
@@ -1670,14 +1577,12 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
k--;\
STACK_BASE_CHECK(k, "STACK_POS_END"); \
if (IS_TO_VOID_TARGET(k)) {\
- INC_NUM_FAILS;\
k->type = STK_VOID;\
}\
else if (k->type == STK_POS) {\
k->type = STK_VOID;\
break;\
}\
- MEMOIZE_LOOKAROUND_MATCH_CACHE_POINT(k);\
}\
} while(0)
@@ -1687,28 +1592,12 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
k--;\
STACK_BASE_CHECK(k, "STACK_STOP_BT_END"); \
if (IS_TO_VOID_TARGET(k)) {\
- INC_NUM_FAILS;\
k->type = STK_VOID;\
}\
else if (k->type == STK_STOP_BT) {\
k->type = STK_VOID;\
break;\
}\
- else if (k->type == STK_MATCH_CACHE_POINT) {\
- k->type = STK_ATOMIC_MATCH_CACHE_POINT;\
- }\
- }\
-} while(0)
-
-#define STACK_STOP_BT_FAIL do {\
- while (1) {\
- stk--;\
- STACK_BASE_CHECK(stk, "STACK_STOP_BT_END"); \
- if (stk->type == STK_STOP_BT) {\
- stk->type = STK_VOID;\
- break;\
- }\
- MEMOIZE_ATOMIC_MATCH_CACHE_POINT;\
}\
} while(0)
@@ -1747,7 +1636,7 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
}\
} while(0)
-#define STACK_NULL_CHECK_MEMST(isnull,id,s,reg) do {\
+#define STACK_NULL_CHECK_MEMST(isnull,ischange,id,s,reg) do {\
OnigStackType* k = STACK_AT((stk-1)->null_check)+1;\
while (1) {\
k--;\
@@ -1764,14 +1653,14 @@ stack_double(OnigStackType** arg_stk_base, OnigStackType** arg_stk_end,
while (k < stk) {\
if (k->type == STK_MEM_START) {\
if (k->u.mem.end == INVALID_STACK_INDEX) {\
- (isnull) = 0; break;\
+ (isnull) = 0; (ischange) = 1; break;\
}\
if (BIT_STATUS_AT(reg->bt_mem_end, k->u.mem.num))\
endp = STACK_AT(k->u.mem.end)->u.mem.pstr;\
else\
endp = (UChar* )k->u.mem.end;\
if (STACK_AT(k->u.mem.start)->u.mem.pstr != endp) {\
- (isnull) = 0; break;\
+ (isnull) = 0; (ischange) = 1; break;\
}\
else if (endp != s) {\
(isnull) = -1; /* empty, but position changed */ \
@@ -2167,7 +2056,7 @@ onig_print_statistics(FILE* f)
#ifdef ONIG_DEBUG_MATCH
-static const char *
+static char *
stack_type_str(int stack_type)
{
switch (stack_type) {
@@ -2189,97 +2078,10 @@ stack_type_str(int stack_type)
case STK_VOID: return "Void ";
case STK_ABSENT_POS: return "AbsPos";
case STK_ABSENT: return "Absent";
- case STK_MATCH_CACHE_POINT: return "MCache";
default: return " ";
}
}
#endif
-#ifdef USE_MATCH_CACHE
-
-static long
-bsearch_cache_opcodes(const OnigCacheOpcode *cache_opcodes, long num_cache_opcodes, const UChar* p)
-{
- long l = 0, r = num_cache_opcodes - 1, m = 0;
-
- while (l <= r) {
- m = (l + r) / 2;
- if (cache_opcodes[m].addr == p) break;
- if (cache_opcodes[m].addr < p) l = m + 1;
- else r = m - 1;
- }
- return m;
-}
-
-static long
-find_cache_point(regex_t* reg, const OnigCacheOpcode* cache_opcodes, long num_cache_opcodes, const UChar* p, const OnigStackType *stk, const OnigStackIndex *repeat_stk, const OnigCacheOpcode **cache_opcode_ptr)
-{
- long m;
- const OnigCacheOpcode* cache_opcode;
- const OnigRepeatRange* range;
- const OnigStackType *stkp;
- int count = 0;
- int is_inc = *p == OP_REPEAT_INC || *p == OP_REPEAT_INC_NG;
- long cache_point;
- long num_cache_points_at_outer_repeat;
- long num_cache_points_in_outer_repeat;
-
- m = bsearch_cache_opcodes(cache_opcodes, num_cache_opcodes, p);
-
- if (!(0 <= m && m < num_cache_opcodes && cache_opcodes[m].addr == p)) {
- return -1;
- }
-
- cache_opcode = &cache_opcodes[m];
- *cache_opcode_ptr = &cache_opcodes[m];
- cache_point = cache_opcode->cache_point;
- if (cache_opcode->outer_repeat_mem == -1) {
- return cache_point;
- }
-
- num_cache_points_at_outer_repeat = cache_opcode->num_cache_points_at_outer_repeat;
- num_cache_points_in_outer_repeat = cache_opcode->num_cache_points_in_outer_repeat;
-
- range = &reg->repeat_range[cache_opcode->outer_repeat_mem];
-
- stkp = &stk[repeat_stk[cache_opcode->outer_repeat_mem]];
- count = is_inc ? stkp->u.repeat.count - 1 : stkp->u.repeat.count;
-
- if (count < range->lower) {
- return num_cache_points_at_outer_repeat +
- num_cache_points_in_outer_repeat * count +
- cache_point;
- }
-
- if (range->upper == 0x7fffffff) {
- return num_cache_points_at_outer_repeat +
- num_cache_points_in_outer_repeat * (range->lower - (is_inc ? 1 : 0)) + (is_inc ? 0 : 1) +
- cache_point;
- }
-
- return num_cache_points_at_outer_repeat +
- num_cache_points_in_outer_repeat * (range->lower - 1) +
- (num_cache_points_in_outer_repeat + 1) * (count - range->lower + 1) +
- cache_point;
-}
-
-static int check_extended_match_cache_point(uint8_t *match_cache_buf, long match_cache_point_index, uint8_t match_cache_point_mask) {
- if (match_cache_point_mask & 0x80) {
- return (match_cache_buf[match_cache_point_index + 1] & 0x01) > 0;
- } else {
- return (match_cache_buf[match_cache_point_index] & (match_cache_point_mask << 1)) > 0;
- }
-}
-
-static void memoize_extended_match_cache_point(uint8_t *match_cache_buf, long match_cache_point_index, uint8_t match_cache_point_mask) {
- match_cache_buf[match_cache_point_index] |= match_cache_point_mask;
- if (match_cache_point_mask & 0x80) {
- match_cache_buf[match_cache_point_index + 1] |= 0x01;
- } else {
- match_cache_buf[match_cache_point_index] |= match_cache_point_mask << 1;
- }
-}
-
-#endif /* USE_MATCH_CACHE */
/* match data(str - end) from position (sstart). */
/* if sstart == str then set sprev to NULL. */
@@ -2306,7 +2108,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
UChar *pkeep;
char *alloca_base;
char *xmalloc_base = NULL;
- OnigStackType *stk_alloc, *stk_base = NULL, *stk, *stk_end;
+ OnigStackType *stk_alloc, *stk_base, *stk, *stk_end;
OnigStackType *stkp; /* used as any purpose. */
OnigStackIndex si;
OnigStackIndex *repeat_stk;
@@ -2588,49 +2390,6 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
# define OPCODE_EXEC_HOOK ((void) 0)
#endif
-#ifdef USE_MATCH_CACHE
-#ifdef ONIG_DEBUG_MATCH_CACHE
-#define MATCH_CACHE_DEBUG fprintf(stderr, "MATCH CACHE: cache %ld (p=%p index=%ld mask=%d)\n", match_cache_point, pbegin, match_cache_point_index, match_cache_point_mask)
-#define MATCH_CACHE_DEBUG_HIT fprintf(stderr, "MATCH CACHE: cache hit\n")
-#else
-#define MATCH_CACHE_DEBUG ((void) 0)
-#define MATCH_CACHE_DEBUG_HIT ((void) 0)
-#endif
-
-#define MATCH_CACHE_HIT ((void) 0)
-
-# define CHECK_MATCH_CACHE do {\
- if (msa->match_cache_status == MATCH_CACHE_STATUS_ENABLED) {\
- const OnigCacheOpcode *cache_opcode;\
- long cache_point = find_cache_point(reg, msa->cache_opcodes, msa->num_cache_opcodes, pbegin, stk_base, repeat_stk, &cache_opcode);\
- if (cache_point >= 0) {\
- long match_cache_point = msa->num_cache_points * (long)(s - str) + cache_point;\
- long match_cache_point_index = match_cache_point >> 3;\
- uint8_t match_cache_point_mask = 1 << (match_cache_point & 7);\
- MATCH_CACHE_DEBUG;\
- if (msa->match_cache_buf[match_cache_point_index] & match_cache_point_mask) {\
- MATCH_CACHE_DEBUG_HIT; MATCH_CACHE_HIT;\
- if (cache_opcode->lookaround_nesting == 0) goto fail;\
- else if (cache_opcode->lookaround_nesting < 0) {\
- if (check_extended_match_cache_point(msa->match_cache_buf, match_cache_point_index, match_cache_point_mask)) {\
- STACK_STOP_BT_FAIL;\
- goto fail;\
- } else goto fail;\
- } else {\
- if (check_extended_match_cache_point(msa->match_cache_buf, match_cache_point_index, match_cache_point_mask)) {\
- p = cache_opcode->match_addr;\
- MOP_OUT;\
- JUMP;\
- } else goto fail;\
- }\
- }\
- STACK_PUSH_MATCH_CACHE_POINT(match_cache_point_index, match_cache_point_mask);\
- }\
- }\
-} while (0)
-#else
-# define CHECK_MATCH_CACHE ((void) 0)
-#endif
VM_LOOP {
CASE(OP_END) MOP_IN(OP_END);
@@ -3058,7 +2817,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_ANYCHAR_STAR) MOP_IN(OP_ANYCHAR_STAR);
while (DATA_ENSURE_CHECK1) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
STACK_PUSH_ALT(p, s, sprev, pkeep);
n = enclen_approx(encode, s, end);
DATA_ENSURE(n);
@@ -3071,7 +2830,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_ANYCHAR_ML_STAR) MOP_IN(OP_ANYCHAR_ML_STAR);
while (DATA_ENSURE_CHECK1) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
STACK_PUSH_ALT(p, s, sprev, pkeep);
n = enclen_approx(encode, s, end);
if (n > 1) {
@@ -3089,14 +2848,14 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_ANYCHAR_STAR_PEEK_NEXT) MOP_IN(OP_ANYCHAR_STAR_PEEK_NEXT);
while (DATA_ENSURE_CHECK1) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, end - s, msa->match_cache);
if (*p == *s) {
STACK_PUSH_ALT(p + 1, s, sprev, pkeep);
} else {
-#ifdef USE_MATCH_CACHE
- /* We need to increment num_fails here, for invoking a cache optimization correctly. */
- /* Actually, the matching will be failed if we use `OP_ANYCHAR_STAR` simply in this case.*/
- msa->num_fails++;
+ /* We need to increment num_fail here, for invoking a cache optimization correctly. */
+ /* Actually, the matching will be failed if we use `OP_ANYCHAR_STAR` simply in this case.*/
+#ifdef USE_CACHE_MATCH_OPT
+ msa->num_fail++;
#endif
}
n = enclen_approx(encode, s, end);
@@ -3111,14 +2870,14 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_ANYCHAR_ML_STAR_PEEK_NEXT)MOP_IN(OP_ANYCHAR_ML_STAR_PEEK_NEXT);
while (DATA_ENSURE_CHECK1) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
if (*p == *s) {
STACK_PUSH_ALT(p + 1, s, sprev, pkeep);
} else {
-#ifdef USE_MATCH_CACHE
- /* We need to increment num_fails here, for invoking a cache optimization correctly. */
- /* Actually, the matching will be failed if we use `OP_ANYCHAR_STAR_ML` simply in this case.*/
- msa->num_fails++;
+ /* We need to increment num_fail here, for invoking a cache optimization correctly. */
+ /* Actually, the matching will be failed if we use `OP_ANYCHAR_STAR_ML` simply in this case.*/
+#ifdef USE_CACHE_MATCH_OPT
+ msa->num_fail++;
#endif
}
n = enclen_approx(encode, s, end);
@@ -3705,9 +3464,10 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_NULL_CHECK_END_MEMST) MOP_IN(OP_NULL_CHECK_END_MEMST);
{
int isnull;
+ int ischanged = 0; // set 1 when a loop is empty but memory status is changed.
GET_MEMNUM_INC(mem, p); /* mem: null check id */
- STACK_NULL_CHECK_MEMST(isnull, mem, s, reg);
+ STACK_NULL_CHECK_MEMST(isnull, ischanged, mem, s, reg);
if (isnull) {
# ifdef ONIG_DEBUG_MATCH
fprintf(stderr, "NULL_CHECK_END_MEMST: skip id:%d, s:%"PRIuPTR" (%p)\n",
@@ -3716,6 +3476,29 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
if (isnull == -1) goto fail;
goto null_check_found;
}
+# ifdef USE_CACHE_MATCH_OPT
+ if (ischanged && msa->enable_cache_match_opt) {
+ RelAddrType rel;
+ OnigUChar *addr;
+ MemNumType mem;
+ UChar* tmp = p;
+ switch (*tmp++) {
+ case OP_JUMP:
+ case OP_PUSH:
+ GET_RELADDR_INC(rel, tmp);
+ addr = tmp + rel;
+ break;
+ case OP_REPEAT_INC:
+ case OP_REPEAT_INC_NG:
+ GET_MEMNUM_INC(mem, tmp);
+ addr = STACK_AT(repeat_stk[mem])->u.repeat.pcode;
+ break;
+ default:
+ goto unexpected_bytecode_error;
+ }
+ reset_match_cache(reg, addr, pbegin, (long)(s - str), msa->match_cache, msa->cache_index_table, msa->num_cache_opcode, msa->num_cache_table);
+ }
+# endif
}
MOP_OUT;
JUMP;
@@ -3758,7 +3541,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_PUSH) MOP_IN(OP_PUSH);
GET_RELADDR_INC(addr, p);
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
MOP_OUT;
JUMP;
@@ -3799,10 +3582,10 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_POP) MOP_IN(OP_POP);
STACK_POP_ONE;
-#ifdef USE_MATCH_CACHE
- /* We need to increment num_fails here, for invoking a cache optimization correctly, */
+ /* We need to increment num_fail here, for invoking a cache optimization correctly, */
/* because Onigmo makes a loop, which is pairwise disjoint to the following set, as atomic. */
- msa->num_fails++;
+#ifdef USE_CACHE_MATCH_OPT
+ msa->num_fail++;
#endif
MOP_OUT;
JUMP;
@@ -3812,7 +3595,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
GET_RELADDR_INC(addr, p);
if (*p == *s && DATA_ENSURE_CHECK1) {
p++;
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
MOP_OUT;
JUMP;
@@ -3824,15 +3607,14 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
CASE(OP_PUSH_IF_PEEK_NEXT) MOP_IN(OP_PUSH_IF_PEEK_NEXT);
GET_RELADDR_INC(addr, p);
- CHECK_MATCH_CACHE;
if (*p == *s) {
p++;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
MOP_OUT;
JUMP;
}
p++;
- INC_NUM_FAILS;
MOP_OUT;
JUMP;
@@ -3846,7 +3628,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
STACK_PUSH_REPEAT(mem, p);
if (reg->repeat_range[mem].lower == 0) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, end - s, msa->match_cache);
STACK_PUSH_ALT(p + addr, s, sprev, pkeep);
}
}
@@ -3863,7 +3645,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
STACK_PUSH_REPEAT(mem, p);
if (reg->repeat_range[mem].lower == 0) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
STACK_PUSH_ALT(p, s, sprev, pkeep);
p += addr;
}
@@ -3882,15 +3664,9 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
/* end of repeat. Nothing to do. */
}
else if (stkp->u.repeat.count >= reg->repeat_range[mem].lower) {
-#ifdef USE_MATCH_CACHE
if (*pbegin == OP_REPEAT_INC) {
-#undef MATCH_CACHE_HIT
-#define MATCH_CACHE_HIT stkp->u.repeat.count--;
- CHECK_MATCH_CACHE;
-#undef MATCH_CACHE_HIT
-#define MATCH_CACHE_HIT ((void) 0)
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
}
-#endif
STACK_PUSH_ALT(p, s, sprev, pkeep);
p = STACK_AT(si)->u.repeat.pcode; /* Don't use stkp after PUSH. */
}
@@ -3922,7 +3698,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
STACK_PUSH_REPEAT_INC(si);
if (*pbegin == OP_REPEAT_INC_NG) {
- CHECK_MATCH_CACHE;
+ DO_CACHE_MATCH_OPT(reg, stk_base, repeat_stk, msa->enable_cache_match_opt, pbegin, msa->num_cache_table, msa->num_cache_opcode, msa->cache_index_table, s - str, msa->match_cache);
}
STACK_PUSH_ALT(pcode, s, sprev, pkeep);
}
@@ -4116,67 +3892,47 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
sprev = stk->u.state.pstr_prev;
pkeep = stk->u.state.pkeep;
-#ifdef USE_MATCH_CACHE
- if (
- msa->match_cache_status != MATCH_CACHE_STATUS_DISABLED &&
- ++msa->num_fails >= (long)(end - str) * msa->num_cache_opcodes
- ) {
- if (msa->match_cache_status == MATCH_CACHE_STATUS_UNINIT) {
- msa->match_cache_status = MATCH_CACHE_STATUS_INIT;
- OnigPosition r = count_num_cache_opcodes(reg, &msa->num_cache_opcodes);
- if (r < 0) goto bytecode_error;
- }
- if (msa->num_cache_opcodes == NUM_CACHE_OPCODES_IMPOSSIBLE || msa->num_cache_opcodes == 0) {
- msa->match_cache_status = MATCH_CACHE_STATUS_DISABLED;
- goto fail_match_cache;
+#ifdef USE_CACHE_MATCH_OPT
+ if (++msa->num_fail >= (long)(end - str) + 1 && msa->num_cache_opcode == NUM_CACHE_OPCODE_UNINIT) {
+ msa->enable_cache_match_opt = 1;
+ if (msa->num_cache_opcode == NUM_CACHE_OPCODE_UNINIT) {
+ OnigPosition r = count_num_cache_opcode(reg, &msa->num_cache_opcode, &msa->num_cache_table);
+ if (r < 0) goto bytecode_error;
}
- if (msa->num_fails < (long)(end - str) * msa->num_cache_opcodes) {
- goto fail_match_cache;
+ if (msa->num_cache_opcode == NUM_CACHE_OPCODE_FAIL || msa->num_cache_opcode == 0) {
+ msa->enable_cache_match_opt = 0;
+ goto fail_match_cache_opt;
}
- if (msa->cache_opcodes == NULL) {
- msa->match_cache_status = MATCH_CACHE_STATUS_ENABLED;
- OnigCacheOpcode* cache_opcodes = (OnigCacheOpcode*)xmalloc(msa->num_cache_opcodes * sizeof(OnigCacheOpcode));
- if (cache_opcodes == NULL) {
+ if (msa->cache_index_table == NULL) {
+ OnigCacheIndex *table = (OnigCacheIndex *)xmalloc(msa->num_cache_table * sizeof(OnigCacheIndex));
+ if (table == NULL) {
return ONIGERR_MEMORY;
}
- OnigPosition r = init_cache_opcodes(reg, cache_opcodes, &msa->num_cache_points);
- if (r < 0) {
- if (r == ONIGERR_UNEXPECTED_BYTECODE) goto unexpected_bytecode_error;
- else goto bytecode_error;
- }
- msa->cache_opcodes = cache_opcodes;
-#ifdef ONIG_DEBUG_MATCH_CACHE
- fprintf(stderr, "MATCH CACHE: #cache opcodes = %ld\n", msa->num_cache_opcodes);
- fprintf(stderr, "MATCH CACHE: #cache points = %ld\n", msa->num_cache_points);
- fprintf(stderr, "MATCH CACHE: cache opcodes (%p):\n", msa->cache_opcodes);
- for (int i = 0; i < msa->num_cache_opcodes; i++) {
- fprintf(stderr, "MATCH CACHE: [%p] cache_point=%ld outer_repeat_mem=%d num_cache_opcodes_at_outer_repeat=%ld num_cache_opcodes_in_outer_repeat=%ld lookaround_nesting=%d match_addr=%p\n", msa->cache_opcodes[i].addr, msa->cache_opcodes[i].cache_point, msa->cache_opcodes[i].outer_repeat_mem, msa->cache_opcodes[i].num_cache_points_at_outer_repeat, msa->cache_opcodes[i].num_cache_points_in_outer_repeat, msa->cache_opcodes[i].lookaround_nesting, msa->cache_opcodes[i].match_addr);
- }
-#endif
+ OnigPosition r = init_cache_index_table(reg, table);
+ if (r < 0) {
+ if (r == ONIGERR_UNEXPECTED_BYTECODE) goto unexpected_bytecode_error;
+ else goto bytecode_error;
+ }
+ msa->cache_index_table = table;
}
- if (msa->match_cache_buf == NULL) {
- size_t length = (end - str) + 1;
- size_t num_match_cache_points = (size_t)msa->num_cache_points * length;
-#ifdef ONIG_DEBUG_MATCH_CACHE
- fprintf(stderr, "MATCH CACHE: #match cache points = %zu (length = %zu)\n", num_match_cache_points, length);
-#endif
- /* Overflow check */
- if (num_match_cache_points / length != (size_t)msa->num_cache_points) {
- return ONIGERR_MEMORY;
- }
- if (num_match_cache_points >= LONG_MAX_LIMIT) {
- return ONIGERR_MEMORY;
- }
- size_t match_cache_buf_length = (num_match_cache_points >> 3) + (num_match_cache_points & 7 ? 1 : 0) + 1;
- uint8_t* match_cache_buf = (uint8_t*)xmalloc(match_cache_buf_length * sizeof(uint8_t));
- if (match_cache_buf == NULL) {
- return ONIGERR_MEMORY;
- }
- xmemset(match_cache_buf, 0, match_cache_buf_length * sizeof(uint8_t));
- msa->match_cache_buf = match_cache_buf;
+ size_t len = (end - str) + 1;
+ size_t match_cache_size8 = (size_t)msa->num_cache_opcode * len;
+ /* overflow check */
+ if (match_cache_size8 / len != (size_t)msa->num_cache_opcode) {
+ return ONIGERR_MEMORY;
+ }
+ /* Currently, int is used for the key of match_cache */
+ if (match_cache_size8 >= LONG_MAX_LIMIT) {
+ return ONIGERR_MEMORY;
}
+ size_t match_cache_size = (match_cache_size8 >> 3) + (match_cache_size8 & 7 ? 1 : 0);
+ msa->match_cache = (uint8_t*)xmalloc(match_cache_size * sizeof(uint8_t));
+ if (msa->match_cache == NULL) {
+ return ONIGERR_MEMORY;
+ }
+ xmemset(msa->match_cache, 0, match_cache_size * sizeof(uint8_t));
}
- fail_match_cache:
+ fail_match_cache_opt:
#endif
#ifdef USE_COMBINATION_EXPLOSION_CHECK
@@ -4196,31 +3952,25 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
finish:
STACK_SAVE;
- xfree(xmalloc_base);
+ if (xmalloc_base) xfree(xmalloc_base);
return best_len;
#ifdef ONIG_DEBUG
stack_error:
STACK_SAVE;
- xfree(xmalloc_base);
+ if (xmalloc_base) xfree(xmalloc_base);
return ONIGERR_STACK_BUG;
#endif
bytecode_error:
STACK_SAVE;
- xfree(xmalloc_base);
+ if (xmalloc_base) xfree(xmalloc_base);
return ONIGERR_UNDEFINED_BYTECODE;
unexpected_bytecode_error:
STACK_SAVE;
- xfree(xmalloc_base);
+ if (xmalloc_base) xfree(xmalloc_base);
return ONIGERR_UNEXPECTED_BYTECODE;
-
- timeout:
- xfree(xmalloc_base);
- if (stk_base != stk_alloc || IS_NOT_NULL(msa->stack_p))
- xfree(stk_base);
- return ONIGERR_TIMEOUT;
}
@@ -5212,64 +4962,44 @@ onig_search_gpos(regex_t* reg, const UChar* str, const UChar* end,
# ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
# define MATCH_AND_RETURN_CHECK(upper_range) \
r = match_at(reg, str, end, (upper_range), s, prev, &msa); \
- switch (r) { \
- case ONIG_MISMATCH: \
- break; \
- case ONIGERR_TIMEOUT: \
- goto timeout; \
- default: \
- if (r >= 0) { \
- if (! IS_FIND_LONGEST(reg->options)) { \
- goto match; \
- }\
+ if (r != ONIG_MISMATCH) {\
+ if (r >= 0) {\
+ if (! IS_FIND_LONGEST(reg->options)) {\
+ goto match;\
}\
- else goto finish; /* error */ \
+ }\
+ else goto finish; /* error */ \
}
# else
# define MATCH_AND_RETURN_CHECK(upper_range) \
r = match_at(reg, str, end, (upper_range), s, prev, &msa); \
- switch (r) { \
- case ONIG_MISMATCH: \
- break; \
- case ONIGERR_TIMEOUT: \
- goto timeout; \
- default: \
- if (r >= 0) { \
- goto match; \
- }\
- else goto finish; /* error */ \
+ if (r != ONIG_MISMATCH) {\
+ if (r >= 0) {\
+ goto match;\
+ }\
+ else goto finish; /* error */ \
}
# endif /* USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE */
#else
# ifdef USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE
# define MATCH_AND_RETURN_CHECK(none) \
r = match_at(reg, str, end, s, prev, &msa);\
- switch (r) { \
- case ONIG_MISMATCH: \
- break; \
- case ONIGERR_TIMEOUT: \
- goto timeout; \
- default: \
- if (r >= 0) { \
- if (! IS_FIND_LONGEST(reg->options)) { \
- goto match; \
- } \
- } \
- else goto finish; /* error */ \
+ if (r != ONIG_MISMATCH) {\
+ if (r >= 0) {\
+ if (! IS_FIND_LONGEST(reg->options)) {\
+ goto match;\
+ }\
+ }\
+ else goto finish; /* error */ \
}
# else
# define MATCH_AND_RETURN_CHECK(none) \
r = match_at(reg, str, end, s, prev, &msa);\
- switch (r) { \
- case ONIG_MISMATCH: \
- break; \
- case ONIGERR_TIMEOUT: \
- goto timeout; \
- default: \
- if (r >= 0) { \
- goto match; \
- } \
- else goto finish; /* error */ \
+ if (r != ONIG_MISMATCH) {\
+ if (r >= 0) {\
+ goto match;\
+ }\
+ else goto finish; /* error */ \
}
# endif /* USE_FIND_LONGEST_SEARCH_ALL_OF_RANGE */
#endif /* USE_MATCH_RANGE_MUST_BE_INSIDE_OF_SPECIFIED_RANGE */
@@ -5572,10 +5302,6 @@ onig_search_gpos(regex_t* reg, const UChar* str, const UChar* end,
match:
MATCH_ARG_FREE(msa);
return s - str;
-
-timeout:
- MATCH_ARG_FREE(msa);
- return ONIGERR_TIMEOUT;
}
extern OnigPosition
diff --git a/regint.h b/regint.h
index 75abfba235..cee766ad6e 100644
--- a/regint.h
+++ b/regint.h
@@ -35,15 +35,19 @@
/* #define ONIG_DEBUG_COMPILE */
/* #define ONIG_DEBUG_SEARCH */
/* #define ONIG_DEBUG_MATCH */
-/* #define ONIG_DEBUG_MATCH_CACHE */
/* #define ONIG_DEBUG_MEMLEAK */
/* #define ONIG_DONT_OPTIMIZE */
/* for byte-code statistical data. */
/* #define ONIG_DEBUG_STATISTICS */
-/* enable the match optimization by using a cache. */
-#define USE_MATCH_CACHE
+/* enable matching optimization by using cache. */
+#define USE_CACHE_MATCH_OPT
+
+#ifdef USE_CACHE_MATCH_OPT
+# define NUM_CACHE_OPCODE_FAIL -1
+# define NUM_CACHE_OPCODE_UNINIT -2
+#endif
#if defined(ONIG_DEBUG_PARSE_TREE) || defined(ONIG_DEBUG_MATCH) || \
defined(ONIG_DEBUG_SEARCH) || defined(ONIG_DEBUG_COMPILE) || \
@@ -154,14 +158,12 @@
#ifdef RUBY
# define CHECK_INTERRUPT_IN_MATCH_AT do { \
- msa->counter++; \
- if (msa->counter >= 128) { \
- msa->counter = 0; \
- if (rb_reg_timeout_p(reg, &msa->end_time)) { \
- goto timeout; \
- } \
- rb_thread_check_ints(); \
- } \
+ msa->counter++; \
+ if (msa->counter >= 128) { \
+ msa->counter = 0; \
+ rb_reg_check_timeout(reg, &msa->end_time); \
+ rb_thread_check_ints(); \
+ } \
} while(0)
# define onig_st_init_table st_init_table
# define onig_st_init_table_with_size st_init_table_with_size
@@ -875,25 +877,15 @@ typedef struct _OnigStackType {
UChar *abs_pstr; /* absent start position */
const UChar *end_pstr; /* end position */
} absent_pos;
-#ifdef USE_MATCH_CACHE
- struct {
- long index; /* index of the match cache buffer */
- uint8_t mask; /* bit-mask for the match cache buffer */
- } match_cache_point;
-#endif
} u;
} OnigStackType;
-#ifdef USE_MATCH_CACHE
+#ifdef USE_CACHE_MATCH_OPT
typedef struct {
UChar *addr;
- long cache_point;
- int outer_repeat_mem;
- long num_cache_points_at_outer_repeat;
- long num_cache_points_in_outer_repeat;
- int lookaround_nesting;
- UChar *match_addr;
-} OnigCacheOpcode;
+ long num;
+ int outer_repeat;
+} OnigCacheIndex;
#endif
typedef struct {
@@ -918,23 +910,16 @@ typedef struct {
#else
uint64_t end_time;
#endif
-#ifdef USE_MATCH_CACHE
- int match_cache_status;
- long num_fails;
- long num_cache_opcodes;
- OnigCacheOpcode* cache_opcodes;
- long num_cache_points;
- uint8_t* match_cache_buf;
+#ifdef USE_CACHE_MATCH_OPT
+ long num_fail;
+ int enable_cache_match_opt;
+ long num_cache_opcode;
+ long num_cache_table;
+ OnigCacheIndex* cache_index_table;
+ uint8_t* match_cache;
#endif
} OnigMatchArg;
-#define NUM_CACHE_OPCODES_UNINIT 1
-#define NUM_CACHE_OPCODES_IMPOSSIBLE -1
-
-#define MATCH_CACHE_STATUS_UNINIT 1
-#define MATCH_CACHE_STATUS_INIT 2
-#define MATCH_CACHE_STATUS_DISABLED -1
-#define MATCH_CACHE_STATUS_ENABLED 0
#define IS_CODE_SB_WORD(enc,code) \
(ONIGENC_IS_CODE_ASCII(code) && ONIGENC_IS_CODE_WORD(enc,code))
@@ -998,7 +983,7 @@ extern int onig_st_insert_strend(hash_table_type* table, const UChar* str_key, c
#ifdef RUBY
extern size_t onig_memsize(const regex_t *reg);
extern size_t onig_region_memsize(const struct re_registers *regs);
-bool rb_reg_timeout_p(regex_t *reg, void *end_time);
+void rb_reg_check_timeout(regex_t *reg, void *end_time);
#endif
RUBY_SYMBOL_EXPORT_END
diff --git a/regparse.c b/regparse.c
index 6f1fbf8191..33df0e06c7 100644
--- a/regparse.c
+++ b/regparse.c
@@ -142,7 +142,7 @@ static void
bbuf_free(BBuf* bbuf)
{
if (IS_NOT_NULL(bbuf)) {
- xfree(bbuf->p);
+ if (IS_NOT_NULL(bbuf->p)) xfree(bbuf->p);
xfree(bbuf);
}
}
@@ -251,7 +251,7 @@ bitset_copy(BitSetRef dest, BitSetRef bs)
#if defined(USE_NAMED_GROUP) && !defined(USE_ST_LIBRARY)
extern int
-onig_strncmp(const UChar* s1, const UChar* s2, size_t n)
+onig_strncmp(const UChar* s1, const UChar* s2, int n)
{
int x;
@@ -275,7 +275,7 @@ onig_strcpy(UChar* dest, const UChar* src, const UChar* end)
#ifdef USE_NAMED_GROUP
static UChar*
-strdup_with_null(OnigEncoding enc, const UChar* s, const UChar* end)
+strdup_with_null(OnigEncoding enc, UChar* s, UChar* end)
{
ptrdiff_t slen;
int term_len, i;
@@ -476,10 +476,8 @@ typedef st_data_t HashDataType; /* 1.6 st.h doesn't define st_data_t type */
# ifdef ONIG_DEBUG
static int
-i_print_name_entry(HashDataType key_, HashDataType e_, HashDataType arg_)
+i_print_name_entry(UChar* key, NameEntry* e, void* arg)
{
- NameEntry* e = (NameEntry *)e_;
- void* arg = (void *)arg_;
int i;
FILE* fp = (FILE* )arg;
@@ -505,7 +503,7 @@ onig_print_names(FILE* fp, regex_t* reg)
if (IS_NOT_NULL(t)) {
fprintf(fp, "name table\n");
- onig_st_foreach(t, i_print_name_entry, (HashDataType )fp);
+ onig_st_foreach(t, (st_foreach_callback_func *)i_print_name_entry, (HashDataType )fp);
fputs("\n", fp);
}
return 0;
@@ -513,12 +511,10 @@ onig_print_names(FILE* fp, regex_t* reg)
# endif /* ONIG_DEBUG */
static int
-i_free_name_entry(HashDataType key_, HashDataType e_, HashDataType arg_ ARG_UNUSED)
+i_free_name_entry(UChar* key, NameEntry* e, void* arg ARG_UNUSED)
{
- UChar* key = (UChar *)key_;
- NameEntry* e = (NameEntry *)e_;
xfree(e->name);
- xfree(e->back_refs);
+ if (IS_NOT_NULL(e->back_refs)) xfree(e->back_refs);
xfree(key);
xfree(e);
return ST_DELETE;
@@ -530,7 +526,7 @@ names_clear(regex_t* reg)
NameTable* t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t)) {
- onig_st_foreach(t, i_free_name_entry, 0);
+ onig_st_foreach(t, (st_foreach_callback_func *)i_free_name_entry, 0);
}
return 0;
}
@@ -550,58 +546,6 @@ onig_names_free(regex_t* reg)
return 0;
}
-static int
-copy_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end,
- int back_num, int *back_refs, OnigRegex regex, void *arg)
-{
- NameTable *copy_table = (NameTable *)arg;
- NameEntry *entry_copy = (NameEntry* )xmalloc(sizeof(NameEntry));
- if (IS_NULL(entry_copy)) return -1;
-
- entry_copy->name_len = name_end - name;
- entry_copy->back_num = back_num;
- entry_copy->back_alloc = back_num;
- entry_copy->back_ref1 = back_refs[0];
- entry_copy->back_refs = xmalloc(back_num * (sizeof(int*)));
- if (IS_NULL(entry_copy->back_refs)) {
- xfree(entry_copy);
- return -1;
- }
- memcpy(entry_copy->back_refs, back_refs, back_num * sizeof(back_refs[0]));
-
- UChar *new_name = strdup_with_null(regex->enc, name, name_end);
- if (IS_NULL(new_name)) {
- xfree(entry_copy->back_refs);
- xfree(entry_copy);
- return -1;
- }
- entry_copy->name = new_name;
-
- if (onig_st_insert_strend(copy_table, new_name, (new_name + entry_copy->name_len), (hash_data_type)entry_copy)) {
- xfree(entry_copy->name);
- xfree(entry_copy->back_refs);
- xfree(entry_copy);
- return -1;
- }
- return 0;
-}
-
-extern int
-onig_names_copy(regex_t* reg, regex_t* oreg)
-{
- NameTable* table = oreg->name_table;
- if (table) {
- NameTable * t = onig_st_init_strend_table_with_size(onig_number_of_names(oreg));
- CHECK_NULL_RETURN_MEMERR(t);
- if (onig_foreach_name(oreg, copy_named_captures_iter, (void*)t)) {
- onig_st_free_table(t);
- return ONIGERR_MEMORY;
- }
- reg->name_table = t;
- }
- return 0;
-}
-
static NameEntry*
name_find(regex_t* reg, const UChar* name, const UChar* name_end)
{
@@ -624,10 +568,8 @@ typedef struct {
} INamesArg;
static int
-i_names(HashDataType key_ ARG_UNUSED, HashDataType e_, HashDataType arg_)
+i_names(UChar* key ARG_UNUSED, NameEntry* e, INamesArg* arg)
{
- NameEntry* e = (NameEntry *)e_;
- INamesArg* arg = (INamesArg *)arg_;
int r = (*(arg->func))(e->name,
e->name + e->name_len,
e->back_num,
@@ -653,16 +595,14 @@ onig_foreach_name(regex_t* reg,
narg.reg = reg;
narg.arg = arg;
narg.enc = reg->enc; /* should be pattern encoding. */
- onig_st_foreach(t, i_names, (HashDataType )&narg);
+ onig_st_foreach(t, (st_foreach_callback_func *)i_names, (HashDataType )&narg);
}
return narg.ret;
}
static int
-i_renumber_name(HashDataType key_ ARG_UNUSED, HashDataType e_, HashDataType map_)
+i_renumber_name(UChar* key ARG_UNUSED, NameEntry* e, GroupNumRemap* map)
{
- NameEntry* e = (NameEntry *)e_;
- GroupNumRemap* map = (GroupNumRemap *)map_;
int i;
if (e->back_num > 1) {
@@ -683,7 +623,7 @@ onig_renumber_name_table(regex_t* reg, GroupNumRemap* map)
NameTable* t = (NameTable* )reg->name_table;
if (IS_NOT_NULL(t)) {
- onig_st_foreach(t, i_renumber_name, (HashDataType )map);
+ onig_st_foreach(t, (st_foreach_callback_func *)i_renumber_name, (HashDataType )map);
}
return 0;
}
@@ -759,13 +699,14 @@ names_clear(regex_t* reg)
e->name_len = 0;
e->back_num = 0;
e->back_alloc = 0;
- xfree(e->back_refs);
+ if (IS_NOT_NULL(e->back_refs)) xfree(e->back_refs);
e->back_refs = (int* )NULL;
}
}
-
- xfree(t->e);
- t->e = NULL;
+ if (IS_NOT_NULL(t->e)) {
+ xfree(t->e);
+ t->e = NULL;
+ }
t->num = 0;
}
return 0;
@@ -781,57 +722,15 @@ onig_names_free(regex_t* reg)
if (r) return r;
t = (NameTable* )reg->name_table;
- xfree(t);
+ if (IS_NOT_NULL(t)) xfree(t);
reg->name_table = NULL;
return 0;
}
-extern int
-onig_names_copy(regex_t* reg, regex_t* oreg)
-{
- NameTable* ot = oreg->name_table;
- if (ot) {
- OnigEncoding enc = oreg->enc;
- int i, num = ot->num;
- NameTable* t = xmalloc(sizeof(*t));
- CHECK_NULL_RETURN_MEMERR(t);
- *t = *ot;
- t->e = xmalloc(t->alloc * sizeof(t->e[0]));
- if (IS_NULL(t->e)) {
- xfree(t);
- return ONIGERR_MEMORY;
- }
- t->num = 0;
- reg->name_table = t;
- for (i = 0; i < num; t->num = ++i) {
- NameEntry* oe = &(ot->e[i]);
- NameEntry* e = &(t->e[i]);
- *e = *oe;
- e->name = NULL;
- e->back_refs = NULL;
- e->name = strdup_with_null(enc, oe->name, oe->name + e->name_len);
- if (IS_NULL(e->name)) {
- onig_names_free(reg);
- return ONIGERR_MEMORY;
- }
- e->back_refs = xmalloc(e->back_alloc * sizeof(e->back_refs[0]));
- if (IS_NULL(e->back_refs)) {
- xfree(e->name);
- onig_names_free(reg);
- return ONIGERR_MEMORY;
- }
- memcpy(e->back_refs, oe->back_refs, e->back_num * sizeof(e->back_refs[0]));
- e->back_ref1 = e->back_refs[0];
- }
- }
- return 0;
-}
-
static NameEntry*
name_find(regex_t* reg, const UChar* name, const UChar* name_end)
{
- int i;
- size_t len;
+ int i, len;
NameEntry* e;
NameTable* t = (NameTable* )reg->name_table;
@@ -867,30 +766,6 @@ onig_foreach_name(regex_t* reg,
}
extern int
-onig_renumber_name_table(regex_t* reg, GroupNumRemap* map)
-{
- int i, j;
- NameEntry* e;
- NameTable* t = (NameTable* )reg->name_table;
-
- if (IS_NOT_NULL(t)) {
- for (i = 0; i < t->num; i++) {
- e = &(t->e[i]);
-
- if (e->back_num > 1) {
- for (j = 0; j < e->back_num; j++) {
- e->back_refs[j] = map[e->back_refs[j]].new_val;
- }
- }
- else if (e->back_num == 1) {
- e->back_ref1 = map[e->back_ref1].new_val;
- }
- }
- }
- return 0;
-}
-
-extern int
onig_number_of_names(const regex_t* reg)
{
NameTable* t = (NameTable* )reg->name_table;
@@ -1092,12 +967,6 @@ onig_number_of_names(const regex_t* reg)
{
return 0;
}
-
-extern int
-onig_names_copy(regex_t* reg, regex_t* oreg)
-{
- return 0;
-}
#endif /* else USE_NAMED_GROUP */
extern int
@@ -1229,24 +1098,29 @@ onig_node_free(Node* node)
{
CClassNode* cc = NCCLASS(node);
- bbuf_free(cc->mbuf);
+ if (cc->mbuf)
+ bbuf_free(cc->mbuf);
}
break;
case NT_QTFR:
- onig_node_free(NQTFR(node)->target);
+ if (NQTFR(node)->target)
+ onig_node_free(NQTFR(node)->target);
break;
case NT_ENCLOSE:
- onig_node_free(NENCLOSE(node)->target);
+ if (NENCLOSE(node)->target)
+ onig_node_free(NENCLOSE(node)->target);
break;
case NT_BREF:
- xfree(NBREF(node)->back_dynamic);
+ if (IS_NOT_NULL(NBREF(node)->back_dynamic))
+ xfree(NBREF(node)->back_dynamic);
break;
case NT_ANCHOR:
- onig_node_free(NANCHOR(node)->target);
+ if (NANCHOR(node)->target)
+ onig_node_free(NANCHOR(node)->target);
break;
}
@@ -6682,10 +6556,7 @@ parse_subexp(Node** top, OnigToken* tok, int term,
headp = &(NCDR(*top));
while (r == TK_ALT) {
r = fetch_token(tok, src, end, env);
- if (r < 0) {
- onig_node_free(node);
- return r;
- }
+ if (r < 0) return r;
r = parse_branch(&node, tok, term, src, end, env);
if (r < 0) {
onig_node_free(node);
diff --git a/regparse.h b/regparse.h
index de980d0ac8..acdd3e2f5c 100644
--- a/regparse.h
+++ b/regparse.h
@@ -339,7 +339,7 @@ typedef struct {
extern int onig_renumber_name_table(regex_t* reg, GroupNumRemap* map);
#endif
-extern int onig_strncmp(const UChar* s1, const UChar* s2, size_t n);
+extern int onig_strncmp(const UChar* s1, const UChar* s2, int n);
extern void onig_strcpy(UChar* dest, const UChar* src, const UChar* end);
extern void onig_scan_env_set_error_string(ScanEnv* env, int ecode, UChar* arg, UChar* arg_end);
extern int onig_scan_unsigned_number(UChar** src, const UChar* end, OnigEncoding enc);
@@ -356,7 +356,6 @@ extern Node* onig_node_list_add(Node* list, Node* x);
extern Node* onig_node_new_alt(Node* left, Node* right);
extern void onig_node_str_clear(Node* node);
extern int onig_names_free(regex_t* reg);
-extern int onig_names_copy(regex_t* reg, regex_t* oreg);
extern int onig_parse_make_tree(Node** root, const UChar* pattern, const UChar* end, regex_t* reg, ScanEnv* env);
extern int onig_free_shared_cclass_table(void);
diff --git a/rjit.c b/rjit.c
deleted file mode 100644
index 72660394b3..0000000000
--- a/rjit.c
+++ /dev/null
@@ -1,501 +0,0 @@
-/**********************************************************************
-
- rjit.c - Ruby JIT compiler functions
-
- Copyright (C) 2023 Takashi Kokubun <k0kubun@ruby-lang.org>.
-
-**********************************************************************/
-
-#include "rjit.h" // defines USE_RJIT
-
-#if USE_RJIT
-
-#include "constant.h"
-#include "id_table.h"
-#include "internal.h"
-#include "internal/class.h"
-#include "internal/cmdlineopt.h"
-#include "internal/cont.h"
-#include "internal/file.h"
-#include "internal/hash.h"
-#include "internal/process.h"
-#include "internal/warnings.h"
-#include "vm_sync.h"
-#include "ractor_core.h"
-
-#ifdef __sun
-#define __EXTENSIONS__ 1
-#endif
-
-#include "vm_core.h"
-#include "vm_callinfo.h"
-#include "rjit_c.h"
-#include "ruby_assert.h"
-#include "ruby/debug.h"
-#include "ruby/thread.h"
-#include "ruby/version.h"
-#include "builtin.h"
-#include "insns.inc"
-#include "insns_info.inc"
-#include "internal/compile.h"
-#include "internal/gc.h"
-
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <dlfcn.h>
-#include <errno.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_SYS_PARAM_H
-# include <sys/param.h>
-#endif
-#include "dln.h"
-
-// For mmapp(), sysconf()
-#ifndef _WIN32
-#include <unistd.h>
-#include <sys/mman.h>
-#endif
-
-#include "ruby/util.h"
-
-// A copy of RJIT portion of MRI options since RJIT initialization. We
-// need them as RJIT threads still can work when the most MRI data were
-// freed.
-struct rb_rjit_options rb_rjit_opts;
-
-// true if RJIT is enabled.
-bool rb_rjit_enabled = false;
-// true if --rjit-stats (used before rb_rjit_opts is set)
-bool rb_rjit_stats_enabled = false;
-// true if --rjit-trace-exits (used before rb_rjit_opts is set)
-bool rb_rjit_trace_exits_enabled = false;
-// true if JIT-ed code should be called. When `ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS`
-// and `rb_rjit_call_p == false`, any JIT-ed code execution is cancelled as soon as possible.
-bool rb_rjit_call_p = false;
-// A flag to communicate that rb_rjit_call_p should be disabled while it's temporarily false.
-static bool rjit_cancel_p = false;
-
-// `rb_ec_ractor_hooks(ec)->events` is moved to this variable during compilation.
-rb_event_flag_t rb_rjit_global_events = 0;
-
-// Basically rb_rjit_opts.stats, but this becomes false during RJIT compilation.
-static bool rjit_stats_p = false;
-
-// RubyVM::RJIT
-static VALUE rb_mRJIT = 0;
-// RubyVM::RJIT::C
-static VALUE rb_mRJITC = 0;
-// RubyVM::RJIT::Compiler
-static VALUE rb_RJITCompiler = 0;
-// RubyVM::RJIT::CPointer::Struct_rb_iseq_t
-static VALUE rb_cRJITIseqPtr = 0;
-// RubyVM::RJIT::CPointer::Struct_rb_control_frame_t
-static VALUE rb_cRJITCfpPtr = 0;
-// RubyVM::RJIT::Hooks
-static VALUE rb_mRJITHooks = 0;
-
-// Frames for --rjit-trace-exits
-VALUE rb_rjit_raw_samples = 0;
-// Line numbers for --rjit-trace-exits
-VALUE rb_rjit_line_samples = 0;
-
-// Postponed job handle for triggering rjit_iseq_update_references
-static rb_postponed_job_handle_t rjit_iseq_update_references_pjob;
-
-// A default threshold used to add iseq to JIT.
-#define DEFAULT_CALL_THRESHOLD 10
-// Size of executable memory block in MiB.
-#define DEFAULT_EXEC_MEM_SIZE 64
-
-#define opt_match_noarg(s, l, name) \
- opt_match(s, l, name) && (*(s) ? (rb_warn("argument to --rjit-" name " is ignored"), 1) : 1)
-#define opt_match_arg(s, l, name) \
- opt_match(s, l, name) && (*(s) ? 1 : (rb_raise(rb_eRuntimeError, "--rjit-" name " needs an argument"), 0))
-
-void
-rb_rjit_setup_options(const char *s, struct rb_rjit_options *rjit_opt)
-{
- const size_t l = strlen(s);
- if (l == 0) {
- return;
- }
- else if (opt_match_arg(s, l, "exec-mem-size")) {
- rjit_opt->exec_mem_size = atoi(s + 1);
- }
- else if (opt_match_arg(s, l, "call-threshold")) {
- rjit_opt->call_threshold = atoi(s + 1);
- }
- else if (opt_match_noarg(s, l, "stats")) {
- rjit_opt->stats = true;
- }
- else if (opt_match_noarg(s, l, "disable")) {
- rjit_opt->disable = true;
- }
- else if (opt_match_noarg(s, l, "trace")) {
- rjit_opt->trace = true;
- }
- else if (opt_match_noarg(s, l, "trace-exits")) {
- rjit_opt->trace_exits = true;
- }
- else if (opt_match_noarg(s, l, "dump-disasm")) {
- rjit_opt->dump_disasm = true;
- }
- else if (opt_match_noarg(s, l, "verify-ctx")) {
- rjit_opt->verify_ctx = true;
- }
- else {
- rb_raise(rb_eRuntimeError,
- "invalid RJIT option '%s' (--help will show valid RJIT options)", s);
- }
-}
-
-#define M(shortopt, longopt, desc) RUBY_OPT_MESSAGE(shortopt, longopt, desc)
-const struct ruby_opt_message rb_rjit_option_messages[] = {
- M("--rjit-exec-mem-size=num", "", "Size of executable memory block in MiB (default: " STRINGIZE(DEFAULT_EXEC_MEM_SIZE) ")."),
- M("--rjit-call-threshold=num", "", "Number of calls to trigger JIT (default: " STRINGIZE(DEFAULT_CALL_THRESHOLD) ")."),
- M("--rjit-stats", "", "Enable collecting RJIT statistics."),
- M("--rjit-disable", "", "Disable RJIT for lazily enabling it with RubyVM::RJIT.enable."),
- M("--rjit-trace", "", "Allow TracePoint during JIT compilation."),
- M("--rjit-trace-exits", "", "Trace side exit locations."),
-#ifdef HAVE_LIBCAPSTONE
- M("--rjit-dump-disasm", "", "Dump all JIT code"),
-#endif
- {0}
-};
-#undef M
-
-struct rb_rjit_runtime_counters rb_rjit_counters = { 0 };
-
-extern VALUE rb_gc_enable(void);
-extern VALUE rb_gc_disable(void);
-extern uint64_t rb_vm_insns_count;
-
-// Disable GC, TracePoint, JIT, stats, and $!
-#define WITH_RJIT_ISOLATED_USING_PC(using_pc, stmt) do { \
- VALUE was_disabled = rb_gc_disable(); \
- \
- rb_hook_list_t *global_hooks = rb_ec_ractor_hooks(GET_EC()); \
- rb_rjit_global_events = global_hooks->events; \
- \
- const VALUE *pc = NULL; \
- if (rb_rjit_opts.trace) { \
- pc = GET_EC()->cfp->pc; \
- if (!using_pc) GET_EC()->cfp->pc = 0; /* avoid crashing on calc_lineno */ \
- } \
- else global_hooks->events = 0; \
- \
- bool original_call_p = rb_rjit_call_p; \
- rb_rjit_call_p = false; \
- \
- rjit_stats_p = false; \
- uint64_t insns_count = rb_vm_insns_count; \
- \
- VALUE err = rb_errinfo(); \
- \
- stmt; \
- \
- rb_set_errinfo(err); \
- \
- rb_vm_insns_count = insns_count; \
- rjit_stats_p = rb_rjit_opts.stats; \
- \
- rb_rjit_call_p = (rjit_cancel_p ? false : original_call_p); \
- \
- if (rb_rjit_opts.trace) GET_EC()->cfp->pc = pc; \
- else global_hooks->events = rb_rjit_global_events; \
- \
- if (!was_disabled) rb_gc_enable(); \
-} while (0);
-#define WITH_RJIT_ISOLATED(stmt) WITH_RJIT_ISOLATED_USING_PC(false, stmt)
-
-void
-rb_rjit_cancel_all(const char *reason)
-{
- if (!rb_rjit_enabled)
- return;
-
- rb_rjit_call_p = false;
- rjit_cancel_p = true;
-}
-
-void
-rb_rjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop)
-{
- if (!rb_rjit_call_p) return;
- rb_rjit_call_p = false;
-}
-
-static void
-rjit_cme_invalidate(void *data)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
- WITH_RJIT_ISOLATED({
- rb_funcall(rb_mRJITHooks, rb_intern("on_cme_invalidate"), 1, SIZET2NUM((size_t)data));
- });
-}
-
-extern int rb_workqueue_register(unsigned flags, rb_postponed_job_func_t func, void *data);
-
-void
-rb_rjit_cme_invalidate(rb_callable_method_entry_t *cme)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
- // Asynchronously hook the Ruby code since running Ruby in the middle of cme invalidation is dangerous.
- rb_workqueue_register(0, rjit_cme_invalidate, (void *)cme);
-}
-
-void
-rb_rjit_before_ractor_spawn(void)
-{
- if (!rb_rjit_call_p) return;
- rb_rjit_call_p = false;
-}
-
-static void
-rjit_constant_state_changed(void *data)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
- RB_VM_LOCK_ENTER();
- rb_vm_barrier();
-
- WITH_RJIT_ISOLATED({
- rb_funcall(rb_mRJITHooks, rb_intern("on_constant_state_changed"), 1, SIZET2NUM((size_t)data));
- });
-
- RB_VM_LOCK_LEAVE();
-}
-
-void
-rb_rjit_constant_state_changed(ID id)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
- // Asynchronously hook the Ruby code since this is hooked during a "Ruby critical section".
- rb_workqueue_register(0, rjit_constant_state_changed, (void *)id);
-}
-
-void
-rb_rjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
-
- RB_VM_LOCK_ENTER();
- rb_vm_barrier();
-
- WITH_RJIT_ISOLATED({
- rb_funcall(rb_mRJITHooks, rb_intern("on_constant_ic_update"), 3,
- SIZET2NUM((size_t)iseq), SIZET2NUM((size_t)ic), UINT2NUM(insn_idx));
- });
-
- RB_VM_LOCK_LEAVE();
-}
-
-void
-rb_rjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
- WITH_RJIT_ISOLATED({
- rb_funcall(rb_mRJITHooks, rb_intern("on_tracing_invalidate_all"), 1, UINT2NUM(new_iseq_events));
- });
-}
-
-static void
-rjit_iseq_update_references(void *data)
-{
- if (!rb_rjit_enabled || !rb_rjit_call_p || !rb_mRJITHooks) return;
- WITH_RJIT_ISOLATED({
- rb_funcall(rb_mRJITHooks, rb_intern("on_update_references"), 0);
- });
-}
-
-void
-rb_rjit_iseq_update_references(struct rb_iseq_constant_body *const body)
-{
- if (!rb_rjit_enabled) return;
-
- if (body->rjit_blocks) {
- body->rjit_blocks = rb_gc_location(body->rjit_blocks);
- }
-
- // Asynchronously hook the Ruby code to avoid allocation during GC.compact.
- // Using _one because it's too slow to invalidate all for each ISEQ. Thus
- // not giving an ISEQ pointer.
- rb_postponed_job_trigger(rjit_iseq_update_references_pjob);
-}
-
-void
-rb_rjit_iseq_mark(VALUE rjit_blocks)
-{
- if (!rb_rjit_enabled) return;
-
- // Note: This wasn't enough for some reason.
- // We actually rely on RubyVM::RJIT::GC_REFS to mark this.
- if (rjit_blocks) {
- rb_gc_mark_movable(rjit_blocks);
- }
-}
-
-// Called by rb_vm_mark()
-void
-rb_rjit_mark(void)
-{
- if (!rb_rjit_enabled)
- return;
- RUBY_MARK_ENTER("rjit");
-
- // Pin object pointers used in this file
- rb_gc_mark(rb_RJITCompiler);
- rb_gc_mark(rb_cRJITIseqPtr);
- rb_gc_mark(rb_cRJITCfpPtr);
- rb_gc_mark(rb_mRJITHooks);
- rb_gc_mark(rb_rjit_raw_samples);
- rb_gc_mark(rb_rjit_line_samples);
-
- RUBY_MARK_LEAVE("rjit");
-}
-
-void
-rb_rjit_free_iseq(const rb_iseq_t *iseq)
-{
- // TODO: implement this. GC_REFS should remove this iseq's mjit_blocks
-}
-
-// TODO: Use this in more places
-VALUE
-rb_rjit_iseq_new(rb_iseq_t *iseq)
-{
- return rb_funcall(rb_cRJITIseqPtr, rb_intern("new"), 1, SIZET2NUM((size_t)iseq));
-}
-
-void
-rb_rjit_compile(const rb_iseq_t *iseq)
-{
- RB_VM_LOCK_ENTER();
- rb_vm_barrier();
-
- WITH_RJIT_ISOLATED_USING_PC(true, {
- VALUE iseq_ptr = rb_funcall(rb_cRJITIseqPtr, rb_intern("new"), 1, SIZET2NUM((size_t)iseq));
- VALUE cfp_ptr = rb_funcall(rb_cRJITCfpPtr, rb_intern("new"), 1, SIZET2NUM((size_t)GET_EC()->cfp));
- rb_funcall(rb_RJITCompiler, rb_intern("compile"), 2, iseq_ptr, cfp_ptr);
- });
-
- RB_VM_LOCK_LEAVE();
-}
-
-void *
-rb_rjit_entry_stub_hit(VALUE branch_stub)
-{
- VALUE result;
-
- RB_VM_LOCK_ENTER();
- rb_vm_barrier();
-
- rb_control_frame_t *cfp = GET_EC()->cfp;
-
- WITH_RJIT_ISOLATED_USING_PC(true, {
- VALUE cfp_ptr = rb_funcall(rb_cRJITCfpPtr, rb_intern("new"), 1, SIZET2NUM((size_t)cfp));
- result = rb_funcall(rb_RJITCompiler, rb_intern("entry_stub_hit"), 2, branch_stub, cfp_ptr);
- });
-
- RB_VM_LOCK_LEAVE();
-
- return (void *)NUM2SIZET(result);
-}
-
-void *
-rb_rjit_branch_stub_hit(VALUE branch_stub, int sp_offset, int target0_p)
-{
- VALUE result;
-
- RB_VM_LOCK_ENTER();
- rb_vm_barrier();
-
- rb_control_frame_t *cfp = GET_EC()->cfp;
- cfp->sp += sp_offset; // preserve stack values, also using the actual sp_offset to make jit.peek_at_stack work
-
- WITH_RJIT_ISOLATED({
- VALUE cfp_ptr = rb_funcall(rb_cRJITCfpPtr, rb_intern("new"), 1, SIZET2NUM((size_t)cfp));
- result = rb_funcall(rb_RJITCompiler, rb_intern("branch_stub_hit"), 3, branch_stub, cfp_ptr, RBOOL(target0_p));
- });
-
- cfp->sp -= sp_offset; // reset for consistency with the code without the stub
-
- RB_VM_LOCK_LEAVE();
-
- return (void *)NUM2SIZET(result);
-}
-
-void
-rb_rjit_init(const struct rb_rjit_options *opts)
-{
- VM_ASSERT(rb_rjit_enabled);
-
- // Normalize options
- rb_rjit_opts = *opts;
- if (rb_rjit_opts.exec_mem_size == 0)
- rb_rjit_opts.exec_mem_size = DEFAULT_EXEC_MEM_SIZE;
- if (rb_rjit_opts.call_threshold == 0)
- rb_rjit_opts.call_threshold = DEFAULT_CALL_THRESHOLD;
-#ifndef HAVE_LIBCAPSTONE
- if (rb_rjit_opts.dump_disasm)
- rb_warn("libcapstone has not been linked. Ignoring --rjit-dump-disasm.");
-#endif
-
- // RJIT doesn't support miniruby, but it might reach here by RJIT_FORCE_ENABLE.
- rb_mRJIT = rb_const_get(rb_cRubyVM, rb_intern("RJIT"));
- if (!rb_const_defined(rb_mRJIT, rb_intern("Compiler"))) {
- rb_warn("Disabling RJIT because RubyVM::RJIT::Compiler is not defined");
- rb_rjit_enabled = false;
- return;
- }
- rjit_iseq_update_references_pjob = rb_postponed_job_preregister(0, rjit_iseq_update_references, NULL);
- if (rjit_iseq_update_references_pjob == POSTPONED_JOB_HANDLE_INVALID) {
- rb_bug("Could not preregister postponed job for RJIT");
- }
- rb_mRJITC = rb_const_get(rb_mRJIT, rb_intern("C"));
- VALUE rb_cRJITCompiler = rb_const_get(rb_mRJIT, rb_intern("Compiler"));
- rb_RJITCompiler = rb_funcall(rb_cRJITCompiler, rb_intern("new"), 0);
- rb_cRJITIseqPtr = rb_funcall(rb_mRJITC, rb_intern("rb_iseq_t"), 0);
- rb_cRJITCfpPtr = rb_funcall(rb_mRJITC, rb_intern("rb_control_frame_t"), 0);
- rb_mRJITHooks = rb_const_get(rb_mRJIT, rb_intern("Hooks"));
- if (rb_rjit_opts.trace_exits) {
- rb_rjit_raw_samples = rb_ary_new();
- rb_rjit_line_samples = rb_ary_new();
- }
-
- // Enable RJIT and stats from here
- rb_rjit_call_p = !rb_rjit_opts.disable;
- rjit_stats_p = rb_rjit_opts.stats;
-}
-
-//
-// Primitive for rjit.rb
-//
-
-// Same as `rb_rjit_opts.stats`, but this is used before rb_rjit_opts is set.
-static VALUE
-rjit_stats_enabled_p(rb_execution_context_t *ec, VALUE self)
-{
- return RBOOL(rb_rjit_stats_enabled);
-}
-
-// Same as `rb_rjit_opts.trace_exits`, but this is used before rb_rjit_opts is set.
-static VALUE
-rjit_trace_exits_enabled_p(rb_execution_context_t *ec, VALUE self)
-{
- return RBOOL(rb_rjit_trace_exits_enabled);
-}
-
-// Disable anything that could impact stats. It ends up disabling JIT calls as well.
-static VALUE
-rjit_stop_stats(rb_execution_context_t *ec, VALUE self)
-{
- rb_rjit_call_p = false;
- rjit_stats_p = false;
- return Qnil;
-}
-
-#include "rjit.rbinc"
-
-#endif // USE_RJIT
diff --git a/rjit.h b/rjit.h
deleted file mode 100644
index 26d1d67fb1..0000000000
--- a/rjit.h
+++ /dev/null
@@ -1,101 +0,0 @@
-#ifndef RUBY_RJIT_H
-#define RUBY_RJIT_H 1
-/**********************************************************************
-
- rjit.h - Interface to RJIT
-
- Copyright (C) 2023 Takashi Kokubun <k0kubun@ruby-lang.org>.
-
-**********************************************************************/
-
-#include "ruby/internal/config.h" // defines USE_RJIT
-#include "ruby/internal/stdbool.h"
-#include "vm_core.h"
-
-# if USE_RJIT
-
-#include "ruby.h"
-#include "vm_core.h"
-
-// RJIT options which can be defined on the MRI command line.
-struct rb_rjit_options {
- // Converted from "rjit" feature flag to tell the enablement
- // information to ruby_show_version().
- bool on;
- // Size of executable memory block in MiB
- unsigned int exec_mem_size;
- // Number of calls to trigger JIT compilation
- unsigned int call_threshold;
- // Collect RJIT statistics
- bool stats;
- // Do not start RJIT until RJIT.enable is called
- bool disable;
- // Allow TracePoint during JIT compilation
- bool trace;
- // Trace side exit locations
- bool trace_exits;
- // Enable disasm of all JIT code
- bool dump_disasm;
- // Verify context objects
- bool verify_ctx;
-};
-
-RUBY_SYMBOL_EXPORT_BEGIN
-RUBY_EXTERN struct rb_rjit_options rb_rjit_opts;
-RUBY_EXTERN bool rb_rjit_call_p;
-
-#define rb_rjit_call_threshold() rb_rjit_opts.call_threshold
-
-extern void rb_rjit_compile(const rb_iseq_t *iseq);
-RUBY_SYMBOL_EXPORT_END
-
-extern void rb_rjit_cancel_all(const char *reason);
-extern void rb_rjit_init(const struct rb_rjit_options *opts);
-extern void rb_rjit_free_iseq(const rb_iseq_t *iseq);
-extern void rb_rjit_iseq_update_references(struct rb_iseq_constant_body *const body);
-extern void rb_rjit_mark(void);
-extern void rb_rjit_iseq_mark(VALUE rjit_blocks);
-extern void rjit_notify_waitpid(int exit_code);
-
-extern void rb_rjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);
-extern void rb_rjit_cme_invalidate(rb_callable_method_entry_t *cme);
-extern void rb_rjit_before_ractor_spawn(void);
-extern void rb_rjit_constant_state_changed(ID id);
-extern void rb_rjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx);
-extern void rb_rjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events);
-
-extern void rb_rjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);
-extern void rb_rjit_before_ractor_spawn(void);
-extern void rb_rjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events);
-extern void rb_rjit_collect_vm_usage_insn(int insn);
-
-extern bool rb_rjit_enabled;
-extern bool rb_rjit_stats_enabled;
-extern bool rb_rjit_trace_exits_enabled;
-
-# else // USE_RJIT
-
-static inline void rb_rjit_compile(const rb_iseq_t *iseq){}
-
-static inline void rb_rjit_cancel_all(const char *reason){}
-static inline void rb_rjit_free_iseq(const rb_iseq_t *iseq){}
-static inline void rb_rjit_mark(void){}
-
-static inline void rb_rjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop) {}
-static inline void rb_rjit_cme_invalidate(rb_callable_method_entry_t *cme) {}
-static inline void rb_rjit_before_ractor_spawn(void) {}
-static inline void rb_rjit_constant_state_changed(ID id) {}
-static inline void rb_rjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx) {}
-static inline void rb_rjit_tracing_invalidate_all(rb_event_flag_t new_iseq_events) {}
-
-#define rb_rjit_enabled false
-#define rb_rjit_call_p false
-#define rb_rjit_stats_enabled false
-#define rb_rjit_trace_exits_enabled false
-
-#define rb_rjit_call_threshold() UINT_MAX
-
-static inline void rb_rjit_collect_vm_usage_insn(int insn) {}
-
-# endif // USE_RJIT
-#endif // RUBY_RJIT_H
diff --git a/rjit.rb b/rjit.rb
deleted file mode 100644
index 12fc10c91e..0000000000
--- a/rjit.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-module RubyVM::RJIT
- # Return true if \RJIT is enabled.
- def self.enabled?
- Primitive.cexpr! 'RBOOL(rb_rjit_enabled)'
- end
-
- # Start JIT compilation after \--rjit-disable.
- def self.enable
- Primitive.cstmt! %{
- rb_rjit_call_p = true;
- return Qnil;
- }
- end
-
- if Primitive.rjit_stats_enabled_p
- at_exit do
- Primitive.rjit_stop_stats
- print_stats
- end
- end
- if Primitive.rjit_trace_exits_enabled_p
- at_exit do
- Primitive.rjit_stop_stats
- dump_trace_exits
- end
- end
-end
-
-if RubyVM::RJIT.enabled?
- begin
- require 'fiddle'
- require 'fiddle/import'
- rescue LoadError
- return # miniruby doesn't support RJIT
- end
-
- require 'ruby_vm/rjit/c_type'
- require 'ruby_vm/rjit/compiler'
- require 'ruby_vm/rjit/hooks'
- require 'ruby_vm/rjit/stats'
-end
diff --git a/rjit_c.c b/rjit_c.c
deleted file mode 100644
index e9863129a1..0000000000
--- a/rjit_c.c
+++ /dev/null
@@ -1,543 +0,0 @@
-/**********************************************************************
-
- rjit_c.c - C helpers for RJIT
-
- Copyright (C) 2017 Takashi Kokubun <k0kubun@ruby-lang.org>.
-
-**********************************************************************/
-
-#include "rjit.h" // defines USE_RJIT
-
-#if USE_RJIT
-
-#include "rjit_c.h"
-#include "include/ruby/assert.h"
-#include "include/ruby/debug.h"
-#include "internal.h"
-#include "internal/compile.h"
-#include "internal/fixnum.h"
-#include "internal/hash.h"
-#include "internal/sanitizers.h"
-#include "internal/gc.h"
-#include "internal/proc.h"
-#include "yjit.h"
-#include "vm_insnhelper.h"
-#include "probes.h"
-#include "probes_helper.h"
-
-#include "insns.inc"
-#include "insns_info.inc"
-
-// For mmapp(), sysconf()
-#ifndef _WIN32
-#include <unistd.h>
-#include <sys/mman.h>
-#endif
-
-#include <errno.h>
-
-#if defined(MAP_FIXED_NOREPLACE) && defined(_SC_PAGESIZE)
-// Align the current write position to a multiple of bytes
-static uint8_t *
-align_ptr(uint8_t *ptr, uint32_t multiple)
-{
- // Compute the pointer modulo the given alignment boundary
- uint32_t rem = ((uint32_t)(uintptr_t)ptr) % multiple;
-
- // If the pointer is already aligned, stop
- if (rem == 0)
- return ptr;
-
- // Pad the pointer by the necessary amount to align it
- uint32_t pad = multiple - rem;
-
- return ptr + pad;
-}
-#endif
-
-// Address space reservation. Memory pages are mapped on an as needed basis.
-// See the Rust mm module for details.
-static uint8_t *
-rjit_reserve_addr_space(uint32_t mem_size)
-{
-#ifndef _WIN32
- uint8_t *mem_block;
-
- // On Linux
- #if defined(MAP_FIXED_NOREPLACE) && defined(_SC_PAGESIZE)
- uint32_t const page_size = (uint32_t)sysconf(_SC_PAGESIZE);
- uint8_t *const cfunc_sample_addr = (void *)&rjit_reserve_addr_space;
- uint8_t *const probe_region_end = cfunc_sample_addr + INT32_MAX;
- // Align the requested address to page size
- uint8_t *req_addr = align_ptr(cfunc_sample_addr, page_size);
-
- // Probe for addresses close to this function using MAP_FIXED_NOREPLACE
- // to improve odds of being in range for 32-bit relative call instructions.
- do {
- mem_block = mmap(
- req_addr,
- mem_size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE,
- -1,
- 0
- );
-
- // If we succeeded, stop
- if (mem_block != MAP_FAILED) {
- break;
- }
-
- // +4MB
- req_addr += 4 * 1024 * 1024;
- } while (req_addr < probe_region_end);
-
- // On MacOS and other platforms
- #else
- // Try to map a chunk of memory as executable
- mem_block = mmap(
- (void *)rjit_reserve_addr_space,
- mem_size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1,
- 0
- );
- #endif
-
- // Fallback
- if (mem_block == MAP_FAILED) {
- // Try again without the address hint (e.g., valgrind)
- mem_block = mmap(
- NULL,
- mem_size,
- PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1,
- 0
- );
- }
-
- // Check that the memory mapping was successful
- if (mem_block == MAP_FAILED) {
- perror("ruby: yjit: mmap:");
- if(errno == ENOMEM) {
- // No crash report if it's only insufficient memory
- exit(EXIT_FAILURE);
- }
- rb_bug("mmap failed");
- }
-
- return mem_block;
-#else
- // Windows not supported for now
- return NULL;
-#endif
-}
-
-static VALUE
-mprotect_write(rb_execution_context_t *ec, VALUE self, VALUE rb_mem_block, VALUE rb_mem_size)
-{
- void *mem_block = (void *)NUM2SIZET(rb_mem_block);
- uint32_t mem_size = NUM2UINT(rb_mem_size);
- return RBOOL(mprotect(mem_block, mem_size, PROT_READ | PROT_WRITE) == 0);
-}
-
-static VALUE
-mprotect_exec(rb_execution_context_t *ec, VALUE self, VALUE rb_mem_block, VALUE rb_mem_size)
-{
- void *mem_block = (void *)NUM2SIZET(rb_mem_block);
- uint32_t mem_size = NUM2UINT(rb_mem_size);
- if (mem_size == 0) return Qfalse; // Some platforms return an error for mem_size 0.
-
- if (mprotect(mem_block, mem_size, PROT_READ | PROT_EXEC)) {
- rb_bug("Couldn't make JIT page (%p, %lu bytes) executable, errno: %s",
- mem_block, (unsigned long)mem_size, strerror(errno));
- }
- return Qtrue;
-}
-
-static VALUE
-rjit_optimized_call(VALUE *recv, rb_execution_context_t *ec, int argc, VALUE *argv, int kw_splat, VALUE block_handler)
-{
- rb_proc_t *proc;
- GetProcPtr(recv, proc);
- return rb_vm_invoke_proc(ec, proc, argc, argv, kw_splat, block_handler);
-}
-
-static VALUE
-rjit_str_neq_internal(VALUE str1, VALUE str2)
-{
- return rb_str_eql_internal(str1, str2) == Qtrue ? Qfalse : Qtrue;
-}
-
-static VALUE
-rjit_str_simple_append(VALUE str1, VALUE str2)
-{
- return rb_str_cat(str1, RSTRING_PTR(str2), RSTRING_LEN(str2));
-}
-
-static VALUE
-rjit_rb_ary_subseq_length(VALUE ary, long beg)
-{
- long len = RARRAY_LEN(ary);
- return rb_ary_subseq(ary, beg, len);
-}
-
-static VALUE
-rjit_build_kwhash(const struct rb_callinfo *ci, VALUE *sp)
-{
- const struct rb_callinfo_kwarg *kw_arg = vm_ci_kwarg(ci);
- int kw_len = kw_arg->keyword_len;
- VALUE hash = rb_hash_new_with_size(kw_len);
-
- for (int i = 0; i < kw_len; i++) {
- VALUE key = kw_arg->keywords[i];
- VALUE val = *(sp - kw_len + i);
- rb_hash_aset(hash, key, val);
- }
- return hash;
-}
-
-// The code we generate in gen_send_cfunc() doesn't fire the c_return TracePoint event
-// like the interpreter. When tracing for c_return is enabled, we patch the code after
-// the C method return to call into this to fire the event.
-static void
-rjit_full_cfunc_return(rb_execution_context_t *ec, VALUE return_value)
-{
- rb_control_frame_t *cfp = ec->cfp;
- RUBY_ASSERT_ALWAYS(cfp == GET_EC()->cfp);
- const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
-
- RUBY_ASSERT_ALWAYS(RUBYVM_CFUNC_FRAME_P(cfp));
- RUBY_ASSERT_ALWAYS(me->def->type == VM_METHOD_TYPE_CFUNC);
-
- // CHECK_CFP_CONSISTENCY("full_cfunc_return"); TODO revive this
-
- // Pop the C func's frame and fire the c_return TracePoint event
- // Note that this is the same order as vm_call_cfunc_with_frame().
- rb_vm_pop_frame(ec);
- EXEC_EVENT_HOOK(ec, RUBY_EVENT_C_RETURN, cfp->self, me->def->original_id, me->called_id, me->owner, return_value);
- // Note, this deviates from the interpreter in that users need to enable
- // a c_return TracePoint for this DTrace hook to work. A reasonable change
- // since the Ruby return event works this way as well.
- RUBY_DTRACE_CMETHOD_RETURN_HOOK(ec, me->owner, me->def->original_id);
-
- // Push return value into the caller's stack. We know that it's a frame that
- // uses cfp->sp because we are patching a call done with gen_send_cfunc().
- ec->cfp->sp[0] = return_value;
- ec->cfp->sp++;
-}
-
-static rb_proc_t *
-rjit_get_proc_ptr(VALUE procv)
-{
- rb_proc_t *proc;
- GetProcPtr(procv, proc);
- return proc;
-}
-
-// Use the same buffer size as Stackprof.
-#define BUFF_LEN 2048
-
-extern VALUE rb_rjit_raw_samples;
-extern VALUE rb_rjit_line_samples;
-
-static void
-rjit_record_exit_stack(const VALUE *exit_pc)
-{
- // Let Primitive.rjit_stop_stats stop this
- if (!rb_rjit_call_p) return;
-
- // Get the opcode from the encoded insn handler at this PC
- int insn = rb_vm_insn_addr2opcode((void *)*exit_pc);
-
- // Create 2 array buffers to be used to collect frames and lines.
- VALUE frames_buffer[BUFF_LEN] = { 0 };
- int lines_buffer[BUFF_LEN] = { 0 };
-
- // Records call frame and line information for each method entry into two
- // temporary buffers. Returns the number of times we added to the buffer (ie
- // the length of the stack).
- //
- // Call frame info is stored in the frames_buffer, line number information
- // in the lines_buffer. The first argument is the start point and the second
- // argument is the buffer limit, set at 2048.
- int stack_length = rb_profile_frames(0, BUFF_LEN, frames_buffer, lines_buffer);
- int samples_length = stack_length + 3; // 3: length, insn, count
-
- // If yjit_raw_samples is less than or equal to the current length of the samples
- // we might have seen this stack trace previously.
- int prev_stack_len_index = (int)RARRAY_LEN(rb_rjit_raw_samples) - samples_length;
- VALUE prev_stack_len_obj;
- if (RARRAY_LEN(rb_rjit_raw_samples) >= samples_length && FIXNUM_P(prev_stack_len_obj = RARRAY_AREF(rb_rjit_raw_samples, prev_stack_len_index))) {
- int prev_stack_len = NUM2INT(prev_stack_len_obj);
- int idx = stack_length - 1;
- int prev_frame_idx = 0;
- bool seen_already = true;
-
- // If the previous stack length and current stack length are equal,
- // loop and compare the current frame to the previous frame. If they are
- // not equal, set seen_already to false and break out of the loop.
- if (prev_stack_len == stack_length) {
- while (idx >= 0) {
- VALUE current_frame = frames_buffer[idx];
- VALUE prev_frame = RARRAY_AREF(rb_rjit_raw_samples, prev_stack_len_index + prev_frame_idx + 1);
-
- // If the current frame and previous frame are not equal, set
- // seen_already to false and break out of the loop.
- if (current_frame != prev_frame) {
- seen_already = false;
- break;
- }
-
- idx--;
- prev_frame_idx++;
- }
-
- // If we know we've seen this stack before, increment the counter by 1.
- if (seen_already) {
- int prev_idx = (int)RARRAY_LEN(rb_rjit_raw_samples) - 1;
- int prev_count = NUM2INT(RARRAY_AREF(rb_rjit_raw_samples, prev_idx));
- int new_count = prev_count + 1;
-
- rb_ary_store(rb_rjit_raw_samples, prev_idx, INT2NUM(new_count));
- rb_ary_store(rb_rjit_line_samples, prev_idx, INT2NUM(new_count));
- return;
- }
- }
- }
-
- rb_ary_push(rb_rjit_raw_samples, INT2NUM(stack_length));
- rb_ary_push(rb_rjit_line_samples, INT2NUM(stack_length));
-
- int idx = stack_length - 1;
-
- while (idx >= 0) {
- VALUE frame = frames_buffer[idx];
- int line = lines_buffer[idx];
-
- rb_ary_push(rb_rjit_raw_samples, frame);
- rb_ary_push(rb_rjit_line_samples, INT2NUM(line));
-
- idx--;
- }
-
- // Push the insn value into the yjit_raw_samples Vec.
- rb_ary_push(rb_rjit_raw_samples, INT2NUM(insn));
-
- // Push the current line onto the yjit_line_samples Vec. This
- // points to the line in insns.def.
- int line = (int)RARRAY_LEN(rb_rjit_line_samples) - 1;
- rb_ary_push(rb_rjit_line_samples, INT2NUM(line));
-
- // Push number of times seen onto the stack, which is 1
- // because it's the first time we've seen it.
- rb_ary_push(rb_rjit_raw_samples, INT2NUM(1));
- rb_ary_push(rb_rjit_line_samples, INT2NUM(1));
-}
-
-// For a given raw_sample (frame), set the hash with the caller's
-// name, file, and line number. Return the hash with collected frame_info.
-static void
-rjit_add_frame(VALUE hash, VALUE frame)
-{
- VALUE frame_id = SIZET2NUM(frame);
-
- if (RTEST(rb_hash_aref(hash, frame_id))) {
- return;
- }
- else {
- VALUE frame_info = rb_hash_new();
- // Full label for the frame
- VALUE name = rb_profile_frame_full_label(frame);
- // Absolute path of the frame from rb_iseq_realpath
- VALUE file = rb_profile_frame_absolute_path(frame);
- // Line number of the frame
- VALUE line = rb_profile_frame_first_lineno(frame);
-
- // If absolute path isn't available use the rb_iseq_path
- if (NIL_P(file)) {
- file = rb_profile_frame_path(frame);
- }
-
- rb_hash_aset(frame_info, ID2SYM(rb_intern("name")), name);
- rb_hash_aset(frame_info, ID2SYM(rb_intern("file")), file);
- rb_hash_aset(frame_info, ID2SYM(rb_intern("samples")), INT2NUM(0));
- rb_hash_aset(frame_info, ID2SYM(rb_intern("total_samples")), INT2NUM(0));
- rb_hash_aset(frame_info, ID2SYM(rb_intern("edges")), rb_hash_new());
- rb_hash_aset(frame_info, ID2SYM(rb_intern("lines")), rb_hash_new());
-
- if (line != INT2FIX(0)) {
- rb_hash_aset(frame_info, ID2SYM(rb_intern("line")), line);
- }
-
- rb_hash_aset(hash, frame_id, frame_info);
- }
-}
-
-static VALUE
-rjit_exit_traces(void)
-{
- int samples_len = (int)RARRAY_LEN(rb_rjit_raw_samples);
- RUBY_ASSERT(samples_len == RARRAY_LEN(rb_rjit_line_samples));
-
- VALUE result = rb_hash_new();
- VALUE raw_samples = rb_ary_new_capa(samples_len);
- VALUE line_samples = rb_ary_new_capa(samples_len);
- VALUE frames = rb_hash_new();
- int idx = 0;
-
- // While the index is less than samples_len, parse yjit_raw_samples and
- // yjit_line_samples, then add casted values to raw_samples and line_samples array.
- while (idx < samples_len) {
- int num = NUM2INT(RARRAY_AREF(rb_rjit_raw_samples, idx));
- int line_num = NUM2INT(RARRAY_AREF(rb_rjit_line_samples, idx));
- idx++;
-
- rb_ary_push(raw_samples, SIZET2NUM(num));
- rb_ary_push(line_samples, INT2NUM(line_num));
-
- // Loop through the length of samples_len and add data to the
- // frames hash. Also push the current value onto the raw_samples
- // and line_samples array respectively.
- for (int o = 0; o < num; o++) {
- rjit_add_frame(frames, RARRAY_AREF(rb_rjit_raw_samples, idx));
- rb_ary_push(raw_samples, SIZET2NUM(RARRAY_AREF(rb_rjit_raw_samples, idx)));
- rb_ary_push(line_samples, RARRAY_AREF(rb_rjit_line_samples, idx));
- idx++;
- }
-
- // insn BIN and lineno
- rb_ary_push(raw_samples, RARRAY_AREF(rb_rjit_raw_samples, idx));
- rb_ary_push(line_samples, RARRAY_AREF(rb_rjit_line_samples, idx));
- idx++;
-
- // Number of times seen
- rb_ary_push(raw_samples, RARRAY_AREF(rb_rjit_raw_samples, idx));
- rb_ary_push(line_samples, RARRAY_AREF(rb_rjit_line_samples, idx));
- idx++;
- }
-
- // Set add the raw_samples, line_samples, and frames to the results
- // hash.
- rb_hash_aset(result, ID2SYM(rb_intern("raw")), raw_samples);
- rb_hash_aset(result, ID2SYM(rb_intern("lines")), line_samples);
- rb_hash_aset(result, ID2SYM(rb_intern("frames")), frames);
-
- return result;
-}
-
-// An offsetof implementation that works for unnamed struct and union.
-// Multiplying 8 for compatibility with libclang's offsetof.
-#define OFFSETOF(ptr, member) RB_SIZE2NUM(((char *)&ptr.member - (char*)&ptr) * 8)
-
-#define SIZEOF(type) RB_SIZE2NUM(sizeof(type))
-#define SIGNED_TYPE_P(type) RBOOL((type)(-1) < (type)(1))
-
-// Insn side exit counters
-static size_t rjit_insn_exits[VM_INSTRUCTION_SIZE] = { 0 };
-
-// macOS: brew install capstone
-// Ubuntu/Debian: apt-get install libcapstone-dev
-// Fedora: dnf -y install capstone-devel
-#ifdef HAVE_LIBCAPSTONE
-#include <capstone/capstone.h>
-#endif
-
-// Return an array of [address, mnemonic, op_str]
-static VALUE
-dump_disasm(rb_execution_context_t *ec, VALUE self, VALUE from, VALUE to, VALUE test)
-{
- VALUE result = rb_ary_new();
-#ifdef HAVE_LIBCAPSTONE
- // Prepare for calling cs_disasm
- static csh handle;
- if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) {
- rb_raise(rb_eRuntimeError, "failed to make Capstone handle");
- }
- size_t from_addr = NUM2SIZET(from);
- size_t to_addr = NUM2SIZET(to);
-
- // Call cs_disasm and convert results to a Ruby array
- cs_insn *insns;
- size_t base_addr = RTEST(test) ? 0 : from_addr; // On tests, start from 0 for output stability.
- size_t count = cs_disasm(handle, (const uint8_t *)from_addr, to_addr - from_addr, base_addr, 0, &insns);
- for (size_t i = 0; i < count; i++) {
- VALUE vals = rb_ary_new_from_args(3, LONG2NUM(insns[i].address), rb_str_new2(insns[i].mnemonic), rb_str_new2(insns[i].op_str));
- rb_ary_push(result, vals);
- }
-
- // Free memory used by capstone
- cs_free(insns, count);
- cs_close(&handle);
-#endif
- return result;
-}
-
-// Same as `RubyVM::RJIT.enabled?`, but this is used before it's defined.
-static VALUE
-rjit_enabled_p(rb_execution_context_t *ec, VALUE self)
-{
- return RBOOL(rb_rjit_enabled);
-}
-
-static int
-for_each_iseq_i(void *vstart, void *vend, size_t stride, void *data)
-{
- VALUE block = (VALUE)data;
- VALUE v = (VALUE)vstart;
- for (; v != (VALUE)vend; v += stride) {
- void *ptr = asan_poisoned_object_p(v);
- asan_unpoison_object(v, false);
-
- if (rb_obj_is_iseq(v)) {
- extern VALUE rb_rjit_iseq_new(rb_iseq_t *iseq);
- rb_iseq_t *iseq = (rb_iseq_t *)v;
- rb_funcall(block, rb_intern("call"), 1, rb_rjit_iseq_new(iseq));
- }
-
- asan_poison_object_if(ptr, v);
- }
- return 0;
-}
-
-static VALUE
-rjit_for_each_iseq(rb_execution_context_t *ec, VALUE self, VALUE block)
-{
- rb_objspace_each_objects(for_each_iseq_i, (void *)block);
- return Qnil;
-}
-
-// bindgen references
-extern ID rb_get_symbol_id(VALUE name);
-extern VALUE rb_fix_aref(VALUE fix, VALUE idx);
-extern VALUE rb_str_getbyte(VALUE str, VALUE index);
-extern VALUE rb_vm_concat_array(VALUE ary1, VALUE ary2st);
-extern VALUE rb_vm_get_ev_const(rb_execution_context_t *ec, VALUE orig_klass, ID id, VALUE allow_nil);
-extern VALUE rb_vm_getclassvariable(const rb_iseq_t *iseq, const rb_control_frame_t *cfp, ID id, ICVARC ic);
-extern VALUE rb_vm_opt_newarray_min(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr);
-extern VALUE rb_vm_opt_newarray_max(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr);
-extern VALUE rb_vm_opt_newarray_hash(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr);
-extern VALUE rb_vm_opt_newarray_pack(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr, VALUE fmt);
-extern VALUE rb_vm_splat_array(VALUE flag, VALUE array);
-extern bool rb_simple_iseq_p(const rb_iseq_t *iseq);
-extern bool rb_vm_defined(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t op_type, VALUE obj, VALUE v);
-extern bool rb_vm_ic_hit_p(IC ic, const VALUE *reg_ep);
-extern rb_event_flag_t rb_rjit_global_events;
-extern void rb_vm_setinstancevariable(const rb_iseq_t *iseq, VALUE obj, ID id, VALUE val, IVC ic);
-extern VALUE rb_vm_throw(const rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t throw_state, VALUE throwobj);
-extern VALUE rb_reg_new_ary(VALUE ary, int opt);
-extern void rb_vm_setclassvariable(const rb_iseq_t *iseq, const rb_control_frame_t *cfp, ID id, VALUE val, ICVARC ic);
-extern VALUE rb_str_bytesize(VALUE str);
-extern const rb_callable_method_entry_t *rb_callable_method_entry_or_negative(VALUE klass, ID mid);
-extern VALUE rb_vm_yield_with_cfunc(rb_execution_context_t *ec, const struct rb_captured_block *captured, int argc, const VALUE *argv);
-extern VALUE rb_vm_set_ivar_id(VALUE obj, ID id, VALUE val);
-extern VALUE rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary);
-extern void* rb_rjit_entry_stub_hit(VALUE branch_stub);
-extern void* rb_rjit_branch_stub_hit(VALUE branch_stub, int sp_offset, int target0_p);
-extern uint64_t rb_vm_insns_count;
-
-#include "rjit_c.rbinc"
-
-#endif // USE_RJIT
diff --git a/rjit_c.h b/rjit_c.h
deleted file mode 100644
index 029f811637..0000000000
--- a/rjit_c.h
+++ /dev/null
@@ -1,165 +0,0 @@
-// This file is parsed by tool/rjit/generate.rb to generate rjit_c.rb
-#ifndef RJIT_C_H
-#define RJIT_C_H
-
-#include "ruby/internal/config.h"
-#include "internal/string.h"
-#include "internal/struct.h"
-#include "internal/variable.h"
-#include "vm_core.h"
-#include "vm_callinfo.h"
-#include "builtin.h"
-#include "ccan/list/list.h"
-#include "rjit.h"
-#include "shape.h"
-
-extern uint8_t *rb_rjit_mem_block;
-
-#define RJIT_RUNTIME_COUNTERS(...) struct rb_rjit_runtime_counters { size_t __VA_ARGS__; };
-RJIT_RUNTIME_COUNTERS(
- rjit_insns_count,
-
- send_args_splat_kw_splat,
- send_args_splat,
- send_args_splat_not_array,
- send_args_splat_length_not_equal,
- send_args_splat_cfunc_var_args,
- send_args_splat_arity_error,
- send_args_splat_ruby2_hash,
- send_args_splat_cfunc_zuper,
- send_args_splat_cfunc_ruby2_keywords,
- send_kw_splat,
- send_kwarg,
- send_klass_megamorphic,
- send_missing_cme,
- send_private,
- send_protected_check_failed,
- send_tailcall,
- send_notimplemented,
- send_missing,
- send_bmethod,
- send_alias,
- send_undef,
- send_zsuper,
- send_refined,
- send_stackoverflow,
- send_arity,
- send_c_tracing,
- send_is_a_class_mismatch,
- send_instance_of_class_mismatch,
- send_keywords,
-
- send_blockiseq,
- send_block_handler,
- send_block_setup,
- send_block_not_nil,
- send_block_not_proxy,
- send_block_arg,
-
- send_iseq_kwparam,
- send_iseq_accepts_no_kwarg,
- send_iseq_has_opt,
- send_iseq_has_kwrest,
- send_iseq_ruby2_keywords,
- send_iseq_has_rest_and_captured,
- send_iseq_has_rest_and_kw_supplied,
- send_iseq_has_no_kw,
- send_iseq_zsuper,
- send_iseq_materialized_block,
- send_iseq_has_rest,
- send_iseq_block_arg0_splat,
- send_iseq_kw_call,
- send_iseq_kw_splat,
- send_iseq_splat,
- send_iseq_has_rest_and_optional,
- send_iseq_arity_error,
- send_iseq_missing_optional_kw,
- send_iseq_too_many_kwargs,
- send_iseq_kwargs_mismatch,
- send_iseq_splat_with_kw,
- send_iseq_splat_arity_error,
- send_iseq_has_rest_and_splat_not_equal,
-
- send_cfunc_variadic,
- send_cfunc_too_many_args,
- send_cfunc_ruby_array_varg,
- send_cfunc_splat_with_kw,
- send_cfunc_tracing,
- send_cfunc_argc_mismatch,
- send_cfunc_toomany_args,
-
- send_attrset_splat,
- send_attrset_kwarg,
- send_attrset_method,
-
- send_ivar_splat,
- send_ivar_opt_send,
-
- send_optimized_send_no_args,
- send_optimized_send_not_sym_or_str,
- send_optimized_send_mid_class_changed,
- send_optimized_send_mid_id_changed,
- send_optimized_send_null_mid,
- send_optimized_send_send,
- send_optimized_call_block,
- send_optimized_call_kwarg,
- send_optimized_call_splat,
- send_optimized_struct_aref_error,
-
- send_optimized_block_call,
- send_optimized_struct_aset,
-
- send_bmethod_not_iseq,
- send_bmethod_blockarg,
-
- invokesuper_me_changed,
- invokesuper_block,
-
- invokeblock_none,
- invokeblock_symbol,
- invokeblock_proc,
- invokeblock_tag_changed,
- invokeblock_iseq_block_changed,
- invokeblock_iseq_arity,
- invokeblock_iseq_arg0_splat,
- invokeblock_ifunc_args_splat,
- invokeblock_ifunc_kw_splat,
- invokeblock_iseq_arg0_args_splat,
- invokeblock_iseq_arg0_has_kw,
-
- getivar_megamorphic,
- getivar_not_heap,
- getivar_special_const,
- getivar_too_complex,
-
- optaref_arg_not_fixnum,
- optaref_argc_not_one,
- optaref_recv_not_array,
- optaref_recv_not_hash,
- optaref_send,
-
- optgetconst_not_cached,
- optgetconst_cref,
- optgetconst_cache_miss,
-
- setivar_frozen,
- setivar_not_heap,
- setivar_megamorphic,
- setivar_too_complex,
-
- expandarray_splat,
- expandarray_postarg,
- expandarray_not_array,
- expandarray_rhs_too_small,
-
- getblockpp_block_param_modified,
- getblockpp_block_handler_none,
- getblockpp_not_gc_guarded,
- getblockpp_not_iseq_block,
-
- compiled_block_count
-)
-#undef RJIT_RUNTIME_COUNTERS
-extern struct rb_rjit_runtime_counters rb_rjit_counters;
-
-#endif /* RJIT_C_H */
diff --git a/rjit_c.rb b/rjit_c.rb
deleted file mode 100644
index 422b7f8e3d..0000000000
--- a/rjit_c.rb
+++ /dev/null
@@ -1,1667 +0,0 @@
-# frozen_string_literal: true
-# Part of this file is generated by tool/rjit/bindgen.rb.
-# Run `make rjit-bindgen` to update code between "RJIT bindgen begin" and "RJIT bindgen end".
-module RubyVM::RJIT # :nodoc: all
- #
- # Main: Used by RJIT
- #
- # This `class << C` section is for calling C functions with Primitive.
- # For importing variables or macros, use tool/rjit/bindgen.rb instead.
- class << C = Module.new
- def mmap(mem_size)
- Primitive.cexpr! 'SIZET2NUM((size_t)rjit_reserve_addr_space(NUM2UINT(mem_size)))'
- end
-
- def mprotect_write(mem_block, mem_size)
- Primitive.mprotect_write(mem_block, mem_size)
- end
-
- def mprotect_exec(mem_block, mem_size)
- Primitive.mprotect_exec(mem_block, mem_size)
- end
-
- def rjit_insn_exits
- addr = Primitive.cexpr! 'SIZET2NUM((size_t)rjit_insn_exits)'
- CType::Immediate.parse("size_t").new(addr)
- end
-
- def rb_rjit_counters
- addr = Primitive.cexpr! 'SIZET2NUM((size_t)&rb_rjit_counters)'
- rb_rjit_runtime_counters.new(addr)
- end
-
- # @param from [Integer] - From address
- # @param to [Integer] - To address
- def dump_disasm(from, to, test: false)
- Primitive.dump_disasm(from, to, test)
- end
-
- # Convert a Ruby object to a VALUE in Integer
- def to_value(obj)
- Primitive.cexpr! 'SIZET2NUM((size_t)obj)'
- end
-
- def BASIC_OP_UNREDEFINED_P(op, klass)
- Primitive.cexpr! 'RBOOL(BASIC_OP_UNREDEFINED_P(NUM2INT(op), NUM2INT(klass)))'
- end
-
- def rb_iseq_line_no(iseq, pos)
- _iseq_addr = iseq.to_i
- Primitive.cexpr! 'UINT2NUM(rb_iseq_line_no((const rb_iseq_t *)NUM2SIZET(_iseq_addr), NUM2SIZET(pos)))'
- end
-
- def rb_class_of(obj)
- Primitive.cexpr! 'rb_class_of(obj)'
- end
-
- def rb_callable_method_entry(klass, mid)
- cme_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_callable_method_entry(klass, NUM2UINT(mid)))'
- return nil if cme_addr == 0
- rb_callable_method_entry_t.new(cme_addr)
- end
-
- def METHOD_ENTRY_VISI(cme)
- _cme_addr = cme.to_i
- Primitive.cexpr! 'UINT2NUM(METHOD_ENTRY_VISI((const rb_callable_method_entry_t *)NUM2SIZET(_cme_addr)))'
- end
-
- def rb_simple_iseq_p(iseq)
- _iseq_addr = iseq.to_i
- Primitive.cexpr! 'RBOOL(rb_simple_iseq_p((rb_iseq_t *)NUM2SIZET(_iseq_addr)))'
- end
-
- def SPECIAL_CONST_P(obj)
- _value = to_value(obj)
- Primitive.cexpr! 'RBOOL(SPECIAL_CONST_P((VALUE)NUM2SIZET(_value)))'
- end
-
- def BUILTIN_TYPE(obj)
- _value = to_value(obj)
- Primitive.cexpr! 'INT2NUM(BUILTIN_TYPE((VALUE)NUM2SIZET(_value)))'
- end
-
- def RB_TYPE_P(obj, type)
- Primitive.cexpr! 'RBOOL(RB_TYPE_P(obj, NUM2UINT(type)))'
- end
-
- def rb_shape_get_shape_id(obj)
- _value = to_value(obj)
- Primitive.cexpr! 'UINT2NUM((unsigned int)rb_shape_get_shape_id((VALUE)NUM2SIZET(_value)))'
- end
-
- def rb_shape_id_offset
- Primitive.cexpr! 'INT2NUM(rb_shape_id_offset())'
- end
-
- def rb_shape_get_iv_index(shape_id, ivar_id)
- Primitive.cstmt! %{
- rb_shape_t *shape = rb_shape_get_shape_by_id((shape_id_t)NUM2SIZET(shape_id));
- attr_index_t index;
- bool found = rb_shape_get_iv_index(shape, (ID)NUM2SIZET(ivar_id), &index);
- return found ? UINT2NUM(index) : Qnil;
- }
- end
-
- def FL_TEST_RAW(obj, flags)
- Primitive.cexpr! 'RBOOL(FL_TEST_RAW(obj, (VALUE)NUM2SIZET(flags)))'
- end
-
- def FL_TEST(obj, flags)
- Primitive.cexpr! 'RBOOL(FL_TEST(obj, (VALUE)NUM2SIZET(flags)))'
- end
-
- def rjit_for_each_iseq(&block)
- Primitive.rjit_for_each_iseq(block)
- end
-
- def get_symbol_id(name)
- Primitive.cexpr! 'SIZET2NUM((size_t)rb_get_symbol_id(name))'
- end
-
- def rb_vm_frame_method_entry(cfp)
- _cfp = cfp.to_i
- cme_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_vm_frame_method_entry((const rb_control_frame_t *)NUM2SIZET(_cfp)))'
- return nil if cme_addr == 0
- rb_callable_method_entry_t.new(cme_addr)
- end
-
- def rb_class_get_superclass(klass)
- Primitive.cexpr! 'rb_class_get_superclass(klass)'
- end
-
- def ID2SYM(id)
- Primitive.cexpr! 'ID2SYM((ID)NUM2SIZET(id))'
- end
-
- def obj_is_kind_of(obj, c)
- Primitive.cexpr! 'rb_obj_is_kind_of(obj, c)'
- end
-
- def imemo_type_p(ptr, type)
- _ptr = ptr.to_i
- Primitive.cexpr! 'RBOOL(imemo_type_p((VALUE)NUM2SIZET(_ptr), NUM2UINT(type)))'
- end
-
- def rb_iseq_only_optparam_p(iseq)
- _iseq = iseq.to_i
- Primitive.cstmt! %{
- extern bool rb_iseq_only_optparam_p(const rb_iseq_t *iseq);
- return RBOOL(rb_iseq_only_optparam_p((rb_iseq_t *)NUM2SIZET(_iseq)));
- }
- end
-
- def rb_iseq_only_kwparam_p(iseq)
- _iseq = iseq.to_i
- Primitive.cstmt! %{
- extern bool rb_iseq_only_kwparam_p(const rb_iseq_t *iseq);
- return RBOOL(rb_iseq_only_kwparam_p((rb_iseq_t *)NUM2SIZET(_iseq)));
- }
- end
-
- def rb_obj_frozen_p(obj)
- Primitive.cexpr! 'rb_obj_frozen_p(obj)'
- end
-
- def rb_intern(str)
- Primitive.cexpr! 'SIZET2NUM((size_t)rb_intern(RSTRING_PTR(str)))'
- end
-
- def rb_method_entry_at(klass, mid)
- me_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_method_entry_at(klass, (ID)NUM2SIZET(mid)))'
- me_addr == 0 ? nil : rb_method_entry_t.new(me_addr)
- end
-
- def rb_shape_get_next_no_warnings(shape, obj, id)
- _shape = shape.to_i
- shape_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_shape_get_next_no_warnings((rb_shape_t *)NUM2SIZET(_shape), obj, (ID)NUM2SIZET(id)))'
- rb_shape_t.new(shape_addr)
- end
-
- def rb_shape_id(shape)
- _shape = shape.to_i
- Primitive.cexpr! 'SIZET2NUM((size_t)rb_shape_id((rb_shape_t *)NUM2SIZET(_shape)))'
- end
-
- def rb_class_attached_object(klass)
- Primitive.cexpr! 'rb_class_attached_object(klass)'
- end
-
- def rb_singleton_class(obj)
- Primitive.cexpr! 'rb_singleton_class(obj)'
- end
-
- def rb_aliased_callable_method_entry(cme)
- _cme = cme.to_i
- cme_addr = Primitive.cstmt! %{
- extern const rb_callable_method_entry_t * rb_aliased_callable_method_entry(const rb_callable_method_entry_t *me);
- return SIZET2NUM((size_t)rb_aliased_callable_method_entry((const rb_callable_method_entry_t *)NUM2SIZET(_cme)));
- }
- rb_callable_method_entry_t.new(cme_addr)
- end
-
- def rb_yjit_get_proc_ptr(proc_addr)
- proc_t_addr = Primitive.cstmt! %{
- extern rb_proc_t * rjit_get_proc_ptr(VALUE procv);
- return SIZET2NUM((size_t)rjit_get_proc_ptr((VALUE)NUM2SIZET(proc_addr)));
- }
- rb_proc_t.new(proc_t_addr)
- end
-
- def rb_shape_get_shape_by_id(shape_id)
- _shape_id = shape_id.to_i
- shape_addr = Primitive.cexpr! 'SIZET2NUM((VALUE)rb_shape_get_shape_by_id((shape_id_t)NUM2UINT(_shape_id)))'
- rb_shape_t.new(shape_addr)
- end
-
- def rb_iseq_check(iseq)
- _iseq_addr = iseq.to_i
- iseq_addr = Primitive.cexpr! 'SIZET2NUM((VALUE)rb_iseq_check((rb_iseq_t *)NUM2SIZET(_iseq_addr)))'
- rb_iseq_t.new(iseq_addr)
- end
-
- def rb_iseq_path(iseq)
- _iseq_addr = iseq.to_i
- Primitive.cexpr! 'rb_iseq_path((rb_iseq_t *)NUM2SIZET(_iseq_addr))'
- end
-
- def vm_ci_argc(ci)
- _ci_addr = ci.to_i
- Primitive.cexpr! 'UINT2NUM(vm_ci_argc((CALL_INFO)NUM2SIZET(_ci_addr)))'
- end
-
- def vm_ci_flag(ci)
- _ci_addr = ci.to_i
- Primitive.cexpr! 'UINT2NUM(vm_ci_flag((CALL_INFO)NUM2SIZET(_ci_addr)))'
- end
-
- def vm_ci_kwarg(ci)
- _ci_addr = ci.to_i
- kwarg_addr = Primitive.cexpr! 'SIZET2NUM((size_t)vm_ci_kwarg((CALL_INFO)NUM2SIZET(_ci_addr)))'
- kwarg_addr == 0 ? nil : rb_callinfo_kwarg.new(kwarg_addr)
- end
-
- def vm_ci_mid(ci)
- _ci_addr = ci.to_i
- Primitive.cexpr! 'SIZET2NUM((size_t)vm_ci_mid((CALL_INFO)NUM2SIZET(_ci_addr)))'
- end
-
- def rjit_opts
- addr = Primitive.cexpr! 'SIZET2NUM((VALUE)&rb_rjit_opts)'
- rb_rjit_options.new(addr)
- end
-
- def rjit_cancel_all(reason)
- Primitive.cstmt! %{
- rb_rjit_cancel_all(RSTRING_PTR(reason));
- return Qnil;
- }
- end
-
- # Convert an encoded VM pointer to an insn BIN.
- def rb_vm_insn_decode(encoded)
- # Using rb_vm_insn_addr2opcode to return trace_ insns
- Primitive.cexpr! 'INT2NUM(rb_vm_insn_addr2opcode((void *)NUM2SIZET(encoded)))'
- end
-
- # Convert Integer VALUE to an actual Ruby object
- def to_ruby(value)
- Primitive.cexpr! '(VALUE)NUM2SIZET(value)'
- end
-
- def HAVE_LIBCAPSTONE
- Primitive.cstmt! %{
- #ifdef HAVE_LIBCAPSTONE
- return Qtrue;
- #else
- return Qfalse;
- #endif
- }
- end
-
- def rjit_exit_traces
- Primitive.cexpr! 'rjit_exit_traces()'
- end
-
- def rb_vm_ep_local_ep(ep)
- _ep = ep.to_i
- lep_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_vm_ep_local_ep((const VALUE *)NUM2SIZET(_ep)))'
- C.VALUE.new(lep_addr)
- end
-
- def rb_hash_keys(hash)
- Primitive.cexpr! 'rb_hash_keys(hash)'
- end
-
- def rb_hash_stlike_lookup(hash, key)
- Primitive.cstmt! %{
- VALUE result = Qnil;
- rb_hash_stlike_lookup(hash, key, &result);
- return result;
- }
- end
-
- def rb_obj_class(obj)
- Primitive.cexpr! 'rb_obj_class(obj)'
- end
-
- def rb_sym2id(sym)
- Primitive.cexpr! 'SIZET2NUM((size_t)rb_sym2id(sym))'
- end
-
- def rb_callable_method_entry_or_negative(klass, mid)
- cme_addr = Primitive.cexpr! 'SIZET2NUM((size_t)rb_callable_method_entry_or_negative(klass, (ID)NUM2SIZET(mid)))'
- return nil if cme_addr == 0
- rb_callable_method_entry_t.new(cme_addr)
- end
-
- def rb_method_basic_definition_p(klass, mid)
- Primitive.cexpr! 'RBOOL(rb_method_basic_definition_p(klass, (ID)NUM2SIZET(mid)))'
- end
-
- def UNDEFINED_METHOD_ENTRY_P(cme)
- _cme_addr = cme.to_i
- Primitive.cexpr! 'RBOOL(UNDEFINED_METHOD_ENTRY_P((const rb_callable_method_entry_t *)NUM2SIZET(_cme_addr)))'
- end
-
- def RCLASS_ORIGIN(klass)
- Primitive.cexpr! 'RCLASS_ORIGIN(klass)'
- end
-
- def RCLASS_SINGLETON_P(klass)
- Primitive.cexpr! 'RCLASS_SINGLETON_P(klass)'
- end
- end
-
- #
- # Utilities: Not used by RJIT, but useful for debugging
- #
- class << C
- # Convert insn BINs to encoded VM pointers.
- def rb_vm_insn_encode(bin)
- Primitive.cexpr! 'SIZET2NUM((VALUE)rb_vm_get_insns_address_table()[NUM2INT(bin)])'
- end
-
- # Convert RubyVM::InstructionSequence to C.rb_iseq_t.
- def rb_iseqw_to_iseq(iseqw)
- iseq_addr = Primitive.cexpr! 'SIZET2NUM((VALUE)rb_iseqw_to_iseq(iseqw))'
- rb_iseq_t.new(iseq_addr)
- end
- end
-
- ### RJIT bindgen begin ###
-
- C::UNLIMITED_ARGUMENTS = Primitive.cexpr! %q{ LONG2NUM(UNLIMITED_ARGUMENTS) }
- C::VM_ENV_DATA_INDEX_ME_CREF = Primitive.cexpr! %q{ LONG2NUM(VM_ENV_DATA_INDEX_ME_CREF) }
- C::VM_ENV_DATA_INDEX_SPECVAL = Primitive.cexpr! %q{ LONG2NUM(VM_ENV_DATA_INDEX_SPECVAL) }
- C::ARRAY_REDEFINED_OP_FLAG = Primitive.cexpr! %q{ SIZET2NUM(ARRAY_REDEFINED_OP_FLAG) }
- C::BOP_AND = Primitive.cexpr! %q{ SIZET2NUM(BOP_AND) }
- C::BOP_AREF = Primitive.cexpr! %q{ SIZET2NUM(BOP_AREF) }
- C::BOP_EQ = Primitive.cexpr! %q{ SIZET2NUM(BOP_EQ) }
- C::BOP_EQQ = Primitive.cexpr! %q{ SIZET2NUM(BOP_EQQ) }
- C::BOP_FREEZE = Primitive.cexpr! %q{ SIZET2NUM(BOP_FREEZE) }
- C::BOP_GE = Primitive.cexpr! %q{ SIZET2NUM(BOP_GE) }
- C::BOP_GT = Primitive.cexpr! %q{ SIZET2NUM(BOP_GT) }
- C::BOP_LE = Primitive.cexpr! %q{ SIZET2NUM(BOP_LE) }
- C::BOP_LT = Primitive.cexpr! %q{ SIZET2NUM(BOP_LT) }
- C::BOP_MINUS = Primitive.cexpr! %q{ SIZET2NUM(BOP_MINUS) }
- C::BOP_MOD = Primitive.cexpr! %q{ SIZET2NUM(BOP_MOD) }
- C::BOP_OR = Primitive.cexpr! %q{ SIZET2NUM(BOP_OR) }
- C::BOP_PLUS = Primitive.cexpr! %q{ SIZET2NUM(BOP_PLUS) }
- C::BUILTIN_ATTR_LEAF = Primitive.cexpr! %q{ SIZET2NUM(BUILTIN_ATTR_LEAF) }
- C::HASH_REDEFINED_OP_FLAG = Primitive.cexpr! %q{ SIZET2NUM(HASH_REDEFINED_OP_FLAG) }
- C::INTEGER_REDEFINED_OP_FLAG = Primitive.cexpr! %q{ SIZET2NUM(INTEGER_REDEFINED_OP_FLAG) }
- C::INVALID_SHAPE_ID = Primitive.cexpr! %q{ SIZET2NUM(INVALID_SHAPE_ID) }
- C::METHOD_VISI_PRIVATE = Primitive.cexpr! %q{ SIZET2NUM(METHOD_VISI_PRIVATE) }
- C::METHOD_VISI_PROTECTED = Primitive.cexpr! %q{ SIZET2NUM(METHOD_VISI_PROTECTED) }
- C::METHOD_VISI_PUBLIC = Primitive.cexpr! %q{ SIZET2NUM(METHOD_VISI_PUBLIC) }
- C::METHOD_VISI_UNDEF = Primitive.cexpr! %q{ SIZET2NUM(METHOD_VISI_UNDEF) }
- C::OBJ_TOO_COMPLEX_SHAPE_ID = Primitive.cexpr! %q{ SIZET2NUM(OBJ_TOO_COMPLEX_SHAPE_ID) }
- C::OPTIMIZED_METHOD_TYPE_BLOCK_CALL = Primitive.cexpr! %q{ SIZET2NUM(OPTIMIZED_METHOD_TYPE_BLOCK_CALL) }
- C::OPTIMIZED_METHOD_TYPE_CALL = Primitive.cexpr! %q{ SIZET2NUM(OPTIMIZED_METHOD_TYPE_CALL) }
- C::OPTIMIZED_METHOD_TYPE_SEND = Primitive.cexpr! %q{ SIZET2NUM(OPTIMIZED_METHOD_TYPE_SEND) }
- C::OPTIMIZED_METHOD_TYPE_STRUCT_AREF = Primitive.cexpr! %q{ SIZET2NUM(OPTIMIZED_METHOD_TYPE_STRUCT_AREF) }
- C::OPTIMIZED_METHOD_TYPE_STRUCT_ASET = Primitive.cexpr! %q{ SIZET2NUM(OPTIMIZED_METHOD_TYPE_STRUCT_ASET) }
- C::RARRAY_EMBED_FLAG = Primitive.cexpr! %q{ SIZET2NUM(RARRAY_EMBED_FLAG) }
- C::RARRAY_EMBED_LEN_MASK = Primitive.cexpr! %q{ SIZET2NUM(RARRAY_EMBED_LEN_MASK) }
- C::RARRAY_EMBED_LEN_SHIFT = Primitive.cexpr! %q{ SIZET2NUM(RARRAY_EMBED_LEN_SHIFT) }
- C::RHASH_PASS_AS_KEYWORDS = Primitive.cexpr! %q{ SIZET2NUM(RHASH_PASS_AS_KEYWORDS) }
- C::RMODULE_IS_REFINEMENT = Primitive.cexpr! %q{ SIZET2NUM(RMODULE_IS_REFINEMENT) }
- C::ROBJECT_EMBED = Primitive.cexpr! %q{ SIZET2NUM(ROBJECT_EMBED) }
- C::RSTRUCT_EMBED_LEN_MASK = Primitive.cexpr! %q{ SIZET2NUM(RSTRUCT_EMBED_LEN_MASK) }
- C::RUBY_ENCODING_MASK = Primitive.cexpr! %q{ SIZET2NUM(RUBY_ENCODING_MASK) }
- C::RUBY_EVENT_CLASS = Primitive.cexpr! %q{ SIZET2NUM(RUBY_EVENT_CLASS) }
- C::RUBY_EVENT_C_CALL = Primitive.cexpr! %q{ SIZET2NUM(RUBY_EVENT_C_CALL) }
- C::RUBY_EVENT_C_RETURN = Primitive.cexpr! %q{ SIZET2NUM(RUBY_EVENT_C_RETURN) }
- C::RUBY_FIXNUM_FLAG = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FIXNUM_FLAG) }
- C::RUBY_FLONUM_FLAG = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FLONUM_FLAG) }
- C::RUBY_FLONUM_MASK = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FLONUM_MASK) }
- C::RUBY_FL_FREEZE = Primitive.cexpr! %q{ SIZET2NUM(RUBY_FL_FREEZE) }
- C::RUBY_IMMEDIATE_MASK = Primitive.cexpr! %q{ SIZET2NUM(RUBY_IMMEDIATE_MASK) }
- C::RUBY_SPECIAL_SHIFT = Primitive.cexpr! %q{ SIZET2NUM(RUBY_SPECIAL_SHIFT) }
- C::RUBY_SYMBOL_FLAG = Primitive.cexpr! %q{ SIZET2NUM(RUBY_SYMBOL_FLAG) }
- C::RUBY_T_ARRAY = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_ARRAY) }
- C::RUBY_T_CLASS = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_CLASS) }
- C::RUBY_T_HASH = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_HASH) }
- C::RUBY_T_ICLASS = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_ICLASS) }
- C::RUBY_T_MASK = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_MASK) }
- C::RUBY_T_MODULE = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_MODULE) }
- C::RUBY_T_OBJECT = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_OBJECT) }
- C::RUBY_T_STRING = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_STRING) }
- C::RUBY_T_SYMBOL = Primitive.cexpr! %q{ SIZET2NUM(RUBY_T_SYMBOL) }
- C::SHAPE_FLAG_SHIFT = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_FLAG_SHIFT) }
- C::SHAPE_FROZEN = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_FROZEN) }
- C::SHAPE_ID_NUM_BITS = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_ID_NUM_BITS) }
- C::SHAPE_IVAR = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_IVAR) }
- C::SHAPE_MASK = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_MASK) }
- C::SHAPE_ROOT = Primitive.cexpr! %q{ SIZET2NUM(SHAPE_ROOT) }
- C::STRING_REDEFINED_OP_FLAG = Primitive.cexpr! %q{ SIZET2NUM(STRING_REDEFINED_OP_FLAG) }
- C::T_OBJECT = Primitive.cexpr! %q{ SIZET2NUM(T_OBJECT) }
- C::VM_BLOCK_HANDLER_NONE = Primitive.cexpr! %q{ SIZET2NUM(VM_BLOCK_HANDLER_NONE) }
- C::VM_CALL_ARGS_BLOCKARG = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_ARGS_BLOCKARG) }
- C::VM_CALL_ARGS_SPLAT = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_ARGS_SPLAT) }
- C::VM_CALL_FCALL = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_FCALL) }
- C::VM_CALL_FORWARDING = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_FORWARDING) }
- C::VM_CALL_KWARG = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_KWARG) }
- C::VM_CALL_KW_SPLAT = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_KW_SPLAT) }
- C::VM_CALL_KW_SPLAT_MUT = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_KW_SPLAT_MUT) }
- C::VM_CALL_KW_SPLAT_bit = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_KW_SPLAT_bit) }
- C::VM_CALL_OPT_SEND = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_OPT_SEND) }
- C::VM_CALL_TAILCALL = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_TAILCALL) }
- C::VM_CALL_TAILCALL_bit = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_TAILCALL_bit) }
- C::VM_CALL_ZSUPER = Primitive.cexpr! %q{ SIZET2NUM(VM_CALL_ZSUPER) }
- C::VM_ENV_DATA_INDEX_FLAGS = Primitive.cexpr! %q{ SIZET2NUM(VM_ENV_DATA_INDEX_FLAGS) }
- C::VM_ENV_DATA_SIZE = Primitive.cexpr! %q{ SIZET2NUM(VM_ENV_DATA_SIZE) }
- C::VM_ENV_FLAG_LOCAL = Primitive.cexpr! %q{ SIZET2NUM(VM_ENV_FLAG_LOCAL) }
- C::VM_ENV_FLAG_WB_REQUIRED = Primitive.cexpr! %q{ SIZET2NUM(VM_ENV_FLAG_WB_REQUIRED) }
- C::VM_FRAME_FLAG_BMETHOD = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_FLAG_BMETHOD) }
- C::VM_FRAME_FLAG_CFRAME = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_FLAG_CFRAME) }
- C::VM_FRAME_FLAG_CFRAME_KW = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_FLAG_CFRAME_KW) }
- C::VM_FRAME_FLAG_LAMBDA = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_FLAG_LAMBDA) }
- C::VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_FLAG_MODIFIED_BLOCK_PARAM) }
- C::VM_FRAME_MAGIC_BLOCK = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_MAGIC_BLOCK) }
- C::VM_FRAME_MAGIC_CFUNC = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_MAGIC_CFUNC) }
- C::VM_FRAME_MAGIC_METHOD = Primitive.cexpr! %q{ SIZET2NUM(VM_FRAME_MAGIC_METHOD) }
- C::VM_METHOD_TYPE_ALIAS = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_ALIAS) }
- C::VM_METHOD_TYPE_ATTRSET = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_ATTRSET) }
- C::VM_METHOD_TYPE_BMETHOD = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_BMETHOD) }
- C::VM_METHOD_TYPE_CFUNC = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_CFUNC) }
- C::VM_METHOD_TYPE_ISEQ = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_ISEQ) }
- C::VM_METHOD_TYPE_IVAR = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_IVAR) }
- C::VM_METHOD_TYPE_MISSING = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_MISSING) }
- C::VM_METHOD_TYPE_NOTIMPLEMENTED = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_NOTIMPLEMENTED) }
- C::VM_METHOD_TYPE_OPTIMIZED = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_OPTIMIZED) }
- C::VM_METHOD_TYPE_REFINED = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_REFINED) }
- C::VM_METHOD_TYPE_UNDEF = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_UNDEF) }
- C::VM_METHOD_TYPE_ZSUPER = Primitive.cexpr! %q{ SIZET2NUM(VM_METHOD_TYPE_ZSUPER) }
- C::VM_SPECIAL_OBJECT_VMCORE = Primitive.cexpr! %q{ SIZET2NUM(VM_SPECIAL_OBJECT_VMCORE) }
-
- def C.block_type_iseq = Primitive.cexpr!(%q{ SIZET2NUM(block_type_iseq) })
- def C.idRespond_to_missing = Primitive.cexpr!(%q{ SIZET2NUM(idRespond_to_missing) })
- def C.imemo_callinfo = Primitive.cexpr!(%q{ SIZET2NUM(imemo_callinfo) })
- def C.imemo_iseq = Primitive.cexpr!(%q{ SIZET2NUM(imemo_iseq) })
- def C.rb_block_param_proxy = Primitive.cexpr!(%q{ SIZET2NUM(rb_block_param_proxy) })
- def C.rb_cArray = Primitive.cexpr!(%q{ SIZET2NUM(rb_cArray) })
- def C.rb_cFalseClass = Primitive.cexpr!(%q{ SIZET2NUM(rb_cFalseClass) })
- def C.rb_cFloat = Primitive.cexpr!(%q{ SIZET2NUM(rb_cFloat) })
- def C.rb_cInteger = Primitive.cexpr!(%q{ SIZET2NUM(rb_cInteger) })
- def C.rb_cNilClass = Primitive.cexpr!(%q{ SIZET2NUM(rb_cNilClass) })
- def C.rb_cString = Primitive.cexpr!(%q{ SIZET2NUM(rb_cString) })
- def C.rb_cSymbol = Primitive.cexpr!(%q{ SIZET2NUM(rb_cSymbol) })
- def C.rb_cTrueClass = Primitive.cexpr!(%q{ SIZET2NUM(rb_cTrueClass) })
- def C.rb_mRubyVMFrozenCore = Primitive.cexpr!(%q{ SIZET2NUM(rb_mRubyVMFrozenCore) })
- def C.rb_rjit_global_events = Primitive.cexpr!(%q{ SIZET2NUM(rb_rjit_global_events) })
- def C.rb_vm_insns_count = Primitive.cexpr!(%q{ SIZET2NUM(rb_vm_insns_count) })
-
- def C.rb_ary_clear
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_clear) }
- end
-
- def C.rb_ary_dup
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_dup) }
- end
-
- def C.rb_ary_entry_internal
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_entry_internal) }
- end
-
- def C.rb_ary_push
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_push) }
- end
-
- def C.rb_ary_resurrect
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_resurrect) }
- end
-
- def C.rb_ary_store
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_store) }
- end
-
- def C.rb_ary_tmp_new_from_values
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_tmp_new_from_values) }
- end
-
- def C.rb_ary_unshift_m
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ary_unshift_m) }
- end
-
- def C.rb_backref_get
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_backref_get) }
- end
-
- def C.rb_ec_ary_new_from_values
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ec_ary_new_from_values) }
- end
-
- def C.rb_ec_str_resurrect
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ec_str_resurrect) }
- end
-
- def C.rb_ensure_iv_list_size
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ensure_iv_list_size) }
- end
-
- def C.rb_fix_aref
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_fix_aref) }
- end
-
- def C.rb_fix_div_fix
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_fix_div_fix) }
- end
-
- def C.rb_fix_mod_fix
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_fix_mod_fix) }
- end
-
- def C.rb_fix_mul_fix
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_fix_mul_fix) }
- end
-
- def C.rb_gc_writebarrier
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_gc_writebarrier) }
- end
-
- def C.rb_get_symbol_id
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_get_symbol_id) }
- end
-
- def C.rb_gvar_get
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_gvar_get) }
- end
-
- def C.rb_hash_aref
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_hash_aref) }
- end
-
- def C.rb_hash_aset
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_hash_aset) }
- end
-
- def C.rb_hash_bulk_insert
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_hash_bulk_insert) }
- end
-
- def C.rb_hash_new
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_hash_new) }
- end
-
- def C.rb_hash_new_with_size
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_hash_new_with_size) }
- end
-
- def C.rb_hash_resurrect
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_hash_resurrect) }
- end
-
- def C.rb_ivar_defined
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ivar_defined) }
- end
-
- def C.rb_ivar_get
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_ivar_get) }
- end
-
- def C.rb_obj_as_string_result
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_obj_as_string_result) }
- end
-
- def C.rb_obj_is_kind_of
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_obj_is_kind_of) }
- end
-
- def C.rb_range_new
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_range_new) }
- end
-
- def C.rb_reg_last_match
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_reg_last_match) }
- end
-
- def C.rb_reg_match_last
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_reg_match_last) }
- end
-
- def C.rb_reg_match_post
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_reg_match_post) }
- end
-
- def C.rb_reg_match_pre
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_reg_match_pre) }
- end
-
- def C.rb_reg_new_ary
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_reg_new_ary) }
- end
-
- def C.rb_reg_nth_match
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_reg_nth_match) }
- end
-
- def C.rb_rjit_branch_stub_hit
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_rjit_branch_stub_hit) }
- end
-
- def C.rb_rjit_entry_stub_hit
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_rjit_entry_stub_hit) }
- end
-
- def C.rb_str_buf_append
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_buf_append) }
- end
-
- def C.rb_str_bytesize
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_bytesize) }
- end
-
- def C.rb_str_concat_literals
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_concat_literals) }
- end
-
- def C.rb_str_dup
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_dup) }
- end
-
- def C.rb_str_eql_internal
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_eql_internal) }
- end
-
- def C.rb_str_getbyte
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_getbyte) }
- end
-
- def C.rb_str_intern
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_str_intern) }
- end
-
- def C.rb_sym_to_proc
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_sym_to_proc) }
- end
-
- def C.rb_vm_bh_to_procval
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_bh_to_procval) }
- end
-
- def C.rb_vm_concat_array
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_concat_array) }
- end
-
- def C.rb_vm_defined
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_defined) }
- end
-
- def C.rb_vm_get_ev_const
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_get_ev_const) }
- end
-
- def C.rb_vm_getclassvariable
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_getclassvariable) }
- end
-
- def C.rb_vm_ic_hit_p
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_ic_hit_p) }
- end
-
- def C.rb_vm_opt_newarray_hash
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_opt_newarray_hash) }
- end
-
- def C.rb_vm_opt_newarray_max
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_opt_newarray_max) }
- end
-
- def C.rb_vm_opt_newarray_min
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_opt_newarray_min) }
- end
-
- def C.rb_vm_opt_newarray_pack
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_opt_newarray_pack) }
- end
-
- def C.rb_vm_set_ivar_id
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_set_ivar_id) }
- end
-
- def C.rb_vm_setclassvariable
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_setclassvariable) }
- end
-
- def C.rb_vm_setinstancevariable
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_setinstancevariable) }
- end
-
- def C.rb_vm_splat_array
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_splat_array) }
- end
-
- def C.rb_vm_throw
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_throw) }
- end
-
- def C.rb_vm_yield_with_cfunc
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_yield_with_cfunc) }
- end
-
- def C.rjit_build_kwhash
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_build_kwhash) }
- end
-
- def C.rjit_full_cfunc_return
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_full_cfunc_return) }
- end
-
- def C.rjit_optimized_call
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_optimized_call) }
- end
-
- def C.rjit_rb_ary_subseq_length
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_rb_ary_subseq_length) }
- end
-
- def C.rjit_record_exit_stack
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_record_exit_stack) }
- end
-
- def C.rjit_str_neq_internal
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_str_neq_internal) }
- end
-
- def C.rjit_str_simple_append
- Primitive.cexpr! %q{ SIZET2NUM((size_t)rjit_str_simple_append) }
- end
-
- def C.CALL_DATA
- @CALL_DATA ||= self.rb_call_data
- end
-
- def C.IC
- @IC ||= self.iseq_inline_constant_cache
- end
-
- def C.ID
- @ID ||= CType::Immediate.parse("unsigned long")
- end
-
- def C.IVC
- @IVC ||= self.iseq_inline_iv_cache_entry
- end
-
- def C.RArray
- @RArray ||= CType::Struct.new(
- "RArray", Primitive.cexpr!("SIZEOF(struct RArray)"),
- basic: [self.RBasic, Primitive.cexpr!("OFFSETOF((*((struct RArray *)NULL)), basic)")],
- as: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct RArray *)NULL)->as)"),
- heap: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct RArray *)NULL)->as.heap)"),
- len: [CType::Immediate.parse("long"), Primitive.cexpr!("OFFSETOF(((struct RArray *)NULL)->as.heap, len)")],
- aux: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct RArray *)NULL)->as.heap.aux)"),
- capa: CType::Immediate.parse("long"),
- shared_root: self.VALUE,
- ), Primitive.cexpr!("OFFSETOF(((struct RArray *)NULL)->as.heap, aux)")],
- ptr: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct RArray *)NULL)->as.heap, ptr)")],
- ),
- ary: CType::Array.new { self.VALUE },
- ), Primitive.cexpr!("OFFSETOF((*((struct RArray *)NULL)), as)")],
- )
- end
-
- def C.RB_BUILTIN
- @RB_BUILTIN ||= self.rb_builtin_function
- end
-
- def C.RBasic
- @RBasic ||= CType::Struct.new(
- "RBasic", Primitive.cexpr!("SIZEOF(struct RBasic)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct RBasic *)NULL)), flags)")],
- klass: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct RBasic *)NULL)), klass)")],
- )
- end
-
- def C.RObject
- @RObject ||= CType::Struct.new(
- "RObject", Primitive.cexpr!("SIZEOF(struct RObject)"),
- basic: [self.RBasic, Primitive.cexpr!("OFFSETOF((*((struct RObject *)NULL)), basic)")],
- as: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct RObject *)NULL)->as)"),
- heap: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct RObject *)NULL)->as.heap)"),
- ivptr: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct RObject *)NULL)->as.heap, ivptr)")],
- iv_index_tbl: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF(((struct RObject *)NULL)->as.heap, iv_index_tbl)")],
- ),
- ary: CType::Array.new { self.VALUE },
- ), Primitive.cexpr!("OFFSETOF((*((struct RObject *)NULL)), as)")],
- )
- end
-
- def C.RString
- @RString ||= CType::Struct.new(
- "RString", Primitive.cexpr!("SIZEOF(struct RString)"),
- basic: [self.RBasic, Primitive.cexpr!("OFFSETOF((*((struct RString *)NULL)), basic)")],
- len: [CType::Immediate.parse("long"), Primitive.cexpr!("OFFSETOF((*((struct RString *)NULL)), len)")],
- as: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct RString *)NULL)->as)"),
- heap: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct RString *)NULL)->as.heap)"),
- ptr: [CType::Pointer.new { CType::Immediate.parse("char") }, Primitive.cexpr!("OFFSETOF(((struct RString *)NULL)->as.heap, ptr)")],
- aux: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct RString *)NULL)->as.heap.aux)"),
- capa: CType::Immediate.parse("long"),
- shared: self.VALUE,
- ), Primitive.cexpr!("OFFSETOF(((struct RString *)NULL)->as.heap, aux)")],
- ),
- embed: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct RString *)NULL)->as.embed)"),
- ary: [CType::Array.new { CType::Immediate.parse("char") }, Primitive.cexpr!("OFFSETOF(((struct RString *)NULL)->as.embed, ary)")],
- ),
- ), Primitive.cexpr!("OFFSETOF((*((struct RString *)NULL)), as)")],
- )
- end
-
- def C.RStruct
- @RStruct ||= CType::Struct.new(
- "RStruct", Primitive.cexpr!("SIZEOF(struct RStruct)"),
- basic: [self.RBasic, Primitive.cexpr!("OFFSETOF((*((struct RStruct *)NULL)), basic)")],
- as: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct RStruct *)NULL)->as)"),
- heap: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct RStruct *)NULL)->as.heap)"),
- len: [CType::Immediate.parse("long"), Primitive.cexpr!("OFFSETOF(((struct RStruct *)NULL)->as.heap, len)")],
- ptr: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct RStruct *)NULL)->as.heap, ptr)")],
- ),
- ary: CType::Array.new { self.VALUE },
- ), Primitive.cexpr!("OFFSETOF((*((struct RStruct *)NULL)), as)")],
- )
- end
-
- def C.attr_index_t
- @attr_index_t ||= CType::Immediate.parse("uint32_t")
- end
-
- def C.iseq_inline_constant_cache
- @iseq_inline_constant_cache ||= CType::Struct.new(
- "iseq_inline_constant_cache", Primitive.cexpr!("SIZEOF(struct iseq_inline_constant_cache)"),
- entry: [CType::Pointer.new { self.iseq_inline_constant_cache_entry }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache *)NULL)), entry)")],
- segments: [CType::Pointer.new { self.ID }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache *)NULL)), segments)")],
- )
- end
-
- def C.iseq_inline_constant_cache_entry
- @iseq_inline_constant_cache_entry ||= CType::Struct.new(
- "iseq_inline_constant_cache_entry", Primitive.cexpr!("SIZEOF(struct iseq_inline_constant_cache_entry)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), flags)")],
- value: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), value)")],
- _unused1: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), _unused1)")],
- _unused2: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), _unused2)")],
- ic_cref: [CType::Pointer.new { self.rb_cref_t }, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_constant_cache_entry *)NULL)), ic_cref)")],
- )
- end
-
- def C.iseq_inline_iv_cache_entry
- @iseq_inline_iv_cache_entry ||= CType::Struct.new(
- "iseq_inline_iv_cache_entry", Primitive.cexpr!("SIZEOF(struct iseq_inline_iv_cache_entry)"),
- value: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), value)")],
- iv_set_name: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct iseq_inline_iv_cache_entry *)NULL)), iv_set_name)")],
- )
- end
-
- def C.iseq_inline_storage_entry
- @iseq_inline_storage_entry ||= CType::Union.new(
- "iseq_inline_storage_entry", Primitive.cexpr!("SIZEOF(union iseq_inline_storage_entry)"),
- once: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((union iseq_inline_storage_entry *)NULL)->once)"),
- running_thread: [CType::Pointer.new { self.rb_thread_struct }, Primitive.cexpr!("OFFSETOF(((union iseq_inline_storage_entry *)NULL)->once, running_thread)")],
- value: [self.VALUE, Primitive.cexpr!("OFFSETOF(((union iseq_inline_storage_entry *)NULL)->once, value)")],
- ),
- ic_cache: self.iseq_inline_constant_cache,
- iv_cache: self.iseq_inline_iv_cache_entry,
- )
- end
-
- def C.method_optimized_type
- @method_optimized_type ||= CType::Immediate.parse("int")
- end
-
- def C.rb_block
- @rb_block ||= CType::Struct.new(
- "rb_block", Primitive.cexpr!("SIZEOF(struct rb_block)"),
- as: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_block *)NULL)->as)"),
- captured: self.rb_captured_block,
- symbol: self.VALUE,
- proc: self.VALUE,
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_block *)NULL)), as)")],
- type: [self.rb_block_type, Primitive.cexpr!("OFFSETOF((*((struct rb_block *)NULL)), type)")],
- )
- end
-
- def C.rb_block_type
- @rb_block_type ||= CType::Immediate.parse("int")
- end
-
- def C.rb_builtin_function
- @rb_builtin_function ||= CType::Struct.new(
- "rb_builtin_function", Primitive.cexpr!("SIZEOF(struct rb_builtin_function)"),
- func_ptr: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), func_ptr)")],
- argc: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), argc)")],
- index: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), index)")],
- name: [CType::Pointer.new { CType::Immediate.parse("char") }, Primitive.cexpr!("OFFSETOF((*((struct rb_builtin_function *)NULL)), name)")],
- )
- end
-
- def C.rb_call_data
- @rb_call_data ||= CType::Struct.new(
- "rb_call_data", Primitive.cexpr!("SIZEOF(struct rb_call_data)"),
- ci: [CType::Pointer.new { self.rb_callinfo }, Primitive.cexpr!("OFFSETOF((*((struct rb_call_data *)NULL)), ci)")],
- cc: [CType::Pointer.new { self.rb_callcache }, Primitive.cexpr!("OFFSETOF((*((struct rb_call_data *)NULL)), cc)")],
- )
- end
-
- def C.rb_callable_method_entry_struct
- @rb_callable_method_entry_struct ||= CType::Struct.new(
- "rb_callable_method_entry_struct", Primitive.cexpr!("SIZEOF(struct rb_callable_method_entry_struct)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), flags)")],
- defined_class: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), defined_class)"), true],
- def: [CType::Pointer.new { self.rb_method_definition_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), def)")],
- called_id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), called_id)")],
- owner: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), owner)")],
- )
- end
-
- def C.rb_callable_method_entry_t
- @rb_callable_method_entry_t ||= CType::Struct.new(
- "rb_callable_method_entry_struct", Primitive.cexpr!("SIZEOF(struct rb_callable_method_entry_struct)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), flags)")],
- defined_class: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), defined_class)"), true],
- def: [CType::Pointer.new { self.rb_method_definition_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), def)")],
- called_id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), called_id)")],
- owner: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callable_method_entry_struct *)NULL)), owner)")],
- )
- end
-
- def C.rb_callcache
- @rb_callcache ||= CType::Struct.new(
- "rb_callcache", Primitive.cexpr!("SIZEOF(struct rb_callcache)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), flags)")],
- klass: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), klass)")],
- cme_: [CType::Pointer.new { self.rb_callable_method_entry_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), cme_)")],
- call_: [self.vm_call_handler, Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), call_)")],
- aux_: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_callcache *)NULL)->aux_)"),
- attr: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_callcache *)NULL)->aux_.attr)"),
- value: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF(((struct rb_callcache *)NULL)->aux_.attr, value)")],
- ),
- method_missing_reason: self.method_missing_reason,
- v: self.VALUE,
- bf: CType::Pointer.new { self.rb_builtin_function },
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_callcache *)NULL)), aux_)")],
- )
- end
-
- def C.rb_callinfo
- @rb_callinfo ||= CType::Struct.new(
- "rb_callinfo", Primitive.cexpr!("SIZEOF(struct rb_callinfo)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), flags)")],
- kwarg: [CType::Pointer.new { self.rb_callinfo_kwarg }, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), kwarg)")],
- mid: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), mid)")],
- flag: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), flag)")],
- argc: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo *)NULL)), argc)")],
- )
- end
-
- def C.rb_callinfo_kwarg
- @rb_callinfo_kwarg ||= CType::Struct.new(
- "rb_callinfo_kwarg", Primitive.cexpr!("SIZEOF(struct rb_callinfo_kwarg)"),
- keyword_len: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo_kwarg *)NULL)), keyword_len)")],
- references: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo_kwarg *)NULL)), references)")],
- keywords: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_callinfo_kwarg *)NULL)), keywords)")],
- )
- end
-
- def C.rb_captured_block
- @rb_captured_block ||= CType::Struct.new(
- "rb_captured_block", Primitive.cexpr!("SIZEOF(struct rb_captured_block)"),
- self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_captured_block *)NULL)), self)")],
- ep: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_captured_block *)NULL)), ep)")],
- code: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_captured_block *)NULL)->code)"),
- iseq: CType::Pointer.new { self.rb_iseq_t },
- ifunc: CType::Pointer.new { self.vm_ifunc },
- val: self.VALUE,
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_captured_block *)NULL)), code)")],
- )
- end
-
- def C.rb_cfunc_t
- @rb_cfunc_t ||= self.VALUE
- end
-
- def C.rb_control_frame_t
- @rb_control_frame_t ||= CType::Struct.new(
- "rb_control_frame_struct", Primitive.cexpr!("SIZEOF(struct rb_control_frame_struct)"),
- pc: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), pc)")],
- sp: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), sp)")],
- iseq: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), iseq)")],
- self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), self)")],
- ep: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), ep)")],
- block_code: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), block_code)")],
- jit_return: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_control_frame_struct *)NULL)), jit_return)")],
- )
- end
-
- def C.rb_cref_t
- @rb_cref_t ||= CType::Struct.new(
- "rb_cref_struct", Primitive.cexpr!("SIZEOF(struct rb_cref_struct)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), flags)")],
- refinements: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), refinements)")],
- klass_or_self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), klass_or_self)")],
- next: [CType::Pointer.new { self.rb_cref_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), next)")],
- scope_visi: [self.rb_scope_visibility_t, Primitive.cexpr!("OFFSETOF((*((struct rb_cref_struct *)NULL)), scope_visi)")],
- )
- end
-
- def C.rb_execution_context_struct
- @rb_execution_context_struct ||= CType::Struct.new(
- "rb_execution_context_struct", Primitive.cexpr!("SIZEOF(struct rb_execution_context_struct)"),
- vm_stack: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), vm_stack)")],
- vm_stack_size: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), vm_stack_size)")],
- cfp: [CType::Pointer.new { self.rb_control_frame_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), cfp)")],
- tag: [CType::Pointer.new { self.rb_vm_tag }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), tag)")],
- interrupt_flag: [self.rb_atomic_t, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), interrupt_flag)")],
- interrupt_mask: [self.rb_atomic_t, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), interrupt_mask)")],
- fiber_ptr: [CType::Pointer.new { self.rb_fiber_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), fiber_ptr)")],
- thread_ptr: [CType::Pointer.new { self.rb_thread_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), thread_ptr)")],
- local_storage: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), local_storage)")],
- local_storage_recursive_hash: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), local_storage_recursive_hash)")],
- local_storage_recursive_hash_for_trace: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), local_storage_recursive_hash_for_trace)")],
- storage: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), storage)")],
- root_lep: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), root_lep)")],
- root_svar: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), root_svar)")],
- trace_arg: [CType::Pointer.new { self.rb_trace_arg_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), trace_arg)")],
- errinfo: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), errinfo)")],
- passed_block_handler: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), passed_block_handler)")],
- raised_flag: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), raised_flag)")],
- private_const_reference: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), private_const_reference)")],
- machine: [CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_execution_context_struct *)NULL)->machine)"),
- stack_start: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_start)")],
- stack_end: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_end)")],
- stack_maxsize: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF(((struct rb_execution_context_struct *)NULL)->machine, stack_maxsize)")],
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_execution_context_struct *)NULL)), machine)")],
- )
- end
-
- def C.rb_execution_context_t
- @rb_execution_context_t ||= self.rb_execution_context_struct
- end
-
- def C.rb_iseq_constant_body
- @rb_iseq_constant_body ||= CType::Struct.new(
- "rb_iseq_constant_body", Primitive.cexpr!("SIZEOF(struct rb_iseq_constant_body)"),
- type: [self.rb_iseq_type, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), type)")],
- iseq_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), iseq_size)")],
- iseq_encoded: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), iseq_encoded)")],
- param: [CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->param)"),
- flags: [CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->param.flags)"),
- has_lead: [CType::BitField.new(1, 0), 0],
- has_opt: [CType::BitField.new(1, 1), 1],
- has_rest: [CType::BitField.new(1, 2), 2],
- has_post: [CType::BitField.new(1, 3), 3],
- has_kw: [CType::BitField.new(1, 4), 4],
- has_kwrest: [CType::BitField.new(1, 5), 5],
- has_block: [CType::BitField.new(1, 6), 6],
- ambiguous_param0: [CType::BitField.new(1, 7), 7],
- accepts_no_kwarg: [CType::BitField.new(1, 0), 8],
- ruby2_keywords: [CType::BitField.new(1, 1), 9],
- anon_rest: [CType::BitField.new(1, 2), 10],
- anon_kwrest: [CType::BitField.new(1, 3), 11],
- use_block: [CType::BitField.new(1, 4), 12],
- forwardable: [CType::BitField.new(1, 5), 13],
- ), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, flags)")],
- size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, size)")],
- lead_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, lead_num)")],
- opt_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, opt_num)")],
- rest_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, rest_start)")],
- post_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, post_start)")],
- post_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, post_num)")],
- block_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, block_start)")],
- opt_table: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, opt_table)")],
- keyword: [CType::Pointer.new { self.rb_iseq_param_keyword }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->param, keyword)")],
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), param)")],
- location: [self.rb_iseq_location_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), location)")],
- insns_info: [self.iseq_insn_info, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), insns_info)")],
- local_table: [CType::Pointer.new { self.ID }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), local_table)")],
- catch_table: [CType::Pointer.new { self.iseq_catch_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), catch_table)")],
- parent_iseq: [CType::Pointer.new { self.rb_iseq_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), parent_iseq)")],
- local_iseq: [CType::Pointer.new { self.rb_iseq_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), local_iseq)")],
- is_entries: [CType::Pointer.new { self.iseq_inline_storage_entry }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), is_entries)")],
- call_data: [CType::Pointer.new { self.rb_call_data }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), call_data)")],
- variable: [CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->variable)"),
- flip_count: [self.rb_snum_t, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, flip_count)")],
- script_lines: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, script_lines)")],
- coverage: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, coverage)")],
- pc2branchindex: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, pc2branchindex)")],
- original_iseq: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_constant_body *)NULL)->variable, original_iseq)")],
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), variable)")],
- local_table_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), local_table_size)")],
- ic_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ic_size)")],
- ise_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ise_size)")],
- ivc_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ivc_size)")],
- icvarc_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), icvarc_size)")],
- ci_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ci_size)")],
- stack_max: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), stack_max)")],
- builtin_attrs: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), builtin_attrs)")],
- prism: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), prism)")],
- mark_bits: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->mark_bits)"),
- list: CType::Pointer.new { self.iseq_bits_t },
- single: self.iseq_bits_t,
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), mark_bits)")],
- outer_variables: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), outer_variables)")],
- mandatory_only_iseq: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), mandatory_only_iseq)")],
- jit_entry: [self.rb_jit_func_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), jit_entry)")],
- jit_entry_calls: [CType::Immediate.parse("unsigned long"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), jit_entry_calls)")],
- rjit_blocks: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), rjit_blocks)"), true],
- )
- end
-
- def C.rb_iseq_location_t
- @rb_iseq_location_t ||= CType::Struct.new(
- "rb_iseq_location_struct", Primitive.cexpr!("SIZEOF(struct rb_iseq_location_struct)"),
- pathobj: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), pathobj)"), true],
- base_label: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), base_label)"), true],
- label: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), label)"), true],
- first_lineno: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), first_lineno)")],
- node_id: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), node_id)")],
- code_location: [self.rb_code_location_t, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_location_struct *)NULL)), code_location)")],
- )
- end
-
- def C.rb_iseq_param_keyword
- @rb_iseq_param_keyword ||= CType::Struct.new(
- "rb_iseq_param_keyword", Primitive.cexpr!("SIZEOF(struct rb_iseq_param_keyword)"),
- num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), num)")],
- required_num: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), required_num)")],
- bits_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), bits_start)")],
- rest_start: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), rest_start)")],
- table: [CType::Pointer.new { self.ID }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), table)")],
- default_values: [CType::Pointer.new { self.VALUE }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_param_keyword *)NULL)), default_values)")],
- )
- end
-
- def C.rb_iseq_struct
- @rb_iseq_struct ||= CType::Struct.new(
- "rb_iseq_struct", Primitive.cexpr!("SIZEOF(struct rb_iseq_struct)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), flags)")],
- wrapper: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), wrapper)")],
- body: [CType::Pointer.new { self.rb_iseq_constant_body }, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), body)")],
- aux: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_struct *)NULL)->aux)"),
- compile_data: CType::Pointer.new { self.iseq_compile_data },
- loader: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_struct *)NULL)->aux.loader)"),
- obj: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.loader, obj)")],
- index: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.loader, index)")],
- ),
- exec: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_iseq_struct *)NULL)->aux.exec)"),
- local_hooks: [CType::Pointer.new { self.rb_hook_list_struct }, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.exec, local_hooks)")],
- global_trace_events: [self.rb_event_flag_t, Primitive.cexpr!("OFFSETOF(((struct rb_iseq_struct *)NULL)->aux.exec, global_trace_events)")],
- ),
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_struct *)NULL)), aux)")],
- )
- end
-
- def C.rb_iseq_t
- @rb_iseq_t ||= self.rb_iseq_struct
- end
-
- def C.rb_jit_func_t
- @rb_jit_func_t ||= CType::Immediate.parse("void *")
- end
-
- def C.rb_method_attr_t
- @rb_method_attr_t ||= CType::Struct.new(
- "rb_method_attr_struct", Primitive.cexpr!("SIZEOF(struct rb_method_attr_struct)"),
- id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_method_attr_struct *)NULL)), id)")],
- location: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_attr_struct *)NULL)), location)")],
- )
- end
-
- def C.rb_method_bmethod_t
- @rb_method_bmethod_t ||= CType::Struct.new(
- "rb_method_bmethod_struct", Primitive.cexpr!("SIZEOF(struct rb_method_bmethod_struct)"),
- proc: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_bmethod_struct *)NULL)), proc)")],
- hooks: [CType::Pointer.new { self.rb_hook_list_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_method_bmethod_struct *)NULL)), hooks)")],
- defined_ractor: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_bmethod_struct *)NULL)), defined_ractor)")],
- )
- end
-
- def C.rb_method_cfunc_t
- @rb_method_cfunc_t ||= CType::Struct.new(
- "rb_method_cfunc_struct", Primitive.cexpr!("SIZEOF(struct rb_method_cfunc_struct)"),
- func: [self.rb_cfunc_t, Primitive.cexpr!("OFFSETOF((*((struct rb_method_cfunc_struct *)NULL)), func)")],
- invoker: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF((*((struct rb_method_cfunc_struct *)NULL)), invoker)")],
- argc: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF((*((struct rb_method_cfunc_struct *)NULL)), argc)")],
- )
- end
-
- def C.rb_method_definition_struct
- @rb_method_definition_struct ||= CType::Struct.new(
- "rb_method_definition_struct", Primitive.cexpr!("SIZEOF(struct rb_method_definition_struct)"),
- type: [CType::BitField.new(4, 0), 0],
- iseq_overload: [CType::BitField.new(1, 4), 4],
- no_redef_warning: [CType::BitField.new(1, 5), 5],
- aliased: [CType::BitField.new(1, 6), 6],
- reference_count: [CType::BitField.new(28, 0), 32],
- body: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_method_definition_struct *)NULL)->body)"),
- iseq: self.rb_method_iseq_t,
- cfunc: self.rb_method_cfunc_t,
- attr: self.rb_method_attr_t,
- alias: self.rb_method_alias_t,
- refined: self.rb_method_refined_t,
- bmethod: self.rb_method_bmethod_t,
- optimized: self.rb_method_optimized_t,
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_method_definition_struct *)NULL)), body)")],
- original_id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_method_definition_struct *)NULL)), original_id)")],
- method_serial: [CType::Immediate.parse("uintptr_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_method_definition_struct *)NULL)), method_serial)")],
- )
- end
-
- def C.rb_method_entry_t
- @rb_method_entry_t ||= CType::Struct.new(
- "rb_method_entry_struct", Primitive.cexpr!("SIZEOF(struct rb_method_entry_struct)"),
- flags: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), flags)")],
- defined_class: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), defined_class)")],
- def: [CType::Pointer.new { self.rb_method_definition_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), def)")],
- called_id: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), called_id)")],
- owner: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_method_entry_struct *)NULL)), owner)")],
- )
- end
-
- def C.rb_method_iseq_t
- @rb_method_iseq_t ||= CType::Struct.new(
- "rb_method_iseq_struct", Primitive.cexpr!("SIZEOF(struct rb_method_iseq_struct)"),
- iseqptr: [CType::Pointer.new { self.rb_iseq_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_method_iseq_struct *)NULL)), iseqptr)")],
- cref: [CType::Pointer.new { self.rb_cref_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_method_iseq_struct *)NULL)), cref)")],
- )
- end
-
- def C.rb_method_optimized_t
- @rb_method_optimized_t ||= CType::Struct.new(
- "rb_method_optimized", Primitive.cexpr!("SIZEOF(struct rb_method_optimized)"),
- type: [self.method_optimized_type, Primitive.cexpr!("OFFSETOF((*((struct rb_method_optimized *)NULL)), type)")],
- index: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_method_optimized *)NULL)), index)")],
- )
- end
-
- def C.rb_method_type_t
- @rb_method_type_t ||= CType::Immediate.parse("int")
- end
-
- def C.rb_proc_t
- @rb_proc_t ||= CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(rb_proc_t)"),
- block: [self.rb_block, Primitive.cexpr!("OFFSETOF((*((rb_proc_t *)NULL)), block)")],
- )
- end
-
- def C.rb_rjit_options
- @rb_rjit_options ||= CType::Struct.new(
- "rb_rjit_options", Primitive.cexpr!("SIZEOF(struct rb_rjit_options)"),
- on: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), on)")],
- exec_mem_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), exec_mem_size)")],
- call_threshold: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), call_threshold)")],
- stats: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), stats)")],
- disable: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), disable)")],
- trace: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), trace)")],
- trace_exits: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), trace_exits)")],
- dump_disasm: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), dump_disasm)")],
- verify_ctx: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_options *)NULL)), verify_ctx)")],
- )
- end
-
- def C.rb_rjit_runtime_counters
- @rb_rjit_runtime_counters ||= CType::Struct.new(
- "rb_rjit_runtime_counters", Primitive.cexpr!("SIZEOF(struct rb_rjit_runtime_counters)"),
- rjit_insns_count: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), rjit_insns_count)")],
- send_args_splat_kw_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_kw_splat)")],
- send_args_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat)")],
- send_args_splat_not_array: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_not_array)")],
- send_args_splat_length_not_equal: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_length_not_equal)")],
- send_args_splat_cfunc_var_args: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_cfunc_var_args)")],
- send_args_splat_arity_error: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_arity_error)")],
- send_args_splat_ruby2_hash: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_ruby2_hash)")],
- send_args_splat_cfunc_zuper: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_cfunc_zuper)")],
- send_args_splat_cfunc_ruby2_keywords: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_args_splat_cfunc_ruby2_keywords)")],
- send_kw_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_kw_splat)")],
- send_kwarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_kwarg)")],
- send_klass_megamorphic: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_klass_megamorphic)")],
- send_missing_cme: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_missing_cme)")],
- send_private: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_private)")],
- send_protected_check_failed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_protected_check_failed)")],
- send_tailcall: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_tailcall)")],
- send_notimplemented: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_notimplemented)")],
- send_missing: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_missing)")],
- send_bmethod: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_bmethod)")],
- send_alias: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_alias)")],
- send_undef: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_undef)")],
- send_zsuper: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_zsuper)")],
- send_refined: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_refined)")],
- send_stackoverflow: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_stackoverflow)")],
- send_arity: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_arity)")],
- send_c_tracing: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_c_tracing)")],
- send_is_a_class_mismatch: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_is_a_class_mismatch)")],
- send_instance_of_class_mismatch: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_instance_of_class_mismatch)")],
- send_keywords: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_keywords)")],
- send_blockiseq: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_blockiseq)")],
- send_block_handler: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_block_handler)")],
- send_block_setup: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_block_setup)")],
- send_block_not_nil: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_block_not_nil)")],
- send_block_not_proxy: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_block_not_proxy)")],
- send_block_arg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_block_arg)")],
- send_iseq_kwparam: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_kwparam)")],
- send_iseq_accepts_no_kwarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_accepts_no_kwarg)")],
- send_iseq_has_opt: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_opt)")],
- send_iseq_has_kwrest: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_kwrest)")],
- send_iseq_ruby2_keywords: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_ruby2_keywords)")],
- send_iseq_has_rest_and_captured: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_rest_and_captured)")],
- send_iseq_has_rest_and_kw_supplied: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_rest_and_kw_supplied)")],
- send_iseq_has_no_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_no_kw)")],
- send_iseq_zsuper: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_zsuper)")],
- send_iseq_materialized_block: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_materialized_block)")],
- send_iseq_has_rest: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_rest)")],
- send_iseq_block_arg0_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_block_arg0_splat)")],
- send_iseq_kw_call: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_kw_call)")],
- send_iseq_kw_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_kw_splat)")],
- send_iseq_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_splat)")],
- send_iseq_has_rest_and_optional: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_rest_and_optional)")],
- send_iseq_arity_error: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_arity_error)")],
- send_iseq_missing_optional_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_missing_optional_kw)")],
- send_iseq_too_many_kwargs: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_too_many_kwargs)")],
- send_iseq_kwargs_mismatch: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_kwargs_mismatch)")],
- send_iseq_splat_with_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_splat_with_kw)")],
- send_iseq_splat_arity_error: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_splat_arity_error)")],
- send_iseq_has_rest_and_splat_not_equal: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_iseq_has_rest_and_splat_not_equal)")],
- send_cfunc_variadic: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_variadic)")],
- send_cfunc_too_many_args: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_too_many_args)")],
- send_cfunc_ruby_array_varg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_ruby_array_varg)")],
- send_cfunc_splat_with_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_splat_with_kw)")],
- send_cfunc_tracing: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_tracing)")],
- send_cfunc_argc_mismatch: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_argc_mismatch)")],
- send_cfunc_toomany_args: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_cfunc_toomany_args)")],
- send_attrset_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_attrset_splat)")],
- send_attrset_kwarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_attrset_kwarg)")],
- send_attrset_method: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_attrset_method)")],
- send_ivar_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_ivar_splat)")],
- send_ivar_opt_send: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_ivar_opt_send)")],
- send_optimized_send_no_args: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_send_no_args)")],
- send_optimized_send_not_sym_or_str: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_send_not_sym_or_str)")],
- send_optimized_send_mid_class_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_send_mid_class_changed)")],
- send_optimized_send_mid_id_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_send_mid_id_changed)")],
- send_optimized_send_null_mid: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_send_null_mid)")],
- send_optimized_send_send: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_send_send)")],
- send_optimized_call_block: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_call_block)")],
- send_optimized_call_kwarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_call_kwarg)")],
- send_optimized_call_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_call_splat)")],
- send_optimized_struct_aref_error: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_struct_aref_error)")],
- send_optimized_block_call: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_block_call)")],
- send_optimized_struct_aset: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_optimized_struct_aset)")],
- send_bmethod_not_iseq: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_bmethod_not_iseq)")],
- send_bmethod_blockarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), send_bmethod_blockarg)")],
- invokesuper_me_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokesuper_me_changed)")],
- invokesuper_block: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokesuper_block)")],
- invokeblock_none: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_none)")],
- invokeblock_symbol: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_symbol)")],
- invokeblock_proc: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_proc)")],
- invokeblock_tag_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_tag_changed)")],
- invokeblock_iseq_block_changed: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_iseq_block_changed)")],
- invokeblock_iseq_arity: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_iseq_arity)")],
- invokeblock_iseq_arg0_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_iseq_arg0_splat)")],
- invokeblock_ifunc_args_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_ifunc_args_splat)")],
- invokeblock_ifunc_kw_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_ifunc_kw_splat)")],
- invokeblock_iseq_arg0_args_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_iseq_arg0_args_splat)")],
- invokeblock_iseq_arg0_has_kw: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), invokeblock_iseq_arg0_has_kw)")],
- getivar_megamorphic: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_megamorphic)")],
- getivar_not_heap: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_not_heap)")],
- getivar_special_const: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_special_const)")],
- getivar_too_complex: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getivar_too_complex)")],
- optaref_arg_not_fixnum: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optaref_arg_not_fixnum)")],
- optaref_argc_not_one: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optaref_argc_not_one)")],
- optaref_recv_not_array: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optaref_recv_not_array)")],
- optaref_recv_not_hash: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optaref_recv_not_hash)")],
- optaref_send: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optaref_send)")],
- optgetconst_not_cached: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optgetconst_not_cached)")],
- optgetconst_cref: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optgetconst_cref)")],
- optgetconst_cache_miss: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), optgetconst_cache_miss)")],
- setivar_frozen: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), setivar_frozen)")],
- setivar_not_heap: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), setivar_not_heap)")],
- setivar_megamorphic: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), setivar_megamorphic)")],
- setivar_too_complex: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), setivar_too_complex)")],
- expandarray_splat: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), expandarray_splat)")],
- expandarray_postarg: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), expandarray_postarg)")],
- expandarray_not_array: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), expandarray_not_array)")],
- expandarray_rhs_too_small: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), expandarray_rhs_too_small)")],
- getblockpp_block_param_modified: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getblockpp_block_param_modified)")],
- getblockpp_block_handler_none: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getblockpp_block_handler_none)")],
- getblockpp_not_gc_guarded: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getblockpp_not_gc_guarded)")],
- getblockpp_not_iseq_block: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), getblockpp_not_iseq_block)")],
- compiled_block_count: [CType::Immediate.parse("size_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_rjit_runtime_counters *)NULL)), compiled_block_count)")],
- )
- end
-
- def C.rb_serial_t
- @rb_serial_t ||= CType::Immediate.parse("unsigned long long")
- end
-
- def C.rb_shape
- @rb_shape ||= CType::Struct.new(
- "rb_shape", Primitive.cexpr!("SIZEOF(struct rb_shape)"),
- edges: [CType::Pointer.new { self.rb_id_table }, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), edges)")],
- edge_name: [self.ID, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), edge_name)")],
- next_iv_index: [self.attr_index_t, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), next_iv_index)")],
- capacity: [CType::Immediate.parse("uint32_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), capacity)")],
- type: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), type)")],
- heap_index: [CType::Immediate.parse("uint8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), heap_index)")],
- parent_id: [self.shape_id_t, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), parent_id)")],
- ancestor_index: [CType::Pointer.new { self.redblack_node_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_shape *)NULL)), ancestor_index)")],
- )
- end
-
- def C.rb_shape_t
- @rb_shape_t ||= self.rb_shape
- end
-
- def C.rb_thread_struct
- @rb_thread_struct ||= CType::Struct.new(
- "rb_thread_struct", Primitive.cexpr!("SIZEOF(struct rb_thread_struct)"),
- lt_node: [self.ccan_list_node, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), lt_node)")],
- self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), self)")],
- ractor: [CType::Pointer.new { self.rb_ractor_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), ractor)")],
- vm: [CType::Pointer.new { self.rb_vm_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), vm)")],
- nt: [CType::Pointer.new { self.rb_native_thread }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), nt)")],
- ec: [CType::Pointer.new { self.rb_execution_context_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), ec)")],
- sched: [self.rb_thread_sched_item, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), sched)")],
- mn_schedulable: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), mn_schedulable)")],
- serial: [self.rb_atomic_t, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), serial)")],
- last_status: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), last_status)")],
- calling: [CType::Pointer.new { self.rb_calling_info }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), calling)")],
- top_self: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), top_self)")],
- top_wrapper: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), top_wrapper)")],
- priority: [CType::Immediate.parse("int8_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), priority)")],
- running_time_us: [CType::Immediate.parse("uint32_t"), Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), running_time_us)")],
- blocking_region_buffer: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), blocking_region_buffer)")],
- thgroup: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), thgroup)")],
- value: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), value)")],
- pending_interrupt_queue: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), pending_interrupt_queue)")],
- pending_interrupt_mask_stack: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), pending_interrupt_mask_stack)")],
- interrupt_lock: [self.rb_nativethread_lock_t, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), interrupt_lock)")],
- unblock: [self.rb_unblock_callback, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), unblock)")],
- locking_mutex: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), locking_mutex)")],
- keeping_mutexes: [CType::Pointer.new { self.rb_mutex_struct }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), keeping_mutexes)")],
- join_list: [CType::Pointer.new { self.rb_waiting_list }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), join_list)")],
- invoke_arg: [CType::Union.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_thread_struct *)NULL)->invoke_arg)"),
- proc: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_thread_struct *)NULL)->invoke_arg.proc)"),
- proc: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_thread_struct *)NULL)->invoke_arg.proc, proc)")],
- args: [self.VALUE, Primitive.cexpr!("OFFSETOF(((struct rb_thread_struct *)NULL)->invoke_arg.proc, args)")],
- kw_splat: [CType::Immediate.parse("int"), Primitive.cexpr!("OFFSETOF(((struct rb_thread_struct *)NULL)->invoke_arg.proc, kw_splat)")],
- ),
- func: CType::Struct.new(
- "", Primitive.cexpr!("SIZEOF(((struct rb_thread_struct *)NULL)->invoke_arg.func)"),
- func: [CType::Immediate.parse("void *"), Primitive.cexpr!("OFFSETOF(((struct rb_thread_struct *)NULL)->invoke_arg.func, func)")],
- arg: [CType::Pointer.new { CType::Immediate.parse("void") }, Primitive.cexpr!("OFFSETOF(((struct rb_thread_struct *)NULL)->invoke_arg.func, arg)")],
- ),
- ), Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), invoke_arg)")],
- invoke_type: [self.thread_invoke_type, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), invoke_type)")],
- stat_insn_usage: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), stat_insn_usage)")],
- root_fiber: [CType::Pointer.new { self.rb_fiber_t }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), root_fiber)")],
- scheduler: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), scheduler)")],
- blocking: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), blocking)")],
- name: [self.VALUE, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), name)")],
- specific_storage: [CType::Pointer.new { CType::Pointer.new { CType::Immediate.parse("void") } }, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), specific_storage)")],
- ext_config: [self.rb_ext_config, Primitive.cexpr!("OFFSETOF((*((struct rb_thread_struct *)NULL)), ext_config)")],
- )
- end
-
- def C.VALUE
- @VALUE ||= CType::Immediate.find(
- Primitive.cexpr!("SIZEOF(VALUE)"),
- Primitive.cexpr!("SIGNED_TYPE_P(VALUE)"),
- )
- end
-
- def C.shape_id_t
- @shape_id_t ||= CType::Immediate.find(
- Primitive.cexpr!("SIZEOF(shape_id_t)"),
- Primitive.cexpr!("SIGNED_TYPE_P(shape_id_t)"),
- )
- end
-
- def C.rb_id_table
- CType::Stub.new(:rb_id_table)
- end
-
- def C.vm_call_handler
- CType::Stub.new(:vm_call_handler)
- end
-
- def C.method_missing_reason
- CType::Stub.new(:method_missing_reason)
- end
-
- def C.vm_ifunc
- CType::Stub.new(:vm_ifunc)
- end
-
- def C.rb_cref_struct
- CType::Stub.new(:rb_cref_struct)
- end
-
- def C.rb_scope_visibility_t
- CType::Stub.new(:rb_scope_visibility_t)
- end
-
- def C.rb_vm_tag
- CType::Stub.new(:rb_vm_tag)
- end
-
- def C.rb_atomic_t
- CType::Stub.new(:rb_atomic_t)
- end
-
- def C.rb_fiber_t
- CType::Stub.new(:rb_fiber_t)
- end
-
- def C.rb_trace_arg_struct
- CType::Stub.new(:rb_trace_arg_struct)
- end
-
- def C.rb_iseq_type
- CType::Stub.new(:rb_iseq_type)
- end
-
- def C.iseq_insn_info
- CType::Stub.new(:iseq_insn_info)
- end
-
- def C.iseq_catch_table
- CType::Stub.new(:iseq_catch_table)
- end
-
- def C.rb_snum_t
- CType::Stub.new(:rb_snum_t)
- end
-
- def C._Bool
- CType::Bool.new
- end
-
- def C.iseq_bits_t
- CType::Stub.new(:iseq_bits_t)
- end
-
- def C.rb_code_location_t
- CType::Stub.new(:rb_code_location_t)
- end
-
- def C.iseq_compile_data
- CType::Stub.new(:iseq_compile_data)
- end
-
- def C.rb_hook_list_struct
- CType::Stub.new(:rb_hook_list_struct)
- end
-
- def C.rb_event_flag_t
- CType::Stub.new(:rb_event_flag_t)
- end
-
- def C.rb_method_alias_t
- CType::Stub.new(:rb_method_alias_t)
- end
-
- def C.rb_method_refined_t
- CType::Stub.new(:rb_method_refined_t)
- end
-
- def C.redblack_node_t
- CType::Stub.new(:redblack_node_t)
- end
-
- def C.ccan_list_node
- CType::Stub.new(:ccan_list_node)
- end
-
- def C.rb_ractor_t
- CType::Stub.new(:rb_ractor_t)
- end
-
- def C.rb_vm_t
- CType::Stub.new(:rb_vm_t)
- end
-
- def C.rb_native_thread
- CType::Stub.new(:rb_native_thread)
- end
-
- def C.rb_thread_sched_item
- CType::Stub.new(:rb_thread_sched_item)
- end
-
- def C.rb_calling_info
- CType::Stub.new(:rb_calling_info)
- end
-
- def C.rb_nativethread_lock_t
- CType::Stub.new(:rb_nativethread_lock_t)
- end
-
- def C.rb_unblock_callback
- CType::Stub.new(:rb_unblock_callback)
- end
-
- def C.rb_mutex_struct
- CType::Stub.new(:rb_mutex_struct)
- end
-
- def C.rb_waiting_list
- CType::Stub.new(:rb_waiting_list)
- end
-
- def C.thread_invoke_type
- CType::Stub.new(:thread_invoke_type)
- end
-
- def C.rb_ext_config
- CType::Stub.new(:rb_ext_config)
- end
-
- ### RJIT bindgen end ###
-end if Primitive.rjit_enabled_p
diff --git a/ruby-runner.c b/ruby-runner.c
index 48acf4396e..e1a53d5236 100644
--- a/ruby-runner.c
+++ b/ruby-runner.c
@@ -7,12 +7,15 @@
#include <sys/types.h>
#include <sys/stat.h>
-#ifdef _WIN32
-# error This feature is unnecessary on Windows in favor of SxS.
-#endif
-
#include "ruby-runner.h"
+#ifdef MAKE_MJIT_BUILD_DIR
+const char MJIT_HEADER[] = BUILDDIR "/" MJIT_MIN_HEADER;
+#else
+
+#define STRINGIZE(expr) STRINGIZE0(expr)
+#define STRINGIZE0(expr) #expr
+
static void
insert_env_path(const char *envname, const char *paths, size_t size, int prepend)
{
@@ -29,24 +32,12 @@ insert_env_path(const char *envname, const char *paths, size_t size, int prepend
char *e = malloc(size+n+1);
size_t pos = 0;
if (prepend) {
- if (size == n || (size < n && env[size] == PATH_SEP)) {
- if (strncmp(paths, env, size) == 0) {
- free(e);
- return;
- }
- }
memcpy(e, paths, pos = size-1);
e[pos++] = PATH_SEP;
}
memcpy(e+pos, env, n);
pos += n;
if (!prepend) {
- if (size == n || (size < n && env[n-size-1] == PATH_SEP)) {
- if (strncmp(paths, &env[n-size], size) == 0) {
- free(e);
- return;
- }
- }
e[pos++] = PATH_SEP;
memcpy(e+pos, paths, size-1);
pos += size-1;
@@ -73,6 +64,10 @@ main(int argc, char **argv)
PATH_SEPARATOR
EXTOUT_DIR"/"ARCH
;
+#ifndef LOAD_RELATIVE
+ static const char mjit_build_dir[] = BUILDDIR"/mjit_build_dir."SOEXT;
+ struct stat stbuf;
+#endif
const size_t dirsize = sizeof(builddir);
const size_t namesize = sizeof(rubypath) - dirsize;
const char *rubyname = rubypath + dirsize;
@@ -80,6 +75,12 @@ main(int argc, char **argv)
insert_env_path(LIBPATHENV, builddir, dirsize, 1);
insert_env_path("RUBYLIB", rubylib, sizeof(rubylib), 0);
+#ifndef LOAD_RELATIVE
+ if (PRELOADENV[0] && stat(mjit_build_dir, &stbuf) == 0) {
+ insert_env_path(PRELOADENV, mjit_build_dir, sizeof(mjit_build_dir), 1);
+ setenv("MJIT_SEARCH_BUILD_DIR", "true", 0);
+ }
+#endif
if (!(p = strrchr(arg0, '/'))) p = arg0; else p++;
if (strlen(p) < namesize - 1) {
@@ -93,3 +94,5 @@ main(int argc, char **argv)
perror(rubypath);
return -1;
}
+
+#endif /* MAKE_MJIT_BUILD_DIR */
diff --git a/ruby.c b/ruby.c
index accf53eec2..09c81db86c 100644
--- a/ruby.c
+++ b/ruby.c
@@ -22,7 +22,7 @@
# include <sys/cygwin.h>
#endif
-#if defined(LOAD_RELATIVE) && defined(HAVE_DLADDR)
+#if (defined(LOAD_RELATIVE) || defined(__MACH__)) && defined(HAVE_DLADDR)
# include <dlfcn.h>
#endif
@@ -53,8 +53,8 @@
#include "internal/loadpath.h"
#include "internal/missing.h"
#include "internal/object.h"
-#include "internal/thread.h"
-#include "internal/ruby_parser.h"
+#include "internal/parse.h"
+#include "internal/process.h"
#include "internal/variable.h"
#include "ruby/encoding.h"
#include "ruby/thread.h"
@@ -105,7 +105,7 @@ void rb_warning_category_update(unsigned int mask, unsigned int bits);
SEP \
X(frozen_string_literal) \
SEP \
- X(rjit) \
+ X(mjit) \
SEP \
X(yjit) \
/* END OF FEATURES */
@@ -117,14 +117,13 @@ void rb_warning_category_update(unsigned int mask, unsigned int bits);
#define DEFINE_DEBUG_FEATURE(bit) feature_debug_##bit
enum feature_flag_bits {
EACH_FEATURES(DEFINE_FEATURE, COMMA),
- DEFINE_FEATURE(frozen_string_literal_set),
feature_debug_flag_first,
-#if defined(RJIT_FORCE_ENABLE) || !USE_YJIT
- DEFINE_FEATURE(jit) = feature_rjit,
+#if defined(MJIT_FORCE_ENABLE) || !USE_YJIT
+ DEFINE_FEATURE(jit) = feature_mjit,
#else
DEFINE_FEATURE(jit) = feature_yjit,
#endif
- feature_jit_mask = FEATURE_BIT(rjit) | FEATURE_BIT(yjit),
+ feature_jit_mask = FEATURE_BIT(mjit) | FEATURE_BIT(yjit),
feature_debug_flag_begin = feature_debug_flag_first - 1,
EACH_DEBUG_FEATURES(DEFINE_DEBUG_FEATURE, COMMA),
@@ -152,19 +151,22 @@ enum feature_flag_bits {
SEP \
X(parsetree) \
SEP \
+ X(parsetree_with_comment) \
+ SEP \
X(insns) \
+ SEP \
+ X(insns_without_opt) \
/* END OF DUMPS */
enum dump_flag_bits {
dump_version_v,
- dump_opt_error_tolerant,
- dump_opt_comment,
- dump_opt_optimize,
+ dump_error_tolerant,
EACH_DUMPS(DEFINE_DUMP, COMMA),
+ dump_error_tolerant_bits = (DUMP_BIT(yydebug) |
+ DUMP_BIT(parsetree) |
+ DUMP_BIT(parsetree_with_comment)),
dump_exit_bits = (DUMP_BIT(yydebug) | DUMP_BIT(syntax) |
- DUMP_BIT(parsetree) | DUMP_BIT(insns)),
- dump_optional_bits = (DUMP_BIT(opt_error_tolerant) |
- DUMP_BIT(opt_comment) |
- DUMP_BIT(opt_optimize))
+ DUMP_BIT(parsetree) | DUMP_BIT(parsetree_with_comment) |
+ DUMP_BIT(insns) | DUMP_BIT(insns_without_opt))
};
static inline void
@@ -190,7 +192,6 @@ enum {
COMPILATION_FEATURES = (
0
| FEATURE_BIT(frozen_string_literal)
- | FEATURE_BIT(frozen_string_literal_set)
| FEATURE_BIT(debug_frozen_string_literal)
),
DEFAULT_FEATURES = (
@@ -199,15 +200,10 @@ enum {
& ~FEATURE_BIT(gems)
#endif
& ~FEATURE_BIT(frozen_string_literal)
- & ~FEATURE_BIT(frozen_string_literal_set)
& ~feature_jit_mask
)
};
-#define BACKTRACE_LENGTH_LIMIT_VALID_P(n) ((n) >= -1)
-#define OPT_BACKTRACE_LENGTH_LIMIT_VALID_P(opt) \
- BACKTRACE_LENGTH_LIMIT_VALID_P((opt)->backtrace_length_limit)
-
static ruby_cmdline_options_t *
cmdline_options_init(ruby_cmdline_options_t *opt)
{
@@ -217,18 +213,16 @@ cmdline_options_init(ruby_cmdline_options_t *opt)
opt->ext.enc.index = -1;
opt->intern.enc.index = -1;
opt->features.set = DEFAULT_FEATURES;
-#ifdef RJIT_FORCE_ENABLE /* to use with: ./configure cppflags="-DRJIT_FORCE_ENABLE" */
- opt->features.set |= FEATURE_BIT(rjit);
+#ifdef MJIT_FORCE_ENABLE /* to use with: ./configure cppflags="-DMJIT_FORCE_ENABLE" */
+ opt->features.set |= FEATURE_BIT(mjit);
#elif defined(YJIT_FORCE_ENABLE)
opt->features.set |= FEATURE_BIT(yjit);
#endif
- opt->dump |= DUMP_BIT(opt_optimize);
- opt->backtrace_length_limit = LONG_MIN;
return opt;
}
-static VALUE load_file(VALUE parser, VALUE fname, VALUE f, int script,
+static rb_ast_t *load_file(VALUE parser, VALUE fname, VALUE f, int script,
ruby_cmdline_options_t *opt);
static VALUE open_load_file(VALUE fname_v, int *xflag);
static void forbid_setid(const char *, const ruby_cmdline_options_t *);
@@ -243,173 +237,121 @@ static const char esc_standout[] = "\n\033[1;7m";
static const char esc_bold[] = "\033[1m";
static const char esc_reset[] = "\033[0m";
static const char esc_none[] = "";
-#define USAGE_INDENT " " /* macro for concatenation */
static void
-show_usage_part(const char *str, const unsigned int namelen,
- const char *str2, const unsigned int secondlen,
- const char *desc,
- int help, int highlight, unsigned int w, int columns)
+show_usage_line(const char *str, unsigned int namelen, unsigned int secondlen, int help, int highlight, unsigned int w)
{
- static const int indent_width = (int)rb_strlen_lit(USAGE_INDENT);
const char *sb = highlight ? esc_bold : esc_none;
const char *se = highlight ? esc_reset : esc_none;
- unsigned int desclen = (unsigned int)strcspn(desc, "\n");
- if (!help && desclen > 0 && strchr(".;:", desc[desclen-1])) --desclen;
- if (help && (namelen + 1 > w) && /* a padding space */
- (int)(namelen + secondlen + indent_width) >= columns) {
- printf(USAGE_INDENT "%s" "%.*s" "%s\n", sb, namelen, str, se);
- if (secondlen > 0) {
- const int second_end = secondlen;
- int n = 0;
- if (str2[n] == ',') n++;
- if (str2[n] == ' ') n++;
- printf(USAGE_INDENT "%s" "%.*s" "%s\n", sb, second_end-n, str2+n, se);
- }
- printf("%-*s%.*s\n", w + indent_width, USAGE_INDENT, desclen, desc);
- }
- else {
- const int wrap = help && namelen + secondlen >= w;
- printf(USAGE_INDENT "%s%.*s%-*.*s%s%-*s%.*s\n", sb, namelen, str,
- (wrap ? 0 : w - namelen),
- (help ? secondlen : 0), str2, se,
- (wrap ? (int)(w + rb_strlen_lit("\n" USAGE_INDENT)) : 0),
- (wrap ? "\n" USAGE_INDENT : ""),
- desclen, desc);
- }
- if (help) {
- while (desc[desclen]) {
- desc += desclen + rb_strlen_lit("\n");
- desclen = (unsigned int)strcspn(desc, "\n");
- printf("%-*s%.*s\n", w + indent_width, USAGE_INDENT, desclen, desc);
- }
- }
-}
-
-static void
-show_usage_line(const struct ruby_opt_message *m,
- int help, int highlight, unsigned int w, int columns)
-{
- const char *str = m->str;
- const unsigned int namelen = m->namelen, secondlen = m->secondlen;
- const char *desc = str + namelen + secondlen;
- show_usage_part(str, namelen - 1, str + namelen, secondlen - 1, desc,
- help, highlight, w, columns);
-}
-
-void
-ruby_show_usage_line(const char *name, const char *secondary, const char *description,
- int help, int highlight, unsigned int width, int columns)
-{
- unsigned int namelen = (unsigned int)strlen(name);
- unsigned int secondlen = (secondary ? (unsigned int)strlen(secondary) : 0);
- show_usage_part(name, namelen, secondary, secondlen,
- description, help, highlight, width, columns);
+ const int wrap = help && namelen + secondlen - 1 > w;
+ printf(" %s%.*s%-*.*s%s%-*s%s\n", sb, namelen-1, str,
+ (wrap ? 0 : w - namelen + 1),
+ (help ? secondlen-1 : 0), str + namelen, se,
+ (wrap ? w + 3 : 0), (wrap ? "\n" : ""),
+ str + namelen + secondlen);
}
static void
usage(const char *name, int help, int highlight, int columns)
{
+ /* This message really ought to be max 23 lines.
+ * Removed -h because the user already knows that option. Others? */
+
#define M(shortopt, longopt, desc) RUBY_OPT_MESSAGE(shortopt, longopt, desc)
#if USE_YJIT
# define PLATFORM_JIT_OPTION "--yjit"
#else
-# define PLATFORM_JIT_OPTION "--rjit (experimental)"
+# define PLATFORM_JIT_OPTION "--mjit (experimental)"
#endif
-
- /* This message really ought to be max 23 lines.
- * Removed -h because the user already knows that option. Others? */
static const struct ruby_opt_message usage_msg[] = {
- M("-0[octal]", "", "Set input record separator ($/):\n"
- "-0 for \\0; -00 for paragraph mode; -0777 for slurp mode."),
- M("-a", "", "Split each input line ($_) into fields ($F)."),
- M("-c", "", "Check syntax (no execution)."),
- M("-Cdirpath", "", "Execute program in specified directory."),
- M("-d", ", --debug", "Set debugging flag ($DEBUG) to true."),
- M("-e 'code'", "", "Execute given Ruby code; multiple -e allowed."),
- M("-Eex[:in]", ", --encoding=ex[:in]", "Set default external and internal encodings."),
- M("-Fpattern", "", "Set input field separator ($;); used with -a."),
- M("-i[extension]", "", "Set ARGF in-place mode;\n"
- "create backup files with given extension."),
- M("-Idirpath", "", "Add specified directory to load paths ($LOAD_PATH);\n"
- "multiple -I allowed."),
- M("-l", "", "Set output record separator ($\\) to $/;\n"
- "used for line-oriented output."),
- M("-n", "", "Run program in gets loop."),
- M("-p", "", "Like -n, with printing added."),
- M("-rlibrary", "", "Require the given library."),
- M("-s", "", "Define global variables using switches following program path."),
- M("-S", "", "Search directories found in the PATH environment variable."),
- M("-v", "", "Print version; set $VERBOSE to true."),
- M("-w", "", "Synonym for -W1."),
- M("-W[level=2|:category]", "", "Set warning flag ($-W):\n"
- "0 for silent; 1 for moderate; 2 for verbose."),
- M("-x[dirpath]", "", "Execute Ruby code starting from a #!ruby line."),
- M("--jit", "", "Enable JIT for the platform; same as " PLATFORM_JIT_OPTION "."),
-#if USE_YJIT
- M("--yjit", "", "Enable in-process JIT compiler."),
+ M("-0[octal]", "", "specify record separator (\\0, if no argument)"),
+ M("-a", "", "autosplit mode with -n or -p (splits $_ into $F)"),
+ M("-c", "", "check syntax only"),
+ M("-Cdirectory", "", "cd to directory before executing your script"),
+ M("-d", ", --debug", "set debugging flags (set $DEBUG to true)"),
+ M("-e 'command'", "", "one line of script. Several -e's allowed. Omit [programfile]"),
+ M("-Eex[:in]", ", --encoding=ex[:in]", "specify the default external and internal character encodings"),
+ M("-Fpattern", "", "split() pattern for autosplit (-a)"),
+ M("-i[extension]", "", "edit ARGV files in place (make backup if extension supplied)"),
+ M("-Idirectory", "", "specify $LOAD_PATH directory (may be used more than once)"),
+ M("-l", "", "enable line ending processing"),
+ M("-n", "", "assume 'while gets(); ... end' loop around your script"),
+ M("-p", "", "assume loop like -n but print line also like sed"),
+ M("-rlibrary", "", "require the library before executing your script"),
+ M("-s", "", "enable some switch parsing for switches after script name"),
+ M("-S", "", "look for the script using PATH environment variable"),
+ M("-v", "", "print the version number, then turn on verbose mode"),
+ M("-w", "", "turn warnings on for your script"),
+ M("-W[level=2|:category]", "", "set warning level; 0=silence, 1=medium, 2=verbose"),
+ M("-x[directory]", "", "strip off text before #!ruby line and perhaps cd to directory"),
+ M("--jit", "", "enable JIT for the platform, same as " PLATFORM_JIT_OPTION),
+#if USE_MJIT
+ M("--mjit", "", "enable C compiler-based JIT compiler (experimental)"),
#endif
-#if USE_RJIT
- M("--rjit", "", "Enable pure-Ruby JIT compiler (experimental)."),
+#if USE_YJIT
+ M("--yjit", "", "enable in-process JIT compiler"),
#endif
- M("-h", "", "Print this help message; use --help for longer message."),
+ M("-h", "", "show this message, --help for more info"),
};
- STATIC_ASSERT(usage_msg_size, numberof(usage_msg) < 25);
-
static const struct ruby_opt_message help_msg[] = {
- M("--backtrace-limit=num", "", "Set backtrace limit."),
- M("--copyright", "", "Print Ruby copyright."),
- M("--crash-report=template", "", "Set template for crash report file."),
- M("--disable=features", "", "Disable features; see list below."),
- M("--dump=items", "", "Dump items; see list below."),
- M("--enable=features", "", "Enable features; see list below."),
- M("--external-encoding=encoding", "", "Set default external encoding."),
- M("--help", "", "Print long help message; use -h for short message."),
- M("--internal-encoding=encoding", "", "Set default internal encoding."),
- M("--parser=parser", "", "Set Ruby parser: parse.y or prism."),
- M("--verbose", "", "Set $VERBOSE to true; ignore input from $stdin."),
- M("--version", "", "Print Ruby version."),
- M("-y", ", --yydebug", "Print parser log; backward compatibility not guaranteed."),
+ M("--copyright", "", "print the copyright"),
+ M("--dump={insns|parsetree|...}[,...]", "",
+ "dump debug information. see below for available dump list"),
+ M("--enable={jit|rubyopt|...}[,...]", ", --disable={jit|rubyopt|...}[,...]",
+ "enable or disable features. see below for available features"),
+ M("--external-encoding=encoding", ", --internal-encoding=encoding",
+ "specify the default external or internal character encoding"),
+ M("--backtrace-limit=num", "", "limit the maximum length of backtrace"),
+ M("--verbose", "", "turn on verbose mode and disable script from stdin"),
+ M("--version", "", "print the version number, then exit"),
+ M("--help", "", "show this message, -h for short message"),
};
static const struct ruby_opt_message dumps[] = {
- M("insns", "", "Instruction sequences."),
- M("yydebug", "", "yydebug of yacc parser generator."),
- M("parsetree", "", "Abstract syntax tree (AST)."),
- M("-optimize", "", "Disable optimization (affects insns)."),
- M("+error-tolerant", "", "Error-tolerant parsing (affects yydebug, parsetree)."),
- M("+comment", "", "Add comments to AST (affects parsetree)."),
+ M("insns", "", "instruction sequences"),
+ M("insns_without_opt", "", "instruction sequences compiled with no optimization"),
+ M("yydebug(+error-tolerant)", "", "yydebug of yacc parser generator"),
+ M("parsetree(+error-tolerant)","", "AST"),
+ M("parsetree_with_comment(+error-tolerant)", "", "AST with comments"),
};
static const struct ruby_opt_message features[] = {
- M("gems", "", "Rubygems (only for debugging, default: "DEFAULT_RUBYGEMS_ENABLED")."),
- M("error_highlight", "", "error_highlight (default: "DEFAULT_RUBYGEMS_ENABLED")."),
- M("did_you_mean", "", "did_you_mean (default: "DEFAULT_RUBYGEMS_ENABLED")."),
- M("syntax_suggest", "", "syntax_suggest (default: "DEFAULT_RUBYGEMS_ENABLED")."),
- M("rubyopt", "", "RUBYOPT environment variable (default: enabled)."),
- M("frozen-string-literal", "", "Freeze all string literals (default: disabled)."),
-#if USE_YJIT
- M("yjit", "", "In-process JIT compiler (default: disabled)."),
+ M("gems", "", "rubygems (only for debugging, default: "DEFAULT_RUBYGEMS_ENABLED")"),
+ M("error_highlight", "", "error_highlight (default: "DEFAULT_RUBYGEMS_ENABLED")"),
+ M("did_you_mean", "", "did_you_mean (default: "DEFAULT_RUBYGEMS_ENABLED")"),
+ M("syntax_suggest", "", "syntax_suggest (default: "DEFAULT_RUBYGEMS_ENABLED")"),
+ M("rubyopt", "", "RUBYOPT environment variable (default: enabled)"),
+ M("frozen-string-literal", "", "freeze all string literals (default: disabled)"),
+#if USE_MJIT
+ M("mjit", "", "C compiler-based JIT compiler (default: disabled)"),
#endif
-#if USE_RJIT
- M("rjit", "", "Pure-Ruby JIT compiler (experimental, default: disabled)."),
+#if USE_YJIT
+ M("yjit", "", "in-process JIT compiler (default: disabled)"),
#endif
};
static const struct ruby_opt_message warn_categories[] = {
- M("deprecated", "", "Deprecated features."),
- M("experimental", "", "Experimental features."),
- M("performance", "", "Performance issues."),
+ M("deprecated", "", "deprecated features"),
+ M("experimental", "", "experimental features"),
+ };
+#if USE_MJIT
+ extern const struct ruby_opt_message mjit_option_messages[];
+#endif
+#if USE_YJIT
+ static const struct ruby_opt_message yjit_options[] = {
+ M("--yjit-stats", "", "Enable collecting YJIT statistics"),
+ M("--yjit-exec-mem-size=num", "", "Size of executable memory block in MiB (default: 64)"),
+ M("--yjit-call-threshold=num", "", "Number of calls to trigger JIT (default: 10)"),
+ M("--yjit-max-versions=num", "", "Maximum number of versions per basic block (default: 4)"),
+ M("--yjit-greedy-versioning", "", "Greedy versioning mode (default: disabled)"),
};
-#if USE_RJIT
- extern const struct ruby_opt_message rb_rjit_option_messages[];
#endif
int i;
const char *sb = highlight ? esc_standout+1 : esc_none;
const char *se = highlight ? esc_reset : esc_none;
const int num = numberof(usage_msg) - (help ? 1 : 0);
unsigned int w = (columns > 80 ? (columns - 79) / 2 : 0) + 16;
-#define SHOW(m) show_usage_line(&(m), help, highlight, w, columns)
+#define SHOW(m) show_usage_line((m).str, (m).namelen, (m).secondlen, help, highlight, w)
- printf("%sUsage:%s %s [options] [--] [filepath] [arguments]\n", sb, se, name);
+ printf("%sUsage:%s %s [switches] [--] [programfile] [arguments]\n", sb, se, name);
for (i = 0; i < num; ++i)
SHOW(usage_msg[i]);
@@ -428,45 +370,54 @@ usage(const char *name, int help, int highlight, int columns)
printf("%s""Warning categories:%s\n", sb, se);
for (i = 0; i < numberof(warn_categories); ++i)
SHOW(warn_categories[i]);
+#if USE_MJIT
+ printf("%s""MJIT options (experimental):%s\n", sb, se);
+ for (i = 0; mjit_option_messages[i].str; ++i)
+ SHOW(mjit_option_messages[i]);
+#endif
#if USE_YJIT
printf("%s""YJIT options:%s\n", sb, se);
- rb_yjit_show_usage(help, highlight, w, columns);
-#endif
-#if USE_RJIT
- printf("%s""RJIT options (experimental):%s\n", sb, se);
- for (i = 0; rb_rjit_option_messages[i].str; ++i)
- SHOW(rb_rjit_option_messages[i]);
+ for (i = 0; i < numberof(yjit_options); ++i)
+ SHOW(yjit_options[i]);
#endif
}
#define rubylib_path_new rb_str_new
static void
-ruby_push_include(const char *path, VALUE (*filter)(VALUE))
+push_include(const char *path, VALUE (*filter)(VALUE))
{
const char sep = PATH_SEP_CHAR;
const char *p, *s;
VALUE load_path = GET_VM()->load_path;
+
+ p = path;
+ while (*p) {
+ while (*p == sep)
+ p++;
+ if (!*p) break;
+ for (s = p; *s && *s != sep; s = CharNext(s));
+ rb_ary_push(load_path, (*filter)(rubylib_path_new(p, s - p)));
+ p = s;
+ }
+}
+
#ifdef __CYGWIN__
+static void
+push_include_cygwin(const char *path, VALUE (*filter)(VALUE))
+{
+ const char *p, *s;
char rubylib[FILENAME_MAX];
VALUE buf = 0;
-# define is_path_sep(c) ((c) == sep || (c) == ';')
-#else
-# define is_path_sep(c) ((c) == sep)
-#endif
- if (path == 0) return;
p = path;
while (*p) {
- long len;
- while (is_path_sep(*p))
+ unsigned int len;
+ while (*p == ';')
p++;
if (!*p) break;
- for (s = p; *s && !is_path_sep(*s); s = CharNext(s));
+ for (s = p; *s && *s != ';'; s = CharNext(s));
len = s - p;
-#undef is_path_sep
-
-#ifdef __CYGWIN__
if (*s) {
if (!buf) {
buf = rb_str_new(p, len);
@@ -483,22 +434,30 @@ ruby_push_include(const char *path, VALUE (*filter)(VALUE))
#else
# error no cygwin_conv_path
#endif
- if (CONV_TO_POSIX_PATH(p, rubylib) == 0) {
+ if (CONV_TO_POSIX_PATH(p, rubylib) == 0)
p = rubylib;
- len = strlen(p);
- }
-#endif
- rb_ary_push(load_path, (*filter)(rubylib_path_new(p, len)));
- p = s;
+ push_include(p, filter);
+ if (!*s) break;
+ p = s + 1;
}
}
+#define push_include push_include_cygwin
+#endif
+
+void
+ruby_push_include(const char *path, VALUE (*filter)(VALUE))
+{
+ if (path == 0)
+ return;
+ push_include(path, filter);
+}
+
static VALUE
identical_path(VALUE path)
{
return path;
}
-
static VALUE
locale_path(VALUE path)
{
@@ -587,13 +546,17 @@ str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
void ruby_init_loadpath(void);
-#if defined(LOAD_RELATIVE)
+#if defined(LOAD_RELATIVE) || defined(__MACH__)
static VALUE
runtime_libruby_path(void)
{
#if defined _WIN32 || defined __CYGWIN__
- DWORD ret;
- DWORD len = 32;
+ DWORD len, ret;
+#if USE_RVARGC
+ len = 32;
+#else
+ len = RSTRING_EMBED_LEN_MAX;
+#endif
VALUE path;
VALUE wsopath = rb_str_new(0, len*sizeof(WCHAR));
WCHAR *wlibpath;
@@ -664,6 +627,10 @@ runtime_libruby_path(void)
#define INITIAL_LOAD_PATH_MARK rb_intern_const("@gem_prelude_index")
VALUE ruby_archlibdir_path, ruby_prefix_path;
+#if defined(__MACH__)
+// A path to libruby.dylib itself or where it's statically linked to.
+VALUE rb_libruby_selfpath;
+#endif
void
ruby_init_loadpath(void)
@@ -671,6 +638,19 @@ ruby_init_loadpath(void)
VALUE load_path, archlibdir = 0;
ID id_initial_load_path_mark;
const char *paths = ruby_initial_load_paths;
+#if defined(LOAD_RELATIVE) || defined(__MACH__)
+ VALUE libruby_path = runtime_libruby_path();
+# if defined(__MACH__)
+ VALUE selfpath = libruby_path;
+# if defined(LOAD_RELATIVE)
+ selfpath = rb_str_dup(selfpath);
+# endif
+ rb_obj_hide(selfpath);
+ OBJ_FREEZE_RAW(selfpath);
+ rb_gc_register_address(&rb_libruby_selfpath);
+ rb_libruby_selfpath = selfpath;
+# endif
+#endif
#if defined LOAD_RELATIVE
#if !defined ENABLE_MULTIARCH
@@ -685,7 +665,7 @@ ruby_init_loadpath(void)
size_t baselen;
const char *p;
- sopath = runtime_libruby_path();
+ sopath = libruby_path;
libpath = RSTRING_PTR(sopath);
p = strrchr(libpath, '/');
@@ -711,11 +691,11 @@ ruby_init_loadpath(void)
p -= bindir_len;
archlibdir = rb_str_subseq(sopath, 0, p - libpath);
rb_str_cat_cstr(archlibdir, libdir);
- OBJ_FREEZE(archlibdir);
+ OBJ_FREEZE_RAW(archlibdir);
}
else if (p - libpath >= libdir_len && !strncmp(p - libdir_len, libdir, libdir_len)) {
archlibdir = rb_str_subseq(sopath, 0, (p2 ? p2 : p) - libpath);
- OBJ_FREEZE(archlibdir);
+ OBJ_FREEZE_RAW(archlibdir);
p -= libdir_len;
}
#ifdef ENABLE_MULTIARCH
@@ -746,7 +726,7 @@ ruby_init_loadpath(void)
#endif
rb_gc_register_address(&ruby_prefix_path);
ruby_prefix_path = PREFIX_PATH();
- OBJ_FREEZE(ruby_prefix_path);
+ OBJ_FREEZE_RAW(ruby_prefix_path);
if (!archlibdir) archlibdir = ruby_prefix_path;
rb_gc_register_address(&ruby_archlibdir_path);
ruby_archlibdir_path = archlibdir;
@@ -806,10 +786,10 @@ toplevel_context(rb_binding_t *bind)
return &bind->block;
}
-static int
-process_sflag(int sflag)
+static void
+process_sflag(int *sflag)
{
- if (sflag > 0) {
+ if (*sflag > 0) {
long n;
const VALUE *args;
VALUE argv = rb_argv;
@@ -866,9 +846,8 @@ process_sflag(int sflag)
while (n--) {
rb_ary_shift(argv);
}
- return -1;
+ *sflag = -1;
}
- return sflag;
}
static long proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt);
@@ -882,26 +861,14 @@ moreswitches(const char *s, ruby_cmdline_options_t *opt, int envopt)
VALUE argstr, argary;
void *ptr;
- VALUE src_enc_name = opt->src.enc.name;
- VALUE ext_enc_name = opt->ext.enc.name;
- VALUE int_enc_name = opt->intern.enc.name;
- ruby_features_t feat = opt->features;
- ruby_features_t warn = opt->warn;
- long backtrace_length_limit = opt->backtrace_length_limit;
- const char *crash_report = opt->crash_report;
-
while (ISSPACE(*s)) s++;
if (!*s) return;
-
- opt->src.enc.name = opt->ext.enc.name = opt->intern.enc.name = 0;
-
- const int hyphen = *s != '-';
- argstr = rb_str_tmp_new((len = strlen(s)) + hyphen);
+ argstr = rb_str_tmp_new((len = strlen(s)) + (envopt!=0));
argary = rb_str_tmp_new(0);
p = RSTRING_PTR(argstr);
- if (hyphen) *p = '-';
- memcpy(p + hyphen, s, len + 1);
+ if (envopt) *p++ = ' ';
+ memcpy(p, s, len + 1);
ap = 0;
rb_str_cat(argary, (char *)&ap, sizeof(ap));
while (*p) {
@@ -929,24 +896,6 @@ moreswitches(const char *s, ruby_cmdline_options_t *opt, int envopt)
}
}
- if (src_enc_name) {
- opt->src.enc.name = src_enc_name;
- }
- if (ext_enc_name) {
- opt->ext.enc.name = ext_enc_name;
- }
- if (int_enc_name) {
- opt->intern.enc.name = int_enc_name;
- }
- FEATURE_SET_RESTORE(opt->features, feat);
- FEATURE_SET_RESTORE(opt->warn, warn);
- if (BACKTRACE_LENGTH_LIMIT_VALID_P(backtrace_length_limit)) {
- opt->backtrace_length_limit = backtrace_length_limit;
- }
- if (crash_report) {
- opt->crash_report = crash_report;
- }
-
ruby_xfree(ptr);
/* get rid of GC */
rb_str_resize(argary, 0);
@@ -966,7 +915,7 @@ name_match_p(const char *name, const char *str, size_t len)
if (*str != '-' && *str != '_') return 0;
while (ISALNUM(*name)) name++;
if (*name != '-' && *name != '_') return 0;
- if (!*++name) return 1;
+ ++name;
++str;
if (--len == 0) return 1;
}
@@ -1010,14 +959,14 @@ feature_option(const char *str, int len, void *arg, const unsigned int enable)
goto found;
}
if (NAME_MATCH_P("all", str, len)) {
- // YJIT and RJIT cannot be enabled at the same time. We enable only one for --enable=all.
+ // YJIT and MJIT cannot be enabled at the same time. We enable only one for --enable=all.
mask &= ~feature_jit_mask | FEATURE_BIT(jit);
goto found;
}
#if AMBIGUOUS_FEATURE_NAMES
if (matched == 1) goto found;
if (matched > 1) {
- VALUE mesg = rb_sprintf("ambiguous feature: '%.*s' (", len, str);
+ VALUE mesg = rb_sprintf("ambiguous feature: `%.*s' (", len, str);
#define ADD_FEATURE_NAME(bit) \
if (FEATURE_BIT(bit) & set) { \
rb_str_cat_cstr(mesg, #bit); \
@@ -1031,16 +980,13 @@ feature_option(const char *str, int len, void *arg, const unsigned int enable)
#else
(void)set;
#endif
- rb_warn("unknown argument for --%s: '%.*s'",
+ rb_warn("unknown argument for --%s: `%.*s'",
enable ? "enable" : "disable", len, str);
rb_warn("features are [%.*s].", (int)strlen(list), list);
return;
found:
FEATURE_SET_TO(*argp, mask, (mask & enable));
- if (NAME_MATCH_P("frozen_string_literal", str, len)) {
- FEATURE_SET_TO(*argp, FEATURE_BIT(frozen_string_literal_set), FEATURE_BIT(frozen_string_literal_set));
- }
return;
}
@@ -1073,7 +1019,7 @@ debug_option(const char *str, int len, void *arg)
#ifdef RUBY_DEVEL
if (ruby_patchlevel < 0 && ruby_env_debug_option(str, len, 0)) return;
#endif
- rb_warn("unknown argument for --debug: '%.*s'", len, str);
+ rb_warn("unknown argument for --debug: `%.*s'", len, str);
rb_warn("debug features are [%.*s].", (int)strlen(list), list);
}
@@ -1089,45 +1035,21 @@ memtermspn(const char *str, char term, int len)
static const char additional_opt_sep = '+';
static unsigned int
-dump_additional_option_flag(const char *str, int len, unsigned int bits, bool set)
-{
-#define SET_DUMP_OPT(bit) if (NAME_MATCH_P(#bit, str, len)) { \
- return set ? (bits | DUMP_BIT(opt_ ## bit)) : (bits & ~DUMP_BIT(opt_ ## bit)); \
- }
- SET_DUMP_OPT(error_tolerant);
- SET_DUMP_OPT(comment);
- SET_DUMP_OPT(optimize);
-#undef SET_DUMP_OPT
- rb_warn("don't know how to dump with%s '%.*s'", set ? "" : "out", len, str);
- return bits;
-}
-
-static unsigned int
-dump_additional_option(const char *str, int len, unsigned int bits)
+dump_additional_option(const char *str, int len, unsigned int bits, const char *name)
{
int w;
for (; len-- > 0 && *str++ == additional_opt_sep; len -= w, str += w) {
w = memtermspn(str, additional_opt_sep, len);
- bool set = true;
- if (*str == '-' || *str == '+') {
- set = *str++ == '+';
- --w;
+#define SET_ADDITIONAL(bit) if (NAME_MATCH_P(#bit, str, w)) { \
+ if (bits & DUMP_BIT(bit)) \
+ rb_warn("duplicate option to dump %s: `%.*s'", name, w, str); \
+ bits |= DUMP_BIT(bit); \
+ continue; \
}
- else {
- int n = memtermspn(str, '-', w);
- if (str[n] == '-') {
- if (NAME_MATCH_P("with", str, n)) {
- str += n;
- w -= n;
- }
- else if (NAME_MATCH_P("without", str, n)) {
- set = false;
- str += n;
- w -= n;
- }
- }
+ if (dump_error_tolerant_bits & bits) {
+ SET_ADDITIONAL(error_tolerant);
}
- bits = dump_additional_option_flag(str, w, bits, set);
+ rb_warn("don't know how to dump %s with `%.*s'", name, w, str);
}
return bits;
}
@@ -1136,21 +1058,16 @@ static void
dump_option(const char *str, int len, void *arg)
{
static const char list[] = EACH_DUMPS(LITERAL_NAME_ELEMENT, ", ");
- unsigned int *bits_ptr = (unsigned int *)arg;
- if (*str == '+' || *str == '-') {
- bool set = *str++ == '+';
- *bits_ptr = dump_additional_option_flag(str, --len, *bits_ptr, set);
- return;
- }
int w = memtermspn(str, additional_opt_sep, len);
#define SET_WHEN_DUMP(bit) \
- if (NAME_MATCH_P(#bit "-", (str), (w))) { \
- *bits_ptr = dump_additional_option(str + w, len - w, *bits_ptr | DUMP_BIT(bit)); \
+ if (NAME_MATCH_P(#bit, (str), (w))) { \
+ *(unsigned int *)arg |= \
+ dump_additional_option(str + w, len - w, DUMP_BIT(bit), #bit); \
return; \
}
EACH_DUMPS(SET_WHEN_DUMP, ;);
- rb_warn("don't know how to dump '%.*s',", len, str);
+ rb_warn("don't know how to dump `%.*s',", len, str);
rb_warn("but only [%.*s].", (int)strlen(list), list);
}
@@ -1196,328 +1113,12 @@ setup_yjit_options(const char *s)
rb_raise(
rb_eRuntimeError,
- "invalid YJIT option '%s' (--help will show valid yjit options)",
+ "invalid YJIT option `%s' (--help will show valid yjit options)",
s
);
}
#endif
-/*
- * Following proc_*_option functions are tree kinds:
- *
- * - with a required argument, takes also `argc` and `argv`, and
- * returns the number of consumed argv including the option itself.
- *
- * - with a mandatory argument just after the option.
- *
- * - no required argument, this returns the address of
- * the next character after the last consumed character.
- */
-
-/* optional */
-static const char *
-proc_W_option(ruby_cmdline_options_t *opt, const char *s, int *warning)
-{
- if (s[1] == ':') {
- unsigned int bits = 0;
- static const char no_prefix[] = "no-";
- int enable = strncmp(s += 2, no_prefix, sizeof(no_prefix)-1) != 0;
- if (!enable) s += sizeof(no_prefix)-1;
- size_t len = strlen(s);
- if (NAME_MATCH_P("deprecated", s, len)) {
- bits = 1U << RB_WARN_CATEGORY_DEPRECATED;
- }
- else if (NAME_MATCH_P("experimental", s, len)) {
- bits = 1U << RB_WARN_CATEGORY_EXPERIMENTAL;
- }
- else if (NAME_MATCH_P("performance", s, len)) {
- bits = 1U << RB_WARN_CATEGORY_PERFORMANCE;
- }
- else {
- rb_warn("unknown warning category: '%s'", s);
- }
- if (bits) FEATURE_SET_TO(opt->warn, bits, enable ? bits : 0);
- return 0;
- }
- else {
- size_t numlen;
- int v = 2; /* -W as -W2 */
-
- if (*++s) {
- v = scan_oct(s, 1, &numlen);
- if (numlen == 0)
- v = 2;
- s += numlen;
- }
- if (!opt->warning) {
- switch (v) {
- case 0:
- ruby_verbose = Qnil;
- break;
- case 1:
- ruby_verbose = Qfalse;
- break;
- default:
- ruby_verbose = Qtrue;
- break;
- }
- }
- *warning = 1;
- switch (v) {
- case 0:
- FEATURE_SET_TO(opt->warn, RB_WARN_CATEGORY_DEFAULT_BITS, 0);
- break;
- case 1:
- FEATURE_SET_TO(opt->warn, 1U << RB_WARN_CATEGORY_DEPRECATED, 0);
- break;
- default:
- FEATURE_SET(opt->warn, RB_WARN_CATEGORY_DEFAULT_BITS);
- break;
- }
- return s;
- }
-}
-
-/* required */
-static long
-proc_e_option(ruby_cmdline_options_t *opt, const char *s, long argc, char **argv)
-{
- long n = 1;
- forbid_setid("-e");
- if (!*++s) {
- if (!--argc)
- rb_raise(rb_eRuntimeError, "no code specified for -e");
- s = *++argv;
- n++;
- }
- if (!opt->e_script) {
- opt->e_script = rb_str_new(0, 0);
- if (opt->script == 0)
- opt->script = "-e";
- }
- rb_str_cat2(opt->e_script, s);
- rb_str_cat2(opt->e_script, "\n");
- return n;
-}
-
-/* optional */
-static const char *
-proc_K_option(ruby_cmdline_options_t *opt, const char *s)
-{
- if (*++s) {
- const char *enc_name = 0;
- switch (*s) {
- case 'E': case 'e':
- enc_name = "EUC-JP";
- break;
- case 'S': case 's':
- enc_name = "Windows-31J";
- break;
- case 'U': case 'u':
- enc_name = "UTF-8";
- break;
- case 'N': case 'n': case 'A': case 'a':
- enc_name = "ASCII-8BIT";
- break;
- }
- if (enc_name) {
- opt->src.enc.name = rb_str_new2(enc_name);
- if (!opt->ext.enc.name)
- opt->ext.enc.name = opt->src.enc.name;
- }
- s++;
- }
- return s;
-}
-
-/* optional */
-static const char *
-proc_0_option(ruby_cmdline_options_t *opt, const char *s)
-{
- size_t numlen;
- int v;
- char c;
-
- v = scan_oct(s, 4, &numlen);
- s += numlen;
- if (v > 0377)
- rb_rs = Qnil;
- else if (v == 0 && numlen >= 2) {
- rb_rs = rb_str_new2("");
- }
- else {
- c = v & 0xff;
- rb_rs = rb_str_new(&c, 1);
- }
- return s;
-}
-
-/* mandatory */
-static void
-proc_encoding_option(ruby_cmdline_options_t *opt, const char *s, const char *opt_name)
-{
- char *p;
-# define set_encoding_part(type) \
- if (!(p = strchr(s, ':'))) { \
- set_##type##_encoding_once(opt, s, 0); \
- return; \
- } \
- else if (p > s) { \
- set_##type##_encoding_once(opt, s, p-s); \
- }
- set_encoding_part(external);
- if (!*(s = ++p)) return;
- set_encoding_part(internal);
- if (!*(s = ++p)) return;
-#if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
- set_encoding_part(source);
- if (!*(s = ++p)) return;
-#endif
- rb_raise(rb_eRuntimeError, "extra argument for %s: %s", opt_name, s);
-# undef set_encoding_part
- UNREACHABLE;
-}
-
-static long
-proc_long_options(ruby_cmdline_options_t *opt, const char *s, long argc, char **argv, int envopt)
-{
- size_t n;
- long argc0 = argc;
-# define is_option_end(c, allow_hyphen) \
- (!(c) || ((allow_hyphen) && (c) == '-') || (c) == '=')
-# define check_envopt(name, allow_envopt) \
- (((allow_envopt) || !envopt) ? (void)0 : \
- rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --" name))
-# define need_argument(name, s, needs_arg, next_arg) \
- ((*(s) ? !*++(s) : (next_arg) && (argc <= 1 || !((s) = argv[1]) || (--argc, ++argv, 0))) && (needs_arg) ? \
- rb_raise(rb_eRuntimeError, "missing argument for --" name) \
- : (void)0)
-# define is_option_with_arg(name, allow_hyphen, allow_envopt) \
- is_option_with_optarg(name, allow_hyphen, allow_envopt, Qtrue, Qtrue)
-# define is_option_with_optarg(name, allow_hyphen, allow_envopt, needs_arg, next_arg) \
- (strncmp((name), s, n = sizeof(name) - 1) == 0 && is_option_end(s[n], (allow_hyphen)) && \
- (s[n] != '-' || (s[n] && s[n+1])) ? \
- (check_envopt(name, (allow_envopt)), s += n, \
- need_argument(name, s, needs_arg, next_arg), 1) : 0)
-
- if (strcmp("copyright", s) == 0) {
- if (envopt) goto noenvopt_long;
- opt->dump |= DUMP_BIT(copyright);
- }
- else if (is_option_with_optarg("debug", Qtrue, Qtrue, Qfalse, Qfalse)) {
- if (s && *s) {
- ruby_each_words(s, debug_option, &opt->features);
- }
- else {
- ruby_debug = Qtrue;
- ruby_verbose = Qtrue;
- }
- }
- else if (is_option_with_arg("enable", Qtrue, Qtrue)) {
- ruby_each_words(s, enable_option, &opt->features);
- }
- else if (is_option_with_arg("disable", Qtrue, Qtrue)) {
- ruby_each_words(s, disable_option, &opt->features);
- }
- else if (is_option_with_arg("encoding", Qfalse, Qtrue)) {
- proc_encoding_option(opt, s, "--encoding");
- }
- else if (is_option_with_arg("internal-encoding", Qfalse, Qtrue)) {
- set_internal_encoding_once(opt, s, 0);
- }
- else if (is_option_with_arg("external-encoding", Qfalse, Qtrue)) {
- set_external_encoding_once(opt, s, 0);
- }
- else if (is_option_with_arg("parser", Qfalse, Qtrue)) {
- if (strcmp("prism", s) == 0) {
- rb_ruby_default_parser_set(RB_DEFAULT_PARSER_PRISM);
- }
- else if (strcmp("parse.y", s) == 0) {
- rb_ruby_default_parser_set(RB_DEFAULT_PARSER_PARSE_Y);
- }
- else {
- rb_raise(rb_eRuntimeError, "unknown parser %s", s);
- }
- }
-#if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
- else if (is_option_with_arg("source-encoding", Qfalse, Qtrue)) {
- set_source_encoding_once(opt, s, 0);
- }
-#endif
- else if (strcmp("version", s) == 0) {
- if (envopt) goto noenvopt_long;
- opt->dump |= DUMP_BIT(version);
- }
- else if (strcmp("verbose", s) == 0) {
- opt->verbose = 1;
- ruby_verbose = Qtrue;
- }
- else if (strcmp("jit", s) == 0) {
-#if USE_YJIT || USE_RJIT
- FEATURE_SET(opt->features, FEATURE_BIT(jit));
-#else
- rb_warn("Ruby was built without JIT support");
-#endif
- }
- else if (is_option_with_optarg("rjit", '-', true, false, false)) {
-#if USE_RJIT
- extern void rb_rjit_setup_options(const char *s, struct rb_rjit_options *rjit_opt);
- FEATURE_SET(opt->features, FEATURE_BIT(rjit));
- rb_rjit_setup_options(s, &opt->rjit);
-#else
- rb_warn("RJIT support is disabled.");
-#endif
- }
- else if (is_option_with_optarg("yjit", '-', true, false, false)) {
-#if USE_YJIT
- FEATURE_SET(opt->features, FEATURE_BIT(yjit));
- setup_yjit_options(s);
-#else
- rb_warn("Ruby was built without YJIT support."
- " You may need to install rustc to build Ruby with YJIT.");
-#endif
- }
- else if (strcmp("yydebug", s) == 0) {
- if (envopt) goto noenvopt_long;
- opt->dump |= DUMP_BIT(yydebug);
- }
- else if (is_option_with_arg("dump", Qfalse, Qfalse)) {
- ruby_each_words(s, dump_option, &opt->dump);
- }
- else if (strcmp("help", s) == 0) {
- if (envopt) goto noenvopt_long;
- opt->dump |= DUMP_BIT(help);
- return 0;
- }
- else if (is_option_with_arg("backtrace-limit", Qfalse, Qtrue)) {
- char *e;
- long n = strtol(s, &e, 10);
- if (errno == ERANGE || !BACKTRACE_LENGTH_LIMIT_VALID_P(n) || *e) {
- rb_raise(rb_eRuntimeError, "wrong limit for backtrace length");
- }
- else {
- opt->backtrace_length_limit = n;
- }
- }
- else if (is_option_with_arg("crash-report", true, true)) {
- opt->crash_report = s;
- }
- else {
- rb_raise(rb_eRuntimeError,
- "invalid option --%s (-h will show valid options)", s);
- }
- return argc0 - argc + 1;
-
- noenvopt_long:
- rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --%s", s);
-# undef is_option_end
-# undef check_envopt
-# undef need_argument
-# undef is_option_with_arg
-# undef is_option_with_optarg
- UNREACHABLE_RETURN(0);
-}
-
static long
proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
{
@@ -1576,12 +1177,65 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
warning = 1;
ruby_verbose = Qtrue;
}
- FEATURE_SET(opt->warn, RB_WARN_CATEGORY_DEFAULT_BITS);
+ FEATURE_SET(opt->warn, RB_WARN_CATEGORY_ALL_BITS);
s++;
goto reswitch;
case 'W':
- if (!(s = proc_W_option(opt, s, &warning))) break;
+ if (s[1] == ':') {
+ unsigned int bits = 0;
+ static const char no_prefix[] = "no-";
+ int enable = strncmp(s += 2, no_prefix, sizeof(no_prefix)-1) != 0;
+ if (!enable) s += sizeof(no_prefix)-1;
+ size_t len = strlen(s);
+ if (NAME_MATCH_P("deprecated", s, len)) {
+ bits = 1U << RB_WARN_CATEGORY_DEPRECATED;
+ }
+ else if (NAME_MATCH_P("experimental", s, len)) {
+ bits = 1U << RB_WARN_CATEGORY_EXPERIMENTAL;
+ }
+ else {
+ rb_warn("unknown warning category: `%s'", s);
+ }
+ if (bits) FEATURE_SET_TO(opt->warn, bits, enable ? bits : 0);
+ break;
+ }
+ {
+ size_t numlen;
+ int v = 2; /* -W as -W2 */
+
+ if (*++s) {
+ v = scan_oct(s, 1, &numlen);
+ if (numlen == 0)
+ v = 2;
+ s += numlen;
+ }
+ if (!opt->warning) {
+ switch (v) {
+ case 0:
+ ruby_verbose = Qnil;
+ break;
+ case 1:
+ ruby_verbose = Qfalse;
+ break;
+ default:
+ ruby_verbose = Qtrue;
+ break;
+ }
+ }
+ warning = 1;
+ switch (v) {
+ case 0:
+ FEATURE_SET_TO(opt->warn, RB_WARN_CATEGORY_ALL_BITS, 0);
+ break;
+ case 1:
+ FEATURE_SET_TO(opt->warn, 1U << RB_WARN_CATEGORY_DEPRECATED, 0);
+ break;
+ default:
+ FEATURE_SET(opt->warn, RB_WARN_CATEGORY_ALL_BITS);
+ break;
+ }
+ }
goto reswitch;
case 'c':
@@ -1618,10 +1272,19 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
case 'e':
if (envopt) goto noenvopt;
- if (!(n = proc_e_option(opt, s, argc, argv))) break;
- --n;
- argc -= n;
- argv += n;
+ forbid_setid("-e");
+ if (!*++s) {
+ if (!--argc)
+ rb_raise(rb_eRuntimeError, "no code specified for -e");
+ s = *++argv;
+ }
+ if (!opt->e_script) {
+ opt->e_script = rb_str_new(0, 0);
+ if (opt->script == 0)
+ opt->script = "-e";
+ }
+ rb_str_cat2(opt->e_script, s);
+ rb_str_cat2(opt->e_script, "\n");
break;
case 'r':
@@ -1673,8 +1336,7 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
if (!*++s && (!--argc || !(s = *++argv))) {
rb_raise(rb_eRuntimeError, "missing argument for -E");
}
- proc_encoding_option(opt, s, "-E");
- break;
+ goto encoding;
case 'U':
set_internal_encoding_once(opt, "UTF-8", 0);
@@ -1682,7 +1344,29 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
goto reswitch;
case 'K':
- if (!(s = proc_K_option(opt, s))) break;
+ if (*++s) {
+ const char *enc_name = 0;
+ switch (*s) {
+ case 'E': case 'e':
+ enc_name = "EUC-JP";
+ break;
+ case 'S': case 's':
+ enc_name = "Windows-31J";
+ break;
+ case 'U': case 'u':
+ enc_name = "UTF-8";
+ break;
+ case 'N': case 'n': case 'A': case 'a':
+ enc_name = "ASCII-8BIT";
+ break;
+ }
+ if (enc_name) {
+ opt->src.enc.name = rb_str_new2(enc_name);
+ if (!opt->ext.enc.name)
+ opt->ext.enc.name = opt->src.enc.name;
+ }
+ s++;
+ }
goto reswitch;
case 'I':
@@ -1697,7 +1381,23 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
case '0':
if (envopt) goto noenvopt;
- if (!(s = proc_0_option(opt, s))) break;
+ {
+ size_t numlen;
+ int v;
+ char c;
+
+ v = scan_oct(s, 4, &numlen);
+ s += numlen;
+ if (v > 0377)
+ rb_rs = Qnil;
+ else if (v == 0 && numlen >= 2) {
+ rb_rs = rb_str_new2("");
+ }
+ else {
+ c = v & 0xff;
+ rb_rs = rb_str_new(&c, 1);
+ }
+ }
goto reswitch;
case '-':
@@ -1707,10 +1407,133 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
}
s++;
- if (!(n = proc_long_options(opt, s, argc, argv, envopt))) goto switch_end;
- --n;
- argc -= n;
- argv += n;
+# define is_option_end(c, allow_hyphen) \
+ (!(c) || ((allow_hyphen) && (c) == '-') || (c) == '=')
+# define check_envopt(name, allow_envopt) \
+ (((allow_envopt) || !envopt) ? (void)0 : \
+ rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --" name))
+# define need_argument(name, s, needs_arg, next_arg) \
+ ((*(s) ? !*++(s) : (next_arg) && (!argc || !((s) = argv[1]) || (--argc, ++argv, 0))) && (needs_arg) ? \
+ rb_raise(rb_eRuntimeError, "missing argument for --" name) \
+ : (void)0)
+# define is_option_with_arg(name, allow_hyphen, allow_envopt) \
+ is_option_with_optarg(name, allow_hyphen, allow_envopt, Qtrue, Qtrue)
+# define is_option_with_optarg(name, allow_hyphen, allow_envopt, needs_arg, next_arg) \
+ (strncmp((name), s, n = sizeof(name) - 1) == 0 && is_option_end(s[n], (allow_hyphen)) && \
+ (s[n] != '-' || s[n+1]) ? \
+ (check_envopt(name, (allow_envopt)), s += n, \
+ need_argument(name, s, needs_arg, next_arg), 1) : 0)
+
+ if (strcmp("copyright", s) == 0) {
+ if (envopt) goto noenvopt_long;
+ opt->dump |= DUMP_BIT(copyright);
+ }
+ else if (is_option_with_optarg("debug", Qtrue, Qtrue, Qfalse, Qfalse)) {
+ if (s && *s) {
+ ruby_each_words(s, debug_option, &opt->features);
+ }
+ else {
+ ruby_debug = Qtrue;
+ ruby_verbose = Qtrue;
+ }
+ }
+ else if (is_option_with_arg("enable", Qtrue, Qtrue)) {
+ ruby_each_words(s, enable_option, &opt->features);
+ }
+ else if (is_option_with_arg("disable", Qtrue, Qtrue)) {
+ ruby_each_words(s, disable_option, &opt->features);
+ }
+ else if (is_option_with_arg("encoding", Qfalse, Qtrue)) {
+ char *p;
+ encoding:
+ do {
+# define set_encoding_part(type) \
+ if (!(p = strchr(s, ':'))) { \
+ set_##type##_encoding_once(opt, s, 0); \
+ break; \
+ } \
+ else if (p > s) { \
+ set_##type##_encoding_once(opt, s, p-s); \
+ }
+ set_encoding_part(external);
+ if (!*(s = ++p)) break;
+ set_encoding_part(internal);
+ if (!*(s = ++p)) break;
+#if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
+ set_encoding_part(source);
+ if (!*(s = ++p)) break;
+#endif
+ rb_raise(rb_eRuntimeError, "extra argument for %s: %s",
+ (arg[1] == '-' ? "--encoding" : "-E"), s);
+# undef set_encoding_part
+ } while (0);
+ }
+ else if (is_option_with_arg("internal-encoding", Qfalse, Qtrue)) {
+ set_internal_encoding_once(opt, s, 0);
+ }
+ else if (is_option_with_arg("external-encoding", Qfalse, Qtrue)) {
+ set_external_encoding_once(opt, s, 0);
+ }
+#if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
+ else if (is_option_with_arg("source-encoding", Qfalse, Qtrue)) {
+ set_source_encoding_once(opt, s, 0);
+ }
+#endif
+ else if (strcmp("version", s) == 0) {
+ if (envopt) goto noenvopt_long;
+ opt->dump |= DUMP_BIT(version);
+ }
+ else if (strcmp("verbose", s) == 0) {
+ opt->verbose = 1;
+ ruby_verbose = Qtrue;
+ }
+ else if (strcmp("jit", s) == 0) {
+#if !USE_MJIT
+ rb_warn("Ruby was built without JIT support");
+#else
+ FEATURE_SET(opt->features, FEATURE_BIT(jit));
+#endif
+ }
+ else if (is_option_with_optarg("mjit", '-', true, false, false)) {
+#if USE_MJIT
+ extern void mjit_setup_options(const char *s, struct mjit_options *mjit_opt);
+ FEATURE_SET(opt->features, FEATURE_BIT(mjit));
+ mjit_setup_options(s, &opt->mjit);
+#else
+ rb_warn("MJIT support is disabled.");
+#endif
+ }
+ else if (is_option_with_optarg("yjit", '-', true, false, false)) {
+#if USE_YJIT
+ FEATURE_SET(opt->features, FEATURE_BIT(yjit));
+ setup_yjit_options(s);
+#else
+ rb_warn("Ruby was built without YJIT support."
+ " You may need to install rustc to build Ruby with YJIT.");
+#endif
+ }
+ else if (strcmp("yydebug", s) == 0) {
+ if (envopt) goto noenvopt_long;
+ opt->dump |= DUMP_BIT(yydebug);
+ }
+ else if (is_option_with_arg("dump", Qfalse, Qfalse)) {
+ ruby_each_words(s, dump_option, &opt->dump);
+ }
+ else if (strcmp("help", s) == 0) {
+ if (envopt) goto noenvopt_long;
+ opt->dump |= DUMP_BIT(help);
+ goto switch_end;
+ }
+ else if (is_option_with_arg("backtrace-limit", Qfalse, Qfalse)) {
+ char *e;
+ long n = strtol(s, &e, 10);
+ if (errno == ERANGE || n < 0 || *e) rb_raise(rb_eRuntimeError, "wrong limit for backtrace length");
+ rb_backtrace_length_limit = n;
+ }
+ else {
+ rb_raise(rb_eRuntimeError,
+ "invalid option --%s (-h will show valid options)", s);
+ }
break;
case '\r':
@@ -1718,9 +1541,11 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
break;
default:
- rb_raise(rb_eRuntimeError,
- "invalid option -%c (-h will show valid options)",
- (int)(unsigned char)*s);
+ {
+ rb_raise(rb_eRuntimeError,
+ "invalid option -%c (-h will show valid options)",
+ (int)(unsigned char)*s);
+ }
goto switch_end;
noenvopt:
@@ -1728,8 +1553,17 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: -%c", *s);
break;
+ noenvopt_long:
+ rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --%s", s);
+ break;
+
case 0:
break;
+# undef is_option_end
+# undef check_envopt
+# undef need_argument
+# undef is_option_with_arg
+# undef is_option_with_optarg
}
}
@@ -1762,8 +1596,6 @@ Init_extra_exts(void)
static void
ruby_opt_init(ruby_cmdline_options_t *opt)
{
- rb_warning_category_update(opt->warn.mask, opt->warn.set);
-
if (opt->dump & dump_exit_bits) return;
if (FEATURE_SET_P(opt->features, gems)) {
@@ -1779,42 +1611,33 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
}
}
- /* [Feature #19785] Warning for removed GC environment variable.
- * Remove this in Ruby 3.4. */
- if (getenv("RUBY_GC_HEAP_INIT_SLOTS")) {
- rb_warn_deprecated("The environment variable RUBY_GC_HEAP_INIT_SLOTS",
- "environment variables RUBY_GC_HEAP_%d_INIT_SLOTS");
- }
+ rb_warning_category_update(opt->warn.mask, opt->warn.set);
-#if USE_RJIT
- // rb_call_builtin_inits depends on RubyVM::RJIT.enabled?
- if (opt->rjit.on)
- rb_rjit_enabled = true;
- if (opt->rjit.stats)
- rb_rjit_stats_enabled = true;
- if (opt->rjit.trace_exits)
- rb_rjit_trace_exits_enabled = true;
+#if USE_MJIT
+ // rb_call_builtin_inits depends on RubyVM::MJIT.enabled?
+ if (opt->mjit.on)
+ mjit_enabled = true;
#endif
Init_ext(); /* load statically linked extensions before rubygems */
Init_extra_exts();
-
- GET_VM()->running = 0;
rb_call_builtin_inits();
- GET_VM()->running = 1;
- memset(ruby_vm_redefined_flag, 0, sizeof(ruby_vm_redefined_flag));
-
ruby_init_prelude();
// Initialize JITs after prelude because JITing prelude is typically not optimal.
-#if USE_RJIT
- // Also, rb_rjit_init is safe only after rb_call_builtin_inits() defines RubyVM::RJIT::Compiler.
- if (opt->rjit.on)
- rb_rjit_init(&opt->rjit);
+#if USE_MJIT
+ // Also, mjit_init is safe only after rb_call_builtin_inits() defines RubyVM::MJIT::Compiler.
+ if (opt->mjit.on)
+ mjit_init(&opt->mjit);
#endif
#if USE_YJIT
- rb_yjit_init(opt->yjit);
+ if (opt->yjit)
+ rb_yjit_init();
#endif
+ // rb_threadptr_root_fiber_setup for the initial thread is called before rb_yjit_enabled_p()
+ // or mjit_enabled becomes true, meaning jit_cont_new is skipped for the initial root fiber.
+ // Therefore we need to call this again here to set the initial root fiber's jit_cont.
+ rb_jit_cont_init(); // must be after mjit_enabled = true and rb_yjit_init()
ruby_set_script_name(opt->script_name);
require_libraries(&opt->req_list);
@@ -1946,10 +1769,7 @@ rb_f_chomp(int argc, VALUE *argv, VALUE _)
static void
setup_pager_env(void)
{
- if (!getenv("LESS")) {
- // Output "raw" control characters, and move per sections.
- ruby_setenv("LESS", "-R +/^[A-Z].*");
- }
+ if (!getenv("LESS")) ruby_setenv("LESS", "-R"); // Output "raw" control characters.
}
#ifdef _WIN32
@@ -2000,298 +1820,12 @@ env_var_truthy(const char *name)
}
#endif
-rb_pid_t rb_fork_ruby(int *status);
-
-static void
-show_help(const char *progname, int help)
-{
- int tty = isatty(1);
- int columns = 0;
- if (help && tty) {
- const char *pager_env = getenv("RUBY_PAGER");
- if (!pager_env) pager_env = getenv("PAGER");
- if (pager_env && *pager_env && isatty(0)) {
- const char *columns_env = getenv("COLUMNS");
- if (columns_env) columns = atoi(columns_env);
- VALUE pager = rb_str_new_cstr(pager_env);
-#ifdef HAVE_WORKING_FORK
- int fds[2];
- if (rb_pipe(fds) == 0) {
- rb_pid_t pid = rb_fork_ruby(NULL);
- if (pid > 0) {
- /* exec PAGER with reading from child */
- dup2(fds[0], 0);
- }
- else if (pid == 0) {
- /* send the help message to the parent PAGER */
- dup2(fds[1], 1);
- dup2(fds[1], 2);
- }
- close(fds[0]);
- close(fds[1]);
- if (pid > 0) {
- setup_pager_env();
- rb_f_exec(1, &pager);
- kill(SIGTERM, pid);
- rb_waitpid(pid, 0, 0);
- }
- }
-#else
- setup_pager_env();
- VALUE port = rb_io_popen(pager, rb_str_new_lit("w"), Qnil, Qnil);
- if (!NIL_P(port)) {
- int oldout = dup(1);
- int olderr = dup(2);
- int fd = RFILE(port)->fptr->fd;
- tty = tty_enabled();
- dup2(fd, 1);
- dup2(fd, 2);
- usage(progname, 1, tty, columns);
- fflush(stdout);
- dup2(oldout, 1);
- dup2(olderr, 2);
- rb_io_close(port);
- return;
- }
-#endif
- }
- }
- usage(progname, help, tty, columns);
-}
-
-static VALUE
-process_script(ruby_cmdline_options_t *opt)
-{
- rb_ast_t *ast;
- VALUE ast_value;
- VALUE parser = rb_parser_new();
- const unsigned int dump = opt->dump;
-
- if (dump & DUMP_BIT(yydebug)) {
- rb_parser_set_yydebug(parser, Qtrue);
- }
-
- if ((dump & dump_exit_bits) && (dump & DUMP_BIT(opt_error_tolerant))) {
- rb_parser_error_tolerant(parser);
- }
-
- if (opt->e_script) {
- VALUE progname = rb_progname;
- rb_parser_set_context(parser, 0, TRUE);
-
- ruby_opt_init(opt);
- ruby_set_script_name(progname);
- rb_parser_set_options(parser, opt->do_print, opt->do_loop,
- opt->do_line, opt->do_split);
- ast_value = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
- }
- else {
- VALUE f;
- int xflag = opt->xflag;
- f = open_load_file(opt->script_name, &xflag);
- opt->xflag = xflag != 0;
- rb_parser_set_context(parser, 0, f == rb_stdin);
- ast_value = load_file(parser, opt->script_name, f, 1, opt);
- }
- ast = rb_ruby_ast_data_get(ast_value);
- if (!ast->body.root) {
- rb_ast_dispose(ast);
- return Qnil;
- }
- return ast_value;
-}
-
-static uint8_t
-prism_script_command_line(ruby_cmdline_options_t *opt)
-{
- uint8_t command_line = 0;
- if (opt->do_split) command_line |= PM_OPTIONS_COMMAND_LINE_A;
- if (opt->do_line) command_line |= PM_OPTIONS_COMMAND_LINE_L;
- if (opt->do_loop) command_line |= PM_OPTIONS_COMMAND_LINE_N;
- if (opt->do_print) command_line |= PM_OPTIONS_COMMAND_LINE_P;
- if (opt->xflag) command_line |= PM_OPTIONS_COMMAND_LINE_X;
- return command_line;
-}
-
-static void
-prism_script_shebang_callback(pm_options_t *options, const uint8_t *source, size_t length, void *data)
-{
- ruby_cmdline_options_t *opt = (ruby_cmdline_options_t *) data;
- opt->warning = 0;
-
- char *switches = malloc(length + 1);
- memcpy(switches, source, length);
- switches[length] = '\0';
-
- int no_src_enc = !opt->src.enc.name;
- int no_ext_enc = !opt->ext.enc.name;
- int no_int_enc = !opt->intern.enc.name;
-
- moreswitches(switches, opt, 0);
- free(switches);
-
- pm_options_command_line_set(options, prism_script_command_line(opt));
-
- if (no_src_enc && opt->src.enc.name) {
- opt->src.enc.index = opt_enc_index(opt->src.enc.name);
- pm_options_encoding_set(options, StringValueCStr(opt->ext.enc.name));
- }
- if (no_ext_enc && opt->ext.enc.name) {
- opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
- }
- if (no_int_enc && opt->intern.enc.name) {
- opt->intern.enc.index = opt_enc_index(opt->intern.enc.name);
- }
-}
-
-/**
- * Process the command line options and parse the script into the given result.
- * Raise an error if the script cannot be parsed.
- */
-static void
-prism_script(ruby_cmdline_options_t *opt, pm_parse_result_t *result)
-{
- memset(result, 0, sizeof(pm_parse_result_t));
-
- pm_options_t *options = &result->options;
- pm_options_line_set(options, 1);
- pm_options_main_script_set(options, true);
-
- const bool read_stdin = (strcmp(opt->script, "-") == 0);
-
- if (read_stdin) {
- pm_options_encoding_set(options, rb_enc_name(rb_locale_encoding()));
- }
- if (opt->src.enc.name != 0) {
- pm_options_encoding_set(options, StringValueCStr(opt->src.enc.name));
- }
-
- uint8_t command_line = prism_script_command_line(opt);
- VALUE error;
-
- if (read_stdin) {
- pm_options_command_line_set(options, command_line);
- pm_options_filepath_set(options, "-");
- pm_options_shebang_callback_set(options, prism_script_shebang_callback, (void *) opt);
-
- ruby_opt_init(opt);
- error = pm_parse_stdin(result);
-
- // If we found an __END__ marker, then we're going to define a global
- // DATA constant that is a file object that can be read to read the
- // contents after the marker.
- if (NIL_P(error) && result->parser.data_loc.start != NULL) {
- rb_define_global_const("DATA", rb_stdin);
- }
- }
- else if (opt->e_script) {
- command_line = (uint8_t) ((command_line | PM_OPTIONS_COMMAND_LINE_E) & ~PM_OPTIONS_COMMAND_LINE_X);
- pm_options_command_line_set(options, command_line);
-
- ruby_opt_init(opt);
- result->node.coverage_enabled = 0;
- error = pm_parse_string(result, opt->e_script, rb_str_new2("-e"), NULL);
- }
- else {
- VALUE script_name = rb_str_encode_ospath(opt->script_name);
-
- pm_options_command_line_set(options, command_line);
- pm_options_shebang_callback_set(options, prism_script_shebang_callback, (void *) opt);
-
- error = pm_load_file(result, script_name, true);
-
- // If reading the file did not error, at that point we load the command
- // line options. We do it in this order so that if the main script fails
- // to load, it doesn't require files required by -r.
- if (NIL_P(error)) {
- ruby_opt_init(opt);
- error = pm_parse_file(result, opt->script_name, NULL);
- }
-
- // Check if (after requiring all of the files through -r flags) we have
- // coverage enabled and need to enable coverage on the main script.
- if (RTEST(rb_get_coverages())) {
- result->node.coverage_enabled = 1;
- }
-
- // If we found an __END__ marker, then we're going to define a global
- // DATA constant that is a file object that can be read to read the
- // contents after the marker.
- if (NIL_P(error) && result->parser.data_loc.start != NULL) {
- int xflag = opt->xflag;
- VALUE file = open_load_file(script_name, &xflag);
-
- const pm_parser_t *parser = &result->parser;
- size_t offset = parser->data_loc.start - parser->start + 7;
-
- if ((parser->start + offset < parser->end) && parser->start[offset] == '\r') offset++;
- if ((parser->start + offset < parser->end) && parser->start[offset] == '\n') offset++;
-
- rb_funcall(file, rb_intern_const("seek"), 2, SIZET2NUM(offset), INT2FIX(SEEK_SET));
- rb_define_global_const("DATA", file);
- }
- }
-
- if (!NIL_P(error)) {
- pm_parse_result_free(result);
- rb_exc_raise(error);
- }
-}
-
-static VALUE
-prism_dump_tree(pm_parse_result_t *result)
-{
- pm_buffer_t output_buffer = { 0 };
-
- pm_prettyprint(&output_buffer, &result->parser, result->node.ast_node);
- VALUE tree = rb_str_new(output_buffer.value, output_buffer.length);
- pm_buffer_free(&output_buffer);
- return tree;
-}
-
-static void
-process_options_global_setup(const ruby_cmdline_options_t *opt, const rb_iseq_t *iseq)
-{
- if (OPT_BACKTRACE_LENGTH_LIMIT_VALID_P(opt)) {
- rb_backtrace_length_limit = opt->backtrace_length_limit;
- }
-
- if (opt->do_loop) {
- rb_define_global_function("sub", rb_f_sub, -1);
- rb_define_global_function("gsub", rb_f_gsub, -1);
- rb_define_global_function("chop", rb_f_chop, 0);
- rb_define_global_function("chomp", rb_f_chomp, -1);
- }
-
- rb_define_readonly_boolean("$-p", opt->do_print);
- rb_define_readonly_boolean("$-l", opt->do_line);
- rb_define_readonly_boolean("$-a", opt->do_split);
-
- rb_gvar_ractor_local("$-p");
- rb_gvar_ractor_local("$-l");
- rb_gvar_ractor_local("$-a");
-
- if ((rb_e_script = opt->e_script) != 0) {
- rb_str_freeze(rb_e_script);
- rb_vm_register_global_object(opt->e_script);
- }
-
- rb_execution_context_t *ec = GET_EC();
- VALUE script = (opt->e_script ? opt->e_script : Qnil);
- rb_exec_event_hook_script_compiled(ec, iseq, script);
-}
-
static VALUE
process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
{
- VALUE ast_value = Qnil;
- struct {
- rb_ast_t *ast;
- pm_parse_result_t prism;
- } result = {0};
-#define dispose_result() \
- (result.ast ? rb_ast_dispose(result.ast) : pm_parse_result_free(&result.prism))
-
+ rb_ast_t *ast = 0;
+ VALUE parser;
+ VALUE script_name;
const rb_iseq_t *iseq;
rb_encoding *enc, *lenc;
#if UTF8_PATH
@@ -2306,11 +1840,62 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
const long loaded_before_enc = RARRAY_LEN(vm->loaded_features);
if (opt->dump & (DUMP_BIT(usage)|DUMP_BIT(help))) {
+ int tty = isatty(1);
const char *const progname =
(argc > 0 && argv && argv[0] ? argv[0] :
origarg.argc > 0 && origarg.argv && origarg.argv[0] ? origarg.argv[0] :
ruby_engine);
- show_help(progname, (opt->dump & DUMP_BIT(help)));
+ int columns = 0;
+ if ((opt->dump & DUMP_BIT(help)) && tty) {
+ const char *pager_env = getenv("RUBY_PAGER");
+ if (!pager_env) pager_env = getenv("PAGER");
+ if (pager_env && *pager_env && isatty(0)) {
+ const char *columns_env = getenv("COLUMNS");
+ if (columns_env) columns = atoi(columns_env);
+ VALUE pager = rb_str_new_cstr(pager_env);
+#ifdef HAVE_WORKING_FORK
+ int fds[2];
+ if (rb_pipe(fds) == 0) {
+ rb_pid_t pid = rb_fork();
+ if (pid > 0) {
+ /* exec PAGER with reading from child */
+ dup2(fds[0], 0);
+ }
+ else if (pid == 0) {
+ /* send the help message to the parent PAGER */
+ dup2(fds[1], 1);
+ dup2(fds[1], 2);
+ }
+ close(fds[0]);
+ close(fds[1]);
+ if (pid > 0) {
+ setup_pager_env();
+ rb_f_exec(1, &pager);
+ kill(SIGTERM, pid);
+ rb_waitpid(pid, 0, 0);
+ }
+ }
+#else
+ setup_pager_env();
+ VALUE port = rb_io_popen(pager, rb_str_new_lit("w"), Qnil, Qnil);
+ if (!NIL_P(port)) {
+ int oldout = dup(1);
+ int olderr = dup(2);
+ int fd = RFILE(port)->fptr->fd;
+ tty = tty_enabled();
+ dup2(fd, 1);
+ dup2(fd, 2);
+ usage(progname, 1, tty, columns);
+ fflush(stdout);
+ dup2(oldout, 1);
+ dup2(olderr, 2);
+ rb_io_close(port);
+ return Qtrue;
+ }
+#endif
+ }
+ }
+ usage(progname, (opt->dump & DUMP_BIT(help)), tty, columns);
return Qtrue;
}
@@ -2318,7 +1903,22 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
argv += i;
if (FEATURE_SET_P(opt->features, rubyopt) && (s = getenv("RUBYOPT"))) {
+ VALUE src_enc_name = opt->src.enc.name;
+ VALUE ext_enc_name = opt->ext.enc.name;
+ VALUE int_enc_name = opt->intern.enc.name;
+ ruby_features_t feat = opt->features;
+ ruby_features_t warn = opt->warn;
+
+ opt->src.enc.name = opt->ext.enc.name = opt->intern.enc.name = 0;
moreswitches(s, opt, 1);
+ if (src_enc_name)
+ opt->src.enc.name = src_enc_name;
+ if (ext_enc_name)
+ opt->ext.enc.name = ext_enc_name;
+ if (int_enc_name)
+ opt->intern.enc.name = int_enc_name;
+ FEATURE_SET_RESTORE(opt->features, feat);
+ FEATURE_SET_RESTORE(opt->warn, warn);
}
if (opt->src.enc.name)
@@ -2335,25 +1935,21 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
#endif
}
if (MULTI_BITS_P(FEATURE_SET_BITS(opt->features) & feature_jit_mask)) {
- rb_warn("RJIT and YJIT cannot both be enabled at the same time. Exiting");
+ rb_warn("MJIT and YJIT cannot both be enabled at the same time. Exiting");
return Qfalse;
}
-#if USE_RJIT
- if (FEATURE_SET_P(opt->features, rjit)) {
- opt->rjit.on = true; // set opt->rjit.on for Init_ruby_description() and calling rb_rjit_init()
+#if USE_MJIT
+ if (FEATURE_SET_P(opt->features, mjit)) {
+ opt->mjit.on = true; // set opt->mjit.on for Init_ruby_description() and calling mjit_init()
}
#endif
#if USE_YJIT
if (FEATURE_SET_P(opt->features, yjit)) {
- bool rb_yjit_option_disable(void);
- opt->yjit = !rb_yjit_option_disable(); // set opt->yjit for Init_ruby_description() and calling rb_yjit_init()
+ opt->yjit = true; // set opt->yjit for Init_ruby_description() and calling rb_yjit_init()
}
#endif
-
- ruby_mn_threads_params();
Init_ruby_description(opt);
-
if (opt->dump & (DUMP_BIT(version) | DUMP_BIT(version_v))) {
ruby_show_version();
if (opt->dump & DUMP_BIT(version)) return Qtrue;
@@ -2400,6 +1996,8 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
#ifdef _WIN32
translit_char_bin(RSTRING_PTR(opt->script_name), '\\', '/');
+#elif defined DOSISH
+ translit_char(RSTRING_PTR(opt->script_name), '\\', '/');
#endif
ruby_gc_set_params();
@@ -2409,6 +2007,13 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
lenc = rb_locale_encoding();
rb_enc_associate(rb_progname, lenc);
rb_obj_freeze(rb_progname);
+ parser = rb_parser_new();
+ if (opt->dump & DUMP_BIT(yydebug)) {
+ rb_parser_set_yydebug(parser, Qtrue);
+ }
+ if (opt->dump & DUMP_BIT(error_tolerant)) {
+ rb_parser_error_tolerant(parser);
+ }
if (opt->ext.enc.name != 0) {
opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
}
@@ -2434,6 +2039,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
ienc = enc;
#endif
}
+ script_name = opt->script_name;
rb_enc_associate(opt->script_name, IF_UTF8_PATH(uenc, lenc));
#if UTF8_PATH
if (uenc != lenc) {
@@ -2492,19 +2098,19 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
#define SET_COMPILE_OPTION(h, o, name) \
rb_hash_aset((h), ID2SYM(rb_intern_const(#name)), \
RBOOL(FEATURE_SET_P(o->features, name)))
-
- if (FEATURE_SET_P(opt->features, frozen_string_literal_set)) {
- SET_COMPILE_OPTION(option, opt, frozen_string_literal);
- }
+ SET_COMPILE_OPTION(option, opt, frozen_string_literal);
SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
rb_funcallv(rb_cISeq, rb_intern_const("compile_option="), 1, &option);
#undef SET_COMPILE_OPTION
}
ruby_set_argv(argc, argv);
- opt->sflag = process_sflag(opt->sflag);
+ process_sflag(&opt->sflag);
if (opt->e_script) {
+ VALUE progname = rb_progname;
rb_encoding *eenc;
+ rb_parser_set_context(parser, 0, TRUE);
+
if (opt->src.enc.index >= 0) {
eenc = rb_enc_from_index(opt->src.enc.index);
}
@@ -2520,19 +2126,22 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
}
#endif
rb_enc_associate(opt->e_script, eenc);
- }
-
- if (!rb_ruby_prism_p()) {
- ast_value = process_script(opt);
- if (!(result.ast = rb_ruby_ast_data_get(ast_value))) return Qfalse;
+ ruby_opt_init(opt);
+ ruby_set_script_name(progname);
+ rb_parser_set_options(parser, opt->do_print, opt->do_loop,
+ opt->do_line, opt->do_split);
+ ast = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
}
else {
- prism_script(opt, &result.prism);
+ VALUE f;
+ f = open_load_file(script_name, &opt->xflag);
+ rb_parser_set_context(parser, 0, f == rb_stdin);
+ ast = load_file(parser, opt->script_name, f, 1, opt);
}
ruby_set_script_name(opt->script_name);
- if ((dump & DUMP_BIT(yydebug)) && !(dump &= ~DUMP_BIT(yydebug))) {
- dispose_result();
- return Qtrue;
+ if (dump & DUMP_BIT(yydebug)) {
+ dump &= ~DUMP_BIT(yydebug);
+ if (!dump) return Qtrue;
}
if (opt->ext.enc.index >= 0) {
@@ -2552,7 +2161,12 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
rb_enc_set_default_internal(Qnil);
rb_stdio_set_default_encoding();
- opt->sflag = process_sflag(opt->sflag);
+ if (!ast->body.root) {
+ rb_ast_dispose(ast);
+ return Qfalse;
+ }
+
+ process_sflag(&opt->sflag);
opt->xflag = 0;
if (dump & DUMP_BIT(syntax)) {
@@ -2561,20 +2175,19 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
if (!dump) return Qtrue;
}
- if (dump & DUMP_BIT(parsetree)) {
- VALUE tree;
- if (result.ast) {
- int comment = opt->dump & DUMP_BIT(opt_comment);
- tree = rb_parser_dump_tree(result.ast->body.root, comment);
- }
- else {
- tree = prism_dump_tree(&result.prism);
- }
- rb_io_write(rb_stdout, tree);
+ if (opt->do_loop) {
+ rb_define_global_function("sub", rb_f_sub, -1);
+ rb_define_global_function("gsub", rb_f_gsub, -1);
+ rb_define_global_function("chop", rb_f_chop, 0);
+ rb_define_global_function("chomp", rb_f_chomp, -1);
+ }
+
+ if (dump & (DUMP_BIT(parsetree)|DUMP_BIT(parsetree_with_comment))) {
+ rb_io_write(rb_stdout, rb_parser_dump_tree(ast->body.root, dump & DUMP_BIT(parsetree_with_comment)));
rb_io_flush(rb_stdout);
- dump &= ~DUMP_BIT(parsetree);
+ dump &= ~DUMP_BIT(parsetree)&~DUMP_BIT(parsetree_with_comment);
if (!dump) {
- dispose_result();
+ rb_ast_dispose(ast);
return Qtrue;
}
}
@@ -2582,7 +2195,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
{
VALUE path = Qnil;
if (!opt->e_script && strcmp(opt->script, "-")) {
- path = rb_realpath_internal(Qnil, opt->script_name, 1);
+ path = rb_realpath_internal(Qnil, script_name, 1);
#if UTF8_PATH
if (uenc != lenc) {
path = str_conv_enc(path, uenc, lenc);
@@ -2594,24 +2207,14 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
}
rb_binding_t *toplevel_binding;
- GetBindingPtr(rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING")), toplevel_binding);
+ GetBindingPtr(rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING")),
+ toplevel_binding);
const struct rb_block *base_block = toplevel_context(toplevel_binding);
- const rb_iseq_t *parent = vm_block_iseq(base_block);
- bool optimize = (opt->dump & DUMP_BIT(opt_optimize)) != 0;
-
- if (!result.ast) {
- pm_parse_result_t *pm = &result.prism;
- iseq = pm_iseq_new_main(&pm->node, opt->script_name, path, parent, optimize);
- pm_parse_result_free(pm);
- }
- else {
- rb_ast_t *ast = result.ast;
- iseq = rb_iseq_new_main(ast_value, opt->script_name, path, parent, optimize);
- rb_ast_dispose(ast);
- }
+ iseq = rb_iseq_new_main(&ast->body, opt->script_name, path, vm_block_iseq(base_block), !(dump & DUMP_BIT(insns_without_opt)));
+ rb_ast_dispose(ast);
}
- if (dump & DUMP_BIT(insns)) {
+ if (dump & (DUMP_BIT(insns) | DUMP_BIT(insns_without_opt))) {
rb_io_write(rb_stdout, rb_iseq_disasm((const rb_iseq_t *)iseq));
rb_io_flush(rb_stdout);
dump &= ~DUMP_BIT(insns);
@@ -2619,7 +2222,31 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
}
if (opt->dump & dump_exit_bits) return Qtrue;
- process_options_global_setup(opt, iseq);
+ rb_define_readonly_boolean("$-p", opt->do_print);
+ rb_define_readonly_boolean("$-l", opt->do_line);
+ rb_define_readonly_boolean("$-a", opt->do_split);
+
+ rb_gvar_ractor_local("$-p");
+ rb_gvar_ractor_local("$-l");
+ rb_gvar_ractor_local("$-a");
+
+ if ((rb_e_script = opt->e_script) != 0) {
+ rb_str_freeze(rb_e_script);
+ rb_gc_register_mark_object(opt->e_script);
+ }
+
+ {
+ rb_execution_context_t *ec = GET_EC();
+
+ if (opt->e_script) {
+ /* -e */
+ rb_exec_event_hook_script_compiled(ec, iseq, opt->e_script);
+ }
+ else {
+ /* file */
+ rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
+ }
+ }
return (VALUE)iseq;
}
@@ -2627,7 +2254,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
static void
warn_cr_in_shebang(const char *str, long len)
{
- if (len > 1 && str[len-1] == '\n' && str[len-2] == '\r') {
+ if (str[len-1] == '\n' && str[len-2] == '\r') {
rb_warn("shebang line ending with \\r may cause problems");
}
}
@@ -2645,8 +2272,6 @@ struct load_file_arg {
VALUE f;
};
-void rb_set_script_lines_for(VALUE vparser, VALUE path);
-
static VALUE
load_file_internal(VALUE argp_v)
{
@@ -2657,7 +2282,7 @@ load_file_internal(VALUE argp_v)
ruby_cmdline_options_t *opt = argp->opt;
VALUE f = argp->f;
int line_start = 1;
- VALUE ast_value = Qnil;
+ rb_ast_t *ast = 0;
rb_encoding *enc;
ID set_encoding;
@@ -2749,16 +2374,13 @@ load_file_internal(VALUE argp_v)
}
rb_parser_set_options(parser, opt->do_print, opt->do_loop,
opt->do_line, opt->do_split);
-
- rb_set_script_lines_for(parser, orig_fname);
-
if (NIL_P(f)) {
f = rb_str_new(0, 0);
rb_enc_associate(f, enc);
- return rb_parser_compile_string_path(parser, orig_fname, f, line_start);
+ return (VALUE)rb_parser_compile_string_path(parser, orig_fname, f, line_start);
}
rb_funcall(f, set_encoding, 2, rb_enc_from_encoding(enc), rb_str_new_cstr("-"));
- ast_value = rb_parser_compile_file_path(parser, orig_fname, f, line_start);
+ ast = rb_parser_compile_file_path(parser, orig_fname, f, line_start);
rb_funcall(f, set_encoding, 1, rb_parser_encoding(parser));
if (script && rb_parser_end_seen_p(parser)) {
/*
@@ -2776,7 +2398,7 @@ load_file_internal(VALUE argp_v)
rb_define_global_const("DATA", f);
argp->f = Qnil;
}
- return ast_value;
+ return (VALUE)ast;
}
/* disabling O_NONBLOCK, and returns 0 on success, otherwise errno */
@@ -2885,7 +2507,7 @@ restore_load_file(VALUE arg)
return Qnil;
}
-static VALUE
+static rb_ast_t *
load_file(VALUE parser, VALUE fname, VALUE f, int script, ruby_cmdline_options_t *opt)
{
struct load_file_arg arg;
@@ -2894,7 +2516,7 @@ load_file(VALUE parser, VALUE fname, VALUE f, int script, ruby_cmdline_options_t
arg.script = script;
arg.opt = opt;
arg.f = f;
- return rb_ensure(load_file_internal, (VALUE)&arg,
+ return (rb_ast_t *)rb_ensure(load_file_internal, (VALUE)&arg,
restore_load_file, (VALUE)&arg);
}
@@ -2908,18 +2530,14 @@ rb_load_file(const char *fname)
void *
rb_load_file_str(VALUE fname_v)
{
- VALUE ast_value;
- ast_value = rb_parser_load_file(rb_parser_new(), fname_v);
- return (void *)rb_ruby_ast_data_get(ast_value);
+ return rb_parser_load_file(rb_parser_new(), fname_v);
}
-VALUE
+void *
rb_parser_load_file(VALUE parser, VALUE fname_v)
{
ruby_cmdline_options_t opt;
- int xflag = 0;
- VALUE f = open_load_file(fname_v, &xflag);
- cmdline_options_init(&opt)->xflag = xflag != 0;
+ VALUE f = open_load_file(fname_v, &cmdline_options_init(&opt)->xflag);
return load_file(parser, fname_v, f, 0, &opt);
}
@@ -2994,18 +2612,12 @@ external_str_new_cstr(const char *p)
#endif
}
-static void
-set_progname(VALUE name)
-{
- rb_orig_progname = rb_progname = name;
- rb_vm_set_progname(rb_progname);
-}
-
void
ruby_script(const char *name)
{
if (name) {
- set_progname(rb_str_freeze(external_str_new_cstr(name)));
+ rb_orig_progname = rb_progname = external_str_new_cstr(name);
+ rb_vm_set_progname(rb_progname);
}
}
@@ -3016,7 +2628,8 @@ ruby_script(const char *name)
void
ruby_set_script_name(VALUE name)
{
- set_progname(rb_str_new_frozen(name));
+ rb_orig_progname = rb_progname = rb_str_dup(name);
+ rb_vm_set_progname(rb_progname);
}
static void
@@ -3140,26 +2753,15 @@ ruby_process_options(int argc, char **argv)
origarg.argc = argc;
origarg.argv = argv;
}
- set_progname(external_str_new_cstr(script_name)); /* for the time being */
+ ruby_script(script_name); /* for the time being */
rb_argv0 = rb_str_new4(rb_progname);
- rb_vm_register_global_object(rb_argv0);
+ rb_gc_register_mark_object(rb_argv0);
+ iseq = process_options(argc, argv, cmdline_options_init(&opt));
#ifndef HAVE_SETPROCTITLE
ruby_init_setproctitle(argc, argv);
#endif
- iseq = process_options(argc, argv, cmdline_options_init(&opt));
-
- if (opt.crash_report && *opt.crash_report) {
- void ruby_set_crash_report(const char *template);
- ruby_set_crash_report(opt.crash_report);
- }
-
- if (getenv("RUBY_FREE_AT_EXIT")) {
- rb_free_at_exit = true;
- rb_category_warn(RB_WARN_CATEGORY_EXPERIMENTAL, "Free at exit is experimental and may be unstable");
- }
-
return (void*)(struct RData*)iseq;
}
diff --git a/ruby_parser.c b/ruby_parser.c
deleted file mode 100644
index 314890c0af..0000000000
--- a/ruby_parser.c
+++ /dev/null
@@ -1,1135 +0,0 @@
-/* This is a wrapper for parse.y */
-
-#include "internal/parse.h"
-#include "internal/re.h"
-#include "internal/ruby_parser.h"
-
-#include "node.h"
-#include "rubyparser.h"
-#include "internal/error.h"
-
-#ifdef UNIVERSAL_PARSER
-
-#include "internal.h"
-#include "internal/array.h"
-#include "internal/bignum.h"
-#include "internal/compile.h"
-#include "internal/complex.h"
-#include "internal/encoding.h"
-#include "internal/gc.h"
-#include "internal/hash.h"
-#include "internal/io.h"
-#include "internal/rational.h"
-#include "internal/re.h"
-#include "internal/string.h"
-#include "internal/symbol.h"
-#include "internal/thread.h"
-
-#include "ruby/ractor.h"
-#include "ruby/ruby.h"
-#include "ruby/util.h"
-#include "internal.h"
-#include "vm_core.h"
-#include "symbol.h"
-
-#define parser_encoding const void
-
-RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 6, 0)
-static VALUE
-syntax_error_append(VALUE exc, VALUE file, int line, int column,
- parser_encoding *enc, const char *fmt, va_list args)
-{
- return rb_syntax_error_append(exc, file, line, column, enc, fmt, args);
-}
-
-static int
-local_defined(ID id, const void *p)
-{
- return rb_local_defined(id, (const rb_iseq_t *)p);
-}
-
-static int
-dvar_defined(ID id, const void *p)
-{
- return rb_dvar_defined(id, (const rb_iseq_t *)p);
-}
-
-static int
-is_usascii_enc(parser_encoding *enc)
-{
- return rb_is_usascii_enc(enc);
-}
-
-static int
-is_local_id2(ID id)
-{
- return is_local_id(id);
-}
-
-static int
-is_attrset_id2(ID id)
-{
- return is_attrset_id(id);
-}
-
-static int
-is_notop_id2(ID id)
-{
- return is_notop_id(id);
-}
-
-static VALUE
-enc_str_new(const char *ptr, long len, parser_encoding *enc)
-{
- return rb_enc_str_new(ptr, len, enc);
-}
-
-static int
-enc_isalnum(OnigCodePoint c, parser_encoding *enc)
-{
- return rb_enc_isalnum(c, enc);
-}
-
-static int
-enc_precise_mbclen(const char *p, const char *e, parser_encoding *enc)
-{
- return rb_enc_precise_mbclen(p, e, enc);
-}
-
-static int
-mbclen_charfound_p(int len)
-{
- return MBCLEN_CHARFOUND_P(len);
-}
-
-static int
-mbclen_charfound_len(int len)
-{
- return MBCLEN_CHARFOUND_LEN(len);
-}
-
-static const char *
-enc_name(parser_encoding *enc)
-{
- return rb_enc_name(enc);
-}
-
-static char *
-enc_prev_char(const char *s, const char *p, const char *e, parser_encoding *enc)
-{
- return rb_enc_prev_char(s, p, e, enc);
-}
-
-static parser_encoding *
-enc_get(VALUE obj)
-{
- return rb_enc_get(obj);
-}
-
-static int
-enc_asciicompat(parser_encoding *enc)
-{
- return rb_enc_asciicompat(enc);
-}
-
-static parser_encoding *
-utf8_encoding(void)
-{
- return rb_utf8_encoding();
-}
-
-static VALUE
-enc_associate(VALUE obj, parser_encoding *enc)
-{
- return rb_enc_associate(obj, enc);
-}
-
-static parser_encoding *
-ascii8bit_encoding(void)
-{
- return rb_ascii8bit_encoding();
-}
-
-static int
-enc_codelen(int c, parser_encoding *enc)
-{
- return rb_enc_codelen(c, enc);
-}
-
-static int
-enc_mbcput(unsigned int c, void *buf, parser_encoding *enc)
-{
- return rb_enc_mbcput(c, buf, enc);
-}
-
-static parser_encoding *
-enc_from_index(int idx)
-{
- return rb_enc_from_index(idx);
-}
-
-static int
-enc_isspace(OnigCodePoint c, parser_encoding *enc)
-{
- return rb_enc_isspace(c, enc);
-}
-
-static ID
-intern3(const char *name, long len, parser_encoding *enc)
-{
- return rb_intern3(name, len, enc);
-}
-
-static parser_encoding *
-usascii_encoding(void)
-{
- return rb_usascii_encoding();
-}
-
-static int
-enc_symname_type(const char *name, long len, parser_encoding *enc, unsigned int allowed_attrset)
-{
- return rb_enc_symname_type(name, len, enc, allowed_attrset);
-}
-
-typedef struct {
- struct parser_params *parser;
- rb_encoding *enc;
- NODE *succ_block;
- const rb_code_location_t *loc;
-} reg_named_capture_assign_t;
-
-static int
-reg_named_capture_assign_iter(const OnigUChar *name, const OnigUChar *name_end,
- int back_num, int *back_refs, OnigRegex regex, void *arg0)
-{
- reg_named_capture_assign_t *arg = (reg_named_capture_assign_t*)arg0;
- struct parser_params* p = arg->parser;
- rb_encoding *enc = arg->enc;
- const rb_code_location_t *loc = arg->loc;
- long len = name_end - name;
- const char *s = (const char *)name;
-
- return rb_reg_named_capture_assign_iter_impl(p, s, len, enc, &arg->succ_block, loc);
-}
-
-static NODE *
-reg_named_capture_assign(struct parser_params* p, VALUE regexp, const rb_code_location_t *loc)
-{
- reg_named_capture_assign_t arg;
-
- arg.parser = p;
- arg.enc = rb_enc_get(regexp);
- arg.succ_block = 0;
- arg.loc = loc;
- onig_foreach_name(RREGEXP_PTR(regexp), reg_named_capture_assign_iter, &arg);
-
- if (!arg.succ_block) return 0;
- return RNODE_BLOCK(arg.succ_block)->nd_next;
-}
-
-static int
-rtest(VALUE obj)
-{
- return (int)RB_TEST(obj);
-}
-
-static int
-nil_p(VALUE obj)
-{
- return (int)NIL_P(obj);
-}
-
-static VALUE
-syntax_error_new(void)
-{
- return rb_class_new_instance(0, 0, rb_eSyntaxError);
-}
-
-static void *
-memmove2(void *dest, const void *src, size_t t, size_t n)
-{
- return memmove(dest, src, rbimpl_size_mul_or_raise(t, n));
-}
-
-static void *
-nonempty_memcpy(void *dest, const void *src, size_t t, size_t n)
-{
- return ruby_nonempty_memcpy(dest, src, rbimpl_size_mul_or_raise(t, n));
-}
-
-static VALUE
-ruby_verbose2(void)
-{
- return ruby_verbose;
-}
-
-static int *
-rb_errno_ptr2(void)
-{
- return rb_errno_ptr();
-}
-
-static void *
-zalloc(size_t elemsiz)
-{
- return ruby_xcalloc(1, elemsiz);
-}
-
-static void
-gc_guard(VALUE obj)
-{
- RB_GC_GUARD(obj);
-}
-
-static VALUE
-arg_error(void)
-{
- return rb_eArgError;
-}
-
-static VALUE
-static_id2sym(ID id)
-{
- return (((VALUE)(id)<<RUBY_SPECIAL_SHIFT)|SYMBOL_FLAG);
-}
-
-static long
-str_coderange_scan_restartable(const char *s, const char *e, parser_encoding *enc, int *cr)
-{
- return rb_str_coderange_scan_restartable(s, e, enc, cr);
-}
-
-static int
-enc_mbminlen(parser_encoding *enc)
-{
- return rb_enc_mbminlen(enc);
-}
-
-static bool
-enc_isascii(OnigCodePoint c, parser_encoding *enc)
-{
- return rb_enc_isascii(c, enc);
-}
-
-static OnigCodePoint
-enc_mbc_to_codepoint(const char *p, const char *e, parser_encoding *enc)
-{
- const OnigUChar *up = RBIMPL_CAST((const OnigUChar *)p);
- const OnigUChar *ue = RBIMPL_CAST((const OnigUChar *)e);
-
- return ONIGENC_MBC_TO_CODE((rb_encoding *)enc, up, ue);
-}
-
-extern VALUE rb_eArgError;
-
-static const rb_parser_config_t rb_global_parser_config = {
- .malloc = ruby_xmalloc,
- .calloc = ruby_xcalloc,
- .realloc = ruby_xrealloc,
- .free = ruby_xfree,
- .alloc_n = ruby_xmalloc2,
- .alloc = ruby_xmalloc,
- .realloc_n = ruby_xrealloc2,
- .zalloc = zalloc,
- .rb_memmove = memmove2,
- .nonempty_memcpy = nonempty_memcpy,
- .xmalloc_mul_add = rb_xmalloc_mul_add,
-
- .compile_callback = rb_suppress_tracing,
- .reg_named_capture_assign = reg_named_capture_assign,
-
- .attr_get = rb_attr_get,
-
- .ary_new = rb_ary_new,
- .ary_push = rb_ary_push,
- .ary_new_from_args = rb_ary_new_from_args,
- .ary_unshift = rb_ary_unshift,
-
- .make_temporary_id = rb_make_temporary_id,
- .is_local_id = is_local_id2,
- .is_attrset_id = is_attrset_id2,
- .is_global_name_punct = is_global_name_punct,
- .id_type = id_type,
- .id_attrset = rb_id_attrset,
- .intern = rb_intern,
- .intern2 = rb_intern2,
- .intern3 = intern3,
- .intern_str = rb_intern_str,
- .is_notop_id = is_notop_id2,
- .enc_symname_type = enc_symname_type,
- .id2name = rb_id2name,
- .id2str = rb_id2str,
- .id2sym = rb_id2sym,
- .sym2id = rb_sym2id,
-
- .str_catf = rb_str_catf,
- .str_cat_cstr = rb_str_cat_cstr,
- .str_resize = rb_str_resize,
- .str_new = rb_str_new,
- .str_new_cstr = rb_str_new_cstr,
- .str_to_interned_str = rb_str_to_interned_str,
- .enc_str_new = enc_str_new,
- .str_vcatf = rb_str_vcatf,
- .rb_sprintf = rb_sprintf,
- .rstring_ptr = RSTRING_PTR,
- .rstring_len = RSTRING_LEN,
- .obj_as_string = rb_obj_as_string,
-
- .int2num = rb_int2num_inline,
-
- .stderr_tty_p = rb_stderr_tty_p,
- .write_error_str = rb_write_error_str,
- .io_write = rb_io_write,
- .io_flush = rb_io_flush,
- .io_puts = rb_io_puts,
-
- .debug_output_stdout = rb_ractor_stdout,
- .debug_output_stderr = rb_ractor_stderr,
-
- .is_usascii_enc = is_usascii_enc,
- .enc_isalnum = enc_isalnum,
- .enc_precise_mbclen = enc_precise_mbclen,
- .mbclen_charfound_p = mbclen_charfound_p,
- .mbclen_charfound_len = mbclen_charfound_len,
- .enc_name = enc_name,
- .enc_prev_char = enc_prev_char,
- .enc_get = enc_get,
- .enc_asciicompat = enc_asciicompat,
- .utf8_encoding = utf8_encoding,
- .enc_associate = enc_associate,
- .ascii8bit_encoding = ascii8bit_encoding,
- .enc_codelen = enc_codelen,
- .enc_mbcput = enc_mbcput,
- .enc_find_index = rb_enc_find_index,
- .enc_from_index = enc_from_index,
- .enc_isspace = enc_isspace,
- .enc_coderange_7bit = ENC_CODERANGE_7BIT,
- .enc_coderange_unknown = ENC_CODERANGE_UNKNOWN,
- .usascii_encoding = usascii_encoding,
- .enc_mbminlen = enc_mbminlen,
- .enc_isascii = enc_isascii,
- .enc_mbc_to_codepoint = enc_mbc_to_codepoint,
-
- .local_defined = local_defined,
- .dvar_defined = dvar_defined,
-
- .syntax_error_append = syntax_error_append,
- .raise = rb_raise,
- .syntax_error_new = syntax_error_new,
-
- .errinfo = rb_errinfo,
- .set_errinfo = rb_set_errinfo,
- .exc_raise = rb_exc_raise,
- .make_exception = rb_make_exception,
-
- .sized_xfree = ruby_sized_xfree,
- .sized_realloc_n = ruby_sized_realloc_n,
- .gc_guard = gc_guard,
- .gc_mark = rb_gc_mark,
-
- .reg_compile = rb_reg_compile,
- .reg_check_preprocess = rb_reg_check_preprocess,
- .memcicmp = rb_memcicmp,
-
- .compile_warn = rb_compile_warn,
- .compile_warning = rb_compile_warning,
- .bug = rb_bug,
- .fatal = rb_fatal,
- .verbose = ruby_verbose2,
- .errno_ptr = rb_errno_ptr2,
-
- .make_backtrace = rb_make_backtrace,
-
- .scan_hex = ruby_scan_hex,
- .scan_oct = ruby_scan_oct,
- .scan_digits = ruby_scan_digits,
- .strtod = ruby_strtod,
-
- .rtest = rtest,
- .nil_p = nil_p,
- .qnil = Qnil,
- .qfalse = Qfalse,
- .eArgError = arg_error,
- .long2int = rb_long2int,
-
- /* For Ripper */
- .static_id2sym = static_id2sym,
- .str_coderange_scan_restartable = str_coderange_scan_restartable,
-};
-#endif
-
-enum lex_type {
- lex_type_str,
- lex_type_io,
- lex_type_array,
- lex_type_generic,
-};
-
-struct ruby_parser {
- rb_parser_t *parser_params;
- enum lex_type type;
- union {
- struct lex_pointer_string lex_str;
- struct {
- VALUE file;
- } lex_io;
- struct {
- VALUE ary;
- } lex_array;
- } data;
-};
-
-static void
-parser_mark(void *ptr)
-{
- struct ruby_parser *parser = (struct ruby_parser*)ptr;
- rb_ruby_parser_mark(parser->parser_params);
-
- switch (parser->type) {
- case lex_type_str:
- rb_gc_mark(parser->data.lex_str.str);
- break;
- case lex_type_io:
- rb_gc_mark(parser->data.lex_io.file);
- break;
- case lex_type_array:
- rb_gc_mark(parser->data.lex_array.ary);
- break;
- case lex_type_generic:
- /* noop. Caller of rb_parser_compile_generic should mark the objects. */
- break;
- }
-}
-
-static void
-parser_free(void *ptr)
-{
- struct ruby_parser *parser = (struct ruby_parser*)ptr;
- rb_ruby_parser_free(parser->parser_params);
- xfree(parser);
-}
-
-static size_t
-parser_memsize(const void *ptr)
-{
- struct ruby_parser *parser = (struct ruby_parser*)ptr;
- return rb_ruby_parser_memsize(parser->parser_params);
-}
-
-static const rb_data_type_t ruby_parser_data_type = {
- "parser",
- {
- parser_mark,
- parser_free,
- parser_memsize,
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
-};
-
-#ifdef UNIVERSAL_PARSER
-const rb_parser_config_t *
-rb_ruby_parser_config(void)
-{
- return &rb_global_parser_config;
-}
-
-rb_parser_t *
-rb_parser_params_new(void)
-{
- return rb_ruby_parser_new(&rb_global_parser_config);
-}
-#else
-rb_parser_t *
-rb_parser_params_new(void)
-{
- return rb_ruby_parser_new();
-}
-#endif /* UNIVERSAL_PARSER */
-
-VALUE
-rb_parser_new(void)
-{
- struct ruby_parser *parser;
- rb_parser_t *parser_params;
-
- /*
- * Create parser_params ahead of vparser because
- * rb_ruby_parser_new can run GC so if create vparser
- * first, parser_mark tries to mark not initialized parser_params.
- */
- parser_params = rb_parser_params_new();
- VALUE vparser = TypedData_Make_Struct(0, struct ruby_parser,
- &ruby_parser_data_type, parser);
- parser->parser_params = parser_params;
-
- return vparser;
-}
-
-void
-rb_parser_set_options(VALUE vparser, int print, int loop, int chomp, int split)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_set_options(parser->parser_params, print, loop, chomp, split);
-}
-
-VALUE
-rb_parser_set_context(VALUE vparser, const struct rb_iseq_struct *base, int main)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_set_context(parser->parser_params, base, main);
- return vparser;
-}
-
-void
-rb_parser_set_script_lines(VALUE vparser)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_set_script_lines(parser->parser_params);
-}
-
-void
-rb_parser_error_tolerant(VALUE vparser)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_error_tolerant(parser->parser_params);
-}
-
-void
-rb_parser_keep_tokens(VALUE vparser)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_keep_tokens(parser->parser_params);
-}
-
-rb_parser_string_t *
-rb_parser_lex_get_str(struct parser_params *p, struct lex_pointer_string *ptr_str)
-{
- char *beg, *end, *start;
- long len;
- VALUE s = ptr_str->str;
-
- beg = RSTRING_PTR(s);
- len = RSTRING_LEN(s);
- start = beg;
- if (ptr_str->ptr) {
- if (len == ptr_str->ptr) return 0;
- beg += ptr_str->ptr;
- len -= ptr_str->ptr;
- }
- end = memchr(beg, '\n', len);
- if (end) len = ++end - beg;
- ptr_str->ptr += len;
- return rb_str_to_parser_string(p, rb_str_subseq(s, beg - start, len));
-}
-
-static rb_parser_string_t *
-lex_get_str(struct parser_params *p, rb_parser_input_data input, int line_count)
-{
- return rb_parser_lex_get_str(p, (struct lex_pointer_string *)input);
-}
-
-static void parser_aset_script_lines_for(VALUE path, rb_parser_ary_t *lines);
-
-static rb_ast_t*
-parser_compile(rb_parser_t *p, rb_parser_lex_gets_func *gets, VALUE fname, rb_parser_input_data input, int line)
-{
- rb_ast_t *ast = rb_parser_compile(p, gets, fname, input, line);
- parser_aset_script_lines_for(fname, ast->body.script_lines);
- return ast;
-}
-
-static rb_ast_t*
-parser_compile_string0(struct ruby_parser *parser, VALUE fname, VALUE s, int line)
-{
- VALUE str = rb_str_new_frozen(s);
-
- parser->type = lex_type_str;
- parser->data.lex_str.str = str;
- parser->data.lex_str.ptr = 0;
-
- return parser_compile(parser->parser_params, lex_get_str, fname, (rb_parser_input_data)&parser->data, line);
-}
-
-static rb_encoding *
-must_be_ascii_compatible(VALUE s)
-{
- rb_encoding *enc = rb_enc_get(s);
- if (!rb_enc_asciicompat(enc)) {
- rb_raise(rb_eArgError, "invalid source encoding");
- }
- return enc;
-}
-
-static rb_ast_t*
-parser_compile_string_path(struct ruby_parser *parser, VALUE f, VALUE s, int line)
-{
- must_be_ascii_compatible(s);
- return parser_compile_string0(parser, f, s, line);
-}
-
-static rb_ast_t*
-parser_compile_string(struct ruby_parser *parser, const char *f, VALUE s, int line)
-{
- return parser_compile_string_path(parser, rb_filesystem_str_new_cstr(f), s, line);
-}
-
-VALUE rb_io_gets_internal(VALUE io);
-
-static rb_parser_string_t *
-lex_io_gets(struct parser_params *p, rb_parser_input_data input, int line_count)
-{
- VALUE io = (VALUE)input;
- VALUE line = rb_io_gets_internal(io);
- if (NIL_P(line)) return 0;
- return rb_str_to_parser_string(p, line);
-}
-
-static rb_parser_string_t *
-lex_gets_array(struct parser_params *p, rb_parser_input_data data, int index)
-{
- VALUE array = (VALUE)data;
- VALUE str = rb_ary_entry(array, index);
- if (!NIL_P(str)) {
- StringValue(str);
- if (!rb_enc_asciicompat(rb_enc_get(str))) {
- rb_raise(rb_eArgError, "invalid source encoding");
- }
- return rb_str_to_parser_string(p, str);
- }
- else {
- return 0;
- }
-}
-
-static rb_ast_t*
-parser_compile_file_path(struct ruby_parser *parser, VALUE fname, VALUE file, int start)
-{
- parser->type = lex_type_io;
- parser->data.lex_io.file = file;
-
- return parser_compile(parser->parser_params, lex_io_gets, fname, (rb_parser_input_data)file, start);
-}
-
-static rb_ast_t*
-parser_compile_array(struct ruby_parser *parser, VALUE fname, VALUE array, int start)
-{
- parser->type = lex_type_array;
- parser->data.lex_array.ary = array;
-
- return parser_compile(parser->parser_params, lex_gets_array, fname, (rb_parser_input_data)array, start);
-}
-
-static rb_ast_t*
-parser_compile_generic(struct ruby_parser *parser, rb_parser_lex_gets_func *lex_gets, VALUE fname, VALUE input, int start)
-{
- parser->type = lex_type_generic;
-
- return parser_compile(parser->parser_params, lex_gets, fname, (rb_parser_input_data)input, start);
-}
-
-static void
-ast_free(void *ptr)
-{
- rb_ast_t *ast = (rb_ast_t *)ptr;
- rb_ast_free(ast);
-}
-
-static const rb_data_type_t ast_data_type = {
- "AST",
- {
- NULL,
- ast_free,
- NULL, // No dsize() because this object does not appear in ObjectSpace.
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
-};
-
-static VALUE
-ast_alloc(void)
-{
- return TypedData_Wrap_Struct(0, &ast_data_type, NULL);
-}
-
-VALUE
-rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE file, int start)
-{
- struct ruby_parser *parser;
- VALUE ast_value = ast_alloc();
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- DATA_PTR(ast_value) = parser_compile_file_path(parser, fname, file, start);
- RB_GC_GUARD(vparser);
-
- return ast_value;
-}
-
-VALUE
-rb_parser_compile_array(VALUE vparser, VALUE fname, VALUE array, int start)
-{
- struct ruby_parser *parser;
- VALUE ast_value = ast_alloc();
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- DATA_PTR(ast_value) = parser_compile_array(parser, fname, array, start);
- RB_GC_GUARD(vparser);
-
- return ast_value;
-}
-
-VALUE
-rb_parser_compile_generic(VALUE vparser, rb_parser_lex_gets_func *lex_gets, VALUE fname, VALUE input, int start)
-{
- struct ruby_parser *parser;
- VALUE ast_value = ast_alloc();
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- DATA_PTR(ast_value) = parser_compile_generic(parser, lex_gets, fname, input, start);
- RB_GC_GUARD(vparser);
-
- return ast_value;
-}
-
-VALUE
-rb_parser_compile_string(VALUE vparser, const char *f, VALUE s, int line)
-{
- struct ruby_parser *parser;
- VALUE ast_value = ast_alloc();
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- DATA_PTR(ast_value) = parser_compile_string(parser, f, s, line);
- RB_GC_GUARD(vparser);
-
- return ast_value;
-}
-
-VALUE
-rb_parser_compile_string_path(VALUE vparser, VALUE f, VALUE s, int line)
-{
- struct ruby_parser *parser;
- VALUE ast_value = ast_alloc();
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- DATA_PTR(ast_value) = parser_compile_string_path(parser, f, s, line);
- RB_GC_GUARD(vparser);
-
- return ast_value;
-}
-
-VALUE
-rb_parser_encoding(VALUE vparser)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- return rb_enc_from_encoding(rb_ruby_parser_encoding(parser->parser_params));
-}
-
-VALUE
-rb_parser_end_seen_p(VALUE vparser)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- return RBOOL(rb_ruby_parser_end_seen_p(parser->parser_params));
-}
-
-VALUE
-rb_parser_set_yydebug(VALUE vparser, VALUE flag)
-{
- struct ruby_parser *parser;
-
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_set_yydebug(parser->parser_params, RTEST(flag));
- return flag;
-}
-
-void
-rb_set_script_lines_for(VALUE vparser, VALUE path)
-{
- struct ruby_parser *parser;
- VALUE hash;
- ID script_lines;
- CONST_ID(script_lines, "SCRIPT_LINES__");
- if (!rb_const_defined_at(rb_cObject, script_lines)) return;
- hash = rb_const_get_at(rb_cObject, script_lines);
- if (RB_TYPE_P(hash, T_HASH)) {
- rb_hash_aset(hash, path, Qtrue);
- TypedData_Get_Struct(vparser, struct ruby_parser, &ruby_parser_data_type, parser);
- rb_ruby_parser_set_script_lines(parser->parser_params);
- }
-}
-
-VALUE
-rb_parser_build_script_lines_from(rb_parser_ary_t *lines)
-{
- int i;
- if (!lines) return Qnil;
- if (lines->data_type != PARSER_ARY_DATA_SCRIPT_LINE) {
- rb_bug("unexpected rb_parser_ary_data_type (%d) for script lines", lines->data_type);
- }
- VALUE script_lines = rb_ary_new_capa(lines->len);
- for (i = 0; i < lines->len; i++) {
- rb_parser_string_t *str = (rb_parser_string_t *)lines->data[i];
- rb_ary_push(script_lines, rb_enc_str_new(str->ptr, str->len, str->enc));
- }
- return script_lines;
-}
-
-VALUE
-rb_str_new_parser_string(rb_parser_string_t *str)
-{
- VALUE string = rb_enc_literal_str(str->ptr, str->len, str->enc);
- rb_enc_str_coderange(string);
- return string;
-}
-
-VALUE
-rb_str_new_mutable_parser_string(rb_parser_string_t *str)
-{
- return rb_enc_str_new(str->ptr, str->len, str->enc);
-}
-
-static VALUE
-negative_numeric(VALUE val)
-{
- if (FIXNUM_P(val)) {
- return LONG2FIX(-FIX2LONG(val));
- }
- if (SPECIAL_CONST_P(val)) {
-#if USE_FLONUM
- if (FLONUM_P(val)) {
- return DBL2NUM(-RFLOAT_VALUE(val));
- }
-#endif
- goto unknown;
- }
- switch (BUILTIN_TYPE(val)) {
- case T_BIGNUM:
- BIGNUM_NEGATE(val);
- val = rb_big_norm(val);
- break;
- case T_RATIONAL:
- RATIONAL_SET_NUM(val, negative_numeric(RRATIONAL(val)->num));
- break;
- case T_COMPLEX:
- RCOMPLEX_SET_REAL(val, negative_numeric(RCOMPLEX(val)->real));
- RCOMPLEX_SET_IMAG(val, negative_numeric(RCOMPLEX(val)->imag));
- break;
- case T_FLOAT:
- val = DBL2NUM(-RFLOAT_VALUE(val));
- break;
- unknown:
- default:
- rb_bug("unknown literal type (%s) passed to negative_numeric",
- rb_builtin_class_name(val));
- break;
- }
- return val;
-}
-
-static VALUE
-integer_value(const char *val, int base)
-{
- return rb_cstr_to_inum(val, base, FALSE);
-}
-
-static VALUE
-rational_value(const char *node_val, int base, int seen_point)
-{
- VALUE lit;
- char* val = strdup(node_val);
- if (seen_point > 0) {
- int len = (int)(strlen(val));
- char *point = &val[seen_point];
- size_t fraclen = len-seen_point-1;
- memmove(point, point+1, fraclen+1);
-
- lit = rb_rational_new(integer_value(val, base), rb_int_positive_pow(10, fraclen));
- }
- else {
- lit = rb_rational_raw1(integer_value(val, base));
- }
-
- free(val);
-
- return lit;
-}
-
-VALUE
-rb_node_integer_literal_val(const NODE *n)
-{
- const rb_node_integer_t *node = RNODE_INTEGER(n);
- VALUE val = integer_value(node->val, node->base);
- if (node->minus) {
- val = negative_numeric(val);
- }
- return val;
-}
-
-VALUE
-rb_node_float_literal_val(const NODE *n)
-{
- const rb_node_float_t *node = RNODE_FLOAT(n);
- double d = strtod(node->val, 0);
- if (node->minus) {
- d = -d;
- }
- VALUE val = DBL2NUM(d);
- return val;
-}
-
-VALUE
-rb_node_rational_literal_val(const NODE *n)
-{
- VALUE lit;
- const rb_node_rational_t *node = RNODE_RATIONAL(n);
-
- lit = rational_value(node->val, node->base, node->seen_point);
-
- if (node->minus) {
- lit = negative_numeric(lit);
- }
-
- return lit;
-}
-
-VALUE
-rb_node_imaginary_literal_val(const NODE *n)
-{
- VALUE lit;
- const rb_node_imaginary_t *node = RNODE_IMAGINARY(n);
-
- enum rb_numeric_type type = node->type;
-
- switch (type) {
- case integer_literal:
- lit = integer_value(node->val, node->base);
- break;
- case float_literal:{
- double d = strtod(node->val, 0);
- lit = DBL2NUM(d);
- break;
- }
- case rational_literal:
- lit = rational_value(node->val, node->base, node->seen_point);
- break;
- default:
- rb_bug("unreachable");
- }
-
- lit = rb_complex_raw(INT2FIX(0), lit);
-
- if (node->minus) {
- lit = negative_numeric(lit);
- }
- return lit;
-}
-
-VALUE
-rb_node_str_string_val(const NODE *node)
-{
- rb_parser_string_t *str = RNODE_STR(node)->string;
- return rb_str_new_parser_string(str);
-}
-
-VALUE
-rb_node_sym_string_val(const NODE *node)
-{
- rb_parser_string_t *str = RNODE_SYM(node)->string;
- return ID2SYM(rb_intern3(str->ptr, str->len, str->enc));
-}
-
-VALUE
-rb_node_dstr_string_val(const NODE *node)
-{
- rb_parser_string_t *str = RNODE_DSTR(node)->string;
- return str ? rb_str_new_parser_string(str) : Qnil;
-}
-
-VALUE
-rb_node_dregx_string_val(const NODE *node)
-{
- rb_parser_string_t *str = RNODE_DREGX(node)->string;
- return rb_str_new_parser_string(str);
-}
-
-VALUE
-rb_node_regx_string_val(const NODE *node)
-{
- rb_node_regx_t *node_reg = RNODE_REGX(node);
- rb_parser_string_t *string = node_reg->string;
- VALUE str = rb_enc_str_new(string->ptr, string->len, string->enc);
-
- return rb_reg_compile(str, node_reg->options, NULL, 0);
-}
-
-VALUE
-rb_node_line_lineno_val(const NODE *node)
-{
- return INT2FIX(node->nd_loc.beg_pos.lineno);
-}
-
-VALUE
-rb_node_file_path_val(const NODE *node)
-{
- return rb_str_new_parser_string(RNODE_FILE(node)->path);
-}
-
-VALUE
-rb_node_encoding_val(const NODE *node)
-{
- return rb_enc_from_encoding(RNODE_ENCODING(node)->enc);
-}
-
-static void
-parser_aset_script_lines_for(VALUE path, rb_parser_ary_t *lines)
-{
- VALUE hash, script_lines;
- ID script_lines_id;
- if (NIL_P(path) || !lines) return;
- CONST_ID(script_lines_id, "SCRIPT_LINES__");
- if (!rb_const_defined_at(rb_cObject, script_lines_id)) return;
- hash = rb_const_get_at(rb_cObject, script_lines_id);
- if (!RB_TYPE_P(hash, T_HASH)) return;
- if (rb_hash_lookup(hash, path) == Qnil) return;
- script_lines = rb_parser_build_script_lines_from(lines);
- rb_hash_aset(hash, path, script_lines);
-}
-
-VALUE
-rb_ruby_ast_new(const NODE *const root)
-{
- rb_ast_t *ast;
- VALUE ast_value = TypedData_Make_Struct(0, rb_ast_t, &ast_data_type, ast);
-#ifdef UNIVERSAL_PARSER
- ast->config = &rb_global_parser_config;
-#endif
- ast->body = (rb_ast_body_t){
- .root = root,
- .frozen_string_literal = -1,
- .coverage_enabled = -1,
- .script_lines = NULL,
- .line_count = 0,
- };
- return ast_value;
-}
-
-rb_ast_t *
-rb_ruby_ast_data_get(VALUE ast_value)
-{
- rb_ast_t *ast;
- if (NIL_P(ast_value)) return NULL;
- TypedData_Get_Struct(ast_value, rb_ast_t, &ast_data_type, ast);
- return ast;
-}
diff --git a/rubyparser.h b/rubyparser.h
deleted file mode 100644
index 08111a8898..0000000000
--- a/rubyparser.h
+++ /dev/null
@@ -1,1350 +0,0 @@
-#ifndef RUBY_RUBYPARSER_H
-#define RUBY_RUBYPARSER_H 1
-/*
- * This is a header file for librubyparser interface
- */
-
-#include <stdarg.h> /* for va_list */
-#include <assert.h>
-
-#ifdef UNIVERSAL_PARSER
-
-#define rb_encoding const void
-#define OnigCodePoint unsigned int
-#include "parser_st.h"
-#ifndef RUBY_RUBY_H
-#include "parser_value.h"
-#endif
-
-#else
-
-#include "ruby/encoding.h"
-
-#endif
-
-#ifndef FLEX_ARY_LEN
-/* From internal/compilers.h */
-/* A macro for defining a flexible array, like: VALUE ary[FLEX_ARY_LEN]; */
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
-# define FLEX_ARY_LEN /* VALUE ary[]; */
-#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
-# define FLEX_ARY_LEN 0 /* VALUE ary[0]; */
-#else
-# define FLEX_ARY_LEN 1 /* VALUE ary[1]; */
-#endif
-#endif
-
-#if defined(__GNUC__)
-# if defined(__MINGW_PRINTF_FORMAT)
-# define RUBYPARSER_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((format(__MINGW_PRINTF_FORMAT, string_index, argument_index)))
-# else
-# define RUBYPARSER_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((format(printf, string_index, argument_index)))
-# endif
-#elif defined(__clang__)
-# define RUBYPARSER_ATTRIBUTE_FORMAT(string_index, argument_index) __attribute__((__format__(__printf__, string_index, argument_index)))
-#else
-# define RUBYPARSER_ATTRIBUTE_FORMAT(string_index, argument_index)
-#endif
-
-/*
- * Parser String
- */
-enum rb_parser_string_coderange_type {
- /** The object's coderange is unclear yet. */
- RB_PARSER_ENC_CODERANGE_UNKNOWN = 0,
- RB_PARSER_ENC_CODERANGE_7BIT = 1,
- RB_PARSER_ENC_CODERANGE_VALID = 2,
- RB_PARSER_ENC_CODERANGE_BROKEN = 3
-};
-
-typedef struct rb_parser_string {
- enum rb_parser_string_coderange_type coderange;
- rb_encoding *enc;
- /* Length of the string, not including terminating NUL character. */
- long len;
- /* Pointer to the contents of the string. */
- char *ptr;
-} rb_parser_string_t;
-
-enum rb_parser_shareability {
- rb_parser_shareable_none,
- rb_parser_shareable_literal,
- rb_parser_shareable_copy,
- rb_parser_shareable_everything,
-};
-
-typedef void* rb_parser_input_data;
-
-/*
- * AST Node
- */
-enum node_type {
- NODE_SCOPE,
- NODE_BLOCK,
- NODE_IF,
- NODE_UNLESS,
- NODE_CASE,
- NODE_CASE2,
- NODE_CASE3,
- NODE_WHEN,
- NODE_IN,
- NODE_WHILE,
- NODE_UNTIL,
- NODE_ITER,
- NODE_FOR,
- NODE_FOR_MASGN,
- NODE_BREAK,
- NODE_NEXT,
- NODE_REDO,
- NODE_RETRY,
- NODE_BEGIN,
- NODE_RESCUE,
- NODE_RESBODY,
- NODE_ENSURE,
- NODE_AND,
- NODE_OR,
- NODE_MASGN,
- NODE_LASGN,
- NODE_DASGN,
- NODE_GASGN,
- NODE_IASGN,
- NODE_CDECL,
- NODE_CVASGN,
- NODE_OP_ASGN1,
- NODE_OP_ASGN2,
- NODE_OP_ASGN_AND,
- NODE_OP_ASGN_OR,
- NODE_OP_CDECL,
- NODE_CALL,
- NODE_OPCALL,
- NODE_FCALL,
- NODE_VCALL,
- NODE_QCALL,
- NODE_SUPER,
- NODE_ZSUPER,
- NODE_LIST,
- NODE_ZLIST,
- NODE_HASH,
- NODE_RETURN,
- NODE_YIELD,
- NODE_LVAR,
- NODE_DVAR,
- NODE_GVAR,
- NODE_IVAR,
- NODE_CONST,
- NODE_CVAR,
- NODE_NTH_REF,
- NODE_BACK_REF,
- NODE_MATCH,
- NODE_MATCH2,
- NODE_MATCH3,
- NODE_INTEGER,
- NODE_FLOAT,
- NODE_RATIONAL,
- NODE_IMAGINARY,
- NODE_STR,
- NODE_DSTR,
- NODE_XSTR,
- NODE_DXSTR,
- NODE_EVSTR,
- NODE_REGX,
- NODE_DREGX,
- NODE_ONCE,
- NODE_ARGS,
- NODE_ARGS_AUX,
- NODE_OPT_ARG,
- NODE_KW_ARG,
- NODE_POSTARG,
- NODE_ARGSCAT,
- NODE_ARGSPUSH,
- NODE_SPLAT,
- NODE_BLOCK_PASS,
- NODE_DEFN,
- NODE_DEFS,
- NODE_ALIAS,
- NODE_VALIAS,
- NODE_UNDEF,
- NODE_CLASS,
- NODE_MODULE,
- NODE_SCLASS,
- NODE_COLON2,
- NODE_COLON3,
- NODE_DOT2,
- NODE_DOT3,
- NODE_FLIP2,
- NODE_FLIP3,
- NODE_SELF,
- NODE_NIL,
- NODE_TRUE,
- NODE_FALSE,
- NODE_ERRINFO,
- NODE_DEFINED,
- NODE_POSTEXE,
- NODE_SYM,
- NODE_DSYM,
- NODE_ATTRASGN,
- NODE_LAMBDA,
- NODE_ARYPTN,
- NODE_HSHPTN,
- NODE_FNDPTN,
- NODE_ERROR,
- NODE_LINE,
- NODE_FILE,
- NODE_ENCODING,
- NODE_LAST
-};
-
-typedef struct rb_ast_id_table {
- int size;
- ID ids[FLEX_ARY_LEN];
-} rb_ast_id_table_t;
-
-typedef struct rb_code_position_struct {
- int lineno;
- int column;
-} rb_code_position_t;
-
-typedef struct rb_code_location_struct {
- rb_code_position_t beg_pos;
- rb_code_position_t end_pos;
-} rb_code_location_t;
-#define YYLTYPE rb_code_location_t
-#define YYLTYPE_IS_DECLARED 1
-
-typedef struct rb_parser_ast_token {
- int id;
- const char *type_name;
- rb_parser_string_t *str;
- rb_code_location_t loc;
-} rb_parser_ast_token_t;
-
-/*
- * Array-like object for parser
- */
-typedef void* rb_parser_ary_data;
-
-enum rb_parser_ary_data_type {
- PARSER_ARY_DATA_AST_TOKEN = 1,
- PARSER_ARY_DATA_SCRIPT_LINE,
- PARSER_ARY_DATA_NODE
-};
-
-typedef struct rb_parser_ary {
- enum rb_parser_ary_data_type data_type;
- rb_parser_ary_data *data;
- long len; // current size
- long capa; // capacity
-} rb_parser_ary_t;
-
-/* Header part of AST Node */
-typedef struct RNode {
- VALUE flags;
- rb_code_location_t nd_loc;
- int node_id;
-} NODE;
-
-typedef struct RNode_SCOPE {
- NODE node;
-
- rb_ast_id_table_t *nd_tbl;
- struct RNode *nd_body;
- struct RNode_ARGS *nd_args;
-} rb_node_scope_t;
-
-typedef struct RNode_BLOCK {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_end;
- struct RNode *nd_next;
-} rb_node_block_t;
-
-typedef struct RNode_IF {
- NODE node;
-
- struct RNode *nd_cond;
- struct RNode *nd_body;
- struct RNode *nd_else;
-} rb_node_if_t;
-
-typedef struct RNode_UNLESS {
- NODE node;
-
- struct RNode *nd_cond;
- struct RNode *nd_body;
- struct RNode *nd_else;
- rb_code_location_t keyword_loc;
- rb_code_location_t then_keyword_loc;
- rb_code_location_t end_keyword_loc;
-} rb_node_unless_t;
-
-typedef struct RNode_CASE {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
- rb_code_location_t case_keyword_loc;
- rb_code_location_t end_keyword_loc;
-} rb_node_case_t;
-
-typedef struct RNode_CASE2 {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
- rb_code_location_t case_keyword_loc;
- rb_code_location_t end_keyword_loc;
-} rb_node_case2_t;
-
-typedef struct RNode_CASE3 {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
- rb_code_location_t case_keyword_loc;
- rb_code_location_t end_keyword_loc;
-} rb_node_case3_t;
-
-typedef struct RNode_WHEN {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
- struct RNode *nd_next;
- rb_code_location_t keyword_loc;
- rb_code_location_t then_keyword_loc;
-} rb_node_when_t;
-
-typedef struct RNode_IN {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
- struct RNode *nd_next;
-} rb_node_in_t;
-
-typedef struct RNode_LOOP {
- NODE node;
-
- struct RNode *nd_cond;
- struct RNode *nd_body;
- long nd_state;
- rb_code_location_t keyword_loc;
- rb_code_location_t closing_loc;
-} rb_node_while_t, rb_node_until_t;
-
-typedef struct RNode_ITER {
- NODE node;
-
- struct RNode *nd_body;
- struct RNode *nd_iter;
-} rb_node_iter_t, rb_node_for_t;
-
-typedef struct RNode_FOR_MASGN {
- NODE node;
-
- struct RNode *nd_var;
-} rb_node_for_masgn_t;
-
-typedef struct RNode_EXITS {
- NODE node;
-
- struct RNode *nd_chain;
- struct RNode *nd_stts;
- rb_code_location_t keyword_loc;
-} rb_node_exits_t, rb_node_break_t, rb_node_next_t, rb_node_redo_t;
-
-typedef struct RNode_RETRY {
- NODE node;
-} rb_node_retry_t;
-
-typedef struct RNode_BEGIN {
- NODE node;
-
- struct RNode *nd_body;
-} rb_node_begin_t;
-
-typedef struct RNode_RESCUE {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_resq;
- struct RNode *nd_else;
-} rb_node_rescue_t;
-
-typedef struct RNode_RESBODY {
- NODE node;
-
- struct RNode *nd_args;
- struct RNode *nd_exc_var;
- struct RNode *nd_body;
- struct RNode *nd_next;
-} rb_node_resbody_t;
-
-typedef struct RNode_ENSURE {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_ensr;
-} rb_node_ensure_t;
-
-typedef struct {
- NODE node;
-
- struct RNode *nd_1st;
- struct RNode *nd_2nd;
- rb_code_location_t operator_loc;
-} rb_node_and_t, rb_node_or_t;
-
-typedef struct RNode_MASGN {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_value;
- struct RNode *nd_args;
-} rb_node_masgn_t;
-
-typedef struct RNode_LASGN {
- NODE node;
-
- ID nd_vid;
- struct RNode *nd_value;
-} rb_node_lasgn_t;
-
-typedef struct RNode_DASGN {
- NODE node;
-
- ID nd_vid;
- struct RNode *nd_value;
-} rb_node_dasgn_t;
-
-typedef struct RNode_GASGN {
- NODE node;
-
- ID nd_vid;
- struct RNode *nd_value;
-} rb_node_gasgn_t;
-
-typedef struct RNode_IASGN {
- NODE node;
-
- ID nd_vid;
- struct RNode *nd_value;
-} rb_node_iasgn_t;
-
-typedef struct RNode_CDECL {
- NODE node;
-
- ID nd_vid;
- struct RNode *nd_value;
- struct RNode *nd_else;
- enum rb_parser_shareability shareability;
-} rb_node_cdecl_t;
-
-typedef struct RNode_CVASGN {
- NODE node;
-
- ID nd_vid;
- struct RNode *nd_value;
-} rb_node_cvasgn_t;
-
-typedef struct RNode_OP_ASGN1 {
- NODE node;
-
- struct RNode *nd_recv;
- ID nd_mid;
- struct RNode *nd_index;
- struct RNode *nd_rvalue;
- rb_code_location_t call_operator_loc;
- rb_code_location_t opening_loc;
- rb_code_location_t closing_loc;
- rb_code_location_t binary_operator_loc;
-} rb_node_op_asgn1_t;
-
-typedef struct RNode_OP_ASGN2 {
- NODE node;
-
- struct RNode *nd_recv;
- struct RNode *nd_value;
- ID nd_vid;
- ID nd_mid;
- bool nd_aid;
- rb_code_location_t call_operator_loc;
- rb_code_location_t message_loc;
- rb_code_location_t binary_operator_loc;
-} rb_node_op_asgn2_t;
-
-typedef struct RNode_OP_ASGN_AND {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_value;
-} rb_node_op_asgn_and_t;
-
-typedef struct RNode_OP_ASGN_OR {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_value;
-} rb_node_op_asgn_or_t;
-
-typedef struct RNode_OP_CDECL {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_value;
- ID nd_aid;
- enum rb_parser_shareability shareability;
-} rb_node_op_cdecl_t;
-
-typedef struct RNode_CALL {
- NODE node;
-
- struct RNode *nd_recv;
- ID nd_mid;
- struct RNode *nd_args;
-} rb_node_call_t;
-
-typedef struct RNode_OPCALL {
- NODE node;
-
- struct RNode *nd_recv;
- ID nd_mid;
- struct RNode *nd_args;
-} rb_node_opcall_t;
-
-typedef struct RNode_FCALL {
- NODE node;
-
- ID nd_mid;
- struct RNode *nd_args;
-} rb_node_fcall_t;
-
-typedef struct RNode_VCALL {
- NODE node;
-
- ID nd_mid;
-} rb_node_vcall_t;
-
-typedef struct RNode_QCALL {
- NODE node;
-
- struct RNode *nd_recv;
- ID nd_mid;
- struct RNode *nd_args;
-} rb_node_qcall_t;
-
-typedef struct RNode_SUPER {
- NODE node;
-
- struct RNode *nd_args;
-} rb_node_super_t;
-
-typedef struct RNode_ZSUPER {
- NODE node;
-} rb_node_zsuper_t;
-
-/*
-
- Structure of LIST:
-
- LIST +--> LIST
- * head --> element | * head
- * alen (length of list) | * nd_end (point to the last LIST)
- * next -----------------+ * next
-
-*/
-typedef struct RNode_LIST {
- NODE node;
-
- struct RNode *nd_head; /* element */
- union {
- long nd_alen;
- struct RNode *nd_end; /* Second list node has this structure */
- } as;
- struct RNode *nd_next; /* next list node */
-} rb_node_list_t;
-
-typedef struct RNode_ZLIST {
- NODE node;
-} rb_node_zlist_t;
-
-typedef struct RNode_HASH {
- NODE node;
-
- struct RNode *nd_head;
- long nd_brace;
-} rb_node_hash_t;
-
-typedef struct RNode_RETURN {
- NODE node;
-
- struct RNode *nd_stts;
- rb_code_location_t keyword_loc;
-} rb_node_return_t;
-
-typedef struct RNode_YIELD {
- NODE node;
-
- struct RNode *nd_head;
-} rb_node_yield_t;
-
-typedef struct RNode_LVAR {
- NODE node;
-
- ID nd_vid;
-} rb_node_lvar_t;
-
-typedef struct RNode_DVAR {
- NODE node;
-
- ID nd_vid;
-} rb_node_dvar_t;
-
-typedef struct RNode_GVAR {
- NODE node;
-
- ID nd_vid;
-} rb_node_gvar_t;
-
-typedef struct RNode_IVAR {
- NODE node;
-
- ID nd_vid;
-} rb_node_ivar_t;
-
-typedef struct RNode_CONST {
- NODE node;
-
- ID nd_vid;
-} rb_node_const_t;
-
-typedef struct RNode_CVAR {
- NODE node;
-
- ID nd_vid;
-} rb_node_cvar_t;
-
-typedef struct RNode_NTH_REF {
- NODE node;
-
- long nd_nth;
-} rb_node_nth_ref_t;
-
-typedef struct RNode_BACK_REF {
- NODE node;
-
- long nd_nth;
-} rb_node_back_ref_t;
-
-typedef struct RNode_MATCH2 {
- NODE node;
-
- struct RNode *nd_recv;
- struct RNode *nd_value;
- struct RNode *nd_args;
-} rb_node_match2_t;
-
-typedef struct RNode_MATCH3 {
- NODE node;
-
- struct RNode *nd_recv;
- struct RNode *nd_value;
-} rb_node_match3_t;
-
-typedef struct RNode_INTEGER {
- NODE node;
-
- char *val;
- int minus;
- int base;
-} rb_node_integer_t;
-
-typedef struct RNode_FLOAT {
- NODE node;
-
- char *val;
- int minus;
-} rb_node_float_t;
-
-typedef struct RNode_RATIONAL {
- NODE node;
-
- char *val;
- int minus;
- int base;
- int seen_point;
-} rb_node_rational_t;
-
-enum rb_numeric_type {
- integer_literal,
- float_literal,
- rational_literal
-};
-
-typedef struct RNode_IMAGINARY {
- NODE node;
-
- char *val;
- int minus;
- int base;
- int seen_point;
- enum rb_numeric_type type;
-} rb_node_imaginary_t;
-
-typedef struct RNode_STR {
- NODE node;
-
- struct rb_parser_string *string;
-} rb_node_str_t;
-
-/* NODE_DSTR, NODE_DXSTR, NODE_DREGX, NODE_DSYM */
-typedef struct RNode_DSTR {
- NODE node;
-
- struct rb_parser_string *string;
- union {
- long nd_alen;
- long nd_cflag;
- struct RNode *nd_end; /* Second dstr node has this structure. See also RNode_LIST */
- } as;
- struct RNode_LIST *nd_next;
-} rb_node_dstr_t;
-
-typedef rb_node_str_t rb_node_xstr_t;
-
-typedef rb_node_dstr_t rb_node_dxstr_t;
-
-typedef struct RNode_EVSTR {
- NODE node;
-
- struct RNode *nd_body;
-} rb_node_evstr_t;
-
-typedef struct RNode_REGX { /* also RNode_MATCH */
- NODE node;
-
- struct rb_parser_string *string;
- int options;
-} rb_node_regx_t, rb_node_match_t;
-
-typedef rb_node_dstr_t rb_node_dregx_t;
-
-typedef struct RNode_ONCE {
- NODE node;
-
- struct RNode *nd_body;
-} rb_node_once_t;
-
-struct rb_args_info {
- NODE *pre_init;
- NODE *post_init;
-
- int pre_args_num; /* count of mandatory pre-arguments */
- int post_args_num; /* count of mandatory post-arguments */
-
- ID first_post_arg;
-
- ID rest_arg;
- ID block_arg;
-
- struct RNode_KW_ARG *kw_args;
- NODE *kw_rest_arg;
-
- struct RNode_OPT_ARG *opt_args;
- unsigned int no_kwarg: 1;
- unsigned int ruby2_keywords: 1;
- unsigned int forwarding: 1;
-};
-
-typedef struct RNode_ARGS {
- NODE node;
-
- struct rb_args_info nd_ainfo;
-} rb_node_args_t;
-
-typedef struct RNode_ARGS_AUX {
- NODE node;
-
- ID nd_pid;
- int nd_plen;
- struct RNode *nd_next;
-} rb_node_args_aux_t;
-
-typedef struct RNode_OPT_ARG {
- NODE node;
-
- struct RNode *nd_body;
- struct RNode_OPT_ARG *nd_next;
-} rb_node_opt_arg_t;
-
-typedef struct RNode_KW_ARG {
- NODE node;
-
- struct RNode *nd_body;
- struct RNode_KW_ARG *nd_next;
-} rb_node_kw_arg_t;
-
-typedef struct RNode_POSTARG {
- NODE node;
-
- struct RNode *nd_1st;
- struct RNode *nd_2nd;
-} rb_node_postarg_t;
-
-typedef struct RNode_ARGSCAT {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
-} rb_node_argscat_t;
-
-typedef struct RNode_ARGSPUSH {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
-} rb_node_argspush_t;
-
-typedef struct RNode_SPLAT {
- NODE node;
-
- struct RNode *nd_head;
- rb_code_location_t operator_loc;
-} rb_node_splat_t;
-
-typedef struct RNode_BLOCK_PASS {
- NODE node;
-
- struct RNode *nd_head;
- struct RNode *nd_body;
- unsigned int forwarding: 1;
- rb_code_location_t operator_loc;
-} rb_node_block_pass_t;
-
-typedef struct RNode_DEFN {
- NODE node;
-
- ID nd_mid;
- struct RNode *nd_defn;
-} rb_node_defn_t;
-
-typedef struct RNode_DEFS {
- NODE node;
-
- struct RNode *nd_recv;
- ID nd_mid;
- struct RNode *nd_defn;
-} rb_node_defs_t;
-
-typedef struct RNode_ALIAS {
- NODE node;
-
- struct RNode *nd_1st;
- struct RNode *nd_2nd;
- rb_code_location_t keyword_loc;
-} rb_node_alias_t;
-
-typedef struct RNode_VALIAS {
- NODE node;
-
- ID nd_alias;
- ID nd_orig;
- rb_code_location_t keyword_loc;
-} rb_node_valias_t;
-
-typedef struct RNode_UNDEF {
- NODE node;
-
- rb_parser_ary_t *nd_undefs;
- rb_code_location_t keyword_loc;
-} rb_node_undef_t;
-
-typedef struct RNode_CLASS {
- NODE node;
-
- struct RNode *nd_cpath;
- struct RNode *nd_body;
- struct RNode *nd_super;
-} rb_node_class_t;
-
-typedef struct RNode_MODULE {
- NODE node;
-
- struct RNode *nd_cpath;
- struct RNode *nd_body;
-} rb_node_module_t;
-
-typedef struct RNode_SCLASS {
- NODE node;
-
- struct RNode *nd_recv;
- struct RNode *nd_body;
-} rb_node_sclass_t;
-
-typedef struct RNode_COLON2 {
- NODE node;
-
- struct RNode *nd_head;
- ID nd_mid;
-} rb_node_colon2_t;
-
-typedef struct RNode_COLON3 {
- NODE node;
-
- ID nd_mid;
-} rb_node_colon3_t;
-
-/* NODE_DOT2, NODE_DOT3, NODE_FLIP2, NODE_FLIP3 */
-typedef struct RNode_DOTS {
- NODE node;
-
- struct RNode *nd_beg;
- struct RNode *nd_end;
-} rb_node_dot2_t, rb_node_dot3_t, rb_node_flip2_t, rb_node_flip3_t;
-
-typedef struct RNode_SELF {
- NODE node;
-
- long nd_state; /* Default 1. See NEW_SELF. */
-} rb_node_self_t;
-
-typedef struct RNode_NIL {
- NODE node;
-} rb_node_nil_t;
-
-typedef struct RNode_TRUE {
- NODE node;
-} rb_node_true_t;
-
-typedef struct RNode_FALSE {
- NODE node;
-} rb_node_false_t;
-
-typedef struct RNode_ERRINFO {
- NODE node;
-} rb_node_errinfo_t;
-
-typedef struct RNode_DEFINED {
- NODE node;
-
- struct RNode *nd_head;
-} rb_node_defined_t;
-
-typedef struct RNode_POSTEXE {
- NODE node;
-
- struct RNode *nd_body;
-} rb_node_postexe_t;
-
-typedef struct RNode_SYM {
- NODE node;
-
- struct rb_parser_string *string;
-} rb_node_sym_t;
-
-typedef rb_node_dstr_t rb_node_dsym_t;
-
-typedef struct RNode_ATTRASGN {
- NODE node;
-
- struct RNode *nd_recv;
- ID nd_mid;
- struct RNode *nd_args;
-} rb_node_attrasgn_t;
-
-typedef struct RNode_LAMBDA {
- NODE node;
-
- struct RNode *nd_body;
-} rb_node_lambda_t;
-
-typedef struct RNode_ARYPTN {
- NODE node;
-
- struct RNode *nd_pconst;
- NODE *pre_args;
- NODE *rest_arg;
- NODE *post_args;
-} rb_node_aryptn_t;
-
-typedef struct RNode_HSHPTN {
- NODE node;
-
- struct RNode *nd_pconst;
- struct RNode *nd_pkwargs;
- struct RNode *nd_pkwrestarg;
-} rb_node_hshptn_t;
-
-typedef struct RNode_FNDPTN {
- NODE node;
-
- struct RNode *nd_pconst;
- NODE *pre_rest_arg;
- NODE *args;
- NODE *post_rest_arg;
-} rb_node_fndptn_t;
-
-typedef struct RNode_LINE {
- NODE node;
-} rb_node_line_t;
-
-typedef struct RNode_FILE {
- NODE node;
-
- struct rb_parser_string *path;
-} rb_node_file_t;
-
-typedef struct RNode_ENCODING {
- NODE node;
- rb_encoding *enc;
-} rb_node_encoding_t;
-
-typedef struct RNode_ERROR {
- NODE node;
-} rb_node_error_t;
-
-#define RNODE(obj) ((NODE *)(obj))
-
-#define RNODE_SCOPE(node) ((rb_node_scope_t *)(node))
-#define RNODE_BLOCK(node) ((rb_node_block_t *)(node))
-#define RNODE_IF(node) ((rb_node_if_t *)(node))
-#define RNODE_UNLESS(node) ((rb_node_unless_t *)(node))
-#define RNODE_CASE(node) ((rb_node_case_t *)(node))
-#define RNODE_CASE2(node) ((rb_node_case2_t *)(node))
-#define RNODE_CASE3(node) ((rb_node_case3_t *)(node))
-#define RNODE_WHEN(node) ((rb_node_when_t *)(node))
-#define RNODE_IN(node) ((rb_node_in_t *)(node))
-#define RNODE_WHILE(node) ((rb_node_while_t *)(node))
-#define RNODE_UNTIL(node) ((rb_node_until_t *)(node))
-#define RNODE_ITER(node) ((rb_node_iter_t *)(node))
-#define RNODE_FOR(node) ((rb_node_for_t *)(node))
-#define RNODE_FOR_MASGN(node) ((rb_node_for_masgn_t *)(node))
-#define RNODE_BREAK(node) ((rb_node_break_t *)(node))
-#define RNODE_NEXT(node) ((rb_node_next_t *)(node))
-#define RNODE_REDO(node) ((rb_node_redo_t *)(node))
-#define RNODE_RETRY(node) ((rb_node_retry_t *)(node))
-#define RNODE_BEGIN(node) ((rb_node_begin_t *)(node))
-#define RNODE_RESCUE(node) ((rb_node_rescue_t *)(node))
-#define RNODE_RESBODY(node) ((rb_node_resbody_t *)(node))
-#define RNODE_ENSURE(node) ((rb_node_ensure_t *)(node))
-#define RNODE_AND(node) ((rb_node_and_t *)(node))
-#define RNODE_OR(node) ((rb_node_or_t *)(node))
-#define RNODE_MASGN(node) ((rb_node_masgn_t *)(node))
-#define RNODE_LASGN(node) ((rb_node_lasgn_t *)(node))
-#define RNODE_DASGN(node) ((rb_node_dasgn_t *)(node))
-#define RNODE_GASGN(node) ((rb_node_gasgn_t *)(node))
-#define RNODE_IASGN(node) ((rb_node_iasgn_t *)(node))
-#define RNODE_CDECL(node) ((rb_node_cdecl_t *)(node))
-#define RNODE_CVASGN(node) ((rb_node_cvasgn_t *)(node))
-#define RNODE_OP_ASGN1(node) ((rb_node_op_asgn1_t *)(node))
-#define RNODE_OP_ASGN2(node) ((rb_node_op_asgn2_t *)(node))
-#define RNODE_OP_ASGN_AND(node) ((rb_node_op_asgn_and_t *)(node))
-#define RNODE_OP_ASGN_OR(node) ((rb_node_op_asgn_or_t *)(node))
-#define RNODE_OP_CDECL(node) ((rb_node_op_cdecl_t *)(node))
-#define RNODE_CALL(node) ((rb_node_call_t *)(node))
-#define RNODE_OPCALL(node) ((rb_node_opcall_t *)(node))
-#define RNODE_FCALL(node) ((rb_node_fcall_t *)(node))
-#define RNODE_VCALL(node) ((rb_node_vcall_t *)(node))
-#define RNODE_QCALL(node) ((rb_node_qcall_t *)(node))
-#define RNODE_SUPER(node) ((rb_node_super_t *)(node))
-#define RNODE_ZSUPER(node) ((rb_node_zsuper_t *)(node))
-#define RNODE_LIST(node) ((rb_node_list_t *)(node))
-#define RNODE_ZLIST(node) ((rb_node_zlist_t *)(node))
-#define RNODE_HASH(node) ((rb_node_hash_t *)(node))
-#define RNODE_RETURN(node) ((rb_node_return_t *)(node))
-#define RNODE_YIELD(node) ((rb_node_yield_t *)(node))
-#define RNODE_LVAR(node) ((rb_node_lvar_t *)(node))
-#define RNODE_DVAR(node) ((rb_node_dvar_t *)(node))
-#define RNODE_GVAR(node) ((rb_node_gvar_t *)(node))
-#define RNODE_IVAR(node) ((rb_node_ivar_t *)(node))
-#define RNODE_CONST(node) ((rb_node_const_t *)(node))
-#define RNODE_CVAR(node) ((rb_node_cvar_t *)(node))
-#define RNODE_NTH_REF(node) ((rb_node_nth_ref_t *)(node))
-#define RNODE_BACK_REF(node) ((rb_node_back_ref_t *)(node))
-#define RNODE_MATCH(node) ((rb_node_match_t *)(node))
-#define RNODE_MATCH2(node) ((rb_node_match2_t *)(node))
-#define RNODE_MATCH3(node) ((rb_node_match3_t *)(node))
-#define RNODE_INTEGER(node) ((rb_node_integer_t *)(node))
-#define RNODE_FLOAT(node) ((rb_node_float_t *)(node))
-#define RNODE_RATIONAL(node) ((rb_node_rational_t *)(node))
-#define RNODE_IMAGINARY(node) ((rb_node_imaginary_t *)(node))
-#define RNODE_STR(node) ((rb_node_str_t *)(node))
-#define RNODE_DSTR(node) ((rb_node_dstr_t *)(node))
-#define RNODE_XSTR(node) ((rb_node_xstr_t *)(node))
-#define RNODE_DXSTR(node) ((rb_node_dxstr_t *)(node))
-#define RNODE_EVSTR(node) ((rb_node_evstr_t *)(node))
-#define RNODE_REGX(node) ((rb_node_regx_t *)(node))
-#define RNODE_DREGX(node) ((rb_node_dregx_t *)(node))
-#define RNODE_ONCE(node) ((rb_node_once_t *)(node))
-#define RNODE_ARGS(node) ((rb_node_args_t *)(node))
-#define RNODE_ARGS_AUX(node) ((rb_node_args_aux_t *)(node))
-#define RNODE_OPT_ARG(node) ((rb_node_opt_arg_t *)(node))
-#define RNODE_KW_ARG(node) ((rb_node_kw_arg_t *)(node))
-#define RNODE_POSTARG(node) ((rb_node_postarg_t *)(node))
-#define RNODE_ARGSCAT(node) ((rb_node_argscat_t *)(node))
-#define RNODE_ARGSPUSH(node) ((rb_node_argspush_t *)(node))
-#define RNODE_SPLAT(node) ((rb_node_splat_t *)(node))
-#define RNODE_BLOCK_PASS(node) ((rb_node_block_pass_t *)(node))
-#define RNODE_DEFN(node) ((rb_node_defn_t *)(node))
-#define RNODE_DEFS(node) ((rb_node_defs_t *)(node))
-#define RNODE_ALIAS(node) ((rb_node_alias_t *)(node))
-#define RNODE_VALIAS(node) ((rb_node_valias_t *)(node))
-#define RNODE_UNDEF(node) ((rb_node_undef_t *)(node))
-#define RNODE_CLASS(node) ((rb_node_class_t *)(node))
-#define RNODE_MODULE(node) ((rb_node_module_t *)(node))
-#define RNODE_SCLASS(node) ((rb_node_sclass_t *)(node))
-#define RNODE_COLON2(node) ((rb_node_colon2_t *)(node))
-#define RNODE_COLON3(node) ((rb_node_colon3_t *)(node))
-#define RNODE_DOT2(node) ((rb_node_dot2_t *)(node))
-#define RNODE_DOT3(node) ((rb_node_dot3_t *)(node))
-#define RNODE_FLIP2(node) ((rb_node_flip2_t *)(node))
-#define RNODE_FLIP3(node) ((rb_node_flip3_t *)(node))
-#define RNODE_SELF(node) ((rb_node_self_t *)(node))
-#define RNODE_NIL(node) ((rb_node_nil_t *)(node))
-#define RNODE_TRUE(node) ((rb_node_true_t *)(node))
-#define RNODE_FALSE(node) ((rb_node_false_t *)(node))
-#define RNODE_ERRINFO(node) ((rb_node_errinfo_t *)(node))
-#define RNODE_DEFINED(node) ((rb_node_defined_t *)(node))
-#define RNODE_POSTEXE(node) ((rb_node_postexe_t *)(node))
-#define RNODE_SYM(node) ((rb_node_sym_t *)(node))
-#define RNODE_DSYM(node) ((rb_node_dsym_t *)(node))
-#define RNODE_ATTRASGN(node) ((rb_node_attrasgn_t *)(node))
-#define RNODE_LAMBDA(node) ((rb_node_lambda_t *)(node))
-#define RNODE_ARYPTN(node) ((rb_node_aryptn_t *)(node))
-#define RNODE_HSHPTN(node) ((rb_node_hshptn_t *)(node))
-#define RNODE_FNDPTN(node) ((rb_node_fndptn_t *)(node))
-#define RNODE_LINE(node) ((rb_node_line_t *)(node))
-#define RNODE_FILE(node) ((rb_node_file_t *)(node))
-#define RNODE_ENCODING(node) ((rb_node_encoding_t *)(node))
-
-/* FL : 0..4: T_TYPES, 5: KEEP_WB, 6: PROMOTED, 7: FINALIZE, 8: UNUSED, 9: UNUSED, 10: EXIVAR, 11: FREEZE */
-/* NODE_FL: 0..4: UNUSED, 5: UNUSED, 6: UNUSED, 7: NODE_FL_NEWLINE,
- * 8..14: nd_type,
- * 15..: nd_line
- */
-#define NODE_FL_NEWLINE (((VALUE)1)<<7)
-
-#define NODE_TYPESHIFT 8
-#define NODE_TYPEMASK (((VALUE)0x7f)<<NODE_TYPESHIFT)
-
-#define nd_fl_newline(n) ((n)->flags & NODE_FL_NEWLINE)
-#define nd_set_fl_newline(n) ((n)->flags |= NODE_FL_NEWLINE)
-#define nd_unset_fl_newline(n) ((n)->flags &= ~NODE_FL_NEWLINE)
-
-#define nd_type(n) ((int) ((RNODE(n)->flags & NODE_TYPEMASK)>>NODE_TYPESHIFT))
-#define nd_set_type(n,t) \
- rb_node_set_type(n, t)
-#define nd_init_type(n,t) \
- (n)->flags=(((n)->flags&~NODE_TYPEMASK)|((((unsigned long)(t))<<NODE_TYPESHIFT)&NODE_TYPEMASK))
-
-typedef struct node_buffer_struct node_buffer_t;
-
-#ifdef UNIVERSAL_PARSER
-typedef struct rb_parser_config_struct rb_parser_config_t;
-#endif
-
-typedef struct rb_ast_body_struct {
- const NODE *root;
- rb_parser_ary_t *script_lines;
- int line_count;
- signed int frozen_string_literal:2; /* -1: not specified, 0: false, 1: true */
- signed int coverage_enabled:2; /* -1: not specified, 0: false, 1: true */
-} rb_ast_body_t;
-typedef struct rb_ast_struct {
- node_buffer_t *node_buffer;
- rb_ast_body_t body;
-#ifdef UNIVERSAL_PARSER
- const rb_parser_config_t *config;
-#endif
-} rb_ast_t;
-
-
-
-/*
- * Parser Interface
- */
-
-
-typedef struct parser_params rb_parser_t;
-#ifndef INTERNAL_IMEMO_H
-typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t;
-#endif
-
-#ifdef UNIVERSAL_PARSER
-typedef struct rb_parser_config_struct {
- /* Memory */
- void *(*malloc)(size_t size);
- void *(*calloc)(size_t number, size_t size);
- void *(*realloc)(void *ptr, size_t newsiz);
- void (*free)(void *ptr);
- void *(*alloc_n)(size_t nelems, size_t elemsiz);
- void *(*alloc)(size_t elemsiz);
- void *(*realloc_n)(void *ptr, size_t newelems, size_t newsiz);
- void *(*zalloc)(size_t elemsiz);
- void *(*rb_memmove)(void *dest, const void *src, size_t t, size_t n);
- void *(*nonempty_memcpy)(void *dest, const void *src, size_t t, size_t n);
- void *(*xmalloc_mul_add)(size_t x, size_t y, size_t z);
-
- // VALUE rb_suppress_tracing(VALUE (*func)(VALUE), VALUE arg);
- VALUE (*compile_callback)(VALUE (*func)(VALUE), VALUE arg);
- NODE *(*reg_named_capture_assign)(struct parser_params* p, VALUE regexp, const rb_code_location_t *loc);
-
- /* Variable */
- VALUE (*attr_get)(VALUE obj, ID id);
-
- /* Array */
- VALUE (*ary_new)(void);
- VALUE (*ary_push)(VALUE ary, VALUE elem);
- VALUE (*ary_new_from_args)(long n, ...);
- VALUE (*ary_unshift)(VALUE ary, VALUE item);
-
- /* Symbol */
- ID (*make_temporary_id)(size_t n);
- int (*is_local_id)(ID);
- int (*is_attrset_id)(ID);
- int (*is_global_name_punct)(const int c);
- int (*id_type)(ID id);
- ID (*id_attrset)(ID);
- ID (*intern)(const char *name);
- ID (*intern2)(const char *name, long len);
- ID (*intern3)(const char *name, long len, rb_encoding *enc);
- ID (*intern_str)(VALUE str);
- int (*is_notop_id)(ID);
- int (*enc_symname_type)(const char *name, long len, rb_encoding *enc, unsigned int allowed_attrset);
- const char *(*id2name)(ID id);
- VALUE (*id2str)(ID id);
- VALUE (*id2sym)(ID x);
- ID (*sym2id)(VALUE sym);
-
- /* String */
- RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
- VALUE (*str_catf)(VALUE str, const char *format, ...);
- VALUE (*str_cat_cstr)(VALUE str, const char *ptr);
- VALUE (*str_resize)(VALUE str, long len);
- VALUE (*str_new)(const char *ptr, long len);
- VALUE (*str_new_cstr)(const char *ptr);
- VALUE (*str_to_interned_str)(VALUE);
- VALUE (*enc_str_new)(const char *ptr, long len, rb_encoding *enc);
- RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 0)
- VALUE (*str_vcatf)(VALUE str, const char *fmt, va_list ap);
- RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
- VALUE (*rb_sprintf)(const char *format, ...);
- char *(*rstring_ptr)(VALUE str);
- long (*rstring_len)(VALUE str);
- VALUE (*obj_as_string)(VALUE);
-
- /* Numeric */
- VALUE (*int2num)(int v);
-
- /* IO */
- int (*stderr_tty_p)(void);
- void (*write_error_str)(VALUE mesg);
- VALUE (*io_write)(VALUE io, VALUE str);
- VALUE (*io_flush)(VALUE io);
- VALUE (*io_puts)(int argc, const VALUE *argv, VALUE out);
-
- /* IO (Ractor) */
- VALUE (*debug_output_stdout)(void);
- VALUE (*debug_output_stderr)(void);
-
- /* Encoding */
- int (*is_usascii_enc)(rb_encoding *enc);
- int (*enc_isalnum)(OnigCodePoint c, rb_encoding *enc);
- int (*enc_precise_mbclen)(const char *p, const char *e, rb_encoding *enc);
- int (*mbclen_charfound_p)(int len);
- int (*mbclen_charfound_len)(int len);
- const char *(*enc_name)(rb_encoding *enc);
- char *(*enc_prev_char)(const char *s, const char *p, const char *e, rb_encoding *enc);
- rb_encoding* (*enc_get)(VALUE obj);
- int (*enc_asciicompat)(rb_encoding *enc);
- rb_encoding *(*utf8_encoding)(void);
- VALUE (*enc_associate)(VALUE obj, rb_encoding *enc);
- rb_encoding *(*ascii8bit_encoding)(void);
- int (*enc_codelen)(int c, rb_encoding *enc);
- int (*enc_mbcput)(unsigned int c, void *buf, rb_encoding *enc);
- int (*enc_find_index)(const char *name);
- rb_encoding *(*enc_from_index)(int idx);
- int (*enc_isspace)(OnigCodePoint c, rb_encoding *enc);
- rb_encoding *(*usascii_encoding)(void);
- int (*enc_mbminlen)(rb_encoding *enc);
- bool (*enc_isascii)(OnigCodePoint c, rb_encoding *enc);
- OnigCodePoint (*enc_mbc_to_codepoint)(const char *p, const char *e, rb_encoding *enc);
-
- /* Compile */
- // int rb_local_defined(ID id, const rb_iseq_t *iseq);
- int (*local_defined)(ID, const void*);
- // int rb_dvar_defined(ID id, const rb_iseq_t *iseq);
- int (*dvar_defined)(ID, const void*);
-
- /* Error (Exception) */
- RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 6, 0)
- VALUE (*syntax_error_append)(VALUE, VALUE, int, int, rb_encoding*, const char*, va_list);
- RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
- void (*raise)(VALUE exc, const char *fmt, ...);
- VALUE (*syntax_error_new)(void);
-
- /* Eval */
- VALUE (*errinfo)(void);
- void (*set_errinfo)(VALUE err);
- void (*exc_raise)(VALUE mesg);
- VALUE (*make_exception)(int argc, const VALUE *argv);
-
- /* GC */
- void (*sized_xfree)(void *x, size_t size);
- void *(*sized_realloc_n)(void *ptr, size_t new_count, size_t element_size, size_t old_count);
- void (*gc_guard)(VALUE);
- void (*gc_mark)(VALUE);
-
- /* Re */
- VALUE (*reg_compile)(VALUE str, int options, const char *sourcefile, int sourceline);
- VALUE (*reg_check_preprocess)(VALUE str);
- int (*memcicmp)(const void *x, const void *y, long len);
-
- /* Error */
- void (*compile_warn)(const char *file, int line, const char *fmt, ...) RUBYPARSER_ATTRIBUTE_FORMAT(3, 4);
- void (*compile_warning)(const char *file, int line, const char *fmt, ...) RUBYPARSER_ATTRIBUTE_FORMAT(3, 4);
- void (*bug)(const char *fmt, ...) RUBYPARSER_ATTRIBUTE_FORMAT(1, 2);
- void (*fatal)(const char *fmt, ...) RUBYPARSER_ATTRIBUTE_FORMAT(1, 2);
- VALUE (*verbose)(void);
- int *(*errno_ptr)(void);
-
- /* VM */
- VALUE (*make_backtrace)(void);
-
- /* Util */
- unsigned long (*scan_hex)(const char *start, size_t len, size_t *retlen);
- unsigned long (*scan_oct)(const char *start, size_t len, size_t *retlen);
- unsigned long (*scan_digits)(const char *str, ssize_t len, int base, size_t *retlen, int *overflow);
- double (*strtod)(const char *s00, char **se);
-
- /* Misc */
- int (*rtest)(VALUE obj);
- int (*nil_p)(VALUE obj);
- VALUE qnil;
- VALUE qfalse;
- VALUE (*eArgError)(void);
- int (*long2int)(long);
-
- /* For Ripper */
- int enc_coderange_7bit;
- int enc_coderange_unknown;
- VALUE (*static_id2sym)(ID id);
- long (*str_coderange_scan_restartable)(const char *s, const char *e, rb_encoding *enc, int *cr);
-} rb_parser_config_t;
-
-#undef rb_encoding
-#undef OnigCodePoint
-#endif /* UNIVERSAL_PARSER */
-
-RUBY_SYMBOL_EXPORT_BEGIN
-void rb_ruby_parser_free(void *ptr);
-
-#ifdef UNIVERSAL_PARSER
-rb_parser_t *rb_ruby_parser_allocate(const rb_parser_config_t *config);
-rb_parser_t *rb_ruby_parser_new(const rb_parser_config_t *config);
-#endif
-
-RUBY_SYMBOL_EXPORT_END
-
-#endif /* RUBY_RUBYPARSER_H */
diff --git a/sample/all-ruby-quine.rb b/sample/all-ruby-quine.rb
deleted file mode 100644
index 7686121468..0000000000
--- a/sample/all-ruby-quine.rb
+++ /dev/null
@@ -1,24 +0,0 @@
- eval($s=("t='eval($s=('+d=34.chr;s=3
- 2.chr+$s*i=8;v=$VERSION||eval('begin;v=V
- ERSION;rescue;v||RUBY_VERSION;end');f=('?'*8
- +'A|'+'?'*20+'G?c'+'?'*15+'A@CXx@~@_`OpGxCxp@~pO
- xS|O~G?c?q?xC`AP|q?x_|C_xC_xO@H@cG?G?qA|_|_`GCpOxC|H
-NFccqq@`_|OF@`?q?x_@x_x_`GB`O``O~G?C@qCxCxP@D@|G~C?pO|C?
- pO|C?AP|A~HNN`ccxC|Q@L@B"+"GpGpc@p?x_`GB`???_@FO|OB@
- xC|P`@?c?q?HPx@~@_`G@`????@L^`?q?x?xq@|_|O~GC`
- xA~@_@GBD').unpack('c*');w=4+v.length*u=
- 15;r=10.chr;j=0;while-24+w*u>i=1+i
- ;x=i%w;x>0||t=t+d+'+'+r+d;k=
- i/w%12>2&&x%u>3&&x%u+i
- /w*11-34+('-._'.
- index(c=v[
- x/u,1]
- )||c.hex +3)*99|
- |0; k=f [k/6 ][k%
- 6]; t=t +s[
- k*j =k+ j,1
- ]end;pr int (t+
- d+' ).s pli
- t.j oin [0,
- 609 ])# Y.E. '+r)
- ").split .join)#
diff --git a/sample/dir.rb b/sample/dir.rb
index 81257cd917..0c55078973 100644
--- a/sample/dir.rb
+++ b/sample/dir.rb
@@ -1,7 +1,12 @@
# directory access
# list all files but .*/*~/*.o
-Dir.foreach(".") do |file|
- unless file.start_with?('.') or file.end_with?('~', '.o')
- puts file
+dirp = Dir.open(".")
+for f in dirp
+ case f
+ when /\A\./, /~\z/, /\.o\z/
+ # do not print
+ else
+ print f, "\n"
end
end
+dirp.close
diff --git a/sample/getoptlong/abbrev.rb b/sample/getoptlong/abbrev.rb
new file mode 100644
index 0000000000..9b89863626
--- /dev/null
+++ b/sample/getoptlong/abbrev.rb
@@ -0,0 +1,9 @@
+require 'getoptlong'
+
+options = GetoptLong.new(
+ ['--xxx', GetoptLong::NO_ARGUMENT],
+ ['--xyz', GetoptLong::NO_ARGUMENT]
+)
+options.each do |option, argument|
+ p [option, argument]
+end
diff --git a/sample/getoptlong/aliases.rb b/sample/getoptlong/aliases.rb
new file mode 100644
index 0000000000..895254c6ae
--- /dev/null
+++ b/sample/getoptlong/aliases.rb
@@ -0,0 +1,8 @@
+require 'getoptlong'
+
+options = GetoptLong.new(
+ ['--xxx', '-x', '--aaa', '-a', '-p', GetoptLong::NO_ARGUMENT]
+)
+options.each do |option, argument|
+ p [option, argument]
+end
diff --git a/sample/getoptlong/argv.rb b/sample/getoptlong/argv.rb
new file mode 100644
index 0000000000..8efcad22ea
--- /dev/null
+++ b/sample/getoptlong/argv.rb
@@ -0,0 +1,12 @@
+require 'getoptlong'
+
+options = GetoptLong.new(
+ ['--xxx', GetoptLong::REQUIRED_ARGUMENT],
+ ['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
+ ['--zzz', GetoptLong::NO_ARGUMENT]
+)
+puts "Original ARGV: #{ARGV}"
+options.each do |option, argument|
+ p [option, argument]
+end
+puts "Remaining ARGV: #{ARGV}"
diff --git a/sample/getoptlong/each.rb b/sample/getoptlong/each.rb
new file mode 100644
index 0000000000..661e0a968f
--- /dev/null
+++ b/sample/getoptlong/each.rb
@@ -0,0 +1,12 @@
+require 'getoptlong'
+
+options = GetoptLong.new(
+ ['--xxx', '-x', GetoptLong::REQUIRED_ARGUMENT],
+ ['--yyy', '-y', GetoptLong::OPTIONAL_ARGUMENT],
+ ['--zzz', '-z',GetoptLong::NO_ARGUMENT]
+)
+puts "Original ARGV: #{ARGV}"
+options.each do |option, argument|
+ p [option, argument]
+end
+puts "Remaining ARGV: #{ARGV}"
diff --git a/sample/getoptlong/fibonacci.rb b/sample/getoptlong/fibonacci.rb
new file mode 100644
index 0000000000..24a2aab3c3
--- /dev/null
+++ b/sample/getoptlong/fibonacci.rb
@@ -0,0 +1,62 @@
+require 'getoptlong'
+
+options = GetoptLong.new(
+ ['--number', '-n', GetoptLong::REQUIRED_ARGUMENT],
+ ['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT],
+ ['--help', '-h', GetoptLong::NO_ARGUMENT]
+)
+
+def help(status = 0)
+ puts <<~HELP
+ Usage:
+
+ -n n, --number n:
+ Compute Fibonacci number for n.
+ -v [boolean], --verbose [boolean]:
+ Show intermediate results; default is 'false'.
+ -h, --help:
+ Show this help.
+ HELP
+ exit(status)
+end
+
+def print_fibonacci (number)
+ return 0 if number == 0
+ return 1 if number == 1 or number == 2
+ i = 0
+ j = 1
+ (2..number).each do
+ k = i + j
+ i = j
+ j = k
+ puts j if @verbose
+ end
+ puts j unless @verbose
+end
+
+options.each do |option, argument|
+ case option
+ when '--number'
+ @number = argument.to_i
+ when '--verbose'
+ @verbose = if argument.empty?
+ true
+ elsif argument.match(/true/i)
+ true
+ elsif argument.match(/false/i)
+ false
+ else
+ puts '--verbose argument must be true or false'
+ help(255)
+ end
+ when '--help'
+ help
+ end
+end
+
+unless @number
+ puts 'Option --number is required.'
+ help(255)
+end
+
+print_fibonacci(@number)
diff --git a/sample/getoptlong/permute.rb b/sample/getoptlong/permute.rb
new file mode 100644
index 0000000000..8efcad22ea
--- /dev/null
+++ b/sample/getoptlong/permute.rb
@@ -0,0 +1,12 @@
+require 'getoptlong'
+
+options = GetoptLong.new(
+ ['--xxx', GetoptLong::REQUIRED_ARGUMENT],
+ ['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
+ ['--zzz', GetoptLong::NO_ARGUMENT]
+)
+puts "Original ARGV: #{ARGV}"
+options.each do |option, argument|
+ p [option, argument]
+end
+puts "Remaining ARGV: #{ARGV}"
diff --git a/sample/getoptlong/require_order.rb b/sample/getoptlong/require_order.rb
new file mode 100644
index 0000000000..357f667905
--- /dev/null
+++ b/sample/getoptlong/require_order.rb
@@ -0,0 +1,13 @@
+require 'getoptlong'
+
+options = GetoptLong.new(
+ ['--xxx', GetoptLong::REQUIRED_ARGUMENT],
+ ['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
+ ['--zzz', GetoptLong::NO_ARGUMENT]
+)
+options.ordering = GetoptLong::REQUIRE_ORDER
+puts "Original ARGV: #{ARGV}"
+options.each do |option, argument|
+ p [option, argument]
+end
+puts "Remaining ARGV: #{ARGV}"
diff --git a/sample/getoptlong/return_in_order.rb b/sample/getoptlong/return_in_order.rb
new file mode 100644
index 0000000000..91ce1ef996
--- /dev/null
+++ b/sample/getoptlong/return_in_order.rb
@@ -0,0 +1,13 @@
+require 'getoptlong'
+
+options = GetoptLong.new(
+ ['--xxx', GetoptLong::REQUIRED_ARGUMENT],
+ ['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
+ ['--zzz', GetoptLong::NO_ARGUMENT]
+)
+options.ordering = GetoptLong::RETURN_IN_ORDER
+puts "Original ARGV: #{ARGV}"
+options.each do |option, argument|
+ p [option, argument]
+end
+puts "Remaining ARGV: #{ARGV}"
diff --git a/sample/getoptlong/simple.rb b/sample/getoptlong/simple.rb
new file mode 100644
index 0000000000..1af6447632
--- /dev/null
+++ b/sample/getoptlong/simple.rb
@@ -0,0 +1,7 @@
+require 'getoptlong'
+
+options = GetoptLong.new(
+ ['--number', '-n', GetoptLong::REQUIRED_ARGUMENT],
+ ['--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT],
+ ['--help', '-h', GetoptLong::NO_ARGUMENT]
+)
diff --git a/sample/getoptlong/types.rb b/sample/getoptlong/types.rb
new file mode 100644
index 0000000000..ac74bfe12e
--- /dev/null
+++ b/sample/getoptlong/types.rb
@@ -0,0 +1,10 @@
+require 'getoptlong'
+
+options = GetoptLong.new(
+ ['--xxx', GetoptLong::REQUIRED_ARGUMENT],
+ ['--yyy', GetoptLong::OPTIONAL_ARGUMENT],
+ ['--zzz', GetoptLong::NO_ARGUMENT]
+)
+options.each do |option, argument|
+ p [option, argument]
+end
diff --git a/sample/net-imap.rb b/sample/net-imap.rb
new file mode 100644
index 0000000000..b93ecb746e
--- /dev/null
+++ b/sample/net-imap.rb
@@ -0,0 +1,167 @@
+require 'net/imap'
+require "getoptlong"
+
+$stdout.sync = true
+$port = nil
+$user = ENV["USER"] || ENV["LOGNAME"]
+$auth = "login"
+$ssl = false
+$starttls = false
+
+def usage
+ <<EOF
+usage: #{$0} [options] <host>
+
+ --help print this message
+ --port=PORT specifies port
+ --user=USER specifies user
+ --auth=AUTH specifies auth type
+ --starttls use starttls
+ --ssl use ssl
+EOF
+end
+
+begin
+ require 'io/console'
+rescue LoadError
+ def _noecho(&block)
+ system("stty", "-echo")
+ begin
+ yield STDIN
+ ensure
+ system("stty", "echo")
+ end
+ end
+else
+ def _noecho(&block)
+ STDIN.noecho(&block)
+ end
+end
+
+def get_password
+ print "password: "
+ begin
+ return _noecho(&:gets).chomp
+ ensure
+ puts
+ end
+end
+
+def get_command
+ printf("%s@%s> ", $user, $host)
+ if line = gets
+ return line.strip.split(/\s+/)
+ else
+ return nil
+ end
+end
+
+parser = GetoptLong.new
+parser.set_options(['--debug', GetoptLong::NO_ARGUMENT],
+ ['--help', GetoptLong::NO_ARGUMENT],
+ ['--port', GetoptLong::REQUIRED_ARGUMENT],
+ ['--user', GetoptLong::REQUIRED_ARGUMENT],
+ ['--auth', GetoptLong::REQUIRED_ARGUMENT],
+ ['--starttls', GetoptLong::NO_ARGUMENT],
+ ['--ssl', GetoptLong::NO_ARGUMENT])
+begin
+ parser.each_option do |name, arg|
+ case name
+ when "--port"
+ $port = arg
+ when "--user"
+ $user = arg
+ when "--auth"
+ $auth = arg
+ when "--ssl"
+ $ssl = true
+ when "--starttls"
+ $starttls = true
+ when "--debug"
+ Net::IMAP.debug = true
+ when "--help"
+ usage
+ exit
+ end
+ end
+rescue
+ abort usage
+end
+
+$host = ARGV.shift
+unless $host
+ abort usage
+end
+
+imap = Net::IMAP.new($host, :port => $port, :ssl => $ssl)
+begin
+ imap.starttls if $starttls
+ class << password = method(:get_password)
+ alias to_str call
+ end
+ imap.authenticate($auth, $user, password)
+ while true
+ cmd, *args = get_command
+ break unless cmd
+ begin
+ case cmd
+ when "list"
+ for mbox in imap.list("", args[0] || "*")
+ if mbox.attr.include?(Net::IMAP::NOSELECT)
+ prefix = "!"
+ elsif mbox.attr.include?(Net::IMAP::MARKED)
+ prefix = "*"
+ else
+ prefix = " "
+ end
+ print prefix, mbox.name, "\n"
+ end
+ when "select"
+ imap.select(args[0] || "inbox")
+ print "ok\n"
+ when "close"
+ imap.close
+ print "ok\n"
+ when "summary"
+ unless messages = imap.responses["EXISTS"][-1]
+ puts "not selected"
+ next
+ end
+ if messages > 0
+ for data in imap.fetch(1..-1, ["ENVELOPE"])
+ print data.seqno, ": ", data.attr["ENVELOPE"].subject, "\n"
+ end
+ else
+ puts "no message"
+ end
+ when "fetch"
+ if args[0]
+ data = imap.fetch(args[0].to_i, ["RFC822.HEADER", "RFC822.TEXT"])[0]
+ puts data.attr["RFC822.HEADER"]
+ puts data.attr["RFC822.TEXT"]
+ else
+ puts "missing argument"
+ end
+ when "logout", "exit", "quit"
+ break
+ when "help", "?"
+ print <<EOF
+list [pattern] list mailboxes
+select [mailbox] select mailbox
+close close mailbox
+summary display summary
+fetch [msgno] display message
+logout logout
+help, ? display help message
+EOF
+ else
+ print "unknown command: ", cmd, "\n"
+ end
+ rescue Net::IMAP::Error
+ puts $!
+ end
+ end
+ensure
+ imap.logout
+ imap.disconnect
+end
diff --git a/sample/prism/find_calls.rb b/sample/prism/find_calls.rb
deleted file mode 100644
index 30af56c719..0000000000
--- a/sample/prism/find_calls.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-# This script finds calls to a specific method with a certain keyword parameter
-# within a given source file.
-
-require "prism"
-require "pp"
-
-# For deprecation or refactoring purposes, it's often useful to find all of the
-# places that call a specific method with a specific k eyword parameter. This is
-# easily accomplished with a visitor such as this one.
-class QuxParameterVisitor < Prism::Visitor
- def initialize(calls)
- @calls = calls
- end
-
- def visit_call_node(node)
- @calls << node if qux?(node)
- super
- end
-
- private
-
- def qux?(node)
- # All nodes implement pattern matching, so you can use the `in` operator to
- # pull out all of their individual fields. As you can see by this extensive
- # pattern match, this is quite a powerful feature.
- node in {
- # This checks that the receiver is the constant Qux or the constant path
- # ::Qux. We are assuming relative constants are fine in this case.
- receiver: (
- Prism::ConstantReadNode[name: :Qux] |
- Prism::ConstantPathNode[parent: nil, name: :Qux]
- ),
- # This checks that the name of the method is qux. We purposefully are not
- # checking the call operator (., ::, or &.) because we want all of them.
- # In other ASTs, this would be multiple node types, but prism combines
- # them all into one for convenience.
- name: :qux,
- arguments: Prism::ArgumentsNode[
- # Here we're going to use the "find" pattern to find the keyword hash
- # node that has the correct key.
- arguments: [
- *,
- Prism::KeywordHashNode[
- # Here we'll use another "find" pattern to find the key that we are
- # specifically looking for.
- elements: [
- *,
- # Finally, we can assert against the key itself. Note that we are
- # not looking at the value of hash pair, because we are only
- # specifically looking for a key.
- Prism::AssocNode[key: Prism::SymbolNode[unescaped: "qux"]],
- *
- ]
- ],
- *
- ]
- ]
- }
- end
-end
-
-calls = []
-Prism.parse_stream(DATA).value.accept(QuxParameterVisitor.new(calls))
-
-calls.each do |call|
- print "CallNode "
- puts PP.pp(call.location, +"")
- print " "
- puts call.slice
-end
-
-# =>
-# CallNode (5,6)-(5,29)
-# Qux.qux(222, qux: true)
-# CallNode (9,6)-(9,30)
-# Qux&.qux(333, qux: true)
-# CallNode (20,6)-(20,51)
-# Qux::qux(888, qux: ::Qux.qux(999, qux: true))
-# CallNode (20,25)-(20,50)
-# ::Qux.qux(999, qux: true)
-
-__END__
-module Foo
- class Bar
- def baz1
- Qux.qux(111)
- Qux.qux(222, qux: true)
- end
-
- def baz2
- Qux&.qux(333, qux: true)
- Qux&.qux(444)
- end
-
- def baz3
- qux(555, qux: false)
- 666.qux(666)
- end
-
- def baz4
- Qux::qux(777)
- Qux::qux(888, qux: ::Qux.qux(999, qux: true))
- end
- end
-end
diff --git a/sample/prism/find_comments.rb b/sample/prism/find_comments.rb
deleted file mode 100644
index 6a26cd32b7..0000000000
--- a/sample/prism/find_comments.rb
+++ /dev/null
@@ -1,100 +0,0 @@
-# This script finds all of the comments within a given source file for a method.
-
-require "prism"
-
-class FindMethodComments < Prism::Visitor
- def initialize(target, comments, nesting = [])
- @target = target
- @comments = comments
- @nesting = nesting
- end
-
- # These visit methods are specific to each class. Defining a visitor allows
- # you to group functionality that applies to all node types into a single
- # class. You can find which method corresponds to which node type by looking
- # at the class name, calling #type on the node, or by looking at the #accept
- # method definition on the node.
- def visit_module_node(node)
- visitor = FindMethodComments.new(@target, @comments, [*@nesting, node.name])
- node.compact_child_nodes.each { |child| child.accept(visitor) }
- end
-
- def visit_class_node(node)
- # We could keep track of an internal state where we push the class name here
- # and then pop it after the visit is complete. However, it is often simpler
- # and cleaner to generate a new visitor instance when the state changes,
- # because then the state is immutable and it's easier to reason about. This
- # also provides for more debugging opportunity in the initializer.
- visitor = FindMethodComments.new(@target, @comments, [*@nesting, node.name])
- node.compact_child_nodes.each { |child| child.accept(visitor) }
- end
-
- def visit_def_node(node)
- if [*@nesting, node.name] == @target
- # Comments are always attached to locations (either inner locations on a
- # node like the location of a keyword or the location on the node itself).
- # Nodes are considered either "leading" or "trailing", which means that
- # they occur before or after the location, respectively. In this case of
- # documentation, we only want to consider leading comments. You can also
- # fetch all of the comments on a location with #comments.
- @comments.concat(node.location.leading_comments)
- else
- super
- end
- end
-end
-
-# Most of the time, the concept of "finding" something in the AST can be
-# accomplished either with a queue or with a visitor. In this case we will use a
-# visitor, but a queue would work just as well.
-def find_comments(result, path)
- target = path.split(/::|#/).map(&:to_sym)
- comments = []
-
- result.value.accept(FindMethodComments.new(target, comments))
- comments
-end
-
-result = Prism.parse_stream(DATA)
-result.attach_comments!
-
-find_comments(result, "Foo#foo").each do |comment|
- puts comment.inspect
- puts comment.slice
-end
-
-# =>
-# #<Prism::InlineComment @location=#<Prism::Location @start_offset=205 @length=27 start_line=13>>
-# # This is the documentation
-# #<Prism::InlineComment @location=#<Prism::Location @start_offset=235 @length=21 start_line=14>>
-# # for the foo method.
-
-find_comments(result, "Foo::Bar#bar").each do |comment|
- puts comment.inspect
- puts comment.slice
-end
-
-# =>
-# #<Prism::InlineComment @location=#<Prism::Location @start_offset=126 @length=23 start_line=7>>
-# # This is documentation
-# #<Prism::InlineComment @location=#<Prism::Location @start_offset=154 @length=21 start_line=8>>
-# # for the bar method.
-
-__END__
-# This is the documentation
-# for the Foo module.
-module Foo
- # This is documentation
- # for the Bar class.
- class Bar
- # This is documentation
- # for the bar method.
- def bar
- end
- end
-
- # This is the documentation
- # for the foo method.
- def foo
- end
-end
diff --git a/sample/prism/locate_nodes.rb b/sample/prism/locate_nodes.rb
deleted file mode 100644
index 7a51db4367..0000000000
--- a/sample/prism/locate_nodes.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# This script locates a set of nodes determined by a line and column (in bytes).
-
-require "prism"
-require "pp"
-
-# This method determines if the given location covers the given line and column.
-# It's important to note that columns (and offsets) in prism are always in
-# bytes. This is because prism supports all 90 source encodings that Ruby
-# supports. You can always retrieve the column (or offset) of a location in
-# other units with other provided APIs, like #start_character_column or
-# #start_code_units_column.
-def covers?(location, line:, column:)
- start_line = location.start_line
- end_line = location.end_line
-
- if start_line == end_line
- # If the location only spans one line, then we only check if the line
- # matches and that the column is covered by the column range.
- line == start_line && (location.start_column...location.end_column).cover?(column)
- else
- # Otherwise, we check that it is on the start line and the column is greater
- # than or equal to the start column, or that it is on the end line and the
- # column is less than the end column, or that it is between the start and
- # end lines.
- (line == start_line && column >= location.start_column) ||
- (line == end_line && column < location.end_column) ||
- (line > start_line && line < end_line)
- end
-end
-
-# This method descends down into the AST whose root is `node` and returns the
-# array of all of the nodes that cover the given line and column.
-def locate(node, line:, column:)
- queue = [node]
- result = []
-
- # We could use a recursive method here instead if we wanted, but it's
- # important to note that that will not work for ASTs that are nested deeply
- # enough to cause a stack overflow.
- while (node = queue.shift)
- result << node
-
- # Nodes have `child_nodes` and `compact_child_nodes`. `child_nodes` have
- # consistent indices but include `nil` for optional fields that are not
- # present, whereas `compact_child_nodes` has inconsistent indices but does
- # not include `nil` for optional fields that are not present.
- node.compact_child_nodes.find do |child|
- queue << child if covers?(child.location, line: line, column: column)
- end
- end
-
- result
-end
-
-result = Prism.parse_stream(DATA)
-locate(result.value, line: 4, column: 14).each_with_index do |node, index|
- print " " * index
- print node.class.name.split("::", 2).last
- print " "
- puts PP.pp(node.location, +"")
-end
-
-# =>
-# ProgramNode (1,0)-(7,3)
-# StatementsNode (1,0)-(7,3)
-# ModuleNode (1,0)-(7,3)
-# StatementsNode (2,2)-(6,5)
-# ClassNode (2,2)-(6,5)
-# StatementsNode (3,4)-(5,7)
-# DefNode (3,4)-(5,7)
-# StatementsNode (4,6)-(4,21)
-# CallNode (4,6)-(4,21)
-# CallNode (4,6)-(4,15)
-# ArgumentsNode (4,12)-(4,15)
-# IntegerNode (4,12)-(4,15)
-
-__END__
-module Foo
- class Bar
- def baz
- 111 + 222 + 333
- end
- end
-end
diff --git a/sample/prism/make_tags.rb b/sample/prism/make_tags.rb
deleted file mode 100644
index dc770ab1b0..0000000000
--- a/sample/prism/make_tags.rb
+++ /dev/null
@@ -1,302 +0,0 @@
-# This script generates a tags file using Prism to parse the Ruby files.
-
-require "prism"
-
-# This visitor is responsible for visiting the nodes in the AST and generating
-# the appropriate tags. The tags are stored in the entries array as strings.
-class TagsVisitor < Prism::Visitor
- # This represents an entry in the tags file, which is a tab-separated line. It
- # houses the logic for how an entry is constructed.
- class Entry
- attr_reader :parts
-
- def initialize(name, filepath, pattern, type)
- @parts = [name, filepath, pattern, type]
- end
-
- def attribute(key, value)
- parts << "#{key}:#{value}"
- end
-
- def attribute_class(nesting, names)
- return if nesting.empty? && names.length == 1
- attribute("class", [*nesting, names].flatten.tap(&:pop).join("."))
- end
-
- def attribute_inherits(names)
- attribute("inherits", names.join(".")) if names
- end
-
- def to_line
- parts.join("\t")
- end
- end
-
- private_constant :Entry
-
- attr_reader :entries, :filepath, :lines, :nesting, :singleton
-
- # Initialize the visitor with the given parameters. The first three parameters
- # are constant throughout the visit, while the last two are controlled by the
- # visitor as it traverses the AST. These are treated as immutable by virtue of
- # the visit methods constructing new visitors when they need to change.
- def initialize(entries, filepath, lines, nesting = [], singleton = false)
- @entries = entries
- @filepath = filepath
- @lines = lines
- @nesting = nesting
- @singleton = singleton
- end
-
- # Visit a method alias node and generate the appropriate tags.
- #
- # alias m2 m1
- #
- def visit_alias_method_node(node)
- enter(node.new_name.unescaped.to_sym, node, "a") do |entry|
- entry.attribute_class(nesting, [nil])
- end
-
- super
- end
-
- # Visit a method call to attr_reader, attr_writer, or attr_accessor without a
- # receiver and generate the appropriate tags. Note that this ignores the fact
- # that these methods could be overridden, which is a limitation of this
- # script.
- #
- # attr_accessor :m1
- #
- def visit_call_node(node)
- if !node.receiver && %i[attr_reader attr_writer attr_accessor].include?(name = node.name)
- (node.arguments&.arguments || []).grep(Prism::SymbolNode).each do |argument|
- if name != :attr_writer
- enter(:"#{argument.unescaped}", argument, singleton ? "F" : "f") do |entry|
- entry.attribute_class(nesting, [nil])
- end
- end
-
- if name != :attr_reader
- enter(:"#{argument.unescaped}=", argument, singleton ? "F" : "f") do |entry|
- entry.attribute_class(nesting, [nil])
- end
- end
- end
- end
-
- super
- end
-
- # Visit a class node and generate the appropriate tags.
- #
- # class C1
- # end
- #
- def visit_class_node(node)
- if (names = names_for(node.constant_path))
- enter(names.last, node, "c") do |entry|
- entry.attribute_class(nesting, names)
- entry.attribute_inherits(names_for(node.superclass))
- end
-
- node.body&.accept(copy_visitor([*nesting, names], singleton))
- end
- end
-
- # Visit a constant path write node and generate the appropriate tags.
- #
- # C1::C2 = 1
- #
- def visit_constant_path_write_node(node)
- if (names = names_for(node.target))
- enter(names.last, node, "C") do |entry|
- entry.attribute_class(nesting, names)
- end
- end
-
- super
- end
-
- # Visit a constant write node and generate the appropriate tags.
- #
- # C1 = 1
- #
- def visit_constant_write_node(node)
- enter(node.name, node, "C") do |entry|
- entry.attribute_class(nesting, [nil])
- end
-
- super
- end
-
- # Visit a method definition node and generate the appropriate tags.
- #
- # def m1; end
- #
- def visit_def_node(node)
- enter(node.name, node, (node.receiver || singleton) ? "F" : "f") do |entry|
- entry.attribute_class(nesting, [nil])
- end
-
- super
- end
-
- # Visit a module node and generate the appropriate tags.
- #
- # module M1
- # end
- #
- def visit_module_node(node)
- if (names = names_for(node.constant_path))
- enter(names.last, node, "m") do |entry|
- entry.attribute_class(nesting, names)
- end
-
- node.body&.accept(copy_visitor([*nesting, names], singleton))
- end
- end
-
- # Visit a singleton class node and generate the appropriate tags.
- #
- # class << self
- # end
- #
- def visit_singleton_class_node(node)
- case node.expression
- when Prism::SelfNode
- node.body&.accept(copy_visitor(nesting, true))
- when Prism::ConstantReadNode, Prism::ConstantPathNode
- if (names = names_for(node.expression))
- node.body&.accept(copy_visitor([*nesting, names], true))
- end
- else
- node.body&.accept(copy_visitor([*nesting, nil], true))
- end
- end
-
- private
-
- # Generate a new visitor with the given dynamic options. The static options
- # are copied over automatically.
- def copy_visitor(nesting, singleton)
- TagsVisitor.new(entries, filepath, lines, nesting, singleton)
- end
-
- # Generate a new entry for the given name, node, and type and add it into the
- # list of entries. The block is used to add additional attributes to the
- # entry.
- def enter(name, node, type)
- line = lines[node.location.start_line - 1].chomp
- pattern = "/^#{line.gsub("\\", "\\\\\\\\").gsub("/", "\\/")}$/;\""
-
- entry = Entry.new(name, filepath, pattern, type)
- yield entry
-
- entries << entry.to_line
- end
-
- # Retrieve the names for the given node. This is used to construct the class
- # attribute for the tags.
- def names_for(node)
- case node
- when Prism::ConstantPathNode
- names = names_for(node.parent)
- return unless names
-
- names << node.name
- when Prism::ConstantReadNode
- [node.name]
- when Prism::SelfNode
- [:self]
- else
- # dynamic
- end
- end
-end
-
-# Parse the Ruby file and visit all of the nodes in the resulting AST. Once all
-# of the nodes have been visited, the entries array should be populated with the
-# tags.
-result = Prism.parse_stream(DATA)
-result.value.accept(TagsVisitor.new(entries = [], __FILE__, result.source.lines))
-
-# Print the tags to STDOUT.
-puts "!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;\" to lines/"
-puts "!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/"
-puts entries.sort
-
-# =>
-# !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
-# !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
-# C1 sample/prism/make_tags.rb /^ class C1$/;" c class:M1.M2
-# C2 sample/prism/make_tags.rb /^ class C2 < Object$/;" c class:M1.M2.C1 inherits:Object
-# C6 sample/prism/make_tags.rb /^ C6 = 1$/;" C class:M1
-# C7 sample/prism/make_tags.rb /^ C7 = 2$/;" C class:M1
-# C9 sample/prism/make_tags.rb /^ C8::C9 = 3$/;" C class:M1.C8
-# M1 sample/prism/make_tags.rb /^module M1$/;" m
-# M2 sample/prism/make_tags.rb /^ module M2$/;" m class:M1
-# M4 sample/prism/make_tags.rb /^ module M3::M4$/;" m class:M1.M3
-# M5 sample/prism/make_tags.rb /^ module self::M5$/;" m class:M1.self
-# m1 sample/prism/make_tags.rb /^ def m1; end$/;" f class:M1.M2.C1.C2
-# m10 sample/prism/make_tags.rb /^ attr_accessor :m10, :m11$/;" f class:M1.M3.M4
-# m10= sample/prism/make_tags.rb /^ attr_accessor :m10, :m11$/;" f class:M1.M3.M4
-# m11 sample/prism/make_tags.rb /^ attr_accessor :m10, :m11$/;" f class:M1.M3.M4
-# m11= sample/prism/make_tags.rb /^ attr_accessor :m10, :m11$/;" f class:M1.M3.M4
-# m12 sample/prism/make_tags.rb /^ attr_reader :m12, :m13, :m14$/;" f class:M1.M3.M4
-# m13 sample/prism/make_tags.rb /^ attr_reader :m12, :m13, :m14$/;" f class:M1.M3.M4
-# m14 sample/prism/make_tags.rb /^ attr_reader :m12, :m13, :m14$/;" f class:M1.M3.M4
-# m15= sample/prism/make_tags.rb /^ attr_writer :m15$/;" f class:M1.M3.M4
-# m2 sample/prism/make_tags.rb /^ def m2; end$/;" f class:M1.M2.C1.C2
-# m3 sample/prism/make_tags.rb /^ alias m3 m1$/;" a class:M1.M2.C1.C2
-# m4 sample/prism/make_tags.rb /^ alias :m4 :m2$/;" a class:M1.M2.C1.C2
-# m5 sample/prism/make_tags.rb /^ def self.m5; end$/;" F class:M1.M2.C1.C2
-# m6 sample/prism/make_tags.rb /^ def m6; end$/;" F class:M1.M2.C1.C2
-# m7 sample/prism/make_tags.rb /^ def m7; end$/;" F class:M1.M2.C1.C2.C3
-# m8 sample/prism/make_tags.rb /^ def m8; end$/;" F class:M1.M2.C1.C2.C4.C5
-# m9 sample/prism/make_tags.rb /^ def m9; end$/;" F class:M1.M2.C1.C2.
-
-__END__
-module M1
- module M2
- class C1
- class C2 < Object
- def m1; end
- def m2; end
-
- alias m3 m1
- alias :m4 :m2
-
- def self.m5; end
-
- class << self
- def m6; end
- end
-
- class << C3
- def m7; end
- end
-
- class << C4::C5
- def m8; end
- end
-
- class << c
- def m9; end
- end
- end
- end
- end
-
- module M3::M4
- attr_accessor :m10, :m11
- attr_reader :m12, :m13, :m14
- attr_writer :m15
- end
-
- module self::M5
- end
-
- C6 = 1
- C7 = 2
- C8::C9 = 3
-end
diff --git a/sample/prism/visit_nodes.rb b/sample/prism/visit_nodes.rb
deleted file mode 100644
index 5ba703b0a3..0000000000
--- a/sample/prism/visit_nodes.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# This script visits all of the nodes of a specific type within a given source
-# file. It uses the visitor class to traverse the AST.
-
-require "prism"
-require "pp"
-
-class CaseInsensitiveRegularExpressionVisitor < Prism::Visitor
- def initialize(regexps)
- @regexps = regexps
- end
-
- # As the visitor is walking the tree, this method will only be called when it
- # encounters a regular expression node. We can then call any regular
- # expression -specific APIs. In this case, we are only interested in the
- # regular expressions that are case-insensitive, which we can retrieve with
- # the #ignore_case? method.
- def visit_regular_expression_node(node)
- @regexps << node if node.ignore_case?
- super
- end
-
- def visit_interpolated_regular_expression_node(node)
- @regexps << node if node.ignore_case?
-
- # The default behavior of the visitor is to continue visiting the children
- # of the node. Because Ruby is so dynamic, it's actually possible for
- # another regular expression to be interpolated in statements contained
- # within the #{} contained in this interpolated regular expression node. By
- # calling `super`, we ensure the visitor will continue. Failing to call
- # `super` will cause the visitor to stop the traversal of the tree, which
- # can also be useful in some cases.
- super
- end
-end
-
-result = Prism.parse_stream(DATA)
-regexps = []
-
-result.value.accept(CaseInsensitiveRegularExpressionVisitor.new(regexps))
-regexps.each do |node|
- print node.class.name.split("::", 2).last
- print " "
- puts PP.pp(node.location, +"")
-
- if node.is_a?(Prism::RegularExpressionNode)
- print " "
- p node.unescaped
- end
-end
-
-# =>
-# InterpolatedRegularExpressionNode (3,9)-(3,47)
-# RegularExpressionNode (3,16)-(3,22)
-# "bar"
-# RegularExpressionNode (4,9)-(4,15)
-# "bar"
-
-__END__
-class Foo
- REG1 = /foo/
- REG2 = /foo #{/bar/i =~ "" ? "bar" : "baz"}/i
- REG3 = /bar/i
-end
diff --git a/sample/win32ole/olegen.rb b/sample/win32ole/olegen.rb
deleted file mode 100644
index 9398194cf1..0000000000
--- a/sample/win32ole/olegen.rb
+++ /dev/null
@@ -1,348 +0,0 @@
-# frozen_string_literal: false
-#-----------------------------
-# olegen.rb
-# $Revision$
-#-----------------------------
-
-require 'win32ole'
-
-class WIN32COMGen
- def initialize(typelib)
- @typelib = typelib
- @receiver = ""
- end
- attr_reader :typelib
-
- def ole_classes(typelib)
- begin
- @ole = WIN32OLE.new(typelib)
- [@ole.ole_obj_help]
- rescue
- WIN32OLE_TYPE.ole_classes(typelib)
- end
- end
-
- def generate_args(method)
- args = []
- if method.size_opt_params >= 0
- size_required_params = method.size_params - method.size_opt_params
- else
- size_required_params = method.size_params - 1
- end
- size_required_params.times do |i|
- if method.params[i] && method.params[i].optional?
- args.push "arg#{i}=nil"
- else
- args.push "arg#{i}"
- end
- end
- if method.size_opt_params >= 0
- method.size_opt_params.times do |i|
- args.push "arg#{i + size_required_params}=nil"
- end
- else
- args.push "*arg"
- end
- args.join(", ")
- end
-
- def generate_argtype(typedetails)
- ts = ''
- typedetails.each do |t|
- case t
- when 'CARRAY', 'VOID', 'UINT', 'RESULT', 'DECIMAL', 'I8', 'UI8'
-# raise "Sorry type\"" + t + "\" not supported"
- ts << "\"??? NOT SUPPORTED TYPE:`#{t}'\""
- when 'USERDEFINED', 'Unknown Type 9'
- ts << 'VT_DISPATCH'
- break;
- when 'SAFEARRAY'
- ts << 'VT_ARRAY|'
- when 'PTR'
- ts << 'VT_BYREF|'
- when 'INT'
- ts << 'VT_I4'
- else
- if String === t
- ts << 'VT_' + t
- end
- end
- end
- if ts.empty?
- ts = 'VT_VARIANT'
- elsif ts.end_with?(?|)
- ts += 'VT_VARIANT'
- end
- ts
- end
-
- def generate_argtypes(method, proptypes)
- types = method.params.collect{|param|
- generate_argtype(param.ole_type_detail)
- }.join(", ")
- if proptypes
- types += ", " if types.size > 0
- types += generate_argtype(proptypes)
- end
- types
- end
-
- def generate_method_body(method, disptype, types=nil)
- " ret = #{@receiver}#{disptype}(#{method.dispid}, [" +
- generate_args(method).gsub("=nil", "") +
- "], [" +
- generate_argtypes(method, types) +
- "])\n" +
- " @lastargs = WIN32OLE::ARGV\n" +
- " ret"
- end
-
- def generate_method_help(method, type = nil)
- str = " # "
- if type
- str += type
- else
- str += method.return_type
- end
- str += " #{method.name}"
- if method.event?
- str += " EVENT"
- str += " in #{method.event_interface}"
- end
- if method.helpstring && method.helpstring != ""
- str += "\n # "
- str += method.helpstring
- end
- args_help = generate_method_args_help(method)
- if args_help
- str += "\n"
- str += args_help
- end
- str
- end
-
- def generate_method_args_help(method)
- args = []
- method.params.each_with_index {|param, i|
- h = " # #{param.ole_type} arg#{i} --- #{param.name}"
- inout = []
- inout.push "IN" if param.input?
- inout.push "OUT" if param.output?
- h += " [#{inout.join('/')}]"
- h += " ( = #{param.default})" if param.default
- args.push h
- }
- if args.size > 0
- args.join("\n")
- else
- nil
- end
- end
-
- def generate_method(method, disptype, io = STDOUT, types = nil)
- io.puts "\n"
- io.puts generate_method_help(method)
- if method.invoke_kind == 'PROPERTYPUT'
- io.print " def #{method.name}=("
- else
- io.print " def #{method.name}("
- end
- io.print generate_args(method)
- io.puts ")"
- io.puts generate_method_body(method, disptype, types)
- io.puts " end"
- end
-
- def generate_propputref_methods(klass, io = STDOUT)
- klass.ole_methods.select {|method|
- method.invoke_kind == 'PROPERTYPUTREF' && method.visible?
- }.each do |method|
- generate_method(method, io)
- end
- end
-
- def generate_properties_with_args(klass, io = STDOUT)
- klass.ole_methods.select {|method|
- method.invoke_kind == 'PROPERTYGET' &&
- method.visible? &&
- method.size_params > 0
- }.each do |method|
- types = method.return_type_detail
- io.puts "\n"
- io.puts generate_method_help(method, types[0])
- io.puts " def #{method.name}"
- if klass.ole_type == "Class"
- io.print " OLEProperty.new(@dispatch, #{method.dispid}, ["
- else
- io.print " OLEProperty.new(self, #{method.dispid}, ["
- end
- io.print generate_argtypes(method, nil)
- io.print "], ["
- io.print generate_argtypes(method, types)
- io.puts "])"
- io.puts " end"
- end
- end
-
- def generate_propput_methods(klass, io = STDOUT)
- klass.ole_methods.select {|method|
- method.invoke_kind == 'PROPERTYPUT' && method.visible? &&
- method.size_params == 1
- }.each do |method|
- ms = klass.ole_methods.select {|m|
- m.invoke_kind == 'PROPERTYGET' &&
- m.dispid == method.dispid
- }
- types = []
- if ms.size == 1
- types = ms[0].return_type_detail
- end
- generate_method(method, '_setproperty', io, types)
- end
- end
-
- def generate_propget_methods(klass, io = STDOUT)
- klass.ole_methods.select {|method|
- method.invoke_kind == 'PROPERTYGET' && method.visible? &&
- method.size_params == 0
- }.each do |method|
- generate_method(method, '_getproperty', io)
- end
- end
-
- def generate_func_methods(klass, io = STDOUT)
- klass.ole_methods.select {|method|
- method.invoke_kind == "FUNC" && method.visible?
- }.each do |method|
- generate_method(method, '_invoke', io)
- end
- end
-
- def generate_methods(klass, io = STDOUT)
- generate_propget_methods(klass, io)
- generate_propput_methods(klass, io)
- generate_properties_with_args(klass, io)
- generate_func_methods(klass, io)
-# generate_propputref_methods(klass, io)
- end
-
- def generate_constants(klass, io = STDOUT)
- klass.variables.select {|v|
- v.visible? && v.variable_kind == 'CONSTANT'
- }.each do |v|
- io.print " "
- io.print v.name.sub(/^./){$&.upcase}
- io.print " = "
- io.puts v.value
- end
- end
-
- def class_name(klass)
- klass_name = klass.name
- if klass.ole_type == "Class" &&
- klass.guid &&
- klass.progid
- klass_name = klass.progid.gsub(/\./, '_')
- end
- if /^[A-Z]/ !~ klass_name || Module.constants.include?(klass_name)
- klass_name = 'OLE' + klass_name
- end
- klass_name
- end
-
- def define_initialize(klass)
- <<STR
-
- def initialize(obj = nil)
- @clsid = "#{klass.guid}"
- @progid = "#{klass.progid}"
- if obj.nil?
- @dispatch = WIN32OLE.new @progid
- else
- @dispatch = obj
- end
- end
-STR
- end
-
- def define_include
- " include WIN32OLE::VARIANT"
- end
-
- def define_instance_variables
- " attr_reader :lastargs"
- end
-
- def define_method_missing
- <<STR
-
- def method_missing(cmd, *arg)
- @dispatch.method_missing(cmd, *arg)
- end
-STR
- end
-
- def define_class(klass, io = STDOUT)
- io.puts "class #{class_name(klass)} # #{klass.name}"
- io.puts define_include
- io.puts define_instance_variables
- io.puts " attr_reader :dispatch"
- io.puts " attr_reader :clsid"
- io.puts " attr_reader :progid"
- io.puts define_initialize(klass)
- io.puts define_method_missing
- end
-
- def define_module(klass, io = STDOUT)
- io.puts "module #{class_name(klass)}"
- io.puts define_include
- io.puts define_instance_variables
- end
-
- def generate_class(klass, io = STDOUT)
- io.puts "\n# #{klass.helpstring}"
- if klass.ole_type == "Class" &&
- klass.guid &&
- klass.progid
- @receiver = "@dispatch."
- define_class(klass, io)
- else
- @receiver = ""
- define_module(klass, io)
- end
- generate_constants(klass, io)
- generate_methods(klass, io)
- io.puts "end"
- end
-
- def generate(io = STDOUT)
- io.puts "require 'win32ole'"
- io.puts "require 'win32ole/property'"
-
- ole_classes(typelib).select{|klass|
- klass.visible? &&
- (klass.ole_type == "Class" ||
- klass.ole_type == "Interface" ||
- klass.ole_type == "Dispatch" ||
- klass.ole_type == "Enum")
- }.each do |klass|
- generate_class(klass, io)
- end
- begin
- @ole.quit if @ole
- rescue
- end
- end
-end
-
-require 'win32ole'
-if __FILE__ == $0
- if ARGV.size == 0
- $stderr.puts "usage: #{$0} Type Library [...]"
- exit 1
- end
- ARGV.each do |typelib|
- comgen = WIN32COMGen.new(typelib)
- comgen.generate
- end
-end
diff --git a/scheduler.c b/scheduler.c
index 3159635dba..4be18e1799 100644
--- a/scheduler.c
+++ b/scheduler.c
@@ -403,7 +403,15 @@ rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber)
{
VM_ASSERT(rb_obj_is_fiber(fiber));
- return rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
+ // `rb_fiber_scheduler_unblock` can be called from points where `errno` is expected to be preserved. Therefore, we should save and restore it. For example `io_binwrite` calls `rb_fiber_scheduler_unblock` and if `errno` is reset to 0 by user code, it will break the error handling in `io_write`.
+ // If we explicitly preserve `errno` in `io_binwrite` and other similar functions (e.g. by returning it), this code is no longer needed. I hope in the future we will be able to remove it.
+ int saved_errno = errno;
+
+ VALUE result = rb_funcall(scheduler, id_unblock, 2, blocker, fiber);
+
+ errno = saved_errno;
+
+ return result;
}
/*
@@ -474,15 +482,15 @@ VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
/*
* Document-method: Fiber::Scheduler#io_read
- * call-seq: io_read(io, buffer, length, offset) -> read length or -errno
+ * call-seq: io_read(io, buffer, minimum_length) -> read length or -errno
*
* Invoked by IO#read or IO#Buffer.read to read +length+ bytes from +io+ into a
- * specified +buffer+ (see IO::Buffer) at the given +offset+.
+ * specified +buffer+ (see IO::Buffer).
*
- * The +length+ argument is the "minimum length to be read". If the IO buffer
- * size is 8KiB, but the +length+ is +1024+ (1KiB), up to 8KiB might be read,
- * but at least 1KiB will be. Generally, the only case where less data than
- * +length+ will be read is if there is an error reading the data.
+ * The +minimum_length+ argument is the "minimum length to be read". If the IO
+ * buffer size is 8KiB, but the +length+ is +1024+ (1KiB), up to 8KiB might be
+ * read, but at least 1KiB will be. Generally, the only case where less data
+ * than +length+ will be read is if there is an error reading the data.
*
* Specifying a +length+ of 0 is valid and means try reading at least once and
* return any available data.
@@ -508,19 +516,13 @@ rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t lengt
return rb_check_funcall(scheduler, id_io_read, 4, arguments);
}
+
/*
* Document-method: Fiber::Scheduler#io_read
* call-seq: io_pread(io, buffer, from, length, offset) -> read length or -errno
*
- * Invoked by IO#pread or IO::Buffer#pread to read +length+ bytes from +io+
- * at offset +from+ into a specified +buffer+ (see IO::Buffer) at the given
- * +offset+.
- *
- * This method is semantically the same as #io_read, but it allows to specify
- * the offset to read from and is often better for asynchronous IO on the same
- * file.
+ * Invoked by IO::Buffer#pread. See that method for description of arguments.
*
- * The method should be considered _experimental_.
*/
VALUE
rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset)
@@ -534,16 +536,16 @@ rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buff
/*
* Document-method: Scheduler#io_write
- * call-seq: io_write(io, buffer, length, offset) -> written length or -errno
+ * call-seq: io_write(io, buffer, minimum_length) -> written length or -errno
*
* Invoked by IO#write or IO::Buffer#write to write +length+ bytes to +io+ from
- * from a specified +buffer+ (see IO::Buffer) at the given +offset+.
+ * from a specified +buffer+ (see IO::Buffer).
*
- * The +length+ argument is the "minimum length to be written". If the IO
- * buffer size is 8KiB, but the +length+ specified is 1024 (1KiB), at most 8KiB
- * will be written, but at least 1KiB will be. Generally, the only case where
- * less data than +length+ will be written is if there is an error writing the
- * data.
+ * The +minimum_length+ argument is the "minimum length to be written". If the
+ * IO buffer size is 8KiB, but the +length+ specified is 1024 (1KiB), at most
+ * 8KiB will be written, but at least 1KiB will be. Generally, the only case
+ * where less data than +minimum_length+ will be written is if there is an
+ * error writing the data.
*
* Specifying a +length+ of 0 is valid and means try writing at least once, as
* much data as possible.
@@ -574,15 +576,7 @@ rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t leng
* Document-method: Fiber::Scheduler#io_pwrite
* call-seq: io_pwrite(io, buffer, from, length, offset) -> written length or -errno
*
- * Invoked by IO#pwrite or IO::Buffer#pwrite to write +length+ bytes to +io+
- * at offset +from+ into a specified +buffer+ (see IO::Buffer) at the given
- * +offset+.
- *
- * This method is semantically the same as #io_write, but it allows to specify
- * the offset to write to and is often better for asynchronous IO on the same
- * file.
- *
- * The method should be considered _experimental_.
+ * Invoked by IO::Buffer#pwrite. See that method for description of arguments.
*
*/
VALUE
@@ -602,7 +596,8 @@ rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t
VALUE result = rb_fiber_scheduler_io_read(scheduler, io, buffer, length, 0);
- rb_io_buffer_free_locked(buffer);
+ rb_io_buffer_unlock(buffer);
+ rb_io_buffer_free(buffer);
return result;
}
@@ -614,31 +609,8 @@ rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base,
VALUE result = rb_fiber_scheduler_io_write(scheduler, io, buffer, length, 0);
- rb_io_buffer_free_locked(buffer);
-
- return result;
-}
-
-VALUE
-rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
-{
- VALUE buffer = rb_io_buffer_new(base, size, RB_IO_BUFFER_LOCKED);
-
- VALUE result = rb_fiber_scheduler_io_pread(scheduler, io, from, buffer, length, 0);
-
- rb_io_buffer_free_locked(buffer);
-
- return result;
-}
-
-VALUE
-rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
-{
- VALUE buffer = rb_io_buffer_new((void*)base, size, RB_IO_BUFFER_LOCKED|RB_IO_BUFFER_READONLY);
-
- VALUE result = rb_fiber_scheduler_io_pwrite(scheduler, io, from, buffer, length, 0);
-
- rb_io_buffer_free_locked(buffer);
+ rb_io_buffer_unlock(buffer);
+ rb_io_buffer_free(buffer);
return result;
}
diff --git a/shape.c b/shape.c
index b0e8866928..1dc08dcb60 100644
--- a/shape.c
+++ b/shape.c
@@ -1,303 +1,22 @@
#include "vm_core.h"
#include "vm_sync.h"
#include "shape.h"
+#include "gc.h"
#include "symbol.h"
#include "id_table.h"
#include "internal/class.h"
-#include "internal/error.h"
-#include "internal/gc.h"
-#include "internal/object.h"
#include "internal/symbol.h"
#include "internal/variable.h"
#include "variable.h"
#include <stdbool.h>
-#ifndef _WIN32
-#include <sys/mman.h>
-#endif
-
#ifndef SHAPE_DEBUG
#define SHAPE_DEBUG (VM_CHECK_MODE > 0)
#endif
-#if SIZEOF_SHAPE_T == 4
-#if RUBY_DEBUG
-#define SHAPE_BUFFER_SIZE 0x8000
-#else
-#define SHAPE_BUFFER_SIZE 0x80000
-#endif
-#else
-#define SHAPE_BUFFER_SIZE 0x8000
-#endif
-
-#define REDBLACK_CACHE_SIZE (SHAPE_BUFFER_SIZE * 32)
-
-/* This depends on that the allocated memory by Ruby's allocator or
- * mmap is not located at an odd address. */
-#define SINGLE_CHILD_TAG 0x1
-#define TAG_SINGLE_CHILD(x) (struct rb_id_table *)((uintptr_t)(x) | SINGLE_CHILD_TAG)
-#define SINGLE_CHILD_MASK (~((uintptr_t)SINGLE_CHILD_TAG))
-#define SINGLE_CHILD_P(x) ((uintptr_t)(x) & SINGLE_CHILD_TAG)
-#define SINGLE_CHILD(x) (rb_shape_t *)((uintptr_t)(x) & SINGLE_CHILD_MASK)
-#define ANCESTOR_CACHE_THRESHOLD 10
-#define MAX_SHAPE_ID (SHAPE_BUFFER_SIZE - 1)
-#define ANCESTOR_SEARCH_MAX_DEPTH 2
-
static ID id_frozen;
static ID id_t_object;
-
-#define LEAF 0
-#define BLACK 0x0
-#define RED 0x1
-
-static redblack_node_t *
-redblack_left(redblack_node_t * node)
-{
- if (node->l == LEAF) {
- return LEAF;
- }
- else {
- RUBY_ASSERT(node->l < GET_SHAPE_TREE()->cache_size);
- redblack_node_t * left = &GET_SHAPE_TREE()->shape_cache[node->l - 1];
- return left;
- }
-}
-
-static redblack_node_t *
-redblack_right(redblack_node_t * node)
-{
- if (node->r == LEAF) {
- return LEAF;
- }
- else {
- RUBY_ASSERT(node->r < GET_SHAPE_TREE()->cache_size);
- redblack_node_t * right = &GET_SHAPE_TREE()->shape_cache[node->r - 1];
- return right;
- }
-}
-
-static redblack_node_t *
-redblack_find(redblack_node_t * tree, ID key)
-{
- if (tree == LEAF) {
- return LEAF;
- }
- else {
- RUBY_ASSERT(redblack_left(tree) == LEAF || redblack_left(tree)->key < tree->key);
- RUBY_ASSERT(redblack_right(tree) == LEAF || redblack_right(tree)->key > tree->key);
-
- if (tree->key == key) {
- return tree;
- }
- else {
- if (key < tree->key) {
- return redblack_find(redblack_left(tree), key);
- }
- else {
- return redblack_find(redblack_right(tree), key);
- }
- }
- }
-}
-
-static inline rb_shape_t *
-redblack_value(redblack_node_t * node)
-{
- // Color is stored in the bottom bit of the shape pointer
- // Mask away the bit so we get the actual pointer back
- return (rb_shape_t *)((uintptr_t)node->value & ~(uintptr_t)1);
-}
-
-#ifdef HAVE_MMAP
-static inline char
-redblack_color(redblack_node_t * node)
-{
- return node && ((uintptr_t)node->value & RED);
-}
-
-static inline bool
-redblack_red_p(redblack_node_t * node)
-{
- return redblack_color(node) == RED;
-}
-
-static redblack_id_t
-redblack_id_for(redblack_node_t * node)
-{
- RUBY_ASSERT(node || node == LEAF);
- if (node == LEAF) {
- return 0;
- }
- else {
- redblack_node_t * redblack_nodes = GET_SHAPE_TREE()->shape_cache;
- redblack_id_t id = (redblack_id_t)(node - redblack_nodes);
- return id + 1;
- }
-}
-
-static redblack_node_t *
-redblack_new(char color, ID key, rb_shape_t * value, redblack_node_t * left, redblack_node_t * right)
-{
- if (GET_SHAPE_TREE()->cache_size + 1 >= REDBLACK_CACHE_SIZE) {
- // We're out of cache, just quit
- return LEAF;
- }
-
- RUBY_ASSERT(left == LEAF || left->key < key);
- RUBY_ASSERT(right == LEAF || right->key > key);
-
- redblack_node_t * redblack_nodes = GET_SHAPE_TREE()->shape_cache;
- redblack_node_t * node = &redblack_nodes[(GET_SHAPE_TREE()->cache_size)++];
- node->key = key;
- node->value = (rb_shape_t *)((uintptr_t)value | color);
- node->l = redblack_id_for(left);
- node->r = redblack_id_for(right);
- return node;
-}
-
-static redblack_node_t *
-redblack_balance(char color, ID key, rb_shape_t * value, redblack_node_t * left, redblack_node_t * right)
-{
- if (color == BLACK) {
- ID new_key, new_left_key, new_right_key;
- rb_shape_t *new_value, *new_left_value, *new_right_value;
- redblack_node_t *new_left_left, *new_left_right, *new_right_left, *new_right_right;
-
- if (redblack_red_p(left) && redblack_red_p(redblack_left(left))) {
- new_right_key = key;
- new_right_value = value;
- new_right_right = right;
-
- new_key = left->key;
- new_value = redblack_value(left);
- new_right_left = redblack_right(left);
-
- new_left_key = redblack_left(left)->key;
- new_left_value = redblack_value(redblack_left(left));
-
- new_left_left = redblack_left(redblack_left(left));
- new_left_right = redblack_right(redblack_left(left));
- }
- else if (redblack_red_p(left) && redblack_red_p(redblack_right(left))) {
- new_right_key = key;
- new_right_value = value;
- new_right_right = right;
-
- new_left_key = left->key;
- new_left_value = redblack_value(left);
- new_left_left = redblack_left(left);
-
- new_key = redblack_right(left)->key;
- new_value = redblack_value(redblack_right(left));
- new_left_right = redblack_left(redblack_right(left));
- new_right_left = redblack_right(redblack_right(left));
- }
- else if (redblack_red_p(right) && redblack_red_p(redblack_left(right))) {
- new_left_key = key;
- new_left_value = value;
- new_left_left = left;
-
- new_right_key = right->key;
- new_right_value = redblack_value(right);
- new_right_right = redblack_right(right);
-
- new_key = redblack_left(right)->key;
- new_value = redblack_value(redblack_left(right));
- new_left_right = redblack_left(redblack_left(right));
- new_right_left = redblack_right(redblack_left(right));
- }
- else if (redblack_red_p(right) && redblack_red_p(redblack_right(right))) {
- new_left_key = key;
- new_left_value = value;
- new_left_left = left;
-
- new_key = right->key;
- new_value = redblack_value(right);
- new_left_right = redblack_left(right);
-
- new_right_key = redblack_right(right)->key;
- new_right_value = redblack_value(redblack_right(right));
- new_right_left = redblack_left(redblack_right(right));
- new_right_right = redblack_right(redblack_right(right));
- }
- else {
- return redblack_new(color, key, value, left, right);
- }
-
- RUBY_ASSERT(new_left_key < new_key);
- RUBY_ASSERT(new_right_key > new_key);
- RUBY_ASSERT(new_left_left == LEAF || new_left_left->key < new_left_key);
- RUBY_ASSERT(new_left_right == LEAF || new_left_right->key > new_left_key);
- RUBY_ASSERT(new_left_right == LEAF || new_left_right->key < new_key);
- RUBY_ASSERT(new_right_left == LEAF || new_right_left->key < new_right_key);
- RUBY_ASSERT(new_right_left == LEAF || new_right_left->key > new_key);
- RUBY_ASSERT(new_right_right == LEAF || new_right_right->key > new_right_key);
-
- return redblack_new(
- RED, new_key, new_value,
- redblack_new(BLACK, new_left_key, new_left_value, new_left_left, new_left_right),
- redblack_new(BLACK, new_right_key, new_right_value, new_right_left, new_right_right));
- }
-
- return redblack_new(color, key, value, left, right);
-}
-
-static redblack_node_t *
-redblack_insert_aux(redblack_node_t * tree, ID key, rb_shape_t * value)
-{
- if (tree == LEAF) {
- return redblack_new(RED, key, value, LEAF, LEAF);
- }
- else {
- redblack_node_t *left, *right;
- if (key < tree->key) {
- left = redblack_insert_aux(redblack_left(tree), key, value);
- RUBY_ASSERT(left != LEAF);
- right = redblack_right(tree);
- RUBY_ASSERT(right == LEAF || right->key > tree->key);
- }
- else if (key > tree->key) {
- left = redblack_left(tree);
- RUBY_ASSERT(left == LEAF || left->key < tree->key);
- right = redblack_insert_aux(redblack_right(tree), key, value);
- RUBY_ASSERT(right != LEAF);
- }
- else {
- return tree;
- }
-
- return redblack_balance(
- redblack_color(tree),
- tree->key,
- redblack_value(tree),
- left,
- right
- );
- }
-}
-
-static redblack_node_t *
-redblack_force_black(redblack_node_t * node)
-{
- node->value = redblack_value(node);
- return node;
-}
-
-static redblack_node_t *
-redblack_insert(redblack_node_t * tree, ID key, rb_shape_t * value)
-{
- redblack_node_t * root = redblack_insert_aux(tree, key, value);
-
- if (redblack_red_p(root)) {
- return redblack_force_black(root);
- }
- else {
- return root;
- }
-}
-#endif
-
-rb_shape_tree_t *rb_shape_tree_ptr = NULL;
+static ID size_pool_edge_names[SIZE_POOL_COUNT];
/*
* Shape getters
@@ -305,32 +24,49 @@ rb_shape_tree_t *rb_shape_tree_ptr = NULL;
rb_shape_t *
rb_shape_get_root_shape(void)
{
- return GET_SHAPE_TREE()->root_shape;
+ return GET_VM()->root_shape;
}
shape_id_t
rb_shape_id(rb_shape_t * shape)
{
- return (shape_id_t)(shape - GET_SHAPE_TREE()->shape_list);
+ return (shape_id_t)(shape - GET_VM()->shape_list);
+}
+
+bool
+rb_shape_root_shape_p(rb_shape_t* shape)
+{
+ return shape == rb_shape_get_root_shape();
}
void
rb_shape_each_shape(each_shape_callback callback, void *data)
{
rb_shape_t *cursor = rb_shape_get_root_shape();
- rb_shape_t *end = rb_shape_get_shape_by_id(GET_SHAPE_TREE()->next_shape_id);
+ rb_shape_t *end = rb_shape_get_shape_by_id(GET_VM()->next_shape_id);
while (cursor < end) {
callback(cursor, data);
cursor += 1;
}
}
-RUBY_FUNC_EXPORTED rb_shape_t *
+rb_shape_t*
rb_shape_get_shape_by_id(shape_id_t shape_id)
{
RUBY_ASSERT(shape_id != INVALID_SHAPE_ID);
- rb_shape_t *shape = &GET_SHAPE_TREE()->shape_list[shape_id];
+ rb_vm_t *vm = GET_VM();
+ rb_shape_t *shape = &vm->shape_list[shape_id];
+ return shape;
+}
+
+rb_shape_t*
+rb_shape_get_shape_by_id_without_assertion(shape_id_t shape_id)
+{
+ RUBY_ASSERT(shape_id != INVALID_SHAPE_ID);
+
+ rb_vm_t *vm = GET_VM();
+ rb_shape_t *shape = &vm->shape_list[shape_id];
return shape;
}
@@ -341,10 +77,17 @@ rb_shape_get_parent(rb_shape_t * shape)
}
#if !SHAPE_IN_BASIC_FLAGS
+shape_id_t
+rb_rclass_shape_id(VALUE obj)
+{
+ RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
+ return RCLASS_EXT(obj)->shape_id;
+}
+
shape_id_t rb_generic_shape_id(VALUE obj);
#endif
-RUBY_FUNC_EXPORTED shape_id_t
+shape_id_t
rb_shape_get_shape_id(VALUE obj)
{
if (RB_SPECIAL_CONST_P(obj)) {
@@ -386,111 +129,8 @@ rb_shape_get_shape(VALUE obj)
return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj));
}
-static rb_shape_t *
-shape_alloc(void)
-{
- shape_id_t shape_id = GET_SHAPE_TREE()->next_shape_id;
- GET_SHAPE_TREE()->next_shape_id++;
-
- if (shape_id == (MAX_SHAPE_ID + 1)) {
- // TODO: Make an OutOfShapesError ??
- rb_bug("Out of shapes");
- }
-
- return &GET_SHAPE_TREE()->shape_list[shape_id];
-}
-
-static rb_shape_t *
-rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id)
-{
- rb_shape_t * shape = shape_alloc();
-
- shape->edge_name = edge_name;
- shape->next_iv_index = 0;
- shape->parent_id = parent_id;
- shape->edges = NULL;
-
- return shape;
-}
-
-static rb_shape_t *
-rb_shape_alloc(ID edge_name, rb_shape_t * parent, enum shape_type type)
-{
- rb_shape_t * shape = rb_shape_alloc_with_parent_id(edge_name, rb_shape_id(parent));
- shape->type = (uint8_t)type;
- shape->heap_index = parent->heap_index;
- shape->capacity = parent->capacity;
- shape->edges = 0;
- return shape;
-}
-
-#ifdef HAVE_MMAP
-static redblack_node_t *
-redblack_cache_ancestors(rb_shape_t * shape)
-{
- if (!(shape->ancestor_index || shape->parent_id == INVALID_SHAPE_ID)) {
- redblack_node_t * parent_index;
-
- parent_index = redblack_cache_ancestors(rb_shape_get_parent(shape));
-
- if (shape->type == SHAPE_IVAR) {
- shape->ancestor_index = redblack_insert(parent_index, shape->edge_name, shape);
-
-#if RUBY_DEBUG
- if (shape->ancestor_index) {
- redblack_node_t *inserted_node = redblack_find(shape->ancestor_index, shape->edge_name);
- RUBY_ASSERT(inserted_node);
- RUBY_ASSERT(redblack_value(inserted_node) == shape);
- }
-#endif
- }
- else {
- shape->ancestor_index = parent_index;
- }
- }
-
- return shape->ancestor_index;
-}
-#else
-static redblack_node_t *
-redblack_cache_ancestors(rb_shape_t * shape)
-{
- return LEAF;
-}
-#endif
-
-static rb_shape_t *
-rb_shape_alloc_new_child(ID id, rb_shape_t * shape, enum shape_type shape_type)
-{
- rb_shape_t * new_shape = rb_shape_alloc(id, shape, shape_type);
-
- switch (shape_type) {
- case SHAPE_IVAR:
- if (UNLIKELY(shape->next_iv_index >= shape->capacity)) {
- RUBY_ASSERT(shape->next_iv_index == shape->capacity);
- new_shape->capacity = (uint32_t)rb_malloc_grow_capa(shape->capacity, sizeof(VALUE));
- }
- RUBY_ASSERT(new_shape->capacity > shape->next_iv_index);
- new_shape->next_iv_index = shape->next_iv_index + 1;
- if (new_shape->next_iv_index > ANCESTOR_CACHE_THRESHOLD) {
- redblack_cache_ancestors(new_shape);
- }
- break;
- case SHAPE_FROZEN:
- new_shape->next_iv_index = shape->next_iv_index;
- break;
- case SHAPE_OBJ_TOO_COMPLEX:
- case SHAPE_ROOT:
- case SHAPE_T_OBJECT:
- rb_bug("Unreachable");
- break;
- }
-
- return new_shape;
-}
-
static rb_shape_t*
-get_next_shape_internal(rb_shape_t * shape, ID id, enum shape_type shape_type, bool * variation_created, bool new_variations_allowed)
+get_next_shape_internal(rb_shape_t * shape, ID id, enum shape_type shape_type, bool * variation_created, bool new_shapes_allowed)
{
rb_shape_t *res = NULL;
@@ -499,71 +139,84 @@ get_next_shape_internal(rb_shape_t * shape, ID id, enum shape_type shape_type, b
*variation_created = false;
- RB_VM_LOCK_ENTER();
- {
- // If the current shape has children
- if (shape->edges) {
- // Check if it only has one child
- if (SINGLE_CHILD_P(shape->edges)) {
- rb_shape_t * child = SINGLE_CHILD(shape->edges);
- // If the one child has a matching edge name, then great,
- // we found what we want.
- if (child->edge_name == id) {
- res = child;
- }
- }
- else {
- // If it has more than one child, do a hash lookup to find it.
- VALUE lookup_result;
- if (rb_id_table_lookup(shape->edges, id, &lookup_result)) {
- res = (rb_shape_t *)lookup_result;
- }
+ if (new_shapes_allowed) {
+ RB_VM_LOCK_ENTER();
+ {
+ bool had_edges = !!shape->edges;
+
+ if (!shape->edges) {
+ shape->edges = rb_id_table_create(0);
}
- }
- // If we didn't find the shape we're looking for we create it.
- if (!res) {
- // If we're not allowed to create a new variation, of if we're out of shapes
- // we return TOO_COMPLEX_SHAPE.
- if (!new_variations_allowed || GET_SHAPE_TREE()->next_shape_id > MAX_SHAPE_ID) {
- res = rb_shape_get_shape_by_id(OBJ_TOO_COMPLEX_SHAPE_ID);
+ // Lookup the shape in edges - if there's already an edge and a corresponding shape for it,
+ // we can return that. Otherwise, we'll need to get a new shape
+ VALUE lookup_result;
+ if (rb_id_table_lookup(shape->edges, id, &lookup_result)) {
+ res = (rb_shape_t *)lookup_result;
}
else {
- rb_shape_t * new_shape = rb_shape_alloc_new_child(id, shape, shape_type);
-
- if (!shape->edges) {
- // If the shape had no edge yet, we can directly set the new child
- shape->edges = TAG_SINGLE_CHILD(new_shape);
- }
- else {
- // If the edge was single child we need to allocate a table.
- if (SINGLE_CHILD_P(shape->edges)) {
- rb_shape_t * old_child = SINGLE_CHILD(shape->edges);
- shape->edges = rb_id_table_create(2);
- rb_id_table_insert(shape->edges, old_child->edge_name, (VALUE)old_child);
- }
-
- rb_id_table_insert(shape->edges, new_shape->edge_name, (VALUE)new_shape);
- *variation_created = true;
+ *variation_created = had_edges;
+
+ rb_shape_t * new_shape = rb_shape_alloc(id, shape);
+
+ new_shape->type = (uint8_t)shape_type;
+ new_shape->capacity = shape->capacity;
+
+ switch (shape_type) {
+ case SHAPE_IVAR:
+ new_shape->next_iv_index = shape->next_iv_index + 1;
+ break;
+ case SHAPE_CAPACITY_CHANGE:
+ case SHAPE_FROZEN:
+ case SHAPE_T_OBJECT:
+ new_shape->next_iv_index = shape->next_iv_index;
+ break;
+ case SHAPE_OBJ_TOO_COMPLEX:
+ case SHAPE_INITIAL_CAPACITY:
+ case SHAPE_ROOT:
+ rb_bug("Unreachable");
+ break;
}
+ rb_id_table_insert(shape->edges, id, (VALUE)new_shape);
+
res = new_shape;
}
}
+ RB_VM_LOCK_LEAVE();
}
- RB_VM_LOCK_LEAVE();
-
return res;
}
-int
+MJIT_FUNC_EXPORTED int
rb_shape_frozen_shape_p(rb_shape_t* shape)
{
return SHAPE_FROZEN == (enum shape_type)shape->type;
}
+static void
+move_iv(VALUE obj, ID id, attr_index_t from, attr_index_t to)
+{
+ switch(BUILTIN_TYPE(obj)) {
+ case T_CLASS:
+ case T_MODULE:
+ RCLASS_IVPTR(obj)[to] = RCLASS_IVPTR(obj)[from];
+ break;
+ case T_OBJECT:
+ RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
+ ROBJECT_IVPTR(obj)[to] = ROBJECT_IVPTR(obj)[from];
+ break;
+ default: {
+ struct gen_ivtbl *ivtbl;
+ rb_gen_ivtbl_get(obj, id, &ivtbl);
+ ivtbl->ivptr[to] = ivtbl->ivptr[from];
+ break;
+ }
+ }
+}
+
static rb_shape_t *
-remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
+remove_shape_recursive(VALUE obj, ID id, rb_shape_t * shape, VALUE * removed)
{
if (shape->parent_id == INVALID_SHAPE_ID) {
// We've hit the top of the shape tree and couldn't find the
@@ -572,29 +225,41 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
}
else {
if (shape->type == SHAPE_IVAR && shape->edge_name == id) {
- *removed_shape = shape;
-
+ // We've hit the edge we wanted to remove, return it's _parent_
+ // as the new parent while we go back down the stack.
+ attr_index_t index = shape->next_iv_index - 1;
+
+ switch(BUILTIN_TYPE(obj)) {
+ case T_CLASS:
+ case T_MODULE:
+ *removed = RCLASS_IVPTR(obj)[index];
+ break;
+ case T_OBJECT:
+ *removed = ROBJECT_IVPTR(obj)[index];
+ break;
+ default: {
+ struct gen_ivtbl *ivtbl;
+ rb_gen_ivtbl_get(obj, id, &ivtbl);
+ *removed = ivtbl->ivptr[index];
+ break;
+ }
+ }
return rb_shape_get_parent(shape);
}
else {
// This isn't the IV we want to remove, keep walking up.
- rb_shape_t *new_parent = remove_shape_recursive(rb_shape_get_parent(shape), id, removed_shape);
+ rb_shape_t * new_parent = remove_shape_recursive(obj, id, rb_shape_get_parent(shape), removed);
// We found a new parent. Create a child of the new parent that
// has the same attributes as this shape.
if (new_parent) {
- if (UNLIKELY(new_parent->type == SHAPE_OBJ_TOO_COMPLEX)) {
- return new_parent;
- }
-
bool dont_care;
- rb_shape_t *new_child = get_next_shape_internal(new_parent, shape->edge_name, shape->type, &dont_care, true);
- if (UNLIKELY(new_child->type == SHAPE_OBJ_TOO_COMPLEX)) {
- return new_child;
+ rb_shape_t * new_child = get_next_shape_internal(new_parent, shape->edge_name, shape->type, &dont_care, true);
+ new_child->capacity = shape->capacity;
+ if (new_child->type == SHAPE_IVAR) {
+ move_iv(obj, id, shape->next_iv_index - 1, new_child->next_iv_index - 1);
}
- RUBY_ASSERT(new_child->capacity <= shape->capacity);
-
return new_child;
}
else {
@@ -606,63 +271,16 @@ remove_shape_recursive(rb_shape_t *shape, ID id, rb_shape_t **removed_shape)
}
}
-bool
-rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape, VALUE *removed)
+void
+rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape, VALUE * removed)
{
- if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
- return false;
- }
-
- rb_shape_t *removed_shape = NULL;
- rb_shape_t *new_shape = remove_shape_recursive(shape, id, &removed_shape);
+ rb_shape_t * new_shape = remove_shape_recursive(obj, id, shape, removed);
if (new_shape) {
- RUBY_ASSERT(removed_shape != NULL);
-
- if (UNLIKELY(new_shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
- return false;
- }
-
- RUBY_ASSERT(new_shape->next_iv_index == shape->next_iv_index - 1);
-
- VALUE *ivptr;
- switch(BUILTIN_TYPE(obj)) {
- case T_CLASS:
- case T_MODULE:
- ivptr = RCLASS_IVPTR(obj);
- break;
- case T_OBJECT:
- ivptr = ROBJECT_IVPTR(obj);
- break;
- default: {
- struct gen_ivtbl *ivtbl;
- rb_gen_ivtbl_get(obj, id, &ivtbl);
- ivptr = ivtbl->as.shape.ivptr;
- break;
- }
- }
-
- *removed = ivptr[removed_shape->next_iv_index - 1];
-
- memmove(&ivptr[removed_shape->next_iv_index - 1], &ivptr[removed_shape->next_iv_index],
- ((new_shape->next_iv_index + 1) - removed_shape->next_iv_index) * sizeof(VALUE));
-
- // Re-embed objects when instances become small enough
- // This is necessary because YJIT assumes that objects with the same shape
- // have the same embeddedness for efficiency (avoid extra checks)
- if (BUILTIN_TYPE(obj) == T_OBJECT &&
- !RB_FL_TEST_RAW(obj, ROBJECT_EMBED) &&
- rb_obj_embedded_size(new_shape->next_iv_index) <= rb_gc_obj_slot_size(obj)) {
- RB_FL_SET_RAW(obj, ROBJECT_EMBED);
- memcpy(ROBJECT_IVPTR(obj), ivptr, new_shape->next_iv_index * sizeof(VALUE));
- xfree(ivptr);
- }
-
rb_shape_set_shape(obj, new_shape);
}
- return true;
}
-rb_shape_t *
+void
rb_shape_transition_shape_frozen(VALUE obj)
{
rb_shape_t* shape = rb_shape_get_shape(obj);
@@ -670,20 +288,21 @@ rb_shape_transition_shape_frozen(VALUE obj)
RUBY_ASSERT(RB_OBJ_FROZEN(obj));
if (rb_shape_frozen_shape_p(shape) || rb_shape_obj_too_complex(obj)) {
- return shape;
+ return;
}
rb_shape_t* next_shape;
if (shape == rb_shape_get_root_shape()) {
- return rb_shape_get_shape_by_id(SPECIAL_CONST_SHAPE_ID);
+ rb_shape_set_shape_id(obj, SPECIAL_CONST_SHAPE_ID);
+ return;
}
bool dont_care;
next_shape = get_next_shape_internal(shape, (ID)id_frozen, SHAPE_FROZEN, &dont_care, true);
RUBY_ASSERT(next_shape);
- return next_shape;
+ rb_shape_set_shape(obj, next_shape);
}
/*
@@ -698,20 +317,10 @@ rb_shape_get_next_iv_shape(rb_shape_t* shape, ID id)
return get_next_shape_internal(shape, id, SHAPE_IVAR, &dont_care, true);
}
-static inline rb_shape_t *
-shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
+rb_shape_t *
+rb_shape_get_next(rb_shape_t* shape, VALUE obj, ID id)
{
RUBY_ASSERT(!is_instance_id(id) || RTEST(rb_sym2str(ID2SYM(id))));
- if (UNLIKELY(shape->type == SHAPE_OBJ_TOO_COMPLEX)) {
- return shape;
- }
-
-#if RUBY_DEBUG
- attr_index_t index;
- if (rb_shape_get_iv_index(shape, id, &index)) {
- rb_bug("rb_shape_get_next: trying to create ivar that already exists at index %u", index);
- }
-#endif
bool allow_new_shape = true;
@@ -721,7 +330,12 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
}
bool variation_created = false;
- rb_shape_t *new_shape = get_next_shape_internal(shape, id, SHAPE_IVAR, &variation_created, allow_new_shape);
+ rb_shape_t * new_shape = get_next_shape_internal(shape, id, SHAPE_IVAR, &variation_created, allow_new_shape);
+
+ if (!new_shape) {
+ RUBY_ASSERT(BUILTIN_TYPE(obj) == T_OBJECT);
+ new_shape = rb_shape_get_shape_by_id(OBJ_TOO_COMPLEX_SHAPE_ID);
+ }
// Check if we should update max_iv_count on the object's class
if (BUILTIN_TYPE(obj) == T_OBJECT) {
@@ -732,17 +346,6 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
if (variation_created) {
RCLASS_EXT(klass)->variation_count++;
- if (emit_warnings && rb_warning_category_enabled_p(RB_WARN_CATEGORY_PERFORMANCE)) {
- if (RCLASS_EXT(klass)->variation_count >= SHAPE_MAX_VARIATIONS) {
- rb_category_warn(
- RB_WARN_CATEGORY_PERFORMANCE,
- "The class %"PRIsVALUE" reached %d shape variations, instance variables accesses will be slower and memory usage increased.\n"
- "It is recommended to define instance variables in a consistent order, for instance by eagerly defining them all in the #initialize method.",
- rb_class_path(klass),
- SHAPE_MAX_VARIATIONS
- );
- }
- }
}
}
@@ -750,76 +353,22 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
}
rb_shape_t *
-rb_shape_get_next(rb_shape_t *shape, VALUE obj, ID id)
-{
- return shape_get_next(shape, obj, id, true);
-}
-
-rb_shape_t *
-rb_shape_get_next_no_warnings(rb_shape_t *shape, VALUE obj, ID id)
+rb_shape_transition_shape_capa(rb_shape_t* shape, uint32_t new_capacity)
{
- return shape_get_next(shape, obj, id, false);
+ ID edge_name = rb_make_temporary_id(new_capacity);
+ bool dont_care;
+ rb_shape_t * new_shape = get_next_shape_internal(shape, edge_name, SHAPE_CAPACITY_CHANGE, &dont_care, true);
+ new_shape->capacity = new_capacity;
+ return new_shape;
}
-// Same as rb_shape_get_iv_index, but uses a provided valid shape id and index
-// to return a result faster if branches of the shape tree are closely related.
bool
-rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t *value, shape_id_t *shape_id_hint)
+rb_shape_get_iv_index(rb_shape_t * shape, ID id, attr_index_t *value)
{
- attr_index_t index_hint = *value;
- rb_shape_t *shape = rb_shape_get_shape_by_id(shape_id);
- rb_shape_t *initial_shape = shape;
-
- if (*shape_id_hint == INVALID_SHAPE_ID) {
- *shape_id_hint = shape_id;
- return rb_shape_get_iv_index(shape, id, value);
- }
-
- rb_shape_t * shape_hint = rb_shape_get_shape_by_id(*shape_id_hint);
-
- // We assume it's likely shape_id_hint and shape_id have a close common
- // ancestor, so we check up to ANCESTOR_SEARCH_MAX_DEPTH ancestors before
- // eventually using the index, as in case of a match it will be faster.
- // However if the shape doesn't have an index, we walk the entire tree.
- int depth = INT_MAX;
- if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
- depth = ANCESTOR_SEARCH_MAX_DEPTH;
- }
-
- while (depth > 0 && shape->next_iv_index > index_hint) {
- while (shape_hint->next_iv_index > shape->next_iv_index) {
- shape_hint = rb_shape_get_parent(shape_hint);
- }
-
- if (shape_hint == shape) {
- // We've found a common ancestor so use the index hint
- *value = index_hint;
- *shape_id_hint = rb_shape_id(shape);
- return true;
- }
- if (shape->edge_name == id) {
- // We found the matching id before a common ancestor
- *value = shape->next_iv_index - 1;
- *shape_id_hint = rb_shape_id(shape);
- return true;
- }
-
- shape = rb_shape_get_parent(shape);
- depth--;
- }
-
- // If the original shape had an index but its ancestor doesn't
- // we switch back to the original one as it will be faster.
- if (!shape->ancestor_index && initial_shape->ancestor_index) {
- shape = initial_shape;
- }
- *shape_id_hint = shape_id;
- return rb_shape_get_iv_index(shape, id, value);
-}
+ // It doesn't make sense to ask for the index of an IV that's stored
+ // on an object that is "too complex" as it uses a hash for storing IVs
+ RUBY_ASSERT(rb_shape_id(shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
-static bool
-shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
-{
while (shape->parent_id != INVALID_SHAPE_ID) {
if (shape->edge_name == id) {
enum shape_type shape_type;
@@ -830,68 +379,64 @@ shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
RUBY_ASSERT(shape->next_iv_index > 0);
*value = shape->next_iv_index - 1;
return true;
+ case SHAPE_CAPACITY_CHANGE:
case SHAPE_ROOT:
+ case SHAPE_INITIAL_CAPACITY:
case SHAPE_T_OBJECT:
return false;
case SHAPE_OBJ_TOO_COMPLEX:
case SHAPE_FROZEN:
- rb_bug("Ivar should not exist on transition");
+ rb_bug("Ivar should not exist on transition\n");
}
}
-
shape = rb_shape_get_parent(shape);
}
-
return false;
}
-static bool
-shape_cache_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
+static rb_shape_t *
+shape_alloc(void)
{
- if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
- redblack_node_t *node = redblack_find(shape->ancestor_index, id);
- if (node) {
- rb_shape_t *shape = redblack_value(node);
- *value = shape->next_iv_index - 1;
+ rb_vm_t *vm = GET_VM();
+ shape_id_t shape_id = vm->next_shape_id;
+ vm->next_shape_id++;
-#if RUBY_DEBUG
- attr_index_t shape_tree_index;
- RUBY_ASSERT(shape_get_iv_index(shape, id, &shape_tree_index));
- RUBY_ASSERT(shape_tree_index == *value);
-#endif
+ if (shape_id == MAX_SHAPE_ID) {
+ // TODO: Make an OutOfShapesError ??
+ rb_bug("Out of shapes\n");
+ }
- return true;
- }
+ return &GET_VM()->shape_list[shape_id];
+}
- /* Verify the cache is correct by checking that this instance variable
- * does not exist in the shape tree either. */
- RUBY_ASSERT(!shape_get_iv_index(shape, id, value));
- }
+rb_shape_t *
+rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id)
+{
+ rb_shape_t * shape = shape_alloc();
- return false;
+ shape->edge_name = edge_name;
+ shape->next_iv_index = 0;
+ shape->parent_id = parent_id;
+
+ return shape;
}
-bool
-rb_shape_get_iv_index(rb_shape_t *shape, ID id, attr_index_t *value)
+rb_shape_t *
+rb_shape_alloc_with_size_pool_index(ID edge_name, rb_shape_t * parent, uint8_t size_pool_index)
{
- // It doesn't make sense to ask for the index of an IV that's stored
- // on an object that is "too complex" as it uses a hash for storing IVs
- RUBY_ASSERT(rb_shape_id(shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
+ rb_shape_t * shape = rb_shape_alloc_with_parent_id(edge_name, rb_shape_id(parent));
+ shape->size_pool_index = size_pool_index;
+ return shape;
+}
- if (!shape_cache_get_iv_index(shape, id, value)) {
- // If it wasn't in the ancestor cache, then don't do a linear search
- if (shape->ancestor_index && shape->next_iv_index >= ANCESTOR_CACHE_THRESHOLD) {
- return false;
- }
- else {
- return shape_get_iv_index(shape, id, value);
- }
- }
- return true;
+rb_shape_t *
+rb_shape_alloc(ID edge_name, rb_shape_t * parent)
+{
+ return rb_shape_alloc_with_size_pool_index(edge_name, parent, parent->size_pool_index);
}
-void
+MJIT_FUNC_EXPORTED void
rb_shape_set_shape(VALUE obj, rb_shape_t* shape)
{
rb_shape_set_shape_id(obj, rb_shape_id(shape));
@@ -924,29 +469,20 @@ rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *dest_shap
}
VALUE lookup_result;
- if (SINGLE_CHILD_P(next_shape->edges)) {
- rb_shape_t * child = SINGLE_CHILD(next_shape->edges);
- if (child->edge_name == dest_shape->edge_name) {
- return child;
- }
- else {
- return NULL;
- }
+ if (rb_id_table_lookup(next_shape->edges, dest_shape->edge_name, &lookup_result)) {
+ next_shape = (rb_shape_t *)lookup_result;
}
else {
- if (rb_id_table_lookup(next_shape->edges, dest_shape->edge_name, &lookup_result)) {
- next_shape = (rb_shape_t *)lookup_result;
- }
- else {
- return NULL;
- }
+ return NULL;
}
break;
case SHAPE_ROOT:
+ case SHAPE_CAPACITY_CHANGE:
+ case SHAPE_INITIAL_CAPACITY:
case SHAPE_T_OBJECT:
break;
case SHAPE_OBJ_TOO_COMPLEX:
- rb_bug("Unreachable");
+ rb_bug("Unreachable\n");
break;
}
@@ -956,18 +492,12 @@ rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *dest_shap
rb_shape_t *
rb_shape_rebuild_shape(rb_shape_t * initial_shape, rb_shape_t * dest_shape)
{
- RUBY_ASSERT(rb_shape_id(initial_shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
- RUBY_ASSERT(rb_shape_id(dest_shape) != OBJ_TOO_COMPLEX_SHAPE_ID);
-
rb_shape_t * midway_shape;
RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
if (dest_shape->type != initial_shape->type) {
midway_shape = rb_shape_rebuild_shape(initial_shape, rb_shape_get_parent(dest_shape));
- if (UNLIKELY(rb_shape_id(midway_shape) == OBJ_TOO_COMPLEX_SHAPE_ID)) {
- return midway_shape;
- }
}
else {
midway_shape = initial_shape;
@@ -975,36 +505,46 @@ rb_shape_rebuild_shape(rb_shape_t * initial_shape, rb_shape_t * dest_shape)
switch ((enum shape_type)dest_shape->type) {
case SHAPE_IVAR:
+ if (midway_shape->capacity <= midway_shape->next_iv_index) {
+ // There isn't enough room to write this IV, so we need to increase the capacity
+ midway_shape = rb_shape_transition_shape_capa(midway_shape, midway_shape->capacity * 2);
+ }
+
midway_shape = rb_shape_get_next_iv_shape(midway_shape, dest_shape->edge_name);
break;
case SHAPE_ROOT:
case SHAPE_FROZEN:
+ case SHAPE_CAPACITY_CHANGE:
+ case SHAPE_INITIAL_CAPACITY:
case SHAPE_T_OBJECT:
break;
case SHAPE_OBJ_TOO_COMPLEX:
- rb_bug("Unreachable");
+ rb_bug("Unreachable\n");
break;
}
return midway_shape;
}
-RUBY_FUNC_EXPORTED bool
+bool
rb_shape_obj_too_complex(VALUE obj)
{
return rb_shape_get_shape_id(obj) == OBJ_TOO_COMPLEX_SHAPE_ID;
}
+void
+rb_shape_set_too_complex(VALUE obj)
+{
+ RUBY_ASSERT(BUILTIN_TYPE(obj) == T_OBJECT);
+ RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
+ rb_shape_set_shape_id(obj, OBJ_TOO_COMPLEX_SHAPE_ID);
+}
+
size_t
rb_shape_edges_count(rb_shape_t *shape)
{
if (shape->edges) {
- if (SINGLE_CHILD_P(shape->edges)) {
- return 1;
- }
- else {
- return rb_id_table_size(shape->edges);
- }
+ return rb_id_table_size(shape->edges);
}
return 0;
}
@@ -1013,7 +553,7 @@ size_t
rb_shape_memsize(rb_shape_t *shape)
{
size_t memsize = sizeof(rb_shape_t);
- if (shape->edges && !SINGLE_CHILD_P(shape->edges)) {
+ if (shape->edges) {
memsize += rb_id_table_memsize(shape->edges);
}
return memsize;
@@ -1059,7 +599,7 @@ rb_shape_t_to_rb_cShape(rb_shape_t *shape)
INT2NUM(shape->parent_id),
rb_shape_edge_name(shape),
INT2NUM(shape->next_iv_index),
- INT2NUM(shape->heap_index),
+ INT2NUM(shape->size_pool_index),
INT2NUM(shape->type),
INT2NUM(shape->capacity));
rb_obj_freeze(obj);
@@ -1084,13 +624,7 @@ rb_shape_edges(VALUE self)
VALUE hash = rb_hash_new();
if (shape->edges) {
- if (SINGLE_CHILD_P(shape->edges)) {
- rb_shape_t * child = SINGLE_CHILD(shape->edges);
- rb_edges_to_hash(child->edge_name, (VALUE)child, &hash);
- }
- else {
- rb_id_table_foreach(shape->edges, rb_edges_to_hash, &hash);
- }
+ rb_id_table_foreach(shape->edges, rb_edges_to_hash, &hash);
}
return hash;
@@ -1145,23 +679,6 @@ rb_shape_root_shape(VALUE self)
return rb_shape_t_to_rb_cShape(rb_shape_get_root_shape());
}
-/* :nodoc: */
-static VALUE
-rb_shape_shapes_available(VALUE self)
-{
- return INT2NUM(MAX_SHAPE_ID - (GET_SHAPE_TREE()->next_shape_id - 1));
-}
-
-/* :nodoc: */
-static VALUE
-rb_shape_exhaust(int argc, VALUE *argv, VALUE self)
-{
- rb_check_arity(argc, 0, 1);
- int offset = argc == 1 ? NUM2INT(argv[0]) : 0;
- GET_SHAPE_TREE()->next_shape_id = MAX_SHAPE_ID - offset + 1;
- return Qnil;
-}
-
VALUE rb_obj_shape(rb_shape_t* shape);
static enum rb_id_table_iterator_result collect_keys_and_values(ID key, VALUE value, void *ref)
@@ -1173,13 +690,8 @@ static enum rb_id_table_iterator_result collect_keys_and_values(ID key, VALUE va
static VALUE edges(struct rb_id_table* edges)
{
VALUE hash = rb_hash_new();
- if (SINGLE_CHILD_P(edges)) {
- rb_shape_t * child = SINGLE_CHILD(edges);
- collect_keys_and_values(child->edge_name, (VALUE)child, &hash);
- }
- else {
+ if (edges)
rb_id_table_foreach(edges, collect_keys_and_values, &hash);
- }
return hash;
}
@@ -1215,88 +727,66 @@ static VALUE
rb_shape_find_by_id(VALUE mod, VALUE id)
{
shape_id_t shape_id = NUM2UINT(id);
- if (shape_id >= GET_SHAPE_TREE()->next_shape_id) {
+ if (shape_id >= GET_VM()->next_shape_id) {
rb_raise(rb_eArgError, "Shape ID %d is out of bounds\n", shape_id);
}
return rb_shape_t_to_rb_cShape(rb_shape_get_shape_by_id(shape_id));
}
#endif
-#ifdef HAVE_MMAP
-#include <sys/mman.h>
-#endif
-
void
Init_default_shapes(void)
{
- rb_shape_tree_ptr = xcalloc(1, sizeof(rb_shape_tree_t));
-
-#ifdef HAVE_MMAP
- rb_shape_tree_ptr->shape_list = (rb_shape_t *)mmap(NULL, rb_size_mul_or_raise(SHAPE_BUFFER_SIZE, sizeof(rb_shape_t), rb_eRuntimeError),
- PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (GET_SHAPE_TREE()->shape_list == MAP_FAILED) {
- GET_SHAPE_TREE()->shape_list = 0;
- }
-#else
- GET_SHAPE_TREE()->shape_list = xcalloc(SHAPE_BUFFER_SIZE, sizeof(rb_shape_t));
-#endif
-
- if (!GET_SHAPE_TREE()->shape_list) {
- rb_memerror();
- }
-
id_frozen = rb_make_internal_id();
id_t_object = rb_make_internal_id();
-#ifdef HAVE_MMAP
- rb_shape_tree_ptr->shape_cache = (redblack_node_t *)mmap(NULL, rb_size_mul_or_raise(REDBLACK_CACHE_SIZE, sizeof(redblack_node_t), rb_eRuntimeError),
- PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- rb_shape_tree_ptr->cache_size = 0;
-
- // If mmap fails, then give up on the redblack tree cache.
- // We set the cache size such that the redblack node allocators think
- // the cache is full.
- if (GET_SHAPE_TREE()->shape_cache == MAP_FAILED) {
- GET_SHAPE_TREE()->shape_cache = 0;
- GET_SHAPE_TREE()->cache_size = REDBLACK_CACHE_SIZE;
+ // Shapes by size pool
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ size_pool_edge_names[i] = rb_make_internal_id();
}
-#endif
// Root shape
- rb_shape_t *root = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
- root->capacity = 0;
+ rb_shape_t * root = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
+ root->capacity = (uint32_t)((rb_size_pool_slot_size(0) - offsetof(struct RObject, as.ary)) / sizeof(VALUE));
root->type = SHAPE_ROOT;
- root->heap_index = 0;
- GET_SHAPE_TREE()->root_shape = root;
- RUBY_ASSERT(rb_shape_id(GET_SHAPE_TREE()->root_shape) == ROOT_SHAPE_ID);
+ root->size_pool_index = 0;
+ GET_VM()->root_shape = root;
+ RUBY_ASSERT(rb_shape_id(GET_VM()->root_shape) == ROOT_SHAPE_ID);
+
+ // Shapes by size pool
+ for (int i = 1; i < SIZE_POOL_COUNT; i++) {
+ uint32_t capa = (uint32_t)((rb_size_pool_slot_size(i) - offsetof(struct RObject, as.ary)) / sizeof(VALUE));
+ rb_shape_t * new_shape = rb_shape_transition_shape_capa(root, capa);
+ new_shape->type = SHAPE_INITIAL_CAPACITY;
+ new_shape->size_pool_index = i;
+ RUBY_ASSERT(rb_shape_id(new_shape) == (shape_id_t)i);
+ }
+
+ // Make shapes for T_OBJECT
+ for (int i = 0; i < SIZE_POOL_COUNT; i++) {
+ rb_shape_t * shape = rb_shape_get_shape_by_id(i);
+ bool dont_care;
+ rb_shape_t * t_object_shape =
+ get_next_shape_internal(shape, id_t_object, SHAPE_T_OBJECT, &dont_care, true);
+ t_object_shape->edges = rb_id_table_create(0);
+ RUBY_ASSERT(rb_shape_id(t_object_shape) == (shape_id_t)(i + SIZE_POOL_COUNT));
+ }
bool dont_care;
// Special const shape
#if RUBY_DEBUG
- rb_shape_t *special_const_shape =
+ rb_shape_t * special_const_shape =
#endif
get_next_shape_internal(root, (ID)id_frozen, SHAPE_FROZEN, &dont_care, true);
RUBY_ASSERT(rb_shape_id(special_const_shape) == SPECIAL_CONST_SHAPE_ID);
- RUBY_ASSERT(SPECIAL_CONST_SHAPE_ID == (GET_SHAPE_TREE()->next_shape_id - 1));
+ RUBY_ASSERT(SPECIAL_CONST_SHAPE_ID == (GET_VM()->next_shape_id - 1));
RUBY_ASSERT(rb_shape_frozen_shape_p(special_const_shape));
- rb_shape_t *too_complex_shape = rb_shape_alloc_with_parent_id(0, ROOT_SHAPE_ID);
- too_complex_shape->type = SHAPE_OBJ_TOO_COMPLEX;
- too_complex_shape->heap_index = 0;
- RUBY_ASSERT(OBJ_TOO_COMPLEX_SHAPE_ID == (GET_SHAPE_TREE()->next_shape_id - 1));
- RUBY_ASSERT(rb_shape_id(too_complex_shape) == OBJ_TOO_COMPLEX_SHAPE_ID);
-
- // Make shapes for T_OBJECT
- size_t *sizes = rb_gc_heap_sizes();
- for (int i = 0; sizes[i] > 0; i++) {
- rb_shape_t *t_object_shape = rb_shape_alloc_with_parent_id(0, INVALID_SHAPE_ID);
- t_object_shape->type = SHAPE_T_OBJECT;
- t_object_shape->heap_index = i;
- t_object_shape->capacity = (uint32_t)((sizes[i] - offsetof(struct RObject, as.ary)) / sizeof(VALUE));
- t_object_shape->edges = rb_id_table_create(0);
- t_object_shape->ancestor_index = LEAF;
- RUBY_ASSERT(rb_shape_id(t_object_shape) == (shape_id_t)(i + FIRST_T_OBJECT_SHAPE_ID));
- }
+ rb_shape_t * hash_fallback_shape = rb_shape_alloc_with_parent_id(0, ROOT_SHAPE_ID);
+ hash_fallback_shape->type = SHAPE_OBJ_TOO_COMPLEX;
+ hash_fallback_shape->size_pool_index = 0;
+ RUBY_ASSERT(OBJ_TOO_COMPLEX_SHAPE_ID == (GET_VM()->next_shape_id - 1));
+ RUBY_ASSERT(rb_shape_id(hash_fallback_shape) == OBJ_TOO_COMPLEX_SHAPE_ID);
}
void
@@ -1308,7 +798,7 @@ Init_shape(void)
"parent_id",
"edge_name",
"next_iv_index",
- "heap_index",
+ "size_pool_index",
"type",
"capacity",
NULL);
@@ -1325,18 +815,11 @@ Init_shape(void)
rb_define_const(rb_cShape, "SHAPE_FLAG_SHIFT", INT2NUM(SHAPE_FLAG_SHIFT));
rb_define_const(rb_cShape, "SPECIAL_CONST_SHAPE_ID", INT2NUM(SPECIAL_CONST_SHAPE_ID));
rb_define_const(rb_cShape, "OBJ_TOO_COMPLEX_SHAPE_ID", INT2NUM(OBJ_TOO_COMPLEX_SHAPE_ID));
- rb_define_const(rb_cShape, "FIRST_T_OBJECT_SHAPE_ID", INT2NUM(FIRST_T_OBJECT_SHAPE_ID));
rb_define_const(rb_cShape, "SHAPE_MAX_VARIATIONS", INT2NUM(SHAPE_MAX_VARIATIONS));
- rb_define_const(rb_cShape, "SIZEOF_RB_SHAPE_T", INT2NUM(sizeof(rb_shape_t)));
- rb_define_const(rb_cShape, "SIZEOF_REDBLACK_NODE_T", INT2NUM(sizeof(redblack_node_t)));
- rb_define_const(rb_cShape, "SHAPE_BUFFER_SIZE", INT2NUM(sizeof(rb_shape_t) * SHAPE_BUFFER_SIZE));
- rb_define_const(rb_cShape, "REDBLACK_CACHE_SIZE", INT2NUM(sizeof(redblack_node_t) * REDBLACK_CACHE_SIZE));
rb_define_singleton_method(rb_cShape, "transition_tree", shape_transition_tree, 0);
rb_define_singleton_method(rb_cShape, "find_by_id", rb_shape_find_by_id, 1);
rb_define_singleton_method(rb_cShape, "of", rb_shape_debug_shape, 1);
rb_define_singleton_method(rb_cShape, "root_shape", rb_shape_root_shape, 0);
- rb_define_singleton_method(rb_cShape, "shapes_available", rb_shape_shapes_available, 0);
- rb_define_singleton_method(rb_cShape, "exhaust_shapes", rb_shape_exhaust, -1);
#endif
}
diff --git a/shape.h b/shape.h
index 3fdbc34a39..8f3451d492 100644
--- a/shape.h
+++ b/shape.h
@@ -3,43 +3,41 @@
#include "internal/gc.h"
-#if (SIZEOF_UINT64_T <= SIZEOF_VALUE)
-
+#if (SIZEOF_UINT64_T == SIZEOF_VALUE)
#define SIZEOF_SHAPE_T 4
#define SHAPE_IN_BASIC_FLAGS 1
typedef uint32_t attr_index_t;
-typedef uint32_t shape_id_t;
-# define SHAPE_ID_NUM_BITS 32
-
#else
-
#define SIZEOF_SHAPE_T 2
#define SHAPE_IN_BASIC_FLAGS 0
typedef uint16_t attr_index_t;
-typedef uint16_t shape_id_t;
-# define SHAPE_ID_NUM_BITS 16
-
#endif
-typedef uint32_t redblack_id_t;
-
#define MAX_IVARS (attr_index_t)(-1)
+#if SIZEOF_SHAPE_T == 4
+typedef uint32_t shape_id_t;
+# define SHAPE_ID_NUM_BITS 32
+#else
+typedef uint16_t shape_id_t;
+# define SHAPE_ID_NUM_BITS 16
+#endif
+
# define SHAPE_MASK (((uintptr_t)1 << SHAPE_ID_NUM_BITS) - 1)
# define SHAPE_FLAG_MASK (((VALUE)-1) >> SHAPE_ID_NUM_BITS)
# define SHAPE_FLAG_SHIFT ((SIZEOF_VALUE * 8) - SHAPE_ID_NUM_BITS)
+# define SHAPE_BITMAP_SIZE 16384
+
# define SHAPE_MAX_VARIATIONS 8
+# define MAX_SHAPE_ID (SHAPE_MASK - 1)
# define INVALID_SHAPE_ID SHAPE_MASK
# define ROOT_SHAPE_ID 0x0
-# define SPECIAL_CONST_SHAPE_ID (ROOT_SHAPE_ID + 1)
+# define SPECIAL_CONST_SHAPE_ID (SIZE_POOL_COUNT * 2)
# define OBJ_TOO_COMPLEX_SHAPE_ID (SPECIAL_CONST_SHAPE_ID + 1)
-# define FIRST_T_OBJECT_SHAPE_ID (OBJ_TOO_COMPLEX_SHAPE_ID + 1)
-
-typedef struct redblack_node redblack_node_t;
struct rb_shape {
struct rb_id_table * edges; // id_table from ID (ivar) to next shape
@@ -47,55 +45,32 @@ struct rb_shape {
attr_index_t next_iv_index;
uint32_t capacity; // Total capacity of the object with this shape
uint8_t type;
- uint8_t heap_index;
+ uint8_t size_pool_index;
shape_id_t parent_id;
- redblack_node_t * ancestor_index;
};
typedef struct rb_shape rb_shape_t;
-struct redblack_node {
- ID key;
- rb_shape_t * value;
- redblack_id_t l;
- redblack_id_t r;
-};
-
enum shape_type {
SHAPE_ROOT,
SHAPE_IVAR,
SHAPE_FROZEN,
+ SHAPE_CAPACITY_CHANGE,
+ SHAPE_INITIAL_CAPACITY,
SHAPE_T_OBJECT,
SHAPE_OBJ_TOO_COMPLEX,
};
-typedef struct {
- /* object shapes */
- rb_shape_t *shape_list;
- rb_shape_t *root_shape;
- shape_id_t next_shape_id;
-
- redblack_node_t *shape_cache;
- unsigned int cache_size;
-} rb_shape_tree_t;
-RUBY_EXTERN rb_shape_tree_t *rb_shape_tree_ptr;
-
-static inline rb_shape_tree_t *
-rb_current_shape_tree(void)
-{
- return rb_shape_tree_ptr;
-}
-#define GET_SHAPE_TREE() rb_current_shape_tree()
-
+#if SHAPE_IN_BASIC_FLAGS
static inline shape_id_t
-get_shape_id_from_flags(VALUE obj)
+RBASIC_SHAPE_ID(VALUE obj)
{
RUBY_ASSERT(!RB_SPECIAL_CONST_P(obj));
return (shape_id_t)(SHAPE_MASK & ((RBASIC(obj)->flags) >> SHAPE_FLAG_SHIFT));
}
static inline void
-set_shape_id_in_flags(VALUE obj, shape_id_t shape_id)
+RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
{
// Ractors are occupying the upper 32 bits of flags, but only in debug mode
// Object shapes are occupying top bits
@@ -103,68 +78,77 @@ set_shape_id_in_flags(VALUE obj, shape_id_t shape_id)
RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT);
}
-
-#if SHAPE_IN_BASIC_FLAGS
static inline shape_id_t
-RBASIC_SHAPE_ID(VALUE obj)
+ROBJECT_SHAPE_ID(VALUE obj)
{
- return get_shape_id_from_flags(obj);
+ RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
+ return RBASIC_SHAPE_ID(obj);
}
static inline void
-RBASIC_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
+ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
{
- set_shape_id_in_flags(obj, shape_id);
+ RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
+ RBASIC_SET_SHAPE_ID(obj, shape_id);
+}
+
+static inline shape_id_t
+RCLASS_SHAPE_ID(VALUE obj)
+{
+ RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
+ return RBASIC_SHAPE_ID(obj);
}
-#endif
+
+#else
static inline shape_id_t
ROBJECT_SHAPE_ID(VALUE obj)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- return get_shape_id_from_flags(obj);
+ return (shape_id_t)(SHAPE_MASK & (RBASIC(obj)->flags >> SHAPE_FLAG_SHIFT));
}
static inline void
ROBJECT_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
{
- RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- set_shape_id_in_flags(obj, shape_id);
+ RBASIC(obj)->flags &= SHAPE_FLAG_MASK;
+ RBASIC(obj)->flags |= ((VALUE)(shape_id) << SHAPE_FLAG_SHIFT);
}
-static inline shape_id_t
-RCLASS_SHAPE_ID(VALUE obj)
-{
- RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
- return get_shape_id_from_flags(obj);
-}
+MJIT_SYMBOL_EXPORT_BEGIN
+shape_id_t rb_rclass_shape_id(VALUE obj);
+MJIT_SYMBOL_EXPORT_END
-static inline void
-RCLASS_SET_SHAPE_ID(VALUE obj, shape_id_t shape_id)
+static inline shape_id_t RCLASS_SHAPE_ID(VALUE obj)
{
- RUBY_ASSERT(RB_TYPE_P(obj, T_CLASS) || RB_TYPE_P(obj, T_MODULE));
- set_shape_id_in_flags(obj, shape_id);
+ return rb_rclass_shape_id(obj);
}
+#endif
+
+bool rb_shape_root_shape_p(rb_shape_t* shape);
rb_shape_t * rb_shape_get_root_shape(void);
+uint8_t rb_shape_id_num_bits(void);
int32_t rb_shape_id_offset(void);
+rb_shape_t* rb_shape_get_shape_by_id_without_assertion(shape_id_t shape_id);
rb_shape_t * rb_shape_get_parent(rb_shape_t * shape);
-RUBY_FUNC_EXPORTED rb_shape_t *rb_shape_get_shape_by_id(shape_id_t shape_id);
-RUBY_FUNC_EXPORTED shape_id_t rb_shape_get_shape_id(VALUE obj);
+MJIT_SYMBOL_EXPORT_BEGIN
+rb_shape_t* rb_shape_get_shape_by_id(shape_id_t shape_id);
+shape_id_t rb_shape_get_shape_id(VALUE obj);
rb_shape_t * rb_shape_get_next_iv_shape(rb_shape_t * shape, ID id);
bool rb_shape_get_iv_index(rb_shape_t * shape, ID id, attr_index_t * value);
-bool rb_shape_get_iv_index_with_hint(shape_id_t shape_id, ID id, attr_index_t * value, shape_id_t *shape_id_hint);
-RUBY_FUNC_EXPORTED bool rb_shape_obj_too_complex(VALUE obj);
+bool rb_shape_obj_too_complex(VALUE obj);
+MJIT_SYMBOL_EXPORT_END
void rb_shape_set_shape(VALUE obj, rb_shape_t* shape);
rb_shape_t* rb_shape_get_shape(VALUE obj);
int rb_shape_frozen_shape_p(rb_shape_t* shape);
-rb_shape_t* rb_shape_transition_shape_frozen(VALUE obj);
-bool rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape, VALUE * removed);
+void rb_shape_transition_shape_frozen(VALUE obj);
+void rb_shape_transition_shape_remove_ivar(VALUE obj, ID id, rb_shape_t *shape, VALUE * removed);
+rb_shape_t * rb_shape_transition_shape_capa(rb_shape_t * shape, uint32_t new_capacity);
rb_shape_t* rb_shape_get_next(rb_shape_t* shape, VALUE obj, ID id);
-rb_shape_t* rb_shape_get_next_no_warnings(rb_shape_t* shape, VALUE obj, ID id);
rb_shape_t * rb_shape_rebuild_shape(rb_shape_t * initial_shape, rb_shape_t * dest_shape);
@@ -174,7 +158,7 @@ ROBJECT_IV_CAPACITY(VALUE obj)
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
// Asking for capacity doesn't make sense when the object is using
// a hash table for storing instance variables
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
+ RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) != OBJ_TOO_COMPLEX_SHAPE_ID);
return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->capacity;
}
@@ -182,15 +166,15 @@ static inline st_table *
ROBJECT_IV_HASH(VALUE obj)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
+ RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) == OBJ_TOO_COMPLEX_SHAPE_ID);
return (st_table *)ROBJECT(obj)->as.heap.ivptr;
}
static inline void
-ROBJECT_SET_IV_HASH(VALUE obj, const st_table *tbl)
+ROBJECT_SET_IV_HASH(VALUE obj, const struct rb_id_table *tbl)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- RUBY_ASSERT(rb_shape_obj_too_complex(obj));
+ RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) == OBJ_TOO_COMPLEX_SHAPE_ID);
ROBJECT(obj)->as.heap.ivptr = (VALUE *)tbl;
}
@@ -199,12 +183,12 @@ size_t rb_id_table_size(const struct rb_id_table *tbl);
static inline uint32_t
ROBJECT_IV_COUNT(VALUE obj)
{
- if (rb_shape_obj_too_complex(obj)) {
+ if (ROBJECT_SHAPE_ID(obj) == OBJ_TOO_COMPLEX_SHAPE_ID) {
return (uint32_t)rb_st_table_size(ROBJECT_IV_HASH(obj));
}
else {
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
- RUBY_ASSERT(!rb_shape_obj_too_complex(obj));
+ RUBY_ASSERT(ROBJECT_SHAPE_ID(obj) != OBJ_TOO_COMPLEX_SHAPE_ID);
return rb_shape_get_shape_by_id(ROBJECT_SHAPE_ID(obj))->next_iv_index;
}
}
@@ -215,11 +199,25 @@ RBASIC_IV_COUNT(VALUE obj)
return rb_shape_get_shape_by_id(rb_shape_get_shape_id(obj))->next_iv_index;
}
+static inline uint32_t
+RCLASS_IV_COUNT(VALUE obj)
+{
+ RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
+ uint32_t ivc = rb_shape_get_shape_by_id(RCLASS_SHAPE_ID(obj))->next_iv_index;
+ return ivc;
+}
+
+rb_shape_t * rb_shape_alloc(ID edge_name, rb_shape_t * parent);
+rb_shape_t * rb_shape_alloc_with_size_pool_index(ID edge_name, rb_shape_t * parent, uint8_t size_pool_index);
+rb_shape_t * rb_shape_alloc_with_parent_id(ID edge_name, shape_id_t parent_id);
+
rb_shape_t *rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *orig_shape);
bool rb_shape_set_shape_id(VALUE obj, shape_id_t shape_id);
VALUE rb_obj_debug_shape(VALUE self, VALUE obj);
+VALUE rb_shape_flags_mask(void);
+void rb_shape_set_too_complex(VALUE obj);
// For ext/objspace
RUBY_SYMBOL_EXPORT_BEGIN
diff --git a/signal.c b/signal.c
index 2f7796c127..1072cb47f1 100644
--- a/signal.c
+++ b/signal.c
@@ -36,7 +36,6 @@
#include "debug_counter.h"
#include "eval_intern.h"
#include "internal.h"
-#include "internal/error.h"
#include "internal/eval.h"
#include "internal/sanitizers.h"
#include "internal/signal.h"
@@ -45,6 +44,7 @@
#include "ruby_atomic.h"
#include "vm_core.h"
#include "ractor_core.h"
+#include "ruby/internal/attr/nonstring.h"
#ifdef NEED_RUBY_ATOMIC_OPS
rb_atomic_t
@@ -133,7 +133,7 @@ static const struct signals {
#ifdef SIGCONT
{"CONT", SIGCONT},
#endif
-#ifdef RUBY_SIGCHLD
+#if RUBY_SIGCHLD
{"CHLD", RUBY_SIGCHLD },
{"CLD", RUBY_SIGCHLD },
#endif
@@ -274,7 +274,7 @@ signm2signo(VALUE *sig_ptr, int negative, int exit, int *prefix_ptr)
vsig = rb_str_subseq(vsig, prefix, len);
prefix = signame_prefix_len;
}
- rb_raise(rb_eArgError, "unsupported signal '%.*s%"PRIsVALUE"'",
+ rb_raise(rb_eArgError, "unsupported signal `%.*s%"PRIsVALUE"'",
prefix, signame_prefix, vsig);
UNREACHABLE_RETURN(0);
}
@@ -403,9 +403,6 @@ interrupt_init(int argc, VALUE *argv, VALUE self)
}
void rb_malloc_info_show_results(void); /* gc.c */
-#if defined(USE_SIGALTSTACK) || defined(_WIN32)
-static void reset_sigmask(int sig);
-#endif
void
ruby_default_signal(int sig)
@@ -416,9 +413,6 @@ ruby_default_signal(int sig)
rb_malloc_info_show_results();
signal(sig, SIG_DFL);
-#if defined(USE_SIGALTSTACK) || defined(_WIN32)
- reset_sigmask(sig);
-#endif
raise(sig);
}
@@ -515,6 +509,9 @@ static struct {
rb_atomic_t cnt[RUBY_NSIG];
rb_atomic_t size;
} signal_buff;
+#if RUBY_SIGCHLD
+volatile unsigned int ruby_nocldwait;
+#endif
#define sighandler_t ruby_sighandler_t
@@ -597,7 +594,7 @@ ruby_signal(int signum, sighandler_t handler)
#endif
sigemptyset(&sigact.sa_mask);
-#if defined(USE_SIGALTSTACK) && !defined(__wasm__)
+#ifdef USE_SIGALTSTACK
if (handler == SIG_IGN || handler == SIG_DFL) {
sigact.sa_handler = handler;
sigact.sa_flags = 0;
@@ -612,6 +609,27 @@ ruby_signal(int signum, sighandler_t handler)
#endif
switch (signum) {
+#if RUBY_SIGCHLD
+ case RUBY_SIGCHLD:
+ if (handler == SIG_IGN) {
+ ruby_nocldwait = 1;
+# ifdef USE_SIGALTSTACK
+ if (sigact.sa_flags & SA_SIGINFO) {
+ sigact.sa_sigaction = (ruby_sigaction_t*)sighandler;
+ }
+ else {
+ sigact.sa_handler = sighandler;
+ }
+# else
+ sigact.sa_handler = handler;
+ sigact.sa_flags = 0;
+# endif
+ }
+ else {
+ ruby_nocldwait = 0;
+ }
+ break;
+#endif
#if defined(SA_ONSTACK) && defined(USE_SIGALTSTACK)
case SIGSEGV:
#ifdef SIGBUS
@@ -634,7 +652,7 @@ ruby_signal(int signum, sighandler_t handler)
}
sighandler_t
-ruby_posix_signal(int signum, sighandler_t handler)
+posix_signal(int signum, sighandler_t handler)
{
return ruby_signal(signum, handler);
}
@@ -690,14 +708,35 @@ signal_enque(int sig)
ATOMIC_INC(signal_buff.size);
}
+#if RUBY_SIGCHLD
+static rb_atomic_t sigchld_hit;
+/* destructive getter than simple predicate */
+# define GET_SIGCHLD_HIT() ATOMIC_EXCHANGE(sigchld_hit, 0)
+#else
+# define GET_SIGCHLD_HIT() 0
+#endif
+
static void
sighandler(int sig)
{
int old_errnum = errno;
- signal_enque(sig);
- rb_thread_wakeup_timer_thread(sig);
+ /* the VM always needs to handle SIGCHLD for rb_waitpid */
+ if (sig == RUBY_SIGCHLD) {
+#if RUBY_SIGCHLD
+ rb_vm_t *vm = GET_VM();
+ ATOMIC_EXCHANGE(sigchld_hit, 1);
+ /* avoid spurious wakeup in main thread if and only if nobody uses trap(:CHLD) */
+ if (vm && ACCESS_ONCE(VALUE, vm->trap_list.cmd[sig])) {
+ signal_enque(sig);
+ }
+#endif
+ }
+ else {
+ signal_enque(sig);
+ }
+ rb_thread_wakeup_timer_thread(sig);
#if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL)
ruby_signal(sig, sighandler);
#endif
@@ -803,8 +842,7 @@ check_stack_overflow(int sig, const uintptr_t addr, const ucontext_t *ctx)
const greg_t bp = mctx->gregs[REG_EBP];
# endif
# elif defined __APPLE__
-# include <AvailabilityMacros.h>
-# if defined(MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+# if __DARWIN_UNIX03
# define MCTX_SS_REG(reg) __ss.__##reg
# else
# define MCTX_SS_REG(reg) ss.reg
@@ -868,19 +906,16 @@ check_stack_overflow(int sig, const void *addr)
}
}
# endif
-
# ifdef _WIN32
# define CHECK_STACK_OVERFLOW() check_stack_overflow(sig, 0)
# else
# define FAULT_ADDRESS info->si_addr
# ifdef USE_UCONTEXT_REG
-# define CHECK_STACK_OVERFLOW_() check_stack_overflow(sig, (uintptr_t)FAULT_ADDRESS, ctx)
+# define CHECK_STACK_OVERFLOW() check_stack_overflow(sig, (uintptr_t)FAULT_ADDRESS, ctx)
# else
-# define CHECK_STACK_OVERFLOW_() check_stack_overflow(sig, FAULT_ADDRESS)
+# define CHECK_STACK_OVERFLOW() check_stack_overflow(sig, FAULT_ADDRESS)
# endif
# define MESSAGE_FAULT_ADDRESS " at %p", FAULT_ADDRESS
-# define SIGNAL_FROM_USER_P() ((info)->si_code == SI_USER)
-# define CHECK_STACK_OVERFLOW() (SIGNAL_FROM_USER_P() ? (void)0 : CHECK_STACK_OVERFLOW_())
# endif
#else
# define CHECK_STACK_OVERFLOW() (void)0
@@ -890,10 +925,10 @@ check_stack_overflow(int sig, const void *addr)
#endif
#if defined SIGSEGV || defined SIGBUS || defined SIGILL || defined SIGFPE
-NOINLINE(static void check_reserved_signal_(const char *name, size_t name_len, int signo));
+NOINLINE(static void check_reserved_signal_(const char *name, size_t name_len));
/* noinine to reduce stack usage in signal handers */
-#define check_reserved_signal(name) check_reserved_signal_(name, sizeof(name)-1, sig)
+#define check_reserved_signal(name) check_reserved_signal_(name, sizeof(name)-1)
#ifdef SIGBUS
@@ -965,38 +1000,33 @@ ruby_abort(void)
}
static void
-check_reserved_signal_(const char *name, size_t name_len, int signo)
+check_reserved_signal_(const char *name, size_t name_len)
{
const char *prev = ATOMIC_PTR_EXCHANGE(received_signal, name);
if (prev) {
ssize_t RB_UNUSED_VAR(err);
- static const int stderr_fd = 2;
-#define NOZ(name, str) name[sizeof(str)-1] = str
+#define NOZ(name, str) RBIMPL_ATTR_NONSTRING() name[sizeof(str)-1] = str
static const char NOZ(msg1, " received in ");
static const char NOZ(msg2, " handler\n");
#ifdef HAVE_WRITEV
struct iovec iov[4];
- int i = 0;
-# define W(str, len) \
- iov[i++] = (struct iovec){.iov_base = (void *)(str), .iov_len = (len)}
-#else
-# define W(str, len) err = write(stderr_fd, (str), (len))
-#endif
-#if __has_feature(address_sanitizer) || \
- __has_feature(memory_sanitizer) || \
- defined(HAVE_VALGRIND_MEMCHECK_H)
- ruby_posix_signal(signo, SIG_DFL);
-#endif
- W(name, name_len);
- W(msg1, sizeof(msg1));
- W(prev, strlen(prev));
- W(msg2, sizeof(msg2));
-# undef W
-#ifdef HAVE_WRITEV
- err = writev(stderr_fd, iov, i);
+ iov[0].iov_base = (void *)name;
+ iov[0].iov_len = name_len;
+ iov[1].iov_base = (void *)msg1;
+ iov[1].iov_len = sizeof(msg1);
+ iov[2].iov_base = (void *)prev;
+ iov[2].iov_len = strlen(prev);
+ iov[3].iov_base = (void *)msg2;
+ iov[3].iov_len = sizeof(msg2);
+ err = writev(2, iov, 4);
+#else
+ err = write(2, name, name_len);
+ err = write(2, msg1, sizeof(msg1));
+ err = write(2, prev, strlen(prev));
+ err = write(2, msg2, sizeof(msg2));
#endif
ruby_abort();
}
@@ -1056,6 +1086,16 @@ rb_vm_trap_exit(rb_vm_t *vm)
}
}
+void ruby_waitpid_all(rb_vm_t *); /* process.c */
+
+void
+ruby_sigchld_handler(rb_vm_t *vm)
+{
+ if (SIGCHLD_LOSSY || GET_SIGCHLD_HIT()) {
+ ruby_waitpid_all(vm);
+ }
+}
+
/* returns true if a trap handler was run, false otherwise */
int
rb_signal_exec(rb_thread_t *th, int sig)
@@ -1123,7 +1163,7 @@ default_handler(int sig)
#ifdef SIGUSR2
case SIGUSR2:
#endif
-#ifdef RUBY_SIGCHLD
+#if RUBY_SIGCHLD
case RUBY_SIGCHLD:
#endif
func = sighandler;
@@ -1191,6 +1231,9 @@ trap_handler(VALUE *cmd, int sig)
break;
case 14:
if (memcmp(cptr, "SYSTEM_DEFAULT", 14) == 0) {
+ if (sig == RUBY_SIGCHLD) {
+ goto sig_dfl;
+ }
func = SIG_DFL;
*cmd = 0;
}
@@ -1341,7 +1384,7 @@ reserved_signal_p(int signo)
* Signal.trap("CLD") { puts "Child died" }
* fork && Process.wait
*
- * <em>produces:</em>
+ * produces:
* Terminating: 27461
* Child died
* Terminating: 27460
@@ -1408,7 +1451,6 @@ sig_list(VALUE _)
if (reserved_signal_p(signum)) rb_bug(failed); \
perror(failed); \
} while (0)
-
static int
install_sighandler_core(int signum, sighandler_t handler, sighandler_t *old_handler)
{
@@ -1433,6 +1475,25 @@ install_sighandler_core(int signum, sighandler_t handler, sighandler_t *old_hand
# define force_install_sighandler(signum, handler, old_handler) \
INSTALL_SIGHANDLER(install_sighandler_core(signum, handler, old_handler), #signum, signum)
+#if RUBY_SIGCHLD
+static int
+init_sigchld(int sig)
+{
+ sighandler_t oldfunc;
+ sighandler_t func = sighandler;
+
+ oldfunc = ruby_signal(sig, SIG_DFL);
+ if (oldfunc == SIG_ERR) return -1;
+ ruby_signal(sig, func);
+ ACCESS_ONCE(VALUE, GET_VM()->trap_list.cmd[sig]) = 0;
+
+ return 0;
+}
+
+# define init_sigchld(signum) \
+ INSTALL_SIGHANDLER(init_sigchld(signum), #signum, signum)
+#endif
+
void
ruby_sig_finalize(void)
{
@@ -1444,6 +1505,7 @@ ruby_sig_finalize(void)
}
}
+
int ruby_enable_coredump = 0;
/*
@@ -1474,10 +1536,10 @@ int ruby_enable_coredump = 0;
* # ...
* Process.kill("TERM", pid)
*
- * <em>produces:</em>
+ * produces:
* Debug now: true
* Debug now: false
- * Terminating...
+ * Terminating...
*
* The list of available signal names and their interpretation is
* system dependent. Signal delivery semantics may also vary between
@@ -1498,9 +1560,6 @@ Init_signal(void)
rb_alias(rb_eSignal, rb_intern_const("signm"), rb_intern_const("message"));
rb_define_method(rb_eInterrupt, "initialize", interrupt_init, -1);
- // It should be ready to call rb_signal_exec()
- VM_ASSERT(GET_THREAD()->pending_interrupt_queue);
-
/* At this time, there is no subthread. Then sigmask guarantee atomics. */
rb_disable_interrupt();
@@ -1543,9 +1602,55 @@ Init_signal(void)
install_sighandler(SIGSYS, sig_do_nothing);
#endif
-#ifdef RUBY_SIGCHLD
- install_sighandler(RUBY_SIGCHLD, sighandler);
+#if RUBY_SIGCHLD
+ init_sigchld(RUBY_SIGCHLD);
#endif
rb_enable_interrupt();
}
+
+#if defined(HAVE_GRANTPT)
+extern int grantpt(int);
+#else
+static int
+fake_grantfd(int masterfd)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#define grantpt(fd) fake_grantfd(fd)
+#endif
+
+int
+rb_grantpt(int masterfd)
+{
+ if (RUBY_SIGCHLD) {
+ rb_vm_t *vm = GET_VM();
+ int ret, e;
+
+ /*
+ * Prevent waitpid calls from Ruby by taking waitpid_lock.
+ * Pedantically, grantpt(3) is undefined if a non-default
+ * SIGCHLD handler is defined, but preventing conflicting
+ * waitpid calls ought to be sufficient.
+ *
+ * We could install the default sighandler temporarily, but that
+ * could cause SIGCHLD to be missed by other threads. Blocking
+ * SIGCHLD won't work here, either, unless we stop and restart
+ * timer-thread (as only timer-thread sees SIGCHLD), but that
+ * seems like overkill.
+ */
+ rb_nativethread_lock_lock(&vm->waitpid_lock);
+ {
+ ret = grantpt(masterfd); /* may spawn `pt_chown' and wait on it */
+ if (ret < 0) e = errno;
+ }
+ rb_nativethread_lock_unlock(&vm->waitpid_lock);
+
+ if (ret < 0) errno = e;
+ return ret;
+ }
+ else {
+ return grantpt(masterfd);
+ }
+}
diff --git a/siphash.c b/siphash.c
index 61b8604fc9..62de622778 100644
--- a/siphash.c
+++ b/siphash.c
@@ -140,6 +140,9 @@ xor64_to(uint64_t *v, const uint64_t s)
#endif
static const union {
+#if defined(__has_attribute) && __has_attribute(nonstring)
+ __attribute__((nonstring))
+#endif
char bin[32];
uint64_t u64[4];
} sip_init_state_bin = {"uespemos""modnarod""arenegyl""setybdet"};
diff --git a/spec/README.md b/spec/README.md
index 6a88c06e09..4fcf090759 100644
--- a/spec/README.md
+++ b/spec/README.md
@@ -91,24 +91,24 @@ To run all specs:
make test-spec
```
-Extra arguments can be added via `SPECOPTS`.
+Extra arguments can be added via `MSPECOPT`.
For instance, to show the help:
```bash
-make test-spec SPECOPTS=-h
+make test-spec MSPECOPT=-h
```
You can also run the specs in parallel, which is currently experimental.
It takes around 10s instead of 60s on a quad-core laptop.
```bash
-make test-spec SPECOPTS=-j
+make test-spec MSPECOPT=-j
```
To run a specific test, add its path to the command:
```bash
-make test-spec SPECOPTS=spec/ruby/language/for_spec.rb
+make test-spec MSPECOPT=spec/ruby/language/for_spec.rb
```
If ruby trunk is your current `ruby` in `$PATH`, you can also run `mspec` directly:
diff --git a/spec/bundled_gems.mspec b/spec/bundled_gems.mspec
deleted file mode 100644
index 762fa1c165..0000000000
--- a/spec/bundled_gems.mspec
+++ /dev/null
@@ -1,6 +0,0 @@
-load File.dirname(__FILE__) + '/default.mspec'
-
-class MSpecScript
- set :library, get(:stdlibs).to_a & get(:bundled_gems).to_a
- set :files, get(:library)
-end
diff --git a/spec/bundler/bundler/bundler_spec.rb b/spec/bundler/bundler/bundler_spec.rb
index 7cfc12a6f6..54fedc8568 100644
--- a/spec/bundler/bundler/bundler_spec.rb
+++ b/spec/bundler/bundler/bundler_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Bundler do
describe "#load_marshal" do
it "is a private method and raises an error" do
data = Marshal.dump(Bundler)
- expect { Bundler.load_marshal(data) }.to raise_error(NoMethodError, /private method [`']load_marshal' called/)
+ expect { Bundler.load_marshal(data) }.to raise_error(NoMethodError, /private method `load_marshal' called/)
end
it "loads any data" do
@@ -23,7 +23,7 @@ RSpec.describe Bundler do
end
it "loads simple structure" do
- simple_structure = { "name" => [:development] }
+ simple_structure = { "name" => [:abc] }
data = Marshal.dump(simple_structure)
expect(Bundler.safe_load_marshal(data)).to eq(simple_structure)
end
@@ -76,7 +76,7 @@ RSpec.describe Bundler do
context "with incorrect YAML file" do
before do
File.open(app_gemspec_path, "wb") do |f|
- f.write <<~GEMSPEC
+ f.write strip_whitespace(<<-GEMSPEC)
---
{:!00 ao=gu\g1= 7~f
GEMSPEC
@@ -88,7 +88,7 @@ RSpec.describe Bundler do
end
end
- context "with correct YAML file", if: defined?(Encoding) do
+ context "with correct YAML file", :if => defined?(Encoding) do
it "can load a gemspec with unicode characters with default ruby encoding" do
# spec_helper forces the external encoding to UTF-8 but that's not the
# default until Ruby 2.0
@@ -99,7 +99,7 @@ RSpec.describe Bundler do
$VERBOSE = verbose
File.open(app_gemspec_path, "wb") do |file|
- file.puts <<~GEMSPEC
+ file.puts <<-GEMSPEC.gsub(/^\s+/, "")
# -*- encoding: utf-8 -*-
Gem::Specification.new do |gem|
gem.author = "André the Giant"
@@ -139,7 +139,7 @@ RSpec.describe Bundler do
end
GEMSPEC
end
- expect(Bundler.rubygems).to receive(:validate).with have_attributes(name: "validated")
+ expect(Bundler.rubygems).to receive(:validate).with have_attributes(:name => "validated")
subject
end
end
@@ -147,7 +147,7 @@ RSpec.describe Bundler do
context "with gemspec containing local variables" do
before do
File.open(app_gemspec_path, "wb") do |f|
- f.write <<~GEMSPEC
+ f.write strip_whitespace(<<-GEMSPEC)
must_not_leak = true
Gem::Specification.new do |gem|
gem.name = "leak check"
@@ -224,17 +224,35 @@ RSpec.describe Bundler do
end
end
+ describe "#rm_rf" do
+ context "the directory is world writable" do
+ let(:bundler_ui) { Bundler.ui }
+ it "should raise a friendly error" do
+ allow(File).to receive(:exist?).and_return(true)
+ allow(::Bundler::FileUtils).to receive(:remove_entry_secure).and_raise(ArgumentError)
+ allow(File).to receive(:world_writable?).and_return(true)
+ message = <<EOF
+It is a security vulnerability to allow your home directory to be world-writable, and bundler cannot continue.
+You should probably consider fixing this issue by running `chmod o-w ~` on *nix.
+Please refer to https://ruby-doc.org/stdlib-3.1.2/libdoc/fileutils/rdoc/FileUtils.html#method-c-remove_entry_secure for details.
+EOF
+ expect(bundler_ui).to receive(:warn).with(message)
+ expect { Bundler.send(:rm_rf, bundled_app) }.to raise_error(Bundler::PathError)
+ end
+ end
+ end
+
describe "#mkdir_p" do
it "creates a folder at the given path" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
allow(Bundler).to receive(:root).and_return(bundled_app)
- Bundler.mkdir_p(bundled_app("foo", "bar"))
- expect(bundled_app("foo", "bar")).to exist
+ Bundler.mkdir_p(bundled_app.join("foo", "bar"))
+ expect(bundled_app.join("foo", "bar")).to exist
end
end
@@ -267,7 +285,6 @@ RSpec.describe Bundler do
it "should issue a warning and return a temporary user home" do
allow(Bundler.rubygems).to receive(:user_home).and_return(path)
allow(File).to receive(:directory?).with(path).and_return true
- allow(File).to receive(:writable?).and_call_original
allow(File).to receive(:writable?).with(path).and_return false
allow(File).to receive(:directory?).with(dotbundle).and_return false
allow(Bundler).to receive(:tmp).and_return(Pathname.new("/tmp/trulyrandom"))
diff --git a/spec/bundler/bundler/ci_detector_spec.rb b/spec/bundler/bundler/ci_detector_spec.rb
deleted file mode 100644
index 299d8005e8..0000000000
--- a/spec/bundler/bundler/ci_detector_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Bundler::CIDetector do
- # This is properly tested in rubygems, under the name Gem::CIDetector
- # But the test that confirms that our version _stays in sync_ with that version
- # will live here.
-
- it "stays in sync with the rubygems implementation" do
- rubygems_implementation_path = File.join(git_root, "lib", "rubygems", "ci_detector.rb")
- expect(File.exist?(rubygems_implementation_path)).to be_truthy
- rubygems_code = File.read(rubygems_implementation_path)
- denamespaced_rubygems_code = rubygems_code.sub("Gem", "NAMESPACE")
-
- bundler_implementation_path = File.join(source_lib_dir, "bundler", "ci_detector.rb")
- expect(File.exist?(bundler_implementation_path)).to be_truthy
- bundler_code = File.read(bundler_implementation_path)
- denamespaced_bundler_code = bundler_code.sub("Bundler", "NAMESPACE")
-
- expect(denamespaced_bundler_code).to eq(denamespaced_rubygems_code)
- end
-end
diff --git a/spec/bundler/bundler/cli_spec.rb b/spec/bundler/bundler/cli_spec.rb
index b2cc1ccfef..b752cd7e70 100644
--- a/spec/bundler/bundler/cli_spec.rb
+++ b/spec/bundler/bundler/cli_spec.rb
@@ -4,12 +4,12 @@ require "bundler/cli"
RSpec.describe "bundle executable" do
it "returns non-zero exit status when passed unrecognized options" do
- bundle "--invalid_argument", raise_on_error: false
+ bundle "--invalid_argument", :raise_on_error => false
expect(exitstatus).to_not be_zero
end
it "returns non-zero exit status when passed unrecognized task" do
- bundle "unrecognized-task", raise_on_error: false
+ bundle "unrecognized-task", :raise_on_error => false
expect(exitstatus).to_not be_zero
end
@@ -87,7 +87,7 @@ RSpec.describe "bundle executable" do
end
context "with no arguments" do
- it "prints a concise help message", bundler: "3" do
+ it "prints a concise help message", :bundler => "3" do
bundle ""
expect(err).to be_empty
expect(out).to include("Bundler version #{Bundler::VERSION}").
@@ -101,30 +101,30 @@ RSpec.describe "bundle executable" do
context "when ENV['BUNDLE_GEMFILE'] is set to an empty string" do
it "ignores it" do
gemfile bundled_app_gemfile, <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- bundle :install, env: { "BUNDLE_GEMFILE" => "" }
+ bundle :install, :env => { "BUNDLE_GEMFILE" => "" }
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
context "with --verbose" do
it "prints the running command" do
- gemfile "source 'https://gem.repo1'"
- bundle "info bundler", verbose: true
+ gemfile "source \"#{file_uri_for(gem_repo1)}\""
+ bundle "info bundler", :verbose => true
expect(out).to start_with("Running `bundle info bundler --verbose` with bundler #{Bundler::VERSION}")
end
it "doesn't print defaults" do
- install_gemfile "source 'https://gem.repo1'", verbose: true
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"", :verbose => true
expect(out).to start_with("Running `bundle install --verbose` with bundler #{Bundler::VERSION}")
end
it "doesn't print defaults" do
- install_gemfile "source 'https://gem.repo1'", verbose: true
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"", :verbose => true
expect(out).to start_with("Running `bundle install --verbose` with bundler #{Bundler::VERSION}")
end
end
@@ -133,13 +133,13 @@ RSpec.describe "bundle executable" do
let(:run_command) do
bundle "install"
- bundle "outdated #{flags}", raise_on_error: false
+ bundle "outdated #{flags}", :raise_on_error => false
end
before do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", '0.9.1'
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", '0.9.1'
G
end
@@ -149,8 +149,8 @@ RSpec.describe "bundle executable" do
it "prints a message when there are outdated gems" do
run_command
- expect(out).to include("Gem Current Latest Requested Groups")
- expect(out).to include("myrack 0.9.1 1.0.0 = 0.9.1 default")
+ expect(out).to include("Gem Current Latest Requested Groups")
+ expect(out).to include("rack 0.9.1 1.0.0 = 0.9.1 default")
end
end
@@ -160,7 +160,7 @@ RSpec.describe "bundle executable" do
it "prints a message when there are outdated gems" do
run_command
- expect(out).to include("myrack (newest 1.0.0, installed 0.9.1, requested = 0.9.1)")
+ expect(out).to include("rack (newest 1.0.0, installed 0.9.1, requested = 0.9.1)")
end
end
@@ -170,7 +170,7 @@ RSpec.describe "bundle executable" do
it "prints a simplified message when there are outdated gems" do
run_command
- expect(out).to include("myrack (newest 1.0.0, installed 0.9.1, requested = 0.9.1)")
+ expect(out).to include("rack (newest 1.0.0, installed 0.9.1, requested = 0.9.1)")
end
end
end
@@ -178,7 +178,7 @@ RSpec.describe "bundle executable" do
describe "printing the outdated warning" do
shared_examples_for "no warning" do
it "prints no warning" do
- bundle "fail", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
+ bundle "fail", :env => { "BUNDLER_VERSION" => bundler_version }, :raise_on_error => false
expect(last_command.stdboth).to eq("Could not find command \"fail\".")
end
end
@@ -213,7 +213,7 @@ RSpec.describe "bundle executable" do
context "when the latest version is greater than the current version" do
let(:latest_version) { "222.0" }
it "prints the version warning" do
- bundle "fail", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
+ bundle "fail", :env => { "BUNDLER_VERSION" => bundler_version }, :raise_on_error => false
expect(err).to start_with(<<-EOS.strip)
The latest bundler is #{latest_version}, but you are currently running #{bundler_version}.
To update to the most recent version, run `bundle update --bundler`
@@ -221,16 +221,16 @@ To update to the most recent version, run `bundle update --bundler`
end
context "and disable_version_check is set" do
- before { bundle "config set disable_version_check true", env: { "BUNDLER_VERSION" => bundler_version } }
+ before { bundle "config set disable_version_check true", :env => { "BUNDLER_VERSION" => bundler_version } }
include_examples "no warning"
end
context "running a parseable command" do
it "prints no warning" do
- bundle "config get --parseable foo", env: { "BUNDLER_VERSION" => bundler_version }
+ bundle "config get --parseable foo", :env => { "BUNDLER_VERSION" => bundler_version }
expect(last_command.stdboth).to eq ""
- bundle "platform --ruby", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
+ bundle "platform --ruby", :env => { "BUNDLER_VERSION" => bundler_version }, :raise_on_error => false
expect(last_command.stdboth).to eq "Could not locate Gemfile"
end
end
@@ -238,7 +238,7 @@ To update to the most recent version, run `bundle update --bundler`
context "and is a pre-release" do
let(:latest_version) { "222.0.0.pre.4" }
it "prints the version warning" do
- bundle "fail", env: { "BUNDLER_VERSION" => bundler_version }, raise_on_error: false
+ bundle "fail", :env => { "BUNDLER_VERSION" => bundler_version }, :raise_on_error => false
expect(err).to start_with(<<-EOS.strip)
The latest bundler is #{latest_version}, but you are currently running #{bundler_version}.
To update to the most recent version, run `bundle update --bundler`
@@ -250,12 +250,12 @@ To update to the most recent version, run `bundle update --bundler`
end
RSpec.describe "bundler executable" do
- it "shows the bundler version just as the `bundle` executable does", bundler: "< 3" do
+ it "shows the bundler version just as the `bundle` executable does", :bundler => "< 3" do
bundler "--version"
expect(out).to eq("Bundler version #{Bundler::VERSION}")
end
- it "shows the bundler version just as the `bundle` executable does", bundler: "3" do
+ it "shows the bundler version just as the `bundle` executable does", :bundler => "3" do
bundler "--version"
expect(out).to eq(Bundler::VERSION)
end
diff --git a/spec/bundler/bundler/compact_index_client/parser_spec.rb b/spec/bundler/bundler/compact_index_client/parser_spec.rb
deleted file mode 100644
index 1f6b9e593b..0000000000
--- a/spec/bundler/bundler/compact_index_client/parser_spec.rb
+++ /dev/null
@@ -1,237 +0,0 @@
-# frozen_string_literal: true
-
-require "bundler/compact_index_client"
-require "bundler/compact_index_client/parser"
-
-TestCompactIndexClient = Struct.new(:names, :versions, :info_data) do
- # Requiring the checksum to match the input data helps ensure
- # that we are parsing the correct checksum from the versions file
- def info(name, checksum)
- info_data.dig(name, checksum)
- end
-
- def set_info_data(name, value)
- info_data[name] = value
- end
-end
-
-RSpec.describe Bundler::CompactIndexClient::Parser do
- subject(:parser) { described_class.new(compact_index) }
-
- let(:compact_index) { TestCompactIndexClient.new(names, versions, info_data) }
- let(:names) { "a\nb\nc\n" }
- let(:versions) { <<~VERSIONS.dup }
- created_at: 2024-05-01T00:00:04Z
- ---
- a 1.0.0,1.0.1,1.1.0 aaa111
- b 2.0.0,2.0.0-java bbb222
- c 3.0.0,3.0.3,3.3.3 ccc333
- c -3.0.3 ccc333yanked
- VERSIONS
- let(:info_data) do
- {
- "a" => { "aaa111" => a_info },
- "b" => { "bbb222" => b_info },
- "c" => { "ccc333yanked" => c_info },
- }
- end
- let(:a_info) { <<~INFO.dup }
- ---
- 1.0.0 |checksum:aaa1,ruby:>= 3.0.0,rubygems:>= 3.2.3
- 1.0.1 |checksum:aaa2,ruby:>= 3.0.0,rubygems:>= 3.2.3
- 1.1.0 |checksum:aaa3,ruby:>= 3.0.0,rubygems:>= 3.2.3
- INFO
- let(:b_info) { <<~INFO }
- 2.0.0 a:~> 1.0&<= 3.0|checksum:bbb1
- 2.0.0-java a:~> 1.0&<= 3.0|checksum:bbb2
- INFO
- let(:c_info) { <<~INFO }
- 3.0.0 a:= 1.0.0,b:~> 2.0|checksum:ccc1,ruby:>= 2.7.0,rubygems:>= 3.0.0
- 3.3.3 a:>= 1.1.0,b:~> 2.0|checksum:ccc3,ruby:>= 3.0.0,rubygems:>= 3.2.3
- INFO
-
- describe "#available?" do
- it "returns true versions are available" do
- expect(parser).to be_available
- end
-
- it "returns true when versions has only one gem" do
- compact_index.versions = +"a 1.0.0 aaa1\n"
- expect(parser).to be_available
- end
-
- it "returns true when versions has a gem and a header" do
- compact_index.versions = +"---\na 1.0.0 aaa1\n"
- expect(parser).to be_available
- end
-
- it "returns true when versions has a gem and a header with header data" do
- compact_index.versions = +"created_at: 2024-05-01T00:00:04Z\n---\na 1.0.0 aaa1\n"
- expect(parser).to be_available
- end
-
- it "returns false when versions has only the header" do
- compact_index.versions = +"---\n"
- expect(parser).not_to be_available
- end
-
- it "returns false when versions has only the header with header data" do
- compact_index.versions = +"created_at: 2024-05-01T00:00:04Z\n---\n"
- expect(parser).not_to be_available
- end
-
- it "returns false when versions index is not available" do
- compact_index.versions = nil
- expect(parser).not_to be_available
- end
-
- it "returns false when versions is empty" do
- compact_index.versions = +""
- expect(parser).not_to be_available
- end
- end
-
- describe "#names" do
- it "returns the names" do
- expect(parser.names).to eq(%w[a b c])
- end
-
- it "returns an empty array when names is empty" do
- compact_index.names = ""
- expect(parser.names).to eq([])
- end
-
- it "returns an empty array when names is not readable" do
- compact_index.names = nil
- expect(parser.names).to eq([])
- end
- end
-
- describe "#versions" do
- it "returns the versions" do
- expect(parser.versions).to eq(
- "a" => [
- ["a", "1.0.0"],
- ["a", "1.0.1"],
- ["a", "1.1.0"],
- ],
- "b" => [
- ["b", "2.0.0"],
- ["b", "2.0.0", "java"],
- ],
- "c" => [
- ["c", "3.0.0"],
- ["c", "3.3.3"],
- ],
- )
- end
-
- it "returns an empty hash when versions is empty" do
- compact_index.versions = ""
- expect(parser.versions).to eq({})
- end
-
- it "returns an empty hash when versions is not readable" do
- compact_index.versions = nil
- expect(parser.versions).to eq({})
- end
- end
-
- describe "#info" do
- let(:a_result) do
- [
- [
- "a",
- "1.0.0",
- nil,
- [],
- [["checksum", ["aaa1"]], ["ruby", [">= 3.0.0"]], ["rubygems", [">= 3.2.3"]]],
- ],
- [
- "a",
- "1.0.1",
- nil,
- [],
- [["checksum", ["aaa2"]], ["ruby", [">= 3.0.0"]], ["rubygems", [">= 3.2.3"]]],
- ],
- [
- "a",
- "1.1.0",
- nil,
- [],
- [["checksum", ["aaa3"]], ["ruby", [">= 3.0.0"]], ["rubygems", [">= 3.2.3"]]],
- ],
- ]
- end
- let(:b_result) do
- [
- [
- "b",
- "2.0.0",
- nil,
- [["a", ["~> 1.0", "<= 3.0"]]],
- [["checksum", ["bbb1"]]],
- ],
- [
- "b",
- "2.0.0",
- "java",
- [["a", ["~> 1.0", "<= 3.0"]]],
- [["checksum", ["bbb2"]]],
- ],
- ]
- end
- let(:c_result) do
- [
- [
- "c",
- "3.0.0",
- nil,
- [["a", ["= 1.0.0"]], ["b", ["~> 2.0"]]],
- [["checksum", ["ccc1"]], ["ruby", [">= 2.7.0"]], ["rubygems", [">= 3.0.0"]]],
- ],
- [
- "c",
- "3.3.3",
- nil,
- [["a", [">= 1.1.0"]], ["b", ["~> 2.0"]]],
- [["checksum", ["ccc3"]], ["ruby", [">= 3.0.0"]], ["rubygems", [">= 3.2.3"]]],
- ],
- ]
- end
-
- it "returns the info for example gem 'a' which has no deps" do
- expect(parser.info("a")).to eq(a_result)
- end
-
- it "returns the info for example gem 'b' which has platform and compound deps" do
- expect(parser.info("b")).to eq(b_result)
- end
-
- it "returns the info for example gem 'c' which has deps and yanked version (requires use of correct info checksum)" do
- expect(parser.info("c")).to eq(c_result)
- end
-
- it "returns an empty array when the info is empty" do
- compact_index.set_info_data("a", {})
- expect(parser.info("a")).to eq([])
- end
-
- it "returns an empty array when the info is not readable" do
- expect(parser.info("d")).to eq([])
- end
-
- it "handles empty lines in the versions file (Artifactory bug that they have yet to fix)" do
- compact_index.versions = +<<~VERSIONS
- created_at: 2024-05-01T00:00:04Z
- ---
- a 1.0.0,1.0.1,1.1.0 aaa111
- b 2.0.0,2.0.0-java bbb222
-
- c 3.0.0,3.0.3,3.3.3 ccc333
- c -3.0.3 ccc333yanked
- VERSIONS
- expect(parser.info("a")).to eq(a_result)
- end
- end
-end
diff --git a/spec/bundler/bundler/compact_index_client/updater_spec.rb b/spec/bundler/bundler/compact_index_client/updater_spec.rb
index 87a73d993f..fe417e3920 100644
--- a/spec/bundler/bundler/compact_index_client/updater_spec.rb
+++ b/spec/bundler/bundler/compact_index_client/updater_spec.rb
@@ -1,208 +1,43 @@
# frozen_string_literal: true
-require "bundler/vendored_net_http"
+require "net/http"
require "bundler/compact_index_client"
require "bundler/compact_index_client/updater"
require "tmpdir"
RSpec.describe Bundler::CompactIndexClient::Updater do
- subject(:updater) { described_class.new(fetcher) }
-
let(:fetcher) { double(:fetcher) }
- let(:local_path) { Pathname.new(Dir.mktmpdir("localpath")).join("versions") }
- let(:etag_path) { Pathname.new(Dir.mktmpdir("localpath-etags")).join("versions.etag") }
+ let(:local_path) { Pathname.new Dir.mktmpdir("localpath") }
let(:remote_path) { double(:remote_path) }
- let(:full_body) { "abc123" }
- let(:response) { double(:response, body: full_body, is_a?: false) }
- let(:digest) { Digest::SHA256.base64digest(full_body) }
-
- context "when the local path does not exist" do
- before do
- allow(response).to receive(:[]).with("Repr-Digest") { nil }
- allow(response).to receive(:[]).with("Digest") { nil }
- allow(response).to receive(:[]).with("ETag") { '"thisisanetag"' }
- end
-
- it "downloads the file without attempting append" do
- expect(fetcher).to receive(:call).once.with(remote_path, {}) { response }
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("thisisanetag")
- end
-
- it "fails immediately on bad checksum" do
- expect(fetcher).to receive(:call).once.with(remote_path, {}) { response }
- allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" }
-
- expect do
- updater.update(remote_path, local_path, etag_path)
- end.to raise_error(Bundler::CompactIndexClient::Updater::MismatchedChecksumError)
- end
- end
-
- context "when the local path exists" do
- let(:local_body) { "abc" }
-
- before do
- local_path.open("w") {|f| f.write(local_body) }
- end
-
- context "with an etag" do
- before do
- etag_path.open("w") {|f| f.write("LocalEtag") }
- end
-
- let(:headers) do
- {
- "If-None-Match" => '"LocalEtag"',
- "Range" => "bytes=2-",
- }
- end
-
- it "does nothing if etags match" do
- expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { false }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { true }
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq("abc")
- expect(etag_path.read).to eq("LocalEtag")
- end
-
- it "appends the file if etags do not match" do
- expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
- allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
- allow(response).to receive(:[]).with("ETag") { '"NewEtag"' }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { false }
- allow(response).to receive(:body) { "c123" }
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("NewEtag")
- end
-
- it "replaces the file if response ignores range" do
- expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
- allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
- allow(response).to receive(:[]).with("ETag") { '"NewEtag"' }
- allow(response).to receive(:body) { full_body }
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("NewEtag")
- end
-
- it "tries the request again if the partial response fails digest check" do
- allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" }
- allow(response).to receive(:body) { "the beginning of the file changed" }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
- expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
-
- full_response = double(:full_response, body: full_body, is_a?: false)
- allow(full_response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
- allow(full_response).to receive(:[]).with("ETag") { '"NewEtag"' }
- expect(fetcher).to receive(:call).once.with(remote_path, { "If-None-Match" => '"LocalEtag"' }).and_return(full_response)
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("NewEtag")
- end
- end
-
- context "without an etag file" do
- let(:headers) do
- { "Range" => "bytes=2-" }
- end
-
- it "appends the file" do
- expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
- allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
- allow(response).to receive(:[]).with("ETag") { '"OpaqueEtag"' }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { false }
- allow(response).to receive(:body) { "c123" }
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("OpaqueEtag")
- end
-
- it "replaces the file on full file response that ignores range request" do
- expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
- allow(response).to receive(:[]).with("Repr-Digest") { nil }
- allow(response).to receive(:[]).with("Digest") { nil }
- allow(response).to receive(:[]).with("ETag") { '"OpaqueEtag"' }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { false }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { false }
- allow(response).to receive(:body) { full_body }
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("OpaqueEtag")
- end
-
- it "tries the request again if the partial response fails digest check" do
- allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" }
- allow(response).to receive(:body) { "the beginning of the file changed" }
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
- expect(fetcher).to receive(:call).once.with(remote_path, headers) do
- # During the failed first request, we simulate another process writing the etag.
- # This ensures the second request doesn't generate the md5 etag again but just uses whatever is written.
- etag_path.open("w") {|f| f.write("LocalEtag") }
- response
- end
-
- full_response = double(:full_response, body: full_body, is_a?: false)
- allow(full_response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
- allow(full_response).to receive(:[]).with("ETag") { '"NewEtag"' }
- expect(fetcher).to receive(:call).once.with(remote_path, { "If-None-Match" => '"LocalEtag"' }).and_return(full_response)
-
- updater.update(remote_path, local_path, etag_path)
-
- expect(local_path.read).to eq(full_body)
- expect(etag_path.read).to eq("NewEtag")
- end
- end
- end
+ let!(:updater) { described_class.new(fetcher) }
context "when the ETag header is missing" do
# Regression test for https://github.com/rubygems/bundler/issues/5463
- let(:response) { double(:response, body: full_body) }
+ let(:response) { double(:response, :body => "abc123") }
it "treats the response as an update" do
- allow(response).to receive(:[]).with("Repr-Digest") { nil }
- allow(response).to receive(:[]).with("Digest") { nil }
- allow(response).to receive(:[]).with("ETag") { nil }
+ expect(response).to receive(:[]).with("ETag") { nil }
expect(fetcher).to receive(:call) { response }
- updater.update(remote_path, local_path, etag_path)
+ updater.update(local_path, remote_path)
end
end
context "when the download is corrupt" do
- let(:response) { double(:response, body: "") }
+ let(:response) { double(:response, :body => "") }
it "raises HTTPError" do
expect(fetcher).to receive(:call).and_raise(Zlib::GzipFile::Error)
expect do
- updater.update(remote_path, local_path, etag_path)
+ updater.update(local_path, remote_path)
end.to raise_error(Bundler::HTTPError)
end
end
context "when receiving non UTF-8 data and default internal encoding set to ASCII" do
- let(:response) { double(:response, body: "\x8B".b) }
+ let(:response) { double(:response, :body => "\x8B".b) }
it "works just fine" do
old_verbose = $VERBOSE
@@ -211,12 +46,10 @@ RSpec.describe Bundler::CompactIndexClient::Updater do
begin
$VERBOSE = false
Encoding.default_internal = "ASCII"
- allow(response).to receive(:[]).with("Repr-Digest") { nil }
- allow(response).to receive(:[]).with("Digest") { nil }
- allow(response).to receive(:[]).with("ETag") { nil }
+ expect(response).to receive(:[]).with("ETag") { nil }
expect(fetcher).to receive(:call) { response }
- updater.update(remote_path, local_path, etag_path)
+ updater.update(local_path, remote_path)
ensure
Encoding.default_internal = previous_internal_encoding
$VERBOSE = old_verbose
diff --git a/spec/bundler/bundler/definition_spec.rb b/spec/bundler/bundler/definition_spec.rb
index 6f8b24e68a..59b958ae42 100644
--- a/spec/bundler/bundler/definition_spec.rb
+++ b/spec/bundler/bundler/definition_spec.rb
@@ -5,60 +5,58 @@ require "bundler/definition"
RSpec.describe Bundler::Definition do
describe "#lock" do
before do
- allow(Bundler::SharedHelpers).to receive(:find_gemfile) { bundled_app_gemfile }
- allow(Bundler).to receive(:ui) { double("UI", info: "", debug: "") }
+ allow(Bundler).to receive(:settings) { Bundler::Settings.new(".") }
+ allow(Bundler::SharedHelpers).to receive(:find_gemfile) { Pathname.new("Gemfile") }
+ allow(Bundler).to receive(:ui) { double("UI", :info => "", :debug => "") }
end
-
- subject { Bundler::Definition.new(bundled_app_lock, [], Bundler::SourceList.new, {}) }
-
context "when it's not possible to write to the file" do
+ subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) }
+
it "raises an PermissionError with explanation" do
allow(File).to receive(:open).and_call_original
- expect(File).to receive(:open).with(bundled_app_lock, "wb").
+ expect(File).to receive(:open).with("Gemfile.lock", "wb").
and_raise(Errno::EACCES)
- expect { subject.lock }.
+ expect { subject.lock("Gemfile.lock") }.
to raise_error(Bundler::PermissionError, /Gemfile\.lock/)
end
end
context "when a temporary resource access issue occurs" do
+ subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) }
+
it "raises a TemporaryResourceError with explanation" do
allow(File).to receive(:open).and_call_original
- expect(File).to receive(:open).with(bundled_app_lock, "wb").
+ expect(File).to receive(:open).with("Gemfile.lock", "wb").
and_raise(Errno::EAGAIN)
- expect { subject.lock }.
+ expect { subject.lock("Gemfile.lock") }.
to raise_error(Bundler::TemporaryResourceError, /temporarily unavailable/)
end
end
context "when Bundler::Definition.no_lock is set to true" do
+ subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) }
before { Bundler::Definition.no_lock = true }
after { Bundler::Definition.no_lock = false }
it "does not create a lock file" do
- subject.lock
- expect(bundled_app_lock).not_to be_file
+ subject.lock("Gemfile.lock")
+ expect(File.file?("Gemfile.lock")).to eq false
end
end
end
describe "detects changes" do
it "for a path gem with changes" do
- build_lib "foo", "1.0", path: lib_path("foo")
+ build_lib "foo", "1.0", :path => lib_path("foo")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "1.0"
- end
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo1, "myrack", "1.0.0"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "1.0"
end
- bundle :install, env: { "DEBUG" => "1" }
+ bundle :install, :env => { "DEBUG" => "1" }
expect(out).to match(/re-resolving dependencies/)
expect(lockfile).to eq <<~G
@@ -66,19 +64,19 @@ RSpec.describe Bundler::Definition do
remote: #{lib_path("foo")}
specs:
foo (1.0)
- myrack (= 1.0)
+ rack (= 1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -91,80 +89,67 @@ RSpec.describe Bundler::Definition do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "ffi"
G
bundle "lock --add-platform java"
- bundle "update ffi", env: { "DEBUG" => "1" }
+ bundle "update ffi", :env => { "DEBUG" => "1" }
expect(out).to match(/because bundler is unlocking gems: \(ffi\)/)
end
it "for a path gem with deps and no changes" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "1.0"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "1.0"
s.add_development_dependency "net-ssh", "1.0"
end
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo1, "myrack", "1.0.0"
- end
-
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
- expected_lockfile = <<~G
+ bundle :check, :env => { "DEBUG" => "1" }
+
+ expect(out).to match(/using resolution from the lockfile/)
+ expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
- myrack (= 1.0)
+ rack (= 1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
-
- expect(lockfile).to eq(expected_lockfile)
-
- bundle :check, env: { "DEBUG" => "1" }
-
- expect(out).to match(/using resolution from the lockfile/)
- expect(lockfile).to eq(expected_lockfile)
end
it "for a locked gem for another platform" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "only_java", platform: :jruby
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo1, "only_java", "1.1", "java"
- end
-
bundle "lock --add-platform java"
- bundle :check, env: { "DEBUG" => "1" }
+ bundle :check, :env => { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
only_java (1.1-java)
@@ -173,28 +158,24 @@ RSpec.describe Bundler::Definition do
DEPENDENCIES
only_java
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "for a rubygems gem" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo1, "foo", "1.0"
- end
-
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
- bundle :check, env: { "DEBUG" => "1" }
+ bundle :check, :env => { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
foo (1.0)
@@ -203,7 +184,7 @@ RSpec.describe Bundler::Definition do
DEPENDENCIES
foo
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -215,13 +196,13 @@ RSpec.describe Bundler::Definition do
context "eager unlock" do
let(:source_list) do
Bundler::SourceList.new.tap do |source_list|
- source_list.add_global_rubygems_remote("https://gem.repo4")
+ source_list.add_global_rubygems_remote(file_uri_for(gem_repo4))
end
end
before do
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'isolated_owner'
gem 'shared_owner_a'
@@ -230,7 +211,7 @@ RSpec.describe Bundler::Definition do
lockfile <<-L
GEM
- remote: https://gem.repo4
+ remote: #{file_uri_for(gem_repo4)}
specs:
isolated_dep (2.0.1)
isolated_owner (1.0.1)
@@ -279,7 +260,7 @@ RSpec.describe Bundler::Definition do
bundled_app_lock,
updated_deps_in_gemfile,
source_list,
- gems: ["shared_owner_a"], conservative: true
+ :gems => ["shared_owner_a"], :conservative => true
)
locked = definition.send(:converge_locked_specs).map(&:name)
expect(locked).to eq %w[isolated_dep isolated_owner shared_dep shared_owner_b]
diff --git a/spec/bundler/bundler/dependency_spec.rb b/spec/bundler/bundler/dependency_spec.rb
index a953372742..6e346c36c1 100644
--- a/spec/bundler/bundler/dependency_spec.rb
+++ b/spec/bundler/bundler/dependency_spec.rb
@@ -40,128 +40,118 @@ RSpec.describe Bundler::Dependency do
# rubocop:disable Naming/VariableNumber
let(:platforms) do
- { ruby: Gem::Platform::RUBY,
- ruby_18: Gem::Platform::RUBY,
- ruby_19: Gem::Platform::RUBY,
- ruby_20: Gem::Platform::RUBY,
- ruby_21: Gem::Platform::RUBY,
- ruby_22: Gem::Platform::RUBY,
- ruby_23: Gem::Platform::RUBY,
- ruby_24: Gem::Platform::RUBY,
- ruby_25: Gem::Platform::RUBY,
- ruby_26: Gem::Platform::RUBY,
- ruby_27: Gem::Platform::RUBY,
- ruby_30: Gem::Platform::RUBY,
- ruby_31: Gem::Platform::RUBY,
- ruby_32: Gem::Platform::RUBY,
- ruby_33: Gem::Platform::RUBY,
- ruby_34: Gem::Platform::RUBY,
- mri: Gem::Platform::RUBY,
- mri_18: Gem::Platform::RUBY,
- mri_19: Gem::Platform::RUBY,
- mri_20: Gem::Platform::RUBY,
- mri_21: Gem::Platform::RUBY,
- mri_22: Gem::Platform::RUBY,
- mri_23: Gem::Platform::RUBY,
- mri_24: Gem::Platform::RUBY,
- mri_25: Gem::Platform::RUBY,
- mri_26: Gem::Platform::RUBY,
- mri_27: Gem::Platform::RUBY,
- mri_30: Gem::Platform::RUBY,
- mri_31: Gem::Platform::RUBY,
- mri_32: Gem::Platform::RUBY,
- mri_33: Gem::Platform::RUBY,
- mri_34: Gem::Platform::RUBY,
- rbx: Gem::Platform::RUBY,
- truffleruby: Gem::Platform::RUBY,
- jruby: Gem::Platform::JAVA,
- jruby_18: Gem::Platform::JAVA,
- jruby_19: Gem::Platform::JAVA,
- windows: Gem::Platform::WINDOWS,
- windows_18: Gem::Platform::WINDOWS,
- windows_19: Gem::Platform::WINDOWS,
- windows_20: Gem::Platform::WINDOWS,
- windows_21: Gem::Platform::WINDOWS,
- windows_22: Gem::Platform::WINDOWS,
- windows_23: Gem::Platform::WINDOWS,
- windows_24: Gem::Platform::WINDOWS,
- windows_25: Gem::Platform::WINDOWS,
- windows_26: Gem::Platform::WINDOWS,
- windows_27: Gem::Platform::WINDOWS,
- windows_30: Gem::Platform::WINDOWS,
- windows_31: Gem::Platform::WINDOWS,
- windows_32: Gem::Platform::WINDOWS,
- windows_33: Gem::Platform::WINDOWS,
- windows_34: Gem::Platform::WINDOWS }
- end
-
- let(:deprecated) do
- { mswin: Gem::Platform::MSWIN,
- mswin_18: Gem::Platform::MSWIN,
- mswin_19: Gem::Platform::MSWIN,
- mswin_20: Gem::Platform::MSWIN,
- mswin_21: Gem::Platform::MSWIN,
- mswin_22: Gem::Platform::MSWIN,
- mswin_23: Gem::Platform::MSWIN,
- mswin_24: Gem::Platform::MSWIN,
- mswin_25: Gem::Platform::MSWIN,
- mswin_26: Gem::Platform::MSWIN,
- mswin_27: Gem::Platform::MSWIN,
- mswin_30: Gem::Platform::MSWIN,
- mswin_31: Gem::Platform::MSWIN,
- mswin_32: Gem::Platform::MSWIN,
- mswin_33: Gem::Platform::MSWIN,
- mswin_34: Gem::Platform::MSWIN,
- mswin64: Gem::Platform::MSWIN64,
- mswin64_19: Gem::Platform::MSWIN64,
- mswin64_20: Gem::Platform::MSWIN64,
- mswin64_21: Gem::Platform::MSWIN64,
- mswin64_22: Gem::Platform::MSWIN64,
- mswin64_23: Gem::Platform::MSWIN64,
- mswin64_24: Gem::Platform::MSWIN64,
- mswin64_25: Gem::Platform::MSWIN64,
- mswin64_26: Gem::Platform::MSWIN64,
- mswin64_27: Gem::Platform::MSWIN64,
- mswin64_30: Gem::Platform::MSWIN64,
- mswin64_31: Gem::Platform::MSWIN64,
- mswin64_32: Gem::Platform::MSWIN64,
- mswin64_33: Gem::Platform::MSWIN64,
- mswin64_34: Gem::Platform::MSWIN64,
- mingw: Gem::Platform::MINGW,
- mingw_18: Gem::Platform::MINGW,
- mingw_19: Gem::Platform::MINGW,
- mingw_20: Gem::Platform::MINGW,
- mingw_21: Gem::Platform::MINGW,
- mingw_22: Gem::Platform::MINGW,
- mingw_23: Gem::Platform::MINGW,
- mingw_24: Gem::Platform::MINGW,
- mingw_25: Gem::Platform::MINGW,
- mingw_26: Gem::Platform::MINGW,
- mingw_27: Gem::Platform::MINGW,
- mingw_30: Gem::Platform::MINGW,
- mingw_31: Gem::Platform::MINGW,
- mingw_32: Gem::Platform::MINGW,
- mingw_33: Gem::Platform::MINGW,
- mingw_34: Gem::Platform::MINGW,
- x64_mingw: Gem::Platform::X64_MINGW,
- x64_mingw_20: Gem::Platform::X64_MINGW,
- x64_mingw_21: Gem::Platform::X64_MINGW,
- x64_mingw_22: Gem::Platform::X64_MINGW,
- x64_mingw_23: Gem::Platform::X64_MINGW,
- x64_mingw_24: Gem::Platform::X64_MINGW,
- x64_mingw_25: Gem::Platform::X64_MINGW,
- x64_mingw_26: Gem::Platform::X64_MINGW,
- x64_mingw_27: Gem::Platform::X64_MINGW,
- x64_mingw_30: Gem::Platform::X64_MINGW,
- x64_mingw_31: Gem::Platform::X64_MINGW,
- x64_mingw_32: Gem::Platform::X64_MINGW,
- x64_mingw_33: Gem::Platform::X64_MINGW,
- x64_mingw_34: Gem::Platform::X64_MINGW }
+ { :ruby => Gem::Platform::RUBY,
+ :ruby_18 => Gem::Platform::RUBY,
+ :ruby_19 => Gem::Platform::RUBY,
+ :ruby_20 => Gem::Platform::RUBY,
+ :ruby_21 => Gem::Platform::RUBY,
+ :ruby_22 => Gem::Platform::RUBY,
+ :ruby_23 => Gem::Platform::RUBY,
+ :ruby_24 => Gem::Platform::RUBY,
+ :ruby_25 => Gem::Platform::RUBY,
+ :ruby_26 => Gem::Platform::RUBY,
+ :ruby_27 => Gem::Platform::RUBY,
+ :ruby_30 => Gem::Platform::RUBY,
+ :ruby_31 => Gem::Platform::RUBY,
+ :ruby_32 => Gem::Platform::RUBY,
+ :ruby_33 => Gem::Platform::RUBY,
+ :mri => Gem::Platform::RUBY,
+ :mri_18 => Gem::Platform::RUBY,
+ :mri_19 => Gem::Platform::RUBY,
+ :mri_20 => Gem::Platform::RUBY,
+ :mri_21 => Gem::Platform::RUBY,
+ :mri_22 => Gem::Platform::RUBY,
+ :mri_23 => Gem::Platform::RUBY,
+ :mri_24 => Gem::Platform::RUBY,
+ :mri_25 => Gem::Platform::RUBY,
+ :mri_26 => Gem::Platform::RUBY,
+ :mri_27 => Gem::Platform::RUBY,
+ :mri_30 => Gem::Platform::RUBY,
+ :mri_31 => Gem::Platform::RUBY,
+ :mri_32 => Gem::Platform::RUBY,
+ :mri_33 => Gem::Platform::RUBY,
+ :rbx => Gem::Platform::RUBY,
+ :truffleruby => Gem::Platform::RUBY,
+ :jruby => Gem::Platform::JAVA,
+ :jruby_18 => Gem::Platform::JAVA,
+ :jruby_19 => Gem::Platform::JAVA,
+ :windows => Gem::Platform::WINDOWS,
+ :windows_18 => Gem::Platform::WINDOWS,
+ :windows_19 => Gem::Platform::WINDOWS,
+ :windows_20 => Gem::Platform::WINDOWS,
+ :windows_21 => Gem::Platform::WINDOWS,
+ :windows_22 => Gem::Platform::WINDOWS,
+ :windows_23 => Gem::Platform::WINDOWS,
+ :windows_24 => Gem::Platform::WINDOWS,
+ :windows_25 => Gem::Platform::WINDOWS,
+ :windows_26 => Gem::Platform::WINDOWS,
+ :windows_27 => Gem::Platform::WINDOWS,
+ :windows_30 => Gem::Platform::WINDOWS,
+ :windows_31 => Gem::Platform::WINDOWS,
+ :windows_32 => Gem::Platform::WINDOWS,
+ :windows_33 => Gem::Platform::WINDOWS,
+ :mswin => Gem::Platform::MSWIN,
+ :mswin_18 => Gem::Platform::MSWIN,
+ :mswin_19 => Gem::Platform::MSWIN,
+ :mswin_20 => Gem::Platform::MSWIN,
+ :mswin_21 => Gem::Platform::MSWIN,
+ :mswin_22 => Gem::Platform::MSWIN,
+ :mswin_23 => Gem::Platform::MSWIN,
+ :mswin_24 => Gem::Platform::MSWIN,
+ :mswin_25 => Gem::Platform::MSWIN,
+ :mswin_26 => Gem::Platform::MSWIN,
+ :mswin_27 => Gem::Platform::MSWIN,
+ :mswin_30 => Gem::Platform::MSWIN,
+ :mswin_31 => Gem::Platform::MSWIN,
+ :mswin_32 => Gem::Platform::MSWIN,
+ :mswin_33 => Gem::Platform::MSWIN,
+ :mswin64 => Gem::Platform::MSWIN64,
+ :mswin64_19 => Gem::Platform::MSWIN64,
+ :mswin64_20 => Gem::Platform::MSWIN64,
+ :mswin64_21 => Gem::Platform::MSWIN64,
+ :mswin64_22 => Gem::Platform::MSWIN64,
+ :mswin64_23 => Gem::Platform::MSWIN64,
+ :mswin64_24 => Gem::Platform::MSWIN64,
+ :mswin64_25 => Gem::Platform::MSWIN64,
+ :mswin64_26 => Gem::Platform::MSWIN64,
+ :mswin64_27 => Gem::Platform::MSWIN64,
+ :mswin64_30 => Gem::Platform::MSWIN64,
+ :mswin64_31 => Gem::Platform::MSWIN64,
+ :mswin64_32 => Gem::Platform::MSWIN64,
+ :mswin64_33 => Gem::Platform::MSWIN64,
+ :mingw => Gem::Platform::MINGW,
+ :mingw_18 => Gem::Platform::MINGW,
+ :mingw_19 => Gem::Platform::MINGW,
+ :mingw_20 => Gem::Platform::MINGW,
+ :mingw_21 => Gem::Platform::MINGW,
+ :mingw_22 => Gem::Platform::MINGW,
+ :mingw_23 => Gem::Platform::MINGW,
+ :mingw_24 => Gem::Platform::MINGW,
+ :mingw_25 => Gem::Platform::MINGW,
+ :mingw_26 => Gem::Platform::MINGW,
+ :mingw_27 => Gem::Platform::MINGW,
+ :mingw_30 => Gem::Platform::MINGW,
+ :mingw_31 => Gem::Platform::MINGW,
+ :mingw_32 => Gem::Platform::MINGW,
+ :mingw_33 => Gem::Platform::MINGW,
+ :x64_mingw => Gem::Platform::X64_MINGW,
+ :x64_mingw_20 => Gem::Platform::X64_MINGW,
+ :x64_mingw_21 => Gem::Platform::X64_MINGW,
+ :x64_mingw_22 => Gem::Platform::X64_MINGW,
+ :x64_mingw_23 => Gem::Platform::X64_MINGW,
+ :x64_mingw_24 => Gem::Platform::X64_MINGW,
+ :x64_mingw_25 => Gem::Platform::X64_MINGW,
+ :x64_mingw_26 => Gem::Platform::X64_MINGW,
+ :x64_mingw_27 => Gem::Platform::X64_MINGW,
+ :x64_mingw_30 => Gem::Platform::X64_MINGW,
+ :x64_mingw_31 => Gem::Platform::X64_MINGW,
+ :x64_mingw_32 => Gem::Platform::X64_MINGW,
+ :x64_mingw_33 => Gem::Platform::X64_MINGW }
end
# rubocop:enable Naming/VariableNumber
it "includes all platforms" do
- expect(subject).to eq(platforms.merge(deprecated))
+ expect(subject).to eq(platforms)
end
end
end
diff --git a/spec/bundler/bundler/digest_spec.rb b/spec/bundler/bundler/digest_spec.rb
index f876827964..841cc0259e 100644
--- a/spec/bundler/bundler/digest_spec.rb
+++ b/spec/bundler/bundler/digest_spec.rb
@@ -1,17 +1,17 @@
# frozen_string_literal: true
-require "openssl"
+require "digest"
require "bundler/digest"
RSpec.describe Bundler::Digest do
context "SHA1" do
subject { Bundler::Digest }
- let(:stdlib) { OpenSSL::Digest::SHA1 }
+ let(:stdlib) { ::Digest::SHA1 }
it "is compatible with stdlib" do
random_strings = ["foo", "skfjsdlkfjsdf", "3924m", "ldskfj"]
- # https://www.rfc-editor.org/rfc/rfc3174#section-7.3
+ # https://datatracker.ietf.org/doc/html/rfc3174#section-7.3
rfc3174_test_cases = ["abc", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "a", "01234567" * 8]
(random_strings + rfc3174_test_cases).each do |payload|
diff --git a/spec/bundler/bundler/dsl_spec.rb b/spec/bundler/bundler/dsl_spec.rb
index 7b6d080593..8b5bf930f2 100644
--- a/spec/bundler/bundler/dsl_spec.rb
+++ b/spec/bundler/bundler/dsl_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Bundler::Dsl do
it "registers custom hosts" do
subject.git_source(:example) {|repo_name| "git@git.example.com:#{repo_name}.git" }
subject.git_source(:foobar) {|repo_name| "git@foobar.com:#{repo_name}.git" }
- subject.gem("dobry-pies", example: "strzalek/dobry-pies")
+ subject.gem("dobry-pies", :example => "strzalek/dobry-pies")
example_uri = "git@git.example.com:strzalek/dobry-pies.git"
expect(subject.dependencies.first.source.uri).to eq(example_uri)
end
@@ -26,136 +26,85 @@ RSpec.describe Bundler::Dsl do
end
it "converts :github PR to URI using https" do
- subject.gem("sparks", github: "https://github.com/indirect/sparks/pull/5")
+ subject.gem("sparks", :github => "https://github.com/indirect/sparks/pull/5")
github_uri = "https://github.com/indirect/sparks.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
expect(subject.dependencies.first.source.ref).to eq("refs/pull/5/head")
end
- it "converts :gitlab PR to URI using https" do
- subject.gem("sparks", gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5")
- gitlab_uri = "https://gitlab.com/indirect/sparks.git"
- expect(subject.dependencies.first.source.uri).to eq(gitlab_uri)
- expect(subject.dependencies.first.source.ref).to eq("refs/merge-requests/5/head")
- end
-
it "rejects :github PR URI with a branch, ref or tag" do
expect do
- subject.gem("sparks", github: "https://github.com/indirect/sparks/pull/5", branch: "foo")
+ subject.gem("sparks", :github => "https://github.com/indirect/sparks/pull/5", :branch => "foo")
end.to raise_error(
Bundler::GemfileError,
%(The :branch option can't be used with `github: "https://github.com/indirect/sparks/pull/5"`),
)
expect do
- subject.gem("sparks", github: "https://github.com/indirect/sparks/pull/5", ref: "foo")
+ subject.gem("sparks", :github => "https://github.com/indirect/sparks/pull/5", :ref => "foo")
end.to raise_error(
Bundler::GemfileError,
%(The :ref option can't be used with `github: "https://github.com/indirect/sparks/pull/5"`),
)
expect do
- subject.gem("sparks", github: "https://github.com/indirect/sparks/pull/5", tag: "foo")
+ subject.gem("sparks", :github => "https://github.com/indirect/sparks/pull/5", :tag => "foo")
end.to raise_error(
Bundler::GemfileError,
%(The :tag option can't be used with `github: "https://github.com/indirect/sparks/pull/5"`),
)
end
- it "rejects :gitlab PR URI with a branch, ref or tag" do
- expect do
- subject.gem("sparks", gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5", branch: "foo")
- end.to raise_error(
- Bundler::GemfileError,
- %(The :branch option can't be used with `gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5"`),
- )
-
- expect do
- subject.gem("sparks", gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5", ref: "foo")
- end.to raise_error(
- Bundler::GemfileError,
- %(The :ref option can't be used with `gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5"`),
- )
-
- expect do
- subject.gem("sparks", gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5", tag: "foo")
- end.to raise_error(
- Bundler::GemfileError,
- %(The :tag option can't be used with `gitlab: "https://gitlab.com/indirect/sparks/-/merge_requests/5"`),
- )
- end
-
it "rejects :github with :git" do
expect do
- subject.gem("sparks", github: "indirect/sparks", git: "https://github.com/indirect/sparks.git")
+ subject.gem("sparks", :github => "indirect/sparks", :git => "https://github.com/indirect/sparks.git")
end.to raise_error(
Bundler::GemfileError,
%(The :git option can't be used with `github: "indirect/sparks"`),
)
end
- it "rejects :gitlab with :git" do
- expect do
- subject.gem("sparks", gitlab: "indirect/sparks", git: "https://gitlab.com/indirect/sparks.git")
- end.to raise_error(
- Bundler::GemfileError,
- %(The :git option can't be used with `gitlab: "indirect/sparks"`),
- )
- end
-
- context "default hosts", bundler: "< 3" do
+ context "default hosts", :bundler => "< 3" do
it "converts :github to URI using https" do
- subject.gem("sparks", github: "indirect/sparks")
+ subject.gem("sparks", :github => "indirect/sparks")
github_uri = "https://github.com/indirect/sparks.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
end
it "converts :github shortcut to URI using https" do
- subject.gem("sparks", github: "rails")
+ subject.gem("sparks", :github => "rails")
github_uri = "https://github.com/rails/rails.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
end
- it "converts :gitlab to URI using https" do
- subject.gem("sparks", gitlab: "indirect/sparks")
- gitlab_uri = "https://gitlab.com/indirect/sparks.git"
- expect(subject.dependencies.first.source.uri).to eq(gitlab_uri)
- end
-
- it "converts :gitlab shortcut to URI using https" do
- subject.gem("sparks", gitlab: "rails")
- gitlab_uri = "https://gitlab.com/rails/rails.git"
- expect(subject.dependencies.first.source.uri).to eq(gitlab_uri)
- end
-
it "converts numeric :gist to :git" do
- subject.gem("not-really-a-gem", gist: 2_859_988)
+ subject.gem("not-really-a-gem", :gist => 2_859_988)
github_uri = "https://gist.github.com/2859988.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
end
it "converts :gist to :git" do
- subject.gem("not-really-a-gem", gist: "2859988")
+ subject.gem("not-really-a-gem", :gist => "2859988")
github_uri = "https://gist.github.com/2859988.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri)
end
it "converts :bitbucket to :git" do
- subject.gem("not-really-a-gem", bitbucket: "mcorp/flatlab-rails")
+ subject.gem("not-really-a-gem", :bitbucket => "mcorp/flatlab-rails")
bitbucket_uri = "https://mcorp@bitbucket.org/mcorp/flatlab-rails.git"
expect(subject.dependencies.first.source.uri).to eq(bitbucket_uri)
end
it "converts 'mcorp' to 'mcorp/mcorp'" do
- subject.gem("not-really-a-gem", bitbucket: "mcorp")
+ subject.gem("not-really-a-gem", :bitbucket => "mcorp")
bitbucket_uri = "https://mcorp@bitbucket.org/mcorp/mcorp.git"
expect(subject.dependencies.first.source.uri).to eq(bitbucket_uri)
end
end
context "default git sources" do
- it "has bitbucket, gist, github, and gitlab" do
- expect(subject.instance_variable_get(:@git_sources).keys.sort).to eq(%w[bitbucket gist github gitlab])
+ it "has bitbucket, gist, and github" do
+ expect(subject.instance_variable_get(:@git_sources).keys.sort).to eq(%w[bitbucket gist github])
end
end
end
@@ -175,7 +124,7 @@ RSpec.describe Bundler::Dsl do
it "handles syntax errors with a useful message" do
expect(Bundler).to receive(:read_file).with(source_root.join("Gemfile").to_s).and_return("}")
expect { subject.eval_gemfile("Gemfile") }.
- to raise_error(Bundler::GemfileError, /There was an error parsing `Gemfile`: (syntax error, unexpected tSTRING_DEND|(compile error - )?syntax error, unexpected '\}'|.+?unexpected '}', ignoring it\n). Bundler cannot continue./m)
+ to raise_error(Bundler::GemfileError, /There was an error parsing `Gemfile`: (syntax error, unexpected tSTRING_DEND|(compile error - )?syntax error, unexpected '\}'). Bundler cannot continue./)
end
it "distinguishes syntax errors from evaluation errors" do
@@ -185,17 +134,6 @@ RSpec.describe Bundler::Dsl do
expect { subject.eval_gemfile("Gemfile") }.
to raise_error(Bundler::GemfileError, /There was an error evaluating `Gemfile`: ruby_version must match the :engine_version for MRI/)
end
-
- it "populates __dir__ and __FILE__ correctly" do
- abs_path = source_root.join("../fragment.rb").to_s
- expect(Bundler).to receive(:read_file).with(abs_path).and_return(<<~RUBY)
- @fragment_dir = __dir__
- @fragment_file = __FILE__
- RUBY
- subject.eval_gemfile("../fragment.rb")
- expect(subject.instance_variable_get(:@fragment_dir)).to eq(source_root.dirname.to_s)
- expect(subject.instance_variable_get(:@fragment_file)).to eq(abs_path)
- end
end
describe "#gem" do
@@ -204,18 +142,18 @@ RSpec.describe Bundler::Dsl do
:ruby_30, :ruby_31, :ruby_32, :ruby_33, :mri, :mri_18, :mri_19, :mri_20, :mri_21, :mri_22, :mri_23, :mri_24,
:mri_25, :mri_26, :mri_27, :mri_30, :mri_31, :mri_32, :mri_33, :jruby, :rbx, :truffleruby].each do |platform|
it "allows #{platform} as a valid platform" do
- subject.gem("foo", platform: platform)
+ subject.gem("foo", :platform => platform)
end
end
# rubocop:enable Naming/VariableNumber
it "allows platforms matching the running Ruby version" do
platform = "ruby_#{RbConfig::CONFIG["MAJOR"]}#{RbConfig::CONFIG["MINOR"]}"
- subject.gem("foo", platform: platform)
+ subject.gem("foo", :platform => platform)
end
it "rejects invalid platforms" do
- expect { subject.gem("foo", platform: :bogus) }.
+ expect { subject.gem("foo", :platform => :bogus) }.
to raise_error(Bundler::GemfileError, /is not a valid platform/)
end
@@ -265,19 +203,19 @@ RSpec.describe Bundler::Dsl do
end
it "rejects branch option on non-git gems" do
- expect { subject.gem("foo", branch: "test") }.
+ expect { subject.gem("foo", :branch => "test") }.
to raise_error(Bundler::GemfileError, /The `branch` option for `gem 'foo'` is not allowed. Only gems with a git source can specify a branch/)
end
it "allows specifying a branch on git gems" do
- subject.gem("foo", branch: "test", git: "http://mytestrepo")
+ subject.gem("foo", :branch => "test", :git => "http://mytestrepo")
dep = subject.dependencies.last
expect(dep.name).to eq "foo"
end
it "allows specifying a branch on git gems with a git_source" do
subject.git_source(:test_source) {|n| "https://github.com/#{n}" }
- subject.gem("foo", branch: "test", test_source: "bundler/bundler")
+ subject.gem("foo", :branch => "test", :test_source => "bundler/bundler")
dep = subject.dependencies.last
expect(dep.name).to eq "foo"
end
@@ -322,7 +260,7 @@ RSpec.describe Bundler::Dsl do
it "will raise a Bundler::GemfileError" do
gemfile "gem 'foo', :path => /unquoted/string/syntax/error"
expect { Bundler::Dsl.evaluate(bundled_app_gemfile, nil, true) }.
- to raise_error(Bundler::GemfileError, /There was an error parsing `Gemfile`:( compile error -)?.+?unknown regexp options - trg.+ Bundler cannot continue./m)
+ to raise_error(Bundler::GemfileError, /There was an error parsing `Gemfile`:( compile error -)? unknown regexp options - trg.+ Bundler cannot continue./)
end
end
@@ -342,7 +280,7 @@ RSpec.describe Bundler::Dsl do
allow(Bundler).to receive(:default_gemfile).and_return(Pathname.new("./Gemfile"))
subject.source("https://other-source.org") do
- subject.gem("dobry-pies", path: "foo")
+ subject.gem("dobry-pies", :path => "foo")
subject.gem("foo")
end
@@ -354,7 +292,7 @@ RSpec.describe Bundler::Dsl do
describe "#check_primary_source_safety" do
context "when a global source is not defined implicitly" do
it "will raise a major deprecation warning" do
- not_a_global_source = double("not-a-global-source", no_remotes?: true)
+ not_a_global_source = double("not-a-global-source", :no_remotes? => true)
allow(Bundler::Source::Rubygems).to receive(:new).and_return(not_a_global_source)
warning = "This Gemfile does not include an explicit global source. " \
diff --git a/spec/bundler/bundler/endpoint_specification_spec.rb b/spec/bundler/bundler/endpoint_specification_spec.rb
index 6518f125ba..7dd6925007 100644
--- a/spec/bundler/bundler/endpoint_specification_spec.rb
+++ b/spec/bundler/bundler/endpoint_specification_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe Bundler::EndpointSpecification do
expect { subject }.to raise_error(
Bundler::GemspecError,
a_string_including("There was an error parsing the metadata for the gem foo (1.0.0)").
- and(a_string_including("The metadata was #{{ "rubygems" => ">\n" }.inspect}"))
+ and(a_string_including('The metadata was {"rubygems"=>">\n"}'))
)
end
end
@@ -60,21 +60,21 @@ RSpec.describe Bundler::EndpointSpecification do
it "should return the remote spec value when not set on endpoint specification and remote spec has one" do
remote_value = "remote_value"
- remote_spec = double(:remote_spec, required_ruby_version: remote_value, required_rubygems_version: nil)
+ remote_spec = double(:remote_spec, :required_ruby_version => remote_value, :required_rubygems_version => nil)
allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec)
expect(spec.required_ruby_version). eql?(remote_value)
end
it "should use the default Gem Requirement value when not set on endpoint specification and not set on remote spec" do
- remote_spec = double(:remote_spec, required_ruby_version: nil, required_rubygems_version: nil)
+ remote_spec = double(:remote_spec, :required_ruby_version => nil, :required_rubygems_version => nil)
allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec)
expect(spec.required_ruby_version). eql?(Gem::Requirement.default)
end
end
it "supports equality comparison" do
- remote_spec = double(:remote_spec, required_ruby_version: nil, required_rubygems_version: nil)
+ remote_spec = double(:remote_spec, :required_ruby_version => nil, :required_rubygems_version => nil)
allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec)
other_spec = described_class.new("bar", version, platform, spec_fetcher, dependencies, metadata)
expect(spec).to eql(spec)
diff --git a/spec/bundler/bundler/env_spec.rb b/spec/bundler/bundler/env_spec.rb
index e0ab0a45e3..a00489d0e5 100644
--- a/spec/bundler/bundler/env_spec.rb
+++ b/spec/bundler/bundler/env_spec.rb
@@ -70,16 +70,16 @@ RSpec.describe Bundler::Env do
context "when there is a Gemfile and a lockfile and print_gemfile is true" do
before do
- gemfile "source 'https://gem.repo1'; gem 'myrack', '1.0.0'"
+ gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem 'rack', '1.0.0'"
lockfile <<-L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
DEPENDENCIES
- myrack
+ rack
BUNDLED WITH
1.10.0
@@ -88,21 +88,21 @@ RSpec.describe Bundler::Env do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
end
- let(:output) { described_class.report(print_gemfile: true) }
+ let(:output) { described_class.report(:print_gemfile => true) }
it "prints the Gemfile" do
expect(output).to include("Gemfile")
- expect(output).to include("'myrack', '1.0.0'")
+ expect(output).to include("'rack', '1.0.0'")
end
it "prints the lockfile" do
expect(output).to include("Gemfile.lock")
- expect(output).to include("myrack (1.0.0)")
+ expect(output).to include("rack (1.0.0)")
end
end
context "when there no Gemfile and print_gemfile is true" do
- let(:output) { described_class.report(print_gemfile: true) }
+ let(:output) { described_class.report(:print_gemfile => true) }
it "prints the environment" do
expect(output).to start_with("## Environment")
@@ -114,7 +114,7 @@ RSpec.describe Bundler::Env do
bundle "config set https://localgemserver.test/ user:pass"
end
- let(:output) { described_class.report(print_gemfile: true) }
+ let(:output) { described_class.report(:print_gemfile => true) }
it "prints the config with redacted values" do
expect(output).to include("https://localgemserver.test")
@@ -128,7 +128,7 @@ RSpec.describe Bundler::Env do
bundle "config set https://localgemserver.test/ api_token:x-oauth-basic"
end
- let(:output) { described_class.report(print_gemfile: true) }
+ let(:output) { described_class.report(:print_gemfile => true) }
it "prints the config with redacted values" do
expect(output).to include("https://localgemserver.test")
@@ -139,7 +139,7 @@ RSpec.describe Bundler::Env do
context "when Gemfile contains a gemspec and print_gemspecs is true" do
let(:gemspec) do
- <<~GEMSPEC
+ strip_whitespace(<<-GEMSPEC)
Gem::Specification.new do |gem|
gem.name = "foo"
gem.author = "Fumofu"
@@ -148,9 +148,9 @@ RSpec.describe Bundler::Env do
end
before do
- gemfile("source 'https://gem.repo1'; gemspec")
+ gemfile("source \"#{file_uri_for(gem_repo1)}\"; gemspec")
- File.open(bundled_app("foo.gemspec"), "wb") do |f|
+ File.open(bundled_app.join("foo.gemspec"), "wb") do |f|
f.write(gemspec)
end
@@ -158,7 +158,7 @@ RSpec.describe Bundler::Env do
end
it "prints the gemspec" do
- output = described_class.report(print_gemspecs: true)
+ output = described_class.report(:print_gemspecs => true)
expect(output).to include("foo.gemspec")
expect(output).to include(gemspec)
@@ -167,18 +167,18 @@ RSpec.describe Bundler::Env do
context "when eval_gemfile is used" do
it "prints all gemfiles" do
- gemfile bundled_app("other/Gemfile-other"), "gem 'myrack'"
- gemfile bundled_app("other/Gemfile"), "eval_gemfile 'Gemfile-other'"
- gemfile bundled_app("Gemfile-alt"), <<-G
- source "https://gem.repo1"
+ create_file bundled_app("other/Gemfile-other"), "gem 'rack'"
+ create_file bundled_app("other/Gemfile"), "eval_gemfile 'Gemfile-other'"
+ create_file bundled_app("Gemfile-alt"), <<-G
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "other/Gemfile"
G
gemfile "eval_gemfile #{bundled_app("Gemfile-alt").to_s.dump}"
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
allow(Bundler::SharedHelpers).to receive(:pwd).and_return(bundled_app)
- output = described_class.report(print_gemspecs: true)
- expect(output).to include(<<~ENV)
+ output = described_class.report(:print_gemspecs => true)
+ expect(output).to include(strip_whitespace(<<-ENV))
## Gemfile
### Gemfile
@@ -190,7 +190,7 @@ RSpec.describe Bundler::Env do
### Gemfile-alt
```ruby
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "other/Gemfile"
```
@@ -203,7 +203,7 @@ RSpec.describe Bundler::Env do
### other/Gemfile-other
```ruby
- gem 'myrack'
+ gem 'rack'
```
### Gemfile.lock
diff --git a/spec/bundler/bundler/environment_preserver_spec.rb b/spec/bundler/bundler/environment_preserver_spec.rb
index 6c7066d0c6..530ca6f835 100644
--- a/spec/bundler/bundler/environment_preserver_spec.rb
+++ b/spec/bundler/bundler/environment_preserver_spec.rb
@@ -27,12 +27,8 @@ RSpec.describe Bundler::EnvironmentPreserver do
context "when a key is empty" do
let(:env) { { "foo" => "" } }
- it "should keep the original entry" do
- expect(subject["foo"]).to be_empty
- end
-
- it "should still create backup entries" do
- expect(subject).to have_key "BUNDLER_ORIG_foo"
+ it "should not create backup entries" do
+ expect(subject).not_to have_key "BUNDLER_ORIG_foo"
end
end
@@ -75,12 +71,8 @@ RSpec.describe Bundler::EnvironmentPreserver do
context "when the original key is empty" do
let(:env) { { "foo" => "my-foo", "BUNDLER_ORIG_foo" => "" } }
- it "should restore the original value" do
- expect(subject["foo"]).to be_empty
- end
-
- it "should delete the backup value" do
- expect(subject.key?("BUNDLER_ORIG_foo")).to eq(false)
+ it "should keep the current value" do
+ expect(subject["foo"]).to eq("my-foo")
end
end
end
diff --git a/spec/bundler/bundler/fetcher/base_spec.rb b/spec/bundler/bundler/fetcher/base_spec.rb
index b8c6b57b10..02506591f3 100644
--- a/spec/bundler/bundler/fetcher/base_spec.rb
+++ b/spec/bundler/bundler/fetcher/base_spec.rb
@@ -4,16 +4,15 @@ RSpec.describe Bundler::Fetcher::Base do
let(:downloader) { double(:downloader) }
let(:remote) { double(:remote) }
let(:display_uri) { "http://sample_uri.com" }
- let(:gem_remote_fetcher) { nil }
class TestClass < described_class; end
- subject { TestClass.new(downloader, remote, display_uri, gem_remote_fetcher) }
+ subject { TestClass.new(downloader, remote, display_uri) }
describe "#initialize" do
context "with the abstract Base class" do
it "should raise an error" do
- expect { described_class.new(downloader, remote, display_uri, gem_remote_fetcher) }.to raise_error(RuntimeError, "Abstract class")
+ expect { described_class.new(downloader, remote, display_uri) }.to raise_error(RuntimeError, "Abstract class")
end
end
@@ -37,7 +36,7 @@ RSpec.describe Bundler::Fetcher::Base do
end
describe "#fetch_uri" do
- let(:remote_uri_obj) { Gem::URI("http://rubygems.org") }
+ let(:remote_uri_obj) { Bundler::URI("http://rubygems.org") }
before { allow(subject).to receive(:remote_uri).and_return(remote_uri_obj) }
@@ -50,10 +49,10 @@ RSpec.describe Bundler::Fetcher::Base do
end
context "when the remote uri's host is not rubygems.org" do
- let(:remote_uri_obj) { Gem::URI("http://otherhost.org") }
+ let(:remote_uri_obj) { Bundler::URI("http://otherhost.org") }
it "should return the remote uri" do
- expect(subject.fetch_uri).to eq(Gem::URI("http://otherhost.org"))
+ expect(subject.fetch_uri).to eq(Bundler::URI("http://otherhost.org"))
end
end
diff --git a/spec/bundler/bundler/fetcher/compact_index_spec.rb b/spec/bundler/bundler/fetcher/compact_index_spec.rb
index aa536673d9..00eb27edea 100644
--- a/spec/bundler/bundler/fetcher/compact_index_spec.rb
+++ b/spec/bundler/bundler/fetcher/compact_index_spec.rb
@@ -4,18 +4,13 @@
require "bundler/compact_index_client"
RSpec.describe Bundler::Fetcher::CompactIndex do
- let(:response) { double(:response) }
- let(:downloader) { double(:downloader, fetch: response) }
- let(:display_uri) { Gem::URI("http://sampleuri.com") }
- let(:remote) { double(:remote, cache_slug: "lsjdf", uri: display_uri) }
- let(:gem_remote_fetcher) { nil }
- let(:compact_index) { described_class.new(downloader, remote, display_uri, gem_remote_fetcher) }
- let(:compact_index_client) { double(:compact_index_client, available?: true, info: [["lskdjf", "1", nil, [], []]]) }
+ let(:downloader) { double(:downloader) }
+ let(:display_uri) { Bundler::URI("http://sampleuri.com") }
+ let(:remote) { double(:remote, :cache_slug => "lsjdf", :uri => display_uri) }
+ let(:compact_index) { described_class.new(downloader, remote, display_uri) }
before do
- allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified).and_return(true)
allow(compact_index).to receive(:log_specs) {}
- allow(compact_index).to receive(:compact_index_client).and_return(compact_index_client)
end
describe "#specs_for_names" do
@@ -36,6 +31,11 @@ RSpec.describe Bundler::Fetcher::CompactIndex do
end
describe "#available?" do
+ before do
+ allow(compact_index).to receive(:compact_index_client).
+ and_return(double(:compact_index_client, :update_and_parse_checksums! => true))
+ end
+
it "returns true" do
expect(compact_index).to be_available
end
diff --git a/spec/bundler/bundler/fetcher/dependency_spec.rb b/spec/bundler/bundler/fetcher/dependency_spec.rb
index c420b7c07f..20307f9c99 100644
--- a/spec/bundler/bundler/fetcher/dependency_spec.rb
+++ b/spec/bundler/bundler/fetcher/dependency_spec.rb
@@ -2,11 +2,10 @@
RSpec.describe Bundler::Fetcher::Dependency do
let(:downloader) { double(:downloader) }
- let(:remote) { double(:remote, uri: Gem::URI("http://localhost:5000")) }
+ let(:remote) { double(:remote, :uri => Bundler::URI("http://localhost:5000")) }
let(:display_uri) { "http://sample_uri.com" }
- let(:gem_remote_fetcher) { nil }
- subject { described_class.new(downloader, remote, display_uri, gem_remote_fetcher) }
+ subject { described_class.new(downloader, remote, display_uri) }
describe "#available?" do
let(:dependency_api_uri) { double(:dependency_api_uri) }
@@ -211,7 +210,7 @@ RSpec.describe Bundler::Fetcher::Dependency do
let(:gem_names) { [%w[foo bar], %w[bundler rubocop]] }
let(:dep_api_uri) { double(:dep_api_uri) }
let(:unmarshalled_gems) { double(:unmarshalled_gems) }
- let(:fetch_response) { double(:fetch_response, body: double(:body)) }
+ let(:fetch_response) { double(:fetch_response, :body => double(:body)) }
let(:rubygems_limit) { 50 }
before { allow(subject).to receive(:dependency_api_uri).with(gem_names).and_return(dep_api_uri) }
@@ -228,20 +227,20 @@ RSpec.describe Bundler::Fetcher::Dependency do
let(:gem_list) do
[
{
- dependencies: {
+ :dependencies => {
"resque" => "req3,req4",
},
- name: "typhoeus",
- number: "1.0.1",
- platform: "ruby",
+ :name => "typhoeus",
+ :number => "1.0.1",
+ :platform => "ruby",
},
{
- dependencies: {
+ :dependencies => {
"faraday" => "req1,req2",
},
- name: "grape",
- number: "2.0.2",
- platform: "jruby",
+ :name => "grape",
+ :number => "2.0.2",
+ :platform => "jruby",
},
]
end
@@ -255,7 +254,7 @@ RSpec.describe Bundler::Fetcher::Dependency do
end
describe "#dependency_api_uri" do
- let(:uri) { Gem::URI("http://gem-api.com") }
+ let(:uri) { Bundler::URI("http://gem-api.com") }
context "with gem names" do
let(:gem_names) { %w[foo bar bundler rubocop] }
diff --git a/spec/bundler/bundler/fetcher/downloader_spec.rb b/spec/bundler/bundler/fetcher/downloader_spec.rb
index d5c32f4730..22aa3a8b0c 100644
--- a/spec/bundler/bundler/fetcher/downloader_spec.rb
+++ b/spec/bundler/bundler/fetcher/downloader_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe Bundler::Fetcher::Downloader do
let(:connection) { double(:connection) }
let(:redirect_limit) { 5 }
- let(:uri) { Gem::URI("http://www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://www.uri-to-fetch.com/api/v2/endpoint") }
let(:options) { double(:options) }
subject { described_class.new(connection, redirect_limit) }
@@ -27,7 +27,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "logging" do
- let(:http_response) { Gem::Net::HTTPSuccess.new("1.1", 200, "Success") }
+ let(:http_response) { Net::HTTPSuccess.new("1.1", 200, "Success") }
it "should log the HTTP response code and message to debug" do
expect(Bundler).to receive_message_chain(:ui, :debug).with("HTTP 200 Success #{uri}")
@@ -35,48 +35,48 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
end
- context "when the request response is a Gem::Net::HTTPRedirection" do
- let(:http_response) { Gem::Net::HTTPRedirection.new(httpv, 308, "Moved") }
+ context "when the request response is a Net::HTTPRedirection" do
+ let(:http_response) { Net::HTTPRedirection.new(httpv, 308, "Moved") }
before { http_response["location"] = "http://www.redirect-uri.com/api/v2/endpoint" }
it "should try to fetch the redirect uri and iterate the # requests counter" do
- expect(subject).to receive(:fetch).with(Gem::URI("http://www.uri-to-fetch.com/api/v2/endpoint"), options, 0).and_call_original
- expect(subject).to receive(:fetch).with(Gem::URI("http://www.redirect-uri.com/api/v2/endpoint"), options, 1)
+ expect(subject).to receive(:fetch).with(Bundler::URI("http://www.uri-to-fetch.com/api/v2/endpoint"), options, 0).and_call_original
+ expect(subject).to receive(:fetch).with(Bundler::URI("http://www.redirect-uri.com/api/v2/endpoint"), options, 1)
subject.fetch(uri, options, counter)
end
context "when the redirect uri and original uri are the same" do
- let(:uri) { Gem::URI("ssh://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("ssh://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
before { http_response["location"] = "ssh://www.uri-to-fetch.com/api/v1/endpoint" }
it "should set the same user and password for the redirect uri" do
- expect(subject).to receive(:fetch).with(Gem::URI("ssh://username:password@www.uri-to-fetch.com/api/v2/endpoint"), options, 0).and_call_original
- expect(subject).to receive(:fetch).with(Gem::URI("ssh://username:password@www.uri-to-fetch.com/api/v1/endpoint"), options, 1)
+ expect(subject).to receive(:fetch).with(Bundler::URI("ssh://username:password@www.uri-to-fetch.com/api/v2/endpoint"), options, 0).and_call_original
+ expect(subject).to receive(:fetch).with(Bundler::URI("ssh://username:password@www.uri-to-fetch.com/api/v1/endpoint"), options, 1)
subject.fetch(uri, options, counter)
end
end
end
- context "when the request response is a Gem::Net::HTTPSuccess" do
- let(:http_response) { Gem::Net::HTTPSuccess.new("1.1", 200, "Success") }
+ context "when the request response is a Net::HTTPSuccess" do
+ let(:http_response) { Net::HTTPSuccess.new("1.1", 200, "Success") }
it "should return the response body" do
expect(subject.fetch(uri, options, counter)).to eq(http_response)
end
end
- context "when the request response is a Gem::Net::HTTPRequestEntityTooLarge" do
- let(:http_response) { Gem::Net::HTTPRequestEntityTooLarge.new("1.1", 413, "Too Big") }
+ context "when the request response is a Net::HTTPRequestEntityTooLarge" do
+ let(:http_response) { Net::HTTPRequestEntityTooLarge.new("1.1", 413, "Too Big") }
it "should raise a Bundler::Fetcher::FallbackError with the response body" do
expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::FallbackError, "Body with info")
end
end
- context "when the request response is a Gem::Net::HTTPUnauthorized" do
- let(:http_response) { Gem::Net::HTTPUnauthorized.new("1.1", 401, "Unauthorized") }
+ context "when the request response is a Net::HTTPUnauthorized" do
+ let(:http_response) { Net::HTTPUnauthorized.new("1.1", 401, "Unauthorized") }
it "should raise a Bundler::Fetcher::AuthenticationRequiredError with the uri host" do
expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::AuthenticationRequiredError,
@@ -89,7 +89,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "when the there are credentials provided in the request" do
- let(:uri) { Gem::URI("http://user:password@www.uri-to-fetch.com") }
+ let(:uri) { Bundler::URI("http://user:password@www.uri-to-fetch.com") }
it "should raise a Bundler::Fetcher::BadAuthenticationError that doesn't contain the password" do
expect { subject.fetch(uri, options, counter) }.
@@ -98,9 +98,9 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
end
- context "when the request response is a Gem::Net::HTTPForbidden" do
- let(:http_response) { Gem::Net::HTTPForbidden.new("1.1", 403, "Forbidden") }
- let(:uri) { Gem::URI("http://user:password@www.uri-to-fetch.com") }
+ context "when the request response is a Net::HTTPForbidden" do
+ let(:http_response) { Net::HTTPForbidden.new("1.1", 403, "Forbidden") }
+ let(:uri) { Bundler::URI("http://user:password@www.uri-to-fetch.com") }
it "should raise a Bundler::Fetcher::AuthenticationForbiddenError with the uri host" do
expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::AuthenticationForbiddenError,
@@ -108,29 +108,29 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
end
- context "when the request response is a Gem::Net::HTTPNotFound" do
- let(:http_response) { Gem::Net::HTTPNotFound.new("1.1", 404, "Not Found") }
+ context "when the request response is a Net::HTTPNotFound" do
+ let(:http_response) { Net::HTTPNotFound.new("1.1", 404, "Not Found") }
- it "should raise a Bundler::Fetcher::FallbackError with Gem::Net::HTTPNotFound" do
+ it "should raise a Bundler::Fetcher::FallbackError with Net::HTTPNotFound" do
expect { subject.fetch(uri, options, counter) }.
- to raise_error(Bundler::Fetcher::FallbackError, "Gem::Net::HTTPNotFound: http://www.uri-to-fetch.com/api/v2/endpoint")
+ to raise_error(Bundler::Fetcher::FallbackError, "Net::HTTPNotFound: http://www.uri-to-fetch.com/api/v2/endpoint")
end
context "when the there are credentials provided in the request" do
- let(:uri) { Gem::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
it "should raise a Bundler::Fetcher::FallbackError that doesn't contain the password" do
expect { subject.fetch(uri, options, counter) }.
- to raise_error(Bundler::Fetcher::FallbackError, "Gem::Net::HTTPNotFound: http://username@www.uri-to-fetch.com/api/v2/endpoint")
+ to raise_error(Bundler::Fetcher::FallbackError, "Net::HTTPNotFound: http://username@www.uri-to-fetch.com/api/v2/endpoint")
end
end
end
context "when the request response is some other type" do
- let(:http_response) { Gem::Net::HTTPBadGateway.new("1.1", 500, "Fatal Error") }
+ let(:http_response) { Net::HTTPBadGateway.new("1.1", 500, "Fatal Error") }
it "should raise a Bundler::HTTPError with the response class and body" do
- expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::HTTPError, "Gem::Net::HTTPBadGateway: Body with info")
+ expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::HTTPError, "Net::HTTPBadGateway: Body with info")
end
end
end
@@ -140,7 +140,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
let(:response) { double(:response) }
before do
- allow(Gem::Net::HTTP::Get).to receive(:new).with("/api/v2/endpoint", options).and_return(net_http_get)
+ allow(Net::HTTP::Get).to receive(:new).with("/api/v2/endpoint", options).and_return(net_http_get)
allow(connection).to receive(:request).with(uri, net_http_get).and_return(response)
end
@@ -152,7 +152,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
context "when there is a user provided in the request" do
context "and there is also a password provided" do
context "that contains cgi escaped characters" do
- let(:uri) { Gem::URI("http://username:password%24@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://username:password%24@www.uri-to-fetch.com/api/v2/endpoint") }
it "should request basic authentication with the username and password" do
expect(net_http_get).to receive(:basic_auth).with("username", "password$")
@@ -161,7 +161,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "that is all unescaped characters" do
- let(:uri) { Gem::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
it "should request basic authentication with the username and proper cgi compliant password" do
expect(net_http_get).to receive(:basic_auth).with("username", "password")
subject.request(uri, options)
@@ -170,7 +170,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "and there is no password provided" do
- let(:uri) { Gem::URI("http://username@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://username@www.uri-to-fetch.com/api/v2/endpoint") }
it "should request basic authentication with just the user" do
expect(net_http_get).to receive(:basic_auth).with("username", nil)
@@ -179,7 +179,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "that contains cgi escaped characters" do
- let(:uri) { Gem::URI("http://username%24@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://username%24@www.uri-to-fetch.com/api/v2/endpoint") }
it "should request basic authentication with the proper cgi compliant password user" do
expect(net_http_get).to receive(:basic_auth).with("username$", nil)
@@ -230,7 +230,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end
context "when the there are credentials provided in the request" do
- let(:uri) { Gem::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
+ let(:uri) { Bundler::URI("http://username:password@www.uri-to-fetch.com/api/v2/endpoint") }
before do
allow(net_http_get).to receive(:basic_auth).with("username", "password")
end
diff --git a/spec/bundler/bundler/fetcher/index_spec.rb b/spec/bundler/bundler/fetcher/index_spec.rb
index dff9ccc3cc..971b64ce8f 100644
--- a/spec/bundler/bundler/fetcher/index_spec.rb
+++ b/spec/bundler/bundler/fetcher/index_spec.rb
@@ -8,9 +8,8 @@ RSpec.describe Bundler::Fetcher::Index do
let(:display_uri) { "http://sample_uri.com" }
let(:rubygems) { double(:rubygems) }
let(:gem_names) { %w[foo bar] }
- let(:gem_remote_fetcher) { nil }
- subject { described_class.new(downloader, remote, display_uri, gem_remote_fetcher) }
+ subject { described_class.new(downloader, remote, display_uri) }
before { allow(Bundler).to receive(:rubygems).and_return(rubygems) }
@@ -20,7 +19,7 @@ RSpec.describe Bundler::Fetcher::Index do
end
context "error handling" do
- let(:remote_uri) { Gem::URI("http://remote-uri.org") }
+ let(:remote_uri) { Bundler::URI("http://remote-uri.org") }
before do
allow(rubygems).to receive(:fetch_all_remote_specs) { raise Gem::RemoteFetcher::FetchError.new(error_message, display_uri) }
allow(subject).to receive(:remote_uri).and_return(remote_uri)
@@ -73,7 +72,7 @@ RSpec.describe Bundler::Fetcher::Index do
context "any other message is returned" do
let(:error_message) { "You get an error, you get an error!" }
- before { allow(Bundler).to receive(:ui).and_return(double(trace: nil)) }
+ before { allow(Bundler).to receive(:ui).and_return(double(:trace => nil)) }
it "should raise a Bundler::HTTPError" do
expect { subject.specs(gem_names) }.to raise_error(Bundler::HTTPError, "Could not fetch specs from http://sample_uri.com due to underlying error <You get an error, you get an error! (http://sample_uri.com)>")
diff --git a/spec/bundler/bundler/fetcher_spec.rb b/spec/bundler/bundler/fetcher_spec.rb
index e20f7e7c48..27a63c476d 100644
--- a/spec/bundler/bundler/fetcher_spec.rb
+++ b/spec/bundler/bundler/fetcher_spec.rb
@@ -3,8 +3,8 @@
require "bundler/fetcher"
RSpec.describe Bundler::Fetcher do
- let(:uri) { Gem::URI("https://example.com") }
- let(:remote) { double("remote", uri: uri, original_uri: nil) }
+ let(:uri) { Bundler::URI("https://example.com") }
+ let(:remote) { double("remote", :uri => uri, :original_uri => nil) }
subject(:fetcher) { Bundler::Fetcher.new(remote) }
@@ -45,9 +45,9 @@ RSpec.describe Bundler::Fetcher do
end
context "when a rubygems source mirror is set" do
- let(:orig_uri) { Gem::URI("http://zombo.com") }
+ let(:orig_uri) { Bundler::URI("http://zombo.com") }
let(:remote_with_mirror) do
- double("remote", uri: uri, original_uri: orig_uri, anonymized_uri: uri)
+ double("remote", :uri => uri, :original_uri => orig_uri, :anonymized_uri => uri)
end
let(:fetcher) { Bundler::Fetcher.new(remote_with_mirror) }
@@ -61,7 +61,7 @@ RSpec.describe Bundler::Fetcher do
context "when there is no rubygems source mirror set" do
let(:remote_no_mirror) do
- double("remote", uri: uri, original_uri: nil, anonymized_uri: uri)
+ double("remote", :uri => uri, :original_uri => nil, :anonymized_uri => uri)
end
let(:fetcher) { Bundler::Fetcher.new(remote_no_mirror) }
@@ -114,9 +114,9 @@ RSpec.describe Bundler::Fetcher do
context "when gem ssl configuration is set" do
before do
allow(Gem.configuration).to receive_messages(
- http_proxy: nil,
- ssl_client_cert: "cert",
- ssl_ca_cert: "ca"
+ :http_proxy => nil,
+ :ssl_client_cert => "cert",
+ :ssl_ca_cert => "ca"
)
expect(File).to receive(:read).and_return("")
expect(OpenSSL::X509::Certificate).to receive(:new).and_return("cert")
@@ -143,20 +143,18 @@ RSpec.describe Bundler::Fetcher do
describe "include CI information" do
it "from one CI" do
- with_env_vars("CI" => nil, "JENKINS_URL" => "foo") do
+ with_env_vars("JENKINS_URL" => "foo") do
ci_part = fetcher.user_agent.split(" ").find {|x| x.start_with?("ci/") }
- cis = ci_part.split("/").last.split(",")
- expect(cis).to include("jenkins")
- expect(cis).not_to include("ci")
+ expect(ci_part).to match("jenkins")
end
end
it "from many CI" do
- with_env_vars("CI" => "true", "SEMAPHORE" => nil, "TRAVIS" => "foo", "GITLAB_CI" => "gitlab", "CI_NAME" => "MY_ci") do
+ with_env_vars("TRAVIS" => "foo", "GITLAB_CI" => "gitlab", "CI_NAME" => "my_ci") do
ci_part = fetcher.user_agent.split(" ").find {|x| x.start_with?("ci/") }
- cis = ci_part.split("/").last.split(",")
- expect(cis).to include("ci", "gitlab", "my_ci", "travis")
- expect(cis).not_to include("semaphore")
+ expect(ci_part).to match("travis")
+ expect(ci_part).to match("gitlab")
+ expect(ci_part).to match("my_ci")
end
end
end
@@ -167,7 +165,7 @@ RSpec.describe Bundler::Fetcher do
let(:version) { "1.3.17" }
let(:platform) { "platform" }
let(:downloader) { double("downloader") }
- let(:body) { double(Gem::Net::HTTP::Get, body: downloaded_data) }
+ let(:body) { double(Net::HTTP::Get, :body => downloaded_data) }
context "when attempting to load a Gem::Specification" do
let(:spec) { Gem::Specification.new(name, version) }
@@ -191,70 +189,4 @@ RSpec.describe Bundler::Fetcher do
end
end
end
-
- describe "#specs_with_retry" do
- let(:downloader) { double(:downloader) }
- let(:remote) { double(:remote, cache_slug: "slug", uri: uri, original_uri: nil, anonymized_uri: uri) }
- let(:compact_index) { double(Bundler::Fetcher::CompactIndex, available?: true, api_fetcher?: true) }
- let(:dependency) { double(Bundler::Fetcher::Dependency, available?: true, api_fetcher?: true) }
- let(:index) { double(Bundler::Fetcher::Index, available?: true, api_fetcher?: false) }
-
- before do
- allow(Bundler::Fetcher::CompactIndex).to receive(:new).and_return(compact_index)
- allow(Bundler::Fetcher::Dependency).to receive(:new).and_return(dependency)
- allow(Bundler::Fetcher::Index).to receive(:new).and_return(index)
- end
-
- it "picks the first fetcher that works" do
- expect(compact_index).to receive(:specs).with("name").and_return([["name", "1.2.3", "ruby"]])
- expect(dependency).not_to receive(:specs)
- expect(index).not_to receive(:specs)
- fetcher.specs_with_retry("name", double(Bundler::Source::Rubygems))
- end
-
- context "when APIs are not available" do
- before do
- allow(compact_index).to receive(:available?).and_return(false)
- allow(dependency).to receive(:available?).and_return(false)
- end
-
- it "uses the index" do
- expect(compact_index).not_to receive(:specs)
- expect(dependency).not_to receive(:specs)
- expect(index).to receive(:specs).with("name").and_return([["name", "1.2.3", "ruby"]])
-
- fetcher.specs_with_retry("name", double(Bundler::Source::Rubygems))
- end
- end
- end
-
- describe "#api_fetcher?" do
- let(:downloader) { double(:downloader) }
- let(:remote) { double(:remote, cache_slug: "slug", uri: uri, original_uri: nil, anonymized_uri: uri) }
- let(:compact_index) { double(Bundler::Fetcher::CompactIndex, available?: false, api_fetcher?: true) }
- let(:dependency) { double(Bundler::Fetcher::Dependency, available?: false, api_fetcher?: true) }
- let(:index) { double(Bundler::Fetcher::Index, available?: true, api_fetcher?: false) }
-
- before do
- allow(Bundler::Fetcher::CompactIndex).to receive(:new).and_return(compact_index)
- allow(Bundler::Fetcher::Dependency).to receive(:new).and_return(dependency)
- allow(Bundler::Fetcher::Index).to receive(:new).and_return(index)
- end
-
- context "when an api fetcher is available" do
- before do
- allow(compact_index).to receive(:available?).and_return(true)
- end
-
- it "is truthy" do
- expect(fetcher).to be_api_fetcher
- end
- end
-
- context "when only the index fetcher is available" do
- it "is falsey" do
- expect(fetcher).not_to be_api_fetcher
- end
- end
- end
end
diff --git a/spec/bundler/bundler/friendly_errors_spec.rb b/spec/bundler/bundler/friendly_errors_spec.rb
index 255019f40a..37afe488f3 100644
--- a/spec/bundler/bundler/friendly_errors_spec.rb
+++ b/spec/bundler/bundler/friendly_errors_spec.rb
@@ -18,11 +18,11 @@ RSpec.describe Bundler, "friendly errors" do
it "reports a relevant friendly error message" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle :install, env: { "DEBUG" => "true" }
+ bundle :install, :env => { "DEBUG" => "true" }
expect(err).to include("Failed to load #{home(".gemrc")}")
end
@@ -101,7 +101,7 @@ RSpec.describe Bundler, "friendly errors" do
context "BundlerError" do
it "Bundler.ui receive error" do
error = Bundler::BundlerError.new
- expect(Bundler.ui).to receive(:error).with(error.message, wrap: true)
+ expect(Bundler.ui).to receive(:error).with(error.message, :wrap => true)
Bundler::FriendlyErrors.log_error(error)
end
end
@@ -121,7 +121,7 @@ RSpec.describe Bundler, "friendly errors" do
context "Gem::InvalidSpecificationException" do
it "Bundler.ui receive error" do
error = Gem::InvalidSpecificationException.new
- expect(Bundler.ui).to receive(:error).with(error.message, wrap: true)
+ expect(Bundler.ui).to receive(:error).with(error.message, :wrap => true)
Bundler::FriendlyErrors.log_error(error)
end
end
diff --git a/spec/bundler/bundler/gem_helper_spec.rb b/spec/bundler/bundler/gem_helper_spec.rb
index 94f66537d3..7d955007ab 100644
--- a/spec/bundler/bundler/gem_helper_spec.rb
+++ b/spec/bundler/bundler/gem_helper_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Bundler::GemHelper do
before(:each) do
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false",
"BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
- git("config --global init.defaultBranch main")
+ sys_exec("git config --global init.defaultBranch main")
bundle "gem #{app_name}"
prepare_gemspec(app_gemspec_path)
end
@@ -253,11 +253,11 @@ RSpec.describe Bundler::GemHelper do
end
before do
- git("init", app_path)
- git("config user.email \"you@example.com\"", app_path)
- git("config user.name \"name\"", app_path)
- git("config commit.gpgsign false", app_path)
- git("config push.default simple", app_path)
+ sys_exec("git init", :dir => app_path)
+ sys_exec("git config user.email \"you@example.com\"", :dir => app_path)
+ sys_exec("git config user.name \"name\"", :dir => app_path)
+ sys_exec("git config commit.gpgsign false", :dir => app_path)
+ sys_exec("git config push.default simple", :dir => app_path)
# silence messages
allow(Bundler.ui).to receive(:confirm)
@@ -271,23 +271,23 @@ RSpec.describe Bundler::GemHelper do
end
it "when there are uncommitted files" do
- git("add .", app_path)
+ sys_exec("git add .", :dir => app_path)
expect { Rake.application["release"].invoke }.
to raise_error("There are files that need to be committed first.")
end
it "when there is no git remote" do
- git("commit -a -m \"initial commit\"", app_path)
+ sys_exec("git commit -a -m \"initial commit\"", :dir => app_path)
expect { Rake.application["release"].invoke }.to raise_error(RuntimeError)
end
end
context "succeeds" do
- let(:repo) { build_git("foo", bare: true) }
+ let(:repo) { build_git("foo", :bare => true) }
before do
- git("remote add origin #{repo.path}", app_path)
- git('commit -a -m "initial commit"', app_path)
+ sys_exec("git remote add origin #{file_uri_for(repo.path)}", :dir => app_path)
+ sys_exec('git commit -a -m "initial commit"', :dir => app_path)
end
context "on releasing" do
@@ -296,7 +296,7 @@ RSpec.describe Bundler::GemHelper do
mock_confirm_message "Tagged v#{app_version}."
mock_confirm_message "Pushed git commits and release tag."
- git("push -u origin main", app_path)
+ sys_exec("git push -u origin main", :dir => app_path)
end
it "calls rubygem_push with proper arguments" do
@@ -314,8 +314,8 @@ RSpec.describe Bundler::GemHelper do
it "also works when releasing from an ambiguous reference" do
# Create a branch with the same name as the tag
- git("checkout -b v#{app_version}", app_path)
- git("push -u origin v#{app_version}", app_path)
+ sys_exec("git checkout -b v#{app_version}", :dir => app_path)
+ sys_exec("git push -u origin v#{app_version}", :dir => app_path)
expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s)
@@ -323,7 +323,7 @@ RSpec.describe Bundler::GemHelper do
end
it "also works with releasing from a branch not yet pushed" do
- git("checkout -b module_function", app_path)
+ sys_exec("git checkout -b module_function", :dir => app_path)
expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s)
@@ -337,7 +337,7 @@ RSpec.describe Bundler::GemHelper do
mock_build_message app_name, app_version
mock_confirm_message "Pushed git commits and release tag."
- git("push -u origin main", app_path)
+ sys_exec("git push -u origin main", :dir => app_path)
expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s)
end
@@ -353,7 +353,7 @@ RSpec.describe Bundler::GemHelper do
mock_confirm_message "Tag v#{app_version} has already been created."
expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s)
- git("tag -a -m \"Version #{app_version}\" v#{app_version}", app_path)
+ sys_exec("git tag -a -m \"Version #{app_version}\" v#{app_version}", :dir => app_path)
Rake.application["release"].invoke
end
@@ -374,10 +374,10 @@ RSpec.describe Bundler::GemHelper do
end
before do
- git("init", app_path)
- git("config user.email \"you@example.com\"", app_path)
- git("config user.name \"name\"", app_path)
- git("config push.gpgsign simple", app_path)
+ sys_exec("git init", :dir => app_path)
+ sys_exec("git config user.email \"you@example.com\"", :dir => app_path)
+ sys_exec("git config user.name \"name\"", :dir => app_path)
+ sys_exec("git config push.gpgsign simple", :dir => app_path)
# silence messages
allow(Bundler.ui).to receive(:confirm)
diff --git a/spec/bundler/bundler/gem_version_promoter_spec.rb b/spec/bundler/bundler/gem_version_promoter_spec.rb
index 917daba95d..8058412f32 100644
--- a/spec/bundler/bundler/gem_version_promoter_spec.rb
+++ b/spec/bundler/bundler/gem_version_promoter_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe Bundler::GemVersionPromoter do
end
def build_package(name, version, locked = [])
- Bundler::Resolver::Package.new(name, [], locked_specs: Bundler::SpecSet.new(build_spec(name, version)), unlock: locked)
+ Bundler::Resolver::Package.new(name, [], :locked_specs => Bundler::SpecSet.new(build_spec(name, version)), :unlock => locked)
end
def sorted_versions(candidates:, current:, name: "foo", locked: [])
@@ -32,14 +32,14 @@ RSpec.describe Bundler::GemVersionPromoter do
end
it "numerically sorts versions" do
- versions = sorted_versions(candidates: %w[1.7.7 1.7.8 1.7.9 1.7.15 1.8.0], current: "1.7.8")
- expect(versions).to eq %w[1.8.0 1.7.15 1.7.9 1.7.8 1.7.7]
+ versions = sorted_versions(:candidates => %w[1.7.7 1.7.8 1.7.9 1.7.15 1.8.0], :current => "1.7.8")
+ expect(versions).to eq %w[1.7.7 1.7.8 1.7.9 1.7.15 1.8.0]
end
context "with no options" do
it "defaults to level=:major, strict=false, pre=false" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[2.1.0 2.0.1 1.0.0 0.9.0 0.3.1 0.3.0 0.2.0]
+ versions = sorted_versions(:candidates => %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], :current => "0.3.0")
+ expect(versions).to eq %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0]
end
end
@@ -50,26 +50,26 @@ RSpec.describe Bundler::GemVersionPromoter do
before { gvp.level = :major }
it "keeps downgrades" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[2.1.0 2.0.1 1.0.0 0.9.0 0.3.1 0.3.0 0.2.0]
+ versions = sorted_versions(:candidates => %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], :current => "0.3.0")
+ expect(versions).to eq %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0]
end
end
context "when level is minor" do
before { gvp.level = :minor }
- it "sorts highest minor within same major in first position" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[0.9.0 0.3.1 0.3.0 1.0.0 2.1.0 2.0.1 0.2.0]
+ it "removes downgrades and major upgrades" do
+ versions = sorted_versions(:candidates => %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], :current => "0.3.0")
+ expect(versions).to eq %w[0.3.0 0.3.1 0.9.0]
end
end
context "when level is patch" do
before { gvp.level = :patch }
- it "sorts highest patch within same minor in first position" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[0.3.1 0.3.0 0.9.0 1.0.0 2.0.1 2.1.0 0.2.0]
+ it "removes downgrades and major and minor upgrades" do
+ versions = sorted_versions(:candidates => %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], :current => "0.3.0")
+ expect(versions).to eq %w[0.3.0 0.3.1]
end
end
end
@@ -81,26 +81,26 @@ RSpec.describe Bundler::GemVersionPromoter do
before { gvp.level = :major }
it "orders by version" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[2.1.0 2.0.1 1.0.0 0.9.0 0.3.1 0.3.0 0.2.0]
+ versions = sorted_versions(:candidates => %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], :current => "0.3.0")
+ expect(versions).to eq %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0]
end
end
context "when level is minor" do
before { gvp.level = :minor }
- it "favors minor upgrades, then patch upgrades, then major upgrades, then downgrades" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[0.9.0 0.3.1 0.3.0 1.0.0 2.1.0 2.0.1 0.2.0]
+ it "favors downgrades, then upgrades by major descending, minor ascending, patch ascending" do
+ versions = sorted_versions(:candidates => %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], :current => "0.3.0")
+ expect(versions).to eq %w[0.2.0 2.0.1 2.1.0 1.0.0 0.3.0 0.3.1 0.9.0]
end
end
context "when level is patch" do
before { gvp.level = :patch }
- it "favors patch upgrades, then minor upgrades, then major upgrades, then downgrades" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], current: "0.3.0")
- expect(versions).to eq %w[0.3.1 0.3.0 0.9.0 1.0.0 2.0.1 2.1.0 0.2.0]
+ it "favors downgrades, then upgrades by major descending, minor descending, patch ascending" do
+ versions = sorted_versions(:candidates => %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.0.1 2.1.0], :current => "0.3.0")
+ expect(versions).to eq %w[0.2.0 2.1.0 2.0.1 1.0.0 0.9.0 0.3.0 0.3.1]
end
end
end
@@ -109,8 +109,8 @@ RSpec.describe Bundler::GemVersionPromoter do
before { gvp.pre = true }
it "sorts regardless of prerelease status" do
- versions = sorted_versions(candidates: %w[1.7.7.pre 1.8.0 1.8.1.pre 1.8.1 2.0.0.pre 2.0.0], current: "1.8.0")
- expect(versions).to eq %w[2.0.0 2.0.0.pre 1.8.1 1.8.1.pre 1.8.0 1.7.7.pre]
+ versions = sorted_versions(:candidates => %w[1.7.7.pre 1.8.0 1.8.1.pre 1.8.1 2.0.0.pre 2.0.0], :current => "1.8.0")
+ expect(versions).to eq %w[1.7.7.pre 1.8.0 1.8.1.pre 1.8.1 2.0.0.pre 2.0.0]
end
end
@@ -118,17 +118,17 @@ RSpec.describe Bundler::GemVersionPromoter do
before { gvp.pre = false }
it "deprioritizes prerelease gems" do
- versions = sorted_versions(candidates: %w[1.7.7.pre 1.8.0 1.8.1.pre 1.8.1 2.0.0.pre 2.0.0], current: "1.8.0")
- expect(versions).to eq %w[2.0.0 1.8.1 1.8.0 2.0.0.pre 1.8.1.pre 1.7.7.pre]
+ versions = sorted_versions(:candidates => %w[1.7.7.pre 1.8.0 1.8.1.pre 1.8.1 2.0.0.pre 2.0.0], :current => "1.8.0")
+ expect(versions).to eq %w[1.7.7.pre 1.8.1.pre 2.0.0.pre 1.8.0 1.8.1 2.0.0]
end
end
context "when locking and not major" do
before { gvp.level = :minor }
- it "keeps the current version first" do
- versions = sorted_versions(candidates: %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.1.0 2.0.1], current: "0.3.0", locked: ["bar"])
- expect(versions.first).to eq("0.3.0")
+ it "keeps the current version last" do
+ versions = sorted_versions(:candidates => %w[0.2.0 0.3.0 0.3.1 0.9.0 1.0.0 2.1.0 2.0.1], :current => "0.3.0", :locked => ["bar"])
+ expect(versions.last).to eq("0.3.0")
end
end
end
diff --git a/spec/bundler/bundler/installer/gem_installer_spec.rb b/spec/bundler/bundler/installer/gem_installer_spec.rb
index 6583bd8181..e86bdf009a 100644
--- a/spec/bundler/bundler/installer/gem_installer_spec.rb
+++ b/spec/bundler/bundler/installer/gem_installer_spec.rb
@@ -3,11 +3,10 @@
require "bundler/installer/gem_installer"
RSpec.describe Bundler::GemInstaller do
- let(:definition) { instance_double("Definition", locked_gems: nil) }
- let(:installer) { instance_double("Installer", definition: definition) }
+ let(:definition) { instance_double("Definition", :locked_gems => nil) }
+ let(:installer) { instance_double("Installer", :definition => definition) }
let(:spec_source) { instance_double("SpecSource") }
- let(:spec) { instance_double("Specification", name: "dummy", version: "0.0.1", loaded_from: "dummy", source: spec_source) }
- let(:base_options) { { force: false, local: false, previous_spec: nil } }
+ let(:spec) { instance_double("Specification", :name => "dummy", :version => "0.0.1", :loaded_from => "dummy", :source => spec_source) }
subject { described_class.new(spec, installer) }
@@ -15,7 +14,7 @@ RSpec.describe Bundler::GemInstaller do
it "invokes install method with empty build_args" do
allow(spec_source).to receive(:install).with(
spec,
- base_options.merge(build_args: [])
+ { :force => false, :ensure_builtin_gems_cached => false, :build_args => [], :previous_spec => nil }
)
subject.install_from_spec
end
@@ -29,7 +28,7 @@ RSpec.describe Bundler::GemInstaller do
allow(Bundler.settings).to receive(:[]).with("build.dummy").and_return("--with-dummy-config=dummy")
expect(spec_source).to receive(:install).with(
spec,
- base_options.merge(build_args: ["--with-dummy-config=dummy"])
+ { :force => false, :ensure_builtin_gems_cached => false, :build_args => ["--with-dummy-config=dummy"], :previous_spec => nil }
)
subject.install_from_spec
end
@@ -43,7 +42,7 @@ RSpec.describe Bundler::GemInstaller do
allow(Bundler.settings).to receive(:[]).with("build.dummy").and_return("--with-dummy-config=dummy --with-another-dummy-config")
expect(spec_source).to receive(:install).with(
spec,
- base_options.merge(build_args: ["--with-dummy-config=dummy", "--with-another-dummy-config"])
+ { :force => false, :ensure_builtin_gems_cached => false, :build_args => ["--with-dummy-config=dummy", "--with-another-dummy-config"], :previous_spec => nil }
)
subject.install_from_spec
end
diff --git a/spec/bundler/bundler/installer/parallel_installer_spec.rb b/spec/bundler/bundler/installer/parallel_installer_spec.rb
new file mode 100644
index 0000000000..c8403a2e38
--- /dev/null
+++ b/spec/bundler/bundler/installer/parallel_installer_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require "bundler/installer/parallel_installer"
+
+RSpec.describe Bundler::ParallelInstaller do
+ let(:installer) { instance_double("Installer") }
+ let(:all_specs) { [] }
+ let(:size) { 1 }
+ let(:standalone) { false }
+ let(:force) { false }
+
+ subject { described_class.new(installer, all_specs, size, standalone, force) }
+
+ context "when the spec set is not a valid resolution" do
+ let(:all_specs) do
+ [
+ build_spec("cucumber", "4.1.0") {|s| s.runtime "diff-lcs", "< 1.4" },
+ build_spec("diff-lcs", "1.4.4"),
+ ].flatten
+ end
+
+ it "prints a warning" do
+ expect(Bundler.ui).to receive(:warn).with(<<-W.strip)
+Your lockfile doesn't include a valid resolution.
+You can fix this by regenerating your lockfile or manually editing the bad locked gems to a version that satisfies all dependencies.
+The unmet dependencies are:
+* diff-lcs (< 1.4), dependency of cucumber-4.1.0, unsatisfied by diff-lcs-1.4.4
+ W
+ subject.check_for_unmet_dependencies
+ end
+ end
+
+ context "when the spec set is a valid resolution" do
+ let(:all_specs) do
+ [
+ build_spec("cucumber", "4.1.0") {|s| s.runtime "diff-lcs", "< 1.4" },
+ build_spec("diff-lcs", "1.3"),
+ ].flatten
+ end
+
+ it "doesn't print a warning" do
+ expect(Bundler.ui).not_to receive(:warn)
+ subject.check_for_unmet_dependencies
+ end
+ end
+end
diff --git a/spec/bundler/bundler/installer/spec_installation_spec.rb b/spec/bundler/bundler/installer/spec_installation_spec.rb
index cbe2589b99..e63ef26cb3 100644
--- a/spec/bundler/bundler/installer/spec_installation_spec.rb
+++ b/spec/bundler/bundler/installer/spec_installation_spec.rb
@@ -42,26 +42,24 @@ RSpec.describe Bundler::ParallelInstaller::SpecInstallation do
context "when all dependencies are installed" do
it "returns true" do
dependencies = []
- dependencies << instance_double("SpecInstallation", spec: "alpha", name: "alpha", installed?: true, all_dependencies: [], type: :production)
- dependencies << instance_double("SpecInstallation", spec: "beta", name: "beta", installed?: true, all_dependencies: [], type: :production)
- all_specs = dependencies + [instance_double("SpecInstallation", spec: "gamma", name: "gamma", installed?: false, all_dependencies: [], type: :production)]
+ dependencies << instance_double("SpecInstallation", :spec => "alpha", :name => "alpha", :installed? => true, :all_dependencies => [], :type => :production)
+ dependencies << instance_double("SpecInstallation", :spec => "beta", :name => "beta", :installed? => true, :all_dependencies => [], :type => :production)
+ all_specs = dependencies + [instance_double("SpecInstallation", :spec => "gamma", :name => "gamma", :installed? => false, :all_dependencies => [], :type => :production)]
spec = described_class.new(dep)
allow(spec).to receive(:all_dependencies).and_return(dependencies)
- installed_specs = all_specs.select(&:installed?).map {|s| [s.name, true] }.to_h
- expect(spec.dependencies_installed?(installed_specs)).to be_truthy
+ expect(spec.dependencies_installed?(all_specs)).to be_truthy
end
end
context "when all dependencies are not installed" do
it "returns false" do
dependencies = []
- dependencies << instance_double("SpecInstallation", spec: "alpha", name: "alpha", installed?: false, all_dependencies: [], type: :production)
- dependencies << instance_double("SpecInstallation", spec: "beta", name: "beta", installed?: true, all_dependencies: [], type: :production)
- all_specs = dependencies + [instance_double("SpecInstallation", spec: "gamma", name: "gamma", installed?: false, all_dependencies: [], type: :production)]
+ dependencies << instance_double("SpecInstallation", :spec => "alpha", :name => "alpha", :installed? => false, :all_dependencies => [], :type => :production)
+ dependencies << instance_double("SpecInstallation", :spec => "beta", :name => "beta", :installed? => true, :all_dependencies => [], :type => :production)
+ all_specs = dependencies + [instance_double("SpecInstallation", :spec => "gamma", :name => "gamma", :installed? => false, :all_dependencies => [], :type => :production)]
spec = described_class.new(dep)
allow(spec).to receive(:all_dependencies).and_return(dependencies)
- installed_specs = all_specs.select(&:installed?).map {|s| [s.name, true] }.to_h
- expect(spec.dependencies_installed?(installed_specs)).to be_falsey
+ expect(spec.dependencies_installed?(all_specs)).to be_falsey
end
end
end
diff --git a/spec/bundler/bundler/lockfile_parser_spec.rb b/spec/bundler/bundler/lockfile_parser_spec.rb
index 88932bf009..3a6d61336f 100644
--- a/spec/bundler/bundler/lockfile_parser_spec.rb
+++ b/spec/bundler/bundler/lockfile_parser_spec.rb
@@ -3,7 +3,7 @@
require "bundler/lockfile_parser"
RSpec.describe Bundler::LockfileParser do
- let(:lockfile_contents) { <<~L }
+ let(:lockfile_contents) { strip_whitespace(<<-L) }
GIT
remote: https://github.com/alloy/peiji-san.git
revision: eca485d8dc95f12aaec1a434b49d295c7e91844b
@@ -22,9 +22,6 @@ RSpec.describe Bundler::LockfileParser do
peiji-san!
rake
- CHECKSUMS
- rake (10.3.2) sha256=814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8
-
RUBY VERSION
ruby 2.1.3p242
@@ -36,13 +33,13 @@ RSpec.describe Bundler::LockfileParser do
it "returns the attributes" do
attributes = described_class.sections_in_lockfile(lockfile_contents)
expect(attributes).to contain_exactly(
- "BUNDLED WITH", "CHECKSUMS", "DEPENDENCIES", "GEM", "GIT", "PLATFORMS", "RUBY VERSION"
+ "BUNDLED WITH", "DEPENDENCIES", "GEM", "GIT", "PLATFORMS", "RUBY VERSION"
)
end
end
describe ".unknown_sections_in_lockfile" do
- let(:lockfile_contents) { <<~L }
+ let(:lockfile_contents) { strip_whitespace(<<-L) }
UNKNOWN ATTR
UNKNOWN ATTR 2
@@ -63,7 +60,7 @@ RSpec.describe Bundler::LockfileParser do
it "returns the same as > 1.0" do
expect(subject).to contain_exactly(
- described_class::BUNDLED, described_class::CHECKSUMS, described_class::RUBY, described_class::PLUGIN
+ described_class::BUNDLED, described_class::RUBY, described_class::PLUGIN
)
end
end
@@ -73,7 +70,7 @@ RSpec.describe Bundler::LockfileParser do
it "returns the same as for the release version" do
expect(subject).to contain_exactly(
- described_class::CHECKSUMS, described_class::RUBY, described_class::PLUGIN
+ described_class::RUBY, described_class::PLUGIN
)
end
end
@@ -118,14 +115,6 @@ RSpec.describe Bundler::LockfileParser do
let(:platforms) { [rb] }
let(:bundler_version) { Gem::Version.new("1.12.0.rc.2") }
let(:ruby_version) { "ruby 2.1.3p242" }
- let(:lockfile_path) { Bundler.default_lockfile.relative_path_from(Dir.pwd) }
- let(:rake_sha256_checksum) do
- Bundler::Checksum.from_lock(
- "sha256=814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8",
- "#{lockfile_path}:20:17"
- )
- end
- let(:rake_checksums) { [rake_sha256_checksum] }
shared_examples_for "parsing" do
it "parses correctly" do
@@ -136,9 +125,6 @@ RSpec.describe Bundler::LockfileParser do
expect(subject.platforms).to eq platforms
expect(subject.bundler_version).to eq bundler_version
expect(subject.ruby_version).to eq ruby_version
- rake_spec = specs.last
- checksums = subject.sources.last.checksum_store.to_lock(specs.last)
- expect(checksums).to eq("#{rake_spec.name_tuple.lock_name} #{rake_checksums.map(&:to_lock).sort.join(",")}")
end
end
@@ -163,59 +149,5 @@ RSpec.describe Bundler::LockfileParser do
let(:lockfile_contents) { super().sub("peiji-san!", "peiji-san!\n foo: bar") }
include_examples "parsing"
end
-
- context "when the checksum is urlsafe base64 encoded" do
- let(:lockfile_contents) do
- super().sub(
- "sha256=814828c34f1315d7e7b7e8295184577cc4e969bad6156ac069d02d63f58d82e8",
- "sha256=gUgow08TFdfnt-gpUYRXfMTpabrWFWrAadAtY_WNgug="
- )
- end
- include_examples "parsing"
- end
-
- context "when the checksum is of an unknown algorithm" do
- let(:rake_sha512_checksum) do
- Bundler::Checksum.from_lock(
- "sha512=pVDn9GLmcFkz8vj1ueiVxj5uGKkAyaqYjEX8zG6L5O4BeVg3wANaKbQdpj/B82Nd/MHVszy6polHcyotUdwilQ==",
- "#{lockfile_path}:20:17"
- )
- end
- let(:lockfile_contents) do
- super().sub(
- "sha256=",
- "sha512=pVDn9GLmcFkz8vj1ueiVxj5uGKkAyaqYjEX8zG6L5O4BeVg3wANaKbQdpj/B82Nd/MHVszy6polHcyotUdwilQ==,sha256="
- )
- end
- let(:rake_checksums) { [rake_sha256_checksum, rake_sha512_checksum] }
- include_examples "parsing"
- end
-
- context "when CHECKSUMS has duplicate checksums in the lockfile that don't match" do
- let(:bad_checksum) { "sha256=c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11c0ffee11" }
- let(:lockfile_contents) { super().split(/(?<=CHECKSUMS\n)/m).insert(1, " rake (10.3.2) #{bad_checksum}\n").join }
-
- it "raises a security error" do
- expect { subject }.to raise_error(Bundler::SecurityError) do |e|
- expect(e.message).to match <<~MESSAGE
- Bundler found mismatched checksums. This is a potential security risk.
- rake (10.3.2) #{bad_checksum}
- from the lockfile CHECKSUMS at #{lockfile_path}:20:17
- rake (10.3.2) #{rake_sha256_checksum.to_lock}
- from the lockfile CHECKSUMS at #{lockfile_path}:21:17
-
- To resolve this issue you can either:
- 1. remove the matching checksum in #{lockfile_path}:21:17
- 2. run `bundle install`
- or if you are sure that the new checksum from the lockfile CHECKSUMS at #{lockfile_path}:21:17 is correct:
- 1. remove the matching checksum in #{lockfile_path}:20:17
- 2. run `bundle install`
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- MESSAGE
- end
- end
- end
end
end
diff --git a/spec/bundler/bundler/mirror_spec.rb b/spec/bundler/bundler/mirror_spec.rb
index ba1c6ed413..1eaf1e9a8e 100644
--- a/spec/bundler/bundler/mirror_spec.rb
+++ b/spec/bundler/bundler/mirror_spec.rb
@@ -36,12 +36,12 @@ RSpec.describe Bundler::Settings::Mirror do
it "takes a string for the uri but returns an uri object" do
mirror.uri = "http://localhost:9292"
- expect(mirror.uri).to eq(Gem::URI("http://localhost:9292"))
+ expect(mirror.uri).to eq(Bundler::URI("http://localhost:9292"))
end
it "takes an uri object for the uri" do
- mirror.uri = Gem::URI("http://localhost:9293")
- expect(mirror.uri).to eq(Gem::URI("http://localhost:9293"))
+ mirror.uri = Bundler::URI("http://localhost:9293")
+ expect(mirror.uri).to eq(Bundler::URI("http://localhost:9293"))
end
context "without a uri" do
@@ -145,7 +145,7 @@ RSpec.describe Bundler::Settings::Mirror do
end
RSpec.describe Bundler::Settings::Mirrors do
- let(:localhost_uri) { Gem::URI("http://localhost:9292") }
+ let(:localhost_uri) { Bundler::URI("http://localhost:9292") }
context "with a just created mirror" do
let(:mirrors) do
@@ -260,7 +260,7 @@ RSpec.describe Bundler::Settings::Mirrors do
before { mirrors.parse("mirror.all.fallback_timeout", "true") }
it "returns the source uri, not localhost" do
- expect(mirrors.for("http://whatever.com").uri).to eq(Gem::URI("http://whatever.com/"))
+ expect(mirrors.for("http://whatever.com").uri).to eq(Bundler::URI("http://whatever.com/"))
end
end
end
@@ -270,7 +270,7 @@ RSpec.describe Bundler::Settings::Mirrors do
context "without a fallback timeout" do
it "returns the uri that is not mirrored" do
- expect(mirrors.for("http://whatever.com").uri).to eq(Gem::URI("http://whatever.com/"))
+ expect(mirrors.for("http://whatever.com").uri).to eq(Bundler::URI("http://whatever.com/"))
end
it "returns localhost for rubygems.org" do
@@ -282,11 +282,11 @@ RSpec.describe Bundler::Settings::Mirrors do
before { mirrors.parse("mirror.http://rubygems.org/.fallback_timeout", "true") }
it "returns the uri that is not mirrored" do
- expect(mirrors.for("http://whatever.com").uri).to eq(Gem::URI("http://whatever.com/"))
+ expect(mirrors.for("http://whatever.com").uri).to eq(Bundler::URI("http://whatever.com/"))
end
it "returns rubygems.org for rubygems.org" do
- expect(mirrors.for("http://rubygems.org/").uri).to eq(Gem::URI("http://rubygems.org/"))
+ expect(mirrors.for("http://rubygems.org/").uri).to eq(Bundler::URI("http://rubygems.org/"))
end
end
end
diff --git a/spec/bundler/bundler/plugin/api/source_spec.rb b/spec/bundler/bundler/plugin/api/source_spec.rb
index ae02e08bea..428ceb220a 100644
--- a/spec/bundler/bundler/plugin/api/source_spec.rb
+++ b/spec/bundler/bundler/plugin/api/source_spec.rb
@@ -51,7 +51,7 @@ RSpec.describe Bundler::Plugin::API::Source do
context "to_lock" do
it "returns the string with remote and type" do
- expected = <<~L
+ expected = strip_whitespace <<-L
PLUGIN SOURCE
remote: #{uri}
type: #{type}
@@ -67,7 +67,7 @@ RSpec.describe Bundler::Plugin::API::Source do
end
it "includes them" do
- expected = <<~L
+ expected = strip_whitespace <<-L
PLUGIN SOURCE
remote: #{uri}
type: #{type}
diff --git a/spec/bundler/bundler/plugin/dsl_spec.rb b/spec/bundler/bundler/plugin/dsl_spec.rb
index 235a549735..00e39dca69 100644
--- a/spec/bundler/bundler/plugin/dsl_spec.rb
+++ b/spec/bundler/bundler/plugin/dsl_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe Bundler::Plugin::DSL do
it "adds #source with :type to list and also inferred_plugins list" do
expect(dsl).to receive(:plugin).with("bundler-source-news").once
- dsl.source("some_random_url", type: "news") {}
+ dsl.source("some_random_url", :type => "news") {}
expect(dsl.inferred_plugins).to eq(["bundler-source-news"])
end
@@ -31,8 +31,8 @@ RSpec.describe Bundler::Plugin::DSL do
it "registers a source type plugin only once for multiple declarations" do
expect(dsl).to receive(:plugin).with("bundler-source-news").and_call_original.once
- dsl.source("some_random_url", type: "news") {}
- dsl.source("another_random_url", type: "news") {}
+ dsl.source("some_random_url", :type => "news") {}
+ dsl.source("another_random_url", :type => "news") {}
end
end
end
diff --git a/spec/bundler/bundler/plugin/index_spec.rb b/spec/bundler/bundler/plugin/index_spec.rb
index e1f10a0db7..5a7047459f 100644
--- a/spec/bundler/bundler/plugin/index_spec.rb
+++ b/spec/bundler/bundler/plugin/index_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe Bundler::Plugin::Index do
before do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- gemfile "source 'https://gem.repo1'"
+ gemfile "source \"#{file_uri_for(gem_repo1)}\""
path = lib_path(plugin_name)
index.register_plugin("new-plugin", path.to_s, [path.join("lib").to_s], commands, sources, hooks)
end
diff --git a/spec/bundler/bundler/plugin/installer_spec.rb b/spec/bundler/bundler/plugin/installer_spec.rb
index 8e1879395a..2c50ee5afc 100644
--- a/spec/bundler/bundler/plugin/installer_spec.rb
+++ b/spec/bundler/bundler/plugin/installer_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Bundler::Plugin::Installer do
describe "cli install" do
it "uses Gem.sources when non of the source is provided" do
sources = double(:sources)
+ Bundler.settings # initialize it before we have to touch rubygems.ext_lock
allow(Gem).to receive(:sources) { sources }
allow(installer).to receive(:install_rubygems).
@@ -20,15 +21,15 @@ RSpec.describe Bundler::Plugin::Installer do
allow(installer).to receive(:install_git).
and_return("new-plugin" => spec)
- expect(installer.install(["new-plugin"], git: "https://some.ran/dom")).
+ expect(installer.install(["new-plugin"], :git => "https://some.ran/dom")).
to eq("new-plugin" => spec)
end
it "returns the installed spec after installing local git plugins" do
- allow(installer).to receive(:install_git).
+ allow(installer).to receive(:install_local_git).
and_return("new-plugin" => spec)
- expect(installer.install(["new-plugin"], git: "/phony/path/repo")).
+ expect(installer.install(["new-plugin"], :local_git => "/phony/path/repo")).
to eq("new-plugin" => spec)
end
@@ -36,7 +37,7 @@ RSpec.describe Bundler::Plugin::Installer do
allow(installer).to receive(:install_rubygems).
and_return("new-plugin" => spec)
- expect(installer.install(["new-plugin"], source: "https://some.ran/dom")).
+ expect(installer.install(["new-plugin"], :source => "https://some.ran/dom")).
to eq("new-plugin" => spec)
end
end
@@ -51,13 +52,13 @@ RSpec.describe Bundler::Plugin::Installer do
context "git plugins" do
before do
- build_git "ga-plugin", path: lib_path("ga-plugin") do |s|
+ build_git "ga-plugin", :path => lib_path("ga-plugin") do |s|
s.write "plugins.rb"
end
end
let(:result) do
- installer.install(["ga-plugin"], git: lib_path("ga-plugin").to_s)
+ installer.install(["ga-plugin"], :git => file_uri_for(lib_path("ga-plugin")))
end
it "returns the installed spec after installing" do
@@ -74,13 +75,13 @@ RSpec.describe Bundler::Plugin::Installer do
context "local git plugins" do
before do
- build_git "ga-plugin", path: lib_path("ga-plugin") do |s|
+ build_git "ga-plugin", :path => lib_path("ga-plugin") do |s|
s.write "plugins.rb"
end
end
let(:result) do
- installer.install(["ga-plugin"], git: lib_path("ga-plugin").to_s)
+ installer.install(["ga-plugin"], :local_git => lib_path("ga-plugin").to_s)
end
it "returns the installed spec after installing" do
@@ -97,7 +98,7 @@ RSpec.describe Bundler::Plugin::Installer do
context "rubygems plugins" do
let(:result) do
- installer.install(["re-plugin"], source: file_uri_for(gem_repo2))
+ installer.install(["re-plugin"], :source => file_uri_for(gem_repo2))
end
it "returns the installed spec after installing " do
@@ -112,7 +113,7 @@ RSpec.describe Bundler::Plugin::Installer do
context "multiple plugins" do
let(:result) do
- installer.install(["re-plugin", "ma-plugin"], source: file_uri_for(gem_repo2))
+ installer.install(["re-plugin", "ma-plugin"], :source => file_uri_for(gem_repo2))
end
it "returns the installed spec after installing " do
diff --git a/spec/bundler/bundler/plugin_spec.rb b/spec/bundler/bundler/plugin_spec.rb
index 3ac7b251a3..d28479cf31 100644
--- a/spec/bundler/bundler/plugin_spec.rb
+++ b/spec/bundler/bundler/plugin_spec.rb
@@ -9,11 +9,11 @@ RSpec.describe Bundler::Plugin do
let(:spec2) { double(:spec2) }
before do
- build_lib "new-plugin", path: lib_path("new-plugin") do |s|
+ build_lib "new-plugin", :path => lib_path("new-plugin") do |s|
s.write "plugins.rb"
end
- build_lib "another-plugin", path: lib_path("another-plugin") do |s|
+ build_lib "another-plugin", :path => lib_path("another-plugin") do |s|
s.write "plugins.rb"
end
@@ -225,7 +225,7 @@ RSpec.describe Bundler::Plugin do
end
end
- describe "#from_lock" do
+ describe "#source_from_lock" do
it "returns instance of registered class initialized with locked opts" do
opts = { "type" => "l_source", "remote" => "xyz", "other" => "random" }
allow(index).to receive(:source_plugin).with("l_source") { "plugin_name" }
@@ -236,7 +236,7 @@ RSpec.describe Bundler::Plugin do
expect(SClass).to receive(:new).
with(hash_including("type" => "l_source", "uri" => "xyz", "other" => "random")) { s_instance }
- expect(subject.from_lock(opts)).to be(s_instance)
+ expect(subject.source_from_lock(opts)).to be(s_instance)
end
end
@@ -247,7 +247,7 @@ RSpec.describe Bundler::Plugin do
end
it "returns plugin dir in app .bundle path" do
- expect(subject.root).to eq(bundled_app(".bundle/plugin"))
+ expect(subject.root).to eq(bundled_app.join(".bundle/plugin"))
end
end
@@ -257,7 +257,7 @@ RSpec.describe Bundler::Plugin do
end
it "returns plugin dir in global bundle path" do
- expect(subject.root).to eq(home(".bundle/plugin"))
+ expect(subject.root).to eq(home.join(".bundle/plugin"))
end
end
end
@@ -275,7 +275,7 @@ RSpec.describe Bundler::Plugin do
describe "#hook" do
before do
path = lib_path("foo-plugin")
- build_lib "foo-plugin", path: path do |s|
+ build_lib "foo-plugin", :path => path do |s|
s.write "plugins.rb", code
end
diff --git a/spec/bundler/bundler/remote_specification_spec.rb b/spec/bundler/bundler/remote_specification_spec.rb
index f35b231d58..921a47a2d3 100644
--- a/spec/bundler/bundler/remote_specification_spec.rb
+++ b/spec/bundler/bundler/remote_specification_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Bundler::RemoteSpecification do
end
describe "#fetch_platform" do
- let(:remote_spec) { double(:remote_spec, platform: "jruby") }
+ let(:remote_spec) { double(:remote_spec, :platform => "jruby") }
before { allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec) }
@@ -113,7 +113,7 @@ RSpec.describe Bundler::RemoteSpecification do
context "comparing a non sortable object" do
let(:other) { Object.new }
- let(:remote_spec) { double(:remote_spec, platform: "jruby") }
+ let(:remote_spec) { double(:remote_spec, :platform => "jruby") }
before do
allow(spec_fetcher).to receive(:fetch_spec).and_return(remote_spec)
@@ -127,8 +127,8 @@ RSpec.describe Bundler::RemoteSpecification do
end
describe "#__swap__" do
- let(:spec) { double(:spec, dependencies: []) }
- let(:new_spec) { double(:new_spec, dependencies: [], runtime_dependencies: []) }
+ let(:spec) { double(:spec, :dependencies => []) }
+ let(:new_spec) { double(:new_spec, :dependencies => [], :runtime_dependencies => []) }
before { subject.instance_variable_set(:@_remote_specification, spec) }
@@ -157,7 +157,7 @@ RSpec.describe Bundler::RemoteSpecification do
describe "method missing" do
context "and is present in Gem::Specification" do
- let(:remote_spec) { double(:remote_spec, authors: "abcd") }
+ let(:remote_spec) { double(:remote_spec, :authors => "abcd") }
before do
allow(subject).to receive(:_remote_specification).and_return(remote_spec)
@@ -172,7 +172,7 @@ RSpec.describe Bundler::RemoteSpecification do
describe "respond to missing?" do
context "and is present in Gem::Specification" do
- let(:remote_spec) { double(:remote_spec, authors: "abcd") }
+ let(:remote_spec) { double(:remote_spec, :authors => "abcd") }
before do
allow(subject).to receive(:_remote_specification).and_return(remote_spec)
diff --git a/spec/bundler/bundler/resolver/candidate_spec.rb b/spec/bundler/bundler/resolver/candidate_spec.rb
index aefad3316e..cd52c867c4 100644
--- a/spec/bundler/bundler/resolver/candidate_spec.rb
+++ b/spec/bundler/bundler/resolver/candidate_spec.rb
@@ -2,19 +2,20 @@
RSpec.describe Bundler::Resolver::Candidate do
it "compares fine" do
- version1 = described_class.new("1.12.5", priority: -1)
- version2 = described_class.new("1.12.5", priority: 1)
+ version1 = described_class.new("1.12.5", :specs => [Gem::Specification.new("foo", "1.12.5") {|s| s.platform = Gem::Platform::RUBY }])
+ version2 = described_class.new("1.12.5") # passing no specs creates a platform specific candidate, so sorts higher
- expect(version2 > version1).to be true
+ expect(version2 >= version1).to be true
- version1 = described_class.new("1.12.5")
- version2 = described_class.new("1.12.5")
+ expect(version1.generic! == version2.generic!).to be true
+ expect(version1.platform_specific! == version2.platform_specific!).to be true
- expect(version2 == version1).to be true
+ expect(version1.platform_specific! >= version2.generic!).to be true
+ expect(version2.platform_specific! >= version1.generic!).to be true
- version1 = described_class.new("1.12.5", priority: 1)
- version2 = described_class.new("1.12.5", priority: -1)
+ version1 = described_class.new("1.12.5", :specs => [Gem::Specification.new("foo", "1.12.5") {|s| s.platform = Gem::Platform::RUBY }])
+ version2 = described_class.new("1.12.5", :specs => [Gem::Specification.new("foo", "1.12.5") {|s| s.platform = Gem::Platform::X64_LINUX }])
- expect(version2 < version1).to be true
+ expect(version2 >= version1).to be true
end
end
diff --git a/spec/bundler/bundler/retry_spec.rb b/spec/bundler/bundler/retry_spec.rb
index ffbc078074..b893580d72 100644
--- a/spec/bundler/bundler/retry_spec.rb
+++ b/spec/bundler/bundler/retry_spec.rb
@@ -68,7 +68,7 @@ RSpec.describe Bundler::Retry do
it "print error message with newlines" do
allow(Bundler.ui).to receive(:debug?).and_return(false)
expect(Bundler.ui).to receive(:info).with("").twice
- expect(Bundler.ui).to receive(:warn).with(failure_message, true)
+ expect(Bundler.ui).to receive(:warn).with(failure_message, false)
expect do
Bundler::Retry.new("test", [], 1).attempt do
diff --git a/spec/bundler/bundler/ruby_dsl_spec.rb b/spec/bundler/bundler/ruby_dsl_spec.rb
index c5ebbdf4db..0ba55e949f 100644
--- a/spec/bundler/bundler/ruby_dsl_spec.rb
+++ b/spec/bundler/bundler/ruby_dsl_spec.rb
@@ -7,7 +7,6 @@ RSpec.describe Bundler::RubyDsl do
include Bundler::RubyDsl
attr_reader :ruby_version
- attr_accessor :gemfile
end
let(:dsl) { MockDSL.new }
@@ -18,18 +17,15 @@ RSpec.describe Bundler::RubyDsl do
let(:engine_version) { "9000" }
let(:patchlevel) { "100" }
let(:options) do
- { patchlevel: patchlevel,
- engine: engine,
- engine_version: engine_version }
+ { :patchlevel => patchlevel,
+ :engine => engine,
+ :engine_version => engine_version }
end
- let(:project_root) { Pathname.new("/path/to/project") }
- let(:gemfile) { project_root.join("Gemfile") }
- before { allow(Bundler).to receive(:root).and_return(project_root) }
let(:invoke) do
proc do
args = []
- args << ruby_version_arg if ruby_version_arg
+ args << Array(ruby_version_arg) if ruby_version_arg
args << options
dsl.ruby(*args)
@@ -37,7 +33,6 @@ RSpec.describe Bundler::RubyDsl do
end
subject do
- dsl.gemfile = gemfile
invoke.call
dsl.ruby_version
end
@@ -68,19 +63,10 @@ RSpec.describe Bundler::RubyDsl do
it_behaves_like "it stores the ruby version"
end
- context "with a preview version" do
- let(:ruby_version) { "3.3.0-preview2" }
-
- it "stores the version" do
- expect(subject.versions).to eq(Array("3.3.0.preview2"))
- expect(subject.gem_version.version).to eq("3.3.0.preview2")
- end
- end
-
context "with two requirements in the same string" do
let(:ruby_version) { ">= 2.0.0, < 3.0" }
it "raises an error" do
- expect { subject }.to raise_error(Bundler::InvalidArgumentError)
+ expect { subject }.to raise_error(ArgumentError)
end
end
@@ -111,90 +97,22 @@ RSpec.describe Bundler::RubyDsl do
end
context "with a file option" do
- let(:file) { ".ruby-version" }
- let(:ruby_version_file_path) { gemfile.dirname.join(file) }
- let(:options) do
- { file: file,
- patchlevel: patchlevel,
- engine: engine,
- engine_version: engine_version }
- end
+ let(:options) { { :file => "foo" } }
+ let(:version) { "3.2.2" }
+ let(:ruby_version) { "3.2.2" }
let(:ruby_version_arg) { nil }
- let(:file_content) { "#{version}\n" }
-
- before do
- allow(Bundler).to receive(:read_file) do |path|
- raise Errno::ENOENT, <<~ERROR unless path == ruby_version_file_path
- #{file} not found in specs:
- expected: #{ruby_version_file_path}
- received: #{path}
- ERROR
- file_content
- end
- end
+ let(:engine_version) { version }
+ let(:patchlevel) { nil }
+ let(:engine) { "ruby" }
+ before { allow(Bundler).to receive(:read_file).with("foo").and_return("#{version}\n") }
it_behaves_like "it stores the ruby version"
- context "with the Gemfile ruby file: path is relative to the Gemfile in a subdir" do
- let(:gemfile) { project_root.join("subdir", "Gemfile") }
- let(:file) { "../.ruby-version" }
- let(:ruby_version_file_path) { gemfile.dirname.join(file) }
-
- it_behaves_like "it stores the ruby version"
- end
-
- context "with bundler root in a subdir of the project" do
- let(:project_root) { Pathname.new("/path/to/project/subdir") }
- let(:gemfile) { project_root.parent.join("Gemfile") }
-
- it_behaves_like "it stores the ruby version"
- end
-
- context "with the ruby- prefix in the file" do
- let(:file_content) { "ruby-#{version}\n" }
-
- it_behaves_like "it stores the ruby version"
- end
-
context "and a version" do
- let(:ruby_version_arg) { version }
-
- it "raises an error" do
- expect { subject }.to raise_error(Bundler::GemfileError, "Do not pass version argument when using :file option")
- end
- end
-
- context "with a @gemset" do
- let(:file_content) { "ruby-#{version}@gemset\n" }
+ let(:ruby_version_arg) { "2.0.0" }
it "raises an error" do
- expect { subject }.to raise_error(Bundler::InvalidArgumentError, "2.0.0@gemset is not a valid requirement on the Ruby version")
- end
- end
-
- context "with a .tool-versions file format" do
- let(:file) { ".tool-versions" }
- let(:ruby_version_arg) { nil }
- let(:file_content) do
- <<~TOOLS
- nodejs 18.16.0
- ruby #{version} # This is a comment
- pnpm 8.6.12
- TOOLS
- end
-
- it_behaves_like "it stores the ruby version"
-
- context "with extra spaces and a very cozy comment" do
- let(:file_content) do
- <<~TOOLS
- nodejs 18.16.0
- ruby #{version}# This is a cozy comment
- pnpm 8.6.12
- TOOLS
- end
-
- it_behaves_like "it stores the ruby version"
+ expect { subject }.to raise_error(Bundler::GemfileError, "Cannot specify version when using the file option")
end
end
end
diff --git a/spec/bundler/bundler/rubygems_integration_spec.rb b/spec/bundler/bundler/rubygems_integration_spec.rb
index 81859d10f2..182aa3646a 100644
--- a/spec/bundler/bundler/rubygems_integration_spec.rb
+++ b/spec/bundler/bundler/rubygems_integration_spec.rb
@@ -1,6 +1,10 @@
# frozen_string_literal: true
RSpec.describe Bundler::RubygemsIntegration do
+ it "uses the same chdir lock as rubygems" do
+ expect(Bundler.rubygems.ext_lock).to eq(Gem::Ext::Builder::CHDIR_MONITOR)
+ end
+
context "#validate" do
let(:spec) do
Gem::Specification.new do |s|
@@ -11,14 +15,14 @@ RSpec.describe Bundler::RubygemsIntegration do
end
subject { Bundler.rubygems.validate(spec) }
- it "validates for resolution" do
- expect(spec).to receive(:validate_for_resolution)
+ it "validates with packaging mode disabled" do
+ expect(spec).to receive(:validate).with(false)
subject
end
context "with an invalid spec" do
before do
- expect(spec).to receive(:validate_for_resolution).
+ expect(spec).to receive(:validate).with(false).
and_raise(Gem::InvalidSpecificationException.new("TODO is not an author"))
end
@@ -32,7 +36,7 @@ RSpec.describe Bundler::RubygemsIntegration do
describe "#download_gem" do
let(:bundler_retry) { double(Bundler::Retry) }
- let(:uri) { Gem::URI.parse("https://foo.bar") }
+ let(:uri) { Bundler::URI.parse("https://foo.bar") }
let(:cache_dir) { "#{Gem.path.first}/cache" }
let(:spec) do
spec = Gem::Specification.new("Foo", Gem::Version.new("2.5.2"))
@@ -42,12 +46,14 @@ RSpec.describe Bundler::RubygemsIntegration do
let(:fetcher) { double("gem_remote_fetcher") }
it "successfully downloads gem with retries" do
+ expect(Bundler.rubygems).to receive(:gem_remote_fetcher).and_return(fetcher)
+ expect(fetcher).to receive(:headers=).with({ "X-Gemfile-Source" => "https://foo.bar" })
expect(Bundler::Retry).to receive(:new).with("download gem from #{uri}/").
and_return(bundler_retry)
expect(bundler_retry).to receive(:attempts).and_yield
expect(fetcher).to receive(:cache_update_path)
- Bundler.rubygems.download_gem(spec, uri, cache_dir, fetcher)
+ Bundler.rubygems.download_gem(spec, uri, cache_dir)
end
end
@@ -58,35 +64,40 @@ RSpec.describe Bundler::RubygemsIntegration do
let(:prerelease_specs_response) { Marshal.dump(["prerelease_specs"]) }
context "when a rubygems source mirror is set" do
- let(:orig_uri) { Gem::URI("http://zombo.com") }
- let(:remote_with_mirror) { double("remote", uri: uri, original_uri: orig_uri) }
+ let(:orig_uri) { Bundler::URI("http://zombo.com") }
+ let(:remote_with_mirror) { double("remote", :uri => uri, :original_uri => orig_uri) }
it "sets the 'X-Gemfile-Source' header containing the original source" do
+ expect(Bundler.rubygems).to receive(:gem_remote_fetcher).twice.and_return(fetcher)
+ expect(fetcher).to receive(:headers=).with({ "X-Gemfile-Source" => "http://zombo.com" }).twice
expect(fetcher).to receive(:fetch_path).with(uri + "specs.4.8.gz").and_return(specs_response)
expect(fetcher).to receive(:fetch_path).with(uri + "prerelease_specs.4.8.gz").and_return(prerelease_specs_response)
- result = Bundler.rubygems.fetch_all_remote_specs(remote_with_mirror, fetcher)
+ result = Bundler.rubygems.fetch_all_remote_specs(remote_with_mirror)
expect(result).to eq(%w[specs prerelease_specs])
end
end
context "when there is no rubygems source mirror set" do
- let(:remote_no_mirror) { double("remote", uri: uri, original_uri: nil) }
+ let(:remote_no_mirror) { double("remote", :uri => uri, :original_uri => nil) }
it "does not set the 'X-Gemfile-Source' header" do
+ expect(Bundler.rubygems).to receive(:gem_remote_fetcher).twice.and_return(fetcher)
+ expect(fetcher).to_not receive(:headers=)
expect(fetcher).to receive(:fetch_path).with(uri + "specs.4.8.gz").and_return(specs_response)
expect(fetcher).to receive(:fetch_path).with(uri + "prerelease_specs.4.8.gz").and_return(prerelease_specs_response)
- result = Bundler.rubygems.fetch_all_remote_specs(remote_no_mirror, fetcher)
+ result = Bundler.rubygems.fetch_all_remote_specs(remote_no_mirror)
expect(result).to eq(%w[specs prerelease_specs])
end
end
context "when loading an unexpected class" do
- let(:remote_no_mirror) { double("remote", uri: uri, original_uri: nil) }
+ let(:remote_no_mirror) { double("remote", :uri => uri, :original_uri => nil) }
let(:unexpected_specs_response) { Marshal.dump(3) }
it "raises a MarshalError error" do
+ expect(Bundler.rubygems).to receive(:gem_remote_fetcher).once.and_return(fetcher)
expect(fetcher).to receive(:fetch_path).with(uri + "specs.4.8.gz").and_return(unexpected_specs_response)
- expect { Bundler.rubygems.fetch_all_remote_specs(remote_no_mirror, fetcher) }.to raise_error(Bundler::MarshalError, /unexpected class/i)
+ expect { Bundler.rubygems.fetch_all_remote_specs(remote_no_mirror) }.to raise_error(Bundler::MarshalError, /unexpected class/i)
end
end
end
diff --git a/spec/bundler/bundler/settings/validator_spec.rb b/spec/bundler/bundler/settings/validator_spec.rb
index b252ba59a0..e4ffd89435 100644
--- a/spec/bundler/bundler/settings/validator_spec.rb
+++ b/spec/bundler/bundler/settings/validator_spec.rb
@@ -44,14 +44,14 @@ RSpec.describe Bundler::Settings::Validator do
validate!("without", "b:c", "BUNDLE_WITH" => "a")
end.not_to raise_error
- expect { validate!("with", "b:c", "BUNDLE_WITHOUT" => "c:d") }.to raise_error Bundler::InvalidOption, <<~EOS.strip
+ expect { validate!("with", "b:c", "BUNDLE_WITHOUT" => "c:d") }.to raise_error Bundler::InvalidOption, strip_whitespace(<<-EOS).strip
Setting `with` to "b:c" failed:
- a group cannot be in both `with` & `without` simultaneously
- `without` is current set to [:c, :d]
- the `c` groups conflict
EOS
- expect { validate!("without", "b:c", "BUNDLE_WITH" => "c:d") }.to raise_error Bundler::InvalidOption, <<~EOS.strip
+ expect { validate!("without", "b:c", "BUNDLE_WITH" => "c:d") }.to raise_error Bundler::InvalidOption, strip_whitespace(<<-EOS).strip
Setting `without` to "b:c" failed:
- a group cannot be in both `with` & `without` simultaneously
- `with` is current set to [:c, :d]
@@ -74,7 +74,7 @@ RSpec.describe Bundler::Settings::Validator do
describe "#fail!" do
it "raises with a helpful message" do
- expect { subject.fail!("key", "value", "reason1", "reason2") }.to raise_error Bundler::InvalidOption, <<~EOS.strip
+ expect { subject.fail!("key", "value", "reason1", "reason2") }.to raise_error Bundler::InvalidOption, strip_whitespace(<<-EOS).strip
Setting `key` to "value" failed:
- rule description
- reason1
diff --git a/spec/bundler/bundler/settings_spec.rb b/spec/bundler/bundler/settings_spec.rb
index b7db548cf9..4636993d9f 100644
--- a/spec/bundler/bundler/settings_spec.rb
+++ b/spec/bundler/bundler/settings_spec.rb
@@ -6,18 +6,12 @@ RSpec.describe Bundler::Settings do
subject(:settings) { described_class.new(bundled_app) }
describe "#set_local" do
- context "root is nil" do
+ context "when the local config file is not found" do
subject(:settings) { described_class.new(nil) }
- before do
- allow(Pathname).to receive(:new).and_call_original
- allow(Pathname).to receive(:new).with(".bundle").and_return home(".bundle")
- end
-
- it "works" do
- subject.set_local("foo", "bar")
-
- expect(subject["foo"]).to eq("bar")
+ it "raises a GemfileNotFound error with explanation" do
+ expect { subject.set_local("foo", "bar") }.
+ to raise_error(Bundler::GemfileNotFound, "Could not locate Gemfile")
end
end
end
@@ -137,7 +131,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
Bundler.settings.set_command_option :no_install, true
- Bundler.settings.temporary(no_install: false) do
+ Bundler.settings.temporary(:no_install => false) do
expect(Bundler.settings[:no_install]).to eq false
end
@@ -153,12 +147,12 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
context "when called without a block" do
it "leaves the setting changed" do
- Bundler.settings.temporary(foo: :random)
+ Bundler.settings.temporary(:foo => :random)
expect(Bundler.settings[:foo]).to eq "random"
end
it "returns nil" do
- expect(Bundler.settings.temporary(foo: :bar)).to be_nil
+ expect(Bundler.settings.temporary(:foo => :bar)).to be_nil
end
end
end
@@ -185,7 +179,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
describe "#mirror_for" do
- let(:uri) { Gem::URI("https://rubygems.org/") }
+ let(:uri) { Bundler::URI("https://rubygems.org/") }
context "with no configured mirror" do
it "returns the original URI" do
@@ -198,7 +192,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
context "with a configured mirror" do
- let(:mirror_uri) { Gem::URI("https://rubygems-mirror.org/") }
+ let(:mirror_uri) { Bundler::URI("https://rubygems-mirror.org/") }
before { settings.set_local "mirror.https://rubygems.org/", mirror_uri.to_s }
@@ -219,7 +213,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
context "with a file URI" do
- let(:mirror_uri) { Gem::URI("file:/foo/BAR/baz/qUx/") }
+ let(:mirror_uri) { Bundler::URI("file:/foo/BAR/baz/qUx/") }
it "returns the mirror URI" do
expect(settings.mirror_for(uri)).to eq(mirror_uri)
@@ -237,7 +231,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
end
describe "#credentials_for" do
- let(:uri) { Gem::URI("https://gemserver.example.org/") }
+ let(:uri) { Bundler::URI("https://gemserver.example.org/") }
let(:credentials) { "username:password" }
context "with no configured credentials" do
@@ -297,7 +291,7 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
it "reads older keys without trailing slashes" do
settings.set_local "mirror.https://rubygems.org", "http://rubygems-mirror.org"
expect(settings.mirror_for("https://rubygems.org/")).to eq(
- Gem::URI("http://rubygems-mirror.org/")
+ Bundler::URI("http://rubygems-mirror.org/")
)
end
@@ -316,8 +310,8 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
let(:settings) { described_class.new(bundled_app(".bundle")) }
it "converts older keys without double underscore" do
- config("BUNDLE_MY__PERSONAL.MYRACK" => "~/Work/git/myrack")
- expect(settings["my.personal.myrack"]).to eq("~/Work/git/myrack")
+ config("BUNDLE_MY__PERSONAL.RACK" => "~/Work/git/rack")
+ expect(settings["my.personal.rack"]).to eq("~/Work/git/rack")
end
it "converts older keys without trailing slashes and double underscore" do
@@ -325,15 +319,6 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
expect(settings["mirror.https://rubygems.org/"]).to eq("http://rubygems-mirror.org")
end
- it "ignores commented out keys" do
- create_file bundled_app(".bundle/config"), <<~C
- # BUNDLE_MY-PERSONAL-SERVER__ORG: my-personal-server.org
- C
-
- expect(Bundler.ui).not_to receive(:warn)
- expect(settings.all).to be_empty
- end
-
it "converts older keys with dashes" do
config("BUNDLE_MY-PERSONAL-SERVER__ORG" => "my-personal-server.org")
expect(Bundler.ui).to receive(:warn).with(
diff --git a/spec/bundler/bundler/shared_helpers_spec.rb b/spec/bundler/bundler/shared_helpers_spec.rb
index 918f73b337..3c6536c4eb 100644
--- a/spec/bundler/bundler/shared_helpers_spec.rb
+++ b/spec/bundler/bundler/shared_helpers_spec.rb
@@ -1,8 +1,12 @@
# frozen_string_literal: true
RSpec.describe Bundler::SharedHelpers do
+ let(:ext_lock_double) { double(:ext_lock) }
+
before do
pwd_stub
+ allow(Bundler.rubygems).to receive(:ext_lock).and_return(ext_lock_double)
+ allow(ext_lock_double).to receive(:synchronize) {|&block| block.call }
end
let(:pwd_stub) { allow(subject).to receive(:pwd).and_return(bundled_app) }
@@ -238,12 +242,14 @@ RSpec.describe Bundler::SharedHelpers do
shared_examples_for "ENV['RUBYOPT'] gets set correctly" do
it "ensures -rbundler/setup is at the beginning of ENV['RUBYOPT']" do
subject.set_bundle_environment
- expect(ENV["RUBYOPT"].split(" ")).to start_with("-r#{install_path}/bundler/setup")
+ expect(ENV["RUBYOPT"].split(" ")).to start_with("-r#{source_lib_dir}/bundler/setup")
end
end
shared_examples_for "ENV['BUNDLER_SETUP'] gets set correctly" do
it "ensures bundler/setup is set in ENV['BUNDLER_SETUP']" do
+ skip "Does not play well with DidYouMean being a bundled gem instead of a default gem in Ruby 2.6" if RUBY_VERSION < "2.7"
+
subject.set_bundle_environment
expect(ENV["BUNDLER_SETUP"]).to eq("#{source_lib_dir}/bundler/setup")
end
@@ -361,41 +367,20 @@ RSpec.describe Bundler::SharedHelpers do
end
end
- context "when bundler install path is standard" do
- let(:install_path) { source_lib_dir }
+ context "ENV['RUBYOPT'] does not exist" do
+ before { ENV.delete("RUBYOPT") }
- context "ENV['RUBYOPT'] does not exist" do
- before { ENV.delete("RUBYOPT") }
-
- it_behaves_like "ENV['RUBYOPT'] gets set correctly"
- end
-
- context "ENV['RUBYOPT'] exists without -rbundler/setup" do
- before { ENV["RUBYOPT"] = "-I/some_app_path/lib" }
-
- it_behaves_like "ENV['RUBYOPT'] gets set correctly"
- end
-
- context "ENV['RUBYOPT'] exists and contains -rbundler/setup" do
- before { ENV["RUBYOPT"] = "-rbundler/setup" }
-
- it_behaves_like "ENV['RUBYOPT'] gets set correctly"
- end
+ it_behaves_like "ENV['RUBYOPT'] gets set correctly"
end
- context "when bundler install path contains special characters" do
- let(:install_path) { "/opt/ruby3.3.0-preview2/lib/ruby/3.3.0+0" }
+ context "ENV['RUBYOPT'] exists without -rbundler/setup" do
+ before { ENV["RUBYOPT"] = "-I/some_app_path/lib" }
- before do
- ENV["RUBYOPT"] = "-r#{install_path}/bundler/setup"
- allow(File).to receive(:expand_path).and_return("#{install_path}/bundler/setup")
- allow(Gem).to receive(:bin_path).and_return("#{install_path}/bundler/setup")
- end
+ it_behaves_like "ENV['RUBYOPT'] gets set correctly"
+ end
- it "ensures -rbundler/setup is not duplicated" do
- subject.set_bundle_environment
- expect(ENV["RUBYOPT"].split(" ").grep(%r{-r.*/bundler/setup}).length).to eq(1)
- end
+ context "ENV['RUBYOPT'] exists and contains -rbundler/setup" do
+ before { ENV["RUBYOPT"] = "-rbundler/setup" }
it_behaves_like "ENV['RUBYOPT'] gets set correctly"
end
@@ -518,34 +503,4 @@ RSpec.describe Bundler::SharedHelpers do
end
end
end
-
- describe "#major_deprecation" do
- before { allow(Bundler).to receive(:bundler_major_version).and_return(37) }
- before { allow(Bundler.ui).to receive(:warn) }
-
- it "prints and raises nothing below the deprecated major version" do
- subject.major_deprecation(38, "Message")
- subject.major_deprecation(39, "Message", removed_message: "Removal", print_caller_location: true)
- expect(Bundler.ui).not_to have_received(:warn)
- end
-
- it "prints but does not raise _at_ the deprecated major version" do
- subject.major_deprecation(37, "Message")
- subject.major_deprecation(37, "Message", removed_message: "Removal")
- expect(Bundler.ui).to have_received(:warn).with("[DEPRECATED] Message").twice
-
- subject.major_deprecation(37, "Message", print_caller_location: true)
- expect(Bundler.ui).to have_received(:warn).
- with(a_string_matching(/^\[DEPRECATED\] Message \(called at .*:\d+\)$/))
- end
-
- it "raises the appropriate errors when _past_ the deprecated major version" do
- expect { subject.major_deprecation(36, "Message") }.
- to raise_error(Bundler::DeprecatedError, "[REMOVED] Message")
- expect { subject.major_deprecation(36, "Message", removed_message: "Removal") }.
- to raise_error(Bundler::DeprecatedError, "[REMOVED] Removal")
- expect { subject.major_deprecation(35, "Message", removed_message: "Removal", print_caller_location: true) }.
- to raise_error(Bundler::DeprecatedError, /^\[REMOVED\] Removal \(called at .*:\d+\)$/)
- end
- end
end
diff --git a/spec/bundler/bundler/source/git/git_proxy_spec.rb b/spec/bundler/bundler/source/git/git_proxy_spec.rb
index f7c883eed4..c79dd8ff71 100644
--- a/spec/bundler/bundler/source/git/git_proxy_spec.rb
+++ b/spec/bundler/bundler/source/git/git_proxy_spec.rb
@@ -3,84 +3,34 @@
RSpec.describe Bundler::Source::Git::GitProxy do
let(:path) { Pathname("path") }
let(:uri) { "https://github.com/rubygems/rubygems.git" }
- let(:ref) { nil }
- let(:branch) { nil }
- let(:tag) { nil }
- let(:options) { { "ref" => ref, "branch" => branch, "tag" => tag }.compact }
+ let(:ref) { "HEAD" }
let(:revision) { nil }
let(:git_source) { nil }
- let(:clone_result) { double(Process::Status, success?: true) }
+ let(:clone_result) { double(Process::Status, :success? => true) }
let(:base_clone_args) { ["clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--depth", "1", "--single-branch"] }
- subject(:git_proxy) { described_class.new(path, uri, options, revision, git_source) }
-
- context "with explicit ref" do
- context "with branch only" do
- let(:branch) { "main" }
- it "sets explicit ref to branch" do
- expect(git_proxy.explicit_ref).to eq(branch)
- end
- end
-
- context "with ref only" do
- let(:ref) { "HEAD" }
- it "sets explicit ref to ref" do
- expect(git_proxy.explicit_ref).to eq(ref)
- end
- end
-
- context "with tag only" do
- let(:tag) { "v1.0" }
- it "sets explicit ref to ref" do
- expect(git_proxy.explicit_ref).to eq(tag)
- end
- end
-
- context "with tag and branch" do
- let(:tag) { "v1.0" }
- let(:branch) { "main" }
- it "raises error" do
- expect { git_proxy }.to raise_error(Bundler::Source::Git::AmbiguousGitReference)
- end
- end
-
- context "with tag and ref" do
- let(:tag) { "v1.0" }
- let(:ref) { "HEAD" }
- it "raises error" do
- expect { git_proxy }.to raise_error(Bundler::Source::Git::AmbiguousGitReference)
- end
- end
-
- context "with branch and ref" do
- let(:branch) { "main" }
- let(:ref) { "HEAD" }
- it "honors ref over branch" do
- expect(git_proxy.explicit_ref).to eq(ref)
- end
- end
- end
+ subject { described_class.new(path, uri, ref, revision, git_source) }
context "with configured credentials" do
it "adds username and password to URI" do
Bundler.settings.temporary(uri => "u:p") do
- allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
- expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s], nil).and_return(["", "", clone_result])
+ allow(subject).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(subject).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
end
it "adds username and password to URI for host" do
Bundler.settings.temporary("github.com" => "u:p") do
- allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
- expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s], nil).and_return(["", "", clone_result])
+ allow(subject).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(subject).to receive(:capture).with([*base_clone_args, "--", "https://u:p@github.com/rubygems/rubygems.git", path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
end
it "does not add username and password to mismatched URI" do
Bundler.settings.temporary("https://u:p@github.com/rubygems/rubygems-mismatch.git" => "u:p") do
- allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
- expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", uri, path.to_s], nil).and_return(["", "", clone_result])
+ allow(subject).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(subject).to receive(:capture).with([*base_clone_args, "--", uri, path.to_s], nil).and_return(["", "", clone_result])
subject.checkout
end
end
@@ -88,10 +38,10 @@ RSpec.describe Bundler::Source::Git::GitProxy do
it "keeps original userinfo" do
Bundler.settings.temporary("github.com" => "u:p") do
original = "https://orig:info@github.com/rubygems/rubygems.git"
- git_proxy = described_class.new(Pathname("path"), original, options)
- allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
- expect(git_proxy).to receive(:capture).with([*base_clone_args, "--", original, path.to_s], nil).and_return(["", "", clone_result])
- git_proxy.checkout
+ subject = described_class.new(Pathname("path"), original, "HEAD")
+ allow(subject).to receive(:git_local).with("--version").and_return("git version 2.14.0")
+ expect(subject).to receive(:capture).with([*base_clone_args, "--", original, path.to_s], nil).and_return(["", "", clone_result])
+ subject.checkout
end
end
end
@@ -99,46 +49,46 @@ RSpec.describe Bundler::Source::Git::GitProxy do
describe "#version" do
context "with a normal version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(subject).to receive(:git_local).with("--version").
and_return("git version 1.2.3")
end
it "returns the git version number" do
- expect(git_proxy.version).to eq("1.2.3")
+ expect(subject.version).to eq("1.2.3")
end
it "does not raise an error when passed into Gem::Version.create" do
- expect { Gem::Version.create git_proxy.version }.not_to raise_error
+ expect { Gem::Version.create subject.version }.not_to raise_error
end
end
context "with a OSX version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(subject).to receive(:git_local).with("--version").
and_return("git version 1.2.3 (Apple Git-BS)")
end
it "strips out OSX specific additions in the version string" do
- expect(git_proxy.version).to eq("1.2.3")
+ expect(subject.version).to eq("1.2.3")
end
it "does not raise an error when passed into Gem::Version.create" do
- expect { Gem::Version.create git_proxy.version }.not_to raise_error
+ expect { Gem::Version.create subject.version }.not_to raise_error
end
end
context "with a msysgit version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(subject).to receive(:git_local).with("--version").
and_return("git version 1.2.3.msysgit.0")
end
it "strips out msysgit specific additions in the version string" do
- expect(git_proxy.version).to eq("1.2.3")
+ expect(subject.version).to eq("1.2.3")
end
it "does not raise an error when passed into Gem::Version.create" do
- expect { Gem::Version.create git_proxy.version }.not_to raise_error
+ expect { Gem::Version.create subject.version }.not_to raise_error
end
end
end
@@ -146,34 +96,34 @@ RSpec.describe Bundler::Source::Git::GitProxy do
describe "#full_version" do
context "with a normal version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(subject).to receive(:git_local).with("--version").
and_return("git version 1.2.3")
end
it "returns the git version number" do
- expect(git_proxy.full_version).to eq("1.2.3")
+ expect(subject.full_version).to eq("1.2.3")
end
end
context "with a OSX version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(subject).to receive(:git_local).with("--version").
and_return("git version 1.2.3 (Apple Git-BS)")
end
it "does not strip out OSX specific additions in the version string" do
- expect(git_proxy.full_version).to eq("1.2.3 (Apple Git-BS)")
+ expect(subject.full_version).to eq("1.2.3 (Apple Git-BS)")
end
end
context "with a msysgit version number" do
before do
- expect(git_proxy).to receive(:git_local).with("--version").
+ expect(subject).to receive(:git_local).with("--version").
and_return("git version 1.2.3.msysgit.0")
end
it "does not strip out msysgit specific additions in the version string" do
- expect(git_proxy.full_version).to eq("1.2.3.msysgit.0")
+ expect(subject.full_version).to eq("1.2.3.msysgit.0")
end
end
end
@@ -193,22 +143,8 @@ RSpec.describe Bundler::Source::Git::GitProxy do
FileUtils.chmod("+x", file)
- bundle :lock, raise_on_error: false
+ bundle :lock, :raise_on_error => false
expect(Pathname.new(bundled_app("canary"))).not_to exist
end
-
- context "URI is HTTP" do
- let(:uri) { "http://github.com/rubygems/rubygems.git" }
- let(:without_depth_arguments) { ["clone", "--bare", "--no-hardlinks", "--quiet", "--no-tags", "--single-branch"] }
- let(:fail_clone_result) { double(Process::Status, success?: false) }
-
- it "retries without --depth when git url is http and fails" do
- allow(git_proxy).to receive(:git_local).with("--version").and_return("git version 2.14.0")
- allow(git_proxy).to receive(:capture).with([*base_clone_args, "--", uri, path.to_s], nil).and_return(["", "dumb http transport does not support shallow capabilities", fail_clone_result])
- expect(git_proxy).to receive(:capture).with([*without_depth_arguments, "--", uri, path.to_s], nil).and_return(["", "", clone_result])
-
- subject.checkout
- end
- end
end
diff --git a/spec/bundler/bundler/source/git_spec.rb b/spec/bundler/bundler/source/git_spec.rb
index feef54bbf4..ed6dc3cd29 100644
--- a/spec/bundler/bundler/source/git_spec.rb
+++ b/spec/bundler/bundler/source/git_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe Bundler::Source::Git do
context "when the source has a reference" do
let(:git_proxy_stub) do
- instance_double(Bundler::Source::Git::GitProxy, revision: "123abc", branch: "v1.0.0")
+ instance_double(Bundler::Source::Git::GitProxy, :revision => "123abc", :branch => "v1.0.0")
end
let(:options) do
{ "uri" => uri, "ref" => "v1.0.0" }
@@ -55,7 +55,7 @@ RSpec.describe Bundler::Source::Git do
context "when the source has both reference and glob specifiers" do
let(:git_proxy_stub) do
- instance_double(Bundler::Source::Git::GitProxy, revision: "123abc", branch: "v1.0.0")
+ instance_double(Bundler::Source::Git::GitProxy, :revision => "123abc", :branch => "v1.0.0")
end
let(:options) do
{ "uri" => uri, "ref" => "v1.0.0", "glob" => "gems/foo/*.gemspec" }
diff --git a/spec/bundler/bundler/source/rubygems/remote_spec.rb b/spec/bundler/bundler/source/rubygems/remote_spec.rb
index 56f3bee459..07ce4f968e 100644
--- a/spec/bundler/bundler/source/rubygems/remote_spec.rb
+++ b/spec/bundler/bundler/source/rubygems/remote_spec.rb
@@ -11,8 +11,8 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
allow(Digest(:MD5)).to receive(:hexdigest).with(duck_type(:to_s)) {|string| "MD5HEX(#{string})" }
end
- let(:uri_no_auth) { Gem::URI("https://gems.example.com") }
- let(:uri_with_auth) { Gem::URI("https://#{credentials}@gems.example.com") }
+ let(:uri_no_auth) { Bundler::URI("https://gems.example.com") }
+ let(:uri_with_auth) { Bundler::URI("https://#{credentials}@gems.example.com") }
let(:credentials) { "username:password" }
context "when the original URI has no credentials" do
@@ -89,11 +89,11 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
end
context "when the original URI has only a username" do
- let(:uri) { Gem::URI("https://SeCrEt-ToKeN@gem.fury.io/me/") }
+ let(:uri) { Bundler::URI("https://SeCrEt-ToKeN@gem.fury.io/me/") }
describe "#anonymized_uri" do
it "returns the URI without username and password" do
- expect(remote(uri).anonymized_uri).to eq(Gem::URI("https://gem.fury.io/me/"))
+ expect(remote(uri).anonymized_uri).to eq(Bundler::URI("https://gem.fury.io/me/"))
end
end
@@ -105,9 +105,9 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
end
context "when a mirror with inline credentials is configured for the URI" do
- let(:uri) { Gem::URI("https://rubygems.org/") }
- let(:mirror_uri_with_auth) { Gem::URI("https://username:password@rubygems-mirror.org/") }
- let(:mirror_uri_no_auth) { Gem::URI("https://rubygems-mirror.org/") }
+ let(:uri) { Bundler::URI("https://rubygems.org/") }
+ let(:mirror_uri_with_auth) { Bundler::URI("https://username:password@rubygems-mirror.org/") }
+ let(:mirror_uri_no_auth) { Bundler::URI("https://rubygems-mirror.org/") }
before { Bundler.settings.temporary("mirror.https://rubygems.org/" => mirror_uri_with_auth.to_s) }
@@ -131,9 +131,9 @@ RSpec.describe Bundler::Source::Rubygems::Remote do
end
context "when a mirror with configured credentials is configured for the URI" do
- let(:uri) { Gem::URI("https://rubygems.org/") }
- let(:mirror_uri_with_auth) { Gem::URI("https://#{credentials}@rubygems-mirror.org/") }
- let(:mirror_uri_no_auth) { Gem::URI("https://rubygems-mirror.org/") }
+ let(:uri) { Bundler::URI("https://rubygems.org/") }
+ let(:mirror_uri_with_auth) { Bundler::URI("https://#{credentials}@rubygems-mirror.org/") }
+ let(:mirror_uri_no_auth) { Bundler::URI("https://rubygems-mirror.org/") }
before do
Bundler.settings.temporary("mirror.https://rubygems.org/" => mirror_uri_no_auth.to_s)
diff --git a/spec/bundler/bundler/source_list_spec.rb b/spec/bundler/bundler/source_list_spec.rb
index 13453cb2a3..f860e9ff58 100644
--- a/spec/bundler/bundler/source_list_spec.rb
+++ b/spec/bundler/bundler/source_list_spec.rb
@@ -85,7 +85,7 @@ RSpec.describe Bundler::SourceList do
end
it "ignores git protocols on request" do
- Bundler.settings.temporary("git.allow_insecure": true)
+ Bundler.settings.temporary(:"git.allow_insecure" => true)
expect(Bundler.ui).to_not receive(:warn).with(msg)
source_list.add_git_source("uri" => "git://existing-git.org/path.git")
end
@@ -125,8 +125,8 @@ RSpec.describe Bundler::SourceList do
it "adds the provided remote to the beginning of the aggregate source" do
source_list.add_global_rubygems_remote("https://othersource.org")
expect(returned_source.remotes).to eq [
- Gem::URI("https://othersource.org/"),
- Gem::URI("https://rubygems.org/"),
+ Bundler::URI("https://othersource.org/"),
+ Bundler::URI("https://rubygems.org/"),
]
end
end
diff --git a/spec/bundler/bundler/source_spec.rb b/spec/bundler/bundler/source_spec.rb
index 3b49c37431..ceb369ecdb 100644
--- a/spec/bundler/bundler/source_spec.rb
+++ b/spec/bundler/bundler/source_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe Bundler::Source do
end
describe "#version_message" do
- let(:spec) { double(:spec, name: "nokogiri", version: ">= 1.6", platform: rb) }
+ let(:spec) { double(:spec, :name => "nokogiri", :version => ">= 1.6", :platform => rb) }
shared_examples_for "the lockfile specs are not relevant" do
it "should return a string with the spec name and version" do
@@ -32,19 +32,19 @@ RSpec.describe Bundler::Source do
context "when there are locked gems" do
context "that contain the relevant gem spec" do
context "without a version" do
- let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: nil) }
+ let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => nil) }
it_behaves_like "the lockfile specs are not relevant"
end
context "with the same version" do
- let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: ">= 1.6") }
+ let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => ">= 1.6") }
it_behaves_like "the lockfile specs are not relevant"
end
context "with a different version" do
- let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: "< 1.5") }
+ let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => "< 1.5") }
context "with color", :no_color_tty do
before do
@@ -70,8 +70,8 @@ RSpec.describe Bundler::Source do
end
context "with a more recent version" do
- let(:spec) { double(:spec, name: "nokogiri", version: "1.6.1", platform: rb) }
- let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: "1.7.0") }
+ let(:spec) { double(:spec, :name => "nokogiri", :version => "1.6.1", :platform => rb) }
+ let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => "1.7.0") }
context "with color", :no_color_tty do
before do
@@ -97,8 +97,8 @@ RSpec.describe Bundler::Source do
end
context "with an older version" do
- let(:spec) { double(:spec, name: "nokogiri", version: "1.7.1", platform: rb) }
- let(:locked_gem) { double(:locked_gem, name: "nokogiri", version: "1.7.0") }
+ let(:spec) { double(:spec, :name => "nokogiri", :version => "1.7.1", :platform => rb) }
+ let(:locked_gem) { double(:locked_gem, :name => "nokogiri", :version => "1.7.0") }
context "with color", :no_color_tty do
before do
@@ -128,7 +128,7 @@ RSpec.describe Bundler::Source do
describe "#can_lock?" do
context "when the passed spec's source is equivalent" do
- let(:spec) { double(:spec, source: subject) }
+ let(:spec) { double(:spec, :source => subject) }
it "should return true" do
expect(subject.can_lock?(spec)).to be_truthy
@@ -136,7 +136,7 @@ RSpec.describe Bundler::Source do
end
context "when the passed spec's source is not equivalent" do
- let(:spec) { double(:spec, source: double(:other_source)) }
+ let(:spec) { double(:spec, :source => double(:other_source)) }
it "should return false" do
expect(subject.can_lock?(spec)).to be_falsey
diff --git a/spec/bundler/bundler/spec_set_spec.rb b/spec/bundler/bundler/spec_set_spec.rb
index c4b6676223..6fedd38b50 100644
--- a/spec/bundler/bundler/spec_set_spec.rb
+++ b/spec/bundler/bundler/spec_set_spec.rb
@@ -45,6 +45,24 @@ RSpec.describe Bundler::SpecSet do
end
end
+ describe "#merge" do
+ let(:other_specs) do
+ [
+ build_spec("f", "1.0"),
+ build_spec("g", "2.0"),
+ ].flatten
+ end
+
+ let(:other_spec_set) { described_class.new(other_specs) }
+
+ it "merges the items in each gemspec" do
+ new_spec_set = subject.merge(other_spec_set)
+ specs = new_spec_set.to_a.map(&:full_name)
+ expect(specs).to include("a-1.0")
+ expect(specs).to include("f-1.0")
+ end
+ end
+
describe "#to_a" do
it "returns the specs in order" do
expect(subject.to_a.map(&:full_name)).to eq %w[
diff --git a/spec/bundler/bundler/specifications/foo.gemspec b/spec/bundler/bundler/specifications/foo.gemspec
deleted file mode 100644
index 81b77d0c86..0000000000
--- a/spec/bundler/bundler/specifications/foo.gemspec
+++ /dev/null
@@ -1,13 +0,0 @@
-# rubocop:disable Style/FrozenStringLiteralComment
-# stub: foo 1.0.0 ruby lib
-
-# The first line would be '# -*- encoding: utf-8 -*-' in a real stub gemspec
-
-Gem::Specification.new do |s|
- s.name = "foo"
- s.version = "1.0.0"
- s.loaded_from = __FILE__
- s.extensions = "ext/foo"
- s.required_ruby_version = ">= 3.1.0"
-end
-# rubocop:enable Style/FrozenStringLiteralComment
diff --git a/spec/bundler/bundler/stub_specification_spec.rb b/spec/bundler/bundler/stub_specification_spec.rb
index beb966b3ce..fb612813c2 100644
--- a/spec/bundler/bundler/stub_specification_spec.rb
+++ b/spec/bundler/bundler/stub_specification_spec.rb
@@ -19,17 +19,6 @@ RSpec.describe Bundler::StubSpecification do
end
end
- describe "#gem_build_complete_path" do
- it "StubSpecification should have equal gem_build_complete_path as Specification" do
- spec_path = File.join(File.dirname(__FILE__), "specifications", "foo.gemspec")
- spec = Gem::Specification.load(spec_path)
- gem_stub = Gem::StubSpecification.new(spec_path, File.dirname(__FILE__),"","")
-
- stub = described_class.from_stub(gem_stub)
- expect(stub.gem_build_complete_path).to eq spec.gem_build_complete_path
- end
- end
-
describe "#manually_installed?" do
it "returns true if installed_by_version is nil or 0" do
stub = described_class.from_stub(with_bundler_stub_spec)
@@ -55,24 +44,4 @@ RSpec.describe Bundler::StubSpecification do
expect(stub.missing_extensions?).to be true
end
end
-
- describe "#activated?" do
- it "returns true after activation" do
- stub = described_class.from_stub(with_bundler_stub_spec)
-
- expect(stub.activated?).to be_falsey
- stub.activated = true
- expect(stub.activated?).to be true
- end
-
- it "returns true after activation if the underlying stub is a `Gem::StubSpecification`" do
- spec_path = File.join(File.dirname(__FILE__), "specifications", "foo.gemspec")
- gem_stub = Gem::StubSpecification.new(spec_path, File.dirname(__FILE__),"","")
- stub = described_class.from_stub(gem_stub)
-
- expect(stub.activated?).to be_falsey
- stub.activated = true
- expect(stub.activated?).to be true
- end
- end
end
diff --git a/spec/bundler/bundler/ui/shell_spec.rb b/spec/bundler/bundler/ui/shell_spec.rb
index 422c850a65..15120a8a41 100644
--- a/spec/bundler/bundler/ui/shell_spec.rb
+++ b/spec/bundler/bundler/ui/shell_spec.rb
@@ -10,13 +10,6 @@ RSpec.describe Bundler::UI::Shell do
it "prints to stdout" do
expect { subject.info("info") }.to output("info\n").to_stdout
end
-
- context "when output_stream is :stderr" do
- before { subject.output_stream = :stderr }
- it "prints to stderr" do
- expect { subject.info("info") }.to output("info\n").to_stderr
- end
- end
end
describe "#confirm" do
@@ -24,36 +17,19 @@ RSpec.describe Bundler::UI::Shell do
it "prints to stdout" do
expect { subject.confirm("confirm") }.to output("confirm\n").to_stdout
end
-
- context "when output_stream is :stderr" do
- before { subject.output_stream = :stderr }
- it "prints to stderr" do
- expect { subject.confirm("confirm") }.to output("confirm\n").to_stderr
- end
- end
end
describe "#warn" do
before { subject.level = "warn" }
- it "prints to stderr, implicitly adding a newline" do
+ it "prints to stderr" do
expect { subject.warn("warning") }.to output("warning\n").to_stderr
end
- it "can be told not to emit a newline" do
- expect { subject.warn("warning", false) }.to output("warning").to_stderr
- end
end
describe "#debug" do
it "prints to stdout" do
expect { subject.debug("debug") }.to output("debug\n").to_stdout
end
-
- context "when output_stream is :stderr" do
- before { subject.output_stream = :stderr }
- it "prints to stderr" do
- expect { subject.debug("debug") }.to output("debug\n").to_stderr
- end
- end
end
describe "#error" do
diff --git a/spec/bundler/bundler/uri_credentials_filter_spec.rb b/spec/bundler/bundler/uri_credentials_filter_spec.rb
index ed24744a1c..466c1b8594 100644
--- a/spec/bundler/bundler/uri_credentials_filter_spec.rb
+++ b/spec/bundler/bundler/uri_credentials_filter_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe Bundler::URICredentialsFilter do
let(:credentials) { "oauth_token:x-oauth-basic@" }
it "returns the uri without the oauth token" do
- expect(subject.credential_filtered_uri(uri).to_s).to eq(Gem::URI("https://x-oauth-basic@github.com/company/private-repo").to_s)
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(Bundler::URI("https://x-oauth-basic@github.com/company/private-repo").to_s)
end
it_behaves_like "original type of uri is maintained"
@@ -26,7 +26,7 @@ RSpec.describe Bundler::URICredentialsFilter do
let(:credentials) { "oauth_token:x@" }
it "returns the uri without the oauth token" do
- expect(subject.credential_filtered_uri(uri).to_s).to eq(Gem::URI("https://x@github.com/company/private-repo").to_s)
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(Bundler::URI("https://x@github.com/company/private-repo").to_s)
end
it_behaves_like "original type of uri is maintained"
@@ -37,7 +37,7 @@ RSpec.describe Bundler::URICredentialsFilter do
let(:credentials) { "username1:hunter3@" }
it "returns the uri without the password" do
- expect(subject.credential_filtered_uri(uri).to_s).to eq(Gem::URI("https://username1@github.com/company/private-repo").to_s)
+ expect(subject.credential_filtered_uri(uri).to_s).to eq(Bundler::URI("https://username1@github.com/company/private-repo").to_s)
end
it_behaves_like "original type of uri is maintained"
@@ -55,7 +55,7 @@ RSpec.describe Bundler::URICredentialsFilter do
end
context "uri is a uri object" do
- let(:uri) { Gem::URI("https://#{credentials}github.com/company/private-repo") }
+ let(:uri) { Bundler::URI("https://#{credentials}github.com/company/private-repo") }
it_behaves_like "sensitive credentials in uri are filtered out"
end
@@ -90,7 +90,7 @@ RSpec.describe Bundler::URICredentialsFilter do
describe "#credential_filtered_string" do
let(:str_to_filter) { "This is a git message containing a uri #{uri}!" }
let(:credentials) { "" }
- let(:uri) { Gem::URI("https://#{credentials}github.com/company/private-repo") }
+ let(:uri) { Bundler::URI("https://#{credentials}github.com/company/private-repo") }
context "with a uri that contains credentials" do
let(:credentials) { "oauth_token:x-oauth-basic@" }
diff --git a/spec/bundler/bundler/yaml_serializer_spec.rb b/spec/bundler/bundler/yaml_serializer_spec.rb
index de437f764a..1241c74bbf 100644
--- a/spec/bundler/bundler/yaml_serializer_spec.rb
+++ b/spec/bundler/bundler/yaml_serializer_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Bundler::YAMLSerializer do
it "works for simple hash" do
hash = { "Q" => "Where does Thursday come before Wednesday? In the dictionary. :P" }
- expected = <<~YAML
+ expected = strip_whitespace <<-YAML
---
Q: "Where does Thursday come before Wednesday? In the dictionary. :P"
YAML
@@ -24,7 +24,7 @@ RSpec.describe Bundler::YAMLSerializer do
},
}
- expected = <<~YAML
+ expected = strip_whitespace <<-YAML
---
nice-one:
read_ahead: "All generalizations are false, including this one"
@@ -45,7 +45,7 @@ RSpec.describe Bundler::YAMLSerializer do
},
}
- expected = <<~YAML
+ expected = strip_whitespace <<-YAML
---
nested_hash:
contains_array:
@@ -57,24 +57,11 @@ RSpec.describe Bundler::YAMLSerializer do
expect(serializer.dump(hash)).to eq(expected)
end
-
- it "handles empty array" do
- hash = {
- "empty_array" => [],
- }
-
- expected = <<~YAML
- ---
- empty_array: []
- YAML
-
- expect(serializer.dump(hash)).to eq(expected)
- end
end
describe "#load" do
it "works for simple hash" do
- yaml = <<~YAML
+ yaml = strip_whitespace <<-YAML
---
Jon: "Air is free dude!"
Jack: "Yes.. until you buy a bag of chips!"
@@ -89,7 +76,7 @@ RSpec.describe Bundler::YAMLSerializer do
end
it "works for nested hash" do
- yaml = <<~YAML
+ yaml = strip_whitespace <<-YAML
---
baa:
baa: "black sheep"
@@ -111,7 +98,7 @@ RSpec.describe Bundler::YAMLSerializer do
end
it "handles colon in key/value" do
- yaml = <<~YAML
+ yaml = strip_whitespace <<-YAML
BUNDLE_MIRROR__HTTPS://RUBYGEMS__ORG/: http://rubygems-mirror.org
YAML
@@ -119,7 +106,7 @@ RSpec.describe Bundler::YAMLSerializer do
end
it "handles arrays inside hashes" do
- yaml = <<~YAML
+ yaml = strip_whitespace <<-YAML
---
nested_hash:
contains_array:
@@ -140,7 +127,7 @@ RSpec.describe Bundler::YAMLSerializer do
end
it "handles windows-style CRLF line endings" do
- yaml = <<~YAML.gsub("\n", "\r\n")
+ yaml = strip_whitespace(<<-YAML).gsub("\n", "\r\n")
---
nested_hash:
contains_array:
@@ -161,34 +148,6 @@ RSpec.describe Bundler::YAMLSerializer do
expect(serializer.load(yaml)).to eq(hash)
end
-
- it "handles empty array" do
- yaml = <<~YAML
- ---
- empty_array: []
- YAML
-
- hash = {
- "empty_array" => [],
- }
-
- expect(serializer.load(yaml)).to eq(hash)
- end
-
- it "skip commented out words" do
- yaml = <<~YAML
- ---
- foo: bar
- buzz: foo # bar
- YAML
-
- hash = {
- "foo" => "bar",
- "buzz" => "foo",
- }
-
- expect(serializer.load(yaml)).to eq(hash)
- end
end
describe "against yaml lib" do
diff --git a/spec/bundler/cache/cache_path_spec.rb b/spec/bundler/cache/cache_path_spec.rb
index d5bd14965b..12385427b1 100644
--- a/spec/bundler/cache/cache_path_spec.rb
+++ b/spec/bundler/cache/cache_path_spec.rb
@@ -3,15 +3,15 @@
RSpec.describe "bundle package" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
context "with --cache-path" do
it "caches gems at given path" do
bundle :cache, "cache-path" => "vendor/cache-foo"
- expect(bundled_app("vendor/cache-foo/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache-foo/rack-1.0.0.gem")).to exist
end
end
@@ -19,14 +19,14 @@ RSpec.describe "bundle package" do
it "caches gems at given path" do
bundle "config set cache_path vendor/cache-foo"
bundle :cache
- expect(bundled_app("vendor/cache-foo/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache-foo/rack-1.0.0.gem")).to exist
end
end
context "with absolute --cache-path" do
it "caches gems at given path" do
- bundle :cache, "cache-path" => bundled_app("vendor/cache-foo")
- expect(bundled_app("vendor/cache-foo/myrack-1.0.0.gem")).to exist
+ bundle :cache, "cache-path" => "/tmp/cache-foo"
+ expect(bundled_app("/tmp/cache-foo/rack-1.0.0.gem")).to exist
end
end
end
diff --git a/spec/bundler/cache/gems_spec.rb b/spec/bundler/cache/gems_spec.rb
index a694df2700..63c00eba01 100644
--- a/spec/bundler/cache/gems_spec.rb
+++ b/spec/bundler/cache/gems_spec.rb
@@ -4,23 +4,23 @@ RSpec.describe "bundle cache" do
shared_examples_for "when there are only gemsources" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- system_gems "myrack-1.0.0", path: path
+ system_gems "rack-1.0.0", :path => path
bundle :cache
end
it "copies the .gem file to vendor/cache" do
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "uses the cache as a source when installing gems" do
- build_gem "omg", path: bundled_app("vendor/cache")
+ build_gem "omg", :path => bundled_app("vendor/cache")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "omg"
G
@@ -28,47 +28,47 @@ RSpec.describe "bundle cache" do
end
it "uses the cache as a source when installing gems with --local" do
- system_gems [], path: default_bundle_path
+ system_gems [], :path => default_bundle_path
bundle "install --local"
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
it "does not reinstall gems from the cache if they exist on the system" do
- build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache") do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0", :path => bundled_app("vendor/cache") do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
it "does not reinstall gems from the cache if they exist in the bundle" do
- system_gems "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-1.0.0", :path => default_bundle_path
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache") do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0", :path => bundled_app("vendor/cache") do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
- bundle :install, local: true
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ bundle :install, :local => true
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
it "creates a lockfile" do
- cache_gems "myrack-1.0.0"
+ cache_gems "rack-1.0.0"
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "cache"
@@ -93,97 +93,82 @@ RSpec.describe "bundle cache" do
let(:default_json_version) { ruby "gem 'json'; require 'json'; puts JSON::VERSION" }
before :each do
- build_gem "json", default_json_version, to_system: true, default: true
- end
-
- context "when a remote gem is available for caching" do
- before do
- build_repo2 do
- build_gem "json", default_json_version
- end
+ build_repo2 do
+ build_gem "json", default_json_version
end
- it "uses remote gems when installing" do
- install_gemfile %(source "https://gem.repo2"; gem 'json', '#{default_json_version}'), verbose: true
- expect(out).to include("Installing json #{default_json_version}")
- end
+ build_gem "json", default_json_version, :to_system => true, :default => true
+ end
- it "does not use remote gems when installing with --local flag" do
- install_gemfile %(source "https://gem.repo2"; gem 'json', '#{default_json_version}'), verbose: true, local: true
- expect(out).to include("Using json #{default_json_version}")
- end
+ it "uses builtin gems when installing to system gems" do
+ bundle "config set path.system true"
+ install_gemfile %(source "#{file_uri_for(gem_repo1)}"; gem 'json', '#{default_json_version}'), :verbose => true
+ expect(out).to include("Using json #{default_json_version}")
+ end
- it "caches remote and builtin gems" do
- install_gemfile <<-G
- source "https://gem.repo2"
- gem 'json', '#{default_json_version}'
- gem 'myrack', '1.0.0'
- G
+ it "caches remote and builtin gems" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'json', '#{default_json_version}'
+ gem 'rack', '1.0.0'
+ G
- bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
- expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
- end
+ bundle :cache
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
+ end
- it "caches builtin gems when cache_all_platforms is set" do
- gemfile <<-G
- source "https://gem.repo2"
- gem "json"
- G
+ it "caches builtin gems when cache_all_platforms is set" do
+ gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+ gem "json"
+ G
- bundle "config set cache_all_platforms true"
+ bundle "config set cache_all_platforms true"
- bundle :cache
- expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
- end
+ bundle :cache
+ expect(bundled_app("vendor/cache/json-#{default_json_version}.gem")).to exist
+ end
- it "doesn't make remote request after caching the gem" do
- build_gem "builtin_gem_2", "1.0.2", path: bundled_app("vendor/cache"), default: true
+ it "doesn't make remote request after caching the gem" do
+ build_gem "builtin_gem_2", "1.0.2", :path => bundled_app("vendor/cache") do |s|
+ s.summary = "This builtin_gem is bundled with Ruby"
+ end
- install_gemfile <<-G
- source "https://gem.repo2"
- gem 'builtin_gem_2', '1.0.2'
- G
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'builtin_gem_2', '1.0.2'
+ G
- bundle "install --local"
- expect(the_bundle).to include_gems("builtin_gem_2 1.0.2")
- end
+ bundle "install --local"
+ expect(the_bundle).to include_gems("builtin_gem_2 1.0.2")
end
- context "when a remote gem is not available for caching" do
- it "warns, but uses builtin gems when installing to system gems" do
- bundle "config set path.system true"
- install_gemfile %(source "https://gem.repo1"; gem 'json', '#{default_json_version}'), verbose: true
- expect(err).to include("json-#{default_json_version} is built in to Ruby, and can't be cached")
- expect(out).to include("Using json #{default_json_version}")
- end
-
- it "errors when explicitly caching" do
- bundle "config set path.system true"
+ it "errors if the builtin gem isn't available to cache" do
+ bundle "config set path.system true"
- install_gemfile <<-G
- source "https://gem.repo1"
- gem 'json', '#{default_json_version}'
- G
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'json', '#{default_json_version}'
+ G
- bundle :cache, raise_on_error: false
- expect(exitstatus).to_not eq(0)
- expect(err).to include("json-#{default_json_version} is built in to Ruby, and can't be cached")
- end
+ bundle :cache, :raise_on_error => false
+ expect(exitstatus).to_not eq(0)
+ expect(err).to include("json-#{default_json_version} is built in to Ruby, and can't be cached")
end
end
describe "when there are also git sources" do
before do
build_git "foo"
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
end
- gem 'myrack'
+ gem 'rack'
G
end
@@ -193,7 +178,7 @@ RSpec.describe "bundle cache" do
system_gems []
bundle "install --local"
- expect(the_bundle).to include_gems("myrack 1.0.0", "foo 1.0")
+ expect(the_bundle).to include_gems("rack 1.0.0", "foo 1.0")
end
it "should not explode if the lockfile is not present" do
@@ -206,44 +191,41 @@ RSpec.describe "bundle cache" do
end
describe "when previously cached" do
- let :setup_main_repo do
+ before :each do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
gem "actionpack"
G
bundle :cache
- expect(cached_gem("myrack-1.0.0")).to exist
+ expect(cached_gem("rack-1.0.0")).to exist
expect(cached_gem("actionpack-2.3.2")).to exist
expect(cached_gem("activesupport-2.3.2")).to exist
end
it "re-caches during install" do
- setup_main_repo
- cached_gem("myrack-1.0.0").rmtree
+ cached_gem("rack-1.0.0").rmtree
bundle :install
expect(out).to include("Updating files in vendor/cache")
- expect(cached_gem("myrack-1.0.0")).to exist
+ expect(cached_gem("rack-1.0.0")).to exist
end
it "adds and removes when gems are updated" do
- setup_main_repo
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
end
- bundle "update", all: true
- expect(cached_gem("myrack-1.2")).to exist
- expect(cached_gem("myrack-1.0.0")).not_to exist
+ bundle "update", :all => true
+ expect(cached_gem("rack-1.2")).to exist
+ expect(cached_gem("rack-1.0.0")).not_to exist
end
it "adds new gems and dependencies" do
- setup_main_repo
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
G
expect(cached_gem("rails-2.3.2")).to exist
@@ -251,26 +233,24 @@ RSpec.describe "bundle cache" do
end
it "removes .gems for removed gems and dependencies" do
- setup_main_repo
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
G
- expect(cached_gem("myrack-1.0.0")).to exist
+ expect(cached_gem("rack-1.0.0")).to exist
expect(cached_gem("actionpack-2.3.2")).not_to exist
expect(cached_gem("activesupport-2.3.2")).not_to exist
end
it "removes .gems when gem changes to git source" do
- setup_main_repo
- build_git "myrack"
+ build_git "rack"
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", :git => "#{lib_path("myrack-1.0")}"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", :git => "#{lib_path("rack-1.0")}"
gem "actionpack"
G
- expect(cached_gem("myrack-1.0.0")).not_to exist
+ expect(cached_gem("rack-1.0.0")).not_to exist
expect(cached_gem("actionpack-2.3.2")).to exist
expect(cached_gem("activesupport-2.3.2")).to exist
end
@@ -278,7 +258,7 @@ RSpec.describe "bundle cache" do
it "doesn't remove gems that are for another platform" do
simulate_platform "java" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
G
@@ -287,108 +267,36 @@ RSpec.describe "bundle cache" do
end
simulate_new_machine
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific"
+ G
- simulate_platform "x86-darwin-100" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "platform_specific"
- G
-
- expect(cached_gem("platform_specific-1.0-x86-darwin-100")).to exist
- expect(cached_gem("platform_specific-1.0-java")).to exist
- end
- end
-
- it "doesn't remove gems cached gems that don't match their remote counterparts, but also refuses to install and prints an error" do
- setup_main_repo
- cached_myrack = cached_gem("myrack-1.0.0")
- cached_myrack.rmtree
- build_gem "myrack", "1.0.0",
- path: cached_myrack.parent,
- rubygems_version: "1.3.2"
-
- simulate_new_machine
-
- FileUtils.rm bundled_app_lock
- bundle :install, raise_on_error: false
-
- expect(err).to eq <<~E.strip
- Bundler found mismatched checksums. This is a potential security risk.
- #{checksum_to_lock(gem_repo2, "myrack", "1.0.0")}
- from the API at https://gem.repo2/
- #{checksum_from_package(cached_myrack, "myrack", "1.0.0")}
- from the gem at #{cached_myrack}
-
- If you trust the API at https://gem.repo2/, to resolve this issue you can:
- 1. remove the gem at #{cached_myrack}
- 2. run `bundle install`
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- E
-
- expect(cached_gem("myrack-1.0.0")).to exist
+ expect(cached_gem("platform_specific-1.0-#{Bundler.local_platform}")).to exist
+ expect(cached_gem("platform_specific-1.0-java")).to exist
end
- it "raises an error when a cached gem is altered and produces a different checksum than the remote gem" do
- setup_main_repo
- cached_gem("myrack-1.0.0").rmtree
- build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache")
-
- checksums = checksums_section do |c|
- c.checksum gem_repo1, "myrack", "1.0.0"
- end
-
+ it "doesn't remove gems with mismatched :rubygems_version or :date" do
+ cached_gem("rack-1.0.0").rmtree
+ build_gem "rack", "1.0.0",
+ :path => bundled_app("vendor/cache"),
+ :rubygems_version => "1.3.2"
simulate_new_machine
- lockfile <<-L
- GEM
- remote: https://gem.repo2/
- specs:
- myrack (1.0.0)
- #{checksums}
- L
-
- bundle :install, raise_on_error: false
- expect(exitstatus).to eq(37)
- expect(err).to include("Bundler found mismatched checksums.")
- expect(err).to include("1. remove the gem at #{cached_gem("myrack-1.0.0")}")
-
- expect(cached_gem("myrack-1.0.0")).to exist
- cached_gem("myrack-1.0.0").rmtree
bundle :install
- expect(cached_gem("myrack-1.0.0")).to exist
- end
-
- it "installs a modified gem with a non-matching checksum when the API implementation does not provide checksums" do
- setup_main_repo
- cached_gem("myrack-1.0.0").rmtree
- build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache")
- simulate_new_machine
-
- lockfile <<-L
- GEM
- remote: https://gem.repo2/
- specs:
- myrack (1.0.0)
- L
-
- bundle :install, artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
- expect(cached_gem("myrack-1.0.0")).to exist
+ expect(cached_gem("rack-1.0.0")).to exist
end
it "handles directories and non .gem files in the cache" do
- setup_main_repo
bundled_app("vendor/cache/foo").mkdir
File.open(bundled_app("vendor/cache/bar"), "w") {|f| f.write("not a gem") }
bundle :cache
end
it "does not say that it is removing gems when it isn't actually doing so" do
- setup_main_repo
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "cache"
bundle "install"
@@ -396,10 +304,9 @@ RSpec.describe "bundle cache" do
end
it "does not warn about all if it doesn't have any git/path dependency" do
- setup_main_repo
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "cache"
expect(out).not_to match(/\-\-all/)
@@ -407,10 +314,10 @@ RSpec.describe "bundle cache" do
it "should install gems with the name bundler in them (that aren't bundler)" do
build_gem "foo-bundler", "1.0",
- path: bundled_app("vendor/cache")
+ :path => bundled_app("vendor/cache")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo-bundler"
G
diff --git a/spec/bundler/cache/git_spec.rb b/spec/bundler/cache/git_spec.rb
index ea91829003..890ba88605 100644
--- a/spec/bundler/cache/git_spec.rb
+++ b/spec/bundler/cache/git_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe "bundle cache with git" do
ref = git.ref_for("main", 11)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
@@ -27,7 +27,6 @@ RSpec.describe "bundle cache with git" do
expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.git")).not_to exist
expect(bundled_app("vendor/cache/foo-1.0-#{ref}/.bundlecache")).to be_file
- expect(Dir.glob(bundled_app("vendor/cache/foo-1.0-#{ref}/hooks/*.sample"))).to be_empty
FileUtils.rm_rf lib_path("foo-1.0")
expect(the_bundle).to include_gems "foo 1.0"
@@ -38,7 +37,7 @@ RSpec.describe "bundle cache with git" do
ref = git.ref_for("main", 11)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
@@ -58,7 +57,7 @@ RSpec.describe "bundle cache with git" do
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
@@ -76,7 +75,7 @@ RSpec.describe "bundle cache with git" do
old_ref = git.ref_for("main", 11)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
@@ -90,7 +89,7 @@ RSpec.describe "bundle cache with git" do
ref = git.ref_for("main", 11)
expect(ref).not_to eq(old_ref)
- bundle "update", all: true
+ bundle "update", :all => true
bundle :cache
expect(bundled_app("vendor/cache/foo-1.0-#{ref}")).to exist
@@ -106,7 +105,7 @@ RSpec.describe "bundle cache with git" do
old_ref = git.ref_for("main", 11)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
@@ -135,7 +134,7 @@ RSpec.describe "bundle cache with git" do
ref = git.ref_for("main", 11)
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-invalid")}', :branch => :main
G
@@ -155,92 +154,7 @@ RSpec.describe "bundle cache with git" do
expect(out).to eq("LOCAL")
end
- it "can use gems after copying install folder to a different machine with git not installed" do
- build_git "foo"
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => '#{lib_path("foo-1.0")}'
- G
- bundle "config set path vendor/bundle"
- bundle :install
-
- simulate_new_machine
- with_path_as "" do
- bundle "config set deployment true"
- bundle "install --local"
- expect(the_bundle).to include_gem "foo 1.0"
- end
- end
-
- it "can install after bundle cache without cloning remote repositories" do
- build_git "foo"
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => '#{lib_path("foo-1.0")}'
- G
- bundle "config set cache_all true"
- bundle :cache, "all-platforms" => true
- FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s
- FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/foo-1.0-*")).first.to_s
-
- simulate_new_machine
- bundle "config set frozen true"
- bundle "install --local --verbose"
- expect(out).to_not include("Fetching")
- expect(the_bundle).to include_gem "foo 1.0"
- end
-
- it "can install after bundle cache without cloning remote repositories even without the original cache" do
- build_git "foo"
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => '#{lib_path("foo-1.0")}'
- G
- bundle "config set cache_all true"
- bundle :cache, "all-platforms" => true
- FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s
- FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/foo-1.0-*")).first.to_s
-
- simulate_new_machine
- bundle "config set frozen true"
- FileUtils.rm_rf "#{default_bundle_path}/cache/bundler/git/foo-1.0-*"
- bundle "install --local --verbose"
- expect(out).to_not include("Fetching")
- expect(the_bundle).to include_gem "foo 1.0"
- end
-
- it "can install after bundle cache without cloning remote repositories with only git tracked files" do
- build_git "foo"
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => '#{lib_path("foo-1.0")}'
- G
- bundle "config set cache_all true"
- bundle :cache, "all-platforms" => true
- FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s
- FileUtils.rm_rf Dir.glob(default_bundle_path("bundler/gems/foo-1.0-*")).first.to_s
-
- simulate_new_machine
- bundle "config set frozen true"
- FileUtils.rm_rf "#{default_bundle_path}/cache/bundler/git/foo-1.0-*"
-
- # Remove untracked files (including the empty refs dir in the cache)
- Dir.chdir(bundled_app) do
- system(*%W[git init --quiet])
- system(*%W[git add --all])
- system(*%W[git clean -d --force --quiet])
- end
-
- bundle "install --local --verbose"
- expect(out).to_not include("Fetching")
- expect(the_bundle).to include_gem "foo 1.0"
- end
-
- it "copies repository to vendor cache" do
+ it "copies repository to vendor cache, including submodules" do
# CVE-2022-39253: https://lore.kernel.org/lkml/xmqq4jw1uku5.fsf@gitster.g/
system(*%W[git config --global protocol.file.allow always])
@@ -250,11 +164,11 @@ RSpec.describe "bundle cache with git" do
s.add_dependency "submodule"
end
- git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0")
- git "commit -m \"submodulator\"", lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("has_submodule-1.0")}", :submodules => true do
gem "has_submodule"
end
@@ -265,74 +179,54 @@ RSpec.describe "bundle cache with git" do
bundle :cache
expect(bundled_app("vendor/cache/has_submodule-1.0-#{ref}")).to exist
+ expect(bundled_app("vendor/cache/has_submodule-1.0-#{ref}/submodule-1.0")).to exist
expect(the_bundle).to include_gems "has_submodule 1.0"
end
+ it "caches pre-evaluated gemspecs" do
+ git = build_git "foo"
+
+ # Insert a gemspec method that shells out
+ spec_lines = lib_path("foo-1.0/foo.gemspec").read.split("\n")
+ spec_lines.insert(-2, "s.description = `echo bob`")
+ update_git("foo") {|s| s.write "foo.gemspec", spec_lines.join("\n") }
+
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => '#{lib_path("foo-1.0")}'
+ G
+ bundle "config set cache_all true"
+ bundle :cache
+
+ ref = git.ref_for("main", 11)
+ gemspec = bundled_app("vendor/cache/foo-1.0-#{ref}/foo.gemspec").read
+ expect(gemspec).to_not match("`echo bob`")
+ end
+
it "can install after bundle cache with git not installed" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
- bundle "config set path vendor/bundle"
bundle "config set cache_all true"
bundle :cache, "all-platforms" => true, :install => false
simulate_new_machine
with_path_as "" do
bundle "config set deployment true"
- bundle :install, local: true
+ bundle :install, :local => true
expect(the_bundle).to include_gem "foo 1.0"
end
end
- it "can install after bundle cache generated with an older Bundler that kept checkouts in the cache" do
- git = build_git("foo")
- locked_revision = git.ref_for("main")
- path_revision = git.ref_for("main", 11)
-
- git_path = lib_path("foo-1.0")
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => '#{git_path}'
- G
- lockfile <<~L
- GIT
- remote: #{git_path}/
- revision: #{locked_revision}
- specs:
- foo (1.0)
-
- GEM
- remote: https://gem.repo1/
- specs:
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- # Simulate an old incorrect situation where vendor/cache would be the install location of git gems
- FileUtils.mkdir_p bundled_app("vendor/cache")
- FileUtils.cp_r git_path, bundled_app("vendor/cache/foo-1.0-#{path_revision}")
- FileUtils.rm_rf bundled_app("vendor/cache/foo-1.0-#{path_revision}/.git")
-
- bundle :install, env: { "BUNDLE_DEPLOYMENT" => "true", "BUNDLE_CACHE_ALL" => "true" }
- end
-
it "respects the --no-install flag" do
git = build_git "foo", &:add_c_extension
ref = git.ref_for("main", 11)
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
bundle "config set cache_all true"
@@ -372,40 +266,11 @@ RSpec.describe "bundle cache with git" do
# Verify that the compilation worked and the result is in $LOAD_PATH by simply attempting
# to require it; that should make sure this spec does not break if the load path behaviour
# is changed.
- bundle :install, local: true
- ruby <<~R, raise_on_error: false
+ bundle :install, :local => true
+ ruby <<~R, :raise_on_error => false
require 'bundler/setup'
require 'foo_c'
R
expect(last_command).to_not be_failure
end
-
- it "doesn't fail when git gem has extensions and an empty cache folder is present before bundle install" do
- build_git "puma" do |s|
- s.add_dependency "rake"
- s.extensions << "Rakefile"
- s.executables = "puma"
- s.write "Rakefile", <<-RUBY
- task :default do
- path = File.expand_path("../lib", __FILE__)
- FileUtils.mkdir_p(path)
- File.open("\#{path}/puma.rb", "w") do |f|
- f.puts "PUMA = 'YES'"
- end
- end
- RUBY
- end
-
- FileUtils.mkdir_p(bundled_app("vendor/cache"))
- bundle "config set cache_all all"
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "puma", :git => "#{lib_path("puma-1.0")}"
- G
-
- bundle "exec puma"
-
- expect(out).to eq("YES")
- end
end
diff --git a/spec/bundler/cache/path_spec.rb b/spec/bundler/cache/path_spec.rb
index 966cb6f531..2ad136a008 100644
--- a/spec/bundler/cache/path_spec.rb
+++ b/spec/bundler/cache/path_spec.rb
@@ -2,10 +2,10 @@
RSpec.describe "bundle cache with path" do
it "is no-op when the path is within the bundle" do
- build_lib "foo", path: bundled_app("lib/foo")
+ build_lib "foo", :path => bundled_app("lib/foo")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{bundled_app("lib/foo")}'
G
@@ -19,7 +19,7 @@ RSpec.describe "bundle cache with path" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -35,10 +35,10 @@ RSpec.describe "bundle cache with path" do
libname = File.basename(bundled_app) + "_gem"
libpath = File.join(File.dirname(bundled_app), libname)
- build_lib libname, path: libpath
+ build_lib libname, :path => libpath
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "#{libname}", :path => '#{libpath}'
G
@@ -54,7 +54,7 @@ RSpec.describe "bundle cache with path" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -77,7 +77,7 @@ RSpec.describe "bundle cache with path" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -89,7 +89,7 @@ RSpec.describe "bundle cache with path" do
build_lib "bar"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :path => '#{lib_path("bar-1.0")}'
G
@@ -97,11 +97,11 @@ RSpec.describe "bundle cache with path" do
expect(bundled_app("vendor/cache/foo-1.0")).not_to exist
end
- it "does not cache path gems by default", bundler: "< 3" do
+ it "does not cache path gems by default", :bundler => "< 3" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -110,11 +110,11 @@ RSpec.describe "bundle cache with path" do
expect(bundled_app("vendor/cache/foo-1.0")).not_to exist
end
- it "caches path gems by default", bundler: "3" do
+ it "caches path gems by default", :bundler => "3" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -127,7 +127,7 @@ RSpec.describe "bundle cache with path" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -136,7 +136,7 @@ RSpec.describe "bundle cache with path" do
build_lib "bar"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
gem "bar", :path => '#{lib_path("bar-1.0")}'
G
@@ -149,7 +149,7 @@ RSpec.describe "bundle cache with path" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
G
@@ -158,12 +158,12 @@ RSpec.describe "bundle cache with path" do
build_lib "baz"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => '#{lib_path("foo-1.0")}'
gem "baz", :path => '#{lib_path("baz-1.0")}'
G
- bundle "cache --no-all", raise_on_error: false
+ bundle "cache --no-all", :raise_on_error => false
expect(bundled_app("vendor/cache/baz-1.0")).not_to exist
end
end
diff --git a/spec/bundler/cache/platform_spec.rb b/spec/bundler/cache/platform_spec.rb
index 71c0eaee8e..128278956c 100644
--- a/spec/bundler/cache/platform_spec.rb
+++ b/spec/bundler/cache/platform_spec.rb
@@ -3,10 +3,10 @@
RSpec.describe "bundle cache with multiple platforms" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
platforms :mri, :rbx do
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
end
platforms :jruby do
@@ -16,9 +16,9 @@ RSpec.describe "bundle cache with multiple platforms" do
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
activesupport (2.3.5)
PLATFORMS
@@ -26,24 +26,24 @@ RSpec.describe "bundle cache with multiple platforms" do
java
DEPENDENCIES
- myrack (1.0.0)
+ rack (1.0.0)
activesupport (2.3.5)
G
- cache_gems "myrack-1.0.0", "activesupport-2.3.5"
+ cache_gems "rack-1.0.0", "activesupport-2.3.5"
end
it "ensures that a successful bundle install does not delete gems for other platforms" do
bundle "install"
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/activesupport-2.3.5.gem")).to exist
end
it "ensures that a successful bundle update does not delete gems for other platforms" do
- bundle "update", all: true
+ bundle "update", :all => true
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/activesupport-2.3.5.gem")).to exist
end
end
diff --git a/spec/bundler/commands/add_spec.rb b/spec/bundler/commands/add_spec.rb
index 0a0d4c0046..5a5b534e8d 100644
--- a/spec/bundler/commands/add_spec.rb
+++ b/spec/bundler/commands/add_spec.rb
@@ -9,34 +9,24 @@ RSpec.describe "bundle add" do
build_gem "bar", "0.12.3"
build_gem "cat", "0.12.3.pre"
build_gem "dog", "1.1.3.pre"
- build_gem "lemur", "3.1.1.pre.2023.1.1"
end
build_git "foo", "2.0"
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "weakling", "~> 0.0.1"
G
end
context "when no gems are specified" do
it "shows error" do
- bundle "add", raise_on_error: false
+ bundle "add", :raise_on_error => false
expect(err).to include("Please specify gems to add")
end
end
- context "when Gemfile is empty, and frozen mode is set" do
- it "shows error" do
- gemfile 'source "https://gem.repo2"'
- bundle "add bar", raise_on_error: false, env: { "BUNDLE_FROZEN" => "true" }
-
- expect(err).to include("Frozen mode is set, but there's no lockfile")
- end
- end
-
describe "without version specified" do
it "version requirement becomes ~> major.minor.patch when resolved version is < 1.0" do
bundle "add 'bar'"
@@ -61,13 +51,6 @@ RSpec.describe "bundle add" do
expect(bundled_app_gemfile.read).to match(/gem "dog", "~> 1.1.pre"/)
expect(the_bundle).to include_gems "dog 1.1.3.pre"
end
-
- it "version requirement becomes ~> major.minor.pre.tail when resolved version has a very long tail pre version" do
- bundle "add 'lemur'"
- # the trailing pre purposely matches the release version to ensure that subbing the release doesn't change the pre.version"
- expect(bundled_app_gemfile.read).to match(/gem "lemur", "~> 3.1.pre.2023.1.1"/)
- expect(the_bundle).to include_gems "lemur 3.1.1.pre.2023.1.1"
- end
end
describe "with --version" do
@@ -80,7 +63,7 @@ RSpec.describe "bundle add" do
it "adds multiple version constraints when specified" do
requirements = ["< 3.0", "> 1.0"]
bundle "add 'foo' --version='#{requirements.join(", ")}'"
- expect(bundled_app_gemfile.read).to match(/gem "foo", #{Gem::Requirement.new(requirements).as_list.map(&:dump).join(", ")}/)
+ expect(bundled_app_gemfile.read).to match(/gem "foo", #{Gem::Requirement.new(requirements).as_list.map(&:dump).join(', ')}/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -113,9 +96,9 @@ RSpec.describe "bundle add" do
describe "with --source" do
it "adds dependency with specified source" do
- bundle "add 'foo' --source='https://gem.repo2'"
+ bundle "add 'foo' --source='#{file_uri_for(gem_repo2)}'"
- expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", :source => "https://gem.repo2"})
+ expect(bundled_app_gemfile.read).to match(/gem "foo", "~> 2.0", :source => "#{file_uri_for(gem_repo2)}"/)
expect(the_bundle).to include_gems "foo 2.0"
end
end
@@ -140,7 +123,7 @@ RSpec.describe "bundle add" do
describe "with --git and --branch" do
before do
- update_git "foo", "2.0", branch: "test"
+ update_git "foo", "2.0", :branch => "test"
end
it "adds dependency with specified git source and branch" do
@@ -161,81 +144,26 @@ RSpec.describe "bundle add" do
end
describe "with --github" do
- it "adds dependency with specified github source" do
+ it "adds dependency with specified github source", :realworld do
bundle "add rake --github=ruby/rake"
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake"})
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.0", :github => "ruby\/rake"})
end
end
describe "with --github and --branch" do
- it "adds dependency with specified github source and branch" do
+ it "adds dependency with specified github source and branch", :realworld do
bundle "add rake --github=ruby/rake --branch=master"
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :branch => "master"})
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.0", :github => "ruby\/rake", :branch => "master"})
end
end
describe "with --github and --ref" do
- it "adds dependency with specified github source and ref" do
+ it "adds dependency with specified github source and ref", :realworld do
bundle "add rake --github=ruby/rake --ref=5c60da8"
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :ref => "5c60da8"})
- end
- end
-
- describe "with --git and --glob" do
- it "adds dependency with specified git source" do
- bundle "add foo --git=#{lib_path("foo-2.0")} --glob='./*.gemspec'"
-
- expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", :git => "#{lib_path("foo-2.0")}", :glob => "\./\*\.gemspec"})
- expect(the_bundle).to include_gems "foo 2.0"
- end
- end
-
- describe "with --git and --branch and --glob" do
- before do
- update_git "foo", "2.0", branch: "test"
- end
-
- it "adds dependency with specified git source and branch" do
- bundle "add foo --git=#{lib_path("foo-2.0")} --branch=test --glob='./*.gemspec'"
-
- expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2.0", :git => "#{lib_path("foo-2.0")}", :branch => "test", :glob => "\./\*\.gemspec"})
- expect(the_bundle).to include_gems "foo 2.0"
- end
- end
-
- describe "with --git and --ref and --glob" do
- it "adds dependency with specified git source and branch" do
- bundle "add foo --git=#{lib_path("foo-2.0")} --ref=#{revision_for(lib_path("foo-2.0"))} --glob='./*.gemspec'"
-
- expect(bundled_app_gemfile.read).to match(%r{gem "foo", "~> 2\.0", :git => "#{lib_path("foo-2.0")}", :ref => "#{revision_for(lib_path("foo-2.0"))}", :glob => "\./\*\.gemspec"})
- expect(the_bundle).to include_gems "foo 2.0"
- end
- end
-
- describe "with --github and --glob" do
- it "adds dependency with specified github source" do
- bundle "add rake --github=ruby/rake --glob='./*.gemspec'"
-
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :glob => "\.\/\*\.gemspec"})
- end
- end
-
- describe "with --github and --branch --and glob" do
- it "adds dependency with specified github source and branch" do
- bundle "add rake --github=ruby/rake --branch=master --glob='./*.gemspec'"
-
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :branch => "master", :glob => "\.\/\*\.gemspec"})
- end
- end
-
- describe "with --github and --ref and --glob" do
- it "adds dependency with specified github source and ref" do
- bundle "add rake --github=ruby/rake --ref=5c60da8 --glob='./*.gemspec'"
-
- expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.\d+", :github => "ruby\/rake", :ref => "5c60da8", :glob => "\.\/\*\.gemspec"})
+ expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.0", :github => "ruby\/rake", :ref => "5c60da8"})
end
end
@@ -249,30 +177,30 @@ RSpec.describe "bundle add" do
end
it "using combination of short form options works like long form" do
- bundle "add 'foo' -s='https://gem.repo2' -g='development' -v='~>1.0'"
- expect(bundled_app_gemfile.read).to include %(gem "foo", "~> 1.0", :group => :development, :source => "https://gem.repo2")
+ bundle "add 'foo' -s='#{file_uri_for(gem_repo2)}' -g='development' -v='~>1.0'"
+ expect(bundled_app_gemfile.read).to include %(gem "foo", "~> 1.0", :group => :development, :source => "#{file_uri_for(gem_repo2)}")
expect(the_bundle).to include_gems "foo 1.1"
end
it "shows error message when version is not formatted correctly" do
- bundle "add 'foo' -v='~>1 . 0'", raise_on_error: false
+ bundle "add 'foo' -v='~>1 . 0'", :raise_on_error => false
expect(err).to match("Invalid gem requirement pattern '~>1 . 0'")
end
it "shows error message when gem cannot be found" do
bundle "config set force_ruby_platform true"
- bundle "add 'werk_it'", raise_on_error: false
+ bundle "add 'werk_it'", :raise_on_error => false
expect(err).to match("Could not find gem 'werk_it' in")
- bundle "add 'werk_it' -s='https://gem.repo2'", raise_on_error: false
+ bundle "add 'werk_it' -s='#{file_uri_for(gem_repo2)}'", :raise_on_error => false
expect(err).to match("Could not find gem 'werk_it' in rubygems repository")
end
it "shows error message when source cannot be reached" do
- bundle "add 'baz' --source='http://badhostasdf'", raise_on_error: false, artifice: "fail"
+ bundle "add 'baz' --source='http://badhostasdf'", :raise_on_error => false
expect(err).to include("Could not reach host badhostasdf. Check your network connection and try again.")
- bundle "add 'baz' --source='file://does/not/exist'", raise_on_error: false
+ bundle "add 'baz' --source='file://does/not/exist'", :raise_on_error => false
expect(err).to include("Could not fetch specs from file://does/not/exist/")
end
@@ -302,9 +230,9 @@ RSpec.describe "bundle add" do
describe "with --optimistic and --strict" do
it "throws error" do
- bundle "add 'foo' --strict --optimistic", raise_on_error: false
+ bundle "add 'foo' --strict --optimistic", :raise_on_error => false
- expect(err).to include("You cannot specify `--strict` and `--optimistic` at the same time")
+ expect(err).to include("You can not specify `--strict` and `--optimistic` at the same time")
end
end
@@ -317,7 +245,7 @@ RSpec.describe "bundle add" do
end
it "throws error if any of the specified gems are present in the gemfile with different version" do
- bundle "add weakling bar", raise_on_error: false
+ bundle "add weakling bar", :raise_on_error => false
expect(err).to include("You cannot specify the same gem twice with different version requirements")
expect(err).to include("You specified: weakling (~> 0.0.1) and weakling (>= 0).")
@@ -327,41 +255,41 @@ RSpec.describe "bundle add" do
describe "when a gem is added which is already specified in Gemfile with version" do
it "shows an error when added with different version requirement" do
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", "1.0"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", "1.0"
G
- bundle "add 'myrack' --version=1.1", raise_on_error: false
+ bundle "add 'rack' --version=1.1", :raise_on_error => false
expect(err).to include("You cannot specify the same gem twice with different version requirements")
- expect(err).to include("If you want to update the gem version, run `bundle update myrack`. You may also need to change the version requirement specified in the Gemfile if it's too restrictive")
+ expect(err).to include("If you want to update the gem version, run `bundle update rack`. You may also need to change the version requirement specified in the Gemfile if it's too restrictive")
end
it "shows error when added without version requirements" do
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", "1.0"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", "1.0"
G
- bundle "add 'myrack'", raise_on_error: false
+ bundle "add 'rack'", :raise_on_error => false
expect(err).to include("Gem already added.")
expect(err).to include("You cannot specify the same gem twice with different version requirements")
- expect(err).not_to include("If you want to update the gem version, run `bundle update myrack`. You may also need to change the version requirement specified in the Gemfile if it's too restrictive")
+ expect(err).not_to include("If you want to update the gem version, run `bundle update rack`. You may also need to change the version requirement specified in the Gemfile if it's too restrictive")
end
end
describe "when a gem is added which is already specified in Gemfile without version" do
it "shows an error when added with different version requirement" do
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
G
- bundle "add 'myrack' --version=1.1", raise_on_error: false
+ bundle "add 'rack' --version=1.1", :raise_on_error => false
expect(err).to include("You cannot specify the same gem twice with different version requirements")
- expect(err).to include("If you want to update the gem version, run `bundle update myrack`.")
+ expect(err).to include("If you want to update the gem version, run `bundle update rack`.")
expect(err).not_to include("You may also need to change the version requirement specified in the Gemfile if it's too restrictive")
end
end
@@ -370,8 +298,8 @@ RSpec.describe "bundle add" do
it "caches all new dependencies added for the specified gem" do
bundle :cache
- bundle "add 'myrack' --version=1.0.0"
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ bundle "add 'rack' --version=1.0.0"
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
end
end
diff --git a/spec/bundler/commands/binstubs_spec.rb b/spec/bundler/commands/binstubs_spec.rb
index 87a68a9cf1..bfbef58181 100644
--- a/spec/bundler/commands/binstubs_spec.rb
+++ b/spec/bundler/commands/binstubs_spec.rb
@@ -4,48 +4,48 @@ RSpec.describe "bundle binstubs <gem>" do
context "when the gem exists in the lockfile" do
it "sets up the binstub" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack"
+ bundle "binstubs rack"
- expect(bundled_app("bin/myrackup")).to exist
+ expect(bundled_app("bin/rackup")).to exist
end
it "does not install other binstubs" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "rails"
G
bundle "binstubs rails"
- expect(bundled_app("bin/myrackup")).not_to exist
+ expect(bundled_app("bin/rackup")).not_to exist
expect(bundled_app("bin/rails")).to exist
end
it "does install multiple binstubs" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "rails"
G
- bundle "binstubs rails myrack"
+ bundle "binstubs rails rack"
- expect(bundled_app("bin/myrackup")).to exist
+ expect(bundled_app("bin/rackup")).to exist
expect(bundled_app("bin/rails")).to exist
end
it "allows installing all binstubs" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
- bundle :binstubs, all: true
+ bundle :binstubs, :all => true
expect(bundled_app("bin/rails")).to exist
expect(bundled_app("bin/rake")).to exist
@@ -53,34 +53,34 @@ RSpec.describe "bundle binstubs <gem>" do
it "allows installing binstubs for all platforms" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack --all-platforms"
+ bundle "binstubs rack --all-platforms"
- expect(bundled_app("bin/myrackup")).to exist
- expect(bundled_app("bin/myrackup.cmd")).to exist
+ expect(bundled_app("bin/rackup")).to exist
+ expect(bundled_app("bin/rackup.cmd")).to exist
end
it "displays an error when used without any gem" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs", raise_on_error: false
+ bundle "binstubs", :raise_on_error => false
expect(exitstatus).to eq(1)
expect(err).to include("`bundle binstubs` needs at least one gem to run.")
end
it "displays an error when used with --all and gems" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack", all: true, raise_on_error: false
+ bundle "binstubs rack", :all => true, :raise_on_error => false
expect(last_command).to be_failure
expect(err).to include("Cannot specify --all with specific gems")
end
@@ -88,17 +88,17 @@ RSpec.describe "bundle binstubs <gem>" do
context "when generating bundle binstub outside bundler" do
it "should abort" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack"
+ bundle "binstubs rack"
File.open(bundled_app("bin/bundle"), "wb") do |file|
file.print "OMG"
end
- sys_exec "bin/myrackup", raise_on_error: false
+ sys_exec "bin/rackup", :raise_on_error => false
expect(err).to include("was not generated by Bundler")
end
@@ -108,42 +108,37 @@ RSpec.describe "bundle binstubs <gem>" do
before do
pristine_system_gems "bundler-#{system_bundler_version}"
build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "prints_loaded_gems", "1.0" do |s|
s.executables = "print_loaded_gems"
s.bindir = "exe"
- s.write "exe/print_loaded_gems", <<~R
- #!/usr/bin/env ruby
+ s.write "exe/print_loaded_gems", <<-R
specs = Gem.loaded_specs.values.reject {|s| s.default_gem? }
puts specs.map(&:full_name).sort.inspect
R
end
-
- build_bundler locked_bundler_version
end
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
gem "prints_loaded_gems"
G
- bundle "binstubs bundler myrack prints_loaded_gems"
+ bundle "binstubs bundler rack prints_loaded_gems"
end
let(:system_bundler_version) { Bundler::VERSION }
- let(:locked_bundler_version) { nil }
- let(:lockfile_content) { lockfile.gsub(system_bundler_version, locked_bundler_version) }
it "runs bundler" do
- bundle "install --verbose", bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :env => { "DEBUG" => "1" }
expect(out).to include %(Using bundler #{system_bundler_version}\n)
end
context "when BUNDLER_VERSION is set" do
it "runs the correct version of bundler" do
- bundle "install", env: { "BUNDLER_VERSION" => "999.999.999" }, raise_on_error: false, bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :env => { "BUNDLER_VERSION" => "999.999.999" }, :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (999.999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '999.999.999'`")
@@ -152,21 +147,19 @@ RSpec.describe "bundle binstubs <gem>" do
it "runs the correct version of bundler even if a higher version is installed" do
system_gems "bundler-999.999.998", "bundler-999.999.999"
- bundle "install --verbose", env: { "BUNDLER_VERSION" => "999.999.998" }, raise_on_error: false, bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :env => { "BUNDLER_VERSION" => "999.999.998", "DEBUG" => "1" }, :raise_on_error => false
expect(out).to include %(Using bundler 999.999.998\n)
end
end
context "when a lockfile exists with a locked bundler version" do
- let(:locked_bundler_version) { "999.999" }
-
context "and the version is newer" do
before do
- lockfile lockfile_content
+ lockfile lockfile.gsub(system_bundler_version, "999.999")
end
it "runs the correct version of bundler" do
- bundle "install", raise_on_error: false, bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 999.999'`")
@@ -176,11 +169,11 @@ RSpec.describe "bundle binstubs <gem>" do
context "and the version is newer when given `gems.rb` and `gems.locked`" do
before do
gemfile bundled_app("gems.rb"), gemfile
- lockfile bundled_app("gems.locked"), lockfile_content
+ lockfile bundled_app("gems.locked"), lockfile.gsub(system_bundler_version, "999.999")
end
it "runs the correct version of bundler" do
- bundle "install", env: { "BUNDLE_GEMFILE" => "gems.rb" }, raise_on_error: false, bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :env => { "BUNDLE_GEMFILE" => "gems.rb" }, :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 999.999) failed:").
@@ -190,14 +183,13 @@ RSpec.describe "bundle binstubs <gem>" do
context "and the version is older and a different major" do
let(:system_bundler_version) { "55" }
- let(:locked_bundler_version) { "44" }
before do
- lockfile lockfile_content
+ lockfile lockfile.gsub(/BUNDLED WITH\n .*$/m, "BUNDLED WITH\n 44.0")
end
it "runs the correct version of bundler" do
- bundle "install", raise_on_error: false, bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 44.0) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 44.0'`")
@@ -206,15 +198,14 @@ RSpec.describe "bundle binstubs <gem>" do
context "and the version is older and a different major when given `gems.rb` and `gems.locked`" do
let(:system_bundler_version) { "55" }
- let(:locked_bundler_version) { "44" }
before do
gemfile bundled_app("gems.rb"), gemfile
- lockfile bundled_app("gems.locked"), lockfile_content
+ lockfile bundled_app("gems.locked"), lockfile.gsub(/BUNDLED WITH\n .*$/m, "BUNDLED WITH\n 44.0")
end
it "runs the correct version of bundler" do
- bundle "install", env: { "BUNDLE_GEMFILE" => "gems.rb" }, raise_on_error: false, bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :env => { "BUNDLE_GEMFILE" => "gems.rb" }, :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 44.0) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 44.0'`")
@@ -223,22 +214,21 @@ RSpec.describe "bundle binstubs <gem>" do
context "and the version is older and the same major" do
let(:system_bundler_version) { "2.999.999" }
- let(:locked_bundler_version) { "2.3.0" }
before do
- lockfile lockfile_content
+ lockfile lockfile.gsub(/BUNDLED WITH\n .*$/m, "BUNDLED WITH\n 2.3.0")
end
- it "installs and runs the exact version of bundler", rubygems: ">= 3.3.0.dev" do
- bundle "install --verbose", bundle_bin: "bin/bundle"
+ it "installs and runs the exact version of bundler", :rubygems => ">= 3.3.0.dev", :realworld => true do
+ sys_exec "bin/bundle install --verbose", :artifice => "vcr"
expect(exitstatus).not_to eq(42)
expect(out).to include("Bundler 2.999.999 is running, but your lockfile was generated with 2.3.0. Installing Bundler 2.3.0 and restarting using that version.")
expect(out).to include("Using bundler 2.3.0")
expect(err).not_to include("Activating bundler (~> 2.3.0) failed:")
end
- it "runs the available version of bundler", rubygems: "< 3.3.0.dev" do
- bundle "install --verbose", bundle_bin: "bin/bundle"
+ it "runs the available version of bundler", :rubygems => "< 3.3.0.dev" do
+ sys_exec "bin/bundle install --verbose"
expect(exitstatus).not_to eq(42)
expect(out).not_to include("Bundler 2.999.999 is running, but your lockfile was generated with 2.3.0. Installing Bundler 2.3.0 and restarting using that version.")
expect(out).to include("Using bundler 2.999.999")
@@ -248,14 +238,13 @@ RSpec.describe "bundle binstubs <gem>" do
context "and the version is a pre-releaser" do
let(:system_bundler_version) { "55" }
- let(:locked_bundler_version) { "2.12.0.a" }
before do
- lockfile lockfile_content
+ lockfile lockfile.gsub(/BUNDLED WITH\n .*$/m, "BUNDLED WITH\n 2.12.0.a")
end
it "runs the correct version of bundler when the version is a pre-release" do
- bundle "install", raise_on_error: false, bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 2.12.a) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 2.12.a'`")
@@ -264,8 +253,10 @@ RSpec.describe "bundle binstubs <gem>" do
end
context "when update --bundler is called" do
- it "calls through to the latest bundler version" do
- bundle "update --bundler --verbose", bundle_bin: "bin/bundle"
+ before { lockfile.gsub(system_bundler_version, "1.1.1") }
+
+ it "calls through to the latest bundler version", :realworld do
+ sys_exec "bin/bundle update --bundler", :env => { "DEBUG" => "1" }
using_bundler_line = /Using bundler ([\w\.]+)\n/.match(out)
expect(using_bundler_line).to_not be_nil
latest_version = using_bundler_line[1]
@@ -273,7 +264,7 @@ RSpec.describe "bundle binstubs <gem>" do
end
it "calls through to the explicit bundler version" do
- bundle "update --bundler=999.999.999", raise_on_error: false, bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle update --bundler=999.999.999", :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (999.999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '999.999.999'`")
@@ -283,7 +274,7 @@ RSpec.describe "bundle binstubs <gem>" do
context "without a lockfile" do
it "falls back to the latest installed bundler" do
FileUtils.rm bundled_app_lock
- bundle "install --verbose", bundle_bin: "bin/bundle"
+ sys_exec "bin/bundle install", :env => { "DEBUG" => "1" }
expect(out).to include "Using bundler #{system_bundler_version}\n"
end
end
@@ -291,14 +282,14 @@ RSpec.describe "bundle binstubs <gem>" do
context "using another binstub" do
it "loads all gems" do
sys_exec bundled_app("bin/print_loaded_gems").to_s
- expect(out).to eq %(["bundler-#{Bundler::VERSION}", "myrack-1.2", "prints_loaded_gems-1.0"])
+ expect(out).to eq %(["bundler-#{Bundler::VERSION}", "prints_loaded_gems-1.0", "rack-1.2"])
end
context "when requesting a different bundler version" do
before { lockfile lockfile.gsub(Bundler::VERSION, "999.999.999") }
it "attempts to load that version" do
- sys_exec bundled_app("bin/myrackup").to_s, raise_on_error: false
+ sys_exec bundled_app("bin/rackup").to_s, :raise_on_error => false
expect(exitstatus).to eq(42)
expect(err).to include("Activating bundler (~> 999.999) failed:").
and include("To install the version of bundler this project requires, run `gem install bundler -v '~> 999.999'`")
@@ -310,11 +301,11 @@ RSpec.describe "bundle binstubs <gem>" do
it "installs binstubs from git gems" do
FileUtils.mkdir_p(lib_path("foo/bin"))
FileUtils.touch(lib_path("foo/bin/foo"))
- build_git "foo", "1.0", path: lib_path("foo") do |s|
+ build_git "foo", "1.0", :path => lib_path("foo") do |s|
s.executables = %w[foo]
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo")}"
G
@@ -326,11 +317,11 @@ RSpec.describe "bundle binstubs <gem>" do
it "installs binstubs from path gems" do
FileUtils.mkdir_p(lib_path("foo/bin"))
FileUtils.touch(lib_path("foo/bin/foo"))
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.executables = %w[foo]
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
@@ -342,12 +333,12 @@ RSpec.describe "bundle binstubs <gem>" do
it "sets correct permissions for binstubs" do
with_umask(0o002) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack"
- binary = bundled_app("bin/myrackup")
+ bundle "binstubs rack"
+ binary = bundled_app("bin/rackup")
expect(File.stat(binary).mode.to_s(8)).to eq(Gem.win_platform? ? "100644" : "100775")
end
end
@@ -355,12 +346,12 @@ RSpec.describe "bundle binstubs <gem>" do
context "when using --shebang" do
it "sets the specified shebang for the binstub" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack --shebang jruby"
- expect(File.readlines(bundled_app("bin/myrackup")).first).to eq("#!/usr/bin/env jruby\n")
+ bundle "binstubs rack --shebang jruby"
+ expect(File.readlines(bundled_app("bin/rackup")).first).to eq("#!/usr/bin/env jruby\n")
end
end
end
@@ -368,10 +359,10 @@ RSpec.describe "bundle binstubs <gem>" do
context "when the gem doesn't exist" do
it "displays an error with correct status" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
- bundle "binstubs doesnt_exist", raise_on_error: false
+ bundle "binstubs doesnt_exist", :raise_on_error => false
expect(exitstatus).to eq(7)
expect(err).to include("Could not find gem 'doesnt_exist'.")
@@ -381,23 +372,23 @@ RSpec.describe "bundle binstubs <gem>" do
context "--path" do
it "sets the binstubs dir" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack --path exec"
+ bundle "binstubs rack --path exec"
- expect(bundled_app("exec/myrackup")).to exist
+ expect(bundled_app("exec/rackup")).to exist
end
- it "setting is saved for bundle install", bundler: "< 3" do
+ it "setting is saved for bundle install", :bundler => "< 3" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "rails"
G
- bundle "binstubs myrack", path: "exec"
+ bundle "binstubs rack", :path => "exec"
bundle :install
expect(bundled_app("exec/rails")).to exist
@@ -407,34 +398,34 @@ RSpec.describe "bundle binstubs <gem>" do
context "with --standalone option" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "rails"
G
end
it "generates a standalone binstub" do
- bundle "binstubs myrack --standalone"
- expect(bundled_app("bin/myrackup")).to exist
+ bundle "binstubs rack --standalone"
+ expect(bundled_app("bin/rackup")).to exist
end
it "generates a binstub that does not depend on rubygems or bundler" do
- bundle "binstubs myrack --standalone"
- expect(File.read(bundled_app("bin/myrackup"))).to_not include("Gem.bin_path")
+ bundle "binstubs rack --standalone"
+ expect(File.read(bundled_app("bin/rackup"))).to_not include("Gem.bin_path")
end
context "when specified --path option" do
it "generates a standalone binstub at the given path" do
- bundle "binstubs myrack --standalone --path foo"
- expect(bundled_app("foo/myrackup")).to exist
+ bundle "binstubs rack --standalone --path foo"
+ expect(bundled_app("foo/rackup")).to exist
end
end
context "when specified --all-platforms option" do
it "generates standalone binstubs for all platforms" do
- bundle "binstubs myrack --standalone --all-platforms"
- expect(bundled_app("bin/myrackup")).to exist
- expect(bundled_app("bin/myrackup.cmd")).to exist
+ bundle "binstubs rack --standalone --all-platforms"
+ expect(bundled_app("bin/rackup")).to exist
+ expect(bundled_app("bin/rackup.cmd")).to exist
end
end
@@ -450,7 +441,7 @@ RSpec.describe "bundle binstubs <gem>" do
context "when specified --all option" do
it "generates standalone binstubs for all gems except bundler" do
bundle "binstubs --standalone --all"
- expect(bundled_app("bin/myrackup")).to exist
+ expect(bundled_app("bin/rackup")).to exist
expect(bundled_app("bin/rails")).to exist
expect(bundled_app("bin/bundle")).not_to exist
expect(bundled_app("bin/bundler")).not_to exist
@@ -462,39 +453,39 @@ RSpec.describe "bundle binstubs <gem>" do
context "when the bin already exists" do
it "doesn't overwrite and warns" do
FileUtils.mkdir_p(bundled_app("bin"))
- File.open(bundled_app("bin/myrackup"), "wb") do |file|
+ File.open(bundled_app("bin/rackup"), "wb") do |file|
file.print "OMG"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack"
+ bundle "binstubs rack"
- expect(bundled_app("bin/myrackup")).to exist
- expect(File.read(bundled_app("bin/myrackup"))).to eq("OMG")
- expect(err).to include("Skipped myrackup")
+ expect(bundled_app("bin/rackup")).to exist
+ expect(File.read(bundled_app("bin/rackup"))).to eq("OMG")
+ expect(err).to include("Skipped rackup")
expect(err).to include("overwrite skipped stubs, use --force")
end
context "when using --force" do
it "overwrites the binstub" do
FileUtils.mkdir_p(bundled_app("bin"))
- File.open(bundled_app("bin/myrackup"), "wb") do |file|
+ File.open(bundled_app("bin/rackup"), "wb") do |file|
file.print "OMG"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "binstubs myrack --force"
+ bundle "binstubs rack --force"
- expect(bundled_app("bin/myrackup")).to exist
- expect(File.read(bundled_app("bin/myrackup"))).not_to eq("OMG")
+ expect(bundled_app("bin/rackup")).to exist
+ expect(File.read(bundled_app("bin/rackup"))).not_to eq("OMG")
end
end
end
@@ -502,18 +493,18 @@ RSpec.describe "bundle binstubs <gem>" do
context "when the gem has no bins" do
it "suggests child gems if they have bins" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack-obama"
G
- bundle "binstubs myrack-obama"
- expect(err).to include("myrack-obama has no executables")
- expect(err).to include("myrack has: myrackup")
+ bundle "binstubs rack-obama"
+ expect(err).to include("rack-obama has no executables")
+ expect(err).to include("rack has: rackup")
end
it "works if child gems don't have bins" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "actionpack"
G
@@ -529,7 +520,7 @@ RSpec.describe "bundle binstubs <gem>" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "with_development_dependency"
G
@@ -541,25 +532,25 @@ RSpec.describe "bundle binstubs <gem>" do
context "when BUNDLE_INSTALL is specified" do
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set auto_install 1"
- bundle "binstubs myrack"
- expect(out).to include("Installing myrack 1.0.0")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle "binstubs rack"
+ expect(out).to include("Installing rack 1.0.0")
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does nothing when already up to date" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set auto_install 1"
- bundle "binstubs myrack", env: { "BUNDLE_INSTALL" => "1" }
- expect(out).not_to include("Installing myrack 1.0.0")
+ bundle "binstubs rack", :env => { "BUNDLE_INSTALL" => "1" }
+ expect(out).not_to include("Installing rack 1.0.0")
end
end
end
diff --git a/spec/bundler/commands/cache_spec.rb b/spec/bundler/commands/cache_spec.rb
index ab8eb06838..a9ed389233 100644
--- a/spec/bundler/commands/cache_spec.rb
+++ b/spec/bundler/commands/cache_spec.rb
@@ -3,8 +3,8 @@
RSpec.describe "bundle cache" do
it "doesn't update the cache multiple times, even if it already exists" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle :cache
@@ -17,14 +17,14 @@ RSpec.describe "bundle cache" do
context "with --gemfile" do
it "finds the gemfile" do
gemfile bundled_app("NotGemfile"), <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
bundle "cache --gemfile=NotGemfile"
ENV["BUNDLE_GEMFILE"] = "NotGemfile"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
@@ -32,15 +32,15 @@ RSpec.describe "bundle cache" do
context "without a gemspec" do
it "caches all dependencies except bundler itself" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
gem 'bundler'
D
bundle "config set cache_all true"
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/bundler-0.9.gem")).to_not exist
end
end
@@ -63,15 +63,15 @@ RSpec.describe "bundle cache" do
it "caches all dependencies except bundler and the gemspec specified gem" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
gemspec
D
bundle "config set cache_all true"
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/nokogiri-1.4.2.gem")).to exist
expect(bundled_app("vendor/cache/mygem-0.1.1.gem")).to_not exist
expect(bundled_app("vendor/cache/bundler-0.9.gem")).to_not exist
@@ -95,15 +95,15 @@ RSpec.describe "bundle cache" do
it "caches all dependencies except bundler and the gemspec specified gem" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
gemspec
D
bundle "config set cache_all true"
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/nokogiri-1.4.2.gem")).to exist
expect(bundled_app("vendor/cache/mygem-0.1.1.gem")).to_not exist
expect(bundled_app("vendor/cache/bundler-0.9.gem")).to_not exist
@@ -139,8 +139,8 @@ RSpec.describe "bundle cache" do
it "caches all dependencies except bundler and the gemspec specified gems" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
gemspec :name => 'mygem'
gemspec :name => 'mygem_test'
D
@@ -148,7 +148,7 @@ RSpec.describe "bundle cache" do
bundle "config set cache_all true"
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
expect(bundled_app("vendor/cache/nokogiri-1.4.2.gem")).to exist
expect(bundled_app("vendor/cache/weakling-0.0.3.gem")).to exist
expect(bundled_app("vendor/cache/mygem-0.1.1.gem")).to_not exist
@@ -158,16 +158,16 @@ RSpec.describe "bundle cache" do
end
end
- context "with --path", bundler: "< 3" do
+ context "with --path", :bundler => "< 3" do
it "sets root directory for gems" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
D
bundle "cache --path #{bundled_app("test")}"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(bundled_app("test/vendor/cache/")).to exist
end
end
@@ -175,60 +175,50 @@ RSpec.describe "bundle cache" do
context "with --no-install" do
it "puts the gems in vendor/cache but does not install them" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
D
bundle "cache --no-install"
- expect(the_bundle).not_to include_gems "myrack 1.0.0"
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(the_bundle).not_to include_gems "rack 1.0.0"
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "does not prevent installing gems with bundle install" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
D
bundle "cache --no-install"
bundle "install"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not prevent installing gems with bundle update" do
gemfile <<-D
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
D
bundle "cache --no-install"
bundle "update --all"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
context "with --all-platforms" do
- it "puts the gems in vendor/cache even for other rubies", bundler: ">= 2.4.0" do
+ it "puts the gems in vendor/cache even for other rubies" do
gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack', :platforms => [:ruby_20, :windows_20]
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', :platforms => [:ruby_20, :x64_mingw_20]
D
bundle "cache --all-platforms"
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
- end
-
- it "puts the gems in vendor/cache even for legacy windows rubies", bundler: ">= 2.4.0" do
- gemfile <<-D
- source "https://gem.repo1"
- gem 'myrack', :platforms => [:ruby_20, :x64_mingw_20]
- D
-
- bundle "cache --all-platforms"
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "does not attempt to install gems in without groups" do
@@ -241,39 +231,39 @@ RSpec.describe "bundle cache" do
end
bundle "config set --local without wo"
- install_gemfile <<-G, artifice: "compact_index_extra_api"
- source "https://main.repo"
- gem "myrack"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
group :wo do
gem "weakling"
- gem "uninstallable", :source => "https://main.repo/extra"
+ gem "uninstallable", :source => "#{file_uri_for(gem_repo4)}"
end
G
- bundle :cache, "all-platforms" => true, artifice: "compact_index_extra_api"
+ bundle :cache, "all-platforms" => true
expect(bundled_app("vendor/cache/weakling-0.0.3.gem")).to exist
expect(bundled_app("vendor/cache/uninstallable-2.0.gem")).to exist
- expect(the_bundle).to include_gem "myrack 1.0"
+ expect(the_bundle).to include_gem "rack 1.0"
expect(the_bundle).not_to include_gems "weakling", "uninstallable"
bundle "config set --local without wo"
- bundle :install, artifice: "compact_index_extra_api"
- expect(the_bundle).to include_gem "myrack 1.0"
- expect(the_bundle).not_to include_gems "weakling"
+ bundle :install
+ expect(the_bundle).to include_gem "rack 1.0"
+ expect(the_bundle).not_to include_gems "weakling", "uninstallable"
end
it "does not fail to cache gems in excluded groups when there's a lockfile but gems not previously installed" do
bundle "config set --local without wo"
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "https://my.gem.repo.1"
+ gem "rack"
group :wo do
gem "weakling"
end
G
- bundle :lock
- bundle :cache, "all-platforms" => true
+ bundle :lock, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
+ bundle :cache, "all-platforms" => true, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
expect(bundled_app("vendor/cache/weakling-0.0.3.gem")).to exist
end
end
@@ -281,29 +271,29 @@ RSpec.describe "bundle cache" do
context "with frozen configured" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "install"
end
subject do
bundle "config set --local frozen true"
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
end
it "tries to install with frozen" do
bundle "config set deployment true"
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
subject
expect(exitstatus).to eq(16)
expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile")
- expect(err).to include("* myrack-obama")
+ expect(err).to include("* rack-obama")
bundle "env"
expect(out).to include("frozen").or include("deployment")
end
@@ -315,12 +305,12 @@ RSpec.describe "bundle cache" do
build_gem "racc", "2.0" do |s|
s.add_dependency "rake"
s.extensions << "Rakefile"
- s.write "Rakefile", "task(:default) { puts 'INSTALLING myrack' }"
+ s.write "Rakefile", "task(:default) { puts 'INSTALLING rack' }"
end
end
gemfile <<~G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "racc"
G
@@ -339,8 +329,8 @@ RSpec.describe "bundle install with gem sources" do
it "does not hit the remote at all" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
G
bundle :cache
@@ -348,14 +338,14 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.rm_rf gem_repo2
bundle "install --local"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not hit the remote at all in frozen mode" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
G
bundle :cache
@@ -365,14 +355,14 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set --local deployment true"
bundle "config set --local path vendor/bundle"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not hit the remote at all when cache_all_platforms configured" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
G
bundle :cache
@@ -383,89 +373,29 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set --local path vendor/bundle"
bundle "install --local"
expect(out).not_to include("Fetching gem metadata")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
- it "uses cached gems for secondary sources when cache_all_platforms configured" do
- build_repo4 do
- build_gem "foo", "1.0.0" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "foo", "1.0.0" do |s|
- s.platform = "arm64-darwin"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo2"
-
- source "https://gem.repo4" do
- gem "foo"
- end
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo2/
- specs:
-
- GEM
- remote: https://gem.repo4/
- specs:
- foo (1.0.0-x86_64-linux)
- foo (1.0.0-arm64-darwin)
-
- PLATFORMS
- arm64-darwin
- ruby
- x86_64-linux
-
- DEPENDENCIES
- foo
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- simulate_platform "x86_64-linux" do
- bundle "config set cache_all_platforms true"
- bundle "config set path vendor/bundle"
- bundle :cache, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
-
- build_repo4 do
- # simulate removal of all remote gems
- end
-
- # delete compact index cache
- FileUtils.rm_rf home(".bundle/cache/compact_index")
-
- bundle "install", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
-
- expect(the_bundle).to include_gems "foo 1.0.0 x86_64-linux"
- end
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not reinstall already-installed gems" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle :cache
- build_gem "myrack", "1.0.0", path: bundled_app("vendor/cache") do |s|
- s.write "lib/myrack.rb", "raise 'omg'"
+ build_gem "rack", "1.0.0", :path => bundled_app("vendor/cache") do |s|
+ s.write "lib/rack.rb", "raise 'omg'"
end
bundle :install
expect(err).to be_empty
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
it "ignores cached gems for the wrong platform" do
simulate_platform "java" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
G
bundle :cache
@@ -476,16 +406,17 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set --local force_ruby_platform true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
G
- expect(the_bundle).to include_gems("platform_specific 1.0 ruby")
+ run "require 'platform_specific' ; puts PLATFORM_SPECIFIC"
+ expect(out).to eq("1.0.0 RUBY")
end
it "does not update the cache if --no-cache is passed" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundled_app("vendor/cache").mkpath
expect(bundled_app("vendor/cache").children).to be_empty
diff --git a/spec/bundler/commands/check_spec.rb b/spec/bundler/commands/check_spec.rb
index 18c4b2d89f..99a858e9e9 100644
--- a/spec/bundler/commands/check_spec.rb
+++ b/spec/bundler/commands/check_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe "bundle check" do
it "returns success when the Gemfile is satisfied" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
@@ -13,17 +13,17 @@ RSpec.describe "bundle check" do
it "works with the --gemfile flag when not in the directory" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
- bundle "check --gemfile bundled_app/Gemfile", dir: tmp
+ bundle "check --gemfile bundled_app/Gemfile", :dir => tmp
expect(out).to include("The Gemfile's dependencies are satisfied")
end
it "creates a Gemfile.lock by default if one does not exist" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
@@ -36,7 +36,7 @@ RSpec.describe "bundle check" do
it "does not create a Gemfile.lock if --dry-run was passed" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
@@ -51,36 +51,25 @@ RSpec.describe "bundle check" do
system_gems ["rails-2.3.2"]
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
end
it "prints a generic error if a Gemfile.lock does not exist and a toplevel dependency does not exist" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(exitstatus).to be > 0
expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
end
- it "prints a generic error if gem git source is not checked out" do
- gemfile <<-G
- source "https://gem.repo1"
- gem "rails", git: "git@github.com:rails/rails.git"
- G
-
- bundle :check, raise_on_error: false
- expect(exitstatus).to eq 1
- expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
- end
-
it "prints a generic message if you changed your lockfile" do
build_repo2 do
build_gem "rails_pinned_to_old_activesupport" do |s|
@@ -89,25 +78,25 @@ RSpec.describe "bundle check" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'rails'
G
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
gem "rails_pinned_to_old_activesupport"
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(err).to include("Bundler can't satisfy your Gemfile's dependencies.")
end
- it "remembers --without option from install", bundler: "< 3" do
+ it "remembers --without option from install", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :foo do
- gem "myrack"
+ gem "rack"
end
G
@@ -119,9 +108,9 @@ RSpec.describe "bundle check" do
it "uses the without setting" do
bundle "config set without foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :foo do
- gem "myrack"
+ gem "rack"
end
G
@@ -131,63 +120,63 @@ RSpec.describe "bundle check" do
it "ensures that gems are actually installed and not just cached" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :group => :foo
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :group => :foo
G
bundle "config set --local without foo"
bundle :install
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "check", raise_on_error: false
- expect(err).to include("* myrack (1.0.0)")
+ bundle "check", :raise_on_error => false
+ expect(err).to include("* rack (1.0.0)")
expect(exitstatus).to eq(1)
end
it "ensures that gems are actually installed and not just cached in applications' cache" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set --local path vendor/bundle"
bundle :cache
- gem_command "uninstall myrack", env: { "GEM_HOME" => vendored_gems.to_s }
+ gem_command "uninstall rack", :env => { "GEM_HOME" => vendored_gems.to_s }
- bundle "check", raise_on_error: false
- expect(err).to include("* myrack (1.0.0)")
+ bundle "check", :raise_on_error => false
+ expect(err).to include("* rack (1.0.0)")
expect(exitstatus).to eq(1)
end
it "ignores missing gems restricted to other platforms" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
platforms :#{not_local_tag} do
gem "activesupport"
end
G
- system_gems "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-1.0.0", :path => default_bundle_path
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
activesupport (2.3.5)
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{generic_local_platform}
#{not_local}
DEPENDENCIES
- myrack
+ rack
activesupport
G
@@ -197,28 +186,28 @@ RSpec.describe "bundle check" do
it "works with env conditionals" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
env :NOT_GOING_TO_BE_SET do
gem "activesupport"
end
G
- system_gems "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-1.0.0", :path => default_bundle_path
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
activesupport (2.3.5)
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{generic_local_platform}
#{not_local}
DEPENDENCIES
- myrack
+ rack
activesupport
G
@@ -227,20 +216,20 @@ RSpec.describe "bundle check" do
end
it "outputs an error when the default Gemfile is not found" do
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(exitstatus).to eq(10)
expect(err).to include("Could not locate Gemfile")
end
it "does not output fatal error message" do
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(exitstatus).to eq(10)
expect(err).not_to include("Unfortunately, a fatal error has occurred. ")
end
it "fails when there's no lock file and frozen is set" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
@@ -248,15 +237,15 @@ RSpec.describe "bundle check" do
bundle "install"
FileUtils.rm(bundled_app_lock)
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(last_command).to be_failure
end
- context "--path", bundler: "< 3" do
+ context "--path", :bundler => "< 3" do
context "after installing gems in the proper directory" do
before do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
bundle "install --path vendor/bundle"
@@ -278,11 +267,11 @@ RSpec.describe "bundle check" do
context "after installing gems on a different directory" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
- bundle "check --path vendor/bundle", raise_on_error: false
+ bundle "check --path vendor/bundle", :raise_on_error => false
end
it "returns false" do
@@ -294,10 +283,10 @@ RSpec.describe "bundle check" do
describe "when locked" do
before :each do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0"
G
end
@@ -309,63 +298,63 @@ RSpec.describe "bundle check" do
it "shows what is missing with the current Gemfile if it is not satisfied" do
simulate_new_machine
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(err).to match(/The following gems are missing/)
- expect(err).to include("* myrack (1.0")
+ expect(err).to include("* rack (1.0")
end
end
describe "when locked with multiple dependents with different requirements" do
before :each do
build_repo4 do
- build_gem "depends_on_myrack" do |s|
- s.add_dependency "myrack", ">= 1.0"
+ build_gem "depends_on_rack" do |s|
+ s.add_dependency "rack", ">= 1.0"
end
- build_gem "also_depends_on_myrack" do |s|
- s.add_dependency "myrack", "~> 1.0"
+ build_gem "also_depends_on_rack" do |s|
+ s.add_dependency "rack", "~> 1.0"
end
- build_gem "myrack"
+ build_gem "rack"
end
gemfile <<-G
- source "https://gem.repo4"
- gem "depends_on_myrack"
- gem "also_depends_on_myrack"
+ source "#{file_uri_for(gem_repo4)}"
+ gem "depends_on_rack"
+ gem "also_depends_on_rack"
G
bundle "lock"
end
it "shows what is missing with the current Gemfile without duplications" do
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(err).to match(/The following gems are missing/)
- expect(err).to include("* myrack (1.0").once
+ expect(err).to include("* rack (1.0").once
end
end
describe "when locked under multiple platforms" do
before :each do
build_repo4 do
- build_gem "myrack"
+ build_gem "rack"
end
gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
lockfile <<-L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
- myrack (1.0)
+ rack (1.0)
PLATFORMS
ruby
#{local_platform}
DEPENDENCIES
- myrack
+ rack
BUNDLED WITH
#{Bundler::VERSION}
@@ -373,24 +362,24 @@ RSpec.describe "bundle check" do
end
it "shows what is missing with the current Gemfile without duplications" do
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
expect(err).to match(/The following gems are missing/)
- expect(err).to include("* myrack (1.0").once
+ expect(err).to include("* rack (1.0").once
end
end
describe "when using only scoped rubygems sources" do
before do
gemfile <<~G
- source "https://gem.repo2"
- source "https://gem.repo1" do
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ source "#{file_uri_for(gem_repo1)}" do
+ gem "rack"
end
G
end
it "returns success when the Gemfile is satisfied" do
- system_gems "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-1.0.0", :path => default_bundle_path
bundle :check
expect(out).to include("The Gemfile's dependencies are satisfied")
end
@@ -399,49 +388,43 @@ RSpec.describe "bundle check" do
describe "when using only scoped rubygems sources with indirect dependencies" do
before do
build_repo4 do
- build_gem "depends_on_myrack" do |s|
- s.add_dependency "myrack"
+ build_gem "depends_on_rack" do |s|
+ s.add_dependency "rack"
end
- build_gem "myrack"
+ build_gem "rack"
end
gemfile <<~G
- source "https://gem.repo1"
- source "https://gem.repo4" do
- gem "depends_on_myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ source "#{file_uri_for(gem_repo4)}" do
+ gem "depends_on_rack"
end
G
end
it "returns success when the Gemfile is satisfied and generates a correct lockfile" do
- system_gems "depends_on_myrack-1.0", "myrack-1.0", gem_repo: gem_repo4, path: default_bundle_path
+ system_gems "depends_on_rack-1.0", "rack-1.0", :gem_repo => gem_repo4, :path => default_bundle_path
bundle :check
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "depends_on_myrack", "1.0"
- c.no_checksum "myrack", "1.0"
- end
-
expect(out).to include("The Gemfile's dependencies are satisfied")
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
- depends_on_myrack (1.0)
- myrack
- myrack (1.0)
+ depends_on_rack (1.0)
+ rack
+ rack (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- depends_on_myrack!
- #{checksums}
+ depends_on_rack!
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -458,7 +441,7 @@ RSpec.describe "bundle check" do
build_gem "dex-dispatch-engine"
end
- build_lib("bundle-check-issue", path: tmp("bundle-check-issue")) do |s|
+ build_lib("bundle-check-issue", :path => tmp.join("bundle-check-issue")) do |s|
s.write "Gemfile", <<-G
source "https://localgemserver.test"
@@ -472,24 +455,16 @@ RSpec.describe "bundle check" do
s.add_dependency "awesome_print"
end
- bundle "install", artifice: "compact_index_extra", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, dir: tmp("bundle-check-issue")
+ bundle "install", :artifice => "compact_index_extra", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, :dir => tmp.join("bundle-check-issue")
end
it "does not corrupt lockfile when changing version" do
- version_file = tmp("bundle-check-issue/bundle-check-issue.gemspec")
+ version_file = tmp.join("bundle-check-issue/bundle-check-issue.gemspec")
File.write(version_file, File.read(version_file).gsub(/s\.version = .+/, "s.version = '9999'"))
- bundle "check --verbose", dir: tmp("bundle-check-issue")
+ bundle "check --verbose", :dir => tmp.join("bundle-check-issue")
- lockfile = File.read(tmp("bundle-check-issue/Gemfile.lock"))
-
- checksums = checksums_section_when_enabled(lockfile) do |c|
- c.checksum gem_repo4, "awesome_print", "1.0"
- c.no_checksum "bundle-check-issue", "9999"
- c.checksum gem_repo2, "dex-dispatch-engine", "1.0"
- end
-
- expect(lockfile).to eq <<~L
+ expect(File.read(tmp.join("bundle-check-issue/Gemfile.lock"))).to eq <<~L
PATH
remote: .
specs:
@@ -512,7 +487,7 @@ RSpec.describe "bundle check" do
DEPENDENCIES
bundle-check-issue!
dex-dispatch-engine!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -523,15 +498,15 @@ RSpec.describe "bundle check" do
def lock_with(bundler_version = nil)
lock = <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
L
if bundler_version
@@ -545,8 +520,8 @@ RSpec.describe "bundle check" do
bundle "config set --local path vendor/bundle"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb
index c27766835e..471cd6c354 100644
--- a/spec/bundler/commands/clean_spec.rb
+++ b/spec/bundler/commands/clean_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe "bundle clean" do
it "removes unused gems that are different" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "foo"
@@ -30,7 +30,7 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
G
@@ -40,17 +40,17 @@ RSpec.describe "bundle clean" do
expect(out).to include("Removing foo (1.0)")
- should_have_gems "thin-1.0", "myrack-1.0.0"
+ should_have_gems "thin-1.0", "rack-1.0.0"
should_not_have_gems "foo-1.0"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "removes old version of gem if unused" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "0.9.1"
+ gem "rack", "0.9.1"
gem "foo"
G
@@ -59,28 +59,28 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
gem "foo"
G
bundle "install"
bundle :clean
- expect(out).to include("Removing myrack (0.9.1)")
+ expect(out).to include("Removing rack (0.9.1)")
- should_have_gems "foo-1.0", "myrack-1.0.0"
- should_not_have_gems "myrack-0.9.1"
+ should_have_gems "foo-1.0", "rack-1.0.0"
+ should_not_have_gems "rack-0.9.1"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "removes new version of gem if unused" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
gem "foo"
G
@@ -89,31 +89,31 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "0.9.1"
+ gem "rack", "0.9.1"
gem "foo"
G
- bundle "update myrack"
+ bundle "update rack"
bundle :clean
- expect(out).to include("Removing myrack (1.0.0)")
+ expect(out).to include("Removing rack (1.0.0)")
- should_have_gems "foo-1.0", "myrack-0.9.1"
- should_not_have_gems "myrack-1.0.0"
+ should_have_gems "foo-1.0", "rack-0.9.1"
+ should_not_have_gems "rack-1.0.0"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "removes gems in bundle without groups" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
group :test_group do
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
end
G
@@ -123,12 +123,12 @@ RSpec.describe "bundle clean" do
bundle "install"
bundle :clean
- expect(out).to include("Removing myrack (1.0.0)")
+ expect(out).to include("Removing rack (1.0.0)")
should_have_gems "foo-1.0"
- should_not_have_gems "myrack-1.0.0"
+ should_not_have_gems "rack-1.0.0"
- expect(vendored_gems("bin/myrackup")).to_not exist
+ expect(vendored_gems("bin/rackup")).to_not exist
end
it "does not remove cached git dir if it's being used" do
@@ -137,9 +137,9 @@ RSpec.describe "bundle clean" do
git_path = lib_path("foo-1.0")
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
git "#{git_path}", :ref => "#{revision}" do
gem "foo"
end
@@ -156,14 +156,14 @@ RSpec.describe "bundle clean" do
end
it "removes unused git gems" do
- build_git "foo", path: lib_path("foo")
+ build_git "foo", :path => lib_path("foo")
git_path = lib_path("foo")
revision = revision_for(git_path)
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
git "#{git_path}", :ref => "#{revision}" do
gem "foo"
end
@@ -173,9 +173,9 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
bundle "install"
@@ -183,25 +183,25 @@ RSpec.describe "bundle clean" do
expect(out).to include("Removing foo (#{revision[0..11]})")
- expect(vendored_gems("gems/myrack-1.0.0")).to exist
+ expect(vendored_gems("gems/rack-1.0.0")).to exist
expect(vendored_gems("bundler/gems/foo-#{revision[0..11]}")).not_to exist
digest = Digest(:SHA1).hexdigest(git_path.to_s)
expect(vendored_gems("cache/bundler/git/foo-#{digest}")).not_to exist
- expect(vendored_gems("specifications/myrack-1.0.0.gemspec")).to exist
+ expect(vendored_gems("specifications/rack-1.0.0.gemspec")).to exist
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "keeps used git gems even if installed to a symlinked location" do
- build_git "foo", path: lib_path("foo")
+ build_git "foo", :path => lib_path("foo")
git_path = lib_path("foo")
revision = revision_for(git_path)
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
git "#{git_path}", :ref => "#{revision}" do
gem "foo"
end
@@ -221,13 +221,13 @@ RSpec.describe "bundle clean" do
end
it "removes old git gems" do
- build_git "foo-bar", path: lib_path("foo-bar")
+ build_git "foo-bar", :path => lib_path("foo-bar")
revision = revision_for(lib_path("foo-bar"))
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
git "#{lib_path("foo-bar")}" do
gem "foo-bar"
end
@@ -236,32 +236,32 @@ RSpec.describe "bundle clean" do
bundle "config set path vendor/bundle"
bundle "install"
- update_git "foo-bar", path: lib_path("foo-bar")
+ update_git "foo-bar", :path => lib_path("foo-bar")
revision2 = revision_for(lib_path("foo-bar"))
- bundle "update", all: true
+ bundle "update", :all => true
bundle :clean
expect(out).to include("Removing foo-bar (#{revision[0..11]})")
- expect(vendored_gems("gems/myrack-1.0.0")).to exist
+ expect(vendored_gems("gems/rack-1.0.0")).to exist
expect(vendored_gems("bundler/gems/foo-bar-#{revision[0..11]}")).not_to exist
expect(vendored_gems("bundler/gems/foo-bar-#{revision2[0..11]}")).to exist
- expect(vendored_gems("specifications/myrack-1.0.0.gemspec")).to exist
+ expect(vendored_gems("specifications/rack-1.0.0.gemspec")).to exist
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "does not remove nested gems in a git repo" do
- build_lib "activesupport", "3.0", path: lib_path("rails/activesupport")
- build_git "rails", "3.0", path: lib_path("rails") do |s|
+ build_lib "activesupport", "3.0", :path => lib_path("rails/activesupport")
+ build_git "rails", "3.0", :path => lib_path("rails") do |s|
s.add_dependency "activesupport", "= 3.0"
end
revision = revision_for(lib_path("rails"))
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport", :git => "#{lib_path("rails")}", :ref => '#{revision}'
G
@@ -274,14 +274,14 @@ RSpec.describe "bundle clean" do
end
it "does not remove git sources that are in without groups" do
- build_git "foo", path: lib_path("foo")
+ build_git "foo", :path => lib_path("foo")
git_path = lib_path("foo")
revision = revision_for(git_path)
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
group :test do
git "#{git_path}", :ref => "#{revision}" do
gem "foo"
@@ -302,9 +302,9 @@ RSpec.describe "bundle clean" do
it "does not blow up when using without groups" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
group :development do
gem "foo"
@@ -321,12 +321,12 @@ RSpec.describe "bundle clean" do
it "displays an error when used without --path" do
bundle "config set path.system true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
- bundle :clean, raise_on_error: false
+ bundle :clean, :raise_on_error => false
expect(exitstatus).to eq(15)
expect(err).to include("--force")
@@ -335,7 +335,7 @@ RSpec.describe "bundle clean" do
# handling bundle clean upgrade path from the pre's
it "removes .gem/.gemspec file even if there's no corresponding gem dir" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "foo"
@@ -345,71 +345,71 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
bundle "install"
- FileUtils.rm(vendored_gems("bin/myrackup"))
+ FileUtils.rm(vendored_gems("bin/rackup"))
FileUtils.rm_rf(vendored_gems("gems/thin-1.0"))
- FileUtils.rm_rf(vendored_gems("gems/myrack-1.0.0"))
+ FileUtils.rm_rf(vendored_gems("gems/rack-1.0.0"))
bundle :clean
- should_not_have_gems "thin-1.0", "myrack-1.0"
+ should_not_have_gems "thin-1.0", "rack-1.0"
should_have_gems "foo-1.0"
- expect(vendored_gems("bin/myrackup")).not_to exist
+ expect(vendored_gems("bin/rackup")).not_to exist
end
it "does not call clean automatically when using system gems" do
bundle "config set path.system true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
- gem "myrack"
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
gem_command :list
- expect(out).to include("myrack (1.0.0)").and include("thin (1.0)")
+ expect(out).to include("rack (1.0.0)").and include("thin (1.0)")
end
- it "--clean should override the bundle setting on install", bundler: "< 3" do
+ it "--clean should override the bundle setting on install", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
- gem "myrack"
+ gem "rack"
G
bundle "config set path vendor/bundle"
bundle "config set clean false"
bundle "install --clean true"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
bundle "install"
- should_have_gems "myrack-1.0.0"
+ should_have_gems "rack-1.0.0"
should_not_have_gems "thin-1.0"
end
- it "--clean should override the bundle setting on update", bundler: "< 3" do
+ it "--clean should override the bundle setting on update", :bundler => "< 3" do
build_repo2
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "foo"
G
@@ -421,17 +421,17 @@ RSpec.describe "bundle clean" do
build_gem "foo", "1.0.1"
end
- bundle "update", all: true
+ bundle "update", :all => true
should_have_gems "foo-1.0.1"
should_not_have_gems "foo-1.0"
end
- it "automatically cleans when path has not been set", bundler: "3" do
+ it "automatically cleans when path has not been set", :bundler => "3" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "foo"
G
@@ -440,7 +440,7 @@ RSpec.describe "bundle clean" do
build_gem "foo", "1.0.1"
end
- bundle "update", all: true
+ bundle "update", :all => true
files = Pathname.glob(bundled_app(".bundle", Bundler.ruby_scope, "*", "*"))
files.map! {|f| f.to_s.sub(bundled_app(".bundle", Bundler.ruby_scope).to_s, "") }
@@ -453,29 +453,29 @@ RSpec.describe "bundle clean" do
it "does not clean automatically on --path" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
- gem "myrack"
+ gem "rack"
G
bundle "config set path vendor/bundle"
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
bundle "install"
- should_have_gems "myrack-1.0.0", "thin-1.0"
+ should_have_gems "rack-1.0.0", "thin-1.0"
end
it "does not clean on bundle update with --path" do
build_repo2
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "foo"
G
@@ -486,7 +486,7 @@ RSpec.describe "bundle clean" do
build_gem "foo", "1.0.1"
end
- bundle :update, all: true
+ bundle :update, :all => true
should_have_gems "foo-1.0", "foo-1.0.1"
end
@@ -496,7 +496,7 @@ RSpec.describe "bundle clean" do
build_repo2
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "foo"
G
@@ -505,7 +505,7 @@ RSpec.describe "bundle clean" do
update_repo2 do
build_gem "foo", "1.0.1"
end
- bundle :update, all: true
+ bundle :update, :all => true
gem_command :list
expect(out).to include("foo (1.0.1, 1.0)")
@@ -515,17 +515,17 @@ RSpec.describe "bundle clean" do
bundle "config set path.system true"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
- gem "myrack"
+ gem "rack"
G
bundle :install
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
bundle :install
bundle "clean --force"
@@ -533,7 +533,7 @@ RSpec.describe "bundle clean" do
expect(out).to include("Removing foo (1.0)")
gem_command :list
expect(out).not_to include("foo (1.0)")
- expect(out).to include("myrack (1.0.0)")
+ expect(out).to include("rack (1.0.0)")
end
describe "when missing permissions", :permissions do
@@ -544,30 +544,30 @@ RSpec.describe "bundle clean" do
end
it "returns a helpful error message" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
- gem "myrack"
+ gem "rack"
G
bundle :install
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
bundle :install
FileUtils.chmod(0o500, system_cache_path)
- bundle :clean, force: true, raise_on_error: false
+ bundle :clean, :force => true, :raise_on_error => false
expect(err).to include(system_gem_path.to_s)
expect(err).to include("grant write permissions")
gem_command :list
expect(out).to include("foo (1.0)")
- expect(out).to include("myrack (1.0.0)")
+ expect(out).to include("rack (1.0.0)")
end
end
@@ -576,7 +576,7 @@ RSpec.describe "bundle clean" do
revision = revision_for(lib_path("foo-1.0"))
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -612,7 +612,7 @@ RSpec.describe "bundle clean" do
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "bindir"
G
@@ -626,21 +626,25 @@ RSpec.describe "bundle clean" do
end
it "when using --force, it doesn't remove default gem binaries", :realworld do
- default_irb_version = ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", raise_on_error: false
+ skip "does not work on old rubies because the realworld gems that need to be installed don't support them" if RUBY_VERSION < "2.7.0"
+
+ skip "does not work on rubygems versions where `--install_dir` doesn't respect --default" unless Gem::Installer.for_spec(loaded_gemspec, :install_dir => "/foo").default_spec_file == "/foo/specifications/default/bundler-#{Bundler::VERSION}.gemspec" # Since rubygems 3.2.0.rc.2
+
+ default_irb_version = ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", :raise_on_error => false
skip "irb isn't a default gem" if default_irb_version.empty?
# simulate executable for default gem
- build_gem "irb", default_irb_version, to_system: true, default: true do |s|
+ build_gem "irb", default_irb_version, :to_system => true, :default => true do |s|
s.executables = "irb"
end
realworld_system_gems "tsort --version 0.1.0", "pathname --version 0.1.0", "set --version 1.0.1"
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
G
- bundle "clean --force", env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
+ bundle "clean --force", :env => { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
expect(out).not_to include("Removing irb")
end
@@ -654,7 +658,7 @@ RSpec.describe "bundle clean" do
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
gem "bar", "1.0", :path => "#{relative_path}"
@@ -667,7 +671,7 @@ RSpec.describe "bundle clean" do
it "doesn't remove gems in dry-run mode with path set" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "foo"
@@ -678,7 +682,7 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
G
@@ -690,14 +694,14 @@ RSpec.describe "bundle clean" do
expect(out).not_to include("Removing foo (1.0)")
expect(out).to include("Would have removed foo (1.0)")
- should_have_gems "thin-1.0", "myrack-1.0.0", "foo-1.0"
+ should_have_gems "thin-1.0", "rack-1.0.0", "foo-1.0"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "doesn't remove gems in dry-run mode with no path set" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "foo"
@@ -708,7 +712,7 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
G
@@ -720,14 +724,14 @@ RSpec.describe "bundle clean" do
expect(out).not_to include("Removing foo (1.0)")
expect(out).to include("Would have removed foo (1.0)")
- should_have_gems "thin-1.0", "myrack-1.0.0", "foo-1.0"
+ should_have_gems "thin-1.0", "rack-1.0.0", "foo-1.0"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "doesn't store dry run as a config setting" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "foo"
@@ -739,7 +743,7 @@ RSpec.describe "bundle clean" do
bundle "config set dry_run false"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
G
@@ -751,15 +755,15 @@ RSpec.describe "bundle clean" do
expect(out).to include("Removing foo (1.0)")
expect(out).not_to include("Would have removed foo (1.0)")
- should_have_gems "thin-1.0", "myrack-1.0.0"
+ should_have_gems "thin-1.0", "rack-1.0.0"
should_not_have_gems "foo-1.0"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "foo"
@@ -770,7 +774,7 @@ RSpec.describe "bundle clean" do
bundle "install"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "weakling"
@@ -779,7 +783,7 @@ RSpec.describe "bundle clean" do
bundle "config set auto_install 1"
bundle :clean
expect(out).to include("Installing weakling 0.0.3")
- should_have_gems "thin-1.0", "myrack-1.0.0", "weakling-0.0.3"
+ should_have_gems "thin-1.0", "rack-1.0.0", "weakling-0.0.3"
should_not_have_gems "foo-1.0"
end
@@ -789,7 +793,7 @@ RSpec.describe "bundle clean" do
revision = revision_for(lib_path("very_simple_git_binary-1.0"))
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}", :ref => "#{revision}"
G
@@ -808,7 +812,7 @@ RSpec.describe "bundle clean" do
it "removes extension directories" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "very_simple_binary"
@@ -828,7 +832,7 @@ RSpec.describe "bundle clean" do
expect(simple_binary_extensions_dir).to exist
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "simple_binary"
@@ -849,7 +853,7 @@ RSpec.describe "bundle clean" do
short_revision = revision[0..11]
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}", :ref => "#{revision}"
@@ -864,7 +868,7 @@ RSpec.describe "bundle clean" do
expect(very_simple_binary_extensions_dir).to exist
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}", :ref => "#{revision}"
G
@@ -874,7 +878,7 @@ RSpec.describe "bundle clean" do
expect(very_simple_binary_extensions_dir).to exist
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
bundle "install"
@@ -891,7 +895,7 @@ RSpec.describe "bundle clean" do
short_revision = revision[0..11]
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :development do
gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}", :ref => "#{revision}"
@@ -901,7 +905,7 @@ RSpec.describe "bundle clean" do
bundle :lock
bundle "config set without development"
bundle "config set path vendor/bundle"
- bundle "install", verbose: true
+ bundle "install"
bundle :clean
very_simple_binary_extensions_dir =
diff --git a/spec/bundler/commands/config_spec.rb b/spec/bundler/commands/config_spec.rb
index 1392b17315..ede93f99eb 100644
--- a/spec/bundler/commands/config_spec.rb
+++ b/spec/bundler/commands/config_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe ".bundle/config" do
context "with env overwrite" do
it "prints config with env" do
- bundle "config list --parseable", env: { "BUNDLE_FOO" => "bar3" }
+ bundle "config list --parseable", :env => { "BUNDLE_FOO" => "bar3" }
expect(out).to include("foo=bar3")
end
end
@@ -38,8 +38,8 @@ RSpec.describe ".bundle/config" do
describe "location with a gemfile" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
end
@@ -56,7 +56,7 @@ RSpec.describe ".bundle/config" do
expect(bundled_app(".bundle")).not_to exist
expect(tmp("foo/bar/config")).to exist
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "can provide a relative path with the environment variable" do
@@ -64,11 +64,11 @@ RSpec.describe ".bundle/config" do
ENV["BUNDLE_APP_CONFIG"] = "../foo"
bundle "config set --local path vendor/bundle"
- bundle "install", dir: bundled_app("omg")
+ bundle "install", :dir => bundled_app("omg")
expect(bundled_app(".bundle")).not_to exist
expect(bundled_app("../foo/config")).to exist
- expect(the_bundle).to include_gems "myrack 1.0.0", dir: bundled_app("omg")
+ expect(the_bundle).to include_gems "rack 1.0.0", :dir => bundled_app("omg")
end
end
@@ -79,14 +79,6 @@ RSpec.describe ".bundle/config" do
expect(home(".bundle/config")).to exist
end
- it "does not list global settings as local" do
- bundle "config set --global foo bar"
- bundle "config list", dir: home
-
- expect(out).to include("for the current user")
- expect(out).not_to include("for your local app")
- end
-
it "works with an absolute path" do
ENV["BUNDLE_APP_CONFIG"] = tmp("foo/bar").to_s
bundle "config set --local path vendor/bundle"
@@ -104,8 +96,8 @@ RSpec.describe ".bundle/config" do
end
it "can be configured through BUNDLE_USER_CONFIG" do
- bundle "config set path vendor", env: { "BUNDLE_USER_CONFIG" => bundle_user_config }
- bundle "config get path", env: { "BUNDLE_USER_CONFIG" => bundle_user_config }
+ bundle "config set path vendor", :env => { "BUNDLE_USER_CONFIG" => bundle_user_config }
+ bundle "config get path", :env => { "BUNDLE_USER_CONFIG" => bundle_user_config }
expect(out).to include("Set for the current user (#{bundle_user_config}): \"vendor\"")
end
@@ -113,8 +105,8 @@ RSpec.describe ".bundle/config" do
let(:bundle_user_home) { bundled_app(".bundle").to_s }
it "uses the right location" do
- bundle "config set path vendor", env: { "BUNDLE_USER_HOME" => bundle_user_home }
- bundle "config get path", env: { "BUNDLE_USER_HOME" => bundle_user_home }
+ bundle "config set path vendor", :env => { "BUNDLE_USER_HOME" => bundle_user_home }
+ bundle "config get path", :env => { "BUNDLE_USER_HOME" => bundle_user_home }
expect(out).to include("Set for the current user (#{bundle_user_home}/config): \"vendor\"")
end
end
@@ -123,8 +115,8 @@ RSpec.describe ".bundle/config" do
describe "global" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
end
@@ -215,8 +207,8 @@ RSpec.describe ".bundle/config" do
describe "local" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
end
@@ -271,8 +263,8 @@ RSpec.describe ".bundle/config" do
describe "env" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
end
@@ -344,8 +336,8 @@ RSpec.describe ".bundle/config" do
describe "gem mirrors" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
end
@@ -358,16 +350,10 @@ end
E
expect(out).to eq("http://gems.example.org/ => http://gem-mirror.example.org/")
end
-
- it "allows configuring fallback timeout for each mirror, and does not duplicate configs", rubygems: ">= 3.5.12" do
- bundle "config set --global mirror.https://rubygems.org.fallback_timeout 1"
- bundle "config set --global mirror.https://rubygems.org.fallback_timeout 2"
- expect(File.read(home(".bundle/config"))).to include("BUNDLE_MIRROR").once
- end
end
describe "quoting" do
- before(:each) { gemfile "source 'https://gem.repo1'" }
+ before(:each) { gemfile "source \"#{file_uri_for(gem_repo1)}\"" }
let(:long_string) do
"--with-xml2-include=/usr/pkg/include/libxml2 --with-xml2-lib=/usr/pkg/lib " \
"--with-xslt-dir=/usr/pkg"
@@ -417,8 +403,8 @@ E
describe "very long lines" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
end
@@ -453,11 +439,11 @@ E
it "does not make bundler crash and ignores the configuration" do
bundle "config list --parseable"
- expect(out).to be_empty
+ expect(out).to eq("#mirror.https://rails-assets.org/=http://localhost:9292")
expect(err).to be_empty
ruby(<<~RUBY)
- require "bundler"
+ require "#{entrypoint}"
print Bundler.settings.mirror_for("https://rails-assets.org")
RUBY
expect(out).to eq("https://rails-assets.org/")
@@ -465,7 +451,7 @@ E
bundle "config set mirror.all http://localhost:9293"
ruby(<<~RUBY)
- require "bundler"
+ require "#{entrypoint}"
print Bundler.settings.mirror_for("https://rails-assets.org")
RUBY
expect(out).to eq("http://localhost:9293/")
@@ -475,26 +461,26 @@ E
describe "subcommands" do
it "list" do
- bundle "config list", env: { "BUNDLE_FOO" => "bar" }
+ bundle "config list", :env => { "BUNDLE_FOO" => "bar" }
expect(out).to eq "Settings are listed in order of priority. The top value will be used.\nfoo\nSet via BUNDLE_FOO: \"bar\""
- bundle "config list", env: { "BUNDLE_FOO" => "bar" }, parseable: true
+ bundle "config list", :env => { "BUNDLE_FOO" => "bar" }, :parseable => true
expect(out).to eq "foo=bar"
end
it "list with credentials" do
- bundle "config list", env: { "BUNDLE_GEMS__MYSERVER__COM" => "user:password" }
+ bundle "config list", :env => { "BUNDLE_GEMS__MYSERVER__COM" => "user:password" }
expect(out).to eq "Settings are listed in order of priority. The top value will be used.\ngems.myserver.com\nSet via BUNDLE_GEMS__MYSERVER__COM: \"user:[REDACTED]\""
- bundle "config list", parseable: true, env: { "BUNDLE_GEMS__MYSERVER__COM" => "user:password" }
+ bundle "config list", :parseable => true, :env => { "BUNDLE_GEMS__MYSERVER__COM" => "user:password" }
expect(out).to eq "gems.myserver.com=user:password"
end
it "list with API token credentials" do
- bundle "config list", env: { "BUNDLE_GEMS__MYSERVER__COM" => "api_token:x-oauth-basic" }
+ bundle "config list", :env => { "BUNDLE_GEMS__MYSERVER__COM" => "api_token:x-oauth-basic" }
expect(out).to eq "Settings are listed in order of priority. The top value will be used.\ngems.myserver.com\nSet via BUNDLE_GEMS__MYSERVER__COM: \"[REDACTED]:x-oauth-basic\""
- bundle "config list", parseable: true, env: { "BUNDLE_GEMS__MYSERVER__COM" => "api_token:x-oauth-basic" }
+ bundle "config list", :parseable => true, :env => { "BUNDLE_GEMS__MYSERVER__COM" => "api_token:x-oauth-basic" }
expect(out).to eq "gems.myserver.com=api_token:x-oauth-basic"
end
@@ -529,7 +515,7 @@ E
bundle "config set --local foo 4.1"
expect(out).to eq "You are replacing the current local value of foo, which is currently \"4\""
- bundle "config set --global --local foo 5", raise_on_error: false
+ bundle "config set --global --local foo 5", :raise_on_error => false
expect(last_command).to be_failure
expect(err).to eq "The options global and local were specified. Please only use one of the switches at a time."
end
@@ -569,7 +555,7 @@ E
expect(out).to eq ""
expect(bundle("config get foo")).to eq "Settings for `foo` in order of priority. The top value will be used\nYou have not configured a value for `foo`"
- bundle "config unset foo --local --global", raise_on_error: false
+ bundle "config unset foo --local --global", :raise_on_error => false
expect(last_command).to be_failure
expect(err).to eq "The options global and local were specified. Please only use one of the switches at a time."
end
@@ -580,8 +566,8 @@ RSpec.describe "setting gemfile via config" do
context "when only the non-default Gemfile exists" do
it "persists the gemfile location to .bundle/config" do
gemfile bundled_app("NotGemfile"), <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
bundle "config set --local gemfile #{bundled_app("NotGemfile")}"
diff --git a/spec/bundler/commands/console_spec.rb b/spec/bundler/commands/console_spec.rb
index 8b02e7aa1b..aa76096e3d 100644
--- a/spec/bundler/commands/console_spec.rb
+++ b/spec/bundler/commands/console_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "bundle console", bundler: "< 3", readline: true do
+RSpec.describe "bundle console", :bundler => "< 3", :readline => true do
before :each do
build_repo2 do
# A minimal fake pry console
@@ -38,16 +38,16 @@ RSpec.describe "bundle console", bundler: "< 3", readline: true do
end
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
G
end
it "starts IRB with the default group loaded" do
bundle "console" do |input, _, _|
- input.puts("puts MYRACK")
+ input.puts("puts RACK")
input.puts("exit")
end
expect(out).to include("0.9.1")
@@ -63,7 +63,7 @@ RSpec.describe "bundle console", bundler: "< 3", readline: true do
it "starts another REPL if configured as such" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "pry"
G
bundle "config set console pry"
@@ -105,7 +105,7 @@ RSpec.describe "bundle console", bundler: "< 3", readline: true do
it "loads the default group" do
bundle "console test" do |input, _, _|
- input.puts("puts MYRACK")
+ input.puts("puts RACK")
input.puts("exit")
end
expect(out).to include("0.9.1")
@@ -113,7 +113,7 @@ RSpec.describe "bundle console", bundler: "< 3", readline: true do
it "doesn't load other groups" do
bundle "console test" do |input, _, _|
- input.puts("puts MYRACK_MIDDLEWARE")
+ input.puts("puts RACK_MIDDLEWARE")
input.puts("exit")
end
expect(out).to include("NameError")
@@ -122,10 +122,10 @@ RSpec.describe "bundle console", bundler: "< 3", readline: true do
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
gem "foo"
G
diff --git a/spec/bundler/commands/doctor_spec.rb b/spec/bundler/commands/doctor_spec.rb
index 744510cd40..1afac00923 100644
--- a/spec/bundler/commands/doctor_spec.rb
+++ b/spec/bundler/commands/doctor_spec.rb
@@ -8,8 +8,8 @@ require "bundler/cli/doctor"
RSpec.describe "bundle doctor" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
@stdout = StringIO.new
@@ -38,11 +38,6 @@ RSpec.describe "bundle doctor" do
allow(stat).to receive(:uid) { Process.uid }
allow(File).to receive(:writable?).with(unwritable_file) { true }
allow(File).to receive(:readable?).with(unwritable_file) { true }
-
- # The following lines are for `Gem::PathSupport#initialize`.
- allow(File).to receive(:exist?).with(Gem.default_dir)
- allow(File).to receive(:writable?).with(Gem.default_dir)
- allow(File).to receive(:writable?).with(File.expand_path("..", Gem.default_dir))
end
it "exits with no message if the installed gem has no C extensions" do
@@ -52,7 +47,7 @@ RSpec.describe "bundle doctor" do
it "exits with no message if the installed gem's C extension dylib breakage is fine" do
doctor = Bundler::CLI::Doctor.new({})
- expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/myrack/myrack.bundle"]
+ expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"]
expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/lib/libSystem.dylib"]
allow(Fiddle).to receive(:dlopen).with("/usr/lib/libSystem.dylib").and_return(true)
expect { doctor.run }.not_to raise_error
@@ -61,13 +56,13 @@ RSpec.describe "bundle doctor" do
it "exits with a message if one of the linked libraries is missing" do
doctor = Bundler::CLI::Doctor.new({})
- expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/myrack/myrack.bundle"]
+ expect(doctor).to receive(:bundles_for_gem).exactly(2).times.and_return ["/path/to/rack/rack.bundle"]
expect(doctor).to receive(:dylibs).exactly(2).times.and_return ["/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib"]
allow(Fiddle).to receive(:dlopen).with("/usr/local/opt/icu4c/lib/libicui18n.57.1.dylib").and_raise(Fiddle::DLError)
- expect { doctor.run }.to raise_error(Bundler::ProductionError, <<~E.strip), @stdout.string
+ expect { doctor.run }.to raise_error(Bundler::ProductionError, strip_whitespace(<<-E).strip), @stdout.string
The following gems are missing OS dependencies:
* bundler: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib
- * myrack: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib
+ * rack: /usr/local/opt/icu4c/lib/libicui18n.57.1.dylib
E
end
end
diff --git a/spec/bundler/commands/exec_spec.rb b/spec/bundler/commands/exec_spec.rb
index 4f87f3c38d..099cdb39fa 100644
--- a/spec/bundler/commands/exec_spec.rb
+++ b/spec/bundler/commands/exec_spec.rb
@@ -1,99 +1,116 @@
# frozen_string_literal: true
RSpec.describe "bundle exec" do
- let(:system_gems_to_install) { %w[myrack-1.0.0 myrack-0.9.1] }
+ let(:system_gems_to_install) { %w[rack-1.0.0 rack-0.9.1] }
it "works with --gemfile flag" do
- system_gems(system_gems_to_install, path: default_bundle_path)
+ system_gems(system_gems_to_install, :path => default_bundle_path)
- gemfile "CustomGemfile", <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ create_file "CustomGemfile", <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
- bundle "exec --gemfile CustomGemfile myrackup"
+ bundle "exec --gemfile CustomGemfile rackup"
expect(out).to eq("1.0.0")
end
it "activates the correct gem" do
- system_gems(system_gems_to_install, path: default_bundle_path)
+ system_gems(system_gems_to_install, :path => default_bundle_path)
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to eq("0.9.1")
end
it "works and prints no warnings when HOME is not writable" do
- system_gems(system_gems_to_install, path: default_bundle_path)
+ system_gems(system_gems_to_install, :path => default_bundle_path)
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- bundle "exec myrackup", env: { "HOME" => "/" }
+ bundle "exec rackup", :env => { "HOME" => "/" }
expect(out).to eq("0.9.1")
expect(err).to be_empty
end
it "works when the bins are in ~/.bundle" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to eq("1.0.0")
end
it "works when running from a random directory" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "exec 'cd #{tmp("gems")} && myrackup'"
+ bundle "exec 'cd #{tmp("gems")} && rackup'"
expect(out).to eq("1.0.0")
end
it "works when exec'ing something else" do
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
bundle "exec echo exec"
expect(out).to eq("exec")
end
it "works when exec'ing to ruby" do
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
bundle "exec ruby -e 'puts %{hi}'"
expect(out).to eq("hi")
end
it "works when exec'ing to rubygems" do
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
bundle "exec #{gem_cmd} --version"
expect(out).to eq(Gem::VERSION)
end
it "works when exec'ing to rubygems through sh -c" do
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
bundle "exec sh -c '#{gem_cmd} --version'"
expect(out).to eq(Gem::VERSION)
end
- it "works when exec'ing back to bundler to run a remote resolve" do
+ it "works when exec'ing back to bundler with a lockfile that doesn't include the current platform" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- bundle "exec bundle lock", env: { "BUNDLER_VERSION" => Bundler::VERSION }
+ # simulate lockfile generated with old version not including specific platform
+ lockfile <<-L
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
+ rack (0.9.1)
- expect(out).to include("Writing lockfile")
+ PLATFORMS
+ RUBY
+
+ DEPENDENCIES
+ rack (= 0.9.1)
+
+ BUNDLED WITH
+ 2.1.4
+ L
+
+ bundle "exec bundle cache", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+
+ expect(out).to include("Updating files in vendor/cache")
end
it "respects custom process title when loading through ruby" do
@@ -103,20 +120,20 @@ RSpec.describe "bundle exec" do
Process.setproctitle("1-2-3-4-5-6-7")
puts `ps -ocommand= -p#{$$}`
RUBY
- gemfile "Gemfile", "source \"https://gem.repo1\""
+ create_file "Gemfile", "source \"#{file_uri_for(gem_repo1)}\""
create_file "a.rb", script_that_changes_its_own_title_and_checks_if_picked_up_by_ps_unix_utility
bundle "exec ruby a.rb"
expect(out).to eq("1-2-3-4-5-6-7")
end
it "accepts --verbose" do
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
bundle "exec --verbose echo foobar"
expect(out).to eq("foobar")
end
it "passes --verbose to command if it is given after the command" do
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
bundle "exec echo --verbose"
expect(out).to eq("--verbose")
end
@@ -140,7 +157,7 @@ RSpec.describe "bundle exec" do
end
G
- install_gemfile "source \"https://gem.repo1\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
sys_exec "#{Gem.ruby} #{command.path}"
expect(out).to be_empty
@@ -148,7 +165,7 @@ RSpec.describe "bundle exec" do
end
it "accepts --keep-file-descriptors" do
- install_gemfile "source \"https://gem.repo1\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
bundle "exec --keep-file-descriptors echo foobar"
expect(err).to be_empty
@@ -157,7 +174,7 @@ RSpec.describe "bundle exec" do
it "can run a command named --verbose" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
- install_gemfile "source \"https://gem.repo1\"; gem \"myrack\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"; gem \"rack\""
File.open(bundled_app("--verbose"), "w") do |f|
f.puts "#!/bin/sh"
f.puts "echo foobar"
@@ -171,37 +188,37 @@ RSpec.describe "bundle exec" do
it "handles different versions in different bundles" do
build_repo2 do
- build_gem "myrack_two", "1.0.0" do |s|
- s.executables = "myrackup"
+ build_gem "rack_two", "1.0.0" do |s|
+ s.executables = "rackup"
end
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- install_gemfile bundled_app2("Gemfile"), <<-G, dir: bundled_app2
- source "https://gem.repo2"
- gem "myrack_two", "1.0.0"
+ install_gemfile bundled_app2("Gemfile"), <<-G, :dir => bundled_app2
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack_two", "1.0.0"
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to eq("0.9.1")
- bundle "exec myrackup", dir: bundled_app2
+ bundle "exec rackup", :dir => bundled_app2
expect(out).to eq("1.0.0")
end
context "with default gems" do
- let(:default_irb_version) { ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", raise_on_error: false }
+ let(:default_irb_version) { ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", :raise_on_error => false }
context "when not specified in Gemfile" do
before do
skip "irb isn't a default gem" if default_irb_version.empty?
- install_gemfile "source \"https://gem.repo1\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
end
it "uses version provided by ruby" do
@@ -224,7 +241,7 @@ RSpec.describe "bundle exec" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "irb", "#{specified_irb_version}"
G
end
@@ -254,7 +271,7 @@ RSpec.describe "bundle exec" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "gem_depending_on_old_irb"
G
@@ -270,54 +287,54 @@ RSpec.describe "bundle exec" do
it "warns about executable conflicts" do
build_repo2 do
- build_gem "myrack_two", "1.0.0" do |s|
- s.executables = "myrackup"
+ build_gem "rack_two", "1.0.0" do |s|
+ s.executables = "rackup"
end
end
bundle "config set --global path.system true"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- install_gemfile bundled_app2("Gemfile"), <<-G, dir: bundled_app2
- source "https://gem.repo2"
- gem "myrack_two", "1.0.0"
+ install_gemfile bundled_app2("Gemfile"), <<-G, :dir => bundled_app2
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack_two", "1.0.0"
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(last_command.stderr).to eq(
- "Bundler is using a binstub that was created for a different gem (myrack).\n" \
- "You should run `bundle binstub myrack_two` to work around a system/bundle conflict."
+ "Bundler is using a binstub that was created for a different gem (rack).\n" \
+ "You should run `bundle binstub rack_two` to work around a system/bundle conflict."
)
end
it "handles gems installed with --without" do
bundle "config set --local without middleware"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack" # myrack 0.9.1 and 1.0 exist
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack" # rack 0.9.1 and 1.0 exist
group :middleware do
- gem "myrack_middleware" # myrack_middleware depends on myrack 0.9.1
+ gem "rack_middleware" # rack_middleware depends on rack 0.9.1
end
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to eq("0.9.1")
- expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
+ expect(the_bundle).not_to include_gems "rack_middleware 1.0"
end
it "does not duplicate already exec'ed RUBYOPT" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundler_setup_opt = "-r#{lib_dir}/bundler/setup"
@@ -327,7 +344,7 @@ RSpec.describe "bundle exec" do
bundle "exec 'echo $RUBYOPT'"
expect(out.split(" ").count(bundler_setup_opt)).to eq(1)
- bundle "exec 'echo $RUBYOPT'", env: { "RUBYOPT" => rubyopt }
+ bundle "exec 'echo $RUBYOPT'", :env => { "RUBYOPT" => rubyopt }
expect(out.split(" ").count(bundler_setup_opt)).to eq(1)
end
@@ -335,8 +352,8 @@ RSpec.describe "bundle exec" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
rubylib = ENV["RUBYLIB"]
@@ -346,17 +363,17 @@ RSpec.describe "bundle exec" do
bundle "exec 'echo $RUBYLIB'"
expect(out).to include(rubylib)
- bundle "exec 'echo $RUBYLIB'", env: { "RUBYLIB" => rubylib }
+ bundle "exec 'echo $RUBYLIB'", :env => { "RUBYLIB" => rubylib }
expect(out).to include(rubylib)
end
it "errors nicely when the argument doesn't exist" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "exec foobarbaz", raise_on_error: false
+ bundle "exec foobarbaz", :raise_on_error => false
expect(exitstatus).to eq(127)
expect(err).to include("bundler: command not found: foobarbaz")
expect(err).to include("Install missing gem executables with `bundle install`")
@@ -364,39 +381,39 @@ RSpec.describe "bundle exec" do
it "errors nicely when the argument is not executable" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "exec touch foo"
- bundle "exec ./foo", raise_on_error: false
+ bundle "exec ./foo", :raise_on_error => false
expect(exitstatus).to eq(126)
expect(err).to include("bundler: not executable: ./foo")
end
it "errors nicely when no arguments are passed" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "exec", raise_on_error: false
+ bundle "exec", :raise_on_error => false
expect(exitstatus).to eq(128)
expect(err).to include("bundler: exec needs a command to run")
end
it "raises a helpful error when exec'ing to something outside of the bundle" do
- system_gems(system_gems_to_install, path: default_bundle_path)
+ system_gems(system_gems_to_install, :path => default_bundle_path)
- bundle "config set clean false" # want to keep the myrackup binstub
+ bundle "config set clean false" # want to keep the rackup binstub
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
[true, false].each do |l|
bundle "config set disable_exec_load #{l}"
- bundle "exec myrackup", raise_on_error: false
- expect(err).to include "can't find executable myrackup for gem myrack. myrack is not currently included in the bundle, perhaps you meant to add it to your Gemfile?"
+ bundle "exec rackup", :raise_on_error => false
+ expect(err).to include "can't find executable rackup for gem rack. rack is not currently included in the bundle, perhaps you meant to add it to your Gemfile?"
end
end
@@ -410,8 +427,8 @@ RSpec.describe "bundle exec" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
create_file("print_args", <<-'RUBY')
@@ -495,31 +512,31 @@ RSpec.describe "bundle exec" do
describe "run from a random directory" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
it "works when unlocked" do
- bundle "exec 'cd #{tmp("gems")} && myrackup'"
+ bundle "exec 'cd #{tmp("gems")} && rackup'"
expect(out).to eq("1.0.0")
end
it "works when locked" do
expect(the_bundle).to be_locked
- bundle "exec 'cd #{tmp("gems")} && myrackup'"
+ bundle "exec 'cd #{tmp("gems")} && rackup'"
expect(out).to eq("1.0.0")
end
end
describe "from gems bundled via :path" do
before(:each) do
- build_lib "fizz", path: home("fizz") do |s|
+ build_lib "fizz", :path => home("fizz") do |s|
s.executables = "fizz"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "fizz", :path => "#{File.expand_path(home("fizz"))}"
G
end
@@ -544,7 +561,7 @@ RSpec.describe "bundle exec" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "fizz_git", :git => "#{lib_path("fizz_git-1.0")}"
G
end
@@ -563,12 +580,12 @@ RSpec.describe "bundle exec" do
describe "from gems bundled via :git with no gemspec" do
before(:each) do
- build_git "fizz_no_gemspec", gemspec: false do |s|
+ build_git "fizz_no_gemspec", :gemspec => false do |s|
s.executables = "fizz_no_gemspec"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "fizz_no_gemspec", "1.0", :git => "#{lib_path("fizz_no_gemspec-1.0")}"
G
end
@@ -588,34 +605,21 @@ RSpec.describe "bundle exec" do
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
gem "foo"
G
bundle "config set auto_install 1"
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to include("Installing foo 1.0")
end
- it "performs an automatic bundle install with git gems" do
- build_git "foo" do |s|
- s.executables = "foo"
+ it "loads the correct optparse when `auto_install` is set, and optparse is a dependency" do
+ if Gem.ruby_version >= Gem::Version.new("3.0.0") && Gem.rubygems_version < Gem::Version.new("3.3.0.a")
+ skip "optparse is a default gem, and rubygems loads it during install"
end
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
- gem "foo", :git => "#{lib_path("foo-1.0")}"
- G
-
- bundle "config set auto_install 1"
- bundle "exec foo"
- expect(out).to include("Fetching myrack 0.9.1")
- expect(out).to include("Fetching #{lib_path("foo-1.0")}")
- expect(out.lines).to end_with("1.0")
- end
- it "loads the correct optparse when `auto_install` is set, and optparse is a dependency" do
build_repo4 do
build_gem "fastlane", "2.192.0" do |s|
s.executables = "fastlane"
@@ -626,13 +630,13 @@ RSpec.describe "bundle exec" do
build_gem "optparse", "999.999.999"
end
- system_gems "optparse-999.999.998", gem_repo: gem_repo4
+ system_gems "optparse-999.999.998", :gem_repo => gem_repo4
bundle "config set auto_install 1"
bundle "config set --local path vendor/bundle"
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "fastlane"
G
@@ -653,20 +657,19 @@ RSpec.describe "bundle exec" do
s.version = '1.0'
s.summary = 'TODO: Add summary'
s.authors = 'Me'
- s.rubygems_version = nil
end
G
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
- bundle "exec irb", raise_on_error: false
+ bundle "exec irb", :raise_on_error => false
expect(err).to match("The gemspec at #{lib_path("foo-1.0").join("foo.gemspec")} is not valid")
- expect(err).to match(/missing value for attribute rubygems_version|rubygems_version must not be nil/)
+ expect(err).to match('"TODO" is not a summary')
end
end
@@ -675,7 +678,7 @@ RSpec.describe "bundle exec" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
module Monkey
def bin_path(a,b,c)
@@ -686,69 +689,50 @@ RSpec.describe "bundle exec" do
G
bundle "config set path.system true"
bundle "install"
- bundle "exec ruby -e '`bundle -v`; puts $?.success?'", env: { "BUNDLER_VERSION" => Bundler::VERSION }
+ bundle "exec ruby -e '`bundle -v`; puts $?.success?'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
expect(out).to match("true")
end
end
- describe "bundle exec gem uninstall" do
- before do
- build_repo4 do
- build_gem "foo"
- end
-
- install_gemfile <<-G
- source "https://gem.repo4"
-
- gem "foo"
- G
- end
-
- it "works" do
- bundle "exec #{gem_cmd} uninstall foo"
- expect(out).to eq("Successfully uninstalled foo-1.0")
- end
- end
-
context "`load`ing a ruby file instead of `exec`ing" do
let(:path) { bundled_app("ruby_executable") }
let(:shebang) { "#!/usr/bin/env ruby" }
- let(:executable) { <<~RUBY.strip }
+ let(:executable) { <<-RUBY.gsub(/^ */, "").strip }
#{shebang}
- require "myrack"
+ require "rack"
puts "EXEC: \#{caller.grep(/load/).empty? ? 'exec' : 'load'}"
puts "ARGS: \#{$0} \#{ARGV.join(' ')}"
- puts "MYRACK: \#{MYRACK}"
+ puts "RACK: \#{RACK}"
process_title = `ps -o args -p \#{Process.pid}`.split("\n", 2).last.strip
puts "PROCESS: \#{process_title}"
RUBY
before do
- system_gems(system_gems_to_install, path: default_bundle_path)
+ system_gems(system_gems_to_install, :path => default_bundle_path)
bundled_app(path).open("w") {|f| f << executable }
bundled_app(path).chmod(0o755)
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
let(:exec) { "EXEC: load" }
let(:args) { "ARGS: #{path} arg1 arg2" }
- let(:myrack) { "MYRACK: 1.0.0" }
+ let(:rack) { "RACK: 1.0.0" }
let(:process) do
title = "PROCESS: #{path}"
title += " arg1 arg2"
title
end
let(:exit_code) { 0 }
- let(:expected) { [exec, args, myrack, process].join("\n") }
+ let(:expected) { [exec, args, rack, process].join("\n") }
let(:expected_err) { "" }
- subject { bundle "exec #{path} arg1 arg2", raise_on_error: false }
+ subject { bundle "exec #{path} arg1 arg2", :raise_on_error => false }
it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
@@ -830,7 +814,8 @@ RSpec.describe "bundle exec" do
let(:executable) { super() << "\nraise 'ERROR'" }
let(:exit_code) { 1 }
let(:expected_err) do
- /\Abundler: failed to load command: #{Regexp.quote(path.to_s)} \(#{Regexp.quote(path.to_s)}\)\n#{Regexp.quote(path.to_s)}:10:in [`']<top \(required\)>': ERROR \(RuntimeError\)/
+ "bundler: failed to load command: #{path} (#{path})" \
+ "\n#{path}:10:in `<top (required)>': ERROR (RuntimeError)"
end
it "runs like a normally executed executable" do
@@ -838,7 +823,7 @@ RSpec.describe "bundle exec" do
subject
expect(exitstatus).to eq(exit_code)
- expect(err).to match(expected_err)
+ expect(err).to start_with(expected_err)
expect(out).to eq(expected)
end
end
@@ -872,11 +857,11 @@ RSpec.describe "bundle exec" do
end
end
- context "when Bundler.setup fails", bundler: "< 3" do
+ context "when Bundler.setup fails", :bundler => "< 3" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack', '2'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', '2'
G
ENV["BUNDLER_FORCE_TTY"] = "true"
end
@@ -884,11 +869,11 @@ RSpec.describe "bundle exec" do
let(:exit_code) { Bundler::GemNotFound.new.status_code }
let(:expected) { "" }
let(:expected_err) { <<-EOS.strip }
-Could not find gem 'myrack (= 2)' in locally installed gems.
+Could not find gem 'rack (= 2)' in locally installed gems.
-The source contains the following gems matching 'myrack':
- * myrack-0.9.1
- * myrack-1.0.0
+The source contains the following gems matching 'rack':
+ * rack-0.9.1
+ * rack-1.0.0
Run `bundle install` to install missing gems.
EOS
@@ -902,11 +887,11 @@ Run `bundle install` to install missing gems.
end
end
- context "when Bundler.setup fails", bundler: "3" do
+ context "when Bundler.setup fails", :bundler => "3" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack', '2'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', '2'
G
ENV["BUNDLER_FORCE_TTY"] = "true"
end
@@ -914,10 +899,10 @@ Run `bundle install` to install missing gems.
let(:exit_code) { Bundler::GemNotFound.new.status_code }
let(:expected) { "" }
let(:expected_err) { <<-EOS.strip }
-Could not find gem 'myrack (= 2)' in locally installed gems.
+Could not find gem 'rack (= 2)' in locally installed gems.
-The source contains the following gems matching 'myrack':
- * myrack-1.0.0
+The source contains the following gems matching 'rack':
+ * rack-1.0.0
Run `bundle install` to install missing gems.
EOS
@@ -933,9 +918,9 @@ Run `bundle install` to install missing gems.
context "when Bundler.setup fails and Gemfile is not the default" do
before do
- gemfile "CustomGemfile", <<-G
- source "https://gem.repo1"
- gem 'myrack', '2'
+ create_file "CustomGemfile", <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', '2'
G
ENV["BUNDLER_FORCE_TTY"] = "true"
ENV["BUNDLE_GEMFILE"] = "CustomGemfile"
@@ -1039,7 +1024,7 @@ __FILE__: #{path.to_s.inspect}
end
context "signals being trapped by bundler" do
- let(:executable) { <<~RUBY }
+ let(:executable) { strip_whitespace <<-RUBY }
#{shebang}
begin
Thread.new do
@@ -1066,7 +1051,7 @@ __FILE__: #{path.to_s.inspect}
end
context "signals not being trapped by bunder" do
- let(:executable) { <<~RUBY }
+ let(:executable) { strip_whitespace <<-RUBY }
#{shebang}
signals = #{test_signals.inspect}
@@ -1097,8 +1082,8 @@ __FILE__: #{path.to_s.inspect}
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set path vendor/bundler"
bundle :install
@@ -1111,7 +1096,7 @@ __FILE__: #{path.to_s.inspect}
puts `bundle exec echo foo`
RUBY
file.chmod(0o777)
- bundle "exec #{file}", env: { "PATH" => path }
+ bundle "exec #{file}", :env => { "PATH" => path }
expect(out).to eq("foo")
end
end
@@ -1120,7 +1105,7 @@ __FILE__: #{path.to_s.inspect}
before do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
- install_gemfile "source \"https://gem.repo1\""
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
end
it "does not undo the monkeypatches" do
@@ -1170,18 +1155,18 @@ __FILE__: #{path.to_s.inspect}
end
bundle "config set path vendor/bundle"
- bundle "config set gemfile gemfiles/myrack_6_1.gemfile"
+ bundle "config set gemfile gemfiles/rack_6_1.gemfile"
- gemfile(bundled_app("gemfiles/myrack_6_1.gemfile"), <<~RUBY)
- source "https://gem.repo2"
+ create_file(bundled_app("gemfiles/rack_6_1.gemfile"), <<~RUBY)
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "6.1.0"
RUBY
# A Gemfile needs to be in the root to trick bundler's root resolution
- gemfile "source 'https://gem.repo1'"
+ create_file(bundled_app("Gemfile"), "source \"#{file_uri_for(gem_repo1)}\"")
- bundle "install", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ bundle "install"
end
it "can still find gems after a nested subprocess" do
@@ -1204,13 +1189,13 @@ __FILE__: #{path.to_s.inspect}
context "with a system gem that shadows a default gem" do
let(:openssl_version) { "99.9.9" }
- let(:expected) { ruby "gem 'openssl', '< 999999'; require 'openssl'; puts OpenSSL::VERSION", artifice: nil, raise_on_error: false }
+ let(:expected) { ruby "gem 'openssl', '< 999999'; require 'openssl'; puts OpenSSL::VERSION", :artifice => nil, :raise_on_error => false }
it "only leaves the default gem in the stdlib available" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
skip "openssl isn't a default gem" if expected.empty?
- install_gemfile "source \"https://gem.repo1\"" # must happen before installing the broken system gem
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\"" # must happen before installing the broken system gem
build_repo4 do
build_gem "openssl", openssl_version do |s|
@@ -1220,7 +1205,7 @@ __FILE__: #{path.to_s.inspect}
end
end
- system_gems("openssl-#{openssl_version}", gem_repo: gem_repo4)
+ system_gems("openssl-#{openssl_version}", :gem_repo => gem_repo4)
file = bundled_app("require_openssl.rb")
create_file(file, <<-RUBY)
@@ -1233,15 +1218,15 @@ __FILE__: #{path.to_s.inspect}
env = { "PATH" => path }
aggregate_failures do
- expect(bundle("exec #{file}", artifice: nil, env: env)).to eq(expected)
- expect(bundle("exec bundle exec #{file}", artifice: nil, env: env)).to eq(expected)
- expect(bundle("exec ruby #{file}", artifice: nil, env: env)).to eq(expected)
- expect(run(file.read, artifice: nil, env: env)).to eq(expected)
+ expect(bundle("exec #{file}", :artifice => nil, :env => env)).to eq(expected)
+ expect(bundle("exec bundle exec #{file}", :artifice => nil, :env => env)).to eq(expected)
+ expect(bundle("exec ruby #{file}", :artifice => nil, :env => env)).to eq(expected)
+ expect(run(file.read, :artifice => nil, :env => env)).to eq(expected)
end
skip "ruby_core has openssl and rubygems in the same folder, and this test needs rubygems require but default openssl not in a directly added entry in $LOAD_PATH" if ruby_core?
# sanity check that we get the newer, custom version without bundler
- sys_exec "#{Gem.ruby} #{file}", env: env, raise_on_error: false
+ sys_exec "#{Gem.ruby} #{file}", :env => env, :raise_on_error => false
expect(err).to include("custom openssl should not be loaded")
end
end
@@ -1251,7 +1236,7 @@ __FILE__: #{path.to_s.inspect}
build_git "simple_git_binary", &:add_c_extension
bundle "config set --local path .bundle"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "simple_git_binary", :git => '#{lib_path("simple_git_binary-1.0")}'
G
end
diff --git a/spec/bundler/commands/fund_spec.rb b/spec/bundler/commands/fund_spec.rb
index 6f4e61da30..5415b88eeb 100644
--- a/spec/bundler/commands/fund_spec.rb
+++ b/spec/bundler/commands/fund_spec.rb
@@ -30,22 +30,22 @@ RSpec.describe "bundle fund" do
it "prints fund information for all gems in the bundle" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding_and_other_metadata'
gem 'has_funding'
- gem 'myrack-obama'
+ gem 'rack-obama'
G
bundle "fund"
expect(out).to include("* has_funding_and_other_metadata (1.0)\n Funding: https://example.com/has_funding_and_other_metadata/funding")
expect(out).to include("* has_funding (1.2.3)\n Funding: https://example.com/has_funding/funding")
- expect(out).to_not include("myrack-obama")
+ expect(out).to_not include("rack-obama")
end
it "does not consider fund information for gem dependencies" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'gem_with_dependent_funding'
G
@@ -55,46 +55,10 @@ RSpec.describe "bundle fund" do
expect(out).to_not include("gem_with_dependent_funding")
end
- it "does not consider fund information for uninstalled optional dependencies" do
- install_gemfile <<-G
- source "https://gem.repo2"
- group :whatever, optional: true do
- gem 'has_funding_and_other_metadata'
- end
- gem 'has_funding'
- gem 'myrack-obama'
- G
-
- bundle "fund"
-
- expect(out).to include("* has_funding (1.2.3)\n Funding: https://example.com/has_funding/funding")
- expect(out).to_not include("has_funding_and_other_metadata")
- expect(out).to_not include("myrack-obama")
- end
-
- it "considers fund information for installed optional dependencies" do
- bundle "config set with whatever"
-
- install_gemfile <<-G
- source "https://gem.repo2"
- group :whatever, optional: true do
- gem 'has_funding_and_other_metadata'
- end
- gem 'has_funding'
- gem 'myrack-obama'
- G
-
- bundle "fund"
-
- expect(out).to include("* has_funding_and_other_metadata (1.0)\n Funding: https://example.com/has_funding_and_other_metadata/funding")
- expect(out).to include("* has_funding (1.2.3)\n Funding: https://example.com/has_funding/funding")
- expect(out).to_not include("myrack-obama")
- end
-
it "prints message if none of the gems have fund information" do
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack-obama'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack-obama'
G
bundle "fund"
@@ -105,7 +69,7 @@ RSpec.describe "bundle fund" do
describe "with --group option" do
it "prints fund message for only specified group gems" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding_and_other_metadata', :group => :development
gem 'has_funding'
G
diff --git a/spec/bundler/commands/help_spec.rb b/spec/bundler/commands/help_spec.rb
index 0c7031e813..409c49f9e1 100644
--- a/spec/bundler/commands/help_spec.rb
+++ b/spec/bundler/commands/help_spec.rb
@@ -15,13 +15,6 @@ RSpec.describe "bundle help" do
expect(out).to eq(%(["#{man_dir}/bundle-install.1"]))
end
- it "prexifes bundle commands with bundle- and resolves aliases when finding the man files" do
- with_fake_man do
- bundle "help package"
- end
- expect(out).to eq(%(["#{man_dir}/bundle-cache.1"]))
- end
-
it "simply outputs the human readable file when there is no man on the path" do
with_path_as("") do
bundle "help install"
@@ -78,7 +71,7 @@ RSpec.describe "bundle help" do
it "has helpful output when using --help flag for a non-existent command" do
with_fake_man do
- bundle "instill -h", raise_on_error: false
+ bundle "instill -h", :raise_on_error => false
end
expect(err).to include('Could not find command "instill".')
end
diff --git a/spec/bundler/commands/info_spec.rb b/spec/bundler/commands/info_spec.rb
index 42f288a1d8..851f50240f 100644
--- a/spec/bundler/commands/info_spec.rb
+++ b/spec/bundler/commands/info_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe "bundle info" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
gem "has_metadata"
gem "thin"
@@ -65,7 +65,7 @@ RSpec.describe "bundle info" do
end
it "complains if gem not in bundle" do
- bundle "info missing", raise_on_error: false
+ bundle "info missing", :raise_on_error => false
expect(err).to eq("Could not find gem 'missing'.")
end
@@ -74,16 +74,16 @@ RSpec.describe "bundle info" do
bundle "info rails --path"
- expect(err).to include("The gem rails has been deleted.")
- expect(err).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
+ expect(err).to match(/The gem rails has been deleted/i)
+ expect(err).to match(default_bundle_path("gems", "rails-2.3.2").to_s)
bundle "info rail --path"
- expect(err).to include("The gem rails has been deleted.")
- expect(err).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
+ expect(err).to match(/The gem rails has been deleted/i)
+ expect(err).to match(default_bundle_path("gems", "rails-2.3.2").to_s)
bundle "info rails"
- expect(err).to include("The gem rails has been deleted.")
- expect(err).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
+ expect(err).to match(/The gem rails has been deleted/i)
+ expect(err).to match(default_bundle_path("gems", "rails-2.3.2").to_s)
end
context "given a default gem shippped in ruby", :ruby_repo do
@@ -127,9 +127,9 @@ RSpec.describe "bundle info" do
context "when gem has a reverse dependency on any version" do
it "prints the details" do
- bundle "info myrack"
+ bundle "info rack"
- expect(out).to include("Reverse Dependencies: \n\t\tthin (1.0) depends on myrack (>= 0)")
+ expect(out).to include("Reverse Dependencies: \n\t\tthin (1.0) depends on rack (>= 0)")
end
end
@@ -157,7 +157,7 @@ RSpec.describe "bundle info" do
it "prints out git info" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
expect(the_bundle).to include_gems "foo 1.0"
@@ -167,13 +167,13 @@ RSpec.describe "bundle info" do
end
it "prints out branch names other than main" do
- update_git "foo", branch: "omg" do |s|
+ update_git "foo", :branch => "omg" do |s|
s.write "lib/foo.rb", "FOO = '1.0.omg'"
end
@revision = revision_for(lib_path("foo-1.0"))[0...6]
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :branch => "omg"
G
expect(the_bundle).to include_gems "foo 1.0.omg"
@@ -185,7 +185,7 @@ RSpec.describe "bundle info" do
it "doesn't print the branch when tied to a ref" do
sha = revision_for(lib_path("foo-1.0"))
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :ref => "#{sha}"
G
@@ -194,9 +194,9 @@ RSpec.describe "bundle info" do
end
it "handles when a version is a '-' prerelease" do
- @git = build_git("foo", "1.0.0-beta.1", path: lib_path("foo"))
+ @git = build_git("foo", "1.0.0-beta.1", :path => lib_path("foo"))
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0.0-beta.1", :git => "#{lib_path("foo")}"
G
expect(the_bundle).to include_gems "foo 1.0.0.pre.beta.1"
@@ -209,26 +209,26 @@ RSpec.describe "bundle info" do
context "with a valid regexp for gem name" do
it "presents alternatives", :readline do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
bundle "info rac"
- expect(out).to match(/\A1 : myrack\n2 : myrack-obama\n0 : - exit -(\n>|\z)/)
+ expect(out).to match(/\A1 : rack\n2 : rack-obama\n0 : - exit -(\n>.*)?\z/)
end
end
context "with an invalid regexp for gem name" do
it "does not find the gem" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
invalid_regexp = "[]"
- bundle "info #{invalid_regexp}", raise_on_error: false
+ bundle "info #{invalid_regexp}", :raise_on_error => false
expect(err).to include("Could not find gem '#{invalid_regexp}'.")
end
end
@@ -238,11 +238,11 @@ RSpec.describe "bundle info" do
bundle "config without test"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails", group: :test
G
- bundle "info rails", raise_on_error: false
+ bundle "info rails", :raise_on_error => false
expect(err).to include("Could not find gem 'rails', because it's in the group 'test', configured to be ignored.")
end
end
diff --git a/spec/bundler/commands/init_spec.rb b/spec/bundler/commands/init_spec.rb
index 538e61fd47..6aa3e9edd1 100644
--- a/spec/bundler/commands/init_spec.rb
+++ b/spec/bundler/commands/init_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe "bundle init" do
it "honours the current process umask when generating from a template" do
FileUtils.mkdir(target_dir)
- bundle :init, dir: target_dir
+ bundle :init, :dir => target_dir
generated_mode = File.stat(File.join(target_dir, "Gemfile")).mode & 0o111
expect(generated_mode).to be_zero
end
@@ -32,17 +32,17 @@ RSpec.describe "bundle init" do
context "when a Gemfile already exists" do
before do
- gemfile <<-G
+ create_file "Gemfile", <<-G
gem "rails"
G
end
it "does not change existing Gemfiles" do
- expect { bundle :init, raise_on_error: false }.not_to change { File.read(bundled_app_gemfile) }
+ expect { bundle :init, :raise_on_error => false }.not_to change { File.read(bundled_app_gemfile) }
end
it "notifies the user that an existing Gemfile already exists" do
- bundle :init, raise_on_error: false
+ bundle :init, :raise_on_error => false
expect(err).to include("Gemfile already exists")
end
end
@@ -55,7 +55,7 @@ RSpec.describe "bundle init" do
FileUtils.mkdir bundled_app(subdir)
- bundle :init, dir: bundled_app(subdir)
+ bundle :init, :dir => bundled_app(subdir)
expect(out).to include("Writing new Gemfile")
expect(bundled_app("#{subdir}/Gemfile")).to be_file
@@ -71,7 +71,7 @@ RSpec.describe "bundle init" do
mode = File.stat(bundled_app(subdir)).mode ^ 0o222
FileUtils.chmod mode, bundled_app(subdir)
- bundle :init, dir: bundled_app(subdir), raise_on_error: false
+ bundle :init, :dir => bundled_app(subdir), :raise_on_error => false
expect(err).to include("directory is not writable")
expect(Dir[bundled_app("#{subdir}/*")]).to be_empty
@@ -79,24 +79,24 @@ RSpec.describe "bundle init" do
end
context "given --gemspec option" do
- let(:spec_file) { tmp("test.gemspec") }
+ let(:spec_file) { tmp.join("test.gemspec") }
it "should generate from an existing gemspec" do
File.open(spec_file, "w") do |file|
file << <<-S
Gem::Specification.new do |s|
s.name = 'test'
- s.add_dependency 'myrack', '= 1.0.1'
+ s.add_dependency 'rack', '= 1.0.1'
s.add_development_dependency 'rspec', '1.2'
end
S
end
- bundle :init, gemspec: spec_file
+ bundle :init, :gemspec => spec_file
gemfile = bundled_app_gemfile.read
expect(gemfile).to match(%r{source 'https://rubygems.org'})
- expect(gemfile.scan(/gem "myrack", "= 1.0.1"/).size).to eq(1)
+ expect(gemfile.scan(/gem "rack", "= 1.0.1"/).size).to eq(1)
expect(gemfile.scan(/gem "rspec", "= 1.2"/).size).to eq(1)
expect(gemfile.scan(/group :development/).size).to eq(1)
end
@@ -112,7 +112,7 @@ RSpec.describe "bundle init" do
S
end
- bundle :init, gemspec: spec_file, raise_on_error: false
+ bundle :init, :gemspec => spec_file, :raise_on_error => false
expect(err).to include("There was an error while loading `test.gemspec`")
end
end
@@ -129,17 +129,17 @@ RSpec.describe "bundle init" do
context "when gems.rb already exists" do
before do
- gemfile("gems.rb", <<-G)
+ create_file("gems.rb", <<-G)
gem "rails"
G
end
it "does not change existing Gemfiles" do
- expect { bundle :init, raise_on_error: false }.not_to change { File.read(bundled_app("gems.rb")) }
+ expect { bundle :init, :raise_on_error => false }.not_to change { File.read(bundled_app("gems.rb")) }
end
it "notifies the user that an existing gems.rb already exists" do
- bundle :init, raise_on_error: false
+ bundle :init, :raise_on_error => false
expect(err).to include("gems.rb already exists")
end
end
@@ -152,7 +152,7 @@ RSpec.describe "bundle init" do
FileUtils.mkdir bundled_app(subdir)
- bundle :init, dir: bundled_app(subdir)
+ bundle :init, :dir => bundled_app(subdir)
expect(out).to include("Writing new gems.rb")
expect(bundled_app("#{subdir}/gems.rb")).to be_file
@@ -160,14 +160,14 @@ RSpec.describe "bundle init" do
end
context "given --gemspec option" do
- let(:spec_file) { tmp("test.gemspec") }
+ let(:spec_file) { tmp.join("test.gemspec") }
before do
File.open(spec_file, "w") do |file|
file << <<-S
Gem::Specification.new do |s|
s.name = 'test'
- s.add_dependency 'myrack', '= 1.0.1'
+ s.add_dependency 'rack', '= 1.0.1'
s.add_development_dependency 'rspec', '1.2'
end
S
@@ -175,17 +175,17 @@ RSpec.describe "bundle init" do
end
it "should generate from an existing gemspec" do
- bundle :init, gemspec: spec_file
+ bundle :init, :gemspec => spec_file
gemfile = bundled_app("gems.rb").read
expect(gemfile).to match(%r{source 'https://rubygems.org'})
- expect(gemfile.scan(/gem "myrack", "= 1.0.1"/).size).to eq(1)
+ expect(gemfile.scan(/gem "rack", "= 1.0.1"/).size).to eq(1)
expect(gemfile.scan(/gem "rspec", "= 1.2"/).size).to eq(1)
expect(gemfile.scan(/group :development/).size).to eq(1)
end
it "prints message to user" do
- bundle :init, gemspec: spec_file
+ bundle :init, :gemspec => spec_file
expect(out).to include("Writing new gems.rb")
end
@@ -196,7 +196,7 @@ RSpec.describe "bundle init" do
it "should use the --gemfile value to name the gemfile" do
custom_gemfile_name = "NiceGemfileName"
- bundle :init, gemfile: custom_gemfile_name
+ bundle :init, :gemfile => custom_gemfile_name
expect(out).to include("Writing new #{custom_gemfile_name}")
used_template = File.read("#{source_root}/lib/bundler/templates/Gemfile")
diff --git a/spec/bundler/commands/inject_spec.rb b/spec/bundler/commands/inject_spec.rb
index 193806a02a..d711fe010d 100644
--- a/spec/bundler/commands/inject_spec.rb
+++ b/spec/bundler/commands/inject_spec.rb
@@ -1,18 +1,18 @@
# frozen_string_literal: true
-RSpec.describe "bundle inject", bundler: "< 3" do
+RSpec.describe "bundle inject", :bundler => "< 3" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
context "without a lockfile" do
it "locks with the injected gems" do
expect(bundled_app_lock).not_to exist
- bundle "inject 'myrack-obama' '> 0'"
- expect(bundled_app_lock.read).to match(/myrack-obama/)
+ bundle "inject 'rack-obama' '> 0'"
+ expect(bundled_app_lock.read).to match(/rack-obama/)
end
end
@@ -22,28 +22,28 @@ RSpec.describe "bundle inject", bundler: "< 3" do
end
it "adds the injected gems to the Gemfile" do
- expect(bundled_app_gemfile.read).not_to match(/myrack-obama/)
- bundle "inject 'myrack-obama' '> 0'"
- expect(bundled_app_gemfile.read).to match(/myrack-obama/)
+ expect(bundled_app_gemfile.read).not_to match(/rack-obama/)
+ bundle "inject 'rack-obama' '> 0'"
+ expect(bundled_app_gemfile.read).to match(/rack-obama/)
end
it "locks with the injected gems" do
- expect(bundled_app_lock.read).not_to match(/myrack-obama/)
- bundle "inject 'myrack-obama' '> 0'"
- expect(bundled_app_lock.read).to match(/myrack-obama/)
+ expect(bundled_app_lock.read).not_to match(/rack-obama/)
+ bundle "inject 'rack-obama' '> 0'"
+ expect(bundled_app_lock.read).to match(/rack-obama/)
end
end
context "with injected gems already in the Gemfile" do
it "doesn't add existing gems" do
- bundle "inject 'myrack' '> 0'", raise_on_error: false
+ bundle "inject 'rack' '> 0'", :raise_on_error => false
expect(err).to match(/cannot specify the same gem twice/i)
end
end
context "incorrect arguments" do
it "fails when more than 2 arguments are passed" do
- bundle "inject gem_name 1 v", raise_on_error: false
+ bundle "inject gem_name 1 v", :raise_on_error => false
expect(err).to eq(<<-E.strip)
ERROR: "bundle inject" was called with arguments ["gem_name", "1", "v"]
Usage: "bundle inject GEM VERSION"
@@ -53,25 +53,25 @@ Usage: "bundle inject GEM VERSION"
context "with source option" do
it "add gem with source option in gemfile" do
- bundle "inject 'foo' '>0' --source https://gem.repo1"
+ bundle "inject 'foo' '>0' --source #{file_uri_for(gem_repo1)}"
gemfile = bundled_app_gemfile.read
- str = "gem \"foo\", \"> 0\", :source => \"https://gem.repo1\""
+ str = "gem \"foo\", \"> 0\", :source => \"#{file_uri_for(gem_repo1)}\""
expect(gemfile).to include str
end
end
context "with group option" do
it "add gem with group option in gemfile" do
- bundle "inject 'myrack-obama' '>0' --group=development"
+ bundle "inject 'rack-obama' '>0' --group=development"
gemfile = bundled_app_gemfile.read
- str = "gem \"myrack-obama\", \"> 0\", :group => :development"
+ str = "gem \"rack-obama\", \"> 0\", :group => :development"
expect(gemfile).to include str
end
it "add gem with multiple groups in gemfile" do
- bundle "inject 'myrack-obama' '>0' --group=development,test"
+ bundle "inject 'rack-obama' '>0' --group=development,test"
gemfile = bundled_app_gemfile.read
- str = "gem \"myrack-obama\", \"> 0\", :groups => [:development, :test]"
+ str = "gem \"rack-obama\", \"> 0\", :groups => [:development, :test]"
expect(gemfile).to include str
end
end
@@ -87,31 +87,31 @@ Usage: "bundle inject GEM VERSION"
end
it "injects anyway" do
- bundle "inject 'myrack-obama' '> 0'"
- expect(bundled_app_gemfile.read).to match(/myrack-obama/)
+ bundle "inject 'rack-obama' '> 0'"
+ expect(bundled_app_gemfile.read).to match(/rack-obama/)
end
it "locks with the injected gems" do
- expect(bundled_app_lock.read).not_to match(/myrack-obama/)
- bundle "inject 'myrack-obama' '> 0'"
- expect(bundled_app_lock.read).to match(/myrack-obama/)
+ expect(bundled_app_lock.read).not_to match(/rack-obama/)
+ bundle "inject 'rack-obama' '> 0'"
+ expect(bundled_app_lock.read).to match(/rack-obama/)
end
it "restores frozen afterwards" do
- bundle "inject 'myrack-obama' '> 0'"
+ bundle "inject 'rack-obama' '> 0'"
config = Psych.load(bundled_app(".bundle/config").read)
expect(config["BUNDLE_DEPLOYMENT"] || config["BUNDLE_FROZEN"]).to eq("true")
end
it "doesn't allow Gemfile changes" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack-obama"
G
- bundle "inject 'myrack' '> 0'", raise_on_error: false
+ bundle "inject 'rack' '> 0'", :raise_on_error => false
expect(err).to match(/the lockfile can't be updated because frozen mode is set/)
- expect(bundled_app_lock.read).not_to match(/myrack-obama/)
+ expect(bundled_app_lock.read).not_to match(/rack-obama/)
end
end
end
diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb
index 19711045c2..f572bdf176 100644
--- a/spec/bundler/commands/install_spec.rb
+++ b/spec/bundler/commands/install_spec.rb
@@ -4,7 +4,7 @@ RSpec.describe "bundle install with gem sources" do
describe "the simple case" do
it "prints output and returns if no dependencies are specified" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
bundle :install
@@ -12,7 +12,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "does not make a lockfile if the install fails" do
- install_gemfile <<-G, raise_on_error: false
+ install_gemfile <<-G, :raise_on_error => false
raise StandardError, "FAIL"
G
@@ -22,17 +22,17 @@ RSpec.describe "bundle install with gem sources" do
it "creates a Gemfile.lock" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
expect(bundled_app_lock).to exist
end
- it "does not create ./.bundle by default", bundler: "< 3" do
+ it "does not create ./.bundle by default", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle :install # can't use install_gemfile since it sets retry
@@ -41,18 +41,18 @@ RSpec.describe "bundle install with gem sources" do
it "does not create ./.bundle by default when installing to system gems" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle :install, env: { "BUNDLE_PATH__SYSTEM" => "true" } # can't use install_gemfile since it sets retry
+ bundle :install, :env => { "BUNDLE_PATH__SYSTEM" => "true" } # can't use install_gemfile since it sets retry
expect(bundled_app(".bundle")).not_to exist
end
it "creates lock files based on the Gemfile name" do
gemfile bundled_app("OmgFile"), <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0"
G
bundle "install --gemfile OmgFile"
@@ -62,13 +62,13 @@ RSpec.describe "bundle install with gem sources" do
it "doesn't delete the lockfile if one already exists" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
lockfile = File.read(bundled_app_lock)
- install_gemfile <<-G, raise_on_error: false
+ install_gemfile <<-G, :raise_on_error => false
raise StandardError, "FAIL"
G
@@ -77,8 +77,8 @@ RSpec.describe "bundle install with gem sources" do
it "does not touch the lockfile if nothing changed" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
expect { run "1" }.not_to change { File.mtime(bundled_app_lock) }
@@ -86,60 +86,60 @@ RSpec.describe "bundle install with gem sources" do
it "fetches gems" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- expect(default_bundle_path("gems/myrack-1.0.0")).to exist
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(default_bundle_path("gems/rack-1.0.0")).to exist
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
it "auto-heals missing gems" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- FileUtils.rm_rf(default_bundle_path("gems/myrack-1.0.0"))
+ FileUtils.rm_rf(default_bundle_path("gems/rack-1.0.0"))
bundle "install --verbose"
- expect(out).to include("Installing myrack 1.0.0")
- expect(default_bundle_path("gems/myrack-1.0.0")).to exist
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(out).to include("Installing rack 1.0.0")
+ expect(default_bundle_path("gems/rack-1.0.0")).to exist
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
it "fetches gems when multiple versions are specified" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack', "> 0.9", "< 1.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', "> 0.9", "< 1.0"
G
- expect(default_bundle_path("gems/myrack-0.9.1")).to exist
- expect(the_bundle).to include_gems("myrack 0.9.1")
+ expect(default_bundle_path("gems/rack-0.9.1")).to exist
+ expect(the_bundle).to include_gems("rack 0.9.1")
end
it "fetches gems when multiple versions are specified take 2" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack', "< 1.0", "> 0.9"
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', "< 1.0", "> 0.9"
G
- expect(default_bundle_path("gems/myrack-0.9.1")).to exist
- expect(the_bundle).to include_gems("myrack 0.9.1")
+ expect(default_bundle_path("gems/rack-0.9.1")).to exist
+ expect(the_bundle).to include_gems("rack 0.9.1")
end
it "raises an appropriate error when gems are specified using symbols" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem :myrack
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem :rack
G
expect(exitstatus).to eq(4)
end
it "pulls in dependencies" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
@@ -148,11 +148,11 @@ RSpec.describe "bundle install with gem sources" do
it "does the right version" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- expect(the_bundle).to include_gems "myrack 0.9.1"
+ expect(the_bundle).to include_gems "rack 0.9.1"
end
it "does not install the development dependency" do
@@ -163,7 +163,7 @@ RSpec.describe "bundle install with gem sources" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "with_development_dependency"
G
@@ -173,7 +173,7 @@ RSpec.describe "bundle install with gem sources" do
it "resolves correctly" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activemerchant"
gem "rails"
G
@@ -183,12 +183,12 @@ RSpec.describe "bundle install with gem sources" do
it "activates gem correctly according to the resolved gems" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport", "2.3.5"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activemerchant"
gem "rails"
G
@@ -197,7 +197,7 @@ RSpec.describe "bundle install with gem sources" do
end
it "does not reinstall any gem that is already available locally" do
- system_gems "activesupport-2.3.2", path: default_bundle_path
+ system_gems "activesupport-2.3.2", :path => default_bundle_path
build_repo2 do
build_gem "activesupport", "2.3.2" do |s|
@@ -206,7 +206,7 @@ RSpec.describe "bundle install with gem sources" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activerecord", "2.3.2"
G
@@ -214,34 +214,36 @@ RSpec.describe "bundle install with gem sources" do
end
it "works when the gemfile specifies gems that only exist in the system" do
- build_gem "foo", to_bundle: true
+ build_gem "foo", :to_bundle => true
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "foo"
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "foo 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0", "foo 1.0.0"
end
it "prioritizes local gems over remote gems" do
- build_gem "myrack", "9.0.0", to_bundle: true
+ build_gem "rack", "1.0.0", :to_bundle => true do |s|
+ s.add_dependency "activesupport", "2.3.5"
+ end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 9.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.5"
end
it "loads env plugins" do
plugin_msg = "hello from an env plugin!"
create_file "plugins/rubygems_plugin.rb", "puts '#{plugin_msg}'"
rubylib = ENV["RUBYLIB"].to_s.split(File::PATH_SEPARATOR).unshift(bundled_app("plugins").to_s).join(File::PATH_SEPARATOR)
- install_gemfile <<-G, env: { "RUBYLIB" => rubylib }
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :env => { "RUBYLIB" => rubylib }
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
expect(last_command.stdboth).to include(plugin_msg)
@@ -249,100 +251,102 @@ RSpec.describe "bundle install with gem sources" do
describe "with a gem that installs multiple platforms" do
it "installs gems for the local platform as first choice" do
- simulate_platform "x86-darwin-100" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "platform_specific"
- G
+ skip "version is 1.0, not 1.0.0" if Gem.win_platform?
- expect(the_bundle).to include_gems("platform_specific 1.0 x86-darwin-100")
- end
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific"
+ G
+
+ run "require 'platform_specific' ; puts PLATFORM_SPECIFIC"
+ expect(out).to eq("1.0.0 #{Bundler.local_platform}")
end
it "falls back on plain ruby" do
- simulate_platform "foo-bar-baz" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "platform_specific"
- G
+ simulate_platform "foo-bar-baz"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific"
+ G
- expect(the_bundle).to include_gems("platform_specific 1.0 ruby")
- end
+ run "require 'platform_specific' ; puts PLATFORM_SPECIFIC"
+ expect(out).to eq("1.0.0 RUBY")
end
it "installs gems for java" do
- simulate_platform "java" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "platform_specific"
- G
+ simulate_platform "java"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific"
+ G
- expect(the_bundle).to include_gems("platform_specific 1.0 java")
- end
+ run "require 'platform_specific' ; puts PLATFORM_SPECIFIC"
+ expect(out).to eq("1.0.0 JAVA")
end
it "installs gems for windows" do
- simulate_platform x86_mswin32 do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "platform_specific"
- G
+ simulate_platform x86_mswin32
- expect(the_bundle).to include_gems("platform_specific 1.0 x86-mswin32")
- end
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "platform_specific"
+ G
+
+ run "require 'platform_specific' ; puts PLATFORM_SPECIFIC"
+ expect(out).to eq("1.0 x86-mswin32")
end
end
describe "doing bundle install foo" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
it "works" do
bundle "config set --local path vendor"
bundle "install"
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
- it "allows running bundle install --system without deleting foo", bundler: "< 3" do
+ it "allows running bundle install --system without deleting foo", :bundler => "< 3" do
bundle "install --path vendor"
bundle "install --system"
FileUtils.rm_rf(bundled_app("vendor"))
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
- it "allows running bundle install --system after deleting foo", bundler: "< 3" do
+ it "allows running bundle install --system after deleting foo", :bundler => "< 3" do
bundle "install --path vendor"
FileUtils.rm_rf(bundled_app("vendor"))
bundle "install --system"
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
- it "finds gems in multiple sources", bundler: "< 3" do
+ it "finds gems in multiple sources", :bundler => "< 3" do
build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
end
- install_gemfile <<-G, artifice: "compact_index_extra"
- source "https://gemserver.test"
- source "https://gemserver.test/extra"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "1.2.3"
- gem "myrack", "1.2"
+ gem "rack", "1.2"
G
- expect(the_bundle).to include_gems "myrack 1.2", "activesupport 1.2.3"
+ expect(the_bundle).to include_gems "rack 1.2", "activesupport 1.2.3"
end
it "gives a useful error if no sources are set" do
- install_gemfile <<-G, raise_on_error: false
- gem "myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ gem "rack"
G
expect(err).to include("This Gemfile does not include an explicit global source. " \
@@ -353,7 +357,7 @@ RSpec.describe "bundle install with gem sources" do
it "creates a Gemfile.lock on a blank Gemfile" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
expect(File.exist?(bundled_app_lock)).to eq(true)
@@ -363,12 +367,12 @@ RSpec.describe "bundle install with gem sources" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
+ gem "rack"
G
- expect(err).to include("Your Gemfile lists the gem myrack (>= 0) more than once.")
+ expect(err).to include("Your Gemfile lists the gem rack (>= 0) more than once.")
expect(err).to include("Remove any duplicate entries and specify the gem only once.")
expect(err).to include("While it's not a problem now, it could cause errors if you change the version of one of them later.")
end
@@ -377,12 +381,12 @@ RSpec.describe "bundle install with gem sources" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", "1.0"
- gem "myrack", "1.0"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", "1.0"
+ gem "rack", "1.0"
G
- expect(err).to include("Your Gemfile lists the gem myrack (= 1.0) more than once.")
+ expect(err).to include("Your Gemfile lists the gem rack (= 1.0) more than once.")
expect(err).to include("Remove any duplicate entries and specify the gem only once.")
expect(err).to include("While it's not a problem now, it could cause errors if you change the version of one of them later.")
end
@@ -391,20 +395,20 @@ RSpec.describe "bundle install with gem sources" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", :platform => :jruby
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", :platform => :jruby
+ gem "rack"
G
bundle "install"
- expect(err).to include("Your Gemfile lists the gem myrack (>= 0) more than once.")
+ expect(err).to include("Your Gemfile lists the gem rack (>= 0) more than once.")
expect(err).to include("Remove any duplicate entries and specify the gem only once.")
expect(err).to include("While it's not a problem now, it could cause errors if you change the version of one of them later.")
end
it "does not throw a warning if a gem is added once in Gemfile and also inside a gemspec as a development dependency" do
- build_lib "my-gem", path: bundled_app do |s|
+ build_lib "my-gem", :path => bundled_app do |s|
s.add_development_dependency "my-private-gem"
end
@@ -413,7 +417,7 @@ RSpec.describe "bundle install with gem sources" do
end
gemfile <<~G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gemspec
@@ -426,180 +430,33 @@ RSpec.describe "bundle install with gem sources" do
expect(the_bundle).to include_gems("my-private-gem 1.0")
end
- it "throws a warning if a gem is added once in Gemfile and also inside a gemspec as a development dependency, with different requirements" do
- build_lib "my-gem", path: bundled_app do |s|
- s.add_development_dependency "rubocop", "~> 1.36.0"
- end
-
- build_repo4 do
- build_gem "rubocop", "1.36.0"
- build_gem "rubocop", "1.37.1"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gemspec
-
- gem "rubocop", group: :development
- G
-
- bundle :install
-
- expect(err).to include("A gemspec development dependency (rubocop, ~> 1.36.0) is being overridden by a Gemfile dependency (rubocop, >= 0).")
- expect(err).to include("This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement")
-
- # This is not the best behavior I believe, it would be better if both
- # requirements are considered if they are compatible, and a version
- # satisfying both is chosen. But not sure about changing it right now, so
- # I went with a warning for the time being.
- expect(the_bundle).to include_gems("rubocop 1.37.1")
- end
-
- it "includes the gem without warning if two gemspecs add it with the same requirement" do
- gem1 = tmp("my-gem-1")
- gem2 = tmp("my-gem-2")
-
- build_lib "my-gem", path: gem1 do |s|
- s.add_development_dependency "rubocop", "~> 1.36.0"
- end
-
- build_lib "my-gem-2", path: gem2 do |s|
- s.add_development_dependency "rubocop", "~> 1.36.0"
- end
-
- build_repo4 do
- build_gem "rubocop", "1.36.0"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gemspec path: "#{gem1}"
- gemspec path: "#{gem2}"
- G
-
- bundle :install
-
- expect(err).to be_empty
- expect(the_bundle).to include_gems("rubocop 1.36.0")
- end
-
- it "warns when a Gemfile dependency is overriding a gemspec development dependency, with different requirements" do
- build_lib "my-gem", path: bundled_app do |s|
- s.add_development_dependency "rails", ">= 5"
- end
-
- build_repo4 do
- build_gem "rails", "7.0.8"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "rails", "~> 7.0.8"
-
- gemspec
- G
-
- bundle :install
-
- expect(err).to include("A gemspec development dependency (rails, >= 5) is being overridden by a Gemfile dependency (rails, ~> 7.0.8).")
- expect(err).to include("This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement")
-
- # This is not the best behavior I believe, it would be better if both
- # requirements are considered if they are compatible, and a version
- # satisfying both is chosen. But not sure about changing it right now, so
- # I went with a warning for the time being.
- expect(the_bundle).to include_gems("rails 7.0.8")
- end
-
- it "does not warn if a gem is added once in Gemfile and also inside a gemspec as a development dependency, with same requirements, and different sources" do
- build_lib "my-gem", path: bundled_app do |s|
- s.add_development_dependency "activesupport"
- end
-
- build_repo4 do
- build_gem "activesupport"
- end
-
- build_git "activesupport", "1.0", path: lib_path("activesupport")
-
- install_gemfile <<~G
- source "https://gem.repo4"
-
- gemspec
-
- gem "activesupport", :git => "#{lib_path("activesupport")}"
- G
-
- expect(err).to be_empty
- expect(the_bundle).to include_gems "activesupport 1.0", source: "git@#{lib_path("activesupport")}"
-
- # if the Gemfile dependency is specified first
- install_gemfile <<~G
- source "https://gem.repo4"
-
- gem "activesupport", :git => "#{lib_path("activesupport")}"
-
- gemspec
- G
-
- expect(err).to be_empty
- expect(the_bundle).to include_gems "activesupport 1.0", source: "git@#{lib_path("activesupport")}"
- end
-
- it "considers both dependencies for resolution if a gem is added once in Gemfile and also inside a local gemspec as a runtime dependency, with different requirements" do
- build_lib "my-gem", path: bundled_app do |s|
- s.add_dependency "rubocop", "~> 1.36.0"
- end
-
- build_repo4 do
- build_gem "rubocop", "1.36.0"
- build_gem "rubocop", "1.37.1"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gemspec
-
- gem "rubocop"
- G
-
- bundle :install
-
- expect(err).to be_empty
- expect(the_bundle).to include_gems("rubocop 1.36.0")
- end
-
it "throws an error if a gem is added twice in Gemfile when version of one dependency is not specified" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
- gem "myrack"
- gem "myrack", "1.0"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
+ gem "rack", "1.0"
G
expect(err).to include("You cannot specify the same gem twice with different version requirements")
- expect(err).to include("You specified: myrack (>= 0) and myrack (= 1.0).")
+ expect(err).to include("You specified: rack (>= 0) and rack (= 1.0).")
end
it "throws an error if a gem is added twice in Gemfile when different versions of both dependencies are specified" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
- gem "myrack", "1.0"
- gem "myrack", "1.1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", "1.0"
+ gem "rack", "1.1"
G
expect(err).to include("You cannot specify the same gem twice with different version requirements")
- expect(err).to include("You specified: myrack (= 1.0) and myrack (= 1.1).")
+ expect(err).to include("You specified: rack (= 1.0) and rack (= 1.1).")
end
it "gracefully handles error when rubygems server is unavailable" do
skip "networking issue" if Gem.win_platform?
- install_gemfile <<-G, artifice: nil, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :artifice => nil, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
source "http://0.0.0.0:9384" do
gem 'foo'
end
@@ -610,8 +467,8 @@ RSpec.describe "bundle install with gem sources" do
end
it "fails gracefully when downloading an invalid specification from the full index" do
- build_repo2(build_compact_index: false) do
- build_gem "ajp-rails", "0.0.0", gemspec: false, skip_validation: true do |s|
+ build_repo2 do
+ build_gem "ajp-rails", "0.0.0", :gemspec => false, :skip_validation => true do |s|
bad_deps = [["ruby-ajp", ">= 0.2.0"], ["rails", ">= 0.14"]]
s.
instance_variable_get(:@spec).
@@ -622,8 +479,8 @@ RSpec.describe "bundle install with gem sources" do
build_gem "ruby-ajp", "1.0.0"
end
- install_gemfile <<-G, full_index: true, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :full_index => true, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "ajp-rails", "0.0.0"
G
@@ -638,7 +495,7 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.touch(bundled_app(".bundle/config"))
install_gemfile(<<-G)
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo'
G
@@ -649,7 +506,7 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.touch("#{Bundler.rubygems.user_home}/.bundle/config")
install_gemfile(<<-G)
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo'
G
@@ -657,11 +514,13 @@ RSpec.describe "bundle install with gem sources" do
end
describe "Ruby version in Gemfile.lock" do
+ include Bundler::GemHelpers
+
context "and using an unsupported Ruby version" do
it "prints an error" do
- install_gemfile <<-G, raise_on_error: false
+ install_gemfile <<-G, :raise_on_error => false
ruby '~> 1.2'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
expect(err).to include("Your Ruby version is #{Gem.ruby_version}, but your Gemfile specified ~> 1.2")
end
@@ -671,22 +530,21 @@ RSpec.describe "bundle install with gem sources" do
before do
install_gemfile <<-G
ruby '~> #{Gem.ruby_version}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
it "writes current Ruby version to Gemfile.lock" do
- checksums = checksums_section_when_enabled
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- #{checksums}
+
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -698,21 +556,19 @@ RSpec.describe "bundle install with gem sources" do
it "updates Gemfile.lock with updated yet still compatible ruby version" do
install_gemfile <<-G
ruby '~> #{current_ruby_minor}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
- checksums = checksums_section_when_enabled
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- #{checksums}
+
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -723,7 +579,7 @@ RSpec.describe "bundle install with gem sources" do
it "does not crash when unlocking" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby '>= 2.1.0'
G
@@ -742,14 +598,14 @@ RSpec.describe "bundle install with gem sources" do
build_lib "foo"
gemfile = <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "#{lib_path("foo-1.0")}"
G
File.open("#{root_dir}/Gemfile", "w") do |file|
file.puts gemfile
end
- bundle :install, dir: root_dir
+ bundle :install, :dir => root_dir
end
it "doesn't blow up when using the `gemspec` DSL" do
@@ -757,16 +613,16 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.mkdir_p(root_dir)
- build_lib "foo", path: root_dir
+ build_lib "foo", :path => root_dir
gemfile = <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
File.open("#{root_dir}/Gemfile", "w") do |file|
file.puts gemfile
end
- bundle :install, dir: root_dir
+ bundle :install, :dir => root_dir
end
end
@@ -775,11 +631,11 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set force_ruby_platform true"
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- bundle :install, quiet: true
+ bundle :install, :quiet => true
expect(out).to be_empty
expect(err).to be_empty
end
@@ -805,25 +661,25 @@ RSpec.describe "bundle install with gem sources" do
RUBY
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'non-existing-gem'
G
- bundle :install, quiet: true, raise_on_error: false, env: { "RUBYOPT" => "-r#{bundled_app("install_with_warning.rb")}" }
+ bundle :install, :quiet => true, :raise_on_error => false, :env => { "RUBYOPT" => "-r#{bundled_app("install_with_warning.rb")}" }
expect(out).to be_empty
expect(err).to include("Could not find gem 'non-existing-gem'")
expect(err).to include("BOOOOO")
end
end
- describe "when bundle path does not have cd permission", :permissions do
+ describe "when bundle path does not have write access", :permissions do
let(:bundle_path) { bundled_app("vendor") }
before do
FileUtils.mkdir_p(bundle_path)
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
end
@@ -831,20 +687,20 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.chmod(0o500, bundle_path)
bundle "config set --local path vendor"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include(bundle_path.to_s)
expect(err).to include("grant write permissions")
end
end
- describe "when bundle gems path does not have cd permission", :permissions do
+ describe "when bundle gems path does not have write access", :permissions do
let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
before do
FileUtils.mkdir_p(gems_path)
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
end
@@ -853,7 +709,7 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set --local path vendor"
begin
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
ensure
FileUtils.chmod("+x", gems_path)
end
@@ -861,79 +717,19 @@ RSpec.describe "bundle install with gem sources" do
expect(err).not_to include("ERROR REPORT TEMPLATE")
expect(err).to include(
- "There was an error while trying to create `#{gems_path.join("myrack-1.0.0")}`. " \
+ "There was an error while trying to create `#{gems_path.join("rack-1.0.0")}`. " \
"It is likely that you need to grant executable permissions for all parent directories and write permissions for `#{gems_path}`."
)
end
end
- describe "when bundle bin dir does not have cd permission", :permissions do
- let(:bin_dir) { bundled_app("vendor/#{Bundler.ruby_scope}/bin") }
-
- before do
- FileUtils.mkdir_p(bin_dir)
- gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
- G
- end
-
- it "should display a proper message to explain the problem" do
- FileUtils.chmod("-x", bin_dir)
- bundle "config set --local path vendor"
-
- begin
- bundle :install, raise_on_error: false
- ensure
- FileUtils.chmod("+x", bin_dir)
- end
-
- expect(err).not_to include("ERROR REPORT TEMPLATE")
-
- expect(err).to include(
- "There was an error while trying to write to `#{bin_dir}`. " \
- "It is likely that you need to grant write permissions for that path."
- )
- end
- end
-
- describe "when bundle bin dir does not have write access", :permissions do
- let(:bin_dir) { bundled_app("vendor/#{Bundler.ruby_scope}/bin") }
-
- before do
- FileUtils.mkdir_p(bin_dir)
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- G
- end
-
- it "should display a proper message to explain the problem" do
- FileUtils.chmod("-w", bin_dir)
- bundle "config set --local path vendor"
-
- begin
- bundle :install, raise_on_error: false
- ensure
- FileUtils.chmod("+w", bin_dir)
- end
-
- expect(err).not_to include("ERROR REPORT TEMPLATE")
-
- expect(err).to include(
- "There was an error while trying to write to `#{bin_dir}`. " \
- "It is likely that you need to grant write permissions for that path."
- )
- end
- end
-
describe "when bundle extensions path does not have write access", :permissions do
let(:extensions_path) { bundled_app("vendor/#{Bundler.ruby_scope}/extensions/#{Gem::Platform.local}/#{Gem.extension_api_version}") }
before do
FileUtils.mkdir_p(extensions_path)
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'simple_binary'
G
end
@@ -943,7 +739,7 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set --local path vendor"
begin
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
ensure
FileUtils.chmod("+x", extensions_path)
end
@@ -957,7 +753,7 @@ RSpec.describe "bundle install with gem sources" do
end
end
- describe "when the path of a specific gem does not have cd permission", :permissions do
+ describe "when the path of a specific gem is not writable", :permissions do
let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
let(:foo_path) { gems_path.join("foo-1.0.0") }
@@ -969,7 +765,7 @@ RSpec.describe "bundle install with gem sources" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo'
G
end
@@ -983,7 +779,7 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.chmod("-x", foo_path)
begin
- bundle "install --redownload", raise_on_error: false
+ bundle "install --redownload", :raise_on_error => false
ensure
FileUtils.chmod("+x", foo_path)
end
@@ -994,107 +790,14 @@ RSpec.describe "bundle install with gem sources" do
end
end
- describe "when gem home does not have the writable bit set, yet it's still writable", :permissions do
- let(:gem_home) { bundled_app("vendor/#{Bundler.ruby_scope}") }
-
- before do
- build_repo4 do
- build_gem "foo", "1.0.0" do |s|
- s.write "CHANGELOG.md", "foo"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo4"
- gem 'foo'
- G
- end
-
- it "should display a proper message to explain the problem" do
- bundle "config set --local path vendor"
- bundle :install
- expect(out).to include("Bundle complete!")
- expect(err).to be_empty
-
- FileUtils.chmod("-w", gem_home)
-
- begin
- bundle "install --redownload"
- ensure
- FileUtils.chmod("+w", gem_home)
- end
-
- expect(out).to include("Bundle complete!")
- expect(err).to be_empty
- end
- end
-
- describe "when gems path is world writable (no sticky bit set)", :permissions do
- let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
-
- before do
- build_repo4 do
- build_gem "foo", "1.0.0" do |s|
- s.write "CHANGELOG.md", "foo"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo4"
- gem 'foo'
- G
- end
-
- it "should display a proper message to explain the problem" do
- bundle "config set --local path vendor"
- bundle :install
- expect(out).to include("Bundle complete!")
- expect(err).to be_empty
-
- FileUtils.chmod(0o777, gems_path)
-
- bundle "install --redownload", raise_on_error: false
-
- expect(err).to include("Bundler cannot reinstall foo-1.0.0 because there's a previous installation of it at #{gems_path}/foo-1.0.0 that is unsafe to remove")
- end
- end
-
- describe "when gems path is world writable (no sticky bit set), but previous install is just an empty dir (like it happens with default gems)", :permissions do
- let(:gems_path) { bundled_app("vendor/#{Bundler.ruby_scope}/gems") }
- let(:full_path) { gems_path.join("foo-1.0.0") }
-
- before do
- build_repo4 do
- build_gem "foo", "1.0.0" do |s|
- s.write "CHANGELOG.md", "foo"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo4"
- gem 'foo'
- G
- end
-
- it "does not try to remove the directory and thus don't abort with an error about unsafe directory removal" do
- bundle "config set --local path vendor"
-
- FileUtils.mkdir_p(gems_path)
- FileUtils.chmod(0o777, gems_path)
- Dir.mkdir(full_path)
-
- bundle "install"
- end
- end
-
describe "when bundle cache path does not have write access", :permissions do
let(:cache_path) { bundled_app("vendor/#{Bundler.ruby_scope}/cache") }
before do
FileUtils.mkdir_p(cache_path)
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
end
@@ -1102,48 +805,25 @@ RSpec.describe "bundle install with gem sources" do
FileUtils.chmod(0o500, cache_path)
bundle "config set --local path vendor"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include(cache_path.to_s)
expect(err).to include("grant write permissions")
end
end
- describe "when gemspecs are unreadable", :permissions do
- let(:gemspec_path) { vendored_gems("specifications/myrack-1.0.0.gemspec") }
-
- before do
- gemfile <<~G
- source "https://gem.repo1"
- gem 'myrack'
- G
- bundle "config path vendor/bundle"
- bundle :install
- expect(out).to include("Bundle complete!")
- expect(err).to be_empty
-
- FileUtils.chmod("-r", gemspec_path)
- end
-
- it "shows a good error" do
- bundle :install, raise_on_error: false
- expect(err).to include(gemspec_path.to_s)
- expect(err).to include("grant read permissions")
- end
- end
-
context "after installing with --standalone" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set --local path bundle"
- bundle "install", standalone: true
+ bundle "install", :standalone => true
end
it "includes the standalone path" do
- bundle "binstubs myrack", standalone: true
- standalone_line = File.read(bundled_app("bin/myrackup")).each_line.find {|line| line.include? "$:.unshift" }.strip
+ bundle "binstubs rack", :standalone => true
+ standalone_line = File.read(bundled_app("bin/rackup")).each_line.find {|line| line.include? "$:.unshift" }.strip
expect(standalone_line).to eq %($:.unshift File.expand_path "../bundle", __dir__)
end
end
@@ -1157,34 +837,30 @@ RSpec.describe "bundle install with gem sources" do
end
it "should display a helpful message explaining how to fix it" do
- bundle :install, env: { "BUNDLE_RUBYGEMS__ORG" => "user:pass{word" }, raise_on_error: false
+ bundle :install, :env => { "BUNDLE_RUBYGEMS__ORG" => "user:pass{word" }, :raise_on_error => false
expect(exitstatus).to eq(17)
expect(err).to eq("Please CGI escape your usernames and passwords before " \
"setting them for authentication.")
end
end
- context "when current platform not included in the lockfile" do
- around do |example|
+ context "in a frozen bundle" do
+ before do
build_repo4 do
build_gem "libv8", "8.4.255.0" do |s|
s.platform = "x86_64-darwin-19"
end
-
- build_gem "libv8", "8.4.255.0" do |s|
- s.platform = "x86_64-linux"
- end
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "libv8"
G
lockfile <<-L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
libv8 (8.4.255.0-x86_64-darwin-19)
@@ -1198,36 +874,11 @@ RSpec.describe "bundle install with gem sources" do
#{Bundler::VERSION}
L
- simulate_platform("x86_64-linux", &example)
- end
-
- it "adds the current platform to the lockfile" do
- bundle "install --verbose"
-
- expect(out).to include("re-resolving dependencies because your lockfile does not include the current platform")
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- libv8 (8.4.255.0-x86_64-darwin-19)
- libv8 (8.4.255.0-x86_64-linux)
-
- PLATFORMS
- x86_64-darwin-19
- x86_64-linux
-
- DEPENDENCIES
- libv8
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
+ bundle "config set --local deployment true"
end
- it "fails loudly if frozen mode set" do
- bundle "config set --local deployment true"
- bundle "install", raise_on_error: false
+ it "should fail loudly if the lockfile platforms don't include the current platform" do
+ simulate_platform(Gem::Platform.new("x86_64-linux")) { bundle "install", :raise_on_error => false }
expect(err).to eq(
"Your bundle only supports platforms [\"x86_64-darwin-19\"] but your local platform is x86_64-linux. " \
@@ -1239,23 +890,23 @@ RSpec.describe "bundle install with gem sources" do
context "with missing platform specific gems in lockfile" do
before do
build_repo4 do
- build_gem "racca", "1.5.2"
+ build_gem "racc", "1.5.2"
build_gem "nokogiri", "1.12.4" do |s|
s.platform = "x86_64-darwin"
- s.add_dependency "racca", "~> 1.4"
+ s.add_runtime_dependency "racc", "~> 1.4"
end
build_gem "nokogiri", "1.12.4" do |s|
s.platform = "x86_64-linux"
- s.add_dependency "racca", "~> 1.4"
+ s.add_runtime_dependency "racc", "~> 1.4"
end
build_gem "crass", "1.0.6"
build_gem "loofah", "2.12.0" do |s|
- s.add_dependency "crass", "~> 1.0.2"
- s.add_dependency "nokogiri", ">= 1.5.9"
+ s.add_runtime_dependency "crass", "~> 1.0.2"
+ s.add_runtime_dependency "nokogiri", ">= 1.5.9"
end
end
@@ -1267,13 +918,6 @@ RSpec.describe "bundle install with gem sources" do
gem "loofah", "~> 2.12.0"
G
- checksums = checksums_section do |c|
- c.checksum gem_repo4, "crass", "1.0.6"
- c.checksum gem_repo4, "loofah", "2.12.0"
- c.checksum gem_repo4, "nokogiri", "1.12.4", "x86_64-darwin"
- c.checksum gem_repo4, "racca", "1.5.2"
- end
-
lockfile <<-L
GEM
remote: https://gem.repo4/
@@ -1283,8 +927,8 @@ RSpec.describe "bundle install with gem sources" do
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
nokogiri (1.12.4-x86_64-darwin)
- racca (~> 1.4)
- racca (1.5.2)
+ racc (~> 1.4)
+ racc (1.5.2)
PLATFORMS
x86_64-darwin-20
@@ -1292,7 +936,7 @@ RSpec.describe "bundle install with gem sources" do
DEPENDENCIES
loofah (~> 2.12.0)
- #{checksums}
+
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -1305,15 +949,7 @@ RSpec.describe "bundle install with gem sources" do
bundle "config set --local path vendor/bundle"
simulate_platform "x86_64-linux" do
- bundle "install", artifice: "compact_index"
- end
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "crass", "1.0.6"
- c.checksum gem_repo4, "loofah", "2.12.0"
- c.checksum gem_repo4, "nokogiri", "1.12.4", "x86_64-darwin"
- c.checksum gem_repo4, "racca", "1.5.2"
- c.checksum gem_repo4, "nokogiri", "1.12.4", "x86_64-linux"
+ bundle "install", :artifice => "compact_index"
end
expect(lockfile).to eq <<~L
@@ -1325,10 +961,10 @@ RSpec.describe "bundle install with gem sources" do
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
nokogiri (1.12.4-x86_64-darwin)
- racca (~> 1.4)
+ racc (~> 1.4)
nokogiri (1.12.4-x86_64-linux)
- racca (~> 1.4)
- racca (1.5.2)
+ racc (~> 1.4)
+ racc (1.5.2)
PLATFORMS
x86_64-darwin-20
@@ -1336,7 +972,7 @@ RSpec.describe "bundle install with gem sources" do
DEPENDENCIES
loofah (~> 2.12.0)
- #{checksums}
+
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -1348,15 +984,15 @@ RSpec.describe "bundle install with gem sources" do
context "with --local flag" do
before do
- system_gems "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-1.0.0", :path => default_bundle_path
end
it "respects installed gems without fetching any remote sources" do
- install_gemfile <<-G, local: true
- source "https://gem.repo1"
+ install_gemfile <<-G, :local => true
+ source "#{file_uri_for(gem_repo1)}"
source "https://not-existing-source" do
- gem "myrack"
+ gem "rack"
end
G
@@ -1371,14 +1007,14 @@ RSpec.describe "bundle install with gem sources" do
it "installs only gems of the specified groups" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
- gem "myrack", group: :a
+ gem "rack", group: :a
gem "rake", group: :b
gem "yard", group: :c
G
- expect(out).to include("Installing myrack")
+ expect(out).to include("Installing rack")
expect(out).to include("Installing rake")
expect(out).not_to include("Installing yard")
end
@@ -1390,22 +1026,14 @@ RSpec.describe "bundle install with gem sources" do
build_gem "foo", "1.0.1"
build_gem "foo", "1.0.0"
build_gem "bar", "1.0.0"
-
- build_gem "a", "1.0.0" do |s|
- s.add_dependency "foo", "~> 1.0.0"
- end
-
- build_gem "b", "1.0.0" do |s|
- s.add_dependency "foo", "~> 1.0.1"
- end
end
- system_gems "foo-1.0.0", path: default_bundle_path, gem_repo: gem_repo4
+ system_gems "foo-1.0.0", :path => default_bundle_path, :gem_repo => gem_repo4
end
- it "fetches remote sources when not available locally" do
- install_gemfile <<-G, "prefer-local": true, verbose: true
- source "https://gem.repo4"
+ it "fetches remote sources only when not available locally" do
+ install_gemfile <<-G, :"prefer-local" => true, :verbose => true
+ source "#{file_uri_for(gem_repo4)}"
gem "foo"
gem "bar"
@@ -1414,40 +1042,6 @@ RSpec.describe "bundle install with gem sources" do
expect(out).to include("Using foo 1.0.0").and include("Fetching bar 1.0.0").and include("Installing bar 1.0.0")
expect(last_command).to be_success
end
-
- it "fetches remote sources when local version does not match requirements" do
- install_gemfile <<-G, "prefer-local": true, verbose: true
- source "https://gem.repo4"
-
- gem "foo", "1.0.1"
- gem "bar"
- G
-
- expect(out).to include("Fetching foo 1.0.1").and include("Installing foo 1.0.1").and include("Fetching bar 1.0.0").and include("Installing bar 1.0.0")
- expect(last_command).to be_success
- end
-
- it "uses the locally available version for sub-dependencies when possible" do
- install_gemfile <<-G, "prefer-local": true, verbose: true
- source "https://gem.repo4"
-
- gem "a"
- G
-
- expect(out).to include("Using foo 1.0.0").and include("Fetching a 1.0.0").and include("Installing a 1.0.0")
- expect(last_command).to be_success
- end
-
- it "fetches remote sources for sub-dependencies when the locally available version does not satisfy the requirement" do
- install_gemfile <<-G, "prefer-local": true, verbose: true
- source "https://gem.repo4"
-
- gem "b"
- G
-
- expect(out).to include("Fetching foo 1.0.1").and include("Installing foo 1.0.1").and include("Fetching b 1.0.0").and include("Installing b 1.0.0")
- expect(last_command).to be_success
- end
end
context "with a symlinked configured as bundle path and a gem with symlinks" do
@@ -1468,7 +1062,7 @@ RSpec.describe "bundle install with gem sources" do
File.symlink("../../README.markdown", File.join(man_path, "README.markdown"))
build_repo4 do
- build_gem "binman", path: gem_repo4("gems"), lib_path: binman_path, no_default: true do |s|
+ build_gem "binman", :path => gem_repo4("gems"), :lib_path => binman_path, :no_default => true do |s|
s.files = ["README.markdown", "man/man0/README.markdown"]
end
end
@@ -1476,7 +1070,7 @@ RSpec.describe "bundle install with gem sources" do
it "installs fine" do
install_gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "binman"
G
@@ -1498,110 +1092,15 @@ RSpec.describe "bundle install with gem sources" do
it "does not crash unexpectedly" do
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "autobuild", "1.10.rc2"
G
- bundle "install --jobs 1", raise_on_error: false
+ bundle "install --jobs 1", :raise_on_error => false
expect(err).not_to include("ERROR REPORT TEMPLATE")
expect(err).to include("Could not find compatible versions")
end
end
-
- context "when a lockfile has unmet dependencies, and the Gemfile has no resolution" do
- before do
- build_repo4 do
- build_gem "aaa", "0.2.0" do |s|
- s.add_dependency "zzz", "< 0.2.0"
- end
-
- build_gem "zzz", "0.2.0"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "aaa"
- gem "zzz"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- aaa (0.2.0)
- zzz (< 0.2.0)
- zzz (0.2.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- aaa!
- zzz!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "does not install, but raises a resolution error" do
- bundle "install", raise_on_error: false
- expect(err).to include("Could not find compatible versions")
- end
- end
-
- context "when --jobs option given" do
- before do
- install_gemfile "source 'https://gem.repo1'", jobs: 1
- end
-
- it "does not save the flag to config" do
- expect(bundled_app(".bundle/config")).not_to exist
- end
- end
-
- context "when bundler installation is corrupt" do
- before do
- system_gems "bundler-9.99.8"
-
- replace_version_file("9.99.9", dir: system_gem_path("gems/bundler-9.99.8"))
- end
-
- it "shows a proper error" do
- lockfile <<~L
- GEM
- remote: https://gem.repo1/
- specs:
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
-
- BUNDLED WITH
- 9.99.8
- L
-
- install_gemfile "source \"https://gem.repo1\"", env: { "BUNDLER_VERSION" => "9.99.8" }, raise_on_error: false
-
- expect(err).not_to include("ERROR REPORT TEMPLATE")
- expect(err).to include("The running version of Bundler (9.99.9) does not match the version of the specification installed for it (9.99.8)")
- end
- end
-
- it "only installs executable files in bin" do
- bundle "config set --local path vendor/bundle"
-
- install_gemfile <<~G
- source "https://gem.repo1"
- gem "myrack"
- G
-
- expected_executables = [vendored_gems("bin/myrackup").to_s]
- expected_executables << vendored_gems("bin/myrackup.bat").to_s if Gem.win_platform?
- expect(Dir.glob(vendored_gems("bin/*"))).to eq(expected_executables)
- end
end
diff --git a/spec/bundler/commands/issue_spec.rb b/spec/bundler/commands/issue_spec.rb
index 346cdedc42..143f6333ce 100644
--- a/spec/bundler/commands/issue_spec.rb
+++ b/spec/bundler/commands/issue_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe "bundle issue" do
it "exits with a message" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
diff --git a/spec/bundler/commands/licenses_spec.rb b/spec/bundler/commands/licenses_spec.rb
index bfec938efd..a203984890 100644
--- a/spec/bundler/commands/licenses_spec.rb
+++ b/spec/bundler/commands/licenses_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe "bundle licenses" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
gem "with_license"
G
@@ -24,7 +24,7 @@ RSpec.describe "bundle licenses" do
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
gem "with_license"
gem "foo"
diff --git a/spec/bundler/commands/list_spec.rb b/spec/bundler/commands/list_spec.rb
index cc0db9169d..66930ded75 100644
--- a/spec/bundler/commands/list_spec.rb
+++ b/spec/bundler/commands/list_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe "bundle list" do
context "with name-only and paths option" do
it "raises an error" do
- bundle "list --name-only --paths", raise_on_error: false
+ bundle "list --name-only --paths", :raise_on_error => false
expect(err).to eq "The `--name-only` and `--paths` options cannot be used together"
end
@@ -11,7 +11,7 @@ RSpec.describe "bundle list" do
context "with without-group and only-group option" do
it "raises an error" do
- bundle "list --without-group dev --only-group test", raise_on_error: false
+ bundle "list --without-group dev --only-group test", :raise_on_error => false
expect(err).to eq "The `--only-group` and `--without-group` options cannot be used together"
end
@@ -20,9 +20,9 @@ RSpec.describe "bundle list" do
describe "with without-group option" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
gem "rspec", :group => [:test]
gem "rails", :group => [:production]
G
@@ -32,7 +32,7 @@ RSpec.describe "bundle list" do
it "prints the gems not in the specified group" do
bundle "list --without-group test"
- expect(out).to include(" * myrack (1.0.0)")
+ expect(out).to include(" * rack (1.0.0)")
expect(out).to include(" * rails (2.3.2)")
expect(out).not_to include(" * rspec (1.2.7)")
end
@@ -40,7 +40,7 @@ RSpec.describe "bundle list" do
context "when group is not found" do
it "raises an error" do
- bundle "list --without-group random", raise_on_error: false
+ bundle "list --without-group random", :raise_on_error => false
expect(err).to eq "`random` group could not be found."
end
@@ -50,7 +50,7 @@ RSpec.describe "bundle list" do
it "prints the gems not in the specified groups" do
bundle "list --without-group test production"
- expect(out).to include(" * myrack (1.0.0)")
+ expect(out).to include(" * rack (1.0.0)")
expect(out).not_to include(" * rails (2.3.2)")
expect(out).not_to include(" * rspec (1.2.7)")
end
@@ -60,9 +60,9 @@ RSpec.describe "bundle list" do
describe "with only-group option" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
gem "rspec", :group => [:test]
gem "rails", :group => [:production]
G
@@ -72,14 +72,14 @@ RSpec.describe "bundle list" do
it "prints the gems in the specified group" do
bundle "list --only-group default"
- expect(out).to include(" * myrack (1.0.0)")
+ expect(out).to include(" * rack (1.0.0)")
expect(out).not_to include(" * rspec (1.2.7)")
end
end
context "when group is not found" do
it "raises an error" do
- bundle "list --only-group random", raise_on_error: false
+ bundle "list --only-group random", :raise_on_error => false
expect(err).to eq "`random` group could not be found."
end
@@ -89,7 +89,7 @@ RSpec.describe "bundle list" do
it "prints the gems in the specified groups" do
bundle "list --only-group default production"
- expect(out).to include(" * myrack (1.0.0)")
+ expect(out).to include(" * rack (1.0.0)")
expect(out).to include(" * rails (2.3.2)")
expect(out).not_to include(" * rspec (1.2.7)")
end
@@ -99,9 +99,9 @@ RSpec.describe "bundle list" do
context "with name-only option" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
gem "rspec", :group => [:test]
G
end
@@ -109,7 +109,7 @@ RSpec.describe "bundle list" do
it "prints only the name of the gems in the bundle" do
bundle "list --name-only"
- expect(out).to include("myrack")
+ expect(out).to include("rack")
expect(out).to include("rspec")
end
end
@@ -117,32 +117,32 @@ RSpec.describe "bundle list" do
context "with paths option" do
before do
build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "bar"
end
- build_git "git_test", "1.0.0", path: lib_path("git_test")
+ build_git "git_test", "1.0.0", :path => lib_path("git_test")
- build_lib("gemspec_test", path: tmp("gemspec_test")) do |s|
+ build_lib("gemspec_test", :path => tmp.join("gemspec_test")) do |s|
s.add_dependency "bar", "=1.0.0"
end
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
gem "rails"
gem "git_test", :git => "#{lib_path("git_test")}"
- gemspec :path => "#{tmp("gemspec_test")}"
+ gemspec :path => "#{tmp.join("gemspec_test")}"
G
end
it "prints the path of each gem in the bundle" do
bundle "list --paths"
expect(out).to match(%r{.*\/rails\-2\.3\.2})
- expect(out).to match(%r{.*\/myrack\-1\.2})
+ expect(out).to match(%r{.*\/rack\-1\.2})
expect(out).to match(%r{.*\/git_test\-\w})
expect(out).to match(%r{.*\/gemspec_test})
end
@@ -151,7 +151,7 @@ RSpec.describe "bundle list" do
context "when no gems are in the gemfile" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
@@ -164,25 +164,25 @@ RSpec.describe "bundle list" do
context "without options" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
gem "rspec", :group => [:test]
G
end
it "lists gems installed in the bundle" do
bundle "list"
- expect(out).to include(" * myrack (1.0.0)")
+ expect(out).to include(" * rack (1.0.0)")
end
end
context "when using the ls alias" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
gem "rspec", :group => [:test]
G
end
diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb
index 5e2a6e7e8f..491fa30949 100644
--- a/spec/bundler/commands/lock_spec.rb
+++ b/spec/bundler/commands/lock_spec.rb
@@ -1,22 +1,27 @@
# frozen_string_literal: true
RSpec.describe "bundle lock" do
- let(:expected_lockfile) do
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "actionmailer", "2.3.2"
- c.checksum gem_repo4, "actionpack", "2.3.2"
- c.checksum gem_repo4, "activerecord", "2.3.2"
- c.checksum gem_repo4, "activeresource", "2.3.2"
- c.checksum gem_repo4, "activesupport", "2.3.2"
- c.checksum gem_repo4, "foo", "1.0"
- c.checksum gem_repo4, "rails", "2.3.2"
- c.checksum gem_repo4, "rake", rake_version
- c.checksum gem_repo4, "weakling", "0.0.3"
- end
+ def strip_lockfile(lockfile)
+ strip_whitespace(lockfile).sub(/\n\Z/, "")
+ end
+
+ def read_lockfile(file = "Gemfile.lock")
+ strip_lockfile bundled_app(file).read
+ end
- <<~L
+ let(:repo) { gem_repo1 }
+
+ before :each do
+ gemfile <<-G
+ source "#{file_uri_for(repo)}"
+ gem "rails"
+ gem "weakling"
+ gem "foo"
+ G
+
+ @lockfile = strip_lockfile(<<-L)
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(repo)}/
specs:
actionmailer (2.3.2)
activesupport (= 2.3.2)
@@ -33,8 +38,8 @@ RSpec.describe "bundle lock" do
actionpack (= 2.3.2)
activerecord (= 2.3.2)
activeresource (= 2.3.2)
- rake (= #{rake_version})
- rake (#{rake_version})
+ rake (= 13.0.1)
+ rake (13.0.1)
weakling (0.0.3)
PLATFORMS
@@ -44,219 +49,54 @@ RSpec.describe "bundle lock" do
foo
rails
weakling
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- let(:outdated_lockfile) do
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "actionmailer", "2.3.1"
- c.checksum gem_repo4, "actionpack", "2.3.1"
- c.checksum gem_repo4, "activerecord", "2.3.1"
- c.checksum gem_repo4, "activeresource", "2.3.1"
- c.checksum gem_repo4, "activesupport", "2.3.1"
- c.checksum gem_repo4, "foo", "1.0"
- c.checksum gem_repo4, "rails", "2.3.1"
- c.checksum gem_repo4, "rake", rake_version
- c.checksum gem_repo4, "weakling", "0.0.3"
- end
- <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- actionmailer (2.3.1)
- activesupport (= 2.3.1)
- actionpack (2.3.1)
- activesupport (= 2.3.1)
- activerecord (2.3.1)
- activesupport (= 2.3.1)
- activeresource (2.3.1)
- activesupport (= 2.3.1)
- activesupport (2.3.1)
- foo (1.0)
- rails (2.3.1)
- actionmailer (= 2.3.1)
- actionpack (= 2.3.1)
- activerecord (= 2.3.1)
- activeresource (= 2.3.1)
- rake (= #{rake_version})
- rake (#{rake_version})
- weakling (0.0.3)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo
- rails
- weakling
- #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
end
- before :each do
- build_repo4 do
- FileUtils.cp rake_path, "#{gem_repo4}/gems/"
-
- build_gem "rake", "10.0.1"
-
- %w[2.3.1 2.3.2].each do |version|
- build_gem "rails", version do |s|
- s.executables = "rails"
- s.add_dependency "rake", version == "2.3.1" ? "10.0.1" : rake_version
- s.add_dependency "actionpack", version
- s.add_dependency "activerecord", version
- s.add_dependency "actionmailer", version
- s.add_dependency "activeresource", version
- end
- build_gem "actionpack", version do |s|
- s.add_dependency "activesupport", version
- end
- build_gem "activerecord", version do |s|
- s.add_dependency "activesupport", version
- end
- build_gem "actionmailer", version do |s|
- s.add_dependency "activesupport", version
- end
- build_gem "activeresource", version do |s|
- s.add_dependency "activesupport", version
- end
- build_gem "activesupport", version
- end
-
- build_gem "weakling", "0.0.3"
-
- build_gem "foo"
- end
-
- gemfile <<-G
- source "https://gem.repo4"
- gem "rails"
- gem "weakling"
- gem "foo"
- G
- end
-
it "prints a lockfile when there is no existing lockfile with --print" do
bundle "lock --print"
- expect(out).to eq(expected_lockfile.chomp)
+ expect(out).to eq(@lockfile)
end
it "prints a lockfile when there is an existing lockfile with --print" do
- lockfile expected_lockfile
-
- bundle "lock --print"
-
- expect(out).to eq(expected_lockfile.chomp)
- end
-
- it "prints a lockfile when there is an existing checksums lockfile with --print" do
- lockfile expected_lockfile
+ lockfile @lockfile
bundle "lock --print"
- expect(out).to eq(expected_lockfile.chomp)
+ expect(out).to eq(@lockfile)
end
it "writes a lockfile when there is no existing lockfile" do
bundle "lock"
- expect(read_lockfile).to eq(expected_lockfile)
- end
-
- it "prints a lockfile without fetching new checksums if the existing lockfile had no checksums" do
- lockfile expected_lockfile
-
- bundle "lock --print"
-
- expect(out).to eq(expected_lockfile.chomp)
- end
-
- it "touches the lockfile when there is an existing lockfile that does not need changes" do
- lockfile expected_lockfile
-
- expect do
- bundle "lock"
- end.to change { bundled_app_lock.mtime }
- end
-
- it "does not touch lockfile with --print" do
- lockfile expected_lockfile
-
- expect do
- bundle "lock --print"
- end.not_to change { bundled_app_lock.mtime }
+ expect(read_lockfile).to eq(@lockfile)
end
it "writes a lockfile when there is an outdated lockfile using --update" do
- lockfile outdated_lockfile
+ lockfile @lockfile.gsub("2.3.2", "2.3.1")
bundle "lock --update"
- expect(read_lockfile).to eq(expected_lockfile)
- end
-
- it "prints an updated lockfile when there is an outdated lockfile using --print --update" do
- lockfile outdated_lockfile
-
- bundle "lock --print --update"
-
- expect(out).to eq(expected_lockfile.rstrip)
- end
-
- it "emits info messages to stderr when updating an outdated lockfile using --print --update" do
- lockfile outdated_lockfile
-
- bundle "lock --print --update"
-
- expect(err).to eq(<<~STDERR.rstrip)
- Fetching gem metadata from https://gem.repo4/...
- Resolving dependencies...
- STDERR
- end
-
- it "writes a lockfile when there is an outdated lockfile and bundle is frozen" do
- lockfile outdated_lockfile
-
- bundle "lock --update", env: { "BUNDLE_FROZEN" => "true" }
-
- expect(read_lockfile).to eq(expected_lockfile)
+ expect(read_lockfile).to eq(@lockfile)
end
it "does not fetch remote specs when using the --local option" do
- bundle "lock --update --local", raise_on_error: false
+ bundle "lock --update --local", :raise_on_error => false
expect(err).to match(/locally installed gems/)
end
- it "does not fetch remote checksums with --local" do
- lockfile expected_lockfile
-
- bundle "lock --print --local"
-
- expect(out).to eq(expected_lockfile.chomp)
- end
-
it "works with --gemfile flag" do
- gemfile "CustomGemfile", <<-G
- source "https://gem.repo4"
+ create_file "CustomGemfile", <<-G
+ source "#{file_uri_for(repo)}"
gem "foo"
G
- bundle "lock --gemfile CustomGemfile"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "foo", "1.0"
- end
-
- lockfile = <<~L
+ lockfile = strip_lockfile(<<-L)
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(repo)}/
specs:
foo (1.0)
@@ -265,10 +105,12 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
foo
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
+ bundle "lock --gemfile CustomGemfile"
+
expect(out).to match(/Writing lockfile to.+CustomGemfile\.lock/)
expect(read_lockfile("CustomGemfile.lock")).to eq(lockfile)
expect { read_lockfile }.to raise_error(Errno::ENOENT)
@@ -278,7 +120,7 @@ RSpec.describe "bundle lock" do
bundle "lock --lockfile=lock"
expect(out).to match(/Writing lockfile to.+lock/)
- expect(read_lockfile("lock")).to eq(expected_lockfile)
+ expect(read_lockfile("lock")).to eq(@lockfile)
expect { read_lockfile }.to raise_error(Errno::ENOENT)
end
@@ -286,256 +128,30 @@ RSpec.describe "bundle lock" do
bundle "install"
bundle "lock --lockfile=lock"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "actionmailer", "2.3.2"
- c.checksum gem_repo4, "actionpack", "2.3.2"
- c.checksum gem_repo4, "activerecord", "2.3.2"
- c.checksum gem_repo4, "activeresource", "2.3.2"
- c.checksum gem_repo4, "activesupport", "2.3.2"
- c.checksum gem_repo4, "foo", "1.0"
- c.checksum gem_repo4, "rails", "2.3.2"
- c.checksum gem_repo4, "rake", rake_version
- c.checksum gem_repo4, "weakling", "0.0.3"
- end
-
- lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- actionmailer (2.3.2)
- activesupport (= 2.3.2)
- actionpack (2.3.2)
- activesupport (= 2.3.2)
- activerecord (2.3.2)
- activesupport (= 2.3.2)
- activeresource (2.3.2)
- activesupport (= 2.3.2)
- activesupport (2.3.2)
- foo (1.0)
- rails (2.3.2)
- actionmailer (= 2.3.2)
- actionpack (= 2.3.2)
- activerecord (= 2.3.2)
- activeresource (= 2.3.2)
- rake (= #{rake_version})
- rake (#{rake_version})
- weakling (0.0.3)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo
- rails
- weakling
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
expect(out).to match(/Writing lockfile to.+lock/)
- expect(read_lockfile("lock")).to eq(lockfile)
+ expect(read_lockfile("lock")).to eq(@lockfile)
end
it "update specific gems using --update" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "actionmailer", "2.3.1"
- c.checksum gem_repo4, "actionpack", "2.3.1"
- c.checksum gem_repo4, "activerecord", "2.3.1"
- c.checksum gem_repo4, "activeresource", "2.3.1"
- c.checksum gem_repo4, "activesupport", "2.3.1"
- c.checksum gem_repo4, "foo", "1.0"
- c.checksum gem_repo4, "rails", "2.3.1"
- c.checksum gem_repo4, "rake", "10.0.1"
- c.checksum gem_repo4, "weakling", "0.0.3"
- end
-
- lockfile_with_outdated_rails_and_rake = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- actionmailer (2.3.1)
- activesupport (= 2.3.1)
- actionpack (2.3.1)
- activesupport (= 2.3.1)
- activerecord (2.3.1)
- activesupport (= 2.3.1)
- activeresource (2.3.1)
- activesupport (= 2.3.1)
- activesupport (2.3.1)
- foo (1.0)
- rails (2.3.1)
- actionmailer (= 2.3.1)
- actionpack (= 2.3.1)
- activerecord (= 2.3.1)
- activeresource (= 2.3.1)
- rake (= 10.0.1)
- rake (10.0.1)
- weakling (0.0.3)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo
- rails
- weakling
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- lockfile lockfile_with_outdated_rails_and_rake
+ lockfile @lockfile.gsub("2.3.2", "2.3.1").gsub("13.0.1", "10.0.1")
bundle "lock --update rails rake"
- expect(read_lockfile).to eq(expected_lockfile)
- end
-
- it "updates specific gems using --update, even if that requires unlocking other top level gems" do
- build_repo4 do
- build_gem "prism", "0.15.1"
- build_gem "prism", "0.24.0"
-
- build_gem "ruby-lsp", "0.12.0" do |s|
- s.add_dependency "prism", "< 0.24.0"
- end
-
- build_gem "ruby-lsp", "0.16.1" do |s|
- s.add_dependency "prism", ">= 0.24.0"
- end
-
- build_gem "tapioca", "0.11.10" do |s|
- s.add_dependency "prism", "< 0.24.0"
- end
-
- build_gem "tapioca", "0.13.1" do |s|
- s.add_dependency "prism", ">= 0.24.0"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "tapioca"
- gem "ruby-lsp"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4
- specs:
- prism (0.15.1)
- ruby-lsp (0.12.0)
- prism (< 0.24.0)
- tapioca (0.11.10)
- prism (< 0.24.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- ruby-lsp
- tapioca
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "lock --update tapioca --verbose"
-
- expect(lockfile).to include("tapioca (0.13.1)")
- end
-
- it "updates specific gems using --update, even if that requires unlocking other top level gems, but only as few as possible" do
- build_repo4 do
- build_gem "prism", "0.15.1"
- build_gem "prism", "0.24.0"
-
- build_gem "ruby-lsp", "0.12.0" do |s|
- s.add_dependency "prism", "< 0.24.0"
- end
-
- build_gem "ruby-lsp", "0.16.1" do |s|
- s.add_dependency "prism", ">= 0.24.0"
- end
-
- build_gem "tapioca", "0.11.10" do |s|
- s.add_dependency "prism", "< 0.24.0"
- end
-
- build_gem "tapioca", "0.13.1" do |s|
- s.add_dependency "prism", ">= 0.24.0"
- end
-
- build_gem "other-prism-dependent", "1.0.0" do |s|
- s.add_dependency "prism", ">= 0.15.1"
- end
-
- build_gem "other-prism-dependent", "1.1.0" do |s|
- s.add_dependency "prism", ">= 0.15.1"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "tapioca"
- gem "ruby-lsp"
- gem "other-prism-dependent"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4
- specs:
- other-prism-dependent (1.0.0)
- prism (>= 0.15.1)
- prism (0.15.1)
- ruby-lsp (0.12.0)
- prism (< 0.24.0)
- tapioca (0.11.10)
- prism (< 0.24.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- ruby-lsp
- tapioca
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "lock --update tapioca"
-
- expect(lockfile).to include("tapioca (0.13.1)")
- expect(lockfile).to include("other-prism-dependent (1.0.0)")
- end
-
- it "preserves unknown checksum algorithms" do
- lockfile expected_lockfile.gsub(/(sha256=[a-f0-9]+)$/, "constant=true,\\1,xyz=123")
-
- previous_lockfile = read_lockfile
-
- bundle "lock"
-
- expect(read_lockfile).to eq(previous_lockfile)
+ expect(read_lockfile).to eq(@lockfile)
end
it "does not unlock git sources when only uri shape changes" do
build_git("foo")
install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo-1.0")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
# Change uri format to end with "/" and reinstall
- install_gemfile <<-G, verbose: true
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo-1.0")}/"
+ install_gemfile <<-G, :verbose => true
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}/"
G
expect(out).to include("using resolution from the lockfile")
@@ -546,21 +162,21 @@ RSpec.describe "bundle lock" do
ref = build_git("foo").ref_for("HEAD")
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rake"
- gem "foo", :git => "#{lib_path("foo-1.0")}", :branch => "deadbeef"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}", :branch => "deadbeef"
G
lockfile <<~L
GIT
- remote: #{lib_path("foo-1.0")}
+ remote: #{file_uri_for(lib_path("foo-1.0"))}
revision: #{ref}
branch: deadbeef
specs:
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
rake (10.0.1)
@@ -577,28 +193,28 @@ RSpec.describe "bundle lock" do
bundle "lock --update rake --verbose"
expect(out).to match(/Writing lockfile to.+lock/)
- expect(lockfile).to include("rake (#{rake_version})")
+ expect(lockfile).to include("rake (13.0.1)")
end
it "errors when updating a missing specific gems using --update" do
- lockfile expected_lockfile
+ lockfile @lockfile
- bundle "lock --update blahblah", raise_on_error: false
+ bundle "lock --update blahblah", :raise_on_error => false
expect(err).to eq("Could not find gem 'blahblah'.")
- expect(read_lockfile).to eq(expected_lockfile)
+ expect(read_lockfile).to eq(@lockfile)
end
it "can lock without downloading gems" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "thin"
- gem "myrack_middleware", :group => "test"
+ gem "rack_middleware", :group => "test"
G
bundle "config set without test"
bundle "config set path vendor/bundle"
- bundle "lock", verbose: true
+ bundle "lock"
expect(bundled_app("vendor/bundle")).not_to exist
end
@@ -625,7 +241,7 @@ RSpec.describe "bundle lock" do
# establish a lockfile set to 1.4.3
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo', '1.4.3'
gem 'bar', '2.0.3'
gem 'qux', '1.0.0'
@@ -634,7 +250,7 @@ RSpec.describe "bundle lock" do
# remove 1.4.3 requirement and bar altogether
# to setup update specs below
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo'
gem 'qux'
G
@@ -654,22 +270,6 @@ RSpec.describe "bundle lock" do
expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[foo-1.5.0 bar-2.1.1 qux-1.1.0].sort)
end
- it "shows proper error when Gemfile changes forbid patch upgrades, and --patch --strict is given" do
- # force next minor via Gemfile
- gemfile <<-G
- source "https://gem.repo4"
- gem 'foo', '1.5.0'
- gem 'qux'
- G
-
- bundle "lock --update foo --patch --strict", raise_on_error: false
-
- expect(err).to include(
- "foo is locked to 1.4.3, while Gemfile is requesting foo (= 1.5.0). " \
- "--strict --patch was specified, but there are no patch level upgrades from 1.4.3 satisfying foo (= 1.5.0), so version solving has failed"
- )
- end
-
context "pre" do
it "defaults to major" do
bundle "lock --update --pre"
@@ -697,67 +297,26 @@ RSpec.describe "bundle lock" do
end
end
- context "conservative updates when minor update adds a new dependency" do
- before do
- build_repo4 do
- build_gem "sequel", "5.71.0"
- build_gem "sequel", "5.72.0" do |s|
- s.add_dependency "bigdecimal", ">= 0"
- end
- build_gem "bigdecimal", %w[1.4.4 99.1.4]
- end
-
- gemfile <<~G
- source "https://gem.repo4"
- gem 'sequel'
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- sequel (5.71.0)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- sequel
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- end
-
- it "adds the latest version of the new dependency" do
- bundle "lock --minor --update sequel"
-
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[sequel-5.72.0 bigdecimal-99.1.4].sort)
- end
- end
-
it "updates the bundler version in the lockfile to the latest bundler version" do
build_repo4 do
build_gem "bundler", "55"
end
- system_gems "bundler-55", gem_repo: gem_repo4
+ system_gems "bundler-55", :gem_repo => gem_repo4
- install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- source "https://gem.repo4"
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ source "https://gems.repo4"
G
lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, '\11.0.0\2')
- bundle "lock --update --bundler --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ bundle "lock --update --bundler --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
expect(lockfile).to end_with("BUNDLED WITH\n 55\n")
update_repo4 do
build_gem "bundler", "99"
end
- bundle "lock --update --bundler --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ bundle "lock --update --bundler --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
expect(lockfile).to end_with("BUNDLED WITH\n 99\n")
end
@@ -766,69 +325,13 @@ RSpec.describe "bundle lock" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
- expect(lockfile.platforms).to match_array(default_platform_list(java, x86_mingw32))
- end
-
- it "supports adding new platforms, when most specific locked platform is not the current platform, and current resolve is not compatible with the target platform" do
- simulate_platform "arm64-darwin-23" do
- build_repo4 do
- build_gem "foo" do |s|
- s.platform = "arm64-darwin"
- end
-
- build_gem "foo" do |s|
- s.platform = "java"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo4"
-
- gem "foo"
- G
-
- lockfile <<-L
- GEM
- remote: https://gem.repo4/
- specs:
- foo (1.0-arm64-darwin)
-
- PLATFORMS
- arm64-darwin
-
- DEPENDENCIES
- foo
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "lock --add-platform java"
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- foo (1.0-arm64-darwin)
- foo (1.0-java)
-
- PLATFORMS
- arm64-darwin
- java
-
- DEPENDENCIES
- foo
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
+ expect(lockfile.platforms).to match_array([java, x86_mingw32, local_platform].uniq)
end
it "supports adding new platforms with force_ruby_platform = true" do
lockfile <<-L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
platform_specific (1.0)
platform_specific (1.0-x86-64_linux)
@@ -854,13 +357,12 @@ RSpec.describe "bundle lock" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
- expect(lockfile.platforms).to match_array(default_platform_list("ruby"))
+ expect(lockfile.platforms).to match_array(["ruby", local_platform].uniq)
end
- it "fails when adding an unknown platform" do
- bundle "lock --add-platform foobarbaz", raise_on_error: false
- expect(err).to include("The platform `foobarbaz` is unknown to RubyGems and can't be added to the lockfile")
- expect(last_command).to be_failure
+ it "warns when adding an unknown platform" do
+ bundle "lock --add-platform foobarbaz"
+ expect(err).to include("The platform `foobarbaz` is unknown to RubyGems and adding it will likely lead to resolution errors")
end
it "allows removing platforms" do
@@ -868,12 +370,12 @@ RSpec.describe "bundle lock" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
lockfile = Bundler::LockfileParser.new(read_lockfile)
- expect(lockfile.platforms).to match_array(default_platform_list(java, x86_mingw32))
+ expect(lockfile.platforms).to match_array([java, x86_mingw32, local_platform].uniq)
bundle "lock --remove-platform java"
lockfile = Bundler::LockfileParser.new(read_lockfile)
- expect(lockfile.platforms).to match_array(default_platform_list(x86_mingw32))
+ expect(lockfile.platforms).to match_array([x86_mingw32, local_platform].uniq)
end
it "also cleans up redundant platform gems when removing platforms" do
@@ -884,14 +386,9 @@ RSpec.describe "bundle lock" do
end
end
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.12.0"
- c.checksum gem_repo4, "nokogiri", "1.12.0", "x86_64-darwin"
- end
-
simulate_platform "x86_64-darwin-22" do
install_gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "nokogiri"
G
@@ -899,7 +396,7 @@ RSpec.describe "bundle lock" do
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.12.0)
nokogiri (1.12.0-x86_64-darwin)
@@ -910,20 +407,18 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
nokogiri
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
- checksums.delete("nokogiri", Gem::Platform::RUBY)
-
simulate_platform "x86_64-darwin-22" do
bundle "lock --remove-platform ruby"
end
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.12.0-x86_64-darwin)
@@ -932,14 +427,14 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
nokogiri
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "errors when removing all platforms" do
- bundle "lock --remove-platform #{local_platform}", raise_on_error: false
+ bundle "lock --remove-platform #{local_platform}", :raise_on_error => false
expect(err).to include("Removing all platforms from the bundle is not allowed")
end
@@ -974,7 +469,7 @@ RSpec.describe "bundle lock" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "mixlib-shellout"
gem "gssapi"
@@ -982,16 +477,9 @@ RSpec.describe "bundle lock" do
simulate_platform(x86_mingw32) { bundle :lock }
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "ffi", "1.9.14", "x86-mingw32"
- c.checksum gem_repo4, "gssapi", "1.2.0"
- c.checksum gem_repo4, "mixlib-shellout", "2.2.6", "universal-mingw32"
- c.checksum gem_repo4, "win32-process", "0.8.3"
- end
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
ffi (1.9.14-x86-mingw32)
gssapi (1.2.0)
@@ -1007,7 +495,7 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
gssapi
mixlib-shellout
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1015,12 +503,9 @@ RSpec.describe "bundle lock" do
bundle "config set --local force_ruby_platform true"
bundle :lock
- checksums.checksum gem_repo4, "ffi", "1.9.14"
- checksums.checksum gem_repo4, "mixlib-shellout", "2.2.6"
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
ffi (1.9.14)
ffi (1.9.14-x86-mingw32)
@@ -1039,7 +524,7 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
gssapi
mixlib-shellout
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1058,14 +543,14 @@ RSpec.describe "bundle lock" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "libv8"
G
lockfile <<-G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
libv8 (8.4.255.0)
libv8 (8.4.255.0-x86_64-darwin-19)
@@ -1081,7 +566,7 @@ RSpec.describe "bundle lock" do
#{Bundler::VERSION}
G
- simulate_platform("x86_64-darwin-19") { bundle "lock --update" }
+ simulate_platform(Gem::Platform.new("x86_64-darwin-19")) { bundle "lock --update" }
expect(out).to match(/Writing lockfile to.+Gemfile\.lock/)
end
@@ -1098,32 +583,26 @@ RSpec.describe "bundle lock" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "libv8"
G
- simulate_platform("x86_64-darwin-19") { bundle "lock" }
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-19"
- c.checksum gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-20"
- end
+ simulate_platform(Gem::Platform.new("x86_64-darwin")) { bundle "lock" }
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
libv8 (8.4.255.0-x86_64-darwin-19)
libv8 (8.4.255.0-x86_64-darwin-20)
PLATFORMS
- x86_64-darwin-19
- x86_64-darwin-20
+ x86_64-darwin
DEPENDENCIES
libv8
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1140,20 +619,15 @@ RSpec.describe "bundle lock" do
end
end
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-19"
- c.checksum gem_repo4, "libv8", "8.4.255.0", "x86_64-darwin-20"
- end
-
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "libv8"
G
lockfile <<-G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
libv8 (8.4.255.0-x86_64-darwin-19)
libv8 (8.4.255.0-x86_64-darwin-20)
@@ -1163,7 +637,7 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
libv8
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1171,7 +645,7 @@ RSpec.describe "bundle lock" do
previous_lockfile = lockfile
%w[x86_64-darwin-19 x86_64-darwin-20].each do |platform|
- simulate_platform(platform) do
+ simulate_platform(Gem::Platform.new(platform)) do
bundle "lock"
expect(lockfile).to eq(previous_lockfile)
@@ -1205,14 +679,14 @@ RSpec.describe "bundle lock" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "https://localgemserver.test"
gem "raygun-apm"
G
lockfile <<-L
GEM
- remote: https://gem.repo4/
+ remote: https://localgemserver.test/
specs:
raygun-apm (1.0.78-universal-darwin)
@@ -1226,61 +700,7 @@ RSpec.describe "bundle lock" do
#{Bundler::VERSION}
L
- bundle "lock --add-platform x86_64-linux"
- end
-
- it "adds platform specific gems as necessary, even when adding the current platform" do
- build_repo4 do
- build_gem "nokogiri", "1.16.0"
-
- build_gem "nokogiri", "1.16.0" do |s|
- s.platform = "x86_64-linux"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo4"
-
- gem "nokogiri"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.16.0)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- nokogiri
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- simulate_platform "x86_64-linux" do
- bundle "lock --add-platform x86_64-linux"
- end
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.16.0)
- nokogiri (1.16.0-x86_64-linux)
-
- PLATFORMS
- ruby
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
+ bundle "lock --add-platform x86_64-linux", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
end
it "does not crash on conflicting ruby requirements between platform versions in two different gems" do
@@ -1336,7 +756,7 @@ RSpec.describe "bundle lock" do
#{Bundler::VERSION}
L
- bundle "install --verbose", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s, "DEBUG_RESOLVER" => "1" }
+ bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s, "DEBUG_RESOLVER" => "1" }
end
it "respects lower bound ruby requirements" do
@@ -1368,123 +788,30 @@ RSpec.describe "bundle lock" do
#{Bundler::VERSION}
L
- bundle "install", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ bundle "install", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
end
context "when an update is available" do
+ let(:repo) { gem_repo2 }
+
before do
- update_repo4 do
+ lockfile(@lockfile)
+ build_repo2 do
build_gem "foo", "2.0"
end
-
- lockfile(expected_lockfile)
end
it "does not implicitly update" do
bundle "lock"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "actionmailer", "2.3.2"
- c.checksum gem_repo4, "actionpack", "2.3.2"
- c.checksum gem_repo4, "activerecord", "2.3.2"
- c.checksum gem_repo4, "activeresource", "2.3.2"
- c.checksum gem_repo4, "activesupport", "2.3.2"
- c.checksum gem_repo4, "foo", "1.0"
- c.checksum gem_repo4, "rails", "2.3.2"
- c.checksum gem_repo4, "rake", rake_version
- c.checksum gem_repo4, "weakling", "0.0.3"
- end
-
- expected_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- actionmailer (2.3.2)
- activesupport (= 2.3.2)
- actionpack (2.3.2)
- activesupport (= 2.3.2)
- activerecord (2.3.2)
- activesupport (= 2.3.2)
- activeresource (2.3.2)
- activesupport (= 2.3.2)
- activesupport (2.3.2)
- foo (1.0)
- rails (2.3.2)
- actionmailer (= 2.3.2)
- actionpack (= 2.3.2)
- activerecord (= 2.3.2)
- activeresource (= 2.3.2)
- rake (= #{rake_version})
- rake (#{rake_version})
- weakling (0.0.3)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo
- rails
- weakling
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- expect(read_lockfile).to eq(expected_lockfile)
+ expect(read_lockfile).to eq(@lockfile)
end
it "accounts for changes in the gemfile" do
gemfile gemfile.gsub('"foo"', '"foo", "2.0"')
bundle "lock"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "actionmailer", "2.3.2"
- c.checksum gem_repo4, "actionpack", "2.3.2"
- c.checksum gem_repo4, "activerecord", "2.3.2"
- c.checksum gem_repo4, "activeresource", "2.3.2"
- c.checksum gem_repo4, "activesupport", "2.3.2"
- c.checksum gem_repo4, "foo", "2.0"
- c.checksum gem_repo4, "rails", "2.3.2"
- c.checksum gem_repo4, "rake", rake_version
- c.checksum gem_repo4, "weakling", "0.0.3"
- end
-
- expected_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- actionmailer (2.3.2)
- activesupport (= 2.3.2)
- actionpack (2.3.2)
- activesupport (= 2.3.2)
- activerecord (2.3.2)
- activesupport (= 2.3.2)
- activeresource (2.3.2)
- activesupport (= 2.3.2)
- activesupport (2.3.2)
- foo (2.0)
- rails (2.3.2)
- actionmailer (= 2.3.2)
- actionpack (= 2.3.2)
- activerecord (= 2.3.2)
- activeresource (= 2.3.2)
- rake (= #{rake_version})
- rake (#{rake_version})
- weakling (0.0.3)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- foo (= 2.0)
- rails
- weakling
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- expect(read_lockfile).to eq(expected_lockfile)
+ expect(read_lockfile).to eq(@lockfile.sub("foo (1.0)", "foo (2.0)").sub(/foo$/, "foo (= 2.0)"))
end
end
@@ -1498,8 +825,8 @@ RSpec.describe "bundle lock" do
build_gem "irb", "1.5.0"
end
- system_gems "irb-1.5.0", gem_repo: gem_repo4
- system_gems "debug-1.6.3", gem_repo: gem_repo4
+ system_gems "irb-1.5.0", :gem_repo => gem_repo4
+ system_gems "debug-1.6.3", :gem_repo => gem_repo4
# simulate gemspec with wrong empty dependencies
debug_gemspec_path = system_gem_path("specifications/debug-1.6.3.gemspec")
@@ -1510,19 +837,14 @@ RSpec.describe "bundle lock" do
it "respects the existing lockfile, even when reresolving" do
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "debug"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "debug", "1.6.3"
- c.checksum gem_repo4, "irb", "1.5.0"
- end
-
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
debug (1.6.3)
irb (>= 1.3.6)
@@ -1533,7 +855,7 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
debug
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1544,7 +866,7 @@ RSpec.describe "bundle lock" do
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
debug (1.6.3)
irb (>= 1.3.6)
@@ -1556,7 +878,7 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
debug
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1583,13 +905,13 @@ RSpec.describe "bundle lock" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "rails", ">= 7.0.3.1"
gem "activeadmin", "2.13.1"
G
- bundle "lock", raise_on_error: false
+ bundle "lock", :raise_on_error => false
expect(err).to eq <<~ERR.strip
Could not find compatible versions
@@ -1597,7 +919,7 @@ RSpec.describe "bundle lock" do
Because rails >= 7.0.4 depends on railties = 7.0.4
and rails < 7.0.4 depends on railties = 7.0.3.1,
railties = 7.0.3.1 OR = 7.0.4 is required.
- So, because railties = 7.0.3.1 OR = 7.0.4 could not be found in rubygems repository https://gem.repo4/ or installed locally,
+ So, because railties = 7.0.3.1 OR = 7.0.4 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally,
version solving has failed.
ERR
end
@@ -1638,7 +960,7 @@ RSpec.describe "bundle lock" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "rails", ">= 7.0.2.3"
gem "activeadmin", "= 2.13.1"
@@ -1646,7 +968,7 @@ RSpec.describe "bundle lock" do
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
activeadmin (2.13.1)
ransack (= 3.1.0)
@@ -1654,7 +976,7 @@ RSpec.describe "bundle lock" do
activemodel (>= 6.0.4)
PLATFORMS
- #{local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
activeadmin (= 2.13.1)
@@ -1664,34 +986,54 @@ RSpec.describe "bundle lock" do
#{Bundler::VERSION}
L
- expected_error = <<~ERR.strip
+ bundle "lock", :raise_on_error => false
+
+ expect(err).to eq <<~ERR.strip
Could not find compatible versions
- Because rails >= 7.0.4 depends on activemodel = 7.0.4
- and rails >= 7.0.3.1, < 7.0.4 depends on activemodel = 7.0.3.1,
- rails >= 7.0.3.1 requires activemodel = 7.0.3.1 OR = 7.0.4.
- (1) So, because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3
- and every version of activemodel depends on activesupport = 6.0.4,
- rails >= 7.0.2.3 requires activesupport = 6.0.4.
+ Because every version of activemodel depends on activesupport = 6.0.4
+ and rails >= 7.0.2.3, < 7.0.3.1 depends on activesupport = 7.0.2.3,
+ every version of activemodel is incompatible with rails >= 7.0.2.3, < 7.0.3.1.
+ And because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3,
+ rails >= 7.0.2.3, < 7.0.3.1 cannot be used.
+ (1) So, because rails >= 7.0.3.1, < 7.0.4 depends on activemodel = 7.0.3.1
+ and rails >= 7.0.4 depends on activemodel = 7.0.4,
+ rails >= 7.0.2.3 requires activemodel = 7.0.3.1 OR = 7.0.4.
- Because rails >= 7.0.2.3, < 7.0.3.1 depends on activesupport = 7.0.2.3
+ Because rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3
and rails >= 7.0.3.1, < 7.0.4 depends on activesupport = 7.0.3.1,
- rails >= 7.0.2.3, < 7.0.4 requires activesupport = 7.0.2.3 OR = 7.0.3.1.
- And because rails >= 7.0.4 depends on activesupport = 7.0.4,
- rails >= 7.0.2.3 requires activesupport = 7.0.2.3 OR = 7.0.3.1 OR = 7.0.4.
- And because rails >= 7.0.2.3 requires activesupport = 6.0.4 (1),
+ rails >= 7.0.2.3, < 7.0.4 requires activemodel = 7.0.2.3 or activesupport = 7.0.3.1.
+ And because rails >= 7.0.4 depends on activesupport = 7.0.4
+ and every version of activemodel depends on activesupport = 6.0.4,
+ activemodel != 7.0.2.3 is incompatible with rails >= 7.0.2.3.
+ And because rails >= 7.0.2.3 requires activemodel = 7.0.3.1 OR = 7.0.4 (1),
rails >= 7.0.2.3 cannot be used.
So, because Gemfile depends on rails >= 7.0.2.3,
version solving has failed.
ERR
- bundle "lock", raise_on_error: false
- expect(err).to eq(expected_error)
+ lockfile lockfile.gsub(/PLATFORMS\n #{lockfile_platforms}/m, "PLATFORMS\n #{lockfile_platforms("ruby")}")
+
+ bundle "lock", :raise_on_error => false
- lockfile lockfile.gsub(/PLATFORMS\n #{local_platform}/m, "PLATFORMS\n #{lockfile_platforms("ruby")}")
+ expect(err).to eq <<~ERR.strip
+ Could not find compatible versions
- bundle "lock", raise_on_error: false
- expect(err).to eq(expected_error)
+ Because rails >= 7.0.3.1, < 7.0.4 depends on activemodel = 7.0.3.1
+ and rails >= 7.0.2.3, < 7.0.3.1 depends on activemodel = 7.0.2.3,
+ rails >= 7.0.2.3, < 7.0.4 requires activemodel = 7.0.2.3 OR = 7.0.3.1.
+ And because every version of activemodel depends on activesupport = 6.0.4,
+ rails >= 7.0.2.3, < 7.0.4 requires activesupport = 6.0.4.
+ Because rails >= 7.0.3.1, < 7.0.4 depends on activesupport = 7.0.3.1
+ and rails >= 7.0.2.3, < 7.0.3.1 depends on activesupport = 7.0.2.3,
+ rails >= 7.0.2.3, < 7.0.4 requires activesupport = 7.0.2.3 OR = 7.0.3.1.
+ Thus, rails >= 7.0.2.3, < 7.0.4 cannot be used.
+ And because rails >= 7.0.4 depends on activemodel = 7.0.4,
+ rails >= 7.0.2.3 requires activemodel = 7.0.4.
+ So, because activemodel = 7.0.4 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally
+ and Gemfile depends on rails >= 7.0.2.3,
+ version solving has failed.
+ ERR
end
it "does not accidentally resolves to prereleases" do
@@ -1711,7 +1053,7 @@ RSpec.describe "bundle lock" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "autoproj", ">= 2.0.0"
G
@@ -1736,7 +1078,7 @@ RSpec.describe "bundle lock" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "rails"
G
@@ -1759,13 +1101,13 @@ RSpec.describe "bundle lock" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "activerecord", "6.0.6"
gem "activerecord-jdbc-adapter", "61.0"
G
simulate_platform "universal-java-19" do
- bundle "lock", raise_on_error: false
+ bundle "lock", :raise_on_error => false
end
expect(err).to include("Could not find compatible versions")
@@ -1785,7 +1127,7 @@ RSpec.describe "bundle lock" do
it "does not end up including gems scoped to other platforms in the lockfile" do
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "rails"
gem "tzinfo-data", platform: :windows
G
@@ -1800,7 +1142,7 @@ RSpec.describe "bundle lock" do
context "when resolving platform specific gems as indirect dependencies on truffleruby", :truffleruby_only do
before do
- build_lib "foo", path: bundled_app do |s|
+ build_lib "foo", :path => bundled_app do |s|
s.add_dependency "nokogiri"
end
@@ -1812,18 +1154,12 @@ RSpec.describe "bundle lock" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gemspec
G
end
- it "locks both ruby and platform specific specs" do
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo4, "nokogiri", "1.14.2"
- c.checksum gem_repo4, "nokogiri", "1.14.2", "x86_64-linux"
- end
-
+ it "locks ruby specs" do
simulate_platform "x86_64-linux" do
bundle "lock"
end
@@ -1836,89 +1172,20 @@ RSpec.describe "bundle lock" do
nokogiri
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.14.2)
- nokogiri (1.14.2-x86_64-linux)
PLATFORMS
- ruby
x86_64-linux
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
-
- context "and a lockfile with platform specific gems only already exists" do
- before do
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo4, "nokogiri", "1.14.2", "x86_64-linux"
- end
-
- lockfile <<~L
- PATH
- remote: .
- specs:
- foo (1.0)
- nokogiri
-
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.14.2-x86_64-linux)
-
- PLATFORMS
- x86_64-linux
-
- DEPENDENCIES
- foo!
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "keeps platform specific gems" do
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo4, "nokogiri", "1.14.2"
- c.checksum gem_repo4, "nokogiri", "1.14.2", "x86_64-linux"
- end
-
- simulate_platform "x86_64-linux" do
- bundle "install"
- end
-
- expect(lockfile).to eq <<~L
- PATH
- remote: .
- specs:
- foo (1.0)
- nokogiri
-
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.14.2)
- nokogiri (1.14.2-x86_64-linux)
-
- PLATFORMS
- ruby
- x86_64-linux
-
- DEPENDENCIES
- foo!
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
end
context "when adding a new gem that requires unlocking other transitive deps" do
@@ -1942,7 +1209,7 @@ RSpec.describe "bundle lock" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "govuk_app_config"
gem "activesupport", "7.0.4.3"
@@ -1953,7 +1220,7 @@ RSpec.describe "bundle lock" do
# version
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
actionpack (7.0.4.1)
activesupport (7.0.4.1)
@@ -1975,20 +1242,13 @@ RSpec.describe "bundle lock" do
end
it "does not downgrade top level dependencies" do
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "actionpack", "7.0.4.3"
- c.no_checksum "activesupport", "7.0.4.3"
- c.no_checksum "govuk_app_config", "4.13.0"
- c.no_checksum "railties", "7.0.4.3"
- end
-
simulate_platform "arm64-darwin-22" do
bundle "lock"
end
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
actionpack (7.0.4.3)
activesupport (7.0.4.3)
@@ -2004,66 +1264,6 @@ RSpec.describe "bundle lock" do
DEPENDENCIES
activesupport (= 7.0.4.3)
govuk_app_config
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- context "when lockfile has incorrectly indented platforms" do
- before do
- build_repo4 do
- build_gem "ffi", "1.1.0" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "ffi", "1.1.0" do |s|
- s.platform = "arm64-darwin"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "ffi"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- ffi (1.1.0-arm64-darwin)
-
- PLATFORMS
- arm64-darwin
-
- DEPENDENCIES
- ffi
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "does not remove any gems" do
- simulate_platform "x86_64-linux" do
- bundle "lock --update"
- end
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- ffi (1.1.0-arm64-darwin)
- ffi (1.1.0-x86_64-linux)
-
- PLATFORMS
- arm64-darwin
- x86_64-linux
-
- DEPENDENCIES
- ffi
BUNDLED WITH
#{Bundler::VERSION}
diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb
index 668bc0f95e..ede1ff6b8e 100644
--- a/spec/bundler/commands/newgem_spec.rb
+++ b/spec/bundler/commands/newgem_spec.rb
@@ -12,14 +12,14 @@ RSpec.describe "bundle gem" do
def bundle_exec_rubocop
prepare_gemspec(bundled_app(gem_name, "#{gem_name}.gemspec"))
- bundle "config set path #{rubocop_gems}", dir: bundled_app(gem_name)
- bundle "exec rubocop --debug --config .rubocop.yml", dir: bundled_app(gem_name)
+ bundle "config set path #{rubocop_gems}", :dir => bundled_app(gem_name)
+ bundle "exec rubocop --debug --config .rubocop.yml", :dir => bundled_app(gem_name)
end
def bundle_exec_standardrb
prepare_gemspec(bundled_app(gem_name, "#{gem_name}.gemspec"))
- bundle "config set path #{standard_gems}", dir: bundled_app(gem_name)
- bundle "exec standardrb --debug", dir: bundled_app(gem_name)
+ bundle "config set path #{standard_gems}", :dir => bundled_app(gem_name)
+ bundle "exec standardrb --debug", :dir => bundled_app(gem_name)
end
let(:generated_gemspec) { Bundler.load_gemspec_uncached(bundled_app(gem_name).join("#{gem_name}.gemspec")) }
@@ -33,28 +33,25 @@ RSpec.describe "bundle gem" do
let(:minitest_test_class_name) { "class TestMygem < Minitest::Test" }
before do
- git("config --global user.name 'Bundler User'")
- git("config --global user.email user@example.com")
- git("config --global github.user bundleuser")
-
- global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false",
- "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
+ sys_exec("git config --global user.name 'Bundler User'")
+ sys_exec("git config --global user.email user@example.com")
+ sys_exec("git config --global github.user bundleuser")
end
describe "git repo initialization" do
- it "generates a gem skeleton with a .git folder" do
+ it "generates a gem skeleton with a .git folder", :readline do
bundle "gem #{gem_name}"
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/.git")).to exist
end
- it "generates a gem skeleton with a .git folder when passing --git" do
+ it "generates a gem skeleton with a .git folder when passing --git", :readline do
bundle "gem #{gem_name} --git"
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/.git")).to exist
end
- it "generates a gem skeleton without a .git folder when passing --no-git" do
+ it "generates a gem skeleton without a .git folder when passing --no-git", :readline do
bundle "gem #{gem_name} --no-git"
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/.git")).not_to exist
@@ -65,10 +62,8 @@ RSpec.describe "bundle gem" do
Dir.mkdir(bundled_app("path with spaces"))
end
- it "properly initializes git repo" do
- skip "path with spaces needs special handling on Windows" if Gem.win_platform?
-
- bundle "gem #{gem_name}", dir: bundled_app("path with spaces")
+ it "properly initializes git repo", :readline do
+ bundle "gem #{gem_name}", :dir => bundled_app("path with spaces")
expect(bundled_app("path with spaces/#{gem_name}/.git")).to exist
end
end
@@ -108,8 +103,8 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/README.md").read).to match(%r{https://github\.com/bundleuser/#{gem_name}/blob/.*/CODE_OF_CONDUCT.md})
end
- it "generates the README with a section for the Code of Conduct, respecting the configured git default branch", git: ">= 2.28.0" do
- git("config --global init.defaultBranch main")
+ it "generates the README with a section for the Code of Conduct, respecting the configured git default branch", :git => ">= 2.28.0" do
+ sys_exec("git config --global init.defaultBranch main")
bundle "gem #{gem_name} --coc"
expect(bundled_app("#{gem_name}/README.md").read).to include("## Code of Conduct")
@@ -136,7 +131,7 @@ RSpec.describe "bundle gem" do
before do
bundle "gem #{gem_name} --changelog"
end
- it "generates a gem skeleton with a CHANGELOG" do
+ it "generates a gem skeleton with a CHANGELOG", :readline do
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/CHANGELOG.md")).to exist
end
@@ -146,16 +141,15 @@ RSpec.describe "bundle gem" do
before do
bundle "gem #{gem_name} --no-changelog"
end
- it "generates a gem skeleton without a CHANGELOG" do
+ it "generates a gem skeleton without a CHANGELOG", :readline do
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/CHANGELOG.md")).to_not exist
end
end
shared_examples_for "--rubocop flag" do
- context "is deprecated", bundler: "< 3" do
+ context "is deprecated", :bundler => "< 3" do
before do
- global_config "BUNDLE_GEM__LINTER" => nil
bundle "gem #{gem_name} --rubocop"
end
@@ -185,7 +179,7 @@ RSpec.describe "bundle gem" do
end
shared_examples_for "--no-rubocop flag" do
- context "is deprecated", bundler: "< 3" do
+ context "is deprecated", :bundler => "< 3" do
define_negated_matcher :exclude, :include
before do
@@ -269,11 +263,11 @@ RSpec.describe "bundle gem" do
end
end
- shared_examples_for "--no-linter flag" do
+ shared_examples_for "--linter=none flag" do
define_negated_matcher :exclude, :include
before do
- bundle "gem #{gem_name} --no-linter"
+ bundle "gem #{gem_name} --linter=none"
end
it "generates a gem skeleton without rubocop" do
@@ -309,49 +303,49 @@ RSpec.describe "bundle gem" do
end
end
- it "has no rubocop offenses when using --linter=rubocop flag" do
+ it "has no rubocop offenses when using --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=c and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=c and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext=c --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=c, --test=minitest, and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=c, --test=minitest, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext=c --test=minitest --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=c, --test=rspec, and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=c, --test=rspec, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext=c --test=rspec --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=c, --test=test-unit, and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=c, --test=test-unit, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext=c --test=test-unit --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
- it "has no standard offenses when using --linter=standard flag" do
+ it "has no standard offenses when using --linter=standard flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --linter=standard"
bundle_exec_standardrb
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=rust and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=rust and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
@@ -360,7 +354,7 @@ RSpec.describe "bundle gem" do
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=rust, --test=minitest, and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=rust, --test=minitest, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
@@ -369,7 +363,7 @@ RSpec.describe "bundle gem" do
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=rust, --test=rspec, and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=rust, --test=rspec, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
@@ -378,7 +372,7 @@ RSpec.describe "bundle gem" do
expect(last_command).to be_success
end
- it "has no rubocop offenses when using --ext=rust, --test=test-unit, and --linter=rubocop flag" do
+ it "has no rubocop offenses when using --ext=rust, --test=test-unit, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
skip "RubyGems incompatible with Rust builder" if ::Gem::Version.new("3.3.11") > ::Gem.rubygems_version
@@ -405,7 +399,7 @@ RSpec.describe "bundle gem" do
end
end
- context "README.md" do
+ context "README.md", :readline do
context "git config github.user present" do
before do
bundle "gem #{gem_name}"
@@ -419,7 +413,7 @@ RSpec.describe "bundle gem" do
context "git config github.user is absent" do
before do
- git("config --global --unset github.user")
+ sys_exec("git config --global --unset github.user")
bundle "gem #{gem_name}"
end
@@ -430,18 +424,18 @@ RSpec.describe "bundle gem" do
end
end
- it "creates a new git repository" do
+ it "creates a new git repository", :readline do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.git")).to exist
end
- context "when git is not available" do
+ context "when git is not available", :readline do
# This spec cannot have `git` available in the test env
before do
load_paths = [lib_dir, spec_dir]
load_path_str = "-I#{load_paths.join(File::PATH_SEPARATOR)}"
- sys_exec "#{Gem.ruby} #{load_path_str} #{bindir.join("bundle")} gem #{gem_name}", env: { "PATH" => "" }
+ sys_exec "#{Gem.ruby} #{load_path_str} #{bindir.join("bundle")} gem #{gem_name}", :env => { "PATH" => "" }
end
it "creates the gem without the need for git" do
@@ -457,24 +451,24 @@ RSpec.describe "bundle gem" do
end
end
- it "generates a valid gemspec", :ruby_repo do
+ it "generates a valid gemspec", :readline, :ruby_repo do
bundle "gem newgem --bin"
prepare_gemspec(bundled_app("newgem", "newgem.gemspec"))
- gems = ["rake-#{rake_version}"]
- path = Bundler.feature_flag.default_install_uses_path? ? local_gem_path(base: bundled_app("newgem")) : system_gem_path
- system_gems gems, path: path
- bundle "exec rake build", dir: bundled_app("newgem")
+ gems = ["rake-13.0.1"]
+ path = Bundler.feature_flag.default_install_uses_path? ? local_gem_path(:base => bundled_app("newgem")) : system_gem_path
+ system_gems gems, :path => path
+ bundle "exec rake build", :dir => bundled_app("newgem")
expect(last_command.stdboth).not_to include("ERROR")
end
- context "gem naming with relative paths" do
+ context "gem naming with relative paths", :readline do
it "resolves ." do
create_temporary_dir("tmp")
- bundle "gem .", dir: bundled_app("tmp")
+ bundle "gem .", :dir => bundled_app("tmp")
expect(bundled_app("tmp/lib/tmp.rb")).to exist
end
@@ -482,7 +476,7 @@ RSpec.describe "bundle gem" do
it "resolves .." do
create_temporary_dir("temp/empty_dir")
- bundle "gem ..", dir: bundled_app("temp/empty_dir")
+ bundle "gem ..", :dir => bundled_app("temp/empty_dir")
expect(bundled_app("temp/lib/temp.rb")).to exist
end
@@ -490,7 +484,7 @@ RSpec.describe "bundle gem" do
it "resolves relative directory" do
create_temporary_dir("tmp/empty/tmp")
- bundle "gem ../../empty", dir: bundled_app("tmp/empty/tmp")
+ bundle "gem ../../empty", :dir => bundled_app("tmp/empty/tmp")
expect(bundled_app("tmp/empty/lib/empty.rb")).to exist
end
@@ -563,12 +557,8 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/bin/setup")).to exist
expect(bundled_app("#{gem_name}/bin/console")).to exist
-
- unless Gem.win_platform?
- expect(bundled_app("#{gem_name}/bin/setup")).to be_executable
- expect(bundled_app("#{gem_name}/bin/console")).to be_executable
- end
-
+ expect(bundled_app("#{gem_name}/bin/setup")).to be_executable
+ expect(bundled_app("#{gem_name}/bin/console")).to be_executable
expect(bundled_app("#{gem_name}/bin/setup").read).to start_with("#!")
expect(bundled_app("#{gem_name}/bin/console").read).to start_with("#!")
end
@@ -601,8 +591,8 @@ RSpec.describe "bundle gem" do
context "git config user.{name,email} is not set" do
before do
- git("config --global --unset user.name")
- git("config --global --unset user.email")
+ sys_exec("git config --global --unset user.name")
+ sys_exec("git config --global --unset user.email")
bundle "gem #{gem_name}"
end
@@ -659,9 +649,9 @@ RSpec.describe "bundle gem" do
it "runs rake without problems" do
bundle "gem #{gem_name}"
- system_gems ["rake-#{rake_version}"]
+ system_gems ["rake-13.0.1"]
- rakefile = <<~RAKEFILE
+ rakefile = strip_whitespace <<-RAKEFILE
task :default do
puts 'SUCCESS'
end
@@ -670,7 +660,7 @@ RSpec.describe "bundle gem" do
file.puts rakefile
end
- sys_exec(rake, dir: bundled_app(gem_name))
+ sys_exec(rake, :dir => bundled_app(gem_name))
expect(out).to include("SUCCESS")
end
@@ -681,9 +671,6 @@ RSpec.describe "bundle gem" do
it "builds exe skeleton" do
expect(bundled_app("#{gem_name}/exe/#{gem_name}")).to exist
- unless Gem.win_platform?
- expect(bundled_app("#{gem_name}/exe/#{gem_name}")).to be_executable
- end
end
it "requires the main file" do
@@ -742,30 +729,6 @@ RSpec.describe "bundle gem" do
end
end
- context "init_gems_rb setting to true" do
- before do
- bundle "config set init_gems_rb true"
- bundle "gem #{gem_name}"
- end
-
- it "generates gems.rb instead of Gemfile" do
- expect(bundled_app("#{gem_name}/gems.rb")).to exist
- expect(bundled_app("#{gem_name}/Gemfile")).to_not exist
- end
- end
-
- context "init_gems_rb setting to false" do
- before do
- bundle "config set init_gems_rb false"
- bundle "gem #{gem_name}"
- end
-
- it "generates Gemfile instead of gems.rb" do
- expect(bundled_app("#{gem_name}/gems.rb")).to_not exist
- expect(bundled_app("#{gem_name}/Gemfile")).to exist
- end
- end
-
context "gem.test setting set to rspec" do
before do
bundle "config set gem.test rspec"
@@ -834,13 +797,17 @@ RSpec.describe "bundle gem" do
end
it "creates a default rake task to run the test suite" do
- rakefile = <<~RAKEFILE
+ rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
- require "minitest/test_task"
+ require "rake/testtask"
- Minitest::TestTask.create
+ Rake::TestTask.new(:test) do |t|
+ t.libs << "test"
+ t.libs << "lib"
+ t.test_files = FileList["test/**/test_*.rb"]
+ end
task default: :test
RAKEFILE
@@ -881,17 +848,6 @@ RSpec.describe "bundle gem" do
end
end
- context "--test parameter set to an invalid value" do
- before do
- bundle "gem #{gem_name} --test=foo", raise_on_error: false
- end
-
- it "fails loudly" do
- expect(last_command).to be_failure
- expect(err).to match(/Expected '--test' to be one of .*; got foo/)
- end
- end
-
context "gem.test setting set to test-unit" do
before do
bundle "config set gem.test test-unit"
@@ -899,7 +855,7 @@ RSpec.describe "bundle gem" do
end
it "creates a default rake task to run the test suite" do
- rakefile = <<~RAKEFILE
+ rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
@@ -918,7 +874,7 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.test set to rspec and --test with no arguments" do
+ context "gem.test set to rspec and --test with no arguments", :hint_text do
before do
bundle "config set gem.test rspec"
bundle "gem #{gem_name} --test"
@@ -935,12 +891,10 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.test setting set to false and --test with no arguments", :readline do
+ context "gem.test setting set to false and --test with no arguments", :hint_text do
before do
bundle "config set gem.test false"
- bundle "gem #{gem_name} --test" do |input, _, _|
- input.puts
- end
+ bundle "gem #{gem_name} --test"
end
it "asks to generate test files" do
@@ -954,12 +908,9 @@ RSpec.describe "bundle gem" do
it_behaves_like "test framework is absent"
end
- context "gem.test setting not set and --test with no arguments", :readline do
+ context "gem.test setting not set and --test with no arguments", :hint_text do
before do
- global_config "BUNDLE_GEM__TEST" => nil
- bundle "gem #{gem_name} --test" do |input, _, _|
- input.puts
- end
+ bundle "gem #{gem_name} --test"
end
it "asks to generate test files" do
@@ -975,15 +926,6 @@ RSpec.describe "bundle gem" do
it_behaves_like "test framework is absent"
end
- context "gem.test setting set to a test framework and --no-test" do
- before do
- bundle "config set gem.test rspec"
- bundle "gem #{gem_name} --no-test"
- end
-
- it_behaves_like "test framework is absent"
- end
-
context "--ci with no argument" do
it "does not generate any CI config" do
bundle "gem #{gem_name}"
@@ -994,17 +936,29 @@ RSpec.describe "bundle gem" do
end
end
- context "--ci set to github" do
+ context "--ci set to travis" do
it "generates a GitHub Actions config file" do
- bundle "gem #{gem_name} --ci=github"
+ bundle "gem #{gem_name} --ci=travis", :raise_on_error => false
+ expect(err).to include("Support for Travis CI was removed from gem skeleton generator.")
- expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
+ expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
end
+ end
- it "contained .gitlab-ci.yml into ignore list" do
+ context "--ci set to travis" do
+ it "generates a GitHub Actions config file" do
+ bundle "gem #{gem_name} --ci=travis", :raise_on_error => false
+ expect(err).to include("Support for Travis CI was removed from gem skeleton generator.")
+
+ expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
+ end
+ end
+
+ context "--ci set to github" do
+ it "generates a GitHub Actions config file" do
bundle "gem #{gem_name} --ci=github"
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(".git .github appveyor")
+ expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
end
end
@@ -1014,12 +968,6 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to exist
end
-
- it "contained .gitlab-ci.yml into ignore list" do
- bundle "gem #{gem_name} --ci=gitlab"
-
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(".git .gitlab-ci.yml appveyor")
- end
end
context "--ci set to circle" do
@@ -1028,23 +976,6 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/.circleci/config.yml")).to exist
end
-
- it "contained .circleci into ignore list" do
- bundle "gem #{gem_name} --ci=circle"
-
- expect(bundled_app("#{gem_name}/#{gem_name}.gemspec").read).to include(".git .circleci appveyor")
- end
- end
-
- context "--ci set to an invalid value" do
- before do
- bundle "gem #{gem_name} --ci=foo", raise_on_error: false
- end
-
- it "fails loudly" do
- expect(last_command).to be_failure
- expect(err).to match(/Expected '--ci' to be one of .*; got foo/)
- end
end
context "gem.ci setting set to none" do
@@ -1055,6 +986,18 @@ RSpec.describe "bundle gem" do
end
end
+ context "gem.ci setting set to travis" do
+ it "errors with friendly message" do
+ bundle "config set gem.ci travis"
+ bundle "gem #{gem_name}", :raise_on_error => false
+
+ expect(err).to include("Support for Travis CI was removed from gem skeleton generator,")
+ expect(err).to include("bundle config unset gem.ci")
+
+ expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
+ end
+ end
+
context "gem.ci setting set to github" do
it "generates a GitHub Actions config file" do
bundle "config set gem.ci github"
@@ -1082,7 +1025,7 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.ci set to github and --ci with no arguments" do
+ context "gem.ci set to github and --ci with no arguments", :hint_text do
before do
bundle "config set gem.ci github"
bundle "gem #{gem_name} --ci"
@@ -1097,12 +1040,10 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.ci setting set to false and --ci with no arguments", :readline do
+ context "gem.ci setting set to false and --ci with no arguments", :hint_text do
before do
bundle "config set gem.ci false"
- bundle "gem #{gem_name} --ci" do |input, _, _|
- input.puts "github"
- end
+ bundle "gem #{gem_name} --ci"
end
it "asks to setup CI" do
@@ -1114,12 +1055,9 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.ci setting not set and --ci with no arguments", :readline do
+ context "gem.ci setting not set and --ci with no arguments", :hint_text do
before do
- global_config "BUNDLE_GEM__CI" => nil
- bundle "gem #{gem_name} --ci" do |input, _, _|
- input.puts "github"
- end
+ bundle "gem #{gem_name} --ci"
end
it "asks to setup CI" do
@@ -1133,19 +1071,6 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.ci setting set to a CI service and --no-ci" do
- before do
- bundle "config set gem.ci github"
- bundle "gem #{gem_name} --no-ci"
- end
-
- it "does not generate any CI config" do
- expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to_not exist
- expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to_not exist
- expect(bundled_app("#{gem_name}/.circleci/config.yml")).to_not exist
- end
- end
-
context "--linter with no argument" do
it "does not generate any linter config" do
bundle "gem #{gem_name}"
@@ -1173,17 +1098,6 @@ RSpec.describe "bundle gem" do
end
end
- context "--linter set to an invalid value" do
- before do
- bundle "gem #{gem_name} --linter=foo", raise_on_error: false
- end
-
- it "fails loudly" do
- expect(last_command).to be_failure
- expect(err).to match(/Expected '--linter' to be one of .*; got foo/)
- end
- end
-
context "gem.linter setting set to none" do
it "doesn't generate any linter config" do
bundle "gem #{gem_name}"
@@ -1211,9 +1125,8 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.rubocop setting set to true", bundler: "< 3" do
+ context "gem.rubocop setting set to true", :bundler => "< 3" do
before do
- global_config "BUNDLE_GEM__LINTER" => nil
bundle "config set gem.rubocop true"
bundle "gem #{gem_name}"
end
@@ -1233,7 +1146,7 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.linter set to rubocop and --linter with no arguments" do
+ context "gem.linter set to rubocop and --linter with no arguments", :hint_text do
before do
bundle "config set gem.linter rubocop"
bundle "gem #{gem_name} --linter"
@@ -1248,12 +1161,10 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.linter setting set to false and --linter with no arguments", :readline do
+ context "gem.linter setting set to false and --linter with no arguments", :hint_text do
before do
bundle "config set gem.linter false"
- bundle "gem #{gem_name} --linter" do |input, _, _|
- input.puts "rubocop"
- end
+ bundle "gem #{gem_name} --linter"
end
it "asks to setup a linter" do
@@ -1265,12 +1176,9 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.linter setting not set and --linter with no arguments", :readline do
+ context "gem.linter setting not set and --linter with no arguments", :hint_text do
before do
- global_config "BUNDLE_GEM__LINTER" => nil
- bundle "gem #{gem_name} --linter" do |input, _, _|
- input.puts "rubocop"
- end
+ bundle "gem #{gem_name} --linter"
end
it "asks to setup a linter" do
@@ -1284,18 +1192,6 @@ RSpec.describe "bundle gem" do
end
end
- context "gem.linter setting set to a linter and --no-linter" do
- before do
- bundle "config set gem.linter rubocop"
- bundle "gem #{gem_name} --no-linter"
- end
-
- it "does not generate any linter config" do
- expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
- expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
- end
- end
-
context "--edit option" do
it "opens the generated gemspec in the user's text editor" do
output = bundle "gem #{gem_name} --edit=echo"
@@ -1305,7 +1201,7 @@ RSpec.describe "bundle gem" do
end
end
- context "testing --mit and --coc options against bundle config settings" do
+ context "testing --mit and --coc options against bundle config settings", :readline do
let(:gem_name) { "test-gem" }
let(:require_path) { "test/gem" }
@@ -1348,7 +1244,7 @@ RSpec.describe "bundle gem" do
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
+ it_behaves_like "--linter=none flag"
it_behaves_like "--rubocop flag"
it_behaves_like "--no-rubocop flag"
end
@@ -1359,7 +1255,7 @@ RSpec.describe "bundle gem" do
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
+ it_behaves_like "--linter=none flag"
it_behaves_like "--rubocop flag"
it_behaves_like "--no-rubocop flag"
end
@@ -1370,7 +1266,7 @@ RSpec.describe "bundle gem" do
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
+ it_behaves_like "--linter=none flag"
end
context "with linter option in bundle config settings set to standard" do
@@ -1379,7 +1275,7 @@ RSpec.describe "bundle gem" do
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
+ it_behaves_like "--linter=none flag"
end
context "with linter option in bundle config settings set to false" do
@@ -1388,7 +1284,7 @@ RSpec.describe "bundle gem" do
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
- it_behaves_like "--no-linter flag"
+ it_behaves_like "--linter=none flag"
end
context "with changelog option in bundle config settings set to true" do
@@ -1408,10 +1304,10 @@ RSpec.describe "bundle gem" do
end
end
- context "testing --github-username option against git and bundle config settings" do
+ context "testing --github-username option against git and bundle config settings", :readline do
context "without git config set" do
before do
- git("config --global --unset github.user")
+ sys_exec("git config --global --unset github.user")
end
context "with github-username option in bundle config settings set to some value" do
before do
@@ -1445,10 +1341,10 @@ RSpec.describe "bundle gem" do
end
end
- context "testing github_username bundle config against git config settings" do
+ context "testing github_username bundle config against git config settings", :readline do
context "without git config set" do
before do
- git("config --global --unset github.user")
+ sys_exec("git config --global --unset github.user")
end
it_behaves_like "github_username configuration"
@@ -1459,7 +1355,7 @@ RSpec.describe "bundle gem" do
end
end
- context "gem naming with underscore" do
+ context "gem naming with underscore", :readline do
let(:gem_name) { "test_gem" }
let(:require_path) { "test_gem" }
@@ -1481,7 +1377,7 @@ RSpec.describe "bundle gem" do
include_examples "generating a gem"
context "--ext parameter with no value" do
- context "is deprecated", bundler: "< 3" do
+ context "is deprecated", :bundler => "< 3" do
it "prints deprecation when used after gem name" do
bundle ["gem", "--ext", gem_name].compact.join(" ")
expect(err).to include "[DEPRECATED]"
@@ -1523,7 +1419,7 @@ RSpec.describe "bundle gem" do
end
it "depends on compile task for build" do
- rakefile = <<~RAKEFILE
+ rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
@@ -1531,9 +1427,7 @@ RSpec.describe "bundle gem" do
task build: :compile
- GEMSPEC = Gem::Specification.load("#{gem_name}.gemspec")
-
- Rake::ExtensionTask.new("#{gem_name}", GEMSPEC) do |ext|
+ Rake::ExtensionTask.new("#{gem_name}") do |ext|
ext.lib_dir = "lib/#{gem_name}"
end
@@ -1583,7 +1477,7 @@ RSpec.describe "bundle gem" do
end
it "depends on compile task for build" do
- rakefile = <<~RAKEFILE
+ rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
@@ -1591,9 +1485,7 @@ RSpec.describe "bundle gem" do
task build: :compile
- GEMSPEC = Gem::Specification.load("#{gem_name}.gemspec")
-
- RbSys::ExtensionTask.new("#{gem_name}", GEMSPEC) do |ext|
+ RbSys::ExtensionTask.new("#{gem_name}") do |ext|
ext.lib_dir = "lib/#{gem_name}"
end
@@ -1605,7 +1497,7 @@ RSpec.describe "bundle gem" do
end
end
- context "gem naming with dashed" do
+ context "gem naming with dashed", :readline do
let(:gem_name) { "test-gem" }
let(:require_path) { "test/gem" }
@@ -1626,29 +1518,29 @@ RSpec.describe "bundle gem" do
end
describe "uncommon gem names" do
- it "can deal with two dashes" do
+ it "can deal with two dashes", :readline do
bundle "gem a--a"
expect(bundled_app("a--a/a--a.gemspec")).to exist
end
it "fails gracefully with a ." do
- bundle "gem foo.gemspec", raise_on_error: false
+ bundle "gem foo.gemspec", :raise_on_error => false
expect(err).to end_with("Invalid gem name foo.gemspec -- `Foo.gemspec` is an invalid constant name")
end
it "fails gracefully with a ^" do
- bundle "gem ^", raise_on_error: false
+ bundle "gem ^", :raise_on_error => false
expect(err).to end_with("Invalid gem name ^ -- `^` is an invalid constant name")
end
it "fails gracefully with a space" do
- bundle "gem 'foo bar'", raise_on_error: false
+ bundle "gem 'foo bar'", :raise_on_error => false
expect(err).to end_with("Invalid gem name foo bar -- `Foo bar` is an invalid constant name")
end
it "fails gracefully when multiple names are passed" do
- bundle "gem foo bar baz", raise_on_error: false
+ bundle "gem foo bar baz", :raise_on_error => false
expect(err).to eq(<<-E.strip)
ERROR: "bundle gem" was called with arguments ["foo", "bar", "baz"]
Usage: "bundle gem NAME [OPTIONS]"
@@ -1656,9 +1548,9 @@ Usage: "bundle gem NAME [OPTIONS]"
end
end
- describe "#ensure_safe_gem_name" do
+ describe "#ensure_safe_gem_name", :readline do
before do
- bundle "gem #{subject}", raise_on_error: false
+ bundle "gem #{subject}", :raise_on_error => false
end
context "with an existing const name" do
@@ -1684,14 +1576,14 @@ Usage: "bundle gem NAME [OPTIONS]"
context "on first run", :readline do
it "asks about test framework" do
- global_config "BUNDLE_GEM__TEST" => nil
+ global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__COC" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "rspec"
end
expect(bundled_app("foobar/spec/spec_helper.rb")).to exist
- rakefile = <<~RAKEFILE
+ rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
@@ -1707,7 +1599,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about CI service" do
- global_config "BUNDLE_GEM__CI" => nil
+ global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "github"
@@ -1717,7 +1609,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about MIT license" do
- global_config "BUNDLE_GEM__MIT" => nil
+ global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false"
bundle "config list"
@@ -1729,7 +1621,7 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about CoC" do
- global_config "BUNDLE_GEM__COC" => nil
+ global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "yes"
@@ -1739,7 +1631,8 @@ Usage: "bundle gem NAME [OPTIONS]"
end
it "asks about CHANGELOG" do
- global_config "BUNDLE_GEM__CHANGELOG" => nil
+ global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false",
+ "BUNDLE_GEM__COC" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "yes"
@@ -1749,16 +1642,16 @@ Usage: "bundle gem NAME [OPTIONS]"
end
end
- context "on conflicts with a previously created file" do
+ context "on conflicts with a previously created file", :readline do
it "should fail gracefully" do
FileUtils.touch(bundled_app("conflict-foobar"))
- bundle "gem conflict-foobar", raise_on_error: false
+ bundle "gem conflict-foobar", :raise_on_error => false
expect(err).to eq("Couldn't create a new gem named `conflict-foobar` because there's an existing file named `conflict-foobar`.")
expect(exitstatus).to eql(32)
end
end
- context "on conflicts with a previously created directory" do
+ context "on conflicts with a previously created directory", :readline do
it "should succeed" do
FileUtils.mkdir_p(bundled_app("conflict-foobar/Gemfile"))
bundle "gem conflict-foobar"
diff --git a/spec/bundler/commands/open_spec.rb b/spec/bundler/commands/open_spec.rb
index e0c79aa407..e30ebfea5b 100644
--- a/spec/bundler/commands/open_spec.rb
+++ b/spec/bundler/commands/open_spec.rb
@@ -4,33 +4,33 @@ RSpec.describe "bundle open" do
context "when opening a regular gem" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
end
it "opens the gem with BUNDLER_EDITOR as highest priority" do
- bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
+ bundle "open rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
expect(out).to include("bundler_editor #{default_bundle_path("gems", "rails-2.3.2")}")
end
it "opens the gem with VISUAL as 2nd highest priority" do
- bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "" }
+ bundle "open rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "" }
expect(out).to include("visual #{default_bundle_path("gems", "rails-2.3.2")}")
end
it "opens the gem with EDITOR as 3rd highest priority" do
- bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("editor #{default_bundle_path("gems", "rails-2.3.2")}")
end
it "complains if no EDITOR is set" do
- bundle "open rails", env: { "EDITOR" => "", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open rails", :env => { "EDITOR" => "", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to eq("To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR")
end
it "complains if gem not in bundle" do
- bundle "open missing", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ bundle "open missing", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
expect(err).to match(/could not find gem 'missing'/i)
end
@@ -39,113 +39,113 @@ RSpec.describe "bundle open" do
ref = git.ref_for("main", 11)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{lib_path("foo-1.0")}"
G
- bundle "open foo", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
- expect(out).to include("editor #{default_bundle_path("bundler", "gems", "foo-1.0-#{ref}")}")
+ bundle "open foo", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ expect(out).to match("editor #{default_bundle_path.join("bundler/gems/foo-1.0-#{ref}")}")
end
it "suggests alternatives for similar-sounding gems" do
- bundle "open Rails", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ bundle "open Rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
expect(err).to match(/did you mean rails\?/i)
end
it "opens the gem with short words" do
- bundle "open rec", env: { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
+ bundle "open rec", :env => { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
expect(out).to include("bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2")}")
end
it "opens subpath of the gem" do
- bundle "open activerecord --path lib/activerecord", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open activerecord --path lib/activerecord", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/lib/activerecord")
end
it "opens subpath file of the gem" do
- bundle "open activerecord --path lib/version.rb", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open activerecord --path lib/version.rb", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/lib/version.rb")
end
it "opens deep subpath of the gem" do
- bundle "open activerecord --path lib/active_record", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open activerecord --path lib/active_record", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/lib/active_record")
end
it "requires value for --path arg" do
- bundle "open activerecord --path", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ bundle "open activerecord --path", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
expect(err).to eq "Cannot specify `--path` option without a value"
end
it "suggests alternatives for similar-sounding gems when using subpath" do
- bundle "open Rails --path README.md", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ bundle "open Rails --path README.md", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
expect(err).to match(/did you mean rails\?/i)
end
it "suggests alternatives for similar-sounding gems when using deep subpath" do
- bundle "open Rails --path some/path/here", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ bundle "open Rails --path some/path/here", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
expect(err).to match(/did you mean rails\?/i)
end
it "opens subpath of the short worded gem" do
- bundle "open rec --path CHANGELOG.md", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open rec --path CHANGELOG.md", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/CHANGELOG.md")
end
it "opens deep subpath of the short worded gem" do
- bundle "open rec --path lib/activerecord", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open rec --path lib/activerecord", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("editor #{default_bundle_path("gems", "activerecord-2.3.2")}/lib/activerecord")
end
it "opens subpath of the selected matching gem", :readline do
env = { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
- bundle "open active --path CHANGELOG.md", env: env do |input, _, _|
+ bundle "open active --path CHANGELOG.md", :env => env do |input, _, _|
input.puts "2"
end
- expect(out).to include("bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2").join("CHANGELOG.md")}")
+ expect(out).to match(%r{bundler_editor #{default_bundle_path('gems', 'activerecord-2.3.2')}/CHANGELOG\.md\z})
end
it "opens deep subpath of the selected matching gem", :readline do
env = { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
- bundle "open active --path lib/activerecord/version.rb", env: env do |input, _, _|
+ bundle "open active --path lib/activerecord/version.rb", :env => env do |input, _, _|
input.puts "2"
end
- expect(out).to include("bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2").join("lib", "activerecord", "version.rb")}")
+ expect(out).to match(%r{bundler_editor #{default_bundle_path('gems', 'activerecord-2.3.2')}/lib/activerecord/version\.rb\z})
end
it "select the gem from many match gems", :readline do
env = { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
- bundle "open active", env: env do |input, _, _|
+ bundle "open active", :env => env do |input, _, _|
input.puts "2"
end
- expect(out).to include("bundler_editor #{default_bundle_path("gems", "activerecord-2.3.2")}")
+ expect(out).to match(/bundler_editor #{default_bundle_path('gems', 'activerecord-2.3.2')}\z/)
end
it "allows selecting exit from many match gems", :readline do
env = { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
- bundle "open active", env: env do |input, _, _|
+ bundle "open active", :env => env do |input, _, _|
input.puts "0"
end
end
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
gem "foo"
G
bundle "config set auto_install 1"
- bundle "open rails", env: { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
+ bundle "open rails", :env => { "EDITOR" => "echo editor", "VISUAL" => "", "BUNDLER_EDITOR" => "" }
expect(out).to include("Installing foo 1.0")
end
it "opens the editor with a clean env" do
- bundle "open", env: { "EDITOR" => "sh -c 'env'", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, raise_on_error: false
+ bundle "open", :env => { "EDITOR" => "sh -c 'env'", "VISUAL" => "", "BUNDLER_EDITOR" => "" }, :raise_on_error => false
expect(out).not_to include("BUNDLE_GEMFILE=")
end
end
@@ -163,12 +163,13 @@ RSpec.describe "bundle open" do
skip "No default gems available on this test run" if default_gems.empty?
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "json"
G
end
it "throws proper error when trying to open default gem" do
- bundle "open json", env: { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
+ bundle "open json", :env => { "EDITOR" => "echo editor", "VISUAL" => "echo visual", "BUNDLER_EDITOR" => "echo bundler_editor" }
expect(out).to include("Unable to open json because it's a default gem, so the directory it would normally be installed to does not exist.")
end
end
diff --git a/spec/bundler/commands/outdated_spec.rb b/spec/bundler/commands/outdated_spec.rb
index 449fba5935..bbc3cb54ae 100644
--- a/spec/bundler/commands/outdated_spec.rb
+++ b/spec/bundler/commands/outdated_spec.rb
@@ -4,12 +4,12 @@ RSpec.describe "bundle outdated" do
describe "with no arguments" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -23,11 +23,11 @@ RSpec.describe "bundle outdated" do
update_repo2 do
build_gem "activesupport", "3.0"
build_gem "weakling", "0.2"
- update_git "foo", path: lib_path("foo")
- update_git "zebra", path: lib_path("zebra")
+ update_git "foo", :path => lib_path("foo")
+ update_git "zebra", :path => lib_path("zebra")
end
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
Gem Current Latest Requested Groups
@@ -46,11 +46,11 @@ RSpec.describe "bundle outdated" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "AAA", "1.0.0"
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE
Gem Current Latest Requested Groups
@@ -63,10 +63,10 @@ RSpec.describe "bundle outdated" do
it "returns non zero exit status if outdated gems present" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expect(exitstatus).to_not be_zero
end
@@ -77,7 +77,7 @@ RSpec.describe "bundle outdated" do
it "adds gem group to dependency output when repo is updated" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "terranova", '8'
@@ -89,7 +89,7 @@ RSpec.describe "bundle outdated" do
update_repo2 { build_gem "activesupport", "3.0" }
update_repo2 { build_gem "terranova", "9" }
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -104,12 +104,12 @@ RSpec.describe "bundle outdated" do
describe "with --verbose option" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -126,20 +126,20 @@ RSpec.describe "bundle outdated" do
update_repo2 { build_gem "terranova", "9" }
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "terranova", '9'
gem 'activesupport', '2.3.5'
G
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "terranova", '8'
gem 'activesupport', '2.3.5'
G
- bundle "outdated --verbose", raise_on_error: false
+ bundle "outdated --verbose", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups Path
@@ -151,7 +151,7 @@ RSpec.describe "bundle outdated" do
end
end
- describe "with multiple, duplicated sources, with lockfile in old format", bundler: "< 3" do
+ describe "with multiple, duplicated sources, with lockfile in old format", :bundler => "< 3" do
before do
build_repo2 do
build_gem "dotenv", "2.7.6"
@@ -162,7 +162,7 @@ RSpec.describe "bundle outdated" do
build_gem "vcr", "6.0.0"
end
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "pkg-gem-flowbyte-with-dep", "1.0.0" do |s|
s.add_dependency "oj"
end
@@ -205,8 +205,8 @@ RSpec.describe "bundle outdated" do
end
it "works" do
- bundle :install, artifice: "compact_index"
- bundle :outdated, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index"
+ bundle :outdated, :artifice => "compact_index", :raise_on_error => false
expected_output = <<~TABLE
Gem Current Latest Requested Groups
@@ -220,12 +220,12 @@ RSpec.describe "bundle outdated" do
describe "with --group option" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "weakling", "~> 0.0.1"
gem "terranova", '8'
@@ -243,7 +243,7 @@ RSpec.describe "bundle outdated" do
build_gem "duradura", "8.0"
end
- bundle "outdated --group #{group}", raise_on_error: false
+ bundle "outdated --group #{group}", :raise_on_error => false
end
it "works when the bundle is up to date" do
@@ -251,14 +251,6 @@ RSpec.describe "bundle outdated" do
expect(out).to end_with("Bundle up to date!")
end
- it "works when only out of date gems are not in given group" do
- update_repo2 do
- build_gem "terranova", "9"
- end
- bundle "outdated --group development"
- expect(out).to end_with("Bundle up to date!")
- end
-
it "returns a sorted list of outdated gems from one group => 'default'" do
test_group_option("default")
@@ -298,8 +290,8 @@ RSpec.describe "bundle outdated" do
describe "with --groups option and outdated transitive dependencies" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
build_gem "bar", %w[2.0.0]
@@ -309,7 +301,7 @@ RSpec.describe "bundle outdated" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "bar_dependant", '7.0'
G
@@ -320,7 +312,7 @@ RSpec.describe "bundle outdated" do
end
it "returns a sorted list of outdated gems" do
- bundle "outdated --groups", raise_on_error: false
+ bundle "outdated --groups", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -334,12 +326,12 @@ RSpec.describe "bundle outdated" do
describe "with --groups option" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "weakling", "~> 0.0.1"
gem "terranova", '8'
@@ -362,7 +354,7 @@ RSpec.describe "bundle outdated" do
build_gem "duradura", "8.0"
end
- bundle "outdated --groups", raise_on_error: false
+ bundle "outdated --groups", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -378,12 +370,12 @@ RSpec.describe "bundle outdated" do
describe "with --local option" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "weakling", "~> 0.0.1"
gem "terranova", '8'
@@ -402,11 +394,11 @@ RSpec.describe "bundle outdated" do
bundle "config set clean false"
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.4"
G
- bundle "outdated --local", raise_on_error: false
+ bundle "outdated --local", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -428,15 +420,15 @@ RSpec.describe "bundle outdated" do
context "and gems are outdated" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
build_gem "activesupport", "3.0"
build_gem "weakling", "0.2"
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -446,51 +438,30 @@ RSpec.describe "bundle outdated" do
G
end
- it "outputs a sorted list of outdated gems with a more minimal format to stdout" do
+ it "outputs a sorted list of outdated gems with a more minimal format" do
minimal_output = "activesupport (newest 3.0, installed 2.3.5, requested = 2.3.5)\n" \
"weakling (newest 0.2, installed 0.0.3, requested ~> 0.0.1)"
subject
expect(out).to eq(minimal_output)
end
-
- it "outputs progress to stderr" do
- subject
- expect(err).to include("Fetching gem metadata")
- end
end
context "and no gems are outdated" do
- before do
- build_repo2 do
- build_gem "activesupport", "3.0"
- end
-
- install_gemfile <<-G
- source "https://gem.repo2"
- gem "activesupport", "3.0"
- G
- end
-
- it "does not output to stdout" do
+ it "has empty output" do
subject
expect(out).to be_empty
end
-
- it "outputs progress to stderr" do
- subject
- expect(err).to include("Fetching gem metadata")
- end
end
end
describe "with --parseable option" do
- subject { bundle "outdated --parseable", raise_on_error: false }
+ subject { bundle "outdated --parseable", :raise_on_error => false }
it_behaves_like "a minimal output is desired"
end
describe "with aliased --porcelain option" do
- subject { bundle "outdated --porcelain", raise_on_error: false }
+ subject { bundle "outdated --porcelain", :raise_on_error => false }
it_behaves_like "a minimal output is desired"
end
@@ -498,12 +469,12 @@ RSpec.describe "bundle outdated" do
describe "with specified gems" do
it "returns list of outdated gems" do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -514,10 +485,10 @@ RSpec.describe "bundle outdated" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
- bundle "outdated foo", raise_on_error: false
+ bundle "outdated foo", :raise_on_error => false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
Gem Current Latest Requested Groups
@@ -531,12 +502,12 @@ RSpec.describe "bundle outdated" do
describe "pre-release gems" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -564,7 +535,7 @@ RSpec.describe "bundle outdated" do
build_gem "activesupport", "3.0.0.beta"
end
- bundle "outdated --pre", raise_on_error: false
+ bundle "outdated --pre", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -583,11 +554,11 @@ RSpec.describe "bundle outdated" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "3.0.0.beta.1"
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -602,12 +573,12 @@ RSpec.describe "bundle outdated" do
describe "with --filter-strict option" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -623,7 +594,7 @@ RSpec.describe "bundle outdated" do
build_gem "weakling", "0.0.5"
end
- bundle :outdated, "filter-strict": true, raise_on_error: false
+ bundle :outdated, :"filter-strict" => true, :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -639,7 +610,7 @@ RSpec.describe "bundle outdated" do
build_gem "weakling", "0.0.5"
end
- bundle :outdated, strict: true, raise_on_error: false
+ bundle :outdated, :strict => true, :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -651,22 +622,22 @@ RSpec.describe "bundle outdated" do
it "doesn't crash when some deps unused on the current platform" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", platforms: [:ruby_22]
G
- bundle :outdated, "filter-strict": true
+ bundle :outdated, :"filter-strict" => true
expect(out).to end_with("Bundle up to date!")
end
it "only reports gem dependencies when they can actually be updated" do
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack_middleware", "1.0"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack_middleware", "1.0"
G
- bundle :outdated, "filter-strict": true
+ bundle :outdated, :"filter-strict" => true
expect(out).to end_with("Bundle up to date!")
end
@@ -674,7 +645,7 @@ RSpec.describe "bundle outdated" do
describe "and filter options" do
it "only reports gems that match requirement and patch filter level" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "~> 2.3"
gem "weakling", ">= 0.0.1"
G
@@ -696,7 +667,7 @@ RSpec.describe "bundle outdated" do
it "only reports gems that match requirement and minor filter level" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "~> 2.3"
gem "weakling", ">= 0.0.1"
G
@@ -718,7 +689,7 @@ RSpec.describe "bundle outdated" do
it "only reports gems that match requirement and major filter level" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "~> 2.3"
gem "weakling", ">= 0.0.1"
G
@@ -743,12 +714,12 @@ RSpec.describe "bundle outdated" do
describe "with invalid gem name" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -759,46 +730,46 @@ RSpec.describe "bundle outdated" do
end
it "returns could not find gem name" do
- bundle "outdated invalid_gem_name", raise_on_error: false
+ bundle "outdated invalid_gem_name", :raise_on_error => false
expect(err).to include("Could not find gem 'invalid_gem_name'.")
end
it "returns non-zero exit code" do
- bundle "outdated invalid_gem_name", raise_on_error: false
+ bundle "outdated invalid_gem_name", :raise_on_error => false
expect(exitstatus).to_not be_zero
end
end
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
gem "foo"
G
bundle "config set auto_install 1"
- bundle :outdated, raise_on_error: false
+ bundle :outdated, :raise_on_error => false
expect(out).to include("Installing foo 1.0")
end
- context "after bundle install --deployment", bundler: "< 3" do
+ context "after bundle install --deployment", :bundler => "< 3" do
before do
build_repo2
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack"
+ gem "rack"
gem "foo"
G
bundle :lock
- bundle :install, deployment: true
+ bundle :install, :deployment => true
end
it "outputs a helpful message about being in deployment mode" do
update_repo2 { build_gem "activesupport", "3.0" }
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expect(last_command).to be_failure
expect(err).to include("You are trying to check outdated gems in deployment mode.")
expect(err).to include("Run `bundle outdated` elsewhere.")
@@ -810,14 +781,14 @@ RSpec.describe "bundle outdated" do
context "after bundle config set --local deployment true" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack"
+ gem "rack"
gem "foo"
G
bundle "config set --local deployment true"
@@ -826,7 +797,7 @@ RSpec.describe "bundle outdated" do
it "outputs a helpful message about being in deployment mode" do
update_repo2 { build_gem "activesupport", "3.0" }
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expect(last_command).to be_failure
expect(err).to include("You are trying to check outdated gems in deployment mode.")
expect(err).to include("Run `bundle outdated` elsewhere.")
@@ -840,7 +811,7 @@ RSpec.describe "bundle outdated" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "laduradura", '= 5.15.2'
G
end
@@ -858,7 +829,7 @@ RSpec.describe "bundle outdated" do
it "reports that updates are available if the Ruby platform is used" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "laduradura", '= 5.15.2', :platforms => [:ruby, :jruby]
G
@@ -868,11 +839,11 @@ RSpec.describe "bundle outdated" do
it "reports that updates are available if the JRuby platform is used", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "laduradura", '= 5.15.2', :platforms => [:ruby, :jruby]
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -896,12 +867,12 @@ RSpec.describe "bundle outdated" do
shared_examples_for "major version updates are detected" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -922,12 +893,12 @@ RSpec.describe "bundle outdated" do
context "when on a new machine" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -938,26 +909,26 @@ RSpec.describe "bundle outdated" do
simulate_new_machine
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
update_repo2 do
build_gem "activesupport", "3.3.5"
build_gem "weakling", "0.8.0"
end
end
- subject { bundle "outdated", raise_on_error: false }
+ subject { bundle "outdated", :raise_on_error => false }
it_behaves_like "version update is detected"
end
shared_examples_for "minor version updates are detected" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -978,12 +949,12 @@ RSpec.describe "bundle outdated" do
shared_examples_for "patch version updates are detected" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -1011,12 +982,12 @@ RSpec.describe "bundle outdated" do
shared_examples_for "major version is ignored" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -1037,12 +1008,12 @@ RSpec.describe "bundle outdated" do
shared_examples_for "minor version is ignored" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -1063,12 +1034,12 @@ RSpec.describe "bundle outdated" do
shared_examples_for "patch version is ignored" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
- build_git "zebra", path: lib_path("zebra")
+ build_git "foo", :path => lib_path("foo")
+ build_git "zebra", :path => lib_path("zebra")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "zebra", :git => "#{lib_path("zebra")}"
gem "foo", :git => "#{lib_path("foo")}"
gem "activesupport", "2.3.5"
@@ -1087,7 +1058,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-major option" do
- subject { bundle "outdated --filter-major", raise_on_error: false }
+ subject { bundle "outdated --filter-major", :raise_on_error => false }
it_behaves_like "major version updates are detected"
it_behaves_like "minor version is ignored"
@@ -1095,7 +1066,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-minor option" do
- subject { bundle "outdated --filter-minor", raise_on_error: false }
+ subject { bundle "outdated --filter-minor", :raise_on_error => false }
it_behaves_like "minor version updates are detected"
it_behaves_like "major version is ignored"
@@ -1103,7 +1074,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-patch option" do
- subject { bundle "outdated --filter-patch", raise_on_error: false }
+ subject { bundle "outdated --filter-patch", :raise_on_error => false }
it_behaves_like "patch version updates are detected"
it_behaves_like "major version is ignored"
@@ -1111,7 +1082,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-minor --filter-patch options" do
- subject { bundle "outdated --filter-minor --filter-patch", raise_on_error: false }
+ subject { bundle "outdated --filter-minor --filter-patch", :raise_on_error => false }
it_behaves_like "minor version updates are detected"
it_behaves_like "patch version updates are detected"
@@ -1119,7 +1090,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-major --filter-minor options" do
- subject { bundle "outdated --filter-major --filter-minor", raise_on_error: false }
+ subject { bundle "outdated --filter-major --filter-minor", :raise_on_error => false }
it_behaves_like "major version updates are detected"
it_behaves_like "minor version updates are detected"
@@ -1127,7 +1098,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-major --filter-patch options" do
- subject { bundle "outdated --filter-major --filter-patch", raise_on_error: false }
+ subject { bundle "outdated --filter-major --filter-patch", :raise_on_error => false }
it_behaves_like "major version updates are detected"
it_behaves_like "patch version updates are detected"
@@ -1135,7 +1106,7 @@ RSpec.describe "bundle outdated" do
end
describe "with --filter-major --filter-minor --filter-patch options" do
- subject { bundle "outdated --filter-major --filter-minor --filter-patch", raise_on_error: false }
+ subject { bundle "outdated --filter-major --filter-minor --filter-patch", :raise_on_error => false }
it_behaves_like "major version updates are detected"
it_behaves_like "minor version updates are detected"
@@ -1152,7 +1123,7 @@ RSpec.describe "bundle outdated" do
# establish a lockfile set to 1.0.0
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'patch', '1.0.0'
gem 'minor', '1.0.0'
gem 'major', '1.0.0'
@@ -1160,7 +1131,7 @@ RSpec.describe "bundle outdated" do
# remove all version requirements
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'patch'
gem 'minor'
gem 'major'
@@ -1174,7 +1145,7 @@ RSpec.describe "bundle outdated" do
end
it "shows all gems when patching and filtering to patch" do
- bundle "outdated --patch --filter-patch", raise_on_error: false
+ bundle "outdated --patch --filter-patch", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -1187,7 +1158,7 @@ RSpec.describe "bundle outdated" do
end
it "shows minor and major when updating to minor and filtering to patch and minor" do
- bundle "outdated --minor --filter-minor", raise_on_error: false
+ bundle "outdated --minor --filter-minor", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -1199,7 +1170,7 @@ RSpec.describe "bundle outdated" do
end
it "shows minor when updating to major and filtering to minor with parseable" do
- bundle "outdated --major --filter-minor --parseable", raise_on_error: false
+ bundle "outdated --major --filter-minor --parseable", :raise_on_error => false
expect(out).not_to include("patch (newest")
expect(out).to include("minor (newest")
@@ -1225,7 +1196,7 @@ RSpec.describe "bundle outdated" do
# establish a lockfile set to 1.4.3
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo', '1.4.3'
gem 'bar', '2.0.3'
gem 'qux', '1.0.0'
@@ -1234,14 +1205,14 @@ RSpec.describe "bundle outdated" do
# remove 1.4.3 requirement and bar altogether
# to setup update specs below
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo'
gem 'qux'
G
end
it "shows gems updating to patch and filtering to patch" do
- bundle "outdated --patch --filter-patch", raise_on_error: false, env: { "DEBUG_RESOLVER" => "1" }
+ bundle "outdated --patch --filter-patch", :raise_on_error => false, :env => { "DEBUG_RESOLVER" => "1" }
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -1253,7 +1224,7 @@ RSpec.describe "bundle outdated" do
end
it "shows gems updating to patch and filtering to patch, in debug mode" do
- bundle "outdated --patch --filter-patch", raise_on_error: false, env: { "DEBUG" => "1" }
+ bundle "outdated --patch --filter-patch", :raise_on_error => false, :env => { "DEBUG" => "1" }
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups Path
@@ -1275,17 +1246,17 @@ RSpec.describe "bundle outdated" do
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'weakling', '0.2'
gem 'bar', '2.1'
G
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'weakling'
G
- bundle "outdated --only-explicit", raise_on_error: false
+ bundle "outdated --only-explicit", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -1312,7 +1283,7 @@ RSpec.describe "bundle outdated" do
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.11.1)
nokogiri (1.11.1-#{Bundler.local_platform})
@@ -1329,13 +1300,13 @@ RSpec.describe "bundle outdated" do
L
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "nokogiri"
G
end
it "reports a single entry per gem" do
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
@@ -1359,14 +1330,14 @@ RSpec.describe "bundle outdated" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "mini_portile2"
G
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
mini_portile2 (2.5.2)
net-ftp (~> 0.1)
@@ -1384,7 +1355,7 @@ RSpec.describe "bundle outdated" do
end
it "works" do
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.strip
Gem Current Latest Requested Groups
diff --git a/spec/bundler/commands/platform_spec.rb b/spec/bundler/commands/platform_spec.rb
index 6e0a02bcf0..688bf7b6df 100644
--- a/spec/bundler/commands/platform_spec.rb
+++ b/spec/bundler/commands/platform_spec.rb
@@ -4,7 +4,7 @@ RSpec.describe "bundle platform" do
context "without flags" do
it "returns all the output" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
#{ruby_version_correct}
@@ -27,7 +27,7 @@ G
it "returns all the output including the patchlevel" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
#{ruby_version_correct_patchlevel}
@@ -50,7 +50,7 @@ G
it "doesn't print ruby version requirement if it isn't specified" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
@@ -68,7 +68,7 @@ G
it "doesn't match the ruby version requirement" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
#{ruby_version_incorrect}
@@ -93,7 +93,7 @@ G
context "--ruby" do
it "returns ruby version when explicit" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.9.3", :engine => 'ruby', :engine_version => '1.9.3'
gem "foo"
@@ -106,7 +106,7 @@ G
it "defaults to MRI" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.9.3"
gem "foo"
@@ -119,7 +119,7 @@ G
it "handles jruby" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.8.7", :engine => 'jruby', :engine_version => '1.6.5'
gem "foo"
@@ -132,7 +132,7 @@ G
it "handles rbx" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.8.7", :engine => 'rbx', :engine_version => '1.2.4'
gem "foo"
@@ -145,7 +145,7 @@ G
it "handles truffleruby" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "2.5.1", :engine => 'truffleruby', :engine_version => '1.0.0-rc6'
gem "foo"
@@ -158,46 +158,46 @@ G
it "raises an error if engine is used but engine version is not" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.8.7", :engine => 'rbx'
gem "foo"
G
- bundle "platform", raise_on_error: false
+ bundle "platform", :raise_on_error => false
expect(exitstatus).not_to eq(0)
end
it "raises an error if engine_version is used but engine is not" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.8.7", :engine_version => '1.2.4'
gem "foo"
G
- bundle "platform", raise_on_error: false
+ bundle "platform", :raise_on_error => false
expect(exitstatus).not_to eq(0)
end
it "raises an error if engine version doesn't match ruby version for MRI" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "1.8.7", :engine => 'ruby', :engine_version => '1.2.4'
gem "foo"
G
- bundle "platform", raise_on_error: false
+ bundle "platform", :raise_on_error => false
expect(exitstatus).not_to eq(0)
end
it "should print if no ruby version is specified" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
@@ -209,13 +209,13 @@ G
it "handles when there is a locked requirement" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "< 1.8.7"
G
lockfile <<-L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -236,12 +236,12 @@ G
it "handles when there is a lockfile with no requirement" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
lockfile <<-L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -259,7 +259,7 @@ G
it "handles when there is a requirement in the gemfile" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= 1.8.7"
G
@@ -269,7 +269,7 @@ G
it "handles when there are multiple requirements in the gemfile" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= 1.8.7", "< 2.0.0"
G
@@ -315,8 +315,8 @@ G
context "bundle install" do
it "installs fine when the ruby version matches" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_correct}
G
@@ -326,8 +326,8 @@ G
it "installs fine with any engine", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_correct_engineless}
G
@@ -337,8 +337,8 @@ G
it "installs fine when the patchlevel matches" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_correct_patchlevel}
G
@@ -347,9 +347,9 @@ G
end
it "doesn't install when the ruby version doesn't match" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_incorrect}
G
@@ -359,9 +359,9 @@ G
end
it "doesn't install when engine doesn't match" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{engine_incorrect}
G
@@ -371,9 +371,9 @@ G
end
it "doesn't install when engine version doesn't match", :jruby_only do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{engine_version_incorrect}
G
@@ -383,9 +383,9 @@ G
end
it "doesn't install when patchlevel doesn't match" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
@@ -398,13 +398,13 @@ G
context "bundle check" do
it "checks fine when the ruby version matches" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_correct}
G
@@ -415,13 +415,13 @@ G
it "checks fine with any engine", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_correct_engineless}
G
@@ -432,69 +432,69 @@ G
it "fails when ruby version doesn't match" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{ruby_version_incorrect}
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails when engine doesn't match" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{engine_incorrect}
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
should_be_engine_incorrect
end
it "fails when engine version doesn't match", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{engine_version_incorrect}
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
should_be_engine_version_incorrect
end
it "fails when patchlevel doesn't match" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
- bundle :check, raise_on_error: false
+ bundle :check, :raise_on_error => false
should_be_patchlevel_incorrect
end
end
@@ -504,57 +504,57 @@ G
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
G
end
it "updates successfully when the ruby version matches" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
#{ruby_version_correct}
G
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
end
- bundle "update", all: true
- expect(the_bundle).to include_gems "myrack 1.2", "myrack-obama 1.0", "activesupport 3.0"
+ bundle "update", :all => true
+ expect(the_bundle).to include_gems "rack 1.2", "rack-obama 1.0", "activesupport 3.0"
end
it "updates fine with any engine", :jruby_only do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
#{ruby_version_correct_engineless}
G
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
end
- bundle "update", all: true
- expect(the_bundle).to include_gems "myrack 1.2", "myrack-obama 1.0", "activesupport 3.0"
+ bundle "update", :all => true
+ expect(the_bundle).to include_gems "rack 1.2", "rack-obama 1.0", "activesupport 3.0"
end
it "fails when ruby version doesn't match" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
#{ruby_version_incorrect}
G
@@ -562,15 +562,15 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, all: true, raise_on_error: false
+ bundle :update, :all => true, :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails when ruby engine doesn't match", :jruby_only do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
#{engine_incorrect}
G
@@ -578,15 +578,15 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, all: true, raise_on_error: false
+ bundle :update, :all => true, :raise_on_error => false
should_be_engine_incorrect
end
it "fails when ruby engine version doesn't match", :jruby_only do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
#{engine_version_incorrect}
G
@@ -594,14 +594,14 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, all: true, raise_on_error: false
+ bundle :update, :all => true, :raise_on_error => false
should_be_engine_version_incorrect
end
it "fails when patchlevel doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
@@ -609,7 +609,7 @@ G
build_gem "activesupport", "3.0"
end
- bundle :update, all: true, raise_on_error: false
+ bundle :update, :all => true, :raise_on_error => false
should_be_patchlevel_incorrect
end
end
@@ -617,14 +617,14 @@ G
context "bundle info" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
end
it "prints path if ruby version is correct" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
#{ruby_version_correct}
@@ -636,7 +636,7 @@ G
it "prints path if ruby version is correct for any engine", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
#{ruby_version_correct_engineless}
@@ -646,46 +646,46 @@ G
expect(out).to eq(default_bundle_path("gems", "rails-2.3.2").to_s)
end
- it "fails if ruby version doesn't match", bundler: "< 3" do
+ it "fails if ruby version doesn't match", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
#{ruby_version_incorrect}
G
- bundle "show rails", raise_on_error: false
+ bundle "show rails", :raise_on_error => false
should_be_ruby_version_incorrect
end
- it "fails if engine doesn't match", bundler: "< 3" do
+ it "fails if engine doesn't match", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
#{engine_incorrect}
G
- bundle "show rails", raise_on_error: false
+ bundle "show rails", :raise_on_error => false
should_be_engine_incorrect
end
- it "fails if engine version doesn't match", bundler: "< 3", jruby_only: true do
+ it "fails if engine version doesn't match", :bundler => "< 3", :jruby_only => true do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
#{engine_version_incorrect}
G
- bundle "show rails", raise_on_error: false
+ bundle "show rails", :raise_on_error => false
should_be_engine_version_incorrect
end
- it "fails when patchlevel doesn't match", bundler: "< 3" do
+ it "fails when patchlevel doesn't match", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
@@ -693,7 +693,7 @@ G
build_gem "activesupport", "3.0"
end
- bundle "show rails", raise_on_error: false
+ bundle "show rails", :raise_on_error => false
should_be_patchlevel_incorrect
end
end
@@ -701,80 +701,80 @@ G
context "bundle cache" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
end
it "copies the .gem file to vendor/cache when ruby version matches" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{ruby_version_correct}
G
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "copies the .gem file to vendor/cache when ruby version matches for any engine", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{ruby_version_correct_engineless}
G
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "fails if the ruby version doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{ruby_version_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails if the engine doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{engine_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_engine_incorrect
end
it "fails if the engine version doesn't match", :jruby_only do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{engine_version_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_engine_version_incorrect
end
it "fails when patchlevel doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_patchlevel_incorrect
end
end
@@ -782,80 +782,80 @@ G
context "bundle pack" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
end
it "copies the .gem file to vendor/cache when ruby version matches" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{ruby_version_correct}
G
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "copies the .gem file to vendor/cache when ruby version matches any engine", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{ruby_version_correct_engineless}
G
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
end
it "fails if the ruby version doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{ruby_version_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails if the engine doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{engine_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_engine_incorrect
end
it "fails if the engine version doesn't match", :jruby_only do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
#{engine_version_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_engine_version_incorrect
end
it "fails when patchlevel doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
- bundle :cache, raise_on_error: false
+ bundle :cache, :raise_on_error => false
should_be_patchlevel_incorrect
end
end
@@ -863,104 +863,104 @@ G
context "bundle exec" do
before do
ENV["BUNDLER_FORCE_TTY"] = "true"
- system_gems "myrack-1.0.0", "myrack-0.9.1", path: default_bundle_path
+ system_gems "rack-1.0.0", "rack-0.9.1", :path => default_bundle_path
end
it "activates the correct gem when ruby version matches" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
#{ruby_version_correct}
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to include("0.9.1")
end
it "activates the correct gem when ruby version matches any engine", :jruby_only do
- system_gems "myrack-1.0.0", "myrack-0.9.1", path: default_bundle_path
+ system_gems "rack-1.0.0", "rack-0.9.1", :path => default_bundle_path
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
#{ruby_version_correct_engineless}
G
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(out).to include("0.9.1")
end
it "fails when the ruby version doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
#{ruby_version_incorrect}
G
- bundle "exec myrackup", raise_on_error: false
+ bundle "exec rackup", :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails when the engine doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
#{engine_incorrect}
G
- bundle "exec myrackup", raise_on_error: false
+ bundle "exec rackup", :raise_on_error => false
should_be_engine_incorrect
end
- it "fails when the engine version doesn't match", :jruby_only do
- gemfile <<-G
- gem "myrack", "0.9.1"
-
- #{engine_version_incorrect}
- G
-
- bundle "exec myrackup", raise_on_error: false
- should_be_engine_version_incorrect
- end
+ # it "fails when the engine version doesn't match", :jruby_only do
+ # gemfile <<-G
+ # gem "rack", "0.9.1"
+ #
+ # #{engine_version_incorrect}
+ # G
+ #
+ # bundle "exec rackup"
+ # should_be_engine_version_incorrect
+ # end
it "fails when patchlevel doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
#{patchlevel_incorrect}
G
- bundle "exec myrackup", raise_on_error: false
+ bundle "exec rackup", :raise_on_error => false
should_be_patchlevel_incorrect
end
end
- context "bundle console", bundler: "< 3" do
+ context "bundle console", :bundler => "< 3" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
G
end
it "starts IRB with the default group loaded when ruby version matches", :readline do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
#{ruby_version_correct}
G
bundle "console" do |input, _, _|
- input.puts("puts MYRACK")
+ input.puts("puts RACK")
input.puts("exit")
end
expect(out).to include("0.9.1")
@@ -968,16 +968,16 @@ G
it "starts IRB with the default group loaded when ruby version matches", :readline, :jruby_only do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
#{ruby_version_correct_engineless}
G
bundle "console" do |input, _, _|
- input.puts("puts MYRACK")
+ input.puts("puts RACK")
input.puts("exit")
end
expect(out).to include("0.9.1")
@@ -985,57 +985,57 @@ G
it "fails when ruby version doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
#{ruby_version_incorrect}
G
- bundle "console", raise_on_error: false
+ bundle "console", :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails when engine doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
#{engine_incorrect}
G
- bundle "console", raise_on_error: false
+ bundle "console", :raise_on_error => false
should_be_engine_incorrect
end
it "fails when engine version doesn't match", :jruby_only do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
#{engine_version_incorrect}
G
- bundle "console", raise_on_error: false
+ bundle "console", :raise_on_error => false
should_be_engine_version_incorrect
end
it "fails when patchlevel doesn't match" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
- gem "myrack_middleware", :group => :development
+ gem "rack_middleware", :group => :development
#{patchlevel_incorrect}
G
- bundle "console", raise_on_error: false
+ bundle "console", :raise_on_error => false
should_be_patchlevel_incorrect
end
end
@@ -1043,9 +1043,9 @@ G
context "Bundler.setup" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack", :group => :test
+ gem "rack", :group => :test
G
ENV["BUNDLER_FORCE_TTY"] = "true"
@@ -1053,9 +1053,9 @@ G
it "makes a Gemfile.lock if setup succeeds" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack"
+ gem "rack"
#{ruby_version_correct}
G
@@ -1068,9 +1068,9 @@ G
it "makes a Gemfile.lock if setup succeeds for any engine", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack"
+ gem "rack"
#{ruby_version_correct_engineless}
G
@@ -1082,68 +1082,68 @@ G
end
it "fails when ruby version doesn't match" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack"
+ gem "rack"
#{ruby_version_incorrect}
G
FileUtils.rm(bundled_app_lock)
- ruby "require 'bundler/setup'", env: { "BUNDLER_VERSION" => Bundler::VERSION }, raise_on_error: false
+ ruby "require 'bundler/setup'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }, :raise_on_error => false
expect(bundled_app_lock).not_to exist
should_be_ruby_version_incorrect
end
it "fails when engine doesn't match" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack"
+ gem "rack"
#{engine_incorrect}
G
FileUtils.rm(bundled_app_lock)
- ruby "require 'bundler/setup'", env: { "BUNDLER_VERSION" => Bundler::VERSION }, raise_on_error: false
+ ruby "require 'bundler/setup'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }, :raise_on_error => false
expect(bundled_app_lock).not_to exist
should_be_engine_incorrect
end
it "fails when engine version doesn't match", :jruby_only do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack"
+ gem "rack"
#{engine_version_incorrect}
G
FileUtils.rm(bundled_app_lock)
- ruby "require 'bundler/setup'", env: { "BUNDLER_VERSION" => Bundler::VERSION }, raise_on_error: false
+ ruby "require 'bundler/setup'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }, :raise_on_error => false
expect(bundled_app_lock).not_to exist
should_be_engine_version_incorrect
end
it "fails when patchlevel doesn't match" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack"
+ gem "rack"
#{patchlevel_incorrect}
G
FileUtils.rm(bundled_app_lock)
- ruby "require 'bundler/setup'", env: { "BUNDLER_VERSION" => Bundler::VERSION }, raise_on_error: false
+ ruby "require 'bundler/setup'", :env => { "BUNDLER_VERSION" => Bundler::VERSION }, :raise_on_error => false
expect(bundled_app_lock).not_to exist
should_be_patchlevel_incorrect
@@ -1153,11 +1153,11 @@ G
context "bundle outdated" do
before do
build_repo2 do
- build_git "foo", path: lib_path("foo")
+ build_git "foo", :path => lib_path("foo")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
G
@@ -1166,18 +1166,18 @@ G
it "returns list of outdated gems when the ruby version matches" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{ruby_version_correct}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
Gem Current Latest Requested Groups
@@ -1192,18 +1192,18 @@ G
bundle :install
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{ruby_version_correct_engineless}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
expected_output = <<~TABLE.gsub("x", "\\\h").tr(".", "\.").strip
Gem Current Latest Requested Groups
@@ -1217,90 +1217,90 @@ G
it "fails when the ruby version doesn't match" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{ruby_version_incorrect}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
should_be_ruby_version_incorrect
end
it "fails when the engine doesn't match" do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{engine_incorrect}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
should_be_engine_incorrect
end
it "fails when the engine version doesn't match", :jruby_only do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{engine_version_incorrect}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
should_be_engine_version_incorrect
end
it "fails when the patchlevel doesn't match", :jruby_only do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{patchlevel_incorrect}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
should_be_patchlevel_incorrect
end
it "fails when the patchlevel is a fixnum", :jruby_only do
update_repo2 do
build_gem "activesupport", "3.0"
- update_git "foo", path: lib_path("foo")
+ update_git "foo", :path => lib_path("foo")
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", "2.3.5"
gem "foo", :git => "#{lib_path("foo")}"
#{patchlevel_fixnum}
G
- bundle "outdated", raise_on_error: false
+ bundle "outdated", :raise_on_error => false
should_be_patchlevel_fixnum
end
end
diff --git a/spec/bundler/commands/post_bundle_message_spec.rb b/spec/bundler/commands/post_bundle_message_spec.rb
index 8671504b25..3050b87754 100644
--- a/spec/bundler/commands/post_bundle_message_spec.rb
+++ b/spec/bundler/commands/post_bundle_message_spec.rb
@@ -3,13 +3,13 @@
RSpec.describe "post bundle message" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", "2.3.5", :group => [:emo, :test]
group :test do
gem "rspec"
end
- gem "myrack-obama", :group => :obama
+ gem "rack-obama", :group => :obama
G
end
@@ -114,26 +114,26 @@ RSpec.describe "post bundle message" do
end
it "should report a helpful error message" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "not-a-gem", :group => :development
G
expect(err).to include <<-EOS.strip
-Could not find gem 'not-a-gem' in rubygems repository https://gem.repo1/ or installed locally.
+Could not find gem 'not-a-gem' in rubygems repository #{file_uri_for(gem_repo1)}/ or installed locally.
EOS
end
it "should report a helpful error message with reference to cache if available" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle :cache
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "myrack"
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "not-a-gem", :group => :development
G
expect(err).to include("Could not find gem 'not-a-gem' in").
@@ -142,7 +142,7 @@ Could not find gem 'not-a-gem' in rubygems repository https://gem.repo1/ or inst
end
end
- describe "for second bundle install run", bundler: "< 3" do
+ describe "for second bundle install run", :bundler => "< 3" do
it "without any options" do
2.times { bundle :install }
expect(out).to include(bundle_show_message)
@@ -179,25 +179,25 @@ Could not find gem 'not-a-gem' in rubygems repository https://gem.repo1/ or inst
describe "for bundle update" do
it "shows proper messages according to the configured groups" do
- bundle :update, all: true
+ bundle :update, :all => true
expect(out).not_to include("Gems in the groups")
expect(out).to include(bundle_updated_message)
bundle "config set --local without emo"
bundle :install
- bundle :update, all: true
+ bundle :update, :all => true
expect(out).to include("Gems in the group 'emo' were not updated")
expect(out).to include(bundle_updated_message)
bundle "config set --local without emo test"
bundle :install
- bundle :update, all: true
+ bundle :update, :all => true
expect(out).to include("Gems in the groups 'emo' and 'test' were not updated")
expect(out).to include(bundle_updated_message)
bundle "config set --local without emo obama test"
bundle :install
- bundle :update, all: true
+ bundle :update, :all => true
expect(out).to include("Gems in the groups 'emo', 'obama' and 'test' were not updated")
expect(out).to include(bundle_updated_message)
end
diff --git a/spec/bundler/commands/pristine_spec.rb b/spec/bundler/commands/pristine_spec.rb
index 547aa12b6c..9e496dc91a 100644
--- a/spec/bundler/commands/pristine_spec.rb
+++ b/spec/bundler/commands/pristine_spec.rb
@@ -4,7 +4,7 @@ require "bundler/vendored_fileutils"
RSpec.describe "bundle pristine" do
before :each do
- build_lib "baz", path: bundled_app do |s|
+ build_lib "baz", :path => bundled_app do |s|
s.version = "1.0.0"
s.add_development_dependency "baz-dev", "=1.0.0"
end
@@ -13,13 +13,13 @@ RSpec.describe "bundle pristine" do
build_gem "weakling"
build_gem "baz-dev", "1.0.0"
build_gem "very_simple_binary", &:add_c_extension
- build_git "foo", path: lib_path("foo")
- build_git "git_with_ext", path: lib_path("git_with_ext"), &:add_c_extension
- build_lib "bar", path: lib_path("bar")
+ build_git "foo", :path => lib_path("foo")
+ build_git "git_with_ext", :path => lib_path("git_with_ext"), &:add_c_extension
+ build_lib "bar", :path => lib_path("bar")
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "weakling"
gem "very_simple_binary"
gem "foo", :git => "#{lib_path("foo")}", :branch => "main"
@@ -164,7 +164,7 @@ RSpec.describe "bundle pristine" do
end
it "raises when one of them is not in the lockfile" do
- bundle "pristine abcabcabc", raise_on_error: false
+ bundle "pristine abcabcabc", :raise_on_error => false
expect(err).to include("Could not find gem 'abcabcabc'.")
end
end
@@ -181,8 +181,8 @@ RSpec.describe "bundle pristine" do
bundle "pristine"
makefile_contents = File.read(c_ext_dir.join("Makefile").to_s)
- expect(makefile_contents).to match(/libpath =.*#{Regexp.escape(c_ext_dir.to_s)}/)
- expect(makefile_contents).to match(/LIBPATH =.*-L#{Regexp.escape(c_ext_dir.to_s)}/)
+ expect(makefile_contents).to match(/libpath =.*#{c_ext_dir}/)
+ expect(makefile_contents).to match(/LIBPATH =.*-L#{c_ext_dir}/)
end
end
@@ -198,14 +198,14 @@ RSpec.describe "bundle pristine" do
bundle "pristine"
makefile_contents = File.read(c_ext_dir.join("Makefile").to_s)
- expect(makefile_contents).to match(/libpath =.*#{Regexp.escape(c_ext_dir.to_s)}/)
- expect(makefile_contents).to match(/LIBPATH =.*-L#{Regexp.escape(c_ext_dir.to_s)}/)
+ expect(makefile_contents).to match(/libpath =.*#{c_ext_dir}/)
+ expect(makefile_contents).to match(/LIBPATH =.*-L#{c_ext_dir}/)
end
end
context "when BUNDLE_GEMFILE doesn't exist" do
before do
- bundle "pristine", env: { "BUNDLE_GEMFILE" => "does/not/exist" }, raise_on_error: false
+ bundle "pristine", :env => { "BUNDLE_GEMFILE" => "does/not/exist" }, :raise_on_error => false
end
it "shows a meaningful error" do
diff --git a/spec/bundler/commands/remove_spec.rb b/spec/bundler/commands/remove_spec.rb
index 7ac2ea9b26..d757e0be4b 100644
--- a/spec/bundler/commands/remove_spec.rb
+++ b/spec/bundler/commands/remove_spec.rb
@@ -4,10 +4,10 @@ RSpec.describe "bundle remove" do
context "when no gems are specified" do
it "throws error" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
- bundle "remove", raise_on_error: false
+ bundle "remove", :raise_on_error => false
expect(err).to include("Please specify gems to remove.")
end
@@ -16,45 +16,45 @@ RSpec.describe "bundle remove" do
context "after 'bundle install' is run" do
describe "running 'bundle remove GEM_NAME'" do
it "removes it from the lockfile" do
- myrack_dep = <<~L
+ rack_dep = <<~L
DEPENDENCIES
- myrack
+ rack
L
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
bundle "install"
- expect(lockfile).to include(myrack_dep)
+ expect(lockfile).to include(rack_dep)
- bundle "remove myrack"
+ bundle "remove rack"
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
- expect(lockfile).to_not include(myrack_dep)
+ expect(lockfile).to_not include(rack_dep)
end
end
end
- context "when --install flag is specified", bundler: "< 3" do
+ context "when --install flag is specified", :bundler => "< 3" do
it "removes gems from .bundle" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
- bundle "remove myrack --install"
+ bundle "remove rack --install"
- expect(out).to include("myrack was removed.")
- expect(the_bundle).to_not include_gems "myrack"
+ expect(out).to include("rack was removed.")
+ expect(the_bundle).to_not include_gems "rack"
end
end
@@ -62,39 +62,39 @@ RSpec.describe "bundle remove" do
context "when gem is present in gemfile" do
it "shows success for removed gem" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
- expect(the_bundle).to_not include_gems "myrack"
+ expect(out).to include("rack was removed.")
+ expect(the_bundle).to_not include_gems "rack"
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
context "when gem is specified in multiple lines" do
it "shows success for removed gem" do
- build_git "myrack"
+ build_git "rack"
gemfile <<-G
- source 'https://gem.repo1'
+ source '#{file_uri_for(gem_repo1)}'
gem 'git'
- gem 'myrack',
- git: "#{lib_path("myrack-1.0")}",
+ gem 'rack',
+ git: "#{lib_path("rack-1.0")}",
branch: 'main'
gem 'nokogiri'
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source 'https://gem.repo1'
+ source '#{file_uri_for(gem_repo1)}'
gem 'git'
gem 'nokogiri'
@@ -106,12 +106,12 @@ RSpec.describe "bundle remove" do
context "when gem is not present in gemfile" do
it "shows warning for gem that could not be removed" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
- bundle "remove myrack", raise_on_error: false
+ bundle "remove rack", :raise_on_error => false
- expect(err).to include("`myrack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
+ expect(err).to include("`rack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
end
end
end
@@ -120,18 +120,18 @@ RSpec.describe "bundle remove" do
context "when all gems are present in gemfile" do
it "shows success fir all removed gems" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
gem "rails"
G
- bundle "remove myrack rails"
+ bundle "remove rack rails"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(out).to include("rails was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -139,18 +139,18 @@ RSpec.describe "bundle remove" do
context "when some gems are not present in the gemfile" do
it "shows warning for those not present and success for those that can be removed" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
gem "minitest"
gem "rspec"
G
- bundle "remove rails myrack minitest", raise_on_error: false
+ bundle "remove rails rack minitest", :raise_on_error => false
- expect(err).to include("`myrack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
+ expect(err).to include("`rack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
gem "minitest"
@@ -163,16 +163,16 @@ RSpec.describe "bundle remove" do
context "with inline groups" do
it "removes the specified gem" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", :group => [:dev]
+ gem "rack", :group => [:dev]
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -181,7 +181,7 @@ RSpec.describe "bundle remove" do
context "when single group block with gem to be removed is present" do
it "removes the group block" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
gem "rspec"
@@ -192,7 +192,7 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -200,19 +200,19 @@ RSpec.describe "bundle remove" do
context "when gem to be removed is outside block" do
it "does not modify group" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
group :test do
gem "coffee-script-source"
end
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
gem "coffee-script-source"
@@ -224,7 +224,7 @@ RSpec.describe "bundle remove" do
context "when an empty block is also present" do
it "removes all empty blocks" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
gem "rspec"
@@ -238,7 +238,7 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -246,7 +246,7 @@ RSpec.describe "bundle remove" do
context "when the gem belongs to multiple groups" do
it "removes the groups" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test, :serioustest do
gem "rspec"
@@ -257,7 +257,7 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -265,7 +265,7 @@ RSpec.describe "bundle remove" do
context "when the gem is present in multiple groups" do
it "removes all empty blocks" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :one do
gem "rspec"
@@ -280,7 +280,7 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -290,7 +290,7 @@ RSpec.describe "bundle remove" do
context "when all the groups will be empty after removal" do
it "removes the empty nested blocks" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
group :serioustest do
@@ -303,7 +303,7 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -311,10 +311,10 @@ RSpec.describe "bundle remove" do
context "when outer group will not be empty after removal" do
it "removes only empty blocks" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
- gem "myrack-test"
+ gem "rack-test"
group :serioustest do
gem "rspec"
@@ -326,10 +326,10 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
- gem "myrack-test"
+ gem "rack-test"
end
G
@@ -339,12 +339,12 @@ RSpec.describe "bundle remove" do
context "when inner group will not be empty after removal" do
it "removes only empty blocks" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
group :serioustest do
gem "rspec"
- gem "myrack-test"
+ gem "rack-test"
end
end
G
@@ -353,11 +353,11 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
group :serioustest do
- gem "myrack-test"
+ gem "rack-test"
end
end
G
@@ -369,38 +369,38 @@ RSpec.describe "bundle remove" do
context "when multiple gems are present in same line" do
it "shows warning for gems not removed" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"; gem "rails"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"; gem "rails"
G
- bundle "remove rails", raise_on_error: false
+ bundle "remove rails", :raise_on_error => false
- expect(err).to include("Gems could not be removed. myrack (>= 0) would also have been removed.")
+ expect(err).to include("Gems could not be removed. rack (>= 0) would also have been removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
- gem "myrack"; gem "rails"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"; gem "rails"
G
end
end
context "when some gems could not be removed" do
it "shows warning for gems not removed and success for those removed" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem"myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem"rack"
gem"rspec"
gem "rails"
gem "minitest"
G
- bundle "remove rails myrack rspec minitest"
+ bundle "remove rails rack rspec minitest"
expect(out).to include("rails was removed.")
expect(out).to include("minitest was removed.")
- expect(out).to include("myrack, rspec could not be removed.")
+ expect(out).to include("rack, rspec could not be removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
- gem"myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem"rack"
gem"rspec"
G
end
@@ -409,18 +409,18 @@ RSpec.describe "bundle remove" do
context "with sources" do
before do
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "rspec"
end
end
it "removes gems and empty source blocks" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
- source "https://gem.repo3" do
+ source "#{file_uri_for(gem_repo3)}" do
gem "rspec"
end
G
@@ -431,9 +431,9 @@ RSpec.describe "bundle remove" do
expect(out).to include("rspec was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
end
end
@@ -441,40 +441,40 @@ RSpec.describe "bundle remove" do
describe "with eval_gemfile" do
context "when gems are present in both gemfiles" do
it "removes the gems" do
- gemfile "Gemfile-other", <<-G
- gem "myrack"
+ create_file "Gemfile-other", <<-G
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
- gem "myrack"
+ gem "rack"
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
end
end
context "when gems are present in other gemfile" do
it "removes the gems" do
- gemfile "Gemfile-other", <<-G
- gem "myrack"
+ create_file "Gemfile-other", <<-G
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(bundled_app("Gemfile-other").read).to_not include("gem \"myrack\"")
- expect(out).to include("myrack was removed.")
+ expect(bundled_app("Gemfile-other").read).to_not include("gem \"rack\"")
+ expect(out).to include("rack was removed.")
end
end
@@ -486,36 +486,36 @@ RSpec.describe "bundle remove" do
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
G
- bundle "remove myrack", raise_on_error: false
+ bundle "remove rack", :raise_on_error => false
- expect(err).to include("`myrack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
+ expect(err).to include("`rack` is not specified in #{bundled_app_gemfile} so it could not be removed.")
end
end
context "when the gem is present in parent file but not in gemfile specified by eval_gemfile" do
it "removes the gem" do
- gemfile "Gemfile-other", <<-G
+ create_file "Gemfile-other", <<-G
gem "rails"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
- gem "myrack"
+ gem "rack"
G
- bundle "remove myrack", raise_on_error: false
+ bundle "remove rack", :raise_on_error => false
- expect(out).to include("myrack was removed.")
- expect(err).to include("`myrack` is not specified in #{bundled_app("Gemfile-other")} so it could not be removed.")
+ expect(out).to include("rack was removed.")
+ expect(err).to include("`rack` is not specified in #{bundled_app("Gemfile-other")} so it could not be removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
G
@@ -524,23 +524,23 @@ RSpec.describe "bundle remove" do
context "when gems cannot be removed from other gemfile" do
it "shows error" do
- gemfile "Gemfile-other", <<-G
- gem "rails"; gem "myrack"
+ create_file "Gemfile-other", <<-G
+ gem "rails"; gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
- gem "myrack"
+ gem "rack"
G
- bundle "remove myrack", raise_on_error: false
+ bundle "remove rack", :raise_on_error => false
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(err).to include("Gems could not be removed. rails (>= 0) would also have been removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
G
@@ -549,47 +549,47 @@ RSpec.describe "bundle remove" do
context "when gems could not be removed from parent gemfile" do
it "shows error" do
- gemfile "Gemfile-other", <<-G
- gem "myrack"
+ create_file "Gemfile-other", <<-G
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
- gem "rails"; gem "myrack"
+ gem "rails"; gem "rack"
G
- bundle "remove myrack", raise_on_error: false
+ bundle "remove rack", :raise_on_error => false
expect(err).to include("Gems could not be removed. rails (>= 0) would also have been removed.")
- expect(bundled_app("Gemfile-other").read).to include("gem \"myrack\"")
+ expect(bundled_app("Gemfile-other").read).to include("gem \"rack\"")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
- gem "rails"; gem "myrack"
+ gem "rails"; gem "rack"
G
end
end
context "when gem present in gemfiles but could not be removed from one from one of them" do
it "removes gem which can be removed and shows warning for file from which it cannot be removed" do
- gemfile "Gemfile-other", <<-G
- gem "myrack"
+ create_file "Gemfile-other", <<-G
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "Gemfile-other"
- gem"myrack"
+ gem"rack"
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
- expect(bundled_app("Gemfile-other").read).to_not include("gem \"myrack\"")
+ expect(out).to include("rack was removed.")
+ expect(bundled_app("Gemfile-other").read).to_not include("gem \"rack\"")
end
end
end
@@ -597,18 +597,18 @@ RSpec.describe "bundle remove" do
context "with install_if" do
it "removes gems inside blocks and empty blocks" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
install_if(lambda { false }) do
- gem "myrack"
+ gem "rack"
end
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -616,32 +616,32 @@ RSpec.describe "bundle remove" do
context "with env" do
it "removes gems inside blocks and empty blocks" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
env "BUNDLER_TEST" do
- gem "myrack"
+ gem "rack"
end
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
context "with gemspec" do
it "should not remove the gem" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("foo.gemspec", "")
- s.add_dependency "myrack"
+ s.add_dependency "rack"
end
install_gemfile(<<-G)
- source "https://gem.repo1"
- gemspec :path => '#{tmp("foo")}', :name => 'foo'
+ source "#{file_uri_for(gem_repo1)}"
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo'
G
bundle "remove foo"
@@ -654,19 +654,19 @@ RSpec.describe "bundle remove" do
context "when comment is a separate line comment" do
it "does not remove the line comment" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- # gem "myrack" might be used in the future
- gem "myrack"
+ # gem "rack" might be used in the future
+ gem "rack"
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- # gem "myrack" might be used in the future
+ # gem "rack" might be used in the future
G
end
end
@@ -674,16 +674,16 @@ RSpec.describe "bundle remove" do
context "when gem specified for removal has an inline comment" do
it "removes the inline comment" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack" # this can be removed
+ gem "rack" # this can be removed
G
- bundle "remove myrack"
+ bundle "remove rack"
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
end
@@ -691,19 +691,19 @@ RSpec.describe "bundle remove" do
context "when gem specified for removal is mentioned in other gem's comment" do
it "does not remove other gem" do
gemfile <<-G
- source "https://gem.repo1"
- gem "puma" # implements interface provided by gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "puma" # implements interface provided by gem "rack"
- gem "myrack"
+ gem "rack"
G
- bundle "remove myrack"
+ bundle "remove rack"
expect(out).to_not include("puma was removed.")
- expect(out).to include("myrack was removed.")
+ expect(out).to include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
- gem "puma" # implements interface provided by gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "puma" # implements interface provided by gem "rack"
G
end
end
@@ -711,20 +711,20 @@ RSpec.describe "bundle remove" do
context "when gem specified for removal has a comment that mentions other gem" do
it "does not remove other gem" do
gemfile <<-G
- source "https://gem.repo1"
- gem "puma" # implements interface provided by gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "puma" # implements interface provided by gem "rack"
- gem "myrack"
+ gem "rack"
G
bundle "remove puma"
expect(out).to include("puma was removed.")
- expect(out).to_not include("myrack was removed.")
+ expect(out).to_not include("rack was removed.")
expect(gemfile).to eq <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
end
end
diff --git a/spec/bundler/commands/show_spec.rb b/spec/bundler/commands/show_spec.rb
index 7f32d0563b..1c6244be41 100644
--- a/spec/bundler/commands/show_spec.rb
+++ b/spec/bundler/commands/show_spec.rb
@@ -1,10 +1,10 @@
# frozen_string_literal: true
-RSpec.describe "bundle show", bundler: "< 3" do
+RSpec.describe "bundle show", :bundler => "< 3" do
context "with a standard Gemfile" do
before :each do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
end
@@ -50,14 +50,14 @@ RSpec.describe "bundle show", bundler: "< 3" do
end
it "complains if gem not in bundle" do
- bundle "show missing", raise_on_error: false
+ bundle "show missing", :raise_on_error => false
expect(err).to match(/could not find gem 'missing'/i)
end
it "prints path of all gems in bundle sorted by name" do
bundle "show --paths"
- expect(out).to include(default_bundle_path("gems", "rake-#{rake_version}").to_s)
+ expect(out).to include(default_bundle_path("gems", "rake-13.0.1").to_s)
expect(out).to include(default_bundle_path("gems", "rails-2.3.2").to_s)
# Gem names are the last component of their path.
@@ -104,7 +104,7 @@ RSpec.describe "bundle show", bundler: "< 3" do
end
it "prints out branch names other than main" do
- update_git "foo", branch: "omg" do |s|
+ update_git "foo", :branch => "omg" do |s|
s.write "lib/foo.rb", "FOO = '1.0.omg'"
end
@revision = revision_for(lib_path("foo-1.0"))[0...6]
@@ -129,7 +129,7 @@ RSpec.describe "bundle show", bundler: "< 3" do
end
it "handles when a version is a '-' prerelease" do
- @git = build_git("foo", "1.0.0-beta.1", path: lib_path("foo"))
+ @git = build_git("foo", "1.0.0-beta.1", :path => lib_path("foo"))
install_gemfile <<-G
gem "foo", "1.0.0-beta.1", :git => "#{lib_path("foo")}"
G
@@ -142,20 +142,20 @@ RSpec.describe "bundle show", bundler: "< 3" do
context "in a fresh gem in a blank git repo" do
before :each do
- build_git "foo", path: lib_path("foo")
+ build_git "foo", :path => lib_path("foo")
File.open(lib_path("foo/Gemfile"), "w") {|f| f.puts "gemspec" }
- sys_exec "rm -rf .git && git init", dir: lib_path("foo")
+ sys_exec "rm -rf .git && git init", :dir => lib_path("foo")
end
it "does not output git errors" do
- bundle :show, dir: lib_path("foo")
+ bundle :show, :dir => lib_path("foo")
expect(err_without_deprecations).to be_empty
end
end
it "performs an automatic bundle install" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo"
G
@@ -167,26 +167,26 @@ RSpec.describe "bundle show", bundler: "< 3" do
context "with a valid regexp for gem name" do
it "presents alternatives", :readline do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
bundle "show rac"
- expect(out).to match(/\A1 : myrack\n2 : myrack-obama\n0 : - exit -(\n>|\z)/)
+ expect(out).to match(/\A1 : rack\n2 : rack-obama\n0 : - exit -(\n>.*)?\z/)
end
end
context "with an invalid regexp for gem name" do
it "does not find the gem" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
invalid_regexp = "[]"
- bundle "show #{invalid_regexp}", raise_on_error: false
+ bundle "show #{invalid_regexp}", :raise_on_error => false
expect(err).to include("Could not find gem '#{invalid_regexp}'.")
end
end
@@ -199,7 +199,7 @@ RSpec.describe "bundle show", bundler: "< 3" do
it "doesn't update gems to newer versions" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
G
@@ -219,6 +219,6 @@ RSpec.describe "bundle show", bundler: "< 3" do
end
end
-RSpec.describe "bundle show", bundler: "3" do
+RSpec.describe "bundle show", :bundler => "3" do
pending "shows a friendly error about the command removal"
end
diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb
index 2d66c0e550..84042709bf 100644
--- a/spec/bundler/commands/update_spec.rb
+++ b/spec/bundler/commands/update_spec.rb
@@ -6,17 +6,17 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
it "updates the entire bundle" do
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
@@ -24,17 +24,17 @@ RSpec.describe "bundle update" do
bundle "update"
expect(out).to include("Bundle updated!")
- expect(the_bundle).to include_gems "myrack 1.2", "myrack-obama 1.0", "activesupport 3.0"
+ expect(the_bundle).to include_gems "rack 1.2", "rack-obama 1.0", "activesupport 3.0"
end
it "doesn't delete the Gemfile.lock file if something goes wrong" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
exit!
G
- bundle "update", raise_on_error: false
+ bundle "update", :raise_on_error => false
expect(bundled_app_lock).to exist
end
end
@@ -44,37 +44,37 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
it "updates the entire bundle" do
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
end
- bundle "update", all: true
+ bundle "update", :all => true
expect(out).to include("Bundle updated!")
- expect(the_bundle).to include_gems "myrack 1.2", "myrack-obama 1.0", "activesupport 3.0"
+ expect(the_bundle).to include_gems "rack 1.2", "rack-obama 1.0", "activesupport 3.0"
end
it "doesn't delete the Gemfile.lock file if something goes wrong" do
- install_gemfile "source 'https://gem.repo1'"
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
exit!
G
- bundle "update", all: true, raise_on_error: false
+ bundle "update", :all => true, :raise_on_error => false
expect(bundled_app_lock).to exist
end
end
@@ -82,11 +82,11 @@ RSpec.describe "bundle update" do
describe "with --gemfile" do
it "creates lock files based on the Gemfile name" do
gemfile bundled_app("OmgFile"), <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0"
G
- bundle "update --gemfile OmgFile", all: true
+ bundle "update --gemfile OmgFile", :all => true
expect(bundled_app("OmgFile.lock")).to exist
end
@@ -96,19 +96,19 @@ RSpec.describe "bundle update" do
before { bundle "config set update_requires_all_flag true" }
it "errors when passed nothing" do
- install_gemfile "source 'https://gem.repo1'"
- bundle :update, raise_on_error: false
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
+ bundle :update, :raise_on_error => false
expect(err).to eq("To update everything, pass the `--all` flag.")
end
it "errors when passed --all and another option" do
- install_gemfile "source 'https://gem.repo1'"
- bundle "update --all foo", raise_on_error: false
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
+ bundle "update --all foo", :raise_on_error => false
expect(err).to eq("Cannot specify --all along with specific options.")
end
it "updates everything when passed --all" do
- install_gemfile "source 'https://gem.repo1'"
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
bundle "update --all"
expect(out).to include("Bundle updated!")
end
@@ -119,9 +119,9 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
@@ -137,24 +137,24 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
it "unlocks all child dependencies that are unrelated to other locked dependencies" do
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
end
- bundle "update myrack-obama"
- expect(the_bundle).to include_gems "myrack 1.2", "myrack-obama 1.0", "activesupport 2.3.5"
+ bundle "update rack-obama"
+ expect(the_bundle).to include_gems "rack 1.2", "rack-obama 1.0", "activesupport 2.3.5"
end
end
@@ -163,19 +163,19 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
it "should inform the user" do
- bundle "update halting-problem-solver", raise_on_error: false
+ bundle "update halting-problem-solver", :raise_on_error => false
expect(err).to include "Could not find gem 'halting-problem-solver'"
end
it "should suggest alternatives" do
- bundle "update platformspecific", raise_on_error: false
+ bundle "update platformspecific", :raise_on_error => false
expect(err).to include "Did you mean platform_specific?"
end
end
@@ -185,22 +185,22 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
it "should update the child dependency" do
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
end
- bundle "update myrack"
- expect(the_bundle).to include_gems "myrack 1.2"
+ bundle "update rack"
+ expect(the_bundle).to include_gems "rack 1.2"
end
end
@@ -223,7 +223,7 @@ RSpec.describe "bundle update" do
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "slim-rails"
gem "slim_lint"
G
@@ -236,7 +236,7 @@ RSpec.describe "bundle update" do
end
end
- bundle "update", all: true
+ bundle "update", :all => true
expect(the_bundle).to include_gems("slim 3.0.9", "slim-rails 3.1.3", "slim_lint 0.16.1")
end
@@ -269,20 +269,15 @@ RSpec.describe "bundle update" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "country_select"
gem "countries"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo4, "countries", "3.1.0")
- c.checksum(gem_repo4, "country_select", "5.1.0")
- end
-
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
countries (3.1.0)
country_select (5.1.0)
@@ -294,14 +289,14 @@ RSpec.describe "bundle update" do
DEPENDENCIES
countries
country_select
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
previous_lockfile = lockfile
- bundle "lock --update", env: { "DEBUG" => "1" }, verbose: true
+ bundle "lock --update"
expect(lockfile).to eq(previous_lockfile)
end
@@ -331,7 +326,7 @@ RSpec.describe "bundle update" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "oauth2"
gem "quickbooks-ruby"
@@ -339,7 +334,7 @@ RSpec.describe "bundle update" do
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
faraday (2.5.2)
multi_json (1.15.0)
@@ -390,7 +385,7 @@ RSpec.describe "bundle update" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gemspec
@@ -404,7 +399,7 @@ RSpec.describe "bundle update" do
specs:
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
rake (13.0.6)
sneakers (2.11.0)
@@ -439,8 +434,8 @@ RSpec.describe "bundle update" do
build_gem "c", "2.0"
end
- install_gemfile <<-G, verbose: true
- source "https://gem.repo4"
+ install_gemfile <<-G, :verbose => true
+ source "#{file_uri_for(gem_repo4)}"
gem "a"
G
@@ -452,7 +447,7 @@ RSpec.describe "bundle update" do
end
end
- bundle "update", all: true, verbose: true
+ bundle "update", :all => true, :verbose => true
expect(the_bundle).to include_gems("a 1.0", "b 1.0", "c 2.0")
end
@@ -464,7 +459,7 @@ RSpec.describe "bundle update" do
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "a"
gem "b"
G
@@ -472,7 +467,7 @@ RSpec.describe "bundle update" do
expect(the_bundle).to include_gems("a 1.0", "b 2.0")
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "a"
gem "b", "1.0"
G
@@ -497,27 +492,22 @@ RSpec.describe "bundle update" do
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "activesupport", "~> 6.1.0"
G
expect(the_bundle).to include_gems("activesupport 6.1.4.1", "tzinfo 2.0.4")
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "activesupport", "~> 6.0.0"
G
original_lockfile = lockfile
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "activesupport", "6.0.4.1"
- c.checksum gem_repo4, "tzinfo", "1.2.9"
- end
-
expected_lockfile = <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
activesupport (6.0.4.1)
tzinfo (~> 1.1)
@@ -528,7 +518,7 @@ RSpec.describe "bundle update" do
DEPENDENCIES
activesupport (~> 6.0.0)
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -553,45 +543,19 @@ RSpec.describe "bundle update" do
before do
build_repo2
- gemfile <<-G
- source "https://gem.repo2"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
it "doesn't hit repo2" do
- simulate_platform "x86-darwin-100" do
- lockfile <<~L
- GEM
- remote: https://gem.repo2/
- specs:
- activesupport (2.3.5)
- platform_specific (1.0-x86-darwin-100)
- myrack (1.0.0)
- myrack-obama (1.0)
- myrack
-
- PLATFORMS
- #{local_platform}
-
- DEPENDENCIES
- activesupport
- platform_specific
- myrack-obama
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "install"
-
- FileUtils.rm_rf(gem_repo2)
-
- bundle "update --local --all"
- expect(out).not_to include("Fetching source index")
- end
+ FileUtils.rm_rf(gem_repo2)
+
+ bundle "update --local --all"
+ expect(out).not_to include("Fetching source index")
end
end
@@ -602,26 +566,26 @@ RSpec.describe "bundle update" do
it "should update only specified group gems" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", :group => :development
- gem "myrack"
+ gem "rack"
G
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
end
bundle "update --group development"
expect(the_bundle).to include_gems "activesupport 3.0"
- expect(the_bundle).not_to include_gems "myrack 1.2"
+ expect(the_bundle).not_to include_gems "rack 1.2"
end
context "when conservatively updating a group with non-group sub-deps" do
it "should update only specified group gems" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activemerchant", :group => :development
gem "activesupport"
G
@@ -637,9 +601,9 @@ RSpec.describe "bundle update" do
context "when there is a source with the same name as a gem in a group" do
before do
- build_git "foo", path: lib_path("activesupport")
+ build_git "foo", :path => lib_path("activesupport")
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport", :group => :development
gem "foo", :git => "#{lib_path("activesupport")}"
G
@@ -647,7 +611,7 @@ RSpec.describe "bundle update" do
it "should not update the gems from that source" do
update_repo2 { build_gem "activesupport", "3.0" }
- update_git "foo", "2.0", path: lib_path("activesupport")
+ update_git "foo", "2.0", :path => lib_path("activesupport")
bundle "update --group development"
expect(the_bundle).to include_gems "activesupport 3.0"
@@ -658,13 +622,13 @@ RSpec.describe "bundle update" do
context "when bundler itself is a transitive dependency" do
it "executes without error" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport", :group => :development
- gem "myrack"
+ gem "rack"
G
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "activesupport", "3.0"
@@ -672,7 +636,7 @@ RSpec.describe "bundle update" do
bundle "update --group development"
expect(the_bundle).to include_gems "activesupport 2.3.5"
expect(the_bundle).to include_gems "bundler #{Bundler::VERSION}"
- expect(the_bundle).not_to include_gems "myrack 1.2"
+ expect(the_bundle).not_to include_gems "rack 1.2"
end
end
end
@@ -682,16 +646,16 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
- gem "myrack-obama"
+ gem "rack-obama"
gem "platform_specific"
G
end
- it "should fail loudly", bundler: "< 3" do
+ it "should fail loudly", :bundler => "< 3" do
bundle "install --deployment"
- bundle "update", all: true, raise_on_error: false
+ bundle "update", :all => true, :raise_on_error => false
expect(last_command).to be_failure
expect(err).to match(/Bundler is unlocking, but the lockfile can't be updated because frozen mode is set/)
@@ -700,20 +664,20 @@ RSpec.describe "bundle update" do
it "should fail loudly when frozen is set globally" do
bundle "config set --global frozen 1"
- bundle "update", all: true, raise_on_error: false
+ bundle "update", :all => true, :raise_on_error => false
expect(err).to match(/Bundler is unlocking, but the lockfile can't be updated because frozen mode is set/).
and match(/freeze by running `bundle config set frozen false`./)
end
it "should fail loudly when deployment is set globally" do
bundle "config set --global deployment true"
- bundle "update", all: true, raise_on_error: false
+ bundle "update", :all => true, :raise_on_error => false
expect(err).to match(/Bundler is unlocking, but the lockfile can't be updated because frozen mode is set/).
and match(/freeze by running `bundle config set frozen false`./)
end
it "should not suggest any command to unfreeze bundler if frozen is set through ENV" do
- bundle "update", all: true, raise_on_error: false, env: { "BUNDLE_FROZEN" => "true" }
+ bundle "update", :all => true, :raise_on_error => false, :env => { "BUNDLE_FROZEN" => "true" }
expect(err).to match(/Bundler is unlocking, but the lockfile can't be updated because frozen mode is set/)
expect(err).not_to match(/by running/)
end
@@ -726,7 +690,7 @@ RSpec.describe "bundle update" do
it "should not update gems not included in the source that happen to have the same name" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
G
update_repo2 { build_gem "activesupport", "3.0" }
@@ -737,7 +701,7 @@ RSpec.describe "bundle update" do
it "should not update gems not included in the source that happen to have the same name" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
G
update_repo2 { build_gem "activesupport", "3.0" }
@@ -757,7 +721,7 @@ RSpec.describe "bundle update" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "harry"
gem "fred"
G
@@ -789,7 +753,7 @@ RSpec.describe "bundle update" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "harry"
gem "fred"
G
@@ -812,18 +776,18 @@ RSpec.describe "bundle update" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
G
- bundle "update", all: true, verbose: true
+ bundle "update", :all => true, :verbose => true
expect(out).to include("Using activesupport 2.3.5")
update_repo2 do
build_gem "activesupport", "3.0"
end
- bundle "update", all: true
+ bundle "update", :all => true
expect(out).to include("Installing activesupport 3.0 (was 2.3.5)")
end
@@ -834,118 +798,35 @@ RSpec.describe "bundle update" do
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "bar"
gem "foo"
G
- bundle "update", all: true
+ bundle "update", :all => true
expect(out).to match(/Resolving dependencies\.\.\.\.*\nBundle updated!/)
update_repo4 do
build_gem "foo", "2.0"
end
- bundle "update", all: true
- expect(out.sub("Removing foo (1.0)\n", "")).to match(/Resolving dependencies\.\.\.\.*\nFetching foo 2\.0 \(was 1\.0\)\nInstalling foo 2\.0 \(was 1\.0\)\nBundle updated/)
+ bundle "update", :all => true
+ out.sub!("Removing foo (1.0)\n", "")
+ expect(out).to match(/Resolving dependencies\.\.\.\.*\nFetching foo 2\.0 \(was 1\.0\)\nInstalling foo 2\.0 \(was 1\.0\)\nBundle updated/)
end
it "shows error message when Gemfile.lock is not preset and gem is specified" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
G
- bundle "update nonexisting", raise_on_error: false
+ bundle "update nonexisting", :raise_on_error => false
expect(err).to include("This Bundle hasn't been installed yet. Run `bundle install` to update and install the bundled gems.")
expect(exitstatus).to eq(22)
end
- context "with multiple sources and caching enabled" do
- before do
- build_repo2 do
- build_gem "myrack", "1.0.0"
-
- build_gem "request_store", "1.0.0" do |s|
- s.add_dependency "myrack", "1.0.0"
- end
- end
-
- build_repo4 do
- # set up repo with no gems
- end
-
- gemfile <<~G
- source "https://gem.repo2"
-
- gem "request_store"
-
- source "https://gem.repo4" do
- end
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo2/
- specs:
- myrack (1.0.0)
- request_store (1.0.0)
- myrack (= 1.0.0)
-
- GEM
- remote: https://gem.repo4/
- specs:
-
- PLATFORMS
- #{local_platform}
-
- DEPENDENCIES
- request_store
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "works" do
- bundle :install
- bundle :cache
-
- update_repo2 do
- build_gem "request_store", "1.1.0" do |s|
- s.add_dependency "myrack", "1.0.0"
- end
- end
-
- bundle "update request_store"
-
- expect(out).to include("Bundle updated!")
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo2/
- specs:
- myrack (1.0.0)
- request_store (1.1.0)
- myrack (= 1.0.0)
-
- GEM
- remote: https://gem.repo4/
- specs:
-
- PLATFORMS
- #{local_platform}
-
- DEPENDENCIES
- request_store
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- context "with multiple, duplicated sources, with lockfile in old format", bundler: "< 3" do
+ context "with multiple, duplicated sources, with lockfile in old format", :bundler => "< 3" do
before do
build_repo2 do
build_gem "dotenv", "2.7.6"
@@ -956,7 +837,7 @@ RSpec.describe "bundle update" do
build_gem "vcr", "6.0.0"
end
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "pkg-gem-flowbyte-with-dep", "1.0.0" do |s|
s.add_dependency "oj"
end
@@ -999,8 +880,8 @@ RSpec.describe "bundle update" do
end
it "works" do
- bundle :install, artifice: "compact_index"
- bundle "update oj", artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
+ bundle "update oj", :artifice => "compact_index"
expect(out).to include("Bundle updated!")
expect(the_bundle).to include_gems "oj 3.11.5"
@@ -1015,49 +896,49 @@ RSpec.describe "bundle update in more complicated situations" do
it "will eagerly unlock dependencies of a specified gem" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "thin"
- gem "myrack-obama"
+ gem "rack-obama"
G
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "thin", "2.0" do |s|
- s.add_dependency "myrack"
+ s.add_dependency "rack"
end
end
bundle "update thin"
- expect(the_bundle).to include_gems "thin 2.0", "myrack 1.2", "myrack-obama 1.0"
+ expect(the_bundle).to include_gems "thin 2.0", "rack 1.2", "rack-obama 1.0"
end
it "will warn when some explicitly updated gems are not updated" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "thin"
- gem "myrack-obama"
+ gem "rack-obama"
G
update_repo2 do
- build_gem("thin", "2.0") {|s| s.add_dependency "myrack" }
- build_gem "myrack", "10.0"
+ build_gem("thin", "2.0") {|s| s.add_dependency "rack" }
+ build_gem "rack", "10.0"
end
- bundle "update thin myrack-obama"
- expect(last_command.stdboth).to include "Bundler attempted to update myrack-obama but its version stayed the same"
- expect(the_bundle).to include_gems "thin 2.0", "myrack 10.0", "myrack-obama 1.0"
+ bundle "update thin rack-obama"
+ expect(last_command.stdboth).to include "Bundler attempted to update rack-obama but its version stayed the same"
+ expect(the_bundle).to include_gems "thin 2.0", "rack 10.0", "rack-obama 1.0"
end
it "will not warn when an explicitly updated git gem changes sha but not version" do
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => '#{lib_path("foo-1.0")}'
G
@@ -1071,28 +952,28 @@ RSpec.describe "bundle update in more complicated situations" do
end
it "will not warn when changing gem sources but not versions" do
- build_git "myrack"
+ build_git "rack"
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", :git => '#{lib_path("myrack-1.0")}'
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", :git => '#{lib_path("rack-1.0")}'
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "update myrack"
+ bundle "update rack"
expect(last_command.stdboth).not_to include "attempted to update"
end
it "will update only from pinned source" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
- source "https://gem.repo1" do
+ source "#{file_uri_for(gem_repo1)}" do
gem "thin"
end
G
@@ -1101,12 +982,12 @@ RSpec.describe "bundle update in more complicated situations" do
build_gem "thin", "2.0"
end
- bundle "update", artifice: "compact_index"
+ bundle "update"
expect(the_bundle).to include_gems "thin 1.0"
end
context "when the lockfile is for a different platform" do
- around do |example|
+ before do
build_repo4 do
build_gem("a", "0.9")
build_gem("a", "0.9") {|s| s.platform = "java" }
@@ -1115,13 +996,13 @@ RSpec.describe "bundle update in more complicated situations" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "a"
G
lockfile <<-L
GEM
- remote: https://gem.repo4
+ remote: #{file_uri_for(gem_repo4)}
specs:
a (0.9-java)
@@ -1132,11 +1013,11 @@ RSpec.describe "bundle update in more complicated situations" do
a
L
- simulate_platform linux, &example
+ simulate_platform linux
end
it "allows updating" do
- bundle :update, all: true
+ bundle :update, :all => true
expect(the_bundle).to include_gem "a 1.1"
end
@@ -1154,13 +1035,13 @@ RSpec.describe "bundle update in more complicated situations" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "a", platform: :jruby
G
lockfile <<-L
GEM
- remote: https://gem.repo4
+ remote: #{file_uri_for(gem_repo4)}
specs:
a (0.9-java)
@@ -1170,14 +1051,14 @@ RSpec.describe "bundle update in more complicated situations" do
DEPENDENCIES
a
L
+
+ simulate_platform linux
end
it "is not updated because it is not actually included in the bundle" do
- simulate_platform linux do
- bundle "update a"
- expect(last_command.stdboth).to include "Bundler attempted to update a but it was not considered because it is for a different platform from the current one"
- expect(the_bundle).to_not include_gem "a"
- end
+ bundle "update a"
+ expect(last_command.stdboth).to include "Bundler attempted to update a but it was not considered because it is for a different platform from the current one"
+ expect(the_bundle).to_not include_gem "a"
end
end
end
@@ -1187,14 +1068,14 @@ RSpec.describe "bundle update without a Gemfile.lock" do
build_repo2
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack", "1.0"
+ gem "rack", "1.0"
G
- bundle "update", all: true
+ bundle "update", :all => true
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
@@ -1202,23 +1083,23 @@ RSpec.describe "bundle update when a gem depends on a newer version of bundler"
before do
build_repo2 do
build_gem "rails", "3.0.1" do |s|
- s.add_dependency "bundler", "9.9.9"
+ s.add_dependency "bundler", Bundler::VERSION.succ
end
- build_gem "bundler", "9.9.9"
+ build_gem "bundler", Bundler::VERSION.succ
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0.1"
G
end
it "should explain that bundler conflicted and how to resolve the conflict" do
- bundle "update", all: true, raise_on_error: false
+ bundle "update", :all => true, :raise_on_error => false
expect(last_command.stdboth).not_to match(/in snapshot/i)
expect(err).to match(/current Bundler version/i).
- and match(/Install the necessary version with `gem install bundler:9\.9\.9`/i)
+ and match(/Install the necessary version with `gem install bundler:#{Bundler::VERSION.succ}`/i)
end
end
@@ -1227,27 +1108,26 @@ RSpec.describe "bundle update --ruby" do
before do
install_gemfile <<-G
ruby '~> #{Gem.ruby_version}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
-
it "removes the Ruby from the Gemfile.lock" do
bundle "update --ruby"
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- #{checksums_section_when_enabled}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1258,33 +1138,32 @@ RSpec.describe "bundle update --ruby" do
before do
install_gemfile <<-G
ruby '~> #{Gem.ruby_version}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
gemfile <<-G
- ruby '~> #{current_ruby_minor}'
- source "https://gem.repo1"
+ ruby '~> #{current_ruby_minor}'
+ source "#{file_uri_for(gem_repo1)}"
G
end
-
it "updates the Gemfile.lock with the latest version" do
bundle "update --ruby"
expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo1/
- specs:
+ GEM
+ remote: #{file_uri_for(gem_repo1)}/
+ specs:
- PLATFORMS
- #{lockfile_platforms}
+ PLATFORMS
+ #{lockfile_platforms}
- DEPENDENCIES
- #{checksums_section_when_enabled}
- RUBY VERSION
- #{Bundler::RubyVersion.system}
+ DEPENDENCIES
- BUNDLED WITH
- #{Bundler::VERSION}
+ RUBY VERSION
+ #{Bundler::RubyVersion.system}
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
L
end
end
@@ -1293,16 +1172,16 @@ RSpec.describe "bundle update --ruby" do
before do
install_gemfile <<-G
ruby '~> #{Gem.ruby_version}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
gemfile <<-G
ruby '~> 2.1.0'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
it "shows a helpful error message" do
- bundle "update --ruby", raise_on_error: false
+ bundle "update --ruby", :raise_on_error => false
expect(err).to include("Your Ruby version is #{Bundler::RubyVersion.system.gem_version}, but your Gemfile specified ~> 2.1.0")
end
@@ -1312,7 +1191,7 @@ RSpec.describe "bundle update --ruby" do
before do
lockfile <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -1320,8 +1199,6 @@ RSpec.describe "bundle update --ruby" do
DEPENDENCIES
- CHECKSUMS
-
RUBY VERSION
ruby 2.1.4p222
@@ -1331,16 +1208,15 @@ RSpec.describe "bundle update --ruby" do
gemfile <<-G
ruby '~> #{Gem.ruby_version}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
end
-
it "updates the Gemfile.lock with the latest version" do
bundle "update --ruby"
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -1348,8 +1224,6 @@ RSpec.describe "bundle update --ruby" do
DEPENDENCIES
- CHECKSUMS
-
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -1363,323 +1237,225 @@ end
RSpec.describe "bundle update --bundler" do
it "updates the bundler version in the lockfile" do
build_repo4 do
- build_gem "bundler", "2.5.9"
- build_gem "myrack", "1.0"
- end
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo4, "myrack", "1.0")
+ build_gem "rack", "1.0"
end
install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- myrack (1.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- myrack
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, '\11.0.0\2')
- bundle :update, bundler: true, verbose: true
+ bundle :update, :bundler => true, :artifice => "compact_index", :verbose => true
expect(out).to include("Using bundler #{Bundler::VERSION}")
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
- myrack (1.0)
+ rack (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
L
- expect(the_bundle).to include_gem "myrack 1.0"
+ expect(the_bundle).to include_gem "rack 1.0"
end
it "updates the bundler version in the lockfile without re-resolving if the highest version is already installed" do
+ system_gems "bundler-2.3.9"
+
build_repo4 do
- build_gem "bundler", "2.3.9"
- build_gem "myrack", "1.0"
+ build_gem "rack", "1.0"
end
install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.3.9")
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo4, "myrack", "1.0")
- end
-
- bundle :update, bundler: true, verbose: true
+ bundle :update, :bundler => true, :artifice => "compact_index", :verbose => true
expect(out).to include("Using bundler #{Bundler::VERSION}")
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
- myrack (1.0)
+ rack (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
L
- expect(the_bundle).to include_gem "myrack 1.0"
+ expect(the_bundle).to include_gem "rack 1.0"
end
- it "updates the bundler version in the lockfile even if the latest version is not installed", :ruby_repo do
- pristine_system_gems "bundler-2.99.9"
+ it "updates the bundler version in the lockfile even if the latest version is not installed", :ruby_repo, :realworld do
+ pristine_system_gems "bundler-2.3.9"
build_repo4 do
- build_gem "myrack", "1.0"
-
- build_bundler "999.0.0"
+ build_gem "rack", "1.0"
end
- install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ install_gemfile <<-G, :env => { "BUNDLER_IGNORE_DEFAULT_GEM" => "true" }
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
- lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.99.9")
-
- bundle :update, bundler: true, verbose: true, preserve_ruby_flags: true
-
- expect(out).to include("Updating bundler to 999.0.0")
- expect(out).to include("Running `bundle update --bundler \"> 0.a\" --verbose` with bundler 999.0.0")
- expect(out).not_to include("Installing Bundler 2.99.9 and restarting using that version.")
+ lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.3.9")
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- myrack (1.0)
+ bundle :update, :bundler => true, :artifice => "vcr", :verbose => true, :env => { "BUNDLER_IGNORE_DEFAULT_GEM" => "true" }
- PLATFORMS
- #{lockfile_platforms}
+ # Only updates properly on modern RubyGems.
- DEPENDENCIES
- myrack
+ if Gem.rubygems_version >= Gem::Version.new("3.3.0.dev")
+ expect(out).to include("Updating bundler to 2.3.10")
+ expect(out).to include("Using bundler 2.3.10")
+ expect(out).not_to include("Installing Bundler 2.3.9 and restarting using that version.")
- BUNDLED WITH
- 999.0.0
- L
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ rack (1.0)
- expect(the_bundle).to include_gems "bundler 999.0.0"
- expect(the_bundle).to include_gems "myrack 1.0"
- end
+ PLATFORMS
+ #{lockfile_platforms}
- it "does not claim to update to Bundler version to a wrong version when cached gems are present" do
- pristine_system_gems "bundler-2.99.0"
+ DEPENDENCIES
+ rack
- build_repo4 do
- build_gem "myrack", "3.0.9.1"
+ BUNDLED WITH
+ 2.3.10
+ L
- build_bundler "2.99.0"
+ expect(the_bundle).to include_gems "bundler 2.3.10"
end
- gemfile <<~G
- source "https://gem.repo4"
- gem "myrack"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- myrack (3.0.9.1)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- myrack
-
- BUNDLED WITH
- 2.99.0
- L
-
- bundle :cache, verbose: true
-
- bundle :update, bundler: true, verbose: true
-
- expect(out).not_to include("Updating bundler to")
+ expect(the_bundle).to include_gems "rack 1.0"
end
- it "does not update the bundler version in the lockfile if the latest version is not compatible with current ruby", :ruby_repo do
- pristine_system_gems "bundler-9.9.9"
+ it "errors if the explicit target version does not exist", :realworld do
+ pristine_system_gems "bundler-2.3.9"
build_repo4 do
- build_gem "myrack", "1.0"
-
- build_bundler "9.9.9"
- build_bundler "999.0.0" do |s|
- s.required_ruby_version = "> #{Gem.ruby_version}"
- end
+ build_gem "rack", "1.0"
end
- checksums = checksums_section do |c|
- c.checksum(gem_repo4, "myrack", "1.0")
- end
-
- install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ install_gemfile <<-G, :env => { "BUNDLER_IGNORE_DEFAULT_GEM" => "true" }
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
+ lockfile lockfile.sub(/(^\s*)#{Bundler::VERSION}($)/, "2.3.9")
- bundle :update, bundler: true, verbose: true
-
- expect(out).to include("Using bundler 9.9.9")
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- myrack (1.0)
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- myrack
- #{checksums}
- BUNDLED WITH
- 9.9.9
- L
-
- expect(the_bundle).to include_gems "bundler 9.9.9"
- expect(the_bundle).to include_gems "myrack 1.0"
- end
+ bundle :update, :bundler => "999.999.999", :artifice => "vcr", :raise_on_error => false
- it "errors if the explicit target version does not exist" do
- pristine_system_gems "bundler-9.9.9"
+ # Only gives a meaningful error message on modern RubyGems.
- build_repo4 do
- build_gem "myrack", "1.0"
+ if Gem.rubygems_version >= Gem::Version.new("3.3.0.dev")
+ expect(last_command).to be_failure
+ expect(err).to include("The `bundle update --bundler` target version (999.999.999) does not exist")
end
-
- install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
- G
-
- bundle :update, bundler: "999.999.999", raise_on_error: false
-
- expect(last_command).to be_failure
- expect(err).to eq("The `bundle update --bundler` target version (999.999.999) does not exist")
end
it "allows updating to development versions if already installed locally" do
system_gems "bundler-2.3.0.dev"
build_repo4 do
- build_gem "myrack", "1.0"
+ build_gem "rack", "1.0"
end
install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
- bundle :update, bundler: "2.3.0.dev", verbose: "true"
+ bundle :update, :bundler => "2.3.0.dev", :verbose => "true"
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo4, "myrack", "1.0")
- end
+ # Only updates properly on modern RubyGems.
- expect(lockfile).to eq <<~L
+ if Gem.rubygems_version >= Gem::Version.new("3.3.0.dev")
+ expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
- myrack (1.0)
+ rack (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
2.3.0.dev
L
- expect(out).to include("Using bundler 2.3.0.dev")
+ expect(out).to include("Using bundler 2.3.0.dev")
+ end
end
it "does not touch the network if not necessary" do
system_gems "bundler-2.3.9"
build_repo4 do
- build_gem "myrack", "1.0"
+ build_gem "rack", "1.0"
end
install_gemfile <<-G
- source "https://gem.repo4"
- gem "myrack"
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
G
- bundle :update, bundler: "2.3.9", verbose: true
+ bundle :update, :bundler => "2.3.9", :raise_on_error => false, :verbose => true
expect(out).not_to include("Fetching gem metadata from https://rubygems.org/")
# Only updates properly on modern RubyGems.
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo4, "myrack", "1.0")
- end
- expect(lockfile).to eq <<~L
+ if Gem.rubygems_version >= Gem::Version.new("3.3.0.dev")
+ expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
- myrack (1.0)
+ rack (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
2.3.9
L
- expect(out).to include("Using bundler 2.3.9")
+ expect(out).to include("Using bundler 2.3.9")
+ end
end
it "prints an error when trying to update bundler in frozen mode" do
system_gems "bundler-2.3.9"
gemfile <<~G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
G
lockfile <<-L
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
PLATFORMS
@@ -1691,7 +1467,7 @@ RSpec.describe "bundle update --bundler" do
2.1.4
L
- bundle "update --bundler=2.3.9", env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
+ bundle "update --bundler=2.3.9", :env => { "BUNDLE_FROZEN" => "true" }, :raise_on_error => false
expect(err).to include("An update to the version of bundler itself was requested, but the lockfile can't be updated because frozen mode is set")
end
end
@@ -1719,7 +1495,7 @@ RSpec.describe "bundle update conservative" do
# establish a lockfile set to 1.4.3
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo', '1.4.3'
gem 'bar', '2.0.3'
gem 'qux', '1.0.0'
@@ -1728,7 +1504,7 @@ RSpec.describe "bundle update conservative" do
# remove 1.4.3 requirement and bar altogether
# to setup update specs below
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'foo'
gem 'qux'
G
@@ -1751,7 +1527,7 @@ RSpec.describe "bundle update conservative" do
end
it "update all" do
- bundle "update --patch", all: true
+ bundle "update --patch", :all => true
expect(the_bundle).to include_gems "foo 1.4.5", "bar 2.1.1", "qux 1.0.1"
end
@@ -1773,7 +1549,7 @@ RSpec.describe "bundle update conservative" do
end
it "minor preferred" do
- bundle "update --minor --strict", all: true
+ bundle "update --minor --strict", :all => true
expect(the_bundle).to include_gems "foo 1.5.0", "bar 2.1.1", "qux 1.1.0"
end
@@ -1824,7 +1600,7 @@ RSpec.describe "bundle update conservative" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'isolated_owner'
gem 'shared_owner_a'
@@ -1833,7 +1609,7 @@ RSpec.describe "bundle update conservative" do
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
isolated_dep (2.0.1)
isolated_owner (1.0.1)
@@ -1852,8 +1628,6 @@ RSpec.describe "bundle update conservative" do
shared_owner_a
shared_owner_b
- CHECKSUMS
-
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1886,17 +1660,9 @@ RSpec.describe "bundle update conservative" do
it "should only change direct dependencies when updating the lockfile with --conservative" do
bundle "lock --update --conservative"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "isolated_dep", "2.0.1"
- c.checksum gem_repo4, "isolated_owner", "1.0.2"
- c.checksum gem_repo4, "shared_dep", "5.0.1"
- c.checksum gem_repo4, "shared_owner_a", "3.0.2"
- c.checksum gem_repo4, "shared_owner_b", "4.0.2"
- end
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
isolated_dep (2.0.1)
isolated_owner (1.0.2)
@@ -1914,7 +1680,7 @@ RSpec.describe "bundle update conservative" do
isolated_owner
shared_owner_a
shared_owner_b
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1922,7 +1688,7 @@ RSpec.describe "bundle update conservative" do
it "should match bundle install conservative update behavior when not eagerly unlocking" do
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'isolated_owner', '1.0.2'
gem 'shared_owner_a', '3.0.2'
@@ -1935,59 +1701,13 @@ RSpec.describe "bundle update conservative" do
end
end
- context "when Gemfile dependencies have changed" do
- before do
- build_repo4 do
- build_gem "nokogiri", "1.16.4" do |s|
- s.platform = "arm64-darwin"
- end
-
- build_gem "nokogiri", "1.16.4" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "prism", "0.25.0"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
- gem "nokogiri", ">=1.16.4"
- gem "prism", ">=0.25.0"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.16.4-arm64-darwin)
- nokogiri (1.16.4-x86_64-linux)
-
- PLATFORMS
- arm64-darwin
- x86_64-linux
-
- DEPENDENCIES
- nokogiri (>= 1.16.4)
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "still works" do
- simulate_platform "arm64-darwin-23" do
- bundle "update"
- end
- end
- end
-
context "error handling" do
before do
- gemfile "source 'https://gem.repo1'"
+ gemfile "source \"#{file_uri_for(gem_repo1)}\""
end
it "raises if too many flags are provided" do
- bundle "update --patch --minor", all: true, raise_on_error: false
+ bundle "update --patch --minor", :all => true, :raise_on_error => false
expect(err).to eq "Provide only one of the following options: minor, patch"
end
diff --git a/spec/bundler/commands/version_spec.rb b/spec/bundler/commands/version_spec.rb
index 307058a5dd..53d545f5fa 100644
--- a/spec/bundler/commands/version_spec.rb
+++ b/spec/bundler/commands/version_spec.rb
@@ -4,42 +4,42 @@ require_relative "../support/path"
RSpec.describe "bundle version" do
if Spec::Path.ruby_core?
- COMMIT_HASH = /unknown|[a-fA-F0-9]{7,}/
+ COMMIT_HASH = /unknown|[a-fA-F0-9]{7,}/.freeze
else
- COMMIT_HASH = /[a-fA-F0-9]{7,}/
+ COMMIT_HASH = /[a-fA-F0-9]{7,}/.freeze
end
context "with -v" do
- it "outputs the version", bundler: "< 3" do
+ it "outputs the version", :bundler => "< 3" do
bundle "-v"
expect(out).to eq("Bundler version #{Bundler::VERSION}")
end
- it "outputs the version", bundler: "3" do
+ it "outputs the version", :bundler => "3" do
bundle "-v"
expect(out).to eq(Bundler::VERSION)
end
end
context "with --version" do
- it "outputs the version", bundler: "< 3" do
+ it "outputs the version", :bundler => "< 3" do
bundle "--version"
expect(out).to eq("Bundler version #{Bundler::VERSION}")
end
- it "outputs the version", bundler: "3" do
+ it "outputs the version", :bundler => "3" do
bundle "--version"
expect(out).to eq(Bundler::VERSION)
end
end
context "with version" do
- it "outputs the version with build metadata", bundler: "< 3" do
+ it "outputs the version with build metadata", :bundler => "< 3" do
bundle "version"
expect(out).to match(/\ABundler version #{Regexp.escape(Bundler::VERSION)} \(\d{4}-\d{2}-\d{2} commit #{COMMIT_HASH}\)\z/)
end
- it "outputs the version with build metadata", bundler: "3" do
+ it "outputs the version with build metadata", :bundler => "3" do
bundle "version"
expect(out).to match(/\A#{Regexp.escape(Bundler::VERSION)} \(\d{4}-\d{2}-\d{2} commit #{COMMIT_HASH}\)\z/)
end
diff --git a/spec/bundler/commands/viz_spec.rb b/spec/bundler/commands/viz_spec.rb
index c26e3c81ed..cf612397ab 100644
--- a/spec/bundler/commands/viz_spec.rb
+++ b/spec/bundler/commands/viz_spec.rb
@@ -1,22 +1,22 @@
# frozen_string_literal: true
-RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld: true do
+RSpec.describe "bundle viz", :bundler => "< 3", :if => Bundler.which("dot"), :realworld => true do
before do
realworld_system_gems "ruby-graphviz --version 1.2.5"
end
it "graphs gems from the Gemfile" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
bundle "viz"
expect(out).to include("gem_graph.png")
- bundle "viz", format: "debug"
- expect(out).to eq(<<~DOT.strip)
+ bundle "viz", :format => "debug"
+ expect(out).to eq(strip_whitespace(<<-DOT).strip)
digraph Gemfile {
concentrate = "true";
normalize = "true";
@@ -25,11 +25,11 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
node[ fontname = "Arial, Helvetica, SansSerif"];
edge[ fontname = "Arial, Helvetica, SansSerif" , fontsize = "12"];
default [style = "filled", fillcolor = "#B9B9D5", shape = "box3d", fontsize = "16", label = "default"];
- myrack [style = "filled", fillcolor = "#B9B9D5", label = "myrack"];
- default -> myrack [constraint = "false"];
- "myrack-obama" [style = "filled", fillcolor = "#B9B9D5", label = "myrack-obama"];
- default -> "myrack-obama" [constraint = "false"];
- "myrack-obama" -> myrack;
+ rack [style = "filled", fillcolor = "#B9B9D5", label = "rack"];
+ default -> rack [constraint = "false"];
+ "rack-obama" [style = "filled", fillcolor = "#B9B9D5", label = "rack-obama"];
+ default -> "rack-obama" [constraint = "false"];
+ "rack-obama" -> rack;
}
debugging bundle viz...
DOT
@@ -37,20 +37,20 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
it "graphs gems that are prereleases" do
build_repo2 do
- build_gem "myrack", "1.3.pre"
+ build_gem "rack", "1.3.pre"
end
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack", "= 1.3.pre"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack", "= 1.3.pre"
+ gem "rack-obama"
G
bundle "viz"
expect(out).to include("gem_graph.png")
- bundle "viz", format: :debug, version: true
- expect(out).to eq(<<~EOS.strip)
+ bundle "viz", :format => :debug, :version => true
+ expect(out).to eq(strip_whitespace(<<-EOS).strip)
digraph Gemfile {
concentrate = "true";
normalize = "true";
@@ -59,11 +59,11 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
node[ fontname = "Arial, Helvetica, SansSerif"];
edge[ fontname = "Arial, Helvetica, SansSerif" , fontsize = "12"];
default [style = "filled", fillcolor = "#B9B9D5", shape = "box3d", fontsize = "16", label = "default"];
- myrack [style = "filled", fillcolor = "#B9B9D5", label = "myrack\\n1.3.pre"];
- default -> myrack [constraint = "false"];
- "myrack-obama" [style = "filled", fillcolor = "#B9B9D5", label = "myrack-obama\\n1.0"];
- default -> "myrack-obama" [constraint = "false"];
- "myrack-obama" -> myrack;
+ rack [style = "filled", fillcolor = "#B9B9D5", label = "rack\\n1.3.pre"];
+ default -> rack [constraint = "false"];
+ "rack-obama" [style = "filled", fillcolor = "#B9B9D5", label = "rack-obama\\n1.0"];
+ default -> "rack-obama" [constraint = "false"];
+ "rack-obama" -> rack;
}
debugging bundle viz...
EOS
@@ -77,18 +77,18 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
end
end
- system_gems "graphviz-999", gem_repo: gem_repo4
+ system_gems "graphviz-999", :gem_repo => gem_repo4
end
it "loads the correct ruby-graphviz gem" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
- bundle "viz", format: "debug"
- expect(out).to eq(<<~DOT.strip)
+ bundle "viz", :format => "debug"
+ expect(out).to eq(strip_whitespace(<<-DOT).strip)
digraph Gemfile {
concentrate = "true";
normalize = "true";
@@ -97,11 +97,11 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
node[ fontname = "Arial, Helvetica, SansSerif"];
edge[ fontname = "Arial, Helvetica, SansSerif" , fontsize = "12"];
default [style = "filled", fillcolor = "#B9B9D5", shape = "box3d", fontsize = "16", label = "default"];
- myrack [style = "filled", fillcolor = "#B9B9D5", label = "myrack"];
- default -> myrack [constraint = "false"];
- "myrack-obama" [style = "filled", fillcolor = "#B9B9D5", label = "myrack-obama"];
- default -> "myrack-obama" [constraint = "false"];
- "myrack-obama" -> myrack;
+ rack [style = "filled", fillcolor = "#B9B9D5", label = "rack"];
+ default -> rack [constraint = "false"];
+ "rack-obama" [style = "filled", fillcolor = "#B9B9D5", label = "rack-obama"];
+ default -> "rack-obama" [constraint = "false"];
+ "rack-obama" -> rack;
}
debugging bundle viz...
DOT
@@ -111,7 +111,7 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
context "--without option" do
it "one group" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
group :rails do
@@ -125,11 +125,11 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
it "two groups" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
- group :myrack do
- gem "myrack"
+ group :rack do
+ gem "rack"
end
group :rails do
@@ -137,7 +137,7 @@ RSpec.describe "bundle viz", bundler: "< 3", if: Bundler.which("dot"), realworld
end
G
- bundle "viz --without=rails:myrack"
+ bundle "viz --without=rails:rack"
expect(out).to include("gem_graph.png")
end
end
diff --git a/spec/bundler/install/allow_offline_install_spec.rb b/spec/bundler/install/allow_offline_install_spec.rb
index 21b0568f7d..4c6c77a61e 100644
--- a/spec/bundler/install/allow_offline_install_spec.rb
+++ b/spec/bundler/install/allow_offline_install_spec.rb
@@ -7,17 +7,17 @@ RSpec.describe "bundle install with :allow_offline_install" do
context "with no cached data locally" do
it "still installs" do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "http://testgemserver.local"
- gem "myrack-obama"
+ gem "rack-obama"
G
- expect(the_bundle).to include_gem("myrack 1.0")
+ expect(the_bundle).to include_gem("rack 1.0")
end
it "still fails when the network is down" do
- install_gemfile <<-G, artifice: "fail", raise_on_error: false
+ install_gemfile <<-G, :artifice => "fail", :raise_on_error => false
source "http://testgemserver.local"
- gem "myrack-obama"
+ gem "rack-obama"
G
expect(err).to include("Could not reach host testgemserver.local.")
expect(the_bundle).to_not be_locked
@@ -26,37 +26,37 @@ RSpec.describe "bundle install with :allow_offline_install" do
context "with cached data locally" do
it "will install from the compact index" do
- system_gems ["myrack-1.0.0"], path: default_bundle_path
+ system_gems ["rack-1.0.0"], :path => default_bundle_path
bundle "config set clean false"
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "http://testgemserver.local"
- gem "myrack-obama"
- gem "myrack", "< 1.0"
+ gem "rack-obama"
+ gem "rack", "< 1.0"
G
- expect(the_bundle).to include_gems("myrack-obama 1.0", "myrack 0.9.1")
+ expect(the_bundle).to include_gems("rack-obama 1.0", "rack 0.9.1")
gemfile <<-G
source "http://testgemserver.local"
- gem "myrack-obama"
+ gem "rack-obama"
G
- bundle :update, artifice: "fail", all: true
+ bundle :update, :artifice => "fail", :all => true
expect(last_command.stdboth).to include "Using the cached data for the new index because of a network error"
- expect(the_bundle).to include_gems("myrack-obama 1.0", "myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack-obama 1.0", "rack 1.0.0")
end
def break_git_remote_ops!
FileUtils.mkdir_p(tmp("broken_path"))
File.open(tmp("broken_path/git"), "w", 0o755) do |f|
- f.puts <<~RUBY
+ f.puts strip_whitespace(<<-RUBY)
#!/usr/bin/env ruby
- fetch_args = %w(fetch --force --quiet --no-tags)
+ fetch_args = %w(fetch --force --quiet)
clone_args = %w(clone --bare --no-hardlinks --quiet)
- if (fetch_args.-(ARGV).empty? || clone_args.-(ARGV).empty?) && File.exist?(ARGV[ARGV.index("--") + 1])
+ if (fetch_args.-(ARGV).empty? || clone_args.-(ARGV).empty?) && ARGV.any? {|arg| arg.start_with?("file://") }
warn "git remote ops have been disabled"
exit 1
end
@@ -75,20 +75,20 @@ RSpec.describe "bundle install with :allow_offline_install" do
it "will install from a cached git repo" do
skip "doesn't print errors" if Gem.win_platform?
- git = build_git "a", "1.0.0", path: lib_path("a")
- update_git("a", path: git.path, branch: "new_branch")
+ git = build_git "a", "1.0.0", :path => lib_path("a")
+ update_git("a", :path => git.path, :branch => "new_branch")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "a", :git => #{git.path.to_s.dump}
G
- break_git_remote_ops! { bundle :update, all: true }
+ break_git_remote_ops! { bundle :update, :all => true }
expect(err).to include("Using cached git data because of network errors")
expect(the_bundle).to be_locked
break_git_remote_ops! do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "a", :git => #{git.path.to_s.dump}, :branch => "new_branch"
G
end
diff --git a/spec/bundler/install/binstubs_spec.rb b/spec/bundler/install/binstubs_spec.rb
index 00765ac6dd..928ba80b15 100644
--- a/spec/bundler/install/binstubs_spec.rb
+++ b/spec/bundler/install/binstubs_spec.rb
@@ -6,14 +6,14 @@ RSpec.describe "bundle install" do
expect(Pathname.new("/usr/bin")).not_to be_writable
gemfile <<-G
def Gem.bindir; "/usr/bin"; end
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
config "BUNDLE_SYSTEM_BINDIR" => system_gem_path("altbin").to_s
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0"
- expect(system_gem_path("altbin/myrackup")).to exist
+ expect(the_bundle).to include_gems "rack 1.0.0"
+ expect(system_gem_path("altbin/rackup")).to exist
end
end
@@ -21,26 +21,26 @@ RSpec.describe "bundle install" do
before do
build_repo2 do
build_gem "fake", "14" do |s|
- s.executables = "myrackup"
+ s.executables = "rackup"
end
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "fake"
- gem "myrack"
+ gem "rack"
G
end
it "warns about the situation" do
- bundle "exec myrackup"
+ bundle "exec rackup"
expect(last_command.stderr).to include(
- "The `myrackup` executable in the `fake` gem is being loaded, but it's also present in other gems (myrack).\n" \
+ "The `rackup` executable in the `fake` gem is being loaded, but it's also present in other gems (rack).\n" \
"If you meant to run the executable for another gem, make sure you use a project specific binstub (`bundle binstub <gem_name>`).\n" \
"If you plan to use multiple conflicting executables, generate binstubs for them and disambiguate their names."
).or include(
- "The `myrackup` executable in the `myrack` gem is being loaded, but it's also present in other gems (fake).\n" \
+ "The `rackup` executable in the `rack` gem is being loaded, but it's also present in other gems (fake).\n" \
"If you meant to run the executable for another gem, make sure you use a project specific binstub (`bundle binstub <gem_name>`).\n" \
"If you plan to use multiple conflicting executables, generate binstubs for them and disambiguate their names."
)
diff --git a/spec/bundler/install/bundler_spec.rb b/spec/bundler/install/bundler_spec.rb
index 56f8431181..e7ec3bc7e7 100644
--- a/spec/bundler/install/bundler_spec.rb
+++ b/spec/bundler/install/bundler_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe "bundle install" do
before(:each) do
build_repo2 do
build_gem "rails", "3.0" do |s|
- s.add_dependency "bundler", ">= 0.9.0"
+ s.add_dependency "bundler", ">= 0.9.0.pre"
end
build_gem "bundler", "0.9.1"
build_gem "bundler", Bundler::VERSION
@@ -14,7 +14,7 @@ RSpec.describe "bundle install" do
it "are forced to the current bundler version" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
G
@@ -23,20 +23,20 @@ RSpec.describe "bundle install" do
it "are forced to the current bundler version even if not already present" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
expect(the_bundle).to include_gems "bundler #{Bundler::VERSION}"
end
it "causes a conflict if explicitly requesting a different version of bundler" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
gem "bundler", "0.9.1"
G
- nice_error = <<~E.strip
+ nice_error = <<-E.strip.gsub(/^ {8}/, "")
Could not find compatible versions
Because the current Bundler version (#{Bundler::VERSION}) does not satisfy bundler = 0.9.1
@@ -50,17 +50,17 @@ RSpec.describe "bundle install" do
end
it "causes a conflict if explicitly requesting a non matching requirement on bundler" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
gem "bundler", "~> 0.8"
G
- nice_error = <<~E.strip
+ nice_error = <<-E.strip.gsub(/^ {8}/, "")
Could not find compatible versions
- Because rails >= 3.0 depends on bundler >= 0.9.0
- and the current Bundler version (#{Bundler::VERSION}) does not satisfy bundler >= 0.9.0, < 1.A,
+ Because rails >= 3.0 depends on bundler >= 0.9.0.pre
+ and the current Bundler version (#{Bundler::VERSION}) does not satisfy bundler >= 0.9.0.pre, < 1.A,
rails >= 3.0 requires bundler >= 1.A.
So, because Gemfile depends on rails = 3.0
and Gemfile depends on bundler ~> 0.8,
@@ -73,13 +73,13 @@ RSpec.describe "bundle install" do
end
it "causes a conflict if explicitly requesting a version of bundler that doesn't exist" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
gem "bundler", "0.9.2"
G
- nice_error = <<~E.strip
+ nice_error = <<-E.strip.gsub(/^ {8}/, "")
Could not find compatible versions
Because the current Bundler version (#{Bundler::VERSION}) does not satisfy bundler = 0.9.2
@@ -99,16 +99,16 @@ RSpec.describe "bundle install" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "multiple_versioned_deps"
G
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "multiple_versioned_deps"
- gem "myrack"
+ gem "rack"
G
expect(the_bundle).to include_gems "multiple_versioned_deps 1.0.0"
@@ -116,7 +116,7 @@ RSpec.describe "bundle install" do
it "includes bundler in the bundle when it's a child dependency" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
G
@@ -126,8 +126,8 @@ RSpec.describe "bundle install" do
it "allows gem 'bundler' when Bundler is not in the Gemfile or its dependencies" do
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
G
run "begin; gem 'bundler'; puts 'WIN'; rescue Gem::LoadError => e; puts e.backtrace; end"
@@ -143,13 +143,13 @@ RSpec.describe "bundle install" do
end
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "activemerchant"
gem "rails_pinned_to_old_activesupport"
G
- nice_error = <<~E.strip
+ nice_error = <<-E.strip.gsub(/^ {8}/, "")
Could not find compatible versions
Because every version of rails_pinned_to_old_activesupport depends on activesupport = 1.2.3
@@ -171,13 +171,13 @@ RSpec.describe "bundle install" do
end
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "rails_pinned_to_old_activesupport"
gem "activesupport", "2.3.5"
G
- nice_error = <<~E.strip
+ nice_error = <<-E.strip.gsub(/^ {8}/, "")
Could not find compatible versions
Because every version of rails_pinned_to_old_activesupport depends on activesupport = 1.2.3
@@ -197,12 +197,12 @@ RSpec.describe "bundle install" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'rails', "2.3.2"
G
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails_pinned_to_old_activesupport"
G
@@ -219,17 +219,17 @@ RSpec.describe "bundle install" do
bundle "config set path.system true"
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'rails', "7.0.4"
G
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'rails', "7.0.3"
G
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'rails', "7.0.4"
G
@@ -243,7 +243,7 @@ RSpec.describe "bundle install" do
system_gems "bundler-99999999.99.1"
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
G
@@ -257,7 +257,7 @@ RSpec.describe "bundle install" do
system_gems "bundler-99999999.99.1"
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0"
G
diff --git a/spec/bundler/install/deploy_spec.rb b/spec/bundler/install/deploy_spec.rb
index bd39ac5cc1..2a88ed5b06 100644
--- a/spec/bundler/install/deploy_spec.rb
+++ b/spec/bundler/install/deploy_spec.rb
@@ -3,31 +3,31 @@
RSpec.describe "install in deployment or frozen mode" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
- context "with CLI flags", bundler: "< 3" do
+ context "with CLI flags", :bundler => "< 3" do
it "fails without a lockfile and says that --deployment requires a lock" do
- bundle "install --deployment", raise_on_error: false
- expect(err).to include("The --deployment flag requires a lockfile")
+ bundle "install --deployment", :raise_on_error => false
+ expect(err).to include("The --deployment flag requires a Gemfile.lock")
end
it "fails without a lockfile and says that --frozen requires a lock" do
- bundle "install --frozen", raise_on_error: false
- expect(err).to include("The --frozen flag requires a lockfile")
+ bundle "install --frozen", :raise_on_error => false
+ expect(err).to include("The --frozen flag requires a Gemfile.lock")
end
it "disallows --deployment --system" do
- bundle "install --deployment --system", raise_on_error: false
+ bundle "install --deployment --system", :raise_on_error => false
expect(err).to include("You have specified both --deployment")
expect(err).to include("Please choose only one option")
expect(exitstatus).to eq(15)
end
it "disallows --deployment --path --system" do
- bundle "install --deployment --path . --system", raise_on_error: false
+ bundle "install --deployment --path . --system", :raise_on_error => false
expect(err).to include("You have specified both --path")
expect(err).to include("as well as --system")
expect(err).to include("Please choose only one option")
@@ -35,9 +35,9 @@ RSpec.describe "install in deployment or frozen mode" do
end
it "doesn't mess up a subsequent `bundle install` after you try to deploy without a lock" do
- bundle "install --deployment", raise_on_error: false
+ bundle "install --deployment", :raise_on_error => false
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
it "installs gems by default to vendor/bundle" do
@@ -60,45 +60,33 @@ RSpec.describe "install in deployment or frozen mode" do
it "explodes with the --deployment flag if you make a change and don't check in the lockfile" do
bundle :lock
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
- bundle "install --deployment", raise_on_error: false
+ bundle "install --deployment", :raise_on_error => false
expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile")
- expect(err).to include("* myrack-obama")
+ expect(err).to include("* rack-obama")
expect(err).not_to include("You have deleted from the Gemfile")
expect(err).not_to include("You have changed in the Gemfile")
end
end
- it "fails without a lockfile and says that deployment requires a lock" do
- bundle "config deployment true"
- bundle "install", raise_on_error: false
- expect(err).to include("The deployment setting requires a lockfile")
- end
-
- it "fails without a lockfile and says that frozen requires a lock" do
- bundle "config frozen true"
- bundle "install", raise_on_error: false
- expect(err).to include("The frozen setting requires a lockfile")
- end
-
it "still works if you are not in the app directory and specify --gemfile" do
bundle "install"
simulate_new_machine
bundle "config set --local deployment true"
bundle "config set --local path vendor/bundle"
- bundle "install --gemfile #{tmp}/bundled_app/Gemfile", dir: tmp
- expect(the_bundle).to include_gems "myrack 1.0"
+ bundle "install --gemfile #{tmp}/bundled_app/Gemfile", :dir => tmp
+ expect(the_bundle).to include_gems "rack 1.0"
end
it "works if you exclude a group with a git gem" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
group :test do
gem "foo", :git => "#{lib_path("foo-1.0")}"
end
@@ -115,14 +103,14 @@ RSpec.describe "install in deployment or frozen mode" do
bundle :install
bundle "config set --local deployment true"
bundle :install
- bundle "exec bundle check", env: { "PATH" => path }
+ bundle "exec bundle check", :env => { "PATH" => path }
end
it "works when using path gems from the same path and the version is specified" do
- build_lib "foo", path: lib_path("nested/foo")
- build_lib "bar", path: lib_path("nested/bar")
+ build_lib "foo", :path => lib_path("nested/foo")
+ build_lib "bar", :path => lib_path("nested/bar")
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0", :path => "#{lib_path("nested")}"
gem "bar", :path => "#{lib_path("nested")}"
G
@@ -133,9 +121,9 @@ RSpec.describe "install in deployment or frozen mode" do
end
it "works when path gems are specified twice" do
- build_lib "foo", path: lib_path("nested/foo")
+ build_lib "foo", :path => lib_path("nested/foo")
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("nested/foo")}"
gem "foo", :path => "#{lib_path("nested/foo")}"
G
@@ -146,28 +134,28 @@ RSpec.describe "install in deployment or frozen mode" do
end
it "works when there are credentials in the source URL" do
- install_gemfile(<<-G, artifice: "endpoint_strict_basic_authentication", quiet: true)
+ install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true)
source "http://user:pass@localgemserver.test/"
- gem "myrack-obama", ">= 1.0"
+ gem "rack-obama", ">= 1.0"
G
bundle "config set --local deployment true"
- bundle :install, artifice: "endpoint_strict_basic_authentication"
+ bundle :install, :artifice => "endpoint_strict_basic_authentication"
end
it "works with sources given by a block" do
install_gemfile <<-G
- source "https://gem.repo1"
- source "https://gem.repo1" do
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ source "#{file_uri_for(gem_repo1)}" do
+ gem "rack"
end
G
bundle "config set --local deployment true"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
context "when replacing a host with the same host with credentials" do
@@ -176,29 +164,69 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "install"
gemfile <<-G
source "http://user_name:password@localgemserver.test/"
- gem "myrack"
+ gem "rack"
G
lockfile <<-G
GEM
remote: http://localgemserver.test/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{generic_local_platform}
DEPENDENCIES
- myrack
+ rack
G
bundle "config set --local deployment true"
end
- it "allows the replace" do
- bundle :install
+ it "prevents the replace by default" do
+ bundle :install, :raise_on_error => false
+
+ expect(err).to match(/The list of sources changed/)
+ end
+
+ context "when allow_deployment_source_credential_changes is true" do
+ before { bundle "config set allow_deployment_source_credential_changes true" }
+
+ it "allows the replace" do
+ bundle :install
+
+ expect(out).to match(/Bundle complete!/)
+ end
+ end
- expect(out).to match(/Bundle complete!/)
+ context "when allow_deployment_source_credential_changes is false" do
+ before { bundle "config set allow_deployment_source_credential_changes false" }
+
+ it "prevents the replace" do
+ bundle :install, :raise_on_error => false
+
+ expect(err).to match(/The list of sources changed/)
+ end
+ end
+
+ context "when BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES env var is true" do
+ before { ENV["BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES"] = "true" }
+
+ it "allows the replace" do
+ bundle :install
+
+ expect(out).to match(/Bundle complete!/)
+ end
+ end
+
+ context "when BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES env var is false" do
+ before { ENV["BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES"] = "false" }
+
+ it "prevents the replace" do
+ bundle :install, :raise_on_error => false
+
+ expect(err).to match(/The list of sources changed/)
+ end
end
end
@@ -209,9 +237,7 @@ RSpec.describe "install in deployment or frozen mode" do
it "installs gems by default to vendor/bundle" do
bundle "config set deployment true"
- expect do
- bundle "install"
- end.not_to change { bundled_app_lock.mtime }
+ bundle "install"
expect(out).to include("vendor/bundle")
end
@@ -224,35 +250,31 @@ RSpec.describe "install in deployment or frozen mode" do
it "installs gems to custom path if specified, even when configured through ENV" do
bundle "config set deployment true"
- bundle "install", env: { "BUNDLE_PATH" => "vendor/bundle2" }
+ bundle "install", :env => { "BUNDLE_PATH" => "vendor/bundle2" }
expect(out).to include("vendor/bundle2")
end
it "works with the `frozen` setting" do
bundle "config set frozen true"
- expect do
- bundle "install"
- end.not_to change { bundled_app_lock.mtime }
+ bundle "install"
end
it "works with BUNDLE_FROZEN if you didn't change anything" do
- expect do
- bundle :install, env: { "BUNDLE_FROZEN" => "true" }
- end.not_to change { bundled_app_lock.mtime }
+ bundle :install, :env => { "BUNDLE_FROZEN" => "true" }
end
it "explodes with the `deployment` setting if you make a change and don't check in the lockfile" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile")
- expect(err).to include("* myrack-obama")
+ expect(err).to include("* rack-obama")
expect(err).not_to include("You have deleted from the Gemfile")
expect(err).not_to include("You have changed in the Gemfile")
end
@@ -260,7 +282,7 @@ RSpec.describe "install in deployment or frozen mode" do
it "works if a path gem is missing but is in a without group" do
build_lib "path_gem"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rake"
gem "path_gem", :path => "#{lib_path("path_gem-1.0")}", :group => :development
G
@@ -270,7 +292,7 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "config set --local path .bundle"
bundle "config set --local without development"
bundle "config set --local deployment true"
- bundle :install, env: { "DEBUG" => "1" }
+ bundle :install, :env => { "DEBUG" => "1" }
run "puts :WIN"
expect(out).to eq("WIN")
end
@@ -279,14 +301,14 @@ RSpec.describe "install in deployment or frozen mode" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
- source "https://gem.repo1" do
+ source "#{file_uri_for(gem_repo1)}" do
gem "rake", platform: :#{not_local_tag}
end
G
- bundle :install, env: { "BUNDLE_FROZEN" => "true" }
+ bundle :install, :env => { "BUNDLE_FROZEN" => "true" }
expect(last_command).to be_success
end
@@ -320,14 +342,14 @@ RSpec.describe "install in deployment or frozen mode" do
#{Bundler::VERSION}
L
- bundle :install, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false, artifice: "compact_index"
+ bundle :install, :env => { "BUNDLE_FROZEN" => "true" }, :raise_on_error => false, :artifice => "compact_index"
expect(err).to include("Your lock file is missing \"bar\", but the lockfile can't be updated because frozen mode is set")
end
it "explodes if a path gem is missing" do
build_lib "path_gem"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rake"
gem "path_gem", :path => "#{lib_path("path_gem-1.0")}", :group => :development
G
@@ -336,38 +358,38 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "config set --local path .bundle"
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include("The path `#{lib_path("path_gem-1.0")}` does not exist.")
end
it "can have --frozen set via an environment variable" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
ENV["BUNDLE_FROZEN"] = "1"
- bundle "install", raise_on_error: false
+ bundle "install", :raise_on_error => false
expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile")
- expect(err).to include("* myrack-obama")
+ expect(err).to include("* rack-obama")
expect(err).not_to include("You have deleted from the Gemfile")
expect(err).not_to include("You have changed in the Gemfile")
end
it "can have --deployment set via an environment variable" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
ENV["BUNDLE_DEPLOYMENT"] = "true"
- bundle "install", raise_on_error: false
+ bundle "install", :raise_on_error => false
expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile")
- expect(err).to include("* myrack-obama")
+ expect(err).to include("* rack-obama")
expect(err).not_to include("You have deleted from the Gemfile")
expect(err).not_to include("You have changed in the Gemfile")
end
@@ -387,9 +409,9 @@ RSpec.describe "install in deployment or frozen mode" do
it "can have --frozen set to false via an environment variable" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
ENV["BUNDLE_FROZEN"] = "false"
@@ -397,109 +419,77 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "install"
expect(out).not_to include("frozen mode")
expect(out).not_to include("You have added to the Gemfile")
- expect(out).not_to include("* myrack-obama")
+ expect(out).not_to include("* rack-obama")
end
- it "explodes if you replace a gem and don't check in the lockfile" do
+ it "explodes if you remove a gem and don't check in the lockfile" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
G
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include("frozen mode")
expect(err).to include("You have added to the Gemfile:\n* activesupport\n\n")
- expect(err).to include("You have deleted from the Gemfile:\n* myrack")
- expect(err).not_to include("You have changed in the Gemfile")
- end
-
- it "explodes if you remove a gem and don't check in the lockfile" do
- gemfile 'source "https://gem.repo1"'
-
- bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
- expect(err).to include("Some dependencies were deleted")
- expect(err).to include("frozen mode")
- expect(err).to include("You have deleted from the Gemfile:\n* myrack")
+ expect(err).to include("You have deleted from the Gemfile:\n* rack")
expect(err).not_to include("You have changed in the Gemfile")
end
it "explodes if you add a source" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "git://hubz.com"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "git://hubz.com"
G
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include("frozen mode")
expect(err).not_to include("You have added to the Gemfile")
- expect(err).to include("You have changed in the Gemfile:\n* myrack from `no specified source` to `git://hubz.com`")
+ expect(err).to include("You have changed in the Gemfile:\n* rack from `no specified source` to `git://hubz.com`")
end
- it "explodes if you change a source from git to the default" do
- build_git "myrack"
+ it "explodes if you change a source" do
+ build_git "rack"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-1.0")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-1.0")}"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include("frozen mode")
expect(err).not_to include("You have deleted from the Gemfile")
expect(err).not_to include("You have added to the Gemfile")
- expect(err).to include("You have changed in the Gemfile:\n* myrack from `#{lib_path("myrack-1.0")}` to `no specified source`")
+ expect(err).to include("You have changed in the Gemfile:\n* rack from `#{lib_path("rack-1.0")}` to `no specified source`")
end
- it "explodes if you change a source from git to the default, in presence of other git sources" do
- build_lib "foo", path: lib_path("myrack/foo")
- build_git "myrack", path: lib_path("myrack")
+ it "explodes if you change a source" do
+ build_lib "foo", :path => lib_path("rack/foo")
+ build_git "rack", :path => lib_path("rack")
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack")}"
- gem "foo", :git => "#{lib_path("myrack")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack")}"
+ gem "foo", :git => "#{lib_path("rack")}"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "foo", :git => "#{lib_path("myrack")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "foo", :git => "#{lib_path("rack")}"
G
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
- expect(err).to include("frozen mode")
- expect(err).to include("You have changed in the Gemfile:\n* myrack from `#{lib_path("myrack")}` to `no specified source`")
- expect(err).not_to include("You have added to the Gemfile")
- expect(err).not_to include("You have deleted from the Gemfile")
- end
-
- it "explodes if you change a source from path to git" do
- build_git "myrack", path: lib_path("myrack")
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :path => "#{lib_path("myrack")}"
- G
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "https:/my-git-repo-for-myrack"
- G
-
- bundle "config set --local frozen true"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include("frozen mode")
- expect(err).to include("You have changed in the Gemfile:\n* myrack from `#{lib_path("myrack")}` to `https:/my-git-repo-for-myrack`")
+ expect(err).to include("You have changed in the Gemfile:\n* rack from `#{lib_path("rack")}` to `no specified source`")
expect(err).not_to include("You have added to the Gemfile")
expect(err).not_to include("You have deleted from the Gemfile")
end
@@ -510,30 +500,30 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "config set --local deployment true"
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
+ gem "rack-obama"
G
- run "require 'myrack'", raise_on_error: false
- expect(err).to include <<~E.strip
- The dependencies in your gemfile changed, but the lockfile can't be updated because frozen mode is set (Bundler::ProductionError)
+ run "require 'rack'", :raise_on_error => false
+ expect(err).to include strip_whitespace(<<-E).strip
+The dependencies in your gemfile changed, but the lockfile can't be updated because frozen mode is set (Bundler::ProductionError)
- You have added to the Gemfile:
- * myrack (= 1.0.0)
- * myrack-obama
+You have added to the Gemfile:
+* rack (= 1.0.0)
+* rack-obama
- You have deleted from the Gemfile:
- * myrack
+You have deleted from the Gemfile:
+* rack
E
end
end
context "with path in Gemfile and packed" do
it "works fine after bundle package and bundle install --local" do
- build_lib "foo", path: lib_path("foo")
+ build_lib "foo", :path => lib_path("foo")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
diff --git a/spec/bundler/install/failure_spec.rb b/spec/bundler/install/failure_spec.rb
index 2c2773e849..4a9c33754f 100644
--- a/spec/bundler/install/failure_spec.rb
+++ b/spec/bundler/install/failure_spec.rb
@@ -14,8 +14,8 @@ RSpec.describe "bundle install" do
end
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
G
expect(err).to start_with("Gem::Ext::BuildError: ERROR: Failed to build gem native extension.")
@@ -39,8 +39,8 @@ In Gemfile:
end
it "removes the downloaded .gem" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo4"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo4)}"
gem "a"
G
diff --git a/spec/bundler/install/gemfile/eval_gemfile_spec.rb b/spec/bundler/install/gemfile/eval_gemfile_spec.rb
index a507e52485..02283291b4 100644
--- a/spec/bundler/install/gemfile/eval_gemfile_spec.rb
+++ b/spec/bundler/install/gemfile/eval_gemfile_spec.rb
@@ -2,7 +2,7 @@
RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
before do
- build_lib("gunks", path: bundled_app("gems/gunks")) do |s|
+ build_lib("gunks", :path => bundled_app.join("gems/gunks")) do |s|
s.name = "gunks"
s.version = "0.0.1"
end
@@ -10,21 +10,21 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
context "eval-ed Gemfile points to an internal gemspec" do
before do
- gemfile "Gemfile-other", <<-G
- source "https://gem.repo1"
+ create_file "Gemfile-other", <<-G
+ source "#{file_uri_for(gem_repo1)}"
gemspec :path => 'gems/gunks'
G
end
it "installs the gemspec specified gem" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile 'Gemfile-other'
G
expect(out).to include("Resolving dependencies")
expect(out).to include("Bundle complete")
- expect(the_bundle).to include_gem "gunks 0.0.1", source: "path@#{bundled_app("gems", "gunks")}"
+ expect(the_bundle).to include_gem "gunks 0.0.1", :source => "path@#{bundled_app("gems", "gunks")}"
end
end
@@ -36,12 +36,12 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
build_gem "zip-zip", "0.3"
end
- gemfile bundled_app("gems/Gemfile"), <<-G
- source "https://gem.repo2"
+ create_file bundled_app("gems/Gemfile"), <<-G
+ source "#{file_uri_for(gem_repo2)}"
gemspec :path => "\#{__dir__}/gunks"
- source "https://gem.repo2" do
+ source "#{file_uri_for(gem_repo2)}" do
gem "zip-zip"
end
G
@@ -49,7 +49,7 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
it "installs and finds gems correctly" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails"
@@ -64,14 +64,14 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
context "eval-ed Gemfile has relative-path gems" do
before do
- build_lib("a", path: bundled_app("gems/a"))
- gemfile bundled_app("nested/Gemfile-nested"), <<-G
- source "https://gem.repo1"
+ build_lib("a", :path => bundled_app("gems/a"))
+ create_file bundled_app("nested/Gemfile-nested"), <<-G
+ source "#{file_uri_for(gem_repo1)}"
gem "a", :path => "../gems/a"
G
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "nested/Gemfile-nested"
G
end
@@ -95,28 +95,28 @@ RSpec.describe "bundle install with gemfile that uses eval_gemfile" do
it "installs the gemspec specified gem" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile 'other/Gemfile-other'
gemspec :path => 'gems/gunks'
G
expect(out).to include("Resolving dependencies")
expect(out).to include("Bundle complete")
- expect(the_bundle).to include_gem "gunks 0.0.1", source: "path@#{bundled_app("gems", "gunks")}"
+ expect(the_bundle).to include_gem "gunks 0.0.1", :source => "path@#{bundled_app("gems", "gunks")}"
end
end
context "eval-ed Gemfile references other gemfiles" do
it "works with relative paths" do
- gemfile "other/Gemfile-other", "gem 'myrack'"
- gemfile "other/Gemfile", "eval_gemfile 'Gemfile-other'"
- gemfile "Gemfile-alt", <<-G
- source "https://gem.repo1"
+ create_file "other/Gemfile-other", "gem 'rack'"
+ create_file "other/Gemfile", "eval_gemfile 'Gemfile-other'"
+ create_file "Gemfile-alt", <<-G
+ source "#{file_uri_for(gem_repo1)}"
eval_gemfile "other/Gemfile"
G
install_gemfile "eval_gemfile File.expand_path('Gemfile-alt')"
- expect(the_bundle).to include_gem "myrack 1.0.0"
+ expect(the_bundle).to include_gem "rack 1.0.0"
end
end
end
diff --git a/spec/bundler/install/gemfile/force_ruby_platform_spec.rb b/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
index 926e7527e6..0e9f1f0292 100644
--- a/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
+++ b/spec/bundler/install/gemfile/force_ruby_platform_spec.rb
@@ -5,68 +5,77 @@ RSpec.describe "bundle install with force_ruby_platform DSL option", :jruby do
before do
build_repo4 do
# Build a gem with platform specific versions
- build_gem("platform_specific")
+ build_gem("platform_specific") do |s|
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 RUBY'"
+ end
build_gem("platform_specific") do |s|
s.platform = Bundler.local_platform
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'"
end
# Build the exact same gem with a different name to compare using vs not using the option
- build_gem("platform_specific_forced")
+ build_gem("platform_specific_forced") do |s|
+ s.write "lib/platform_specific_forced.rb", "PLATFORM_SPECIFIC_FORCED = '1.0.0 RUBY'"
+ end
build_gem("platform_specific_forced") do |s|
s.platform = Bundler.local_platform
+ s.write "lib/platform_specific_forced.rb", "PLATFORM_SPECIFIC_FORCED = '1.0.0 #{Bundler.local_platform}'"
end
end
end
it "pulls the pure ruby variant of the given gem" do
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "platform_specific_forced", :force_ruby_platform => true
gem "platform_specific"
G
- expect(the_bundle).to include_gems "platform_specific_forced 1.0 ruby"
- expect(the_bundle).to include_gems "platform_specific 1.0 #{Bundler.local_platform}"
+ expect(the_bundle).to include_gems "platform_specific_forced 1.0.0 RUBY"
+ expect(the_bundle).to include_gems "platform_specific 1.0.0 #{Bundler.local_platform}"
end
it "still respects a global `force_ruby_platform` config" do
- install_gemfile <<-G, env: { "BUNDLE_FORCE_RUBY_PLATFORM" => "true" }
- source "https://gem.repo4"
+ install_gemfile <<-G, :env => { "BUNDLE_FORCE_RUBY_PLATFORM" => "true" }
+ source "#{file_uri_for(gem_repo4)}"
gem "platform_specific_forced", :force_ruby_platform => true
gem "platform_specific"
G
- expect(the_bundle).to include_gems "platform_specific_forced 1.0 ruby"
- expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gems "platform_specific_forced 1.0.0 RUBY"
+ expect(the_bundle).to include_gems "platform_specific 1.0.0 RUBY"
end
end
context "when also a transitive dependency" do
before do
build_repo4 do
- build_gem("depends_on_platform_specific") {|s| s.add_dependency "platform_specific" }
+ build_gem("depends_on_platform_specific") {|s| s.add_runtime_dependency "platform_specific" }
- build_gem("platform_specific")
+ build_gem("platform_specific") do |s|
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 RUBY'"
+ end
build_gem("platform_specific") do |s|
s.platform = Bundler.local_platform
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'"
end
end
end
it "still pulls the ruby variant" do
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "depends_on_platform_specific"
gem "platform_specific", :force_ruby_platform => true
G
- expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gems "platform_specific 1.0.0 RUBY"
end
end
@@ -74,63 +83,36 @@ RSpec.describe "bundle install with force_ruby_platform DSL option", :jruby do
before do
build_repo4 do
build_gem("depends_on_platform_specific") do |s|
- s.add_dependency "platform_specific"
+ s.add_runtime_dependency "platform_specific"
+ s.write "lib/depends_on_platform_specific.rb", "DEPENDS_ON_PLATFORM_SPECIFIC = '1.0.0 RUBY'"
end
build_gem("depends_on_platform_specific") do |s|
- s.add_dependency "platform_specific"
+ s.add_runtime_dependency "platform_specific"
s.platform = Bundler.local_platform
+ s.write "lib/depends_on_platform_specific.rb", "DEPENDS_ON_PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'"
end
- build_gem("platform_specific")
+ build_gem("platform_specific") do |s|
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 RUBY'"
+ end
build_gem("platform_specific") do |s|
s.platform = Bundler.local_platform
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'"
end
end
end
it "ignores ruby variants for the transitive dependencies" do
- install_gemfile <<-G, env: { "DEBUG_RESOLVER" => "true" }
- source "https://gem.repo4"
+ install_gemfile <<-G, :env => { "DEBUG_RESOLVER" => "true" }
+ source "#{file_uri_for(gem_repo4)}"
gem "depends_on_platform_specific", :force_ruby_platform => true
G
- expect(the_bundle).to include_gems "depends_on_platform_specific 1.0 ruby"
- expect(the_bundle).to include_gems "platform_specific 1.0 #{Bundler.local_platform}"
- end
-
- it "reinstalls the ruby variant when a platform specific variant is already installed, the lockile has only ruby platform, and :force_ruby_platform is used in the Gemfile" do
- skip "Can't simulate platform reliably on JRuby, installing a platform specific gem fails to activate io-wait because only the -java version is present, and we're simulating a different platform" if RUBY_ENGINE == "jruby"
-
- lockfile <<-L
- GEM
- remote: https://gem.repo4
- specs:
- platform_specific (1.0)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- platform_specific
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- simulate_platform "x86-darwin-100" do
- system_gems "platform_specific-1.0-x86-darwin-100", path: default_bundle_path
-
- install_gemfile <<-G, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, artifice: "compact_index"
- source "https://gem.repo4"
-
- gem "platform_specific", :force_ruby_platform => true
- G
-
- expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
- end
+ expect(the_bundle).to include_gems "depends_on_platform_specific 1.0.0 RUBY"
+ expect(the_bundle).to include_gems "platform_specific 1.0.0 #{Bundler.local_platform}"
end
end
end
diff --git a/spec/bundler/install/gemfile/gemspec_spec.rb b/spec/bundler/install/gemfile/gemspec_spec.rb
index be0694cb55..73f04f071d 100644
--- a/spec/bundler/install/gemfile/gemspec_spec.rb
+++ b/spec/bundler/install/gemfile/gemspec_spec.rb
@@ -10,9 +10,11 @@ RSpec.describe "bundle install from an existing gemspec" do
let(:x64_mingw_archs) do
if RUBY_PLATFORM == "x64-mingw-ucrt"
-
- ["x64-mingw-ucrt", "x64-mingw32"]
-
+ if Gem.rubygems_version >= Gem::Version.new("3.2.28")
+ ["x64-mingw-ucrt", "x64-mingw32"]
+ else
+ ["x64-mingw32", "x64-unknown"]
+ end
else
["x64-mingw32"]
end
@@ -26,46 +28,36 @@ RSpec.describe "bundle install from an existing gemspec" do
x64_mingw_archs.join("\n ")
end
- def x64_mingw_checksums(checksums)
- x64_mingw_archs.each do |arch|
- if arch == "x64-mingw-ucrt"
- checksums.no_checksum "platform_specific", "1.0", arch
- else
- checksums.checksum gem_repo2, "platform_specific", "1.0", arch
- end
- end
- end
-
it "should install runtime and development dependencies" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("Gemfile", "source :rubygems\ngemspec")
s.add_dependency "bar", "=1.0.0"
s.add_development_dependency "bar-dev", "=1.0.0"
end
install_gemfile <<-G
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}'
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}'
G
expect(the_bundle).to include_gems "bar 1.0.0"
- expect(the_bundle).to include_gems "bar-dev 1.0.0", groups: :development
+ expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :development
end
it "that is hidden should install runtime and development dependencies" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("Gemfile", "source :rubygems\ngemspec")
s.add_dependency "bar", "=1.0.0"
s.add_development_dependency "bar-dev", "=1.0.0"
end
- FileUtils.mv tmp("foo", "foo.gemspec"), tmp("foo", ".gemspec")
+ FileUtils.mv tmp.join("foo", "foo.gemspec"), tmp.join("foo", ".gemspec")
install_gemfile <<-G
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}'
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}'
G
expect(the_bundle).to include_gems "bar 1.0.0"
- expect(the_bundle).to include_gems "bar-dev 1.0.0", groups: :development
+ expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :development
end
it "should handle a list of requirements" do
@@ -74,151 +66,151 @@ RSpec.describe "bundle install from an existing gemspec" do
build_gem "baz", "1.1"
end
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("Gemfile", "source :rubygems\ngemspec")
s.add_dependency "baz", ">= 1.0", "< 1.1"
end
install_gemfile <<-G
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}'
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}'
G
expect(the_bundle).to include_gems "baz 1.0"
end
it "should raise if there are no gemspecs available" do
- build_lib("foo", path: tmp("foo"), gemspec: false)
+ build_lib("foo", :path => tmp.join("foo"), :gemspec => false)
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}'
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}'
G
- expect(err).to match(/There are no gemspecs at #{tmp("foo")}/)
+ expect(err).to match(/There are no gemspecs at #{tmp.join('foo')}/)
end
it "should raise if there are too many gemspecs available" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("foo2.gemspec", build_spec("foo", "4.0").first.to_ruby)
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}'
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}'
G
- expect(err).to match(/There are multiple gemspecs at #{tmp("foo")}/)
+ expect(err).to match(/There are multiple gemspecs at #{tmp.join('foo')}/)
end
it "should pick a specific gemspec" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("foo2.gemspec", "")
s.add_dependency "bar", "=1.0.0"
s.add_development_dependency "bar-dev", "=1.0.0"
end
install_gemfile(<<-G)
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}', :name => 'foo'
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo'
G
expect(the_bundle).to include_gems "bar 1.0.0"
- expect(the_bundle).to include_gems "bar-dev 1.0.0", groups: :development
+ expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :development
end
it "should use a specific group for development dependencies" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.write("foo2.gemspec", "")
s.add_dependency "bar", "=1.0.0"
s.add_development_dependency "bar-dev", "=1.0.0"
end
install_gemfile(<<-G)
- source "https://gem.repo2"
- gemspec :path => '#{tmp("foo")}', :name => 'foo', :development_group => :dev
+ source "#{file_uri_for(gem_repo2)}"
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo', :development_group => :dev
G
expect(the_bundle).to include_gems "bar 1.0.0"
- expect(the_bundle).not_to include_gems "bar-dev 1.0.0", groups: :development
- expect(the_bundle).to include_gems "bar-dev 1.0.0", groups: :dev
+ expect(the_bundle).not_to include_gems "bar-dev 1.0.0", :groups => :development
+ expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :dev
end
it "should match a lockfile even if the gemspec defines development dependencies" do
- build_lib("foo", path: tmp("foo")) do |s|
- s.write("Gemfile", "source 'https://gem.repo1'\ngemspec")
+ build_lib("foo", :path => tmp.join("foo")) do |s|
+ s.write("Gemfile", "source '#{file_uri_for(gem_repo1)}'\ngemspec")
s.add_dependency "actionpack", "=2.3.2"
- s.add_development_dependency "rake", rake_version
+ s.add_development_dependency "rake", "=13.0.1"
end
- bundle "install", dir: tmp("foo"), artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
+ bundle "install", :dir => tmp.join("foo")
# This should really be able to rely on $stderr, but, it's not written
# right, so we can't. In fact, this is a bug negation test, and so it'll
# ghost pass in future, and will only catch a regression if the message
# doesn't change. Exit codes should be used correctly (they can be more
# than just 0 and 1).
bundle "config set --local deployment true"
- output = bundle("install", dir: tmp("foo"), artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s })
+ output = bundle("install", :dir => tmp.join("foo"))
expect(output).not_to match(/You have added to the Gemfile/)
expect(output).not_to match(/You have deleted from the Gemfile/)
expect(output).not_to match(/the lockfile can't be updated because frozen mode is set/)
end
it "should match a lockfile without needing to re-resolve" do
- build_lib("foo", path: tmp("foo")) do |s|
- s.add_dependency "myrack"
+ build_lib("foo", :path => tmp.join("foo")) do |s|
+ s.add_dependency "rack"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gemspec :path => '#{tmp("foo")}'
+ source "#{file_uri_for(gem_repo1)}"
+ gemspec :path => '#{tmp.join("foo")}'
G
- bundle "install", verbose: true
+ bundle "install", :verbose => true
message = "Found no changes, using resolution from the lockfile"
expect(out.scan(message).size).to eq(1)
end
it "should match a lockfile without needing to re-resolve with development dependencies" do
- simulate_platform java do
- build_lib("foo", path: tmp("foo")) do |s|
- s.add_dependency "myrack"
- s.add_development_dependency "thin"
- end
+ simulate_platform java
- install_gemfile <<-G
- source "https://gem.repo1"
- gemspec :path => '#{tmp("foo")}'
- G
+ build_lib("foo", :path => tmp.join("foo")) do |s|
+ s.add_dependency "rack"
+ s.add_development_dependency "thin"
+ end
- bundle "install", verbose: true
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gemspec :path => '#{tmp.join("foo")}'
+ G
- message = "Found no changes, using resolution from the lockfile"
- expect(out.scan(message).size).to eq(1)
- end
+ bundle "install", :verbose => true
+
+ message = "Found no changes, using resolution from the lockfile"
+ expect(out.scan(message).size).to eq(1)
end
it "should match a lockfile on non-ruby platforms with a transitive platform dependency", :jruby_only do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.add_dependency "platform_specific"
end
- system_gems "platform_specific-1.0-java", path: default_bundle_path
+ system_gems "platform_specific-1.0-java", :path => default_bundle_path
install_gemfile <<-G
- gemspec :path => '#{tmp("foo")}'
+ gemspec :path => '#{tmp.join("foo")}'
G
- bundle "update --bundler", artifice: "compact_index", verbose: true
- expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 java"
+ bundle "update --bundler", :artifice => "compact_index", :verbose => true
+ expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 JAVA"
end
it "should evaluate the gemspec in its directory" do
- build_lib("foo", path: tmp("foo"))
- File.open(tmp("foo/foo.gemspec"), "w") do |s|
- s.write "raise 'ahh' unless Dir.pwd == '#{tmp("foo")}'"
+ build_lib("foo", :path => tmp.join("foo"))
+ File.open(tmp.join("foo/foo.gemspec"), "w") do |s|
+ s.write "raise 'ahh' unless Dir.pwd == '#{tmp.join("foo")}'"
end
- install_gemfile <<-G, raise_on_error: false
- gemspec :path => '#{tmp("foo")}'
+ install_gemfile <<-G, :raise_on_error => false
+ gemspec :path => '#{tmp.join("foo")}'
G
expect(last_command.stdboth).not_to include("ahh")
end
@@ -229,16 +221,16 @@ RSpec.describe "bundle install from an existing gemspec" do
#
# issue was caused by rubygems having an unresolved gem during a require,
# so emulate that
- system_gems %w[myrack-1.0.0 myrack-0.9.1 myrack-obama-1.0]
+ system_gems %w[rack-1.0.0 rack-0.9.1 rack-obama-1.0]
- build_lib("foo", path: bundled_app)
+ build_lib("foo", :path => bundled_app)
gemspec = bundled_app("foo.gemspec").read
bundled_app("foo.gemspec").open("w") do |f|
- f.write "#{gemspec.strip}.tap { gem 'myrack-obama'; require 'myrack/obama' }"
+ f.write "#{gemspec.strip}.tap { gem 'rack-obama'; require 'rack/obama' }"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
@@ -246,26 +238,26 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "allows conflicts" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.version = "1.0.0"
s.add_dependency "bar", "= 1.0.0"
end
- build_gem "deps", to_bundle: true do |s|
+ build_gem "deps", :to_bundle => true do |s|
s.add_dependency "foo", "= 0.0.1"
end
- build_gem "foo", "0.0.1", to_bundle: true
+ build_gem "foo", "0.0.1", :to_bundle => true
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "deps"
- gemspec :path => '#{tmp("foo")}', :name => 'foo'
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo'
G
expect(the_bundle).to include_gems "foo 1.0.0"
end
it "does not break Gem.finish_resolve with conflicts" do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.version = "1.0.0"
s.add_dependency "bar", "= 1.0.0"
end
@@ -277,9 +269,9 @@ RSpec.describe "bundle install from an existing gemspec" do
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "deps"
- gemspec :path => '#{tmp("foo")}', :name => 'foo'
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo'
G
expect(the_bundle).to include_gems "foo 1.0.0"
@@ -289,14 +281,14 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "handles downgrades" do
- build_lib "omg", "2.0", path: lib_path("omg")
+ build_lib "omg", "2.0", :path => lib_path("omg")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec :path => "#{lib_path("omg")}"
G
- build_lib "omg", "1.0", path: lib_path("omg")
+ build_lib "omg", "1.0", :path => lib_path("omg")
bundle :install
@@ -306,23 +298,23 @@ RSpec.describe "bundle install from an existing gemspec" do
context "in deployment mode" do
context "when the lockfile was not updated after a change to the gemspec's dependencies" do
it "reports that installation failed" do
- build_lib "cocoapods", path: bundled_app do |s|
+ build_lib "cocoapods", :path => bundled_app do |s|
s.add_dependency "activesupport", ">= 1"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
expect(the_bundle).to include_gems("cocoapods 1.0", "activesupport 2.3.5")
- build_lib "cocoapods", path: bundled_app do |s|
+ build_lib "cocoapods", :path => bundled_app do |s|
s.add_dependency "activesupport", ">= 1.0.1"
end
bundle "config set --local deployment true"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include("changed")
end
@@ -332,24 +324,24 @@ RSpec.describe "bundle install from an existing gemspec" do
context "when child gemspecs conflict with a released gemspec" do
before do
# build the "parent" gem that depends on another gem in the same repo
- build_lib "source_conflict", path: bundled_app do |s|
- s.add_dependency "myrack_middleware"
+ build_lib "source_conflict", :path => bundled_app do |s|
+ s.add_dependency "rack_middleware"
end
# build the "child" gem that is the same version as a released gem, but
# has completely different and conflicting dependency requirements
- build_lib "myrack_middleware", "1.0", path: bundled_app("myrack_middleware") do |s|
- s.add_dependency "myrack", "1.0" # anything other than 0.9.1
+ build_lib "rack_middleware", "1.0", :path => bundled_app("rack_middleware") do |s|
+ s.add_dependency "rack", "1.0" # anything other than 0.9.1
end
end
it "should install the child gemspec's deps" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
@@ -357,8 +349,8 @@ RSpec.describe "bundle install from an existing gemspec" do
let(:source_uri) { "http://localgemserver.test" }
before do
- build_lib("foo", path: tmp("foo")) do |s|
- s.add_dependency "myrack", "=1.0.0"
+ build_lib("foo", :path => tmp.join("foo")) do |s|
+ s.add_dependency "rack", "=1.0.0"
end
gemfile <<-G
@@ -366,28 +358,24 @@ RSpec.describe "bundle install from an existing gemspec" do
gemspec :path => "../foo"
G
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- end
-
lockfile <<-L
PATH
remote: ../foo
specs:
foo (1.0)
- myrack (= 1.0.0)
+ rack (= 1.0.0)
GEM
remote: #{source_uri}
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{generic_local_platform}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -396,9 +384,9 @@ RSpec.describe "bundle install from an existing gemspec" do
context "using JRuby with explicit platform", :jruby_only do
before do
create_file(
- tmp("foo", "foo-java.gemspec"),
+ tmp.join("foo", "foo-java.gemspec"),
build_spec("foo", "1.0", "java") do
- dep "myrack", "=1.0.0"
+ dep "rack", "=1.0.0"
@spec.authors = "authors"
@spec.summary = "summary"
end.first.to_ruby
@@ -406,16 +394,16 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "should install" do
- results = bundle "install", artifice: "endpoint"
- expect(results).to include("Installing myrack 1.0.0")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ results = bundle "install", :artifice => "endpoint"
+ expect(results).to include("Installing rack 1.0.0")
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
it "should install", :jruby do
- results = bundle "install", artifice: "endpoint"
- expect(results).to include("Installing myrack 1.0.0")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ results = bundle "install", :artifice => "endpoint"
+ expect(results).to include("Installing rack 1.0.0")
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
context "bundled for multiple platforms" do
@@ -428,7 +416,7 @@ RSpec.describe "bundle install from an existing gemspec" do
end
end
- build_lib "foo", path: bundled_app do |s|
+ build_lib "foo", :path => bundled_app do |s|
if platform_specific_type == :runtime
s.add_runtime_dependency dependency
elsif platform_specific_type == :development
@@ -439,7 +427,7 @@ RSpec.describe "bundle install from an existing gemspec" do
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gemspec
G
@@ -459,16 +447,8 @@ RSpec.describe "bundle install from an existing gemspec" do
context "as a runtime dependency" do
it "keeps all platform dependencies in the lockfile" do
- expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 ruby"
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo2, "platform_specific", "1.0"
- c.checksum gem_repo2, "platform_specific", "1.0", "java"
- x64_mingw_checksums(c)
- end
-
- expect(lockfile).to eq <<~L
+ expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY"
+ expect(lockfile).to eq strip_whitespace(<<-L)
PATH
remote: .
specs:
@@ -476,7 +456,7 @@ RSpec.describe "bundle install from an existing gemspec" do
platform_specific
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
platform_specific (1.0)
platform_specific (1.0-java)
@@ -489,7 +469,7 @@ RSpec.describe "bundle install from an existing gemspec" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -500,23 +480,15 @@ RSpec.describe "bundle install from an existing gemspec" do
let(:platform_specific_type) { :development }
it "keeps all platform dependencies in the lockfile" do
- expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 ruby"
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo2, "platform_specific", "1.0"
- c.checksum gem_repo2, "platform_specific", "1.0", "java"
- x64_mingw_checksums(c)
- end
-
- expect(lockfile).to eq <<~L
+ expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY"
+ expect(lockfile).to eq strip_whitespace(<<-L)
PATH
remote: .
specs:
foo (1.0)
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
platform_specific (1.0)
platform_specific (1.0-java)
@@ -530,7 +502,7 @@ RSpec.describe "bundle install from an existing gemspec" do
DEPENDENCIES
foo!
platform_specific
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -542,24 +514,15 @@ RSpec.describe "bundle install from an existing gemspec" do
let(:dependency) { "indirect_platform_specific" }
it "keeps all platform dependencies in the lockfile" do
- expect(the_bundle).to include_gems "foo 1.0", "indirect_platform_specific 1.0", "platform_specific 1.0 ruby"
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo2, "indirect_platform_specific", "1.0"
- c.checksum gem_repo2, "platform_specific", "1.0"
- c.checksum gem_repo2, "platform_specific", "1.0", "java"
- x64_mingw_checksums(c)
- end
-
- expect(lockfile).to eq <<~L
+ expect(the_bundle).to include_gems "foo 1.0", "indirect_platform_specific 1.0", "platform_specific 1.0 RUBY"
+ expect(lockfile).to eq strip_whitespace(<<-L)
PATH
remote: .
specs:
foo (1.0)
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
indirect_platform_specific (1.0)
platform_specific
@@ -575,7 +538,7 @@ RSpec.describe "bundle install from an existing gemspec" do
DEPENDENCIES
foo!
indirect_platform_specific
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -587,10 +550,10 @@ RSpec.describe "bundle install from an existing gemspec" do
context "with multiple platforms" do
before do
- build_lib("foo", path: tmp("foo")) do |s|
+ build_lib("foo", :path => tmp.join("foo")) do |s|
s.version = "1.0.0"
- s.add_development_dependency "myrack"
- s.write "foo-universal-java.gemspec", build_spec("foo", "1.0.0", "universal-java") {|sj| sj.runtime "myrack", "1.0.0" }.first.to_ruby
+ s.add_development_dependency "rack"
+ s.write "foo-universal-java.gemspec", build_spec("foo", "1.0.0", "universal-java") {|sj| sj.runtime "rack", "1.0.0" }.first.to_ruby
end
end
@@ -598,11 +561,11 @@ RSpec.describe "bundle install from an existing gemspec" do
bundle "config set --local force_ruby_platform true"
install_gemfile <<-G
- source "https://gem.repo1"
- gemspec :path => '#{tmp("foo")}', :name => 'foo'
+ source "#{file_uri_for(gem_repo1)}"
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo'
G
- expect(the_bundle).to include_gems "foo 1.0.0", "myrack 1.0.0"
+ expect(the_bundle).to include_gems "foo 1.0.0", "rack 1.0.0"
end
it "installs the ruby platform gemspec and skips dev deps with `without development` configured" do
@@ -610,18 +573,18 @@ RSpec.describe "bundle install from an existing gemspec" do
bundle "config set --local without development"
install_gemfile <<-G
- source "https://gem.repo1"
- gemspec :path => '#{tmp("foo")}', :name => 'foo'
+ source "#{file_uri_for(gem_repo1)}"
+ gemspec :path => '#{tmp.join("foo")}', :name => 'foo'
G
expect(the_bundle).to include_gem "foo 1.0.0"
- expect(the_bundle).not_to include_gem "myrack"
+ expect(the_bundle).not_to include_gem "rack"
end
end
context "with multiple platforms and resolving for more specific platforms" do
before do
- build_lib("chef", path: tmp("chef")) do |s|
+ build_lib("chef", :path => tmp.join("chef")) do |s|
s.version = "17.1.17"
s.write "chef-universal-mingw32.gemspec", build_spec("chef", "17.1.17", "universal-mingw32") {|sw| sw.runtime "win32-api", "~> 1.5.3" }.first.to_ruby
end
@@ -635,16 +598,10 @@ RSpec.describe "bundle install from an existing gemspec" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gemspec :path => "../chef"
G
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "chef", "17.1.17"
- c.no_checksum "chef", "17.1.17", "universal-mingw32"
- c.checksum gem_repo4, "win32-api", "1.5.3", "universal-mingw32"
- end
-
initial_lockfile = <<~L
PATH
remote: ../chef
@@ -654,7 +611,7 @@ RSpec.describe "bundle install from an existing gemspec" do
win32-api (~> 1.5.3)
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
win32-api (1.5.3-universal-mingw32)
@@ -665,7 +622,7 @@ RSpec.describe "bundle install from an existing gemspec" do
DEPENDENCIES
chef!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -680,7 +637,7 @@ RSpec.describe "bundle install from an existing gemspec" do
context "with multiple locked platforms" do
before do
- build_lib("activeadmin", path: tmp("activeadmin")) do |s|
+ build_lib("activeadmin", :path => tmp.join("activeadmin")) do |s|
s.version = "2.9.0"
s.add_dependency "railties", ">= 5.2", "< 6.2"
end
@@ -694,7 +651,7 @@ RSpec.describe "bundle install from an existing gemspec" do
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gemspec :path => "../activeadmin"
gem "jruby-openssl", :platform => :jruby
G
@@ -703,12 +660,6 @@ RSpec.describe "bundle install from an existing gemspec" do
end
it "does not remove the platform specific specs from the lockfile when re-resolving due to gemspec changes" do
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "activeadmin", "2.9.0"
- c.checksum gem_repo4, "jruby-openssl", "0.10.7", "java"
- c.checksum gem_repo4, "railties", "6.1.4"
- end
-
expect(lockfile).to eq <<~L
PATH
remote: ../activeadmin
@@ -717,7 +668,7 @@ RSpec.describe "bundle install from an existing gemspec" do
railties (>= 5.2, < 6.2)
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
jruby-openssl (0.10.7-java)
railties (6.1.4)
@@ -728,12 +679,12 @@ RSpec.describe "bundle install from an existing gemspec" do
DEPENDENCIES
activeadmin!
jruby-openssl
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
- gemspec = tmp("activeadmin/activeadmin.gemspec")
+ gemspec = tmp.join("activeadmin/activeadmin.gemspec")
File.write(gemspec, File.read(gemspec).sub(">= 5.2", ">= 6.0"))
previous_lockfile = lockfile
diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb
index 83b3c06cbe..910f96f4ab 100644
--- a/spec/bundler/install/gemfile/git_spec.rb
+++ b/spec/bundler/install/gemfile/git_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe "bundle install with git sources" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
end
@@ -26,12 +26,12 @@ RSpec.describe "bundle install with git sources" do
expect(out).to eq("WIN")
end
- it "caches the git repo", bundler: "< 3" do
- expect(Dir["#{default_bundle_path}/cache/bundler/git/foo-1.0-*"]).to have_attributes size: 1
+ it "caches the git repo", :bundler => "< 3" do
+ expect(Dir["#{default_bundle_path}/cache/bundler/git/foo-1.0-*"]).to have_attributes :size => 1
end
it "does not write to cache on bundler/setup" do
- cache_path = default_bundle_path("cache")
+ cache_path = default_bundle_path.join("cache")
FileUtils.rm_rf(cache_path)
ruby "require 'bundler/setup'"
expect(cache_path).not_to exist
@@ -41,7 +41,7 @@ RSpec.describe "bundle install with git sources" do
simulate_new_machine
bundle "config set global_gem_cache true"
bundle :install
- expect(Dir["#{home}/.bundle/cache/git/foo-1.0-*"]).to have_attributes size: 1
+ expect(Dir["#{home}/.bundle/cache/git/foo-1.0-*"]).to have_attributes :size => 1
bundle "install --verbose"
expect(err).to be_empty
@@ -59,7 +59,7 @@ RSpec.describe "bundle install with git sources" do
bundle "update foo"
sha = git.ref_for("main", 11)
- spec_file = default_bundle_path("bundler/gems/foo-1.0-#{sha}/foo.gemspec")
+ spec_file = default_bundle_path.join("bundler/gems/foo-1.0-#{sha}/foo.gemspec")
expect(spec_file).to exist
ruby_code = Gem::Specification.load(spec_file.to_s).to_ruby
file_code = File.read(spec_file)
@@ -69,8 +69,8 @@ RSpec.describe "bundle install with git sources" do
it "does not update the git source implicitly" do
update_git "foo"
- install_gemfile bundled_app2("Gemfile"), <<-G, dir: bundled_app2
- source "https://gem.repo1"
+ install_gemfile bundled_app2("Gemfile"), <<-G, :dir => bundled_app2
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
end
@@ -92,8 +92,8 @@ RSpec.describe "bundle install with git sources" do
it "complains if pinned specs don't exist in the git repo" do
build_git "foo"
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.1", :git => "#{lib_path("foo-1.0")}"
G
@@ -105,8 +105,8 @@ RSpec.describe "bundle install with git sources" do
s.platform = "java"
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
platforms :jruby do
gem "only_java", "1.2", :git => "#{lib_path("only_java-1.0-java")}"
end
@@ -125,8 +125,8 @@ RSpec.describe "bundle install with git sources" do
s.write "only_java1-0.gemspec", File.read("#{lib_path("only_java-1.0-java")}/only_java.gemspec")
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
platforms :jruby do
gem "only_java", "1.2", :git => "#{lib_path("only_java-1.1-java")}"
end
@@ -141,7 +141,7 @@ RSpec.describe "bundle install with git sources" do
FileUtils.mv bundled_app, tmp("bundled_app.bck")
- expect(the_bundle).to include_gems "foo 1.0", dir: tmp("bundled_app.bck")
+ expect(the_bundle).to include_gems "foo 1.0", :dir => tmp("bundled_app.bck")
end
it "can still install after moving the application directory" do
@@ -150,20 +150,20 @@ RSpec.describe "bundle install with git sources" do
FileUtils.mv bundled_app, tmp("bundled_app.bck")
- update_git "foo", "1.1", path: lib_path("foo-1.0")
+ update_git "foo", "1.1", :path => lib_path("foo-1.0")
gemfile tmp("bundled_app.bck/Gemfile"), <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
end
- gem "myrack", "1.0"
+ gem "rack", "1.0"
G
- bundle "update foo", dir: tmp("bundled_app.bck")
+ bundle "update foo", :dir => tmp("bundled_app.bck")
- expect(the_bundle).to include_gems "foo 1.1", "myrack 1.0", dir: tmp("bundled_app.bck")
+ expect(the_bundle).to include_gems "foo 1.1", "rack 1.0", :dir => tmp("bundled_app.bck")
end
end
@@ -171,8 +171,8 @@ RSpec.describe "bundle install with git sources" do
before do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
git "#{lib_path("foo-1.0")}" do
# this page left intentionally blank
@@ -182,7 +182,7 @@ RSpec.describe "bundle install with git sources" do
it "does not explode" do
bundle "install"
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
@@ -195,7 +195,7 @@ RSpec.describe "bundle install with git sources" do
it "works" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}", :ref => "#{@revision}" do
gem "foo"
end
@@ -212,7 +212,7 @@ RSpec.describe "bundle install with git sources" do
it "works when the revision is a symbol" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}", :ref => #{@revision.to_sym.inspect} do
gem "foo"
end
@@ -229,14 +229,14 @@ RSpec.describe "bundle install with git sources" do
it "works when an abbreviated revision is added after an initial, potentially shallow clone" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem "foo"
end
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}", :ref => #{@revision[0..7].inspect} do
gem "foo"
end
@@ -245,21 +245,21 @@ RSpec.describe "bundle install with git sources" do
it "works when a tag that does not look like a commit hash is used as the value of :ref" do
build_git "foo"
- @remote = build_git("bar", bare: true)
- update_git "foo", remote: @remote.path
- update_git "foo", push: "main"
+ @remote = build_git("bar", :bare => true)
+ update_git "foo", :remote => file_uri_for(@remote.path)
+ update_git "foo", :push => "main"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{@remote.path}"
G
# Create a new tag on the remote that needs fetching
- update_git "foo", tag: "v1.0.0"
- update_git "foo", push: "v1.0.0"
+ update_git "foo", :tag => "v1.0.0"
+ update_git "foo", :push => "v1.0.0"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{@remote.path}", :ref => "v1.0.0"
G
@@ -268,19 +268,19 @@ RSpec.describe "bundle install with git sources" do
it "works when the revision is a non-head ref" do
# want to ensure we don't fallback to main
- update_git "foo", path: lib_path("foo-1.0") do |s|
+ update_git "foo", :path => lib_path("foo-1.0") do |s|
s.write("lib/foo.rb", "raise 'FAIL'")
end
- git("update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", lib_path("foo-1.0"))
+ sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", :dir => lib_path("foo-1.0"))
# want to ensure we don't fallback to HEAD
- update_git "foo", path: lib_path("foo-1.0"), branch: "rando" do |s|
+ update_git "foo", :path => lib_path("foo-1.0"), :branch => "rando" do |s|
s.write("lib/foo.rb", "raise 'FAIL_FROM_RANDO'")
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}", :ref => "refs/bundler/1" do
gem "foo"
end
@@ -297,26 +297,26 @@ RSpec.describe "bundle install with git sources" do
it "works when the revision is a non-head ref and it was previously downloaded" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem "foo"
end
G
# want to ensure we don't fallback to main
- update_git "foo", path: lib_path("foo-1.0") do |s|
+ update_git "foo", :path => lib_path("foo-1.0") do |s|
s.write("lib/foo.rb", "raise 'FAIL'")
end
- git("update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", lib_path("foo-1.0"))
+ sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", :dir => lib_path("foo-1.0"))
# want to ensure we don't fallback to HEAD
- update_git "foo", path: lib_path("foo-1.0"), branch: "rando" do |s|
+ update_git "foo", :path => lib_path("foo-1.0"), :branch => "rando" do |s|
s.write("lib/foo.rb", "raise 'FAIL_FROM_RANDO'")
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}", :ref => "refs/bundler/1" do
gem "foo"
end
@@ -332,21 +332,21 @@ RSpec.describe "bundle install with git sources" do
end
it "does not download random non-head refs" do
- git("update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", lib_path("foo-1.0"))
+ sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", :dir => lib_path("foo-1.0"))
bundle "config set global_gem_cache true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem "foo"
end
G
# ensure we also git fetch after cloning
- bundle :update, all: true
+ bundle :update, :all => true
- git("ls-remote .", Dir[home(".bundle/cache/git/foo-*")].first)
+ sys_exec("git ls-remote .", :dir => Dir[home(".bundle/cache/git/foo-*")].first)
expect(out).not_to include("refs/bundler/1")
end
@@ -357,10 +357,10 @@ RSpec.describe "bundle install with git sources" do
let(:repo) { build_git("foo").path }
it "works" do
- update_git("foo", path: repo, branch: branch)
+ update_git("foo", :path => repo, :branch => branch)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{repo}", :branch => #{branch.dump} do
gem "foo"
end
@@ -374,10 +374,10 @@ RSpec.describe "bundle install with git sources" do
it "works" do
skip "git does not accept this" if Gem.win_platform?
- update_git("foo", path: repo, branch: branch)
+ update_git("foo", :path => repo, :branch => branch)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{repo}", :branch => #{branch.dump} do
gem "foo"
end
@@ -392,10 +392,10 @@ RSpec.describe "bundle install with git sources" do
it "works" do
skip "git does not accept this" if Gem.win_platform?
- update_git("foo", path: repo, branch: branch)
+ update_git("foo", :path => repo, :branch => branch)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{repo}", :branch => #{branch.dump} do
gem "foo"
end
@@ -411,10 +411,10 @@ RSpec.describe "bundle install with git sources" do
let(:repo) { build_git("foo").path }
it "works" do
- update_git("foo", path: repo, tag: tag)
+ update_git("foo", :path => repo, :tag => tag)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{repo}", :tag => #{tag.dump} do
gem "foo"
end
@@ -428,10 +428,10 @@ RSpec.describe "bundle install with git sources" do
it "works" do
skip "git does not accept this" if Gem.win_platform?
- update_git("foo", path: repo, tag: tag)
+ update_git("foo", :path => repo, :tag => tag)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{repo}", :tag => #{tag.dump} do
gem "foo"
end
@@ -446,10 +446,10 @@ RSpec.describe "bundle install with git sources" do
it "works" do
skip "git does not accept this" if Gem.win_platform?
- update_git("foo", path: repo, tag: tag)
+ update_git("foo", :path => repo, :tag => tag)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{repo}", :tag => #{tag.dump} do
gem "foo"
end
@@ -462,100 +462,100 @@ RSpec.describe "bundle install with git sources" do
describe "when specifying local override" do
it "uses the local repository instead of checking a new one out" do
- build_git "myrack", "0.8", path: lib_path("local-myrack") do |s|
- s.write "lib/myrack.rb", "puts :LOCAL"
+ build_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
end
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
- run "require 'myrack'"
+ run "require 'rack'"
expect(out).to eq("LOCAL")
end
it "chooses the local repository on runtime" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
- update_git "myrack", "0.8", path: lib_path("local-myrack") do |s|
- s.write "lib/myrack.rb", "puts :LOCAL"
+ update_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- run "require 'myrack'"
+ bundle %(config set local.rack #{lib_path("local-rack")})
+ run "require 'rack'"
expect(out).to eq("LOCAL")
end
it "unlocks the source when the dependencies have changed while switching to the local" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
- update_git "myrack", "0.8", path: lib_path("local-myrack") do |s|
- s.write "myrack.gemspec", build_spec("myrack", "0.8") { runtime "rspec", "> 0" }.first.to_ruby
- s.write "lib/myrack.rb", "puts :LOCAL"
+ update_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ s.write "rack.gemspec", build_spec("rack", "0.8") { runtime "rspec", "> 0" }.first.to_ruby
+ s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
- run "require 'myrack'"
+ run "require 'rack'"
expect(out).to eq("LOCAL")
end
it "updates specs on runtime" do
system_gems "nokogiri-1.4.2"
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
lockfile0 = File.read(bundled_app_lock)
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
- update_git "myrack", "0.8", path: lib_path("local-myrack") do |s|
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
+ update_git "rack", "0.8", :path => lib_path("local-rack") do |s|
s.add_dependency "nokogiri", "1.4.2"
end
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- run "require 'myrack'"
+ bundle %(config set local.rack #{lib_path("local-rack")})
+ run "require 'rack'"
lockfile1 = File.read(bundled_app_lock)
expect(lockfile1).not_to eq(lockfile0)
end
it "updates ref on install" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
lockfile0 = File.read(bundled_app_lock)
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
- update_git "myrack", "0.8", path: lib_path("local-myrack")
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
+ update_git "rack", "0.8", :path => lib_path("local-rack")
- bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
lockfile1 = File.read(bundled_app_lock)
@@ -563,18 +563,18 @@ RSpec.describe "bundle install with git sources" do
end
it "explodes and gives correct solution if given path does not exist on install" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- bundle :install, raise_on_error: false
- expect(err).to match(/Cannot use local override for myrack-0.8 because #{Regexp.escape(lib_path("local-myrack").to_s)} does not exist/)
+ bundle %(config set local.rack #{lib_path("local-rack")})
+ bundle :install, :raise_on_error => false
+ expect(err).to match(/Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path('local-rack').to_s)} does not exist/)
- solution = "config unset local.myrack"
+ solution = "config unset local.rack"
expect(err).to match(/Run `bundle #{solution}` to remove the local override/)
bundle solution
@@ -584,19 +584,19 @@ RSpec.describe "bundle install with git sources" do
end
it "explodes and gives correct solution if branch is not given on install" do
- build_git "myrack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ build_git "rack", "0.8"
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- bundle :install, raise_on_error: false
- expect(err).to match(/Cannot use local override for myrack-0.8 at #{Regexp.escape(lib_path("local-myrack").to_s)} because :branch is not specified in Gemfile/)
+ bundle %(config set local.rack #{lib_path("local-rack")})
+ bundle :install, :raise_on_error => false
+ expect(err).to match(/Cannot use local override for rack-0.8 at #{Regexp.escape(lib_path('local-rack').to_s)} because :branch is not specified in Gemfile/)
- solution = "config unset local.myrack"
+ solution = "config unset local.rack"
expect(err).to match(/Specify a branch or run `bundle #{solution}` to remove the local override/)
bundle solution
@@ -606,69 +606,69 @@ RSpec.describe "bundle install with git sources" do
end
it "does not explode if disable_local_branch_check is given" do
- build_git "myrack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ build_git "rack", "0.8"
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle %(config set local.rack #{lib_path("local-rack")})
bundle %(config set disable_local_branch_check true)
bundle :install
expect(out).to match(/Bundle complete!/)
end
it "explodes on different branches on install" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
- update_git "myrack", "0.8", path: lib_path("local-myrack"), branch: "another" do |s|
- s.write "lib/myrack.rb", "puts :LOCAL"
+ update_git "rack", "0.8", :path => lib_path("local-rack"), :branch => "another" do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- bundle :install, raise_on_error: false
+ bundle %(config set local.rack #{lib_path("local-rack")})
+ bundle :install, :raise_on_error => false
expect(err).to match(/is using branch another but Gemfile specifies main/)
end
it "explodes on invalid revision on install" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- build_git "myrack", "0.8", path: lib_path("local-myrack") do |s|
- s.write "lib/myrack.rb", "puts :LOCAL"
+ build_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- bundle :install, raise_on_error: false
+ bundle %(config set local.rack #{lib_path("local-rack")})
+ bundle :install, :raise_on_error => false
expect(err).to match(/The Gemfile lock is pointing to revision \w+/)
end
it "does not explode on invalid revision on install" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- build_git "myrack", "0.8", path: lib_path("local-myrack") do |s|
- s.write "lib/myrack.rb", "puts :LOCAL"
+ build_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle %(config set local.rack #{lib_path("local-rack")})
bundle %(config set disable_local_revision_check true)
bundle :install
expect(out).to match(/Bundle complete!/)
@@ -693,76 +693,76 @@ RSpec.describe "bundle install with git sources" do
# end
it "installs from git even if a newer gem is available elsewhere" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}"
G
- expect(the_bundle).to include_gems "myrack 0.8"
+ expect(the_bundle).to include_gems "rack 0.8"
end
it "installs dependencies from git even if a newer gem is available elsewhere" do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
- build_lib "myrack", "1.0", path: lib_path("nested/bar") do |s|
- s.write "lib/myrack.rb", "puts 'WIN OVERRIDE'"
+ build_lib "rack", "1.0", :path => lib_path("nested/bar") do |s|
+ s.write "lib/rack.rb", "puts 'WIN OVERRIDE'"
end
- build_git "foo", path: lib_path("nested") do |s|
- s.add_dependency "myrack", "= 1.0"
+ build_git "foo", :path => lib_path("nested") do |s|
+ s.add_dependency "rack", "= 1.0"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("nested")}"
G
- run "require 'myrack'"
+ run "require 'rack'"
expect(out).to eq("WIN OVERRIDE")
end
it "correctly unlocks when changing to a git source" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
- build_git "myrack", path: lib_path("myrack")
+ build_git "rack", :path => lib_path("rack")
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0", :git => "#{lib_path("myrack")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0", :git => "#{lib_path("rack")}"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "correctly unlocks when changing to a git source without versions" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- build_git "myrack", "1.2", path: lib_path("myrack")
+ build_git "rack", "1.2", :path => lib_path("rack")
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack")}"
G
- expect(the_bundle).to include_gems "myrack 1.2"
+ expect(the_bundle).to include_gems "rack 1.2"
end
end
describe "block syntax" do
it "pulls all gems from a git block" do
- build_lib "omg", path: lib_path("hi2u/omg")
- build_lib "hi2u", path: lib_path("hi2u")
+ build_lib "omg", :path => lib_path("hi2u/omg")
+ build_lib "hi2u", :path => lib_path("hi2u")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path("hi2u")}" do
gem "omg"
gem "hi2u"
@@ -779,7 +779,7 @@ RSpec.describe "bundle install with git sources" do
update_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :ref => "#{@revision}"
G
@@ -797,7 +797,7 @@ RSpec.describe "bundle install with git sources" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
gem "rails", "2.3.2"
G
@@ -807,7 +807,7 @@ RSpec.describe "bundle install with git sources" do
end
it "runs the gemspec in the context of its parent directory" do
- build_lib "bar", path: lib_path("foo/bar"), gemspec: false do |s|
+ build_lib "bar", :path => lib_path("foo/bar"), :gemspec => false do |s|
s.write lib_path("foo/bar/lib/version.rb"), %(BAR_VERSION = '1.0')
s.write "bar.gemspec", <<-G
$:.unshift Dir.pwd
@@ -822,12 +822,12 @@ RSpec.describe "bundle install with git sources" do
G
end
- build_git "foo", path: lib_path("foo") do |s|
+ build_git "foo", :path => lib_path("foo") do |s|
s.write "bin/foo", ""
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :git => "#{lib_path("foo")}"
gem "rails", "2.3.2"
G
@@ -836,41 +836,15 @@ RSpec.describe "bundle install with git sources" do
expect(the_bundle).to include_gems "rails 2.3.2"
end
- it "runs the gemspec in the context of its parent directory, when using local overrides" do
- build_git "foo", path: lib_path("foo"), gemspec: false do |s|
- s.write lib_path("foo/lib/foo/version.rb"), %(FOO_VERSION = '1.0')
- s.write "foo.gemspec", <<-G
- $:.unshift Dir.pwd
- require 'lib/foo/version'
- Gem::Specification.new do |s|
- s.name = 'foo'
- s.author = 'no one'
- s.version = FOO_VERSION
- s.summary = 'Foo'
- s.files = Dir["lib/**/*.rb"]
- end
- G
- end
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => "https://github.com/gems/foo", branch: "main"
- G
-
- bundle %(config set local.foo #{lib_path("foo")})
-
- expect(the_bundle).to include_gems "foo 1.0"
- end
-
it "installs from git even if a rubygems gem is present" do
- build_gem "foo", "1.0", path: lib_path("fake_foo"), to_system: true do |s|
+ build_gem "foo", "1.0", :path => lib_path("fake_foo"), :to_system => true do |s|
s.write "lib/foo.rb", "raise 'FAIL'"
end
build_git "foo", "1.0"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0", :git => "#{lib_path("foo-1.0")}"
G
@@ -878,10 +852,10 @@ RSpec.describe "bundle install with git sources" do
end
it "fakes the gem out if there is no gemspec" do
- build_git "foo", gemspec: false
+ build_git "foo", :gemspec => false
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0", :git => "#{lib_path("foo-1.0")}"
gem "rails", "2.3.2"
G
@@ -892,11 +866,11 @@ RSpec.describe "bundle install with git sources" do
it "catches git errors and spits out useful output" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0", :git => "omgomg"
G
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include("Git error:")
expect(err).to include("fatal")
@@ -904,10 +878,10 @@ RSpec.describe "bundle install with git sources" do
end
it "works when the gem path has spaces in it" do
- build_git "foo", path: lib_path("foo space-1.0")
+ build_git "foo", :path => lib_path("foo space-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo space-1.0")}"
G
@@ -918,7 +892,7 @@ RSpec.describe "bundle install with git sources" do
build_git "forced", "1.0"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("forced-1.0")}" do
gem 'forced'
end
@@ -929,12 +903,12 @@ RSpec.describe "bundle install with git sources" do
s.write "lib/forced.rb", "FORCED = '1.1'"
end
- bundle "update", all: true
+ bundle "update", :all => true
expect(the_bundle).to include_gems "forced 1.1"
- git("reset --hard HEAD^", lib_path("forced-1.0"))
+ sys_exec("git reset --hard HEAD^", :dir => lib_path("forced-1.0"))
- bundle "update", all: true
+ bundle "update", :all => true
expect(the_bundle).to include_gems "forced 1.0"
end
@@ -946,16 +920,16 @@ RSpec.describe "bundle install with git sources" do
build_git "has_submodule", "1.0" do |s|
s.add_dependency "submodule"
end
- git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0")
- git "commit -m \"submodulator\"", lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("has_submodule-1.0")}" do
gem "has_submodule"
end
G
- expect(err).to match(%r{submodule >= 0 could not be found in rubygems repository https://gem.repo1/ or installed locally})
+ expect(err).to match(%r{submodule >= 0 could not be found in rubygems repository #{file_uri_for(gem_repo1)}/ or installed locally})
expect(the_bundle).not_to include_gems "has_submodule 1.0"
end
@@ -968,11 +942,11 @@ RSpec.describe "bundle install with git sources" do
build_git "has_submodule", "1.0" do |s|
s.add_dependency "submodule"
end
- git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0")
- git "commit -m \"submodulator\"", lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("has_submodule-1.0")}", :submodules => true do
gem "has_submodule"
end
@@ -988,11 +962,11 @@ RSpec.describe "bundle install with git sources" do
build_git "submodule", "1.0"
build_git "has_submodule", "1.0"
- git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0")
- git "commit -m \"submodulator\"", lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("has_submodule-1.0")}" do
gem "has_submodule"
end
@@ -1007,7 +981,7 @@ RSpec.describe "bundle install with git sources" do
git = build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem "foo"
end
@@ -1017,7 +991,7 @@ RSpec.describe "bundle install with git sources" do
update_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}", :ref => "#{git.ref_for("HEAD^")}" do
gem "foo"
end
@@ -1035,7 +1009,7 @@ RSpec.describe "bundle install with git sources" do
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1049,7 +1023,7 @@ RSpec.describe "bundle install with git sources" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1063,8 +1037,8 @@ RSpec.describe "bundle install with git sources" do
FileUtils.mkdir_p(default_bundle_path)
FileUtils.touch(default_bundle_path("bundler"))
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1075,14 +1049,14 @@ RSpec.describe "bundle install with git sources" do
end
it "does not duplicate git gem sources" do
- build_lib "foo", path: lib_path("nested/foo")
- build_lib "bar", path: lib_path("nested/bar")
+ build_lib "foo", :path => lib_path("nested/foo")
+ build_lib "bar", :path => lib_path("nested/bar")
- build_git "foo", path: lib_path("nested")
- build_git "bar", path: lib_path("nested")
+ build_git "foo", :path => lib_path("nested")
+ build_git "bar", :path => lib_path("nested")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("nested")}"
gem "bar", :git => "#{lib_path("nested")}"
G
@@ -1092,21 +1066,21 @@ RSpec.describe "bundle install with git sources" do
describe "switching sources" do
it "doesn't explode when switching Path to Git sources" do
- build_gem "foo", "1.0", to_system: true do |s|
+ build_gem "foo", "1.0", :to_system => true do |s|
s.write "lib/foo.rb", "raise 'fail'"
end
- build_lib "foo", "1.0", path: lib_path("bar/foo")
- build_git "bar", "1.0", path: lib_path("bar") do |s|
+ build_lib "foo", "1.0", :path => lib_path("bar/foo")
+ build_git "bar", "1.0", :path => lib_path("bar") do |s|
s.add_dependency "foo"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :path => "#{lib_path("bar")}"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :git => "#{lib_path("bar")}"
G
@@ -1115,43 +1089,24 @@ RSpec.describe "bundle install with git sources" do
it "doesn't explode when switching Gem to Git source" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack-obama"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack-obama"
+ gem "rack", "1.0.0"
G
- build_git "myrack", "1.0" do |s|
+ build_git "rack", "1.0" do |s|
s.write "lib/new_file.rb", "puts 'USING GIT'"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack-obama"
- gem "myrack", "1.0.0", :git => "#{lib_path("myrack-1.0")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack-obama"
+ gem "rack", "1.0.0", :git => "#{lib_path("rack-1.0")}"
G
run "require 'new_file'"
expect(out).to eq("USING GIT")
end
-
- it "doesn't explode when removing an explicit exact version from a git gem with dependencies" do
- build_lib "activesupport", "7.1.4", path: lib_path("rails/activesupport")
- build_git "rails", "7.1.4", path: lib_path("rails") do |s|
- s.add_dependency "activesupport", "= 7.1.4"
- end
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "rails", "7.1.4", :git => "#{lib_path("rails")}"
- G
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "rails", :git => "#{lib_path("rails")}"
- G
-
- expect(the_bundle).to include_gem "rails 7.1.4", "activesupport 7.1.4"
- end
end
describe "bundle install after the remote has been updated" do
@@ -1159,8 +1114,8 @@ RSpec.describe "bundle install with git sources" do
build_git "valim"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "valim", :git => "#{lib_path("valim-1.0")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "valim", :git => "#{file_uri_for(lib_path("valim-1.0"))}"
G
old_revision = revision_for(lib_path("valim-1.0"))
@@ -1185,14 +1140,14 @@ RSpec.describe "bundle install with git sources" do
revision = revision_for(lib_path("foo-1.0"))
install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo-1.0")}", :ref => "#{revision}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}", :ref => "#{revision}"
G
expect(out).to_not match(/Revision.*does not exist/)
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo-1.0")}", :ref => "deadbeef"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}", :ref => "deadbeef"
G
expect(err).to include("Revision deadbeef does not exist in the repository")
end
@@ -1200,9 +1155,9 @@ RSpec.describe "bundle install with git sources" do
it "gives a helpful error message when the remote branch no longer exists" do
build_git "foo"
- install_gemfile <<-G, env: { "LANG" => "en" }, raise_on_error: false
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo-1.0")}", :branch => "deadbeef"
+ install_gemfile <<-G, :env => { "LANG" => "en" }, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}", :branch => "deadbeef"
G
expect(err).to include("Revision deadbeef does not exist in the repository")
@@ -1211,10 +1166,10 @@ RSpec.describe "bundle install with git sources" do
describe "bundle install with deployment mode configured and git sources" do
it "works" do
- build_git "valim", path: lib_path("valim")
+ build_git "valim", :path => lib_path("valim")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "valim", "= 1.0", :git => "#{lib_path("valim")}"
G
@@ -1229,7 +1184,7 @@ RSpec.describe "bundle install with git sources" do
it "runs pre-install hooks" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1242,14 +1197,14 @@ RSpec.describe "bundle install with git sources" do
end
bundle :install,
- requires: [lib_path("install_hooks.rb")]
+ :requires => [lib_path("install_hooks.rb")]
expect(err_without_deprecations).to eq("Ran pre-install hook: foo-1.0")
end
it "runs post-install hooks" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1262,14 +1217,14 @@ RSpec.describe "bundle install with git sources" do
end
bundle :install,
- requires: [lib_path("install_hooks.rb")]
+ :requires => [lib_path("install_hooks.rb")]
expect(err_without_deprecations).to eq("Ran post-install hook: foo-1.0")
end
it "complains if the install hook fails" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1281,7 +1236,7 @@ RSpec.describe "bundle install with git sources" do
H
end
- bundle :install, requires: [lib_path("install_hooks.rb")], raise_on_error: false
+ bundle :install, :requires => [lib_path("install_hooks.rb")], :raise_on_error => false
expect(err).to include("failed for foo-1.0")
end
end
@@ -1303,7 +1258,7 @@ RSpec.describe "bundle install with git sources" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1320,10 +1275,11 @@ RSpec.describe "bundle install with git sources" do
end
it "does not use old extension after ref changes" do
- git_reader = build_git "foo", no_default: true do |s|
+ git_reader = build_git "foo", :no_default => true do |s|
s.extensions = ["ext/extconf.rb"]
s.write "ext/extconf.rb", <<-RUBY
require "mkmf"
+ $extout = "$(topdir)/" + RbConfig::CONFIG["EXTOUT"]
create_makefile("foo")
RUBY
s.write "ext/foo.c", "void Init_foo() {}"
@@ -1337,12 +1293,12 @@ RSpec.describe "bundle install with git sources" do
void Init_foo() { rb_define_global_function("foo", &foo, 0); }
C
end
- git("commit -m \"commit for iteration #{i}\" ext/foo.c", git_reader.path)
+ sys_exec("git commit -m \"commit for iteration #{i}\" ext/foo.c", :dir => git_reader.path)
git_commit_sha = git_reader.ref_for("HEAD")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :ref => "#{git_commit_sha}"
G
@@ -1366,8 +1322,8 @@ RSpec.describe "bundle install with git sources" do
RUBY
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1397,7 +1353,7 @@ In Gemfile:
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1410,7 +1366,7 @@ In Gemfile:
expect(installed_time).to match(/\A\d+\.\d+\z/)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1438,8 +1394,8 @@ In Gemfile:
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1452,8 +1408,8 @@ In Gemfile:
expect(installed_time).to match(/\A\d+\.\d+\z/)
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1481,7 +1437,7 @@ In Gemfile:
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -1492,12 +1448,12 @@ In Gemfile:
installed_time = out
- update_git("foo", branch: "branch2")
+ update_git("foo", :branch => "branch2")
expect(installed_time).to match(/\A\d+\.\d+\z/)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :branch => "branch2"
G
@@ -1530,7 +1486,7 @@ In Gemfile:
ENV["GIT_WORK_TREE"] = "bar"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("xxxxxx-1.0")}" do
gem 'xxxxxx'
end
@@ -1544,7 +1500,7 @@ In Gemfile:
describe "without git installed" do
it "prints a better error message when installing" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rake", git: "https://github.com/ruby/rake"
G
@@ -1571,7 +1527,7 @@ In Gemfile:
L
with_path_as("") do
- bundle "install", raise_on_error: false
+ bundle "install", :raise_on_error => false
end
expect(err).
to include("You need to install git to be able to use gems from git repositories. For help installing git, please refer to GitHub's tutorial at https://help.github.com/articles/set-up-git")
@@ -1581,33 +1537,33 @@ In Gemfile:
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
end
G
with_path_as("") do
- bundle "update", all: true, raise_on_error: false
+ bundle "update", :all => true, :raise_on_error => false
end
expect(err).
to include("You need to install git to be able to use gems from git repositories. For help installing git, please refer to GitHub's tutorial at https://help.github.com/articles/set-up-git")
end
- it "doesn't need git in the new machine if an installed git gem is copied to another machine" do
+ it "installs a packaged git gem successfully" do
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem 'foo'
end
G
- bundle "config set --global path vendor/bundle"
- bundle :install
+ bundle "config set cache_all true"
+ bundle :cache
simulate_new_machine
- bundle "install", env: { "PATH" => "" }
+ bundle "install", :env => { "PATH" => "" }
expect(out).to_not include("You need to install git to be able to use gems from git repositories.")
end
end
@@ -1625,10 +1581,10 @@ In Gemfile:
end
it "installs successfully" do
- build_git "foo", "1.0", path: lib_path("foo")
+ build_git "foo", "1.0", :path => lib_path("foo")
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo")}", :branch => "main"
G
@@ -1643,8 +1599,8 @@ In Gemfile:
let(:credentials) { "user1:password1" }
it "does not display the password" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
git "https://#{credentials}@github.com/company/private-repo" do
gem "foo"
end
@@ -1659,8 +1615,8 @@ In Gemfile:
let(:credentials) { "oauth_token" }
it "displays the oauth scheme but not the oauth token" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
git "https://#{credentials}:x-oauth-basic@github.com/company/private-repo" do
gem "foo"
end
diff --git a/spec/bundler/install/gemfile/groups_spec.rb b/spec/bundler/install/gemfile/groups_spec.rb
index 71871899a2..734e012e84 100644
--- a/spec/bundler/install/gemfile/groups_spec.rb
+++ b/spec/bundler/install/gemfile/groups_spec.rb
@@ -4,8 +4,8 @@ RSpec.describe "bundle install with groups" do
describe "installing with no options" do
before :each do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
group :emo do
gem "activesupport", "2.3.5"
end
@@ -14,7 +14,7 @@ RSpec.describe "bundle install with groups" do
end
it "installs gems in the default group" do
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "installs gems in a group block into that group" do
@@ -40,7 +40,7 @@ RSpec.describe "bundle install with groups" do
end
it "sets up everything if Bundler.setup is used with no groups" do
- output = run("require 'myrack'; puts MYRACK")
+ output = run("require 'rack'; puts RACK")
expect(output).to eq("1.0.0")
output = run("require 'activesupport'; puts ACTIVESUPPORT")
@@ -74,8 +74,8 @@ RSpec.describe "bundle install with groups" do
describe "with gems assigned to a single group" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
group :emo do
gem "activesupport", "2.3.5"
end
@@ -88,32 +88,32 @@ RSpec.describe "bundle install with groups" do
it "installs gems in the default group" do
bundle "config set --local without emo"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0", groups: [:default]
+ expect(the_bundle).to include_gems "rack 1.0.0", :groups => [:default]
end
it "respects global `without` configuration, but does not save it locally" do
bundle "config set --global without emo"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0", groups: [:default]
+ expect(the_bundle).to include_gems "rack 1.0.0", :groups => [:default]
bundle "config list"
expect(out).not_to include("Set for your local app (#{bundled_app(".bundle/config")}): [:emo]")
expect(out).to include("Set for the current user (#{home(".bundle/config")}): [:emo]")
end
- it "allows running application where groups where configured by a different user", bundler: "< 3" do
+ it "allows running application where groups where configured by a different user", :bundler => "< 3" do
bundle "config set without emo"
bundle :install
- bundle "exec ruby -e 'puts 42'", env: { "BUNDLE_USER_HOME" => tmp("new_home").to_s }
+ bundle "exec ruby -e 'puts 42'", :env => { "BUNDLE_USER_HOME" => tmp("new_home").to_s }
expect(out).to include("42")
end
it "does not install gems from the excluded group" do
bundle "config set --local without emo"
bundle :install
- expect(the_bundle).not_to include_gems "activesupport 2.3.5", groups: [:default]
+ expect(the_bundle).not_to include_gems "activesupport 2.3.5", :groups => [:default]
end
- it "remembers previous exclusion with `--without`", bundler: "< 3" do
+ it "remembers previous exclusion with `--without`", :bundler => "< 3" do
bundle "install --without emo"
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
bundle :install
@@ -129,13 +129,13 @@ RSpec.describe "bundle install with groups" do
it "allows Bundler.setup for specific groups" do
bundle "config set --local without emo"
bundle :install
- run("require 'myrack'; puts MYRACK", :default)
+ run("require 'rack'; puts RACK", :default)
expect(out).to eq("1.0.0")
end
it "does not effect the resolve" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
group :emo do
gem "rails", "2.3.2"
@@ -144,7 +144,7 @@ RSpec.describe "bundle install with groups" do
bundle "config set --local without emo"
bundle :install
- expect(the_bundle).to include_gems "activesupport 2.3.2", groups: [:default]
+ expect(the_bundle).to include_gems "activesupport 2.3.2", :groups => [:default]
end
it "still works when BUNDLE_WITHOUT is set" do
@@ -153,20 +153,20 @@ RSpec.describe "bundle install with groups" do
bundle :install
expect(out).not_to include("activesupport")
- expect(the_bundle).to include_gems "myrack 1.0.0", groups: [:default]
- expect(the_bundle).not_to include_gems "activesupport 2.3.5", groups: [:default]
+ expect(the_bundle).to include_gems "rack 1.0.0", :groups => [:default]
+ expect(the_bundle).not_to include_gems "activesupport 2.3.5", :groups => [:default]
ENV["BUNDLE_WITHOUT"] = nil
end
- it "clears --without when passed an empty list", bundler: "< 3" do
+ it "clears --without when passed an empty list", :bundler => "< 3" do
bundle "install --without emo"
bundle "install --without ''"
expect(the_bundle).to include_gems "activesupport 2.3.5"
end
- it "doesn't clear without when nothing is passed", bundler: "< 3" do
+ it "doesn't clear without when nothing is passed", :bundler => "< 3" do
bundle "install --without emo"
bundle :install
@@ -184,7 +184,7 @@ RSpec.describe "bundle install with groups" do
expect(the_bundle).to include_gems "thin 1.0"
end
- it "installs gems from the previously requested group", bundler: "< 3" do
+ it "installs gems from the previously requested group", :bundler => "< 3" do
bundle "install --with debugging"
expect(the_bundle).to include_gems "thin 1.0"
bundle :install
@@ -198,26 +198,26 @@ RSpec.describe "bundle install with groups" do
ENV["BUNDLE_WITH"] = nil
end
- it "clears --with when passed an empty list", bundler: "< 3" do
+ it "clears --with when passed an empty list", :bundler => "< 3" do
bundle "install --with debugging"
bundle "install --with ''"
expect(the_bundle).not_to include_gems "thin 1.0"
end
- it "removes groups from without when passed at --with", bundler: "< 3" do
+ it "removes groups from without when passed at --with", :bundler => "< 3" do
bundle "config set --local without emo"
bundle "install --with emo"
expect(the_bundle).to include_gems "activesupport 2.3.5"
end
- it "removes groups from with when passed at --without", bundler: "< 3" do
+ it "removes groups from with when passed at --without", :bundler => "< 3" do
bundle "config set --local with debugging"
- bundle "install --without debugging", raise_on_error: false
+ bundle "install --without debugging", :raise_on_error => false
expect(the_bundle).not_to include_gem "thin 1.0"
end
- it "errors out when passing a group to with and without via CLI flags", bundler: "< 3" do
- bundle "install --with emo debugging --without emo", raise_on_error: false
+ it "errors out when passing a group to with and without via CLI flags", :bundler => "< 3" do
+ bundle "install --with emo debugging --without emo", :raise_on_error => false
expect(last_command).to be_failure
expect(err).to include("The offending groups are: emo")
end
@@ -235,7 +235,7 @@ RSpec.describe "bundle install with groups" do
expect(the_bundle).to include_gem "thin 1.0"
end
- it "can add and remove a group at the same time", bundler: "< 3" do
+ it "can add and remove a group at the same time", :bundler => "< 3" do
bundle "install --with debugging --without emo"
expect(the_bundle).to include_gems "thin 1.0"
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
@@ -257,8 +257,8 @@ RSpec.describe "bundle install with groups" do
describe "with gems assigned to multiple groups" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
group :emo, :lolercoaster do
gem "activesupport", "2.3.5"
end
@@ -268,20 +268,20 @@ RSpec.describe "bundle install with groups" do
it "installs gems in the default group" do
bundle "config set --local without emo lolercoaster"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "installs the gem if any of its groups are installed" do
bundle "config set --local without emo"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0", "activesupport 2.3.5"
+ expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.5"
end
describe "with a gem defined multiple times in different groups" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
group :emo do
gem "activesupport", "2.3.5"
@@ -316,8 +316,8 @@ RSpec.describe "bundle install with groups" do
describe "nesting groups" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
group :emo do
group :lolercoaster do
gem "activesupport", "2.3.5"
@@ -329,13 +329,13 @@ RSpec.describe "bundle install with groups" do
it "installs gems in the default group" do
bundle "config set --local without emo lolercoaster"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "installs the gem if any of its groups are installed" do
bundle "config set --local without emo"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0", "activesupport 2.3.5"
+ expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.5"
end
end
end
@@ -343,16 +343,16 @@ RSpec.describe "bundle install with groups" do
describe "when loading only the default group" do
it "should not load all groups" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :groups => :development
G
ruby <<-R
- require "bundler"
+ require "#{entrypoint}"
Bundler.setup :default
Bundler.require :default
- puts MYRACK
+ puts RACK
begin
require "activesupport"
rescue LoadError
@@ -369,34 +369,34 @@ RSpec.describe "bundle install with groups" do
before(:each) do
build_repo2
- system_gems "myrack-0.9.1"
+ system_gems "rack-0.9.1"
- bundle "config set --local without myrack"
+ bundle "config set --local without rack"
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
- group :myrack do
- gem "myrack_middleware"
+ group :rack do
+ gem "rack_middleware"
end
G
end
it "uses the correct versions even if --without was used on the original" do
- expect(the_bundle).to include_gems "myrack 0.9.1"
- expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
+ expect(the_bundle).to include_gems "rack 0.9.1"
+ expect(the_bundle).not_to include_gems "rack_middleware 1.0"
simulate_new_machine
bundle :install
- expect(the_bundle).to include_gems "myrack 0.9.1"
- expect(the_bundle).to include_gems "myrack_middleware 1.0"
+ expect(the_bundle).to include_gems "rack 0.9.1"
+ expect(the_bundle).to include_gems "rack_middleware 1.0"
end
it "does not hit the remote a second time" do
FileUtils.rm_rf gem_repo2
- bundle "config set --local without myrack"
- bundle :install, verbose: true
+ bundle "config set --local without rack"
+ bundle :install, :verbose => true
expect(last_command.stdboth).not_to match(/fetching/i)
end
end
diff --git a/spec/bundler/install/gemfile/install_if_spec.rb b/spec/bundler/install/gemfile/install_if_spec.rb
index 170b58c4c0..3d2d15a698 100644
--- a/spec/bundler/install/gemfile/install_if_spec.rb
+++ b/spec/bundler/install/gemfile/install_if_spec.rb
@@ -3,7 +3,7 @@
RSpec.describe "bundle install with install_if conditionals" do
it "follows the install_if DSL" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
install_if(lambda { true }) do
gem "activesupport", "2.3.5"
end
@@ -11,29 +11,22 @@ RSpec.describe "bundle install with install_if conditionals" do
install_if(lambda { false }) do
gem "foo"
end
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems("myrack 1.0", "activesupport 2.3.5")
+ expect(the_bundle).to include_gems("rack 1.0", "activesupport 2.3.5")
expect(the_bundle).not_to include_gems("thin")
expect(the_bundle).not_to include_gems("foo")
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo1, "activesupport", "2.3.5"
- c.checksum gem_repo1, "foo", "1.0"
- c.checksum gem_repo1, "myrack", "1.0.0"
- c.checksum gem_repo1, "thin", "1.0"
- end
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
activesupport (2.3.5)
foo (1.0)
- myrack (1.0.0)
+ rack (1.0.0)
thin (1.0)
- myrack
+ rack
PLATFORMS
#{lockfile_platforms}
@@ -41,9 +34,9 @@ RSpec.describe "bundle install with install_if conditionals" do
DEPENDENCIES
activesupport (= 2.3.5)
foo
- myrack
+ rack
thin
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
diff --git a/spec/bundler/install/gemfile/lockfile_spec.rb b/spec/bundler/install/gemfile/lockfile_spec.rb
index f80b21e562..313e99d0b8 100644
--- a/spec/bundler/install/gemfile/lockfile_spec.rb
+++ b/spec/bundler/install/gemfile/lockfile_spec.rb
@@ -2,20 +2,15 @@
RSpec.describe "bundle install with a lockfile present" do
let(:gf) { <<-G }
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
subject do
install_gemfile(gf)
end
- it "touches the lockfile on install even when nothing has changed" do
- subject
- expect { bundle :install }.to change { bundled_app_lock.mtime }
- end
-
context "gemfile evaluation" do
let(:gf) { super() + "\n\n File.open('evals', 'a') {|f| f << %(1\n) } unless ENV['BUNDLER_SPEC_NO_APPEND']" }
@@ -28,7 +23,7 @@ RSpec.describe "bundle install with a lockfile present" do
it "does not evaluate the gemfile twice" do
bundle :install
- with_env_vars("BUNDLER_SPEC_NO_APPEND" => "1") { expect(the_bundle).to include_gem "myrack 1.0.0" }
+ with_env_vars("BUNDLER_SPEC_NO_APPEND" => "1") { expect(the_bundle).to include_gem "rack 1.0.0" }
# The first eval is from the initial install, we're testing that the
# second install doesn't double-eval
@@ -41,7 +36,7 @@ RSpec.describe "bundle install with a lockfile present" do
it "does not evaluate the gemfile twice" do
bundle :install
- with_env_vars("BUNDLER_SPEC_NO_APPEND" => "1") { expect(the_bundle).to include_gem "myrack 1.0.0" }
+ with_env_vars("BUNDLER_SPEC_NO_APPEND" => "1") { expect(the_bundle).to include_gem "rack 1.0.0" }
# The first eval is from the initial install, we're testing that the
# second install doesn't double-eval
diff --git a/spec/bundler/install/gemfile/path_spec.rb b/spec/bundler/install/gemfile/path_spec.rb
index 7525404b24..a5207036c3 100644
--- a/spec/bundler/install/gemfile/path_spec.rb
+++ b/spec/bundler/install/gemfile/path_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.describe "bundle install with explicit source paths" do
- it "fetches gems with a global path source", bundler: "< 3" do
+ it "fetches gems with a global path source", :bundler => "< 3" do
build_lib "foo"
install_gemfile <<-G
@@ -16,7 +16,7 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path("foo-1.0")}" do
gem 'foo'
end
@@ -29,7 +29,7 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "#{lib_path("foo-1.0")}"
G
@@ -42,7 +42,7 @@ RSpec.describe "bundle install with explicit source paths" do
relative_path = lib_path("foo-1.0").relative_path_from(bundled_app)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "#{relative_path}"
G
@@ -55,7 +55,7 @@ RSpec.describe "bundle install with explicit source paths" do
relative_path = lib_path("foo-1.0").relative_path_from(Pathname.new("~").expand_path)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "~/#{relative_path}"
G
@@ -69,8 +69,8 @@ RSpec.describe "bundle install with explicit source paths" do
username = "some_unexisting_user"
relative_path = lib_path("foo-1.0").relative_path_from(Pathname.new("/home/#{username}").expand_path)
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "~#{username}/#{relative_path}"
G
expect(err).to match("There was an error while trying to use the path `~#{username}/#{relative_path}`.")
@@ -78,31 +78,26 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "expands paths relative to Bundler.root" do
- build_lib "foo", path: bundled_app("foo-1.0")
+ build_lib "foo", :path => bundled_app("foo-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "./foo-1.0"
G
- expect(the_bundle).to include_gems("foo 1.0", dir: bundled_app("subdir").mkpath)
+ expect(the_bundle).to include_gems("foo 1.0", :dir => bundled_app("subdir").mkpath)
end
it "sorts paths consistently on install and update when they start with ./" do
- build_lib "demo", path: lib_path("demo")
- build_lib "aaa", path: lib_path("demo/aaa")
+ build_lib "demo", :path => lib_path("demo")
+ build_lib "aaa", :path => lib_path("demo/aaa")
gemfile lib_path("demo/Gemfile"), <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
gem "aaa", :path => "./aaa"
G
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "aaa", "1.0"
- c.no_checksum "demo", "1.0"
- end
-
lockfile = <<~L
PATH
remote: .
@@ -115,7 +110,7 @@ RSpec.describe "bundle install with explicit source paths" do
aaa (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -124,22 +119,22 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
aaa!
demo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
- bundle :install, dir: lib_path("demo")
+ bundle :install, :dir => lib_path("demo")
expect(lib_path("demo/Gemfile.lock")).to read_as(lockfile)
- bundle :update, all: true, dir: lib_path("demo")
+ bundle :update, :all => true, :dir => lib_path("demo")
expect(lib_path("demo/Gemfile.lock")).to read_as(lockfile)
end
it "expands paths when comparing locked paths to Gemfile paths" do
- build_lib "foo", path: bundled_app("foo-1.0")
+ build_lib "foo", :path => bundled_app("foo-1.0")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => File.expand_path("foo-1.0", __dir__)
G
@@ -148,38 +143,38 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "installs dependencies from the path even if a newer gem is available elsewhere" do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
- build_lib "myrack", "1.0", path: lib_path("nested/bar") do |s|
- s.write "lib/myrack.rb", "puts 'WIN OVERRIDE'"
+ build_lib "rack", "1.0", :path => lib_path("nested/bar") do |s|
+ s.write "lib/rack.rb", "puts 'WIN OVERRIDE'"
end
- build_lib "foo", path: lib_path("nested") do |s|
- s.add_dependency "myrack", "= 1.0"
+ build_lib "foo", :path => lib_path("nested") do |s|
+ s.add_dependency "rack", "= 1.0"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("nested")}"
G
- run "require 'myrack'"
+ run "require 'rack'"
expect(out).to eq("WIN OVERRIDE")
end
it "works" do
- build_gem "foo", "1.0.0", to_system: true do |s|
+ build_gem "foo", "1.0.0", :to_system => true do |s|
s.write "lib/foo.rb", "puts 'FAIL'"
end
- build_lib "omg", "1.0", path: lib_path("omg") do |s|
+ build_lib "omg", "1.0", :path => lib_path("omg") do |s|
s.add_dependency "foo"
end
- build_lib "foo", "1.0.0", path: lib_path("omg/foo")
+ build_lib "foo", "1.0.0", :path => lib_path("omg/foo")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "omg", :path => "#{lib_path("omg")}"
G
@@ -187,10 +182,10 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "works when using prereleases of 0.0.0" do
- build_lib "foo", "0.0.0.dev", path: lib_path("foo")
+ build_lib "foo", "0.0.0.dev", :path => lib_path("foo")
gemfile <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
@@ -201,7 +196,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo (0.0.0.dev)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -220,10 +215,10 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "works when using uppercase prereleases of 0.0.0" do
- build_lib "foo", "0.0.0.SNAPSHOT", path: lib_path("foo")
+ build_lib "foo", "0.0.0.SNAPSHOT", :path => lib_path("foo")
gemfile <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
@@ -234,7 +229,7 @@ RSpec.describe "bundle install with explicit source paths" do
foo (0.0.0.SNAPSHOT)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -253,14 +248,14 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "handles downgrades" do
- build_lib "omg", "2.0", path: lib_path("omg")
+ build_lib "omg", "2.0", :path => lib_path("omg")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "omg", :path => "#{lib_path("omg")}"
G
- build_lib "omg", "1.0", path: lib_path("omg")
+ build_lib "omg", "1.0", :path => lib_path("omg")
bundle :install
@@ -268,7 +263,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "prefers gemspecs closer to the path root" do
- build_lib "premailer", "1.0.0", path: lib_path("premailer") do |s|
+ build_lib "premailer", "1.0.0", :path => lib_path("premailer") do |s|
s.write "gemfiles/ruby187.gemspec", <<-G
Gem::Specification.new do |s|
s.name = 'premailer'
@@ -280,7 +275,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "premailer", :path => "#{lib_path("premailer")}"
G
@@ -301,8 +296,8 @@ RSpec.describe "bundle install with explicit source paths" do
G
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
@@ -313,18 +308,18 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "supports gemspec syntax" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "1.0"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "1.0"
end
gemfile lib_path("foo/Gemfile"), <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
- bundle "install", dir: lib_path("foo")
- expect(the_bundle).to include_gems "foo 1.0", dir: lib_path("foo")
- expect(the_bundle).to include_gems "myrack 1.0", dir: lib_path("foo")
+ bundle "install", :dir => lib_path("foo")
+ expect(the_bundle).to include_gems "foo 1.0", :dir => lib_path("foo")
+ expect(the_bundle).to include_gems "rack 1.0", :dir => lib_path("foo")
end
it "does not unlock dependencies of path sources" do
@@ -333,24 +328,19 @@ RSpec.describe "bundle install with explicit source paths" do
build_gem "graphql", "2.0.16"
end
- build_lib "foo", "0.1.0", path: lib_path("foo") do |s|
+ build_lib "foo", "0.1.0", :path => lib_path("foo") do |s|
s.add_dependency "graphql", "~> 2.0"
end
gemfile_path = lib_path("foo/Gemfile")
gemfile gemfile_path, <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gemspec
G
lockfile_path = lib_path("foo/Gemfile.lock")
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "0.1.0"
- c.checksum gem_repo4, "graphql", "2.0.15"
- end
-
original_lockfile = <<~L
PATH
remote: .
@@ -359,7 +349,7 @@ RSpec.describe "bundle install with explicit source paths" do
graphql (~> 2.0)
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
graphql (2.0.15)
@@ -368,79 +358,79 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
lockfile lockfile_path, original_lockfile
- build_lib "foo", "0.1.1", path: lib_path("foo") do |s|
+ build_lib "foo", "0.1.1", :path => lib_path("foo") do |s|
s.add_dependency "graphql", "~> 2.0"
end
- bundle "install", dir: lib_path("foo")
+ bundle "install", :dir => lib_path("foo")
expect(lockfile_path).to read_as(original_lockfile.gsub("foo (0.1.0)", "foo (0.1.1)"))
end
it "supports gemspec syntax with an alternative path" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "1.0"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "1.0"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec :path => "#{lib_path("foo")}"
G
expect(the_bundle).to include_gems "foo 1.0"
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
it "doesn't automatically unlock dependencies when using the gemspec syntax" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", ">= 1.0"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", ">= 1.0"
end
- install_gemfile lib_path("foo/Gemfile"), <<-G, dir: lib_path("foo")
- source "https://gem.repo1"
+ install_gemfile lib_path("foo/Gemfile"), <<-G, :dir => lib_path("foo")
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
- build_gem "myrack", "1.0.1", to_system: true
+ build_gem "rack", "1.0.1", :to_system => true
- bundle "install", dir: lib_path("foo")
+ bundle "install", :dir => lib_path("foo")
- expect(the_bundle).to include_gems "foo 1.0", dir: lib_path("foo")
- expect(the_bundle).to include_gems "myrack 1.0", dir: lib_path("foo")
+ expect(the_bundle).to include_gems "foo 1.0", :dir => lib_path("foo")
+ expect(the_bundle).to include_gems "rack 1.0", :dir => lib_path("foo")
end
it "doesn't automatically unlock dependencies when using the gemspec syntax and the gem has development dependencies" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", ">= 1.0"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", ">= 1.0"
s.add_development_dependency "activesupport"
end
- install_gemfile lib_path("foo/Gemfile"), <<-G, dir: lib_path("foo")
- source "https://gem.repo1"
+ install_gemfile lib_path("foo/Gemfile"), <<-G, :dir => lib_path("foo")
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
- build_gem "myrack", "1.0.1", to_system: true
+ build_gem "rack", "1.0.1", :to_system => true
- bundle "install", dir: lib_path("foo")
+ bundle "install", :dir => lib_path("foo")
- expect(the_bundle).to include_gems "foo 1.0", dir: lib_path("foo")
- expect(the_bundle).to include_gems "myrack 1.0", dir: lib_path("foo")
+ expect(the_bundle).to include_gems "foo 1.0", :dir => lib_path("foo")
+ expect(the_bundle).to include_gems "rack 1.0", :dir => lib_path("foo")
end
it "raises if there are multiple gemspecs" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.write "bar.gemspec", build_spec("bar", "1.0").first.to_ruby
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gemspec :path => "#{lib_path("foo")}"
G
@@ -449,12 +439,12 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "allows :name to be specified to resolve ambiguity" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.write "bar.gemspec"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec :path => "#{lib_path("foo")}", :name => "foo"
G
@@ -466,8 +456,8 @@ RSpec.describe "bundle install with explicit source paths" do
s.executables = "foobar"
end
- install_gemfile <<-G, verbose: true
- source "https://gem.repo1"
+ install_gemfile <<-G, :verbose => true
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path("foo-1.0")}" do
gem 'foo'
end
@@ -485,7 +475,7 @@ RSpec.describe "bundle install with explicit source paths" do
lib_path("foo-1.0").join("bin/performance").mkpath
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', '1.0', :path => "#{lib_path("foo-1.0")}"
G
expect(err).to be_empty
@@ -495,7 +485,7 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :path => "#{lib_path("foo-1.0")}"
G
@@ -508,7 +498,7 @@ RSpec.describe "bundle install with explicit source paths" do
build_lib "hi2u"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "omg"
gem "hi2u"
@@ -520,14 +510,14 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "keeps source pinning" do
- build_lib "foo", "1.0", path: lib_path("foo")
- build_lib "omg", "1.0", path: lib_path("omg")
- build_lib "foo", "1.0", path: lib_path("omg/foo") do |s|
+ build_lib "foo", "1.0", :path => lib_path("foo")
+ build_lib "omg", "1.0", :path => lib_path("omg")
+ build_lib "foo", "1.0", :path => lib_path("omg/foo") do |s|
s.write "lib/foo.rb", "puts 'FAIL'"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
gem "omg", :path => "#{lib_path("omg")}"
G
@@ -536,10 +526,10 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "works when the path does not have a gemspec" do
- build_lib "foo", gemspec: false
+ build_lib "foo", :gemspec => false
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", "1.0", :path => "#{lib_path("foo-1.0")}"
G
@@ -569,34 +559,34 @@ RSpec.describe "bundle install with explicit source paths" do
context "existing lockfile" do
it "rubygems gems don't re-resolve without changes" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack-obama', '1.0'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack-obama', '1.0'
gem 'net-ssh', '1.0'
G
- bundle :check, env: { "DEBUG" => "1" }
+ bundle :check, :env => { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
- expect(the_bundle).to include_gems "myrack-obama 1.0", "net-ssh 1.0"
+ expect(the_bundle).to include_gems "rack-obama 1.0", "net-ssh 1.0"
end
it "source path gems w/deps don't re-resolve without changes" do
- build_lib "myrack-obama", "1.0", path: lib_path("omg") do |s|
+ build_lib "rack-obama", "1.0", :path => lib_path("omg") do |s|
s.add_dependency "yard"
end
- build_lib "net-ssh", "1.0", path: lib_path("omg") do |s|
+ build_lib "net-ssh", "1.0", :path => lib_path("omg") do |s|
s.add_dependency "yard"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack-obama', :path => "#{lib_path("omg")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack-obama', :path => "#{lib_path("omg")}"
gem 'net-ssh', :path => "#{lib_path("omg")}"
G
- bundle :check, env: { "DEBUG" => "1" }
+ bundle :check, :env => { "DEBUG" => "1" }
expect(out).to match(/using resolution from the lockfile/)
- expect(the_bundle).to include_gems "myrack-obama 1.0", "net-ssh 1.0"
+ expect(the_bundle).to include_gems "rack-obama 1.0", "net-ssh 1.0"
end
end
@@ -606,7 +596,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
@@ -616,19 +606,19 @@ RSpec.describe "bundle install with explicit source paths" do
describe "when the gem version in the path is updated" do
before :each do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.add_dependency "bar"
end
- build_lib "bar", "1.0", path: lib_path("foo/bar")
+ build_lib "bar", "1.0", :path => lib_path("foo/bar")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
end
it "unlocks all gems when the top level gem is updated" do
- build_lib "foo", "2.0", path: lib_path("foo") do |s|
+ build_lib "foo", "2.0", :path => lib_path("foo") do |s|
s.add_dependency "bar"
end
@@ -638,7 +628,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "unlocks all gems when a child dependency gem is updated" do
- build_lib "bar", "2.0", path: lib_path("foo/bar")
+ build_lib "bar", "2.0", :path => lib_path("foo/bar")
bundle "install"
@@ -648,62 +638,57 @@ RSpec.describe "bundle install with explicit source paths" do
describe "when dependencies in the path are updated" do
before :each do
- build_lib "foo", "1.0", path: lib_path("foo")
+ build_lib "foo", "1.0", :path => lib_path("foo")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo")}"
G
end
it "gets dependencies that are updated in the path" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack"
end
bundle "install"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "keeps using the same version if it's compatible" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "0.9.1"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "0.9.1"
end
bundle "install"
- expect(the_bundle).to include_gems "myrack 0.9.1"
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo1, "myrack", "0.9.1"
- end
+ expect(the_bundle).to include_gems "rack 0.9.1"
expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
- myrack (= 0.9.1)
+ rack (= 0.9.1)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack"
end
bundle "install"
@@ -713,105 +698,94 @@ RSpec.describe "bundle install with explicit source paths" do
remote: #{lib_path("foo")}
specs:
foo (1.0)
- myrack
+ rack
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
- expect(the_bundle).to include_gems "myrack 0.9.1"
+ expect(the_bundle).to include_gems "rack 0.9.1"
end
it "keeps using the same version even when another dependency is added" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "0.9.1"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "0.9.1"
end
bundle "install"
- expect(the_bundle).to include_gems "myrack 0.9.1"
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.checksum gem_repo1, "myrack", "0.9.1"
- end
+ expect(the_bundle).to include_gems "rack 0.9.1"
expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
- myrack (= 0.9.1)
+ rack (= 0.9.1)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack"
- s.add_dependency "rake", rake_version
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack"
+ s.add_dependency "rake", "13.0.1"
end
bundle "install"
- checksums.checksum gem_repo1, "rake", rake_version
-
expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
- myrack
- rake (= #{rake_version})
+ rack
+ rake (= 13.0.1)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (0.9.1)
- rake (#{rake_version})
+ rack (0.9.1)
+ rake (13.0.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
- expect(the_bundle).to include_gems "myrack 0.9.1"
+ expect(the_bundle).to include_gems "rack 0.9.1"
end
it "does not remove existing ruby platform" do
- build_lib "foo", "1.0", path: lib_path("foo") do |s|
- s.add_dependency "myrack", "0.9.1"
- end
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "0.9.1"
end
lockfile <<~L
@@ -825,33 +799,31 @@ RSpec.describe "bundle install with explicit source paths" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
bundle "lock"
- checksums.checksum gem_repo1, "myrack", "0.9.1"
-
expect(lockfile).to eq <<~G
PATH
remote: #{lib_path("foo")}
specs:
foo (1.0)
- myrack (= 0.9.1)
+ rack (= 0.9.1)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
#{lockfile_platforms("ruby")}
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -860,21 +832,21 @@ RSpec.describe "bundle install with explicit source paths" do
describe "switching sources" do
it "doesn't switch pinned git sources to rubygems when pinning the parent gem to a path source" do
- build_gem "foo", "1.0", to_system: true do |s|
+ build_gem "foo", "1.0", :to_system => true do |s|
s.write "lib/foo.rb", "raise 'fail'"
end
- build_lib "foo", "1.0", path: lib_path("bar/foo")
- build_git "bar", "1.0", path: lib_path("bar") do |s|
+ build_lib "foo", "1.0", :path => lib_path("bar/foo")
+ build_git "bar", "1.0", :path => lib_path("bar") do |s|
s.add_dependency "foo"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :git => "#{lib_path("bar")}"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :path => "#{lib_path("bar")}"
G
@@ -882,23 +854,23 @@ RSpec.describe "bundle install with explicit source paths" do
end
it "switches the source when the gem existed in rubygems and the path was already being used for another gem" do
- build_lib "foo", "1.0", path: lib_path("foo")
- build_gem "bar", "1.0", to_bundle: true do |s|
+ build_lib "foo", "1.0", :path => lib_path("foo")
+ build_gem "bar", "1.0", :to_bundle => true do |s|
s.write "lib/bar.rb", "raise 'fail'"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar"
path "#{lib_path("foo")}" do
gem "foo"
end
G
- build_lib "bar", "1.0", path: lib_path("foo/bar")
+ build_lib "bar", "1.0", :path => lib_path("foo/bar")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path("foo")}" do
gem "foo"
gem "bar"
@@ -911,17 +883,17 @@ RSpec.describe "bundle install with explicit source paths" do
describe "when there are both a gemspec and remote gems" do
it "doesn't query rubygems for local gemspec name" do
- build_lib "private_lib", "2.2", path: lib_path("private_lib")
+ build_lib "private_lib", "2.2", :path => lib_path("private_lib")
gemfile lib_path("private_lib/Gemfile"), <<-G
source "http://localgemserver.test"
gemspec
- gem 'myrack'
+ gem 'rack'
G
- bundle :install, env: { "DEBUG" => "1" }, artifice: "endpoint", dir: lib_path("private_lib")
- expect(out).to match(%r{^HTTP GET http://localgemserver\.test/api/v1/dependencies\?gems=myrack$})
+ bundle :install, :env => { "DEBUG" => "1" }, :artifice => "endpoint", :dir => lib_path("private_lib")
+ expect(out).to match(%r{^HTTP GET http://localgemserver\.test/api/v1/dependencies\?gems=rack$})
expect(out).not_to match(/^HTTP GET.*private_lib/)
- expect(the_bundle).to include_gems "private_lib 2.2", dir: lib_path("private_lib")
- expect(the_bundle).to include_gems "myrack 1.0", dir: lib_path("private_lib")
+ expect(the_bundle).to include_gems "private_lib 2.2", :dir => lib_path("private_lib")
+ expect(the_bundle).to include_gems "rack 1.0", :dir => lib_path("private_lib")
end
end
@@ -929,7 +901,7 @@ RSpec.describe "bundle install with explicit source paths" do
it "runs pre-install hooks" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -942,14 +914,14 @@ RSpec.describe "bundle install with explicit source paths" do
end
bundle :install,
- requires: [lib_path("install_hooks.rb")]
+ :requires => [lib_path("install_hooks.rb")]
expect(err_without_deprecations).to eq("Ran pre-install hook: foo-1.0")
end
it "runs post-install hooks" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -962,14 +934,14 @@ RSpec.describe "bundle install with explicit source paths" do
end
bundle :install,
- requires: [lib_path("install_hooks.rb")]
+ :requires => [lib_path("install_hooks.rb")]
expect(err_without_deprecations).to eq("Ran post-install hook: foo-1.0")
end
it "complains if the install hook fails" do
build_git "foo"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -981,7 +953,7 @@ RSpec.describe "bundle install with explicit source paths" do
H
end
- bundle :install, requires: [lib_path("install_hooks.rb")], raise_on_error: false
+ bundle :install, :requires => [lib_path("install_hooks.rb")], :raise_on_error => false
expect(err).to include("failed for foo-1.0")
end
@@ -1000,7 +972,7 @@ RSpec.describe "bundle install with explicit source paths" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo-1.0")}"
gem "bar", :path => "#{lib_path("bar-1.0")}"
G
diff --git a/spec/bundler/install/gemfile/platform_spec.rb b/spec/bundler/install/gemfile/platform_spec.rb
index 820feb18bf..219ae6c2f4 100644
--- a/spec/bundler/install/gemfile/platform_spec.rb
+++ b/spec/bundler/install/gemfile/platform_spec.rb
@@ -4,30 +4,30 @@ RSpec.describe "bundle install across platforms" do
it "maintains the same lockfile if all gems are compatible across platforms" do
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
#{not_local}
DEPENDENCIES
- myrack
+ rack
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 0.9.1"
+ expect(the_bundle).to include_gems "rack 0.9.1"
end
it "pulls in the correct platform specific gem" do
lockfile <<-G
GEM
- remote: https://gem.repo1
+ remote: #{file_uri_for(gem_repo1)}
specs:
platform_specific (1.0)
platform_specific (1.0-java)
@@ -40,21 +40,20 @@ RSpec.describe "bundle install across platforms" do
platform_specific
G
- simulate_platform "java" do
- install_gemfile <<-G
- source "https://gem.repo1"
+ simulate_platform "java"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
- gem "platform_specific"
- G
+ gem "platform_specific"
+ G
- expect(the_bundle).to include_gems "platform_specific 1.0 java"
- end
+ expect(the_bundle).to include_gems "platform_specific 1.0 JAVA"
end
it "pulls the pure ruby version on jruby if the java platform is not present in the lockfile and bundler is run in frozen mode", :jruby_only do
lockfile <<-G
GEM
- remote: https://gem.repo1
+ remote: #{file_uri_for(gem_repo1)}
specs:
platform_specific (1.0)
@@ -68,12 +67,12 @@ RSpec.describe "bundle install across platforms" do
bundle "config set --local frozen true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
G
- expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gems "platform_specific 1.0 RUBY"
end
context "on universal Rubies" do
@@ -81,12 +80,15 @@ RSpec.describe "bundle install across platforms" do
build_repo4 do
build_gem "darwin_single_arch" do |s|
s.platform = "ruby"
+ s.write "lib/darwin_single_arch.rb", "DARWIN_SINGLE_ARCH = '1.0 RUBY'"
end
build_gem "darwin_single_arch" do |s|
s.platform = "arm64-darwin"
+ s.write "lib/darwin_single_arch.rb", "DARWIN_SINGLE_ARCH = '1.0 arm64-darwin'"
end
build_gem "darwin_single_arch" do |s|
s.platform = "x86_64-darwin"
+ s.write "lib/darwin_single_arch.rb", "DARWIN_SINGLE_ARCH = '1.0 x86_64-darwin'"
end
end
end
@@ -94,7 +96,7 @@ RSpec.describe "bundle install across platforms" do
it "pulls in the correct architecture gem" do
lockfile <<-G
GEM
- remote: https://gem.repo4
+ remote: #{file_uri_for(gem_repo4)}
specs:
darwin_single_arch (1.0)
darwin_single_arch (1.0-arm64-darwin)
@@ -107,23 +109,22 @@ RSpec.describe "bundle install across platforms" do
darwin_single_arch
G
- simulate_platform "universal-darwin-21" do
- simulate_ruby_platform "universal.x86_64-darwin21" do
- install_gemfile <<-G
- source "https://gem.repo4"
+ simulate_platform "universal-darwin-21"
+ simulate_ruby_platform "universal.x86_64-darwin21" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
- gem "darwin_single_arch"
- G
+ gem "darwin_single_arch"
+ G
- expect(the_bundle).to include_gems "darwin_single_arch 1.0 x86_64-darwin"
- end
+ expect(the_bundle).to include_gems "darwin_single_arch 1.0 x86_64-darwin"
end
end
it "pulls in the correct architecture gem on arm64e macOS Ruby" do
lockfile <<-G
GEM
- remote: https://gem.repo4
+ remote: #{file_uri_for(gem_repo4)}
specs:
darwin_single_arch (1.0)
darwin_single_arch (1.0-arm64-darwin)
@@ -136,42 +137,41 @@ RSpec.describe "bundle install across platforms" do
darwin_single_arch
G
- simulate_platform "universal-darwin-21" do
- simulate_ruby_platform "universal.arm64e-darwin21" do
- install_gemfile <<-G
- source "https://gem.repo4"
+ simulate_platform "universal-darwin-21"
+ simulate_ruby_platform "universal.arm64e-darwin21" do
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
- gem "darwin_single_arch"
- G
+ gem "darwin_single_arch"
+ G
- expect(the_bundle).to include_gems "darwin_single_arch 1.0 arm64-darwin"
- end
+ expect(the_bundle).to include_gems "darwin_single_arch 1.0 arm64-darwin"
end
end
end
it "works with gems that have different dependencies" do
- simulate_platform "java" do
- install_gemfile <<-G
- source "https://gem.repo1"
+ simulate_platform "java"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
- gem "nokogiri"
- G
+ gem "nokogiri"
+ G
- expect(the_bundle).to include_gems "nokogiri 1.4.2 java", "weakling 0.0.3"
+ expect(the_bundle).to include_gems "nokogiri 1.4.2 JAVA", "weakling 0.0.3"
- simulate_new_machine
- bundle "config set --local force_ruby_platform true"
- bundle "install"
+ simulate_new_machine
+ bundle "config set --local force_ruby_platform true"
+ bundle "install"
- expect(the_bundle).to include_gems "nokogiri 1.4.2"
- expect(the_bundle).not_to include_gems "weakling"
+ expect(the_bundle).to include_gems "nokogiri 1.4.2"
+ expect(the_bundle).not_to include_gems "weakling"
- simulate_new_machine
- bundle "install"
+ simulate_new_machine
+ simulate_platform "java"
+ bundle "install"
- expect(the_bundle).to include_gems "nokogiri 1.4.2 java", "weakling 0.0.3"
- end
+ expect(the_bundle).to include_gems "nokogiri 1.4.2 JAVA", "weakling 0.0.3"
end
it "does not keep unneeded platforms for gems that are used" do
@@ -179,189 +179,178 @@ RSpec.describe "bundle install across platforms" do
build_gem "empyrean", "0.1.0"
build_gem "coderay", "1.1.2"
build_gem "method_source", "0.9.0"
- build_gem("spoon", "0.0.6") {|s| s.add_dependency "ffi" }
+ build_gem("spoon", "0.0.6") {|s| s.add_runtime_dependency "ffi" }
build_gem "pry", "0.11.3" do |s|
s.platform = "java"
- s.add_dependency "coderay", "~> 1.1.0"
- s.add_dependency "method_source", "~> 0.9.0"
- s.add_dependency "spoon", "~> 0.0"
+ s.add_runtime_dependency "coderay", "~> 1.1.0"
+ s.add_runtime_dependency "method_source", "~> 0.9.0"
+ s.add_runtime_dependency "spoon", "~> 0.0"
end
build_gem "pry", "0.11.3" do |s|
- s.add_dependency "coderay", "~> 1.1.0"
- s.add_dependency "method_source", "~> 0.9.0"
+ s.add_runtime_dependency "coderay", "~> 1.1.0"
+ s.add_runtime_dependency "method_source", "~> 0.9.0"
end
build_gem("ffi", "1.9.23") {|s| s.platform = "java" }
build_gem("ffi", "1.9.23")
end
- simulate_platform java do
- install_gemfile <<-G
- source "https://gem.repo4"
+ simulate_platform java
- gem "empyrean", "0.1.0"
- gem "pry"
- G
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo4)}"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "coderay", "1.1.2"
- c.checksum gem_repo4, "empyrean", "0.1.0"
- c.checksum gem_repo4, "ffi", "1.9.23", "java"
- c.checksum gem_repo4, "method_source", "0.9.0"
- c.checksum gem_repo4, "pry", "0.11.3", "java"
- c.checksum gem_repo4, "spoon", "0.0.6"
- end
+ gem "empyrean", "0.1.0"
+ gem "pry"
+ G
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- coderay (1.1.2)
- empyrean (0.1.0)
- ffi (1.9.23-java)
- method_source (0.9.0)
- pry (0.11.3-java)
- coderay (~> 1.1.0)
- method_source (~> 0.9.0)
- spoon (~> 0.0)
- spoon (0.0.6)
- ffi
+ expect(lockfile).to eq <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ coderay (1.1.2)
+ empyrean (0.1.0)
+ ffi (1.9.23-java)
+ method_source (0.9.0)
+ pry (0.11.3-java)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
+ spoon (~> 0.0)
+ spoon (0.0.6)
+ ffi
- PLATFORMS
- java
+ PLATFORMS
+ java
- DEPENDENCIES
- empyrean (= 0.1.0)
- pry
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
+ DEPENDENCIES
+ empyrean (= 0.1.0)
+ pry
- bundle "lock --add-platform ruby"
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
- checksums.checksum gem_repo4, "pry", "0.11.3"
+ bundle "lock --add-platform ruby"
- good_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- coderay (1.1.2)
- empyrean (0.1.0)
- ffi (1.9.23-java)
- method_source (0.9.0)
- pry (0.11.3)
- coderay (~> 1.1.0)
- method_source (~> 0.9.0)
- pry (0.11.3-java)
- coderay (~> 1.1.0)
- method_source (~> 0.9.0)
- spoon (~> 0.0)
- spoon (0.0.6)
- ffi
+ good_lockfile = <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ coderay (1.1.2)
+ empyrean (0.1.0)
+ ffi (1.9.23-java)
+ method_source (0.9.0)
+ pry (0.11.3)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
+ pry (0.11.3-java)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
+ spoon (~> 0.0)
+ spoon (0.0.6)
+ ffi
- PLATFORMS
- java
- ruby
+ PLATFORMS
+ java
+ ruby
- DEPENDENCIES
- empyrean (= 0.1.0)
- pry
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
+ DEPENDENCIES
+ empyrean (= 0.1.0)
+ pry
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ L
+ expect(lockfile).to eq good_lockfile
+
+ bad_lockfile = <<~L
+ GEM
+ remote: #{file_uri_for(gem_repo4)}/
+ specs:
+ coderay (1.1.2)
+ empyrean (0.1.0)
+ ffi (1.9.23)
+ ffi (1.9.23-java)
+ method_source (0.9.0)
+ pry (0.11.3)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
+ pry (0.11.3-java)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
+ spoon (~> 0.0)
+ spoon (0.0.6)
+ ffi
+
+ PLATFORMS
+ java
+ ruby
+
+ DEPENDENCIES
+ empyrean (= 0.1.0)
+ pry
+
+ BUNDLED WITH
+ 1.16.1
+ L
+
+ aggregate_failures do
+ lockfile bad_lockfile
+ bundle :install, :env => { "BUNDLER_VERSION" => Bundler::VERSION }
expect(lockfile).to eq good_lockfile
- bad_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- coderay (1.1.2)
- empyrean (0.1.0)
- ffi (1.9.23)
- ffi (1.9.23-java)
- method_source (0.9.0)
- pry (0.11.3)
- coderay (~> 1.1.0)
- method_source (~> 0.9.0)
- pry (0.11.3-java)
- coderay (~> 1.1.0)
- method_source (~> 0.9.0)
- spoon (~> 0.0)
- spoon (0.0.6)
- ffi
+ lockfile bad_lockfile
+ bundle :update, :all => true, :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ expect(lockfile).to eq good_lockfile
- PLATFORMS
- java
- ruby
+ lockfile bad_lockfile
+ bundle "update ffi", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ expect(lockfile).to eq good_lockfile
- DEPENDENCIES
- empyrean (= 0.1.0)
- pry
- #{checksums}
- BUNDLED WITH
- 1.16.1
- L
-
- aggregate_failures do
- lockfile bad_lockfile
- bundle :install, env: { "BUNDLER_VERSION" => Bundler::VERSION }
- expect(lockfile).to eq good_lockfile
-
- lockfile bad_lockfile
- bundle :update, all: true, env: { "BUNDLER_VERSION" => Bundler::VERSION }
- expect(lockfile).to eq good_lockfile
-
- lockfile bad_lockfile
- bundle "update ffi", env: { "BUNDLER_VERSION" => Bundler::VERSION }
- expect(lockfile).to eq good_lockfile
-
- lockfile bad_lockfile
- bundle "update empyrean", env: { "BUNDLER_VERSION" => Bundler::VERSION }
- expect(lockfile).to eq good_lockfile
-
- lockfile bad_lockfile
- bundle :lock, env: { "BUNDLER_VERSION" => Bundler::VERSION }
- expect(lockfile).to eq good_lockfile
- end
+ lockfile bad_lockfile
+ bundle "update empyrean", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ expect(lockfile).to eq good_lockfile
+
+ lockfile bad_lockfile
+ bundle :lock, :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ expect(lockfile).to eq good_lockfile
end
end
it "works with gems with platform-specific dependency having different requirements order" do
- simulate_platform x64_mac do
- update_repo2 do
- build_gem "fspath", "3"
- build_gem "image_optim_pack", "1.2.3" do |s|
- s.add_dependency "fspath", ">= 2.1", "< 4"
- end
- build_gem "image_optim_pack", "1.2.3" do |s|
- s.platform = "universal-darwin"
- s.add_dependency "fspath", "< 4", ">= 2.1"
- end
+ simulate_platform x64_mac
+
+ update_repo2 do
+ build_gem "fspath", "3"
+ build_gem "image_optim_pack", "1.2.3" do |s|
+ s.add_runtime_dependency "fspath", ">= 2.1", "< 4"
end
+ build_gem "image_optim_pack", "1.2.3" do |s|
+ s.platform = "universal-darwin"
+ s.add_runtime_dependency "fspath", "< 4", ">= 2.1"
+ end
+ end
- install_gemfile <<-G
- source "https://gem.repo2"
- G
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+ G
- install_gemfile <<-G
- source "https://gem.repo2"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
- gem "image_optim_pack"
- G
+ gem "image_optim_pack"
+ G
- expect(err).not_to include "Unable to use the platform-specific"
+ expect(err).not_to include "Unable to use the platform-specific"
- expect(the_bundle).to include_gem "image_optim_pack 1.2.3 universal-darwin"
- end
+ expect(the_bundle).to include_gem "image_optim_pack 1.2.3 universal-darwin"
end
it "fetches gems again after changing the version of Ruby" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
bundle "config set --local path vendor/bundle"
@@ -370,18 +359,13 @@ RSpec.describe "bundle install across platforms" do
FileUtils.mv(vendored_gems, bundled_app("vendor/bundle", Gem.ruby_engine, "1.8"))
bundle :install
- expect(vendored_gems("gems/myrack-1.0.0")).to exist
+ expect(vendored_gems("gems/rack-1.0.0")).to exist
end
it "keeps existing platforms when installing with force_ruby_platform" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo1, "platform_specific", "1.0"
- c.checksum gem_repo1, "platform_specific", "1.0", "java"
- end
-
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
platform_specific (1.0-java)
@@ -390,23 +374,20 @@ RSpec.describe "bundle install across platforms" do
DEPENDENCIES
platform_specific
- #{checksums}
G
bundle "config set --local force_ruby_platform true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
G
- checksums.checksum gem_repo1, "platform_specific", "1.0"
-
- expect(the_bundle).to include_gem "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gem "platform_specific 1.0 RUBY"
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
platform_specific (1.0)
platform_specific (1.0-java)
@@ -417,7 +398,7 @@ RSpec.describe "bundle install across platforms" do
DEPENDENCIES
platform_specific
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -427,7 +408,7 @@ end
RSpec.describe "bundle install with platform conditionals" do
it "installs gems tagged w/ the current platforms" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
platforms :#{local_tag} do
gem "nokogiri"
@@ -439,14 +420,14 @@ RSpec.describe "bundle install with platform conditionals" do
it "does not install gems tagged w/ another platforms" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
platforms :#{not_local_tag} do
gem "nokogiri"
end
G
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
expect(the_bundle).not_to include_gems "nokogiri 1.4.2"
end
@@ -460,7 +441,7 @@ RSpec.describe "bundle install with platform conditionals" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "activesupport"
@@ -471,7 +452,7 @@ RSpec.describe "bundle install with platform conditionals" do
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
activesupport (6.1.4.1)
tzinfo (~> 2.0)
@@ -495,7 +476,7 @@ RSpec.describe "bundle install with platform conditionals" do
it "installs gems tagged w/ the current platforms inline" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "nokogiri", :platforms => :#{local_tag}
G
expect(the_bundle).to include_gems "nokogiri 1.4.2"
@@ -503,17 +484,17 @@ RSpec.describe "bundle install with platform conditionals" do
it "does not install gems tagged w/ another platforms inline" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "nokogiri", :platforms => :#{not_local_tag}
G
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
expect(the_bundle).not_to include_gems "nokogiri 1.4.2"
end
it "installs gems tagged w/ the current platform inline" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "nokogiri", :platform => :#{local_tag}
G
expect(the_bundle).to include_gems "nokogiri 1.4.2"
@@ -521,7 +502,7 @@ RSpec.describe "bundle install with platform conditionals" do
it "doesn't install gems tagged w/ another platform inline" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "nokogiri", :platform => :#{not_local_tag}
G
expect(the_bundle).not_to include_gems "nokogiri 1.4.2"
@@ -531,7 +512,7 @@ RSpec.describe "bundle install with platform conditionals" do
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
platform :#{not_local_tag} do
gem "foo", :git => "#{lib_path("foo-1.0")}"
end
@@ -544,7 +525,7 @@ RSpec.describe "bundle install with platform conditionals" do
bundle "config set --local force_ruby_platform true"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "some_gem", :platform => :rbx
G
@@ -555,7 +536,7 @@ RSpec.describe "bundle install with platform conditionals" do
it "does not attempt to install gems from other rubies when using --local" do
bundle "config set --local force_ruby_platform true"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "some_gem", platform: :ruby_22
G
@@ -567,9 +548,9 @@ RSpec.describe "bundle install with platform conditionals" do
bundle "config set --local force_ruby_platform true"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", :platform => [:windows, :mswin, :mswin64, :mingw, :x64_mingw, :jruby]
+ gem "rack", :platform => [:windows, :mingw, :mswin, :x64_mingw, :jruby]
G
bundle "install"
@@ -578,15 +559,15 @@ RSpec.describe "bundle install with platform conditionals" do
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
ruby
DEPENDENCIES
- myrack
- #{checksums_section_when_enabled}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -604,7 +585,7 @@ RSpec.describe "bundle install with platform conditionals" do
end
install_gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "listen"
gem "ffi", :platform => :windows
@@ -615,23 +596,23 @@ end
RSpec.describe "when a gem has no architecture" do
it "still installs correctly" do
- simulate_platform x86_mswin32 do
- build_repo2 do
- # The rcov gem is platform mswin32, but has no arch
- build_gem "rcov" do |s|
- s.platform = Gem::Platform.new([nil, "mswin32", nil])
- s.write "lib/rcov.rb", "RCOV = '1.0.0'"
- end
+ simulate_platform x86_mswin32
+
+ build_repo2 do
+ # The rcov gem is platform mswin32, but has no arch
+ build_gem "rcov" do |s|
+ s.platform = Gem::Platform.new([nil, "mswin32", nil])
+ s.write "lib/rcov.rb", "RCOV = '1.0.0'"
end
+ end
- gemfile <<-G
- # Try to install gem with nil arch
- source "http://localgemserver.test/"
- gem "rcov"
- G
+ gemfile <<-G
+ # Try to install gem with nil arch
+ source "http://localgemserver.test/"
+ gem "rcov"
+ G
- bundle :install, artifice: "windows", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
- expect(the_bundle).to include_gems "rcov 1.0.0"
- end
+ bundle :install, :artifice => "windows", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ expect(the_bundle).to include_gems "rcov 1.0.0"
end
end
diff --git a/spec/bundler/install/gemfile/ruby_spec.rb b/spec/bundler/install/gemfile/ruby_spec.rb
index 3e15d82bbe..39f09031b7 100644
--- a/spec/bundler/install/gemfile/ruby_spec.rb
+++ b/spec/bundler/install/gemfile/ruby_spec.rb
@@ -10,77 +10,77 @@ RSpec.describe "ruby requirement" do
# requirement. This test verifies the fix, committed in bfbad5c5.
it "allows adding gems" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "#{Gem.ruby_version}"
- gem "myrack"
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "#{Gem.ruby_version}"
- gem "myrack"
- gem "myrack-obama"
+ gem "rack"
+ gem "rack-obama"
G
- expect(the_bundle).to include_gems "myrack-obama 1.0"
+ expect(the_bundle).to include_gems "rack-obama 1.0"
end
it "allows removing the ruby version requirement" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "~> #{Gem.ruby_version}"
- gem "myrack"
+ gem "rack"
G
expect(lockfile).to include("RUBY VERSION")
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(lockfile).not_to include("RUBY VERSION")
end
it "allows changing the ruby version requirement to something compatible" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= #{current_ruby_minor}"
- gem "myrack"
+ gem "rack"
G
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
expect(locked_ruby_version).to eq(Bundler::RubyVersion.system)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= #{Gem.ruby_version}"
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(locked_ruby_version).to eq(Bundler::RubyVersion.system)
end
it "allows changing the ruby version requirement to something incompatible" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= 1.0.0"
- gem "myrack"
+ gem "rack"
G
lockfile <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
RUBY VERSION
ruby 2.1.4p422
@@ -92,66 +92,32 @@ RSpec.describe "ruby requirement" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= #{current_ruby_minor}"
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(locked_ruby_version).to eq(Bundler::RubyVersion.system)
end
it "allows requirements with trailing whitespace" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "#{Gem.ruby_version}\\n \t\\n"
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "fails gracefully with malformed requirements" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
ruby ">= 0", "-.\\0"
- gem "myrack"
+ gem "rack"
G
expect(err).to include("There was an error parsing") # i.e. DSL error, not error template
end
-
- it "allows picking up ruby version from a file" do
- create_file ".ruby-version", Gem.ruby_version.to_s
-
- install_gemfile <<-G
- source "https://gem.repo1"
- ruby file: ".ruby-version"
- gem "myrack"
- G
-
- expect(lockfile).to include("RUBY VERSION")
- end
-
- it "reads the ruby version file from the right folder when nested Gemfiles are involved" do
- create_file ".ruby-version", Gem.ruby_version.to_s
-
- gemfile <<-G
- source "https://gem.repo1"
- ruby file: ".ruby-version"
- gem "myrack"
- G
-
- nested_dir = bundled_app(".ruby-lsp")
-
- FileUtils.mkdir nested_dir
-
- gemfile ".ruby-lsp/Gemfile", <<-G
- eval_gemfile(File.expand_path("../Gemfile", __dir__))
- G
-
- bundle "install", dir: nested_dir
-
- expect(bundled_app(".ruby-lsp/Gemfile.lock").read).to include("RUBY VERSION")
- end
end
diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb
index 84af5c0d06..dd86187a6b 100644
--- a/spec/bundler/install/gemfile/sources_spec.rb
+++ b/spec/bundler/install/gemfile/sources_spec.rb
@@ -2,167 +2,85 @@
RSpec.describe "bundle install with gems on multiple sources" do
# repo1 is built automatically before all of the specs run
- # it contains myrack-obama 1.0.0 and myrack 0.9.1 & 1.0.0 amongst other gems
+ # it contains rack-obama 1.0.0 and rack 0.9.1 & 1.0.0 amongst other gems
context "without source affinity" do
before do
- # Oh no! Someone evil is trying to hijack myrack :(
+ # Oh no! Someone evil is trying to hijack rack :(
# need this to be broken to check for correct source ordering
- build_repo3 do
- build_gem "myrack", repo3_myrack_version do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_repo gem_repo3 do
+ build_gem "rack", repo3_rack_version do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
end
context "with multiple toplevel sources" do
- let(:repo3_myrack_version) { "1.0.0" }
+ let(:repo3_rack_version) { "1.0.0" }
before do
gemfile <<-G
source "https://gem.repo3"
source "https://gem.repo1"
- gem "myrack-obama"
- gem "myrack"
+ gem "rack-obama"
+ gem "rack"
G
end
- it "refuses to install mismatched checksum because one gem has been tampered with", bundler: "< 3" do
- lockfile <<~L
- GEM
- remote: https://gem.repo3/
- remote: https://gem.repo1/
- specs:
- myrack (1.0.0)
-
- PLATFORMS
- #{local_platform}
-
- DEPENDENCIES
- depends_on_myrack!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle :install, artifice: "compact_index", raise_on_error: false
+ it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first", :bundler => "< 3" do
+ bundle :install, :artifice => "compact_index"
- expect(exitstatus).to eq(37)
- expect(err).to eq <<~E.strip
- [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source.
- Bundler found mismatched checksums. This is a potential security risk.
- #{checksum_to_lock(gem_repo1, "myrack", "1.0.0")}
- from the API at https://gem.repo1/
- #{checksum_to_lock(gem_repo3, "myrack", "1.0.0")}
- from the API at https://gem.repo3/
-
- Mismatched checksums each have an authoritative source:
- 1. the API at https://gem.repo1/
- 2. the API at https://gem.repo3/
- You may need to alter your Gemfile sources to resolve this issue.
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- E
+ expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(err).to include("Installed from: https://gem.repo1")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", :source => "remote1")
end
- context "when checksum validation is disabled" do
- before do
- bundle "config set --local disable_checksum_validation true"
- end
-
- it "warns about ambiguous gems, but installs anyway, prioritizing sources last to first", bundler: "< 3" do
- bundle :install, artifice: "compact_index"
-
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(err).to include("Installed from: https://gem.repo1")
- expect(the_bundle).to include_gems("myrack-obama 1.0.0", "myrack 1.0.0", source: "remote1")
- end
-
- it "does not use the full index unnecessarily", bundler: "< 3" do
- bundle :install, artifice: "compact_index", verbose: true
-
- expect(out).to include("https://gem.repo1/versions")
- expect(out).to include("https://gem.repo3/versions")
- expect(out).not_to include("https://gem.repo1/quick/Marshal.4.8/")
- expect(out).not_to include("https://gem.repo3/quick/Marshal.4.8/")
- end
-
- it "fails", bundler: "3" do
- bundle :install, artifice: "compact_index", raise_on_error: false
- expect(err).to include("Each source after the first must include a block")
- expect(exitstatus).to eq(4)
- end
+ it "fails", :bundler => "3" do
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
+ expect(err).to include("Each source after the first must include a block")
+ expect(exitstatus).to eq(4)
end
end
context "when different versions of the same gem are in multiple sources" do
- let(:repo3_myrack_version) { "1.2" }
+ let(:repo3_rack_version) { "1.2" }
before do
gemfile <<-G
source "https://gem.repo3"
source "https://gem.repo1"
- gem "myrack-obama"
- gem "myrack", "1.0.0" # force it to install the working version in repo1
+ gem "rack-obama"
+ gem "rack", "1.0.0" # force it to install the working version in repo1
G
end
- it "warns about ambiguous gems, but installs anyway", bundler: "< 3" do
- bundle :install, artifice: "compact_index"
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
+ it "warns about ambiguous gems, but installs anyway", :bundler => "< 3" do
+ bundle :install, :artifice => "compact_index"
+ expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).to include("Installed from: https://gem.repo1")
- expect(the_bundle).to include_gems("myrack-obama 1.0.0", "myrack 1.0.0", source: "remote1")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0", :source => "remote1")
end
- it "fails", bundler: "3" do
- bundle :install, artifice: "compact_index", raise_on_error: false
+ it "fails", :bundler => "3" do
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to include("Each source after the first must include a block")
expect(exitstatus).to eq(4)
end
end
end
- context "without source affinity, and a stdlib gem present in one of the sources", :ruby_repo do
- let(:default_json_version) { ruby "gem 'json'; require 'json'; puts JSON::VERSION" }
-
- before do
- build_repo2 do
- build_gem "json", default_json_version
- end
-
- build_repo4 do
- build_gem "foo" do |s|
- s.add_dependency "json", default_json_version
- end
- end
-
- gemfile <<-G
- source "https://gem.repo2"
- source "https://gem.repo4"
-
- gem "foo"
- G
- end
-
- it "works in standalone mode", bundler: "< 3" do
- gem_checksum = checksum_digest(gem_repo4, "foo", "1.0")
- bundle "install --standalone", artifice: "compact_index", env: { "BUNDLER_SPEC_FOO_CHECKSUM" => gem_checksum }
- end
- end
-
context "with source affinity" do
context "with sources given by a block" do
before do
- # Oh no! Someone evil is trying to hijack myrack :(
+ # Oh no! Someone evil is trying to hijack rack :(
# need this to be broken to check for correct source ordering
- build_repo3 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_repo gem_repo3 do
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
- build_gem "myrack-obama" do |s|
- s.add_dependency "myrack"
+ build_gem "rack-obama" do |s|
+ s.add_dependency "rack"
end
end
@@ -170,76 +88,76 @@ RSpec.describe "bundle install with gems on multiple sources" do
source "https://gem.repo3"
source "https://gem.repo1" do
gem "thin" # comes first to test name sorting
- gem "myrack"
+ gem "rack"
end
- gem "myrack-obama" # should come from repo3!
+ gem "rack-obama" # should come from repo3!
G
end
it "installs the gems without any warning" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("myrack-obama 1.0.0")
- expect(the_bundle).to include_gems("myrack 1.0.0", source: "remote1")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0", :source => "remote1")
end
it "can cache and deploy" do
- bundle :cache, artifice: "compact_index"
+ bundle :cache, :artifice => "compact_index"
- expect(bundled_app("vendor/cache/myrack-1.0.0.gem")).to exist
- expect(bundled_app("vendor/cache/myrack-obama-1.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-1.0.0.gem")).to exist
+ expect(bundled_app("vendor/cache/rack-obama-1.0.gem")).to exist
bundle "config set --local deployment true"
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
- expect(the_bundle).to include_gems("myrack-obama 1.0.0", "myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0")
end
end
context "with sources set by an option" do
before do
- # Oh no! Someone evil is trying to hijack myrack :(
+ # Oh no! Someone evil is trying to hijack rack :(
# need this to be broken to check for correct source ordering
- build_repo3 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_repo gem_repo3 do
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
- build_gem "myrack-obama" do |s|
- s.add_dependency "myrack"
+ build_gem "rack-obama" do |s|
+ s.add_dependency "rack"
end
end
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo3"
- gem "myrack-obama" # should come from repo3!
- gem "myrack", :source => "https://gem.repo1"
+ gem "rack-obama" # should come from repo3!
+ gem "rack", :source => "https://gem.repo1"
G
end
it "installs the gems without any warning" do
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("myrack-obama 1.0.0", "myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack-obama 1.0.0", "rack 1.0.0")
end
end
context "when a pinned gem has an indirect dependency in the pinned source" do
before do
- build_repo3 do
- build_gem "depends_on_myrack", "1.0.1" do |s|
- s.add_dependency "myrack"
+ build_repo gem_repo3 do
+ build_gem "depends_on_rack", "1.0.1" do |s|
+ s.add_dependency "rack"
end
end
- # we need a working myrack gem in repo3
+ # we need a working rack gem in repo3
update_repo gem_repo3 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
gemfile <<-G
source "https://gem.repo2"
source "https://gem.repo3" do
- gem "depends_on_myrack"
+ gem "depends_on_rack"
end
G
end
@@ -250,9 +168,9 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs from the same source without any warning" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
end
end
@@ -260,57 +178,57 @@ RSpec.describe "bundle install with gems on multiple sources" do
before do
# need this to be broken to check for correct source ordering
build_repo gem_repo2 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
end
it "installs from the same source without any warning" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
- expect(err).not_to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote3")
+ expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
# In https://github.com/bundler/bundler/issues/3585 this failed
# when there is already a lock file, and the gems are missing, so try again
system_gems []
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
- expect(err).not_to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote3")
+ expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
end
end
end
context "when a pinned gem has an indirect dependency in a different source" do
before do
- # In these tests, we need a working myrack gem in repo2 and not repo3
+ # In these tests, we need a working rack gem in repo2 and not repo3
- build_repo3 do
- build_gem "depends_on_myrack", "1.0.1" do |s|
- s.add_dependency "myrack"
+ build_repo gem_repo3 do
+ build_gem "depends_on_rack", "1.0.1" do |s|
+ s.add_dependency "rack"
end
end
build_repo gem_repo2 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
end
context "and not in any other sources" do
before do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo2"
source "https://gem.repo3" do
- gem "depends_on_myrack"
+ gem "depends_on_rack"
end
G
end
it "installs from the other source without any warning" do
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
end
end
@@ -320,138 +238,46 @@ RSpec.describe "bundle install with gems on multiple sources" do
source "https://gem.repo1"
source "https://gem.repo2"
source "https://gem.repo3" do
- gem "depends_on_myrack"
+ gem "depends_on_rack"
end
G
end
- it "fails when the two sources don't have the same checksum", bundler: "< 3" do
- bundle :install, artifice: "compact_index", raise_on_error: false
-
- expect(err).to eq(<<~E.strip)
- [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source.
- Bundler found mismatched checksums. This is a potential security risk.
- #{checksum_to_lock(gem_repo2, "myrack", "1.0.0")}
- from the API at https://gem.repo2/
- #{checksum_to_lock(gem_repo1, "myrack", "1.0.0")}
- from the API at https://gem.repo1/
-
- Mismatched checksums each have an authoritative source:
- 1. the API at https://gem.repo2/
- 2. the API at https://gem.repo1/
- You may need to alter your Gemfile sources to resolve this issue.
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- E
- expect(exitstatus).to eq(37)
- end
-
- it "fails when the two sources agree, but the local gem calculates a different checksum", bundler: "< 3" do
- myrack_checksum = "c0ffee11" * 8
- bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_MYRACK_CHECKSUM" => myrack_checksum }, raise_on_error: false
-
- expect(err).to eq(<<~E.strip)
- [DEPRECATED] Your Gemfile contains multiple global sources. Using `source` more than once without a block is a security risk, and may result in installing unexpected gems. To resolve this warning, use a block to indicate which gems should come from the secondary source.
- Bundler found mismatched checksums. This is a potential security risk.
- myrack (1.0.0) sha256=#{myrack_checksum}
- from the API at https://gem.repo2/
- and the API at https://gem.repo1/
- #{checksum_to_lock(gem_repo2, "myrack", "1.0.0")}
- from the gem at #{default_bundle_path("cache", "myrack-1.0.0.gem")}
-
- If you trust the API at https://gem.repo2/, to resolve this issue you can:
- 1. remove the gem at #{default_bundle_path("cache", "myrack-1.0.0.gem")}
- 2. run `bundle install`
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- E
- expect(exitstatus).to eq(37)
- end
-
- it "installs from the other source and warns about ambiguous gems when the sources have the same checksum", bundler: "< 3" do
- gem_checksum = checksum_digest(gem_repo2, "myrack", "1.0.0")
- bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_MYRACK_CHECKSUM" => gem_checksum, "DEBUG" => "1" }
-
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
+ it "installs from the other source and warns about ambiguous gems", :bundler => "< 3" do
+ bundle :install, :artifice => "compact_index"
+ expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).to include("Installed from: https://gem.repo2")
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo3, "depends_on_myrack", "1.0.1"
- c.checksum gem_repo2, "myrack", "1.0.0"
- end
-
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo1/
remote: https://gem.repo2/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
GEM
remote: https://gem.repo3/
specs:
- depends_on_myrack (1.0.1)
- myrack
+ depends_on_rack (1.0.1)
+ rack
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
- depends_on_myrack!
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- previous_lockfile = lockfile
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0")
- expect(lockfile).to eq(previous_lockfile)
- end
-
- it "installs from the other source and warns about ambiguous gems when checksum validation is disabled", bundler: "< 3" do
- bundle "config set --local disable_checksum_validation true"
- bundle :install, artifice: "compact_index"
-
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(err).to include("Installed from: https://gem.repo2")
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "depends_on_myrack", "1.0.1"
- c.no_checksum "myrack", "1.0.0"
- end
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo1/
- remote: https://gem.repo2/
- specs:
- myrack (1.0.0)
+ depends_on_rack!
- GEM
- remote: https://gem.repo3/
- specs:
- depends_on_myrack (1.0.1)
- myrack
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- depends_on_myrack!
- #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
previous_lockfile = lockfile
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
expect(lockfile).to eq(previous_lockfile)
end
- it "fails", bundler: "3" do
- bundle :install, artifice: "compact_index", raise_on_error: false
+ it "fails", :bundler => "3" do
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to include("Each source after the first must include a block")
expect(exitstatus).to eq(4)
end
@@ -461,37 +287,37 @@ RSpec.describe "bundle install with gems on multiple sources" do
before do
# need this to be broken to check for correct source ordering
build_repo gem_repo2 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
gemfile <<-G
- source "https://gem.repo3" # contains depends_on_myrack
- source "https://gem.repo2" # contains broken myrack
+ source "https://gem.repo3" # contains depends_on_rack
+ source "https://gem.repo2" # contains broken rack
- gem "depends_on_myrack" # installed from gem_repo3
- gem "myrack", :source => "https://gem.repo1"
+ gem "depends_on_rack" # installed from gem_repo3
+ gem "rack", :source => "https://gem.repo1"
G
end
- it "installs the dependency from the pinned source without warning", bundler: "< 3" do
- bundle :install, artifice: "compact_index"
+ it "installs the dependency from the pinned source without warning", :bundler => "< 3" do
+ bundle :install, :artifice => "compact_index"
- expect(err).not_to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0")
+ expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
# In https://github.com/rubygems/bundler/issues/3585 this failed
# when there is already a lock file, and the gems are missing, so try again
system_gems []
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
- expect(err).not_to include("Warning: the gem 'myrack' was found in multiple sources.")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0")
+ expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
end
- it "fails", bundler: "3" do
- bundle :install, artifice: "compact_index", raise_on_error: false
+ it "fails", :bundler => "3" do
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to include("Each source after the first must include a block")
expect(exitstatus).to eq(4)
end
@@ -502,7 +328,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
before do
build_repo2
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "private_gem_1", "1.0.0"
build_gem "private_gem_2", "1.0.0"
end
@@ -519,16 +345,16 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "fails" do
- bundle :install, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to include("Could not find gem 'private_gem_1' in rubygems repository https://gem.repo2/ or installed locally.")
end
end
- context "when an indirect dependency can't be found in the aggregate rubygems source", bundler: "< 3" do
+ context "when an indirect dependency can't be found in the aggregate rubygems source", :bundler => "< 3" do
before do
build_repo2
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "depends_on_missing", "1.0.1" do |s|
s.add_dependency "missing"
end
@@ -544,7 +370,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "fails" do
- bundle :install, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to end_with <<~E.strip
Could not find compatible versions
@@ -560,19 +386,19 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "when a top-level gem has an indirect dependency" do
before do
build_repo gem_repo2 do
- build_gem "depends_on_myrack", "1.0.1" do |s|
- s.add_dependency "myrack"
+ build_gem "depends_on_rack", "1.0.1" do |s|
+ s.add_dependency "rack"
end
end
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "unrelated_gem", "1.0.0"
end
gemfile <<-G
source "https://gem.repo2"
- gem "depends_on_myrack"
+ gem "depends_on_rack"
source "https://gem.repo3" do
gem "unrelated_gem"
@@ -583,37 +409,37 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "and the dependency is only in the top-level source" do
before do
update_repo gem_repo2 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
end
it "installs the dependency from the top-level source without warning" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", "unrelated_gem 1.0.0")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote2")
- expect(the_bundle).to include_gems("unrelated_gem 1.0.0", source: "remote3")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote2")
+ expect(the_bundle).to include_gems("unrelated_gem 1.0.0", :source => "remote3")
end
end
context "and the dependency is only in a pinned source" do
before do
update_repo gem_repo3 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
end
it "does not find the dependency" do
- bundle :install, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to end_with <<~E.strip
Could not find compatible versions
- Because every version of depends_on_myrack depends on myrack >= 0
- and myrack >= 0 could not be found in rubygems repository https://gem.repo2/ or installed locally,
- depends_on_myrack cannot be used.
- So, because Gemfile depends on depends_on_myrack >= 0,
+ Because every version of depends_on_rack depends on rack >= 0
+ and rack >= 0 could not be found in rubygems repository https://gem.repo2/ or installed locally,
+ depends_on_rack cannot be used.
+ So, because Gemfile depends on depends_on_rack >= 0,
version solving has failed.
E
end
@@ -622,36 +448,36 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "and the dependency is in both the top-level and a pinned source" do
before do
update_repo gem_repo2 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
update_repo gem_repo3 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
end
it "installs the dependency from the top-level source without warning" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).not_to include("Warning")
- expect(run("require 'myrack'; puts MYRACK")).to eq("1.0.0")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", "unrelated_gem 1.0.0")
- expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote2")
- expect(the_bundle).to include_gems("unrelated_gem 1.0.0", source: "remote3")
+ expect(run("require 'rack'; puts RACK")).to eq("1.0.0")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", "unrelated_gem 1.0.0")
+ expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote2")
+ expect(the_bundle).to include_gems("unrelated_gem 1.0.0", :source => "remote3")
end
end
end
context "when a scoped gem has a deeply nested indirect dependency" do
before do
- build_repo3 do
- build_gem "depends_on_depends_on_myrack", "1.0.1" do |s|
- s.add_dependency "depends_on_myrack"
+ build_repo gem_repo3 do
+ build_gem "depends_on_depends_on_rack", "1.0.1" do |s|
+ s.add_dependency "depends_on_rack"
end
- build_gem "depends_on_myrack", "1.0.1" do |s|
- s.add_dependency "myrack"
+ build_gem "depends_on_rack", "1.0.1" do |s|
+ s.add_dependency "rack"
end
end
@@ -659,7 +485,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
source "https://gem.repo2"
source "https://gem.repo3" do
- gem "depends_on_depends_on_myrack"
+ gem "depends_on_depends_on_rack"
end
G
end
@@ -667,15 +493,15 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "and the dependency is only in the top-level source" do
before do
update_repo gem_repo2 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
end
it "installs the dependency from the top-level source" do
- bundle :install, artifice: "compact_index"
- expect(the_bundle).to include_gems("depends_on_depends_on_myrack 1.0.1", "depends_on_myrack 1.0.1", "myrack 1.0.0")
- expect(the_bundle).to include_gems("myrack 1.0.0", source: "remote2")
- expect(the_bundle).to include_gems("depends_on_depends_on_myrack 1.0.1", "depends_on_myrack 1.0.1", source: "remote3")
+ bundle :install, :artifice => "compact_index"
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0", :source => "remote2")
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", :source => "remote3")
end
end
@@ -684,32 +510,32 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_repo2
update_repo gem_repo3 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
end
it "installs the dependency from the pinned source" do
- bundle :install, artifice: "compact_index"
- expect(the_bundle).to include_gems("depends_on_depends_on_myrack 1.0.1", "depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote3")
+ bundle :install, :artifice => "compact_index"
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
end
end
context "and the dependency is in both the top-level and a pinned source" do
before do
update_repo gem_repo2 do
- build_gem "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
update_repo gem_repo3 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
end
it "installs the dependency from the pinned source without warning" do
- bundle :install, artifice: "compact_index"
- expect(the_bundle).to include_gems("depends_on_depends_on_myrack 1.0.1", "depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote3")
+ bundle :install, :artifice => "compact_index"
+ expect(the_bundle).to include_gems("depends_on_depends_on_rack 1.0.1", "depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
end
end
end
@@ -742,12 +568,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
build_gem "minitest", "5.14.3"
- build_gem "myrack", "2.2.3"
+ build_gem "rack", "2.2.3"
build_gem "redis", "4.2.5"
build_gem "sidekiq", "6.1.3" do |s|
s.add_dependency "connection_pool", ">= 2.2.2"
- s.add_dependency "myrack", "~> 2.0"
+ s.add_dependency "rack", "~> 2.0"
s.add_dependency "redis", ">= 4.2.0"
end
@@ -764,7 +590,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "zeitwerk", "2.4.2"
end
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "sidekiq-pro", "5.2.1" do |s|
s.add_dependency "connection_pool", ">= 2.2.3"
s.add_dependency "sidekiq", ">= 6.1.0"
@@ -783,21 +609,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
- @locked_checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "activesupport", "6.0.3.4"
- c.checksum gem_repo2, "concurrent-ruby", "1.1.8"
- c.checksum gem_repo2, "connection_pool", "2.2.3"
- c.checksum gem_repo2, "i18n", "1.8.9"
- c.checksum gem_repo2, "minitest", "5.14.3"
- c.checksum gem_repo2, "myrack", "2.2.3"
- c.checksum gem_repo2, "redis", "4.2.5"
- c.checksum gem_repo2, "sidekiq", "6.1.3"
- c.checksum gem_repo3, "sidekiq-pro", "5.2.1"
- c.checksum gem_repo2, "thread_safe", "0.3.6"
- c.checksum gem_repo2, "tzinfo", "1.2.9"
- c.checksum gem_repo2, "zeitwerk", "2.4.2"
- end
-
lockfile <<~L
GEM
remote: https://gem.repo2/
@@ -814,11 +625,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
i18n (1.8.9)
concurrent-ruby (~> 1.0)
minitest (5.14.3)
- myrack (2.2.3)
+ rack (2.2.3)
redis (4.2.5)
sidekiq (6.1.3)
connection_pool (>= 2.2.2)
- myrack (~> 2.0)
+ rack (~> 2.0)
redis (>= 4.2.0)
sidekiq-pro (5.2.1)
connection_pool (>= 2.2.3)
@@ -829,19 +640,19 @@ RSpec.describe "bundle install with gems on multiple sources" do
zeitwerk (2.4.2)
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
activesupport
sidekiq-pro!
- #{@locked_checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "does not install newer versions but updates the lockfile format when running bundle install in non frozen mode, and doesn't warn" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).to be_empty
expect(the_bundle).to include_gems("activesupport 6.0.3.4")
@@ -866,11 +677,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
i18n (1.8.9)
concurrent-ruby (~> 1.0)
minitest (5.14.3)
- myrack (2.2.3)
+ rack (2.2.3)
redis (4.2.5)
sidekiq (6.1.3)
connection_pool (>= 2.2.2)
- myrack (~> 2.0)
+ rack (~> 2.0)
redis (>= 4.2.0)
thread_safe (0.3.6)
tzinfo (1.2.9)
@@ -885,22 +696,22 @@ RSpec.describe "bundle install with gems on multiple sources" do
sidekiq (>= 6.1.0)
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
activesupport
sidekiq-pro!
- #{@locked_checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
- it "does not install newer versions or generate lockfile changes when running bundle install in frozen mode, and warns", bundler: "< 3" do
+ it "does not install newer versions or generate lockfile changes when running bundle install in frozen mode, and warns", :bundler => "< 3" do
initial_lockfile = lockfile
bundle "config set --local frozen true"
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
@@ -914,11 +725,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(lockfile).to eq(initial_lockfile)
end
- it "fails when running bundle install in frozen mode", bundler: "3" do
+ it "fails when running bundle install in frozen mode", :bundler => "3" do
initial_lockfile = lockfile
bundle "config set --local frozen true"
- bundle :install, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
@@ -926,21 +737,15 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "splits sections and upgrades gems when running bundle update, and doesn't warn" do
- bundle "update --all", artifice: "compact_index"
+ bundle "update --all", :artifice => "compact_index"
expect(err).to be_empty
expect(the_bundle).not_to include_gems("activesupport 6.0.3.4")
expect(the_bundle).to include_gems("activesupport 6.1.2.1")
- @locked_checksums.checksum gem_repo2, "activesupport", "6.1.2.1"
-
expect(the_bundle).not_to include_gems("tzinfo 1.2.9")
expect(the_bundle).to include_gems("tzinfo 2.0.4")
- @locked_checksums.checksum gem_repo2, "tzinfo", "2.0.4"
- @locked_checksums.delete "thread_safe"
-
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
- @locked_checksums.checksum gem_repo2, "concurrent-ruby", "1.1.9"
expect(lockfile).to eq <<~L
GEM
@@ -957,11 +762,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
i18n (1.8.9)
concurrent-ruby (~> 1.0)
minitest (5.14.3)
- myrack (2.2.3)
+ rack (2.2.3)
redis (4.2.5)
sidekiq (6.1.3)
connection_pool (>= 2.2.2)
- myrack (~> 2.0)
+ rack (~> 2.0)
redis (>= 4.2.0)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
@@ -975,19 +780,19 @@ RSpec.describe "bundle install with gems on multiple sources" do
sidekiq (>= 6.1.0)
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
activesupport
sidekiq-pro!
- #{@locked_checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "upgrades the lockfile format and upgrades the requested gem when running bundle update with an argument" do
- bundle "update concurrent-ruby", artifice: "compact_index"
+ bundle "update concurrent-ruby", :artifice => "compact_index"
expect(err).to be_empty
expect(the_bundle).to include_gems("activesupport 6.0.3.4")
@@ -997,8 +802,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
- @locked_checksums.checksum gem_repo2, "concurrent-ruby", "1.1.9"
-
expect(lockfile).to eq <<~L
GEM
remote: https://gem.repo2/
@@ -1014,11 +817,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
i18n (1.8.9)
concurrent-ruby (~> 1.0)
minitest (5.14.3)
- myrack (2.2.3)
+ rack (2.2.3)
redis (4.2.5)
sidekiq (6.1.3)
connection_pool (>= 2.2.2)
- myrack (~> 2.0)
+ rack (~> 2.0)
redis (>= 4.2.0)
thread_safe (0.3.6)
tzinfo (1.2.9)
@@ -1033,12 +836,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
sidekiq (>= 6.1.0)
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
activesupport
sidekiq-pro!
- #{@locked_checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1047,8 +850,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "when a top-level gem has an indirect dependency present in the default source, but with a different version from the one resolved" do
before do
- build_lib "activesupport", "7.0.0.alpha", path: lib_path("rails/activesupport")
- build_lib "rails", "7.0.0.alpha", path: lib_path("rails") do |s|
+ build_lib "activesupport", "7.0.0.alpha", :path => lib_path("rails/activesupport")
+ build_lib "rails", "7.0.0.alpha", :path => lib_path("rails") do |s|
s.add_dependency "activesupport", "= 7.0.0.alpha"
end
@@ -1070,17 +873,17 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs all gems without warning" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", "rails 7.0.0.alpha")
- expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", source: "path@#{lib_path("rails/activesupport")}")
- expect(the_bundle).to include_gems("rails 7.0.0.alpha", source: "path@#{lib_path("rails")}")
+ expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", :source => "path@#{lib_path("rails/activesupport")}")
+ expect(the_bundle).to include_gems("rails 7.0.0.alpha", :source => "path@#{lib_path("rails")}")
end
end
context "when a pinned gem has an indirect dependency with more than one level of indirection in the default source " do
before do
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "handsoap", "0.2.5.5" do |s|
s.add_dependency "nokogiri", ">= 1.2.3"
end
@@ -1106,12 +909,6 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "installs from the default source without any warnings or errors and generates a proper lockfile" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo3, "handsoap", "0.2.5.5"
- c.checksum gem_repo2, "nokogiri", "1.11.1"
- c.checksum gem_repo2, "racca", "1.5.2"
- end
-
expected_lockfile = <<~L
GEM
remote: https://gem.repo2/
@@ -1127,41 +924,41 @@ RSpec.describe "bundle install with gems on multiple sources" do
nokogiri (>= 1.2.3)
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
handsoap!
nokogiri
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
- bundle "install --verbose", artifice: "compact_index"
+ bundle "install --verbose", :artifice => "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2")
- expect(the_bundle).to include_gems("handsoap 0.2.5.5", source: "remote3")
- expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", source: "remote2")
+ expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3")
+ expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2")
expect(lockfile).to eq(expected_lockfile)
# Even if the gems are already installed
FileUtils.rm bundled_app_lock
- bundle "install --verbose", artifice: "compact_index"
+ bundle "install --verbose", :artifice => "compact_index"
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2")
- expect(the_bundle).to include_gems("handsoap 0.2.5.5", source: "remote3")
- expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", source: "remote2")
+ expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3")
+ expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2")
expect(lockfile).to eq(expected_lockfile)
end
end
context "with a gem that is only found in the wrong source" do
before do
- build_repo3 do
+ build_repo gem_repo3 do
build_gem "not_in_repo1", "1.0.0"
end
- install_gemfile <<-G, artifice: "compact_index", raise_on_error: false
+ install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false
source "https://gem.repo3"
gem "not_in_repo1", :source => "https://gem.repo1"
G
@@ -1174,7 +971,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "with an existing lockfile" do
before do
- system_gems "myrack-0.9.1", "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-0.9.1", "rack-1.0.0", :path => default_bundle_path
lockfile <<-L
GEM
@@ -1184,26 +981,26 @@ RSpec.describe "bundle install with gems on multiple sources" do
GEM
remote: https://gem.repo3
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
- myrack!
+ rack!
L
gemfile <<-G
source "https://gem.repo1"
source "https://gem.repo3" do
- gem 'myrack'
+ gem 'rack'
end
G
end
# Reproduction of https://github.com/rubygems/bundler/issues/3298
it "does not unlock the installed gem on exec" do
- expect(the_bundle).to include_gems("myrack 0.9.1")
+ expect(the_bundle).to include_gems("rack 0.9.1")
end
end
@@ -1214,14 +1011,14 @@ RSpec.describe "bundle install with gems on multiple sources" do
remote: https://gem.repo1/
remote: https://gem.repo3/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
- myrack!
- #{checksums_section}
+ rack!
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1236,13 +1033,13 @@ RSpec.describe "bundle install with gems on multiple sources" do
GEM
remote: https://gem.repo3/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
- myrack!
+ rack!
BUNDLED WITH
#{Bundler::VERSION}
@@ -1250,62 +1047,34 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
before do
- build_repo3 do
- build_gem "myrack", "0.9.1"
+ build_repo gem_repo3 do
+ build_gem "rack", "0.9.1"
end
gemfile <<-G
source "https://gem.repo1"
source "https://gem.repo3" do
- gem 'myrack'
+ gem 'rack'
end
G
lockfile aggregate_gem_section_lockfile
end
- it "installs the existing lockfile but prints a warning when checksum validation is disabled", bundler: "< 3" do
+ it "installs the existing lockfile but prints a warning", :bundler => "< 3" do
bundle "config set --local deployment true"
- bundle "config set --local disable_checksum_validation true"
- bundle "install", artifice: "compact_index"
+ bundle "install", :artifice => "compact_index"
expect(lockfile).to eq(aggregate_gem_section_lockfile)
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
- expect(the_bundle).to include_gems("myrack 0.9.1", source: "remote3")
- end
-
- it "prints a checksum warning when the checksums from both sources do not match", bundler: "< 3" do
- bundle "config set --local deployment true"
-
- bundle "install", artifice: "compact_index", raise_on_error: false
-
- api_checksum1 = checksum_digest(gem_repo1, "myrack", "0.9.1")
- api_checksum3 = checksum_digest(gem_repo3, "myrack", "0.9.1")
-
- expect(exitstatus).to eq(37)
- expect(err).to eq(<<~E.strip)
- [DEPRECATED] Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure.
- Bundler found mismatched checksums. This is a potential security risk.
- myrack (0.9.1) sha256=#{api_checksum3}
- from the API at https://gem.repo3/
- myrack (0.9.1) sha256=#{api_checksum1}
- from the API at https://gem.repo1/
-
- Mismatched checksums each have an authoritative source:
- 1. the API at https://gem.repo3/
- 2. the API at https://gem.repo1/
- You may need to alter your Gemfile sources to resolve this issue.
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- E
+ expect(the_bundle).to include_gems("rack 0.9.1", :source => "remote3")
end
- it "refuses to install the existing lockfile and prints an error", bundler: "3" do
+ it "refuses to install the existing lockfile and prints an error", :bundler => "3" do
bundle "config set --local deployment true"
- bundle "install", artifice: "compact_index", raise_on_error: false
+ bundle "install", :artifice => "compact_index", :raise_on_error =>false
expect(lockfile).to eq(aggregate_gem_section_lockfile)
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
@@ -1318,14 +1087,14 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_lib "foo"
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :source => "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :source => "https://gem.repo1"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
end
it "does not unlock the non-path gem after install" do
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
bundle %(exec ruby -e 'puts "OK"')
@@ -1336,17 +1105,17 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "when an older version of the same gem also ships with Ruby" do
before do
- system_gems "myrack-0.9.1"
+ system_gems "rack-0.9.1"
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo1"
- gem "myrack" # should come from repo1!
+ gem "rack" # should come from repo1!
G
end
it "installs the gems without any warning" do
expect(err).not_to include("Warning")
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
end
@@ -1361,13 +1130,13 @@ RSpec.describe "bundle install with gems on multiple sources" do
# Installing this gemfile...
gemfile <<-G
source 'https://gem.repo1'
- gem 'myrack'
+ gem 'rack'
gem 'foo', '~> 0.1', :source => 'https://gem.repo4'
gem 'bar', '~> 0.1', :source => 'https://gem.repo4'
G
bundle "config set --local path ../gems/system"
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
# And then we add some new versions...
update_repo4 do
@@ -1378,9 +1147,9 @@ RSpec.describe "bundle install with gems on multiple sources" do
it "allows them to be unlocked separately" do
# And install this gemfile, updating only foo.
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source 'https://gem.repo1'
- gem 'myrack'
+ gem 'rack'
gem 'foo', '~> 0.2', :source => 'https://gem.repo4'
gem 'bar', '~> 0.1', :source => 'https://gem.repo4'
G
@@ -1393,8 +1162,8 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "re-resolving" do
context "when there is a mix of sources in the gemfile" do
before do
- build_repo3 do
- build_gem "myrack"
+ build_repo gem_repo3 do
+ build_gem "rack"
end
build_lib "path1"
@@ -1402,12 +1171,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_git "git1"
build_git "git2"
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo1"
gem "rails"
source "https://gem.repo3" do
- gem "myrack"
+ gem "rack"
end
gem "path1", :path => "#{lib_path("path1-1.0")}"
@@ -1418,7 +1187,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
it "does not re-resolve" do
- bundle :install, artifice: "compact_index", verbose: true
+ bundle :install, :artifice => "compact_index", :verbose => true
expect(out).to include("using resolution from the lockfile")
expect(out).not_to include("re-resolving dependencies")
end
@@ -1427,28 +1196,28 @@ RSpec.describe "bundle install with gems on multiple sources" do
context "when a gem is installed to system gems" do
before do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo1"
- gem "myrack"
+ gem "rack"
G
end
context "and the gemfile changes" do
it "is still able to find that gem from remote sources" do
build_repo4 do
- build_gem "myrack", "2.0.1.1.forked"
+ build_gem "rack", "2.0.1.1.forked"
build_gem "thor", "0.19.1.1.forked"
end
# When this gemfile is installed...
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo1"
source "https://gem.repo4" do
- gem "myrack", "2.0.1.1.forked"
+ gem "rack", "2.0.1.1.forked"
gem "thor"
end
- gem "myrack-obama"
+ gem "rack-obama"
G
# Then we change the Gemfile by adding a version to thor
@@ -1456,47 +1225,47 @@ RSpec.describe "bundle install with gems on multiple sources" do
source "https://gem.repo1"
source "https://gem.repo4" do
- gem "myrack", "2.0.1.1.forked"
+ gem "rack", "2.0.1.1.forked"
gem "thor", "0.19.1.1.forked"
end
- gem "myrack-obama"
+ gem "rack-obama"
G
- # But we should still be able to find myrack 2.0.1.1.forked and install it
- bundle :install, artifice: "compact_index"
+ # But we should still be able to find rack 2.0.1.1.forked and install it
+ bundle :install, :artifice => "compact_index"
end
end
end
describe "source changed to one containing a higher version of a dependency" do
before do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo1"
- gem "myrack"
+ gem "rack"
G
build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
build_gem "bar"
end
- build_lib("gemspec_test", path: tmp("gemspec_test")) do |s|
+ build_lib("gemspec_test", :path => tmp.join("gemspec_test")) do |s|
s.add_dependency "bar", "=1.0.0"
end
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo2"
- gem "myrack"
- gemspec :path => "#{tmp("gemspec_test")}"
+ gem "rack"
+ gemspec :path => "#{tmp.join("gemspec_test")}"
G
end
it "conservatively installs the existing locked version" do
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0")
end
end
@@ -1506,18 +1275,18 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "bar"
end
- build_lib("gemspec_test", path: tmp("gemspec_test")) do |s|
+ build_lib("gemspec_test", :path => tmp.join("gemspec_test")) do |s|
s.add_development_dependency "bar"
end
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo1"
source "https://gem.repo4" do
gem "bar"
end
- gemspec :path => "#{tmp("gemspec_test")}"
+ gemspec :path => "#{tmp.join("gemspec_test")}"
G
end
@@ -1535,7 +1304,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "example", "1.0.2"
end
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "https://gem.repo4"
gem "example", :source => "https://gem.repo2"
@@ -1544,9 +1313,9 @@ RSpec.describe "bundle install with gems on multiple sources" do
bundle "info example"
expect(out).to include("example (0.1.0)")
- system_gems "example-1.0.2", path: default_bundle_path, gem_repo: gem_repo4
+ system_gems "example-1.0.2", :path => default_bundle_path, :gem_repo => gem_repo4
- bundle "update example --verbose", artifice: "compact_index"
+ bundle "update example --verbose", :artifice => "compact_index"
expect(out).not_to include("Using example 1.0.2")
expect(out).to include("Using example 0.1.0")
end
@@ -1560,9 +1329,11 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
- ruby <<~R, raise_on_error: false
- require 'bundler/setup'
- R
+ simulate_bundler_version_when_missing_prerelease_default_gem_activation do
+ ruby <<~R, :raise_on_error => false
+ require 'bundler/setup'
+ R
+ end
expect(last_command).to be_failure
expect(err).to include("Could not find gem 'example' in locally installed gems.")
@@ -1577,36 +1348,36 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
G
- bundle "install", artifice: nil, raise_on_error: false
+ bundle "install", :artifice => nil, :raise_on_error => false
expect(last_command).to be_failure
expect(err).to include("Could not reach host gem.repo4. Check your network connection and try again.")
end
- context "when an indirect dependency is available from multiple ambiguous sources", bundler: "< 3" do
+ context "when an indirect dependency is available from multiple ambiguous sources", :bundler => "< 3" do
it "succeeds but warns, suggesting a source block" do
build_repo4 do
- build_gem "depends_on_myrack" do |s|
- s.add_dependency "myrack"
+ build_gem "depends_on_rack" do |s|
+ s.add_dependency "rack"
end
- build_gem "myrack"
+ build_gem "rack"
end
- install_gemfile <<-G, artifice: "compact_index_extra_api", raise_on_error: false
- source "https://global.source"
+ install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
- source "https://scoped.source/extra" do
- gem "depends_on_myrack"
+ source "https://gem.repo4" do
+ gem "depends_on_rack"
end
- source "https://scoped.source" do
+ source "https://gem.repo1" do
gem "thin"
end
G
- expect(err).to eq <<~EOS.strip
- Warning: The gem 'myrack' was found in multiple relevant sources.
- * rubygems repository https://scoped.source/
- * rubygems repository https://scoped.source/extra/
+ expect(err).to eq strip_whitespace(<<-EOS).strip
+ Warning: The gem 'rack' was found in multiple relevant sources.
+ * rubygems repository https://gem.repo1/
+ * rubygems repository https://gem.repo4/
You should add this gem to the source block for the source you wish it to be installed from.
EOS
expect(last_command).to be_success
@@ -1614,31 +1385,29 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
end
- context "when an indirect dependency is available from multiple ambiguous sources", bundler: "3" do
+ context "when an indirect dependency is available from multiple ambiguous sources", :bundler => "3" do
it "raises, suggesting a source block" do
build_repo4 do
- build_gem "depends_on_myrack" do |s|
- s.add_dependency "myrack"
+ build_gem "depends_on_rack" do |s|
+ s.add_dependency "rack"
end
- build_gem "myrack"
+ build_gem "rack"
end
- install_gemfile <<-G, artifice: "compact_index_extra_api", raise_on_error: false
- source "https://global.source"
-
- source "https://scoped.source/extra" do
- gem "depends_on_myrack"
+ install_gemfile <<-G, :artifice => "compact_index", :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
+ source "https://gem.repo4" do
+ gem "depends_on_rack"
end
-
- source "https://scoped.source" do
+ source "https://gem.repo1" do
gem "thin"
end
G
expect(last_command).to be_failure
- expect(err).to eq <<~EOS.strip
- The gem 'myrack' was found in multiple relevant sources.
- * rubygems repository https://scoped.source/
- * rubygems repository https://scoped.source/extra/
+ expect(err).to eq strip_whitespace(<<-EOS).strip
+ The gem 'rack' was found in multiple relevant sources.
+ * rubygems repository https://gem.repo1/
+ * rubygems repository https://gem.repo4/
You must add this gem to the source block for the source you wish it to be installed from.
EOS
expect(the_bundle).not_to be_locked
@@ -1679,23 +1448,16 @@ RSpec.describe "bundle install with gems on multiple sources" do
mime-types (3.3.1)
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
capybara (~> 2.5.0)
mime-types (~> 3.0)!
-
- CHECKSUMS
L
end
it "upgrades the lockfile correctly" do
- bundle "lock --update", artifice: "compact_index"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "capybara", "2.5.0"
- c.checksum gem_repo4, "mime-types", "3.0.0"
- end
+ bundle "lock --update", :artifice => "compact_index"
expect(lockfile).to eq <<~L
GEM
@@ -1710,12 +1472,12 @@ RSpec.describe "bundle install with gems on multiple sources" do
mime-types (3.0.0)
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
capybara (~> 2.5.0)
mime-types (~> 3.0)!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1742,38 +1504,33 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "https://localgemserver.test"
- gem "ruport", "= 1.7.0.3", :source => "https://gem.repo4/extra"
+ gem "ruport", "= 1.7.0.3", :source => "https://localgemserver.test/extra"
G
end
it "handles that fine" do
- bundle "install", artifice: "compact_index_extra"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "pdf-writer", "1.1.8"
- c.checksum gem_repo2, "ruport", "1.7.0.3"
- end
+ bundle "install", :artifice => "compact_index_extra", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: https://localgemserver.test/
specs:
pdf-writer (1.1.8)
GEM
- remote: https://gem.repo4/extra/
+ remote: https://localgemserver.test/extra/
specs:
ruport (1.7.0.3)
pdf-writer (= 1.1.8)
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
ruport (= 1.7.0.3)!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1800,38 +1557,33 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "https://localgemserver.test"
- gem "ruport", "= 1.7.0.3", :source => "https://gem.repo4/extra"
+ gem "ruport", "= 1.7.0.3", :source => "https://localgemserver.test/extra"
G
end
it "handles that fine" do
- bundle "install", artifice: "compact_index_extra"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "pdf-writer", "1.1.8"
- c.checksum gem_repo2, "ruport", "1.7.0.3"
- end
+ bundle "install", :artifice => "compact_index_extra", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: https://localgemserver.test/
specs:
pdf-writer (1.1.8)
GEM
- remote: https://gem.repo4/extra/
+ remote: https://localgemserver.test/extra/
specs:
ruport (1.7.0.3)
pdf-writer (= 1.1.8)
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
ruport (= 1.7.0.3)!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1852,31 +1604,27 @@ RSpec.describe "bundle install with gems on multiple sources" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "https://localgemserver.test"
gem "pdf-writer", "= 1.1.8"
G
end
it "handles that fine" do
- bundle "install --verbose", artifice: "endpoint"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "pdf-writer", "1.1.8"
- end
+ bundle "install --verbose", :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: https://localgemserver.test/
specs:
pdf-writer (1.1.8)
PLATFORMS
- #{lockfile_platforms}
+ #{local_platform}
DEPENDENCIES
pdf-writer (= 1.1.8)
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1895,7 +1643,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
build_gem "example", "1.0.0"
end
- install_gemfile <<~G, artifice: "compact_index"
+ install_gemfile <<~G, :artifice => "compact_index"
source "https://gem.repo2"
source "https://gem.repo4" do
@@ -1915,76 +1663,10 @@ RSpec.describe "bundle install with gems on multiple sources" do
it "shows a proper error message and does not generate a corrupted lockfile" do
expect do
- bundle :install, artifice: "compact_index", raise_on_error: false, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ bundle :install, :artifice => "compact_index", :raise_on_error => false, :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
end.not_to change { lockfile }
expect(err).to include("Could not find gem 'example' in rubygems repository https://gem.repo4/")
end
end
-
- context "when a gem has versions in two sources, but only the locked one has updates" do
- let(:original_lockfile) do
- <<~L
- GEM
- remote: https://main.source/
- specs:
- activesupport (1.0)
- bigdecimal
- bigdecimal (1.0.0)
-
- GEM
- remote: https://main.source/extra/
- specs:
- foo (1.0)
- bigdecimal
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- activesupport
- foo!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- before do
- build_repo3 do
- build_gem "activesupport" do |s|
- s.add_dependency "bigdecimal"
- end
-
- build_gem "bigdecimal", "1.0.0"
- build_gem "bigdecimal", "3.3.1"
- end
-
- build_repo4 do
- build_gem "foo" do |s|
- s.add_dependency "bigdecimal"
- end
-
- build_gem "bigdecimal", "1.0.0"
- end
-
- gemfile <<~G
- source "https://main.source"
-
- gem "activesupport"
-
- source "https://main.source/extra" do
- gem "foo"
- end
- G
-
- lockfile original_lockfile
- end
-
- it "properly upgrades the lockfile when updating that specific gem" do
- bundle "update bigdecimal --conservative", artifice: "compact_index_extra_api", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo3.to_s }
-
- expect(lockfile).to eq original_lockfile.gsub("bigdecimal (1.0.0)", "bigdecimal (3.3.1)")
- end
- end
end
diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb
index a1feadb113..cab53a663a 100644
--- a/spec/bundler/install/gemfile/specific_platform_spec.rb
+++ b/spec/bundler/install/gemfile/specific_platform_spec.rb
@@ -2,7 +2,7 @@
RSpec.describe "bundle install with specific platforms" do
let(:google_protobuf) { <<-G }
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "google-protobuf"
G
@@ -11,11 +11,11 @@ RSpec.describe "bundle install with specific platforms" do
setup_multiplatform_gem
install_gemfile(google_protobuf)
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- expect(the_bundle.locked_gems.platforms).to include(pl("x86_64-darwin-15"))
+ expect(the_bundle.locked_gems.platforms).to eq([pl("x86_64-darwin-15")])
expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin")
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to include(
- "google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin"
- )
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[
+ google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin
+ ])
end
end
@@ -26,14 +26,14 @@ RSpec.describe "bundle install with specific platforms" do
system_gems "bundler-2.1.4"
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle", env: { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "config set --local path vendor/bundle", :env => { "BUNDLER_VERSION" => "2.1.4" }
- install_gemfile(google_protobuf, env: { "BUNDLER_VERSION" => "2.1.4" })
+ install_gemfile(google_protobuf, :env => { "BUNDLER_VERSION" => "2.1.4" })
# simulate lockfile created with old bundler, which only locks for ruby platform
lockfile <<-L
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
google-protobuf (3.0.0.alpha.5.0.5.1)
@@ -48,32 +48,28 @@ RSpec.describe "bundle install with specific platforms" do
L
# force strict usage of the lock file by setting frozen mode
- bundle "config set --local frozen true", env: { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "config set --local frozen true", :env => { "BUNDLER_VERSION" => "2.1.4" }
# make sure the platform that got actually installed with the old bundler is used
expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin")
end
end
- it "understands that a non-platform specific gem in a new lockfile locked only to ruby doesn't necessarily mean installing the non-specific variant" do
+ it "understands that a non-platform specific gem in a new lockfile locked only to RUBY doesn't necessarily mean installing the non-specific variant" do
simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem
system_gems "bundler-2.1.4"
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle", env: { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "config set --local path vendor/bundle", :env => { "BUNDLER_VERSION" => "2.1.4" }
gemfile google_protobuf
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "google-protobuf", "3.0.0.alpha.4.0"
- end
-
# simulate lockfile created with old bundler, which only locks for ruby platform
lockfile <<-L
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
google-protobuf (3.0.0.alpha.4.0)
@@ -82,14 +78,12 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
google-protobuf
- #{checksums}
+
BUNDLED WITH
2.1.4
L
- bundle "update", env: { "BUNDLER_VERSION" => Bundler::VERSION }
-
- checksums.checksum gem_repo2, "google-protobuf", "3.0.0.alpha.5.0.5.1"
+ bundle "update", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
# make sure the platform that the platform specific dependency is used, since we're only locked to ruby
expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin")
@@ -97,7 +91,7 @@ RSpec.describe "bundle install with specific platforms" do
# make sure we're still only locked to ruby
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
google-protobuf (3.0.0.alpha.5.0.5.1)
@@ -106,14 +100,14 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
google-protobuf
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
end
- context "when running on a legacy lockfile locked only to ruby" do
+ context "when running on a legacy lockfile locked only to RUBY" do
around do |example|
build_repo4 do
build_gem "nokogiri", "1.3.10"
@@ -124,14 +118,14 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "nokogiri"
G
lockfile <<-L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.3.10)
@@ -148,13 +142,13 @@ RSpec.describe "bundle install with specific platforms" do
simulate_platform "arm64-darwin-22", &example
end
- it "still installs the generic ruby variant if necessary" do
- bundle "install --verbose"
+ it "still installs the generic RUBY variant if necessary" do
+ bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
expect(out).to include("Installing nokogiri 1.3.10")
end
- it "still installs the generic ruby variant if necessary, even in frozen mode" do
- bundle "install --verbose", env: { "BUNDLE_FROZEN" => "true" }
+ it "still installs the generic RUBY variant if necessary, even in frozen mode" do
+ bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s, "BUNDLE_FROZEN" => "true" }
expect(out).to include("Installing nokogiri 1.3.10")
end
end
@@ -166,24 +160,24 @@ RSpec.describe "bundle install with specific platforms" do
build_gem("libv8", "8.4.255.0") {|s| s.platform = "universal-darwin" }
build_gem("mini_racer", "1.0.0") do |s|
- s.add_dependency "libv8"
+ s.add_runtime_dependency "libv8"
end
end
system_gems "bundler-2.1.4"
# Consistent location to install and look for gems
- bundle "config set --local path vendor/bundle", env: { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "config set --local path vendor/bundle", :env => { "BUNDLER_VERSION" => "2.1.4" }
gemfile <<-G
- source "https://gem.repo2"
+ source "https://localgemserver.test"
gem "libv8"
G
# simulate lockfile created with old bundler, which only locks for ruby platform
lockfile <<-L
GEM
- remote: https://gem.repo2/
+ remote: https://localgemserver.test/
specs:
libv8 (8.4.255.0)
@@ -197,10 +191,10 @@ RSpec.describe "bundle install with specific platforms" do
2.1.4
L
- bundle "install --verbose", env: { "BUNDLER_VERSION" => "2.1.4" }
+ bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_VERSION" => "2.1.4", "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(out).to include("Installing libv8 8.4.255.0 (universal-darwin)")
- bundle "add mini_racer --verbose"
+ bundle "add mini_racer --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(out).to include("Using libv8 8.4.255.0 (universal-darwin)")
end
end
@@ -213,14 +207,14 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "https://localgemserver.test"
gem "grpc"
G
# simulate lockfile created with old bundler, which only locks for ruby platform
lockfile <<-L
GEM
- remote: https://gem.repo4/
+ remote: https://localgemserver.test/
specs:
grpc (1.50.0)
@@ -234,7 +228,7 @@ RSpec.describe "bundle install with specific platforms" do
#{Bundler::VERSION}
L
- bundle "install --verbose", artifice: "compact_index_precompiled_before"
+ bundle "install --verbose", :artifice => "compact_index_precompiled_before", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
expect(out).to include("Installing grpc 1.50.0 (universal-darwin)")
end
end
@@ -268,7 +262,7 @@ RSpec.describe "bundle install with specific platforms" do
git = build_git "pg_array_parser", "1.0"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "pg_array_parser", :git => "#{lib_path("pg_array_parser-1.0")}"
G
@@ -304,15 +298,15 @@ RSpec.describe "bundle install with specific platforms" do
simulate_platform "x86_64-darwin-15" do
setup_multiplatform_gem_with_different_dependencies_per_platform
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "facter"
G
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- expect(the_bundle.locked_gems.platforms).to include(pl("x86_64-darwin-15"))
+ expect(the_bundle.locked_gems.platforms).to eq([pl("x86_64-darwin-15")])
expect(the_bundle).to include_gems("facter 2.4.6 universal-darwin", "CFPropertyList 1.0")
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to include("CFPropertyList-1.0",
- "facter-2.4.6-universal-darwin")
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(["CFPropertyList-1.0",
+ "facter-2.4.6-universal-darwin"])
end
end
@@ -327,8 +321,8 @@ RSpec.describe "bundle install with specific platforms" do
install_gemfile(google_protobuf)
bundle "lock --add-platform=#{x64_mingw32}"
- expect(the_bundle.locked_gems.platforms).to include(x64_mingw32, pl("x86_64-darwin-15"))
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to include(*%w[
+ expect(the_bundle.locked_gems.platforms).to eq([x64_mingw32, pl("x86_64-darwin-15")])
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[
google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin
google-protobuf-3.0.0.alpha.5.0.5.1-x64-mingw32
])
@@ -341,11 +335,11 @@ RSpec.describe "bundle install with specific platforms" do
install_gemfile(google_protobuf)
bundle "lock --add-platform=#{java}"
- expect(the_bundle.locked_gems.platforms).to include(java, pl("x86_64-darwin-15"))
- expect(the_bundle.locked_gems.specs.map(&:full_name)).to include(
- "google-protobuf-3.0.0.alpha.5.0.5.1",
- "google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin"
- )
+ expect(the_bundle.locked_gems.platforms).to eq([java, pl("x86_64-darwin-15")])
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(%w[
+ google-protobuf-3.0.0.alpha.5.0.5.1
+ google-protobuf-3.0.0.alpha.5.0.5.1-universal-darwin
+ ])
end
end
end
@@ -358,14 +352,14 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "sorbet-static", "0.5.6403"
G
lockfile <<~L
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
sorbet-static (0.5.6403-#{Bundler.local_platform})
@@ -389,13 +383,13 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "sorbet-static", "0.5.6433"
G
error_message = <<~ERROR.strip
- Could not find gem 'sorbet-static (= 0.5.6433)' with platform 'arm64-darwin-21' in rubygems repository https://gem.repo4/ or installed locally.
+ Could not find gem 'sorbet-static (= 0.5.6433)' with platform 'arm64-darwin-21' in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally.
The source contains the following gems matching 'sorbet-static (= 0.5.6433)':
* sorbet-static-0.5.6433-universal-darwin-20
@@ -403,7 +397,7 @@ RSpec.describe "bundle install with specific platforms" do
ERROR
simulate_platform "arm64-darwin-21" do
- bundle "lock", raise_on_error: false
+ bundle "lock", :raise_on_error => false
end
expect(err).to include(error_message).once
@@ -411,7 +405,7 @@ RSpec.describe "bundle install with specific platforms" do
# Make sure it doesn't print error twice in verbose mode
simulate_platform "arm64-darwin-21" do
- bundle "lock --verbose", raise_on_error: false
+ bundle "lock --verbose", :raise_on_error => false
end
expect(err).to include(error_message).once
@@ -425,7 +419,7 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "sorbet", "0.5.6433"
G
@@ -434,7 +428,7 @@ RSpec.describe "bundle install with specific platforms" do
Could not find compatible versions
Because every version of sorbet depends on sorbet-static = 0.5.6433
- and sorbet-static = 0.5.6433 could not be found in rubygems repository https://gem.repo4/ or installed locally for any resolution platforms (arm64-darwin-21),
+ and sorbet-static = 0.5.6433 could not be found in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally for any resolution platforms (arm64-darwin-21),
sorbet cannot be used.
So, because Gemfile depends on sorbet = 0.5.6433,
version solving has failed.
@@ -445,7 +439,7 @@ RSpec.describe "bundle install with specific platforms" do
ERROR
simulate_platform "arm64-darwin-21" do
- bundle "lock", raise_on_error: false
+ bundle "lock", :raise_on_error => false
end
expect(err).to include(error_message).once
@@ -453,42 +447,42 @@ RSpec.describe "bundle install with specific platforms" do
# Make sure it doesn't print error twice in verbose mode
simulate_platform "arm64-darwin-21" do
- bundle "lock --verbose", raise_on_error: false
+ bundle "lock --verbose", :raise_on_error => false
end
expect(err).to include(error_message).once
end
- it "does not generate a lockfile if ruby platform is forced and some gem has no ruby variant available" do
+ it "does not generate a lockfile if RUBY platform is forced and some gem has no RUBY variant available" do
build_repo4 do
build_gem("sorbet-static", "0.5.9889") {|s| s.platform = Gem::Platform.local }
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "sorbet-static", "0.5.9889"
G
- bundle "lock", raise_on_error: false, env: { "BUNDLE_FORCE_RUBY_PLATFORM" => "true" }
+ bundle "lock", :raise_on_error => false, :env => { "BUNDLE_FORCE_RUBY_PLATFORM" => "true" }
expect(err).to include <<~ERROR.rstrip
- Could not find gem 'sorbet-static (= 0.5.9889)' with platform 'ruby' in rubygems repository https://gem.repo4/ or installed locally.
+ Could not find gem 'sorbet-static (= 0.5.9889)' with platform 'ruby' in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally.
The source contains the following gems matching 'sorbet-static (= 0.5.9889)':
* sorbet-static-0.5.9889-#{Gem::Platform.local}
ERROR
end
- it "automatically fixes the lockfile if ruby platform is locked and some gem has no ruby variant available" do
+ it "automatically fixes the lockfile if RUBY platform is locked and some gem has no RUBY variant available" do
build_repo4 do
build_gem("sorbet-static-and-runtime", "0.5.10160") do |s|
- s.add_dependency "sorbet", "= 0.5.10160"
- s.add_dependency "sorbet-runtime", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet-runtime", "= 0.5.10160"
end
build_gem("sorbet", "0.5.10160") do |s|
- s.add_dependency "sorbet-static", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet-static", "= 0.5.10160"
end
build_gem("sorbet-runtime", "0.5.10160")
@@ -499,14 +493,14 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "sorbet-static-and-runtime"
G
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet (0.5.10160)
sorbet-static (= 0.5.10160)
@@ -517,7 +511,7 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-runtime (= 0.5.10160)
PLATFORMS
- #{lockfile_platforms}
+ #{lockfile_platforms("ruby")}
DEPENDENCIES
sorbet-static-and-runtime
@@ -528,16 +522,9 @@ RSpec.describe "bundle install with specific platforms" do
bundle "update"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "sorbet", "0.5.10160"
- c.checksum gem_repo4, "sorbet-runtime", "0.5.10160"
- c.checksum gem_repo4, "sorbet-static", "0.5.10160", Gem::Platform.local
- c.checksum gem_repo4, "sorbet-static-and-runtime", "0.5.10160"
- end
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet (0.5.10160)
sorbet-static (= 0.5.10160)
@@ -548,17 +535,17 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-runtime (= 0.5.10160)
PLATFORMS
- #{local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
sorbet-static-and-runtime
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
- it "automatically fixes the lockfile if both ruby platform and a more specific platform are locked, and some gem has no ruby variant available" do
+ it "automatically fixes the lockfile if both RUBY platform and a more specific platform are locked, and some gem has no RUBY variant available" do
build_repo4 do
build_gem "nokogiri", "1.12.0"
build_gem "nokogiri", "1.12.0" do |s|
@@ -577,21 +564,16 @@ RSpec.describe "bundle install with specific platforms" do
simulate_platform "x86_64-darwin-22" do
install_gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "nokogiri"
gem "sorbet-static"
G
end
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.13.0", "x86_64-darwin"
- c.checksum gem_repo4, "sorbet-static", "0.5.10601", "x86_64-darwin"
- end
-
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.12.0)
nokogiri (1.12.0-x86_64-darwin)
@@ -603,8 +585,8 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
nokogiri
- sorbet-static
- #{checksums}
+ sorbet
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -615,7 +597,7 @@ RSpec.describe "bundle install with specific platforms" do
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.13.0-x86_64-darwin)
sorbet-static (0.5.10601-x86_64-darwin)
@@ -626,21 +608,21 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
nokogiri
sorbet-static
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
- it "automatically fixes the lockfile if only ruby platform is locked and some gem has no ruby variant available" do
+ it "automatically fixes the lockfile if only RUBY platform is locked and some gem has no RUBY variant available" do
build_repo4 do
build_gem("sorbet-static-and-runtime", "0.5.10160") do |s|
- s.add_dependency "sorbet", "= 0.5.10160"
- s.add_dependency "sorbet-runtime", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet-runtime", "= 0.5.10160"
end
build_gem("sorbet", "0.5.10160") do |s|
- s.add_dependency "sorbet-static", "= 0.5.10160"
+ s.add_runtime_dependency "sorbet-static", "= 0.5.10160"
end
build_gem("sorbet-runtime", "0.5.10160")
@@ -651,14 +633,14 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "sorbet-static-and-runtime"
G
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet (0.5.10160)
sorbet-static (= 0.5.10160)
@@ -680,16 +662,9 @@ RSpec.describe "bundle install with specific platforms" do
bundle "update"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "sorbet", "0.5.10160"
- c.checksum gem_repo4, "sorbet-runtime", "0.5.10160"
- c.checksum gem_repo4, "sorbet-static", "0.5.10160", Gem::Platform.local
- c.checksum gem_repo4, "sorbet-static-and-runtime", "0.5.10160"
- end
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet (0.5.10160)
sorbet-static (= 0.5.10160)
@@ -700,86 +675,16 @@ RSpec.describe "bundle install with specific platforms" do
sorbet-runtime (= 0.5.10160)
PLATFORMS
- #{local_platform}
+ #{lockfile_platforms}
DEPENDENCIES
sorbet-static-and-runtime
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
- it "automatically fixes the lockfile if multiple platforms locked, but no valid versions of direct dependencies for all of them" do
- simulate_platform "x86_64-linux" do
- build_repo4 do
- build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "x86_64-linux"
- end
- build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "arm-linux"
- end
-
- build_gem "sorbet-static", "0.5.10696" do |s|
- s.platform = "x86_64-linux"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "nokogiri"
- gem "sorbet-static"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.14.0-arm-linux)
- nokogiri (1.14.0-x86_64-linux)
- sorbet-static (0.5.10696-x86_64-linux)
-
- PLATFORMS
- aarch64-linux
- arm-linux
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
- sorbet-static
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "update"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.14.0", "x86_64-linux"
- c.checksum gem_repo4, "sorbet-static", "0.5.10696", "x86_64-linux"
- end
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.14.0-x86_64-linux)
- sorbet-static (0.5.10696-x86_64-linux)
-
- PLATFORMS
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
- sorbet-static
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
it "automatically fixes the lockfile without removing other variants if it's missing platform gems, but they are installed locally" do
simulate_platform "x86_64-darwin-21" do
build_repo4 do
@@ -794,20 +699,15 @@ RSpec.describe "bundle install with specific platforms" do
# Make sure sorbet-static-0.5.10549-universal-darwin-21 is installed
install_gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "sorbet-static", "= 0.5.10549"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "sorbet-static", "0.5.10549", "universal-darwin-20"
- c.checksum gem_repo4, "sorbet-static", "0.5.10549", "universal-darwin-21"
- end
-
# Make sure the lockfile is missing sorbet-static-0.5.10549-universal-darwin-21
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet-static (0.5.10549-universal-darwin-20)
@@ -816,7 +716,7 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
sorbet-static (= 0.5.10549)
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -825,7 +725,7 @@ RSpec.describe "bundle install with specific platforms" do
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet-static (0.5.10549-universal-darwin-20)
sorbet-static (0.5.10549-universal-darwin-21)
@@ -835,63 +735,6 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
sorbet-static (= 0.5.10549)
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- it "automatically fixes the lockfile if locked only to ruby, and some locked specs don't meed locked dependencies" do
- simulate_platform "x86_64-linux" do
- build_repo4 do
- build_gem("ibandit", "0.7.0") do |s|
- s.add_dependency "i18n", "~> 0.7.0"
- end
-
- build_gem("i18n", "0.7.0.beta1")
- build_gem("i18n", "0.7.0")
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "ibandit", "~> 0.7.0"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- i18n (0.7.0.beta1)
- ibandit (0.7.0)
- i18n (~> 0.7.0)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- ibandit (~> 0.7.0)
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- bundle "lock --update i18n"
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- i18n (0.7.0)
- ibandit (0.7.0)
- i18n (~> 0.7.0)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- ibandit (~> 0.7.0)
BUNDLED WITH
#{Bundler::VERSION}
@@ -908,21 +751,16 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "nokogiri"
gem "tzinfo", "~> 1.2", platform: :#{not_local_tag}
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.13.8"
- c.checksum gem_repo4, "nokogiri", "1.13.8", Gem::Platform.local
- end
-
original_lockfile = <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.13.8)
nokogiri (1.13.8-#{Gem::Platform.local})
@@ -933,60 +771,14 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
nokogiri
tzinfo (~> 1.2)
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- lockfile original_lockfile
-
- bundle "lock --update"
-
- expect(lockfile).to eq(original_lockfile)
- end
-
- it "does not remove ruby if gems for other platforms, and not present in the lockfile, exist in the Gemfile, and the lockfile only has ruby" do
- build_repo4 do
- build_gem "nokogiri", "1.13.8"
- build_gem "nokogiri", "1.13.8" do |s|
- s.platform = "arm64-darwin"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "nokogiri"
- gem "tzinfo", "~> 1.2", platforms: %i[mingw mswin x64_mingw jruby]
- G
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.13.8"
- end
-
- original_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.13.8)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- nokogiri
- tzinfo (~> 1.2)
- #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
L
lockfile original_lockfile
- simulate_platform "arm64-darwin-23" do
- bundle "lock --update"
- end
+ bundle "lock --update"
expect(lockfile).to eq(original_lockfile)
end
@@ -994,24 +786,19 @@ RSpec.describe "bundle install with specific platforms" do
it "does not remove ruby when adding a new gem to the Gemfile" do
build_repo4 do
build_gem "concurrent-ruby", "1.2.2"
- build_gem "myrack", "3.0.7"
+ build_gem "rack", "3.0.7"
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "concurrent-ruby"
- gem "myrack"
+ gem "rack"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "concurrent-ruby", "1.2.2"
- c.checksum gem_repo4, "myrack", "3.0.7"
- end
-
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
concurrent-ruby (1.2.2)
@@ -1020,7 +807,7 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
concurrent-ruby
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1029,18 +816,18 @@ RSpec.describe "bundle install with specific platforms" do
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
concurrent-ruby (1.2.2)
- myrack (3.0.7)
+ rack (3.0.7)
PLATFORMS
- #{lockfile_platforms("ruby", generic_local_platform, defaults: [])}
+ #{formatted_lockfile_platforms(*["ruby", generic_local_platform].uniq)}
DEPENDENCIES
concurrent-ruby
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -1049,8 +836,10 @@ RSpec.describe "bundle install with specific platforms" do
it "can fallback to a source gem when platform gems are incompatible with current ruby version" do
setup_multiplatform_gem_with_source_gem
+ source = file_uri_for(gem_repo2)
+
gemfile <<~G
- source "https://gem.repo2"
+ source "#{source}"
gem "my-precompiled-gem"
G
@@ -1060,7 +849,7 @@ RSpec.describe "bundle install with specific platforms" do
# - A source gem with compatible ruby version
lockfile <<-L
GEM
- remote: https://gem.repo2/
+ remote: #{source}/
specs:
my-precompiled-gem (3.0.0)
my-precompiled-gem (3.0.0-#{Bundler.local_platform})
@@ -1096,18 +885,14 @@ RSpec.describe "bundle install with specific platforms" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "nokogiri", "1.14.0"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.14.0", "x86_64-linux"
- end
-
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.14.0-x86_64-linux)
@@ -1116,20 +901,16 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
nokogiri (= 1.14.0)
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
bundle :install
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.14.0"
- end
-
expect(lockfile).to eq(<<~L)
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.14.0)
@@ -1138,522 +919,10 @@ RSpec.describe "bundle install with specific platforms" do
DEPENDENCIES
nokogiri (= 1.14.0)
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- it "automatically fixes the lockfile when only ruby platform locked, and adding a dependency with subdependencies not valid for ruby" do
- simulate_platform "x86_64-linux" do
- build_repo4 do
- build_gem("sorbet", "0.5.10160") do |s|
- s.add_dependency "sorbet-static", "= 0.5.10160"
- end
-
- build_gem("sorbet-static", "0.5.10160") do |s|
- s.platform = "x86_64-linux"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "sorbet"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
BUNDLED WITH
#{Bundler::VERSION}
L
-
- bundle "lock"
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- sorbet (0.5.10160)
- sorbet-static (= 0.5.10160)
- sorbet-static (0.5.10160-x86_64-linux)
-
- PLATFORMS
- x86_64-linux
-
- DEPENDENCIES
- sorbet
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- it "locks specific platforms automatically" do
- simulate_platform "x86_64-linux" do
- build_repo4 do
- build_gem "nokogiri", "1.14.0"
- build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "x86_64-linux"
- end
- build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "arm-linux"
- end
- build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "x64-mingw32"
- end
- build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "java"
- end
-
- build_gem "sorbet-static", "0.5.10696" do |s|
- s.platform = "x86_64-linux"
- end
- build_gem "sorbet-static", "0.5.10696" do |s|
- s.platform = "universal-darwin-22"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "nokogiri"
- G
-
- bundle "lock"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.14.0"
- c.checksum gem_repo4, "nokogiri", "1.14.0", "arm-linux"
- c.checksum gem_repo4, "nokogiri", "1.14.0", "x86_64-linux"
- end
-
- # locks all compatible platforms, excluding Java and Windows
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.14.0)
- nokogiri (1.14.0-arm-linux)
- nokogiri (1.14.0-x86_64-linux)
-
- PLATFORMS
- arm-linux
- ruby
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "nokogiri"
- gem "sorbet-static"
- G
-
- FileUtils.rm bundled_app_lock
-
- bundle "lock"
-
- checksums.delete "nokogiri", "arm-linux"
- checksums.checksum gem_repo4, "sorbet-static", "0.5.10696", "universal-darwin-22"
- checksums.checksum gem_repo4, "sorbet-static", "0.5.10696", "x86_64-linux"
-
- # locks only platforms compatible with all gems in the bundle
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.14.0)
- nokogiri (1.14.0-x86_64-linux)
- sorbet-static (0.5.10696-universal-darwin-22)
- sorbet-static (0.5.10696-x86_64-linux)
-
- PLATFORMS
- universal-darwin-22
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
- sorbet-static
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- it "does not fail when a platform variant is incompatible with the current ruby and another equivalent platform specific variant is part of the resolution", rubygems: ">= 3.3.21" do
- build_repo4 do
- build_gem "nokogiri", "1.15.5"
-
- build_gem "nokogiri", "1.15.5" do |s|
- s.platform = "x86_64-linux"
- s.required_ruby_version = "< #{current_ruby_minor}.dev"
- end
-
- build_gem "sass-embedded", "1.69.5"
-
- build_gem "sass-embedded", "1.69.5" do |s|
- s.platform = "x86_64-linux-gnu"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "nokogiri"
- gem "sass-embedded"
- G
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.15.5"
- c.checksum gem_repo4, "sass-embedded", "1.69.5"
- c.checksum gem_repo4, "sass-embedded", "1.69.5", "x86_64-linux-gnu"
- end
-
- simulate_platform "x86_64-linux" do
- bundle "install --verbose"
-
- # locks all compatible platforms, excluding Java and Windows
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.15.5)
- sass-embedded (1.69.5)
- sass-embedded (1.69.5-x86_64-linux-gnu)
-
- PLATFORMS
- ruby
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
- sass-embedded
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- it "does not add ruby platform gem if it brings extra dependencies not resolved originally" do
- build_repo4 do
- build_gem "nokogiri", "1.15.5" do |s|
- s.add_dependency "mini_portile2", "~> 2.8.2"
- end
-
- build_gem "nokogiri", "1.15.5" do |s|
- s.platform = "x86_64-linux"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "nokogiri"
- G
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "nokogiri", "1.15.5", "x86_64-linux"
- end
-
- simulate_platform "x86_64-linux" do
- bundle "install --verbose"
-
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.15.5-x86_64-linux)
-
- PLATFORMS
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- ["x86_64-linux", "x86_64-linux-musl"].each do |host_platform|
- describe "on host platform #{host_platform}" do
- it "adds current musl platform" do
- build_repo4 do
- build_gem "rcee_precompiled", "0.5.0" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "rcee_precompiled", "0.5.0" do |s|
- s.platform = "x86_64-linux-musl"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "rcee_precompiled", "0.5.0"
- G
-
- simulate_platform host_platform do
- bundle "lock"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "rcee_precompiled", "0.5.0", "x86_64-linux"
- c.checksum gem_repo4, "rcee_precompiled", "0.5.0", "x86_64-linux-musl"
- end
-
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- rcee_precompiled (0.5.0-x86_64-linux)
- rcee_precompiled (0.5.0-x86_64-linux-musl)
-
- PLATFORMS
- x86_64-linux
- x86_64-linux-musl
-
- DEPENDENCIES
- rcee_precompiled (= 0.5.0)
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
- end
- end
-
- it "adds current musl platform, when there are also gnu variants", rubygems: ">= 3.3.21" do
- build_repo4 do
- build_gem "rcee_precompiled", "0.5.0" do |s|
- s.platform = "x86_64-linux-gnu"
- end
-
- build_gem "rcee_precompiled", "0.5.0" do |s|
- s.platform = "x86_64-linux-musl"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "rcee_precompiled", "0.5.0"
- G
-
- simulate_platform "x86_64-linux-musl" do
- bundle "lock"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "rcee_precompiled", "0.5.0", "x86_64-linux-gnu"
- c.checksum gem_repo4, "rcee_precompiled", "0.5.0", "x86_64-linux-musl"
- end
-
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- rcee_precompiled (0.5.0-x86_64-linux-gnu)
- rcee_precompiled (0.5.0-x86_64-linux-musl)
-
- PLATFORMS
- x86_64-linux-gnu
- x86_64-linux-musl
-
- DEPENDENCIES
- rcee_precompiled (= 0.5.0)
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- it "does not add current platform if there's an equivalent less specific platform among the ones resolved" do
- build_repo4 do
- build_gem "rcee_precompiled", "0.5.0" do |s|
- s.platform = "universal-darwin"
- end
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "rcee_precompiled", "0.5.0"
- G
-
- simulate_platform "x86_64-darwin-15" do
- bundle "lock"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "rcee_precompiled", "0.5.0", "universal-darwin"
- end
-
- expect(lockfile).to eq(<<~L)
- GEM
- remote: https://gem.repo4/
- specs:
- rcee_precompiled (0.5.0-universal-darwin)
-
- PLATFORMS
- universal-darwin
-
- DEPENDENCIES
- rcee_precompiled (= 0.5.0)
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
- it "does not re-resolve when a specific platform, but less specific than the current platform, is locked" do
- build_repo4 do
- build_gem "nokogiri"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "nokogiri"
- G
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.0)
-
- PLATFORMS
- arm64-darwin
-
- DEPENDENCIES
- nokogiri!
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- simulate_platform "arm64-darwin-23" do
- bundle "install --verbose"
-
- expect(out).to include("Found no changes, using resolution from the lockfile")
- end
- end
-
- it "does not remove generic platform gems locked for a specific platform from lockfile when unlocking an unrelated gem" do
- build_repo4 do
- build_gem "ffi"
-
- build_gem "ffi" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "nokogiri"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "ffi"
- gem "nokogiri"
- G
-
- original_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- ffi (1.0)
- nokogiri (1.0)
-
- PLATFORMS
- x86_64-linux
-
- DEPENDENCIES
- ffi
- nokogiri
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- lockfile original_lockfile
-
- simulate_platform "x86_64-linux" do
- bundle "lock --update nokogiri"
-
- expect(lockfile).to eq(original_lockfile)
- end
- end
-
- it "does not remove generic platform gems locked for a specific platform from lockfile when unlocking an unrelated gem, and variants for other platform also locked" do
- build_repo4 do
- build_gem "ffi"
-
- build_gem "ffi" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "ffi" do |s|
- s.platform = "java"
- end
-
- build_gem "nokogiri"
- end
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "ffi"
- gem "nokogiri"
- G
-
- original_lockfile = <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- ffi (1.0)
- ffi (1.0-java)
- nokogiri (1.0)
-
- PLATFORMS
- java
- x86_64-linux
-
- DEPENDENCIES
- ffi
- nokogiri
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- lockfile original_lockfile
-
- simulate_platform "x86_64-linux" do
- bundle "lock --update nokogiri"
-
- expect(lockfile).to eq(original_lockfile)
end
end
@@ -1682,7 +951,7 @@ RSpec.describe "bundle install with specific platforms" do
build_gem("facter", "2.4.6")
build_gem("facter", "2.4.6") do |s|
s.platform = "universal-darwin"
- s.add_dependency "CFPropertyList"
+ s.add_runtime_dependency "CFPropertyList"
end
build_gem("CFPropertyList")
end
diff --git a/spec/bundler/install/gemfile_spec.rb b/spec/bundler/install/gemfile_spec.rb
index 96ed174e9b..e643573454 100644
--- a/spec/bundler/install/gemfile_spec.rb
+++ b/spec/bundler/install/gemfile_spec.rb
@@ -3,8 +3,8 @@
RSpec.describe "bundle install" do
context "with duplicated gems" do
it "will display a warning" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem 'rails', '~> 4.0.0'
gem 'rails', '~> 4.0.0'
@@ -16,24 +16,24 @@ RSpec.describe "bundle install" do
context "with --gemfile" do
it "finds the gemfile" do
gemfile bundled_app("NotGemfile"), <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- bundle :install, gemfile: bundled_app("NotGemfile")
+ bundle :install, :gemfile => bundled_app("NotGemfile")
# Specify BUNDLE_GEMFILE for `the_bundle`
# to retrieve the proper Gemfile
ENV["BUNDLE_GEMFILE"] = "NotGemfile"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
context "with gemfile set via config" do
before do
gemfile bundled_app("NotGemfile"), <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
bundle "config set --local gemfile #{bundled_app("NotGemfile")}"
@@ -42,59 +42,34 @@ RSpec.describe "bundle install" do
bundle "install"
bundle "list"
- expect(out).to include("myrack (1.0.0)")
+ expect(out).to include("rack (1.0.0)")
end
it "uses the gemfile while in a subdirectory" do
bundled_app("subdir").mkpath
- bundle "install", dir: bundled_app("subdir")
- bundle "list", dir: bundled_app("subdir")
+ bundle "install", :dir => bundled_app("subdir")
+ bundle "list", :dir => bundled_app("subdir")
- expect(out).to include("myrack (1.0.0)")
+ expect(out).to include("rack (1.0.0)")
end
end
context "with deprecated features" do
it "reports that lib is an invalid option" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack", :lib => "myrack"
+ gem "rack", :lib => "rack"
G
- bundle :install, raise_on_error: false
- expect(err).to match(/You passed :lib as an option for gem 'myrack', but it is invalid/)
- end
- end
-
- context "when an internal error happens" do
- let(:bundler_bug) do
- create_file("bundler_bug.rb", <<~RUBY)
- require "bundler"
-
- module Bundler
- class Dsl
- def source(source, *args, &blk)
- nil.name
- end
- end
- end
- RUBY
-
- bundled_app("bundler_bug.rb").to_s
- end
-
- it "shows culprit file and line" do
- skip "ruby-core test setup has always \"lib\" in $LOAD_PATH so `require \"bundler\"` always activates the local version rather than using RubyGems gem activation stuff, causing conflicts" if ruby_core?
-
- install_gemfile "source 'https://gem.repo1'", requires: [bundler_bug], artifice: nil, raise_on_error: false
- expect(err).to include("bundler_bug.rb:6")
+ bundle :install, :raise_on_error => false
+ expect(err).to match(/You passed :lib as an option for gem 'rack', but it is invalid/)
end
end
context "with engine specified in symbol", :jruby_only do
it "does not raise any error parsing Gemfile" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "#{RUBY_VERSION}", :engine => :jruby, :engine_version => "#{RUBY_ENGINE_VERSION}"
G
@@ -103,19 +78,19 @@ RSpec.describe "bundle install" do
it "installation succeeds" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
ruby "#{RUBY_VERSION}", :engine => :jruby, :engine_version => "#{RUBY_ENGINE_VERSION}"
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
context "with a Gemfile containing non-US-ASCII characters" do
it "reads the Gemfile with the UTF-8 encoding by default" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
str = "Il était une fois ..."
puts "The source encoding is: " + str.encoding.name
@@ -130,7 +105,7 @@ RSpec.describe "bundle install" do
# NOTE: This works thanks to #eval interpreting the magic encoding comment
install_gemfile <<-G
# encoding: iso-8859-1
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
str = "Il #{"\xE9".dup.force_encoding("binary")}tait une fois ..."
puts "The source encoding is: " + str.encoding.name
diff --git a/spec/bundler/install/gems/compact_index_spec.rb b/spec/bundler/install/gems/compact_index_spec.rb
index 4653ce6d87..65be262748 100644
--- a/spec/bundler/install/gems/compact_index_spec.rb
+++ b/spec/bundler/install/gems/compact_index_spec.rb
@@ -7,27 +7,12 @@ RSpec.describe "compact index api" do
it "should use the API" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
- it "has a debug mode" do
- gemfile <<-G
- source "#{source_uri}"
- gem "myrack"
- G
-
- bundle :install, artifice: "compact_index", env: { "DEBUG_COMPACT_INDEX" => "true" }
- expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(err).to include("[Bundler::CompactIndexClient] available?")
- expect(err).to include("[Bundler::CompactIndexClient] fetching versions")
- expect(err).to include("[Bundler::CompactIndexClient] info(myrack)")
- expect(err).to include("[Bundler::CompactIndexClient] fetching info/myrack")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "should URI encode gem names" do
@@ -36,7 +21,7 @@ RSpec.describe "compact index api" do
gem " sinatra"
G
- bundle :install, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to include("' sinatra' is not a valid gem name because it contains whitespace.")
end
@@ -46,7 +31,7 @@ RSpec.describe "compact index api" do
gem "rails"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(out).to include("Fetching gem metadata from #{source_uri}")
expect(the_bundle).to include_gems(
"rails 2.3.2",
@@ -59,23 +44,23 @@ RSpec.describe "compact index api" do
end
it "should handle case sensitivity conflicts" do
- build_repo4(build_compact_index: false) do
- build_gem "myrack", "1.0" do |s|
- s.add_dependency("Myrack", "0.1")
+ build_repo4 do
+ build_gem "rack", "1.0" do |s|
+ s.add_runtime_dependency("Rack", "0.1")
end
- build_gem "Myrack", "0.1"
+ build_gem "Rack", "0.1"
end
- install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
source "#{source_uri}"
- gem "myrack", "1.0"
- gem "Myrack", "0.1"
+ gem "rack", "1.0"
+ gem "Rack", "0.1"
G
# can't use `include_gems` here since the `require` will conflict on a
# case-insensitive FS
- run "Bundler.require; puts Gem.loaded_specs.values_at('myrack', 'Myrack').map(&:full_name)"
- expect(out).to eq("myrack-1.0\nMyrack-0.1")
+ run "Bundler.require; puts Gem.loaded_specs.values_at('rack', 'Rack').map(&:full_name)"
+ expect(out).to eq("rack-1.0\nRack-0.1")
end
it "should handle multiple gem dependencies on the same gem" do
@@ -84,22 +69,22 @@ RSpec.describe "compact index api" do
gem "net-sftp"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(the_bundle).to include_gems "net-sftp 1.1.1"
end
it "should use the endpoint when using deployment mode" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
bundle "config set --local deployment true"
bundle "config set --local path vendor/bundle"
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "handles git dependencies that are in rubygems" do
@@ -110,12 +95,12 @@ RSpec.describe "compact index api" do
gemfile <<-G
source "#{source_uri}"
- git "#{lib_path("foo-1.0")}" do
+ git "#{file_uri_for(lib_path("foo-1.0"))}" do
gem 'foo'
end
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(the_bundle).to include_gems("rails 2.3.2")
end
@@ -128,13 +113,13 @@ RSpec.describe "compact index api" do
gemfile <<-G
source "#{source_uri}"
- gem 'foo', :git => "#{lib_path("foo-1.0")}"
+ gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
bundle "config set --local deployment true"
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(the_bundle).to include_gems("rails 2.3.2")
end
@@ -143,12 +128,12 @@ RSpec.describe "compact index api" do
build_git "foo"
gemfile <<-G
source "#{source_uri}"
- gem 'foo', :git => "#{lib_path("foo-1.0")}"
+ gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
- bundle "install", artifice: "compact_index"
+ bundle "install", :artifice => "compact_index"
bundle "config set --local deployment true"
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(the_bundle).to include_gems("foo 1.0")
end
@@ -156,42 +141,41 @@ RSpec.describe "compact index api" do
it "falls back when the API URL returns 403 Forbidden" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, verbose: true, artifice: "compact_index_forbidden"
+ bundle :install, :verbose => true, :artifice => "compact_index_forbidden"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "falls back when the versions endpoint has a checksum mismatch" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, verbose: true, artifice: "compact_index_checksum_mismatch"
+ bundle :install, :verbose => true, :artifice => "compact_index_checksum_mismatch"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(out).to include("The checksum of /versions does not match the checksum provided by the server!")
- expect(out).to include("Calculated checksums #{{ "sha-256" => "8KfZiM/fszVkqhP/m5s9lvE6M9xKu4I1bU4Izddp5Ms=" }.inspect} did not match expected #{{ "sha-256" => "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=" }.inspect}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(out).to include <<-'WARN'
+The checksum of /versions does not match the checksum provided by the server! Something is wrong (local checksum is "\"d41d8cd98f00b204e9800998ecf8427e\"", was expecting "\"123\"").
+ WARN
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "shows proper path when permission errors happen", :permissions do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- versions = Pathname.new(Bundler.rubygems.user_home).join(
- ".bundle", "cache", "compact_index",
- "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions"
- )
- versions.dirname.mkpath
- versions.write("created_at")
+ versions = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
+ "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions")
+ FileUtils.mkdir_p(File.dirname(versions))
+ FileUtils.touch(versions)
FileUtils.chmod("-r", versions)
- bundle :install, artifice: "compact_index", raise_on_error: false
+ bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to include(
"There was an error while trying to read from `#{versions}`. It is likely that you need to grant read permissions for that path."
@@ -203,28 +187,28 @@ RSpec.describe "compact index api" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "handles host redirects" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index_host_redirect"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "compact_index_host_redirect"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
- it "handles host redirects without Gem::Net::HTTP::Persistent" do
+ it "handles host redirects without Net::HTTP::Persistent" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
FileUtils.mkdir_p lib_path
@@ -240,18 +224,18 @@ RSpec.describe "compact index api" do
H
end
- bundle :install, artifice: "compact_index_host_redirect", requires: [lib_path("disable_net_http_persistent.rb")]
+ bundle :install, :artifice => "compact_index_host_redirect", :requires => [lib_path("disable_net_http_persistent.rb")]
expect(out).to_not match(/Too many redirects/)
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "times out when Bundler::Fetcher redirects too much" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index_redirects", raise_on_error: false
+ bundle :install, :artifice => "compact_index_redirects", :raise_on_error => false
expect(err).to match(/Too many redirects/)
end
@@ -259,23 +243,23 @@ RSpec.describe "compact index api" do
it "should use the modern index for install" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --full-index", artifice: "compact_index"
+ bundle "install --full-index", :artifice => "compact_index"
expect(out).to include("Fetching source index from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "should use the modern index for update" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "update --full-index", artifice: "compact_index", all: true
+ bundle "update --full-index", :artifice => "compact_index", :all => true
expect(out).to include("Fetching source index from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
@@ -303,22 +287,22 @@ RSpec.describe "compact index api" do
end
end
- system_gems %w[myrack-1.0.0 thin-1.0 net_a-1.0], gem_repo: gem_repo2
+ system_gems %w[rack-1.0.0 thin-1.0 net_a-1.0], :gem_repo => gem_repo2
bundle "config set --local path.system true"
- ENV["BUNDLER_SPEC_ALL_REQUESTS"] = <<~EOS.strip
+ ENV["BUNDLER_SPEC_ALL_REQUESTS"] = strip_whitespace(<<-EOS).strip
#{source_uri}/versions
- #{source_uri}/info/myrack
+ #{source_uri}/info/rack
EOS
- install_gemfile <<-G, artifice: "compact_index", verbose: true, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ install_gemfile <<-G, :artifice => "compact_index", :verbose => true, :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
expect(last_command.stdboth).not_to include "Double checking"
end
- it "fetches again when more dependencies are found in subsequent sources", bundler: "< 3" do
+ it "fetches again when more dependencies are found in subsequent sources", :bundler => "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -332,7 +316,7 @@ RSpec.describe "compact index api" do
gem "back_deps"
G
- bundle :install, artifice: "compact_index_extra"
+ bundle :install, :artifice => "compact_index_extra"
expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0"
end
@@ -344,7 +328,7 @@ RSpec.describe "compact index api" do
FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")]
end
- install_gemfile <<-G, artifice: "compact_index_extra", verbose: true
+ install_gemfile <<-G, :artifice => "compact_index_extra", :verbose => true
source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
@@ -357,27 +341,27 @@ RSpec.describe "compact index api" do
it "fetches gem versions even when those gems are already installed" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
- bundle :install, artifice: "compact_index_extra_api"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "compact_index_extra_api"
+ expect(the_bundle).to include_gems "rack 1.0.0"
build_repo4 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
end
gemfile <<-G
source "#{source_uri}" do; end
source "#{source_uri}/extra"
- gem "myrack", "1.2"
+ gem "rack", "1.2"
G
- bundle :install, artifice: "compact_index_extra_api"
- expect(the_bundle).to include_gems "myrack 1.2"
+ bundle :install, :artifice => "compact_index_extra_api"
+ expect(the_bundle).to include_gems "rack 1.2"
end
- it "considers all possible versions of dependencies from all api gem sources", bundler: "< 3" do
+ it "considers all possible versions of dependencies from all api gem sources", :bundler => "< 3" do
# In this scenario, the gem "somegem" only exists in repo4. It depends on specific version of activesupport that
# exists only in repo1. There happens also be a version of activesupport in repo4, but not the one that version 1.0.0
# of somegem wants. This test makes sure that bundler actually finds version 1.2.3 of active support in the other
@@ -395,7 +379,7 @@ RSpec.describe "compact index api" do
gem 'somegem', '1.0.0'
G
- bundle :install, artifice: "compact_index_extra_api"
+ bundle :install, :artifice => "compact_index_extra_api"
expect(the_bundle).to include_gems "somegem 1.0.0"
expect(the_bundle).to include_gems "activesupport 1.2.3"
@@ -416,7 +400,7 @@ RSpec.describe "compact index api" do
end
G
- bundle :install, artifice: "compact_index_extra"
+ bundle :install, :artifice => "compact_index_extra"
expect(out).to include("Fetching gem metadata from http://localgemserver.test/")
expect(out).to include("Fetching source index from http://localgemserver.test/extra")
@@ -432,7 +416,7 @@ RSpec.describe "compact index api" do
FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")]
end
- install_gemfile <<-G, artifice: "compact_index_extra_missing"
+ install_gemfile <<-G, :artifice => "compact_index_extra_missing", :env => env_for_missing_prerelease_default_gem_activation
source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
@@ -452,7 +436,7 @@ RSpec.describe "compact index api" do
FileUtils.rm_rf Dir[gem_repo4("gems/foo-*.gem")]
end
- install_gemfile <<-G, artifice: "compact_index_extra_api_missing"
+ install_gemfile <<-G, :artifice => "compact_index_extra_api_missing", :env => env_for_missing_prerelease_default_gem_activation
source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
@@ -469,11 +453,11 @@ RSpec.describe "compact index api" do
gem 'foo'
G
- bundle :install, artifice: "compact_index_api_missing"
+ bundle :install, :artifice => "compact_index_api_missing"
expect(the_bundle).to include_gems "foo 1.0"
end
- it "fetches again when more dependencies are found in subsequent sources using deployment mode", bundler: "< 3" do
+ it "fetches again when more dependencies are found in subsequent sources using deployment mode", :bundler => "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -487,9 +471,9 @@ RSpec.describe "compact index api" do
gem "back_deps"
G
- bundle :install, artifice: "compact_index_extra"
+ bundle :install, :artifice => "compact_index_extra"
bundle "config --set local deployment true"
- bundle :install, artifice: "compact_index_extra"
+ bundle :install, :artifice => "compact_index_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -508,9 +492,9 @@ RSpec.describe "compact index api" do
end
G
- bundle :install, artifice: "compact_index_extra"
+ bundle :install, :artifice => "compact_index_extra"
bundle "config set --local deployment true"
- bundle :install, artifice: "compact_index_extra"
+ bundle :install, :artifice => "compact_index_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -527,70 +511,70 @@ RSpec.describe "compact index api" do
gem "bundler_dep"
G
- bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ bundle :install, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(out).to include("Fetching gem metadata from #{source_uri}")
end
- it "installs the binstubs", bundler: "< 3" do
+ it "installs the binstubs", :bundler => "< 3" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --binstubs", artifice: "compact_index"
+ bundle "install --binstubs", :artifice => "compact_index"
- gembin "myrackup"
+ gembin "rackup"
expect(out).to eq("1.0.0")
end
- it "installs the bins when using --path and uses autoclean", bundler: "< 3" do
+ it "installs the bins when using --path and uses autoclean", :bundler => "< 3" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --path vendor/bundle", artifice: "compact_index"
+ bundle "install --path vendor/bundle", :artifice => "compact_index"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
- it "installs the bins when using --path and uses bundle clean", bundler: "< 3" do
+ it "installs the bins when using --path and uses bundle clean", :bundler => "< 3" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --path vendor/bundle --no-clean", artifice: "compact_index"
+ bundle "install --path vendor/bundle --no-clean", :artifice => "compact_index"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "prints post_install_messages" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack-obama'
+ gem 'rack-obama'
G
- bundle :install, artifice: "compact_index"
- expect(out).to include("Post-install message from myrack:")
+ bundle :install, :artifice => "compact_index"
+ expect(out).to include("Post-install message from rack:")
end
it "should display the post install message for a dependency" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack_middleware'
+ gem 'rack_middleware'
G
- bundle :install, artifice: "compact_index"
- expect(out).to include("Post-install message from myrack:")
- expect(out).to include("Myrack's post install message")
+ bundle :install, :artifice => "compact_index"
+ expect(out).to include("Post-install message from rack:")
+ expect(out).to include("Rack's post install message")
end
context "when using basic authentication" do
let(:user) { "user" }
let(:password) { "pass" }
let(:basic_auth_source_uri) do
- uri = Gem::URI.parse(source_uri)
+ uri = Bundler::URI.parse(source_uri)
uri.user = user
uri.password = password
@@ -600,110 +584,110 @@ RSpec.describe "compact index api" do
it "passes basic authentication details and strips out creds" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index_basic_authentication"
+ bundle :install, :artifice => "compact_index_basic_authentication"
expect(out).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "passes basic authentication details and strips out creds also in verbose mode" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, verbose: true, artifice: "compact_index_basic_authentication"
+ bundle :install, :verbose => true, :artifice => "compact_index_basic_authentication"
expect(out).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
- it "strips http basic auth creds when warning about ambiguous sources", bundler: "< 3" do
+ it "strips http basic auth creds when warning about ambiguous sources", :bundler => "< 3" do
gemfile <<-G
source "#{basic_auth_source_uri}"
source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index_basic_authentication"
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
+ bundle :install, :artifice => "compact_index_basic_authentication"
+ expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not pass the user / password to different hosts on redirect" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index_creds_diff_host"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "compact_index_creds_diff_host"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
describe "with authentication details in bundle config" do
before do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
end
it "reads authentication details by host name from bundle config" do
bundle "config set #{source_hostname} #{user}:#{password}"
- bundle :install, artifice: "compact_index_strict_basic_authentication"
+ bundle :install, :artifice => "compact_index_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "reads authentication details by full url from bundle config" do
# The trailing slash is necessary here; Fetcher canonicalizes the URI.
bundle "config set #{source_uri}/ #{user}:#{password}"
- bundle :install, artifice: "compact_index_strict_basic_authentication"
+ bundle :install, :artifice => "compact_index_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "should use the API" do
bundle "config set #{source_hostname} #{user}:#{password}"
- bundle :install, artifice: "compact_index_strict_basic_authentication"
+ bundle :install, :artifice => "compact_index_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "prefers auth supplied in the source uri" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
bundle "config set #{source_hostname} otheruser:wrong"
- bundle :install, artifice: "compact_index_strict_basic_authentication"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "compact_index_strict_basic_authentication"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "shows instructions if auth is not provided for the source" do
- bundle :install, artifice: "compact_index_strict_basic_authentication", raise_on_error: false
+ bundle :install, :artifice => "compact_index_strict_basic_authentication", :raise_on_error => false
expect(err).to include("bundle config set --global #{source_hostname} username:password")
end
it "fails if authentication has already been provided, but failed" do
bundle "config set #{source_hostname} #{user}:wrong"
- bundle :install, artifice: "compact_index_strict_basic_authentication", raise_on_error: false
+ bundle :install, :artifice => "compact_index_strict_basic_authentication", :raise_on_error => false
expect(err).to include("Bad username or password")
end
it "does not fallback to old dependency API if bad authentication is provided" do
bundle "config set #{source_hostname} #{user}:wrong"
- bundle :install, artifice: "compact_index_strict_basic_authentication", raise_on_error: false, verbose: true
+ bundle :install, :artifice => "compact_index_strict_basic_authentication", :raise_on_error => false, :verbose => true
expect(err).to include("Bad username or password")
expect(out).to include("HTTP 401 Unauthorized http://user@localgemserver.test/versions")
expect(out).not_to include("HTTP 401 Unauthorized http://user@localgemserver.test/api/v1/dependencies")
@@ -716,11 +700,11 @@ RSpec.describe "compact index api" do
it "passes basic authentication details" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index_basic_authentication"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "compact_index_basic_authentication"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
end
@@ -741,10 +725,10 @@ RSpec.describe "compact index api" do
it "explains what to do to get it" do
gemfile <<-G
source "#{source_uri.gsub(/http/, "https")}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, env: { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, raise_on_error: false, artifice: nil
+ bundle :install, :env => { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, :raise_on_error => false
expect(err).to include("OpenSSL")
end
end
@@ -754,17 +738,17 @@ RSpec.describe "compact index api" do
# Install a monkeypatch that reproduces the effects of openssl raising
# a certificate validation error when RubyGems tries to connect.
gemfile <<-G
- class Gem::Net::HTTP
+ class Net::HTTP
def start
raise OpenSSL::SSL::SSLError, "certificate verify failed"
end
end
source "#{source_uri.gsub(/http/, "https")}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to match(/could not verify the SSL certificate/i)
end
end
@@ -772,206 +756,118 @@ RSpec.describe "compact index api" do
context ".gemrc with sources is present" do
it "uses other sources declared in the Gemfile" do
File.open(home(".gemrc"), "w") do |file|
- file.puts({ sources: ["https://rubygems.org"] }.to_yaml)
+ file.puts({ :sources => ["https://rubygems.org"] }.to_yaml)
end
begin
gemfile <<-G
source "#{source_uri}"
- gem 'myrack'
+ gem 'rack'
G
- bundle :install, artifice: "compact_index_forbidden"
+ bundle :install, :artifice => "compact_index_forbidden"
ensure
home(".gemrc").rmtree
end
end
end
- it "performs update with etag not-modified" do
- versions_etag = Pathname.new(Bundler.rubygems.user_home).join(
- ".bundle", "cache", "compact_index",
- "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions.etag"
- )
- expect(versions_etag.file?).to eq(false)
-
+ it "performs partial update with a non-empty range" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack', '0.9.1'
+ gem 'rack', '0.9.1'
G
- # Initial install creates the cached versions file and etag file
- bundle :install, artifice: "compact_index"
-
- expect(versions_etag.file?).to eq(true)
- previous_content = versions_etag.binread
+ # Initial install creates the cached versions file
+ bundle :install, :artifice => "compact_index"
# Update the Gemfile so we can check subsequent install was successful
gemfile <<-G
source "#{source_uri}"
- gem 'myrack', '1.0.0'
- G
-
- # Second install should match etag
- bundle :install, artifice: "compact_index_etag_match"
-
- expect(versions_etag.binread).to eq(previous_content)
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
- it "performs full update when range is ignored" do
- gemfile <<-G
- source "#{source_uri}"
- gem 'myrack', '0.9.1'
- G
-
- # Initial install creates the cached versions file and etag file
- bundle :install, artifice: "compact_index"
-
- gemfile <<-G
- source "#{source_uri}"
- gem 'myrack', '1.0.0'
- G
-
- versions = Pathname.new(Bundler.rubygems.user_home).join(
- ".bundle", "cache", "compact_index",
- "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions"
- )
- # Modify the cached file. The ranged request will be based on this but,
- # in this test, the range is ignored so this gets overwritten, allowing install.
- versions.write "ruining this file"
-
- bundle :install, artifice: "compact_index_range_ignored"
-
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
- it "performs partial update with a non-empty range" do
- build_repo4 do
- build_gem "myrack", "0.9.1"
- end
-
- # Initial install creates the cached versions file
- install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- source "#{source_uri}"
- gem 'myrack', '0.9.1'
+ gem 'rack', '1.0.0'
G
- update_repo4 do
- build_gem "myrack", "1.0.0"
- end
-
- install_gemfile <<-G, artifice: "compact_index_partial_update", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- source "#{source_uri}"
- gem 'myrack', '1.0.0'
- G
+ # Second install should make only a partial request to /versions
+ bundle :install, :artifice => "compact_index_partial_update"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "performs partial update while local cache is updated by another process" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack'
+ gem 'rack'
G
- # Create a partial cache versions file
- versions = Pathname.new(Bundler.rubygems.user_home).join(
- ".bundle", "cache", "compact_index",
- "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions"
- )
- versions.dirname.mkpath
- versions.write("created_at")
+ # Create an empty file to trigger a partial download
+ versions = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
+ "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions")
+ FileUtils.mkdir_p(File.dirname(versions))
+ FileUtils.touch(versions)
- bundle :install, artifice: "compact_index_concurrent_download"
+ bundle :install, :artifice => "compact_index_concurrent_download"
- expect(versions.read).to start_with("created_at")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(File.read(versions)).to start_with("created_at")
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
- it "performs a partial update that fails digest check, then a full update" do
+ it "performs full update if server endpoints serve partial content responses but don't have incremental content and provide no Etag" do
build_repo4 do
- build_gem "myrack", "0.9.1"
+ build_gem "rack", "0.9.1"
end
- install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
source "#{source_uri}"
- gem 'myrack', '0.9.1'
+ gem 'rack', '0.9.1'
G
update_repo4 do
- build_gem "myrack", "1.0.0"
+ build_gem "rack", "1.0.0"
end
- install_gemfile <<-G, artifice: "compact_index_partial_update_bad_digest", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ install_gemfile <<-G, :artifice => "compact_index_partial_update_no_etag_not_incremental", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
source "#{source_uri}"
- gem 'myrack', '1.0.0'
+ gem 'rack', '1.0.0'
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
-
- it "performs full update if server endpoints serve partial content responses but don't have incremental content and provide no digest" do
- build_repo4 do
- build_gem "myrack", "0.9.1"
- end
-
- install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- source "#{source_uri}"
- gem 'myrack', '0.9.1'
- G
-
- update_repo4 do
- build_gem "myrack", "1.0.0"
- end
-
- install_gemfile <<-G, artifice: "compact_index_partial_update_no_digest_not_incremental", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- source "#{source_uri}"
- gem 'myrack', '1.0.0'
- G
-
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "performs full update of compact index info cache if range is not satisfiable" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack', '0.9.1'
+ gem 'rack', '0.9.1'
G
- bundle :install, artifice: "compact_index"
-
- cache_path = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index", "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5")
+ rake_info_path = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
+ "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "info", "rack")
- # We must remove the etag so that we don't ignore the range and get a 304 Not Modified.
- myrack_info_etag_path = File.join(cache_path, "info-etags", "myrack-92f3313ce5721296f14445c3a6b9c073")
- File.unlink(myrack_info_etag_path) if File.exist?(myrack_info_etag_path)
+ bundle :install, :artifice => "compact_index"
- myrack_info_path = File.join(cache_path, "info", "myrack")
- expected_myrack_info_content = File.read(myrack_info_path)
+ expected_rack_info_content = File.read(rake_info_path)
- # Modify the cache files to make the range not satisfiable
- File.open(myrack_info_path, "a") {|f| f << "0.9.2 |checksum:c55b525b421fd833a93171ad3d7f04528ca8e87d99ac273f8933038942a5888c" }
+ # Modify the cache files. We expect them to be reset to the normal ones when we re-run :install
+ File.open(rake_info_path, "w") {|f| f << (expected_rack_info_content + "this is different") }
# Update the Gemfile so the next install does its normal things
gemfile <<-G
source "#{source_uri}"
- gem 'myrack', '1.0.0'
+ gem 'rack', '1.0.0'
G
# The cache files now being longer means the requested range is going to be not satisfiable
# Bundler must end up requesting the whole file to fix things up.
- bundle :install, artifice: "compact_index_range_not_satisfiable"
+ bundle :install, :artifice => "compact_index_range_not_satisfiable"
- resulting_myrack_info_content = File.read(myrack_info_path)
+ resulting_rack_info_content = File.read(rake_info_path)
- expect(resulting_myrack_info_content).to eq(expected_myrack_info_content)
+ expect(resulting_rack_info_content).to eq(expected_rack_info_content)
end
it "fails gracefully when the source URI has an invalid scheme" do
- install_gemfile <<-G, raise_on_error: false
+ install_gemfile <<-G, :raise_on_error => false
source "htps://rubygems.org"
- gem "myrack"
+ gem "rack"
G
expect(exitstatus).to eq(15)
expect(err).to end_with(<<-E.strip)
@@ -980,96 +876,58 @@ RSpec.describe "compact index api" do
end
describe "checksum validation" do
- before do
- lockfile <<-L
- GEM
- remote: #{source_uri}
- specs:
- myrack (1.0.0)
-
- PLATFORMS
- ruby
-
- DEPENDENCIES
- #{checksums_section}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
-
- it "handles checksums from the server in base64" do
- api_checksum = checksum_digest(gem_repo1, "myrack", "1.0.0")
- myrack_checksum = [[api_checksum].pack("H*")].pack("m0")
- install_gemfile <<-G, artifice: "compact_index", env: { "BUNDLER_SPEC_MYRACK_CHECKSUM" => myrack_checksum }
- source "#{source_uri}"
- gem "myrack"
- G
-
- expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems("myrack 1.0.0")
- end
-
it "raises when the checksum does not match" do
- install_gemfile <<-G, artifice: "compact_index_wrong_gem_checksum", raise_on_error: false
+ install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum", :raise_on_error => false
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- gem_path = if Bundler.feature_flag.global_gem_cache?
- default_cache_path.dirname.join("cache", "gems", "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "myrack-1.0.0.gem")
- else
- default_cache_path.dirname.join("myrack-1.0.0.gem")
- end
-
- expect(exitstatus).to eq(37)
- expect(err).to eq <<~E.strip
- Bundler found mismatched checksums. This is a potential security risk.
- myrack (1.0.0) sha256=2222222222222222222222222222222222222222222222222222222222222222
- from the API at http://localgemserver.test/
- #{checksum_to_lock(gem_repo1, "myrack", "1.0.0")}
- from the gem at #{gem_path}
-
- If you trust the API at http://localgemserver.test/, to resolve this issue you can:
- 1. remove the gem at #{gem_path}
- 2. run `bundle install`
-
- To ignore checksum security warnings, disable checksum validation with
- `bundle config set --local disable_checksum_validation true`
- E
+ expect(exitstatus).to eq(19)
+ expect(err).
+ to include("Bundler cannot continue installing rack (1.0.0).").
+ and include("The checksum for the downloaded `rack-1.0.0.gem` does not match the checksum given by the server.").
+ and include("This means the contents of the downloaded gem is different from what was uploaded to the server, and could be a potential security issue.").
+ and include("To resolve this issue:").
+ and include("1. delete the downloaded gem located at: `#{default_bundle_path}/gems/rack-1.0.0/rack-1.0.0.gem`").
+ and include("2. run `bundle install`").
+ and include("If you wish to continue installing the downloaded gem, and are certain it does not pose a security issue despite the mismatching checksum, do the following:").
+ and include("1. run `bundle config set --local disable_checksum_validation true` to turn off checksum verification").
+ and include("2. run `bundle install`").
+ and match(/\(More info: The expected SHA256 checksum was "#{"ab" * 22}", but the checksum for the downloaded gem was ".+?"\.\)/)
end
it "raises when the checksum is the wrong length" do
- install_gemfile <<-G, artifice: "compact_index_wrong_gem_checksum", env: { "BUNDLER_SPEC_MYRACK_CHECKSUM" => "checksum!", "DEBUG" => "1" }, verbose: true, raise_on_error: false
+ install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum", :env => { "BUNDLER_SPEC_RACK_CHECKSUM" => "checksum!", "DEBUG" => "1" }, :verbose => true, :raise_on_error => false
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- expect(exitstatus).to eq(14)
- expect(err).to include('Invalid checksum for myrack-0.9.1: "checksum!" is not a valid SHA256 hex or base64 digest')
+ expect(exitstatus).to eq(5)
+ expect(err).to include("The given checksum for rack-1.0.0 (\"checksum!\") is not a valid SHA256 hexdigest nor base64digest")
end
it "does not raise when disable_checksum_validation is set" do
bundle "config set disable_checksum_validation true"
- install_gemfile <<-G, artifice: "compact_index_wrong_gem_checksum"
+ install_gemfile <<-G, :artifice => "compact_index_wrong_gem_checksum"
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
end
end
it "works when cache dir is world-writable" do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
File.umask(0000)
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
end
it "doesn't explode when the API dependencies are wrong" do
- install_gemfile <<-G, artifice: "compact_index_wrong_dependencies", env: { "DEBUG" => "true" }, raise_on_error: false
+ install_gemfile <<-G, :artifice => "compact_index_wrong_dependencies", :env => { "DEBUG" => "true" }, :raise_on_error => false
source "#{source_uri}"
gem "rails"
G
- deps = [Gem::Dependency.new("rake", "= #{rake_version}"),
+ deps = [Gem::Dependency.new("rake", "= 13.0.1"),
Gem::Dependency.new("actionpack", "= 2.3.2"),
Gem::Dependency.new("activerecord", "= 2.3.2"),
Gem::Dependency.new("actionmailer", "= 2.3.2"),
@@ -1082,16 +940,15 @@ Running `bundle update rails` should fix the problem.
end
it "does not duplicate specs in the lockfile when updating and a dependency is not installed" do
- install_gemfile <<-G, artifice: "compact_index"
- source "https://gem.repo1"
+ install_gemfile <<-G, :artifice => "compact_index"
+ source "#{file_uri_for(gem_repo1)}"
source "#{source_uri}" do
gem "rails"
gem "activemerchant"
end
G
gem_command "uninstall activemerchant"
- bundle "update rails", artifice: "compact_index"
- count = lockfile.match?("CHECKSUMS") ? 2 : 1 # Once in the specs, and once in CHECKSUMS
- expect(lockfile.scan(/activemerchant \(/).size).to eq(count)
+ bundle "update rails", :artifice => "compact_index"
+ expect(lockfile.scan(/activemerchant \(/).size).to eq(1)
end
end
diff --git a/spec/bundler/install/gems/dependency_api_fallback_spec.rb b/spec/bundler/install/gems/dependency_api_fallback_spec.rb
deleted file mode 100644
index 107da15d67..0000000000
--- a/spec/bundler/install/gems/dependency_api_fallback_spec.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "../../support/silent_logger"
-
-RSpec.describe "gemcutter's dependency API" do
- context "when Gemcutter API takes too long to respond" do
- before do
- require_rack
-
- port = find_unused_port
- @server_uri = "http://127.0.0.1:#{port}"
-
- require_relative "../../support/artifice/endpoint_timeout"
-
- # mustermann depends on URI::RFC2396_PARSER behavior
- URI.parser = URI::RFC2396_PARSER if URI.respond_to?(:parser=)
-
- require "rackup/server"
-
- @t = Thread.new do
- server = Rackup::Server.start(app: EndpointTimeout,
- Host: "0.0.0.0",
- Port: port,
- server: "webrick",
- AccessLog: [],
- Logger: Spec::SilentLogger.new)
- server.start
- end
- @t.run
-
- wait_for_server("127.0.0.1", port)
- bundle "config set timeout 1"
- end
-
- after do
- Artifice.deactivate
- @t.kill
- @t.join
-
- URI.parser = URI::DEFAULT_PARSER if URI.respond_to?(:parser=)
- end
-
- it "times out and falls back on the modern index" do
- install_gemfile <<-G, artifice: nil, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
- source "#{@server_uri}"
- gem "myrack"
- G
-
- expect(out).to include("Fetching source index from #{@server_uri}/")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
- end
-end
diff --git a/spec/bundler/install/gems/dependency_api_spec.rb b/spec/bundler/install/gems/dependency_api_spec.rb
index 7396843f1d..a54f1db772 100644
--- a/spec/bundler/install/gems/dependency_api_spec.rb
+++ b/spec/bundler/install/gems/dependency_api_spec.rb
@@ -7,12 +7,12 @@ RSpec.describe "gemcutter's dependency API" do
it "should use the API" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "should URI encode gem names" do
@@ -21,7 +21,7 @@ RSpec.describe "gemcutter's dependency API" do
gem " sinatra"
G
- bundle :install, artifice: "endpoint", raise_on_error: false
+ bundle :install, :artifice => "endpoint", :raise_on_error => false
expect(err).to include("' sinatra' is not a valid gem name because it contains whitespace.")
end
@@ -31,7 +31,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "rails"
G
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(out).to include("Fetching gem metadata from #{source_uri}/...")
expect(the_bundle).to include_gems(
"rails 2.3.2",
@@ -49,22 +49,22 @@ RSpec.describe "gemcutter's dependency API" do
gem "net-sftp"
G
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(the_bundle).to include_gems "net-sftp 1.1.1"
end
it "should use the endpoint when using deployment mode" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
bundle "config set --local deployment true"
bundle "config set --local path vendor/bundle"
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "handles git dependencies that are in rubygems" do
@@ -75,12 +75,12 @@ RSpec.describe "gemcutter's dependency API" do
gemfile <<-G
source "#{source_uri}"
- git "#{lib_path("foo-1.0")}" do
+ git "#{file_uri_for(lib_path("foo-1.0"))}" do
gem 'foo'
end
G
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(the_bundle).to include_gems("rails 2.3.2")
end
@@ -93,13 +93,13 @@ RSpec.describe "gemcutter's dependency API" do
gemfile <<-G
source "#{source_uri}"
- gem 'foo', :git => "#{lib_path("foo-1.0")}"
+ gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
bundle "config set --local deployment true"
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(the_bundle).to include_gems("rails 2.3.2")
end
@@ -108,35 +108,35 @@ RSpec.describe "gemcutter's dependency API" do
build_git "foo"
gemfile <<-G
source "#{source_uri}"
- gem 'foo', :git => "#{lib_path("foo-1.0")}"
+ gem 'foo', :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
- bundle "install", artifice: "endpoint"
+ bundle "install", :artifice => "endpoint"
bundle "config set --local deployment true"
- bundle :install, artifice: "endpoint"
+ bundle :install, :artifice => "endpoint"
expect(the_bundle).to include_gems("foo 1.0")
end
it "falls back when the API errors out" do
- simulate_platform x86_mswin32 do
- build_repo2 do
- # The rcov gem is platform mswin32, but has no arch
- build_gem "rcov" do |s|
- s.platform = Gem::Platform.new([nil, "mswin32", nil])
- s.write "lib/rcov.rb", "RCOV = '1.0.0'"
- end
+ simulate_platform x86_mswin32
+
+ build_repo2 do
+ # The rcov gem is platform mswin32, but has no arch
+ build_gem "rcov" do |s|
+ s.platform = Gem::Platform.new([nil, "mswin32", nil])
+ s.write "lib/rcov.rb", "RCOV = '1.0.0'"
end
+ end
- gemfile <<-G
- source "#{source_uri}"
- gem "rcov"
- G
+ gemfile <<-G
+ source "#{source_uri}"
+ gem "rcov"
+ G
- bundle :install, artifice: "windows", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
- expect(out).to include("Fetching source index from #{source_uri}")
- expect(the_bundle).to include_gems "rcov 1.0.0"
- end
+ bundle :install, :artifice => "windows", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ expect(out).to include("Fetching source index from #{source_uri}")
+ expect(the_bundle).to include_gems "rcov 1.0.0"
end
it "falls back when hitting the Gemcutter Dependency Limit" do
@@ -147,10 +147,10 @@ RSpec.describe "gemcutter's dependency API" do
gem "actionmailer"
gem "activeresource"
gem "thin"
- gem "myrack"
+ gem "rack"
gem "rails"
G
- bundle :install, artifice: "endpoint_fallback"
+ bundle :install, :artifice => "endpoint_fallback"
expect(out).to include("Fetching source index from #{source_uri}")
expect(the_bundle).to include_gems(
@@ -160,7 +160,7 @@ RSpec.describe "gemcutter's dependency API" do
"activeresource 2.3.2",
"activesupport 2.3.2",
"thin 1.0.0",
- "myrack 1.0.0",
+ "rack 1.0.0",
"rails 2.3.2"
)
end
@@ -168,39 +168,39 @@ RSpec.describe "gemcutter's dependency API" do
it "falls back when Gemcutter API doesn't return proper Marshal format" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, verbose: true, artifice: "endpoint_marshal_fail"
+ bundle :install, :verbose => true, :artifice => "endpoint_marshal_fail"
expect(out).to include("could not fetch from the dependency API, trying the full index")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "falls back when the API URL returns 403 Forbidden" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, verbose: true, artifice: "endpoint_api_forbidden"
+ bundle :install, :verbose => true, :artifice => "endpoint_api_forbidden"
expect(out).to include("Fetching source index from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "handles host redirects" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_host_redirect"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "endpoint_host_redirect"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
- it "handles host redirects without Gem::Net::HTTP::Persistent" do
+ it "handles host redirects without Net::HTTP::Persistent" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
FileUtils.mkdir_p lib_path
@@ -216,18 +216,18 @@ RSpec.describe "gemcutter's dependency API" do
H
end
- bundle :install, artifice: "endpoint_host_redirect", requires: [lib_path("disable_net_http_persistent.rb")]
+ bundle :install, :artifice => "endpoint_host_redirect", :requires => [lib_path("disable_net_http_persistent.rb")]
expect(out).to_not match(/Too many redirects/)
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "timeouts when Bundler::Fetcher redirects too much" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_redirect", raise_on_error: false
+ bundle :install, :artifice => "endpoint_redirect", :raise_on_error => false
expect(err).to match(/Too many redirects/)
end
@@ -235,27 +235,27 @@ RSpec.describe "gemcutter's dependency API" do
it "should use the modern index for install" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --full-index", artifice: "endpoint"
+ bundle "install --full-index", :artifice => "endpoint"
expect(out).to include("Fetching source index from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "should use the modern index for update" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "update --full-index", artifice: "endpoint", all: true
+ bundle "update --full-index", :artifice => "endpoint", :all => true
expect(out).to include("Fetching source index from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
- it "fetches again when more dependencies are found in subsequent sources", bundler: "< 3" do
+ it "fetches again when more dependencies are found in subsequent sources", :bundler => "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -269,7 +269,7 @@ RSpec.describe "gemcutter's dependency API" do
gem "back_deps"
G
- bundle :install, artifice: "endpoint_extra"
+ bundle :install, :artifice => "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0"
end
@@ -288,33 +288,33 @@ RSpec.describe "gemcutter's dependency API" do
end
G
- bundle :install, artifice: "endpoint_extra"
+ bundle :install, :artifice => "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0", "foo 1.0"
end
it "fetches gem versions even when those gems are already installed" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
- bundle :install, artifice: "endpoint_extra_api"
+ bundle :install, :artifice => "endpoint_extra_api"
build_repo4 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
end
gemfile <<-G
source "#{source_uri}" do; end
source "#{source_uri}/extra"
- gem "myrack", "1.2"
+ gem "rack", "1.2"
G
- bundle :install, artifice: "endpoint_extra_api"
- expect(the_bundle).to include_gems "myrack 1.2"
+ bundle :install, :artifice => "endpoint_extra_api"
+ expect(the_bundle).to include_gems "rack 1.2"
end
- it "considers all possible versions of dependencies from all api gem sources", bundler: "< 3" do
+ it "considers all possible versions of dependencies from all api gem sources", :bundler => "< 3" do
# In this scenario, the gem "somegem" only exists in repo4. It depends on specific version of activesupport that
# exists only in repo1. There happens also be a version of activesupport in repo4, but not the one that version 1.0.0
# of somegem wants. This test makes sure that bundler actually finds version 1.2.3 of active support in the other
@@ -332,7 +332,7 @@ RSpec.describe "gemcutter's dependency API" do
gem 'somegem', '1.0.0'
G
- bundle :install, artifice: "endpoint_extra_api"
+ bundle :install, :artifice => "endpoint_extra_api"
expect(the_bundle).to include_gems "somegem 1.0.0"
expect(the_bundle).to include_gems "activesupport 1.2.3"
@@ -353,13 +353,13 @@ RSpec.describe "gemcutter's dependency API" do
end
G
- bundle :install, artifice: "endpoint_extra"
+ bundle :install, :artifice => "endpoint_extra"
expect(out).to include("Fetching gem metadata from http://localgemserver.test/.")
expect(out).to include("Fetching source index from http://localgemserver.test/extra")
end
- it "does not fetch every spec when doing back deps", bundler: "< 3" do
+ it "does not fetch every spec when doing back deps", :bundler => "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -369,7 +369,7 @@ RSpec.describe "gemcutter's dependency API" do
FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")]
end
- install_gemfile <<-G, artifice: "endpoint_extra_missing"
+ install_gemfile <<-G, :artifice => "endpoint_extra_missing", :env => env_for_missing_prerelease_default_gem_activation
source "#{source_uri}"
source "#{source_uri}/extra"
gem "back_deps"
@@ -388,7 +388,7 @@ RSpec.describe "gemcutter's dependency API" do
FileUtils.rm_rf Dir[gem_repo2("gems/foo-*.gem")]
end
- install_gemfile <<-G, artifice: "endpoint_extra_missing"
+ install_gemfile <<-G, :artifice => "endpoint_extra_missing", :env => env_for_missing_prerelease_default_gem_activation
source "#{source_uri}"
source "#{source_uri}/extra" do
gem "back_deps"
@@ -398,7 +398,7 @@ RSpec.describe "gemcutter's dependency API" do
expect(the_bundle).to include_gems "back_deps 1.0"
end
- it "fetches again when more dependencies are found in subsequent sources using deployment mode", bundler: "< 3" do
+ it "fetches again when more dependencies are found in subsequent sources using deployment mode", :bundler => "< 3" do
build_repo2 do
build_gem "back_deps" do |s|
s.add_dependency "foo"
@@ -412,9 +412,9 @@ RSpec.describe "gemcutter's dependency API" do
gem "back_deps"
G
- bundle :install, artifice: "endpoint_extra"
+ bundle :install, :artifice => "endpoint_extra"
bundle "config set --local deployment true"
- bundle :install, artifice: "endpoint_extra"
+ bundle :install, :artifice => "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -433,9 +433,9 @@ RSpec.describe "gemcutter's dependency API" do
end
G
- bundle :install, artifice: "endpoint_extra"
+ bundle :install, :artifice => "endpoint_extra"
bundle "config set --local deployment true"
- bundle "install", artifice: "endpoint_extra"
+ bundle "install", :artifice => "endpoint_extra"
expect(the_bundle).to include_gems "back_deps 1.0"
end
@@ -445,7 +445,7 @@ RSpec.describe "gemcutter's dependency API" do
build_gem "foo", "2.0"
end
- install_gemfile <<-G, artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, verbose: true
+ install_gemfile <<-G, :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, :verbose => true
source "#{source_uri}"
gem "foo"
@@ -468,70 +468,70 @@ RSpec.describe "gemcutter's dependency API" do
gem "bundler_dep"
G
- bundle :install, artifice: "endpoint", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ bundle :install, :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(out).to include("Fetching gem metadata from #{source_uri}")
end
- it "installs the binstubs", bundler: "< 3" do
+ it "installs the binstubs", :bundler => "< 3" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --binstubs", artifice: "endpoint"
+ bundle "install --binstubs", :artifice => "endpoint"
- gembin "myrackup"
+ gembin "rackup"
expect(out).to eq("1.0.0")
end
- it "installs the bins when using --path and uses autoclean", bundler: "< 3" do
+ it "installs the bins when using --path and uses autoclean", :bundler => "< 3" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --path vendor/bundle", artifice: "endpoint"
+ bundle "install --path vendor/bundle", :artifice => "endpoint"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
- it "installs the bins when using --path and uses bundle clean", bundler: "< 3" do
+ it "installs the bins when using --path and uses bundle clean", :bundler => "< 3" do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle "install --path vendor/bundle --no-clean", artifice: "endpoint"
+ bundle "install --path vendor/bundle --no-clean", :artifice => "endpoint"
- expect(vendored_gems("bin/myrackup")).to exist
+ expect(vendored_gems("bin/rackup")).to exist
end
it "prints post_install_messages" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack-obama'
+ gem 'rack-obama'
G
- bundle :install, artifice: "endpoint"
- expect(out).to include("Post-install message from myrack:")
+ bundle :install, :artifice => "endpoint"
+ expect(out).to include("Post-install message from rack:")
end
it "should display the post install message for a dependency" do
gemfile <<-G
source "#{source_uri}"
- gem 'myrack_middleware'
+ gem 'rack_middleware'
G
- bundle :install, artifice: "endpoint"
- expect(out).to include("Post-install message from myrack:")
- expect(out).to include("Myrack's post install message")
+ bundle :install, :artifice => "endpoint"
+ expect(out).to include("Post-install message from rack:")
+ expect(out).to include("Rack's post install message")
end
context "when using basic authentication" do
let(:user) { "user" }
let(:password) { "pass" }
let(:basic_auth_source_uri) do
- uri = Gem::URI.parse(source_uri)
+ uri = Bundler::URI.parse(source_uri)
uri.user = user
uri.password = password
@@ -541,82 +541,82 @@ RSpec.describe "gemcutter's dependency API" do
it "passes basic authentication details and strips out creds" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_basic_authentication"
+ bundle :install, :artifice => "endpoint_basic_authentication"
expect(out).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "passes basic authentication details and strips out creds also in verbose mode" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, verbose: true, artifice: "endpoint_basic_authentication"
+ bundle :install, :verbose => true, :artifice => "endpoint_basic_authentication"
expect(out).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "strips http basic authentication creds for modern index" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_marshal_fail_basic_authentication"
+ bundle :install, :artifice => "endpoint_marshal_fail_basic_authentication"
expect(out).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "strips http basic auth creds when it can't reach the server" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_500", raise_on_error: false
+ bundle :install, :artifice => "endpoint_500", :raise_on_error => false
expect(out).not_to include("#{user}:#{password}")
end
- it "strips http basic auth creds when warning about ambiguous sources", bundler: "< 3" do
+ it "strips http basic auth creds when warning about ambiguous sources", :bundler => "< 3" do
gemfile <<-G
source "#{basic_auth_source_uri}"
source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_basic_authentication"
- expect(err).to include("Warning: the gem 'myrack' was found in multiple sources.")
+ bundle :install, :artifice => "endpoint_basic_authentication"
+ expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).not_to include("#{user}:#{password}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not pass the user / password to different hosts on redirect" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_creds_diff_host"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "endpoint_creds_diff_host"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
describe "with host including dashes" do
before do
gemfile <<-G
source "http://local-gemserver.test"
- gem "myrack"
+ gem "rack"
G
end
it "reads authentication details from a valid ENV variable" do
- bundle :install, artifice: "endpoint_strict_basic_authentication", env: { "BUNDLE_LOCAL___GEMSERVER__TEST" => "#{user}:#{password}" }
+ bundle :install, :artifice => "endpoint_strict_basic_authentication", :env => { "BUNDLE_LOCAL___GEMSERVER__TEST" => "#{user}:#{password}" }
expect(out).to include("Fetching gem metadata from http://local-gemserver.test")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
@@ -624,57 +624,57 @@ RSpec.describe "gemcutter's dependency API" do
before do
gemfile <<-G
source "#{source_uri}"
- gem "myrack"
+ gem "rack"
G
end
it "reads authentication details by host name from bundle config" do
bundle "config set #{source_hostname} #{user}:#{password}"
- bundle :install, artifice: "endpoint_strict_basic_authentication"
+ bundle :install, :artifice => "endpoint_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "reads authentication details by full url from bundle config" do
# The trailing slash is necessary here; Fetcher canonicalizes the URI.
bundle "config set #{source_uri}/ #{user}:#{password}"
- bundle :install, artifice: "endpoint_strict_basic_authentication"
+ bundle :install, :artifice => "endpoint_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "should use the API" do
bundle "config set #{source_hostname} #{user}:#{password}"
- bundle :install, artifice: "endpoint_strict_basic_authentication"
+ bundle :install, :artifice => "endpoint_strict_basic_authentication"
expect(out).to include("Fetching gem metadata from #{source_uri}")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "prefers auth supplied in the source uri" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
bundle "config set #{source_hostname} otheruser:wrong"
- bundle :install, artifice: "endpoint_strict_basic_authentication"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "endpoint_strict_basic_authentication"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "shows instructions if auth is not provided for the source" do
- bundle :install, artifice: "endpoint_strict_basic_authentication", raise_on_error: false
+ bundle :install, :artifice => "endpoint_strict_basic_authentication", :raise_on_error => false
expect(err).to include("bundle config set --global #{source_hostname} username:password")
end
it "fails if authentication has already been provided, but failed" do
bundle "config set #{source_hostname} #{user}:wrong"
- bundle :install, artifice: "endpoint_strict_basic_authentication", raise_on_error: false
+ bundle :install, :artifice => "endpoint_strict_basic_authentication", :raise_on_error => false
expect(err).to include("Bad username or password")
end
end
@@ -685,11 +685,11 @@ RSpec.describe "gemcutter's dependency API" do
it "passes basic authentication details" do
gemfile <<-G
source "#{basic_auth_source_uri}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "endpoint_basic_authentication"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "endpoint_basic_authentication"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
end
@@ -710,10 +710,10 @@ RSpec.describe "gemcutter's dependency API" do
it "explains what to do to get it" do
gemfile <<-G
source "#{source_uri.gsub(/http/, "https")}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "fail", env: { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, raise_on_error: false
+ bundle :install, :env => { "RUBYOPT" => opt_add("-I#{bundled_app("broken_ssl")}", ENV["RUBYOPT"]) }, :raise_on_error => false
expect(err).to include("OpenSSL")
end
end
@@ -723,17 +723,17 @@ RSpec.describe "gemcutter's dependency API" do
# Install a monkeypatch that reproduces the effects of openssl raising
# a certificate validation error when RubyGems tries to connect.
gemfile <<-G
- class Gem::Net::HTTP
+ class Net::HTTP
def start
raise OpenSSL::SSL::SSLError, "certificate verify failed"
end
end
source "#{source_uri.gsub(/http/, "https")}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to match(/could not verify the SSL certificate/i)
end
end
@@ -741,16 +741,16 @@ RSpec.describe "gemcutter's dependency API" do
context ".gemrc with sources is present" do
it "uses other sources declared in the Gemfile" do
File.open(home(".gemrc"), "w") do |file|
- file.puts({ sources: ["https://rubygems.org"] }.to_yaml)
+ file.puts({ :sources => ["https://rubygems.org"] }.to_yaml)
end
begin
gemfile <<-G
source "#{source_uri}"
- gem 'myrack'
+ gem 'rack'
G
- bundle "install", artifice: "endpoint_marshal_fail"
+ bundle "install", :artifice => "endpoint_marshal_fail"
ensure
home(".gemrc").rmtree
end
diff --git a/spec/bundler/install/gems/env_spec.rb b/spec/bundler/install/gems/env_spec.rb
index 6d5aa456fe..a6dfadcfc8 100644
--- a/spec/bundler/install/gems/env_spec.rb
+++ b/spec/bundler/install/gems/env_spec.rb
@@ -4,104 +4,104 @@ RSpec.describe "bundle install with ENV conditionals" do
describe "when just setting an ENV key as a string" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
env "BUNDLER_TEST" do
- gem "myrack"
+ gem "rack"
end
G
end
it "excludes the gems when the ENV variable is not set" do
bundle :install
- expect(the_bundle).not_to include_gems "myrack"
+ expect(the_bundle).not_to include_gems "rack"
end
it "includes the gems when the ENV variable is set" do
ENV["BUNDLER_TEST"] = "1"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
describe "when just setting an ENV key as a symbol" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
env :BUNDLER_TEST do
- gem "myrack"
+ gem "rack"
end
G
end
it "excludes the gems when the ENV variable is not set" do
bundle :install
- expect(the_bundle).not_to include_gems "myrack"
+ expect(the_bundle).not_to include_gems "rack"
end
it "includes the gems when the ENV variable is set" do
ENV["BUNDLER_TEST"] = "1"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
describe "when setting a string to match the env" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
env "BUNDLER_TEST" => "foo" do
- gem "myrack"
+ gem "rack"
end
G
end
it "excludes the gems when the ENV variable is not set" do
bundle :install
- expect(the_bundle).not_to include_gems "myrack"
+ expect(the_bundle).not_to include_gems "rack"
end
it "excludes the gems when the ENV variable is set but does not match the condition" do
ENV["BUNDLER_TEST"] = "1"
bundle :install
- expect(the_bundle).not_to include_gems "myrack"
+ expect(the_bundle).not_to include_gems "rack"
end
it "includes the gems when the ENV variable is set and matches the condition" do
ENV["BUNDLER_TEST"] = "foo"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
describe "when setting a regex to match the env" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
env "BUNDLER_TEST" => /foo/ do
- gem "myrack"
+ gem "rack"
end
G
end
it "excludes the gems when the ENV variable is not set" do
bundle :install
- expect(the_bundle).not_to include_gems "myrack"
+ expect(the_bundle).not_to include_gems "rack"
end
it "excludes the gems when the ENV variable is set but does not match the condition" do
ENV["BUNDLER_TEST"] = "fo"
bundle :install
- expect(the_bundle).not_to include_gems "myrack"
+ expect(the_bundle).not_to include_gems "rack"
end
it "includes the gems when the ENV variable is set and matches the condition" do
ENV["BUNDLER_TEST"] = "foobar"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
end
diff --git a/spec/bundler/install/gems/flex_spec.rb b/spec/bundler/install/gems/flex_spec.rb
index b7e1b5f1bd..d5fa55be48 100644
--- a/spec/bundler/install/gems/flex_spec.rb
+++ b/spec/bundler/install/gems/flex_spec.rb
@@ -3,30 +3,30 @@
RSpec.describe "bundle flex_install" do
it "installs the gems as expected" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(the_bundle).to be_locked
end
it "installs even when the lockfile is invalid" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(the_bundle).to be_locked
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack', '1.0'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', '1.0'
G
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(the_bundle).to be_locked
end
@@ -34,19 +34,19 @@ RSpec.describe "bundle flex_install" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack-obama"
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "myrack-obama 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0", "rack-obama 1.0.0"
update_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack-obama", "1.0"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack-obama", "1.0"
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "myrack-obama 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0", "rack-obama 1.0.0"
end
describe "adding new gems" do
@@ -54,38 +54,38 @@ RSpec.describe "bundle flex_install" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
G
update_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
gem 'activesupport', '2.3.5'
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "activesupport 2.3.5"
+ expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.5"
end
it "keeps child dependencies pinned" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack-obama"
G
update_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack-obama"
gem "thin"
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "myrack-obama 1.0", "thin 1.0"
+ expect(the_bundle).to include_gems "rack 1.0.0", "rack-obama 1.0", "thin 1.0"
end
end
@@ -93,43 +93,43 @@ RSpec.describe "bundle flex_install" do
it "removes gems without changing the versions of remaining gems" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
gem 'activesupport', '2.3.5'
G
update_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
gem 'activesupport', '2.3.2'
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "activesupport 2.3.2"
+ expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.2"
end
it "removes top level dependencies when removed from the Gemfile while leaving other dependencies intact" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
gem 'activesupport', '2.3.5'
G
update_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack'
G
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
@@ -138,21 +138,21 @@ RSpec.describe "bundle flex_install" do
it "removes child dependencies" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem 'myrack-obama'
+ source "#{file_uri_for(gem_repo2)}"
+ gem 'rack-obama'
gem 'activesupport'
G
- expect(the_bundle).to include_gems "myrack 1.0.0", "myrack-obama 1.0.0", "activesupport 2.3.5"
+ expect(the_bundle).to include_gems "rack 1.0.0", "rack-obama 1.0.0", "activesupport 2.3.5"
update_repo2
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'activesupport'
G
expect(the_bundle).to include_gems "activesupport 2.3.5"
- expect(the_bundle).not_to include_gems "myrack-obama", "myrack"
+ expect(the_bundle).not_to include_gems "rack-obama", "rack"
end
end
@@ -160,63 +160,63 @@ RSpec.describe "bundle flex_install" do
before(:each) do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack_middleware"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack_middleware"
G
- expect(the_bundle).to include_gems "myrack_middleware 1.0", "myrack 0.9.1"
+ expect(the_bundle).to include_gems "rack_middleware 1.0", "rack 0.9.1"
build_repo2 do
- build_gem "myrack-obama", "2.0" do |s|
- s.add_dependency "myrack", "=1.2"
+ build_gem "rack-obama", "2.0" do |s|
+ s.add_dependency "rack", "=1.2"
end
- build_gem "myrack_middleware", "2.0" do |s|
- s.add_dependency "myrack", ">=1.0"
+ build_gem "rack_middleware", "2.0" do |s|
+ s.add_dependency "rack", ">=1.0"
end
end
gemfile <<-G
- source "https://gem.repo2"
- gem "myrack-obama", "2.0"
- gem "myrack_middleware"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack-obama", "2.0"
+ gem "rack_middleware"
G
end
it "does not install gems whose dependencies are not met" do
- bundle :install, raise_on_error: false
- ruby <<-RUBY, raise_on_error: false
+ bundle :install, :raise_on_error => false
+ ruby <<-RUBY, :raise_on_error => false
require 'bundler/setup'
RUBY
- expect(err).to match(/could not find gem 'myrack-obama/i)
+ expect(err).to match(/could not find gem 'rack-obama/i)
end
it "discards the locked gems when the Gemfile requires different versions than the lock" do
bundle "config set force_ruby_platform true"
- nice_error = <<~E.strip
+ nice_error = <<-E.strip.gsub(/^ {8}/, "")
Could not find compatible versions
- Because myrack-obama >= 2.0 depends on myrack = 1.2
- and myrack = 1.2 could not be found in rubygems repository https://gem.repo2/ or installed locally,
- myrack-obama >= 2.0 cannot be used.
- So, because Gemfile depends on myrack-obama = 2.0,
+ Because rack-obama >= 2.0 depends on rack = 1.2
+ and rack = 1.2 could not be found in rubygems repository #{file_uri_for(gem_repo2)}/ or installed locally,
+ rack-obama >= 2.0 cannot be used.
+ So, because Gemfile depends on rack-obama = 2.0,
version solving has failed.
E
- bundle :install, retry: 0, raise_on_error: false
+ bundle :install, :retry => 0, :raise_on_error => false
expect(err).to end_with(nice_error)
end
it "does not include conflicts with a single requirement tree, because that can't possibly be a conflict" do
bundle "config set force_ruby_platform true"
- bad_error = <<~E.strip
- Bundler could not find compatible versions for gem "myrack-obama":
+ bad_error = <<-E.strip.gsub(/^ {8}/, "")
+ Bundler could not find compatible versions for gem "rack-obama":
In Gemfile:
- myrack-obama (= 2.0)
+ rack-obama (= 2.0)
E
- bundle "update myrack_middleware", retry: 0, raise_on_error: false
+ bundle "update rack_middleware", :retry => 0, :raise_on_error => false
expect(err).not_to end_with(bad_error)
end
end
@@ -233,19 +233,19 @@ RSpec.describe "bundle flex_install" do
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "jekyll-feed", "~> 0.12"
G
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "github-pages", "~> 226"
gem "jekyll-feed", "~> 0.12"
G
end
it "discards the conflicting lockfile information and resolves properly" do
- bundle :update, raise_on_error: false, all: true
+ bundle :update, :raise_on_error => false, :all => true
expect(err).to be_empty
end
end
@@ -253,48 +253,43 @@ RSpec.describe "bundle flex_install" do
describe "subtler cases" do
before :each do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
+ gem "rack-obama"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
- gem "myrack-obama"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
+ gem "rack-obama"
G
end
it "should work when you install" do
bundle "install"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo1, "myrack", "0.9.1"
- c.checksum gem_repo1, "myrack-obama", "1.0"
- end
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (0.9.1)
- myrack-obama (1.0)
- myrack
+ rack (0.9.1)
+ rack-obama (1.0)
+ rack
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack (= 0.9.1)
- myrack-obama
- #{checksums}
+ rack (= 0.9.1)
+ rack-obama
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "should work when you update" do
- bundle "update myrack"
+ bundle "update rack"
end
end
@@ -302,37 +297,33 @@ RSpec.describe "bundle flex_install" do
it "updates the lockfile" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo1"
- source "https://gem.repo2" do
+ source "#{file_uri_for(gem_repo1)}"
+ source "#{file_uri_for(gem_repo2)}" do
end
- gem "myrack"
+ gem "rack"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo1, "myrack", "1.0.0"
- end
-
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -344,17 +335,17 @@ RSpec.describe "bundle flex_install" do
before(:each) do
build_repo2 do
build_gem "capybara", "0.3.9" do |s|
- s.add_dependency "myrack", ">= 1.0.0"
+ s.add_dependency "rack", ">= 1.0.0"
end
- build_gem "myrack", "1.1.0"
+ build_gem "rack", "1.1.0"
build_gem "rails", "3.0.0.rc4" do |s|
- s.add_dependency "myrack", "~> 1.1.0"
+ s.add_dependency "rack", "~> 1.1.0"
end
- build_gem "myrack", "1.2.1"
+ build_gem "rack", "1.2.1"
build_gem "rails", "3.0.0" do |s|
- s.add_dependency "myrack", "~> 1.2.1"
+ s.add_dependency "rack", "~> 1.2.1"
end
end
end
@@ -362,14 +353,14 @@ RSpec.describe "bundle flex_install" do
it "resolves them" do
# install Rails 3.0.0.rc
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0.0.rc4"
gem "capybara", "0.3.9"
G
# upgrade Rails to 3.0.0 and then install again
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "rails", "3.0.0"
gem "capybara", "0.3.9"
G
diff --git a/spec/bundler/install/gems/fund_spec.rb b/spec/bundler/install/gems/fund_spec.rb
index 0855a62b86..9aadc9ed25 100644
--- a/spec/bundler/install/gems/fund_spec.rb
+++ b/spec/bundler/install/gems/fund_spec.rb
@@ -32,10 +32,10 @@ RSpec.describe "bundle install" do
context "when gems include a fund URI" do
it "displays the plural fund message after installing" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding_and_other_metadata'
gem 'has_funding'
- gem 'myrack-obama'
+ gem 'rack-obama'
G
expect(out).to include("2 installed gems you directly depend on are looking for funding.")
@@ -43,9 +43,9 @@ RSpec.describe "bundle install" do
it "displays the singular fund message after installing" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding'
- gem 'myrack-obama'
+ gem 'rack-obama'
G
expect(out).to include("1 installed gem you directly depend on is looking for funding.")
@@ -59,10 +59,10 @@ RSpec.describe "bundle install" do
it "does not display the plural fund message after installing" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding_and_other_metadata'
gem 'has_funding'
- gem 'myrack-obama'
+ gem 'rack-obama'
G
expect(out).not_to include("2 installed gems you directly depend on are looking for funding.")
@@ -70,9 +70,9 @@ RSpec.describe "bundle install" do
it "does not display the singular fund message after installing" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding'
- gem 'myrack-obama'
+ gem 'rack-obama'
G
expect(out).not_to include("1 installed gem you directly depend on is looking for funding.")
@@ -82,7 +82,7 @@ RSpec.describe "bundle install" do
context "when gems do not include fund messages" do
it "does not display any fund messages" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "activesupport"
G
@@ -93,7 +93,7 @@ RSpec.describe "bundle install" do
context "when a dependency includes a fund message" do
it "does not display the fund message" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'gem_with_dependent_funding'
G
@@ -111,7 +111,7 @@ RSpec.describe "bundle install" do
}
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'also_has_funding', :git => '#{lib_path("also_has_funding-1.0")}'
G
@@ -125,7 +125,7 @@ RSpec.describe "bundle install" do
}
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'also_has_funding', :git => '#{lib_path("also_has_funding-1.0")}'
G
@@ -135,7 +135,7 @@ RSpec.describe "bundle install" do
}
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'also_has_funding', :git => '#{lib_path("also_has_funding-1.1")}'
G
@@ -149,7 +149,7 @@ RSpec.describe "bundle install" do
}
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'also_has_funding', :git => '#{lib_path("also_has_funding-1.0")}'
G
diff --git a/spec/bundler/install/gems/mirror_spec.rb b/spec/bundler/install/gems/mirror_spec.rb
index 70c0da50ef..9611973701 100644
--- a/spec/bundler/install/gems/mirror_spec.rb
+++ b/spec/bundler/install/gems/mirror_spec.rb
@@ -4,17 +4,17 @@ RSpec.describe "bundle install with a mirror configured" do
describe "when the mirror does not match the gem source" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
bundle "config set --local mirror.http://gems.example.org http://gem-mirror.example.org"
end
it "installs from the normal location" do
bundle :install
- expect(out).to include("Fetching gem metadata from https://gem.repo1")
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(out).to include("Fetching source index from #{file_uri_for(gem_repo1)}")
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
@@ -22,18 +22,18 @@ RSpec.describe "bundle install with a mirror configured" do
before :each do
gemfile <<-G
# This source is bogus and doesn't have the gem we're looking for
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack"
+ gem "rack"
G
- bundle "config set --local mirror.https://gem.repo2 https://gem.repo1"
+ bundle "config set --local mirror.#{file_uri_for(gem_repo2)} #{file_uri_for(gem_repo1)}"
end
it "installs the gem from the mirror" do
- bundle :install, artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
- expect(out).to include("Fetching gem metadata from https://gem.repo1")
- expect(out).not_to include("Fetching gem metadata from https://gem.repo2")
- expect(the_bundle).to include_gems "myrack 1.0"
+ bundle :install
+ expect(out).to include("Fetching source index from #{file_uri_for(gem_repo1)}")
+ expect(out).not_to include("Fetching source index from #{file_uri_for(gem_repo2)}")
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
end
diff --git a/spec/bundler/install/gems/native_extensions_spec.rb b/spec/bundler/install/gems/native_extensions_spec.rb
index 874818fa87..5c18d2cc51 100644
--- a/spec/bundler/install/gems/native_extensions_spec.rb
+++ b/spec/bundler/install/gems/native_extensions_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe "installing a gem with native extensions" do
s.extensions = ["ext/extconf.rb"]
s.write "ext/extconf.rb", <<-E
require "mkmf"
+ $extout = "$(topdir)/" + RbConfig::CONFIG["EXTOUT"]
name = "c_extension_bundle"
dir_config(name)
raise "OMG" unless with_config("c_extension") == "hello"
@@ -33,7 +34,7 @@ RSpec.describe "installing a gem with native extensions" do
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "c_extension"
G
@@ -51,6 +52,7 @@ RSpec.describe "installing a gem with native extensions" do
s.extensions = ["ext/extconf.rb"]
s.write "ext/extconf.rb", <<-E
require "mkmf"
+ $extout = "$(topdir)/" + RbConfig::CONFIG["EXTOUT"]
name = "c_extension_bundle"
dir_config(name)
raise "OMG" unless with_config("c_extension") == "hello"
@@ -78,7 +80,7 @@ RSpec.describe "installing a gem with native extensions" do
bundle "config set build.c_extension --with-c_extension=hello"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "c_extension", :git => #{lib_path("c_extension-1.0").to_s.dump}
G
@@ -91,10 +93,11 @@ RSpec.describe "installing a gem with native extensions" do
it "installs correctly from git when multiple gems with extensions share one repository" do
build_repo2 do
["one", "two"].each do |n|
- build_lib "c_extension_#{n}", "1.0", path: lib_path("gems/c_extension_#{n}") do |s|
+ build_lib "c_extension_#{n}", "1.0", :path => lib_path("gems/c_extension_#{n}") do |s|
s.extensions = ["ext/extconf.rb"]
s.write "ext/extconf.rb", <<-E
require "mkmf"
+ $extout = "$(topdir)/" + RbConfig::CONFIG["EXTOUT"]
name = "c_extension_bundle_#{n}"
dir_config(name)
raise "OMG" unless with_config("c_extension_#{n}") == "#{n}"
@@ -119,7 +122,7 @@ RSpec.describe "installing a gem with native extensions" do
C
end
end
- build_git "gems", path: lib_path("gems"), gemspec: false
+ build_git "gems", :path => lib_path("gems"), :gemspec => false
end
bundle "config set build.c_extension_one --with-c_extension_one=one"
@@ -127,13 +130,13 @@ RSpec.describe "installing a gem with native extensions" do
# 1st time, require only one gem -- only one of the extensions gets built.
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "c_extension_one", :git => #{lib_path("gems").to_s.dump}
G
# 2nd time, require both gems -- we need both extensions to be built now.
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "c_extension_one", :git => #{lib_path("gems").to_s.dump}
gem "c_extension_two", :git => #{lib_path("gems").to_s.dump}
G
@@ -147,6 +150,7 @@ RSpec.describe "installing a gem with native extensions" do
s.extensions = ["ext/extconf.rb"]
s.write "ext/extconf.rb", <<-E
require "mkmf"
+ $extout = "$(topdir)/" + RbConfig::CONFIG["EXTOUT"]
name = "c_extension_bundle"
dir_config(name)
raise "OMG" unless with_config("c_extension") == "hello" && with_config("c_extension_bundle-dir") == "hola"
@@ -174,7 +178,7 @@ RSpec.describe "installing a gem with native extensions" do
bundle "config set build.c_extension --with-c_extension=hello --with-c_extension_bundle-dir=hola"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "c_extension", :git => #{lib_path("c_extension-1.0").to_s.dump}
G
diff --git a/spec/bundler/install/gems/post_install_spec.rb b/spec/bundler/install/gems/post_install_spec.rb
index af753dba3e..7426f54877 100644
--- a/spec/bundler/install/gems/post_install_spec.rb
+++ b/spec/bundler/install/gems/post_install_spec.rb
@@ -5,26 +5,26 @@ RSpec.describe "bundle install" do
context "when gems include post install messages" do
it "should display the post-install messages after installing" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
gem 'thin'
- gem 'myrack-obama'
+ gem 'rack-obama'
G
bundle :install
- expect(out).to include("Post-install message from myrack:")
- expect(out).to include("Myrack's post install message")
+ expect(out).to include("Post-install message from rack:")
+ expect(out).to include("Rack's post install message")
expect(out).to include("Post-install message from thin:")
expect(out).to include("Thin's post install message")
- expect(out).to include("Post-install message from myrack-obama:")
- expect(out).to include("Myrack-obama's post install message")
+ expect(out).to include("Post-install message from rack-obama:")
+ expect(out).to include("Rack-obama's post install message")
end
end
context "when gems do not include post install messages" do
it "should not display any post-install messages" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
G
@@ -36,13 +36,13 @@ RSpec.describe "bundle install" do
context "when a dependency includes a post install message" do
it "should display the post install message" do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack_middleware'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack_middleware'
G
bundle :install
- expect(out).to include("Post-install message from myrack:")
- expect(out).to include("Myrack's post install message")
+ expect(out).to include("Post-install message from rack:")
+ expect(out).to include("Rack's post install message")
end
end
end
@@ -54,7 +54,7 @@ RSpec.describe "bundle install" do
s.post_install_message = "Foo's post install message"
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => '#{lib_path("foo-1.0")}'
G
@@ -68,7 +68,7 @@ RSpec.describe "bundle install" do
s.post_install_message = "Foo's post install message"
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => '#{lib_path("foo-1.0")}'
G
bundle :install
@@ -77,7 +77,7 @@ RSpec.describe "bundle install" do
s.post_install_message = "Foo's 1.1 post install message"
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => '#{lib_path("foo-1.1")}'
G
bundle :install
@@ -91,7 +91,7 @@ RSpec.describe "bundle install" do
s.post_install_message = "Foo's post install message"
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => '#{lib_path("foo-1.0")}'
G
@@ -110,7 +110,7 @@ RSpec.describe "bundle install" do
s.post_install_message = nil
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => '#{lib_path("foo-1.0")}'
G
@@ -123,11 +123,11 @@ RSpec.describe "bundle install" do
context "when ignore post-install messages for gem is set" do
it "doesn't display any post-install messages" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "config set ignore_messages.myrack true"
+ bundle "config set ignore_messages.rack true"
bundle :install
expect(out).not_to include("Post-install message")
@@ -137,8 +137,8 @@ RSpec.describe "bundle install" do
context "when ignore post-install messages for all gems" do
it "doesn't display any post-install messages" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set ignore_messages true"
diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb
index 694bc7c131..fb6dda2f88 100644
--- a/spec/bundler/install/gems/resolving_spec.rb
+++ b/spec/bundler/install/gems/resolving_spec.rb
@@ -66,7 +66,7 @@ RSpec.describe "bundle install with install-time dependencies" do
it "installs gems with implicit rake dependencies" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "with_implicit_rake_dep"
gem "another_implicit_rake_dep"
gem "rake"
@@ -84,7 +84,7 @@ RSpec.describe "bundle install with install-time dependencies" do
it "installs gems with implicit rake dependencies without rake previously installed" do
with_path_as("") do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "with_implicit_rake_dep"
gem "another_implicit_rake_dep"
gem "rake"
@@ -100,32 +100,30 @@ RSpec.describe "bundle install with install-time dependencies" do
expect(out).to eq("YES\nYES")
end
- it "does not install gems with a dependency with no type" do
+ it "installs gems with a dependency with no type" do
build_repo2
path = "#{gem_repo2}/#{Gem::MARSHAL_SPEC_DIR}/actionpack-2.3.2.gemspec.rz"
spec = Marshal.load(Bundler.rubygems.inflate(File.binread(path)))
spec.dependencies.each do |d|
- d.instance_variable_set(:@type, "fail")
+ d.instance_variable_set(:@type, :fail)
end
File.open(path, "wb") do |f|
f.write Gem.deflate(Marshal.dump(spec))
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
gem "actionpack", "2.3.2"
G
- expect(err).to include("Downloading actionpack-2.3.2 revealed dependencies not in the API or the lockfile (activesupport (= 2.3.2)).")
-
- expect(the_bundle).not_to include_gems "actionpack 2.3.2", "activesupport 2.3.2"
+ expect(the_bundle).to include_gems "actionpack 2.3.2", "activesupport 2.3.2"
end
describe "with crazy rubygem plugin stuff" do
it "installs plugins" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "net_b"
G
@@ -133,8 +131,8 @@ RSpec.describe "bundle install with install-time dependencies" do
end
it "installs plugins depended on by other plugins" do
- install_gemfile <<-G, env: { "DEBUG" => "1" }
- source "https://gem.repo2"
+ install_gemfile <<-G, :env => { "DEBUG" => "1" }
+ source "#{file_uri_for(gem_repo2)}"
gem "net_a"
G
@@ -142,8 +140,8 @@ RSpec.describe "bundle install with install-time dependencies" do
end
it "installs multiple levels of dependencies" do
- install_gemfile <<-G, env: { "DEBUG" => "1" }
- source "https://gem.repo2"
+ install_gemfile <<-G, :env => { "DEBUG" => "1" }
+ source "#{file_uri_for(gem_repo2)}"
gem "net_c"
gem "net_e"
G
@@ -154,12 +152,12 @@ RSpec.describe "bundle install with install-time dependencies" do
context "with ENV['BUNDLER_DEBUG_RESOLVER'] set" do
it "produces debug output" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "net_c"
gem "net_e"
G
- bundle :install, env: { "BUNDLER_DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
+ bundle :install, :env => { "BUNDLER_DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
expect(out).to include("Resolving dependencies...")
end
@@ -168,12 +166,12 @@ RSpec.describe "bundle install with install-time dependencies" do
context "with ENV['DEBUG_RESOLVER'] set" do
it "produces debug output" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "net_c"
gem "net_e"
G
- bundle :install, env: { "DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
+ bundle :install, :env => { "DEBUG_RESOLVER" => "1", "DEBUG" => "1" }
expect(out).to include("Resolving dependencies...")
end
@@ -182,12 +180,12 @@ RSpec.describe "bundle install with install-time dependencies" do
context "with ENV['DEBUG_RESOLVER_TREE'] set" do
it "produces debug output" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "net_c"
gem "net_e"
G
- bundle :install, env: { "DEBUG_RESOLVER_TREE" => "1", "DEBUG" => "1" }
+ bundle :install, :env => { "DEBUG_RESOLVER_TREE" => "1", "DEBUG" => "1" }
expect(out).to include(" net_b").
and include("Resolving dependencies...").
@@ -201,44 +199,44 @@ RSpec.describe "bundle install with install-time dependencies" do
context "allows only an older version" do
it "installs the older version" do
build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
- build_gem "myrack", "9001.0.0" do |s|
+ build_gem "rack", "9001.0.0" do |s|
s.required_ruby_version = "> 9000"
end
end
- install_gemfile <<-G
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
ruby "#{Gem.ruby_version}"
- source "https://gem.repo2"
- gem 'myrack'
+ source "http://localgemserver.test/"
+ gem 'rack'
G
- expect(err).to_not include("myrack-9001.0.0 requires ruby version > 9000")
- expect(the_bundle).to include_gems("myrack 1.2")
+ expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000")
+ expect(the_bundle).to include_gems("rack 1.2")
end
it "installs the older version when using servers not implementing the compact index API" do
build_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
- build_gem "myrack", "9001.0.0" do |s|
+ build_gem "rack", "9001.0.0" do |s|
s.required_ruby_version = "> 9000"
end
end
- install_gemfile <<-G, artifice: "endpoint"
+ install_gemfile <<-G, :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
ruby "#{Gem.ruby_version}"
- source "https://gem.repo2"
- gem 'myrack'
+ source "http://localgemserver.test/"
+ gem 'rack'
G
- expect(err).to_not include("myrack-9001.0.0 requires ruby version > 9000")
- expect(the_bundle).to include_gems("myrack 1.2")
+ expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000")
+ expect(the_bundle).to include_gems("rack 1.2")
end
context "when there is a lockfile using the newer incompatible version" do
@@ -254,17 +252,13 @@ RSpec.describe "bundle install with install-time dependencies" do
end
gemfile <<-G
- source "https://gem.repo2"
+ source "http://localgemserver.test/"
gem 'parallel_tests'
G
- checksums = checksums_section do |c|
- c.checksum gem_repo2, "parallel_tests", "3.8.0"
- end
-
lockfile <<~L
GEM
- remote: https://gem.repo2/
+ remote: http://localgemserver.test/
specs:
parallel_tests (3.8.0)
@@ -273,22 +267,18 @@ RSpec.describe "bundle install with install-time dependencies" do
DEPENDENCIES
parallel_tests
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "automatically updates lockfile to use the older version" do
- bundle "install --verbose"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "parallel_tests", "3.7.0"
- end
+ bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo2/
+ remote: http://localgemserver.test/
specs:
parallel_tests (3.7.0)
@@ -297,7 +287,7 @@ RSpec.describe "bundle install with install-time dependencies" do
DEPENDENCIES
parallel_tests
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -305,7 +295,7 @@ RSpec.describe "bundle install with install-time dependencies" do
it "gives a meaningful error if we're in frozen mode" do
expect do
- bundle "install --verbose", env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
+ bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s, "BUNDLE_FROZEN" => "true" }, :raise_on_error => false
end.not_to change { lockfile }
expect(err).to include("parallel_tests-3.8.0 requires ruby version >= #{next_ruby_minor}")
@@ -338,18 +328,13 @@ RSpec.describe "bundle install with install-time dependencies" do
end
gemfile <<-G
- source "https://gem.repo2"
+ source "http://localgemserver.test/"
gem 'rubocop'
G
- checksums = checksums_section do |c|
- c.checksum gem_repo2, "rubocop", "1.35.0"
- c.checksum gem_repo2, "rubocop-ast", "1.21.0"
- end
-
lockfile <<~L
GEM
- remote: https://gem.repo2/
+ remote: http://localgemserver.test/
specs:
rubocop (1.35.0)
rubocop-ast (>= 1.20.1, < 2.0)
@@ -360,23 +345,18 @@ RSpec.describe "bundle install with install-time dependencies" do
DEPENDENCIES
parallel_tests
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "automatically updates lockfile to use the older compatible versions" do
- bundle "install --verbose"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "rubocop", "1.28.2"
- c.checksum gem_repo2, "rubocop-ast", "1.17.0"
- end
+ bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo2/
+ remote: http://localgemserver.test/
specs:
rubocop (1.28.2)
rubocop-ast (>= 1.17.0, < 2.0)
@@ -387,7 +367,7 @@ RSpec.describe "bundle install with install-time dependencies" do
DEPENDENCIES
rubocop
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
@@ -407,13 +387,13 @@ RSpec.describe "bundle install with install-time dependencies" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem 'sorbet', '= 0.5.10554'
G
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
sorbet (0.5.10554)
sorbet-static (= 0.5.10554)
@@ -432,11 +412,11 @@ RSpec.describe "bundle install with install-time dependencies" do
it "raises a proper error" do
simulate_platform "aarch64-linux" do
- bundle "install", raise_on_error: false
+ bundle "install", :raise_on_error => false
end
- nice_error = <<~E.strip
- Could not find gems matching 'sorbet-static (= 0.5.10554)' valid for all resolution platforms (arm64-darwin-21, aarch64-linux) in rubygems repository https://gem.repo4/ or installed locally.
+ nice_error = strip_whitespace(<<-E).strip
+ Could not find gem 'sorbet-static (= 0.5.10554)' with platforms 'arm64-darwin-21', 'aarch64-linux' in rubygems repository #{file_uri_for(gem_repo4)}/ or installed locally.
The source contains the following gems matching 'sorbet-static (= 0.5.10554)':
* sorbet-static-0.5.10554-universal-darwin-21
@@ -445,62 +425,6 @@ RSpec.describe "bundle install with install-time dependencies" do
end
end
- context "when adding a new gem that does not resolve under all locked platforms" do
- before do
- simulate_platform "x86_64-linux" do
- build_repo4 do
- build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "x86_64-linux"
- end
- build_gem "nokogiri", "1.14.0" do |s|
- s.platform = "arm-linux"
- end
-
- build_gem "sorbet-static", "0.5.10696" do |s|
- s.platform = "x86_64-linux"
- end
- end
-
- lockfile <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- nokogiri (1.14.0-arm-linux)
- nokogiri (1.14.0-x86_64-linux)
-
- PLATFORMS
- arm-linux
- x86_64-linux
-
- DEPENDENCIES
- nokogiri
-
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- gemfile <<~G
- source "https://gem.repo4"
-
- gem "nokogiri"
- gem "sorbet-static"
- G
-
- bundle "lock", raise_on_error: false
- end
- end
-
- it "raises a proper error" do
- nice_error = <<~E.strip
- Could not find gems matching 'sorbet-static' valid for all resolution platforms (arm-linux, x86_64-linux) in rubygems repository https://gem.repo4/ or installed locally.
-
- The source contains the following gems matching 'sorbet-static':
- * sorbet-static-0.5.10696-x86_64-linux
- E
- expect(err).to end_with(nice_error)
- end
- end
-
it "gives a meaningful error on ruby version mismatches between dependencies" do
build_repo4 do
build_gem "requires-old-ruby" do |s|
@@ -508,14 +432,14 @@ RSpec.describe "bundle install with install-time dependencies" do
end
end
- build_lib("foo", path: bundled_app) do |s|
+ build_lib("foo", :path => bundled_app) do |s|
s.required_ruby_version = ">= #{Gem.ruby_version}"
s.add_dependency "requires-old-ruby"
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo4"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo4)}"
gemspec
G
@@ -533,47 +457,47 @@ RSpec.describe "bundle install with install-time dependencies" do
it "installs the older version under rate limiting conditions" do
build_repo4 do
- build_gem "myrack", "9001.0.0" do |s|
+ build_gem "rack", "9001.0.0" do |s|
s.required_ruby_version = "> 9000"
end
- build_gem "myrack", "1.2"
+ build_gem "rack", "1.2"
build_gem "foo1", "1.0"
end
- install_gemfile <<-G, artifice: "compact_index_rate_limited"
+ install_gemfile <<-G, :artifice => "compact_index_rate_limited", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
ruby "#{Gem.ruby_version}"
- source "https://gem.repo4"
- gem 'myrack'
+ source "http://localgemserver.test/"
+ gem 'rack'
gem 'foo1'
G
- expect(err).to_not include("myrack-9001.0.0 requires ruby version > 9000")
- expect(the_bundle).to include_gems("myrack 1.2")
+ expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000")
+ expect(the_bundle).to include_gems("rack 1.2")
end
it "installs the older not platform specific version" do
build_repo4 do
- build_gem "myrack", "9001.0.0" do |s|
+ build_gem "rack", "9001.0.0" do |s|
s.required_ruby_version = "> 9000"
end
- build_gem "myrack", "1.2" do |s|
+ build_gem "rack", "1.2" do |s|
s.platform = x86_mingw32
s.required_ruby_version = "> 9000"
end
- build_gem "myrack", "1.2"
+ build_gem "rack", "1.2"
end
simulate_platform x86_mingw32 do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
ruby "#{Gem.ruby_version}"
- source "https://gem.repo4"
- gem 'myrack'
+ source "http://localgemserver.test/"
+ gem 'rack'
G
end
- expect(err).to_not include("myrack-9001.0.0 requires ruby version > 9000")
- expect(err).to_not include("myrack-1.2-#{Bundler.local_platform} requires ruby version > 9000")
- expect(the_bundle).to include_gems("myrack 1.2")
+ expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000")
+ expect(err).to_not include("rack-1.2-#{Bundler.local_platform} requires ruby version > 9000")
+ expect(the_bundle).to include_gems("rack 1.2")
end
end
@@ -590,14 +514,14 @@ RSpec.describe "bundle install with install-time dependencies" do
let(:error_message_requirement) { "= #{Gem.ruby_version}" }
it "raises a proper error that mentions the current Ruby version during resolution" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, :raise_on_error => false
+ source "http://localgemserver.test/"
gem 'require_ruby'
G
expect(out).to_not include("Gem::InstallError: require_ruby requires Ruby version > 9000")
- nice_error = <<~E.strip
+ nice_error = strip_whitespace(<<-E).strip
Could not find compatible versions
Because every version of require_ruby depends on Ruby > 9000
@@ -611,15 +535,15 @@ RSpec.describe "bundle install with install-time dependencies" do
shared_examples_for "ruby version conflicts" do
it "raises an error during resolution" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, :raise_on_error => false
+ source "http://localgemserver.test/"
ruby #{ruby_requirement}
gem 'require_ruby'
G
expect(out).to_not include("Gem::InstallError: require_ruby requires Ruby version > 9000")
- nice_error = <<~E.strip
+ nice_error = strip_whitespace(<<-E).strip
Could not find compatible versions
Because every version of require_ruby depends on Ruby > 9000
@@ -657,13 +581,13 @@ RSpec.describe "bundle install with install-time dependencies" do
end
end
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
gem 'require_rubygems'
G
expect(err).to_not include("Gem::InstallError: require_rubygems requires RubyGems version > 9000")
- nice_error = <<~E.strip
+ nice_error = strip_whitespace(<<-E).strip
Because every version of require_rubygems depends on RubyGems > 9000
and Gemfile depends on require_rubygems >= 0,
RubyGems > 9000 is required.
@@ -673,55 +597,4 @@ RSpec.describe "bundle install with install-time dependencies" do
expect(err).to end_with(nice_error)
end
end
-
- context "when non platform specific gems bring more dependencies", :truffleruby_only do
- before do
- build_repo4 do
- build_gem "foo", "1.0" do |s|
- s.add_dependency "bar"
- end
-
- build_gem "foo", "2.0" do |s|
- s.platform = "x86_64-linux"
- end
-
- build_gem "bar"
- end
-
- gemfile <<-G
- source "https://gem.repo4"
- gem "foo"
- G
- end
-
- it "locks both ruby and current platform, and resolve to ruby variants that install on truffleruby" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "foo", "1.0"
- c.checksum gem_repo4, "bar", "1.0"
- end
-
- simulate_platform "x86_64-linux" do
- bundle "install"
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- bar (1.0)
- foo (1.0)
- bar
-
- PLATFORMS
- ruby
- x86_64-linux
-
- DEPENDENCIES
- foo
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
- end
end
diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb
index 65b14ea425..4d08752256 100644
--- a/spec/bundler/install/gems/standalone_spec.rb
+++ b/spec/bundler/install/gems/standalone_spec.rb
@@ -8,9 +8,9 @@ RSpec.shared_examples "bundle install --standalone" do
end
it "still makes system gems unavailable to normal bundler" do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
- expect(the_bundle).to_not include_gems("myrack")
+ expect(the_bundle).to_not include_gems("rack")
end
it "generates a bundle/bundler/setup.rb" do
@@ -63,14 +63,14 @@ RSpec.shared_examples "bundle install --standalone" do
end
it "makes system gems unavailable without bundler" do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
testrb = String.new <<-RUBY
$:.unshift File.expand_path("bundle")
require "bundler/setup"
begin
- require "myrack"
+ require "rack"
rescue LoadError
puts "LoadError"
end
@@ -97,23 +97,7 @@ RSpec.shared_examples "bundle install --standalone" do
testrb << "\nrequire \"#{k}\""
testrb << "\nputs #{k.upcase}"
end
- ruby testrb, dir: "#{bundled_app}2"
-
- expect(out).to eq(expected_gems.values.join("\n"))
- end
-
- it "skips activating gems" do
- testrb = String.new <<-RUBY
- $:.unshift File.expand_path("bundle")
- require "bundler/setup"
-
- gem "do_not_activate_me"
- RUBY
- expected_gems.each do |k, _|
- testrb << "\nrequire \"#{k}\""
- testrb << "\nputs #{k.upcase}"
- end
- sys_exec %(#{Gem.ruby} -w -e #{testrb.shellescape})
+ ruby testrb, :dir => "#{bundled_app}2"
expect(out).to eq(expected_gems.values.join("\n"))
end
@@ -122,11 +106,11 @@ RSpec.shared_examples "bundle install --standalone" do
describe "with simple gems" do
before do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, standalone: true, dir: cwd
+ bundle :install, :standalone => true, :dir => cwd
end
let(:expected_gems) do
@@ -141,21 +125,21 @@ RSpec.shared_examples "bundle install --standalone" do
describe "with default gems and a lockfile", :ruby_repo do
before do
- necessary_system_gems = ["tsort --version 0.1.0"]
- necessary_system_gems += ["etc --version 1.4.3"]
- realworld_system_gems(*necessary_system_gems)
- end
+ skip "does not work on rubygems versions where `--install_dir` doesn't respect --default" unless Gem::Installer.for_spec(loaded_gemspec, :install_dir => "/foo").default_spec_file == "/foo/specifications/default/bundler-#{Bundler::VERSION}.gemspec" # Since rubygems 3.2.0.rc.2
+ skip "does not work on old rubies because the realworld gems that need to be installed don't support them" if RUBY_VERSION < "2.7.0"
- it "works and points to the vendored copies, not to the default copies" do
- necessary_gems_in_bundle_path = ["optparse --version 0.1.1", "psych --version 3.3.2", "logger --version 1.4.3", "etc --version 1.4.3", "stringio --version 3.1.0"]
- necessary_gems_in_bundle_path += ["yaml --version 0.1.1"] if Gem.rubygems_version < Gem::Version.new("3.4.a")
- realworld_system_gems(*necessary_gems_in_bundle_path, path: scoped_gem_path(bundled_app("bundle")))
+ realworld_system_gems "tsort --version 0.1.0"
- build_gem "foo", "1.0.0", to_system: true, default: true do |s|
+ necessary_system_gems = ["optparse --version 0.1.1", "psych --version 3.3.2", "logger --version 1.4.3", "etc --version 1.2.0", "stringio --version 3.0.1"]
+ necessary_system_gems += ["shellwords --version 0.1.0", "base64 --version 0.1.0", "resolv --version 0.2.1"] if Gem.rubygems_version < Gem::Version.new("3.3.a")
+ necessary_system_gems += ["yaml --version 0.1.1"] if Gem.rubygems_version < Gem::Version.new("3.4.a")
+ realworld_system_gems(*necessary_system_gems, :path => scoped_gem_path(bundled_app("bundle")))
+
+ build_gem "foo", "1.0.0", :to_system => true, :default => true do |s|
s.add_dependency "bar"
end
- build_gem "bar", "1.0.0", to_system: true, default: true
+ build_gem "bar", "1.0.0", :to_system => true, :default => true
build_repo4 do
build_gem "foo", "1.0.0" do |s|
@@ -170,10 +154,12 @@ RSpec.shared_examples "bundle install --standalone" do
gem "foo"
G
- bundle "lock", dir: cwd
+ bundle "lock", :dir => cwd, :artifice => "compact_index"
+ end
+ it "works and points to the vendored copies, not to the default copies", :realworld do
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, standalone: true, dir: cwd, env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
+ bundle :install, :standalone => true, :dir => cwd, :artifice => "compact_index", :env => { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
load_path_lines = bundled_app("bundle/bundler/setup.rb").read.split("\n").select {|line| line.start_with?("$:.unshift") }
@@ -182,59 +168,27 @@ RSpec.shared_examples "bundle install --standalone" do
'$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/foo-1.0.0/lib")',
]
end
-
- it "works for gems with extensions and points to the vendored copies, not to the default copies" do
- necessary_gems_in_bundle_path = ["optparse --version 0.1.1", "psych --version 3.3.2", "logger --version 1.4.3", "etc --version 1.4.3", "stringio --version 3.1.0", "shellwords --version 0.2.0", "open3 --version 0.2.1"]
- necessary_gems_in_bundle_path += ["yaml --version 0.1.1"] if Gem.rubygems_version < Gem::Version.new("3.4.a")
- realworld_system_gems(*necessary_gems_in_bundle_path, path: scoped_gem_path(bundled_app("bundle")))
-
- build_gem "baz", "1.0.0", to_system: true, default: true, &:add_c_extension
-
- build_repo4 do
- build_gem "baz", "1.0.0", &:add_c_extension
- end
-
- gemfile <<-G
- source "https://gem.repo4"
- gem "baz"
- G
-
- bundle "config set --local path #{bundled_app("bundle")}"
-
- simulate_platform "arm64-darwin-23" do
- bundle "lock", dir: cwd
-
- bundle :install, standalone: true, dir: cwd, env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
- end
-
- load_path_lines = bundled_app("bundle/bundler/setup.rb").read.split("\n").select {|line| line.start_with?("$:.unshift") }
-
- expect(load_path_lines).to eq [
- '$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-23/#{Gem.extension_api_version}/baz-1.0.0")',
- '$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/baz-1.0.0/lib")',
- ]
- end
end
describe "with Gemfiles using absolute path sources and resulting bundle moved to a folder hierarchy with different nesting" do
before do
- build_lib "minitest", "1.0.0", path: lib_path("minitest")
+ build_lib "minitest", "1.0.0", :path => lib_path("minitest")
Dir.mkdir bundled_app("app")
gemfile bundled_app("app/Gemfile"), <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "minitest", :path => "#{lib_path("minitest")}"
G
- bundle "install", standalone: true, dir: bundled_app("app")
+ bundle "install", :standalone => true, :dir => bundled_app("app")
Dir.mkdir tmp("one_more_level")
FileUtils.mv bundled_app, tmp("one_more_level")
end
it "also works" do
- ruby <<-RUBY, dir: tmp("one_more_level/bundled_app/app")
+ ruby <<-RUBY, :dir => tmp("one_more_level/bundled_app/app")
require "./bundle/bundler/setup"
require "minitest"
@@ -250,20 +204,20 @@ RSpec.shared_examples "bundle install --standalone" do
before do
FileUtils.mkdir_p bundled_app("app/vendor")
- build_lib "minitest", "1.0.0", path: bundled_app("app/vendor/minitest")
+ build_lib "minitest", "1.0.0", :path => bundled_app("app/vendor/minitest")
gemfile bundled_app("app/Gemfile"), <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "minitest", :path => "vendor/minitest"
G
- bundle "install", standalone: true, dir: bundled_app("app")
+ bundle "install", :standalone => true, :dir => bundled_app("app")
FileUtils.mv(bundled_app("app"), bundled_app2("app"))
end
it "also works" do
- ruby <<-RUBY, dir: bundled_app2("app")
+ ruby <<-RUBY, :dir => bundled_app2("app")
require "./bundle/bundler/setup"
require "minitest"
@@ -278,8 +232,8 @@ RSpec.shared_examples "bundle install --standalone" do
describe "with gems with native extension" do
before do
bundle "config set --local path #{bundled_app("bundle")}"
- install_gemfile <<-G, standalone: true, dir: cwd
- source "https://gem.repo1"
+ install_gemfile <<-G, :standalone => true, :dir => cwd
+ source "#{file_uri_for(gem_repo1)}"
gem "very_simple_binary"
G
end
@@ -298,7 +252,7 @@ RSpec.shared_examples "bundle install --standalone" do
describe "with gem that has an invalid gemspec" do
before do
- build_git "bar", gemspec: false do |s|
+ build_git "bar", :gemspec => false do |s|
s.write "lib/bar/version.rb", %(BAR_VERSION = '1.0')
s.write "bar.gemspec", <<-G
lib = File.expand_path('lib/', __dir__)
@@ -316,15 +270,15 @@ RSpec.shared_examples "bundle install --standalone" do
G
end
bundle "config set --local path #{bundled_app("bundle")}"
- install_gemfile <<-G, standalone: true, dir: cwd, raise_on_error: false
- source "https://gem.repo1"
+ install_gemfile <<-G, :standalone => true, :dir => cwd, :raise_on_error => false
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :git => "#{lib_path("bar-1.0")}"
G
end
it "outputs a helpful error message" do
expect(err).to include("You have one or more invalid gemspecs that need to be fixed.")
- expect(err).to include("bar.gemspec is not valid")
+ expect(err).to include("bar 1.0 has an invalid gemspec")
end
end
@@ -333,12 +287,12 @@ RSpec.shared_examples "bundle install --standalone" do
build_git "devise", "1.0"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
gem "devise", :git => "#{lib_path("devise-1.0")}"
G
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, standalone: true, dir: cwd
+ bundle :install, :standalone => true, :dir => cwd
end
let(:expected_gems) do
@@ -357,16 +311,16 @@ RSpec.shared_examples "bundle install --standalone" do
build_git "devise", "1.0"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
group :test do
gem "rspec"
- gem "myrack-test"
+ gem "rack-test"
end
G
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, standalone: true, dir: cwd
+ bundle :install, :standalone => true, :dir => cwd
end
let(:expected_gems) do
@@ -380,7 +334,7 @@ RSpec.shared_examples "bundle install --standalone" do
it "allows creating a standalone file with limited groups" do
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, standalone: "default", dir: cwd
+ bundle :install, :standalone => "default", :dir => cwd
load_error_ruby <<-RUBY, "spec"
$:.unshift File.expand_path("bundle")
@@ -398,7 +352,7 @@ RSpec.shared_examples "bundle install --standalone" do
it "allows `without` configuration to limit the groups used in a standalone" do
bundle "config set --local path #{bundled_app("bundle")}"
bundle "config set --local without test"
- bundle :install, standalone: true, dir: cwd
+ bundle :install, :standalone => true, :dir => cwd
load_error_ruby <<-RUBY, "spec"
$:.unshift File.expand_path("bundle")
@@ -415,7 +369,7 @@ RSpec.shared_examples "bundle install --standalone" do
it "allows `path` configuration to change the location of the standalone bundle" do
bundle "config set --local path path/to/bundle"
- bundle "install", standalone: true, dir: cwd
+ bundle "install", :standalone => true, :dir => cwd
ruby <<-RUBY
$:.unshift File.expand_path("path/to/bundle")
@@ -430,9 +384,9 @@ RSpec.shared_examples "bundle install --standalone" do
it "allows `without` to limit the groups used in a standalone" do
bundle "config set --local without test"
- bundle :install, dir: cwd
+ bundle :install, :dir => cwd
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, standalone: true, dir: cwd
+ bundle :install, :standalone => true, :dir => cwd
load_error_ruby <<-RUBY, "spec"
$:.unshift File.expand_path("bundle")
@@ -458,7 +412,7 @@ RSpec.shared_examples "bundle install --standalone" do
gem "rails"
G
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, standalone: true, artifice: "endpoint", dir: cwd
+ bundle :install, :standalone => true, :artifice => "endpoint", :dir => cwd
end
let(:expected_gems) do
@@ -472,14 +426,14 @@ RSpec.shared_examples "bundle install --standalone" do
end
end
- describe "with --binstubs", bundler: "< 3" do
+ describe "with --binstubs", :bundler => "< 3" do
before do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
bundle "config set --local path #{bundled_app("bundle")}"
- bundle :install, standalone: true, binstubs: true, dir: cwd
+ bundle :install, :standalone => true, :binstubs => true, :dir => cwd
end
let(:expected_gems) do
@@ -497,7 +451,7 @@ RSpec.shared_examples "bundle install --standalone" do
it "creates stubs that can be executed from anywhere" do
require "tmpdir"
- sys_exec(%(#{bundled_app("bin/rails")} -v), dir: Dir.tmpdir)
+ sys_exec(%(#{bundled_app("bin/rails")} -v), :dir => Dir.tmpdir)
expect(out).to eq("2.3.2")
end
@@ -535,23 +489,23 @@ end
RSpec.describe "bundle install --standalone --local" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- system_gems "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-1.0.0", :path => default_bundle_path
end
it "generates script pointing to system gems" do
bundle "install --standalone --local --verbose"
- expect(out).to include("Using myrack 1.0.0")
+ expect(out).to include("Using rack 1.0.0")
load_error_ruby <<-RUBY, "spec"
require "./bundler/setup"
- require "myrack"
- puts MYRACK
+ require "rack"
+ puts RACK
require "spec"
RUBY
diff --git a/spec/bundler/install/gems/win32_spec.rb b/spec/bundler/install/gems/win32_spec.rb
index be37673aa1..419b14ff0f 100644
--- a/spec/bundler/install/gems/win32_spec.rb
+++ b/spec/bundler/install/gems/win32_spec.rb
@@ -4,22 +4,22 @@ RSpec.describe "bundle install with win32-generated lockfile" do
it "should read lockfile" do
File.open(bundled_app_lock, "wb") do |f|
f << "GEM\r\n"
- f << " remote: https://gem.repo1/\r\n"
+ f << " remote: #{file_uri_for(gem_repo1)}/\r\n"
f << " specs:\r\n"
f << "\r\n"
- f << " myrack (1.0.0)\r\n"
+ f << " rack (1.0.0)\r\n"
f << "\r\n"
f << "PLATFORMS\r\n"
f << " ruby\r\n"
f << "\r\n"
f << "DEPENDENCIES\r\n"
- f << " myrack\r\n"
+ f << " rack\r\n"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
- gem "myrack"
+ gem "rack"
G
end
end
diff --git a/spec/bundler/install/gemspecs_spec.rb b/spec/bundler/install/gemspecs_spec.rb
index 7629870db2..7b58ea9839 100644
--- a/spec/bundler/install/gemspecs_spec.rb
+++ b/spec/bundler/install/gemspecs_spec.rb
@@ -4,13 +4,13 @@ RSpec.describe "bundle install" do
describe "when a gem has a YAML gemspec" do
before :each do
build_repo2 do
- build_gem "yaml_spec", gemspec: :yaml
+ build_gem "yaml_spec", :gemspec => :yaml
end
end
it "still installs correctly" do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "yaml_spec"
G
bundle :install
@@ -18,10 +18,10 @@ RSpec.describe "bundle install" do
end
it "still installs correctly when using path" do
- build_lib "yaml_spec", gemspec: :yaml
+ build_lib "yaml_spec", :gemspec => :yaml
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'yaml_spec', :path => "#{lib_path("yaml_spec-1.0")}"
G
expect(err).to be_empty
@@ -31,22 +31,22 @@ RSpec.describe "bundle install" do
it "should use gemspecs in the system cache when available" do
gemfile <<-G
source "http://localtestserver.gem"
- gem 'myrack'
+ gem 'rack'
G
- system_gems "myrack-1.0.0", path: default_bundle_path
+ system_gems "rack-1.0.0", :path => default_bundle_path
FileUtils.mkdir_p "#{default_bundle_path}/specifications"
- File.open("#{default_bundle_path}/specifications/myrack-1.0.0.gemspec", "w+") do |f|
+ File.open("#{default_bundle_path}/specifications/rack-1.0.0.gemspec", "w+") do |f|
spec = Gem::Specification.new do |s|
- s.name = "myrack"
+ s.name = "rack"
s.version = "1.0.0"
- s.add_dependency "activesupport", "2.3.2"
+ s.add_runtime_dependency "activesupport", "2.3.2"
end
f.write spec.to_ruby
end
- bundle :install, artifice: "endpoint_marshal_fail" # force gemspec load
- expect(the_bundle).to include_gems "myrack 1.0.0", "activesupport 2.3.2"
+ bundle :install, :artifice => "endpoint_marshal_fail" # force gemspec load
+ expect(the_bundle).to include_gems "rack 1.0.0", "activesupport 2.3.2"
end
it "does not hang when gemspec has incompatible encoding" do
@@ -59,8 +59,8 @@ RSpec.describe "bundle install" do
end
G
- install_gemfile <<-G, env: { "LANG" => "C" }
- source "https://gem.repo1"
+ install_gemfile <<-G, :env => { "LANG" => "C" }
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
@@ -86,7 +86,7 @@ RSpec.describe "bundle install" do
G
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
@@ -95,43 +95,43 @@ RSpec.describe "bundle install" do
context "when ruby version is specified in gemspec and gemfile" do
it "installs when patch level is not specified and the version matches",
- if: RUBY_PATCHLEVEL >= 0 do
- build_lib("foo", path: bundled_app) do |s|
+ :if => RUBY_PATCHLEVEL >= 0 do
+ build_lib("foo", :path => bundled_app) do |s|
s.required_ruby_version = "~> #{RUBY_VERSION}.0"
end
install_gemfile <<-G
ruby '#{RUBY_VERSION}', :engine_version => '#{RUBY_VERSION}', :engine => 'ruby'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
expect(the_bundle).to include_gems "foo 1.0"
end
it "installs when patch level is specified and the version still matches the current version",
- if: RUBY_PATCHLEVEL >= 0 do
- build_lib("foo", path: bundled_app) do |s|
+ :if => RUBY_PATCHLEVEL >= 0 do
+ build_lib("foo", :path => bundled_app) do |s|
s.required_ruby_version = "#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}"
end
- install_gemfile <<-G, raise_on_error: false
+ install_gemfile <<-G, :raise_on_error => false
ruby '#{RUBY_VERSION}', :engine_version => '#{RUBY_VERSION}', :engine => 'ruby', :patchlevel => '#{RUBY_PATCHLEVEL}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
expect(the_bundle).to include_gems "foo 1.0"
end
it "fails and complains about patchlevel on patchlevel mismatch",
- if: RUBY_PATCHLEVEL >= 0 do
+ :if => RUBY_PATCHLEVEL >= 0 do
patchlevel = RUBY_PATCHLEVEL.to_i + 1
- build_lib("foo", path: bundled_app) do |s|
+ build_lib("foo", :path => bundled_app) do |s|
s.required_ruby_version = "#{RUBY_VERSION}.#{patchlevel}"
end
- install_gemfile <<-G, raise_on_error: false
+ install_gemfile <<-G, :raise_on_error => false
ruby '#{RUBY_VERSION}', :engine_version => '#{RUBY_VERSION}', :engine => 'ruby', :patchlevel => '#{patchlevel}'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
@@ -143,13 +143,13 @@ RSpec.describe "bundle install" do
it "fails and complains about version on version mismatch" do
version = Gem::Requirement.create(RUBY_VERSION).requirements.first.last.bump.version
- build_lib("foo", path: bundled_app) do |s|
+ build_lib("foo", :path => bundled_app) do |s|
s.required_ruby_version = version
end
- install_gemfile <<-G, raise_on_error: false
+ install_gemfile <<-G, :raise_on_error => false
ruby '#{version}', :engine_version => '#{version}', :engine => 'ruby'
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
@@ -157,25 +157,5 @@ RSpec.describe "bundle install" do
expect(err).to include("but your Gemfile specified")
expect(exitstatus).to eq(18)
end
-
- it "validates gemspecs just once when everything installed and lockfile up to date" do
- build_lib "foo"
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gemspec path: "#{lib_path("foo-1.0")}"
-
- module Monkey
- def validate(spec)
- puts "Validate called on \#{spec.full_name}"
- end
- end
- Bundler.rubygems.extend(Monkey)
- G
-
- bundle "install"
-
- expect(out).to include("Validate called on foo-1.0").once
- end
end
end
diff --git a/spec/bundler/install/git_spec.rb b/spec/bundler/install/git_spec.rb
index d1f6b7a7ca..882f2a2d42 100644
--- a/spec/bundler/install/git_spec.rb
+++ b/spec/bundler/install/git_spec.rb
@@ -3,77 +3,64 @@
RSpec.describe "bundle install" do
context "git sources" do
it "displays the revision hash of the gem repository" do
- build_git "foo", "1.0", path: lib_path("foo")
+ build_git "foo", "1.0", :path => lib_path("foo")
- install_gemfile <<-G, verbose: true
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo")}"
+ install_gemfile <<-G, :verbose => true
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo"))}"
G
- expect(out).to include("Using foo 1.0 from #{lib_path("foo")} (at main@#{revision_for(lib_path("foo"))[0..6]})")
- expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}"
+ expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at main@#{revision_for(lib_path("foo"))[0..6]})")
+ expect(the_bundle).to include_gems "foo 1.0", :source => "git@#{lib_path("foo")}"
end
- it "displays the revision hash of the gem repository when passed a relative local path" do
- build_git "foo", "1.0", path: lib_path("foo")
+ it "displays the correct default branch", :git => ">= 2.28.0" do
+ build_git "foo", "1.0", :path => lib_path("foo"), :default_branch => "main"
- relative_path = lib_path("foo").relative_path_from(bundled_app)
- install_gemfile <<-G, verbose: true
- source "https://gem.repo1"
- gem "foo", :git => "#{relative_path}"
+ install_gemfile <<-G, :verbose => true
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo"))}"
G
- expect(out).to include("Using foo 1.0 from #{relative_path} (at main@#{revision_for(lib_path("foo"))[0..6]})")
- expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}"
- end
-
- it "displays the correct default branch", git: ">= 2.28.0" do
- build_git "foo", "1.0", path: lib_path("foo"), default_branch: "main"
-
- install_gemfile <<-G, verbose: true
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo")}"
- G
-
- expect(out).to include("Using foo 1.0 from #{lib_path("foo")} (at main@#{revision_for(lib_path("foo"))[0..6]})")
- expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}"
+ expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at main@#{revision_for(lib_path("foo"))[0..6]})")
+ expect(the_bundle).to include_gems "foo 1.0", :source => "git@#{lib_path("foo")}"
end
it "displays the ref of the gem repository when using branch~num as a ref" do
skip "maybe branch~num notation doesn't work on Windows' git" if Gem.win_platform?
- build_git "foo", "1.0", path: lib_path("foo")
+ build_git "foo", "1.0", :path => lib_path("foo")
rev = revision_for(lib_path("foo"))[0..6]
- update_git "foo", "2.0", path: lib_path("foo"), gemspec: true
+ update_git "foo", "2.0", :path => lib_path("foo"), :gemspec => true
rev2 = revision_for(lib_path("foo"))[0..6]
- update_git "foo", "3.0", path: lib_path("foo"), gemspec: true
+ update_git "foo", "3.0", :path => lib_path("foo"), :gemspec => true
- install_gemfile <<-G, verbose: true
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo")}", :ref => "main~2"
+ install_gemfile <<-G, :verbose => true
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo"))}", :ref => "main~2"
G
- expect(out).to include("Using foo 1.0 from #{lib_path("foo")} (at main~2@#{rev})")
- expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}"
+ expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at main~2@#{rev})")
+ expect(the_bundle).to include_gems "foo 1.0", :source => "git@#{lib_path("foo")}"
- update_git "foo", "4.0", path: lib_path("foo"), gemspec: true
+ update_git "foo", "4.0", :path => lib_path("foo"), :gemspec => true
- bundle :update, all: true, verbose: true
- expect(out).to include("Using foo 2.0 (was 1.0) from #{lib_path("foo")} (at main~2@#{rev2})")
- expect(the_bundle).to include_gems "foo 2.0", source: "git@#{lib_path("foo")}"
+ bundle :update, :all => true, :verbose => true
+ expect(out).to include("Using foo 2.0 (was 1.0) from #{file_uri_for(lib_path("foo"))} (at main~2@#{rev2})")
+ expect(the_bundle).to include_gems "foo 2.0", :source => "git@#{lib_path("foo")}"
end
- it "allows git repos that are missing but not being installed" do
+ it "should allows git repos that are missing but not being installed" do
revision = build_git("foo").ref_for("HEAD")
gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo-1.0")}", :group => :development
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}", :group => :development
G
lockfile <<-L
GIT
- remote: #{lib_path("foo-1.0")}
+ remote: #{file_uri_for(lib_path("foo-1.0"))}
revision: #{revision}
specs:
foo (1.0)
@@ -94,15 +81,15 @@ RSpec.describe "bundle install" do
it "allows multiple gems from the same git source" do
build_repo2 do
- build_lib "foo", "1.0", path: lib_path("gems/foo")
- build_lib "zebra", "2.0", path: lib_path("gems/zebra")
- build_git "gems", path: lib_path("gems"), gemspec: false
+ build_lib "foo", "1.0", :path => lib_path("gems/foo")
+ build_lib "zebra", "2.0", :path => lib_path("gems/zebra")
+ build_git "gems", :path => lib_path("gems"), :gemspec => false
end
install_gemfile <<-G
- source "https://gem.repo2"
- gem "foo", :git => "#{lib_path("gems")}", :glob => "foo/*.gemspec"
- gem "zebra", :git => "#{lib_path("gems")}", :glob => "zebra/*.gemspec"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("gems"))}", :glob => "foo/*.gemspec"
+ gem "zebra", :git => "#{file_uri_for(lib_path("gems"))}", :glob => "zebra/*.gemspec"
G
bundle "info foo"
@@ -119,13 +106,13 @@ RSpec.describe "bundle install" do
# NOTE: both gems MUST have the same path! It has to be two gems in one repo.
- test = build_git "test", "1.0.0", path: lib_path("test-and-other")
- other = build_git "other", "1.0.0", path: lib_path("test-and-other")
+ test = build_git "test", "1.0.0", :path => lib_path("test-and-other")
+ other = build_git "other", "1.0.0", :path => lib_path("test-and-other")
test_ref = test.ref_for("HEAD")
other_ref = other.ref_for("HEAD")
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "test", git: #{test.path.to_s.inspect}
gem "other", ref: #{other_ref.inspect}, git: #{other.path.to_s.inspect}
@@ -146,7 +133,7 @@ RSpec.describe "bundle install" do
other (1.0.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -183,36 +170,5 @@ RSpec.describe "bundle install" do
expect(out).to include("Bundle complete!")
end
-
- it "allows older revisions of git source when clean true" do
- build_git "foo", "1.0", path: lib_path("foo")
- rev = revision_for(lib_path("foo"))
-
- bundle "config set path vendor/bundle"
- bundle "config set clean true"
- install_gemfile <<-G, verbose: true
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo")}"
- G
-
- expect(out).to include("Using foo 1.0 from #{lib_path("foo")} (at main@#{rev[0..6]})")
- expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}"
-
- old_lockfile = lockfile
-
- update_git "foo", "2.0", path: lib_path("foo"), gemspec: true
- rev2 = revision_for(lib_path("foo"))
-
- bundle :update, all: true, verbose: true
- expect(out).to include("Using foo 2.0 (was 1.0) from #{lib_path("foo")} (at main@#{rev2[0..6]})")
- expect(out).to include("Removing foo (#{rev[0..11]})")
- expect(the_bundle).to include_gems "foo 2.0", source: "git@#{lib_path("foo")}"
-
- lockfile(old_lockfile)
-
- bundle :install, verbose: true
- expect(out).to include("Using foo 1.0 from #{lib_path("foo")} (at main@#{rev[0..6]})")
- expect(the_bundle).to include_gems "foo 1.0", source: "git@#{lib_path("foo")}"
- end
end
end
diff --git a/spec/bundler/install/global_cache_spec.rb b/spec/bundler/install/global_cache_spec.rb
index df4559c42e..be34d8b5bc 100644
--- a/spec/bundler/install/global_cache_spec.rb
+++ b/spec/bundler/install/global_cache_spec.rb
@@ -16,165 +16,165 @@ RSpec.describe "global gem caching" do
end
it "caches gems into the global cache on download" do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "#{source}"
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
- expect(source_global_cache("myrack-1.0.0.gem")).to exist
+ expect(the_bundle).to include_gems "rack 1.0.0"
+ expect(source_global_cache("rack-1.0.0.gem")).to exist
end
it "uses globally cached gems if they exist" do
source_global_cache.mkpath
- FileUtils.cp(gem_repo1("gems/myrack-1.0.0.gem"), source_global_cache("myrack-1.0.0.gem"))
+ FileUtils.cp(gem_repo1("gems/rack-1.0.0.gem"), source_global_cache("rack-1.0.0.gem"))
- install_gemfile <<-G, artifice: "compact_index_no_gem"
+ install_gemfile <<-G, :artifice => "compact_index_no_gem"
source "#{source}"
- gem "myrack"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "shows a proper error message if a cached gem is corrupted" do
source_global_cache.mkpath
- FileUtils.touch(source_global_cache("myrack-1.0.0.gem"))
+ FileUtils.touch(source_global_cache("rack-1.0.0.gem"))
- install_gemfile <<-G, artifice: "compact_index_no_gem", raise_on_error: false
+ install_gemfile <<-G, :artifice => "compact_index_no_gem", :raise_on_error => false
source "#{source}"
- gem "myrack"
+ gem "rack"
G
- expect(err).to include("Gem::Package::FormatError: package metadata is missing in #{source_global_cache("myrack-1.0.0.gem")}")
+ expect(err).to include("Gem::Package::FormatError: package metadata is missing in #{source_global_cache("rack-1.0.0.gem")}")
end
describe "when the same gem from different sources is installed" do
it "should use the appropriate one from the global cache" do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "#{source}"
- gem "myrack"
+ gem "rack"
G
simulate_new_machine
- expect(the_bundle).not_to include_gems "myrack 1.0.0"
- expect(source_global_cache("myrack-1.0.0.gem")).to exist
- # myrack 1.0.0 is not installed and it is in the global cache
+ expect(the_bundle).not_to include_gems "rack 1.0.0"
+ expect(source_global_cache("rack-1.0.0.gem")).to exist
+ # rack 1.0.0 is not installed and it is in the global cache
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "#{source2}"
- gem "myrack", "0.9.1"
+ gem "rack", "0.9.1"
G
simulate_new_machine
- expect(the_bundle).not_to include_gems "myrack 0.9.1"
- expect(source2_global_cache("myrack-0.9.1.gem")).to exist
- # myrack 0.9.1 is not installed and it is in the global cache
+ expect(the_bundle).not_to include_gems "rack 0.9.1"
+ expect(source2_global_cache("rack-0.9.1.gem")).to exist
+ # rack 0.9.1 is not installed and it is in the global cache
gemfile <<-G
source "#{source}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
- bundle :install, artifice: "compact_index_no_gem"
- # myrack 1.0.0 is installed and myrack 0.9.1 is not
- expect(the_bundle).to include_gems "myrack 1.0.0"
- expect(the_bundle).not_to include_gems "myrack 0.9.1"
+ bundle :install, :artifice => "compact_index_no_gem"
+ # rack 1.0.0 is installed and rack 0.9.1 is not
+ expect(the_bundle).to include_gems "rack 1.0.0"
+ expect(the_bundle).not_to include_gems "rack 0.9.1"
simulate_new_machine
gemfile <<-G
source "#{source2}"
- gem "myrack", "0.9.1"
+ gem "rack", "0.9.1"
G
- bundle :install, artifice: "compact_index_no_gem"
- # myrack 0.9.1 is installed and myrack 1.0.0 is not
- expect(the_bundle).to include_gems "myrack 0.9.1"
- expect(the_bundle).not_to include_gems "myrack 1.0.0"
+ bundle :install, :artifice => "compact_index_no_gem"
+ # rack 0.9.1 is installed and rack 1.0.0 is not
+ expect(the_bundle).to include_gems "rack 0.9.1"
+ expect(the_bundle).not_to include_gems "rack 1.0.0"
end
it "should not install if the wrong source is provided" do
gemfile <<-G
source "#{source}"
- gem "myrack"
+ gem "rack"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
simulate_new_machine
- expect(the_bundle).not_to include_gems "myrack 1.0.0"
- expect(source_global_cache("myrack-1.0.0.gem")).to exist
- # myrack 1.0.0 is not installed and it is in the global cache
+ expect(the_bundle).not_to include_gems "rack 1.0.0"
+ expect(source_global_cache("rack-1.0.0.gem")).to exist
+ # rack 1.0.0 is not installed and it is in the global cache
gemfile <<-G
source "#{source2}"
- gem "myrack", "0.9.1"
+ gem "rack", "0.9.1"
G
- bundle :install, artifice: "compact_index"
+ bundle :install, :artifice => "compact_index"
simulate_new_machine
- expect(the_bundle).not_to include_gems "myrack 0.9.1"
- expect(source2_global_cache("myrack-0.9.1.gem")).to exist
- # myrack 0.9.1 is not installed and it is in the global cache
+ expect(the_bundle).not_to include_gems "rack 0.9.1"
+ expect(source2_global_cache("rack-0.9.1.gem")).to exist
+ # rack 0.9.1 is not installed and it is in the global cache
gemfile <<-G
source "#{source2}"
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
- expect(source_global_cache("myrack-1.0.0.gem")).to exist
- expect(source2_global_cache("myrack-0.9.1.gem")).to exist
- bundle :install, artifice: "compact_index_no_gem", raise_on_error: false
+ expect(source_global_cache("rack-1.0.0.gem")).to exist
+ expect(source2_global_cache("rack-0.9.1.gem")).to exist
+ bundle :install, :artifice => "compact_index_no_gem", :raise_on_error => false
expect(err).to include("Internal Server Error 500")
expect(err).not_to include("ERROR REPORT TEMPLATE")
- # myrack 1.0.0 is not installed and myrack 0.9.1 is not
- expect(the_bundle).not_to include_gems "myrack 1.0.0"
- expect(the_bundle).not_to include_gems "myrack 0.9.1"
+ # rack 1.0.0 is not installed and rack 0.9.1 is not
+ expect(the_bundle).not_to include_gems "rack 1.0.0"
+ expect(the_bundle).not_to include_gems "rack 0.9.1"
gemfile <<-G
source "#{source}"
- gem "myrack", "0.9.1"
+ gem "rack", "0.9.1"
G
- expect(source_global_cache("myrack-1.0.0.gem")).to exist
- expect(source2_global_cache("myrack-0.9.1.gem")).to exist
- bundle :install, artifice: "compact_index_no_gem", raise_on_error: false
+ expect(source_global_cache("rack-1.0.0.gem")).to exist
+ expect(source2_global_cache("rack-0.9.1.gem")).to exist
+ bundle :install, :artifice => "compact_index_no_gem", :raise_on_error => false
expect(err).to include("Internal Server Error 500")
expect(err).not_to include("ERROR REPORT TEMPLATE")
- # myrack 0.9.1 is not installed and myrack 1.0.0 is not
- expect(the_bundle).not_to include_gems "myrack 0.9.1"
- expect(the_bundle).not_to include_gems "myrack 1.0.0"
+ # rack 0.9.1 is not installed and rack 1.0.0 is not
+ expect(the_bundle).not_to include_gems "rack 0.9.1"
+ expect(the_bundle).not_to include_gems "rack 1.0.0"
end
end
describe "when installing gems from a different directory" do
it "uses the global cache as a source" do
- install_gemfile <<-G, artifice: "compact_index"
+ install_gemfile <<-G, :artifice => "compact_index"
source "#{source}"
- gem "myrack"
+ gem "rack"
gem "activesupport"
G
# Both gems are installed and in the global cache
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(the_bundle).to include_gems "activesupport 2.3.5"
- expect(source_global_cache("myrack-1.0.0.gem")).to exist
+ expect(source_global_cache("rack-1.0.0.gem")).to exist
expect(source_global_cache("activesupport-2.3.5.gem")).to exist
simulate_new_machine
# Both gems are now only in the global cache
- expect(the_bundle).not_to include_gems "myrack 1.0.0"
+ expect(the_bundle).not_to include_gems "rack 1.0.0"
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
- install_gemfile <<-G, artifice: "compact_index_no_gem"
+ install_gemfile <<-G, :artifice => "compact_index_no_gem"
source "#{source}"
- gem "myrack"
+ gem "rack"
G
- # myrack is installed and both are in the global cache
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ # rack is installed and both are in the global cache
+ expect(the_bundle).to include_gems "rack 1.0.0"
expect(the_bundle).not_to include_gems "activesupport 2.3.5"
- expect(source_global_cache("myrack-1.0.0.gem")).to exist
+ expect(source_global_cache("rack-1.0.0.gem")).to exist
expect(source_global_cache("activesupport-2.3.5.gem")).to exist
create_file bundled_app2("gems.rb"), <<-G
@@ -183,20 +183,22 @@ RSpec.describe "global gem caching" do
G
# Neither gem is installed and both are in the global cache
- expect(the_bundle).not_to include_gems "myrack 1.0.0", dir: bundled_app2
- expect(the_bundle).not_to include_gems "activesupport 2.3.5", dir: bundled_app2
- expect(source_global_cache("myrack-1.0.0.gem")).to exist
+ expect(the_bundle).not_to include_gems "rack 1.0.0", :dir => bundled_app2
+ expect(the_bundle).not_to include_gems "activesupport 2.3.5", :dir => bundled_app2
+ expect(source_global_cache("rack-1.0.0.gem")).to exist
expect(source_global_cache("activesupport-2.3.5.gem")).to exist
# Install using the global cache instead of by downloading the .gem
# from the server
- bundle :install, artifice: "compact_index_no_gem", dir: bundled_app2
+ bundle :install, :artifice => "compact_index_no_gem", :dir => bundled_app2
# activesupport is installed and both are in the global cache
- expect(the_bundle).not_to include_gems "myrack 1.0.0", dir: bundled_app2
- expect(the_bundle).to include_gems "activesupport 2.3.5", dir: bundled_app2
+ simulate_bundler_version_when_missing_prerelease_default_gem_activation do
+ expect(the_bundle).not_to include_gems "rack 1.0.0", :dir => bundled_app2
+ expect(the_bundle).to include_gems "activesupport 2.3.5", :dir => bundled_app2
+ end
- expect(source_global_cache("myrack-1.0.0.gem")).to exist
+ expect(source_global_cache("rack-1.0.0.gem")).to exist
expect(source_global_cache("activesupport-2.3.5.gem")).to exist
end
end
@@ -211,7 +213,7 @@ RSpec.describe "global gem caching" do
revision = revision_for(lib_path("very_simple_git_binary-1.0"))[0, 12]
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "very_simple_binary"
gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}"
@@ -219,7 +221,7 @@ RSpec.describe "global gem caching" do
G
gem_binary_cache = home(".bundle", "cache", "extensions", local_platform.to_s, Bundler.ruby_scope,
- "gem.repo1.443.#{Digest(:MD5).hexdigest("gem.repo1.443./")}", "very_simple_binary-1.0")
+ Digest(:MD5).hexdigest("#{gem_repo1}/"), "very_simple_binary-1.0")
git_binary_cache = home(".bundle", "cache", "extensions", local_platform.to_s, Bundler.ruby_scope,
"very_simple_git_binary-1.0-#{revision}", "very_simple_git_binary-1.0")
@@ -232,7 +234,7 @@ RSpec.describe "global gem caching" do
R
expect(out).to eq "VERY_SIMPLE_BINARY_IN_C\nVERY_SIMPLE_GIT_BINARY_IN_C"
- FileUtils.rm_rf Dir[home(".bundle", "cache", "extensions", "**", "*binary_c*")]
+ FileUtils.rm Dir[home(".bundle", "cache", "extensions", "**", "*binary_c*")]
gem_binary_cache.join("very_simple_binary_c.rb").open("w") {|f| f << "puts File.basename(__FILE__)" }
git_binary_cache.join("very_simple_git_binary_c.rb").open("w") {|f| f << "puts File.basename(__FILE__)" }
diff --git a/spec/bundler/install/path_spec.rb b/spec/bundler/install/path_spec.rb
index 8d32e033d6..bd5385b265 100644
--- a/spec/bundler/install/path_spec.rb
+++ b/spec/bundler/install/path_spec.rb
@@ -3,27 +3,27 @@
RSpec.describe "bundle install" do
describe "with path configured" do
before :each do
- build_gem "myrack", "1.0.0", to_system: true do |s|
- s.write "lib/myrack.rb", "puts 'FAIL'"
+ build_gem "rack", "1.0.0", :to_system => true do |s|
+ s.write "lib/rack.rb", "puts 'FAIL'"
end
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
it "does not use available system gems with `vendor/bundle" do
bundle "config set --local path vendor/bundle"
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "uses system gems with `path.system` configured with more priority than `path`" do
bundle "config set --local path.system true"
bundle "config set --global path vendor/bundle"
bundle :install
- run "require 'myrack'", raise_on_error: false
+ run "require 'rack'", :raise_on_error => false
expect(out).to include("FAIL")
end
@@ -32,7 +32,7 @@ RSpec.describe "bundle install" do
dir.mkpath
bundle "config set --local path #{dir.join("vendor/bundle")}"
- bundle :install, dir: dir
+ bundle :install, :dir => dir
expect(out).to include("installed into `./vendor/bundle`")
dir.rmtree
@@ -44,40 +44,40 @@ RSpec.describe "bundle install" do
expect(out).to include("gems are installed into `./vendor/bundle`")
end
- it "disallows --path vendor/bundle --system", bundler: "< 3" do
- bundle "install --path vendor/bundle --system", raise_on_error: false
+ it "disallows --path vendor/bundle --system", :bundler => "< 3" do
+ bundle "install --path vendor/bundle --system", :raise_on_error => false
expect(err).to include("Please choose only one option.")
expect(exitstatus).to eq(15)
end
- it "remembers to disable system gems after the first time with bundle --path vendor/bundle", bundler: "< 3" do
+ it "remembers to disable system gems after the first time with bundle --path vendor/bundle", :bundler => "< 3" do
bundle "install --path vendor/bundle"
FileUtils.rm_rf bundled_app("vendor")
bundle "install"
- expect(vendored_gems("gems/myrack-1.0.0")).to be_directory
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(vendored_gems("gems/rack-1.0.0")).to be_directory
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
context "with path_relative_to_cwd set to true" do
before { bundle "config set path_relative_to_cwd true" }
- it "installs the bundle relatively to current working directory", bundler: "< 3" do
- bundle "install --gemfile='#{bundled_app}/Gemfile' --path vendor/bundle", dir: bundled_app.parent
+ it "installs the bundle relatively to current working directory", :bundler => "< 3" do
+ bundle "install --gemfile='#{bundled_app}/Gemfile' --path vendor/bundle", :dir => bundled_app.parent
expect(out).to include("installed into `./vendor/bundle`")
expect(bundled_app("../vendor/bundle")).to be_directory
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "installs the standalone bundle relative to the cwd" do
- bundle :install, gemfile: bundled_app_gemfile, standalone: true, dir: bundled_app.parent
+ bundle :install, :gemfile => bundled_app_gemfile, :standalone => true, :dir => bundled_app.parent
expect(out).to include("installed into `./bundled_app/bundle`")
expect(bundled_app("bundle")).to be_directory
expect(bundled_app("bundle/ruby")).to be_directory
bundle "config unset path"
- bundle :install, gemfile: bundled_app_gemfile, standalone: true, dir: bundled_app("subdir").tap(&:mkpath)
+ bundle :install, :gemfile => bundled_app_gemfile, :standalone => true, :dir => bundled_app("subdir").tap(&:mkpath)
expect(out).to include("installed into `../bundle`")
expect(bundled_app("bundle")).to be_directory
expect(bundled_app("bundle/ruby")).to be_directory
@@ -87,13 +87,13 @@ RSpec.describe "bundle install" do
describe "when BUNDLE_PATH or the global path config is set" do
before :each do
- build_lib "myrack", "1.0.0", to_system: true do |s|
- s.write "lib/myrack.rb", "raise 'FAIL'"
+ build_lib "rack", "1.0.0", :to_system => true do |s|
+ s.write "lib/rack.rb", "raise 'FAIL'"
end
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
@@ -112,9 +112,9 @@ RSpec.describe "bundle install" do
bundle "config set --local path vendor/bundle"
bundle :install
- expect(vendored_gems("gems/myrack-1.0.0")).to be_directory
+ expect(vendored_gems("gems/rack-1.0.0")).to be_directory
expect(bundled_app("vendor2")).not_to be_directory
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "installs gems to ." do
@@ -123,9 +123,9 @@ RSpec.describe "bundle install" do
bundle :install
- paths_to_exist = %w[cache/myrack-1.0.0.gem gems/myrack-1.0.0 specifications/myrack-1.0.0.gemspec].map {|path| bundled_app(Bundler.ruby_scope, path) }
+ paths_to_exist = %w[cache/rack-1.0.0.gem gems/rack-1.0.0 specifications/rack-1.0.0.gemspec].map {|path| bundled_app(Bundler.ruby_scope, path) }
expect(paths_to_exist).to all exist
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "installs gems to the path" do
@@ -133,18 +133,18 @@ RSpec.describe "bundle install" do
bundle :install
- expect(bundled_app("vendor", Bundler.ruby_scope, "gems/myrack-1.0.0")).to be_directory
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(bundled_app("vendor", Bundler.ruby_scope, "gems/rack-1.0.0")).to be_directory
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "installs gems to the path relative to root when relative" do
set_bundle_path(type, "vendor")
FileUtils.mkdir_p bundled_app("lol")
- bundle :install, dir: bundled_app("lol")
+ bundle :install, :dir => bundled_app("lol")
- expect(bundled_app("vendor", Bundler.ruby_scope, "gems/myrack-1.0.0")).to be_directory
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(bundled_app("vendor", Bundler.ruby_scope, "gems/rack-1.0.0")).to be_directory
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
end
@@ -154,35 +154,35 @@ RSpec.describe "bundle install" do
bundle :install
- expect(vendored_gems("gems/myrack-1.0.0")).to be_directory
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(vendored_gems("gems/rack-1.0.0")).to be_directory
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "sets BUNDLE_PATH as the first argument to bundle install" do
bundle "config set --local path ./vendor/bundle"
bundle :install
- expect(vendored_gems("gems/myrack-1.0.0")).to be_directory
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(vendored_gems("gems/rack-1.0.0")).to be_directory
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "disables system gems when passing a path to install" do
# This is so that vendored gems can be distributed to others
- build_gem "myrack", "1.1.0", to_system: true
+ build_gem "rack", "1.1.0", :to_system => true
bundle "config set --local path ./vendor/bundle"
bundle :install
- expect(vendored_gems("gems/myrack-1.0.0")).to be_directory
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(vendored_gems("gems/rack-1.0.0")).to be_directory
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "re-installs gems whose extensions have been deleted" do
- build_lib "very_simple_binary", "1.0.0", to_system: true do |s|
+ build_lib "very_simple_binary", "1.0.0", :to_system => true do |s|
s.write "lib/very_simple_binary.rb", "raise 'FAIL'"
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "very_simple_binary"
G
@@ -191,11 +191,11 @@ RSpec.describe "bundle install" do
expect(vendored_gems("gems/very_simple_binary-1.0")).to be_directory
expect(vendored_gems("extensions")).to be_directory
- expect(the_bundle).to include_gems "very_simple_binary 1.0", source: "remote1"
+ expect(the_bundle).to include_gems "very_simple_binary 1.0", :source => "remote1"
vendored_gems("extensions").rmtree
- run "require 'very_simple_binary_c'", raise_on_error: false
+ run "require 'very_simple_binary_c'", :raise_on_error => false
expect(err).to include("Bundler::GemNotFound")
bundle "config set --local path ./vendor/bundle"
@@ -203,7 +203,7 @@ RSpec.describe "bundle install" do
expect(vendored_gems("gems/very_simple_binary-1.0")).to be_directory
expect(vendored_gems("extensions")).to be_directory
- expect(the_bundle).to include_gems "very_simple_binary 1.0", source: "remote1"
+ expect(the_bundle).to include_gems "very_simple_binary 1.0", :source => "remote1"
end
end
@@ -214,12 +214,12 @@ RSpec.describe "bundle install" do
it "reports the file exists" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle "config set --local path bundle"
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err).to include("file already exists")
end
end
diff --git a/spec/bundler/install/prereleases_spec.rb b/spec/bundler/install/prereleases_spec.rb
index 57764ce722..629eb89dac 100644
--- a/spec/bundler/install/prereleases_spec.rb
+++ b/spec/bundler/install/prereleases_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe "bundle install" do
describe "when prerelease gems are available" do
it "finds prereleases" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "not_released"
G
expect(the_bundle).to include_gems "not_released 1.0.pre"
@@ -21,7 +21,7 @@ RSpec.describe "bundle install" do
it "uses regular releases if available" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "has_prerelease"
G
expect(the_bundle).to include_gems "has_prerelease 1.0"
@@ -29,7 +29,7 @@ RSpec.describe "bundle install" do
it "uses prereleases if requested" do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "has_prerelease", "1.1.pre"
G
expect(the_bundle).to include_gems "has_prerelease 1.1.pre"
@@ -38,17 +38,17 @@ RSpec.describe "bundle install" do
describe "when prerelease gems are not available" do
it "still works" do
- build_repo3 do
- build_gem "myrack"
+ build_repo gem_repo3 do
+ build_gem "rack"
end
FileUtils.rm_rf Dir[gem_repo3("prerelease*")]
install_gemfile <<-G
- source "https://gem.repo3"
- gem "myrack"
+ source "#{file_uri_for(gem_repo3)}"
+ gem "rack"
G
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
end
diff --git a/spec/bundler/install/process_lock_spec.rb b/spec/bundler/install/process_lock_spec.rb
index 8082ec40fa..1f8c62f26e 100644
--- a/spec/bundler/install/process_lock_spec.rb
+++ b/spec/bundler/install/process_lock_spec.rb
@@ -8,17 +8,17 @@ RSpec.describe "process lock spec" do
thread = Thread.new do
Bundler::ProcessLock.lock(default_bundle_path) do
sleep 1 # ignore quality_spec
- expect(the_bundle).not_to include_gems "myrack 1.0"
+ expect(the_bundle).not_to include_gems "rack 1.0"
end
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
thread.join
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
context "when creating a lock raises Errno::ENOTSUP" do
diff --git a/spec/bundler/install/redownload_spec.rb b/spec/bundler/install/redownload_spec.rb
index b522e22bd5..a936b2b536 100644
--- a/spec/bundler/install/redownload_spec.rb
+++ b/spec/bundler/install/redownload_spec.rb
@@ -3,29 +3,29 @@
RSpec.describe "bundle install" do
before :each do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
shared_examples_for "an option to force redownloading gems" do
it "re-installs installed gems" do
- myrack_lib = default_bundle_path("gems/myrack-1.0.0/lib/myrack.rb")
+ rack_lib = default_bundle_path("gems/rack-1.0.0/lib/rack.rb")
bundle :install
- myrack_lib.open("w") {|f| f.write("blah blah blah") }
+ rack_lib.open("w") {|f| f.write("blah blah blah") }
bundle :install, flag => true
- expect(out).to include "Installing myrack 1.0.0"
- expect(myrack_lib.open(&:read)).to eq("MYRACK = '1.0.0'\n")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(out).to include "Installing rack 1.0.0"
+ expect(rack_lib.open(&:read)).to eq("RACK = '1.0.0'\n")
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "works on first bundle install" do
bundle :install, flag => true
- expect(out).to include "Installing myrack 1.0.0"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(out).to include "Installing rack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
context "with a git gem" do
@@ -33,7 +33,7 @@ RSpec.describe "bundle install" do
before do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
end
@@ -57,7 +57,7 @@ RSpec.describe "bundle install" do
end
end
- describe "with --force", bundler: 2 do
+ describe "with --force", :bundler => 2 do
it_behaves_like "an option to force redownloading gems" do
let(:flag) { "force" }
end
diff --git a/spec/bundler/install/security_policy_spec.rb b/spec/bundler/install/security_policy_spec.rb
index e7f64dc227..43c3069c4e 100644
--- a/spec/bundler/install/security_policy_spec.rb
+++ b/spec/bundler/install/security_policy_spec.rb
@@ -9,30 +9,30 @@ RSpec.describe "policies with unsigned gems" do
before do
build_security_repo
gemfile <<-G
- source "https://gems.security"
- gem "myrack"
+ source "#{file_uri_for(security_repo)}"
+ gem "rack"
gem "signed_gem"
G
end
it "will work after you try to deploy without a lock" do
- bundle "install --deployment", raise_on_error: false
+ bundle "install --deployment", :raise_on_error => false
bundle :install
- expect(the_bundle).to include_gems "myrack 1.0", "signed_gem 1.0"
+ expect(the_bundle).to include_gems "rack 1.0", "signed_gem 1.0"
end
it "will fail when given invalid security policy" do
- bundle "install --trust-policy=InvalidPolicyName", raise_on_error: false
+ bundle "install --trust-policy=InvalidPolicyName", :raise_on_error => false
expect(err).to include("RubyGems doesn't know about trust policy")
end
it "will fail with High Security setting due to presence of unsigned gem" do
- bundle "install --trust-policy=HighSecurity", raise_on_error: false
+ bundle "install --trust-policy=HighSecurity", :raise_on_error => false
expect(err).to include("security policy didn't allow")
end
it "will fail with Medium Security setting due to presence of unsigned gem" do
- bundle "install --trust-policy=MediumSecurity", raise_on_error: false
+ bundle "install --trust-policy=MediumSecurity", :raise_on_error => false
expect(err).to include("security policy didn't allow")
end
@@ -45,18 +45,18 @@ RSpec.describe "policies with signed gems and no CA" do
before do
build_security_repo
gemfile <<-G
- source "https://gems.security"
+ source "#{file_uri_for(security_repo)}"
gem "signed_gem"
G
end
it "will fail with High Security setting, gem is self-signed" do
- bundle "install --trust-policy=HighSecurity", raise_on_error: false
+ bundle "install --trust-policy=HighSecurity", :raise_on_error => false
expect(err).to include("security policy didn't allow")
end
it "will fail with Medium Security setting, gem is self-signed" do
- bundle "install --trust-policy=MediumSecurity", raise_on_error: false
+ bundle "install --trust-policy=MediumSecurity", :raise_on_error => false
expect(err).to include("security policy didn't allow")
end
diff --git a/spec/bundler/install/yanked_spec.rb b/spec/bundler/install/yanked_spec.rb
index b2edd11acd..dc054b50bb 100644
--- a/spec/bundler/install/yanked_spec.rb
+++ b/spec/bundler/install/yanked_spec.rb
@@ -10,7 +10,7 @@ RSpec.context "when installing a bundle that includes yanked gems" do
it "throws an error when the original gem version is yanked" do
lockfile <<-L
GEM
- remote: https://gem.repo4
+ remote: #{file_uri_for(gem_repo4)}
specs:
foo (10.0.0)
@@ -22,8 +22,8 @@ RSpec.context "when installing a bundle that includes yanked gems" do
L
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo4"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo4)}"
gem "foo", "10.0.0"
G
@@ -35,8 +35,7 @@ RSpec.context "when installing a bundle that includes yanked gems" do
skip "Materialization on Windows is not yet strict, so the example does not detect the gem has been yanked" if Gem.win_platform?
build_repo4 do
- build_gem "foo", "1.0.0"
- build_gem "foo", "1.0.1"
+ build_gem "foo", "1.0.0", "1.0.1"
build_gem "actiontext", "6.1.7" do |s|
s.add_dependency "nokogiri", ">= 1.8"
end
@@ -77,10 +76,10 @@ RSpec.context "when installing a bundle that includes yanked gems" do
end
context "and the old index is used" do
- let(:source_uri) { "https://gem.repo4" }
+ let(:source_uri) { file_uri_for(gem_repo4) }
it "reports the yanked gem properly" do
- bundle "install", artifice: "endpoint", raise_on_error: false, verbose: true
+ bundle "install", :raise_on_error => false
expect(err).to include("Your bundle is locked to nokogiri (1.13.8-#{Bundler.local_platform})")
end
@@ -90,7 +89,7 @@ RSpec.context "when installing a bundle that includes yanked gems" do
let(:source_uri) { "https://gem.repo4" }
it "reports the yanked gem properly" do
- bundle "install", artifice: "compact_index", raise_on_error: false
+ bundle "install", :artifice => "compact_index", :raise_on_error => false
expect(err).to include("Your bundle is locked to nokogiri (1.13.8-#{Bundler.local_platform})")
end
@@ -100,8 +99,8 @@ RSpec.context "when installing a bundle that includes yanked gems" do
it "throws the original error when only the Gemfile specifies a gem version that doesn't exist" do
bundle "config set force_ruby_platform true"
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo4"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo4)}"
gem "foo", "10.0.0"
G
@@ -121,7 +120,7 @@ RSpec.context "when resolving a bundle that includes yanked gems, but unlocking
lockfile <<-L
GEM
- remote: https://gem.repo4
+ remote: #{file_uri_for(gem_repo4)}
specs:
foo (9.0.0)
bar (1.0.0)
@@ -138,7 +137,7 @@ RSpec.context "when resolving a bundle that includes yanked gems, but unlocking
L
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "foo"
gem "bar"
G
@@ -149,7 +148,7 @@ RSpec.context "when resolving a bundle that includes yanked gems, but unlocking
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
bar (2.0.0)
foo (9.0.0)
@@ -170,65 +169,65 @@ end
RSpec.context "when using gem before installing" do
it "does not suggest the author has yanked the gem" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
lockfile <<-L
GEM
- remote: https://gem.repo1
+ remote: #{file_uri_for(gem_repo1)}
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack (= 0.9.1)
+ rack (= 0.9.1)
L
- bundle :list, raise_on_error: false
+ bundle :list, :raise_on_error => false
- expect(err).to include("Could not find myrack-0.9.1 in locally installed gems")
- expect(err).to_not include("Your bundle is locked to myrack (0.9.1) from")
- expect(err).to_not include("If you haven't changed sources, that means the author of myrack (0.9.1) has removed it.")
- expect(err).to_not include("You'll need to update your bundle to a different version of myrack (0.9.1) that hasn't been removed in order to install.")
+ expect(err).to include("Could not find rack-0.9.1 in locally installed gems")
+ expect(err).to_not include("Your bundle is locked to rack (0.9.1) from")
+ expect(err).to_not include("If you haven't changed sources, that means the author of rack (0.9.1) has removed it.")
+ expect(err).to_not include("You'll need to update your bundle to a different version of rack (0.9.1) that hasn't been removed in order to install.")
# Check error message is still correct when multiple platforms are locked
lockfile lockfile.gsub(/PLATFORMS\n #{lockfile_platforms}/m, "PLATFORMS\n #{lockfile_platforms("ruby")}")
- bundle :list, raise_on_error: false
- expect(err).to include("Could not find myrack-0.9.1 in locally installed gems")
+ bundle :list, :raise_on_error => false
+ expect(err).to include("Could not find rack-0.9.1 in locally installed gems")
end
it "does not suggest the author has yanked the gem when using more than one gem, but shows all gems that couldn't be found in the source" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
- gem "myrack_middleware", "1.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
+ gem "rack_middleware", "1.0"
G
lockfile <<-L
GEM
- remote: https://gem.repo1
+ remote: #{file_uri_for(gem_repo1)}
specs:
- myrack (0.9.1)
- myrack_middleware (1.0)
+ rack (0.9.1)
+ rack_middleware (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack (= 0.9.1)
- myrack_middleware (1.0)
+ rack (= 0.9.1)
+ rack_middleware (1.0)
L
- bundle :list, raise_on_error: false
+ bundle :list, :raise_on_error => false
- expect(err).to include("Could not find myrack-0.9.1, myrack_middleware-1.0 in locally installed gems")
+ expect(err).to include("Could not find rack-0.9.1, rack_middleware-1.0 in locally installed gems")
expect(err).to include("Install missing gems with `bundle install`.")
- expect(err).to_not include("Your bundle is locked to myrack (0.9.1) from")
- expect(err).to_not include("If you haven't changed sources, that means the author of myrack (0.9.1) has removed it.")
- expect(err).to_not include("You'll need to update your bundle to a different version of myrack (0.9.1) that hasn't been removed in order to install.")
+ expect(err).to_not include("Your bundle is locked to rack (0.9.1) from")
+ expect(err).to_not include("If you haven't changed sources, that means the author of rack (0.9.1) has removed it.")
+ expect(err).to_not include("You'll need to update your bundle to a different version of rack (0.9.1) that hasn't been removed in order to install.")
end
end
diff --git a/spec/bundler/lock/git_spec.rb b/spec/bundler/lock/git_spec.rb
index 13c661ae14..ac3d10223c 100644
--- a/spec/bundler/lock/git_spec.rb
+++ b/spec/bundler/lock/git_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe "bundle lock with git gems" do
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{lib_path("foo-1.0")}"
G
end
@@ -24,11 +24,11 @@ RSpec.describe "bundle lock with git gems" do
it "prints a proper error when changing a locked Gemfile to point to a bad branch" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{lib_path("foo-1.0")}", :branch => "bad"
G
- bundle "lock --update foo", env: { "LANG" => "en" }, raise_on_error: false
+ bundle "lock --update foo", :env => { "LANG" => "en" }, :raise_on_error => false
expect(err).to include("Revision bad does not exist in the repository")
end
@@ -42,7 +42,7 @@ RSpec.describe "bundle lock with git gems" do
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -55,7 +55,7 @@ RSpec.describe "bundle lock with git gems" do
#{Bundler::VERSION}
L
- bundle "install", raise_on_error: false
+ bundle "install", :raise_on_error => false
expect(err).to include("Revision #{"a" * 40} does not exist in the repository")
end
@@ -75,7 +75,7 @@ RSpec.describe "bundle lock with git gems" do
it "properly clones a git source locked to an out of date ref" do
update_git "foo"
- bundle :install, env: { "BUNDLE_PATH" => "foo" }
+ bundle :install, :env => { "BUNDLE_PATH" => "foo" }
expect(err).to be_empty
end
@@ -87,7 +87,7 @@ RSpec.describe "bundle lock with git gems" do
git "branch -D foo ", lib_path("foo-1.0")
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{lib_path("foo-1.0")}"
G
@@ -99,7 +99,7 @@ RSpec.describe "bundle lock with git gems" do
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -123,7 +123,7 @@ RSpec.describe "bundle lock with git gems" do
annotated_tag = git("rev-parse v1.0", lib_path("foo-1.0"))
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{lib_path("foo-1.0")}"
G
@@ -135,7 +135,7 @@ RSpec.describe "bundle lock with git gems" do
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb
index 95022e291b..ccf23a9e3c 100644
--- a/spec/bundler/lock/lockfile_spec.rb
+++ b/spec/bundler/lock/lockfile_spec.rb
@@ -6,28 +6,24 @@ RSpec.describe "the lockfile format" do
end
it "generates a simple lockfile for a single source, gem" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo2, "myrack", "1.0.0")
- end
-
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack"
+ gem "rack"
G
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -43,25 +39,25 @@ RSpec.describe "the lockfile format" do
specs:
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
omg!
- myrack
+ rack
BUNDLED WITH
1.8.2
L
- install_gemfile <<-G, verbose: true, env: { "BUNDLER_VERSION" => Bundler::VERSION }
- source "https://gem.repo2"
+ install_gemfile <<-G, :verbose => true, :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack"
+ gem "rack"
G
expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with 1.8.2.")
@@ -69,50 +65,44 @@ RSpec.describe "the lockfile format" do
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
BUNDLED WITH
#{Bundler::VERSION}
G
end
- it "does not update the lockfile's bundler version if nothing changed during bundle install, but uses the locked version", rubygems: ">= 3.3.0.a" do
+ it "does not update the lockfile's bundler version if nothing changed during bundle install, but uses the locked version", :rubygems => ">= 3.3.0.a", :realworld => true do
version = "2.3.0"
- build_repo4 do
- build_gem "myrack", "1.0.0"
-
- build_bundler version
- end
-
lockfile <<-L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
BUNDLED WITH
#{version}
L
- install_gemfile <<-G, verbose: true, preserve_ruby_flags: true
- source "https://gem.repo4"
+ install_gemfile <<-G, :verbose => true, :artifice => "vcr"
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack"
+ gem "rack"
G
expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{version}.")
@@ -120,54 +110,44 @@ RSpec.describe "the lockfile format" do
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
BUNDLED WITH
#{version}
G
end
- it "does not update the lockfile's bundler version if nothing changed during bundle install, and uses the latest version", rubygems: "< 3.3.0.a" do
+ it "does not update the lockfile's bundler version if nothing changed during bundle install, and uses the latest version", :rubygems => "< 3.3.0.a" do
version = "#{Bundler::VERSION.split(".").first}.0.0.a"
- build_repo4 do
- build_gem "myrack", "1.0.0"
-
- build_bundler version
- end
-
- checksums = checksums_section do |c|
- c.checksum(gem_repo4, "myrack", "1.0.0")
- end
-
lockfile <<-L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{version}
L
- install_gemfile <<-G, verbose: true
- source "https://gem.repo4"
+ install_gemfile <<-G, :verbose => true
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack"
+ gem "rack"
G
expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{version}.")
@@ -175,16 +155,16 @@ RSpec.describe "the lockfile format" do
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{version}
G
@@ -193,34 +173,34 @@ RSpec.describe "the lockfile format" do
it "adds the BUNDLED WITH section if not present" do
lockfile <<-L
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
L
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack", "> 0"
+ gem "rack", "> 0"
G
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack (> 0)
+ rack (> 0)
BUNDLED WITH
#{Bundler::VERSION}
@@ -235,39 +215,39 @@ RSpec.describe "the lockfile format" do
lockfile <<-L
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
BUNDLED WITH
#{older_major}
L
- install_gemfile <<-G, env: { "BUNDLER_VERSION" => Bundler::VERSION }
- source "https://gem.repo2/"
+ install_gemfile <<-G, :env => { "BUNDLER_VERSION" => Bundler::VERSION }
+ source "#{file_uri_for(gem_repo2)}/"
- gem "myrack"
+ gem "rack"
G
expect(err).to be_empty
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
BUNDLED WITH
#{current_version}
@@ -276,30 +256,25 @@ RSpec.describe "the lockfile format" do
it "generates a simple lockfile for a single source, gem with dependencies" do
install_gemfile <<-G
- source "https://gem.repo2/"
+ source "#{file_uri_for(gem_repo2)}/"
- gem "myrack-obama"
+ gem "rack-obama"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "myrack", "1.0.0"
- c.checksum gem_repo2, "myrack-obama", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
- myrack-obama (1.0)
- myrack
+ rack (1.0.0)
+ rack-obama (1.0)
+ rack
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack-obama
- #{checksums}
+ rack-obama
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -307,164 +282,50 @@ RSpec.describe "the lockfile format" do
it "generates a simple lockfile for a single source, gem with a version requirement" do
install_gemfile <<-G
- source "https://gem.repo2/"
+ source "#{file_uri_for(gem_repo2)}/"
- gem "myrack-obama", ">= 1.0"
+ gem "rack-obama", ">= 1.0"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "myrack", "1.0.0"
- c.checksum gem_repo2, "myrack-obama", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
- myrack-obama (1.0)
- myrack
+ rack (1.0.0)
+ rack-obama (1.0)
+ rack
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack-obama (>= 1.0)
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- G
- end
-
- it "generates a lockfile without credentials" do
- bundle "config set https://localgemserver.test/ user:pass"
+ rack-obama (>= 1.0)
- install_gemfile(<<-G, artifice: "endpoint_strict_basic_authentication", quiet: true)
- source "https://gem.repo1"
-
- source "https://localgemserver.test/" do
-
- end
-
- source "https://user:pass@othergemserver.test/" do
- gem "myrack-obama", ">= 1.0"
- end
- G
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "myrack", "1.0.0"
- c.checksum gem_repo2, "myrack-obama", "1.0"
- end
-
- expect(lockfile).to eq <<~G
- GEM
- remote: https://gem.repo1/
- specs:
-
- GEM
- remote: https://localgemserver.test/
- specs:
-
- GEM
- remote: https://othergemserver.test/
- specs:
- myrack (1.0.0)
- myrack-obama (1.0)
- myrack
-
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- myrack-obama (>= 1.0)!
- #{checksums}
BUNDLED WITH
#{Bundler::VERSION}
G
end
- it "does not add credentials to lockfile when it does not have them already" do
+ it "generates a lockfile without credentials for a configured source" do
bundle "config set http://localgemserver.test/ user:pass"
- gemfile <<~G
- source "https://gem.repo1"
+ install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true)
+ source "#{file_uri_for(gem_repo1)}"
source "http://localgemserver.test/" do
end
source "http://user:pass@othergemserver.test/" do
- gem "myrack-obama", ">= 1.0"
+ gem "rack-obama", ">= 1.0"
end
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "myrack", "1.0.0"
- c.checksum gem_repo2, "myrack-obama", "1.0"
- end
-
- lockfile_without_credentials = <<~L
- GEM
- remote: http://localgemserver.test/
- specs:
-
- GEM
- remote: http://othergemserver.test/
- specs:
- myrack (1.0.0)
- myrack-obama (1.0)
- myrack
-
+ expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- PLATFORMS
- #{lockfile_platforms}
-
- DEPENDENCIES
- myrack-obama (>= 1.0)!
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
-
- lockfile lockfile_without_credentials
-
- # when not re-resolving
- bundle "install", artifice: "endpoint_strict_basic_authentication", quiet: true
- expect(lockfile).to eq lockfile_without_credentials
-
- # when re-resolving with full unlock
- bundle "update", artifice: "endpoint_strict_basic_authentication"
- expect(lockfile).to eq lockfile_without_credentials
-
- # when re-resolving without ful unlocking
- bundle "update myrack-obama", artifice: "endpoint_strict_basic_authentication"
- expect(lockfile).to eq lockfile_without_credentials
- end
-
- it "keeps credentials in lockfile if already there" do
- bundle "config set http://localgemserver.test/ user:pass"
-
- gemfile <<~G
- source "https://gem.repo1"
-
- source "http://localgemserver.test/" do
-
- end
-
- source "http://user:pass@othergemserver.test/" do
- gem "myrack-obama", ">= 1.0"
- end
- G
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "myrack", "1.0.0"
- c.checksum gem_repo2, "myrack-obama", "1.0"
- end
-
- lockfile_with_credentials = <<~L
GEM
remote: http://localgemserver.test/
specs:
@@ -472,45 +333,30 @@ RSpec.describe "the lockfile format" do
GEM
remote: http://user:pass@othergemserver.test/
specs:
- myrack (1.0.0)
- myrack-obama (1.0)
- myrack
-
- GEM
- remote: https://gem.repo1/
- specs:
+ rack (1.0.0)
+ rack-obama (1.0)
+ rack
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack-obama (>= 1.0)!
- #{checksums}
+ rack-obama (>= 1.0)!
+
BUNDLED WITH
#{Bundler::VERSION}
- L
-
- lockfile lockfile_with_credentials
-
- bundle "install", artifice: "endpoint_strict_basic_authentication", quiet: true
-
- expect(lockfile).to eq lockfile_with_credentials
+ G
end
it "generates lockfiles with multiple requirements" do
install_gemfile <<-G
- source "https://gem.repo2/"
+ source "#{file_uri_for(gem_repo2)}/"
gem "net-sftp"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "net-sftp", "1.1.1"
- c.checksum gem_repo2, "net-ssh", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
net-sftp (1.1.1)
net-ssh (>= 1.0.0, < 1.99.0)
@@ -521,7 +367,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
net-sftp
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -533,14 +379,10 @@ RSpec.describe "the lockfile format" do
git = build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- end
-
expect(lockfile).to eq <<~G
GIT
remote: #{lib_path("foo-1.0")}
@@ -549,7 +391,7 @@ RSpec.describe "the lockfile format" do
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -557,23 +399,23 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "does not asplode when a platform specific dependency is present and the Gemfile has not been resolved on that platform" do
- build_lib "omg", path: lib_path("omg")
+ build_lib "omg", :path => lib_path("omg")
gemfile <<-G
- source "https://gem.repo2/"
+ source "#{file_uri_for(gem_repo2)}/"
platforms :#{not_local_tag} do
gem "omg", :path => "#{lib_path("omg")}"
end
- gem "myrack"
+ gem "rack"
G
lockfile <<-L
@@ -583,34 +425,30 @@ RSpec.describe "the lockfile format" do
specs:
GEM
- remote: https://gem.repo2//
+ remote: #{file_uri_for(gem_repo2)}//
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{not_local}
DEPENDENCIES
omg!
- myrack
+ rack
BUNDLED WITH
#{Bundler::VERSION}
L
bundle "install"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "serializes global git sources" do
git = build_git "foo"
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- end
-
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}" do
gem "foo"
end
@@ -624,7 +462,7 @@ RSpec.describe "the lockfile format" do
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -632,7 +470,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -640,14 +478,10 @@ RSpec.describe "the lockfile format" do
it "generates a lockfile with a ref for a single pinned source, git gem with a branch requirement" do
git = build_git "foo"
- update_git "foo", branch: "omg"
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- end
+ update_git "foo", :branch => "omg"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :branch => "omg"
G
@@ -660,7 +494,7 @@ RSpec.describe "the lockfile format" do
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -668,7 +502,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -676,14 +510,10 @@ RSpec.describe "the lockfile format" do
it "generates a lockfile with a ref for a single pinned source, git gem with a tag requirement" do
git = build_git "foo"
- update_git "foo", tag: "omg"
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- end
+ update_git "foo", :tag => "omg"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}", :tag => "omg"
G
@@ -696,7 +526,7 @@ RSpec.describe "the lockfile format" do
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -704,7 +534,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -718,29 +548,29 @@ RSpec.describe "the lockfile format" do
FileUtils.mkdir_p lib_path("ckeditor/lib")
- @remote = build_git("ckeditor_remote", bare: true)
+ @remote = build_git("ckeditor_remote", :bare => true)
- build_git "ckeditor", path: lib_path("ckeditor") do |s|
+ build_git "ckeditor", :path => lib_path("ckeditor") do |s|
s.write "lib/ckeditor.rb", "CKEDITOR = '4.0.7'"
s.version = "4.0.7"
s.add_dependency "orm_adapter"
end
- update_git "ckeditor", path: lib_path("ckeditor"), remote: @remote.path
- update_git "ckeditor", path: lib_path("ckeditor"), tag: "v4.0.7"
- old_git = update_git "ckeditor", path: lib_path("ckeditor"), push: "v4.0.7"
+ update_git "ckeditor", :path => lib_path("ckeditor"), :remote => file_uri_for(@remote.path)
+ update_git "ckeditor", :path => lib_path("ckeditor"), :tag => "v4.0.7"
+ old_git = update_git "ckeditor", :path => lib_path("ckeditor"), :push => "v4.0.7"
- update_git "ckeditor", path: lib_path("ckeditor"), gemspec: true do |s|
+ update_git "ckeditor", :path => lib_path("ckeditor"), :gemspec => true do |s|
s.write "lib/ckeditor.rb", "CKEDITOR = '4.0.8'"
s.version = "4.0.8"
s.add_dependency "orm_adapter"
end
- update_git "ckeditor", path: lib_path("ckeditor"), tag: "v4.0.8"
+ update_git "ckeditor", :path => lib_path("ckeditor"), :tag => "v4.0.8"
- new_git = update_git "ckeditor", path: lib_path("ckeditor"), push: "v4.0.8"
+ new_git = update_git "ckeditor", :path => lib_path("ckeditor"), :push => "v4.0.8"
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "ckeditor", :git => "#{@remote.path}", :tag => "v4.0.8"
G
@@ -754,7 +584,7 @@ RSpec.describe "the lockfile format" do
orm_adapter
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
orm_adapter (0.4.1)
@@ -781,7 +611,7 @@ RSpec.describe "the lockfile format" do
orm_adapter
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
orm_adapter (0.4.1)
@@ -799,12 +629,8 @@ RSpec.describe "the lockfile format" do
it "serializes pinned path sources to the lockfile" do
build_lib "foo"
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- end
-
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
@@ -815,7 +641,7 @@ RSpec.describe "the lockfile format" do
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -823,7 +649,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -833,17 +659,13 @@ RSpec.describe "the lockfile format" do
build_lib "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :path => "#{lib_path("foo-1.0")}"
G
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- end
-
bundle "config set cache_all true"
bundle :cache
- bundle :install, local: true
+ bundle :install, :local => true
expect(lockfile).to eq <<~G
PATH
@@ -852,7 +674,7 @@ RSpec.describe "the lockfile format" do
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -860,7 +682,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -870,16 +692,10 @@ RSpec.describe "the lockfile format" do
build_lib "foo"
bar = build_git "bar"
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- c.no_checksum "bar", "1.0"
- c.checksum gem_repo2, "myrack", "1.0.0"
- end
-
install_gemfile <<-G
- source "https://gem.repo2/"
+ source "#{file_uri_for(gem_repo2)}/"
- gem "myrack"
+ gem "rack"
gem "foo", :path => "#{lib_path("foo-1.0")}"
gem "bar", :git => "#{lib_path("bar-1.0")}"
G
@@ -897,9 +713,9 @@ RSpec.describe "the lockfile format" do
foo (1.0)
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
@@ -907,8 +723,8 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
bar!
foo!
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -916,27 +732,23 @@ RSpec.describe "the lockfile format" do
it "removes redundant sources" do
install_gemfile <<-G
- source "https://gem.repo2/"
+ source "#{file_uri_for(gem_repo2)}/"
- gem "myrack", :source => "https://gem.repo2/"
+ gem "rack", :source => "#{file_uri_for(gem_repo2)}/"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "myrack", "1.0.0"
- end
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack!
- #{checksums}
+ rack!
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -944,42 +756,34 @@ RSpec.describe "the lockfile format" do
it "lists gems alphabetically" do
install_gemfile <<-G
- source "https://gem.repo2/"
+ source "#{file_uri_for(gem_repo2)}/"
gem "thin"
gem "actionpack"
- gem "myrack-obama"
+ gem "rack-obama"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "actionpack", "2.3.2"
- c.checksum gem_repo2, "activesupport", "2.3.2"
- c.checksum gem_repo2, "myrack", "1.0.0"
- c.checksum gem_repo2, "myrack-obama", "1.0"
- c.checksum gem_repo2, "thin", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
actionpack (2.3.2)
activesupport (= 2.3.2)
activesupport (2.3.2)
- myrack (1.0.0)
- myrack-obama (1.0)
- myrack
+ rack (1.0.0)
+ rack-obama (1.0)
+ rack
thin (1.0)
- myrack
+ rack
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
actionpack
- myrack-obama
+ rack-obama
thin
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -987,24 +791,14 @@ RSpec.describe "the lockfile format" do
it "orders dependencies' dependencies in alphabetical order" do
install_gemfile <<-G
- source "https://gem.repo2/"
+ source "#{file_uri_for(gem_repo2)}/"
gem "rails"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "actionmailer", "2.3.2"
- c.checksum gem_repo2, "actionpack", "2.3.2"
- c.checksum gem_repo2, "activerecord", "2.3.2"
- c.checksum gem_repo2, "activeresource", "2.3.2"
- c.checksum gem_repo2, "activesupport", "2.3.2"
- c.checksum gem_repo2, "rails", "2.3.2"
- c.checksum gem_repo2, "rake", rake_version
- end
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
actionmailer (2.3.2)
activesupport (= 2.3.2)
@@ -1020,15 +814,15 @@ RSpec.describe "the lockfile format" do
actionpack (= 2.3.2)
activerecord (= 2.3.2)
activeresource (= 2.3.2)
- rake (= #{rake_version})
- rake (#{rake_version})
+ rake (= 13.0.1)
+ rake (13.0.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
rails
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1039,25 +833,20 @@ RSpec.describe "the lockfile format" do
# Capistrano did this (at least until version 2.5.10)
# RubyGems 2.2 doesn't allow the specifying of a dependency twice
# See https://github.com/rubygems/rubygems/commit/03dbac93a3396a80db258d9bc63500333c25bd2f
- build_gem "double_deps", "1.0", skip_validation: true do |s|
+ build_gem "double_deps", "1.0", :skip_validation => true do |s|
s.add_dependency "net-ssh", ">= 1.0.0"
s.add_dependency "net-ssh"
end
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}/"
gem 'double_deps'
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "double_deps", "1.0"
- c.checksum gem_repo2, "net-ssh", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
double_deps (1.0)
net-ssh
@@ -1069,7 +858,7 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
double_deps
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1077,30 +866,25 @@ RSpec.describe "the lockfile format" do
it "does not add the :require option to the lockfile" do
install_gemfile <<-G
- source "https://gem.repo2/"
+ source "#{file_uri_for(gem_repo2)}/"
- gem "myrack-obama", ">= 1.0", :require => "myrack/obama"
+ gem "rack-obama", ">= 1.0", :require => "rack/obama"
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "myrack", "1.0.0"
- c.checksum gem_repo2, "myrack-obama", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
- myrack-obama (1.0)
- myrack
+ rack (1.0.0)
+ rack-obama (1.0)
+ rack
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack-obama (>= 1.0)
- #{checksums}
+ rack-obama (>= 1.0)
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -1108,44 +892,35 @@ RSpec.describe "the lockfile format" do
it "does not add the :group option to the lockfile" do
install_gemfile <<-G
- source "https://gem.repo2/"
+ source "#{file_uri_for(gem_repo2)}/"
- gem "myrack-obama", ">= 1.0", :group => :test
+ gem "rack-obama", ">= 1.0", :group => :test
G
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "myrack", "1.0.0"
- c.checksum gem_repo2, "myrack-obama", "1.0"
- end
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
- myrack-obama (1.0)
- myrack
+ rack (1.0.0)
+ rack-obama (1.0)
+ rack
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack-obama (>= 1.0)
- #{checksums}
+ rack-obama (>= 1.0)
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "stores relative paths when the path is provided in a relative fashion and in Gemfile dir" do
- build_lib "foo", path: bundled_app("foo")
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- end
+ build_lib "foo", :path => bundled_app("foo")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "foo" do
gem "foo"
end
@@ -1158,7 +933,7 @@ RSpec.describe "the lockfile format" do
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -1166,21 +941,17 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "stores relative paths when the path is provided in a relative fashion and is above Gemfile dir" do
- build_lib "foo", path: bundled_app(File.join("..", "foo"))
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- end
+ build_lib "foo", :path => bundled_app(File.join("..", "foo"))
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "../foo" do
gem "foo"
end
@@ -1193,7 +964,7 @@ RSpec.describe "the lockfile format" do
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -1201,26 +972,22 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "stores relative paths when the path is provided in an absolute fashion but is relative" do
- build_lib "foo", path: bundled_app("foo")
+ build_lib "foo", :path => bundled_app("foo")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path File.expand_path("foo", __dir__) do
gem "foo"
end
G
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- end
-
expect(lockfile).to eq <<~G
PATH
remote: foo
@@ -1228,7 +995,7 @@ RSpec.describe "the lockfile format" do
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -1236,21 +1003,17 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "stores relative paths when the path is provided for gemspec" do
- build_lib("foo", path: tmp("foo"))
-
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "1.0"
- end
+ build_lib("foo", :path => tmp.join("foo"))
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec :path => "../foo"
G
@@ -1261,7 +1024,7 @@ RSpec.describe "the lockfile format" do
foo (1.0)
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
PLATFORMS
@@ -1269,103 +1032,52 @@ RSpec.describe "the lockfile format" do
DEPENDENCIES
foo!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "keeps existing platforms in the lockfile" do
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "myrack", "1.0.0"
- end
-
lockfile <<-G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
java
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
G
install_gemfile <<-G
- source "https://gem.repo2/"
+ source "#{file_uri_for(gem_repo2)}/"
- gem "myrack"
+ gem "rack"
G
- checksums.checksum(gem_repo2, "myrack", "1.0.0")
-
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
- #{lockfile_platforms("java", local_platform, defaults: [])}
+ #{lockfile_platforms("java")}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
- it "adds compatible platform specific variants to the lockfile, even if resolution fallback to ruby due to some other incompatible platform specific variant" do
- simulate_platform "arm64-darwin-23" do
- build_repo4 do
- build_gem "google-protobuf", "3.25.1"
- build_gem "google-protobuf", "3.25.1" do |s|
- s.platform = "arm64-darwin-23"
- end
- build_gem "google-protobuf", "3.25.1" do |s|
- s.platform = "x64-mingw-ucrt"
- s.required_ruby_version = "> #{Gem.ruby_version}"
- end
- end
-
- gemfile <<-G
- source "https://gem.repo4"
- gem "google-protobuf"
- G
- bundle "lock --add-platform x64-mingw-ucrt"
-
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo4, "google-protobuf", "3.25.1"
- c.checksum gem_repo4, "google-protobuf", "3.25.1", "arm64-darwin-23"
- end
-
- expect(lockfile).to eq <<~L
- GEM
- remote: https://gem.repo4/
- specs:
- google-protobuf (3.25.1)
- google-protobuf (3.25.1-arm64-darwin-23)
-
- PLATFORMS
- arm64-darwin-23
- ruby
- x64-mingw-ucrt
-
- DEPENDENCIES
- google-protobuf
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- L
- end
- end
-
it "persists the spec's specific platform to the lockfile" do
build_repo2 do
build_gem "platform_specific", "1.0" do |s|
@@ -1373,226 +1085,197 @@ RSpec.describe "the lockfile format" do
end
end
- simulate_platform "universal-java-16" do
- install_gemfile <<-G
- source "https://gem.repo2"
- gem "platform_specific"
- G
+ simulate_platform "universal-java-16"
- checksums = checksums_section_when_enabled do |c|
- c.checksum gem_repo2, "platform_specific", "1.0", "universal-java-16"
- end
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo2)}"
+ gem "platform_specific"
+ G
- expect(lockfile).to eq <<~G
- GEM
- remote: https://gem.repo2/
- specs:
- platform_specific (1.0-universal-java-16)
+ expect(lockfile).to eq <<~G
+ GEM
+ remote: #{file_uri_for(gem_repo2)}/
+ specs:
+ platform_specific (1.0-universal-java-16)
- PLATFORMS
- universal-java-16
+ PLATFORMS
+ universal-java-16
- DEPENDENCIES
- platform_specific
- #{checksums}
- BUNDLED WITH
- #{Bundler::VERSION}
- G
- end
+ DEPENDENCIES
+ platform_specific
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ G
end
it "does not add duplicate gems" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo2, "activesupport", "2.3.5")
- c.checksum(gem_repo2, "myrack", "1.0.0")
- end
-
install_gemfile <<-G
- source "https://gem.repo2/"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}/"
+ gem "rack"
G
install_gemfile <<-G
- source "https://gem.repo2/"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}/"
+ gem "rack"
gem "activesupport"
G
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
activesupport (2.3.5)
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
activesupport
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "does not add duplicate dependencies" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo2, "myrack", "1.0.0")
- end
-
install_gemfile <<-G
- source "https://gem.repo2/"
- gem "myrack"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}/"
+ gem "rack"
+ gem "rack"
G
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "does not add duplicate dependencies with versions" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo2, "myrack", "1.0.0")
- end
-
install_gemfile <<-G
- source "https://gem.repo2/"
- gem "myrack", "1.0"
- gem "myrack", "1.0"
+ source "#{file_uri_for(gem_repo2)}/"
+ gem "rack", "1.0"
+ gem "rack", "1.0"
G
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack (= 1.0)
- #{checksums}
+ rack (= 1.0)
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "does not add duplicate dependencies in different groups" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo2, "myrack", "1.0.0")
- end
-
install_gemfile <<-G
- source "https://gem.repo2/"
- gem "myrack", "1.0", :group => :one
- gem "myrack", "1.0", :group => :two
+ source "#{file_uri_for(gem_repo2)}/"
+ gem "rack", "1.0", :group => :one
+ gem "rack", "1.0", :group => :two
G
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack (= 1.0)
- #{checksums}
+ rack (= 1.0)
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "raises if two different versions are used" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2/"
- gem "myrack", "1.0"
- gem "myrack", "1.1"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}/"
+ gem "rack", "1.0"
+ gem "rack", "1.1"
G
expect(bundled_app_lock).not_to exist
- expect(err).to include "myrack (= 1.0) and myrack (= 1.1)"
+ expect(err).to include "rack (= 1.0) and rack (= 1.1)"
end
it "raises if two different sources are used" do
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2/"
- gem "myrack"
- gem "myrack", :git => "git://hubz.com"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}/"
+ gem "rack"
+ gem "rack", :git => "git://hubz.com"
G
expect(bundled_app_lock).not_to exist
- expect(err).to include "myrack (>= 0) should come from an unspecified source and git://hubz.com"
+ expect(err).to include "rack (>= 0) should come from an unspecified source and git://hubz.com"
end
it "works correctly with multiple version dependencies" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo2, "myrack", "0.9.1")
- end
-
install_gemfile <<-G
- source "https://gem.repo2/"
- gem "myrack", "> 0.9", "< 1.0"
+ source "#{file_uri_for(gem_repo2)}/"
+ gem "rack", "> 0.9", "< 1.0"
G
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack (> 0.9, < 1.0)
- #{checksums}
+ rack (> 0.9, < 1.0)
+
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "captures the Ruby version in the lockfile" do
- checksums = checksums_section_when_enabled do |c|
- c.checksum(gem_repo2, "myrack", "0.9.1")
- end
-
install_gemfile <<-G
- source "https://gem.repo2/"
+ source "#{file_uri_for(gem_repo2)}/"
ruby '#{Gem.ruby_version}'
- gem "myrack", "> 0.9", "< 1.0"
+ gem "rack", "> 0.9", "< 1.0"
G
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack (> 0.9, < 1.0)
- #{checksums}
+ rack (> 0.9, < 1.0)
+
RUBY VERSION
#{Bundler::RubyVersion.system}
@@ -1604,24 +1287,24 @@ RSpec.describe "the lockfile format" do
it "raises a helpful error message when the lockfile is missing deps" do
lockfile <<-L
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack_middleware (1.0)
+ rack_middleware (1.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack_middleware
+ rack_middleware
L
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2"
- gem "myrack_middleware"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack_middleware"
G
- expect(err).to include("Downloading myrack_middleware-1.0 revealed dependencies not in the API or the lockfile (#{Gem::Dependency.new("myrack", "= 0.9.1")}).").
- and include("Running `bundle update myrack_middleware` should fix the problem.")
+ expect(err).to include("Downloading rack_middleware-1.0 revealed dependencies not in the API or the lockfile (#{Gem::Dependency.new("rack", "= 0.9.1")}).").
+ and include("Running `bundle update rack_middleware` should fix the problem.")
end
it "regenerates a lockfile with no specs" do
@@ -1637,7 +1320,7 @@ RSpec.describe "the lockfile format" do
lockfile <<-G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
PLATFORMS
@@ -1651,21 +1334,21 @@ RSpec.describe "the lockfile format" do
G
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "direct_dependency"
G
expect(lockfile).to eq <<~G
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
direct_dependency (4.5.6)
indirect_dependency
indirect_dependency (1.2.3)
PLATFORMS
- #{lockfile_platforms("ruby", generic_local_platform, defaults: [])}
+ #{formatted_lockfile_platforms(*["ruby", generic_local_platform].uniq)}
DEPENDENCIES
direct_dependency
@@ -1686,14 +1369,14 @@ RSpec.describe "the lockfile format" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "minitest-bisect"
G
# Corrupt lockfile (completely missing path_expander)
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
minitest-bisect (1.6.0)
@@ -1707,12 +1390,12 @@ RSpec.describe "the lockfile format" do
#{Bundler::VERSION}
L
- cache_gems "minitest-bisect-1.6.0", "path_expander-1.1.1", gem_repo: gem_repo4
+ cache_gems "minitest-bisect-1.6.0", "path_expander-1.1.1", :gem_repo => gem_repo4
bundle :install
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
minitest-bisect (1.6.0)
path_expander (~> 1.1)
@@ -1752,13 +1435,13 @@ RSpec.describe "the lockfile format" do
end
gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "minitest-bisect"
G
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
minitest-bisect (1.6.0)
path_expander (~> 1.1)
@@ -1774,11 +1457,11 @@ RSpec.describe "the lockfile format" do
L
bundle "install --verbose"
- expect(out).to include("re-resolving dependencies because your lock file includes \"minitest-bisect\" but not some of its dependencies")
+ expect(out).to include("re-resolving dependencies because your lock file is missing \"minitest-bisect\"")
expect(lockfile).to eq <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
minitest-bisect (1.6.0)
path_expander (~> 1.1)
@@ -1804,36 +1487,36 @@ RSpec.describe "the lockfile format" do
build_repo2
install_gemfile <<-G
- source "https://gem.repo2"
- gem "myrack"
+ source "#{file_uri_for(gem_repo2)}"
+ gem "rack"
G
set_lockfile_mtime_to_known_value
end
it "generates Gemfile.lock with \\n line endings" do
expect(File.read(bundled_app_lock)).not_to match("\r\n")
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
context "during updates" do
it "preserves Gemfile.lock \\n line endings" do
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
end
- expect { bundle "update", all: true }.to change { File.mtime(bundled_app_lock) }
+ expect { bundle "update", :all => true }.to change { File.mtime(bundled_app_lock) }
expect(File.read(bundled_app_lock)).not_to match("\r\n")
- expect(the_bundle).to include_gems "myrack 1.2"
+ expect(the_bundle).to include_gems "rack 1.2"
end
it "preserves Gemfile.lock \\n\\r line endings" do
skip "needs to be adapted" if Gem.win_platform?
update_repo2 do
- build_gem "myrack", "1.2" do |s|
- s.executables = "myrackup"
+ build_gem "rack", "1.2" do |s|
+ s.executables = "rackup"
end
end
@@ -1841,10 +1524,12 @@ RSpec.describe "the lockfile format" do
File.open(bundled_app_lock, "wb") {|f| f.puts(win_lock) }
set_lockfile_mtime_to_known_value
- expect { bundle "update", all: true }.to change { File.mtime(bundled_app_lock) }
+ expect { bundle "update", :all => true }.to change { File.mtime(bundled_app_lock) }
expect(File.read(bundled_app_lock)).to match("\r\n")
- expect(the_bundle).to include_gems "myrack 1.2"
+ simulate_bundler_version_when_missing_prerelease_default_gem_activation do
+ expect(the_bundle).to include_gems "rack 1.2"
+ end
end
end
@@ -1865,7 +1550,7 @@ RSpec.describe "the lockfile format" do
expect do
ruby <<-RUBY
- require 'bundler'
+ require '#{entrypoint}'
Bundler.setup
RUBY
end.not_to change { File.mtime(bundled_app_lock) }
@@ -1876,27 +1561,27 @@ RSpec.describe "the lockfile format" do
it "refuses to install if Gemfile.lock contains conflict markers" do
lockfile <<-L
GEM
- remote: https://gem.repo2//
+ remote: #{file_uri_for(gem_repo2)}//
specs:
<<<<<<<
- myrack (1.0.0)
+ rack (1.0.0)
=======
- myrack (1.0.1)
+ rack (1.0.1)
>>>>>>>
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
BUNDLED WITH
#{Bundler::VERSION}
L
- install_gemfile <<-G, raise_on_error: false
- source "https://gem.repo2/"
- gem "myrack"
+ install_gemfile <<-G, :raise_on_error => false
+ source "#{file_uri_for(gem_repo2)}/"
+ gem "rack"
G
expect(err).to match(/your Gemfile.lock contains merge conflicts/i)
diff --git a/spec/bundler/other/cli_dispatch_spec.rb b/spec/bundler/other/cli_dispatch_spec.rb
index 48b285045a..2d6080296f 100644
--- a/spec/bundler/other/cli_dispatch_spec.rb
+++ b/spec/bundler/other/cli_dispatch_spec.rb
@@ -2,19 +2,19 @@
RSpec.describe "bundle command names" do
it "work when given fully" do
- bundle "install", raise_on_error: false
+ bundle "install", :raise_on_error => false
expect(err).to eq("Could not locate Gemfile")
expect(last_command.stdboth).not_to include("Ambiguous command")
end
it "work when not ambiguous" do
- bundle "ins", raise_on_error: false
+ bundle "ins", :raise_on_error => false
expect(err).to eq("Could not locate Gemfile")
expect(last_command.stdboth).not_to include("Ambiguous command")
end
it "print a friendly error when ambiguous" do
- bundle "in", raise_on_error: false
+ bundle "in", :raise_on_error => false
expect(err).to eq("Ambiguous command in matches [info, init, inject, install]")
end
end
diff --git a/spec/bundler/other/ext_spec.rb b/spec/bundler/other/ext_spec.rb
index 9fc0414b4d..9b829a2b36 100644
--- a/spec/bundler/other/ext_spec.rb
+++ b/spec/bundler/other/ext_spec.rb
@@ -53,33 +53,13 @@ end
RSpec.describe "Gem::SourceIndex#refresh!" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
it "does not explode when called" do
- run "Gem.source_index.refresh!", raise_on_error: false
- run "Gem::SourceIndex.new([]).refresh!", raise_on_error: false
- end
-end
-
-RSpec.describe "Gem::NameTuple" do
- describe "#initialize" do
- it "creates a Gem::NameTuple with equality regardless of platform type" do
- gem_platform = Gem::NameTuple.new "a", v("1"), pl("x86_64-linux")
- str_platform = Gem::NameTuple.new "a", v("1"), "x86_64-linux"
- expect(gem_platform).to eq(str_platform)
- expect(gem_platform.hash).to eq(str_platform.hash)
- expect(gem_platform.to_a).to eq(str_platform.to_a)
- end
- end
-
- describe "#lock_name" do
- it "returns the lock name" do
- expect(Gem::NameTuple.new("a", v("1.0.0"), pl("x86_64-linux")).lock_name).to eq("a (1.0.0-x86_64-linux)")
- expect(Gem::NameTuple.new("a", v("1.0.0"), "ruby").lock_name).to eq("a (1.0.0)")
- expect(Gem::NameTuple.new("a", v("1.0.0")).lock_name).to eq("a (1.0.0)")
- end
+ run "Gem.source_index.refresh!", :raise_on_error => false
+ run "Gem::SourceIndex.new([]).refresh!", :raise_on_error => false
end
end
diff --git a/spec/bundler/other/major_deprecation_spec.rb b/spec/bundler/other/major_deprecation_spec.rb
index f05a8c43f8..7b7ceb4586 100644
--- a/spec/bundler/other/major_deprecation_spec.rb
+++ b/spec/bundler/other/major_deprecation_spec.rb
@@ -6,8 +6,8 @@ RSpec.describe "major deprecations" do
describe "Bundler" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
@@ -17,14 +17,14 @@ RSpec.describe "major deprecations" do
bundle "exec ruby -e #{source.dump}"
end
- it "is deprecated in favor of .unbundled_env", bundler: "< 3" do
+ it "is deprecated in favor of .unbundled_env", :bundler => "< 3" do
expect(deprecations).to include \
"`Bundler.clean_env` has been deprecated in favor of `Bundler.unbundled_env`. " \
"If you instead want the environment before bundler was originally loaded, use `Bundler.original_env` " \
"(called at -e:1)"
end
- pending "is removed and shows a helpful error message about it", bundler: "3"
+ pending "is removed and shows a helpful error message about it", :bundler => "3"
end
describe ".with_clean_env" do
@@ -33,7 +33,7 @@ RSpec.describe "major deprecations" do
bundle "exec ruby -e #{source.dump}"
end
- it "is deprecated in favor of .unbundled_env", bundler: "< 3" do
+ it "is deprecated in favor of .unbundled_env", :bundler => "< 3" do
expect(deprecations).to include(
"`Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. " \
"If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env` " \
@@ -41,7 +41,7 @@ RSpec.describe "major deprecations" do
)
end
- pending "is removed and shows a helpful error message about it", bundler: "3"
+ pending "is removed and shows a helpful error message about it", :bundler => "3"
end
describe ".clean_system" do
@@ -50,7 +50,7 @@ RSpec.describe "major deprecations" do
bundle "exec ruby -e #{source.dump}"
end
- it "is deprecated in favor of .unbundled_system", bundler: "< 3" do
+ it "is deprecated in favor of .unbundled_system", :bundler => "< 3" do
expect(deprecations).to include(
"`Bundler.clean_system` has been deprecated in favor of `Bundler.unbundled_system`. " \
"If you instead want to run the command in the environment before bundler was originally loaded, use `Bundler.original_system` " \
@@ -58,7 +58,7 @@ RSpec.describe "major deprecations" do
)
end
- pending "is removed and shows a helpful error message about it", bundler: "3"
+ pending "is removed and shows a helpful error message about it", :bundler => "3"
end
describe ".clean_exec" do
@@ -67,7 +67,7 @@ RSpec.describe "major deprecations" do
bundle "exec ruby -e #{source.dump}"
end
- it "is deprecated in favor of .unbundled_exec", bundler: "< 3" do
+ it "is deprecated in favor of .unbundled_exec", :bundler => "< 3" do
expect(deprecations).to include(
"`Bundler.clean_exec` has been deprecated in favor of `Bundler.unbundled_exec`. " \
"If you instead want to exec to a command in the environment before bundler was originally loaded, use `Bundler.original_exec` " \
@@ -75,7 +75,7 @@ RSpec.describe "major deprecations" do
)
end
- pending "is removed and shows a helpful error message about it", bundler: "3"
+ pending "is removed and shows a helpful error message about it", :bundler => "3"
end
describe ".environment" do
@@ -84,29 +84,29 @@ RSpec.describe "major deprecations" do
bundle "exec ruby -e #{source.dump}"
end
- it "is deprecated in favor of .load", bundler: "< 3" do
+ it "is deprecated in favor of .load", :bundler => "< 3" do
expect(deprecations).to include "Bundler.environment has been removed in favor of Bundler.load (called at -e:1)"
end
- pending "is removed and shows a helpful error message about it", bundler: "3"
+ pending "is removed and shows a helpful error message about it", :bundler => "3"
end
end
describe "bundle exec --no-keep-file-descriptors" do
before do
- bundle "exec --no-keep-file-descriptors -e 1", raise_on_error: false
+ bundle "exec --no-keep-file-descriptors -e 1", :raise_on_error => false
end
- it "is deprecated", bundler: "< 3" do
+ it "is deprecated", :bundler => "< 3" do
expect(deprecations).to include "The `--no-keep-file-descriptors` has been deprecated. `bundle exec` no longer mess with your file descriptors. Close them in the exec'd script if you need to"
end
- pending "is removed and shows a helpful error message about it", bundler: "3"
+ pending "is removed and shows a helpful error message about it", :bundler => "3"
end
describe "bundle update --quiet" do
it "does not print any deprecations" do
- bundle :update, quiet: true, raise_on_error: false
+ bundle :update, :quiet => true, :raise_on_error => false
expect(deprecations).to be_empty
end
end
@@ -114,58 +114,58 @@ RSpec.describe "major deprecations" do
context "bundle check --path" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "check --path vendor/bundle", raise_on_error: false
+ bundle "check --path vendor/bundle", :raise_on_error => false
end
- it "should print a deprecation warning", bundler: "< 3" do
+ it "should print a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include(
"The `--path` flag is deprecated because it relies on being " \
"remembered across bundler invocations, which bundler will no " \
- "longer do in future versions. Instead please use `bundle config set " \
+ "longer do in future versions. Instead please use `bundle config set --local " \
"path 'vendor/bundle'`, and stop using this flag"
)
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
context "bundle check --path=" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "check --path=vendor/bundle", raise_on_error: false
+ bundle "check --path=vendor/bundle", :raise_on_error => false
end
- it "should print a deprecation warning", bundler: "< 3" do
+ it "should print a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include(
"The `--path` flag is deprecated because it relies on being " \
"remembered across bundler invocations, which bundler will no " \
- "longer do in future versions. Instead please use `bundle config set " \
+ "longer do in future versions. Instead please use `bundle config set --local " \
"path 'vendor/bundle'`, and stop using this flag"
)
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
context "bundle cache --all" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "cache --all", raise_on_error: false
+ bundle "cache --all", :raise_on_error => false
end
- it "should print a deprecation warning", bundler: "< 3" do
+ it "should print a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include(
"The `--all` flag is deprecated because it relies on being " \
"remembered across bundler invocations, which bundler will no " \
@@ -174,20 +174,20 @@ RSpec.describe "major deprecations" do
)
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
context "bundle cache --path" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- bundle "cache --path foo", raise_on_error: false
+ bundle "cache --path foo", :raise_on_error => false
end
- it "should print a deprecation warning", bundler: "< 3" do
+ it "should print a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include(
"The `--path` flag is deprecated because its semantics are unclear. " \
"Use `bundle config cache_path` to configure the path of your cache of gems, " \
@@ -196,7 +196,7 @@ RSpec.describe "major deprecations" do
)
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
describe "bundle config" do
@@ -205,11 +205,11 @@ RSpec.describe "major deprecations" do
bundle "config"
end
- it "warns", bundler: "3" do
+ it "warns", :bundler => "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config list` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
describe "old get interface" do
@@ -217,11 +217,11 @@ RSpec.describe "major deprecations" do
bundle "config waka"
end
- it "warns", bundler: "3" do
+ it "warns", :bundler => "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config get waka` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
describe "old set interface" do
@@ -229,11 +229,11 @@ RSpec.describe "major deprecations" do
bundle "config waka wakapun"
end
- it "warns", bundler: "3" do
+ it "warns", :bundler => "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config set waka wakapun` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
describe "old set interface with --local" do
@@ -241,11 +241,11 @@ RSpec.describe "major deprecations" do
bundle "config --local waka wakapun"
end
- it "warns", bundler: "3" do
+ it "warns", :bundler => "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config set --local waka wakapun` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
describe "old set interface with --global" do
@@ -253,11 +253,11 @@ RSpec.describe "major deprecations" do
bundle "config --global waka wakapun"
end
- it "warns", bundler: "3" do
+ it "warns", :bundler => "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config set --global waka wakapun` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
describe "old unset interface" do
@@ -265,11 +265,11 @@ RSpec.describe "major deprecations" do
bundle "config --delete waka"
end
- it "warns", bundler: "3" do
+ it "warns", :bundler => "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config unset waka` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
describe "old unset interface with --local" do
@@ -277,11 +277,11 @@ RSpec.describe "major deprecations" do
bundle "config --delete --local waka"
end
- it "warns", bundler: "3" do
+ it "warns", :bundler => "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config unset --local waka` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
describe "old unset interface with --global" do
@@ -289,28 +289,28 @@ RSpec.describe "major deprecations" do
bundle "config --delete --global waka"
end
- it "warns", bundler: "3" do
+ it "warns", :bundler => "3" do
expect(deprecations).to include("Using the `config` command without a subcommand [list, get, set, unset] is deprecated and will be removed in the future. Use `bundle config unset --global waka` instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
end
describe "bundle update" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
- it "warns when no options are given", bundler: "3" do
+ it "warns when no options are given", :bundler => "3" do
bundle "update"
expect(deprecations).to include("Pass --all to `bundle update` to update everything")
end
- pending "fails with a helpful error when no options are given", bundler: "3"
+ pending "fails with a helpful error when no options are given", :bundler => "3"
it "does not warn when --all is passed" do
bundle "update --all"
@@ -320,24 +320,24 @@ RSpec.describe "major deprecations" do
describe "bundle install --binstubs" do
before do
- install_gemfile <<-G, binstubs: true
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :binstubs => true
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
- it "should output a deprecation warning", bundler: "< 3" do
+ it "should output a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include("The --binstubs option will be removed in favor of `bundle binstubs --all`")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
context "bundle install with both gems.rb and Gemfile present" do
it "should not warn about gems.rb" do
- gemfile "gems.rb", <<-G
- source "https://gem.repo1"
- gem "myrack"
+ create_file "gems.rb", <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle :install
@@ -345,17 +345,17 @@ RSpec.describe "major deprecations" do
end
it "should print a proper warning, and use gems.rb" do
- gemfile "gems.rb", "source 'https://gem.repo1'"
+ create_file "gems.rb", "source \"#{file_uri_for(gem_repo1)}\""
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
expect(warnings).to include(
"Multiple gemfiles (gems.rb and Gemfile) detected. Make sure you remove Gemfile and Gemfile.lock since bundler is ignoring them in favor of gems.rb and gems.locked."
)
- expect(the_bundle).not_to include_gem "myrack 1.0"
+ expect(the_bundle).not_to include_gem "rack 1.0"
end
end
@@ -364,22 +364,22 @@ RSpec.describe "major deprecations" do
bundle "config set --local path vendor/bundle"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
{
- "clean" => ["clean", "true"],
- "deployment" => ["deployment", "true"],
- "frozen" => ["frozen", "true"],
- "no-deployment" => ["deployment", "false"],
- "no-prune" => ["no_prune", "true"],
- "path" => ["path", "'vendor/bundle'"],
- "shebang" => ["shebang", "'ruby27'"],
- "system" => ["path.system", "true"],
- "without" => ["without", "'development'"],
- "with" => ["with", "'development'"],
+ "clean" => ["clean", true],
+ "deployment" => ["deployment", true],
+ "frozen" => ["frozen", true],
+ "no-deployment" => ["deployment", false],
+ "no-prune" => ["no_prune", true],
+ "path" => ["path", "vendor/bundle"],
+ "shebang" => ["shebang", "ruby27"],
+ "system" => ["system", true],
+ "without" => ["without", "development"],
+ "with" => ["with", "development"],
}.each do |name, expectations|
option_name, value = *expectations
flag_name = "--#{name}"
@@ -390,16 +390,16 @@ RSpec.describe "major deprecations" do
bundle "install #{flag_name} #{value}"
end
- it "should print a deprecation warning", bundler: "< 3" do
+ it "should print a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include(
"The `#{flag_name}` flag is deprecated because it relies on " \
"being remembered across bundler invocations, which bundler " \
"will no longer do in future versions. Instead please use " \
- "`bundle config set #{option_name} #{value}`, and stop using this flag"
+ "`bundle config set --local #{option_name} '#{value}'`, and stop using this flag"
)
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
end
end
@@ -407,12 +407,12 @@ RSpec.describe "major deprecations" do
context "bundle install with multiple sources" do
before do
install_gemfile <<-G
- source "https://gem.repo3"
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo3)}"
+ source "#{file_uri_for(gem_repo1)}"
G
end
- it "shows a deprecation", bundler: "< 3" do
+ it "shows a deprecation", :bundler => "< 3" do
expect(deprecations).to include(
"Your Gemfile contains multiple global sources. " \
"Using `source` more than once without a block is a security risk, and " \
@@ -421,7 +421,7 @@ RSpec.describe "major deprecations" do
)
end
- it "doesn't show lockfile deprecations if there's a lockfile", bundler: "< 3" do
+ it "doesn't show lockfile deprecations if there's a lockfile", :bundler => "< 3" do
bundle "install"
expect(deprecations).to include(
@@ -449,34 +449,34 @@ RSpec.describe "major deprecations" do
)
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
context "bundle install in frozen mode with a lockfile with a single rubygems section with multiple remotes" do
before do
- build_repo3 do
- build_gem "myrack", "0.9.1"
+ build_repo gem_repo3 do
+ build_gem "rack", "0.9.1"
end
gemfile <<-G
- source "https://gem.repo1"
- source "https://gem.repo3" do
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ source "#{file_uri_for(gem_repo3)}" do
+ gem 'rack'
end
G
lockfile <<~L
GEM
- remote: https://gem.repo1/
- remote: https://gem.repo3/
+ remote: #{file_uri_for(gem_repo1)}/
+ remote: #{file_uri_for(gem_repo3)}/
specs:
- myrack (0.9.1)
+ rack (0.9.1)
PLATFORMS
ruby
DEPENDENCIES
- myrack!
+ rack!
BUNDLED WITH
#{Bundler::VERSION}
@@ -485,25 +485,25 @@ RSpec.describe "major deprecations" do
bundle "config set --local frozen true"
end
- it "shows a deprecation", bundler: "< 3" do
+ it "shows a deprecation", :bundler => "< 3" do
bundle "install"
expect(deprecations).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
context "when Bundler.setup is run in a ruby script" do
before do
- create_file "gems.rb", "source 'https://gem.repo1'"
+ create_file "gems.rb", "source \"#{file_uri_for(gem_repo1)}\""
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :group => :test
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :group => :test
G
ruby <<-RUBY
- require 'bundler'
+ require '#{entrypoint}'
Bundler.setup
Bundler.setup
@@ -519,26 +519,26 @@ RSpec.describe "major deprecations" do
context "when `bundler/deployment` is required in a ruby script" do
before do
- ruby <<-RUBY
+ ruby(<<-RUBY, :env => env_for_missing_prerelease_default_gem_activation)
require 'bundler/deployment'
RUBY
end
- it "should print a capistrano deprecation warning", bundler: "< 3" do
+ it "should print a capistrano deprecation warning", :bundler => "< 3" do
expect(deprecations).to include("Bundler no longer integrates " \
"with Capistrano, but Capistrano provides " \
"its own integration with Bundler via the " \
"capistrano-bundler gem. Use it instead.")
end
- pending "fails with a helpful error", bundler: "3"
+ pending "fails with a helpful error", :bundler => "3"
end
context "bundle show" do
before do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
@@ -547,89 +547,67 @@ RSpec.describe "major deprecations" do
bundle "show --outdated"
end
- it "prints a deprecation warning informing about its removal", bundler: "< 3" do
+ it "prints a deprecation warning informing about its removal", :bundler => "< 3" do
expect(deprecations).to include("the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement")
end
- pending "fails with a helpful message", bundler: "3"
+ pending "fails with a helpful message", :bundler => "3"
end
end
context "bundle remove" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
context "with --install" do
- it "shows a deprecation warning", bundler: "< 3" do
- bundle "remove myrack --install"
+ it "shows a deprecation warning", :bundler => "< 3" do
+ bundle "remove rack --install"
expect(err).to include "[DEPRECATED] The `--install` flag has been deprecated. `bundle install` is triggered by default."
end
- pending "fails with a helpful message", bundler: "3"
+ pending "fails with a helpful message", :bundler => "3"
end
end
context "bundle console" do
before do
- bundle "console", raise_on_error: false
+ bundle "console", :raise_on_error => false
end
- it "prints a deprecation warning", bundler: "< 3" do
+ it "prints a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include \
"bundle console will be replaced by `bin/console` generated by `bundle gem <name>`"
end
- pending "fails with a helpful message", bundler: "3"
+ pending "fails with a helpful message", :bundler => "3"
end
context "bundle viz", :realworld do
before do
realworld_system_gems "ruby-graphviz --version 1.2.5"
- create_file "gems.rb", "source 'https://gem.repo1'"
+ create_file "gems.rb", "source \"#{file_uri_for(gem_repo1)}\""
bundle "viz"
end
- it "prints a deprecation warning", bundler: "< 3" do
+ it "prints a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include "The `viz` command has been renamed to `graph` and moved to a plugin. See https://github.com/rubygems/bundler-graph"
end
- pending "fails with a helpful message", bundler: "3"
+ pending "fails with a helpful message", :bundler => "3"
end
- context "bundle plugin install --local_git" do
- before do
- build_git "foo" do |s|
- s.write "plugins.rb"
- end
- end
-
- it "prints a deprecation warning", bundler: "< 3" do
- bundle "plugin install foo --local_git #{lib_path("foo-1.0")}"
-
- expect(out).to include("Installed plugin foo")
- expect(deprecations).to include "--local_git is deprecated, use --git"
- end
-
- pending "fails with a helpful message", bundler: "3"
- end
-
- describe "deprecating rubocop" do
- before do
- global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false",
- "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false"
- end
-
+ describe "deprecating rubocop", :readline do
context "bundle gem --rubocop" do
before do
- bundle "gem my_new_gem --rubocop", raise_on_error: false
+ bundle "gem my_new_gem --rubocop", :raise_on_error => false
end
- it "prints a deprecation warning", bundler: "< 3" do
+ it "prints a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include \
"--rubocop is deprecated, use --linter=rubocop"
end
@@ -637,10 +615,10 @@ RSpec.describe "major deprecations" do
context "bundle gem --no-rubocop" do
before do
- bundle "gem my_new_gem --no-rubocop", raise_on_error: false
+ bundle "gem my_new_gem --no-rubocop", :raise_on_error => false
end
- it "prints a deprecation warning", bundler: "< 3" do
+ it "prints a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include \
"--no-rubocop is deprecated, use --linter"
end
@@ -648,10 +626,10 @@ RSpec.describe "major deprecations" do
context "bundle gem with gem.rubocop set to true" do
before do
- bundle "gem my_new_gem", env: { "BUNDLE_GEM__RUBOCOP" => "true" }, raise_on_error: false
+ bundle "gem my_new_gem", :env => { "BUNDLE_GEM__RUBOCOP" => "true" }, :raise_on_error => false
end
- it "prints a deprecation warning", bundler: "< 3" do
+ it "prints a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include \
"config gem.rubocop is deprecated; we've updated your config to use gem.linter instead"
end
@@ -659,10 +637,10 @@ RSpec.describe "major deprecations" do
context "bundle gem with gem.rubocop set to false" do
before do
- bundle "gem my_new_gem", env: { "BUNDLE_GEM__RUBOCOP" => "false" }, raise_on_error: false
+ bundle "gem my_new_gem", :env => { "BUNDLE_GEM__RUBOCOP" => "false" }, :raise_on_error => false
end
- it "prints a deprecation warning", bundler: "< 3" do
+ it "prints a deprecation warning", :bundler => "< 3" do
expect(deprecations).to include \
"config gem.rubocop is deprecated; we've updated your config to use gem.linter instead"
end
diff --git a/spec/bundler/plugins/command_spec.rb b/spec/bundler/plugins/command_spec.rb
index f8dacb0e51..3a7adf4b48 100644
--- a/spec/bundler/plugins/command_spec.rb
+++ b/spec/bundler/plugins/command_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe "command plugins" do
end
end
- bundle "plugin install command-mah --source https://gem.repo2"
+ bundle "plugin install command-mah --source #{file_uri_for(gem_repo2)}"
end
it "executes without arguments" do
@@ -29,7 +29,7 @@ RSpec.describe "command plugins" do
end
it "accepts the arguments" do
- update_repo2 do
+ build_repo2 do
build_plugin "the-echoer" do |s|
s.write "plugins.rb", <<-RUBY
module Resonance
@@ -46,7 +46,7 @@ RSpec.describe "command plugins" do
end
end
- bundle "plugin install the-echoer --source https://gem.repo2"
+ bundle "plugin install the-echoer --source #{file_uri_for(gem_repo2)}"
expect(out).to include("Installed plugin the-echoer")
bundle "echo tacos tofu lasange"
@@ -54,7 +54,7 @@ RSpec.describe "command plugins" do
end
it "raises error on redeclaration of command" do
- update_repo2 do
+ build_repo2 do
build_plugin "copycat" do |s|
s.write "plugins.rb", <<-RUBY
module CopyCat
@@ -69,7 +69,7 @@ RSpec.describe "command plugins" do
end
end
- bundle "plugin install copycat --source https://gem.repo2", raise_on_error: false
+ bundle "plugin install copycat --source #{file_uri_for(gem_repo2)}", :raise_on_error => false
expect(out).not_to include("Installed plugin copycat")
diff --git a/spec/bundler/plugins/hook_spec.rb b/spec/bundler/plugins/hook_spec.rb
index 3f9053bbc8..72feb14d84 100644
--- a/spec/bundler/plugins/hook_spec.rb
+++ b/spec/bundler/plugins/hook_spec.rb
@@ -13,17 +13,17 @@ RSpec.describe "hook plugins" do
end
end
- bundle "plugin install before-install-all-plugin --source https://gem.repo2"
+ bundle "plugin install before-install-all-plugin --source #{file_uri_for(gem_repo2)}"
end
it "runs before all rubygems are installed" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rake"
- gem "myrack"
+ gem "rack"
G
- expect(out).to include "gems to be installed rake, myrack"
+ expect(out).to include "gems to be installed rake, rack"
end
end
@@ -39,18 +39,18 @@ RSpec.describe "hook plugins" do
end
end
- bundle "plugin install before-install-plugin --source https://gem.repo2"
+ bundle "plugin install before-install-plugin --source #{file_uri_for(gem_repo2)}"
end
it "runs before each rubygem is installed" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rake"
- gem "myrack"
+ gem "rack"
G
expect(out).to include "installing gem rake"
- expect(out).to include "installing gem myrack"
+ expect(out).to include "installing gem rack"
end
end
@@ -66,17 +66,17 @@ RSpec.describe "hook plugins" do
end
end
- bundle "plugin install after-install-all-plugin --source https://gem.repo2"
+ bundle "plugin install after-install-all-plugin --source #{file_uri_for(gem_repo2)}"
end
- it "runs after each all rubygems are installed" do
+ it "runs after each rubygem is installed" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rake"
- gem "myrack"
+ gem "rack"
G
- expect(out).to include "installed gems rake, myrack"
+ expect(out).to include "installed gems rake, rack"
end
end
@@ -92,117 +92,18 @@ RSpec.describe "hook plugins" do
end
end
- bundle "plugin install after-install-plugin --source https://gem.repo2"
+ bundle "plugin install after-install-plugin --source #{file_uri_for(gem_repo2)}"
end
it "runs after each rubygem is installed" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rake"
- gem "myrack"
+ gem "rack"
G
expect(out).to include "installed gem rake : installed"
- expect(out).to include "installed gem myrack : installed"
- end
- end
-
- context "before-require-all hook" do
- before do
- build_repo2 do
- build_plugin "before-require-all-plugin" do |s|
- s.write "plugins.rb", <<-RUBY
- Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_BEFORE_REQUIRE_ALL do |deps|
- puts "gems to be required \#{deps.map(&:name).join(", ")}"
- end
- RUBY
- end
- end
-
- bundle "plugin install before-require-all-plugin --source https://gem.repo2"
- end
-
- it "runs before all rubygems are required" do
- install_gemfile_and_bundler_require
- expect(out).to include "gems to be required rake, myrack"
+ expect(out).to include "installed gem rack : installed"
end
end
-
- context "before-require hook" do
- before do
- build_repo2 do
- build_plugin "before-require-plugin" do |s|
- s.write "plugins.rb", <<-RUBY
- Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_BEFORE_REQUIRE do |dep|
- puts "requiring gem \#{dep.name}"
- end
- RUBY
- end
- end
-
- bundle "plugin install before-require-plugin --source https://gem.repo2"
- end
-
- it "runs before each rubygem is required" do
- install_gemfile_and_bundler_require
- expect(out).to include "requiring gem rake"
- expect(out).to include "requiring gem myrack"
- end
- end
-
- context "after-require-all hook" do
- before do
- build_repo2 do
- build_plugin "after-require-all-plugin" do |s|
- s.write "plugins.rb", <<-RUBY
- Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_AFTER_REQUIRE_ALL do |deps|
- puts "required gems \#{deps.map(&:name).join(", ")}"
- end
- RUBY
- end
- end
-
- bundle "plugin install after-require-all-plugin --source https://gem.repo2"
- end
-
- it "runs after all rubygems are required" do
- install_gemfile_and_bundler_require
- expect(out).to include "required gems rake, myrack"
- end
- end
-
- context "after-require hook" do
- before do
- build_repo2 do
- build_plugin "after-require-plugin" do |s|
- s.write "plugins.rb", <<-RUBY
- Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_AFTER_REQUIRE do |dep|
- puts "required gem \#{dep.name}"
- end
- RUBY
- end
- end
-
- bundle "plugin install after-require-plugin --source https://gem.repo2"
- end
-
- it "runs after each rubygem is required" do
- install_gemfile_and_bundler_require
- expect(out).to include "required gem rake"
- expect(out).to include "required gem myrack"
- end
- end
-
- def install_gemfile_and_bundler_require
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "rake"
- gem "myrack"
- G
-
- ruby <<-RUBY
- require "bundler"
- Bundler.require
- RUBY
- end
end
diff --git a/spec/bundler/plugins/install_spec.rb b/spec/bundler/plugins/install_spec.rb
index d0de607e6c..aec131f2ee 100644
--- a/spec/bundler/plugins/install_spec.rb
+++ b/spec/bundler/plugins/install_spec.rb
@@ -9,28 +9,28 @@ RSpec.describe "bundler plugin install" do
end
it "shows proper message when gem in not found in the source" do
- bundle "plugin install no-foo --source https://gem.repo1", raise_on_error: false
+ bundle "plugin install no-foo --source #{file_uri_for(gem_repo1)}", :raise_on_error => false
expect(err).to include("Could not find")
plugin_should_not_be_installed("no-foo")
end
it "installs from rubygems source" do
- bundle "plugin install foo --source https://gem.repo2"
+ bundle "plugin install foo --source #{file_uri_for(gem_repo2)}"
expect(out).to include("Installed plugin foo")
plugin_should_be_installed("foo")
end
it "installs from rubygems source in frozen mode" do
- bundle "plugin install foo --source https://gem.repo2", env: { "BUNDLE_DEPLOYMENT" => "true" }
+ bundle "plugin install foo --source #{file_uri_for(gem_repo2)}", :env => { "BUNDLE_DEPLOYMENT" => "true" }
expect(out).to include("Installed plugin foo")
plugin_should_be_installed("foo")
end
it "installs from sources configured as Gem.sources without any flags" do
- bundle "plugin install foo", artifice: "compact_index", env: { "BUNDLER_SPEC_GEM_SOURCES" => "https://gem.repo2" }
+ bundle "plugin install foo", :env => { "BUNDLER_SPEC_GEM_SOURCES" => file_uri_for(gem_repo2).to_s }
expect(out).to include("Installed plugin foo")
plugin_should_be_installed("foo")
@@ -45,18 +45,18 @@ RSpec.describe "bundler plugin install" do
context "plugin is already installed" do
before do
- bundle "plugin install foo --source https://gem.repo2"
+ bundle "plugin install foo --source #{file_uri_for(gem_repo2)}"
end
it "doesn't install plugin again" do
- bundle "plugin install foo --source https://gem.repo2"
+ bundle "plugin install foo --source #{file_uri_for(gem_repo2)}"
expect(out).not_to include("Installing plugin foo")
expect(out).not_to include("Installed plugin foo")
end
end
it "installs multiple plugins" do
- bundle "plugin install foo kung-foo --source https://gem.repo2"
+ bundle "plugin install foo kung-foo --source #{file_uri_for(gem_repo2)}"
expect(out).to include("Installed plugin foo")
expect(out).to include("Installed plugin kung-foo")
@@ -70,7 +70,7 @@ RSpec.describe "bundler plugin install" do
build_plugin "kung-foo", "1.1"
end
- bundle "plugin install foo kung-foo --version '1.0' --source https://gem.repo2"
+ bundle "plugin install foo kung-foo --version '1.0' --source #{file_uri_for(gem_repo2)}"
expect(out).to include("Installing foo 1.0")
expect(out).to include("Installing kung-foo 1.0")
@@ -82,32 +82,30 @@ RSpec.describe "bundler plugin install" do
build_plugin "foo", "1.1"
end
- bundle "plugin install foo --version 1.0 --source https://gem.repo2 --verbose"
+ bundle "plugin install foo --version 1.0 --source #{file_uri_for(gem_repo2)} --verbose"
expect(out).to include("Installing foo 1.0")
- bundle "plugin install foo --source https://gem.repo2 --verbose"
+ bundle "plugin install foo --source #{file_uri_for(gem_repo2)} --verbose"
expect(out).to include("Installing foo 1.1")
- bundle "plugin install foo --source https://gem.repo2 --verbose"
+ bundle "plugin install foo --source #{file_uri_for(gem_repo2)} --verbose"
expect(out).to include("Using foo 1.1")
end
- it "raises an error when when --branch specified" do
- bundle "plugin install foo --branch main --source https://gem.repo2", raise_on_error: false
+ it "installs when --branch specified" do
+ bundle "plugin install foo --branch main --source #{file_uri_for(gem_repo2)}"
- expect(out).not_to include("Installed plugin foo")
-
- expect(err).to include("--branch can only be used with git sources")
+ expect(out).to include("Installed plugin foo")
end
- it "raises an error when --ref specified" do
- bundle "plugin install foo --ref v1.2.3 --source https://gem.repo2", raise_on_error: false
+ it "installs when --ref specified" do
+ bundle "plugin install foo --ref v1.2.3 --source #{file_uri_for(gem_repo2)}"
- expect(err).to include("--ref can only be used with git sources")
+ expect(out).to include("Installed plugin foo")
end
it "raises error when both --branch and --ref options are specified" do
- bundle "plugin install foo --source https://gem.repo2 --branch main --ref v1.2.3", raise_on_error: false
+ bundle "plugin install foo --source #{file_uri_for(gem_repo2)} --branch main --ref v1.2.3", :raise_on_error => false
expect(out).not_to include("Installed plugin foo")
@@ -131,7 +129,7 @@ RSpec.describe "bundler plugin install" do
s.write("src/fubar.rb")
end
end
- bundle "plugin install testing --source https://gem.repo2"
+ bundle "plugin install testing --source #{file_uri_for(gem_repo2)}"
bundle "check2", "no-color" => false
expect(out).to eq("mate")
@@ -144,17 +142,17 @@ RSpec.describe "bundler plugin install" do
build_plugin "kung-foo", "1.1"
end
- bundle "plugin install foo kung-foo --version '1.0' --source https://gem.repo2"
+ bundle "plugin install foo kung-foo --version '1.0' --source #{file_uri_for(gem_repo2)}"
expect(out).to include("Installing foo 1.0")
expect(out).to include("Installing kung-foo 1.0")
plugin_should_be_installed("foo", "kung-foo")
- update_repo2 do
+ build_repo2 do
build_gem "charlie"
end
- bundle "plugin install charlie --source https://gem.repo2", raise_on_error: false
+ bundle "plugin install charlie --source #{file_uri_for(gem_repo2)}", :raise_on_error => false
expect(err).to include("Failed to install plugin `charlie`, due to Bundler::Plugin::MalformattedPlugin (plugins.rb was not found in the plugin.)")
@@ -173,7 +171,7 @@ RSpec.describe "bundler plugin install" do
end
end
- bundle "plugin install chaplin --source https://gem.repo2", raise_on_error: false
+ bundle "plugin install chaplin --source #{file_uri_for(gem_repo2)}", :raise_on_error => false
expect(global_plugin_gem("chaplin-1.0")).not_to be_directory
@@ -187,7 +185,7 @@ RSpec.describe "bundler plugin install" do
s.write "plugins.rb"
end
- bundle "plugin install foo --git #{lib_path("foo-1.0")}"
+ bundle "plugin install foo --git #{file_uri_for(lib_path("foo-1.0"))}"
expect(out).to include("Installed plugin foo")
plugin_should_be_installed("foo")
@@ -198,58 +196,20 @@ RSpec.describe "bundler plugin install" do
s.write "plugins.rb"
end
- bundle "plugin install foo --git #{lib_path("foo-1.0")}"
+ bundle "plugin install foo --local_git #{lib_path("foo-1.0")}"
expect(out).to include("Installed plugin foo")
plugin_should_be_installed("foo")
end
- it "raises an error when both git and local git sources are specified", bundler: "< 3" do
- bundle "plugin install foo --git /phony/path/project --local_git git@gitphony.com:/repo/project", raise_on_error: false
+ it "raises an error when both git and local git sources are specified" do
+ bundle "plugin install foo --local_git /phony/path/project --git git@gitphony.com:/repo/project", :raise_on_error => false
expect(exitstatus).not_to eq(0)
expect(err).to eq("Remote and local plugin git sources can't be both specified")
end
end
- context "path plugins" do
- it "installs from a path source" do
- build_lib "path_plugin" do |s|
- s.write "plugins.rb"
- end
- bundle "plugin install path_plugin --path #{lib_path("path_plugin-1.0")}"
-
- expect(out).to include("Installed plugin path_plugin")
- plugin_should_be_installed("path_plugin")
- end
-
- it "installs from a relative path source" do
- build_lib "path_plugin" do |s|
- s.write "plugins.rb"
- end
- path = lib_path("path_plugin-1.0").relative_path_from(bundled_app)
- bundle "plugin install path_plugin --path #{path}"
-
- expect(out).to include("Installed plugin path_plugin")
- plugin_should_be_installed("path_plugin")
- end
-
- it "installs from a relative path source when inside an app" do
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
- gemfile ""
-
- build_lib "ga-plugin" do |s|
- s.write "plugins.rb"
- end
-
- path = lib_path("ga-plugin-1.0").relative_path_from(bundled_app)
- bundle "plugin install ga-plugin --path #{path}"
-
- plugin_should_be_installed("ga-plugin")
- expect(local_plugin_gem("foo-1.0")).not_to be_directory
- end
- end
-
context "Gemfile eval" do
before do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
@@ -257,9 +217,9 @@ RSpec.describe "bundler plugin install" do
it "installs plugins listed in gemfile" do
gemfile <<-G
- source 'https://gem.repo2'
+ source '#{file_uri_for(gem_repo2)}'
plugin 'foo'
- gem 'myrack', "1.0.0"
+ gem 'rack', "1.0.0"
G
bundle "install"
@@ -268,7 +228,7 @@ RSpec.describe "bundler plugin install" do
expect(out).to include("Bundle complete!")
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0")
plugin_should_be_installed("foo")
end
@@ -278,7 +238,7 @@ RSpec.describe "bundler plugin install" do
end
gemfile <<-G
- source 'https://gem.repo2'
+ source '#{file_uri_for(gem_repo2)}'
plugin 'foo', "1.0"
G
@@ -297,7 +257,7 @@ RSpec.describe "bundler plugin install" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
plugin 'ga-plugin', :git => "#{lib_path("ga-plugin-1.0")}"
G
@@ -311,7 +271,7 @@ RSpec.describe "bundler plugin install" do
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
plugin 'ga-plugin', :path => "#{lib_path("ga-plugin-1.0")}"
G
@@ -319,40 +279,25 @@ RSpec.describe "bundler plugin install" do
plugin_should_be_installed("ga-plugin")
end
- it "accepts relative path sources" do
- build_lib "ga-plugin" do |s|
- s.write "plugins.rb"
- end
-
- path = lib_path("ga-plugin-1.0").relative_path_from(bundled_app)
- install_gemfile <<-G
- source "https://gem.repo1"
- plugin 'ga-plugin', :path => "#{path}"
- G
-
- expect(out).to include("Installed plugin ga-plugin")
- plugin_should_be_installed("ga-plugin")
- end
-
context "in deployment mode" do
it "installs plugins" do
install_gemfile <<-G
- source 'https://gem.repo2'
- gem 'myrack', "1.0.0"
+ source '#{file_uri_for(gem_repo2)}'
+ gem 'rack', "1.0.0"
G
bundle "config set --local deployment true"
install_gemfile <<-G
- source 'https://gem.repo2'
+ source '#{file_uri_for(gem_repo2)}'
plugin 'foo'
- gem 'myrack', "1.0.0"
+ gem 'rack', "1.0.0"
G
expect(out).to include("Installed plugin foo")
expect(out).to include("Bundle complete!")
- expect(the_bundle).to include_gems("myrack 1.0.0")
+ expect(the_bundle).to include_gems("rack 1.0.0")
plugin_should_be_installed("foo")
end
end
@@ -364,12 +309,12 @@ RSpec.describe "bundler plugin install" do
require "bundler/inline"
gemfile do
- source 'https://gem.repo2'
+ source '#{file_uri_for(gem_repo2)}'
plugin 'foo'
end
RUBY
- ruby code, artifice: "compact_index", env: { "BUNDLER_VERSION" => Bundler::VERSION }
+ ruby code, :env => { "BUNDLER_VERSION" => Bundler::VERSION }
expect(local_plugin_gem("foo-1.0", "plugins.rb")).to exist
end
end
@@ -378,7 +323,7 @@ RSpec.describe "bundler plugin install" do
it "is installed when inside an app" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
gemfile ""
- bundle "plugin install foo --source https://gem.repo2"
+ bundle "plugin install foo --source #{file_uri_for(gem_repo2)}"
plugin_should_be_installed("foo")
expect(local_plugin_gem("foo-1.0")).to be_directory
@@ -401,7 +346,7 @@ RSpec.describe "bundler plugin install" do
end
# inside the app
- gemfile "source 'https://gem.repo2'\nplugin 'fubar'"
+ gemfile "source '#{file_uri_for(gem_repo2)}'\nplugin 'fubar'"
bundle "install"
update_repo2 do
@@ -419,7 +364,7 @@ RSpec.describe "bundler plugin install" do
end
# outside the app
- bundle "plugin install fubar --source https://gem.repo2", dir: tmp
+ bundle "plugin install fubar --source #{file_uri_for(gem_repo2)}", :dir => tmp
end
it "inside the app takes precedence over global plugin" do
@@ -428,7 +373,7 @@ RSpec.describe "bundler plugin install" do
end
it "outside the app global plugin is used" do
- bundle "shout", dir: tmp
+ bundle "shout", :dir => tmp
expect(out).to eq("global_one")
end
end
diff --git a/spec/bundler/plugins/list_spec.rb b/spec/bundler/plugins/list_spec.rb
index 30e3f82467..4a686415ad 100644
--- a/spec/bundler/plugins/list_spec.rb
+++ b/spec/bundler/plugins/list_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe "bundler plugin list" do
context "single plugin installed" do
it "shows plugin name with commands list" do
- bundle "plugin install foo --source https://gem.repo2"
+ bundle "plugin install foo --source #{file_uri_for(gem_repo2)}"
plugin_should_be_installed("foo")
bundle "plugin list"
@@ -49,7 +49,7 @@ RSpec.describe "bundler plugin list" do
context "multiple plugins installed" do
it "shows plugin names with commands list" do
- bundle "plugin install foo bar --source https://gem.repo2"
+ bundle "plugin install foo bar --source #{file_uri_for(gem_repo2)}"
plugin_should_be_installed("foo", "bar")
bundle "plugin list"
diff --git a/spec/bundler/plugins/source/example_spec.rb b/spec/bundler/plugins/source/example_spec.rb
index 32940bf849..9d153b6063 100644
--- a/spec/bundler/plugins/source/example_spec.rb
+++ b/spec/bundler/plugins/source/example_spec.rb
@@ -52,7 +52,7 @@ RSpec.describe "real source plugins" do
build_lib "a-path-gem"
gemfile <<-G
- source "https://gem.repo2" # plugin source
+ source "#{file_uri_for(gem_repo2)}" # plugin source
source "#{lib_path("a-path-gem-1.0")}", :type => :mpath do
gem "a-path-gem"
end
@@ -70,10 +70,6 @@ RSpec.describe "real source plugins" do
it "writes to lock file" do
bundle "install"
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "a-path-gem", "1.0"
- end
-
expect(lockfile).to eq <<~G
PLUGIN SOURCE
remote: #{lib_path("a-path-gem-1.0")}
@@ -82,7 +78,7 @@ RSpec.describe "real source plugins" do
a-path-gem (1.0)
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
PLATFORMS
@@ -90,7 +86,7 @@ RSpec.describe "real source plugins" do
DEPENDENCIES
a-path-gem!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -110,7 +106,7 @@ RSpec.describe "real source plugins" do
end
install_gemfile <<-G
- source "https://gem.repo2" # plugin source
+ source "#{file_uri_for(gem_repo2)}" # plugin source
source "#{lib_path("gem_with_bin-1.0")}", :type => :mpath do
gem "gem_with_bin"
end
@@ -170,7 +166,7 @@ RSpec.describe "real source plugins" do
a-path-gem (1.0)
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
PLATFORMS
@@ -323,8 +319,8 @@ RSpec.describe "real source plugins" do
build_git "ma-gitp-gem"
gemfile <<-G
- source "https://gem.repo2" # plugin source
- source "#{lib_path("ma-gitp-gem-1.0")}", :type => :gitp do
+ source "#{file_uri_for(gem_repo2)}" # plugin source
+ source "#{file_uri_for(lib_path("ma-gitp-gem-1.0"))}", :type => :gitp do
gem "ma-gitp-gem"
end
G
@@ -340,20 +336,16 @@ RSpec.describe "real source plugins" do
revision = revision_for(lib_path("ma-gitp-gem-1.0"))
bundle "install"
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "ma-gitp-gem", "1.0"
- end
-
expect(lockfile).to eq <<~G
PLUGIN SOURCE
- remote: #{lib_path("ma-gitp-gem-1.0")}
+ remote: #{file_uri_for(lib_path("ma-gitp-gem-1.0"))}
type: gitp
revision: #{revision}
specs:
ma-gitp-gem (1.0)
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
PLATFORMS
@@ -361,7 +353,7 @@ RSpec.describe "real source plugins" do
DEPENDENCIES
ma-gitp-gem!
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
G
@@ -372,14 +364,14 @@ RSpec.describe "real source plugins" do
revision = revision_for(lib_path("ma-gitp-gem-1.0"))
lockfile <<-G
PLUGIN SOURCE
- remote: #{lib_path("ma-gitp-gem-1.0")}
+ remote: #{file_uri_for(lib_path("ma-gitp-gem-1.0"))}
type: gitp
revision: #{revision}
specs:
ma-gitp-gem (1.0)
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
PLATFORMS
@@ -421,10 +413,10 @@ RSpec.describe "real source plugins" do
end
it "updates the deps on change in gemfile" do
- update_git "ma-gitp-gem", "1.1", path: lib_path("ma-gitp-gem-1.0"), gemspec: true
+ update_git "ma-gitp-gem", "1.1", :path => lib_path("ma-gitp-gem-1.0"), :gemspec => true
gemfile <<-G
- source "https://gem.repo2" # plugin source
- source "#{lib_path("ma-gitp-gem-1.0")}", :type => :gitp do
+ source "#{file_uri_for(gem_repo2)}" # plugin source
+ source "#{file_uri_for(lib_path("ma-gitp-gem-1.0"))}", :type => :gitp do
gem "ma-gitp-gem", "1.1"
end
G
@@ -440,7 +432,7 @@ RSpec.describe "real source plugins" do
ref = git.ref_for("main", 11)
install_gemfile <<-G
- source "https://gem.repo2" # plugin source
+ source "#{file_uri_for(gem_repo2)}" # plugin source
source '#{lib_path("foo-1.0")}', :type => :gitp do
gem "foo"
end
diff --git a/spec/bundler/plugins/source_spec.rb b/spec/bundler/plugins/source_spec.rb
index 995e50e653..14643e5c81 100644
--- a/spec/bundler/plugins/source_spec.rb
+++ b/spec/bundler/plugins/source_spec.rb
@@ -16,8 +16,8 @@ RSpec.describe "bundler source plugin" do
it "installs bundler-source-* gem when no handler for source is present" do
install_gemfile <<-G
- source "https://gem.repo2"
- source "#{lib_path("gitp")}", :type => :psource do
+ source "#{file_uri_for(gem_repo2)}"
+ source "#{file_uri_for(lib_path("gitp"))}", :type => :psource do
end
G
@@ -38,8 +38,8 @@ RSpec.describe "bundler source plugin" do
end
install_gemfile <<-G
- source "https://gem.repo2"
- source "#{lib_path("gitp")}", :type => :psource do
+ source "#{file_uri_for(gem_repo2)}"
+ source "#{file_uri_for(lib_path("gitp"))}", :type => :psource do
end
G
@@ -62,11 +62,11 @@ RSpec.describe "bundler source plugin" do
context "explicit presence in gemfile" do
before do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
plugin "another-psource"
- source "#{lib_path("gitp")}", :type => :psource do
+ source "#{file_uri_for(lib_path("gitp"))}", :type => :psource do
end
G
end
@@ -88,11 +88,11 @@ RSpec.describe "bundler source plugin" do
context "explicit default source" do
before do
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
plugin "bundler-source-psource"
- source "#{lib_path("gitp")}", :type => :psource do
+ source "#{file_uri_for(lib_path("gitp"))}", :type => :psource do
end
G
end
diff --git a/spec/bundler/plugins/uninstall_spec.rb b/spec/bundler/plugins/uninstall_spec.rb
index dedcc9f37c..8180241911 100644
--- a/spec/bundler/plugins/uninstall_spec.rb
+++ b/spec/bundler/plugins/uninstall_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe "bundler plugin uninstall" do
end
it "uninstalls specified plugins" do
- bundle "plugin install foo kung-foo --source https://gem.repo2"
+ bundle "plugin install foo kung-foo --source #{file_uri_for(gem_repo2)}"
plugin_should_be_installed("foo")
plugin_should_be_installed("kung-foo")
@@ -30,34 +30,9 @@ RSpec.describe "bundler plugin uninstall" do
plugin_should_not_be_installed("foo")
end
- it "doesn't wipe out path plugins" do
- build_lib "path_plugin" do |s|
- s.write "plugins.rb"
- end
- path = lib_path("path_plugin-1.0")
- expect(path).to be_a_directory
-
- allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
-
- install_gemfile <<-G
- source 'https://gem.repo2'
- plugin 'path_plugin', :path => "#{path}"
- gem 'myrack', '1.0.0'
- G
-
- plugin_should_be_installed("path_plugin")
- expect(Bundler::Plugin.index.plugin_path("path_plugin")).to eq path
-
- bundle "plugin uninstall path_plugin"
- expect(out).to include("Uninstalled plugin path_plugin")
- plugin_should_not_be_installed("path_plugin")
- # the actual gem still exists though
- expect(path).to be_a_directory
- end
-
describe "with --all" do
it "uninstalls all installed plugins" do
- bundle "plugin install foo kung-foo --source https://gem.repo2"
+ bundle "plugin install foo kung-foo --source #{file_uri_for(gem_repo2)}"
plugin_should_be_installed("foo")
plugin_should_be_installed("kung-foo")
diff --git a/spec/bundler/quality_spec.rb b/spec/bundler/quality_spec.rb
index c7fce17b62..a98815158e 100644
--- a/spec/bundler/quality_spec.rb
+++ b/spec/bundler/quality_spec.rb
@@ -40,14 +40,16 @@ RSpec.describe "The library itself" do
"#{filename} has spaces on the EOL on lines #{failing_lines.join(", ")}"
end
- def check_for_extraneous_quotes(filename)
+ def check_for_straneous_quotes(filename)
+ return if File.expand_path(filename) == __FILE__
+
failing_lines = []
each_line(filename) do |line, number|
- failing_lines << number + 1 if /\u{2019}/.match?(line)
+ failing_lines << number + 1 if /’/.match?(line)
end
return if failing_lines.empty?
- "#{filename} has an extraneous quote on lines #{failing_lines.join(", ")}"
+ "#{filename} has an straneous quote on lines #{failing_lines.join(", ")}"
end
def check_for_expendable_words(filename)
@@ -94,12 +96,12 @@ RSpec.describe "The library itself" do
expect(error_messages.compact).to be_well_formed
end
- it "has no extraneous quotes" do
+ it "has no estraneous quotes" do
exempt = /vendor|vcr_cassettes|LICENSE|rbreadline\.diff/
error_messages = []
tracked_files.each do |filename|
next if filename&.match?(exempt)
- error_messages << check_for_extraneous_quotes(filename)
+ error_messages << check_for_straneous_quotes(filename)
end
expect(error_messages.compact).to be_well_formed
end
@@ -191,10 +193,9 @@ RSpec.describe "The library itself" do
end
it "ships the correct set of files" do
- git_list = tracked_files.reject {|f| f.start_with?("spec/") }
+ git_list = git_ls_files(ruby_core? ? "lib/bundler lib/bundler.rb libexec/bundle*" : "lib exe CHANGELOG.md LICENSE.md README.md bundler.gemspec")
gem_list = loaded_gemspec.files
- gem_list.map! {|f| f.sub(%r{\Aexe/}, "libexec/") } if ruby_core?
expect(git_list).to match_array(gem_list)
end
@@ -236,24 +237,9 @@ RSpec.describe "The library itself" do
expect(all_bad_requires).to be_empty, "#{all_bad_requires.size} internal requires that should use `require_relative`: #{all_bad_requires}"
end
- # We don't want our artifice code to activate bundler, but it needs to use the
- # namespaced implementation of `Net::HTTP`. So we duplicate the file in
- # bundler that loads that.
- it "keeps vendored_net_http spec code in sync with the lib implementation" do
- lib_implementation_path = File.join(source_lib_dir, "bundler", "vendored_net_http.rb")
- expect(File.exist?(lib_implementation_path)).to be_truthy
- lib_code = File.read(lib_implementation_path)
-
- spec_implementation_path = File.join(spec_dir, "support", "vendored_net_http.rb")
- expect(File.exist?(spec_implementation_path)).to be_truthy
- spec_code = File.read(spec_implementation_path)
-
- expect(lib_code).to eq(spec_code)
- end
-
private
def each_line(filename, &block)
- File.readlines(filename, encoding: "UTF-8").each_with_index(&block)
+ File.readlines(filename, :encoding => "UTF-8").each_with_index(&block)
end
end
diff --git a/spec/bundler/realworld/dependency_api_spec.rb b/spec/bundler/realworld/dependency_api_spec.rb
new file mode 100644
index 0000000000..14f99bd262
--- /dev/null
+++ b/spec/bundler/realworld/dependency_api_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require_relative "../support/silent_logger"
+
+RSpec.describe "gemcutter's dependency API", :realworld => true do
+ context "when Gemcutter API takes too long to respond" do
+ before do
+ require_rack
+
+ port = find_unused_port
+ @server_uri = "http://127.0.0.1:#{port}"
+
+ require_relative "../support/artifice/endpoint_timeout"
+
+ @t = Thread.new do
+ server = Rack::Server.start(:app => EndpointTimeout,
+ :Host => "0.0.0.0",
+ :Port => port,
+ :server => "webrick",
+ :AccessLog => [],
+ :Logger => Spec::SilentLogger.new)
+ server.start
+ end
+ @t.run
+
+ wait_for_server("127.0.0.1", port)
+ bundle "config set timeout 1"
+ end
+
+ after do
+ Artifice.deactivate
+ @t.kill
+ @t.join
+ end
+
+ it "times out and falls back on the modern index" do
+ install_gemfile <<-G, :artifice => nil
+ source "#{@server_uri}"
+ gem "rack"
+ G
+
+ expect(out).to include("Fetching source index from #{@server_uri}/")
+ expect(the_bundle).to include_gems "rack 1.0.0"
+ end
+ end
+end
diff --git a/spec/bundler/realworld/double_check_spec.rb b/spec/bundler/realworld/double_check_spec.rb
index 0741560395..d7f28d10bb 100644
--- a/spec/bundler/realworld/double_check_spec.rb
+++ b/spec/bundler/realworld/double_check_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "double checking sources", realworld: true do
+RSpec.describe "double checking sources", :realworld => true do
it "finds already-installed gems" do
create_file("rails.gemspec", <<-RUBY)
Gem::Specification.new do |s|
@@ -25,9 +25,9 @@ RSpec.describe "double checking sources", realworld: true do
RUBY
cmd = <<-RUBY
- require "bundler"
+ require "#{entrypoint}"
require "#{spec_dir}/support/artifice/vcr"
- require "bundler/inline"
+ require "#{entrypoint}/inline"
gemfile(true) do
source "https://rubygems.org"
gem "rails", path: "."
diff --git a/spec/bundler/realworld/edgecases_spec.rb b/spec/bundler/realworld/edgecases_spec.rb
index fb434aba70..2f465b7b25 100644
--- a/spec/bundler/realworld/edgecases_spec.rb
+++ b/spec/bundler/realworld/edgecases_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "real world edgecases", realworld: true do
+RSpec.describe "real world edgecases", :realworld => true do
def rubygems_version(name, requirement)
ruby <<-RUBY
require "#{spec_dir}/support/artifice/vcr"
@@ -8,10 +8,9 @@ RSpec.describe "real world edgecases", realworld: true do
require "bundler/source/rubygems/remote"
require "bundler/fetcher"
rubygem = Bundler.ui.silence do
- remote = Bundler::Source::Rubygems::Remote.new(Gem::URI("https://rubygems.org"))
- source = Bundler::Source::Rubygems.new
- fetcher = Bundler::Fetcher.new(remote)
- index = fetcher.specs([#{name.dump}], source)
+ source = Bundler::Source::Rubygems::Remote.new(Bundler::URI("https://rubygems.org"))
+ fetcher = Bundler::Fetcher.new(source)
+ index = fetcher.specs([#{name.dump}], nil)
requirement = Gem::Requirement.create(#{requirement.dump})
index.search(#{name.dump}).select {|spec| requirement.satisfied_by?(spec.version) }.last
end
@@ -193,13 +192,24 @@ RSpec.describe "real world edgecases", realworld: true do
rails (~> 4.2.7.1)
L
- bundle "lock --update paperclip", env: { "BUNDLER_VERSION" => "1.99.0" }
+ bundle "lock --update paperclip", :env => { "BUNDLER_VERSION" => "1.99.0" }
expect(lockfile).to include(rubygems_version("paperclip", "~> 5.1.0"))
end
- it "outputs a helpful warning when gems have a gemspec with invalid `require_paths`" do
- install_gemfile <<-G, standalone: true, env: { "BUNDLE_FORCE_RUBY_PLATFORM" => "1" }
+ it "outputs a helpful error message when gems have invalid gemspecs", :rubygems => "< 3.3.16" do
+ install_gemfile <<-G, :standalone => true, :raise_on_error => false, :env => { "BUNDLE_FORCE_RUBY_PLATFORM" => "1" }
+ source 'https://rubygems.org'
+ gem "resque-scheduler", "2.2.0"
+ gem "redis-namespace", "1.6.0" # for a consistent resolution including ruby 2.3.0
+ gem "ruby2_keywords", "0.0.5"
+ G
+ expect(err).to include("You have one or more invalid gemspecs that need to be fixed.")
+ expect(err).to include("resque-scheduler 2.2.0 has an invalid gemspec")
+ end
+
+ it "outputs a helpful warning when gems have a gemspec with invalid `require_paths`", :rubygems => ">= 3.3.16" do
+ install_gemfile <<-G, :standalone => true, :env => { "BUNDLE_FORCE_RUBY_PLATFORM" => "1" }
source 'https://rubygems.org'
gem "resque-scheduler", "2.2.0"
gem "redis-namespace", "1.6.0" # for a consistent resolution including ruby 2.3.0
@@ -207,4 +217,300 @@ RSpec.describe "real world edgecases", realworld: true do
G
expect(err).to include("resque-scheduler 2.2.0 includes a gemspec with `require_paths` set to an array of arrays. Newer versions of this gem might've already fixed this").once
end
+
+ it "doesn't hang on big gemfile" do
+ skip "Only for ruby 2.7" unless RUBY_VERSION.start_with?("2.7")
+
+ gemfile <<~G
+ # frozen_string_literal: true
+
+ source "https://rubygems.org"
+
+ ruby "~> 2.7.7"
+
+ gem "rails"
+ gem "pg", ">= 0.18", "< 2.0"
+ gem "goldiloader"
+ gem "awesome_nested_set"
+ gem "circuitbox"
+ gem "passenger"
+ gem "globalid"
+ gem "rack-cors"
+ gem "rails-pg-extras"
+ gem "linear_regression_trend"
+ gem "rack-protection"
+ gem "pundit"
+ gem "remote_ip_proxy_scrubber"
+ gem "bcrypt"
+ gem "searchkick"
+ gem "excon"
+ gem "faraday_middleware-aws-sigv4"
+ gem "typhoeus"
+ gem "sidekiq"
+ gem "sidekiq-undertaker"
+ gem "sidekiq-cron"
+ gem "storext"
+ gem "appsignal"
+ gem "fcm"
+ gem "business_time"
+ gem "tzinfo"
+ gem "holidays"
+ gem "bigdecimal"
+ gem "progress_bar"
+ gem "redis"
+ gem "hiredis"
+ gem "state_machines"
+ gem "state_machines-audit_trail"
+ gem "state_machines-activerecord"
+ gem "interactor"
+ gem "ar_transaction_changes"
+ gem "redis-rails"
+ gem "seed_migration"
+ gem "lograge"
+ gem "graphiql-rails", group: :development
+ gem "graphql"
+ gem "pusher"
+ gem "rbnacl"
+ gem "jwt"
+ gem "json-schema"
+ gem "discard"
+ gem "money"
+ gem "strip_attributes"
+ gem "validates_email_format_of"
+ gem "audited"
+ gem "concurrent-ruby"
+ gem "with_advisory_lock"
+
+ group :test do
+ gem "rspec-sidekiq"
+ gem "simplecov", require: false
+ end
+
+ group :development, :test do
+ gem "byebug", platform: :mri
+ gem "guard"
+ gem "guard-bundler"
+ gem "guard-rspec"
+ gem "rb-fsevent"
+ gem "rspec_junit_formatter"
+ gem "rspec-collection_matchers"
+ gem "rspec-rails"
+ gem "rspec-retry"
+ gem "state_machines-rspec"
+ gem "dotenv-rails"
+ gem "database_cleaner-active_record"
+ gem "database_cleaner-redis"
+ gem "timecop"
+ end
+
+ gem "factory_bot_rails"
+ gem "faker"
+
+ group :development do
+ gem "listen"
+ gem "sql_queries_count"
+ gem "rubocop"
+ gem "rubocop-performance"
+ gem "rubocop-rspec"
+ gem "rubocop-rails"
+ gem "brakeman"
+ gem "bundler-audit"
+ gem "solargraph"
+ gem "annotate"
+ end
+ G
+
+ if Bundler.feature_flag.bundler_3_mode?
+ # Conflicts on bundler version, so we count attempts differently
+ bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }, :raise_on_error => false
+ expect(out.split("\n").grep(/backtracking to/).count).to eq(16)
+ else
+ bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }
+ expect(out).to include("Solution found after 7 attempts")
+ end
+ end
+
+ it "doesn't hang on tricky gemfile" do
+ skip "Only for ruby 2.7" unless RUBY_VERSION.start_with?("2.7")
+
+ gemfile <<~G
+ source 'https://rubygems.org'
+
+ group :development do
+ gem "puppet-module-posix-default-r2.7", '~> 0.3'
+ gem "puppet-module-posix-dev-r2.7", '~> 0.3'
+ gem "beaker-rspec"
+ gem "beaker-puppet"
+ gem "beaker-docker"
+ gem "beaker-puppet_install_helper"
+ gem "beaker-module_install_helper"
+ end
+ G
+
+ bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }
+
+ expect(out).to include("Solution found after 6 attempts")
+ end
+
+ it "doesn't hang on nix gemfile" do
+ skip "Only for ruby 3.0" unless RUBY_VERSION.start_with?("3.0")
+
+ gemfile <<~G
+ source "https://rubygems.org"
+
+ gem "addressable"
+ gem "atk"
+ gem "awesome_print"
+ gem "bacon"
+ gem "byebug"
+ gem "cairo"
+ gem "cairo-gobject"
+ gem "camping"
+ gem "charlock_holmes"
+ gem "cld3"
+ gem "cocoapods"
+ gem "cocoapods-acknowledgements"
+ gem "cocoapods-art"
+ gem "cocoapods-bin"
+ gem "cocoapods-browser"
+ gem "cocoapods-bugsnag"
+ gem "cocoapods-check"
+ gem "cocoapods-clean"
+ gem "cocoapods-clean_build_phases_scripts"
+ gem "cocoapods-core"
+ gem "cocoapods-coverage"
+ gem "cocoapods-deintegrate"
+ gem "cocoapods-dependencies"
+ gem "cocoapods-deploy"
+ gem "cocoapods-downloader"
+ gem "cocoapods-expert-difficulty"
+ gem "cocoapods-fix-react-native"
+ gem "cocoapods-generate"
+ gem "cocoapods-git_url_rewriter"
+ gem "cocoapods-keys"
+ gem "cocoapods-no-dev-schemes"
+ gem "cocoapods-open"
+ gem "cocoapods-packager"
+ gem "cocoapods-playgrounds"
+ gem "cocoapods-plugins"
+ gem "cocoapods-prune-localizations"
+ gem "cocoapods-rome"
+ gem "cocoapods-search"
+ gem "cocoapods-sorted-search"
+ gem "cocoapods-static-swift-framework"
+ gem "cocoapods-stats"
+ gem "cocoapods-tdfire-binary"
+ gem "cocoapods-testing"
+ gem "cocoapods-trunk"
+ gem "cocoapods-try"
+ gem "cocoapods-try-release-fix"
+ gem "cocoapods-update-if-you-dare"
+ gem "cocoapods-whitelist"
+ gem "cocoapods-wholemodule"
+ gem "coderay"
+ gem "concurrent-ruby"
+ gem "curb"
+ gem "curses"
+ gem "daemons"
+ gem "dep-selector-libgecode"
+ gem "digest-sha3"
+ gem "domain_name"
+ gem "do_sqlite3"
+ gem "ethon"
+ gem "eventmachine"
+ gem "excon"
+ gem "faraday"
+ gem "ffi"
+ gem "ffi-rzmq-core"
+ gem "fog-dnsimple"
+ gem "gdk_pixbuf2"
+ gem "gio2"
+ gem "gitlab-markup"
+ gem "glib2"
+ gem "gpgme"
+ gem "gtk2"
+ gem "hashie"
+ gem "highline"
+ gem "hike"
+ gem "hitimes"
+ gem "hpricot"
+ gem "httpclient"
+ gem "http-cookie"
+ gem "iconv"
+ gem "idn-ruby"
+ gem "jbuilder"
+ gem "jekyll"
+ gem "jmespath"
+ gem "jwt"
+ gem "libv8"
+ gem "libxml-ruby"
+ gem "magic"
+ gem "markaby"
+ gem "method_source"
+ gem "mini_magick"
+ gem "msgpack"
+ gem "mysql2"
+ gem "ncursesw"
+ gem "netrc"
+ gem "net-scp"
+ gem "net-ssh"
+ gem "nokogiri"
+ gem "opus-ruby"
+ gem "ovirt-engine-sdk"
+ gem "pango"
+ gem "patron"
+ gem "pcaprub"
+ gem "pg"
+ gem "pry"
+ gem "pry-byebug"
+ gem "pry-doc"
+ gem "public_suffix"
+ gem "puma"
+ gem "rails"
+ gem "rainbow"
+ gem "rbnacl"
+ gem "rb-readline"
+ gem "re2"
+ gem "redis"
+ gem "redis-rack"
+ gem "rest-client"
+ gem "rmagick"
+ gem "rpam2"
+ gem "rspec"
+ gem "rubocop"
+ gem "rubocop-performance"
+ gem "ruby-libvirt"
+ gem "ruby-lxc"
+ gem "ruby-progressbar"
+ gem "ruby-terminfo"
+ gem "ruby-vips"
+ gem "rubyzip"
+ gem "rugged"
+ gem "sassc"
+ gem "scrypt"
+ gem "semian"
+ gem "sequel"
+ gem "sequel_pg"
+ gem "simplecov"
+ gem "sinatra"
+ gem "slop"
+ gem "snappy"
+ gem "sqlite3"
+ gem "taglib-ruby"
+ gem "thrift"
+ gem "tilt"
+ gem "tiny_tds"
+ gem "treetop"
+ gem "typhoeus"
+ gem "tzinfo"
+ gem "unf_ext"
+ gem "uuid4r"
+ gem "whois"
+ gem "zookeeper"
+ G
+
+ bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }
+
+ expect(out).to include("Solution found after 4 attempts")
+ end
end
diff --git a/spec/bundler/realworld/ffi_spec.rb b/spec/bundler/realworld/ffi_spec.rb
index 5f40b43a0f..fdefc14091 100644
--- a/spec/bundler/realworld/ffi_spec.rb
+++ b/spec/bundler/realworld/ffi_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "loading dynamically linked library on a bundle exec context", realworld: true do
+RSpec.describe "loading dynamically linked library on a bundle exec context", :realworld => true do
it "passes ENV right after argv in memory" do
create_file "foo.rb", <<~RUBY
require 'ffi'
diff --git a/spec/bundler/realworld/fixtures/warbler/Gemfile b/spec/bundler/realworld/fixtures/warbler/Gemfile
index e4d3e8ea96..4fbf2d05a7 100644
--- a/spec/bundler/realworld/fixtures/warbler/Gemfile
+++ b/spec/bundler/realworld/fixtures/warbler/Gemfile
@@ -2,6 +2,6 @@
source "https://rubygems.org"
-gem "demo", path: "./demo"
-gem "jruby-jars", "~> 9.4"
+gem "demo", :path => "./demo"
+gem "jruby-jars", "~> 9.2"
gem "warbler", "~> 2.0"
diff --git a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
index b8171d28ce..8f29bd341f 100644
--- a/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
+++ b/spec/bundler/realworld/fixtures/warbler/Gemfile.lock
@@ -6,7 +6,7 @@ PATH
GEM
remote: https://rubygems.org/
specs:
- jruby-jars (9.4.8.0)
+ jruby-jars (9.2.16.0)
jruby-rack (1.1.21)
rake (13.0.1)
rubyzip (1.3.0)
@@ -23,8 +23,8 @@ PLATFORMS
DEPENDENCIES
demo!
- jruby-jars (~> 9.4)
+ jruby-jars (~> 9.2)
warbler (~> 2.0)
BUNDLED WITH
- 2.6.0.dev
+ 2.4.0.dev
diff --git a/spec/bundler/realworld/gemfile_source_header_spec.rb b/spec/bundler/realworld/gemfile_source_header_spec.rb
index f47ba3a855..60c0055a62 100644
--- a/spec/bundler/realworld/gemfile_source_header_spec.rb
+++ b/spec/bundler/realworld/gemfile_source_header_spec.rb
@@ -2,7 +2,7 @@
require_relative "../support/silent_logger"
-RSpec.describe "fetching dependencies with a mirrored source", realworld: true do
+RSpec.describe "fetching dependencies with a mirrored source", :realworld => true do
let(:mirror) { "https://server.example.org" }
let(:original) { "http://127.0.0.1:#{@port}" }
@@ -17,13 +17,13 @@ RSpec.describe "fetching dependencies with a mirrored source", realworld: true d
@t.join
end
- it "sets the 'X-Gemfile-Source' and 'User-Agent' headers and bundles successfully" do
+ it "sets the 'X-Gemfile-Source' header and bundles successfully" do
gemfile <<-G
source "#{mirror}"
gem 'weakling'
G
- bundle :install, artifice: nil
+ bundle :install, :artifice => nil
expect(out).to include("Installing weakling")
expect(out).to include("Bundle complete")
@@ -39,15 +39,13 @@ RSpec.describe "fetching dependencies with a mirrored source", realworld: true d
require_relative "../support/artifice/endpoint_mirror_source"
- require "rackup/server"
-
@t = Thread.new do
- Rackup::Server.start(app: EndpointMirrorSource,
- Host: "0.0.0.0",
- Port: @port,
- server: "webrick",
- AccessLog: [],
- Logger: Spec::SilentLogger.new)
+ Rack::Server.start(:app => EndpointMirrorSource,
+ :Host => "0.0.0.0",
+ :Port => @port,
+ :server => "webrick",
+ :AccessLog => [],
+ :Logger => Spec::SilentLogger.new)
end.run
wait_for_server("127.0.0.1", @port)
diff --git a/spec/bundler/realworld/git_spec.rb b/spec/bundler/realworld/git_spec.rb
index 9eff74f1c9..3d352626ea 100644
--- a/spec/bundler/realworld/git_spec.rb
+++ b/spec/bundler/realworld/git_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "github source", realworld: true do
+RSpec.describe "github source", :realworld => true do
it "properly fetches PRs" do
install_gemfile <<-G
source "https://rubygems.org"
diff --git a/spec/bundler/realworld/mirror_probe_spec.rb b/spec/bundler/realworld/mirror_probe_spec.rb
index 61312860d1..f2ce477c10 100644
--- a/spec/bundler/realworld/mirror_probe_spec.rb
+++ b/spec/bundler/realworld/mirror_probe_spec.rb
@@ -2,7 +2,7 @@
require_relative "../support/silent_logger"
-RSpec.describe "fetching dependencies with a not available mirror", realworld: true do
+RSpec.describe "fetching dependencies with a not available mirror", :realworld => true do
let(:mirror) { @mirror_uri }
let(:original) { @server_uri }
let(:server_port) { @server_port }
@@ -32,7 +32,7 @@ RSpec.describe "fetching dependencies with a not available mirror", realworld: t
gem 'weakling'
G
- bundle :install, artifice: nil
+ bundle :install, :artifice => nil
expect(out).to include("Installing weakling")
expect(out).to include("Bundle complete")
@@ -52,7 +52,7 @@ RSpec.describe "fetching dependencies with a not available mirror", realworld: t
gem 'weakling'
G
- bundle :install, artifice: nil
+ bundle :install, :artifice => nil
expect(out).to include("Installing weakling")
expect(out).to include("Bundle complete")
@@ -71,7 +71,7 @@ RSpec.describe "fetching dependencies with a not available mirror", realworld: t
gem 'weakling'
G
- bundle :install, artifice: nil, raise_on_error: false
+ bundle :install, :artifice => nil, :raise_on_error => false
expect(out).to include("Fetching source index from #{mirror}")
@@ -94,7 +94,7 @@ RSpec.describe "fetching dependencies with a not available mirror", realworld: t
gem 'weakling'
G
- bundle :install, artifice: nil, raise_on_error: false
+ bundle :install, :artifice => nil, :raise_on_error => false
expect(out).to include("Fetching source index from #{mirror}")
@@ -112,15 +112,13 @@ RSpec.describe "fetching dependencies with a not available mirror", realworld: t
require_relative "../support/artifice/endpoint"
- require "rackup/server"
-
@server_thread = Thread.new do
- Rackup::Server.start(app: Endpoint,
- Host: host,
- Port: @server_port,
- server: "webrick",
- AccessLog: [],
- Logger: Spec::SilentLogger.new)
+ Rack::Server.start(:app => Endpoint,
+ :Host => host,
+ :Port => @server_port,
+ :server => "webrick",
+ :AccessLog => [],
+ :Logger => Spec::SilentLogger.new)
end.run
wait_for_server(host, @server_port)
diff --git a/spec/bundler/realworld/parallel_spec.rb b/spec/bundler/realworld/parallel_spec.rb
index b57fdfd0ee..a1e4f83909 100644
--- a/spec/bundler/realworld/parallel_spec.rb
+++ b/spec/bundler/realworld/parallel_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.describe "parallel", realworld: true do
+RSpec.describe "parallel", :realworld => true do
it "installs" do
gemfile <<-G
source "https://rubygems.org"
@@ -9,7 +9,7 @@ RSpec.describe "parallel", realworld: true do
gem 'i18n', '~> 0.6.0' # Because 0.7+ requires Ruby 1.9.3+
G
- bundle :install, jobs: 4, env: { "DEBUG" => "1" }
+ bundle :install, :jobs => 4, :env => { "DEBUG" => "1" }
expect(out).to match(/[1-3]: /)
@@ -34,7 +34,7 @@ RSpec.describe "parallel", realworld: true do
gem 'i18n', '~> 0.6.0' # Because 0.7+ requires Ruby 1.9.3+
G
- bundle :update, jobs: 4, env: { "DEBUG" => "1" }, all: true
+ bundle :update, :jobs => 4, :env => { "DEBUG" => "1" }, :all => true
expect(out).to match(/[1-3]: /)
@@ -51,7 +51,7 @@ RSpec.describe "parallel", realworld: true do
gem "diff-lcs"
G
- bundle :install, standalone: true, jobs: 4
+ bundle :install, :standalone => true, :jobs => 4
ruby <<-RUBY
$:.unshift File.expand_path("bundle")
diff --git a/spec/bundler/realworld/slow_perf_spec.rb b/spec/bundler/realworld/slow_perf_spec.rb
index 32e266ff1b..aa8a48fcc7 100644
--- a/spec/bundler/realworld/slow_perf_spec.rb
+++ b/spec/bundler/realworld/slow_perf_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe "bundle install with complex dependencies", realworld: true do
+RSpec.describe "bundle install with complex dependencies", :realworld => true do
it "resolves quickly" do
gemfile <<-G
source 'https://rubygems.org'
@@ -11,8 +11,7 @@ RSpec.describe "bundle install with complex dependencies", realworld: true do
gem "mongoid", ">= 0.10.2"
G
- bundle "lock", env: { "DEBUG_RESOLVER" => "1" }
- expect(out).to include("Solution found after 1 attempts")
+ expect { bundle "lock" }.to take_less_than(18) # seconds
end
it "resolves quickly (case 2)" do
@@ -29,116 +28,6 @@ RSpec.describe "bundle install with complex dependencies", realworld: true do
gem 'rspec-rails'
G
- bundle "lock", env: { "DEBUG_RESOLVER" => "1" }
- expect(out).to include("Solution found after 1 attempts")
- end
-
- it "resolves big gemfile quickly" do
- gemfile <<~G
- # frozen_string_literal: true
-
- source "https://rubygems.org"
-
- gem "rails"
- gem "pg", ">= 0.18", "< 2.0"
- gem "goldiloader"
- gem "awesome_nested_set"
- gem "circuitbox"
- gem "passenger"
- gem "globalid"
- gem "rack-cors"
- gem "rails-pg-extras"
- gem "linear_regression_trend"
- gem "rack-protection"
- gem "pundit"
- gem "remote_ip_proxy_scrubber"
- gem "bcrypt"
- gem "searchkick"
- gem "excon"
- gem "faraday_middleware-aws-sigv4"
- gem "typhoeus"
- gem "sidekiq"
- gem "sidekiq-undertaker"
- gem "sidekiq-cron"
- gem "storext"
- gem "appsignal"
- gem "fcm"
- gem "business_time"
- gem "tzinfo"
- gem "holidays"
- gem "bigdecimal"
- gem "progress_bar"
- gem "redis"
- gem "hiredis"
- gem "state_machines"
- gem "state_machines-audit_trail"
- gem "state_machines-activerecord"
- gem "interactor"
- gem "ar_transaction_changes"
- gem "redis-rails"
- gem "seed_migration"
- gem "lograge"
- gem "graphiql-rails", group: :development
- gem "graphql"
- gem "pusher"
- gem "rbnacl"
- gem "jwt"
- gem "json-schema"
- gem "discard"
- gem "money"
- gem "strip_attributes"
- gem "validates_email_format_of"
- gem "audited"
- gem "concurrent-ruby"
- gem "with_advisory_lock"
-
- group :test do
- gem "rspec-sidekiq"
- gem "simplecov", require: false
- end
-
- group :development, :test do
- gem "byebug", platform: :mri
- gem "guard"
- gem "guard-bundler"
- gem "guard-rspec"
- gem "rb-fsevent"
- gem "rspec_junit_formatter"
- gem "rspec-collection_matchers"
- gem "rspec-rails"
- gem "rspec-retry"
- gem "state_machines-rspec"
- gem "dotenv-rails"
- gem "database_cleaner-active_record"
- gem "database_cleaner-redis"
- gem "timecop"
- end
-
- gem "factory_bot_rails"
- gem "faker"
-
- group :development do
- gem "listen"
- gem "sql_queries_count"
- gem "rubocop"
- gem "rubocop-performance"
- gem "rubocop-rspec"
- gem "rubocop-rails"
- gem "brakeman"
- gem "bundler-audit"
- gem "solargraph"
- gem "annotate"
- end
- G
-
- if Bundler.feature_flag.bundler_3_mode?
- bundle "lock", env: { "DEBUG_RESOLVER" => "1" }, raise_on_error: false
-
- expect(out).to include("backtracking").exactly(26).times
- else
- bundle "lock", env: { "DEBUG_RESOLVER" => "1" }
-
- expect(out).to include("Solution found after 10 attempts")
- end
+ expect { bundle "lock" }.to take_less_than(30) # seconds
end
end
diff --git a/spec/bundler/resolver/basic_spec.rb b/spec/bundler/resolver/basic_spec.rb
index f152907d35..f739f8c02b 100644
--- a/spec/bundler/resolver/basic_spec.rb
+++ b/spec/bundler/resolver/basic_spec.rb
@@ -6,15 +6,15 @@ RSpec.describe "Resolving" do
end
it "resolves a single gem" do
- dep "myrack"
+ dep "rack"
- should_resolve_as %w[myrack-1.1]
+ should_resolve_as %w[rack-1.1]
end
it "resolves a gem with dependencies" do
dep "actionpack"
- should_resolve_as %w[actionpack-2.3.5 activesupport-2.3.5 myrack-1.0]
+ should_resolve_as %w[actionpack-2.3.5 activesupport-2.3.5 rack-1.0]
end
it "resolves a conflicting index" do
@@ -84,7 +84,7 @@ RSpec.describe "Resolving" do
dep "activesupport", "= 3.0.0.beta"
dep "actionpack"
- should_resolve_as %w[activesupport-3.0.0.beta actionpack-3.0.0.beta myrack-1.1 myrack-mount-0.6]
+ should_resolve_as %w[activesupport-3.0.0.beta actionpack-3.0.0.beta rack-1.1 rack-mount-0.6]
end
it "prefers non-pre-releases when doing conservative updates" do
@@ -100,22 +100,13 @@ RSpec.describe "Resolving" do
end
it "raises an exception if a child dependency is not resolved" do
- @index = a_unresolvable_child_index
+ @index = a_unresovable_child_index
dep "chef_app_error"
expect do
resolve
end.to raise_error(Bundler::SolveFailure)
end
- it "does not try to re-resolve including prereleases if gems involved don't have prereleases" do
- @index = a_unresolvable_child_index
- dep "chef_app_error"
- expect(Bundler.ui).not_to receive(:debug).with("Retrying resolution...", any_args)
- expect do
- resolve
- end.to raise_error(Bundler::SolveFailure)
- end
-
it "raises an exception with the minimal set of conflicting dependencies" do
@index = build_index do
%w[0.9 1.0 2.0].each {|v| gem("a", v) }
@@ -313,10 +304,10 @@ RSpec.describe "Resolving" do
it "handles versions that redundantly depend on themselves" do
@index = build_index do
- gem "myrack", "3.0.0"
+ gem "rack", "3.0.0"
gem "standalone_migrations", "7.1.0" do
- dep "myrack", "~> 2.0"
+ dep "rack", "~> 2.0"
end
gem "standalone_migrations", "2.0.4" do
@@ -324,45 +315,22 @@ RSpec.describe "Resolving" do
end
gem "standalone_migrations", "1.0.13" do
- dep "myrack", ">= 0"
+ dep "rack", ">= 0"
end
end
- dep "myrack", "~> 3.0"
+ dep "rack", "~> 3.0"
dep "standalone_migrations"
- should_resolve_as %w[myrack-3.0.0 standalone_migrations-2.0.4]
+ should_resolve_as %w[rack-3.0.0 standalone_migrations-2.0.4]
end
it "ignores versions that incorrectly depend on themselves" do
@index = build_index do
- gem "myrack", "3.0.0"
-
- gem "standalone_migrations", "7.1.0" do
- dep "myrack", "~> 2.0"
- end
-
- gem "standalone_migrations", "2.0.4" do
- dep "standalone_migrations", ">= 2.0.5"
- end
-
- gem "standalone_migrations", "1.0.13" do
- dep "myrack", ">= 0"
- end
- end
-
- dep "myrack", "~> 3.0"
- dep "standalone_migrations"
-
- should_resolve_as %w[myrack-3.0.0 standalone_migrations-1.0.13]
- end
-
- it "does not ignore versions that incorrectly depend on themselves when dependency_api is not available" do
- @index = build_index do
- gem "myrack", "3.0.0"
+ gem "rack", "3.0.0"
gem "standalone_migrations", "7.1.0" do
- dep "myrack", "~> 2.0"
+ dep "rack", "~> 2.0"
end
gem "standalone_migrations", "2.0.4" do
@@ -370,13 +338,13 @@ RSpec.describe "Resolving" do
end
gem "standalone_migrations", "1.0.13" do
- dep "myrack", ">= 0"
+ dep "rack", ">= 0"
end
end
- dep "myrack", "~> 3.0"
+ dep "rack", "~> 3.0"
dep "standalone_migrations"
- should_resolve_without_dependency_api %w[myrack-3.0.0 standalone_migrations-2.0.4]
+ should_resolve_as %w[rack-3.0.0 standalone_migrations-1.0.13]
end
end
diff --git a/spec/bundler/resolver/platform_spec.rb b/spec/bundler/resolver/platform_spec.rb
index 8e51911bbd..a710dfcb28 100644
--- a/spec/bundler/resolver/platform_spec.rb
+++ b/spec/bundler/resolver/platform_spec.rb
@@ -82,7 +82,7 @@ RSpec.describe "Resolving platform craziness" do
should_resolve_as %w[foo-1.0.0-x64-mingw32]
end
- describe "on a linux platform" do
+ describe "on a linux platform", :rubygems => ">= 3.1.0.pre.1" do
# Ruby's platform is *-linux => platform's libc is glibc, so not musl
# Ruby's platform is *-linux-musl => platform's libc is musl, so not glibc
# Gem's platform is *-linux => gem is glibc + maybe musl compatible
@@ -381,16 +381,20 @@ RSpec.describe "Resolving platform craziness" do
should_resolve_as %w[win32-api-1.5.1-universal-mingw32]
end
- it "finds x64-mingw-ucrt gems" do
- platforms "x64-mingw-ucrt"
- dep "thin"
- should_resolve_as %w[thin-1.2.7-x64-mingw-ucrt]
+ if Gem.rubygems_version >= Gem::Version.new("3.2.28")
+ it "finds x64-mingw-ucrt gems" do
+ platforms "x64-mingw-ucrt"
+ dep "thin"
+ should_resolve_as %w[thin-1.2.7-x64-mingw-ucrt]
+ end
end
- it "finds universal-mingw gems on x64-mingw-ucrt", rubygems: ">= 3.3.18" do
- platform "x64-mingw-ucrt"
- dep "win32-api"
- should_resolve_as %w[win32-api-1.5.1-universal-mingw32]
+ if Gem.rubygems_version >= Gem::Version.new("3.3.18")
+ it "finds universal-mingw gems on x64-mingw-ucrt" do
+ platform "x64-mingw-ucrt"
+ dep "win32-api"
+ should_resolve_as %w[win32-api-1.5.1-universal-mingw32]
+ end
end
end
diff --git a/spec/bundler/runtime/env_helpers_spec.rb b/spec/bundler/runtime/env_helpers_spec.rb
deleted file mode 100644
index a1607cd057..0000000000
--- a/spec/bundler/runtime/env_helpers_spec.rb
+++ /dev/null
@@ -1,307 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "env helpers" do
- def bundle_exec_ruby(args, options = {})
- build_bundler_context options.dup
- bundle "exec '#{Gem.ruby}' #{args}", options
- end
-
- def build_bundler_context(options = {})
- bundle "config set path vendor/bundle", options.dup
- gemfile "source 'https://gem.repo1'"
- bundle "install", options
- end
-
- def run_bundler_script(env, script)
- system(env, "ruby", "-I#{lib_dir}", "-rbundler", script.to_s)
- end
-
- describe "Bundler.original_env" do
- it "should return the PATH present before bundle was activated" do
- create_file("source.rb", <<-RUBY)
- print Bundler.original_env["PATH"]
- RUBY
- path = `getconf PATH`.strip + "#{File::PATH_SEPARATOR}/foo"
- with_path_as(path) do
- bundle_exec_ruby(bundled_app("source.rb").to_s)
- expect(last_command.stdboth).to eq(path)
- end
- end
-
- it "should return the GEM_PATH present before bundle was activated" do
- create_file("source.rb", <<-RUBY)
- print Bundler.original_env['GEM_PATH']
- RUBY
- gem_path = ENV["GEM_PATH"] + "#{File::PATH_SEPARATOR}/foo"
- with_gem_path_as(gem_path) do
- bundle_exec_ruby(bundled_app("source.rb").to_s)
- expect(last_command.stdboth).to eq(gem_path)
- end
- end
-
- it "works with nested bundle exec invocations", :ruby_repo do
- create_file("exe.rb", <<-'RUBY')
- count = ARGV.first.to_i
- exit if count < 0
- STDERR.puts "#{count} #{ENV["PATH"].end_with?("#{File::PATH_SEPARATOR}/foo")}"
- if count == 2
- ENV["PATH"] = "#{ENV["PATH"]}#{File::PATH_SEPARATOR}/foo"
- end
- exec(Gem.ruby, __FILE__, (count - 1).to_s)
- RUBY
- path = `getconf PATH`.strip + File::PATH_SEPARATOR + File.dirname(Gem.ruby)
- with_path_as(path) do
- build_bundler_context
- bundle_exec_ruby("#{bundled_app("exe.rb")} 2")
- end
- expect(err).to eq <<-EOS.strip
-2 false
-1 true
-0 true
- EOS
- end
-
- it "removes variables that bundler added", :ruby_repo do
- # Simulate bundler has not yet been loaded
- ENV.replace(ENV.to_hash.delete_if {|k, _v| k.start_with?(Bundler::EnvironmentPreserver::BUNDLER_PREFIX) })
-
- original = ruby('puts ENV.to_a.map {|e| e.join("=") }.sort.join("\n")', artifice: "fail")
- create_file("source.rb", <<-RUBY)
- puts Bundler.original_env.to_a.map {|e| e.join("=") }.sort.join("\n")
- RUBY
- bundle_exec_ruby bundled_app("source.rb"), artifice: "fail"
- expect(out).to eq original
- end
- end
-
- shared_examples_for "an unbundling helper" do
- it "should delete BUNDLE_PATH" do
- create_file("source.rb", <<-RUBY)
- print #{modified_env}.has_key?('BUNDLE_PATH')
- RUBY
- ENV["BUNDLE_PATH"] = "./foo"
- bundle_exec_ruby bundled_app("source.rb")
- expect(last_command.stdboth).to include "false"
- end
-
- it "should remove absolute path to 'bundler/setup' from RUBYOPT even if it was present in original env" do
- create_file("source.rb", <<-RUBY)
- print #{modified_env}['RUBYOPT']
- RUBY
- setup_require = "-r#{lib_dir}/bundler/setup"
- ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 #{setup_require} #{ENV["RUBYOPT"]}"
- bundle_exec_ruby bundled_app("source.rb")
- expect(last_command.stdboth).not_to include(setup_require)
- end
-
- it "should remove relative path to 'bundler/setup' from RUBYOPT even if it was present in original env" do
- create_file("source.rb", <<-RUBY)
- print #{modified_env}['RUBYOPT']
- RUBY
- ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 -rbundler/setup #{ENV["RUBYOPT"]}"
- bundle_exec_ruby bundled_app("source.rb")
- expect(last_command.stdboth).not_to include("-rbundler/setup")
- end
-
- it "should delete BUNDLER_SETUP even if it was present in original env" do
- create_file("source.rb", <<-RUBY)
- print #{modified_env}.has_key?('BUNDLER_SETUP')
- RUBY
- ENV["BUNDLER_ORIG_BUNDLER_SETUP"] = system_gem_path("gems/bundler-#{Bundler::VERSION}/lib/bundler/setup").to_s
- bundle_exec_ruby bundled_app("source.rb")
- expect(last_command.stdboth).to include "false"
- end
-
- it "should restore RUBYLIB", :ruby_repo do
- create_file("source.rb", <<-RUBY)
- print #{modified_env}['RUBYLIB']
- RUBY
- ENV["RUBYLIB"] = lib_dir.to_s + File::PATH_SEPARATOR + "/foo"
- ENV["BUNDLER_ORIG_RUBYLIB"] = lib_dir.to_s + File::PATH_SEPARATOR + "/foo-original"
- bundle_exec_ruby bundled_app("source.rb")
- expect(last_command.stdboth).to include("/foo-original")
- end
-
- it "should restore the original MANPATH" do
- create_file("source.rb", <<-RUBY)
- print #{modified_env}['MANPATH']
- RUBY
- ENV["MANPATH"] = "/foo"
- ENV["BUNDLER_ORIG_MANPATH"] = "/foo-original"
- bundle_exec_ruby bundled_app("source.rb")
- expect(last_command.stdboth).to include("/foo-original")
- end
- end
-
- describe "Bundler.unbundled_env" do
- let(:modified_env) { "Bundler.unbundled_env" }
-
- it_behaves_like "an unbundling helper"
- end
-
- describe "Bundler.clean_env", bundler: 2 do
- let(:modified_env) { "Bundler.clean_env" }
-
- it_behaves_like "an unbundling helper"
- end
-
- describe "Bundler.with_original_env" do
- it "should set ENV to original_env in the block" do
- expected = Bundler.original_env
- actual = Bundler.with_original_env { ENV.to_hash }
- expect(actual).to eq(expected)
- end
-
- it "should restore the environment after execution" do
- Bundler.with_original_env do
- ENV["FOO"] = "hello"
- end
-
- expect(ENV).not_to have_key("FOO")
- end
- end
-
- describe "Bundler.with_clean_env", bundler: 2 do
- it "should set ENV to unbundled_env in the block" do
- expected = Bundler.unbundled_env
-
- actual = Bundler.ui.silence do
- Bundler.with_clean_env { ENV.to_hash }
- end
-
- expect(actual).to eq(expected)
- end
-
- it "should restore the environment after execution" do
- Bundler.ui.silence do
- Bundler.with_clean_env { ENV["FOO"] = "hello" }
- end
-
- expect(ENV).not_to have_key("FOO")
- end
- end
-
- describe "Bundler.with_unbundled_env" do
- it "should set ENV to unbundled_env in the block" do
- expected = Bundler.unbundled_env
- actual = Bundler.with_unbundled_env { ENV.to_hash }
- expect(actual).to eq(expected)
- end
-
- it "should restore the environment after execution" do
- Bundler.with_unbundled_env do
- ENV["FOO"] = "hello"
- end
-
- expect(ENV).not_to have_key("FOO")
- end
- end
-
- describe "Bundler.original_system" do
- before do
- create_file("source.rb", <<-'RUBY')
- Bundler.original_system("ruby", "-e", "exit(42) if ENV['BUNDLE_FOO'] == 'bar'")
-
- exit $?.exitstatus
- RUBY
- end
-
- it "runs system inside with_original_env" do
- run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
- expect($?.exitstatus).to eq(42)
- end
- end
-
- describe "Bundler.clean_system", bundler: 2 do
- before do
- create_file("source.rb", <<-'RUBY')
- Bundler.ui.silence { Bundler.clean_system("ruby", "-e", "exit(42) unless ENV['BUNDLE_FOO'] == 'bar'") }
-
- exit $?.exitstatus
- RUBY
- end
-
- it "runs system inside with_clean_env" do
- run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
- expect($?.exitstatus).to eq(42)
- end
- end
-
- describe "Bundler.unbundled_system" do
- before do
- create_file("source.rb", <<-'RUBY')
- Bundler.unbundled_system("ruby", "-e", "exit(42) unless ENV['BUNDLE_FOO'] == 'bar'")
-
- exit $?.exitstatus
- RUBY
- end
-
- it "runs system inside with_unbundled_env" do
- run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
- expect($?.exitstatus).to eq(42)
- end
- end
-
- describe "Bundler.original_exec" do
- before do
- create_file("source.rb", <<-'RUBY')
- Process.fork do
- exit Bundler.original_exec(%(test "\$BUNDLE_FOO" = "bar"))
- end
-
- _, status = Process.wait2
-
- exit(status.exitstatus)
- RUBY
- end
-
- it "runs exec inside with_original_env" do
- skip "Fork not implemented" if Gem.win_platform?
-
- run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
- expect($?.exitstatus).to eq(0)
- end
- end
-
- describe "Bundler.clean_exec", bundler: 2 do
- before do
- create_file("source.rb", <<-'RUBY')
- Process.fork do
- exit Bundler.ui.silence { Bundler.clean_exec(%(test "\$BUNDLE_FOO" = "bar")) }
- end
-
- _, status = Process.wait2
-
- exit(status.exitstatus)
- RUBY
- end
-
- it "runs exec inside with_clean_env" do
- skip "Fork not implemented" if Gem.win_platform?
-
- run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
- expect($?.exitstatus).to eq(1)
- end
- end
-
- describe "Bundler.unbundled_exec" do
- before do
- create_file("source.rb", <<-'RUBY')
- Process.fork do
- exit Bundler.unbundled_exec(%(test "\$BUNDLE_FOO" = "bar"))
- end
-
- _, status = Process.wait2
-
- exit(status.exitstatus)
- RUBY
- end
-
- it "runs exec inside with_clean_env" do
- skip "Fork not implemented" if Gem.win_platform?
-
- run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
- expect($?.exitstatus).to eq(1)
- end
- end
-end
diff --git a/spec/bundler/runtime/executable_spec.rb b/spec/bundler/runtime/executable_spec.rb
index b11c48539a..a11f547648 100644
--- a/spec/bundler/runtime/executable_spec.rb
+++ b/spec/bundler/runtime/executable_spec.rb
@@ -3,83 +3,83 @@
RSpec.describe "Running bin/* commands" do
before :each do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
it "runs the bundled command when in the bundle" do
- bundle "binstubs myrack"
+ bundle "binstubs rack"
- build_gem "myrack", "2.0", to_system: true do |s|
- s.executables = "myrackup"
+ build_gem "rack", "2.0", :to_system => true do |s|
+ s.executables = "rackup"
end
- gembin "myrackup"
+ gembin "rackup"
expect(out).to eq("1.0.0")
end
it "allows the location of the gem stubs to be specified" do
- bundle "binstubs myrack", path: "gbin"
+ bundle "binstubs rack", :path => "gbin"
expect(bundled_app("bin")).not_to exist
- expect(bundled_app("gbin/myrackup")).to exist
+ expect(bundled_app("gbin/rackup")).to exist
- gembin bundled_app("gbin/myrackup")
+ gembin bundled_app("gbin/rackup")
expect(out).to eq("1.0.0")
end
it "allows absolute paths as a specification of where to install bin stubs" do
- bundle "binstubs myrack", path: tmp("bin")
+ bundle "binstubs rack", :path => tmp("bin")
- gembin tmp("bin/myrackup")
+ gembin tmp("bin/rackup")
expect(out).to eq("1.0.0")
end
it "uses the default ruby install name when shebang is not specified" do
- bundle "binstubs myrack"
- expect(File.readlines(bundled_app("bin/myrackup")).first).to eq("#!/usr/bin/env #{RbConfig::CONFIG["ruby_install_name"]}\n")
+ bundle "binstubs rack"
+ expect(File.readlines(bundled_app("bin/rackup")).first).to eq("#!/usr/bin/env #{RbConfig::CONFIG["ruby_install_name"]}\n")
end
it "allows the name of the shebang executable to be specified" do
- bundle "binstubs myrack", shebang: "ruby-foo"
- expect(File.readlines(bundled_app("bin/myrackup")).first).to eq("#!/usr/bin/env ruby-foo\n")
+ bundle "binstubs rack", :shebang => "ruby-foo"
+ expect(File.readlines(bundled_app("bin/rackup")).first).to eq("#!/usr/bin/env ruby-foo\n")
end
it "runs the bundled command when out of the bundle" do
- bundle "binstubs myrack"
+ bundle "binstubs rack"
- build_gem "myrack", "2.0", to_system: true do |s|
- s.executables = "myrackup"
+ build_gem "rack", "2.0", :to_system => true do |s|
+ s.executables = "rackup"
end
- gembin "myrackup", dir: tmp
+ gembin "rackup", :dir => tmp
expect(out).to eq("1.0.0")
end
it "works with gems in path" do
- build_lib "myrack", path: lib_path("myrack") do |s|
- s.executables = "myrackup"
+ build_lib "rack", :path => lib_path("rack") do |s|
+ s.executables = "rackup"
end
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :path => "#{lib_path("myrack")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :path => "#{lib_path("rack")}"
G
- bundle "binstubs myrack"
+ bundle "binstubs rack"
- build_gem "myrack", "2.0", to_system: true do |s|
- s.executables = "myrackup"
+ build_gem "rack", "2.0", :to_system => true do |s|
+ s.executables = "rackup"
end
- gembin "myrackup"
+ gembin "rackup"
expect(out).to eq("1.0")
end
it "creates a bundle binstub" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bundler"
G
@@ -91,52 +91,52 @@ RSpec.describe "Running bin/* commands" do
it "does not generate bin stubs if the option was not specified" do
bundle "install"
- expect(bundled_app("bin/myrackup")).not_to exist
+ expect(bundled_app("bin/rackup")).not_to exist
end
- it "allows you to stop installing binstubs", bundler: "< 3" do
+ it "allows you to stop installing binstubs", :bundler => "< 3" do
skip "delete permission error" if Gem.win_platform?
bundle "install --binstubs bin/"
- bundled_app("bin/myrackup").rmtree
+ bundled_app("bin/rackup").rmtree
bundle "install --binstubs \"\""
- expect(bundled_app("bin/myrackup")).not_to exist
+ expect(bundled_app("bin/rackup")).not_to exist
bundle "config bin"
expect(out).to include("You have not configured a value for `bin`")
end
- it "remembers that the option was specified", bundler: "< 3" do
+ it "remembers that the option was specified", :bundler => "< 3" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
G
- bundle :install, binstubs: "bin"
+ bundle :install, :binstubs => "bin"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
- gem "myrack"
+ gem "rack"
G
bundle "install"
- expect(bundled_app("bin/myrackup")).to exist
+ expect(bundled_app("bin/rackup")).to exist
end
it "rewrites bins on binstubs (to maintain backwards compatibility)" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- create_file("bin/myrackup", "OMG")
+ create_file("bin/rackup", "OMG")
- bundle "binstubs myrack"
+ bundle "binstubs rack"
- expect(bundled_app("bin/myrackup").read).to_not eq("OMG")
+ expect(bundled_app("bin/rackup").read).to_not eq("OMG")
end
it "use BUNDLE_GEMFILE gemfile for binstub" do
@@ -148,8 +148,8 @@ RSpec.describe "Running bin/* commands" do
build_gem("bindir") {|s| s.executables = "foo" }
end
- gemfile("OtherGemfile", <<-G)
- source "https://gem.repo2"
+ create_file("OtherGemfile", <<-G)
+ source "#{file_uri_for(gem_repo2)}"
gem 'bindir'
G
diff --git a/spec/bundler/runtime/gem_tasks_spec.rb b/spec/bundler/runtime/gem_tasks_spec.rb
index 046300391b..b89fdf2cb1 100644
--- a/spec/bundler/runtime/gem_tasks_spec.rb
+++ b/spec/bundler/runtime/gem_tasks_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.describe "require 'bundler/gem_tasks'" do
- let(:define_local_gem_using_gem_tasks) do
+ before :each do
bundled_app("foo.gemspec").open("w") do |f|
f.write <<-GEMSPEC
Gem::Specification.new do |s|
@@ -20,54 +20,15 @@ RSpec.describe "require 'bundler/gem_tasks'" do
end
install_gemfile <<-G
- source "https://gem.repo1"
-
- gem "rake"
- G
- end
-
- let(:define_local_gem_with_extensions_using_gem_tasks_and_gemspec_dsl) do
- bundled_app("foo.gemspec").open("w") do |f|
- f.write <<-GEMSPEC
- Gem::Specification.new do |s|
- s.name = "foo"
- s.version = "1.0"
- s.summary = "dummy"
- s.author = "Perry Mason"
- s.extensions = "ext/extconf.rb"
- end
- GEMSPEC
- end
-
- bundled_app("Rakefile").open("w") do |f|
- f.write <<-RAKEFILE
- require "bundler/gem_tasks"
- RAKEFILE
- end
-
- Dir.mkdir bundled_app("ext")
-
- bundled_app("ext/extconf.rb").open("w") do |f|
- f.write <<-EXTCONF
- require "mkmf"
- File.write("Makefile", dummy_makefile($srcdir).join)
- EXTCONF
- end
-
- install_gemfile <<-G
- source "https://gem.repo1"
-
- gemspec
+ source "#{file_uri_for(gem_repo1)}"
gem "rake"
G
end
it "includes the relevant tasks" do
- define_local_gem_using_gem_tasks
-
with_gem_path_as(base_system_gem_path.to_s) do
- sys_exec "#{rake} -T", env: { "GEM_HOME" => system_gem_path.to_s }
+ sys_exec "#{rake} -T", :env => { "GEM_HOME" => system_gem_path.to_s }
end
expect(err).to be_empty
@@ -83,10 +44,8 @@ RSpec.describe "require 'bundler/gem_tasks'" do
end
it "defines a working `rake install` task", :ruby_repo do
- define_local_gem_using_gem_tasks
-
with_gem_path_as(base_system_gem_path.to_s) do
- sys_exec "#{rake} install", env: { "GEM_HOME" => system_gem_path.to_s }
+ sys_exec "#{rake} install", :env => { "GEM_HOME" => system_gem_path.to_s }
end
expect(err).to be_empty
@@ -96,21 +55,11 @@ RSpec.describe "require 'bundler/gem_tasks'" do
expect(err).to be_empty
end
- it "defines a working `rake install` task for local gems with extensions", :ruby_repo do
- define_local_gem_with_extensions_using_gem_tasks_and_gemspec_dsl
-
- bundle "exec rake install"
-
- expect(err).to be_empty
- end
-
context "rake build when path has spaces", :ruby_repo do
before do
- define_local_gem_using_gem_tasks
-
- spaced_bundled_app = tmp("bundled app")
+ spaced_bundled_app = tmp.join("bundled app")
FileUtils.cp_r bundled_app, spaced_bundled_app
- bundle "exec rake build", dir: spaced_bundled_app
+ bundle "exec rake build", :dir => spaced_bundled_app
end
it "still runs successfully" do
@@ -120,11 +69,9 @@ RSpec.describe "require 'bundler/gem_tasks'" do
context "rake build when path has brackets", :ruby_repo do
before do
- define_local_gem_using_gem_tasks
-
- bracketed_bundled_app = tmp("bundled[app")
+ bracketed_bundled_app = tmp.join("bundled[app")
FileUtils.cp_r bundled_app, bracketed_bundled_app
- bundle "exec rake build", dir: bracketed_bundled_app
+ bundle "exec rake build", :dir => bracketed_bundled_app
end
it "still runs successfully" do
@@ -134,14 +81,12 @@ RSpec.describe "require 'bundler/gem_tasks'" do
context "bundle path configured locally" do
before do
- define_local_gem_using_gem_tasks
-
bundle "config set path vendor/bundle"
end
it "works", :ruby_repo do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rake"
G
@@ -153,10 +98,8 @@ RSpec.describe "require 'bundler/gem_tasks'" do
end
it "adds 'pkg' to rake/clean's CLOBBER" do
- define_local_gem_using_gem_tasks
-
with_gem_path_as(base_system_gem_path.to_s) do
- sys_exec %(#{rake} -e 'load "Rakefile"; puts CLOBBER.inspect'), env: { "GEM_HOME" => system_gem_path.to_s }
+ sys_exec %(#{rake} -e 'load "Rakefile"; puts CLOBBER.inspect'), :env => { "GEM_HOME" => system_gem_path.to_s }
end
expect(out).to eq '["pkg"]'
end
diff --git a/spec/bundler/runtime/inline_spec.rb b/spec/bundler/runtime/inline_spec.rb
index 5be6eef7bd..29ef036828 100644
--- a/spec/bundler/runtime/inline_spec.rb
+++ b/spec/bundler/runtime/inline_spec.rb
@@ -2,9 +2,10 @@
RSpec.describe "bundler/inline#gemfile" do
def script(code, options = {})
- options[:artifice] ||= "compact_index"
- options[:env] ||= { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
- ruby("require 'bundler/inline'\n\n" + code, options)
+ requires = ["#{entrypoint}/inline"]
+ requires.unshift "#{spec_dir}/support/artifice/" + options.delete(:artifice) if options.key?(:artifice)
+ requires = requires.map {|r| "require '#{r}'" }.join("\n")
+ ruby("#{requires}\n\n" + code, options)
end
before :each do
@@ -27,7 +28,7 @@ RSpec.describe "bundler/inline#gemfile" do
s.write "lib/four.rb", "puts 'four'"
end
- build_lib "five", "1.0.0", no_default: true do |s|
+ build_lib "five", "1.0.0", :no_default => true do |s|
s.write "lib/mofive.rb", "puts 'five'"
end
@@ -47,7 +48,7 @@ RSpec.describe "bundler/inline#gemfile" do
it "requires the gems" do
script <<-RUBY
gemfile do
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "two"
end
@@ -56,9 +57,9 @@ RSpec.describe "bundler/inline#gemfile" do
expect(out).to eq("two")
- script <<-RUBY, raise_on_error: false
+ script <<-RUBY, :raise_on_error => false
gemfile do
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "eleven"
end
@@ -72,14 +73,14 @@ RSpec.describe "bundler/inline#gemfile" do
script <<-RUBY
gemfile(true) do
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
end
RUBY
- expect(out).to include("Myrack's post install message")
+ expect(out).to include("Rack's post install message")
- script <<-RUBY, artifice: "endpoint"
+ script <<-RUBY, :artifice => "endpoint"
gemfile(true) do
source "https://notaserver.com"
gem "activesupport", :require => true
@@ -88,13 +89,13 @@ RSpec.describe "bundler/inline#gemfile" do
expect(out).to include("Installing activesupport")
err_lines = err.split("\n")
- err_lines.reject! {|line| line =~ /\.rb:\d+: warning: / }
+ err_lines.reject! {|line| line =~ /\.rb:\d+: warning: / } unless RUBY_VERSION < "2.7"
expect(err_lines).to be_empty
end
it "lets me use my own ui object" do
- script <<-RUBY, artifice: "endpoint"
- require 'bundler'
+ script <<-RUBY, :artifice => "endpoint"
+ require '#{entrypoint}'
class MyBundlerUI < Bundler::UI::Shell
def confirm(msg, newline = nil)
puts "CONFIRMED!"
@@ -112,8 +113,8 @@ RSpec.describe "bundler/inline#gemfile" do
end
it "has an option for quiet installation" do
- script <<-RUBY, artifice: "endpoint"
- require 'bundler/inline'
+ script <<-RUBY, :artifice => "endpoint"
+ require '#{entrypoint}/inline'
gemfile(true, :quiet => true) do
source "https://notaserver.com"
@@ -125,7 +126,7 @@ RSpec.describe "bundler/inline#gemfile" do
end
it "raises an exception if passed unknown arguments" do
- script <<-RUBY, raise_on_error: false
+ script <<-RUBY, :raise_on_error => false
gemfile(true, :arglebargle => true) do
path "#{lib_path}"
gem "two"
@@ -139,10 +140,10 @@ RSpec.describe "bundler/inline#gemfile" do
it "does not mutate the option argument" do
script <<-RUBY
- require 'bundler'
+ require '#{entrypoint}'
options = { :ui => Bundler::UI::Shell.new }
gemfile(false, options) do
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "two"
end
@@ -156,11 +157,11 @@ RSpec.describe "bundler/inline#gemfile" do
it "installs quietly if necessary when the install option is not set" do
script <<-RUBY
gemfile do
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
end
- puts MYRACK
+ puts RACK
RUBY
expect(out).to eq("1.0.0")
@@ -169,21 +170,21 @@ RSpec.describe "bundler/inline#gemfile" do
it "installs subdependencies quietly if necessary when the install option is not set" do
build_repo4 do
- build_gem "myrack" do |s|
- s.add_dependency "myrackdep"
+ build_gem "rack" do |s|
+ s.add_dependency "rackdep"
end
- build_gem "myrackdep", "1.0.0"
+ build_gem "rackdep", "1.0.0"
end
- script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ script <<-RUBY
gemfile do
- source "https://gem.repo4"
- gem "myrack"
+ source "#{file_uri_for(gem_repo4)}"
+ gem "rack"
end
- require "myrackdep"
- puts MYRACKDEP
+ require "rackdep"
+ puts RACKDEP
RUBY
expect(out).to eq("1.0.0")
@@ -192,23 +193,23 @@ RSpec.describe "bundler/inline#gemfile" do
it "installs subdependencies quietly if necessary when the install option is not set, and multiple sources used" do
build_repo4 do
- build_gem "myrack" do |s|
- s.add_dependency "myrackdep"
+ build_gem "rack" do |s|
+ s.add_dependency "rackdep"
end
- build_gem "myrackdep", "1.0.0"
+ build_gem "rackdep", "1.0.0"
end
- script <<-RUBY, artifice: "compact_index_extra_api"
+ script <<-RUBY
gemfile do
- source "https://test.repo"
- source "https://test.repo/extra" do
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ source "#{file_uri_for(gem_repo4)}" do
+ gem "rack"
end
end
- require "myrackdep"
- puts MYRACKDEP
+ require "rackdep"
+ puts RACKDEP
RUBY
expect(out).to eq("1.0.0")
@@ -220,7 +221,7 @@ RSpec.describe "bundler/inline#gemfile" do
baz_ref = build_git("baz", "2.0.0").ref_for("HEAD")
script <<-RUBY
gemfile do
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => #{lib_path("foo-1.0.0").to_s.dump}
gem "baz", :git => #{lib_path("baz-2.0.0").to_s.dump}, :ref => #{baz_ref.dump}
end
@@ -237,14 +238,14 @@ RSpec.describe "bundler/inline#gemfile" do
script <<-RUBY
gemfile do
path "#{lib_path}" do
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "two"
end
end
gemfile do
path "#{lib_path}" do
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "four"
end
end
@@ -255,73 +256,73 @@ RSpec.describe "bundler/inline#gemfile" do
end
it "doesn't reinstall already installed gems" do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
script <<-RUBY
- require 'bundler'
+ require '#{entrypoint}'
ui = Bundler::UI::Shell.new
ui.level = "confirm"
gemfile(true, ui: ui) do
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
- gem "myrack"
+ gem "rack"
end
RUBY
expect(out).to include("Installing activesupport")
- expect(out).not_to include("Installing myrack")
+ expect(out).not_to include("Installing rack")
expect(err).to be_empty
end
it "installs gems in later gemfile calls" do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
script <<-RUBY
- require 'bundler'
+ require '#{entrypoint}'
ui = Bundler::UI::Shell.new
ui.level = "confirm"
gemfile(true, ui: ui) do
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
end
gemfile(true, ui: ui) do
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
end
RUBY
expect(out).to include("Installing activesupport")
- expect(out).not_to include("Installing myrack")
+ expect(out).not_to include("Installing rack")
expect(err).to be_empty
end
it "doesn't reinstall already installed gems in later gemfile calls" do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
script <<-RUBY
- require 'bundler'
+ require '#{entrypoint}'
ui = Bundler::UI::Shell.new
ui.level = "confirm"
gemfile(true, ui: ui) do
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
end
gemfile(true, ui: ui) do
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
end
RUBY
expect(out).to include("Installing activesupport")
- expect(out).not_to include("Installing myrack")
+ expect(out).not_to include("Installing rack")
expect(err).to be_empty
end
it "installs gems with native extensions in later gemfile calls" do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
build_git "foo" do |s|
s.add_dependency "rake"
@@ -338,16 +339,16 @@ RSpec.describe "bundler/inline#gemfile" do
end
script <<-RUBY
- require 'bundler'
+ require '#{entrypoint}'
ui = Bundler::UI::Shell.new
ui.level = "confirm"
gemfile(true, ui: ui) do
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
end
gemfile(true, ui: ui) do
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
end
@@ -385,11 +386,11 @@ RSpec.describe "bundler/inline#gemfile" do
script <<-RUBY
gemfile do
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
end
- puts MYRACK
+ puts RACK
RUBY
expect(err).to be_empty
@@ -419,37 +420,37 @@ RSpec.describe "bundler/inline#gemfile" do
script <<-RUBY
gemfile(true) do
- source "https://gem.repo1"
- gem "rake", "#{rake_version}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rake", "~> 13.0"
end
RUBY
- expect(out).to include("Installing rake #{rake_version}")
+ expect(out).to include("Installing rake 13.0")
expect(out).not_to include("was 11.3.0")
expect(err).to be_empty
end
it "installs inline gems when frozen is set" do
- script <<-RUBY, env: { "BUNDLE_FROZEN" => "true", "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
+ script <<-RUBY, :env => { "BUNDLE_FROZEN" => "true" }
gemfile do
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
end
- puts MYRACK
+ puts RACK
RUBY
expect(last_command.stderr).to be_empty
end
it "installs inline gems when deployment is set" do
- script <<-RUBY, env: { "BUNDLE_DEPLOYMENT" => "true", "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
+ script <<-RUBY, :env => { "BUNDLE_DEPLOYMENT" => "true" }
gemfile do
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
end
- puts MYRACK
+ puts RACK
RUBY
expect(last_command.stderr).to be_empty
@@ -460,11 +461,11 @@ RSpec.describe "bundler/inline#gemfile" do
script <<-RUBY
gemfile do
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
end
- puts MYRACK
+ puts RACK
RUBY
expect(err).to be_empty
@@ -475,11 +476,11 @@ RSpec.describe "bundler/inline#gemfile" do
script <<-RUBY
gemfile do
- source "https://gem.repo1"
- gem "myrack" # has the myrackup executable
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack" # has the rackup executable
end
- puts MYRACK
+ puts RACK
RUBY
expect(last_command).to be_success
expect(out).to eq "1.0.0"
@@ -487,14 +488,14 @@ RSpec.describe "bundler/inline#gemfile" do
context "when BUNDLE_PATH is set" do
it "installs inline gems to the system path regardless" do
- script <<-RUBY, env: { "BUNDLE_PATH" => "./vendor/inline", "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
+ script <<-RUBY, :env => { "BUNDLE_PATH" => "./vendor/inline" }
gemfile(true) do
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
end
RUBY
expect(last_command).to be_success
- expect(system_gem_path("gems/myrack-1.0.0")).to exist
+ expect(system_gem_path("gems/rack-1.0.0")).to exist
end
end
@@ -503,8 +504,8 @@ RSpec.describe "bundler/inline#gemfile" do
script <<-RUBY
gemfile(true) do
- source "https://gem.repo1"
- gem "myrack", platform: :jruby
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", platform: :jruby
end
RUBY
@@ -516,21 +517,21 @@ RSpec.describe "bundler/inline#gemfile" do
script <<-RUBY
gemfile do
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
end
RUBY
expect(last_command).to be_success
- expect(system_gem_path("gems/myrack-1.0.0")).to exist
+ expect(system_gem_path("gems/rack-1.0.0")).to exist
end
it "preserves previous BUNDLE_GEMFILE value" do
ENV["BUNDLE_GEMFILE"] = ""
script <<-RUBY
gemfile do
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
end
puts "BUNDLE_GEMFILE is empty" if ENV["BUNDLE_GEMFILE"].empty?
@@ -546,8 +547,8 @@ RSpec.describe "bundler/inline#gemfile" do
ENV["BUNDLE_GEMFILE"] = nil
script <<-RUBY
gemfile do
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
end
puts "BUNDLE_GEMFILE is empty" if ENV["BUNDLE_GEMFILE"].empty?
@@ -575,9 +576,9 @@ RSpec.describe "bundler/inline#gemfile" do
s.write "lib/foo.rb", foo_code
end
- script <<-RUBY, dir: tmp("path_without_gemfile"), env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
+ script <<-RUBY, :dir => tmp("path_without_gemfile")
gemfile do
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
path "#{lib_path}" do
gem "foo", require: false
end
@@ -590,143 +591,36 @@ RSpec.describe "bundler/inline#gemfile" do
expect(err).to be_empty
end
- it "when requiring fileutils after does not show redefinition warnings" do
+ it "when requiring fileutils after does not show redefinition warnings", :realworld do
+ dependency_installer_loads_fileutils = ruby "require 'rubygems/dependency_installer'; puts $LOADED_FEATURES.grep(/fileutils/)", :raise_on_error => false
+ skip "does not work if rubygems/dependency_installer loads fileutils, which happens until rubygems 3.2.0" unless dependency_installer_loads_fileutils.empty?
+
+ skip "pathname does not install cleanly on this ruby" if RUBY_VERSION < "2.7.0"
+
Dir.mkdir tmp("path_without_gemfile")
- default_fileutils_version = ruby "gem 'fileutils', '< 999999'; require 'fileutils'; puts FileUtils::VERSION", raise_on_error: false
+ default_fileutils_version = ruby "gem 'fileutils', '< 999999'; require 'fileutils'; puts FileUtils::VERSION", :raise_on_error => false
skip "fileutils isn't a default gem" if default_fileutils_version.empty?
realworld_system_gems "fileutils --version 1.4.1"
realworld_system_gems "pathname --version 0.2.0"
- script <<-RUBY, dir: tmp("path_without_gemfile"), env: { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s, "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }
- require "bundler/inline"
-
- gemfile(true) do
- source "https://gem.repo2"
- end
-
- require "fileutils"
- RUBY
-
- expect(err).to eq("The Gemfile specifies no dependencies")
- end
-
- it "does not load default timeout" do
- default_timeout_version = ruby "gem 'timeout', '< 999999'; require 'timeout'; puts Timeout::VERSION", raise_on_error: false
- skip "timeout isn't a default gem" if default_timeout_version.empty?
-
- # This only works on RubyGems 3.5.0 or higher
- ruby "require 'rubygems/timeout'", raise_on_error: false
- skip "rubygems under test does not yet vendor timeout" unless last_command.success?
-
- build_repo4 do
- build_gem "timeout", "999"
- end
-
- script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
- require "bundler/inline"
-
- gemfile(true) do
- source "https://gem.repo4"
-
- gem "timeout"
- end
- RUBY
-
- expect(out).to include("Installing timeout 999")
- end
-
- it "does not upcase ENV" do
- script <<-RUBY
- require 'bundler/inline'
-
- ENV['Test_Variable'] = 'value string'
- puts("before: \#{ENV.each_key.select { |key| key.match?(/test_variable/i) }}")
-
- gemfile do
- source "https://gem.repo1"
- end
-
- puts("after: \#{ENV.each_key.select { |key| key.match?(/test_variable/i) }}")
- RUBY
-
- expect(out).to include("before: [\"Test_Variable\"]")
- expect(out).to include("after: [\"Test_Variable\"]")
- end
-
- it "does not create a lockfile" do
- script <<-RUBY
- require 'bundler/inline'
-
- gemfile do
- source "https://gem.repo1"
- end
-
- puts Dir.glob("Gemfile.lock")
- RUBY
+ realworld_system_gems "timeout uri" # this spec uses net/http which requires these default gems
- expect(out).to be_empty
- end
+ # on prerelease rubies, a required_rubygems_version constraint is added by RubyGems to the resolution, causing Molinillo to load the `set` gem
+ realworld_system_gems "set --version 1.0.3" if Gem.ruby_version.prerelease?
- it "does not reset ENV" do
- script <<-RUBY
- require 'bundler/inline'
-
- gemfile do
- source "https://gem.repo1"
-
- ENV['FOO'] = 'bar'
- end
-
- puts ENV['FOO']
- RUBY
-
- expect(out).to eq("bar")
- end
-
- it "does not load specified version of psych and stringio", :ruby_repo do
- build_repo4 do
- build_gem "psych", "999"
- build_gem "stringio", "999"
- end
-
- script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
+ script <<-RUBY, :dir => tmp("path_without_gemfile"), :env => { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }
require "bundler/inline"
gemfile(true) do
- source "https://gem.repo4"
-
- gem "psych"
- gem "stringio"
+ source "#{file_uri_for(gem_repo2)}"
end
- RUBY
-
- expect(out).to include("Installing psych 999")
- expect(out).to include("Installing stringio 999")
- expect(out).to include("The psych gem was resolved to 999")
- expect(out).to include("The stringio gem was resolved to 999")
- end
-
- it "leaves a lockfile in the same directory as the inline script alone" do
- install_gemfile <<~G
- source "https://gem.repo1"
- gem "foo"
- G
-
- original_lockfile = lockfile
- script <<-RUBY, env: { "BUNDLER_SPEC_GEM_REPO" => gem_repo1.to_s }
- require "bundler/inline"
-
- gemfile(true) do
- source "https://gem.repo1"
-
- gem "myrack"
- end
+ require "fileutils"
RUBY
- expect(lockfile).to eq(original_lockfile)
+ expect(err).to eq("The Gemfile specifies no dependencies")
end
end
diff --git a/spec/bundler/runtime/load_spec.rb b/spec/bundler/runtime/load_spec.rb
index 15f3d0eb5b..96a22a46cc 100644
--- a/spec/bundler/runtime/load_spec.rb
+++ b/spec/bundler/runtime/load_spec.rb
@@ -4,18 +4,18 @@ RSpec.describe "Bundler.load" do
describe "with a gemfile" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
allow(Bundler::SharedHelpers).to receive(:pwd).and_return(bundled_app)
end
it "provides a list of the env dependencies" do
- expect(Bundler.load.dependencies).to have_dep("myrack", ">= 0")
+ expect(Bundler.load.dependencies).to have_dep("rack", ">= 0")
end
it "provides a list of the resolved gems" do
- expect(Bundler.load.gems).to have_gem("myrack-1.0.0", "bundler-#{Bundler::VERSION}")
+ expect(Bundler.load.gems).to have_gem("rack-1.0.0", "bundler-#{Bundler::VERSION}")
end
it "ignores blank BUNDLE_GEMFILEs" do
@@ -28,20 +28,20 @@ RSpec.describe "Bundler.load" do
describe "with a gems.rb file" do
before(:each) do
- gemfile "gems.rb", <<-G
- source "https://gem.repo1"
- gem "myrack"
+ create_file "gems.rb", <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
bundle :install
allow(Bundler::SharedHelpers).to receive(:pwd).and_return(bundled_app)
end
it "provides a list of the env dependencies" do
- expect(Bundler.load.dependencies).to have_dep("myrack", ">= 0")
+ expect(Bundler.load.dependencies).to have_dep("rack", ">= 0")
end
it "provides a list of the resolved gems" do
- expect(Bundler.load.gems).to have_gem("myrack-1.0.0", "bundler-#{Bundler::VERSION}")
+ expect(Bundler.load.gems).to have_gem("rack-1.0.0", "bundler-#{Bundler::VERSION}")
end
end
@@ -76,16 +76,16 @@ RSpec.describe "Bundler.load" do
describe "when called twice" do
it "doesn't try to load the runtime twice" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "activesupport", :group => :test
G
ruby <<-RUBY
- require "bundler"
+ require "#{entrypoint}"
Bundler.setup :default
Bundler.require :default
- puts MYRACK
+ puts RACK
begin
require "activesupport"
rescue LoadError
@@ -100,7 +100,7 @@ RSpec.describe "Bundler.load" do
describe "not hurting brittle rubygems" do
it "does not inject #source into the generated YAML of the gem specs" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activerecord"
G
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
diff --git a/spec/bundler/runtime/platform_spec.rb b/spec/bundler/runtime/platform_spec.rb
index 007733d3de..a9933f90e9 100644
--- a/spec/bundler/runtime/platform_spec.rb
+++ b/spec/bundler/runtime/platform_spec.rb
@@ -3,26 +3,26 @@
RSpec.describe "Bundler.setup with multi platform stuff" do
it "raises a friendly error when gems are missing locally" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0)
+ rack (1.0)
PLATFORMS
#{local_tag}
DEPENDENCIES
- myrack
+ rack
G
ruby <<-R
begin
- require 'bundler'
+ require '#{entrypoint}'
Bundler.ui.silence { Bundler.setup }
rescue Bundler::GemNotFound => e
puts "WIN"
@@ -35,7 +35,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
it "will resolve correctly on the current platform when the lockfile was targeted for a different one" do
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
nokogiri (1.4.2-java)
weakling (= 0.0.3)
@@ -48,63 +48,55 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
nokogiri
G
- simulate_platform "x86-darwin-10" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "nokogiri"
- G
+ simulate_platform "x86-darwin-10"
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "nokogiri"
+ G
- expect(the_bundle).to include_gems "nokogiri 1.4.2"
- end
+ expect(the_bundle).to include_gems "nokogiri 1.4.2"
end
it "will keep both platforms when both ruby and a specific ruby platform are locked and the bundle is unlocked" do
build_repo4 do
build_gem "nokogiri", "1.11.1" do |s|
s.add_dependency "mini_portile2", "~> 2.5.0"
- s.add_dependency "racca", "~> 1.5.2"
+ s.add_dependency "racc", "~> 1.5.2"
end
build_gem "nokogiri", "1.11.1" do |s|
s.platform = Bundler.local_platform
- s.add_dependency "racca", "~> 1.4"
+ s.add_dependency "racc", "~> 1.4"
end
build_gem "mini_portile2", "2.5.0"
- build_gem "racca", "1.5.2"
- end
-
- checksums = checksums_section do |c|
- c.checksum gem_repo4, "mini_portile2", "2.5.0"
- c.checksum gem_repo4, "nokogiri", "1.11.1"
- c.checksum gem_repo4, "nokogiri", "1.11.1", Bundler.local_platform
- c.checksum gem_repo4, "racca", "1.5.2"
+ build_gem "racc", "1.5.2"
end
good_lockfile = <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
mini_portile2 (2.5.0)
nokogiri (1.11.1)
mini_portile2 (~> 2.5.0)
- racca (~> 1.5.2)
+ racc (~> 1.5.2)
nokogiri (1.11.1-#{Bundler.local_platform})
- racca (~> 1.4)
- racca (1.5.2)
+ racc (~> 1.4)
+ racc (1.5.2)
PLATFORMS
#{lockfile_platforms("ruby")}
DEPENDENCIES
nokogiri (~> 1.11)
- #{checksums}
+
BUNDLED WITH
#{Bundler::VERSION}
L
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "nokogiri", "~> 1.11"
G
@@ -126,13 +118,13 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "https://gems.repo4"
gem "nokogiri"
G
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: https://gems.repo4/
specs:
nokogiri (1.11.1)
@@ -146,7 +138,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
#{Bundler::VERSION}
L
- bundle "install"
+ bundle "install", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
expect(out).to include("Fetching nokogiri 1.11.1")
expect(the_bundle).to include_gems "nokogiri 1.11.1"
@@ -155,13 +147,13 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
it "will use the java platform if both generic java and generic ruby platforms are locked", :jruby_only do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "nokogiri"
G
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
nokogiri (1.4.2)
nokogiri (1.4.2-java)
@@ -182,13 +174,13 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
bundle "install"
expect(out).to include("Fetching nokogiri 1.4.2 (java)")
- expect(the_bundle).to include_gems "nokogiri 1.4.2 java"
+ expect(the_bundle).to include_gems "nokogiri 1.4.2 JAVA"
end
it "will add the resolve for the current platform" do
lockfile <<-G
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
nokogiri (1.4.2-java)
weakling (= 0.0.3)
@@ -201,20 +193,20 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
nokogiri
G
- simulate_platform "x86-darwin-100" do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "nokogiri"
- gem "platform_specific"
- G
+ simulate_platform "x86-darwin-100"
- expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 x86-darwin-100"
- end
+ install_gemfile <<-G
+ source "#{file_uri_for(gem_repo1)}"
+ gem "nokogiri"
+ gem "platform_specific"
+ G
+
+ expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 x86-darwin-100"
end
it "allows specifying only-ruby-platform on jruby", :jruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "nokogiri"
gem "platform_specific"
G
@@ -223,12 +215,12 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
bundle "install"
- expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 RUBY"
end
it "allows specifying only-ruby-platform" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "nokogiri"
gem "platform_specific"
G
@@ -237,12 +229,12 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
bundle "install"
- expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 RUBY"
end
it "allows specifying only-ruby-platform even if the lockfile is locked to a specific compatible platform" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "nokogiri"
gem "platform_specific"
G
@@ -251,27 +243,27 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
bundle "install"
- expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 RUBY"
end
it "doesn't pull platform specific gems on truffleruby", :truffleruby_only do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
G
- expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gems "platform_specific 1.0 RUBY"
end
- it "doesn't pull platform specific gems on truffleruby (except when whitelisted) even if lockfile was generated with an older version that declared ruby as platform", :truffleruby_only do
+ it "doesn't pull platform specific gems on truffleruby (except when whitelisted) even if lockfile was generated with an older version that declared RUBY as platform", :truffleruby_only do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
G
lockfile <<-L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
platform_specific (1.0)
@@ -287,7 +279,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
bundle "install"
- expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gems "platform_specific 1.0 RUBY"
simulate_platform "x86_64-linux" do
build_repo4 do
@@ -299,13 +291,13 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
end
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "libv8"
G
lockfile <<-L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo4)}/
specs:
libv8 (1.0)
@@ -327,13 +319,13 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
it "doesn't pull platform specific gems on truffleruby, even if lockfile only includes those", :truffleruby_only do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific"
G
lockfile <<-L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
platform_specific (1.0-x86-darwin-100)
@@ -349,7 +341,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
bundle "install"
- expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gems "platform_specific 1.0 RUBY"
end
it "pulls platform specific gems correctly on musl" do
@@ -360,8 +352,8 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
end
simulate_platform "aarch64-linux-musl" do
- install_gemfile <<-G, verbose: true
- source "https://gem.repo4"
+ install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }, :verbose => true
+ source "https://gems.repo4"
gem "nokogiri"
G
end
@@ -372,8 +364,8 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
it "allows specifying only-ruby-platform on windows with dependency platforms" do
simulate_windows do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "nokogiri", :platforms => [:windows, :mswin, :mswin64, :mingw, :x64_mingw, :jruby]
+ source "#{file_uri_for(gem_repo1)}"
+ gem "nokogiri", :platforms => [:mingw, :mswin, :x64_mingw, :jruby]
gem "platform_specific"
G
@@ -381,18 +373,18 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
bundle "install"
- expect(the_bundle).to include_gems "platform_specific 1.0 ruby"
+ expect(the_bundle).to include_gems "platform_specific 1.0 RUBY"
expect(the_bundle).to not_include_gems "nokogiri"
end
end
it "allows specifying only-ruby-platform on windows with gemspec dependency" do
- build_lib("foo", "1.0", path: bundled_app) do |s|
- s.add_dependency "myrack"
+ build_lib("foo", "1.0", :path => bundled_app) do |s|
+ s.add_dependency "rack"
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gemspec
G
bundle :lock
@@ -401,7 +393,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
bundle "config set force_ruby_platform true"
bundle "install"
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
@@ -414,7 +406,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
simulate_windows x64_mingw32 do
lockfile <<-L
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
platform_specific (1.0-x86-mingw32)
requires_platform_specific (1.0)
@@ -428,8 +420,8 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
requires_platform_specific
L
- install_gemfile <<-G, verbose: true
- source "https://gem.repo2"
+ install_gemfile <<-G, :verbose => true
+ source "#{file_uri_for(gem_repo2)}"
gem "requires_platform_specific"
G
@@ -445,7 +437,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
simulate_windows platform do
lockfile <<-L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
platform_specific (1.0-#{platform})
requires_platform_specific (1.0)
@@ -459,7 +451,7 @@ RSpec.describe "Bundler.setup with multi platform stuff" do
L
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "platform_specific", :platforms => [:windows]
G
diff --git a/spec/bundler/runtime/require_spec.rb b/spec/bundler/runtime/require_spec.rb
index ff45a3c5e2..e59fa564f6 100644
--- a/spec/bundler/runtime/require_spec.rb
+++ b/spec/bundler/runtime/require_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe "Bundler.require" do
s.write "lib/four.rb", "puts 'four'"
end
- build_lib "five", "1.0.0", no_default: true do |s|
+ build_lib "five", "1.0.0", :no_default => true do |s|
s.write "lib/mofive.rb", "puts 'five'"
end
@@ -46,7 +46,7 @@ RSpec.describe "Bundler.require" do
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "one", :group => :bar, :require => %w[baz qux]
gem "two"
@@ -113,7 +113,7 @@ RSpec.describe "Bundler.require" do
it "raises an exception if a require is specified but the file does not exist" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "two", :require => 'fail'
end
@@ -132,13 +132,13 @@ RSpec.describe "Bundler.require" do
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "faulty"
end
G
- run "Bundler.require", raise_on_error: false
+ run "Bundler.require", :raise_on_error => false
expect(err).to match("error while trying to load the gem 'faulty'")
expect(err).to match("Gem Internal Error Message")
end
@@ -149,7 +149,7 @@ RSpec.describe "Bundler.require" do
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "loadfuuu"
end
@@ -176,7 +176,7 @@ RSpec.describe "Bundler.require" do
it "requires gem names that are namespaced" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path '#{lib_path}' do
gem 'jquery-rails'
end
@@ -187,11 +187,11 @@ RSpec.describe "Bundler.require" do
end
it "silently passes if the require fails" do
- build_lib "bcrypt-ruby", "1.0.0", no_default: true do |s|
+ build_lib "bcrypt-ruby", "1.0.0", :no_default => true do |s|
s.write "lib/brcrypt.rb", "BCrypt = '1.0.0'"
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "bcrypt-ruby"
@@ -199,7 +199,7 @@ RSpec.describe "Bundler.require" do
G
cmd = <<-RUBY
- require 'bundler'
+ require '#{entrypoint}'
Bundler.require
RUBY
ruby(cmd)
@@ -209,7 +209,7 @@ RSpec.describe "Bundler.require" do
it "does not mangle explicitly given requires" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem 'jquery-rails', :require => 'jquery-rails'
end
@@ -227,7 +227,7 @@ RSpec.describe "Bundler.require" do
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "load-fuuu"
end
@@ -251,7 +251,7 @@ RSpec.describe "Bundler.require" do
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "load-fuuu"
end
@@ -310,7 +310,7 @@ RSpec.describe "Bundler.require" do
it "works when the gems are in the Gemfile in the correct order" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "two"
gem "one"
@@ -323,13 +323,13 @@ RSpec.describe "Bundler.require" do
describe "a gem with different requires for different envs" do
before(:each) do
- build_gem "multi_gem", to_bundle: true do |s|
+ build_gem "multi_gem", :to_bundle => true do |s|
s.write "lib/one.rb", "puts 'ONE'"
s.write "lib/two.rb", "puts 'TWO'"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "multi_gem", :require => "one", :group => :one
gem "multi_gem", :require => "two", :group => :two
G
@@ -353,7 +353,7 @@ RSpec.describe "Bundler.require" do
it "fails when the gems are in the Gemfile in the wrong order" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
path "#{lib_path}" do
gem "one"
gem "two"
@@ -366,12 +366,12 @@ RSpec.describe "Bundler.require" do
describe "with busted gems" do
it "should be busted" do
- build_gem "busted_require", to_bundle: true do |s|
+ build_gem "busted_require", :to_bundle => true do |s|
s.write "lib/busted_require.rb", "require 'no_such_file_omg'"
end
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "busted_require"
G
@@ -385,12 +385,12 @@ RSpec.describe "Bundler.require" do
it "does not load rubygems gemspecs that are used" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
run <<-R
- path = File.join(Gem.dir, "specifications", "myrack-1.0.0.gemspec")
+ path = File.join(Gem.dir, "specifications", "rack-1.0.0.gemspec")
contents = File.read(path)
contents = contents.lines.to_a.insert(-2, "\n raise 'broken gemspec'\n").join
File.open(path, "w") do |f|
@@ -410,7 +410,7 @@ RSpec.describe "Bundler.require" do
build_git "foo"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "foo", :git => "#{lib_path("foo-1.0")}"
G
@@ -430,42 +430,18 @@ RSpec.describe "Bundler.require" do
expect(out).to eq("WIN")
end
-
- it "does not extract gemspecs from application cache packages" do
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- G
-
- bundle :cache
-
- path = cached_gem("myrack-1.0.0")
-
- run <<-R
- File.open("#{path}", "w") do |f|
- f.write "broken package"
- end
- R
-
- run <<-R
- Bundler.require
- puts "WIN"
- R
-
- expect(out).to eq("WIN")
- end
end
RSpec.describe "Bundler.require with platform specific dependencies" do
it "does not require the gems that are pinned to other platforms" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
platforms :#{not_local_tag} do
gem "platform_specific", :require => "omgomg"
end
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
G
run "Bundler.require"
@@ -474,14 +450,14 @@ RSpec.describe "Bundler.require with platform specific dependencies" do
it "requires gems pinned to multiple platforms, including the current one" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
platforms :#{not_local_tag}, :#{local_tag} do
- gem "myrack", :require => "myrack"
+ gem "rack", :require => "rack"
end
G
- run "Bundler.require; puts MYRACK"
+ run "Bundler.require; puts RACK"
expect(out).to eq("1.0.0")
expect(err).to be_empty
diff --git a/spec/bundler/runtime/requiring_spec.rb b/spec/bundler/runtime/requiring_spec.rb
deleted file mode 100644
index 1f32269622..0000000000
--- a/spec/bundler/runtime/requiring_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "Requiring bundler" do
- it "takes care of requiring rubygems when entrypoint is bundler/setup" do
- sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler/setup -e'puts true'", env: { "RUBYOPT" => opt_add("--disable=gems", ENV["RUBYOPT"]) })
-
- expect(last_command.stdboth).to eq("true")
- end
-
- it "takes care of requiring rubygems when requiring just bundler" do
- sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler -e'puts true'", env: { "RUBYOPT" => opt_add("--disable=gems", ENV["RUBYOPT"]) })
-
- expect(last_command.stdboth).to eq("true")
- end
-end
diff --git a/spec/bundler/runtime/self_management_spec.rb b/spec/bundler/runtime/self_management_spec.rb
index c6910e95c0..61cfc9b795 100644
--- a/spec/bundler/runtime/self_management_spec.rb
+++ b/spec/bundler/runtime/self_management_spec.rb
@@ -1,28 +1,18 @@
# frozen_string_literal: true
-RSpec.describe "Self management", rubygems: ">= 3.3.0.dev" do
+RSpec.describe "Self management", :rubygems => ">= 3.3.0.dev", :realworld => true do
describe "auto switching" do
let(:previous_minor) do
"2.3.0"
end
- let(:current_version) do
- "2.4.0"
- end
-
before do
- build_repo4 do
- build_bundler previous_minor
-
- build_bundler current_version
-
- build_gem "myrack", "1.0.0"
- end
+ build_repo2
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo2)}"
- gem "myrack"
+ gem "rack"
G
end
@@ -30,34 +20,19 @@ RSpec.describe "Self management", rubygems: ">= 3.3.0.dev" do
lockfile_bundled_with(previous_minor)
bundle "config set --local path.system true"
- bundle "install", preserve_ruby_flags: true
+ bundle "install", :artifice => "vcr"
expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
# It uninstalls the older system bundler
- bundle "clean --force", artifice: nil
+ bundle "clean --force"
expect(out).to eq("Removing bundler (#{Bundler::VERSION})")
# App now uses locked version
- bundle "-v", artifice: nil
+ bundle "-v"
expect(out).to end_with(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor)
- # ruby-core test setup has always "lib" in $LOAD_PATH so `require "bundler/setup"` always activate the local version rather than using RubyGems gem activation stuff
- unless ruby_core?
- # App now uses locked version, even when not using the CLI directly
- file = bundled_app("bin/bundle_version.rb")
- create_file file, <<-RUBY
- #!#{Gem.ruby}
- require 'bundler/setup'
- puts Bundler::VERSION
- RUBY
- file.chmod(0o777)
- cmd = Gem.win_platform? ? "#{Gem.ruby} bin/bundle_version.rb" : "bin/bundle_version.rb"
- sys_exec cmd, artifice: nil
- expect(out).to eq(previous_minor)
- end
-
# Subsequent installs use the locked version without reinstalling
- bundle "install --verbose", artifice: nil
+ bundle "install --verbose"
expect(out).to include("Using bundler #{previous_minor}")
expect(out).not_to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
end
@@ -66,7 +41,7 @@ RSpec.describe "Self management", rubygems: ">= 3.3.0.dev" do
lockfile_bundled_with(previous_minor)
bundle "config set --local path vendor/bundle"
- bundle "install", preserve_ruby_flags: true
+ bundle "install", :artifice => "vcr"
expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
expect(vendored_gems("gems/bundler-#{previous_minor}")).to exist
@@ -78,21 +53,6 @@ RSpec.describe "Self management", rubygems: ">= 3.3.0.dev" do
bundle "-v"
expect(out).to end_with(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor)
- # ruby-core test setup has always "lib" in $LOAD_PATH so `require "bundler/setup"` always activate the local version rather than using RubyGems gem activation stuff
- unless ruby_core?
- # App now uses locked version, even when not using the CLI directly
- file = bundled_app("bin/bundle_version.rb")
- create_file file, <<-RUBY
- #!#{Gem.ruby}
- require 'bundler/setup'
- puts Bundler::VERSION
- RUBY
- file.chmod(0o777)
- cmd = Gem.win_platform? ? "#{Gem.ruby} bin/bundle_version.rb" : "bin/bundle_version.rb"
- sys_exec cmd, artifice: nil
- expect(out).to eq(previous_minor)
- end
-
# Subsequent installs use the locked version without reinstalling
bundle "install --verbose"
expect(out).to include("Using bundler #{previous_minor}")
@@ -103,7 +63,7 @@ RSpec.describe "Self management", rubygems: ">= 3.3.0.dev" do
lockfile_bundled_with(previous_minor)
bundle "config set --local deployment true"
- bundle "install", preserve_ruby_flags: true
+ bundle "install", :artifice => "vcr"
expect(out).to include("Bundler #{Bundler::VERSION} is running, but your lockfile was generated with #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
expect(vendored_gems("gems/bundler-#{previous_minor}")).to exist
@@ -131,83 +91,32 @@ RSpec.describe "Self management", rubygems: ">= 3.3.0.dev" do
expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
end
- it "does not try to install when --local is passed" do
- lockfile_bundled_with(previous_minor)
- system_gems "myrack-1.0.0", path: default_bundle_path
-
- bundle "install --local"
- expect(out).not_to match(/Installing Bundler/)
-
- bundle "-v"
- expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
- end
-
it "shows a discrete message if locked bundler does not exist" do
- missing_minor = "#{Bundler::VERSION[0]}.999.999"
+ missing_minor ="#{Bundler::VERSION[0]}.999.999"
lockfile_bundled_with(missing_minor)
- bundle "install"
+ bundle "install", :artifice => "vcr"
expect(err).to eq("Your lockfile is locked to a version of bundler (#{missing_minor}) that doesn't exist at https://rubygems.org/. Going on using #{Bundler::VERSION}")
bundle "-v"
expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
end
- it "installs BUNDLE_VERSION version when using bundle config version x.y.z" do
- lockfile_bundled_with(current_version)
-
- bundle "config set --local version #{previous_minor}"
- bundle "install", preserve_ruby_flags: true
- expect(out).to include("Bundler #{Bundler::VERSION} is running, but your configuration was #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.")
-
- bundle "-v"
- expect(out).to eq(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor)
- end
-
- it "does not try to install when using bundle config version global" do
- lockfile_bundled_with(previous_minor)
-
- bundle "config set version system"
- bundle "install"
- expect(out).not_to match(/restarting using that version/)
-
- bundle "-v"
- expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
- end
-
- it "does not try to install when using bundle config version <dev-version>" do
- lockfile_bundled_with(previous_minor)
-
- bundle "config set version #{previous_minor}.dev"
- bundle "install"
- expect(out).not_to match(/restarting using that version/)
-
- bundle "-v"
- expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
- end
-
- it "ignores malformed lockfile version" do
- lockfile_bundled_with("2.3.")
-
- bundle "install --verbose"
- expect(out).to include("Using bundler #{Bundler::VERSION}")
- end
-
private
def lockfile_bundled_with(version)
lockfile <<~L
GEM
- remote: https://gem.repo4/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
BUNDLED WITH
#{version}
diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb
index fc574f3196..2d39d72937 100644
--- a/spec/bundler/runtime/setup_spec.rb
+++ b/spec/bundler/runtime/setup_spec.rb
@@ -6,16 +6,16 @@ RSpec.describe "Bundler.setup" do
describe "with no arguments" do
it "makes all groups available" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :group => :test
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :group => :test
G
ruby <<-RUBY
require 'bundler'
Bundler.setup
- require 'myrack'
- puts MYRACK
+ require 'rack'
+ puts RACK
RUBY
expect(err).to be_empty
expect(out).to eq("1.0.0")
@@ -25,9 +25,9 @@ RSpec.describe "Bundler.setup" do
describe "when called with groups" do
before(:each) do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack", :group => :test
+ gem "rack", :group => :test
G
end
@@ -37,7 +37,7 @@ RSpec.describe "Bundler.setup" do
Bundler.setup(:default)
begin
- require 'myrack'
+ require 'rack'
rescue LoadError
puts "WIN"
end
@@ -51,8 +51,8 @@ RSpec.describe "Bundler.setup" do
require 'bundler'
Bundler.setup(:default, 'test')
- require 'myrack'
- puts MYRACK
+ require 'rack'
+ puts RACK
RUBY
expect(err).to be_empty
expect(out).to eq("1.0.0")
@@ -64,8 +64,8 @@ RSpec.describe "Bundler.setup" do
Bundler.setup
Bundler.setup(:default)
- require 'myrack'
- puts MYRACK
+ require 'rack'
+ puts RACK
RUBY
expect(err).to be_empty
expect(out).to eq("1.0.0")
@@ -89,16 +89,16 @@ RSpec.describe "Bundler.setup" do
end
it "handles multiple non-additive invocations" do
- ruby <<-RUBY, raise_on_error: false
+ ruby <<-RUBY, :raise_on_error => false
require 'bundler'
Bundler.setup(:default, :test)
Bundler.setup(:default)
- require 'myrack'
+ require 'rack'
puts "FAIL"
RUBY
- expect(err).to match("myrack")
+ expect(err).to match("rack")
expect(err).to match("LoadError")
expect(out).not_to match("FAIL")
end
@@ -113,8 +113,8 @@ RSpec.describe "Bundler.setup" do
it "puts loaded gems after -I and RUBYLIB", :ruby_repo do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
ENV["RUBYOPT"] = "#{ENV["RUBYOPT"]} -Idash_i_dir"
@@ -127,24 +127,23 @@ RSpec.describe "Bundler.setup" do
RUBY
load_path = out.split("\n")
- myrack_load_order = load_path.index {|path| path.include?("myrack") }
+ rack_load_order = load_path.index {|path| path.include?("rack") }
expect(err).to be_empty
expect(load_path).to include(a_string_ending_with("dash_i_dir"), "rubylib_dir")
- expect(myrack_load_order).to be > 0
+ expect(rack_load_order).to be > 0
end
it "orders the load path correctly when there are dependencies" do
bundle "config set path.system true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "rails"
G
ruby <<-RUBY
require 'bundler'
- gem "bundler", "#{Bundler::VERSION}" if #{ruby_core?}
Bundler.setup
puts $LOAD_PATH
RUBY
@@ -158,7 +157,7 @@ RSpec.describe "Bundler.setup" do
"/gems/actionpack-2.3.2/lib",
"/gems/actionmailer-2.3.2/lib",
"/gems/activesupport-2.3.2/lib",
- "/gems/rake-#{rake_version}/lib"
+ "/gems/rake-13.0.1/lib"
)
end
@@ -166,7 +165,7 @@ RSpec.describe "Bundler.setup" do
bundle "config set path.system true"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "weakling"
gem "duradura"
gem "terranova"
@@ -189,12 +188,12 @@ RSpec.describe "Bundler.setup" do
it "raises if the Gemfile was not yet installed" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
ruby <<-R
- require 'bundler'
+ require '#{entrypoint}'
begin
Bundler.setup
@@ -209,11 +208,11 @@ RSpec.describe "Bundler.setup" do
it "doesn't create a Gemfile.lock if the setup fails" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- ruby <<-R, raise_on_error: false
+ ruby <<-R, :raise_on_error => false
require 'bundler'
Bundler.setup
@@ -224,19 +223,19 @@ RSpec.describe "Bundler.setup" do
it "doesn't change the Gemfile.lock if the setup fails" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
lockfile = File.read(bundled_app_lock)
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "nosuchgem", "10.0"
G
- ruby <<-R, raise_on_error: false
+ ruby <<-R, :raise_on_error => false
require 'bundler'
Bundler.setup
@@ -247,8 +246,8 @@ RSpec.describe "Bundler.setup" do
it "makes a Gemfile.lock if setup succeeds" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
File.read(bundled_app_lock)
@@ -263,12 +262,12 @@ RSpec.describe "Bundler.setup" do
context "user provides an absolute path" do
it "uses BUNDLE_GEMFILE to locate the gemfile if present" do
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
gemfile bundled_app("4realz"), <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport", "2.3.5"
G
@@ -282,7 +281,7 @@ RSpec.describe "Bundler.setup" do
context "an absolute path is not provided" do
it "uses BUNDLE_GEMFILE to locate the gemfile if present and doesn't fail in deployment mode" do
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
bundle "install"
@@ -308,23 +307,23 @@ RSpec.describe "Bundler.setup" do
it "prioritizes gems in BUNDLE_PATH over gems in GEM_HOME" do
ENV["BUNDLE_PATH"] = bundled_app(".bundle").to_s
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
G
- build_gem "myrack", "1.0", to_system: true do |s|
- s.write "lib/myrack.rb", "MYRACK = 'FAIL'"
+ build_gem "rack", "1.0", :to_system => true do |s|
+ s.write "lib/rack.rb", "RACK = 'FAIL'"
end
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
describe "integrate with rubygems" do
describe "by replacing #gem" do
before :each do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "0.9.1"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "0.9.1"
G
end
@@ -344,7 +343,7 @@ RSpec.describe "Bundler.setup" do
it "replaces #gem but raises when the version is wrong" do
run <<-R
begin
- gem "myrack", "1.0.0"
+ gem "rack", "1.0.0"
puts "FAIL"
rescue LoadError
puts "WIN"
@@ -359,7 +358,7 @@ RSpec.describe "Bundler.setup" do
before :each do
system_gems "activesupport-2.3.5"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
G
end
@@ -372,7 +371,7 @@ RSpec.describe "Bundler.setup" do
context "when the ruby stdlib is a substring of Gem.path" do
it "does not reject the stdlib from $LOAD_PATH" do
substring = "/" + $LOAD_PATH.find {|p| p.include?("vendor_ruby") }.split("/")[2]
- run "puts 'worked!'", env: { "GEM_PATH" => substring }
+ run "puts 'worked!'", :env => { "GEM_PATH" => substring }
expect(out).to eq("worked!")
end
end
@@ -381,37 +380,37 @@ RSpec.describe "Bundler.setup" do
describe "with paths" do
it "activates the gems in the path source" do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
- build_lib "myrack", "1.0.0" do |s|
- s.write "lib/myrack.rb", "puts 'WIN'"
+ build_lib "rack", "1.0.0" do |s|
+ s.write "lib/rack.rb", "puts 'WIN'"
end
gemfile <<-G
- source "https://gem.repo1"
- path "#{lib_path("myrack-1.0.0")}" do
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ path "#{lib_path("rack-1.0.0")}" do
+ gem "rack"
end
G
- run "require 'myrack'"
+ run "require 'rack'"
expect(out).to eq("WIN")
end
end
describe "with git" do
before do
- build_git "myrack", "1.0.0"
+ build_git "rack", "1.0.0"
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-1.0.0")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-1.0.0")}"
G
end
it "provides a useful exception when the git repo is not checked out yet" do
- run "1", raise_on_error: false
- expect(err).to match(/the git source #{lib_path("myrack-1.0.0")} is not yet checked out. Please run `bundle install`/i)
+ run "1", :raise_on_error => false
+ expect(err).to match(/the git source #{lib_path('rack-1.0.0')} is not yet checked out. Please run `bundle install`/i)
end
it "does not hit the git binary if the lockfile is available and up to date" do
@@ -441,7 +440,7 @@ RSpec.describe "Bundler.setup" do
break_git!
ruby <<-R
- require "bundler"
+ require "#{entrypoint}"
begin
Bundler.setup
@@ -451,7 +450,7 @@ RSpec.describe "Bundler.setup" do
end
R
- run "puts 'FAIL'", raise_on_error: false
+ run "puts 'FAIL'", :raise_on_error => false
expect(err).not_to include "This is not the git you are looking for"
end
@@ -460,7 +459,7 @@ RSpec.describe "Bundler.setup" do
bundle "config set --local path vendor/bundle"
bundle :install
FileUtils.rm_rf vendored_gems("cache")
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
it "does not randomly change the path when specifying --path and the bundle directory becomes read only" do
@@ -468,7 +467,7 @@ RSpec.describe "Bundler.setup" do
bundle :install
with_read_only("#{bundled_app}/**/*") do
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
@@ -477,91 +476,91 @@ RSpec.describe "Bundler.setup" do
bundle "install"
with_read_only("#{bundled_app(".bundle")}/**/*") do
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
end
describe "when specifying local override" do
it "explodes if given path does not exist on runtime" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
- FileUtils.rm_rf(lib_path("local-myrack"))
- run "require 'myrack'", raise_on_error: false
- expect(err).to match(/Cannot use local override for myrack-0.8 because #{Regexp.escape(lib_path("local-myrack").to_s)} does not exist/)
+ FileUtils.rm_rf(lib_path("local-rack"))
+ run "require 'rack'", :raise_on_error => false
+ expect(err).to match(/Cannot use local override for rack-0.8 because #{Regexp.escape(lib_path('local-rack').to_s)} does not exist/)
end
it "explodes if branch is not given on runtime" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}"
G
- run "require 'myrack'", raise_on_error: false
+ run "require 'rack'", :raise_on_error => false
expect(err).to match(/because :branch is not specified in Gemfile/)
end
it "explodes on different branches on runtime" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
+ bundle %(config set local.rack #{lib_path("local-rack")})
bundle :install
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "changed"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "changed"
G
- run "require 'myrack'", raise_on_error: false
+ run "require 'rack'", :raise_on_error => false
expect(err).to match(/is using branch main but Gemfile specifies changed/)
end
it "explodes on refs with different branches on runtime" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- FileUtils.cp_r("#{lib_path("myrack-0.8")}/.", lib_path("local-myrack"))
+ FileUtils.cp_r("#{lib_path("rack-0.8")}/.", lib_path("local-rack"))
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :ref => "main", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "main", :branch => "main"
G
gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :ref => "main", :branch => "nonexistent"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "main", :branch => "nonexistent"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- run "require 'myrack'", raise_on_error: false
+ bundle %(config set local.rack #{lib_path("local-rack")})
+ run "require 'rack'", :raise_on_error => false
expect(err).to match(/is using branch main but Gemfile specifies nonexistent/)
end
end
@@ -570,7 +569,7 @@ RSpec.describe "Bundler.setup" do
it "doesn't change the resolve if --without is used" do
bundle "config set --local without rails"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
group :rails do
@@ -580,13 +579,13 @@ RSpec.describe "Bundler.setup" do
system_gems "activesupport-2.3.5"
- expect(the_bundle).to include_gems "activesupport 2.3.2", groups: :default
+ expect(the_bundle).to include_gems "activesupport 2.3.2", :groups => :default
end
it "remembers --without and does not bail on bare Bundler.setup" do
bundle "config set --local without rails"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
group :rails do
@@ -603,17 +602,17 @@ RSpec.describe "Bundler.setup" do
bundle "config set --local without development"
path = bundled_app(File.join("vendor", "foo"))
- build_lib "foo", path: path
+ build_lib "foo", :path => path
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport", "2.3.2"
gem 'foo', :path => 'vendor/foo', :group => :development
G
FileUtils.rm_rf(path)
- ruby "require 'bundler'; Bundler.setup", env: { "DEBUG" => "1" }
+ ruby "require 'bundler'; Bundler.setup", :env => { "DEBUG" => "1" }
expect(out).to include("Assuming that source at `vendor/foo` has not changed since fetching its specs errored")
expect(out).to include("Found no changes, using resolution from the lockfile")
expect(err).to be_empty
@@ -629,11 +628,11 @@ RSpec.describe "Bundler.setup" do
end
install_gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "depends_on_bundler"
G
- ruby "require '#{system_gem_path("gems/bundler-9.99.9.beta1/lib/bundler.rb")}'; Bundler.setup", env: { "DEBUG" => "1" }
+ ruby "require '#{system_gem_path("gems/bundler-9.99.9.beta1/lib/bundler.rb")}'; Bundler.setup", :env => { "DEBUG" => "1" }
expect(out).to include("Found no changes, using resolution from the lockfile")
expect(out).not_to include("lockfile does not have all gems needed for the current platform")
expect(err).to be_empty
@@ -641,24 +640,24 @@ RSpec.describe "Bundler.setup" do
it "doesn't fail in frozen mode when bundler is a Gemfile dependency" do
install_gemfile <<~G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "bundler"
G
- bundle "install --verbose", env: { "BUNDLE_FROZEN" => "true" }
+ bundle "install --verbose", :env => { "BUNDLE_FROZEN" => "true" }
expect(err).to be_empty
end
it "doesn't re-resolve when deleting dependencies" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "actionpack"
G
- install_gemfile <<-G, verbose: true
- source "https://gem.repo1"
- gem "myrack"
+ install_gemfile <<-G, :verbose => true
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
expect(out).to include("Some dependencies were deleted, using a subset of the resolution from the lockfile")
@@ -668,11 +667,11 @@ RSpec.describe "Bundler.setup" do
it "remembers --without and does not include groups passed to Bundler.setup" do
bundle "config set --local without rails"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
- group :myrack do
- gem "myrack"
+ group :rack do
+ gem "rack"
end
group :rails do
@@ -680,19 +679,19 @@ RSpec.describe "Bundler.setup" do
end
G
- expect(the_bundle).not_to include_gems "activesupport 2.3.2", groups: :myrack
- expect(the_bundle).to include_gems "myrack 1.0.0", groups: :myrack
+ expect(the_bundle).not_to include_gems "activesupport 2.3.2", :groups => :rack
+ expect(the_bundle).to include_gems "rack 1.0.0", :groups => :rack
end
end
# RubyGems returns loaded_from as a string
it "has loaded_from as a string on all specs" do
build_git "foo"
- build_git "no-gemspec", gemspec: false
+ build_git "no-gemspec", :gemspec => false
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
gem "foo", :git => "#{lib_path("foo-1.0")}"
gem "no-gemspec", "1.0", :git => "#{lib_path("no-gemspec-1.0")}"
G
@@ -708,8 +707,8 @@ RSpec.describe "Bundler.setup" do
it "does not load all gemspecs" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
run <<-R
@@ -728,27 +727,6 @@ end
R
run <<-R
- File.open(File.join(Gem.dir, "specifications", "broken-ext.gemspec"), "w") do |f|
- f.write <<-RUBY
-# -*- encoding: utf-8 -*-
-# stub: broken-ext 1.0.0 ruby lib
-# stub: a.ext\\0b.ext
-
-Gem::Specification.new do |s|
- s.name = "broken-ext"
- s.version = "1.0.0"
- raise "BROKEN GEMSPEC EXT"
-end
- RUBY
- end
- # Need to write the gem.build_complete file,
- # otherwise the full spec is loaded to check the installed_by_version
- extensions_dir = Gem.default_ext_dir_for(Gem.dir) || File.join(Gem.dir, "extensions", Gem::Platform.local.to_s, Gem.extension_api_version)
- Bundler::FileUtils.mkdir_p(File.join(extensions_dir, "broken-ext-1.0.0"))
- File.open(File.join(extensions_dir, "broken-ext-1.0.0", "gem.build_complete"), "w") {}
- R
-
- run <<-R
puts "WIN"
R
@@ -757,8 +735,8 @@ end
it "ignores empty gem paths" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
ENV["GEM_HOME"] = ""
@@ -767,18 +745,6 @@ end
expect(err).to be_empty
end
- it "can require rubygems without warnings, when using a local cache", :truffleruby do
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
- G
-
- bundle "package"
- bundle %(exec ruby -w -e "require 'rubygems'")
-
- expect(err).to be_empty
- end
-
context "when the user has `MANPATH` set", :man do
before { ENV["MANPATH"] = "/foo#{File::PATH_SEPARATOR}" }
@@ -790,7 +756,7 @@ end
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "with_man"
G
@@ -814,7 +780,7 @@ end
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "with_man"
G
@@ -827,7 +793,7 @@ end
expect(out).to eq("#{default_bundle_path("gems/with_man-1.0/man")}#{File::PATH_SEPARATOR}\ntrue")
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "with_man_overriding_system_man"
G
@@ -854,7 +820,7 @@ end
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem "requirepaths", :require => nil
G
@@ -870,7 +836,7 @@ end
system_gems full_gem_name
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
G
ruby <<-R
@@ -917,9 +883,9 @@ end
end
it "should not remove itself from the LOAD_PATH and require a different copy of 'bundler/setup'" do
- install_gemfile "source 'https://gem.repo1'"
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
- ruby <<-R, env: { "GEM_PATH" => symlinked_gem_home }
+ ruby <<-R, :env => { "GEM_PATH" => symlinked_gem_home }
TracePoint.trace(:class) do |tp|
if tp.path.include?("bundler") && !tp.path.start_with?("#{source_root}")
puts "OMG. Defining a class from another bundler at \#{tp.path}:\#{tp.lineno}"
@@ -934,17 +900,17 @@ end
end
it "does not reveal system gems even when Gem.refresh is called" do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport"
G
run <<-R
- puts Bundler.rubygems.installed_specs.map(&:name)
+ puts Bundler.rubygems.all_specs.map(&:name)
Gem.refresh
- puts Bundler.rubygems.installed_specs.map(&:name)
+ puts Bundler.rubygems.all_specs.map(&:name)
R
expect(out).to eq("activesupport\nbundler\nactivesupport\nbundler")
@@ -959,18 +925,18 @@ end
it "should resolve paths relative to the Gemfile" do
path = bundled_app(File.join("vendor", "foo"))
- build_lib "foo", path: path
+ build_lib "foo", :path => path
# If the .gemspec exists, then Bundler handles the path differently.
# See Source::Path.load_spec_files for details.
FileUtils.rm(File.join(path, "foo.gemspec"))
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', '1.2.3', :path => 'vendor/foo'
G
- run <<-R, env: { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, dir: bundled_app.parent
+ run <<-R, :env => { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, :dir => bundled_app.parent
require 'foo'
R
expect(err).to be_empty
@@ -980,20 +946,20 @@ end
relative_path = File.join("vendor", Dir.pwd.gsub(/^#{filesystem_root}/, ""))
absolute_path = bundled_app(relative_path)
FileUtils.mkdir_p(absolute_path)
- build_lib "foo", path: absolute_path
+ build_lib "foo", :path => absolute_path
# If the .gemspec exists, then Bundler handles the path differently.
# See Source::Path.load_spec_files for details.
FileUtils.rm(File.join(absolute_path, "foo.gemspec"))
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', '1.2.3', :path => '#{relative_path}'
G
bundle :install
- run <<-R, env: { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, dir: bundled_app.parent
+ run <<-R, :env => { "BUNDLE_GEMFILE" => bundled_app_gemfile.to_s }, :dir => bundled_app.parent
require 'foo'
R
@@ -1003,10 +969,10 @@ end
describe "with git gems that don't have gemspecs" do
before :each do
- build_git "no_gemspec", gemspec: false
+ build_git "no_gemspec", :gemspec => false
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "no_gemspec", "1.0", :git => "#{lib_path("no_gemspec-1.0")}"
G
end
@@ -1023,10 +989,10 @@ end
describe "with bundled and system gems" do
before :each do
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport", "2.3.5"
G
@@ -1035,7 +1001,7 @@ end
it "does not pull in system gems" do
run <<-R
begin;
- require 'myrack'
+ require 'rack'
rescue LoadError
puts 'WIN'
end
@@ -1057,13 +1023,13 @@ end
it "raises an exception if gem is used to invoke a system gem not in the bundle" do
run <<-R
begin
- gem 'myrack'
+ gem 'rack'
rescue LoadError => e
puts e.message
end
R
- expect(out).to eq("myrack is not part of the bundle. Add it to your Gemfile.")
+ expect(out).to eq("rack is not part of the bundle. Add it to your Gemfile.")
end
it "sets GEM_HOME appropriately" do
@@ -1075,11 +1041,11 @@ end
describe "with system gems in the bundle" do
before :each do
bundle "config set path.system true"
- system_gems "myrack-1.0.0"
+ system_gems "rack-1.0.0"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", "1.0.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", "1.0.0"
gem "activesupport", "2.3.5"
G
end
@@ -1093,7 +1059,7 @@ end
describe "with a gemspec that requires other files" do
before :each do
- build_git "bar", gemspec: false do |s|
+ build_git "bar", :gemspec => false do |s|
s.write "lib/bar/version.rb", %(BAR_VERSION = '1.0')
s.write "bar.gemspec", <<-G
require_relative 'lib/bar/version'
@@ -1109,7 +1075,7 @@ end
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :git => "#{lib_path("bar-1.0")}"
G
end
@@ -1123,10 +1089,10 @@ end
it "error intelligently if the gemspec has a LoadError" do
skip "whitespace issue?" if Gem.win_platform?
- ref = update_git "bar", gemspec: false do |s|
+ ref = update_git "bar", :gemspec => false do |s|
s.write "bar.gemspec", "require 'foobarbaz'"
end.ref_for("HEAD")
- bundle :install, raise_on_error: false
+ bundle :install, :raise_on_error => false
expect(err.lines.map(&:chomp)).to include(
a_string_starting_with("[!] There was an error while loading `bar.gemspec`:"),
@@ -1156,7 +1122,7 @@ end
describe "when Bundler is bundled" do
it "doesn't blow up" do
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bundler", :path => "#{root}"
G
@@ -1169,15 +1135,15 @@ end
def lock_with(bundler_version = nil)
lock = <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
+ rack
L
if bundler_version
@@ -1191,15 +1157,15 @@ end
bundle "config set --local path.system true"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
context "is not present" do
it "does not change the lock" do
lockfile lock_with(nil)
- ruby "require 'bundler/setup'"
+ ruby "require '#{entrypoint}/setup'"
expect(lockfile).to eq lock_with(nil)
end
end
@@ -1218,7 +1184,7 @@ end
it "does not change the lock" do
system_gems "bundler-1.10.1"
lockfile lock_with("1.10.1")
- ruby "require 'bundler/setup'"
+ ruby "require '#{entrypoint}/setup'"
expect(lockfile).to eq lock_with("1.10.1")
end
end
@@ -1228,22 +1194,17 @@ end
let(:ruby_version) { nil }
def lock_with(ruby_version = nil)
- checksums = checksums_section do |c|
- c.checksum gem_repo1, "myrack", "1.0.0"
- end
-
lock = <<~L
GEM
- remote: https://gem.repo1/
+ remote: #{file_uri_for(gem_repo1)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
- myrack
- #{checksums}
+ rack
L
if ruby_version
@@ -1262,8 +1223,8 @@ end
before do
install_gemfile <<-G
ruby ">= 0"
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
lockfile lock_with(ruby_version)
end
@@ -1293,7 +1254,9 @@ end
describe "with gemified standard libraries" do
it "does not load Digest", :ruby_repo do
- build_git "bar", gemspec: false do |s|
+ skip "Only for Ruby 3.0+" unless RUBY_VERSION >= "3.0"
+
+ build_git "bar", :gemspec => false do |s|
s.write "lib/bar/version.rb", %(BAR_VERSION = '1.0')
s.write "bar.gemspec", <<-G
require_relative 'lib/bar/version'
@@ -1305,20 +1268,20 @@ end
s.files = Dir["lib/**/*.rb"]
s.author = 'no one'
- s.add_dependency 'digest'
+ s.add_runtime_dependency 'digest'
end
G
end
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "bar", :git => "#{lib_path("bar-1.0")}"
G
bundle :install
- ruby <<-RUBY, artifice: nil
- require 'bundler/setup'
+ ruby <<-RUBY
+ require '#{entrypoint}/setup'
puts defined?(::Digest) ? "Digest defined" : "Digest undefined"
require 'digest'
RUBY
@@ -1326,9 +1289,9 @@ end
end
it "does not load Psych" do
- gemfile "source 'https://gem.repo1'"
+ gemfile "source \"#{file_uri_for(gem_repo1)}\""
ruby <<-RUBY
- require 'bundler/setup'
+ require '#{entrypoint}/setup'
puts defined?(Psych::VERSION) ? Psych::VERSION : "undefined"
require 'psych'
puts Psych::VERSION
@@ -1339,8 +1302,8 @@ end
end
it "does not load openssl" do
- install_gemfile "source 'https://gem.repo1'"
- ruby <<-RUBY, artifice: nil
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
+ ruby <<-RUBY
require "bundler/setup"
puts defined?(OpenSSL) || "undefined"
require "openssl"
@@ -1349,63 +1312,20 @@ end
expect(out).to eq("undefined\nconstant")
end
- it "does not load uri while reading gemspecs", rubygems: ">= 3.6.0.dev" do
- Dir.mkdir bundled_app("test")
-
- create_file(bundled_app("test/test.gemspec"), <<-G)
- Gem::Specification.new do |s|
- s.name = "test"
- s.version = "1.0.0"
- s.summary = "test"
- s.authors = ['John Doe']
- s.homepage = 'https://example.com'
- end
- G
-
- install_gemfile <<-G
- source "https://gem.repo1"
- gem "test", path: "#{bundled_app("test")}"
- G
-
- ruby <<-RUBY, artifice: nil
- require "bundler/setup"
- puts defined?(URI) || "undefined"
- require "uri"
- puts defined?(URI) || "undefined"
- RUBY
- expect(out).to eq("undefined\nconstant")
- end
-
- it "activates default gems when they are part of the bundle, but not installed explicitly", :ruby_repo do
- default_delegate_version = ruby "gem 'delegate'; require 'delegate'; puts Delegator::VERSION"
-
- build_repo2 do
- build_gem "delegate", default_delegate_version
- end
-
- gemfile "source \"https://gem.repo2\"; gem 'delegate'"
-
- ruby <<-RUBY
- require "bundler/setup"
- require "delegate"
- puts defined?(::Delegator) ? "Delegator defined" : "Delegator undefined"
- RUBY
-
- expect(out).to eq("Delegator defined")
- expect(err).to be_empty
- end
-
describe "default gem activation" do
let(:exemptions) do
- exempts = %w[did_you_mean bundler uri pathname]
- exempts << "etc" if (Gem.ruby_version < Gem::Version.new("3.2") || Gem.ruby_version >= Gem::Version.new("3.3.2")) && Gem.win_platform?
+ exempts = %w[did_you_mean bundler]
+ exempts << "uri" if Gem.ruby_version >= Gem::Version.new("2.7")
+ exempts << "pathname" if Gem.ruby_version >= Gem::Version.new("3.0")
+ exempts << "set" unless Gem.rubygems_version >= Gem::Version.new("3.2.6")
+ exempts << "tsort" unless Gem.rubygems_version >= Gem::Version.new("3.2.31")
exempts << "error_highlight" # added in Ruby 3.1 as a default gem
exempts << "ruby2_keywords" # added in Ruby 3.1 as a default gem
exempts << "syntax_suggest" # added in Ruby 3.2 as a default gem
exempts
end
- let(:activation_warning_hack) { <<~RUBY }
+ let(:activation_warning_hack) { strip_whitespace(<<-RUBY) }
require #{spec_dir.join("support/hax").to_s.dump}
Gem::Specification.send(:alias_method, :bundler_spec_activate, :activate)
@@ -1425,7 +1345,7 @@ end
"-r#{bundled_app("activation_warning_hack.rb")} #{ENV["RUBYOPT"]}"
end
- let(:code) { <<~RUBY }
+ let(:code) { strip_whitespace(<<-RUBY) }
require "pp"
loaded_specs = Gem.loaded_specs.dup
#{exemptions.inspect}.each {|s| loaded_specs.delete(s) }
@@ -1439,25 +1359,25 @@ end
RUBY
it "activates no gems with -rbundler/setup" do
- install_gemfile "source 'https://gem.repo1'"
- ruby code, env: { "RUBYOPT" => activation_warning_hack_rubyopt + " -rbundler/setup" }, artifice: nil
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
+ ruby code, :env => { "RUBYOPT" => activation_warning_hack_rubyopt + " -rbundler/setup" }
expect(out).to eq("{}")
end
it "activates no gems with bundle exec" do
- install_gemfile "source 'https://gem.repo1'"
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
create_file("script.rb", code)
- bundle "exec ruby ./script.rb", env: { "RUBYOPT" => activation_warning_hack_rubyopt }
+ bundle "exec ruby ./script.rb", :env => { "RUBYOPT" => activation_warning_hack_rubyopt }
expect(out).to eq("{}")
end
it "activates no gems with bundle exec that is loaded" do
skip "not executable" if Gem.win_platform?
- install_gemfile "source 'https://gem.repo1'"
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
create_file("script.rb", "#!/usr/bin/env ruby\n\n#{code}")
FileUtils.chmod(0o777, bundled_app("script.rb"))
- bundle "exec ./script.rb", artifice: nil, env: { "RUBYOPT" => activation_warning_hack_rubyopt }
+ bundle "exec ./script.rb", :artifice => nil, :env => { "RUBYOPT" => activation_warning_hack_rubyopt }
expect(out).to eq("{}")
end
@@ -1466,10 +1386,10 @@ end
build_gem "net-http-pipeline", "1.0.1"
end
- system_gems "net-http-pipeline-1.0.1", gem_repo: gem_repo4
+ system_gems "net-http-pipeline-1.0.1", :gem_repo => gem_repo4
gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "net-http-pipeline", "1.0.1"
G
@@ -1491,11 +1411,11 @@ end
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "#{g}", "999999"
G
- expect(the_bundle).to include_gem("#{g} 999999", env: { "RUBYOPT" => activation_warning_hack_rubyopt }, artifice: nil)
+ expect(the_bundle).to include_gem("#{g} 999999", :env => { "RUBYOPT" => activation_warning_hack_rubyopt })
end
it "activates older versions of #{g}", :ruby_repo do
@@ -1506,41 +1426,41 @@ end
end
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
gem "#{g}", "0.0.0.a"
G
- expect(the_bundle).to include_gem("#{g} 0.0.0.a", env: { "RUBYOPT" => activation_warning_hack_rubyopt }, artifice: nil)
+ expect(the_bundle).to include_gem("#{g} 0.0.0.a", :env => { "RUBYOPT" => activation_warning_hack_rubyopt })
end
end
end
end
describe "after setup" do
- it "allows calling #gem on random objects", bundler: "< 3" do
+ it "allows calling #gem on random objects", :bundler => "< 3" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
ruby <<-RUBY
require "bundler/setup"
- Object.new.gem "myrack"
- puts Gem.loaded_specs["myrack"].full_name
+ Object.new.gem "rack"
+ puts Gem.loaded_specs["rack"].full_name
RUBY
- expect(out).to eq("myrack-1.0.0")
+ expect(out).to eq("rack-1.0.0")
end
- it "keeps Kernel#gem private", bundler: "3" do
+ it "keeps Kernel#gem private", :bundler => "3" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- ruby <<-RUBY, raise_on_error: false
+ ruby <<-RUBY, :raise_on_error => false
require "bundler/setup"
- Object.new.gem "myrack"
+ Object.new.gem "rack"
puts "FAIL"
RUBY
@@ -1550,34 +1470,40 @@ end
it "keeps Kernel#require private" do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
- ruby <<-RUBY, raise_on_error: false
+ ruby <<-RUBY, :raise_on_error => false
require "bundler/setup"
- Object.new.require "myrack"
+ Object.new.require "rack"
puts "FAIL"
RUBY
expect(last_command.stdboth).not_to include "FAIL"
- expect(err).to match(/private method [`']require'/)
+ expect(err).to include "private method `require'"
+ end
+
+ it "takes care of requiring rubygems" do
+ sys_exec("#{Gem.ruby} -I#{lib_dir} -rbundler/setup -e'puts true'", :env => { "RUBYOPT" => opt_add("--disable=gems", ENV["RUBYOPT"]) })
+
+ expect(last_command.stdboth).to eq("true")
end
it "memoizes initial set of specs when requiring bundler/setup, so that even if further code mutates dependencies, Bundler.definition.specs is not affected" do
install_gemfile <<~G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "yard"
- gem "myrack", :group => :test
+ gem "rack", :group => :test
G
- ruby <<-RUBY, raise_on_error: false
+ ruby <<-RUBY, :raise_on_error => false
require "bundler/setup"
Bundler.require(:test).select! {|d| (d.groups & [:test]).any? }
puts Bundler.definition.specs.map(&:name).join(", ")
RUBY
- expect(out).to include("myrack, yard")
+ expect(out).to include("rack, yard")
end
it "does not cause double loads when higher versions of default gems are activated before bundler" do
@@ -1591,9 +1517,9 @@ end
end
end
- system_gems "json-999.999.999", gem_repo: gem_repo2
+ system_gems "json-999.999.999", :gem_repo => gem_repo2
- install_gemfile "source 'https://gem.repo1'"
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
ruby <<-RUBY
require "json"
require "bundler/setup"
@@ -1604,8 +1530,8 @@ end
end
end
- it "does not undo the Kernel.require decorations", rubygems: ">= 3.4.6" do
- install_gemfile "source 'https://gem.repo1'"
+ it "does not undo the Kernel.require decorations", :rubygems => ">= 3.4.6" do
+ install_gemfile "source \"#{file_uri_for(gem_repo1)}\""
script = bundled_app("bin/script")
create_file(script, <<~RUBY)
module Kernel
@@ -1625,26 +1551,7 @@ end
require "foo"
RUBY
- sys_exec "#{Gem.ruby} #{script}", raise_on_error: false
+ sys_exec "#{Gem.ruby} #{script}", :raise_on_error => false
expect(out).to include("requiring foo used the monkeypatch")
end
-
- it "performs an automatic bundle install" do
- build_repo4 do
- build_gem "myrack", "1.0.0"
- end
-
- gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :group => :test
- G
-
- bundle "config set auto_install 1"
-
- ruby <<-RUBY, artifice: "compact_index"
- require 'bundler/setup'
- RUBY
- expect(err).to be_empty
- expect(out).to include("Installing myrack 1.0.0")
- end
end
diff --git a/spec/bundler/runtime/with_unbundled_env_spec.rb b/spec/bundler/runtime/with_unbundled_env_spec.rb
new file mode 100644
index 0000000000..731a9921a2
--- /dev/null
+++ b/spec/bundler/runtime/with_unbundled_env_spec.rb
@@ -0,0 +1,302 @@
+# frozen_string_literal: true
+
+RSpec.describe "Bundler.with_env helpers" do
+ def bundle_exec_ruby(args, options = {})
+ build_bundler_context options
+ bundle "exec '#{Gem.ruby}' #{args}", options
+ end
+
+ def build_bundler_context(options = {})
+ bundle "config set path vendor/bundle"
+ gemfile "source \"#{file_uri_for(gem_repo1)}\""
+ bundle "install", options
+ end
+
+ def run_bundler_script(env, script)
+ system(env, "ruby", "-I#{lib_dir}", "-rbundler", script.to_s)
+ end
+
+ describe "Bundler.original_env" do
+ it "should return the PATH present before bundle was activated" do
+ create_file("source.rb", <<-RUBY)
+ print Bundler.original_env["PATH"]
+ RUBY
+ path = `getconf PATH`.strip + "#{File::PATH_SEPARATOR}/foo"
+ with_path_as(path) do
+ bundle_exec_ruby(bundled_app("source.rb").to_s)
+ expect(last_command.stdboth).to eq(path)
+ end
+ end
+
+ it "should return the GEM_PATH present before bundle was activated" do
+ create_file("source.rb", <<-RUBY)
+ print Bundler.original_env['GEM_PATH']
+ RUBY
+ gem_path = ENV["GEM_PATH"] + "#{File::PATH_SEPARATOR}/foo"
+ with_gem_path_as(gem_path) do
+ bundle_exec_ruby(bundled_app("source.rb").to_s)
+ expect(last_command.stdboth).to eq(gem_path)
+ end
+ end
+
+ it "works with nested bundle exec invocations", :ruby_repo do
+ create_file("exe.rb", <<-'RUBY')
+ count = ARGV.first.to_i
+ exit if count < 0
+ STDERR.puts "#{count} #{ENV["PATH"].end_with?("#{File::PATH_SEPARATOR}/foo")}"
+ if count == 2
+ ENV["PATH"] = "#{ENV["PATH"]}#{File::PATH_SEPARATOR}/foo"
+ end
+ exec(Gem.ruby, __FILE__, (count - 1).to_s)
+ RUBY
+ path = `getconf PATH`.strip + File::PATH_SEPARATOR + File.dirname(Gem.ruby)
+ with_path_as(path) do
+ build_bundler_context
+ bundle_exec_ruby("#{bundled_app("exe.rb")} 2")
+ end
+ expect(err).to eq <<-EOS.strip
+2 false
+1 true
+0 true
+ EOS
+ end
+
+ it "removes variables that bundler added", :ruby_repo do
+ # Simulate bundler has not yet been loaded
+ ENV.replace(ENV.to_hash.delete_if {|k, _v| k.start_with?(Bundler::EnvironmentPreserver::BUNDLER_PREFIX) })
+
+ original = ruby('puts ENV.to_a.map {|e| e.join("=") }.sort.join("\n")')
+ create_file("source.rb", <<-RUBY)
+ puts Bundler.original_env.to_a.map {|e| e.join("=") }.sort.join("\n")
+ RUBY
+ bundle_exec_ruby bundled_app("source.rb")
+ expect(out).to eq original
+ end
+ end
+
+ shared_examples_for "an unbundling helper" do
+ it "should delete BUNDLE_PATH" do
+ create_file("source.rb", <<-RUBY)
+ print #{modified_env}.has_key?('BUNDLE_PATH')
+ RUBY
+ ENV["BUNDLE_PATH"] = "./foo"
+ bundle_exec_ruby bundled_app("source.rb")
+ expect(last_command.stdboth).to include "false"
+ end
+
+ it "should remove absolute path to 'bundler/setup' from RUBYOPT even if it was present in original env" do
+ create_file("source.rb", <<-RUBY)
+ print #{modified_env}['RUBYOPT']
+ RUBY
+ setup_require = "-r#{lib_dir}/bundler/setup"
+ ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 #{setup_require} #{ENV["RUBYOPT"]}"
+ simulate_bundler_version_when_missing_prerelease_default_gem_activation do
+ bundle_exec_ruby bundled_app("source.rb")
+ end
+ expect(last_command.stdboth).not_to include(setup_require)
+ end
+
+ it "should remove relative path to 'bundler/setup' from RUBYOPT even if it was present in original env" do
+ create_file("source.rb", <<-RUBY)
+ print #{modified_env}['RUBYOPT']
+ RUBY
+ ENV["BUNDLER_ORIG_RUBYOPT"] = "-W2 -rbundler/setup #{ENV["RUBYOPT"]}"
+ simulate_bundler_version_when_missing_prerelease_default_gem_activation do
+ bundle_exec_ruby bundled_app("source.rb")
+ end
+ expect(last_command.stdboth).not_to include("-rbundler/setup")
+ end
+
+ it "should restore RUBYLIB", :ruby_repo do
+ create_file("source.rb", <<-RUBY)
+ print #{modified_env}['RUBYLIB']
+ RUBY
+ ENV["RUBYLIB"] = lib_dir.to_s + File::PATH_SEPARATOR + "/foo"
+ ENV["BUNDLER_ORIG_RUBYLIB"] = lib_dir.to_s + File::PATH_SEPARATOR + "/foo-original"
+ bundle_exec_ruby bundled_app("source.rb")
+ expect(last_command.stdboth).to include("/foo-original")
+ end
+
+ it "should restore the original MANPATH" do
+ create_file("source.rb", <<-RUBY)
+ print #{modified_env}['MANPATH']
+ RUBY
+ ENV["MANPATH"] = "/foo"
+ ENV["BUNDLER_ORIG_MANPATH"] = "/foo-original"
+ bundle_exec_ruby bundled_app("source.rb")
+ expect(last_command.stdboth).to include("/foo-original")
+ end
+ end
+
+ describe "Bundler.unbundled_env" do
+ let(:modified_env) { "Bundler.unbundled_env" }
+
+ it_behaves_like "an unbundling helper"
+ end
+
+ describe "Bundler.clean_env", :bundler => 2 do
+ let(:modified_env) { "Bundler.clean_env" }
+
+ it_behaves_like "an unbundling helper"
+ end
+
+ describe "Bundler.with_original_env" do
+ it "should set ENV to original_env in the block" do
+ expected = Bundler.original_env
+ actual = Bundler.with_original_env { Bundler::EnvironmentPreserver.env_to_hash(ENV) }
+ expect(actual).to eq(expected)
+ end
+
+ it "should restore the environment after execution" do
+ Bundler.with_original_env do
+ ENV["FOO"] = "hello"
+ end
+
+ expect(ENV).not_to have_key("FOO")
+ end
+ end
+
+ describe "Bundler.with_clean_env", :bundler => 2 do
+ it "should set ENV to unbundled_env in the block" do
+ expected = Bundler.unbundled_env
+
+ actual = Bundler.ui.silence do
+ Bundler.with_clean_env { Bundler::EnvironmentPreserver.env_to_hash(ENV) }
+ end
+
+ expect(actual).to eq(expected)
+ end
+
+ it "should restore the environment after execution" do
+ Bundler.ui.silence do
+ Bundler.with_clean_env { ENV["FOO"] = "hello" }
+ end
+
+ expect(ENV).not_to have_key("FOO")
+ end
+ end
+
+ describe "Bundler.with_unbundled_env" do
+ it "should set ENV to unbundled_env in the block" do
+ expected = Bundler.unbundled_env
+ actual = Bundler.with_unbundled_env { Bundler::EnvironmentPreserver.env_to_hash(ENV) }
+ expect(actual).to eq(expected)
+ end
+
+ it "should restore the environment after execution" do
+ Bundler.with_unbundled_env do
+ ENV["FOO"] = "hello"
+ end
+
+ expect(ENV).not_to have_key("FOO")
+ end
+ end
+
+ describe "Bundler.original_system" do
+ before do
+ create_file("source.rb", <<-'RUBY')
+ Bundler.original_system("ruby", "-e", "exit(42) if ENV['BUNDLE_FOO'] == 'bar'")
+
+ exit $?.exitstatus
+ RUBY
+ end
+
+ it "runs system inside with_original_env" do
+ run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
+ expect($?.exitstatus).to eq(42)
+ end
+ end
+
+ describe "Bundler.clean_system", :bundler => 2 do
+ before do
+ create_file("source.rb", <<-'RUBY')
+ Bundler.ui.silence { Bundler.clean_system("ruby", "-e", "exit(42) unless ENV['BUNDLE_FOO'] == 'bar'") }
+
+ exit $?.exitstatus
+ RUBY
+ end
+
+ it "runs system inside with_clean_env" do
+ run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
+ expect($?.exitstatus).to eq(42)
+ end
+ end
+
+ describe "Bundler.unbundled_system" do
+ before do
+ create_file("source.rb", <<-'RUBY')
+ Bundler.unbundled_system("ruby", "-e", "exit(42) unless ENV['BUNDLE_FOO'] == 'bar'")
+
+ exit $?.exitstatus
+ RUBY
+ end
+
+ it "runs system inside with_unbundled_env" do
+ run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
+ expect($?.exitstatus).to eq(42)
+ end
+ end
+
+ describe "Bundler.original_exec" do
+ before do
+ create_file("source.rb", <<-'RUBY')
+ Process.fork do
+ exit Bundler.original_exec(%(test "\$BUNDLE_FOO" = "bar"))
+ end
+
+ _, status = Process.wait2
+
+ exit(status.exitstatus)
+ RUBY
+ end
+
+ it "runs exec inside with_original_env" do
+ skip "Fork not implemented" if Gem.win_platform?
+
+ run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
+ expect($?.exitstatus).to eq(0)
+ end
+ end
+
+ describe "Bundler.clean_exec", :bundler => 2 do
+ before do
+ create_file("source.rb", <<-'RUBY')
+ Process.fork do
+ exit Bundler.ui.silence { Bundler.clean_exec(%(test "\$BUNDLE_FOO" = "bar")) }
+ end
+
+ _, status = Process.wait2
+
+ exit(status.exitstatus)
+ RUBY
+ end
+
+ it "runs exec inside with_clean_env" do
+ skip "Fork not implemented" if Gem.win_platform?
+
+ run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
+ expect($?.exitstatus).to eq(1)
+ end
+ end
+
+ describe "Bundler.unbundled_exec" do
+ before do
+ create_file("source.rb", <<-'RUBY')
+ Process.fork do
+ exit Bundler.unbundled_exec(%(test "\$BUNDLE_FOO" = "bar"))
+ end
+
+ _, status = Process.wait2
+
+ exit(status.exitstatus)
+ RUBY
+ end
+
+ it "runs exec inside with_clean_env" do
+ skip "Fork not implemented" if Gem.win_platform?
+
+ run_bundler_script({ "BUNDLE_FOO" => "bar" }, bundled_app("source.rb"))
+ expect($?.exitstatus).to eq(1)
+ end
+ end
+end
diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb
index c6bd786347..6a7e2891a6 100644
--- a/spec/bundler/spec_helper.rb
+++ b/spec/bundler/spec_helper.rb
@@ -17,7 +17,6 @@ require "rspec/support/differ"
require_relative "support/builders"
require_relative "support/build_metadata"
-require_relative "support/checksums"
require_relative "support/filters"
require_relative "support/helpers"
require_relative "support/indexes"
@@ -35,7 +34,6 @@ end
RSpec.configure do |config|
config.include Spec::Builders
- config.include Spec::Checksums
config.include Spec::Helpers
config.include Spec::Indexes
config.include Spec::Matchers
@@ -48,9 +46,6 @@ RSpec.configure do |config|
config.silence_filter_announcements = !ENV["TEST_ENV_NUMBER"].nil?
- config.backtrace_exclusion_patterns <<
- %r{./spec/(spec_helper\.rb|support/.+)}
-
config.disable_monkey_patching!
# Since failures cause us to keep a bunch of long strings in memory, stop
@@ -77,6 +72,7 @@ RSpec.configure do |config|
require_relative "support/rubygems_ext"
Spec::Rubygems.test_setup
ENV["BUNDLER_SPEC_RUN"] = "true"
+ ENV["BUNDLER_NO_OLD_RUBYGEMS_WARNING"] = "true"
ENV["BUNDLE_USER_CONFIG"] = ENV["BUNDLE_USER_CACHE"] = ENV["BUNDLE_USER_PLUGIN"] = nil
ENV["BUNDLE_APP_CONFIG"] = nil
ENV["BUNDLE_SILENCE_ROOT_WARNING"] = nil
@@ -87,10 +83,11 @@ RSpec.configure do |config|
# Don't wrap output in tests
ENV["THOR_COLUMNS"] = "10000"
- Spec::Helpers.install_dev_bundler unless ENV["CI"]
-
- extend(Spec::Builders)
+ extend(Spec::Helpers)
+ system_gems :bundler, :path => pristine_system_gem_path
+ end
+ config.before :all do
check_test_gems!
build_repo1
@@ -117,6 +114,6 @@ RSpec.configure do |config|
end
config.after :suite do
- FileUtils.rm_rf Spec::Path.pristine_system_gem_path
+ FileUtils.rm_r Spec::Path.pristine_system_gem_path
end
end
diff --git a/spec/bundler/support/activate.rb b/spec/bundler/support/activate.rb
deleted file mode 100644
index 143b77833d..0000000000
--- a/spec/bundler/support/activate.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-require "rubygems"
-Gem.instance_variable_set(:@ruby, ENV["RUBY"]) if ENV["RUBY"]
-
-require_relative "path"
-bundler_gemspec = Spec::Path.loaded_gemspec
-bundler_gemspec.instance_variable_set(:@full_gem_path, Spec::Path.source_root.to_s)
-bundler_gemspec.activate if bundler_gemspec.respond_to?(:activate)
diff --git a/spec/bundler/support/artifice/compact_index_checksum_mismatch.rb b/spec/bundler/support/artifice/compact_index_checksum_mismatch.rb
index 83b147d2ae..a6545b9ee4 100644
--- a/spec/bundler/support/artifice/compact_index_checksum_mismatch.rb
+++ b/spec/bundler/support/artifice/compact_index_checksum_mismatch.rb
@@ -4,10 +4,10 @@ require_relative "helpers/compact_index"
class CompactIndexChecksumMismatch < CompactIndexAPI
get "/versions" do
- headers "Repr-Digest" => "sha-256=:ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=:"
+ headers "ETag" => quote("123")
headers "Surrogate-Control" => "max-age=2592000, stale-while-revalidate=60"
content_type "text/plain"
- body "content does not match the checksum"
+ body ""
end
end
diff --git a/spec/bundler/support/artifice/compact_index_concurrent_download.rb b/spec/bundler/support/artifice/compact_index_concurrent_download.rb
index 5d55b8a72b..35548f278c 100644
--- a/spec/bundler/support/artifice/compact_index_concurrent_download.rb
+++ b/spec/bundler/support/artifice/compact_index_concurrent_download.rb
@@ -7,12 +7,11 @@ class CompactIndexConcurrentDownload < CompactIndexAPI
versions = File.join(Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
"localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions")
- # Verify the original content hasn't been deleted, e.g. on a retry
- data = File.binread(versions)
- data == "created_at" || raise("Original file should be present with expected content")
+ # Verify the original (empty) content hasn't been deleted, e.g. on a retry
+ File.binread(versions) == "" || raise("Original file should be present and empty")
# Verify this is only requested once for a partial download
- env["HTTP_RANGE"] == "bytes=#{data.bytesize - 1}-" || raise("Missing Range header for expected partial download")
+ env["HTTP_RANGE"] || raise("Missing Range header for expected partial download")
# Overwrite the file in parallel, which should be then overwritten
# after a successful download to prevent corruption
diff --git a/spec/bundler/support/artifice/compact_index_etag_match.rb b/spec/bundler/support/artifice/compact_index_etag_match.rb
deleted file mode 100644
index 08d7b5ec53..0000000000
--- a/spec/bundler/support/artifice/compact_index_etag_match.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "helpers/compact_index"
-
-class CompactIndexEtagMatch < CompactIndexAPI
- get "/versions" do
- raise "ETag header should be present" unless env["HTTP_IF_NONE_MATCH"]
- headers "ETag" => env["HTTP_IF_NONE_MATCH"]
- status 304
- body ""
- end
-end
-
-require_relative "helpers/artifice"
-
-Artifice.activate_with(CompactIndexEtagMatch)
diff --git a/spec/bundler/support/artifice/compact_index_host_redirect.rb b/spec/bundler/support/artifice/compact_index_host_redirect.rb
index 4f82bf3812..9a711186db 100644
--- a/spec/bundler/support/artifice/compact_index_host_redirect.rb
+++ b/spec/bundler/support/artifice/compact_index_host_redirect.rb
@@ -3,7 +3,7 @@
require_relative "helpers/compact_index"
class CompactIndexHostRedirect < CompactIndexAPI
- get "/fetch/actual/gem/:id", host_name: "localgemserver.test" do
+ get "/fetch/actual/gem/:id", :host_name => "localgemserver.test" do
redirect "http://bundler.localgemserver.test#{request.path_info}"
end
diff --git a/spec/bundler/support/artifice/compact_index_partial_update.rb b/spec/bundler/support/artifice/compact_index_partial_update.rb
index f111d91ef9..8c73011346 100644
--- a/spec/bundler/support/artifice/compact_index_partial_update.rb
+++ b/spec/bundler/support/artifice/compact_index_partial_update.rb
@@ -23,7 +23,7 @@ class CompactIndexPartialUpdate < CompactIndexAPI
# Verify that a partial request is made, starting from the index of the
# final byte of the cached file.
unless env["HTTP_RANGE"] == "bytes=#{File.binread(cached_versions_path).bytesize - 1}-"
- raise("Range header should be present, and start from the index of the final byte of the cache. #{env["HTTP_RANGE"].inspect}")
+ raise("Range header should be present, and start from the index of the final byte of the cache.")
end
etag_response do
diff --git a/spec/bundler/support/artifice/compact_index_partial_update_bad_digest.rb b/spec/bundler/support/artifice/compact_index_partial_update_bad_digest.rb
deleted file mode 100644
index ac04336636..0000000000
--- a/spec/bundler/support/artifice/compact_index_partial_update_bad_digest.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "helpers/compact_index"
-
-# The purpose of this Artifice is to test that an incremental response is invalidated
-# and a second request is issued for the full content.
-class CompactIndexPartialUpdateBadDigest < CompactIndexAPI
- def partial_update_bad_digest
- response_body = yield
- if request.env["HTTP_RANGE"]
- headers "Repr-Digest" => "sha-256=:#{Digest::SHA256.base64digest("wrong digest on ranged request")}:"
- else
- headers "Repr-Digest" => "sha-256=:#{Digest::SHA256.base64digest(response_body)}:"
- end
- headers "Surrogate-Control" => "max-age=2592000, stale-while-revalidate=60"
- content_type "text/plain"
- requested_range_for(response_body)
- end
-
- get "/versions" do
- partial_update_bad_digest do
- file = tmp("versions.list")
- FileUtils.rm_f(file)
- file = CompactIndex::VersionsFile.new(file.to_s)
- file.create(gems)
- file.contents([], calculate_info_checksums: true)
- end
- end
-
- get "/info/:name" do
- partial_update_bad_digest do
- gem = gems.find {|g| g.name == params[:name] }
- CompactIndex.info(gem ? gem.versions : [])
- end
- end
-end
-
-require_relative "helpers/artifice"
-
-Artifice.activate_with(CompactIndexPartialUpdateBadDigest)
diff --git a/spec/bundler/support/artifice/compact_index_partial_update_no_digest_not_incremental.rb b/spec/bundler/support/artifice/compact_index_partial_update_no_digest_not_incremental.rb
deleted file mode 100644
index 99bae039f0..0000000000
--- a/spec/bundler/support/artifice/compact_index_partial_update_no_digest_not_incremental.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "helpers/compact_index"
-
-# The purpose of this Artifice is to test that an incremental response is ignored
-# when the digest is not present to verify that the partial response is valid.
-class CompactIndexPartialUpdateNoDigestNotIncremental < CompactIndexAPI
- def partial_update_no_digest
- response_body = yield
- headers "Surrogate-Control" => "max-age=2592000, stale-while-revalidate=60"
- content_type "text/plain"
- requested_range_for(response_body)
- end
-
- get "/versions" do
- partial_update_no_digest do
- file = tmp("versions.list")
- FileUtils.rm_f(file)
- file = CompactIndex::VersionsFile.new(file.to_s)
- file.create(gems)
- lines = file.contents([], calculate_info_checksums: true).split("\n")
- name, versions, checksum = lines.last.split(" ")
-
- # shuffle versions so new versions are not appended to the end
- [*lines[0..-2], [name, versions.split(",").reverse.join(","), checksum].join(" ")].join("\n")
- end
- end
-
- get "/info/:name" do
- partial_update_no_digest do
- gem = gems.find {|g| g.name == params[:name] }
- lines = CompactIndex.info(gem ? gem.versions : []).split("\n")
-
- # shuffle versions so new versions are not appended to the end
- [lines.first, lines.last, *lines[1..-2]].join("\n")
- end
- end
-end
-
-require_relative "helpers/artifice"
-
-Artifice.activate_with(CompactIndexPartialUpdateNoDigestNotIncremental)
diff --git a/spec/bundler/support/artifice/compact_index_partial_update_no_etag_not_incremental.rb b/spec/bundler/support/artifice/compact_index_partial_update_no_etag_not_incremental.rb
new file mode 100644
index 0000000000..20546ba4c3
--- /dev/null
+++ b/spec/bundler/support/artifice/compact_index_partial_update_no_etag_not_incremental.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require_relative "helpers/compact_index"
+
+class CompactIndexPartialUpdateNoEtagNotIncremental < CompactIndexAPI
+ def partial_update_no_etag
+ response_body = yield
+ headers "Surrogate-Control" => "max-age=2592000, stale-while-revalidate=60"
+ content_type "text/plain"
+ requested_range_for(response_body)
+ end
+
+ get "/versions" do
+ partial_update_no_etag do
+ file = tmp("versions.list")
+ FileUtils.rm_f(file)
+ file = CompactIndex::VersionsFile.new(file.to_s)
+ file.create(gems)
+ lines = file.contents([], :calculate_info_checksums => true).split("\n")
+ name, versions, checksum = lines.last.split(" ")
+
+ # shuffle versions so new versions are not appended to the end
+ [*lines[0..-2], [name, versions.split(",").reverse.join(","), checksum].join(" ")].join("\n")
+ end
+ end
+
+ get "/info/:name" do
+ partial_update_no_etag do
+ gem = gems.find {|g| g.name == params[:name] }
+ lines = CompactIndex.info(gem ? gem.versions : []).split("\n")
+
+ # shuffle versions so new versions are not appended to the end
+ [lines.first, lines.last, *lines[1..-2]].join("\n")
+ end
+ end
+end
+
+require_relative "helpers/artifice"
+
+Artifice.activate_with(CompactIndexPartialUpdateNoEtagNotIncremental)
diff --git a/spec/bundler/support/artifice/compact_index_range_ignored.rb b/spec/bundler/support/artifice/compact_index_range_ignored.rb
deleted file mode 100644
index 2303682c1f..0000000000
--- a/spec/bundler/support/artifice/compact_index_range_ignored.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "helpers/compact_index"
-
-class CompactIndexRangeIgnored < CompactIndexAPI
- # Stub the server to not return 304 so that we don't bypass all the logic
- def not_modified?(_checksum)
- false
- end
-
- get "/versions" do
- cached_versions_path = File.join(
- Bundler.rubygems.user_home, ".bundle", "cache", "compact_index",
- "localgemserver.test.80.dd34752a738ee965a2a4298dc16db6c5", "versions"
- )
-
- # Verify a cached copy of the versions file exists
- unless File.binread(cached_versions_path).size > 0
- raise("Cached versions file should be present and have content")
- end
-
- # Verify that a partial request is made, starting from the index of the
- # final byte of the cached file.
- unless env.delete("HTTP_RANGE")
- raise("Expected client to write the full response on the first try")
- end
-
- etag_response do
- file = tmp("versions.list")
- FileUtils.rm_f(file)
- file = CompactIndex::VersionsFile.new(file.to_s)
- file.create(gems)
- file.contents
- end
- end
-end
-
-require_relative "helpers/artifice"
-
-Artifice.activate_with(CompactIndexRangeIgnored)
diff --git a/spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb b/spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb
index 9bd2ca0a9d..acc13a56ff 100644
--- a/spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb
+++ b/spec/bundler/support/artifice/compact_index_wrong_gem_checksum.rb
@@ -7,8 +7,7 @@ class CompactIndexWrongGemChecksum < CompactIndexAPI
etag_response do
name = params[:name]
gem = gems.find {|g| g.name == name }
- # This generates the hexdigest "2222222222222222222222222222222222222222222222222222222222222222"
- checksum = ENV.fetch("BUNDLER_SPEC_#{name.upcase}_CHECKSUM") { "IiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiI=" }
+ checksum = ENV.fetch("BUNDLER_SPEC_#{name.upcase}_CHECKSUM") { "ab" * 22 }
versions = gem ? gem.versions : []
versions.each {|v| v.checksum = checksum }
CompactIndex.info(versions)
diff --git a/spec/bundler/support/artifice/endpoint_500.rb b/spec/bundler/support/artifice/endpoint_500.rb
index b1ed1964c8..d8ab6b65bc 100644
--- a/spec/bundler/support/artifice/endpoint_500.rb
+++ b/spec/bundler/support/artifice/endpoint_500.rb
@@ -2,7 +2,7 @@
require_relative "../path"
-$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gem_path.join("gems/{mustermann,rack,tilt,sinatra,ruby2_keywords,base64}-*/lib")].map(&:to_s))
+$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gem_path.join("gems/{mustermann,rack,tilt,sinatra,ruby2_keywords}-*/lib")].map(&:to_s))
require "sinatra/base"
diff --git a/spec/bundler/support/artifice/endpoint_host_redirect.rb b/spec/bundler/support/artifice/endpoint_host_redirect.rb
index 6ce51bed93..0efb6cda02 100644
--- a/spec/bundler/support/artifice/endpoint_host_redirect.rb
+++ b/spec/bundler/support/artifice/endpoint_host_redirect.rb
@@ -3,7 +3,7 @@
require_relative "helpers/endpoint"
class EndpointHostRedirect < Endpoint
- get "/fetch/actual/gem/:id", host_name: "localgemserver.test" do
+ get "/fetch/actual/gem/:id", :host_name => "localgemserver.test" do
redirect "http://bundler.localgemserver.test#{request.path_info}"
end
diff --git a/spec/bundler/support/artifice/endpoint_mirror_source.rb b/spec/bundler/support/artifice/endpoint_mirror_source.rb
index fed7a746b9..6ea1a77eca 100644
--- a/spec/bundler/support/artifice/endpoint_mirror_source.rb
+++ b/spec/bundler/support/artifice/endpoint_mirror_source.rb
@@ -4,7 +4,7 @@ require_relative "helpers/endpoint"
class EndpointMirrorSource < Endpoint
get "/gems/:id" do
- if request.env["HTTP_X_GEMFILE_SOURCE"] == "https://server.example.org/" && request.env["HTTP_USER_AGENT"].start_with?("bundler")
+ if request.env["HTTP_X_GEMFILE_SOURCE"] == "https://server.example.org/"
File.binread("#{gem_repo1}/gems/#{params[:id]}")
else
halt 500
diff --git a/spec/bundler/support/artifice/fail.rb b/spec/bundler/support/artifice/fail.rb
index 5ddbc4e590..6286e43fbd 100644
--- a/spec/bundler/support/artifice/fail.rb
+++ b/spec/bundler/support/artifice/fail.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
-require_relative "../vendored_net_http"
+require "net/http"
-class Fail < Gem::Net::HTTP
- # Gem::Net::HTTP uses a @newimpl instance variable to decide whether
+class Fail < Net::HTTP
+ # Net::HTTP uses a @newimpl instance variable to decide whether
# to use a legacy implementation. Since we are subclassing
- # Gem::Net::HTTP, we must set it
+ # Net::HTTP, we must set it
@newimpl = true
def request(req, body = nil, &block)
@@ -17,11 +17,13 @@ class Fail < Gem::Net::HTTP
end
def exception(req)
- Errno::ENETUNREACH.new("host down: Bundler spec artifice fail! #{req["PATH_INFO"]}")
+ name = ENV.fetch("BUNDLER_SPEC_EXCEPTION") { "Errno::ENETUNREACH" }
+ const = name.split("::").reduce(Object) {|mod, sym| mod.const_get(sym) }
+ const.new("host down: Bundler spec artifice fail! #{req["PATH_INFO"]}")
end
end
require_relative "helpers/artifice"
-# Replace Gem::Net::HTTP with our failing subclass
+# Replace Net::HTTP with our failing subclass
Artifice.replace_net_http(::Fail)
diff --git a/spec/bundler/support/artifice/helpers/artifice.rb b/spec/bundler/support/artifice/helpers/artifice.rb
index 788268295c..b8c78614fb 100644
--- a/spec/bundler/support/artifice/helpers/artifice.rb
+++ b/spec/bundler/support/artifice/helpers/artifice.rb
@@ -4,7 +4,7 @@
module Artifice
# Activate Artifice with a particular Rack endpoint.
#
- # Calling this method will replace the Gem::Net::HTTP system
+ # Calling this method will replace the Net::HTTP system
# with a replacement that routes all requests to the
# Rack endpoint.
#
@@ -18,11 +18,11 @@ module Artifice
# Deactivate the Artifice replacement.
def self.deactivate
- replace_net_http(::Gem::Net::HTTP)
+ replace_net_http(::Net::HTTP)
end
def self.replace_net_http(value)
- ::Gem::Net.class_eval do
+ ::Net.class_eval do
remove_const(:HTTP)
const_set(:HTTP, value)
end
diff --git a/spec/bundler/support/artifice/helpers/compact_index.rb b/spec/bundler/support/artifice/helpers/compact_index.rb
index f045b71bcf..4df47a9659 100644
--- a/spec/bundler/support/artifice/helpers/compact_index.rb
+++ b/spec/bundler/support/artifice/helpers/compact_index.rb
@@ -4,7 +4,6 @@ require_relative "endpoint"
$LOAD_PATH.unshift Dir[Spec::Path.base_system_gem_path.join("gems/compact_index*/lib")].first.to_s
require "compact_index"
-require "digest"
class CompactIndexAPI < Endpoint
helpers do
@@ -18,10 +17,9 @@ class CompactIndexAPI < Endpoint
def etag_response
response_body = yield
- etag = Digest::MD5.hexdigest(response_body)
- headers "ETag" => quote(etag)
- return if not_modified?(etag)
- headers "Repr-Digest" => "sha-256=:#{Digest::SHA256.base64digest(response_body)}:"
+ checksum = Digest(:MD5).hexdigest(response_body)
+ return if not_modified?(checksum)
+ headers "ETag" => quote(checksum)
headers "Surrogate-Control" => "max-age=2592000, stale-while-revalidate=60"
content_type "text/plain"
requested_range_for(response_body)
@@ -31,16 +29,17 @@ class CompactIndexAPI < Endpoint
raise
end
- def not_modified?(etag)
+ def not_modified?(checksum)
etags = parse_etags(request.env["HTTP_IF_NONE_MATCH"])
- return unless etags.include?(etag)
+ return unless etags.include?(checksum)
+ headers "ETag" => quote(checksum)
status 304
body ""
end
def requested_range_for(response_body)
- ranges = Rack::Utils.get_byte_ranges(env["HTTP_RANGE"], response_body.bytesize)
+ ranges = Rack::Utils.byte_ranges(env, response_body.bytesize)
if ranges
status 206
@@ -68,10 +67,7 @@ class CompactIndexAPI < Endpoint
@gems[gem_repo] ||= begin
specs = Bundler::Deprecate.skip_during do
%w[specs.4.8 prerelease_specs.4.8].map do |filename|
- spec_index = gem_repo.join(filename)
- next [] unless File.exist?(spec_index)
-
- Marshal.load(File.binread(spec_index)).map do |name, version, platform|
+ Marshal.load(File.open(gem_repo.join(filename)).read).map do |name, version, platform|
load_spec(name, version, platform, gem_repo)
end
end.flatten
@@ -79,17 +75,15 @@ class CompactIndexAPI < Endpoint
specs.group_by(&:name).map do |name, versions|
gem_versions = versions.map do |spec|
- deps = spec.runtime_dependencies.map do |d|
+ deps = spec.dependencies.select {|d| d.type == :runtime }.map do |d|
reqs = d.requirement.requirements.map {|r| r.join(" ") }.join(", ")
CompactIndex::Dependency.new(d.name, reqs)
end
- begin
- checksum = ENV.fetch("BUNDLER_SPEC_#{name.upcase}_CHECKSUM") do
- Digest(:SHA256).file("#{gem_repo}/gems/#{spec.original_name}.gem").hexdigest
- end
- rescue StandardError
- checksum = nil
- end
+ checksum = begin
+ Digest(:SHA256).file("#{gem_repo}/gems/#{spec.original_name}.gem").base64digest
+ rescue StandardError
+ nil
+ end
CompactIndex::GemVersion.new(spec.version.version, spec.platform.to_s, checksum, nil,
deps, spec.required_ruby_version.to_s, spec.required_rubygems_version.to_s)
end
diff --git a/spec/bundler/support/artifice/helpers/endpoint.rb b/spec/bundler/support/artifice/helpers/endpoint.rb
index 329d2d807a..fc0381dc38 100644
--- a/spec/bundler/support/artifice/helpers/endpoint.rb
+++ b/spec/bundler/support/artifice/helpers/endpoint.rb
@@ -2,7 +2,7 @@
require_relative "../../path"
-$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gem_path.join("gems/{mustermann,rack,tilt,sinatra,ruby2_keywords,base64}-*/lib")].map(&:to_s))
+$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gem_path.join("gems/{mustermann,rack,tilt,sinatra,ruby2_keywords}-*/lib")].map(&:to_s))
require "sinatra/base"
@@ -62,17 +62,17 @@ class Endpoint < Sinatra::Base
return [] if gem_names.nil? || gem_names.empty?
all_specs = %w[specs.4.8 prerelease_specs.4.8].map do |filename|
- Marshal.load(File.binread(gem_repo.join(filename)))
+ Marshal.load(File.open(gem_repo.join(filename)).read)
end.inject(:+)
all_specs.map do |name, version, platform|
spec = load_spec(name, version, platform, gem_repo)
next unless gem_names.include?(spec.name)
{
- name: spec.name,
- number: spec.version.version,
- platform: spec.platform.to_s,
- dependencies: spec.runtime_dependencies.map do |dep|
+ :name => spec.name,
+ :number => spec.version.version,
+ :platform => spec.platform.to_s,
+ :dependencies => spec.dependencies.select {|dep| dep.type == :runtime }.map do |dep|
[dep.name, dep.requirement.requirements.map {|a| a.join(" ") }.join(", ")]
end,
}
diff --git a/spec/bundler/support/artifice/helpers/rack_request.rb b/spec/bundler/support/artifice/helpers/rack_request.rb
index 05ff034463..c4a07812a6 100644
--- a/spec/bundler/support/artifice/helpers/rack_request.rb
+++ b/spec/bundler/support/artifice/helpers/rack_request.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require "rack/test"
-require_relative "../../vendored_net_http"
+require "net/http"
module Artifice
module Net
@@ -16,25 +16,25 @@ module Artifice
end
end
- class HTTP < ::Gem::Net::HTTP
+ class HTTP < ::Net::HTTP
class << self
attr_accessor :endpoint
end
- # Gem::Net::HTTP uses a @newimpl instance variable to decide whether
+ # Net::HTTP uses a @newimpl instance variable to decide whether
# to use a legacy implementation. Since we are subclassing
- # Gem::Net::HTTP, we must set it
+ # Net::HTTP, we must set it
@newimpl = true
# We don't need to connect, so blank out this method
def connect
end
- # Replace the Gem::Net::HTTP request method with a method
+ # Replace the Net::HTTP request method with a method
# that converts the request into a Rack request and
# dispatches it to the Rack endpoint.
#
- # @param [Net::HTTPRequest] req A Gem::Net::HTTPRequest
+ # @param [Net::HTTPRequest] req A Net::HTTPRequest
# object, or one if its subclasses
# @param [optional, String, #read] body This should
# be sent as "rack.input". If it's a String, it will
@@ -42,7 +42,7 @@ module Artifice
# @return [Net::HTTPResponse]
#
# @yield [Net::HTTPResponse] If a block is provided,
- # this method will yield the Gem::Net::HTTPResponse to
+ # this method will yield the Net::HTTPResponse to
# it after the body is read.
def request(req, body = nil, &block)
rack_request = RackRequest.new(self.class.endpoint)
@@ -56,17 +56,17 @@ module Artifice
body_stream_contents = req.body_stream.read if req.body_stream
response = rack_request.request("#{prefix}#{req.path}",
- { method: req.method, input: body || req.body || body_stream_contents })
+ { :method => req.method, :input => body || req.body || body_stream_contents })
make_net_http_response(response, &block)
end
private
- # This method takes a Rack response and creates a Gem::Net::HTTPResponse
+ # This method takes a Rack response and creates a Net::HTTPResponse
# Instead of trying to mock HTTPResponse directly, we just convert
# the Rack response into a String that looks like a normal HTTP
- # response and call Gem::Net::HTTPResponse.read_new
+ # response and call Net::HTTPResponse.read_new
#
# @param [Array(#to_i, Hash, #each)] response a Rack response
# @return [Net::HTTPResponse]
@@ -86,8 +86,8 @@ module Artifice
response_string << "" << body
- response_io = ::Gem::Net::BufferedIO.new(StringIO.new(response_string.join("\n")))
- res = ::Gem::Net::HTTPResponse.read_new(response_io)
+ response_io = ::Net::BufferedIO.new(StringIO.new(response_string.join("\n")))
+ res = ::Net::HTTPResponse.read_new(response_io)
res.reading_body(response_io, true) do
yield res if block_given?
diff --git a/spec/bundler/support/artifice/used_cassettes.txt b/spec/bundler/support/artifice/used_cassettes.txt
new file mode 100644
index 0000000000..a96efc790d
--- /dev/null
+++ b/spec/bundler/support/artifice/used_cassettes.txt
@@ -0,0 +1,20908 @@
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ffi-1.15.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/capybara/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/selenium-webdriver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/xpath/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/culerity/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uglifier/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/matrix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyzip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/childprocess/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libwebsocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-active_record/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/therubyracer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gherkin3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-wire/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/event-bus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-formatter-dots/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-html-formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-gherkin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-cucumber-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-messages/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-create-meta/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-uname/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/database_cleaner-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libv8/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trollop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/c21e/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag_expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cucumber-tag-expressions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-protobuf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/protobuf-cucumber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/curses/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis-namespace/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/resque/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rufus-scheduler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mono_logger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/et-orbi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/vegas/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fugit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/raabro/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.2.3.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-4.5.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mono_logger-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/ruby2_keywords-0.0.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tilt-2.0.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/mustermann-1.1.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/redis-namespace-1.6.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/vegas-0.1.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-protection-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/sinatra-2.1.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/tzinfo-2.0.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-1.24.1.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rufus-scheduler-2.0.24.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/resque-scheduler-2.2.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/climate_control/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cocaine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/paperclip/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/terrapin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_aws/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mocha/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thoughtbot-shoulda/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metaclass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/right_http_connection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gxapi_rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-api-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sass-listen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/addressable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/extlib/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/signet/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpadapter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/liquid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/launchy/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/autoparse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sinatra/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uuidtools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jwt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/retriable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/googleauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hurley/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoist/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/representable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-generator/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sassc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fchange/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-fsevent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-inotify/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rb-kqueue/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_dep/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-io/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/public_suffix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/english/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-protection/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongrel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mustermann/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multipart-post/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_http/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-net_http_persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-em_synchrony/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-httpclient/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-patron/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday-rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/logging/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/os/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hooks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/uber/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/declarative-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/trailblazer-option/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrick/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/google-apis-discovery_v1/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gems/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/cgi_multipart_eof_fix/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/fastthread/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gem_plugin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/escape_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/excon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-http-persistent/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/flexmock/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/little-plugger/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hashie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faraday_middleware/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rash/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/oauth2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/roauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/httpauth/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.10.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongoid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongodb-mongo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/durran-validatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mislav-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mongo_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/leshill-will_paginate/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bson/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/origin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/moped/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby2_keywords/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pry/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/optionable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/connection_pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coderay/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spoon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coveralls/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/metasploit-erd/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/yard/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-graphviz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/choice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/webrat/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/railties/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-mocks/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-core/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-expectations/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-collection_matchers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-support/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov-html/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/docile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/lockfile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/colorize/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/simplecov_json_formatter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rest-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tins/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/term-ansicolor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activeresource/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionwebservice/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionview/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activejob/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actioncable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activestorage/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actiontext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/actionmailbox/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-ssl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rexml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nokogiri/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hpricot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-test/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/abstract/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rdoc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/treetop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-mount/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack-cache/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sprockets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/journey/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-deprecated_sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-dom-testing/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-html-sanitizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activerecord-deprecated_finders/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/arel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/netrc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-cookie/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/http-accept/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sync/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-format/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rails-observers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-serializers-xml/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/erubi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/marcel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_mime/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mimemagic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activemodel-globalid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-rails/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/em-hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faye-websocket/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-driver/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/redis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nio4r/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facets/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/polyglot/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/weakling/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mini_portile2/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pkg-config/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/racc/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multimap/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/loofah/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hike/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tilt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mime-types-data/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/domain_name/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-essentials/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sqlite3/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tlsmail/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hiredis/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/text-hyphen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/eventmachine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timers/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/facter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-extras/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-fsm/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-pool/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/nenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/celluloid-supervision/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rspec-logsplit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/websocket-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ftp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/crass/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake-compiler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hitimes/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/CFPropertyList/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sys-admin/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32console/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-dir/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-api/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/windows-pr/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hocon/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/win32-security/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/dotenv-deployment/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coffee-script-source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/daemons/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/execjs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/time/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/configuration/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/mkrf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-protocol/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unf_ext/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rainbow/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/backports/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/powerpack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-progressbar/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/astrolabe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jaro_winkler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/parallel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubocop-ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/regexp_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/psych/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/test-unit/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/libxml-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi-win32-extensions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/date/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/io-wait/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/timeout/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ast/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/slop/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jar-dependencies/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strscan/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/power_assert/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pattern-match/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/maven-tools/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby-maven-libs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/virtus/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/axiom-types/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/coercible/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equalizer/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/descendants_tracker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/adamantium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ice_nine/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memoizable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bundler/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/bundler-2.3.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/concurrent-ruby-1.1.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.9.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.12.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/activesupport/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/i18n/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/faker/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/builder/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/memcache-client/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tzinfo/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thread_safe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/minitest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/method_source/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/zeitwerk/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/concurrent-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/multi_json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/pastel/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/thor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-pager/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-screen/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-tree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/RubyInline/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/hoe/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ZenTest/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/atomic/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/functional-ruby/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ruby_parser/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/equatable/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-which/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/tty-color/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ref/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/verse/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rubyforge/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/gemcutter/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/sexp_processor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ParseTree/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode_utils/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/unicode-display_width/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/strings-ansi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rake/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-scp/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json_pure/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/SexpProcessor/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/spruz/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/net-ssh/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/jruby-pageant/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rbnacl-libsodium/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/bcrypt_pbkdf/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/needle/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/ffi/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/i18n-0.6.11.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/multi_json-1.15.0.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/activesupport-3.2.22.5.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/faker-1.1.2.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/diff-lcs/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/diff-lcs-1.4.4.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/rack/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/info/json/GET/response
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/request
+spec/support/artifice/vcr_cassettes/realworld/rubygems.org/gems/rack-2.0.9.gem/GET/response
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/request
+spec/support/artifice/vcr_cassettes/realworld/index.rubygems.org/versions/GET/response
diff --git a/spec/bundler/support/artifice/vcr.rb b/spec/bundler/support/artifice/vcr.rb
index 2386a4c6b7..6a346f1ff9 100644
--- a/spec/bundler/support/artifice/vcr.rb
+++ b/spec/bundler/support/artifice/vcr.rb
@@ -1,13 +1,13 @@
# frozen_string_literal: true
-require_relative "../vendored_net_http"
+require "net/http"
require_relative "../path"
-CASSETTE_PATH = "#{Spec::Path.spec_dir}/support/artifice/vcr_cassettes".freeze
-USED_CASSETTES_PATH = "#{Spec::Path.spec_dir}/support/artifice/used_cassettes.txt".freeze
+CASSETTE_PATH = "#{Spec::Path.spec_dir}/support/artifice/vcr_cassettes"
+USED_CASSETTES_PATH = "#{Spec::Path.spec_dir}/support/artifice/used_cassettes.txt"
CASSETTE_NAME = ENV.fetch("BUNDLER_SPEC_VCR_CASSETTE_NAME") { "realworld" }
-class BundlerVCRHTTP < Gem::Net::HTTP
+class BundlerVCRHTTP < Net::HTTP
class RequestHandler
attr_reader :http, :request, :body, :response_block
def initialize(http, request, body = nil, &response_block)
@@ -41,8 +41,8 @@ class BundlerVCRHTTP < Gem::Net::HTTP
def recorded_response
File.open(request_pair_paths.last, "rb:ASCII-8BIT") do |response_file|
- response_io = ::Gem::Net::BufferedIO.new(response_file)
- ::Gem::Net::HTTPResponse.read_new(response_io).tap do |response|
+ response_io = ::Net::BufferedIO.new(response_file)
+ ::Net::HTTPResponse.read_new(response_io).tap do |response|
response.decode_content = request.decode_content if request.respond_to?(:decode_content)
response.uri = request.uri
@@ -148,5 +148,5 @@ end
require_relative "helpers/artifice"
-# Replace Gem::Net::HTTP with our VCR subclass
+# Replace Net::HTTP with our VCR subclass
Artifice.replace_net_http(BundlerVCRHTTP)
diff --git a/spec/bundler/support/artifice/windows.rb b/spec/bundler/support/artifice/windows.rb
index fea991c071..4d90e0a426 100644
--- a/spec/bundler/support/artifice/windows.rb
+++ b/spec/bundler/support/artifice/windows.rb
@@ -2,7 +2,7 @@
require_relative "../path"
-$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gem_path.join("gems/{mustermann,rack,tilt,sinatra,ruby2_keywords,base64}-*/lib")].map(&:to_s))
+$LOAD_PATH.unshift(*Dir[Spec::Path.base_system_gem_path.join("gems/{mustermann,rack,tilt,sinatra,ruby2_keywords}-*/lib")].map(&:to_s))
require "sinatra/base"
diff --git a/spec/bundler/support/build_metadata.rb b/spec/bundler/support/build_metadata.rb
index 189100edb7..98d8ac23c8 100644
--- a/spec/bundler/support/build_metadata.rb
+++ b/spec/bundler/support/build_metadata.rb
@@ -10,20 +10,20 @@ module Spec
def write_build_metadata(dir: source_root)
build_metadata = {
- git_commit_sha: git_commit_sha,
- built_at: loaded_gemspec.date.utc.strftime("%Y-%m-%d"),
- release: true,
+ :git_commit_sha => git_commit_sha,
+ :built_at => loaded_gemspec.date.utc.strftime("%Y-%m-%d"),
+ :release => true,
}
- replace_build_metadata(build_metadata, dir: dir)
+ replace_build_metadata(build_metadata, dir: dir) # rubocop:disable Style/HashSyntax
end
def reset_build_metadata(dir: source_root)
build_metadata = {
- release: false,
+ :release => false,
}
- replace_build_metadata(build_metadata, dir: dir)
+ replace_build_metadata(build_metadata, dir: dir) # rubocop:disable Style/HashSyntax
end
private
@@ -41,7 +41,7 @@ module Spec
end
def git_commit_sha
- ruby_core_tarball? ? "unknown" : git("rev-parse --short HEAD", source_root).strip
+ ruby_core_tarball? ? "unknown" : sys_exec("git rev-parse --short HEAD", :dir => source_root).strip
end
extend self
diff --git a/spec/bundler/support/builders.rb b/spec/bundler/support/builders.rb
index a187d2ae48..dfc7139523 100644
--- a/spec/bundler/support/builders.rb
+++ b/spec/bundler/support/builders.rb
@@ -5,11 +5,6 @@ require "shellwords"
module Spec
module Builders
- def self.extended(mod)
- mod.extend Path
- mod.extend Helpers
- end
-
def self.constantize(name)
name.delete("-").upcase
end
@@ -22,11 +17,9 @@ module Spec
Gem::Platform.new(platform)
end
- def rake_version
- "13.2.1"
- end
-
def build_repo1
+ rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first
+
build_repo gem_repo1 do
FileUtils.cp rake_path, "#{gem_repo1}/gems/"
@@ -35,28 +28,28 @@ module Spec
build_gem "puma"
build_gem "minitest"
- build_gem "myrack", %w[0.9.1 1.0.0] do |s|
- s.executables = "myrackup"
- s.post_install_message = "Myrack's post install message"
+ build_gem "rack", %w[0.9.1 1.0.0] do |s|
+ s.executables = "rackup"
+ s.post_install_message = "Rack's post install message"
end
build_gem "thin" do |s|
- s.add_dependency "myrack"
+ s.add_dependency "rack"
s.post_install_message = "Thin's post install message"
end
- build_gem "myrack-obama" do |s|
- s.add_dependency "myrack"
- s.post_install_message = "Myrack-obama's post install message"
+ build_gem "rack-obama" do |s|
+ s.add_dependency "rack"
+ s.post_install_message = "Rack-obama's post install message"
end
- build_gem "myrack_middleware", "1.0" do |s|
- s.add_dependency "myrack", "0.9.1"
+ build_gem "rack_middleware", "1.0" do |s|
+ s.add_dependency "rack", "0.9.1"
end
build_gem "rails", "2.3.2" do |s|
s.executables = "rails"
- s.add_dependency "rake", rake_version
+ s.add_dependency "rake", "13.0.1"
s.add_dependency "actionpack", "2.3.2"
s.add_dependency "activerecord", "2.3.2"
s.add_dependency "actionmailer", "2.3.2"
@@ -80,66 +73,84 @@ module Spec
s.add_dependency "activesupport", ">= 2.0.0"
end
- build_gem "rspec", "1.2.7", no_default: true do |s|
+ build_gem "rspec", "1.2.7", :no_default => true do |s|
s.write "lib/spec.rb", "SPEC = '1.2.7'"
end
- build_gem "myrack-test", no_default: true do |s|
- s.write "lib/myrack/test.rb", "MYRACK_TEST = '1.0'"
+ build_gem "rack-test", :no_default => true do |s|
+ s.write "lib/rack/test.rb", "RACK_TEST = '1.0'"
+ end
+
+ build_gem "platform_specific" do |s|
+ s.platform = Gem::Platform.local
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Gem::Platform.local}'"
end
build_gem "platform_specific" do |s|
s.platform = "java"
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 JAVA'"
end
build_gem "platform_specific" do |s|
s.platform = "ruby"
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 RUBY'"
end
build_gem "platform_specific" do |s|
s.platform = "x86-mswin32"
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0 x86-mswin32'"
end
build_gem "platform_specific" do |s|
s.platform = "x64-mswin64"
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0 x64-mswin64'"
end
build_gem "platform_specific" do |s|
s.platform = "x86-mingw32"
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0 x86-mingw32'"
end
build_gem "platform_specific" do |s|
s.platform = "x64-mingw32"
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0 x64-mingw32'"
end
build_gem "platform_specific" do |s|
s.platform = "x64-mingw-ucrt"
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0 x64-mingw-ucrt'"
end
build_gem "platform_specific" do |s|
s.platform = "x86-darwin-100"
+ s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 x86-darwin-100'"
end
build_gem "only_java", "1.0" do |s|
s.platform = "java"
+ s.write "lib/only_java.rb", "ONLY_JAVA = '1.0.0 JAVA'"
end
build_gem "only_java", "1.1" do |s|
s.platform = "java"
+ s.write "lib/only_java.rb", "ONLY_JAVA = '1.1.0 JAVA'"
end
build_gem "nokogiri", "1.4.2"
build_gem "nokogiri", "1.4.2" do |s|
s.platform = "java"
+ s.write "lib/nokogiri.rb", "NOKOGIRI = '1.4.2 JAVA'"
s.add_dependency "weakling", ">= 0.0.3"
end
build_gem "laduradura", "5.15.2"
build_gem "laduradura", "5.15.2" do |s|
s.platform = "java"
+ s.write "lib/laduradura.rb", "LADURADURA = '5.15.2 JAVA'"
end
build_gem "laduradura", "5.15.3" do |s|
s.platform = "java"
+ s.write "lib/laduradura.rb", "LADURADURA = '5.15.2 JAVA'"
end
build_gem "weakling", "0.0.3"
@@ -153,7 +164,7 @@ module Spec
build_gem "bundler", "0.9" do |s|
s.executables = "bundle"
- s.write "bin/bundle", "#!/usr/bin/env ruby\nputs 'FAIL'"
+ s.write "bin/bundle", "puts 'FAIL'"
end
# The bundler 0.8 gem has a rubygems plugin that always loads :(
@@ -180,36 +191,30 @@ module Spec
end
end
- def build_repo2(**kwargs, &blk)
+ def build_repo2(&blk)
FileUtils.rm_rf gem_repo2
FileUtils.cp_r gem_repo1, gem_repo2
- update_repo2(**kwargs, &blk) if block_given?
+ update_repo2(&blk) if block_given?
end
# A repo that has no pre-installed gems included. (The caller completely
# determines the contents with the block.)
- def build_repo3(**kwargs, &blk)
- build_empty_repo gem_repo3, **kwargs, &blk
- end
-
- # Like build_repo3, this is a repo that has no pre-installed gems included.
- # We have two different methods for situations where two different empty
- # sources are needed.
- def build_repo4(**kwargs, &blk)
- build_empty_repo gem_repo4, **kwargs, &blk
+ def build_repo4(&blk)
+ FileUtils.rm_rf gem_repo4
+ build_repo(gem_repo4, &blk)
end
def update_repo4(&blk)
update_repo(gem_repo4, &blk)
end
- def update_repo2(**kwargs, &blk)
- update_repo(gem_repo2, **kwargs, &blk)
+ def update_repo2(&blk)
+ update_repo(gem_repo2, &blk)
end
def build_security_repo
build_repo security_repo do
- build_gem "myrack"
+ build_gem "rack"
build_gem "signed_gem" do |s|
cert = "signing-cert.pem"
@@ -222,18 +227,21 @@ module Spec
end
end
- def build_repo(path, **kwargs, &blk)
+ def build_repo(path, &blk)
return if File.directory?(path)
FileUtils.mkdir_p("#{path}/gems")
- update_repo(path,**kwargs, &blk)
+ update_repo(path, &blk)
end
def check_test_gems!
+ rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first
+
if rake_path.nil?
- FileUtils.rm_rf(base_system_gems)
+ FileUtils.rm_rf(Path.base_system_gems)
Spec::Rubygems.install_test_deps
+ rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first
end
if rake_path.nil?
@@ -241,22 +249,16 @@ module Spec
end
end
- def update_repo(path, build_compact_index: true)
- exempted_caller = Gem.ruby_version >= Gem::Version.new("3.4.0.dev") ? "#{Module.nesting.first}#build_repo" : "build_repo"
- if path == gem_repo1 && caller_locations(1, 1).first.label != exempted_caller
+ def update_repo(path)
+ if path == gem_repo1 && caller.first.split(" ").last == "`build_repo`"
raise "Updating gem_repo1 is unsupported -- use gem_repo2 instead"
end
return unless block_given?
@_build_path = "#{path}/gems"
@_build_repo = File.basename(path)
yield
- with_gem_path_as base_system_gem_path do
- Dir[base_system_gem_path.join("gems/rubygems-generate_index*/lib")].first ||
- raise("Could not find rubygems-generate_index lib directory in #{base_system_gem_path}")
-
- command = "generate_index"
- command += " --no-compact" if !build_compact_index && gem_command(command + " --help").include?("--[no-]compact")
- gem_command command, dir: path
+ with_gem_path_as Path.base_system_gem_path do
+ gem_command :generate_index, :dir => path
end
ensure
@_build_path = nil
@@ -286,10 +288,6 @@ module Spec
build_with(LibBuilder, name, args, &blk)
end
- def build_bundler(*args, &blk)
- build_with(BundlerBuilder, "bundler", args, &blk)
- end
-
def build_gem(name, *args, &blk)
build_with(GemBuilder, name, args, &blk)
end
@@ -313,11 +311,6 @@ module Spec
private
- def build_empty_repo(gem_repo, **kwargs, &blk)
- FileUtils.rm_rf gem_repo
- build_repo(gem_repo, **kwargs, &blk)
- end
-
def build_with(builder, name, args, &blk)
@_build_path ||= nil
@_build_repo ||= nil
@@ -400,49 +393,6 @@ module Spec
alias_method :dep, :runtime
end
- class BundlerBuilder
- attr_writer :required_ruby_version
-
- def initialize(context, name, version)
- raise "can only build bundler" unless name == "bundler"
-
- @context = context
- @version = version || Bundler::VERSION
- end
-
- def _build(options = {})
- full_name = "bundler-#{@version}"
- build_path = @context.tmp + full_name
- bundler_path = build_path + "#{full_name}.gem"
-
- FileUtils.mkdir_p build_path
-
- @context.shipped_files.each do |shipped_file|
- target_shipped_file = shipped_file
- target_shipped_file = shipped_file.sub(/\Alibexec/, "exe") if @context.ruby_core?
- target_shipped_file = build_path + target_shipped_file
- target_shipped_dir = File.dirname(target_shipped_file)
- FileUtils.mkdir_p target_shipped_dir unless File.directory?(target_shipped_dir)
- FileUtils.cp shipped_file, target_shipped_file, preserve: true
- end
-
- @context.replace_version_file(@version, dir: build_path)
- @context.replace_required_ruby_version(@required_ruby_version, dir: build_path) if @required_ruby_version
-
- Spec::BuildMetadata.write_build_metadata(dir: build_path)
-
- @context.gem_command "build #{@context.relative_gemspec}", dir: build_path
-
- if block_given?
- yield(bundler_path)
- else
- FileUtils.mv bundler_path, options[:path]
- end
- ensure
- build_path.rmtree
- end
- end
-
class LibBuilder
def initialize(context, name, version)
@context = context
@@ -456,7 +406,6 @@ module Spec
s.email = "foo@bar.baz"
s.homepage = "http://example.com"
s.license = "MIT"
- s.required_ruby_version = ">= 3.0"
end
@files = {}
end
@@ -473,17 +422,24 @@ module Spec
@spec.executables = Array(val)
@spec.executables.each do |file|
executable = "#{@spec.bindir}/#{file}"
- shebang = "#!/usr/bin/env ruby\n"
+ shebang = if Bundler.current_ruby.jruby?
+ "#!/usr/bin/env jruby\n"
+ else
+ "#!/usr/bin/env ruby\n"
+ end
@spec.files << executable
write executable, "#{shebang}require_relative '../lib/#{@name}' ; puts #{Builders.constantize(@name)}"
end
end
def add_c_extension
+ require_paths << "ext"
extensions << "ext/extconf.rb"
write "ext/extconf.rb", <<-RUBY
require "mkmf"
+ $extout = "$(topdir)/" + RbConfig::CONFIG["EXTOUT"]
+
extension_name = "#{name}_c"
if extra_lib_dir = with_config("ext-lib")
# add extra libpath if --with-ext-lib is
@@ -508,6 +464,7 @@ module Spec
if options[:rubygems_version]
@spec.rubygems_version = options[:rubygems_version]
+ def @spec.mark_version; end
def @spec.validate(*); end
end
@@ -534,10 +491,10 @@ module Spec
end
@files.each do |file, source|
- full_path = Pathname.new(path).join(file)
- FileUtils.mkdir_p(full_path.dirname)
- File.open(full_path, "w") {|f| f.puts source }
- FileUtils.chmod("+x", full_path) if @spec.executables.map {|exe| "#{@spec.bindir}/#{exe}" }.include?(file)
+ file = Pathname.new(path).join(file)
+ FileUtils.mkdir_p(file.dirname)
+ File.open(file, "w") {|f| f.puts source }
+ File.chmod("+x", file) if @spec.executables.map {|exe| "#{@spec.bindir}/#{exe}" }.include?(file)
end
path
end
@@ -564,7 +521,7 @@ module Spec
default_branch = options[:default_branch] || "main"
path = options[:path] || _default_path
source = options[:source] || "git@#{path}"
- super(options.merge(path: path, source: source))
+ super(options.merge(:path => path, :source => source))
@context.git("config --global init.defaultBranch #{default_branch}", path)
@context.git("init", path)
@context.git("add *", path)
@@ -578,7 +535,7 @@ module Spec
class GitBareBuilder < LibBuilder
def _build(options)
path = options[:path] || _default_path
- super(options.merge(path: path))
+ super(options.merge(:path => path))
@context.git("init --bare", path)
end
end
@@ -603,7 +560,7 @@ module Spec
_default_files.keys.each do |path|
_default_files[path] += "\n#{Builders.constantize(name)}_PREV_REF = '#{current_ref}'"
end
- super(options.merge(path: libpath, gemspec: update_gemspec, source: source))
+ super(options.merge(:path => libpath, :gemspec => update_gemspec, :source => source))
@context.git("commit -am BUMP", libpath)
end
end
@@ -626,7 +583,7 @@ module Spec
class GemBuilder < LibBuilder
def _build(opts)
lib_path = opts[:lib_path] || @context.tmp(".tmp/#{@spec.full_name}")
- lib_path = super(opts.merge(path: lib_path, no_default: opts[:no_default]))
+ lib_path = super(opts.merge(:path => lib_path, :no_default => opts[:no_default]))
destination = opts[:path] || _default_path
FileUtils.mkdir_p(lib_path.join(destination))
@@ -635,16 +592,16 @@ module Spec
Bundler.rubygems.build(@spec, opts[:skip_validation])
end
elsif opts[:skip_validation]
- @context.gem_command "build --force #{@spec.name}", dir: lib_path
+ @context.gem_command "build --force #{@spec.name}", :dir => lib_path
else
- @context.gem_command "build #{@spec.name}", dir: lib_path
+ @context.gem_command "build #{@spec.name}", :dir => lib_path
end
gem_path = File.expand_path("#{@spec.full_name}.gem", lib_path)
if opts[:to_system]
- @context.system_gems gem_path, default: opts[:default]
+ @context.system_gems gem_path, :default => opts[:default]
elsif opts[:to_bundle]
- @context.system_gems gem_path, path: @context.default_bundle_path
+ @context.system_gems gem_path, :path => @context.default_bundle_path
else
FileUtils.mv(gem_path, destination)
end
@@ -664,7 +621,7 @@ module Spec
end
end
- TEST_CERT = <<~CERT
+ TEST_CERT = <<-CERT.gsub(/^\s*/, "")
-----BEGIN CERTIFICATE-----
MIIDMjCCAhqgAwIBAgIBATANBgkqhkiG9w0BAQUFADAnMQwwCgYDVQQDDAN5b3Ux
FzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMB4XDTE1MDIwODAwMTIyM1oXDTQyMDYy
@@ -687,7 +644,7 @@ module Spec
-----END CERTIFICATE-----
CERT
- TEST_PKEY = <<~PKEY
+ TEST_PKEY = <<-PKEY.gsub(/^\s*/, "")
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA2W8V2k3jdzgMxL0mjTqbRruTdtDcdZDXKtiFkyLvsXUXvc2k
GSdgcjMOS1CkafqGz/hAUlPibjM0QEXjtQuMdTmdMrmuORLeeIZhSO+HdkTNV6j3
diff --git a/spec/bundler/support/bundle.rb b/spec/bundler/support/bundle.rb
index 5d6d658040..5f808531ff 100644
--- a/spec/bundler/support/bundle.rb
+++ b/spec/bundler/support/bundle.rb
@@ -1,5 +1,10 @@
# frozen_string_literal: true
-require_relative "activate"
+require "rubygems"
+Gem.instance_variable_set(:@ruby, ENV["RUBY"]) if ENV["RUBY"]
+require_relative "path"
+bundler_gemspec = Spec::Path.loaded_gemspec
+bundler_gemspec.instance_variable_set(:@full_gem_path, Spec::Path.source_root)
+bundler_gemspec.activate if bundler_gemspec.respond_to?(:activate)
load File.expand_path("bundle", Spec::Path.bindir)
diff --git a/spec/bundler/support/checksums.rb b/spec/bundler/support/checksums.rb
deleted file mode 100644
index f3aa13ca9f..0000000000
--- a/spec/bundler/support/checksums.rb
+++ /dev/null
@@ -1,126 +0,0 @@
-# frozen_string_literal: true
-
-module Spec
- module Checksums
- class ChecksumsBuilder
- def initialize(enabled = true, &block)
- @enabled = enabled
- @checksums = {}
- yield self if block_given?
- end
-
- def initialize_copy(original)
- super
- @checksums = @checksums.dup
- end
-
- def checksum(repo, name, version, platform = Gem::Platform::RUBY)
- name_tuple = Gem::NameTuple.new(name, version, platform)
- gem_file = File.join(repo, "gems", "#{name_tuple.full_name}.gem")
- File.open(gem_file, "rb") do |f|
- register(name_tuple, Bundler::Checksum.from_gem(f, "#{gem_file} (via ChecksumsBuilder#checksum)"))
- end
- end
-
- def no_checksum(name, version, platform = Gem::Platform::RUBY)
- name_tuple = Gem::NameTuple.new(name, version, platform)
- register(name_tuple, nil)
- end
-
- def delete(name, platform = nil)
- @checksums.reject! {|k, _| k.name == name && (platform.nil? || k.platform == platform) }
- end
-
- def to_s
- return "" unless @enabled
-
- locked_checksums = @checksums.map do |name_tuple, checksum|
- checksum &&= " #{checksum.to_lock}"
- " #{name_tuple.lock_name}#{checksum}\n"
- end
-
- "\nCHECKSUMS\n#{locked_checksums.sort.join}"
- end
-
- private
-
- def register(name_tuple, checksum)
- delete(name_tuple.name, name_tuple.platform)
- @checksums[name_tuple] = checksum
- end
- end
-
- def checksums_section(enabled = true, &block)
- ChecksumsBuilder.new(enabled, &block)
- end
-
- def checksums_section_when_enabled(target_lockfile = nil, &block)
- begin
- enabled = (target_lockfile || lockfile).match?(/^CHECKSUMS$/)
- rescue Errno::ENOENT
- enabled = Bundler.feature_flag.bundler_3_mode?
- end
- checksums_section(enabled, &block)
- end
-
- def checksum_to_lock(*args)
- checksums_section do |c|
- c.checksum(*args)
- end.to_s.sub(/^CHECKSUMS\n/, "").strip
- end
-
- def checksum_digest(*args)
- checksum_to_lock(*args).split(Bundler::Checksum::ALGO_SEPARATOR, 2).last
- end
-
- # if prefixes is given, removes all checksums where the line
- # has any of the prefixes on the line before the checksum
- # otherwise, removes all checksums from the lockfile
- def remove_checksums_from_lockfile(lockfile, *prefixes)
- head, remaining = lockfile.split(/^CHECKSUMS$/, 2)
- return lockfile unless remaining
- checksums, tail = remaining.split("\n\n", 2)
-
- prefixes =
- if prefixes.empty?
- nil
- else
- /(#{prefixes.map {|p| Regexp.escape(p) }.join("|")})/
- end
-
- checksums = checksums.each_line.map do |line|
- if prefixes.nil? || line.match?(prefixes)
- line.gsub(/ sha256=[a-f0-9]{64}/i, "")
- else
- line
- end
- end
-
- head.concat(
- "CHECKSUMS",
- checksums.join,
- "\n\n",
- tail
- )
- end
-
- def remove_checksums_section_from_lockfile(lockfile)
- head, remaining = lockfile.split(/^CHECKSUMS$/, 2)
- return lockfile unless remaining
- _checksums, tail = remaining.split("\n\n", 2)
- head.concat(tail)
- end
-
- def checksum_from_package(gem_file, name, version)
- name_tuple = Gem::NameTuple.new(name, version)
-
- checksum = nil
-
- File.open(gem_file, "rb") do |f|
- checksum = Bundler::Checksum.from_gem(f, gemfile)
- end
-
- "#{name_tuple.lock_name} #{checksum.to_lock}"
- end
- end
-end
diff --git a/spec/bundler/support/command_execution.rb b/spec/bundler/support/command_execution.rb
index 02726744d3..68e5c56c75 100644
--- a/spec/bundler/support/command_execution.rb
+++ b/spec/bundler/support/command_execution.rb
@@ -1,37 +1,7 @@
# frozen_string_literal: true
module Spec
- class CommandExecution
- def initialize(command, working_directory:, timeout:)
- @command = command
- @working_directory = working_directory
- @timeout = timeout
- @original_stdout = String.new
- @original_stderr = String.new
- end
-
- attr_accessor :exitstatus, :command, :original_stdout, :original_stderr
- attr_reader :timeout
- attr_writer :failure_reason
-
- def raise_error!
- return unless failure?
-
- error_header = if failure_reason == :timeout
- "Invoking `#{command}` was aborted after #{timeout} seconds with output:"
- else
- "Invoking `#{command}` failed with output:"
- end
-
- raise <<~ERROR
- #{error_header}
-
- ----------------------------------------------------------------------
- #{stdboth}
- ----------------------------------------------------------------------
- ERROR
- end
-
+ CommandExecution = Struct.new(:command, :working_directory, :exitstatus, :stdout, :stderr) do
def to_s
"$ #{command}"
end
@@ -41,14 +11,6 @@ module Spec
@stdboth ||= [stderr, stdout].join("\n").strip
end
- def stdout
- normalize(original_stdout)
- end
-
- def stderr
- normalize(original_stderr)
- end
-
def to_s_verbose
[
to_s,
@@ -67,13 +29,5 @@ module Spec
return true unless exitstatus
exitstatus > 0
end
-
- private
-
- attr_reader :failure_reason
-
- def normalize(string)
- string.force_encoding(Encoding::UTF_8).strip.gsub("\r\n", "\n")
- end
end
end
diff --git a/spec/bundler/support/env.rb b/spec/bundler/support/env.rb
deleted file mode 100644
index 2d13c449fe..0000000000
--- a/spec/bundler/support/env.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-module Spec
- module Env
- def ruby_core?
- File.exist?(File.expand_path("../../../lib/bundler/bundler.gemspec", __dir__))
- end
- end
-end
diff --git a/spec/bundler/support/filters.rb b/spec/bundler/support/filters.rb
index e1683ae75b..78545d2e64 100644
--- a/spec/bundler/support/filters.rb
+++ b/spec/bundler/support/filters.rb
@@ -14,25 +14,25 @@ class RequirementChecker < Proc
attr_accessor :provided
def inspect
- "\"#{provided}\""
+ "\"!= #{provided}\""
end
end
RSpec.configure do |config|
- config.filter_run_excluding realworld: true
+ config.filter_run_excluding :realworld => true
git_version = Bundler::Source::Git::GitProxy.new(nil, nil).version
- config.filter_run_excluding git: RequirementChecker.against(git_version)
- config.filter_run_excluding bundler: RequirementChecker.against(Bundler::VERSION.split(".")[0])
- config.filter_run_excluding rubygems: RequirementChecker.against(Gem::VERSION)
- config.filter_run_excluding ruby_repo: !ENV["GEM_COMMAND"].nil?
- config.filter_run_excluding no_color_tty: Gem.win_platform? || !ENV["GITHUB_ACTION"].nil?
- config.filter_run_excluding permissions: Gem.win_platform?
- config.filter_run_excluding readline: Gem.win_platform?
- config.filter_run_excluding jruby_only: RUBY_ENGINE != "jruby"
- config.filter_run_excluding truffleruby_only: RUBY_ENGINE != "truffleruby"
- config.filter_run_excluding man: Gem.win_platform?
+ config.filter_run_excluding :git => RequirementChecker.against(git_version)
+ config.filter_run_excluding :bundler => RequirementChecker.against(Bundler::VERSION.split(".")[0])
+ config.filter_run_excluding :rubygems => RequirementChecker.against(Gem::VERSION)
+ config.filter_run_excluding :ruby_repo => !ENV["GEM_COMMAND"].nil?
+ config.filter_run_excluding :no_color_tty => Gem.win_platform? || !ENV["GITHUB_ACTION"].nil?
+ config.filter_run_excluding :permissions => Gem.win_platform?
+ config.filter_run_excluding :readline => Gem.win_platform?
+ config.filter_run_excluding :jruby_only => RUBY_ENGINE != "jruby"
+ config.filter_run_excluding :truffleruby_only => RUBY_ENGINE != "truffleruby"
+ config.filter_run_excluding :man => Gem.win_platform?
config.filter_run_when_matching :focus unless ENV["CI"]
end
diff --git a/spec/bundler/support/hax.rb b/spec/bundler/support/hax.rb
index 492c6ca8ed..c7fe3637cc 100644
--- a/spec/bundler/support/hax.rb
+++ b/spec/bundler/support/hax.rb
@@ -36,4 +36,18 @@ module Gem
if ENV["BUNDLER_SPEC_GEM_SOURCES"]
self.sources = [ENV["BUNDLER_SPEC_GEM_SOURCES"]]
end
+
+ if ENV["BUNDLER_IGNORE_DEFAULT_GEM"]
+ module RemoveDefaultBundlerStub
+ def default_stubs(pattern = "*")
+ super.delete_if {|stub| stub.name == "bundler" }
+ end
+ end
+
+ class Specification
+ class << self
+ prepend RemoveDefaultBundlerStub
+ end
+ end
+ end
end
diff --git a/spec/bundler/support/helpers.rb b/spec/bundler/support/helpers.rb
index 145008ab42..7b8c56b6ad 100644
--- a/spec/bundler/support/helpers.rb
+++ b/spec/bundler/support/helpers.rb
@@ -1,21 +1,12 @@
# frozen_string_literal: true
+require_relative "command_execution"
require_relative "the_bundle"
require_relative "path"
-require_relative "options"
-require_relative "subprocess"
module Spec
module Helpers
include Spec::Path
- include Spec::Options
- include Spec::Subprocess
-
- def self.extended(mod)
- mod.extend Spec::Path
- mod.extend Spec::Options
- mod.extend Spec::Subprocess
- end
def reset!
Dir.glob("#{tmp}/{gems/*,*}", File::FNM_DOTMATCH).each do |dir|
@@ -36,7 +27,23 @@ module Spec
TheBundle.new(*args)
end
- MAJOR_DEPRECATION = /^\[DEPRECATED\]\s*/
+ def command_executions
+ @command_executions ||= []
+ end
+
+ def last_command
+ command_executions.last || raise("There is no last command")
+ end
+
+ def out
+ last_command.stdout
+ end
+
+ def err
+ last_command.stderr
+ end
+
+ MAJOR_DEPRECATION = /^\[DEPRECATED\]\s*/.freeze
def err_without_deprecations
err.gsub(/#{MAJOR_DEPRECATION}.+[\n]?/, "")
@@ -46,10 +53,14 @@ module Spec
err.split("\n").select {|l| l =~ MAJOR_DEPRECATION }.join("\n").split(MAJOR_DEPRECATION)
end
+ def exitstatus
+ last_command.exitstatus
+ end
+
def run(cmd, *args)
opts = args.last.is_a?(Hash) ? args.pop : {}
groups = args.map(&:inspect).join(", ")
- setup = "require 'bundler' ; Bundler.ui.silence { Bundler.setup(#{groups}) }"
+ setup = "require '#{entrypoint}' ; Bundler.ui.silence { Bundler.setup(#{groups}) }"
ruby([setup, cmd].join(" ; "), opts)
end
@@ -71,26 +82,31 @@ module Spec
bundle_bin ||= installed_bindir.join("bundle")
env = options.delete(:env) || {}
- preserve_ruby_flags = options.delete(:preserve_ruby_flags)
requires = options.delete(:requires) || []
+ realworld = RSpec.current_example.metadata[:realworld]
- dir = options.delete(:dir) || bundled_app
+ artifice = options.delete(:artifice) do
+ if realworld
+ "vcr"
+ else
+ "fail"
+ end
+ end
+ if artifice
+ requires << "#{Path.spec_dir}/support/artifice/#{artifice}.rb"
+ end
load_path = []
load_path << spec_dir
- build_ruby_options = { load_path: load_path, requires: requires, env: env }
- build_ruby_options.merge!(artifice: options.delete(:artifice)) if options.key?(:artifice)
-
- match_source(cmd)
-
- env, ruby_cmd = build_ruby_cmd(build_ruby_options)
-
+ dir = options.delete(:dir) || bundled_app
raise_on_error = options.delete(:raise_on_error)
args = options.map do |k, v|
case v
+ when nil
+ next
when true
" --#{k}"
when false
@@ -100,30 +116,19 @@ module Spec
end
end.join
+ ruby_cmd = build_ruby_cmd({ :load_path => load_path, :requires => requires })
cmd = "#{ruby_cmd} #{bundle_bin} #{cmd}#{args}"
- env["BUNDLER_SPEC_ORIGINAL_CMD"] = "#{ruby_cmd} #{bundle_bin}" if preserve_ruby_flags
- sys_exec(cmd, { env: env, dir: dir, raise_on_error: raise_on_error }, &block)
- end
-
- def main_source(dir)
- gemfile = File.expand_path("Gemfile", dir)
- return unless File.exist?(gemfile)
-
- match = File.readlines(gemfile).first.match(/source ["'](?<source>[^"']+)["']/)
- return unless match
-
- match[:source]
+ sys_exec(cmd, { :env => env, :dir => dir, :raise_on_error => raise_on_error }, &block)
end
def bundler(cmd, options = {})
- options[:bundle_bin] = system_gem_path("bin/bundler")
+ options[:bundle_bin] = system_gem_path.join("bin/bundler")
bundle(cmd, options)
end
def ruby(ruby, options = {})
- env, ruby_cmd = build_ruby_cmd({ artifice: nil }.merge(options))
+ ruby_cmd = build_ruby_cmd
escaped_ruby = ruby.shellescape
- options[:env] = env if env
sys_exec(%(#{ruby_cmd} -w -e #{escaped_ruby}), options)
end
@@ -141,40 +146,11 @@ module Spec
libs = options.delete(:load_path)
lib_option = libs ? "-I#{libs.join(File::PATH_SEPARATOR)}" : []
- env = options.delete(:env) || {}
- current_example = RSpec.current_example
-
- main_source = @gemfile_source if defined?(@gemfile_source)
- compact_index_main_source = main_source&.start_with?("https://gem.repo", "https://gems.security")
-
requires = options.delete(:requires) || []
- artifice = options.delete(:artifice) do
- if current_example && current_example.metadata[:realworld]
- "vcr"
- elsif compact_index_main_source
- env["BUNDLER_SPEC_GEM_REPO"] ||=
- case main_source
- when "https://gem.repo1" then gem_repo1.to_s
- when "https://gem.repo2" then gem_repo2.to_s
- when "https://gem.repo3" then gem_repo3.to_s
- when "https://gem.repo4" then gem_repo4.to_s
- when "https://gems.security" then security_repo.to_s
- end
-
- "compact_index"
- else
- "fail"
- end
- end
- if artifice
- requires << "#{Path.spec_dir}/support/artifice/#{artifice}.rb"
- end
-
requires << "#{Path.spec_dir}/support/hax.rb"
-
require_option = requires.map {|r| "-r#{r}" }
- [env, [Gem.ruby, *lib_option, *require_option].compact.join(" ")]
+ [Gem.ruby, *lib_option, *require_option].compact.join(" ")
end
def gembin(cmd, options = {})
@@ -186,40 +162,70 @@ module Spec
env = options[:env] || {}
env["RUBYOPT"] = opt_add(opt_add("-r#{spec_dir}/support/hax.rb", env["RUBYOPT"]), ENV["RUBYOPT"])
options[:env] = env
- output = sys_exec("#{Path.gem_bin} #{command}", options)
- stderr = last_command.stderr
- raise stderr if stderr.include?("WARNING") && !allowed_rubygems_warning?(stderr)
- output
+ sys_exec("#{Path.gem_bin} #{command}", options)
end
def rake
"#{Gem.ruby} -S #{ENV["GEM_PATH"]}/bin/rake"
end
- def sys_exec(cmd, options = {}, &block)
+ def git(cmd, path, options = {})
+ sys_exec("git #{cmd}", options.merge(:dir => path))
+ end
+
+ def sys_exec(cmd, options = {})
env = options[:env] || {}
env["RUBYOPT"] = opt_add(opt_add("-r#{spec_dir}/support/switch_rubygems.rb", env["RUBYOPT"]), ENV["RUBYOPT"])
- options[:env] = env
- options[:dir] ||= bundled_app
+ dir = options[:dir] || bundled_app
+ command_execution = CommandExecution.new(cmd.to_s, dir)
+
+ require "open3"
+ require "shellwords"
+ Open3.popen3(env, *cmd.shellsplit, :chdir => dir) do |stdin, stdout, stderr, wait_thr|
+ yield stdin, stdout, wait_thr if block_given?
+ stdin.close
+
+ stdout_read_thread = Thread.new { stdout.read }
+ stderr_read_thread = Thread.new { stderr.read }
+ command_execution.stdout = stdout_read_thread.value.strip
+ command_execution.stderr = stderr_read_thread.value.strip
+
+ status = wait_thr.value
+ command_execution.exitstatus = if status.exited?
+ status.exitstatus
+ elsif status.signaled?
+ exit_status_for_signal(status.termsig)
+ end
+ end
- sh(cmd, options, &block)
- end
+ unless options[:raise_on_error] == false || command_execution.success?
+ raise <<~ERROR
- def config(config = nil, path = bundled_app(".bundle/config"))
- current = File.exist?(path) ? Psych.load_file(path) : {}
- return current unless config
+ Invoking `#{cmd}` failed with output:
+ ----------------------------------------------------------------------
+ #{command_execution.stdboth}
+ ----------------------------------------------------------------------
+ ERROR
+ end
- current = {} if current.empty?
+ command_executions << command_execution
- FileUtils.mkdir_p(File.dirname(path))
+ command_execution.stdout
+ end
- new_config = current.merge(config).compact
+ def all_commands_output
+ return "" if command_executions.empty?
- File.open(path, "w+") do |f|
- f.puts new_config.to_yaml
- end
+ "\n\nCommands:\n#{command_executions.map(&:to_s_verbose).join("\n\n")}"
+ end
- new_config
+ def config(config = nil, path = bundled_app(".bundle/config"))
+ return Psych.load_file(path) unless config
+ FileUtils.mkdir_p(File.dirname(path))
+ File.open(path, "w") do |f|
+ f.puts config.to_yaml
+ end
+ config
end
def global_config(config = nil)
@@ -238,9 +244,8 @@ module Spec
contents = args.pop
if contents.nil?
- read_gemfile
+ File.open(bundled_app_gemfile, "r", &:read)
else
- match_source(contents)
create_file(args.pop || "Gemfile", contents)
end
end
@@ -249,24 +254,12 @@ module Spec
contents = args.pop
if contents.nil?
- read_lockfile
+ File.open(bundled_app_lock, "r", &:read)
else
create_file(args.pop || "Gemfile.lock", contents)
end
end
- def read_gemfile(file = "Gemfile")
- read_bundled_app_file(file)
- end
-
- def read_lockfile(file = "Gemfile.lock")
- read_bundled_app_file(file)
- end
-
- def read_bundled_app_file(file)
- bundled_app(file).read
- end
-
def strip_whitespace(str)
# Trim the leading spaces
spaces = str[/\A\s+/, 0] || ""
@@ -288,43 +281,59 @@ module Spec
def system_gems(*gems)
gems = gems.flatten
options = gems.last.is_a?(Hash) ? gems.pop : {}
- install_dir = options.fetch(:path, system_gem_path)
+ path = options.fetch(:path, system_gem_path)
default = options.fetch(:default, false)
- with_gem_path_as(install_dir) do
+ with_gem_path_as(path) do
gem_repo = options.fetch(:gem_repo, gem_repo1)
gems.each do |g|
gem_name = g.to_s
if gem_name.start_with?("bundler")
version = gem_name.match(/\Abundler-(?<version>.*)\z/)[:version] if gem_name != "bundler"
- with_built_bundler(version) {|gem_path| install_gem(gem_path, install_dir, default) }
+ with_built_bundler(version) {|gem_path| install_gem(gem_path, default) }
elsif %r{\A(?:[a-zA-Z]:)?/.*\.gem\z}.match?(gem_name)
- install_gem(gem_name, install_dir, default)
+ install_gem(gem_name, default)
else
- install_gem("#{gem_repo}/gems/#{gem_name}.gem", install_dir, default)
+ install_gem("#{gem_repo}/gems/#{gem_name}.gem", default)
end
end
end
end
- def self.install_dev_bundler
- extend self
-
- system_gems :bundler, path: pristine_system_gem_path
- end
-
- def install_gem(path, install_dir, default = false)
+ def install_gem(path, default = false)
raise "OMG `#{path}` does not exist!" unless File.exist?(path)
- args = "--no-document --ignore-dependencies --verbose --local --install-dir #{install_dir}"
- args += " --default" if default
+ args = "--no-document --ignore-dependencies --verbose --local"
+ args += " --default --install-dir #{system_gem_path}" if default
gem_command "install #{args} '#{path}'"
end
- def with_built_bundler(version = nil, &block)
- require_relative "builders"
+ def with_built_bundler(version = nil)
+ version ||= Bundler::VERSION
+ full_name = "bundler-#{version}"
+ build_path = tmp + full_name
+ bundler_path = build_path + "#{full_name}.gem"
+
+ Dir.mkdir build_path
+
+ begin
+ shipped_files.each do |shipped_file|
+ target_shipped_file = build_path + shipped_file
+ target_shipped_dir = File.dirname(target_shipped_file)
+ FileUtils.mkdir_p target_shipped_dir unless File.directory?(target_shipped_dir)
+ FileUtils.cp shipped_file, target_shipped_file, :preserve => true
+ end
+
+ replace_version_file(version, dir: build_path) # rubocop:disable Style/HashSyntax
+
+ Spec::BuildMetadata.write_build_metadata(dir: build_path) # rubocop:disable Style/HashSyntax
+
+ gem_command "build #{relative_gemspec}", :dir => build_path
- Builders::BundlerBuilder.new(self, "bundler", version)._build(&block)
+ yield(bundler_path)
+ ensure
+ build_path.rmtree
+ end
end
def with_gem_path_as(path)
@@ -358,6 +367,16 @@ module Spec
end
end
+ def opt_add(option, options)
+ [option.strip, options].compact.reject(&:empty?).join(" ")
+ end
+
+ def opt_remove(option, options)
+ return unless options
+
+ options.split(" ").reject {|opt| opt.strip == option.strip }.join(" ")
+ end
+
def break_git!
FileUtils.mkdir_p(tmp("broken_path"))
File.open(tmp("broken_path/git"), "w", 0o755) do |f|
@@ -424,7 +443,7 @@ module Spec
def simulate_platform(platform)
old = ENV["BUNDLER_SPEC_PLATFORM"]
ENV["BUNDLER_SPEC_PLATFORM"] = platform.to_s
- yield
+ yield if block_given?
ensure
ENV["BUNDLER_SPEC_PLATFORM"] = old if block_given?
end
@@ -433,12 +452,32 @@ module Spec
old = ENV["BUNDLER_SPEC_WINDOWS"]
ENV["BUNDLER_SPEC_WINDOWS"] = "true"
simulate_platform platform do
- yield
+ simulate_bundler_version_when_missing_prerelease_default_gem_activation do
+ yield
+ end
end
ensure
ENV["BUNDLER_SPEC_WINDOWS"] = old
end
+ def simulate_bundler_version_when_missing_prerelease_default_gem_activation
+ return yield unless rubygems_version_failing_to_activate_bundler_prereleases
+
+ old = ENV["BUNDLER_VERSION"]
+ ENV["BUNDLER_VERSION"] = Bundler::VERSION
+ yield
+ ensure
+ ENV["BUNDLER_VERSION"] = old
+ end
+
+ def env_for_missing_prerelease_default_gem_activation
+ if rubygems_version_failing_to_activate_bundler_prereleases
+ { "BUNDLER_VERSION" => Bundler::VERSION }
+ else
+ {}
+ end
+ end
+
def current_ruby_minor
Gem.ruby_version.segments.tap {|s| s.delete_at(2) }.join(".")
end
@@ -457,8 +496,14 @@ module Spec
Gem.ruby_version.segments[0..1]
end
+ # versions not including
+ # https://github.com/rubygems/rubygems/commit/929e92d752baad3a08f3ac92eaec162cb96aedd1
+ def rubygems_version_failing_to_activate_bundler_prereleases
+ Gem.rubygems_version < Gem::Version.new("3.1.0.pre.1")
+ end
+
def revision_for(path)
- git("rev-parse HEAD", path).strip
+ sys_exec("git rev-parse HEAD", :dir => path).strip
end
def with_read_only(pattern)
@@ -545,17 +590,6 @@ module Spec
private
- def allowed_rubygems_warning?(text)
- text.include?("open-ended") || text.include?("is a symlink") || text.include?("rake based") || text.include?("expected RubyGems version")
- end
-
- def match_source(contents)
- match = /source ["']?(?<source>http[^"']+)["']?/.match(contents)
- return unless match
-
- @gemfile_source = match[:source]
- end
-
def git_root_dir?
root.to_s == `git rev-parse --show-toplevel`.chomp
end
diff --git a/spec/bundler/support/indexes.rb b/spec/bundler/support/indexes.rb
index 7960bae59f..78372302f1 100644
--- a/spec/bundler/support/indexes.rb
+++ b/spec/bundler/support/indexes.rb
@@ -14,10 +14,10 @@ module Spec
alias_method :platforms, :platform
- def resolve(args = [], dependency_api_available: true)
+ def resolve(args = [])
@platforms ||= ["ruby"]
- default_source = instance_double("Bundler::Source::Rubygems", specs: @index, to_s: "locally install gems", dependency_api_available?: dependency_api_available)
- source_requirements = { default: default_source }
+ default_source = instance_double("Bundler::Source::Rubygems", :specs => @index, :to_s => "locally install gems")
+ source_requirements = { :default => default_source }
base = args[0] || Bundler::SpecSet.new([])
base.each {|ls| ls.source = default_source }
gem_version_promoter = args[1] || Bundler::GemVersionPromoter.new
@@ -27,7 +27,7 @@ module Spec
name = d.name
source_requirements[name] = d.source = default_source
end
- packages = Bundler::Resolver::Base.new(source_requirements, @deps, base, @platforms, locked_specs: originally_locked, unlock: unlock)
+ packages = Bundler::Resolver::Base.new(source_requirements, @deps, base, @platforms, :locked_specs => originally_locked, :unlock => unlock)
Bundler::Resolver.new(packages, gem_version_promoter).start
end
@@ -41,12 +41,6 @@ module Spec
expect(got).to eq(specs.sort)
end
- def should_resolve_without_dependency_api(specs)
- got = resolve(dependency_api_available: false)
- got = got.map(&:full_name).sort
- expect(got).to eq(specs.sort)
- end
-
def should_resolve_and_include(specs, args = [])
got = resolve(args)
got = got.map(&:full_name).sort
@@ -77,8 +71,8 @@ module Spec
def an_awesome_index
build_index do
- gem "myrack", %w[0.8 0.9 0.9.1 0.9.2 1.0 1.1]
- gem "myrack-mount", %w[0.4 0.5 0.5.1 0.5.2 0.6]
+ gem "rack", %w[0.8 0.9 0.9.1 0.9.2 1.0 1.1]
+ gem "rack-mount", %w[0.4 0.5 0.5.1 0.5.2 0.6]
# --- Pre-release support
gem "RubyGems\0", ["1.3.2"]
@@ -89,10 +83,10 @@ module Spec
gem "actionpack", version do
dep "activesupport", version
if version >= v("3.0.0.beta")
- dep "myrack", "~> 1.1"
- dep "myrack-mount", ">= 0.5"
- elsif version > v("2.3") then dep "myrack", "~> 1.0.0"
- elsif version > v("2.0.0") then dep "myrack", "~> 0.9.0"
+ dep "rack", "~> 1.1"
+ dep "rack-mount", ">= 0.5"
+ elsif version > v("2.3") then dep "rack", "~> 1.0.0"
+ elsif version > v("2.0.0") then dep "rack", "~> 0.9.0"
end
end
gem "activerecord", version do
@@ -304,7 +298,7 @@ module Spec
end
end
- def a_unresolvable_child_index
+ def a_unresovable_child_index
build_index do
gem "json", %w[1.8.0]
@@ -367,7 +361,7 @@ module Spec
def a_circular_index
build_index do
- gem "myrack", "1.0.1"
+ gem "rack", "1.0.1"
gem("foo", "0.2.6") do
dep "bar", ">= 0"
end
diff --git a/spec/bundler/support/matchers.rb b/spec/bundler/support/matchers.rb
index ed11e3ba52..ea7c784683 100644
--- a/spec/bundler/support/matchers.rb
+++ b/spec/bundler/support/matchers.rb
@@ -97,6 +97,18 @@ module Spec
end
end
+ RSpec::Matchers.define :take_less_than do |seconds|
+ match do |actual|
+ start_time = Time.now
+
+ actual.call
+
+ (Time.now - start_time).to_f < seconds
+ end
+
+ supports_block_expectations
+ end
+
define_compound_matcher :read_as, [exist] do |file_contents|
diffable
@@ -118,7 +130,6 @@ module Spec
opts[:raise_on_error] = false
@errors = names.map do |full_name|
name, version, platform = full_name.split(/\s+/)
- platform ||= "ruby"
require_path = name.tr("-", "/")
version_const = name == "bundler" ? "Bundler::VERSION" : Spec::Builders.constantize(name)
source_const = "#{Spec::Builders.constantize(name)}_SOURCE"
@@ -128,7 +139,6 @@ module Spec
require '#{require_path}'
actual_version, actual_platform = #{version_const}.split(/\s+/, 2)
- actual_platform ||= "ruby"
unless Gem::Version.new(actual_version) == Gem::Version.new('#{version}')
puts actual_version
exit 64
@@ -152,7 +162,7 @@ module Spec
end
if exitstatus == 65
actual_platform = out.split("\n").last
- next "#{name} was expected to be of platform #{platform} but was #{actual_platform}"
+ next "#{name} was expected to be of platform #{platform || "ruby"} but was #{actual_platform || "ruby"}"
end
if exitstatus == 66
actual_source = out.split("\n").last
diff --git a/spec/bundler/support/options.rb b/spec/bundler/support/options.rb
deleted file mode 100644
index 551fa1acd8..0000000000
--- a/spec/bundler/support/options.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# frozen_string_literal: true
-
-module Spec
- module Options
- def opt_add(option, options)
- [option.strip, options].compact.reject(&:empty?).join(" ")
- end
-
- def opt_remove(option, options)
- return unless options
-
- options.split(" ").reject {|opt| opt.strip == option.strip }.join(" ")
- end
- end
-end
diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb
index b26e77d376..8b9c0e1290 100644
--- a/spec/bundler/support/path.rb
+++ b/spec/bundler/support/path.rb
@@ -3,12 +3,8 @@
require "pathname"
require "rbconfig"
-require_relative "env"
-
module Spec
module Path
- include Spec::Env
-
def source_root
@source_root ||= Pathname.new(ruby_core? ? "../../.." : "../..").expand_path(__dir__)
end
@@ -62,7 +58,7 @@ module Spec
end
def gem_bin
- @gem_bin ||= ENV["GEM_COMMAND"] || "gem"
+ @gem_bin ||= ruby_core? ? ENV["GEM_COMMAND"] : "gem"
end
def path
@@ -84,13 +80,7 @@ module Spec
end
def shipped_files
- @shipped_files ||= if ruby_core_tarball?
- loaded_gemspec.files.map {|f| f.gsub(%r{^exe/}, "libexec/") }
- elsif ruby_core?
- tracked_files
- else
- loaded_gemspec.files
- end
+ @shipped_files ||= loaded_gemspec.files
end
def lib_tracked_files
@@ -102,18 +92,7 @@ module Spec
end
def tmp(*path)
- tmp_root(scope).join(*path)
- end
-
- def tmp_root(scope)
- source_root.join("tmp", "#{test_env_version}.#{scope}")
- end
-
- # Bump this version whenever you make a breaking change to the spec setup
- # that requires regenerating tmp/.
-
- def test_env_version
- 1
+ source_root.join("tmp", scope, *path)
end
def scope
@@ -124,7 +103,7 @@ module Spec
end
def home(*path)
- tmp("home", *path)
+ tmp.join("home", *path)
end
def default_bundle_path(*path)
@@ -144,13 +123,13 @@ module Spec
end
def bundled_app(*path)
- root = tmp("bundled_app")
+ root = tmp.join("bundled_app")
FileUtils.mkdir_p(root)
root.join(*path)
end
def bundled_app2(*path)
- root = tmp("bundled_app2")
+ root = tmp.join("bundled_app2")
FileUtils.mkdir_p(root)
root.join(*path)
end
@@ -176,15 +155,15 @@ module Spec
end
def base_system_gems
- tmp("gems/base")
+ tmp.join("gems/base")
end
def rubocop_gems
- tmp("gems/rubocop")
+ tmp.join("gems/rubocop")
end
def standard_gems
- tmp("gems/standard")
+ tmp.join("gems/standard")
end
def file_uri_for(path)
@@ -246,6 +225,13 @@ module Spec
root.join("lib")
end
+ # Sometimes rubygems version under test does not include
+ # https://github.com/rubygems/rubygems/pull/2728 and will not always end up
+ # activating the current bundler. In that case, require bundler absolutely.
+ def entrypoint
+ Gem.rubygems_version < Gem::Version.new("3.1.a") ? "#{lib_dir}/bundler" : "bundler"
+ end
+
def global_plugin_gem(*args)
home ".bundle", "plugin", "gems", *args
end
@@ -265,31 +251,31 @@ module Spec
File.open(version_file, "w") {|f| f << contents }
end
- def replace_required_ruby_version(version, dir:)
- gemspec_file = File.expand_path("bundler.gemspec", dir)
- contents = File.read(gemspec_file)
- contents.sub!(/(^\s+s\.required_ruby_version\s*=\s*)"[^"]+"/, %(\\1"#{version}"))
- File.open(gemspec_file, "w") {|f| f << contents }
+ def ruby_core?
+ # avoid to warnings
+ @ruby_core ||= nil
+
+ if @ruby_core.nil?
+ @ruby_core = true & ENV["GEM_COMMAND"]
+ else
+ @ruby_core
+ end
end
def git_root
ruby_core? ? source_root : source_root.parent
end
- def rake_path
- Dir["#{base_system_gems}/#{Bundler.ruby_scope}/**/rake*.gem"].first
- end
-
private
def git_ls_files(glob)
skip "Not running on a git context, since running tests from a tarball" if ruby_core_tarball?
- git("ls-files -z -- #{glob}", source_root).split("\x0")
+ sys_exec("git ls-files -z -- #{glob}", :dir => source_root).split("\x0")
end
def tracked_files_glob
- ruby_core? ? "libexec/bundle* lib/bundler lib/bundler.rb spec/bundler man/bundle*" : "lib exe spec CHANGELOG.md LICENSE.md README.md bundler.gemspec"
+ ruby_core? ? "lib/bundler lib/bundler.rb spec/bundler man/bundle*" : ""
end
def lib_tracked_files_glob
diff --git a/spec/bundler/support/platforms.rb b/spec/bundler/support/platforms.rb
index 526e1c09a9..eca1b2e60d 100644
--- a/spec/bundler/support/platforms.rb
+++ b/spec/bundler/support/platforms.rb
@@ -95,17 +95,12 @@ module Spec
9999
end
- def default_platform_list(*extra, defaults: default_locked_platforms)
- defaults.concat(extra).uniq
+ def lockfile_platforms(*extra)
+ formatted_lockfile_platforms(local_platform, *extra)
end
- def lockfile_platforms(*extra, defaults: default_locked_platforms)
- platforms = default_platform_list(*extra, defaults: defaults)
+ def formatted_lockfile_platforms(*platforms)
platforms.map(&:to_s).sort.join("\n ")
end
-
- def default_locked_platforms
- [local_platform, generic_local_platform]
- end
end
end
diff --git a/spec/bundler/support/rubygems_ext.rb b/spec/bundler/support/rubygems_ext.rb
index 5dfc2591b7..4553c0606e 100644
--- a/spec/bundler/support/rubygems_ext.rb
+++ b/spec/bundler/support/rubygems_ext.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-abort "RubyGems only supports Ruby 3.1 or higher" if RUBY_VERSION < "3.1.0"
-
require_relative "path"
$LOAD_PATH.unshift(Spec::Path.source_lib_dir.to_s)
@@ -26,9 +24,9 @@ module Spec
gem_load_activate_and_possibly_install(gem_name, bin_container)
end
- def gem_require(gem_name, entrypoint)
+ def gem_require(gem_name)
gem_activate(gem_name)
- require entrypoint
+ require gem_name
end
def test_setup
@@ -40,10 +38,6 @@ module Spec
FileUtils.mkdir_p(Path.tmpdir)
ENV["HOME"] = Path.home.to_s
- # Remove "RUBY_CODESIGN", which is used by mkmf-generated Makefile to
- # sign extension bundles on macOS, to avoid trying to find the specified key
- # from the fake $HOME/Library/Keychains directory.
- ENV.delete "RUBY_CODESIGN"
ENV["TMPDIR"] = Path.tmpdir.to_s
require "rubygems/user_interaction"
@@ -59,8 +53,8 @@ module Spec
install_test_deps
(2..Parallel.processor_count).each do |n|
- source = Path.tmp_root("1")
- destination = Path.tmp_root(n.to_s)
+ source = Path.source_root.join("tmp", "1")
+ destination = Path.source_root.join("tmp", n.to_s)
FileUtils.rm_rf destination
FileUtils.cp_r source, destination
@@ -72,20 +66,14 @@ module Spec
ENV["BUNDLE_PATH"] = nil
ENV["GEM_HOME"] = ENV["GEM_PATH"] = Path.base_system_gem_path.to_s
- ENV["PATH"] = [Path.system_gem_path("bin"), ENV["PATH"]].join(File::PATH_SEPARATOR)
+ ENV["PATH"] = [Path.system_gem_path.join("bin"), ENV["PATH"]].join(File::PATH_SEPARATOR)
ENV["PATH"] = [Path.bindir, ENV["PATH"]].join(File::PATH_SEPARATOR) if Path.ruby_core?
end
def install_test_deps
- Gem.clear_paths
-
install_gems(test_gemfile, Path.base_system_gems.to_s)
install_gems(rubocop_gemfile, Path.rubocop_gems.to_s)
install_gems(standard_gemfile, Path.standard_gems.to_s)
-
- # For some reason, doing this here crashes on JRuby + Windows. So defer to
- # when the test suite is running in that case.
- Helpers.install_dev_bundler unless Gem.win_platform? && RUBY_ENGINE == "jruby"
end
def check_source_control_changes(success_message:, error_message:)
@@ -98,7 +86,7 @@ module Spec
puts success_message
puts
else
- system("git diff")
+ system("git status --porcelain")
puts
puts error_message
@@ -130,7 +118,6 @@ module Spec
end
def gem_activate(gem_name)
- require_relative "activate"
require "bundler"
gem_requirement = Bundler::LockfileParser.new(File.read(dev_lockfile)).specs.find {|spec| spec.name == gem_name }.version
gem gem_name, gem_requirement
diff --git a/spec/bundler/support/rubygems_version_manager.rb b/spec/bundler/support/rubygems_version_manager.rb
index c174c461f0..5653601ae8 100644
--- a/spec/bundler/support/rubygems_version_manager.rb
+++ b/spec/bundler/support/rubygems_version_manager.rb
@@ -1,13 +1,12 @@
# frozen_string_literal: true
-require_relative "options"
-require_relative "env"
-require_relative "subprocess"
+require "pathname"
+require_relative "helpers"
+require_relative "path"
class RubygemsVersionManager
- include Spec::Options
- include Spec::Env
- include Spec::Subprocess
+ include Spec::Helpers
+ include Spec::Path
def initialize(source)
@source = source
@@ -31,10 +30,11 @@ class RubygemsVersionManager
rubygems_default_path = rubygems_path + "/defaults"
bundler_path = rubylibdir + "/bundler"
+ bundler_exemptions = Gem.rubygems_version < Gem::Version.new("3.2.0") ? [bundler_path + "/errors.rb"] : []
bad_loaded_features = $LOADED_FEATURES.select do |loaded_feature|
(loaded_feature.start_with?(rubygems_path) && !loaded_feature.start_with?(rubygems_default_path)) ||
- loaded_feature.start_with?(bundler_path)
+ (loaded_feature.start_with?(bundler_path) && !bundler_exemptions.any? {|bundler_exemption| loaded_feature.start_with?(bundler_exemption) })
end
errors = if bad_loaded_features.any?
@@ -58,7 +58,7 @@ class RubygemsVersionManager
cmd = [RbConfig.ruby, $0, *ARGV].compact
- ENV["RUBYOPT"] = opt_add("-I#{File.join(local_copy_path, "lib")}", opt_remove("--disable-gems", ENV["RUBYOPT"]))
+ ENV["RUBYOPT"] = opt_add("-I#{local_copy_path.join("lib")}", opt_remove("--disable-gems", ENV["RUBYOPT"]))
exec(ENV, *cmd)
end
@@ -66,14 +66,14 @@ class RubygemsVersionManager
def switch_local_copy_if_needed
return unless local_copy_switch_needed?
- git("checkout #{target_tag}", local_copy_path)
+ sys_exec("git checkout #{target_tag}", :dir => local_copy_path)
- ENV["RGV"] = local_copy_path
+ ENV["RGV"] = local_copy_path.to_s
end
def rubygems_unrequire_needed?
require "rubygems"
- !$LOADED_FEATURES.include?(File.join(local_copy_path, "lib/rubygems.rb"))
+ !$LOADED_FEATURES.include?(local_copy_path.join("lib/rubygems.rb").to_s)
end
def local_copy_switch_needed?
@@ -85,7 +85,7 @@ class RubygemsVersionManager
end
def local_copy_tag
- git("rev-parse --abbrev-ref HEAD", local_copy_path)
+ sys_exec("git rev-parse --abbrev-ref HEAD", :dir => local_copy_path)
end
def local_copy_path
@@ -95,25 +95,21 @@ class RubygemsVersionManager
def resolve_local_copy_path
return expanded_source if source_is_path?
- rubygems_path = File.join(source_root, "tmp/rubygems")
+ rubygems_path = source_root.join("tmp/rubygems")
- unless File.directory?(rubygems_path)
- git("clone .. #{rubygems_path}", source_root)
+ unless rubygems_path.directory?
+ sys_exec("git clone .. #{rubygems_path}", :dir => source_root)
end
rubygems_path
end
def source_is_path?
- File.directory?(expanded_source)
+ expanded_source.directory?
end
def expanded_source
- @expanded_source ||= File.expand_path(@source, source_root)
- end
-
- def source_root
- @source_root ||= File.expand_path(ruby_core? ? "../../.." : "../..", __dir__)
+ @expanded_source ||= Pathname.new(@source).expand_path(source_root)
end
def resolve_target_tag
diff --git a/spec/bundler/support/subprocess.rb b/spec/bundler/support/subprocess.rb
deleted file mode 100644
index ade18e7805..0000000000
--- a/spec/bundler/support/subprocess.rb
+++ /dev/null
@@ -1,108 +0,0 @@
-# frozen_string_literal: true
-
-require_relative "command_execution"
-
-module Spec
- module Subprocess
- class TimeoutExceeded < StandardError; end
-
- def command_executions
- @command_executions ||= []
- end
-
- def last_command
- command_executions.last || raise("There is no last command")
- end
-
- def out
- last_command.stdout
- end
-
- def err
- last_command.stderr
- end
-
- def exitstatus
- last_command.exitstatus
- end
-
- def git(cmd, path = Dir.pwd, options = {})
- sh("git #{cmd}", options.merge(dir: path))
- end
-
- def sh(cmd, options = {})
- dir = options[:dir]
- env = options[:env] || {}
-
- command_execution = CommandExecution.new(cmd.to_s, working_directory: dir, timeout: 60)
-
- require "open3"
- require "shellwords"
- Open3.popen3(env, *cmd.shellsplit, chdir: dir) do |stdin, stdout, stderr, wait_thr|
- yield stdin, stdout, wait_thr if block_given?
- stdin.close
-
- stdout_handler = ->(data) { command_execution.original_stdout << data }
- stderr_handler = ->(data) { command_execution.original_stderr << data }
-
- stdout_thread = read_stream(stdout, stdout_handler, timeout: command_execution.timeout)
- stderr_thread = read_stream(stderr, stderr_handler, timeout: command_execution.timeout)
-
- stdout_thread.join
- stderr_thread.join
-
- status = wait_thr.value
- command_execution.exitstatus = if status.exited?
- status.exitstatus
- elsif status.signaled?
- exit_status_for_signal(status.termsig)
- end
- rescue TimeoutExceeded
- command_execution.failure_reason = :timeout
- command_execution.exitstatus = exit_status_for_signal(Signal.list["INT"])
- end
-
- unless options[:raise_on_error] == false || command_execution.success?
- command_execution.raise_error!
- end
-
- command_executions << command_execution
-
- command_execution.stdout
- end
-
- # Mostly copied from https://github.com/piotrmurach/tty-command/blob/49c37a895ccea107e8b78d20e4cb29de6a1a53c8/lib/tty/command/process_runner.rb#L165-L193
- def read_stream(stream, handler, timeout:)
- Thread.new do
- Thread.current.report_on_exception = false
- cmd_start = Time.now
- readers = [stream]
-
- while readers.any?
- ready = IO.select(readers, nil, readers, timeout)
- raise TimeoutExceeded if ready.nil?
-
- ready[0].each do |reader|
- chunk = reader.readpartial(16 * 1024)
- handler.call(chunk)
-
- # control total time spent reading
- runtime = Time.now - cmd_start
- time_left = timeout - runtime
- raise TimeoutExceeded if time_left < 0.0
- rescue Errno::EAGAIN, Errno::EINTR
- rescue EOFError, Errno::EPIPE, Errno::EIO
- readers.delete(reader)
- reader.close
- end
- end
- end
- end
-
- def all_commands_output
- return "" if command_executions.empty?
-
- "\n\nCommands:\n#{command_executions.map(&:to_s_verbose).join("\n\n")}"
- end
- end
-end
diff --git a/spec/bundler/support/vendored_net_http.rb b/spec/bundler/support/vendored_net_http.rb
deleted file mode 100644
index 8ff2ccd1fe..0000000000
--- a/spec/bundler/support/vendored_net_http.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-# This defined? guard can be removed once RubyGems 3.4 support is dropped.
-#
-# Bundler specs load this code from `spec/support/vendored_net_http.rb` to avoid
-# activating the Bundler gem too early. Without this guard, we get redefinition
-# warnings once Bundler is actually activated and
-# `lib/bundler/vendored_net_http.rb` is required. This is not an issue in
-# RubyGems versions including `rubygems/vendored_net_http` since `require` takes
-# care of avoiding the double load.
-#
-unless defined?(Gem::Net)
- begin
- require "rubygems/vendored_net_http"
- rescue LoadError
- begin
- require "rubygems/net/http"
- rescue LoadError
- require "net/http"
- Gem::Net = Net
- end
- end
-end
diff --git a/spec/bundler/update/gemfile_spec.rb b/spec/bundler/update/gemfile_spec.rb
index cb94799061..1c5294101e 100644
--- a/spec/bundler/update/gemfile_spec.rb
+++ b/spec/bundler/update/gemfile_spec.rb
@@ -4,25 +4,25 @@ RSpec.describe "bundle update" do
context "with --gemfile" do
it "finds the gemfile" do
gemfile bundled_app("NotGemfile"), <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
- bundle :install, gemfile: bundled_app("NotGemfile")
- bundle :update, gemfile: bundled_app("NotGemfile"), all: true
+ bundle :install, :gemfile => bundled_app("NotGemfile")
+ bundle :update, :gemfile => bundled_app("NotGemfile"), :all => true
# Specify BUNDLE_GEMFILE for `the_bundle`
# to retrieve the proper Gemfile
ENV["BUNDLE_GEMFILE"] = "NotGemfile"
- expect(the_bundle).to include_gems "myrack 1.0.0"
+ expect(the_bundle).to include_gems "rack 1.0.0"
end
end
context "with gemfile set via config" do
before do
gemfile bundled_app("NotGemfile"), <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
G
bundle "config set --local gemfile #{bundled_app("NotGemfile")}"
@@ -30,18 +30,18 @@ RSpec.describe "bundle update" do
end
it "uses the gemfile to update" do
- bundle "update", all: true
+ bundle "update", :all => true
bundle "list"
- expect(out).to include("myrack (1.0.0)")
+ expect(out).to include("rack (1.0.0)")
end
it "uses the gemfile while in a subdirectory" do
bundled_app("subdir").mkpath
- bundle "update", all: true, dir: bundled_app("subdir")
- bundle "list", dir: bundled_app("subdir")
+ bundle "update", :all => true, :dir => bundled_app("subdir")
+ bundle "list", :dir => bundled_app("subdir")
- expect(out).to include("myrack (1.0.0)")
+ expect(out).to include("rack (1.0.0)")
end
end
end
diff --git a/spec/bundler/update/gems/fund_spec.rb b/spec/bundler/update/gems/fund_spec.rb
index a5624d3e0a..d80f4018f3 100644
--- a/spec/bundler/update/gems/fund_spec.rb
+++ b/spec/bundler/update/gems/fund_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe "bundle update" do
end
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding_and_other_metadata'
gem 'has_funding', '< 2.0'
G
@@ -35,12 +35,12 @@ RSpec.describe "bundle update" do
context "when listed gems are updated" do
before do
gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
gem 'has_funding_and_other_metadata'
gem 'has_funding'
G
- bundle :update, all: true
+ bundle :update, :all => true
end
it "displays fund message" do
diff --git a/spec/bundler/update/gems/post_install_spec.rb b/spec/bundler/update/gems/post_install_spec.rb
index 9c71f6e0e3..3aaa659d57 100644
--- a/spec/bundler/update/gems/post_install_spec.rb
+++ b/spec/bundler/update/gems/post_install_spec.rb
@@ -5,8 +5,8 @@ RSpec.describe "bundle update" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack', "< 1.0"
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack', "< 1.0"
gem 'thin'
G
@@ -17,10 +17,10 @@ RSpec.describe "bundle update" do
shared_examples "a config observer" do
context "when ignore post-install messages for gem is set" do
- let(:config) { "ignore_messages.myrack true" }
+ let(:config) { "ignore_messages.rack true" }
it "doesn't display gem's post-install message" do
- expect(out).not_to include("Myrack's post install message")
+ expect(out).not_to include("Rack's post install message")
end
end
@@ -35,8 +35,8 @@ RSpec.describe "bundle update" do
shared_examples "a post-install message outputter" do
it "should display post-install messages for updated gems" do
- expect(out).to include("Post-install message from myrack:")
- expect(out).to include("Myrack's post install message")
+ expect(out).to include("Post-install message from rack:")
+ expect(out).to include("Rack's post install message")
end
it "should not display the post-install message for non-updated gems" do
@@ -47,12 +47,12 @@ RSpec.describe "bundle update" do
context "when listed gem is updated" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack'
gem 'thin'
G
- bundle :update, all: true
+ bundle :update, :all => true
end
it_behaves_like "a post-install message outputter"
@@ -62,12 +62,12 @@ RSpec.describe "bundle update" do
context "when dependency triggers update" do
before do
gemfile <<-G
- source "https://gem.repo1"
- gem 'myrack-obama'
+ source "#{file_uri_for(gem_repo1)}"
+ gem 'rack-obama'
gem 'thin'
G
- bundle :update, all: true
+ bundle :update, :all => true
end
it_behaves_like "a post-install message outputter"
diff --git a/spec/bundler/update/git_spec.rb b/spec/bundler/update/git_spec.rb
index 64124e0920..59e3d2f5fb 100644
--- a/spec/bundler/update/git_spec.rb
+++ b/spec/bundler/update/git_spec.rb
@@ -4,10 +4,10 @@ RSpec.describe "bundle update" do
describe "git sources" do
it "floats on a branch when :branch is used" do
build_git "foo", "1.0"
- update_git "foo", branch: "omg"
+ update_git "foo", :branch => "omg"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo-1.0")}", :branch => "omg" do
gem 'foo'
end
@@ -17,20 +17,20 @@ RSpec.describe "bundle update" do
s.write "lib/foo.rb", "FOO = '1.1'"
end
- bundle "update", all: true
+ bundle "update", :all => true
expect(the_bundle).to include_gems "foo 1.1"
end
it "updates correctly when you have like craziness" do
- build_lib "activesupport", "3.0", path: lib_path("rails/activesupport")
- build_git "rails", "3.0", path: lib_path("rails") do |s|
+ build_lib "activesupport", "3.0", :path => lib_path("rails/activesupport")
+ build_git "rails", "3.0", :path => lib_path("rails") do |s|
s.add_dependency "activesupport", "= 3.0"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "rails", :git => "#{lib_path("rails")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rails", :git => "#{file_uri_for(lib_path("rails"))}"
G
bundle "update rails"
@@ -38,17 +38,17 @@ RSpec.describe "bundle update" do
end
it "floats on a branch when :branch is used and the source is specified in the update" do
- build_git "foo", "1.0", path: lib_path("foo")
- update_git "foo", branch: "omg", path: lib_path("foo")
+ build_git "foo", "1.0", :path => lib_path("foo")
+ update_git "foo", :branch => "omg", :path => lib_path("foo")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
git "#{lib_path("foo")}", :branch => "omg" do
gem 'foo'
end
G
- update_git "foo", path: lib_path("foo") do |s|
+ update_git "foo", :path => lib_path("foo") do |s|
s.write "lib/foo.rb", "FOO = '1.1'"
end
@@ -58,18 +58,18 @@ RSpec.describe "bundle update" do
end
it "floats on main when updating all gems that are pinned to the source even if you have child dependencies" do
- build_git "foo", path: lib_path("foo")
- build_gem "bar", to_bundle: true do |s|
+ build_git "foo", :path => lib_path("foo")
+ build_gem "bar", :to_bundle => true do |s|
s.add_dependency "foo"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo"))}"
gem "bar"
G
- update_git "foo", path: lib_path("foo") do |s|
+ update_git "foo", :path => lib_path("foo") do |s|
s.write "lib/foo.rb", "FOO = '1.1'"
end
@@ -79,47 +79,47 @@ RSpec.describe "bundle update" do
end
it "notices when you change the repo url in the Gemfile" do
- build_git "foo", path: lib_path("foo_one")
- build_git "foo", path: lib_path("foo_two")
+ build_git "foo", :path => lib_path("foo_one")
+ build_git "foo", :path => lib_path("foo_two")
install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", "1.0", :git => "#{lib_path("foo_one")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", "1.0", :git => "#{file_uri_for(lib_path("foo_one"))}"
G
FileUtils.rm_rf lib_path("foo_one")
install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", "1.0", :git => "#{lib_path("foo_two")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", "1.0", :git => "#{file_uri_for(lib_path("foo_two"))}"
G
expect(err).to be_empty
- expect(out).to include("Fetching #{lib_path}/foo_two")
+ expect(out).to include("Fetching #{file_uri_for(lib_path)}/foo_two")
expect(out).to include("Bundle complete!")
end
it "fetches tags from the remote" do
build_git "foo"
- @remote = build_git("bar", bare: true)
- update_git "foo", remote: @remote.path
- update_git "foo", push: "main"
+ @remote = build_git("bar", :bare => true)
+ update_git "foo", :remote => file_uri_for(@remote.path)
+ update_git "foo", :push => "main"
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{@remote.path}"
G
# Create a new tag on the remote that needs fetching
- update_git "foo", tag: "fubar"
- update_git "foo", push: "fubar"
+ update_git "foo", :tag => "fubar"
+ update_git "foo", :push => "fubar"
gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{@remote.path}", :tag => "fubar"
G
- bundle "update", all: true
+ bundle "update", :all => true
expect(err).to be_empty
end
@@ -142,13 +142,13 @@ RSpec.describe "bundle update" do
s.add_dependency "submodule"
end
- git "submodule add #{lib_path("submodule-1.0")} submodule-1.0", lib_path("has_submodule-1.0")
- git "commit -m \"submodulator\"", lib_path("has_submodule-1.0")
+ sys_exec "git submodule add #{lib_path("submodule-1.0")} submodule-1.0", :dir => lib_path("has_submodule-1.0")
+ sys_exec "git commit -m \"submodulator\"", :dir => lib_path("has_submodule-1.0")
end
it "it unlocks the source when submodules are added to a git source" do
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
git "#{lib_path("has_submodule-1.0")}" do
gem "has_submodule"
end
@@ -158,7 +158,7 @@ RSpec.describe "bundle update" do
expect(out).to eq("GEM")
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
git "#{lib_path("has_submodule-1.0")}", :submodules => true do
gem "has_submodule"
end
@@ -168,9 +168,9 @@ RSpec.describe "bundle update" do
expect(out).to eq("GIT")
end
- it "unlocks the source when submodules are removed from git source", git: ">= 2.9.0" do
+ it "unlocks the source when submodules are removed from git source", :git => ">= 2.9.0" do
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
git "#{lib_path("has_submodule-1.0")}", :submodules => true do
gem "has_submodule"
end
@@ -180,7 +180,7 @@ RSpec.describe "bundle update" do
expect(out).to eq("GIT")
install_gemfile <<-G
- source "https://gem.repo4"
+ source "#{file_uri_for(gem_repo4)}"
git "#{lib_path("has_submodule-1.0")}" do
gem "has_submodule"
end
@@ -195,67 +195,67 @@ RSpec.describe "bundle update" do
build_git "foo", "1.0"
install_gemfile <<-G
- source "https://gem.repo1"
- gem "foo", :git => "#{lib_path("foo-1.0")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "foo", :git => "#{file_uri_for(lib_path("foo-1.0"))}"
G
lib_path("foo-1.0").join(".git").rmtree
- bundle :update, all: true, raise_on_error: false
+ bundle :update, :all => true, :raise_on_error => false
expect(err).to include(lib_path("foo-1.0").to_s).
and match(/Git error: command `git fetch.+has failed/)
end
it "should not explode on invalid revision on update of gem by name" do
- build_git "myrack", "0.8"
+ build_git "rack", "0.8"
- build_git "myrack", "0.8", path: lib_path("local-myrack") do |s|
- s.write "lib/myrack.rb", "puts :LOCAL"
+ build_git "rack", "0.8", :path => lib_path("local-rack") do |s|
+ s.write "lib/rack.rb", "puts :LOCAL"
end
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack", :git => "#{lib_path("myrack-0.8")}", :branch => "main"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack", :git => "#{file_uri_for(lib_path("rack-0.8"))}", :branch => "main"
G
- bundle %(config set local.myrack #{lib_path("local-myrack")})
- bundle "update myrack"
+ bundle %(config set local.rack #{lib_path("local-rack")})
+ bundle "update rack"
expect(out).to include("Bundle updated!")
end
it "shows the previous version of the gem" do
- build_git "rails", "2.3.2", path: lib_path("rails")
+ build_git "rails", "2.3.2", :path => lib_path("rails")
install_gemfile <<-G
- source "https://gem.repo1"
- gem "rails", :git => "#{lib_path("rails")}"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rails", :git => "#{file_uri_for(lib_path("rails"))}"
G
- update_git "rails", "3.0", path: lib_path("rails"), gemspec: true
+ update_git "rails", "3.0", :path => lib_path("rails"), :gemspec => true
- bundle "update", all: true
- expect(out).to include("Using rails 3.0 (was 2.3.2) from #{lib_path("rails")} (at main@#{revision_for(lib_path("rails"))[0..6]})")
+ bundle "update", :all => true
+ expect(out).to include("Using rails 3.0 (was 2.3.2) from #{file_uri_for(lib_path("rails"))} (at main@#{revision_for(lib_path("rails"))[0..6]})")
end
end
describe "with --source flag" do
before :each do
build_repo2
- @git = build_git "foo", path: lib_path("foo") do |s|
+ @git = build_git "foo", :path => lib_path("foo") do |s|
s.executables = "foobar"
end
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
git "#{lib_path("foo")}" do
gem 'foo'
end
- gem 'myrack'
+ gem 'rack'
G
end
it "updates the source" do
- update_git "foo", path: @git.path
+ update_git "foo", :path => @git.path
bundle "update --source foo"
@@ -268,7 +268,7 @@ RSpec.describe "bundle update" do
end
it "unlocks gems that were originally pulled in by the source" do
- update_git "foo", "2.0", path: @git.path
+ update_git "foo", "2.0", :path => @git.path
bundle "update --source foo"
expect(the_bundle).to include_gems "foo 2.0"
@@ -276,24 +276,24 @@ RSpec.describe "bundle update" do
it "leaves all other gems frozen" do
update_repo2
- update_git "foo", path: @git.path
+ update_git "foo", :path => @git.path
bundle "update --source foo"
- expect(the_bundle).to include_gems "myrack 1.0"
+ expect(the_bundle).to include_gems "rack 1.0"
end
end
context "when the gem and the repository have different names" do
before :each do
build_repo2
- @git = build_git "foo", path: lib_path("bar")
+ @git = build_git "foo", :path => lib_path("bar")
install_gemfile <<-G
- source "https://gem.repo2"
+ source "#{file_uri_for(gem_repo2)}"
git "#{lib_path("bar")}" do
gem 'foo'
end
- gem 'myrack'
+ gem 'rack'
G
end
@@ -301,7 +301,7 @@ RSpec.describe "bundle update" do
spec_lines = lib_path("bar/foo.gemspec").read.split("\n")
spec_lines[5] = "s.version = '2.0'"
- update_git "foo", "2.0", path: @git.path do |s|
+ update_git "foo", "2.0", :path => @git.path do |s|
s.write "foo.gemspec", spec_lines.join("\n")
end
@@ -309,11 +309,6 @@ RSpec.describe "bundle update" do
bundle "update --source bar"
- checksums = checksums_section_when_enabled do |c|
- c.no_checksum "foo", "2.0"
- c.checksum gem_repo2, "myrack", "1.0.0"
- end
-
expect(lockfile).to eq <<~G
GIT
remote: #{@git.path}
@@ -322,17 +317,17 @@ RSpec.describe "bundle update" do
foo (2.0)
GEM
- remote: https://gem.repo2/
+ remote: #{file_uri_for(gem_repo2)}/
specs:
- myrack (1.0.0)
+ rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
foo!
- myrack
- #{checksums}
+ rack
+
BUNDLED WITH
#{Bundler::VERSION}
G
diff --git a/spec/bundler/update/path_spec.rb b/spec/bundler/update/path_spec.rb
index 8c76c94e1a..756770313b 100644
--- a/spec/bundler/update/path_spec.rb
+++ b/spec/bundler/update/path_spec.rb
@@ -3,14 +3,14 @@
RSpec.describe "path sources" do
describe "bundle update --source" do
it "shows the previous version of the gem when updated from path source" do
- build_lib "activesupport", "2.3.5", path: lib_path("rails/activesupport")
+ build_lib "activesupport", "2.3.5", :path => lib_path("rails/activesupport")
install_gemfile <<-G
- source "https://gem.repo1"
+ source "#{file_uri_for(gem_repo1)}"
gem "activesupport", :path => "#{lib_path("rails/activesupport")}"
G
- build_lib "activesupport", "3.0", path: lib_path("rails/activesupport")
+ build_lib "activesupport", "3.0", :path => lib_path("rails/activesupport")
bundle "update --source activesupport"
expect(out).to include("Using activesupport 3.0 (was 2.3.5) from source at `#{lib_path("rails/activesupport")}`")
diff --git a/spec/bundler/update/redownload_spec.rb b/spec/bundler/update/redownload_spec.rb
index 66437fb938..147be823f5 100644
--- a/spec/bundler/update/redownload_spec.rb
+++ b/spec/bundler/update/redownload_spec.rb
@@ -3,42 +3,32 @@
RSpec.describe "bundle update" do
before :each do
install_gemfile <<-G
- source "https://gem.repo1"
- gem "myrack"
+ source "#{file_uri_for(gem_repo1)}"
+ gem "rack"
G
end
describe "with --force" do
- it "shows a deprecation when single flag passed", bundler: 2 do
- bundle "update myrack --force"
+ it "shows a deprecation when single flag passed", :bundler => 2 do
+ bundle "update rack --force"
expect(err).to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
end
- it "shows a deprecation when multiple flags passed", bundler: 2 do
- bundle "update myrack --no-color --force"
+ it "shows a deprecation when multiple flags passed", :bundler => 2 do
+ bundle "update rack --no-color --force"
expect(err).to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
end
end
describe "with --redownload" do
it "does not show a deprecation when single flag passed" do
- bundle "update myrack --redownload"
+ bundle "update rack --redownload"
expect(err).not_to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
end
it "does not show a deprecation when single multiple flags passed" do
- bundle "update myrack --no-color --redownload"
+ bundle "update rack --no-color --redownload"
expect(err).not_to include "[DEPRECATED] The `--force` option has been renamed to `--redownload`"
end
-
- it "re-installs installed gems" do
- myrack_lib = default_bundle_path("gems/myrack-1.0.0/lib/myrack.rb")
- myrack_lib.open("w") {|f| f.write("blah blah blah") }
- bundle :update, redownload: true
-
- expect(out).to include "Installing myrack 1.0.0"
- expect(myrack_lib.open(&:read)).to eq("MYRACK = '1.0.0'\n")
- expect(the_bundle).to include_gems "myrack 1.0.0"
- end
end
end
diff --git a/spec/default.mspec b/spec/default.mspec
index ecd3f3afe9..0dba98306c 100644
--- a/spec/default.mspec
+++ b/spec/default.mspec
@@ -3,14 +3,9 @@ $VERBOSE = false
if (opt = ENV["RUBYOPT"]) and (opt = opt.dup).sub!(/(?:\A|\s)-w(?=\z|\s)/, '')
ENV["RUBYOPT"] = opt
end
-
-# Enable constant leak checks by ruby/mspec
-ENV["CHECK_CONSTANT_LEAKS"] ||= "true"
-
require "./rbconfig" unless defined?(RbConfig)
-require_relative "../tool/test-coverage" if ENV.key?("COVERAGE")
load File.dirname(__FILE__) + '/ruby/default.mspec'
-OBJDIR = File.expand_path("spec/ruby/optional/capi/ext") unless defined?(OBJDIR)
+OBJDIR = File.expand_path("spec/ruby/optional/capi/ext")
class MSpecScript
@testing_ruby = true
@@ -30,20 +25,6 @@ class MSpecScript
--
]
end
-
- # Disable to run for bundled gems in test-spec
- set :bundled_gems, (File.readlines("#{srcdir}/gems/bundled_gems").map do |line|
- next if /^\s*(?:#|$)/ =~ line
- "#{srcdir}/spec/ruby/library/" + line.split.first
- end.compact)
- set :stdlibs, Dir.glob("#{srcdir}/spec/ruby/library/*")
- set :library, get(:stdlibs).to_a - get(:bundled_gems).to_a
-
- set :files, get(:command_line) + get(:language) + get(:core) + get(:library) + get(:security) + get(:optional)
-
- if ENV.key?("COVERAGE")
- set :excludes, ["Coverage"]
- end
end
module MSpecScript::JobServer
@@ -84,76 +65,3 @@ end
class MSpecScript
prepend JobServer
end
-
-require 'mspec/runner/formatters/dotted'
-
-class DottedFormatter
- prepend Module.new {
- BASE = __dir__ + "/ruby/" unless defined?(BASE)
- COUNT_WIDTH = 6 unless defined?(COUNT_WIDTH)
-
- def initialize(out = nil)
- super
- if out
- @columns = nil
- else
- columns = ENV["COLUMNS"]&.to_i
- columns = 80 unless columns&.nonzero?
- w = COUNT_WIDTH + 1
- round = 20
- @columns = (columns - w) / round * round + w
- end
- @dotted = 0
- @loaded = false
- @count = 0
- end
-
- def register
- super
- MSpec.register :load, self
- MSpec.register :unload, self
- end
-
- def after(*)
- if @columns
- if @dotted == 0
- s = sprintf("%*d ", COUNT_WIDTH, @count)
- print(s)
- @dotted += s.size
- end
- @count +=1
- end
- super
- if @columns and (@dotted += 1) >= @columns
- print "\n"
- @dotted = 0
- end
- end
-
- def load(*)
- file = MSpec.file || MSpec.files_array.first
- @loaded = true
- s = "#{file.delete_prefix(BASE)}:"
- print s
- if @columns
- if (@dotted += s.size) >= @columns
- print "\n"
- @dotted = 0
- else
- print " "
- @dotted += 1
- end
- end
- @count = 0
- end
-
- def unload
- super
- if @loaded
- print "\n" if @dotted > 0
- @dotted = 0
- @loaded = nil
- end
- end
- }
-end
diff --git a/spec/lib/formatter_overrides.rb b/spec/lib/formatter_overrides.rb
deleted file mode 100644
index 4a61d425d1..0000000000
--- a/spec/lib/formatter_overrides.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-module FormatterOverrides
- def example_pending(_); end
- def dump_pending(_); end
-end
-
-RSpec::Core::Formatters::ProgressFormatter.prepend FormatterOverrides
diff --git a/spec/lib/spec_coverage.rb b/spec/lib/spec_coverage.rb
deleted file mode 100644
index 34aed32f72..0000000000
--- a/spec/lib/spec_coverage.rb
+++ /dev/null
@@ -1 +0,0 @@
-require_relative "../../tool/test-coverage" if ENV.key?('COVERAGE')
diff --git a/spec/mspec/lib/mspec/commands/mspec.rb b/spec/mspec/lib/mspec/commands/mspec.rb
index f5341c699d..9c38cebcda 100755
--- a/spec/mspec/lib/mspec/commands/mspec.rb
+++ b/spec/mspec/lib/mspec/commands/mspec.rb
@@ -38,6 +38,11 @@ class MSpecMain < MSpecScript
options.targets
+ options.on("--warnings", "Don't suppress warnings") do
+ config[:flags] << '-w'
+ ENV['OUTPUT_WARNINGS'] = '1'
+ end
+
options.on("-j", "--multi", "Run multiple (possibly parallel) subprocesses") do
config[:multi] = true
end
diff --git a/spec/mspec/lib/mspec/guards/platform.rb b/spec/mspec/lib/mspec/guards/platform.rb
index 03c0fca8f5..e87b08a4c1 100644
--- a/spec/mspec/lib/mspec/guards/platform.rb
+++ b/spec/mspec/lib/mspec/guards/platform.rb
@@ -53,27 +53,23 @@ class PlatformGuard < SpecGuard
end
end
+ WORD_SIZE = 1.size * 8
+
POINTER_SIZE = begin
require 'rbconfig/sizeof'
RbConfig::SIZEOF["void*"] * 8
rescue LoadError
- [0].pack('j').size
+ WORD_SIZE
end
- C_LONG_SIZE = if defined?(RbConfig::SIZEOF[])
- RbConfig::SIZEOF["long"] * 8
- else
- [0].pack('l!').size
+ def self.wordsize?(size)
+ size == WORD_SIZE
end
def self.pointer_size?(size)
size == POINTER_SIZE
end
- def self.c_long_size?(size)
- size == C_LONG_SIZE
- end
-
def initialize(*args)
if args.last.is_a?(Hash)
@options, @platforms = args.last, args[0..-2]
@@ -89,10 +85,10 @@ class PlatformGuard < SpecGuard
case key
when :os
match &&= PlatformGuard.os?(*value)
+ when :wordsize
+ match &&= PlatformGuard.wordsize? value
when :pointer_size
match &&= PlatformGuard.pointer_size? value
- when :c_long_size
- match &&= PlatformGuard::c_long_size? value
end
end
match
diff --git a/spec/mspec/lib/mspec/helpers/io.rb b/spec/mspec/lib/mspec/helpers/io.rb
index 2ad14f47a1..29c6c37a1a 100644
--- a/spec/mspec/lib/mspec/helpers/io.rb
+++ b/spec/mspec/lib/mspec/helpers/io.rb
@@ -7,7 +7,7 @@ class IOStub
end
def write(*str)
- self << str.join('')
+ self << str.join
end
def << str
@@ -16,7 +16,7 @@ class IOStub
end
def print(*str)
- write(str.join('') + $\.to_s)
+ write(str.join + $\.to_s)
end
def method_missing(name, *args, &block)
diff --git a/spec/mspec/lib/mspec/helpers/numeric.rb b/spec/mspec/lib/mspec/helpers/numeric.rb
index d877fc9296..c1ed81a233 100644
--- a/spec/mspec/lib/mspec/helpers/numeric.rb
+++ b/spec/mspec/lib/mspec/helpers/numeric.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: true
require 'mspec/guards/platform'
def nan_value
@@ -16,13 +15,11 @@ def bignum_value(plus = 0)
end
def max_long
- long_byte_size = [0].pack('l!').size
- 2**(long_byte_size * 8 - 1) - 1
+ 2**(0.size * 8 - 1) - 1
end
def min_long
- long_byte_size = [0].pack('l!').size
- -(2**(long_byte_size * 8 - 1))
+ -(2**(0.size * 8 - 1))
end
# This is a bit hairy, but we need to be able to write specs that cover the
@@ -31,24 +28,7 @@ end
# specs based on the relationship between values rather than specific
# values.
if PlatformGuard.standard? or PlatformGuard.implementation? :topaz
- limits_available = begin
- require 'rbconfig/sizeof'
- defined?(RbConfig::LIMITS.[]) && ['FIXNUM_MAX', 'FIXNUM_MIN'].all? do |key|
- Integer === RbConfig::LIMITS[key]
- end
- rescue LoadError
- false
- end
-
- if limits_available
- def fixnum_max
- RbConfig::LIMITS['FIXNUM_MAX']
- end
-
- def fixnum_min
- RbConfig::LIMITS['FIXNUM_MIN']
- end
- elsif PlatformGuard.c_long_size? 32
+ if PlatformGuard.wordsize? 32
def fixnum_max
(2**30) - 1
end
@@ -56,7 +36,7 @@ if PlatformGuard.standard? or PlatformGuard.implementation? :topaz
def fixnum_min
-(2**30)
end
- elsif PlatformGuard.c_long_size? 64
+ elsif PlatformGuard.wordsize? 64
def fixnum_max
(2**62) - 1
end
diff --git a/spec/mspec/lib/mspec/helpers/ruby_exe.rb b/spec/mspec/lib/mspec/helpers/ruby_exe.rb
index 2e499d6f9a..7fde001cda 100644
--- a/spec/mspec/lib/mspec/helpers/ruby_exe.rb
+++ b/spec/mspec/lib/mspec/helpers/ruby_exe.rb
@@ -140,44 +140,28 @@ def ruby_exe(code = :not_given, opts = {})
expected_status = opts.fetch(:exit_status, 0)
begin
- command = ruby_cmd(code, opts)
-
- # Try to avoid the extra shell for 2>&1
- # This is notably useful for TimeoutAction which can then signal the ruby subprocess and not the shell
- popen_options = []
- if command.end_with?(' 2>&1')
- command = command[0...-5]
- popen_options = [{ err: [:child, :out] }]
- end
-
- output = IO.popen(command, *popen_options) do |io|
- pid = io.pid
- MSpec.subprocesses << pid
- begin
- io.read
- ensure
- MSpec.subprocesses.delete(pid)
+ platform_is_not :opal do
+ command = ruby_cmd(code, opts)
+ output = `#{command}`
+ status = Process.last_status
+
+ exit_status = if status.exited?
+ status.exitstatus
+ elsif status.signaled?
+ signame = Signal.signame status.termsig
+ raise "No signal name?" unless signame
+ :"SIG#{signame}"
+ else
+ raise SpecExpectationNotMetError, "#{exit_status.inspect} is neither exited? nor signaled?"
+ end
+ if exit_status != expected_status
+ formatted_output = output.lines.map { |line| " #{line}" }.join
+ raise SpecExpectationNotMetError,
+ "Expected exit status is #{expected_status.inspect} but actual is #{exit_status.inspect} for command ruby_exe(#{command.inspect})\nOutput:\n#{formatted_output}"
end
- end
- status = Process.last_status
-
- exit_status = if status.exited?
- status.exitstatus
- elsif status.signaled?
- signame = Signal.signame status.termsig
- raise "No signal name?" unless signame
- :"SIG#{signame}"
- else
- raise SpecExpectationNotMetError, "#{exit_status.inspect} is neither exited? nor signaled?"
- end
- if exit_status != expected_status
- formatted_output = output.lines.map { |line| " #{line}" }.join
- raise SpecExpectationNotMetError,
- "Expected exit status is #{expected_status.inspect} but actual is #{exit_status.inspect} for command ruby_exe(#{command.inspect})\nOutput:\n#{formatted_output}"
+ output
end
-
- output
ensure
saved_env.each { |key, value| ENV[key] = value }
env.keys.each do |key|
diff --git a/spec/mspec/lib/mspec/helpers/tmp.rb b/spec/mspec/lib/mspec/helpers/tmp.rb
index e903dd9f50..b2a38ee983 100644
--- a/spec/mspec/lib/mspec/helpers/tmp.rb
+++ b/spec/mspec/lib/mspec/helpers/tmp.rb
@@ -12,7 +12,7 @@ else
end
SPEC_TEMP_DIR = spec_temp_dir
-SPEC_TEMP_UNIQUIFIER = +"0"
+SPEC_TEMP_UNIQUIFIER = "0"
at_exit do
begin
@@ -36,25 +36,11 @@ all specs are cleaning up temporary files:
end
def tmp(name, uniquify = true)
- if Dir.exist? SPEC_TEMP_DIR
- stat = File.stat(SPEC_TEMP_DIR)
- if stat.world_writable? and !stat.sticky?
- raise ArgumentError, "SPEC_TEMP_DIR (#{SPEC_TEMP_DIR}) is world writable but not sticky"
- end
- else
- platform_is_not :windows do
- umask = File.umask
- if (umask & 0002) == 0 # o+w
- raise ArgumentError, "File.umask #=> #{umask.to_s(8)} (world-writable)"
- end
- end
- mkdir_p SPEC_TEMP_DIR
- end
+ mkdir_p SPEC_TEMP_DIR unless Dir.exist? SPEC_TEMP_DIR
if uniquify and !name.empty?
slash = name.rindex "/"
index = slash ? slash + 1 : 0
- name = +name
name.insert index, "#{SPEC_TEMP_UNIQUIFIER.succ!}-"
end
diff --git a/spec/mspec/lib/mspec/matchers/complain.rb b/spec/mspec/lib/mspec/matchers/complain.rb
index 19310c0bbb..887e72b4b0 100644
--- a/spec/mspec/lib/mspec/matchers/complain.rb
+++ b/spec/mspec/lib/mspec/matchers/complain.rb
@@ -19,6 +19,7 @@ class ComplainMatcher
@verbose = $VERBOSE
err = IOStub.new
+ Thread.current[:in_mspec_complain_matcher] = true
$stderr = err
$VERBOSE = @options.key?(:verbose) ? @options[:verbose] : false
begin
@@ -26,6 +27,7 @@ class ComplainMatcher
ensure
$VERBOSE = @verbose
$stderr = @saved_err
+ Thread.current[:in_mspec_complain_matcher] = false
end
@warning = err.to_s
diff --git a/spec/mspec/lib/mspec/mocks/mock.rb b/spec/mspec/lib/mspec/mocks/mock.rb
index c61ba35ea7..28a083cc15 100644
--- a/spec/mspec/lib/mspec/mocks/mock.rb
+++ b/spec/mspec/lib/mspec/mocks/mock.rb
@@ -18,16 +18,20 @@ module Mock
@stubs ||= Hash.new { |h,k| h[k] = [] }
end
- def self.replaced_name(key)
- :"__mspec_#{key.last}__"
+ def self.replaced_name(obj, sym)
+ :"__mspec_#{obj.__id__}_#{sym}__"
end
def self.replaced_key(obj, sym)
- [obj.__id__, sym]
+ [replaced_name(obj, sym), sym]
end
- def self.replaced?(key)
- mocks.include?(key) or stubs.include?(key)
+ def self.has_key?(keys, sym)
+ !!keys.find { |k| k.first == sym }
+ end
+
+ def self.replaced?(sym)
+ has_key?(mocks.keys, sym) or has_key?(stubs.keys, sym)
end
def self.clear_replaced(key)
@@ -36,9 +40,8 @@ module Mock
end
def self.mock_respond_to?(obj, sym, include_private = false)
- key = replaced_key(obj, :respond_to?)
- if replaced? key
- name = replaced_name(key)
+ name = replaced_name(obj, :respond_to?)
+ if replaced? name
obj.__send__ name, sym, include_private
else
obj.respond_to? sym, include_private
@@ -56,8 +59,8 @@ module Mock
return
end
- if (sym == :respond_to? or mock_respond_to?(obj, sym, true)) and !replaced?(key)
- meta.__send__ :alias_method, replaced_name(key), sym
+ if (sym == :respond_to? or mock_respond_to?(obj, sym, true)) and !replaced?(key.first)
+ meta.__send__ :alias_method, key.first, sym
end
suppress_warning {
@@ -188,7 +191,7 @@ module Mock
next
end
- replaced = replaced_name(key)
+ replaced = key.first
sym = key.last
meta = obj.singleton_class
diff --git a/spec/mspec/lib/mspec/runner/actions/leakchecker.rb b/spec/mspec/lib/mspec/runner/actions/leakchecker.rb
index 0a8c9c3252..69181b71d3 100644
--- a/spec/mspec/lib/mspec/runner/actions/leakchecker.rb
+++ b/spec/mspec/lib/mspec/runner/actions/leakchecker.rb
@@ -132,14 +132,14 @@ class LeakChecker
attr_accessor :count
end
- def new(...)
+ def new(data)
LeakChecker::TempfileCounter.count += 1
- super
+ super(data)
end
}
LeakChecker.const_set(:TempfileCounter, m)
- class << Tempfile
+ class << Tempfile::Remover
prepend LeakChecker::TempfileCounter
end
end
@@ -301,7 +301,6 @@ class LeakCheckerAction
end
def start
- disable_nss_modules
@checker = LeakChecker.new
end
@@ -317,61 +316,4 @@ class LeakCheckerAction
end
end
end
-
- private
-
- # This function is intended to disable all NSS modules when ruby is compiled
- # against glibc. NSS modules allow the system administrator to load custom
- # shared objects into all processes using glibc, and use them to customise
- # the behaviour of username, groupname, hostname, etc lookups. This is
- # normally configured in the file /etc/nsswitch.conf.
- # These modules often do things like open cache files or connect to system
- # daemons like sssd or dbus, which of course means they have open file
- # descriptors of their own. This can cause the leak-checking functionality
- # in this file to report that such descriptors have been leaked, and fail
- # the test suite.
- # This function uses glibc's __nss_configure_lookup function to override any
- # configuration in /etc/nsswitch.conf, and just use the built in files/dns
- # name lookup functionality (which is of course perfectly sufficient for
- # running ruby/spec).
- def disable_nss_modules
- begin
- require 'fiddle'
- rescue LoadError
- # Make sure it's possible to run the test suite on a ruby implementation
- # which does not (yet?) have Fiddle.
- return
- end
-
- begin
- libc = Fiddle.dlopen(nil)
- # Older versions of fiddle don't have Fiddle::Type (and instead rely on Fiddle::TYPE_)
- # Even older versions of fiddle don't have CONST_STRING,
- string_type = defined?(Fiddle::TYPE_CONST_STRING) ? Fiddle::TYPE_CONST_STRING : Fiddle::TYPE_VOIDP
- nss_configure_lookup = Fiddle::Function.new(
- libc['__nss_configure_lookup'],
- [string_type, string_type],
- Fiddle::TYPE_INT
- )
- rescue Fiddle::DLError
- # We're not running with glibc - no need to do this.
- return
- end
-
- nss_configure_lookup.call 'passwd', 'files'
- nss_configure_lookup.call 'shadow', 'files'
- nss_configure_lookup.call 'group', 'files'
- nss_configure_lookup.call 'hosts', 'files dns'
- nss_configure_lookup.call 'services', 'files'
- nss_configure_lookup.call 'netgroup', 'files'
- nss_configure_lookup.call 'automount', 'files'
- nss_configure_lookup.call 'aliases', 'files'
- nss_configure_lookup.call 'ethers', 'files'
- nss_configure_lookup.call 'gshadow', 'files'
- nss_configure_lookup.call 'initgroups', 'files'
- nss_configure_lookup.call 'networks', 'files dns'
- nss_configure_lookup.call 'protocols', 'files'
- nss_configure_lookup.call 'publickey', 'files'
- nss_configure_lookup.call 'rpc', 'files'
- end
end
diff --git a/spec/mspec/lib/mspec/runner/actions/timeout.rb b/spec/mspec/lib/mspec/runner/actions/timeout.rb
index 1200926872..543b7366d7 100644
--- a/spec/mspec/lib/mspec/runner/actions/timeout.rb
+++ b/spec/mspec/lib/mspec/runner/actions/timeout.rb
@@ -3,8 +3,6 @@ class TimeoutAction
@timeout = timeout
@queue = Queue.new
@started = now
- @fail = false
- @error_message = "took longer than the configured timeout of #{@timeout}s"
end
def register
@@ -39,26 +37,15 @@ class TimeoutAction
elapsed = now - @started
if elapsed > @timeout
if @current_state
- STDERR.puts "\nExample #{@error_message}:"
+ STDERR.puts "\nExample took longer than the configured timeout of #{@timeout}s:"
STDERR.puts "#{@current_state.description}"
else
- STDERR.puts "\nSome code outside an example #{@error_message}"
+ STDERR.puts "\nSome code outside an example took longer than the configured timeout of #{@timeout}s"
end
STDERR.flush
show_backtraces
- if MSpec.subprocesses.empty?
- exit! 2
- else
- # Do not exit but signal the subprocess so we can get their output
- MSpec.subprocesses.each do |pid|
- kill_wait_one_second :SIGTERM, pid
- hard_kill :SIGKILL, pid
- end
- @fail = true
- @current_state = nil
- break # stop this thread, will fail in #after
- end
+ exit 2
end
end
end
@@ -78,11 +65,6 @@ class TimeoutAction
@queue << -> do
@current_state = nil
end
-
- if @fail
- STDERR.puts "\n\nThe last example #{@error_message}. See above for the subprocess stacktrace."
- exit! 2
- end
end
def finish
@@ -90,54 +72,20 @@ class TimeoutAction
@thread.join
end
- private def hard_kill(signal, pid)
- begin
- Process.kill signal, pid
- rescue Errno::ESRCH
- # Process already terminated
- end
- end
-
- private def kill_wait_one_second(signal, pid)
- begin
- Process.kill signal, pid
+ private def show_backtraces
+ if RUBY_ENGINE == 'truffleruby'
+ STDERR.puts 'Java stacktraces:'
+ Process.kill :SIGQUIT, Process.pid
sleep 1
- rescue Errno::ESRCH
- # Process already terminated
end
- end
- private def show_backtraces
- java_stacktraces = -> pid {
- if RUBY_ENGINE == 'truffleruby' || RUBY_ENGINE == 'jruby'
- STDERR.puts 'Java stacktraces:'
- kill_wait_one_second :SIGQUIT, pid
- end
- }
-
- if MSpec.subprocesses.empty?
- java_stacktraces.call Process.pid
-
- STDERR.puts "\nRuby backtraces:"
- if defined?(Truffle::Debug.show_backtraces)
- Truffle::Debug.show_backtraces
- else
- Thread.list.each do |thread|
- unless thread == Thread.current
- STDERR.puts thread.inspect, thread.backtrace, ''
- end
- end
- end
+ STDERR.puts "\nRuby backtraces:"
+ if defined?(Truffle::Debug.show_backtraces)
+ Truffle::Debug.show_backtraces
else
- MSpec.subprocesses.each do |pid|
- STDERR.puts "\nFor subprocess #{pid}"
- java_stacktraces.call pid
-
- if RUBY_ENGINE == 'truffleruby'
- STDERR.puts "\nRuby backtraces:"
- kill_wait_one_second :SIGALRM, pid
- else
- STDERR.puts "Don't know how to print backtraces of a subprocess on #{RUBY_ENGINE}"
+ Thread.list.each do |thread|
+ unless thread == Thread.current
+ STDERR.puts thread.inspect, thread.backtrace, ''
end
end
end
diff --git a/spec/mspec/lib/mspec/runner/formatters/base.rb b/spec/mspec/lib/mspec/runner/formatters/base.rb
index e3b5bb23e0..54a83c9c32 100644
--- a/spec/mspec/lib/mspec/runner/formatters/base.rb
+++ b/spec/mspec/lib/mspec/runner/formatters/base.rb
@@ -5,9 +5,6 @@ require 'mspec/utils/options'
if ENV['CHECK_LEAKS']
require 'mspec/runner/actions/leakchecker'
-end
-
-if ENV['CHECK_LEAKS'] || ENV['CHECK_CONSTANT_LEAKS']
require 'mspec/runner/actions/constants_leak_checker'
end
@@ -43,11 +40,8 @@ class BaseFormatter
@counter = @tally.counter
if ENV['CHECK_LEAKS']
+ save = ENV['CHECK_LEAKS'] == 'save'
LeakCheckerAction.new.register
- end
-
- if ENV['CHECK_LEAKS'] || ENV['CHECK_CONSTANT_LEAKS']
- save = ENV['CHECK_LEAKS'] == 'save' || ENV['CHECK_CONSTANT_LEAKS'] == 'save'
ConstantsLeakCheckerAction.new(save).register
end
diff --git a/spec/mspec/lib/mspec/runner/formatters/multi.rb b/spec/mspec/lib/mspec/runner/formatters/multi.rb
index fa1da3766b..a723ae8eb9 100644
--- a/spec/mspec/lib/mspec/runner/formatters/multi.rb
+++ b/spec/mspec/lib/mspec/runner/formatters/multi.rb
@@ -42,6 +42,6 @@ module MultiFormatter
end
def print_exception(exc, count)
- @err.print "\n#{count})\n#{exc}\n"
+ print "\n#{count})\n#{exc}\n"
end
end
diff --git a/spec/mspec/lib/mspec/runner/mspec.rb b/spec/mspec/lib/mspec/runner/mspec.rb
index 97c3f365bc..889e085175 100644
--- a/spec/mspec/lib/mspec/runner/mspec.rb
+++ b/spec/mspec/lib/mspec/runner/mspec.rb
@@ -38,10 +38,9 @@ module MSpec
@expectation = nil
@expectations = false
@skips = []
- @subprocesses = []
class << self
- attr_reader :file, :include, :exclude, :skips, :subprocesses
+ attr_reader :file, :include, :exclude, :skips
attr_writer :repeat, :randomize
attr_accessor :formatter
end
@@ -396,7 +395,7 @@ module MSpec
desc = tag.escape(tag.description)
file = tags_file
if File.exist? file
- lines = File.readlines(file)
+ lines = IO.readlines(file)
File.open(file, "w:utf-8") do |f|
lines.each do |line|
line = line.chomp
diff --git a/spec/mspec/lib/mspec/utils/options.rb b/spec/mspec/lib/mspec/utils/options.rb
index 3b5962dbe6..612caf6771 100644
--- a/spec/mspec/lib/mspec/utils/options.rb
+++ b/spec/mspec/lib/mspec/utils/options.rb
@@ -477,7 +477,7 @@ class MSpecOptions
def debug
on("-d", "--debug",
- "Disable MSpec backtrace filtering") do
+ "Set MSpec debugging flag for more verbose output") do
$MSPEC_DEBUG = true
end
end
diff --git a/spec/mspec/lib/mspec/utils/warnings.rb b/spec/mspec/lib/mspec/utils/warnings.rb
index 23efc696a5..0d3d36fada 100644
--- a/spec/mspec/lib/mspec/utils/warnings.rb
+++ b/spec/mspec/lib/mspec/utils/warnings.rb
@@ -8,3 +8,46 @@ if Object.const_defined?(:Warning) and Warning.respond_to?(:[]=)
Warning[:deprecated] = true
Warning[:experimental] = false
end
+
+if Object.const_defined?(:Warning) and Warning.respond_to?(:warn)
+ def Warning.warn(message, category: nil)
+ # Suppress any warning inside the method to prevent recursion
+ verbose = $VERBOSE
+ $VERBOSE = nil
+
+ if Thread.current[:in_mspec_complain_matcher]
+ return $stderr.write(message)
+ end
+
+ case message
+ # $VERBOSE = true warnings
+ when /(.+\.rb):(\d+):.+possibly useless use of (<|<=|==|>=|>) in void context/
+ # Make sure there is a .should otherwise it is missing
+ line_nb = Integer($2)
+ unless File.exist?($1) and /\.should(_not)? (<|<=|==|>=|>)/ === File.readlines($1)[line_nb-1]
+ $stderr.write message
+ end
+ when /possibly useless use of (\+|-) in void context/
+ when /assigned but unused variable/
+ when /method redefined/
+ when /previous definition of/
+ when /instance variable @.+ not initialized/
+ when /statement not reached/
+ when /shadowing outer local variable/
+ when /setting Encoding.default_(in|ex)ternal/
+ when /unknown (un)?pack directive/
+ when /(un)?trust(ed\?)? is deprecated/
+ when /\.exists\? is a deprecated name/
+ when /Float .+ out of range/
+ when /passing a block to String#(bytes|chars|codepoints|lines) is deprecated/
+ when /core\/string\/modulo_spec\.rb:\d+: warning: too many arguments for format string/
+ when /regexp\/shared\/new_ascii(_8bit)?\.rb:\d+: warning: Unknown escape .+ is ignored/
+ else
+ $stderr.write message
+ end
+ ensure
+ $VERBOSE = verbose
+ end
+else
+ $VERBOSE = nil unless ENV['OUTPUT_WARNINGS']
+end
diff --git a/spec/mspec/spec/commands/mspec_spec.rb b/spec/mspec/spec/commands/mspec_spec.rb
index d19bebb2d6..82201c2075 100644
--- a/spec/mspec/spec/commands/mspec_spec.rb
+++ b/spec/mspec/spec/commands/mspec_spec.rb
@@ -92,6 +92,33 @@ RSpec.describe MSpecMain, "#run" do
end
end
+RSpec.describe "The --warnings option" do
+ before :each do
+ @options, @config = new_option
+ allow(MSpecOptions).to receive(:new).and_return(@options)
+ @script = MSpecMain.new
+ allow(@script).to receive(:config).and_return(@config)
+ end
+
+ it "is enabled by #options" do
+ allow(@options).to receive(:on)
+ expect(@options).to receive(:on).with("--warnings", an_instance_of(String))
+ @script.options
+ end
+
+ it "sets flags to -w" do
+ @config[:flags] = []
+ @script.options ["--warnings"]
+ expect(@config[:flags]).to include("-w")
+ end
+
+ it "set OUTPUT_WARNINGS = '1' in the environment" do
+ ENV['OUTPUT_WARNINGS'] = '0'
+ @script.options ["--warnings"]
+ expect(ENV['OUTPUT_WARNINGS']).to eq('1')
+ end
+end
+
RSpec.describe "The -j, --multi option" do
before :each do
@options, @config = new_option
diff --git a/spec/mspec/spec/guards/platform_spec.rb b/spec/mspec/spec/guards/platform_spec.rb
index bd37432800..88a7ad86f2 100644
--- a/spec/mspec/spec/guards/platform_spec.rb
+++ b/spec/mspec/spec/guards/platform_spec.rb
@@ -81,44 +81,44 @@ RSpec.describe Object, "#platform_is_not" do
end
end
-RSpec.describe Object, "#platform_is :c_long_size => SIZE_SPEC" do
+RSpec.describe Object, "#platform_is :wordsize => SIZE_SPEC" do
before :each do
- @guard = PlatformGuard.new :darwin, :c_long_size => 32
+ @guard = PlatformGuard.new :darwin, :wordsize => 32
allow(PlatformGuard).to receive(:os?).and_return(true)
allow(PlatformGuard).to receive(:new).and_return(@guard)
ScratchPad.clear
end
- it "yields when #c_long_size? returns true" do
- allow(PlatformGuard).to receive(:c_long_size?).and_return(true)
- platform_is(:c_long_size => 32) { ScratchPad.record :yield }
+ it "yields when #wordsize? returns true" do
+ allow(PlatformGuard).to receive(:wordsize?).and_return(true)
+ platform_is(:wordsize => 32) { ScratchPad.record :yield }
expect(ScratchPad.recorded).to eq(:yield)
end
- it "doesn not yield when #c_long_size? returns false" do
- allow(PlatformGuard).to receive(:c_long_size?).and_return(false)
- platform_is(:c_long_size => 32) { ScratchPad.record :yield }
+ it "doesn not yield when #wordsize? returns false" do
+ allow(PlatformGuard).to receive(:wordsize?).and_return(false)
+ platform_is(:wordsize => 32) { ScratchPad.record :yield }
expect(ScratchPad.recorded).not_to eq(:yield)
end
end
-RSpec.describe Object, "#platform_is_not :c_long_size => SIZE_SPEC" do
+RSpec.describe Object, "#platform_is_not :wordsize => SIZE_SPEC" do
before :each do
- @guard = PlatformGuard.new :darwin, :c_long_size => 32
+ @guard = PlatformGuard.new :darwin, :wordsize => 32
allow(PlatformGuard).to receive(:os?).and_return(true)
allow(PlatformGuard).to receive(:new).and_return(@guard)
ScratchPad.clear
end
- it "yields when #c_long_size? returns false" do
- allow(PlatformGuard).to receive(:c_long_size?).and_return(false)
- platform_is_not(:c_long_size => 32) { ScratchPad.record :yield }
+ it "yields when #wordsize? returns false" do
+ allow(PlatformGuard).to receive(:wordsize?).and_return(false)
+ platform_is_not(:wordsize => 32) { ScratchPad.record :yield }
expect(ScratchPad.recorded).to eq(:yield)
end
- it "doesn not yield when #c_long_size? returns true" do
- allow(PlatformGuard).to receive(:c_long_size?).and_return(true)
- platform_is_not(:c_long_size => 32) { ScratchPad.record :yield }
+ it "doesn not yield when #wordsize? returns true" do
+ allow(PlatformGuard).to receive(:wordsize?).and_return(true)
+ platform_is_not(:wordsize => 32) { ScratchPad.record :yield }
expect(ScratchPad.recorded).not_to eq(:yield)
end
end
@@ -184,13 +184,13 @@ RSpec.describe PlatformGuard, ".standard?" do
end
end
-RSpec.describe PlatformGuard, ".c_long_size?" do
+RSpec.describe PlatformGuard, ".wordsize?" do
it "returns true when arg is 32 and 1.size is 4" do
- expect(PlatformGuard.c_long_size?(32)).to eq(1.size == 4)
+ expect(PlatformGuard.wordsize?(32)).to eq(1.size == 4)
end
it "returns true when arg is 64 and 1.size is 8" do
- expect(PlatformGuard.c_long_size?(64)).to eq(1.size == 8)
+ expect(PlatformGuard.wordsize?(64)).to eq(1.size == 8)
end
end
diff --git a/spec/mspec/spec/helpers/ruby_exe_spec.rb b/spec/mspec/spec/helpers/ruby_exe_spec.rb
index 56bade1ba9..61225a2756 100644
--- a/spec/mspec/spec/helpers/ruby_exe_spec.rb
+++ b/spec/mspec/spec/helpers/ruby_exe_spec.rb
@@ -145,7 +145,7 @@ RSpec.describe Object, "#ruby_exe" do
stub_const 'RUBY_EXE', 'ruby_spec_exe -w -Q'
@script = RubyExeSpecs.new
- allow(IO).to receive(:popen).and_return('OUTPUT')
+ allow(@script).to receive(:`).and_return('OUTPUT')
status_successful = double(Process::Status, exited?: true, exitstatus: 0)
allow(Process).to receive(:last_status).and_return(status_successful)
@@ -155,7 +155,7 @@ RSpec.describe Object, "#ruby_exe" do
code = "code"
options = {}
output = "output"
- expect(IO).to receive(:popen).and_return(output)
+ allow(@script).to receive(:`).and_return(output)
expect(@script.ruby_exe(code, options)).to eq output
end
@@ -168,7 +168,7 @@ RSpec.describe Object, "#ruby_exe" do
code = "code"
options = {}
expect(@script).to receive(:ruby_cmd).and_return("ruby_cmd")
- expect(IO).to receive(:popen).with("ruby_cmd")
+ expect(@script).to receive(:`).with("ruby_cmd")
@script.ruby_exe(code, options)
end
@@ -227,7 +227,7 @@ RSpec.describe Object, "#ruby_exe" do
expect(ENV).to receive(:[]=).with("ABC", "xyz")
expect(ENV).to receive(:[]=).with("ABC", "123")
- expect(IO).to receive(:popen).and_raise(Exception)
+ expect(@script).to receive(:`).and_raise(Exception)
expect do
@script.ruby_exe nil, :env => { :ABC => "xyz" }
end.to raise_error(Exception)
@@ -248,7 +248,7 @@ RSpec.describe Object, "#ruby_exe" do
it "does not raise exception when command ends with expected status" do
output = "output"
- expect(IO).to receive(:popen).and_return(output)
+ allow(@script).to receive(:`).and_return(output)
expect(@script.ruby_exe("path", exit_status: 4)).to eq output
end
diff --git a/spec/mspec/spec/integration/run_spec.rb b/spec/mspec/spec/integration/run_spec.rb
index ea0735e9b2..90dc051543 100644
--- a/spec/mspec/spec/integration/run_spec.rb
+++ b/spec/mspec/spec/integration/run_spec.rb
@@ -1,21 +1,20 @@
require 'spec_helper'
RSpec.describe "Running mspec" do
- q = BACKTRACE_QUOTE
a_spec_output = <<EOS
1)
Foo#bar errors FAILED
Expected 1 == 2
to be truthy but was false
-CWD/spec/fixtures/a_spec.rb:8:in #{q}block (2 levels) in <top (required)>'
-CWD/spec/fixtures/a_spec.rb:2:in #{q}<top (required)>'
+CWD/spec/fixtures/a_spec.rb:8:in `block (2 levels) in <top (required)>'
+CWD/spec/fixtures/a_spec.rb:2:in `<top (required)>'
2)
Foo#bar fails ERROR
RuntimeError: failure
-CWD/spec/fixtures/a_spec.rb:12:in #{q}block (2 levels) in <top (required)>'
-CWD/spec/fixtures/a_spec.rb:2:in #{q}<top (required)>'
+CWD/spec/fixtures/a_spec.rb:12:in `block (2 levels) in <top (required)>'
+CWD/spec/fixtures/a_spec.rb:2:in `<top (required)>'
Finished in D.DDDDDD seconds
EOS
diff --git a/spec/mspec/spec/integration/tag_spec.rb b/spec/mspec/spec/integration/tag_spec.rb
index ae08e9d45f..33df1cfd40 100644
--- a/spec/mspec/spec/integration/tag_spec.rb
+++ b/spec/mspec/spec/integration/tag_spec.rb
@@ -13,7 +13,6 @@ RSpec.describe "Running mspec tag" do
it "tags the failing specs" do
fixtures = "spec/fixtures"
out, ret = run_mspec("tag", "--add fails --fail #{fixtures}/tagging_spec.rb")
- q = BACKTRACE_QUOTE
expect(out).to eq <<EOS
RUBY_DESCRIPTION
.FF
@@ -27,15 +26,15 @@ Tag#me érròrs in unicode
Tag#me errors FAILED
Expected 1 == 2
to be truthy but was false
-CWD/spec/fixtures/tagging_spec.rb:9:in #{q}block (2 levels) in <top (required)>'
-CWD/spec/fixtures/tagging_spec.rb:3:in #{q}<top (required)>'
+CWD/spec/fixtures/tagging_spec.rb:9:in `block (2 levels) in <top (required)>'
+CWD/spec/fixtures/tagging_spec.rb:3:in `<top (required)>'
2)
Tag#me érròrs in unicode FAILED
Expected 1 == 2
to be truthy but was false
-CWD/spec/fixtures/tagging_spec.rb:13:in #{q}block (2 levels) in <top (required)>'
-CWD/spec/fixtures/tagging_spec.rb:3:in #{q}<top (required)>'
+CWD/spec/fixtures/tagging_spec.rb:13:in `block (2 levels) in <top (required)>'
+CWD/spec/fixtures/tagging_spec.rb:3:in `<top (required)>'
Finished in D.DDDDDD seconds
diff --git a/spec/mspec/spec/mocks/mock_spec.rb b/spec/mspec/spec/mocks/mock_spec.rb
index 7426e0ff88..73f9bdfa14 100644
--- a/spec/mspec/spec/mocks/mock_spec.rb
+++ b/spec/mspec/spec/mocks/mock_spec.rb
@@ -22,14 +22,14 @@ end
RSpec.describe Mock, ".replaced_name" do
it "returns the name for a method that is being replaced by a mock method" do
m = double('a fake id')
- expect(Mock.replaced_name(Mock.replaced_key(m, :method_call))).to eq(:"__mspec_method_call__")
+ expect(Mock.replaced_name(m, :method_call)).to eq(:"__mspec_#{m.object_id}_method_call__")
end
end
RSpec.describe Mock, ".replaced_key" do
it "returns a key used internally by Mock" do
m = double('a fake id')
- expect(Mock.replaced_key(m, :method_call)).to eq([m.object_id, :method_call])
+ expect(Mock.replaced_key(m, :method_call)).to eq([:"__mspec_#{m.object_id}_method_call__", :method_call])
end
end
@@ -42,16 +42,16 @@ RSpec.describe Mock, ".replaced?" do
it "returns true if a method has been stubbed on an object" do
Mock.install_method @mock, :method_call
- expect(Mock.replaced?(Mock.replaced_key(@mock, :method_call))).to be_truthy
+ expect(Mock.replaced?(Mock.replaced_name(@mock, :method_call))).to be_truthy
end
it "returns true if a method has been mocked on an object" do
Mock.install_method @mock, :method_call, :stub
- expect(Mock.replaced?(Mock.replaced_key(@mock, :method_call))).to be_truthy
+ expect(Mock.replaced?(Mock.replaced_name(@mock, :method_call))).to be_truthy
end
it "returns false if a method has not been stubbed or mocked" do
- expect(Mock.replaced?(Mock.replaced_key(@mock, :method_call))).to be_falsey
+ expect(Mock.replaced?(Mock.replaced_name(@mock, :method_call))).to be_falsey
end
end
@@ -197,11 +197,11 @@ RSpec.describe Mock, ".install_method" do
Mock.install_method @mock, :method_call
expect(@mock).to respond_to(:method_call)
- expect(@mock).not_to respond_to(Mock.replaced_name(Mock.replaced_key(@mock, :method_call)))
+ expect(@mock).not_to respond_to(Mock.replaced_name(@mock, :method_call))
Mock.install_method @mock, :method_call, :stub
expect(@mock).to respond_to(:method_call)
- expect(@mock).not_to respond_to(Mock.replaced_name(Mock.replaced_key(@mock, :method_call)))
+ expect(@mock).not_to respond_to(Mock.replaced_name(@mock, :method_call))
end
end
@@ -493,7 +493,7 @@ RSpec.describe Mock, ".cleanup" do
it "removes the replaced method if the mock method overrides an existing method" do
def @mock.already_here() :hey end
expect(@mock).to respond_to(:already_here)
- replaced_name = Mock.replaced_name(Mock.replaced_key(@mock, :already_here))
+ replaced_name = Mock.replaced_name(@mock, :already_here)
Mock.install_method @mock, :already_here
expect(@mock).to respond_to(replaced_name)
@@ -521,9 +521,10 @@ RSpec.describe Mock, ".cleanup" do
replaced_key = Mock.replaced_key(@mock, :method_call)
expect(Mock).to receive(:clear_replaced).with(replaced_key)
- expect(Mock.replaced?(replaced_key)).to be_truthy
+ replaced_name = Mock.replaced_name(@mock, :method_call)
+ expect(Mock.replaced?(replaced_name)).to be_truthy
Mock.cleanup
- expect(Mock.replaced?(replaced_key)).to be_falsey
+ expect(Mock.replaced?(replaced_name)).to be_falsey
end
end
diff --git a/spec/mspec/spec/runner/context_spec.rb b/spec/mspec/spec/runner/context_spec.rb
index 9ebc708c0c..a864428aec 100644
--- a/spec/mspec/spec/runner/context_spec.rb
+++ b/spec/mspec/spec/runner/context_spec.rb
@@ -914,7 +914,7 @@ RSpec.describe ContextState, "#it_should_behave_like" do
it "raises an Exception if unable to find the shared ContextState" do
expect(MSpec).to receive(:retrieve_shared).and_return(nil)
- expect { @state.it_should_behave_like :this }.to raise_error(Exception)
+ expect { @state.it_should_behave_like "this" }.to raise_error(Exception)
end
describe "for nested ContextState instances" do
diff --git a/spec/mspec/spec/spec_helper.rb b/spec/mspec/spec/spec_helper.rb
index 5cabfe5626..3a749581ee 100644
--- a/spec/mspec/spec/spec_helper.rb
+++ b/spec/mspec/spec/spec_helper.rb
@@ -66,5 +66,3 @@ PublicMSpecMatchers = Class.new {
include MSpecMatchers
public :raise_error
}.new
-
-BACKTRACE_QUOTE = RUBY_VERSION >= "3.4" ? "'" : "`"
diff --git a/spec/mspec/tool/check_require_spec_helper.rb b/spec/mspec/tool/check_require_spec_helper.rb
deleted file mode 100755
index 07126e68dc..0000000000
--- a/spec/mspec/tool/check_require_spec_helper.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/env ruby
-
-# This script is used to check that each *_spec.rb file has
-# a relative_require for spec_helper which should live higher
-# up in the ruby/spec repo directory tree.
-#
-# Prints errors to $stderr and returns a non-zero exit code when
-# errors are found.
-#
-# Related to https://github.com/ruby/spec/pull/992
-
-def check_file(fn)
- File.foreach(fn) do |line|
- return $1 if line =~ /^\s*require_relative\s*['"](.*spec_helper)['"]/
- end
- nil
-end
-
-rootdir = ARGV[0] || "."
-fglob = File.join(rootdir, "**", "*_spec.rb")
-specfiles = Dir.glob(fglob)
-raise "No spec files found in #{fglob.inspect}. Give an argument to specify the root-directory of ruby/spec" if specfiles.empty?
-
-errors = 0
-specfiles.sort.each do |fn|
- result = check_file(fn)
- if result.nil?
- warn "Missing require_relative for *spec_helper for file: #{fn}"
- errors += 1
- end
-end
-
-puts "# Found #{errors} files with require_relative spec_helper issues."
-exit 1 if errors > 0
diff --git a/spec/mspec/tool/remove_old_guards.rb b/spec/mspec/tool/remove_old_guards.rb
index 3fd95e6b31..67485446bb 100644
--- a/spec/mspec/tool/remove_old_guards.rb
+++ b/spec/mspec/tool/remove_old_guards.rb
@@ -46,51 +46,6 @@ def remove_guards(guard, keep)
end
end
-def remove_empty_files
- each_spec_file do |file|
- unless file.include?("fixtures/")
- lines = File.readlines(file)
- if lines.all? { |line| line.chomp.empty? or line.start_with?('require', '#') }
- puts "Removing empty file #{file}"
- File.delete(file)
- end
- end
- end
-end
-
-def remove_unused_shared_specs
- shared_groups = {}
- # Dir["**/shared/**/*.rb"].each do |shared|
- each_spec_file do |shared|
- next if File.basename(shared) == 'constants.rb'
- contents = File.binread(shared)
- found = false
- contents.scan(/^\s*describe (:[\w_?]+), shared: true do$/) {
- shared_groups[$1] = 0
- found = true
- }
- if !found and shared.include?('shared/') and !shared.include?('fixtures/') and !shared.end_with?('/constants.rb')
- puts "no shared describe in #{shared} ?"
- end
- end
-
- each_spec_file do |file|
- contents = File.binread(file)
- contents.scan(/(?:it_behaves_like|it_should_behave_like) (:[\w_?]+)[,\s]/) do
- puts $1 unless shared_groups.key?($1)
- shared_groups[$1] += 1
- end
- end
-
- shared_groups.each_pair do |group, value|
- if value == 0
- puts "Shared describe #{group} seems unused"
- elsif value == 1
- puts "Shared describe #{group} seems used only once" if $VERBOSE
- end
- end
-end
-
def search(regexp)
each_spec_file do |file|
contents = File.binread(file)
@@ -109,11 +64,7 @@ version = Regexp.escape(ARGV.fetch(0))
version += "(?:\\.0)?" if version.count(".") < 2
remove_guards(/ruby_version_is (["'])#{version}\1 do/, true)
remove_guards(/ruby_version_is (["'])[0-9.]*\1 *... *(["'])#{version}\2 do/, false)
-remove_guards(/ruby_bug ["']#\d+["'], (["'])[0-9.]*\1 *... *(["'])#{version}\2 do/, true)
-
-remove_empty_files
-remove_unused_shared_specs
+remove_guards(/ruby_bug "#\d+", (["'])[0-9.]*\1 *... *(["'])#{version}\2 do/, true)
-puts "Search:"
search(/(["'])#{version}\1/)
search(/^\s*#.+#{version}/)
diff --git a/spec/mspec/tool/tag_from_output.rb b/spec/mspec/tool/tag_from_output.rb
index b6b4603855..a6e60945cd 100755
--- a/spec/mspec/tool/tag_from_output.rb
+++ b/spec/mspec/tool/tag_from_output.rb
@@ -3,8 +3,6 @@
# Adds tags based on error and failures output (e.g., from a CI log),
# without running any spec code.
-tag = ENV["TAG"] || "fails"
-
tags_dir = %w[
spec/tags
spec/tags/ruby
@@ -32,9 +30,9 @@ output.slice_before(NUMBER).select { |number, *rest|
if spec_file
spec_file = spec_file[SPEC_FILE, 1] or raise
else
- if error_line =~ /^([\w:]+)[#\.](\w+) /
- mod, method = $1, $2
- file = "#{mod.downcase.gsub('::', '/')}/#{method}_spec.rb"
+ if error_line =~ /^(\w+)[#\.](\w+) /
+ module_method = error_line.split(' ', 2).first
+ file = "#{$1.downcase}/#{$2}_spec.rb"
spec_file = ['spec/ruby/core', 'spec/ruby/library', *Dir.glob('spec/ruby/library/*')].find { |dir|
path = "#{dir}/#{file}"
break path if File.exist?(path)
@@ -56,7 +54,7 @@ output.slice_before(NUMBER).select { |number, *rest|
dir = File.dirname(tags_file)
Dir.mkdir(dir) unless Dir.exist?(dir)
- tag_line = "#{tag}:#{description}"
+ tag_line = "fails:#{description}"
lines = File.exist?(tags_file) ? File.readlines(tags_file, chomp: true) : []
unless lines.include?(tag_line)
puts tags_file
diff --git a/spec/ruby/.mspec.constants b/spec/ruby/.mspec.constants
index 4da3633715..5dd477eb66 100644
--- a/spec/ruby/.mspec.constants
+++ b/spec/ruby/.mspec.constants
@@ -146,7 +146,6 @@ Prime
Private
ProcFromMethod
Psych
-RactorLocalSingleton
REXML
RUBY_SIGNALS
RbReadline
@@ -205,7 +204,6 @@ UserArray
UserCustomConstructorString
UserDefined
UserDefinedImmediate
-UserDefinedString
UserDefinedWithIvar
UserHash
UserHashInitParams
diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml
index 5a902e0f01..82733c4b4d 100644
--- a/spec/ruby/.rubocop.yml
+++ b/spec/ruby/.rubocop.yml
@@ -1,7 +1,7 @@
inherit_from: .rubocop_todo.yml
AllCops:
- TargetRubyVersion: 3.1
+ TargetRubyVersion: 2.7
DisplayCopNames: true
Exclude:
- command_line/fixtures/bad_syntax.rb
@@ -33,16 +33,15 @@ Lint/AssignmentInCondition:
Lint/BooleanSymbol:
Enabled: false
-Lint/DeprecatedOpenSSLConstant:
- Exclude:
- - library/openssl/digest/**/*.rb
-
Lint/InterpolationCheck:
Enabled: false
Lint/LiteralAsCondition:
Enabled: false
+Lint/RedundantRequireStatement:
+ Enabled: false
+
Lint/RedundantSplatExpansion:
Enabled: false
@@ -103,9 +102,6 @@ Lint/OutOfRangeRegexpRef:
Lint/InheritException:
Enabled: false
-Lint/SafeNavigationChain:
- Enabled: false
-
Lint/ElseLayout:
Exclude:
- 'language/if_spec.rb'
diff --git a/spec/ruby/.rubocop_todo.yml b/spec/ruby/.rubocop_todo.yml
index 3ebb23a8bb..ac9cfae2bf 100644
--- a/spec/ruby/.rubocop_todo.yml
+++ b/spec/ruby/.rubocop_todo.yml
@@ -63,6 +63,7 @@ Lint/LiteralInInterpolation:
- 'language/string_spec.rb'
- 'language/symbol_spec.rb'
- 'language/undef_spec.rb'
+ - 'library/net/ftp/connect_spec.rb'
# Offense count: 8
# Cop supports --auto-correct.
@@ -97,7 +98,6 @@ Lint/RescueException:
- 'core/dir/fileno_spec.rb'
- 'core/exception/cause_spec.rb'
- 'core/exception/no_method_error_spec.rb'
- - 'core/fiber/kill_spec.rb'
- 'core/kernel/fixtures/autoload_frozen.rb'
- 'core/kernel/raise_spec.rb'
- 'core/module/autoload_spec.rb'
diff --git a/spec/ruby/CONTRIBUTING.md b/spec/ruby/CONTRIBUTING.md
index e9314208d1..adfc2fb0ca 100644
--- a/spec/ruby/CONTRIBUTING.md
+++ b/spec/ruby/CONTRIBUTING.md
@@ -138,12 +138,12 @@ Here is a list of the most commonly-used guards:
#### Version guards
```ruby
-ruby_version_is ""..."3.2" do
- # Specs for RUBY_VERSION < 3.2
+ruby_version_is ""..."2.6" do
+ # Specs for RUBY_VERSION < 2.6
end
-ruby_version_is "3.2" do
- # Specs for RUBY_VERSION >= 3.2
+ruby_version_is "2.6" do
+ # Specs for RUBY_VERSION >= 2.6
end
```
@@ -164,7 +164,7 @@ end
platform_is_not :linux, :darwin do # Not Linux and not Darwin
end
-platform_is pointer_size: 64 do
+platform_is wordsize: 64 do
# 64-bit platform
end
@@ -179,7 +179,6 @@ In case there is a bug in MRI and the fix will be backported to previous version
If it is not backported or not likely, use `ruby_version_is` instead.
First, file a bug at https://bugs.ruby-lang.org/.
The problem is `ruby_bug` would make non-MRI implementations fail this spec while MRI itself does not pass it, so it should only be used if the bug is/will be fixed and backported.
-Otherwise, non-MRI implementations would have to choose between being incompatible with the latest release of MRI to pass the spec or fail the spec, both which make no sense.
```ruby
ruby_bug '#13669', ''...'3.2' do
@@ -192,11 +191,11 @@ end
#### Combining guards
```ruby
-guard -> { platform_is :windows and ruby_version_is ""..."3.2" } do
- # Windows and RUBY_VERSION < 3.2
+guard -> { platform_is :windows and ruby_version_is ""..."2.6" } do
+ # Windows and RUBY_VERSION < 2.6
end
-guard_not -> { platform_is :windows and ruby_version_is ""..."3.2" } do
+guard_not -> { platform_is :windows and ruby_version_is ""..."2.6" } do
# The opposite
end
```
@@ -277,13 +276,13 @@ describe :kernel_sprintf, shared: true do
end
describe "Kernel#sprintf" do
- it_behaves_like :kernel_sprintf, -> format, *args {
+ it_behaves_like :kernel_sprintf, -> (format, *args) {
sprintf(format, *args)
}
end
describe "Kernel.sprintf" do
- it_behaves_like :kernel_sprintf, -> format, *args {
+ it_behaves_like :kernel_sprintf, -> (format, *args) {
Kernel.sprintf(format, *args)
}
end
diff --git a/spec/ruby/README.md b/spec/ruby/README.md
index 964efbec48..018bf0ca3e 100644
--- a/spec/ruby/README.md
+++ b/spec/ruby/README.md
@@ -30,12 +30,12 @@ ruby/spec is known to be tested in these implementations for every commit:
* [Opal](https://github.com/opal/opal/tree/master/spec)
* [Artichoke](https://github.com/artichoke/spec/tree/artichoke-vendor)
-ruby/spec describes the behavior of Ruby 3.0 and more recent Ruby versions.
-More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (3.0.x, 3.1.x, 3.2.x, etc), and those are tested in CI.
+ruby/spec describes the behavior of Ruby 2.7 and more recent Ruby versions.
+More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (2.7.x, 3.0.x, 3.1.x, etc), and those are tested in CI.
### Synchronization with Ruby Implementations
-The specs are synchronized both ways around once a month by @andrykonchin between ruby/spec, MRI, JRuby and TruffleRuby,
+The specs are synchronized both ways around once a month by @eregon between ruby/spec, MRI, JRuby and TruffleRuby,
using [this script](https://github.com/ruby/mspec/blob/master/tool/sync/sync-rubyspec.rb).
Each of these repositories has a full copy of the specs under `spec/ruby` to ease editing specs.
Any of these repositories can be used to add or edit specs, use what is most convenient for you.
@@ -61,7 +61,6 @@ For older specs try these commits:
* Ruby 2.4.10 - [Suite](https://github.com/ruby/spec/commit/bce4f2b81d6c31db67cf4d023a0625ceadde59bd) using [MSpec](https://github.com/ruby/mspec/commit/e7eb8aa4c26495b7b461e687d950b96eb08b3ff2)
* Ruby 2.5.9 - [Suite](https://github.com/ruby/spec/commit/c503335d3d9f6ec6ef24de60a0716c34af69b64f) using [MSpec](https://github.com/ruby/mspec/commit/0091e8a62e954717cd54641f935eaf1403692041)
* Ruby 2.6.10 - [Suite](https://github.com/ruby/spec/commit/aaf998fb8c92c4e63ad423a2e7ca6e6921818c6e) using [MSpec](https://github.com/ruby/mspec/commit/5e36c684e9e2b92b1187589bba1df22c640a8661)
-* Ruby 2.7.8 - [Suite](https://github.com/ruby/spec/commit/93787e6035c925b593a9c0c6fb0e7e07a6f1df1f) using [MSpec](https://github.com/ruby/mspec/commit/1d8cf64722d8a7529f7cd205be5f16a89b7a67fd)
### Running the specs
@@ -128,12 +127,6 @@ MSpec can automatically add new top-level constants in this file with:
$ CHECK_LEAKS=save mspec ../mspec/bin/mspec file
-### Running Specs on S390x CPU Architecture
-
-Run the specs with `DFLTCC=0` if you see failing specs related to the zlib library on s390x CPU architecture. The failures can happen with the zlib library applying the patch madler/zlib#410 to enable the deflate algorithm producing a different compressed byte stream.
-
- $ DFLTCC=0 ../mspec/bin/mspec
-
### Contributing and Writing Specs
See [CONTRIBUTING.md](https://github.com/ruby/spec/blob/master/CONTRIBUTING.md) for documentation about contributing and writing specs (guards, matchers, etc).
diff --git a/spec/ruby/command_line/backtrace_limit_spec.rb b/spec/ruby/command_line/backtrace_limit_spec.rb
index 4d57bc268b..56afa8efef 100644
--- a/spec/ruby/command_line/backtrace_limit_spec.rb
+++ b/spec/ruby/command_line/backtrace_limit_spec.rb
@@ -1,7 +1,7 @@
require_relative '../spec_helper'
-describe "The --backtrace-limit command line option" do
- ruby_version_is ""..."3.4" do
+ruby_version_is "3.0" do
+ describe "The --backtrace-limit command line option" do
it "limits top-level backtraces to a given number of entries" do
file = fixture(__FILE__ , "backtrace.rb")
out = ruby_exe(file, options: "--backtrace-limit=2", args: "top 2>&1", exit_status: 1)
@@ -45,49 +45,4 @@ backtrace
MSG
end
end
-
- ruby_version_is "3.4" do
- it "limits top-level backtraces to a given number of entries" do
- file = fixture(__FILE__ , "backtrace.rb")
- out = ruby_exe(file, options: "--backtrace-limit=2", args: "top 2>&1", exit_status: 1)
- out = out.gsub(__dir__, '')
-
- out.should == <<-MSG
-top
-/fixtures/backtrace.rb:2:in 'Object#a': oops (RuntimeError)
-\tfrom /fixtures/backtrace.rb:6:in 'Object#b'
-\tfrom /fixtures/backtrace.rb:10:in 'Object#c'
-\t ... 2 levels...
- MSG
- end
-
- it "affects Exception#full_message" do
- file = fixture(__FILE__ , "backtrace.rb")
- out = ruby_exe(file, options: "--backtrace-limit=2", args: "full_message 2>&1")
- out = out.gsub(__dir__, '')
-
- out.should == <<-MSG
-full_message
-/fixtures/backtrace.rb:2:in 'Object#a': oops (RuntimeError)
-\tfrom /fixtures/backtrace.rb:6:in 'Object#b'
-\tfrom /fixtures/backtrace.rb:10:in 'Object#c'
-\t ... 2 levels...
- MSG
- end
-
- it "does not affect Exception#backtrace" do
- file = fixture(__FILE__ , "backtrace.rb")
- out = ruby_exe(file, options: "--backtrace-limit=2", args: "backtrace 2>&1")
- out = out.gsub(__dir__, '')
-
- out.should == <<-MSG
-backtrace
-/fixtures/backtrace.rb:2:in 'Object#a'
-/fixtures/backtrace.rb:6:in 'Object#b'
-/fixtures/backtrace.rb:10:in 'Object#c'
-/fixtures/backtrace.rb:14:in 'Object#d'
-/fixtures/backtrace.rb:29:in '<main>'
- MSG
- end
- end
end
diff --git a/spec/ruby/command_line/dash_a_spec.rb b/spec/ruby/command_line/dash_a_spec.rb
index 43d923ce16..9ea135dc76 100644
--- a/spec/ruby/command_line/dash_a_spec.rb
+++ b/spec/ruby/command_line/dash_a_spec.rb
@@ -6,13 +6,13 @@ describe "The -a command line option" do
end
it "runs the code in loop conditional on Kernel.gets()" do
- ruby_exe("puts $F.last", options: "-n -a",
+ ruby_exe("puts $F.last", options: "-n -a", escape: true,
args: " < #{@names}").should ==
"jones\nfield\ngrey\n"
end
it "sets $-a" do
- ruby_exe("puts $-a", options: "-n -a",
+ ruby_exe("puts $-a", options: "-n -a", escape: true,
args: " < #{@names}").should ==
"true\ntrue\ntrue\n"
end
diff --git a/spec/ruby/command_line/dash_l_spec.rb b/spec/ruby/command_line/dash_l_spec.rb
index 44a98445f3..5c1d3cf4cd 100644
--- a/spec/ruby/command_line/dash_l_spec.rb
+++ b/spec/ruby/command_line/dash_l_spec.rb
@@ -6,25 +6,25 @@ describe "The -l command line option" do
end
it "chomps lines with default separator" do
- ruby_exe('puts $_.end_with?("\n")', options: "-n -l",
+ ruby_exe('puts $_.end_with?("\n")', options: "-n -l", escape: true,
args: " < #{@names}").should ==
"false\nfalse\nfalse\n"
end
it "chomps last line based on $/" do
- ruby_exe('BEGIN { $/ = "ones\n" }; puts $_', options: "-W0 -n -l",
+ ruby_exe('BEGIN { $/ = "ones\n" }; puts $_', options: "-W0 -n -l", escape: true,
args: " < #{@names}").should ==
"alice j\nbob field\njames grey\n"
end
it "sets $\\ to the value of $/" do
- ruby_exe("puts $\\ == $/", options: "-W0 -n -l",
+ ruby_exe("puts $\\ == $/", options: "-W0 -n -l", escape: true,
args: " < #{@names}").should ==
"true\ntrue\ntrue\n"
end
it "sets $-l" do
- ruby_exe("puts $-l", options: "-n -l",
+ ruby_exe("puts $-l", options: "-n -l", escape: true,
args: " < #{@names}").should ==
"true\ntrue\ntrue\n"
end
diff --git a/spec/ruby/command_line/dash_n_spec.rb b/spec/ruby/command_line/dash_n_spec.rb
index 1dd9379259..9d331d6065 100644
--- a/spec/ruby/command_line/dash_n_spec.rb
+++ b/spec/ruby/command_line/dash_n_spec.rb
@@ -6,19 +6,19 @@ describe "The -n command line option" do
end
it "runs the code in loop conditional on Kernel.gets()" do
- ruby_exe("puts $_", options: "-n",
+ ruby_exe("puts $_", options: "-n", escape: true,
args: " < #{@names}").should ==
"alice\nbob\njames\n"
end
it "only evaluates BEGIN blocks once" do
- ruby_exe("BEGIN { puts \"hi\" }; puts $_", options: "-n",
+ ruby_exe("BEGIN { puts \"hi\" }; puts $_", options: "-n", escape: true,
args: " < #{@names}").should ==
"hi\nalice\nbob\njames\n"
end
it "only evaluates END blocks once" do
- ruby_exe("puts $_; END {puts \"bye\"}", options: "-n",
+ ruby_exe("puts $_; END {puts \"bye\"}", options: "-n", escape: true,
args: " < #{@names}").should ==
"alice\nbob\njames\nbye\n"
end
@@ -29,7 +29,7 @@ describe "The -n command line option" do
$total += 1
END { puts $total }
script
- ruby_exe(script, options: "-n",
+ ruby_exe(script, options: "-n", escape: true,
args: " < #{@names}").should ==
"3\n"
end
diff --git a/spec/ruby/command_line/dash_p_spec.rb b/spec/ruby/command_line/dash_p_spec.rb
index 967e3796de..39827c3868 100644
--- a/spec/ruby/command_line/dash_p_spec.rb
+++ b/spec/ruby/command_line/dash_p_spec.rb
@@ -6,13 +6,13 @@ describe "The -p command line option" do
end
it "runs the code in loop conditional on Kernel.gets() and prints $_" do
- ruby_exe("$_ = $_.upcase", options: "-p",
+ ruby_exe("$_ = $_.upcase", options: "-p", escape: true,
args: " < #{@names}").should ==
"ALICE\nBOB\nJAMES\n"
end
it "sets $-p" do
- ruby_exe("$_ = $-p", options: "-p",
+ ruby_exe("$_ = $-p", options: "-p", escape: true,
args: " < #{@names}").should ==
"truetruetrue"
end
diff --git a/spec/ruby/command_line/dash_r_spec.rb b/spec/ruby/command_line/dash_r_spec.rb
index 9f673c53dc..ea5bde5adf 100644
--- a/spec/ruby/command_line/dash_r_spec.rb
+++ b/spec/ruby/command_line/dash_r_spec.rb
@@ -16,10 +16,7 @@ describe "The -r command line option" do
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), options: "-r #{@test_file}", args: "2>&1", exit_status: 1)
$?.should_not.success?
out.should include("REQUIRED")
-
- # it's tempting not to rely on error message and rely only on exception class name,
- # but CRuby before 3.2 doesn't print class name for syntax error
- out.should include_any_of("syntax error", "SyntaxError")
+ out.should include("syntax error")
end
it "does not require the file if the main script file does not exist" do
diff --git a/spec/ruby/command_line/dash_upper_f_spec.rb b/spec/ruby/command_line/dash_upper_f_spec.rb
index 5c10a7140d..967acc2ece 100644
--- a/spec/ruby/command_line/dash_upper_f_spec.rb
+++ b/spec/ruby/command_line/dash_upper_f_spec.rb
@@ -6,7 +6,7 @@ describe "the -F command line option" do
end
it "specifies the field separator pattern for -a" do
- ruby_exe("puts $F[0]", options: "-naF:",
+ ruby_exe("puts $F[0]", options: "-naF:", escape: true,
args: " < #{@passwd}").should ==
"nobody\nroot\ndaemon\n"
end
diff --git a/spec/ruby/command_line/dash_upper_u_spec.rb b/spec/ruby/command_line/dash_upper_u_spec.rb
index 15854e7b73..d62718b095 100644
--- a/spec/ruby/command_line/dash_upper_u_spec.rb
+++ b/spec/ruby/command_line/dash_upper_u_spec.rb
@@ -6,13 +6,6 @@ describe "ruby -U" do
options: '-U').should == 'UTF-8'
end
- it "sets Encoding.default_internal to UTF-8 when RUBYOPT is empty or only spaces" do
- ruby_exe('p Encoding.default_internal',
- options: '-U', env: { 'RUBYOPT' => '' }).should == "#<Encoding:UTF-8>\n"
- ruby_exe('p Encoding.default_internal',
- options: '-U', env: { 'RUBYOPT' => ' ' }).should == "#<Encoding:UTF-8>\n"
- end
-
it "does nothing different if specified multiple times" do
ruby_exe('print Encoding.default_internal.name',
options: '-U -U').should == 'UTF-8'
diff --git a/spec/ruby/command_line/dash_v_spec.rb b/spec/ruby/command_line/dash_v_spec.rb
index 747db7f755..a4f4dcd051 100644
--- a/spec/ruby/command_line/dash_v_spec.rb
+++ b/spec/ruby/command_line/dash_v_spec.rb
@@ -6,9 +6,8 @@ describe "The -v command line option" do
describe "when used alone" do
it "prints version and ends" do
- ruby_exe(nil, args: '-v').sub("+PRISM ", "").should include(RUBY_DESCRIPTION.sub("+PRISM ", ""))
+ ruby_exe(nil, args: '-v').should include(RUBY_DESCRIPTION)
end unless (defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?) ||
- (defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled?) ||
- (ENV['RUBY_MN_THREADS'] == '1')
+ (defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled?)
end
end
diff --git a/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt b/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt
index 1da779b1b9..c556bf0b71 100644
--- a/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt
+++ b/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt
@@ -1,3 +1,3 @@
@@@This line is not value Ruby
#!ruby
-puts 'success'
+puts 'success' \ No newline at end of file
diff --git a/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb b/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb
index df4b952c46..fa348d59e7 100644
--- a/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb
+++ b/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb
Binary files differ
diff --git a/spec/ruby/command_line/fixtures/string_literal_frozen_comment.rb b/spec/ruby/command_line/fixtures/string_literal_frozen_comment.rb
deleted file mode 100644
index fb84b546c0..0000000000
--- a/spec/ruby/command_line/fixtures/string_literal_frozen_comment.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-# frozen_string_literal: true
-frozen = "test".frozen?
-interned = "test".equal?("test")
-puts "frozen:#{frozen} interned:#{interned}"
diff --git a/spec/ruby/command_line/fixtures/string_literal_mutable_comment.rb b/spec/ruby/command_line/fixtures/string_literal_mutable_comment.rb
deleted file mode 100644
index 381a742001..0000000000
--- a/spec/ruby/command_line/fixtures/string_literal_mutable_comment.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-# frozen_string_literal: false
-frozen = "test".frozen?
-interned = "test".equal?("test")
-puts "frozen:#{frozen} interned:#{interned}"
diff --git a/spec/ruby/command_line/fixtures/string_literal_raw.rb b/spec/ruby/command_line/fixtures/string_literal_raw.rb
deleted file mode 100644
index 56b1841296..0000000000
--- a/spec/ruby/command_line/fixtures/string_literal_raw.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-frozen = "test".frozen?
-interned = "test".equal?("test")
-puts "frozen:#{frozen} interned:#{interned}"
diff --git a/spec/ruby/command_line/frozen_strings_spec.rb b/spec/ruby/command_line/frozen_strings_spec.rb
index 06889755d2..647b69daed 100644
--- a/spec/ruby/command_line/frozen_strings_spec.rb
+++ b/spec/ruby/command_line/frozen_strings_spec.rb
@@ -19,42 +19,6 @@ describe "The --enable-frozen-string-literal flag causes string literals to" do
end
end
-describe "The --disable-frozen-string-literal flag causes string literals to" do
-
- it "produce a different object each time" do
- ruby_exe(fixture(__FILE__, "freeze_flag_one_literal.rb"), options: "--disable-frozen-string-literal").chomp.should == "false"
- end
-
-end
-
-describe "With neither --enable-frozen-string-literal nor --disable-frozen-string-literal flag set" do
- before do
- # disable --enable-frozen-string-literal and --disable-frozen-string-literal passed in $RUBYOPT
- @rubyopt = ENV["RUBYOPT"]
- ENV["RUBYOPT"] = ""
- end
-
- after do
- ENV["RUBYOPT"] = @rubyopt
- end
-
- it "produce a different object each time" do
- ruby_exe(fixture(__FILE__, "freeze_flag_one_literal.rb")).chomp.should == "false"
- end
-
- it "if file has no frozen_string_literal comment produce different mutable strings each time" do
- ruby_exe(fixture(__FILE__, "string_literal_raw.rb")).chomp.should == "frozen:false interned:false"
- end
-
- it "if file has frozen_string_literal:true comment produce same frozen strings each time" do
- ruby_exe(fixture(__FILE__, "string_literal_frozen_comment.rb")).chomp.should == "frozen:true interned:true"
- end
-
- it "if file has frozen_string_literal:false comment produce different mutable strings each time" do
- ruby_exe(fixture(__FILE__, "string_literal_mutable_comment.rb")).chomp.should == "frozen:false interned:false"
- end
-end
-
describe "The --debug flag produces" do
it "debugging info on attempted frozen string modification" do
error_str = ruby_exe(fixture(__FILE__, 'debug_info.rb'), options: '--debug', args: "2>&1")
diff --git a/spec/ruby/command_line/rubyopt_spec.rb b/spec/ruby/command_line/rubyopt_spec.rb
index 18a5959b18..bbea4d557d 100644
--- a/spec/ruby/command_line/rubyopt_spec.rb
+++ b/spec/ruby/command_line/rubyopt_spec.rb
@@ -11,52 +11,52 @@ describe "Processing RUBYOPT" do
it "adds the -I path to $LOAD_PATH" do
ENV["RUBYOPT"] = "-Ioptrubyspecincl"
- result = ruby_exe("puts $LOAD_PATH.grep(/byspecin/)")
+ result = ruby_exe("puts $LOAD_PATH.grep(/byspecin/)", escape: true)
result.chomp[-15..-1].should == "optrubyspecincl"
end
it "sets $DEBUG to true for '-d'" do
ENV["RUBYOPT"] = '-d'
command = %[puts "value of $DEBUG is \#{$DEBUG}"]
- result = ruby_exe(command, args: "2>&1")
+ result = ruby_exe(command, escape: true, args: "2>&1")
result.should =~ /value of \$DEBUG is true/
end
guard -> { not CROSS_COMPILING } do
it "prints the version number for '-v'" do
ENV["RUBYOPT"] = '-v'
- ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION.sub("+PRISM ", "")
+ ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION
end
it "ignores whitespace around the option" do
ENV["RUBYOPT"] = ' -v '
- ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION.sub("+PRISM ", "")
+ ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION
end
end
it "sets $VERBOSE to true for '-w'" do
ENV["RUBYOPT"] = '-w'
- ruby_exe("p $VERBOSE").chomp.should == "true"
+ ruby_exe("p $VERBOSE", escape: true).chomp.should == "true"
end
it "sets $VERBOSE to true for '-W'" do
ENV["RUBYOPT"] = '-W'
- ruby_exe("p $VERBOSE").chomp.should == "true"
+ ruby_exe("p $VERBOSE", escape: true).chomp.should == "true"
end
it "sets $VERBOSE to nil for '-W0'" do
ENV["RUBYOPT"] = '-W0'
- ruby_exe("p $VERBOSE").chomp.should == "nil"
+ ruby_exe("p $VERBOSE", escape: true).chomp.should == "nil"
end
it "sets $VERBOSE to false for '-W1'" do
ENV["RUBYOPT"] = '-W1'
- ruby_exe("p $VERBOSE").chomp.should == "false"
+ ruby_exe("p $VERBOSE", escape: true).chomp.should == "false"
end
it "sets $VERBOSE to true for '-W2'" do
ENV["RUBYOPT"] = '-W2'
- ruby_exe("p $VERBOSE").chomp.should == "true"
+ ruby_exe("p $VERBOSE", escape: true).chomp.should == "true"
end
it "suppresses deprecation warnings for '-W:no-deprecated'" do
diff --git a/spec/ruby/command_line/syntax_error_spec.rb b/spec/ruby/command_line/syntax_error_spec.rb
index 9ba87b9e22..444ea9635c 100644
--- a/spec/ruby/command_line/syntax_error_spec.rb
+++ b/spec/ruby/command_line/syntax_error_spec.rb
@@ -3,17 +3,11 @@ require_relative '../spec_helper'
describe "The interpreter" do
it "prints an error when given a file with invalid syntax" do
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), args: "2>&1", exit_status: 1)
-
- # it's tempting not to rely on error message and rely only on exception class name,
- # but CRuby before 3.2 doesn't print class name for syntax error
- out.should include_any_of("syntax error", "SyntaxError")
+ out.should include "syntax error"
end
it "prints an error when given code via -e with invalid syntax" do
out = ruby_exe(nil, args: "-e 'a{' 2>&1", exit_status: 1)
-
- # it's tempting not to rely on error message and rely only on exception class name,
- # but CRuby before 3.2 doesn't print class name for syntax error
- out.should include_any_of("syntax error", "SyntaxError")
+ out.should include "syntax error"
end
end
diff --git a/spec/ruby/core/argf/bytes_spec.rb b/spec/ruby/core/argf/bytes_spec.rb
new file mode 100644
index 0000000000..bf35ded1db
--- /dev/null
+++ b/spec/ruby/core/argf/bytes_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+require_relative 'shared/each_byte'
+
+ruby_version_is ''...'3.0' do
+ describe "ARGF.bytes" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :argf_each_byte, :bytes
+ end
+end
diff --git a/spec/ruby/core/argf/chars_spec.rb b/spec/ruby/core/argf/chars_spec.rb
new file mode 100644
index 0000000000..6af73cdabb
--- /dev/null
+++ b/spec/ruby/core/argf/chars_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+require_relative 'shared/each_char'
+
+ruby_version_is ''...'3.0' do
+ describe "ARGF.chars" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :argf_each_char, :chars
+ end
+end
diff --git a/spec/ruby/core/argf/codepoints_spec.rb b/spec/ruby/core/argf/codepoints_spec.rb
new file mode 100644
index 0000000000..bb28c17fbb
--- /dev/null
+++ b/spec/ruby/core/argf/codepoints_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+require_relative 'shared/each_codepoint'
+
+ruby_version_is ''...'3.0' do
+ describe "ARGF.codepoints" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :argf_each_codepoint, :codepoints
+ end
+end
diff --git a/spec/ruby/core/argf/lines_spec.rb b/spec/ruby/core/argf/lines_spec.rb
new file mode 100644
index 0000000000..e964dbd0d3
--- /dev/null
+++ b/spec/ruby/core/argf/lines_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+require_relative 'shared/each_line'
+
+ruby_version_is ''...'3.0' do
+ describe "ARGF.lines" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :argf_each_line, :lines
+ end
+end
diff --git a/spec/ruby/core/argf/readpartial_spec.rb b/spec/ruby/core/argf/readpartial_spec.rb
index ea4301f25c..5e284b3423 100644
--- a/spec/ruby/core/argf/readpartial_spec.rb
+++ b/spec/ruby/core/argf/readpartial_spec.rb
@@ -29,7 +29,7 @@ describe "ARGF.readpartial" do
it "clears output buffer even if EOFError is raised because @argf is at end" do
begin
- output = +"to be cleared"
+ output = "to be cleared"
argf [@file1_name] do
@argf.read
@@ -69,7 +69,7 @@ describe "ARGF.readpartial" do
print ARGF.readpartial(#{@stdin.size})
ARGF.readpartial(1) rescue print $!.class
STR
- stdin = ruby_exe(ruby_str, args: "< #{@stdin_name}")
+ stdin = ruby_exe(ruby_str, args: "< #{@stdin_name}", escape: true)
stdin.should == @stdin + "EOFError"
end
end
diff --git a/spec/ruby/core/argf/shared/getc.rb b/spec/ruby/core/argf/shared/getc.rb
index d63372d9d7..8be39c60b6 100644
--- a/spec/ruby/core/argf/shared/getc.rb
+++ b/spec/ruby/core/argf/shared/getc.rb
@@ -9,7 +9,7 @@ describe :argf_getc, shared: true do
it "reads each char of files" do
argf [@file1, @file2] do
- chars = +""
+ chars = ""
@chars.size.times { chars << @argf.send(@method) }
chars.should == @chars
end
diff --git a/spec/ruby/core/argf/shared/read.rb b/spec/ruby/core/argf/shared/read.rb
index e76d022139..fe903983c0 100644
--- a/spec/ruby/core/argf/shared/read.rb
+++ b/spec/ruby/core/argf/shared/read.rb
@@ -15,7 +15,7 @@ describe :argf_read, shared: true do
it "treats second argument as an output buffer" do
argf [@file1_name] do
- buffer = +""
+ buffer = ""
@argf.send(@method, @file1.size, buffer)
buffer.should == @file1
end
@@ -23,7 +23,7 @@ describe :argf_read, shared: true do
it "clears output buffer before appending to it" do
argf [@file1_name] do
- buffer = +"to be cleared"
+ buffer = "to be cleared"
@argf.send(@method, @file1.size, buffer)
buffer.should == @file1
end
diff --git a/spec/ruby/core/array/all_spec.rb b/spec/ruby/core/array/all_spec.rb
deleted file mode 100644
index 680e8c26fa..0000000000
--- a/spec/ruby/core/array/all_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
-
-describe "Array#all?" do
- @value_to_return = -> _ { true }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :all?
-
- it "ignores the block if there is an argument" do
- -> {
- ['bar', 'foobar'].all?(/bar/) { false }.should == true
- }.should complain(/given block not used/)
- end
-end
diff --git a/spec/ruby/core/array/any_spec.rb b/spec/ruby/core/array/any_spec.rb
index b51ce62f0f..09d949fe6e 100644
--- a/spec/ruby/core/array/any_spec.rb
+++ b/spec/ruby/core/array/any_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#any?" do
describe 'with no block given (a default block of { |x| x } is implicit)' do
@@ -20,9 +19,6 @@ describe "Array#any?" do
end
describe 'with a block given' do
- @value_to_return = -> _ { false }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :any?
-
it 'is false if the array is empty' do
empty_array = []
empty_array.any? {|v| 1 == 1 }.should == false
@@ -38,12 +34,4 @@ describe "Array#any?" do
array_with_members.any? {|v| v == 42 }.should == false
end
end
-
- describe 'when given a pattern argument' do
- it "ignores the block if there is an argument" do
- -> {
- ['bar', 'foobar'].any?(/bar/) { false }.should == true
- }.should complain(/given block not used/)
- end
- end
end
diff --git a/spec/ruby/core/array/assoc_spec.rb b/spec/ruby/core/array/assoc_spec.rb
index f0be3de795..f8479d763c 100644
--- a/spec/ruby/core/array/assoc_spec.rb
+++ b/spec/ruby/core/array/assoc_spec.rb
@@ -6,7 +6,7 @@ describe "Array#assoc" do
s1 = ["colors", "red", "blue", "green"]
s2 = [:letters, "a", "b", "c"]
s3 = [4]
- s4 = ["colors", "cyan", "yellow", "magenta"]
+ s4 = ["colors", "cyan", "yellow", "magenda"]
s5 = [:letters, "a", "i", "u"]
s_nil = [nil, nil]
a = [s1, s2, s3, s4, s5, s_nil]
@@ -37,16 +37,4 @@ describe "Array#assoc" do
a.assoc(s1.first).should equal(s1)
a.assoc(s2.first).should equal(s2)
end
-
- it "calls to_ary on non-array elements" do
- s1 = [1, 2]
- s2 = ArraySpecs::ArrayConvertible.new(2, 3)
- a = [s1, s2]
-
- s1.should_not_receive(:to_ary)
- a.assoc(s1.first).should equal(s1)
-
- a.assoc(2).should == [2, 3]
- s2.called.should equal(:to_ary)
- end
end
diff --git a/spec/ruby/core/array/bsearch_index_spec.rb b/spec/ruby/core/array/bsearch_index_spec.rb
index 94d85b37f3..df2c7c098e 100644
--- a/spec/ruby/core/array/bsearch_index_spec.rb
+++ b/spec/ruby/core/array/bsearch_index_spec.rb
@@ -63,6 +63,10 @@ describe "Array#bsearch_index" do
@array.bsearch_index { |x| -1 }.should be_nil
end
+ it "returns the middle element when block always returns zero" do
+ @array.bsearch_index { |x| 0 }.should == 2
+ end
+
context "magnitude does not effect the result" do
it "returns the index of any matched elements where element is between 4n <= xn < 8n" do
[1, 2].should include(@array.bsearch_index { |x| (1 - x / 4) * (2**100) })
diff --git a/spec/ruby/core/array/count_spec.rb b/spec/ruby/core/array/count_spec.rb
index e778233c16..eaf275aeb7 100644
--- a/spec/ruby/core/array/count_spec.rb
+++ b/spec/ruby/core/array/count_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#count" do
it "returns the number of elements" do
@@ -13,14 +12,4 @@ describe "Array#count" do
it "returns the number of element for which the block evaluates to true" do
[:a, :b, :c].count { |s| s != :b }.should == 2
end
-
- it "ignores the block if there is an argument" do
- -> {
- [:a, :b, :b, :c].count(:b) { |e| e.size > 10 }.should == 2
- }.should complain(/given block not used/)
- end
-
- context "when a block argument given" do
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :count
- end
end
diff --git a/spec/ruby/core/array/delete_if_spec.rb b/spec/ruby/core/array/delete_if_spec.rb
index 10972eee0e..1459cc8d04 100644
--- a/spec/ruby/core/array/delete_if_spec.rb
+++ b/spec/ruby/core/array/delete_if_spec.rb
@@ -2,7 +2,6 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/enumeratorize'
require_relative 'shared/delete_if'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
require_relative '../enumerable/shared/enumeratorized'
describe "Array#delete_if" do
@@ -48,35 +47,6 @@ describe "Array#delete_if" do
-> { ArraySpecs.empty_frozen_array.delete_if {} }.should raise_error(FrozenError)
end
- it "does not truncate the array is the block raises an exception" do
- a = [1, 2, 3]
- begin
- a.delete_if { raise StandardError, 'Oops' }
- rescue
- end
-
- a.should == [1, 2, 3]
- end
-
- it "only removes elements for which the block returns true, keeping the element which raised an error." do
- a = [1, 2, 3, 4]
- begin
- a.delete_if do |e|
- case e
- when 2 then true
- when 3 then raise StandardError, 'Oops'
- else false
- end
- end
- rescue StandardError
- end
-
- a.should == [1, 3, 4]
- end
-
it_behaves_like :enumeratorized_with_origin_size, :delete_if, [1,2,3]
it_behaves_like :delete_if, :delete_if
-
- @value_to_return = -> _ { false }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :delete_if
end
diff --git a/spec/ruby/core/array/drop_spec.rb b/spec/ruby/core/array/drop_spec.rb
index 0ea748e47d..f911fd9018 100644
--- a/spec/ruby/core/array/drop_spec.rb
+++ b/spec/ruby/core/array/drop_spec.rb
@@ -50,7 +50,15 @@ describe "Array#drop" do
-> { [1, 2].drop(obj) }.should raise_error(TypeError)
end
- it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it 'returns a subclass instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it 'returns a Array instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(Array)
+ end
end
end
diff --git a/spec/ruby/core/array/drop_while_spec.rb b/spec/ruby/core/array/drop_while_spec.rb
index bd46e8b882..bb783d22a5 100644
--- a/spec/ruby/core/array/drop_while_spec.rb
+++ b/spec/ruby/core/array/drop_while_spec.rb
@@ -1,11 +1,7 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#drop_while" do
- @value_to_return = -> _ { true }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :drop_while
-
it "removes elements from the start of the array while the block evaluates to true" do
[1, 2, 3, 4].drop_while { |n| n < 4 }.should == [4]
end
@@ -18,7 +14,15 @@ describe "Array#drop_while" do
[1, 2, 3, false, 5].drop_while { |n| n }.should == [false, 5]
end
- it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it 'returns a subclass instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(ArraySpecs::MyArray)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it 'returns a Array instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(Array)
+ end
end
end
diff --git a/spec/ruby/core/array/each_index_spec.rb b/spec/ruby/core/array/each_index_spec.rb
index 3a4bca9251..51af5842c4 100644
--- a/spec/ruby/core/array/each_index_spec.rb
+++ b/spec/ruby/core/array/each_index_spec.rb
@@ -5,7 +5,7 @@ require_relative '../enumerable/shared/enumeratorized'
# Modifying a collection while the contents are being iterated
# gives undefined behavior. See
-# https://blade.ruby-lang.org/ruby-core/23633
+# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633
describe "Array#each_index" do
before :each do
@@ -40,19 +40,3 @@ describe "Array#each_index" do
it_behaves_like :enumeratorize, :each_index
it_behaves_like :enumeratorized_with_origin_size, :each_index, [1,2,3]
end
-
-describe "Array#each_index" do
- it "tolerates increasing an array size during iteration" do
- array = [:a, :b, :c]
- ScratchPad.record []
- i = 0
-
- array.each_index do |index|
- ScratchPad << index
- array << i if i < 100
- i += 1
- end
-
- ScratchPad.recorded.should == (0..102).to_a # element indices
- end
-end
diff --git a/spec/ruby/core/array/each_spec.rb b/spec/ruby/core/array/each_spec.rb
index f4b5b758d0..cf8e9da6d8 100644
--- a/spec/ruby/core/array/each_spec.rb
+++ b/spec/ruby/core/array/each_spec.rb
@@ -1,13 +1,12 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/enumeratorize'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
require_relative '../enumerable/shared/enumeratorized'
# Mutating the array while it is being iterated is discouraged as it can result in confusing behavior.
# Yet a Ruby implementation must not crash in such a case, and following the simple CRuby behavior makes sense.
# CRuby simply reads the array storage and checks the size for every iteration;
-# like `i = 0; while i < size; yield self[i]; i += 1; end`
+# like `i = 0; while i < size; yield self[i]; end`
describe "Array#each" do
it "yields each element to the block" do
@@ -76,7 +75,3 @@ describe "Array#each" do
it_behaves_like :enumeratorize, :each
it_behaves_like :enumeratorized_with_origin_size, :each, [1,2,3]
end
-
-describe "Array#each" do
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :each
-end
diff --git a/spec/ruby/core/array/fetch_values_spec.rb b/spec/ruby/core/array/fetch_values_spec.rb
deleted file mode 100644
index 559b6c2b2f..0000000000
--- a/spec/ruby/core/array/fetch_values_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-describe "Array#fetch_values" do
- before :each do
- @array = [:a, :b, :c]
- end
-
- ruby_version_is "3.4" do
- describe "with matched indexes" do
- it "returns the values for indexes" do
- @array.fetch_values(0).should == [:a]
- @array.fetch_values(0, 2).should == [:a, :c]
- end
-
- it "returns the values for indexes ordered in the order of the requested indexes" do
- @array.fetch_values(2, 0).should == [:c, :a]
- end
- end
-
- describe "with unmatched indexes" do
- it "raises a index error if no block is provided" do
- -> { @array.fetch_values(0, 1, 44) }.should raise_error(IndexError)
- end
-
- it "returns the default value from block" do
- @array.fetch_values(44) { |index| "`#{index}' is not found" }.should == ["`44' is not found"]
- @array.fetch_values(0, 44) { |index| "`#{index}' is not found" }.should == [:a, "`44' is not found"]
- end
- end
-
- describe "without keys" do
- it "returns an empty Array" do
- @array.fetch_values.should == []
- end
- end
-
- it "tries to convert the passed argument to an Integer using #to_int" do
- obj = mock('to_int')
- obj.should_receive(:to_int).and_return(2)
- @array.fetch_values(obj).should == [:c]
- end
-
- it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { [].fetch_values("cat") }.should raise_error(TypeError)
- end
- end
-end
diff --git a/spec/ruby/core/array/fill_spec.rb b/spec/ruby/core/array/fill_spec.rb
index 2c3b5d9e84..23728414be 100644
--- a/spec/ruby/core/array/fill_spec.rb
+++ b/spec/ruby/core/array/fill_spec.rb
@@ -21,7 +21,7 @@ describe "Array#fill" do
it "does not replicate the filler" do
ary = [1, 2, 3, 4]
- str = +"x"
+ str = "x"
ary.fill(str).should == [str, str, str, str]
str << "y"
ary.should == [str, str, str, str]
@@ -52,9 +52,11 @@ describe "Array#fill" do
end
it "raises an ArgumentError if 4 or more arguments are passed when no block given" do
- [].fill('a').should == []
- [].fill('a', 1).should == []
- [].fill('a', 1, 2).should == [nil, 'a', 'a']
+ -> { [].fill('a') }.should_not raise_error(ArgumentError)
+
+ -> { [].fill('a', 1) }.should_not raise_error(ArgumentError)
+
+ -> { [].fill('a', 1, 2) }.should_not raise_error(ArgumentError)
-> { [].fill('a', 1, 2, true) }.should raise_error(ArgumentError)
end
@@ -63,52 +65,12 @@ describe "Array#fill" do
end
it "raises an ArgumentError if 3 or more arguments are passed when a block given" do
- [].fill() {|i|}.should == []
- [].fill(1) {|i|}.should == []
- [].fill(1, 2) {|i|}.should == [nil, nil, nil]
- -> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError)
- end
+ -> { [].fill() {|i|} }.should_not raise_error(ArgumentError)
- it "does not truncate the array is the block raises an exception" do
- a = [1, 2, 3]
- begin
- a.fill { raise StandardError, 'Oops' }
- rescue
- end
+ -> { [].fill(1) {|i|} }.should_not raise_error(ArgumentError)
- a.should == [1, 2, 3]
- end
-
- it "only changes elements before error is raised, keeping the element which raised an error." do
- a = [1, 2, 3, 4]
- begin
- a.fill do |i|
- case i
- when 0 then -1
- when 1 then -2
- when 2 then raise StandardError, 'Oops'
- else 0
- end
- end
- rescue StandardError
- end
-
- a.should == [-1, -2, 3, 4]
- end
-
- it "tolerates increasing an array size during iteration" do
- array = [:a, :b, :c]
- ScratchPad.record []
- i = 0
-
- array.fill do |index|
- ScratchPad << index
- array << i if i < 100
- i++
- index
- end
-
- ScratchPad.recorded.should == [0, 1, 2]
+ -> { [].fill(1, 2) {|i|} }.should_not raise_error(ArgumentError)
+ -> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError)
end
end
@@ -207,25 +169,25 @@ describe "Array#fill with (filler, index, length)" do
[1, 2, 3, 4, 5].fill(-2, -2, &@never_passed).should == [1, 2, 3, 4, 5]
end
- # See: https://blade.ruby-lang.org/ruby-core/17481
+ # See: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/17481
it "does not raise an exception if the given length is negative and its absolute value does not exceed the index" do
- [1, 2, 3, 4].fill('a', 3, -1).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill('a', 3, -2).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill('a', 3, -3).should == [1, 2, 3, 4]
+ -> { [1, 2, 3, 4].fill('a', 3, -1)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill('a', 3, -2)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill('a', 3, -3)}.should_not raise_error(ArgumentError)
- [1, 2, 3, 4].fill(3, -1, &@never_passed).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill(3, -2, &@never_passed).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill(3, -3, &@never_passed).should == [1, 2, 3, 4]
+ -> { [1, 2, 3, 4].fill(3, -1, &@never_passed)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill(3, -2, &@never_passed)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill(3, -3, &@never_passed)}.should_not raise_error(ArgumentError)
end
it "does not raise an exception even if the given length is negative and its absolute value exceeds the index" do
- [1, 2, 3, 4].fill('a', 3, -4).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill('a', 3, -5).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill('a', 3, -10000).should == [1, 2, 3, 4]
+ -> { [1, 2, 3, 4].fill('a', 3, -4)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill('a', 3, -5)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill('a', 3, -10000)}.should_not raise_error(ArgumentError)
- [1, 2, 3, 4].fill(3, -4, &@never_passed).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill(3, -5, &@never_passed).should == [1, 2, 3, 4]
- [1, 2, 3, 4].fill(3, -10000, &@never_passed).should == [1, 2, 3, 4]
+ -> { [1, 2, 3, 4].fill(3, -4, &@never_passed)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill(3, -5, &@never_passed)}.should_not raise_error(ArgumentError)
+ -> { [1, 2, 3, 4].fill(3, -10000, &@never_passed)}.should_not raise_error(ArgumentError)
end
it "tries to convert the second and third arguments to Integers using #to_int" do
diff --git a/spec/ruby/core/array/fixtures/classes.rb b/spec/ruby/core/array/fixtures/classes.rb
index 05283c0f74..aa5fecd96b 100644
--- a/spec/ruby/core/array/fixtures/classes.rb
+++ b/spec/ruby/core/array/fixtures/classes.rb
@@ -56,20 +56,23 @@ module ArraySpecs
101.621, 102.816, 104.010, 105.202, 106.393, 107.583, 108.771, 109.958, 111.144, 112.329,
113.512, 114.695, 115.876, 117.057, 118.236, 119.414, 120.591, 121.767, 122.942, 124.116,
125.289, 126.462, 127.633, 128.803, 129.973, 131.141, 132.309, 133.476, 134.642, 135.807,
- ]
+ ]
def self.measure_sample_fairness(size, samples, iters)
ary = Array.new(size) { |x| x }
- expected = iters.fdiv size
(samples).times do |i|
chi_results = []
3.times do
- counts = Array.new(size, 0)
+ counts = Array.new(size) { 0 }
+ expected = iters / size
iters.times do
x = ary.sample(samples)[i]
counts[x] += 1
end
- chi_squared = counts.sum {|count| (count - expected) ** 2} / expected
+ chi_squared = 0.0
+ counts.each do |count|
+ chi_squared += (((count - expected) ** 2) * 1.0 / expected)
+ end
chi_results << chi_squared
break if chi_squared <= CHI_SQUARED_CRITICAL_VALUES[size]
end
@@ -80,14 +83,17 @@ module ArraySpecs
def self.measure_sample_fairness_large_sample_size(size, samples, iters)
ary = Array.new(size) { |x| x }
- counts = Array.new(size, 0)
- expected = (iters * samples).fdiv size
+ counts = Array.new(size) { 0 }
+ expected = iters * samples / size
iters.times do
ary.sample(samples).each do |sample|
counts[sample] += 1
end
end
- chi_squared = counts.sum {|count| (count - expected) ** 2} / expected
+ chi_squared = 0.0
+ counts.each do |count|
+ chi_squared += (((count - expected) ** 2) * 1.0 / expected)
+ end
# Chi squared critical values for tests with 4 degrees of freedom
# Values obtained from NIST Engineering Statistic Handbook at
@@ -154,16 +160,6 @@ module ArraySpecs
end
end
- class ArrayMethodMissing
- def initialize(*values, &block)
- @values = values;
- end
-
- def method_missing(name, *args)
- @values
- end
- end
-
class SortSame
def <=>(other); 0; end
def ==(other); true; end
@@ -217,370 +213,366 @@ module ArraySpecs
obj
end
- LargeArray = [
- "test_create_table_with_force_true_does_not_drop_nonexisting_table",
- "test_add_table",
- "assert_difference",
- "assert_operator",
- "instance_variables",
- "class",
- "instance_variable_get",
- "__class__",
- "expects",
- "assert_no_difference",
- "name",
- "assert_blank",
- "assert_not_same",
- "is_a?",
- "test_add_table_with_decimals",
- "test_create_table_with_timestamps_should_create_datetime_columns",
- "assert_present",
- "assert_no_match",
- "__instance_of__",
- "assert_deprecated",
- "assert",
- "assert_throws",
- "kind_of?",
- "try",
- "__instance_variable_get__",
- "object_id",
- "timeout",
- "instance_variable_set",
- "assert_nothing_thrown",
- "__instance_variable_set__",
- "copy_object",
- "test_create_table_with_timestamps_should_create_datetime_columns_with_options",
- "assert_not_deprecated",
- "assert_in_delta",
- "id",
- "copy_metaclass",
- "test_create_table_without_a_block",
- "dup",
- "assert_not_nil",
- "send",
- "__instance_variables__",
- "to_sql",
- "mock",
- "assert_send",
- "instance_variable_defined?",
- "clone",
- "require",
- "test_migrator",
- "__instance_variable_defined_eh__",
- "frozen?",
- "test_add_column_not_null_with_default",
- "freeze",
- "test_migrator_one_up",
- "test_migrator_one_down",
- "singleton_methods",
- "method_exists?",
- "create_fixtures",
- "test_migrator_one_up_one_down",
- "test_native_decimal_insert_manual_vs_automatic",
- "instance_exec",
- "__is_a__",
- "test_migrator_double_up",
- "stub",
- "private_methods",
- "stubs",
- "test_migrator_double_down",
- "fixture_path",
- "private_singleton_methods",
- "stub_everything",
- "test_migrator_one_up_with_exception_and_rollback",
- "sequence",
- "protected_methods",
- "enum_for",
- "test_finds_migrations",
- "run_before_mocha",
- "states",
- "protected_singleton_methods",
- "to_json",
- "instance_values",
- "==",
- "mocha_setup",
- "public_methods",
- "test_finds_pending_migrations",
- "mocha_verify",
- "assert_kind_of",
- "===",
- "=~",
- "test_relative_migrations",
- "mocha_teardown",
- "gem",
- "mocha",
- "test_only_loads_pending_migrations",
- "test_add_column_with_precision_and_scale",
- "require_or_load",
- "eql?",
- "require_dependency",
- "test_native_types",
- "test_target_version_zero_should_run_only_once",
- "extend",
- "to_matcher",
- "unloadable",
- "require_association",
- "hash",
- "__id__",
- "load_dependency",
- "equals",
- "test_migrator_db_has_no_schema_migrations_table",
- "test_migrator_verbosity",
- "kind_of",
- "to_yaml",
- "to_bool",
- "test_migrator_verbosity_off",
- "taint",
- "test_migrator_going_down_due_to_version_target",
- "tainted?",
- "mocha_inspect",
- "test_migrator_rollback",
- "vim",
- "untaint",
- "taguri=",
- "test_migrator_forward",
- "test_schema_migrations_table_name",
- "test_proper_table_name",
- "all_of",
- "test_add_drop_table_with_prefix_and_suffix",
- "_setup_callbacks",
- "setup",
- "Not",
- "test_create_table_with_binary_column",
- "assert_not_equal",
- "enable_warnings",
- "acts_like?",
- "Rational",
- "_removed_setup_callbacks",
- "Table",
- "bind",
- "any_of",
- "__method__",
- "test_migrator_with_duplicates",
- "_teardown_callbacks",
- "method",
- "test_migrator_with_duplicate_names",
- "_removed_teardown_callbacks",
- "any_parameters",
- "test_migrator_with_missing_version_numbers",
- "test_add_remove_single_field_using_string_arguments",
- "test_create_table_with_custom_sequence_name",
- "test_add_remove_single_field_using_symbol_arguments",
- "_one_time_conditions_valid_14?",
- "_one_time_conditions_valid_16?",
- "run_callbacks",
- "anything",
- "silence_warnings",
- "instance_variable_names",
- "_fixture_path",
- "copy_instance_variables_from",
- "fixture_path?",
- "has_entry",
- "__marshal__",
- "_fixture_table_names",
- "__kind_of__",
- "fixture_table_names?",
- "test_add_rename",
- "assert_equal",
- "_fixture_class_names",
- "fixture_class_names?",
- "has_entries",
- "_use_transactional_fixtures",
- "people",
- "test_rename_column_using_symbol_arguments",
- "use_transactional_fixtures?",
- "instance_eval",
- "blank?",
- "with_warnings",
- "__nil__",
- "load",
- "metaclass",
- "_use_instantiated_fixtures",
- "has_key",
- "class_eval",
- "present?",
- "test_rename_column",
- "teardown",
- "use_instantiated_fixtures?",
- "method_name",
- "silence_stderr",
- "presence",
- "test_rename_column_preserves_default_value_not_null",
- "silence_stream",
- "_pre_loaded_fixtures",
- "__metaclass__",
- "__fixnum__",
- "pre_loaded_fixtures?",
- "has_value",
- "suppress",
- "to_yaml_properties",
- "test_rename_nonexistent_column",
- "test_add_index",
- "includes",
- "find_correlate_in",
- "equality_predicate_sql",
- "assert_nothing_raised",
- "let",
- "not_predicate_sql",
- "test_rename_column_with_sql_reserved_word",
- "singleton_class",
- "test_rename_column_with_an_index",
- "display",
- "taguri",
- "to_yaml_style",
- "test_remove_column_with_index",
- "size",
- "current_adapter?",
- "test_remove_column_with_multi_column_index",
- "respond_to?",
- "test_change_type_of_not_null_column",
- "is_a",
- "to_a",
- "test_rename_table_for_sqlite_should_work_with_reserved_words",
- "require_library_or_gem",
- "setup_fixtures",
- "equal?",
- "teardown_fixtures",
- "nil?",
- "fixture_table_names",
- "fixture_class_names",
- "test_create_table_without_id",
- "use_transactional_fixtures",
- "test_add_column_with_primary_key_attribute",
- "repair_validations",
- "use_instantiated_fixtures",
- "instance_of?",
- "test_create_table_adds_id",
- "test_rename_table",
- "pre_loaded_fixtures",
- "to_enum",
- "test_create_table_with_not_null_column",
- "instance_of",
- "test_change_column_nullability",
- "optionally",
- "test_rename_table_with_an_index",
- "run",
- "test_change_column",
- "default_test",
- "assert_raise",
- "test_create_table_with_defaults",
- "assert_nil",
- "flunk",
- "regexp_matches",
- "duplicable?",
- "reset_mocha",
- "stubba_method",
- "filter_backtrace",
- "test_create_table_with_limits",
- "responds_with",
- "stubba_object",
- "test_change_column_with_nil_default",
- "assert_block",
- "__show__",
- "assert_date_from_db",
- "__respond_to_eh__",
- "run_in_transaction?",
- "inspect",
- "assert_sql",
- "test_change_column_with_new_default",
- "yaml_equivalent",
- "build_message",
- "to_s",
- "test_change_column_default",
- "assert_queries",
- "pending",
- "as_json",
- "assert_no_queries",
- "test_change_column_quotes_column_names",
- "assert_match",
- "test_keeping_default_and_notnull_constraint_on_change",
- "methods",
- "connection_allow_concurrency_setup",
- "connection_allow_concurrency_teardown",
- "test_create_table_with_primary_key_prefix_as_table_name_with_underscore",
- "__send__",
- "make_connection",
- "assert_raises",
- "tap",
- "with_kcode",
- "assert_instance_of",
- "test_create_table_with_primary_key_prefix_as_table_name",
- "assert_respond_to",
- "test_change_column_default_to_null",
- "assert_same",
- "__extend__",
- ]
-
- LargeTestArraySorted = [
- "test_add_column_not_null_with_default",
- "test_add_column_with_precision_and_scale",
- "test_add_column_with_primary_key_attribute",
- "test_add_drop_table_with_prefix_and_suffix",
- "test_add_index",
- "test_add_remove_single_field_using_string_arguments",
- "test_add_remove_single_field_using_symbol_arguments",
- "test_add_rename",
- "test_add_table",
- "test_add_table_with_decimals",
- "test_change_column",
- "test_change_column_default",
- "test_change_column_default_to_null",
- "test_change_column_nullability",
- "test_change_column_quotes_column_names",
- "test_change_column_with_new_default",
- "test_change_column_with_nil_default",
- "test_change_type_of_not_null_column",
- "test_create_table_adds_id",
- "test_create_table_with_binary_column",
- "test_create_table_with_custom_sequence_name",
- "test_create_table_with_defaults",
- "test_create_table_with_force_true_does_not_drop_nonexisting_table",
- "test_create_table_with_limits",
- "test_create_table_with_not_null_column",
- "test_create_table_with_primary_key_prefix_as_table_name",
- "test_create_table_with_primary_key_prefix_as_table_name_with_underscore",
- "test_create_table_with_timestamps_should_create_datetime_columns",
- "test_create_table_with_timestamps_should_create_datetime_columns_with_options",
- "test_create_table_without_a_block",
- "test_create_table_without_id",
- "test_finds_migrations",
- "test_finds_pending_migrations",
- "test_keeping_default_and_notnull_constraint_on_change",
- "test_migrator",
- "test_migrator_db_has_no_schema_migrations_table",
- "test_migrator_double_down",
- "test_migrator_double_up",
- "test_migrator_forward",
- "test_migrator_going_down_due_to_version_target",
- "test_migrator_one_down",
- "test_migrator_one_up",
- "test_migrator_one_up_one_down",
- "test_migrator_one_up_with_exception_and_rollback",
- "test_migrator_rollback",
- "test_migrator_verbosity",
- "test_migrator_verbosity_off",
- "test_migrator_with_duplicate_names",
- "test_migrator_with_duplicates",
- "test_migrator_with_missing_version_numbers",
- "test_native_decimal_insert_manual_vs_automatic",
- "test_native_types",
- "test_only_loads_pending_migrations",
- "test_proper_table_name",
- "test_relative_migrations",
- "test_remove_column_with_index",
- "test_remove_column_with_multi_column_index",
- "test_rename_column",
- "test_rename_column_preserves_default_value_not_null",
- "test_rename_column_using_symbol_arguments",
- "test_rename_column_with_an_index",
- "test_rename_column_with_sql_reserved_word",
- "test_rename_nonexistent_column",
- "test_rename_table",
- "test_rename_table_for_sqlite_should_work_with_reserved_words",
- "test_rename_table_with_an_index",
- "test_schema_migrations_table_name",
- "test_target_version_zero_should_run_only_once",
- ]
+ LargeArray = ["test_create_table_with_force_true_does_not_drop_nonexisting_table",
+ "test_add_table",
+ "assert_difference",
+ "assert_operator",
+ "instance_variables",
+ "class",
+ "instance_variable_get",
+ "__class__",
+ "expects",
+ "assert_no_difference",
+ "name",
+ "assert_blank",
+ "assert_not_same",
+ "is_a?",
+ "test_add_table_with_decimals",
+ "test_create_table_with_timestamps_should_create_datetime_columns",
+ "assert_present",
+ "assert_no_match",
+ "__instance_of__",
+ "assert_deprecated",
+ "assert",
+ "assert_throws",
+ "kind_of?",
+ "try",
+ "__instance_variable_get__",
+ "object_id",
+ "timeout",
+ "instance_variable_set",
+ "assert_nothing_thrown",
+ "__instance_variable_set__",
+ "copy_object",
+ "test_create_table_with_timestamps_should_create_datetime_columns_with_options",
+ "assert_not_deprecated",
+ "assert_in_delta",
+ "id",
+ "copy_metaclass",
+ "test_create_table_without_a_block",
+ "dup",
+ "assert_not_nil",
+ "send",
+ "__instance_variables__",
+ "to_sql",
+ "mock",
+ "assert_send",
+ "instance_variable_defined?",
+ "clone",
+ "require",
+ "test_migrator",
+ "__instance_variable_defined_eh__",
+ "frozen?",
+ "test_add_column_not_null_with_default",
+ "freeze",
+ "test_migrator_one_up",
+ "test_migrator_one_down",
+ "singleton_methods",
+ "method_exists?",
+ "create_fixtures",
+ "test_migrator_one_up_one_down",
+ "test_native_decimal_insert_manual_vs_automatic",
+ "instance_exec",
+ "__is_a__",
+ "test_migrator_double_up",
+ "stub",
+ "private_methods",
+ "stubs",
+ "test_migrator_double_down",
+ "fixture_path",
+ "private_singleton_methods",
+ "stub_everything",
+ "test_migrator_one_up_with_exception_and_rollback",
+ "sequence",
+ "protected_methods",
+ "enum_for",
+ "test_finds_migrations",
+ "run_before_mocha",
+ "states",
+ "protected_singleton_methods",
+ "to_json",
+ "instance_values",
+ "==",
+ "mocha_setup",
+ "public_methods",
+ "test_finds_pending_migrations",
+ "mocha_verify",
+ "assert_kind_of",
+ "===",
+ "=~",
+ "test_relative_migrations",
+ "mocha_teardown",
+ "gem",
+ "mocha",
+ "test_only_loads_pending_migrations",
+ "test_add_column_with_precision_and_scale",
+ "require_or_load",
+ "eql?",
+ "require_dependency",
+ "test_native_types",
+ "test_target_version_zero_should_run_only_once",
+ "extend",
+ "to_matcher",
+ "unloadable",
+ "require_association",
+ "hash",
+ "__id__",
+ "load_dependency",
+ "equals",
+ "test_migrator_db_has_no_schema_migrations_table",
+ "test_migrator_verbosity",
+ "kind_of",
+ "to_yaml",
+ "to_bool",
+ "test_migrator_verbosity_off",
+ "taint",
+ "test_migrator_going_down_due_to_version_target",
+ "tainted?",
+ "mocha_inspect",
+ "test_migrator_rollback",
+ "vim",
+ "untaint",
+ "taguri=",
+ "test_migrator_forward",
+ "test_schema_migrations_table_name",
+ "test_proper_table_name",
+ "all_of",
+ "test_add_drop_table_with_prefix_and_suffix",
+ "_setup_callbacks",
+ "setup",
+ "Not",
+ "test_create_table_with_binary_column",
+ "assert_not_equal",
+ "enable_warnings",
+ "acts_like?",
+ "Rational",
+ "_removed_setup_callbacks",
+ "Table",
+ "bind",
+ "any_of",
+ "__method__",
+ "test_migrator_with_duplicates",
+ "_teardown_callbacks",
+ "method",
+ "test_migrator_with_duplicate_names",
+ "_removed_teardown_callbacks",
+ "any_parameters",
+ "test_migrator_with_missing_version_numbers",
+ "test_add_remove_single_field_using_string_arguments",
+ "test_create_table_with_custom_sequence_name",
+ "test_add_remove_single_field_using_symbol_arguments",
+ "_one_time_conditions_valid_14?",
+ "_one_time_conditions_valid_16?",
+ "run_callbacks",
+ "anything",
+ "silence_warnings",
+ "instance_variable_names",
+ "_fixture_path",
+ "copy_instance_variables_from",
+ "fixture_path?",
+ "has_entry",
+ "__marshal__",
+ "_fixture_table_names",
+ "__kind_of__",
+ "fixture_table_names?",
+ "test_add_rename",
+ "assert_equal",
+ "_fixture_class_names",
+ "fixture_class_names?",
+ "has_entries",
+ "_use_transactional_fixtures",
+ "people",
+ "test_rename_column_using_symbol_arguments",
+ "use_transactional_fixtures?",
+ "instance_eval",
+ "blank?",
+ "with_warnings",
+ "__nil__",
+ "load",
+ "metaclass",
+ "_use_instantiated_fixtures",
+ "has_key",
+ "class_eval",
+ "present?",
+ "test_rename_column",
+ "teardown",
+ "use_instantiated_fixtures?",
+ "method_name",
+ "silence_stderr",
+ "presence",
+ "test_rename_column_preserves_default_value_not_null",
+ "silence_stream",
+ "_pre_loaded_fixtures",
+ "__metaclass__",
+ "__fixnum__",
+ "pre_loaded_fixtures?",
+ "has_value",
+ "suppress",
+ "to_yaml_properties",
+ "test_rename_nonexistent_column",
+ "test_add_index",
+ "includes",
+ "find_correlate_in",
+ "equality_predicate_sql",
+ "assert_nothing_raised",
+ "let",
+ "not_predicate_sql",
+ "test_rename_column_with_sql_reserved_word",
+ "singleton_class",
+ "test_rename_column_with_an_index",
+ "display",
+ "taguri",
+ "to_yaml_style",
+ "test_remove_column_with_index",
+ "size",
+ "current_adapter?",
+ "test_remove_column_with_multi_column_index",
+ "respond_to?",
+ "test_change_type_of_not_null_column",
+ "is_a",
+ "to_a",
+ "test_rename_table_for_sqlite_should_work_with_reserved_words",
+ "require_library_or_gem",
+ "setup_fixtures",
+ "equal?",
+ "teardown_fixtures",
+ "nil?",
+ "fixture_table_names",
+ "fixture_class_names",
+ "test_create_table_without_id",
+ "use_transactional_fixtures",
+ "test_add_column_with_primary_key_attribute",
+ "repair_validations",
+ "use_instantiated_fixtures",
+ "instance_of?",
+ "test_create_table_adds_id",
+ "test_rename_table",
+ "pre_loaded_fixtures",
+ "to_enum",
+ "test_create_table_with_not_null_column",
+ "instance_of",
+ "test_change_column_nullability",
+ "optionally",
+ "test_rename_table_with_an_index",
+ "run",
+ "test_change_column",
+ "default_test",
+ "assert_raise",
+ "test_create_table_with_defaults",
+ "assert_nil",
+ "flunk",
+ "regexp_matches",
+ "duplicable?",
+ "reset_mocha",
+ "stubba_method",
+ "filter_backtrace",
+ "test_create_table_with_limits",
+ "responds_with",
+ "stubba_object",
+ "test_change_column_with_nil_default",
+ "assert_block",
+ "__show__",
+ "assert_date_from_db",
+ "__respond_to_eh__",
+ "run_in_transaction?",
+ "inspect",
+ "assert_sql",
+ "test_change_column_with_new_default",
+ "yaml_equivalent",
+ "build_message",
+ "to_s",
+ "test_change_column_default",
+ "assert_queries",
+ "pending",
+ "as_json",
+ "assert_no_queries",
+ "test_change_column_quotes_column_names",
+ "assert_match",
+ "test_keeping_default_and_notnull_constraint_on_change",
+ "methods",
+ "connection_allow_concurrency_setup",
+ "connection_allow_concurrency_teardown",
+ "test_create_table_with_primary_key_prefix_as_table_name_with_underscore",
+ "__send__",
+ "make_connection",
+ "assert_raises",
+ "tap",
+ "with_kcode",
+ "assert_instance_of",
+ "test_create_table_with_primary_key_prefix_as_table_name",
+ "assert_respond_to",
+ "test_change_column_default_to_null",
+ "assert_same",
+ "__extend__"]
+
+ LargeTestArraySorted = ["test_add_column_not_null_with_default",
+ "test_add_column_with_precision_and_scale",
+ "test_add_column_with_primary_key_attribute",
+ "test_add_drop_table_with_prefix_and_suffix",
+ "test_add_index",
+ "test_add_remove_single_field_using_string_arguments",
+ "test_add_remove_single_field_using_symbol_arguments",
+ "test_add_rename",
+ "test_add_table",
+ "test_add_table_with_decimals",
+ "test_change_column",
+ "test_change_column_default",
+ "test_change_column_default_to_null",
+ "test_change_column_nullability",
+ "test_change_column_quotes_column_names",
+ "test_change_column_with_new_default",
+ "test_change_column_with_nil_default",
+ "test_change_type_of_not_null_column",
+ "test_create_table_adds_id",
+ "test_create_table_with_binary_column",
+ "test_create_table_with_custom_sequence_name",
+ "test_create_table_with_defaults",
+ "test_create_table_with_force_true_does_not_drop_nonexisting_table",
+ "test_create_table_with_limits",
+ "test_create_table_with_not_null_column",
+ "test_create_table_with_primary_key_prefix_as_table_name",
+ "test_create_table_with_primary_key_prefix_as_table_name_with_underscore",
+ "test_create_table_with_timestamps_should_create_datetime_columns",
+ "test_create_table_with_timestamps_should_create_datetime_columns_with_options",
+ "test_create_table_without_a_block",
+ "test_create_table_without_id",
+ "test_finds_migrations",
+ "test_finds_pending_migrations",
+ "test_keeping_default_and_notnull_constraint_on_change",
+ "test_migrator",
+ "test_migrator_db_has_no_schema_migrations_table",
+ "test_migrator_double_down",
+ "test_migrator_double_up",
+ "test_migrator_forward",
+ "test_migrator_going_down_due_to_version_target",
+ "test_migrator_one_down",
+ "test_migrator_one_up",
+ "test_migrator_one_up_one_down",
+ "test_migrator_one_up_with_exception_and_rollback",
+ "test_migrator_rollback",
+ "test_migrator_verbosity",
+ "test_migrator_verbosity_off",
+ "test_migrator_with_duplicate_names",
+ "test_migrator_with_duplicates",
+ "test_migrator_with_missing_version_numbers",
+ "test_native_decimal_insert_manual_vs_automatic",
+ "test_native_types",
+ "test_only_loads_pending_migrations",
+ "test_proper_table_name",
+ "test_relative_migrations",
+ "test_remove_column_with_index",
+ "test_remove_column_with_multi_column_index",
+ "test_rename_column",
+ "test_rename_column_preserves_default_value_not_null",
+ "test_rename_column_using_symbol_arguments",
+ "test_rename_column_with_an_index",
+ "test_rename_column_with_sql_reserved_word",
+ "test_rename_nonexistent_column",
+ "test_rename_table",
+ "test_rename_table_for_sqlite_should_work_with_reserved_words",
+ "test_rename_table_with_an_index",
+ "test_schema_migrations_table_name",
+ "test_target_version_zero_should_run_only_once"]
class PrivateToAry
private
diff --git a/spec/ruby/core/array/fixtures/encoded_strings.rb b/spec/ruby/core/array/fixtures/encoded_strings.rb
index b5888d86ae..5b85bd0e06 100644
--- a/spec/ruby/core/array/fixtures/encoded_strings.rb
+++ b/spec/ruby/core/array/fixtures/encoded_strings.rb
@@ -2,14 +2,14 @@
module ArraySpecs
def self.array_with_usascii_and_7bit_utf8_strings
[
- 'foo'.dup.force_encoding('US-ASCII'),
+ 'foo'.force_encoding('US-ASCII'),
'bar'
]
end
def self.array_with_usascii_and_utf8_strings
[
- 'foo'.dup.force_encoding('US-ASCII'),
+ 'foo'.force_encoding('US-ASCII'),
'báz'
]
end
@@ -17,7 +17,7 @@ module ArraySpecs
def self.array_with_7bit_utf8_and_usascii_strings
[
'bar',
- 'foo'.dup.force_encoding('US-ASCII')
+ 'foo'.force_encoding('US-ASCII')
]
end
@@ -25,13 +25,13 @@ module ArraySpecs
[
'báz',
'bar',
- 'foo'.dup.force_encoding('US-ASCII')
+ 'foo'.force_encoding('US-ASCII')
]
end
def self.array_with_usascii_and_utf8_strings
[
- 'foo'.dup.force_encoding('US-ASCII'),
+ 'foo'.force_encoding('US-ASCII'),
'bar',
'báz'
]
@@ -41,7 +41,7 @@ module ArraySpecs
[
'bar',
'báz',
- 'foo'.dup.force_encoding('BINARY')
+ 'foo'.force_encoding('BINARY')
]
end
@@ -55,14 +55,14 @@ module ArraySpecs
def self.array_with_usascii_and_7bit_binary_strings
[
- 'bar'.dup.force_encoding('US-ASCII'),
- 'foo'.dup.force_encoding('BINARY')
+ 'bar'.force_encoding('US-ASCII'),
+ 'foo'.force_encoding('BINARY')
]
end
def self.array_with_usascii_and_binary_strings
[
- 'bar'.dup.force_encoding('US-ASCII'),
+ 'bar'.force_encoding('US-ASCII'),
[255].pack('C').force_encoding('BINARY')
]
end
diff --git a/spec/ruby/core/array/flatten_spec.rb b/spec/ruby/core/array/flatten_spec.rb
index 8c97000c79..1770b5389a 100644
--- a/spec/ruby/core/array/flatten_spec.rb
+++ b/spec/ruby/core/array/flatten_spec.rb
@@ -75,12 +75,24 @@ describe "Array#flatten" do
[[obj]].flatten(1)
end
- it "returns Array instance for Array subclasses" do
- ArraySpecs::MyArray[].flatten.should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == [1, 2, 3, 4]
- [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instance for Array subclasses" do
+ ArraySpecs::MyArray[].flatten.should be_an_instance_of(ArraySpecs::MyArray)
+ ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(ArraySpecs::MyArray)
+ ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(ArraySpecs::MyArray)
+ ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == ArraySpecs::MyArray[1, 2, 3, 4]
+ [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns Array instance for Array subclasses" do
+ ArraySpecs::MyArray[].flatten.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == [1, 2, 3, 4]
+ [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array)
+ end
end
it "is not destructive" do
diff --git a/spec/ruby/core/array/initialize_spec.rb b/spec/ruby/core/array/initialize_spec.rb
index b9fa77b16e..a8deed2b84 100644
--- a/spec/ruby/core/array/initialize_spec.rb
+++ b/spec/ruby/core/array/initialize_spec.rb
@@ -53,9 +53,7 @@ describe "Array#initialize with no arguments" do
end
it "does not use the given block" do
- -> {
- -> { [1, 2, 3].send(:initialize) { raise } }.should_not raise_error
- }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
+ ->{ [1, 2, 3].send(:initialize) { raise } }.should_not raise_error
end
end
diff --git a/spec/ruby/core/array/intersect_spec.rb b/spec/ruby/core/array/intersect_spec.rb
index 62ac157278..b8c5b1e69a 100644
--- a/spec/ruby/core/array/intersect_spec.rb
+++ b/spec/ruby/core/array/intersect_spec.rb
@@ -1,66 +1,17 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
describe 'Array#intersect?' do
ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/15198
describe 'when at least one element in two Arrays is the same' do
it 'returns true' do
- [1, 2].intersect?([2, 3, 4]).should == true
- [2, 3, 4].intersect?([1, 2]).should == true
+ [1, 2].intersect?([2, 3]).should == true
end
end
describe 'when there are no elements in common between two Arrays' do
it 'returns false' do
- [0, 1, 2].intersect?([3, 4]).should == false
- [3, 4].intersect?([0, 1, 2]).should == false
- [3, 4].intersect?([]).should == false
- [].intersect?([0, 1, 2]).should == false
+ [1, 2].intersect?([3, 4]).should == false
end
end
-
- it "tries to convert the passed argument to an Array using #to_ary" do
- obj = mock('[1,2,3]')
- obj.should_receive(:to_ary).and_return([1, 2, 3])
-
- [1, 2].intersect?(obj).should == true
- end
-
- it "determines equivalence between elements in the sense of eql?" do
- obj1 = mock('1')
- obj2 = mock('2')
- obj1.stub!(:hash).and_return(0)
- obj2.stub!(:hash).and_return(0)
- obj1.stub!(:eql?).and_return(true)
- obj2.stub!(:eql?).and_return(true)
-
- [obj1].intersect?([obj2]).should == true
-
- obj1 = mock('3')
- obj2 = mock('4')
- obj1.stub!(:hash).and_return(0)
- obj2.stub!(:hash).and_return(0)
- obj1.stub!(:eql?).and_return(false)
- obj2.stub!(:eql?).and_return(false)
-
- [obj1].intersect?([obj2]).should == false
- end
-
- it "does not call to_ary on array subclasses" do
- [5, 6].intersect?(ArraySpecs::ToAryArray[1, 2, 5, 6]).should == true
- end
-
- it "properly handles an identical item even when its #eql? isn't reflexive" do
- x = mock('x')
- x.stub!(:hash).and_return(42)
- x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
-
- [x].intersect?([x]).should == true
- end
-
- it "has semantic of !(a & b).empty?" do
- [].intersect?([]).should == false
- [nil].intersect?([nil]).should == true
- end
end
end
diff --git a/spec/ruby/core/array/multiply_spec.rb b/spec/ruby/core/array/multiply_spec.rb
index eca51142fb..23d5c99f3a 100644
--- a/spec/ruby/core/array/multiply_spec.rb
+++ b/spec/ruby/core/array/multiply_spec.rb
@@ -76,10 +76,20 @@ describe "Array#* with an integer" do
@array = ArraySpecs::MyArray[1, 2, 3, 4, 5]
end
- it "returns an Array instance" do
- (@array * 0).should be_an_instance_of(Array)
- (@array * 1).should be_an_instance_of(Array)
- (@array * 2).should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it "returns a subclass instance" do
+ (@array * 0).should be_an_instance_of(ArraySpecs::MyArray)
+ (@array * 1).should be_an_instance_of(ArraySpecs::MyArray)
+ (@array * 2).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns an Array instance" do
+ (@array * 0).should be_an_instance_of(Array)
+ (@array * 1).should be_an_instance_of(Array)
+ (@array * 2).should be_an_instance_of(Array)
+ end
end
it "does not call #initialize on the subclass instance" do
diff --git a/spec/ruby/core/array/new_spec.rb b/spec/ruby/core/array/new_spec.rb
index b50a4857b0..96ec6b8198 100644
--- a/spec/ruby/core/array/new_spec.rb
+++ b/spec/ruby/core/array/new_spec.rb
@@ -26,9 +26,7 @@ describe "Array.new with no arguments" do
end
it "does not use the given block" do
- -> {
- -> { Array.new { raise } }.should_not raise_error
- }.should complain(/warning: given block not used/, verbose: true)
+ ->{ Array.new { raise } }.should_not raise_error
end
end
diff --git a/spec/ruby/core/array/none_spec.rb b/spec/ruby/core/array/none_spec.rb
deleted file mode 100644
index 31cd8c46d6..0000000000
--- a/spec/ruby/core/array/none_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
-
-describe "Array#none?" do
- @value_to_return = -> _ { false }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :none?
-
- it "ignores the block if there is an argument" do
- -> {
- ['bar', 'foobar'].none?(/baz/) { true }.should == true
- }.should complain(/given block not used/)
- end
-end
diff --git a/spec/ruby/core/array/one_spec.rb b/spec/ruby/core/array/one_spec.rb
deleted file mode 100644
index 0c61907881..0000000000
--- a/spec/ruby/core/array/one_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
-
-describe "Array#one?" do
- @value_to_return = -> _ { false }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :one?
-
- it "ignores the block if there is an argument" do
- -> {
- ['bar', 'foobar'].one?(/foo/) { false }.should == true
- }.should complain(/given block not used/)
- end
-end
diff --git a/spec/ruby/core/array/pack/buffer_spec.rb b/spec/ruby/core/array/pack/buffer_spec.rb
index b77b2d1efa..ecb40bfd06 100644
--- a/spec/ruby/core/array/pack/buffer_spec.rb
+++ b/spec/ruby/core/array/pack/buffer_spec.rb
@@ -13,13 +13,13 @@ describe "Array#pack with :buffer option" do
it "adds result at the end of buffer content" do
n = [ 65, 66, 67 ] # result without buffer is "ABC"
- buffer = +""
+ buffer = ""
n.pack("ccc", buffer: buffer).should == "ABC"
- buffer = +"123"
+ buffer = "123"
n.pack("ccc", buffer: buffer).should == "123ABC"
- buffer = +"12345"
+ buffer = "12345"
n.pack("ccc", buffer: buffer).should == "12345ABC"
end
@@ -28,32 +28,22 @@ describe "Array#pack with :buffer option" do
TypeError, "buffer must be String, not Array")
end
- it "raise FrozenError if buffer is frozen" do
- -> { [65].pack("c", buffer: "frozen-string".freeze) }.should raise_error(FrozenError)
- end
-
- it "preserves the encoding of the given buffer" do
- buffer = ''.encode(Encoding::ISO_8859_1)
- [65, 66, 67].pack("ccc", buffer: buffer)
- buffer.encoding.should == Encoding::ISO_8859_1
- end
-
context "offset (@) is specified" do
it 'keeps buffer content if it is longer than offset' do
n = [ 65, 66, 67 ]
- buffer = +"123456"
+ buffer = "123456"
n.pack("@3ccc", buffer: buffer).should == "123ABC"
end
it "fills the gap with \\0 if buffer content is shorter than offset" do
n = [ 65, 66, 67 ]
- buffer = +"123"
+ buffer = "123"
n.pack("@6ccc", buffer: buffer).should == "123\0\0\0ABC"
end
it 'does not keep buffer content if it is longer than offset + result' do
n = [ 65, 66, 67 ]
- buffer = +"1234567890"
+ buffer = "1234567890"
n.pack("@3ccc", buffer: buffer).should == "123ABC"
end
end
diff --git a/spec/ruby/core/array/pack/c_spec.rb b/spec/ruby/core/array/pack/c_spec.rb
index ac133ff9b6..be03551629 100644
--- a/spec/ruby/core/array/pack/c_spec.rb
+++ b/spec/ruby/core/array/pack/c_spec.rb
@@ -47,9 +47,7 @@ describe :array_pack_8bit, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02"
- end
+ [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02"
end
end
diff --git a/spec/ruby/core/array/pack/l_spec.rb b/spec/ruby/core/array/pack/l_spec.rb
index f6dfb1da83..b446a7a36a 100644
--- a/spec/ruby/core/array/pack/l_spec.rb
+++ b/spec/ruby/core/array/pack/l_spec.rb
@@ -29,7 +29,7 @@ describe "Array#pack with format 'L'" do
it_behaves_like :array_pack_32bit_be, 'L>'
end
- platform_is c_long_size: 32 do
+ platform_is wordsize: 32 do
describe "with modifier '<' and '_'" do
it_behaves_like :array_pack_32bit_le, 'L<_'
it_behaves_like :array_pack_32bit_le, 'L_<'
@@ -51,7 +51,7 @@ describe "Array#pack with format 'L'" do
end
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
describe "with modifier '<' and '_'" do
it_behaves_like :array_pack_64bit_le, 'L<_'
it_behaves_like :array_pack_64bit_le, 'L_<'
@@ -83,7 +83,7 @@ describe "Array#pack with format 'l'" do
it_behaves_like :array_pack_32bit_be, 'l>'
end
- platform_is c_long_size: 32 do
+ platform_is wordsize: 32 do
describe "with modifier '<' and '_'" do
it_behaves_like :array_pack_32bit_le, 'l<_'
it_behaves_like :array_pack_32bit_le, 'l_<'
@@ -105,7 +105,7 @@ describe "Array#pack with format 'l'" do
end
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
describe "with modifier '<' and '_'" do
it_behaves_like :array_pack_64bit_le, 'l<_'
it_behaves_like :array_pack_64bit_le, 'l_<'
@@ -137,7 +137,7 @@ little_endian do
it_behaves_like :array_pack_32bit_le, 'l'
end
- platform_is c_long_size: 32 do
+ platform_is wordsize: 32 do
describe "Array#pack with format 'L' with modifier '_'" do
it_behaves_like :array_pack_32bit_le, 'L_'
end
@@ -155,7 +155,7 @@ little_endian do
end
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
describe "Array#pack with format 'L' with modifier '_'" do
it_behaves_like :array_pack_64bit_le, 'L_'
end
@@ -183,7 +183,7 @@ big_endian do
it_behaves_like :array_pack_32bit_be, 'l'
end
- platform_is c_long_size: 32 do
+ platform_is wordsize: 32 do
describe "Array#pack with format 'L' with modifier '_'" do
it_behaves_like :array_pack_32bit_be, 'L_'
end
@@ -201,7 +201,7 @@ big_endian do
end
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
describe "Array#pack with format 'L' with modifier '_'" do
it_behaves_like :array_pack_64bit_be, 'L_'
end
diff --git a/spec/ruby/core/array/pack/shared/basic.rb b/spec/ruby/core/array/pack/shared/basic.rb
index 5e3eea55f9..65fdaa45d8 100644
--- a/spec/ruby/core/array/pack/shared/basic.rb
+++ b/spec/ruby/core/array/pack/shared/basic.rb
@@ -31,7 +31,7 @@ describe :array_pack_basic_non_float, shared: true do
# 2 additional directives ('a') are required for the X directive
[@obj, @obj, @obj, @obj].pack("aa #{pack_format} # some comment \n#{pack_format}").should be_an_instance_of(String)
end
-
+
ruby_version_is ""..."3.2" do
it "warns in verbose mode that a directive is unknown" do
# additional directive ('a') is required for the X directive
diff --git a/spec/ruby/core/array/pack/shared/float.rb b/spec/ruby/core/array/pack/shared/float.rb
index 1780d7635e..9510cffed7 100644
--- a/spec/ruby/core/array/pack/shared/float.rb
+++ b/spec/ruby/core/array/pack/shared/float.rb
@@ -27,9 +27,7 @@ describe :array_pack_float_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A"
- end
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A"
end
end
@@ -107,9 +105,7 @@ describe :array_pack_float_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333"
- end
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333"
end
end
@@ -179,9 +175,7 @@ describe :array_pack_double_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@"
- end
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@"
end
end
@@ -250,9 +244,7 @@ describe :array_pack_double_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff"
- end
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff"
end
end
diff --git a/spec/ruby/core/array/pack/shared/integer.rb b/spec/ruby/core/array/pack/shared/integer.rb
index a89b5b733b..d3ce9b5792 100644
--- a/spec/ruby/core/array/pack/shared/integer.rb
+++ b/spec/ruby/core/array/pack/shared/integer.rb
@@ -43,10 +43,8 @@ describe :array_pack_16bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x78\x65\xcd\xab"
- end
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x78\x65\xcd\xab"
end
end
@@ -107,10 +105,8 @@ describe :array_pack_16bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x65\x78\xab\xcd"
- end
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x65\x78\xab\xcd"
end
end
@@ -171,10 +167,8 @@ describe :array_pack_32bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde"
- end
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde"
end
end
@@ -235,10 +229,8 @@ describe :array_pack_32bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd"
- end
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd"
end
end
@@ -273,7 +265,7 @@ describe :array_pack_32bit_le_platform, shared: true do
str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde\x21\x43\x65\x78"
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
it "encodes the least significant 32 bits of a number that is greater than 32 bits" do
[ [[0xff_7865_4321], "\x21\x43\x65\x78"],
[[-0xff_7865_4321], "\xdf\xbc\x9a\x87"]
@@ -299,7 +291,7 @@ describe :array_pack_32bit_be_platform, shared: true do
str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd\x78\x65\x43\x21"
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
it "encodes the least significant 32 bits of a number that is greater than 32 bits" do
[ [[0xff_7865_4321], "\x78\x65\x43\x21"],
[[-0xff_7865_4321], "\x87\x9a\xbc\xdf"]
@@ -359,10 +351,8 @@ describe :array_pack_64bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78"
- end
+ str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78"
end
end
@@ -431,10 +421,8 @@ describe :array_pack_64bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0"
- end
+ str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0"
end
end
diff --git a/spec/ruby/core/array/pack/shared/string.rb b/spec/ruby/core/array/pack/shared/string.rb
index 2f70dc3951..8c82e8c617 100644
--- a/spec/ruby/core/array/pack/shared/string.rb
+++ b/spec/ruby/core/array/pack/shared/string.rb
@@ -40,7 +40,7 @@ describe :array_pack_string, shared: true do
f = pack_format("*")
[ [["\u{3042 3044 3046 3048}", 0x2000B].pack(f+"U"), Encoding::BINARY],
[["abcde\xd1", "\xFF\xFe\x81\x82"].pack(f+"u"), Encoding::BINARY],
- [["a".dup.force_encoding("ascii"), "\xFF\xFe\x81\x82"].pack(f+"u"), Encoding::BINARY],
+ [["a".force_encoding("ascii"), "\xFF\xFe\x81\x82"].pack(f+"u"), Encoding::BINARY],
# under discussion [ruby-dev:37294]
[["\u{3042 3044 3046 3048}", 1].pack(f+"N"), Encoding::BINARY]
].should be_computed_by(:encoding)
diff --git a/spec/ruby/core/array/pack/shared/unicode.rb b/spec/ruby/core/array/pack/shared/unicode.rb
index 4d8eaef323..130c447bb7 100644
--- a/spec/ruby/core/array/pack/shared/unicode.rb
+++ b/spec/ruby/core/array/pack/shared/unicode.rb
@@ -69,9 +69,7 @@ describe :array_pack_unicode, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [1, 2, 3].pack("U\x00U").should == "\x01\x02"
- end
+ [1, 2, 3].pack("U\x00U").should == "\x01\x02"
end
end
diff --git a/spec/ruby/core/array/pack/w_spec.rb b/spec/ruby/core/array/pack/w_spec.rb
index 48ed4496a5..e241d1519c 100644
--- a/spec/ruby/core/array/pack/w_spec.rb
+++ b/spec/ruby/core/array/pack/w_spec.rb
@@ -26,9 +26,7 @@ describe "Array#pack with format 'w'" do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- [1, 2, 3].pack("w\x00w").should == "\x01\x02"
- end
+ [1, 2, 3].pack("w\x00w").should == "\x01\x02"
end
end
diff --git a/spec/ruby/core/array/plus_spec.rb b/spec/ruby/core/array/plus_spec.rb
index b7153fd3ef..3962b05c39 100644
--- a/spec/ruby/core/array/plus_spec.rb
+++ b/spec/ruby/core/array/plus_spec.rb
@@ -14,23 +14,10 @@ describe "Array#+" do
(ary + ary).should == [1, 2, 3, 1, 2, 3]
end
- describe "converts the passed argument to an Array using #to_ary" do
- it "successfully concatenates the resulting array from the #to_ary call" do
- obj = mock('["x", "y"]')
- obj.should_receive(:to_ary).and_return(["x", "y"])
- ([1, 2, 3] + obj).should == [1, 2, 3, "x", "y"]
- end
-
- it "raises a TypeError if the given argument can't be converted to an array" do
- -> { [1, 2, 3] + nil }.should raise_error(TypeError)
- -> { [1, 2, 3] + "abc" }.should raise_error(TypeError)
- end
-
- it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do
- obj = mock("hello")
- obj.should_receive(:to_ary).and_raise(NoMethodError)
- -> { [1, 2, 3] + obj }.should raise_error(NoMethodError)
- end
+ it "tries to convert the passed argument to an Array using #to_ary" do
+ obj = mock('["x", "y"]')
+ obj.should_receive(:to_ary).and_return(["x", "y"])
+ ([1, 2, 3] + obj).should == [1, 2, 3, "x", "y"]
end
it "properly handles recursive arrays" do
diff --git a/spec/ruby/core/array/product_spec.rb b/spec/ruby/core/array/product_spec.rb
index 6fb3818508..07d2880a96 100644
--- a/spec/ruby/core/array/product_spec.rb
+++ b/spec/ruby/core/array/product_spec.rb
@@ -9,11 +9,6 @@ describe "Array#product" do
ar.called.should == :to_ary
end
- it "returns converted arguments using :method_missing" do
- ar = ArraySpecs::ArrayMethodMissing.new(2,3)
- [1].product(ar).should == [[1,2],[1,3]]
- end
-
it "returns the expected result" do
[1,2].product([3,4,5],[6,8]).should == [[1, 3, 6], [1, 3, 8], [1, 4, 6], [1, 4, 8], [1, 5, 6], [1, 5, 8],
[2, 3, 6], [2, 3, 8], [2, 4, 6], [2, 4, 8], [2, 5, 6], [2, 5, 8]]
diff --git a/spec/ruby/core/array/rassoc_spec.rb b/spec/ruby/core/array/rassoc_spec.rb
index 632a05e8b3..62fbd40611 100644
--- a/spec/ruby/core/array/rassoc_spec.rb
+++ b/spec/ruby/core/array/rassoc_spec.rb
@@ -35,18 +35,4 @@ describe "Array#rassoc" do
[[1, :foobar, o], [2, o, 1], [3, mock('foo')]].rassoc(key).should == [2, o, 1]
end
-
- ruby_version_is "3.3" do
- it "calls to_ary on non-array elements" do
- s1 = [1, 2]
- s2 = ArraySpecs::ArrayConvertible.new(2, 3)
- a = [s1, s2]
-
- s1.should_not_receive(:to_ary)
- a.rassoc(2).should equal(s1)
-
- a.rassoc(3).should == [2, 3]
- s2.called.should equal(:to_ary)
- end
- end
end
diff --git a/spec/ruby/core/array/reject_spec.rb b/spec/ruby/core/array/reject_spec.rb
index 81a467e364..fcf43fabde 100644
--- a/spec/ruby/core/array/reject_spec.rb
+++ b/spec/ruby/core/array/reject_spec.rb
@@ -2,7 +2,6 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/enumeratorize'
require_relative 'shared/delete_if'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
require_relative '../enumerable/shared/enumeratorized'
describe "Array#reject" do
@@ -48,10 +47,6 @@ describe "Array#reject" do
it_behaves_like :enumeratorized_with_origin_size, :reject, [1,2,3]
end
-describe "Array#reject" do
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :reject
-end
-
describe "Array#reject!" do
it "removes elements for which block is true" do
a = [3, 4, 5, 6, 7, 8, 9, 10, 11]
@@ -116,11 +111,6 @@ describe "Array#reject!" do
-> { ArraySpecs.empty_frozen_array.reject! {} }.should raise_error(FrozenError)
end
- it "raises a FrozenError on a frozen array only during iteration if called without a block" do
- enum = ArraySpecs.frozen_array.reject!
- -> { enum.each {} }.should raise_error(FrozenError)
- end
-
it "does not truncate the array is the block raises an exception" do
a = [1, 2, 3]
begin
@@ -151,8 +141,3 @@ describe "Array#reject!" do
it_behaves_like :enumeratorized_with_origin_size, :reject!, [1,2,3]
it_behaves_like :delete_if, :reject!
end
-
-describe "Array#reject!" do
- @value_to_return = -> _ { false }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :reject!
-end
diff --git a/spec/ruby/core/array/reverse_each_spec.rb b/spec/ruby/core/array/reverse_each_spec.rb
index 59dabcd33d..28b8bfcb34 100644
--- a/spec/ruby/core/array/reverse_each_spec.rb
+++ b/spec/ruby/core/array/reverse_each_spec.rb
@@ -5,7 +5,7 @@ require_relative '../enumerable/shared/enumeratorized'
# Modifying a collection while the contents are being iterated
# gives undefined behavior. See
-# https://blade.ruby-lang.org/ruby-core/23633
+# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633
describe "Array#reverse_each" do
before :each do
@@ -38,20 +38,6 @@ describe "Array#reverse_each" do
[1, 2, 3].reverse_each.size.should == 3
end
- it "tolerates increasing an array size during iteration" do
- array = [:a, :b, :c]
- ScratchPad.record []
- i = 0
-
- array.reverse_each do |e|
- ScratchPad << e
- array.prepend i if i < 100
- i += 1
- end
-
- ScratchPad.recorded.should == [:c, :a, 1]
- end
-
it_behaves_like :enumeratorize, :reverse_each
it_behaves_like :enumeratorized_with_origin_size, :reverse_each, [1,2,3]
end
diff --git a/spec/ruby/core/array/rindex_spec.rb b/spec/ruby/core/array/rindex_spec.rb
index 13de88818c..175c7bcfe2 100644
--- a/spec/ruby/core/array/rindex_spec.rb
+++ b/spec/ruby/core/array/rindex_spec.rb
@@ -4,7 +4,7 @@ require_relative '../enumerable/shared/enumeratorized'
# Modifying a collection while the contents are being iterated
# gives undefined behavior. See
-# https://blade.ruby-lang.org/ruby-core/23633
+# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633
describe "Array#rindex" do
it "returns the first index backwards from the end where element == to object" do
@@ -68,21 +68,6 @@ describe "Array#rindex" do
seen.should == [3]
end
- it "tolerates increasing an array size during iteration" do
- array = [:a, :b, :c]
- ScratchPad.record []
- i = 0
-
- array.rindex do |e|
- ScratchPad << e
- array.prepend i if i < 100
- i += 1
- false
- end
-
- ScratchPad.recorded.should == [:c, :a, 1]
- end
-
describe "given no argument and no block" do
it "produces an Enumerator" do
enum = [4, 2, 1, 5, 1, 3].rindex
diff --git a/spec/ruby/core/array/sample_spec.rb b/spec/ruby/core/array/sample_spec.rb
index 6ef78594f0..5b3aac9aed 100644
--- a/spec/ruby/core/array/sample_spec.rb
+++ b/spec/ruby/core/array/sample_spec.rb
@@ -29,10 +29,6 @@ describe "Array#sample" do
[4].sample(random: Random.new(42)).should equal(4)
end
- it "returns a single value when not passed a count and a Random class is given" do
- [4].sample(random: Random).should equal(4)
- end
-
it "returns an empty Array when passed zero" do
[4].sample(0).should == []
end
diff --git a/spec/ruby/core/array/shared/collect.rb b/spec/ruby/core/array/shared/collect.rb
index 030302ced6..8d75f7db9a 100644
--- a/spec/ruby/core/array/shared/collect.rb
+++ b/spec/ruby/core/array/shared/collect.rb
@@ -1,5 +1,4 @@
require_relative '../../enumerable/shared/enumeratorized'
-require_relative '../shared/iterable_and_tolerating_size_increasing'
describe :array_collect, shared: true do
it "returns a copy of array with each element replaced by the value returned by block" do
@@ -47,8 +46,6 @@ describe :array_collect, shared: true do
@object = [1, 2, 3, 4]
end
it_should_behave_like :enumeratorized_with_origin_size
-
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
end
describe :array_collect_b, shared: true do
@@ -105,37 +102,8 @@ describe :array_collect_b, shared: true do
end
end
- it "does not truncate the array is the block raises an exception" do
- a = [1, 2, 3]
- begin
- a.send(@method) { raise StandardError, 'Oops' }
- rescue
- end
-
- a.should == [1, 2, 3]
- end
-
- it "only changes elements before error is raised, keeping the element which raised an error." do
- a = [1, 2, 3, 4]
- begin
- a.send(@method) do |e|
- case e
- when 1 then -1
- when 2 then -2
- when 3 then raise StandardError, 'Oops'
- else 0
- end
- end
- rescue StandardError
- end
-
- a.should == [-1, -2, 3, 4]
- end
-
before :all do
@object = [1, 2, 3, 4]
end
it_should_behave_like :enumeratorized_with_origin_size
-
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
end
diff --git a/spec/ruby/core/array/shared/index.rb b/spec/ruby/core/array/shared/index.rb
index a4a0adbab6..a9896554f2 100644
--- a/spec/ruby/core/array/shared/index.rb
+++ b/spec/ruby/core/array/shared/index.rb
@@ -1,5 +1,3 @@
-require_relative '../shared/iterable_and_tolerating_size_increasing'
-
describe :array_index, shared: true do
it "returns the index of the first element == to object" do
x = mock('3')
@@ -36,6 +34,4 @@ describe :array_index, shared: true do
[].send(@method).should be_an_instance_of(Enumerator)
end
end
-
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
end
diff --git a/spec/ruby/core/array/shared/inspect.rb b/spec/ruby/core/array/shared/inspect.rb
index af5128c645..a2b43d4959 100644
--- a/spec/ruby/core/array/shared/inspect.rb
+++ b/spec/ruby/core/array/shared/inspect.rb
@@ -19,7 +19,7 @@ describe :array_inspect, shared: true do
end
it "does not call #to_s on a String returned from #inspect" do
- str = +"abc"
+ str = "abc"
str.should_not_receive(:to_s)
[str].send(@method).should == '["abc"]'
@@ -98,8 +98,8 @@ describe :array_inspect, shared: true do
end
it "does not raise if inspected result is not default external encoding" do
- utf_16be = mock(+"utf_16be")
- utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode(Encoding::UTF_16BE))
+ utf_16be = mock("utf_16be")
+ utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode!(Encoding::UTF_16BE))
[utf_16be].send(@method).should == '["utf_16be \u3042"]'
end
diff --git a/spec/ruby/core/array/shared/intersection.rb b/spec/ruby/core/array/shared/intersection.rb
index 0b4166ab63..49849b08c2 100644
--- a/spec/ruby/core/array/shared/intersection.rb
+++ b/spec/ruby/core/array/shared/intersection.rb
@@ -11,8 +11,7 @@ describe :array_intersection, shared: true do
end
it "creates an array with elements in order they are first encountered" do
- [ 1, 2, 3, 2, 5, 6, 7, 8 ].send(@method, [ 5, 2, 3, 4 ]).should == [2, 3, 5] # array > other
- [ 5, 2, 3, 4 ].send(@method, [ 1, 2, 3, 2, 5, 6, 7, 8 ]).should == [5, 2, 3] # array < other
+ [ 1, 2, 3, 2, 5 ].send(@method, [ 5, 2, 3, 4 ]).should == [2, 3, 5]
end
it "does not modify the original Array" do
diff --git a/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb b/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb
deleted file mode 100644
index 3e73bad44b..0000000000
--- a/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-describe :array_iterable_and_tolerating_size_increasing, shared: true do
- before do
- @value_to_return ||= -> _ { nil }
- end
-
- it "tolerates increasing an array size during iteration" do
- # The goal is to trigger potential reallocation of internal array storage, so we:
- # - use elements of different types, starting with the less generic (Integer)
- # - add reasonably big number of new elements (~ 100)
- array = [1, 2, 3] # to test some methods we need several uniq elements
- array_to_join = [:a, :b, :c] + (4..100).to_a
-
- ScratchPad.record []
- i = 0
-
- array.send(@method) do |e|
- ScratchPad << e
- array << array_to_join[i] if i < array_to_join.size
- i += 1
- @value_to_return.call(e)
- end
-
- ScratchPad.recorded.should == [1, 2, 3] + array_to_join
- end
-end
diff --git a/spec/ruby/core/array/shared/keep_if.rb b/spec/ruby/core/array/shared/keep_if.rb
index 43a047c0a7..f26aff028c 100644
--- a/spec/ruby/core/array/shared/keep_if.rb
+++ b/spec/ruby/core/array/shared/keep_if.rb
@@ -1,5 +1,4 @@
require_relative '../../enumerable/shared/enumeratorized'
-require_relative '../shared/iterable_and_tolerating_size_increasing'
describe :keep_if, shared: true do
it "deletes elements for which the block returns a false value" do
@@ -57,39 +56,5 @@ describe :keep_if, shared: true do
-> { @frozen.send(@method) { false } }.should raise_error(FrozenError)
end
end
-
- it "raises a FrozenError on a frozen array only during iteration if called without a block" do
- enum = @frozen.send(@method)
- -> { enum.each {} }.should raise_error(FrozenError)
- end
- end
-
- it "does not truncate the array is the block raises an exception" do
- a = [1, 2, 3]
- begin
- a.send(@method) { raise StandardError, 'Oops' }
- rescue
- end
-
- a.should == [1, 2, 3]
end
-
- it "only changes elements before error is raised, keeping the element which raised an error." do
- a = [1, 2, 3, 4]
- begin
- a.send(@method) do |e|
- case e
- when 2 then false
- when 3 then raise StandardError, 'Oops'
- else true
- end
- end
- rescue StandardError
- end
-
- a.should == [1, 3, 4]
- end
-
- @value_to_return = -> _ { true }
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
end
diff --git a/spec/ruby/core/array/shared/select.rb b/spec/ruby/core/array/shared/select.rb
index 9c2cbf76c4..09101e8ab5 100644
--- a/spec/ruby/core/array/shared/select.rb
+++ b/spec/ruby/core/array/shared/select.rb
@@ -2,14 +2,11 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/enumeratorize'
require_relative '../shared/keep_if'
-require_relative '../shared/iterable_and_tolerating_size_increasing'
require_relative '../../enumerable/shared/enumeratorized'
describe :array_select, shared: true do
it_should_behave_like :enumeratorize
- it_should_behave_like :array_iterable_and_tolerating_size_increasing
-
before :each do
@object = [1,2,3]
end
diff --git a/spec/ruby/core/array/shared/slice.rb b/spec/ruby/core/array/shared/slice.rb
index d2866970a5..8fb33738b9 100644
--- a/spec/ruby/core/array/shared/slice.rb
+++ b/spec/ruby/core/array/shared/slice.rb
@@ -397,28 +397,56 @@ describe :array_slice, shared: true do
@array = ArraySpecs::MyArray[1, 2, 3, 4, 5]
end
- it "returns a Array instance with [n, m]" do
- @array.send(@method, 0, 2).should be_an_instance_of(Array)
- end
+ ruby_version_is ''...'3.0' do
+ it "returns a subclass instance with [n, m]" do
+ @array.send(@method, 0, 2).should be_an_instance_of(ArraySpecs::MyArray)
+ end
- it "returns a Array instance with [-n, m]" do
- @array.send(@method, -3, 2).should be_an_instance_of(Array)
- end
+ it "returns a subclass instance with [-n, m]" do
+ @array.send(@method, -3, 2).should be_an_instance_of(ArraySpecs::MyArray)
+ end
- it "returns a Array instance with [n..m]" do
- @array.send(@method, 1..3).should be_an_instance_of(Array)
- end
+ it "returns a subclass instance with [n..m]" do
+ @array.send(@method, 1..3).should be_an_instance_of(ArraySpecs::MyArray)
+ end
- it "returns a Array instance with [n...m]" do
- @array.send(@method, 1...3).should be_an_instance_of(Array)
- end
+ it "returns a subclass instance with [n...m]" do
+ @array.send(@method, 1...3).should be_an_instance_of(ArraySpecs::MyArray)
+ end
- it "returns a Array instance with [-n..-m]" do
- @array.send(@method, -3..-1).should be_an_instance_of(Array)
+ it "returns a subclass instance with [-n..-m]" do
+ @array.send(@method, -3..-1).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+
+ it "returns a subclass instance with [-n...-m]" do
+ @array.send(@method, -3...-1).should be_an_instance_of(ArraySpecs::MyArray)
+ end
end
- it "returns a Array instance with [-n...-m]" do
- @array.send(@method, -3...-1).should be_an_instance_of(Array)
+ ruby_version_is '3.0' do
+ it "returns a Array instance with [n, m]" do
+ @array.send(@method, 0, 2).should be_an_instance_of(Array)
+ end
+
+ it "returns a Array instance with [-n, m]" do
+ @array.send(@method, -3, 2).should be_an_instance_of(Array)
+ end
+
+ it "returns a Array instance with [n..m]" do
+ @array.send(@method, 1..3).should be_an_instance_of(Array)
+ end
+
+ it "returns a Array instance with [n...m]" do
+ @array.send(@method, 1...3).should be_an_instance_of(Array)
+ end
+
+ it "returns a Array instance with [-n..-m]" do
+ @array.send(@method, -3..-1).should be_an_instance_of(Array)
+ end
+
+ it "returns a Array instance with [-n...-m]" do
+ @array.send(@method, -3...-1).should be_an_instance_of(Array)
+ end
end
it "returns an empty array when m == n with [m...n]" do
@@ -506,237 +534,239 @@ describe :array_slice, shared: true do
a.send(@method, eval("(-9...)")).should == nil
end
- describe "can be sliced with Enumerator::ArithmeticSequence" do
- before :each do
- @array = [0, 1, 2, 3, 4, 5]
- end
+ ruby_version_is "3.0" do
+ describe "can be sliced with Enumerator::ArithmeticSequence" do
+ before :each do
+ @array = [0, 1, 2, 3, 4, 5]
+ end
- it "has endless range and positive steps" do
- @array.send(@method, eval("(0..).step(1)")).should == [0, 1, 2, 3, 4, 5]
- @array.send(@method, eval("(0..).step(2)")).should == [0, 2, 4]
- @array.send(@method, eval("(0..).step(10)")).should == [0]
+ it "has endless range and positive steps" do
+ @array.send(@method, eval("(0..).step(1)")).should == [0, 1, 2, 3, 4, 5]
+ @array.send(@method, eval("(0..).step(2)")).should == [0, 2, 4]
+ @array.send(@method, eval("(0..).step(10)")).should == [0]
- @array.send(@method, eval("(2..).step(1)")).should == [2, 3, 4, 5]
- @array.send(@method, eval("(2..).step(2)")).should == [2, 4]
- @array.send(@method, eval("(2..).step(10)")).should == [2]
+ @array.send(@method, eval("(2..).step(1)")).should == [2, 3, 4, 5]
+ @array.send(@method, eval("(2..).step(2)")).should == [2, 4]
+ @array.send(@method, eval("(2..).step(10)")).should == [2]
- @array.send(@method, eval("(-3..).step(1)")).should == [3, 4, 5]
- @array.send(@method, eval("(-3..).step(2)")).should == [3, 5]
- @array.send(@method, eval("(-3..).step(10)")).should == [3]
- end
+ @array.send(@method, eval("(-3..).step(1)")).should == [3, 4, 5]
+ @array.send(@method, eval("(-3..).step(2)")).should == [3, 5]
+ @array.send(@method, eval("(-3..).step(10)")).should == [3]
+ end
- it "has beginless range and positive steps" do
- # end with zero index
- @array.send(@method, (..0).step(1)).should == [0]
- @array.send(@method, (...0).step(1)).should == []
+ it "has beginless range and positive steps" do
+ # end with zero index
+ @array.send(@method, (..0).step(1)).should == [0]
+ @array.send(@method, (...0).step(1)).should == []
- @array.send(@method, (..0).step(2)).should == [0]
- @array.send(@method, (...0).step(2)).should == []
+ @array.send(@method, (..0).step(2)).should == [0]
+ @array.send(@method, (...0).step(2)).should == []
- @array.send(@method, (..0).step(10)).should == [0]
- @array.send(@method, (...0).step(10)).should == []
+ @array.send(@method, (..0).step(10)).should == [0]
+ @array.send(@method, (...0).step(10)).should == []
- # end with positive index
- @array.send(@method, (..3).step(1)).should == [0, 1, 2, 3]
- @array.send(@method, (...3).step(1)).should == [0, 1, 2]
+ # end with positive index
+ @array.send(@method, (..3).step(1)).should == [0, 1, 2, 3]
+ @array.send(@method, (...3).step(1)).should == [0, 1, 2]
- @array.send(@method, (..3).step(2)).should == [0, 2]
- @array.send(@method, (...3).step(2)).should == [0, 2]
+ @array.send(@method, (..3).step(2)).should == [0, 2]
+ @array.send(@method, (...3).step(2)).should == [0, 2]
- @array.send(@method, (..3).step(10)).should == [0]
- @array.send(@method, (...3).step(10)).should == [0]
+ @array.send(@method, (..3).step(10)).should == [0]
+ @array.send(@method, (...3).step(10)).should == [0]
- # end with negative index
- @array.send(@method, (..-2).step(1)).should == [0, 1, 2, 3, 4,]
- @array.send(@method, (...-2).step(1)).should == [0, 1, 2, 3]
+ # end with negative index
+ @array.send(@method, (..-2).step(1)).should == [0, 1, 2, 3, 4,]
+ @array.send(@method, (...-2).step(1)).should == [0, 1, 2, 3]
- @array.send(@method, (..-2).step(2)).should == [0, 2, 4]
- @array.send(@method, (...-2).step(2)).should == [0, 2]
+ @array.send(@method, (..-2).step(2)).should == [0, 2, 4]
+ @array.send(@method, (...-2).step(2)).should == [0, 2]
- @array.send(@method, (..-2).step(10)).should == [0]
- @array.send(@method, (...-2).step(10)).should == [0]
- end
+ @array.send(@method, (..-2).step(10)).should == [0]
+ @array.send(@method, (...-2).step(10)).should == [0]
+ end
- it "has endless range and negative steps" do
- @array.send(@method, eval("(0..).step(-1)")).should == [0]
- @array.send(@method, eval("(0..).step(-2)")).should == [0]
- @array.send(@method, eval("(0..).step(-10)")).should == [0]
+ it "has endless range and negative steps" do
+ @array.send(@method, eval("(0..).step(-1)")).should == [0]
+ @array.send(@method, eval("(0..).step(-2)")).should == [0]
+ @array.send(@method, eval("(0..).step(-10)")).should == [0]
- @array.send(@method, eval("(2..).step(-1)")).should == [2, 1, 0]
- @array.send(@method, eval("(2..).step(-2)")).should == [2, 0]
+ @array.send(@method, eval("(2..).step(-1)")).should == [2, 1, 0]
+ @array.send(@method, eval("(2..).step(-2)")).should == [2, 0]
- @array.send(@method, eval("(-3..).step(-1)")).should == [3, 2, 1, 0]
- @array.send(@method, eval("(-3..).step(-2)")).should == [3, 1]
- end
+ @array.send(@method, eval("(-3..).step(-1)")).should == [3, 2, 1, 0]
+ @array.send(@method, eval("(-3..).step(-2)")).should == [3, 1]
+ end
- it "has closed range and positive steps" do
- # start and end with 0
- @array.send(@method, eval("(0..0).step(1)")).should == [0]
- @array.send(@method, eval("(0...0).step(1)")).should == []
+ it "has closed range and positive steps" do
+ # start and end with 0
+ @array.send(@method, eval("(0..0).step(1)")).should == [0]
+ @array.send(@method, eval("(0...0).step(1)")).should == []
- @array.send(@method, eval("(0..0).step(2)")).should == [0]
- @array.send(@method, eval("(0...0).step(2)")).should == []
+ @array.send(@method, eval("(0..0).step(2)")).should == [0]
+ @array.send(@method, eval("(0...0).step(2)")).should == []
- @array.send(@method, eval("(0..0).step(10)")).should == [0]
- @array.send(@method, eval("(0...0).step(10)")).should == []
+ @array.send(@method, eval("(0..0).step(10)")).should == [0]
+ @array.send(@method, eval("(0...0).step(10)")).should == []
- # start and end with positive index
- @array.send(@method, eval("(1..3).step(1)")).should == [1, 2, 3]
- @array.send(@method, eval("(1...3).step(1)")).should == [1, 2]
+ # start and end with positive index
+ @array.send(@method, eval("(1..3).step(1)")).should == [1, 2, 3]
+ @array.send(@method, eval("(1...3).step(1)")).should == [1, 2]
- @array.send(@method, eval("(1..3).step(2)")).should == [1, 3]
- @array.send(@method, eval("(1...3).step(2)")).should == [1]
+ @array.send(@method, eval("(1..3).step(2)")).should == [1, 3]
+ @array.send(@method, eval("(1...3).step(2)")).should == [1]
- @array.send(@method, eval("(1..3).step(10)")).should == [1]
- @array.send(@method, eval("(1...3).step(10)")).should == [1]
+ @array.send(@method, eval("(1..3).step(10)")).should == [1]
+ @array.send(@method, eval("(1...3).step(10)")).should == [1]
- # start with positive index, end with negative index
- @array.send(@method, eval("(1..-2).step(1)")).should == [1, 2, 3, 4]
- @array.send(@method, eval("(1...-2).step(1)")).should == [1, 2, 3]
+ # start with positive index, end with negative index
+ @array.send(@method, eval("(1..-2).step(1)")).should == [1, 2, 3, 4]
+ @array.send(@method, eval("(1...-2).step(1)")).should == [1, 2, 3]
- @array.send(@method, eval("(1..-2).step(2)")).should == [1, 3]
- @array.send(@method, eval("(1...-2).step(2)")).should == [1, 3]
+ @array.send(@method, eval("(1..-2).step(2)")).should == [1, 3]
+ @array.send(@method, eval("(1...-2).step(2)")).should == [1, 3]
- @array.send(@method, eval("(1..-2).step(10)")).should == [1]
- @array.send(@method, eval("(1...-2).step(10)")).should == [1]
+ @array.send(@method, eval("(1..-2).step(10)")).should == [1]
+ @array.send(@method, eval("(1...-2).step(10)")).should == [1]
- # start with negative index, end with positive index
- @array.send(@method, eval("(-4..4).step(1)")).should == [2, 3, 4]
- @array.send(@method, eval("(-4...4).step(1)")).should == [2, 3]
+ # start with negative index, end with positive index
+ @array.send(@method, eval("(-4..4).step(1)")).should == [2, 3, 4]
+ @array.send(@method, eval("(-4...4).step(1)")).should == [2, 3]
- @array.send(@method, eval("(-4..4).step(2)")).should == [2, 4]
- @array.send(@method, eval("(-4...4).step(2)")).should == [2]
+ @array.send(@method, eval("(-4..4).step(2)")).should == [2, 4]
+ @array.send(@method, eval("(-4...4).step(2)")).should == [2]
- @array.send(@method, eval("(-4..4).step(10)")).should == [2]
- @array.send(@method, eval("(-4...4).step(10)")).should == [2]
+ @array.send(@method, eval("(-4..4).step(10)")).should == [2]
+ @array.send(@method, eval("(-4...4).step(10)")).should == [2]
- # start with negative index, end with negative index
- @array.send(@method, eval("(-4..-2).step(1)")).should == [2, 3, 4]
- @array.send(@method, eval("(-4...-2).step(1)")).should == [2, 3]
+ # start with negative index, end with negative index
+ @array.send(@method, eval("(-4..-2).step(1)")).should == [2, 3, 4]
+ @array.send(@method, eval("(-4...-2).step(1)")).should == [2, 3]
- @array.send(@method, eval("(-4..-2).step(2)")).should == [2, 4]
- @array.send(@method, eval("(-4...-2).step(2)")).should == [2]
+ @array.send(@method, eval("(-4..-2).step(2)")).should == [2, 4]
+ @array.send(@method, eval("(-4...-2).step(2)")).should == [2]
- @array.send(@method, eval("(-4..-2).step(10)")).should == [2]
- @array.send(@method, eval("(-4...-2).step(10)")).should == [2]
- end
+ @array.send(@method, eval("(-4..-2).step(10)")).should == [2]
+ @array.send(@method, eval("(-4...-2).step(10)")).should == [2]
+ end
- it "has closed range and negative steps" do
- # start and end with 0
- @array.send(@method, eval("(0..0).step(-1)")).should == [0]
- @array.send(@method, eval("(0...0).step(-1)")).should == []
+ it "has closed range and negative steps" do
+ # start and end with 0
+ @array.send(@method, eval("(0..0).step(-1)")).should == [0]
+ @array.send(@method, eval("(0...0).step(-1)")).should == []
- @array.send(@method, eval("(0..0).step(-2)")).should == [0]
- @array.send(@method, eval("(0...0).step(-2)")).should == []
+ @array.send(@method, eval("(0..0).step(-2)")).should == [0]
+ @array.send(@method, eval("(0...0).step(-2)")).should == []
- @array.send(@method, eval("(0..0).step(-10)")).should == [0]
- @array.send(@method, eval("(0...0).step(-10)")).should == []
+ @array.send(@method, eval("(0..0).step(-10)")).should == [0]
+ @array.send(@method, eval("(0...0).step(-10)")).should == []
- # start and end with positive index
- @array.send(@method, eval("(1..3).step(-1)")).should == []
- @array.send(@method, eval("(1...3).step(-1)")).should == []
+ # start and end with positive index
+ @array.send(@method, eval("(1..3).step(-1)")).should == []
+ @array.send(@method, eval("(1...3).step(-1)")).should == []
- @array.send(@method, eval("(1..3).step(-2)")).should == []
- @array.send(@method, eval("(1...3).step(-2)")).should == []
+ @array.send(@method, eval("(1..3).step(-2)")).should == []
+ @array.send(@method, eval("(1...3).step(-2)")).should == []
- @array.send(@method, eval("(1..3).step(-10)")).should == []
- @array.send(@method, eval("(1...3).step(-10)")).should == []
+ @array.send(@method, eval("(1..3).step(-10)")).should == []
+ @array.send(@method, eval("(1...3).step(-10)")).should == []
- # start with positive index, end with negative index
- @array.send(@method, eval("(1..-2).step(-1)")).should == []
- @array.send(@method, eval("(1...-2).step(-1)")).should == []
+ # start with positive index, end with negative index
+ @array.send(@method, eval("(1..-2).step(-1)")).should == []
+ @array.send(@method, eval("(1...-2).step(-1)")).should == []
- @array.send(@method, eval("(1..-2).step(-2)")).should == []
- @array.send(@method, eval("(1...-2).step(-2)")).should == []
+ @array.send(@method, eval("(1..-2).step(-2)")).should == []
+ @array.send(@method, eval("(1...-2).step(-2)")).should == []
- @array.send(@method, eval("(1..-2).step(-10)")).should == []
- @array.send(@method, eval("(1...-2).step(-10)")).should == []
+ @array.send(@method, eval("(1..-2).step(-10)")).should == []
+ @array.send(@method, eval("(1...-2).step(-10)")).should == []
- # start with negative index, end with positive index
- @array.send(@method, eval("(-4..4).step(-1)")).should == []
- @array.send(@method, eval("(-4...4).step(-1)")).should == []
+ # start with negative index, end with positive index
+ @array.send(@method, eval("(-4..4).step(-1)")).should == []
+ @array.send(@method, eval("(-4...4).step(-1)")).should == []
- @array.send(@method, eval("(-4..4).step(-2)")).should == []
- @array.send(@method, eval("(-4...4).step(-2)")).should == []
+ @array.send(@method, eval("(-4..4).step(-2)")).should == []
+ @array.send(@method, eval("(-4...4).step(-2)")).should == []
- @array.send(@method, eval("(-4..4).step(-10)")).should == []
- @array.send(@method, eval("(-4...4).step(-10)")).should == []
+ @array.send(@method, eval("(-4..4).step(-10)")).should == []
+ @array.send(@method, eval("(-4...4).step(-10)")).should == []
- # start with negative index, end with negative index
- @array.send(@method, eval("(-4..-2).step(-1)")).should == []
- @array.send(@method, eval("(-4...-2).step(-1)")).should == []
+ # start with negative index, end with negative index
+ @array.send(@method, eval("(-4..-2).step(-1)")).should == []
+ @array.send(@method, eval("(-4...-2).step(-1)")).should == []
- @array.send(@method, eval("(-4..-2).step(-2)")).should == []
- @array.send(@method, eval("(-4...-2).step(-2)")).should == []
+ @array.send(@method, eval("(-4..-2).step(-2)")).should == []
+ @array.send(@method, eval("(-4...-2).step(-2)")).should == []
- @array.send(@method, eval("(-4..-2).step(-10)")).should == []
- @array.send(@method, eval("(-4...-2).step(-10)")).should == []
- end
+ @array.send(@method, eval("(-4..-2).step(-10)")).should == []
+ @array.send(@method, eval("(-4...-2).step(-10)")).should == []
+ end
- it "has inverted closed range and positive steps" do
- # start and end with positive index
- @array.send(@method, eval("(3..1).step(1)")).should == []
- @array.send(@method, eval("(3...1).step(1)")).should == []
+ it "has inverted closed range and positive steps" do
+ # start and end with positive index
+ @array.send(@method, eval("(3..1).step(1)")).should == []
+ @array.send(@method, eval("(3...1).step(1)")).should == []
- @array.send(@method, eval("(3..1).step(2)")).should == []
- @array.send(@method, eval("(3...1).step(2)")).should == []
+ @array.send(@method, eval("(3..1).step(2)")).should == []
+ @array.send(@method, eval("(3...1).step(2)")).should == []
- @array.send(@method, eval("(3..1).step(10)")).should == []
- @array.send(@method, eval("(3...1).step(10)")).should == []
+ @array.send(@method, eval("(3..1).step(10)")).should == []
+ @array.send(@method, eval("(3...1).step(10)")).should == []
- # start with negative index, end with positive index
- @array.send(@method, eval("(-2..1).step(1)")).should == []
- @array.send(@method, eval("(-2...1).step(1)")).should == []
+ # start with negative index, end with positive index
+ @array.send(@method, eval("(-2..1).step(1)")).should == []
+ @array.send(@method, eval("(-2...1).step(1)")).should == []
- @array.send(@method, eval("(-2..1).step(2)")).should == []
- @array.send(@method, eval("(-2...1).step(2)")).should == []
+ @array.send(@method, eval("(-2..1).step(2)")).should == []
+ @array.send(@method, eval("(-2...1).step(2)")).should == []
- @array.send(@method, eval("(-2..1).step(10)")).should == []
- @array.send(@method, eval("(-2...1).step(10)")).should == []
+ @array.send(@method, eval("(-2..1).step(10)")).should == []
+ @array.send(@method, eval("(-2...1).step(10)")).should == []
- # start with positive index, end with negative index
- @array.send(@method, eval("(4..-4).step(1)")).should == []
- @array.send(@method, eval("(4...-4).step(1)")).should == []
+ # start with positive index, end with negative index
+ @array.send(@method, eval("(4..-4).step(1)")).should == []
+ @array.send(@method, eval("(4...-4).step(1)")).should == []
- @array.send(@method, eval("(4..-4).step(2)")).should == []
- @array.send(@method, eval("(4...-4).step(2)")).should == []
+ @array.send(@method, eval("(4..-4).step(2)")).should == []
+ @array.send(@method, eval("(4...-4).step(2)")).should == []
- @array.send(@method, eval("(4..-4).step(10)")).should == []
- @array.send(@method, eval("(4...-4).step(10)")).should == []
+ @array.send(@method, eval("(4..-4).step(10)")).should == []
+ @array.send(@method, eval("(4...-4).step(10)")).should == []
- # start with negative index, end with negative index
- @array.send(@method, eval("(-2..-4).step(1)")).should == []
- @array.send(@method, eval("(-2...-4).step(1)")).should == []
+ # start with negative index, end with negative index
+ @array.send(@method, eval("(-2..-4).step(1)")).should == []
+ @array.send(@method, eval("(-2...-4).step(1)")).should == []
- @array.send(@method, eval("(-2..-4).step(2)")).should == []
- @array.send(@method, eval("(-2...-4).step(2)")).should == []
+ @array.send(@method, eval("(-2..-4).step(2)")).should == []
+ @array.send(@method, eval("(-2...-4).step(2)")).should == []
- @array.send(@method, eval("(-2..-4).step(10)")).should == []
- @array.send(@method, eval("(-2...-4).step(10)")).should == []
- end
+ @array.send(@method, eval("(-2..-4).step(10)")).should == []
+ @array.send(@method, eval("(-2...-4).step(10)")).should == []
+ end
- it "has range with bounds outside of array" do
- # end is equal to array's length
- @array.send(@method, (0..6).step(1)).should == [0, 1, 2, 3, 4, 5]
- -> { @array.send(@method, (0..6).step(2)) }.should raise_error(RangeError)
+ it "has range with bounds outside of array" do
+ # end is equal to array's length
+ @array.send(@method, (0..6).step(1)).should == [0, 1, 2, 3, 4, 5]
+ -> { @array.send(@method, (0..6).step(2)) }.should raise_error(RangeError)
- # end is greater than length with positive steps
- @array.send(@method, (1..6).step(2)).should == [1, 3, 5]
- @array.send(@method, (2..7).step(2)).should == [2, 4]
- -> { @array.send(@method, (2..8).step(2)) }.should raise_error(RangeError)
+ # end is greater than length with positive steps
+ @array.send(@method, (1..6).step(2)).should == [1, 3, 5]
+ @array.send(@method, (2..7).step(2)).should == [2, 4]
+ -> { @array.send(@method, (2..8).step(2)) }.should raise_error(RangeError)
- # begin is greater than length with negative steps
- @array.send(@method, (6..1).step(-2)).should == [5, 3, 1]
- @array.send(@method, (7..2).step(-2)).should == [5, 3]
- -> { @array.send(@method, (8..2).step(-2)) }.should raise_error(RangeError)
- end
+ # begin is greater than length with negative steps
+ @array.send(@method, (6..1).step(-2)).should == [5, 3, 1]
+ @array.send(@method, (7..2).step(-2)).should == [5, 3]
+ -> { @array.send(@method, (8..2).step(-2)) }.should raise_error(RangeError)
+ end
- it "has endless range with start outside of array's bounds" do
- @array.send(@method, eval("(6..).step(1)")).should == []
- @array.send(@method, eval("(7..).step(1)")).should == nil
+ it "has endless range with start outside of array's bounds" do
+ @array.send(@method, eval("(6..).step(1)")).should == []
+ @array.send(@method, eval("(7..).step(1)")).should == nil
- @array.send(@method, eval("(6..).step(2)")).should == []
- -> { @array.send(@method, eval("(7..).step(2)")) }.should raise_error(RangeError)
+ @array.send(@method, eval("(6..).step(2)")).should == []
+ -> { @array.send(@method, eval("(7..).step(2)")) }.should raise_error(RangeError)
+ end
end
end
diff --git a/spec/ruby/core/array/shuffle_spec.rb b/spec/ruby/core/array/shuffle_spec.rb
index 1d528c124f..b255147c75 100644
--- a/spec/ruby/core/array/shuffle_spec.rb
+++ b/spec/ruby/core/array/shuffle_spec.rb
@@ -47,10 +47,6 @@ describe "Array#shuffle" do
[1, 2].shuffle(random: random).should be_an_instance_of(Array)
end
- it "accepts a Random class for the value for random: argument" do
- [1, 2].shuffle(random: Random).should be_an_instance_of(Array)
- end
-
it "calls #to_int on the Object returned by #rand" do
value = mock("array_shuffle_random_value")
value.should_receive(:to_int).at_least(1).times.and_return(0)
@@ -97,14 +93,4 @@ describe "Array#shuffle!" do
-> { ArraySpecs.frozen_array.shuffle! }.should raise_error(FrozenError)
-> { ArraySpecs.empty_frozen_array.shuffle! }.should raise_error(FrozenError)
end
-
- it "matches CRuby with random:" do
- %w[a b c].shuffle(random: Random.new(1)).should == %w[a c b]
- (0..10).to_a.shuffle(random: Random.new(10)).should == [2, 6, 8, 5, 7, 10, 3, 1, 0, 4, 9]
- end
-
- it "matches CRuby with srand" do
- srand(123)
- %w[a b c d e f g h i j k].shuffle.should == %w[a e f h i j d b g k c]
- end
end
diff --git a/spec/ruby/core/array/slice_spec.rb b/spec/ruby/core/array/slice_spec.rb
index 731c129251..8e1499855a 100644
--- a/spec/ruby/core/array/slice_spec.rb
+++ b/spec/ruby/core/array/slice_spec.rb
@@ -187,28 +187,56 @@ describe "Array#slice!" do
@array = ArraySpecs::MyArray[1, 2, 3, 4, 5]
end
- it "returns a Array instance with [n, m]" do
- @array.slice!(0, 2).should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it "returns a subclass instance with [n, m]" do
+ @array.slice!(0, 2).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+
+ it "returns a subclass instance with [-n, m]" do
+ @array.slice!(-3, 2).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+
+ it "returns a subclass instance with [n..m]" do
+ @array.slice!(1..3).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+
+ it "returns a subclass instance with [n...m]" do
+ @array.slice!(1...3).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+
+ it "returns a subclass instance with [-n..-m]" do
+ @array.slice!(-3..-1).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+
+ it "returns a subclass instance with [-n...-m]" do
+ @array.slice!(-3...-1).should be_an_instance_of(ArraySpecs::MyArray)
+ end
end
- it "returns a Array instance with [-n, m]" do
- @array.slice!(-3, 2).should be_an_instance_of(Array)
- end
+ ruby_version_is '3.0' do
+ it "returns a Array instance with [n, m]" do
+ @array.slice!(0, 2).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [n..m]" do
- @array.slice!(1..3).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [-n, m]" do
+ @array.slice!(-3, 2).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [n...m]" do
- @array.slice!(1...3).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [n..m]" do
+ @array.slice!(1..3).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [-n..-m]" do
- @array.slice!(-3..-1).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [n...m]" do
+ @array.slice!(1...3).should be_an_instance_of(Array)
+ end
+
+ it "returns a Array instance with [-n..-m]" do
+ @array.slice!(-3..-1).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [-n...-m]" do
- @array.slice!(-3...-1).should be_an_instance_of(Array)
+ it "returns a Array instance with [-n...-m]" do
+ @array.slice!(-3...-1).should be_an_instance_of(Array)
+ end
end
end
end
diff --git a/spec/ruby/core/array/sort_by_spec.rb b/spec/ruby/core/array/sort_by_spec.rb
index 0334f953f6..7cea6ec6d3 100644
--- a/spec/ruby/core/array/sort_by_spec.rb
+++ b/spec/ruby/core/array/sort_by_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
require_relative '../enumerable/shared/enumeratorized'
describe "Array#sort_by!" do
@@ -32,11 +31,6 @@ describe "Array#sort_by!" do
-> { ArraySpecs.empty_frozen_array.sort_by! {}}.should raise_error(FrozenError)
end
- it "raises a FrozenError on a frozen array only during iteration if called without a block" do
- enum = ArraySpecs.frozen_array.sort_by!
- -> { enum.each {} }.should raise_error(FrozenError)
- end
-
it "returns the specified value when it would break in the given block" do
[1, 2, 3].sort_by!{ break :a }.should == :a
end
@@ -54,32 +48,5 @@ describe "Array#sort_by!" do
[1].sort_by!(&:to_s).should == [1]
end
- it "does not truncate the array is the block raises an exception" do
- a = [1, 2, 3]
- begin
- a.sort_by! { raise StandardError, 'Oops' }
- rescue
- end
-
- a.should == [1, 2, 3]
- end
-
- it "doesn't change array if error is raised" do
- a = [4, 3, 2, 1]
- begin
- a.sort_by! do |e|
- raise StandardError, 'Oops' if e == 1
- e
- end
- rescue StandardError
- end
-
- a.should == [4, 3, 2, 1]
- end
-
it_behaves_like :enumeratorized_with_origin_size, :sort_by!, [1,2,3]
end
-
-describe "Array#sort_by!" do
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :sort_by!
-end
diff --git a/spec/ruby/core/array/sum_spec.rb b/spec/ruby/core/array/sum_spec.rb
index 06abe06135..8ca8353a67 100644
--- a/spec/ruby/core/array/sum_spec.rb
+++ b/spec/ruby/core/array/sum_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#sum" do
it "returns the sum of elements" do
@@ -10,12 +9,8 @@ describe "Array#sum" do
[1, 2, 3].sum { |i| i * 10 }.should == 60
end
- it "doesn't apply the block init" do
- [1, 2, 3].sum(1) { |i| i * 10 }.should == 61
- end
-
# https://bugs.ruby-lang.org/issues/12217
- # https://github.com/ruby/ruby/blob/master/doc/ChangeLog/ChangeLog-2.4.0#L6208-L6214
+ # https://github.com/ruby/ruby/blob/master/doc/ChangeLog-2.4.0#L6208-L6214
it "uses Kahan's compensated summation algorithm for precise sum of float numbers" do
floats = [2.7800000000000002, 5.0, 2.5, 4.44, 3.89, 3.89, 4.44, 7.78, 5.0, 2.7800000000000002, 5.0, 2.5]
naive_sum = floats.reduce { |sum, e| sum + e }
@@ -73,18 +68,4 @@ describe "Array#sum" do
a.should_receive(:+).with(b).and_return(42)
[b].sum(a).should == 42
end
-
- ruby_bug '#19530', ''...'3.3' do
- it "calls + on the init value" do
- a = mock("a")
- b = mock("b")
- a.should_receive(:+).with(42).and_return(b)
- [42].sum(a).should == b
- end
- end
-end
-
-describe "Array#sum" do
- @value_to_return = -> _ { 1 }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :sum
end
diff --git a/spec/ruby/core/array/take_spec.rb b/spec/ruby/core/array/take_spec.rb
index c4f0ac9aa4..4fb6f0ce75 100644
--- a/spec/ruby/core/array/take_spec.rb
+++ b/spec/ruby/core/array/take_spec.rb
@@ -26,7 +26,15 @@ describe "Array#take" do
->{ [1].take(-3) }.should raise_error(ArgumentError)
end
- it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it 'returns a subclass instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(ArraySpecs::MyArray)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it 'returns a Array instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(Array)
+ end
end
end
diff --git a/spec/ruby/core/array/take_while_spec.rb b/spec/ruby/core/array/take_while_spec.rb
index 8f50260b42..363419b265 100644
--- a/spec/ruby/core/array/take_while_spec.rb
+++ b/spec/ruby/core/array/take_while_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#take_while" do
it "returns all elements until the block returns false" do
@@ -15,12 +14,15 @@ describe "Array#take_while" do
[1, 2, false, 4].take_while{ |element| element }.should == [1, 2]
end
- it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it 'returns a subclass instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(ArraySpecs::MyArray)
+ end
end
-end
-describe "Array#take_while" do
- @value_to_return = -> _ { true }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :take_while
+ ruby_version_is '3.0' do
+ it 'returns a Array instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(Array)
+ end
+ end
end
diff --git a/spec/ruby/core/array/to_h_spec.rb b/spec/ruby/core/array/to_h_spec.rb
index 1c814f3d01..f5a7e546e6 100644
--- a/spec/ruby/core/array/to_h_spec.rb
+++ b/spec/ruby/core/array/to_h_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#to_h" do
it "converts empty array to empty hash" do
@@ -45,12 +44,6 @@ describe "Array#to_h" do
[:a, :b].to_h { |k| [k, k.to_s] }.should == { a: 'a', b: 'b' }
end
- it "passes to a block each element as a single argument" do
- ScratchPad.record []
- [[:a, 1], [:b, 2]].to_h { |*args| ScratchPad << args; [args[0], args[1]] }
- ScratchPad.recorded.sort.should == [[[:a, 1]], [[:b, 2]]]
- end
-
it "raises ArgumentError if block returns longer or shorter array" do
-> do
[:a, :b].to_h { |k| [k, k.to_s, 1] }
@@ -84,8 +77,3 @@ describe "Array#to_h" do
end
end
end
-
-describe "Array#to_h" do
- @value_to_return = -> e { [e, e.to_s] }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :to_h
-end
diff --git a/spec/ruby/core/array/try_convert_spec.rb b/spec/ruby/core/array/try_convert_spec.rb
index bea8815006..47b4722d80 100644
--- a/spec/ruby/core/array/try_convert_spec.rb
+++ b/spec/ruby/core/array/try_convert_spec.rb
@@ -39,7 +39,7 @@ describe "Array.try_convert" do
it "sends #to_ary to the argument and raises TypeError if it's not a kind of Array" do
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(Object.new)
- -> { Array.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_ary gives Object)")
+ -> { Array.try_convert obj }.should raise_error(TypeError)
end
it "does not rescue exceptions raised by #to_ary" do
diff --git a/spec/ruby/core/array/uniq_spec.rb b/spec/ruby/core/array/uniq_spec.rb
index d5d826db15..4461cae16b 100644
--- a/spec/ruby/core/array/uniq_spec.rb
+++ b/spec/ruby/core/array/uniq_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#uniq" do
it "returns an array with no duplicates" do
@@ -85,8 +84,16 @@ describe "Array#uniq" do
[false, nil, 42].uniq { :bar }.should == [false]
end
- it "returns Array instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(Array)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instance on Array subclasses" do
+ ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(ArraySpecs::MyArray)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns Array instance on Array subclasses" do
+ ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(Array)
+ end
end
it "properly handles an identical item even when its #eql? isn't reflexive" do
@@ -124,11 +131,6 @@ describe "Array#uniq" do
end
end
-describe "Array#uniq" do
- @value_to_return = -> e { e }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :uniq
-end
-
describe "Array#uniq!" do
it "modifies the array in place" do
a = [ "a", "a", "b", "b", "c" ]
@@ -212,32 +214,4 @@ describe "Array#uniq!" do
a.uniq!
a.should == [x]
end
-
- it "does not truncate the array is the block raises an exception" do
- a = [1, 2, 3]
- begin
- a.send(@method) { raise StandardError, 'Oops' }
- rescue
- end
-
- a.should == [1, 2, 3]
- end
-
- it "doesn't change array if error is raised" do
- a = [1, 1, 2, 2, 3, 3, 4, 4]
- begin
- a.send(@method) do |e|
- raise StandardError, 'Oops' if e == 3
- e
- end
- rescue StandardError
- end
-
- a.should == [1, 1, 2, 2, 3, 3, 4, 4]
- end
-end
-
-describe "Array#uniq!" do
- @value_to_return = -> e { e }
- it_behaves_like :array_iterable_and_tolerating_size_increasing, :uniq!
end
diff --git a/spec/ruby/core/basicobject/fixtures/classes.rb b/spec/ruby/core/basicobject/fixtures/classes.rb
index ed5a2dda17..d1785afe31 100644
--- a/spec/ruby/core/basicobject/fixtures/classes.rb
+++ b/spec/ruby/core/basicobject/fixtures/classes.rb
@@ -15,231 +15,8 @@ module BasicObjectSpecs
include InstExec
end
- module InstEval
- module CVar
- module Get
- class ReceiverScope
- @@cvar = :value_defined_in_receiver_scope
- end
-
- class BlockDefinitionScope
- @@cvar = :value_defined_in_block_definition_scope
-
- def block
- -> * { @@cvar }
- end
- end
-
- class CallerScope
- @@cvar = :value_defined_in_caller_scope
-
- def get_class_variable_with_string(obj)
- obj.instance_eval("@@cvar")
- end
-
- def get_class_variable_with_block(obj, block)
- obj.instance_eval(&block)
- end
- end
-
- class CallerWithoutCVarScope
- def get_class_variable_with_string(obj)
- obj.instance_eval("@@cvar")
- end
- end
-
- ReceiverWithCVarDefinedInSingletonClass = Class.new.new.tap do |obj|
- obj.singleton_class.class_variable_set(:@@cvar, :value_defined_in_receiver_singleton_class)
- end
- end
-
- module Set
- class ReceiverScope
- end
-
- class BlockDefinitionScope
- def self.get_class_variable
- @@cvar
- end
-
- def block_to_assign(value)
- -> * { @@cvar = value }
- end
- end
-
- class CallerScope
- def self.get_class_variable
- @@cvar
- end
-
- def set_class_variable_with_string(obj, value)
- obj.instance_eval("@@cvar=#{value.inspect}")
- end
-
- def set_class_variable_with_block(obj, block)
- obj.instance_eval(&block)
- end
- end
- end
- end
- end
-
- module InstEval
- module Constants
- module ConstantInReceiverSingletonClass
- module ReceiverScope
- FOO = :ReceiverScope
-
- class ReceiverParent
- FOO = :ReceiverParent
- end
-
- class Receiver < ReceiverParent
- FOO = :Receiver
-
- def initialize
- self.singleton_class.const_set(:FOO, :singleton_class)
- end
- end
- end
-
- module CallerScope
- FOO = :CallerScope
-
- class CallerParent
- FOO = :CallerParent
- end
-
- class Caller < CallerParent
- FOO = :Caller
-
- def get_constant_with_string(receiver)
- receiver.instance_eval("FOO")
- end
- end
- end
- end
-
- module ConstantInReceiverClass
- module ReceiverScope
- FOO = :ReceiverScope
-
- class ReceiverParent
- FOO = :ReceiverParent
- end
-
- class Receiver < ReceiverParent
- FOO = :Receiver
- end
- end
-
- module CallerScope
- FOO = :CallerScope
-
- class CallerParent
- FOO = :CallerParent
- end
-
- class Caller < CallerParent
- FOO = :Caller
-
- def get_constant_with_string(receiver)
- receiver.instance_eval("FOO")
- end
- end
- end
- end
-
- module ConstantInCallerClass
- module ReceiverScope
- FOO = :ReceiverScope
-
- class ReceiverParent
- FOO = :ReceiverParent
- end
-
- class Receiver < ReceiverParent
- # FOO is not declared in a receiver class
- end
- end
-
- module CallerScope
- FOO = :CallerScope
-
- class CallerParent
- FOO = :CallerParent
- end
-
- class Caller < CallerParent
- FOO = :Caller
-
- def get_constant_with_string(receiver)
- receiver.instance_eval("FOO")
- end
- end
- end
- end
-
- module ConstantInCallerOuterScopes
- module ReceiverScope
- FOO = :ReceiverScope
-
- class ReceiverParent
- FOO = :ReceiverParent
- end
-
- class Receiver < ReceiverParent
- # FOO is not declared in a receiver class
- end
- end
-
- module CallerScope
- FOO = :CallerScope
-
- class CallerParent
- FOO = :CallerParent
- end
-
- class Caller < CallerParent
- # FOO is not declared in a caller class
-
- def get_constant_with_string(receiver)
- receiver.instance_eval("FOO")
- end
- end
- end
- end
-
- module ConstantInReceiverParentClass
- module ReceiverScope
- FOO = :ReceiverScope
-
- class ReceiverParent
- FOO = :ReceiverParent
- end
-
- class Receiver < ReceiverParent
- # FOO is not declared in a receiver class
- end
- end
-
- module CallerScope
- # FOO is not declared in a caller outer scopes
-
- class CallerParent
- FOO = :CallerParent
- end
-
- class Caller < CallerParent
- # FOO is not declared in a caller class
-
- def get_constant_with_string(receiver)
- receiver.instance_eval("FOO")
- end
- end
- end
- end
- end
+ module InstEvalCVar
+ instance_eval { @@count = 2 }
end
class InstEvalConst
@@ -249,6 +26,7 @@ module BasicObjectSpecs
module InstEvalOuter
module Inner
obj = InstEvalConst.new
+ X_BY_STR = obj.instance_eval("INST_EVAL_CONST_X") rescue nil
X_BY_BLOCK = obj.instance_eval { INST_EVAL_CONST_X } rescue nil
end
end
diff --git a/spec/ruby/core/basicobject/instance_eval_spec.rb b/spec/ruby/core/basicobject/instance_eval_spec.rb
index 1f3a43f341..350b08a30e 100644
--- a/spec/ruby/core/basicobject/instance_eval_spec.rb
+++ b/spec/ruby/core/basicobject/instance_eval_spec.rb
@@ -84,30 +84,11 @@ describe "BasicObject#instance_eval" do
end
- ruby_version_is "3.3" do
- it "uses the caller location as default location" do
- f = Object.new
- f.instance_eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
- end
- end
-
it "has access to receiver's instance variables" do
BasicObjectSpecs::IVars.new.instance_eval { @secret }.should == 99
BasicObjectSpecs::IVars.new.instance_eval("@secret").should == 99
end
- it "raises TypeError for frozen objects when tries to set receiver's instance variables" do
- -> { nil.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen NilClass: nil")
- -> { true.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen TrueClass: true")
- -> { false.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen FalseClass: false")
- -> { 1.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen Integer: 1")
- -> { :symbol.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen Symbol: :symbol")
-
- obj = Object.new
- obj.freeze
- -> { obj.instance_eval { @foo = 42 } }.should raise_error(FrozenError)
- end
-
it "treats block-local variables as local to the block" do
prc = instance_eval <<-CODE
proc do |x, prc|
@@ -124,6 +105,11 @@ describe "BasicObject#instance_eval" do
prc.call(false, prc).should == 1
end
+ it "sets class variables in the receiver" do
+ BasicObjectSpecs::InstEvalCVar.class_variables.should include(:@@count)
+ BasicObjectSpecs::InstEvalCVar.send(:class_variable_get, :@@count).should == 2
+ end
+
it "makes the receiver metaclass the scoped class when used with a string" do
obj = Object.new
obj.instance_eval %{
@@ -133,52 +119,8 @@ describe "BasicObject#instance_eval" do
obj.singleton_class.const_get(:B).should be_an_instance_of(Class)
end
- describe "constants lookup when a String given" do
- it "looks in the receiver singleton class first" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverSingletonClass::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverSingletonClass::CallerScope::Caller.new
-
- caller.get_constant_with_string(receiver).should == :singleton_class
- end
-
- ruby_version_is ""..."3.1" do
- it "looks in the caller scope next" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new
-
- caller.get_constant_with_string(receiver).should == :Caller
- end
- end
-
- ruby_version_is "3.1" do
- it "looks in the receiver class next" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new
-
- caller.get_constant_with_string(receiver).should == :Receiver
- end
- end
-
- it "looks in the caller class next" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInCallerClass::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInCallerClass::CallerScope::Caller.new
-
- caller.get_constant_with_string(receiver).should == :Caller
- end
-
- it "looks in the caller outer scopes next" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInCallerOuterScopes::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInCallerOuterScopes::CallerScope::Caller.new
-
- caller.get_constant_with_string(receiver).should == :CallerScope
- end
-
- it "looks in the receiver class hierarchy next" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverParentClass::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverParentClass::CallerScope::Caller.new
-
- caller.get_constant_with_string(receiver).should == :ReceiverParent
- end
+ it "gets constants in the receiver if a string given" do
+ BasicObjectSpecs::InstEvalOuter::Inner::X_BY_STR.should == 2
end
it "doesn't get constants in the receiver if a block given" do
@@ -194,51 +136,17 @@ describe "BasicObject#instance_eval" do
end.should raise_error(TypeError)
end
- describe "class variables lookup" do
- it "gets class variables in the caller class when called with a String" do
- receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverScope.new
- caller = BasicObjectSpecs::InstEval::CVar::Get::CallerScope.new
-
- caller.get_class_variable_with_string(receiver).should == :value_defined_in_caller_scope
- end
-
- it "gets class variables in the block definition scope when called with a block" do
- receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverScope.new
- caller = BasicObjectSpecs::InstEval::CVar::Get::CallerScope.new
- block = BasicObjectSpecs::InstEval::CVar::Get::BlockDefinitionScope.new.block
-
- caller.get_class_variable_with_block(receiver, block).should == :value_defined_in_block_definition_scope
- end
+quarantine! do # Not clean, leaves cvars lying around to break other specs
+ it "scopes class var accesses in the caller when called on an Integer" do
+ # Integer can take instance vars
+ Integer.class_eval "@@__tmp_instance_eval_spec = 1"
+ (defined? @@__tmp_instance_eval_spec).should be_nil
- it "sets class variables in the caller class when called with a String" do
- receiver = BasicObjectSpecs::InstEval::CVar::Set::ReceiverScope.new
- caller = BasicObjectSpecs::InstEval::CVar::Set::CallerScope.new
-
- caller.set_class_variable_with_string(receiver, 1)
- BasicObjectSpecs::InstEval::CVar::Set::CallerScope.get_class_variable.should == 1
- end
-
- it "sets class variables in the block definition scope when called with a block" do
- receiver = BasicObjectSpecs::InstEval::CVar::Set::ReceiverScope.new
- caller = BasicObjectSpecs::InstEval::CVar::Set::CallerScope.new
- block = BasicObjectSpecs::InstEval::CVar::Set::BlockDefinitionScope.new.block_to_assign(1)
-
- caller.set_class_variable_with_block(receiver, block)
- BasicObjectSpecs::InstEval::CVar::Set::BlockDefinitionScope.get_class_variable.should == 1
- end
-
- it "does not have access to class variables in the receiver class when called with a String" do
- receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverScope.new
- caller = BasicObjectSpecs::InstEval::CVar::Get::CallerWithoutCVarScope.new
- -> { caller.get_class_variable_with_string(receiver) }.should raise_error(NameError, /uninitialized class variable @@cvar/)
- end
-
- it "does not have access to class variables in the receiver's singleton class when called with a String" do
- receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverWithCVarDefinedInSingletonClass
- caller = BasicObjectSpecs::InstEval::CVar::Get::CallerWithoutCVarScope.new
- -> { caller.get_class_variable_with_string(receiver) }.should raise_error(NameError, /uninitialized class variable @@cvar/)
- end
+ @@__tmp_instance_eval_spec = 2
+ 1.instance_eval { @@__tmp_instance_eval_spec }.should == 2
+ Integer.__send__(:remove_class_variable, :@@__tmp_instance_eval_spec)
end
+end
it "raises a TypeError when defining methods on numerics" do
-> do
diff --git a/spec/ruby/core/basicobject/method_missing_spec.rb b/spec/ruby/core/basicobject/method_missing_spec.rb
index a29d4375bc..b048780ee8 100644
--- a/spec/ruby/core/basicobject/method_missing_spec.rb
+++ b/spec/ruby/core/basicobject/method_missing_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/basicobject/method_missing'
describe "BasicObject#method_missing" do
diff --git a/spec/ruby/core/basicobject/singleton_method_added_spec.rb b/spec/ruby/core/basicobject/singleton_method_added_spec.rb
index fc65a091aa..ab6b2a2d10 100644
--- a/spec/ruby/core/basicobject/singleton_method_added_spec.rb
+++ b/spec/ruby/core/basicobject/singleton_method_added_spec.rb
@@ -94,7 +94,7 @@ describe "BasicObject#singleton_method_added" do
-> {
def self.foo
end
- }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for/)
+ }.should raise_error(NoMethodError, /undefined method `singleton_method_added' for/)
end
end
@@ -106,16 +106,16 @@ describe "BasicObject#singleton_method_added" do
-> {
def foo
end
- }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
+ }.should raise_error(NoMethodError, /undefined method `singleton_method_added' for #<Object:/)
-> {
define_method(:bar) {}
- }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
+ }.should raise_error(NoMethodError, /undefined method `singleton_method_added' for #<Object:/)
end
-> {
object.define_singleton_method(:baz) {}
- }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
+ }.should raise_error(NoMethodError, /undefined method `singleton_method_added' for #<Object:/)
end
it "calls #method_missing" do
diff --git a/spec/ruby/core/binding/clone_spec.rb b/spec/ruby/core/binding/clone_spec.rb
index f1769ac6de..ebd40f5377 100644
--- a/spec/ruby/core/binding/clone_spec.rb
+++ b/spec/ruby/core/binding/clone_spec.rb
@@ -4,10 +4,4 @@ require_relative 'shared/clone'
describe "Binding#clone" do
it_behaves_like :binding_clone, :clone
-
- it "preserves frozen status" do
- bind = binding.freeze
- bind.frozen?.should == true
- bind.clone.frozen?.should == true
- end
end
diff --git a/spec/ruby/core/binding/dup_spec.rb b/spec/ruby/core/binding/dup_spec.rb
index 4eff66bd9a..43968213c8 100644
--- a/spec/ruby/core/binding/dup_spec.rb
+++ b/spec/ruby/core/binding/dup_spec.rb
@@ -4,27 +4,4 @@ require_relative 'shared/clone'
describe "Binding#dup" do
it_behaves_like :binding_clone, :dup
-
- it "resets frozen status" do
- bind = binding.freeze
- bind.frozen?.should == true
- bind.dup.frozen?.should == false
- end
-
- it "retains original binding variables but the list is distinct" do
- bind1 = binding
- eval "a = 1", bind1
-
- bind2 = bind1.dup
- eval("a = 2", bind2)
- eval("a", bind1).should == 2
- eval("a", bind2).should == 2
-
- eval("b = 2", bind2)
- -> { eval("b", bind1) }.should raise_error(NameError)
- eval("b", bind2).should == 2
-
- bind1.local_variables.sort.should == [:a, :bind1, :bind2]
- bind2.local_variables.sort.should == [:a, :b, :bind1, :bind2]
- end
end
diff --git a/spec/ruby/core/binding/eval_spec.rb b/spec/ruby/core/binding/eval_spec.rb
index bb2036f739..4bb3da7a6c 100644
--- a/spec/ruby/core/binding/eval_spec.rb
+++ b/spec/ruby/core/binding/eval_spec.rb
@@ -23,29 +23,58 @@ describe "Binding#eval" do
bind2.local_variables.should == []
end
- it "starts with line 1 if single argument is given" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- bind.eval("__LINE__").should == 1
- end
+ ruby_version_is ""..."3.0" do
+ it "inherits __LINE__ from the enclosing scope" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
+ end
- it "preserves __LINE__ across multiple calls to eval" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- bind.eval("__LINE__").should == 1
- bind.eval("__LINE__").should == 1
- end
+ it "preserves __LINE__ across multiple calls to eval" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
+ suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
+ end
- it "increments __LINE__ on each line of a multiline eval" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- bind.eval("#foo\n__LINE__").should == 2
+ it "increments __LINE__ on each line of a multiline eval" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ suppress_warning {bind.eval("#foo\n__LINE__")}.should == obj.get_line_of_binding + 1
+ end
+
+ it "inherits __LINE__ from the enclosing scope even if the Binding is created with #send" do
+ obj = BindingSpecs::Demo.new(1)
+ bind, line = obj.get_binding_with_send_and_line
+ suppress_warning {bind.eval("__LINE__")}.should == line
+ end
end
- it "starts with line 1 if the Binding is created with #send" do
- obj = BindingSpecs::Demo.new(1)
- bind, line = obj.get_binding_with_send_and_line
- bind.eval("__LINE__").should == 1
+ ruby_version_is "3.0" do
+ it "starts with line 1 if single argument is given" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ bind.eval("__LINE__").should == 1
+ end
+
+ it "preserves __LINE__ across multiple calls to eval" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ bind.eval("__LINE__").should == 1
+ bind.eval("__LINE__").should == 1
+ end
+
+ it "increments __LINE__ on each line of a multiline eval" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ bind.eval("#foo\n__LINE__").should == 2
+ end
+
+ it "starts with line 1 if the Binding is created with #send" do
+ obj = BindingSpecs::Demo.new(1)
+ bind, line = obj.get_binding_with_send_and_line
+ bind.eval("__LINE__").should == 1
+ end
end
it "starts with a __LINE__ of 1 if a filename is passed" do
@@ -60,18 +89,32 @@ describe "Binding#eval" do
bind.eval("#foo\n__LINE__", "(test)", 88).should == 89
end
- ruby_version_is ""..."3.3" do
+ ruby_version_is ""..."3.0" do
+ it "inherits __FILE__ from the enclosing scope" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ suppress_warning { bind.eval("__FILE__") }.should == obj.get_file_of_binding
+ end
+
+ it "inherits __LINE__ from the enclosing scope" do
+ obj = BindingSpecs::Demo.new(1)
+ bind, line = obj.get_binding_and_line
+ suppress_warning { bind.eval("__LINE__") }.should == line
+ end
+ end
+
+ ruby_version_is "3.0" do
it "uses (eval) as __FILE__ if single argument given" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("__FILE__").should == '(eval)'
end
- end
- it "uses 1 as __LINE__" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- suppress_warning { bind.eval("__LINE__") }.should == 1
+ it "uses 1 as __LINE__" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ suppress_warning { bind.eval("__LINE__") }.should == 1
+ end
end
it "uses the __FILE__ that is passed in" do
@@ -106,10 +149,4 @@ describe "Binding#eval" do
bind.eval("'bar'.foo").should == "foo"
end
-
- ruby_version_is "3.3" do
- it "uses the caller location as default filename" do
- binding.eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
- end
- end
end
diff --git a/spec/ruby/core/binding/fixtures/irbrc b/spec/ruby/core/binding/fixtures/irbrc
new file mode 100644
index 0000000000..2bc12af2f7
--- /dev/null
+++ b/spec/ruby/core/binding/fixtures/irbrc
@@ -0,0 +1 @@
+# empty configuration
diff --git a/spec/ruby/core/binding/irb_spec.rb b/spec/ruby/core/binding/irb_spec.rb
index 2607c7ef33..b3bc274f78 100644
--- a/spec/ruby/core/binding/irb_spec.rb
+++ b/spec/ruby/core/binding/irb_spec.rb
@@ -1,19 +1,16 @@
require_relative '../../spec_helper'
-require 'tmpdir'
describe "Binding#irb" do
it "creates an IRB session with the binding in scope" do
irb_fixture = fixture __FILE__, "irb.rb"
- envs = %w[IRBRC HOME XDG_CONFIG_HOME].to_h {|e| [e, nil]}
+ irbrc_fixture = fixture __FILE__, "irbrc"
- out = Dir.mktmpdir do |dir|
- IO.popen([envs, *ruby_exe, irb_fixture, chdir: dir], "r+") do |pipe|
- pipe.puts "a ** 2"
- pipe.puts "exit"
- pipe.readlines.map(&:chomp).reject(&:empty?)
- end
+ out = IO.popen([{"IRBRC"=>irbrc_fixture}, *ruby_exe, irb_fixture], "r+") do |pipe|
+ pipe.puts "a ** 2"
+ pipe.puts "exit"
+ pipe.readlines.map(&:chomp)
end
- out.last(3).should == ["a ** 2", "100", "exit"]
+ out[-3..-1].should == ["a ** 2", "100", "exit"]
end
end
diff --git a/spec/ruby/core/binding/shared/clone.rb b/spec/ruby/core/binding/shared/clone.rb
index 1224b8ec7d..0e934ac1b5 100644
--- a/spec/ruby/core/binding/shared/clone.rb
+++ b/spec/ruby/core/binding/shared/clone.rb
@@ -31,26 +31,4 @@ describe :binding_clone, shared: true do
b2.local_variable_defined?(:x).should == false
end
end
-
- ruby_version_is "3.4" do
- it "copies instance variables" do
- @b1.instance_variable_set(:@ivar, 1)
- cl = @b1.send(@method)
- cl.instance_variables.should == [:@ivar]
- end
-
- it "copies the finalizer" do
- code = <<-RUBY
- obj = binding
-
- ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" })
-
- obj.clone
-
- exit 0
- RUBY
-
- ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"]
- end
- end
end
diff --git a/spec/ruby/core/binding/source_location_spec.rb b/spec/ruby/core/binding/source_location_spec.rb
index d1c8191ea8..d439c3e399 100644
--- a/spec/ruby/core/binding/source_location_spec.rb
+++ b/spec/ruby/core/binding/source_location_spec.rb
@@ -6,9 +6,4 @@ describe "Binding#source_location" do
b = BindingSpecs::LocationMethod::TEST_BINDING
b.source_location.should == [BindingSpecs::LocationMethod::FILE_PATH, 4]
end
-
- it "works for eval with a given line" do
- b = eval('binding', nil, "foo", 100)
- b.source_location.should == ["foo", 100]
- end
end
diff --git a/spec/ruby/core/class/attached_object_spec.rb b/spec/ruby/core/class/attached_object_spec.rb
index f1c0f63a44..115d5fa563 100644
--- a/spec/ruby/core/class/attached_object_spec.rb
+++ b/spec/ruby/core/class/attached_object_spec.rb
@@ -19,13 +19,13 @@ ruby_version_is '3.2' do
it "raises TypeError if the class is not a singleton class" do
a = Class.new
- -> { a.attached_object }.should raise_error(TypeError, /is not a singleton class/)
+ -> { a.attached_object }.should raise_error(TypeError)
end
it "raises TypeError for special singleton classes" do
- -> { nil.singleton_class.attached_object }.should raise_error(TypeError, /[`']NilClass' is not a singleton class/)
- -> { true.singleton_class.attached_object }.should raise_error(TypeError, /[`']TrueClass' is not a singleton class/)
- -> { false.singleton_class.attached_object }.should raise_error(TypeError, /[`']FalseClass' is not a singleton class/)
+ -> { nil.singleton_class.attached_object }.should raise_error(TypeError)
+ -> { true.singleton_class.attached_object }.should raise_error(TypeError)
+ -> { false.singleton_class.attached_object }.should raise_error(TypeError)
end
end
end
diff --git a/spec/ruby/core/class/dup_spec.rb b/spec/ruby/core/class/dup_spec.rb
index c09ed71b31..701fd72e19 100644
--- a/spec/ruby/core/class/dup_spec.rb
+++ b/spec/ruby/core/class/dup_spec.rb
@@ -61,7 +61,4 @@ describe "Class#dup" do
CoreClassSpecs::RecordCopy.name.should == "CoreClassSpecs::RecordCopy"
end
- it "raises TypeError if called on BasicObject" do
- -> { BasicObject.dup }.should raise_error(TypeError, "can't copy the root class")
- end
end
diff --git a/spec/ruby/core/class/subclasses_spec.rb b/spec/ruby/core/class/subclasses_spec.rb
index 50eb5358d9..a16b934d4f 100644
--- a/spec/ruby/core/class/subclasses_spec.rb
+++ b/spec/ruby/core/class/subclasses_spec.rb
@@ -7,7 +7,7 @@ ruby_version_is '3.1' do
assert_subclasses(ModuleSpecs::Parent, [ModuleSpecs::Child, ModuleSpecs::Child2])
end
- it "does not return included modules from the parent" do
+ it "does not return included modules" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
@@ -16,33 +16,6 @@ ruby_version_is '3.1' do
assert_subclasses(parent, [child])
end
- it "does not return included modules from the child" do
- parent = Class.new
- child = Class.new(parent)
- mod = Module.new
- parent.include(mod)
-
- assert_subclasses(parent, [child])
- end
-
- it "does not return prepended modules from the parent" do
- parent = Class.new
- child = Class.new(parent)
- mod = Module.new
- parent.prepend(mod)
-
- assert_subclasses(parent, [child])
- end
-
- it "does not return prepended modules from the child" do
- parent = Class.new
- child = Class.new(parent)
- mod = Module.new
- child.prepend(mod)
-
- assert_subclasses(parent, [child])
- end
-
it "does not return singleton classes" do
a = Class.new
diff --git a/spec/ruby/core/complex/inspect_spec.rb b/spec/ruby/core/complex/inspect_spec.rb
index 045be94b22..71aabde5be 100644
--- a/spec/ruby/core/complex/inspect_spec.rb
+++ b/spec/ruby/core/complex/inspect_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative '../numeric/fixtures/classes'
describe "Complex#inspect" do
it "returns (${real}+${image}i) for positive imaginary parts" do
@@ -14,24 +13,4 @@ describe "Complex#inspect" do
Complex(-1, -4).inspect.should == "(-1-4i)"
Complex(-7, -6.7).inspect.should == "(-7-6.7i)"
end
-
- it "calls #inspect on real and imaginary" do
- real = NumericSpecs::Subclass.new
- # + because of https://bugs.ruby-lang.org/issues/20337
- real.should_receive(:inspect).and_return(+"1")
- imaginary = NumericSpecs::Subclass.new
- imaginary.should_receive(:inspect).and_return("2")
- imaginary.should_receive(:<).any_number_of_times.and_return(false)
- Complex(real, imaginary).inspect.should == "(1+2i)"
- end
-
- it "adds an `*' before the `i' if the last character of the imaginary part is not numeric" do
- real = NumericSpecs::Subclass.new
- # + because of https://bugs.ruby-lang.org/issues/20337
- real.should_receive(:inspect).and_return(+"(1)")
- imaginary = NumericSpecs::Subclass.new
- imaginary.should_receive(:inspect).and_return("(2)")
- imaginary.should_receive(:<).any_number_of_times.and_return(false)
- Complex(real, imaginary).inspect.should == "((1)+(2)*i)"
- end
end
diff --git a/spec/ruby/core/complex/to_r_spec.rb b/spec/ruby/core/complex/to_r_spec.rb
index 788027a500..4559921492 100644
--- a/spec/ruby/core/complex/to_r_spec.rb
+++ b/spec/ruby/core/complex/to_r_spec.rb
@@ -34,16 +34,8 @@ describe "Complex#to_r" do
end
describe "when the imaginary part is Float 0.0" do
- ruby_version_is ''...'3.4' do
- it "raises RangeError" do
- -> { Complex(0, 0.0).to_r }.should raise_error(RangeError)
- end
- end
-
- ruby_version_is '3.4' do
- it "returns a Rational" do
- Complex(0, 0.0).to_r.should == 0r
- end
+ it "raises RangeError" do
+ -> { Complex(0, 0.0).to_r }.should raise_error(RangeError)
end
end
end
diff --git a/spec/ruby/core/complex/to_s_spec.rb b/spec/ruby/core/complex/to_s_spec.rb
index ceccffe470..989a7ae0b7 100644
--- a/spec/ruby/core/complex/to_s_spec.rb
+++ b/spec/ruby/core/complex/to_s_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative '../numeric/fixtures/classes'
describe "Complex#to_s" do
describe "when self's real component is 0" do
@@ -42,14 +41,4 @@ describe "Complex#to_s" do
it "returns 1+NaN*i for Complex(1, NaN)" do
Complex(1, nan_value).to_s.should == "1+NaN*i"
end
-
- it "treats real and imaginary parts as strings" do
- real = NumericSpecs::Subclass.new
- # + because of https://bugs.ruby-lang.org/issues/20337
- real.should_receive(:to_s).and_return(+"1")
- imaginary = NumericSpecs::Subclass.new
- imaginary.should_receive(:to_s).and_return("2")
- imaginary.should_receive(:<).any_number_of_times.and_return(false)
- Complex(real, imaginary).to_s.should == "1+2i"
- end
end
diff --git a/spec/ruby/core/conditionvariable/broadcast_spec.rb b/spec/ruby/core/conditionvariable/broadcast_spec.rb
index 55a7b89c72..d88159df23 100644
--- a/spec/ruby/core/conditionvariable/broadcast_spec.rb
+++ b/spec/ruby/core/conditionvariable/broadcast_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require 'thread'
describe "ConditionVariable#broadcast" do
it "releases all threads waiting in line for this resource" do
diff --git a/spec/ruby/core/conditionvariable/marshal_dump_spec.rb b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
index 88b1cc38c1..f951a13e28 100644
--- a/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
+++ b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require 'thread'
describe "ConditionVariable#marshal_dump" do
it "raises a TypeError" do
diff --git a/spec/ruby/core/conditionvariable/signal_spec.rb b/spec/ruby/core/conditionvariable/signal_spec.rb
index 43a9cc611b..86383073f1 100644
--- a/spec/ruby/core/conditionvariable/signal_spec.rb
+++ b/spec/ruby/core/conditionvariable/signal_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require 'thread'
describe "ConditionVariable#signal" do
it "releases the first thread waiting in line for this resource" do
diff --git a/spec/ruby/core/conditionvariable/wait_spec.rb b/spec/ruby/core/conditionvariable/wait_spec.rb
index fe73e513c0..9a68c2b5a1 100644
--- a/spec/ruby/core/conditionvariable/wait_spec.rb
+++ b/spec/ruby/core/conditionvariable/wait_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require 'thread'
describe "ConditionVariable#wait" do
it "calls #sleep on the given object" do
diff --git a/spec/ruby/core/data/constants_spec.rb b/spec/ruby/core/data/constants_spec.rb
index 2eb43d501e..d9d55b50f9 100644
--- a/spec/ruby/core/data/constants_spec.rb
+++ b/spec/ruby/core/data/constants_spec.rb
@@ -1,6 +1,20 @@
require_relative '../../spec_helper'
-ruby_version_is ''...'3.2' do
+ruby_version_is ''...'3.0' do
+ describe "Data" do
+ it "is a subclass of Object" do
+ suppress_warning do
+ Data.superclass.should == Object
+ end
+ end
+
+ it "is deprecated" do
+ -> { Data }.should complain(/constant ::Data is deprecated/)
+ end
+ end
+end
+
+ruby_version_is '3.0'...'3.2' do
describe "Data" do
it "does not exist anymore" do
Object.should_not have_constant(:Data)
diff --git a/spec/ruby/core/data/define_spec.rb b/spec/ruby/core/data/define_spec.rb
deleted file mode 100644
index 2aa2c50d4c..0000000000
--- a/spec/ruby/core/data/define_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-ruby_version_is "3.2" do
- describe "Data.define" do
- it "accepts no arguments" do
- empty_data = Data.define
- empty_data.members.should == []
- end
-
- it "accepts symbols" do
- movie = Data.define(:title, :year)
- movie.members.should == [:title, :year]
- end
-
- it "accepts strings" do
- movie = Data.define("title", "year")
- movie.members.should == [:title, :year]
- end
-
- it "accepts a mix of strings and symbols" do
- movie = Data.define("title", :year, "genre")
- movie.members.should == [:title, :year, :genre]
- end
-
- it "accepts a block" do
- movie = Data.define(:title, :year) do
- def title_with_year
- "#{title} (#{year})"
- end
- end
- movie.members.should == [:title, :year]
- movie.new("Matrix", 1999).title_with_year.should == "Matrix (1999)"
- end
- end
-end
diff --git a/spec/ruby/core/data/fixtures/classes.rb b/spec/ruby/core/data/fixtures/classes.rb
deleted file mode 100644
index 46a6b48bb2..0000000000
--- a/spec/ruby/core/data/fixtures/classes.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-module DataSpecs
- guard -> { ruby_version_is "3.2" and Data.respond_to?(:define) } do
- Measure = Data.define(:amount, :unit)
- end
-end
diff --git a/spec/ruby/core/data/initialize_spec.rb b/spec/ruby/core/data/initialize_spec.rb
deleted file mode 100644
index 2c36bd3ac4..0000000000
--- a/spec/ruby/core/data/initialize_spec.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-ruby_version_is "3.2" do
- describe "Data#initialize" do
- it "accepts positional arguments" do
- data = DataSpecs::Measure.new(42, "km")
-
- data.amount.should == 42
- data.unit.should == "km"
- end
-
- it "accepts alternative positional arguments" do
- data = DataSpecs::Measure[42, "km"]
-
- data.amount.should == 42
- data.unit.should == "km"
- end
-
- it "accepts keyword arguments" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
-
- data.amount.should == 42
- data.unit.should == "km"
- end
-
- it "accepts alternative keyword arguments" do
- data = DataSpecs::Measure[amount: 42, unit: "km"]
-
- data.amount.should == 42
- data.unit.should == "km"
- end
-
- it "accepts String keyword arguments" do
- data = DataSpecs::Measure.new("amount" => 42, "unit" => "km")
-
- data.amount.should == 42
- data.unit.should == "km"
- end
-
- it "raises ArgumentError if no arguments are given" do
- -> {
- DataSpecs::Measure.new
- }.should raise_error(ArgumentError) { |e|
- e.message.should.include?("missing keywords: :amount, :unit")
- }
- end
-
- it "raises ArgumentError if at least one argument is missing" do
- -> {
- DataSpecs::Measure.new(unit: "km")
- }.should raise_error(ArgumentError) { |e|
- e.message.should.include?("missing keyword: :amount")
- }
- end
-
- it "raises ArgumentError if unknown keyword is given" do
- -> {
- DataSpecs::Measure.new(amount: 42, unit: "km", system: "metric")
- }.should raise_error(ArgumentError) { |e|
- e.message.should.include?("unknown keyword: :system")
- }
- end
- end
-end
diff --git a/spec/ruby/core/data/with_spec.rb b/spec/ruby/core/data/with_spec.rb
deleted file mode 100644
index 97e34c951f..0000000000
--- a/spec/ruby/core/data/with_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-ruby_version_is "3.2" do
- describe "Data#with" do
- it "returns self if given no arguments" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
- data = data.with.should.equal?(data)
- end
-
- it "accepts keyword arguments" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
- data = data.with(amount: 4, unit: "m")
-
- data.amount.should == 4
- data.unit.should == "m"
- end
-
- it "accepts String keyword arguments" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
- data = data.with("amount" => 4, "unit" => "m")
-
- data.amount.should == 4
- data.unit.should == "m"
- end
-
- it "raises ArgumentError if no keyword arguments are given" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
-
- -> {
- data.with(4, "m")
- }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)")
- end
- end
-end
diff --git a/spec/ruby/core/dir/chdir_spec.rb b/spec/ruby/core/dir/chdir_spec.rb
index 7ced2a7057..729ac403e3 100644
--- a/spec/ruby/core/dir/chdir_spec.rb
+++ b/spec/ruby/core/dir/chdir_spec.rb
@@ -19,14 +19,14 @@ describe "Dir.chdir" do
end
it "defaults to $HOME with no arguments" do
- skip "$HOME not valid directory" unless ENV['HOME'] && File.directory?(ENV['HOME'])
+ if ENV['HOME']
+ Dir.chdir
+ current_dir = Dir.pwd
- Dir.chdir
- current_dir = Dir.pwd
-
- Dir.chdir(ENV['HOME'])
- home = Dir.pwd
- current_dir.should == home
+ Dir.chdir(ENV['HOME'])
+ home = Dir.pwd
+ current_dir.should == home
+ end
end
it "changes to the specified directory" do
@@ -70,8 +70,6 @@ describe "Dir.chdir" do
end
it "defaults to the home directory when given a block but no argument" do
- skip "$HOME not valid directory" unless ENV['HOME'] && File.directory?(ENV['HOME'])
-
# Windows will return a path with forward slashes for ENV["HOME"] so we have
# to compare the route representations returned by Dir.chdir.
current_dir = ""
diff --git a/spec/ruby/core/dir/children_spec.rb b/spec/ruby/core/dir/children_spec.rb
index 0ad3df4669..03698cc246 100644
--- a/spec/ruby/core/dir/children_spec.rb
+++ b/spec/ruby/core/dir/children_spec.rb
@@ -47,7 +47,7 @@ describe "Dir.children" do
encoding = Encoding.find("filesystem")
encoding = Encoding::BINARY if encoding == Encoding::US_ASCII
platform_is_not :windows do
- children.should include("ã“ã‚“ã«ã¡ã¯.txt".dup.force_encoding(encoding))
+ children.should include("ã“ã‚“ã«ã¡ã¯.txt".force_encoding(encoding))
end
children.first.encoding.should equal(Encoding.find("filesystem"))
end
@@ -113,7 +113,7 @@ describe "Dir#children" do
encoding = Encoding.find("filesystem")
encoding = Encoding::BINARY if encoding == Encoding::US_ASCII
platform_is_not :windows do
- children.should include("ã“ã‚“ã«ã¡ã¯.txt".dup.force_encoding(encoding))
+ children.should include("ã“ã‚“ã«ã¡ã¯.txt".force_encoding(encoding))
end
children.first.encoding.should equal(Encoding.find("filesystem"))
end
@@ -131,17 +131,4 @@ describe "Dir#children" do
children = @dir.children.sort
children.first.encoding.should equal(Encoding::EUC_KR)
end
-
- it "returns the same result when called repeatedly" do
- @dir = Dir.open DirSpecs.mock_dir
-
- a = []
- @dir.each {|dir| a << dir}
-
- b = []
- @dir.each {|dir| b << dir}
-
- a.sort.should == b.sort
- a.sort.should == DirSpecs.expected_paths
- end
end
diff --git a/spec/ruby/core/dir/each_child_spec.rb b/spec/ruby/core/dir/each_child_spec.rb
index 7194273b95..520186e79e 100644
--- a/spec/ruby/core/dir/each_child_spec.rb
+++ b/spec/ruby/core/dir/each_child_spec.rb
@@ -86,19 +86,6 @@ describe "Dir#each_child" do
@dir.each_child { |f| f }.should == @dir
end
- it "returns the same result when called repeatedly" do
- @dir = Dir.open DirSpecs.mock_dir
-
- a = []
- @dir.each {|dir| a << dir}
-
- b = []
- @dir.each {|dir| b << dir}
-
- a.sort.should == b.sort
- a.sort.should == DirSpecs.expected_paths
- end
-
describe "when no block is given" do
it "returns an Enumerator" do
@dir = Dir.new(DirSpecs.mock_dir)
diff --git a/spec/ruby/core/dir/each_spec.rb b/spec/ruby/core/dir/each_spec.rb
index 7674663d82..8c69a7212b 100644
--- a/spec/ruby/core/dir/each_spec.rb
+++ b/spec/ruby/core/dir/each_spec.rb
@@ -35,17 +35,6 @@ describe "Dir#each" do
ls.should include(@dir.read)
end
- it "returns the same result when called repeatedly" do
- a = []
- @dir.each {|dir| a << dir}
-
- b = []
- @dir.each {|dir| b << dir}
-
- a.sort.should == b.sort
- a.sort.should == DirSpecs.expected_paths
- end
-
describe "when no block is given" do
it "returns an Enumerator" do
@dir.each.should be_an_instance_of(Enumerator)
diff --git a/spec/ruby/core/dir/entries_spec.rb b/spec/ruby/core/dir/entries_spec.rb
index 7462542acf..91c30fccae 100644
--- a/spec/ruby/core/dir/entries_spec.rb
+++ b/spec/ruby/core/dir/entries_spec.rb
@@ -47,7 +47,7 @@ describe "Dir.entries" do
encoding = Encoding.find("filesystem")
encoding = Encoding::BINARY if encoding == Encoding::US_ASCII
platform_is_not :windows do
- entries.should include("ã“ã‚“ã«ã¡ã¯.txt".dup.force_encoding(encoding))
+ entries.should include("ã“ã‚“ã«ã¡ã¯.txt".force_encoding(encoding))
end
entries.first.encoding.should equal(Encoding.find("filesystem"))
end
diff --git a/spec/ruby/core/dir/exist_spec.rb b/spec/ruby/core/dir/exist_spec.rb
index 9023de533f..43987b0f32 100644
--- a/spec/ruby/core/dir/exist_spec.rb
+++ b/spec/ruby/core/dir/exist_spec.rb
@@ -13,11 +13,3 @@ describe "Dir.exist?" do
it_behaves_like :dir_exist, :exist?
end
-
-ruby_version_is "3.2" do
- describe "Dir.exists?" do
- it "has been removed" do
- Dir.should_not.respond_to?(:exists?)
- end
- end
-end
diff --git a/spec/ruby/core/dir/fchdir_spec.rb b/spec/ruby/core/dir/fchdir_spec.rb
deleted file mode 100644
index 429e569691..0000000000
--- a/spec/ruby/core/dir/fchdir_spec.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/common'
-
-ruby_version_is '3.3' do
- guard -> { Dir.respond_to? :fchdir } do
- describe "Dir.fchdir" do
- before :all do
- DirSpecs.create_mock_dirs
- end
-
- after :all do
- DirSpecs.delete_mock_dirs
- end
-
- before :each do
- @dirs = [Dir.new('.')]
- @original = @dirs.first.fileno
- end
-
- after :each do
- Dir.fchdir(@original)
- @dirs.each(&:close)
- end
-
- it "changes to the specified directory" do
- dir = Dir.new(DirSpecs.mock_dir)
- @dirs << dir
- Dir.fchdir dir.fileno
- Dir.pwd.should == DirSpecs.mock_dir
- end
-
- it "returns 0 when successfully changing directory" do
- Dir.fchdir(@original).should == 0
- end
-
- it "returns the value of the block when a block is given" do
- Dir.fchdir(@original) { :block_value }.should == :block_value
- end
-
- it "changes to the specified directory for the duration of the block" do
- pwd = Dir.pwd
- dir = Dir.new(DirSpecs.mock_dir)
- @dirs << dir
- Dir.fchdir(dir.fileno) { Dir.pwd }.should == DirSpecs.mock_dir
- Dir.pwd.should == pwd
- end
-
- it "raises a SystemCallError if the file descriptor given is not valid" do
- -> { Dir.fchdir(-1) }.should raise_error(SystemCallError)
- -> { Dir.fchdir(-1) { } }.should raise_error(SystemCallError)
- end
-
- it "raises a SystemCallError if the file descriptor given is not for a directory" do
- -> { Dir.fchdir $stdout.fileno }.should raise_error(SystemCallError)
- -> { Dir.fchdir($stdout.fileno) { } }.should raise_error(SystemCallError)
- end
- end
- end
-
- guard_not -> { Dir.respond_to? :fchdir } do
- describe "Dir.fchdir" do
- it "raises NotImplementedError" do
- -> { Dir.fchdir 1 }.should raise_error(NotImplementedError)
- -> { Dir.fchdir(1) { } }.should raise_error(NotImplementedError)
- end
- end
- end
-end
diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb
index 32f515c81d..06b52b90fb 100644
--- a/spec/ruby/core/dir/glob_spec.rb
+++ b/spec/ruby/core/dir/glob_spec.rb
@@ -106,11 +106,11 @@ describe "Dir.glob" do
ruby_version_is '3.1' do
it "recursively matches files and directories in nested dot subdirectory except . with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do
expected = %w[
- nested/.
- nested/.dotsubir
- nested/.dotsubir/.dotfile
- nested/.dotsubir/nondotfile
- ]
+ nested/.
+ nested/.dotsubir
+ nested/.dotsubir/.dotfile
+ nested/.dotsubir/nondotfile
+ ]
Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort
end
@@ -182,134 +182,6 @@ describe "Dir.glob" do
Dir.glob('**/**/**').should_not.empty?
end
- it "handles **/** with base keyword argument" do
- Dir.glob('**/**', base: "dir").should == ["filename_ordering"]
-
- expected = %w[
- nested
- nested/directory
- nested/directory/structure
- nested/directory/structure/bar
- nested/directory/structure/baz
- nested/directory/structure/file_one
- nested/directory/structure/file_one.ext
- nested/directory/structure/foo
- nondotfile
- ].sort
-
- Dir.glob('**/**', base: "deeply").sort.should == expected
- end
-
- it "handles **/ with base keyword argument" do
- expected = %w[
- /
- directory/
- directory/structure/
- ]
- Dir.glob('**/', base: "deeply/nested").sort.should == expected
- end
-
- it "handles **/nondotfile with base keyword argument" do
- expected = %w[
- deeply/nondotfile
- nondotfile
- subdir_one/nondotfile
- subdir_two/nondotfile
- ]
- Dir.glob('**/nondotfile', base: ".").sort.should == expected
- end
-
- it "handles **/nondotfile with base keyword argument and FNM_DOTMATCH" do
- expected = %w[
- .dotsubdir/nondotfile
- deeply/nondotfile
- nested/.dotsubir/nondotfile
- nondotfile
- subdir_one/nondotfile
- subdir_two/nondotfile
- ]
- Dir.glob('**/nondotfile', File::FNM_DOTMATCH, base: ".").sort.should == expected
- end
-
- it "handles **/.dotfile with base keyword argument" do
- expected = %w[
- .dotfile
- deeply/.dotfile
- subdir_one/.dotfile
- ]
- Dir.glob('**/.dotfile', base: ".").sort.should == expected
- end
-
- it "handles **/.dotfile with base keyword argument and FNM_DOTMATCH" do
- expected = %w[
- .dotfile
- .dotsubdir/.dotfile
- deeply/.dotfile
- nested/.dotsubir/.dotfile
- subdir_one/.dotfile
- ]
- Dir.glob('**/.dotfile', File::FNM_DOTMATCH, base: ".").sort.should == expected
- end
-
- it "handles **/.* with base keyword argument" do
- expected = %w[
- .dotfile.ext
- directory/structure/.ext
- ].sort
-
- Dir.glob('**/.*', base: "deeply/nested").sort.should == expected
- end
-
- # < 3.1 include a "." entry for every dir: ["directory/.", "directory/structure/.", ...]
- ruby_version_is '3.1' do
- it "handles **/.* with base keyword argument and FNM_DOTMATCH" do
- expected = %w[
- .
- .dotfile.ext
- directory/structure/.ext
- ].sort
-
- Dir.glob('**/.*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
- end
-
- it "handles **/** with base keyword argument and FNM_DOTMATCH" do
- expected = %w[
- .
- .dotfile.ext
- directory
- directory/structure
- directory/structure/.ext
- directory/structure/bar
- directory/structure/baz
- directory/structure/file_one
- directory/structure/file_one.ext
- directory/structure/foo
- ].sort
-
- Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
- end
- end
-
- it "handles **/*pattern* with base keyword argument and FNM_DOTMATCH" do
- expected = %w[
- .dotfile.ext
- directory/structure/file_one
- directory/structure/file_one.ext
- ]
-
- Dir.glob('**/*file*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
- end
-
- it "handles **/glob with base keyword argument and FNM_EXTGLOB" do
- expected = %w[
- directory/structure/bar
- directory/structure/file_one
- directory/structure/file_one.ext
- ]
-
- Dir.glob('**/*{file,bar}*', File::FNM_EXTGLOB, base: "deeply/nested").sort.should == expected
- end
-
it "handles simple filename patterns" do
Dir.glob('.dotfile').should == ['.dotfile']
end
diff --git a/spec/ruby/core/dir/home_spec.rb b/spec/ruby/core/dir/home_spec.rb
index 3cf745ab46..bbe347ba9e 100644
--- a/spec/ruby/core/dir/home_spec.rb
+++ b/spec/ruby/core/dir/home_spec.rb
@@ -40,21 +40,22 @@ describe "Dir.home" do
home.should == "C:/rubyspäc/home"
home.encoding.should == Encoding::UTF_8
end
+ end
- it "retrieves the directory from HOME, USERPROFILE, HOMEDRIVE/HOMEPATH and the WinAPI in that order" do
- old_dirs = [ENV.delete('HOME'), ENV.delete('USERPROFILE'), ENV.delete('HOMEDRIVE'), ENV.delete('HOMEPATH')]
+ it "retrieves the directory from HOME, USERPROFILE, HOMEDRIVE/HOMEPATH and the WinAPI in that order" do
+ old_dirs = [ENV.delete('HOME'), ENV.delete('USERPROFILE'), ENV.delete('HOMEDRIVE'), ENV.delete('HOMEPATH')]
- Dir.home.should == old_dirs[1].gsub("\\", "/")
- ENV['HOMEDRIVE'] = "C:"
- ENV['HOMEPATH'] = "\\rubyspec\\home1"
- Dir.home.should == "C:/rubyspec/home1"
- ENV['USERPROFILE'] = "C:\\rubyspec\\home2"
- Dir.home.should == "C:/rubyspec/home2"
- ENV['HOME'] = "C:\\rubyspec\\home3"
- Dir.home.should == "C:/rubyspec/home3"
- ensure
- ENV['HOME'], ENV['USERPROFILE'], ENV['HOMEDRIVE'], ENV['HOMEPATH'] = *old_dirs
- end
+ Dir.home.should == old_dirs[1].gsub("\\", "/")
+ ENV['HOMEDRIVE'] = "C:"
+ ENV['HOMEPATH'] = "\\rubyspec\\home1"
+ Dir.home.should == "C:/rubyspec/home1"
+ ENV['USERPROFILE'] = "C:\\rubyspec\\home2"
+ # https://bugs.ruby-lang.org/issues/19244
+ # Dir.home.should == "C:/rubyspec/home2"
+ ENV['HOME'] = "C:\\rubyspec\\home3"
+ Dir.home.should == "C:/rubyspec/home3"
+ ensure
+ ENV['HOME'], ENV['USERPROFILE'], ENV['HOMEDRIVE'], ENV['HOMEPATH'] = *old_dirs
end
end
end
@@ -84,10 +85,4 @@ describe "Dir.home" do
it "raises an ArgumentError if the named user doesn't exist" do
-> { Dir.home('geuw2n288dh2k') }.should raise_error(ArgumentError)
end
-
- describe "when called with a nil user name" do
- it "returns the current user's home directory, reading $HOME first" do
- Dir.home(nil).should == "/rubyspec_home"
- end
- end
end
diff --git a/spec/ruby/core/dir/shared/chroot.rb b/spec/ruby/core/dir/shared/chroot.rb
index a8f7c10a19..8c0599fe3f 100644
--- a/spec/ruby/core/dir/shared/chroot.rb
+++ b/spec/ruby/core/dir/shared/chroot.rb
@@ -2,7 +2,7 @@ describe :dir_chroot_as_root, shared: true do
before :all do
DirSpecs.create_mock_dirs
- @real_root = "../" * (__dir__.count('/') - 1)
+ @real_root = "../" * (File.dirname(__FILE__).count('/') - 1)
@ref_dir = File.join("/", File.basename(Dir["/*"].first))
end
@@ -18,7 +18,7 @@ describe :dir_chroot_as_root, shared: true do
compilations_ci = ENV["GITHUB_WORKFLOW"] == "Compilations"
it "can be used to change the process' root directory" do
- -> { Dir.send(@method, __dir__) }.should_not raise_error
+ -> { Dir.send(@method, File.dirname(__FILE__)) }.should_not raise_error
File.should.exist?("/#{File.basename(__FILE__)}")
end unless compilations_ci
diff --git a/spec/ruby/core/dir/shared/exist.rb b/spec/ruby/core/dir/shared/exist.rb
index 3097f57715..765d1b656c 100644
--- a/spec/ruby/core/dir/shared/exist.rb
+++ b/spec/ruby/core/dir/shared/exist.rb
@@ -1,6 +1,6 @@
describe :dir_exist, shared: true do
it "returns true if the given directory exists" do
- Dir.send(@method, __dir__).should be_true
+ Dir.send(@method, File.dirname(__FILE__)).should be_true
end
it "returns true for '.'" do
@@ -20,7 +20,7 @@ describe :dir_exist, shared: true do
end
it "understands relative paths" do
- Dir.send(@method, __dir__ + '/../').should be_true
+ Dir.send(@method, File.dirname(__FILE__) + '/../').should be_true
end
it "returns false if the given directory doesn't exist" do
@@ -28,13 +28,12 @@ describe :dir_exist, shared: true do
end
it "doesn't require the name to have a trailing slash" do
- dir = __dir__
+ dir = File.dirname(__FILE__)
dir.sub!(/\/$/,'')
Dir.send(@method, dir).should be_true
end
it "doesn't expand paths" do
- skip "$HOME not valid directory" unless ENV['HOME'] && File.directory?(ENV['HOME'])
Dir.send(@method, File.expand_path('~')).should be_true
Dir.send(@method, '~').should be_false
end
@@ -51,7 +50,7 @@ describe :dir_exist, shared: true do
it "calls #to_path on non String arguments" do
p = mock('path')
- p.should_receive(:to_path).and_return(__dir__)
+ p.should_receive(:to_path).and_return(File.dirname(__FILE__))
Dir.send(@method, p)
end
end
diff --git a/spec/ruby/core/dir/shared/glob.rb b/spec/ruby/core/dir/shared/glob.rb
index 745f02d46b..33b2828c27 100644
--- a/spec/ruby/core/dir/shared/glob.rb
+++ b/spec/ruby/core/dir/shared/glob.rb
@@ -12,7 +12,7 @@ describe :dir_glob, shared: true do
end
it "raises an Encoding::CompatibilityError if the argument encoding is not compatible with US-ASCII" do
- pattern = "file*".dup.force_encoding Encoding::UTF_16BE
+ pattern = "file*".force_encoding Encoding::UTF_16BE
-> { Dir.send(@method, pattern) }.should raise_error(Encoding::CompatibilityError)
end
@@ -27,22 +27,24 @@ describe :dir_glob, shared: true do
-> {Dir.send(@method, "file_o*\0file_t*")}.should raise_error ArgumentError, /nul-separated/
end
- it "result is sorted by default" do
- result = Dir.send(@method, '*')
- result.should == result.sort
- end
+ ruby_version_is "3.0" do
+ it "result is sorted by default" do
+ result = Dir.send(@method, '*')
+ result.should == result.sort
+ end
- it "result is sorted with sort: true" do
- result = Dir.send(@method, '*', sort: true)
- result.should == result.sort
- end
+ it "result is sorted with sort: true" do
+ result = Dir.send(@method, '*', sort: true)
+ result.should == result.sort
+ end
- it "sort: false returns same files" do
- result = Dir.send(@method,'*', sort: false)
- result.sort.should == Dir.send(@method, '*').sort
+ it "sort: false returns same files" do
+ result = Dir.send(@method,'*', sort: false)
+ result.sort.should == Dir.send(@method, '*').sort
+ end
end
- ruby_version_is ""..."3.1" do
+ ruby_version_is "3.0"..."3.1" do
it "result is sorted with any non false value of sort:" do
result = Dir.send(@method, '*', sort: 0)
result.should == result.sort
diff --git a/spec/ruby/core/encoding/compatible_spec.rb b/spec/ruby/core/encoding/compatible_spec.rb
index f18d8680a9..80ecab6155 100644
--- a/spec/ruby/core/encoding/compatible_spec.rb
+++ b/spec/ruby/core/encoding/compatible_spec.rb
@@ -7,7 +7,7 @@ require_relative '../../spec_helper'
describe "Encoding.compatible? String, String" do
describe "when the first's Encoding is valid US-ASCII" do
before :each do
- @str = "abc".dup.force_encoding Encoding::US_ASCII
+ @str = "abc".force_encoding Encoding::US_ASCII
end
it "returns US-ASCII when the second's is US-ASCII" do
@@ -33,28 +33,28 @@ describe "Encoding.compatible? String, String" do
describe "when the first's Encoding is ASCII compatible and ASCII only" do
it "returns the first's Encoding if the second is ASCII compatible and ASCII only" do
- [ [Encoding, "abc".dup.force_encoding("UTF-8"), "123".dup.force_encoding("Shift_JIS"), Encoding::UTF_8],
- [Encoding, "123".dup.force_encoding("Shift_JIS"), "abc".dup.force_encoding("UTF-8"), Encoding::Shift_JIS]
+ [ [Encoding, "abc".force_encoding("UTF-8"), "123".force_encoding("Shift_JIS"), Encoding::UTF_8],
+ [Encoding, "123".force_encoding("Shift_JIS"), "abc".force_encoding("UTF-8"), Encoding::Shift_JIS]
].should be_computed_by(:compatible?)
end
it "returns the first's Encoding if the second is ASCII compatible and ASCII only" do
- [ [Encoding, "abc".dup.force_encoding("BINARY"), "123".dup.force_encoding("US-ASCII"), Encoding::BINARY],
- [Encoding, "123".dup.force_encoding("US-ASCII"), "abc".dup.force_encoding("BINARY"), Encoding::US_ASCII]
+ [ [Encoding, "abc".force_encoding("BINARY"), "123".force_encoding("US-ASCII"), Encoding::BINARY],
+ [Encoding, "123".force_encoding("US-ASCII"), "abc".force_encoding("BINARY"), Encoding::US_ASCII]
].should be_computed_by(:compatible?)
end
it "returns the second's Encoding if the second is ASCII compatible but not ASCII only" do
- [ [Encoding, "abc".dup.force_encoding("UTF-8"), "\xff".dup.force_encoding("Shift_JIS"), Encoding::Shift_JIS],
- [Encoding, "123".dup.force_encoding("Shift_JIS"), "\xff".dup.force_encoding("UTF-8"), Encoding::UTF_8],
- [Encoding, "abc".dup.force_encoding("BINARY"), "\xff".dup.force_encoding("US-ASCII"), Encoding::US_ASCII],
- [Encoding, "123".dup.force_encoding("US-ASCII"), "\xff".dup.force_encoding("BINARY"), Encoding::BINARY],
+ [ [Encoding, "abc".force_encoding("UTF-8"), "\xff".force_encoding("Shift_JIS"), Encoding::Shift_JIS],
+ [Encoding, "123".force_encoding("Shift_JIS"), "\xff".force_encoding("UTF-8"), Encoding::UTF_8],
+ [Encoding, "abc".force_encoding("BINARY"), "\xff".force_encoding("US-ASCII"), Encoding::US_ASCII],
+ [Encoding, "123".force_encoding("US-ASCII"), "\xff".force_encoding("BINARY"), Encoding::BINARY],
].should be_computed_by(:compatible?)
end
it "returns nil if the second's Encoding is not ASCII compatible" do
- a = "abc".dup.force_encoding("UTF-8")
- b = "1234".dup.force_encoding("UTF-16LE")
+ a = "abc".force_encoding("UTF-8")
+ b = "1234".force_encoding("UTF-16LE")
Encoding.compatible?(a, b).should be_nil
end
end
@@ -75,7 +75,7 @@ describe "Encoding.compatible? String, String" do
describe "when the first's Encoding is not ASCII compatible" do
before :each do
- @str = "abc".dup.force_encoding Encoding::UTF_7
+ @str = "abc".force_encoding Encoding::UTF_7
end
it "returns nil when the second String is US-ASCII" do
@@ -91,14 +91,14 @@ describe "Encoding.compatible? String, String" do
end
it "returns the Encoding when the second's Encoding is not ASCII compatible but the same as the first's Encoding" do
- encoding = Encoding.compatible?(@str, "def".dup.force_encoding("utf-7"))
+ encoding = Encoding.compatible?(@str, "def".force_encoding("utf-7"))
encoding.should == Encoding::UTF_7
end
end
describe "when the first's Encoding is invalid" do
before :each do
- @str = "\xff".dup.force_encoding Encoding::UTF_8
+ @str = "\xff".force_encoding Encoding::UTF_8
end
it "returns the first's Encoding when the second's Encoding is US-ASCII" do
@@ -114,11 +114,11 @@ describe "Encoding.compatible? String, String" do
end
it "returns nil when the second's Encoding is invalid and ASCII only" do
- Encoding.compatible?(@str, "\x7f".dup.force_encoding("utf-16be")).should be_nil
+ Encoding.compatible?(@str, "\x7f".force_encoding("utf-16be")).should be_nil
end
it "returns nil when the second's Encoding is invalid and not ASCII only" do
- Encoding.compatible?(@str, "\xff".dup.force_encoding("utf-16be")).should be_nil
+ Encoding.compatible?(@str, "\xff".force_encoding("utf-16be")).should be_nil
end
it "returns the Encoding when the second's Encoding is invalid but the same as the first" do
@@ -129,7 +129,7 @@ describe "Encoding.compatible? String, String" do
describe "when the first String is empty and the second is not" do
describe "and the first's Encoding is ASCII compatible" do
before :each do
- @str = "".dup.force_encoding("utf-8")
+ @str = "".force_encoding("utf-8")
end
it "returns the first's encoding when the second String is ASCII only" do
@@ -143,7 +143,7 @@ describe "Encoding.compatible? String, String" do
describe "when the first's Encoding is not ASCII compatible" do
before :each do
- @str = "".dup.force_encoding Encoding::UTF_7
+ @str = "".force_encoding Encoding::UTF_7
end
it "returns the second string's encoding" do
@@ -154,7 +154,7 @@ describe "Encoding.compatible? String, String" do
describe "when the second String is empty" do
before :each do
- @str = "abc".dup.force_encoding("utf-7")
+ @str = "abc".force_encoding("utf-7")
end
it "returns the first Encoding" do
@@ -165,7 +165,7 @@ end
describe "Encoding.compatible? String, Regexp" do
it "returns US-ASCII if both are US-ASCII" do
- str = "abc".dup.force_encoding("us-ascii")
+ str = "abc".force_encoding("us-ascii")
Encoding.compatible?(str, /abc/).should == Encoding::US_ASCII
end
@@ -180,15 +180,15 @@ describe "Encoding.compatible? String, Regexp" do
it "returns the String's Encoding if the String is not ASCII only" do
[ [Encoding, "\xff", Encoding::BINARY],
[Encoding, "\u3042".encode("utf-8"), Encoding::UTF_8],
- [Encoding, "\xa4\xa2".dup.force_encoding("euc-jp"), Encoding::EUC_JP],
- [Encoding, "\x82\xa0".dup.force_encoding("shift_jis"), Encoding::Shift_JIS],
+ [Encoding, "\xa4\xa2".force_encoding("euc-jp"), Encoding::EUC_JP],
+ [Encoding, "\x82\xa0".force_encoding("shift_jis"), Encoding::Shift_JIS],
].should be_computed_by(:compatible?, /abc/)
end
end
describe "Encoding.compatible? String, Symbol" do
it "returns US-ASCII if both are ASCII only" do
- str = "abc".dup.force_encoding("us-ascii")
+ str = "abc".force_encoding("us-ascii")
Encoding.compatible?(str, :abc).should == Encoding::US_ASCII
end
@@ -203,8 +203,8 @@ describe "Encoding.compatible? String, Symbol" do
it "returns the String's Encoding if the String is not ASCII only" do
[ [Encoding, "\xff", Encoding::BINARY],
[Encoding, "\u3042".encode("utf-8"), Encoding::UTF_8],
- [Encoding, "\xa4\xa2".dup.force_encoding("euc-jp"), Encoding::EUC_JP],
- [Encoding, "\x82\xa0".dup.force_encoding("shift_jis"), Encoding::Shift_JIS],
+ [Encoding, "\xa4\xa2".force_encoding("euc-jp"), Encoding::EUC_JP],
+ [Encoding, "\x82\xa0".force_encoding("shift_jis"), Encoding::Shift_JIS],
].should be_computed_by(:compatible?, :abc)
end
end
@@ -221,8 +221,8 @@ describe "Encoding.compatible? String, Encoding" do
it "returns the String's encoding if the Encoding is US-ASCII" do
[ [Encoding, "\xff", Encoding::BINARY],
[Encoding, "\u3042".encode("utf-8"), Encoding::UTF_8],
- [Encoding, "\xa4\xa2".dup.force_encoding("euc-jp"), Encoding::EUC_JP],
- [Encoding, "\x82\xa0".dup.force_encoding("shift_jis"), Encoding::Shift_JIS],
+ [Encoding, "\xa4\xa2".force_encoding("euc-jp"), Encoding::EUC_JP],
+ [Encoding, "\x82\xa0".force_encoding("shift_jis"), Encoding::Shift_JIS],
].should be_computed_by(:compatible?, Encoding::US_ASCII)
end
@@ -242,7 +242,7 @@ end
describe "Encoding.compatible? Regexp, String" do
it "returns US-ASCII if both are US-ASCII" do
- str = "abc".dup.force_encoding("us-ascii")
+ str = "abc".force_encoding("us-ascii")
Encoding.compatible?(/abc/, str).should == Encoding::US_ASCII
end
@@ -256,8 +256,8 @@ describe "Encoding.compatible? Regexp, Regexp" do
it "returns the first's Encoding if it is not US-ASCII and not ASCII only" do
[ [Encoding, Regexp.new("\xff"), Encoding::BINARY],
[Encoding, Regexp.new("\u3042".encode("utf-8")), Encoding::UTF_8],
- [Encoding, Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp")), Encoding::EUC_JP],
- [Encoding, Regexp.new("\x82\xa0".dup.force_encoding("shift_jis")), Encoding::Shift_JIS],
+ [Encoding, Regexp.new("\xa4\xa2".force_encoding("euc-jp")), Encoding::EUC_JP],
+ [Encoding, Regexp.new("\x82\xa0".force_encoding("shift_jis")), Encoding::Shift_JIS],
].should be_computed_by(:compatible?, /abc/)
end
end
@@ -270,15 +270,15 @@ describe "Encoding.compatible? Regexp, Symbol" do
it "returns the first's Encoding if it is not US-ASCII and not ASCII only" do
[ [Encoding, Regexp.new("\xff"), Encoding::BINARY],
[Encoding, Regexp.new("\u3042".encode("utf-8")), Encoding::UTF_8],
- [Encoding, Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp")), Encoding::EUC_JP],
- [Encoding, Regexp.new("\x82\xa0".dup.force_encoding("shift_jis")), Encoding::Shift_JIS],
+ [Encoding, Regexp.new("\xa4\xa2".force_encoding("euc-jp")), Encoding::EUC_JP],
+ [Encoding, Regexp.new("\x82\xa0".force_encoding("shift_jis")), Encoding::Shift_JIS],
].should be_computed_by(:compatible?, /abc/)
end
end
describe "Encoding.compatible? Symbol, String" do
it "returns US-ASCII if both are ASCII only" do
- str = "abc".dup.force_encoding("us-ascii")
+ str = "abc".force_encoding("us-ascii")
Encoding.compatible?(str, :abc).should == Encoding::US_ASCII
end
end
@@ -291,8 +291,8 @@ describe "Encoding.compatible? Symbol, Regexp" do
it "returns the Regexp's Encoding if it is not US-ASCII and not ASCII only" do
a = Regexp.new("\xff")
b = Regexp.new("\u3042".encode("utf-8"))
- c = Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp"))
- d = Regexp.new("\x82\xa0".dup.force_encoding("shift_jis"))
+ c = Regexp.new("\xa4\xa2".force_encoding("euc-jp"))
+ d = Regexp.new("\x82\xa0".force_encoding("shift_jis"))
[ [Encoding, :abc, a, Encoding::BINARY],
[Encoding, :abc, b, Encoding::UTF_8],
@@ -310,8 +310,8 @@ describe "Encoding.compatible? Symbol, Symbol" do
it "returns the first's Encoding if it is not ASCII only" do
[ [Encoding, "\xff".to_sym, Encoding::BINARY],
[Encoding, "\u3042".encode("utf-8").to_sym, Encoding::UTF_8],
- [Encoding, "\xa4\xa2".dup.force_encoding("euc-jp").to_sym, Encoding::EUC_JP],
- [Encoding, "\x82\xa0".dup.force_encoding("shift_jis").to_sym, Encoding::Shift_JIS],
+ [Encoding, "\xa4\xa2".force_encoding("euc-jp").to_sym, Encoding::EUC_JP],
+ [Encoding, "\x82\xa0".force_encoding("shift_jis").to_sym, Encoding::Shift_JIS],
].should be_computed_by(:compatible?, :abc)
end
end
diff --git a/spec/ruby/core/encoding/converter/convert_spec.rb b/spec/ruby/core/encoding/converter/convert_spec.rb
index 7f249d90a3..95a9e0b758 100644
--- a/spec/ruby/core/encoding/converter/convert_spec.rb
+++ b/spec/ruby/core/encoding/converter/convert_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: binary -*-
-# frozen_string_literal: true
require_relative '../../../spec_helper'
describe "Encoding::Converter#convert" do
@@ -10,31 +9,31 @@ describe "Encoding::Converter#convert" do
it "sets the encoding of the result to the target encoding" do
ec = Encoding::Converter.new('ascii', 'utf-8')
- str = 'glark'.dup.force_encoding('ascii')
+ str = 'glark'.force_encoding('ascii')
ec.convert(str).encoding.should == Encoding::UTF_8
end
it "transcodes the given String to the target encoding" do
ec = Encoding::Converter.new("utf-8", "euc-jp")
- ec.convert("\u3042".dup.force_encoding('UTF-8')).should == \
- "\xA4\xA2".dup.force_encoding('EUC-JP')
+ ec.convert("\u3042".force_encoding('UTF-8')).should == \
+ "\xA4\xA2".force_encoding('EUC-JP')
end
it "allows Strings of different encodings to the source encoding" do
ec = Encoding::Converter.new('ascii', 'utf-8')
- str = 'glark'.dup.force_encoding('SJIS')
+ str = 'glark'.force_encoding('SJIS')
ec.convert(str).encoding.should == Encoding::UTF_8
end
it "reuses the given encoding pair if called multiple times" do
ec = Encoding::Converter.new('ascii', 'SJIS')
- ec.convert('a'.dup.force_encoding('ASCII')).should == 'a'.dup.force_encoding('SJIS')
- ec.convert('b'.dup.force_encoding('ASCII')).should == 'b'.dup.force_encoding('SJIS')
+ ec.convert('a'.force_encoding('ASCII')).should == 'a'.force_encoding('SJIS')
+ ec.convert('b'.force_encoding('ASCII')).should == 'b'.force_encoding('SJIS')
end
it "raises UndefinedConversionError if the String contains characters invalid for the target encoding" do
ec = Encoding::Converter.new('UTF-8', Encoding.find('macCyrillic'))
- -> { ec.convert("\u{6543}".dup.force_encoding('UTF-8')) }.should \
+ -> { ec.convert("\u{6543}".force_encoding('UTF-8')) }.should \
raise_error(Encoding::UndefinedConversionError)
end
diff --git a/spec/ruby/core/encoding/converter/finish_spec.rb b/spec/ruby/core/encoding/converter/finish_spec.rb
index 239243430b..11ca7e8510 100644
--- a/spec/ruby/core/encoding/converter/finish_spec.rb
+++ b/spec/ruby/core/encoding/converter/finish_spec.rb
@@ -16,8 +16,8 @@ describe "Encoding::Converter#finish" do
end
it "returns the last part of the converted String if it hasn't already" do
- @ec.convert("\u{9999}").should == "\e$B9a".dup.force_encoding('iso-2022-jp')
- @ec.finish.should == "\e(B".dup.force_encoding('iso-2022-jp')
+ @ec.convert("\u{9999}").should == "\e$B9a".force_encoding('iso-2022-jp')
+ @ec.finish.should == "\e(B".force_encoding('iso-2022-jp')
end
it "returns a String in the destination encoding" do
diff --git a/spec/ruby/core/encoding/converter/last_error_spec.rb b/spec/ruby/core/encoding/converter/last_error_spec.rb
index 78779be70b..68567737b7 100644
--- a/spec/ruby/core/encoding/converter/last_error_spec.rb
+++ b/spec/ruby/core/encoding/converter/last_error_spec.rb
@@ -9,45 +9,45 @@ describe "Encoding::Converter#last_error" do
it "returns nil when the last conversion did not produce an error" do
ec = Encoding::Converter.new('ascii','utf-8')
- ec.convert('a'.dup.force_encoding('ascii'))
+ ec.convert('a'.force_encoding('ascii'))
ec.last_error.should be_nil
end
it "returns nil when #primitive_convert last returned :destination_buffer_full" do
ec = Encoding::Converter.new("utf-8", "iso-2022-jp")
- ec.primitive_convert(+"\u{9999}", +"", 0, 0, partial_input: false) \
+ ec.primitive_convert("\u{9999}", "", 0, 0, partial_input: false) \
.should == :destination_buffer_full
ec.last_error.should be_nil
end
it "returns nil when #primitive_convert last returned :finished" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
- ec.primitive_convert("glark".dup.force_encoding('utf-8'), +"").should == :finished
+ ec.primitive_convert("glark".force_encoding('utf-8'),"").should == :finished
ec.last_error.should be_nil
end
it "returns nil if the last conversion succeeded but the penultimate failed" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
- ec.primitive_convert(+"\xf1abcd", +"").should == :invalid_byte_sequence
- ec.primitive_convert("glark".dup.force_encoding('utf-8'), +"").should == :finished
+ ec.primitive_convert("\xf1abcd","").should == :invalid_byte_sequence
+ ec.primitive_convert("glark".force_encoding('utf-8'),"").should == :finished
ec.last_error.should be_nil
end
it "returns an Encoding::InvalidByteSequenceError when #primitive_convert last returned :invalid_byte_sequence" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
- ec.primitive_convert(+"\xf1abcd", +"").should == :invalid_byte_sequence
+ ec.primitive_convert("\xf1abcd","").should == :invalid_byte_sequence
ec.last_error.should be_an_instance_of(Encoding::InvalidByteSequenceError)
end
it "returns an Encoding::UndefinedConversionError when #primitive_convert last returned :undefined_conversion" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
- ec.primitive_convert(+"\u{9876}", +"").should == :undefined_conversion
+ ec.primitive_convert("\u{9876}","").should == :undefined_conversion
ec.last_error.should be_an_instance_of(Encoding::UndefinedConversionError)
end
it "returns an Encoding::InvalidByteSequenceError when #primitive_convert last returned :incomplete_input" do
ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
- ec.primitive_convert(+"\xa4", +"", nil, 10).should == :incomplete_input
+ ec.primitive_convert("\xa4", "", nil, 10).should == :incomplete_input
ec.last_error.should be_an_instance_of(Encoding::InvalidByteSequenceError)
end
diff --git a/spec/ruby/core/encoding/converter/new_spec.rb b/spec/ruby/core/encoding/converter/new_spec.rb
index db9c3364d7..1f7affc72b 100644
--- a/spec/ruby/core/encoding/converter/new_spec.rb
+++ b/spec/ruby/core/encoding/converter/new_spec.rb
@@ -107,7 +107,7 @@ describe "Encoding::Converter.new" do
it "sets the replacement String to '\\uFFFD'" do
conv = Encoding::Converter.new("us-ascii", "utf-8", replace: nil)
- conv.replacement.should == "\u{fffd}".dup.force_encoding("utf-8")
+ conv.replacement.should == "\u{fffd}".force_encoding("utf-8")
end
it "sets the replacement String encoding to UTF-8" do
diff --git a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
index 63f25eddef..802d8e7cb1 100644
--- a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
+++ b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: binary -*-
-# frozen_string_literal: false
require_relative '../../../spec_helper'
describe "Encoding::Converter#primitive_convert" do
@@ -15,10 +14,6 @@ describe "Encoding::Converter#primitive_convert" do
-> { @ec.primitive_convert("","") }.should_not raise_error
end
- it "raises FrozenError when the destination buffer is a frozen String" do
- -> { @ec.primitive_convert("", "".freeze) }.should raise_error(FrozenError)
- end
-
it "accepts nil for the destination byte offset" do
-> { @ec.primitive_convert("","", nil) }.should_not raise_error
end
diff --git a/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb b/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
index 668eb9a924..1f836b259f 100644
--- a/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
+++ b/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: binary -*-
-# frozen_string_literal: false
require_relative '../../../spec_helper'
describe "Encoding::Converter#primitive_errinfo" do
diff --git a/spec/ruby/core/encoding/converter/putback_spec.rb b/spec/ruby/core/encoding/converter/putback_spec.rb
index e19fe6c314..c4e0a5da21 100644
--- a/spec/ruby/core/encoding/converter/putback_spec.rb
+++ b/spec/ruby/core/encoding/converter/putback_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../../spec_helper'
describe "Encoding::Converter#putback" do
before :each do
@ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
- @ret = @ec.primitive_convert(@src=+"abc\xa1def", @dst=+"", nil, 10)
+ @ret = @ec.primitive_convert(@src="abc\xa1def", @dst="", nil, 10)
end
it "returns a String" do
@@ -36,21 +36,21 @@ describe "Encoding::Converter#putback" do
it "returns the problematic bytes for UTF-16LE" do
ec = Encoding::Converter.new("utf-16le", "iso-8859-1")
- src = +"\x00\xd8\x61\x00"
- dst = +""
+ src = "\x00\xd8\x61\x00"
+ dst = ""
ec.primitive_convert(src, dst).should == :invalid_byte_sequence
ec.primitive_errinfo.should == [:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "a\x00"]
- ec.putback.should == "a\x00".dup.force_encoding("utf-16le")
+ ec.putback.should == "a\x00".force_encoding("utf-16le")
ec.putback.should == ""
end
it "accepts an integer argument corresponding to the number of bytes to be put back" do
ec = Encoding::Converter.new("utf-16le", "iso-8859-1")
- src = +"\x00\xd8\x61\x00"
- dst = +""
+ src = "\x00\xd8\x61\x00"
+ dst = ""
ec.primitive_convert(src, dst).should == :invalid_byte_sequence
ec.primitive_errinfo.should == [:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "a\x00"]
- ec.putback(2).should == "a\x00".dup.force_encoding("utf-16le")
+ ec.putback(2).should == "a\x00".force_encoding("utf-16le")
ec.putback.should == ""
end
end
diff --git a/spec/ruby/core/encoding/converter/replacement_spec.rb b/spec/ruby/core/encoding/converter/replacement_spec.rb
index ea514ca8dd..5ca42e7e5a 100644
--- a/spec/ruby/core/encoding/converter/replacement_spec.rb
+++ b/spec/ruby/core/encoding/converter/replacement_spec.rb
@@ -13,7 +13,7 @@ describe "Encoding::Converter#replacement" do
it "returns \\uFFFD when the destination encoding is UTF-8" do
ec = Encoding::Converter.new("us-ascii", "utf-8")
- ec.replacement.should == "\u{fffd}".dup.force_encoding('utf-8')
+ ec.replacement.should == "\u{fffd}".force_encoding('utf-8')
ec.replacement.encoding.should == Encoding::UTF_8
end
end
@@ -38,33 +38,33 @@ describe "Encoding::Converter#replacement=" do
it "sets #replacement" do
ec = Encoding::Converter.new("us-ascii", "utf-8")
- ec.replacement.should == "\u{fffd}".dup.force_encoding('utf-8')
+ ec.replacement.should == "\u{fffd}".force_encoding('utf-8')
ec.replacement = '?'.encode('utf-8')
- ec.replacement.should == '?'.dup.force_encoding('utf-8')
+ ec.replacement.should == '?'.force_encoding('utf-8')
end
it "raises an UndefinedConversionError is the argument cannot be converted into the destination encoding" do
ec = Encoding::Converter.new("sjis", "ascii")
- utf8_q = "\u{986}".dup.force_encoding('utf-8')
- ec.primitive_convert(utf8_q.dup, +"").should == :undefined_conversion
+ utf8_q = "\u{986}".force_encoding('utf-8')
+ ec.primitive_convert(utf8_q.dup, "").should == :undefined_conversion
-> { ec.replacement = utf8_q }.should \
raise_error(Encoding::UndefinedConversionError)
end
it "does not change the replacement character if the argument cannot be converted into the destination encoding" do
ec = Encoding::Converter.new("sjis", "ascii")
- utf8_q = "\u{986}".dup.force_encoding('utf-8')
- ec.primitive_convert(utf8_q.dup, +"").should == :undefined_conversion
+ utf8_q = "\u{986}".force_encoding('utf-8')
+ ec.primitive_convert(utf8_q.dup, "").should == :undefined_conversion
-> { ec.replacement = utf8_q }.should \
raise_error(Encoding::UndefinedConversionError)
- ec.replacement.should == "?".dup.force_encoding('us-ascii')
+ ec.replacement.should == "?".force_encoding('us-ascii')
end
it "uses the replacement character" do
ec = Encoding::Converter.new("utf-8", "us-ascii", :invalid => :replace, :undef => :replace)
ec.replacement = "!"
- dest = +""
- status = ec.primitive_convert(+"中文123", dest)
+ dest = ""
+ status = ec.primitive_convert "中文123", dest
status.should == :finished
dest.should == "!!123"
diff --git a/spec/ruby/core/encoding/default_external_spec.rb b/spec/ruby/core/encoding/default_external_spec.rb
index 9aae4976e0..682d49d37c 100644
--- a/spec/ruby/core/encoding/default_external_spec.rb
+++ b/spec/ruby/core/encoding/default_external_spec.rb
@@ -18,9 +18,11 @@ describe "Encoding.default_external" do
Encoding.default_external.should == Encoding::SHIFT_JIS
end
- platform_is :windows do
- it 'is UTF-8 by default on Windows' do
- Encoding.default_external.should == Encoding::UTF_8
+ ruby_version_is "3.0" do
+ platform_is :windows do
+ it 'is UTF-8 by default on Windows' do
+ Encoding.default_external.should == Encoding::UTF_8
+ end
end
end
end
diff --git a/spec/ruby/core/encoding/inspect_spec.rb b/spec/ruby/core/encoding/inspect_spec.rb
index df96141db9..9a930b2a77 100644
--- a/spec/ruby/core/encoding/inspect_spec.rb
+++ b/spec/ruby/core/encoding/inspect_spec.rb
@@ -5,23 +5,9 @@ describe "Encoding#inspect" do
Encoding::UTF_8.inspect.should be_an_instance_of(String)
end
- ruby_version_is ""..."3.4" do
- it "returns #<Encoding:name> for a non-dummy encoding named 'name'" do
- Encoding.list.to_a.reject {|e| e.dummy? }.each do |enc|
- enc.inspect.should =~ /#<Encoding:#{enc.name}>/
- end
- end
- end
-
- ruby_version_is "3.4" do
- it "returns #<Encoding:name> for a non-dummy encoding named 'name'" do
- Encoding.list.to_a.reject {|e| e.dummy? }.each do |enc|
- if enc.name == "ASCII-8BIT"
- enc.inspect.should == "#<Encoding:BINARY (ASCII-8BIT)>"
- else
- enc.inspect.should =~ /#<Encoding:#{enc.name}>/
- end
- end
+ it "returns #<Encoding:name> for a non-dummy encoding named 'name'" do
+ Encoding.list.to_a.reject {|e| e.dummy? }.each do |enc|
+ enc.inspect.should =~ /#<Encoding:#{enc.name}>/
end
end
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb
index 2b15fc1a0f..f5fa6f55e3 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#destination_encoding_name" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb
index c2ed6de1d8..43be3ddd71 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#destination_encoding" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
index d2fc360dce..a8f7354b16 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: binary -*-
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#error_bytes" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb
index 8a3f3de69a..94201a9b15 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb
@@ -8,7 +8,7 @@ describe "Encoding::InvalidByteSequenceError#incomplete_input?" do
it "returns true if #primitive_convert returned :incomplete_input for the same data" do
ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
- ec.primitive_convert(+"\xA1", +'').should == :incomplete_input
+ ec.primitive_convert("\xA1",'').should == :incomplete_input
begin
ec.convert("\xA1")
rescue Encoding::InvalidByteSequenceError => e
@@ -18,7 +18,7 @@ describe "Encoding::InvalidByteSequenceError#incomplete_input?" do
it "returns false if #primitive_convert returned :invalid_byte_sequence for the same data" do
ec = Encoding::Converter.new("ascii", "utf-8")
- ec.primitive_convert(+"\xfffffffff", +'').should == :invalid_byte_sequence
+ ec.primitive_convert("\xfffffffff",'').should == :invalid_byte_sequence
begin
ec.convert("\xfffffffff")
rescue Encoding::InvalidByteSequenceError => e
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb
index a5e2824984..93823b5db4 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: binary -*-
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#readagain_bytes" do
@@ -15,11 +14,11 @@ describe "Encoding::InvalidByteSequenceError#readagain_bytes" do
it "returns the bytes to be read again" do
@exception.readagain_bytes.size.should == 1
- @exception.readagain_bytes.should == "a".dup.force_encoding('binary')
+ @exception.readagain_bytes.should == "a".force_encoding('binary')
@exception.readagain_bytes.should == @errinfo[-1]
@exception2.readagain_bytes.size.should == 1
- @exception2.readagain_bytes.should == "\xFF".dup.force_encoding('binary')
+ @exception2.readagain_bytes.should == "\xFF".force_encoding('binary')
@exception2.readagain_bytes.should == @errinfo2[-1]
end
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
index a9464114a8..bd3a51cbc5 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#source_encoding_name" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
index 7fdc0a122b..f43d6d5830 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#source_encoding" do
diff --git a/spec/ruby/core/encoding/name_spec.rb b/spec/ruby/core/encoding/name_spec.rb
index dce9347978..5eadb1d2f5 100644
--- a/spec/ruby/core/encoding/name_spec.rb
+++ b/spec/ruby/core/encoding/name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative 'shared/name'
describe "Encoding#name" do
diff --git a/spec/ruby/core/encoding/replicate_spec.rb b/spec/ruby/core/encoding/replicate_spec.rb
index e22673db7d..848415eeb4 100644
--- a/spec/ruby/core/encoding/replicate_spec.rb
+++ b/spec/ruby/core/encoding/replicate_spec.rb
@@ -18,8 +18,8 @@ describe "Encoding#replicate" do
e.name.should == name
Encoding.find(name).should == e
- "a".dup.force_encoding(e).valid_encoding?.should be_true
- "\x80".dup.force_encoding(e).valid_encoding?.should be_false
+ "a".force_encoding(e).valid_encoding?.should be_true
+ "\x80".force_encoding(e).valid_encoding?.should be_false
end
it "returns a replica of UTF-8" do
@@ -28,9 +28,9 @@ describe "Encoding#replicate" do
e.name.should == name
Encoding.find(name).should == e
- "a".dup.force_encoding(e).valid_encoding?.should be_true
- "\u3042".dup.force_encoding(e).valid_encoding?.should be_true
- "\x80".dup.force_encoding(e).valid_encoding?.should be_false
+ "a".force_encoding(e).valid_encoding?.should be_true
+ "\u3042".force_encoding(e).valid_encoding?.should be_true
+ "\x80".force_encoding(e).valid_encoding?.should be_false
end
it "returns a replica of UTF-16BE" do
@@ -39,9 +39,9 @@ describe "Encoding#replicate" do
e.name.should == name
Encoding.find(name).should == e
- "a".dup.force_encoding(e).valid_encoding?.should be_false
- "\x30\x42".dup.force_encoding(e).valid_encoding?.should be_true
- "\x80".dup.force_encoding(e).valid_encoding?.should be_false
+ "a".force_encoding(e).valid_encoding?.should be_false
+ "\x30\x42".force_encoding(e).valid_encoding?.should be_true
+ "\x80".force_encoding(e).valid_encoding?.should be_false
end
it "returns a replica of ISO-2022-JP" do
@@ -61,25 +61,12 @@ describe "Encoding#replicate" do
e.name.should == name
Encoding.find(name).should == e
- s = "abc".dup.force_encoding(e)
+ s = "abc".force_encoding(e)
s.encoding.should == e
s.encoding.name.should == name
end
end
- ruby_version_is "3.2"..."3.3" do
- it "warns about deprecation" do
- -> {
- Encoding::US_ASCII.replicate('MY-US-ASCII')
- }.should complain(/warning: Encoding#replicate is deprecated and will be removed in Ruby 3.3; use the original encoding instead/)
- end
-
- it "raises EncodingError if too many encodings" do
- code = '1_000.times {|i| Encoding::US_ASCII.replicate("R_#{i}") }'
- ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
- end
- end
-
ruby_version_is "3.3" do
it "has been removed" do
Encoding::US_ASCII.should_not.respond_to?(:replicate, true)
diff --git a/spec/ruby/core/encoding/to_s_spec.rb b/spec/ruby/core/encoding/to_s_spec.rb
index bab394a888..82d282386b 100644
--- a/spec/ruby/core/encoding/to_s_spec.rb
+++ b/spec/ruby/core/encoding/to_s_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative 'shared/name'
describe "Encoding#to_s" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb
index a51a9f46a0..106fc7ecac 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#destination_encoding_name" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb
index 905556407c..c6e24732fd 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#destination_encoding" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb
index 9cb55e6d95..780d81c1ee 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#error_char" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
index d5e60e78db..3b697cb82f 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#source_encoding_name" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
index de456a4b5a..9101d51e11 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#source_encoding" do
diff --git a/spec/ruby/core/enumerable/all_spec.rb b/spec/ruby/core/enumerable/all_spec.rb
index 160cd52628..0ded1e8eba 100644
--- a/spec/ruby/core/enumerable/all_spec.rb
+++ b/spec/ruby/core/enumerable/all_spec.rb
@@ -177,11 +177,5 @@ describe "Enumerable#all?" do
multi.all?(pattern).should == true
pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]]
end
-
- it "ignores the block if there is an argument" do
- -> {
- EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).all?(String) { true }.should == false
- }.should complain(/given block not used/)
- end
end
end
diff --git a/spec/ruby/core/enumerable/any_spec.rb b/spec/ruby/core/enumerable/any_spec.rb
index 243f8735d5..355cd0c290 100644
--- a/spec/ruby/core/enumerable/any_spec.rb
+++ b/spec/ruby/core/enumerable/any_spec.rb
@@ -190,11 +190,5 @@ describe "Enumerable#any?" do
multi.any?(pattern).should == false
pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]]
end
-
- it "ignores the block if there is an argument" do
- -> {
- EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).any?(String) { true }.should == false
- }.should complain(/given block not used/)
- end
end
end
diff --git a/spec/ruby/core/enumerable/chunk_spec.rb b/spec/ruby/core/enumerable/chunk_spec.rb
index ed6304307f..c5579d67fa 100644
--- a/spec/ruby/core/enumerable/chunk_spec.rb
+++ b/spec/ruby/core/enumerable/chunk_spec.rb
@@ -29,11 +29,6 @@ describe "Enumerable#chunk" do
result.should == [[1, [1, 2]], [0, [3]], [1, [2]], [0, [3]], [1, [2, 1]]]
end
- it "returns a partitioned Array of values" do
- e = EnumerableSpecs::Numerous.new(1,2,3)
- e.chunk { |x| x > 2 }.map(&:last).should == [[1, 2], [3]]
- end
-
it "returns elements for which the block returns :_alone in separate Arrays" do
e = EnumerableSpecs::Numerous.new(1, 2, 3, 2, 1)
result = e.chunk { |x| x < 2 && :_alone }.to_a
diff --git a/spec/ruby/core/enumerable/fixtures/classes.rb b/spec/ruby/core/enumerable/fixtures/classes.rb
index 2701c6999c..fb4951c6e6 100644
--- a/spec/ruby/core/enumerable/fixtures/classes.rb
+++ b/spec/ruby/core/enumerable/fixtures/classes.rb
@@ -342,10 +342,4 @@ module EnumerableSpecs
@block.call(*args)
end
end
-
- # Set is a core class since Ruby 3.2
- ruby_version_is '3.2' do
- class SetSubclass < Set
- end
- end
end # EnumerableSpecs utility classes
diff --git a/spec/ruby/core/enumerable/grep_spec.rb b/spec/ruby/core/enumerable/grep_spec.rb
index 989358f01b..b81075291f 100644
--- a/spec/ruby/core/enumerable/grep_spec.rb
+++ b/spec/ruby/core/enumerable/grep_spec.rb
@@ -40,28 +40,43 @@ describe "Enumerable#grep" do
$~.should == nil
end
- it "does not set $~ when given no block" do
- "z" =~ /z/ # Reset $~
- ["abc", "def"].grep(/b/).should == ["abc"]
- $&.should == "z"
- end
+ ruby_version_is ""..."3.0.0" do
+ it "sets $~ to the last match when given no block" do
+ "z" =~ /z/ # Reset $~
+ ["abc", "def"].grep(/b/).should == ["abc"]
+
+ # Set by the failed match of "def"
+ $~.should == nil
- it "does not modify Regexp.last_match without block" do
- "z" =~ /z/ # Reset last match
- ["abc", "def"].grep(/b/).should == ["abc"]
- Regexp.last_match[0].should == "z"
+ ["abc", "def"].grep(/e/)
+ $&.should == "e"
+ end
end
- it "correctly handles non-string elements" do
- 'set last match' =~ /set last (.*)/
- [:a, 'b', 'z', :c, 42, nil].grep(/[a-d]/).should == [:a, 'b', :c]
- $1.should == 'match'
+ ruby_version_is "3.0.0" do
+ it "does not set $~ when given no block" do
+ "z" =~ /z/ # Reset $~
+ ["abc", "def"].grep(/b/).should == ["abc"]
+ $&.should == "z"
+ end
- o = Object.new
- def o.to_str
- 'hello'
+ it "does not modify Regexp.last_match without block" do
+ "z" =~ /z/ # Reset last match
+ ["abc", "def"].grep(/b/).should == ["abc"]
+ Regexp.last_match[0].should == "z"
+ end
+
+ it "correctly handles non-string elements" do
+ 'set last match' =~ /set last (.*)/
+ [:a, 'b', 'z', :c, 42, nil].grep(/[a-d]/).should == [:a, 'b', :c]
+ $1.should == 'match'
+
+ o = Object.new
+ def o.to_str
+ 'hello'
+ end
+ [o].grep(/ll/).first.should.equal?(o)
end
- [o].grep(/ll/).first.should.equal?(o)
end
describe "with a block" do
diff --git a/spec/ruby/core/enumerable/grep_v_spec.rb b/spec/ruby/core/enumerable/grep_v_spec.rb
index ba19216968..35fde27eb6 100644
--- a/spec/ruby/core/enumerable/grep_v_spec.rb
+++ b/spec/ruby/core/enumerable/grep_v_spec.rb
@@ -20,28 +20,43 @@ describe "Enumerable#grep_v" do
$&.should == "e"
end
- it "does not set $~ when given no block" do
- "z" =~ /z/ # Reset $~
- ["abc", "def"].grep_v(/e/).should == ["abc"]
- $&.should == "z"
- end
+ ruby_version_is ""..."3.0.0" do
+ it "sets $~ to the last match when given no block" do
+ "z" =~ /z/ # Reset $~
+ ["abc", "def"].grep_v(/e/).should == ["abc"]
- it "does not modify Regexp.last_match without block" do
- "z" =~ /z/ # Reset last match
- ["abc", "def"].grep_v(/e/).should == ["abc"]
- Regexp.last_match[0].should == "z"
+ # Set by the match of "def"
+ $&.should == "e"
+
+ ["abc", "def"].grep_v(/b/)
+ $&.should == nil
+ end
end
- it "correctly handles non-string elements" do
- 'set last match' =~ /set last (.*)/
- [:a, 'b', 'z', :c, 42, nil].grep_v(/[a-d]/).should == ['z', 42, nil]
- $1.should == 'match'
+ ruby_version_is "3.0.0" do
+ it "does not set $~ when given no block" do
+ "z" =~ /z/ # Reset $~
+ ["abc", "def"].grep_v(/e/).should == ["abc"]
+ $&.should == "z"
+ end
+
+ it "does not modify Regexp.last_match without block" do
+ "z" =~ /z/ # Reset last match
+ ["abc", "def"].grep_v(/e/).should == ["abc"]
+ Regexp.last_match[0].should == "z"
+ end
+
+ it "correctly handles non-string elements" do
+ 'set last match' =~ /set last (.*)/
+ [:a, 'b', 'z', :c, 42, nil].grep_v(/[a-d]/).should == ['z', 42, nil]
+ $1.should == 'match'
- o = Object.new
- def o.to_str
- 'hello'
+ o = Object.new
+ def o.to_str
+ 'hello'
+ end
+ [o].grep_v(/mm/).first.should.equal?(o)
end
- [o].grep_v(/mm/).first.should.equal?(o)
end
describe "without block" do
diff --git a/spec/ruby/core/enumerable/none_spec.rb b/spec/ruby/core/enumerable/none_spec.rb
index fb42f13386..99bb7f7a4e 100644
--- a/spec/ruby/core/enumerable/none_spec.rb
+++ b/spec/ruby/core/enumerable/none_spec.rb
@@ -143,11 +143,5 @@ describe "Enumerable#none?" do
multi.none?(pattern).should == true
pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]]
end
-
- it "ignores the block if there is an argument" do
- -> {
- EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).none?(String) { true }.should == true
- }.should complain(/given block not used/)
- end
end
end
diff --git a/spec/ruby/core/enumerable/one_spec.rb b/spec/ruby/core/enumerable/one_spec.rb
index 4bf8623d2e..47bfd65a0f 100644
--- a/spec/ruby/core/enumerable/one_spec.rb
+++ b/spec/ruby/core/enumerable/one_spec.rb
@@ -83,6 +83,7 @@ describe "Enumerable#one?" do
end
end
+
describe 'when given a pattern argument' do
it "calls `===` on the pattern the return value " do
pattern = EnumerableSpecs::Pattern.new { |x| x == 1 }
@@ -144,11 +145,5 @@ describe "Enumerable#one?" do
multi.one?(pattern).should == false
pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]]
end
-
- it "ignores the block if there is an argument" do
- -> {
- EnumerableSpecs::Numerous.new(1, 2, 3, 4, "5").one?(String) { false }.should == true
- }.should complain(/given block not used/)
- end
end
end
diff --git a/spec/ruby/core/enumerable/shared/inject.rb b/spec/ruby/core/enumerable/shared/inject.rb
index 92f220efa4..c5907f92d8 100644
--- a/spec/ruby/core/enumerable/shared/inject.rb
+++ b/spec/ruby/core/enumerable/shared/inject.rb
@@ -1,5 +1,3 @@
-require_relative '../../array/shared/iterable_and_tolerating_size_increasing'
-
describe :enumerable_inject, shared: true do
it "with argument takes a block with an accumulator (with argument as initial value) and the current element. Value of block becomes new accumulator" do
a = []
@@ -16,65 +14,15 @@ describe :enumerable_inject, shared: true do
it "can take two argument" do
EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, :-).should == 4
- EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, "-").should == 4
-
- [1, 2, 3].send(@method, 10, :-).should == 4
- [1, 2, 3].send(@method, 10, "-").should == 4
- end
-
- it "converts non-Symbol method name argument to String with #to_str if two arguments" do
- name = Object.new
- def name.to_str; "-"; end
-
- EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, name).should == 4
- [1, 2, 3].send(@method, 10, name).should == 4
- end
-
- it "raises TypeError when the second argument is not Symbol or String and it cannot be converted to String if two arguments" do
- -> { EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, Object.new) }.should raise_error(TypeError, /is not a symbol nor a string/)
- -> { [1, 2, 3].send(@method, 10, Object.new) }.should raise_error(TypeError, /is not a symbol nor a string/)
end
it "ignores the block if two arguments" do
- -> {
- EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, :-) { raise "we never get here"}.should == 4
- }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
-
- -> {
- [1, 2, 3].send(@method, 10, :-) { raise "we never get here"}.should == 4
- }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
- end
-
- it "does not warn when given a Symbol with $VERBOSE true" do
- -> {
- [1, 2].send(@method, 0, :+)
- [1, 2].send(@method, :+)
- EnumerableSpecs::Numerous.new(1, 2).send(@method, 0, :+)
- EnumerableSpecs::Numerous.new(1, 2).send(@method, :+)
- }.should_not complain(verbose: true)
+ EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, :-) { raise "we never get here"}.should == 4
+ [].send(@method, 3, :+) { raise "we never get here"}.should == 3
end
it "can take a symbol argument" do
EnumerableSpecs::Numerous.new(10, 1, 2, 3).send(@method, :-).should == 4
- [10, 1, 2, 3].send(@method, :-).should == 4
- end
-
- it "can take a String argument" do
- EnumerableSpecs::Numerous.new(10, 1, 2, 3).send(@method, "-").should == 4
- [10, 1, 2, 3].send(@method, "-").should == 4
- end
-
- it "converts non-Symbol method name argument to String with #to_str" do
- name = Object.new
- def name.to_str; "-"; end
-
- EnumerableSpecs::Numerous.new(10, 1, 2, 3).send(@method, name).should == 4
- [10, 1, 2, 3].send(@method, name).should == 4
- end
-
- it "raises TypeError when passed not Symbol or String method name argument and it cannot be converted to String" do
- -> { EnumerableSpecs::Numerous.new(10, 1, 2, 3).send(@method, Object.new) }.should raise_error(TypeError, /is not a symbol nor a string/)
- -> { [10, 1, 2, 3].send(@method, Object.new) }.should raise_error(TypeError, /is not a symbol nor a string/)
end
it "without argument takes a block with an accumulator (with first element as initial value) and the current element. Value of block becomes new accumulator" do
@@ -83,10 +31,10 @@ describe :enumerable_inject, shared: true do
a.should == [[2, 5], [5, 3], [3, 6], [6, 1], [1, 4]]
end
- it "gathers whole arrays as elements when each yields multiple" do
- multi = EnumerableSpecs::YieldsMulti.new
- multi.send(@method, []) {|acc, e| acc << e }.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]]
- end
+ it "gathers whole arrays as elements when each yields multiple" do
+ multi = EnumerableSpecs::YieldsMulti.new
+ multi.send(@method, []) {|acc, e| acc << e }.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]]
+ end
it "with inject arguments(legacy rubycon)" do
# with inject argument
@@ -113,28 +61,13 @@ describe :enumerable_inject, shared: true do
EnumerableSpecs::EachDefiner.new('a','b','c').send(@method) {|result, i| i+result}.should == "cba"
EnumerableSpecs::EachDefiner.new(3, 4, 5).send(@method) {|result, i| result*i}.should == 60
EnumerableSpecs::EachDefiner.new([1], 2, 'a','b').send(@method){|r,i| r<<i}.should == [1, 2, 'a', 'b']
+
end
it "returns nil when fails(legacy rubycon)" do
EnumerableSpecs::EachDefiner.new().send(@method) {|acc,x| 999 }.should == nil
end
- it "tolerates increasing a collection size during iterating Array" do
- array = [:a, :b, :c]
- ScratchPad.record []
- i = 0
-
- array.send(@method, nil) do |_, e|
- ScratchPad << e
- array << i if i < 100
- i += 1
- end
-
- actual = ScratchPad.recorded
- expected = [:a, :b, :c] + (0..99).to_a
- actual.sort_by(&:to_s).should == expected.sort_by(&:to_s)
- end
-
ruby_bug '#18635', ''...'3.2' do
it "raises an ArgumentError when no parameters or block is given" do
-> { [1,2].send(@method) }.should raise_error(ArgumentError)
diff --git a/spec/ruby/core/enumerable/sum_spec.rb b/spec/ruby/core/enumerable/sum_spec.rb
index 2eb74db6ac..fc173e4173 100644
--- a/spec/ruby/core/enumerable/sum_spec.rb
+++ b/spec/ruby/core/enumerable/sum_spec.rb
@@ -40,7 +40,7 @@ describe 'Enumerable#sum' do
end
# https://bugs.ruby-lang.org/issues/12217
- # https://github.com/ruby/ruby/blob/master/doc/ChangeLog/ChangeLog-2.4.0#L6208-L6214
+ # https://github.com/ruby/ruby/blob/master/doc/ChangeLog-2.4.0#L6208-L6214
it "uses Kahan's compensated summation algorithm for precise sum of float numbers" do
floats = [2.7800000000000002, 5.0, 2.5, 4.44, 3.89, 3.89, 4.44, 7.78, 5.0, 2.7800000000000002, 5.0, 2.5].to_enum
naive_sum = floats.reduce { |sum, e| sum + e }
diff --git a/spec/ruby/core/enumerable/tally_spec.rb b/spec/ruby/core/enumerable/tally_spec.rb
index e0edc8dc75..f09a8f533a 100644
--- a/spec/ruby/core/enumerable/tally_spec.rb
+++ b/spec/ruby/core/enumerable/tally_spec.rb
@@ -49,13 +49,6 @@ ruby_version_is "3.1" do
enum.tally(hash).should equal(hash)
end
- it "calls #to_hash to convert argument to Hash implicitly if passed not a Hash" do
- enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
- object = Object.new
- def object.to_hash; { 'foo' => 1 }; end
- enum.tally(object).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
- end
-
it "raises a FrozenError and does not update the given hash when the hash is frozen" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
hash = { 'foo' => 1 }.freeze
@@ -63,12 +56,6 @@ ruby_version_is "3.1" do
hash.should == { 'foo' => 1 }
end
- it "raises a FrozenError even if enumerable is empty" do
- enum = EnumerableSpecs::Numerous.new()
- hash = { 'foo' => 1 }.freeze
- -> { enum.tally(hash) }.should raise_error(FrozenError)
- end
-
it "does not call given block" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally({ 'foo' => 1 }) { |v| ScratchPad << v }
diff --git a/spec/ruby/core/enumerable/to_h_spec.rb b/spec/ruby/core/enumerable/to_h_spec.rb
index 11a4933c10..0489134552 100644
--- a/spec/ruby/core/enumerable/to_h_spec.rb
+++ b/spec/ruby/core/enumerable/to_h_spec.rb
@@ -53,14 +53,6 @@ describe "Enumerable#to_h" do
@enum.to_h { |k| [k, k.to_s] }.should == { a: 'a', b: 'b' }
end
- it "passes to a block each element as a single argument" do
- enum_of_arrays = EnumerableSpecs::EachDefiner.new([:a, 1], [:b, 2])
-
- ScratchPad.record []
- enum_of_arrays.to_h { |*args| ScratchPad << args; [args[0], args[1]] }
- ScratchPad.recorded.sort.should == [[[:a, 1]], [[:b, 2]]]
- end
-
it "raises ArgumentError if block returns longer or shorter array" do
-> do
@enum.to_h { |k| [k, k.to_s, 1] }
diff --git a/spec/ruby/core/enumerable/to_set_spec.rb b/spec/ruby/core/enumerable/to_set_spec.rb
deleted file mode 100644
index c21a2772c4..0000000000
--- a/spec/ruby/core/enumerable/to_set_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-ruby_version_is "3.2" do
- describe "Enumerable#to_set" do
- it "returns a new Set created from self" do
- [1, 2, 3].to_set.should == Set[1, 2, 3]
- {a: 1, b: 2}.to_set.should == Set[[:b, 2], [:a, 1]]
- end
-
- it "passes down passed blocks" do
- [1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9]
- end
-
- it "instantiates an object of provided as the first argument set class" do
- set = [1, 2, 3].to_set(EnumerableSpecs::SetSubclass)
- set.should be_kind_of(EnumerableSpecs::SetSubclass)
- set.to_a.sort.should == [1, 2, 3]
- end
-
- it "does not need explicit `require 'set'`" do
- output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1')
- puts [1, 2, 3].to_set
- RUBY
-
- output.chomp.should == "#<Set: {1, 2, 3}>"
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/chain/initialize_spec.rb b/spec/ruby/core/enumerator/chain/initialize_spec.rb
index daa30351d7..69484dfcb4 100644
--- a/spec/ruby/core/enumerator/chain/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/chain/initialize_spec.rb
@@ -22,10 +22,10 @@ describe "Enumerator::Chain#initialize" do
end
describe "on frozen instance" do
- it "raises a FrozenError" do
+ it "raises a RuntimeError" do
-> {
@uninitialized.freeze.send(:initialize)
- }.should raise_error(FrozenError)
+ }.should raise_error(RuntimeError)
end
end
end
diff --git a/spec/ruby/core/enumerator/chain/inspect_spec.rb b/spec/ruby/core/enumerator/chain/inspect_spec.rb
index 9b5a442b75..a0450c808a 100644
--- a/spec/ruby/core/enumerator/chain/inspect_spec.rb
+++ b/spec/ruby/core/enumerator/chain/inspect_spec.rb
@@ -11,8 +11,4 @@ describe "Enumerator::Chain#inspect" do
obj.should_receive(:inspect).and_return('some desc')
Enumerator::Chain.new(obj).inspect.should == "#<Enumerator::Chain: [some desc]>"
end
-
- it "returns a not initialized representation if #initialized is not called yet" do
- Enumerator::Chain.allocate.inspect.should == "#<Enumerator::Chain: uninitialized>"
- end
end
diff --git a/spec/ruby/core/enumerator/each_spec.rb b/spec/ruby/core/enumerator/each_spec.rb
index 3af16e5587..99ac3120af 100644
--- a/spec/ruby/core/enumerator/each_spec.rb
+++ b/spec/ruby/core/enumerator/each_spec.rb
@@ -10,41 +10,41 @@ describe "Enumerator#each" do
@enum_with_arguments = object_each_with_arguments.to_enum(:each_with_arguments, :arg0, :arg1, :arg2)
- @enum_with_yielder = Enumerator.new { |y| y.yield :ok }
+ @enum_with_yielder = Enumerator.new {|y| y.yield :ok}
end
it "yields each element of self to the given block" do
acc = []
- [1, 2, 3].to_enum.each { |e| acc << e }
- acc.should == [1, 2, 3]
+ [1,2,3].to_enum.each {|e| acc << e }
+ acc.should == [1,2,3]
end
it "calls #each on the object given in the constructor by default" do
each = mock('each')
each.should_receive(:each)
- each.to_enum.each { |e| e }
+ each.to_enum.each {|e| e }
end
it "calls #each on the underlying object until it's exhausted" do
each = mock('each')
each.should_receive(:each).and_yield(1).and_yield(2).and_yield(3)
acc = []
- each.to_enum.each { |e| acc << e }
- acc.should == [1, 2, 3]
+ each.to_enum.each {|e| acc << e }
+ acc.should == [1,2,3]
end
it "calls the method given in the constructor instead of #each" do
each = mock('peach')
each.should_receive(:peach)
- each.to_enum(:peach).each { |e| e }
+ each.to_enum(:peach).each {|e| e }
end
it "calls the method given in the constructor until it's exhausted" do
each = mock('peach')
each.should_receive(:peach).and_yield(1).and_yield(2).and_yield(3)
acc = []
- each.to_enum(:peach).each { |e| acc << e }
- acc.should == [1, 2, 3]
+ each.to_enum(:peach).each {|e| acc << e }
+ acc.should == [1,2,3]
end
it "raises a NoMethodError if the object doesn't respond to #each" do
diff --git a/spec/ruby/core/enumerator/generator/initialize_spec.rb b/spec/ruby/core/enumerator/generator/initialize_spec.rb
index acc1174253..f75c7d6f26 100644
--- a/spec/ruby/core/enumerator/generator/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/generator/initialize_spec.rb
@@ -17,10 +17,10 @@ describe "Enumerator::Generator#initialize" do
end
describe "on frozen instance" do
- it "raises a FrozenError" do
+ it "raises a RuntimeError" do
-> {
@uninitialized.freeze.send(:initialize) {}
- }.should raise_error(FrozenError)
+ }.should raise_error(RuntimeError)
end
end
end
diff --git a/spec/ruby/core/enumerator/initialize_spec.rb b/spec/ruby/core/enumerator/initialize_spec.rb
index 5e0256ca46..217af1d3bc 100644
--- a/spec/ruby/core/enumerator/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/initialize_spec.rb
@@ -11,6 +11,14 @@ describe "Enumerator#initialize" do
Enumerator.should have_private_instance_method(:initialize, false)
end
+ ruby_version_is ''...'3.0' do
+ it "returns self when given an object" do
+ suppress_warning do
+ @uninitialized.send(:initialize, Object.new).should equal(@uninitialized)
+ end
+ end
+ end
+
it "returns self when given a block" do
@uninitialized.send(:initialize) {}.should equal(@uninitialized)
end
@@ -48,10 +56,10 @@ describe "Enumerator#initialize" do
end
describe "on frozen instance" do
- it "raises a FrozenError" do
+ it "raises a RuntimeError" do
-> {
@uninitialized.freeze.send(:initialize) {}
- }.should raise_error(FrozenError)
+ }.should raise_error(RuntimeError)
end
end
end
diff --git a/spec/ruby/core/enumerator/inspect_spec.rb b/spec/ruby/core/enumerator/inspect_spec.rb
index 7e97864246..3bcf07e754 100644
--- a/spec/ruby/core/enumerator/inspect_spec.rb
+++ b/spec/ruby/core/enumerator/inspect_spec.rb
@@ -14,9 +14,4 @@ describe "Enumerator#inspect" do
(1..3).each.each_slice(2).inspect.should == "#<Enumerator: #<Enumerator: 1..3:each>:each_slice(2)>"
end
end
-
- it "returns a not initialized representation if #initialized is not called yet" do
- Enumerator.allocate.inspect.should == "#<Enumerator: uninitialized>"
- Enumerator::Lazy.allocate.inspect.should == "#<Enumerator::Lazy: uninitialized>"
- end
end
diff --git a/spec/ruby/core/enumerator/lazy/compact_spec.rb b/spec/ruby/core/enumerator/lazy/compact_spec.rb
index e678bc71eb..80b6f9481d 100644
--- a/spec/ruby/core/enumerator/lazy/compact_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/compact_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../../spec_helper'
-require_relative 'fixtures/classes'
ruby_version_is '3.1' do
describe "Enumerator::Lazy#compact" do
@@ -8,9 +7,5 @@ ruby_version_is '3.1' do
arr.should be_an_instance_of(Enumerator::Lazy)
arr.force.should == [1, 3, false, 5]
end
-
- it "sets #size to nil" do
- Enumerator::Lazy.new(Object.new, 100) {}.compact.size.should == nil
- end
end
end
diff --git a/spec/ruby/core/enumerator/lazy/initialize_spec.rb b/spec/ruby/core/enumerator/lazy/initialize_spec.rb
index e1e0b1d608..f23018d010 100644
--- a/spec/ruby/core/enumerator/lazy/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/initialize_spec.rb
@@ -56,8 +56,8 @@ describe "Enumerator::Lazy#initialize" do
end
describe "on frozen instance" do
- it "raises a FrozenError" do
- -> { @uninitialized.freeze.send(:initialize, @receiver) {} }.should raise_error(FrozenError)
+ it "raises a RuntimeError" do
+ -> { @uninitialized.freeze.send(:initialize, @receiver) {} }.should raise_error(RuntimeError)
end
end
end
diff --git a/spec/ruby/core/enumerator/new_spec.rb b/spec/ruby/core/enumerator/new_spec.rb
index 671912224f..c439469525 100644
--- a/spec/ruby/core/enumerator/new_spec.rb
+++ b/spec/ruby/core/enumerator/new_spec.rb
@@ -2,8 +2,51 @@ require_relative '../../spec_helper'
describe "Enumerator.new" do
context "no block given" do
- it "raises" do
- -> { Enumerator.new(1, :upto, 3) }.should raise_error(ArgumentError)
+ ruby_version_is '3.0' do
+ it "raises" do
+ -> { Enumerator.new(1, :upto, 3) }.should raise_error(ArgumentError)
+ end
+ end
+
+ ruby_version_is ''...'3.0' do
+ it "creates a new custom enumerator with the given object, iterator and arguments" do
+ enum = suppress_warning { Enumerator.new(1, :upto, 3) }
+ enum.should be_an_instance_of(Enumerator)
+ end
+
+ it "creates a new custom enumerator that responds to #each" do
+ enum = suppress_warning { Enumerator.new(1, :upto, 3) }
+ enum.respond_to?(:each).should == true
+ end
+
+ it "creates a new custom enumerator that runs correctly" do
+ suppress_warning { Enumerator.new(1, :upto, 3) }.map{ |x| x }.should == [1,2,3]
+ end
+
+ it "aliases the second argument to :each" do
+ suppress_warning { Enumerator.new(1..2) }.to_a.should ==
+ suppress_warning { Enumerator.new(1..2, :each) }.to_a
+ end
+
+ it "doesn't check for the presence of the iterator method" do
+ suppress_warning { Enumerator.new(nil) }.should be_an_instance_of(Enumerator)
+ end
+
+ it "uses the latest define iterator method" do
+ class StrangeEach
+ def each
+ yield :foo
+ end
+ end
+ enum = suppress_warning { Enumerator.new(StrangeEach.new) }
+ enum.to_a.should == [:foo]
+ class StrangeEach
+ def each
+ yield :bar
+ end
+ end
+ enum.to_a.should == [:bar]
+ end
end
end
diff --git a/spec/ruby/core/enumerator/next_values_spec.rb b/spec/ruby/core/enumerator/next_values_spec.rb
index 2202700c58..201b5d323f 100644
--- a/spec/ruby/core/enumerator/next_values_spec.rb
+++ b/spec/ruby/core/enumerator/next_values_spec.rb
@@ -11,7 +11,6 @@ describe "Enumerator#next_values" do
yield :e1, :e2, :e3
yield nil
yield
- yield [:f1, :f2]
end
@e = o.to_enum
@@ -49,13 +48,8 @@ describe "Enumerator#next_values" do
@e.next_values.should == []
end
- it "returns an array of array if yield is called with an array" do
- 7.times { @e.next }
- @e.next_values.should == [[:f1, :f2]]
- end
-
it "raises StopIteration if called on a finished enumerator" do
- 8.times { @e.next }
+ 7.times { @e.next }
-> { @e.next_values }.should raise_error(StopIteration)
end
end
diff --git a/spec/ruby/core/enumerator/peek_values_spec.rb b/spec/ruby/core/enumerator/peek_values_spec.rb
index 8b84fc8afc..7865546515 100644
--- a/spec/ruby/core/enumerator/peek_values_spec.rb
+++ b/spec/ruby/core/enumerator/peek_values_spec.rb
@@ -11,7 +11,6 @@ describe "Enumerator#peek_values" do
yield :e1, :e2, :e3
yield nil
yield
- yield [:f1, :f2]
end
@e = o.to_enum
@@ -51,13 +50,8 @@ describe "Enumerator#peek_values" do
@e.peek_values.should == []
end
- it "returns an array of array if yield is called with an array" do
- 7.times { @e.next }
- @e.peek_values.should == [[:f1, :f2]]
- end
-
it "raises StopIteration if called on a finished enumerator" do
- 8.times { @e.next }
+ 7.times { @e.next }
-> { @e.peek_values }.should raise_error(StopIteration)
end
end
diff --git a/spec/ruby/core/enumerator/product/each_spec.rb b/spec/ruby/core/enumerator/product/each_spec.rb
deleted file mode 100644
index cabeb9d93a..0000000000
--- a/spec/ruby/core/enumerator/product/each_spec.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../../enumerable/shared/enumeratorized'
-
-ruby_version_is "3.2" do
- describe "Enumerator::Product#each" do
- it_behaves_like :enumeratorized_with_origin_size, :each, Enumerator::Product.new([1, 2], [:a, :b])
-
- it "yields each element of Cartesian product of enumerators" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- acc = []
- enum.each { |e| acc << e }
- acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "calls #each_entry method on enumerators" do
- object1 = Object.new
- def object1.each_entry
- yield 1
- yield 2
- end
-
- object2 = Object.new
- def object2.each_entry
- yield :a
- yield :b
- end
-
- enum = Enumerator::Product.new(object1, object2)
- acc = []
- enum.each { |e| acc << e }
- acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "raises a NoMethodError if the object doesn't respond to #each_entry" do
- -> {
- Enumerator::Product.new(Object.new).each {}
- }.should raise_error(NoMethodError, /undefined method [`']each_entry' for/)
- end
-
- it "returns enumerator if not given a block" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.each.should.kind_of?(Enumerator)
-
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "returns self if given a block" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.each {}.should.equal?(enum)
- end
-
- it "doesn't accept arguments" do
- Enumerator::Product.instance_method(:each).arity.should == 0
- end
-
- it "yields each element to a block that takes multiple arguments" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
-
- acc = []
- enum.each { |x, y| acc << x }
- acc.should == [1, 1, 2, 2]
-
- acc = []
- enum.each { |x, y| acc << y }
- acc.should == [:a, :b, :a, :b]
-
- acc = []
- enum.each { |x, y, z| acc << z }
- acc.should == [nil, nil, nil, nil]
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/product/initialize_copy_spec.rb b/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
deleted file mode 100644
index 46e8421322..0000000000
--- a/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Enumerator::Product#initialize_copy" do
- it "replaces content of the receiver with content of the other object" do
- enum = Enumerator::Product.new([true, false])
- enum2 = Enumerator::Product.new([1, 2], [:a, :b])
-
- enum.send(:initialize_copy, enum2)
- enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "returns self" do
- enum = Enumerator::Product.new([true, false])
- enum2 = Enumerator::Product.new([1, 2], [:a, :b])
-
- enum.send(:initialize_copy, enum2).should.equal?(enum)
- end
-
- it "is a private method" do
- Enumerator::Product.should have_private_instance_method(:initialize_copy, false)
- end
-
- it "does nothing if the argument is the same as the receiver" do
- enum = Enumerator::Product.new(1..2)
- enum.send(:initialize_copy, enum).should.equal?(enum)
-
- enum.freeze
- enum.send(:initialize_copy, enum).should.equal?(enum)
- end
-
- it "raises FrozenError if the receiver is frozen" do
- enum = Enumerator::Product.new(1..2)
- enum2 = Enumerator::Product.new(3..4)
-
- -> { enum.freeze.send(:initialize_copy, enum2) }.should raise_error(FrozenError)
- end
-
- it "raises TypeError if the objects are of different class" do
- enum = Enumerator::Product.new(1..2)
- enum2 = Class.new(Enumerator::Product).new(3..4)
-
- -> { enum.send(:initialize_copy, enum2) }.should raise_error(TypeError, 'initialize_copy should take same class object')
- -> { enum2.send(:initialize_copy, enum) }.should raise_error(TypeError, 'initialize_copy should take same class object')
- end
-
- it "raises ArgumentError if the argument is not initialized yet" do
- enum = Enumerator::Product.new(1..2)
- enum2 = Enumerator::Product.allocate
-
- -> { enum.send(:initialize_copy, enum2) }.should raise_error(ArgumentError, 'uninitialized product')
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/product/initialize_spec.rb b/spec/ruby/core/enumerator/product/initialize_spec.rb
deleted file mode 100644
index 4b60564240..0000000000
--- a/spec/ruby/core/enumerator/product/initialize_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Enumerator::Product#initialize" do
- before :each do
- @uninitialized = Enumerator::Product.allocate
- end
-
- it "is a private method" do
- Enumerator::Product.should have_private_instance_method(:initialize, false)
- end
-
- it "returns self" do
- @uninitialized.send(:initialize).should equal(@uninitialized)
- end
-
- it "accepts many arguments" do
- @uninitialized.send(:initialize, 0..1, 2..3, 4..5).should equal(@uninitialized)
- end
-
- it "accepts arguments that are not Enumerable nor responding to :each_entry" do
- @uninitialized.send(:initialize, Object.new).should equal(@uninitialized)
- end
-
- describe "on frozen instance" do
- it "raises a FrozenError" do
- -> {
- @uninitialized.freeze.send(:initialize, 0..1)
- }.should raise_error(FrozenError)
- end
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/product/inspect_spec.rb b/spec/ruby/core/enumerator/product/inspect_spec.rb
deleted file mode 100644
index 1ea8e9c49b..0000000000
--- a/spec/ruby/core/enumerator/product/inspect_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Enumerator::Product#inspect" do
- it "returns a String including enumerators" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.inspect.should == "#<Enumerator::Product: [[1, 2], [:a, :b]]>"
- end
-
- it "represents a recursive element with '[...]'" do
- enum = [1, 2]
- enum_recursive = Enumerator::Product.new(enum)
-
- enum << enum_recursive
- enum_recursive.inspect.should == "#<Enumerator::Product: [[1, 2, #<Enumerator::Product: ...>]]>"
- end
-
- it "returns a not initialized representation if #initialized is not called yet" do
- Enumerator::Product.allocate.inspect.should == "#<Enumerator::Product: uninitialized>"
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/product/rewind_spec.rb b/spec/ruby/core/enumerator/product/rewind_spec.rb
deleted file mode 100644
index e8ee730239..0000000000
--- a/spec/ruby/core/enumerator/product/rewind_spec.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Enumerator::Product#rewind" do
- before :each do
- @enum = Enumerator::Product.new([1, 2].each.to_enum, [:a, :b].each.to_enum)
- end
-
- it "resets the enumerator to its initial state" do
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- @enum.rewind
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "returns self" do
- @enum.rewind.should.equal? @enum
- end
-
- it "has no effect on a new enumerator" do
- @enum.rewind
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "has no effect if called multiple, consecutive times" do
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- @enum.rewind
- @enum.rewind
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "calls the enclosed object's rewind method if one exists" do
- obj = mock('rewinder')
- enum = Enumerator::Product.new(obj.to_enum)
-
- obj.should_receive(:rewind)
- enum.rewind
- end
-
- it "does nothing if the object doesn't have a #rewind method" do
- obj = mock('rewinder')
- enum = Enumerator::Product.new(obj.to_enum)
-
- enum.rewind.should == enum
- end
-
- it "calls a rewind method on each enumerable in direct order" do
- ScratchPad.record []
-
- object1 = Object.new
- def object1.rewind; ScratchPad << :object1; end
-
- object2 = Object.new
- def object2.rewind; ScratchPad << :object2; end
-
- object3 = Object.new
- def object3.rewind; ScratchPad << :object3; end
-
- enum = Enumerator::Product.new(object1, object2, object3)
- enum.rewind
-
- ScratchPad.recorded.should == [:object1, :object2, :object3]
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/product/size_spec.rb b/spec/ruby/core/enumerator/product/size_spec.rb
deleted file mode 100644
index 46958b1a22..0000000000
--- a/spec/ruby/core/enumerator/product/size_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Enumerator::Product#size" do
- it "returns the total size of the enumerator product calculated by multiplying the sizes of enumerables in the product" do
- product = Enumerator::Product.new(1..2, 1..3, 1..4)
- product.size.should == 24 # 2 * 3 * 4
- end
-
- it "returns nil if any enumerable reports its size as nil" do
- enum = Object.new
- def enum.size; nil; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
-
- it "returns Float::INFINITY if any enumerable reports its size as Float::INFINITY" do
- enum = Object.new
- def enum.size; Float::INFINITY; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == Float::INFINITY
- end
-
- it "returns nil if any enumerable reports its size as Float::NAN" do
- enum = Object.new
- def enum.size; Float::NAN; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
-
- it "returns nil if any enumerable doesn't respond to #size" do
- enum = Object.new
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
-
- it "returns nil if any enumerable reports a not-convertible to Integer" do
- enum = Object.new
- def enum.size; :symbol; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
-
- it "returns nil if any enumerable reports a non-Integer but convertible to Integer size" do
- enum = Object.new
- def enum.size; 1.0; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/product_spec.rb b/spec/ruby/core/enumerator/product_spec.rb
deleted file mode 100644
index 0acca6690e..0000000000
--- a/spec/ruby/core/enumerator/product_spec.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-require_relative '../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Enumerator.product" do
- it "returns a Cartesian product of enumerators" do
- enum = Enumerator.product(1..2, ["A", "B"])
- enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
- end
-
- it "accepts a list of enumerators of any length" do
- enum = Enumerator.product(1..2)
- enum.to_a.should == [[1], [2]]
-
- enum = Enumerator.product(1..2, ["A"])
- enum.to_a.should == [[1, "A"], [2, "A"]]
-
- enum = Enumerator.product(1..2, ["A"], ["B"])
- enum.to_a.should == [[1, "A", "B"], [2, "A", "B"]]
-
- enum = Enumerator.product(2..3, ["A"], ["B"], ["C"])
- enum.to_a.should == [[2, "A", "B", "C"], [3, "A", "B", "C"]]
- end
-
- it "returns an enumerator with an empty array when no arguments passed" do
- enum = Enumerator.product
- enum.to_a.should == [[]]
- end
-
- it "returns an instance of Enumerator::Product" do
- enum = Enumerator.product
- enum.class.should == Enumerator::Product
- end
-
- it "accepts infinite enumerators and returns infinite enumerator" do
- enum = Enumerator.product(1.., ["A", "B"])
- enum.take(5).should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"]]
- enum.size.should == Float::INFINITY
- end
-
- it "accepts a block" do
- elems = []
- enum = Enumerator.product(1..2, ["X", "Y"]) { elems << _1 }
-
- elems.should == [[1, "X"], [1, "Y"], [2, "X"], [2, "Y"]]
- end
-
- it "returns nil when a block passed" do
- Enumerator.product(1..2) {}.should == nil
- end
-
- # https://bugs.ruby-lang.org/issues/19829
- it "reject keyword arguments" do
- -> {
- Enumerator.product(1..3, foo: 1, bar: 2)
- }.should raise_error(ArgumentError, "unknown keywords: :foo, :bar")
- end
-
- it "calls only #each_entry method on arguments" do
- object = Object.new
- def object.each_entry
- yield 1
- yield 2
- end
-
- enum = Enumerator.product(object, ["A", "B"])
- enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
- end
-
- it "raises NoMethodError when argument doesn't respond to #each_entry" do
- -> {
- Enumerator.product(Object.new).to_a
- }.should raise_error(NoMethodError, /undefined method [`']each_entry' for/)
- end
-
- it "calls #each_entry lazily" do
- Enumerator.product(Object.new).should be_kind_of(Enumerator)
- end
-
- it "iterates through consuming enumerator elements only once" do
- a = [1, 2, 3]
- i = 0
-
- enum = Enumerator.new do |y|
- while i < a.size
- y << a[i]
- i += 1
- end
- end
-
- Enumerator.product(['a', 'b'], enum).to_a.should == [["a", 1], ["a", 2], ["a", 3]]
- end
- end
-end
diff --git a/spec/ruby/core/enumerator/rewind_spec.rb b/spec/ruby/core/enumerator/rewind_spec.rb
index 6ba0edf174..a105f2c619 100644
--- a/spec/ruby/core/enumerator/rewind_spec.rb
+++ b/spec/ruby/core/enumerator/rewind_spec.rb
@@ -14,7 +14,7 @@ describe "Enumerator#rewind" do
end
it "returns self" do
- @enum.rewind.should.equal? @enum
+ @enum.rewind.should == @enum
end
it "has no effect on a new enumerator" do
@@ -49,7 +49,7 @@ describe "Enumerator#rewind" do
obj = mock('rewinder')
enum = obj.to_enum
obj.should_receive(:each).at_most(1)
- enum.rewind.should == enum
+ -> { enum.rewind.should == enum }.should_not raise_error
end
end
diff --git a/spec/ruby/core/env/clone_spec.rb b/spec/ruby/core/env/clone_spec.rb
deleted file mode 100644
index 991e4e6774..0000000000
--- a/spec/ruby/core/env/clone_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "ENV#clone" do
- it "raises ArgumentError when keyword argument 'freeze' is neither nil nor boolean" do
- -> {
- ENV.clone(freeze: 1)
- }.should raise_error(ArgumentError)
- end
-
- it "raises ArgumentError when keyword argument is not 'freeze'" do
- -> {
- ENV.clone(foo: nil)
- }.should raise_error(ArgumentError)
- end
-
- ruby_version_is "3.2" do
- it "raises TypeError" do
- -> {
- ENV.clone
- }.should raise_error(TypeError, /Cannot clone ENV, use ENV.to_h to get a copy of ENV as a hash/)
- end
- end
-end
diff --git a/spec/ruby/core/env/delete_spec.rb b/spec/ruby/core/env/delete_spec.rb
index f28ac97911..5e7891f74d 100644
--- a/spec/ruby/core/env/delete_spec.rb
+++ b/spec/ruby/core/env/delete_spec.rb
@@ -30,9 +30,11 @@ describe "ENV.delete" do
ScratchPad.recorded.should == "foo"
end
- it "returns the result of given block if the named environment variable does not exist" do
- ENV.delete("foo")
- ENV.delete("foo") { |name| "bar" }.should == "bar"
+ ruby_version_is "3.0" do
+ it "returns the result of given block if the named environment variable does not exist" do
+ ENV.delete("foo")
+ ENV.delete("foo") { |name| "bar" }.should == "bar"
+ end
end
it "does not evaluate the block if the environment variable exists" do
@@ -41,14 +43,6 @@ describe "ENV.delete" do
ENV["foo"].should == nil
end
- it "removes the variable coerced with #to_str" do
- ENV["foo"] = "bar"
- k = mock('key')
- k.should_receive(:to_str).and_return("foo")
- ENV.delete(k)
- ENV["foo"].should == nil
- end
-
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
-> { ENV.delete(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
end
diff --git a/spec/ruby/core/env/dup_spec.rb b/spec/ruby/core/env/dup_spec.rb
deleted file mode 100644
index 46d125aca8..0000000000
--- a/spec/ruby/core/env/dup_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "ENV#dup" do
- ruby_version_is "3.1" do
- it "raises TypeError" do
- -> {
- ENV.dup
- }.should raise_error(TypeError, /Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash/)
- end
- end
-end
diff --git a/spec/ruby/core/env/except_spec.rb b/spec/ruby/core/env/except_spec.rb
index fb8f3b7536..cfe5865abe 100644
--- a/spec/ruby/core/env/except_spec.rb
+++ b/spec/ruby/core/env/except_spec.rb
@@ -1,34 +1,36 @@
require_relative 'spec_helper'
require_relative 'shared/to_hash'
-describe "ENV.except" do
- before do
- @orig_hash = ENV.to_hash
- end
+ruby_version_is "3.0" do
+ describe "ENV.except" do
+ before do
+ @orig_hash = ENV.to_hash
+ end
- after do
- ENV.replace @orig_hash
- end
+ after do
+ ENV.replace @orig_hash
+ end
- # Testing the method without arguments is covered via
- it_behaves_like :env_to_hash, :except
+ # Testing the method without arguments is covered via
+ it_behaves_like :env_to_hash, :except
- it "returns a hash without the requested subset" do
- ENV.clear
+ it "returns a hash without the requested subset" do
+ ENV.clear
- ENV['one'] = '1'
- ENV['two'] = '2'
- ENV['three'] = '3'
+ ENV['one'] = '1'
+ ENV['two'] = '2'
+ ENV['three'] = '3'
- ENV.except('one', 'three').should == { 'two' => '2' }
- end
+ ENV.except('one', 'three').should == { 'two' => '2' }
+ end
- it "ignores keys not present in the original hash" do
- ENV.clear
+ it "ignores keys not present in the original hash" do
+ ENV.clear
- ENV['one'] = '1'
- ENV['two'] = '2'
+ ENV['one'] = '1'
+ ENV['two'] = '2'
- ENV.except('one', 'three').should == { 'two' => '2' }
+ ENV.except('one', 'three').should == { 'two' => '2' }
+ end
end
end
diff --git a/spec/ruby/core/env/index_spec.rb b/spec/ruby/core/env/index_spec.rb
new file mode 100644
index 0000000000..301a66ab4e
--- /dev/null
+++ b/spec/ruby/core/env/index_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../spec_helper'
+require_relative 'shared/key'
+
+ruby_version_is ''...'3.0' do
+ describe "ENV.index" do
+ it_behaves_like :env_key, :index
+
+ it "warns about deprecation" do
+ -> do
+ ENV.index("foo")
+ end.should complain(/warning: ENV.index is deprecated; use ENV.key/)
+ end
+ end
+end
diff --git a/spec/ruby/core/env/indexes_spec.rb b/spec/ruby/core/env/indexes_spec.rb
new file mode 100644
index 0000000000..e724feaa39
--- /dev/null
+++ b/spec/ruby/core/env/indexes_spec.rb
@@ -0,0 +1 @@
+require_relative '../../spec_helper'
diff --git a/spec/ruby/core/env/indices_spec.rb b/spec/ruby/core/env/indices_spec.rb
new file mode 100644
index 0000000000..e724feaa39
--- /dev/null
+++ b/spec/ruby/core/env/indices_spec.rb
@@ -0,0 +1 @@
+require_relative '../../spec_helper'
diff --git a/spec/ruby/core/env/key_spec.rb b/spec/ruby/core/env/key_spec.rb
index cf70286409..82cfbefa39 100644
--- a/spec/ruby/core/env/key_spec.rb
+++ b/spec/ruby/core/env/key_spec.rb
@@ -1,39 +1,11 @@
require_relative '../../spec_helper'
require_relative 'shared/include'
+require_relative 'shared/key'
describe "ENV.key?" do
it_behaves_like :env_include, :key?
end
describe "ENV.key" do
- before :each do
- @saved_foo = ENV["foo"]
- end
-
- after :each do
- ENV["foo"] = @saved_foo
- end
-
- it "returns the index associated with the passed value" do
- ENV["foo"] = "bar"
- ENV.key("bar").should == "foo"
- end
-
- it "returns nil if the passed value is not found" do
- ENV.delete("foo")
- ENV.key("foo").should be_nil
- end
-
- it "coerces the key element with #to_str" do
- ENV["foo"] = "bar"
- k = mock('key')
- k.should_receive(:to_str).and_return("bar")
- ENV.key(k).should == "foo"
- end
-
- it "raises TypeError if the argument is not a String and does not respond to #to_str" do
- -> {
- ENV.key(Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
+ it_behaves_like :env_key, :key
end
diff --git a/spec/ruby/core/env/shared/include.rb b/spec/ruby/core/env/shared/include.rb
index 70aa555301..3efcd523d6 100644
--- a/spec/ruby/core/env/shared/include.rb
+++ b/spec/ruby/core/env/shared/include.rb
@@ -17,13 +17,6 @@ describe :env_include, shared: true do
ENV.send(@method, "foo").should == false
end
- it "coerces the key with #to_str" do
- ENV["foo"] = "bar"
- k = mock('key')
- k.should_receive(:to_str).and_return("foo")
- ENV.send(@method, k).should == true
- end
-
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
-> { ENV.send(@method, Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
end
diff --git a/spec/ruby/core/env/shared/key.rb b/spec/ruby/core/env/shared/key.rb
new file mode 100644
index 0000000000..93396d2aca
--- /dev/null
+++ b/spec/ruby/core/env/shared/key.rb
@@ -0,0 +1,31 @@
+describe :env_key, shared: true do
+ before :each do
+ @saved_foo = ENV["foo"]
+ end
+
+ after :each do
+ ENV["foo"] = @saved_foo
+ end
+
+ it "returns the index associated with the passed value" do
+ ENV["foo"] = "bar"
+ suppress_warning {
+ ENV.send(@method, "bar").should == "foo"
+ }
+ end
+
+ it "returns nil if the passed value is not found" do
+ ENV.delete("foo")
+ suppress_warning {
+ ENV.send(@method, "foo").should be_nil
+ }
+ end
+
+ it "raises TypeError if the argument is not a String and does not respond to #to_str" do
+ -> {
+ suppress_warning {
+ ENV.send(@method, Object.new)
+ }
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+end
diff --git a/spec/ruby/core/env/shared/value.rb b/spec/ruby/core/env/shared/value.rb
index c2b5025465..bef96b5fef 100644
--- a/spec/ruby/core/env/shared/value.rb
+++ b/spec/ruby/core/env/shared/value.rb
@@ -16,13 +16,6 @@ describe :env_value, shared: true do
ENV.send(@method, "foo").should == false
end
- it "coerces the value element with #to_str" do
- ENV["foo"] = "bar"
- v = mock('value')
- v.should_receive(:to_str).and_return("bar")
- ENV.send(@method, v).should == true
- end
-
it "returns nil if the argument is not a String and does not respond to #to_str" do
ENV.send(@method, Object.new).should == nil
end
diff --git a/spec/ruby/core/env/slice_spec.rb b/spec/ruby/core/env/slice_spec.rb
index 959239d2b2..e3b6020391 100644
--- a/spec/ruby/core/env/slice_spec.rb
+++ b/spec/ruby/core/env/slice_spec.rb
@@ -21,16 +21,6 @@ describe "ENV.slice" do
ENV.slice("foo", "boo", "bar").should == {"foo" => "0", "bar" => "1"}
end
- it "returns the values for the keys coerced with #to_str, but keeps the original objects as result keys" do
- foo = mock('key 1')
- foo.should_receive(:to_str).and_return("foo")
- boo = mock('key 2')
- boo.should_receive(:to_str).and_return("boo")
- bar = mock('key 3')
- bar.should_receive(:to_str).and_return("bar")
- ENV.slice(foo, boo, bar).should == {foo => "0", bar => "1"}
- end
-
it "raises TypeError if any argument is not a String and does not respond to #to_str" do
-> { ENV.slice(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
end
diff --git a/spec/ruby/core/env/to_a_spec.rb b/spec/ruby/core/env/to_a_spec.rb
index 2b1649281f..39e3877b48 100644
--- a/spec/ruby/core/env/to_a_spec.rb
+++ b/spec/ruby/core/env/to_a_spec.rb
@@ -6,10 +6,7 @@ describe "ENV.to_a" do
a = ENV.to_a
a.is_a?(Array).should == true
a.size.should == ENV.size
- a.each { |k,v| ENV[k].should == v }
-
- a.first.should.is_a?(Array)
- a.first.size.should == 2
+ ENV.each_pair { |k, v| a.should include([k, v])}
end
it "returns the entries in the locale encoding" do
diff --git a/spec/ruby/core/env/to_h_spec.rb b/spec/ruby/core/env/to_h_spec.rb
index 58ea2d2030..3c4a92aa57 100644
--- a/spec/ruby/core/env/to_h_spec.rb
+++ b/spec/ruby/core/env/to_h_spec.rb
@@ -18,18 +18,6 @@ describe "ENV.to_h" do
ENV.to_h { |k, v| [k, v.upcase] }.should == { 'a' => "B", 'c' => "D" }
end
- it "passes to a block each pair's key and value as separate arguments" do
- ENV.replace("a" => "b", "c" => "d")
-
- ScratchPad.record []
- ENV.to_h { |k, v| ScratchPad << [k, v]; [k, v] }
- ScratchPad.recorded.sort.should == [["a", "b"], ["c", "d"]]
-
- ScratchPad.record []
- ENV.to_h { |*args| ScratchPad << args; [args[0], args[1]] }
- ScratchPad.recorded.sort.should == [["a", "b"], ["c", "d"]]
- end
-
it "does not require the array elements to be strings" do
ENV.replace("a" => "b", "c" => "d")
ENV.to_h { |k, v| [k.to_sym, v.to_sym] }.should == { :a => :b, :c => :d }
diff --git a/spec/ruby/core/exception/backtrace_spec.rb b/spec/ruby/core/exception/backtrace_spec.rb
index 9a65ea3820..3f74c4cefe 100644
--- a/spec/ruby/core/exception/backtrace_spec.rb
+++ b/spec/ruby/core/exception/backtrace_spec.rb
@@ -27,7 +27,7 @@ describe "Exception#backtrace" do
end
it "includes the name of the method from where self raised in the first element" do
- @backtrace.first.should =~ /in [`'](?:ExceptionSpecs::Backtrace\.)?backtrace'/
+ @backtrace.first.should =~ /in `backtrace'/
end
it "includes the filename of the location immediately prior to where self raised in the second element" do
@@ -38,25 +38,12 @@ describe "Exception#backtrace" do
@backtrace[1].should =~ /:6(:in )?/
end
- ruby_version_is ""..."3.4" do
- it "contains lines of the same format for each prior position in the stack" do
- @backtrace[2..-1].each do |line|
- # This regexp is deliberately imprecise to account for the need to abstract out
- # the paths of the included mspec files and the desire to avoid specifying in any
- # detail what the in `...' portion looks like.
- line.should =~ /^.+:\d+:in `[^`]+'$/
- end
- end
- end
-
- ruby_version_is "3.4" do
- it "contains lines of the same format for each prior position in the stack" do
- @backtrace[2..-1].each do |line|
- # This regexp is deliberately imprecise to account for the need to abstract out
- # the paths of the included mspec files and the desire to avoid specifying in any
- # detail what the in '...' portion looks like.
- line.should =~ /^.+:\d+:in '[^`]+'$/
- end
+ it "contains lines of the same format for each prior position in the stack" do
+ @backtrace[2..-1].each do |line|
+ # This regexp is deliberately imprecise to account for the need to abstract out
+ # the paths of the included mspec files and the desire to avoid specifying in any
+ # detail what the in `...' portion looks like.
+ line.should =~ /^.+:\d+:in `[^`]+'$/
end
end
diff --git a/spec/ruby/core/exception/case_compare_spec.rb b/spec/ruby/core/exception/case_compare_spec.rb
index 5fd11ae741..87b9dee3ca 100644
--- a/spec/ruby/core/exception/case_compare_spec.rb
+++ b/spec/ruby/core/exception/case_compare_spec.rb
@@ -26,11 +26,13 @@ describe "SystemCallError.===" do
end
it "returns true if receiver is generic and arg is kind of SystemCallError" do
+ unknown_error_number = Errno.constants.size
e = SystemCallError.new('foo', @example_errno)
SystemCallError.===(e).should == true
end
it "returns false if receiver is generic and arg is not kind of SystemCallError" do
+ unknown_error_number = Errno.constants.size
e = Object.new
SystemCallError.===(e).should == false
end
diff --git a/spec/ruby/core/exception/detailed_message_spec.rb b/spec/ruby/core/exception/detailed_message_spec.rb
deleted file mode 100644
index 8178278b2b..0000000000
--- a/spec/ruby/core/exception/detailed_message_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/common'
-
-describe "Exception#detailed_message" do
- ruby_version_is "3.2" do
- it "returns decorated message" do
- RuntimeError.new("new error").detailed_message.should == "new error (RuntimeError)"
- end
-
- it "is called by #full_message to allow message customization" do
- exception = Exception.new("new error")
- def exception.detailed_message(**)
- "<prefix>#{message}<suffix>"
- end
- exception.full_message(highlight: false).should.include? "<prefix>new error<suffix>"
- end
-
- it "returns just a message if exception class is anonymous" do
- Class.new(RuntimeError).new("message").detailed_message.should == "message"
- end
-
- it "returns 'unhandled exception' for an instance of RuntimeError with empty message" do
- RuntimeError.new("").detailed_message.should == "unhandled exception"
- end
-
- it "returns just class name for an instance other than RuntimeError with empty message" do
- DetailedMessageSpec::C.new("").detailed_message.should == "DetailedMessageSpec::C"
- StandardError.new("").detailed_message.should == "StandardError"
- end
-
- it "returns a generated class name for an instance of RuntimeError anonymous subclass with empty message" do
- klass = Class.new(RuntimeError)
- klass.new("").detailed_message.should =~ /\A#<Class:0x\h+>\z/
- end
-
- it "accepts highlight keyword argument and adds escape control sequences" do
- RuntimeError.new("new error").detailed_message(highlight: true).should == "\e[1mnew error (\e[1;4mRuntimeError\e[m\e[1m)\e[m"
- end
-
- it "accepts highlight keyword argument and adds escape control sequences for an instance of RuntimeError with empty message" do
- RuntimeError.new("").detailed_message(highlight: true).should == "\e[1;4munhandled exception\e[m"
- end
-
- it "accepts highlight keyword argument and adds escape control sequences for an instance other than RuntimeError with empty message" do
- StandardError.new("").detailed_message(highlight: true).should == "\e[1;4mStandardError\e[m"
- end
-
- it "allows and ignores other keyword arguments" do
- RuntimeError.new("new error").detailed_message(foo: true).should == "new error (RuntimeError)"
- end
- end
-end
diff --git a/spec/ruby/core/exception/equal_value_spec.rb b/spec/ruby/core/exception/equal_value_spec.rb
index e8f3ce0f8d..7f2065511a 100644
--- a/spec/ruby/core/exception/equal_value_spec.rb
+++ b/spec/ruby/core/exception/equal_value_spec.rb
@@ -22,18 +22,18 @@ describe "Exception#==" do
it "returns true if both exceptions have the same class, the same message, and the same backtrace" do
one = TypeError.new("message")
- one.set_backtrace [__dir__]
+ one.set_backtrace [File.dirname(__FILE__)]
two = TypeError.new("message")
- two.set_backtrace [__dir__]
+ two.set_backtrace [File.dirname(__FILE__)]
one.should == two
end
it "returns false if the two exceptions inherit from Exception but have different classes" do
one = RuntimeError.new("message")
- one.set_backtrace [__dir__]
+ one.set_backtrace [File.dirname(__FILE__)]
one.should be_kind_of(Exception)
two = TypeError.new("message")
- two.set_backtrace [__dir__]
+ two.set_backtrace [File.dirname(__FILE__)]
two.should be_kind_of(Exception)
one.should_not == two
end
@@ -52,7 +52,7 @@ describe "Exception#==" do
it "returns false if the two exceptions differ only in their backtrace" do
one = RuntimeError.new("message")
- one.set_backtrace [__dir__]
+ one.set_backtrace [File.dirname(__FILE__)]
two = RuntimeError.new("message")
two.set_backtrace nil
one.should_not == two
@@ -60,9 +60,9 @@ describe "Exception#==" do
it "returns false if the two exceptions differ only in their message" do
one = RuntimeError.new("message")
- one.set_backtrace [__dir__]
+ one.set_backtrace [File.dirname(__FILE__)]
two = RuntimeError.new("message2")
- two.set_backtrace [__dir__]
+ two.set_backtrace [File.dirname(__FILE__)]
one.should_not == two
end
end
diff --git a/spec/ruby/core/exception/fixtures/common.rb b/spec/ruby/core/exception/fixtures/common.rb
index 1e243098bd..0ffb3ed855 100644
--- a/spec/ruby/core/exception/fixtures/common.rb
+++ b/spec/ruby/core/exception/fixtures/common.rb
@@ -93,7 +93,3 @@ class NameErrorSpecs
end
end
end
-
-module DetailedMessageSpec
- C = Class.new(RuntimeError)
-end
diff --git a/spec/ruby/core/exception/fixtures/syntax_error.rb b/spec/ruby/core/exception/fixtures/syntax_error.rb
deleted file mode 100644
index ccec62f7a1..0000000000
--- a/spec/ruby/core/exception/fixtures/syntax_error.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-# rubocop:disable Lint/Syntax
-1+1=2
-# rubocop:enable Lint/Syntax
diff --git a/spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb b/spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb
deleted file mode 100644
index c109ec6247..0000000000
--- a/spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-ready = false
-t = Thread.new do
- f = Fiber.new do
- begin
- Fiber.yield
- ensure
- STDERR.puts "suspended fiber ensure"
- end
- end
- f.resume
-
- begin
- ready = true
- sleep
- ensure
- STDERR.puts "current fiber ensure"
- end
-end
-
-Thread.pass until ready && t.stop?
-
-# let the program end, it's the same as #exit or an exception for this behavior
diff --git a/spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb b/spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb
deleted file mode 100644
index 3364ed06d0..0000000000
--- a/spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-ready = false
-t = Thread.new do
- f = Fiber.new do
- begin
- Fiber.yield
- ensure
- STDERR.puts "suspended fiber ensure"
- end
- end
- f.resume
-
- f2 = Fiber.new do
- begin
- ready = true
- sleep
- ensure
- STDERR.puts "current fiber ensure"
- end
- end
- f2.resume
-end
-
-Thread.pass until ready && t.stop?
-
-# let the program end, it's the same as #exit or an exception for this behavior
diff --git a/spec/ruby/core/exception/frozen_error_spec.rb b/spec/ruby/core/exception/frozen_error_spec.rb
index 979ec2ff98..2efdc239d8 100644
--- a/spec/ruby/core/exception/frozen_error_spec.rb
+++ b/spec/ruby/core/exception/frozen_error_spec.rb
@@ -20,19 +20,3 @@ describe "FrozenError#receiver" do
end
end
end
-
-describe "Modifying a frozen object" do
- context "#inspect is redefined and modifies the object" do
- it "returns ... instead of String representation of object" do
- object = Object.new
- def object.inspect; @a = 1 end
- def object.modify; @a = 2 end
-
- object.freeze
-
- # CRuby's message contains multiple whitespaces before '...'.
- # So handle both multiple and single whitespace.
- -> { object.modify }.should raise_error(FrozenError, /can't modify frozen .*?: \s*.../)
- end
- end
-end
diff --git a/spec/ruby/core/exception/full_message_spec.rb b/spec/ruby/core/exception/full_message_spec.rb
index 5154354555..9757a2f407 100644
--- a/spec/ruby/core/exception/full_message_spec.rb
+++ b/spec/ruby/core/exception/full_message_spec.rb
@@ -42,59 +42,16 @@ describe "Exception#full_message" do
e = RuntimeError.new("Some runtime error")
e.backtrace.should == nil
full_message = e.full_message(highlight: false, order: :top).lines
- full_message[0].should.start_with?("#{__FILE__}:#{__LINE__-1}:in ")
+ full_message[0].should.start_with?("#{__FILE__}:#{__LINE__-1}:in `")
full_message[0].should.end_with?("': Some runtime error (RuntimeError)\n")
end
- describe "includes details about whether an exception was handled" do
- describe "RuntimeError" do
- it "should report as unhandled if message is empty" do
- err = RuntimeError.new("")
-
- err.full_message.should =~ /unhandled exception/
- err.full_message(highlight: true).should =~ /unhandled exception/
- err.full_message(highlight: false).should =~ /unhandled exception/
- end
-
- it "should not report as unhandled if the message is not empty" do
- err = RuntimeError.new("non-empty")
-
- err.full_message.should !~ /unhandled exception/
- err.full_message(highlight: true).should !~ /unhandled exception/
- err.full_message(highlight: false).should !~ /unhandled exception/
- end
-
- it "should not report as unhandled if the message is nil" do
- err = RuntimeError.new(nil)
-
- err.full_message.should !~ /unhandled exception/
- err.full_message(highlight: true).should !~ /unhandled exception/
- err.full_message(highlight: false).should !~ /unhandled exception/
- end
-
- it "should not report as unhandled if the message is not specified" do
- err = RuntimeError.new()
-
- err.full_message.should !~ /unhandled exception/
- err.full_message(highlight: true).should !~ /unhandled exception/
- err.full_message(highlight: false).should !~ /unhandled exception/
- end
- end
-
- describe "generic Error" do
- it "should not report as unhandled in any event" do
- StandardError.new("").full_message.should !~ /unhandled exception/
- StandardError.new("non-empty").full_message.should !~ /unhandled exception/
- end
- end
- end
-
it "shows the exception class at the end of the first line of the message when the message contains multiple lines" do
begin
line = __LINE__; raise "first line\nsecond line"
rescue => e
full_message = e.full_message(highlight: false, order: :top).lines
- full_message[0].should.start_with?("#{__FILE__}:#{line}:in ")
+ full_message[0].should.start_with?("#{__FILE__}:#{line}:in `")
full_message[0].should.end_with?(": first line (RuntimeError)\n")
full_message[1].should == "second line\n"
end
@@ -105,7 +62,7 @@ describe "Exception#full_message" do
line = __LINE__; raise "first line\nsecond line\nthird line"
rescue => e
full_message = e.full_message(highlight: true, order: :top).lines
- full_message[0].should.start_with?("#{__FILE__}:#{line}:in ")
+ full_message[0].should.start_with?("#{__FILE__}:#{line}:in `")
full_message[0].should.end_with?(": \e[1mfirst line (\e[1;4mRuntimeError\e[m\e[1m)\e[m\n")
full_message[1].should == "\e[1msecond line\e[m\n"
full_message[2].should == "\e[1mthird line\e[m\n"
@@ -146,53 +103,4 @@ describe "Exception#full_message" do
exception.full_message.should include "intermediate exception"
exception.full_message.should include "origin exception"
end
-
- ruby_version_is "3.2" do
- it "relies on #detailed_message" do
- e = RuntimeError.new("new error")
- e.define_singleton_method(:detailed_message) { |**| "DETAILED MESSAGE" }
-
- e.full_message.lines.first.should =~ /DETAILED MESSAGE/
- end
-
- it "passes all its own keyword arguments (with :highlight default value and without :order default value) to #detailed_message" do
- e = RuntimeError.new("new error")
- options_passed = nil
- e.define_singleton_method(:detailed_message) do |**options|
- options_passed = options
- "DETAILED MESSAGE"
- end
-
- e.full_message(foo: "bar")
- options_passed.should == { foo: "bar", highlight: Exception.to_tty? }
- end
-
- it "converts #detailed_message returned value to String if it isn't a String" do
- message = Object.new
- def message.to_str; "DETAILED MESSAGE"; end
-
- e = RuntimeError.new("new error")
- e.define_singleton_method(:detailed_message) { |**| message }
-
- e.full_message.lines.first.should =~ /DETAILED MESSAGE/
- end
-
- it "uses class name if #detailed_message returns nil" do
- e = RuntimeError.new("new error")
- e.define_singleton_method(:detailed_message) { |**| nil }
-
- e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
- e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
- end
-
- it "uses class name if exception object doesn't respond to #detailed_message" do
- e = RuntimeError.new("new error")
- class << e
- undef :detailed_message
- end
-
- e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
- e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
- end
- end
end
diff --git a/spec/ruby/core/exception/interrupt_spec.rb b/spec/ruby/core/exception/interrupt_spec.rb
index 90d261e470..299b5b81f3 100644
--- a/spec/ruby/core/exception/interrupt_spec.rb
+++ b/spec/ruby/core/exception/interrupt_spec.rb
@@ -54,7 +54,7 @@ describe "Interrupt" do
err = IO.popen([*ruby_exe, '-e', 'Process.kill :INT, Process.pid; sleep'], err: [:child, :out], &:read)
$?.termsig.should == Signal.list.fetch('INT')
err.should.include? ': Interrupt'
- err.should =~ /from -e:1:in [`']<main>'/
+ err.should.include? "from -e:1:in `<main>'"
end
end
end
diff --git a/spec/ruby/core/exception/no_method_error_spec.rb b/spec/ruby/core/exception/no_method_error_spec.rb
index 26df3338e9..8428ba0382 100644
--- a/spec/ruby/core/exception/no_method_error_spec.rb
+++ b/spec/ruby/core/exception/no_method_error_spec.rb
@@ -62,49 +62,26 @@ describe "NoMethodError#message" do
NoMethodErrorSpecs::NoMethodErrorC.new.a_private_method
rescue Exception => e
e.should be_kind_of(NoMethodError)
- e.message.lines[0].should =~ /private method [`']a_private_method' called for /
+ e.message.lines[0].should =~ /private method `a_private_method' called for #<NoMethodErrorSpecs::NoMethodErrorC:0x[\h]+>/
end
end
- ruby_version_is ""..."3.3" do
- it "calls receiver.inspect only when calling Exception#message" do
- ScratchPad.record []
- test_class = Class.new do
- def inspect
- ScratchPad << :inspect_called
- "<inspect>"
- end
- end
- instance = test_class.new
- begin
- instance.bar
- rescue Exception => e
- e.name.should == :bar
- ScratchPad.recorded.should == []
- e.message.should =~ /undefined method.+\bbar\b/
- ScratchPad.recorded.should == [:inspect_called]
+ it "calls receiver.inspect only when calling Exception#message" do
+ ScratchPad.record []
+ test_class = Class.new do
+ def inspect
+ ScratchPad << :inspect_called
+ "<inspect>"
end
end
- end
-
- ruby_version_is "3.3" do
- it "does not call receiver.inspect even when calling Exception#message" do
- ScratchPad.record []
- test_class = Class.new do
- def inspect
- ScratchPad << :inspect_called
- "<inspect>"
- end
- end
- instance = test_class.new
- begin
- instance.bar
- rescue Exception => e
- e.name.should == :bar
- ScratchPad.recorded.should == []
- e.message.should =~ /undefined method.+\bbar\b/
- ScratchPad.recorded.should == []
- end
+ instance = test_class.new
+ begin
+ instance.bar
+ rescue Exception => e
+ e.name.should == :bar
+ ScratchPad.recorded.should == []
+ e.message.should =~ /undefined method.+\bbar\b/
+ ScratchPad.recorded.should == [:inspect_called]
end
end
@@ -125,19 +102,21 @@ describe "NoMethodError#message" do
end
end
- it "uses #name to display the receiver if it is a class or a module" do
- klass = Class.new { def self.name; "MyClass"; end }
- begin
- klass.foo
- rescue NoMethodError => error
- error.message.lines.first.chomp.should =~ /^undefined method [`']foo' for /
- end
+ ruby_version_is "3.0" do
+ it "uses #name to display the receiver if it is a class or a module" do
+ klass = Class.new { def self.name; "MyClass"; end }
+ begin
+ klass.foo
+ rescue NoMethodError => error
+ error.message.lines.first.chomp.should == "undefined method `foo' for MyClass:Class"
+ end
- mod = Module.new { def self.name; "MyModule"; end }
- begin
- mod.foo
- rescue NoMethodError => error
- error.message.lines.first.chomp.should =~ /^undefined method [`']foo' for /
+ mod = Module.new { def self.name; "MyModule"; end }
+ begin
+ mod.foo
+ rescue NoMethodError => error
+ error.message.lines.first.chomp.should == "undefined method `foo' for MyModule:Module"
+ end
end
end
end
diff --git a/spec/ruby/core/exception/set_backtrace_spec.rb b/spec/ruby/core/exception/set_backtrace_spec.rb
index 12c1da919c..ba2e1bf7aa 100644
--- a/spec/ruby/core/exception/set_backtrace_spec.rb
+++ b/spec/ruby/core/exception/set_backtrace_spec.rb
@@ -11,37 +11,9 @@ describe "Exception#set_backtrace" do
it "allows the user to set the backtrace from a rescued exception" do
bt = ExceptionSpecs::Backtrace.backtrace
err = RuntimeError.new
- err.backtrace.should == nil
- err.backtrace_locations.should == nil
err.set_backtrace bt
-
err.backtrace.should == bt
- err.backtrace_locations.should == nil
- end
-
- ruby_version_is "3.4" do
- it "allows the user to set backtrace locations from a rescued exception" do
- bt_locations = ExceptionSpecs::Backtrace.backtrace_locations
- err = RuntimeError.new
- err.backtrace.should == nil
- err.backtrace_locations.should == nil
-
- err.set_backtrace bt_locations
-
- err.backtrace_locations.size.should == bt_locations.size
- err.backtrace_locations.each_with_index do |loc, index|
- other_loc = bt_locations[index]
-
- loc.path.should == other_loc.path
- loc.label.should == other_loc.label
- loc.base_label.should == other_loc.base_label
- loc.lineno.should == other_loc.lineno
- loc.absolute_path.should == other_loc.absolute_path
- loc.to_s.should == other_loc.to_s
- end
- err.backtrace.size.should == err.backtrace_locations.size
- end
end
it "accepts an empty Array" do
diff --git a/spec/ruby/core/exception/syntax_error_spec.rb b/spec/ruby/core/exception/syntax_error_spec.rb
deleted file mode 100644
index 6cc8522de3..0000000000
--- a/spec/ruby/core/exception/syntax_error_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative '../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "SyntaxError#path" do
- it "returns the file path provided to eval" do
- filename = "speccing.rb"
-
- -> {
- eval("if true", TOPLEVEL_BINDING, filename)
- }.should raise_error(SyntaxError) { |e|
- e.path.should == filename
- }
- end
-
- it "returns the file path that raised an exception" do
- expected_path = fixture(__FILE__, "syntax_error.rb")
-
- -> {
- require_relative "fixtures/syntax_error"
- }.should raise_error(SyntaxError) { |e| e.path.should == expected_path }
- end
-
- it "returns nil when constructed directly" do
- SyntaxError.new.path.should == nil
- end
- end
-end
diff --git a/spec/ruby/core/exception/to_s_spec.rb b/spec/ruby/core/exception/to_s_spec.rb
index 65c0d73a98..4c4c7ab432 100644
--- a/spec/ruby/core/exception/to_s_spec.rb
+++ b/spec/ruby/core/exception/to_s_spec.rb
@@ -23,7 +23,7 @@ describe "NameError#to_s" do
begin
puts not_defined
rescue => exception
- exception.message.should =~ /undefined local variable or method [`']not_defined'/
+ exception.message.should =~ /undefined local variable or method `not_defined'/
end
end
diff --git a/spec/ruby/core/exception/top_level_spec.rb b/spec/ruby/core/exception/top_level_spec.rb
index cc961d06d5..b47648425e 100644
--- a/spec/ruby/core/exception/top_level_spec.rb
+++ b/spec/ruby/core/exception/top_level_spec.rb
@@ -2,38 +2,30 @@ require_relative '../../spec_helper'
describe "An Exception reaching the top level" do
it "is printed on STDERR" do
- ruby_exe('raise "foo"', args: "2>&1", exit_status: 1).should =~ /in [`']<main>': foo \(RuntimeError\)/
+ ruby_exe('raise "foo"', args: "2>&1", exit_status: 1).should.include?("in `<main>': foo (RuntimeError)")
end
it "the Exception#cause is printed to STDERR with backtraces" do
code = <<-RUBY
def raise_cause
- raise "the cause" # 2
+ raise "the cause"
end
def raise_wrapped
- raise "wrapped" # 5
+ raise "wrapped"
end
begin
- raise_cause # 8
+ raise_cause
rescue
- raise_wrapped # 10
+ raise_wrapped
end
RUBY
lines = ruby_exe(code, args: "2>&1", exit_status: 1).lines
-
- lines.map! { |l| l.chomp[/:(\d+:in.+)/, 1] }
- lines[0].should =~ /\A5:in [`'](?:Object#)?raise_wrapped': wrapped \(RuntimeError\)\z/
- if lines[1].include? 'rescue in'
- # CRuby < 3.4 has an extra 'rescue in' backtrace entry
- lines[1].should =~ /\A10:in [`']rescue in <main>'\z/
- lines.delete_at 1
- lines[1].should =~ /\A7:in [`']<main>'\z/
- else
- lines[1].should =~ /\A10:in [`']<main>'\z/
- end
- lines[2].should =~ /\A2:in [`'](?:Object#)?raise_cause': the cause \(RuntimeError\)\z/
- lines[3].should =~ /\A8:in [`']<main>'\z/
- lines.size.should == 4
+ lines.reject! { |l| l.include?('rescue in') }
+ lines.map! { |l| l.chomp[/:(in.+)/, 1] }
+ lines.should == ["in `raise_wrapped': wrapped (RuntimeError)",
+ "in `<main>'",
+ "in `raise_cause': the cause (RuntimeError)",
+ "in `<main>'"]
end
describe "with a custom backtrace" do
@@ -50,16 +42,4 @@ describe "An Exception reaching the top level" do
EOS
end
end
-
- describe "kills all threads and fibers, ensure clauses are only run for threads current fibers, not for suspended fibers" do
- it "with ensure on the root fiber" do
- file = fixture(__FILE__, "thread_fiber_ensure.rb")
- ruby_exe(file, args: "2>&1", exit_status: 0).should == "current fiber ensure\n"
- end
-
- it "with ensure on non-root fiber" do
- file = fixture(__FILE__, "thread_fiber_ensure_non_root_fiber.rb")
- ruby_exe(file, args: "2>&1", exit_status: 0).should == "current fiber ensure\n"
- end
- end
end
diff --git a/spec/ruby/core/false/singleton_method_spec.rb b/spec/ruby/core/false/singleton_method_spec.rb
deleted file mode 100644
index 738794b46c..0000000000
--- a/spec/ruby/core/false/singleton_method_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "FalseClass#singleton_method" do
- ruby_version_is '3.3' do
- it "raises regardless of whether FalseClass defines the method" do
- -> { false.singleton_method(:foo) }.should raise_error(NameError)
- begin
- def (false).foo; end
- -> { false.singleton_method(:foo) }.should raise_error(NameError)
- ensure
- FalseClass.send(:remove_method, :foo)
- end
- end
- end
-end
diff --git a/spec/ruby/core/fiber/blocking_spec.rb b/spec/ruby/core/fiber/blocking_spec.rb
index ebefa116af..eeee5a71c1 100644
--- a/spec/ruby/core/fiber/blocking_spec.rb
+++ b/spec/ruby/core/fiber/blocking_spec.rb
@@ -1,59 +1,61 @@
require_relative '../../spec_helper'
require_relative 'shared/blocking'
-require "fiber"
+ruby_version_is "3.0" do
+ require "fiber"
-describe "Fiber.blocking?" do
- it_behaves_like :non_blocking_fiber, -> { Fiber.blocking? }
+ describe "Fiber.blocking?" do
+ it_behaves_like :non_blocking_fiber, -> { Fiber.blocking? }
- context "when fiber is blocking" do
- context "root Fiber of the main thread" do
- it "returns 1 for blocking: true" do
- fiber = Fiber.new(blocking: true) { Fiber.blocking? }
- blocking = fiber.resume
-
- blocking.should == 1
- end
- end
-
- context "root Fiber of a new thread" do
- it "returns 1 for blocking: true" do
- thread = Thread.new do
+ context "when fiber is blocking" do
+ context "root Fiber of the main thread" do
+ it "returns 1 for blocking: true" do
fiber = Fiber.new(blocking: true) { Fiber.blocking? }
blocking = fiber.resume
blocking.should == 1
end
-
- thread.join
end
- end
- end
-end
-describe "Fiber#blocking?" do
- it_behaves_like :non_blocking_fiber, -> { Fiber.current.blocking? }
+ context "root Fiber of a new thread" do
+ it "returns 1 for blocking: true" do
+ thread = Thread.new do
+ fiber = Fiber.new(blocking: true) { Fiber.blocking? }
+ blocking = fiber.resume
- context "when fiber is blocking" do
- context "root Fiber of the main thread" do
- it "returns true for blocking: true" do
- fiber = Fiber.new(blocking: true) { Fiber.current.blocking? }
- blocking = fiber.resume
+ blocking.should == 1
+ end
- blocking.should == true
+ thread.join
+ end
end
end
+ end
- context "root Fiber of a new thread" do
- it "returns true for blocking: true" do
- thread = Thread.new do
+ describe "Fiber#blocking?" do
+ it_behaves_like :non_blocking_fiber, -> { Fiber.current.blocking? }
+
+ context "when fiber is blocking" do
+ context "root Fiber of the main thread" do
+ it "returns true for blocking: true" do
fiber = Fiber.new(blocking: true) { Fiber.current.blocking? }
blocking = fiber.resume
blocking.should == true
end
+ end
- thread.join
+ context "root Fiber of a new thread" do
+ it "returns true for blocking: true" do
+ thread = Thread.new do
+ fiber = Fiber.new(blocking: true) { Fiber.current.blocking? }
+ blocking = fiber.resume
+
+ blocking.should == true
+ end
+
+ thread.join
+ end
end
end
end
diff --git a/spec/ruby/core/fiber/inspect_spec.rb b/spec/ruby/core/fiber/inspect_spec.rb
deleted file mode 100644
index f20a153fc2..0000000000
--- a/spec/ruby/core/fiber/inspect_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require_relative '../../spec_helper'
-require 'fiber'
-
-describe "Fiber#inspect" do
- describe "status" do
- it "is resumed for the root Fiber of a Thread" do
- inspected = Thread.new { Fiber.current.inspect }.value
- inspected.should =~ /\A#<Fiber:0x\h+ .*\(resumed\)>\z/
- end
-
- it "is created for a Fiber which did not run yet" do
- inspected = Fiber.new {}.inspect
- inspected.should =~ /\A#<Fiber:0x\h+ .+ \(created\)>\z/
- end
-
- it "is resumed for a Fiber which was resumed" do
- inspected = Fiber.new { Fiber.current.inspect }.resume
- inspected.should =~ /\A#<Fiber:0x\h+ .+ \(resumed\)>\z/
- end
-
- it "is resumed for a Fiber which was transferred" do
- inspected = Fiber.new { Fiber.current.inspect }.transfer
- inspected.should =~ /\A#<Fiber:0x\h+ .+ \(resumed\)>\z/
- end
-
- it "is suspended for a Fiber which was resumed and yielded" do
- inspected = Fiber.new { Fiber.yield }.tap(&:resume).inspect
- inspected.should =~ /\A#<Fiber:0x\h+ .+ \(suspended\)>\z/
- end
-
- it "is terminated for a Fiber which has terminated" do
- inspected = Fiber.new {}.tap(&:resume).inspect
- inspected.should =~ /\A#<Fiber:0x\h+ .+ \(terminated\)>\z/
- end
- end
-end
diff --git a/spec/ruby/core/fiber/kill_spec.rb b/spec/ruby/core/fiber/kill_spec.rb
deleted file mode 100644
index 2f4c499280..0000000000
--- a/spec/ruby/core/fiber/kill_spec.rb
+++ /dev/null
@@ -1,90 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative '../../shared/kernel/raise'
-
-ruby_version_is "3.3" do
- describe "Fiber#kill" do
- it "kills a non-resumed fiber" do
- fiber = Fiber.new{}
-
- fiber.alive?.should == true
-
- fiber.kill
- fiber.alive?.should == false
- end
-
- it "kills a resumed fiber" do
- fiber = Fiber.new{while true; Fiber.yield; end}
- fiber.resume
-
- fiber.alive?.should == true
-
- fiber.kill
- fiber.alive?.should == false
- end
-
- it "can kill itself" do
- fiber = Fiber.new do
- Fiber.current.kill
- end
-
- fiber.alive?.should == true
-
- fiber.resume
- fiber.alive?.should == false
- end
-
- it "kills a resumed fiber from a child" do
- parent = Fiber.new do
- child = Fiber.new do
- parent.kill
- parent.alive?.should == true
- end
-
- child.resume
- end
-
- parent.resume
- parent.alive?.should == false
- end
-
- it "executes the ensure block" do
- ensure_executed = false
-
- fiber = Fiber.new do
- while true; Fiber.yield; end
- ensure
- ensure_executed = true
- end
-
- fiber.resume
- fiber.kill
- ensure_executed.should == true
- end
-
- it "does not execute rescue block" do
- rescue_executed = false
-
- fiber = Fiber.new do
- while true; Fiber.yield; end
- rescue Exception
- rescue_executed = true
- end
-
- fiber.resume
- fiber.kill
- rescue_executed.should == false
- end
-
- it "repeatedly kills a fiber" do
- fiber = Fiber.new do
- while true; Fiber.yield; end
- ensure
- while true; Fiber.yield; end
- end
-
- fiber.kill
- fiber.alive?.should == false
- end
- end
-end
diff --git a/spec/ruby/core/fiber/raise_spec.rb b/spec/ruby/core/fiber/raise_spec.rb
index b3e021e636..09c4c1b524 100644
--- a/spec/ruby/core/fiber/raise_spec.rb
+++ b/spec/ruby/core/fiber/raise_spec.rb
@@ -91,49 +91,29 @@ describe "Fiber#raise" do
fiber_two.resume.should == [:yield_one, :rescued]
end
+end
- ruby_version_is "3.4" do
- it "raises on the resumed fiber" do
- root_fiber = Fiber.current
- f1 = Fiber.new { root_fiber.transfer }
- f2 = Fiber.new { f1.resume }
- f2.transfer
-
- -> do
- f2.raise(RuntimeError, "Expected error")
- end.should raise_error(RuntimeError, "Expected error")
- end
- it "raises on itself" do
- -> do
- Fiber.current.raise(RuntimeError, "Expected error")
- end.should raise_error(RuntimeError, "Expected error")
- end
-
- it "should raise on parent fiber" do
- f2 = nil
- f1 = Fiber.new do
- # This is equivalent to Kernel#raise:
- f2.raise(RuntimeError, "Expected error")
- end
- f2 = Fiber.new do
- f1.resume
- end
-
- -> do
- f2.resume
- end.should raise_error(RuntimeError, "Expected error")
+ruby_version_is ""..."3.0" do
+ describe "Fiber#raise" do
+ it "raises a FiberError if invoked on a transferring Fiber" do
+ require "fiber"
+ root = Fiber.current
+ fiber = Fiber.new { root.transfer }
+ fiber.transfer
+ -> { fiber.raise }.should raise_error(FiberError, "cannot resume transferred Fiber")
end
end
end
-
-describe "Fiber#raise" do
- it "transfers and raises on a transferring fiber" do
- require "fiber"
- root = Fiber.current
- fiber = Fiber.new { root.transfer }
- fiber.transfer
- -> { fiber.raise "msg" }.should raise_error(RuntimeError, "msg")
+ruby_version_is "3.0" do
+ describe "Fiber#raise" do
+ it "transfers and raises on a transferring fiber" do
+ require "fiber"
+ root = Fiber.current
+ fiber = Fiber.new { root.transfer }
+ fiber.transfer
+ -> { fiber.raise "msg" }.should raise_error(RuntimeError, "msg")
+ end
end
end
diff --git a/spec/ruby/core/fiber/resume_spec.rb b/spec/ruby/core/fiber/resume_spec.rb
index ab9a6799ab..273bc866af 100644
--- a/spec/ruby/core/fiber/resume_spec.rb
+++ b/spec/ruby/core/fiber/resume_spec.rb
@@ -28,9 +28,18 @@ describe "Fiber#resume" do
fiber.resume :second
end
- it "raises a FiberError if the Fiber tries to resume itself" do
- fiber = Fiber.new { fiber.resume }
- -> { fiber.resume }.should raise_error(FiberError, /current fiber/)
+ ruby_version_is '3.0' do
+ it "raises a FiberError if the Fiber tries to resume itself" do
+ fiber = Fiber.new { fiber.resume }
+ -> { fiber.resume }.should raise_error(FiberError, /current fiber/)
+ end
+ end
+
+ ruby_version_is '' ... '3.0' do
+ it "raises a FiberError if the Fiber tries to resume itself" do
+ fiber = Fiber.new { fiber.resume }
+ -> { fiber.resume }.should raise_error(FiberError, /double resume/)
+ end
end
it "returns control to the calling Fiber if called from one" do
diff --git a/spec/ruby/core/fiber/storage_spec.rb b/spec/ruby/core/fiber/storage_spec.rb
index 5c87ed5d41..e2bf6da04c 100644
--- a/spec/ruby/core/fiber/storage_spec.rb
+++ b/spec/ruby/core/fiber/storage_spec.rb
@@ -1,7 +1,9 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "Fiber.new(storage:)" do
+require 'fiber'
+
+describe "Fiber.new(storage:)" do
+ ruby_version_is "3.2" do
it "creates a Fiber with the given storage" do
storage = {life: 42}
fiber = Fiber.new(storage: storage) { Fiber.current.storage }
@@ -9,7 +11,7 @@ ruby_version_is "3.2" do
end
it "creates a fiber with lazily initialized storage" do
- Fiber.new(storage: nil) { Fiber[:x] = 10; Fiber.current.storage }.resume.should == {x: 10}
+ Fiber.new(storage: nil) { Fiber.current.storage }.resume.should == {}
end
it "creates a fiber by inheriting the storage of the parent fiber" do
@@ -22,40 +24,24 @@ ruby_version_is "3.2" do
it "cannot create a fiber with non-hash storage" do
-> { Fiber.new(storage: 42) {} }.should raise_error(TypeError)
end
-
- it "cannot create a fiber with a frozen hash as storage" do
- -> { Fiber.new(storage: {life: 43}.freeze) {} }.should raise_error(FrozenError)
- end
-
- it "cannot create a fiber with a storage hash with non-symbol keys" do
- -> { Fiber.new(storage: {life: 43, Object.new => 44}) {} }.should raise_error(TypeError)
- end
- end
-
- describe "Fiber#storage" do
- it "cannot be accessed from a different fiber" do
- f = Fiber.new(storage: {life: 42}) { nil }
- -> {
- f.storage
- }.should raise_error(ArgumentError, /Fiber storage can only be accessed from the Fiber it belongs to/)
- end
end
+end
- describe "Fiber#storage=" do
+describe "Fiber#storage=" do
+ ruby_version_is "3.2" do
it "can clear the storage of the fiber" do
- fiber = Fiber.new(storage: {life: 42}) do
+ fiber = Fiber.new(storage: {life: 42}) {
Fiber.current.storage = nil
- Fiber[:x] = 10
Fiber.current.storage
- end
- fiber.resume.should == {x: 10}
+ }
+ fiber.resume.should == {}
end
it "can set the storage of the fiber" do
- fiber = Fiber.new(storage: {life: 42}) do
+ fiber = Fiber.new(storage: {life: 42}) {
Fiber.current.storage = {life: 43}
Fiber.current.storage
- end
+ }
fiber.resume.should == {life: 43}
end
@@ -71,8 +57,10 @@ ruby_version_is "3.2" do
-> { Fiber.current.storage = {life: 43, Object.new => 44} }.should raise_error(TypeError)
end
end
+end
- describe "Fiber.[]" do
+describe "Fiber.[]" do
+ ruby_version_is "3.2" do
it "returns the value of the given key in the storage of the current fiber" do
Fiber.new(storage: {life: 42}) { Fiber[:life] }.resume.should == 42
end
@@ -84,34 +72,25 @@ ruby_version_is "3.2" do
it "returns nil if the current fiber has no storage" do
Fiber.new { Fiber[:life] }.resume.should be_nil
end
+ end
- ruby_version_is "3.2.3" do
- it "can use dynamically defined keys" do
- key = :"#{self.class.name}#.#{self.object_id}"
- Fiber.new { Fiber[key] = 42; Fiber[key] }.resume.should == 42
- end
-
- it "can't use invalid keys" do
- invalid_keys = [Object.new, "Foo", 12]
- invalid_keys.each do |key|
- -> { Fiber[key] }.should raise_error(TypeError)
- end
- end
+ ruby_version_is "3.2.3" do
+ it "can use dynamically defined keys" do
+ key = :"#{self.class.name}#.#{self.object_id}"
+ Fiber.new { Fiber[key] = 42; Fiber[key] }.resume.should == 42
end
- it "can access the storage of the parent fiber" do
- f = Fiber.new(storage: {life: 42}) do
- Fiber.new { Fiber[:life] }.resume
+ it "can't use invalid keys" do
+ invalid_keys = [Object.new, "Foo", 12]
+ invalid_keys.each do |key|
+ -> { Fiber[key] }.should raise_error(TypeError)
end
- f.resume.should == 42
- end
-
- it "can't access the storage of the fiber with non-symbol keys" do
- -> { Fiber[Object.new] }.should raise_error(TypeError)
end
end
+end
- describe "Fiber.[]=" do
+describe "Fiber.[]=" do
+ ruby_version_is "3.2" do
it "sets the value of the given key in the storage of the current fiber" do
Fiber.new(storage: {life: 42}) { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43
end
@@ -123,31 +102,11 @@ ruby_version_is "3.2" do
it "sets the value of the given key in the storage of the current fiber" do
Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43
end
-
- it "does not overwrite the storage of the parent fiber" do
- f = Fiber.new(storage: {life: 42}) do
- Fiber.yield Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume
- Fiber[:life]
- end
- f.resume.should == 43 # Value of the inner fiber
- f.resume.should == 42 # Value of the outer fiber
- end
-
- it "can't access the storage of the fiber with non-symbol keys" do
- -> { Fiber[Object.new] = 44 }.should raise_error(TypeError)
- end
-
- ruby_version_is "3.3" do
- it "deletes the fiber storage key when assigning nil" do
- Fiber.new(storage: {life: 42}) {
- Fiber[:life] = nil
- Fiber.current.storage
- }.resume.should == {}
- end
- end
end
+end
- describe "Thread.new" do
+describe "Thread.new" do
+ ruby_version_is "3.2" do
it "creates a thread with the storage of the current fiber" do
fiber = Fiber.new(storage: {life: 42}) do
Thread.new { Fiber.current.storage }.value
diff --git a/spec/ruby/core/file/absolute_path_spec.rb b/spec/ruby/core/file/absolute_path_spec.rb
index 315eead34f..e35c80ec3c 100644
--- a/spec/ruby/core/file/absolute_path_spec.rb
+++ b/spec/ruby/core/file/absolute_path_spec.rb
@@ -85,7 +85,7 @@ describe "File.absolute_path" do
end
it "accepts a second argument of a directory from which to resolve the path" do
- File.absolute_path(__FILE__, __dir__).should == @abs
+ File.absolute_path(__FILE__, File.dirname(__FILE__)).should == @abs
end
it "calls #to_path on its argument" do
diff --git a/spec/ruby/core/file/atime_spec.rb b/spec/ruby/core/file/atime_spec.rb
index e47e70e5ac..3df258016c 100644
--- a/spec/ruby/core/file/atime_spec.rb
+++ b/spec/ruby/core/file/atime_spec.rb
@@ -15,7 +15,7 @@ describe "File.atime" do
File.atime(@file).should be_kind_of(Time)
end
- platform_is :linux, :windows do
+ platform_is :linux do
unless ENV.key?('TRAVIS') # https://bugs.ruby-lang.org/issues/17926
## NOTE also that some Linux systems disable atime (e.g. via mount params) for better filesystem speed.
it "returns the last access time for the named file with microseconds" do
@@ -27,9 +27,6 @@ describe "File.atime" do
else
File.atime(__FILE__).usec.should == 0
end
- rescue Errno::ENOENT => e
- # Native Windows don't have stat command.
- skip e.message
end
end
end
diff --git a/spec/ruby/core/file/ctime_spec.rb b/spec/ruby/core/file/ctime_spec.rb
index 718f26d5cc..9b7ab272ff 100644
--- a/spec/ruby/core/file/ctime_spec.rb
+++ b/spec/ruby/core/file/ctime_spec.rb
@@ -14,7 +14,7 @@ describe "File.ctime" do
File.ctime(@file).should be_kind_of(Time)
end
- platform_is :linux, :windows do
+ platform_is :linux do
it "returns the change time for the named file (the time at which directory information about the file was changed, not the file itself) with microseconds." do
supports_subseconds = Integer(`stat -c%z '#{__FILE__}'`[/\.(\d{1,6})/, 1], 10)
if supports_subseconds != 0
@@ -22,9 +22,6 @@ describe "File.ctime" do
else
File.ctime(__FILE__).usec.should == 0
end
- rescue Errno::ENOENT => e
- # Windows don't have stat command.
- skip e.message
end
end
diff --git a/spec/ruby/core/file/dirname_spec.rb b/spec/ruby/core/file/dirname_spec.rb
index 8dd6c4ca88..cf0f909f59 100644
--- a/spec/ruby/core/file/dirname_spec.rb
+++ b/spec/ruby/core/file/dirname_spec.rb
@@ -12,33 +12,18 @@ describe "File.dirname" do
end
ruby_version_is '3.1' do
- context "when level is passed" do
- it "returns all the components of filename except the last parts by the level" do
- File.dirname('/home/jason', 2).should == '/'
- File.dirname('/home/jason/poot.txt', 2).should == '/home'
- end
-
- it "returns the same String if the level is 0" do
- File.dirname('poot.txt', 0).should == 'poot.txt'
- File.dirname('/', 0).should == '/'
- end
-
- it "raises ArgumentError if the level is negative" do
- -> {
- File.dirname('/home/jason', -1)
- }.should raise_error(ArgumentError, "negative level: -1")
- end
-
- it "returns '/' when level exceeds the number of segments in the path" do
- File.dirname("/home/jason", 100).should == '/'
- end
-
- it "calls #to_int if passed not numeric value" do
- object = Object.new
- def object.to_int; 2; end
-
- File.dirname("/a/b/c/d", object).should == '/a/b'
- end
+ it "returns all the components of filename except the last parts by the level" do
+ File.dirname('/home/jason', 2).should == '/'
+ File.dirname('/home/jason/poot.txt', 2).should == '/home'
+ end
+
+ it "returns the same string if the level is 0" do
+ File.dirname('poot.txt', 0).should == 'poot.txt'
+ File.dirname('/', 0).should == '/'
+ end
+
+ it "raises ArgumentError if the level is negative" do
+ -> {File.dirname('/home/jason', -1)}.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/file/exist_spec.rb b/spec/ruby/core/file/exist_spec.rb
index 2633376880..ddb5febcba 100644
--- a/spec/ruby/core/file/exist_spec.rb
+++ b/spec/ruby/core/file/exist_spec.rb
@@ -4,11 +4,3 @@ require_relative '../../shared/file/exist'
describe "File.exist?" do
it_behaves_like :file_exist, :exist?, File
end
-
-ruby_version_is "3.2" do
- describe "File.exists?" do
- it "has been removed" do
- File.should_not.respond_to?(:exists?)
- end
- end
-end
diff --git a/spec/ruby/core/file/expand_path_spec.rb b/spec/ruby/core/file/expand_path_spec.rb
index 1abcf93900..c31f885b92 100644
--- a/spec/ruby/core/file/expand_path_spec.rb
+++ b/spec/ruby/core/file/expand_path_spec.rb
@@ -137,7 +137,7 @@ describe "File.expand_path" do
it "returns a String in the same encoding as the argument" do
Encoding.default_external = Encoding::SHIFT_JIS
- path = "./a".dup.force_encoding Encoding::CP1251
+ path = "./a".force_encoding Encoding::CP1251
File.expand_path(path).encoding.should equal(Encoding::CP1251)
weird_path = [222, 173, 190, 175].pack('C*')
diff --git a/spec/ruby/core/file/flock_spec.rb b/spec/ruby/core/file/flock_spec.rb
index 070d830bc4..751e99d994 100644
--- a/spec/ruby/core/file/flock_spec.rb
+++ b/spec/ruby/core/file/flock_spec.rb
@@ -30,7 +30,7 @@ describe "File#flock" do
it "returns false if trying to lock an exclusively locked file" do
@file.flock File::LOCK_EX
- ruby_exe(<<-END_OF_CODE).should == "false"
+ ruby_exe(<<-END_OF_CODE, escape: true).should == "false"
File.open('#{@name}', "w") do |f2|
print f2.flock(File::LOCK_EX | File::LOCK_NB).to_s
end
@@ -40,7 +40,7 @@ describe "File#flock" do
it "blocks if trying to lock an exclusively locked file" do
@file.flock File::LOCK_EX
- out = ruby_exe(<<-END_OF_CODE)
+ out = ruby_exe(<<-END_OF_CODE, escape: true)
running = false
t = Thread.new do
diff --git a/spec/ruby/core/file/lutime_spec.rb b/spec/ruby/core/file/lutime_spec.rb
index 0f6df42ea3..1f0625f61e 100644
--- a/spec/ruby/core/file/lutime_spec.rb
+++ b/spec/ruby/core/file/lutime_spec.rb
@@ -1,12 +1,7 @@
require_relative '../../spec_helper'
-require_relative 'shared/update_time'
-platform_is_not :windows do
- describe "File.lutime" do
- it_behaves_like :update_time, :lutime
- end
-
- describe "File.lutime" do
+describe "File.lutime" do
+ platform_is_not :windows do
before :each do
@atime = Time.utc(2000)
@mtime = Time.utc(2001)
diff --git a/spec/ruby/core/file/mtime_spec.rb b/spec/ruby/core/file/mtime_spec.rb
index 0e9c95caee..6c43265a2c 100644
--- a/spec/ruby/core/file/mtime_spec.rb
+++ b/spec/ruby/core/file/mtime_spec.rb
@@ -15,7 +15,7 @@ describe "File.mtime" do
File.mtime(@filename).should be_close(@mtime, TIME_TOLERANCE)
end
- platform_is :linux, :windows do
+ platform_is :linux do
unless ENV.key?('TRAVIS') # https://bugs.ruby-lang.org/issues/17926
it "returns the modification Time of the file with microseconds" do
supports_subseconds = Integer(`stat -c%y '#{__FILE__}'`[/\.(\d{1,6})/, 1], 10)
@@ -26,9 +26,6 @@ describe "File.mtime" do
else
File.mtime(__FILE__).usec.should == 0
end
- rescue Errno::ENOENT => e
- # Windows don't have stat command.
- skip e.message
end
end
end
diff --git a/spec/ruby/core/file/new_spec.rb b/spec/ruby/core/file/new_spec.rb
index 1e82a070b1..004f78503a 100644
--- a/spec/ruby/core/file/new_spec.rb
+++ b/spec/ruby/core/file/new_spec.rb
@@ -78,29 +78,13 @@ describe "File.new" do
File.should.exist?(@file)
end
- it "returns a new read-only File when mode is not specified" do
- @fh = File.new(@file)
-
- -> { @fh.puts("test") }.should raise_error(IOError)
- @fh.read.should == ""
- File.should.exist?(@file)
- end
-
- it "returns a new read-only File when mode is not specified but flags option is present" do
- @fh = File.new(@file, flags: File::CREAT)
-
- -> { @fh.puts("test") }.should raise_error(IOError)
- @fh.read.should == ""
- File.should.exist?(@file)
- end
-
it "creates a new file when use File::EXCL mode" do
@fh = File.new(@file, File::EXCL)
@fh.should be_kind_of(File)
File.should.exist?(@file)
end
- it "raises an Errno::EEXIST if the file exists when create a new file with File::CREAT|File::EXCL" do
+ it "raises an Errorno::EEXIST if the file exists when create a new file with File::CREAT|File::EXCL" do
-> { @fh = File.new(@file, File::CREAT|File::EXCL) }.should raise_error(Errno::EEXIST)
end
@@ -128,32 +112,13 @@ describe "File.new" do
File.should.exist?(@file)
end
+
it "creates a new file when use File::WRONLY|File::TRUNC mode" do
@fh = File.new(@file, File::WRONLY|File::TRUNC)
@fh.should be_kind_of(File)
File.should.exist?(@file)
end
- it "returns a new read-only File when use File::RDONLY|File::CREAT mode" do
- @fh = File.new(@file, File::RDONLY|File::CREAT)
- @fh.should be_kind_of(File)
- File.should.exist?(@file)
-
- # it's read-only
- -> { @fh.puts("test") }.should raise_error(IOError)
- @fh.read.should == ""
- end
-
- it "returns a new read-only File when use File::CREAT mode" do
- @fh = File.new(@file, File::CREAT)
- @fh.should be_kind_of(File)
- File.should.exist?(@file)
-
- # it's read-only
- -> { @fh.puts("test") }.should raise_error(IOError)
- @fh.read.should == ""
- end
-
it "coerces filename using to_str" do
name = mock("file")
name.should_receive(:to_str).and_return(@file)
@@ -168,32 +133,6 @@ describe "File.new" do
File.should.exist?(@file)
end
- it "accepts options as a keyword argument" do
- @fh = File.new(@file, 'w', 0755, flags: @flags)
- @fh.should be_kind_of(File)
- @fh.close
-
- -> {
- @fh = File.new(@file, 'w', 0755, {flags: @flags})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
- end
-
- it "bitwise-ORs mode and flags option" do
- -> {
- @fh = File.new(@file, 'w', flags: File::EXCL)
- }.should raise_error(Errno::EEXIST, /File exists/)
-
- -> {
- @fh = File.new(@file, mode: 'w', flags: File::EXCL)
- }.should raise_error(Errno::EEXIST, /File exists/)
- end
-
- it "does not use the given block and warns to use File::open" do
- -> {
- @fh = File.new(@file) { raise }
- }.should complain(/warning: File::new\(\) does not take block; use File::open\(\) instead/)
- end
-
it "raises a TypeError if the first parameter can't be coerced to a string" do
-> { File.new(true) }.should raise_error(TypeError)
-> { File.new(false) }.should raise_error(TypeError)
diff --git a/spec/ruby/core/file/open_spec.rb b/spec/ruby/core/file/open_spec.rb
index 6bfc16bbf9..1729780570 100644
--- a/spec/ruby/core/file/open_spec.rb
+++ b/spec/ruby/core/file/open_spec.rb
@@ -314,7 +314,7 @@ describe "File.open" do
end
end
- it "raises an IOError when write in a block opened with File::RDONLY|File::APPEND mode" do
+ it "raises an IOError when read in a block opened with File::RDONLY|File::APPEND mode" do
-> {
File.open(@file, File::RDONLY|File::APPEND ) do |f|
f.puts("writing")
@@ -354,7 +354,7 @@ describe "File.open" do
end
end
- it "raises an Errno::EEXIST if the file exists when open with File::CREAT|File::EXCL" do
+ it "raises an Errorno::EEXIST if the file exists when open with File::CREAT|File::EXCL" do
-> {
File.open(@file, File::CREAT|File::EXCL) do |f|
f.puts("writing")
@@ -423,7 +423,7 @@ describe "File.open" do
}.should raise_error(IOError)
end
- it "raises an Errno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
+ it "raises an Errorno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
-> {
File.open(@file, File::RDONLY|File::TRUNC) do |f|
f.puts("writing").should == nil
@@ -441,7 +441,7 @@ describe "File.open" do
}.should raise_error(Errno::EINVAL)
end
- it "raises an Errno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
+ it "raises an Errorno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
-> {
File.open(@file, File::RDONLY|File::TRUNC) do |f|
f.puts("writing").should == nil
@@ -565,15 +565,6 @@ describe "File.open" do
File.open(@file, 'wb+') {|f| f.external_encoding.should == Encoding::BINARY}
end
- it "accepts options as a keyword argument" do
- @fh = File.open(@file, 'w', 0755, flags: File::CREAT)
- @fh.should be_an_instance_of(File)
-
- -> {
- File.open(@file, 'w', 0755, {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
- end
-
it "uses the second argument as an options Hash" do
@fh = File.open(@file, mode: "r")
@fh.should be_an_instance_of(File)
diff --git a/spec/ruby/core/file/realpath_spec.rb b/spec/ruby/core/file/realpath_spec.rb
index bd25bfdecf..bd27e09da6 100644
--- a/spec/ruby/core/file/realpath_spec.rb
+++ b/spec/ruby/core/file/realpath_spec.rb
@@ -54,10 +54,6 @@ platform_is_not :windows do
File.realpath(@relative_symlink).should == @file
end
- it "removes the file element when going one level up" do
- File.realpath('../', @file).should == @real_dir
- end
-
it "raises an Errno::ELOOP if the symlink points to itself" do
File.unlink @link
File.symlink(@link, @link)
diff --git a/spec/ruby/core/file/shared/fnmatch.rb b/spec/ruby/core/file/shared/fnmatch.rb
index db4b5c5d8c..94f22144b0 100644
--- a/spec/ruby/core/file/shared/fnmatch.rb
+++ b/spec/ruby/core/file/shared/fnmatch.rb
@@ -102,7 +102,6 @@ describe :file_fnmatch, shared: true do
it "matches ranges of characters using exclusive bracket expression (e.g. [^t] or [!t])" do
File.send(@method, 'ca[^t]', 'cat').should == false
- File.send(@method, 'ca[^t]', 'cas').should == true
File.send(@method, 'ca[!t]', 'cat').should == false
end
@@ -126,13 +125,6 @@ describe :file_fnmatch, shared: true do
end
end
- it "matches wildcard with characters when flags includes FNM_PATHNAME" do
- File.send(@method, '*a', 'aa', File::FNM_PATHNAME).should == true
- File.send(@method, 'a*', 'aa', File::FNM_PATHNAME).should == true
- File.send(@method, 'a*', 'aaa', File::FNM_PATHNAME).should == true
- File.send(@method, '*a', 'aaa', File::FNM_PATHNAME).should == true
- end
-
it "does not match '/' characters with ? or * when flags includes FNM_PATHNAME" do
File.send(@method, '?', '/', File::FNM_PATHNAME).should == false
File.send(@method, '*', '/', File::FNM_PATHNAME).should == false
@@ -173,19 +165,9 @@ describe :file_fnmatch, shared: true do
File.should_not.send(@method, '*/*', 'dave/.profile', File::FNM_PATHNAME)
end
- it "matches patterns with leading periods to dotfiles" do
+ it "matches patterns with leading periods to dotfiles by default" do
File.send(@method, '.*', '.profile').should == true
- File.send(@method, '.*', '.profile', File::FNM_PATHNAME).should == true
File.send(@method, ".*file", "nondotfile").should == false
- File.send(@method, ".*file", "nondotfile", File::FNM_PATHNAME).should == false
- end
-
- it "does not match directories with leading periods by default with FNM_PATHNAME" do
- File.send(@method, '.*', '.directory/nondotfile', File::FNM_PATHNAME).should == false
- File.send(@method, '.*', '.directory/.profile', File::FNM_PATHNAME).should == false
- File.send(@method, '.*', 'foo/.directory/nondotfile', File::FNM_PATHNAME).should == false
- File.send(@method, '.*', 'foo/.directory/.profile', File::FNM_PATHNAME).should == false
- File.send(@method, '**/.dotfile', '.dotsubdir/.dotfile', File::FNM_PATHNAME).should == false
end
it "matches leading periods in filenames when flags includes FNM_DOTMATCH" do
@@ -239,33 +221,6 @@ describe :file_fnmatch, shared: true do
File.send(@method, pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
end
- it "has special handling for ./ when using * and FNM_PATHNAME" do
- File.send(@method, './*', '.', File::FNM_PATHNAME).should be_false
- File.send(@method, './*', './', File::FNM_PATHNAME).should be_true
- File.send(@method, './*/', './', File::FNM_PATHNAME).should be_false
- File.send(@method, './**', './', File::FNM_PATHNAME).should be_true
- File.send(@method, './**/', './', File::FNM_PATHNAME).should be_true
- File.send(@method, './*', '.', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_false
- File.send(@method, './*', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
- File.send(@method, './*/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_false
- File.send(@method, './**', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
- File.send(@method, './**/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
- end
-
- it "matches **/* with FNM_PATHNAME to recurse directories" do
- File.send(@method, 'nested/**/*', 'nested/subdir', File::FNM_PATHNAME).should be_true
- File.send(@method, 'nested/**/*', 'nested/subdir/file', File::FNM_PATHNAME).should be_true
- File.send(@method, 'nested/**/*', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
- File.send(@method, 'nested/**/*', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
- end
-
- it "matches ** with FNM_PATHNAME only in current directory" do
- File.send(@method, 'nested/**', 'nested/subdir', File::FNM_PATHNAME).should be_true
- File.send(@method, 'nested/**', 'nested/subdir/file', File::FNM_PATHNAME).should be_false
- File.send(@method, 'nested/**', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
- File.send(@method, 'nested/**', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_false
- end
-
it "accepts an object that has a #to_path method" do
File.send(@method, '\*', mock_to_path('a')).should == false
end
diff --git a/spec/ruby/core/file/shared/path.rb b/spec/ruby/core/file/shared/path.rb
index aa2a64cf25..ee8109ba05 100644
--- a/spec/ruby/core/file/shared/path.rb
+++ b/spec/ruby/core/file/shared/path.rb
@@ -1,7 +1,7 @@
describe :file_path, shared: true do
before :each do
- @path = tmp("file_to_path")
- @name = File.basename(@path)
+ @name = "file_to_path"
+ @path = tmp(@name)
touch @path
end
diff --git a/spec/ruby/core/file/shared/update_time.rb b/spec/ruby/core/file/shared/update_time.rb
deleted file mode 100644
index 3fe7266a00..0000000000
--- a/spec/ruby/core/file/shared/update_time.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-describe :update_time, shared: true do
- before :all do
- @time_is_float = platform_is :windows
- end
-
- before :each do
- @atime = Time.now
- @mtime = Time.now
- @file1 = tmp("specs_file_utime1")
- @file2 = tmp("specs_file_utime2")
- touch @file1
- touch @file2
- end
-
- after :each do
- rm_r @file1, @file2
- end
-
- it "sets the access and modification time of each file" do
- File.send(@method, @atime, @mtime, @file1, @file2)
-
- if @time_is_float
- File.atime(@file1).should be_close(@atime, 0.0001)
- File.mtime(@file1).should be_close(@mtime, 0.0001)
- File.atime(@file2).should be_close(@atime, 0.0001)
- File.mtime(@file2).should be_close(@mtime, 0.0001)
- else
- File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
- File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
- File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
- File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
- end
- end
-
- it "uses the current times if two nil values are passed" do
- tn = Time.now
- File.send(@method, nil, nil, @file1, @file2)
-
- if @time_is_float
- File.atime(@file1).should be_close(tn, 0.050)
- File.mtime(@file1).should be_close(tn, 0.050)
- File.atime(@file2).should be_close(tn, 0.050)
- File.mtime(@file2).should be_close(tn, 0.050)
- else
- File.atime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
- File.mtime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
- File.atime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
- File.mtime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
- end
- end
-
- it "accepts an object that has a #to_path method" do
- File.send(@method, @atime, @mtime, mock_to_path(@file1), mock_to_path(@file2))
- end
-
- it "accepts numeric atime and mtime arguments" do
- if @time_is_float
- File.send(@method, @atime.to_f, @mtime.to_f, @file1, @file2)
-
- File.atime(@file1).should be_close(@atime, 0.0001)
- File.mtime(@file1).should be_close(@mtime, 0.0001)
- File.atime(@file2).should be_close(@atime, 0.0001)
- File.mtime(@file2).should be_close(@mtime, 0.0001)
- else
- File.send(@method, @atime.to_i, @mtime.to_i, @file1, @file2)
-
- File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
- File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
- File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
- File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
- end
- end
-
- it "may set nanosecond precision" do
- t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r)
- File.send(@method, t, t, @file1)
-
- File.atime(@file1).nsec.should.between?(0, 123500000)
- File.mtime(@file1).nsec.should.between?(0, 123500000)
- end
-
- it "returns the number of filenames in the arguments" do
- File.send(@method, @atime.to_f, @mtime.to_f, @file1, @file2).should == 2
- end
-
- platform_is :linux do
- platform_is pointer_size: 64 do
- it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19 or 2486-07-02)" do
- # https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Timestamps
- # "Therefore, timestamps should not overflow until May 2446."
- # https://lwn.net/Articles/804382/
- # "On-disk timestamps hitting the y2038 limit..."
- # The problem seems to be being improved, but currently it actually fails on XFS on RHEL8
- # https://rubyci.org/logs/rubyci.s3.amazonaws.com/rhel8/ruby-master/log/20201112T123004Z.fail.html.gz
- # Amazon Linux 2023 returns 2486-07-02 in this example
- # http://rubyci.s3.amazonaws.com/amazon2023/ruby-master/log/20230322T063004Z.fail.html.gz
- time = Time.at(1<<44)
- File.send(@method, time, time, @file1)
-
- [559444, 2486, 2446, 2038].should.include? File.atime(@file1).year
- [559444, 2486, 2446, 2038].should.include? File.mtime(@file1).year
- end
- end
- end
-end
diff --git a/spec/ruby/core/file/utime_spec.rb b/spec/ruby/core/file/utime_spec.rb
index d87626be50..cf7a0aec20 100644
--- a/spec/ruby/core/file/utime_spec.rb
+++ b/spec/ruby/core/file/utime_spec.rb
@@ -1,6 +1,104 @@
require_relative '../../spec_helper'
-require_relative 'shared/update_time'
describe "File.utime" do
- it_behaves_like :update_time, :utime
+
+ before :all do
+ @time_is_float = platform_is :windows
+ end
+
+ before :each do
+ @atime = Time.now
+ @mtime = Time.now
+ @file1 = tmp("specs_file_utime1")
+ @file2 = tmp("specs_file_utime2")
+ touch @file1
+ touch @file2
+ end
+
+ after :each do
+ rm_r @file1, @file2
+ end
+
+ platform_is_not :windows do
+ it "sets the access and modification time of each file" do
+ File.utime(@atime, @mtime, @file1, @file2)
+ if @time_is_float
+ File.atime(@file1).should be_close(@atime, 0.0001)
+ File.mtime(@file1).should be_close(@mtime, 0.0001)
+ File.atime(@file2).should be_close(@atime, 0.0001)
+ File.mtime(@file2).should be_close(@mtime, 0.0001)
+ else
+ File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
+ File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
+ File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
+ File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
+ end
+ end
+ end
+
+ it "uses the current times if two nil values are passed" do
+ tn = Time.now
+ File.utime(nil, nil, @file1, @file2)
+ if @time_is_float
+ File.atime(@file1).should be_close(tn, 0.050)
+ File.mtime(@file1).should be_close(tn, 0.050)
+ File.atime(@file2).should be_close(tn, 0.050)
+ File.mtime(@file2).should be_close(tn, 0.050)
+ else
+ File.atime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
+ File.mtime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
+ File.atime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
+ File.mtime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
+ end
+ end
+
+ it "accepts an object that has a #to_path method" do
+ File.utime(@atime, @mtime, mock_to_path(@file1), mock_to_path(@file2))
+ end
+
+ it "accepts numeric atime and mtime arguments" do
+ if @time_is_float
+ File.utime(@atime.to_f, @mtime.to_f, @file1, @file2)
+ File.atime(@file1).should be_close(@atime, 0.0001)
+ File.mtime(@file1).should be_close(@mtime, 0.0001)
+ File.atime(@file2).should be_close(@atime, 0.0001)
+ File.mtime(@file2).should be_close(@mtime, 0.0001)
+ else
+ File.utime(@atime.to_i, @mtime.to_i, @file1, @file2)
+ File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
+ File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
+ File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
+ File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
+ end
+ end
+
+ it "may set nanosecond precision" do
+ t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r)
+ File.utime(t, t, @file1)
+ File.atime(@file1).nsec.should.between?(0, 123500000)
+ File.mtime(@file1).nsec.should.between?(0, 123500000)
+ end
+
+ it "returns the number of filenames in the arguments" do
+ File.utime(@atime.to_f, @mtime.to_f, @file1, @file2).should == 2
+ end
+
+ platform_is :linux do
+ platform_is wordsize: 64 do
+ it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19 or 2486-07-02)" do
+ # https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Timestamps
+ # "Therefore, timestamps should not overflow until May 2446."
+ # https://lwn.net/Articles/804382/
+ # "On-disk timestamps hitting the y2038 limit..."
+ # The problem seems to be being improved, but currently it actually fails on XFS on RHEL8
+ # https://rubyci.org/logs/rubyci.s3.amazonaws.com/rhel8/ruby-master/log/20201112T123004Z.fail.html.gz
+ # Amazon Linux 2023 returns 2486-07-02 in this example
+ # http://rubyci.s3.amazonaws.com/amazon2023/ruby-master/log/20230322T063004Z.fail.html.gz
+ time = Time.at(1<<44)
+ File.utime(time, time, @file1)
+ [559444, 2486, 2446, 2038].should.include? File.atime(@file1).year
+ [559444, 2486, 2446, 2038].should.include? File.mtime(@file1).year
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/filetest/exist_spec.rb b/spec/ruby/core/filetest/exist_spec.rb
index a95d3f91a1..4d14bea231 100644
--- a/spec/ruby/core/filetest/exist_spec.rb
+++ b/spec/ruby/core/filetest/exist_spec.rb
@@ -4,11 +4,3 @@ require_relative '../../shared/file/exist'
describe "FileTest.exist?" do
it_behaves_like :file_exist, :exist?, FileTest
end
-
-ruby_version_is "3.2" do
- describe "FileTest.exists?" do
- it "has been removed" do
- FileTest.should_not.respond_to?(:exists?)
- end
- end
-end
diff --git a/spec/ruby/core/float/magnitude_spec.rb b/spec/ruby/core/float/magnitude_spec.rb
index 7cdd8ef28a..db577c15c5 100644
--- a/spec/ruby/core/float/magnitude_spec.rb
+++ b/spec/ruby/core/float/magnitude_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative 'shared/abs'
describe "Float#magnitude" do
diff --git a/spec/ruby/core/float/round_spec.rb b/spec/ruby/core/float/round_spec.rb
index 9b4c307f9d..e5a8f534e7 100644
--- a/spec/ruby/core/float/round_spec.rb
+++ b/spec/ruby/core/float/round_spec.rb
@@ -136,7 +136,7 @@ describe "Float#round" do
-4.809999999999999.round(5, half: :even).should eql(-4.81)
end
- ruby_bug "#19318", ""..."3.3" do
+ ruby_bug "", ""..."3.3" do
# These numbers are neighbouring floating point numbers round a
# precise value. They test that the rounding modes work correctly
# round that value and precision is not lost which might cause
diff --git a/spec/ruby/core/gc/auto_compact_spec.rb b/spec/ruby/core/gc/auto_compact_spec.rb
index 33ad1cb56c..4f9d043171 100644
--- a/spec/ruby/core/gc/auto_compact_spec.rb
+++ b/spec/ruby/core/gc/auto_compact_spec.rb
@@ -1,24 +1,26 @@
require_relative '../../spec_helper'
-describe "GC.auto_compact" do
- it "can set and get a boolean value" do
- begin
- GC.auto_compact = GC.auto_compact
- rescue NotImplementedError # platform does not support autocompact
- skip
- end
+ruby_version_is "3.0" do
+ describe "GC.auto_compact" do
+ it "can set and get a boolean value" do
+ begin
+ GC.auto_compact = GC.auto_compact
+ rescue NotImplementedError # platform does not support autocompact
+ skip
+ end
- original = GC.auto_compact
- begin
- GC.auto_compact = !original
- rescue NotImplementedError # platform does not support autocompact
- skip
- end
+ original = GC.auto_compact
+ begin
+ GC.auto_compact = !original
+ rescue NotImplementedError # platform does not support autocompact
+ skip
+ end
- begin
- GC.auto_compact.should == !original
- ensure
- GC.auto_compact = original
+ begin
+ GC.auto_compact.should == !original
+ ensure
+ GC.auto_compact = original
+ end
end
end
end
diff --git a/spec/ruby/core/hash/assoc_spec.rb b/spec/ruby/core/hash/assoc_spec.rb
index 62b2a11b30..64442918d1 100644
--- a/spec/ruby/core/hash/assoc_spec.rb
+++ b/spec/ruby/core/hash/assoc_spec.rb
@@ -22,11 +22,11 @@ describe "Hash#assoc" do
end
it "only returns the first matching key-value pair for identity hashes" do
- # Avoid literal String keys since string literals can be frozen and interned e.g. with --enable-frozen-string-literal
+ # Avoid literal String keys in Hash#[]= due to https://bugs.ruby-lang.org/issues/12855
h = {}.compare_by_identity
- k1 = 'pear'.dup
+ k1 = 'pear'
h[k1] = :red
- k2 = 'pear'.dup
+ k2 = 'pear'
h[k2] = :green
h.size.should == 2
h.keys.grep(/pear/).size.should == 2
diff --git a/spec/ruby/core/hash/compact_spec.rb b/spec/ruby/core/hash/compact_spec.rb
index 76aa43949d..2989afc8b7 100644
--- a/spec/ruby/core/hash/compact_spec.rb
+++ b/spec/ruby/core/hash/compact_spec.rb
@@ -18,30 +18,6 @@ describe "Hash#compact" do
@hash.compact
@hash.should == @initial_pairs
end
-
- ruby_version_is '3.3' do
- it "retains the default value" do
- hash = Hash.new(1)
- hash.compact.default.should == 1
- hash[:a] = 1
- hash.compact.default.should == 1
- end
-
- it "retains the default_proc" do
- pr = proc { |h, k| h[k] = [] }
- hash = Hash.new(&pr)
- hash.compact.default_proc.should == pr
- hash[:a] = 1
- hash.compact.default_proc.should == pr
- end
-
- it "retains compare_by_identity_flag" do
- hash = {}.compare_by_identity
- hash.compact.compare_by_identity?.should == true
- hash[:a] = 1
- hash.compact.compare_by_identity?.should == true
- end
- end
end
describe "Hash#compact!" do
diff --git a/spec/ruby/core/hash/compare_by_identity_spec.rb b/spec/ruby/core/hash/compare_by_identity_spec.rb
index 2975526a97..874cd46eb7 100644
--- a/spec/ruby/core/hash/compare_by_identity_spec.rb
+++ b/spec/ruby/core/hash/compare_by_identity_spec.rb
@@ -85,21 +85,19 @@ describe "Hash#compare_by_identity" do
-> { @h.compare_by_identity }.should raise_error(FrozenError)
end
- # Behaviour confirmed in https://bugs.ruby-lang.org/issues/1871
+ # Behaviour confirmed in bug #1871
it "persists over #dups" do
- @idh['foo'.dup] = :bar
- @idh['foo'.dup] = :glark
+ @idh['foo'] = :bar
+ @idh['foo'] = :glark
@idh.dup.should == @idh
@idh.dup.size.should == @idh.size
- @idh.dup.should.compare_by_identity?
end
it "persists over #clones" do
- @idh['foo'.dup] = :bar
- @idh['foo'.dup] = :glark
+ @idh['foo'] = :bar
+ @idh['foo'] = :glark
@idh.clone.should == @idh
@idh.clone.size.should == @idh.size
- @idh.dup.should.compare_by_identity?
end
it "does not copy string keys" do
@@ -110,16 +108,9 @@ describe "Hash#compare_by_identity" do
@idh.keys.first.should equal foo
end
- # Check `#[]=` call with a String literal.
- # Don't use `#+` because with `#+` it's no longer a String literal.
- #
- # See https://bugs.ruby-lang.org/issues/12855
it "gives different identity for string literals" do
- eval <<~RUBY
- # frozen_string_literal: false
@idh['foo'] = 1
@idh['foo'] = 2
- RUBY
@idh.values.should == [1, 2]
@idh.size.should == 2
end
diff --git a/spec/ruby/core/hash/constructor_spec.rb b/spec/ruby/core/hash/constructor_spec.rb
index 8d29773909..8fba47958f 100644
--- a/spec/ruby/core/hash/constructor_spec.rb
+++ b/spec/ruby/core/hash/constructor_spec.rb
@@ -103,26 +103,8 @@ describe "Hash.[]" do
HashSpecs::MyInitializerHash[Hash[1, 2]].should be_an_instance_of(HashSpecs::MyInitializerHash)
end
- it "removes the default value" do
- hash = Hash.new(1)
- Hash[hash].default.should be_nil
- hash[:a] = 1
- Hash[hash].default.should be_nil
- end
-
it "removes the default_proc" do
hash = Hash.new { |h, k| h[k] = [] }
Hash[hash].default_proc.should be_nil
- hash[:a] = 1
- Hash[hash].default_proc.should be_nil
- end
-
- ruby_version_is '3.3' do
- it "does not retain compare_by_identity_flag" do
- hash = {}.compare_by_identity
- Hash[hash].compare_by_identity?.should == false
- hash[:a] = 1
- Hash[hash].compare_by_identity?.should == false
- end
end
end
diff --git a/spec/ruby/core/hash/delete_spec.rb b/spec/ruby/core/hash/delete_spec.rb
index 3e3479c69c..b262e8846b 100644
--- a/spec/ruby/core/hash/delete_spec.rb
+++ b/spec/ruby/core/hash/delete_spec.rb
@@ -24,7 +24,7 @@ describe "Hash#delete" do
it "allows removing a key while iterating" do
h = { a: 1, b: 2 }
visited = []
- h.each_pair { |k, v|
+ h.each_pair { |k,v|
visited << k
h.delete(k)
}
@@ -32,27 +32,13 @@ describe "Hash#delete" do
h.should == {}
end
- it "allows removing a key while iterating for big hashes" do
- h = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10,
- k: 11, l: 12, m: 13, n: 14, o: 15, p: 16, q: 17, r: 18, s: 19, t: 20,
- u: 21, v: 22, w: 23, x: 24, y: 25, z: 26 }
- visited = []
- h.each_pair { |k, v|
- visited << k
- h.delete(k)
- }
- visited.should == [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j, :k, :l, :m,
- :n, :o, :p, :q, :r, :s, :t, :u, :v, :w, :x, :y, :z]
- h.should == {}
- end
-
it "accepts keys with private #hash method" do
key = HashSpecs::KeyWithPrivateHash.new
{ key => 5 }.delete(key).should == 5
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.delete("foo") }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.delete("foo") }.should raise_error(FrozenError)
-> { HashSpecs.empty_frozen_hash.delete("foo") }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/element_reference_spec.rb b/spec/ruby/core/hash/element_reference_spec.rb
index 94e8237839..e271f37ea6 100644
--- a/spec/ruby/core/hash/element_reference_spec.rb
+++ b/spec/ruby/core/hash/element_reference_spec.rb
@@ -30,7 +30,7 @@ describe "Hash#[]" do
end
it "does not create copies of the immediate default value" do
- str = +"foo"
+ str = "foo"
h = Hash.new(str)
a = h[:a]
b = h[:b]
diff --git a/spec/ruby/core/hash/except_spec.rb b/spec/ruby/core/hash/except_spec.rb
index ac84f9975c..82cfced72f 100644
--- a/spec/ruby/core/hash/except_spec.rb
+++ b/spec/ruby/core/hash/except_spec.rb
@@ -1,32 +1,34 @@
require_relative '../../spec_helper'
-describe "Hash#except" do
- before :each do
- @hash = { a: 1, b: 2, c: 3 }
- end
+ruby_version_is "3.0" do
+ describe "Hash#except" do
+ before :each do
+ @hash = { a: 1, b: 2, c: 3 }
+ end
- it "returns a new duplicate hash without arguments" do
- ret = @hash.except
- ret.should_not equal(@hash)
- ret.should == @hash
- end
+ it "returns a new duplicate hash without arguments" do
+ ret = @hash.except
+ ret.should_not equal(@hash)
+ ret.should == @hash
+ end
- it "returns a hash without the requested subset" do
- @hash.except(:c, :a).should == { b: 2 }
- end
+ it "returns a hash without the requested subset" do
+ @hash.except(:c, :a).should == { b: 2 }
+ end
- it "ignores keys not present in the original hash" do
- @hash.except(:a, :chunky_bacon).should == { b: 2, c: 3 }
- end
+ it "ignores keys not present in the original hash" do
+ @hash.except(:a, :chunky_bacon).should == { b: 2, c: 3 }
+ end
- it "always returns a Hash without a default" do
- klass = Class.new(Hash)
- h = klass.new(:default)
- h[:bar] = 12
- h[:foo] = 42
- r = h.except(:foo)
- r.should == {bar: 12}
- r.class.should == Hash
- r.default.should == nil
+ it "always returns a Hash without a default" do
+ klass = Class.new(Hash)
+ h = klass.new(:default)
+ h[:bar] = 12
+ h[:foo] = 42
+ r = h.except(:foo)
+ r.should == {bar: 12}
+ r.class.should == Hash
+ r.default.should == nil
+ end
end
end
diff --git a/spec/ruby/core/hash/fetch_spec.rb b/spec/ruby/core/hash/fetch_spec.rb
index 6e0d207224..753167f709 100644
--- a/spec/ruby/core/hash/fetch_spec.rb
+++ b/spec/ruby/core/hash/fetch_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../shared/hash/key_error'
describe "Hash#fetch" do
context "when the key is not found" do
- it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, Hash.new({ a: 5 })
+ it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, Hash.new(a: 5)
it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, {}
it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, Hash.new { 5 }
it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, Hash.new(5)
diff --git a/spec/ruby/core/hash/fetch_values_spec.rb b/spec/ruby/core/hash/fetch_values_spec.rb
index 0cd48565af..af3673f6ef 100644
--- a/spec/ruby/core/hash/fetch_values_spec.rb
+++ b/spec/ruby/core/hash/fetch_values_spec.rb
@@ -19,7 +19,7 @@ describe "Hash#fetch_values" do
end
describe "with unmatched keys" do
- it_behaves_like :key_error, -> obj, key { obj.fetch_values(key) }, Hash.new({ a: 5 })
+ it_behaves_like :key_error, -> obj, key { obj.fetch_values(key) }, Hash.new(a: 5)
it "returns the default value from block" do
@hash.fetch_values(:z) { |key| "`#{key}' is not found" }.should == ["`z' is not found"]
diff --git a/spec/ruby/core/hash/hash_spec.rb b/spec/ruby/core/hash/hash_spec.rb
index 19eb806dc4..2ccb483120 100644
--- a/spec/ruby/core/hash/hash_spec.rb
+++ b/spec/ruby/core/hash/hash_spec.rb
@@ -43,7 +43,7 @@ describe "Hash#hash" do
end
ruby_version_is "3.1" do
- it "allows omitting values" do
+ it "allows ommiting values" do
a = 1
b = 2
diff --git a/spec/ruby/core/hash/index_spec.rb b/spec/ruby/core/hash/index_spec.rb
new file mode 100644
index 0000000000..be4e2cc6ab
--- /dev/null
+++ b/spec/ruby/core/hash/index_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/index'
+
+ruby_version_is ''...'3.0' do
+ describe "Hash#index" do
+ it_behaves_like :hash_index, :index
+ end
+end
diff --git a/spec/ruby/core/hash/new_spec.rb b/spec/ruby/core/hash/new_spec.rb
index 5ae3e1f98d..6054b69bdd 100644
--- a/spec/ruby/core/hash/new_spec.rb
+++ b/spec/ruby/core/hash/new_spec.rb
@@ -33,35 +33,4 @@ describe "Hash.new" do
-> { Hash.new(5) { 0 } }.should raise_error(ArgumentError)
-> { Hash.new(nil) { 0 } }.should raise_error(ArgumentError)
end
-
- ruby_version_is "3.3"..."3.4" do
- it "emits a deprecation warning if keyword arguments are passed" do
- -> { Hash.new(unknown: true) }.should complain(
- Regexp.new(Regexp.escape("Calling Hash.new with keyword arguments is deprecated and will be removed in Ruby 3.4; use Hash.new({ key: value }) instead"))
- )
-
- -> { Hash.new(1, unknown: true) }.should raise_error(ArgumentError)
- -> { Hash.new(unknown: true) { 0 } }.should raise_error(ArgumentError)
-
- Hash.new({ unknown: true }).default.should == { unknown: true }
- end
- end
-
- ruby_version_is "3.4" do
- it "accepts a capacity: argument" do
- Hash.new(5, capacity: 42).default.should == 5
- Hash.new(capacity: 42).default.should == nil
- (Hash.new(capacity: 42) { 1 }).default_proc.should_not == nil
- end
-
- it "ignores negative capacity" do
- -> { Hash.new(capacity: -42) }.should_not raise_error
- end
-
- it "raises an error if unknown keyword arguments are passed" do
- -> { Hash.new(unknown: true) }.should raise_error(ArgumentError)
- -> { Hash.new(1, unknown: true) }.should raise_error(ArgumentError)
- -> { Hash.new(unknown: true) { 0 } }.should raise_error(ArgumentError)
- end
- end
end
diff --git a/spec/ruby/core/hash/rehash_spec.rb b/spec/ruby/core/hash/rehash_spec.rb
index db3e91b166..0049080456 100644
--- a/spec/ruby/core/hash/rehash_spec.rb
+++ b/spec/ruby/core/hash/rehash_spec.rb
@@ -77,36 +77,6 @@ describe "Hash#rehash" do
h.keys.should_not.include? [1]
end
- it "iterates keys in insertion order" do
- key = Class.new do
- attr_reader :name
-
- def initialize(name)
- @name = name
- end
-
- def hash
- 123
- end
- end
-
- a, b, c, d = key.new('a'), key.new('b'), key.new('c'), key.new('d')
- h = { a => 1, b => 2, c => 3, d => 4 }
- h.size.should == 4
-
- key.class_exec do
- def eql?(other)
- true
- end
- end
-
- h.rehash
- h.size.should == 1
- k, v = h.first
- k.name.should == 'a'
- v.should == 4
- end
-
it "raises a FrozenError if called on a frozen instance" do
-> { HashSpecs.frozen_hash.rehash }.should raise_error(FrozenError)
-> { HashSpecs.empty_frozen_hash.rehash }.should raise_error(FrozenError)
diff --git a/spec/ruby/core/hash/replace_spec.rb b/spec/ruby/core/hash/replace_spec.rb
index a26a31f5f9..92b2118fd3 100644
--- a/spec/ruby/core/hash/replace_spec.rb
+++ b/spec/ruby/core/hash/replace_spec.rb
@@ -1,70 +1,7 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/replace'
describe "Hash#replace" do
- it "replaces the contents of self with other" do
- h = { a: 1, b: 2 }
- h.replace(c: -1, d: -2).should equal(h)
- h.should == { c: -1, d: -2 }
- end
-
- it "tries to convert the passed argument to a hash using #to_hash" do
- obj = mock('{1=>2,3=>4}')
- obj.should_receive(:to_hash).and_return({ 1 => 2, 3 => 4 })
-
- h = {}
- h.replace(obj)
- h.should == { 1 => 2, 3 => 4 }
- end
-
- it "calls to_hash on hash subclasses" do
- h = {}
- h.replace(HashSpecs::ToHashHash[1 => 2])
- h.should == { 1 => 2 }
- end
-
- it "transfers the compare_by_identity flag" do
- hash_a = { a: 1 }
- hash_b = { b: 2 }
- hash_b.compare_by_identity
- hash_a.should_not.compare_by_identity?
- hash_a.replace(hash_b)
- hash_a.should.compare_by_identity?
-
- hash_a = { a: 1 }
- hash_b = { b: 2 }
- hash_a.compare_by_identity
- hash_a.should.compare_by_identity?
- hash_a.replace(hash_b)
- hash_a.should_not.compare_by_identity?
- end
-
- it "does not transfer default values" do
- hash_a = {}
- hash_b = Hash.new(5)
- hash_a.replace(hash_b)
- hash_a.default.should == 5
-
- hash_a = {}
- hash_b = Hash.new { |h, k| k * 2 }
- hash_a.replace(hash_b)
- hash_a.default(5).should == 10
-
- hash_a = Hash.new { |h, k| k * 5 }
- hash_b = Hash.new(-> { raise "Should not invoke lambda" })
- hash_a.replace(hash_b)
- hash_a.default.should == hash_b.default
- end
-
- it "raises a FrozenError if called on a frozen instance that would not be modified" do
- -> do
- HashSpecs.frozen_hash.replace(HashSpecs.frozen_hash)
- end.should raise_error(FrozenError)
- end
-
- it "raises a FrozenError if called on a frozen instance that is modified" do
- -> do
- HashSpecs.frozen_hash.replace(HashSpecs.empty_frozen_hash)
- end.should raise_error(FrozenError)
- end
+ it_behaves_like :hash_replace, :replace
end
diff --git a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
index 7dbb9c0a98..e9337b9d1c 100644
--- a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
+++ b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
@@ -56,28 +56,4 @@ describe "Hash.ruby2_keywords_hash" do
it "raises TypeError for non-Hash" do
-> { Hash.ruby2_keywords_hash(nil) }.should raise_error(TypeError)
end
-
- it "retains the default value" do
- hash = Hash.new(1)
- Hash.ruby2_keywords_hash(hash).default.should == 1
- hash[:a] = 1
- Hash.ruby2_keywords_hash(hash).default.should == 1
- end
-
- it "retains the default_proc" do
- pr = proc { |h, k| h[k] = [] }
- hash = Hash.new(&pr)
- Hash.ruby2_keywords_hash(hash).default_proc.should == pr
- hash[:a] = 1
- Hash.ruby2_keywords_hash(hash).default_proc.should == pr
- end
-
- ruby_version_is '3.3' do
- it "retains compare_by_identity_flag" do
- hash = {}.compare_by_identity
- Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true
- hash[:a] = 1
- Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true
- end
- end
end
diff --git a/spec/ruby/core/hash/shared/each.rb b/spec/ruby/core/hash/shared/each.rb
index f9839ff58f..b2483c8116 100644
--- a/spec/ruby/core/hash/shared/each.rb
+++ b/spec/ruby/core/hash/shared/each.rb
@@ -21,18 +21,37 @@ describe :hash_each, shared: true do
ary.sort.should == ["a", "b", "c"]
end
- it "always yields an Array of 2 elements, even when given a callable of arity 2" do
- obj = Object.new
- def obj.foo(key, value)
- end
+ ruby_version_is ""..."3.0" do
+ it "yields 2 values and not an Array of 2 elements when given a callable of arity 2" do
+ obj = Object.new
+ def obj.foo(key, value)
+ ScratchPad << key << value
+ end
- -> {
+ ScratchPad.record([])
{ "a" => 1 }.send(@method, &obj.method(:foo))
- }.should raise_error(ArgumentError)
+ ScratchPad.recorded.should == ["a", 1]
- -> {
- { "a" => 1 }.send(@method, &-> key, value { })
- }.should raise_error(ArgumentError)
+ ScratchPad.record([])
+ { "a" => 1 }.send(@method, &-> key, value { ScratchPad << key << value })
+ ScratchPad.recorded.should == ["a", 1]
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "always yields an Array of 2 elements, even when given a callable of arity 2" do
+ obj = Object.new
+ def obj.foo(key, value)
+ end
+
+ -> {
+ { "a" => 1 }.send(@method, &obj.method(:foo))
+ }.should raise_error(ArgumentError)
+
+ -> {
+ { "a" => 1 }.send(@method, &-> key, value { })
+ }.should raise_error(ArgumentError)
+ end
end
it "yields an Array of 2 elements when given a callable of arity 1" do
diff --git a/spec/ruby/core/hash/shared/equal.rb b/spec/ruby/core/hash/shared/equal.rb
new file mode 100644
index 0000000000..43606437fe
--- /dev/null
+++ b/spec/ruby/core/hash/shared/equal.rb
@@ -0,0 +1,90 @@
+describe :hash_equal, shared: true do
+ it "does not compare values when keys don't match" do
+ value = mock('x')
+ value.should_not_receive(:==)
+ value.should_not_receive(:eql?)
+ { 1 => value }.send(@method, { 2 => value }).should be_false
+ end
+
+ it "returns false when the numbers of keys differ without comparing any elements" do
+ obj = mock('x')
+ h = { obj => obj }
+
+ obj.should_not_receive(:==)
+ obj.should_not_receive(:eql?)
+
+ {}.send(@method, h).should be_false
+ h.send(@method, {}).should be_false
+ end
+
+ it "first compares keys via hash" do
+ x = mock('x')
+ x.should_receive(:hash).and_return(0)
+ y = mock('y')
+ y.should_receive(:hash).and_return(0)
+
+ { x => 1 }.send(@method, { y => 1 }).should be_false
+ end
+
+ it "does not compare keys with different hash codes via eql?" do
+ x = mock('x')
+ y = mock('y')
+ x.should_not_receive(:eql?)
+ y.should_not_receive(:eql?)
+
+ x.should_receive(:hash).and_return(0)
+ y.should_receive(:hash).and_return(1)
+
+ def x.hash() 0 end
+ def y.hash() 1 end
+
+ { x => 1 }.send(@method, { y => 1 }).should be_false
+ end
+
+ it "computes equality for recursive hashes" do
+ h = {}
+ h[:a] = h
+ h.send(@method, h[:a]).should be_true
+ (h == h[:a]).should be_true
+ end
+
+ it "computes equality for complex recursive hashes" do
+ a, b = {}, {}
+ a.merge! self: a, other: b
+ b.merge! self: b, other: a
+ a.send(@method, b).should be_true # they both have the same structure!
+
+ c = {}
+ c.merge! other: c, self: c
+ c.send(@method, a).should be_true # subtle, but they both have the same structure!
+ a[:delta] = c[:delta] = a
+ c.send(@method, a).should be_false # not quite the same structure, as a[:other][:delta] = nil
+ c[:delta] = 42
+ c.send(@method, a).should be_false
+ a[:delta] = 42
+ c.send(@method, a).should be_false
+ b[:delta] = 42
+ c.send(@method, a).should be_true
+ end
+
+ it "computes equality for recursive hashes & arrays" do
+ x, y, z = [], [], []
+ a, b, c = {foo: x, bar: 42}, {foo: y, bar: 42}, {foo: z, bar: 42}
+ x << a
+ y << c
+ z << b
+ b.send(@method, c).should be_true # they clearly have the same structure!
+ y.send(@method, z).should be_true
+ a.send(@method, b).should be_true # subtle, but they both have the same structure!
+ x.send(@method, y).should be_true
+ y << x
+ y.send(@method, z).should be_false
+ z << x
+ y.send(@method, z).should be_true
+
+ a[:foo], a[:bar] = a[:bar], a[:foo]
+ a.send(@method, b).should be_false
+ b[:bar] = b[:foo]
+ b.send(@method, c).should be_false
+ end
+end
diff --git a/spec/ruby/core/hash/shared/replace.rb b/spec/ruby/core/hash/shared/replace.rb
new file mode 100644
index 0000000000..bea64384bb
--- /dev/null
+++ b/spec/ruby/core/hash/shared/replace.rb
@@ -0,0 +1,51 @@
+describe :hash_replace, shared: true do
+ it "replaces the contents of self with other" do
+ h = { a: 1, b: 2 }
+ h.send(@method, c: -1, d: -2).should equal(h)
+ h.should == { c: -1, d: -2 }
+ end
+
+ it "tries to convert the passed argument to a hash using #to_hash" do
+ obj = mock('{1=>2,3=>4}')
+ obj.should_receive(:to_hash).and_return({ 1 => 2, 3 => 4 })
+
+ h = {}
+ h.send(@method, obj)
+ h.should == { 1 => 2, 3 => 4 }
+ end
+
+ it "calls to_hash on hash subclasses" do
+ h = {}
+ h.send(@method, HashSpecs::ToHashHash[1 => 2])
+ h.should == { 1 => 2 }
+ end
+
+ it "does not transfer default values" do
+ hash_a = {}
+ hash_b = Hash.new(5)
+ hash_a.send(@method, hash_b)
+ hash_a.default.should == 5
+
+ hash_a = {}
+ hash_b = Hash.new { |h, k| k * 2 }
+ hash_a.send(@method, hash_b)
+ hash_a.default(5).should == 10
+
+ hash_a = Hash.new { |h, k| k * 5 }
+ hash_b = Hash.new(-> { raise "Should not invoke lambda" })
+ hash_a.send(@method, hash_b)
+ hash_a.default.should == hash_b.default
+ end
+
+ it "raises a FrozenError if called on a frozen instance that would not be modified" do
+ -> do
+ HashSpecs.frozen_hash.send(@method, HashSpecs.frozen_hash)
+ end.should raise_error(FrozenError)
+ end
+
+ it "raises a FrozenError if called on a frozen instance that is modified" do
+ -> do
+ HashSpecs.frozen_hash.send(@method, HashSpecs.empty_frozen_hash)
+ end.should raise_error(FrozenError)
+ end
+end
diff --git a/spec/ruby/core/hash/shared/store.rb b/spec/ruby/core/hash/shared/store.rb
index dd1bb52bac..b823ea45ca 100644
--- a/spec/ruby/core/hash/shared/store.rb
+++ b/spec/ruby/core/hash/shared/store.rb
@@ -9,7 +9,7 @@ describe :hash_store, shared: true do
it "duplicates string keys using dup semantics" do
# dup doesn't copy singleton methods
- key = +"foo"
+ key = "foo"
def key.reverse() "bar" end
h = {}
h.send(@method, key, 0)
@@ -44,7 +44,7 @@ describe :hash_store, shared: true do
end
it "duplicates and freezes string keys" do
- key = +"foo"
+ key = "foo"
h = {}
h.send(@method, key, 0)
key << "bar"
@@ -75,8 +75,8 @@ describe :hash_store, shared: true do
it "keeps the existing String key in the hash if there is a matching one" do
h = { "a" => 1, "b" => 2, "c" => 3, "d" => 4 }
- key1 = "foo".dup
- key2 = "foo".dup
+ key1 = "foo"
+ key2 = "foo"
key1.should_not equal(key2)
h[key1] = 41
frozen_key = h.keys.last
diff --git a/spec/ruby/core/hash/shared/to_s.rb b/spec/ruby/core/hash/shared/to_s.rb
index 5f0a8f97fd..2db3a96583 100644
--- a/spec/ruby/core/hash/shared/to_s.rb
+++ b/spec/ruby/core/hash/shared/to_s.rb
@@ -4,8 +4,14 @@ require_relative '../fixtures/classes'
describe :hash_to_s, shared: true do
it "returns a string representation with same order as each()" do
h = { a: [1, 2], b: -2, d: -6, nil => nil }
- expected = ruby_version_is("3.4") ? "{a: [1, 2], b: -2, d: -6, nil => nil}" : "{:a=>[1, 2], :b=>-2, :d=>-6, nil=>nil}"
- h.send(@method).should == expected
+
+ pairs = []
+ h.each do |key, value|
+ pairs << key.inspect + '=>' + value.inspect
+ end
+
+ str = '{' + pairs.join(', ') + '}'
+ h.send(@method).should == str
end
it "calls #inspect on keys and values" do
@@ -13,31 +19,31 @@ describe :hash_to_s, shared: true do
val = mock('val')
key.should_receive(:inspect).and_return('key')
val.should_receive(:inspect).and_return('val')
- expected = ruby_version_is("3.4") ? "{key => val}" : "{key=>val}"
- { key => val }.send(@method).should == expected
+
+ { key => val }.send(@method).should == '{key=>val}'
end
it "does not call #to_s on a String returned from #inspect" do
- str = +"abc"
+ str = "abc"
str.should_not_receive(:to_s)
- expected = ruby_version_is("3.4") ? '{a: "abc"}' : '{:a=>"abc"}'
- { a: str }.send(@method).should == expected
+
+ { a: str }.send(@method).should == '{:a=>"abc"}'
end
it "calls #to_s on the object returned from #inspect if the Object isn't a String" do
obj = mock("Hash#inspect/to_s calls #to_s")
obj.should_receive(:inspect).and_return(obj)
obj.should_receive(:to_s).and_return("abc")
- expected = ruby_version_is("3.4") ? "{a: abc}" : "{:a=>abc}"
- { a: obj }.send(@method).should == expected
+
+ { a: obj }.send(@method).should == "{:a=>abc}"
end
it "does not call #to_str on the object returned from #inspect when it is not a String" do
obj = mock("Hash#inspect/to_s does not call #to_str")
obj.should_receive(:inspect).and_return(obj)
obj.should_not_receive(:to_str)
- expected_pattern = ruby_version_is("3.4") ? /^\{a: #<MockObject:0x[0-9a-f]+>\}$/ : /^\{:a=>#<MockObject:0x[0-9a-f]+>\}$/
- { a: obj }.send(@method).should =~ expected_pattern
+
+ { a: obj }.send(@method).should =~ /^\{:a=>#<MockObject:0x[0-9a-f]+>\}$/
end
it "does not call #to_str on the object returned from #to_s when it is not a String" do
@@ -45,8 +51,8 @@ describe :hash_to_s, shared: true do
obj.should_receive(:inspect).and_return(obj)
obj.should_receive(:to_s).and_return(obj)
obj.should_not_receive(:to_str)
- expected_pattern = ruby_version_is("3.4") ? /^\{a: #<MockObject:0x[0-9a-f]+>\}$/ : /^\{:a=>#<MockObject:0x[0-9a-f]+>\}$/
- { a: obj }.send(@method).should =~ expected_pattern
+
+ { a: obj }.send(@method).should =~ /^\{:a=>#<MockObject:0x[0-9a-f]+>\}$/
end
it "does not swallow exceptions raised by #to_s" do
@@ -60,28 +66,24 @@ describe :hash_to_s, shared: true do
it "handles hashes with recursive values" do
x = {}
x[0] = x
- expected = ruby_version_is("3.4") ? '{0 => {...}}' : '{0=>{...}}'
- x.send(@method).should == expected
+ x.send(@method).should == '{0=>{...}}'
x = {}
y = {}
x[0] = y
y[1] = x
- expected_x = ruby_version_is("3.4") ? '{0 => {1 => {...}}}' : '{0=>{1=>{...}}}'
- expected_y = ruby_version_is("3.4") ? '{1 => {0 => {...}}}' : '{1=>{0=>{...}}}'
- x.send(@method).should == expected_x
- y.send(@method).should == expected_y
+ x.send(@method).should == "{0=>{1=>{...}}}"
+ y.send(@method).should == "{1=>{0=>{...}}}"
end
it "does not raise if inspected result is not default external encoding" do
utf_16be = mock("utf_16be")
- utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode(Encoding::UTF_16BE))
- expected = ruby_version_is("3.4") ? '{a: "utf_16be \u3042"}' : '{:a=>"utf_16be \u3042"}'
- {a: utf_16be}.send(@method).should == expected
+ utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode!(Encoding::UTF_16BE))
+
+ {a: utf_16be}.send(@method).should == '{:a=>"utf_16be \u3042"}'
end
it "works for keys and values whose #inspect return a frozen String" do
- expected = ruby_version_is("3.4") ? "{true => false}" : "{true=>false}"
- { true => false }.to_s.should == expected
+ { true => false }.to_s.should == "{true=>false}"
end
end
diff --git a/spec/ruby/core/hash/to_a_spec.rb b/spec/ruby/core/hash/to_a_spec.rb
index 5baf677929..8b7894a2ba 100644
--- a/spec/ruby/core/hash/to_a_spec.rb
+++ b/spec/ruby/core/hash/to_a_spec.rb
@@ -26,4 +26,14 @@ describe "Hash#to_a" do
ent.should be_kind_of(Array)
ent.should == pairs
end
+
+ ruby_version_is ''...'3.0' do
+ it "returns a not tainted array if self is tainted" do
+ {}.taint.to_a.tainted?.should be_false
+ end
+
+ it "returns a trusted array if self is untrusted" do
+ {}.untrust.to_a.untrusted?.should be_false
+ end
+ end
end
diff --git a/spec/ruby/core/hash/to_h_spec.rb b/spec/ruby/core/hash/to_h_spec.rb
index e17ca7e671..75ebce68b1 100644
--- a/spec/ruby/core/hash/to_h_spec.rb
+++ b/spec/ruby/core/hash/to_h_spec.rb
@@ -37,16 +37,6 @@ describe "Hash#to_h" do
{ a: 1, b: 2 }.to_h { |k, v| [k.to_s, v*v]}.should == { "a" => 1, "b" => 4 }
end
- it "passes to a block each pair's key and value as separate arguments" do
- ScratchPad.record []
- { a: 1, b: 2 }.to_h { |k, v| ScratchPad << [k, v]; [k, v] }
- ScratchPad.recorded.sort.should == [[:a, 1], [:b, 2]]
-
- ScratchPad.record []
- { a: 1, b: 2 }.to_h { |*args| ScratchPad << args; [args[0], args[1]] }
- ScratchPad.recorded.sort.should == [[:a, 1], [:b, 2]]
- end
-
it "raises ArgumentError if block returns longer or shorter array" do
-> do
{ a: 1, b: 2 }.to_h { |k, v| [k.to_s, v*v, 1] }
diff --git a/spec/ruby/core/hash/to_proc_spec.rb b/spec/ruby/core/hash/to_proc_spec.rb
index 9dbc79e5eb..8f5d21beb5 100644
--- a/spec/ruby/core/hash/to_proc_spec.rb
+++ b/spec/ruby/core/hash/to_proc_spec.rb
@@ -19,12 +19,20 @@ describe "Hash#to_proc" do
@proc = @hash.to_proc
end
- it "is a lambda" do
- @proc.should.lambda?
+ ruby_version_is ""..."3.0" do
+ it "is not a lambda" do
+ @proc.should_not.lambda?
+ end
end
- it "has an arity of 1" do
- @proc.arity.should == 1
+ ruby_version_is "3.0" do
+ it "is a lambda" do
+ @proc.should.lambda?
+ end
+
+ it "has an arity of 1" do
+ @proc.arity.should == 1
+ end
end
it "raises ArgumentError if not passed exactly one argument" do
diff --git a/spec/ruby/core/hash/transform_keys_spec.rb b/spec/ruby/core/hash/transform_keys_spec.rb
index 2fbb17a8e2..361089ca97 100644
--- a/spec/ruby/core/hash/transform_keys_spec.rb
+++ b/spec/ruby/core/hash/transform_keys_spec.rb
@@ -43,16 +43,18 @@ describe "Hash#transform_keys" do
r.class.should == Hash
end
- it "allows a hash argument" do
- @hash.transform_keys({ a: :A, b: :B, c: :C }).should == { A: 1, B: 2, C: 3 }
- end
+ ruby_version_is "3.0" do
+ it "allows a hash argument" do
+ @hash.transform_keys({ a: :A, b: :B, c: :C }).should == { A: 1, B: 2, C: 3 }
+ end
- it "allows a partial transformation of keys when using a hash argument" do
- @hash.transform_keys({ a: :A, c: :C }).should == { A: 1, b: 2, C: 3 }
- end
+ it "allows a partial transformation of keys when using a hash argument" do
+ @hash.transform_keys({ a: :A, c: :C }).should == { A: 1, b: 2, C: 3 }
+ end
- it "allows a combination of hash and block argument" do
- @hash.transform_keys({ a: :A }, &:to_s).should == { A: 1, 'b' => 2, 'c' => 3 }
+ it "allows a combination of hash and block argument" do
+ @hash.transform_keys({ a: :A }, &:to_s).should == { A: 1, 'b' => 2, 'c' => 3 }
+ end
end
end
@@ -109,9 +111,11 @@ describe "Hash#transform_keys!" do
end
end
- it "allows a hash argument" do
- @hash.transform_keys!({ a: :A, b: :B, c: :C, d: :D })
- @hash.should == { A: 1, B: 2, C: 3, D: 4 }
+ ruby_version_is "3.0" do
+ it "allows a hash argument" do
+ @hash.transform_keys!({ a: :A, b: :B, c: :C, d: :D })
+ @hash.should == { A: 1, B: 2, C: 3, D: 4 }
+ end
end
describe "on frozen instance" do
@@ -128,8 +132,10 @@ describe "Hash#transform_keys!" do
@hash.should == @initial_pairs
end
- it "raises a FrozenError on hash argument" do
- ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError)
+ ruby_version_is "3.0" do
+ it "raises a FrozenError on hash argument" do
+ ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError)
+ end
end
context "when no block is given" do
diff --git a/spec/ruby/core/hash/try_convert_spec.rb b/spec/ruby/core/hash/try_convert_spec.rb
index d359ae49d8..44195c5010 100644
--- a/spec/ruby/core/hash/try_convert_spec.rb
+++ b/spec/ruby/core/hash/try_convert_spec.rb
@@ -39,7 +39,7 @@ describe "Hash.try_convert" do
it "sends #to_hash to the argument and raises TypeError if it's not a kind of Hash" do
obj = mock("to_hash")
obj.should_receive(:to_hash).and_return(Object.new)
- -> { Hash.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Hash (MockObject#to_hash gives Object)")
+ -> { Hash.try_convert obj }.should raise_error(TypeError)
end
it "does not rescue exceptions raised by #to_hash" do
diff --git a/spec/ruby/core/integer/bit_and_spec.rb b/spec/ruby/core/integer/bit_and_spec.rb
index e7face39ac..8de5a14aaa 100644
--- a/spec/ruby/core/integer/bit_and_spec.rb
+++ b/spec/ruby/core/integer/bit_and_spec.rb
@@ -30,7 +30,7 @@ describe "Integer#&" do
it "coerces the rhs and calls #coerce" do
obj = mock("fixnum bit and")
- obj.should_receive(:coerce).with(6).and_return([6, 3])
+ obj.should_receive(:coerce).with(6).and_return([3, 6])
(6 & obj).should == 2
end
diff --git a/spec/ruby/core/integer/bit_or_spec.rb b/spec/ruby/core/integer/bit_or_spec.rb
index fdf8a191e5..6f4279c170 100644
--- a/spec/ruby/core/integer/bit_or_spec.rb
+++ b/spec/ruby/core/integer/bit_or_spec.rb
@@ -30,9 +30,9 @@ describe "Integer#|" do
end
it "coerces the rhs and calls #coerce" do
- obj = mock("fixnum bit or")
- obj.should_receive(:coerce).with(6).and_return([6, 3])
- (6 | obj).should == 7
+ obj = mock("fixnum bit and")
+ obj.should_receive(:coerce).with(6).and_return([3, 6])
+ (6 & obj).should == 2
end
it "raises a TypeError when passed a Float" do
diff --git a/spec/ruby/core/integer/bit_xor_spec.rb b/spec/ruby/core/integer/bit_xor_spec.rb
index 1f46bc52f3..f1150a20d5 100644
--- a/spec/ruby/core/integer/bit_xor_spec.rb
+++ b/spec/ruby/core/integer/bit_xor_spec.rb
@@ -28,8 +28,8 @@ describe "Integer#^" do
end
it "coerces the rhs and calls #coerce" do
- obj = mock("fixnum bit xor")
- obj.should_receive(:coerce).with(6).and_return([6, 3])
+ obj = mock("fixnum bit and")
+ obj.should_receive(:coerce).with(6).and_return([3, 6])
(6 ^ obj).should == 5
end
diff --git a/spec/ruby/core/integer/ceildiv_spec.rb b/spec/ruby/core/integer/ceildiv_spec.rb
deleted file mode 100644
index 18d07c66d0..0000000000
--- a/spec/ruby/core/integer/ceildiv_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "Integer#ceildiv" do
- ruby_version_is '3.2' do
- it "returns a quotient of division which is rounded up to the nearest integer" do
- 0.ceildiv(3).should eql(0)
- 1.ceildiv(3).should eql(1)
- 3.ceildiv(3).should eql(1)
- 4.ceildiv(3).should eql(2)
-
- 4.ceildiv(-3).should eql(-1)
- -4.ceildiv(3).should eql(-1)
- -4.ceildiv(-3).should eql(2)
-
- 3.ceildiv(1.2).should eql(3)
- 3.ceildiv(6/5r).should eql(3)
-
- (10**100-11).ceildiv(10**99-1).should eql(10)
- (10**100-9).ceildiv(10**99-1).should eql(11)
- end
- end
-end
diff --git a/spec/ruby/core/integer/chr_spec.rb b/spec/ruby/core/integer/chr_spec.rb
index 39cafe2874..8fe20ff812 100644
--- a/spec/ruby/core/integer/chr_spec.rb
+++ b/spec/ruby/core/integer/chr_spec.rb
@@ -10,12 +10,12 @@ describe "Integer#chr without argument" do
end
it "raises a RangeError is self is less than 0" do
- -> { -1.chr }.should raise_error(RangeError, /-1 out of char range/)
- -> { (-bignum_value).chr }.should raise_error(RangeError, /bignum out of char range/)
+ -> { -1.chr }.should raise_error(RangeError)
+ -> { (-bignum_value).chr }.should raise_error(RangeError)
end
it "raises a RangeError if self is too large" do
- -> { 2206368128.chr(Encoding::UTF_8) }.should raise_error(RangeError, /2206368128 out of char range/)
+ -> { 2206368128.chr(Encoding::UTF_8) }.should raise_error(RangeError)
end
describe "when Encoding.default_internal is nil" do
@@ -48,8 +48,8 @@ describe "Integer#chr without argument" do
end
it "raises a RangeError is self is greater than 255" do
- -> { 256.chr }.should raise_error(RangeError, /256 out of char range/)
- -> { bignum_value.chr }.should raise_error(RangeError, /bignum out of char range/)
+ -> { 256.chr }.should raise_error(RangeError)
+ -> { bignum_value.chr }.should raise_error(RangeError)
end
end
@@ -137,7 +137,7 @@ describe "Integer#chr without argument" do
[620, "TIS-620"]
].each do |integer, encoding_name|
Encoding.default_internal = Encoding.find(encoding_name)
- -> { integer.chr }.should raise_error(RangeError, /(invalid codepoint|out of char range)/)
+ -> { integer.chr }.should raise_error(RangeError)
end
end
end
@@ -165,12 +165,12 @@ describe "Integer#chr with an encoding argument" do
# http://redmine.ruby-lang.org/issues/4869
it "raises a RangeError is self is less than 0" do
- -> { -1.chr(Encoding::UTF_8) }.should raise_error(RangeError, /-1 out of char range/)
- -> { (-bignum_value).chr(Encoding::EUC_JP) }.should raise_error(RangeError, /bignum out of char range/)
+ -> { -1.chr(Encoding::UTF_8) }.should raise_error(RangeError)
+ -> { (-bignum_value).chr(Encoding::EUC_JP) }.should raise_error(RangeError)
end
it "raises a RangeError if self is too large" do
- -> { 2206368128.chr(Encoding::UTF_8) }.should raise_error(RangeError, /2206368128 out of char range/)
+ -> { 2206368128.chr(Encoding::UTF_8) }.should raise_error(RangeError)
end
it "returns a String with the specified encoding" do
diff --git a/spec/ruby/core/integer/coerce_spec.rb b/spec/ruby/core/integer/coerce_spec.rb
index 1d6dc9713f..f1f3256032 100644
--- a/spec/ruby/core/integer/coerce_spec.rb
+++ b/spec/ruby/core/integer/coerce_spec.rb
@@ -1,5 +1,7 @@
require_relative '../../spec_helper'
+require 'bigdecimal'
+
describe "Integer#coerce" do
context "fixnum" do
describe "when given a Fixnum" do
@@ -88,4 +90,15 @@ describe "Integer#coerce" do
ary.should == [1.2, a.to_f]
end
end
+
+ context "bigdecimal" do
+ it "produces Floats" do
+ x, y = 3.coerce(BigDecimal("3.4"))
+ x.class.should == Float
+ x.should == 3.4
+ y.class.should == Float
+ y.should == 3.0
+ end
+ end
+
end
diff --git a/spec/ruby/core/integer/div_spec.rb b/spec/ruby/core/integer/div_spec.rb
index 2eb9c0623b..344e095179 100644
--- a/spec/ruby/core/integer/div_spec.rb
+++ b/spec/ruby/core/integer/div_spec.rb
@@ -143,12 +143,4 @@ describe "Integer#div" do
-> { @bignum.div(-0) }.should raise_error(ZeroDivisionError)
end
end
-
- context "rational" do
- it "returns self divided by the given argument as an Integer" do
- 2.div(6/5r).should == 1
- 1.div(6/5r).should == 0
- 5.div(6/5r).should == 4
- end
- end
end
diff --git a/spec/ruby/core/integer/left_shift_spec.rb b/spec/ruby/core/integer/left_shift_spec.rb
index 0781371d93..135af90421 100644
--- a/spec/ruby/core/integer/left_shift_spec.rb
+++ b/spec/ruby/core/integer/left_shift_spec.rb
@@ -191,23 +191,21 @@ describe "Integer#<< (with n << m)" do
(0 << bignum_value).should == 0
end
- it "raises RangeError when m > 0 and n != 0" do
- # https://bugs.ruby-lang.org/issues/18518#note-9
- limit = RUBY_ENGINE == 'ruby' ? 2**67 : 2**32
-
- coerce_long = mock("long")
- coerce_long.stub!(:to_int).and_return(limit)
- coerce_bignum = mock("bignum")
- coerce_bignum.stub!(:to_int).and_return(bignum_value)
- exps = [limit, coerce_long]
- exps << bignum_value << coerce_bignum if bignum_value >= limit
-
- exps.each { |exp|
- -> { (1 << exp) }.should raise_error(RangeError, 'shift width too big')
- -> { (-1 << exp) }.should raise_error(RangeError, 'shift width too big')
- -> { (bignum_value << exp) }.should raise_error(RangeError, 'shift width too big')
- -> { (-bignum_value << exp) }.should raise_error(RangeError, 'shift width too big')
- }
+ ruby_bug "#18518", ""..."3.3" do
+ it "raises NoMemoryError when m > 0 and n != 0" do
+ coerce_long = mock("long")
+ coerce_long.stub!(:to_int).and_return(2**40)
+ coerce_bignum = mock("bignum")
+ coerce_bignum.stub!(:to_int).and_return(bignum_value)
+ exps = [2**40, bignum_value, coerce_long, coerce_bignum]
+
+ exps.each { |exp|
+ -> { (1 << exp) }.should raise_error(NoMemoryError)
+ -> { (-1 << exp) }.should raise_error(NoMemoryError)
+ -> { (bignum_value << exp) }.should raise_error(NoMemoryError)
+ -> { (-bignum_value << exp) }.should raise_error(NoMemoryError)
+ }
+ end
end
end
end
diff --git a/spec/ruby/core/integer/right_shift_spec.rb b/spec/ruby/core/integer/right_shift_spec.rb
index e91613d8d1..81405667b2 100644
--- a/spec/ruby/core/integer/right_shift_spec.rb
+++ b/spec/ruby/core/integer/right_shift_spec.rb
@@ -213,23 +213,21 @@ describe "Integer#>> (with n >> m)" do
(0 >> -bignum_value).should == 0
end
- it "raises RangeError when m < 0 and n != 0" do
- # https://bugs.ruby-lang.org/issues/18518#note-9
- limit = RUBY_ENGINE == 'ruby' ? 2**67 : 2**32
-
- coerce_long = mock("long")
- coerce_long.stub!(:to_int).and_return(-limit)
- coerce_bignum = mock("bignum")
- coerce_bignum.stub!(:to_int).and_return(-bignum_value)
- exps = [-limit, coerce_long]
- exps << -bignum_value << coerce_bignum if bignum_value >= limit
-
- exps.each { |exp|
- -> { (1 >> exp) }.should raise_error(RangeError, 'shift width too big')
- -> { (-1 >> exp) }.should raise_error(RangeError, 'shift width too big')
- -> { (bignum_value >> exp) }.should raise_error(RangeError, 'shift width too big')
- -> { (-bignum_value >> exp) }.should raise_error(RangeError, 'shift width too big')
- }
+ ruby_bug "#18518", ""..."3.3" do
+ it "raises NoMemoryError when m < 0 and n != 0" do
+ coerce_long = mock("long")
+ coerce_long.stub!(:to_int).and_return(-(2**40))
+ coerce_bignum = mock("bignum")
+ coerce_bignum.stub!(:to_int).and_return(-bignum_value)
+ exps = [-(2**40), -bignum_value, coerce_long, coerce_bignum]
+
+ exps.each { |exp|
+ -> { (1 >> exp) }.should raise_error(NoMemoryError)
+ -> { (-1 >> exp) }.should raise_error(NoMemoryError)
+ -> { (bignum_value >> exp) }.should raise_error(NoMemoryError)
+ -> { (-bignum_value >> exp) }.should raise_error(NoMemoryError)
+ }
+ end
end
end
end
diff --git a/spec/ruby/core/integer/round_spec.rb b/spec/ruby/core/integer/round_spec.rb
index 189384f11a..45ac126fd3 100644
--- a/spec/ruby/core/integer/round_spec.rb
+++ b/spec/ruby/core/integer/round_spec.rb
@@ -21,8 +21,10 @@ describe "Integer#round" do
(-25 * 10**70).round(-71).should eql(-30 * 10**70)
end
- it "raises a RangeError when passed a big negative value" do
- -> { 42.round(min_long - 1) }.should raise_error(RangeError)
+ platform_is_not wordsize: 32 do
+ it "raises a RangeError when passed a big negative value" do
+ -> { 42.round(fixnum_min) }.should raise_error(RangeError)
+ end
end
it "raises a RangeError when passed Float::INFINITY" do
diff --git a/spec/ruby/core/integer/shared/arithmetic_coerce.rb b/spec/ruby/core/integer/shared/arithmetic_coerce.rb
index 1260192df1..4c0cbcb999 100644
--- a/spec/ruby/core/integer/shared/arithmetic_coerce.rb
+++ b/spec/ruby/core/integer/shared/arithmetic_coerce.rb
@@ -1,5 +1,25 @@
require_relative '../fixtures/classes'
+describe :integer_arithmetic_coerce_rescue, shared: true do
+ it "rescues exception (StandardError and subclasses) raised in other#coerce and raises TypeError" do
+ b = mock("numeric with failed #coerce")
+ b.should_receive(:coerce).and_raise(IntegerSpecs::CoerceError)
+
+ # e.g. 1 + b
+ -> { 1.send(@method, b) }.should raise_error(TypeError, /MockObject can't be coerced into Integer/)
+ end
+
+ it "does not rescue Exception and StandardError siblings raised in other#coerce" do
+ [Exception, NoMemoryError].each do |exception|
+ b = mock("numeric with failed #coerce")
+ b.should_receive(:coerce).and_raise(exception)
+
+ # e.g. 1 + b
+ -> { 1.send(@method, b) }.should raise_error(exception)
+ end
+ end
+end
+
describe :integer_arithmetic_coerce_not_rescue, shared: true do
it "does not rescue exception raised in other#coerce" do
b = mock("numeric with failed #coerce")
diff --git a/spec/ruby/core/integer/size_spec.rb b/spec/ruby/core/integer/size_spec.rb
index 725e9eb062..a134e82384 100644
--- a/spec/ruby/core/integer/size_spec.rb
+++ b/spec/ruby/core/integer/size_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
describe "Integer#size" do
- platform_is c_long_size: 32 do
+ platform_is wordsize: 32 do
it "returns the number of bytes in the machine representation of self" do
-1.size.should == 4
0.size.should == 4
@@ -9,7 +9,7 @@ describe "Integer#size" do
end
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
it "returns the number of bytes in the machine representation of self" do
-1.size.should == 8
0.size.should == 8
diff --git a/spec/ruby/core/integer/try_convert_spec.rb b/spec/ruby/core/integer/try_convert_spec.rb
index 4bc7d3851a..45c66eec79 100644
--- a/spec/ruby/core/integer/try_convert_spec.rb
+++ b/spec/ruby/core/integer/try_convert_spec.rb
@@ -28,17 +28,7 @@ ruby_version_is "3.1" do
it "sends #to_int to the argument and raises TypeError if it's not a kind of Integer" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return(Object.new)
- -> {
- Integer.try_convert obj
- }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Object)")
- end
-
- it "responds with a different error message when it raises a TypeError, depending on the type of the non-Integer object :to_int returns" do
- obj = mock("to_int")
- obj.should_receive(:to_int).and_return("A String")
- -> {
- Integer.try_convert obj
- }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives String)")
+ -> { Integer.try_convert obj }.should raise_error(TypeError)
end
it "does not rescue exceptions raised by #to_int" do
diff --git a/spec/ruby/core/integer/zero_spec.rb b/spec/ruby/core/integer/zero_spec.rb
index bd362c4181..2dac50c406 100644
--- a/spec/ruby/core/integer/zero_spec.rb
+++ b/spec/ruby/core/integer/zero_spec.rb
@@ -7,7 +7,15 @@ describe "Integer#zero?" do
-1.should_not.zero?
end
- it "Integer#zero? overrides Numeric#zero?" do
- 42.method(:zero?).owner.should == Integer
+ ruby_version_is "3.0" do
+ it "Integer#zero? overrides Numeric#zero?" do
+ 42.method(:zero?).owner.should == Integer
+ end
+ end
+
+ ruby_version_is ""..."3.0" do
+ it "Integer#zero? uses Numeric#zero?" do
+ 42.method(:zero?).owner.should == Numeric
+ end
end
end
diff --git a/spec/ruby/core/io/autoclose_spec.rb b/spec/ruby/core/io/autoclose_spec.rb
deleted file mode 100644
index 715ada7c93..0000000000
--- a/spec/ruby/core/io/autoclose_spec.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-describe "IO#autoclose?" do
- before :each do
- @io = IOSpecs.io_fixture "lines.txt"
- end
-
- after :each do
- @io.autoclose = true unless @io.closed?
- @io.close unless @io.closed?
- end
-
- it "is set to true by default" do
- @io.should.autoclose?
- end
-
- it "cannot be queried on a closed IO object" do
- @io.close
- -> { @io.autoclose? }.should raise_error(IOError, /closed stream/)
- end
-end
-
-describe "IO#autoclose=" do
- before :each do
- @io = IOSpecs.io_fixture "lines.txt"
- end
-
- after :each do
- @io.autoclose = true unless @io.closed?
- @io.close unless @io.closed?
- end
-
- it "can be set to true" do
- @io.autoclose = false
- @io.autoclose = true
- @io.should.autoclose?
- end
-
- it "can be set to false" do
- @io.autoclose = true
- @io.autoclose = false
- @io.should_not.autoclose?
- end
-
- it "can be set to any truthy value" do
- @io.autoclose = false
- @io.autoclose = 42
- @io.should.autoclose?
-
- @io.autoclose = false
- @io.autoclose = Object.new
- @io.should.autoclose?
- end
-
- it "can be set to any falsy value" do
- @io.autoclose = true
- @io.autoclose = nil
- @io.should_not.autoclose?
- end
-
- it "can be set multiple times" do
- @io.autoclose = true
- @io.should.autoclose?
-
- @io.autoclose = false
- @io.should_not.autoclose?
-
- @io.autoclose = true
- @io.should.autoclose?
- end
-
- it "cannot be set on a closed IO object" do
- @io.close
- -> { @io.autoclose = false }.should raise_error(IOError, /closed stream/)
- end
-end
diff --git a/spec/ruby/core/io/binread_spec.rb b/spec/ruby/core/io/binread_spec.rb
index 418e89213b..a3f752d8f9 100644
--- a/spec/ruby/core/io/binread_spec.rb
+++ b/spec/ruby/core/io/binread_spec.rb
@@ -44,14 +44,4 @@ describe "IO.binread" do
it "raises an Errno::EINVAL when not passed a valid offset" do
-> { IO.binread @fname, 0, -1 }.should raise_error(Errno::EINVAL)
end
-
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19630
- it "warns about deprecation given a path with a pipe" do
- cmd = "|echo ok"
- -> {
- IO.binread(cmd)
- }.should complain(/IO process creation with a leading '\|'/)
- end
- end
end
diff --git a/spec/ruby/core/io/bytes_spec.rb b/spec/ruby/core/io/bytes_spec.rb
new file mode 100644
index 0000000000..6e328983f2
--- /dev/null
+++ b/spec/ruby/core/io/bytes_spec.rb
@@ -0,0 +1,47 @@
+# -*- encoding: utf-8 -*-
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is ''...'3.0' do
+ describe "IO#bytes" do
+ before :each do
+ @io = IOSpecs.io_fixture "lines.txt"
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ @io.close unless @io.closed?
+ end
+
+ it "returns an enumerator of the next bytes from the stream" do
+ enum = @io.bytes
+ enum.should be_an_instance_of(Enumerator)
+ @io.readline.should == "Voici la ligne une.\n"
+ enum.first(5).should == [81, 117, 105, 32, 195]
+ end
+
+ it "yields each byte" do
+ count = 0
+ ScratchPad.record []
+ @io.each_byte do |byte|
+ ScratchPad << byte
+ break if 4 < count += 1
+ end
+
+ ScratchPad.recorded.should == [86, 111, 105, 99, 105]
+ end
+
+ it "raises an IOError on closed stream" do
+ enum = IOSpecs.closed_io.bytes
+ -> { enum.first }.should raise_error(IOError)
+ end
+
+ it "raises an IOError on an enumerator for a stream that has been closed" do
+ enum = @io.bytes
+ enum.first.should == 86
+ @io.close
+ -> { enum.first }.should raise_error(IOError)
+ end
+ end
+end
diff --git a/spec/ruby/core/io/chars_spec.rb b/spec/ruby/core/io/chars_spec.rb
new file mode 100644
index 0000000000..15db595aed
--- /dev/null
+++ b/spec/ruby/core/io/chars_spec.rb
@@ -0,0 +1,30 @@
+# -*- encoding: utf-8 -*-
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/chars'
+
+ruby_version_is ''...'3.0' do
+ describe "IO#chars" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :io_chars, :chars
+ end
+
+ describe "IO#chars" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :io_chars_empty, :chars
+ end
+end
diff --git a/spec/ruby/core/io/close_read_spec.rb b/spec/ruby/core/io/close_read_spec.rb
index e700e85bd9..26454bfddd 100644
--- a/spec/ruby/core/io/close_read_spec.rb
+++ b/spec/ruby/core/io/close_read_spec.rb
@@ -4,8 +4,7 @@ require_relative 'fixtures/classes'
describe "IO#close_read" do
before :each do
- cmd = platform_is(:windows) ? 'rem' : 'cat'
- @io = IO.popen cmd, "r+"
+ @io = IO.popen 'cat', "r+"
@path = tmp('io.close.txt')
end
diff --git a/spec/ruby/core/io/close_write_spec.rb b/spec/ruby/core/io/close_write_spec.rb
index 70610a3e9d..14835e4e2c 100644
--- a/spec/ruby/core/io/close_write_spec.rb
+++ b/spec/ruby/core/io/close_write_spec.rb
@@ -3,8 +3,7 @@ require_relative 'fixtures/classes'
describe "IO#close_write" do
before :each do
- cmd = platform_is(:windows) ? 'rem' : 'cat'
- @io = IO.popen cmd, 'r+'
+ @io = IO.popen 'cat', 'r+'
@path = tmp('io.close.txt')
end
@@ -49,15 +48,12 @@ describe "IO#close_write" do
io.should.closed?
end
- # Windows didn't have command like cat
- platform_is_not :windows do
- it "flushes and closes the write stream" do
- @io.puts '12345'
+ it "flushes and closes the write stream" do
+ @io.puts '12345'
- @io.close_write
+ @io.close_write
- @io.read.should == "12345\n"
- end
+ @io.read.should == "12345\n"
end
it "does nothing on closed stream" do
diff --git a/spec/ruby/core/io/codepoints_spec.rb b/spec/ruby/core/io/codepoints_spec.rb
new file mode 100644
index 0000000000..04c115dd3f
--- /dev/null
+++ b/spec/ruby/core/io/codepoints_spec.rb
@@ -0,0 +1,38 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/codepoints'
+
+ruby_version_is ''...'3.0' do
+
+ # See redmine #1667
+ describe "IO#codepoints" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :io_codepoints, :codepoints
+ end
+
+ describe "IO#codepoints" do
+ before :each do
+ @io = IOSpecs.io_fixture "lines.txt"
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ @io.close unless @io.closed?
+ end
+
+ it "calls the given block" do
+ r = []
+ @io.codepoints { |c| r << c }
+ r[24].should == 232
+ r.last.should == 10
+ end
+ end
+end
diff --git a/spec/ruby/core/io/copy_stream_spec.rb b/spec/ruby/core/io/copy_stream_spec.rb
index ffa2ea992c..df9c5c7390 100644
--- a/spec/ruby/core/io/copy_stream_spec.rb
+++ b/spec/ruby/core/io/copy_stream_spec.rb
@@ -69,12 +69,9 @@ describe :io_copy_stream_to_io, shared: true do
end
it "raises an IOError if the destination IO is not open for writing" do
- to_io = new_io __FILE__, "r"
- begin
- -> { IO.copy_stream @object.from, to_io }.should raise_error(IOError)
- ensure
- to_io.close
- end
+ @to_io.close
+ @to_io = new_io @to_name, "r"
+ -> { IO.copy_stream @object.from, @to_io }.should raise_error(IOError)
end
it "does not close the destination IO" do
@@ -112,8 +109,7 @@ describe "IO.copy_stream" do
end
after :each do
- rm_r @to_name if @to_name
- rm_r @from_bigfile
+ rm_r @to_name, @from_bigfile
end
describe "from an IO" do
@@ -168,25 +164,6 @@ describe "IO.copy_stream" do
it_behaves_like :io_copy_stream_to_io, nil, IOSpecs::CopyStream
it_behaves_like :io_copy_stream_to_io_with_offset, nil, IOSpecs::CopyStream
end
-
- describe "to a Tempfile" do
- before :all do
- require 'tempfile'
- end
-
- before :each do
- @to_io = Tempfile.new("rubyspec_copy_stream", encoding: Encoding::BINARY, mode: File::RDONLY)
- @to_name = @to_io.path
- end
-
- after :each do
- @to_io.close!
- @to_name = nil # do not rm_r it, already done by Tempfile#close!
- end
-
- it_behaves_like :io_copy_stream_to_io, nil, IOSpecs::CopyStream
- it_behaves_like :io_copy_stream_to_io_with_offset, nil, IOSpecs::CopyStream
- end
end
describe "from a file name" do
@@ -300,8 +277,10 @@ describe "IO.copy_stream" do
@io.should_not_receive(:pos)
IO.copy_stream(@io, @to_name)
end
+
end
+
describe "with a destination that does partial reads" do
before do
@from_out, @from_in = IO.pipe
diff --git a/spec/ruby/core/io/eof_spec.rb b/spec/ruby/core/io/eof_spec.rb
index b4850df437..315345d942 100644
--- a/spec/ruby/core/io/eof_spec.rb
+++ b/spec/ruby/core/io/eof_spec.rb
@@ -76,7 +76,7 @@ describe "IO#eof?" do
end
it "returns true on one-byte stream after single-byte read" do
- File.open(__dir__ + '/fixtures/one_byte.txt') { |one_byte|
+ File.open(File.dirname(__FILE__) + '/fixtures/one_byte.txt') { |one_byte|
one_byte.read(1)
one_byte.should.eof?
}
diff --git a/spec/ruby/core/io/flush_spec.rb b/spec/ruby/core/io/flush_spec.rb
index f7d5ba77fc..34cf42c425 100644
--- a/spec/ruby/core/io/flush_spec.rb
+++ b/spec/ruby/core/io/flush_spec.rb
@@ -19,11 +19,11 @@ describe "IO#flush" do
end
end
- # [ruby-core:90895] RJIT worker may leave fd open in a forked child.
- # For instance, RJIT creates a worker before @r.close with fork(), @r.close happens,
- # and the RJIT worker keeps the pipe open until the worker execve().
- # TODO: consider acquiring GVL from RJIT worker.
- guard_not -> { defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? } do
+ # [ruby-core:90895] MJIT worker may leave fd open in a forked child.
+ # For instance, MJIT creates a worker before @r.close with fork(), @r.close happens,
+ # and the MJIT worker keeps the pipe open until the worker execve().
+ # TODO: consider acquiring GVL from MJIT worker.
+ guard_not -> { defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? } do
it "raises Errno::EPIPE if sync=false and the read end is closed" do
@w.sync = false
@w.write "foo"
diff --git a/spec/ruby/core/io/foreach_spec.rb b/spec/ruby/core/io/foreach_spec.rb
index c361d27879..c2276cf544 100644
--- a/spec/ruby/core/io/foreach_spec.rb
+++ b/spec/ruby/core/io/foreach_spec.rb
@@ -20,10 +20,7 @@ describe "IO.foreach" do
platform_is :windows do
cmd = "|cmd.exe /C echo hello&echo line2"
end
-
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.foreach(cmd) { |l| ScratchPad << l }
- end
+ IO.foreach(cmd) { |l| ScratchPad << l }
ScratchPad.recorded.should == ["hello\n", "line2\n"]
end
@@ -31,9 +28,7 @@ describe "IO.foreach" do
it "gets data from a fork when passed -" do
parent_pid = $$
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.foreach("|-") { |l| ScratchPad << l }
- end
+ IO.foreach("|-") { |l| ScratchPad << l }
if $$ == parent_pid
ScratchPad.recorded.should == ["hello\n", "from a fork\n"]
@@ -44,16 +39,6 @@ describe "IO.foreach" do
end
end
end
-
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19630
- it "warns about deprecation given a path with a pipe" do
- cmd = "|echo ok"
- -> {
- IO.foreach(cmd).to_a
- }.should complain(/IO process creation with a leading '\|'/)
- end
- end
end
end
diff --git a/spec/ruby/core/io/getbyte_spec.rb b/spec/ruby/core/io/getbyte_spec.rb
index b4351160e6..6ba8f0a3e0 100644
--- a/spec/ruby/core/io/getbyte_spec.rb
+++ b/spec/ruby/core/io/getbyte_spec.rb
@@ -40,19 +40,3 @@ describe "IO#getbyte" do
@io.getbyte.should == nil
end
end
-
-describe "IO#getbyte" do
- before :each do
- @name = tmp("io_getbyte.txt")
- @io = new_io(@name, 'w')
- end
-
- after :each do
- @io.close if @io
- rm_r @name if @name
- end
-
- it "raises an IOError if the stream is not readable" do
- -> { @io.getbyte }.should raise_error(IOError)
- end
-end
diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb
index ca64bf860e..d0c91705af 100644
--- a/spec/ruby/core/io/gets_spec.rb
+++ b/spec/ruby/core/io/gets_spec.rb
@@ -24,12 +24,6 @@ describe "IO#gets" do
end
end
- it "sets $_ to nil after the last line has been read" do
- while @io.gets
- end
- $_.should be_nil
- end
-
it "returns nil if called at the end of the stream" do
IOSpecs.lines.length.times { @io.gets }
@io.gets.should == nil
@@ -119,35 +113,6 @@ describe "IO#gets" do
$..should == @count += 1
end
end
-
- describe "that consists of multiple bytes" do
- platform_is_not :windows do
- it "should match the separator even if the buffer is filled over successive reads" do
- IO.pipe do |read, write|
-
- # Write part of the string with the separator split between two write calls. We want
- # the read to intertwine such that when the read starts the full data isn't yet
- # available in the buffer.
- write.write("Aquí está la línea tres\r\n")
-
- t = Thread.new do
- # Continue reading until the separator is encountered or the pipe is closed.
- read.gets("\r\n\r\n")
- end
-
- # Write the other half of the separator, which should cause the `gets` call to now
- # match. Explicitly close the pipe for good measure so a bug in `gets` doesn't block forever.
- Thread.pass until t.stop?
-
- write.write("\r\nelse\r\n\r\n")
- write.close
-
- t.value.bytes.should == "Aquí está la línea tres\r\n\r\n".bytes
- read.read(8).bytes.should == "else\r\n\r\n".bytes
- end
- end
- end
- end
end
describe "when passed chomp" do
@@ -155,12 +120,14 @@ describe "IO#gets" do
@io.gets(chomp: true).should == IOSpecs.lines_without_newline_characters[0]
end
- it "raises exception when options passed as Hash" do
- -> { @io.gets({ chomp: true }) }.should raise_error(TypeError)
+ ruby_version_is "3.0" do
+ it "raises exception when options passed as Hash" do
+ -> { @io.gets({ chomp: true }) }.should raise_error(TypeError)
- -> {
- @io.gets("\n", 1, { chomp: true })
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ -> {
+ @io.gets("\n", 1, { chomp: true })
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
end
end
end
@@ -338,23 +305,11 @@ describe "IO#gets" do
@io.gets.encoding.should == Encoding::BINARY
end
- ruby_version_is ''...'3.3' do
- it "transcodes to internal encoding if the IO object's external encoding is BINARY" do
- Encoding.default_external = Encoding::BINARY
- Encoding.default_internal = Encoding::UTF_8
- @io = new_io @name, 'r'
- @io.set_encoding Encoding::BINARY, Encoding::UTF_8
- @io.gets.encoding.should == Encoding::UTF_8
- end
- end
-
- ruby_version_is '3.3' do
- it "ignores the internal encoding if the IO object's external encoding is BINARY" do
- Encoding.default_external = Encoding::BINARY
- Encoding.default_internal = Encoding::UTF_8
- @io = new_io @name, 'r'
- @io.set_encoding Encoding::BINARY, Encoding::UTF_8
- @io.gets.encoding.should == Encoding::BINARY
- end
+ it "transcodes to internal encoding if the IO object's external encoding is BINARY" do
+ Encoding.default_external = Encoding::BINARY
+ Encoding.default_internal = Encoding::UTF_8
+ @io = new_io @name, 'r'
+ @io.set_encoding Encoding::BINARY, Encoding::UTF_8
+ @io.gets.encoding.should == Encoding::UTF_8
end
end
diff --git a/spec/ruby/core/io/initialize_spec.rb b/spec/ruby/core/io/initialize_spec.rb
index 026252a13d..ba5bc117b7 100644
--- a/spec/ruby/core/io/initialize_spec.rb
+++ b/spec/ruby/core/io/initialize_spec.rb
@@ -27,17 +27,6 @@ describe "IO#initialize" do
@io.fileno.should == fd
end
- it "accepts options as keyword arguments" do
- fd = new_fd @name, "w:utf-8"
-
- @io.send(:initialize, fd, "w", flags: File::CREAT)
- @io.fileno.should == fd
-
- -> {
- @io.send(:initialize, fd, "w", {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 1..2)")
- end
-
it "raises a TypeError when passed an IO" do
-> { @io.send :initialize, STDOUT, 'w' }.should raise_error(TypeError)
end
diff --git a/spec/ruby/core/io/ioctl_spec.rb b/spec/ruby/core/io/ioctl_spec.rb
index 3f7b5ad5d7..8dcd9eb2c6 100644
--- a/spec/ruby/core/io/ioctl_spec.rb
+++ b/spec/ruby/core/io/ioctl_spec.rb
@@ -12,7 +12,7 @@ describe "IO#ioctl" do
guard -> { RUBY_PLATFORM.include?("86") } do # x86 / x86_64
it "resizes an empty String to match the output size" do
File.open(__FILE__, 'r') do |f|
- buffer = +''
+ buffer = ''
# FIONREAD in /usr/include/asm-generic/ioctls.h
f.ioctl 0x541B, buffer
buffer.unpack('I').first.should be_kind_of(Integer)
diff --git a/spec/ruby/core/io/lineno_spec.rb b/spec/ruby/core/io/lineno_spec.rb
index e82cdd9f17..9a4ad90880 100644
--- a/spec/ruby/core/io/lineno_spec.rb
+++ b/spec/ruby/core/io/lineno_spec.rb
@@ -26,8 +26,7 @@ describe "IO#lineno" do
end
it "raises an IOError on a duplexed stream with the read side closed" do
- cmd = platform_is(:windows) ? 'rem' : 'cat'
- IO.popen(cmd, 'r+') do |p|
+ IO.popen('cat', 'r+') do |p|
p.close_read
-> { p.lineno }.should raise_error(IOError)
end
@@ -71,8 +70,7 @@ describe "IO#lineno=" do
end
it "raises an IOError on a duplexed stream with the read side closed" do
- cmd = platform_is(:windows) ? 'rem' : 'cat'
- IO.popen(cmd, 'r+') do |p|
+ IO.popen('cat', 'r+') do |p|
p.close_read
-> { p.lineno = 0 }.should raise_error(IOError)
end
diff --git a/spec/ruby/core/io/lines_spec.rb b/spec/ruby/core/io/lines_spec.rb
new file mode 100644
index 0000000000..5b29a1d07e
--- /dev/null
+++ b/spec/ruby/core/io/lines_spec.rb
@@ -0,0 +1,46 @@
+# -*- encoding: utf-8 -*-
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is ''...'3.0' do
+ describe "IO#lines" do
+ before :each do
+ @io = IOSpecs.io_fixture "lines.txt"
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ @io.close if @io
+ end
+
+ it "returns an Enumerator" do
+ @io.lines.should be_an_instance_of(Enumerator)
+ end
+
+ describe "when no block is given" do
+ it "returns an Enumerator" do
+ @io.lines.should be_an_instance_of(Enumerator)
+ end
+
+ describe "returned Enumerator" do
+ describe "size" do
+ it "should return nil" do
+ @io.lines.size.should == nil
+ end
+ end
+ end
+ end
+
+ it "returns a line when accessed" do
+ enum = @io.lines
+ enum.first.should == IOSpecs.lines[0]
+ end
+
+ it "yields each line to the passed block" do
+ ScratchPad.record []
+ @io.lines { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.lines
+ end
+ end
+end
diff --git a/spec/ruby/core/io/new_spec.rb b/spec/ruby/core/io/new_spec.rb
index 979ac0efcb..0ef30991fd 100644
--- a/spec/ruby/core/io/new_spec.rb
+++ b/spec/ruby/core/io/new_spec.rb
@@ -1,16 +1,10 @@
require_relative '../../spec_helper'
require_relative 'shared/new'
-# NOTE: should be synchronized with library/stringio/initialize_spec.rb
+# NOTE: should be syncronized with library/stringio/initialize_spec.rb
describe "IO.new" do
it_behaves_like :io_new, :new
-
- it "does not use the given block and warns to use IO::open" do
- -> {
- @io = IO.send(@method, @fd) { raise }
- }.should complain(/warning: IO::new\(\) does not take block; use IO::open\(\) instead/)
- end
end
describe "IO.new" do
diff --git a/spec/ruby/core/io/nonblock_spec.rb b/spec/ruby/core/io/nonblock_spec.rb
index 99dc0cafd0..e81ac10c58 100644
--- a/spec/ruby/core/io/nonblock_spec.rb
+++ b/spec/ruby/core/io/nonblock_spec.rb
@@ -12,21 +12,43 @@ platform_is_not :windows do
end
end
- it "returns true for pipe by default" do
- r, w = IO.pipe
- begin
- r.nonblock?.should == true
- w.nonblock?.should == true
- ensure
- r.close
- w.close
+ ruby_version_is ""..."3.0" do
+ it "returns false for pipe by default" do
+ r, w = IO.pipe
+ begin
+ r.nonblock?.should == false
+ w.nonblock?.should == false
+ ensure
+ r.close
+ w.close
+ end
+ end
+
+ it "returns false for socket by default" do
+ require 'socket'
+ TCPServer.open(0) do |socket|
+ socket.nonblock?.should == false
+ end
end
end
- it "returns true for socket by default" do
- require 'socket'
- TCPServer.open(0) do |socket|
- socket.nonblock?.should == true
+ ruby_version_is "3.0" do
+ it "returns true for pipe by default" do
+ r, w = IO.pipe
+ begin
+ r.nonblock?.should == true
+ w.nonblock?.should == true
+ ensure
+ r.close
+ w.close
+ end
+ end
+
+ it "returns true for socket by default" do
+ require 'socket'
+ TCPServer.open(0) do |socket|
+ socket.nonblock?.should == true
+ end
end
end
end
diff --git a/spec/ruby/core/io/open_spec.rb b/spec/ruby/core/io/open_spec.rb
index d151da9ce5..d3a3961df7 100644
--- a/spec/ruby/core/io/open_spec.rb
+++ b/spec/ruby/core/io/open_spec.rb
@@ -37,19 +37,6 @@ describe "IO.open" do
ScratchPad.recorded.should == :called
end
- it "propagate an exception in the block after calling #close" do
- -> do
- IO.open(@fd, "w") do |io|
- IOSpecs.io_mock(io, :close) do
- super()
- ScratchPad.record :called
- end
- raise Exception
- end
- end.should raise_error(Exception)
- ScratchPad.recorded.should == :called
- end
-
it "propagates an exception raised by #close that is not a StandardError" do
-> do
IO.open(@fd, "w") do |io|
diff --git a/spec/ruby/core/io/pread_spec.rb b/spec/ruby/core/io/pread_spec.rb
index 6d93b432c2..43071d6a31 100644
--- a/spec/ruby/core/io/pread_spec.rb
+++ b/spec/ruby/core/io/pread_spec.rb
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
+platform_is_not :windows do
describe "IO#pread" do
before :each do
@fname = tmp("io_pread.txt")
@@ -21,100 +21,16 @@ guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
end
it "accepts a length, an offset, and an output buffer" do
- buffer = +"foo"
- @file.pread(3, 4, buffer).should.equal?(buffer)
+ buffer = "foo"
+ @file.pread(3, 4, buffer)
buffer.should == "567"
end
- it "shrinks the buffer in case of less bytes read" do
- buffer = +"foo"
- @file.pread(1, 0, buffer)
- buffer.should == "1"
- end
-
- it "grows the buffer in case of more bytes read" do
- buffer = +"foo"
- @file.pread(5, 0, buffer)
- buffer.should == "12345"
- end
-
- it "preserves the encoding of the given buffer" do
- buffer = ''.encode(Encoding::ISO_8859_1)
- @file.pread(10, 0, buffer)
-
- buffer.encoding.should == Encoding::ISO_8859_1
- end
-
it "does not advance the file pointer" do
@file.pread(4, 0).should == "1234"
@file.read.should == "1234567890"
end
- it "ignores the current offset" do
- @file.pos = 3
- @file.pread(4, 0).should == "1234"
- end
-
- it "returns an empty string for maxlen = 0" do
- @file.pread(0, 4).should == ""
- end
-
- it "ignores the offset for maxlen = 0, even if it is out of file bounds" do
- @file.pread(0, 400).should == ""
- end
-
- it "does not reset the buffer when reading with maxlen = 0" do
- buffer = +"foo"
- @file.pread(0, 4, buffer)
- buffer.should == "foo"
-
- @file.pread(0, 400, buffer)
- buffer.should == "foo"
- end
-
- it "converts maxlen to Integer using #to_int" do
- maxlen = mock('maxlen')
- maxlen.should_receive(:to_int).and_return(4)
- @file.pread(maxlen, 0).should == "1234"
- end
-
- it "converts offset to Integer using #to_int" do
- offset = mock('offset')
- offset.should_receive(:to_int).and_return(0)
- @file.pread(4, offset).should == "1234"
- end
-
- it "converts a buffer to String using to_str" do
- buffer = mock('buffer')
- buffer.should_receive(:to_str).at_least(1).and_return(+"foo")
- @file.pread(4, 0, buffer)
- buffer.should_not.is_a?(String)
- buffer.to_str.should == "1234"
- end
-
- it "raises TypeError if maxlen is not an Integer and cannot be coerced into Integer" do
- maxlen = Object.new
- -> { @file.pread(maxlen, 0) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer')
- end
-
- it "raises TypeError if offset is not an Integer and cannot be coerced into Integer" do
- offset = Object.new
- -> { @file.pread(4, offset) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer')
- end
-
- it "raises ArgumentError for negative values of maxlen" do
- -> { @file.pread(-4, 0) }.should raise_error(ArgumentError, 'negative string size (or size too big)')
- end
-
- it "raised Errno::EINVAL for negative values of offset" do
- -> { @file.pread(4, -1) }.should raise_error(Errno::EINVAL, /Invalid argument/)
- end
-
- it "raises TypeError if the buffer is not a String and cannot be coerced into String" do
- buffer = Object.new
- -> { @file.pread(4, 0, buffer) }.should raise_error(TypeError, 'no implicit conversion of Object into String')
- end
-
it "raises EOFError if end-of-file is reached" do
-> { @file.pread(1, 10) }.should raise_error(EOFError)
end
diff --git a/spec/ruby/core/io/puts_spec.rb b/spec/ruby/core/io/puts_spec.rb
index 9ed343c94c..9a708fffef 100644
--- a/spec/ruby/core/io/puts_spec.rb
+++ b/spec/ruby/core/io/puts_spec.rb
@@ -6,7 +6,7 @@ describe "IO#puts" do
@before_separator = $/
@name = tmp("io_puts.txt")
@io = new_io @name
- ScratchPad.record(+"")
+ ScratchPad.record ""
def @io.write(str)
ScratchPad << str
end
diff --git a/spec/ruby/core/io/pwrite_spec.rb b/spec/ruby/core/io/pwrite_spec.rb
index 2bc508b37d..fe29d1e1f6 100644
--- a/spec/ruby/core/io/pwrite_spec.rb
+++ b/spec/ruby/core/io/pwrite_spec.rb
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
+platform_is_not :windows do
describe "IO#pwrite" do
before :each do
@fname = tmp("io_pwrite.txt")
@@ -28,42 +28,16 @@ guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
@file.pread(6, 0).should == "foobar"
end
- it "calls #to_s on the object to be written" do
- object = mock("to_s")
- object.should_receive(:to_s).and_return("foo")
- @file.pwrite(object, 0)
- @file.pread(3, 0).should == "foo"
- end
-
- it "calls #to_int on the offset" do
- offset = mock("to_int")
- offset.should_receive(:to_int).and_return(2)
- @file.pwrite("foo", offset)
- @file.pread(3, 2).should == "foo"
- end
-
it "raises IOError when file is not open in write mode" do
File.open(@fname, "r") do |file|
- -> { file.pwrite("foo", 1) }.should raise_error(IOError, "not opened for writing")
+ -> { file.pwrite("foo", 1) }.should raise_error(IOError)
end
end
it "raises IOError when file is closed" do
file = File.open(@fname, "w+")
file.close
- -> { file.pwrite("foo", 1) }.should raise_error(IOError, "closed stream")
- end
-
- it "raises a NoMethodError if object does not respond to #to_s" do
- -> {
- @file.pwrite(BasicObject.new, 0)
- }.should raise_error(NoMethodError, /undefined method [`']to_s'/)
- end
-
- it "raises a TypeError if the offset cannot be converted to an Integer" do
- -> {
- @file.pwrite("foo", Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ -> { file.pwrite("foo", 1) }.should raise_error(IOError)
end
end
end
diff --git a/spec/ruby/core/io/read_nonblock_spec.rb b/spec/ruby/core/io/read_nonblock_spec.rb
index 51e7cd6bd2..a62b75274c 100644
--- a/spec/ruby/core/io/read_nonblock_spec.rb
+++ b/spec/ruby/core/io/read_nonblock_spec.rb
@@ -96,21 +96,21 @@ describe "IO#read_nonblock" do
end
it "reads into the passed buffer" do
- buffer = +""
+ buffer = ""
@write.write("1")
@read.read_nonblock(1, buffer)
buffer.should == "1"
end
it "returns the passed buffer" do
- buffer = +""
+ buffer = ""
@write.write("1")
output = @read.read_nonblock(1, buffer)
output.should equal(buffer)
end
it "discards the existing buffer content upon successful read" do
- buffer = +"existing content"
+ buffer = "existing content"
@write.write("hello world")
@write.close
@read.read_nonblock(11, buffer)
@@ -118,7 +118,7 @@ describe "IO#read_nonblock" do
end
it "discards the existing buffer content upon error" do
- buffer = +"existing content"
+ buffer = "existing content"
@write.close
-> { @read.read_nonblock(1, buffer) }.should raise_error(EOFError)
buffer.should be_empty
diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb
index 8741d9f017..529afbf0ff 100644
--- a/spec/ruby/core/io/read_spec.rb
+++ b/spec/ruby/core/io/read_spec.rb
@@ -23,15 +23,6 @@ describe "IO.read" do
IO.read(p)
end
- # https://bugs.ruby-lang.org/issues/19354
- it "accepts options as keyword arguments" do
- IO.read(@fname, 3, 0, mode: "r+").should == @contents[0, 3]
-
- -> {
- IO.read(@fname, 3, 0, {mode: "r+"})
- }.should raise_error(ArgumentError, /wrong number of arguments/)
- end
-
it "accepts an empty options Hash" do
IO.read(@fname, **{}).should == @contents
end
@@ -64,33 +55,6 @@ describe "IO.read" do
IO.read(@fname, mode: "a+").should == @contents
end
- platform_is_not :windows do
- ruby_version_is ""..."3.3" do
- it "uses an :open_args option" do
- string = IO.read(@fname, nil, 0, open_args: ["r", nil, {encoding: Encoding::US_ASCII}])
- string.encoding.should == Encoding::US_ASCII
-
- string = IO.read(@fname, nil, 0, open_args: ["r", nil, {}])
- string.encoding.should == Encoding::UTF_8
- end
- end
- end
-
- it "disregards other options if :open_args is given" do
- string = IO.read(@fname,mode: "w", encoding: Encoding::UTF_32LE, open_args: ["r", encoding: Encoding::UTF_8])
- string.encoding.should == Encoding::UTF_8
- end
-
- it "doesn't require mode to be specified in :open_args" do
- string = IO.read(@fname, nil, 0, open_args: [{encoding: Encoding::US_ASCII}])
- string.encoding.should == Encoding::US_ASCII
- end
-
- it "doesn't require mode to be specified in :open_args even if flags option passed" do
- string = IO.read(@fname, nil, 0, open_args: [{encoding: Encoding::US_ASCII, flags: File::CREAT}])
- string.encoding.should == Encoding::US_ASCII
- end
-
it "treats second nil argument as no length limit" do
IO.read(@fname, nil).should == @contents
IO.read(@fname, nil, 5).should == IO.read(@fname, @contents.length, 5)
@@ -113,15 +77,6 @@ describe "IO.read" do
IO.read(@fname, 1, 10).should == nil
end
- it "returns an empty string when reading zero bytes" do
- IO.read(@fname, 0).should == ''
- end
-
- it "returns a String in BINARY when passed a size" do
- IO.read(@fname, 1).encoding.should == Encoding::BINARY
- IO.read(@fname, 0).encoding.should == Encoding::BINARY
- end
-
it "raises an Errno::ENOENT when the requested file does not exist" do
rm_r @fname
-> { IO.read @fname }.should raise_error(Errno::ENOENT)
@@ -135,18 +90,9 @@ describe "IO.read" do
-> { IO.read @fname, -1 }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'3.3' do
- it "raises an Errno::EINVAL when not passed a valid offset" do
- -> { IO.read @fname, 0, -1 }.should raise_error(Errno::EINVAL)
- -> { IO.read @fname, -1, -1 }.should raise_error(Errno::EINVAL)
- end
- end
-
- ruby_version_is '3.3' do
- it "raises an ArgumentError when not passed a valid offset" do
- -> { IO.read @fname, 0, -1 }.should raise_error(ArgumentError)
- -> { IO.read @fname, -1, -1 }.should raise_error(ArgumentError)
- end
+ it "raises an Errno::EINVAL when not passed a valid offset" do
+ -> { IO.read @fname, 0, -1 }.should raise_error(Errno::EINVAL)
+ -> { IO.read @fname, -1, -1 }.should raise_error(Errno::EINVAL)
end
it "uses the external encoding specified via the :external_encoding option" do
@@ -174,19 +120,12 @@ describe "IO.read from a pipe" do
platform_is :windows do
cmd = "|cmd.exe /C echo hello"
end
-
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.read(cmd).should == "hello\n"
- end
+ IO.read(cmd).should == "hello\n"
end
platform_is_not :windows do
it "opens a pipe to a fork if the rest is -" do
- str = nil
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- str = IO.read("|-")
- end
-
+ str = IO.read("|-")
if str # parent
str.should == "hello from child\n"
else #child
@@ -201,18 +140,13 @@ describe "IO.read from a pipe" do
platform_is :windows do
cmd = "|cmd.exe /C echo hello"
end
-
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.read(cmd, 1).should == "h"
- end
+ IO.read(cmd, 1).should == "h"
end
platform_is_not :windows do
it "raises Errno::ESPIPE if passed an offset" do
-> {
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.read("|sh -c 'echo hello'", 1, 1)
- end
+ IO.read("|sh -c 'echo hello'", 1, 1)
}.should raise_error(Errno::ESPIPE)
end
end
@@ -223,23 +157,11 @@ quarantine! do # The process tried to write to a nonexistent pipe.
# once https://bugs.ruby-lang.org/issues/12230 is fixed.
it "raises Errno::EINVAL if passed an offset" do
-> {
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.read("|cmd.exe /C echo hello", 1, 1)
- end
+ IO.read("|cmd.exe /C echo hello", 1, 1)
}.should raise_error(Errno::EINVAL)
end
end
end
-
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19630
- it "warns about deprecation given a path with a pipe" do
- cmd = "|echo ok"
- -> {
- IO.read(cmd)
- }.should complain(/IO process creation with a leading '\|'/)
- end
- end
end
describe "IO.read on an empty file" do
@@ -283,55 +205,21 @@ describe "IO#read" do
@io.read(4).should == '7890'
end
- it "treats first nil argument as no length limit" do
- @io.read(nil).should == @contents
- end
-
- it "raises an ArgumentError when not passed a valid length" do
- -> { @io.read(-1) }.should raise_error(ArgumentError)
- end
-
it "clears the output buffer if there is nothing to read" do
@io.pos = 10
- buf = +'non-empty string'
+ buf = 'non-empty string'
@io.read(10, buf).should == nil
buf.should == ''
-
- buf = +'non-empty string'
-
- @io.read(nil, buf).should == ""
-
- buf.should == ''
-
- buf = +'non-empty string'
-
- @io.read(0, buf).should == ""
-
- buf.should == ''
- end
-
- it "raise FrozenError if the output buffer is frozen" do
- @io.read
- -> { @io.read(0, 'frozen-string'.freeze) }.should raise_error(FrozenError)
- -> { @io.read(1, 'frozen-string'.freeze) }.should raise_error(FrozenError)
- -> { @io.read(nil, 'frozen-string'.freeze) }.should raise_error(FrozenError)
- end
-
- ruby_bug "", ""..."3.3" do
- it "raise FrozenError if the output buffer is frozen (2)" do
- @io.read
- -> { @io.read(1, ''.freeze) }.should raise_error(FrozenError)
- end
end
it "consumes zero bytes when reading zero bytes" do
@io.read(0).should == ''
@io.pos.should == 0
- @io.getc.should == '1'
+ @io.getc.chr.should == '1'
end
it "is at end-of-file when everything has been read" do
@@ -344,68 +232,53 @@ describe "IO#read" do
end
it "places the specified number of bytes in the buffer" do
- buf = +""
+ buf = ""
@io.read 5, buf
buf.should == "12345"
end
it "expands the buffer when too small" do
- buf = +"ABCDE"
+ buf = "ABCDE"
@io.read nil, buf
buf.should == @contents
end
it "overwrites the buffer" do
- buf = +"ABCDEFGHIJ"
+ buf = "ABCDEFGHIJ"
@io.read nil, buf
buf.should == @contents
end
it "truncates the buffer when too big" do
- buf = +"ABCDEFGHIJKLMNO"
+ buf = "ABCDEFGHIJKLMNO"
@io.read nil, buf
buf.should == @contents
@io.rewind
- buf = +"ABCDEFGHIJKLMNO"
+ buf = "ABCDEFGHIJKLMNO"
@io.read 5, buf
buf.should == @contents[0..4]
end
- it "preserves the encoding of the given buffer" do
- buffer = ''.encode(Encoding::ISO_8859_1)
- @io.read(10, buffer)
-
- buffer.encoding.should == Encoding::ISO_8859_1
- end
-
- # https://bugs.ruby-lang.org/issues/20416
- it "does not preserve the encoding of the given buffer when max length is not provided" do
- buffer = ''.encode(Encoding::ISO_8859_1)
- @io.read(nil, buffer)
-
- buffer.encoding.should_not == Encoding::ISO_8859_1
- end
-
it "returns the given buffer" do
- buf = +""
+ buf = ""
@io.read(nil, buf).should equal buf
end
it "returns the given buffer when there is nothing to read" do
- buf = +""
+ buf = ""
@io.read
@io.read(nil, buf).should equal buf
end
it "coerces the second argument to string and uses it as a buffer" do
- buf = +"ABCDE"
+ buf = "ABCDE"
obj = mock("buff")
obj.should_receive(:to_str).any_number_of_times.and_return(buf)
@@ -603,13 +476,13 @@ describe :io_read_internal_encoding, shared: true do
describe "when passed nil for limit" do
it "sets the buffer to a transcoded String" do
- result = @io.read(nil, buf = +"")
+ result = @io.read(nil, buf = "")
buf.should equal(result)
buf.should == "ã‚りãŒã¨ã†\n"
end
it "sets the buffer's encoding to the internal encoding" do
- buf = "".dup.force_encoding Encoding::ISO_8859_1
+ buf = "".force_encoding Encoding::ISO_8859_1
@io.read(nil, buf)
buf.encoding.should equal(Encoding::UTF_8)
end
@@ -623,18 +496,17 @@ describe :io_read_size_internal_encoding, shared: true do
it "returns a String in BINARY when passed a size" do
@io.read(4).encoding.should equal(Encoding::BINARY)
- @io.read(0).encoding.should equal(Encoding::BINARY)
end
it "does not change the buffer's encoding when passed a limit" do
- buf = "".dup.force_encoding Encoding::ISO_8859_1
+ buf = "".force_encoding Encoding::ISO_8859_1
@io.read(4, buf)
buf.should == [164, 162, 164, 234].pack('C*').force_encoding(Encoding::ISO_8859_1)
buf.encoding.should equal(Encoding::ISO_8859_1)
end
it "truncates the buffer but does not change the buffer's encoding when no data remains" do
- buf = "abc".dup.force_encoding Encoding::ISO_8859_1
+ buf = "abc".force_encoding Encoding::ISO_8859_1
@io.read
@io.read(1, buf).should be_nil
diff --git a/spec/ruby/core/io/readline_spec.rb b/spec/ruby/core/io/readline_spec.rb
index a814c1be90..cf9f0dfc11 100644
--- a/spec/ruby/core/io/readline_spec.rb
+++ b/spec/ruby/core/io/readline_spec.rb
@@ -73,12 +73,14 @@ describe "IO#readline" do
@io.readline(chomp: true).should == IOSpecs.lines_without_newline_characters[0]
end
- it "raises exception when options passed as Hash" do
- -> { @io.readline({ chomp: true }) }.should raise_error(TypeError)
+ ruby_version_is "3.0" do
+ it "raises exception when options passed as Hash" do
+ -> { @io.readline({ chomp: true }) }.should raise_error(TypeError)
- -> {
- @io.readline("\n", 1, { chomp: true })
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ -> {
+ @io.readline("\n", 1, { chomp: true })
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
end
end
end
diff --git a/spec/ruby/core/io/readlines_spec.rb b/spec/ruby/core/io/readlines_spec.rb
index 3a6ff3d0f3..496003002d 100644
--- a/spec/ruby/core/io/readlines_spec.rb
+++ b/spec/ruby/core/io/readlines_spec.rb
@@ -117,18 +117,14 @@ describe "IO#readlines" do
@io.readlines(chomp: true).should == IOSpecs.lines_without_newline_characters
end
- it "raises exception when options passed as Hash" do
- -> { @io.readlines({ chomp: true }) }.should raise_error(TypeError)
+ ruby_version_is "3.0" do
+ it "raises exception when options passed as Hash" do
+ -> { @io.readlines({ chomp: true }) }.should raise_error(TypeError)
- -> {
- @io.readlines("\n", 1, { chomp: true })
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
- end
- end
-
- describe "when passed arbitrary keyword argument" do
- it "tolerates it" do
- @io.readlines(chomp: true, foo: :bar).should == IOSpecs.lines_without_newline_characters
+ -> {
+ @io.readlines("\n", 1, { chomp: true })
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
end
end
end
@@ -180,20 +176,13 @@ describe "IO.readlines" do
platform_is :windows do
cmd = "|cmd.exe /C echo hello&echo line2"
end
-
- lines = nil
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- lines = IO.readlines(cmd)
- end
+ lines = IO.readlines(cmd)
lines.should == ["hello\n", "line2\n"]
end
platform_is_not :windows do
it "gets data from a fork when passed -" do
- lines = nil
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- lines = IO.readlines("|-")
- end
+ lines = IO.readlines("|-")
if lines # parent
lines.should == ["hello\n", "from a fork\n"]
@@ -206,16 +195,6 @@ describe "IO.readlines" do
end
end
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19630
- it "warns about deprecation given a path with a pipe" do
- cmd = "|echo ok"
- -> {
- IO.readlines(cmd)
- }.should complain(/IO process creation with a leading '\|'/)
- end
- end
-
it_behaves_like :io_readlines, :readlines
it_behaves_like :io_readlines_options_19, :readlines
end
diff --git a/spec/ruby/core/io/readpartial_spec.rb b/spec/ruby/core/io/readpartial_spec.rb
index 0852f20b2d..2901b429c2 100644
--- a/spec/ruby/core/io/readpartial_spec.rb
+++ b/spec/ruby/core/io/readpartial_spec.rb
@@ -59,10 +59,10 @@ describe "IO#readpartial" do
end
it "discards the existing buffer content upon successful read" do
- buffer = +"existing content"
+ buffer = "existing content"
@wr.write("hello world")
@wr.close
- @rd.readpartial(11, buffer).should.equal?(buffer)
+ @rd.readpartial(11, buffer)
buffer.should == "hello world"
end
@@ -74,7 +74,7 @@ describe "IO#readpartial" do
end
it "discards the existing buffer content upon error" do
- buffer = +'hello'
+ buffer = 'hello'
@wr.close
-> { @rd.readpartial(1, buffer) }.should raise_error(EOFError)
buffer.should be_empty
@@ -95,7 +95,7 @@ describe "IO#readpartial" do
ruby_bug "#18421", ""..."3.0.4" do
it "clears and returns the given buffer if the length argument is 0" do
- buffer = +"existing content"
+ buffer = "existing content"
@rd.readpartial(0, buffer).should == buffer
buffer.should == ""
end
@@ -106,7 +106,6 @@ describe "IO#readpartial" do
@wr.write("abc")
@wr.close
@rd.readpartial(10, buffer)
-
buffer.encoding.should == Encoding::ISO_8859_1
end
end
diff --git a/spec/ruby/core/io/select_spec.rb b/spec/ruby/core/io/select_spec.rb
index 3893e7620f..4603c1fbbc 100644
--- a/spec/ruby/core/io/select_spec.rb
+++ b/spec/ruby/core/io/select_spec.rb
@@ -55,8 +55,8 @@ describe "IO.select" do
end
end
- it "returns supplied objects correctly when monitoring the same object in different arrays" do
- filename = tmp("IO_select_pipe_file")
+ it "returns supplied objects correctly even when monitoring the same object in different arrays" do
+ filename = tmp("IO_select_pipe_file") + $$.to_s
io = File.open(filename, 'w+')
result = IO.select [io], [io], nil, 0
result.should == [[io], [io], []]
@@ -64,17 +64,6 @@ describe "IO.select" do
rm_r filename
end
- it "returns the pipe read end in read set if the pipe write end is closed concurrently" do
- main = Thread.current
- t = Thread.new {
- Thread.pass until main.stop?
- @wr.close
- }
- IO.select([@rd]).should == [[@rd], [], []]
- ensure
- t.join
- end
-
it "invokes to_io on supplied objects that are not IO and returns the supplied objects" do
# make some data available
@wr.write("foobar")
@@ -114,39 +103,6 @@ describe "IO.select" do
it "raises an ArgumentError when passed a negative timeout" do
-> { IO.select(nil, nil, nil, -5)}.should raise_error(ArgumentError)
end
-
- describe "returns the available descriptors when the file descriptor" do
- it "is in both read and error arrays" do
- @wr.write("foobar")
- result = IO.select([@rd], nil, [@rd])
- result.should == [[@rd], [], []]
- end
-
- it "is in both write and error arrays" do
- result = IO.select(nil, [@wr], [@wr])
- result.should == [[], [@wr], []]
- end
-
- it "is in both read and write arrays" do
- filename = tmp("IO_select_read_write_file")
- w = File.open(filename, 'w+')
- begin
- IO.select([w], [w], []).should == [[w], [w], []]
- ensure
- w.close
- rm_r filename
- end
-
- IO.select([@wr], [@wr], []).should == [[], [@wr], []]
-
- @wr.write("foobar")
- # CRuby on macOS returns [[@rd], [@rd], []], weird but we accept it here, probably only for pipe read-end
- [
- [[@rd], [], []],
- [[@rd], [@rd], []]
- ].should.include? IO.select([@rd], [@rd], [])
- end
- end
end
describe "IO.select when passed nil for timeout" do
diff --git a/spec/ruby/core/io/shared/binwrite.rb b/spec/ruby/core/io/shared/binwrite.rb
index e51093329b..3649bb47ff 100644
--- a/spec/ruby/core/io/shared/binwrite.rb
+++ b/spec/ruby/core/io/shared/binwrite.rb
@@ -21,14 +21,6 @@ describe :io_binwrite, shared: true do
IO.send(@method, @filename, "abcde").should == 5
end
- it "accepts options as a keyword argument" do
- IO.send(@method, @filename, "hi", 0, flags: File::CREAT).should == 2
-
- -> {
- IO.send(@method, @filename, "hi", 0, {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 2..3)")
- end
-
it "creates a file if missing" do
fn = @filename + "xxx"
begin
@@ -75,11 +67,6 @@ describe :io_binwrite, shared: true do
File.read(@filename).should == "\0\0foo"
end
- it "accepts a :flags option without :mode one" do
- IO.send(@method, @filename, "hello, world!", flags: File::CREAT)
- File.read(@filename).should == "hello, world!"
- end
-
it "raises an error if readonly mode is specified" do
-> { IO.send(@method, @filename, "abcde", mode: "r") }.should raise_error(IOError)
end
diff --git a/spec/ruby/core/io/shared/each.rb b/spec/ruby/core/io/shared/each.rb
index aca622834f..02bbe19c1a 100644
--- a/spec/ruby/core/io/shared/each.rb
+++ b/spec/ruby/core/io/shared/each.rb
@@ -33,6 +33,10 @@ describe :io_each, shared: true do
$_.should == "test"
end
+ it "returns self" do
+ @io.send(@method) { |l| l }.should equal(@io)
+ end
+
it "raises an IOError when self is not readable" do
-> { IOSpecs.closed_io.send(@method) {} }.should raise_error(IOError)
end
@@ -176,14 +180,16 @@ describe :io_each, shared: true do
ScratchPad.recorded.should == IOSpecs.lines_without_newline_characters
end
- it "raises exception when options passed as Hash" do
- -> {
- @io.send(@method, { chomp: true }) { |s| }
- }.should raise_error(TypeError)
+ ruby_version_is "3.0" do
+ it "raises exception when options passed as Hash" do
+ -> {
+ @io.send(@method, { chomp: true }) { |s| }
+ }.should raise_error(TypeError)
- -> {
- @io.send(@method, "\n", 1, { chomp: true }) { |s| }
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ -> {
+ @io.send(@method, "\n", 1, { chomp: true }) { |s| }
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
end
end
diff --git a/spec/ruby/core/io/shared/new.rb b/spec/ruby/core/io/shared/new.rb
index cba5f33ebf..7677aada6e 100644
--- a/spec/ruby/core/io/shared/new.rb
+++ b/spec/ruby/core/io/shared/new.rb
@@ -1,6 +1,6 @@
require_relative '../fixtures/classes'
-# NOTE: should be synchronized with library/stringio/initialize_spec.rb
+# NOTE: should be syncronized with library/stringio/initialize_spec.rb
# This group of specs may ONLY contain specs that do successfully create
# an IO instance from the file descriptor returned by #new_fd helper.
@@ -64,15 +64,6 @@ describe :io_new, shared: true do
@io.should be_an_instance_of(IO)
end
- it "accepts options as keyword arguments" do
- @io = IO.send(@method, @fd, "w", flags: File::CREAT)
- @io.write("foo").should == 3
-
- -> {
- IO.send(@method, @fd, "w", {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 1..2)")
- end
-
it "accepts a :mode option" do
@io = IO.send(@method, @fd, mode: "w")
@io.write("foo").should == 3
@@ -208,10 +199,21 @@ describe :io_new, shared: true do
@io.internal_encoding.to_s.should == 'IBM866'
end
- it "raises ArgumentError for nil options" do
- -> {
- IO.send(@method, @fd, 'w', nil)
- }.should raise_error(ArgumentError)
+ ruby_version_is ''...'3.0' do
+ it "accepts nil options" do
+ @io = suppress_keyword_warning do
+ IO.send(@method, @fd, 'w', nil)
+ end
+ @io.write("foo").should == 3
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "raises ArgumentError for nil options" do
+ -> {
+ IO.send(@method, @fd, 'w', nil)
+ }.should raise_error(ArgumentError)
+ end
end
it "coerces mode with #to_str" do
@@ -382,9 +384,21 @@ describe :io_new_errors, shared: true do
}.should raise_error(ArgumentError)
end
- it "raises ArgumentError if passed a hash for mode and nil for options" do
- -> {
- @io = IO.send(@method, @fd, {mode: 'w'}, nil)
- }.should raise_error(ArgumentError)
+ ruby_version_is ''...'3.0' do
+ it "raises TypeError if passed a hash for mode and nil for options" do
+ -> {
+ suppress_keyword_warning do
+ @io = IO.send(@method, @fd, {mode: 'w'}, nil)
+ end
+ }.should raise_error(TypeError)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "raises ArgumentError if passed a hash for mode and nil for options" do
+ -> {
+ @io = IO.send(@method, @fd, {mode: 'w'}, nil)
+ }.should raise_error(ArgumentError)
+ end
end
end
diff --git a/spec/ruby/core/io/shared/readlines.rb b/spec/ruby/core/io/shared/readlines.rb
index 6c1fa11a59..7681e1b5c1 100644
--- a/spec/ruby/core/io/shared/readlines.rb
+++ b/spec/ruby/core/io/shared/readlines.rb
@@ -99,16 +99,18 @@ describe :io_readlines_options_19, shared: true do
end
it "accepts non-ASCII data as separator" do
- result = IO.send(@method, @name, "\303\250".dup.force_encoding("utf-8"), &@object)
+ result = IO.send(@method, @name, "\303\250".force_encoding("utf-8"), &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_arbitrary_separator
end
end
describe "when the object is an options Hash" do
- it "raises TypeError exception" do
- -> {
- IO.send(@method, @name, { chomp: true }, &@object)
- }.should raise_error(TypeError)
+ ruby_version_is "3.0" do
+ it "raises TypeError exception" do
+ -> {
+ IO.send(@method, @name, { chomp: true }, &@object)
+ }.should raise_error(TypeError)
+ end
end
end
@@ -177,10 +179,12 @@ describe :io_readlines_options_19, shared: true do
end
describe "when the second object is an options Hash" do
- it "raises TypeError exception" do
- -> {
- IO.send(@method, @name, "", { chomp: true }, &@object)
- }.should raise_error(TypeError)
+ ruby_version_is "3.0" do
+ it "raises TypeError exception" do
+ -> {
+ IO.send(@method, @name, "", { chomp: true }, &@object)
+ }.should raise_error(TypeError)
+ end
end
end
end
diff --git a/spec/ruby/core/io/shared/write.rb b/spec/ruby/core/io/shared/write.rb
index 964064746a..9503f94212 100644
--- a/spec/ruby/core/io/shared/write.rb
+++ b/spec/ruby/core/io/shared/write.rb
@@ -85,11 +85,11 @@ describe :io_write, shared: true do
@r.read.should == "foo"
end
- # [ruby-core:90895] RJIT worker may leave fd open in a forked child.
- # For instance, RJIT creates a worker before @r.close with fork(), @r.close happens,
- # and the RJIT worker keeps the pipe open until the worker execve().
- # TODO: consider acquiring GVL from RJIT worker.
- guard_not -> { defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? } do
+ # [ruby-core:90895] MJIT worker may leave fd open in a forked child.
+ # For instance, MJIT creates a worker before @r.close with fork(), @r.close happens,
+ # and the MJIT worker keeps the pipe open until the worker execve().
+ # TODO: consider acquiring GVL from MJIT worker.
+ guard_not -> { defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? } do
it "raises Errno::EPIPE if the read end is closed and does not die from SIGPIPE" do
@r.close
-> { @w.send(@method, "foo") }.should raise_error(Errno::EPIPE, /Broken pipe/)
@@ -97,58 +97,3 @@ describe :io_write, shared: true do
end
end
end
-
-describe :io_write_transcode, shared: true do
- before :each do
- @transcode_filename = tmp("io_write_transcode")
- end
-
- after :each do
- rm_r @transcode_filename
- end
-
- it "transcodes the given string when the external encoding is set and neither is BINARY" do
- utf8_str = "hello"
-
- File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file|
- file.external_encoding.should == Encoding::UTF_16BE
- file.send(@method, utf8_str)
- end
-
- result = File.binread(@transcode_filename)
- expected = [0, 104, 0, 101, 0, 108, 0, 108, 0, 111] # UTF-16BE bytes for "hello"
-
- result.bytes.should == expected
- end
-
- it "transcodes the given string when the external encoding is set and the string encoding is BINARY" do
- str = "été".b
-
- File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file|
- file.external_encoding.should == Encoding::UTF_16BE
- -> { file.send(@method, str) }.should raise_error(Encoding::UndefinedConversionError)
- end
- end
-end
-
-describe :io_write_no_transcode, shared: true do
- before :each do
- @transcode_filename = tmp("io_write_no_transcode")
- end
-
- after :each do
- rm_r @transcode_filename
- end
-
- it "does not transcode the given string even when the external encoding is set" do
- utf8_str = "hello"
-
- File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file|
- file.external_encoding.should == Encoding::UTF_16BE
- file.send(@method, utf8_str)
- end
-
- result = File.binread(@transcode_filename)
- result.bytes.should == utf8_str.bytes
- end
-end
diff --git a/spec/ruby/core/io/stat_spec.rb b/spec/ruby/core/io/stat_spec.rb
index 717c45d0a3..58eba02b8f 100644
--- a/spec/ruby/core/io/stat_spec.rb
+++ b/spec/ruby/core/io/stat_spec.rb
@@ -3,8 +3,7 @@ require_relative 'fixtures/classes'
describe "IO#stat" do
before :each do
- cmd = platform_is(:windows) ? 'rem' : 'cat'
- @io = IO.popen cmd, "r+"
+ @io = IO.popen 'cat', "r+"
end
after :each do
diff --git a/spec/ruby/core/io/sysread_spec.rb b/spec/ruby/core/io/sysread_spec.rb
index 8851214283..e7f63cefec 100644
--- a/spec/ruby/core/io/sysread_spec.rb
+++ b/spec/ruby/core/io/sysread_spec.rb
@@ -21,25 +21,25 @@ describe "IO#sysread on a file" do
end
it "reads the specified number of bytes from the file to the buffer" do
- buf = +"" # empty buffer
+ buf = "" # empty buffer
@file.sysread(15, buf).should == buf
buf.should == "012345678901234"
@file.rewind
- buf = +"ABCDE" # small buffer
+ buf = "ABCDE" # small buffer
@file.sysread(15, buf).should == buf
buf.should == "012345678901234"
@file.rewind
- buf = +"ABCDE" * 5 # large buffer
+ buf = "ABCDE" * 5 # large buffer
@file.sysread(15, buf).should == buf
buf.should == "012345678901234"
end
it "coerces the second argument to string and uses it as a buffer" do
- buf = +"ABCDE"
+ buf = "ABCDE"
(obj = mock("buff")).should_receive(:to_str).any_number_of_times.and_return(buf)
@file.sysread(15, obj).should == buf
buf.should == "012345678901234"
@@ -90,30 +90,23 @@ describe "IO#sysread on a file" do
end
it "immediately returns the given buffer if the length argument is 0" do
- buffer = +"existing content"
+ buffer = "existing content"
@file.sysread(0, buffer).should == buffer
buffer.should == "existing content"
end
it "discards the existing buffer content upon successful read" do
- buffer = +"existing content"
- @file.sysread(11, buffer).should.equal?(buffer)
+ buffer = "existing content"
+ @file.sysread(11, buffer)
buffer.should == "01234567890"
end
it "discards the existing buffer content upon error" do
- buffer = +"existing content"
+ buffer = "existing content"
@file.seek(0, :END)
-> { @file.sysread(1, buffer) }.should raise_error(EOFError)
buffer.should be_empty
end
-
- it "preserves the encoding of the given buffer" do
- buffer = ''.encode(Encoding::ISO_8859_1)
- string = @file.sysread(10, buffer)
-
- buffer.encoding.should == Encoding::ISO_8859_1
- end
end
describe "IO#sysread" do
diff --git a/spec/ruby/core/io/syswrite_spec.rb b/spec/ruby/core/io/syswrite_spec.rb
index 8bf61a27c3..eeb8d302a7 100644
--- a/spec/ruby/core/io/syswrite_spec.rb
+++ b/spec/ruby/core/io/syswrite_spec.rb
@@ -78,5 +78,4 @@ end
describe "IO#syswrite" do
it_behaves_like :io_write, :syswrite
- it_behaves_like :io_write_no_transcode, :syswrite
end
diff --git a/spec/ruby/core/io/try_convert_spec.rb b/spec/ruby/core/io/try_convert_spec.rb
index a9e99de7aa..5fbd10b6fa 100644
--- a/spec/ruby/core/io/try_convert_spec.rb
+++ b/spec/ruby/core/io/try_convert_spec.rb
@@ -38,7 +38,7 @@ describe "IO.try_convert" do
it "raises a TypeError if the object does not return an IO from #to_io" do
obj = mock("io")
obj.should_receive(:to_io).and_return("io")
- -> { IO.try_convert(obj) }.should raise_error(TypeError, "can't convert MockObject to IO (MockObject#to_io gives String)")
+ -> { IO.try_convert(obj) }.should raise_error(TypeError)
end
it "propagates an exception raised by #to_io" do
diff --git a/spec/ruby/core/io/ungetc_spec.rb b/spec/ruby/core/io/ungetc_spec.rb
index 47a4e99ebf..41a455c836 100644
--- a/spec/ruby/core/io/ungetc_spec.rb
+++ b/spec/ruby/core/io/ungetc_spec.rb
@@ -103,9 +103,19 @@ describe "IO#ungetc" do
-> { @io.sysread(1) }.should raise_error(IOError)
end
- it "raises TypeError if passed nil" do
- @io.getc.should == ?V
- proc{@io.ungetc(nil)}.should raise_error(TypeError)
+ ruby_version_is ""..."3.0" do
+ it "does not affect the stream and returns nil when passed nil" do
+ @io.getc.should == ?V
+ @io.ungetc(nil)
+ @io.getc.should == ?o
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "raises TypeError if passed nil" do
+ @io.getc.should == ?V
+ proc{@io.ungetc(nil)}.should raise_error(TypeError)
+ end
end
it "puts one or more characters back in the stream" do
diff --git a/spec/ruby/core/io/write_nonblock_spec.rb b/spec/ruby/core/io/write_nonblock_spec.rb
index c403c864fd..5532556d8a 100644
--- a/spec/ruby/core/io/write_nonblock_spec.rb
+++ b/spec/ruby/core/io/write_nonblock_spec.rb
@@ -50,7 +50,6 @@ platform_is_not :windows do
describe "IO#write_nonblock" do
it_behaves_like :io_write, :write_nonblock
- it_behaves_like :io_write_no_transcode, :write_nonblock
end
end
diff --git a/spec/ruby/core/io/write_spec.rb b/spec/ruby/core/io/write_spec.rb
index 4a26f8dbaf..bcc0582d9e 100644
--- a/spec/ruby/core/io/write_spec.rb
+++ b/spec/ruby/core/io/write_spec.rb
@@ -24,6 +24,10 @@ describe "IO#write on a file" do
-> { @readonly_file.write("") }.should_not raise_error
end
+ it "returns a length of 0 when writing a blank string" do
+ @file.write('').should == 0
+ end
+
before :each do
@external = Encoding.default_external
@internal = Encoding.default_internal
@@ -36,18 +40,6 @@ describe "IO#write on a file" do
Encoding.default_internal = @internal
end
- it "returns a length of 0 when writing a blank string" do
- @file.write('').should == 0
- end
-
- it "returns a length of 0 when writing blank strings" do
- @file.write('', '', '').should == 0
- end
-
- it "returns a length of 0 when passed no arguments" do
- @file.write().should == 0
- end
-
it "returns the number of bytes written" do
@file.write("hellø").should == 6
end
@@ -62,18 +54,6 @@ describe "IO#write on a file" do
File.binread(@filename).bytes.should == [159]
end
- it "does not modify arguments when passed multiple arguments and external encoding not set" do
- a, b = "a".freeze, "b".freeze
-
- File.open(@filename, "w") do |f|
- f.write(a, b)
- end
-
- File.binread(@filename).bytes.should == [97, 98]
- a.encoding.should == Encoding::UTF_8
- b.encoding.should == Encoding::UTF_8
- end
-
it "uses the encoding from the given option for non-ascii encoding" do
File.open(@filename, "w", encoding: Encoding::UTF_32LE) do |file|
file.write("hi").should == 8
@@ -81,25 +61,8 @@ describe "IO#write on a file" do
File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000"
end
- it "uses the encoding from the given option for non-ascii encoding even if in binary mode" do
- File.open(@filename, "w", encoding: Encoding::UTF_32LE, binmode: true) do |file|
- file.should.binmode?
- file.write("hi").should == 8
- end
- File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000"
-
- File.open(@filename, "wb", encoding: Encoding::UTF_32LE) do |file|
- file.should.binmode?
- file.write("hi").should == 8
- end
- File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000"
- end
-
- it "uses the encoding from the given option for non-ascii encoding when multiple arguments passes" do
- File.open(@filename, "w", encoding: Encoding::UTF_32LE) do |file|
- file.write("h", "i").should == 8
- end
- File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000"
+ it "uses an :open_args option" do
+ IO.write(@filename, 'hi', open_args: ["w", nil, {encoding: Encoding::UTF_32LE}]).should == 8
end
it "raises a invalid byte sequence error if invalid bytes are being written" do
@@ -119,20 +82,6 @@ describe "IO#write on a file" do
res = "H#{ë}ll#{ö}"
File.binread(@filename).should == res.force_encoding(Encoding::BINARY)
end
-
- platform_is_not :windows do
- it "writes binary data if no encoding is given and multiple arguments passed" do
- File.open(@filename, "w") do |file|
- file.write("\x87".b, "Ä…") # 0x87 isn't a valid UTF-8 binary representation of a character
- end
- File.binread(@filename).bytes.should == [0x87, 0xC4, 0x85]
-
- File.open(@filename, "w") do |file|
- file.write("\x61".encode("utf-32le"), "Ä…")
- end
- File.binread(@filename).bytes.should == [0x61, 0x00, 0x00, 0x00, 0xC4, 0x85]
- end
- end
end
describe "IO.write" do
@@ -147,38 +96,10 @@ describe "IO.write" do
File.read(@filename).should == "\0\0hi"
end
- it "requires mode to be specified in :open_args" do
- -> {
- IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true}])
- }.should raise_error(IOError, "not opened for writing")
-
- IO.write(@filename, 'hi', open_args: ["w", {encoding: Encoding::UTF_32LE, binmode: true}]).should == 8
- IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true, mode: "w"}]).should == 8
- end
-
- it "requires mode to be specified in :open_args even if flags option passed" do
- -> {
- IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true, flags: File::CREAT}])
- }.should raise_error(IOError, "not opened for writing")
-
- IO.write(@filename, 'hi', open_args: ["w", {encoding: Encoding::UTF_32LE, binmode: true, flags: File::CREAT}]).should == 8
- IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true, flags: File::CREAT, mode: "w"}]).should == 8
- end
-
it "uses the given encoding and returns the number of bytes written" do
IO.write(@filename, 'hi', mode: "w", encoding: Encoding::UTF_32LE).should == 8
end
- it "raises ArgumentError if encoding is specified in mode parameter and is given as :encoding option" do
- -> {
- IO.write(@filename, 'hi', mode: "w:UTF-16LE:UTF-16BE", encoding: Encoding::UTF_32LE)
- }.should raise_error(ArgumentError, "encoding specified twice")
-
- -> {
- IO.write(@filename, 'hi', mode: "w:UTF-16BE", encoding: Encoding::UTF_32LE)
- }.should raise_error(ArgumentError, "encoding specified twice")
- end
-
it "writes the file with the permissions in the :perm parameter" do
rm_r @filename
IO.write(@filename, 'write :perm spec', mode: "w", perm: 0o755).should == 16
@@ -203,31 +124,16 @@ describe "IO.write" do
rm_r @fifo
end
- # rb_cloexec_open() is currently missing a retry on EINTR.
- # @ioquatix is looking into fixing it. Quarantined until it's done.
- quarantine! do
- it "writes correctly" do
- thr = Thread.new do
- IO.read(@fifo)
- end
- begin
- string = "hi"
- IO.write(@fifo, string).should == string.length
- ensure
- thr.join
- end
+ it "writes correctly" do
+ thr = Thread.new do
+ IO.read(@fifo)
+ end
+ begin
+ string = "hi"
+ IO.write(@fifo, string).should == string.length
+ ensure
+ thr.join
end
- end
- end
-
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19630
- it "warns about deprecation given a path with a pipe" do
- -> {
- -> {
- IO.write("|cat", "xxx")
- }.should output_to_fd("xxx")
- }.should complain(/IO process creation with a leading '\|'/)
end
end
end
@@ -235,7 +141,6 @@ end
describe "IO#write" do
it_behaves_like :io_write, :write
- it_behaves_like :io_write_transcode, :write
it "accepts multiple arguments" do
IO.pipe do |r, w|
@@ -274,23 +179,25 @@ platform_is :windows do
end
end
-describe "IO#write on STDOUT" do
- # https://bugs.ruby-lang.org/issues/14413
- platform_is_not :windows do
- it "raises SignalException SIGPIPE if the stream is closed instead of Errno::EPIPE like other IOs" do
- stderr_file = tmp("stderr")
- begin
- IO.popen([*ruby_exe, "-e", "loop { puts :ok }"], "r", err: stderr_file) do |io|
- io.gets.should == "ok\n"
- io.close
+ruby_version_is "3.0" do
+ describe "IO#write on STDOUT" do
+ # https://bugs.ruby-lang.org/issues/14413
+ platform_is_not :windows do
+ it "raises SignalException SIGPIPE if the stream is closed instead of Errno::EPIPE like other IOs" do
+ stderr_file = tmp("stderr")
+ begin
+ IO.popen([*ruby_exe, "-e", "loop { puts :ok }"], "r", err: stderr_file) do |io|
+ io.gets.should == "ok\n"
+ io.close
+ end
+ status = $?
+ status.should_not.success?
+ status.should.signaled?
+ Signal.signame(status.termsig).should == 'PIPE'
+ File.read(stderr_file).should.empty?
+ ensure
+ rm_r stderr_file
end
- status = $?
- status.should_not.success?
- status.should.signaled?
- Signal.signame(status.termsig).should == 'PIPE'
- File.read(stderr_file).should.empty?
- ensure
- rm_r stderr_file
end
end
end
diff --git a/spec/ruby/core/kernel/Complex_spec.rb b/spec/ruby/core/kernel/Complex_spec.rb
index 346d50ab5e..cc8177fa02 100644
--- a/spec/ruby/core/kernel/Complex_spec.rb
+++ b/spec/ruby/core/kernel/Complex_spec.rb
@@ -269,8 +269,4 @@ describe "Kernel.Complex()" do
end
end
end
-
- it "freezes its result" do
- Complex(1).frozen?.should == true
- end
end
diff --git a/spec/ruby/core/kernel/Float_spec.rb b/spec/ruby/core/kernel/Float_spec.rb
index 0f83cb5824..015bcb33d6 100644
--- a/spec/ruby/core/kernel/Float_spec.rb
+++ b/spec/ruby/core/kernel/Float_spec.rb
@@ -41,7 +41,7 @@ describe :kernel_float, shared: true do
end
it "converts Strings to floats without calling #to_f" do
- string = +"10"
+ string = "10"
string.should_not_receive(:to_f)
@object.send(:Float, string).should == 10.0
end
diff --git a/spec/ruby/core/kernel/Integer_spec.rb b/spec/ruby/core/kernel/Integer_spec.rb
index 74dd3e0dd2..2c78e27428 100644
--- a/spec/ruby/core/kernel/Integer_spec.rb
+++ b/spec/ruby/core/kernel/Integer_spec.rb
@@ -145,7 +145,7 @@ describe :kernel_integer, shared: true do
end
end
-describe :kernel_integer_string, shared: true do
+describe "Integer() given a String", shared: true do
it "raises an ArgumentError if the String is a null byte" do
-> { Integer("\0") }.should raise_error(ArgumentError)
end
@@ -348,7 +348,7 @@ describe :kernel_integer_string, shared: true do
end
end
-describe :kernel_integer_string_base, shared: true do
+describe "Integer() given a String and base", shared: true do
it "raises an ArgumentError if the String is a null byte" do
-> { Integer("\0", 2) }.should raise_error(ArgumentError)
end
@@ -573,31 +573,9 @@ describe :kernel_integer_string_base, shared: true do
-> { Integer("0#{d}1", base) }.should raise_error(ArgumentError)
end
end
- end
-
- it "raises an ArgumentError if a base is given for a non-String value" do
- -> { Integer(98, 15) }.should raise_error(ArgumentError)
- end
-
- it "tries to convert the base to an integer using to_int" do
- obj = mock('8')
- obj.should_receive(:to_int).and_return(8)
-
- Integer("777", obj).should == 0777
- end
-
- # https://bugs.ruby-lang.org/issues/19349
- ruby_version_is ''...'3.3' do
- it "ignores the base if it is not an integer and does not respond to #to_i" do
- Integer("777", "8").should == 777
- end
- end
- ruby_version_is '3.3' do
- it "raises a TypeError if it is not an integer and does not respond to #to_i" do
- -> {
- Integer("777", "8")
- }.should raise_error(TypeError, "no implicit conversion of String into Integer")
+ it "raises an ArgumentError if a base is given for a non-String value" do
+ -> { Integer(98, 15) }.should raise_error(ArgumentError)
end
end
@@ -799,9 +777,9 @@ describe "Kernel.Integer" do
# TODO: fix these specs
it_behaves_like :kernel_integer, :Integer, Kernel
- it_behaves_like :kernel_integer_string, :Integer
+ it_behaves_like "Integer() given a String", :Integer
- it_behaves_like :kernel_integer_string_base, :Integer
+ it_behaves_like "Integer() given a String and base", :Integer
it "is a public method" do
Kernel.Integer(10).should == 10
@@ -813,9 +791,9 @@ describe "Kernel#Integer" do
# TODO: fix these specs
it_behaves_like :kernel_integer, :Integer, Object.new
- it_behaves_like :kernel_integer_string, :Integer
+ it_behaves_like "Integer() given a String", :Integer
- it_behaves_like :kernel_integer_string_base, :Integer
+ it_behaves_like "Integer() given a String and base", :Integer
it "is a private method" do
Kernel.should have_private_instance_method(:Integer)
diff --git a/spec/ruby/core/kernel/String_spec.rb b/spec/ruby/core/kernel/String_spec.rb
index 7caec6eda5..47ee797be5 100644
--- a/spec/ruby/core/kernel/String_spec.rb
+++ b/spec/ruby/core/kernel/String_spec.rb
@@ -78,7 +78,7 @@ describe :kernel_String, shared: true do
end
it "returns the same object if it is already a String" do
- string = +"Hello"
+ string = "Hello"
string.should_not_receive(:to_s)
string2 = @object.send(@method, string)
string.should equal(string2)
diff --git a/spec/ruby/core/kernel/__dir___spec.rb b/spec/ruby/core/kernel/__dir___spec.rb
index 242adbf48b..324792a408 100644
--- a/spec/ruby/core/kernel/__dir___spec.rb
+++ b/spec/ruby/core/kernel/__dir___spec.rb
@@ -19,9 +19,19 @@ describe "Kernel#__dir__" do
end
end
- context "when used in eval with top level binding" do
- it "returns nil" do
- eval("__dir__", binding).should == nil
+ ruby_version_is ""..."3.0" do
+ context "when used in eval with top level binding" do
+ it "returns the real name of the directory containing the currently-executing file" do
+ eval("__dir__", binding).should == File.realpath(File.dirname(__FILE__))
+ end
+ end
+ end
+
+ ruby_version_is "3.0" do
+ context "when used in eval with top level binding" do
+ it "returns nil" do
+ eval("__dir__", binding).should == nil
+ end
end
end
end
diff --git a/spec/ruby/core/kernel/at_exit_spec.rb b/spec/ruby/core/kernel/at_exit_spec.rb
index ebd9a71d15..a784c1ae17 100644
--- a/spec/ruby/core/kernel/at_exit_spec.rb
+++ b/spec/ruby/core/kernel/at_exit_spec.rb
@@ -1,16 +1,67 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative '../../shared/kernel/at_exit'
describe "Kernel.at_exit" do
- it_behaves_like :kernel_at_exit, :at_exit
-
it "is a private method" do
Kernel.should have_private_instance_method(:at_exit)
end
- it "raises ArgumentError if called without a block" do
- -> { at_exit }.should raise_error(ArgumentError, "called without a block")
+ it "runs after all other code" do
+ ruby_exe("at_exit {print 5}; print 6").should == "65"
+ end
+
+ it "runs in reverse order of registration" do
+ code = "at_exit {print 4};at_exit {print 5}; print 6; at_exit {print 7}"
+ ruby_exe(code).should == "6754"
+ end
+
+ it "allows calling exit inside at_exit handler" do
+ code = "at_exit {print 3}; at_exit {print 4; exit; print 5}; at_exit {print 6}"
+ ruby_exe(code).should == "643"
+ end
+
+ it "gives access to the last raised exception" do
+ code = <<-EOC
+ at_exit do
+ puts "The exception matches: \#{$! == $exception} (message=\#{$!.message})"
+ end
+
+ begin
+ raise "foo"
+ rescue => $exception
+ raise
+ end
+ EOC
+
+ result = ruby_exe(code, args: "2>&1", exit_status: 1)
+ result.lines.should.include?("The exception matches: true (message=foo)\n")
+ end
+
+ it "both exceptions in at_exit and in the main script are printed" do
+ code = 'at_exit { raise "at_exit_error" }; raise "main_script_error"'
+ result = ruby_exe(code, args: "2>&1", exit_status: 1)
+ result.should.include?('at_exit_error (RuntimeError)')
+ result.should.include?('main_script_error (RuntimeError)')
+ end
+
+ it "decides the exit status if both at_exit and the main script raise SystemExit" do
+ ruby_exe('at_exit { exit 43 }; exit 42', args: "2>&1", exit_status: 43)
+ $?.exitstatus.should == 43
+ end
+
+ it "runs all at_exit even if some raise exceptions" do
+ code = 'at_exit { STDERR.puts "last" }; at_exit { exit 43 }; at_exit { STDERR.puts "first" }; exit 42'
+ result = ruby_exe(code, args: "2>&1", exit_status: 43)
+ result.should == "first\nlast\n"
+ $?.exitstatus.should == 43
+ end
+
+ it "runs at_exit handlers even if the main script fails to parse" do
+ script = fixture(__FILE__, "at_exit.rb")
+ result = ruby_exe('{', options: "-r#{script}", args: "2>&1", exit_status: 1)
+ $?.should_not.success?
+ result.should.include?("at_exit ran\n")
+ result.should.include?("syntax error")
end
end
diff --git a/spec/ruby/core/kernel/caller_locations_spec.rb b/spec/ruby/core/kernel/caller_locations_spec.rb
index aaacd9a910..5994b28fa3 100644
--- a/spec/ruby/core/kernel/caller_locations_spec.rb
+++ b/spec/ruby/core/kernel/caller_locations_spec.rb
@@ -71,28 +71,14 @@ describe 'Kernel#caller_locations' do
end
guard -> { Kernel.instance_method(:tap).source_location } do
- ruby_version_is ""..."3.4" do
- it "includes core library methods defined in Ruby" do
- file, line = Kernel.instance_method(:tap).source_location
- file.should.start_with?('<internal:')
-
- loc = nil
- tap { loc = caller_locations(1, 1)[0] }
- loc.label.should == "tap"
- loc.path.should.start_with? "<internal:"
- end
- end
-
- ruby_version_is "3.4" do
- it "includes core library methods defined in Ruby" do
- file, line = Kernel.instance_method(:tap).source_location
- file.should.start_with?('<internal:')
-
- loc = nil
- tap { loc = caller_locations(1, 1)[0] }
- loc.label.should == "Kernel#tap"
- loc.path.should.start_with? "<internal:"
- end
+ it "includes core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller_locations(1, 1)[0] }
+ loc.label.should == "tap"
+ loc.path.should.start_with? "<internal:"
end
end
end
diff --git a/spec/ruby/core/kernel/caller_spec.rb b/spec/ruby/core/kernel/caller_spec.rb
index 33c7929a31..f1ff7044b8 100644
--- a/spec/ruby/core/kernel/caller_spec.rb
+++ b/spec/ruby/core/kernel/caller_spec.rb
@@ -38,49 +38,22 @@ describe 'Kernel#caller' do
it "returns an Array with the block given to #at_exit at the base of the stack" do
path = fixture(__FILE__, "caller_at_exit.rb")
lines = ruby_exe(path).lines
- lines.size.should == 2
- lines[0].should =~ /\A#{path}:6:in [`'](?:Object#)?foo'\n\z/
- lines[1].should =~ /\A#{path}:2:in [`']block in <main>'\n\z/
- end
-
- it "can be called with a range" do
- locations1 = caller(0)
- locations2 = caller(2..4)
- locations1[2..4].should == locations2
+ lines.should == [
+ "#{path}:6:in `foo'\n",
+ "#{path}:2:in `block in <main>'\n"
+ ]
end
it "works with endless ranges" do
locations1 = KernelSpecs::CallerTest.locations(0)
locations2 = KernelSpecs::CallerTest.locations(eval("(2..)"))
- locations2.should == locations1[2..-1]
+ locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s)
end
it "works with beginless ranges" do
locations1 = KernelSpecs::CallerTest.locations(0)
locations2 = KernelSpecs::CallerTest.locations((..5))
- locations2[eval("(2..)")].should == locations1[(..5)][eval("(2..)")]
- end
-
- it "can be called with a range whose end is negative" do
- locations1 = caller(0)
- locations2 = caller(2..-1)
- locations3 = caller(2..-2)
- locations1[2..-1].should == locations2
- locations1[2..-2].should == locations3
- end
-
- it "must return nil if omitting more locations than available" do
- caller(100).should == nil
- caller(100..-1).should == nil
- end
-
- it "must return [] if omitting exactly the number of locations available" do
- omit = caller(0).length
- caller(omit).should == []
- end
-
- it "must return the same locations when called with 1..-1 and when called with no arguments" do
- caller.should == caller(1..-1)
+ locations2.map(&:to_s)[eval("(2..)")].should == locations1[(..5)].map(&:to_s)[eval("(2..)")]
end
guard -> { Kernel.instance_method(:tap).source_location } do
@@ -90,7 +63,8 @@ describe 'Kernel#caller' do
loc = nil
tap { loc = caller(1, 1)[0] }
- loc.should =~ /\A<internal:.*in [`'](?:Kernel#)?tap'\z/
+ loc.should.end_with? "in `tap'"
+ loc.should.start_with? "<internal:"
end
end
end
diff --git a/spec/ruby/core/kernel/catch_spec.rb b/spec/ruby/core/kernel/catch_spec.rb
index 9f59d3b384..4060172429 100644
--- a/spec/ruby/core/kernel/catch_spec.rb
+++ b/spec/ruby/core/kernel/catch_spec.rb
@@ -35,7 +35,7 @@ describe "Kernel.catch" do
end
it "raises an ArgumentError if a String with different identity is thrown" do
- -> { catch("exit".dup) { throw "exit".dup } }.should raise_error(ArgumentError)
+ -> { catch("exit") { throw "exit" } }.should raise_error(ArgumentError)
end
it "catches a Symbol when thrown a matching Symbol" do
diff --git a/spec/ruby/core/kernel/class_spec.rb b/spec/ruby/core/kernel/class_spec.rb
index b1d9df1671..2725bde19b 100644
--- a/spec/ruby/core/kernel/class_spec.rb
+++ b/spec/ruby/core/kernel/class_spec.rb
@@ -19,7 +19,7 @@ describe "Kernel#class" do
end
it "returns the first non-singleton class" do
- a = +"hello"
+ a = "hello"
def a.my_singleton_method; end
a.class.should equal(String)
end
diff --git a/spec/ruby/core/kernel/clone_spec.rb b/spec/ruby/core/kernel/clone_spec.rb
index 5adcbbe603..a87c7544fe 100644
--- a/spec/ruby/core/kernel/clone_spec.rb
+++ b/spec/ruby/core/kernel/clone_spec.rb
@@ -45,18 +45,26 @@ describe "Kernel#clone" do
end
describe "with freeze: nil" do
- it "copies frozen state from the original, like #clone without arguments" do
- o2 = @obj.clone(freeze: nil)
- o2.should_not.frozen?
-
- @obj.freeze
- o3 = @obj.clone(freeze: nil)
- o3.should.frozen?
+ ruby_version_is ""..."3.0" do
+ it "raises ArgumentError" do
+ -> { @obj.clone(freeze: nil) }.should raise_error(ArgumentError, /unexpected value for freeze: NilClass/)
+ end
end
- it "copies frozen?" do
- o = "".freeze.clone(freeze: nil)
- o.frozen?.should be_true
+ ruby_version_is "3.0" do
+ it "copies frozen state from the original, like #clone without arguments" do
+ o2 = @obj.clone(freeze: nil)
+ o2.should_not.frozen?
+
+ @obj.freeze
+ o3 = @obj.clone(freeze: nil)
+ o3.should.frozen?
+ end
+
+ it "copies frozen?" do
+ o = "".freeze.clone(freeze: nil)
+ o.frozen?.should be_true
+ end
end
end
@@ -66,19 +74,33 @@ describe "Kernel#clone" do
@obj.clone(freeze: true).should.frozen?
end
- it 'freezes the copy even if the original was not frozen' do
- @obj.clone(freeze: true).should.frozen?
- end
+ ruby_version_is ''...'3.0' do
+ it 'does not freeze the copy even if the original is not frozen' do
+ @obj.clone(freeze: true).should_not.frozen?
+ end
- it "calls #initialize_clone with kwargs freeze: true" do
- obj = KernelSpecs::CloneFreeze.new
- obj.clone(freeze: true)
- ScratchPad.recorded.should == [obj, { freeze: true }]
+ it "calls #initialize_clone with no kwargs" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: true)
+ ScratchPad.recorded.should == [obj, {}]
+ end
end
- it "calls #initialize_clone with kwargs freeze: true even if #initialize_clone only takes a single argument" do
- obj = KernelSpecs::Clone.new
- -> { obj.clone(freeze: true) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ ruby_version_is '3.0' do
+ it 'freezes the copy even if the original was not frozen' do
+ @obj.clone(freeze: true).should.frozen?
+ end
+
+ it "calls #initialize_clone with kwargs freeze: true" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: true)
+ ScratchPad.recorded.should == [obj, { freeze: true }]
+ end
+
+ it "calls #initialize_clone with kwargs freeze: true even if #initialize_clone only takes a single argument" do
+ obj = KernelSpecs::Clone.new
+ -> { obj.clone(freeze: true) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ end
end
end
@@ -92,15 +114,25 @@ describe "Kernel#clone" do
@obj.clone(freeze: false).should_not.frozen?
end
- it "calls #initialize_clone with kwargs freeze: false" do
- obj = KernelSpecs::CloneFreeze.new
- obj.clone(freeze: false)
- ScratchPad.recorded.should == [obj, { freeze: false }]
+ ruby_version_is ''...'3.0' do
+ it "calls #initialize_clone with no kwargs" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: false)
+ ScratchPad.recorded.should == [obj, {}]
+ end
end
- it "calls #initialize_clone with kwargs freeze: false even if #initialize_clone only takes a single argument" do
- obj = KernelSpecs::Clone.new
- -> { obj.clone(freeze: false) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ ruby_version_is '3.0' do
+ it "calls #initialize_clone with kwargs freeze: false" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: false)
+ ScratchPad.recorded.should == [obj, { freeze: false }]
+ end
+
+ it "calls #initialize_clone with kwargs freeze: false even if #initialize_clone only takes a single argument" do
+ obj = KernelSpecs::Clone.new
+ -> { obj.clone(freeze: false) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
+ end
end
end
diff --git a/spec/ruby/core/kernel/define_singleton_method_spec.rb b/spec/ruby/core/kernel/define_singleton_method_spec.rb
index 24acec84f5..2d8b1bf413 100644
--- a/spec/ruby/core/kernel/define_singleton_method_spec.rb
+++ b/spec/ruby/core/kernel/define_singleton_method_spec.rb
@@ -111,10 +111,4 @@ describe "Kernel#define_singleton_method" do
cls.foo.should == :ok
}.should_not raise_error(NoMethodError)
end
-
- it "cannot define a singleton method with a frozen singleton class" do
- o = Object.new
- o.freeze
- -> { o.define_singleton_method(:foo) { 1 } }.should raise_error(FrozenError)
- end
end
diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb
index 454bc4a58e..9be0f2dfd3 100644
--- a/spec/ruby/core/kernel/eval_spec.rb
+++ b/spec/ruby/core/kernel/eval_spec.rb
@@ -135,7 +135,7 @@ describe "Kernel#eval" do
it "includes file and line information in syntax error" do
expected = 'speccing.rb'
-> {
- eval('if true', TOPLEVEL_BINDING, expected)
+ eval('if true',TOPLEVEL_BINDING, expected)
}.should raise_error(SyntaxError) { |e|
e.message.should =~ /#{expected}:1:.+/
}
@@ -144,7 +144,7 @@ describe "Kernel#eval" do
it "evaluates string with given filename and negative linenumber" do
expected_file = 'speccing.rb'
-> {
- eval('if true', TOPLEVEL_BINDING, expected_file, -100)
+ eval('if true',TOPLEVEL_BINDING, expected_file, -100)
}.should raise_error(SyntaxError) { |e|
e.message.should =~ /#{expected_file}:-100:.+/
}
@@ -159,7 +159,24 @@ describe "Kernel#eval" do
end
end
- ruby_version_is ""..."3.3" do
+ ruby_version_is ""..."3.0" do
+ it "uses the filename of the binding if none is provided" do
+ eval("__FILE__").should == "(eval)"
+ suppress_warning {eval("__FILE__", binding)}.should == __FILE__
+ eval("__FILE__", binding, "success").should == "success"
+ suppress_warning {eval("eval '__FILE__', binding")}.should == "(eval)"
+ suppress_warning {eval("eval '__FILE__', binding", binding)}.should == __FILE__
+ suppress_warning {eval("eval '__FILE__', binding", binding, 'success')}.should == 'success'
+ end
+
+ it 'uses the given binding file and line for __FILE__ and __LINE__' do
+ suppress_warning {
+ eval("[__FILE__, __LINE__]", binding).should == [__FILE__, __LINE__]
+ }
+ end
+ end
+
+ ruby_version_is "3.0" do
it "uses (eval) filename if none is provided" do
eval("__FILE__").should == "(eval)"
eval("__FILE__", binding).should == "(eval)"
@@ -175,21 +192,6 @@ describe "Kernel#eval" do
end
end
- ruby_version_is "3.3" do
- it "uses (eval at __FILE__:__LINE__) if none is provided" do
- eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})"
- eval("__FILE__", binding).should == "(eval at #{__FILE__}:#{__LINE__})"
- eval("__FILE__", binding, "success").should == "success"
- eval("eval '__FILE__', binding").should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)"
- eval("eval '__FILE__', binding", binding).should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)"
- eval("eval '__FILE__', binding", binding, 'success').should == "(eval at success:1)"
- eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
- end
-
- it 'uses (eval at __FILE__:__LINE__) for __FILE__ and 1 for __LINE__ with a binding argument' do
- eval("[__FILE__, __LINE__]", binding).should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
- end
- end
# Found via Rubinius bug github:#149
it "does not alter the value of __FILE__ in the binding" do
first_time = EvalSpecs.call_eval
@@ -226,20 +228,6 @@ describe "Kernel#eval" do
-> { eval("return :eval") }.call.should == :eval
end
- it "returns from the method calling #eval when evaluating 'return'" do
- def eval_return(n)
- eval("return n*2")
- end
- -> { eval_return(3) }.call.should == 6
- end
-
- it "returns from the method calling #eval when evaluating 'return' in BEGIN" do
- def eval_return(n)
- eval("BEGIN {return n*3}")
- end
- -> { eval_return(4) }.call.should == 12
- end
-
it "unwinds through a Proc-style closure and returns from a lambda-style closure in the closure chain" do
code = fixture __FILE__, "eval_return_with_lambda.rb"
ruby_exe(code).chomp.should == "a,b,c,eval,f"
@@ -261,19 +249,6 @@ describe "Kernel#eval" do
end
end
- it "makes flip-flop operator work correctly" do
- ScratchPad.record []
-
- eval "10.times { |i| ScratchPad << i if (i == 4)...(i == 4) }"
- ScratchPad.recorded.should == [4, 5, 6, 7, 8, 9]
-
- ScratchPad.clear
- end
-
- it "returns nil if given an empty string" do
- eval("").should == nil
- end
-
# See language/magic_comment_spec.rb for more magic comments specs
describe "with a magic encoding comment" do
it "uses the magic comment encoding for the encoding of literal strings" do
@@ -350,11 +325,12 @@ CODE
end
it "allows a magic encoding comment and a subsequent frozen_string_literal magic comment" do
- frozen_string_default = "test".frozen?
+ # Make sure frozen_string_literal is not default true
+ eval("'foo'".b).frozen?.should be_false
code = <<CODE.b
# encoding: UTF-8
-# frozen_string_literal: #{!frozen_string_default}
+# frozen_string_literal: true
class EvalSpecs
VÏ€string = "frozen"
end
@@ -364,7 +340,7 @@ CODE
EvalSpecs.constants(false).should include(:"VÏ€string")
EvalSpecs::VÏ€string.should == "frozen"
EvalSpecs::VÏ€string.encoding.should == Encoding::UTF_8
- EvalSpecs::VÏ€string.frozen?.should == !frozen_string_default
+ EvalSpecs::VÏ€string.frozen?.should be_true
end
it "allows a magic encoding comment and a frozen_string_literal magic comment on the same line in emacs style" do
@@ -383,9 +359,8 @@ CODE
end
it "ignores the magic encoding comment if it is after a frozen_string_literal magic comment" do
- frozen_string_default = "test".frozen?
code = <<CODE.b
-# frozen_string_literal: #{!frozen_string_default}
+# frozen_string_literal: true
# encoding: UTF-8
class EvalSpecs
VÏ€frozen_first = "frozen"
@@ -399,24 +374,23 @@ CODE
value = EvalSpecs.const_get(binary_constant)
value.should == "frozen"
value.encoding.should == Encoding::BINARY
- value.frozen?.should == !frozen_string_default
+ value.frozen?.should be_true
end
it "ignores the frozen_string_literal magic comment if it appears after a token and warns if $VERBOSE is true" do
- frozen_string_default = "test".frozen?
code = <<CODE
some_token_before_magic_comment = :anything
-# frozen_string_literal: #{!frozen_string_default}
+# frozen_string_literal: true
class EvalSpecs
VÏ€string_not_frozen = "not frozen"
end
CODE
- -> { eval(code) }.should complain(/warning: [`']frozen_string_literal' is ignored after any tokens/, verbose: true)
- EvalSpecs::VÏ€string_not_frozen.frozen?.should == frozen_string_default
+ -> { eval(code) }.should complain(/warning: `frozen_string_literal' is ignored after any tokens/, verbose: true)
+ EvalSpecs::VÏ€string_not_frozen.frozen?.should be_false
EvalSpecs.send :remove_const, :VÏ€string_not_frozen
-> { eval(code) }.should_not complain(verbose: false)
- EvalSpecs::VÏ€string_not_frozen.frozen?.should == frozen_string_default
+ EvalSpecs::VÏ€string_not_frozen.frozen?.should be_false
EvalSpecs.send :remove_const, :VÏ€string_not_frozen
end
end
diff --git a/spec/ruby/core/kernel/exec_spec.rb b/spec/ruby/core/kernel/exec_spec.rb
index 3d9520ad67..1b4a7ae6f4 100644
--- a/spec/ruby/core/kernel/exec_spec.rb
+++ b/spec/ruby/core/kernel/exec_spec.rb
@@ -7,12 +7,12 @@ describe "Kernel#exec" do
end
it "runs the specified command, replacing current process" do
- ruby_exe('exec "echo hello"; puts "fail"').should == "hello\n"
+ ruby_exe('exec "echo hello"; puts "fail"', escape: true).should == "hello\n"
end
end
describe "Kernel.exec" do
it "runs the specified command, replacing current process" do
- ruby_exe('Kernel.exec "echo hello"; puts "fail"').should == "hello\n"
+ ruby_exe('Kernel.exec "echo hello"; puts "fail"', escape: true).should == "hello\n"
end
end
diff --git a/spec/ruby/core/kernel/exit_spec.rb b/spec/ruby/core/kernel/exit_spec.rb
index 93cec3fee5..f168cb375e 100644
--- a/spec/ruby/core/kernel/exit_spec.rb
+++ b/spec/ruby/core/kernel/exit_spec.rb
@@ -10,10 +10,6 @@ describe "Kernel#exit" do
it_behaves_like :process_exit, :exit, KernelSpecs::Method.new
end
-describe "Kernel.exit" do
- it_behaves_like :process_exit, :exit, Kernel
-end
-
describe "Kernel#exit!" do
it "is a private method" do
Kernel.should have_private_instance_method(:exit!)
@@ -22,6 +18,10 @@ describe "Kernel#exit!" do
it_behaves_like :process_exit!, :exit!, "self"
end
+describe "Kernel.exit" do
+ it_behaves_like :process_exit, :exit, Kernel
+end
+
describe "Kernel.exit!" do
- it_behaves_like :process_exit!, :exit!, "Kernel"
+ it_behaves_like :process_exit!, :exit!, Kernel
end
diff --git a/spec/ruby/core/kernel/fixtures/at_exit.rb b/spec/ruby/core/kernel/fixtures/at_exit.rb
new file mode 100644
index 0000000000..9c11a7ad6c
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/at_exit.rb
@@ -0,0 +1,3 @@
+at_exit do
+ STDERR.puts "at_exit ran"
+end
diff --git a/spec/ruby/core/kernel/format_spec.rb b/spec/ruby/core/kernel/format_spec.rb
index 1d0c000c15..e8b031e480 100644
--- a/spec/ruby/core/kernel/format_spec.rb
+++ b/spec/ruby/core/kernel/format_spec.rb
@@ -12,36 +12,4 @@ describe "Kernel.format" do
it "is accessible as a module function" do
Kernel.format("%s", "hello").should == "hello"
end
-
- describe "when $VERBOSE is true" do
- it "warns if too many arguments are passed" do
- code = <<~RUBY
- $VERBOSE = true
- format("test", 1)
- RUBY
-
- ruby_exe(code, args: "2>&1").should include("warning: too many arguments for format string")
- end
-
- it "does not warns if too many keyword arguments are passed" do
- code = <<~RUBY
- $VERBOSE = true
- format("test %{test}", test: 1, unused: 2)
- RUBY
-
- ruby_exe(code, args: "2>&1").should_not include("warning")
- end
-
- ruby_bug "#20593", ""..."3.4" do
- it "doesn't warns if keyword arguments are passed and none are used" do
- code = <<~RUBY
- $VERBOSE = true
- format("test", test: 1)
- format("test", {})
- RUBY
-
- ruby_exe(code, args: "2>&1").should_not include("warning")
- end
- end
- end
end
diff --git a/spec/ruby/core/kernel/initialize_clone_spec.rb b/spec/ruby/core/kernel/initialize_clone_spec.rb
index 21a90c19f0..2d889f5aad 100644
--- a/spec/ruby/core/kernel/initialize_clone_spec.rb
+++ b/spec/ruby/core/kernel/initialize_clone_spec.rb
@@ -18,9 +18,11 @@ describe "Kernel#initialize_clone" do
a.send(:initialize_clone, b)
end
- it "accepts a :freeze keyword argument for obj.clone(freeze: value)" do
- a = Object.new
- b = Object.new
- a.send(:initialize_clone, b, freeze: true).should == a
+ ruby_version_is "3.0" do
+ it "accepts a :freeze keyword argument for obj.clone(freeze: value)" do
+ a = Object.new
+ b = Object.new
+ a.send(:initialize_clone, b, freeze: true).should == a
+ end
end
end
diff --git a/spec/ruby/core/kernel/initialize_copy_spec.rb b/spec/ruby/core/kernel/initialize_copy_spec.rb
index d71ca9f60f..fe08d184ad 100644
--- a/spec/ruby/core/kernel/initialize_copy_spec.rb
+++ b/spec/ruby/core/kernel/initialize_copy_spec.rb
@@ -1,18 +1,11 @@
require_relative '../../spec_helper'
describe "Kernel#initialize_copy" do
- it "returns self" do
- obj = Object.new
- obj.send(:initialize_copy, obj).should.equal?(obj)
- end
-
it "does nothing if the argument is the same as the receiver" do
obj = Object.new
obj.send(:initialize_copy, obj).should.equal?(obj)
-
- obj = Object.new.freeze
+ obj.freeze
obj.send(:initialize_copy, obj).should.equal?(obj)
-
1.send(:initialize_copy, 1).should.equal?(1)
end
diff --git a/spec/ruby/core/kernel/iterator_spec.rb b/spec/ruby/core/kernel/iterator_spec.rb
new file mode 100644
index 0000000000..3fe8317f26
--- /dev/null
+++ b/spec/ruby/core/kernel/iterator_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is ""..."3.0" do
+ describe "Kernel#iterator?" do
+ it "is a private method" do
+ Kernel.should have_private_instance_method(:iterator?)
+ end
+ end
+
+ describe "Kernel.iterator?" do
+ it "needs to be reviewed for spec completeness"
+ end
+end
diff --git a/spec/ruby/core/kernel/lambda_spec.rb b/spec/ruby/core/kernel/lambda_spec.rb
index 565536ac0d..2aa4d4f2fb 100644
--- a/spec/ruby/core/kernel/lambda_spec.rb
+++ b/spec/ruby/core/kernel/lambda_spec.rb
@@ -26,44 +26,42 @@ describe "Kernel.lambda" do
l.lambda?.should be_true
end
- ruby_version_is ""..."3.3" do
- it "creates a lambda-style Proc if given a literal block via Kernel.public_send" do
- suppress_warning do
- l = Kernel.public_send(:lambda) { 42 }
- l.lambda?.should be_true
- end
+ it "creates a lambda-style Proc if given a literal block via Kernel.public_send" do
+ suppress_warning do
+ l = Kernel.public_send(:lambda) { 42 }
+ l.lambda?.should be_true
end
+ end
- it "returns the passed Proc if given an existing Proc" do
- some_proc = proc {}
- l = suppress_warning {lambda(&some_proc)}
- l.should equal(some_proc)
- l.lambda?.should be_false
- end
+ it "returns the passed Proc if given an existing Proc" do
+ some_proc = proc {}
+ l = suppress_warning {lambda(&some_proc)}
+ l.should equal(some_proc)
+ l.lambda?.should be_false
+ end
- it "creates a lambda-style Proc when called with zsuper" do
- suppress_warning do
- l = KernelSpecs::LambdaSpecs::ForwardBlockWithZSuper.new.lambda { 42 }
- l.lambda?.should be_true
- l.call.should == 42
+ it "creates a lambda-style Proc when called with zsuper" do
+ suppress_warning do
+ l = KernelSpecs::LambdaSpecs::ForwardBlockWithZSuper.new.lambda { 42 }
+ l.lambda?.should be_true
+ l.call.should == 42
- lambda { l.call(:extra) }.should raise_error(ArgumentError)
- end
+ lambda { l.call(:extra) }.should raise_error(ArgumentError)
end
+ end
- it "returns the passed Proc if given an existing Proc through super" do
- some_proc = proc { }
- l = KernelSpecs::LambdaSpecs::SuperAmpersand.new.lambda(&some_proc)
- l.should equal(some_proc)
- l.lambda?.should be_false
- end
+ it "returns the passed Proc if given an existing Proc through super" do
+ some_proc = proc { }
+ l = KernelSpecs::LambdaSpecs::SuperAmpersand.new.lambda(&some_proc)
+ l.should equal(some_proc)
+ l.lambda?.should be_false
+ end
- it "does not create lambda-style Procs when captured with #method" do
- kernel_lambda = method(:lambda)
- l = suppress_warning {kernel_lambda.call { 42 }}
- l.lambda?.should be_false
- l.call(:extra).should == 42
- end
+ it "does not create lambda-style Procs when captured with #method" do
+ kernel_lambda = method(:lambda)
+ l = suppress_warning {kernel_lambda.call { 42 }}
+ l.lambda?.should be_false
+ l.call(:extra).should == 42
end
it "checks the arity of the call when no args are specified" do
@@ -138,21 +136,15 @@ describe "Kernel.lambda" do
klass.new.ret.should == 1
end
- context "when called without a literal block" do
- ruby_version_is ""..."3.3" do
+ ruby_version_is "3.0" do
+ context "when called without a literal block" do
it "warns when proc isn't a lambda" do
-> { lambda(&proc{}) }.should complain("#{__FILE__}:#{__LINE__}: warning: lambda without a literal block is deprecated; use the proc without lambda instead\n")
end
- end
- ruby_version_is "3.3" do
- it "raises when proc isn't a lambda" do
- -> { lambda(&proc{}) }.should raise_error(ArgumentError, /the lambda method requires a literal block/)
+ it "doesn't warn when proc is lambda" do
+ -> { lambda(&lambda{}) }.should_not complain(verbose: true)
end
end
-
- it "doesn't warn when proc is lambda" do
- -> { lambda(&lambda{}) }.should_not complain(verbose: true)
- end
end
end
diff --git a/spec/ruby/core/kernel/method_spec.rb b/spec/ruby/core/kernel/method_spec.rb
index 3fc566d6a6..caf2ec948b 100644
--- a/spec/ruby/core/kernel/method_spec.rb
+++ b/spec/ruby/core/kernel/method_spec.rb
@@ -29,7 +29,7 @@ describe "Kernel#method" do
m.call.should == :defined
end
- it "can be called even if we only respond_to_missing? method, true" do
+ it "can be called even if we only repond_to_missing? method, true" do
m = KernelSpecs::RespondViaMissing.new.method(:handled_privately)
m.should be_an_instance_of(Method)
m.call(1, 2, 3).should == "Done handled_privately([1, 2, 3])"
@@ -58,23 +58,4 @@ describe "Kernel#method" do
m = cls.new.method(:bar)
m.call.should == :bar
end
-
- describe "converts the given name to a String using #to_str" do
- it "calls #to_str to convert the given name to a String" do
- name = mock("method-name")
- name.should_receive(:to_str).and_return("hash")
- Object.method(name).should == Object.method(:hash)
- end
-
- it "raises a TypeError if the given name can't be converted to a String" do
- -> { Object.method(nil) }.should raise_error(TypeError)
- -> { Object.method([]) }.should raise_error(TypeError)
- end
-
- it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
- name = mock("method-name")
- name.should_receive(:to_str).and_raise(NoMethodError)
- -> { Object.method(name) }.should raise_error(NoMethodError)
- end
- end
end
diff --git a/spec/ruby/core/kernel/not_match_spec.rb b/spec/ruby/core/kernel/not_match_spec.rb
index f8dd82fad8..906f18df2c 100644
--- a/spec/ruby/core/kernel/not_match_spec.rb
+++ b/spec/ruby/core/kernel/not_match_spec.rb
@@ -14,20 +14,6 @@ describe "Kernel#!~" do
(obj !~ :foo).should == false
end
- ruby_version_is ""..."3.2" do
- it "returns true if self does not respond to #=~" do
- suppress_warning do
- (Object.new !~ :foo).should == true
- end
- end
- end
-
- ruby_version_is "3.2" do
- it "raises NoMethodError if self does not respond to #=~" do
- -> { Object.new !~ :foo }.should raise_error(NoMethodError)
- end
- end
-
it 'can be overridden in subclasses' do
obj = KernelSpecs::NotMatch.new
(obj !~ :bar).should == :foo
diff --git a/spec/ruby/core/kernel/open_spec.rb b/spec/ruby/core/kernel/open_spec.rb
index bb42c31f31..fa9299f9d4 100644
--- a/spec/ruby/core/kernel/open_spec.rb
+++ b/spec/ruby/core/kernel/open_spec.rb
@@ -29,9 +29,7 @@ describe "Kernel#open" do
platform_is_not :windows, :wasi do
it "opens an io when path starts with a pipe" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- @io = open("|date")
- end
+ @io = open("|date")
begin
@io.should be_kind_of(IO)
@io.read
@@ -41,27 +39,21 @@ describe "Kernel#open" do
end
it "opens an io when called with a block" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- @output = open("|date") { |f| f.read }
- end
+ @output = open("|date") { |f| f.read }
@output.should_not == ''
end
it "opens an io for writing" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- -> {
- bytes = open("|cat", "w") { |io| io.write(".") }
- bytes.should == 1
- }.should output_to_fd(".")
- end
+ -> do
+ bytes = open("|cat", "w") { |io| io.write(".") }
+ bytes.should == 1
+ end.should output_to_fd(".")
end
end
platform_is :windows do
it "opens an io when path starts with a pipe" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- @io = open("|date /t")
- end
+ @io = open("|date /t")
begin
@io.should be_kind_of(IO)
@io.read
@@ -71,36 +63,15 @@ describe "Kernel#open" do
end
it "opens an io when called with a block" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- @output = open("|date /t") { |f| f.read }
- end
+ @output = open("|date /t") { |f| f.read }
@output.should_not == ''
end
end
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19630
- it "warns about deprecation given a path with a pipe" do
- cmd = "|echo ok"
- -> {
- open(cmd) { |f| f.read }
- }.should complain(/Kernel#open with a leading '\|'/)
- end
- end
-
it "raises an ArgumentError if not passed one argument" do
-> { open }.should raise_error(ArgumentError)
end
- it "accepts options as keyword arguments" do
- @file = open(@name, "r", 0666, flags: File::CREAT)
- @file.should be_kind_of(File)
-
- -> {
- open(@name, "r", 0666, {flags: File::CREAT})
- }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
- end
-
describe "when given an object that responds to to_open" do
before :each do
ScratchPad.clear
@@ -138,19 +109,9 @@ describe "Kernel#open" do
it "passes its arguments onto #to_open" do
obj = mock('to_open')
- obj.should_receive(:to_open).with(1, 2, 3)
- open(obj, 1, 2, 3)
- end
-
- it "passes keyword arguments onto #to_open as keyword arguments if to_open accepts them" do
- obj = Object.new
- def obj.to_open(*args, **kw)
- ScratchPad << {args: args, kw: kw}
- end
+ obj.should_receive(:to_open).with(1,2,3)
- ScratchPad.record []
- open(obj, 1, 2, 3, a: "b")
- ScratchPad.recorded.should == [args: [1, 2, 3], kw: {a: "b"}]
+ open(obj, 1, 2, 3)
end
it "passes the return value from #to_open to a block" do
@@ -176,14 +137,28 @@ describe "Kernel#open" do
open(@name, nil, nil) { |f| f.gets }.should == @content
end
- it "is not redefined by open-uri" do
- code = <<~RUBY
- before = Kernel.instance_method(:open)
+ ruby_version_is ""..."3.0" do
+ it "works correctly when redefined by open-uri" do
+ code = <<~RUBY
require 'open-uri'
- after = Kernel.instance_method(:open)
- p before == after
- RUBY
- ruby_exe(code, args: "2>&1").should == "true\n"
+ obj = Object.new
+ def obj.to_open; self; end
+ p open(obj) == obj
+ RUBY
+ ruby_exe(code, args: "2>&1").should == "true\n"
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "is not redefined by open-uri" do
+ code = <<~RUBY
+ before = Kernel.instance_method(:open)
+ require 'open-uri'
+ after = Kernel.instance_method(:open)
+ p before == after
+ RUBY
+ ruby_exe(code, args: "2>&1").should == "true\n"
+ end
end
end
diff --git a/spec/ruby/core/kernel/printf_spec.rb b/spec/ruby/core/kernel/printf_spec.rb
index 61bf955c25..d8f93ce429 100644
--- a/spec/ruby/core/kernel/printf_spec.rb
+++ b/spec/ruby/core/kernel/printf_spec.rb
@@ -31,13 +31,6 @@ describe "Kernel.printf" do
object.should_receive(:write).with("string")
Kernel.printf(object, "%s", "string")
end
-
- it "calls #to_str to convert the format object to a String" do
- object = mock('format string')
- object.should_receive(:to_str).and_return("to_str: %i")
- $stdout.should_receive(:write).with("to_str: 42")
- Kernel.printf($stdout, object, 42)
- end
end
describe "Kernel.printf" do
diff --git a/spec/ruby/core/kernel/proc_spec.rb b/spec/ruby/core/kernel/proc_spec.rb
index 6553b8fd04..231c1f0dfb 100644
--- a/spec/ruby/core/kernel/proc_spec.rb
+++ b/spec/ruby/core/kernel/proc_spec.rb
@@ -40,9 +40,19 @@ describe "Kernel#proc" do
proc
end
- it "raises an ArgumentError when passed no block" do
- -> {
- some_method { "hello" }
- }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
+ ruby_version_is ""..."3.0" do
+ it "can be created when called with no block" do
+ -> {
+ some_method { "hello" }
+ }.should complain(/Capturing the given block using Kernel#proc is deprecated/)
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "raises an ArgumentError when passed no block" do
+ -> {
+ some_method { "hello" }
+ }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
+ end
end
end
diff --git a/spec/ruby/core/kernel/public_send_spec.rb b/spec/ruby/core/kernel/public_send_spec.rb
index b684b1729c..4dae419ff9 100644
--- a/spec/ruby/core/kernel/public_send_spec.rb
+++ b/spec/ruby/core/kernel/public_send_spec.rb
@@ -105,11 +105,11 @@ describe "Kernel#public_send" do
end
it "includes `public_send` in the backtrace when passed not enough arguments" do
- -> { public_send() }.should raise_error(ArgumentError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?public_send'/ }
+ -> { public_send() }.should raise_error(ArgumentError) { |e| e.backtrace[0].should.include?("`public_send'") }
end
it "includes `public_send` in the backtrace when passed a single incorrect argument" do
- -> { public_send(Object.new) }.should raise_error(TypeError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?public_send'/ }
+ -> { public_send(Object.new) }.should raise_error(TypeError) { |e| e.backtrace[0].should.include?("`public_send'") }
end
it_behaves_like :basicobject_send, :public_send
diff --git a/spec/ruby/core/kernel/require_relative_spec.rb b/spec/ruby/core/kernel/require_relative_spec.rb
index 6188d13a4e..5999855de6 100644
--- a/spec/ruby/core/kernel/require_relative_spec.rb
+++ b/spec/ruby/core/kernel/require_relative_spec.rb
@@ -5,9 +5,9 @@ describe "Kernel#require_relative with a relative path" do
before :each do
CodeLoadingSpecs.spec_setup
@dir = "../../fixtures/code"
- @abs_dir = File.realpath(@dir, __dir__)
+ @abs_dir = File.realpath(@dir, File.dirname(__FILE__))
@path = "#{@dir}/load_fixture.rb"
- @abs_path = File.realpath(@path, __dir__)
+ @abs_path = File.realpath(@path, File.dirname(__FILE__))
end
after :each do
@@ -92,7 +92,7 @@ describe "Kernel#require_relative with a relative path" do
it "raises a LoadError that includes the missing path" do
missing_path = "#{@dir}/nonexistent.rb"
- expanded_missing_path = File.expand_path(missing_path, __dir__)
+ expanded_missing_path = File.expand_path(missing_path, File.dirname(__FILE__))
-> { require_relative(missing_path) }.should raise_error(LoadError) { |e|
e.message.should include(expanded_missing_path)
e.path.should == expanded_missing_path
@@ -277,7 +277,7 @@ end
describe "Kernel#require_relative with an absolute path" do
before :each do
CodeLoadingSpecs.spec_setup
- @dir = File.expand_path "../../fixtures/code", __dir__
+ @dir = File.expand_path "../../fixtures/code", File.dirname(__FILE__)
@abs_dir = @dir
@path = File.join @dir, "load_fixture.rb"
@abs_path = @path
diff --git a/spec/ruby/core/kernel/require_spec.rb b/spec/ruby/core/kernel/require_spec.rb
index 4029e68725..dc3da4b7e6 100644
--- a/spec/ruby/core/kernel/require_spec.rb
+++ b/spec/ruby/core/kernel/require_spec.rb
@@ -16,26 +16,6 @@ describe "Kernel#require" do
Kernel.should have_private_instance_method(:require)
end
- provided = %w[complex enumerator rational thread ruby2_keywords]
- ruby_version_is "3.1" do
- provided << "fiber"
- end
-
- it "#{provided.join(', ')} are already required" do
- out = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems --disable-did-you-mean')
- features = out.lines.map { |line| File.basename(line.chomp, '.*') }
-
- # Ignore CRuby internals
- features -= %w[encdb transdb windows_1252 windows_31j]
- features.reject! { |feature| feature.end_with?('-fake') }
-
- features.sort.should == provided.sort
-
- code = provided.map { |f| "puts require #{f.inspect}\n" }.join
- required = ruby_exe(code, options: '--disable-gems')
- required.should == "false\n" * provided.size
- end
-
it_behaves_like :kernel_require_basic, :require, CodeLoadingSpecs::Method.new
it_behaves_like :kernel_require, :require, CodeLoadingSpecs::Method.new
end
diff --git a/spec/ruby/core/kernel/shared/load.rb b/spec/ruby/core/kernel/shared/load.rb
index 0fe2d5ce16..5c41c19bf6 100644
--- a/spec/ruby/core/kernel/shared/load.rb
+++ b/spec/ruby/core/kernel/shared/load.rb
@@ -1,6 +1,5 @@
main = self
-# The big difference is Kernel#load does not attempt to add an extension to the passed path, unlike Kernel#require
describe :kernel_load, shared: true do
before :each do
CodeLoadingSpecs.spec_setup
@@ -11,31 +10,22 @@ describe :kernel_load, shared: true do
CodeLoadingSpecs.spec_cleanup
end
- describe "(path resolution)" do
- # This behavior is specific to Kernel#load, it differs for Kernel#require
- it "loads a non-extensioned file as a Ruby source file" do
- path = File.expand_path "load_fixture", CODE_LOADING_DIR
- @object.load(path).should be_true
- ScratchPad.recorded.should == [:no_ext]
- end
-
- it "loads a non .rb extensioned file as a Ruby source file" do
- path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
- @object.load(path).should be_true
- ScratchPad.recorded.should == [:no_rb_ext]
- end
+ it "loads a non-extensioned file as a Ruby source file" do
+ path = File.expand_path "load_fixture", CODE_LOADING_DIR
+ @object.load(path).should be_true
+ ScratchPad.recorded.should == [:no_ext]
+ end
- it "loads from the current working directory" do
- Dir.chdir CODE_LOADING_DIR do
- @object.load("load_fixture.rb").should be_true
- ScratchPad.recorded.should == [:loaded]
- end
- end
+ it "loads a non .rb extensioned file as a Ruby source file" do
+ path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
+ @object.load(path).should be_true
+ ScratchPad.recorded.should == [:no_rb_ext]
+ end
- # This behavior is specific to Kernel#load, it differs for Kernel#require
- it "does not look for a c-extension file when passed a path without extension (when no .rb is present)" do
- path = File.join CODE_LOADING_DIR, "a", "load_fixture"
- -> { @object.send(@method, path) }.should raise_error(LoadError)
+ it "loads from the current working directory" do
+ Dir.chdir CODE_LOADING_DIR do
+ @object.load("load_fixture.rb").should be_true
+ ScratchPad.recorded.should == [:loaded]
end
end
diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb
index 250813191b..ae814aa317 100644
--- a/spec/ruby/core/kernel/shared/require.rb
+++ b/spec/ruby/core/kernel/shared/require.rb
@@ -212,34 +212,6 @@ end
describe :kernel_require, shared: true do
describe "(path resolution)" do
- it "loads .rb file when passed absolute path without extension" do
- path = File.expand_path "load_fixture", CODE_LOADING_DIR
- @object.send(@method, path).should be_true
- # This should _not_ be [:no_ext]
- ScratchPad.recorded.should == [:loaded]
- end
-
- platform_is :linux, :darwin do
- it "loads c-extension file when passed absolute path without extension when no .rb is present" do
- # the error message is specific to what dlerror() returns
- path = File.join CODE_LOADING_DIR, "a", "load_fixture"
- -> { @object.send(@method, path) }.should raise_error(Exception, /file too short|not a mach-o file/)
- end
- end
-
- platform_is :darwin do
- it "loads .bundle file when passed absolute path with .so" do
- # the error message is specific to what dlerror() returns
- path = File.join CODE_LOADING_DIR, "a", "load_fixture.so"
- -> { @object.send(@method, path) }.should raise_error(Exception, /load_fixture\.bundle.+(file too short|not a mach-o file)/)
- end
- end
-
- it "does not try an extra .rb if the path already ends in .rb" do
- path = File.join CODE_LOADING_DIR, "d", "load_fixture.rb"
- -> { @object.send(@method, path) }.should raise_error(LoadError)
- end
-
# For reference see [ruby-core:24155] in which matz confirms this feature is
# intentional for security reasons.
it "does not load a bare filename unless the current working directory is in $LOAD_PATH" do
@@ -290,11 +262,13 @@ describe :kernel_require, shared: true do
ScratchPad.recorded.should == [:loaded]
end
- it "does not load a feature twice when $LOAD_PATH has been modified" do
- $LOAD_PATH.replace [CODE_LOADING_DIR]
- @object.require("load_fixture").should be_true
- $LOAD_PATH.replace [File.expand_path("b", CODE_LOADING_DIR), CODE_LOADING_DIR]
- @object.require("load_fixture").should be_false
+ ruby_bug "#16926", ""..."3.0" do
+ it "does not load a feature twice when $LOAD_PATH has been modified" do
+ $LOAD_PATH.replace [CODE_LOADING_DIR]
+ @object.require("load_fixture").should be_true
+ $LOAD_PATH.replace [File.expand_path("b", CODE_LOADING_DIR), CODE_LOADING_DIR]
+ @object.require("load_fixture").should be_false
+ end
end
end
@@ -583,6 +557,20 @@ describe :kernel_require, shared: true do
ScratchPad.recorded.should == []
end
+ provided = %w[complex enumerator rational thread]
+ provided << 'ruby2_keywords'
+
+ it "#{provided.join(', ')} are already required" do
+ features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
+ provided.each { |feature|
+ features.should =~ /\b#{feature}\.(rb|so|jar)$/
+ }
+
+ code = provided.map { |f| "puts require #{f.inspect}\n" }.join
+ required = ruby_exe(code, options: '--disable-gems')
+ required.should == "false\n" * provided.size
+ end
+
it "unicode_normalize is part of core and not $LOADED_FEATURES" do
features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
features.lines.each { |feature|
@@ -592,21 +580,23 @@ describe :kernel_require, shared: true do
-> { @object.require("unicode_normalize") }.should raise_error(LoadError)
end
- it "does not load a file earlier on the $LOAD_PATH when other similar features were already loaded" do
- Dir.chdir CODE_LOADING_DIR do
- @object.send(@method, "../code/load_fixture").should be_true
- end
- ScratchPad.recorded.should == [:loaded]
+ ruby_version_is "3.0" do
+ it "does not load a file earlier on the $LOAD_PATH when other similar features were already loaded" do
+ Dir.chdir CODE_LOADING_DIR do
+ @object.send(@method, "../code/load_fixture").should be_true
+ end
+ ScratchPad.recorded.should == [:loaded]
- $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/b"
- # This loads because the above load was not on the $LOAD_PATH
- @object.send(@method, "load_fixture").should be_true
- ScratchPad.recorded.should == [:loaded, :loaded]
+ $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/b"
+ # This loads because the above load was not on the $LOAD_PATH
+ @object.send(@method, "load_fixture").should be_true
+ ScratchPad.recorded.should == [:loaded, :loaded]
- $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/c"
- # This does not load because the above load was on the $LOAD_PATH
- @object.send(@method, "load_fixture").should be_false
- ScratchPad.recorded.should == [:loaded, :loaded]
+ $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/c"
+ # This does not load because the above load was on the $LOAD_PATH
+ @object.send(@method, "load_fixture").should be_false
+ ScratchPad.recorded.should == [:loaded, :loaded]
+ end
end
end
diff --git a/spec/ruby/core/kernel/shared/sprintf.rb b/spec/ruby/core/kernel/shared/sprintf.rb
index 13dc6e97f0..2db50bd686 100644
--- a/spec/ruby/core/kernel/shared/sprintf.rb
+++ b/spec/ruby/core/kernel/shared/sprintf.rb
@@ -356,13 +356,13 @@ describe :kernel_sprintf, shared: true do
it "raises TypeError if converting to Integer with to_int returns non-Integer" do
obj = BasicObject.new
- def obj.to_int
+ def obj.to_str
:foo
end
-> {
@method.call("%c", obj)
- }.should raise_error(TypeError, /can't convert BasicObject to Integer/)
+ }.should raise_error(TypeError, /can't convert BasicObject to String/)
end
end
diff --git a/spec/ruby/core/kernel/shared/sprintf_encoding.rb b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
index 7ec0fe4c48..9cedb8b662 100644
--- a/spec/ruby/core/kernel/shared/sprintf_encoding.rb
+++ b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
@@ -14,14 +14,14 @@ describe :kernel_sprintf_encoding, shared: true do
end
it "returns a String in the same encoding as the format String if compatible" do
- string = "%s".dup.force_encoding(Encoding::KOI8_U)
+ string = "%s".force_encoding(Encoding::KOI8_U)
result = @method.call(string, "dogs")
result.encoding.should equal(Encoding::KOI8_U)
end
it "returns a String in the argument's encoding if format encoding is more restrictive" do
- string = "foo %s".dup.force_encoding(Encoding::US_ASCII)
- argument = "b\303\274r".dup.force_encoding(Encoding::UTF_8)
+ string = "foo %s".force_encoding(Encoding::US_ASCII)
+ argument = "b\303\274r".force_encoding(Encoding::UTF_8)
result = @method.call(string, argument)
result.encoding.should equal(Encoding::UTF_8)
@@ -56,7 +56,7 @@ describe :kernel_sprintf_encoding, shared: true do
end
it "uses the encoding of the format string to interpret codepoints" do
- format = "%c".dup.force_encoding("euc-jp")
+ format = "%c".force_encoding("euc-jp")
result = @method.call(format, 9415601)
result.encoding.should == Encoding::EUC_JP
diff --git a/spec/ruby/core/kernel/singleton_class_spec.rb b/spec/ruby/core/kernel/singleton_class_spec.rb
index 23c400f9bd..c56fa08cc1 100644
--- a/spec/ruby/core/kernel/singleton_class_spec.rb
+++ b/spec/ruby/core/kernel/singleton_class_spec.rb
@@ -1,4 +1,3 @@
-# truffleruby_primitives: true
require_relative '../../spec_helper'
describe "Kernel#singleton_class" do
@@ -21,54 +20,10 @@ describe "Kernel#singleton_class" do
end
it "raises TypeError for Integer" do
- -> { 123.singleton_class }.should raise_error(TypeError, "can't define singleton")
- end
-
- it "raises TypeError for Float" do
- -> { 3.14.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { 123.singleton_class }.should raise_error(TypeError)
end
it "raises TypeError for Symbol" do
- -> { :foo.singleton_class }.should raise_error(TypeError, "can't define singleton")
- end
-
- it "raises TypeError for a frozen deduplicated String" do
- -> { (-"string").singleton_class }.should raise_error(TypeError, "can't define singleton")
- -> { a = -"string"; a.singleton_class }.should raise_error(TypeError, "can't define singleton")
- -> { a = "string"; (-a).singleton_class }.should raise_error(TypeError, "can't define singleton")
- end
-
- it "returns a frozen singleton class if object is frozen" do
- obj = Object.new
- obj.freeze
- obj.singleton_class.frozen?.should be_true
- end
-
- context "for an IO object with a replaced singleton class" do
- it "looks up singleton methods from the fresh singleton class after an object instance got a new one" do
- proxy = -> io { io.foo }
- if RUBY_ENGINE == 'truffleruby'
- # We need an inline cache with only this object seen, the best way to do that is to use a Primitive
- sclass = -> io { Primitive.singleton_class(io) }
- else
- sclass = -> io { io.singleton_class }
- end
-
- io = File.new(__FILE__)
- io.define_singleton_method(:foo) { "old" }
- sclass1 = sclass.call(io)
- proxy.call(io).should == "old"
-
- # IO#reopen is the only method which can replace an object's singleton class
- io2 = File.new(__FILE__)
- io.reopen(io2)
- io.define_singleton_method(:foo) { "new" }
- sclass2 = sclass.call(io)
- sclass2.should_not.equal?(sclass1)
- proxy.call(io).should == "new"
- ensure
- io2.close
- io.close
- end
+ -> { :foo.singleton_class }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/kernel/sleep_spec.rb b/spec/ruby/core/kernel/sleep_spec.rb
index d35e313006..32da6344c1 100644
--- a/spec/ruby/core/kernel/sleep_spec.rb
+++ b/spec/ruby/core/kernel/sleep_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Kernel#sleep" do
it "is a private method" do
@@ -21,7 +22,7 @@ describe "Kernel#sleep" do
sleep(Rational(1, 999)).should >= 0
end
- it "accepts any Object that responds to divmod" do
+ it "accepts any Object that reponds to divmod" do
o = Object.new
def o.divmod(*); [0, 0.001]; end
sleep(o).should >= 0
@@ -32,6 +33,10 @@ describe "Kernel#sleep" do
-> { sleep(-1) }.should raise_error(ArgumentError)
end
+ it "raises a TypeError when passed nil" do
+ -> { sleep(nil) }.should raise_error(TypeError)
+ end
+
it "raises a TypeError when passed a String" do
-> { sleep('2') }.should raise_error(TypeError)
end
@@ -50,29 +55,6 @@ describe "Kernel#sleep" do
t.wakeup
t.value.should == 5
end
-
- ruby_version_is ""..."3.3" do
- it "raises a TypeError when passed nil" do
- -> { sleep(nil) }.should raise_error(TypeError)
- end
- end
-
- ruby_version_is "3.3" do
- it "accepts a nil duration" do
- running = false
- t = Thread.new do
- running = true
- sleep(nil)
- 5
- end
-
- Thread.pass until running
- Thread.pass while t.status and t.status != "sleep"
-
- t.wakeup
- t.value.should == 5
- end
- end
end
describe "Kernel.sleep" do
diff --git a/spec/ruby/core/kernel/sprintf_spec.rb b/spec/ruby/core/kernel/sprintf_spec.rb
index 9ef7f86f16..7adf71be76 100644
--- a/spec/ruby/core/kernel/sprintf_spec.rb
+++ b/spec/ruby/core/kernel/sprintf_spec.rb
@@ -3,14 +3,6 @@ require_relative 'fixtures/classes'
require_relative 'shared/sprintf'
require_relative 'shared/sprintf_encoding'
-describe :kernel_sprintf_to_str, shared: true do
- it "calls #to_str to convert the format object to a String" do
- obj = mock('format string')
- obj.should_receive(:to_str).and_return("to_str: %i")
- @method.call(obj, 42).should == "to_str: 42"
- end
-end
-
describe "Kernel#sprintf" do
it_behaves_like :kernel_sprintf, -> format, *args {
sprintf(format, *args)
@@ -19,10 +11,6 @@ describe "Kernel#sprintf" do
it_behaves_like :kernel_sprintf_encoding, -> format, *args {
sprintf(format, *args)
}
-
- it_behaves_like :kernel_sprintf_to_str, -> format, *args {
- sprintf(format, *args)
- }
end
describe "Kernel.sprintf" do
@@ -33,8 +21,4 @@ describe "Kernel.sprintf" do
it_behaves_like :kernel_sprintf_encoding, -> format, *args {
Kernel.sprintf(format, *args)
}
-
- it_behaves_like :kernel_sprintf_to_str, -> format, *args {
- Kernel.sprintf(format, *args)
- }
end
diff --git a/spec/ruby/core/kernel/system_spec.rb b/spec/ruby/core/kernel/system_spec.rb
index 9bc03924dd..9671a650cc 100644
--- a/spec/ruby/core/kernel/system_spec.rb
+++ b/spec/ruby/core/kernel/system_spec.rb
@@ -64,23 +64,6 @@ describe :kernel_system, shared: true do
end
end
- platform_is_not :windows do
- before :each do
- require 'tmpdir'
- @shell_command = File.join(Dir.mktmpdir, "noshebang.cmd")
- File.write(@shell_command, %[echo "$PATH"\n], perm: 0o700)
- end
-
- after :each do
- File.unlink(@shell_command)
- Dir.rmdir(File.dirname(@shell_command))
- end
-
- it "executes with `sh` if the command is executable but not binary and there is no shebang" do
- -> { @object.system(@shell_command) }.should output_to_fd(ENV['PATH'] + "\n")
- end
- end
-
before :each do
ENV['TEST_SH_EXPANSION'] = 'foo'
@shell_var = '$TEST_SH_EXPANSION'
diff --git a/spec/ruby/core/kernel/taint_spec.rb b/spec/ruby/core/kernel/taint_spec.rb
index 0c16b1dbbf..9a58bb5f04 100644
--- a/spec/ruby/core/kernel/taint_spec.rb
+++ b/spec/ruby/core/kernel/taint_spec.rb
@@ -2,13 +2,11 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#taint" do
- ruby_version_is ""..."3.2" do
+ ruby_version_is ""..."3.0" do
it "is a no-op" do
- suppress_warning do
- o = Object.new
- o.taint
- o.should_not.tainted?
- end
+ o = Object.new
+ o.taint
+ o.should_not.tainted?
end
it "warns in verbose mode" do
@@ -18,10 +16,4 @@ describe "Kernel#taint" do
}.should complain(/Object#taint is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:taint)
- end
- end
end
diff --git a/spec/ruby/core/kernel/tainted_spec.rb b/spec/ruby/core/kernel/tainted_spec.rb
index fcae433069..7511c730c9 100644
--- a/spec/ruby/core/kernel/tainted_spec.rb
+++ b/spec/ruby/core/kernel/tainted_spec.rb
@@ -2,15 +2,13 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#tainted?" do
- ruby_version_is ""..."3.2" do
+ ruby_version_is ""..."3.0" do
it "is a no-op" do
- suppress_warning do
- o = mock('o')
- p = mock('p')
- p.taint
- o.should_not.tainted?
- p.should_not.tainted?
- end
+ o = mock('o')
+ p = mock('p')
+ p.taint
+ o.should_not.tainted?
+ p.should_not.tainted?
end
it "warns in verbose mode" do
@@ -20,10 +18,4 @@ describe "Kernel#tainted?" do
}.should complain(/Object#tainted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:tainted?)
- end
- end
end
diff --git a/spec/ruby/core/kernel/test_spec.rb b/spec/ruby/core/kernel/test_spec.rb
index d26dc06361..abb365aed2 100644
--- a/spec/ruby/core/kernel/test_spec.rb
+++ b/spec/ruby/core/kernel/test_spec.rb
@@ -3,8 +3,8 @@ require_relative 'fixtures/classes'
describe "Kernel#test" do
before :all do
- @file = __dir__ + '/fixtures/classes.rb'
- @dir = __dir__ + '/fixtures'
+ @file = File.dirname(__FILE__) + '/fixtures/classes.rb'
+ @dir = File.dirname(__FILE__) + '/fixtures'
end
it "is a private method" do
diff --git a/spec/ruby/core/kernel/trust_spec.rb b/spec/ruby/core/kernel/trust_spec.rb
index db6f17e0fb..4665036da6 100644
--- a/spec/ruby/core/kernel/trust_spec.rb
+++ b/spec/ruby/core/kernel/trust_spec.rb
@@ -2,14 +2,12 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#trust" do
- ruby_version_is ""..."3.2" do
+ ruby_version_is ""..."3.0" do
it "is a no-op" do
- suppress_warning do
- o = Object.new.untrust
- o.should_not.untrusted?
- o.trust
- o.should_not.untrusted?
- end
+ o = Object.new.untrust
+ o.should_not.untrusted?
+ o.trust
+ o.should_not.untrusted?
end
it "warns in verbose mode" do
@@ -19,10 +17,4 @@ describe "Kernel#trust" do
}.should complain(/Object#trust is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:trust)
- end
- end
end
diff --git a/spec/ruby/core/kernel/untaint_spec.rb b/spec/ruby/core/kernel/untaint_spec.rb
index 26b2aabbe9..42fe8a4239 100644
--- a/spec/ruby/core/kernel/untaint_spec.rb
+++ b/spec/ruby/core/kernel/untaint_spec.rb
@@ -2,14 +2,12 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untaint" do
- ruby_version_is ""..."3.2" do
+ ruby_version_is ""..."3.0" do
it "is a no-op" do
- suppress_warning do
- o = Object.new.taint
- o.should_not.tainted?
- o.untaint
- o.should_not.tainted?
- end
+ o = Object.new.taint
+ o.should_not.tainted?
+ o.untaint
+ o.should_not.tainted?
end
it "warns in verbose mode" do
@@ -19,10 +17,4 @@ describe "Kernel#untaint" do
}.should complain(/Object#untaint is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:untaint)
- end
- end
end
diff --git a/spec/ruby/core/kernel/untrust_spec.rb b/spec/ruby/core/kernel/untrust_spec.rb
index 5310cd8eb4..ba0e073cf0 100644
--- a/spec/ruby/core/kernel/untrust_spec.rb
+++ b/spec/ruby/core/kernel/untrust_spec.rb
@@ -2,13 +2,11 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untrust" do
- ruby_version_is ""..."3.2" do
+ ruby_version_is ""..."3.0" do
it "is a no-op" do
- suppress_warning do
- o = Object.new
- o.untrust
- o.should_not.untrusted?
- end
+ o = Object.new
+ o.untrust
+ o.should_not.untrusted?
end
it "warns in verbose mode" do
@@ -18,10 +16,4 @@ describe "Kernel#untrust" do
}.should complain(/Object#untrust is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:untrust)
- end
- end
end
diff --git a/spec/ruby/core/kernel/untrusted_spec.rb b/spec/ruby/core/kernel/untrusted_spec.rb
index ea36d6c98c..517bd4711b 100644
--- a/spec/ruby/core/kernel/untrusted_spec.rb
+++ b/spec/ruby/core/kernel/untrusted_spec.rb
@@ -2,14 +2,12 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untrusted?" do
- ruby_version_is ""..."3.2" do
+ ruby_version_is ""..."3.0" do
it "is a no-op" do
- suppress_warning do
- o = mock('o')
- o.should_not.untrusted?
- o.untrust
- o.should_not.untrusted?
- end
+ o = mock('o')
+ o.should_not.untrusted?
+ o.untrust
+ o.should_not.untrusted?
end
it "warns in verbose mode" do
@@ -19,10 +17,4 @@ describe "Kernel#untrusted?" do
}.should complain(/Object#untrusted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:untrusted?)
- end
- end
end
diff --git a/spec/ruby/core/kernel/warn_spec.rb b/spec/ruby/core/kernel/warn_spec.rb
index 00164ad90b..7df6fa72d1 100644
--- a/spec/ruby/core/kernel/warn_spec.rb
+++ b/spec/ruby/core/kernel/warn_spec.rb
@@ -128,34 +128,36 @@ describe "Kernel#warn" do
end
end
- it "accepts :category keyword with a symbol" do
- -> {
- $VERBOSE = true
- warn("message", category: :deprecated)
- }.should output(nil, "message\n")
- end
+ ruby_version_is "3.0" do
+ it "accepts :category keyword with a symbol" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: :deprecated)
+ }.should output(nil, "message\n")
+ end
- it "accepts :category keyword with nil" do
- -> {
- $VERBOSE = true
- warn("message", category: nil)
- }.should output(nil, "message\n")
- end
+ it "accepts :category keyword with nil" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: nil)
+ }.should output(nil, "message\n")
+ end
- it "accepts :category keyword with object convertible to symbol" do
- o = Object.new
- def o.to_sym; :deprecated; end
- -> {
- $VERBOSE = true
- warn("message", category: o)
- }.should output(nil, "message\n")
- end
+ it "accepts :category keyword with object convertible to symbol" do
+ o = Object.new
+ def o.to_sym; :deprecated; end
+ -> {
+ $VERBOSE = true
+ warn("message", category: o)
+ }.should output(nil, "message\n")
+ end
- it "raises if :category keyword is not nil and not convertible to symbol" do
- -> {
- $VERBOSE = true
- warn("message", category: Object.new)
- }.should raise_error(TypeError)
+ it "raises if :category keyword is not nil and not convertible to symbol" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: Object.new)
+ }.should raise_error(TypeError)
+ end
end
it "converts first arg using to_s" do
@@ -210,52 +212,67 @@ describe "Kernel#warn" do
-> { warn('foo', **h) }.should complain("foo\n")
end
- it "calls Warning.warn without keyword arguments if Warning.warn does not accept keyword arguments" do
- verbose = $VERBOSE
- $VERBOSE = false
- class << Warning
- alias_method :_warn, :warn
- def warn(message)
- ScratchPad.record(message)
+ ruby_version_is '3.0' do
+ it "calls Warning.warn without keyword arguments if Warning.warn does not accept keyword arguments" do
+ verbose = $VERBOSE
+ $VERBOSE = false
+ class << Warning
+ alias_method :_warn, :warn
+ def warn(message)
+ ScratchPad.record(message)
+ end
end
- end
- begin
- ScratchPad.clear
- Kernel.warn("Chunky bacon!")
- ScratchPad.recorded.should == "Chunky bacon!\n"
+ begin
+ ScratchPad.clear
+ Kernel.warn("Chunky bacon!")
+ ScratchPad.recorded.should == "Chunky bacon!\n"
+
+ Kernel.warn("Deprecated bacon!", category: :deprecated)
+ ScratchPad.recorded.should == "Deprecated bacon!\n"
+ ensure
+ class << Warning
+ remove_method :warn
+ alias_method :warn, :_warn
+ remove_method :_warn
+ end
+ $VERBOSE = verbose
+ end
+ end
- Kernel.warn("Deprecated bacon!", category: :deprecated)
- ScratchPad.recorded.should == "Deprecated bacon!\n"
- ensure
- class << Warning
- remove_method :warn
- alias_method :warn, :_warn
- remove_method :_warn
+ it "calls Warning.warn with category: nil if Warning.warn accepts keyword arguments" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!")
+ ensure
+ $VERBOSE = verbose
end
- $VERBOSE = verbose
end
- end
- it "calls Warning.warn with category: nil if Warning.warn accepts keyword arguments" do
- Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
- verbose = $VERBOSE
- $VERBOSE = false
- begin
- Kernel.warn("Chunky bacon!")
- ensure
- $VERBOSE = verbose
+ it "calls Warning.warn with given category keyword converted to a symbol" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!", category: 'deprecated')
+ ensure
+ $VERBOSE = verbose
+ end
end
end
- it "calls Warning.warn with given category keyword converted to a symbol" do
- Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated)
- verbose = $VERBOSE
- $VERBOSE = false
- begin
- Kernel.warn("Chunky bacon!", category: 'deprecated')
- ensure
- $VERBOSE = verbose
+ ruby_version_is ''...'3.0' do
+ it "calls Warning.warn with no keyword arguments" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n")
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!")
+ ensure
+ $VERBOSE = verbose
+ end
end
end
diff --git a/spec/ruby/core/main/private_spec.rb b/spec/ruby/core/main/private_spec.rb
index e8c1f3f44c..cac0645b40 100644
--- a/spec/ruby/core/main/private_spec.rb
+++ b/spec/ruby/core/main/private_spec.rb
@@ -22,11 +22,13 @@ describe "main#private" do
end
end
- context "when single argument is passed and is an array" do
- it "sets the visibility of the given methods to private" do
- eval "private [:main_public_method, :main_public_method2]", TOPLEVEL_BINDING
- Object.should have_private_method(:main_public_method)
- Object.should have_private_method(:main_public_method2)
+ ruby_version_is "3.0" do
+ context "when single argument is passed and is an array" do
+ it "sets the visibility of the given methods to private" do
+ eval "private [:main_public_method, :main_public_method2]", TOPLEVEL_BINDING
+ Object.should have_private_method(:main_public_method)
+ Object.should have_private_method(:main_public_method2)
+ end
end
end
diff --git a/spec/ruby/core/main/public_spec.rb b/spec/ruby/core/main/public_spec.rb
index 31baad4583..91f045dbab 100644
--- a/spec/ruby/core/main/public_spec.rb
+++ b/spec/ruby/core/main/public_spec.rb
@@ -22,11 +22,13 @@ describe "main#public" do
end
end
- context "when single argument is passed and is an array" do
- it "sets the visibility of the given methods to public" do
- eval "public [:main_private_method, :main_private_method2]", TOPLEVEL_BINDING
- Object.should_not have_private_method(:main_private_method)
- Object.should_not have_private_method(:main_private_method2)
+ ruby_version_is "3.0" do
+ context "when single argument is passed and is an array" do
+ it "sets the visibility of the given methods to public" do
+ eval "public [:main_private_method, :main_private_method2]", TOPLEVEL_BINDING
+ Object.should_not have_private_method(:main_private_method)
+ Object.should_not have_private_method(:main_private_method2)
+ end
end
end
diff --git a/spec/ruby/core/marshal/dump_spec.rb b/spec/ruby/core/marshal/dump_spec.rb
index adabfdf025..879ea287ce 100644
--- a/spec/ruby/core/marshal/dump_spec.rb
+++ b/spec/ruby/core/marshal/dump_spec.rb
@@ -38,7 +38,7 @@ describe "Marshal.dump" do
].should be_computed_by(:dump)
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
it "dumps a positive Fixnum > 31 bits as a Bignum" do
Marshal.dump(2**31 + 1).should == "\x04\bl+\a\x01\x00\x00\x80"
end
@@ -76,7 +76,7 @@ describe "Marshal.dump" do
end
it "dumps a binary encoded Symbol" do
- s = "\u2192".dup.force_encoding("binary").to_sym
+ s = "\u2192".force_encoding("binary").to_sym
Marshal.dump(s).should == "\x04\b:\b\xE2\x86\x92"
end
@@ -85,8 +85,8 @@ describe "Marshal.dump" do
symbol1 = "I:\t\xE2\x82\xACa\x06:\x06ET"
symbol2 = "I:\t\xE2\x82\xACb\x06;\x06T"
value = [
- "€a".dup.force_encoding(Encoding::UTF_8).to_sym,
- "€b".dup.force_encoding(Encoding::UTF_8).to_sym
+ "€a".force_encoding(Encoding::UTF_8).to_sym,
+ "€b".force_encoding(Encoding::UTF_8).to_sym
]
Marshal.dump(value).should == "\x04\b[\a#{symbol1}#{symbol2}"
@@ -104,42 +104,19 @@ describe "Marshal.dump" do
UserMarshal.should_not_receive(:name)
Marshal.dump(UserMarshal.new)
end
-
- it "raises TypeError if an Object is an instance of an anonymous class" do
- -> { Marshal.dump(Class.new(UserMarshal).new) }.should raise_error(TypeError, /can't dump anonymous class/)
- end
end
describe "with an object responding to #_dump" do
- it "dumps the String returned by #_dump" do
+ it "dumps the object returned by #_dump" do
Marshal.dump(UserDefined.new).should == "\004\bu:\020UserDefined\022\004\b[\a:\nstuff;\000"
end
- it "dumps the String in non US-ASCII and non UTF-8 encoding" do
- object = UserDefinedString.new("a".encode("windows-1251"))
- Marshal.dump(object).should == "\x04\bIu:\x16UserDefinedString\x06a\x06:\rencoding\"\x11Windows-1251"
- end
-
- it "dumps the String in multibyte encoding" do
- object = UserDefinedString.new("a".encode("utf-32le"))
- Marshal.dump(object).should == "\x04\bIu:\x16UserDefinedString\ta\x00\x00\x00\x06:\rencoding\"\rUTF-32LE"
- end
-
- it "ignores overridden name method" do
- obj = MarshalSpec::UserDefinedWithOverriddenName.new
- Marshal.dump(obj).should == "\x04\bu:/MarshalSpec::UserDefinedWithOverriddenName\x12\x04\b[\a:\nstuff;\x00"
- end
-
it "raises a TypeError if _dump returns a non-string" do
m = mock("marshaled")
m.should_receive(:_dump).and_return(0)
-> { Marshal.dump(m) }.should raise_error(TypeError)
end
- it "raises TypeError if an Object is an instance of an anonymous class" do
- -> { Marshal.dump(Class.new(UserDefined).new) }.should raise_error(TypeError, /can't dump anonymous class/)
- end
-
it "favors marshal_dump over _dump" do
m = mock("marshaled")
m.should_receive(:marshal_dump).and_return(0)
@@ -150,7 +127,7 @@ describe "Marshal.dump" do
it "indexes instance variables of a String returned by #_dump at first and then indexes the object itself" do
class MarshalSpec::M1::A
def _dump(level)
- s = +"<dump>"
+ s = "<dump>"
s.instance_variable_set(:@foo, "bar")
s
end
@@ -189,17 +166,8 @@ describe "Marshal.dump" do
Marshal.dump(UserDefined::Nested).should == "\004\bc\030UserDefined::Nested"
end
- it "ignores overridden name method" do
- Marshal.dump(MarshalSpec::ClassWithOverriddenName).should == "\x04\bc)MarshalSpec::ClassWithOverriddenName"
- end
-
- it "dumps a class with multibyte characters in name" do
- source_object = eval("MarshalSpec::Multibyteãã‚ãƒã„Class".dup.force_encoding(Encoding::UTF_8))
- Marshal.dump(source_object).should == "\x04\bc,MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Class"
- end
-
it "raises TypeError with an anonymous Class" do
- -> { Marshal.dump(Class.new) }.should raise_error(TypeError, /can't dump anonymous class/)
+ -> { Marshal.dump(Class.new) }.should raise_error(TypeError)
end
it "raises TypeError with a singleton Class" do
@@ -212,17 +180,8 @@ describe "Marshal.dump" do
Marshal.dump(Marshal).should == "\004\bm\fMarshal"
end
- it "ignores overridden name method" do
- Marshal.dump(MarshalSpec::ModuleWithOverriddenName).should == "\x04\bc*MarshalSpec::ModuleWithOverriddenName"
- end
-
- it "dumps a module with multibyte characters in name" do
- source_object = eval("MarshalSpec::Multibyteã‘ã’ã“ã”Module".dup.force_encoding(Encoding::UTF_8))
- Marshal.dump(source_object).should == "\x04\bm-MarshalSpec::Multibyte\xE3\x81\x91\xE3\x81\x92\xE3\x81\x93\xE3\x81\x94Module"
- end
-
it "raises TypeError with an anonymous Module" do
- -> { Marshal.dump(Module.new) }.should raise_error(TypeError, /can't dump anonymous module/)
+ -> { Marshal.dump(Module.new) }.should raise_error(TypeError)
end
end
@@ -271,25 +230,13 @@ describe "Marshal.dump" do
end
end
- describe "with a Rational" do
- it "dumps a Rational" do
- Marshal.dump(Rational(2, 3)).should == "\x04\bU:\rRational[\ai\ai\b"
- end
- end
-
- describe "with a Complex" do
- it "dumps a Complex" do
- Marshal.dump(Complex(2, 3)).should == "\x04\bU:\fComplex[\ai\ai\b"
- end
- end
-
describe "with a String" do
it "dumps a blank String" do
- Marshal.dump("".dup.force_encoding("binary")).should == "\004\b\"\000"
+ Marshal.dump("".force_encoding("binary")).should == "\004\b\"\000"
end
it "dumps a short String" do
- Marshal.dump("short".dup.force_encoding("binary")).should == "\004\b\"\012short"
+ Marshal.dump("short".force_encoding("binary")).should == "\004\b\"\012short"
end
it "dumps a long String" do
@@ -297,7 +244,7 @@ describe "Marshal.dump" do
end
it "dumps a String extended with a Module" do
- Marshal.dump("".dup.extend(Meths).force_encoding("binary")).should == "\004\be:\nMeths\"\000"
+ Marshal.dump("".extend(Meths).force_encoding("binary")).should == "\004\be:\nMeths\"\000"
end
it "dumps a String subclass" do
@@ -308,29 +255,24 @@ describe "Marshal.dump" do
Marshal.dump(UserString.new.extend(Meths).force_encoding("binary")).should == "\004\be:\nMethsC:\017UserString\"\000"
end
- it "ignores overridden name method when dumps a String subclass" do
- obj = MarshalSpec::StringWithOverriddenName.new
- Marshal.dump(obj).should == "\x04\bC:*MarshalSpec::StringWithOverriddenName\"\x00"
- end
-
it "dumps a String with instance variables" do
- str = +""
+ str = ""
str.instance_variable_set("@foo", "bar")
Marshal.dump(str.force_encoding("binary")).should == "\x04\bI\"\x00\x06:\t@foo\"\bbar"
end
it "dumps a US-ASCII String" do
- str = "abc".dup.force_encoding("us-ascii")
+ str = "abc".force_encoding("us-ascii")
Marshal.dump(str).should == "\x04\bI\"\babc\x06:\x06EF"
end
it "dumps a UTF-8 String" do
- str = "\x6d\xc3\xb6\x68\x72\x65".dup.force_encoding("utf-8")
+ str = "\x6d\xc3\xb6\x68\x72\x65".force_encoding("utf-8")
Marshal.dump(str).should == "\x04\bI\"\vm\xC3\xB6hre\x06:\x06ET"
end
it "dumps a String in another encoding" do
- str = "\x6d\x00\xf6\x00\x68\x00\x72\x00\x65\x00".dup.force_encoding("utf-16le")
+ str = "\x6d\x00\xf6\x00\x68\x00\x72\x00\x65\x00".force_encoding("utf-16le")
result = "\x04\bI\"\x0Fm\x00\xF6\x00h\x00r\x00e\x00\x06:\rencoding\"\rUTF-16LE"
Marshal.dump(str).should == result
end
@@ -364,46 +306,18 @@ describe "Marshal.dump" do
end
it "dumps a binary Regexp" do
- o = Regexp.new("".dup.force_encoding("binary"), Regexp::FIXEDENCODING)
+ o = Regexp.new("".force_encoding("binary"), Regexp::FIXEDENCODING)
Marshal.dump(o).should == "\x04\b/\x00\x10"
end
- it "dumps an ascii-compatible Regexp" do
- o = Regexp.new("a".encode("us-ascii"), Regexp::FIXEDENCODING)
- Marshal.dump(o).should == "\x04\bI/\x06a\x10\x06:\x06EF"
-
- o = Regexp.new("a".encode("us-ascii"))
- Marshal.dump(o).should == "\x04\bI/\x06a\x00\x06:\x06EF"
-
- o = Regexp.new("a".encode("windows-1251"), Regexp::FIXEDENCODING)
- Marshal.dump(o).should == "\x04\bI/\x06a\x10\x06:\rencoding\"\x11Windows-1251"
-
- o = Regexp.new("a".encode("windows-1251"))
- Marshal.dump(o).should == "\x04\bI/\x06a\x00\x06:\x06EF"
- end
-
it "dumps a UTF-8 Regexp" do
- o = Regexp.new("".dup.force_encoding("utf-8"), Regexp::FIXEDENCODING)
+ o = Regexp.new("".force_encoding("utf-8"), Regexp::FIXEDENCODING)
Marshal.dump(o).should == "\x04\bI/\x00\x10\x06:\x06ET"
-
- o = Regexp.new("a".dup.force_encoding("utf-8"), Regexp::FIXEDENCODING)
- Marshal.dump(o).should == "\x04\bI/\x06a\x10\x06:\x06ET"
-
- o = Regexp.new("\u3042".dup.force_encoding("utf-8"), Regexp::FIXEDENCODING)
- Marshal.dump(o).should == "\x04\bI/\b\xE3\x81\x82\x10\x06:\x06ET"
end
it "dumps a Regexp in another encoding" do
- o = Regexp.new("".dup.force_encoding("utf-16le"), Regexp::FIXEDENCODING)
+ o = Regexp.new("".force_encoding("utf-16le"), Regexp::FIXEDENCODING)
Marshal.dump(o).should == "\x04\bI/\x00\x10\x06:\rencoding\"\rUTF-16LE"
-
- o = Regexp.new("a".encode("utf-16le"), Regexp::FIXEDENCODING)
- Marshal.dump(o).should == "\x04\bI/\aa\x00\x10\x06:\rencoding\"\rUTF-16LE"
- end
-
- it "ignores overridden name method when dumps a Regexp subclass" do
- obj = MarshalSpec::RegexpWithOverriddenName.new("")
- Marshal.dump(obj).should == "\x04\bIC:*MarshalSpec::RegexpWithOverriddenName/\x00\x00\x06:\x06EF"
end
end
@@ -435,11 +349,6 @@ describe "Marshal.dump" do
it "dumps an extended Array" do
Marshal.dump([].extend(Meths)).should == "\004\be:\nMeths[\000"
end
-
- it "ignores overridden name method when dumps an Array subclass" do
- obj = MarshalSpec::ArrayWithOverriddenName.new
- Marshal.dump(obj).should == "\x04\bC:)MarshalSpec::ArrayWithOverriddenName[\x00"
- end
end
describe "with a Hash" do
@@ -447,10 +356,6 @@ describe "Marshal.dump" do
Marshal.dump({}).should == "\004\b{\000"
end
- it "dumps a non-empty Hash" do
- Marshal.dump({a: 1}).should == "\x04\b{\x06:\x06ai\x06"
- end
-
it "dumps a Hash subclass" do
Marshal.dump(UserHash.new).should == "\004\bC:\rUserHash{\000"
end
@@ -459,24 +364,8 @@ describe "Marshal.dump" do
Marshal.dump(Hash.new(1)).should == "\004\b}\000i\006"
end
- ruby_version_is "3.1" do
- it "dumps a Hash with compare_by_identity" do
- h = {}
- h.compare_by_identity
-
- Marshal.dump(h).should == "\004\bC:\tHash{\x00"
- end
-
- it "dumps a Hash subclass with compare_by_identity" do
- h = UserHash.new
- h.compare_by_identity
-
- Marshal.dump(h).should == "\x04\bC:\rUserHashC:\tHash{\x00"
- end
- end
-
it "raises a TypeError with hash having default proc" do
- -> { Marshal.dump(Hash.new {}) }.should raise_error(TypeError, "can't dump hash with default proc")
+ -> { Marshal.dump(Hash.new {}) }.should raise_error(TypeError)
end
it "dumps a Hash with instance variables" do
@@ -492,11 +381,6 @@ describe "Marshal.dump" do
it "dumps an Hash subclass with a parameter to initialize" do
Marshal.dump(UserHashInitParams.new(1)).should == "\004\bIC:\027UserHashInitParams{\000\006:\a@ai\006"
end
-
- it "ignores overridden name method when dumps a Hash subclass" do
- obj = MarshalSpec::HashWithOverriddenName.new
- Marshal.dump(obj).should == "\x04\bC:(MarshalSpec::HashWithOverriddenName{\x00"
- end
end
describe "with a Struct" do
@@ -525,15 +409,6 @@ describe "Marshal.dump" do
Marshal.dump(obj).should == "\004\be:\nMethsS:\025Struct::Extended\a:\006a[\a;\a\"\ahi:\006b[\a;\000@\a"
Struct.send(:remove_const, :Extended)
end
-
- it "ignores overridden name method" do
- obj = MarshalSpec::StructWithOverriddenName.new("member")
- Marshal.dump(obj).should == "\x04\bS:*MarshalSpec::StructWithOverriddenName\x06:\x06a\"\vmember"
- end
-
- it "raises TypeError with an anonymous Struct" do
- -> { Marshal.dump(Struct.new(:a).new(1)) }.should raise_error(TypeError, /can't dump anonymous class/)
- end
end
describe "with an Object" do
@@ -553,7 +428,7 @@ describe "Marshal.dump" do
it "dumps an Object with a non-US-ASCII instance variable" do
obj = Object.new
- ivar = "@é".dup.force_encoding(Encoding::UTF_8).to_sym
+ ivar = "@é".force_encoding(Encoding::UTF_8).to_sym
obj.instance_variable_set(ivar, 1)
Marshal.dump(obj).should == "\x04\bo:\vObject\x06I:\b@\xC3\xA9\x06:\x06ETi\x06"
end
@@ -565,18 +440,13 @@ describe "Marshal.dump" do
Marshal.dump(obj).should == "\004\bo:\x0BObject\x00"
end
- it "dumps an Object if it has a singleton class but no singleton methods and no singleton instance variables" do
+ it "dumps an Object if it has a singleton class but no singleton methods" do
obj = Object.new
obj.singleton_class
Marshal.dump(obj).should == "\004\bo:\x0BObject\x00"
end
- it "ignores overridden name method" do
- obj = MarshalSpec::ClassWithOverriddenName.new
- Marshal.dump(obj).should == "\x04\bo:)MarshalSpec::ClassWithOverriddenName\x00"
- end
-
- it "raises TypeError if an Object has a singleton class and singleton methods" do
+ it "raises if an Object has a singleton class and singleton methods" do
obj = Object.new
def obj.foo; end
-> {
@@ -584,45 +454,10 @@ describe "Marshal.dump" do
}.should raise_error(TypeError, "singleton can't be dumped")
end
- it "raises TypeError if an Object has a singleton class and singleton instance variables" do
- obj = Object.new
- class << obj
- @v = 1
- end
-
- -> {
- Marshal.dump(obj)
- }.should raise_error(TypeError, "singleton can't be dumped")
- end
-
- it "raises TypeError if an Object is an instance of an anonymous class" do
- anonymous_class = Class.new
- obj = anonymous_class.new
-
- -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
- end
-
- it "raises TypeError if an Object extends an anonymous module" do
- anonymous_module = Module.new
- obj = Object.new
- obj.extend(anonymous_module)
-
- -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
- end
-
it "dumps a BasicObject subclass if it defines respond_to?" do
obj = MarshalSpec::BasicObjectSubWithRespondToFalse.new
Marshal.dump(obj).should == "\x04\bo:2MarshalSpec::BasicObjectSubWithRespondToFalse\x00"
end
-
- it "dumps without marshaling any attached finalizer" do
- obj = Object.new
- finalizer = Object.new
- def finalizer.noop(_)
- end
- ObjectSpace.define_finalizer(obj, finalizer.method(:noop))
- Marshal.load(Marshal.dump(obj)).class.should == Object
- end
end
describe "with a Range" do
@@ -638,8 +473,15 @@ describe "Marshal.dump" do
load.should == (1...2)
end
- it "raises TypeError with an anonymous Range subclass" do
- -> { Marshal.dump(Class.new(Range).new(1, 2)) }.should raise_error(TypeError, /can't dump anonymous class/)
+ ruby_version_is ""..."3.0" do
+ it "dumps a Range with extra instance variables" do
+ range = (1...3)
+ range.instance_variable_set :@foo, 42
+ dump = Marshal.dump(range)
+ load = Marshal.load(dump)
+ load.should == range
+ load.instance_variable_get(:@foo).should == 42
+ end
end
end
@@ -678,20 +520,6 @@ describe "Marshal.dump" do
zone = ":\tzoneI\"\bUTC\x06:\x06EF" # Last is 'F' (US-ASCII)
dump.should == "\x04\bIu:\tTime\r#{@utc_dump}\x06#{zone}"
end
-
- it "ignores overridden name method" do
- obj = MarshalSpec::TimeWithOverriddenName.new
- Marshal.dump(obj).should include("MarshalSpec::TimeWithOverriddenName")
- end
-
- it "dumps a Time subclass with multibyte characters in name" do
- source_object = eval("MarshalSpec::Multibyteãã‚ãƒã„Time".dup.force_encoding(Encoding::UTF_8))
- Marshal.dump(source_object).should == "\x04\bc+MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Time"
- end
-
- it "raises TypeError with an anonymous Time subclass" do
- -> { Marshal.dump(Class.new(Time).now) }.should raise_error(TypeError)
- end
end
describe "with an Exception" do
@@ -732,23 +560,6 @@ describe "Marshal.dump" do
reloaded.cause.should be_an_instance_of(StandardError)
reloaded.cause.message.should == "the cause"
end
-
- # NoMethodError uses an exception formatter on TruffleRuby and computes a message lazily
- it "dumps the message for the raised NoMethodError exception" do
- begin
- "".foo
- rescue => e
- end
-
- Marshal.dump(e).should =~ /undefined method [`']foo' for ("":String|an instance of String)/
- end
-
- it "raises TypeError if an Object is an instance of an anonymous class" do
- anonymous_class = Class.new(Exception)
- obj = anonymous_class.new
-
- -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
- end
end
it "dumps subsequent appearances of a symbol as a link" do
@@ -781,6 +592,7 @@ describe "Marshal.dump" do
end
describe "when passed an IO" do
+
it "writes the serialized data to the IO-Object" do
(obj = mock('test')).should_receive(:write).at_least(1)
Marshal.dump("test", obj)
@@ -803,6 +615,8 @@ describe "Marshal.dump" do
obj.should_receive(:binmode).at_least(1)
Marshal.dump("test", obj)
end
+
+
end
describe "when passed a StringIO" do
diff --git a/spec/ruby/core/marshal/fixtures/marshal_data.rb b/spec/ruby/core/marshal/fixtures/marshal_data.rb
index a508b6bea1..9373ef7ba8 100644
--- a/spec/ruby/core/marshal/fixtures/marshal_data.rb
+++ b/spec/ruby/core/marshal/fixtures/marshal_data.rb
@@ -38,7 +38,7 @@ class UserDefinedWithIvar
attr_reader :a, :b, :c
def initialize
- @a = +'stuff'
+ @a = 'stuff'
@a.instance_variable_set :@foo, :UserDefinedWithIvar
@b = 'more'
@c = @b
@@ -78,22 +78,6 @@ class UserDefinedImmediate
end
end
-class UserDefinedString
- attr_reader :string
-
- def initialize(string)
- @string = string
- end
-
- def _dump(depth)
- @string
- end
-
- def self._load(data)
- new(data)
- end
-end
-
class UserPreviouslyDefinedWithInitializedIvar
attr_accessor :field1, :field2
end
@@ -183,17 +167,12 @@ module MarshalSpec
end
end
- StructToDump = Struct.new(:a, :b)
-
class BasicObjectSubWithRespondToFalse < BasicObject
def respond_to?(method_name, include_all=false)
false
end
end
- module ModuleToExtendBy
- end
-
def self.random_data
randomizer = Random.new(42)
1000.times{randomizer.rand} # Make sure we exhaust his first state of 624 random words
@@ -213,81 +192,6 @@ module MarshalSpec
set_swapped_class(nil)
end
- class ClassWithOverriddenName
- def self.name
- "Foo"
- end
- end
-
- class ModuleWithOverriddenName
- def self.name
- "Foo"
- end
- end
-
- class TimeWithOverriddenName < Time
- def self.name
- "Foo"
- end
- end
-
- class StructWithOverriddenName < Struct.new(:a)
- def self.name
- "Foo"
- end
- end
-
- class UserDefinedWithOverriddenName < UserDefined
- def self.name
- "Foo"
- end
- end
-
- class StringWithOverriddenName < String
- def self.name
- "Foo"
- end
- end
-
- class ArrayWithOverriddenName < Array
- def self.name
- "Foo"
- end
- end
-
- class HashWithOverriddenName < Hash
- def self.name
- "Foo"
- end
- end
-
- class RegexpWithOverriddenName < Regexp
- def self.name
- "Foo"
- end
- end
-
- module_eval(<<~ruby.dup.force_encoding(Encoding::UTF_8))
- class Multibyteãã‚ãƒã„Class
- end
-
- module Multibyteã‘ã’ã“ã”Module
- end
-
- class Multibyteãã‚ãƒã„Time < Time
- end
- ruby
-
- class ObjectWithFreezeRaisingException < Object
- def freeze
- raise
- end
- end
-
- class ObjectWithoutFreeze < Object
- undef freeze
- end
-
DATA = {
"nil" => [nil, "\004\b0"],
"1..2" => [(1..2),
@@ -313,7 +217,7 @@ module MarshalSpec
"\004\b\"\012small"],
"String big" => ['big' * 100,
"\004\b\"\002,\001#{'big' * 100}"],
- "String extended" => [''.dup.extend(Meths), # TODO: check for module on load
+ "String extended" => [''.extend(Meths), # TODO: check for module on load
"\004\be:\nMeths\"\000"],
"String subclass" => [UserString.new,
"\004\bC:\017UserString\"\000"],
@@ -420,7 +324,7 @@ module MarshalSpec
"\x04\bI\"\nsmall\x06:\x06EF"],
"String big" => ['big' * 100,
"\x04\bI\"\x02,\x01bigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbig\x06:\x06EF"],
- "String extended" => [''.dup.extend(Meths), # TODO: check for module on load
+ "String extended" => [''.extend(Meths), # TODO: check for module on load
"\x04\bIe:\nMeths\"\x00\x06:\x06EF"],
"String subclass" => [UserString.new,
"\004\bC:\017UserString\"\000"],
diff --git a/spec/ruby/core/marshal/shared/load.rb b/spec/ruby/core/marshal/shared/load.rb
index 4eac21a952..479c7477ec 100644
--- a/spec/ruby/core/marshal/shared/load.rb
+++ b/spec/ruby/core/marshal/shared/load.rb
@@ -8,11 +8,7 @@ describe :marshal_load, shared: true do
it "raises an ArgumentError when the dumped data is truncated" do
obj = {first: 1, second: 2, third: 3}
- -> { Marshal.send(@method, Marshal.dump(obj)[0, 5]) }.should raise_error(ArgumentError, "marshal data too short")
- end
-
- it "raises an ArgumentError when the argument is empty String" do
- -> { Marshal.send(@method, "") }.should raise_error(ArgumentError, "marshal data too short")
+ -> { Marshal.send(@method, Marshal.dump(obj)[0, 5]) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when the dumped class is missing" do
@@ -54,136 +50,29 @@ describe :marshal_load, shared: true do
regexp.should.frozen?
end
- it "returns frozen structs" do
- struct = Marshal.send(@method, Marshal.dump(MarshalSpec::StructToDump.new(1, 2)), freeze: true)
- struct.should == MarshalSpec::StructToDump.new(1, 2)
- struct.should.frozen?
- end
-
it "returns frozen objects" do
source_object = Object.new
+ source_object.instance_variable_set(:@foo, "bar")
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object.should.frozen?
- end
-
- describe "deep freezing" do
- it "returns hashes with frozen keys and values" do
- key = Object.new
- value = Object.new
- source_object = {key => value}
-
- hash = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
- hash.size.should == 1
- hash.keys[0].should.frozen?
- hash.values[0].should.frozen?
- end
-
- it "returns arrays with frozen elements" do
- object = Object.new
- source_object = [object]
-
- array = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
- array.size.should == 1
- array[0].should.frozen?
- end
-
- it "returns structs with frozen members" do
- object1 = Object.new
- object2 = Object.new
- source_object = MarshalSpec::StructToDump.new(object1, object2)
-
- struct = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
- struct.a.should.frozen?
- struct.b.should.frozen?
- end
-
- it "returns objects with frozen instance variables" do
- source_object = Object.new
- instance_variable = Object.new
- source_object.instance_variable_set(:@a, instance_variable)
-
- object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
- object.instance_variable_get(:@a).should != nil
- object.instance_variable_get(:@a).should.frozen?
- end
-
- it "deduplicates frozen strings" do
- source_object = ["foo" + "bar", "foobar"]
- object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
-
- object[0].should equal(object[1])
- end
+ object.instance_variable_get(:@foo).should.frozen?
end
it "does not freeze modules" do
- object = Marshal.send(@method, Marshal.dump(Kernel), freeze: true)
- object.should_not.frozen?
+ Marshal.send(@method, Marshal.dump(Kernel), freeze: true)
Kernel.should_not.frozen?
end
it "does not freeze classes" do
- object = Marshal.send(@method, Marshal.dump(Object), freeze: true)
- object.should_not.frozen?
+ Marshal.send(@method, Marshal.dump(Object), freeze: true)
Object.should_not.frozen?
end
- ruby_bug "#19427", ""..."3.3" do
- it "does freeze extended objects" do
- object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", freeze: true)
- object.should.frozen?
- end
-
- it "does freeze extended objects with instance variables" do
- object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x06:\n@ivarT", freeze: true)
- object.should.frozen?
- end
- end
-
- ruby_bug "#19427", "3.1"..."3.3" do
- it "returns frozen object having #_dump method" do
- object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true)
- object.should.frozen?
- end
-
- it "returns frozen object responding to #marshal_dump and #marshal_load" do
- object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true)
- object.should.frozen?
- end
-
- it "returns frozen object extended by a module" do
- object = Object.new
- object.extend(MarshalSpec::ModuleToExtendBy)
-
- object = Marshal.send(@method, Marshal.dump(object), freeze: true)
- object.should.frozen?
- end
- end
-
- it "does not call freeze method" do
- object = MarshalSpec::ObjectWithFreezeRaisingException.new
- object = Marshal.send(@method, Marshal.dump(object), freeze: true)
- object.should.frozen?
- end
-
- it "returns frozen object even if object does not respond to freeze method" do
- object = MarshalSpec::ObjectWithoutFreeze.new
- object = Marshal.send(@method, Marshal.dump(object), freeze: true)
- object.should.frozen?
- end
-
- it "returns a frozen object when is an instance of String/Array/Regexp/Hash subclass and has instance variables" do
- source_object = UserString.new
- source_object.instance_variable_set(:@foo, "bar")
-
- object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
- object.should.frozen?
- end
-
describe "when called with a proc" do
it "call the proc with frozen objects" do
arr = []
- s = +'hi'
+ s = 'hi'
s.instance_variable_set(:@foo, 5)
st = Struct.new("Brittle", :a).new
st.instance_variable_set(:@clue, 'none')
@@ -243,14 +132,6 @@ describe :marshal_load, shared: true do
end
end
- ruby_bug "#19427", ""..."3.3" do
- it "call the proc with extended objects" do
- objs = []
- obj = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", Proc.new { |o| objs << o; o })
- objs.should == [obj]
- end
- end
-
it "returns the value of the proc" do
Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4]
end
@@ -268,7 +149,7 @@ describe :marshal_load, shared: true do
it "loads an Array with proc" do
arr = []
- s = +'hi'
+ s = 'hi'
s.instance_variable_set(:@foo, 5)
st = Struct.new("Brittle", :a).new
st.instance_variable_set(:@clue, 'none')
@@ -314,19 +195,7 @@ describe :marshal_load, shared: true do
marshaled_obj.field2.should be_nil
end
- it "loads the String in non US-ASCII and non UTF-8 encoding" do
- source_object = UserDefinedString.new("a".encode("windows-1251"))
- object = Marshal.send(@method, Marshal.dump(source_object))
- object.string.should == "a".encode("windows-1251")
- end
-
- it "loads the String in multibyte encoding" do
- source_object = UserDefinedString.new("a".encode("utf-32le"))
- object = Marshal.send(@method, Marshal.dump(source_object))
- object.string.should == "a".encode("utf-32le")
- end
-
- describe "that returns an immediate value" do
+ describe "that return an immediate value" do
it "loads an array containing an instance of the object, followed by multiple instances of another object" do
str = "string"
@@ -413,13 +282,13 @@ describe :marshal_load, shared: true do
end
it "raises a TypeError with bad Marshal version" do
- marshal_data = +'\xff\xff'
+ marshal_data = '\xff\xff'
marshal_data[0] = (Marshal::MAJOR_VERSION).chr
marshal_data[1] = (Marshal::MINOR_VERSION + 1).chr
-> { Marshal.send(@method, marshal_data) }.should raise_error(TypeError)
- marshal_data = +'\xff\xff'
+ marshal_data = '\xff\xff'
marshal_data[0] = (Marshal::MAJOR_VERSION - 1).chr
marshal_data[1] = (Marshal::MINOR_VERSION).chr
@@ -470,7 +339,7 @@ describe :marshal_load, shared: true do
end
it "loads an array having ivar" do
- s = +'well'
+ s = 'well'
s.instance_variable_set(:@foo, 10)
obj = ['5', s, 'hi'].extend(Meths, MethsMore)
obj.instance_variable_set(:@mix, s)
@@ -516,7 +385,7 @@ describe :marshal_load, shared: true do
end
it "preserves hash ivars when hash contains a string having ivar" do
- s = +'string'
+ s = 'string'
s.instance_variable_set :@string_ivar, 'string ivar'
h = { key: s }
h.instance_variable_set :@hash_ivar, 'hash ivar'
@@ -525,38 +394,6 @@ describe :marshal_load, shared: true do
unmarshalled.instance_variable_get(:@hash_ivar).should == 'hash ivar'
unmarshalled[:key].instance_variable_get(:@string_ivar).should == 'string ivar'
end
-
- ruby_version_is "3.1" do
- it "preserves compare_by_identity behaviour" do
- h = { a: 1 }
- h.compare_by_identity
- unmarshalled = Marshal.send(@method, Marshal.dump(h))
- unmarshalled.should.compare_by_identity?
-
- h = { a: 1 }
- unmarshalled = Marshal.send(@method, Marshal.dump(h))
- unmarshalled.should_not.compare_by_identity?
- end
-
- it "preserves compare_by_identity behaviour for a Hash subclass" do
- h = UserHash.new({ a: 1 })
- h.compare_by_identity
- unmarshalled = Marshal.send(@method, Marshal.dump(h))
- unmarshalled.should.compare_by_identity?
-
- h = UserHash.new({ a: 1 })
- unmarshalled = Marshal.send(@method, Marshal.dump(h))
- unmarshalled.should_not.compare_by_identity?
- end
- end
-
- it "allocates an instance of the proper class when Hash subclass with compare_by_identity behaviour" do
- h = UserHash.new({ a: 1 })
- h.compare_by_identity
-
- unmarshalled = Marshal.send(@method, Marshal.dump(h))
- unmarshalled.should.kind_of?(UserHash)
- end
end
describe "for a Symbol" do
@@ -600,7 +437,7 @@ describe :marshal_load, shared: true do
end
it "loads a binary encoded Symbol" do
- s = "\u2192".dup.force_encoding("binary").to_sym
+ s = "\u2192".force_encoding("binary").to_sym
sym = Marshal.send(@method, "\x04\b:\b\xE2\x86\x92")
sym.should == s
sym.encoding.should == Encoding::BINARY
@@ -614,8 +451,8 @@ describe :marshal_load, shared: true do
value = Marshal.send(@method, dump)
value.map(&:encoding).should == [Encoding::UTF_8, Encoding::UTF_8]
expected = [
- "€a".dup.force_encoding(Encoding::UTF_8).to_sym,
- "€b".dup.force_encoding(Encoding::UTF_8).to_sym
+ "€a".force_encoding(Encoding::UTF_8).to_sym,
+ "€b".force_encoding(Encoding::UTF_8).to_sym
]
value.should == expected
@@ -623,19 +460,11 @@ describe :marshal_load, shared: true do
value.map(&:encoding).should == [Encoding::UTF_8, Encoding::UTF_8, Encoding::UTF_8]
value.should == [*expected, expected[0]]
end
-
- it "raises ArgumentError when end of byte sequence reached before symbol characters end" do
- Marshal.dump(:hello).should == "\x04\b:\nhello"
-
- -> {
- Marshal.send(@method, "\x04\b:\nhel")
- }.should raise_error(ArgumentError, "marshal data too short")
- end
end
describe "for a String" do
it "loads a string having ivar with ref to self" do
- obj = +'hi'
+ obj = 'hi'
obj.instance_variable_set(:@self, obj)
Marshal.send(@method, "\004\bI\"\ahi\006:\n@self@\000").should == obj
end
@@ -646,12 +475,6 @@ describe :marshal_load, shared: true do
Marshal.send(@method, StringIO.new(Marshal.dump(obj))).should == obj
end
- it "sets binmode if it is loading through StringIO stream" do
- io = StringIO.new("\004\b:\vsymbol")
- def io.binmode; raise "binmode"; end
- -> { Marshal.load(io) }.should raise_error(RuntimeError, "binmode")
- end
-
it "loads a string with an ivar" do
str = Marshal.send(@method, "\x04\bI\"\x00\x06:\t@fooI\"\bbar\x06:\x06EF")
str.instance_variable_get("@foo").should == "bar"
@@ -663,7 +486,7 @@ describe :marshal_load, shared: true do
end
it "loads a US-ASCII String" do
- str = "abc".dup.force_encoding("us-ascii")
+ str = "abc".force_encoding("us-ascii")
data = "\x04\bI\"\babc\x06:\x06EF"
result = Marshal.send(@method, data)
result.should == str
@@ -671,7 +494,7 @@ describe :marshal_load, shared: true do
end
it "loads a UTF-8 String" do
- str = "\x6d\xc3\xb6\x68\x72\x65".dup.force_encoding("utf-8")
+ str = "\x6d\xc3\xb6\x68\x72\x65".force_encoding("utf-8")
data = "\x04\bI\"\vm\xC3\xB6hre\x06:\x06ET"
result = Marshal.send(@method, data)
result.should == str
@@ -679,7 +502,7 @@ describe :marshal_load, shared: true do
end
it "loads a String in another encoding" do
- str = "\x6d\x00\xf6\x00\x68\x00\x72\x00\x65\x00".dup.force_encoding("utf-16le")
+ str = "\x6d\x00\xf6\x00\x68\x00\x72\x00\x65\x00".force_encoding("utf-16le")
data = "\x04\bI\"\x0Fm\x00\xF6\x00h\x00r\x00e\x00\x06:\rencoding\"\rUTF-16LE"
result = Marshal.send(@method, data)
result.should == str
@@ -687,20 +510,12 @@ describe :marshal_load, shared: true do
end
it "loads a String as BINARY if no encoding is specified at the end" do
- str = "\xC3\xB8".dup.force_encoding("BINARY")
- data = "\x04\b\"\a\xC3\xB8".dup.force_encoding("UTF-8")
+ str = "\xC3\xB8".force_encoding("BINARY")
+ data = "\x04\b\"\a\xC3\xB8".force_encoding("UTF-8")
result = Marshal.send(@method, data)
result.encoding.should == Encoding::BINARY
result.should == str
end
-
- it "raises ArgumentError when end of byte sequence reached before string characters end" do
- Marshal.dump("hello").should == "\x04\b\"\nhello"
-
- -> {
- Marshal.send(@method, "\x04\b\"\nhel")
- }.should raise_error(ArgumentError, "marshal data too short")
- end
end
describe "for a Struct" do
@@ -823,7 +638,7 @@ describe :marshal_load, shared: true do
end
it "loads an Object with a non-US-ASCII instance variable" do
- ivar = "@é".dup.force_encoding(Encoding::UTF_8).to_sym
+ ivar = "@é".force_encoding(Encoding::UTF_8).to_sym
obj = Marshal.send(@method, "\x04\bo:\vObject\x06I:\b@\xC3\xA9\x06:\x06ETi\x06")
obj.instance_variables.should == [ivar]
obj.instance_variables[0].encoding.should == Encoding::UTF_8
@@ -835,14 +650,6 @@ describe :marshal_load, shared: true do
Marshal.send(@method, "\x04\bo:\tFile\001\001:\001\005@path\"\x10/etc/passwd")
end.should raise_error(ArgumentError)
end
-
- it "raises ArgumentError when end of byte sequence reached before class name end" do
- Marshal.dump(Object.new).should == "\x04\bo:\vObject\x00"
-
- -> {
- Marshal.send(@method, "\x04\bo:\vObj")
- }.should raise_error(ArgumentError, "marshal data too short")
- end
end
describe "for an object responding to #marshal_dump and #marshal_load" do
@@ -901,7 +708,7 @@ describe :marshal_load, shared: true do
[Meths, MethsMore, Regexp]
end
- it "loads a Regexp subclass instance variables when it is extended with a module" do
+ it "loads a extended_user_regexp having ivar" do
obj = UserRegexp.new('').extend(Meths)
obj.instance_variable_set(:@noise, 'much')
@@ -924,22 +731,6 @@ describe :marshal_load, shared: true do
new_obj.instance_variable_get(:@regexp_ivar).should == [42]
end
end
-
- it "preserves Regexp encoding" do
- source_object = Regexp.new("a".encode("utf-32le"))
- regexp = Marshal.send(@method, Marshal.dump(source_object))
-
- regexp.encoding.should == Encoding::UTF_32LE
- regexp.source.should == "a".encode("utf-32le")
- end
-
- it "raises ArgumentError when end of byte sequence reached before source string end" do
- Marshal.dump(/hello world/).should == "\x04\bI/\x10hello world\x00\x06:\x06EF"
-
- -> {
- Marshal.send(@method, "\x04\bI/\x10hel")
- }.should raise_error(ArgumentError, "marshal data too short")
- end
end
describe "for a Float" do
@@ -961,14 +752,6 @@ describe :marshal_load, shared: true do
obj = 1.1867345e+22
Marshal.send(@method, "\004\bf\0361.1867344999999999e+22\000\344@").should == obj
end
-
- it "raises ArgumentError when end of byte sequence reached before float string representation end" do
- Marshal.dump(1.3).should == "\x04\bf\b1.3"
-
- -> {
- Marshal.send(@method, "\004\bf\v1")
- }.should raise_error(ArgumentError, "marshal data too short")
- end
end
describe "for an Integer" do
@@ -1034,22 +817,18 @@ describe :marshal_load, shared: true do
describe "for a Rational" do
it "loads" do
- r = Marshal.send(@method, Marshal.dump(Rational(1, 3)))
- r.should == Rational(1, 3)
- r.should.frozen?
+ Marshal.send(@method, Marshal.dump(Rational(1, 3))).should == Rational(1, 3)
end
end
describe "for a Complex" do
it "loads" do
- c = Marshal.send(@method, Marshal.dump(Complex(4, 3)))
- c.should == Complex(4, 3)
- c.should.frozen?
+ Marshal.send(@method, Marshal.dump(Complex(4, 3))).should == Complex(4, 3)
end
end
describe "for a Bignum" do
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
context "that is Bignum on 32-bit platforms but Fixnum on 64-bit" do
it "dumps a Fixnum" do
val = Marshal.send(@method, "\004\bl+\ab:wU")
@@ -1085,47 +864,17 @@ describe :marshal_load, shared: true do
t1.should equal t2
end
- it "keeps the local zone" do
+ it "loads the zone" do
with_timezone 'AST', 3 do
t = Time.local(2012, 1, 1)
Marshal.send(@method, Marshal.dump(t)).zone.should == t.zone
end
end
- it "keeps UTC zone" do
- t = Time.now.utc
- t2 = Marshal.send(@method, Marshal.dump(t))
- t2.should.utc?
- end
-
- it "keeps the zone" do
- t = nil
-
- with_timezone 'AST', 4 do
- t = Time.local(2012, 1, 1)
- end
-
- with_timezone 'EET', -2 do
- Marshal.send(@method, Marshal.dump(t)).zone.should == 'AST'
- end
- end
-
- it "keeps utc offset" do
- t = Time.new(2007,11,1,15,25,0, "+09:00")
- t2 = Marshal.send(@method, Marshal.dump(t))
- t2.utc_offset.should == 32400
- end
-
- it "keeps nanoseconds" do
+ it "loads nanoseconds" do
t = Time.now
Marshal.send(@method, Marshal.dump(t)).nsec.should == t.nsec
end
-
- it "does not add any additional instance variable" do
- t = Time.now
- t2 = Marshal.send(@method, Marshal.dump(t))
- t2.instance_variables.should.empty?
- end
end
describe "for nil" do
@@ -1158,14 +907,6 @@ describe :marshal_load, shared: true do
it "raises ArgumentError if given a nonexistent class" do
-> { Marshal.send(@method, "\x04\bc\vStrung") }.should raise_error(ArgumentError)
end
-
- it "raises ArgumentError when end of byte sequence reached before class name end" do
- Marshal.dump(String).should == "\x04\bc\vString"
-
- -> {
- Marshal.send(@method, "\x04\bc\vStr")
- }.should raise_error(ArgumentError, "marshal data too short")
- end
end
describe "for a Module" do
@@ -1180,14 +921,6 @@ describe :marshal_load, shared: true do
it "loads an old module" do
Marshal.send(@method, "\x04\bM\vKernel").should == Kernel
end
-
- it "raises ArgumentError when end of byte sequence reached before module name end" do
- Marshal.dump(Kernel).should == "\x04\bm\vKernel"
-
- -> {
- Marshal.send(@method, "\x04\bm\vKer")
- }.should raise_error(ArgumentError, "marshal data too short")
- end
end
describe "for a wrapped C pointer" do
diff --git a/spec/ruby/core/matchdata/begin_spec.rb b/spec/ruby/core/matchdata/begin_spec.rb
index 54b4e0a33f..85c454da56 100644
--- a/spec/ruby/core/matchdata/begin_spec.rb
+++ b/spec/ruby/core/matchdata/begin_spec.rb
@@ -36,18 +36,6 @@ describe "MatchData#begin" do
match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
match_data.begin(obj).should == 2
end
-
- it "raises IndexError if index is out of bounds" do
- match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- -> {
- match_data.begin(-1)
- }.should raise_error(IndexError, "index -1 out of matches")
-
- -> {
- match_data.begin(3)
- }.should raise_error(IndexError, "index 3 out of matches")
- end
end
context "when passed a String argument" do
@@ -80,14 +68,6 @@ describe "MatchData#begin" do
match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
match_data.begin("æ").should == 1
end
-
- it "raises IndexError if there is no group with the provided name" do
- match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- -> {
- match_data.begin("y")
- }.should raise_error(IndexError, "undefined group name reference: y")
- end
end
context "when passed a Symbol argument" do
@@ -120,13 +100,5 @@ describe "MatchData#begin" do
match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
match_data.begin(:æ).should == 1
end
-
- it "raises IndexError if there is no group with the provided name" do
- match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- -> {
- match_data.begin(:y)
- }.should raise_error(IndexError, "undefined group name reference: y")
- end
end
end
diff --git a/spec/ruby/core/matchdata/byteoffset_spec.rb b/spec/ruby/core/matchdata/byteoffset_spec.rb
deleted file mode 100644
index b27267fd0e..0000000000
--- a/spec/ruby/core/matchdata/byteoffset_spec.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "MatchData#byteoffset" do
- ruby_version_is "3.2" do
- it "returns beginning and ending byte-based offset of whole matched substring for 0 element" do
- m = /(.)(.)(\d+)(\d)/.match("THX1138.")
- m.byteoffset(0).should == [1, 7]
- end
-
- it "returns beginning and ending byte-based offset of n-th match, all the subsequent elements are capturing groups" do
- m = /(.)(.)(\d+)(\d)/.match("THX1138.")
-
- m.byteoffset(2).should == [2, 3]
- m.byteoffset(3).should == [3, 6]
- m.byteoffset(4).should == [6, 7]
- end
-
- it "accepts String as a reference to a named capture" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- m.byteoffset("f").should == [0, 3]
- m.byteoffset("b").should == [3, 6]
- end
-
- it "accepts Symbol as a reference to a named capture" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- m.byteoffset(:f).should == [0, 3]
- m.byteoffset(:b).should == [3, 6]
- end
-
- it "returns [nil, nil] if a capturing group is optional and doesn't match" do
- m = /(?<x>q..)?/.match("foobarbaz")
-
- m.byteoffset("x").should == [nil, nil]
- m.byteoffset(1).should == [nil, nil]
- end
-
- it "returns correct beginning and ending byte-based offset for multi-byte strings" do
- m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
-
- m.byteoffset(1).should == [3, 6]
- m.byteoffset(3).should == [6, 9]
- end
-
- it "returns [nil, nil] if a capturing group is optional and doesn't match for multi-byte string" do
- m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
-
- m.byteoffset(2).should == [nil, nil]
- end
-
- it "converts argument into integer if is not String nor Symbol" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- obj = Object.new
- def obj.to_int; 2; end
-
- m.byteoffset(1r).should == [0, 3]
- m.byteoffset(1.1).should == [0, 3]
- m.byteoffset(obj).should == [3, 6]
- end
-
- it "raises IndexError if there is no group with the provided name" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- -> {
- m.byteoffset("y")
- }.should raise_error(IndexError, "undefined group name reference: y")
-
- -> {
- m.byteoffset(:y)
- }.should raise_error(IndexError, "undefined group name reference: y")
- end
-
- it "raises IndexError if index is out of bounds" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- -> {
- m.byteoffset(-1)
- }.should raise_error(IndexError, "index -1 out of matches")
-
- -> {
- m.byteoffset(3)
- }.should raise_error(IndexError, "index 3 out of matches")
- end
-
- it "raises TypeError if can't convert argument into Integer" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- -> {
- m.byteoffset([])
- }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
- end
- end
-end
diff --git a/spec/ruby/core/matchdata/captures_spec.rb b/spec/ruby/core/matchdata/captures_spec.rb
index f829a25481..58d4620709 100644
--- a/spec/ruby/core/matchdata/captures_spec.rb
+++ b/spec/ruby/core/matchdata/captures_spec.rb
@@ -1,6 +1,15 @@
require_relative '../../spec_helper'
-require_relative 'shared/captures'
+require_relative 'fixtures/classes'
describe "MatchData#captures" do
- it_behaves_like :matchdata_captures, :captures
+ it "returns an array of the match captures" do
+ /(.)(.)(\d+)(\d)/.match("THX1138.").captures.should == ["H","X","113","8"]
+ end
+
+ ruby_version_is "3.0" do
+ it "returns instances of String when given a String subclass" do
+ str = MatchDataSpecs::MyString.new("THX1138: The Movie")
+ /(.)(.)(\d+)(\d)/.match(str).captures.each { |c| c.should be_an_instance_of(String) }
+ end
+ end
end
diff --git a/spec/ruby/core/matchdata/deconstruct_keys_spec.rb b/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
deleted file mode 100644
index 5b68f886c7..0000000000
--- a/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "MatchData#deconstruct_keys" do
- ruby_version_is "3.2" do
- it "returns whole hash for nil as an argument" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- m.deconstruct_keys(nil).should == { f: "foo", b: "bar" }
- end
-
- it "returns only specified keys" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- m.deconstruct_keys([:f]).should == { f: "foo" }
- end
-
- it "requires one argument" do
- m = /l/.match("l")
-
- -> {
- m.deconstruct_keys
- }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1)")
- end
-
- it "it raises error when argument is neither nil nor array" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- -> { m.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array)")
- -> { m.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array)")
- -> { m.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array)")
- -> { m.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array)")
- end
-
- it "returns {} when passed []" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- m.deconstruct_keys([]).should == {}
- end
-
- it "does not accept non-Symbol keys" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
-
- -> {
- m.deconstruct_keys(['year', :foo])
- }.should raise_error(TypeError, "wrong argument type String (expected Symbol)")
- end
-
- it "process keys till the first non-existing one" do
- m = /(?<f>foo)(?<b>bar)(?<c>baz)/.match("foobarbaz")
-
- m.deconstruct_keys([:f, :a, :b]).should == { f: "foo" }
- end
-
- it "returns {} when there are no named captured groups at all" do
- m = /foo.+/.match("foobar")
-
- m.deconstruct_keys(nil).should == {}
- end
-
- it "returns {} when passed more keys than named captured groups" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
- m.deconstruct_keys([:f, :b, :c]).should == {}
- end
- end
-end
diff --git a/spec/ruby/core/matchdata/deconstruct_spec.rb b/spec/ruby/core/matchdata/deconstruct_spec.rb
deleted file mode 100644
index 6af55113b6..0000000000
--- a/spec/ruby/core/matchdata/deconstruct_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/captures'
-
-describe "MatchData#deconstruct" do
- ruby_version_is "3.2" do
- it_behaves_like :matchdata_captures, :deconstruct
- end
-end
diff --git a/spec/ruby/core/matchdata/element_reference_spec.rb b/spec/ruby/core/matchdata/element_reference_spec.rb
index 0924be0aae..7c0f089bb4 100644
--- a/spec/ruby/core/matchdata/element_reference_spec.rb
+++ b/spec/ruby/core/matchdata/element_reference_spec.rb
@@ -20,18 +20,8 @@ describe "MatchData#[]" do
# negative index is larger than the number of match values
/(.)(.)(\d+)(\d)/.match("THX1138.")[-30, 2].should == nil
- # positive index larger than number of match values
- /(.)(.)(\d+)(\d)/.match("THX1138.")[5, 2].should == []
- /(.)(.)(\d+)(\d)/.match("THX1138.")[6, 2].should == nil
- /(.)(.)(\d+)(\d)/.match("THX1138.")[30, 2].should == nil
-
# length argument larger than number of match values is capped to match value length
/(.)(.)(\d+)(\d)/.match("THX1138.")[3, 10].should == %w|113 8|
-
- /(.)(.)(\d+)(\d)/.match("THX1138.")[3, 0].should == []
-
- /(.)(.)(\d+)(\d)/.match("THX1138.")[3, -1].should == nil
- /(.)(.)(\d+)(\d)/.match("THX1138.")[3, -30].should == nil
end
it "supports ranges [start..end]" do
@@ -53,9 +43,11 @@ describe "MatchData#[]" do
/(.)(.)(\d+)(\d)/.match("THX1138.")[nil..nil].should == %w|HX1138 H X 113 8|
end
- it "returns instances of String when given a String subclass" do
- str = MatchDataSpecs::MyString.new("THX1138.")
- /(.)(.)(\d+)(\d)/.match(str)[0..-1].each { |m| m.should be_an_instance_of(String) }
+ ruby_version_is "3.0" do
+ it "returns instances of String when given a String subclass" do
+ str = MatchDataSpecs::MyString.new("THX1138.")
+ /(.)(.)(\d+)(\d)/.match(str)[0..-1].each { |m| m.should be_an_instance_of(String) }
+ end
end
end
@@ -118,7 +110,7 @@ describe "MatchData#[Symbol]" do
it "returns matches in the String's encoding" do
rex = /(?<t>t(?<a>ack))/u
- md = 'haystack'.dup.force_encoding('euc-jp').match(rex)
+ md = 'haystack'.force_encoding('euc-jp').match(rex)
md[:t].encoding.should == Encoding::EUC_JP
end
end
diff --git a/spec/ruby/core/matchdata/named_captures_spec.rb b/spec/ruby/core/matchdata/named_captures_spec.rb
index 5e4693d62d..9b1e324a24 100644
--- a/spec/ruby/core/matchdata/named_captures_spec.rb
+++ b/spec/ruby/core/matchdata/named_captures_spec.rb
@@ -12,16 +12,4 @@ describe 'MatchData#named_captures' do
it 'returns the latest matched capture, even if a later one that does not match exists' do
/\A(?<a>.)(?<b>.)(?<b>.)(?<a>.)?\z/.match('012').named_captures.should == { 'a' => '0', 'b' => '2' }
end
-
- ruby_version_is "3.3" do
- it 'returns a Hash with Symbol keys when symbolize_names is provided a true value' do
- /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: true).should == { a: '0', b: nil }
- /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: "truly").should == { a: '0', b: nil }
- end
-
- it 'returns a Hash with String keys when symbolize_names is provided a false value' do
- /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: false).should == { 'a' => '0', 'b' => '2' }
- /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: nil).should == { 'a' => '0', 'b' => '2' }
- end
- end
end
diff --git a/spec/ruby/core/matchdata/post_match_spec.rb b/spec/ruby/core/matchdata/post_match_spec.rb
index 7bfe6df119..d3aa4c8900 100644
--- a/spec/ruby/core/matchdata/post_match_spec.rb
+++ b/spec/ruby/core/matchdata/post_match_spec.rb
@@ -8,17 +8,19 @@ describe "MatchData#post_match" do
end
it "sets the encoding to the encoding of the source String" do
- str = "abc".dup.force_encoding Encoding::EUC_JP
+ str = "abc".force_encoding Encoding::EUC_JP
str.match(/b/).post_match.encoding.should equal(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
- str = "abc".dup.force_encoding Encoding::ISO_8859_1
+ str = "abc".force_encoding Encoding::ISO_8859_1
str.match(/c/).post_match.encoding.should equal(Encoding::ISO_8859_1)
end
- it "returns an instance of String when given a String subclass" do
- str = MatchDataSpecs::MyString.new("THX1138: The Movie")
- /(.)(.)(\d+)(\d)/.match(str).post_match.should be_an_instance_of(String)
+ ruby_version_is "3.0" do
+ it "returns an instance of String when given a String subclass" do
+ str = MatchDataSpecs::MyString.new("THX1138: The Movie")
+ /(.)(.)(\d+)(\d)/.match(str).post_match.should be_an_instance_of(String)
+ end
end
end
diff --git a/spec/ruby/core/matchdata/pre_match_spec.rb b/spec/ruby/core/matchdata/pre_match_spec.rb
index 2f1ba9b8f6..b43be5fb41 100644
--- a/spec/ruby/core/matchdata/pre_match_spec.rb
+++ b/spec/ruby/core/matchdata/pre_match_spec.rb
@@ -8,17 +8,19 @@ describe "MatchData#pre_match" do
end
it "sets the encoding to the encoding of the source String" do
- str = "abc".dup.force_encoding Encoding::EUC_JP
+ str = "abc".force_encoding Encoding::EUC_JP
str.match(/b/).pre_match.encoding.should equal(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
- str = "abc".dup.force_encoding Encoding::ISO_8859_1
+ str = "abc".force_encoding Encoding::ISO_8859_1
str.match(/a/).pre_match.encoding.should equal(Encoding::ISO_8859_1)
end
- it "returns an instance of String when given a String subclass" do
- str = MatchDataSpecs::MyString.new("THX1138: The Movie")
- /(.)(.)(\d+)(\d)/.match(str).pre_match.should be_an_instance_of(String)
+ ruby_version_is "3.0" do
+ it "returns an instance of String when given a String subclass" do
+ str = MatchDataSpecs::MyString.new("THX1138: The Movie")
+ /(.)(.)(\d+)(\d)/.match(str).pre_match.should be_an_instance_of(String)
+ end
end
end
diff --git a/spec/ruby/core/matchdata/shared/captures.rb b/spec/ruby/core/matchdata/shared/captures.rb
deleted file mode 100644
index 33f834561a..0000000000
--- a/spec/ruby/core/matchdata/shared/captures.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../fixtures/classes'
-
-describe :matchdata_captures, shared: true do
- it "returns an array of the match captures" do
- /(.)(.)(\d+)(\d)/.match("THX1138.").send(@method).should == ["H","X","113","8"]
- end
-
- it "returns instances of String when given a String subclass" do
- str = MatchDataSpecs::MyString.new("THX1138: The Movie")
- /(.)(.)(\d+)(\d)/.match(str).send(@method).each { |c| c.should be_an_instance_of(String) }
- end
-end
diff --git a/spec/ruby/core/matchdata/string_spec.rb b/spec/ruby/core/matchdata/string_spec.rb
index 952e953318..420233e1f3 100644
--- a/spec/ruby/core/matchdata/string_spec.rb
+++ b/spec/ruby/core/matchdata/string_spec.rb
@@ -17,9 +17,8 @@ describe "MatchData#string" do
md.string.should equal(md.string)
end
- it "returns a frozen copy of the matched string for gsub!(String)" do
- s = +'he[[o'
- s.gsub!('[', ']')
+ it "returns a frozen copy of the matched string for gsub(String)" do
+ 'he[[o'.gsub!('[', ']')
$~.string.should == 'he[[o'
$~.string.should.frozen?
end
diff --git a/spec/ruby/core/matchdata/to_a_spec.rb b/spec/ruby/core/matchdata/to_a_spec.rb
index 4fa11ff604..50f5a161a5 100644
--- a/spec/ruby/core/matchdata/to_a_spec.rb
+++ b/spec/ruby/core/matchdata/to_a_spec.rb
@@ -6,8 +6,10 @@ describe "MatchData#to_a" do
/(.)(.)(\d+)(\d)/.match("THX1138.").to_a.should == ["HX1138", "H", "X", "113", "8"]
end
- it "returns instances of String when given a String subclass" do
- str = MatchDataSpecs::MyString.new("THX1138.")
- /(.)(.)(\d+)(\d)/.match(str)[0..-1].to_a.each { |m| m.should be_an_instance_of(String) }
+ ruby_version_is "3.0" do
+ it "returns instances of String when given a String subclass" do
+ str = MatchDataSpecs::MyString.new("THX1138.")
+ /(.)(.)(\d+)(\d)/.match(str)[0..-1].to_a.each { |m| m.should be_an_instance_of(String) }
+ end
end
end
diff --git a/spec/ruby/core/matchdata/to_s_spec.rb b/spec/ruby/core/matchdata/to_s_spec.rb
index cd1c4dbca2..aab0955ae1 100644
--- a/spec/ruby/core/matchdata/to_s_spec.rb
+++ b/spec/ruby/core/matchdata/to_s_spec.rb
@@ -6,8 +6,10 @@ describe "MatchData#to_s" do
/(.)(.)(\d+)(\d)/.match("THX1138.").to_s.should == "HX1138"
end
- it "returns an instance of String when given a String subclass" do
- str = MatchDataSpecs::MyString.new("THX1138.")
- /(.)(.)(\d+)(\d)/.match(str).to_s.should be_an_instance_of(String)
+ ruby_version_is "3.0" do
+ it "returns an instance of String when given a String subclass" do
+ str = MatchDataSpecs::MyString.new("THX1138.")
+ /(.)(.)(\d+)(\d)/.match(str).to_s.should be_an_instance_of(String)
+ end
end
end
diff --git a/spec/ruby/core/matchdata/values_at_spec.rb b/spec/ruby/core/matchdata/values_at_spec.rb
index 535719a2ee..4fd0bfc42a 100644
--- a/spec/ruby/core/matchdata/values_at_spec.rb
+++ b/spec/ruby/core/matchdata/values_at_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../spec_helper'
-describe "MatchData#values_at" do
+describe "Struct#values_at" do
# Should be synchronized with core/array/values_at_spec.rb and core/struct/values_at_spec.rb
#
# /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").to_a # => ["HX1138", "H", "X", "113", "8"]
@@ -34,7 +34,7 @@ describe "MatchData#values_at" do
end
it "supports beginningless Range" do
- /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(..2).should == ["HX1138", "H", "X"]
+ /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(0..2).should == ["HX1138", "H", "X"]
end
it "returns an empty Array when Range is empty" do
diff --git a/spec/ruby/core/math/cos_spec.rb b/spec/ruby/core/math/cos_spec.rb
index 006afeb2cc..3ba7a54c38 100644
--- a/spec/ruby/core/math/cos_spec.rb
+++ b/spec/ruby/core/math/cos_spec.rb
@@ -15,6 +15,7 @@ describe "Math.cos" do
Math.cos(2*Math::PI).should be_close(1.0, TOLERANCE)
end
+
it "raises a TypeError unless the argument is Numeric and has #to_f" do
-> { Math.cos("test") }.should raise_error(TypeError)
end
@@ -23,23 +24,14 @@ describe "Math.cos" do
Math.cos(nan_value).nan?.should be_true
end
- describe "coerces its argument with #to_f" do
- it "coerces its argument with #to_f" do
- f = mock_numeric('8.2')
- f.should_receive(:to_f).and_return(8.2)
- Math.cos(f).should == Math.cos(8.2)
- end
-
- it "raises a TypeError if the given argument can't be converted to a Float" do
- -> { Math.cos(nil) }.should raise_error(TypeError)
- -> { Math.cos(:abc) }.should raise_error(TypeError)
- end
-
- it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a Float" do
- object = mock_numeric('mock-float')
- object.should_receive(:to_f).and_raise(NoMethodError)
- -> { Math.cos(object) }.should raise_error(NoMethodError)
- end
+ it "raises a TypeError if the argument is nil" do
+ -> { Math.cos(nil) }.should raise_error(TypeError)
+ end
+
+ it "coerces its argument with #to_f" do
+ f = mock_numeric('8.2')
+ f.should_receive(:to_f).and_return(8.2)
+ Math.cos(f).should == Math.cos(8.2)
end
end
diff --git a/spec/ruby/core/method/clone_spec.rb b/spec/ruby/core/method/clone_spec.rb
index b0eb5751a9..3fe4000fb7 100644
--- a/spec/ruby/core/method/clone_spec.rb
+++ b/spec/ruby/core/method/clone_spec.rb
@@ -1,13 +1,14 @@
require_relative '../../spec_helper'
-require_relative 'shared/dup'
+require_relative 'fixtures/classes'
describe "Method#clone" do
- it_behaves_like :method_dup, :clone
+ it "returns a copy of the method" do
+ m1 = MethodSpecs::Methods.new.method(:foo)
+ m2 = m1.clone
- it "preserves frozen status" do
- method = Object.new.method(:method)
- method.freeze
- method.frozen?.should == true
- method.clone.frozen?.should == true
+ m1.should == m2
+ m1.should_not equal(m2)
+
+ m1.call.should == m2.call
end
end
diff --git a/spec/ruby/core/method/compose_spec.rb b/spec/ruby/core/method/compose_spec.rb
index 7506e33ea8..87cf61f7ad 100644
--- a/spec/ruby/core/method/compose_spec.rb
+++ b/spec/ruby/core/method/compose_spec.rb
@@ -38,7 +38,8 @@ describe "Method#<<" do
double = proc { |x| x + x }
(pow_2 << double).is_a?(Proc).should == true
- (pow_2 << double).should_not.lambda?
+ ruby_version_is(''...'3.0') { (pow_2 << double).should.lambda? }
+ ruby_version_is('3.0') { (pow_2 << double).should_not.lambda? }
end
it "may accept multiple arguments" do
diff --git a/spec/ruby/core/method/dup_spec.rb b/spec/ruby/core/method/dup_spec.rb
deleted file mode 100644
index e3e29d8a68..0000000000
--- a/spec/ruby/core/method/dup_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/dup'
-
-describe "Method#dup" do
- ruby_version_is "3.4" do
- it_behaves_like :method_dup, :dup
-
- it "resets frozen status" do
- method = Object.new.method(:method)
- method.freeze
- method.frozen?.should == true
- method.dup.frozen?.should == false
- end
- end
-end
diff --git a/spec/ruby/core/method/parameters_spec.rb b/spec/ruby/core/method/parameters_spec.rb
index 8495aef4d2..e6d51d1b4d 100644
--- a/spec/ruby/core/method/parameters_spec.rb
+++ b/spec/ruby/core/method/parameters_spec.rb
@@ -7,7 +7,6 @@ describe "Method#parameters" do
def one_keyrest(**a); end
def one_keyreq(a:); end
- def one_nokey(**nil); end
def one_splat_one_req(*a,b); end
def one_splat_two_req(*a,b,c); end
@@ -16,16 +15,11 @@ describe "Method#parameters" do
def one_opt_with_stabby(a=-> b { true }); end
def one_unnamed_splat(*); end
- def one_unnamed_keyrest(**); end
def one_splat_one_block(*args, &block)
local_is_not_parameter = {}
end
- def forward_parameters(...) end
-
- def underscore_parameters(_, _, _ = 1, *_, _:, _: 2, **_, &_); end
-
define_method(:one_optional_defined_method) {|x = 1|}
end
@@ -182,11 +176,6 @@ describe "Method#parameters" do
m.parameters.should == [[:keyreq,:a]]
end
- it "returns [[:nokey]] for a method with a single **nil parameter" do
- m = MethodSpecs::Methods.instance_method(:one_nokey)
- m.parameters.should == [[:nokey]]
- end
-
it "works with ->(){} as the value of an optional argument" do
m = MethodSpecs::Methods.instance_method(:one_opt_with_stabby)
m.parameters.should == [[:opt,:a]]
@@ -234,15 +223,10 @@ describe "Method#parameters" do
end
ruby_version_is '3.2' do
- it "adds rest arg with name * for \"star\" argument" do
+ it "adds * rest arg for \"star\" argument" do
m = MethodSpecs::Methods.new
m.method(:one_unnamed_splat).parameters.should == [[:rest, :*]]
end
-
- it "adds keyrest arg with ** as a name for \"double star\" argument" do
- m = MethodSpecs::Methods.new
- m.method(:one_unnamed_keyrest).parameters.should == [[:keyrest, :**]]
- end
end
ruby_version_is ''...'3.2' do
@@ -250,37 +234,6 @@ describe "Method#parameters" do
m = MethodSpecs::Methods.new
m.method(:one_unnamed_splat).parameters.should == [[:rest]]
end
-
- it "adds nameless keyrest arg for \"double star\" argument" do
- m = MethodSpecs::Methods.new
- m.method(:one_unnamed_keyrest).parameters.should == [[:keyrest]]
- end
- end
-
- ruby_version_is '3.1' do
- it "adds block arg with name & for anonymous block argument" do
- object = Object.new
-
- eval(<<~RUBY).should == [[:block, :&]]
- def object.foo(&)
- end
- object.method(:foo).parameters
- RUBY
- end
- end
-
- ruby_version_is ""..."3.1" do
- it "returns [:rest, :*], [:block, :&] for forward parameters operator" do
- m = MethodSpecs::Methods.new
- m.method(:forward_parameters).parameters.should == [[:rest, :*], [:block, :&]]
- end
- end
-
- ruby_version_is "3.1" do
- it "returns [:rest, :*], [:keyrest, :**], [:block, :&] for forward parameters operator" do
- m = MethodSpecs::Methods.new
- m.method(:forward_parameters).parameters.should == [[:rest, :*], [:keyrest, :**], [:block, :&]]
- end
end
it "returns the args and block for a splat and block argument" do
@@ -298,20 +251,6 @@ describe "Method#parameters" do
m.method(:writer=).parameters.should == [[:req]]
end
- it "returns all parameters defined with the name _ as _" do
- m = MethodSpecs::Methods.instance_method(:underscore_parameters)
- m.parameters.should == [
- [:req, :_],
- [:req, :_],
- [:opt, :_],
- [:rest, :_],
- [:keyreq, :_],
- [:key, :_],
- [:keyrest, :_],
- [:block, :_]
- ]
- end
-
it "returns [[:rest]] for core methods with variable-length argument lists" do
# delete! takes rest args
"foo".method(:delete!).parameters.should == [[:rest]]
diff --git a/spec/ruby/core/method/private_spec.rb b/spec/ruby/core/method/private_spec.rb
index fd550036a3..230a4e9e81 100644
--- a/spec/ruby/core/method/private_spec.rb
+++ b/spec/ruby/core/method/private_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-describe "Method#private?" do
- ruby_version_is "3.1"..."3.2" do
+ruby_version_is "3.1"..."3.2" do
+ describe "Method#private?" do
it "returns false when the method is public" do
obj = MethodSpecs::Methods.new
obj.method(:my_public_method).private?.should == false
@@ -18,11 +18,4 @@ describe "Method#private?" do
obj.method(:my_private_method).private?.should == true
end
end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_private_method).should_not.respond_to?(:private?)
- end
- end
end
diff --git a/spec/ruby/core/method/protected_spec.rb b/spec/ruby/core/method/protected_spec.rb
index 8423e8c64c..6ee85f7738 100644
--- a/spec/ruby/core/method/protected_spec.rb
+++ b/spec/ruby/core/method/protected_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-describe "Method#protected?" do
- ruby_version_is "3.1"..."3.2" do
+ruby_version_is "3.1"..."3.2" do
+ describe "Method#protected?" do
it "returns false when the method is public" do
obj = MethodSpecs::Methods.new
obj.method(:my_public_method).protected?.should == false
@@ -18,11 +18,4 @@ describe "Method#protected?" do
obj.method(:my_private_method).protected?.should == false
end
end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_protected_method).should_not.respond_to?(:protected?)
- end
- end
end
diff --git a/spec/ruby/core/method/public_spec.rb b/spec/ruby/core/method/public_spec.rb
index 20d0081a27..3988468551 100644
--- a/spec/ruby/core/method/public_spec.rb
+++ b/spec/ruby/core/method/public_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-describe "Method#public?" do
- ruby_version_is "3.1"..."3.2" do
+ruby_version_is "3.1"..."3.2" do
+ describe "Method#public?" do
it "returns true when the method is public" do
obj = MethodSpecs::Methods.new
obj.method(:my_public_method).public?.should == true
@@ -18,11 +18,4 @@ describe "Method#public?" do
obj.method(:my_private_method).public?.should == false
end
end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_public_method).should_not.respond_to?(:public?)
- end
- end
end
diff --git a/spec/ruby/core/method/shared/dup.rb b/spec/ruby/core/method/shared/dup.rb
deleted file mode 100644
index 1a10b90689..0000000000
--- a/spec/ruby/core/method/shared/dup.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-describe :method_dup, shared: true do
- it "returns a copy of self" do
- a = Object.new.method(:method)
- b = a.send(@method)
-
- a.should == b
- a.should_not equal(b)
- end
-
- ruby_version_is "3.4" do
- it "copies instance variables" do
- method = Object.new.method(:method)
- method.instance_variable_set(:@ivar, 1)
- cl = method.send(@method)
- cl.instance_variables.should == [:@ivar]
- end
-
- it "copies the finalizer" do
- code = <<-RUBY
- obj = Object.new.method(:method)
-
- ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" })
-
- obj.clone
-
- exit 0
- RUBY
-
- ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"]
- end
- end
-end
diff --git a/spec/ruby/core/method/shared/to_s.rb b/spec/ruby/core/method/shared/to_s.rb
index b2d27d370f..6fdeaaf99c 100644
--- a/spec/ruby/core/method/shared/to_s.rb
+++ b/spec/ruby/core/method/shared/to_s.rb
@@ -53,18 +53,20 @@ describe :method_to_s, shared: true do
MethodSpecs::A.new.method(:baz).send(@method).should.start_with? "#<Method: MethodSpecs::A#baz"
end
- it "returns a String containing the Module containing the method if object has a singleton class but method is not defined in the singleton class" do
- obj = MethodSpecs::MySub.new
- obj.singleton_class
- @m = obj.method(:bar)
- @string = @m.send(@method)
- @string.should.start_with? "#<Method: MethodSpecs::MySub(MethodSpecs::MyMod)#bar"
+ ruby_version_is '3.0' do
+ it "returns a String containing the Module containing the method if object has a singleton class but method is not defined in the singleton class" do
+ obj = MethodSpecs::MySub.new
+ obj.singleton_class
+ @m = obj.method(:bar)
+ @string = @m.send(@method)
+ @string.should.start_with? "#<Method: MethodSpecs::MySub(MethodSpecs::MyMod)#bar"
- c = MethodSpecs::MySub.dup
- m = Module.new{def bar; end}
- c.extend(m)
- @string = c.method(:bar).send(@method)
- @string.should.start_with? "#<Method: #<Class:#{c.inspect}>(#{m.inspect})#bar"
+ c = MethodSpecs::MySub.dup
+ m = Module.new{def bar; end}
+ c.extend(m)
+ @string = c.method(:bar).send(@method)
+ @string.should.start_with? "#<Method: #<Class:#{c.inspect}>(#{m.inspect})#bar"
+ end
end
it "returns a String containing the singleton class if method is defined in the singleton class" do
@@ -75,7 +77,9 @@ describe :method_to_s, shared: true do
@string.should.start_with? "#<Method: #<MethodSpecs::MySub:0xXXXXXX>.bar"
end
- it "shows the metaclass and the owner for a Module instance method retrieved from a class" do
- String.method(:include).inspect.should.start_with?("#<Method: #<Class:String>(Module)#include")
+ ruby_bug '#17428', ''...'3.0' do
+ it "shows the metaclass and the owner for a Module instance method retrieved from a class" do
+ String.method(:include).inspect.should.start_with?("#<Method: #<Class:String>(Module)#include")
+ end
end
end
diff --git a/spec/ruby/core/method/source_location_spec.rb b/spec/ruby/core/method/source_location_spec.rb
index c5b296f6e2..1f476aaa9b 100644
--- a/spec/ruby/core/method/source_location_spec.rb
+++ b/spec/ruby/core/method/source_location_spec.rb
@@ -13,7 +13,7 @@ describe "Method#source_location" do
it "sets the first value to the path of the file in which the method was defined" do
file = @method.source_location.first
file.should be_an_instance_of(String)
- file.should == File.realpath('fixtures/classes.rb', __dir__)
+ file.should == File.realpath('../fixtures/classes.rb', __FILE__)
end
it "sets the last value to an Integer representing the line on which the method was defined" do
@@ -104,13 +104,6 @@ describe "Method#source_location" do
end
end
- it "works for eval with a given line" do
- c = Class.new do
- eval('def self.m; end', nil, "foo", 100)
- end
- c.method(:m).source_location.should == ["foo", 100]
- end
-
describe "for a Method generated by respond_to_missing?" do
it "returns nil" do
m = MethodSpecs::Methods.new
diff --git a/spec/ruby/core/method/super_method_spec.rb b/spec/ruby/core/method/super_method_spec.rb
index c63a7aaa0f..f9a18f3878 100644
--- a/spec/ruby/core/method/super_method_spec.rb
+++ b/spec/ruby/core/method/super_method_spec.rb
@@ -55,10 +55,12 @@ describe "Method#super_method" do
end
end
- context "after aliasing an inherited method" do
- it "returns the expected super_method" do
- method = MethodSpecs::InheritedMethods::C.new.method(:meow)
- method.super_method.owner.should == MethodSpecs::InheritedMethods::A
+ ruby_version_is "2.7.3" do
+ context "after aliasing an inherited method" do
+ it "returns the expected super_method" do
+ method = MethodSpecs::InheritedMethods::C.new.method(:meow)
+ method.super_method.owner.should == MethodSpecs::InheritedMethods::A
+ end
end
end
end
diff --git a/spec/ruby/core/method/to_proc_spec.rb b/spec/ruby/core/method/to_proc_spec.rb
index 4993cce239..29b7bec2b3 100644
--- a/spec/ruby/core/method/to_proc_spec.rb
+++ b/spec/ruby/core/method/to_proc_spec.rb
@@ -35,7 +35,7 @@ describe "Method#to_proc" do
end
it "returns a proc that can be used by define_method" do
- x = +'test'
+ x = 'test'
to_s = class << x
define_method :foo, method(:to_s).to_proc
to_s
diff --git a/spec/ruby/core/module/alias_method_spec.rb b/spec/ruby/core/module/alias_method_spec.rb
index c36dedd2d8..5d3d0c23d9 100644
--- a/spec/ruby/core/module/alias_method_spec.rb
+++ b/spec/ruby/core/module/alias_method_spec.rb
@@ -81,20 +81,22 @@ describe "Module#alias_method" do
-> { @class.make_alias mock('x'), :public_one }.should raise_error(TypeError)
end
- it "raises a NoMethodError if the given name raises a NoMethodError during type coercion using to_str" do
- obj = mock("mock-name")
- obj.should_receive(:to_str).and_raise(NoMethodError)
- -> { @class.make_alias obj, :public_one }.should raise_error(NoMethodError)
- end
-
it "is a public method" do
Module.should have_public_instance_method(:alias_method, false)
end
describe "returned value" do
- it "returns symbol of the defined method name" do
- @class.send(:alias_method, :checking_return_value, :public_one).should equal(:checking_return_value)
- @class.send(:alias_method, 'checking_return_value', :public_one).should equal(:checking_return_value)
+ ruby_version_is ""..."3.0" do
+ it "returns self" do
+ @class.send(:alias_method, :checking_return_value, :public_one).should equal(@class)
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "returns symbol of the defined method name" do
+ @class.send(:alias_method, :checking_return_value, :public_one).should equal(:checking_return_value)
+ @class.send(:alias_method, 'checking_return_value', :public_one).should equal(:checking_return_value)
+ end
end
end
diff --git a/spec/ruby/core/module/attr_accessor_spec.rb b/spec/ruby/core/module/attr_accessor_spec.rb
index 503dccc61e..ba5289cbea 100644
--- a/spec/ruby/core/module/attr_accessor_spec.rb
+++ b/spec/ruby/core/module/attr_accessor_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/attr_added'
describe "Module#attr_accessor" do
it "creates a getter and setter for each given attribute name" do
@@ -81,9 +80,19 @@ describe "Module#attr_accessor" do
Module.should have_public_instance_method(:attr_accessor, false)
end
- it "returns an array of defined method names as symbols" do
- Class.new do
- (attr_accessor :foo, 'bar').should == [:foo, :foo=, :bar, :bar=]
+ ruby_version_is ""..."3.0" do
+ it "returns nil" do
+ Class.new do
+ (attr_accessor :foo, 'bar').should == nil
+ end
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "returns an array of defined method names as symbols" do
+ Class.new do
+ (attr_accessor :foo, 'bar').should == [:foo, :foo=, :bar, :bar=]
+ end
end
end
@@ -107,6 +116,4 @@ describe "Module#attr_accessor" do
1.foobar.should be_nil
end
end
-
- it_behaves_like :module_attr_added, :attr_accessor
end
diff --git a/spec/ruby/core/module/attr_reader_spec.rb b/spec/ruby/core/module/attr_reader_spec.rb
index 37fd537ff5..b0ae906ab5 100644
--- a/spec/ruby/core/module/attr_reader_spec.rb
+++ b/spec/ruby/core/module/attr_reader_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/attr_added'
describe "Module#attr_reader" do
it "creates a getter for each given attribute name" do
@@ -63,11 +62,19 @@ describe "Module#attr_reader" do
Module.should have_public_instance_method(:attr_reader, false)
end
- it "returns an array of defined method names as symbols" do
- Class.new do
- (attr_reader :foo, 'bar').should == [:foo, :bar]
+ ruby_version_is ""..."3.0" do
+ it "returns nil" do
+ Class.new do
+ (attr_reader :foo, 'bar').should == nil
+ end
end
end
- it_behaves_like :module_attr_added, :attr_reader
+ ruby_version_is "3.0" do
+ it "returns an array of defined method names as symbols" do
+ Class.new do
+ (attr_reader :foo, 'bar').should == [:foo, :bar]
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/module/attr_spec.rb b/spec/ruby/core/module/attr_spec.rb
index 2f9f4e26dc..33e0eb8628 100644
--- a/spec/ruby/core/module/attr_spec.rb
+++ b/spec/ruby/core/module/attr_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/attr_added'
describe "Module#attr" do
before :each do
@@ -147,13 +146,23 @@ describe "Module#attr" do
Module.should have_public_instance_method(:attr, false)
end
- it "returns an array of defined method names as symbols" do
- Class.new do
- (attr :foo, 'bar').should == [:foo, :bar]
- (attr :baz, false).should == [:baz]
- (attr :qux, true).should == [:qux, :qux=]
+ ruby_version_is ""..."3.0" do
+ it "returns nil" do
+ Class.new do
+ (attr :foo, 'bar').should == nil
+ (attr :baz, false).should == nil
+ (attr :qux, true).should == nil
+ end
end
end
- it_behaves_like :module_attr_added, :attr
+ ruby_version_is "3.0" do
+ it "returns an array of defined method names as symbols" do
+ Class.new do
+ (attr :foo, 'bar').should == [:foo, :bar]
+ (attr :baz, false).should == [:baz]
+ (attr :qux, true).should == [:qux, :qux=]
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/module/attr_writer_spec.rb b/spec/ruby/core/module/attr_writer_spec.rb
index 5b863ef88c..0e9d201317 100644
--- a/spec/ruby/core/module/attr_writer_spec.rb
+++ b/spec/ruby/core/module/attr_writer_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/attr_added'
describe "Module#attr_writer" do
it "creates a setter for each given attribute name" do
@@ -73,11 +72,19 @@ describe "Module#attr_writer" do
Module.should have_public_instance_method(:attr_writer, false)
end
- it "returns an array of defined method names as symbols" do
- Class.new do
- (attr_writer :foo, 'bar').should == [:foo=, :bar=]
+ ruby_version_is ""..."3.0" do
+ it "returns nil" do
+ Class.new do
+ (attr_writer :foo, 'bar').should == nil
+ end
end
end
- it_behaves_like :module_attr_added, :attr_writer
+ ruby_version_is "3.0" do
+ it "returns an array of defined method names as symbols" do
+ Class.new do
+ (attr_writer :foo, 'bar').should == [:foo=, :bar=]
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb
index 45d18b8608..af04ab26c8 100644
--- a/spec/ruby/core/module/autoload_spec.rb
+++ b/spec/ruby/core/module/autoload_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
require_relative '../../fixtures/code_loading'
require_relative 'fixtures/classes'
+require 'thread'
describe "Module#autoload?" do
it "returns the name of the file that will be autoloaded" do
@@ -342,29 +343,6 @@ describe "Module#autoload" do
end
end
- def check_before_during_thread_after(const, &check)
- before = check.call
- to_autoload_thread, from_autoload_thread = Queue.new, Queue.new
- ScratchPad.record -> {
- from_autoload_thread.push check.call
- to_autoload_thread.pop
- }
- t = Thread.new {
- in_loading_thread = from_autoload_thread.pop
- in_other_thread = check.call
- to_autoload_thread.push :done
- [in_loading_thread, in_other_thread]
- }
- in_loading_thread, in_other_thread = nil
- begin
- ModuleSpecs::Autoload.const_get(const)
- ensure
- in_loading_thread, in_other_thread = t.value
- end
- after = check.call
- [before, in_loading_thread, in_other_thread, after]
- end
-
describe "during the autoload before the constant is assigned" do
before :each do
@path = fixture(__FILE__, "autoload_during_autoload.rb")
@@ -373,83 +351,58 @@ describe "Module#autoload" do
raise unless ModuleSpecs::Autoload.autoload?(:DuringAutoload) == @path
end
+ def check_before_during_thread_after(&check)
+ before = check.call
+ to_autoload_thread, from_autoload_thread = Queue.new, Queue.new
+ ScratchPad.record -> {
+ from_autoload_thread.push check.call
+ to_autoload_thread.pop
+ }
+ t = Thread.new {
+ in_loading_thread = from_autoload_thread.pop
+ in_other_thread = check.call
+ to_autoload_thread.push :done
+ [in_loading_thread, in_other_thread]
+ }
+ in_loading_thread, in_other_thread = nil
+ begin
+ ModuleSpecs::Autoload::DuringAutoload
+ ensure
+ in_loading_thread, in_other_thread = t.value
+ end
+ after = check.call
+ [before, in_loading_thread, in_other_thread, after]
+ end
+
it "returns nil in autoload thread and 'constant' otherwise for defined?" do
- results = check_before_during_thread_after(:DuringAutoload) {
+ results = check_before_during_thread_after {
defined?(ModuleSpecs::Autoload::DuringAutoload)
}
results.should == ['constant', nil, 'constant', 'constant']
end
it "keeps the constant in Module#constants" do
- results = check_before_during_thread_after(:DuringAutoload) {
+ results = check_before_during_thread_after {
ModuleSpecs::Autoload.constants(false).include?(:DuringAutoload)
}
results.should == [true, true, true, true]
end
it "returns false in autoload thread and true otherwise for Module#const_defined?" do
- results = check_before_during_thread_after(:DuringAutoload) {
+ results = check_before_during_thread_after {
ModuleSpecs::Autoload.const_defined?(:DuringAutoload, false)
}
results.should == [true, false, true, true]
end
it "returns nil in autoload thread and returns the path in other threads for Module#autoload?" do
- results = check_before_during_thread_after(:DuringAutoload) {
+ results = check_before_during_thread_after {
ModuleSpecs::Autoload.autoload?(:DuringAutoload)
}
results.should == [@path, nil, @path, nil]
end
end
- describe "during the autoload after the constant is assigned" do
- before :each do
- @path = fixture(__FILE__, "autoload_during_autoload_after_define.rb")
- ModuleSpecs::Autoload.autoload :DuringAutoloadAfterDefine, @path
- @autoload_location = [__FILE__, __LINE__ - 1]
- @const_location = [@path, 2]
- @remove << :DuringAutoloadAfterDefine
- raise unless ModuleSpecs::Autoload.autoload?(:DuringAutoloadAfterDefine) == @path
- end
-
- it "returns 'constant' in both threads" do
- results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
- defined?(ModuleSpecs::Autoload::DuringAutoloadAfterDefine)
- }
- results.should == ['constant', 'constant', 'constant', 'constant']
- end
-
- it "Module#constants include the autoloaded in both threads" do
- results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
- ModuleSpecs::Autoload.constants(false).include?(:DuringAutoloadAfterDefine)
- }
- results.should == [true, true, true, true]
- end
-
- it "Module#const_defined? returns true in both threads" do
- results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
- ModuleSpecs::Autoload.const_defined?(:DuringAutoloadAfterDefine, false)
- }
- results.should == [true, true, true, true]
- end
-
- it "returns nil in autoload thread and returns the path in other threads for Module#autoload?" do
- results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
- ModuleSpecs::Autoload.autoload?(:DuringAutoloadAfterDefine)
- }
- results.should == [@path, nil, @path, nil]
- end
-
- ruby_bug("#20188", ""..."3.4") do
- it "returns the real constant location in autoload thread and returns the autoload location in other threads for Module#const_source_location" do
- results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
- ModuleSpecs::Autoload.const_source_location(:DuringAutoloadAfterDefine)
- }
- results.should == [@autoload_location, @const_location, @autoload_location, @const_location]
- end
- end
- end
-
it "does not remove the constant from Module#constants if load fails and keeps it as an autoload" do
ModuleSpecs::Autoload.autoload :Fail, @non_existent
diff --git a/spec/ruby/core/module/const_added_spec.rb b/spec/ruby/core/module/const_added_spec.rb
index f9edda3a07..31ac6eb105 100644
--- a/spec/ruby/core/module/const_added_spec.rb
+++ b/spec/ruby/core/module/const_added_spec.rb
@@ -121,40 +121,5 @@ describe "Module#const_added" do
ScratchPad.recorded.should == [line + 2, line + 4, line + 7, line + 11]
end
-
- it "is called when the constant is already assigned a value" do
- ScratchPad.record []
-
- mod = Module.new do
- def self.const_added(name)
- ScratchPad.record const_get(name)
- end
- end
-
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- TEST = 123
- RUBY
-
- ScratchPad.recorded.should == 123
- end
-
- it "records re-definition of existing constants" do
- ScratchPad.record []
-
- mod = Module.new do
- def self.const_added(name)
- ScratchPad << const_get(name)
- end
- end
-
- -> {
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- TEST = 123
- TEST = 456
- RUBY
- }.should complain(/warning: already initialized constant .+::TEST/)
-
- ScratchPad.recorded.should == [123, 456]
- end
end
end
diff --git a/spec/ruby/core/module/const_defined_spec.rb b/spec/ruby/core/module/const_defined_spec.rb
index 027cf5a245..0c15629c08 100644
--- a/spec/ruby/core/module/const_defined_spec.rb
+++ b/spec/ruby/core/module/const_defined_spec.rb
@@ -80,23 +80,10 @@ describe "Module#const_defined?" do
ConstantSpecs::ClassA.const_defined?(:CS_CONSTX).should == false
end
- describe "converts the given name to a String using #to_str" do
- it "calls #to_str to convert the given name to a String" do
- name = mock("ClassA")
- name.should_receive(:to_str).and_return("ClassA")
- ConstantSpecs.const_defined?(name).should == true
- end
-
- it "raises a TypeError if the given name can't be converted to a String" do
- -> { ConstantSpecs.const_defined?(nil) }.should raise_error(TypeError)
- -> { ConstantSpecs.const_defined?([]) }.should raise_error(TypeError)
- end
-
- it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
- name = mock("classA")
- name.should_receive(:to_str).and_raise(NoMethodError)
- -> { ConstantSpecs.const_defined?(name) }.should raise_error(NoMethodError)
- end
+ it "calls #to_str to convert the given name to a String" do
+ name = mock("ClassA")
+ name.should_receive(:to_str).and_return("ClassA")
+ ConstantSpecs.const_defined?(name).should == true
end
it "special cases Object and checks it's included Modules" do
diff --git a/spec/ruby/core/module/const_get_spec.rb b/spec/ruby/core/module/const_get_spec.rb
index 0233118f4b..69f181cf51 100644
--- a/spec/ruby/core/module/const_get_spec.rb
+++ b/spec/ruby/core/module/const_get_spec.rb
@@ -105,7 +105,7 @@ describe "Module#const_get" do
-> { ConstantSpecs.const_get("CS_CONST1", false) }.should raise_error(NameError)
end
- it "returns a constant whose module is defined the toplevel" do
+ it "returns a constant whose module is defined the the toplevel" do
ConstantSpecs.const_get("ConstantSpecsTwo::Foo").should == :cs_two_foo
ConstantSpecsThree.const_get("ConstantSpecsTwo::Foo").should == :cs_three_foo
end
diff --git a/spec/ruby/core/module/const_set_spec.rb b/spec/ruby/core/module/const_set_spec.rb
index 5bdfd7b68f..ba7810d17b 100644
--- a/spec/ruby/core/module/const_set_spec.rb
+++ b/spec/ruby/core/module/const_set_spec.rb
@@ -20,10 +20,20 @@ describe "Module#const_set" do
m.name.should == "ConstantSpecs::CS_CONST1000"
end
- it "sets the name of a module scoped by an anonymous module" do
- a, b = Module.new, Module.new
- a.const_set :B, b
- b.name.should.end_with? '::B'
+ ruby_version_is ""..."3.0" do
+ it "does not set the name of a module scoped by an anonymous module" do
+ a, b = Module.new, Module.new
+ a.const_set :B, b
+ b.name.should be_nil
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "sets the name of a module scoped by an anonymous module" do
+ a, b = Module.new, Module.new
+ a.const_set :B, b
+ b.name.should.end_with? '::B'
+ end
end
it "sets the name of contained modules when assigning a toplevel anonymous module" do
diff --git a/spec/ruby/core/module/const_source_location_spec.rb b/spec/ruby/core/module/const_source_location_spec.rb
index c194c9113f..11a2e74756 100644
--- a/spec/ruby/core/module/const_source_location_spec.rb
+++ b/spec/ruby/core/module/const_source_location_spec.rb
@@ -67,11 +67,6 @@ describe "Module#const_source_location" do
end
describe "with statically assigned constants" do
- it "works for the module and class keywords" do
- ConstantSpecs.const_source_location(:ModuleB).should == [@constants_fixture_path, ConstantSpecs::ModuleB::LINE]
- ConstantSpecs.const_source_location(:ClassA).should == [@constants_fixture_path, ConstantSpecs::ClassA::LINE]
- end
-
it "searches location path the immediate class or module first" do
ConstantSpecs::ClassA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE]
ConstantSpecs::ModuleA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST10_LINE]
@@ -138,7 +133,7 @@ describe "Module#const_source_location" do
it "calls #to_str to convert the given name to a String" do
name = mock("ClassA")
name.should_receive(:to_str).and_return("ClassA")
- ConstantSpecs.const_source_location(name).should == [@constants_fixture_path, ConstantSpecs::ClassA::LINE]
+ ConstantSpecs.const_source_location(name).should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CLASS_A_LINE]
end
it "raises a TypeError if conversion to a String by calling #to_str fails" do
@@ -210,13 +205,6 @@ describe "Module#const_source_location" do
ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE]
end
- it "works for eval with a given line" do
- c = Class.new do
- eval('self::C = 1', nil, "foo", 100)
- end
- c.const_source_location(:C).should == ["foo", 100]
- end
-
context 'autoload' do
before :all do
ConstantSpecs.autoload :CSL_CONST1, "#{__dir__}/notexisting.rb"
@@ -233,17 +221,5 @@ describe "Module#const_source_location" do
line = ConstantSpecs::CONST_LOCATION
ConstantSpecs.const_source_location('CONST_LOCATION').should == [file, line]
end
-
- ruby_bug("#20188", ""..."3.4") do
- it 'returns the real constant location as soon as it is defined' do
- file = fixture(__FILE__, 'autoload_const_source_location.rb')
- ConstantSpecs.autoload :ConstSource, file
- autoload_location = [__FILE__, __LINE__ - 1]
-
- ConstantSpecs.const_source_location(:ConstSource).should == autoload_location
- ConstantSpecs::ConstSource::LOCATION.should == ConstantSpecs.const_source_location(:ConstSource)
- ConstantSpecs::BEFORE_DEFINE_LOCATION.should == autoload_location
- end
- end
end
end
diff --git a/spec/ruby/core/module/define_method_spec.rb b/spec/ruby/core/module/define_method_spec.rb
index e04bb87ceb..ce94436bfd 100644
--- a/spec/ruby/core/module/define_method_spec.rb
+++ b/spec/ruby/core/module/define_method_spec.rb
@@ -133,17 +133,6 @@ describe "Module#define_method when name is not a special private name" do
klass.should have_public_instance_method(:baz)
end
end
-
- it "sets the method owner for a dynamically added method with a different original owner" do
- mixin_module = Module.new do
- def bar; end
- end
-
- foo = Object.new
- foo.singleton_class.define_method(:bar, mixin_module.instance_method(:bar))
-
- foo.method(:bar).owner.should == foo.singleton_class
- end
end
describe "passed a block" do
@@ -499,33 +488,6 @@ describe "Module#define_method" do
Class.new { define_method :bar, m }
}.should raise_error(TypeError, /can't bind singleton method to a different class/)
end
-
- it "defines a new method with public visibility when a Method passed and the class/module of the context isn't equal to the receiver of #define_method" do
- c = Class.new do
- private def foo
- "public"
- end
- end
-
- object = c.new
- object.singleton_class.define_method(:bar, object.method(:foo))
-
- object.bar.should == "public"
- end
-
- it "defines the new method according to the scope visibility when a Method passed and the class/module of the context is equal to the receiver of #define_method" do
- c = Class.new do
- def foo; end
- end
-
- object = c.new
- object.singleton_class.class_eval do
- private
- define_method(:bar, c.new.method(:foo))
- end
-
- -> { object.bar }.should raise_error(NoMethodError)
- end
end
describe "Module#define_method" do
@@ -724,7 +686,7 @@ describe "Module#define_method" do
end
end
-describe "Module#define_method when passed a Method object" do
+describe "Method#define_method when passed a Method object" do
before :each do
@klass = Class.new do
def m(a, b, *c)
@@ -749,7 +711,7 @@ describe "Module#define_method when passed a Method object" do
end
end
-describe "Module#define_method when passed an UnboundMethod object" do
+describe "Method#define_method when passed an UnboundMethod object" do
before :each do
@klass = Class.new do
def m(a, b, *c)
@@ -774,7 +736,7 @@ describe "Module#define_method when passed an UnboundMethod object" do
end
end
-describe "Module#define_method when passed a Proc object" do
+describe "Method#define_method when passed a Proc object" do
describe "and a method is defined inside" do
it "defines the nested method in the default definee where the Proc was created" do
prc = nil
@@ -799,7 +761,7 @@ describe "Module#define_method when passed a Proc object" do
end
end
-describe "Module#define_method when passed a block" do
+describe "Method#define_method when passed a block" do
describe "behaves exactly like a lambda" do
it "for return" do
Class.new do
diff --git a/spec/ruby/core/module/fixtures/autoload_const_source_location.rb b/spec/ruby/core/module/fixtures/autoload_const_source_location.rb
deleted file mode 100644
index ee0e5a689f..0000000000
--- a/spec/ruby/core/module/fixtures/autoload_const_source_location.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-module ConstantSpecs
- BEFORE_DEFINE_LOCATION = const_source_location(:ConstSource)
- module ConstSource
- LOCATION = Object.const_source_location(name)
- end
-end
diff --git a/spec/ruby/core/module/fixtures/autoload_during_autoload_after_define.rb b/spec/ruby/core/module/fixtures/autoload_during_autoload_after_define.rb
deleted file mode 100644
index a9d886dfd6..0000000000
--- a/spec/ruby/core/module/fixtures/autoload_during_autoload_after_define.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-module ModuleSpecs::Autoload
- class DuringAutoloadAfterDefine
- block = ScratchPad.recorded
- ScratchPad.record(block.call)
- end
-end
diff --git a/spec/ruby/core/module/fixtures/classes.rb b/spec/ruby/core/module/fixtures/classes.rb
index a434e7b0b8..bc6b940a6c 100644
--- a/spec/ruby/core/module/fixtures/classes.rb
+++ b/spec/ruby/core/module/fixtures/classes.rb
@@ -596,32 +596,6 @@ module ModuleSpecs
private :foo
end
EmptyFooMethod = m.instance_method(:foo)
-
- # for undefined_instance_methods spec
- module UndefinedInstanceMethods
- module Super
- def super_included_method; end
- end
-
- class Parent
- def undefed_method; end
- undef_method :undefed_method
-
- def parent_method; end
- def another_parent_method; end
- end
-
- class Child < Parent
- include Super
-
- undef_method :parent_method
- undef_method :another_parent_method
- end
-
- class Grandchild < Child
- undef_method :super_included_method
- end
- end
end
class Object
diff --git a/spec/ruby/core/module/fixtures/module.rb b/spec/ruby/core/module/fixtures/module.rb
index 34543ca2b4..9050a272ec 100644
--- a/spec/ruby/core/module/fixtures/module.rb
+++ b/spec/ruby/core/module/fixtures/module.rb
@@ -1,8 +1,4 @@
module ModuleSpecs
module Anonymous
- module Child
- end
-
- SameChild = Child
end
end
diff --git a/spec/ruby/core/module/include_spec.rb b/spec/ruby/core/module/include_spec.rb
index 78f6b41031..c073bc31ca 100644
--- a/spec/ruby/core/module/include_spec.rb
+++ b/spec/ruby/core/module/include_spec.rb
@@ -47,34 +47,6 @@ describe "Module#include" do
-> { ModuleSpecs::SubclassSpec.include(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
end
- ruby_version_is ""..."3.2" do
- it "raises ArgumentError when the argument is a refinement" do
- refinement = nil
-
- Module.new do
- refine String do
- refinement = self
- end
- end
-
- -> { ModuleSpecs::Basic.include(refinement) }.should raise_error(ArgumentError, "refinement module is not allowed")
- end
- end
-
- ruby_version_is "3.2" do
- it "raises a TypeError when the argument is a refinement" do
- refinement = nil
-
- Module.new do
- refine String do
- refinement = self
- end
- end
-
- -> { ModuleSpecs::Basic.include(refinement) }.should raise_error(TypeError, "Cannot include refinement")
- end
- end
-
it "imports constants to modules and classes" do
ModuleSpecs::A.constants.should include(:CONSTANT_A)
ModuleSpecs::B.constants.should include(:CONSTANT_A, :CONSTANT_B)
diff --git a/spec/ruby/core/module/method_added_spec.rb b/spec/ruby/core/module/method_added_spec.rb
index ec92cddc1e..b983c8da76 100644
--- a/spec/ruby/core/module/method_added_spec.rb
+++ b/spec/ruby/core/module/method_added_spec.rb
@@ -2,10 +2,6 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Module#method_added" do
- before :each do
- ScratchPad.record []
- end
-
it "is a private instance method" do
Module.should have_private_instance_method(:method_added)
end
@@ -17,6 +13,8 @@ describe "Module#method_added" do
end
it "is called when a new instance method is defined in self" do
+ ScratchPad.record []
+
Module.new do
def self.method_added(name)
ScratchPad << name
@@ -34,6 +32,8 @@ describe "Module#method_added" do
it "is not called when a singleton method is added" do
# obj.singleton_method_added is called instead
+ ScratchPad.record []
+
klass = Class.new
def klass.method_added(name)
ScratchPad << name
@@ -60,71 +60,8 @@ describe "Module#method_added" do
m.should_not have_method(:method_to_undef)
end
- it "is not called when a method changes visibility" do
- Module.new do
- def public_method
- end
-
- def private_method
- end
-
- def self.method_added(name)
- ScratchPad << name
- end
-
- public :public_method
- private :public_method
-
- private :private_method
- public :private_method
- end
-
- ScratchPad.recorded.should == []
- end
-
- it "is called when using #private in a subclass" do
- parent = Class.new do
- def foo
- end
- end
-
- Class.new(parent) do
- def self.method_added(name)
- ScratchPad << name
- end
-
- # Create an instance as that might initialize some method lookup caches, which is interesting to test
- self.new.foo
-
- private :foo
- public :foo
- end
-
- ScratchPad.recorded.should == [:foo]
- end
-
- it "is not called when a method is copied via module_function, rather #singleton_method_added is called" do
- Module.new do
- def mod_function
- end
-
- def self.method_added(name)
- ScratchPad << [:method_added, name]
- end
-
- def self.singleton_method_added(name)
- ScratchPad << [:singleton_method_added, name]
- end
-
- ScratchPad.record []
-
- module_function :mod_function
- end
-
- ScratchPad.recorded.should == [[:singleton_method_added, :mod_function]]
- end
-
it "is called with a precise caller location with the line of the 'def'" do
+ ScratchPad.record []
line = nil
Module.new do
diff --git a/spec/ruby/core/module/module_function_spec.rb b/spec/ruby/core/module/module_function_spec.rb
index 1c3ec5471b..0602e95ca9 100644
--- a/spec/ruby/core/module/module_function_spec.rb
+++ b/spec/ruby/core/module/module_function_spec.rb
@@ -155,62 +155,15 @@ describe "Module#module_function with specific method names" do
m.foo.should == ["m", "super_m"]
end
-
- context "methods created with define_method" do
- context "passed a block" do
- it "creates duplicates of the given instance methods" do
- m = Module.new do
- define_method :test1 do; end
- module_function :test1
- end
-
- m.respond_to?(:test1).should == true
- end
- end
-
- context "passed a method" do
- it "creates duplicates of the given instance methods" do
- module_with_method = Module.new do
- def test1; end
- end
-
- c = Class.new do
- extend module_with_method
- end
-
- m = Module.new do
- define_method :test2, c.method(:test1)
- module_function :test2
- end
-
- m.respond_to?(:test2).should == true
- end
- end
-
- context "passed an unbound method" do
- it "creates duplicates of the given instance methods" do
- module_with_method = Module.new do
- def test1; end
- end
-
- m = Module.new do
- define_method :test2, module_with_method.instance_method(:test1)
- module_function :test2
- end
-
- m.respond_to?(:test2).should == true
- end
- end
- end
end
describe "Module#module_function as a toggle (no arguments) in a Module body" do
it "makes any subsequently defined methods module functions with the normal semantics" do
- m = Module.new do
+ m = Module.new {
module_function
def test1() end
def test2() end
- end
+ }
m.respond_to?(:test1).should == true
m.respond_to?(:test2).should == true
@@ -234,13 +187,13 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do
it "stops creating module functions if the body encounters another toggle " \
"like public/protected/private without arguments" do
- m = Module.new do
+ m = Module.new {
module_function
def test1() end
def test2() end
public
def test3() end
- end
+ }
m.respond_to?(:test1).should == true
m.respond_to?(:test2).should == true
@@ -249,14 +202,14 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do
it "does not stop creating module functions if the body encounters " \
"public/protected/private WITH arguments" do
- m = Module.new do
+ m = Module.new {
def foo() end
module_function
def test1() end
def test2() end
public :foo
def test3() end
- end
+ }
m.respond_to?(:test1).should == true
m.respond_to?(:test2).should == true
@@ -264,116 +217,69 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do
end
it "does not affect module_evaled method definitions also if outside the eval itself" do
- m = Module.new do
+ m = Module.new {
module_function
module_eval { def test1() end }
module_eval " def test2() end "
- end
+ }
m.respond_to?(:test1).should == false
m.respond_to?(:test2).should == false
end
it "has no effect if inside a module_eval if the definitions are outside of it" do
- m = Module.new do
+ m = Module.new {
module_eval { module_function }
def test1() end
def test2() end
- end
+ }
m.respond_to?(:test1).should == false
m.respond_to?(:test2).should == false
end
it "functions normally if both toggle and definitions inside a module_eval" do
- m = Module.new do
- module_eval do
+ m = Module.new {
+ module_eval {
module_function
def test1() end
def test2() end
- end
- end
+ }
+ }
m.respond_to?(:test1).should == true
m.respond_to?(:test2).should == true
end
- it "affects eval'ed method definitions also even when outside the eval itself" do
- m = Module.new do
+ it "affects evaled method definitions also even when outside the eval itself" do
+ m = Module.new {
module_function
eval "def test1() end"
- end
+ }
m.respond_to?(:test1).should == true
end
it "doesn't affect definitions when inside an eval even if the definitions are outside of it" do
- m = Module.new do
+ m = Module.new {
eval "module_function"
def test1() end
- end
+ }
m.respond_to?(:test1).should == false
end
it "functions normally if both toggle and definitions inside a eval" do
- m = Module.new do
+ m = Module.new {
eval <<-CODE
module_function
def test1() end
def test2() end
CODE
- end
+ }
m.respond_to?(:test1).should == true
m.respond_to?(:test2).should == true
end
-
- context "methods are defined with define_method" do
- context "passed a block" do
- it "makes any subsequently defined methods module functions with the normal semantics" do
- m = Module.new do
- module_function
- define_method :test1 do; end
- end
-
- m.respond_to?(:test1).should == true
- end
- end
-
- context "passed a method" do
- it "makes any subsequently defined methods module functions with the normal semantics" do
- module_with_method = Module.new do
- def test1; end
- end
-
- c = Class.new do
- extend module_with_method
- end
-
- m = Module.new do
- module_function
- define_method :test2, c.method(:test1)
- end
-
- m.respond_to?(:test2).should == true
- end
- end
-
- context "passed an unbound method" do
- it "makes any subsequently defined methods module functions with the normal semantics" do
- module_with_method = Module.new do
- def test1; end
- end
-
- m = Module.new do
- module_function
- define_method :test2, module_with_method.instance_method(:test1)
- end
-
- m.respond_to?(:test2).should == true
- end
- end
- end
end
diff --git a/spec/ruby/core/module/name_spec.rb b/spec/ruby/core/module/name_spec.rb
index 0d1f4e24d5..b78bbfcc80 100644
--- a/spec/ruby/core/module/name_spec.rb
+++ b/spec/ruby/core/module/name_spec.rb
@@ -6,10 +6,20 @@ describe "Module#name" do
Module.new.name.should be_nil
end
- it "is not nil when assigned to a constant in an anonymous module" do
- m = Module.new
- m::N = Module.new
- m::N.name.should.end_with? '::N'
+ ruby_version_is ""..."3.0" do
+ it "is nil when assigned to a constant in an anonymous module" do
+ m = Module.new
+ m::N = Module.new
+ m::N.name.should be_nil
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "is not nil when assigned to a constant in an anonymous module" do
+ m = Module.new
+ m::N = Module.new
+ m::N.name.should.end_with? '::N'
+ end
end
it "is not nil for a nested module created with the module keyword" do
@@ -32,19 +42,6 @@ describe "Module#name" do
m::N.name.should == "ModuleSpecs::Anonymous::WasAnnon"
end
- it "may be the repeated in different module objects" do
- m = Module.new
- n = Module.new
-
- suppress_warning do
- ModuleSpecs::Anonymous::SameName = m
- ModuleSpecs::Anonymous::SameName = n
- end
-
- m.name.should == "ModuleSpecs::Anonymous::SameName"
- n.name.should == "ModuleSpecs::Anonymous::SameName"
- end
-
it "is set after it is removed from a constant" do
module ModuleSpecs
module ModuleToRemove
@@ -72,18 +69,12 @@ describe "Module#name" do
ModuleSpecs::Anonymous.name.should == "ModuleSpecs::Anonymous"
end
- it "is set when assigning to a constant (constant path matches outer module name)" do
+ it "is set when assigning to a constant" do
m = Module.new
ModuleSpecs::Anonymous::A = m
m.name.should == "ModuleSpecs::Anonymous::A"
end
- it "is set when assigning to a constant (constant path does not match outer module name)" do
- m = Module.new
- ModuleSpecs::Anonymous::SameChild::A = m
- m.name.should == "ModuleSpecs::Anonymous::Child::A"
- end
-
it "is not modified when assigning to a new constant after it has been accessed" do
m = Module.new
ModuleSpecs::Anonymous::B = m
@@ -120,26 +111,13 @@ describe "Module#name" do
ModuleSpecs::NameEncoding.new.name.encoding.should == Encoding::UTF_8
end
- it "is set when the anonymous outer module name is set (module in one single constant)" do
+ it "is set when the anonymous outer module name is set" do
m = Module.new
m::N = Module.new
ModuleSpecs::Anonymous::E = m
m::N.name.should == "ModuleSpecs::Anonymous::E::N"
end
- # https://bugs.ruby-lang.org/issues/19681
- it "is set when the anonymous outer module name is set (module in several constants)" do
- m = Module.new
- m::N = Module.new
- m::O = m::N
- ModuleSpecs::Anonymous::StoredInMultiplePlaces = m
- valid_names = [
- "ModuleSpecs::Anonymous::StoredInMultiplePlaces::N",
- "ModuleSpecs::Anonymous::StoredInMultiplePlaces::O"
- ]
- valid_names.should include(m::N.name) # You get one of the two, but you don't know which one.
- end
-
it "returns a frozen String" do
ModuleSpecs.name.should.frozen?
end
diff --git a/spec/ruby/core/module/new_spec.rb b/spec/ruby/core/module/new_spec.rb
index ec521360bd..da7f3b8720 100644
--- a/spec/ruby/core/module/new_spec.rb
+++ b/spec/ruby/core/module/new_spec.rb
@@ -6,10 +6,6 @@ describe "Module.new" do
Module.new.is_a?(Module).should == true
end
- it "creates a module without a name" do
- Module.new.name.should be_nil
- end
-
it "creates a new Module and passes it to the provided block" do
test_mod = nil
m = Module.new do |mod|
diff --git a/spec/ruby/core/module/prepend_spec.rb b/spec/ruby/core/module/prepend_spec.rb
index b40d12f0de..976b09b105 100644
--- a/spec/ruby/core/module/prepend_spec.rb
+++ b/spec/ruby/core/module/prepend_spec.rb
@@ -75,26 +75,6 @@ describe "Module#prepend" do
foo.call.should == 'm'
end
- it "updates the optimized method when a prepended module is updated" do
- out = ruby_exe(<<~RUBY)
- module M; end
- class Integer
- prepend M
- end
- l = -> { 1 + 2 }
- p l.call
- M.module_eval do
- def +(o)
- $called = true
- super(o)
- end
- end
- p l.call
- p $called
- RUBY
- out.should == "3\n3\ntrue\n"
- end
-
it "updates the method when there is a base included method and the prepended module overrides it" do
base_module = Module.new do
def foo
@@ -435,34 +415,6 @@ describe "Module#prepend" do
-> { ModuleSpecs::SubclassSpec.prepend(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
end
- ruby_version_is ""..."3.2" do
- it "raises ArgumentError when the argument is a refinement" do
- refinement = nil
-
- Module.new do
- refine String do
- refinement = self
- end
- end
-
- -> { ModuleSpecs::Basic.prepend(refinement) }.should raise_error(ArgumentError, "refinement module is not allowed")
- end
- end
-
- ruby_version_is "3.2" do
- it "raises a TypeError when the argument is a refinement" do
- refinement = nil
-
- Module.new do
- refine String do
- refinement = self
- end
- end
-
- -> { ModuleSpecs::Basic.prepend(refinement) }.should raise_error(TypeError, "Cannot prepend refinement")
- end
- end
-
it "imports constants" do
m1 = Module.new
m1::MY_CONSTANT = 1
@@ -547,17 +499,34 @@ describe "Module#prepend" do
c.dup.new.should be_kind_of(m)
end
- it "uses only new module when dupping the module" do
- m1 = Module.new { def calc(x) x end }
- m2 = Module.new { prepend(m1) }
- c1 = Class.new { prepend(m2) }
- m2dup = m2.dup
- m2dup.ancestors.should == [m1,m2dup]
- c2 = Class.new { prepend(m2dup) }
- c1.ancestors[0,3].should == [m1,m2,c1]
- c1.new.should be_kind_of(m1)
- c2.ancestors[0,3].should == [m1,m2dup,c2]
- c2.new.should be_kind_of(m1)
+ ruby_version_is ''...'3.0' do
+ it "keeps the module in the chain when dupping an intermediate module" do
+ m1 = Module.new { def calc(x) x end }
+ m2 = Module.new { prepend(m1) }
+ c1 = Class.new { prepend(m2) }
+ m2dup = m2.dup
+ m2dup.ancestors.should == [m2dup,m1,m2]
+ c2 = Class.new { prepend(m2dup) }
+ c1.ancestors[0,3].should == [m1,m2,c1]
+ c1.new.should be_kind_of(m1)
+ c2.ancestors[0,4].should == [m2dup,m1,m2,c2]
+ c2.new.should be_kind_of(m1)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "uses only new module when dupping the module" do
+ m1 = Module.new { def calc(x) x end }
+ m2 = Module.new { prepend(m1) }
+ c1 = Class.new { prepend(m2) }
+ m2dup = m2.dup
+ m2dup.ancestors.should == [m1,m2dup]
+ c2 = Class.new { prepend(m2dup) }
+ c1.ancestors[0,3].should == [m1,m2,c1]
+ c1.new.should be_kind_of(m1)
+ c2.ancestors[0,3].should == [m1,m2dup,c2]
+ c2.new.should be_kind_of(m1)
+ end
end
it "depends on prepend_features to add the module" do
@@ -774,50 +743,6 @@ describe "Module#prepend" do
ary.should == [3, 2, 1]
end
- it "does not prepend a second copy if the module already indirectly exists in the hierarchy" do
- mod = Module.new do; end
- submod = Module.new do; end
- klass = Class.new do; end
- klass.include(mod)
- mod.prepend(submod)
- klass.include(mod)
-
- klass.ancestors.take(4).should == [klass, submod, mod, Object]
- end
-
- # https://bugs.ruby-lang.org/issues/17423
- describe "when module already exists in ancestor chain" do
- ruby_version_is ""..."3.1" do
- it "does not modify the ancestor chain" do
- m = Module.new do; end
- a = Module.new do; end
- b = Class.new do; end
-
- b.include(a)
- a.prepend(m)
- b.ancestors.take(4).should == [b, m, a, Object]
-
- b.prepend(m)
- b.ancestors.take(4).should == [b, m, a, Object]
- end
- end
-
- ruby_version_is "3.1" do
- it "modifies the ancestor chain" do
- m = Module.new do; end
- a = Module.new do; end
- b = Class.new do; end
-
- b.include(a)
- a.prepend(m)
- b.ancestors.take(4).should == [b, m, a, Object]
-
- b.prepend(m)
- b.ancestors.take(5).should == [m, b, m, a, Object]
- end
- end
- end
-
describe "called on a module" do
describe "included into a class"
it "does not obscure the module's methods from reflective access" do
diff --git a/spec/ruby/core/module/private_class_method_spec.rb b/spec/ruby/core/module/private_class_method_spec.rb
index f899c71a57..407779cccc 100644
--- a/spec/ruby/core/module/private_class_method_spec.rb
+++ b/spec/ruby/core/module/private_class_method_spec.rb
@@ -79,13 +79,15 @@ describe "Module#private_class_method" do
end.should raise_error(NameError)
end
- context "when single argument is passed and is an array" do
- it "sets the visibility of the given methods to private" do
- c = Class.new do
- def self.foo() "foo" end
- private_class_method [:foo]
+ ruby_version_is "3.0" do
+ context "when single argument is passed and is an array" do
+ it "sets the visibility of the given methods to private" do
+ c = Class.new do
+ def self.foo() "foo" end
+ private_class_method [:foo]
+ end
+ -> { c.foo }.should raise_error(NoMethodError)
end
- -> { c.foo }.should raise_error(NoMethodError)
end
end
end
diff --git a/spec/ruby/core/module/public_class_method_spec.rb b/spec/ruby/core/module/public_class_method_spec.rb
index 71b20acda5..b5d76e7b7a 100644
--- a/spec/ruby/core/module/public_class_method_spec.rb
+++ b/spec/ruby/core/module/public_class_method_spec.rb
@@ -78,17 +78,19 @@ describe "Module#public_class_method" do
end.should raise_error(NameError)
end
- context "when single argument is passed and is an array" do
- it "makes a class method public" do
- c = Class.new do
- class << self
- private
- def foo() "foo" end
+ ruby_version_is "3.0" do
+ context "when single argument is passed and is an array" do
+ it "makes a class method public" do
+ c = Class.new do
+ class << self
+ private
+ def foo() "foo" end
+ end
+ public_class_method [:foo]
end
- public_class_method [:foo]
- end
- c.foo.should == "foo"
+ c.foo.should == "foo"
+ end
end
end
end
diff --git a/spec/ruby/core/module/refine_spec.rb b/spec/ruby/core/module/refine_spec.rb
index 11085c325b..841900cf87 100644
--- a/spec/ruby/core/module/refine_spec.rb
+++ b/spec/ruby/core/module/refine_spec.rb
@@ -71,7 +71,7 @@ describe "Module#refine" do
Module.new do
refine("foo") {}
end
- end.should raise_error(TypeError, "wrong argument type String (expected Class or Module)")
+ end.should raise_error(TypeError)
end
it "accepts a module as argument" do
diff --git a/spec/ruby/core/module/refinements_spec.rb b/spec/ruby/core/module/refinements_spec.rb
deleted file mode 100644
index 5648fcbd6f..0000000000
--- a/spec/ruby/core/module/refinements_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "Module#refinements" do
- ruby_version_is "3.2" do
- it "returns refinements defined in a module" do
- ScratchPad.record []
-
- m = Module.new do
- refine String do
- ScratchPad << self
- end
-
- refine Array do
- ScratchPad << self
- end
- end
-
- m.refinements.sort_by(&:object_id).should == ScratchPad.recorded.sort_by(&:object_id)
- end
-
- it "does not return refinements defined in the included module" do
- ScratchPad.record []
-
- m1 = Module.new do
- refine Integer do
- nil
- end
- end
-
- m2 = Module.new do
- include m1
-
- refine String do
- ScratchPad << self
- end
- end
-
- m2.refinements.should == ScratchPad.recorded
- end
-
- it "returns an empty array if no refinements defined in a module" do
- Module.new.refinements.should == []
- end
- end
-end
diff --git a/spec/ruby/core/module/ruby2_keywords_spec.rb b/spec/ruby/core/module/ruby2_keywords_spec.rb
index aca419f522..80a99e2624 100644
--- a/spec/ruby/core/module/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/module/ruby2_keywords_spec.rb
@@ -22,6 +22,9 @@ describe "Module#ruby2_keywords" do
end
h = {a: 1}
+ ruby_version_is "3.0" do
+ obj.regular(**h).should.equal?(h)
+ end
last = mark(**h).last
Hash.ruby2_keywords_hash?(last).should == true
@@ -220,6 +223,25 @@ describe "Module#ruby2_keywords" do
Hash.ruby2_keywords_hash?(last).should == true
end
+ ruby_version_is ""..."3.0" do
+ it "fixes delegation warnings when calling a method accepting keywords" do
+ obj = Object.new
+
+ obj.singleton_class.class_exec do
+ def foo(*a) bar(*a) end
+ def bar(*a, **b) end
+ end
+
+ -> { obj.foo(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/)
+
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
+ end
+
+ -> { obj.foo(1, 2, {a: "a"}) }.should_not complain
+ end
+ end
+
it "returns nil" do
obj = Object.new
@@ -237,7 +259,7 @@ describe "Module#ruby2_keywords" do
obj.singleton_class.class_exec do
ruby2_keywords :not_existing
end
- }.should raise_error(NameError, /undefined method [`']not_existing'/)
+ }.should raise_error(NameError, /undefined method `not_existing'/)
end
it "accepts String as well" do
diff --git a/spec/ruby/core/module/set_temporary_name_spec.rb b/spec/ruby/core/module/set_temporary_name_spec.rb
deleted file mode 100644
index f5886a3398..0000000000
--- a/spec/ruby/core/module/set_temporary_name_spec.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require_relative '../../spec_helper'
-
-ruby_version_is "3.3" do
- describe "Module#set_temporary_name" do
- it "can assign a temporary name" do
- m = Module.new
- m.name.should be_nil
-
- m.set_temporary_name("fake_name")
- m.name.should == "fake_name"
-
- m.set_temporary_name(nil)
- m.name.should be_nil
- end
-
- it "can assign a temporary name which is not a valid constant path" do
- m = Module.new
- m.set_temporary_name("a::B")
- m.name.should == "a::B"
-
- m.set_temporary_name("Template['foo.rb']")
- m.name.should == "Template['foo.rb']"
- end
-
- it "can't assign empty string as name" do
- m = Module.new
- -> { m.set_temporary_name("") }.should raise_error(ArgumentError, "empty class/module name")
- end
-
- it "can't assign a constant name as a temporary name" do
- m = Module.new
- -> { m.set_temporary_name("Object") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
- end
-
- it "can't assign a constant path as a temporary name" do
- m = Module.new
- -> { m.set_temporary_name("A::B") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
- -> { m.set_temporary_name("::A") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
- -> { m.set_temporary_name("::A::B") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
- end
-
- it "can't assign name to permanent module" do
- -> { Object.set_temporary_name("fake_name") }.should raise_error(RuntimeError, "can't change permanent name")
- end
-
- it "can assign a temporary name to a nested module" do
- m = Module.new
- module m::N; end
- m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
-
- m::N.set_temporary_name("fake_name")
- m::N.name.should == "fake_name"
-
- m::N.set_temporary_name(nil)
- m::N.name.should be_nil
- end
-
- it "can update the name when assigned to a constant" do
- m = Module.new
- m::N = Module.new
- m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
- m::N.set_temporary_name(nil)
-
- m::M = m::N
- m::M.name.should =~ /\A#<Module:0x\h+>::M\z/m
- end
- end
-end
diff --git a/spec/ruby/core/module/shared/attr_added.rb b/spec/ruby/core/module/shared/attr_added.rb
deleted file mode 100644
index ce832cdcff..0000000000
--- a/spec/ruby/core/module/shared/attr_added.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-describe :module_attr_added, shared: true do
- it "calls method_added for normal classes" do
- ScratchPad.record []
-
- cls = Class.new do
- class << self
- def method_added(name)
- ScratchPad.recorded << name
- end
- end
- end
-
- cls.send(@method, :foo)
-
- ScratchPad.recorded.each {|name| name.to_s.should =~ /foo[=]?/}
- end
-
- it "calls singleton_method_added for singleton classes" do
- ScratchPad.record []
- cls = Class.new do
- class << self
- def singleton_method_added(name)
- # called for this def so ignore it
- return if name == :singleton_method_added
- ScratchPad.recorded << name
- end
- end
- end
-
- cls.singleton_class.send(@method, :foo)
-
- ScratchPad.recorded.each {|name| name.to_s.should =~ /foo[=]?/}
- end
-end
diff --git a/spec/ruby/core/module/shared/class_eval.rb b/spec/ruby/core/module/shared/class_eval.rb
index b1d5cb3814..9ef7b5be44 100644
--- a/spec/ruby/core/module/shared/class_eval.rb
+++ b/spec/ruby/core/module/shared/class_eval.rb
@@ -52,12 +52,6 @@ describe :module_class_eval, shared: true do
ModuleSpecs.send(@method, "[__FILE__, __LINE__]", "test", 102).should == ["test", 102]
end
- ruby_version_is "3.3" do
- it "uses the caller location as default filename" do
- ModuleSpecs.send(@method, "[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
- end
- end
-
it "converts a non-string filename to a string using to_str" do
(file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__)
ModuleSpecs.send(@method, "1+1", file)
diff --git a/spec/ruby/core/module/shared/set_visibility.rb b/spec/ruby/core/module/shared/set_visibility.rb
index a1586dd2bd..9f31e230ca 100644
--- a/spec/ruby/core/module/shared/set_visibility.rb
+++ b/spec/ruby/core/module/shared/set_visibility.rb
@@ -22,19 +22,21 @@ describe :set_visibility, shared: true do
end
end
- describe "array as a single argument" do
- it "sets visibility of given method names" do
- visibility = @method
- old_visibility = [:protected, :private].find {|vis| vis != visibility }
-
- mod = Module.new {
- send old_visibility
- def test1() end
- def test2() end
- send visibility, [:test1, :test2]
- }
- mod.should send(:"have_#{visibility}_instance_method", :test1, false)
- mod.should send(:"have_#{visibility}_instance_method", :test2, false)
+ ruby_version_is "3.0" do
+ describe "array as a single argument" do
+ it "sets visibility of given method names" do
+ visibility = @method
+ old_visibility = [:protected, :private].find {|vis| vis != visibility }
+
+ mod = Module.new {
+ send old_visibility
+ def test1() end
+ def test2() end
+ send visibility, [:test1, :test2]
+ }
+ mod.should send(:"have_#{visibility}_instance_method", :test1, false)
+ mod.should send(:"have_#{visibility}_instance_method", :test2, false)
+ end
end
end
diff --git a/spec/ruby/core/module/undef_method_spec.rb b/spec/ruby/core/module/undef_method_spec.rb
index d4efcd51cb..c2ad200536 100644
--- a/spec/ruby/core/module/undef_method_spec.rb
+++ b/spec/ruby/core/module/undef_method_spec.rb
@@ -50,7 +50,7 @@ describe "Module#undef_method" do
end
it "raises a NameError when passed a missing name for a module" do
- -> { @module.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method [`']not_exist' for module [`']#{@module}'/) { |e|
+ -> { @module.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method `not_exist' for module `#{@module}'/) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -58,7 +58,7 @@ describe "Module#undef_method" do
it "raises a NameError when passed a missing name for a class" do
klass = Class.new
- -> { klass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method [`']not_exist' for class [`']#{klass}'/) { |e|
+ -> { klass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method `not_exist' for class `#{klass}'/) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -69,8 +69,8 @@ describe "Module#undef_method" do
obj = klass.new
sclass = obj.singleton_class
- -> { sclass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method [`']not_exist' for class [`']#{sclass}'/) { |e|
- e.message.should =~ /[`']#<Class:#<#<Class:/
+ -> { sclass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method `not_exist' for class `#{sclass}'/) { |e|
+ e.message.should include('`#<Class:#<#<Class:')
# a NameError and not a NoMethodError
e.class.should == NameError
@@ -79,7 +79,7 @@ describe "Module#undef_method" do
it "raises a NameError when passed a missing name for a metaclass" do
klass = String.singleton_class
- -> { klass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method [`']not_exist' for class [`']String'/) { |e|
+ -> { klass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method `not_exist' for class `String'/) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
diff --git a/spec/ruby/core/module/undefined_instance_methods_spec.rb b/spec/ruby/core/module/undefined_instance_methods_spec.rb
deleted file mode 100644
index 3be860d053..0000000000
--- a/spec/ruby/core/module/undefined_instance_methods_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-describe "Module#undefined_instance_methods" do
- ruby_version_is "3.2" do
- it "returns methods undefined in the class" do
- methods = ModuleSpecs::UndefinedInstanceMethods::Parent.undefined_instance_methods
- methods.should == [:undefed_method]
- end
-
- it "returns inherited methods undefined in the class" do
- methods = ModuleSpecs::UndefinedInstanceMethods::Child.undefined_instance_methods
- methods.should include(:parent_method, :another_parent_method)
- end
-
- it "returns methods from an included module that are undefined in the class" do
- methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
- methods.should include(:super_included_method)
- end
-
- it "does not returns ancestors undefined methods" do
- methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
- methods.should_not include(:parent_method, :another_parent_method)
- end
- end
-end
diff --git a/spec/ruby/core/module/used_refinements_spec.rb b/spec/ruby/core/module/used_refinements_spec.rb
deleted file mode 100644
index c16cab0e3c..0000000000
--- a/spec/ruby/core/module/used_refinements_spec.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "Module.used_refinements" do
- ruby_version_is "3.2" do
- it "returns list of all refinements imported in the current scope" do
- refinement_int = nil
- refinement_str = nil
- ScratchPad.record []
-
- m1 = Module.new do
- refine Integer do
- refinement_int = self
- end
- end
-
- m2 = Module.new do
- refine String do
- refinement_str = self
- end
- end
-
- Module.new do
- using m1
- using m2
-
- Module.used_refinements.each { |r| ScratchPad << r }
- end
-
- ScratchPad.recorded.sort_by(&:object_id).should == [refinement_int, refinement_str].sort_by(&:object_id)
- end
-
- it "returns empty array if does not have any refinements imported" do
- used_refinements = nil
-
- Module.new do
- used_refinements = Module.used_refinements
- end
-
- used_refinements.should == []
- end
-
- it "ignores refinements imported in a module that is included into the current one" do
- used_refinements = nil
-
- m1 = Module.new do
- refine Integer do
- nil
- end
- end
-
- m2 = Module.new do
- using m1
- end
-
- Module.new do
- include m2
-
- used_refinements = Module.used_refinements
- end
-
- used_refinements.should == []
- end
-
- it "returns refinements even not defined directly in a module refinements are imported from" do
- used_refinements = nil
- ScratchPad.record []
-
- m1 = Module.new do
- refine Integer do
- ScratchPad << self
- end
- end
-
- m2 = Module.new do
- include m1
- end
-
- Module.new do
- using m2
-
- used_refinements = Module.used_refinements
- end
-
- used_refinements.should == ScratchPad.recorded
- end
- end
-end
diff --git a/spec/ruby/core/module/using_spec.rb b/spec/ruby/core/module/using_spec.rb
index a908363c96..4781b99bb7 100644
--- a/spec/ruby/core/module/using_spec.rb
+++ b/spec/ruby/core/module/using_spec.rb
@@ -316,7 +316,7 @@ describe "Module#using" do
using refinement
def initialize
- @a = +"1703"
+ @a = "1703"
@a.instance_eval do
def abc
diff --git a/spec/ruby/core/mutex/lock_spec.rb b/spec/ruby/core/mutex/lock_spec.rb
index e9d33f5fd9..7a39817b11 100644
--- a/spec/ruby/core/mutex/lock_spec.rb
+++ b/spec/ruby/core/mutex/lock_spec.rb
@@ -1,6 +1,10 @@
require_relative '../../spec_helper'
describe "Mutex#lock" do
+ before :each do
+ ScratchPad.clear
+ end
+
it "returns self" do
m = Mutex.new
m.lock.should == m
diff --git a/spec/ruby/core/mutex/owned_spec.rb b/spec/ruby/core/mutex/owned_spec.rb
index 7bfc7d8f83..1f843cd576 100644
--- a/spec/ruby/core/mutex/owned_spec.rb
+++ b/spec/ruby/core/mutex/owned_spec.rb
@@ -41,13 +41,15 @@ describe "Mutex#owned?" do
end
end
- it "is held per Fiber" do
- m = Mutex.new
- m.lock
-
- Fiber.new do
- m.locked?.should == true
- m.owned?.should == false
- end.resume
+ ruby_version_is "3.0" do
+ it "is held per Fiber" do
+ m = Mutex.new
+ m.lock
+
+ Fiber.new do
+ m.locked?.should == true
+ m.owned?.should == false
+ end.resume
+ end
end
end
diff --git a/spec/ruby/core/nil/singleton_method_spec.rb b/spec/ruby/core/nil/singleton_method_spec.rb
deleted file mode 100644
index 8d898b1cc9..0000000000
--- a/spec/ruby/core/nil/singleton_method_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "NilClass#singleton_method" do
- ruby_version_is '3.3' do
- it "raises regardless of whether NilClass defines the method" do
- -> { nil.singleton_method(:foo) }.should raise_error(NameError)
- begin
- def (nil).foo; end
- -> { nil.singleton_method(:foo) }.should raise_error(NameError)
- ensure
- NilClass.send(:remove_method, :foo)
- end
- end
- end
-end
diff --git a/spec/ruby/core/numeric/clone_spec.rb b/spec/ruby/core/numeric/clone_spec.rb
index 423cec85dd..c3b06ca0c9 100644
--- a/spec/ruby/core/numeric/clone_spec.rb
+++ b/spec/ruby/core/numeric/clone_spec.rb
@@ -14,7 +14,7 @@ describe "Numeric#clone" do
1.clone.frozen?.should == true
end
- it "accepts optional keyword argument :freeze" do
+ it "accepts optonal keyword argument :freeze" do
value = 1
value.clone(freeze: true).should equal(value)
end
@@ -23,8 +23,10 @@ describe "Numeric#clone" do
-> { 1.clone(freeze: false) }.should raise_error(ArgumentError, /can't unfreeze/)
end
- it "does not change frozen status if passed freeze: nil" do
- value = 1
- value.clone(freeze: nil).should equal(value)
+ ruby_version_is "3.0" do
+ it "does not change frozen status if passed freeze: nil" do
+ value = 1
+ value.clone(freeze: nil).should equal(value)
+ end
end
end
diff --git a/spec/ruby/core/numeric/fdiv_spec.rb b/spec/ruby/core/numeric/fdiv_spec.rb
index e97fa77f79..907e5d343c 100644
--- a/spec/ruby/core/numeric/fdiv_spec.rb
+++ b/spec/ruby/core/numeric/fdiv_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative 'shared/quo'
describe "Numeric#fdiv" do
it "coerces self with #to_f" do
diff --git a/spec/ruby/core/numeric/magnitude_spec.rb b/spec/ruby/core/numeric/magnitude_spec.rb
index 1371dff21f..7a3290b036 100644
--- a/spec/ruby/core/numeric/magnitude_spec.rb
+++ b/spec/ruby/core/numeric/magnitude_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative 'shared/abs'
describe "Numeric#magnitude" do
diff --git a/spec/ruby/core/numeric/quo_spec.rb b/spec/ruby/core/numeric/quo_spec.rb
index 6e3ce7a374..67bacee9b5 100644
--- a/spec/ruby/core/numeric/quo_spec.rb
+++ b/spec/ruby/core/numeric/quo_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/quo'
describe "Numeric#quo" do
it "returns the result of self divided by the given Integer as a Rational" do
diff --git a/spec/ruby/core/numeric/remainder_spec.rb b/spec/ruby/core/numeric/remainder_spec.rb
index 674fa22d8e..1e2f5f3a96 100644
--- a/spec/ruby/core/numeric/remainder_spec.rb
+++ b/spec/ruby/core/numeric/remainder_spec.rb
@@ -6,9 +6,6 @@ describe "Numeric#remainder" do
@obj = NumericSpecs::Subclass.new
@result = mock("Numeric#% result")
@other = mock("Passed Object")
- ruby_version_is "3.3" do
- @other.should_receive(:coerce).with(@obj).and_return([@obj, @other])
- end
end
it "returns the result of calling self#% with other if self is 0" do
diff --git a/spec/ruby/core/numeric/shared/quo.rb b/spec/ruby/core/numeric/shared/quo.rb
new file mode 100644
index 0000000000..2392636fe7
--- /dev/null
+++ b/spec/ruby/core/numeric/shared/quo.rb
@@ -0,0 +1,7 @@
+describe :numeric_quo_18, shared: true do
+ it "returns the result of calling self#/ with other" do
+ obj = mock_numeric('numeric')
+ obj.should_receive(:/).with(19).and_return(:result)
+ obj.send(@method, 19).should == :result
+ end
+end
diff --git a/spec/ruby/core/numeric/shared/step.rb b/spec/ruby/core/numeric/shared/step.rb
index 977ec6de02..8b1a7bf307 100644
--- a/spec/ruby/core/numeric/shared/step.rb
+++ b/spec/ruby/core/numeric/shared/step.rb
@@ -5,7 +5,7 @@ require_relative '../fixtures/classes'
# To be able to do it, the @step ivar must contain a Proc that transforms
# the step call arguments passed as positional arguments to the style of
# arguments pretended to test.
-describe :numeric_step, shared: true do
+describe :numeric_step, :shared => true do
before :each do
ScratchPad.record []
@prc = -> x { ScratchPad << x }
@@ -258,6 +258,12 @@ describe :numeric_step, shared: true do
describe "when no block is given" do
step_enum_class = Enumerator::ArithmeticSequence
+ ruby_version_is ""..."3.0" do
+ it "returns an #{step_enum_class} when step is 0" do
+ @step.call(1, 2, 0).should be_an_instance_of(step_enum_class)
+ end
+ end
+
it "returns an #{step_enum_class} when not passed a block and self > stop" do
@step.call(1, 0, 2).should be_an_instance_of(step_enum_class)
end
diff --git a/spec/ruby/core/numeric/step_spec.rb b/spec/ruby/core/numeric/step_spec.rb
index 1705fb1b4e..095c474fec 100644
--- a/spec/ruby/core/numeric/step_spec.rb
+++ b/spec/ruby/core/numeric/step_spec.rb
@@ -23,8 +23,30 @@ describe "Numeric#step" do
describe "when no block is given" do
step_enum_class = Enumerator::ArithmeticSequence
+ ruby_version_is ""..."3.0" do
+ it "returns an #{step_enum_class} when step is 0" do
+ 1.step(5, 0).should be_an_instance_of(step_enum_class)
+ end
+
+ it "returns an #{step_enum_class} when step is 0.0" do
+ 1.step(2, 0.0).should be_an_instance_of(step_enum_class)
+ end
+ end
+
describe "returned #{step_enum_class}" do
describe "size" do
+ ruby_version_is ""..."3.0" do
+ it "is infinity when step is 0" do
+ enum = 1.step(5, 0)
+ enum.size.should == Float::INFINITY
+ end
+
+ it "is infinity when step is 0.0" do
+ enum = 1.step(2, 0.0)
+ enum.size.should == Float::INFINITY
+ end
+ end
+
it "defaults to an infinite size" do
enum = 1.step
enum.size.should == Float::INFINITY
@@ -41,6 +63,22 @@ describe "Numeric#step" do
end
describe 'with keyword arguments' do
+ ruby_version_is ""..."3.0" do
+ it "doesn't raise an error when step is 0" do
+ -> { 1.step(to: 5, by: 0) { break } }.should_not raise_error
+ end
+
+ it "doesn't raise an error when step is 0.0" do
+ -> { 1.step(to: 2, by: 0.0) { break } }.should_not raise_error
+ end
+
+ it "should loop over self when step is 0 or 0.0" do
+ 1.step(to: 2, by: 0.0).take(5).should eql [1.0, 1.0, 1.0, 1.0, 1.0]
+ 1.step(to: 2, by: 0).take(5).should eql [1, 1, 1, 1, 1]
+ 1.1.step(to: 2, by: 0).take(5).should eql [1.1, 1.1, 1.1, 1.1, 1.1]
+ end
+ end
+
describe "when no block is given" do
describe "returned Enumerator" do
describe "size" do
@@ -48,6 +86,16 @@ describe "Numeric#step" do
1.step(by: 42).size.should == infinity_value
end
+ ruby_version_is ""..."3.0" do
+ it "should return infinity_value when step is 0" do
+ 1.step(to: 5, by: 0).size.should == infinity_value
+ end
+
+ it "should return infinity_value when step is 0.0" do
+ 1.step(to: 2, by: 0.0).size.should == infinity_value
+ end
+ end
+
it "should return infinity_value when ascending towards a limit of Float::INFINITY" do
1.step(to: Float::INFINITY, by: 42).size.should == infinity_value
end
@@ -80,12 +128,24 @@ describe "Numeric#step" do
end
describe 'with mixed arguments' do
- it " raises an ArgumentError when step is 0" do
- -> { 1.step(5, by: 0) { break } }.should raise_error(ArgumentError)
+ ruby_version_is ""..."3.0" do
+ it "doesn't raise an error when step is 0" do
+ -> { 1.step(5, by: 0) { break } }.should_not raise_error
+ end
+
+ it "doesn't raise an error when step is 0.0" do
+ -> { 1.step(2, by: 0.0) { break } }.should_not raise_error
+ end
end
- it "raises an ArgumentError when step is 0.0" do
- -> { 1.step(2, by: 0.0) { break } }.should raise_error(ArgumentError)
+ ruby_version_is "3.0" do
+ it " raises an ArgumentError when step is 0" do
+ -> { 1.step(5, by: 0) { break } }.should raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError when step is 0.0" do
+ -> { 1.step(2, by: 0.0) { break } }.should raise_error(ArgumentError)
+ end
end
it "raises a ArgumentError when limit and to are defined" do
@@ -96,9 +156,26 @@ describe "Numeric#step" do
-> { 1.step(5, 1, by: 5) { break } }.should raise_error(ArgumentError)
end
+ ruby_version_is ""..."3.0" do
+ it "should loop over self when step is 0 or 0.0" do
+ 1.step(2, by: 0.0).take(5).should eql [1.0, 1.0, 1.0, 1.0, 1.0]
+ 1.step(2, by: 0).take(5).should eql [1, 1, 1, 1, 1]
+ 1.1.step(2, by: 0).take(5).should eql [1.1, 1.1, 1.1, 1.1, 1.1]
+ end
+ end
+
describe "when no block is given" do
describe "returned Enumerator" do
describe "size" do
+ ruby_version_is ""..."3.0" do
+ it "should return infinity_value when step is 0" do
+ 1.step(5, by: 0).size.should == infinity_value
+ end
+
+ it "should return infinity_value when step is 0.0" do
+ 1.step(2, by: 0.0).size.should == infinity_value
+ end
+ end
end
end
end
diff --git a/spec/ruby/core/objectspace/define_finalizer_spec.rb b/spec/ruby/core/objectspace/define_finalizer_spec.rb
index effecc41d0..d9db027e0b 100644
--- a/spec/ruby/core/objectspace/define_finalizer_spec.rb
+++ b/spec/ruby/core/objectspace/define_finalizer_spec.rb
@@ -52,7 +52,7 @@ describe "ObjectSpace.define_finalizer" do
Proc.new { puts "finalizer run" }
end
handler = scoped
- obj = +"Test"
+ obj = "Test"
ObjectSpace.define_finalizer(obj, handler)
exit 0
RUBY
@@ -60,58 +60,60 @@ describe "ObjectSpace.define_finalizer" do
ruby_exe(code, :args => "2>&1").should include("finalizer run\n")
end
- it "warns if the finalizer has the object as the receiver" do
- code = <<-RUBY
- class CapturesSelf
- def initialize
- ObjectSpace.define_finalizer(self, proc {
- puts "finalizer run"
- })
+ ruby_version_is "3.0" do
+ it "warns if the finalizer has the object as the receiver" do
+ code = <<-RUBY
+ class CapturesSelf
+ def initialize
+ ObjectSpace.define_finalizer(self, proc {
+ puts "finalizer run"
+ })
+ end
end
- end
- CapturesSelf.new
- exit 0
- RUBY
+ CapturesSelf.new
+ exit 0
+ RUBY
- ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
- end
+ ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
+ end
- it "warns if the finalizer is a method bound to the receiver" do
- code = <<-RUBY
- class CapturesSelf
- def initialize
- ObjectSpace.define_finalizer(self, method(:finalize))
- end
- def finalize(id)
- puts "finalizer run"
+ it "warns if the finalizer is a method bound to the receiver" do
+ code = <<-RUBY
+ class CapturesSelf
+ def initialize
+ ObjectSpace.define_finalizer(self, method(:finalize))
+ end
+ def finalize(id)
+ puts "finalizer run"
+ end
end
- end
- CapturesSelf.new
- exit 0
- RUBY
+ CapturesSelf.new
+ exit 0
+ RUBY
- ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
- end
+ ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
+ end
- it "warns if the finalizer was a block in the receiver" do
- code = <<-RUBY
- class CapturesSelf
- def initialize
- ObjectSpace.define_finalizer(self) do
- puts "finalizer run"
+ it "warns if the finalizer was a block in the receiver" do
+ code = <<-RUBY
+ class CapturesSelf
+ def initialize
+ ObjectSpace.define_finalizer(self) do
+ puts "finalizer run"
+ end
end
end
- end
- CapturesSelf.new
- exit 0
- RUBY
+ CapturesSelf.new
+ exit 0
+ RUBY
- ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
+ ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
+ end
end
it "calls a finalizer at exit even if it is self-referencing" do
code = <<-RUBY
- obj = +"Test"
+ obj = "Test"
handler = Proc.new { puts "finalizer run" }
ObjectSpace.define_finalizer(obj, handler)
exit 0
@@ -141,9 +143,9 @@ describe "ObjectSpace.define_finalizer" do
it "calls a finalizer defined in a finalizer running at exit" do
code = <<-RUBY
- obj = +"Test"
+ obj = "Test"
handler = Proc.new do
- obj2 = +"Test"
+ obj2 = "Test"
handler2 = Proc.new { puts "finalizer 2 run" }
ObjectSpace.define_finalizer(obj2, handler2)
exit 0
diff --git a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
deleted file mode 100644
index 6e534b8ea8..0000000000
--- a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is '3.3' do
- describe "ObjectSpace::WeakKeyMap#delete" do
- it "removes the entry and returns the deleted value" do
- m = ObjectSpace::WeakKeyMap.new
- key = Object.new
- value = Object.new
- m[key] = value
-
- m.delete(key).should == value
- m.key?(key).should == false
- end
-
- it "uses equality semantic" do
- m = ObjectSpace::WeakKeyMap.new
- key = "foo".upcase
- value = Object.new
- m[key] = value
-
- m.delete("foo".upcase).should == value
- m.key?(key).should == false
- end
-
- it "calls supplied block if the key is not found" do
- key = Object.new
- m = ObjectSpace::WeakKeyMap.new
- return_value = m.delete(key) do |yielded_key|
- yielded_key.should == key
- 5
- end
- return_value.should == 5
- end
-
- it "returns nil if the key is not found when no block is given" do
- m = ObjectSpace::WeakMap.new
- m.delete(Object.new).should == nil
- end
- end
-end
diff --git a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
deleted file mode 100644
index 862480cd02..0000000000
--- a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.3" do
- describe "ObjectSpace::WeakKeyMap#[]" do
- it "is faithful to the map's content" do
- map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a b].map(&:upcase)
- ref1, ref2 = %w[x y]
- map[key1] = ref1
- map[key1].should == ref1
- map[key1] = ref1
- map[key1].should == ref1
- map[key2] = ref2
- map[key1].should == ref1
- map[key2].should == ref2
- end
-
- it "matches using equality semantics" do
- map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a a].map(&:upcase)
- ref = "x"
- map[key1] = ref
- map[key2].should == ref
- end
- end
-end
diff --git a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
deleted file mode 100644
index c427e01ca5..0000000000
--- a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.3" do
- describe "ObjectSpace::WeakKeyMap#[]=" do
- def should_accept(map, key, value)
- (map[key] = value).should == value
- map.should.key?(key)
- map[key].should == value
- end
-
- def should_not_accept(map, key, value)
- -> { map[key] = value }.should raise_error(ArgumentError)
- end
-
- it "is correct" do
- map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a b].map(&:upcase)
- ref1, ref2 = %w[x y]
- should_accept(map, key1, ref1)
- should_accept(map, key1, ref1)
- should_accept(map, key2, ref2)
- map[key1].should == ref1
- end
-
- it "requires the keys to implement #hash" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[BasicObject.new] = 1 }.should raise_error(NoMethodError, /undefined method [`']hash' for an instance of BasicObject/)
- end
-
- it "accepts frozen keys or values" do
- map = ObjectSpace::WeakKeyMap.new
- x = Object.new
- should_accept(map, x, true)
- should_accept(map, x, false)
- should_accept(map, x, 42)
- should_accept(map, x, :foo)
-
- y = Object.new.freeze
- should_accept(map, x, y)
- should_accept(map, y, x)
- end
-
- it "rejects symbols as keys" do
- map = ObjectSpace::WeakKeyMap.new
- should_not_accept(map, :foo, true)
- should_not_accept(map, rand.to_s.to_sym, true)
- end
-
- it "rejects integers as keys" do
- map = ObjectSpace::WeakKeyMap.new
- should_not_accept(map, 42, true)
- should_not_accept(map, 2 ** 68, true)
- end
-
- it "rejects floats as keys" do
- map = ObjectSpace::WeakKeyMap.new
- should_not_accept(map, 4.2, true)
- end
-
- it "rejects booleans as keys" do
- map = ObjectSpace::WeakKeyMap.new
- should_not_accept(map, true, true)
- should_not_accept(map, false, true)
- end
-
- it "rejects nil as keys" do
- map = ObjectSpace::WeakKeyMap.new
- should_not_accept(map, nil, true)
- end
- end
-end
diff --git a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
deleted file mode 100644
index 3af0186f27..0000000000
--- a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.3" do
- describe "ObjectSpace::WeakKeyMap#getkey" do
- it "returns the existing equal key" do
- map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a a].map(&:upcase)
-
- map[key1] = true
- map.getkey(key2).should equal(key1)
- map.getkey("X").should == nil
- end
- end
-end
diff --git a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
deleted file mode 100644
index 557fbc8733..0000000000
--- a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.3" do
- describe "ObjectSpace::WeakKeyMap#inspect" do
- it "only displays size in output" do
- map = ObjectSpace::WeakKeyMap.new
- key1, key2, key3 = "foo", "bar", "bar"
- map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=0>\z/
- map[key1] = 1
- map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=1>\z/
- map[key2] = 2
- map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
- map[key3] = 3
- map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
- end
- end
-end
diff --git a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
deleted file mode 100644
index 2af9c2b8e7..0000000000
--- a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is "3.3" do
- describe "ObjectSpace::WeakKeyMap#key?" do
- it "recognizes keys in use" do
- map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a b].map(&:upcase)
- ref1, ref2 = %w[x y]
-
- map[key1] = ref1
- map.key?(key1).should == true
- map[key1] = ref1
- map.key?(key1).should == true
- map[key2] = ref2
- map.key?(key2).should == true
- end
-
- it "matches using equality semantics" do
- map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a a].map(&:upcase)
- ref = "x"
- map[key1] = ref
- map.key?(key2).should == true
- end
-
- it "reports true if the pair exists and the value is nil" do
- map = ObjectSpace::WeakKeyMap.new
- key = Object.new
- map[key] = nil
- map.key?(key).should == true
- end
- end
-end
diff --git a/spec/ruby/core/objectspace/weakmap/delete_spec.rb b/spec/ruby/core/objectspace/weakmap/delete_spec.rb
deleted file mode 100644
index 302de264fb..0000000000
--- a/spec/ruby/core/objectspace/weakmap/delete_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is '3.3' do
- describe "ObjectSpace::WeakMap#delete" do
- it "removes the entry and returns the deleted value" do
- m = ObjectSpace::WeakMap.new
- key = Object.new
- value = Object.new
- m[key] = value
-
- m.delete(key).should == value
- m.key?(key).should == false
- end
-
- it "calls supplied block if the key is not found" do
- key = Object.new
- m = ObjectSpace::WeakMap.new
- return_value = m.delete(key) do |yielded_key|
- yielded_key.should == key
- 5
- end
- return_value.should == 5
- end
-
- it "returns nil if the key is not found when no block is given" do
- m = ObjectSpace::WeakMap.new
- m.delete(Object.new).should == nil
- end
- end
-end
diff --git a/spec/ruby/core/proc/arity_spec.rb b/spec/ruby/core/proc/arity_spec.rb
index 5c7728cb30..f7cb5ad0f8 100644
--- a/spec/ruby/core/proc/arity_spec.rb
+++ b/spec/ruby/core/proc/arity_spec.rb
@@ -268,14 +268,6 @@ describe "Proc#arity" do
@a.arity.should == 3
@b.arity.should == 3
end
-
- # implicit rest
- evaluate <<-ruby do
- @a = lambda { |a, | }
- ruby
-
- @a.arity.should == 1
- end
end
context "returns negative values" do
@@ -538,14 +530,6 @@ describe "Proc#arity" do
@a.arity.should == 1
@b.arity.should == 5
end
-
- # implicit rest
- evaluate <<-ruby do
- @a = proc { |a, | }
- ruby
-
- @a.arity.should == 1
- end
end
context "returns negative values" do
diff --git a/spec/ruby/core/proc/clone_spec.rb b/spec/ruby/core/proc/clone_spec.rb
index 7eca9c561e..a1a1292654 100644
--- a/spec/ruby/core/proc/clone_spec.rb
+++ b/spec/ruby/core/proc/clone_spec.rb
@@ -3,13 +3,4 @@ require_relative 'shared/dup'
describe "Proc#clone" do
it_behaves_like :proc_dup, :clone
-
- ruby_bug "cloning a frozen proc is broken on Ruby 3.3", "3.3"..."3.4" do
- it "preserves frozen status" do
- proc = Proc.new { }
- proc.freeze
- proc.frozen?.should == true
- proc.clone.frozen?.should == true
- end
- end
end
diff --git a/spec/ruby/core/proc/compose_spec.rb b/spec/ruby/core/proc/compose_spec.rb
index 9e9b57e06f..94814d11bc 100644
--- a/spec/ruby/core/proc/compose_spec.rb
+++ b/spec/ruby/core/proc/compose_spec.rb
@@ -37,22 +37,42 @@ describe "Proc#<<" do
(f << g).should_not.lambda?
end
- it "is a lambda when parameter is lambda" do
- f = -> x { x * x }
- g = proc { |x| x + x }
- lambda_proc = -> x { x }
+ ruby_version_is(''...'3.0') do
+ it "is a Proc when other is lambda" do
+ f = proc { |x| x * x }
+ g = -> x { x + x }
+
+ (f << g).is_a?(Proc).should == true
+ (f << g).should_not.lambda?
+ end
+
+ it "is a lambda when self is lambda" do
+ f = -> x { x * x }
+ g = proc { |x| x + x }
+
+ (f << g).is_a?(Proc).should == true
+ (f << g).should.lambda?
+ end
+ end
- # lambda << proc
- (f << g).is_a?(Proc).should == true
- (f << g).should_not.lambda?
+ ruby_version_is('3.0') do
+ it "is a lambda when parameter is lambda" do
+ f = -> x { x * x }
+ g = proc { |x| x + x }
+ lambda_proc = -> x { x }
+
+ # lambda << proc
+ (f << g).is_a?(Proc).should == true
+ (f << g).should_not.lambda?
- # lambda << lambda
- (f << lambda_proc).is_a?(Proc).should == true
- (f << lambda_proc).should.lambda?
+ # lambda << lambda
+ (f << lambda_proc).is_a?(Proc).should == true
+ (f << lambda_proc).should.lambda?
- # proc << lambda
- (g << f).is_a?(Proc).should == true
- (g << f).should.lambda?
+ # proc << lambda
+ (g << f).is_a?(Proc).should == true
+ (g << f).should.lambda?
+ end
end
it "may accept multiple arguments" do
diff --git a/spec/ruby/core/proc/dup_spec.rb b/spec/ruby/core/proc/dup_spec.rb
index dd19b3c1e9..6da2f3080c 100644
--- a/spec/ruby/core/proc/dup_spec.rb
+++ b/spec/ruby/core/proc/dup_spec.rb
@@ -3,11 +3,4 @@ require_relative 'shared/dup'
describe "Proc#dup" do
it_behaves_like :proc_dup, :dup
-
- it "resets frozen status" do
- proc = Proc.new { }
- proc.freeze
- proc.frozen?.should == true
- proc.dup.frozen?.should == false
- end
end
diff --git a/spec/ruby/core/proc/eql_spec.rb b/spec/ruby/core/proc/eql_spec.rb
index ad8f6749fc..06aee272e5 100644
--- a/spec/ruby/core/proc/eql_spec.rb
+++ b/spec/ruby/core/proc/eql_spec.rb
@@ -2,5 +2,11 @@ require_relative '../../spec_helper'
require_relative 'shared/equal'
describe "Proc#eql?" do
- it_behaves_like :proc_equal, :eql?
+ ruby_version_is ""..."3.0" do
+ it_behaves_like :proc_equal_undefined, :eql?
+ end
+
+ ruby_version_is "3.0" do
+ it_behaves_like :proc_equal, :eql?
+ end
end
diff --git a/spec/ruby/core/proc/equal_value_spec.rb b/spec/ruby/core/proc/equal_value_spec.rb
index ec7f274732..ee88c0537d 100644
--- a/spec/ruby/core/proc/equal_value_spec.rb
+++ b/spec/ruby/core/proc/equal_value_spec.rb
@@ -2,5 +2,11 @@ require_relative '../../spec_helper'
require_relative 'shared/equal'
describe "Proc#==" do
- it_behaves_like :proc_equal, :==
+ ruby_version_is ""..."3.0" do
+ it_behaves_like :proc_equal_undefined, :==
+ end
+
+ ruby_version_is "3.0" do
+ it_behaves_like :proc_equal, :==
+ end
end
diff --git a/spec/ruby/core/proc/fixtures/proc_aref.rb b/spec/ruby/core/proc/fixtures/proc_aref.rb
index 8ee355b14c..a305667797 100644
--- a/spec/ruby/core/proc/fixtures/proc_aref.rb
+++ b/spec/ruby/core/proc/fixtures/proc_aref.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
module ProcArefSpecs
def self.aref
proc {|a| a }["sometext"]
diff --git a/spec/ruby/core/proc/lambda_spec.rb b/spec/ruby/core/proc/lambda_spec.rb
index 5c3c38fc2a..b2d3f50350 100644
--- a/spec/ruby/core/proc/lambda_spec.rb
+++ b/spec/ruby/core/proc/lambda_spec.rb
@@ -14,11 +14,9 @@ describe "Proc#lambda?" do
Proc.new {}.lambda?.should be_false
end
- ruby_version_is ""..."3.3" do
- it "is preserved when passing a Proc with & to the lambda keyword" do
- suppress_warning {lambda(&->{})}.lambda?.should be_true
- suppress_warning {lambda(&proc{})}.lambda?.should be_false
- end
+ it "is preserved when passing a Proc with & to the lambda keyword" do
+ suppress_warning {lambda(&->{})}.lambda?.should be_true
+ suppress_warning {lambda(&proc{})}.lambda?.should be_false
end
it "is preserved when passing a Proc with & to the proc keyword" do
diff --git a/spec/ruby/core/proc/new_spec.rb b/spec/ruby/core/proc/new_spec.rb
index b2b7387756..cb52e94f44 100644
--- a/spec/ruby/core/proc/new_spec.rb
+++ b/spec/ruby/core/proc/new_spec.rb
@@ -166,13 +166,36 @@ describe "Proc.new without a block" do
-> { ProcSpecs.new_proc_subclass_in_method }.should raise_error(ArgumentError)
end
- it "raises an ArgumentError when passed no block" do
- def some_method
- Proc.new
+ ruby_version_is ""..."3.0" do
+ it "can be created if invoked from within a method with a block" do
+ -> { ProcSpecs.new_proc_in_method { "hello" } }.should complain(/Capturing the given block using Proc.new is deprecated/)
+ end
+
+ it "can be created if invoked on a subclass from within a method with a block" do
+ -> { ProcSpecs.new_proc_subclass_in_method { "hello" } }.should complain(/Capturing the given block using Proc.new is deprecated/)
+ end
+
+
+ it "can be create when called with no block" do
+ def some_method
+ Proc.new
+ end
+
+ -> {
+ some_method { "hello" }
+ }.should complain(/Capturing the given block using Proc.new is deprecated/)
end
+ end
- -> { ProcSpecs.new_proc_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
- -> { ProcSpecs.new_proc_subclass_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
- -> { some_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
+ ruby_version_is "3.0" do
+ it "raises an ArgumentError when passed no block" do
+ def some_method
+ Proc.new
+ end
+
+ -> { ProcSpecs.new_proc_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
+ -> { ProcSpecs.new_proc_subclass_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
+ -> { some_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
+ end
end
end
diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb
index 972596d2ea..3a56b613cd 100644
--- a/spec/ruby/core/proc/parameters_spec.rb
+++ b/spec/ruby/core/proc/parameters_spec.rb
@@ -21,7 +21,7 @@ describe "Proc#parameters" do
end
ruby_version_is "3.2" do
- it "sets the first element of each sub-Array to :req for required argument if lambda keyword used" do
+ it "sets the first element of each sub-Array to :req if argument would be required if a lambda if lambda keyword used" do
proc {|x| }.parameters(lambda: true).first.first.should == :req
proc {|y,*x| }.parameters(lambda: true).first.first.should == :req
end
@@ -33,16 +33,6 @@ describe "Proc#parameters" do
it "regards named parameters in lambda as optional if lambda: false keyword used" do
-> x { }.parameters(lambda: false).first.first.should == :opt
end
-
- it "regards named parameters in procs and lambdas as required if lambda keyword is truthy" do
- proc {|x| }.parameters(lambda: 123).first.first.should == :req
- -> x { }.parameters(lambda: 123).first.first.should == :req
- end
-
- it "ignores the lambda keyword if it is nil" do
- proc {|x|}.parameters(lambda: nil).first.first.should == :opt
- -> x { }.parameters(lambda: nil).first.first.should == :req
- end
end
it "regards optional keyword parameters in procs as optional" do
@@ -101,38 +91,19 @@ describe "Proc#parameters" do
proc {|&block| }.parameters.first.last.should == :block
end
- it "ignores unnamed rest arguments" do
+ it "ignores unnamed rest args" do
-> x {}.parameters.should == [[:req, :x]]
end
- it "ignores implicit rest arguments" do
- proc { |x, | }.parameters.should == [[:opt, :x]]
- -> x { }.parameters.should == [[:req, :x]]
- end
-
ruby_version_is '3.2' do
- it "adds rest arg with name * for \"star\" argument" do
- -> * {}.parameters.should == [[:rest, :*]]
- end
-
- it "adds keyrest arg with ** as a name for \"double star\" argument" do
- -> ** {}.parameters.should == [[:keyrest, :**]]
+ it "adds * rest arg for \"star\" argument" do
+ -> x, * {}.parameters.should == [[:req, :x], [:rest, :*]]
end
end
ruby_version_is ''...'3.2' do
it "adds nameless rest arg for \"star\" argument" do
- -> * {}.parameters.should == [[:rest]]
- end
-
- it "adds nameless keyrest arg for \"double star\" argument" do
- -> ** {}.parameters.should == [[:keyrest]]
- end
- end
-
- ruby_version_is '3.1' do
- it "adds block arg with name & for anonymous block argument" do
- eval('-> & {}.parameters').should == [[:block, :&]]
+ -> x, * {}.parameters.should == [[:req, :x], [:rest]]
end
end
@@ -144,34 +115,4 @@ describe "Proc#parameters" do
local_is_not_parameter = {}
end.parameters.should == [[:rest, :args], [:block, :blk]]
end
-
- it "returns all parameters defined with the name _ as _" do
- proc = proc {|_, _, _ = 1, *_, _:, _: 2, **_, &_| }
- proc.parameters.should == [
- [:opt, :_],
- [:opt, :_],
- [:opt, :_],
- [:rest, :_],
- [:keyreq, :_],
- [:key, :_],
- [:keyrest, :_],
- [:block, :_]
- ]
-
- lambda = -> _, _, _ = 1, *_, _:, _: 2, **_, &_ {}
- lambda.parameters.should == [
- [:req, :_],
- [:req, :_],
- [:opt, :_],
- [:rest, :_],
- [:keyreq, :_],
- [:key, :_],
- [:keyrest, :_],
- [:block, :_]
- ]
- end
-
- it "returns :nokey for **nil parameter" do
- proc { |**nil| }.parameters.should == [[:nokey]]
- end
end
diff --git a/spec/ruby/core/proc/ruby2_keywords_spec.rb b/spec/ruby/core/proc/ruby2_keywords_spec.rb
index ab67302231..c6eb03e693 100644
--- a/spec/ruby/core/proc/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/proc/ruby2_keywords_spec.rb
@@ -25,6 +25,28 @@ describe "Proc#ruby2_keywords" do
Hash.ruby2_keywords_hash?(f4.call(1, 2, a: "a")).should == true
end
+ ruby_version_is ""..."3.0" do
+ it "fixes delegation warnings when calling a method accepting keywords" do
+ obj = Object.new
+ def obj.foo(*a, **b) end
+
+ f = -> *a { obj.foo(*a) }
+
+ -> { f.call(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/)
+ f.ruby2_keywords
+ -> { f.call(1, 2, {a: "a"}) }.should_not complain
+ end
+
+ it "fixes delegation warnings when calling a proc accepting keywords" do
+ g = -> *a, **b { }
+ f = -> *a { g.call(*a) }
+
+ -> { f.call(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/)
+ f.ruby2_keywords
+ -> { f.call(1, 2, {a: "a"}) }.should_not complain
+ end
+ end
+
it "returns self" do
f = -> *a { }
f.ruby2_keywords.should equal f
diff --git a/spec/ruby/core/proc/shared/dup.rb b/spec/ruby/core/proc/shared/dup.rb
index c419a4078a..eda1d6929d 100644
--- a/spec/ruby/core/proc/shared/dup.rb
+++ b/spec/ruby/core/proc/shared/dup.rb
@@ -7,35 +7,4 @@ describe :proc_dup, shared: true do
a.call.should == b.call
end
-
- ruby_version_is "3.2" do
- it "returns an instance of subclass" do
- cl = Class.new(Proc)
-
- cl.new{}.send(@method).class.should == cl
- end
- end
-
- ruby_version_is "3.4" do
- it "copies instance variables" do
- proc = -> { "hello" }
- proc.instance_variable_set(:@ivar, 1)
- cl = proc.send(@method)
- cl.instance_variables.should == [:@ivar]
- end
-
- it "copies the finalizer" do
- code = <<-RUBY
- obj = Proc.new { }
-
- ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" })
-
- obj.clone
-
- exit 0
- RUBY
-
- ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"]
- end
- end
end
diff --git a/spec/ruby/core/proc/shared/equal.rb b/spec/ruby/core/proc/shared/equal.rb
index d0503fb064..0c0020ca7f 100644
--- a/spec/ruby/core/proc/shared/equal.rb
+++ b/spec/ruby/core/proc/shared/equal.rb
@@ -81,3 +81,20 @@ describe :proc_equal, shared: true do
p.send(@method, p2).should be_false
end
end
+
+describe :proc_equal_undefined, shared: true do
+ it "is not defined" do
+ Proc.should_not have_instance_method(@method, false)
+ end
+
+ it "returns false if other is a dup of the original" do
+ p = proc { :foo }
+ p.send(@method, p.dup).should be_false
+
+ p = Proc.new { :foo }
+ p.send(@method, p.dup).should be_false
+
+ p = -> { :foo }
+ p.send(@method, p.dup).should be_false
+ end
+end
diff --git a/spec/ruby/core/proc/shared/to_s.rb b/spec/ruby/core/proc/shared/to_s.rb
index a52688a89f..f1e2f416fc 100644
--- a/spec/ruby/core/proc/shared/to_s.rb
+++ b/spec/ruby/core/proc/shared/to_s.rb
@@ -31,13 +31,13 @@ describe :proc_to_s, shared: true do
describe "for a proc created with UnboundMethod#to_proc" do
it "returns a description including '(lambda)' and optionally including file and line number" do
- def hello; end
- s = method("hello").to_proc.send(@method)
- if s.include? __FILE__
- s.should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/
- else
- s.should =~ /^#<Proc:([^ ]*?) \(lambda\)>$/
- end
+ def hello; end
+ s = method("hello").to_proc.send(@method)
+ if s.include? __FILE__
+ s.should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/
+ else
+ s.should =~ /^#<Proc:([^ ]*?) \(lambda\)>$/
+ end
end
it "has a binary encoding" do
diff --git a/spec/ruby/core/proc/source_location_spec.rb b/spec/ruby/core/proc/source_location_spec.rb
index a8b99287d5..f268499b82 100644
--- a/spec/ruby/core/proc/source_location_spec.rb
+++ b/spec/ruby/core/proc/source_location_spec.rb
@@ -19,19 +19,19 @@ describe "Proc#source_location" do
it "sets the first value to the path of the file in which the proc was defined" do
file = @proc.source_location.first
file.should be_an_instance_of(String)
- file.should == File.realpath('fixtures/source_location.rb', __dir__)
+ file.should == File.realpath('../fixtures/source_location.rb', __FILE__)
file = @proc_new.source_location.first
file.should be_an_instance_of(String)
- file.should == File.realpath('fixtures/source_location.rb', __dir__)
+ file.should == File.realpath('../fixtures/source_location.rb', __FILE__)
file = @lambda.source_location.first
file.should be_an_instance_of(String)
- file.should == File.realpath('fixtures/source_location.rb', __dir__)
+ file.should == File.realpath('../fixtures/source_location.rb', __FILE__)
file = @method.source_location.first
file.should be_an_instance_of(String)
- file.should == File.realpath('fixtures/source_location.rb', __dir__)
+ file.should == File.realpath('../fixtures/source_location.rb', __FILE__)
end
it "sets the last value to an Integer representing the line on which the proc was defined" do
@@ -83,9 +83,4 @@ describe "Proc#source_location" do
proc.source_location.should == nil
end
-
- it "works for eval with a given line" do
- proc = eval('-> {}', nil, "foo", 100)
- proc.source_location.should == ["foo", 100]
- end
end
diff --git a/spec/ruby/core/process/argv0_spec.rb b/spec/ruby/core/process/argv0_spec.rb
deleted file mode 100644
index f5aba719e9..0000000000
--- a/spec/ruby/core/process/argv0_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "Process.argv0" do
- it "returns a String" do
- Process.argv0.should be_kind_of(String)
- end
-
- it "is the path given as the main script and the same as __FILE__" do
- script = "fixtures/argv0.rb"
-
- Dir.chdir(__dir__) do
- ruby_exe(script).should == "#{script}\n#{script}\nOK"
- end
- end
-
- ruby_bug "#19597", ""..."3.3" do
- it "returns a frozen object" do
- Process.argv0.should.frozen?
- end
- end
-
- it "returns every time the same object" do
- Process.argv0.should.equal?(Process.argv0)
- end
-end
diff --git a/spec/ruby/core/process/constants_spec.rb b/spec/ruby/core/process/constants_spec.rb
index 616c54b8e1..4130bb58a5 100644
--- a/spec/ruby/core/process/constants_spec.rb
+++ b/spec/ruby/core/process/constants_spec.rb
@@ -56,18 +56,12 @@ describe "Process::Constants" do
end
platform_is :netbsd, :freebsd do
- it "has the correct constant values on NetBSD and FreeBSD" do
+ it "Process::RLIMIT_SBSIZE" do
Process::RLIMIT_SBSIZE.should == 9 # FIXME: what's it equal?
Process::RLIMIT_AS.should == 10
end
end
- platform_is :freebsd do
- it "has the correct constant values on FreeBSD" do
- Process::RLIMIT_NPTS.should == 11
- end
- end
-
platform_is :windows do
it "does not define RLIMIT constants" do
%i[
diff --git a/spec/ruby/core/process/daemon_spec.rb b/spec/ruby/core/process/daemon_spec.rb
index 36825771d1..20b0d743b9 100644
--- a/spec/ruby/core/process/daemon_spec.rb
+++ b/spec/ruby/core/process/daemon_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/common'
platform_is_not :windows do
- # macOS 15 beta is not working this examples
+ # macOS 15 is not working this examples
return if /darwin/ =~ RUBY_PLATFORM && /15/ =~ `sw_vers -productVersion`
describe :process_daemon_keep_stdio_open_false, shared: true do
diff --git a/spec/ruby/core/process/detach_spec.rb b/spec/ruby/core/process/detach_spec.rb
index f13bda1f5d..91661afcea 100644
--- a/spec/ruby/core/process/detach_spec.rb
+++ b/spec/ruby/core/process/detach_spec.rb
@@ -44,17 +44,11 @@ describe "Process.detach" do
end
it "tolerates not existing child process pid" do
- # Use a value that is close to the INT_MAX (pid usually is signed int).
- # It should (at least) be greater than allowed pid limit value that depends on OS.
- pid_not_existing = 2.pow(30)
+ # ensure there is no child process with this hardcoded pid
+ # `kill 0 pid` for existing process returns "1" and raises Errno::ESRCH if process doesn't exist
+ -> { Process.kill(0, 100500) }.should raise_error(Errno::ESRCH)
- # Check that there is no a child process with this hardcoded pid.
- # Command `kill 0 pid`:
- # - returns "1" if a process exists and
- # - raises Errno::ESRCH otherwise
- -> { Process.kill(0, pid_not_existing) }.should raise_error(Errno::ESRCH)
-
- thr = Process.detach(pid_not_existing)
+ thr = Process.detach(100500)
thr.join
thr.should be_kind_of(Thread)
diff --git a/spec/ruby/core/process/exec_spec.rb b/spec/ruby/core/process/exec_spec.rb
index 0f371b39c8..deb8913b6b 100644
--- a/spec/ruby/core/process/exec_spec.rb
+++ b/spec/ruby/core/process/exec_spec.rb
@@ -30,20 +30,20 @@ describe "Process.exec" do
end
it "raises Errno::EACCES when passed a directory" do
- -> { Process.exec __dir__ }.should raise_error(Errno::EACCES)
+ -> { Process.exec File.dirname(__FILE__) }.should raise_error(Errno::EACCES)
end
it "runs the specified command, replacing current process" do
- ruby_exe('Process.exec "echo hello"; puts "fail"').should == "hello\n"
+ ruby_exe('Process.exec "echo hello"; puts "fail"', escape: true).should == "hello\n"
end
it "sets the current directory when given the :chdir option" do
tmpdir = tmp("")[0..-2]
platform_is_not :windows do
- ruby_exe("Process.exec(\"pwd\", chdir: #{tmpdir.inspect})").should == "#{tmpdir}\n"
+ ruby_exe("Process.exec(\"pwd\", chdir: #{tmpdir.inspect})", escape: true).should == "#{tmpdir}\n"
end
platform_is :windows do
- ruby_exe("Process.exec(\"cd\", chdir: #{tmpdir.inspect})").tr('\\', '/').should == "#{tmpdir}\n"
+ ruby_exe("Process.exec(\"cd\", chdir: #{tmpdir.inspect})", escape: true).tr('\\', '/').should == "#{tmpdir}\n"
end
end
@@ -73,13 +73,13 @@ describe "Process.exec" do
platform_is_not :windows do
it "subjects the specified command to shell expansion" do
result = Dir.chdir(@dir) do
- ruby_exe('Process.exec "echo *"')
+ ruby_exe('Process.exec "echo *"', escape: true)
end
result.chomp.should == @name
end
it "creates an argument array with shell parsing semantics for whitespace" do
- ruby_exe('Process.exec "echo a b c d"').should == "a b c d\n"
+ ruby_exe('Process.exec "echo a b c d"', escape: true).should == "a b c d\n"
end
end
@@ -87,13 +87,13 @@ describe "Process.exec" do
# There is no shell expansion on Windows
it "does not subject the specified command to shell expansion on Windows" do
result = Dir.chdir(@dir) do
- ruby_exe('Process.exec "echo *"')
+ ruby_exe('Process.exec "echo *"', escape: true)
end
result.should == "*\n"
end
it "does not create an argument array with shell parsing semantics for whitespace on Windows" do
- ruby_exe('Process.exec "echo a b c d"').should == "a b c d\n"
+ ruby_exe('Process.exec "echo a b c d"', escape: true).should == "a b c d\n"
end
end
@@ -105,7 +105,7 @@ describe "Process.exec" do
platform_is :windows do
cmd = '"cmd.exe", "/C", "echo", "*"'
end
- ruby_exe("Process.exec #{cmd}").should == "*\n"
+ ruby_exe("Process.exec #{cmd}", escape: true).should == "*\n"
end
end
@@ -124,29 +124,29 @@ describe "Process.exec" do
end
it "sets environment variables in the child environment" do
- ruby_exe('Process.exec({"FOO" => "BAR"}, "echo ' + var + '")').should == "BAR\n"
+ ruby_exe('Process.exec({"FOO" => "BAR"}, "echo ' + var + '")', escape: true).should == "BAR\n"
end
it "unsets environment variables whose value is nil" do
platform_is_not :windows do
- ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")').should == "\n"
+ ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")', escape: true).should == "\n"
end
platform_is :windows do
# On Windows, echo-ing a non-existent env var is treated as echo-ing any other string of text
- ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")').should == var + "\n"
+ ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")', escape: true).should == var + "\n"
end
end
it "coerces environment argument using to_hash" do
- ruby_exe('o = Object.new; def o.to_hash; {"FOO" => "BAR"}; end; Process.exec(o, "echo ' + var + '")').should == "BAR\n"
+ ruby_exe('o = Object.new; def o.to_hash; {"FOO" => "BAR"}; end; Process.exec(o, "echo ' + var + '")', escape: true).should == "BAR\n"
end
it "unsets other environment variables when given a true :unsetenv_others option" do
platform_is_not :windows do
- ruby_exe('Process.exec("echo ' + var + '", unsetenv_others: true)').should == "\n"
+ ruby_exe('Process.exec("echo ' + var + '", unsetenv_others: true)', escape: true).should == "\n"
end
platform_is :windows do
- ruby_exe('Process.exec("' + ENV['COMSPEC'].gsub('\\', '\\\\\\') + ' /C echo ' + var + '", unsetenv_others: true)').should == var + "\n"
+ ruby_exe('Process.exec("' + ENV['COMSPEC'].gsub('\\', '\\\\\\') + ' /C echo ' + var + '", unsetenv_others: true)', escape: true).should == var + "\n"
end
end
end
@@ -154,19 +154,19 @@ describe "Process.exec" do
describe "with a command array" do
it "uses the first element as the command name and the second as the argv[0] value" do
platform_is_not :windows do
- ruby_exe('Process.exec(["/bin/sh", "argv_zero"], "-c", "echo $0")').should == "argv_zero\n"
+ ruby_exe('Process.exec(["/bin/sh", "argv_zero"], "-c", "echo $0")', escape: true).should == "argv_zero\n"
end
platform_is :windows do
- ruby_exe('Process.exec(["cmd.exe", "/C"], "/C", "echo", "argv_zero")').should == "argv_zero\n"
+ ruby_exe('Process.exec(["cmd.exe", "/C"], "/C", "echo", "argv_zero")', escape: true).should == "argv_zero\n"
end
end
it "coerces the argument using to_ary" do
platform_is_not :windows do
- ruby_exe('o = Object.new; def o.to_ary; ["/bin/sh", "argv_zero"]; end; Process.exec(o, "-c", "echo $0")').should == "argv_zero\n"
+ ruby_exe('o = Object.new; def o.to_ary; ["/bin/sh", "argv_zero"]; end; Process.exec(o, "-c", "echo $0")', escape: true).should == "argv_zero\n"
end
platform_is :windows do
- ruby_exe('o = Object.new; def o.to_ary; ["cmd.exe", "/C"]; end; Process.exec(o, "/C", "echo", "argv_zero")').should == "argv_zero\n"
+ ruby_exe('o = Object.new; def o.to_ary; ["cmd.exe", "/C"]; end; Process.exec(o, "/C", "echo", "argv_zero")', escape: true).should == "argv_zero\n"
end
end
@@ -200,7 +200,7 @@ describe "Process.exec" do
end
EOC
- ruby_exe(cmd)
+ ruby_exe(cmd, escape: true)
child_fd = IO.read(@child_fd_file).to_i
child_fd.to_i.should > STDERR.fileno
@@ -216,7 +216,7 @@ describe "Process.exec" do
Process.exec("#{ruby_cmd(map_fd_fixture)} \#{f.fileno}", f.fileno => f.fileno)
EOC
- output = ruby_exe(cmd)
+ output = ruby_exe(cmd, escape: true)
child_fd, close_on_exec = output.split
child_fd.to_i.should > STDERR.fileno
@@ -232,7 +232,7 @@ describe "Process.exec" do
puts(f.close_on_exec?)
EOC
- output = ruby_exe(cmd)
+ output = ruby_exe(cmd, escape: true)
output.split.should == ['true', 'false']
end
end
diff --git a/spec/ruby/core/process/exit_spec.rb b/spec/ruby/core/process/exit_spec.rb
index 4f7dc94407..70d79d789d 100644
--- a/spec/ruby/core/process/exit_spec.rb
+++ b/spec/ruby/core/process/exit_spec.rb
@@ -6,5 +6,5 @@ describe "Process.exit" do
end
describe "Process.exit!" do
- it_behaves_like :process_exit!, :exit!, "Process"
+ it_behaves_like :process_exit!, :exit!, Process
end
diff --git a/spec/ruby/core/process/fixtures/argv0.rb b/spec/ruby/core/process/fixtures/argv0.rb
deleted file mode 100644
index 847a3e903e..0000000000
--- a/spec/ruby/core/process/fixtures/argv0.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-puts Process.argv0
-puts __FILE__
-
-if Process.argv0 == __FILE__
- print "OK"
-end
diff --git a/spec/ruby/core/process/fixtures/kill.rb b/spec/ruby/core/process/fixtures/kill.rb
index b922a043f1..0b88f8ee1f 100644
--- a/spec/ruby/core/process/fixtures/kill.rb
+++ b/spec/ruby/core/process/fixtures/kill.rb
@@ -1,3 +1,5 @@
+require 'thread'
+
pid_file = ARGV.shift
scenario = ARGV.shift
diff --git a/spec/ruby/core/process/spawn_spec.rb b/spec/ruby/core/process/spawn_spec.rb
index 283a7f033d..c8a58c4d04 100644
--- a/spec/ruby/core/process/spawn_spec.rb
+++ b/spec/ruby/core/process/spawn_spec.rb
@@ -714,7 +714,7 @@ describe "Process.spawn" do
end
it "raises an Errno::EACCES or Errno::EISDIR when passed a directory" do
- -> { Process.spawn __dir__ }.should raise_error(SystemCallError) { |e|
+ -> { Process.spawn File.dirname(__FILE__) }.should raise_error(SystemCallError) { |e|
[Errno::EACCES, Errno::EISDIR].should include(e.class)
}
end
diff --git a/spec/ruby/core/process/status/termsig_spec.rb b/spec/ruby/core/process/status/termsig_spec.rb
index 9a22dbea71..5d286950f8 100644
--- a/spec/ruby/core/process/status/termsig_spec.rb
+++ b/spec/ruby/core/process/status/termsig_spec.rb
@@ -6,7 +6,7 @@ describe "Process::Status#termsig" do
ruby_exe("exit(0)")
end
- it "returns nil" do
+ it "returns true" do
$?.termsig.should be_nil
end
end
diff --git a/spec/ruby/core/process/status/wait_spec.rb b/spec/ruby/core/process/status/wait_spec.rb
index 57d56209a9..b9d80e31f4 100644
--- a/spec/ruby/core/process/status/wait_spec.rb
+++ b/spec/ruby/core/process/status/wait_spec.rb
@@ -1,100 +1,102 @@
require_relative '../../../spec_helper'
require_relative '../fixtures/common'
-describe "Process::Status.wait" do
- ProcessSpecs.use_system_ruby(self)
-
- before :all do
- begin
- leaked = Process.waitall
- # Ruby-space should not see PIDs used by rjit
- raise "subprocesses leaked before wait specs: #{leaked}" unless leaked.empty?
- rescue NotImplementedError
+ruby_version_is "3.0" do
+ describe "Process::Status.wait" do
+ ProcessSpecs.use_system_ruby(self)
+
+ before :all do
+ begin
+ leaked = Process.waitall
+ # Ruby-space should not see PIDs used by mjit
+ raise "subprocesses leaked before wait specs: #{leaked}" unless leaked.empty?
+ rescue NotImplementedError
+ end
end
- end
-
- it "returns a status with pid -1 if there are no child processes" do
- Process::Status.wait.pid.should == -1
- end
- platform_is_not :windows do
- it "returns a status with its child pid" do
- pid = Process.spawn(ruby_cmd('exit'))
- status = Process::Status.wait
- status.should be_an_instance_of(Process::Status)
- status.pid.should == pid
+ it "returns a status with pid -1 if there are no child processes" do
+ Process::Status.wait.pid.should == -1
end
- it "should not set $? to the Process::Status" do
- pid = Process.spawn(ruby_cmd('exit'))
- status = Process::Status.wait
- $?.should_not equal(status)
- end
+ platform_is_not :windows do
+ it "returns a status with its child pid" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ status = Process::Status.wait
+ status.should be_an_instance_of(Process::Status)
+ status.pid.should == pid
+ end
- it "should not change the value of $?" do
- pid = Process.spawn(ruby_cmd('exit'))
- Process.wait
- status = $?
- Process::Status.wait
- status.should equal($?)
- end
+ it "should not set $? to the Process::Status" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ status = Process::Status.wait
+ $?.should_not equal(status)
+ end
- it "waits for any child process if no pid is given" do
- pid = Process.spawn(ruby_cmd('exit'))
- Process::Status.wait.pid.should == pid
- -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
- end
+ it "should not change the value of $?" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ Process.wait
+ status = $?
+ Process::Status.wait
+ status.should equal($?)
+ end
- it "waits for a specific child if a pid is given" do
- pid1 = Process.spawn(ruby_cmd('exit'))
- pid2 = Process.spawn(ruby_cmd('exit'))
- Process::Status.wait(pid2).pid.should == pid2
- Process::Status.wait(pid1).pid.should == pid1
- -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
- -> { Process.kill(0, pid2) }.should raise_error(Errno::ESRCH)
- end
+ it "waits for any child process if no pid is given" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ Process::Status.wait.pid.should == pid
+ -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ end
- it "coerces the pid to an Integer" do
- pid1 = Process.spawn(ruby_cmd('exit'))
- Process::Status.wait(mock_int(pid1)).pid.should == pid1
- -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
- end
+ it "waits for a specific child if a pid is given" do
+ pid1 = Process.spawn(ruby_cmd('exit'))
+ pid2 = Process.spawn(ruby_cmd('exit'))
+ Process::Status.wait(pid2).pid.should == pid2
+ Process::Status.wait(pid1).pid.should == pid1
+ -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid2) }.should raise_error(Errno::ESRCH)
+ end
- # This spec is probably system-dependent.
- it "waits for a child whose process group ID is that of the calling process" do
- pid1 = Process.spawn(ruby_cmd('exit'), pgroup: true)
- pid2 = Process.spawn(ruby_cmd('exit'))
+ it "coerces the pid to an Integer" do
+ pid1 = Process.spawn(ruby_cmd('exit'))
+ Process::Status.wait(mock_int(pid1)).pid.should == pid1
+ -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
+ end
- Process::Status.wait(0).pid.should == pid2
- Process::Status.wait.pid.should == pid1
- end
+ # This spec is probably system-dependent.
+ it "waits for a child whose process group ID is that of the calling process" do
+ pid1 = Process.spawn(ruby_cmd('exit'), pgroup: true)
+ pid2 = Process.spawn(ruby_cmd('exit'))
- # This spec is probably system-dependent.
- it "doesn't block if no child is available when WNOHANG is used" do
- read, write = IO.pipe
- pid = Process.fork do
- read.close
- Signal.trap("TERM") { Process.exit! }
- write << 1
- write.close
- sleep
+ Process::Status.wait(0).pid.should == pid2
+ Process::Status.wait.pid.should == pid1
end
- Process::Status.wait(pid, Process::WNOHANG).should be_nil
+ # This spec is probably system-dependent.
+ it "doesn't block if no child is available when WNOHANG is used" do
+ read, write = IO.pipe
+ pid = Process.fork do
+ read.close
+ Signal.trap("TERM") { Process.exit! }
+ write << 1
+ write.close
+ sleep
+ end
- # wait for the child to setup its TERM handler
- write.close
- read.read(1)
- read.close
+ Process::Status.wait(pid, Process::WNOHANG).should be_nil
- Process.kill("TERM", pid)
- Process::Status.wait.pid.should == pid
- end
+ # wait for the child to setup its TERM handler
+ write.close
+ read.read(1)
+ read.close
- it "always accepts flags=0" do
- pid = Process.spawn(ruby_cmd('exit'))
- Process::Status.wait(-1, 0).pid.should == pid
- -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ Process.kill("TERM", pid)
+ Process::Status.wait.pid.should == pid
+ end
+
+ it "always accepts flags=0" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ Process::Status.wait(-1, 0).pid.should == pid
+ -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ end
end
end
end
diff --git a/spec/ruby/core/process/times_spec.rb b/spec/ruby/core/process/times_spec.rb
index d3bff2cda9..6142cd257c 100644
--- a/spec/ruby/core/process/times_spec.rb
+++ b/spec/ruby/core/process/times_spec.rb
@@ -16,4 +16,24 @@ describe "Process.times" do
Process.times.utime.should > user
end
end
+
+ platform_is_not :windows do
+ it "uses getrusage when available to improve precision beyond milliseconds" do
+ max = 10_000
+ has_getrusage = max.times.find do
+ time = Process.clock_gettime(:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
+ ('%.6f' % time).end_with?('000')
+ end
+ unless has_getrusage
+ skip "getrusage is not supported on this environment"
+ end
+
+ found = (max * 100).times.find do
+ time = Process.times.utime
+ ('%.6f' % time).end_with?('000')
+ end
+
+ found.should_not == nil
+ end
+ end
end
diff --git a/spec/ruby/core/process/wait2_spec.rb b/spec/ruby/core/process/wait2_spec.rb
index 8ba429dc96..673d3cdb9d 100644
--- a/spec/ruby/core/process/wait2_spec.rb
+++ b/spec/ruby/core/process/wait2_spec.rb
@@ -4,14 +4,14 @@ describe "Process.wait2" do
before :all do
# HACK: this kludge is temporarily necessary because some
# misbehaving spec somewhere else does not clear processes
- # Note: background processes are unavoidable with RJIT,
+ # Note: background processes are unavoidable with MJIT,
# but we shouldn't reap them from Ruby-space
begin
Process.wait(-1, Process::WNOHANG)
$stderr.puts "Leaked process before wait2 specs! Waiting for it"
leaked = Process.waitall
$stderr.puts "leaked before wait2 specs: #{leaked}" unless leaked.empty?
- # Ruby-space should not see PIDs used by rjit
+ # Ruby-space should not see PIDs used by mjit
leaked.should be_empty
rescue Errno::ECHILD # No child processes
rescue NotImplementedError
diff --git a/spec/ruby/core/process/wait_spec.rb b/spec/ruby/core/process/wait_spec.rb
index 385acc9928..44c95d6304 100644
--- a/spec/ruby/core/process/wait_spec.rb
+++ b/spec/ruby/core/process/wait_spec.rb
@@ -7,7 +7,7 @@ describe "Process.wait" do
before :all do
begin
leaked = Process.waitall
- # Ruby-space should not see PIDs used by rjit
+ # Ruby-space should not see PIDs used by mjit
raise "subprocesses leaked before wait specs: #{leaked}" unless leaked.empty?
rescue NotImplementedError
end
diff --git a/spec/ruby/core/process/waitpid_spec.rb b/spec/ruby/core/process/waitpid_spec.rb
index a02147b663..f7cf1a45a8 100644
--- a/spec/ruby/core/process/waitpid_spec.rb
+++ b/spec/ruby/core/process/waitpid_spec.rb
@@ -2,8 +2,7 @@ require_relative '../../spec_helper'
describe "Process.waitpid" do
it "returns nil when the process has not yet completed and WNOHANG is specified" do
- cmd = platform_is(:windows) ? "timeout" : "sleep"
- pid = spawn("#{cmd} 5")
+ pid = spawn("sleep 5")
begin
Process.waitpid(pid, Process::WNOHANG).should == nil
Process.kill("KILL", pid)
diff --git a/spec/ruby/core/process/warmup_spec.rb b/spec/ruby/core/process/warmup_spec.rb
deleted file mode 100644
index b562d52d22..0000000000
--- a/spec/ruby/core/process/warmup_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "Process.warmup" do
- ruby_version_is "3.3" do
- # The behavior is entirely implementation specific.
- # Other implementations are free to just make it a noop
- it "is implemented" do
- Process.warmup.should == true
- end
- end
-end
diff --git a/spec/ruby/core/queue/deq_spec.rb b/spec/ruby/core/queue/deq_spec.rb
index f84d4220ea..9510978eac 100644
--- a/spec/ruby/core/queue/deq_spec.rb
+++ b/spec/ruby/core/queue/deq_spec.rb
@@ -1,13 +1,6 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/deque'
-require_relative '../../shared/types/rb_num2dbl_fails'
describe "Queue#deq" do
it_behaves_like :queue_deq, :deq, -> { Queue.new }
end
-
-describe "Queue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.deq(timeout: v) }
- end
-end
diff --git a/spec/ruby/core/queue/initialize_spec.rb b/spec/ruby/core/queue/initialize_spec.rb
index c6c1ae63c5..c45abcd29d 100644
--- a/spec/ruby/core/queue/initialize_spec.rb
+++ b/spec/ruby/core/queue/initialize_spec.rb
@@ -22,29 +22,16 @@ describe "Queue#initialize" do
q.should.empty?
end
- describe "converts the given argument to an Array using #to_a" do
- it "uses #to_a on the provided Enumerable" do
- enumerable = MockObject.new('mock-enumerable')
- enumerable.should_receive(:to_a).and_return([1, 2, 3])
- q = Queue.new(enumerable)
- q.size.should == 3
- q.should_not.empty?
- q.pop.should == 1
- q.pop.should == 2
- q.pop.should == 3
- q.should.empty?
- end
-
- it "raises a TypeError if the given argument can't be converted to an Array" do
- -> { Queue.new(42) }.should raise_error(TypeError)
- -> { Queue.new(:abc) }.should raise_error(TypeError)
- end
-
- it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do
- enumerable = MockObject.new('mock-enumerable')
- enumerable.should_receive(:to_a).and_raise(NoMethodError)
- -> { Queue.new(enumerable) }.should raise_error(NoMethodError)
- end
+ it "uses #to_a on the provided Enumerable" do
+ enumerable = MockObject.new('mock-enumerable')
+ enumerable.should_receive(:to_a).and_return([1, 2, 3])
+ q = Queue.new(enumerable)
+ q.size.should == 3
+ q.should_not.empty?
+ q.pop.should == 1
+ q.pop.should == 2
+ q.pop.should == 3
+ q.should.empty?
end
it "raises TypeError if the provided Enumerable does not respond to #to_a" do
diff --git a/spec/ruby/core/queue/pop_spec.rb b/spec/ruby/core/queue/pop_spec.rb
index d344740834..1ce9231685 100644
--- a/spec/ruby/core/queue/pop_spec.rb
+++ b/spec/ruby/core/queue/pop_spec.rb
@@ -1,13 +1,6 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/deque'
-require_relative '../../shared/types/rb_num2dbl_fails'
describe "Queue#pop" do
it_behaves_like :queue_deq, :pop, -> { Queue.new }
end
-
-describe "Queue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.pop(timeout: v) }
- end
-end
diff --git a/spec/ruby/core/queue/shift_spec.rb b/spec/ruby/core/queue/shift_spec.rb
index 64165e0b61..f84058e1df 100644
--- a/spec/ruby/core/queue/shift_spec.rb
+++ b/spec/ruby/core/queue/shift_spec.rb
@@ -1,13 +1,6 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/deque'
-require_relative '../../shared/types/rb_num2dbl_fails'
describe "Queue#shift" do
it_behaves_like :queue_deq, :shift, -> { Queue.new }
end
-
-describe "Queue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.shift(timeout: v) }
- end
-end
diff --git a/spec/ruby/core/random/bytes_spec.rb b/spec/ruby/core/random/bytes_spec.rb
index b42dc61234..ed1b3a7b41 100644
--- a/spec/ruby/core/random/bytes_spec.rb
+++ b/spec/ruby/core/random/bytes_spec.rb
@@ -9,6 +9,7 @@ describe "Random#bytes" do
Random.new(33).bytes(2).should == Random.new(33).bytes(2)
end
+ # Should double check this is official spec
it "returns the same numeric output for a given seed across all implementations and platforms" do
rnd = Random.new(33)
rnd.bytes(2).should == "\x14\\"
diff --git a/spec/ruby/core/random/default_spec.rb b/spec/ruby/core/random/default_spec.rb
index 01d7430df8..b4ffcb81f4 100644
--- a/spec/ruby/core/random/default_spec.rb
+++ b/spec/ruby/core/random/default_spec.rb
@@ -14,16 +14,26 @@ describe "Random::DEFAULT" do
seed1.should != seed2
end
- it "refers to the Random class" do
- suppress_warning do
- Random::DEFAULT.should.equal?(Random)
+ ruby_version_is ''...'3.0' do
+ it "returns a Random instance" do
+ suppress_warning do
+ Random::DEFAULT.should be_an_instance_of(Random)
+ end
end
end
- it "is deprecated" do
- -> {
- Random::DEFAULT.should.equal?(Random)
- }.should complain(/constant Random::DEFAULT is deprecated/)
+ ruby_version_is '3.0' do
+ it "refers to the Random class" do
+ suppress_warning do
+ Random::DEFAULT.should.equal?(Random)
+ end
+ end
+
+ it "is deprecated" do
+ -> {
+ Random::DEFAULT.should.equal?(Random)
+ }.should complain(/constant Random::DEFAULT is deprecated/)
+ end
end
end
diff --git a/spec/ruby/core/random/new_spec.rb b/spec/ruby/core/random/new_spec.rb
index 90e2a9d6f2..4280b5b9c3 100644
--- a/spec/ruby/core/random/new_spec.rb
+++ b/spec/ruby/core/random/new_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
describe "Random.new" do
it "returns a new instance of Random" do
Random.new.should be_an_instance_of(Random)
diff --git a/spec/ruby/core/range/bsearch_spec.rb b/spec/ruby/core/range/bsearch_spec.rb
index 5254ab756c..9c93671d85 100644
--- a/spec/ruby/core/range/bsearch_spec.rb
+++ b/spec/ruby/core/range/bsearch_spec.rb
@@ -9,30 +9,22 @@ describe "Range#bsearch" do
it_behaves_like :enumeratorized_with_unknown_size, :bsearch, (1..3)
it "raises a TypeError if the block returns an Object" do
- -> { (0..1).bsearch { Object.new } }.should raise_error(TypeError, "wrong argument type Object (must be numeric, true, false or nil)")
+ -> { (0..1).bsearch { Object.new } }.should raise_error(TypeError)
end
- it "raises a TypeError if the block returns a String and boundaries are Integer values" do
- -> { (0..1).bsearch { "1" } }.should raise_error(TypeError, "wrong argument type String (must be numeric, true, false or nil)")
- end
-
- it "raises a TypeError if the block returns a String and boundaries are Float values" do
- -> { (0.0..1.0).bsearch { "1" } }.should raise_error(TypeError, "wrong argument type String (must be numeric, true, false or nil)")
+ it "raises a TypeError if the block returns a String" do
+ -> { (0..1).bsearch { "1" } }.should raise_error(TypeError)
end
it "raises a TypeError if the Range has Object values" do
value = mock("range bsearch")
r = Range.new value, value
- -> { r.bsearch { true } }.should raise_error(TypeError, "can't do binary search for MockObject")
+ -> { r.bsearch { true } }.should raise_error(TypeError)
end
it "raises a TypeError if the Range has String values" do
- -> { ("a".."e").bsearch { true } }.should raise_error(TypeError, "can't do binary search for String")
- end
-
- it "raises TypeError when non-Numeric begin/end and block not passed" do
- -> { ("a".."e").bsearch }.should raise_error(TypeError, "can't do binary search for String")
+ -> { ("a".."e").bsearch { true } }.should raise_error(TypeError)
end
context "with Integer values" do
@@ -102,10 +94,6 @@ describe "Range#bsearch" do
(4..2).bsearch { 0 }.should == nil
(4..2).bsearch { -1 }.should == nil
end
-
- it "returns enumerator when block not passed" do
- (0...3).bsearch.kind_of?(Enumerator).should == true
- end
end
context "with Float values" do
@@ -168,6 +156,7 @@ describe "Range#bsearch" do
it "returns nil if the block returns greater than zero for every element" do
(0.3..3.0).bsearch { |x| x <=> -1 }.should be_nil
+
end
it "returns nil if the block never returns zero" do
@@ -224,10 +213,6 @@ describe "Range#bsearch" do
(0...inf).bsearch { |x| x >= Float::MAX ? 0 : 1 }.should == Float::MAX
end
end
-
- it "returns enumerator when block not passed" do
- (0.1...2.3).bsearch.kind_of?(Enumerator).should == true
- end
end
context "with endless ranges and Integer values" do
@@ -265,10 +250,6 @@ describe "Range#bsearch" do
[1, 2, 3].should include(result)
end
end
-
- it "returns enumerator when block not passed" do
- eval("(-2..)").bsearch.kind_of?(Enumerator).should == true
- end
end
context "with endless ranges and Float values" do
@@ -346,12 +327,9 @@ describe "Range#bsearch" do
eval("(0.0...)").bsearch { 0 }.should != inf
end
end
-
- it "returns enumerator when block not passed" do
- eval("(0.1..)").bsearch.kind_of?(Enumerator).should == true
- end
end
+
context "with beginless ranges and Integer values" do
context "with a block returning true or false" do
it "returns the smallest element for which block returns true" do
@@ -383,10 +361,6 @@ describe "Range#bsearch" do
[1, 2, 3].should include(result)
end
end
-
- it "returns enumerator when block not passed" do
- (..10).bsearch.kind_of?(Enumerator).should == true
- end
end
context "with beginless ranges and Float values" do
@@ -458,9 +432,5 @@ describe "Range#bsearch" do
(...inf).bsearch { |x| 3 - x }.should == 3
end
end
-
- it "returns enumerator when block not passed" do
- (..-0.1).bsearch.kind_of?(Enumerator).should == true
- end
end
end
diff --git a/spec/ruby/core/range/cover_spec.rb b/spec/ruby/core/range/cover_spec.rb
index eb7cddc967..fa881607e9 100644
--- a/spec/ruby/core/range/cover_spec.rb
+++ b/spec/ruby/core/range/cover_spec.rb
@@ -7,8 +7,4 @@ describe "Range#cover?" do
it_behaves_like :range_cover_and_include, :cover?
it_behaves_like :range_cover, :cover?
it_behaves_like :range_cover_subrange, :cover?
-
- it "covers U+9995 in the range U+0999..U+9999" do
- ("\u{999}".."\u{9999}").cover?("\u{9995}").should be_true
- end
end
diff --git a/spec/ruby/core/range/frozen_spec.rb b/spec/ruby/core/range/frozen_spec.rb
index 8dab5e5339..298ffc87cb 100644
--- a/spec/ruby/core/range/frozen_spec.rb
+++ b/spec/ruby/core/range/frozen_spec.rb
@@ -2,24 +2,26 @@ require_relative '../../spec_helper'
# There is no Range#frozen? method but this feels like the best place for these specs
describe "Range#frozen?" do
- it "is true for literal ranges" do
- (1..2).should.frozen?
- (1..).should.frozen?
- (..1).should.frozen?
- end
+ ruby_version_is "3.0" do
+ it "is true for literal ranges" do
+ (1..2).should.frozen?
+ (1..).should.frozen?
+ (..1).should.frozen?
+ end
- it "is true for Range.new" do
- Range.new(1, 2).should.frozen?
- Range.new(1, nil).should.frozen?
- Range.new(nil, 1).should.frozen?
- end
+ it "is true for Range.new" do
+ Range.new(1, 2).should.frozen?
+ Range.new(1, nil).should.frozen?
+ Range.new(nil, 1).should.frozen?
+ end
- it "is false for instances of a subclass of Range" do
- sub_range = Class.new(Range).new(1, 2)
- sub_range.should_not.frozen?
- end
+ it "is false for instances of a subclass of Range" do
+ sub_range = Class.new(Range).new(1, 2)
+ sub_range.should_not.frozen?
+ end
- it "is false for Range.allocate" do
- Range.allocate.should_not.frozen?
+ it "is false for Range.allocate" do
+ Range.allocate.should_not.frozen?
+ end
end
end
diff --git a/spec/ruby/core/range/include_spec.rb b/spec/ruby/core/range/include_spec.rb
index 277de205d1..b2c7a54545 100644
--- a/spec/ruby/core/range/include_spec.rb
+++ b/spec/ruby/core/range/include_spec.rb
@@ -7,8 +7,4 @@ require_relative 'shared/cover'
describe "Range#include?" do
it_behaves_like :range_cover_and_include, :include?
it_behaves_like :range_include, :include?
-
- it "does not include U+9995 in the range U+0999..U+9999" do
- ("\u{999}".."\u{9999}").include?("\u{9995}").should be_false
- end
end
diff --git a/spec/ruby/core/range/initialize_spec.rb b/spec/ruby/core/range/initialize_spec.rb
index c653caf0c6..8a6ca65daa 100644
--- a/spec/ruby/core/range/initialize_spec.rb
+++ b/spec/ruby/core/range/initialize_spec.rb
@@ -27,9 +27,18 @@ describe "Range#initialize" do
-> { @range.send(:initialize, 1, 3, 5, 7, 9) }.should raise_error(ArgumentError)
end
- it "raises a FrozenError if called on an already initialized Range" do
- -> { (0..1).send(:initialize, 1, 3) }.should raise_error(FrozenError)
- -> { (0..1).send(:initialize, 1, 3, true) }.should raise_error(FrozenError)
+ ruby_version_is ""..."3.0" do
+ it "raises a NameError if called on an already initialized Range" do
+ -> { (0..1).send(:initialize, 1, 3) }.should raise_error(NameError)
+ -> { (0..1).send(:initialize, 1, 3, true) }.should raise_error(NameError)
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "raises a FrozenError if called on an already initialized Range" do
+ -> { (0..1).send(:initialize, 1, 3) }.should raise_error(FrozenError)
+ -> { (0..1).send(:initialize, 1, 3, true) }.should raise_error(FrozenError)
+ end
end
it "raises an ArgumentError if arguments don't respond to <=>" do
diff --git a/spec/ruby/core/range/max_spec.rb b/spec/ruby/core/range/max_spec.rb
index a3bbc31e7d..6c9ada2a3c 100644
--- a/spec/ruby/core/range/max_spec.rb
+++ b/spec/ruby/core/range/max_spec.rb
@@ -50,15 +50,17 @@ describe "Range#max" do
-> { eval("(1..)").max }.should raise_error(RangeError)
end
- it "returns the end point for beginless ranges" do
- (..1).max.should == 1
- (..1.0).max.should == 1.0
- end
+ ruby_version_is "3.0" do
+ it "returns the end point for beginless ranges" do
+ (..1).max.should == 1
+ (..1.0).max.should == 1.0
+ end
- it "raises for an exclusive beginless range" do
- -> {
- (...1).max
- }.should raise_error(TypeError, 'cannot exclude end value with non Integer begin value')
+ it "raises for an exclusive beginless range" do
+ -> {
+ (...1).max
+ }.should raise_error(TypeError, 'cannot exclude end value with non Integer begin value')
+ end
end
end
diff --git a/spec/ruby/core/range/minmax_spec.rb b/spec/ruby/core/range/minmax_spec.rb
index 6651ae3726..b2b4fd61a1 100644
--- a/spec/ruby/core/range/minmax_spec.rb
+++ b/spec/ruby/core/range/minmax_spec.rb
@@ -86,22 +86,24 @@ describe 'Range#minmax' do
/cannot get the maximum of beginless range with custom comparison method|cannot get the minimum of beginless range/)
end
- it 'should return nil pair if beginning and end are equal without iterating the range' do
- @x.should_not_receive(:succ)
+ ruby_bug "#17014", ""..."3.0" do
+ it 'should return nil pair if beginning and end are equal without iterating the range' do
+ @x.should_not_receive(:succ)
- (@x...@x).minmax.should == [nil, nil]
- end
+ (@x...@x).minmax.should == [nil, nil]
+ end
- it 'should return nil pair if beginning is greater than end without iterating the range' do
- @y.should_not_receive(:succ)
+ it 'should return nil pair if beginning is greater than end without iterating the range' do
+ @y.should_not_receive(:succ)
- (@y...@x).minmax.should == [nil, nil]
- end
+ (@y...@x).minmax.should == [nil, nil]
+ end
- it 'should return the minimum and maximum values for a non-numeric range by iterating the range' do
- @x.should_receive(:succ).once.and_return(@y)
+ it 'should return the minimum and maximum values for a non-numeric range by iterating the range' do
+ @x.should_receive(:succ).once.and_return(@y)
- (@x...@y).minmax.should == [@x, @x]
+ (@x...@y).minmax.should == [@x, @x]
+ end
end
it 'should return the minimum and maximum values for a numeric range' do
diff --git a/spec/ruby/core/range/new_spec.rb b/spec/ruby/core/range/new_spec.rb
index 3cab887799..40df914b83 100644
--- a/spec/ruby/core/range/new_spec.rb
+++ b/spec/ruby/core/range/new_spec.rb
@@ -66,12 +66,14 @@ describe "Range.new" do
range_exclude.should_not == range_include
end
- it "creates a frozen range if the class is Range.class" do
- Range.new(1, 2).should.frozen?
- end
-
- it "does not create a frozen range if the class is not Range.class" do
- Class.new(Range).new(1, 2).should_not.frozen?
+ ruby_version_is "3.0" do
+ it "creates a frozen range if the class is Range.class" do
+ Range.new(1, 2).should.frozen?
+ end
+
+ it "does not create a frozen range if the class is not Range.class" do
+ Class.new(Range).new(1, 2).should_not.frozen?
+ end
end
end
end
diff --git a/spec/ruby/core/range/shared/cover_and_include.rb b/spec/ruby/core/range/shared/cover_and_include.rb
index f36a2cef8b..7028afaa89 100644
--- a/spec/ruby/core/range/shared/cover_and_include.rb
+++ b/spec/ruby/core/range/shared/cover_and_include.rb
@@ -57,6 +57,7 @@ describe :range_cover_and_include, shared: true do
it "returns true if argument is less than the last value of the range and greater than the first value" do
(20..30).send(@method, 28).should be_true
('e'..'h').send(@method, 'g').should be_true
+ ("\u{999}".."\u{9999}").send @method, "\u{9995}"
end
it "returns true if argument is sole element in the range" do
diff --git a/spec/ruby/core/range/size_spec.rb b/spec/ruby/core/range/size_spec.rb
index a1fe3ce17d..9b625c9963 100644
--- a/spec/ruby/core/range/size_spec.rb
+++ b/spec/ruby/core/range/size_spec.rb
@@ -4,22 +4,34 @@ describe "Range#size" do
it "returns the number of elements in the range" do
(1..16).size.should == 16
(1...16).size.should == 15
+
+ (1.0..16.0).size.should == 16
+ (1.0...16.0).size.should == 15
+ (1.0..15.9).size.should == 15
+ (1.1..16.0).size.should == 15
+ (1.1..15.9).size.should == 15
end
it "returns 0 if last is less than first" do
(16..0).size.should == 0
+ (16.0..0.0).size.should == 0
+ (Float::INFINITY..0).size.should == 0
end
it 'returns Float::INFINITY for increasing, infinite ranges' do
(0..Float::INFINITY).size.should == Float::INFINITY
+ (-Float::INFINITY..0).size.should == Float::INFINITY
+ (-Float::INFINITY..Float::INFINITY).size.should == Float::INFINITY
end
it 'returns Float::INFINITY for endless ranges if the start is numeric' do
eval("(1..)").size.should == Float::INFINITY
+ eval("(0.5...)").size.should == Float::INFINITY
end
it 'returns nil for endless ranges if the start is not numeric' do
eval("('z'..)").size.should == nil
+ eval("([]...)").size.should == nil
end
ruby_version_is ""..."3.2" do
@@ -31,13 +43,13 @@ describe "Range#size" do
end
end
- ruby_version_is "3.2"..."3.4" do
- it 'returns Float::INFINITY for all beginless ranges if the end is numeric' do
+ ruby_version_is "3.2" do
+ it 'returns Float::INFINITY for all beginless ranges if the start is numeric' do
(..1).size.should == Float::INFINITY
(...0.5).size.should == Float::INFINITY
end
- it 'returns nil for all beginless ranges if the end is not numeric' do
+ it 'returns nil for all beginless ranges if the start is numeric' do
(...'o').size.should == nil
end
@@ -46,54 +58,6 @@ describe "Range#size" do
end
end
- ruby_version_is ""..."3.4" do
- it "returns the number of elements in the range" do
- (1.0..16.0).size.should == 16
- (1.0...16.0).size.should == 15
- (1.0..15.9).size.should == 15
- (1.1..16.0).size.should == 15
- (1.1..15.9).size.should == 15
- end
-
- it "returns 0 if last is less than first" do
- (16.0..0.0).size.should == 0
- (Float::INFINITY..0).size.should == 0
- end
-
- it 'returns Float::INFINITY for increasing, infinite ranges' do
- (-Float::INFINITY..0).size.should == Float::INFINITY
- (-Float::INFINITY..Float::INFINITY).size.should == Float::INFINITY
- end
-
- it 'returns Float::INFINITY for endless ranges if the start is numeric' do
- eval("(0.5...)").size.should == Float::INFINITY
- end
-
- it 'returns nil for endless ranges if the start is not numeric' do
- eval("([]...)").size.should == nil
- end
- end
-
- ruby_version_is "3.4" do
- it 'raises TypeError if a range is not iterable' do
- -> { (1.0..16.0).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (1.0...16.0).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (1.0..15.9).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (1.1..16.0).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (1.1..15.9).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (16.0..0.0).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (Float::INFINITY..0).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (-Float::INFINITY..0).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (-Float::INFINITY..Float::INFINITY).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (..1).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (...0.5).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (..nil).size }.should raise_error(TypeError, /can't iterate from/)
- -> { (...'o').size }.should raise_error(TypeError, /can't iterate from/)
- -> { eval("(0.5...)").size }.should raise_error(TypeError, /can't iterate from/)
- -> { eval("([]...)").size }.should raise_error(TypeError, /can't iterate from/)
- end
- end
-
it "returns nil if first and last are not Numeric" do
(:a..:z).size.should be_nil
('a'..'z').size.should be_nil
diff --git a/spec/ruby/core/range/step_spec.rb b/spec/ruby/core/range/step_spec.rb
index 31cfd400cc..61ddc5205d 100644
--- a/spec/ruby/core/range/step_spec.rb
+++ b/spec/ruby/core/range/step_spec.rb
@@ -10,50 +10,44 @@ describe "Range#step" do
r.step { }.should equal(r)
end
- ruby_version_is ""..."3.4" do
- it "calls #to_int to coerce step to an Integer" do
- obj = mock("Range#step")
- obj.should_receive(:to_int).and_return(1)
-
- (1..2).step(obj) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1, 2])
- end
+ it "raises TypeError if step" do
+ obj = mock("mock")
+ -> { (1..10).step(obj) { } }.should raise_error(TypeError)
+ end
- it "raises a TypeError if step does not respond to #to_int" do
- obj = mock("Range#step non-integer")
+ it "calls #to_int to coerce step to an Integer" do
+ obj = mock("Range#step")
+ obj.should_receive(:to_int).and_return(1)
- -> { (1..2).step(obj) { } }.should raise_error(TypeError)
- end
+ (1..2).step(obj) { |x| ScratchPad << x }
+ ScratchPad.recorded.should eql([1, 2])
+ end
- it "raises a TypeError if #to_int does not return an Integer" do
- obj = mock("Range#step non-integer")
- obj.should_receive(:to_int).and_return("1")
+ it "raises a TypeError if step does not respond to #to_int" do
+ obj = mock("Range#step non-integer")
- -> { (1..2).step(obj) { } }.should raise_error(TypeError)
- end
+ -> { (1..2).step(obj) { } }.should raise_error(TypeError)
+ end
- it "raises a TypeError if the first element does not respond to #succ" do
- obj = mock("Range#step non-comparable")
- obj.should_receive(:<=>).with(obj).and_return(1)
+ it "raises a TypeError if #to_int does not return an Integer" do
+ obj = mock("Range#step non-integer")
+ obj.should_receive(:to_int).and_return("1")
- -> { (obj..obj).step { |x| x } }.should raise_error(TypeError)
- end
+ -> { (1..2).step(obj) { } }.should raise_error(TypeError)
end
- ruby_version_is "3.4" do
- it "calls #coerce to coerce step to an Integer" do
- obj = mock("Range#step")
- obj.should_receive(:coerce).at_least(:once).and_return([1, 2])
-
- (1..3).step(obj) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1, 3])
- end
+ it "coerces the argument to integer by invoking to_int" do
+ (obj = mock("2")).should_receive(:to_int).and_return(2)
+ res = []
+ (1..10).step(obj) {|x| res << x}
+ res.should == [1, 3, 5, 7, 9]
+ end
- it "raises a TypeError if step does not respond to #coerce" do
- obj = mock("Range#step non-coercible")
+ it "raises a TypeError if the first element does not respond to #succ" do
+ obj = mock("Range#step non-comparable")
+ obj.should_receive(:<=>).with(obj).and_return(1)
- -> { (1..2).step(obj) { } }.should raise_error(TypeError)
- end
+ -> { (obj..obj).step { |x| x } }.should raise_error(TypeError)
end
it "raises an ArgumentError if step is 0" do
@@ -64,17 +58,8 @@ describe "Range#step" do
-> { (-1..1).step(0.0) { |x| x } }.should raise_error(ArgumentError)
end
- ruby_version_is "3.4" do
- it "does not raise an ArgumentError if step is 0 for non-numeric ranges" do
- t = Time.utc(2023, 2, 24)
- -> { (t..t+1).step(0) { break } }.should_not raise_error(ArgumentError)
- end
- end
-
- ruby_version_is ""..."3.4" do
- it "raises an ArgumentError if step is negative" do
- -> { (-1..1).step(-2) { |x| x } }.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError if step is negative" do
+ -> { (-1..1).step(-2) { |x| x } }.should raise_error(ArgumentError)
end
describe "with inclusive end" do
@@ -93,18 +78,6 @@ describe "Range#step" do
(-2..2).step(1.5) { |x| ScratchPad << x }
ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
end
-
- ruby_version_is "3.4" do
- it "does not iterate if step is negative for forward range" do
- (-1..1).step(-1) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([])
- end
-
- it "iterates backward if step is negative for backward range" do
- (1..-1).step(-1) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1, 0, -1])
- end
- end
end
describe "and Float values" do
@@ -189,96 +162,13 @@ describe "Range#step" do
-> { ("A".."G").step(2.0) { } }.should raise_error(TypeError)
end
- ruby_version_is ""..."3.4" do
- it "calls #succ on begin and each element returned by #succ" do
- obj = mock("Range#step String start")
- obj.should_receive(:<=>).exactly(3).times.and_return(-1, -1, -1, 0)
- obj.should_receive(:succ).exactly(2).times.and_return(obj)
+ it "calls #succ on begin and each element returned by #succ" do
+ obj = mock("Range#step String start")
+ obj.should_receive(:<=>).exactly(3).times.and_return(-1, -1, -1, 0)
+ obj.should_receive(:succ).exactly(2).times.and_return(obj)
- (obj..obj).step { |x| ScratchPad << x }
- ScratchPad.recorded.should == [obj, obj, obj]
- end
- end
-
- ruby_version_is "3.4" do
- it "yields String values adjusted by step and less than or equal to end" do
- ("A".."AAA").step("A") { |x| ScratchPad << x }
- ScratchPad.recorded.should == ["A", "AA", "AAA"]
- end
-
- it "raises a TypeError when passed an incompatible type step" do
- -> { ("A".."G").step([]) { } }.should raise_error(TypeError)
- end
-
- it "calls #+ on begin and each element returned by #+" do
- start = mock("Range#step String start")
- stop = mock("Range#step String stop")
-
- mid1 = mock("Range#step String mid1")
- mid2 = mock("Range#step String mid2")
-
- step = mock("Range#step String step")
-
- # Deciding on the direction of iteration
- start.should_receive(:<=>).with(stop).at_least(:twice).and_return(-1)
- # Deciding whether the step moves iteration in the right direction
- start.should_receive(:<=>).with(mid1).and_return(-1)
- # Iteration 1
- start.should_receive(:+).at_least(:once).with(step).and_return(mid1)
- # Iteration 2
- mid1.should_receive(:<=>).with(stop).and_return(-1)
- mid1.should_receive(:+).with(step).and_return(mid2)
- # Iteration 3
- mid2.should_receive(:<=>).with(stop).and_return(0)
-
- (start..stop).step(step) { |x| ScratchPad << x }
- ScratchPad.recorded.should == [start, mid1, mid2]
- end
-
- it "iterates backward if the step is decreasing values, and the range is backward" do
- start = mock("Range#step String start")
- stop = mock("Range#step String stop")
-
- mid1 = mock("Range#step String mid1")
- mid2 = mock("Range#step String mid2")
-
- step = mock("Range#step String step")
-
- # Deciding on the direction of iteration
- start.should_receive(:<=>).with(stop).at_least(:twice).and_return(1)
- # Deciding whether the step moves iteration in the right direction
- start.should_receive(:<=>).with(mid1).and_return(1)
- # Iteration 1
- start.should_receive(:+).at_least(:once).with(step).and_return(mid1)
- # Iteration 2
- mid1.should_receive(:<=>).with(stop).and_return(1)
- mid1.should_receive(:+).with(step).and_return(mid2)
- # Iteration 3
- mid2.should_receive(:<=>).with(stop).and_return(0)
-
- (start..stop).step(step) { |x| ScratchPad << x }
- ScratchPad.recorded.should == [start, mid1, mid2]
- end
-
- it "does no iteration of the direction of the range and of the step don't match" do
- start = mock("Range#step String start")
- stop = mock("Range#step String stop")
-
- mid1 = mock("Range#step String mid1")
- mid2 = mock("Range#step String mid2")
-
- step = mock("Range#step String step")
-
- # Deciding on the direction of iteration: stop > start
- start.should_receive(:<=>).with(stop).at_least(:twice).and_return(1)
- # Deciding whether the step moves iteration in the right direction
- # start + step < start, the direction is opposite to the range's
- start.should_receive(:+).with(step).and_return(mid1)
- start.should_receive(:<=>).with(mid1).and_return(-1)
-
- (start..stop).step(step) { |x| ScratchPad << x }
- ScratchPad.recorded.should == []
- end
+ (obj..obj).step { |x| ScratchPad << x }
+ ScratchPad.recorded.should == [obj, obj, obj]
end
end
end
@@ -376,31 +266,18 @@ describe "Range#step" do
end
describe "and String values" do
- ruby_version_is ""..."3.4" do
- it "yields String values incremented by #succ and less than or equal to end when not passed a step" do
- ("A"..."E").step { |x| ScratchPad << x }
- ScratchPad.recorded.should == ["A", "B", "C", "D"]
- end
-
- it "yields String values incremented by #succ called Integer step times" do
- ("A"..."G").step(2) { |x| ScratchPad << x }
- ScratchPad.recorded.should == ["A", "C", "E"]
- end
-
- it "raises a TypeError when passed a Float step" do
- -> { ("A"..."G").step(2.0) { } }.should raise_error(TypeError)
- end
+ it "yields String values incremented by #succ and less than or equal to end when not passed a step" do
+ ("A"..."E").step { |x| ScratchPad << x }
+ ScratchPad.recorded.should == ["A", "B", "C", "D"]
end
- ruby_version_is "3.4" do
- it "yields String values adjusted by step and less than or equal to end" do
- ("A"..."AAA").step("A") { |x| ScratchPad << x }
- ScratchPad.recorded.should == ["A", "AA"]
- end
+ it "yields String values incremented by #succ called Integer step times" do
+ ("A"..."G").step(2) { |x| ScratchPad << x }
+ ScratchPad.recorded.should == ["A", "C", "E"]
+ end
- it "raises a TypeError when passed an incompatible type step" do
- -> { ("A".."G").step([]) { } }.should raise_error(TypeError)
- end
+ it "raises a TypeError when passed a Float step" do
+ -> { ("A"..."G").step(2.0) { } }.should raise_error(TypeError)
end
end
end
@@ -496,33 +373,35 @@ describe "Range#step" do
-> { eval("('A'..)").step(2.0) { } }.should raise_error(TypeError)
-> { eval("('A'...)").step(2.0) { } }.should raise_error(TypeError)
end
-
- ruby_version_is "3.4" do
- it "yields String values adjusted by step" do
- eval("('A'..)").step("A") { |x| break if x > "AAA"; ScratchPad << x }
- ScratchPad.recorded.should == ["A", "AA", "AAA"]
-
- ScratchPad.record []
- eval("('A'...)").step("A") { |x| break if x > "AAA"; ScratchPad << x }
- ScratchPad.recorded.should == ["A", "AA", "AAA"]
- end
-
- it "raises a TypeError when passed an incompatible type step" do
- -> { eval("('A'..)").step([]) { } }.should raise_error(TypeError)
- -> { eval("('A'...)").step([]) { } }.should raise_error(TypeError)
- end
- end
end
end
describe "when no block is given" do
- it "raises an ArgumentError if step is 0" do
- -> { (-1..1).step(0) }.should raise_error(ArgumentError)
+ ruby_version_is "3.0" do
+ it "raises an ArgumentError if step is 0" do
+ -> { (-1..1).step(0) }.should raise_error(ArgumentError)
+ end
end
describe "returned Enumerator" do
describe "size" do
- ruby_version_is ""..."3.4" do
+ ruby_version_is ""..."3.0" do
+ it "raises a TypeError if step does not respond to #to_int" do
+ obj = mock("Range#step non-integer")
+ enum = (1..2).step(obj)
+ -> { enum.size }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError if #to_int does not return an Integer" do
+ obj = mock("Range#step non-integer")
+ obj.should_receive(:to_int).and_return("1")
+ enum = (1..2).step(obj)
+
+ -> { enum.size }.should raise_error(TypeError)
+ end
+ end
+
+ ruby_version_is "3.0" do
it "raises a TypeError if step does not respond to #to_int" do
obj = mock("Range#step non-integer")
-> { (1..2).step(obj) }.should raise_error(TypeError)
@@ -535,10 +414,10 @@ describe "Range#step" do
end
end
- ruby_version_is "3.4" do
- it "does not raise if step is incompatible" do
- obj = mock("Range#step non-integer")
- -> { (1..2).step(obj) }.should_not raise_error
+ ruby_version_is ""..."3.0" do
+ it "returns Float::INFINITY for zero step" do
+ (-1..1).step(0).size.should == Float::INFINITY
+ (-1..1).step(0.0).size.should == Float::INFINITY
end
end
@@ -579,47 +458,26 @@ describe "Range#step" do
(1.0...6.4).step(1.8).size.should == 3
end
- ruby_version_is ""..."3.4" do
- it "returns nil with begin and end are String" do
- ("A".."E").step(2).size.should == nil
- ("A"..."E").step(2).size.should == nil
- ("A".."E").step.size.should == nil
- ("A"..."E").step.size.should == nil
- end
-
- it "return nil and not raises a TypeError if the first element does not respond to #succ" do
- obj = mock("Range#step non-comparable")
- obj.should_receive(:<=>).with(obj).and_return(1)
- enum = (obj..obj).step
- -> { enum.size }.should_not raise_error
- enum.size.should == nil
- end
+ it "returns nil with begin and end are String" do
+ ("A".."E").step(2).size.should == nil
+ ("A"..."E").step(2).size.should == nil
+ ("A".."E").step.size.should == nil
+ ("A"..."E").step.size.should == nil
end
- ruby_version_is "3.4" do
- it "returns nil with begin and end are String" do
- ("A".."E").step("A").size.should == nil
- ("A"..."E").step("A").size.should == nil
- end
-
- it "return nil and not raises a TypeError if the first element is not of compatible type" do
- obj = mock("Range#step non-comparable")
- obj.should_receive(:<=>).with(obj).and_return(1)
- enum = (obj..obj).step(obj)
- -> { enum.size }.should_not raise_error
- enum.size.should == nil
- end
+ it "return nil and not raises a TypeError if the first element does not respond to #succ" do
+ obj = mock("Range#step non-comparable")
+ obj.should_receive(:<=>).with(obj).and_return(1)
+ enum = (obj..obj).step
+ -> { enum.size }.should_not raise_error
+ enum.size.should == nil
end
end
- # We use .take below to ensure the enumerator works
- # because that's an Enumerable method and so it uses the Enumerator behavior
- # not just a method overridden in Enumerator::ArithmeticSequence.
describe "type" do
context "when both begin and end are numerics" do
it "returns an instance of Enumerator::ArithmeticSequence" do
(1..10).step.class.should == Enumerator::ArithmeticSequence
- (1..10).step(3).take(4).should == [1, 4, 7, 10]
end
end
@@ -632,51 +490,22 @@ describe "Range#step" do
context "when range is endless" do
it "returns an instance of Enumerator::ArithmeticSequence when begin is numeric" do
(1..).step.class.should == Enumerator::ArithmeticSequence
- (1..).step(2).take(3).should == [1, 3, 5]
- end
-
- ruby_version_is ""..."3.4" do
- it "returns an instance of Enumerator when begin is not numeric" do
- ("a"..).step.class.should == Enumerator
- ("a"..).step(2).take(3).should == %w[a c e]
- end
end
- ruby_version_is "3.4" do
- it "returns an instance of Enumerator when begin is not numeric" do
- ("a"..).step("a").class.should == Enumerator
- ("a"..).step("a").take(3).should == %w[a aa aaa]
- end
+ it "returns an instance of Enumerator when begin is not numeric" do
+ ("a"..).step.class.should == Enumerator
end
end
context "when range is beginless and endless" do
- ruby_version_is ""..."3.4" do
- it "returns an instance of Enumerator" do
- Range.new(nil, nil).step.class.should == Enumerator
- end
- end
-
- ruby_version_is "3.4" do
- it "raises an ArgumentError" do
- -> { Range.new(nil, nil).step(1) }.should raise_error(ArgumentError)
- end
+ it "returns an instance of Enumerator" do
+ Range.new(nil, nil).step.class.should == Enumerator
end
end
context "when begin and end are not numerics" do
- ruby_version_is ""..."3.4" do
- it "returns an instance of Enumerator" do
- ("a".."z").step.class.should == Enumerator
- ("a".."z").step(3).take(4).should == %w[a d g j]
- end
- end
-
- ruby_version_is "3.4" do
- it "returns an instance of Enumerator" do
- ("a".."z").step("a").class.should == Enumerator
- ("a".."z").step("a").take(4).should == %w[a aa aaa aaaa]
- end
+ it "returns an instance of Enumerator" do
+ ("a".."z").step.class.should == Enumerator
end
end
end
diff --git a/spec/ruby/core/rational/abs_spec.rb b/spec/ruby/core/rational/abs_spec.rb
index 7272ad2422..aed7713058 100644
--- a/spec/ruby/core/rational/abs_spec.rb
+++ b/spec/ruby/core/rational/abs_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/abs'
describe "Rational#abs" do
diff --git a/spec/ruby/core/rational/ceil_spec.rb b/spec/ruby/core/rational/ceil_spec.rb
index e736351604..5b0ca4a9d6 100644
--- a/spec/ruby/core/rational/ceil_spec.rb
+++ b/spec/ruby/core/rational/ceil_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/ceil'
describe "Rational#ceil" do
diff --git a/spec/ruby/core/rational/coerce_spec.rb b/spec/ruby/core/rational/coerce_spec.rb
new file mode 100644
index 0000000000..3f78f0bcd6
--- /dev/null
+++ b/spec/ruby/core/rational/coerce_spec.rb
@@ -0,0 +1,5 @@
+require_relative '../../shared/rational/coerce'
+
+describe "Rational#coerce" do
+ it_behaves_like :rational_coerce, :coerce
+end
diff --git a/spec/ruby/core/rational/comparison_spec.rb b/spec/ruby/core/rational/comparison_spec.rb
index 877069fb8f..9d8e7fd7ee 100644
--- a/spec/ruby/core/rational/comparison_spec.rb
+++ b/spec/ruby/core/rational/comparison_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/comparison'
describe "Rational#<=> when passed a Rational object" do
diff --git a/spec/ruby/core/rational/denominator_spec.rb b/spec/ruby/core/rational/denominator_spec.rb
index c2f49b4190..6214b40587 100644
--- a/spec/ruby/core/rational/denominator_spec.rb
+++ b/spec/ruby/core/rational/denominator_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/denominator'
describe "Rational#denominator" do
diff --git a/spec/ruby/core/rational/div_spec.rb b/spec/ruby/core/rational/div_spec.rb
index bee7d01a67..1cd8606b90 100644
--- a/spec/ruby/core/rational/div_spec.rb
+++ b/spec/ruby/core/rational/div_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/div'
describe "Rational#div" do
diff --git a/spec/ruby/core/rational/divide_spec.rb b/spec/ruby/core/rational/divide_spec.rb
index 14e8c4c195..d8e3a44dc2 100644
--- a/spec/ruby/core/rational/divide_spec.rb
+++ b/spec/ruby/core/rational/divide_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/divide'
require_relative '../../shared/rational/arithmetic_exception_in_coerce'
diff --git a/spec/ruby/core/rational/divmod_spec.rb b/spec/ruby/core/rational/divmod_spec.rb
index 7ffdde74f4..6be1f8bd73 100644
--- a/spec/ruby/core/rational/divmod_spec.rb
+++ b/spec/ruby/core/rational/divmod_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/divmod'
describe "Rational#divmod when passed a Rational" do
diff --git a/spec/ruby/core/rational/equal_value_spec.rb b/spec/ruby/core/rational/equal_value_spec.rb
index c6f7f4c6a2..8e7acb1354 100644
--- a/spec/ruby/core/rational/equal_value_spec.rb
+++ b/spec/ruby/core/rational/equal_value_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/equal_value'
describe "Rational#==" do
diff --git a/spec/ruby/core/rational/exponent_spec.rb b/spec/ruby/core/rational/exponent_spec.rb
index 7e35b4ebc1..622cf22782 100644
--- a/spec/ruby/core/rational/exponent_spec.rb
+++ b/spec/ruby/core/rational/exponent_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/exponent'
describe "Rational#**" do
diff --git a/spec/ruby/core/rational/fdiv_spec.rb b/spec/ruby/core/rational/fdiv_spec.rb
index b75f39abd5..bfb321abaa 100644
--- a/spec/ruby/core/rational/fdiv_spec.rb
+++ b/spec/ruby/core/rational/fdiv_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/fdiv'
describe "Rational#fdiv" do
diff --git a/spec/ruby/core/rational/floor_spec.rb b/spec/ruby/core/rational/floor_spec.rb
index 70db0499d0..752a2d8815 100644
--- a/spec/ruby/core/rational/floor_spec.rb
+++ b/spec/ruby/core/rational/floor_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/floor'
describe "Rational#floor" do
diff --git a/spec/ruby/core/rational/hash_spec.rb b/spec/ruby/core/rational/hash_spec.rb
index 7e8d30049b..84cd31518a 100644
--- a/spec/ruby/core/rational/hash_spec.rb
+++ b/spec/ruby/core/rational/hash_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/hash'
describe "Rational#hash" do
diff --git a/spec/ruby/core/rational/inspect_spec.rb b/spec/ruby/core/rational/inspect_spec.rb
index 2cbf6cadc1..ef337ef0ce 100644
--- a/spec/ruby/core/rational/inspect_spec.rb
+++ b/spec/ruby/core/rational/inspect_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/inspect'
describe "Rational#inspect" do
diff --git a/spec/ruby/core/rational/integer_spec.rb b/spec/ruby/core/rational/integer_spec.rb
index be7476a9dd..0f9a3bdead 100644
--- a/spec/ruby/core/rational/integer_spec.rb
+++ b/spec/ruby/core/rational/integer_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
describe "Rational#integer?" do
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
diff --git a/spec/ruby/core/rational/magnitude_spec.rb b/spec/ruby/core/rational/magnitude_spec.rb
index 27d9af6a81..878fc8f879 100644
--- a/spec/ruby/core/rational/magnitude_spec.rb
+++ b/spec/ruby/core/rational/magnitude_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/abs'
describe "Rational#abs" do
diff --git a/spec/ruby/core/rational/modulo_spec.rb b/spec/ruby/core/rational/modulo_spec.rb
index 7a60c176ac..c43f7788e3 100644
--- a/spec/ruby/core/rational/modulo_spec.rb
+++ b/spec/ruby/core/rational/modulo_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/modulo'
describe "Rational#%" do
diff --git a/spec/ruby/core/rational/multiply_spec.rb b/spec/ruby/core/rational/multiply_spec.rb
index 7413376bb1..ea644074e9 100644
--- a/spec/ruby/core/rational/multiply_spec.rb
+++ b/spec/ruby/core/rational/multiply_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/multiply'
require_relative '../../shared/rational/arithmetic_exception_in_coerce'
diff --git a/spec/ruby/core/rational/numerator_spec.rb b/spec/ruby/core/rational/numerator_spec.rb
index 6f9a9c0e3b..85b2ed9e86 100644
--- a/spec/ruby/core/rational/numerator_spec.rb
+++ b/spec/ruby/core/rational/numerator_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/numerator'
describe "Rational#numerator" do
diff --git a/spec/ruby/core/rational/plus_spec.rb b/spec/ruby/core/rational/plus_spec.rb
index 67c0ff63d2..e7ef3a8f92 100644
--- a/spec/ruby/core/rational/plus_spec.rb
+++ b/spec/ruby/core/rational/plus_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/plus'
require_relative '../../shared/rational/arithmetic_exception_in_coerce'
diff --git a/spec/ruby/core/rational/quo_spec.rb b/spec/ruby/core/rational/quo_spec.rb
index 181f091f7c..119aca1955 100644
--- a/spec/ruby/core/rational/quo_spec.rb
+++ b/spec/ruby/core/rational/quo_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/divide'
describe "Rational#quo" do
diff --git a/spec/ruby/core/rational/remainder_spec.rb b/spec/ruby/core/rational/remainder_spec.rb
index 1c0035e5f4..0f9442f6f5 100644
--- a/spec/ruby/core/rational/remainder_spec.rb
+++ b/spec/ruby/core/rational/remainder_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/remainder'
describe "Rational#remainder" do
diff --git a/spec/ruby/core/rational/to_f_spec.rb b/spec/ruby/core/rational/to_f_spec.rb
index a9cd1be3b5..15bf1e88dc 100644
--- a/spec/ruby/core/rational/to_f_spec.rb
+++ b/spec/ruby/core/rational/to_f_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/to_f'
describe "Rational#to_f" do
diff --git a/spec/ruby/core/rational/to_i_spec.rb b/spec/ruby/core/rational/to_i_spec.rb
index 22cf02b4da..3deb3664e1 100644
--- a/spec/ruby/core/rational/to_i_spec.rb
+++ b/spec/ruby/core/rational/to_i_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/to_i'
describe "Rational#to_i" do
diff --git a/spec/ruby/core/rational/to_r_spec.rb b/spec/ruby/core/rational/to_r_spec.rb
index 03f204daf1..cc704c965e 100644
--- a/spec/ruby/core/rational/to_r_spec.rb
+++ b/spec/ruby/core/rational/to_r_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/to_r'
describe "Rational#to_r" do
diff --git a/spec/ruby/core/rational/to_s_spec.rb b/spec/ruby/core/rational/to_s_spec.rb
index 5d90c7d80b..c5c419787c 100644
--- a/spec/ruby/core/rational/to_s_spec.rb
+++ b/spec/ruby/core/rational/to_s_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/to_s'
describe "Rational#to_s" do
diff --git a/spec/ruby/core/rational/truncate_spec.rb b/spec/ruby/core/rational/truncate_spec.rb
index 47a7cdf17c..4e72339752 100644
--- a/spec/ruby/core/rational/truncate_spec.rb
+++ b/spec/ruby/core/rational/truncate_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative '../../shared/rational/truncate'
describe "Rational#truncate" do
diff --git a/spec/ruby/core/rational/zero_spec.rb b/spec/ruby/core/rational/zero_spec.rb
index af7fb391ac..e6dd751922 100644
--- a/spec/ruby/core/rational/zero_spec.rb
+++ b/spec/ruby/core/rational/zero_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
describe "Rational#zero?" do
it "returns true if the numerator is 0" do
Rational(0,26).zero?.should be_true
diff --git a/spec/ruby/core/refinement/extend_object_spec.rb b/spec/ruby/core/refinement/extend_object_spec.rb
index 6c2a0af4f3..e44e9f46d8 100644
--- a/spec/ruby/core/refinement/extend_object_spec.rb
+++ b/spec/ruby/core/refinement/extend_object_spec.rb
@@ -11,10 +11,8 @@ describe "Refinement#extend_object" do
Module.new do
refine c do
called = false
- define_method(:extend_object) { called = true }
- -> {
- c.extend(self)
- }.should raise_error(TypeError)
+ define_method(:extend_object){called = true}
+ proc{c.extend(self)}.should raise_error(TypeError)
called.should == false
end
end
diff --git a/spec/ruby/core/refinement/fixtures/classes.rb b/spec/ruby/core/refinement/fixtures/classes.rb
deleted file mode 100644
index 94324db47c..0000000000
--- a/spec/ruby/core/refinement/fixtures/classes.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-module RefinementSpec
-
- module ModuleWithAncestors
- include Module.new do
- def indent(level)
- " " * level + self
- end
- end
- end
-end
diff --git a/spec/ruby/core/refinement/import_methods_spec.rb b/spec/ruby/core/refinement/import_methods_spec.rb
index 614c54dff8..1c526f5822 100644
--- a/spec/ruby/core/refinement/import_methods_spec.rb
+++ b/spec/ruby/core/refinement/import_methods_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
describe "Refinement#import_methods" do
ruby_version_is "3.1" do
@@ -18,229 +17,6 @@ describe "Refinement#import_methods" do
end
end
end
-
- it "throws an exception when argument is not a module" do
- Module.new do
- refine String do
- -> {
- import_methods Integer
- }.should raise_error(TypeError, "wrong argument type Class (expected Module)")
- end
- end
- end
-
- it "imports methods from multiple modules" do
- str_utils = Module.new do
- def indent(level)
- " " * level + self
- end
- end
-
- str_utils_fancy = Module.new do
- def indent_star(level)
- "*" * level + self
- end
- end
-
- Module.new do
- refine String do
- import_methods str_utils, str_utils_fancy
- "foo".indent(3).should == " foo"
- "foo".indent_star(3).should == "***foo"
- end
- end
- end
-
- it "imports a method defined in the last module if method with same name is defined in multiple modules" do
- str_utils = Module.new do
- def indent(level)
- " " * level + self
- end
- end
-
- str_utils_fancy = Module.new do
- def indent(level)
- "*" * level + self
- end
- end
-
- Module.new do
- refine String do
- import_methods str_utils, str_utils_fancy
- "foo".indent(3).should == "***foo"
- end
- end
- end
-
- it "still imports methods of modules listed before a module that contains method not defined in Ruby" do
- str_utils = Module.new do
- def indent(level)
- " " * level + self
- end
- end
-
- string_refined = Module.new do
- refine String do
- -> {
- import_methods str_utils, Kernel
- }.should raise_error(ArgumentError)
- end
- end
-
- Module.new do
- using string_refined
- "foo".indent(3).should == " foo"
- end
- end
- end
-
- it "warns if a module includes/prepends some other module" do
- module1 = Module.new do
- end
-
- module2 = Module.new do
- include module1
- end
-
- Module.new do
- refine String do
- -> {
- import_methods module2
- }.should complain(/warning: #<Module:\w*> has ancestors, but Refinement#import_methods doesn't import their methods/)
- end
- end
-
- Module.new do
- refine String do
- -> {
- import_methods RefinementSpec::ModuleWithAncestors
- }.should complain(/warning: RefinementSpec::ModuleWithAncestors has ancestors, but Refinement#import_methods doesn't import their methods/)
- end
- end
- end
-
- it "doesn't import methods from included/prepended modules" do
- Module.new do
- refine String do
- suppress_warning { import_methods RefinementSpec::ModuleWithAncestors }
- end
-
- using self
- -> {
- "foo".indent(3)
- }.should raise_error(NoMethodError, /undefined method [`']indent' for ("foo":String|an instance of String)/)
- end
- end
-
- it "doesn't import any methods if one of the arguments is not a module" do
- str_utils = Module.new do
- def indent(level)
- " " * level + self
- end
- end
-
- string_refined = Module.new do
- refine String do
- -> {
- import_methods str_utils, Integer
- }.should raise_error(TypeError)
- end
- end
-
- Module.new do
- using string_refined
- -> {
- "foo".indent(3)
- }.should raise_error(NoMethodError)
- end
- end
-
- it "imports methods from multiple modules so that methods see other's module's methods" do
- str_utils = Module.new do
- def indent(level)
- " " * level + self
- end
- end
-
- str_utils_normal = Module.new do
- def indent_normal(level)
- self.indent(level)
- end
- end
-
- Module.new do
- refine String do
- import_methods str_utils, str_utils_normal
- end
-
- using self
- "foo".indent_normal(3).should == " foo"
- end
- end
-
- it "imports methods from module so that methods can see each other" do
- str_utils = Module.new do
- def indent(level)
- " " * level + self
- end
-
- def indent_with_dot(level)
- self.indent(level) + "."
- end
- end
-
- Module.new do
- refine String do
- import_methods str_utils
- end
-
- using self
- "foo".indent_with_dot(3).should == " foo."
- end
- end
-
- it "doesn't import module's class methods" do
- str_utils = Module.new do
- def self.indent(level)
- " " * level + self
- end
- end
-
- Module.new do
- refine String do
- import_methods str_utils
- end
-
- using self
- -> {
- String.indent(3)
- }.should raise_error(NoMethodError, /undefined method [`']indent' for (String:Class|class String)/)
- end
- end
-
- it "imports module methods with super" do
- class_to_refine = Class.new do
- def foo(number)
- 2 * number
- end
- end
-
- extension = Module.new do
- def foo(number)
- super * 2
- end
- end
-
- refinement = Module.new do
- refine class_to_refine do
- import_methods extension
- end
- end
-
- Module.new do
- using refinement
- class_to_refine.new.foo(2).should == 8
- end
end
context "when methods are not defined in Ruby code" do
@@ -253,17 +29,6 @@ describe "Refinement#import_methods" do
end
end
end
-
- it "raises ArgumentError when importing methods from C extension" do
- require 'zlib'
- Module.new do
- refine String do
- -> {
- import_methods Zlib
- }.should raise_error(ArgumentError, /Can't import method which is not defined with Ruby code: Zlib#*/)
- end
- end
- end
end
end
end
diff --git a/spec/ruby/core/refinement/refined_class_spec.rb b/spec/ruby/core/refinement/refined_class_spec.rb
deleted file mode 100644
index 00b65d0895..0000000000
--- a/spec/ruby/core/refinement/refined_class_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "Refinement#refined_class" do
- ruby_version_is "3.2"..."3.3" do
- it "returns the class refined by the receiver" do
- refinement_int = nil
-
- Module.new do
- refine Integer do
- refinement_int = self
- end
- end
-
- refinement_int.refined_class.should == Integer
- end
- end
-end
diff --git a/spec/ruby/core/regexp/initialize_spec.rb b/spec/ruby/core/regexp/initialize_spec.rb
index dd57292242..a1583384af 100644
--- a/spec/ruby/core/regexp/initialize_spec.rb
+++ b/spec/ruby/core/regexp/initialize_spec.rb
@@ -5,8 +5,16 @@ describe "Regexp#initialize" do
Regexp.should have_private_instance_method(:initialize)
end
- it "raises a FrozenError on a Regexp literal" do
- -> { //.send(:initialize, "") }.should raise_error(FrozenError)
+ ruby_version_is ""..."3.0" do
+ it "raises a SecurityError on a Regexp literal" do
+ -> { //.send(:initialize, "") }.should raise_error(SecurityError)
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "raises a FrozenError on a Regexp literal" do
+ -> { //.send(:initialize, "") }.should raise_error(FrozenError)
+ end
end
it "raises a TypeError on an initialized non-literal Regexp" do
diff --git a/spec/ruby/core/regexp/linear_time_spec.rb b/spec/ruby/core/regexp/linear_time_spec.rb
deleted file mode 100644
index 4dc436264f..0000000000
--- a/spec/ruby/core/regexp/linear_time_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Regexp.linear_time?" do
- it "returns true if matching can be done in linear time" do
- Regexp.linear_time?(/a/).should == true
- Regexp.linear_time?('a').should == true
- end
-
- it "return false if matching can't be done in linear time" do
- Regexp.linear_time?(/(a)\1/).should == false
- Regexp.linear_time?("(a)\\1").should == false
- end
-
- it "accepts flags for string argument" do
- Regexp.linear_time?('a', Regexp::IGNORECASE).should == true
- end
-
- it "warns about flags being ignored for regexp arguments" do
- -> {
- Regexp.linear_time?(/a/, Regexp::IGNORECASE)
- }.should complain(/warning: flags ignored/)
- end
- end
-end
diff --git a/spec/ruby/core/regexp/shared/new.rb b/spec/ruby/core/regexp/shared/new.rb
index 7052bcab63..058a51b1aa 100644
--- a/spec/ruby/core/regexp/shared/new.rb
+++ b/spec/ruby/core/regexp/shared/new.rb
@@ -56,7 +56,7 @@ describe :regexp_new_string, shared: true do
end
it "raises a RegexpError when passed an incorrect regexp" do
- -> { Regexp.send(@method, "^[$", 0) }.should raise_error(RegexpError, Regexp.new(Regexp.escape("premature end of char-class: /^[$/")))
+ -> { Regexp.send(@method, "^[$", 0) }.should raise_error(RegexpError)
end
it "does not set Regexp options if only given one argument" do
@@ -123,30 +123,14 @@ describe :regexp_new_string, shared: true do
(r.options & Regexp::EXTENDED).should_not == 0
end
- ruby_version_is ""..."3.2" do
- it "does not try to convert the second argument to Integer with #to_int method call" do
- ScratchPad.clear
- obj = Object.new
- def obj.to_int() ScratchPad.record(:called) end
-
- Regexp.send(@method, "Hi", obj)
-
- ScratchPad.recorded.should == nil
- end
- end
-
- ruby_version_is "3.2" do
- it "does not try to convert the second argument to Integer with #to_int method call" do
- ScratchPad.clear
- obj = Object.new
- def obj.to_int() ScratchPad.record(:called) end
+ it "does not try to convert the second argument to Integer with #to_int method call" do
+ ScratchPad.clear
+ obj = Object.new
+ def obj.to_int() ScratchPad.record(:called) end
- -> {
- Regexp.send(@method, "Hi", obj)
- }.should complain(/expected true or false as ignorecase/, {verbose: true})
+ Regexp.send(@method, "Hi", obj)
- ScratchPad.recorded.should == nil
- end
+ ScratchPad.recorded.should == nil
end
ruby_version_is ""..."3.2" do
@@ -204,12 +188,12 @@ describe :regexp_new_string, shared: true do
end
it "raises an Argument error if the second argument contains unsupported chars" do
- -> { Regexp.send(@method, 'Hi', 'e') }.should raise_error(ArgumentError, "unknown regexp option: e")
- -> { Regexp.send(@method, 'Hi', 'n') }.should raise_error(ArgumentError, "unknown regexp option: n")
- -> { Regexp.send(@method, 'Hi', 's') }.should raise_error(ArgumentError, "unknown regexp option: s")
- -> { Regexp.send(@method, 'Hi', 'u') }.should raise_error(ArgumentError, "unknown regexp option: u")
- -> { Regexp.send(@method, 'Hi', 'j') }.should raise_error(ArgumentError, "unknown regexp option: j")
- -> { Regexp.send(@method, 'Hi', 'mjx') }.should raise_error(ArgumentError, /unknown regexp option: mjx\b/)
+ -> { Regexp.send(@method, 'Hi', 'e') }.should raise_error(ArgumentError)
+ -> { Regexp.send(@method, 'Hi', 'n') }.should raise_error(ArgumentError)
+ -> { Regexp.send(@method, 'Hi', 's') }.should raise_error(ArgumentError)
+ -> { Regexp.send(@method, 'Hi', 'u') }.should raise_error(ArgumentError)
+ -> { Regexp.send(@method, 'Hi', 'j') }.should raise_error(ArgumentError)
+ -> { Regexp.send(@method, 'Hi', 'mjx') }.should raise_error(ArgumentError)
end
end
@@ -261,7 +245,7 @@ describe :regexp_new_string, shared: true do
describe "with escaped characters" do
it "raises a Regexp error if there is a trailing backslash" do
- -> { Regexp.send(@method, "\\") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("too short escape sequence: /\\/")))
+ -> { Regexp.send(@method, "\\") }.should raise_error(RegexpError)
end
it "does not raise a Regexp error if there is an escaped trailing backslash" do
@@ -293,7 +277,7 @@ describe :regexp_new_string, shared: true do
end
it "raises a RegexpError if \\x is not followed by any hexadecimal digits" do
- -> { Regexp.send(@method, "\\" + "xn") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid hex escape: /\\xn/")))
+ -> { Regexp.send(@method, "\\" + "xn") }.should raise_error(RegexpError)
end
it "accepts an escaped string interpolation" do
@@ -448,20 +432,16 @@ describe :regexp_new_string, shared: true do
Regexp.send(@method, "\056\x42\u3042\x52\076").should == /#{"\x2e\x42\u3042\x52\x3e"}/
end
- it "accepts a multiple byte character which need not be escaped" do
- Regexp.send(@method, "\§").should == /#{"§"}/
- end
-
it "raises a RegexpError if less than four digits are given for \\uHHHH" do
- -> { Regexp.send(@method, "\\" + "u304") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid Unicode escape: /\\u304/")))
+ -> { Regexp.send(@method, "\\" + "u304") }.should raise_error(RegexpError)
end
it "raises a RegexpError if the \\u{} escape is empty" do
- -> { Regexp.send(@method, "\\" + "u{}") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid Unicode list: /\\u{}/")))
+ -> { Regexp.send(@method, "\\" + "u{}") }.should raise_error(RegexpError)
end
it "raises a RegexpError if more than six hexadecimal digits are given" do
- -> { Regexp.send(@method, "\\" + "u{0ffffff}") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid Unicode range: /\\u{0ffffff}/")))
+ -> { Regexp.send(@method, "\\" + "u{0ffffff}") }.should raise_error(RegexpError)
end
it "returns a Regexp with US-ASCII encoding if only 7-bit ASCII characters are present regardless of the input String's encoding" do
@@ -489,12 +469,12 @@ describe :regexp_new_string, shared: true do
end
it "returns a Regexp with the input String's encoding" do
- str = "\x82\xa0".dup.force_encoding(Encoding::Shift_JIS)
+ str = "\x82\xa0".force_encoding(Encoding::Shift_JIS)
Regexp.send(@method, str).encoding.should == Encoding::Shift_JIS
end
it "returns a Regexp with source String having the input String's encoding" do
- str = "\x82\xa0".dup.force_encoding(Encoding::Shift_JIS)
+ str = "\x82\xa0".force_encoding(Encoding::Shift_JIS)
Regexp.send(@method, str).source.encoding.should == Encoding::Shift_JIS
end
end
diff --git a/spec/ruby/core/regexp/shared/quote.rb b/spec/ruby/core/regexp/shared/quote.rb
index b5ecc35f04..9533102766 100644
--- a/spec/ruby/core/regexp/shared/quote.rb
+++ b/spec/ruby/core/regexp/shared/quote.rb
@@ -18,23 +18,23 @@ describe :regexp_quote, shared: true do
end
it "works for broken strings" do
- Regexp.send(@method, "a.\x85b.".dup.force_encoding("US-ASCII")).should =="a\\.\x85b\\.".dup.force_encoding("US-ASCII")
- Regexp.send(@method, "a.\x80".dup.force_encoding("UTF-8")).should == "a\\.\x80".dup.force_encoding("UTF-8")
+ Regexp.send(@method, "a.\x85b.".force_encoding("US-ASCII")).should =="a\\.\x85b\\.".force_encoding("US-ASCII")
+ Regexp.send(@method, "a.\x80".force_encoding("UTF-8")).should == "a\\.\x80".force_encoding("UTF-8")
end
it "sets the encoding of the result to US-ASCII if there are only US-ASCII characters present in the input String" do
- str = "abc".dup.force_encoding("euc-jp")
+ str = "abc".force_encoding("euc-jp")
Regexp.send(@method, str).encoding.should == Encoding::US_ASCII
end
it "sets the encoding of the result to the encoding of the String if any non-US-ASCII characters are present in an input String with valid encoding" do
- str = "ã‚りãŒã¨ã†".dup.force_encoding("utf-8")
+ str = "ã‚りãŒã¨ã†".force_encoding("utf-8")
str.valid_encoding?.should be_true
Regexp.send(@method, str).encoding.should == Encoding::UTF_8
end
it "sets the encoding of the result to BINARY if any non-US-ASCII characters are present in an input String with invalid encoding" do
- str = "\xff".dup.force_encoding "us-ascii"
+ str = "\xff".force_encoding "us-ascii"
str.valid_encoding?.should be_false
Regexp.send(@method, "\xff").encoding.should == Encoding::BINARY
end
diff --git a/spec/ruby/core/regexp/try_convert_spec.rb b/spec/ruby/core/regexp/try_convert_spec.rb
index e775dbe971..be567e2130 100644
--- a/spec/ruby/core/regexp/try_convert_spec.rb
+++ b/spec/ruby/core/regexp/try_convert_spec.rb
@@ -18,10 +18,4 @@ describe "Regexp.try_convert" do
rex.should_receive(:to_regexp).and_return(/(p(a)t[e]rn)/)
Regexp.try_convert(rex).should == /(p(a)t[e]rn)/
end
-
- it "raises a TypeError if the object does not return an Regexp from #to_regexp" do
- obj = mock("regexp")
- obj.should_receive(:to_regexp).and_return("string")
- -> { Regexp.try_convert(obj) }.should raise_error(TypeError, "can't convert MockObject to Regexp (MockObject#to_regexp gives String)")
- end
end
diff --git a/spec/ruby/core/regexp/union_spec.rb b/spec/ruby/core/regexp/union_spec.rb
index ea5a5053f7..8076836471 100644
--- a/spec/ruby/core/regexp/union_spec.rb
+++ b/spec/ruby/core/regexp/union_spec.rb
@@ -43,27 +43,6 @@ describe "Regexp.union" do
Regexp.union("\u00A9".encode("ISO-8859-1"), "a".encode("UTF-8")).encoding.should == Encoding::ISO_8859_1
end
- it "returns ASCII-8BIT if the regexp encodings are ASCII-8BIT and at least one has non-ASCII characters" do
- us_ascii_implicit, us_ascii_explicit, binary = /abc/, /[\x00-\x7f]/n, /[\x80-\xBF]/n
- us_ascii_implicit.encoding.should == Encoding::US_ASCII
- us_ascii_explicit.encoding.should == Encoding::US_ASCII
- binary.encoding.should == Encoding::BINARY
-
- Regexp.union(us_ascii_implicit, us_ascii_explicit, binary).encoding.should == Encoding::BINARY
- Regexp.union(us_ascii_implicit, binary, us_ascii_explicit).encoding.should == Encoding::BINARY
- Regexp.union(us_ascii_explicit, us_ascii_implicit, binary).encoding.should == Encoding::BINARY
- Regexp.union(us_ascii_explicit, binary, us_ascii_implicit).encoding.should == Encoding::BINARY
- Regexp.union(binary, us_ascii_implicit, us_ascii_explicit).encoding.should == Encoding::BINARY
- Regexp.union(binary, us_ascii_explicit, us_ascii_implicit).encoding.should == Encoding::BINARY
- end
-
- it "return US-ASCII if all patterns are ASCII-only" do
- Regexp.union(/abc/e, /def/e).encoding.should == Encoding::US_ASCII
- Regexp.union(/abc/n, /def/n).encoding.should == Encoding::US_ASCII
- Regexp.union(/abc/s, /def/s).encoding.should == Encoding::US_ASCII
- Regexp.union(/abc/u, /def/u).encoding.should == Encoding::US_ASCII
- end
-
it "returns a Regexp with UTF-8 if one part is UTF-8" do
Regexp.union(/probl[éeè]me/i, /help/i).encoding.should == Encoding::UTF_8
end
@@ -75,83 +54,83 @@ describe "Regexp.union" do
it "raises ArgumentError if the arguments include conflicting ASCII-incompatible Strings" do
-> {
Regexp.union("a".encode("UTF-16LE"), "b".encode("UTF-16BE"))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and UTF-16BE')
+ }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the arguments include conflicting ASCII-incompatible Regexps" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")),
Regexp.new("b".encode("UTF-16BE")))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and UTF-16BE')
+ }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the arguments include conflicting fixed encoding Regexps" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-8"), Regexp::FIXEDENCODING),
Regexp.new("b".encode("US-ASCII"), Regexp::FIXEDENCODING))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-8 and US-ASCII')
+ }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the arguments include a fixed encoding Regexp and a String containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-8"), Regexp::FIXEDENCODING),
"\u00A9".encode("ISO-8859-1"))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-8 and ISO-8859-1')
+ }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the arguments include a String containing non-ASCII-compatible characters and a fixed encoding Regexp in a different encoding" do
-> {
Regexp.union("\u00A9".encode("ISO-8859-1"),
Regexp.new("a".encode("UTF-8"), Regexp::FIXEDENCODING))
- }.should raise_error(ArgumentError, 'incompatible encodings: ISO-8859-1 and UTF-8')
+ }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible String and an ASCII-only String" do
-> {
Regexp.union("a".encode("UTF-16LE"), "b".encode("UTF-8"))
- }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
+ }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and an ASCII-only String" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")), "b".encode("UTF-8"))
- }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
+ }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible String and an ASCII-only Regexp" do
-> {
Regexp.union("a".encode("UTF-16LE"), Regexp.new("b".encode("UTF-8")))
- }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
+ }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and an ASCII-only Regexp" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")), Regexp.new("b".encode("UTF-8")))
- }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
+ }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible String and a String containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union("a".encode("UTF-16LE"), "\u00A9".encode("ISO-8859-1"))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
+ }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and a String containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")), "\u00A9".encode("ISO-8859-1"))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
+ }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible String and a Regexp containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union("a".encode("UTF-16LE"), Regexp.new("\u00A9".encode("ISO-8859-1")))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
+ }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and a Regexp containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")), Regexp.new("\u00A9".encode("ISO-8859-1")))
- }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
+ }.should raise_error(ArgumentError)
end
it "uses to_str to convert arguments (if not Regexp)" do
@@ -175,8 +154,6 @@ describe "Regexp.union" do
not_supported_on :opal do
Regexp.union([/dogs/, /cats/i]).should == /(?-mix:dogs)|(?i-mx:cats)/
end
- -> {
- Regexp.union(["skiing", "sledding"], [/dogs/, /cats/i])
- }.should raise_error(TypeError, 'no implicit conversion of Array into String')
+ ->{Regexp.union(["skiing", "sledding"], [/dogs/, /cats/i])}.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/signal/signame_spec.rb b/spec/ruby/core/signal/signame_spec.rb
index adfe895d97..b66de9fc85 100644
--- a/spec/ruby/core/signal/signame_spec.rb
+++ b/spec/ruby/core/signal/signame_spec.rb
@@ -9,22 +9,10 @@ describe "Signal.signame" do
Signal.signame(-1).should == nil
end
- it "calls #to_int on an object to convert to an Integer" do
- obj = mock('signal')
- obj.should_receive(:to_int).and_return(0)
- Signal.signame(obj).should == "EXIT"
- end
-
it "raises a TypeError when the passed argument can't be coerced to Integer" do
-> { Signal.signame("hello") }.should raise_error(TypeError)
end
- it "raises a TypeError when the passed argument responds to #to_int but does not return an Integer" do
- obj = mock('signal')
- obj.should_receive(:to_int).and_return('not an int')
- -> { Signal.signame(obj) }.should raise_error(TypeError)
- end
-
platform_is_not :windows do
it "the original should take precedence over alias when looked up by number" do
Signal.signame(Signal.list["ABRT"]).should == "ABRT"
diff --git a/spec/ruby/core/signal/trap_spec.rb b/spec/ruby/core/signal/trap_spec.rb
index 6d654a99be..10e122e072 100644
--- a/spec/ruby/core/signal/trap_spec.rb
+++ b/spec/ruby/core/signal/trap_spec.rb
@@ -221,29 +221,10 @@ describe "Signal.trap" do
Signal.trap(:HUP, @saved_trap).should equal(@proc)
end
- it "calls #to_str on an object to convert to a String" do
- obj = mock("signal")
- obj.should_receive(:to_str).exactly(2).times.and_return("HUP")
- Signal.trap obj, @proc
- Signal.trap(obj, @saved_trap).should equal(@proc)
- end
-
- it "accepts Integer values" do
- hup = Signal.list["HUP"]
- Signal.trap hup, @proc
- Signal.trap(hup, @saved_trap).should equal(@proc)
- end
-
- it "does not call #to_int on an object to convert to an Integer" do
- obj = mock("signal")
- obj.should_not_receive(:to_int)
- -> { Signal.trap obj, @proc }.should raise_error(ArgumentError, /bad signal type/)
- end
-
it "raises ArgumentError when passed unknown signal" do
-> { Signal.trap(300) { } }.should raise_error(ArgumentError, "invalid signal number (300)")
- -> { Signal.trap("USR10") { } }.should raise_error(ArgumentError, /\Aunsupported signal [`']SIGUSR10'\z/)
- -> { Signal.trap("SIGUSR10") { } }.should raise_error(ArgumentError, /\Aunsupported signal [`']SIGUSR10'\z/)
+ -> { Signal.trap("USR10") { } }.should raise_error(ArgumentError, "unsupported signal `SIGUSR10'")
+ -> { Signal.trap("SIGUSR10") { } }.should raise_error(ArgumentError, "unsupported signal `SIGUSR10'")
end
it "raises ArgumentError when passed signal is not Integer, String or Symbol" do
@@ -264,14 +245,6 @@ describe "Signal.trap" do
end
end
- %w[SEGV BUS ILL FPE VTALRM].each do |signal|
- it "raises ArgumentError for SIG#{signal} which is reserved by Ruby" do
- -> {
- Signal.trap(signal, -> {})
- }.should raise_error(ArgumentError, "can't trap reserved signal: SIG#{signal}")
- end
- end
-
it "allows to register a handler for all known signals, except reserved signals for which it raises ArgumentError" do
out = ruby_exe(fixture(__FILE__, "trap_all.rb"), args: "2>&1")
out.should == "OK\n"
diff --git a/spec/ruby/core/sizedqueue/append_spec.rb b/spec/ruby/core/sizedqueue/append_spec.rb
index 6fffe2f272..ca79068930 100644
--- a/spec/ruby/core/sizedqueue/append_spec.rb
+++ b/spec/ruby/core/sizedqueue/append_spec.rb
@@ -1,7 +1,6 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/enque'
require_relative '../../shared/sizedqueue/enque'
-require_relative '../../shared/types/rb_num2dbl_fails'
describe "SizedQueue#<<" do
it_behaves_like :queue_enq, :<<, -> { SizedQueue.new(10) }
@@ -10,9 +9,3 @@ end
describe "SizedQueue#<<" do
it_behaves_like :sizedqueue_enq, :<<, -> n { SizedQueue.new(n) }
end
-
-describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.send(:<<, 1, timeout: v) }
- end
-end
diff --git a/spec/ruby/core/sizedqueue/deq_spec.rb b/spec/ruby/core/sizedqueue/deq_spec.rb
index 985d654bb3..5e1bd9f746 100644
--- a/spec/ruby/core/sizedqueue/deq_spec.rb
+++ b/spec/ruby/core/sizedqueue/deq_spec.rb
@@ -1,13 +1,6 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/deque'
-require_relative '../../shared/types/rb_num2dbl_fails'
describe "SizedQueue#deq" do
it_behaves_like :queue_deq, :deq, -> { SizedQueue.new(10) }
end
-
-describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.deq(timeout: v) }
- end
-end
diff --git a/spec/ruby/core/sizedqueue/enq_spec.rb b/spec/ruby/core/sizedqueue/enq_spec.rb
index 619373e46b..3821afac95 100644
--- a/spec/ruby/core/sizedqueue/enq_spec.rb
+++ b/spec/ruby/core/sizedqueue/enq_spec.rb
@@ -1,7 +1,6 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/enque'
require_relative '../../shared/sizedqueue/enque'
-require_relative '../../shared/types/rb_num2dbl_fails'
describe "SizedQueue#enq" do
it_behaves_like :queue_enq, :enq, -> { SizedQueue.new(10) }
@@ -10,9 +9,3 @@ end
describe "SizedQueue#enq" do
it_behaves_like :sizedqueue_enq, :enq, -> n { SizedQueue.new(n) }
end
-
-describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.enq(1, timeout: v) }
- end
-end
diff --git a/spec/ruby/core/sizedqueue/pop_spec.rb b/spec/ruby/core/sizedqueue/pop_spec.rb
index 5e7cfea8fb..a0cf6f509c 100644
--- a/spec/ruby/core/sizedqueue/pop_spec.rb
+++ b/spec/ruby/core/sizedqueue/pop_spec.rb
@@ -1,13 +1,6 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/deque'
-require_relative '../../shared/types/rb_num2dbl_fails'
describe "SizedQueue#pop" do
it_behaves_like :queue_deq, :pop, -> { SizedQueue.new(10) }
end
-
-describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.pop(timeout: v) }
- end
-end
diff --git a/spec/ruby/core/sizedqueue/push_spec.rb b/spec/ruby/core/sizedqueue/push_spec.rb
index ce61e89b53..bba9be9e3f 100644
--- a/spec/ruby/core/sizedqueue/push_spec.rb
+++ b/spec/ruby/core/sizedqueue/push_spec.rb
@@ -1,7 +1,6 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/enque'
require_relative '../../shared/sizedqueue/enque'
-require_relative '../../shared/types/rb_num2dbl_fails'
describe "SizedQueue#push" do
it_behaves_like :queue_enq, :push, -> { SizedQueue.new(10) }
@@ -10,9 +9,3 @@ end
describe "SizedQueue#push" do
it_behaves_like :sizedqueue_enq, :push, -> n { SizedQueue.new(n) }
end
-
-describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.push(1, timeout: v) }
- end
-end
diff --git a/spec/ruby/core/sizedqueue/shift_spec.rb b/spec/ruby/core/sizedqueue/shift_spec.rb
index 3220801f3a..5138e68258 100644
--- a/spec/ruby/core/sizedqueue/shift_spec.rb
+++ b/spec/ruby/core/sizedqueue/shift_spec.rb
@@ -1,13 +1,6 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/deque'
-require_relative '../../shared/types/rb_num2dbl_fails'
describe "SizedQueue#shift" do
it_behaves_like :queue_deq, :shift, -> { SizedQueue.new(10) }
end
-
-describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.shift(timeout: v) }
- end
-end
diff --git a/spec/ruby/core/string/append_as_bytes_spec.rb b/spec/ruby/core/string/append_as_bytes_spec.rb
deleted file mode 100644
index 0e1d09558b..0000000000
--- a/spec/ruby/core/string/append_as_bytes_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "String#append_bytes" do
- ruby_version_is "3.4" do
- it "doesn't allow to mutate frozen strings" do
- str = "hello".freeze
- -> { str.append_as_bytes("\xE2\x82") }.should raise_error(FrozenError)
- end
-
- it "allows creating broken strings" do
- str = +"hello"
- str.append_as_bytes("\xE2\x82")
- str.valid_encoding?.should == false
-
- str.append_as_bytes("\xAC")
- str.valid_encoding?.should == true
-
- str = "abc".encode(Encoding::UTF_32LE)
- str.append_as_bytes("def")
- str.encoding.should == Encoding::UTF_32LE
- str.valid_encoding?.should == false
- end
-
- it "never changes the receiver encoding" do
- str = "".b
- str.append_as_bytes("€")
- str.encoding.should == Encoding::BINARY
- end
-
- it "accepts variadic String or Integer arguments" do
- str = "hello".b
- str.append_as_bytes("\xE2\x82", 12, 43, "\xAC")
- str.encoding.should == Encoding::BINARY
- str.should == "hello\xE2\x82\f+\xAC".b
- end
-
- it "only accepts strings or integers, and doesn't attempt to cast with #to_str or #to_int" do
- to_str = mock("to_str")
- to_str.should_not_receive(:to_str)
- to_str.should_not_receive(:to_int)
-
- str = +"hello"
- -> { str.append_as_bytes(to_str) }.should raise_error(TypeError, "wrong argument type MockObject (expected String or Integer)")
- end
- end
-end
diff --git a/spec/ruby/core/string/append_spec.rb b/spec/ruby/core/string/append_spec.rb
index 8497ce8262..e001257621 100644
--- a/spec/ruby/core/string/append_spec.rb
+++ b/spec/ruby/core/string/append_spec.rb
@@ -5,7 +5,6 @@ require_relative 'shared/concat'
describe "String#<<" do
it_behaves_like :string_concat, :<<
it_behaves_like :string_concat_encoding, :<<
- it_behaves_like :string_concat_type_coercion, :<<
it "raises an ArgumentError when given the incorrect number of arguments" do
-> { "hello".send(:<<) }.should raise_error(ArgumentError)
diff --git a/spec/ruby/core/string/ascii_only_spec.rb b/spec/ruby/core/string/ascii_only_spec.rb
index 88a0559cfd..c7e02fd874 100644
--- a/spec/ruby/core/string/ascii_only_spec.rb
+++ b/spec/ruby/core/string/ascii_only_spec.rb
@@ -7,12 +7,12 @@ describe "String#ascii_only?" do
it "returns true if the encoding is UTF-8" do
[ ["hello", true],
["hello".encode('UTF-8'), true],
- ["hello".dup.force_encoding('UTF-8'), true],
+ ["hello".force_encoding('UTF-8'), true],
].should be_computed_by(:ascii_only?)
end
it "returns true if the encoding is US-ASCII" do
- "hello".dup.force_encoding(Encoding::US_ASCII).ascii_only?.should be_true
+ "hello".force_encoding(Encoding::US_ASCII).ascii_only?.should be_true
"hello".encode(Encoding::US_ASCII).ascii_only?.should be_true
end
@@ -34,13 +34,13 @@ describe "String#ascii_only?" do
[ ["\u{6666}", false],
["hello, \u{6666}", false],
["\u{6666}".encode('UTF-8'), false],
- ["\u{6666}".dup.force_encoding('UTF-8'), false],
+ ["\u{6666}".force_encoding('UTF-8'), false],
].should be_computed_by(:ascii_only?)
end
it "returns false if the encoding is US-ASCII" do
- [ ["\u{6666}".dup.force_encoding(Encoding::US_ASCII), false],
- ["hello, \u{6666}".dup.force_encoding(Encoding::US_ASCII), false],
+ [ ["\u{6666}".force_encoding(Encoding::US_ASCII), false],
+ ["hello, \u{6666}".force_encoding(Encoding::US_ASCII), false],
].should be_computed_by(:ascii_only?)
end
end
@@ -51,16 +51,17 @@ describe "String#ascii_only?" do
end
it "returns false for the empty String with a non-ASCII-compatible encoding" do
- "".dup.force_encoding('UTF-16LE').ascii_only?.should be_false
+ "".force_encoding('UTF-16LE').ascii_only?.should be_false
"".encode('UTF-16BE').ascii_only?.should be_false
end
it "returns false for a non-empty String with non-ASCII-compatible encoding" do
- "\x78\x00".dup.force_encoding("UTF-16LE").ascii_only?.should be_false
+ "\x78\x00".force_encoding("UTF-16LE").ascii_only?.should be_false
end
it "returns false when interpolating non ascii strings" do
- base = "EU currency is".dup.force_encoding(Encoding::US_ASCII)
+ base = "EU currency is"
+ base.force_encoding(Encoding::US_ASCII)
euro = "\u20AC"
interp = "#{base} #{euro}"
euro.ascii_only?.should be_false
@@ -69,14 +70,14 @@ describe "String#ascii_only?" do
end
it "returns false after appending non ASCII characters to an empty String" do
- ("".dup << "λ").ascii_only?.should be_false
+ ("" << "λ").ascii_only?.should be_false
end
it "returns false when concatenating an ASCII and non-ASCII String" do
- "".dup.concat("λ").ascii_only?.should be_false
+ "".concat("λ").ascii_only?.should be_false
end
it "returns false when replacing an ASCII String with a non-ASCII String" do
- "".dup.replace("λ").ascii_only?.should be_false
+ "".replace("λ").ascii_only?.should be_false
end
end
diff --git a/spec/ruby/core/string/b_spec.rb b/spec/ruby/core/string/b_spec.rb
index 4b1fafff11..37c7994700 100644
--- a/spec/ruby/core/string/b_spec.rb
+++ b/spec/ruby/core/string/b_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
describe "String#b" do
diff --git a/spec/ruby/core/string/byteindex_spec.rb b/spec/ruby/core/string/byteindex_spec.rb
index 47c7be1029..af70c729e8 100644
--- a/spec/ruby/core/string/byteindex_spec.rb
+++ b/spec/ruby/core/string/byteindex_spec.rb
@@ -1,304 +1,16 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/byte_index_common.rb'
-
-describe "String#byteindex" do
- ruby_version_is "3.2" do
- it "calls #to_str to convert the first argument" do
- char = mock("string index char")
- char.should_receive(:to_str).and_return("b")
- "abc".byteindex(char).should == 1
- end
-
- it "calls #to_int to convert the second argument" do
- offset = mock("string index offset")
- offset.should_receive(:to_int).and_return(1)
- "abc".byteindex("c", offset).should == 2
- end
-
- it "does not raise IndexError when byte offset is correct or on string boundary" do
- "ã‚".byteindex("").should == 0
- "ã‚".byteindex("", 0).should == 0
- "ã‚".byteindex("", 3).should == 3
- end
-
- it_behaves_like :byte_index_common, :byteindex
- end
-end
-
-describe "String#byteindex with String" do
- ruby_version_is "3.2" do
- it "behaves the same as String#byteindex(char) for one-character strings" do
- "blablabla hello cruel world...!".split("").uniq.each do |str|
- chr = str[0]
- str.byteindex(str).should == str.byteindex(chr)
-
- 0.upto(str.size + 1) do |start|
- str.byteindex(str, start).should == str.byteindex(chr, start)
- end
-
- (-str.size - 1).upto(-1) do |start|
- str.byteindex(str, start).should == str.byteindex(chr, start)
- end
- end
- end
-
- it "returns the byteindex of the first occurrence of the given substring" do
- "blablabla".byteindex("").should == 0
- "blablabla".byteindex("b").should == 0
- "blablabla".byteindex("bla").should == 0
- "blablabla".byteindex("blabla").should == 0
- "blablabla".byteindex("blablabla").should == 0
-
- "blablabla".byteindex("l").should == 1
- "blablabla".byteindex("la").should == 1
- "blablabla".byteindex("labla").should == 1
- "blablabla".byteindex("lablabla").should == 1
-
- "blablabla".byteindex("a").should == 2
- "blablabla".byteindex("abla").should == 2
- "blablabla".byteindex("ablabla").should == 2
- end
-
- it "treats the offset as a byteindex" do
- "aaaaa".byteindex("a", 0).should == 0
- "aaaaa".byteindex("a", 2).should == 2
- "aaaaa".byteindex("a", 4).should == 4
- end
-
- it "ignores string subclasses" do
- "blablabla".byteindex(StringSpecs::MyString.new("bla")).should == 0
- StringSpecs::MyString.new("blablabla").byteindex("bla").should == 0
- StringSpecs::MyString.new("blablabla").byteindex(StringSpecs::MyString.new("bla")).should == 0
- end
-
- it "starts the search at the given offset" do
- "blablabla".byteindex("bl", 0).should == 0
- "blablabla".byteindex("bl", 1).should == 3
- "blablabla".byteindex("bl", 2).should == 3
- "blablabla".byteindex("bl", 3).should == 3
-
- "blablabla".byteindex("bla", 0).should == 0
- "blablabla".byteindex("bla", 1).should == 3
- "blablabla".byteindex("bla", 2).should == 3
- "blablabla".byteindex("bla", 3).should == 3
-
- "blablabla".byteindex("blab", 0).should == 0
- "blablabla".byteindex("blab", 1).should == 3
- "blablabla".byteindex("blab", 2).should == 3
- "blablabla".byteindex("blab", 3).should == 3
-
- "blablabla".byteindex("la", 1).should == 1
- "blablabla".byteindex("la", 2).should == 4
- "blablabla".byteindex("la", 3).should == 4
- "blablabla".byteindex("la", 4).should == 4
-
- "blablabla".byteindex("lab", 1).should == 1
- "blablabla".byteindex("lab", 2).should == 4
- "blablabla".byteindex("lab", 3).should == 4
- "blablabla".byteindex("lab", 4).should == 4
-
- "blablabla".byteindex("ab", 2).should == 2
- "blablabla".byteindex("ab", 3).should == 5
- "blablabla".byteindex("ab", 4).should == 5
- "blablabla".byteindex("ab", 5).should == 5
-
- "blablabla".byteindex("", 0).should == 0
- "blablabla".byteindex("", 1).should == 1
- "blablabla".byteindex("", 2).should == 2
- "blablabla".byteindex("", 7).should == 7
- "blablabla".byteindex("", 8).should == 8
- "blablabla".byteindex("", 9).should == 9
- end
-
- it "starts the search at offset + self.length if offset is negative" do
- str = "blablabla"
-
- ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
- (-str.length .. -1).each do |offset|
- str.byteindex(needle, offset).should ==
- str.byteindex(needle, offset + str.length)
- end
- end
- end
-
- it "returns nil if the substring isn't found" do
- "blablabla".byteindex("B").should == nil
- "blablabla".byteindex("z").should == nil
- "blablabla".byteindex("BLA").should == nil
- "blablabla".byteindex("blablablabla").should == nil
- "blablabla".byteindex("", 10).should == nil
-
- "hello".byteindex("he", 1).should == nil
- "hello".byteindex("he", 2).should == nil
- "I’ve got a multibyte character.\n".byteindex("\n\n").should == nil
- end
-
- it "returns the character byteindex of a multibyte character" do
- "ã‚りãŒã¨ã†".byteindex("ãŒ").should == 6
- end
-
- it "returns the character byteindex after offset" do
- "ã‚れã‚れ".byteindex("ã‚", 3).should == 6
- "ã‚りãŒã¨ã†ã‚りãŒã¨ã†".byteindex("ãŒ", 9).should == 21
- end
-
- it "returns the character byteindex after a partial first match" do
- "</</h".byteindex("</h").should == 2
- end
-
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- char = "れ".encode Encoding::EUC_JP
- -> do
- "ã‚れ".byteindex(char)
- end.should raise_error(Encoding::CompatibilityError)
- end
-
- it "handles a substring in a superset encoding" do
- 'abc'.dup.force_encoding(Encoding::US_ASCII).byteindex('é').should == nil
- end
-
- it "handles a substring in a subset encoding" do
- 'été'.byteindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 2
- end
- end
-end
describe "String#byteindex with Regexp" do
ruby_version_is "3.2" do
- it "behaves the same as String#byteindex(string) for escaped string regexps" do
- ["blablabla", "hello cruel world...!"].each do |str|
- ["", "b", "bla", "lab", "o c", "d."].each do |needle|
- regexp = Regexp.new(Regexp.escape(needle))
- str.byteindex(regexp).should == str.byteindex(needle)
-
- 0.upto(str.size + 1) do |start|
- str.byteindex(regexp, start).should == str.byteindex(needle, start)
- end
-
- (-str.size - 1).upto(-1) do |start|
- str.byteindex(regexp, start).should == str.byteindex(needle, start)
- end
- end
- end
- end
-
- it "returns the byteindex of the first match of regexp" do
- "blablabla".byteindex(/bla/).should == 0
- "blablabla".byteindex(/BLA/i).should == 0
-
- "blablabla".byteindex(/.{0}/).should == 0
- "blablabla".byteindex(/.{6}/).should == 0
- "blablabla".byteindex(/.{9}/).should == 0
-
- "blablabla".byteindex(/.*/).should == 0
- "blablabla".byteindex(/.+/).should == 0
-
- "blablabla".byteindex(/lab|b/).should == 0
-
- not_supported_on :opal do
- "blablabla".byteindex(/\A/).should == 0
- "blablabla".byteindex(/\Z/).should == 9
- "blablabla".byteindex(/\z/).should == 9
- "blablabla\n".byteindex(/\Z/).should == 9
- "blablabla\n".byteindex(/\z/).should == 10
- end
-
- "blablabla".byteindex(/^/).should == 0
- "\nblablabla".byteindex(/^/).should == 0
- "b\nablabla".byteindex(/$/).should == 1
- "bl\nablabla".byteindex(/$/).should == 2
-
- "blablabla".byteindex(/.l./).should == 0
- end
-
- it "starts the search at the given offset" do
- "blablabla".byteindex(/.{0}/, 5).should == 5
- "blablabla".byteindex(/.{1}/, 5).should == 5
- "blablabla".byteindex(/.{2}/, 5).should == 5
- "blablabla".byteindex(/.{3}/, 5).should == 5
- "blablabla".byteindex(/.{4}/, 5).should == 5
-
- "blablabla".byteindex(/.{0}/, 3).should == 3
- "blablabla".byteindex(/.{1}/, 3).should == 3
- "blablabla".byteindex(/.{2}/, 3).should == 3
- "blablabla".byteindex(/.{5}/, 3).should == 3
- "blablabla".byteindex(/.{6}/, 3).should == 3
-
- "blablabla".byteindex(/.l./, 0).should == 0
- "blablabla".byteindex(/.l./, 1).should == 3
- "blablabla".byteindex(/.l./, 2).should == 3
- "blablabla".byteindex(/.l./, 3).should == 3
-
- "xblaxbla".byteindex(/x./, 0).should == 0
- "xblaxbla".byteindex(/x./, 1).should == 4
- "xblaxbla".byteindex(/x./, 2).should == 4
-
- not_supported_on :opal do
- "blablabla\n".byteindex(/\Z/, 9).should == 9
- end
- end
-
- it "starts the search at offset + self.length if offset is negative" do
- str = "blablabla"
-
- ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
- (-str.length .. -1).each do |offset|
- str.byteindex(needle, offset).should ==
- str.byteindex(needle, offset + str.length)
- end
- end
- end
-
- it "returns nil if the substring isn't found" do
- "blablabla".byteindex(/BLA/).should == nil
-
- "blablabla".byteindex(/.{10}/).should == nil
- "blaxbla".byteindex(/.x/, 3).should == nil
- "blaxbla".byteindex(/..x/, 2).should == nil
- end
-
- it "returns nil if the Regexp matches the empty string and the offset is out of range" do
- "ruby".byteindex(//, 12).should be_nil
- end
-
- it "supports \\G which matches at the given start offset" do
- "helloYOU.".byteindex(/\GYOU/, 5).should == 5
- "helloYOU.".byteindex(/\GYOU/).should == nil
-
- re = /\G.+YOU/
- # The # marks where \G will match.
- [
- ["#hi!YOUall.", 0],
- ["h#i!YOUall.", 1],
- ["hi#!YOUall.", 2],
- ["hi!#YOUall.", nil]
- ].each do |spec|
-
- start = spec[0].byteindex("#")
- str = spec[0].delete("#")
-
- str.byteindex(re, start).should == spec[1]
- end
- end
-
- it "converts start_offset to an integer via to_int" do
- obj = mock('1')
- obj.should_receive(:to_int).and_return(1)
- "RWOARW".byteindex(/R./, obj).should == 4
- end
-
- it "returns the character byteindex of a multibyte character" do
- "ã‚りãŒã¨ã†".byteindex(/ãŒ/).should == 6
- end
-
- it "returns the character byteindex after offset" do
- "ã‚れã‚れ".byteindex(/ã‚/, 3).should == 6
- end
+ it "always clear $~" do
+ "a".byteindex(/a/)
+ $~.should_not == nil
- it "treats the offset as a byteindex" do
- "ã‚れã‚ã‚れ".byteindex(/ã‚/, 6).should == 6
+ string = "blablabla"
+ string.byteindex(/bla/, string.bytesize + 1)
+ $~.should == nil
end
end
end
diff --git a/spec/ruby/core/string/byterindex_spec.rb b/spec/ruby/core/string/byterindex_spec.rb
deleted file mode 100644
index 150f709b90..0000000000
--- a/spec/ruby/core/string/byterindex_spec.rb
+++ /dev/null
@@ -1,359 +0,0 @@
-# -*- encoding: utf-8 -*-
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/byte_index_common.rb'
-
-describe "String#byterindex with object" do
- ruby_version_is "3.2" do
- it "tries to convert obj to a string via to_str" do
- obj = mock('lo')
- def obj.to_str() "lo" end
- "hello".byterindex(obj).should == "hello".byterindex("lo")
-
- obj = mock('o')
- def obj.respond_to?(arg, *) true end
- def obj.method_missing(*args) "o" end
- "hello".byterindex(obj).should == "hello".byterindex("o")
- end
-
- it "calls #to_int to convert the second argument" do
- offset = mock("string index offset")
- offset.should_receive(:to_int).and_return(3)
- "abc".byterindex("c", offset).should == 2
- end
-
- it "does not raise IndexError when byte offset is correct or on string boundary" do
- "ã‚".byterindex("", 0).should == 0
- "ã‚".byterindex("", 3).should == 3
- "ã‚".byterindex("").should == 3
- end
-
- it_behaves_like :byte_index_common, :byterindex
- end
-end
-
-describe "String#byterindex with String" do
- ruby_version_is "3.2" do
- it "behaves the same as String#byterindex(char) for one-character strings" do
- "blablabla hello cruel world...!".split("").uniq.each do |str|
- chr = str[0]
- str.byterindex(str).should == str.byterindex(chr)
-
- 0.upto(str.size + 1) do |start|
- str.byterindex(str, start).should == str.byterindex(chr, start)
- end
-
- (-str.size - 1).upto(-1) do |start|
- str.byterindex(str, start).should == str.byterindex(chr, start)
- end
- end
- end
-
- it "behaves the same as String#byterindex(?char) for one-character strings" do
- "blablabla hello cruel world...!".split("").uniq.each do |str|
- chr = str[0] =~ / / ? str[0] : eval("?#{str[0]}")
- str.byterindex(str).should == str.byterindex(chr)
-
- 0.upto(str.size + 1) do |start|
- str.byterindex(str, start).should == str.byterindex(chr, start)
- end
-
- (-str.size - 1).upto(-1) do |start|
- str.byterindex(str, start).should == str.byterindex(chr, start)
- end
- end
- end
-
- it "returns the index of the last occurrence of the given substring" do
- "blablabla".byterindex("").should == 9
- "blablabla".byterindex("a").should == 8
- "blablabla".byterindex("la").should == 7
- "blablabla".byterindex("bla").should == 6
- "blablabla".byterindex("abla").should == 5
- "blablabla".byterindex("labla").should == 4
- "blablabla".byterindex("blabla").should == 3
- "blablabla".byterindex("ablabla").should == 2
- "blablabla".byterindex("lablabla").should == 1
- "blablabla".byterindex("blablabla").should == 0
-
- "blablabla".byterindex("l").should == 7
- "blablabla".byterindex("bl").should == 6
- "blablabla".byterindex("abl").should == 5
- "blablabla".byterindex("labl").should == 4
- "blablabla".byterindex("blabl").should == 3
- "blablabla".byterindex("ablabl").should == 2
- "blablabla".byterindex("lablabl").should == 1
- "blablabla".byterindex("blablabl").should == 0
-
- "blablabla".byterindex("b").should == 6
- "blablabla".byterindex("ab").should == 5
- "blablabla".byterindex("lab").should == 4
- "blablabla".byterindex("blab").should == 3
- "blablabla".byterindex("ablab").should == 2
- "blablabla".byterindex("lablab").should == 1
- "blablabla".byterindex("blablab").should == 0
- end
-
- it "ignores string subclasses" do
- "blablabla".byterindex(StringSpecs::MyString.new("bla")).should == 6
- StringSpecs::MyString.new("blablabla").byterindex("bla").should == 6
- StringSpecs::MyString.new("blablabla").byterindex(StringSpecs::MyString.new("bla")).should == 6
- end
-
- it "starts the search at the given offset" do
- "blablabla".byterindex("bl", 0).should == 0
- "blablabla".byterindex("bl", 1).should == 0
- "blablabla".byterindex("bl", 2).should == 0
- "blablabla".byterindex("bl", 3).should == 3
-
- "blablabla".byterindex("bla", 0).should == 0
- "blablabla".byterindex("bla", 1).should == 0
- "blablabla".byterindex("bla", 2).should == 0
- "blablabla".byterindex("bla", 3).should == 3
-
- "blablabla".byterindex("blab", 0).should == 0
- "blablabla".byterindex("blab", 1).should == 0
- "blablabla".byterindex("blab", 2).should == 0
- "blablabla".byterindex("blab", 3).should == 3
- "blablabla".byterindex("blab", 6).should == 3
- "blablablax".byterindex("blab", 6).should == 3
-
- "blablabla".byterindex("la", 1).should == 1
- "blablabla".byterindex("la", 2).should == 1
- "blablabla".byterindex("la", 3).should == 1
- "blablabla".byterindex("la", 4).should == 4
-
- "blablabla".byterindex("lab", 1).should == 1
- "blablabla".byterindex("lab", 2).should == 1
- "blablabla".byterindex("lab", 3).should == 1
- "blablabla".byterindex("lab", 4).should == 4
-
- "blablabla".byterindex("ab", 2).should == 2
- "blablabla".byterindex("ab", 3).should == 2
- "blablabla".byterindex("ab", 4).should == 2
- "blablabla".byterindex("ab", 5).should == 5
-
- "blablabla".byterindex("", 0).should == 0
- "blablabla".byterindex("", 1).should == 1
- "blablabla".byterindex("", 2).should == 2
- "blablabla".byterindex("", 7).should == 7
- "blablabla".byterindex("", 8).should == 8
- "blablabla".byterindex("", 9).should == 9
- "blablabla".byterindex("", 10).should == 9
- end
-
- it "starts the search at offset + self.length if offset is negative" do
- str = "blablabla"
-
- ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
- (-str.length .. -1).each do |offset|
- str.byterindex(needle, offset).should ==
- str.byterindex(needle, offset + str.length)
- end
- end
- end
-
- it "returns nil if the substring isn't found" do
- "blablabla".byterindex("B").should == nil
- "blablabla".byterindex("z").should == nil
- "blablabla".byterindex("BLA").should == nil
- "blablabla".byterindex("blablablabla").should == nil
-
- "hello".byterindex("lo", 0).should == nil
- "hello".byterindex("lo", 1).should == nil
- "hello".byterindex("lo", 2).should == nil
-
- "hello".byterindex("llo", 0).should == nil
- "hello".byterindex("llo", 1).should == nil
-
- "hello".byterindex("el", 0).should == nil
- "hello".byterindex("ello", 0).should == nil
-
- "hello".byterindex("", -6).should == nil
- "hello".byterindex("", -7).should == nil
-
- "hello".byterindex("h", -6).should == nil
- end
-
- it "tries to convert start_offset to an integer via to_int" do
- obj = mock('5')
- def obj.to_int() 5 end
- "str".byterindex("st", obj).should == 0
-
- obj = mock('5')
- def obj.respond_to?(arg, *) true end
- def obj.method_missing(*args) 5 end
- "str".byterindex("st", obj).should == 0
- end
-
- it "raises a TypeError when given offset is nil" do
- -> { "str".byterindex("st", nil) }.should raise_error(TypeError)
- end
-
- it "handles a substring in a superset encoding" do
- 'abc'.dup.force_encoding(Encoding::US_ASCII).byterindex('é').should == nil
- end
-
- it "handles a substring in a subset encoding" do
- 'été'.byterindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 2
- end
- end
-end
-
-describe "String#byterindex with Regexp" do
- ruby_version_is "3.2" do
- it "behaves the same as String#byterindex(string) for escaped string regexps" do
- ["blablabla", "hello cruel world...!"].each do |str|
- ["", "b", "bla", "lab", "o c", "d."].each do |needle|
- regexp = Regexp.new(Regexp.escape(needle))
- str.byterindex(regexp).should == str.byterindex(needle)
-
- 0.upto(str.size + 1) do |start|
- str.byterindex(regexp, start).should == str.byterindex(needle, start)
- end
-
- (-str.size - 1).upto(-1) do |start|
- str.byterindex(regexp, start).should == str.byterindex(needle, start)
- end
- end
- end
- end
-
- it "returns the index of the first match from the end of string of regexp" do
- "blablabla".byterindex(/bla/).should == 6
- "blablabla".byterindex(/BLA/i).should == 6
-
- "blablabla".byterindex(/.{0}/).should == 9
- "blablabla".byterindex(/.{1}/).should == 8
- "blablabla".byterindex(/.{2}/).should == 7
- "blablabla".byterindex(/.{6}/).should == 3
- "blablabla".byterindex(/.{9}/).should == 0
-
- "blablabla".byterindex(/.*/).should == 9
- "blablabla".byterindex(/.+/).should == 8
-
- "blablabla".byterindex(/bla|a/).should == 8
-
- not_supported_on :opal do
- "blablabla".byterindex(/\A/).should == 0
- "blablabla".byterindex(/\Z/).should == 9
- "blablabla".byterindex(/\z/).should == 9
- "blablabla\n".byterindex(/\Z/).should == 10
- "blablabla\n".byterindex(/\z/).should == 10
- end
-
- "blablabla".byterindex(/^/).should == 0
- not_supported_on :opal do
- "\nblablabla".byterindex(/^/).should == 1
- "b\nlablabla".byterindex(/^/).should == 2
- end
- "blablabla".byterindex(/$/).should == 9
-
- "blablabla".byterindex(/.l./).should == 6
- end
-
- it "starts the search at the given offset" do
- "blablabla".byterindex(/.{0}/, 5).should == 5
- "blablabla".byterindex(/.{1}/, 5).should == 5
- "blablabla".byterindex(/.{2}/, 5).should == 5
- "blablabla".byterindex(/.{3}/, 5).should == 5
- "blablabla".byterindex(/.{4}/, 5).should == 5
-
- "blablabla".byterindex(/.{0}/, 3).should == 3
- "blablabla".byterindex(/.{1}/, 3).should == 3
- "blablabla".byterindex(/.{2}/, 3).should == 3
- "blablabla".byterindex(/.{5}/, 3).should == 3
- "blablabla".byterindex(/.{6}/, 3).should == 3
-
- "blablabla".byterindex(/.l./, 0).should == 0
- "blablabla".byterindex(/.l./, 1).should == 0
- "blablabla".byterindex(/.l./, 2).should == 0
- "blablabla".byterindex(/.l./, 3).should == 3
-
- "blablablax".byterindex(/.x/, 10).should == 8
- "blablablax".byterindex(/.x/, 9).should == 8
- "blablablax".byterindex(/.x/, 8).should == 8
-
- "blablablax".byterindex(/..x/, 10).should == 7
- "blablablax".byterindex(/..x/, 9).should == 7
- "blablablax".byterindex(/..x/, 8).should == 7
- "blablablax".byterindex(/..x/, 7).should == 7
-
- not_supported_on :opal do
- "blablabla\n".byterindex(/\Z/, 9).should == 9
- end
- end
-
- it "starts the search at offset + self.length if offset is negative" do
- str = "blablabla"
-
- ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
- (-str.length .. -1).each do |offset|
- str.byterindex(needle, offset).should ==
- str.byterindex(needle, offset + str.length)
- end
- end
- end
-
- it "returns nil if the substring isn't found" do
- "blablabla".byterindex(/BLA/).should == nil
- "blablabla".byterindex(/.{10}/).should == nil
- "blablablax".byterindex(/.x/, 7).should == nil
- "blablablax".byterindex(/..x/, 6).should == nil
-
- not_supported_on :opal do
- "blablabla".byterindex(/\Z/, 5).should == nil
- "blablabla".byterindex(/\z/, 5).should == nil
- "blablabla\n".byterindex(/\z/, 9).should == nil
- end
- end
-
- not_supported_on :opal do
- it "supports \\G which matches at the given start offset" do
- "helloYOU.".byterindex(/YOU\G/, 8).should == 5
- "helloYOU.".byterindex(/YOU\G/).should == nil
-
- idx = "helloYOUall!".index("YOU")
- re = /YOU.+\G.+/
- # The # marks where \G will match.
- [
- ["helloYOU#all.", nil],
- ["helloYOUa#ll.", idx],
- ["helloYOUal#l.", idx],
- ["helloYOUall#.", idx],
- ["helloYOUall.#", nil]
- ].each do |i|
- start = i[0].index("#")
- str = i[0].delete("#")
-
- str.byterindex(re, start).should == i[1]
- end
- end
- end
-
- it "tries to convert start_offset to an integer" do
- obj = mock('5')
- def obj.to_int() 5 end
- "str".byterindex(/../, obj).should == 1
-
- obj = mock('5')
- def obj.respond_to?(arg, *) true end
- def obj.method_missing(*args); 5; end
- "str".byterindex(/../, obj).should == 1
- end
-
- it "raises a TypeError when given offset is nil" do
- -> { "str".byterindex(/../, nil) }.should raise_error(TypeError)
- end
-
- it "returns the reverse byte index of a multibyte character" do
- "ã‚りãŒã‚ŠãŒã¨ã†".byterindex("ãŒ").should == 12
- "ã‚りãŒã‚ŠãŒã¨ã†".byterindex(/ãŒ/).should == 12
- end
-
- it "returns the character index before the finish" do
- "ã‚りãŒã‚ŠãŒã¨ã†".byterindex("ãŒ", 9).should == 6
- "ã‚りãŒã‚ŠãŒã¨ã†".byterindex(/ãŒ/, 9).should == 6
- end
- end
-end
diff --git a/spec/ruby/core/string/bytes_spec.rb b/spec/ruby/core/string/bytes_spec.rb
index 02151eebbc..859b346550 100644
--- a/spec/ruby/core/string/bytes_spec.rb
+++ b/spec/ruby/core/string/bytes_spec.rb
@@ -50,6 +50,6 @@ describe "String#bytes" do
end
it "is unaffected by #force_encoding" do
- @utf8.dup.force_encoding('ASCII').bytes.to_a.should == @utf8.bytes.to_a
+ @utf8.force_encoding('ASCII').bytes.to_a.should == @utf8.bytes.to_a
end
end
diff --git a/spec/ruby/core/string/bytesize_spec.rb b/spec/ruby/core/string/bytesize_spec.rb
index 2bbefc0820..a31f3ae671 100644
--- a/spec/ruby/core/string/bytesize_spec.rb
+++ b/spec/ruby/core/string/bytesize_spec.rb
@@ -13,21 +13,21 @@ describe "String#bytesize" do
end
it "works with pseudo-ASCII strings containing single UTF-8 characters" do
- "\u{6666}".dup.force_encoding('ASCII').bytesize.should == 3
+ "\u{6666}".force_encoding('ASCII').bytesize.should == 3
end
it "works with strings containing UTF-8 characters" do
- "c \u{6666}".dup.force_encoding('UTF-8').bytesize.should == 5
+ "c \u{6666}".force_encoding('UTF-8').bytesize.should == 5
"c \u{6666}".bytesize.should == 5
end
it "works with pseudo-ASCII strings containing UTF-8 characters" do
- "c \u{6666}".dup.force_encoding('ASCII').bytesize.should == 5
+ "c \u{6666}".force_encoding('ASCII').bytesize.should == 5
end
it "returns 0 for the empty string" do
"".bytesize.should == 0
- "".dup.force_encoding('ASCII').bytesize.should == 0
- "".dup.force_encoding('UTF-8').bytesize.should == 0
+ "".force_encoding('ASCII').bytesize.should == 0
+ "".force_encoding('UTF-8').bytesize.should == 0
end
end
diff --git a/spec/ruby/core/string/byteslice_spec.rb b/spec/ruby/core/string/byteslice_spec.rb
index 5b1027f4a5..312229523d 100644
--- a/spec/ruby/core/string/byteslice_spec.rb
+++ b/spec/ruby/core/string/byteslice_spec.rb
@@ -19,10 +19,10 @@ end
describe "String#byteslice on on non ASCII strings" do
it "returns byteslice of unicode strings" do
- "\u3042".byteslice(1).should == "\x81".dup.force_encoding("UTF-8")
- "\u3042".byteslice(1, 2).should == "\x81\x82".dup.force_encoding("UTF-8")
- "\u3042".byteslice(1..2).should == "\x81\x82".dup.force_encoding("UTF-8")
- "\u3042".byteslice(-1).should == "\x82".dup.force_encoding("UTF-8")
+ "\u3042".byteslice(1).should == "\x81".force_encoding("UTF-8")
+ "\u3042".byteslice(1, 2).should == "\x81\x82".force_encoding("UTF-8")
+ "\u3042".byteslice(1..2).should == "\x81\x82".force_encoding("UTF-8")
+ "\u3042".byteslice(-1).should == "\x82".force_encoding("UTF-8")
end
it "returns a String in the same encoding as self" do
diff --git a/spec/ruby/core/string/bytesplice_spec.rb b/spec/ruby/core/string/bytesplice_spec.rb
deleted file mode 100644
index 967edcba29..0000000000
--- a/spec/ruby/core/string/bytesplice_spec.rb
+++ /dev/null
@@ -1,134 +0,0 @@
-# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
-require_relative '../../spec_helper'
-
-describe "String#bytesplice" do
- ruby_version_is "3.2" do
- it "raises IndexError when index is less than -bytesize" do
- -> { "hello".bytesplice(-6, 0, "xxx") }.should raise_error(IndexError, "index -6 out of string")
- end
-
- it "raises IndexError when index is greater than bytesize" do
- -> { "hello".bytesplice(6, 0, "xxx") }.should raise_error(IndexError, "index 6 out of string")
- end
-
- it "raises IndexError for negative length" do
- -> { "abc".bytesplice(0, -2, "") }.should raise_error(IndexError, "negative length -2")
- end
-
- it "replaces with integer indices" do
- "hello".bytesplice(-5, 0, "xxx").should == "xxxhello"
- "hello".bytesplice(0, 0, "xxx").should == "xxxhello"
- "hello".bytesplice(0, 1, "xxx").should == "xxxello"
- "hello".bytesplice(0, 5, "xxx").should == "xxx"
- "hello".bytesplice(0, 6, "xxx").should == "xxx"
- end
-
- it "raises RangeError when range left boundary is less than -bytesize" do
- -> { "hello".bytesplice(-6...-6, "xxx") }.should raise_error(RangeError, "-6...-6 out of range")
- end
-
- it "replaces with ranges" do
- "hello".bytesplice(-5...-5, "xxx").should == "xxxhello"
- "hello".bytesplice(0...0, "xxx").should == "xxxhello"
- "hello".bytesplice(0..0, "xxx").should == "xxxello"
- "hello".bytesplice(0...1, "xxx").should == "xxxello"
- "hello".bytesplice(0..1, "xxx").should == "xxxllo"
- "hello".bytesplice(0..-1, "xxx").should == "xxx"
- "hello".bytesplice(0...5, "xxx").should == "xxx"
- "hello".bytesplice(0...6, "xxx").should == "xxx"
- end
-
- it "raises TypeError when integer index is provided without length argument" do
- -> { "hello".bytesplice(0, "xxx") }.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
- end
-
- it "replaces on an empty string" do
- "".bytesplice(0, 0, "").should == ""
- "".bytesplice(0, 0, "xxx").should == "xxx"
- end
-
- it "mutates self" do
- s = "hello"
- s.bytesplice(2, 1, "xxx").should.equal?(s)
- end
-
- it "raises when string is frozen" do
- s = "hello".freeze
- -> { s.bytesplice(2, 1, "xxx") }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
- end
- end
-end
-
-describe "String#bytesplice with multibyte characters" do
- ruby_version_is "3.2" do
- it "raises IndexError when index is out of byte size boundary" do
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-16, 0, "xxx") }.should raise_error(IndexError, "index -16 out of string")
- end
-
- it "raises IndexError when index is not on a codepoint boundary" do
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(1, 0, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- end
-
- it "raises IndexError when length is not matching the codepoint boundary" do
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 1, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 2, "xxx") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- end
-
- it "replaces with integer indices" do
- "ã“ã‚“ã«ã¡ã¯".bytesplice(-15, 0, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 0, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 3, "xxx").should == "xxxã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã¯ã¯").should == "ã“ã¯ã¯ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(15, 0, "xxx").should == "ã“ã‚“ã«ã¡ã¯xxx"
- end
-
- it "replaces with range" do
- "ã“ã‚“ã«ã¡ã¯".bytesplice(-15...-16, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0...0, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "xxx").should == "xxxã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0...3, "xxx").should == "xxxã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..5, "xxx").should == "xxxã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..-1, "xxx").should == "xxx"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0...15, "xxx").should == "xxx"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0...18, "xxx").should == "xxx"
- end
-
- it "treats negative length for range as 0" do
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0...-100, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(3...-100, "xxx").should == "ã“xxxã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(-15...-100, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
- end
-
- it "raises when ranges not match codepoint boundaries" do
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0..0, "x") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0..1, "x") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- # Begin is incorrect
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-4..-1, "x") }.should raise_error(IndexError, "offset 11 does not land on character boundary")
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-5..-1, "x") }.should raise_error(IndexError, "offset 10 does not land on character boundary")
- # End is incorrect
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-3..-2, "x") }.should raise_error(IndexError, "offset 14 does not land on character boundary")
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-3..-3, "x") }.should raise_error(IndexError, "offset 13 does not land on character boundary")
- end
-
- it "deals with a different encoded argument" do
- s = "ã“ã‚“ã«ã¡ã¯"
- s.encoding.should == Encoding::UTF_8
- sub = "xxxxxx"
- sub.force_encoding(Encoding::US_ASCII)
-
- result = s.bytesplice(0, 3, sub)
- result.should == "xxxxxxã‚“ã«ã¡ã¯"
- result.encoding.should == Encoding::UTF_8
-
- s = "xxxxxx"
- s.force_encoding(Encoding::US_ASCII)
- sub = "ã“ã‚“ã«ã¡ã¯"
- sub.encoding.should == Encoding::UTF_8
-
- result = s.bytesplice(0, 3, sub)
- result.should == "ã“ã‚“ã«ã¡ã¯xxx"
- result.encoding.should == Encoding::UTF_8
- end
- end
-end
diff --git a/spec/ruby/core/string/capitalize_spec.rb b/spec/ruby/core/string/capitalize_spec.rb
index 5e59b656c5..3f85cf5ae4 100644
--- a/spec/ruby/core/string/capitalize_spec.rb
+++ b/spec/ruby/core/string/capitalize_spec.rb
@@ -78,9 +78,18 @@ describe "String#capitalize" do
-> { "abc".capitalize(:invalid_option) }.should raise_error(ArgumentError)
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(String)
- StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(String)
+ StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(String)
+ end
end
it "returns a String in the same encoding as self" do
@@ -90,7 +99,7 @@ end
describe "String#capitalize!" do
it "capitalizes self in place" do
- a = +"hello"
+ a = "hello"
a.capitalize!.should equal(a)
a.should == "Hello"
end
@@ -103,13 +112,13 @@ describe "String#capitalize!" do
describe "full Unicode case mapping" do
it "modifies self in place for all of Unicode with no option" do
- a = +"äöÜ"
+ a = "äöÜ"
a.capitalize!
a.should == "Äöü"
end
it "only capitalizes the first resulting character when upcasing a character produces a multi-character sequence" do
- a = +"ß"
+ a = "ß"
a.capitalize!
a.should == "Ss"
end
@@ -121,7 +130,7 @@ describe "String#capitalize!" do
end
it "updates string metadata" do
- capitalized = +"ßeT"
+ capitalized = "ßeT"
capitalized.capitalize!
capitalized.should == "Sset"
@@ -133,7 +142,7 @@ describe "String#capitalize!" do
describe "modifies self in place for ASCII-only case mapping" do
it "does not capitalize non-ASCII characters" do
- a = +"ßet"
+ a = "ßet"
a.capitalize!(:ascii)
a.should == "ßet"
end
@@ -147,13 +156,13 @@ describe "String#capitalize!" do
describe "modifies self in place for full Unicode case mapping adapted for Turkic languages" do
it "capitalizes ASCII characters according to Turkic semantics" do
- a = +"iSa"
+ a = "iSa"
a.capitalize!(:turkic)
a.should == "İsa"
end
it "allows Lithuanian as an extra option" do
- a = +"iSa"
+ a = "iSa"
a.capitalize!(:turkic, :lithuanian)
a.should == "İsa"
end
@@ -165,13 +174,13 @@ describe "String#capitalize!" do
describe "modifies self in place for full Unicode case mapping adapted for Lithuanian" do
it "currently works the same as full Unicode case mapping" do
- a = +"iß"
+ a = "iß"
a.capitalize!(:lithuanian)
a.should == "Iß"
end
it "allows Turkic as an extra option (and applies Turkic semantics)" do
- a = +"iß"
+ a = "iß"
a.capitalize!(:lithuanian, :turkic)
a.should == "İß"
end
@@ -190,12 +199,12 @@ describe "String#capitalize!" do
end
it "returns nil when no changes are made" do
- a = +"Hello"
+ a = "Hello"
a.capitalize!.should == nil
a.should == "Hello"
- (+"").capitalize!.should == nil
- (+"H").capitalize!.should == nil
+ "".capitalize!.should == nil
+ "H".capitalize!.should == nil
end
it "raises a FrozenError when self is frozen" do
diff --git a/spec/ruby/core/string/casecmp_spec.rb b/spec/ruby/core/string/casecmp_spec.rb
index 81ebea557c..986fbc8718 100644
--- a/spec/ruby/core/string/casecmp_spec.rb
+++ b/spec/ruby/core/string/casecmp_spec.rb
@@ -117,11 +117,6 @@ describe "String#casecmp independent of case" do
"B".casecmp(a).should == 1
end
end
-
- it "returns 0 for empty strings in different encodings" do
- ''.b.casecmp('').should == 0
- ''.b.casecmp(''.encode("UTF-32LE")).should == 0
- end
end
describe 'String#casecmp? independent of case' do
@@ -196,9 +191,4 @@ describe 'String#casecmp? independent of case' do
it "returns nil if other can't be converted to a string" do
"abc".casecmp?(mock('abc')).should be_nil
end
-
- it "returns true for empty strings in different encodings" do
- ''.b.should.casecmp?('')
- ''.b.should.casecmp?(''.encode("UTF-32LE"))
- end
end
diff --git a/spec/ruby/core/string/center_spec.rb b/spec/ruby/core/string/center_spec.rb
index 1667b59327..76da6e1e09 100644
--- a/spec/ruby/core/string/center_spec.rb
+++ b/spec/ruby/core/string/center_spec.rb
@@ -81,18 +81,31 @@ describe "String#center with length, padding" do
-> { "hello".center(0, "") }.should raise_error(ArgumentError)
end
- it "returns String instances when called on subclasses" do
- StringSpecs::MyString.new("").center(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on subclasses" do
+ StringSpecs::MyString.new("").center(10).should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString)
+
+ "".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ "foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ end
+ end
- "".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- "foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ ruby_version_is '3.0' do
+ it "returns String instances when called on subclasses" do
+ StringSpecs::MyString.new("").center(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+
+ "".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ "foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ end
end
describe "with width" do
it "returns a String in the same encoding as the original" do
- str = "abc".dup.force_encoding Encoding::IBM437
+ str = "abc".force_encoding Encoding::IBM437
result = str.center 6
result.should == " abc "
result.encoding.should equal(Encoding::IBM437)
@@ -101,7 +114,7 @@ describe "String#center with length, padding" do
describe "with width, pattern" do
it "returns a String in the compatible encoding" do
- str = "abc".dup.force_encoding Encoding::IBM437
+ str = "abc".force_encoding Encoding::IBM437
result = str.center 6, "ã‚"
result.should == "ã‚abcã‚ã‚"
result.encoding.should equal(Encoding::UTF_8)
diff --git a/spec/ruby/core/string/chars_spec.rb b/spec/ruby/core/string/chars_spec.rb
index ee85430574..715e65dc90 100644
--- a/spec/ruby/core/string/chars_spec.rb
+++ b/spec/ruby/core/string/chars_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative 'shared/chars'
describe "String#chars" do
diff --git a/spec/ruby/core/string/chilled_string_spec.rb b/spec/ruby/core/string/chilled_string_spec.rb
deleted file mode 100644
index 9f81b1af6d..0000000000
--- a/spec/ruby/core/string/chilled_string_spec.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "chilled String" do
- guard -> { ruby_version_is "3.4" and !"test".equal?("test") } do
- describe "#frozen?" do
- it "returns false" do
- "chilled".frozen?.should == false
- end
- end
-
- describe "#-@" do
- it "returns a different instance" do
- input = "chilled"
- interned = (-input)
- interned.frozen?.should == true
- interned.object_id.should_not == input.object_id
- end
- end
-
- describe "#+@" do
- it "returns a different instance" do
- input = "chilled"
- duped = (+input)
- duped.frozen?.should == false
- duped.object_id.should_not == input.object_id
- end
- end
-
- describe "#clone" do
- it "preserves chilled status" do
- input = "chilled".clone
- -> {
- input << "-mutated"
- }.should complain(/literal string will be frozen in the future/)
- input.should == "chilled-mutated"
- end
- end
-
- describe "mutation" do
- it "emits a warning" do
- input = "chilled"
- -> {
- input << "-mutated"
- }.should complain(/literal string will be frozen in the future/)
- input.should == "chilled-mutated"
- end
-
- it "emits a warning on singleton_class creation" do
- -> {
- "chilled".singleton_class
- }.should complain(/literal string will be frozen in the future/)
- end
-
- it "emits a warning on instance variable assignment" do
- -> {
- "chilled".instance_variable_set(:@ivar, 42)
- }.should complain(/literal string will be frozen in the future/)
- end
-
- it "raises FrozenError after the string was explicitly frozen" do
- input = "chilled"
- input.freeze
- -> {
- -> {
- input << "mutated"
- }.should raise_error(FrozenError)
- }.should_not complain(/literal string will be frozen in the future/)
- end
- end
- end
-end
diff --git a/spec/ruby/core/string/chomp_spec.rb b/spec/ruby/core/string/chomp_spec.rb
index d27c84c6f6..d0508d938f 100644
--- a/spec/ruby/core/string/chomp_spec.rb
+++ b/spec/ruby/core/string/chomp_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -45,9 +44,18 @@ describe "String#chomp" do
"abc\n\n".encode("US-ASCII").chomp.encoding.should == Encoding::US_ASCII
end
- it "returns String instances when called on a subclass" do
- str = StringSpecs::MyString.new("hello\n").chomp
- str.should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ str = StringSpecs::MyString.new("hello\n").chomp
+ str.should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ str = StringSpecs::MyString.new("hello\n").chomp
+ str.should be_an_instance_of(String)
+ end
end
it "removes trailing characters that match $/ when it has been assigned a value" do
diff --git a/spec/ruby/core/string/chop_spec.rb b/spec/ruby/core/string/chop_spec.rb
index 99c2c82190..f598d34bc8 100644
--- a/spec/ruby/core/string/chop_spec.rb
+++ b/spec/ruby/core/string/chop_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -50,8 +49,16 @@ describe "String#chop" do
s.chop.should_not equal(s)
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(String)
+ end
end
it "returns a String in the same encoding as self" do
diff --git a/spec/ruby/core/string/clear_spec.rb b/spec/ruby/core/string/clear_spec.rb
index 152986fd0f..e1d68e03bd 100644
--- a/spec/ruby/core/string/clear_spec.rb
+++ b/spec/ruby/core/string/clear_spec.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
require_relative '../../spec_helper'
describe "String#clear" do
diff --git a/spec/ruby/core/string/codepoints_spec.rb b/spec/ruby/core/string/codepoints_spec.rb
index b276d0baa8..0b6cde82f7 100644
--- a/spec/ruby/core/string/codepoints_spec.rb
+++ b/spec/ruby/core/string/codepoints_spec.rb
@@ -11,7 +11,7 @@ describe "String#codepoints" do
end
it "raises an ArgumentError when no block is given if self has an invalid encoding" do
- s = "\xDF".dup.force_encoding(Encoding::UTF_8)
+ s = "\xDF".force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
-> { s.codepoints }.should raise_error(ArgumentError)
end
diff --git a/spec/ruby/core/string/comparison_spec.rb b/spec/ruby/core/string/comparison_spec.rb
index 9db0cff5ee..91cfdca25a 100644
--- a/spec/ruby/core/string/comparison_spec.rb
+++ b/spec/ruby/core/string/comparison_spec.rb
@@ -61,12 +61,12 @@ describe "String#<=> with String" do
end
it "ignores encoding difference" do
- ("ÄÖÛ".dup.force_encoding("utf-8") <=> "ÄÖÜ".dup.force_encoding("iso-8859-1")).should == -1
- ("ÄÖÜ".dup.force_encoding("utf-8") <=> "ÄÖÛ".dup.force_encoding("iso-8859-1")).should == 1
+ ("ÄÖÛ".force_encoding("utf-8") <=> "ÄÖÜ".force_encoding("iso-8859-1")).should == -1
+ ("ÄÖÜ".force_encoding("utf-8") <=> "ÄÖÛ".force_encoding("iso-8859-1")).should == 1
end
it "returns 0 with identical ASCII-compatible bytes of different encodings" do
- ("abc".dup.force_encoding("utf-8") <=> "abc".dup.force_encoding("iso-8859-1")).should == 0
+ ("abc".force_encoding("utf-8") <=> "abc".force_encoding("iso-8859-1")).should == 0
end
it "compares the indices of the encodings when the strings have identical non-ASCII-compatible bytes" do
@@ -77,7 +77,7 @@ describe "String#<=> with String" do
end
it "returns 0 when comparing 2 empty strings but one is not ASCII-compatible" do
- ("" <=> "".dup.force_encoding('iso-2022-jp')).should == 0
+ ("" <=> "".force_encoding('iso-2022-jp')).should == 0
end
end
diff --git a/spec/ruby/core/string/concat_spec.rb b/spec/ruby/core/string/concat_spec.rb
index cbd7df54e2..5f6daadad7 100644
--- a/spec/ruby/core/string/concat_spec.rb
+++ b/spec/ruby/core/string/concat_spec.rb
@@ -5,22 +5,21 @@ require_relative 'shared/concat'
describe "String#concat" do
it_behaves_like :string_concat, :concat
it_behaves_like :string_concat_encoding, :concat
- it_behaves_like :string_concat_type_coercion, :concat
it "takes multiple arguments" do
- str = +"hello "
+ str = "hello "
str.concat "wo", "", "rld"
str.should == "hello world"
end
it "concatenates the initial value when given arguments contain 2 self" do
- str = +"hello"
+ str = "hello"
str.concat str, str
str.should == "hellohellohello"
end
it "returns self when given no arguments" do
- str = +"hello"
+ str = "hello"
str.concat.should equal(str)
str.should == "hello"
end
diff --git a/spec/ruby/core/string/dedup_spec.rb b/spec/ruby/core/string/dedup_spec.rb
index 57d2be2cfd..919d440c51 100644
--- a/spec/ruby/core/string/dedup_spec.rb
+++ b/spec/ruby/core/string/dedup_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'shared/dedup'
describe 'String#dedup' do
- ruby_version_is '3.2' do
+ ruby_version_is '3.2'do
it_behaves_like :string_dedup, :dedup
end
end
diff --git a/spec/ruby/core/string/delete_prefix_spec.rb b/spec/ruby/core/string/delete_prefix_spec.rb
index ee7f044905..238de85f05 100644
--- a/spec/ruby/core/string/delete_prefix_spec.rb
+++ b/spec/ruby/core/string/delete_prefix_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -39,9 +38,18 @@ describe "String#delete_prefix" do
'hello'.delete_prefix(o).should == 'o'
end
- it "returns a String instance when called on a subclass instance" do
- s = StringSpecs::MyString.new('hello')
- s.delete_prefix('hell').should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns a subclass instance when called on a subclass instance" do
+ s = StringSpecs::MyString.new('hello')
+ s.delete_prefix('hell').should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns a String instance when called on a subclass instance" do
+ s = StringSpecs::MyString.new('hello')
+ s.delete_prefix('hell').should be_an_instance_of(String)
+ end
end
it "returns a String in the same encoding as self" do
diff --git a/spec/ruby/core/string/delete_spec.rb b/spec/ruby/core/string/delete_spec.rb
index 6d359776e4..87831a9d19 100644
--- a/spec/ruby/core/string/delete_spec.rb
+++ b/spec/ruby/core/string/delete_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -85,8 +84,16 @@ describe "String#delete" do
-> { "hello world".delete(mock('x')) }.should raise_error(TypeError)
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(String)
+ end
end
it "returns a String in the same encoding as self" do
diff --git a/spec/ruby/core/string/delete_suffix_spec.rb b/spec/ruby/core/string/delete_suffix_spec.rb
index 1842d75aa5..6883d6938c 100644
--- a/spec/ruby/core/string/delete_suffix_spec.rb
+++ b/spec/ruby/core/string/delete_suffix_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -39,9 +38,18 @@ describe "String#delete_suffix" do
'hello'.delete_suffix(o).should == 'h'
end
- it "returns a String instance when called on a subclass instance" do
- s = StringSpecs::MyString.new('hello')
- s.delete_suffix('ello').should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns a subclass instance when called on a subclass instance" do
+ s = StringSpecs::MyString.new('hello')
+ s.delete_suffix('ello').should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns a String instance when called on a subclass instance" do
+ s = StringSpecs::MyString.new('hello')
+ s.delete_suffix('ello').should be_an_instance_of(String)
+ end
end
it "returns a String in the same encoding as self" do
diff --git a/spec/ruby/core/string/downcase_spec.rb b/spec/ruby/core/string/downcase_spec.rb
index 2d260f23f1..153b4ce191 100644
--- a/spec/ruby/core/string/downcase_spec.rb
+++ b/spec/ruby/core/string/downcase_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -77,8 +76,16 @@ describe "String#downcase" do
-> { "ABC".downcase(:invalid_option) }.should raise_error(ArgumentError)
end
- it "returns a String instance for subclasses" do
- StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns a subclass instance for subclasses" do
+ StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns a String instance for subclasses" do
+ StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(String)
+ end
end
end
diff --git a/spec/ruby/core/string/dump_spec.rb b/spec/ruby/core/string/dump_spec.rb
index cab8beff5a..81de0cfae4 100644
--- a/spec/ruby/core/string/dump_spec.rb
+++ b/spec/ruby/core/string/dump_spec.rb
@@ -7,8 +7,16 @@ describe "String#dump" do
"foo".freeze.dump.should_not.frozen?
end
- it "returns a String instance" do
- StringSpecs::MyString.new.dump.should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns a subclass instance" do
+ StringSpecs::MyString.new.dump.should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns a String instance" do
+ StringSpecs::MyString.new.dump.should be_an_instance_of(String)
+ end
end
it "wraps string with \"" do
diff --git a/spec/ruby/core/string/dup_spec.rb b/spec/ruby/core/string/dup_spec.rb
index 073802d84b..73f71b8ffc 100644
--- a/spec/ruby/core/string/dup_spec.rb
+++ b/spec/ruby/core/string/dup_spec.rb
@@ -51,7 +51,7 @@ describe "String#dup" do
end
it "does not modify the original setbyte-mutated string when changing dupped string" do
- orig = +"a"
+ orig = "a"
orig.setbyte 0, "b".ord
copy = orig.dup
orig.setbyte 0, "c".ord
diff --git a/spec/ruby/core/string/each_byte_spec.rb b/spec/ruby/core/string/each_byte_spec.rb
index 7b3db265ac..e04dca807f 100644
--- a/spec/ruby/core/string/each_byte_spec.rb
+++ b/spec/ruby/core/string/each_byte_spec.rb
@@ -9,26 +9,26 @@ describe "String#each_byte" do
end
it "keeps iterating from the old position (to new string end) when self changes" do
- r = +""
- s = +"hello world"
+ r = ""
+ s = "hello world"
s.each_byte do |c|
r << c
s.insert(0, "<>") if r.size < 3
end
r.should == "h><>hello world"
- r = +""
- s = +"hello world"
+ r = ""
+ s = "hello world"
s.each_byte { |c| s.slice!(-1); r << c }
r.should == "hello "
- r = +""
- s = +"hello world"
+ r = ""
+ s = "hello world"
s.each_byte { |c| s.slice!(0); r << c }
r.should == "hlowrd"
- r = +""
- s = +"hello world"
+ r = ""
+ s = "hello world"
s.each_byte { |c| s.slice!(0..-1); r << c }
r.should == "h"
end
diff --git a/spec/ruby/core/string/each_char_spec.rb b/spec/ruby/core/string/each_char_spec.rb
index 36219f79db..aff98c0a5c 100644
--- a/spec/ruby/core/string/each_char_spec.rb
+++ b/spec/ruby/core/string/each_char_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative 'shared/chars'
require_relative 'shared/each_char_without_block'
diff --git a/spec/ruby/core/string/each_grapheme_cluster_spec.rb b/spec/ruby/core/string/each_grapheme_cluster_spec.rb
index e1fa4ae67b..b45d89ecb0 100644
--- a/spec/ruby/core/string/each_grapheme_cluster_spec.rb
+++ b/spec/ruby/core/string/each_grapheme_cluster_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative 'shared/chars'
require_relative 'shared/grapheme_clusters'
require_relative 'shared/each_char_without_block'
@@ -8,9 +7,11 @@ describe "String#each_grapheme_cluster" do
it_behaves_like :string_grapheme_clusters, :each_grapheme_cluster
it_behaves_like :string_each_char_without_block, :each_grapheme_cluster
- it "yields String instances for subclasses" do
- a = []
- StringSpecs::MyString.new("abc").each_grapheme_cluster { |s| a << s.class }
- a.should == [String, String, String]
+ ruby_version_is '3.0' do
+ it "yields String instances for subclasses" do
+ a = []
+ StringSpecs::MyString.new("abc").each_grapheme_cluster { |s| a << s.class }
+ a.should == [String, String, String]
+ end
end
end
diff --git a/spec/ruby/core/string/element_set_spec.rb b/spec/ruby/core/string/element_set_spec.rb
index e7599f832c..fa041fa31d 100644
--- a/spec/ruby/core/string/element_set_spec.rb
+++ b/spec/ruby/core/string/element_set_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
diff --git a/spec/ruby/core/string/encode_spec.rb b/spec/ruby/core/string/encode_spec.rb
index cd449498a3..5604ab7210 100644
--- a/spec/ruby/core/string/encode_spec.rb
+++ b/spec/ruby/core/string/encode_spec.rb
@@ -34,8 +34,8 @@ describe "String#encode" do
it "encodes an ascii substring of a binary string to UTF-8" do
x82 = [0x82].pack('C')
- str = "#{x82}foo".dup.force_encoding("binary")[1..-1].encode("utf-8")
- str.should == "foo".dup.force_encoding("utf-8")
+ str = "#{x82}foo".force_encoding("binary")[1..-1].encode("utf-8")
+ str.should == "foo".force_encoding("utf-8")
str.encoding.should equal(Encoding::UTF_8)
end
end
@@ -49,7 +49,7 @@ describe "String#encode" do
end
it "round trips a String" do
- str = "abc def".dup.force_encoding Encoding::US_ASCII
+ str = "abc def".force_encoding Encoding::US_ASCII
str.encode("utf-32be").encode("ascii").should == "abc def"
end
end
@@ -61,22 +61,10 @@ describe "String#encode" do
str.encode(invalid: :replace).should_not equal(str)
end
- it "normalizes newlines with cr_newline option" do
- "\r\nfoo".encode(cr_newline: true).should == "\r\rfoo"
- "\rfoo".encode(cr_newline: true).should == "\rfoo"
- "\nfoo".encode(cr_newline: true).should == "\rfoo"
- end
-
- it "normalizes newlines with crlf_newline option" do
- "\r\nfoo".encode(crlf_newline: true).should == "\r\r\nfoo"
- "\rfoo".encode(crlf_newline: true).should == "\rfoo"
- "\nfoo".encode(crlf_newline: true).should == "\r\nfoo"
- end
-
- it "normalizes newlines with universal_newline option" do
+ it "normalizes newlines" do
"\r\nfoo".encode(universal_newline: true).should == "\nfoo"
+
"\rfoo".encode(universal_newline: true).should == "\nfoo"
- "\nfoo".encode(universal_newline: true).should == "\nfoo"
end
it "replaces invalid encoding in source with default replacement" do
@@ -91,10 +79,6 @@ describe "String#encode" do
encoded.encode("UTF-8").should == "ã¡foofoo"
end
- it "replace multiple invalid bytes at the end with a single replacement character" do
- "\xE3\x81\x93\xE3\x81".encode("UTF-8", invalid: :replace).should == "\u3053\ufffd"
- end
-
it "replaces invalid encoding in source using a specified replacement even when a fallback is given" do
encoded = "ã¡\xE3\x81\xFF".encode("UTF-16LE", invalid: :replace, replace: "foo", fallback: -> c { "bar" })
encoded.should == "\u3061foofoo".encode("UTF-16LE")
@@ -134,7 +118,8 @@ describe "String#encode" do
describe "when passed to, from" do
it "returns a copy in the destination encoding when both encodings are the same" do
- str = "ã‚".dup.force_encoding("binary")
+ str = "ã‚"
+ str.force_encoding("binary")
encoded = str.encode("utf-8", "utf-8")
encoded.should_not equal(str)
@@ -166,7 +151,8 @@ describe "String#encode" do
end
it "returns a copy in the destination encoding when both encodings are the same" do
- str = "ã‚".dup.force_encoding("binary")
+ str = "ã‚"
+ str.force_encoding("binary")
encoded = str.encode("utf-8", "utf-8", invalid: :replace)
encoded.should_not equal(str)
@@ -201,13 +187,13 @@ describe "String#encode!" do
describe "when passed no options" do
it "returns self when Encoding.default_internal is nil" do
Encoding.default_internal = nil
- str = +"ã‚"
+ str = "ã‚"
str.encode!.should equal(str)
end
it "returns self for a ASCII-only String when Encoding.default_internal is nil" do
Encoding.default_internal = nil
- str = +"abc"
+ str = "abc"
str.encode!.should equal(str)
end
end
@@ -215,14 +201,14 @@ describe "String#encode!" do
describe "when passed options" do
it "returns self for ASCII-only String when Encoding.default_internal is nil" do
Encoding.default_internal = nil
- str = +"abc"
+ str = "abc"
str.encode!(invalid: :replace).should equal(str)
end
end
describe "when passed to encoding" do
it "returns self" do
- str = +"abc"
+ str = "abc"
result = str.encode!(Encoding::BINARY)
result.encoding.should equal(Encoding::BINARY)
result.should equal(str)
@@ -231,7 +217,7 @@ describe "String#encode!" do
describe "when passed to, from" do
it "returns self" do
- str = +"ã‚ã‚"
+ str = "ã‚ã‚"
result = str.encode!("euc-jp", "utf-8")
result.encoding.should equal(Encoding::EUC_JP)
result.should equal(str)
diff --git a/spec/ruby/core/string/encoding_spec.rb b/spec/ruby/core/string/encoding_spec.rb
index f6e8fd3470..574a1e2f92 100644
--- a/spec/ruby/core/string/encoding_spec.rb
+++ b/spec/ruby/core/string/encoding_spec.rb
@@ -14,11 +14,11 @@ describe "String#encoding" do
end
it "returns the given encoding if #force_encoding has been called" do
- "a".dup.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "a".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
end
it "returns the given encoding if #encode!has been called" do
- "a".dup.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "a".encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
end
end
@@ -108,13 +108,13 @@ describe "String#encoding for Strings with \\u escapes" do
end
it "returns the given encoding if #force_encoding has been called" do
- "\u{20}".dup.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- "\u{2020}".dup.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "\u{20}".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "\u{2020}".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
end
it "returns the given encoding if #encode!has been called" do
- "\u{20}".dup.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- "\u{2020}".dup.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "\u{20}".encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "\u{2020}".encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
end
end
@@ -173,12 +173,16 @@ describe "String#encoding for Strings with \\x escapes" do
end
it "returns the given encoding if #force_encoding has been called" do
- "\x50".dup.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- [212].pack('C').force_encoding(Encoding::ISO_8859_9).encoding.should == Encoding::ISO_8859_9
+ x50 = "\x50"
+ x50.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ xD4 = [212].pack('C')
+ xD4.force_encoding(Encoding::ISO_8859_9).encoding.should == Encoding::ISO_8859_9
end
it "returns the given encoding if #encode!has been called" do
- "\x50".dup.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- "x\00".dup.encode!(Encoding::UTF_8).encoding.should == Encoding::UTF_8
+ x50 = "\x50"
+ x50.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ x00 = "x\00"
+ x00.encode!(Encoding::UTF_8).encoding.should == Encoding::UTF_8
end
end
diff --git a/spec/ruby/core/string/fixtures/utf-8-encoding.rb b/spec/ruby/core/string/fixtures/utf-8-encoding.rb
new file mode 100644
index 0000000000..fd243ec522
--- /dev/null
+++ b/spec/ruby/core/string/fixtures/utf-8-encoding.rb
@@ -0,0 +1,7 @@
+# -*- encoding: utf-8 -*-
+module StringSpecs
+ class UTF8Encoding
+ def self.source_encoding; __ENCODING__; end
+ def self.egrave; "é"; end
+ end
+end
diff --git a/spec/ruby/core/string/force_encoding_spec.rb b/spec/ruby/core/string/force_encoding_spec.rb
index 2259dcf3cf..f37aaf9eb4 100644
--- a/spec/ruby/core/string/force_encoding_spec.rb
+++ b/spec/ruby/core/string/force_encoding_spec.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
require_relative '../../spec_helper'
describe "String#force_encoding" do
diff --git a/spec/ruby/core/string/freeze_spec.rb b/spec/ruby/core/string/freeze_spec.rb
index 2e8e70386d..04d1e9513c 100644
--- a/spec/ruby/core/string/freeze_spec.rb
+++ b/spec/ruby/core/string/freeze_spec.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
require_relative '../../spec_helper'
describe "String#freeze" do
diff --git a/spec/ruby/core/string/grapheme_clusters_spec.rb b/spec/ruby/core/string/grapheme_clusters_spec.rb
index 380a245083..3046265a12 100644
--- a/spec/ruby/core/string/grapheme_clusters_spec.rb
+++ b/spec/ruby/core/string/grapheme_clusters_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative 'shared/chars'
require_relative 'shared/grapheme_clusters'
diff --git a/spec/ruby/core/string/gsub_spec.rb b/spec/ruby/core/string/gsub_spec.rb
index 0d9f32eca2..c87a566591 100644
--- a/spec/ruby/core/string/gsub_spec.rb
+++ b/spec/ruby/core/string/gsub_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -193,11 +192,22 @@ describe "String#gsub with pattern and replacement" do
-> { "hello".gsub(/[aeiou]/, nil) }.should raise_error(TypeError)
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(String)
+ end
end
it "sets $~ to MatchData of last match and nil when there's none" do
diff --git a/spec/ruby/core/string/include_spec.rb b/spec/ruby/core/string/include_spec.rb
index 9781140a55..23e1e134ec 100644
--- a/spec/ruby/core/string/include_spec.rb
+++ b/spec/ruby/core/string/include_spec.rb
@@ -15,16 +15,16 @@ describe "String#include? with String" do
it "returns true if both strings are empty" do
"".should.include?("")
- "".dup.force_encoding("EUC-JP").should.include?("")
- "".should.include?("".dup.force_encoding("EUC-JP"))
- "".dup.force_encoding("EUC-JP").should.include?("".dup.force_encoding("EUC-JP"))
+ "".force_encoding("EUC-JP").should.include?("")
+ "".should.include?("".force_encoding("EUC-JP"))
+ "".force_encoding("EUC-JP").should.include?("".force_encoding("EUC-JP"))
end
it "returns true if the RHS is empty" do
"a".should.include?("")
- "a".dup.force_encoding("EUC-JP").should.include?("")
- "a".should.include?("".dup.force_encoding("EUC-JP"))
- "a".dup.force_encoding("EUC-JP").should.include?("".dup.force_encoding("EUC-JP"))
+ "a".force_encoding("EUC-JP").should.include?("")
+ "a".should.include?("".force_encoding("EUC-JP"))
+ "a".force_encoding("EUC-JP").should.include?("".force_encoding("EUC-JP"))
end
it "tries to convert other to string using to_str" do
diff --git a/spec/ruby/core/string/index_spec.rb b/spec/ruby/core/string/index_spec.rb
index 835263a2cd..2eeee9be87 100644
--- a/spec/ruby/core/string/index_spec.rb
+++ b/spec/ruby/core/string/index_spec.rb
@@ -161,18 +161,11 @@ describe "String#index with String" do
end
it "handles a substring in a superset encoding" do
- 'abc'.dup.force_encoding(Encoding::US_ASCII).index('é').should == nil
+ 'abc'.force_encoding(Encoding::US_ASCII).index('é').should == nil
end
it "handles a substring in a subset encoding" do
- 'été'.index('t'.dup.force_encoding(Encoding::US_ASCII)).should == 1
- end
-
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- str = 'abc'.dup.force_encoding("ISO-2022-JP")
- pattern = 'b'.dup.force_encoding("EUC-JP")
-
- -> { str.index(pattern) }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP")
+ 'été'.index('t'.force_encoding(Encoding::US_ASCII)).should == 1
end
end
@@ -231,17 +224,6 @@ describe "String#index with Regexp" do
$~.should == nil
end
- ruby_bug "#20421", ""..."3.3" do
- it "always clear $~" do
- "a".index(/a/)
- $~.should_not == nil
-
- string = "blablabla"
- string.index(/bla/, string.length + 1)
- $~.should == nil
- end
- end
-
it "starts the search at the given offset" do
"blablabla".index(/.{0}/, 5).should == 5
"blablabla".index(/.{1}/, 5).should == 5
@@ -330,17 +312,6 @@ describe "String#index with Regexp" do
"ã‚れã‚ã‚れ".index(/ã‚/, 3).should == 3
end
- ruby_bug "#19763", ""..."3.3.0" do
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- re = Regexp.new "れ".encode(Encoding::EUC_JP)
- -> do
- "ã‚れ".index re
- end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
- end
- end
-
- # The exception message was incorrectly "incompatible character encodings: UTF-8 and EUC-JP" before 3.3.0
- # Still test that the right exception class is used before that.
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
re = Regexp.new "れ".encode(Encoding::EUC_JP)
-> do
diff --git a/spec/ruby/core/string/insert_spec.rb b/spec/ruby/core/string/insert_spec.rb
index 483f3c9367..0c87df3a95 100644
--- a/spec/ruby/core/string/insert_spec.rb
+++ b/spec/ruby/core/string/insert_spec.rb
@@ -1,5 +1,5 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
+
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
diff --git a/spec/ruby/core/string/inspect_spec.rb b/spec/ruby/core/string/inspect_spec.rb
index 15db06c7f5..8bf3d3161f 100644
--- a/spec/ruby/core/string/inspect_spec.rb
+++ b/spec/ruby/core/string/inspect_spec.rb
@@ -327,7 +327,7 @@ describe "String#inspect" do
end
it "works for broken US-ASCII strings" do
- s = "©".dup.force_encoding("US-ASCII")
+ s = "©".force_encoding("US-ASCII")
s.inspect.should == '"\xC2\xA9"'
end
diff --git a/spec/ruby/core/string/ljust_spec.rb b/spec/ruby/core/string/ljust_spec.rb
index 47324c59d2..9a25d3abd4 100644
--- a/spec/ruby/core/string/ljust_spec.rb
+++ b/spec/ruby/core/string/ljust_spec.rb
@@ -64,18 +64,31 @@ describe "String#ljust with length, padding" do
-> { "hello".ljust(10, '') }.should raise_error(ArgumentError)
end
- it "returns String instances when called on subclasses" do
- StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on subclasses" do
+ StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString)
+
+ "".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ "foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ end
+ end
- "".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- "foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ ruby_version_is '3.0' do
+ it "returns String instances when called on subclasses" do
+ StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+
+ "".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ "foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ end
end
describe "with width" do
it "returns a String in the same encoding as the original" do
- str = "abc".dup.force_encoding Encoding::IBM437
+ str = "abc".force_encoding Encoding::IBM437
result = str.ljust 5
result.should == "abc "
result.encoding.should equal(Encoding::IBM437)
@@ -84,7 +97,7 @@ describe "String#ljust with length, padding" do
describe "with width, pattern" do
it "returns a String in the compatible encoding" do
- str = "abc".dup.force_encoding Encoding::IBM437
+ str = "abc".force_encoding Encoding::IBM437
result = str.ljust 5, "ã‚"
result.should == "abcã‚ã‚"
result.encoding.should equal(Encoding::UTF_8)
diff --git a/spec/ruby/core/string/lstrip_spec.rb b/spec/ruby/core/string/lstrip_spec.rb
index 99bab6f349..75434613f1 100644
--- a/spec/ruby/core/string/lstrip_spec.rb
+++ b/spec/ruby/core/string/lstrip_spec.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/strip'
@@ -21,9 +20,11 @@ describe "String#lstrip" do
" ã“ã«ã¡ã‚ "[1...-1].lstrip.should == "ã“ã«ã¡ã‚"
end
- it "strips leading \\0" do
- "\x00hello".lstrip.should == "hello"
- "\000 \000hello\000 \000".lstrip.should == "hello\000 \000"
+ ruby_version_is '3.0' do
+ it "strips leading \\0" do
+ "\x00hello".lstrip.should == "hello"
+ "\000 \000hello\000 \000".lstrip.should == "hello\000 \000"
+ end
end
end
@@ -46,10 +47,12 @@ describe "String#lstrip!" do
" ".lstrip.should == ""
end
- it "removes leading NULL bytes and whitespace" do
- a = "\000 \000hello\000 \000"
- a.lstrip!
- a.should == "hello\000 \000"
+ ruby_version_is '3.0' do
+ it "removes leading NULL bytes and whitespace" do
+ a = "\000 \000hello\000 \000"
+ a.lstrip!
+ a.should == "hello\000 \000"
+ end
end
it "raises a FrozenError on a frozen instance that is modified" do
diff --git a/spec/ruby/core/string/modulo_spec.rb b/spec/ruby/core/string/modulo_spec.rb
index 8e3853551f..bf96a82874 100644
--- a/spec/ruby/core/string/modulo_spec.rb
+++ b/spec/ruby/core/string/modulo_spec.rb
@@ -55,48 +55,33 @@ describe "String#%" do
-> { ("foo%" % [])}.should raise_error(ArgumentError)
end
- ruby_version_is ""..."3.4" do
- it "formats single % character before a newline as literal %" do
- ("%\n" % []).should == "%\n"
- ("foo%\n" % []).should == "foo%\n"
- ("%\n.3f" % 1.2).should == "%\n.3f"
- end
-
- it "formats single % character before a NUL as literal %" do
- ("%\0" % []).should == "%\0"
- ("foo%\0" % []).should == "foo%\0"
- ("%\0.3f" % 1.2).should == "%\0.3f"
- end
-
- it "raises an error if single % appears anywhere else" do
- -> { (" % " % []) }.should raise_error(ArgumentError)
- -> { ("foo%quux" % []) }.should raise_error(ArgumentError)
- end
+ it "formats single % character before a newline as literal %" do
+ ("%\n" % []).should == "%\n"
+ ("foo%\n" % []).should == "foo%\n"
+ ("%\n.3f" % 1.2).should == "%\n.3f"
+ end
- it "raises an error if NULL or \\n appear anywhere else in the format string" do
- begin
- old_debug, $DEBUG = $DEBUG, false
+ it "formats single % character before a NUL as literal %" do
+ ("%\0" % []).should == "%\0"
+ ("foo%\0" % []).should == "foo%\0"
+ ("%\0.3f" % 1.2).should == "%\0.3f"
+ end
- -> { "%.\n3f" % 1.2 }.should raise_error(ArgumentError)
- -> { "%.3\nf" % 1.2 }.should raise_error(ArgumentError)
- -> { "%.\03f" % 1.2 }.should raise_error(ArgumentError)
- -> { "%.3\0f" % 1.2 }.should raise_error(ArgumentError)
- ensure
- $DEBUG = old_debug
- end
- end
+ it "raises an error if single % appears anywhere else" do
+ -> { (" % " % []) }.should raise_error(ArgumentError)
+ -> { ("foo%quux" % []) }.should raise_error(ArgumentError)
end
- ruby_version_is "3.4" do
- it "raises an ArgumentError if % is not followed by a conversion specifier" do
- -> { "%" % [] }.should raise_error(ArgumentError)
- -> { "%\n" % [] }.should raise_error(ArgumentError)
- -> { "%\0" % [] }.should raise_error(ArgumentError)
- -> { " % " % [] }.should raise_error(ArgumentError)
+ it "raises an error if NULL or \\n appear anywhere else in the format string" do
+ begin
+ old_debug, $DEBUG = $DEBUG, false
+
-> { "%.\n3f" % 1.2 }.should raise_error(ArgumentError)
-> { "%.3\nf" % 1.2 }.should raise_error(ArgumentError)
-> { "%.\03f" % 1.2 }.should raise_error(ArgumentError)
-> { "%.3\0f" % 1.2 }.should raise_error(ArgumentError)
+ ensure
+ $DEBUG = old_debug
end
end
@@ -140,16 +125,8 @@ describe "String#%" do
end
end
- ruby_version_is ""..."3.4" do
- it "replaces trailing absolute argument specifier without type with percent sign" do
- ("hello %1$" % "foo").should == "hello %"
- end
- end
-
- ruby_version_is "3.4" do
- it "raises an ArgumentError if absolute argument specifier is followed by a conversion specifier" do
- -> { "hello %1$" % "foo" }.should raise_error(ArgumentError)
- end
+ it "replaces trailing absolute argument specifier without type with percent sign" do
+ ("hello %1$" % "foo").should == "hello %"
end
it "raises an ArgumentError when given invalid argument specifiers" do
@@ -570,7 +547,7 @@ describe "String#%" do
("%1$p" % [10, 5]).should == "10"
("%-22p" % 10).should == "10 "
("%*p" % [10, 10]).should == " 10"
- ("%p" % {capture: 1}).should == {capture: 1}.inspect
+ ("%p" % {capture: 1}).should == "{:capture=>1}"
("%p" % "str").should == "\"str\""
end
@@ -749,9 +726,6 @@ describe "String#%" do
(format % "-10.4e-20").should == (format % -10.4e-20)
(format % ".5").should == (format % 0.5)
(format % "-.5").should == (format % -0.5)
- ruby_bug("#20705", ""..."3.4") do
- (format % "10.").should == (format % 10)
- end
# Something's strange with this spec:
# it works just fine in individual mode, but not when run as part of a group
(format % "10_1_0.5_5_5").should == (format % 1010.555)
@@ -761,6 +735,7 @@ describe "String#%" do
-> { format % "" }.should raise_error(ArgumentError)
-> { format % "x" }.should raise_error(ArgumentError)
-> { format % "." }.should raise_error(ArgumentError)
+ -> { format % "10." }.should raise_error(ArgumentError)
-> { format % "5x" }.should raise_error(ArgumentError)
-> { format % "0b1" }.should raise_error(ArgumentError)
-> { format % "10e10.5" }.should raise_error(ArgumentError)
diff --git a/spec/ruby/core/string/ord_spec.rb b/spec/ruby/core/string/ord_spec.rb
index 35af3b5458..4cf26990fe 100644
--- a/spec/ruby/core/string/ord_spec.rb
+++ b/spec/ruby/core/string/ord_spec.rb
@@ -27,7 +27,7 @@ describe "String#ord" do
end
it "raises ArgumentError if the character is broken" do
- s = "©".dup.force_encoding("US-ASCII")
+ s = "©".force_encoding("US-ASCII")
-> { s.ord }.should raise_error(ArgumentError, "invalid byte sequence in US-ASCII")
end
end
diff --git a/spec/ruby/core/string/partition_spec.rb b/spec/ruby/core/string/partition_spec.rb
index d5370dcc73..9cb3672881 100644
--- a/spec/ruby/core/string/partition_spec.rb
+++ b/spec/ruby/core/string/partition_spec.rb
@@ -40,7 +40,7 @@ describe "String#partition with String" do
end
it "handles a pattern in a superset encoding" do
- string = "hello".dup.force_encoding(Encoding::US_ASCII)
+ string = "hello".force_encoding(Encoding::US_ASCII)
result = string.partition("é")
@@ -51,7 +51,7 @@ describe "String#partition with String" do
end
it "handles a pattern in a subset encoding" do
- pattern = "o".dup.force_encoding(Encoding::US_ASCII)
+ pattern = "o".force_encoding(Encoding::US_ASCII)
result = "héllo world".partition(pattern)
diff --git a/spec/ruby/core/string/plus_spec.rb b/spec/ruby/core/string/plus_spec.rb
index 9da17451c6..5ff198f07e 100644
--- a/spec/ruby/core/string/plus_spec.rb
+++ b/spec/ruby/core/string/plus_spec.rb
@@ -3,9 +3,6 @@ require_relative 'fixtures/classes'
require_relative 'shared/concat'
describe "String#+" do
- it_behaves_like :string_concat_encoding, :+
- it_behaves_like :string_concat_type_coercion, :+
-
it "returns a new string containing the given string concatenated to self" do
("" + "").should == ""
("" + "Hello").should == "Hello"
@@ -34,4 +31,6 @@ describe "String#+" do
("hello" + StringSpecs::MyString.new("foo")).should be_an_instance_of(String)
("hello" + StringSpecs::MyString.new("")).should be_an_instance_of(String)
end
+
+ it_behaves_like :string_concat_encoding, :+
end
diff --git a/spec/ruby/core/string/prepend_spec.rb b/spec/ruby/core/string/prepend_spec.rb
index 5248ea8056..a0393d4760 100644
--- a/spec/ruby/core/string/prepend_spec.rb
+++ b/spec/ruby/core/string/prepend_spec.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
diff --git a/spec/ruby/core/string/reverse_spec.rb b/spec/ruby/core/string/reverse_spec.rb
index aa6abe6036..73526256ef 100644
--- a/spec/ruby/core/string/reverse_spec.rb
+++ b/spec/ruby/core/string/reverse_spec.rb
@@ -1,5 +1,4 @@
# encoding: utf-8
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -11,10 +10,20 @@ describe "String#reverse" do
"".reverse.should == ""
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("stressed").reverse.should be_an_instance_of(String)
- StringSpecs::MyString.new("m").reverse.should be_an_instance_of(String)
- StringSpecs::MyString.new("").reverse.should be_an_instance_of(String)
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("stressed").reverse.should be_an_instance_of(String)
+ StringSpecs::MyString.new("m").reverse.should be_an_instance_of(String)
+ StringSpecs::MyString.new("").reverse.should be_an_instance_of(String)
+ end
+ end
+
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new("stressed").reverse.should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("m").reverse.should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("").reverse.should be_an_instance_of(StringSpecs::MyString)
+ end
end
it "reverses a string with multi byte characters" do
diff --git a/spec/ruby/core/string/rindex_spec.rb b/spec/ruby/core/string/rindex_spec.rb
index 88ce733583..cd2aabba34 100644
--- a/spec/ruby/core/string/rindex_spec.rb
+++ b/spec/ruby/core/string/rindex_spec.rb
@@ -1,6 +1,7 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'fixtures/utf-8-encoding'
describe "String#rindex with object" do
it "raises a TypeError if obj isn't a String or Regexp" do
@@ -197,18 +198,11 @@ describe "String#rindex with String" do
end
it "handles a substring in a superset encoding" do
- 'abc'.dup.force_encoding(Encoding::US_ASCII).rindex('é').should == nil
+ 'abc'.force_encoding(Encoding::US_ASCII).rindex('é').should == nil
end
it "handles a substring in a subset encoding" do
- 'été'.rindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 1
- end
-
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- str = 'abc'.dup.force_encoding("ISO-2022-JP")
- pattern = 'b'.dup.force_encoding("EUC-JP")
-
- -> { str.rindex(pattern) }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP")
+ 'été'.rindex('t'.force_encoding(Encoding::US_ASCII)).should == 1
end
end
@@ -271,6 +265,15 @@ describe "String#rindex with Regexp" do
$~.should == nil
end
+ it "always clear $~" do
+ "a".rindex(/a/)
+ $~.should_not == nil
+
+ string = "blablabla"
+ string.rindex(/bla/, -(string.length + 1))
+ $~.should == nil
+ end
+
it "starts the search at the given offset" do
"blablabla".rindex(/.{0}/, 5).should == 5
"blablabla".rindex(/.{1}/, 5).should == 5
@@ -379,6 +382,6 @@ describe "String#rindex with Regexp" do
re = Regexp.new "れ".encode(Encoding::EUC_JP)
-> do
"ã‚れ".rindex re
- end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
+ end.should raise_error(Encoding::CompatibilityError)
end
end
diff --git a/spec/ruby/core/string/rjust_spec.rb b/spec/ruby/core/string/rjust_spec.rb
index 4ad3e54aea..d067b7bdb3 100644
--- a/spec/ruby/core/string/rjust_spec.rb
+++ b/spec/ruby/core/string/rjust_spec.rb
@@ -64,18 +64,31 @@ describe "String#rjust with length, padding" do
-> { "hello".rjust(10, '') }.should raise_error(ArgumentError)
end
- it "returns String instances when called on subclasses" do
- StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on subclasses" do
+ StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString)
+
+ "".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ "foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ end
+ end
- "".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- "foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ ruby_version_is '3.0' do
+ it "returns String instances when called on subclasses" do
+ StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+
+ "".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ "foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ end
end
describe "with width" do
it "returns a String in the same encoding as the original" do
- str = "abc".dup.force_encoding Encoding::IBM437
+ str = "abc".force_encoding Encoding::IBM437
result = str.rjust 5
result.should == " abc"
result.encoding.should equal(Encoding::IBM437)
@@ -84,7 +97,7 @@ describe "String#rjust with length, padding" do
describe "with width, pattern" do
it "returns a String in the compatible encoding" do
- str = "abc".dup.force_encoding Encoding::IBM437
+ str = "abc".force_encoding Encoding::IBM437
result = str.rjust 5, "ã‚"
result.should == "ã‚ã‚abc"
result.encoding.should equal(Encoding::UTF_8)
diff --git a/spec/ruby/core/string/rpartition_spec.rb b/spec/ruby/core/string/rpartition_spec.rb
index cef0384c73..21e87f530a 100644
--- a/spec/ruby/core/string/rpartition_spec.rb
+++ b/spec/ruby/core/string/rpartition_spec.rb
@@ -48,7 +48,7 @@ describe "String#rpartition with String" do
end
it "handles a pattern in a superset encoding" do
- string = "hello".dup.force_encoding(Encoding::US_ASCII)
+ string = "hello".force_encoding(Encoding::US_ASCII)
result = string.rpartition("é")
@@ -59,7 +59,7 @@ describe "String#rpartition with String" do
end
it "handles a pattern in a subset encoding" do
- pattern = "o".dup.force_encoding(Encoding::US_ASCII)
+ pattern = "o".force_encoding(Encoding::US_ASCII)
result = "héllo world".rpartition(pattern)
diff --git a/spec/ruby/core/string/rstrip_spec.rb b/spec/ruby/core/string/rstrip_spec.rb
index 6d46eb590e..e96ce4120f 100644
--- a/spec/ruby/core/string/rstrip_spec.rb
+++ b/spec/ruby/core/string/rstrip_spec.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/strip'
@@ -52,10 +51,12 @@ describe "String#rstrip!" do
" ".rstrip.should == ""
end
- it "removes trailing NULL bytes and whitespace" do
- a = "\000 goodbye \000"
- a.rstrip!
- a.should == "\000 goodbye"
+ ruby_version_is '3.0' do
+ it "removes trailing NULL bytes and whitespace" do
+ a = "\000 goodbye \000"
+ a.rstrip!
+ a.should == "\000 goodbye"
+ end
end
it "raises a FrozenError on a frozen instance that is modified" do
diff --git a/spec/ruby/core/string/scan_spec.rb b/spec/ruby/core/string/scan_spec.rb
index 70c3b7fb7b..a2d1815132 100644
--- a/spec/ruby/core/string/scan_spec.rb
+++ b/spec/ruby/core/string/scan_spec.rb
@@ -165,9 +165,11 @@ describe "String#scan with pattern and block" do
end
end
- it "yields String instances for subclasses" do
- a = []
- StringSpecs::MyString.new("abc").scan(/./) { |s| a << s.class }
- a.should == [String, String, String]
+ ruby_version_is '3.0' do
+ it "yields String instances for subclasses" do
+ a = []
+ StringSpecs::MyString.new("abc").scan(/./) { |s| a << s.class }
+ a.should == [String, String, String]
+ end
end
end
diff --git a/spec/ruby/core/string/scrub_spec.rb b/spec/ruby/core/string/scrub_spec.rb
index b9ef0f1a16..a51fbd020a 100644
--- a/spec/ruby/core/string/scrub_spec.rb
+++ b/spec/ruby/core/string/scrub_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -37,10 +36,18 @@ describe "String#scrub with a default replacement" do
"abc\u3042#{x81}".scrub.encoding.should == Encoding::UTF_8
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("foo").scrub.should be_an_instance_of(String)
- input = [0x81].pack('C').force_encoding('utf-8')
- StringSpecs::MyString.new(input).scrub.should be_an_instance_of(String)
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("foo").scrub.should be_an_instance_of(String)
+ input = [0x81].pack('C').force_encoding('utf-8')
+ StringSpecs::MyString.new(input).scrub.should be_an_instance_of(String)
+ end
+ end
+
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new("foo").scrub.should be_an_instance_of(StringSpecs::MyString)
+ end
end
end
@@ -90,10 +97,12 @@ describe "String#scrub with a custom replacement" do
block.should raise_error(TypeError)
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("foo").scrub("*").should be_an_instance_of(String)
- input = [0x81].pack('C').force_encoding('utf-8')
- StringSpecs::MyString.new(input).scrub("*").should be_an_instance_of(String)
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("foo").scrub("*").should be_an_instance_of(String)
+ input = [0x81].pack('C').force_encoding('utf-8')
+ StringSpecs::MyString.new(input).scrub("*").should be_an_instance_of(String)
+ end
end
end
@@ -120,10 +129,12 @@ describe "String#scrub with a block" do
replaced.should == "€€"
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("foo").scrub { |b| "*" }.should be_an_instance_of(String)
- input = [0x81].pack('C').force_encoding('utf-8')
- StringSpecs::MyString.new(input).scrub { |b| "<#{b.unpack("H*")[0]}>" }.should be_an_instance_of(String)
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("foo").scrub { |b| "*" }.should be_an_instance_of(String)
+ input = [0x81].pack('C').force_encoding('utf-8')
+ StringSpecs::MyString.new(input).scrub { |b| "<#{b.unpack("H*")[0]}>" }.should be_an_instance_of(String)
+ end
end
end
diff --git a/spec/ruby/core/string/setbyte_spec.rb b/spec/ruby/core/string/setbyte_spec.rb
index 85403ca62c..77bff64038 100644
--- a/spec/ruby/core/string/setbyte_spec.rb
+++ b/spec/ruby/core/string/setbyte_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
describe "String#setbyte" do
diff --git a/spec/ruby/core/string/shared/byte_index_common.rb b/spec/ruby/core/string/shared/byte_index_common.rb
deleted file mode 100644
index 3de1453f4f..0000000000
--- a/spec/ruby/core/string/shared/byte_index_common.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# -*- encoding: utf-8 -*-
-require_relative '../../../spec_helper'
-
-describe :byte_index_common, shared: true do
- describe "raises on type errors" do
- it "raises a TypeError if passed nil" do
- -> { "abc".send(@method, nil) }.should raise_error(TypeError, "no implicit conversion of nil into String")
- end
-
- it "raises a TypeError if passed a boolean" do
- -> { "abc".send(@method, true) }.should raise_error(TypeError, "no implicit conversion of true into String")
- end
-
- it "raises a TypeError if passed a Symbol" do
- not_supported_on :opal do
- -> { "abc".send(@method, :a) }.should raise_error(TypeError, "no implicit conversion of Symbol into String")
- end
- end
-
- it "raises a TypeError if passed a Symbol" do
- obj = mock('x')
- obj.should_not_receive(:to_int)
- -> { "hello".send(@method, obj) }.should raise_error(TypeError, "no implicit conversion of MockObject into String")
- end
-
- it "raises a TypeError if passed an Integer" do
- -> { "abc".send(@method, 97) }.should raise_error(TypeError, "no implicit conversion of Integer into String")
- end
- end
-
- describe "with multibyte codepoints" do
- it "raises an IndexError when byte offset lands in the middle of a multibyte character" do
- -> { "ã‚".send(@method, "", 1) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "ã‚".send(@method, "", 2) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- -> { "ã‚".send(@method, "", -1) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- -> { "ã‚".send(@method, "", -2) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- end
-
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- re = Regexp.new "れ".encode(Encoding::EUC_JP)
- -> do
- "ã‚れ".send(@method, re)
- end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
- end
- end
-
- describe "with global variables" do
- it "doesn't set $~ for non regex search" do
- $~ = nil
-
- 'hello.'.send(@method, 'll')
- $~.should == nil
- end
-
- it "sets $~ to MatchData of match and nil when there's none" do
- 'hello.'.send(@method, /.e./)
- $~[0].should == 'hel'
-
- 'hello.'.send(@method, /not/)
- $~.should == nil
- end
- end
-end
diff --git a/spec/ruby/core/string/shared/chars.rb b/spec/ruby/core/string/shared/chars.rb
index c730643cf4..e9fdf89fd6 100644
--- a/spec/ruby/core/string/shared/chars.rb
+++ b/spec/ruby/core/string/shared/chars.rb
@@ -21,12 +21,12 @@ describe :string_chars, shared: true do
end
it "returns characters in the same encoding as self" do
- "&%".dup.force_encoding('Shift_JIS').send(@method).to_a.all? {|c| c.encoding.name.should == 'Shift_JIS'}
+ "&%".force_encoding('Shift_JIS').send(@method).to_a.all? {|c| c.encoding.name.should == 'Shift_JIS'}
"&%".encode('BINARY').send(@method).to_a.all? {|c| c.encoding.should == Encoding::BINARY }
end
it "works with multibyte characters" do
- s = "\u{8987}".dup.force_encoding("UTF-8")
+ s = "\u{8987}".force_encoding("UTF-8")
s.bytesize.should == 3
s.send(@method).to_a.should == [s]
end
@@ -39,14 +39,14 @@ describe :string_chars, shared: true do
end
it "returns a different character if the String is transcoded" do
- s = "\u{20AC}".dup.force_encoding('UTF-8')
- s.encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".dup.force_encoding('UTF-8')]
+ s = "\u{20AC}".force_encoding('UTF-8')
+ s.encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".force_encoding('UTF-8')]
s.encode('iso-8859-15').send(@method).to_a.should == [[0xA4].pack('C').force_encoding('iso-8859-15')]
- s.encode('iso-8859-15').encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".dup.force_encoding('UTF-8')]
+ s.encode('iso-8859-15').encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".force_encoding('UTF-8')]
end
it "uses the String's encoding to determine what characters it contains" do
- s = +"\u{24B62}"
+ s = "\u{24B62}"
s.force_encoding('UTF-8').send(@method).to_a.should == [
s.force_encoding('UTF-8')
diff --git a/spec/ruby/core/string/shared/codepoints.rb b/spec/ruby/core/string/shared/codepoints.rb
index f71263054a..0b2e078e0a 100644
--- a/spec/ruby/core/string/shared/codepoints.rb
+++ b/spec/ruby/core/string/shared/codepoints.rb
@@ -7,7 +7,7 @@ describe :string_codepoints, shared: true do
end
it "raises an ArgumentError when self has an invalid encoding and a method is called on the returned Enumerator" do
- s = "\xDF".dup.force_encoding(Encoding::UTF_8)
+ s = "\xDF".force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
-> { s.send(@method).to_a }.should raise_error(ArgumentError)
end
@@ -21,7 +21,7 @@ describe :string_codepoints, shared: true do
end
it "raises an ArgumentError if self's encoding is invalid and a block is given" do
- s = "\xDF".dup.force_encoding(Encoding::UTF_8)
+ s = "\xDF".force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
-> { s.send(@method) { } }.should raise_error(ArgumentError)
end
@@ -49,7 +49,7 @@ describe :string_codepoints, shared: true do
it "round-trips to the original String using Integer#chr" do
s = "\u{13}\u{7711}\u{1010}"
- s2 = +""
+ s2 = ""
s.send(@method) {|n| s2 << n.chr(Encoding::UTF_8)}
s.should == s2
end
diff --git a/spec/ruby/core/string/shared/concat.rb b/spec/ruby/core/string/shared/concat.rb
index dded9a69e7..54ac1035d3 100644
--- a/spec/ruby/core/string/shared/concat.rb
+++ b/spec/ruby/core/string/shared/concat.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
describe :string_concat, shared: true do
it "concatenates the given argument to self and returns self" do
str = 'hello '
@@ -6,6 +5,18 @@ describe :string_concat, shared: true do
str.should == "hello world"
end
+ it "converts the given argument to a String using to_str" do
+ obj = mock('world!')
+ obj.should_receive(:to_str).and_return("world!")
+ a = 'hello '.send(@method, obj)
+ a.should == 'hello world!'
+ end
+
+ it "raises a TypeError if the given argument can't be converted to a String" do
+ -> { 'hello '.send(@method, []) }.should raise_error(TypeError)
+ -> { 'hello '.send(@method, mock('x')) }.should raise_error(TypeError)
+ end
+
it "raises a FrozenError when self is frozen" do
a = "hello"
a.freeze
@@ -137,23 +148,3 @@ describe :string_concat_encoding, shared: true do
end
end
end
-
-describe :string_concat_type_coercion, shared: true do
- it "converts the given argument to a String using to_str" do
- obj = mock('world!')
- obj.should_receive(:to_str).and_return("world!")
- a = 'hello '.send(@method, obj)
- a.should == 'hello world!'
- end
-
- it "raises a TypeError if the given argument can't be converted to a String" do
- -> { 'hello '.send(@method, []) }.should raise_error(TypeError)
- -> { 'hello '.send(@method, mock('x')) }.should raise_error(TypeError)
- end
-
- it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
- obj = mock('world!')
- obj.should_receive(:to_str).and_raise(NoMethodError)
- -> { 'hello '.send(@method, obj) }.should raise_error(NoMethodError)
- end
-end
diff --git a/spec/ruby/core/string/shared/dedup.rb b/spec/ruby/core/string/shared/dedup.rb
index 97b5df6ed1..6ffcb9b045 100644
--- a/spec/ruby/core/string/shared/dedup.rb
+++ b/spec/ruby/core/string/shared/dedup.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
describe :string_dedup, shared: true do
it 'returns self if the String is frozen' do
input = 'foo'.freeze
@@ -49,8 +48,10 @@ describe :string_dedup, shared: true do
dynamic.send(@method).should equal(dynamic)
end
- it "interns the provided string if it is frozen" do
- dynamic = "this string is unique and frozen #{rand}".freeze
- dynamic.send(@method).should equal(dynamic)
+ ruby_version_is "3.0" do
+ it "interns the provided string if it is frozen" do
+ dynamic = "this string is unique and frozen #{rand}".freeze
+ dynamic.send(@method).should equal(dynamic)
+ end
end
end
diff --git a/spec/ruby/core/string/shared/each_codepoint_without_block.rb b/spec/ruby/core/string/shared/each_codepoint_without_block.rb
index 31b4c02c9c..92b7f76032 100644
--- a/spec/ruby/core/string/shared/each_codepoint_without_block.rb
+++ b/spec/ruby/core/string/shared/each_codepoint_without_block.rb
@@ -6,7 +6,7 @@ describe :string_each_codepoint_without_block, shared: true do
end
it "returns an Enumerator even when self has an invalid encoding" do
- s = "\xDF".dup.force_encoding(Encoding::UTF_8)
+ s = "\xDF".force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
s.send(@method).should be_an_instance_of(Enumerator)
end
@@ -23,7 +23,7 @@ describe :string_each_codepoint_without_block, shared: true do
end
it "should return the size of the string even when the string has an invalid encoding" do
- s = "\xDF".dup.force_encoding(Encoding::UTF_8)
+ s = "\xDF".force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
s.send(@method).size.should == 1
end
diff --git a/spec/ruby/core/string/shared/each_line.rb b/spec/ruby/core/string/shared/each_line.rb
index 231a6d9d4f..df78bd2186 100644
--- a/spec/ruby/core/string/shared/each_line.rb
+++ b/spec/ruby/core/string/shared/each_line.rb
@@ -85,10 +85,20 @@ describe :string_each_line, shared: true do
end
end
- it "yields String instances for subclasses" do
- a = []
- StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class }
- a.should == [String, String]
+ ruby_version_is ''...'3.0' do
+ it "yields subclass instances for subclasses" do
+ a = []
+ StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class }
+ a.should == [StringSpecs::MyString, StringSpecs::MyString]
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "yields String instances for subclasses" do
+ a = []
+ StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class }
+ a.should == [String, String]
+ end
end
it "returns self" do
@@ -106,7 +116,7 @@ describe :string_each_line, shared: true do
end
it "does not care if the string is modified while substituting" do
- str = +"hello\nworld."
+ str = "hello\nworld."
out = []
str.send(@method){|x| out << x; str[-1] = '!' }.should == "hello\nworld!"
out.should == ["hello\n", "world."]
diff --git a/spec/ruby/core/string/shared/encode.rb b/spec/ruby/core/string/shared/encode.rb
index 9466308886..a73de5b943 100644
--- a/spec/ruby/core/string/shared/encode.rb
+++ b/spec/ruby/core/string/shared/encode.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
describe :string_encode, shared: true do
describe "when passed no options" do
it "transcodes to Encoding.default_internal when set" do
@@ -194,190 +193,6 @@ describe :string_encode, shared: true do
end
end
- describe "given the fallback option" do
- context "given a hash" do
- it "looks up the replacement value from the hash" do
- encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: { "\ufffd" => "bar" })
- encoded.should == "Bbar"
- end
-
- it "calls to_str on the returned value" do
- obj = Object.new
- obj.should_receive(:to_str).and_return("bar")
- encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: { "\ufffd" => obj })
- encoded.should == "Bbar"
- end
-
- it "does not call to_s on the returned value" do
- obj = Object.new
- obj.should_not_receive(:to_s)
- -> {
- "B\ufffd".encode(Encoding::US_ASCII, fallback: { "\ufffd" => obj })
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
-
- it "raises an error if the key is not present in the hash" do
- -> {
- "B\ufffd".encode(Encoding::US_ASCII, fallback: { "foo" => "bar" })
- }.should raise_error(Encoding::UndefinedConversionError, "U+FFFD from UTF-8 to US-ASCII")
- end
-
- it "raises an error if the value is itself invalid" do
- -> {
- "B\ufffd".encode(Encoding::US_ASCII, fallback: { "\ufffd" => "\uffee" })
- }.should raise_error(ArgumentError, "too big fallback string")
- end
-
- it "uses the hash's default value if set" do
- hash = {}
- hash.default = "bar"
- encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: hash)
- encoded.should == "Bbar"
- end
-
- it "uses the result of calling default_proc if set" do
- hash = {}
- hash.default_proc = -> _, _ { "bar" }
- encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: hash)
- encoded.should == "Bbar"
- end
- end
-
- context "given an object inheriting from Hash" do
- before do
- klass = Class.new(Hash)
- @hash_like = klass.new
- @hash_like["\ufffd"] = "bar"
- end
-
- it "looks up the replacement value from the object" do
- encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: @hash_like)
- encoded.should == "Bbar"
- end
- end
-
- context "given an object responding to []" do
- before do
- klass = Class.new do
- def [](c) = c.bytes.inspect
- end
- @hash_like = klass.new
- end
-
- it "calls [] on the object, passing the invalid character" do
- encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: @hash_like)
- encoded.should == "B[239, 191, 189]"
- end
- end
-
- context "given an object not responding to []" do
- before do
- @non_hash_like = Object.new
- end
-
- it "raises an error" do
- -> {
- "B\ufffd".encode(Encoding::US_ASCII, fallback: @non_hash_like)
- }.should raise_error(Encoding::UndefinedConversionError, "U+FFFD from UTF-8 to US-ASCII")
- end
- end
-
- context "given a proc" do
- it "calls the proc to get the replacement value, passing in the invalid character" do
- encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: proc { |c| c.bytes.inspect })
- encoded.should == "B[239, 191, 189]"
- end
-
- it "calls to_str on the returned value" do
- obj = Object.new
- obj.should_receive(:to_str).and_return("bar")
- encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: proc { |c| obj })
- encoded.should == "Bbar"
- end
-
- it "does not call to_s on the returned value" do
- obj = Object.new
- obj.should_not_receive(:to_s)
- -> {
- "B\ufffd".encode(Encoding::US_ASCII, fallback: proc { |c| obj })
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
-
- it "raises an error if the returned value is itself invalid" do
- -> {
- "B\ufffd".encode(Encoding::US_ASCII, fallback: -> c { "\uffee" })
- }.should raise_error(ArgumentError, "too big fallback string")
- end
- end
-
- context "given a lambda" do
- it "calls the lambda to get the replacement value, passing in the invalid character" do
- encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: -> c { c.bytes.inspect })
- encoded.should == "B[239, 191, 189]"
- end
-
- it "calls to_str on the returned value" do
- obj = Object.new
- obj.should_receive(:to_str).and_return("bar")
- encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: -> c { obj })
- encoded.should == "Bbar"
- end
-
- it "does not call to_s on the returned value" do
- obj = Object.new
- obj.should_not_receive(:to_s)
- -> {
- "B\ufffd".encode(Encoding::US_ASCII, fallback: -> c { obj })
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
-
- it "raises an error if the returned value is itself invalid" do
- -> {
- "B\ufffd".encode(Encoding::US_ASCII, fallback: -> c { "\uffee" })
- }.should raise_error(ArgumentError, "too big fallback string")
- end
- end
-
- context "given a method" do
- def replace(c) = c.bytes.inspect
- def replace_bad(c) = "\uffee"
-
- def replace_to_str(c)
- obj = Object.new
- obj.should_receive(:to_str).and_return("bar")
- obj
- end
-
- def replace_to_s(c)
- obj = Object.new
- obj.should_not_receive(:to_s)
- obj
- end
-
- it "calls the method to get the replacement value, passing in the invalid character" do
- encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: method(:replace))
- encoded.should == "B[239, 191, 189]"
- end
-
- it "calls to_str on the returned value" do
- encoded = "B\ufffd".encode(Encoding::US_ASCII, fallback: method(:replace_to_str))
- encoded.should == "Bbar"
- end
-
- it "does not call to_s on the returned value" do
- -> {
- "B\ufffd".encode(Encoding::US_ASCII, fallback: method(:replace_to_s))
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
-
- it "raises an error if the returned value is itself invalid" do
- -> {
- "B\ufffd".encode(Encoding::US_ASCII, fallback: method(:replace_bad))
- }.should raise_error(ArgumentError, "too big fallback string")
- end
- end
- end
-
describe "given the xml: :text option" do
it "replaces all instances of '&' with '&amp;'" do
'& and &'.send(@method, "UTF-8", xml: :text).should == '&amp; and &amp;'
diff --git a/spec/ruby/core/string/shared/eql.rb b/spec/ruby/core/string/shared/eql.rb
index 845b0a3e15..6f268c929c 100644
--- a/spec/ruby/core/string/shared/eql.rb
+++ b/spec/ruby/core/string/shared/eql.rb
@@ -13,15 +13,15 @@ describe :string_eql_value, shared: true do
end
it "ignores encoding difference of compatible string" do
- "hello".dup.force_encoding("utf-8").send(@method, "hello".dup.force_encoding("iso-8859-1")).should be_true
+ "hello".force_encoding("utf-8").send(@method, "hello".force_encoding("iso-8859-1")).should be_true
end
it "considers encoding difference of incompatible string" do
- "\xff".dup.force_encoding("utf-8").send(@method, "\xff".dup.force_encoding("iso-8859-1")).should be_false
+ "\xff".force_encoding("utf-8").send(@method, "\xff".force_encoding("iso-8859-1")).should be_false
end
it "considers encoding compatibility" do
- "abcd".dup.force_encoding("utf-8").send(@method, "abcd".dup.force_encoding("utf-32le")).should be_false
+ "abcd".force_encoding("utf-8").send(@method, "abcd".force_encoding("utf-32le")).should be_false
end
it "ignores subclass differences" do
@@ -33,6 +33,6 @@ describe :string_eql_value, shared: true do
end
it "returns true when comparing 2 empty strings but one is not ASCII-compatible" do
- "".send(@method, "".dup.force_encoding('iso-2022-jp')).should == true
+ "".send(@method, "".force_encoding('iso-2022-jp')).should == true
end
end
diff --git a/spec/ruby/core/string/shared/length.rb b/spec/ruby/core/string/shared/length.rb
index ae572ba755..94e5ec135b 100644
--- a/spec/ruby/core/string/shared/length.rb
+++ b/spec/ruby/core/string/shared/length.rb
@@ -18,7 +18,7 @@ describe :string_length, shared: true do
end
it "returns the length of the new self after encoding is changed" do
- str = +'ã“ã«ã¡ã‚'
+ str = 'ã“ã«ã¡ã‚'
str.send(@method)
str.force_encoding('BINARY').send(@method).should == 12
@@ -44,12 +44,12 @@ describe :string_length, shared: true do
end
it "adds 1 (and not 2) for a incomplete surrogate in UTF-16" do
- "\x00\xd8".dup.force_encoding("UTF-16LE").send(@method).should == 1
- "\xd8\x00".dup.force_encoding("UTF-16BE").send(@method).should == 1
+ "\x00\xd8".force_encoding("UTF-16LE").send(@method).should == 1
+ "\xd8\x00".force_encoding("UTF-16BE").send(@method).should == 1
end
it "adds 1 for a broken sequence in UTF-32" do
- "\x04\x03\x02\x01".dup.force_encoding("UTF-32LE").send(@method).should == 1
- "\x01\x02\x03\x04".dup.force_encoding("UTF-32BE").send(@method).should == 1
+ "\x04\x03\x02\x01".force_encoding("UTF-32LE").send(@method).should == 1
+ "\x01\x02\x03\x04".force_encoding("UTF-32BE").send(@method).should == 1
end
end
diff --git a/spec/ruby/core/string/shared/partition.rb b/spec/ruby/core/string/shared/partition.rb
index 4cac149ce5..41b3c7e0c9 100644
--- a/spec/ruby/core/string/shared/partition.rb
+++ b/spec/ruby/core/string/shared/partition.rb
@@ -2,17 +2,35 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
describe :string_partition, shared: true do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("hello").send(@method, "l").each do |item|
- item.should be_an_instance_of(String)
- end
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("hello").send(@method, "l").each do |item|
+ item.should be_an_instance_of(String)
+ end
+
+ StringSpecs::MyString.new("hello").send(@method, "x").each do |item|
+ item.should be_an_instance_of(String)
+ end
- StringSpecs::MyString.new("hello").send(@method, "x").each do |item|
- item.should be_an_instance_of(String)
+ StringSpecs::MyString.new("hello").send(@method, /l./).each do |item|
+ item.should be_an_instance_of(String)
+ end
end
+ end
+
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new("hello").send(@method, StringSpecs::MyString.new("l")).each do |item|
+ item.should be_an_instance_of(StringSpecs::MyString)
+ end
+
+ StringSpecs::MyString.new("hello").send(@method, "x").each do |item|
+ item.should be_an_instance_of(StringSpecs::MyString)
+ end
- StringSpecs::MyString.new("hello").send(@method, /l./).each do |item|
- item.should be_an_instance_of(String)
+ StringSpecs::MyString.new("hello").send(@method, /l./).each do |item|
+ item.should be_an_instance_of(StringSpecs::MyString)
+ end
end
end
diff --git a/spec/ruby/core/string/shared/replace.rb b/spec/ruby/core/string/shared/replace.rb
index 24dac0eb27..a5108d9e7c 100644
--- a/spec/ruby/core/string/shared/replace.rb
+++ b/spec/ruby/core/string/shared/replace.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
describe :string_replace, shared: true do
it "returns self" do
a = "a"
diff --git a/spec/ruby/core/string/shared/slice.rb b/spec/ruby/core/string/shared/slice.rb
index 2f69b9ddce..a7c1d05b56 100644
--- a/spec/ruby/core/string/shared/slice.rb
+++ b/spec/ruby/core/string/shared/slice.rb
@@ -84,8 +84,8 @@ describe :string_slice_index_length, shared: true do
s = "hello there"
s.send(@method, 1, 9).encoding.should == s.encoding
- a = "hello".dup.force_encoding("binary")
- b = " there".dup.force_encoding("ISO-8859-1")
+ a = "hello".force_encoding("binary")
+ b = " there".force_encoding("ISO-8859-1")
c = (a + b).force_encoding(Encoding::US_ASCII)
c.send(@method, 0, 5).encoding.should == Encoding::US_ASCII
@@ -152,11 +152,22 @@ describe :string_slice_index_length, shared: true do
-> { "hello".send(@method, 0, bignum_value) }.should raise_error(RangeError)
end
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, 0,0).should be_an_instance_of(String)
- s.send(@method, 0,4).should be_an_instance_of(String)
- s.send(@method, 1,4).should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, 0,0).should be_an_instance_of(StringSpecs::MyString)
+ s.send(@method, 0,4).should be_an_instance_of(StringSpecs::MyString)
+ s.send(@method, 1,4).should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, 0,0).should be_an_instance_of(String)
+ s.send(@method, 0,4).should be_an_instance_of(String)
+ s.send(@method, 1,4).should be_an_instance_of(String)
+ end
end
it "handles repeated application" do
@@ -231,11 +242,22 @@ describe :string_slice_range, shared: true do
"x".send(@method, 1...-1).should == ""
end
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, 0...0).should be_an_instance_of(String)
- s.send(@method, 0..4).should be_an_instance_of(String)
- s.send(@method, 1..4).should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, 0...0).should be_an_instance_of(StringSpecs::MyString)
+ s.send(@method, 0..4).should be_an_instance_of(StringSpecs::MyString)
+ s.send(@method, 1..4).should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, 0...0).should be_an_instance_of(String)
+ s.send(@method, 0..4).should be_an_instance_of(String)
+ s.send(@method, 1..4).should be_an_instance_of(String)
+ end
end
it "calls to_int on range arguments" do
@@ -314,10 +336,20 @@ describe :string_slice_regexp, shared: true do
"hello there".encode("US-ASCII").send(@method, /[aeiou](.)\1/).encoding.should == Encoding::US_ASCII
end
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, //).should be_an_instance_of(String)
- s.send(@method, /../).should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, //).should be_an_instance_of(StringSpecs::MyString)
+ s.send(@method, /../).should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, //).should be_an_instance_of(String)
+ s.send(@method, /../).should be_an_instance_of(String)
+ end
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -386,10 +418,20 @@ describe :string_slice_regexp_index, shared: true do
-> { "hello".send(@method, /(.)(.)(.)/, nil) }.should raise_error(TypeError)
end
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, /(.)(.)/, 0).should be_an_instance_of(String)
- s.send(@method, /(.)(.)/, 1).should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, /(.)(.)/, 0).should be_an_instance_of(StringSpecs::MyString)
+ s.send(@method, /(.)(.)/, 1).should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, /(.)(.)/, 0).should be_an_instance_of(String)
+ s.send(@method, /(.)(.)/, 1).should be_an_instance_of(String)
+ end
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -428,11 +470,22 @@ describe :string_slice_string, shared: true do
-> { "hello".send(@method, o) }.should raise_error(TypeError)
end
- it "returns a String instance when given a subclass instance" do
- s = StringSpecs::MyString.new("el")
- r = "hello".send(@method, s)
- r.should == "el"
- r.should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns a subclass instance when given a subclass instance" do
+ s = StringSpecs::MyString.new("el")
+ r = "hello".send(@method, s)
+ r.should == "el"
+ r.should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns a String instance when given a subclass instance" do
+ s = StringSpecs::MyString.new("el")
+ r = "hello".send(@method, s)
+ r.should == "el"
+ r.should be_an_instance_of(String)
+ end
end
end
@@ -478,9 +531,18 @@ describe :string_slice_regexp_group, shared: true do
-> { "hello".send(@method, /(?<q>)/, '') }.should raise_error(IndexError)
end
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(String)
+ end
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
diff --git a/spec/ruby/core/string/shared/strip.rb b/spec/ruby/core/string/shared/strip.rb
index 3af77b50fe..0c0aae20f3 100644
--- a/spec/ruby/core/string/shared/strip.rb
+++ b/spec/ruby/core/string/shared/strip.rb
@@ -6,9 +6,19 @@ describe :string_strip, shared: true do
" hello ".encode("US-ASCII").send(@method).encoding.should == Encoding::US_ASCII
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new(" hello ").send(@method).should be_an_instance_of(String)
- StringSpecs::MyString.new(" ").send(@method).should be_an_instance_of(String)
- StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String)
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new(" hello ").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new(" ").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String)
+ end
+ end
+
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new(" hello ").send(@method).should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new(" ").send(@method).should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("").send(@method).should be_an_instance_of(StringSpecs::MyString)
+ end
end
end
diff --git a/spec/ruby/core/string/shared/succ.rb b/spec/ruby/core/string/shared/succ.rb
index b69a394875..3605fa99a2 100644
--- a/spec/ruby/core/string/shared/succ.rb
+++ b/spec/ruby/core/string/shared/succ.rb
@@ -59,10 +59,20 @@ describe :string_succ, shared: true do
"\xFF\xFF".send(@method).should == "\x01\x00\x00"
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String)
- StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(String)
- StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new("").send(@method).should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(String)
+ end
end
it "returns a String in the same encoding as self" do
@@ -73,7 +83,6 @@ end
describe :string_succ_bang, shared: true do
it "is equivalent to succ, but modifies self in place (still returns self)" do
["", "abcd", "THX1138"].each do |s|
- s = +s
r = s.dup.send(@method)
s.send(@method).should equal(s)
s.should == r
diff --git a/spec/ruby/core/string/shared/to_a.rb b/spec/ruby/core/string/shared/to_a.rb
new file mode 100644
index 0000000000..bad3ea6584
--- /dev/null
+++ b/spec/ruby/core/string/shared/to_a.rb
@@ -0,0 +1,9 @@
+describe :string_to_a, shared: true do
+ it "returns an empty array for empty strings" do
+ "".send(@method).should == []
+ end
+
+ it "returns an array containing the string for non-empty strings" do
+ "hello".send(@method).should == ["hello"]
+ end
+end
diff --git a/spec/ruby/core/string/shared/to_sym.rb b/spec/ruby/core/string/shared/to_sym.rb
index 833eae100e..ef7c22bb6a 100644
--- a/spec/ruby/core/string/shared/to_sym.rb
+++ b/spec/ruby/core/string/shared/to_sym.rb
@@ -56,9 +56,9 @@ describe :string_to_sym, shared: true do
it "ignores existing symbols with different encoding" do
source = "fée"
- iso_symbol = source.dup.force_encoding(Encoding::ISO_8859_1).send(@method)
+ iso_symbol = source.force_encoding(Encoding::ISO_8859_1).send(@method)
iso_symbol.encoding.should == Encoding::ISO_8859_1
- binary_symbol = source.dup.force_encoding(Encoding::BINARY).send(@method)
+ binary_symbol = source.force_encoding(Encoding::BINARY).send(@method)
binary_symbol.encoding.should == Encoding::BINARY
end
@@ -67,6 +67,6 @@ describe :string_to_sym, shared: true do
invalid_utf8.should_not.valid_encoding?
-> {
invalid_utf8.send(@method)
- }.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"')
+ }.should raise_error(EncodingError, /invalid/)
end
end
diff --git a/spec/ruby/core/string/slice_spec.rb b/spec/ruby/core/string/slice_spec.rb
index 5aba2d3be0..c9e13ed1bc 100644
--- a/spec/ruby/core/string/slice_spec.rb
+++ b/spec/ruby/core/string/slice_spec.rb
@@ -1,5 +1,5 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
+
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/slice'
@@ -132,10 +132,20 @@ describe "String#slice! with index, length" do
"hello".slice!(obj, obj).should == "ll"
end
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.slice!(0, 0).should be_an_instance_of(String)
- s.slice!(0, 4).should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.slice!(0, 0).should be_an_instance_of(StringSpecs::MyString)
+ s.slice!(0, 4).should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.slice!(0, 0).should be_an_instance_of(String)
+ s.slice!(0, 4).should be_an_instance_of(String)
+ end
end
it "returns the substring given by the character offsets" do
@@ -175,10 +185,20 @@ describe "String#slice! Range" do
b.should == "hello"
end
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.slice!(0...0).should be_an_instance_of(String)
- s.slice!(0..4).should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.slice!(0...0).should be_an_instance_of(StringSpecs::MyString)
+ s.slice!(0..4).should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.slice!(0...0).should be_an_instance_of(String)
+ s.slice!(0..4).should be_an_instance_of(String)
+ end
end
it "calls to_int on range arguments" do
@@ -254,10 +274,20 @@ describe "String#slice! with Regexp" do
s.should == "this is a string"
end
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.slice!(//).should be_an_instance_of(String)
- s.slice!(/../).should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.slice!(//).should be_an_instance_of(StringSpecs::MyString)
+ s.slice!(/../).should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.slice!(//).should be_an_instance_of(String)
+ s.slice!(/../).should be_an_instance_of(String)
+ end
end
it "returns the matching portion of self with a multi byte character" do
@@ -314,10 +344,20 @@ describe "String#slice! with Regexp, index" do
"har".slice!(/(.)(.)(.)/, obj).should == "a"
end
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.slice!(/(.)(.)/, 0).should be_an_instance_of(String)
- s.slice!(/(.)(.)/, 1).should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.slice!(/(.)(.)/, 0).should be_an_instance_of(StringSpecs::MyString)
+ s.slice!(/(.)(.)/, 1).should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.slice!(/(.)(.)/, 0).should be_an_instance_of(String)
+ s.slice!(/(.)(.)/, 1).should be_an_instance_of(String)
+ end
end
it "returns the encoding aware capture for the given index" do
@@ -375,11 +415,22 @@ describe "String#slice! with String" do
-> { "hello".slice!(o) }.should raise_error(TypeError)
end
- it "returns a subclass instance when given a subclass instance" do
- s = StringSpecs::MyString.new("el")
- r = "hello".slice!(s)
- r.should == "el"
- r.should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns a subclass instance when given a subclass instance" do
+ s = StringSpecs::MyString.new("el")
+ r = "hello".slice!(s)
+ r.should == "el"
+ r.should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns a subclass instance when given a subclass instance" do
+ s = StringSpecs::MyString.new("el")
+ r = "hello".slice!(s)
+ r.should == "el"
+ r.should be_an_instance_of(String)
+ end
end
it "raises a FrozenError if self is frozen" do
diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb
index 3c6d1864d1..519c5d845d 100644
--- a/spec/ruby/core/string/split_spec.rb
+++ b/spec/ruby/core/string/split_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
describe "String#split with String" do
it "throws an ArgumentError if the string is not a valid" do
- s = "\xDF".dup.force_encoding(Encoding::UTF_8)
+ s = "\xDF".force_encoding(Encoding::UTF_8)
-> { s.split }.should raise_error(ArgumentError)
-> { s.split(':') }.should raise_error(ArgumentError)
@@ -12,7 +12,7 @@ describe "String#split with String" do
it "throws an ArgumentError if the pattern is not a valid string" do
str = 'проверка'
- broken_str = "\xDF".dup.force_encoding(Encoding::UTF_8)
+ broken_str = "\xDF".force_encoding(Encoding::UTF_8)
-> { str.split(broken_str) }.should raise_error(ArgumentError)
end
@@ -192,16 +192,44 @@ describe "String#split with String" do
"foo".split("bar", 3).should == ["foo"]
end
- it "returns String instances based on self" do
- ["", "x.y.z.", " x y "].each do |str|
- ["", ".", " "].each do |pat|
- [-1, 0, 1, 2].each do |limit|
- StringSpecs::MyString.new(str).split(pat, limit).each do |x|
- x.should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances based on self" do
+ ["", "x.y.z.", " x y "].each do |str|
+ ["", ".", " "].each do |pat|
+ [-1, 0, 1, 2].each do |limit|
+ StringSpecs::MyString.new(str).split(pat, limit).each do |x|
+ x.should be_an_instance_of(StringSpecs::MyString)
+ end
+
+ str.split(StringSpecs::MyString.new(pat), limit).each do |x|
+ x.should be_an_instance_of(String)
+ end
end
+ end
+ end
+ end
- str.split(StringSpecs::MyString.new(pat), limit).each do |x|
- x.should be_an_instance_of(String)
+ it "does not call constructor on created subclass instances" do
+ # can't call should_not_receive on an object that doesn't yet exist
+ # so failure here is signalled by exception, not expectation failure
+
+ s = StringSpecs::StringWithRaisingConstructor.new('silly:string')
+ s.split(':').first.should == 'silly'
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances based on self" do
+ ["", "x.y.z.", " x y "].each do |str|
+ ["", ".", " "].each do |pat|
+ [-1, 0, 1, 2].each do |limit|
+ StringSpecs::MyString.new(str).split(pat, limit).each do |x|
+ x.should be_an_instance_of(String)
+ end
+
+ str.split(StringSpecs::MyString.new(pat), limit).each do |x|
+ x.should be_an_instance_of(String)
+ end
end
end
end
@@ -229,7 +257,7 @@ end
describe "String#split with Regexp" do
it "throws an ArgumentError if the string is not a valid" do
- s = "\xDF".dup.force_encoding(Encoding::UTF_8)
+ s = "\xDF".force_encoding(Encoding::UTF_8)
-> { s.split(/./) }.should raise_error(ArgumentError)
end
@@ -386,12 +414,36 @@ describe "String#split with Regexp" do
"foo".split(/bar/, 3).should == ["foo"]
end
- it "returns String instances based on self" do
- ["", "x:y:z:", " x y "].each do |str|
- [//, /:/, /\s+/].each do |pat|
- [-1, 0, 1, 2].each do |limit|
- StringSpecs::MyString.new(str).split(pat, limit).each do |x|
- x.should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances based on self" do
+ ["", "x:y:z:", " x y "].each do |str|
+ [//, /:/, /\s+/].each do |pat|
+ [-1, 0, 1, 2].each do |limit|
+ StringSpecs::MyString.new(str).split(pat, limit).each do |x|
+ x.should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+ end
+ end
+ end
+
+ it "does not call constructor on created subclass instances" do
+ # can't call should_not_receive on an object that doesn't yet exist
+ # so failure here is signalled by exception, not expectation failure
+
+ s = StringSpecs::StringWithRaisingConstructor.new('silly:string')
+ s.split(/:/).first.should == 'silly'
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances based on self" do
+ ["", "x:y:z:", " x y "].each do |str|
+ [//, /:/, /\s+/].each do |pat|
+ [-1, 0, 1, 2].each do |limit|
+ StringSpecs::MyString.new(str).split(pat, limit).each do |x|
+ x.should be_an_instance_of(String)
+ end
end
end
end
@@ -409,7 +461,7 @@ describe "String#split with Regexp" do
end
it "returns an ArgumentError if an invalid UTF-8 string is supplied" do
- broken_str = +'проверка' # in russian, means "test"
+ broken_str = 'проверка' # in russian, means "test"
broken_str.force_encoding('binary')
broken_str.chop!
broken_str.force_encoding('utf-8')
@@ -517,16 +569,32 @@ describe "String#split with Regexp" do
end
describe "for a String subclass" do
- it "yields instances of String" do
- a = []
- StringSpecs::MyString.new("a|b").split("|") { |str| a << str }
- first, last = a
+ ruby_version_is ''...'3.0' do
+ it "yields instances of the same subclass" do
+ a = []
+ StringSpecs::MyString.new("a|b").split("|") { |str| a << str }
+ first, last = a
- first.should be_an_instance_of(String)
- first.should == "a"
+ first.should be_an_instance_of(StringSpecs::MyString)
+ first.should == "a"
- last.should be_an_instance_of(String)
- last.should == "b"
+ last.should be_an_instance_of(StringSpecs::MyString)
+ last.should == "b"
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "yields instances of String" do
+ a = []
+ StringSpecs::MyString.new("a|b").split("|") { |str| a << str }
+ first, last = a
+
+ first.should be_an_instance_of(String)
+ first.should == "a"
+
+ last.should be_an_instance_of(String)
+ last.should == "b"
+ end
end
end
diff --git a/spec/ruby/core/string/squeeze_spec.rb b/spec/ruby/core/string/squeeze_spec.rb
index 4ea238e6b5..2f3fa65745 100644
--- a/spec/ruby/core/string/squeeze_spec.rb
+++ b/spec/ruby/core/string/squeeze_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: binary -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -76,8 +75,16 @@ describe "String#squeeze" do
-> { "hello world".squeeze(mock('x')) }.should raise_error(TypeError)
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(String)
+ end
end
end
diff --git a/spec/ruby/core/string/start_with_spec.rb b/spec/ruby/core/string/start_with_spec.rb
index 35e33b46a6..3833289f96 100644
--- a/spec/ruby/core/string/start_with_spec.rb
+++ b/spec/ruby/core/string/start_with_spec.rb
@@ -7,21 +7,12 @@ describe "String#start_with?" do
it_behaves_like :start_with, :to_s
# Here and not in the shared examples because this is invalid as a Symbol
- it "matches part of a character with the same part" do
+ it "does not check that we are not starting to match at the head of a character" do
"\xA9".should.start_with?("\xA9") # A9 is not a character head for UTF-8
end
- ruby_version_is ""..."3.3" do
- it "does not check we are matching only part of a character" do
- "\xe3\x81\x82".size.should == 1
- "\xe3\x81\x82".should.start_with?("\xe3")
- end
- end
-
- ruby_version_is "3.3" do # #19784
- it "checks we are matching only part of a character" do
- "\xe3\x81\x82".size.should == 1
- "\xe3\x81\x82".should_not.start_with?("\xe3")
- end
+ it "does not check we are matching only part of a character" do
+ "\xe3\x81\x82".size.should == 1
+ "\xe3\x81\x82".should.start_with?("\xe3")
end
end
diff --git a/spec/ruby/core/string/strip_spec.rb b/spec/ruby/core/string/strip_spec.rb
index edb6ea3b44..662f13b032 100644
--- a/spec/ruby/core/string/strip_spec.rb
+++ b/spec/ruby/core/string/strip_spec.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/strip'
@@ -12,8 +11,10 @@ describe "String#strip" do
"\tgoodbye\r\v\n".strip.should == "goodbye"
end
- it "returns a copy of self without leading and trailing NULL bytes and whitespace" do
- " \x00 goodbye \x00 ".strip.should == "goodbye"
+ ruby_version_is '3.0' do
+ it "returns a copy of self without leading and trailing NULL bytes and whitespace" do
+ " \x00 goodbye \x00 ".strip.should == "goodbye"
+ end
end
end
@@ -40,10 +41,12 @@ describe "String#strip!" do
" ".strip.should == ""
end
- it "removes leading and trailing NULL bytes and whitespace" do
- a = "\000 goodbye \000"
- a.strip!
- a.should == "goodbye"
+ ruby_version_is '3.0' do
+ it "removes leading and trailing NULL bytes and whitespace" do
+ a = "\000 goodbye \000"
+ a.strip!
+ a.should == "goodbye"
+ end
end
it "raises a FrozenError on a frozen instance that is modified" do
diff --git a/spec/ruby/core/string/sub_spec.rb b/spec/ruby/core/string/sub_spec.rb
index 4f9f87a433..99dd7b45a8 100644
--- a/spec/ruby/core/string/sub_spec.rb
+++ b/spec/ruby/core/string/sub_spec.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -171,11 +170,22 @@ describe "String#sub with pattern, replacement" do
-> { "hello".sub(/[aeiou]/, 99) }.should raise_error(TypeError)
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(String)
+ end
end
it "sets $~ to MatchData of match and nil when there's none" do
diff --git a/spec/ruby/core/string/swapcase_spec.rb b/spec/ruby/core/string/swapcase_spec.rb
index 7f4c68366d..d369ab3e4e 100644
--- a/spec/ruby/core/string/swapcase_spec.rb
+++ b/spec/ruby/core/string/swapcase_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -75,9 +74,18 @@ describe "String#swapcase" do
-> { "abc".swapcase(:invalid_option) }.should raise_error(ArgumentError)
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("").swapcase.should be_an_instance_of(String)
- StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new("").swapcase.should be_an_instance_of(StringSpecs::MyString)
+ StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("").swapcase.should be_an_instance_of(String)
+ StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(String)
+ end
end
end
diff --git a/spec/ruby/core/string/to_c_spec.rb b/spec/ruby/core/string/to_c_spec.rb
index 9d24f1f56c..edc8a4f14f 100644
--- a/spec/ruby/core/string/to_c_spec.rb
+++ b/spec/ruby/core/string/to_c_spec.rb
@@ -38,16 +38,4 @@ describe "String#to_c" do
'79+4i'.encode("UTF-16").to_c
}.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
end
-
- ruby_version_is "3.2" do
- it "treats a sequence of underscores as an end of Complex string" do
- "5+3_1i".to_c.should == Complex(5, 31)
- "5+3__1i".to_c.should == Complex(5)
- "5+3___1i".to_c.should == Complex(5)
-
- "12_3".to_c.should == Complex(123)
- "12__3".to_c.should == Complex(12)
- "12___3".to_c.should == Complex(12)
- end
- end
end
diff --git a/spec/ruby/core/string/to_i_spec.rb b/spec/ruby/core/string/to_i_spec.rb
index 9931502baa..e4fa89aab3 100644
--- a/spec/ruby/core/string/to_i_spec.rb
+++ b/spec/ruby/core/string/to_i_spec.rb
@@ -10,18 +10,6 @@ describe "String#to_i" do
"1_2_3asdf".to_i.should == 123
end
- it "ignores multiple non-consecutive underscoes when the first digit is 0" do
- (2..16).each do |base|
- "0_0_010".to_i(base).should == base;
- end
- end
-
- it "bails out at the first double underscore if the first digit is 0" do
- (2..16).each do |base|
- "010__1".to_i(base).should == base;
- end
- end
-
it "ignores leading whitespaces" do
[ " 123", " 123", "\r\n\r\n123", "\t\t123",
"\r\n\t\n123", " \t\n\r\t 123"].each do |str|
diff --git a/spec/ruby/core/string/tr_s_spec.rb b/spec/ruby/core/string/tr_s_spec.rb
index dd72da440c..e1bb20ce35 100644
--- a/spec/ruby/core/string/tr_s_spec.rb
+++ b/spec/ruby/core/string/tr_s_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -18,15 +17,6 @@ describe "String#tr_s" do
"hello ^--^".tr_s("---", "_").should == "hello ^_^"
end
- ruby_bug "#19769", ""..."3.3" do
- it "accepts c1-c1 notation to denote range of one character" do
- "hello".tr_s('e-e', 'x').should == "hxllo"
- "123456789".tr_s("2-23","xy").should == "1xy456789"
- "hello ^-^".tr_s("e-", "a-a_").should == "hallo ^_^"
- "hello ^-^".tr_s("---o", "_a").should == "hella ^_^"
- end
- end
-
it "pads to_str with its last char if it is shorter than from_string" do
"this".tr_s("this", "x").should == "x"
end
@@ -55,8 +45,16 @@ describe "String#tr_s" do
"bla".tr_s(from_str, to_str).should == "BlA"
end
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(String)
+ end
end
# http://redmine.ruby-lang.org/issues/show/1839
diff --git a/spec/ruby/core/string/tr_spec.rb b/spec/ruby/core/string/tr_spec.rb
index 75841a974f..72adb9f2eb 100644
--- a/spec/ruby/core/string/tr_spec.rb
+++ b/spec/ruby/core/string/tr_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -17,15 +16,6 @@ describe "String#tr" do
"hello ^-^".tr("---", "_").should == "hello ^_^"
end
- ruby_bug "#19769", ""..."3.3" do
- it "accepts c1-c1 notation to denote range of one character" do
- "hello".tr('e-e', 'x').should == "hxllo"
- "123456789".tr("2-23","xy").should == "1xy456789"
- "hello ^-^".tr("e-", "a-a_").should == "hallo ^_^"
- "hello ^-^".tr("---o", "_a").should == "hella ^_^"
- end
- end
-
it "pads to_str with its last char if it is shorter than from_string" do
"this".tr("this", "x").should == "xxxx"
"hello".tr("a-z", "A-H.").should == "HE..."
@@ -67,8 +57,16 @@ describe "String#tr" do
"bla".tr(from_str, to_str).should == "BlA"
end
- it "returns Stringinstances when called on a subclass" do
- StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns subclass instances when called on a subclass" do
+ StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns Stringinstances when called on a subclass" do
+ StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(String)
+ end
end
# http://redmine.ruby-lang.org/issues/show/1839
diff --git a/spec/ruby/core/string/try_convert_spec.rb b/spec/ruby/core/string/try_convert_spec.rb
index 72ce5dd8b2..84415c4a75 100644
--- a/spec/ruby/core/string/try_convert_spec.rb
+++ b/spec/ruby/core/string/try_convert_spec.rb
@@ -39,7 +39,7 @@ describe "String.try_convert" do
it "sends #to_str to the argument and raises TypeError if it's not a kind of String" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(Object.new)
- -> { String.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to String (MockObject#to_str gives Object)")
+ -> { String.try_convert obj }.should raise_error(TypeError)
end
it "does not rescue exceptions raised by #to_str" do
diff --git a/spec/ruby/core/string/unicode_normalize_spec.rb b/spec/ruby/core/string/unicode_normalize_spec.rb
index 2e7d22394a..6de7533fc7 100644
--- a/spec/ruby/core/string/unicode_normalize_spec.rb
+++ b/spec/ruby/core/string/unicode_normalize_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
# Examples taken from http://www.unicode.org/reports/tr15/#Norm_Forms
diff --git a/spec/ruby/core/string/unicode_normalized_spec.rb b/spec/ruby/core/string/unicode_normalized_spec.rb
index 91cf2086b2..87f3740459 100644
--- a/spec/ruby/core/string/unicode_normalized_spec.rb
+++ b/spec/ruby/core/string/unicode_normalized_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
describe "String#unicode_normalized?" do
diff --git a/spec/ruby/core/string/unpack/a_spec.rb b/spec/ruby/core/string/unpack/a_spec.rb
index 4002ece697..2d83b4c824 100644
--- a/spec/ruby/core/string/unpack/a_spec.rb
+++ b/spec/ruby/core/string/unpack/a_spec.rb
@@ -31,7 +31,7 @@ describe "String#unpack with format 'A'" do
end
it "decodes into raw (ascii) string values" do
- str = "str".dup.force_encoding('UTF-8').unpack("A*")[0]
+ str = "str".force_encoding('UTF-8').unpack("A*")[0]
str.encoding.should == Encoding::BINARY
end
diff --git a/spec/ruby/core/string/unpack/b_spec.rb b/spec/ruby/core/string/unpack/b_spec.rb
index 23d93a8aea..2cf5ebad34 100644
--- a/spec/ruby/core/string/unpack/b_spec.rb
+++ b/spec/ruby/core/string/unpack/b_spec.rb
@@ -88,9 +88,7 @@ describe "String#unpack with format 'B'" do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- "\x80\x00".unpack("B\x00B").should == ["1", "0"]
- end
+ "\x80\x00".unpack("B\x00B").should == ["1", "0"]
end
end
@@ -107,7 +105,7 @@ describe "String#unpack with format 'B'" do
end
it "decodes into US-ASCII string values" do
- str = "s".dup.force_encoding('UTF-8').unpack("B*")[0]
+ str = "s".force_encoding('UTF-8').unpack("B*")[0]
str.encoding.name.should == 'US-ASCII'
end
end
@@ -196,9 +194,7 @@ describe "String#unpack with format 'b'" do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- "\x01\x00".unpack("b\x00b").should == ["1", "0"]
- end
+ "\x01\x00".unpack("b\x00b").should == ["1", "0"]
end
end
@@ -215,7 +211,7 @@ describe "String#unpack with format 'b'" do
end
it "decodes into US-ASCII string values" do
- str = "s".dup.force_encoding('UTF-8').unpack("b*")[0]
+ str = "s".force_encoding('UTF-8').unpack("b*")[0]
str.encoding.name.should == 'US-ASCII'
end
end
diff --git a/spec/ruby/core/string/unpack/c_spec.rb b/spec/ruby/core/string/unpack/c_spec.rb
index c2bf813954..dbcbacc74d 100644
--- a/spec/ruby/core/string/unpack/c_spec.rb
+++ b/spec/ruby/core/string/unpack/c_spec.rb
@@ -37,9 +37,7 @@ describe :string_unpack_8bit, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- "abc".unpack(unpack_format("\000", 2)).should == [97, 98]
- end
+ "abc".unpack(unpack_format("\000", 2)).should == [97, 98]
end
end
diff --git a/spec/ruby/core/string/unpack/h_spec.rb b/spec/ruby/core/string/unpack/h_spec.rb
index 19c4d63664..ee08d20926 100644
--- a/spec/ruby/core/string/unpack/h_spec.rb
+++ b/spec/ruby/core/string/unpack/h_spec.rb
@@ -58,9 +58,7 @@ describe "String#unpack with format 'H'" do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- "\x01\x10".unpack("H\x00H").should == ["0", "1"]
- end
+ "\x01\x10".unpack("H\x00H").should == ["0", "1"]
end
end
@@ -135,9 +133,7 @@ describe "String#unpack with format 'h'" do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- "\x01\x10".unpack("h\x00h").should == ["1", "0"]
- end
+ "\x01\x10".unpack("h\x00h").should == ["1", "0"]
end
end
diff --git a/spec/ruby/core/string/unpack/l_spec.rb b/spec/ruby/core/string/unpack/l_spec.rb
index 0adb567eca..18bb68b8d0 100644
--- a/spec/ruby/core/string/unpack/l_spec.rb
+++ b/spec/ruby/core/string/unpack/l_spec.rb
@@ -14,7 +14,7 @@ describe "String#unpack with format 'L'" do
it_behaves_like :string_unpack_32bit_be_unsigned, 'L>'
end
- platform_is c_long_size: 32 do
+ platform_is wordsize: 32 do
describe "with modifier '<' and '_'" do
it_behaves_like :string_unpack_32bit_le, 'L<_'
it_behaves_like :string_unpack_32bit_le, 'L_<'
@@ -44,7 +44,7 @@ describe "String#unpack with format 'L'" do
end
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
describe "with modifier '<' and '_'" do
it_behaves_like :string_unpack_64bit_le, 'L<_'
it_behaves_like :string_unpack_64bit_le, 'L_<'
@@ -86,7 +86,7 @@ describe "String#unpack with format 'l'" do
it_behaves_like :string_unpack_32bit_be_signed, 'l>'
end
- platform_is c_long_size: 32 do
+ platform_is wordsize: 32 do
describe "with modifier '<' and '_'" do
it_behaves_like :string_unpack_32bit_le, 'l<_'
it_behaves_like :string_unpack_32bit_le, 'l_<'
@@ -116,7 +116,7 @@ describe "String#unpack with format 'l'" do
end
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
describe "with modifier '<' and '_'" do
it_behaves_like :string_unpack_64bit_le, 'l<_'
it_behaves_like :string_unpack_64bit_le, 'l_<'
@@ -160,7 +160,7 @@ little_endian do
it_behaves_like :string_unpack_32bit_le_signed, 'l'
end
- platform_is c_long_size: 32 do
+ platform_is wordsize: 32 do
describe "String#unpack with format 'L' with modifier '_'" do
it_behaves_like :string_unpack_32bit_le, 'L_'
it_behaves_like :string_unpack_32bit_le_unsigned, 'L_'
@@ -182,7 +182,7 @@ little_endian do
end
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
describe "String#unpack with format 'L' with modifier '_'" do
it_behaves_like :string_unpack_64bit_le, 'L_'
it_behaves_like :string_unpack_64bit_le_unsigned, 'L_'
@@ -218,7 +218,7 @@ big_endian do
it_behaves_like :string_unpack_32bit_be_signed, 'l'
end
- platform_is c_long_size: 32 do
+ platform_is wordsize: 32 do
describe "String#unpack with format 'L' with modifier '_'" do
it_behaves_like :string_unpack_32bit_be, 'L_'
it_behaves_like :string_unpack_32bit_be_unsigned, 'L_'
@@ -240,7 +240,7 @@ big_endian do
end
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
describe "String#unpack with format 'L' with modifier '_'" do
it_behaves_like :string_unpack_64bit_be, 'L_'
it_behaves_like :string_unpack_64bit_be_unsigned, 'L_'
diff --git a/spec/ruby/core/string/unpack/shared/float.rb b/spec/ruby/core/string/unpack/shared/float.rb
index 93282bf4c9..ccddf94f99 100644
--- a/spec/ruby/core/string/unpack/shared/float.rb
+++ b/spec/ruby/core/string/unpack/shared/float.rb
@@ -58,10 +58,8 @@ describe :string_unpack_float_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- array = "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
- array.should == [2.9000000953674316, 1.399999976158142]
- end
+ array = "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
+ array.should == [2.9000000953674316, 1.399999976158142]
end
end
@@ -137,10 +135,8 @@ describe :string_unpack_float_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- array = "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
- array.should == [2.9000000953674316, 1.399999976158142]
- end
+ array = "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
+ array.should == [2.9000000953674316, 1.399999976158142]
end
end
@@ -219,9 +215,7 @@ describe :string_unpack_double_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
- end
+ "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
end
end
@@ -299,9 +293,7 @@ describe :string_unpack_double_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
- end
+ "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
end
end
diff --git a/spec/ruby/core/string/unpack/shared/integer.rb b/spec/ruby/core/string/unpack/shared/integer.rb
index d71a2cf00d..ba4f149dad 100644
--- a/spec/ruby/core/string/unpack/shared/integer.rb
+++ b/spec/ruby/core/string/unpack/shared/integer.rb
@@ -34,9 +34,7 @@ describe :string_unpack_16bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- "abcd".unpack(unpack_format("\000", 2)).should == [25185, 25699]
- end
+ "abcd".unpack(unpack_format("\000", 2)).should == [25185, 25699]
end
end
@@ -99,9 +97,7 @@ describe :string_unpack_16bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- "badc".unpack(unpack_format("\000", 2)).should == [25185, 25699]
- end
+ "badc".unpack(unpack_format("\000", 2)).should == [25185, 25699]
end
end
@@ -165,9 +161,7 @@ describe :string_unpack_32bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- "abcdefgh".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
- end
+ "abcdefgh".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
end
end
@@ -231,9 +225,7 @@ describe :string_unpack_32bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- "dcbahgfe".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
- end
+ "dcbahgfe".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
end
end
@@ -293,10 +285,8 @@ describe :string_unpack_64bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- array = "abcdefghabghefcd".unpack(unpack_format("\000", 2))
- array.should == [7523094288207667809, 7233738012216484449]
- end
+ array = "abcdefghabghefcd".unpack(unpack_format("\000", 2))
+ array.should == [7523094288207667809, 7233738012216484449]
end
end
@@ -367,10 +357,8 @@ describe :string_unpack_64bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- array = "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
- array.should == [7523094288207667809, 7233738012216484449]
- end
+ array = "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
+ array.should == [7523094288207667809, 7233738012216484449]
end
end
diff --git a/spec/ruby/core/string/unpack/shared/unicode.rb b/spec/ruby/core/string/unpack/shared/unicode.rb
index 9fe07f53ae..ce1f29fe87 100644
--- a/spec/ruby/core/string/unpack/shared/unicode.rb
+++ b/spec/ruby/core/string/unpack/shared/unicode.rb
@@ -52,9 +52,7 @@ describe :string_unpack_unicode, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- "\x01\x02".unpack("U\x00U").should == [1, 2]
- end
+ "\x01\x02".unpack("U\x00U").should == [1, 2]
end
end
diff --git a/spec/ruby/core/string/unpack/u_spec.rb b/spec/ruby/core/string/unpack/u_spec.rb
index 456abee784..7845e6d5f2 100644
--- a/spec/ruby/core/string/unpack/u_spec.rb
+++ b/spec/ruby/core/string/unpack/u_spec.rb
@@ -33,7 +33,7 @@ describe "String#unpack with format 'u'" do
str = "".unpack("u")[0]
str.encoding.should == Encoding::BINARY
- str = "1".dup.force_encoding('UTF-8').unpack("u")[0]
+ str = "1".force_encoding('UTF-8').unpack("u")[0]
str.encoding.should == Encoding::BINARY
end
diff --git a/spec/ruby/core/string/unpack/w_spec.rb b/spec/ruby/core/string/unpack/w_spec.rb
index 6a1cff1965..b213b32921 100644
--- a/spec/ruby/core/string/unpack/w_spec.rb
+++ b/spec/ruby/core/string/unpack/w_spec.rb
@@ -17,9 +17,7 @@ describe "String#unpack with directive 'w'" do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- suppress_warning do
- "\x01\x02\x03".unpack("w\x00w").should == [1, 2]
- end
+ "\x01\x02\x03".unpack("w\x00w").should == [1, 2]
end
end
diff --git a/spec/ruby/core/string/unpack_spec.rb b/spec/ruby/core/string/unpack_spec.rb
index 52b4af3a95..4ff7d07460 100644
--- a/spec/ruby/core/string/unpack_spec.rb
+++ b/spec/ruby/core/string/unpack_spec.rb
@@ -31,4 +31,4 @@ describe "String#unpack" do
-> { "a".unpack("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string")
end
end
-end
+end \ No newline at end of file
diff --git a/spec/ruby/core/string/upcase_spec.rb b/spec/ruby/core/string/upcase_spec.rb
index 652de5c2ef..5ce7b0b95f 100644
--- a/spec/ruby/core/string/upcase_spec.rb
+++ b/spec/ruby/core/string/upcase_spec.rb
@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -74,8 +73,16 @@ describe "String#upcase" do
-> { "abc".upcase(:invalid_option) }.should raise_error(ArgumentError)
end
- it "returns a String instance for subclasses" do
- StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(String)
+ ruby_version_is ''...'3.0' do
+ it "returns a subclass instance for subclasses" do
+ StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(StringSpecs::MyString)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "returns a String instance for subclasses" do
+ StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(String)
+ end
end
end
diff --git a/spec/ruby/core/string/uplus_spec.rb b/spec/ruby/core/string/uplus_spec.rb
index c0b0c49ede..038b283c90 100644
--- a/spec/ruby/core/string/uplus_spec.rb
+++ b/spec/ruby/core/string/uplus_spec.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
require_relative '../../spec_helper'
describe 'String#+@' do
@@ -8,9 +7,6 @@ describe 'String#+@' do
output.should_not.frozen?
output.should == 'foo'
-
- output << 'bar'
- output.should == 'foobar'
end
it 'returns self if the String is not frozen' do
diff --git a/spec/ruby/core/string/upto_spec.rb b/spec/ruby/core/string/upto_spec.rb
index 8bc847d5ac..f8529b1d2b 100644
--- a/spec/ruby/core/string/upto_spec.rb
+++ b/spec/ruby/core/string/upto_spec.rb
@@ -80,12 +80,6 @@ describe "String#upto" do
a.should == ["Σ", "Τ", "Υ", "Φ", "Χ", "Ψ", "Ω"]
end
- it "raises Encoding::CompatibilityError when incompatible characters are given" do
- char1 = 'a'.dup.force_encoding("EUC-JP")
- char2 = 'b'.dup.force_encoding("ISO-2022-JP")
- -> { char1.upto(char2) {} }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: EUC-JP and ISO-2022-JP")
- end
-
describe "on sequence of numbers" do
it "calls the block as Integer#upto" do
"8".upto("11").to_a.should == 8.upto(11).map(&:to_s)
diff --git a/spec/ruby/core/string/valid_encoding_spec.rb b/spec/ruby/core/string/valid_encoding_spec.rb
index 375035cd94..be7cef7a8e 100644
--- a/spec/ruby/core/string/valid_encoding_spec.rb
+++ b/spec/ruby/core/string/valid_encoding_spec.rb
@@ -7,13 +7,13 @@ describe "String#valid_encoding?" do
end
it "returns true if self is valid in the current encoding and other encodings" do
- str = +"\x77"
+ str = "\x77"
str.force_encoding('utf-8').valid_encoding?.should be_true
str.force_encoding('binary').valid_encoding?.should be_true
end
it "returns true for all encodings self is valid in" do
- str = +"\xE6\x9D\x94"
+ str = "\xE6\x9D\x94"
str.force_encoding('BINARY').valid_encoding?.should be_true
str.force_encoding('UTF-8').valid_encoding?.should be_true
str.force_encoding('US-ASCII').valid_encoding?.should be_false
@@ -43,10 +43,10 @@ describe "String#valid_encoding?" do
str.force_encoding('KOI8-R').valid_encoding?.should be_true
str.force_encoding('KOI8-U').valid_encoding?.should be_true
str.force_encoding('Shift_JIS').valid_encoding?.should be_false
- "\xD8\x00".dup.force_encoding('UTF-16BE').valid_encoding?.should be_false
- "\x00\xD8".dup.force_encoding('UTF-16LE').valid_encoding?.should be_false
- "\x04\x03\x02\x01".dup.force_encoding('UTF-32BE').valid_encoding?.should be_false
- "\x01\x02\x03\x04".dup.force_encoding('UTF-32LE').valid_encoding?.should be_false
+ "\xD8\x00".force_encoding('UTF-16BE').valid_encoding?.should be_false
+ "\x00\xD8".force_encoding('UTF-16LE').valid_encoding?.should be_false
+ "\x04\x03\x02\x01".force_encoding('UTF-32BE').valid_encoding?.should be_false
+ "\x01\x02\x03\x04".force_encoding('UTF-32LE').valid_encoding?.should be_false
str.force_encoding('Windows-1251').valid_encoding?.should be_true
str.force_encoding('IBM437').valid_encoding?.should be_true
str.force_encoding('IBM737').valid_encoding?.should be_true
@@ -100,25 +100,27 @@ describe "String#valid_encoding?" do
str.force_encoding('UTF8-MAC').valid_encoding?.should be_true
end
- it "returns true for IBM720 encoding self is valid in" do
- str = +"\xE6\x9D\x94"
- str.force_encoding('IBM720').valid_encoding?.should be_true
- str.force_encoding('CP720').valid_encoding?.should be_true
+ ruby_version_is '3.0' do
+ it "returns true for IBM720 encoding self is valid in" do
+ str = "\xE6\x9D\x94"
+ str.force_encoding('IBM720').valid_encoding?.should be_true
+ str.force_encoding('CP720').valid_encoding?.should be_true
+ end
end
it "returns false if self is valid in one encoding, but invalid in the one it's tagged with" do
- str = +"\u{8765}"
+ str = "\u{8765}"
str.valid_encoding?.should be_true
- str.force_encoding('ascii')
+ str = str.force_encoding('ascii')
str.valid_encoding?.should be_false
end
it "returns false if self contains a character invalid in the associated encoding" do
- "abc#{[0x80].pack('C')}".dup.force_encoding('ascii').valid_encoding?.should be_false
+ "abc#{[0x80].pack('C')}".force_encoding('ascii').valid_encoding?.should be_false
end
it "returns false if a valid String had an invalid character appended to it" do
- str = +"a"
+ str = "a"
str.valid_encoding?.should be_true
str << [0xDD].pack('C').force_encoding('utf-8')
str.valid_encoding?.should be_false
diff --git a/spec/ruby/core/struct/constants_spec.rb b/spec/ruby/core/struct/constants_spec.rb
deleted file mode 100644
index fa61a4b912..0000000000
--- a/spec/ruby/core/struct/constants_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Struct::Group" do
- it "is no longer defined" do
- Struct.should_not.const_defined?(:Group)
- end
- end
-
- describe "Struct::Passwd" do
- it "is no longer defined" do
- Struct.should_not.const_defined?(:Passwd)
- end
- end
-end
diff --git a/spec/ruby/core/struct/deconstruct_keys_spec.rb b/spec/ruby/core/struct/deconstruct_keys_spec.rb
index b4c84c49df..088803d028 100644
--- a/spec/ruby/core/struct/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/struct/deconstruct_keys_spec.rb
@@ -64,7 +64,7 @@ describe "Struct#deconstruct_keys" do
obj.deconstruct_keys(nil).should == {x: 1, y: 2}
end
- it "raise TypeError if passed anything except nil or array" do
+ it "raise TypeError if passed anything accept nil or array" do
struct = Struct.new(:x, :y)
s = struct.new(1, 2)
diff --git a/spec/ruby/core/struct/fixtures/classes.rb b/spec/ruby/core/struct/fixtures/classes.rb
index bf838d05df..6d620f9060 100644
--- a/spec/ruby/core/struct/fixtures/classes.rb
+++ b/spec/ruby/core/struct/fixtures/classes.rb
@@ -13,12 +13,6 @@ module StructClasses
end
end
- class StructWithOverriddenName < Struct.new(:a)
- def self.name
- "A"
- end
- end
-
class SubclassX < Struct
end
diff --git a/spec/ruby/core/struct/initialize_spec.rb b/spec/ruby/core/struct/initialize_spec.rb
index a5ebe9551c..cfb302209e 100644
--- a/spec/ruby/core/struct/initialize_spec.rb
+++ b/spec/ruby/core/struct/initialize_spec.rb
@@ -48,14 +48,4 @@ describe "Struct#initialize" do
}.should complain(/warning: Passing only keyword arguments/)
end
end
-
- ruby_version_is "3.2" do
- it "can be initialized with keyword arguments" do
- positional_args = StructClasses::Ruby.new("3.2", "OS")
- keyword_args = StructClasses::Ruby.new(version: "3.2", platform: "OS")
-
- positional_args.version.should == keyword_args.version
- positional_args.platform.should == keyword_args.platform
- end
- end
end
diff --git a/spec/ruby/core/struct/inspect_spec.rb b/spec/ruby/core/struct/inspect_spec.rb
index 657b06abc1..83e13597ba 100644
--- a/spec/ruby/core/struct/inspect_spec.rb
+++ b/spec/ruby/core/struct/inspect_spec.rb
@@ -3,5 +3,10 @@ require_relative 'fixtures/classes'
require_relative 'shared/inspect'
describe "Struct#inspect" do
+ it "returns a string representation showing members and values" do
+ car = StructClasses::Car.new('Ford', 'Ranger')
+ car.inspect.should == '#<struct StructClasses::Car make="Ford", model="Ranger", year=nil>'
+ end
+
it_behaves_like :struct_inspect, :inspect
end
diff --git a/spec/ruby/core/struct/keyword_init_spec.rb b/spec/ruby/core/struct/keyword_init_spec.rb
index 8de4c14351..061f4c56e0 100644
--- a/spec/ruby/core/struct/keyword_init_spec.rb
+++ b/spec/ruby/core/struct/keyword_init_spec.rb
@@ -17,24 +17,5 @@ ruby_version_is "3.1" do
struct = Struct.new(:arg)
struct.keyword_init?.should be_nil
end
-
- it "returns nil for a struct that does specify keyword_init to be nil" do
- struct = Struct.new(:arg, keyword_init: nil)
- struct.keyword_init?.should be_nil
- end
-
- it "returns true for any truthy value, not just for true" do
- struct = Struct.new(:arg, keyword_init: 1)
- struct.keyword_init?.should be_true
-
- struct = Struct.new(:arg, keyword_init: "")
- struct.keyword_init?.should be_true
-
- struct = Struct.new(:arg, keyword_init: [])
- struct.keyword_init?.should be_true
-
- struct = Struct.new(:arg, keyword_init: {})
- struct.keyword_init?.should be_true
- end
end
end
diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb
index a94eb852e1..7b4a4f7980 100644
--- a/spec/ruby/core/struct/new_spec.rb
+++ b/spec/ruby/core/struct/new_spec.rb
@@ -47,11 +47,6 @@ describe "Struct.new" do
Struct.const_defined?("Animal2").should be_false
end
- it "allows non-ASCII member name" do
- name = "r\xe9sum\xe9".dup.force_encoding(Encoding::ISO_8859_1).to_sym
- struct = Struct.new(name)
- struct.new("foo").send(name).should == "foo"
- end
it "fails with invalid constant name as first argument" do
-> { Struct.new('animal', :name, :legs, :eyeballs) }.should raise_error(NameError)
@@ -83,20 +78,6 @@ describe "Struct.new" do
end
end
- ruby_version_is ""..."3.3" do
- it "raises ArgumentError if not provided any arguments" do
- -> { Struct.new }.should raise_error(ArgumentError)
- end
- end
-
- ruby_version_is "3.3" do
- it "works when not provided any arguments" do
- c = Struct.new
- c.should be_kind_of(Class)
- c.superclass.should == Struct
- end
- end
-
it "raises ArgumentError when there is a duplicate member" do
-> { Struct.new(:foo, :foo) }.should raise_error(ArgumentError, "duplicate member: foo")
end
diff --git a/spec/ruby/core/struct/shared/inspect.rb b/spec/ruby/core/struct/shared/inspect.rb
index 1a0fb6a6b2..90594a5452 100644
--- a/spec/ruby/core/struct/shared/inspect.rb
+++ b/spec/ruby/core/struct/shared/inspect.rb
@@ -1,40 +1,5 @@
describe :struct_inspect, shared: true do
- it "returns a string representation showing members and values" do
- car = StructClasses::Car.new('Ford', 'Ranger')
- car.send(@method).should == '#<struct StructClasses::Car make="Ford", model="Ranger", year=nil>'
- end
-
it "returns a string representation without the class name for anonymous structs" do
Struct.new(:a).new("").send(@method).should == '#<struct a="">'
end
-
- it "returns a string representation without the class name for structs nested in anonymous classes" do
- c = Class.new
- c.class_eval <<~DOC
- class Foo < Struct.new(:a); end
- DOC
-
- c::Foo.new("").send(@method).should == '#<struct a="">'
- end
-
- it "returns a string representation without the class name for structs nested in anonymous modules" do
- m = Module.new
- m.module_eval <<~DOC
- class Foo < Struct.new(:a); end
- DOC
-
- m::Foo.new("").send(@method).should == '#<struct a="">'
- end
-
- it "does not call #name method" do
- struct = StructClasses::StructWithOverriddenName.new("")
- struct.send(@method).should == '#<struct StructClasses::StructWithOverriddenName a="">'
- end
-
- it "does not call #name method when struct is anonymous" do
- struct = Struct.new(:a)
- def struct.name; "A"; end
-
- struct.new("").send(@method).should == '#<struct a="">'
- end
end
diff --git a/spec/ruby/core/struct/to_h_spec.rb b/spec/ruby/core/struct/to_h_spec.rb
index 861ce3f49d..bfb0af07ba 100644
--- a/spec/ruby/core/struct/to_h_spec.rb
+++ b/spec/ruby/core/struct/to_h_spec.rb
@@ -21,18 +21,6 @@ describe "Struct#to_h" do
h.should == { "make" => "ford", "model" => "ranger", "year" => "" }
end
- it "passes to a block each pair's key and value as separate arguments" do
- s = StructClasses::Ruby.new('3.2.4', 'macos')
-
- ScratchPad.record []
- s.to_h { |k, v| ScratchPad << [k, v]; [k, v] }
- ScratchPad.recorded.sort.should == [[:platform, 'macos'], [:version, '3.2.4']]
-
- ScratchPad.record []
- s.to_h { |*args| ScratchPad << args; [args[0], args[1]] }
- ScratchPad.recorded.sort.should == [[:platform, 'macos'], [:version, '3.2.4']]
- end
-
it "raises ArgumentError if block returns longer or shorter array" do
-> do
StructClasses::Car.new.to_h { |k, v| [k.to_s, "#{v}".downcase, 1] }
diff --git a/spec/ruby/core/symbol/casecmp_spec.rb b/spec/ruby/core/symbol/casecmp_spec.rb
index 662a29a284..80ea51e910 100644
--- a/spec/ruby/core/symbol/casecmp_spec.rb
+++ b/spec/ruby/core/symbol/casecmp_spec.rb
@@ -56,10 +56,6 @@ describe "Symbol#casecmp with Symbol" do
lower_a_tilde.casecmp(upper_a_tilde).should == 1
lower_a_umlaut.casecmp(upper_a_umlaut).should == 1
end
-
- it "returns 0 for empty strings in different encodings" do
- ''.to_sym.casecmp(''.encode("UTF-32LE").to_sym).should == 0
- end
end
describe "Symbol#casecmp" do
@@ -145,8 +141,4 @@ describe 'Symbol#casecmp?' do
upper_a_tilde.casecmp?(lower_a_tilde).should == nil
lower_a_tilde.casecmp?(upper_a_tilde).should == nil
end
-
- it "returns true for empty symbols in different encodings" do
- ''.to_sym.should.casecmp?(''.encode("UTF-32LE").to_sym)
- end
end
diff --git a/spec/ruby/core/symbol/inspect_spec.rb b/spec/ruby/core/symbol/inspect_spec.rb
index 6dbb36c2ad..58402ab261 100644
--- a/spec/ruby/core/symbol/inspect_spec.rb
+++ b/spec/ruby/core/symbol/inspect_spec.rb
@@ -5,8 +5,6 @@ describe "Symbol#inspect" do
fred: ":fred",
:fred? => ":fred?",
:fred! => ":fred!",
- :BAD! => ":BAD!",
- :_BAD! => ":_BAD!",
:$ruby => ":$ruby",
:@ruby => ":@ruby",
:@@ruby => ":@@ruby",
diff --git a/spec/ruby/core/symbol/name_spec.rb b/spec/ruby/core/symbol/name_spec.rb
index f9b631266c..15b9aa75e9 100644
--- a/spec/ruby/core/symbol/name_spec.rb
+++ b/spec/ruby/core/symbol/name_spec.rb
@@ -1,17 +1,19 @@
require_relative '../../spec_helper'
-describe "Symbol#name" do
- it "returns string" do
- :ruby.name.should == "ruby"
- :ルビー.name.should == "ルビー"
- end
+ruby_version_is "3.0" do
+ describe "Symbol#name" do
+ it "returns string" do
+ :ruby.name.should == "ruby"
+ :ルビー.name.should == "ルビー"
+ end
- it "returns same string instance" do
- :"ruby_3".name.should.equal?(:ruby_3.name)
- :"ruby_#{1+2}".name.should.equal?(:ruby_3.name)
- end
+ it "returns same string instance" do
+ :"ruby_3".name.should.equal?(:ruby_3.name)
+ :"ruby_#{1+2}".name.should.equal?(:ruby_3.name)
+ end
- it "returns frozen string" do
- :symbol.name.should.frozen?
+ it "returns frozen string" do
+ :symbol.name.should.frozen?
+ end
end
end
diff --git a/spec/ruby/core/symbol/to_proc_spec.rb b/spec/ruby/core/symbol/to_proc_spec.rb
index 54eccdba11..6d9c4bc622 100644
--- a/spec/ruby/core/symbol/to_proc_spec.rb
+++ b/spec/ruby/core/symbol/to_proc_spec.rb
@@ -12,19 +12,38 @@ describe "Symbol#to_proc" do
:to_s.to_proc.call(obj).should == "Received #to_s"
end
- it "returns a Proc with #lambda? true" do
- pr = :to_s.to_proc
- pr.should.lambda?
- end
+ ruby_version_is ""..."3.0" do
+ it "returns a Proc with #lambda? false" do
+ pr = :to_s.to_proc
+ pr.should_not.lambda?
+ end
- it "produces a Proc with arity -2" do
- pr = :to_s.to_proc
- pr.arity.should == -2
+ it "produces a Proc with arity -1" do
+ pr = :to_s.to_proc
+ pr.arity.should == -1
+ end
+
+ it "produces a Proc that always returns [[:rest]] for #parameters" do
+ pr = :to_s.to_proc
+ pr.parameters.should == [[:rest]]
+ end
end
- it "produces a Proc that always returns [[:req], [:rest]] for #parameters" do
- pr = :to_s.to_proc
- pr.parameters.should == [[:req], [:rest]]
+ ruby_version_is "3.0" do
+ it "returns a Proc with #lambda? true" do
+ pr = :to_s.to_proc
+ pr.should.lambda?
+ end
+
+ it "produces a Proc with arity -2" do
+ pr = :to_s.to_proc
+ pr.arity.should == -2
+ end
+
+ it "produces a Proc that always returns [[:req], [:rest]] for #parameters" do
+ pr = :to_s.to_proc
+ pr.parameters.should == [[:req], [:rest]]
+ end
end
ruby_version_is "3.2" do
@@ -39,8 +58,8 @@ describe "Symbol#to_proc" do
@a = []
singleton_class.class_eval(&body)
tap(&:pub)
- proc{tap(&:pro)}.should raise_error(NoMethodError, /protected method [`']pro' called/)
- proc{tap(&:pri)}.should raise_error(NoMethodError, /private method [`']pri' called/)
+ proc{tap(&:pro)}.should raise_error(NoMethodError, /protected method `pro' called/)
+ proc{tap(&:pri)}.should raise_error(NoMethodError, /private method `pri' called/)
@a.should == [:pub]
@a = []
@@ -48,8 +67,8 @@ describe "Symbol#to_proc" do
o = c.new
o.instance_variable_set(:@a, [])
o.tap(&:pub)
- proc{tap(&:pro)}.should raise_error(NoMethodError, /protected method [`']pro' called/)
- proc{o.tap(&:pri)}.should raise_error(NoMethodError, /private method [`']pri' called/)
+ proc{tap(&:pro)}.should raise_error(NoMethodError, /protected method `pro' called/)
+ proc{o.tap(&:pri)}.should raise_error(NoMethodError, /private method `pri' called/)
o.a.should == [:pub]
end
end
diff --git a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
index 6e381e4868..e35e1fc0b4 100644
--- a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
@@ -59,7 +59,7 @@ describe 'Thread::Backtrace::Location#absolute_path' do
it "returns nil" do
location = nil
tap { location = caller_locations(1, 1)[0] }
- location.label.should =~ /\A(?:Kernel#)?tap\z/
+ location.label.should == "tap"
if location.path.start_with?("<internal:")
location.absolute_path.should == nil
else
diff --git a/spec/ruby/core/thread/backtrace/location/label_spec.rb b/spec/ruby/core/thread/backtrace/location/label_spec.rb
index 85ddccc8e3..7312d017e5 100644
--- a/spec/ruby/core/thread/backtrace/location/label_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/label_spec.rb
@@ -7,11 +7,11 @@ describe 'Thread::Backtrace::Location#label' do
end
it 'returns the method name for a method location' do
- ThreadBacktraceLocationSpecs.method_location[0].label.should =~ /\A(?:ThreadBacktraceLocationSpecs\.)?method_location\z/
+ ThreadBacktraceLocationSpecs.method_location[0].label.should == "method_location"
end
it 'returns the block name for a block location' do
- ThreadBacktraceLocationSpecs.block_location[0].label.should =~ /\Ablock in (?:ThreadBacktraceLocationSpecs\.)?block_location\z/
+ ThreadBacktraceLocationSpecs.block_location[0].label.should == "block in block_location"
end
it 'returns the module name for a module location' do
@@ -22,9 +22,9 @@ describe 'Thread::Backtrace::Location#label' do
first_level_location, second_level_location, third_level_location =
ThreadBacktraceLocationSpecs.locations_inside_nested_blocks
- first_level_location.label.should =~ /\Ablock in (?:ThreadBacktraceLocationSpecs\.)?locations_inside_nested_blocks\z/
- second_level_location.label.should =~ /\Ablock \(2 levels\) in (?:ThreadBacktraceLocationSpecs\.)?locations_inside_nested_blocks\z/
- third_level_location.label.should =~ /\Ablock \(3 levels\) in (?:ThreadBacktraceLocationSpecs\.)?locations_inside_nested_blocks\z/
+ first_level_location.label.should == 'block in locations_inside_nested_blocks'
+ second_level_location.label.should == 'block (2 levels) in locations_inside_nested_blocks'
+ third_level_location.label.should == 'block (3 levels) in locations_inside_nested_blocks'
end
it 'sets the location label for a top-level block differently depending on it being in the main file or a required file' do
diff --git a/spec/ruby/core/thread/backtrace/location/lineno_spec.rb b/spec/ruby/core/thread/backtrace/location/lineno_spec.rb
index 10457f80f0..d14cf17514 100644
--- a/spec/ruby/core/thread/backtrace/location/lineno_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/lineno_spec.rb
@@ -7,7 +7,7 @@ describe 'Thread::Backtrace::Location#lineno' do
@line = __LINE__ - 1
end
- it 'returns the line number of the call frame' do
+ it 'returns the absolute path of the call frame' do
@frame.lineno.should == @line
end
diff --git a/spec/ruby/core/thread/backtrace/location/path_spec.rb b/spec/ruby/core/thread/backtrace/location/path_spec.rb
index 75f76833a9..7863c055d3 100644
--- a/spec/ruby/core/thread/backtrace/location/path_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/path_spec.rb
@@ -41,7 +41,7 @@ describe 'Thread::Backtrace::Location#path' do
context 'when using a relative script path' do
it 'returns a path relative to the working directory' do
path = 'fixtures/main.rb'
- directory = __dir__
+ directory = File.dirname(__FILE__)
Dir.chdir(directory) {
ruby_exe(path)
}.should == path
diff --git a/spec/ruby/core/thread/backtrace_locations_spec.rb b/spec/ruby/core/thread/backtrace_locations_spec.rb
index 09fe622e0d..c970ae023b 100644
--- a/spec/ruby/core/thread/backtrace_locations_spec.rb
+++ b/spec/ruby/core/thread/backtrace_locations_spec.rb
@@ -70,7 +70,7 @@ describe "Thread#backtrace_locations" do
end
it "the first location reports the call to #backtrace_locations" do
- Thread.current.backtrace_locations(0..0)[0].to_s.should =~ /\A#{__FILE__ }:#{__LINE__ }:in [`'](?:Thread#)?backtrace_locations'\z/
+ Thread.current.backtrace_locations(0..0)[0].to_s.should == "#{__FILE__ }:#{__LINE__ }:in `backtrace_locations'"
end
it "[1..-1] is the same as #caller_locations(0..-1) for Thread.current" do
diff --git a/spec/ruby/core/thread/backtrace_spec.rb b/spec/ruby/core/thread/backtrace_spec.rb
index 15bb29a349..9001b1b7eb 100644
--- a/spec/ruby/core/thread/backtrace_spec.rb
+++ b/spec/ruby/core/thread/backtrace_spec.rb
@@ -13,7 +13,7 @@ describe "Thread#backtrace" do
backtrace = t.backtrace
backtrace.should be_kind_of(Array)
- backtrace.first.should =~ /[`'](?:Kernel#)?sleep'/
+ backtrace.first.should =~ /`sleep'/
t.raise 'finish the thread'
t.join
diff --git a/spec/ruby/core/thread/each_caller_location_spec.rb b/spec/ruby/core/thread/each_caller_location_spec.rb
deleted file mode 100644
index 29c271789b..0000000000
--- a/spec/ruby/core/thread/each_caller_location_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "Thread.each_caller_location" do
- ruby_version_is "3.2" do
- it "iterates through the current execution stack and matches caller_locations content and type" do
- ScratchPad.record []
- Thread.each_caller_location { |l| ScratchPad << l; }
-
- ScratchPad.recorded.map(&:to_s).should == caller_locations.map(&:to_s)
- ScratchPad.recorded[0].should be_kind_of(Thread::Backtrace::Location)
- end
-
- it "returns subset of 'Thread.to_enum(:each_caller_location)' locations" do
- ar = []
- ecl = Thread.each_caller_location { |x| ar << x }
-
- (ar.map(&:to_s) - Thread.to_enum(:each_caller_location).to_a.map(&:to_s)).should.empty?
- end
-
- it "stops the backtrace iteration if 'break' occurs" do
- i = 0
- ar = []
- ecl = Thread.each_caller_location do |x|
- ar << x
- i += 1
- break x if i == 2
- end
-
- ar.map(&:to_s).should == caller_locations(1, 2).map(&:to_s)
- ecl.should be_kind_of(Thread::Backtrace::Location)
- end
-
- it "returns nil" do
- Thread.each_caller_location {}.should == nil
- end
-
- it "raises LocalJumpError when called without a block" do
- -> {
- Thread.each_caller_location
- }.should raise_error(LocalJumpError, "no block given")
- end
-
- it "doesn't accept keyword arguments" do
- -> {
- Thread.each_caller_location(12, foo: 10) {}
- }.should raise_error(ArgumentError);
- end
- end
-end
diff --git a/spec/ruby/core/thread/exclusive_spec.rb b/spec/ruby/core/thread/exclusive_spec.rb
new file mode 100644
index 0000000000..37c4b19d1a
--- /dev/null
+++ b/spec/ruby/core/thread/exclusive_spec.rb
@@ -0,0 +1,49 @@
+require_relative '../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ describe "Thread.exclusive" do
+ before :each do
+ ScratchPad.clear
+ $VERBOSE, @verbose = nil, $VERBOSE
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it "yields to the block" do
+ Thread.exclusive { ScratchPad.record true }
+ ScratchPad.recorded.should == true
+ end
+
+ it "returns the result of yielding" do
+ Thread.exclusive { :result }.should == :result
+ end
+
+ it "blocks the caller if another thread is also in an exclusive block" do
+ m = Mutex.new
+ q1 = Queue.new
+ q2 = Queue.new
+
+ t = Thread.new {
+ Thread.exclusive {
+ q1.push :ready
+ q2.pop
+ }
+ }
+
+ q1.pop.should == :ready
+
+ -> { Thread.exclusive { } }.should block_caller
+
+ q2.push :done
+ t.join
+ end
+
+ it "is not recursive" do
+ Thread.exclusive do
+ -> { Thread.exclusive { } }.should raise_error(ThreadError)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/thread/fetch_spec.rb b/spec/ruby/core/thread/fetch_spec.rb
index 85ffb71874..6b37d4cfc5 100644
--- a/spec/ruby/core/thread/fetch_spec.rb
+++ b/spec/ruby/core/thread/fetch_spec.rb
@@ -29,36 +29,6 @@ describe 'Thread#fetch' do
end
end
- describe 'with a block' do
- it 'returns the value of the fiber-local variable if value has been assigned' do
- th = Thread.new { Thread.current[:cat] = 'meow' }
- th.join
- th.fetch(:cat) { true }.should == 'meow'
- end
-
- it "returns the block value if fiber-local variable hasn't been assigned" do
- th = Thread.new {}
- th.join
- th.fetch(:cat) { true }.should == true
- end
-
- it "does not call the block if value has been assigned" do
- th = Thread.new { Thread.current[:cat] = 'meow' }
- th.join
- var = :not_updated
- th.fetch(:cat) { var = :updated }.should == 'meow'
- var.should == :not_updated
- end
-
- it "uses the block if a default is given and warns about it" do
- th = Thread.new {}
- th.join
- -> {
- th.fetch(:cat, false) { true }.should == true
- }.should complain(/warning: block supersedes default value argument/)
- end
- end
-
it 'raises an ArgumentError when not passed one or two arguments' do
-> { Thread.current.fetch() }.should raise_error(ArgumentError)
-> { Thread.current.fetch(1, 2, 3) }.should raise_error(ArgumentError)
diff --git a/spec/ruby/core/thread/ignore_deadlock_spec.rb b/spec/ruby/core/thread/ignore_deadlock_spec.rb
index b48bc9f9b0..53cc2a7f5b 100644
--- a/spec/ruby/core/thread/ignore_deadlock_spec.rb
+++ b/spec/ruby/core/thread/ignore_deadlock_spec.rb
@@ -1,19 +1,21 @@
require_relative '../../spec_helper'
-describe "Thread.ignore_deadlock" do
- it "returns false by default" do
- Thread.ignore_deadlock.should == false
+ruby_version_is "3.0" do
+ describe "Thread.ignore_deadlock" do
+ it "returns false by default" do
+ Thread.ignore_deadlock.should == false
+ end
end
-end
-describe "Thread.ignore_deadlock=" do
- it "changes the value of Thread.ignore_deadlock" do
- ignore_deadlock = Thread.ignore_deadlock
- Thread.ignore_deadlock = true
- begin
- Thread.ignore_deadlock.should == true
- ensure
- Thread.ignore_deadlock = ignore_deadlock
+ describe "Thread.ignore_deadlock=" do
+ it "changes the value of Thread.ignore_deadlock" do
+ ignore_deadlock = Thread.ignore_deadlock
+ Thread.ignore_deadlock = true
+ begin
+ Thread.ignore_deadlock.should == true
+ ensure
+ Thread.ignore_deadlock = ignore_deadlock
+ end
end
end
end
diff --git a/spec/ruby/core/thread/kill_spec.rb b/spec/ruby/core/thread/kill_spec.rb
index 4b62c686c7..f932bf5232 100644
--- a/spec/ruby/core/thread/kill_spec.rb
+++ b/spec/ruby/core/thread/kill_spec.rb
@@ -9,6 +9,10 @@ platform_is_not :mingw do
it_behaves_like :thread_exit, :kill
end
+ describe "Thread#kill!" do
+ it "needs to be reviewed for spec completeness"
+ end
+
describe "Thread.kill" do
it "causes the given thread to exit" do
thread = Thread.new { sleep }
diff --git a/spec/ruby/core/thread/native_thread_id_spec.rb b/spec/ruby/core/thread/native_thread_id_spec.rb
index 17a08c8a15..d6cc332bf6 100644
--- a/spec/ruby/core/thread/native_thread_id_spec.rb
+++ b/spec/ruby/core/thread/native_thread_id_spec.rb
@@ -1,37 +1,17 @@
require_relative '../../spec_helper'
-ruby_version_is "3.1" do
- platform_is :linux, :darwin, :windows, :freebsd do
- describe "Thread#native_thread_id" do
- it "returns an integer when the thread is alive" do
- Thread.current.native_thread_id.should be_kind_of(Integer)
- end
+if ruby_version_is "3.1" and Thread.method_defined?(:native_thread_id)
+ # This method is very platform specific
- it "returns nil when the thread is not running" do
- t = Thread.new {}
- t.join
- t.native_thread_id.should == nil
- end
-
- it "each thread has different native thread id" do
- t = Thread.new { sleep }
- Thread.pass until t.stop?
- main_thread_id = Thread.current.native_thread_id
- t_thread_id = t.native_thread_id
-
- if ruby_version_is "3.3"
- # native_thread_id can be nil on a M:N scheduler
- t_thread_id.should be_kind_of(Integer) if t_thread_id != nil
- else
- t_thread_id.should be_kind_of(Integer)
- end
-
- main_thread_id.should_not == t_thread_id
+ describe "Thread#native_thread_id" do
+ it "returns an integer when the thread is alive" do
+ Thread.current.native_thread_id.should be_kind_of(Integer)
+ end
- t.run
- t.join
- t.native_thread_id.should == nil
- end
+ it "returns nil when the thread is not running" do
+ t = Thread.new {}
+ t.join
+ t.native_thread_id.should == nil
end
end
end
diff --git a/spec/ruby/core/thread/report_on_exception_spec.rb b/spec/ruby/core/thread/report_on_exception_spec.rb
index d9daa041cd..9279fa1da5 100644
--- a/spec/ruby/core/thread/report_on_exception_spec.rb
+++ b/spec/ruby/core/thread/report_on_exception_spec.rb
@@ -61,32 +61,34 @@ describe "Thread#report_on_exception=" do
}.should raise_error(RuntimeError, "Thread#report_on_exception specs")
end
- it "prints a backtrace on $stderr in the regular backtrace order" do
- line_raise = __LINE__ + 2
- def foo
- raise RuntimeError, "Thread#report_on_exception specs backtrace order"
- end
-
- line_call_foo = __LINE__ + 5
- go = false
- t = Thread.new {
- Thread.current.report_on_exception = true
- Thread.pass until go
- foo
- }
+ ruby_version_is "3.0" do
+ it "prints a backtrace on $stderr in the regular backtrace order" do
+ line_raise = __LINE__ + 2
+ def foo
+ raise RuntimeError, "Thread#report_on_exception specs backtrace order"
+ end
+
+ line_call_foo = __LINE__ + 5
+ go = false
+ t = Thread.new {
+ Thread.current.report_on_exception = true
+ Thread.pass until go
+ foo
+ }
- -> {
- go = true
- Thread.pass while t.alive?
- }.should output("", /\A
-#{Regexp.quote(t.inspect)}\sterminated\swith\sexception\s\(report_on_exception\sis\strue\):\n
-#{Regexp.quote(__FILE__)}:#{line_raise}:in\s[`']foo':\sThread\#report_on_exception\sspecs\sbacktrace\sorder\s\(RuntimeError\)\n
-\tfrom\s#{Regexp.quote(__FILE__)}:#{line_call_foo}:in\s[`']block\s\(4\slevels\)\sin\s<top\s\(required\)>'\n
-\z/x)
+ -> {
+ go = true
+ Thread.pass while t.alive?
+ }.should output("", <<ERR)
+#{t.inspect} terminated with exception (report_on_exception is true):
+#{__FILE__}:#{line_raise}:in `foo': Thread#report_on_exception specs backtrace order (RuntimeError)
+\tfrom #{__FILE__}:#{line_call_foo}:in `block (5 levels) in <top (required)>'
+ERR
- -> {
- t.join
- }.should raise_error(RuntimeError, "Thread#report_on_exception specs backtrace order")
+ -> {
+ t.join
+ }.should raise_error(RuntimeError, "Thread#report_on_exception specs backtrace order")
+ end
end
it "prints the backtrace even if the thread was killed just after Thread#raise" do
diff --git a/spec/ruby/core/thread/shared/exit.rb b/spec/ruby/core/thread/shared/exit.rb
index 13e8832684..3663827579 100644
--- a/spec/ruby/core/thread/shared/exit.rb
+++ b/spec/ruby/core/thread/shared/exit.rb
@@ -113,25 +113,6 @@ describe :thread_exit, shared: true do
ScratchPad.recorded.should == nil
end
- it "kills other fibers of that thread without running their ensure clauses" do
- t = Thread.new do
- f = Fiber.new do
- ScratchPad.record :fiber_resumed
- begin
- Fiber.yield
- ensure
- ScratchPad.record :fiber_ensure
- end
- end
- f.resume
- sleep
- end
- Thread.pass until t.stop?
- t.send(@method)
- t.join
- ScratchPad.recorded.should == :fiber_resumed
- end
-
# This spec is a mess. It fails randomly, it hangs on MRI, it needs to be removed
quarantine! do
it "killing dying running does nothing" do
diff --git a/spec/ruby/core/thread/thread_variable_get_spec.rb b/spec/ruby/core/thread/thread_variable_get_spec.rb
index 1ea34cf2b3..38f90d5830 100644
--- a/spec/ruby/core/thread/thread_variable_get_spec.rb
+++ b/spec/ruby/core/thread/thread_variable_get_spec.rb
@@ -13,48 +13,13 @@ describe "Thread#thread_variable_get" do
@t.thread_variable_get(:a).should be_nil
end
- it "returns the value previously set by #thread_variable_set" do
- @t.thread_variable_set(:a, 49)
+ it "returns the value previously set by #[]=" do
+ @t.thread_variable_set :a, 49
@t.thread_variable_get(:a).should == 49
end
it "returns a value private to self" do
- @t.thread_variable_set(:thread_variable_get_spec, 82)
+ @t.thread_variable_set :thread_variable_get_spec, 82
Thread.current.thread_variable_get(:thread_variable_get_spec).should be_nil
end
-
- it "accepts String and Symbol keys interchangeably" do
- @t.thread_variable_set("a", 49)
- @t.thread_variable_get("a").should == 49
- @t.thread_variable_get(:a).should == 49
- end
-
- it "converts a key that is neither String nor Symbol with #to_str" do
- key = mock('key')
- key.should_receive(:to_str).and_return('a')
- @t.thread_variable_set(:a, 49)
- @t.thread_variable_get(key).should == 49
- end
-
- it "does not raise FrozenError if the thread is frozen" do
- @t.freeze
- @t.thread_variable_get(:a).should be_nil
- end
-
- it "raises a TypeError if the key is neither Symbol nor String when thread variables are already set" do
- @t.thread_variable_set(:a, 49)
- -> { @t.thread_variable_get(123) }.should raise_error(TypeError, /123 is not a symbol/)
- end
-
- ruby_version_is '3.4' do
- it "raises a TypeError if the key is neither Symbol nor String when no thread variables are set" do
- -> { @t.thread_variable_get(123) }.should raise_error(TypeError, /123 is not a symbol/)
- end
-
- it "raises a TypeError if the key is neither Symbol nor String without calling #to_sym" do
- key = mock('key')
- key.should_not_receive(:to_sym)
- -> { @t.thread_variable_get(key) }.should raise_error(TypeError, /#{Regexp.escape(key.inspect)} is not a symbol/)
- end
- end
end
diff --git a/spec/ruby/core/thread/thread_variable_set_spec.rb b/spec/ruby/core/thread/thread_variable_set_spec.rb
index eadee76afb..1338c306c7 100644
--- a/spec/ruby/core/thread/thread_variable_set_spec.rb
+++ b/spec/ruby/core/thread/thread_variable_set_spec.rb
@@ -10,53 +10,17 @@ describe "Thread#thread_variable_set" do
end
it "returns the value set" do
- @t.thread_variable_set(:a, 2).should == 2
+ (@t.thread_variable_set :a, 2).should == 2
end
it "sets a value that will be returned by #thread_variable_get" do
- @t.thread_variable_set(:a, 49)
+ @t.thread_variable_set :a, 49
@t.thread_variable_get(:a).should == 49
end
it "sets a value private to self" do
- @t.thread_variable_set(:thread_variable_get_spec, 82)
+ @t.thread_variable_set :thread_variable_get_spec, 82
@t.thread_variable_get(:thread_variable_get_spec).should == 82
Thread.current.thread_variable_get(:thread_variable_get_spec).should be_nil
end
-
- it "accepts String and Symbol keys interchangeably" do
- @t.thread_variable_set('a', 49)
- @t.thread_variable_get('a').should == 49
-
- @t.thread_variable_set(:a, 50)
- @t.thread_variable_get('a').should == 50
- end
-
- it "converts a key that is neither String nor Symbol with #to_str" do
- key = mock('key')
- key.should_receive(:to_str).and_return('a')
- @t.thread_variable_set(key, 49)
- @t.thread_variable_get(:a).should == 49
- end
-
- it "removes a key if the value is nil" do
- @t.thread_variable_set(:a, 52)
- @t.thread_variable_set(:a, nil)
- @t.thread_variable?(:a).should be_false
- end
-
- it "raises a FrozenError if the thread is frozen" do
- @t.freeze
- -> { @t.thread_variable_set(:a, 1) }.should raise_error(FrozenError, "can't modify frozen thread locals")
- end
-
- it "raises a TypeError if the key is neither Symbol nor String, nor responds to #to_str" do
- -> { @t.thread_variable_set(123, 1) }.should raise_error(TypeError, /123 is not a symbol/)
- end
-
- it "does not try to convert the key with #to_sym" do
- key = mock('key')
- key.should_not_receive(:to_sym)
- -> { @t.thread_variable_set(key, 42) }.should raise_error(TypeError, /#{Regexp.quote(key.inspect)} is not a symbol/)
- end
end
diff --git a/spec/ruby/core/thread/thread_variable_spec.rb b/spec/ruby/core/thread/thread_variable_spec.rb
index 1b021e9404..6bd1950c04 100644
--- a/spec/ruby/core/thread/thread_variable_spec.rb
+++ b/spec/ruby/core/thread/thread_variable_spec.rb
@@ -10,51 +10,12 @@ describe "Thread#thread_variable?" do
end
it "returns false if the thread variables do not contain 'key'" do
- @t.thread_variable_set(:a, 2)
+ @t.thread_variable_set :a, 2
@t.thread_variable?(:b).should be_false
end
it "returns true if the thread variables contain 'key'" do
- @t.thread_variable_set(:a, 2)
+ @t.thread_variable_set :a, 2
@t.thread_variable?(:a).should be_true
end
-
- it "accepts String and Symbol keys interchangeably" do
- @t.thread_variable?('a').should be_false
- @t.thread_variable?(:a).should be_false
-
- @t.thread_variable_set(:a, 49)
-
- @t.thread_variable?('a').should be_true
- @t.thread_variable?(:a).should be_true
- end
-
- it "converts a key that is neither String nor Symbol with #to_str" do
- key = mock('key')
- key.should_receive(:to_str).and_return('a')
- @t.thread_variable_set(:a, 49)
- @t.thread_variable?(key).should be_true
- end
-
- it "does not raise FrozenError if the thread is frozen" do
- @t.freeze
- @t.thread_variable?(:a).should be_false
- end
-
- it "raises a TypeError if the key is neither Symbol nor String when thread variables are already set" do
- @t.thread_variable_set(:a, 49)
- -> { @t.thread_variable?(123) }.should raise_error(TypeError, /123 is not a symbol/)
- end
-
- ruby_version_is '3.4' do
- it "raises a TypeError if the key is neither Symbol nor String when no thread variables are set" do
- -> { @t.thread_variable?(123) }.should raise_error(TypeError, /123 is not a symbol/)
- end
-
- it "raises a TypeError if the key is neither Symbol nor String without calling #to_sym" do
- key = mock('key')
- key.should_not_receive(:to_sym)
- -> { @t.thread_variable?(key) }.should raise_error(TypeError, /#{Regexp.escape(key.inspect)} is not a symbol/)
- end
- end
end
diff --git a/spec/ruby/core/thread/thread_variables_spec.rb b/spec/ruby/core/thread/thread_variables_spec.rb
index 51ceef3376..1bd68b17f1 100644
--- a/spec/ruby/core/thread/thread_variables_spec.rb
+++ b/spec/ruby/core/thread/thread_variables_spec.rb
@@ -10,15 +10,15 @@ describe "Thread#thread_variables" do
end
it "returns the keys of all the values set" do
- @t.thread_variable_set(:a, 2)
- @t.thread_variable_set(:b, 4)
- @t.thread_variable_set(:c, 6)
+ @t.thread_variable_set :a, 2
+ @t.thread_variable_set :b, 4
+ @t.thread_variable_set :c, 6
@t.thread_variables.sort.should == [:a, :b, :c]
end
- it "returns the keys private to self" do
- @t.thread_variable_set(:a, 82)
- @t.thread_variable_set(:b, 82)
+ it "sets a value private to self" do
+ @t.thread_variable_set :a, 82
+ @t.thread_variable_set :b, 82
Thread.current.thread_variables.should_not include(:a, :b)
end
@@ -26,14 +26,4 @@ describe "Thread#thread_variables" do
Thread.current.thread_variables.should == []
@t.thread_variables.should == []
end
-
- it "returns keys as Symbols" do
- key = mock('key')
- key.should_receive(:to_str).and_return('a')
-
- @t.thread_variable_set(key, 49)
- @t.thread_variable_set('b', 50)
- @t.thread_variable_set(:c, 51)
- @t.thread_variables.sort.should == [:a, :b, :c]
- end
end
diff --git a/spec/ruby/core/time/_load_spec.rb b/spec/ruby/core/time/_load_spec.rb
index bb0d705bbc..152934370f 100644
--- a/spec/ruby/core/time/_load_spec.rb
+++ b/spec/ruby/core/time/_load_spec.rb
@@ -44,7 +44,8 @@ describe "Time._load" do
end
it "treats the data as binary data" do
- data = "\x04\bu:\tTime\r\fM\x1C\xC0\x00\x00\xD0\xBE".dup.force_encoding Encoding::UTF_8
+ data = "\x04\bu:\tTime\r\fM\x1C\xC0\x00\x00\xD0\xBE"
+ data.force_encoding Encoding::UTF_8
t = Marshal.load(data)
t.to_s.should == "2013-04-08 12:47:45 UTC"
end
diff --git a/spec/ruby/core/time/at_spec.rb b/spec/ruby/core/time/at_spec.rb
index 48fb3c6f52..0459589f01 100644
--- a/spec/ruby/core/time/at_spec.rb
+++ b/spec/ruby/core/time/at_spec.rb
@@ -32,6 +32,13 @@ describe "Time.at" do
t2.nsec.should == t.nsec
end
+ describe "passed BigDecimal" do
+ it "doesn't round input value" do
+ require 'bigdecimal'
+ Time.at(BigDecimal('1.1')).to_f.should == 1.1
+ end
+ end
+
describe "passed Rational" do
it "returns Time with correct microseconds" do
t = Time.at(Rational(1_486_570_508_539_759, 1_000_000))
@@ -196,7 +203,7 @@ describe "Time.at" do
end
it "does not try to convert format to Symbol with #to_sym" do
- format = +"usec"
+ format = "usec"
format.should_not_receive(:to_sym)
-> { Time.at(0, 123456, format) }.should raise_error(ArgumentError)
end
diff --git a/spec/ruby/core/time/deconstruct_keys_spec.rb b/spec/ruby/core/time/deconstruct_keys_spec.rb
deleted file mode 100644
index ee17e7dbd4..0000000000
--- a/spec/ruby/core/time/deconstruct_keys_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-require_relative '../../spec_helper'
-
-ruby_version_is "3.2" do
- describe "Time#deconstruct_keys" do
- it "returns whole hash for nil as an argument" do
- d = Time.utc(2022, 10, 5, 13, 30)
- res = { year: 2022, month: 10, day: 5, yday: 278, wday: 3, hour: 13,
- min: 30, sec: 0, subsec: 0, dst: false, zone: "UTC" }
- d.deconstruct_keys(nil).should == res
- end
-
- it "returns only specified keys" do
- d = Time.utc(2022, 10, 5, 13, 39)
- d.deconstruct_keys([:zone, :subsec]).should == { zone: "UTC", subsec: 0 }
- end
-
- it "requires one argument" do
- -> {
- Time.new(2022, 10, 5, 13, 30).deconstruct_keys
- }.should raise_error(ArgumentError)
- end
-
- it "it raises error when argument is neither nil nor array" do
- d = Time.new(2022, 10, 5, 13, 30)
-
- -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)")
- -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)")
- -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)")
- -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)")
- end
-
- it "returns {} when passed []" do
- Time.new(2022, 10, 5, 13, 30).deconstruct_keys([]).should == {}
- end
-
- it "ignores non-Symbol keys" do
- Time.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {}
- end
-
- it "ignores not existing Symbol keys and processes keys after the first non-existing one" do
- d = Time.utc(2022, 10, 5, 13, 30)
- d.deconstruct_keys([:year, :a, :month, :b, :day]).should == { year: 2022, month: 10, day: 5 }
- end
- end
-end
diff --git a/spec/ruby/core/time/fixtures/classes.rb b/spec/ruby/core/time/fixtures/classes.rb
index 21c4e1effb..1a9511b261 100644
--- a/spec/ruby/core/time/fixtures/classes.rb
+++ b/spec/ruby/core/time/fixtures/classes.rb
@@ -59,6 +59,7 @@ module TimeSpecs
Zone = Struct.new(:std, :dst, :dst_range)
Zones = {
"Asia/Colombo" => Zone[Z[5*3600+30*60, "MMT"], nil, nil],
+ "Europe/Kiev" => Zone[Z[2*3600, "EET"], Z[3*3600, "EEST"], 4..10],
"PST" => Zone[Z[(-9*60*60), "PST"], nil, nil],
}
diff --git a/spec/ruby/core/time/iso8601_spec.rb b/spec/ruby/core/time/iso8601_spec.rb
deleted file mode 100644
index ad60c3bb32..0000000000
--- a/spec/ruby/core/time/iso8601_spec.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/xmlschema'
-
-describe "Time#iso8601" do
- it_behaves_like :time_xmlschema, :iso8601
-end
diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb
index d686355270..727fdf92c2 100644
--- a/spec/ruby/core/time/new_spec.rb
+++ b/spec/ruby/core/time/new_spec.rb
@@ -58,7 +58,7 @@ describe "Time.new with a utc_offset argument" do
Time.new(2000, 1, 1, 0, 0, 0, "-04:10:43").utc_offset.should == -15043
end
- ruby_bug '#13669', ''...'3.1' do
+ ruby_bug '#13669', '3.0'...'3.1' do
it "returns a Time with a UTC offset specified as +HH" do
Time.new(2000, 1, 1, 0, 0, 0, "+05").utc_offset.should == 3600 * 5
end
@@ -200,8 +200,10 @@ describe "Time.new with a timezone argument" do
time.zone.should == zone
time.utc_offset.should == 5*3600+30*60
- time.wday.should == 6
- time.yday.should == 1
+ ruby_version_is "3.0" do
+ time.wday.should == 6
+ time.yday.should == 1
+ end
end
it "accepts timezone argument that must have #local_to_utc and #utc_to_local methods" do
@@ -358,7 +360,7 @@ describe "Time.new with a timezone argument" do
-> {
Marshal.dump(time)
- }.should raise_error(NoMethodError, /undefined method [`']name' for/)
+ }.should raise_error(NoMethodError, /undefined method `name' for/)
end
end
@@ -429,10 +431,6 @@ describe "Time.new with a timezone argument" do
time.zone.should == nil
end
- it "returns a Time with UTC offset specified as a single letter military timezone" do
- Time.new(2000, 1, 1, 0, 0, 0, in: "W").utc_offset.should == 3600 * -10
- end
-
it "could be a timezone object" do
zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
time = Time.new(2000, 1, 1, 12, 0, 0, in: zone)
@@ -447,199 +445,13 @@ describe "Time.new with a timezone argument" do
time.zone.should == zone
end
- it "allows omitting minor arguments" do
- Time.new(2000, 1, 1, 12, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 1, "+05:00")
- Time.new(2000, 1, 1, 12, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 0, "+05:00")
- Time.new(2000, 1, 1, 12, in: "+05:00").should == Time.new(2000, 1, 1, 12, 0, 0, "+05:00")
- Time.new(2000, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
- Time.new(2000, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
- Time.new(2000, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
- Time.new(in: "+05:00").should be_close(Time.now.getlocal("+05:00"), TIME_TOLERANCE)
- end
-
- it "converts to a provided timezone if all the positional arguments are omitted" do
- Time.new(in: "+05:00").utc_offset.should == 5*3600
- end
-
it "raises ArgumentError if format is invalid" do
-> { Time.new(2000, 1, 1, 12, 0, 0, in: "+09:99") }.should raise_error(ArgumentError)
-> { Time.new(2000, 1, 1, 12, 0, 0, in: "ABC") }.should raise_error(ArgumentError)
end
it "raises ArgumentError if two offset arguments are given" do
- -> {
- Time.new(2000, 1, 1, 12, 0, 0, "+05:00", in: "+05:00")
- }.should raise_error(ArgumentError, "timezone argument given as positional and keyword arguments")
- end
- end
- end
-
- ruby_version_is "3.2" do
- describe "Time.new with a String argument" do
- it "parses an ISO-8601 like format" do
- t = Time.utc(2020, 12, 24, 15, 56, 17)
-
- Time.new("2020-12-24T15:56:17Z").should == t
- Time.new("2020-12-25 00:56:17 +09:00").should == t
- Time.new("2020-12-25 00:57:47 +09:01:30").should == t
- Time.new("2020-12-25 00:56:17 +0900").should == t
- Time.new("2020-12-25 00:57:47 +090130").should == t
- Time.new("2020-12-25T00:56:17+09:00").should == t
- end
-
- it "accepts precision keyword argument and truncates specified digits of sub-second part" do
- Time.new("2021-12-25 00:00:00.123456789876 +09:00").subsec.should == 0.123456789r
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: nil).subsec.should == 0.123456789876r
- Time.new("2021-12-25 00:00:00 +09:00", precision: 0).subsec.should == 0
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: -1).subsec.should == 0.123456789876r
- end
-
- it "returns Time in local timezone if not provided in the String argument" do
- Time.new("2021-12-25 00:00:00").zone.should == Time.new(2021, 12, 25).zone
- Time.new("2021-12-25 00:00:00").utc_offset.should == Time.new(2021, 12, 25).utc_offset
- end
-
- it "returns Time in timezone specified in the String argument" do
- Time.new("2021-12-25 00:00:00 +05:00").to_s.should == "2021-12-25 00:00:00 +0500"
- end
-
- it "returns Time in timezone specified in the String argument even if the in keyword argument provided" do
- Time.new("2021-12-25 00:00:00 +09:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 +0900"
- end
-
- it "returns Time in timezone specified with in keyword argument if timezone isn't provided in the String argument" do
- Time.new("2021-12-25 00:00:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 -0100"
- end
-
- it "converts precision keyword argument into Integer if is not nil" do
- obj = Object.new
- def obj.to_int; 3; end
-
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 1.2).subsec.should == 0.1r
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: obj).subsec.should == 0.123r
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 3r).subsec.should == 0.123r
- end
-
- ruby_version_is ""..."3.3" do
- it "raise TypeError is can't convert precision keyword argument into Integer" do
- -> {
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "")
- }.should raise_error(TypeError, "no implicit conversion from string")
- end
- end
-
- ruby_version_is "3.3" do
- it "raise TypeError is can't convert precision keyword argument into Integer" do
- -> {
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "")
- }.should raise_error(TypeError, "no implicit conversion of String into Integer")
- end
- end
-
- it "raises ArgumentError if part of time string is missing" do
- -> {
- Time.new("2020-12-25 00:56 +09:00")
- }.should raise_error(ArgumentError, "missing sec part: 00:56 ")
-
- -> {
- Time.new("2020-12-25 00 +09:00")
- }.should raise_error(ArgumentError, "missing min part: 00 ")
- end
-
- it "raises ArgumentError if subsecond is missing after dot" do
- -> {
- Time.new("2020-12-25 00:56:17. +0900")
- }.should raise_error(ArgumentError, "subsecond expected after dot: 00:56:17. ")
- end
-
- it "raises ArgumentError if String argument is not in the supported format" do
- -> {
- Time.new("021-12-25 00:00:00.123456 +09:00")
- }.should raise_error(ArgumentError, "year must be 4 or more digits: 021")
-
- -> {
- Time.new("2020-012-25 00:56:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -012-25 00:\z/)
-
- -> {
- Time.new("2020-2-25 00:56:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -2-25 00:56\z/)
-
- -> {
- Time.new("2020-12-215 00:56:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits mday is expected after [`']-': -215 00:56:\z/)
-
- -> {
- Time.new("2020-12-25 000:56:17 +0900")
- }.should raise_error(ArgumentError, "two digits hour is expected: 000:56:17 ")
-
- -> {
- Time.new("2020-12-25 0:56:17 +0900")
- }.should raise_error(ArgumentError, "two digits hour is expected: 0:56:17 +0")
-
- -> {
- Time.new("2020-12-25 00:516:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :516:17 \+09\z/)
-
- -> {
- Time.new("2020-12-25 00:6:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :6:17 \+0900\z/)
-
- -> {
- Time.new("2020-12-25 00:56:137 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :137 \+0900\z/)
-
- -> {
- Time.new("2020-12-25 00:56:7 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :7 \+0900\z/)
-
- -> {
- Time.new("2020-12-25 00:56. +0900")
- }.should raise_error(ArgumentError, "fraction min is not supported: 00:56.")
-
- -> {
- Time.new("2020-12-25 00. +0900")
- }.should raise_error(ArgumentError, "fraction hour is not supported: 00.")
- end
-
- it "raises ArgumentError if date/time parts values are not valid" do
- -> {
- Time.new("2020-13-25 00:56:17 +09:00")
- }.should raise_error(ArgumentError, "mon out of range")
-
- -> {
- Time.new("2020-12-32 00:56:17 +09:00")
- }.should raise_error(ArgumentError, "mday out of range")
-
- -> {
- Time.new("2020-12-25 25:56:17 +09:00")
- }.should raise_error(ArgumentError, "hour out of range")
-
- -> {
- Time.new("2020-12-25 00:61:17 +09:00")
- }.should raise_error(ArgumentError, "min out of range")
-
- -> {
- Time.new("2020-12-25 00:56:61 +09:00")
- }.should raise_error(ArgumentError, "sec out of range")
-
- -> {
- Time.new("2020-12-25 00:56:17 +23:59:60")
- }.should raise_error(ArgumentError, "utc_offset out of range")
-
- -> {
- Time.new("2020-12-25 00:56:17 +24:00")
- }.should raise_error(ArgumentError, "utc_offset out of range")
-
- -> {
- Time.new("2020-12-25 00:56:17 +23:61")
- }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +23:61')
- end
-
- it "raises ArgumentError if string has not ascii-compatible encoding" do
- -> {
- Time.new("2021-11-31 00:00:60 +09:00".encode("utf-32le"))
- }.should raise_error(ArgumentError, "time string should have ASCII compatible encoding")
+ -> { Time.new(2000, 1, 1, 12, 0, 0, "+05:00", in: "+05:00") }.should raise_error(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/time/now_spec.rb b/spec/ruby/core/time/now_spec.rb
index d47f00723e..2b2e53a17c 100644
--- a/spec/ruby/core/time/now_spec.rb
+++ b/spec/ruby/core/time/now_spec.rb
@@ -4,54 +4,48 @@ require_relative 'shared/now'
describe "Time.now" do
it_behaves_like :time_now, :now
- ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/17485
- describe ":in keyword argument" do
- it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do
- time = Time.now(in: "+05:00")
+ describe ":in keyword argument" do
+ it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do
+ time = Time.now(in: "+05:00")
- time.utc_offset.should == 5*60*60
- time.zone.should == nil
+ time.utc_offset.should == 5*60*60
+ time.zone.should == nil
- time = Time.now(in: "-09:00")
+ time = Time.now(in: "-09:00")
- time.utc_offset.should == -9*60*60
- time.zone.should == nil
- end
-
- it "could be UTC offset as a number of seconds" do
- time = Time.now(in: 5*60*60)
+ time.utc_offset.should == -9*60*60
+ time.zone.should == nil
+ end
- time.utc_offset.should == 5*60*60
- time.zone.should == nil
+ it "could be UTC offset as a number of seconds" do
+ time = Time.now(in: 5*60*60)
- time = Time.now(in: -9*60*60)
+ time.utc_offset.should == 5*60*60
+ time.zone.should == nil
- time.utc_offset.should == -9*60*60
- time.zone.should == nil
- end
+ time = Time.now(in: -9*60*60)
- it "returns a Time with UTC offset specified as a single letter military timezone" do
- Time.now(in: "W").utc_offset.should == 3600 * -10
- end
+ time.utc_offset.should == -9*60*60
+ time.zone.should == nil
+ end
- it "could be a timezone object" do
- zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
- time = Time.now(in: zone)
+ it "could be a timezone object" do
+ zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
+ time = Time.now(in: zone)
- time.utc_offset.should == 5*3600+30*60
- time.zone.should == zone
+ time.utc_offset.should == 5*3600+30*60
+ time.zone.should == zone
- zone = TimeSpecs::TimezoneWithName.new(name: "PST")
- time = Time.now(in: zone)
+ zone = TimeSpecs::TimezoneWithName.new(name: "PST")
+ time = Time.now(in: zone)
- time.utc_offset.should == -9*60*60
- time.zone.should == zone
- end
+ time.utc_offset.should == -9*60*60
+ time.zone.should == zone
+ end
- it "raises ArgumentError if format is invalid" do
- -> { Time.now(in: "+09:99") }.should raise_error(ArgumentError)
- -> { Time.now(in: "ABC") }.should raise_error(ArgumentError)
- end
+ it "raises ArgumentError if format is invalid" do
+ -> { Time.now(in: "+09:99") }.should raise_error(ArgumentError)
+ -> { Time.now(in: "ABC") }.should raise_error(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/time/shared/xmlschema.rb b/spec/ruby/core/time/shared/xmlschema.rb
deleted file mode 100644
index d68c18df36..0000000000
--- a/spec/ruby/core/time/shared/xmlschema.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-describe :time_xmlschema, shared: true do
- ruby_version_is "3.4" do
- it "generates ISO-8601 strings in Z for UTC times" do
- t = Time.utc(1985, 4, 12, 23, 20, 50, 521245)
- t.send(@method).should == "1985-04-12T23:20:50Z"
- t.send(@method, 2).should == "1985-04-12T23:20:50.52Z"
- t.send(@method, 9).should == "1985-04-12T23:20:50.521245000Z"
- end
-
- it "generates ISO-8601 string with timeone offset for non-UTC times" do
- t = Time.new(1985, 4, 12, 23, 20, 50, "+02:00")
- t.send(@method).should == "1985-04-12T23:20:50+02:00"
- t.send(@method, 2).should == "1985-04-12T23:20:50.00+02:00"
- end
-
- it "year is always at least 4 digits" do
- t = Time.utc(12, 4, 12)
- t.send(@method).should == "0012-04-12T00:00:00Z"
- end
-
- it "year can be more than 4 digits" do
- t = Time.utc(40_000, 4, 12)
- t.send(@method).should == "40000-04-12T00:00:00Z"
- end
-
- it "year can be negative" do
- t = Time.utc(-2000, 4, 12)
- t.send(@method).should == "-2000-04-12T00:00:00Z"
- end
- end
-end
diff --git a/spec/ruby/core/time/succ_spec.rb b/spec/ruby/core/time/succ_spec.rb
new file mode 100644
index 0000000000..e8249059d1
--- /dev/null
+++ b/spec/ruby/core/time/succ_spec.rb
@@ -0,0 +1,39 @@
+ruby_version_is ""..."3.0" do
+ require_relative '../../spec_helper'
+ require_relative 'fixtures/classes'
+
+ describe "Time#succ" do
+ it "returns a new time one second later than time" do
+ suppress_warning {
+ @result = Time.at(100).succ
+ }
+
+ @result.should == Time.at(101)
+ end
+
+ it "returns a new instance" do
+ time = Time.at(100)
+
+ suppress_warning {
+ @result = time.succ
+ }
+
+ @result.should_not equal time
+ end
+
+ it "is obsolete" do
+ -> {
+ Time.at(100).succ
+ }.should complain(/Time#succ is obsolete/)
+ end
+
+ context "zone is a timezone object" do
+ it "preserves time zone" do
+ zone = TimeSpecs::Timezone.new(offset: (5*3600+30*60))
+ time = Time.new(2012, 1, 1, 12, 0, 0, zone) - 1
+
+ time.zone.should == zone
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/time/utc_spec.rb b/spec/ruby/core/time/utc_spec.rb
index 566509fd33..809accc809 100644
--- a/spec/ruby/core/time/utc_spec.rb
+++ b/spec/ruby/core/time/utc_spec.rb
@@ -21,22 +21,12 @@ describe "Time#utc?" do
Time.new(2022, 1, 1, 0, 0, 0, "UTC").utc?.should == true
Time.now.localtime("UTC").utc?.should == true
Time.at(Time.now, in: 'UTC').utc?.should == true
-
- ruby_version_is "3.1" do
- Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").utc?.should == true
- Time.now(in: "UTC").utc?.should == true
- end
end
it "does treat time with Z offset as UTC" do
Time.new(2022, 1, 1, 0, 0, 0, "Z").utc?.should == true
Time.now.localtime("Z").utc?.should == true
Time.at(Time.now, in: 'Z').utc?.should == true
-
- ruby_version_is "3.1" do
- Time.new(2022, 1, 1, 0, 0, 0, in: "Z").utc?.should == true
- Time.now(in: "Z").utc?.should == true
- end
end
ruby_version_is "3.1" do
diff --git a/spec/ruby/core/time/xmlschema_spec.rb b/spec/ruby/core/time/xmlschema_spec.rb
deleted file mode 100644
index bdf1dc7923..0000000000
--- a/spec/ruby/core/time/xmlschema_spec.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/xmlschema'
-
-describe "Time#xmlschema" do
- it_behaves_like :time_xmlschema, :xmlschema
-end
diff --git a/spec/ruby/core/time/yday_spec.rb b/spec/ruby/core/time/yday_spec.rb
index e920c2e28d..6ea5ff8f1b 100644
--- a/spec/ruby/core/time/yday_spec.rb
+++ b/spec/ruby/core/time/yday_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative '../../shared/time/yday'
describe "Time#yday" do
it "returns an integer representing the day of the year, 1..366" do
@@ -8,5 +7,15 @@ describe "Time#yday" do
end
end
- it_behaves_like :time_yday, -> year, month, day { Time.new(year, month, day).yday }
+ it 'returns the correct value for each day of each month' do
+ mdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+
+ yday = 1
+ mdays.each_with_index do |days, month|
+ days.times do |day|
+ Time.new(2014, month+1, day+1).yday.should == yday
+ yday += 1
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/time/zone_spec.rb b/spec/ruby/core/time/zone_spec.rb
index 63c92602d1..cbb0977f24 100644
--- a/spec/ruby/core/time/zone_spec.rb
+++ b/spec/ruby/core/time/zone_spec.rb
@@ -74,17 +74,6 @@ describe "Time#zone" do
Time.now.localtime("-00:00").zone.should == "UTC"
Time.at(Time.now, in: '-00:00').zone.should == "UTC"
end
-
- ruby_version_is "3.1" do
- Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").zone.should == "UTC"
- Time.new(2022, 1, 1, 0, 0, 0, in: "Z").zone.should == "UTC"
-
- Time.now(in: 'UTC').zone.should == "UTC"
- Time.now(in: 'Z').zone.should == "UTC"
-
- Time.at(Time.now, in: 'UTC').zone.should == "UTC"
- Time.at(Time.now, in: 'Z').zone.should == "UTC"
- end
end
platform_is_not :aix, :windows do
diff --git a/spec/ruby/core/tracepoint/enable_spec.rb b/spec/ruby/core/tracepoint/enable_spec.rb
index 6cc8bb3897..24f6070b97 100644
--- a/spec/ruby/core/tracepoint/enable_spec.rb
+++ b/spec/ruby/core/tracepoint/enable_spec.rb
@@ -149,7 +149,13 @@ describe 'TracePoint#enable' do
describe "when nested" do
before do
- @path_prefix = ' '
+ ruby_version_is ""..."3.0" do
+ @path_prefix = '@'
+ end
+
+ ruby_version_is "3.0" do
+ @path_prefix = ' '
+ end
end
it "enables both TracePoints but only calls the respective callbacks" do
diff --git a/spec/ruby/core/tracepoint/inspect_spec.rb b/spec/ruby/core/tracepoint/inspect_spec.rb
index 6cc2ebe243..151a08e7b4 100644
--- a/spec/ruby/core/tracepoint/inspect_spec.rb
+++ b/spec/ruby/core/tracepoint/inspect_spec.rb
@@ -3,7 +3,13 @@ require_relative 'fixtures/classes'
describe 'TracePoint#inspect' do
before do
- @path_prefix = ' '
+ ruby_version_is ""..."3.0" do
+ @path_prefix = '@'
+ end
+
+ ruby_version_is "3.0" do
+ @path_prefix = ' '
+ end
end
it 'returns a string containing a human-readable TracePoint status' do
@@ -24,8 +30,6 @@ describe 'TracePoint#inspect' do
line = nil
TracePoint.new(:line) { |tp|
next unless TracePointSpec.target_thread?
- next unless tp.path == __FILE__
-
inspect ||= tp.inspect
}.enable do
line = __LINE__
@@ -39,8 +43,6 @@ describe 'TracePoint#inspect' do
line = nil
TracePoint.new(:call) { |tp|
next unless TracePointSpec.target_thread?
- next unless tp.path == __FILE__
-
inspect ||= tp.inspect
}.enable do
line = __LINE__ + 1
@@ -48,7 +50,7 @@ describe 'TracePoint#inspect' do
trace_point_spec_test_call
end
- inspect.should =~ /\A#<TracePoint:call [`']trace_point_spec_test_call'#{@path_prefix}#{__FILE__}:#{line}>\z/
+ inspect.should == "#<TracePoint:call `trace_point_spec_test_call'#{@path_prefix}#{__FILE__}:#{line}>"
end
it 'returns a String showing the event, method, path and line for a :return event' do
@@ -56,8 +58,6 @@ describe 'TracePoint#inspect' do
line = nil
TracePoint.new(:return) { |tp|
next unless TracePointSpec.target_thread?
- next unless tp.path == __FILE__
-
inspect ||= tp.inspect
}.enable do
line = __LINE__ + 4
@@ -67,17 +67,14 @@ describe 'TracePoint#inspect' do
end
trace_point_spec_test_return
end
- ruby_version_is("3.4") { line -= 1 }
- inspect.should =~ /\A#<TracePoint:return [`']trace_point_spec_test_return'#{@path_prefix}#{__FILE__}:#{line}>\z/
+ inspect.should == "#<TracePoint:return `trace_point_spec_test_return'#{@path_prefix}#{__FILE__}:#{line}>"
end
it 'returns a String showing the event, method, path and line for a :c_call event' do
inspect = nil
tracepoint = TracePoint.new(:c_call) { |tp|
next unless TracePointSpec.target_thread?
- next unless tp.path == __FILE__
-
inspect ||= tp.inspect
}
line = __LINE__ + 2
@@ -85,7 +82,7 @@ describe 'TracePoint#inspect' do
[0, 1].max
end
- inspect.should =~ /\A#<TracePoint:c_call [`']max'#{@path_prefix}#{__FILE__}:#{line}>\z/
+ inspect.should == "#<TracePoint:c_call `max'#{@path_prefix}#{__FILE__}:#{line}>"
end
it 'returns a String showing the event, path and line for a :class event' do
@@ -93,8 +90,6 @@ describe 'TracePoint#inspect' do
line = nil
TracePoint.new(:class) { |tp|
next unless TracePointSpec.target_thread?
- next unless tp.path == __FILE__
-
inspect ||= tp.inspect
}.enable do
line = __LINE__ + 1
@@ -111,7 +106,6 @@ describe 'TracePoint#inspect' do
thread_inspection = nil
TracePoint.new(:thread_begin) { |tp|
next unless Thread.current == thread
-
inspect ||= tp.inspect
}.enable(target_thread: nil) do
thread = Thread.new {}
@@ -128,7 +122,6 @@ describe 'TracePoint#inspect' do
thread_inspection = nil
TracePoint.new(:thread_end) { |tp|
next unless Thread.current == thread
-
inspect ||= tp.inspect
}.enable(target_thread: nil) do
thread = Thread.new {}
diff --git a/spec/ruby/core/tracepoint/path_spec.rb b/spec/ruby/core/tracepoint/path_spec.rb
index dc2ca840b8..5b6c6d4cfc 100644
--- a/spec/ruby/core/tracepoint/path_spec.rb
+++ b/spec/ruby/core/tracepoint/path_spec.rb
@@ -13,29 +13,14 @@ describe 'TracePoint#path' do
path.should == "#{__FILE__}"
end
- ruby_version_is ""..."3.3" do
- it 'equals (eval) inside an eval for :end event' do
- path = nil
- TracePoint.new(:end) { |tp|
- next unless TracePointSpec.target_thread?
- path = tp.path
- }.enable do
- eval("module TracePointSpec; end")
- end
- path.should == '(eval)'
- end
- end
-
- ruby_version_is "3.3" do
- it 'equals "(eval at __FILE__:__LINE__)" inside an eval for :end event' do
- path = nil
- TracePoint.new(:end) { |tp|
- next unless TracePointSpec.target_thread?
- path = tp.path
- }.enable do
- eval("module TracePointSpec; end")
- end
- path.should == "(eval at #{__FILE__}:#{__LINE__ - 2})"
+ it 'equals (eval) inside an eval for :end event' do
+ path = nil
+ TracePoint.new(:end) { |tp|
+ next unless TracePointSpec.target_thread?
+ path = tp.path
+ }.enable do
+ eval("module TracePointSpec; end")
end
+ path.should == '(eval)'
end
end
diff --git a/spec/ruby/core/true/singleton_method_spec.rb b/spec/ruby/core/true/singleton_method_spec.rb
deleted file mode 100644
index c06793850f..0000000000
--- a/spec/ruby/core/true/singleton_method_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-
-describe "TrueClass#singleton_method" do
- ruby_version_is '3.3' do
- it "raises regardless of whether TrueClass defines the method" do
- -> { true.singleton_method(:foo) }.should raise_error(NameError)
- begin
- def (true).foo; end
- -> { true.singleton_method(:foo) }.should raise_error(NameError)
- ensure
- TrueClass.send(:remove_method, :foo)
- end
- end
- end
-end
diff --git a/spec/ruby/core/unboundmethod/bind_call_spec.rb b/spec/ruby/core/unboundmethod/bind_call_spec.rb
index 80b2095d86..8f25f8bd0d 100644
--- a/spec/ruby/core/unboundmethod/bind_call_spec.rb
+++ b/spec/ruby/core/unboundmethod/bind_call_spec.rb
@@ -7,8 +7,6 @@ describe "UnboundMethod#bind_call" do
@parent_um = UnboundMethodSpecs::Parent.new.method(:foo).unbind
@child1_um = UnboundMethodSpecs::Child1.new.method(:foo).unbind
@child2_um = UnboundMethodSpecs::Child2.new.method(:foo).unbind
- @normal_um_super = UnboundMethodSpecs::Mod.instance_method(:foo_super)
- @parent_um_super = UnboundMethodSpecs::Parent.new.method(:foo_super).unbind
end
it "raises TypeError if object is not kind_of? the Module the method defined in" do
@@ -49,10 +47,4 @@ describe "UnboundMethod#bind_call" do
um = p.method(:singleton_method).unbind
->{ um.bind_call(other) }.should raise_error(TypeError)
end
-
- it "allows calling super for module methods bound to hierarchies that do not already have that module" do
- p = UnboundMethodSpecs::Parent.new
-
- @normal_um_super.bind_call(p).should == true
- end
end
diff --git a/spec/ruby/core/unboundmethod/bind_spec.rb b/spec/ruby/core/unboundmethod/bind_spec.rb
index 7658b664e5..03aaa22e74 100644
--- a/spec/ruby/core/unboundmethod/bind_spec.rb
+++ b/spec/ruby/core/unboundmethod/bind_spec.rb
@@ -7,8 +7,6 @@ describe "UnboundMethod#bind" do
@parent_um = UnboundMethodSpecs::Parent.new.method(:foo).unbind
@child1_um = UnboundMethodSpecs::Child1.new.method(:foo).unbind
@child2_um = UnboundMethodSpecs::Child2.new.method(:foo).unbind
- @normal_um_super = UnboundMethodSpecs::Mod.instance_method(:foo_super)
- @parent_um_super = UnboundMethodSpecs::Parent.new.method(:foo_super).unbind
end
it "raises TypeError if object is not kind_of? the Module the method defined in" do
@@ -60,10 +58,4 @@ describe "UnboundMethod#bind" do
um = p.method(:singleton_method).unbind
->{ um.bind(other) }.should raise_error(TypeError)
end
-
- it "allows calling super for module methods bound to hierarchies that do not already have that module" do
- p = UnboundMethodSpecs::Parent.new
-
- @normal_um_super.bind(p).call.should == true
- end
end
diff --git a/spec/ruby/core/unboundmethod/clone_spec.rb b/spec/ruby/core/unboundmethod/clone_spec.rb
index 1e7fb18744..098ee61476 100644
--- a/spec/ruby/core/unboundmethod/clone_spec.rb
+++ b/spec/ruby/core/unboundmethod/clone_spec.rb
@@ -1,13 +1,12 @@
require_relative '../../spec_helper'
-require_relative 'shared/dup'
+require_relative 'fixtures/classes'
describe "UnboundMethod#clone" do
- it_behaves_like :unboundmethod_dup, :clone
+ it "returns a copy of the UnboundMethod" do
+ um1 = UnboundMethodSpecs::Methods.instance_method(:foo)
+ um2 = um1.clone
- it "preserves frozen status" do
- method = Class.instance_method(:instance_method)
- method.freeze
- method.frozen?.should == true
- method.clone.frozen?.should == true
+ (um1 == um2).should == true
+ um1.bind(UnboundMethodSpecs::Methods.new).call.should == um2.bind(UnboundMethodSpecs::Methods.new).call
end
end
diff --git a/spec/ruby/core/unboundmethod/dup_spec.rb b/spec/ruby/core/unboundmethod/dup_spec.rb
deleted file mode 100644
index 5a78dd8e36..0000000000
--- a/spec/ruby/core/unboundmethod/dup_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/dup'
-
-describe "UnboundMethod#dup" do
- ruby_version_is "3.4" do
- it_behaves_like :unboundmethod_dup, :dup
-
- it "resets frozen status" do
- method = Class.instance_method(:instance_method)
- method.freeze
- method.frozen?.should == true
- method.dup.frozen?.should == false
- end
- end
-end
diff --git a/spec/ruby/core/unboundmethod/fixtures/classes.rb b/spec/ruby/core/unboundmethod/fixtures/classes.rb
index 28d8e0a965..6ab958d447 100644
--- a/spec/ruby/core/unboundmethod/fixtures/classes.rb
+++ b/spec/ruby/core/unboundmethod/fixtures/classes.rb
@@ -22,7 +22,6 @@ module UnboundMethodSpecs
module Mod
def from_mod; end
- def foo_super; super; end
end
class Methods
@@ -64,9 +63,6 @@ module UnboundMethodSpecs
class Parent
def foo; end
- def foo_super
- true
- end
def self.class_method
"I am #{name}"
end
diff --git a/spec/ruby/core/unboundmethod/private_spec.rb b/spec/ruby/core/unboundmethod/private_spec.rb
index 8ea50bb5d4..fa735846bb 100644
--- a/spec/ruby/core/unboundmethod/private_spec.rb
+++ b/spec/ruby/core/unboundmethod/private_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-describe "UnboundMethod#private?" do
- ruby_version_is "3.1"..."3.2" do
+ruby_version_is "3.1"..."3.2" do
+ describe "UnboundMethod#private?" do
it "returns false when the method is public" do
obj = UnboundMethodSpecs::Methods.new
obj.method(:my_public_method).unbind.private?.should == false
@@ -18,11 +18,4 @@ describe "UnboundMethod#private?" do
obj.method(:my_private_method).unbind.private?.should == true
end
end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_private_method).unbind.should_not.respond_to?(:private?)
- end
- end
end
diff --git a/spec/ruby/core/unboundmethod/protected_spec.rb b/spec/ruby/core/unboundmethod/protected_spec.rb
index 0c215d8638..db00e7ef43 100644
--- a/spec/ruby/core/unboundmethod/protected_spec.rb
+++ b/spec/ruby/core/unboundmethod/protected_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-describe "UnboundMethod#protected?" do
- ruby_version_is "3.1"..."3.2" do
+ruby_version_is "3.1"..."3.2" do
+ describe "UnboundMethod#protected?" do
it "returns false when the method is public" do
obj = UnboundMethodSpecs::Methods.new
obj.method(:my_public_method).unbind.protected?.should == false
@@ -18,11 +18,4 @@ describe "UnboundMethod#protected?" do
obj.method(:my_private_method).unbind.protected?.should == false
end
end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_protected_method).unbind.should_not.respond_to?(:protected?)
- end
- end
end
diff --git a/spec/ruby/core/unboundmethod/public_spec.rb b/spec/ruby/core/unboundmethod/public_spec.rb
index 552bbf6eab..7b87a03b15 100644
--- a/spec/ruby/core/unboundmethod/public_spec.rb
+++ b/spec/ruby/core/unboundmethod/public_spec.rb
@@ -1,8 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-describe "UnboundMethod#public?" do
- ruby_version_is "3.1"..."3.2" do
+ruby_version_is "3.1"..."3.2" do
+ describe "UnboundMethod#public?" do
it "returns true when the method is public" do
obj = UnboundMethodSpecs::Methods.new
obj.method(:my_public_method).unbind.public?.should == true
@@ -18,11 +18,4 @@ describe "UnboundMethod#public?" do
obj.method(:my_private_method).unbind.public?.should == false
end
end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_public_method).unbind.should_not.respond_to?(:public?)
- end
- end
end
diff --git a/spec/ruby/core/unboundmethod/shared/dup.rb b/spec/ruby/core/unboundmethod/shared/dup.rb
deleted file mode 100644
index 943a7faaa3..0000000000
--- a/spec/ruby/core/unboundmethod/shared/dup.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-describe :unboundmethod_dup, shared: true do
- it "returns a copy of self" do
- a = Class.instance_method(:instance_method)
- b = a.send(@method)
-
- a.should == b
- a.should_not equal(b)
- end
-
- ruby_version_is "3.4" do
- it "copies instance variables" do
- method = Class.instance_method(:instance_method)
- method.instance_variable_set(:@ivar, 1)
- cl = method.send(@method)
- cl.instance_variables.should == [:@ivar]
- end
-
- it "copies the finalizer" do
- code = <<-RUBY
- obj = Class.instance_method(:instance_method)
-
- ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" })
-
- obj.clone
-
- exit 0
- RUBY
-
- ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"]
- end
- end
-end
diff --git a/spec/ruby/core/unboundmethod/source_location_spec.rb b/spec/ruby/core/unboundmethod/source_location_spec.rb
index 5c2f14362c..96933a5d40 100644
--- a/spec/ruby/core/unboundmethod/source_location_spec.rb
+++ b/spec/ruby/core/unboundmethod/source_location_spec.rb
@@ -9,7 +9,7 @@ describe "UnboundMethod#source_location" do
it "sets the first value to the path of the file in which the method was defined" do
file = @method.source_location.first
file.should be_an_instance_of(String)
- file.should == File.realpath('fixtures/classes.rb', __dir__)
+ file.should == File.realpath('../fixtures/classes.rb', __FILE__)
end
it "sets the last value to an Integer representing the line on which the method was defined" do
@@ -49,11 +49,4 @@ describe "UnboundMethod#source_location" do
method.source_location[0].should =~ /#{__FILE__}/
method.source_location[1].should == line
end
-
- it "works for eval with a given line" do
- c = Class.new do
- eval('def m; end', nil, "foo", 100)
- end
- c.instance_method(:m).source_location.should == ["foo", 100]
- end
end
diff --git a/spec/ruby/core/unboundmethod/super_method_spec.rb b/spec/ruby/core/unboundmethod/super_method_spec.rb
index aa7c129377..101c83b8b3 100644
--- a/spec/ruby/core/unboundmethod/super_method_spec.rb
+++ b/spec/ruby/core/unboundmethod/super_method_spec.rb
@@ -40,10 +40,12 @@ describe "UnboundMethod#super_method" do
end
end
- context "after aliasing an inherited method" do
- it "returns the expected super_method" do
- method = MethodSpecs::InheritedMethods::C.instance_method(:meow)
- method.super_method.owner.should == MethodSpecs::InheritedMethods::A
+ ruby_version_is "2.7.3" do
+ context "after aliasing an inherited method" do
+ it "returns the expected super_method" do
+ method = MethodSpecs::InheritedMethods::C.instance_method(:meow)
+ method.super_method.owner.should == MethodSpecs::InheritedMethods::A
+ end
end
end
end
diff --git a/spec/ruby/core/warning/element_reference_spec.rb b/spec/ruby/core/warning/element_reference_spec.rb
index c0ed37ef13..67728ca0f6 100644
--- a/spec/ruby/core/warning/element_reference_spec.rb
+++ b/spec/ruby/core/warning/element_reference_spec.rb
@@ -1,19 +1,10 @@
require_relative '../../spec_helper'
describe "Warning.[]" do
- it "returns default values for categories :deprecated and :experimental" do
- # If any warning options were set on the Ruby that will be executed, then
- # it's possible this test will fail. In this case we will skip this test.
- skip if ruby_exe.any? { |opt| opt.start_with?("-W") }
-
- ruby_exe('p [Warning[:deprecated], Warning[:experimental]]').chomp.should == "[false, true]"
- ruby_exe('p [Warning[:deprecated], Warning[:experimental]]', options: "-w").chomp.should == "[true, true]"
- end
-
- ruby_version_is '3.3' do
- it "returns default values for :performance category" do
- ruby_exe('p Warning[:performance]').chomp.should == "false"
- ruby_exe('p Warning[:performance]', options: "-w").chomp.should == "false"
+ ruby_version_is '2.7.2' do
+ it "returns default values for categories :deprecated and :experimental" do
+ ruby_exe('p Warning[:deprecated]').chomp.should == "false"
+ ruby_exe('p Warning[:experimental]').chomp.should == "true"
end
end
diff --git a/spec/ruby/core/warning/element_set_spec.rb b/spec/ruby/core/warning/element_set_spec.rb
index d59a7d4c9e..d20ee215ad 100644
--- a/spec/ruby/core/warning/element_set_spec.rb
+++ b/spec/ruby/core/warning/element_set_spec.rb
@@ -8,7 +8,13 @@ describe "Warning.[]=" do
describe ":experimental" do
before do
- @src = 'warn "This is experimental warning.", category: :experimental'
+ ruby_version_is ""..."3.0" do
+ @src = 'case [0, 1]; in [a, b]; end'
+ end
+
+ ruby_version_is "3.0" do
+ @src = 'warn "This is experimental warning.", category: :experimental'
+ end
end
it "emits and suppresses warnings for :experimental" do
@@ -17,18 +23,6 @@ describe "Warning.[]=" do
end
end
- ruby_version_is '3.3' do
- it "enables or disables performance warnings" do
- original = Warning[:performance]
- begin
- Warning[:performance] = !original
- Warning[:performance].should == !original
- ensure
- Warning[:performance] = original
- end
- end
- end
-
it "raises for unknown category" do
-> { Warning[:noop] = false }.should raise_error(ArgumentError, /unknown category: noop/)
end
diff --git a/spec/ruby/core/warning/performance_warning_spec.rb b/spec/ruby/core/warning/performance_warning_spec.rb
deleted file mode 100644
index ab0badcd3d..0000000000
--- a/spec/ruby/core/warning/performance_warning_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative '../../spec_helper'
-
-
-describe "Performance warnings" do
- guard -> { ruby_version_is("3.4") || RUBY_ENGINE == "truffleruby" } do
- # Optimising Integer, Float or Symbol methods is kind of implementation detail
- # but multiple implementations do so. So it seems reasonable to have a test case
- # for at least one such common method.
- # See https://bugs.ruby-lang.org/issues/20429
- context "when redefined optimised methods" do
- it "emits performance warning for redefining Integer#+" do
- code = <<~CODE
- Warning[:performance] = true
-
- class Integer
- ORIG_METHOD = instance_method(:+)
-
- def +(...)
- ORIG_METHOD.bind(self).call(...)
- end
- end
- CODE
-
- ruby_exe(code, args: "2>&1").should.include?("warning: Redefining 'Integer#+' disables interpreter and JIT optimizations")
- end
- end
- end
-end
diff --git a/spec/ruby/core/warning/warn_spec.rb b/spec/ruby/core/warning/warn_spec.rb
index 1c21fe29e0..5ccff3aa2b 100644
--- a/spec/ruby/core/warning/warn_spec.rb
+++ b/spec/ruby/core/warning/warn_spec.rb
@@ -51,109 +51,40 @@ describe "Warning.warn" do
end
end
- it "is called by Kernel.warn with nil category keyword" do
- Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
- verbose = $VERBOSE
- $VERBOSE = false
- begin
- Kernel.warn("Chunky bacon!")
- ensure
- $VERBOSE = verbose
- end
- end
-
- it "is called by Kernel.warn with given category keyword converted to a symbol" do
- Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated)
- verbose = $VERBOSE
- $VERBOSE = false
- begin
- Kernel.warn("Chunky bacon!", category: "deprecated")
- ensure
- $VERBOSE = verbose
- end
- end
-
- it "warns when category is :deprecated and Warning[:deprecated] is true" do
- warn_deprecated = Warning[:deprecated]
- Warning[:deprecated] = true
- begin
- -> {
- Warning.warn("foo", category: :deprecated)
- }.should complain("foo")
- ensure
- Warning[:deprecated] = warn_deprecated
- end
- end
-
- it "warns when category is :experimental and Warning[:experimental] is true" do
- warn_experimental = Warning[:experimental]
- Warning[:experimental] = true
- begin
- -> {
- Warning.warn("foo", category: :experimental)
- }.should complain("foo")
- ensure
- Warning[:experimental] = warn_experimental
- end
- end
-
- it "doesn't print message when category is :deprecated but Warning[:deprecated] is false" do
- warn_deprecated = Warning[:deprecated]
- Warning[:deprecated] = false
- begin
- -> {
- Warning.warn("foo", category: :deprecated)
- }.should_not complain
- ensure
- Warning[:deprecated] = warn_deprecated
- end
- end
-
- it "doesn't print message when category is :experimental but Warning[:experimental] is false" do
- warn_experimental = Warning[:experimental]
- Warning[:experimental] = false
- begin
- -> {
- Warning.warn("foo", category: :experimental)
- }.should_not complain
- ensure
- Warning[:experimental] = warn_experimental
- end
- end
-
- ruby_bug '#19530', ''...'3.4' do
- it "isn't called by Kernel.warn when category is :deprecated but Warning[:deprecated] is false" do
- warn_deprecated = Warning[:deprecated]
+ ruby_version_is '3.0' do
+ it "is called by Kernel.warn with nil category keyword" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
+ verbose = $VERBOSE
+ $VERBOSE = false
begin
- Warning[:deprecated] = false
- Warning.should_not_receive(:warn)
- Kernel.warn("foo", category: :deprecated)
+ Kernel.warn("Chunky bacon!")
ensure
- Warning[:deprecated] = warn_deprecated
+ $VERBOSE = verbose
end
end
- it "isn't called by Kernel.warn when category is :experimental but Warning[:experimental] is false" do
- warn_experimental = Warning[:experimental]
+ it "is called by Kernel.warn with given category keyword converted to a symbol" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated)
+ verbose = $VERBOSE
+ $VERBOSE = false
begin
- Warning[:experimental] = false
- Warning.should_not_receive(:warn)
- Kernel.warn("foo", category: :experimental)
+ Kernel.warn("Chunky bacon!", category: "deprecated")
ensure
- Warning[:experimental] = warn_experimental
+ $VERBOSE = verbose
end
end
end
- it "prints the message when VERBOSE is false" do
- -> { Warning.warn("foo") }.should complain("foo")
- end
-
- it "prints the message when VERBOSE is nil" do
- -> { Warning.warn("foo") }.should complain("foo", verbose: nil)
- end
-
- it "prints the message when VERBOSE is true" do
- -> { Warning.warn("foo") }.should complain("foo", verbose: true)
+ ruby_version_is ''...'3.0' do
+ it "is called by Kernel.warn" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n")
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!")
+ ensure
+ $VERBOSE = verbose
+ end
+ end
end
end
diff --git a/spec/ruby/default.mspec b/spec/ruby/default.mspec
index 1e8f8893aa..a0dc69c03d 100644
--- a/spec/ruby/default.mspec
+++ b/spec/ruby/default.mspec
@@ -1,4 +1,3 @@
-# -*- ruby -*-
# Configuration file for Ruby >= 2.0 implementations.
class MSpecScript
diff --git a/spec/ruby/fixtures/code/d/load_fixture.rb.rb b/spec/ruby/fixtures/code/d/load_fixture.rb.rb
deleted file mode 100644
index 7e9217729a..0000000000
--- a/spec/ruby/fixtures/code/d/load_fixture.rb.rb
+++ /dev/null
@@ -1 +0,0 @@
-ScratchPad << :rbrb
diff --git a/spec/ruby/fixtures/constants.rb b/spec/ruby/fixtures/constants.rb
index ffe45fb1f6..47a8e87e56 100644
--- a/spec/ruby/fixtures/constants.rb
+++ b/spec/ruby/fixtures/constants.rb
@@ -44,7 +44,6 @@ module ConstantSpecs
# Included in ParentA
module ModuleB
- LINE = __LINE__ - 1
CS_CONST10 = :const10_9
CS_CONST11 = :const11_2
CS_CONST12 = :const12_1
@@ -88,7 +87,7 @@ module ConstantSpecs
# are run.
class ClassA
- LINE = __LINE__ - 1
+ CS_CLASS_A_LINE = __LINE__ - 1
CS_CONST10 = :const10_10
CS_CONST10_LINE = __LINE__ - 1
CS_CONST16 = :const16
diff --git a/spec/ruby/fixtures/io.rb b/spec/ruby/fixtures/io.rb
deleted file mode 100644
index 87ebbbb2bd..0000000000
--- a/spec/ruby/fixtures/io.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-module IOSpec
- def self.exhaust_write_buffer(io)
- written = 0
- buf = " " * 4096
-
- while true
- written += io.write_nonblock(buf)
- end
- rescue Errno::EAGAIN, Errno::EWOULDBLOCK
- written
- end
-end
diff --git a/spec/ruby/language/END_spec.rb b/spec/ruby/language/END_spec.rb
index c84f0cc9ac..762a8db0c0 100644
--- a/spec/ruby/language/END_spec.rb
+++ b/spec/ruby/language/END_spec.rb
@@ -1,33 +1,15 @@
require_relative '../spec_helper'
-require_relative '../shared/kernel/at_exit'
describe "The END keyword" do
- it_behaves_like :kernel_at_exit, :END
-
it "runs only once for multiple calls" do
ruby_exe("10.times { END { puts 'foo' }; } ").should == "foo\n"
end
- it "is affected by the toplevel assignment" do
- ruby_exe("foo = 'foo'; END { puts foo }").should == "foo\n"
- end
-
- it "warns when END is used in a method" do
- ruby_exe(<<~ruby, args: "2>&1").should =~ /warning: END in method; use at_exit/
- def foo
- END { }
- end
- ruby
+ it "runs last in a given code unit" do
+ ruby_exe("END { puts 'bar' }; puts'foo'; ").should == "foo\nbar\n"
end
- context "END blocks and at_exit callbacks are mixed" do
- it "runs them all in reverse order of registration" do
- ruby_exe(<<~ruby).should == "at_exit#2\nEND#2\nat_exit#1\nEND#1\n"
- END { puts 'END#1' }
- at_exit { puts 'at_exit#1' }
- END { puts 'END#2' }
- at_exit { puts 'at_exit#2' }
- ruby
- end
+ it "runs multiple ends in LIFO order" do
+ ruby_exe("END { puts 'foo' }; END { puts 'bar' }").should == "bar\nfoo\n"
end
end
diff --git a/spec/ruby/language/alias_spec.rb b/spec/ruby/language/alias_spec.rb
index 61fddb0184..c353390679 100644
--- a/spec/ruby/language/alias_spec.rb
+++ b/spec/ruby/language/alias_spec.rb
@@ -52,15 +52,6 @@ describe "The alias keyword" do
@obj.a.should == 5
end
- it "works with an interpolated symbol with non-literal embedded expression on the left-hand side" do
- @meta.class_eval do
- eval %Q{
- alias :"#{'a' + ''.to_s}" value
- }
- end
- @obj.a.should == 5
- end
-
it "works with a simple symbol on the right-hand side" do
@meta.class_eval do
alias a :value
@@ -89,15 +80,6 @@ describe "The alias keyword" do
@obj.a.should == 5
end
- it "works with an interpolated symbol with non-literal embedded expression on the right-hand side" do
- @meta.class_eval do
- eval %Q{
- alias a :"#{'value' + ''.to_s}"
- }
- end
- @obj.a.should == 5
- end
-
it "adds the new method to the list of methods" do
original_methods = @obj.methods
@meta.class_eval do
@@ -252,7 +234,7 @@ describe "The alias keyword" do
it "on top level defines the alias on Object" do
# because it defines on the default definee / current module
- ruby_exe("def foo; end; alias bla foo; print method(:bla).owner").should == "Object"
+ ruby_exe("def foo; end; alias bla foo; print method(:bla).owner", escape: true).should == "Object"
end
it "raises a NameError when passed a missing name" do
diff --git a/spec/ruby/language/assignments_spec.rb b/spec/ruby/language/assignments_spec.rb
deleted file mode 100644
index 2773508d8d..0000000000
--- a/spec/ruby/language/assignments_spec.rb
+++ /dev/null
@@ -1,529 +0,0 @@
-require_relative '../spec_helper'
-
-# Should be synchronized with spec/ruby/language/optional_assignments_spec.rb
-# Some specs for assignments are located in language/variables_spec.rb
-describe 'Assignments' do
- describe 'using =' do
- describe 'evaluation order' do
- it 'evaluates expressions left to right when assignment with an accessor' do
- object = Object.new
- def object.a=(value) end
- ScratchPad.record []
-
- (ScratchPad << :receiver; object).a = (ScratchPad << :rhs; :value)
- ScratchPad.recorded.should == [:receiver, :rhs]
- end
-
- it 'evaluates expressions left to right when assignment with a #[]=' do
- object = Object.new
- def object.[]=(_, _) end
- ScratchPad.record []
-
- (ScratchPad << :receiver; object)[(ScratchPad << :argument; :a)] = (ScratchPad << :rhs; :value)
- ScratchPad.recorded.should == [:receiver, :argument, :rhs]
- end
-
- # similar tests for evaluation order are located in language/constants_spec.rb
- ruby_version_is ''...'3.2' do
- it 'evaluates expressions right to left when assignment with compounded constant' do
- m = Module.new
- ScratchPad.record []
-
- (ScratchPad << :module; m)::A = (ScratchPad << :rhs; :value)
- ScratchPad.recorded.should == [:rhs, :module]
- end
- end
-
- ruby_version_is '3.2' do
- it 'evaluates expressions left to right when assignment with compounded constant' do
- m = Module.new
- ScratchPad.record []
-
- (ScratchPad << :module; m)::A = (ScratchPad << :rhs; :value)
- ScratchPad.recorded.should == [:module, :rhs]
- end
- end
-
- it 'raises TypeError after evaluation of right-hand-side when compounded constant module is not a module' do
- ScratchPad.record []
-
- -> {
- (:not_a_module)::A = (ScratchPad << :rhs; :value)
- }.should raise_error(TypeError)
-
- ScratchPad.recorded.should == [:rhs]
- end
- end
- end
-
- describe 'using +=' do
- describe 'using an accessor' do
- before do
- klass = Class.new { attr_accessor :b }
- @a = klass.new
- end
-
- it 'does evaluate receiver only once when assigns' do
- ScratchPad.record []
- @a.b = 1
-
- (ScratchPad << :evaluated; @a).b += 2
-
- ScratchPad.recorded.should == [:evaluated]
- @a.b.should == 3
- end
-
- it 'ignores method visibility when receiver is self' do
- klass_with_private_methods = Class.new do
- def initialize(n) @a = n end
- def public_method(n); self.a += n end
- private
- def a; @a end
- def a=(n) @a = n; 42 end
- end
-
- a = klass_with_private_methods.new(0)
- a.public_method(2).should == 2
- end
- end
-
- describe 'using a #[]' do
- before do
- klass = Class.new do
- def [](k)
- @hash ||= {}
- @hash[k]
- end
-
- def []=(k, v)
- @hash ||= {}
- @hash[k] = v
- 7
- end
- end
- @b = klass.new
- end
-
- it 'evaluates receiver only once when assigns' do
- ScratchPad.record []
- a = {k: 1}
-
- (ScratchPad << :evaluated; a)[:k] += 2
-
- ScratchPad.recorded.should == [:evaluated]
- a[:k].should == 3
- end
-
- it 'ignores method visibility when receiver is self' do
- klass_with_private_methods = Class.new do
- def initialize(h) @a = h end
- def public_method(k, n); self[k] += n end
- private
- def [](k) @a[k] end
- def []=(k, v) @a[k] = v; 42 end
- end
-
- a = klass_with_private_methods.new(k: 0)
- a.public_method(:k, 2).should == 2
- end
-
- context 'splatted argument' do
- it 'correctly handles it' do
- @b[:m] = 10
- (@b[*[:m]] += 10).should == 20
- @b[:m].should == 20
-
- @b[:n] = 10
- (@b[*(1; [:n])] += 10).should == 20
- @b[:n].should == 20
-
- @b[:k] = 10
- (@b[*begin 1; [:k] end] += 10).should == 20
- @b[:k].should == 20
- end
-
- it 'calls #to_a only once' do
- k = Object.new
- def k.to_a
- ScratchPad << :to_a
- [:k]
- end
-
- ScratchPad.record []
- @b[:k] = 10
- (@b[*k] += 10).should == 20
- @b[:k].should == 20
- ScratchPad.recorded.should == [:to_a]
- end
-
- it 'correctly handles a nested splatted argument' do
- @b[:k] = 10
- (@b[*[*[:k]]] += 10).should == 20
- @b[:k].should == 20
- end
-
- it 'correctly handles multiple nested splatted arguments' do
- klass_with_multiple_parameters = Class.new do
- def [](k1, k2, k3)
- @hash ||= {}
- @hash[:"#{k1}#{k2}#{k3}"]
- end
-
- def []=(k1, k2, k3, v)
- @hash ||= {}
- @hash[:"#{k1}#{k2}#{k3}"] = v
- 7
- end
- end
- a = klass_with_multiple_parameters.new
-
- a[:a, :b, :c] = 10
- (a[*[:a], *[:b], *[:c]] += 10).should == 20
- a[:a, :b, :c].should == 20
- end
- end
- end
-
- describe 'using compounded constants' do
- it 'causes side-effects of the module part to be applied only once (when assigns)' do
- module ConstantSpecs
- OpAssignTrue = 1
- end
-
- suppress_warning do # already initialized constant
- x = 0
- (x += 1; ConstantSpecs)::OpAssignTrue += 2
- x.should == 1
- ConstantSpecs::OpAssignTrue.should == 3
- end
-
- ConstantSpecs.send :remove_const, :OpAssignTrue
- end
- end
- end
-end
-
-# generic cases
-describe 'Multiple assignments' do
- it 'assigns multiple targets when assignment with an accessor' do
- object = Object.new
- class << object
- attr_accessor :a, :b
- end
-
- object.a, object.b = :a, :b
-
- object.a.should == :a
- object.b.should == :b
- end
-
- it 'assigns multiple targets when assignment with a nested accessor' do
- object = Object.new
- class << object
- attr_accessor :a, :b
- end
-
- (object.a, object.b), c = [:a, :b], nil
-
- object.a.should == :a
- object.b.should == :b
- end
-
- it 'assigns multiple targets when assignment with a #[]=' do
- object = Object.new
- class << object
- def []=(k, v) (@h ||= {})[k] = v; end
- def [](k) (@h ||= {})[k]; end
- end
-
- object[:a], object[:b] = :a, :b
-
- object[:a].should == :a
- object[:b].should == :b
- end
-
- it 'assigns multiple targets when assignment with a nested #[]=' do
- object = Object.new
- class << object
- def []=(k, v) (@h ||= {})[k] = v; end
- def [](k) (@h ||= {})[k]; end
- end
-
- (object[:a], object[:b]), c = [:v1, :v2], nil
-
- object[:a].should == :v1
- object[:b].should == :v2
- end
-
- it 'assigns multiple targets when assignment with compounded constant' do
- m = Module.new
-
- m::A, m::B = :a, :b
-
- m::A.should == :a
- m::B.should == :b
- end
-
- it 'assigns multiple targets when assignment with a nested compounded constant' do
- m = Module.new
-
- (m::A, m::B), c = [:a, :b], nil
-
- m::A.should == :a
- m::B.should == :b
- end
-end
-
-describe 'Multiple assignments' do
- describe 'evaluation order' do
- ruby_version_is ''...'3.1' do
- it 'evaluates expressions right to left when assignment with an accessor' do
- object = Object.new
- def object.a=(value) end
- ScratchPad.record []
-
- (ScratchPad << :a; object).a, (ScratchPad << :b; object).a = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
- ScratchPad.recorded.should == [:c, :d, :a, :b]
- end
-
- it 'evaluates expressions right to left when assignment with a nested accessor' do
- object = Object.new
- def object.a=(value) end
- ScratchPad.record []
-
- ((ScratchPad << :a; object).a, foo), bar = [(ScratchPad << :b; :b)]
- ScratchPad.recorded.should == [:b, :a]
- end
- end
-
- ruby_version_is '3.1' do
- it 'evaluates expressions left to right when assignment with an accessor' do
- object = Object.new
- def object.a=(value) end
- ScratchPad.record []
-
- (ScratchPad << :a; object).a, (ScratchPad << :b; object).a = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
- ScratchPad.recorded.should == [:a, :b, :c, :d]
- end
-
- it 'evaluates expressions left to right when assignment with a nested accessor' do
- object = Object.new
- def object.a=(value) end
- ScratchPad.record []
-
- ((ScratchPad << :a; object).a, foo), bar = [(ScratchPad << :b; :b)]
- ScratchPad.recorded.should == [:a, :b]
- end
-
- it 'evaluates expressions left to right when assignment with a deeply nested accessor' do
- o = Object.new
- def o.a=(value) end
- def o.b=(value) end
- def o.c=(value) end
- def o.d=(value) end
- def o.e=(value) end
- def o.f=(value) end
- ScratchPad.record []
-
- (ScratchPad << :a; o).a,
- ((ScratchPad << :b; o).b,
- ((ScratchPad << :c; o).c, (ScratchPad << :d; o).d),
- (ScratchPad << :e; o).e),
- (ScratchPad << :f; o).f = (ScratchPad << :value; :value)
-
- ScratchPad.recorded.should == [:a, :b, :c, :d, :e, :f, :value]
- end
- end
-
- ruby_version_is ''...'3.1' do
- it 'evaluates expressions right to left when assignment with a #[]=' do
- object = Object.new
- def object.[]=(_, _) end
- ScratchPad.record []
-
- (ScratchPad << :a; object)[(ScratchPad << :b; :b)], (ScratchPad << :c; object)[(ScratchPad << :d; :d)] = (ScratchPad << :e; :e), (ScratchPad << :f; :f)
- ScratchPad.recorded.should == [:e, :f, :a, :b, :c, :d]
- end
-
- it 'evaluates expressions right to left when assignment with a nested #[]=' do
- object = Object.new
- def object.[]=(_, _) end
- ScratchPad.record []
-
- ((ScratchPad << :a; object)[(ScratchPad << :b; :b)], foo), bar = [(ScratchPad << :c; :c)]
- ScratchPad.recorded.should == [:c, :a, :b]
- end
- end
-
- ruby_version_is '3.1' do
- it 'evaluates expressions left to right when assignment with a #[]=' do
- object = Object.new
- def object.[]=(_, _) end
- ScratchPad.record []
-
- (ScratchPad << :a; object)[(ScratchPad << :b; :b)], (ScratchPad << :c; object)[(ScratchPad << :d; :d)] = (ScratchPad << :e; :e), (ScratchPad << :f; :f)
- ScratchPad.recorded.should == [:a, :b, :c, :d, :e, :f]
- end
-
- it 'evaluates expressions left to right when assignment with a nested #[]=' do
- object = Object.new
- def object.[]=(_, _) end
- ScratchPad.record []
-
- ((ScratchPad << :a; object)[(ScratchPad << :b; :b)], foo), bar = [(ScratchPad << :c; :c)]
- ScratchPad.recorded.should == [:a, :b, :c]
- end
-
- it 'evaluates expressions left to right when assignment with a deeply nested #[]=' do
- o = Object.new
- def o.[]=(_, _) end
- ScratchPad.record []
-
- (ScratchPad << :ra; o)[(ScratchPad << :aa; :aa)],
- ((ScratchPad << :rb; o)[(ScratchPad << :ab; :ab)],
- ((ScratchPad << :rc; o)[(ScratchPad << :ac; :ac)], (ScratchPad << :rd; o)[(ScratchPad << :ad; :ad)]),
- (ScratchPad << :re; o)[(ScratchPad << :ae; :ae)]),
- (ScratchPad << :rf; o)[(ScratchPad << :af; :af)] = (ScratchPad << :value; :value)
-
- ScratchPad.recorded.should == [:ra, :aa, :rb, :ab, :rc, :ac, :rd, :ad, :re, :ae, :rf, :af, :value]
- end
- end
-
- ruby_version_is ''...'3.2' do
- it 'evaluates expressions right to left when assignment with compounded constant' do
- m = Module.new
- ScratchPad.record []
-
- (ScratchPad << :a; m)::A, (ScratchPad << :b; m)::B = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
- ScratchPad.recorded.should == [:c, :d, :a, :b]
- end
- end
-
- ruby_version_is '3.2' do
- it 'evaluates expressions left to right when assignment with compounded constant' do
- m = Module.new
- ScratchPad.record []
-
- (ScratchPad << :a; m)::A, (ScratchPad << :b; m)::B = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
- ScratchPad.recorded.should == [:a, :b, :c, :d]
- end
-
- it 'evaluates expressions left to right when assignment with a nested compounded constant' do
- m = Module.new
- ScratchPad.record []
-
- ((ScratchPad << :a; m)::A, foo), bar = [(ScratchPad << :b; :b)]
- ScratchPad.recorded.should == [:a, :b]
- end
-
- it 'evaluates expressions left to right when assignment with deeply nested compounded constants' do
- m = Module.new
- ScratchPad.record []
-
- (ScratchPad << :a; m)::A,
- ((ScratchPad << :b; m)::B,
- ((ScratchPad << :c; m)::C, (ScratchPad << :d; m)::D),
- (ScratchPad << :e; m)::E),
- (ScratchPad << :f; m)::F = (ScratchPad << :value; :value)
-
- ScratchPad.recorded.should == [:a, :b, :c, :d, :e, :f, :value]
- end
- end
- end
-
- context 'when assignment with method call and receiver is self' do
- it 'assigns values correctly when assignment with accessor' do
- object = Object.new
- class << object
- attr_accessor :a, :b
-
- def assign(v1, v2)
- self.a, self.b = v1, v2
- end
- end
-
- object.assign :v1, :v2
- object.a.should == :v1
- object.b.should == :v2
- end
-
- it 'evaluates expressions right to left when assignment with a nested accessor' do
- object = Object.new
- class << object
- attr_accessor :a, :b
-
- def assign(v1, v2)
- (self.a, self.b), c = [v1, v2], nil
- end
- end
-
- object.assign :v1, :v2
- object.a.should == :v1
- object.b.should == :v2
- end
-
- it 'assigns values correctly when assignment with a #[]=' do
- object = Object.new
- class << object
- def []=(key, v)
- @h ||= {}
- @h[key] = v
- end
-
- def [](key)
- (@h || {})[key]
- end
-
- def assign(k1, v1, k2, v2)
- self[k1], self[k2] = v1, v2
- end
- end
-
- object.assign :k1, :v1, :k2, :v2
- object[:k1].should == :v1
- object[:k2].should == :v2
- end
-
- it 'assigns values correctly when assignment with a nested #[]=' do
- object = Object.new
- class << object
- def []=(key, v)
- @h ||= {}
- @h[key] = v
- end
-
- def [](key)
- (@h || {})[key]
- end
-
- def assign(k1, v1, k2, v2)
- (self[k1], self[k2]), c = [v1, v2], nil
- end
- end
-
- object.assign :k1, :v1, :k2, :v2
- object[:k1].should == :v1
- object[:k2].should == :v2
- end
-
- it 'assigns values correctly when assignment with compounded constant' do
- m = Module.new
- m.module_exec do
- self::A, self::B = :v1, :v2
- end
-
- m::A.should == :v1
- m::B.should == :v2
- end
-
- it 'assigns values correctly when assignment with a nested compounded constant' do
- m = Module.new
- m.module_exec do
- (self::A, self::B), c = [:v1, :v2], nil
- end
-
- m::A.should == :v1
- m::B.should == :v2
- end
- end
-end
diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb
index cf0931b688..8488b945d5 100644
--- a/spec/ruby/language/block_spec.rb
+++ b/spec/ruby/language/block_spec.rb
@@ -40,42 +40,10 @@ describe "A block yielded a single" do
m([1, 2]) { |a=5, b, c, d| [a, b, c, d] }.should == [5, 1, 2, nil]
end
- it "assigns elements to pre arguments" do
- m([1, 2]) { |a, b, c, d=5| [a, b, c, d] }.should == [1, 2, nil, 5]
- end
-
- it "assigns elements to pre and post arguments" do
- m([1 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 5, 6, nil, nil]
- m([1, 2 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 5, 6, 2, nil]
- m([1, 2, 3 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 5, 6, 2, 3]
- m([1, 2, 3, 4 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 2, 6, 3, 4]
- m([1, 2, 3, 4, 5 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 2, 3, 4, 5]
- m([1, 2, 3, 4, 5, 6]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 2, 3, 4, 5]
- end
-
- it "assigns elements to pre and post arguments when *rest is present" do
- m([1 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 5, 6, [], nil, nil]
- m([1, 2 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 5, 6, [], 2, nil]
- m([1, 2, 3 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 5, 6, [], 2, 3]
- m([1, 2, 3, 4 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 2, 6, [], 3, 4]
- m([1, 2, 3, 4, 5 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 2, 3, [], 4, 5]
- m([1, 2, 3, 4, 5, 6]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 2, 3, [4], 5, 6]
- end
-
ruby_version_is "3.2" do
it "does not autosplat single argument to required arguments when a keyword rest argument is present" do
m([1, 2]) { |a, **k| [a, k] }.should == [[1, 2], {}]
end
-
- it "does not autosplat single argument to required arguments when keyword arguments are present" do
- m([1, 2]) { |a, b: :b, c: :c| [a, b, c] }.should == [[1, 2], :b, :c]
- end
-
- it "raises error when required keyword arguments are present" do
- -> {
- m([1, 2]) { |a, b:, c:| [a, b, c] }
- }.should raise_error(ArgumentError, "missing keywords: :b, :c")
- end
end
ruby_version_is ''..."3.2" do
@@ -83,30 +51,68 @@ describe "A block yielded a single" do
it "autosplats single argument to required arguments when a keyword rest argument is present" do
m([1, 2]) { |a, **k| [a, k] }.should == [1, {}]
end
+ end
- it "autosplats single argument to required arguments when optional keyword arguments are present" do
- m([1, 2]) { |a, b: :b, c: :c| [a, b, c] }.should == [1, :b, :c]
+ ruby_version_is ''..."3.0" do
+ it "assigns elements to mixed argument types" do
+ suppress_keyword_warning do
+ result = m([1, 2, 3, {x: 9}]) { |a, b=5, *c, d, e: 2, **k| [a, b, c, d, e, k] }
+ result.should == [1, 2, [], 3, 2, {x: 9}]
+ end
end
- it "raises error when required keyword arguments are present" do
- -> {
- m([1, 2]) { |a, b:, c:| [a, b, c] }
- }.should raise_error(ArgumentError, "missing keywords: :b, :c")
+ it "assigns symbol keys from a Hash to keyword arguments" do
+ suppress_keyword_warning do
+ result = m(["a" => 1, a: 10]) { |a=nil, **b| [a, b] }
+ result.should == [{"a" => 1}, a: 10]
+ end
+ end
+
+ it "assigns symbol keys from a Hash returned by #to_hash to keyword arguments" do
+ suppress_keyword_warning do
+ obj = mock("coerce block keyword arguments")
+ obj.should_receive(:to_hash).and_return({"a" => 1, b: 2})
+
+ result = m([obj]) { |a=nil, **b| [a, b] }
+ result.should == [{"a" => 1}, b: 2]
+ end
end
end
- it "assigns elements to mixed argument types" do
- result = m([1, 2, 3, {x: 9}]) { |a, b=5, *c, d, e: 2, **k| [a, b, c, d, e, k] }
- result.should == [1, 2, [3], {x: 9}, 2, {}]
+ ruby_version_is "3.0" do
+ it "assigns elements to mixed argument types" do
+ result = m([1, 2, 3, {x: 9}]) { |a, b=5, *c, d, e: 2, **k| [a, b, c, d, e, k] }
+ result.should == [1, 2, [3], {x: 9}, 2, {}]
+ end
+
+ it "does not treat final Hash as keyword arguments and does not autosplat" do
+ result = m(["a" => 1, a: 10]) { |a=nil, **b| [a, b] }
+ result.should == [[{"a" => 1, a: 10}], {}]
+ end
+
+ it "does not call #to_hash on final argument to get keyword arguments and does not autosplat" do
+ suppress_keyword_warning do
+ obj = mock("coerce block keyword arguments")
+ obj.should_not_receive(:to_hash)
+
+ result = m([obj]) { |a=nil, **b| [a, b] }
+ result.should == [[obj], {}]
+ end
+ end
end
- it "does not treat final Hash as keyword arguments and does not autosplat" do
- result = m(["a" => 1, a: 10]) { |a=nil, **b| [a, b] }
- result.should == [[{"a" => 1, a: 10}], {}]
+ ruby_version_is ""...'3.0' do
+ it "calls #to_hash on the argument but ignores result when optional argument and keyword argument accepted" do
+ obj = mock("coerce block keyword arguments")
+ obj.should_receive(:to_hash).and_return({"a" => 1, "b" => 2})
+
+ result = m([obj]) { |a=nil, **b| [a, b] }
+ result.should == [obj, {}]
+ end
end
- it "does not call #to_hash on final argument to get keyword arguments and does not autosplat" do
- suppress_keyword_warning do
+ ruby_version_is "3.0" do
+ it "does not call #to_hash on the argument when optional argument and keyword argument accepted and does not autosplat" do
obj = mock("coerce block keyword arguments")
obj.should_not_receive(:to_hash)
@@ -115,42 +121,102 @@ describe "A block yielded a single" do
end
end
- it "does not call #to_hash on the argument when optional argument and keyword argument accepted and does not autosplat" do
- obj = mock("coerce block keyword arguments")
- obj.should_not_receive(:to_hash)
+ describe "when non-symbol keys are in a keyword arguments Hash" do
+ ruby_version_is ""..."3.0" do
+ it "separates non-symbol keys and symbol keys" do
+ suppress_keyword_warning do
+ result = m(["a" => 10, b: 2]) { |a=nil, **b| [a, b] }
+ result.should == [{"a" => 10}, {b: 2}]
+ end
+ end
+ end
+ ruby_version_is "3.0" do
+ it "does not separate non-symbol keys and symbol keys and does not autosplat" do
+ suppress_keyword_warning do
+ result = m(["a" => 10, b: 2]) { |a=nil, **b| [a, b] }
+ result.should == [[{"a" => 10, b: 2}], {}]
+ end
+ end
+ end
+ end
- result = m([obj]) { |a=nil, **b| [a, b] }
- result.should == [[obj], {}]
+ ruby_version_is ""..."3.0" do
+ it "does not treat hashes with string keys as keyword arguments" do
+ result = m(["a" => 10]) { |a = nil, **b| [a, b] }
+ result.should == [{"a" => 10}, {}]
+ end
end
- describe "when non-symbol keys are in a keyword arguments Hash" do
- it "does not separate non-symbol keys and symbol keys and does not autosplat" do
+ ruby_version_is "3.0" do
+ it "does not treat hashes with string keys as keyword arguments and does not autosplat" do
+ result = m(["a" => 10]) { |a = nil, **b| [a, b] }
+ result.should == [[{"a" => 10}], {}]
+ end
+ end
+
+ ruby_version_is ''...'3.0' do
+ it "calls #to_hash on the last element if keyword arguments are present" do
suppress_keyword_warning do
- result = m(["a" => 10, b: 2]) { |a=nil, **b| [a, b] }
- result.should == [[{"a" => 10, b: 2}], {}]
+ obj = mock("destructure block keyword arguments")
+ obj.should_receive(:to_hash).and_return({x: 9})
+
+ result = m([1, 2, 3, obj]) { |a, *b, c, **k| [a, b, c, k] }
+ result.should == [1, [2], 3, {x: 9}]
end
end
- end
- it "does not treat hashes with string keys as keyword arguments and does not autosplat" do
- result = m(["a" => 10]) { |a = nil, **b| [a, b] }
- result.should == [[{"a" => 10}], {}]
- end
+ it "assigns the last element to a non-keyword argument if #to_hash returns nil" do
+ suppress_keyword_warning do
+ obj = mock("destructure block keyword arguments")
+ obj.should_receive(:to_hash).and_return(nil)
+
+ result = m([1, 2, 3, obj]) { |a, *b, c, **k| [a, b, c, k] }
+ result.should == [1, [2, 3], obj, {}]
+ end
+ end
+
+ it "calls #to_hash on the last element when there are more arguments than parameters" do
+ suppress_keyword_warning do
+ x = mock("destructure matching block keyword argument")
+ x.should_receive(:to_hash).and_return({x: 9})
+
+ result = m([1, 2, 3, {y: 9}, 4, 5, x]) { |a, b=5, c, **k| [a, b, c, k] }
+ result.should == [1, 2, 3, {x: 9}]
+ end
+ end
+
+ it "raises a TypeError if #to_hash does not return a Hash" do
+ obj = mock("destructure block keyword arguments")
+ obj.should_receive(:to_hash).and_return(1)
+
+ -> { m([1, 2, 3, obj]) { |a, *b, c, **k| } }.should raise_error(TypeError)
+ end
- it "does not call #to_hash on the last element if keyword arguments are present" do
- obj = mock("destructure block keyword arguments")
- obj.should_not_receive(:to_hash)
+ it "raises the error raised inside #to_hash" do
+ obj = mock("destructure block keyword arguments")
+ error = RuntimeError.new("error while converting to a hash")
+ obj.should_receive(:to_hash).and_raise(error)
- result = m([1, 2, 3, obj]) { |a, *b, c, **k| [a, b, c, k] }
- result.should == [1, [2, 3], obj, {}]
+ -> { m([1, 2, 3, obj]) { |a, *b, c, **k| } }.should raise_error(error)
+ end
end
- it "does not call #to_hash on the last element when there are more arguments than parameters" do
- x = mock("destructure matching block keyword argument")
- x.should_not_receive(:to_hash)
+ ruby_version_is '3.0' do
+ it "does not call #to_hash on the last element if keyword arguments are present" do
+ obj = mock("destructure block keyword arguments")
+ obj.should_not_receive(:to_hash)
- result = m([1, 2, 3, {y: 9}, 4, 5, x]) { |a, b=5, c, **k| [a, b, c, k] }
- result.should == [1, 2, 3, {}]
+ result = m([1, 2, 3, obj]) { |a, *b, c, **k| [a, b, c, k] }
+ result.should == [1, [2, 3], obj, {}]
+ end
+
+ it "does not call #to_hash on the last element when there are more arguments than parameters" do
+ x = mock("destructure matching block keyword argument")
+ x.should_not_receive(:to_hash)
+
+ result = m([1, 2, 3, {y: 9}, 4, 5, x]) { |a, b=5, c, **k| [a, b, c, k] }
+ result.should == [1, 2, 3, {}]
+ end
end
it "does not call #to_ary on the Array" do
@@ -410,6 +476,7 @@ describe "A block" do
-> { @y.s(obj) { |a, b| } }.should raise_error(ZeroDivisionError)
end
+
end
describe "taking |a, *b| arguments" do
@@ -742,42 +809,6 @@ describe "A block" do
eval("Proc.new { |_,_| }").should be_an_instance_of(Proc)
end
end
-
- describe 'pre and post parameters' do
- it "assigns nil to unassigned required arguments" do
- proc { |a, *b, c, d| [a, b, c, d] }.call(1, 2).should == [1, [], 2, nil]
- end
-
- it "assigns elements to optional arguments" do
- proc { |a=5, b=4, c=3| [a, b, c] }.call(1, 2).should == [1, 2, 3]
- end
-
- it "assigns elements to post arguments" do
- proc { |a=5, b, c, d| [a, b, c, d] }.call(1, 2).should == [5, 1, 2, nil]
- end
-
- it "assigns elements to pre arguments" do
- proc { |a, b, c, d=5| [a, b, c, d] }.call(1, 2).should == [1, 2, nil, 5]
- end
-
- it "assigns elements to pre and post arguments" do
- proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1 ).should == [1, 5, 6, nil, nil]
- proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2 ).should == [1, 5, 6, 2, nil]
- proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2, 3 ).should == [1, 5, 6, 2, 3]
- proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2, 3, 4 ).should == [1, 2, 6, 3, 4]
- proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2, 3, 4, 5 ).should == [1, 2, 3, 4, 5]
- proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2, 3, 4, 5, 6).should == [1, 2, 3, 4, 5]
- end
-
- it "assigns elements to pre and post arguments when *rest is present" do
- proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1 ).should == [1, 5, 6, [], nil, nil]
- proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2 ).should == [1, 5, 6, [], 2, nil]
- proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2, 3 ).should == [1, 5, 6, [], 2, 3]
- proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2, 3, 4 ).should == [1, 2, 6, [], 3, 4]
- proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2, 3, 4, 5 ).should == [1, 2, 3, [], 4, 5]
- proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2, 3, 4, 5, 6).should == [1, 2, 3, [4], 5, 6]
- end
- end
end
describe "Block-local variables" do
@@ -960,27 +991,24 @@ describe "Post-args" do
end
describe "with a circular argument reference" do
- ruby_version_is ""..."3.4" do
- it "raises a SyntaxError if using the argument in its default value" do
- a = 1
- -> {
- eval "proc { |a=a| a }"
- }.should raise_error(SyntaxError)
- end
+ it "raises a SyntaxError if using an existing local with the same name as the argument" do
+ a = 1
+ -> {
+ @proc = eval "proc { |a=a| a }"
+ }.should raise_error(SyntaxError)
end
- ruby_version_is "3.4" do
- it "is nil if using the argument in its default value" do
- -> {
- eval "proc { |a=a| a }.call"
- }.call.should == nil
- end
+ it "raises a SyntaxError if there is an existing method with the same name as the argument" do
+ def a; 1; end
+ -> {
+ @proc = eval "proc { |a=a| a }"
+ }.should raise_error(SyntaxError)
end
- end
- it "calls an existing method with the same name as the argument if explicitly using ()" do
- def a; 1; end
- proc { |a=a()| a }.call.should == 1
+ it "calls an existing method with the same name as the argument if explicitly using ()" do
+ def a; 1; end
+ proc { |a=a()| a }.call.should == 1
+ end
end
end
@@ -1001,7 +1029,7 @@ end
describe "Anonymous block forwarding" do
ruby_version_is "3.1" do
- it "forwards blocks to other method that formally declares anonymous block" do
+ it "forwards blocks to other functions that formally declare anonymous blocks" do
eval <<-EOF
def b(&); c(&) end
def c(&); yield :non_null end
diff --git a/spec/ruby/language/break_spec.rb b/spec/ruby/language/break_spec.rb
index 7e5b6fb328..627cb4a071 100644
--- a/spec/ruby/language/break_spec.rb
+++ b/spec/ruby/language/break_spec.rb
@@ -252,25 +252,6 @@ describe "Break inside a while loop" do
end
end
-describe "The break statement in a method" do
- it "is invalid and raises a SyntaxError" do
- -> {
- eval("def m; break; end")
- }.should raise_error(SyntaxError)
- end
-end
-
-describe "The break statement in a module literal" do
- it "is invalid and raises a SyntaxError" do
- code = <<~RUBY
- module BreakSpecs:ModuleWithBreak
- break
- end
- RUBY
-
- -> { eval(code) }.should raise_error(SyntaxError)
- end
-end
# TODO: Rewrite all the specs from here to the end of the file in the style
# above.
@@ -391,7 +372,7 @@ describe "Executing break from within a block" do
end.should_not raise_error
end
- it "raises LocalJumpError when converted into a proc during a super call" do
+ it "raises LocalJumpError when converted into a proc during a a super call" do
cls1 = Class.new { def foo(&b); b; end }
cls2 = Class.new(cls1) { def foo; super { break 1 }.call; end }
diff --git a/spec/ruby/language/case_spec.rb b/spec/ruby/language/case_spec.rb
index 464d06e46a..915c032a71 100644
--- a/spec/ruby/language/case_spec.rb
+++ b/spec/ruby/language/case_spec.rb
@@ -329,6 +329,49 @@ describe "The 'case'-construct" do
100
end.should == 100
end
+end
+
+describe "The 'case'-construct with no target expression" do
+ it "evaluates the body of the first clause when at least one of its condition expressions is true" do
+ case
+ when true, false; 'foo'
+ end.should == 'foo'
+ end
+
+ it "evaluates the body of the first when clause that is not false/nil" do
+ case
+ when false; 'foo'
+ when 2; 'bar'
+ when 1 == 1; 'baz'
+ end.should == 'bar'
+
+ case
+ when false; 'foo'
+ when nil; 'foo'
+ when 1 == 1; 'bar'
+ end.should == 'bar'
+ end
+
+ it "evaluates the body of the else clause if all when clauses are false/nil" do
+ case
+ when false; 'foo'
+ when nil; 'foo'
+ when 1 == 2; 'bar'
+ else 'baz'
+ end.should == 'baz'
+ end
+
+ it "evaluates multiple conditional expressions as a boolean disjunction" do
+ case
+ when true, false; 'foo'
+ else 'bar'
+ end.should == 'foo'
+
+ case
+ when false, true; 'foo'
+ else 'bar'
+ end.should == 'foo'
+ end
it "evaluates true as only 'true' when true is the first clause" do
case 1
@@ -391,104 +434,6 @@ describe "The 'case'-construct" do
end.should == :called
end
- it "only matches last value in complex expressions within ()" do
- case 'a'
- when ('a'; 'b')
- :wrong_called
- when ('b'; 'a')
- :called
- end.should == :called
- end
-
- it "supports declaring variables in the case target expression" do
- def test(v)
- case new_variable_in_expression = v
- when true
- # This extra block is a test that `new_variable_in_expression` is declared outside of it and not inside
- self.then { new_variable_in_expression }
- else
- # Same
- self.then { new_variable_in_expression.casecmp?("foo") }
- end
- end
-
- self.test("bar").should == false
- self.test(true).should == true
- end
-
- ruby_version_is ""..."3.4" do
- it "warns if there are identical when clauses" do
- -> {
- eval <<~RUBY
- case 1
- when 2
- :foo
- when 2
- :bar
- end
- RUBY
- }.should complain(/warning: (duplicated .when' clause with line \d+ is ignored|'when' clause on line \d+ duplicates 'when' clause on line \d+ and is ignored)/, verbose: true)
- end
- end
-
- ruby_version_is "3.4" do
- it "warns if there are identical when clauses" do
- -> {
- eval <<~RUBY
- case 1
- when 2
- :foo
- when 2
- :bar
- end
- RUBY
- }.should complain(/warning: 'when' clause on line \d+ duplicates 'when' clause on line \d+ and is ignored/, verbose: true)
- end
- end
-end
-
-describe "The 'case'-construct with no target expression" do
- it "evaluates the body of the first clause when at least one of its condition expressions is true" do
- case
- when true, false; 'foo'
- end.should == 'foo'
- end
-
- it "evaluates the body of the first when clause that is not false/nil" do
- case
- when false; 'foo'
- when 2; 'bar'
- when 1 == 1; 'baz'
- end.should == 'bar'
-
- case
- when false; 'foo'
- when nil; 'foo'
- when 1 == 1; 'bar'
- end.should == 'bar'
- end
-
- it "evaluates the body of the else clause if all when clauses are false/nil" do
- case
- when false; 'foo'
- when nil; 'foo'
- when 1 == 2; 'bar'
- else 'baz'
- end.should == 'baz'
- end
-
- it "evaluates multiple conditional expressions as a boolean disjunction" do
- case
- when true, false; 'foo'
- else 'bar'
- end.should == 'foo'
-
- case
- when false, true; 'foo'
- else 'bar'
- end.should == 'foo'
- end
-
# Homogeneous cases are often optimized to avoid === using a jump table, and should be tested separately.
# See https://github.com/jruby/jruby/issues/6440
it "handles homogeneous cases" do
@@ -497,13 +442,4 @@ describe "The 'case'-construct with no target expression" do
when 2; 'bar'
end.should == 'foo'
end
-
- it "expands arrays to lists of values" do
- case
- when *[false]
- "foo"
- when *[true]
- "bar"
- end.should == "bar"
- end
end
diff --git a/spec/ruby/language/class_spec.rb b/spec/ruby/language/class_spec.rb
index eab3cd0651..877895bf15 100644
--- a/spec/ruby/language/class_spec.rb
+++ b/spec/ruby/language/class_spec.rb
@@ -308,10 +308,20 @@ describe "A class definition extending an object (sclass)" do
-> { class TestClass < BasicObject.new; end }.should raise_error(TypeError, error_msg)
end
- it "does not allow accessing the block of the original scope" do
- -> {
- ClassSpecs.sclass_with_block { 123 }
- }.should raise_error(SyntaxError)
+ ruby_version_is ""..."3.0" do
+ it "allows accessing the block of the original scope" do
+ suppress_warning do
+ ClassSpecs.sclass_with_block { 123 }.should == 123
+ end
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "does not allow accessing the block of the original scope" do
+ -> {
+ ClassSpecs.sclass_with_block { 123 }
+ }.should raise_error(SyntaxError)
+ end
end
it "can use return to cause the enclosing method to return" do
diff --git a/spec/ruby/language/class_variable_spec.rb b/spec/ruby/language/class_variable_spec.rb
index a26a3fb8de..f98deaa081 100644
--- a/spec/ruby/language/class_variable_spec.rb
+++ b/spec/ruby/language/class_variable_spec.rb
@@ -83,32 +83,34 @@ describe 'A class variable definition' do
end
end
-describe 'Accessing a class variable' do
- it "raises a RuntimeError when accessed from the toplevel scope (not in some module or class)" do
- -> {
- eval "@@cvar_toplevel1"
- }.should raise_error(RuntimeError, 'class variable access from toplevel')
- -> {
- eval "@@cvar_toplevel2 = 2"
- }.should raise_error(RuntimeError, 'class variable access from toplevel')
- end
-
- it "does not raise an error when checking if defined from the toplevel scope" do
- -> {
- eval "defined?(@@cvar_toplevel1)"
- }.should_not raise_error
- end
-
- it "raises a RuntimeError when a class variable is overtaken in an ancestor class" do
- parent = Class.new()
- subclass = Class.new(parent)
- subclass.class_variable_set(:@@cvar_overtaken, :subclass)
- parent.class_variable_set(:@@cvar_overtaken, :parent)
-
- -> {
- subclass.class_variable_get(:@@cvar_overtaken)
- }.should raise_error(RuntimeError, /class variable @@cvar_overtaken of .+ is overtaken by .+/)
-
- parent.class_variable_get(:@@cvar_overtaken).should == :parent
+ruby_version_is "3.0" do
+ describe 'Accessing a class variable' do
+ it "raises a RuntimeError when accessed from the toplevel scope (not in some module or class)" do
+ -> {
+ eval "@@cvar_toplevel1"
+ }.should raise_error(RuntimeError, 'class variable access from toplevel')
+ -> {
+ eval "@@cvar_toplevel2 = 2"
+ }.should raise_error(RuntimeError, 'class variable access from toplevel')
+ end
+
+ it "does not raise an error when checking if defined from the toplevel scope" do
+ -> {
+ eval "defined?(@@cvar_toplevel1)"
+ }.should_not raise_error
+ end
+
+ it "raises a RuntimeError when a class variable is overtaken in an ancestor class" do
+ parent = Class.new()
+ subclass = Class.new(parent)
+ subclass.class_variable_set(:@@cvar_overtaken, :subclass)
+ parent.class_variable_set(:@@cvar_overtaken, :parent)
+
+ -> {
+ subclass.class_variable_get(:@@cvar_overtaken)
+ }.should raise_error(RuntimeError, /class variable @@cvar_overtaken of .+ is overtaken by .+/)
+
+ parent.class_variable_get(:@@cvar_overtaken).should == :parent
+ end
end
end
diff --git a/spec/ruby/language/constants_spec.rb b/spec/ruby/language/constants_spec.rb
index 08c534487e..8586e46158 100644
--- a/spec/ruby/language/constants_spec.rb
+++ b/spec/ruby/language/constants_spec.rb
@@ -170,32 +170,34 @@ describe "Literal (A::X) constant resolution" do
-> { ConstantSpecs::ParentA::CS_CONSTX }.should raise_error(NameError)
end
- it "uses the module or class #name to craft the error message" do
- mod = Module.new do
- def self.name
- "ModuleName"
- end
+ ruby_version_is "3.0" do
+ it "uses the module or class #name to craft the error message" do
+ mod = Module.new do
+ def self.name
+ "ModuleName"
+ end
- def self.inspect
- "<unusable info>"
+ def self.inspect
+ "<unusable info>"
+ end
end
+
+ -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant ModuleName::DOES_NOT_EXIST/)
end
- -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant ModuleName::DOES_NOT_EXIST/)
- end
+ it "uses the module or class #inspect to craft the error message if they are anonymous" do
+ mod = Module.new do
+ def self.name
+ nil
+ end
- it "uses the module or class #inspect to craft the error message if they are anonymous" do
- mod = Module.new do
- def self.name
- nil
+ def self.inspect
+ "<unusable info>"
+ end
end
- def self.inspect
- "<unusable info>"
- end
+ -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant <unusable info>::DOES_NOT_EXIST/)
end
-
- -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant <unusable info>::DOES_NOT_EXIST/)
end
it "sends #const_missing to the original class or module scope" do
diff --git a/spec/ruby/language/def_spec.rb b/spec/ruby/language/def_spec.rb
index ce8077eb69..c8531343c0 100644
--- a/spec/ruby/language/def_spec.rb
+++ b/spec/ruby/language/def_spec.rb
@@ -197,25 +197,15 @@ describe "An instance method with a default argument" do
foo(2,3,3).should == [2,3,[3]]
end
- ruby_version_is ""..."3.4" do
- it "raises a SyntaxError if using the argument in its default value" do
- -> {
- eval "def foo(bar = bar)
- bar
- end"
- }.should raise_error(SyntaxError)
- end
- end
-
- ruby_version_is "3.4" do
- it "is nil if using the argument in its default value" do
- -> {
- eval "def foo(bar = bar)
- bar
- end
- foo"
- }.call.should == nil
+ it "raises a SyntaxError when there is an existing method with the same name as the local variable" do
+ def bar
+ 1
end
+ -> {
+ eval "def foo(bar = bar)
+ bar
+ end"
+ }.should raise_error(SyntaxError)
end
it "calls a method with the same name as the local when explicitly using ()" do
@@ -248,7 +238,7 @@ describe "A singleton method definition" do
end
it "can be declared for a global variable" do
- $__a__ = +"hi"
+ $__a__ = "hi"
def $__a__.foo
7
end
diff --git a/spec/ruby/language/defined_spec.rb b/spec/ruby/language/defined_spec.rb
index 34408c0190..ae2bf45bda 100644
--- a/spec/ruby/language/defined_spec.rb
+++ b/spec/ruby/language/defined_spec.rb
@@ -116,11 +116,6 @@ describe "The defined? keyword when called with a method name" do
defined?(obj.a_defined_method).should == "method"
end
- it "returns 'method' for []=" do
- a = []
- defined?(a[0] = 1).should == "method"
- end
-
it "returns nil if the method is not defined" do
obj = DefinedSpecs::Basic.new
defined?(obj.an_undefined_method).should be_nil
@@ -185,32 +180,6 @@ describe "The defined? keyword when called with a method name" do
ScratchPad.recorded.should == :defined_specs_fixnum_method
end
end
-
- describe "having a throw in the receiver" do
- it "escapes defined? and performs the throw semantics as normal" do
- defined_returned = false
- catch(:out) {
- # NOTE: defined? behaves differently if it is called in a void context, see below
- defined?(throw(:out, 42).foo).should == :unreachable
- defined_returned = true
- }.should == 42
- defined_returned.should == false
- end
- end
-
- describe "in a void context" do
- it "does not execute the receiver" do
- ScratchPad.record :not_executed
- defined?(DefinedSpecs.side_effects / 2)
- ScratchPad.recorded.should == :not_executed
- end
-
- it "warns about the void context when parsing it" do
- -> {
- eval "defined?(DefinedSpecs.side_effects / 2); 42"
- }.should complain(/warning: possibly useless use of defined\? in void context/, verbose: true)
- end
- end
end
describe "The defined? keyword for an expression" do
@@ -236,14 +205,6 @@ describe "The defined? keyword for an expression" do
defined?(@@defined_specs_x = 2).should == "assignment"
end
- it "returns 'assignment' for assigning a constant" do
- defined?(A = 2).should == "assignment"
- end
-
- it "returns 'assignment' for assigning a fully qualified constant" do
- defined?(Object::A = 2).should == "assignment"
- end
-
it "returns 'assignment' for assigning multiple variables" do
defined?((a, b = 1, 2)).should == "assignment"
end
@@ -261,27 +222,7 @@ describe "The defined? keyword for an expression" do
end
it "returns 'assignment' for an expression with '+='" do
- defined?(a += 1).should == "assignment"
- defined?(@a += 1).should == "assignment"
- defined?(@@a += 1).should == "assignment"
- defined?($a += 1).should == "assignment"
- defined?(A += 1).should == "assignment"
- # fully qualified constant check is moved out into a separate test case
- defined?(a.b += 1).should == "assignment"
- defined?(a[:b] += 1).should == "assignment"
- end
-
- # https://bugs.ruby-lang.org/issues/20111
- ruby_version_is ""..."3.4" do
- it "returns 'expression' for an assigning a fully qualified constant with '+='" do
- defined?(Object::A += 1).should == "expression"
- end
- end
-
- ruby_version_is "3.4" do
- it "returns 'assignment' for an assigning a fully qualified constant with '+='" do
- defined?(Object::A += 1).should == "assignment"
- end
+ defined?(x += 2).should == "assignment"
end
it "returns 'assignment' for an expression with '*='" do
@@ -312,90 +253,12 @@ describe "The defined? keyword for an expression" do
defined?(x >>= 2).should == "assignment"
end
- context "||=" do
- it "returns 'assignment' for assigning a local variable with '||='" do
- defined?(a ||= true).should == "assignment"
- end
-
- it "returns 'assignment' for assigning an instance variable with '||='" do
- defined?(@a ||= true).should == "assignment"
- end
-
- it "returns 'assignment' for assigning a class variable with '||='" do
- defined?(@@a ||= true).should == "assignment"
- end
-
- it "returns 'assignment' for assigning a global variable with '||='" do
- defined?($a ||= true).should == "assignment"
- end
-
- it "returns 'assignment' for assigning a constant with '||='" do
- defined?(A ||= true).should == "assignment"
- end
-
- # https://bugs.ruby-lang.org/issues/20111
- ruby_version_is ""..."3.4" do
- it "returns 'expression' for assigning a fully qualified constant with '||='" do
- defined?(Object::A ||= true).should == "expression"
- end
- end
-
- ruby_version_is "3.4" do
- it "returns 'assignment' for assigning a fully qualified constant with '||='" do
- defined?(Object::A ||= true).should == "assignment"
- end
- end
-
- it "returns 'assignment' for assigning an attribute with '||='" do
- defined?(a.b ||= true).should == "assignment"
- end
-
- it "returns 'assignment' for assigning a referenced element with '||='" do
- defined?(a[:b] ||= true).should == "assignment"
- end
+ it "returns 'assignment' for an expression with '||='" do
+ defined?(x ||= 2).should == "assignment"
end
- context "&&=" do
- it "returns 'assignment' for assigning a local variable with '&&='" do
- defined?(a &&= true).should == "assignment"
- end
-
- it "returns 'assignment' for assigning an instance variable with '&&='" do
- defined?(@a &&= true).should == "assignment"
- end
-
- it "returns 'assignment' for assigning a class variable with '&&='" do
- defined?(@@a &&= true).should == "assignment"
- end
-
- it "returns 'assignment' for assigning a global variable with '&&='" do
- defined?($a &&= true).should == "assignment"
- end
-
- it "returns 'assignment' for assigning a constant with '&&='" do
- defined?(A &&= true).should == "assignment"
- end
-
- # https://bugs.ruby-lang.org/issues/20111
- ruby_version_is ""..."3.4" do
- it "returns 'expression' for assigning a fully qualified constant with '&&='" do
- defined?(Object::A &&= true).should == "expression"
- end
- end
-
- ruby_version_is "3.4" do
- it "returns 'assignment' for assigning a fully qualified constant with '&&='" do
- defined?(Object::A &&= true).should == "assignment"
- end
- end
-
- it "returns 'assignment' for assigning an attribute with '&&='" do
- defined?(a.b &&= true).should == "assignment"
- end
-
- it "returns 'assignment' for assigning a referenced element with '&&='" do
- defined?(a[:b] &&= true).should == "assignment"
- end
+ it "returns 'assignment' for an expression with '&&='" do
+ defined?(x &&= 2).should == "assignment"
end
it "returns 'assignment' for an expression with '**='" do
diff --git a/spec/ruby/language/delegation_spec.rb b/spec/ruby/language/delegation_spec.rb
index d780506421..3f24a79d5c 100644
--- a/spec/ruby/language/delegation_spec.rb
+++ b/spec/ruby/language/delegation_spec.rb
@@ -31,63 +31,35 @@ describe "delegation with def(...)" do
def delegate(...)
target ...
end
- RUBY
- end
+ RUBY
+ end
- a.new.delegate(1, b: 2).should == Range.new([[], {}], nil, true)
+ a.new.delegate(1, b: 2).should == Range.new([[], {}], nil, true)
end
end
-describe "delegation with def(x, ...)" do
- it "delegates rest and kwargs" do
- a = Class.new(DelegationSpecs::Target)
- a.class_eval(<<-RUBY)
- def delegate(x, ...)
- target(...)
- end
- RUBY
-
- a.new.delegate(0, 1, b: 2).should == [[1], {b: 2}]
- end
-
- it "delegates block" do
- a = Class.new(DelegationSpecs::Target)
- a.class_eval(<<-RUBY)
- def delegate_block(x, ...)
- target_block(...)
- end
- RUBY
-
- a.new.delegate_block(0, 1, b: 2) { |x| x }.should == [{b: 2}, [1]]
- end
-end
-
-ruby_version_is "3.2" do
- describe "delegation with def(*)" do
- it "delegates rest" do
+ruby_version_is "2.7.3" do
+ describe "delegation with def(x, ...)" do
+ it "delegates rest and kwargs" do
a = Class.new(DelegationSpecs::Target)
a.class_eval(<<-RUBY)
- def delegate(*)
- target(*)
- end
- RUBY
+ def delegate(x, ...)
+ target(...)
+ end
+ RUBY
- a.new.delegate(0, 1).should == [[0, 1], {}]
+ a.new.delegate(0, 1, b: 2).should == [[1], {b: 2}]
end
- end
-end
-ruby_version_is "3.2" do
- describe "delegation with def(**)" do
- it "delegates kwargs" do
+ it "delegates block" do
a = Class.new(DelegationSpecs::Target)
a.class_eval(<<-RUBY)
- def delegate(**)
- target(**)
- end
- RUBY
+ def delegate_block(x, ...)
+ target_block(...)
+ end
+ RUBY
- a.new.delegate(a: 1) { |x| x }.should == [[], {a: 1}]
+ a.new.delegate_block(0, 1, b: 2) { |x| x }.should == [{b: 2}, [1]]
end
end
end
diff --git a/spec/ruby/language/encoding_spec.rb b/spec/ruby/language/encoding_spec.rb
index e761a53cb6..5430c9cb98 100644
--- a/spec/ruby/language/encoding_spec.rb
+++ b/spec/ruby/language/encoding_spec.rb
@@ -13,15 +13,15 @@ describe "The __ENCODING__ pseudo-variable" do
end
it "is the evaluated strings's one inside an eval" do
- eval("__ENCODING__".dup.force_encoding("US-ASCII")).should == Encoding::US_ASCII
- eval("__ENCODING__".dup.force_encoding("BINARY")).should == Encoding::BINARY
+ eval("__ENCODING__".force_encoding("US-ASCII")).should == Encoding::US_ASCII
+ eval("__ENCODING__".force_encoding("BINARY")).should == Encoding::BINARY
end
it "is the encoding specified by a magic comment inside an eval" do
- code = "# encoding: BINARY\n__ENCODING__".dup.force_encoding("US-ASCII")
+ code = "# encoding: BINARY\n__ENCODING__".force_encoding("US-ASCII")
eval(code).should == Encoding::BINARY
- code = "# encoding: us-ascii\n__ENCODING__".dup.force_encoding("BINARY")
+ code = "# encoding: us-ascii\n__ENCODING__".force_encoding("BINARY")
eval(code).should == Encoding::US_ASCII
end
diff --git a/spec/ruby/language/ensure_spec.rb b/spec/ruby/language/ensure_spec.rb
index 16e626b4d0..e893904bcb 100644
--- a/spec/ruby/language/ensure_spec.rb
+++ b/spec/ruby/language/ensure_spec.rb
@@ -328,21 +328,4 @@ describe "An ensure block inside 'do end' block" do
result.should == :begin
end
-
- ruby_version_is "3.4" do
- it "does not introduce extra backtrace entries" do
- def foo
- begin
- raise "oops"
- ensure
- return caller(0, 2) # rubocop:disable Lint/EnsureReturn
- end
- end
- line = __LINE__
- foo.should == [
- "#{__FILE__}:#{line-3}:in 'foo'",
- "#{__FILE__}:#{line+1}:in 'block (3 levels) in <top (required)>'"
- ]
- end
- end
end
diff --git a/spec/ruby/language/execution_spec.rb b/spec/ruby/language/execution_spec.rb
index 51bcde62e8..4e0310946d 100644
--- a/spec/ruby/language/execution_spec.rb
+++ b/spec/ruby/language/execution_spec.rb
@@ -5,45 +5,6 @@ describe "``" do
ip = 'world'
`echo disc #{ip}`.should == "disc world\n"
end
-
- it "can be redefined and receive a frozen string as argument" do
- called = false
- runner = Object.new
-
- runner.singleton_class.define_method(:`) do |str|
- called = true
-
- str.should == "test command"
- str.frozen?.should == true
- end
-
- runner.instance_exec do
- `test command`
- end
-
- called.should == true
- end
-
- it "the argument isn't frozen if it contains interpolation" do
- called = false
- runner = Object.new
-
- runner.singleton_class.define_method(:`) do |str|
- called = true
-
- str.should == "test command"
- str.frozen?.should == false
- str << "mutated"
- end
-
- 2.times do
- runner.instance_exec do
- `test #{:command}` # rubocop:disable Lint/LiteralInInterpolation
- end
- end
-
- called.should == true
- end
end
describe "%x" do
@@ -51,43 +12,4 @@ describe "%x" do
ip = 'world'
%x(echo disc #{ip}).should == "disc world\n"
end
-
- it "can be redefined and receive a frozen string as argument" do
- called = false
- runner = Object.new
-
- runner.singleton_class.define_method(:`) do |str|
- called = true
-
- str.should == "test command"
- str.frozen?.should == true
- end
-
- runner.instance_exec do
- %x{test command}
- end
-
- called.should == true
- end
-
- it "the argument isn't frozen if it contains interpolation" do
- called = false
- runner = Object.new
-
- runner.singleton_class.define_method(:`) do |str|
- called = true
-
- str.should == "test command"
- str.frozen?.should == false
- str << "mutated"
- end
-
- 2.times do
- runner.instance_exec do
- %x{test #{:command}} # rubocop:disable Lint/LiteralInInterpolation
- end
- end
-
- called.should == true
- end
end
diff --git a/spec/ruby/language/file_spec.rb b/spec/ruby/language/file_spec.rb
index 59563d9642..136b262d07 100644
--- a/spec/ruby/language/file_spec.rb
+++ b/spec/ruby/language/file_spec.rb
@@ -7,16 +7,8 @@ describe "The __FILE__ pseudo-variable" do
-> { eval("__FILE__ = 1") }.should raise_error(SyntaxError)
end
- ruby_version_is ""..."3.3" do
- it "equals (eval) inside an eval" do
- eval("__FILE__").should == "(eval)"
- end
- end
-
- ruby_version_is "3.3" do
- it "equals (eval at __FILE__:__LINE__) inside an eval" do
- eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})"
- end
+ it "equals (eval) inside an eval" do
+ eval("__FILE__").should == "(eval)"
end
end
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb b/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb
index f72a32e879..d0558a2251 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb
Binary files differ
diff --git a/spec/ruby/language/fixtures/rescue/top_level.rb b/spec/ruby/language/fixtures/rescue/top_level.rb
deleted file mode 100644
index 59e78ef1d6..0000000000
--- a/spec/ruby/language/fixtures/rescue/top_level.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# capturing in local variable at top-level
-
-begin
- raise "message"
-rescue => e
- ScratchPad << e.message
-end
diff --git a/spec/ruby/language/fixtures/super.rb b/spec/ruby/language/fixtures/super.rb
index c5bdcf0e40..218f1e4970 100644
--- a/spec/ruby/language/fixtures/super.rb
+++ b/spec/ruby/language/fixtures/super.rb
@@ -539,30 +539,6 @@ module SuperSpecs
args
end
- def m3(*args)
- args
- end
-
- def m4(*args)
- args
- end
-
- def m_default(*args)
- args
- end
-
- def m_rest(*args)
- args
- end
-
- def m_pre_default_rest_post(*args)
- args
- end
-
- def m_kwrest(**kw)
- kw
- end
-
def m_modified(*args)
args
end
@@ -573,30 +549,6 @@ module SuperSpecs
super
end
- def m3(_, _, _)
- super
- end
-
- def m4(_, _, _, _)
- super
- end
-
- def m_default(_ = 0)
- super
- end
-
- def m_rest(*_)
- super
- end
-
- def m_pre_default_rest_post(_, _, _=:a, _=:b, *_, _, _)
- super
- end
-
- def m_kwrest(**_)
- super
- end
-
def m_modified(_, _)
_ = 14
super
@@ -604,20 +556,6 @@ module SuperSpecs
end
end
- module ZSuperInBlock
- class A
- def m(arg:)
- arg
- end
- end
-
- class B < A
- def m(arg:)
- proc { super }.call
- end
- end
- end
-
module Keywords
class Arguments
def foo(**args)
diff --git a/spec/ruby/language/fixtures/variables.rb b/spec/ruby/language/fixtures/variables.rb
index 527caa7a78..07265dbb2b 100644
--- a/spec/ruby/language/fixtures/variables.rb
+++ b/spec/ruby/language/fixtures/variables.rb
@@ -82,76 +82,4 @@ module VariablesSpecs
def self.false
false
end
-
- class EvalOrder
- attr_reader :order
-
- def initialize
- @order = []
- end
-
- def reset
- @order = []
- end
-
- def foo
- self << "foo"
- FooClass.new(self)
- end
-
- def bar
- self << "bar"
- BarClass.new(self)
- end
-
- def a
- self << "a"
- end
-
- def b
- self << "b"
- end
-
- def node
- self << "node"
-
- node = Node.new
- node.left = Node.new
- node.left.right = Node.new
-
- node
- end
-
- def <<(value)
- order << value
- end
-
- class FooClass
- attr_reader :evaluator
-
- def initialize(evaluator)
- @evaluator = evaluator
- end
-
- def []=(_index, _value)
- evaluator << "foo[]="
- end
- end
-
- class BarClass
- attr_reader :evaluator
-
- def initialize(evaluator)
- @evaluator = evaluator
- end
-
- def baz=(_value)
- evaluator << "bar.baz="
- end
- end
-
- class Node
- attr_accessor :left, :right
- end
- end
end
diff --git a/spec/ruby/language/for_spec.rb b/spec/ruby/language/for_spec.rb
index b8ddfe5f0d..0ad5ea88af 100644
--- a/spec/ruby/language/for_spec.rb
+++ b/spec/ruby/language/for_spec.rb
@@ -19,27 +19,6 @@ describe "The for expression" do
end
end
- it "iterates over a list of arrays and destructures with an empty splat" do
- for i, * in [[1,2]]
- i.should == 1
- end
- end
-
- it "iterates over a list of arrays and destructures with a splat" do
- for i, *j in [[1,2]]
- i.should == 1
- j.should == [2]
- end
- end
-
- it "iterates over a list of arrays and destructures with a splat and additional targets" do
- for i, *j, k in [[1,2,3,4]]
- i.should == 1
- j.should == [2,3]
- k.should == 4
- end
- end
-
it "iterates over an Hash passing each key-value pair to the block" do
k = 0
l = 0
@@ -102,88 +81,6 @@ describe "The for expression" do
end
end
- it "allows a global variable as an iterator name" do
- old_global_var = $var
- m = [1,2,3]
- n = 0
- for $var in m
- n += 1
- end
- $var.should == 3
- n.should == 3
- $var = old_global_var
- end
-
- it "allows an attribute as an iterator name" do
- class OFor
- attr_accessor :target
- end
-
- ofor = OFor.new
- m = [1,2,3]
- n = 0
- for ofor.target in m
- n += 1
- end
- ofor.target.should == 3
- n.should == 3
- end
-
- # Segfault in MRI 3.3 and lower: https://bugs.ruby-lang.org/issues/20468
- ruby_bug "#20468", ""..."3.4" do
- it "allows an attribute with safe navigation as an iterator name" do
- class OFor
- attr_accessor :target
- end
-
- ofor = OFor.new
- m = [1,2,3]
- n = 0
- eval <<~RUBY
- for ofor&.target in m
- n += 1
- end
- RUBY
- ofor.target.should == 3
- n.should == 3
- end
-
- it "allows an attribute with safe navigation on a nil base as an iterator name" do
- ofor = nil
- m = [1,2,3]
- n = 0
- eval <<~RUBY
- for ofor&.target in m
- n += 1
- end
- RUBY
- ofor.should be_nil
- n.should == 3
- end
- end
-
- it "allows an array index writer as an iterator name" do
- arr = [:a, :b, :c]
- m = [1,2,3]
- n = 0
- for arr[1] in m
- n += 1
- end
- arr.should == [:a, 3, :c]
- n.should == 3
- end
-
- it "allows a hash index writer as an iterator name" do
- hash = { a: 10, b: 20, c: 30 }
- m = [1,2,3]
- n = 0
- for hash[:b] in m
- n += 1
- end
- hash.should == { a: 10, b: 3, c: 30 }
- n.should == 3
- end
-
# 1.9 behaviour verified by nobu in
# http://redmine.ruby-lang.org/issues/show/2053
it "yields only as many values as there are arguments" do
diff --git a/spec/ruby/language/hash_spec.rb b/spec/ruby/language/hash_spec.rb
index 068ac0f39c..c84564d3ea 100644
--- a/spec/ruby/language/hash_spec.rb
+++ b/spec/ruby/language/hash_spec.rb
@@ -33,7 +33,7 @@ describe "Hash literal" do
end
it "freezes string keys on initialization" do
- key = +"foo"
+ key = "foo"
h = {key => "bar"}
key.reverse!
h["foo"].should == "bar"
@@ -86,30 +86,6 @@ describe "Hash literal" do
-> { eval("{:a ==> 1}") }.should raise_error(SyntaxError)
end
- it "recognizes '!' at the end of the key" do
- eval("{:a! =>1}").should == {:"a!" => 1}
- eval("{:a! => 1}").should == {:"a!" => 1}
-
- eval("{a!:1}").should == {:"a!" => 1}
- eval("{a!: 1}").should == {:"a!" => 1}
- end
-
- it "raises a SyntaxError if there is no space between `!` and `=>`" do
- -> { eval("{:a!=> 1}") }.should raise_error(SyntaxError)
- end
-
- it "recognizes '?' at the end of the key" do
- eval("{:a? =>1}").should == {:"a?" => 1}
- eval("{:a? => 1}").should == {:"a?" => 1}
-
- eval("{a?:1}").should == {:"a?" => 1}
- eval("{a?: 1}").should == {:"a?" => 1}
- end
-
- it "raises a SyntaxError if there is no space between `?` and `=>`" do
- -> { eval("{:a?=> 1}") }.should raise_error(SyntaxError)
- end
-
it "constructs a new hash with the given elements" do
{foo: 123}.should == {foo: 123}
h = {rbx: :cool, specs: 'fail_sometimes'}
@@ -151,24 +127,11 @@ describe "Hash literal" do
{a: 1, **h, c: 4}.should == {a: 1, b: 2, c: 4}
end
- it "expands an '**{}' or '**obj' element with the last key/value pair taking precedence" do
+ it "expands an '**{}' element with the last key/value pair taking precedence" do
-> {
@h = eval "{a: 1, **{a: 2, b: 3, c: 1}, c: 3}"
}.should complain(/key :a is duplicated|duplicated key/)
@h.should == {a: 2, b: 3, c: 3}
-
- -> {
- h = {a: 2, b: 3, c: 1}
- @h = eval "{a: 1, **h, c: 3}"
- }.should_not complain
- @h.should == {a: 2, b: 3, c: 3}
- end
-
- it "expands an '**{}' and warns when finding an additional duplicate key afterwards" do
- -> {
- @h = eval "{d: 1, **{a: 2, b: 3, c: 1}, c: 3}"
- }.should complain(/key :c is duplicated|duplicated key/)
- @h.should == {a: 2, b: 3, c: 3, d: 1}
end
it "merges multiple nested '**obj' in Hash literals" do
@@ -214,24 +177,6 @@ describe "Hash literal" do
utf8_hash.keys.first.should == usascii_hash.keys.first
usascii_hash.keys.first.encoding.should == Encoding::US_ASCII
end
-
- ruby_bug "#20280", ""..."3.4" do
- it "raises a SyntaxError at parse time when Symbol key with invalid bytes" do
- ScratchPad.record []
- -> {
- eval 'ScratchPad << 1; {:"\xC3" => 1}'
- }.should raise_error(SyntaxError, /invalid symbol/)
- ScratchPad.recorded.should == []
- end
-
- it "raises a SyntaxError at parse time when Symbol key with invalid bytes and 'key: value' syntax used" do
- ScratchPad.record []
- -> {
- eval 'ScratchPad << 1; {"\xC3": 1}'
- }.should raise_error(SyntaxError, /invalid symbol/)
- ScratchPad.recorded.should == []
- end
- end
end
describe "The ** operator" do
@@ -246,8 +191,8 @@ describe "The ** operator" do
h.should == { one: 1, two: 2 }
end
- ruby_bug "#20012", ""..."3.3" do
- it "makes a copy when calling a method taking a positional Hash" do
+ ruby_version_is ""..."3.0" do
+ it "makes a caller-side copy when calling a method taking a positional Hash" do
def m(h)
h.delete(:one); h
end
@@ -259,6 +204,19 @@ describe "The ** operator" do
end
end
+ ruby_version_is "3.0" do
+ it "does not copy when calling a method taking a positional Hash" do
+ def m(h)
+ h.delete(:one); h
+ end
+
+ h = { one: 1, two: 2 }
+ m(**h).should == { two: 2 }
+ m(**h).should.equal?(h)
+ h.should == { two: 2 }
+ end
+ end
+
ruby_version_is "3.1" do
describe "hash with omitted value" do
it "accepts short notation 'key' for 'key: value' syntax" do
@@ -295,14 +253,6 @@ describe "The ** operator" do
a.new.foo(1).should == {bar: "baz", val: 1}
end
-
- it "raises a SyntaxError when the hash key ends with `!`" do
- -> { eval("{a!:}") }.should raise_error(SyntaxError, /identifier a! is not valid to get/)
- end
-
- it "raises a SyntaxError when the hash key ends with `?`" do
- -> { eval("{a?:}") }.should raise_error(SyntaxError, /identifier a\? is not valid to get/)
- end
end
end
end
diff --git a/spec/ruby/language/heredoc_spec.rb b/spec/ruby/language/heredoc_spec.rb
index 47ee9c2c51..b3b160fd11 100644
--- a/spec/ruby/language/heredoc_spec.rb
+++ b/spec/ruby/language/heredoc_spec.rb
@@ -106,14 +106,4 @@ HERE
SquigglyHeredocSpecs.least_indented_on_the_first_line_single.should == "a\n b\n c\n"
SquigglyHeredocSpecs.least_indented_on_the_last_line_single.should == " a\n b\nc\n"
end
-
- it "reports line numbers inside HEREDOC with method call" do
- -> {
- <<-HERE.chomp
- a
- b
- #{c}
- HERE
- }.should raise_error(NameError) { |e| e.backtrace[0].should.start_with?("#{__FILE__}:#{__LINE__ - 2}") }
- end
end
diff --git a/spec/ruby/language/if_spec.rb b/spec/ruby/language/if_spec.rb
index 2d1a89f081..d1d95c1607 100644
--- a/spec/ruby/language/if_spec.rb
+++ b/spec/ruby/language/if_spec.rb
@@ -305,59 +305,6 @@ describe "The if expression" do
6.times(&b)
ScratchPad.recorded.should == [4, 5, 4, 5]
end
-
- it "warns when Integer literals are used instead of predicates" do
- -> {
- eval <<~RUBY
- $. = 0
- 10.times { |i| ScratchPad << i if 4..5 }
- RUBY
- }.should complain(/warning: integer literal in flip-flop/, verbose: true)
- ScratchPad.recorded.should == []
- end
- end
-
- describe "when a branch syntactically does not return a value" do
- it "raises SyntaxError if both do not return a value" do
- -> {
- eval <<~RUBY
- def m
- a = if rand
- return
- else
- return
- end
- a
- end
- RUBY
- }.should raise_error(SyntaxError, /void value expression/)
- end
-
- it "does not raise SyntaxError if one branch returns a value" do
- eval(<<~RUBY).should == 1
- def m
- a = if false # using false to make it clear that's not checked for
- 42
- else
- return 1
- end
- a
- end
- m
- RUBY
-
- eval(<<~RUBY).should == 1
- def m
- a = if true # using true to make it clear that's not checked for
- return 1
- else
- 42
- end
- a
- end
- m
- RUBY
- end
end
end
diff --git a/spec/ruby/language/keyword_arguments_spec.rb b/spec/ruby/language/keyword_arguments_spec.rb
index 8668799d26..c47b7b0ae9 100644
--- a/spec/ruby/language/keyword_arguments_spec.rb
+++ b/spec/ruby/language/keyword_arguments_spec.rb
@@ -1,374 +1,286 @@
require_relative '../spec_helper'
-describe "Keyword arguments" do
- def target(*args, **kwargs)
- [args, kwargs]
- end
-
- it "are separated from positional arguments" do
- def m(*args, **kwargs)
+ruby_version_is "3.0" do
+ describe "Keyword arguments" do
+ def target(*args, **kwargs)
[args, kwargs]
end
- empty = {}
- m(**empty).should == [[], {}]
- m(empty).should == [[{}], {}]
+ it "are separated from positional arguments" do
+ def m(*args, **kwargs)
+ [args, kwargs]
+ end
- m(a: 1).should == [[], {a: 1}]
- m({a: 1}).should == [[{a: 1}], {}]
- end
+ empty = {}
+ m(**empty).should == [[], {}]
+ m(empty).should == [[{}], {}]
- it "when the receiving method has not keyword parameters it treats kwargs as positional" do
- def m(*a)
- a
+ m(a: 1).should == [[], {a: 1}]
+ m({a: 1}).should == [[{a: 1}], {}]
end
- m(a: 1).should == [{a: 1}]
- m({a: 1}).should == [{a: 1}]
- end
-
- context "empty kwargs are treated as if they were not passed" do
- it "when calling a method" do
+ it "when the receiving method has not keyword parameters it treats kwargs as positional" do
def m(*a)
a
end
- empty = {}
- m(**empty).should == []
- m(empty).should == [{}]
+ m(a: 1).should == [{a: 1}]
+ m({a: 1}).should == [{a: 1}]
end
- it "when yielding to a block" do
- def y(*args, **kwargs)
- yield(*args, **kwargs)
- end
-
- empty = {}
- y(**empty) { |*a| a }.should == []
- y(empty) { |*a| a }.should == [{}]
- end
- end
-
- it "extra keywords are not allowed without **kwrest" do
- def m(*a, kw:)
- a
- end
-
- m(kw: 1).should == []
- -> { m(kw: 1, kw2: 2) }.should raise_error(ArgumentError, 'unknown keyword: :kw2')
- -> { m(kw: 1, true => false) }.should raise_error(ArgumentError, 'unknown keyword: true')
- -> { m(kw: 1, a: 1, b: 2, c: 3) }.should raise_error(ArgumentError, 'unknown keywords: :a, :b, :c')
- end
-
- it "raises ArgumentError exception when required keyword argument is not passed" do
- def m(a:, b:, c:)
- [a, b, c]
- end
-
- -> { m(a: 1, b: 2) }.should raise_error(ArgumentError, /missing keyword: :c/)
- -> { m() }.should raise_error(ArgumentError, /missing keywords: :a, :b, :c/)
- end
-
- it "raises ArgumentError for missing keyword arguments even if there are extra ones" do
- def m(a:)
- a
- end
-
- -> { m(b: 1) }.should raise_error(ArgumentError, /missing keyword: :a/)
- end
-
- it "handle * and ** at the same call site" do
- def m(*a)
- a
- end
-
- m(*[], **{}).should == []
- m(*[], 42, **{}).should == [42]
- end
-
- context "**" do
- ruby_version_is "3.3" do
- it "copies a non-empty Hash for a method taking (*args)" do
- def m(*args)
- args[0]
+ context "empty kwargs are treated as if they were not passed" do
+ it "when calling a method" do
+ def m(*a)
+ a
end
- h = {a: 1}
- m(**h).should_not.equal?(h)
- h.should == {a: 1}
- end
- end
-
- it "copies the given Hash for a method taking (**kwargs)" do
- def m(**kw)
- kw
+ empty = {}
+ m(**empty).should == []
+ m(empty).should == [{}]
end
- empty = {}
- m(**empty).should == empty
- m(**empty).should_not.equal?(empty)
+ it "when yielding to a block" do
+ def y(*args, **kwargs)
+ yield(*args, **kwargs)
+ end
- h = {a: 1}
- m(**h).should == h
- m(**h).should_not.equal?(h)
+ empty = {}
+ y(**empty) { |*a| a }.should == []
+ y(empty) { |*a| a }.should == [{}]
+ end
end
- end
- context "delegation" do
- it "works with (*args, **kwargs)" do
- def m(*args, **kwargs)
- target(*args, **kwargs)
+ it "extra keywords are not allowed without **kwrest" do
+ def m(*a, kw:)
+ a
end
- empty = {}
- m(**empty).should == [[], {}]
- m(empty).should == [[{}], {}]
-
- m(a: 1).should == [[], {a: 1}]
- m({a: 1}).should == [[{a: 1}], {}]
+ m(kw: 1).should == []
+ -> { m(kw: 1, kw2: 2) }.should raise_error(ArgumentError, 'unknown keyword: :kw2')
+ -> { m(kw: 1, true => false) }.should raise_error(ArgumentError, 'unknown keyword: true')
+ -> { m(kw: 1, a: 1, b: 2, c: 3) }.should raise_error(ArgumentError, 'unknown keywords: :a, :b, :c')
end
- it "works with proc { |*args, **kwargs| }" do
- m = proc do |*args, **kwargs|
- target(*args, **kwargs)
+ it "raises ArgumentError exception when required keyword argument is not passed" do
+ def m(a:, b:, c:)
+ [a, b, c]
end
- empty = {}
- m.(**empty).should == [[], {}]
- m.(empty).should == [[{}], {}]
-
- m.(a: 1).should == [[], {a: 1}]
- m.({a: 1}).should == [[{a: 1}], {}]
-
- # no autosplatting for |*args, **kwargs|
- m.([1, 2]).should == [[[1, 2]], {}]
+ -> { m(a: 1, b: 2) }.should raise_error(ArgumentError, /missing keyword: :c/)
+ -> { m() }.should raise_error(ArgumentError, /missing keywords: :a, :b, :c/)
end
- it "works with -> (*args, **kwargs) {}" do
- m = -> *args, **kwargs do
- target(*args, **kwargs)
+ it "raises ArgumentError for missing keyword arguments even if there are extra ones" do
+ def m(a:)
+ a
end
- empty = {}
- m.(**empty).should == [[], {}]
- m.(empty).should == [[{}], {}]
-
- m.(a: 1).should == [[], {a: 1}]
- m.({a: 1}).should == [[{a: 1}], {}]
+ -> { m(b: 1) }.should raise_error(ArgumentError, /missing keyword: :a/)
end
- it "works with (...)" do
- instance_eval <<~DEF
- def m(...)
- target(...)
+ it "handle * and ** at the same call site" do
+ def m(*a)
+ a
end
- DEF
- empty = {}
- m(**empty).should == [[], {}]
- m(empty).should == [[{}], {}]
-
- m(a: 1).should == [[], {a: 1}]
- m({a: 1}).should == [[{a: 1}], {}]
+ m(*[], **{}).should == []
+ m(*[], 42, **{}).should == [42]
end
- it "works with call(*ruby2_keyword_args)" do
- class << self
- ruby2_keywords def m(*args)
- target(*args)
+ context "**" do
+ it "does not copy a non-empty Hash for a method taking (*args)" do
+ def m(*args)
+ args[0]
end
- end
- empty = {}
- m(**empty).should == [[], {}]
- Hash.ruby2_keywords_hash?(empty).should == false
- m(empty).should == [[{}], {}]
- Hash.ruby2_keywords_hash?(empty).should == false
-
- m(a: 1).should == [[], {a: 1}]
- m({a: 1}).should == [[{a: 1}], {}]
+ h = {a: 1}
+ m(**h).should.equal?(h)
+ end
- kw = {a: 1}
+ it "copies the given Hash for a method taking (**kwargs)" do
+ def m(**kw)
+ kw
+ end
- m(**kw).should == [[], {a: 1}]
- m(**kw)[1].should == kw
- m(**kw)[1].should_not.equal?(kw)
- Hash.ruby2_keywords_hash?(kw).should == false
- Hash.ruby2_keywords_hash?(m(**kw)[1]).should == false
+ empty = {}
+ m(**empty).should == empty
+ m(**empty).should_not.equal?(empty)
- m(kw).should == [[{a: 1}], {}]
- m(kw)[0][0].should.equal?(kw)
- Hash.ruby2_keywords_hash?(kw).should == false
+ h = {a: 1}
+ m(**h).should == h
+ m(**h).should_not.equal?(h)
+ end
end
- it "works with super(*ruby2_keyword_args)" do
- parent = Class.new do
+ context "delegation" do
+ it "works with (*args, **kwargs)" do
def m(*args, **kwargs)
- [args, kwargs]
+ target(*args, **kwargs)
end
- end
- child = Class.new(parent) do
- ruby2_keywords def m(*args)
- super(*args)
- end
+ empty = {}
+ m(**empty).should == [[], {}]
+ m(empty).should == [[{}], {}]
+
+ m(a: 1).should == [[], {a: 1}]
+ m({a: 1}).should == [[{a: 1}], {}]
end
- obj = child.new
+ it "works with proc { |*args, **kwargs| }" do
+ m = proc do |*args, **kwargs|
+ target(*args, **kwargs)
+ end
- empty = {}
- obj.m(**empty).should == [[], {}]
- Hash.ruby2_keywords_hash?(empty).should == false
- obj.m(empty).should == [[{}], {}]
- Hash.ruby2_keywords_hash?(empty).should == false
+ empty = {}
+ m.(**empty).should == [[], {}]
+ m.(empty).should == [[{}], {}]
- obj.m(a: 1).should == [[], {a: 1}]
- obj.m({a: 1}).should == [[{a: 1}], {}]
+ m.(a: 1).should == [[], {a: 1}]
+ m.({a: 1}).should == [[{a: 1}], {}]
- kw = {a: 1}
+ # no autosplatting for |*args, **kwargs|
+ m.([1, 2]).should == [[[1, 2]], {}]
+ end
- obj.m(**kw).should == [[], {a: 1}]
- obj.m(**kw)[1].should == kw
- obj.m(**kw)[1].should_not.equal?(kw)
- Hash.ruby2_keywords_hash?(kw).should == false
- Hash.ruby2_keywords_hash?(obj.m(**kw)[1]).should == false
+ it "works with -> (*args, **kwargs) {}" do
+ m = -> *args, **kwargs do
+ target(*args, **kwargs)
+ end
- obj.m(kw).should == [[{a: 1}], {}]
- obj.m(kw)[0][0].should.equal?(kw)
- Hash.ruby2_keywords_hash?(kw).should == false
- end
+ empty = {}
+ m.(**empty).should == [[], {}]
+ m.(empty).should == [[{}], {}]
- it "works with zsuper" do
- parent = Class.new do
- def m(*args, **kwargs)
- [args, kwargs]
- end
+ m.(a: 1).should == [[], {a: 1}]
+ m.({a: 1}).should == [[{a: 1}], {}]
end
- child = Class.new(parent) do
- ruby2_keywords def m(*args)
- super
+ it "works with (...)" do
+ instance_eval <<~DEF
+ def m(...)
+ target(...)
end
+ DEF
+
+ empty = {}
+ m(**empty).should == [[], {}]
+ m(empty).should == [[{}], {}]
+
+ m(a: 1).should == [[], {a: 1}]
+ m({a: 1}).should == [[{a: 1}], {}]
end
- obj = child.new
+ it "works with call(*ruby2_keyword_args)" do
+ class << self
+ ruby2_keywords def m(*args)
+ target(*args)
+ end
+ end
- empty = {}
- obj.m(**empty).should == [[], {}]
- Hash.ruby2_keywords_hash?(empty).should == false
- obj.m(empty).should == [[{}], {}]
- Hash.ruby2_keywords_hash?(empty).should == false
+ empty = {}
+ m(**empty).should == [[], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+ m(empty).should == [[{}], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
- obj.m(a: 1).should == [[], {a: 1}]
- obj.m({a: 1}).should == [[{a: 1}], {}]
+ m(a: 1).should == [[], {a: 1}]
+ m({a: 1}).should == [[{a: 1}], {}]
- kw = {a: 1}
+ kw = {a: 1}
- obj.m(**kw).should == [[], {a: 1}]
- obj.m(**kw)[1].should == kw
- obj.m(**kw)[1].should_not.equal?(kw)
- Hash.ruby2_keywords_hash?(kw).should == false
- Hash.ruby2_keywords_hash?(obj.m(**kw)[1]).should == false
+ m(**kw).should == [[], {a: 1}]
+ m(**kw)[1].should == kw
+ m(**kw)[1].should_not.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ Hash.ruby2_keywords_hash?(m(**kw)[1]).should == false
- obj.m(kw).should == [[{a: 1}], {}]
- obj.m(kw)[0][0].should.equal?(kw)
- Hash.ruby2_keywords_hash?(kw).should == false
- end
+ m(kw).should == [[{a: 1}], {}]
+ m(kw)[0][0].should.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ end
- it "works with yield(*ruby2_keyword_args)" do
- class << self
- def y(args)
- yield(*args)
+ it "works with super(*ruby2_keyword_args)" do
+ parent = Class.new do
+ def m(*args, **kwargs)
+ [args, kwargs]
+ end
end
- ruby2_keywords def m(*outer_args)
- y(outer_args, &-> *args, **kwargs { target(*args, **kwargs) })
+ child = Class.new(parent) do
+ ruby2_keywords def m(*args)
+ super(*args)
+ end
end
- end
- empty = {}
- m(**empty).should == [[], {}]
- Hash.ruby2_keywords_hash?(empty).should == false
- m(empty).should == [[{}], {}]
- Hash.ruby2_keywords_hash?(empty).should == false
+ obj = child.new
- m(a: 1).should == [[], {a: 1}]
- m({a: 1}).should == [[{a: 1}], {}]
+ empty = {}
+ obj.m(**empty).should == [[], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+ obj.m(empty).should == [[{}], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
- kw = {a: 1}
+ obj.m(a: 1).should == [[], {a: 1}]
+ obj.m({a: 1}).should == [[{a: 1}], {}]
- m(**kw).should == [[], {a: 1}]
- m(**kw)[1].should == kw
- m(**kw)[1].should_not.equal?(kw)
- Hash.ruby2_keywords_hash?(kw).should == false
- Hash.ruby2_keywords_hash?(m(**kw)[1]).should == false
+ kw = {a: 1}
- m(kw).should == [[{a: 1}], {}]
- m(kw)[0][0].should.equal?(kw)
- Hash.ruby2_keywords_hash?(kw).should == false
- end
+ obj.m(**kw).should == [[], {a: 1}]
+ obj.m(**kw)[1].should == kw
+ obj.m(**kw)[1].should_not.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ Hash.ruby2_keywords_hash?(obj.m(**kw)[1]).should == false
- it "does not work with (*args)" do
- class << self
- def m(*args)
- target(*args)
- end
+ obj.m(kw).should == [[{a: 1}], {}]
+ obj.m(kw)[0][0].should.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
end
- empty = {}
- m(**empty).should == [[], {}]
- m(empty).should == [[{}], {}]
-
- m(a: 1).should == [[{a: 1}], {}]
- m({a: 1}).should == [[{a: 1}], {}]
- end
-
- ruby_version_is "3.1" do
- describe "omitted values" do
- it "accepts short notation 'key' for 'key: value' syntax" do
- def m(a:, b:)
- [a, b]
+ it "works with zsuper" do
+ parent = Class.new do
+ def m(*args, **kwargs)
+ [args, kwargs]
end
-
- a = 1
- b = 2
-
- eval('m(a:, b:).should == [1, 2]')
end
- end
- end
-
- ruby_version_is "3.2" do
- it "does not work with call(*ruby2_keyword_args) with missing ruby2_keywords in between" do
- class << self
- def n(*args) # Note the missing ruby2_keywords here
- target(*args)
- end
+ child = Class.new(parent) do
ruby2_keywords def m(*args)
- n(*args)
+ super
end
end
+ obj = child.new
+
empty = {}
- m(**empty).should == [[], {}]
- m(empty).should == [[{}], {}]
+ obj.m(**empty).should == [[], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+ obj.m(empty).should == [[{}], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
- m(a: 1).should == [[{a: 1}], {}]
- m({a: 1}).should == [[{a: 1}], {}]
+ obj.m(a: 1).should == [[], {a: 1}]
+ obj.m({a: 1}).should == [[{a: 1}], {}]
+
+ kw = {a: 1}
+
+ obj.m(**kw).should == [[], {a: 1}]
+ obj.m(**kw)[1].should == kw
+ obj.m(**kw)[1].should_not.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ Hash.ruby2_keywords_hash?(obj.m(**kw)[1]).should == false
+
+ obj.m(kw).should == [[{a: 1}], {}]
+ obj.m(kw)[0][0].should.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
end
- end
- ruby_version_is ""..."3.2" do
- # https://bugs.ruby-lang.org/issues/18625
- it "works with call(*ruby2_keyword_args) with missing ruby2_keywords in between due to CRuby bug #18625" do
+ it "works with yield(*ruby2_keyword_args)" do
class << self
- def n(*args) # Note the missing ruby2_keywords here
- target(*args)
+ def y(args)
+ yield(*args)
end
- ruby2_keywords def m(*args)
- n(*args)
+ ruby2_keywords def m(*outer_args)
+ y(outer_args, &-> *args, **kwargs { target(*args, **kwargs) })
end
end
@@ -393,34 +305,93 @@ describe "Keyword arguments" do
m(kw)[0][0].should.equal?(kw)
Hash.ruby2_keywords_hash?(kw).should == false
end
- end
- end
- context "in define_method(name, &proc)" do
- # This tests that a free-standing proc used in define_method and converted to ruby2_keywords adopts that logic.
- # See jruby/jruby#8119 for a case where aggressive JIT optimization broke later ruby2_keywords changes.
- it "works with ruby2_keywords" do
- m = Class.new do
- def bar(a, foo: nil)
- [a, foo]
+ it "does not work with (*args)" do
+ class << self
+ def m(*args)
+ target(*args)
+ end
end
- # define_method and ruby2_keywords using send to avoid peephole optimizations
- def self.setup
- pr = make_proc
- send :define_method, :foo, &pr
- send :ruby2_keywords, :foo
+ empty = {}
+ m(**empty).should == [[], {}]
+ m(empty).should == [[{}], {}]
+
+ m(a: 1).should == [[{a: 1}], {}]
+ m({a: 1}).should == [[{a: 1}], {}]
+ end
+
+ ruby_version_is "3.1" do
+ describe "omitted values" do
+ it "accepts short notation 'key' for 'key: value' syntax" do
+ def m(a:, b:)
+ [a, b]
+ end
+
+ a = 1
+ b = 2
+
+ eval('m(a:, b:).should == [1, 2]')
+ end
end
+ end
- # create proc in isolated method to force jit compilation on some implementations
- def self.make_proc
- proc { |a, *args| bar(a, *args) }
+ ruby_version_is "3.2" do
+ it "does not work with call(*ruby2_keyword_args) with missing ruby2_keywords in between" do
+ class << self
+ def n(*args) # Note the missing ruby2_keywords here
+ target(*args)
+ end
+
+ ruby2_keywords def m(*args)
+ n(*args)
+ end
+ end
+
+ empty = {}
+ m(**empty).should == [[], {}]
+ m(empty).should == [[{}], {}]
+
+ m(a: 1).should == [[{a: 1}], {}]
+ m({a: 1}).should == [[{a: 1}], {}]
end
end
- m.setup
+ ruby_version_is ""..."3.2" do
+ # https://bugs.ruby-lang.org/issues/18625
+ it "works with call(*ruby2_keyword_args) with missing ruby2_keywords in between due to CRuby bug #18625" do
+ class << self
+ def n(*args) # Note the missing ruby2_keywords here
+ target(*args)
+ end
+
+ ruby2_keywords def m(*args)
+ n(*args)
+ end
+ end
- m.new.foo(1, foo:2).should == [1, 2]
+ empty = {}
+ m(**empty).should == [[], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+ m(empty).should == [[{}], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+
+ m(a: 1).should == [[], {a: 1}]
+ m({a: 1}).should == [[{a: 1}], {}]
+
+ kw = {a: 1}
+
+ m(**kw).should == [[], {a: 1}]
+ m(**kw)[1].should == kw
+ m(**kw)[1].should_not.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ Hash.ruby2_keywords_hash?(m(**kw)[1]).should == false
+
+ m(kw).should == [[{a: 1}], {}]
+ m(kw)[0][0].should.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ end
+ end
end
end
end
diff --git a/spec/ruby/language/lambda_spec.rb b/spec/ruby/language/lambda_spec.rb
index ed5a1c69e8..a3f01ec04b 100644
--- a/spec/ruby/language/lambda_spec.rb
+++ b/spec/ruby/language/lambda_spec.rb
@@ -177,16 +177,34 @@ describe "A lambda literal -> () { }" do
result.should == [1, 2, 3, [4, 5], 6, [7, 8], 9, 10, 11, 12]
end
- evaluate <<-ruby do
- @a = -> (*, **k) { k }
- ruby
+ ruby_version_is ''...'3.0' do
+ evaluate <<-ruby do
+ @a = -> (*, **k) { k }
+ ruby
+
+ @a.().should == {}
+ @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
+
+ suppress_keyword_warning do
+ h = mock("keyword splat")
+ h.should_receive(:to_hash).and_return({a: 1})
+ @a.(h).should == {a: 1}
+ end
+ end
+ end
- @a.().should == {}
- @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
+ ruby_version_is '3.0' do
+ evaluate <<-ruby do
+ @a = -> (*, **k) { k }
+ ruby
- h = mock("keyword splat")
- h.should_not_receive(:to_hash)
- @a.(h).should == {}
+ @a.().should == {}
+ @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
+
+ h = mock("keyword splat")
+ h.should_not_receive(:to_hash)
+ @a.(h).should == {}
+ end
end
evaluate <<-ruby do
@@ -263,21 +281,18 @@ describe "A lambda literal -> () { }" do
end
describe "with circular optional argument reference" do
- ruby_version_is ""..."3.4" do
- it "raises a SyntaxError if using the argument in its default value" do
- a = 1
- -> {
- eval "-> (a=a) { a }"
- }.should raise_error(SyntaxError)
- end
+ it "raises a SyntaxError if using an existing local with the same name as the argument" do
+ a = 1
+ -> {
+ @proc = eval "-> (a=a) { a }"
+ }.should raise_error(SyntaxError)
end
- ruby_version_is "3.4" do
- it "is nil if using the argument in its default value" do
- -> {
- eval "-> (a=a) { a }.call"
- }.call.should == nil
- end
+ it "raises a SyntaxError if there is an existing method with the same name as the argument" do
+ def a; 1; end
+ -> {
+ @proc = eval "-> (a=a) { a }"
+ }.should raise_error(SyntaxError)
end
it "calls an existing method with the same name as the argument if explicitly using ()" do
@@ -499,16 +514,34 @@ describe "A lambda expression 'lambda { ... }'" do
result.should == [1, 2, 3, [4, 5], 6, [7, 8], 9, 10, 11, 12]
end
- evaluate <<-ruby do
- @a = lambda { |*, **k| k }
- ruby
+ ruby_version_is ''...'3.0' do
+ evaluate <<-ruby do
+ @a = lambda { |*, **k| k }
+ ruby
- @a.().should == {}
- @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
+ @a.().should == {}
+ @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
- h = mock("keyword splat")
- h.should_not_receive(:to_hash)
- @a.(h).should == {}
+ suppress_keyword_warning do
+ h = mock("keyword splat")
+ h.should_receive(:to_hash).and_return({a: 1})
+ @a.(h).should == {a: 1}
+ end
+ end
+ end
+
+ ruby_version_is '3.0' do
+ evaluate <<-ruby do
+ @a = lambda { |*, **k| k }
+ ruby
+
+ @a.().should == {}
+ @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
+
+ h = mock("keyword splat")
+ h.should_not_receive(:to_hash)
+ @a.(h).should == {}
+ end
end
evaluate <<-ruby do
diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb
index 9abe4cde20..b80b314f6f 100644
--- a/spec/ruby/language/method_spec.rb
+++ b/spec/ruby/language/method_spec.rb
@@ -749,31 +749,68 @@ describe "A method" do
end
end
- evaluate <<-ruby do
- def m(a, b: 1) [a, b] end
- ruby
+ ruby_version_is ""..."3.0" do
+ evaluate <<-ruby do
+ def m(a, b: 1) [a, b] end
+ ruby
- m(2).should == [2, 1]
- m(1, b: 2).should == [1, 2]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
- end
+ m(2).should == [2, 1]
+ m(1, b: 2).should == [1, 2]
+ suppress_keyword_warning do
+ m("a" => 1, b: 2).should == [{"a" => 1, b: 2}, 1]
+ end
+ end
- evaluate <<-ruby do
- def m(a, **) a end
- ruby
+ evaluate <<-ruby do
+ def m(a, **) a end
+ ruby
- m(1).should == 1
- m(1, a: 2, b: 3).should == 1
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ m(1).should == 1
+ m(1, a: 2, b: 3).should == 1
+ suppress_keyword_warning do
+ m("a" => 1, b: 2).should == {"a" => 1, b: 2}
+ end
+ end
+
+ evaluate <<-ruby do
+ def m(a, **k) [a, k] end
+ ruby
+
+ m(1).should == [1, {}]
+ m(1, a: 2, b: 3).should == [1, {a: 2, b: 3}]
+ suppress_keyword_warning do
+ m("a" => 1, b: 2).should == [{"a" => 1, b: 2}, {}]
+ end
+ end
end
- evaluate <<-ruby do
- def m(a, **k) [a, k] end
- ruby
+ ruby_version_is "3.0" do
+ evaluate <<-ruby do
+ def m(a, b: 1) [a, b] end
+ ruby
+
+ m(2).should == [2, 1]
+ m(1, b: 2).should == [1, 2]
+ -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ end
- m(1).should == [1, {}]
- m(1, a: 2, b: 3).should == [1, {a: 2, b: 3}]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ evaluate <<-ruby do
+ def m(a, **) a end
+ ruby
+
+ m(1).should == 1
+ m(1, a: 2, b: 3).should == 1
+ -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ end
+
+ evaluate <<-ruby do
+ def m(a, **k) [a, k] end
+ ruby
+
+ m(1).should == [1, {}]
+ m(1, a: 2, b: 3).should == [1, {a: 2, b: 3}]
+ -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ end
end
evaluate <<-ruby do
@@ -884,23 +921,50 @@ describe "A method" do
result.should == [[1, 2, 3], 4, [5, 6], 7, [], 8]
end
- evaluate <<-ruby do
- def m(a=1, b:) [a, b] end
- ruby
+ ruby_version_is ""..."3.0" do
+ evaluate <<-ruby do
+ def m(a=1, b:) [a, b] end
+ ruby
+
+ m(b: 2).should == [1, 2]
+ m(2, b: 1).should == [2, 1]
+ suppress_keyword_warning do
+ m("a" => 1, b: 2).should == [{"a" => 1}, 2]
+ end
+ end
- m(b: 2).should == [1, 2]
- m(2, b: 1).should == [2, 1]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ evaluate <<-ruby do
+ def m(a=1, b: 2) [a, b] end
+ ruby
+
+ m().should == [1, 2]
+ m(2).should == [2, 2]
+ m(b: 3).should == [1, 3]
+ suppress_keyword_warning do
+ m("a" => 1, b: 2).should == [{"a" => 1}, 2]
+ end
+ end
end
- evaluate <<-ruby do
- def m(a=1, b: 2) [a, b] end
- ruby
+ ruby_version_is "3.0" do
+ evaluate <<-ruby do
+ def m(a=1, b:) [a, b] end
+ ruby
- m().should == [1, 2]
- m(2).should == [2, 2]
- m(b: 3).should == [1, 3]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ m(b: 2).should == [1, 2]
+ m(2, b: 1).should == [2, 1]
+ -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ end
+
+ evaluate <<-ruby do
+ def m(a=1, b: 2) [a, b] end
+ ruby
+
+ m().should == [1, 2]
+ m(2).should == [2, 2]
+ m(b: 3).should == [1, 3]
+ -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ end
end
evaluate <<-ruby do
@@ -949,6 +1013,292 @@ describe "A method" do
m(1, 2, 3).should == [[1, 2], 3]
end
+ ruby_version_is ""...'3.0' do
+ evaluate <<-ruby do
+ def m(*, a:) a end
+ ruby
+
+ m(a: 1).should == 1
+ m(1, 2, a: 3).should == 3
+ suppress_keyword_warning do
+ m("a" => 1, a: 2).should == 2
+ end
+ end
+
+ evaluate <<-ruby do
+ def m(*a, b:) [a, b] end
+ ruby
+
+ m(b: 1).should == [[], 1]
+ m(1, 2, b: 3).should == [[1, 2], 3]
+ suppress_keyword_warning do
+ m("a" => 1, b: 2).should == [[{"a" => 1}], 2]
+ end
+ end
+
+ evaluate <<-ruby do
+ def m(*, a: 1) a end
+ ruby
+
+ m().should == 1
+ m(1, 2).should == 1
+ m(a: 2).should == 2
+ m(1, a: 2).should == 2
+ suppress_keyword_warning do
+ m("a" => 1, a: 2).should == 2
+ end
+ end
+
+ evaluate <<-ruby do
+ def m(*a, b: 1) [a, b] end
+ ruby
+
+ m().should == [[], 1]
+ m(1, 2, 3, b: 4).should == [[1, 2, 3], 4]
+ suppress_keyword_warning do
+ m("a" => 1, b: 2).should == [[{"a" => 1}], 2]
+ end
+
+ a = mock("splat")
+ a.should_not_receive(:to_ary)
+ m(*a).should == [[a], 1]
+ end
+
+ evaluate <<-ruby do
+ def m(*a, **) a end
+ ruby
+
+ m().should == []
+ m(1, 2, 3, a: 4, b: 5).should == [1, 2, 3]
+ m("a" => 1, a: 1).should == []
+ m(1, **{a: 2}).should == [1]
+
+ h = mock("keyword splat")
+ h.should_receive(:to_hash)
+ -> { m(**h) }.should raise_error(TypeError)
+ end
+
+ evaluate <<-ruby do
+ def m(*, **k) k end
+ ruby
+
+ m().should == {}
+ m(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
+ m("a" => 1, a: 1).should == {"a" => 1, a: 1}
+
+ h = mock("keyword splat")
+ h.should_receive(:to_hash).and_return({a: 1})
+ suppress_warning do
+ m(h).should == {a: 1}
+ end
+ end
+
+ evaluate <<-ruby do
+ def m(a = nil, **k) [a, k] end
+ ruby
+
+ m().should == [nil, {}]
+ m("a" => 1).should == [nil, {"a" => 1}]
+ m(a: 1).should == [nil, {a: 1}]
+ m("a" => 1, a: 1).should == [nil, {"a" => 1, a: 1}]
+ m({ "a" => 1 }, a: 1).should == [{"a" => 1}, {a: 1}]
+ suppress_warning do
+ m({a: 1}, {}).should == [{a: 1}, {}]
+
+ h = {"a" => 1, b: 2}
+ m(h).should == [{"a" => 1}, {b: 2}]
+ h.should == {"a" => 1, b: 2}
+
+ h = {"a" => 1}
+ m(h).first.should == h
+
+ h = {}
+ r = m(h)
+ r.first.should be_nil
+ r.last.should == {}
+
+ hh = {}
+ h = mock("keyword splat empty hash")
+ h.should_receive(:to_hash).and_return(hh)
+ r = m(h)
+ r.first.should be_nil
+ r.last.should == {}
+
+ h = mock("keyword splat")
+ h.should_receive(:to_hash).and_return({"a" => 1, a: 2})
+ m(h).should == [{"a" => 1}, {a: 2}]
+ end
+ end
+
+ evaluate <<-ruby do
+ def m(*a, **k) [a, k] end
+ ruby
+
+ m().should == [[], {}]
+ m(1).should == [[1], {}]
+ m(a: 1, b: 2).should == [[], {a: 1, b: 2}]
+ m(1, 2, 3, a: 2).should == [[1, 2, 3], {a: 2}]
+
+ m("a" => 1).should == [[], {"a" => 1}]
+ m(a: 1).should == [[], {a: 1}]
+ m("a" => 1, a: 1).should == [[], {"a" => 1, a: 1}]
+ m({ "a" => 1 }, a: 1).should == [[{"a" => 1}], {a: 1}]
+ suppress_warning do
+ m({a: 1}, {}).should == [[{a: 1}], {}]
+ end
+ m({a: 1}, {"a" => 1}).should == [[{a: 1}, {"a" => 1}], {}]
+
+ bo = BasicObject.new
+ def bo.to_a; [1, 2, 3]; end
+ def bo.to_hash; {:b => 2, :c => 3}; end
+
+ m(*bo, **bo).should == [[1, 2, 3], {:b => 2, :c => 3}]
+ end
+
+ evaluate <<-ruby do
+ def m(*, a:) a end
+ ruby
+
+ m(a: 1).should == 1
+ m(1, 2, a: 3).should == 3
+ suppress_keyword_warning do
+ m("a" => 1, a: 2).should == 2
+ end
+ end
+
+ evaluate <<-ruby do
+ def m(*a, b:) [a, b] end
+ ruby
+
+ m(b: 1).should == [[], 1]
+ m(1, 2, b: 3).should == [[1, 2], 3]
+ suppress_keyword_warning do
+ m("a" => 1, b: 2).should == [[{"a" => 1}], 2]
+ end
+ end
+
+ evaluate <<-ruby do
+ def m(*, a: 1) a end
+ ruby
+
+ m().should == 1
+ m(1, 2).should == 1
+ m(a: 2).should == 2
+ m(1, a: 2).should == 2
+ suppress_keyword_warning do
+ m("a" => 1, a: 2).should == 2
+ end
+ end
+
+ evaluate <<-ruby do
+ def m(*a, b: 1) [a, b] end
+ ruby
+
+ m().should == [[], 1]
+ m(1, 2, 3, b: 4).should == [[1, 2, 3], 4]
+ suppress_keyword_warning do
+ m("a" => 1, b: 2).should == [[{"a" => 1}], 2]
+ end
+
+ a = mock("splat")
+ a.should_not_receive(:to_ary)
+ m(*a).should == [[a], 1]
+ end
+
+ evaluate <<-ruby do
+ def m(*a, **) a end
+ ruby
+
+ m().should == []
+ m(1, 2, 3, a: 4, b: 5).should == [1, 2, 3]
+ m("a" => 1, a: 1).should == []
+ m(1, **{a: 2}).should == [1]
+
+ h = mock("keyword splat")
+ h.should_receive(:to_hash)
+ -> { m(**h) }.should raise_error(TypeError)
+ end
+
+ evaluate <<-ruby do
+ def m(*, **k) k end
+ ruby
+
+ m().should == {}
+ m(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
+ m("a" => 1, a: 1).should == {"a" => 1, a: 1}
+
+ h = mock("keyword splat")
+ h.should_receive(:to_hash).and_return({a: 1})
+ suppress_keyword_warning do
+ m(h).should == {a: 1}
+ end
+ end
+
+ evaluate <<-ruby do
+ def m(a = nil, **k) [a, k] end
+ ruby
+
+ m().should == [nil, {}]
+ m("a" => 1).should == [nil, {"a" => 1}]
+ m(a: 1).should == [nil, {a: 1}]
+ m("a" => 1, a: 1).should == [nil, {"a" => 1, a: 1}]
+ m({ "a" => 1 }, a: 1).should == [{"a" => 1}, {a: 1}]
+ suppress_keyword_warning do
+ m({a: 1}, {}).should == [{a: 1}, {}]
+ end
+
+ h = {"a" => 1, b: 2}
+ suppress_keyword_warning do
+ m(h).should == [{"a" => 1}, {b: 2}]
+ end
+ h.should == {"a" => 1, b: 2}
+
+ h = {"a" => 1}
+ m(h).first.should == h
+
+ h = {}
+ suppress_keyword_warning do
+ m(h).should == [nil, {}]
+ end
+
+ hh = {}
+ h = mock("keyword splat empty hash")
+ h.should_receive(:to_hash).and_return({a: 1})
+ suppress_keyword_warning do
+ m(h).should == [nil, {a: 1}]
+ end
+
+ h = mock("keyword splat")
+ h.should_receive(:to_hash).and_return({"a" => 1})
+ m(h).should == [h, {}]
+ end
+
+ evaluate <<-ruby do
+ def m(*a, **k) [a, k] end
+ ruby
+
+ m().should == [[], {}]
+ m(1).should == [[1], {}]
+ m(a: 1, b: 2).should == [[], {a: 1, b: 2}]
+ m(1, 2, 3, a: 2).should == [[1, 2, 3], {a: 2}]
+
+ m("a" => 1).should == [[], {"a" => 1}]
+ m(a: 1).should == [[], {a: 1}]
+ m("a" => 1, a: 1).should == [[], {"a" => 1, a: 1}]
+ m({ "a" => 1 }, a: 1).should == [[{"a" => 1}], {a: 1}]
+ suppress_keyword_warning do
+ m({a: 1}, {}).should == [[{a: 1}], {}]
+ end
+ m({a: 1}, {"a" => 1}).should == [[{a: 1}, {"a" => 1}], {}]
+
+ bo = BasicObject.new
+ def bo.to_a; [1, 2, 3]; end
+ def bo.to_hash; {:b => 2, :c => 3}; end
+
+ m(*bo, **bo).should == [[1, 2, 3], {:b => 2, :c => 3}]
+ end
+ end
+
evaluate <<-ruby do
def m(*, &b) b end
ruby
@@ -1107,25 +1457,47 @@ describe "A method" do
m({a: 1}).should == {a: 1}
m({"a" => 1}).should == {"a" => 1}
- -> { m(a: 1) }.should raise_error(ArgumentError, 'no keywords accepted')
- -> { m(**{a: 1}) }.should raise_error(ArgumentError, 'no keywords accepted')
- -> { m("a" => 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ -> { m(a: 1) }.should raise_error(ArgumentError)
+ -> { m(**{a: 1}) }.should raise_error(ArgumentError)
+ -> { m("a" => 1) }.should raise_error(ArgumentError)
end
- evaluate <<-ruby do
- def m(a, b = nil, c = nil, d, e: nil, **f)
- [a, b, c, d, e, f]
+ ruby_version_is ''...'3.0' do
+ evaluate <<-ruby do
+ def m(a, b = nil, c = nil, d, e: nil, **f)
+ [a, b, c, d, e, f]
+ end
+ ruby
+
+ result = m(1, 2)
+ result.should == [1, nil, nil, 2, nil, {}]
+
+ suppress_warning do
+ result = m(1, 2, {foo: :bar})
+ result.should == [1, nil, nil, 2, nil, {foo: :bar}]
end
- ruby
- result = m(1, 2)
- result.should == [1, nil, nil, 2, nil, {}]
+ result = m(1, {foo: :bar})
+ result.should == [1, nil, nil, {foo: :bar}, nil, {}]
+ end
+ end
+
+ ruby_version_is '3.0' do
+ evaluate <<-ruby do
+ def m(a, b = nil, c = nil, d, e: nil, **f)
+ [a, b, c, d, e, f]
+ end
+ ruby
+
+ result = m(1, 2)
+ result.should == [1, nil, nil, 2, nil, {}]
- result = m(1, 2, {foo: :bar})
- result.should == [1, 2, nil, {foo: :bar}, nil, {}]
+ result = m(1, 2, {foo: :bar})
+ result.should == [1, 2, nil, {foo: :bar}, nil, {}]
- result = m(1, {foo: :bar})
- result.should == [1, nil, nil, {foo: :bar}, nil, {}]
+ result = m(1, {foo: :bar})
+ result.should == [1, nil, nil, {foo: :bar}, nil, {}]
+ end
end
end
@@ -1139,27 +1511,60 @@ describe "A method" do
end
end
- context 'when passing an empty keyword splat to a method that does not accept keywords' do
- evaluate <<-ruby do
- def m(a); a; end
- ruby
- h = {}
+ ruby_version_is ''...'3.0' do
+ context 'when passing an empty keyword splat to a method that does not accept keywords' do
+ evaluate <<-ruby do
+ def m(a); a; end
+ ruby
+ h = {}
- -> do
- m(**h).should == {}
- end.should raise_error(ArgumentError)
+ -> do
+ m(**h).should == {}
+ end.should complain(/warning: Passing the keyword argument as the last hash parameter is deprecated/)
+ end
end
end
- context "raises ArgumentError if passing hash as keyword arguments" do
- evaluate <<-ruby do
- def m(a: nil); a; end
- ruby
+ ruby_version_is ''...'3.0' do
+ context "assigns keyword arguments from a passed Hash without modifying it" do
+ evaluate <<-ruby do
+ def m(a: nil); a; end
+ ruby
- options = {a: 1}.freeze
- -> do
- m(options)
- end.should raise_error(ArgumentError)
+ options = {a: 1}.freeze
+ -> do
+ suppress_warning do
+ m(options).should == 1
+ end
+ end.should_not raise_error
+ options.should == {a: 1}
+ end
+ end
+ end
+
+ ruby_version_is '3.0' do
+ context 'when passing an empty keyword splat to a method that does not accept keywords' do
+ evaluate <<-ruby do
+ def m(a); a; end
+ ruby
+ h = {}
+
+ -> do
+ m(**h).should == {}
+ end.should raise_error(ArgumentError)
+ end
+ end
+
+ context "raises ArgumentError if passing hash as keyword arguments" do
+ evaluate <<-ruby do
+ def m(a: nil); a; end
+ ruby
+
+ options = {a: 1}.freeze
+ -> do
+ m(options)
+ end.should raise_error(ArgumentError)
+ end
end
end
@@ -1193,42 +1598,14 @@ describe "A method call with a space between method name and parentheses" do
end
end
- context "when a single argument is provided" do
- it "assigns a simple expression" do
- args = m (1)
- args.should == [1]
- end
-
- it "assigns an expression consisting of multiple statements" do
- args = m ((0; 1))
- args.should == [1]
- end
-
- it "assigns one single statement, without the need of parentheses" do
+ context "when a single argument provided" do
+ it "assigns it" do
args = m (1 == 1 ? true : false)
args.should == [true]
end
-
- ruby_version_is "3.3" do
- it "supports multiple statements" do
- eval("m (1; 2)").should == [2]
- end
- end
end
- context "when multiple arguments are provided" do
- it "assigns simple expressions" do
- args = m (1), (2)
- args.should == [1, 2]
- end
-
- it "assigns expressions consisting of multiple statements" do
- args = m ((0; 1)), ((2; 3))
- args.should == [1, 3]
- end
- end
-
- context "when the argument looks like an argument list" do
+ context "when 2+ arguments provided" do
it "raises a syntax error" do
-> {
eval("m (1, 2)")
@@ -1293,108 +1670,105 @@ describe "An array-dereference method ([])" do
end
end
-describe "An endless method definition" do
- context "without arguments" do
- evaluate <<-ruby do
- def m() = 42
- ruby
-
- m.should == 42
- end
-
- context "without parenthesis" do
+ruby_version_is "3.0" do
+ describe "An endless method definition" do
+ context "without arguments" do
evaluate <<-ruby do
- def m = 42
- ruby
+ def m() = 42
+ ruby
m.should == 42
end
+
+ context "without parenthesis" do
+ evaluate <<-ruby do
+ def m = 42
+ ruby
+
+ m.should == 42
+ end
+ end
end
- end
- context "with arguments" do
- evaluate <<-ruby do
- def m(a, b) = a + b
- ruby
+ context "with arguments" do
+ evaluate <<-ruby do
+ def m(a, b) = a + b
+ ruby
- m(1, 4).should == 5
+ m(1, 4).should == 5
+ end
end
- end
- context "with multiline body" do
- evaluate <<-ruby do
- def m(n) =
- if n > 2
- m(n - 2) + m(n - 1)
- else
- 1
- end
- ruby
+ context "with multiline body" do
+ evaluate <<-ruby do
+ def m(n) =
+ if n > 2
+ m(n - 2) + m(n - 1)
+ else
+ 1
+ end
+ ruby
- m(6).should == 8
+ m(6).should == 8
+ end
end
- end
- # tested more thoroughly in language/delegation_spec.rb
- context "with args forwarding" do
- evaluate <<-ruby do
- def mm(word, num:)
- word * num
- end
+ context "with args forwarding" do
+ evaluate <<-ruby do
+ def mm(word, num:)
+ word * num
+ end
- def m(...) = mm(...) + mm(...)
- ruby
+ def m(...) = mm(...) + mm(...)
+ ruby
- m("meow", num: 2).should == "meow" * 4
+ m("meow", num: 2).should == "meow" * 4
+ end
end
- end
-end
-describe "Keyword arguments are now separated from positional arguments" do
- context "when the method has only positional parameters" do
- it "treats incoming keyword arguments as positional for compatibility" do
- def foo(a, b, c, hsh)
- hsh[:key]
+ ruby_version_is ""..."3.0" do
+ context "inside 'endless' method definitions" do
+ it "does not allow method calls without parenthesis" do
+ -> {
+ eval("def greet(person) = 'Hi, '.concat person")
+ }.should raise_error(SyntaxError)
+ end
end
-
- foo(1, 2, 3, key: 42).should == 42
end
end
- context "when the method takes a ** parameter" do
- it "captures the passed literal keyword arguments" do
- def foo(a, b, c, **hsh)
- hsh[:key]
- end
+ describe "Keyword arguments are now separated from positional arguments" do
+ context "when the method has only positional parameters" do
+ it "treats incoming keyword arguments as positional for compatibility" do
+ def foo(a, b, c, hsh)
+ hsh[:key]
+ end
- foo(1, 2, 3, key: 42).should == 42
+ foo(1, 2, 3, key: 42).should == 42
+ end
end
- it "captures the passed ** keyword arguments" do
- def foo(a, b, c, **hsh)
- hsh[:key]
+ context "when the method takes a ** parameter" do
+ it "captures the passed literal keyword arguments" do
+ def foo(a, b, c, **hsh)
+ hsh[:key]
+ end
+
+ foo(1, 2, 3, key: 42).should == 42
end
- h = { key: 42 }
- foo(1, 2, 3, **h).should == 42
- end
+ it "captures the passed ** keyword arguments" do
+ def foo(a, b, c, **hsh)
+ hsh[:key]
+ end
- it "does not convert a positional Hash to keyword arguments" do
- def foo(a, b, c, **hsh)
- hsh[:key]
+ h = { key: 42 }
+ foo(1, 2, 3, **h).should == 42
end
- -> {
- foo(1, 2, 3, { key: 42 })
- }.should raise_error(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
- end
- end
-
- context "when the method takes a key: parameter" do
- context "when it's called with a positional Hash and no **" do
- it "raises ArgumentError" do
- def foo(a, b, c, key: 1)
- key
+ it "does not convert a positional Hash to keyword arguments" do
+ def foo(a, b, c, **hsh)
+ hsh[:key]
end
-> {
@@ -1403,14 +1777,28 @@ describe "Keyword arguments are now separated from positional arguments" do
end
end
- context "when it's called with **" do
- it "captures the passed keyword arguments" do
- def foo(a, b, c, key: 1)
- key
+ context "when the method takes a key: parameter" do
+ context "when it's called with a positional Hash and no **" do
+ it "raises ArgumentError" do
+ def foo(a, b, c, key: 1)
+ key
+ end
+
+ -> {
+ foo(1, 2, 3, { key: 42 })
+ }.should raise_error(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
end
+ end
- h = { key: 42 }
- foo(1, 2, 3, **h).should == 42
+ context "when it's called with **" do
+ it "captures the passed keyword arguments" do
+ def foo(a, b, c, key: 1)
+ key
+ end
+
+ h = { key: 42 }
+ foo(1, 2, 3, **h).should == 42
+ end
end
end
end
@@ -1459,7 +1847,7 @@ ruby_version_is "3.1" do
describe "Inside 'endless' method definitions" do
it "allows method calls without parenthesis" do
eval <<-ruby
- def greet(person) = "Hi, ".dup.concat person
+ def greet(person) = "Hi, ".concat person
ruby
greet("Homer").should == "Hi, Homer"
diff --git a/spec/ruby/language/module_spec.rb b/spec/ruby/language/module_spec.rb
index fffcf9c90d..e361bf58f5 100644
--- a/spec/ruby/language/module_spec.rb
+++ b/spec/ruby/language/module_spec.rb
@@ -78,10 +78,20 @@ describe "Assigning an anonymous module to a constant" do
mod.name.should == "ModuleSpecs_CS1"
end
- it "sets the name of a module scoped by an anonymous module" do
- a, b = Module.new, Module.new
- a::B = b
- b.name.should.end_with? '::B'
+ ruby_version_is ""..."3.0" do
+ it "does not set the name of a module scoped by an anonymous module" do
+ a, b = Module.new, Module.new
+ a::B = b
+ b.name.should be_nil
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "sets the name of a module scoped by an anonymous module" do
+ a, b = Module.new, Module.new
+ a::B = b
+ b.name.should.end_with? '::B'
+ end
end
it "sets the name of contained modules when assigning a toplevel anonymous module" do
diff --git a/spec/ruby/language/numbered_parameters_spec.rb b/spec/ruby/language/numbered_parameters_spec.rb
index 06f9948c58..424d7a06e3 100644
--- a/spec/ruby/language/numbered_parameters_spec.rb
+++ b/spec/ruby/language/numbered_parameters_spec.rb
@@ -22,7 +22,7 @@ describe "Numbered parameters" do
it "does not support more than 9 parameters" do
-> {
proc { [_10] }.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
- }.should raise_error(NameError, /undefined local variable or method [`']_10'/)
+ }.should raise_error(NameError, /undefined local variable or method `_10'/)
end
it "can not be used in both outer and nested blocks at the same time" do
@@ -31,19 +31,38 @@ describe "Numbered parameters" do
}.should raise_error(SyntaxError, /numbered parameter is already used in/m)
end
- it "cannot be overwritten with local variable" do
- -> {
- eval <<~CODE
- _1 = 0
- proc { _1 }.call("a").should == 0
- CODE
- }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
+ ruby_version_is ''...'3.0' do
+ it "can be overwritten with local variable" do
+ suppress_warning do
+ eval <<~CODE
+ _1 = 0
+ proc { _1 }.call("a").should == 0
+ CODE
+ end
+ end
+
+ it "warns when numbered parameter is overwritten with local variable" do
+ -> {
+ eval("_1 = 0")
+ }.should complain(/warning: `_1' is reserved for numbered parameter; consider another name/)
+ end
end
- it "errors when numbered parameter is overwritten with local variable" do
- -> {
- eval("_1 = 0")
- }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
+ ruby_version_is '3.0' do
+ it "cannot be overwritten with local variable" do
+ -> {
+ eval <<~CODE
+ _1 = 0
+ proc { _1 }.call("a").should == 0
+ CODE
+ }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
+ end
+
+ it "errors when numbered parameter is overwritten with local variable" do
+ -> {
+ eval("_1 = 0")
+ }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
+ end
end
it "raises SyntaxError when block parameters are specified explicitly" do
@@ -61,8 +80,16 @@ describe "Numbered parameters" do
end
describe "assigning to a numbered parameter" do
- it "raises SyntaxError" do
- -> { eval("proc { _1 = 0 }") }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
+ ruby_version_is ''...'3.0' do
+ it "warns" do
+ -> { eval("proc { _1 = 0 }") }.should complain(/warning: `_1' is reserved for numbered parameter; consider another name/)
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "raises SyntaxError" do
+ -> { eval("proc { _1 = 0 }") }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
+ end
end
end
@@ -82,19 +109,6 @@ describe "Numbered parameters" do
lambda { _9 }.arity.should == 9
end
- it "affects block parameters" do
- -> { _1 }.parameters.should == [[:req, :_1]]
- -> { _2 }.parameters.should == [[:req, :_1], [:req, :_2]]
-
- proc { _1 }.parameters.should == [[:opt, :_1]]
- proc { _2 }.parameters.should == [[:opt, :_1], [:opt, :_2]]
- end
-
- it "affects binding local variables" do
- -> { _1; binding.local_variables }.call("a").should == [:_1]
- -> { _2; binding.local_variables }.call("a", "b").should == [:_1, :_2]
- end
-
it "does not work in methods" do
obj = Object.new
def obj.foo; _1 end
diff --git a/spec/ruby/language/optional_assignments_spec.rb b/spec/ruby/language/optional_assignments_spec.rb
index 2443cc6b79..02461655d6 100644
--- a/spec/ruby/language/optional_assignments_spec.rb
+++ b/spec/ruby/language/optional_assignments_spec.rb
@@ -57,7 +57,7 @@ describe 'Optional variable assignments' do
end
end
- describe 'using an accessor' do
+ describe 'using a accessor' do
before do
klass = Class.new { attr_accessor :b }
@a = klass.new
@@ -103,16 +103,6 @@ describe 'Optional variable assignments' do
@a.b.should == 10
end
- it 'does evaluate receiver only once when assigns' do
- ScratchPad.record []
- @a.b = nil
-
- (ScratchPad << :evaluated; @a).b ||= 10
-
- ScratchPad.recorded.should == [:evaluated]
- @a.b.should == 10
- end
-
it 'returns the new value if set to false' do
def @a.b=(x)
:v
@@ -132,148 +122,29 @@ describe 'Optional variable assignments' do
(@a.b ||= 20).should == 10
end
- it 'ignores method visibility when receiver is self' do
- klass_with_private_methods = Class.new do
- def initialize(v) @a = v end
- def public_method(v); self.a ||= v end
- private
- def a; @a end
- def a=(v) @a = v; 42 end
- end
-
- a = klass_with_private_methods.new(false)
- a.public_method(10).should == 10
- end
- end
-
- describe 'using a #[]' do
- before do
- @a = {}
+ it 'works when writer is private' do
klass = Class.new do
- def [](k)
- @hash ||= {}
- @hash[k]
- end
-
- def []=(k, v)
- @hash ||= {}
- @hash[k] = v
- 7
+ def t
+ self.b = false
+ (self.b ||= 10).should == 10
+ (self.b ||= 20).should == 10
end
- end
- @b = klass.new
- end
-
- it 'returns the assigned value, not the result of the []= method with ||=' do
- (@b[:k] ||= 12).should == 12
- end
-
- it "evaluates the index precisely once" do
- ary = [:x, :y]
- @a[:x] = 15
- @a[ary.pop] ||= 25
- ary.should == [:x]
- @a.should == { x: 15, y: 25 }
- end
- it "evaluates the index arguments in the correct order" do
- ary = Class.new(Array) do
- def [](x, y)
- super(x + 3 * y)
+ def b
+ @b
end
- def []=(x, y, value)
- super(x + 3 * y, value)
+ def b=(x)
+ @b = x
+ :v
end
- end.new
- ary[0, 0] = 1
- ary[1, 0] = 1
- ary[2, 0] = nil
- ary[3, 0] = 1
- ary[4, 0] = 1
- ary[5, 0] = 1
- ary[6, 0] = nil
-
- foo = [0, 2]
-
- ary[foo.pop, foo.pop] ||= 2 # expected `ary[2, 0] ||= 2`
-
- ary[2, 0].should == 2
- ary[6, 0].should == nil # returns the same element as `ary[0, 2]`
- end
-
- it 'evaluates receiver only once when assigns' do
- ScratchPad.record []
- @a[:k] = nil
- (ScratchPad << :evaluated; @a)[:k] ||= 2
-
- ScratchPad.recorded.should == [:evaluated]
- @a[:k].should == 2
- end
-
- it 'ignores method visibility when receiver is self' do
- klass_with_private_methods = Class.new do
- def initialize(h) @a = h end
- def public_method(k, v); self[k] ||= v end
- private
- def [](k) @a[k] end
- def []=(k, v) @a[k] = v; 42 end
+ private :b=
end
- a = klass_with_private_methods.new(k: false)
- a.public_method(:k, 10).should == 10
+ klass.new.t
end
- context 'splatted argument' do
- it 'correctly handles it' do
- (@b[*[:m]] ||= 10).should == 10
- @b[:m].should == 10
-
- (@b[*(1; [:n])] ||= 10).should == 10
- @b[:n].should == 10
-
- (@b[*begin 1; [:k] end] ||= 10).should == 10
- @b[:k].should == 10
- end
-
- it 'calls #to_a only once' do
- k = Object.new
- def k.to_a
- ScratchPad << :to_a
- [:k]
- end
-
- ScratchPad.record []
- (@b[*k] ||= 20).should == 20
- @b[:k].should == 20
- ScratchPad.recorded.should == [:to_a]
- end
-
- it 'correctly handles a nested splatted argument' do
- (@b[*[*[:k]]] ||= 20).should == 20
- @b[:k].should == 20
- end
-
- it 'correctly handles multiple nested splatted arguments' do
- klass_with_multiple_parameters = Class.new do
- def [](k1, k2, k3)
- @hash ||= {}
- @hash[:"#{k1}#{k2}#{k3}"]
- end
-
- def []=(k1, k2, k3, v)
- @hash ||= {}
- @hash[:"#{k1}#{k2}#{k3}"] = v
- 7
- end
- end
- a = klass_with_multiple_parameters.new
-
- (a[*[:a], *[:b], *[:c]] ||= 20).should == 20
- a[:a, :b, :c].should == 20
- end
- end
end
end
@@ -320,7 +191,7 @@ describe 'Optional variable assignments' do
end
end
- describe 'using an accessor' do
+ describe 'using a single variable' do
before do
klass = Class.new { attr_accessor :b }
@a = klass.new
@@ -365,29 +236,6 @@ describe 'Optional variable assignments' do
@a.b.should == 20
end
-
- it 'does evaluate receiver only once when assigns' do
- ScratchPad.record []
- @a.b = 10
-
- (ScratchPad << :evaluated; @a).b &&= 20
-
- ScratchPad.recorded.should == [:evaluated]
- @a.b.should == 20
- end
-
- it 'ignores method visibility when receiver is self' do
- klass_with_private_methods = Class.new do
- def initialize(v) @a = v end
- def public_method(v); self.a &&= v end
- private
- def a; @a end
- def a=(v) @a = v; 42 end
- end
-
- a = klass_with_private_methods.new(true)
- a.public_method(10).should == 10
- end
end
describe 'using a #[]' do
@@ -449,15 +297,17 @@ describe 'Optional variable assignments' do
end
it 'returns the assigned value, not the result of the []= method with ||=' do
- @b[:k] = 10
- (@b[:k] &&= 12).should == 12
+ (@b[:k] ||= 12).should == 12
+ end
+
+ it 'correctly handles a splatted argument for the index' do
+ (@b[*[:k]] ||= 12).should == 12
end
it "evaluates the index precisely once" do
ary = [:x, :y]
@a[:x] = 15
- @a[:y] = 20
- @a[ary.pop] &&= 25
+ @a[ary.pop] ||= 25
ary.should == [:x]
@a.should == { x: 15, y: 25 }
end
@@ -474,103 +324,24 @@ describe 'Optional variable assignments' do
end.new
ary[0, 0] = 1
ary[1, 0] = 1
- ary[2, 0] = 1
+ ary[2, 0] = nil
ary[3, 0] = 1
ary[4, 0] = 1
ary[5, 0] = 1
- ary[6, 0] = 1
+ ary[6, 0] = nil
foo = [0, 2]
- ary[foo.pop, foo.pop] &&= 2 # expected `ary[2, 0] &&= 2`
+ ary[foo.pop, foo.pop] ||= 2
ary[2, 0].should == 2
- ary[6, 0].should == 1 # returns the same element as `ary[0, 2]`
- end
-
- it 'evaluates receiver only once when assigns' do
- ScratchPad.record []
- @a[:k] = 1
-
- (ScratchPad << :evaluated; @a)[:k] &&= 2
-
- ScratchPad.recorded.should == [:evaluated]
- @a[:k].should == 2
+ ary[6, 0].should == nil
end
it 'returns the assigned value, not the result of the []= method with +=' do
@b[:k] = 17
(@b[:k] += 12).should == 29
end
-
- it 'ignores method visibility when receiver is self' do
- klass_with_private_methods = Class.new do
- def initialize(h) @a = h end
- def public_method(k, v); self[k] &&= v end
- private
- def [](k) @a[k] end
- def []=(k, v) @a[k] = v; 42 end
- end
-
- a = klass_with_private_methods.new(k: true)
- a.public_method(:k, 10).should == 10
- end
-
- context 'splatted argument' do
- it 'correctly handles it' do
- @b[:m] = 0
- (@b[*[:m]] &&= 10).should == 10
- @b[:m].should == 10
-
- @b[:n] = 0
- (@b[*(1; [:n])] &&= 10).should == 10
- @b[:n].should == 10
-
- @b[:k] = 0
- (@b[*begin 1; [:k] end] &&= 10).should == 10
- @b[:k].should == 10
- end
-
- it 'calls #to_a only once' do
- k = Object.new
- def k.to_a
- ScratchPad << :to_a
- [:k]
- end
-
- ScratchPad.record []
- @b[:k] = 10
- (@b[*k] &&= 20).should == 20
- @b[:k].should == 20
- ScratchPad.recorded.should == [:to_a]
- end
-
- it 'correctly handles a nested splatted argument' do
- @b[:k] = 10
- (@b[*[*[:k]]] &&= 20).should == 20
- @b[:k].should == 20
- end
-
- it 'correctly handles multiple nested splatted arguments' do
- klass_with_multiple_parameters = Class.new do
- def [](k1, k2, k3)
- @hash ||= {}
- @hash[:"#{k1}#{k2}#{k3}"]
- end
-
- def []=(k1, k2, k3, v)
- @hash ||= {}
- @hash[:"#{k1}#{k2}#{k3}"] = v
- 7
- end
- end
- a = klass_with_multiple_parameters.new
-
- a[:a, :b, :c] = 10
- (a[*[:a], *[:b], *[:c]] &&= 20).should == 20
- a[:a, :b, :c].should == 20
- end
- end
end
end
@@ -663,7 +434,7 @@ describe 'Optional constant assignment' do
ConstantSpecs::ClassA::OR_ASSIGNED_CONSTANT2.should == :assigned
end
- it 'causes side-effects of the module part to be applied only once (for nil constant)' do
+ it 'causes side-effects of the module part to be applied (for nil constant)' do
suppress_warning do # already initialized constant
ConstantSpecs::ClassA::NIL_OR_ASSIGNED_CONSTANT2 = nil
x = 0
@@ -721,20 +492,5 @@ describe 'Optional constant assignment' do
ConstantSpecs::OpAssignFalse.should == false
ConstantSpecs.send :remove_const, :OpAssignFalse
end
-
- it 'causes side-effects of the module part to be applied only once (when assigns)' do
- module ConstantSpecs
- OpAssignTrue = true
- end
-
- suppress_warning do # already initialized constant
- x = 0
- (x += 1; ConstantSpecs)::OpAssignTrue &&= :assigned
- x.should == 1
- ConstantSpecs::OpAssignTrue.should == :assigned
- end
-
- ConstantSpecs.send :remove_const, :OpAssignTrue
- end
end
end
diff --git a/spec/ruby/language/pattern_matching/3.1.rb b/spec/ruby/language/pattern_matching/3.1.rb
deleted file mode 100644
index 7a09084e41..0000000000
--- a/spec/ruby/language/pattern_matching/3.1.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-describe "Pattern matching" do
- before :each do
- ScratchPad.record []
- end
-
- describe "Ruby 3.1 improvements" do
- ruby_version_is "3.1" do
- it "can omit parentheses in one line pattern matching" do
- [1, 2] => a, b
- [a, b].should == [1, 2]
-
- {a: 1} => a:
- a.should == 1
- end
-
- it "supports pinning instance variables" do
- @a = /a/
- case 'abc'
- in ^@a
- true
- end.should == true
- end
-
- it "supports pinning class variables" do
- result = nil
- Module.new do
- result = module_eval(<<~RUBY)
- @@a = 0..10
-
- case 2
- in ^@@a
- true
- end
- RUBY
- end
-
- result.should == true
- end
-
- it "supports pinning global variables" do
- $a = /a/
- case 'abc'
- in ^$a
- true
- end.should == true
- end
-
- it "supports pinning expressions" do
- case 'abc'
- in ^(/a/)
- true
- end.should == true
-
- case 0
- in ^(0 + 0)
- true
- end.should == true
- end
-
- it "supports pinning expressions in array pattern" do
- case [3]
- in [^(1 + 2)]
- true
- end.should == true
- end
-
- it "supports pinning expressions in hash pattern" do
- case {name: '2.6', released_at: Time.new(2018, 12, 25)}
- in {released_at: ^(Time.new(2010)..Time.new(2020))}
- true
- end.should == true
- end
- end
- end
-end
diff --git a/spec/ruby/language/pattern_matching_spec.rb b/spec/ruby/language/pattern_matching_spec.rb
index 94432b1fa0..f3cc86fa0b 100644
--- a/spec/ruby/language/pattern_matching_spec.rb
+++ b/spec/ruby/language/pattern_matching_spec.rb
@@ -1,143 +1,143 @@
require_relative '../spec_helper'
describe "Pattern matching" do
+ # TODO: Remove excessive eval calls when Ruby 3 is the minimum version.
+ # It is best to keep the eval's longer if other Ruby impls cannot parse pattern matching yet.
+
before :each do
ScratchPad.record []
end
- describe "Rightward assignment (`=>`) that can be standalone assoc operator that" do
- it "deconstructs value" do
- suppress_warning do
- [0, 1] => [a, b]
- [a, b].should == [0, 1]
- end
- end
-
- it "deconstructs value and properly scopes variables" do
+ ruby_version_is "3.0" do
+ it "can be standalone assoc operator that deconstructs value" do
suppress_warning do
- a = nil
- 1.times {
+ eval(<<-RUBY).should == [0, 1]
[0, 1] => [a, b]
- }
- [a, defined?(b)].should == [0, nil]
+ [a, b]
+ RUBY
end
end
- it "can work with keywords" do
- { a: 0, b: 1 } => { a:, b: }
- [a, b].should == [0, 1]
- end
- end
-
- describe "One-line pattern matching" do
- it "can be used to check if a pattern matches for Array-like entities" do
- ([0, 1] in [a, b]).should == true
- ([0, 1] in [a, b, c]).should == false
- end
-
- it "can be used to check if a pattern matches for Hash-like entities" do
- ({ a: 0, b: 1 } in { a:, b: }).should == true
- ({ a: 0, b: 1 } in { a:, b:, c: }).should == false
- end
- end
-
- describe "find pattern" do
- it "captures preceding elements to the pattern" do
- case [0, 1, 2, 3]
- in [*pre, 2, 3]
- pre
- else
- false
- end.should == [0, 1]
- end
+ describe "find pattern" do
+ it "captures preceding elements to the pattern" do
+ eval(<<~RUBY).should == [0, 1]
+ case [0, 1, 2, 3]
+ in [*pre, 2, 3]
+ pre
+ else
+ false
+ end
+ RUBY
+ end
- it "captures following elements to the pattern" do
- case [0, 1, 2, 3]
- in [0, 1, *post]
- post
- else
- false
- end.should == [2, 3]
- end
+ it "captures following elements to the pattern" do
+ eval(<<~RUBY).should == [2, 3]
+ case [0, 1, 2, 3]
+ in [0, 1, *post]
+ post
+ else
+ false
+ end
+ RUBY
+ end
- it "captures both preceding and following elements to the pattern" do
- case [0, 1, 2, 3, 4]
- in [*pre, 2, *post]
- [pre, post]
- else
- false
- end.should == [[0, 1], [3, 4]]
- end
+ it "captures both preceding and following elements to the pattern" do
+ eval(<<~RUBY).should == [[0, 1], [3, 4]]
+ case [0, 1, 2, 3, 4]
+ in [*pre, 2, *post]
+ [pre, post]
+ else
+ false
+ end
+ RUBY
+ end
- it "can capture the entirety of the pattern" do
- case [0, 1, 2, 3, 4]
- in [*everything]
- everything
- else
- false
- end.should == [0, 1, 2, 3, 4]
- end
+ it "can capture the entirety of the pattern" do
+ eval(<<~RUBY).should == [0, 1, 2, 3, 4]
+ case [0, 1, 2, 3, 4]
+ in [*everything]
+ everything
+ else
+ false
+ end
+ RUBY
+ end
- it "will match an empty Array-like structure" do
- case []
- in [*everything]
- everything
- else
- false
- end.should == []
- end
+ it "will match an empty Array-like structure" do
+ eval(<<~RUBY).should == []
+ case []
+ in [*everything]
+ everything
+ else
+ false
+ end
+ RUBY
+ end
- it "can be nested" do
- case [0, [2, 4, 6], [3, 9, 27], [4, 16, 64]]
- in [*pre, [*, 9, a], *post]
- [pre, post, a]
- else
- false
- end.should == [[0, [2, 4, 6]], [[4, 16, 64]], 27]
- end
+ it "can be nested" do
+ eval(<<~RUBY).should == [[0, [2, 4, 6]], [[4, 16, 64]], 27]
+ case [0, [2, 4, 6], [3, 9, 27], [4, 16, 64]]
+ in [*pre, [*, 9, a], *post]
+ [pre, post, a]
+ else
+ false
+ end
+ RUBY
+ end
- it "can be nested with an array pattern" do
- case [0, [2, 4, 6], [3, 9, 27], [4, 16, 64]]
- in [_, _, [*, 9, *], *post]
- post
- else
- false
- end.should == [[4, 16, 64]]
- end
+ it "can be nested with an array pattern" do
+ eval(<<~RUBY).should == [[4, 16, 64]]
+ case [0, [2, 4, 6], [3, 9, 27], [4, 16, 64]]
+ in [_, _, [*, 9, *], *post]
+ post
+ else
+ false
+ end
+ RUBY
+ end
- it "can be nested within a hash pattern" do
- case {a: [3, 9, 27]}
- in {a: [*, 9, *post]}
- post
- else
- false
- end.should == [27]
- end
+ it "can be nested within a hash pattern" do
+ eval(<<~RUBY).should == [27]
+ case {a: [3, 9, 27]}
+ in {a: [*, 9, *post]}
+ post
+ else
+ false
+ end
+ RUBY
+ end
- it "can nest hash and array patterns" do
- case [0, {a: 42, b: [0, 1]}, {a: 42, b: [1, 2]}]
- in [*, {a:, b: [1, c]}, *]
- [a, c]
- else
- false
- end.should == [42, 2]
+ it "can nest hash and array patterns" do
+ eval(<<~RUBY).should == [42, 2]
+ case [0, {a: 42, b: [0, 1]}, {a: 42, b: [1, 2]}]
+ in [*, {a:, b: [1, c]}, *]
+ [a, c]
+ else
+ false
+ end
+ RUBY
+ end
end
end
it "extends case expression with case/in construction" do
- case [0, 1]
- in [0]
- :foo
- in [0, 1]
- :bar
- end.should == :bar
+ eval(<<~RUBY).should == :bar
+ case [0, 1]
+ in [0]
+ :foo
+ in [0, 1]
+ :bar
+ end
+ RUBY
end
it "allows using then operator" do
- case [0, 1]
- in [0] then :foo
- in [0, 1] then :bar
- end.should == :bar
+ eval(<<~RUBY).should == :bar
+ case [0, 1]
+ in [0] then :foo
+ in [0, 1] then :bar
+ end
+ RUBY
end
describe "warning" do
@@ -154,35 +154,47 @@ describe "Pattern matching" do
@src = 'case [0, 1]; in [a, b]; end'
end
- it "does not warn about pattern matching is experimental feature" do
- -> { eval @src }.should_not complain
- end
- end
-
- context 'when one-line form' do
- before :each do
- @src = '[0, 1] => [a, b]'
- end
-
- ruby_version_is ""..."3.1" do
+ ruby_version_is ""..."3.0" do
it "warns about pattern matching is experimental feature" do
-> { eval @src }.should complain(/pattern matching is experimental, and the behavior may change in future versions of Ruby!/i)
end
end
- ruby_version_is "3.1" do
+ ruby_version_is "3.0" do
it "does not warn about pattern matching is experimental feature" do
-> { eval @src }.should_not complain
end
end
end
+
+ context 'when one-line form' do
+ ruby_version_is '3.0' do
+ before :each do
+ @src = '[0, 1] => [a, b]'
+ end
+
+ ruby_version_is ""..."3.1" do
+ it "warns about pattern matching is experimental feature" do
+ -> { eval @src }.should complain(/pattern matching is experimental, and the behavior may change in future versions of Ruby!/i)
+ end
+ end
+
+ ruby_version_is "3.1" do
+ it "does not warn about pattern matching is experimental feature" do
+ -> { eval @src }.should_not complain
+ end
+ end
+ end
+ end
end
it "binds variables" do
- case [0, 1]
- in [0, a]
- a
- end.should == 1
+ eval(<<~RUBY).should == 1
+ case [0, 1]
+ in [0, a]
+ a
+ end
+ RUBY
end
it "cannot mix in and when operators" do
@@ -193,7 +205,7 @@ describe "Pattern matching" do
in []
end
RUBY
- }.should raise_error(SyntaxError, /syntax error, unexpected `in'|\(eval\):3: syntax error, unexpected keyword_in|unexpected 'in'/)
+ }.should raise_error(SyntaxError, /syntax error, unexpected `in'/)
-> {
eval <<~RUBY
@@ -202,52 +214,41 @@ describe "Pattern matching" do
when 1 == 1
end
RUBY
- }.should raise_error(SyntaxError, /syntax error, unexpected `when'|\(eval\):3: syntax error, unexpected keyword_when|unexpected 'when'/)
+ }.should raise_error(SyntaxError, /syntax error, unexpected `when'/)
end
it "checks patterns until the first matching" do
- case [0, 1]
- in [0]
- :foo
- in [0, 1]
- :bar
- in [0, 1]
- :baz
- end.should == :bar
+ eval(<<~RUBY).should == :bar
+ case [0, 1]
+ in [0]
+ :foo
+ in [0, 1]
+ :bar
+ in [0, 1]
+ :baz
+ end
+ RUBY
end
it "executes else clause if no pattern matches" do
- case [0, 1]
- in [0]
- true
- else
- false
- end.should == false
- end
-
- it "raises NoMatchingPatternError if no pattern matches and no else clause" do
- -> {
+ eval(<<~RUBY).should == false
case [0, 1]
in [0]
+ true
+ else
+ false
end
- }.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
-
- error_pattern = ruby_version_is("3.4") ? /\{a: 0, b: 1\}/ : /\{:a=>0, :b=>1\}/
- -> {
- case {a: 0, b: 1}
- in a: 1, b: 1
- end
- }.should raise_error(NoMatchingPatternError, error_pattern)
+ RUBY
end
- it "raises NoMatchingPatternError if no pattern matches and evaluates the expression only once" do
- evals = 0
+ it "raises NoMatchingPatternError if no pattern matches and no else clause" do
-> {
- case (evals += 1; [0, 1])
- in [0]
- end
+ eval <<~RUBY
+ case [0, 1]
+ in [0]
+ end
+ RUBY
}.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
- evals.should == 1
end
it "does not allow calculation or method calls in a pattern" do
@@ -258,185 +259,230 @@ describe "Pattern matching" do
true
end
RUBY
- }.should raise_error(SyntaxError, /unexpected|expected a delimiter after the patterns of an `in` clause/)
+ }.should raise_error(SyntaxError, /unexpected/)
end
it "evaluates the case expression once for multiple patterns, caching the result" do
- case (ScratchPad << :foo; 1)
- in 0
- false
- in 1
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case (ScratchPad << :foo; 1)
+ in 0
+ false
+ in 1
+ true
+ end
+ RUBY
ScratchPad.recorded.should == [:foo]
end
describe "guards" do
it "supports if guard" do
- case 0
- in 0 if false
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == false
+ case 0
+ in 0 if false
+ true
+ else
+ false
+ end
+ RUBY
- case 0
- in 0 if true
- true
- else
- false
- end.should == true
+ eval(<<~RUBY).should == true
+ case 0
+ in 0 if true
+ true
+ else
+ false
+ end
+ RUBY
end
it "supports unless guard" do
- case 0
- in 0 unless true
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == false
+ case 0
+ in 0 unless true
+ true
+ else
+ false
+ end
+ RUBY
- case 0
- in 0 unless false
- true
- else
- false
- end.should == true
+ eval(<<~RUBY).should == true
+ case 0
+ in 0 unless false
+ true
+ else
+ false
+ end
+ RUBY
end
it "makes bound variables visible in guard" do
- case [0, 1]
- in [a, 1] if a >= 0
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [0, 1]
+ in [a, 1] if a >= 0
+ true
+ end
+ RUBY
end
it "does not evaluate guard if pattern does not match" do
- case 0
- in 1 if (ScratchPad << :foo) || true
- else
- end
+ eval <<~RUBY
+ case 0
+ in 1 if (ScratchPad << :foo) || true
+ else
+ end
+ RUBY
ScratchPad.recorded.should == []
end
it "takes guards into account when there are several matching patterns" do
- case 0
- in 0 if false
- :foo
- in 0 if true
- :bar
- end.should == :bar
+ eval(<<~RUBY).should == :bar
+ case 0
+ in 0 if false
+ :foo
+ in 0 if true
+ :bar
+ end
+ RUBY
end
it "executes else clause if no guarded pattern matches" do
- case 0
- in 0 if false
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == false
+ case 0
+ in 0 if false
+ true
+ else
+ false
+ end
+ RUBY
end
it "raises NoMatchingPatternError if no guarded pattern matches and no else clause" do
-> {
- case [0, 1]
- in [0, 1] if false
- end
+ eval <<~RUBY
+ case [0, 1]
+ in [0, 1] if false
+ end
+ RUBY
}.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
end
end
describe "value pattern" do
it "matches an object such that pattern === object" do
- case 0
- in 0
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case 0
+ in 0
+ true
+ end
+ RUBY
- case 0
- in (
- -1..1)
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case 0
+ in (-1..1)
+ true
+ end
+ RUBY
- case 0
- in Integer
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case 0
+ in Integer
+ true
+ end
+ RUBY
- case "0"
- in /0/
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case "0"
+ in /0/
+ true
+ end
+ RUBY
- case "0"
- in -> s { s == "0" }
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case "0"
+ in ->(s) { s == "0" }
+ true
+ end
+ RUBY
end
it "allows string literal with interpolation" do
x = "x"
- case "x"
- in "#{x + ""}"
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case "x"
+ in "#{x + ""}"
+ true
+ end
+ RUBY
end
end
describe "variable pattern" do
it "matches a value and binds variable name to this value" do
- case 0
- in a
- a
- end.should == 0
+ eval(<<~RUBY).should == 0
+ case 0
+ in a
+ a
+ end
+ RUBY
end
it "makes bounded variable visible outside a case statement scope" do
- case 0
- in a
- end
+ eval(<<~RUBY).should == 0
+ case 0
+ in a
+ end
- a.should == 0
+ a
+ RUBY
end
it "create local variables even if a pattern doesn't match" do
- case 0
- in a
- in b
- in c
- end
+ eval(<<~RUBY).should == [0, nil, nil]
+ case 0
+ in a
+ in b
+ in c
+ end
- [a, b, c].should == [0, nil, nil]
+ [a, b, c]
+ RUBY
end
it "allow using _ name to drop values" do
- case [0, 1]
- in [a, _]
- a
- end.should == 0
+ eval(<<~RUBY).should == 0
+ case [0, 1]
+ in [a, _]
+ a
+ end
+ RUBY
end
it "supports using _ in a pattern several times" do
- case [0, 1, 2]
- in [0, _, _]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [0, 1, 2]
+ in [0, _, _]
+ true
+ end
+ RUBY
end
it "supports using any name with _ at the beginning in a pattern several times" do
- case [0, 1, 2]
- in [0, _x, _x]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [0, 1, 2]
+ in [0, _x, _x]
+ true
+ end
+ RUBY
- case {a: 0, b: 1, c: 2}
- in {a: 0, b: _x, c: _x}
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case {a: 0, b: 1, c: 2}
+ in {a: 0, b: _x, c: _x}
+ true
+ end
+ RUBY
end
it "does not support using variable name (except _) several times" do
@@ -452,24 +498,30 @@ describe "Pattern matching" do
it "supports existing variables in a pattern specified with ^ operator" do
a = 0
- case 0
- in ^a
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case 0
+ in ^a
+ true
+ end
+ RUBY
end
it "allows applying ^ operator to bound variables" do
- case [1, 1]
- in [n, ^n]
- n
- end.should == 1
+ eval(<<~RUBY).should == 1
+ case [1, 1]
+ in [n, ^n]
+ n
+ end
+ RUBY
- case [1, 2]
- in [n, ^n]
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == false
+ case [1, 2]
+ in [n, ^n]
+ true
+ else
+ false
+ end
+ RUBY
end
it "requires bound variable to be specified in a pattern before ^ operator when it relies on a bound variable" do
@@ -488,10 +540,12 @@ describe "Pattern matching" do
describe "alternative pattern" do
it "matches if any of patterns matches" do
- case 0
- in 0 | 1 | 2
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case 0
+ in 0 | 1 | 2
+ true
+ end
+ RUBY
end
it "does not support variable binding" do
@@ -505,370 +559,430 @@ describe "Pattern matching" do
end
it "support underscore prefixed variables in alternation" do
- case [0, 1]
- in [1, _]
- false
- in [0, 0] | [0, _a]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [0, 1]
+ in [1, _]
+ false
+ in [0, 0] | [0, _a]
+ true
+ end
+ RUBY
end
it "can be used as a nested pattern" do
- case [[1], ["2"]]
- in [[0] | nil, _]
- false
- in [[1], [1]]
- false
- in [[1], [2 | "2"]]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [[1], ["2"]]
+ in [[0] | nil, _]
+ false
+ in [[1], [1]]
+ false
+ in [[1], [2 | "2"]]
+ true
+ end
+ RUBY
- case [1, 2]
- in [0, _] | {a: 0}
- false
- in {a: 1, b: 2} | [1, 2]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [1, 2]
+ in [0, _] | {a: 0}
+ false
+ in {a: 1, b: 2} | [1, 2]
+ true
+ end
+ RUBY
end
end
describe "AS pattern" do
it "binds a variable to a value if pattern matches" do
- case 0
- in Integer => n
- n
- end.should == 0
+ eval(<<~RUBY).should == 0
+ case 0
+ in Integer => n
+ n
+ end
+ RUBY
end
it "can be used as a nested pattern" do
- case [1, [2, 3]]
- in [1, Array => ary]
- ary
- end.should == [2, 3]
+ eval(<<~RUBY).should == [2, 3]
+ case [1, [2, 3]]
+ in [1, Array => ary]
+ ary
+ end
+ RUBY
end
end
describe "Array pattern" do
it "supports form Constant(pat, pat, ...)" do
- case [0, 1, 2]
- in Array(0, 1, 2)
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [0, 1, 2]
+ in Array(0, 1, 2)
+ true
+ end
+ RUBY
end
it "supports form Constant[pat, pat, ...]" do
- case [0, 1, 2]
- in Array[0, 1, 2]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [0, 1, 2]
+ in Array[0, 1, 2]
+ true
+ end
+ RUBY
end
it "supports form [pat, pat, ...]" do
- case [0, 1, 2]
- in [0, 1, 2]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [0, 1, 2]
+ in [0, 1, 2]
+ true
+ end
+ RUBY
end
it "supports form pat, pat, ..." do
- case [0, 1, 2]
- in 0, 1, 2
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [0, 1, 2]
+ in 0, 1, 2
+ true
+ end
+ RUBY
- case [0, 1, 2]
- in 0, a, 2
- a
- end.should == 1
+ eval(<<~RUBY).should == 1
+ case [0, 1, 2]
+ in 0, a, 2
+ a
+ end
+ RUBY
- case [0, 1, 2]
- in 0, *rest
- rest
- end.should == [1, 2]
+ eval(<<~RUBY).should == [1, 2]
+ case [0, 1, 2]
+ in 0, *rest
+ rest
+ end
+ RUBY
end
it "matches an object with #deconstruct method which returns an array and each element in array matches element in pattern" do
obj = Object.new
+ def obj.deconstruct; [0, 1] end
- def obj.deconstruct
- [0, 1]
- end
-
- case obj
- in [Integer, Integer]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case obj
+ in [Integer, Integer]
+ true
+ end
+ RUBY
end
- it "calls #deconstruct once for multiple patterns, caching the result" do
- obj = Object.new
+ ruby_version_is "3.0" do
+ it "calls #deconstruct once for multiple patterns, caching the result" do
+ obj = Object.new
- def obj.deconstruct
- ScratchPad << :deconstruct
- [0, 1]
- end
+ def obj.deconstruct
+ ScratchPad << :deconstruct
+ [0, 1]
+ end
- case obj
- in [1, 2]
- false
- in [0, 1]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case obj
+ in [1, 2]
+ false
+ in [0, 1]
+ true
+ end
+ RUBY
- ScratchPad.recorded.should == [:deconstruct]
+ ScratchPad.recorded.should == [:deconstruct]
+ end
end
it "calls #deconstruct even on objects that are already an array" do
obj = [1, 2]
-
def obj.deconstruct
ScratchPad << :deconstruct
[3, 4]
end
- case obj
- in [3, 4]
- true
- else
- false
- end.should == true
+ eval(<<~RUBY).should == true
+ case obj
+ in [3, 4]
+ true
+ else
+ false
+ end
+ RUBY
ScratchPad.recorded.should == [:deconstruct]
end
it "does not match object if Constant === object returns false" do
- case [0, 1, 2]
- in String[0, 1, 2]
- true
- else
- false
- end.should == false
- end
-
- it "checks Constant === object before calling #deconstruct" do
- c1 = Class.new
- obj = c1.new
- obj.should_not_receive(:deconstruct)
-
- case obj
- in String[1]
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == false
+ case [0, 1, 2]
+ in String[0, 1, 2]
+ true
+ else
+ false
+ end
+ RUBY
end
it "does not match object without #deconstruct method" do
obj = Object.new
obj.should_receive(:respond_to?).with(:deconstruct)
- case obj
- in Object[]
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == false
+ case obj
+ in Object[]
+ true
+ else
+ false
+ end
+ RUBY
end
it "raises TypeError if #deconstruct method does not return array" do
obj = Object.new
-
- def obj.deconstruct
- ""
- end
+ def obj.deconstruct; "" end
-> {
- case obj
- in Object[]
- else
- end
+ eval <<~RUBY
+ case obj
+ in Object[]
+ else
+ end
+ RUBY
}.should raise_error(TypeError, /deconstruct must return Array/)
end
it "accepts a subclass of Array from #deconstruct" do
obj = Object.new
-
def obj.deconstruct
- Class.new(Array).new([0, 1])
+ subarray = Class.new(Array).new(2)
+ def subarray.[](n)
+ n
+ end
+ subarray
end
- case obj
- in [1, 2]
- false
- in [0, 1]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case obj
+ in [1, 2]
+ false
+ in [0, 1]
+ true
+ end
+ RUBY
end
it "does not match object if elements of array returned by #deconstruct method does not match elements in pattern" do
obj = Object.new
+ def obj.deconstruct; [1] end
- def obj.deconstruct
- [1]
- end
-
- case obj
- in Object[0]
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == false
+ case obj
+ in Object[0]
+ true
+ else
+ false
+ end
+ RUBY
end
it "binds variables" do
- case [0, 1, 2]
- in [a, b, c]
- [a, b, c]
- end.should == [0, 1, 2]
+ eval(<<~RUBY).should == [0, 1, 2]
+ case [0, 1, 2]
+ in [a, b, c]
+ [a, b, c]
+ end
+ RUBY
end
it "supports splat operator *rest" do
- case [0, 1, 2]
- in [0, *rest]
- rest
- end.should == [1, 2]
+ eval(<<~RUBY).should == [1, 2]
+ case [0, 1, 2]
+ in [0, *rest]
+ rest
+ end
+ RUBY
end
it "does not match partially by default" do
- case [0, 1, 2, 3]
- in [1, 2]
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == false
+ case [0, 1, 2, 3]
+ in [1, 2]
+ true
+ else
+ false
+ end
+ RUBY
end
it "does match partially from the array beginning if list + , syntax used" do
- case [0, 1, 2, 3]
- in [0, 1, ]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [0, 1, 2, 3]
+ in [0, 1,]
+ true
+ end
+ RUBY
- case [0, 1, 2, 3]
- in 0, 1,;
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [0, 1, 2, 3]
+ in 0, 1,;
+ true
+ end
+ RUBY
end
it "matches [] with []" do
- case []
- in []
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case []
+ in []
+ true
+ end
+ RUBY
end
it "matches anything with *" do
- case [0, 1]
- in *;
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [0, 1]
+ in *;
+ true
+ end
+ RUBY
end
it "can be used as a nested pattern" do
- case [[1], ["2"]]
- in [[0] | nil, _]
- false
- in [[1], [1]]
- false
- in [[1], [2 | "2"]]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [[1], ["2"]]
+ in [[0] | nil, _]
+ false
+ in [[1], [1]]
+ false
+ in [[1], [2 | "2"]]
+ true
+ end
+ RUBY
- case [1, 2]
- in [0, _] | {a: 0}
- false
- in {a: 1, b: 2} | [1, 2]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [1, 2]
+ in [0, _] | {a: 0}
+ false
+ in {a: 1, b: 2} | [1, 2]
+ true
+ end
+ RUBY
end
end
describe "Hash pattern" do
it "supports form Constant(id: pat, id: pat, ...)" do
- case {a: 0, b: 1}
- in Hash(a: 0, b: 1)
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case {a: 0, b: 1}
+ in Hash(a: 0, b: 1)
+ true
+ end
+ RUBY
end
it "supports form Constant[id: pat, id: pat, ...]" do
- case {a: 0, b: 1}
- in Hash[a: 0, b: 1]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case {a: 0, b: 1}
+ in Hash[a: 0, b: 1]
+ true
+ end
+ RUBY
end
it "supports form {id: pat, id: pat, ...}" do
- case {a: 0, b: 1}
- in {a: 0, b: 1}
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case {a: 0, b: 1}
+ in {a: 0, b: 1}
+ true
+ end
+ RUBY
end
it "supports form id: pat, id: pat, ..." do
- case {a: 0, b: 1}
- in a: 0, b: 1
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case {a: 0, b: 1}
+ in a: 0, b: 1
+ true
+ end
+ RUBY
- case {a: 0, b: 1}
- in a: a, b: b
- [a, b]
- end.should == [0, 1]
+ eval(<<~RUBY).should == [0, 1]
+ case {a: 0, b: 1}
+ in a: a, b: b
+ [a, b]
+ end
+ RUBY
- case {a: 0, b: 1, c: 2}
- in a: 0, **rest
- rest
- end.should == {b: 1, c: 2}
+ eval(<<~RUBY).should == { b: 1, c: 2 }
+ case {a: 0, b: 1, c: 2}
+ in a: 0, **rest
+ rest
+ end
+ RUBY
end
it "supports a: which means a: a" do
- case {a: 0, b: 1}
- in Hash(a:, b:)
- [a, b]
- end.should == [0, 1]
+ eval(<<~RUBY).should == [0, 1]
+ case {a: 0, b: 1}
+ in Hash(a:, b:)
+ [a, b]
+ end
+ RUBY
a = b = nil
-
- case {a: 0, b: 1}
- in Hash[a:, b:]
- [a, b]
- end.should == [0, 1]
+ eval(<<~RUBY).should == [0, 1]
+ case {a: 0, b: 1}
+ in Hash[a:, b:]
+ [a, b]
+ end
+ RUBY
a = b = nil
-
- case {a: 0, b: 1}
- in {a:, b:}
- [a, b]
- end.should == [0, 1]
+ eval(<<~RUBY).should == [0, 1]
+ case {a: 0, b: 1}
+ in {a:, b:}
+ [a, b]
+ end
+ RUBY
a = nil
-
- case {a: 0, b: 1, c: 2}
- in {a:, **rest}
- [a, rest]
- end.should == [0, {b: 1, c: 2}]
+ eval(<<~RUBY).should == [0, {b: 1, c: 2}]
+ case {a: 0, b: 1, c: 2}
+ in {a:, **rest}
+ [a, rest]
+ end
+ RUBY
a = b = nil
-
- case {a: 0, b: 1}
- in a:, b:
- [a, b]
- end.should == [0, 1]
+ eval(<<~RUBY).should == [0, 1]
+ case {a: 0, b: 1}
+ in a:, b:
+ [a, b]
+ end
+ RUBY
end
it "can mix key (a:) and key-value (a: b) declarations" do
- case {a: 0, b: 1}
- in Hash(a:, b: x)
- [a, x]
- end.should == [0, 1]
+ eval(<<~RUBY).should == [0, 1]
+ case {a: 0, b: 1}
+ in Hash(a:, b: x)
+ [a, x]
+ end
+ RUBY
end
it "supports 'string': key literal" do
- case {a: 0}
- in {"a": 0}
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case {a: 0}
+ in {"a": 0}
+ true
+ end
+ RUBY
end
it "does not support non-symbol keys" do
@@ -878,17 +992,19 @@ describe "Pattern matching" do
in {"a" => 1}
end
RUBY
- }.should raise_error(SyntaxError, /unexpected|expected a label as the key in the hash pattern/)
+ }.should raise_error(SyntaxError, /unexpected/)
end
it "does not support string interpolation in keys" do
+ x = "a"
+
-> {
eval <<~'RUBY'
case {a: 1}
in {"#{x}": 1}
end
RUBY
- }.should raise_error(SyntaxError, /symbol literal with interpolation is not allowed|expected a label as the key in the hash pattern/)
+ }.should raise_error(SyntaxError, /symbol literal with interpolation is not allowed/)
end
it "raise SyntaxError when keys duplicate in pattern" do
@@ -903,15 +1019,14 @@ describe "Pattern matching" do
it "matches an object with #deconstruct_keys method which returns a Hash with equal keys and each value in Hash matches value in pattern" do
obj = Object.new
+ def obj.deconstruct_keys(*); {a: 1} end
- def obj.deconstruct_keys(*)
- {a: 1}
- end
-
- case obj
- in {a: 1}
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case obj
+ in {a: 1}
+ true
+ end
+ RUBY
end
it "calls #deconstruct_keys per pattern" do
@@ -922,92 +1037,82 @@ describe "Pattern matching" do
{a: 1}
end
- case obj
- in {b: 1}
- false
- in {a: 1}
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case obj
+ in {b: 1}
+ false
+ in {a: 1}
+ true
+ end
+ RUBY
ScratchPad.recorded.should == [:deconstruct_keys, :deconstruct_keys]
end
it "does not match object if Constant === object returns false" do
- case {a: 1}
- in String[a: 1]
- true
- else
- false
- end.should == false
- end
-
- it "checks Constant === object before calling #deconstruct_keys" do
- c1 = Class.new
- obj = c1.new
- obj.should_not_receive(:deconstruct_keys)
-
- case obj
- in String(a: 1)
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == false
+ case {a: 1}
+ in String[a: 1]
+ true
+ else
+ false
+ end
+ RUBY
end
it "does not match object without #deconstruct_keys method" do
obj = Object.new
obj.should_receive(:respond_to?).with(:deconstruct_keys)
- case obj
- in Object[a: 1]
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == false
+ case obj
+ in Object[a: 1]
+ true
+ else
+ false
+ end
+ RUBY
end
it "does not match object if #deconstruct_keys method does not return Hash" do
obj = Object.new
-
- def obj.deconstruct_keys(*)
- ""
- end
+ def obj.deconstruct_keys(*); "" end
-> {
- case obj
- in Object[a: 1]
- end
+ eval <<~RUBY
+ case obj
+ in Object[a: 1]
+ end
+ RUBY
}.should raise_error(TypeError, /deconstruct_keys must return Hash/)
end
it "does not match object if #deconstruct_keys method returns Hash with non-symbol keys" do
obj = Object.new
+ def obj.deconstruct_keys(*); {"a" => 1} end
- def obj.deconstruct_keys(*)
- {"a" => 1}
- end
-
- case obj
- in Object[a: 1]
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == false
+ case obj
+ in Object[a: 1]
+ true
+ else
+ false
+ end
+ RUBY
end
it "does not match object if elements of Hash returned by #deconstruct_keys method does not match values in pattern" do
obj = Object.new
+ def obj.deconstruct_keys(*); {a: 1} end
- def obj.deconstruct_keys(*)
- {a: 1}
- end
-
- case obj
- in Object[a: 2]
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == false
+ case obj
+ in Object[a: 2]
+ true
+ else
+ false
+ end
+ RUBY
end
it "passes keys specified in pattern as arguments to #deconstruct_keys method" do
@@ -1018,9 +1123,11 @@ describe "Pattern matching" do
{a: 1, b: 2, c: 3}
end
- case obj
- in Object[a: 1, b: 2, c: 3]
- end
+ eval <<~RUBY
+ case obj
+ in Object[a: 1, b: 2, c: 3]
+ end
+ RUBY
ScratchPad.recorded.sort.should == [[[:a, :b, :c]]]
end
@@ -1033,9 +1140,11 @@ describe "Pattern matching" do
{a: 1, b: 2, c: 3}
end
- case obj
- in Object[a: 1, b: 2, **]
- end
+ eval <<~RUBY
+ case obj
+ in Object[a: 1, b: 2, **]
+ end
+ RUBY
ScratchPad.recorded.sort.should == [[[:a, :b]]]
end
@@ -1048,105 +1157,100 @@ describe "Pattern matching" do
{a: 1, b: 2}
end
- case obj
- in Object[a: 1, **rest]
- end
+ eval <<~RUBY
+ case obj
+ in Object[a: 1, **rest]
+ end
+ RUBY
ScratchPad.recorded.should == [[nil]]
end
it "binds variables" do
- case {a: 0, b: 1, c: 2}
- in {a: x, b: y, c: z}
- [x, y, z]
- end.should == [0, 1, 2]
+ eval(<<~RUBY).should == [0, 1, 2]
+ case {a: 0, b: 1, c: 2}
+ in {a: x, b: y, c: z}
+ [x, y, z]
+ end
+ RUBY
end
it "supports double splat operator **rest" do
- case {a: 0, b: 1, c: 2}
- in {a: 0, **rest}
- rest
- end.should == {b: 1, c: 2}
+ eval(<<~RUBY).should == {b: 1, c: 2}
+ case {a: 0, b: 1, c: 2}
+ in {a: 0, **rest}
+ rest
+ end
+ RUBY
end
it "treats **nil like there should not be any other keys in a matched Hash" do
- case {a: 1, b: 2}
- in {a: 1, b: 2, **nil}
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case {a: 1, b: 2}
+ in {a: 1, b: 2, **nil}
+ true
+ end
+ RUBY
- case {a: 1, b: 2}
- in {a: 1, **nil}
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == false
+ case {a: 1, b: 2}
+ in {a: 1, **nil}
+ true
+ else
+ false
+ end
+ RUBY
end
it "can match partially" do
- case {a: 1, b: 2}
- in {a: 1}
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case {a: 1, b: 2}
+ in {a: 1}
+ true
+ end
+ RUBY
end
it "matches {} with {}" do
- case {}
- in {}
- true
- end.should == true
- end
-
- it "in {} only matches empty hashes" do
- case {a: 1}
- in {}
- true
- else
- false
- end.should == false
- end
-
- it "in {**nil} only matches empty hashes" do
- case {}
- in {**nil}
- true
- else
- false
- end.should == true
-
- case {a: 1}
- in {**nil}
- true
- else
- false
- end.should == false
+ eval(<<~RUBY).should == true
+ case {}
+ in {}
+ true
+ end
+ RUBY
end
it "matches anything with **" do
- case {a: 1}
- in **;
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case {a: 1}
+ in **;
+ true
+ end
+ RUBY
end
it "can be used as a nested pattern" do
- case {a: {a: 1, b: 1}, b: {a: 1, b: 2}}
- in {a: {a: 0}}
- false
- in {a: {a: 1}, b: {b: 1}}
- false
- in {a: {a: 1}, b: {b: 2} }
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case {a: {a: 1, b: 1}, b: {a: 1, b: 2}}
+ in {a: {a: 0}}
+ false
+ in {a: {a: 1}, b: {b: 1}}
+ false
+ in {a: {a: 1}, b: {b: 2}}
+ true
+ end
+ RUBY
- case [{a: 1, b: [1]}, {a: 1, c: ["2"]}]
- in [{a:, c:}, ]
- false
- in [{a: 1, b:}, {a: 1, c: [Integer]}]
- false
- in [_, {a: 1, c: [String]}]
- true
- end.should == true
+ eval(<<~RUBY).should == true
+ case [{a: 1, b: [1]}, {a: 1, c: ["2"]}]
+ in [{a:, c:},]
+ false
+ in [{a: 1, b:}, {a: 1, c: [Integer]}]
+ false
+ in [_, {a: 1, c: [String]}]
+ true
+ end
+ RUBY
end
end
@@ -1164,11 +1268,12 @@ describe "Pattern matching" do
Module.new do
using refinery
- result =
+ result = eval(<<~RUBY)
case []
in [0]
true
end
+ RUBY
end
result.should == true
@@ -1187,11 +1292,12 @@ describe "Pattern matching" do
Module.new do
using refinery
- result =
+ result = eval(<<~RUBY)
case {}
in a: 0
true
end
+ RUBY
end
result.should == true
@@ -1210,18 +1316,88 @@ describe "Pattern matching" do
Module.new do
using refinery
- result =
+ result = eval(<<~RUBY)
case {}
in Array
true
end
+ RUBY
end
result.should == true
end
end
-end
-ruby_version_is "3.1" do
- require_relative 'pattern_matching/3.1'
+ ruby_version_is "3.1" do
+ it "can omit parentheses in one line pattern matching" do
+ eval(<<~RUBY).should == [1, 2]
+ [1, 2] => a, b
+ [a, b]
+ RUBY
+
+ eval(<<~RUBY).should == 1
+ {a: 1} => a:
+ a
+ RUBY
+ end
+
+ it "supports pinning instance variables" do
+ eval(<<~RUBY).should == true
+ @a = /a/
+ case 'abc'
+ in ^@a
+ true
+ end
+ RUBY
+ end
+
+ it "supports pinning class variables" do
+ result = nil
+ Module.new do
+ result = module_eval(<<~RUBY)
+ @@a = 0..10
+
+ case 2
+ in ^@@a
+ true
+ end
+ RUBY
+ end
+
+ result.should == true
+ end
+
+ it "supports pinning global variables" do
+ eval(<<~RUBY).should == true
+ $a = /a/
+ case 'abc'
+ in ^$a
+ true
+ end
+ RUBY
+ end
+
+ it "supports pinning expressions" do
+ eval(<<~RUBY).should == true
+ case 'abc'
+ in ^(/a/)
+ true
+ end
+ RUBY
+
+ eval(<<~RUBY).should == true
+ case {name: '2.6', released_at: Time.new(2018, 12, 25)}
+ in {released_at: ^(Time.new(2010)..Time.new(2020))}
+ true
+ end
+ RUBY
+
+ eval(<<~RUBY).should == true
+ case 0
+ in ^(0+0)
+ true
+ end
+ RUBY
+ end
+ end
end
diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb
index ac28f1e8a0..d1cda25918 100644
--- a/spec/ruby/language/predefined_spec.rb
+++ b/spec/ruby/language/predefined_spec.rb
@@ -133,7 +133,7 @@ describe "Predefined global $&" do
end
it "sets the encoding to the encoding of the source String" do
- "abc".dup.force_encoding(Encoding::EUC_JP) =~ /b/
+ "abc".force_encoding(Encoding::EUC_JP) =~ /b/
$&.encoding.should equal(Encoding::EUC_JP)
end
end
@@ -146,12 +146,12 @@ describe "Predefined global $`" do
end
it "sets the encoding to the encoding of the source String" do
- "abc".dup.force_encoding(Encoding::EUC_JP) =~ /b/
+ "abc".force_encoding(Encoding::EUC_JP) =~ /b/
$`.encoding.should equal(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
- "abc".dup.force_encoding(Encoding::ISO_8859_1) =~ /a/
+ "abc".force_encoding(Encoding::ISO_8859_1) =~ /a/
$`.encoding.should equal(Encoding::ISO_8859_1)
end
end
@@ -164,12 +164,12 @@ describe "Predefined global $'" do
end
it "sets the encoding to the encoding of the source String" do
- "abc".dup.force_encoding(Encoding::EUC_JP) =~ /b/
+ "abc".force_encoding(Encoding::EUC_JP) =~ /b/
$'.encoding.should equal(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
- "abc".dup.force_encoding(Encoding::ISO_8859_1) =~ /c/
+ "abc".force_encoding(Encoding::ISO_8859_1) =~ /c/
$'.encoding.should equal(Encoding::ISO_8859_1)
end
end
@@ -187,7 +187,7 @@ describe "Predefined global $+" do
end
it "sets the encoding to the encoding of the source String" do
- "abc".dup.force_encoding(Encoding::EUC_JP) =~ /(b)/
+ "abc".force_encoding(Encoding::EUC_JP) =~ /(b)/
$+.encoding.should equal(Encoding::EUC_JP)
end
end
@@ -214,7 +214,7 @@ describe "Predefined globals $1..N" do
end
it "sets the encoding to the encoding of the source String" do
- "abc".dup.force_encoding(Encoding::EUC_JP) =~ /(b)/
+ "abc".force_encoding(Encoding::EUC_JP) =~ /(b)/
$1.encoding.should equal(Encoding::EUC_JP)
end
end
@@ -687,7 +687,7 @@ describe "Predefined global $," do
end
it "warns if assigned non-nil" do
- -> { $, = "_" }.should complain(/warning: [`']\$,' is deprecated/)
+ -> { $, = "_" }.should complain(/warning: `\$,' is deprecated/)
end
end
@@ -724,7 +724,7 @@ describe "Predefined global $;" do
end
it "warns if assigned non-nil" do
- -> { $; = "_" }.should complain(/warning: [`']\$;' is deprecated/)
+ -> { $; = "_" }.should complain(/warning: `\$;' is deprecated/)
end
end
@@ -979,10 +979,6 @@ describe "Global variable $VERBOSE" do
$VERBOSE = @verbose
end
- it "is false by default" do
- $VERBOSE.should be_false
- end
-
it "converts truthy values to true" do
[true, 1, 0, [], ""].each do |true_value|
$VERBOSE = true_value
@@ -1037,7 +1033,7 @@ describe "Global variable $0" do
it "is the path given as the main script and the same as __FILE__" do
script = "fixtures/dollar_zero.rb"
- Dir.chdir(__dir__) do
+ Dir.chdir(File.dirname(__FILE__)) do
ruby_exe(script).should == "#{script}\n#{script}\nOK"
end
end
@@ -1161,20 +1157,47 @@ end
describe "The predefined global constants" do
describe "TRUE" do
- it "is no longer defined" do
- Object.const_defined?(:TRUE).should == false
+ ruby_version_is "3.0" do
+ it "is no longer defined" do
+ Object.const_defined?(:TRUE).should == false
+ end
+ end
+
+ ruby_version_is ""..."3.0" do
+ it "includes TRUE" do
+ Object.const_defined?(:TRUE).should == true
+ -> { TRUE }.should complain(/constant ::TRUE is deprecated/)
+ end
end
end
describe "FALSE" do
- it "is no longer defined" do
- Object.const_defined?(:FALSE).should == false
+ ruby_version_is "3.0" do
+ it "is no longer defined" do
+ Object.const_defined?(:FALSE).should == false
+ end
+ end
+
+ ruby_version_is ""..."3.0" do
+ it "includes FALSE" do
+ Object.const_defined?(:FALSE).should == true
+ -> { FALSE }.should complain(/constant ::FALSE is deprecated/)
+ end
end
end
describe "NIL" do
- it "is no longer defined" do
- Object.const_defined?(:NIL).should == false
+ ruby_version_is "3.0" do
+ it "is no longer defined" do
+ Object.const_defined?(:NIL).should == false
+ end
+ end
+
+ ruby_version_is ""..."3.0" do
+ it "includes NIL" do
+ Object.const_defined?(:NIL).should == true
+ -> { NIL }.should complain(/constant ::NIL is deprecated/)
+ end
end
end
diff --git a/spec/ruby/language/proc_spec.rb b/spec/ruby/language/proc_spec.rb
index cc69b7799c..f8a29962b0 100644
--- a/spec/ruby/language/proc_spec.rb
+++ b/spec/ruby/language/proc_spec.rb
@@ -161,18 +161,6 @@ describe "A Proc" do
end
end
- describe "taking |*a, b| arguments" do
- it "assigns [] to the argument when passed no values" do
- proc { |*a, b| [a, b] }.call.should == [[], nil]
- end
- end
-
- describe "taking |a, *b, c| arguments" do
- it "assigns [] to the argument when passed no values" do
- proc { |a, *b, c| [a, b, c] }.call.should == [nil, [], nil]
- end
- end
-
describe "taking |a, | arguments" do
before :each do
@l = lambda { |a, | a }
@@ -235,8 +223,18 @@ describe "A Proc" do
@p = proc { |*a, **kw| [a, kw] }
end
- it 'does not autosplat keyword arguments' do
- @p.call([1, {a: 1}]).should == [[[1, {a: 1}]], {}]
+ ruby_version_is ""..."3.0" do
+ it 'autosplats keyword arguments and warns' do
+ -> {
+ @p.call([1, {a: 1}]).should == [[1], {a: 1}]
+ }.should complain(/warning: Using the last argument as keyword parameters is deprecated; maybe \*\* should be added to the call/)
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it 'does not autosplat keyword arguments' do
+ @p.call([1, {a: 1}]).should == [[[1, {a: 1}]], {}]
+ end
end
end
diff --git a/spec/ruby/language/regexp/back-references_spec.rb b/spec/ruby/language/regexp/back-references_spec.rb
index 627c8daace..26750c20c5 100644
--- a/spec/ruby/language/regexp/back-references_spec.rb
+++ b/spec/ruby/language/regexp/back-references_spec.rb
@@ -22,15 +22,6 @@ describe "Regexps with back-references" do
$10.should == "0"
end
- it "returns nil for numbered variable with too large index" do
- -> {
- eval(<<~CODE).should == nil
- "a" =~ /(.)/
- eval('$4294967296')
- CODE
- }.should complain(/warning: ('|`)\$4294967296' is too big for a number variable, always nil/)
- end
-
it "will not clobber capture variables across threads" do
cap1, cap2, cap3 = nil
"foo" =~ /(o+)/
diff --git a/spec/ruby/language/regexp/character_classes_spec.rb b/spec/ruby/language/regexp/character_classes_spec.rb
index 98d431a817..12a51178b2 100644
--- a/spec/ruby/language/regexp/character_classes_spec.rb
+++ b/spec/ruby/language/regexp/character_classes_spec.rb
@@ -610,12 +610,14 @@ describe "Regexp with character classes" do
end
it "supports negated property condition" do
- "a".match(eval("/\P{L}/")).should be_nil
- "1".match(eval("/\P{N}/")).should be_nil
+ "a".match(/\P{L}/).should be_nil
+ "1".match(/\P{N}/).should be_nil
end
- it "raises a RegexpError for an unterminated unicode property" do
- -> { Regexp.new('\p{') }.should raise_error(RegexpError)
+ ruby_bug "#17340", ''...'3.0' do
+ it "raises a RegexpError for an unterminated unicode property" do
+ -> { Regexp.new('\p{') }.should raise_error(RegexpError)
+ end
end
it "supports \\X (unicode 9.0 with UTR #51 workarounds)" do
diff --git a/spec/ruby/language/regexp/encoding_spec.rb b/spec/ruby/language/regexp/encoding_spec.rb
index 0571b2d3cf..febc3fdb37 100644
--- a/spec/ruby/language/regexp/encoding_spec.rb
+++ b/spec/ruby/language/regexp/encoding_spec.rb
@@ -4,18 +4,18 @@ require_relative '../fixtures/classes'
describe "Regexps with encoding modifiers" do
it "supports /e (EUC encoding)" do
- match = /./e.match("\303\251".dup.force_encoding(Encoding::EUC_JP))
- match.to_a.should == ["\303\251".dup.force_encoding(Encoding::EUC_JP)]
+ match = /./e.match("\303\251".force_encoding(Encoding::EUC_JP))
+ match.to_a.should == ["\303\251".force_encoding(Encoding::EUC_JP)]
end
it "supports /e (EUC encoding) with interpolation" do
- match = /#{/./}/e.match("\303\251".dup.force_encoding(Encoding::EUC_JP))
- match.to_a.should == ["\303\251".dup.force_encoding(Encoding::EUC_JP)]
+ match = /#{/./}/e.match("\303\251".force_encoding(Encoding::EUC_JP))
+ match.to_a.should == ["\303\251".force_encoding(Encoding::EUC_JP)]
end
it "supports /e (EUC encoding) with interpolation /o" do
- match = /#{/./}/e.match("\303\251".dup.force_encoding(Encoding::EUC_JP))
- match.to_a.should == ["\303\251".dup.force_encoding(Encoding::EUC_JP)]
+ match = /#{/./}/e.match("\303\251".force_encoding(Encoding::EUC_JP))
+ match.to_a.should == ["\303\251".force_encoding(Encoding::EUC_JP)]
end
it 'uses EUC-JP as /e encoding' do
@@ -39,7 +39,7 @@ describe "Regexps with encoding modifiers" do
end
it "warns when using /n with a match string with non-ASCII characters and an encoding other than ASCII-8BIT" do
- -> { /./n.match("\303\251".dup.force_encoding('utf-8')) }.should complain(%r{historical binary regexp match /.../n against UTF-8 string})
+ -> { /./n.match("\303\251".force_encoding('utf-8')) }.should complain(%r{historical binary regexp match /.../n against UTF-8 string})
end
it 'uses US-ASCII as /n encoding if all chars are 7-bit' do
@@ -63,18 +63,18 @@ describe "Regexps with encoding modifiers" do
end
it "supports /s (Windows_31J encoding)" do
- match = /./s.match("\303\251".dup.force_encoding(Encoding::Windows_31J))
- match.to_a.should == ["\303".dup.force_encoding(Encoding::Windows_31J)]
+ match = /./s.match("\303\251".force_encoding(Encoding::Windows_31J))
+ match.to_a.should == ["\303".force_encoding(Encoding::Windows_31J)]
end
it "supports /s (Windows_31J encoding) with interpolation" do
- match = /#{/./}/s.match("\303\251".dup.force_encoding(Encoding::Windows_31J))
- match.to_a.should == ["\303".dup.force_encoding(Encoding::Windows_31J)]
+ match = /#{/./}/s.match("\303\251".force_encoding(Encoding::Windows_31J))
+ match.to_a.should == ["\303".force_encoding(Encoding::Windows_31J)]
end
it "supports /s (Windows_31J encoding) with interpolation and /o" do
- match = /#{/./}/s.match("\303\251".dup.force_encoding(Encoding::Windows_31J))
- match.to_a.should == ["\303".dup.force_encoding(Encoding::Windows_31J)]
+ match = /#{/./}/s.match("\303\251".force_encoding(Encoding::Windows_31J))
+ match.to_a.should == ["\303".force_encoding(Encoding::Windows_31J)]
end
it 'uses Windows-31J as /s encoding' do
@@ -86,15 +86,15 @@ describe "Regexps with encoding modifiers" do
end
it "supports /u (UTF8 encoding)" do
- /./u.match("\303\251".dup.force_encoding('utf-8')).to_a.should == ["\u{e9}"]
+ /./u.match("\303\251".force_encoding('utf-8')).to_a.should == ["\u{e9}"]
end
it "supports /u (UTF8 encoding) with interpolation" do
- /#{/./}/u.match("\303\251".dup.force_encoding('utf-8')).to_a.should == ["\u{e9}"]
+ /#{/./}/u.match("\303\251".force_encoding('utf-8')).to_a.should == ["\u{e9}"]
end
it "supports /u (UTF8 encoding) with interpolation and /o" do
- /#{/./}/u.match("\303\251".dup.force_encoding('utf-8')).to_a.should == ["\u{e9}"]
+ /#{/./}/u.match("\303\251".force_encoding('utf-8')).to_a.should == ["\u{e9}"]
end
it 'uses UTF-8 as /u encoding' do
@@ -122,26 +122,26 @@ describe "Regexps with encoding modifiers" do
end
it "raises Encoding::CompatibilityError when the regexp has a fixed, non-ASCII-compatible encoding" do
- -> { Regexp.new("".dup.force_encoding("UTF-16LE"), Regexp::FIXEDENCODING) =~ " ".encode("UTF-8") }.should raise_error(Encoding::CompatibilityError)
+ -> { Regexp.new("".force_encoding("UTF-16LE"), Regexp::FIXEDENCODING) =~ " ".encode("UTF-8") }.should raise_error(Encoding::CompatibilityError)
end
it "raises Encoding::CompatibilityError when the regexp has a fixed encoding and the match string has non-ASCII characters" do
- -> { Regexp.new("".dup.force_encoding("US-ASCII"), Regexp::FIXEDENCODING) =~ "\303\251".dup.force_encoding('UTF-8') }.should raise_error(Encoding::CompatibilityError)
+ -> { Regexp.new("".force_encoding("US-ASCII"), Regexp::FIXEDENCODING) =~ "\303\251".force_encoding('UTF-8') }.should raise_error(Encoding::CompatibilityError)
end
it "raises ArgumentError when trying to match a broken String" do
- s = "\x80".dup.force_encoding('UTF-8')
+ s = "\x80".force_encoding('UTF-8')
-> { s =~ /./ }.should raise_error(ArgumentError, "invalid byte sequence in UTF-8")
end
it "computes the Regexp Encoding for each interpolated Regexp instance" do
make_regexp = -> str { /#{str}/ }
- r = make_regexp.call("été".dup.force_encoding(Encoding::UTF_8))
+ r = make_regexp.call("été".force_encoding(Encoding::UTF_8))
r.should.fixed_encoding?
r.encoding.should == Encoding::UTF_8
- r = make_regexp.call("abc".dup.force_encoding(Encoding::UTF_8))
+ r = make_regexp.call("abc".force_encoding(Encoding::UTF_8))
r.should_not.fixed_encoding?
r.encoding.should == Encoding::US_ASCII
end
diff --git a/spec/ruby/language/regexp/repetition_spec.rb b/spec/ruby/language/regexp/repetition_spec.rb
index d76619688f..9a191d74e2 100644
--- a/spec/ruby/language/regexp/repetition_spec.rb
+++ b/spec/ruby/language/regexp/repetition_spec.rb
@@ -87,7 +87,9 @@ describe "Regexps with repetition" do
/a+?*/.match("a")[0].should == "a"
/(a+?)*/.match("a")[0].should == "a"
- /a+?*/.match("aa")[0].should == "aa"
+ ruby_bug '#17341', ''...'3.0' do
+ /a+?*/.match("aa")[0].should == "aa"
+ end
/(a+?)*/.match("aa")[0].should == "aa"
# a+?+ should not be reduced, it should be equivalent to (a+?)+
@@ -98,7 +100,9 @@ describe "Regexps with repetition" do
/a+?+/.match("a")[0].should == "a"
/(a+?)+/.match("a")[0].should == "a"
- /a+?+/.match("aa")[0].should == "aa"
+ ruby_bug '#17341', ''...'3.0' do
+ /a+?+/.match("aa")[0].should == "aa"
+ end
/(a+?)+/.match("aa")[0].should == "aa"
# both a**? and a+*? should be equivalent to (a+)??
diff --git a/spec/ruby/language/regexp_spec.rb b/spec/ruby/language/regexp_spec.rb
index 89d0914807..d49689349d 100644
--- a/spec/ruby/language/regexp_spec.rb
+++ b/spec/ruby/language/regexp_spec.rb
@@ -18,8 +18,10 @@ describe "Literal Regexps" do
/Hello/.should be_kind_of(Regexp)
end
- it "is frozen" do
- /Hello/.should.frozen?
+ ruby_version_is "3.0" do
+ it "is frozen" do
+ /Hello/.should.frozen?
+ end
end
it "caches the Regexp object" do
@@ -112,7 +114,7 @@ describe "Literal Regexps" do
/foo.(?<=\d)/.match("fooA foo1").to_a.should == ["foo1"]
end
- ruby_bug "#13671", ""..."3.5" do # https://bugs.ruby-lang.org/issues/13671
+ ruby_bug "#13671", ""..."3.3" do # https://bugs.ruby-lang.org/issues/13671
it "handles a lookbehind with ss characters" do
r = Regexp.new("(?<!dss)", Regexp::IGNORECASE)
r.should =~ "✨"
diff --git a/spec/ruby/language/rescue_spec.rb b/spec/ruby/language/rescue_spec.rb
index 4dc25a5b45..b91b52fa0f 100644
--- a/spec/ruby/language/rescue_spec.rb
+++ b/spec/ruby/language/rescue_spec.rb
@@ -52,16 +52,6 @@ describe "The rescue keyword" do
RescueSpecs::SafeNavigationSetterCaptor.should_capture_exception
end
- it 'using a safely navigated setter method on a nil target' do
- target = nil
- begin
- raise SpecificExampleException, "Raising this to be handled below"
- rescue SpecificExampleException => target&.captured_error
- :caught
- end.should == :caught
- target.should be_nil
- end
-
it 'using a setter method' do
RescueSpecs::SetterCaptor.should_capture_exception
end
@@ -71,78 +61,6 @@ describe "The rescue keyword" do
end
end
- describe 'capturing in a local variable (that defines it)' do
- it 'captures successfully in a method' do
- ScratchPad.record []
-
- def a
- raise "message"
- rescue => e
- ScratchPad << e.message
- end
-
- a
- ScratchPad.recorded.should == ["message"]
- end
-
- it 'captures successfully in a block' do
- ScratchPad.record []
-
- p = proc do
- raise "message"
- rescue => e
- ScratchPad << e.message
- end
-
- p.call
- ScratchPad.recorded.should == ["message"]
- end
-
- it 'captures successfully in a class' do
- ScratchPad.record []
-
- class RescueSpecs::C
- raise "message"
- rescue => e
- ScratchPad << e.message
- end
-
- ScratchPad.recorded.should == ["message"]
- end
-
- it 'captures successfully in a module' do
- ScratchPad.record []
-
- module RescueSpecs::M
- raise "message"
- rescue => e
- ScratchPad << e.message
- end
-
- ScratchPad.recorded.should == ["message"]
- end
-
- it 'captures sucpcessfully in a singleton class' do
- ScratchPad.record []
-
- class << Object.new
- raise "message"
- rescue => e
- ScratchPad << e.message
- end
-
- ScratchPad.recorded.should == ["message"]
- end
-
- it 'captures successfully at the top-level' do
- ScratchPad.record []
-
- require_relative 'fixtures/rescue/top_level'
-
- ScratchPad.recorded.should == ["message"]
- end
- end
-
it "returns value from `rescue` if an exception was raised" do
begin
raise
@@ -273,7 +191,7 @@ describe "The rescue keyword" do
rescue ArgumentError
end
rescue StandardError => e
- e.backtrace.first.should =~ /:in [`'](?:RescueSpecs\.)?raise_standard_error'/
+ e.backtrace.first.should include ":in `raise_standard_error'"
else
fail("exception wasn't handled by the correct rescue block")
end
@@ -563,23 +481,6 @@ describe "The rescue keyword" do
eval('1.+((1 rescue 1))').should == 2
end
- ruby_version_is "3.4" do
- it "does not introduce extra backtrace entries" do
- def foo
- begin
- raise "oops"
- rescue
- return caller(0, 2)
- end
- end
- line = __LINE__
- foo.should == [
- "#{__FILE__}:#{line-3}:in 'foo'",
- "#{__FILE__}:#{line+1}:in 'block (3 levels) in <top (required)>'"
- ]
- end
- end
-
describe "inline form" do
it "can be inlined" do
a = 1/0 rescue 1
diff --git a/spec/ruby/language/retry_spec.rb b/spec/ruby/language/retry_spec.rb
index 669d5f0ff5..ee5377946f 100644
--- a/spec/ruby/language/retry_spec.rb
+++ b/spec/ruby/language/retry_spec.rb
@@ -31,11 +31,8 @@ describe "The retry statement" do
results.should == [1, 2, 3, 1, 2, 4, 5, 6, 4, 5]
end
- it "raises a SyntaxError when used outside of a rescue statement" do
+ it "raises a SyntaxError when used outside of a begin statement" do
-> { eval 'retry' }.should raise_error(SyntaxError)
- -> { eval 'begin; retry; end' }.should raise_error(SyntaxError)
- -> { eval 'def m; retry; end' }.should raise_error(SyntaxError)
- -> { eval 'module RetrySpecs; retry; end' }.should raise_error(SyntaxError)
end
end
diff --git a/spec/ruby/language/safe_navigator_spec.rb b/spec/ruby/language/safe_navigator_spec.rb
index b1e28c3963..c3aecff2dd 100644
--- a/spec/ruby/language/safe_navigator_spec.rb
+++ b/spec/ruby/language/safe_navigator_spec.rb
@@ -7,43 +7,43 @@ describe "Safe navigator" do
context "when context is nil" do
it "always returns nil" do
- nil&.unknown.should == nil
- [][10]&.unknown.should == nil
+ eval("nil&.unknown").should == nil
+ eval("[][10]&.unknown").should == nil
end
it "can be chained" do
- nil&.one&.two&.three.should == nil
+ eval("nil&.one&.two&.three").should == nil
end
it "doesn't evaluate arguments" do
obj = Object.new
obj.should_not_receive(:m)
- nil&.unknown(obj.m) { obj.m }
+ eval("nil&.unknown(obj.m) { obj.m }")
end
end
context "when context is false" do
it "calls the method" do
- false&.to_s.should == "false"
+ eval("false&.to_s").should == "false"
- -> { false&.unknown }.should raise_error(NoMethodError)
+ -> { eval("false&.unknown") }.should raise_error(NoMethodError)
end
end
context "when context is truthy" do
it "calls the method" do
- 1&.to_s.should == "1"
+ eval("1&.to_s").should == "1"
- -> { 1&.unknown }.should raise_error(NoMethodError)
+ -> { eval("1&.unknown") }.should raise_error(NoMethodError)
end
end
it "takes a list of arguments" do
- [1,2,3]&.first(2).should == [1,2]
+ eval("[1,2,3]&.first(2)").should == [1,2]
end
it "takes a block" do
- [1,2]&.map { |i| i * 2 }.should == [2, 4]
+ eval("[1,2]&.map { |i| i * 2 }").should == [2, 4]
end
it "allows assignment methods" do
@@ -56,77 +56,29 @@ describe "Safe navigator" do
end
obj = klass.new
- (obj&.foo = 3).should == 3
+ eval("obj&.foo = 3").should == 3
obj.foo.should == 3
obj = nil
- (obj&.foo = 3).should == nil
+ eval("obj&.foo = 3").should == nil
end
it "allows assignment operators" do
klass = Class.new do
- attr_reader :m
+ attr_accessor :m
def initialize
@m = 0
end
-
- def m=(v)
- @m = v
- 42
- end
end
obj = klass.new
- obj&.m += 3
+ eval("obj&.m += 3")
obj.m.should == 3
obj = nil
- (obj&.m += 3).should == nil
- end
-
- it "allows ||= operator" do
- klass = Class.new do
- attr_reader :m
-
- def initialize
- @m = false
- end
-
- def m=(v)
- @m = v
- 42
- end
- end
-
- obj = klass.new
-
- (obj&.m ||= true).should == true
- obj.m.should == true
-
- obj = nil
- (obj&.m ||= true).should == nil
- obj.should == nil
- end
-
- it "allows &&= operator" do
- klass = Class.new do
- attr_accessor :m
-
- def initialize
- @m = true
- end
- end
-
- obj = klass.new
-
- (obj&.m &&= false).should == false
- obj.m.should == false
-
- obj = nil
- (obj&.m &&= false).should == nil
- obj.should == nil
+ eval("obj&.m += 3").should == nil
end
it "does not call the operator method lazily with an assignment operator" do
@@ -139,7 +91,7 @@ describe "Safe navigator" do
obj = klass.new
-> {
- obj&.foo += 3
+ eval("obj&.foo += 3")
}.should raise_error(NoMethodError) { |e|
e.name.should == :+
}
diff --git a/spec/ruby/language/safe_spec.rb b/spec/ruby/language/safe_spec.rb
index 03ae96148e..ee5c1b3ccc 100644
--- a/spec/ruby/language/safe_spec.rb
+++ b/spec/ruby/language/safe_spec.rb
@@ -1,11 +1,27 @@
require_relative '../spec_helper'
describe "The $SAFE variable" do
- it "$SAFE is a regular global variable" do
- $SAFE.should == nil
- $SAFE = 42
- $SAFE.should == 42
- ensure
- $SAFE = nil
+ ruby_version_is ""..."3.0" do
+ it "warn when access" do
+ -> {
+ $SAFE
+ }.should complain(/\$SAFE will become a normal global variable in Ruby 3.0/)
+ end
+
+ it "warn when set" do
+ -> {
+ $SAFE = 1
+ }.should complain(/\$SAFE will become a normal global variable in Ruby 3.0/)
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "$SAFE is a regular global variable" do
+ $SAFE.should == nil
+ $SAFE = 42
+ $SAFE.should == 42
+ ensure
+ $SAFE = nil
+ end
end
end
diff --git a/spec/ruby/language/send_spec.rb b/spec/ruby/language/send_spec.rb
index aaccdf0998..5999079d58 100644
--- a/spec/ruby/language/send_spec.rb
+++ b/spec/ruby/language/send_spec.rb
@@ -43,7 +43,7 @@ describe "Invoking a method" do
end
describe "with optional arguments" do
- it "uses the optional argument if none is passed" do
+ it "uses the optional argument if none is is passed" do
specs.fooM0O1.should == [1]
end
@@ -411,18 +411,36 @@ describe "Invoking a method" do
specs.rest_len(0,*a,4,*5,6,7,*c,-1).should == 11
end
- it "expands the Array elements from the splat before applying block argument operations" do
- def self.m(*args, &block)
- [args, block]
+ ruby_version_is ""..."3.0" do
+ it "expands the Array elements from the splat after executing the arguments and block if no other arguments follow the splat" do
+ def self.m(*args, &block)
+ [args, block]
+ end
+
+ args = [1, nil]
+ m(*args, &args.pop).should == [[1], nil]
+
+ args = [1, nil]
+ order = []
+ m(*(order << :args; args), &(order << :block; args.pop)).should == [[1], nil]
+ order.should == [:args, :block]
end
+ end
- args = [1, nil]
- m(*args, &args.pop).should == [[1, nil], nil]
+ ruby_version_is "3.0" do
+ it "expands the Array elements from the splat before applying block argument operations" do
+ def self.m(*args, &block)
+ [args, block]
+ end
- args = [1, nil]
- order = []
- m(*(order << :args; args), &(order << :block; args.pop)).should == [[1, nil], nil]
- order.should == [:args, :block]
+ args = [1, nil]
+ m(*args, &args.pop).should == [[1, nil], nil]
+
+ args = [1, nil]
+ order = []
+ m(*(order << :args; args), &(order << :block; args.pop)).should == [[1, nil], nil]
+ order.should == [:args, :block]
+ end
end
it "evaluates the splatted arguments before the block if there are other arguments after the splat" do
diff --git a/spec/ruby/language/singleton_class_spec.rb b/spec/ruby/language/singleton_class_spec.rb
index 45e1f7f3ad..c1fb682ea0 100644
--- a/spec/ruby/language/singleton_class_spec.rb
+++ b/spec/ruby/language/singleton_class_spec.rb
@@ -70,7 +70,7 @@ describe "A singleton class" do
end
it "has class String as the superclass of a String instance" do
- "blah".dup.singleton_class.superclass.should == String
+ "blah".singleton_class.superclass.should == String
end
it "doesn't have singleton class" do
@@ -291,27 +291,3 @@ describe "Instantiating a singleton class" do
}.should raise_error(TypeError)
end
end
-
-describe "Frozen properties" do
- it "is frozen if the object it is created from is frozen" do
- o = Object.new
- o.freeze
- klass = o.singleton_class
- klass.frozen?.should == true
- end
-
- it "will be frozen if the object it is created from becomes frozen" do
- o = Object.new
- klass = o.singleton_class
- klass.frozen?.should == false
- o.freeze
- klass.frozen?.should == true
- end
-
- it "will be unfrozen if the frozen object is cloned with freeze set to false" do
- o = Object.new
- o.freeze
- o2 = o.clone(freeze: false)
- o2.singleton_class.frozen?.should == false
- end
-end
diff --git a/spec/ruby/language/source_encoding_spec.rb b/spec/ruby/language/source_encoding_spec.rb
index 7135bc0a70..19364fc676 100644
--- a/spec/ruby/language/source_encoding_spec.rb
+++ b/spec/ruby/language/source_encoding_spec.rb
@@ -15,7 +15,7 @@ describe "Source files" do
end
describe "encoded in UTF-16 LE without a BOM" do
- it "are parsed as empty because they contain a NUL byte before the encoding comment" do
+ it "are parsed because empty as they contain a NUL byte before the encoding comment" do
ruby_exe(fixture(__FILE__, "utf16-le-nobom.rb"), args: "2>&1").should == ""
end
end
diff --git a/spec/ruby/language/string_spec.rb b/spec/ruby/language/string_spec.rb
index 083a7f5db5..02e3488a1f 100644
--- a/spec/ruby/language/string_spec.rb
+++ b/spec/ruby/language/string_spec.rb
@@ -231,16 +231,8 @@ describe "Ruby String literals" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files.rb")).chomp.should == "true"
end
- guard -> { !(eval("'test'").frozen? && "test".equal?("test")) } do
- it "produces different objects for literals with the same content in different files if the other file doesn't have the comment and String literals aren't frozen by default" do
- ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_no_comment.rb")).chomp.should == "true"
- end
- end
-
- guard -> { eval("'test'").frozen? && "test".equal?("test") } do
- it "produces the same objects for literals with the same content in different files if the other file doesn't have the comment and String literals are frozen by default" do
- ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_no_comment.rb")).chomp.should == "false"
- end
+ it "produce different objects for literals with the same content in different files if the other file doesn't have the comment" do
+ ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_no_comment.rb")).chomp.should == "true"
end
it "produce different objects for literals with the same content in different files if they have different encodings" do
@@ -259,12 +251,12 @@ describe "Ruby String interpolation" do
it "returns a string with the source encoding by default" do
"a#{"b"}c".encoding.should == Encoding::BINARY
- eval('"a#{"b"}c"'.dup.force_encoding("us-ascii")).encoding.should == Encoding::US_ASCII
+ eval('"a#{"b"}c"'.force_encoding("us-ascii")).encoding.should == Encoding::US_ASCII
eval("# coding: US-ASCII \n 'a#{"b"}c'").encoding.should == Encoding::US_ASCII
end
it "returns a string with the source encoding, even if the components have another encoding" do
- a = "abc".dup.force_encoding("euc-jp")
+ a = "abc".force_encoding("euc-jp")
"#{a}".encoding.should == Encoding::BINARY
b = "abc".encode("utf-8")
@@ -273,7 +265,7 @@ describe "Ruby String interpolation" do
it "raises an Encoding::CompatibilityError if the Encodings are not compatible" do
a = "\u3042"
- b = "\xff".dup.force_encoding "binary"
+ b = "\xff".force_encoding "binary"
-> { "#{a} #{b}" }.should raise_error(Encoding::CompatibilityError)
end
@@ -285,11 +277,23 @@ describe "Ruby String interpolation" do
eval(code).should_not.frozen?
end
- it "creates a non-frozen String when # frozen-string-literal: true is used" do
- code = <<~'RUBY'
- # frozen-string-literal: true
- "a#{6*7}c"
- RUBY
- eval(code).should_not.frozen?
+ ruby_version_is "3.0" do
+ it "creates a non-frozen String when # frozen-string-literal: true is used" do
+ code = <<~'RUBY'
+ # frozen-string-literal: true
+ "a#{6*7}c"
+ RUBY
+ eval(code).should_not.frozen?
+ end
+ end
+
+ ruby_version_is ""..."3.0" do
+ it "creates a frozen String when # frozen-string-literal: true is used" do
+ code = <<~'RUBY'
+ # frozen-string-literal: true
+ "a#{6*7}c"
+ RUBY
+ eval(code).should.frozen?
+ end
end
end
diff --git a/spec/ruby/language/super_spec.rb b/spec/ruby/language/super_spec.rb
index a98b3b3091..1ac5c5e1be 100644
--- a/spec/ruby/language/super_spec.rb
+++ b/spec/ruby/language/super_spec.rb
@@ -203,25 +203,6 @@ describe "The super keyword" do
-> { klass.new.a(:a_called) }.should raise_error(RuntimeError)
end
- it "is able to navigate to super, when a method is defined dynamically on the singleton class" do
- foo_class = Class.new do
- def bar
- "bar"
- end
- end
-
- mixin_module = Module.new do
- def bar
- "super_" + super
- end
- end
-
- foo = foo_class.new
- foo.singleton_class.define_method(:bar, mixin_module.instance_method(:bar))
-
- foo.bar.should == "super_bar"
- end
-
# Rubinius ticket github#157
it "calls method_missing when a superclass method is not found" do
SuperSpecs::MM_B.new.is_a?(Hash).should == false
@@ -335,23 +316,12 @@ describe "The super keyword" do
it "without explicit arguments that are '_'" do
SuperSpecs::ZSuperWithUnderscores::B.new.m(1, 2).should == [1, 2]
- SuperSpecs::ZSuperWithUnderscores::B.new.m3(1, 2, 3).should == [1, 2, 3]
- SuperSpecs::ZSuperWithUnderscores::B.new.m4(1, 2, 3, 4).should == [1, 2, 3, 4]
- SuperSpecs::ZSuperWithUnderscores::B.new.m_default(1).should == [1]
- SuperSpecs::ZSuperWithUnderscores::B.new.m_default.should == [0]
- SuperSpecs::ZSuperWithUnderscores::B.new.m_pre_default_rest_post(1, 2, 3, 4, 5, 6, 7).should == [1, 2, 3, 4, 5, 6, 7]
- SuperSpecs::ZSuperWithUnderscores::B.new.m_rest(1, 2).should == [1, 2]
- SuperSpecs::ZSuperWithUnderscores::B.new.m_kwrest(a: 1).should == {a: 1}
end
it "without explicit arguments that are '_' including any modifications" do
SuperSpecs::ZSuperWithUnderscores::B.new.m_modified(1, 2).should == [14, 2]
end
- it "should pass method arguments when called within a closure" do
- SuperSpecs::ZSuperInBlock::B.new.m(arg: 1).should == 1
- end
-
describe 'when using keyword arguments' do
before :each do
@req = SuperSpecs::Keywords::RequiredArguments.new
diff --git a/spec/ruby/language/symbol_spec.rb b/spec/ruby/language/symbol_spec.rb
index 0801d3223e..d6a41d3059 100644
--- a/spec/ruby/language/symbol_spec.rb
+++ b/spec/ruby/language/symbol_spec.rb
@@ -96,13 +96,11 @@ describe "A Symbol literal" do
%I{a b #{"c"}}.should == [:a, :b, :c]
end
- ruby_bug "#20280", ""..."3.4" do
- it "raises an SyntaxError at parse time when Symbol with invalid bytes" do
- ScratchPad.record []
- -> {
- eval 'ScratchPad << 1; :"\xC3"'
- }.should raise_error(SyntaxError, /invalid symbol/)
- ScratchPad.recorded.should == []
- end
+ it "with invalid bytes raises an EncodingError at parse time" do
+ ScratchPad.record []
+ -> {
+ eval 'ScratchPad << 1; :"\xC3"'
+ }.should raise_error(EncodingError, /invalid/)
+ ScratchPad.recorded.should == []
end
end
diff --git a/spec/ruby/language/undef_spec.rb b/spec/ruby/language/undef_spec.rb
index 29dba4afb4..4e473b803f 100644
--- a/spec/ruby/language/undef_spec.rb
+++ b/spec/ruby/language/undef_spec.rb
@@ -38,19 +38,12 @@ describe "The undef keyword" do
-> { @obj.meth(5) }.should raise_error(NoMethodError)
end
- it "with an interpolated symbol" do
+ it "with a interpolated symbol" do
@undef_class.class_eval do
undef :"#{'meth'}"
end
-> { @obj.meth(5) }.should raise_error(NoMethodError)
end
-
- it "with an interpolated symbol when interpolated expression is not a String literal" do
- @undef_class.class_eval do
- undef :"#{'meth'.to_sym}"
- end
- -> { @obj.meth(5) }.should raise_error(NoMethodError)
- end
end
it "allows undefining multiple methods at a time" do
diff --git a/spec/ruby/language/variables_spec.rb b/spec/ruby/language/variables_spec.rb
index 01be61a9dc..c900c03d37 100644
--- a/spec/ruby/language/variables_spec.rb
+++ b/spec/ruby/language/variables_spec.rb
@@ -1,86 +1,6 @@
require_relative '../spec_helper'
require_relative 'fixtures/variables'
-describe "Evaluation order during assignment" do
- context "with single assignment" do
- it "evaluates from left to right" do
- obj = VariablesSpecs::EvalOrder.new
- obj.instance_eval do
- foo[0] = a
- end
-
- obj.order.should == ["foo", "a", "foo[]="]
- end
- end
-
- context "with multiple assignment" do
- ruby_version_is ""..."3.1" do
- it "does not evaluate from left to right" do
- obj = VariablesSpecs::EvalOrder.new
-
- obj.instance_eval do
- foo[0], bar.baz = a, b
- end
-
- obj.order.should == ["a", "b", "foo", "foo[]=", "bar", "bar.baz="]
- end
-
- it "cannot be used to swap variables with nested method calls" do
- node = VariablesSpecs::EvalOrder.new.node
-
- original_node = node
- original_node_left = node.left
- original_node_left_right = node.left.right
-
- node.left, node.left.right, node = node.left.right, node, node.left
- # Should evaluate in the order of:
- # RHS: node.left.right, node, node.left
- # LHS:
- # * node(original_node), original_node.left = original_node_left_right
- # * node(original_node), node.left(changed in the previous assignment to original_node_left_right),
- # original_node_left_right.right = original_node
- # * node = original_node_left
-
- node.should == original_node_left
- node.right.should_not == original_node
- node.right.left.should_not == original_node_left_right
- end
- end
-
- ruby_version_is "3.1" do
- it "evaluates from left to right, receivers first then methods" do
- obj = VariablesSpecs::EvalOrder.new
- obj.instance_eval do
- foo[0], bar.baz = a, b
- end
-
- obj.order.should == ["foo", "bar", "a", "b", "foo[]=", "bar.baz="]
- end
-
- it "can be used to swap variables with nested method calls" do
- node = VariablesSpecs::EvalOrder.new.node
-
- original_node = node
- original_node_left = node.left
- original_node_left_right = node.left.right
-
- node.left, node.left.right, node = node.left.right, node, node.left
- # Should evaluate in the order of:
- # LHS: node, node.left(original_node_left)
- # RHS: original_node_left_right, original_node, original_node_left
- # Ops:
- # * node(original_node), original_node.left = original_node_left_right
- # * original_node_left.right = original_node
- # * node = original_node_left
-
- node.should == original_node_left
- node.right.should == original_node
- node.right.left.should == original_node_left_right
- end
- end
- end
-end
-
describe "Multiple assignment" do
context "with a single RHS value" do
it "assigns a simple MLHS" do
@@ -367,13 +287,8 @@ describe "Multiple assignment" do
it "assigns indexed elements" do
a = []
- a[1], a[2] = 1, 2
- a.should == [nil, 1, 2]
-
- # with splatted argument
- a = []
- a[*[1]], a[*[2]] = 1, 2
- a.should == [nil, 1, 2]
+ a[1], a[2] = 1
+ a.should == [nil, 1, nil]
end
it "assigns constants" do
@@ -909,11 +824,22 @@ end
describe "Instance variables" do
context "when instance variable is uninitialized" do
- it "doesn't warn about accessing uninitialized instance variable" do
- obj = Object.new
- def obj.foobar; a = @a; end
+ ruby_version_is ""..."3.0" do
+ it "warns about accessing uninitialized instance variable" do
+ obj = Object.new
+ def obj.foobar; a = @a; end
- -> { obj.foobar }.should_not complain(verbose: true)
+ -> { obj.foobar }.should complain(/warning: instance variable @a not initialized/, verbose: true)
+ end
+ end
+
+ ruby_version_is "3.0" do
+ it "doesn't warn about accessing uninitialized instance variable" do
+ obj = Object.new
+ def obj.foobar; a = @a; end
+
+ -> { obj.foobar }.should_not complain(verbose: true)
+ end
end
it "doesn't warn at lazy initialization" do
@@ -930,7 +856,7 @@ describe "Instance variables" do
obj = Object.new
def obj.foobar; a = $specs_uninitialized_global_variable; end
- -> { obj.foobar }.should complain(/warning: global variable [`']\$specs_uninitialized_global_variable' not initialized/, verbose: true)
+ -> { obj.foobar }.should complain(/warning: global variable `\$specs_uninitialized_global_variable' not initialized/, verbose: true)
end
it "doesn't warn at lazy initialization" do
diff --git a/spec/ruby/language/yield_spec.rb b/spec/ruby/language/yield_spec.rb
index e125cf8e73..05d713af70 100644
--- a/spec/ruby/language/yield_spec.rb
+++ b/spec/ruby/language/yield_spec.rb
@@ -186,34 +186,39 @@ describe "The yield call" do
end
describe "Using yield in a singleton class literal" do
- it 'raises a SyntaxError' do
- code = <<~RUBY
- class << Object.new
- yield
- end
- RUBY
+ ruby_version_is ""..."3.0" do
+ it 'emits a deprecation warning' do
+ code = <<~RUBY
+ def m
+ class << Object.new
+ yield
+ end
+ end
+ m { :ok }
+ RUBY
- -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
+ -> { eval(code) }.should complain(/warning: `yield' in class syntax will not be supported from Ruby 3.0/)
+ end
end
-end
-describe "Using yield in non-lambda block" do
- it 'raises a SyntaxError' do
- code = <<~RUBY
- 1.times { yield }
+ ruby_version_is "3.0" do
+ it 'raises a SyntaxError' do
+ code = <<~RUBY
+ class << Object.new
+ yield
+ end
RUBY
- -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
+ -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
+ end
end
end
-describe "Using yield in a module literal" do
+describe "Using yield in non-lambda block" do
it 'raises a SyntaxError' do
code = <<~RUBY
- module YieldSpecs::ModuleWithYield
- yield
- end
- RUBY
+ 1.times { yield }
+ RUBY
-> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
end
diff --git a/spec/ruby/library/English/English_spec.rb b/spec/ruby/library/English/English_spec.rb
index 4d615d1e25..480602d5e5 100644
--- a/spec/ruby/library/English/English_spec.rb
+++ b/spec/ruby/library/English/English_spec.rb
@@ -130,15 +130,13 @@ describe "English" do
$LAST_MATCH_INFO.should == $~
end
- ruby_version_is ""..."3.3" do
- it "aliases $IGNORECASE to $=" do
- $VERBOSE, verbose = nil, $VERBOSE
- begin
- $IGNORECASE.should_not be_nil
- $IGNORECASE.should == $=
- ensure
- $VERBOSE = verbose
- end
+ it "aliases $IGNORECASE to $=" do
+ $VERBOSE, verbose = nil, $VERBOSE
+ begin
+ $IGNORECASE.should_not be_nil
+ $IGNORECASE.should == $=
+ ensure
+ $VERBOSE = verbose
end
end
diff --git a/spec/ruby/library/bigdecimal/add_spec.rb b/spec/ruby/library/bigdecimal/add_spec.rb
index 542713011d..bea8b8f764 100644
--- a/spec/ruby/library/bigdecimal/add_spec.rb
+++ b/spec/ruby/library/bigdecimal/add_spec.rb
@@ -24,7 +24,7 @@ describe "BigDecimal#add" do
end
it "returns a + b with given precision" do
- # documentation states that precision is optional, but it ain't,
+ # documentation states, that precision ist optional, but it ain't,
@two.add(@one, 1).should == @three
@one .add(@two, 1).should == @three
@one.add(@one_minus, 1).should == @zero
@@ -60,7 +60,7 @@ describe "BigDecimal#add" do
end
# TODO:
-# https://blade.ruby-lang.org/ruby-core/17374
+# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/17374
#
# This doesn't work on MRI and looks like a bug to me:
# one can use BigDecimal + Float, but not Bigdecimal.add(Float)
diff --git a/spec/ruby/library/bigdecimal/core_spec.rb b/spec/ruby/library/bigdecimal/core_spec.rb
deleted file mode 100644
index acee4dcf56..0000000000
--- a/spec/ruby/library/bigdecimal/core_spec.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-require_relative '../../spec_helper'
-require 'bigdecimal'
-
-describe "Core extension by bigdecimal" do
- context "Integer#coerce" do
- it "produces Floats" do
- x, y = 3.coerce(BigDecimal("3.4"))
- x.class.should == Float
- x.should == 3.4
- y.class.should == Float
- y.should == 3.0
- end
- end
-
- describe "Time.at passed BigDecimal" do
- it "doesn't round input value" do
- Time.at(BigDecimal('1.1')).to_f.should == 1.1
- end
- end
-
- describe "BigDecimal#log" do
- it "handles high-precision Rational arguments" do
- result = BigDecimal('0.22314354220170971436137296411949880462556361100856391620766259404746040597133837784E0')
- r = Rational(1_234_567_890, 987_654_321)
- BigMath.log(r, 50).should == result
- end
- end
-
- describe "Rational#coerce" do
- it "returns the passed argument, self as Float, when given a Float" do
- result = Rational(3, 4).coerce(1.0)
- result.should == [1.0, 0.75]
- result.first.is_a?(Float).should be_true
- result.last.is_a?(Float).should be_true
- end
-
- it "returns the passed argument, self as Rational, when given an Integer" do
- result = Rational(3, 4).coerce(10)
- result.should == [Rational(10, 1), Rational(3, 4)]
- result.first.is_a?(Rational).should be_true
- result.last.is_a?(Rational).should be_true
- end
-
- it "coerces to Rational, when given a Complex" do
- Rational(3, 4).coerce(Complex(5)).should == [Rational(5, 1), Rational(3, 4)]
- Rational(12, 4).coerce(Complex(5, 1)).should == [Complex(5, 1), Complex(3)]
- end
-
- it "returns [argument, self] when given a Rational" do
- Rational(3, 7).coerce(Rational(9, 2)).should == [Rational(9, 2), Rational(3, 7)]
- end
-
- it "raises an error when passed a BigDecimal" do
- -> {
- Rational(500, 3).coerce(BigDecimal('166.666666666'))
- }.should raise_error(TypeError, /BigDecimal can't be coerced into Rational/)
- end
- end
-end
diff --git a/spec/ruby/library/bigdecimal/remainder_spec.rb b/spec/ruby/library/bigdecimal/remainder_spec.rb
index bac5f37ba9..1866f665cd 100644
--- a/spec/ruby/library/bigdecimal/remainder_spec.rb
+++ b/spec/ruby/library/bigdecimal/remainder_spec.rb
@@ -54,23 +54,21 @@ describe "BigDecimal#remainder" do
@nan.remainder(@infinity).should.nan?
end
- version_is BigDecimal::VERSION, ""..."3.1.4" do #ruby_version_is ""..."3.3" do
- it "returns NaN if Infinity is involved" do
- @infinity.remainder(@infinity).should.nan?
- @infinity.remainder(@one).should.nan?
- @infinity.remainder(@mixed).should.nan?
- @infinity.remainder(@one_minus).should.nan?
- @infinity.remainder(@frac_1).should.nan?
- @one.remainder(@infinity).should.nan?
+ it "returns NaN if Infinity is involved" do
+ @infinity.remainder(@infinity).should.nan?
+ @infinity.remainder(@one).should.nan?
+ @infinity.remainder(@mixed).should.nan?
+ @infinity.remainder(@one_minus).should.nan?
+ @infinity.remainder(@frac_1).should.nan?
+ @one.remainder(@infinity).should.nan?
- @infinity_minus.remainder(@infinity_minus).should.nan?
- @infinity_minus.remainder(@one).should.nan?
- @one.remainder(@infinity_minus).should.nan?
- @frac_2.remainder(@infinity_minus).should.nan?
+ @infinity_minus.remainder(@infinity_minus).should.nan?
+ @infinity_minus.remainder(@one).should.nan?
+ @one.remainder(@infinity_minus).should.nan?
+ @frac_2.remainder(@infinity_minus).should.nan?
- @infinity.remainder(@infinity_minus).should.nan?
- @infinity_minus.remainder(@infinity).should.nan?
- end
+ @infinity.remainder(@infinity_minus).should.nan?
+ @infinity_minus.remainder(@infinity).should.nan?
end
it "coerces arguments to BigDecimal if possible" do
diff --git a/spec/ruby/library/bigdecimal/round_spec.rb b/spec/ruby/library/bigdecimal/round_spec.rb
index fba52df65d..bfc6dbc763 100644
--- a/spec/ruby/library/bigdecimal/round_spec.rb
+++ b/spec/ruby/library/bigdecimal/round_spec.rb
@@ -228,13 +228,13 @@ describe "BigDecimal#round" do
-> { BigDecimal('-Infinity').round(2) }.should_not raise_error(FloatDomainError)
end
- version_is BigDecimal::VERSION, ''...'3.1.3' do #ruby_version_is ''...'3.2' do
+ ruby_version_is ''...'3.2' do
it 'raise for a non-existent round mode' do
-> { @p1_50.round(0, :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode")
end
end
- version_is BigDecimal::VERSION, '3.1.3' do #ruby_version_is '3.2' do
+ ruby_version_is '3.2' do
it 'raise for a non-existent round mode' do
-> { @p1_50.round(0, :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode (nonsense)")
end
diff --git a/spec/ruby/library/bigdecimal/shared/to_int.rb b/spec/ruby/library/bigdecimal/shared/to_int.rb
index 44b6a3c7b2..0f16251612 100644
--- a/spec/ruby/library/bigdecimal/shared/to_int.rb
+++ b/spec/ruby/library/bigdecimal/shared/to_int.rb
@@ -1,6 +1,6 @@
require 'bigdecimal'
-describe :bigdecimal_to_int, shared: true do
+describe :bigdecimal_to_int , shared: true do
it "raises FloatDomainError if BigDecimal is infinity or NaN" do
-> { BigDecimal("Infinity").send(@method) }.should raise_error(FloatDomainError)
-> { BigDecimal("NaN").send(@method) }.should raise_error(FloatDomainError)
diff --git a/spec/ruby/library/bigdecimal/sqrt_spec.rb b/spec/ruby/library/bigdecimal/sqrt_spec.rb
index 42cf4545cb..d149003b9f 100644
--- a/spec/ruby/library/bigdecimal/sqrt_spec.rb
+++ b/spec/ruby/library/bigdecimal/sqrt_spec.rb
@@ -36,10 +36,8 @@ describe "BigDecimal#sqrt" do
BigDecimal('121').sqrt(5).should be_close(11, 0.00001)
end
- platform_is_not c_long_size: 32 do # fails on i686
- it "returns square root of 0.9E-99999 with desired precision" do
- @frac_2.sqrt(1).to_s.should =~ /\A0\.3E-49999\z/i
- end
+ it "returns square root of 0.9E-99999 with desired precision" do
+ @frac_2.sqrt(1).to_s.should =~ /\A0\.3E-49999\z/i
end
it "raises ArgumentError when no argument is given" do
diff --git a/spec/ruby/library/bigdecimal/to_s_spec.rb b/spec/ruby/library/bigdecimal/to_s_spec.rb
index ba9f960eb3..4f1054d38e 100644
--- a/spec/ruby/library/bigdecimal/to_s_spec.rb
+++ b/spec/ruby/library/bigdecimal/to_s_spec.rb
@@ -39,25 +39,20 @@ describe "BigDecimal#to_s" do
@bigneg.to_s("+").should_not =~ /^\+.*/
end
- it "inserts a space every n chars to fraction part, if integer n is supplied" do
+ it "inserts a space every n chars, if integer n is supplied" do
re =\
- /\A0\.314 159 265 358 979 323 846 264 338 327 950 288 419 716 939 937E1\z/i
+ /\A0\.314 159 265 358 979 323 846 264 338 327 950 288 419 716 939 937E1\z/i
@bigdec.to_s(3).should =~ re
str1 = '-123.45678 90123 45678 9'
BigDecimal("-123.45678901234567890").to_s('5F').should == str1
+ BigDecimal('1000010').to_s('5F').should == "10000 10.0"
# trailing zeroes removed
BigDecimal("1.00000000000").to_s('1F').should == "1.0"
# 0 is treated as no spaces
BigDecimal("1.2345").to_s('0F').should == "1.2345"
end
- version_is BigDecimal::VERSION, "3.1.5" do #ruby_version_is '3.3' do
- it "inserts a space every n chars to integer part, if integer n is supplied" do
- BigDecimal('1000010').to_s('5F').should == "10 00010.0"
- end
- end
-
it "can return a leading space for values > 0" do
@bigdec.to_s(" F").should =~ /\ .*/
@bigneg.to_s(" F").should_not =~ /\ .*/
@@ -88,13 +83,15 @@ describe "BigDecimal#to_s" do
end
end
- it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
- Encoding.default_internal = nil
- BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
- end
+ ruby_version_is "3.0" do
+ it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
+ Encoding.default_internal = nil
+ BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
+ end
- it "returns a String in US-ASCII encoding when Encoding.default_internal is not nil" do
- Encoding.default_internal = Encoding::IBM437
- BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
+ it "returns a String in US-ASCII encoding when Encoding.default_internal is not nil" do
+ Encoding.default_internal = Encoding::IBM437
+ BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
+ end
end
end
diff --git a/spec/ruby/library/bigmath/log_spec.rb b/spec/ruby/library/bigmath/log_spec.rb
new file mode 100644
index 0000000000..2ffbf8b6b9
--- /dev/null
+++ b/spec/ruby/library/bigmath/log_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../spec_helper'
+require 'bigdecimal'
+
+describe "BigDecimal#log" do
+ it "handles high-precision Rational arguments" do
+ result = BigDecimal('0.22314354220170971436137296411949880462556361100856391620766259404746040597133837784E0')
+ r = Rational(1_234_567_890, 987_654_321)
+ BigMath.log(r, 50).should == result
+ end
+end
diff --git a/spec/ruby/library/cgi/escapeURIComponent_spec.rb b/spec/ruby/library/cgi/escapeURIComponent_spec.rb
deleted file mode 100644
index f05795a2f5..0000000000
--- a/spec/ruby/library/cgi/escapeURIComponent_spec.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-require_relative '../../spec_helper'
-require 'cgi'
-
-ruby_version_is "3.2" do
- describe "CGI.escapeURIComponent" do
- it "escapes whitespace" do
- string = "&<>\" \xE3\x82\x86\xE3\x82\x93\xE3\x82\x86\xE3\x82\x93"
- CGI.escapeURIComponent(string).should == '%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93'
- end
-
- it "does not escape with unreserved characters" do
- string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
- CGI.escapeURIComponent(string).should == "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
- end
-
- it "supports String with invalid encoding" do
- string = "\xC0\<\<".dup.force_encoding("UTF-8")
- CGI.escapeURIComponent(string).should == "%C0%3C%3C"
- end
-
- it "processes String bytes one by one, not characters" do
- CGI.escapeURIComponent("β").should == "%CE%B2" # "β" bytes representation is CE B2
- end
-
- it "raises a TypeError with nil" do
- -> {
- CGI.escapeURIComponent(nil)
- }.should raise_error(TypeError, 'no implicit conversion of nil into String')
- end
-
- it "encodes empty string" do
- CGI.escapeURIComponent("").should == ""
- end
-
- it "encodes single whitespace" do
- CGI.escapeURIComponent(" ").should == "%20"
- end
-
- it "encodes double whitespace" do
- CGI.escapeURIComponent(" ").should == "%20%20"
- end
-
- it "preserves encoding" do
- string = "whatever".encode("ASCII-8BIT")
- CGI.escapeURIComponent(string).encoding.should == Encoding::ASCII_8BIT
- end
-
- it "uses implicit type conversion to String" do
- object = Object.new
- def object.to_str
- "a b"
- end
-
- CGI.escapeURIComponent(object).should == "a%20b"
- end
- end
-end
diff --git a/spec/ruby/library/cgi/initialize_spec.rb b/spec/ruby/library/cgi/initialize_spec.rb
index 61bc971d49..f794f157f0 100644
--- a/spec/ruby/library/cgi/initialize_spec.rb
+++ b/spec/ruby/library/cgi/initialize_spec.rb
@@ -29,8 +29,8 @@ describe "CGI#initialize when passed no arguments" do
it "does not extend self with any of the other HTML modules" do
@cgi.send(:initialize)
- @cgi.should_not be_kind_of(CGI::HtmlExtension)
@cgi.should_not be_kind_of(CGI::Html3)
+ @cgi.should_not be_kind_of(CGI::HtmlExtension)
@cgi.should_not be_kind_of(CGI::Html4)
@cgi.should_not be_kind_of(CGI::Html4Tr)
@cgi.should_not be_kind_of(CGI::Html4Fr)
diff --git a/spec/ruby/library/coverage/fixtures/code_with_begin.rb b/spec/ruby/library/coverage/fixtures/code_with_begin.rb
deleted file mode 100644
index 9a6384e337..0000000000
--- a/spec/ruby/library/coverage/fixtures/code_with_begin.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-begin
- 'coverage with begin'
-end
diff --git a/spec/ruby/library/coverage/result_spec.rb b/spec/ruby/library/coverage/result_spec.rb
index 54a3249e45..4bcce00cd7 100644
--- a/spec/ruby/library/coverage/result_spec.rb
+++ b/spec/ruby/library/coverage/result_spec.rb
@@ -6,20 +6,12 @@ describe 'Coverage.result' do
@class_file = fixture __FILE__, 'some_class.rb'
@config_file = fixture __FILE__, 'start_coverage.rb'
@eval_code_file = fixture __FILE__, 'eval_code.rb'
- @with_begin_file = fixture __FILE__, 'code_with_begin.rb'
- end
-
- before :each do
- Coverage.running?.should == false
end
after :each do
$LOADED_FEATURES.delete(@class_file)
$LOADED_FEATURES.delete(@config_file)
$LOADED_FEATURES.delete(@eval_code_file)
- $LOADED_FEATURES.delete(@with_begin_file)
-
- Coverage.result if Coverage.running?
end
it 'gives the covered files as a hash with arrays of count or nil' do
@@ -34,41 +26,6 @@ describe 'Coverage.result' do
}
end
- ruby_version_is "3.2" do
- it 'returns results for each mode separately when enabled :all modes' do
- Coverage.start(:all)
- require @class_file.chomp('.rb')
- result = Coverage.result
-
- result.should == {
- @class_file => {
- lines: [
- nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
- ],
- branches: {},
- methods: {
- [SomeClass, :some_method, 6, 2, 11, 5] => 0
- }
- }
- }
- end
-
- it 'returns results for each mode separately when enabled any mode explicitly' do
- Coverage.start(lines: true)
- require @class_file.chomp('.rb')
- result = Coverage.result
-
- result.should == {
- @class_file =>
- {
- lines: [
- nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
- ]
- }
- }
- end
- end
-
it 'no requires/loads should give empty hash' do
Coverage.start
result = Coverage.result
@@ -118,6 +75,17 @@ describe 'Coverage.result' do
end
end
+ ruby_version_is '3.1' do
+ it 'second Coverage.start give exception' do
+ Coverage.start
+ -> {
+ require @config_file.chomp('.rb')
+ }.should raise_error(RuntimeError, 'coverage measurement is already setup')
+ ensure
+ Coverage.result
+ end
+ end
+
it 'does not include the file starting coverage since it is not tracked' do
require @config_file.chomp('.rb')
Coverage.result.should_not include(@config_file)
@@ -130,14 +98,18 @@ describe 'Coverage.result' do
result = Coverage.result
result.should == {
- @eval_code_file => [
- 1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1
- ]
+ @eval_code_file => [
+ 1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1
+ ]
}
end
end
ruby_version_is '3.2' do
+ it 'indicates support for different features' do
+ Coverage.supported?(:lines).should == true
+ end
+
it 'returns the correct results when eval coverage is enabled' do
Coverage.supported?(:eval).should == true
@@ -146,13 +118,13 @@ describe 'Coverage.result' do
result = Coverage.result
result.should == {
- @eval_code_file => {
- lines: [1, nil, 1, nil, 1, 1, nil, nil, nil, nil, 1]
- }
+ @eval_code_file => {
+ lines: [1, nil, 1, nil, 1, 1, nil, nil, nil, nil, 1]
+ }
}
end
- it 'returns the correct results when eval coverage is disabled' do
+ it 'returns the correct results when eval coverage is enabled' do
Coverage.supported?(:eval).should == true
Coverage.start(lines: true, eval: false)
@@ -160,212 +132,10 @@ describe 'Coverage.result' do
result = Coverage.result
result.should == {
- @eval_code_file => {
- lines: [1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1]
- }
+ @eval_code_file => {
+ lines: [1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1]
+ }
}
end
end
-
- it "disables coverage measurement when stop option is not specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- Coverage.result
- Coverage.running?.should == false
- end
-
- it "disables coverage measurement when stop: true option is specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- -> {
- Coverage.result(stop: true)
- }.should complain(/warning: stop implies clear/)
-
- Coverage.running?.should == false
- end
-
- it "does not disable coverage measurement when stop: false option is specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- Coverage.result(stop: false)
- Coverage.running?.should == true
- end
-
- it "does not disable coverage measurement when stop option is not specified but clear: true specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- Coverage.result(clear: true)
- Coverage.running?.should == true
- end
-
- it "does not disable coverage measurement when stop option is not specified but clear: false specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- Coverage.result(clear: false)
- Coverage.running?.should == true
- end
-
- it "disables coverage measurement when stop: true and clear: true specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- Coverage.result(stop: true, clear: true)
- Coverage.running?.should == false
- end
-
- it "disables coverage measurement when stop: true and clear: false specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- -> {
- Coverage.result(stop: true, clear: false)
- }.should complain(/warning: stop implies clear/)
-
- Coverage.running?.should == false
- end
-
- it "does not disable coverage measurement when stop: false and clear: true specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- Coverage.result(stop: false, clear: true)
- Coverage.running?.should == true
- end
-
- it "does not disable coverage measurement when stop: false and clear: false specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- Coverage.result(stop: false, clear: false)
- Coverage.running?.should == true
- end
-
- it "resets counters (remove them) when stop: true specified but clear option is not specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- -> {
- Coverage.result(stop: true) # clears counters
- }.should complain(/warning: stop implies clear/)
-
- Coverage.start
- Coverage.peek_result.should == {}
- end
-
- it "resets counters (remove them) when stop: true and clear: true specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- Coverage.result(stop: true, clear: true) # clears counters
-
- Coverage.start
- Coverage.peek_result.should == {}
- end
-
- it "resets counters (remove them) when stop: true and clear: false specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- -> {
- Coverage.result(stop: true, clear: false) # clears counters
- }.should complain(/warning: stop implies clear/)
-
- Coverage.start
- Coverage.peek_result.should == {}
- end
-
- it "resets counters (remove them) when both stop and clear options are not specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- Coverage.result # clears counters
-
- Coverage.start
- Coverage.peek_result.should == {}
- end
-
- it "clears counters (sets 0 values) when stop is not specified but clear: true specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- Coverage.result(clear: true) # clears counters
-
- Coverage.peek_result.should == {
- @class_file => [
- nil, nil, 0, nil, nil, 0, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
- ]
- }
- end
-
- it "does not clear counters when stop is not specified but clear: false specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- result = Coverage.result(clear: false) # doesn't clear counters
- result.should == {
- @class_file => [
- nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
- ]
- }
-
- Coverage.peek_result.should == result
- end
-
- it "does not clear counters when stop: false and clear is not specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- result = Coverage.result(stop: false) # doesn't clear counters
- result.should == {
- @class_file => [
- nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
- ]
- }
-
- Coverage.peek_result.should == result
- end
-
- it "clears counters (sets 0 values) when stop: false and clear: true specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- Coverage.result(stop: false, clear: true) # clears counters
-
- Coverage.peek_result.should == {
- @class_file => [
- nil, nil, 0, nil, nil, 0, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
- ]
- }
- end
-
- it "does not clear counters when stop: false and clear: false specified" do
- Coverage.start
- require @class_file.chomp('.rb')
-
- result = Coverage.result(stop: false, clear: false) # doesn't clear counters
- result.should == {
- @class_file => [
- nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
- ]
- }
-
- Coverage.peek_result.should == result
- end
-
- it 'covers 100% lines with begin' do
- Coverage.start
- require @with_begin_file.chomp('.rb')
- result = Coverage.result
-
- result.should == {
- @with_begin_file => [
- nil, 1, nil
- ]
- }
- end
end
diff --git a/spec/ruby/library/coverage/running_spec.rb b/spec/ruby/library/coverage/running_spec.rb
index e9cc7ada5a..745270164f 100644
--- a/spec/ruby/library/coverage/running_spec.rb
+++ b/spec/ruby/library/coverage/running_spec.rb
@@ -17,4 +17,4 @@ describe 'Coverage.running?' do
Coverage.result
Coverage.running?.should == false
end
-end
+end \ No newline at end of file
diff --git a/spec/ruby/library/coverage/start_spec.rb b/spec/ruby/library/coverage/start_spec.rb
index 7fccf2d5cf..a993abbf4e 100644
--- a/spec/ruby/library/coverage/start_spec.rb
+++ b/spec/ruby/library/coverage/start_spec.rb
@@ -2,87 +2,8 @@ require_relative '../../spec_helper'
require 'coverage'
describe 'Coverage.start' do
- before :each do
- Coverage.should_not.running?
- end
-
- after :each do
- Coverage.result(stop: true, clear: true) if Coverage.running?
- end
-
- it "enables the coverage measurement" do
- Coverage.start
- Coverage.should.running?
- end
-
- it "returns nil" do
- Coverage.start.should == nil
- end
-
- ruby_version_is '3.1' do
- it 'raises error when repeated Coverage.start call happens' do
- Coverage.start
-
- -> {
- Coverage.start
- }.should raise_error(RuntimeError, 'coverage measurement is already setup')
- end
- end
-
ruby_version_is '3.2' do
- it "accepts :all optional argument" do
- Coverage.start(:all)
- Coverage.should.running?
- end
-
- it "accepts lines: optional keyword argument" do
- Coverage.start(lines: true)
- Coverage.should.running?
- end
-
- it "accepts branches: optional keyword argument" do
- Coverage.start(branches: true)
- Coverage.should.running?
- end
-
- it "accepts methods: optional keyword argument" do
- Coverage.start(methods: true)
- Coverage.should.running?
- end
-
- it "accepts eval: optional keyword argument" do
- Coverage.start(eval: true)
- Coverage.should.running?
- end
-
- it "accepts oneshot_lines: optional keyword argument" do
- Coverage.start(oneshot_lines: true)
- Coverage.should.running?
- end
-
- it "ignores unknown keyword arguments" do
- Coverage.start(foo: true)
- Coverage.should.running?
- end
-
- it "expects a Hash if not passed :all" do
- -> {
- Coverage.start(42)
- }.should raise_error(TypeError, "no implicit conversion of Integer into Hash")
- end
-
- it "does not accept both lines: and oneshot_lines: keyword arguments" do
- -> {
- Coverage.start(lines: true, oneshot_lines: true)
- }.should raise_error(RuntimeError, "cannot enable lines and oneshot_lines simultaneously")
- end
-
- it "enables the coverage measurement if passed options with `false` value" do
- Coverage.start(lines: false, branches: false, methods: false, eval: false, oneshot_lines: false)
- Coverage.should.running?
- end
-
- it "measures coverage within eval" do
+ it "can measure coverage within eval" do
Coverage.start(lines: true, eval: true)
eval("Object.new\n"*3, binding, "test.rb", 1)
Coverage.result["test.rb"].should == {lines: [1, 1, 1]}
diff --git a/spec/ruby/library/coverage/supported_spec.rb b/spec/ruby/library/coverage/supported_spec.rb
deleted file mode 100644
index 78b3784ee0..0000000000
--- a/spec/ruby/library/coverage/supported_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../../spec_helper'
-require 'coverage'
-
-describe "Coverage.supported?" do
- ruby_version_is "3.2" do
- it "returns true or false if coverage measurement is supported for the given mode" do
- [true, false].should.include?(Coverage.supported?(:lines))
- [true, false].should.include?(Coverage.supported?(:branches))
- [true, false].should.include?(Coverage.supported?(:methods))
- [true, false].should.include?(Coverage.supported?(:eval))
- end
-
- it "returns false for not existing modes" do
- Coverage.supported?(:foo).should == false
- Coverage.supported?(:bar).should == false
- end
-
- it "raise TypeError if argument is not Symbol" do
- -> {
- Coverage.supported?("lines")
- }.should raise_error(TypeError, "wrong argument type String (expected Symbol)")
-
- -> {
- Coverage.supported?([])
- }.should raise_error(TypeError, "wrong argument type Array (expected Symbol)")
-
- -> {
- Coverage.supported?(1)
- }.should raise_error(TypeError, "wrong argument type Integer (expected Symbol)")
- end
- end
-end
diff --git a/spec/ruby/library/csv/generate_spec.rb b/spec/ruby/library/csv/generate_spec.rb
index b45e2eb95b..0a1e3d9604 100644
--- a/spec/ruby/library/csv/generate_spec.rb
+++ b/spec/ruby/library/csv/generate_spec.rb
@@ -21,7 +21,7 @@ describe "CSV.generate" do
end
it "appends and returns the argument itself" do
- str = +""
+ str = ""
csv_str = CSV.generate(str) do |csv|
csv.add_row [1, 2, 3]
csv << [4, 5, 6]
diff --git a/spec/ruby/library/date/accessor_spec.rb b/spec/ruby/library/date/accessor_spec.rb
index 74ed0e9c21..68a2d9f3de 100644
--- a/spec/ruby/library/date/accessor_spec.rb
+++ b/spec/ruby/library/date/accessor_spec.rb
@@ -38,7 +38,7 @@ describe "Date#year" do
end
describe "Date#yday" do
- it "determines the day of the year" do
+ it "determines the year" do
Date.civil(2007, 1, 17).yday.should == 17
Date.civil(2008, 10, 28).yday.should == 302
end
diff --git a/spec/ruby/library/date/deconstruct_keys_spec.rb b/spec/ruby/library/date/deconstruct_keys_spec.rb
deleted file mode 100644
index 92579e35c7..0000000000
--- a/spec/ruby/library/date/deconstruct_keys_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-require_relative '../../spec_helper'
-require 'date'
-date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
-
-version_is date_version, "3.3" do #ruby_version_is "3.2" do
- describe "Date#deconstruct_keys" do
- it "returns whole hash for nil as an argument" do
- d = Date.new(2022, 10, 5)
- d.deconstruct_keys(nil).should == { year: 2022, month: 10, day: 5, yday: 278, wday: 3 }
- end
-
- it "returns only specified keys" do
- d = Date.new(2022, 10, 5)
- d.deconstruct_keys([:year, :month]).should == { year: 2022, month: 10 }
- end
-
- it "requires one argument" do
- -> {
- Date.new(2022, 10, 5).deconstruct_keys
- }.should raise_error(ArgumentError)
- end
-
- it "it raises error when argument is neither nil nor array" do
- d = Date.new(2022, 10, 5)
-
- -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)")
- -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)")
- -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)")
- -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)")
- end
-
- it "returns {} when passed []" do
- Date.new(2022, 10, 5).deconstruct_keys([]).should == {}
- end
-
- it "ignores non-Symbol keys" do
- Date.new(2022, 10, 5).deconstruct_keys(['year', []]).should == {}
- end
-
- it "ignores not existing Symbol keys" do
- Date.new(2022, 10, 5).deconstruct_keys([:year, :a]).should == { year: 2022 }
- end
- end
-end
diff --git a/spec/ruby/library/date/iso8601_spec.rb b/spec/ruby/library/date/iso8601_spec.rb
index af66845a6b..a29652014e 100644
--- a/spec/ruby/library/date/iso8601_spec.rb
+++ b/spec/ruby/library/date/iso8601_spec.rb
@@ -22,18 +22,6 @@ describe "Date.iso8601" do
d.should == Date.civil(-4712, 1, 1)
end
- it "raises a Date::Error if the argument is a invalid Date" do
- -> {
- Date.iso8601('invalid')
- }.should raise_error(Date::Error, "invalid date")
- end
-
- it "raises a Date::Error when passed a nil" do
- -> {
- Date.iso8601(nil)
- }.should raise_error(Date::Error, "invalid date")
- end
-
it "raises a TypeError when passed an Object" do
-> { Date.iso8601(Object.new) }.should raise_error(TypeError)
end
@@ -44,13 +32,4 @@ describe "Date._iso8601" do
h = Date._iso8601('invalid')
h.should == {}
end
-
- it "returns an empty hash if the argument is nil" do
- h = Date._iso8601(nil)
- h.should == {}
- end
-
- it "raises a TypeError when passed an Object" do
- -> { Date._iso8601(Object.new) }.should raise_error(TypeError)
- end
end
diff --git a/spec/ruby/library/date/new_spec.rb b/spec/ruby/library/date/new_spec.rb
index cb64cabce6..18120118c0 100644
--- a/spec/ruby/library/date/new_spec.rb
+++ b/spec/ruby/library/date/new_spec.rb
@@ -1,6 +1,7 @@
require 'date'
require_relative '../../spec_helper'
require_relative 'shared/civil'
+require_relative 'shared/new_bang'
describe "Date.new" do
it_behaves_like :date_civil, :new
diff --git a/spec/ruby/library/date/parse_spec.rb b/spec/ruby/library/date/parse_spec.rb
index 5ef4f6e9b5..bfbe86fbac 100644
--- a/spec/ruby/library/date/parse_spec.rb
+++ b/spec/ruby/library/date/parse_spec.rb
@@ -93,7 +93,7 @@ describe "Date#parse with '.' separator" do
@sep = '.'
end
- it_should_behave_like :date_parse
+ it_should_behave_like "date_parse"
end
describe "Date#parse with '/' separator" do
@@ -101,7 +101,7 @@ describe "Date#parse with '/' separator" do
@sep = '/'
end
- it_should_behave_like :date_parse
+ it_should_behave_like "date_parse"
end
describe "Date#parse with ' ' separator" do
@@ -109,7 +109,7 @@ describe "Date#parse with ' ' separator" do
@sep = ' '
end
- it_should_behave_like :date_parse
+ it_should_behave_like "date_parse"
end
describe "Date#parse with '/' separator US-style" do
@@ -117,7 +117,7 @@ describe "Date#parse with '/' separator US-style" do
@sep = '/'
end
- it_should_behave_like :date_parse_us
+ it_should_behave_like "date_parse_us"
end
describe "Date#parse with '-' separator EU-style" do
@@ -125,7 +125,7 @@ describe "Date#parse with '-' separator EU-style" do
@sep = '-'
end
- it_should_behave_like :date_parse_eu
+ it_should_behave_like "date_parse_eu"
end
describe "Date#parse(.)" do
diff --git a/spec/ruby/library/date/shared/new_bang.rb b/spec/ruby/library/date/shared/new_bang.rb
new file mode 100644
index 0000000000..90f1b432f0
--- /dev/null
+++ b/spec/ruby/library/date/shared/new_bang.rb
@@ -0,0 +1,14 @@
+describe :date_new_bang, shared: true do
+
+ it "returns a new Date object set to Astronomical Julian Day 0 if no arguments passed" do
+ d = Date.send(@method)
+ d.ajd.should == 0
+ end
+
+ it "accepts astronomical julian day number, offset as a fraction of a day and returns a new Date object" do
+ d = Date.send(@method, 10, 0.5)
+ d.ajd.should == 10
+ d.jd.should == 11
+ end
+
+end
diff --git a/spec/ruby/library/date/shared/parse.rb b/spec/ruby/library/date/shared/parse.rb
index 40af908386..1015285e04 100644
--- a/spec/ruby/library/date/shared/parse.rb
+++ b/spec/ruby/library/date/shared/parse.rb
@@ -13,7 +13,7 @@ describe :date_parse, shared: true do
d.day.should == 23
end
- it "can parse a 'DD mmm YYYY' string into a Date object" do
+ it "can parse a 'mmm DD YYYY' string into a Date object" do
d = Date.parse("23#{@sep}feb#{@sep}2008")
d.year.should == 2008
d.month.should == 2
@@ -42,7 +42,7 @@ describe :date_parse, shared: true do
d.should == Date.civil(2005, 11, 5)
end
- it "can parse a day, month name and year into a Date object" do
+ it "can parse a year, day and month name into a Date object" do
d = Date.parse("5th#{@sep}november#{@sep}2005")
d.should == Date.civil(2005, 11, 5)
end
diff --git a/spec/ruby/library/date/shared/parse_eu.rb b/spec/ruby/library/date/shared/parse_eu.rb
index 3819524a57..ecb15e3c0e 100644
--- a/spec/ruby/library/date/shared/parse_eu.rb
+++ b/spec/ruby/library/date/shared/parse_eu.rb
@@ -7,28 +7,28 @@ describe :date_parse_eu, shared: true do
d.day.should == 1
end
- it "can parse a DD-MM-YYYY string into a Date object" do
+ it "can parse a MM-DD-YYYY string into a Date object" do
d = Date.parse("10#{@sep}01#{@sep}2007")
d.year.should == 2007
d.month.should == 1
d.day.should == 10
end
- it "can parse a YY-MM-DD string into a Date object" do
+ it "can parse a MM-DD-YY string into a Date object" do
d = Date.parse("10#{@sep}01#{@sep}07")
d.year.should == 2010
d.month.should == 1
d.day.should == 7
end
- it "can parse a YY-MM-DD string into a Date object NOT using the year digits as 20XX" do
+ it "can parse a MM-DD-YY string into a Date object NOT using the year digits as 20XX" do
d = Date.parse("10#{@sep}01#{@sep}07", false)
d.year.should == 10
d.month.should == 1
d.day.should == 7
end
- it "can parse a YY-MM-DD string into a Date object using the year digits as 20XX" do
+ it "can parse a MM-DD-YY string into a Date object using the year digits as 20XX" do
d = Date.parse("10#{@sep}01#{@sep}07", true)
d.year.should == 2010
d.month.should == 1
diff --git a/spec/ruby/library/date/shared/parse_us.rb b/spec/ruby/library/date/shared/parse_us.rb
index 17e2fc96c1..7be62b1af1 100644
--- a/spec/ruby/library/date/shared/parse_us.rb
+++ b/spec/ruby/library/date/shared/parse_us.rb
@@ -6,28 +6,28 @@ describe :date_parse_us, shared: true do
d.day.should == 1
end
- it "parses a DD#{@sep}MM#{@sep}YYYY string into a Date object" do
+ it "parses a MM#{@sep}DD#{@sep}YYYY string into a Date object" do
d = Date.parse("10#{@sep}01#{@sep}2007")
d.year.should == 2007
d.month.should == 1
d.day.should == 10
end
- it "parses a YY#{@sep}MM#{@sep}DD string into a Date object" do
+ it "parses a MM#{@sep}DD#{@sep}YY string into a Date object" do
d = Date.parse("10#{@sep}01#{@sep}07")
d.year.should == 2010
d.month.should == 1
d.day.should == 7
end
- it "parses a YY#{@sep}MM#{@sep}DD string into a Date object NOT using the year digits as 20XX" do
+ it "parses a MM#{@sep}DD#{@sep}YY string into a Date object NOT using the year digits as 20XX" do
d = Date.parse("10#{@sep}01#{@sep}07", false)
d.year.should == 10
d.month.should == 1
d.day.should == 7
end
- it "parses a YY#{@sep}MM#{@sep}DD string into a Date object using the year digits as 20XX" do
+ it "parses a MM#{@sep}DD#{@sep}YY string into a Date object using the year digits as 20XX" do
d = Date.parse("10#{@sep}01#{@sep}07", true)
d.year.should == 2010
d.month.should == 1
diff --git a/spec/ruby/library/date/strftime_spec.rb b/spec/ruby/library/date/strftime_spec.rb
index b5232a2073..8b1ebe061c 100644
--- a/spec/ruby/library/date/strftime_spec.rb
+++ b/spec/ruby/library/date/strftime_spec.rb
@@ -1,7 +1,5 @@
-require_relative "../../spec_helper"
require 'date'
require_relative '../../shared/time/strftime_for_date'
-date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
describe "Date#strftime" do
before :all do
@@ -24,14 +22,14 @@ describe "Date#strftime" do
end
# %v is %e-%b-%Y for Date/DateTime
- version_is date_version, ""..."3.2" do #ruby_version_is ""..."3.1" do
+ ruby_version_is ""..."3.1" do
it "should be able to show the commercial week" do
@date.strftime("%v").should == " 9-Apr-2000"
@date.strftime("%v").should == @date.strftime('%e-%b-%Y')
end
end
- version_is date_version, "3.2" do #ruby_version_is "3.1" do
+ ruby_version_is "3.1" do
it "should be able to show the commercial week" do
@date.strftime("%v").should == " 9-APR-2000"
@date.strftime("%v").should != @date.strftime('%e-%b-%Y')
diff --git a/spec/ruby/library/date/time/to_date_spec.rb b/spec/ruby/library/date/time/to_date_spec.rb
deleted file mode 100644
index f9132da289..0000000000
--- a/spec/ruby/library/date/time/to_date_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-
-require_relative '../../../spec_helper'
-require 'time'
-
-describe "Time#to_date" do
- it "yields accurate julian date for ambiguous pre-Gregorian reform value" do
- Time.utc(1582, 10, 4).to_date.jd.should == Date::ITALY - 11 # 2299150j
- end
-
- it "yields accurate julian date for Julian-Gregorian gap value" do
- Time.utc(1582, 10, 14).to_date.jd.should == Date::ITALY - 1 # 2299160j
- end
-
- it "yields accurate julian date for post-Gregorian reform value" do
- Time.utc(1582, 10, 15).to_date.jd.should == Date::ITALY # 2299161j
- end
-
- it "yields same julian day regardless of UTC time value" do
- Time.utc(1582, 10, 15, 00, 00, 00).to_date.jd.should == Date::ITALY
- Time.utc(1582, 10, 15, 23, 59, 59).to_date.jd.should == Date::ITALY
- end
-
- it "yields same julian day regardless of local time or zone" do
-
- with_timezone("Pacific/Pago_Pago", -11) do
- Time.local(1582, 10, 15, 00, 00, 00).to_date.jd.should == Date::ITALY
- Time.local(1582, 10, 15, 23, 59, 59).to_date.jd.should == Date::ITALY
- end
-
- with_timezone("Asia/Kamchatka", +12) do
- Time.local(1582, 10, 15, 00, 00, 00).to_date.jd.should == Date::ITALY
- Time.local(1582, 10, 15, 23, 59, 59).to_date.jd.should == Date::ITALY
- end
-
- end
-
- it "yields date with default Calendar reform day" do
- Time.utc(1582, 10, 4).to_date.start.should == Date::ITALY
- Time.utc(1582, 10, 14).to_date.start.should == Date::ITALY
- Time.utc(1582, 10, 15).to_date.start.should == Date::ITALY
- end
-end
diff --git a/spec/ruby/library/date/yday_spec.rb b/spec/ruby/library/date/yday_spec.rb
index 7dd42e52a5..cfb174a4c2 100644
--- a/spec/ruby/library/date/yday_spec.rb
+++ b/spec/ruby/library/date/yday_spec.rb
@@ -1,7 +1,6 @@
require_relative '../../spec_helper'
-require_relative '../../shared/time/yday'
require 'date'
describe "Date#yday" do
- it_behaves_like :time_yday, -> year, month, day { Date.new(year, month, day).yday }
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/library/datetime/deconstruct_keys_spec.rb b/spec/ruby/library/datetime/deconstruct_keys_spec.rb
deleted file mode 100644
index 77ceaa51c4..0000000000
--- a/spec/ruby/library/datetime/deconstruct_keys_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-require_relative '../../spec_helper'
-require 'date'
-date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
-
-version_is date_version, "3.3" do #ruby_version_is "3.2" do
- describe "DateTime#deconstruct_keys" do
- it "returns whole hash for nil as an argument" do
- d = DateTime.new(2022, 10, 5, 13, 30)
- res = { year: 2022, month: 10, day: 5, yday: 278, wday: 3, hour: 13,
- min: 30, sec: 0, sec_fraction: (0/1), zone: "+00:00" }
- d.deconstruct_keys(nil).should == res
- end
-
- it "returns only specified keys" do
- d = DateTime.new(2022, 10, 5, 13, 39)
- d.deconstruct_keys([:zone, :hour]).should == { zone: "+00:00", hour: 13 }
- end
-
- it "requires one argument" do
- -> {
- DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys
- }.should raise_error(ArgumentError)
- end
-
- it "it raises error when argument is neither nil nor array" do
- d = DateTime.new(2022, 10, 5, 13, 30)
-
- -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)")
- -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)")
- -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)")
- -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)")
- end
-
- it "returns {} when passed []" do
- DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys([]).should == {}
- end
-
- it "ignores non-Symbol keys" do
- DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {}
- end
-
- it "ignores not existing Symbol keys" do
- DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys([:year, :a]).should == { year: 2022 }
- end
- end
-end
diff --git a/spec/ruby/library/datetime/rfc2822_spec.rb b/spec/ruby/library/datetime/rfc2822_spec.rb
index 83f7fa8d5b..70bfca60b4 100644
--- a/spec/ruby/library/datetime/rfc2822_spec.rb
+++ b/spec/ruby/library/datetime/rfc2822_spec.rb
@@ -3,8 +3,4 @@ require 'date'
describe "DateTime.rfc2822" do
it "needs to be reviewed for spec completeness"
-
- it "raises DateError if passed nil" do
- -> { DateTime.rfc2822(nil) }.should raise_error(Date::Error, "invalid date")
- end
end
diff --git a/spec/ruby/library/datetime/strftime_spec.rb b/spec/ruby/library/datetime/strftime_spec.rb
index abb0838e8e..725bcafb0d 100644
--- a/spec/ruby/library/datetime/strftime_spec.rb
+++ b/spec/ruby/library/datetime/strftime_spec.rb
@@ -2,7 +2,6 @@ require_relative '../../spec_helper'
require 'date'
require_relative '../../shared/time/strftime_for_date'
require_relative '../../shared/time/strftime_for_time'
-date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
describe "DateTime#strftime" do
before :all do
@@ -34,14 +33,14 @@ describe "DateTime#strftime" do
end
# %v is %e-%b-%Y for Date/DateTime
- version_is date_version, ""..."3.2" do #ruby_version_is ""..."3.1" do
+ ruby_version_is ""..."3.1" do
it "should be able to show the commercial week" do
@time.strftime("%v").should == " 3-Feb-2001"
@time.strftime("%v").should == @time.strftime('%e-%b-%Y')
end
end
- version_is date_version, "3.2" do #ruby_version_is "3.1" do
+ ruby_version_is "3.1" do
it "should be able to show the commercial week" do
@time.strftime("%v").should == " 3-FEB-2001"
@time.strftime("%v").should != @time.strftime('%e-%b-%Y')
diff --git a/spec/ruby/library/datetime/time/to_datetime_spec.rb b/spec/ruby/library/datetime/time/to_datetime_spec.rb
deleted file mode 100644
index 1125dbe851..0000000000
--- a/spec/ruby/library/datetime/time/to_datetime_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-require_relative '../../../spec_helper'
-require 'time'
-require 'date'
-date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
-
-describe "Time#to_datetime" do
- it "returns a DateTime representing the same instant" do
- time = Time.utc(2012, 12, 31, 23, 58, 59)
- datetime = time.to_datetime
- datetime.year.should == 2012
- datetime.month.should == 12
- datetime.day.should == 31
- datetime.hour.should == 23
- datetime.min.should == 58
- datetime.sec.should == 59
- end
-
- version_is date_version, '3.2.3' do #ruby_version_is '3.2' do
- it "returns a DateTime representing the same instant before Gregorian" do
- time = Time.utc(1582, 10, 14, 23, 58, 59)
- datetime = time.to_datetime
- datetime.year.should == 1582
- datetime.month.should == 10
- datetime.day.should == 4
- datetime.hour.should == 23
- datetime.min.should == 58
- datetime.sec.should == 59
- end
- end
-
- it "roundtrips" do
- time = Time.utc(3, 12, 31, 23, 58, 59)
- datetime = time.to_datetime
- datetime.to_time.utc.should == time
- end
-
- it "yields a DateTime with the default Calendar reform day" do
- Time.utc(1582, 10, 4, 1, 2, 3).to_datetime.start.should == Date::ITALY
- Time.utc(1582, 10, 14, 1, 2, 3).to_datetime.start.should == Date::ITALY
- Time.utc(1582, 10, 15, 1, 2, 3).to_datetime.start.should == Date::ITALY
- end
-end
diff --git a/spec/ruby/library/datetime/to_time_spec.rb b/spec/ruby/library/datetime/to_time_spec.rb
index 09e6192e7f..95eca864da 100644
--- a/spec/ruby/library/datetime/to_time_spec.rb
+++ b/spec/ruby/library/datetime/to_time_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require 'date'
-date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
describe "DateTime#to_time" do
it "yields a new Time object" do
@@ -19,7 +18,8 @@ describe "DateTime#to_time" do
time.sec.should == 59
end
- version_is date_version, '3.2.3' do #ruby_version_is "3.2" do
+ date_version = defined?(Date::VERSION) ? Date::VERSION : '0.0.0'
+ version_is(date_version, '3.2.3') do
it "returns a Time representing the same instant before Gregorian" do
datetime = DateTime.civil(1582, 10, 4, 23, 58, 59)
time = datetime.to_time.utc
diff --git a/spec/ruby/library/datetime/yday_spec.rb b/spec/ruby/library/datetime/yday_spec.rb
deleted file mode 100644
index 08a72c6480..0000000000
--- a/spec/ruby/library/datetime/yday_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require_relative '../../shared/time/yday'
-require 'date'
-
-describe "DateTime#yday" do
- it_behaves_like :time_yday, -> year, month, day { DateTime.new(year, month, day).yday }
-end
diff --git a/spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb b/spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb
index 3975e5208b..729cfc96c6 100644
--- a/spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb
+++ b/spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require 'delegate'
describe "DelegateClass#respond_to_missing?" do
diff --git a/spec/ruby/library/digest/instance/shared/update.rb b/spec/ruby/library/digest/instance/shared/update.rb
index 17779e54a4..dccc8f80df 100644
--- a/spec/ruby/library/digest/instance/shared/update.rb
+++ b/spec/ruby/library/digest/instance/shared/update.rb
@@ -3,6 +3,6 @@ describe :digest_instance_update, shared: true do
c = Class.new do
include Digest::Instance
end
- -> { c.new.send(@method, "test") }.should raise_error(RuntimeError)
+ -> { c.new.update("test") }.should raise_error(RuntimeError)
end
end
diff --git a/spec/ruby/library/digest/md5/shared/sample.rb b/spec/ruby/library/digest/md5/shared/sample.rb
new file mode 100644
index 0000000000..2bb4f658b1
--- /dev/null
+++ b/spec/ruby/library/digest/md5/shared/sample.rb
@@ -0,0 +1,17 @@
+# -*- encoding: binary -*-
+
+require 'digest/md5'
+
+module MD5Constants
+
+ Contents = "Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. \nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. \nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
+
+ Klass = ::Digest::MD5
+ BlockLength = 64
+ DigestLength = 16
+ BlankDigest = "\324\035\214\331\217\000\262\004\351\200\t\230\354\370B~"
+ Digest = "\2473\267qw\276\364\343\345\320\304\350\313\314\217n"
+ BlankHexdigest = "d41d8cd98f00b204e9800998ecf8427e"
+ Hexdigest = "a733b77177bef4e3e5d0c4e8cbcc8f6e"
+
+end
diff --git a/spec/ruby/library/drb/start_service_spec.rb b/spec/ruby/library/drb/start_service_spec.rb
index 57a8cf6e15..016c8b2cff 100644
--- a/spec/ruby/library/drb/start_service_spec.rb
+++ b/spec/ruby/library/drb/start_service_spec.rb
@@ -1,33 +1,28 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/test_server'
+require 'drb'
-# This does not work yet when run in CRuby via make test-spec:
-# Gem::MissingSpecError: Could not find 'ruby2_keywords' (>= 0) among 28 total gem(s)
-guard_not -> { MSpecScript.instance_variable_defined?(:@testing_ruby) } do
- require_relative 'fixtures/test_server'
- require 'drb'
-
- describe "DRb.start_service" do
- before :each do
- @server = DRb.start_service("druby://localhost:0", TestServer.new)
- end
+describe "DRb.start_service" do
+ before :each do
+ @server = DRb.start_service("druby://localhost:0", TestServer.new)
+ end
- after :each do
- DRb.stop_service if @server
- end
+ after :each do
+ DRb.stop_service if @server
+ end
- it "runs a basic remote call" do
- DRb.current_server.should == @server
- obj = DRbObject.new(nil, @server.uri)
- obj.add(1,2,3).should == 6
- end
+ it "runs a basic remote call" do
+ DRb.current_server.should == @server
+ obj = DRbObject.new(nil, @server.uri)
+ obj.add(1,2,3).should == 6
+ end
- it "runs a basic remote call passing a block" do
- DRb.current_server.should == @server
- obj = DRbObject.new(nil, @server.uri)
- obj.add_yield(2) do |i|
- i.should == 2
- i+1
- end.should == 4
- end
+ it "runs a basic remote call passing a block" do
+ DRb.current_server.should == @server
+ obj = DRbObject.new(nil, @server.uri)
+ obj.add_yield(2) do |i|
+ i.should == 2
+ i+1
+ end.should == 4
end
end
diff --git a/spec/ruby/library/erb/new_spec.rb b/spec/ruby/library/erb/new_spec.rb
index a5aeeaeed1..4d7f7bf36a 100644
--- a/spec/ruby/library/erb/new_spec.rb
+++ b/spec/ruby/library/erb/new_spec.rb
@@ -140,7 +140,7 @@ END
end
describe "warning about arguments" do
- version_is ERB.version, "2.2.1" do #ruby_version_is "3.1" do
+ ruby_version_is "3.1" do
it "warns when passed safe_level and later arguments" do
-> {
ERB.new(@eruby_str, nil, '%')
diff --git a/spec/ruby/library/erb/run_spec.rb b/spec/ruby/library/erb/run_spec.rb
index 602e53ab38..8c07442d8f 100644
--- a/spec/ruby/library/erb/run_spec.rb
+++ b/spec/ruby/library/erb/run_spec.rb
@@ -6,7 +6,7 @@ describe "ERB#run" do
# lambda { ... }.should output
def _steal_stdout
orig = $stdout
- s = +''
+ s = ''
def s.write(arg); self << arg.to_s; end
$stdout = s
begin
diff --git a/spec/ruby/library/etc/confstr_spec.rb b/spec/ruby/library/etc/confstr_spec.rb
index 5b43461150..41a970a918 100644
--- a/spec/ruby/library/etc/confstr_spec.rb
+++ b/spec/ruby/library/etc/confstr_spec.rb
@@ -1,4 +1,4 @@
-require_relative '../../spec_helper'
+require File.expand_path('../../../spec_helper', __FILE__)
require 'etc'
platform_is_not :windows, :android do
diff --git a/spec/ruby/library/etc/passwd_spec.rb b/spec/ruby/library/etc/passwd_spec.rb
index 7157fd3f2e..d61dada451 100644
--- a/spec/ruby/library/etc/passwd_spec.rb
+++ b/spec/ruby/library/etc/passwd_spec.rb
@@ -1,4 +1,4 @@
-require_relative '../../spec_helper'
+require File.expand_path('../../../spec_helper', __FILE__)
require 'etc'
platform_is_not :windows do
diff --git a/spec/ruby/library/etc/sysconf_spec.rb b/spec/ruby/library/etc/sysconf_spec.rb
index 1f2c7a770f..e7d59d1b22 100644
--- a/spec/ruby/library/etc/sysconf_spec.rb
+++ b/spec/ruby/library/etc/sysconf_spec.rb
@@ -1,4 +1,4 @@
-require_relative '../../spec_helper'
+require File.expand_path('../../../spec_helper', __FILE__)
require 'etc'
platform_is_not :windows do
diff --git a/spec/ruby/library/etc/sysconfdir_spec.rb b/spec/ruby/library/etc/sysconfdir_spec.rb
index 8538faa65b..d54299c513 100644
--- a/spec/ruby/library/etc/sysconfdir_spec.rb
+++ b/spec/ruby/library/etc/sysconfdir_spec.rb
@@ -1,4 +1,4 @@
-require_relative '../../spec_helper'
+require File.expand_path('../../../spec_helper', __FILE__)
require 'etc'
describe "Etc.sysconfdir" do
diff --git a/spec/ruby/library/etc/systmpdir_spec.rb b/spec/ruby/library/etc/systmpdir_spec.rb
index 5b007aa9f9..99c82903f8 100644
--- a/spec/ruby/library/etc/systmpdir_spec.rb
+++ b/spec/ruby/library/etc/systmpdir_spec.rb
@@ -1,4 +1,4 @@
-require_relative '../../spec_helper'
+require File.expand_path('../../../spec_helper', __FILE__)
require 'etc'
describe "Etc.systmpdir" do
diff --git a/spec/ruby/library/etc/uname_spec.rb b/spec/ruby/library/etc/uname_spec.rb
deleted file mode 100644
index a42558f593..0000000000
--- a/spec/ruby/library/etc/uname_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require_relative '../../spec_helper'
-require 'etc'
-
-describe "Etc.uname" do
- it "returns a Hash with the documented keys" do
- uname = Etc.uname
- uname.should be_kind_of(Hash)
- uname.should.key?(:sysname)
- uname.should.key?(:nodename)
- uname.should.key?(:release)
- uname.should.key?(:version)
- uname.should.key?(:machine)
- end
-end
diff --git a/spec/ruby/library/expect/expect_spec.rb b/spec/ruby/library/expect/expect_spec.rb
index 76ea3d5451..a7041d42ee 100644
--- a/spec/ruby/library/expect/expect_spec.rb
+++ b/spec/ruby/library/expect/expect_spec.rb
@@ -1,6 +1,5 @@
-require_relative '../../spec_helper'
-
platform_is_not :windows do
+ require_relative '../../spec_helper'
require 'expect'
describe "IO#expect" do
diff --git a/spec/ruby/library/fiber/current_spec.rb b/spec/ruby/library/fiber/current_spec.rb
index 1467a88d0d..e67d7d050a 100644
--- a/spec/ruby/library/fiber/current_spec.rb
+++ b/spec/ruby/library/fiber/current_spec.rb
@@ -3,12 +3,6 @@ require_relative '../../spec_helper'
require 'fiber'
describe "Fiber.current" do
- ruby_version_is "3.1" do
- it "is available without an extra require" do
- ruby_exe("print Fiber.current.class", options: '--disable-gems --disable-did-you-mean').should == "Fiber"
- end
- end
-
it "returns the root Fiber when called outside of a Fiber" do
root = Fiber.current
root.should be_an_instance_of(Fiber)
@@ -48,11 +42,22 @@ describe "Fiber.current" do
fiber3 = Fiber.new do
states << :fiber3
fiber2.transfer
- states << :fiber3_terminated
+ ruby_version_is '3.0' do
+ states << :fiber3_terminated
+ end
+ ruby_version_is '' ... '3.0' do
+ flunk
+ end
end
fiber3.resume
- states.should == [:fiber3, :fiber2, :fiber, :fiber3_terminated]
+ ruby_version_is "" ... "3.0" do
+ states.should == [:fiber3, :fiber2, :fiber]
+ end
+
+ ruby_version_is "3.0" do
+ states.should == [:fiber3, :fiber2, :fiber, :fiber3_terminated]
+ end
end
end
diff --git a/spec/ruby/library/fiber/resume_spec.rb b/spec/ruby/library/fiber/resume_spec.rb
index fd69d3ba99..8b7c104a6f 100644
--- a/spec/ruby/library/fiber/resume_spec.rb
+++ b/spec/ruby/library/fiber/resume_spec.rb
@@ -3,16 +3,33 @@ require_relative '../../spec_helper'
require 'fiber'
describe "Fiber#resume" do
- it "can work with Fiber#transfer" do
- fiber1 = Fiber.new { true }
- fiber2 = Fiber.new { fiber1.transfer; Fiber.yield 10 ; Fiber.yield 20; raise }
- fiber2.resume.should == 10
- fiber2.resume.should == 20
+ ruby_version_is '' ... '3.0' do
+ it "raises a FiberError if the Fiber has transferred control to another Fiber" do
+ fiber1 = Fiber.new { true }
+ fiber2 = Fiber.new { fiber1.transfer; Fiber.yield }
+ fiber2.resume
+ -> { fiber2.resume }.should raise_error(FiberError)
+ end
+
+ it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do
+ root_fiber = Fiber.current
+ fiber1 = Fiber.new { root_fiber.resume }
+ -> { fiber1.resume }.should raise_error(FiberError, /double resume/)
+ end
end
- it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do
- root_fiber = Fiber.current
- fiber1 = Fiber.new { root_fiber.resume }
- -> { fiber1.resume }.should raise_error(FiberError, /attempt to resume a resuming fiber/)
+ ruby_version_is '3.0' do
+ it "can work with Fiber#transfer" do
+ fiber1 = Fiber.new { true }
+ fiber2 = Fiber.new { fiber1.transfer; Fiber.yield 10 ; Fiber.yield 20; raise }
+ fiber2.resume.should == 10
+ fiber2.resume.should == 20
+ end
+
+ it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do
+ root_fiber = Fiber.current
+ fiber1 = Fiber.new { root_fiber.resume }
+ -> { fiber1.resume }.should raise_error(FiberError, /attempt to resume a resuming fiber/)
+ end
end
end
diff --git a/spec/ruby/library/fiber/transfer_spec.rb b/spec/ruby/library/fiber/transfer_spec.rb
index e20d51352e..7af548da1a 100644
--- a/spec/ruby/library/fiber/transfer_spec.rb
+++ b/spec/ruby/library/fiber/transfer_spec.rb
@@ -11,7 +11,13 @@ describe "Fiber#transfer" do
it "transfers control from one Fiber to another when called from a Fiber" do
fiber1 = Fiber.new { :fiber1 }
fiber2 = Fiber.new { fiber1.transfer; :fiber2 }
- fiber2.resume.should == :fiber2
+
+ ruby_version_is '' ... '3.0' do
+ fiber2.resume.should == :fiber1
+ end
+ ruby_version_is '3.0' do
+ fiber2.resume.should == :fiber2
+ end
end
it "returns to the root Fiber when finished" do
@@ -34,12 +40,24 @@ describe "Fiber#transfer" do
states.should == [:start, :end]
end
- it "can not transfer control to a Fiber that has suspended by Fiber.yield" do
- states = []
- fiber1 = Fiber.new { states << :fiber1 }
- fiber2 = Fiber.new { states << :fiber2_start; Fiber.yield fiber1.transfer; states << :fiber2_end}
- fiber2.resume.should == [:fiber2_start, :fiber1]
- -> { fiber2.transfer }.should raise_error(FiberError)
+ ruby_version_is '' ... '3.0' do
+ it "can transfer control to a Fiber that has transferred to another Fiber" do
+ states = []
+ fiber1 = Fiber.new { states << :fiber1 }
+ fiber2 = Fiber.new { states << :fiber2_start; fiber1.transfer; states << :fiber2_end}
+ fiber2.resume.should == [:fiber2_start, :fiber1]
+ fiber2.transfer.should == [:fiber2_start, :fiber1, :fiber2_end]
+ end
+ end
+
+ ruby_version_is '3.0' do
+ it "can not transfer control to a Fiber that has suspended by Fiber.yield" do
+ states = []
+ fiber1 = Fiber.new { states << :fiber1 }
+ fiber2 = Fiber.new { states << :fiber2_start; Fiber.yield fiber1.transfer; states << :fiber2_end}
+ fiber2.resume.should == [:fiber2_start, :fiber1]
+ -> { fiber2.transfer }.should raise_error(FiberError)
+ end
end
it "raises a FiberError when transferring to a Fiber which resumes itself" do
@@ -83,4 +101,28 @@ describe "Fiber#transfer" do
thread.join
states.should == [0, 1, 2, 3]
end
+
+ ruby_version_is "" ... "3.0" do
+ it "runs until Fiber.yield" do
+ obj = mock('obj')
+ obj.should_not_receive(:do)
+ fiber = Fiber.new { 1 + 2; Fiber.yield; obj.do }
+ fiber.transfer
+ end
+
+ it "resumes from the last call to Fiber.yield on subsequent invocations" do
+ fiber = Fiber.new { Fiber.yield :first; :second }
+ fiber.transfer.should == :first
+ fiber.transfer.should == :second
+ end
+
+ it "sets the block parameters to its arguments on the first invocation" do
+ first = mock('first')
+ first.should_receive(:arg).with(:first).twice
+
+ fiber = Fiber.new { |arg| first.arg arg; Fiber.yield; first.arg arg; }
+ fiber.transfer :first
+ fiber.transfer :second
+ end
+ end
end
diff --git a/spec/ruby/library/find/fixtures/common.rb b/spec/ruby/library/find/fixtures/common.rb
index 99f3bbb45a..14a7edb09a 100644
--- a/spec/ruby/library/find/fixtures/common.rb
+++ b/spec/ruby/library/find/fixtures/common.rb
@@ -71,17 +71,13 @@ module FindDirSpecs
end
def self.create_mock_dirs
- tmp('') # make sure there is an tmpdir
umask = File.umask 0
- begin
- mock_dir_files.each do |name|
- file = File.join mock_dir, name
- mkdir_p File.dirname(file)
- touch file
- end
- ensure
- File.umask umask
+ mock_dir_files.each do |name|
+ file = File.join mock_dir, name
+ mkdir_p File.dirname(file)
+ touch file
end
+ File.umask umask
end
def self.delete_mock_dirs
diff --git a/spec/ruby/library/io-wait/wait_readable_spec.rb b/spec/ruby/library/io-wait/wait_readable_spec.rb
index df25fdb931..06ffbda5c8 100644
--- a/spec/ruby/library/io-wait/wait_readable_spec.rb
+++ b/spec/ruby/library/io-wait/wait_readable_spec.rb
@@ -24,23 +24,4 @@ describe "IO#wait_readable" do
it "waits for the IO to become readable with the given large timeout" do
@io.wait_readable(365 * 24 * 60 * 60).should == @io
end
-
- it "can be interrupted" do
- rd, wr = IO.pipe
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
-
- t = Thread.new do
- rd.wait_readable(10)
- end
-
- Thread.pass until t.stop?
- t.kill
- t.join
-
- finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- (finish - start).should < 9
- ensure
- rd.close
- wr.close
- end
end
diff --git a/spec/ruby/library/io-wait/wait_spec.rb b/spec/ruby/library/io-wait/wait_spec.rb
deleted file mode 100644
index 5952f127f7..0000000000
--- a/spec/ruby/library/io-wait/wait_spec.rb
+++ /dev/null
@@ -1,186 +0,0 @@
-require_relative '../../spec_helper'
-require_relative '../../fixtures/io'
-
-ruby_version_is ''...'3.2' do
- require 'io/wait'
-end
-
-describe "IO#wait" do
- before :each do
- @io = File.new(__FILE__ )
-
- if /mswin|mingw/ =~ RUBY_PLATFORM
- require 'socket'
- @r, @w = Socket.pair(Socket::AF_INET, Socket::SOCK_STREAM, 0)
- else
- @r, @w = IO.pipe
- end
- end
-
- after :each do
- @io.close unless @io.closed?
-
- @r.close unless @r.closed?
- @w.close unless @w.closed?
- end
-
- context "[events, timeout] passed" do
- ruby_version_is ""..."3.2" do
- it "returns self when the READABLE event is ready during the timeout" do
- @w.write('data to read')
- @r.wait(IO::READABLE, 2).should.equal?(@r)
- end
-
- it "returns self when the WRITABLE event is ready during the timeout" do
- @w.wait(IO::WRITABLE, 0).should.equal?(@w)
- end
- end
-
- ruby_version_is "3.2" do
- it "returns events mask when the READABLE event is ready during the timeout" do
- @w.write('data to read')
- @r.wait(IO::READABLE, 2).should == IO::READABLE
- end
-
- it "returns events mask when the WRITABLE event is ready during the timeout" do
- @w.wait(IO::WRITABLE, 0).should == IO::WRITABLE
- end
- end
-
- it "waits for the READABLE event to be ready" do
- @r.wait(IO::READABLE, 0).should == nil
-
- @w.write('data to read')
- @r.wait(IO::READABLE, 0).should_not == nil
- end
-
- it "waits for the WRITABLE event to be ready" do
- written_bytes = IOSpec.exhaust_write_buffer(@w)
- @w.wait(IO::WRITABLE, 0).should == nil
-
- @r.read(written_bytes)
- @w.wait(IO::WRITABLE, 0).should_not == nil
- end
-
- it "returns nil when the READABLE event is not ready during the timeout" do
- @w.wait(IO::READABLE, 0).should == nil
- end
-
- it "returns nil when the WRITABLE event is not ready during the timeout" do
- IOSpec.exhaust_write_buffer(@w)
- @w.wait(IO::WRITABLE, 0).should == nil
- end
-
- it "raises IOError when io is closed (closed stream (IOError))" do
- @io.close
- -> { @io.wait(IO::READABLE, 0) }.should raise_error(IOError, "closed stream")
- end
-
- ruby_version_is "3.2" do
- it "raises ArgumentError when events is not positive" do
- -> { @w.wait(0, 0) }.should raise_error(ArgumentError, "Events must be positive integer!")
- -> { @w.wait(-1, 0) }.should raise_error(ArgumentError, "Events must be positive integer!")
- end
- end
-
- it "changes thread status to 'sleep' when waits for READABLE event" do
- t = Thread.new { @r.wait(IO::READABLE, 10) }
- sleep 1
- t.status.should == 'sleep'
- t.kill
- t.join # Thread#kill doesn't wait for the thread to end
- end
-
- it "changes thread status to 'sleep' when waits for WRITABLE event" do
- IOSpec.exhaust_write_buffer(@w)
-
- t = Thread.new { @w.wait(IO::WRITABLE, 10) }
- sleep 1
- t.status.should == 'sleep'
- t.kill
- t.join # Thread#kill doesn't wait for the thread to end
- end
-
- it "can be interrupted when waiting for READABLE event" do
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
-
- t = Thread.new do
- @r.wait(IO::READABLE, 10)
- end
-
- Thread.pass until t.stop?
- t.kill
- t.join # Thread#kill doesn't wait for the thread to end
-
- finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- (finish - start).should < 9
- end
-
- it "can be interrupted when waiting for WRITABLE event" do
- IOSpec.exhaust_write_buffer(@w)
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
-
- t = Thread.new do
- @w.wait(IO::WRITABLE, 10)
- end
-
- Thread.pass until t.stop?
- t.kill
- t.join # Thread#kill doesn't wait for the thread to end
-
- finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- (finish - start).should < 9
- end
- end
-
- context "[timeout, mode] passed" do
- it "accepts :r, :read, :readable mode to check READABLE event" do
- @io.wait(0, :r).should == @io
- @io.wait(0, :read).should == @io
- @io.wait(0, :readable).should == @io
- end
-
- it "accepts :w, :write, :writable mode to check WRITABLE event" do
- @io.wait(0, :w).should == @io
- @io.wait(0, :write).should == @io
- @io.wait(0, :writable).should == @io
- end
-
- it "accepts :rw, :read_write, :readable_writable mode to check READABLE and WRITABLE events" do
- @io.wait(0, :rw).should == @io
- @io.wait(0, :read_write).should == @io
- @io.wait(0, :readable_writable).should == @io
- end
-
- it "accepts a list of modes" do
- @io.wait(0, :r, :w, :rw).should == @io
- end
-
- # It works at least since 2.7 but by some reason may fail on 3.1
- ruby_version_is "3.2" do
- it "accepts timeout and mode in any order" do
- @io.wait(0, :r).should == @io
- @io.wait(:r, 0).should == @io
- @io.wait(:r, 0, :w).should == @io
- end
- end
-
- it "raises ArgumentError when passed wrong Symbol value as mode argument" do
- -> { @io.wait(0, :wrong) }.should raise_error(ArgumentError, "unsupported mode: wrong")
- end
-
- # It works since 3.0 but by some reason may fail on 3.1
- ruby_version_is "3.2" do
- it "raises ArgumentError when several Integer arguments passed" do
- -> { @w.wait(0, 10, :r) }.should raise_error(ArgumentError, "timeout given more than once")
- end
- end
-
- ruby_version_is "3.2" do
- it "raises IOError when io is closed (closed stream (IOError))" do
- @io.close
- -> { @io.wait(0, :r) }.should raise_error(IOError, "closed stream")
- end
- end
- end
-end
diff --git a/spec/ruby/library/io-wait/wait_writable_spec.rb b/spec/ruby/library/io-wait/wait_writable_spec.rb
index 8639dd717b..8c44780d39 100644
--- a/spec/ruby/library/io-wait/wait_writable_spec.rb
+++ b/spec/ruby/library/io-wait/wait_writable_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative '../../fixtures/io'
ruby_version_is ''...'3.2' do
require 'io/wait'
@@ -18,24 +17,4 @@ describe "IO#wait_writable" do
# Represents one year and is larger than a 32-bit int
STDOUT.wait_writable(365 * 24 * 60 * 60).should == STDOUT
end
-
- it "can be interrupted" do
- rd, wr = IO.pipe
- IOSpec.exhaust_write_buffer(wr)
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
-
- t = Thread.new do
- wr.wait_writable(10)
- end
-
- Thread.pass until t.stop?
- t.kill
- t.join
-
- finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- (finish - start).should < 9
- ensure
- rd.close unless rd.closed?
- wr.close unless wr.closed?
- end
end
diff --git a/spec/ruby/library/ipaddr/new_spec.rb b/spec/ruby/library/ipaddr/new_spec.rb
index 714c1e2f1a..053928c3cf 100644
--- a/spec/ruby/library/ipaddr/new_spec.rb
+++ b/spec/ruby/library/ipaddr/new_spec.rb
@@ -77,13 +77,7 @@ describe "IPAddr#new" do
a.family.should == Socket::AF_INET6
end
- ipaddr_version = if defined?(IPAddr::VERSION) #ruby_version_is ""..."3.1" do
- IPAddr::VERSION
- else
- "1.2.2"
- end
-
- version_is ipaddr_version, ""..."1.2.3" do #ruby_version_is ""..."3.1" do
+ ruby_version_is ""..."3.1" do
it "raises on incorrect IPAddr strings" do
[
["fe80::1%fxp0"],
@@ -99,7 +93,7 @@ describe "IPAddr#new" do
end
end
- version_is ipaddr_version, "1.2.3" do #ruby_version_is "3.1" do
+ ruby_version_is "3.1" do
it "raises on incorrect IPAddr strings" do
[
["::1/255.255.255.0"],
diff --git a/spec/ruby/library/logger/device/close_spec.rb b/spec/ruby/library/logger/device/close_spec.rb
index 1db5d582a7..7c5e118d56 100644
--- a/spec/ruby/library/logger/device/close_spec.rb
+++ b/spec/ruby/library/logger/device/close_spec.rb
@@ -15,8 +15,17 @@ describe "Logger::LogDevice#close" do
rm_r @file_path
end
- it "closes the LogDevice's stream" do
- @device.close
- -> { @device.write("Test") }.should complain(/\Alog shifting failed\./)
+ version_is Logger::VERSION, ""..."1.4.0" do
+ it "closes the LogDevice's stream" do
+ @device.close
+ -> { @device.write("Test") }.should complain(/\Alog writing failed\./)
+ end
+ end
+
+ version_is Logger::VERSION, "1.4.0" do
+ it "closes the LogDevice's stream" do
+ @device.close
+ -> { @device.write("Test") }.should complain(/\Alog shifting failed\./)
+ end
end
end
diff --git a/spec/ruby/library/logger/device/write_spec.rb b/spec/ruby/library/logger/device/write_spec.rb
index 87ecf2ad6a..cd2d7e27a9 100644
--- a/spec/ruby/library/logger/device/write_spec.rb
+++ b/spec/ruby/library/logger/device/write_spec.rb
@@ -35,8 +35,17 @@ describe "Logger::LogDevice#write" do
rm_r path
end
- it "fails if the device is already closed" do
- @device.close
- -> { @device.write "foo" }.should complain(/\Alog shifting failed\./)
+ version_is Logger::VERSION, ""..."1.4.0" do
+ it "fails if the device is already closed" do
+ @device.close
+ -> { @device.write "foo" }.should complain(/\Alog writing failed\./)
+ end
+ end
+
+ version_is Logger::VERSION, "1.4.0" do
+ it "fails if the device is already closed" do
+ @device.close
+ -> { @device.write "foo" }.should complain(/\Alog shifting failed\./)
+ end
end
end
diff --git a/spec/ruby/library/matrix/I_spec.rb b/spec/ruby/library/matrix/I_spec.rb
index 6eeffe8e98..aa064ed54b 100644
--- a/spec/ruby/library/matrix/I_spec.rb
+++ b/spec/ruby/library/matrix/I_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/identity'
-describe "Matrix.I" do
- it_behaves_like :matrix_identity, :I
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/identity'
+
+ describe "Matrix.I" do
+ it_behaves_like :matrix_identity, :I
+ end
end
diff --git a/spec/ruby/library/matrix/antisymmetric_spec.rb b/spec/ruby/library/matrix/antisymmetric_spec.rb
index 200df703cb..dcc3c30f3e 100644
--- a/spec/ruby/library/matrix/antisymmetric_spec.rb
+++ b/spec/ruby/library/matrix/antisymmetric_spec.rb
@@ -1,36 +1,38 @@
require_relative '../../spec_helper'
-require 'matrix'
+ruby_version_is ""..."3.1" do
+ require 'matrix'
-describe "Matrix#antisymmetric?" do
- it "returns true for an antisymmetric Matrix" do
- Matrix[[0, -2, Complex(1, 3)], [2, 0, 5], [-Complex(1, 3), -5, 0]].antisymmetric?.should be_true
- end
+ describe "Matrix#antisymmetric?" do
+ it "returns true for an antisymmetric Matrix" do
+ Matrix[[0, -2, Complex(1, 3)], [2, 0, 5], [-Complex(1, 3), -5, 0]].antisymmetric?.should be_true
+ end
- it "returns true for a 0x0 empty matrix" do
- Matrix.empty.antisymmetric?.should be_true
- end
+ it "returns true for a 0x0 empty matrix" do
+ Matrix.empty.antisymmetric?.should be_true
+ end
- it "returns false for non-antisymmetric matrices" do
- [
- Matrix[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
- Matrix[[1, -2, 3], [2, 0, 6], [-3, -6, 0]], # wrong diagonal element
- Matrix[[0, 2, -3], [2, 0, 6], [-3, 6, 0]] # only signs wrong
- ].each do |matrix|
- matrix.antisymmetric?.should be_false
+ it "returns false for non-antisymmetric matrices" do
+ [
+ Matrix[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
+ Matrix[[1, -2, 3], [2, 0, 6], [-3, -6, 0]], # wrong diagonal element
+ Matrix[[0, 2, -3], [2, 0, 6], [-3, 6, 0]] # only signs wrong
+ ].each do |matrix|
+ matrix.antisymmetric?.should be_false
+ end
end
- end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.antisymmetric?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.antisymmetric?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/build_spec.rb b/spec/ruby/library/matrix/build_spec.rb
index 6d8017a3df..d3055a1aa7 100644
--- a/spec/ruby/library/matrix/build_spec.rb
+++ b/spec/ruby/library/matrix/build_spec.rb
@@ -1,73 +1,76 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix.build" do
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "returns a Matrix object of the given size" do
- m = Matrix.build(3, 4){1}
- m.should be_an_instance_of(Matrix)
- m.row_size.should == 3
- m.column_size.should == 4
- end
+ describe "Matrix.build" do
- it "builds the Matrix using the given block" do
- Matrix.build(2, 3){|col, row| 10*col - row}.should ==
- Matrix[[0, -1, -2], [10, 9, 8]]
- end
+ it "returns a Matrix object of the given size" do
+ m = Matrix.build(3, 4){1}
+ m.should be_an_instance_of(Matrix)
+ m.row_size.should == 3
+ m.column_size.should == 4
+ end
- it "iterates through the first row, then the second, ..." do
- acc = []
- Matrix.build(2, 3){|*args| acc << args}
- acc.should == [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]
- end
+ it "builds the Matrix using the given block" do
+ Matrix.build(2, 3){|col, row| 10*col - row}.should ==
+ Matrix[[0, -1, -2], [10, 9, 8]]
+ end
- it "returns an Enumerator is no block is given" do
- enum = Matrix.build(2, 1)
- enum.should be_an_instance_of(Enumerator)
- enum.each{1}.should == Matrix[[1], [1]]
- end
+ it "iterates through the first row, then the second, ..." do
+ acc = []
+ Matrix.build(2, 3){|*args| acc << args}
+ acc.should == [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]
+ end
- it "requires integers as parameters" do
- -> { Matrix.build("1", "2"){1} }.should raise_error(TypeError)
- -> { Matrix.build(nil, nil){1} }.should raise_error(TypeError)
- -> { Matrix.build(1..2){1} }.should raise_error(TypeError)
- end
+ it "returns an Enumerator is no block is given" do
+ enum = Matrix.build(2, 1)
+ enum.should be_an_instance_of(Enumerator)
+ enum.each{1}.should == Matrix[[1], [1]]
+ end
- it "requires non-negative integers" do
- -> { Matrix.build(-1, 1){1} }.should raise_error(ArgumentError)
- -> { Matrix.build(+1,-1){1} }.should raise_error(ArgumentError)
- end
+ it "requires integers as parameters" do
+ -> { Matrix.build("1", "2"){1} }.should raise_error(TypeError)
+ -> { Matrix.build(nil, nil){1} }.should raise_error(TypeError)
+ -> { Matrix.build(1..2){1} }.should raise_error(TypeError)
+ end
- it "returns empty Matrix if one argument is zero" do
- m = Matrix.build(0, 3){
- raise "Should not yield"
- }
- m.should be_empty
- m.column_size.should == 3
+ it "requires non-negative integers" do
+ -> { Matrix.build(-1, 1){1} }.should raise_error(ArgumentError)
+ -> { Matrix.build(+1,-1){1} }.should raise_error(ArgumentError)
+ end
- m = Matrix.build(3, 0){
- raise "Should not yield"
- }
- m.should be_empty
- m.row_size.should == 3
- end
+ it "returns empty Matrix if one argument is zero" do
+ m = Matrix.build(0, 3){
+ raise "Should not yield"
+ }
+ m.should be_empty
+ m.column_size.should == 3
- it "tries to calls :to_int on arguments" do
- int = mock('int')
- int.should_receive(:to_int).twice.and_return(2)
- Matrix.build(int, int){ 1 }.should == Matrix[ [1,1], [1,1] ]
- end
+ m = Matrix.build(3, 0){
+ raise "Should not yield"
+ }
+ m.should be_empty
+ m.row_size.should == 3
+ end
- it "builds an nxn Matrix when given only one argument" do
- m = Matrix.build(3){1}
- m.row_size.should == 3
- m.column_size.should == 3
+ it "tries to calls :to_int on arguments" do
+ int = mock('int')
+ int.should_receive(:to_int).twice.and_return(2)
+ Matrix.build(int, int){ 1 }.should == Matrix[ [1,1], [1,1] ]
+ end
+
+ it "builds an nxn Matrix when given only one argument" do
+ m = Matrix.build(3){1}
+ m.row_size.should == 3
+ m.column_size.should == 3
+ end
end
-end
-describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.build(3){1}.should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.build(3){1}.should be_an_instance_of(MatrixSub)
+ end
end
end
diff --git a/spec/ruby/library/matrix/clone_spec.rb b/spec/ruby/library/matrix/clone_spec.rb
index 74e5bf157e..bde119988f 100644
--- a/spec/ruby/library/matrix/clone_spec.rb
+++ b/spec/ruby/library/matrix/clone_spec.rb
@@ -1,25 +1,28 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix#clone" do
- before :each do
- @a = Matrix[[1, 2], [3, 4], [5, 6]]
- end
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "returns a shallow copy of the matrix" do
- b = @a.clone
- @a.should_not equal(b)
- b.should be_kind_of(Matrix)
- b.should == @a
- 0.upto(@a.row_size - 1) do |i|
- @a.row(i).should_not equal(b.row(i))
+ describe "Matrix#clone" do
+ before :each do
+ @a = Matrix[[1, 2], [3, 4], [5, 6]]
+ end
+
+ it "returns a shallow copy of the matrix" do
+ b = @a.clone
+ @a.should_not equal(b)
+ b.should be_kind_of(Matrix)
+ b.should == @a
+ 0.upto(@a.row_size - 1) do |i|
+ @a.row(i).should_not equal(b.row(i))
+ end
end
- end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.ins.clone.should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.ins.clone.should be_an_instance_of(MatrixSub)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/coerce_spec.rb b/spec/ruby/library/matrix/coerce_spec.rb
index 4022f00236..aa3a32765a 100644
--- a/spec/ruby/library/matrix/coerce_spec.rb
+++ b/spec/ruby/library/matrix/coerce_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#coerce" do
- it "allows the division of integer by a Matrix " do
- (1/Matrix[[0,1],[-1,0]]).should == Matrix[[0,-1],[1,0]]
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix#coerce" do
+ it "allows the division of integer by a Matrix " do
+ (1/Matrix[[0,1],[-1,0]]).should == Matrix[[0,-1],[1,0]]
+ end
end
end
diff --git a/spec/ruby/library/matrix/collect_spec.rb b/spec/ruby/library/matrix/collect_spec.rb
index bba640213b..66ec3486c8 100644
--- a/spec/ruby/library/matrix/collect_spec.rb
+++ b/spec/ruby/library/matrix/collect_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/collect'
-describe "Matrix#collect" do
- it_behaves_like :collect, :collect
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/collect'
+
+ describe "Matrix#collect" do
+ it_behaves_like :collect, :collect
+ end
end
diff --git a/spec/ruby/library/matrix/column_size_spec.rb b/spec/ruby/library/matrix/column_size_spec.rb
index 041914e5b9..e7b42b101e 100644
--- a/spec/ruby/library/matrix/column_size_spec.rb
+++ b/spec/ruby/library/matrix/column_size_spec.rb
@@ -1,13 +1,16 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#column_size" do
- it "returns the number of columns" do
- Matrix[ [1,2], [3,4] ].column_size.should == 2
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix#column_size" do
+ it "returns the number of columns" do
+ Matrix[ [1,2], [3,4] ].column_size.should == 2
+ end
- it "returns 0 for empty matrices" do
- Matrix[ [], [] ].column_size.should == 0
- Matrix[ ].column_size.should == 0
+ it "returns 0 for empty matrices" do
+ Matrix[ [], [] ].column_size.should == 0
+ Matrix[ ].column_size.should == 0
+ end
end
end
diff --git a/spec/ruby/library/matrix/column_spec.rb b/spec/ruby/library/matrix/column_spec.rb
index 1f3c80964a..98a767ad08 100644
--- a/spec/ruby/library/matrix/column_spec.rb
+++ b/spec/ruby/library/matrix/column_spec.rb
@@ -1,35 +1,38 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#column" do
- before :all do
- @m = Matrix[[1,2,3], [2,3,4]]
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns a Vector when called without a block" do
- @m.column(1).should == Vector[2,3]
- end
+ describe "Matrix#column" do
+ before :all do
+ @m = Matrix[[1,2,3], [2,3,4]]
+ end
- it "yields each element in the column to the block" do
- a = []
- @m.column(1) {|n| a << n }
- a.should == [2,3]
- end
+ it "returns a Vector when called without a block" do
+ @m.column(1).should == Vector[2,3]
+ end
- it "counts backwards for negative argument" do
- @m.column(-1).should == Vector[3, 4]
- end
+ it "yields each element in the column to the block" do
+ a = []
+ @m.column(1) {|n| a << n }
+ a.should == [2,3]
+ end
- it "returns self when called with a block" do
- @m.column(0) { |x| x }.should equal(@m)
- end
+ it "counts backwards for negative argument" do
+ @m.column(-1).should == Vector[3, 4]
+ end
- it "returns nil when out of bounds" do
- @m.column(3).should == nil
- end
+ it "returns self when called with a block" do
+ @m.column(0) { |x| x }.should equal(@m)
+ end
+
+ it "returns nil when out of bounds" do
+ @m.column(3).should == nil
+ end
- it "never yields when out of bounds" do
- -> { @m.column(3){ raise } }.should_not raise_error
- -> { @m.column(-4){ raise } }.should_not raise_error
+ it "never yields when out of bounds" do
+ -> { @m.column(3){ raise } }.should_not raise_error
+ -> { @m.column(-4){ raise } }.should_not raise_error
+ end
end
end
diff --git a/spec/ruby/library/matrix/column_vector_spec.rb b/spec/ruby/library/matrix/column_vector_spec.rb
index 47e866a8d5..afdeaced47 100644
--- a/spec/ruby/library/matrix/column_vector_spec.rb
+++ b/spec/ruby/library/matrix/column_vector_spec.rb
@@ -1,25 +1,28 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix.column_vector" do
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "returns a single column Matrix when called with an Array" do
- m = Matrix.column_vector([4,5,6])
- m.should be_an_instance_of(Matrix)
- m.should == Matrix[ [4],[5],[6] ]
- end
+ describe "Matrix.column_vector" do
- it "returns an empty Matrix when called with an empty Array" do
- m = Matrix.column_vector([])
- m.should be_an_instance_of(Matrix)
- m.row_size.should == 0
- m.column_size.should == 1
- end
+ it "returns a single column Matrix when called with an Array" do
+ m = Matrix.column_vector([4,5,6])
+ m.should be_an_instance_of(Matrix)
+ m.should == Matrix[ [4],[5],[6] ]
+ end
+
+ it "returns an empty Matrix when called with an empty Array" do
+ m = Matrix.column_vector([])
+ m.should be_an_instance_of(Matrix)
+ m.row_size.should == 0
+ m.column_size.should == 1
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.column_vector([4,5,6]).should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.column_vector([4,5,6]).should be_an_instance_of(MatrixSub)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/column_vectors_spec.rb b/spec/ruby/library/matrix/column_vectors_spec.rb
index b0cb6f914c..7bec095b9a 100644
--- a/spec/ruby/library/matrix/column_vectors_spec.rb
+++ b/spec/ruby/library/matrix/column_vectors_spec.rb
@@ -1,26 +1,29 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#column_vectors" do
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- before :each do
- @vectors = Matrix[ [1,2], [3,4] ].column_vectors
- end
+ describe "Matrix#column_vectors" do
- it "returns an Array" do
- Matrix[ [1,2], [3,4] ].column_vectors.should be_an_instance_of(Array)
- end
+ before :each do
+ @vectors = Matrix[ [1,2], [3,4] ].column_vectors
+ end
- it "returns an Array of Vectors" do
- @vectors.all? {|v| v.should be_an_instance_of(Vector)}
- end
+ it "returns an Array" do
+ Matrix[ [1,2], [3,4] ].column_vectors.should be_an_instance_of(Array)
+ end
- it "returns each column as a Vector" do
- @vectors.should == [Vector[1,3], Vector[2,4]]
- end
+ it "returns an Array of Vectors" do
+ @vectors.all? {|v| v.should be_an_instance_of(Vector)}
+ end
- it "returns an empty Array for empty matrices" do
- Matrix[ [] ].column_vectors.should == []
- end
+ it "returns each column as a Vector" do
+ @vectors.should == [Vector[1,3], Vector[2,4]]
+ end
+
+ it "returns an empty Array for empty matrices" do
+ Matrix[ [] ].column_vectors.should == []
+ end
+ end
end
diff --git a/spec/ruby/library/matrix/columns_spec.rb b/spec/ruby/library/matrix/columns_spec.rb
index 3095fdd7af..757086c14b 100644
--- a/spec/ruby/library/matrix/columns_spec.rb
+++ b/spec/ruby/library/matrix/columns_spec.rb
@@ -1,42 +1,45 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix.columns" do
- before :each do
- @a = [1, 2]
- @b = [3, 4]
- @m = Matrix.columns([@a, @b])
- end
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "creates a Matrix from argument columns" do
- @m.should be_an_instance_of(Matrix)
- @m.column(0).to_a.should == @a
- @m.column(1).to_a.should == @b
- end
+ describe "Matrix.columns" do
+ before :each do
+ @a = [1, 2]
+ @b = [3, 4]
+ @m = Matrix.columns([@a, @b])
+ end
- it "accepts Vectors as argument columns" do
- m = Matrix.columns([Vector[*@a], Vector[*@b]])
- m.should == @m
- m.column(0).to_a.should == @a
- m.column(1).to_a.should == @b
- end
+ it "creates a Matrix from argument columns" do
+ @m.should be_an_instance_of(Matrix)
+ @m.column(0).to_a.should == @a
+ @m.column(1).to_a.should == @b
+ end
- it "handles empty matrices" do
- e = Matrix.columns([])
- e.row_size.should == 0
- e.column_size.should == 0
- e.should == Matrix[]
+ it "accepts Vectors as argument columns" do
+ m = Matrix.columns([Vector[*@a], Vector[*@b]])
+ m.should == @m
+ m.column(0).to_a.should == @a
+ m.column(1).to_a.should == @b
+ end
- v = Matrix.columns([[],[],[]])
- v.row_size.should == 0
- v.column_size.should == 3
- v.should == Matrix[[], [], []].transpose
- end
+ it "handles empty matrices" do
+ e = Matrix.columns([])
+ e.row_size.should == 0
+ e.column_size.should == 0
+ e.should == Matrix[]
+
+ v = Matrix.columns([[],[],[]])
+ v.row_size.should == 0
+ v.column_size.should == 3
+ v.should == Matrix[[], [], []].transpose
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.columns([[1]]).should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.columns([[1]]).should be_an_instance_of(MatrixSub)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/conj_spec.rb b/spec/ruby/library/matrix/conj_spec.rb
index ecee95c255..a922580399 100644
--- a/spec/ruby/library/matrix/conj_spec.rb
+++ b/spec/ruby/library/matrix/conj_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/conjugate'
-describe "Matrix#conj" do
- it_behaves_like :matrix_conjugate, :conj
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/conjugate'
+
+ describe "Matrix#conj" do
+ it_behaves_like :matrix_conjugate, :conj
+ end
end
diff --git a/spec/ruby/library/matrix/conjugate_spec.rb b/spec/ruby/library/matrix/conjugate_spec.rb
index 682bd41d94..b99792a24b 100644
--- a/spec/ruby/library/matrix/conjugate_spec.rb
+++ b/spec/ruby/library/matrix/conjugate_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/conjugate'
-describe "Matrix#conjugate" do
- it_behaves_like :matrix_conjugate, :conjugate
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/conjugate'
+
+ describe "Matrix#conjugate" do
+ it_behaves_like :matrix_conjugate, :conjugate
+ end
end
diff --git a/spec/ruby/library/matrix/constructor_spec.rb b/spec/ruby/library/matrix/constructor_spec.rb
index 70d77babbb..d8224b4430 100644
--- a/spec/ruby/library/matrix/constructor_spec.rb
+++ b/spec/ruby/library/matrix/constructor_spec.rb
@@ -1,65 +1,68 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix.[]" do
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "requires arrays as parameters" do
- -> { Matrix[5] }.should raise_error(TypeError)
- -> { Matrix[nil] }.should raise_error(TypeError)
- -> { Matrix[1..2] }.should raise_error(TypeError)
- -> { Matrix[[1, 2], 3] }.should raise_error(TypeError)
- end
+ describe "Matrix.[]" do
- it "creates an empty Matrix with no arguments" do
- m = Matrix[]
- m.column_size.should == 0
- m.row_size.should == 0
- end
+ it "requires arrays as parameters" do
+ -> { Matrix[5] }.should raise_error(TypeError)
+ -> { Matrix[nil] }.should raise_error(TypeError)
+ -> { Matrix[1..2] }.should raise_error(TypeError)
+ -> { Matrix[[1, 2], 3] }.should raise_error(TypeError)
+ end
- it "raises for non-rectangular matrices" do
- ->{ Matrix[ [0], [0,1] ] }.should \
- raise_error(Matrix::ErrDimensionMismatch)
- ->{ Matrix[ [0,1], [0,1,2], [0,1] ]}.should \
- raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "creates an empty Matrix with no arguments" do
+ m = Matrix[]
+ m.column_size.should == 0
+ m.row_size.should == 0
+ end
- it "accepts vector arguments" do
- a = Matrix[Vector[1, 2], Vector[3, 4]]
- a.should be_an_instance_of(Matrix)
- a.should == Matrix[ [1, 2], [3, 4] ]
- end
+ it "raises for non-rectangular matrices" do
+ ->{ Matrix[ [0], [0,1] ] }.should \
+ raise_error(Matrix::ErrDimensionMismatch)
+ ->{ Matrix[ [0,1], [0,1,2], [0,1] ]}.should \
+ raise_error(Matrix::ErrDimensionMismatch)
+ end
- it "tries to calls :to_ary on arguments" do
- array = mock('ary')
- array.should_receive(:to_ary).and_return([1,2])
- Matrix[array, [3,4] ].should == Matrix[ [1,2], [3,4] ]
- end
+ it "accepts vector arguments" do
+ a = Matrix[Vector[1, 2], Vector[3, 4]]
+ a.should be_an_instance_of(Matrix)
+ a.should == Matrix[ [1, 2], [3, 4] ]
+ end
+ it "tries to calls :to_ary on arguments" do
+ array = mock('ary')
+ array.should_receive(:to_ary).and_return([1,2])
+ Matrix[array, [3,4] ].should == Matrix[ [1,2], [3,4] ]
+ end
- it "returns a Matrix object" do
- Matrix[ [1] ].should be_an_instance_of(Matrix)
- end
- it "can create an nxn Matrix" do
- m = Matrix[ [20,30], [40.5, 9] ]
- m.row_size.should == 2
- m.column_size.should == 2
- m.column(0).should == Vector[20, 40.5]
- m.column(1).should == Vector[30, 9]
- m.row(0).should == Vector[20, 30]
- m.row(1).should == Vector[40.5, 9]
- end
+ it "returns a Matrix object" do
+ Matrix[ [1] ].should be_an_instance_of(Matrix)
+ end
- it "can create a 0xn Matrix" do
- m = Matrix[ [], [], [] ]
- m.row_size.should == 3
- m.column_size.should == 0
- end
+ it "can create an nxn Matrix" do
+ m = Matrix[ [20,30], [40.5, 9] ]
+ m.row_size.should == 2
+ m.column_size.should == 2
+ m.column(0).should == Vector[20, 40.5]
+ m.column(1).should == Vector[30, 9]
+ m.row(0).should == Vector[20, 30]
+ m.row(1).should == Vector[40.5, 9]
+ end
+
+ it "can create a 0xn Matrix" do
+ m = Matrix[ [], [], [] ]
+ m.row_size.should == 3
+ m.column_size.should == 0
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub[ [20,30], [40.5, 9] ].should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub[ [20,30], [40.5, 9] ].should be_an_instance_of(MatrixSub)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/det_spec.rb b/spec/ruby/library/matrix/det_spec.rb
index aa7086cacf..7d3d547735 100644
--- a/spec/ruby/library/matrix/det_spec.rb
+++ b/spec/ruby/library/matrix/det_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'shared/determinant'
-require 'matrix'
-describe "Matrix#det" do
- it_behaves_like :determinant, :det
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/determinant'
+ require 'matrix'
+
+ describe "Matrix#det" do
+ it_behaves_like :determinant, :det
+ end
end
diff --git a/spec/ruby/library/matrix/determinant_spec.rb b/spec/ruby/library/matrix/determinant_spec.rb
index 825c9907b1..bfd91fcf68 100644
--- a/spec/ruby/library/matrix/determinant_spec.rb
+++ b/spec/ruby/library/matrix/determinant_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'shared/determinant'
-require 'matrix'
-describe "Matrix#determinant" do
- it_behaves_like :determinant, :determinant
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/determinant'
+ require 'matrix'
+
+ describe "Matrix#determinant" do
+ it_behaves_like :determinant, :determinant
+ end
end
diff --git a/spec/ruby/library/matrix/diagonal_spec.rb b/spec/ruby/library/matrix/diagonal_spec.rb
index ef9738e73e..8c82433fde 100644
--- a/spec/ruby/library/matrix/diagonal_spec.rb
+++ b/spec/ruby/library/matrix/diagonal_spec.rb
@@ -1,72 +1,75 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix.diagonal" do
- before :each do
- @m = Matrix.diagonal(10, 11, 12, 13, 14)
- end
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "returns an object of type Matrix" do
- @m.should be_kind_of(Matrix)
- end
+ describe "Matrix.diagonal" do
+ before :each do
+ @m = Matrix.diagonal(10, 11, 12, 13, 14)
+ end
- it "returns a square Matrix of the right size" do
- @m.column_size.should == 5
- @m.row_size.should == 5
- end
+ it "returns an object of type Matrix" do
+ @m.should be_kind_of(Matrix)
+ end
- it "sets the diagonal to the arguments" do
- (0..4).each do |i|
- @m[i, i].should == i + 10
+ it "returns a square Matrix of the right size" do
+ @m.column_size.should == 5
+ @m.row_size.should == 5
end
- end
- it "fills all non-diagonal cells with 0" do
- (0..4).each do |i|
- (0..4).each do |j|
- if i != j
- @m[i, j].should == 0
+ it "sets the diagonal to the arguments" do
+ (0..4).each do |i|
+ @m[i, i].should == i + 10
+ end
+ end
+
+ it "fills all non-diagonal cells with 0" do
+ (0..4).each do |i|
+ (0..4).each do |j|
+ if i != j
+ @m[i, j].should == 0
+ end
end
end
end
- end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.diagonal(1).should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.diagonal(1).should be_an_instance_of(MatrixSub)
+ end
end
end
-end
-describe "Matrix.diagonal?" do
- it "returns true for a diagonal Matrix" do
- Matrix.diagonal([1, 2, 3]).diagonal?.should be_true
- end
+ describe "Matrix.diagonal?" do
+ it "returns true for a diagonal Matrix" do
+ Matrix.diagonal([1, 2, 3]).diagonal?.should be_true
+ end
- it "returns true for a zero square Matrix" do
- Matrix.zero(3).diagonal?.should be_true
- end
+ it "returns true for a zero square Matrix" do
+ Matrix.zero(3).diagonal?.should be_true
+ end
- it "returns false for a non diagonal square Matrix" do
- Matrix[[0, 1], [0, 0]].diagonal?.should be_false
- Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].diagonal?.should be_false
- end
+ it "returns false for a non diagonal square Matrix" do
+ Matrix[[0, 1], [0, 0]].diagonal?.should be_false
+ Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].diagonal?.should be_false
+ end
- it "returns true for an empty 0x0 matrix" do
- Matrix.empty(0,0).diagonal?.should be_true
- end
+ it "returns true for an empty 0x0 matrix" do
+ Matrix.empty(0,0).diagonal?.should be_true
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.diagonal?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.diagonal?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/divide_spec.rb b/spec/ruby/library/matrix/divide_spec.rb
index 2e3bb85bf6..68e6f1fde5 100644
--- a/spec/ruby/library/matrix/divide_spec.rb
+++ b/spec/ruby/library/matrix/divide_spec.rb
@@ -1,54 +1,57 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-
-describe "Matrix#/" do
- before :each do
- @a = Matrix[ [1, 2], [3, 4] ]
- @b = Matrix[ [4, 5], [6, 7] ]
- @c = Matrix[ [1.2, 2.4], [3.6, 4.8] ]
- end
- it "returns the result of dividing self by another Matrix" do
- (@a / @b).should be_close_to_matrix([[2.5, -1.5], [1.5, -0.5]])
- end
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/classes'
+ require 'matrix'
- # Guard against the Mathn library
- guard -> { !defined?(Math.rsqrt) } do
- it "returns the result of dividing self by a Fixnum" do
- (@a / 2).should == Matrix[ [0, 1], [1, 2] ]
+ describe "Matrix#/" do
+ before :each do
+ @a = Matrix[ [1, 2], [3, 4] ]
+ @b = Matrix[ [4, 5], [6, 7] ]
+ @c = Matrix[ [1.2, 2.4], [3.6, 4.8] ]
end
- it "returns the result of dividing self by a Bignum" do
- (@a / bignum_value).should == Matrix[ [0, 0], [0, 0] ]
+ it "returns the result of dividing self by another Matrix" do
+ (@a / @b).should be_close_to_matrix([[2.5, -1.5], [1.5, -0.5]])
end
- end
- it "returns the result of dividing self by a Float" do
- (@c / 1.2).should == Matrix[ [1, 2], [3, 4] ]
- end
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ it "returns the result of dividing self by a Fixnum" do
+ (@a / 2).should == Matrix[ [0, 1], [1, 2] ]
+ end
- it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a / Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "returns the result of dividing self by a Bignum" do
+ (@a / bignum_value).should == Matrix[ [0, 0], [0, 0] ]
+ end
+ end
- it "returns an instance of Matrix" do
- (@a / @b).should be_kind_of(Matrix)
- end
+ it "returns the result of dividing self by a Float" do
+ (@c / 1.2).should == Matrix[ [1, 2], [3, 4] ]
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- m = MatrixSub.ins
- (m/m).should be_an_instance_of(MatrixSub)
- (m/1).should be_an_instance_of(MatrixSub)
+ it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
+ -> { @a / Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
+
+ it "returns an instance of Matrix" do
+ (@a / @b).should be_kind_of(Matrix)
end
- end
- it "raises a TypeError if other is of wrong type" do
- -> { @a / nil }.should raise_error(TypeError)
- -> { @a / "a" }.should raise_error(TypeError)
- -> { @a / [ [1, 2] ] }.should raise_error(TypeError)
- -> { @a / Object.new }.should raise_error(TypeError)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ m = MatrixSub.ins
+ (m/m).should be_an_instance_of(MatrixSub)
+ (m/1).should be_an_instance_of(MatrixSub)
+ end
+ end
+
+ it "raises a TypeError if other is of wrong type" do
+ -> { @a / nil }.should raise_error(TypeError)
+ -> { @a / "a" }.should raise_error(TypeError)
+ -> { @a / [ [1, 2] ] }.should raise_error(TypeError)
+ -> { @a / Object.new }.should raise_error(TypeError)
+ end
end
end
diff --git a/spec/ruby/library/matrix/each_spec.rb b/spec/ruby/library/matrix/each_spec.rb
index f3b0f01867..d2b13c80b6 100644
--- a/spec/ruby/library/matrix/each_spec.rb
+++ b/spec/ruby/library/matrix/each_spec.rb
@@ -1,74 +1,77 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#each" do
- before :all do
- @m = Matrix[ [1, 2, 3], [4, 5, 6] ]
- @result = (1..6).to_a
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns an Enumerator when called without a block" do
- enum = @m.each
- enum.should be_an_instance_of(Enumerator)
- enum.to_a.should == @result
- end
+ describe "Matrix#each" do
+ before :all do
+ @m = Matrix[ [1, 2, 3], [4, 5, 6] ]
+ @result = (1..6).to_a
+ end
- it "returns self" do
- @m.each{}.should equal(@m)
- end
+ it "returns an Enumerator when called without a block" do
+ enum = @m.each
+ enum.should be_an_instance_of(Enumerator)
+ enum.to_a.should == @result
+ end
- it "yields the elements starting with the those of the first row" do
- a = []
- @m.each {|x| a << x}
- a.should == @result
- end
-end
+ it "returns self" do
+ @m.each{}.should equal(@m)
+ end
-describe "Matrix#each with an argument" do
- before :all do
- @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ]
- @t = Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ]
+ it "yields the elements starting with the those of the first row" do
+ a = []
+ @m.each {|x| a << x}
+ a.should == @result
+ end
end
- it "raises an ArgumentError for unrecognized argument" do
- -> {
- @m.each("all"){}
- }.should raise_error(ArgumentError)
- -> {
- @m.each(nil){}
- }.should raise_error(ArgumentError)
- -> {
- @m.each(:left){}
- }.should raise_error(ArgumentError)
- end
+ describe "Matrix#each with an argument" do
+ before :all do
+ @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ]
+ @t = Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ]
+ end
- it "yields the rights elements when passed :diagonal" do
- @m.each(:diagonal).to_a.should == [1, 6]
- @t.each(:diagonal).to_a.should == [1, 4]
- end
+ it "raises an ArgumentError for unrecognized argument" do
+ -> {
+ @m.each("all"){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.each(nil){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.each(:left){}
+ }.should raise_error(ArgumentError)
+ end
- it "yields the rights elements when passed :off_diagonal" do
- @m.each(:off_diagonal).to_a.should == [2, 3, 4, 5, 7, 8]
- @t.each(:off_diagonal).to_a.should == [2, 3, 5, 6, 7, 8]
- end
+ it "yields the rights elements when passed :diagonal" do
+ @m.each(:diagonal).to_a.should == [1, 6]
+ @t.each(:diagonal).to_a.should == [1, 4]
+ end
- it "yields the rights elements when passed :lower" do
- @m.each(:lower).to_a.should == [1, 5, 6]
- @t.each(:lower).to_a.should == [1, 3, 4, 5, 6, 7, 8]
- end
+ it "yields the rights elements when passed :off_diagonal" do
+ @m.each(:off_diagonal).to_a.should == [2, 3, 4, 5, 7, 8]
+ @t.each(:off_diagonal).to_a.should == [2, 3, 5, 6, 7, 8]
+ end
- it "yields the rights elements when passed :strict_lower" do
- @m.each(:strict_lower).to_a.should == [5]
- @t.each(:strict_lower).to_a.should == [3, 5, 6, 7, 8]
- end
+ it "yields the rights elements when passed :lower" do
+ @m.each(:lower).to_a.should == [1, 5, 6]
+ @t.each(:lower).to_a.should == [1, 3, 4, 5, 6, 7, 8]
+ end
- it "yields the rights elements when passed :strict_upper" do
- @m.each(:strict_upper).to_a.should == [2, 3, 4, 7, 8]
- @t.each(:strict_upper).to_a.should == [2]
- end
+ it "yields the rights elements when passed :strict_lower" do
+ @m.each(:strict_lower).to_a.should == [5]
+ @t.each(:strict_lower).to_a.should == [3, 5, 6, 7, 8]
+ end
+
+ it "yields the rights elements when passed :strict_upper" do
+ @m.each(:strict_upper).to_a.should == [2, 3, 4, 7, 8]
+ @t.each(:strict_upper).to_a.should == [2]
+ end
- it "yields the rights elements when passed :upper" do
- @m.each(:upper).to_a.should == [1, 2, 3, 4, 6, 7, 8]
- @t.each(:upper).to_a.should == [1, 2, 4]
+ it "yields the rights elements when passed :upper" do
+ @m.each(:upper).to_a.should == [1, 2, 3, 4, 6, 7, 8]
+ @t.each(:upper).to_a.should == [1, 2, 4]
+ end
end
end
diff --git a/spec/ruby/library/matrix/each_with_index_spec.rb b/spec/ruby/library/matrix/each_with_index_spec.rb
index a005b88621..59549f77b7 100644
--- a/spec/ruby/library/matrix/each_with_index_spec.rb
+++ b/spec/ruby/library/matrix/each_with_index_spec.rb
@@ -1,81 +1,84 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#each_with_index" do
- before :all do
- @m = Matrix[ [1, 2, 3], [4, 5, 6] ]
- @result = [
- [1, 0, 0],
- [2, 0, 1],
- [3, 0, 2],
- [4, 1, 0],
- [5, 1, 1],
- [6, 1, 2]
- ]
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns an Enumerator when called without a block" do
- enum = @m.each_with_index
- enum.should be_an_instance_of(Enumerator)
- enum.to_a.should == @result
- end
+ describe "Matrix#each_with_index" do
+ before :all do
+ @m = Matrix[ [1, 2, 3], [4, 5, 6] ]
+ @result = [
+ [1, 0, 0],
+ [2, 0, 1],
+ [3, 0, 2],
+ [4, 1, 0],
+ [5, 1, 1],
+ [6, 1, 2]
+ ]
+ end
- it "returns self" do
- @m.each_with_index{}.should equal(@m)
- end
+ it "returns an Enumerator when called without a block" do
+ enum = @m.each_with_index
+ enum.should be_an_instance_of(Enumerator)
+ enum.to_a.should == @result
+ end
- it "yields the elements starting with the those of the first row" do
- a = []
- @m.each_with_index {|x, r, c| a << [x, r, c]}
- a.should == @result
- end
-end
+ it "returns self" do
+ @m.each_with_index{}.should equal(@m)
+ end
-describe "Matrix#each_with_index with an argument" do
- before :all do
- @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ]
- @t = Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ]
+ it "yields the elements starting with the those of the first row" do
+ a = []
+ @m.each_with_index {|x, r, c| a << [x, r, c]}
+ a.should == @result
+ end
end
- it "raises an ArgumentError for unrecognized argument" do
- -> {
- @m.each_with_index("all"){}
- }.should raise_error(ArgumentError)
- -> {
- @m.each_with_index(nil){}
- }.should raise_error(ArgumentError)
- -> {
- @m.each_with_index(:left){}
- }.should raise_error(ArgumentError)
- end
+ describe "Matrix#each_with_index with an argument" do
+ before :all do
+ @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ]
+ @t = Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ]
+ end
- it "yields the rights elements when passed :diagonal" do
- @m.each_with_index(:diagonal).to_a.should == [[1, 0, 0], [6, 1, 1]]
- @t.each_with_index(:diagonal).to_a.should == [[1, 0, 0], [4, 1, 1]]
- end
+ it "raises an ArgumentError for unrecognized argument" do
+ -> {
+ @m.each_with_index("all"){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.each_with_index(nil){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.each_with_index(:left){}
+ }.should raise_error(ArgumentError)
+ end
- it "yields the rights elements when passed :off_diagonal" do
- @m.each_with_index(:off_diagonal).to_a.should == [[2, 0, 1], [3, 0, 2], [4, 0, 3], [5, 1, 0], [7, 1, 2], [8, 1, 3]]
- @t.each_with_index(:off_diagonal).to_a.should == [[2, 0, 1], [3, 1, 0], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]]
- end
+ it "yields the rights elements when passed :diagonal" do
+ @m.each_with_index(:diagonal).to_a.should == [[1, 0, 0], [6, 1, 1]]
+ @t.each_with_index(:diagonal).to_a.should == [[1, 0, 0], [4, 1, 1]]
+ end
- it "yields the rights elements when passed :lower" do
- @m.each_with_index(:lower).to_a.should == [[1, 0, 0], [5, 1, 0], [6, 1, 1]]
- @t.each_with_index(:lower).to_a.should == [[1, 0, 0], [3, 1, 0], [4, 1, 1], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]]
- end
+ it "yields the rights elements when passed :off_diagonal" do
+ @m.each_with_index(:off_diagonal).to_a.should == [[2, 0, 1], [3, 0, 2], [4, 0, 3], [5, 1, 0], [7, 1, 2], [8, 1, 3]]
+ @t.each_with_index(:off_diagonal).to_a.should == [[2, 0, 1], [3, 1, 0], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]]
+ end
- it "yields the rights elements when passed :strict_lower" do
- @m.each_with_index(:strict_lower).to_a.should == [[5, 1, 0]]
- @t.each_with_index(:strict_lower).to_a.should == [[3, 1, 0], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]]
- end
+ it "yields the rights elements when passed :lower" do
+ @m.each_with_index(:lower).to_a.should == [[1, 0, 0], [5, 1, 0], [6, 1, 1]]
+ @t.each_with_index(:lower).to_a.should == [[1, 0, 0], [3, 1, 0], [4, 1, 1], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]]
+ end
- it "yields the rights elements when passed :strict_upper" do
- @m.each_with_index(:strict_upper).to_a.should == [[2, 0, 1], [3, 0, 2], [4, 0, 3], [7, 1, 2], [8, 1, 3]]
- @t.each_with_index(:strict_upper).to_a.should == [[2, 0, 1]]
- end
+ it "yields the rights elements when passed :strict_lower" do
+ @m.each_with_index(:strict_lower).to_a.should == [[5, 1, 0]]
+ @t.each_with_index(:strict_lower).to_a.should == [[3, 1, 0], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]]
+ end
+
+ it "yields the rights elements when passed :strict_upper" do
+ @m.each_with_index(:strict_upper).to_a.should == [[2, 0, 1], [3, 0, 2], [4, 0, 3], [7, 1, 2], [8, 1, 3]]
+ @t.each_with_index(:strict_upper).to_a.should == [[2, 0, 1]]
+ end
- it "yields the rights elements when passed :upper" do
- @m.each_with_index(:upper).to_a.should == [[1, 0, 0], [2, 0, 1], [3, 0, 2], [4, 0, 3], [6, 1, 1], [7, 1, 2], [8, 1, 3]]
- @t.each_with_index(:upper).to_a.should == [[1, 0, 0], [2, 0, 1], [4, 1, 1]]
+ it "yields the rights elements when passed :upper" do
+ @m.each_with_index(:upper).to_a.should == [[1, 0, 0], [2, 0, 1], [3, 0, 2], [4, 0, 3], [6, 1, 1], [7, 1, 2], [8, 1, 3]]
+ @t.each_with_index(:upper).to_a.should == [[1, 0, 0], [2, 0, 1], [4, 1, 1]]
+ end
end
end
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalue_matrix_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalue_matrix_spec.rb
index 67f9dd1c19..f9ffca0123 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalue_matrix_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalue_matrix_spec.rb
@@ -1,9 +1,12 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::EigenvalueDecomposition#eigenvalue_matrix" do
- it "returns a diagonal matrix with the eigenvalues on the diagonal" do
- Matrix[[14, 16], [-6, -6]].eigensystem.eigenvalue_matrix.should == Matrix[[6, 0],[0, 2]]
- Matrix[[1, 1], [-1, 1]].eigensystem.eigenvalue_matrix.should == Matrix[[Complex(1,1), 0],[0, Complex(1,-1)]]
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::EigenvalueDecomposition#eigenvalue_matrix" do
+ it "returns a diagonal matrix with the eigenvalues on the diagonal" do
+ Matrix[[14, 16], [-6, -6]].eigensystem.eigenvalue_matrix.should == Matrix[[6, 0],[0, 2]]
+ Matrix[[1, 1], [-1, 1]].eigensystem.eigenvalue_matrix.should == Matrix[[Complex(1,1), 0],[0, Complex(1,-1)]]
+ end
end
end
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalues_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalues_spec.rb
index 7552b7616c..650d43d90f 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalues_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalues_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::EigenvalueDecomposition#eigenvalues" do
- it "returns an array of complex eigenvalues for a rotation matrix" do
- Matrix[[ 1, 1],
- [-1, 1]].eigensystem.eigenvalues.sort_by{|v| v.imag}.should ==
- [ Complex(1, -1), Complex(1, 1)]
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns an array of real eigenvalues for a symmetric matrix" do
- Matrix[[1, 2],
- [2, 1]].eigensystem.eigenvalues.sort.map!{|x| x.round(10)}.should ==
- [ -1, 3 ]
- end
+ describe "Matrix::EigenvalueDecomposition#eigenvalues" do
+ it "returns an array of complex eigenvalues for a rotation matrix" do
+ Matrix[[ 1, 1],
+ [-1, 1]].eigensystem.eigenvalues.sort_by{|v| v.imag}.should ==
+ [ Complex(1, -1), Complex(1, 1)]
+ end
+
+ it "returns an array of real eigenvalues for a symmetric matrix" do
+ Matrix[[1, 2],
+ [2, 1]].eigensystem.eigenvalues.sort.map!{|x| x.round(10)}.should ==
+ [ -1, 3 ]
+ end
- it "returns an array of real eigenvalues for a matrix" do
- Matrix[[14, 16],
- [-6, -6]].eigensystem.eigenvalues.sort.map!{|x| x.round(10)}.should ==
- [ 2, 6 ]
+ it "returns an array of real eigenvalues for a matrix" do
+ Matrix[[14, 16],
+ [-6, -6]].eigensystem.eigenvalues.sort.map!{|x| x.round(10)}.should ==
+ [ 2, 6 ]
+ end
end
end
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvector_matrix_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvector_matrix_spec.rb
index 09f229ee15..57299ce69e 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvector_matrix_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvector_matrix_spec.rb
@@ -1,20 +1,23 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::EigenvalueDecomposition#eigenvector_matrix" do
- it "returns a complex eigenvector matrix given a rotation matrix" do
- # Fix me: should test for linearity, not for equality
- Matrix[[ 1, 1],
- [-1, 1]].eigensystem.eigenvector_matrix.should ==
- Matrix[[1, 1],
- [Complex(0, 1), Complex(0, -1)]]
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::EigenvalueDecomposition#eigenvector_matrix" do
+ it "returns a complex eigenvector matrix given a rotation matrix" do
+ # Fix me: should test for linearity, not for equality
+ Matrix[[ 1, 1],
+ [-1, 1]].eigensystem.eigenvector_matrix.should ==
+ Matrix[[1, 1],
+ [Complex(0, 1), Complex(0, -1)]]
+ end
- it "returns an real eigenvector matrix for a symmetric matrix" do
- # Fix me: should test for linearity, not for equality
- Matrix[[1, 2],
- [2, 1]].eigensystem.eigenvector_matrix.should ==
- Matrix[[0.7071067811865475, 0.7071067811865475],
- [-0.7071067811865475, 0.7071067811865475]]
+ it "returns an real eigenvector matrix for a symmetric matrix" do
+ # Fix me: should test for linearity, not for equality
+ Matrix[[1, 2],
+ [2, 1]].eigensystem.eigenvector_matrix.should ==
+ Matrix[[0.7071067811865475, 0.7071067811865475],
+ [-0.7071067811865475, 0.7071067811865475]]
+ end
end
end
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvectors_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvectors_spec.rb
index 2b6ce74ea8..54e6857bf3 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvectors_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvectors_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::EigenvalueDecomposition#eigenvectors" do
- it "returns an array of complex eigenvectors for a rotation matrix" do
- # Fix me: should test for linearity, not for equality
- Matrix[[ 1, 1],
- [-1, 1]].eigensystem.eigenvectors.should ==
- [ Vector[1, Complex(0, 1)],
- Vector[1, Complex(0, -1)]
- ]
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::EigenvalueDecomposition#eigenvectors" do
+ it "returns an array of complex eigenvectors for a rotation matrix" do
+ # Fix me: should test for linearity, not for equality
+ Matrix[[ 1, 1],
+ [-1, 1]].eigensystem.eigenvectors.should ==
+ [ Vector[1, Complex(0, 1)],
+ Vector[1, Complex(0, -1)]
+ ]
+ end
- it "returns an array of real eigenvectors for a symmetric matrix" do
- # Fix me: should test for linearity, not for equality
- Matrix[[1, 2],
- [2, 1]].eigensystem.eigenvectors.should ==
- [ Vector[0.7071067811865475, -0.7071067811865475],
- Vector[0.7071067811865475, 0.7071067811865475]
- ]
+ it "returns an array of real eigenvectors for a symmetric matrix" do
+ # Fix me: should test for linearity, not for equality
+ Matrix[[1, 2],
+ [2, 1]].eigensystem.eigenvectors.should ==
+ [ Vector[0.7071067811865475, -0.7071067811865475],
+ Vector[0.7071067811865475, 0.7071067811865475]
+ ]
+ end
end
end
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb
index 8438f63133..02aad65c4b 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb
@@ -1,24 +1,27 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::EigenvalueDecomposition#initialize" do
- it "raises an error if argument is not a matrix" do
- -> {
- Matrix::EigenvalueDecomposition.new([[]])
- }.should raise_error(TypeError)
- -> {
- Matrix::EigenvalueDecomposition.new(42)
- }.should raise_error(TypeError)
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "raises an error if matrix is not square" do
- -> {
- Matrix::EigenvalueDecomposition.new(Matrix[[1, 2]])
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ describe "Matrix::EigenvalueDecomposition#initialize" do
+ it "raises an error if argument is not a matrix" do
+ -> {
+ Matrix::EigenvalueDecomposition.new([[]])
+ }.should raise_error(TypeError)
+ -> {
+ Matrix::EigenvalueDecomposition.new(42)
+ }.should raise_error(TypeError)
+ end
+
+ it "raises an error if matrix is not square" do
+ -> {
+ Matrix::EigenvalueDecomposition.new(Matrix[[1, 2]])
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
- it "never hangs" do
- m = Matrix[ [0,0,0,0,0], [0,0,0,0,1], [0,0,0,1,0], [1,1,0,0,1], [1,0,1,0,1] ]
- Matrix::EigenvalueDecomposition.new(m).should_not == "infinite loop"
+ it "never hangs" do
+ m = Matrix[ [0,0,0,0,0], [0,0,0,0,1], [0,0,0,1,0], [1,1,0,0,1], [1,0,1,0,1] ]
+ Matrix::EigenvalueDecomposition.new(m).should_not == "infinite loop"
+ end
end
end
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/to_a_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/to_a_spec.rb
index 8be41a5720..352ae274b4 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/to_a_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/to_a_spec.rb
@@ -1,18 +1,21 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::EigenvalueDecomposition#to_a" do
- before :each do
- @a = Matrix[[14, 16], [-6, -6]]
- @e = Matrix::EigenvalueDecomposition.new(@a)
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns an array of with [V, D, V.inv]" do
- @e.to_a.should == [@e.v, @e.d, @e.v_inv]
- end
+ describe "Matrix::EigenvalueDecomposition#to_a" do
+ before :each do
+ @a = Matrix[[14, 16], [-6, -6]]
+ @e = Matrix::EigenvalueDecomposition.new(@a)
+ end
+
+ it "returns an array of with [V, D, V.inv]" do
+ @e.to_a.should == [@e.v, @e.d, @e.v_inv]
+ end
- it "returns a factorization" do
- v, d, v_inv = @e.to_a
- (v * d * v_inv).map{|e| e.round(10)}.should == @a
+ it "returns a factorization" do
+ v, d, v_inv = @e.to_a
+ (v * d * v_inv).map{|e| e.round(10)}.should == @a
+ end
end
end
diff --git a/spec/ruby/library/matrix/element_reference_spec.rb b/spec/ruby/library/matrix/element_reference_spec.rb
index b950d1c391..286ab851bd 100644
--- a/spec/ruby/library/matrix/element_reference_spec.rb
+++ b/spec/ruby/library/matrix/element_reference_spec.rb
@@ -1,23 +1,26 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#[]" do
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- before :all do
- @m = Matrix[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]
- end
+ describe "Matrix#[]" do
+
+ before :all do
+ @m = Matrix[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]
+ end
- it "returns element at (i, j)" do
- (0..3).each do |i|
- (0..2).each do |j|
- @m[i, j].should == (i * 3) + j
+ it "returns element at (i, j)" do
+ (0..3).each do |i|
+ (0..2).each do |j|
+ @m[i, j].should == (i * 3) + j
+ end
end
end
- end
- it "returns nil for an invalid index pair" do
- @m[8,1].should be_nil
- @m[1,8].should be_nil
- end
+ it "returns nil for an invalid index pair" do
+ @m[8,1].should be_nil
+ @m[1,8].should be_nil
+ end
+ end
end
diff --git a/spec/ruby/library/matrix/empty_spec.rb b/spec/ruby/library/matrix/empty_spec.rb
index 5f294711db..0b5d5ffe0f 100644
--- a/spec/ruby/library/matrix/empty_spec.rb
+++ b/spec/ruby/library/matrix/empty_spec.rb
@@ -1,68 +1,71 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix#empty?" do
- it "returns true when the Matrix is empty" do
- Matrix[ ].empty?.should be_true
- Matrix[ [], [], [] ].empty?.should be_true
- Matrix[ [], [], [] ].transpose.empty?.should be_true
- end
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "returns false when the Matrix has elements" do
- Matrix[ [1, 2] ].empty?.should be_false
- Matrix[ [1], [2] ].empty?.should be_false
- end
+ describe "Matrix#empty?" do
+ it "returns true when the Matrix is empty" do
+ Matrix[ ].empty?.should be_true
+ Matrix[ [], [], [] ].empty?.should be_true
+ Matrix[ [], [], [] ].transpose.empty?.should be_true
+ end
+
+ it "returns false when the Matrix has elements" do
+ Matrix[ [1, 2] ].empty?.should be_false
+ Matrix[ [1], [2] ].empty?.should be_false
+ end
- it "doesn't accept any parameter" do
- ->{
- Matrix[ [1, 2] ].empty?(42)
- }.should raise_error(ArgumentError)
+ it "doesn't accept any parameter" do
+ ->{
+ Matrix[ [1, 2] ].empty?(42)
+ }.should raise_error(ArgumentError)
+ end
end
-end
-describe "Matrix.empty" do
- it "returns an empty matrix of the requested size" do
- m = Matrix.empty(3, 0)
- m.row_size.should == 3
- m.column_size.should == 0
+ describe "Matrix.empty" do
+ it "returns an empty matrix of the requested size" do
+ m = Matrix.empty(3, 0)
+ m.row_size.should == 3
+ m.column_size.should == 0
- m = Matrix.empty(0, 3)
- m.row_size.should == 0
- m.column_size.should == 3
- end
+ m = Matrix.empty(0, 3)
+ m.row_size.should == 0
+ m.column_size.should == 3
+ end
- it "has arguments defaulting to 0" do
- Matrix.empty.should == Matrix.empty(0, 0)
- Matrix.empty(42).should == Matrix.empty(42, 0)
- end
+ it "has arguments defaulting to 0" do
+ Matrix.empty.should == Matrix.empty(0, 0)
+ Matrix.empty(42).should == Matrix.empty(42, 0)
+ end
- it "does not accept more than two parameters" do
- ->{
- Matrix.empty(1, 2, 3)
- }.should raise_error(ArgumentError)
- end
+ it "does not accept more than two parameters" do
+ ->{
+ Matrix.empty(1, 2, 3)
+ }.should raise_error(ArgumentError)
+ end
- it "raises an error if both dimensions are > 0" do
- ->{
- Matrix.empty(1, 2)
- }.should raise_error(ArgumentError)
- end
+ it "raises an error if both dimensions are > 0" do
+ ->{
+ Matrix.empty(1, 2)
+ }.should raise_error(ArgumentError)
+ end
- it "raises an error if any dimension is < 0" do
- ->{
- Matrix.empty(-2, 0)
- }.should raise_error(ArgumentError)
+ it "raises an error if any dimension is < 0" do
+ ->{
+ Matrix.empty(-2, 0)
+ }.should raise_error(ArgumentError)
- ->{
- Matrix.empty(0, -2)
- }.should raise_error(ArgumentError)
- end
+ ->{
+ Matrix.empty(0, -2)
+ }.should raise_error(ArgumentError)
+ end
-end
+ end
-describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.empty(0, 1).should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.empty(0, 1).should be_an_instance_of(MatrixSub)
+ end
end
end
diff --git a/spec/ruby/library/matrix/eql_spec.rb b/spec/ruby/library/matrix/eql_spec.rb
index ea26c3320d..d3f03dd6f3 100644
--- a/spec/ruby/library/matrix/eql_spec.rb
+++ b/spec/ruby/library/matrix/eql_spec.rb
@@ -1,11 +1,14 @@
require_relative '../../spec_helper'
-require_relative 'shared/equal_value'
-require 'matrix'
-describe "Matrix#eql?" do
- it_behaves_like :equal, :eql?
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/equal_value'
+ require 'matrix'
- it "returns false if some elements are == but not eql?" do
- Matrix[[1, 2],[3, 4]].eql?(Matrix[[1, 2],[3, 4.0]]).should be_false
+ describe "Matrix#eql?" do
+ it_behaves_like :equal, :eql?
+
+ it "returns false if some elements are == but not eql?" do
+ Matrix[[1, 2],[3, 4]].eql?(Matrix[[1, 2],[3, 4.0]]).should be_false
+ end
end
end
diff --git a/spec/ruby/library/matrix/equal_value_spec.rb b/spec/ruby/library/matrix/equal_value_spec.rb
index 10cf1e6c29..0408a8ef3e 100644
--- a/spec/ruby/library/matrix/equal_value_spec.rb
+++ b/spec/ruby/library/matrix/equal_value_spec.rb
@@ -1,11 +1,14 @@
require_relative '../../spec_helper'
-require_relative 'shared/equal_value'
-require 'matrix'
-describe "Matrix#==" do
- it_behaves_like :equal, :==
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/equal_value'
+ require 'matrix'
- it "returns true if some elements are == but not eql?" do
- Matrix[[1, 2],[3, 4]].should == Matrix[[1, 2],[3, 4.0]]
+ describe "Matrix#==" do
+ it_behaves_like :equal, :==
+
+ it "returns true if some elements are == but not eql?" do
+ Matrix[[1, 2],[3, 4]].should == Matrix[[1, 2],[3, 4.0]]
+ end
end
end
diff --git a/spec/ruby/library/matrix/exponent_spec.rb b/spec/ruby/library/matrix/exponent_spec.rb
index b76e18b4cd..5262627fd5 100644
--- a/spec/ruby/library/matrix/exponent_spec.rb
+++ b/spec/ruby/library/matrix/exponent_spec.rb
@@ -1,64 +1,67 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix#**" do
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- describe "given an integer _n_" do
- it "multiples the Matrix by itself _n_ times" do
- m = Matrix[ [7,6], [3,9] ]
- (m ** 1).should == m
- (m ** 2).should == Matrix[ [67, 96], [48,99] ]
- (m ** 2).should == m * m
- (m ** 3).should == m * m * m
- (m ** 4).should == m * m * m * m
- (m ** 5).should == m * m * m * m * m
- end
-
- it "raises a ErrDimensionMismatch for non square matrices" do
- m = Matrix[ [1, 1], [1, 2], [2, 3]]
- -> { m ** 3 }.should raise_error(Matrix::ErrDimensionMismatch)
- -> { m ** 0 }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ describe "Matrix#**" do
- describe "that is < 0" do
- it "returns the inverse of **(-n)" do
- m = Matrix[ [1, 1], [1, 2] ]
- (m ** -2).should == Matrix[ [5, -3], [-3, 2]]
- (m ** -4).should == (m.inverse ** 4)
+ describe "given an integer _n_" do
+ it "multiples the Matrix by itself _n_ times" do
+ m = Matrix[ [7,6], [3,9] ]
+ (m ** 1).should == m
+ (m ** 2).should == Matrix[ [67, 96], [48,99] ]
+ (m ** 2).should == m * m
+ (m ** 3).should == m * m * m
+ (m ** 4).should == m * m * m * m
+ (m ** 5).should == m * m * m * m * m
end
- it "raises a ErrNotRegular for irregular matrices" do
- m = Matrix[ [1, 1], [1, 1] ]
- -> { m ** -2 }.should raise_error(Matrix::ErrNotRegular)
+ it "raises a ErrDimensionMismatch for non square matrices" do
+ m = Matrix[ [1, 1], [1, 2], [2, 3]]
+ -> { m ** 3 }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> { m ** 0 }.should raise_error(Matrix::ErrDimensionMismatch)
end
- end
- ruby_version_is '3.1.0' do # https://bugs.ruby-lang.org/issues/17521
- describe "that is 0" do
- it "returns the identity for square matrices" do
+ describe "that is < 0" do
+ it "returns the inverse of **(-n)" do
+ m = Matrix[ [1, 1], [1, 2] ]
+ (m ** -2).should == Matrix[ [5, -3], [-3, 2]]
+ (m ** -4).should == (m.inverse ** 4)
+ end
+
+ it "raises a ErrNotRegular for irregular matrices" do
m = Matrix[ [1, 1], [1, 1] ]
- (m ** 0).should == Matrix.identity(2)
+ -> { m ** -2 }.should raise_error(Matrix::ErrNotRegular)
end
+ end
+
+ ruby_version_is '3.1.0' do # https://bugs.ruby-lang.org/issues/17521
+ describe "that is 0" do
+ it "returns the identity for square matrices" do
+ m = Matrix[ [1, 1], [1, 1] ]
+ (m ** 0).should == Matrix.identity(2)
+ end
- it "raises an ErrDimensionMismatch for non-square matrices" do
- m = Matrix[ [1, 1] ]
- -> { m ** 0 }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "raises an ErrDimensionMismatch for non-square matrices" do
+ m = Matrix[ [1, 1] ]
+ -> { m ** 0 }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
end
end
end
- end
- it "returns the power for non integer powers" do
- a = Matrix[[5, 4], [4, 5]]
- ((a ** 0.5) ** 2).round(8).should == a
- a = Matrix[[7, 10], [15, 22]]
- ((a ** 0.25) ** 4).round(8).should == a
- end
+ it "returns the power for non integer powers" do
+ a = Matrix[[5, 4], [4, 5]]
+ ((a ** 0.5) ** 2).round(8).should == a
+ a = Matrix[[7, 10], [15, 22]]
+ ((a ** 0.25) ** 4).round(8).should == a
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- (MatrixSub.ins ** 1).should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ (MatrixSub.ins ** 1).should be_an_instance_of(MatrixSub)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/find_index_spec.rb b/spec/ruby/library/matrix/find_index_spec.rb
index c2bfa6d61a..a0e3679aef 100644
--- a/spec/ruby/library/matrix/find_index_spec.rb
+++ b/spec/ruby/library/matrix/find_index_spec.rb
@@ -1,146 +1,149 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#find_index without any argument" do
- before :all do
- @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ]
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns an Enumerator when called without a block" do
- enum = @m.find_index
- enum.should be_an_instance_of(Enumerator)
- enum.to_a.should == [1, 2, 3, 4, 5, 6, 7, 8]
- end
+ describe "Matrix#find_index without any argument" do
+ before :all do
+ @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ]
+ end
- it "returns nil if the block is always false" do
- @m.find_index{false}.should be_nil
- end
+ it "returns an Enumerator when called without a block" do
+ enum = @m.find_index
+ enum.should be_an_instance_of(Enumerator)
+ enum.to_a.should == [1, 2, 3, 4, 5, 6, 7, 8]
+ end
- it "returns the first index for which the block is true" do
- @m.find_index{|x| x >= 3}.should == [0, 2]
- end
-end
+ it "returns nil if the block is always false" do
+ @m.find_index{false}.should be_nil
+ end
-describe "Matrix#find_index with a subselection argument" do
- before :all do
- @tests = [
- [ Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ], {
- diagonal: [1, 6] ,
- off_diagonal: [2, 3, 4, 5, 7, 8],
- lower: [1, 5, 6] ,
- strict_lower: [5] ,
- strict_upper: [2, 3, 4, 7, 8] ,
- upper: [1, 2, 3, 4, 6, 7, 8] ,
- }
- ],
- [ Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ], {
- diagonal: [1, 4] ,
- off_diagonal: [2, 3, 5, 6, 7, 8],
- lower: [1, 3, 4, 5, 6, 7, 8] ,
- strict_lower: [3, 5, 6, 7, 8] ,
- strict_upper: [2] ,
- upper: [1, 2, 4] ,
- }
- ]]
+ it "returns the first index for which the block is true" do
+ @m.find_index{|x| x >= 3}.should == [0, 2]
+ end
end
- describe "and no generic argument" do
- it "returns an Enumerator when called without a block" do
- @tests.each do |matrix, h|
- h.each do |selector, result|
- matrix.find_index(selector).should be_an_instance_of(Enumerator)
- end
- end
+ describe "Matrix#find_index with a subselection argument" do
+ before :all do
+ @tests = [
+ [ Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ], {
+ diagonal: [1, 6] ,
+ off_diagonal: [2, 3, 4, 5, 7, 8],
+ lower: [1, 5, 6] ,
+ strict_lower: [5] ,
+ strict_upper: [2, 3, 4, 7, 8] ,
+ upper: [1, 2, 3, 4, 6, 7, 8] ,
+ }
+ ],
+ [ Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ], {
+ diagonal: [1, 4] ,
+ off_diagonal: [2, 3, 5, 6, 7, 8],
+ lower: [1, 3, 4, 5, 6, 7, 8] ,
+ strict_lower: [3, 5, 6, 7, 8] ,
+ strict_upper: [2] ,
+ upper: [1, 2, 4] ,
+ }
+ ]]
end
- it "yields the rights elements" do
- @tests.each do |matrix, h|
- h.each do |selector, result|
- matrix.find_index(selector).to_a.should == result
+ describe "and no generic argument" do
+ it "returns an Enumerator when called without a block" do
+ @tests.each do |matrix, h|
+ h.each do |selector, result|
+ matrix.find_index(selector).should be_an_instance_of(Enumerator)
+ end
end
end
- end
- it "returns the first index for which the block returns true" do
- @tests.each do |matrix, h|
- h.each do |selector, result|
- cnt = result.size.div 2
- which = result[cnt]
- idx = matrix.find_index(selector){|x| cnt -= 1; x == which}
- matrix[*idx].should == which
- cnt.should == -1
+ it "yields the rights elements" do
+ @tests.each do |matrix, h|
+ h.each do |selector, result|
+ matrix.find_index(selector).to_a.should == result
+ end
end
end
- end
- it "returns nil if the block is always false" do
- @tests.each do |matrix, h|
- h.each do |selector, result|
- matrix.find_index(selector){ nil }.should == nil
+ it "returns the first index for which the block returns true" do
+ @tests.each do |matrix, h|
+ h.each do |selector, result|
+ cnt = result.size.div 2
+ which = result[cnt]
+ idx = matrix.find_index(selector){|x| cnt -= 1; x == which}
+ matrix[*idx].should == which
+ cnt.should == -1
+ end
end
end
- end
- end
+ it "returns nil if the block is always false" do
+ @tests.each do |matrix, h|
+ h.each do |selector, result|
+ matrix.find_index(selector){ nil }.should == nil
+ end
+ end
+ end
- describe "and a generic argument" do
- it "ignores a block" do
- @m.find_index(42, :diagonal){raise "oups"}.should == nil
end
- it "returns the index of the requested value" do
- @tests.each do |matrix, h|
- h.each do |selector, result|
- cnt = result.size / 2
- which = result[cnt]
- idx = matrix.find_index(which, selector)
- matrix[*idx].should == which
+ describe "and a generic argument" do
+ it "ignores a block" do
+ @m.find_index(42, :diagonal){raise "oups"}.should == nil
+ end
+
+ it "returns the index of the requested value" do
+ @tests.each do |matrix, h|
+ h.each do |selector, result|
+ cnt = result.size / 2
+ which = result[cnt]
+ idx = matrix.find_index(which, selector)
+ matrix[*idx].should == which
+ end
end
end
- end
- it "returns nil if the requested value is not found" do
- @tests.each do |matrix, h|
- h.each do |selector, result|
- matrix.find_index(42, selector).should == nil
+ it "returns nil if the requested value is not found" do
+ @tests.each do |matrix, h|
+ h.each do |selector, result|
+ matrix.find_index(42, selector).should == nil
+ end
end
end
end
- end
-end
-
-describe "Matrix#find_index with only a generic argument" do
- before :all do
- @m = Matrix[ [1, 2, 3, 4], [1, 2, 3, 4] ]
end
- it "returns nil if the value is not found" do
- @m.find_index(42).should be_nil
- end
+ describe "Matrix#find_index with only a generic argument" do
+ before :all do
+ @m = Matrix[ [1, 2, 3, 4], [1, 2, 3, 4] ]
+ end
- it "returns the first index for of the requested value" do
- @m.find_index(3).should == [0, 2]
- end
+ it "returns nil if the value is not found" do
+ @m.find_index(42).should be_nil
+ end
+
+ it "returns the first index for of the requested value" do
+ @m.find_index(3).should == [0, 2]
+ end
- it "ignores a block" do
- @m.find_index(4){raise "oups"}.should == [0, 3]
+ it "ignores a block" do
+ @m.find_index(4){raise "oups"}.should == [0, 3]
+ end
end
-end
-describe "Matrix#find_index with two arguments" do
- it "raises an ArgumentError for an unrecognized last argument" do
- -> {
- @m.find_index(1, "all"){}
- }.should raise_error(ArgumentError)
- -> {
- @m.find_index(1, nil){}
- }.should raise_error(ArgumentError)
- -> {
- @m.find_index(1, :left){}
- }.should raise_error(ArgumentError)
- -> {
- @m.find_index(:diagonal, 1){}
- }.should raise_error(ArgumentError)
+ describe "Matrix#find_index with two arguments" do
+ it "raises an ArgumentError for an unrecognized last argument" do
+ -> {
+ @m.find_index(1, "all"){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.find_index(1, nil){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.find_index(1, :left){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.find_index(:diagonal, 1){}
+ }.should raise_error(ArgumentError)
+ end
end
end
diff --git a/spec/ruby/library/matrix/hash_spec.rb b/spec/ruby/library/matrix/hash_spec.rb
index 7dabcd3737..7c1970511b 100644
--- a/spec/ruby/library/matrix/hash_spec.rb
+++ b/spec/ruby/library/matrix/hash_spec.rb
@@ -1,15 +1,18 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#hash" do
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns an Integer" do
- Matrix[ [1,2] ].hash.should be_an_instance_of(Integer)
- end
+ describe "Matrix#hash" do
- it "returns the same value for the same matrix" do
- data = [ [40,5], [2,7] ]
- Matrix[ *data ].hash.should == Matrix[ *data ].hash
- end
+ it "returns an Integer" do
+ Matrix[ [1,2] ].hash.should be_an_instance_of(Integer)
+ end
+ it "returns the same value for the same matrix" do
+ data = [ [40,5], [2,7] ]
+ Matrix[ *data ].hash.should == Matrix[ *data ].hash
+ end
+
+ end
end
diff --git a/spec/ruby/library/matrix/hermitian_spec.rb b/spec/ruby/library/matrix/hermitian_spec.rb
index 177ca64d83..4038ee3fa9 100644
--- a/spec/ruby/library/matrix/hermitian_spec.rb
+++ b/spec/ruby/library/matrix/hermitian_spec.rb
@@ -1,34 +1,37 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix.hermitian?" do
- it "returns true for a hermitian Matrix" do
- Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, -3), 5, 6]].hermitian?.should be_true
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns true for a 0x0 empty matrix" do
- Matrix.empty.hermitian?.should be_true
- end
+ describe "Matrix.hermitian?" do
+ it "returns true for a hermitian Matrix" do
+ Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, -3), 5, 6]].hermitian?.should be_true
+ end
- it "returns false for an asymmetric Matrix" do
- Matrix[[1, 2],[-2, 1]].hermitian?.should be_false
- end
+ it "returns true for a 0x0 empty matrix" do
+ Matrix.empty.hermitian?.should be_true
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.hermitian?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "returns false for an asymmetric Matrix" do
+ Matrix[[1, 2],[-2, 1]].hermitian?.should be_false
+ end
+
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.hermitian?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
end
- end
- it "returns false for a matrix with complex values on the diagonal" do
- Matrix[[Complex(1,1)]].hermitian?.should be_false
- Matrix[[Complex(1,0)]].hermitian?.should be_true
+ it "returns false for a matrix with complex values on the diagonal" do
+ Matrix[[Complex(1,1)]].hermitian?.should be_false
+ Matrix[[Complex(1,0)]].hermitian?.should be_true
+ end
end
end
diff --git a/spec/ruby/library/matrix/identity_spec.rb b/spec/ruby/library/matrix/identity_spec.rb
index 646462bc47..14f51c402e 100644
--- a/spec/ruby/library/matrix/identity_spec.rb
+++ b/spec/ruby/library/matrix/identity_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/identity'
-describe "Matrix.identity" do
- it_behaves_like :matrix_identity, :identity
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/identity'
+
+ describe "Matrix.identity" do
+ it_behaves_like :matrix_identity, :identity
+ end
end
diff --git a/spec/ruby/library/matrix/imag_spec.rb b/spec/ruby/library/matrix/imag_spec.rb
index 1c988753d8..a89186ec02 100644
--- a/spec/ruby/library/matrix/imag_spec.rb
+++ b/spec/ruby/library/matrix/imag_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/imaginary'
-describe "Matrix#imag" do
- it_behaves_like :matrix_imaginary, :imag
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/imaginary'
+
+ describe "Matrix#imag" do
+ it_behaves_like :matrix_imaginary, :imag
+ end
end
diff --git a/spec/ruby/library/matrix/imaginary_spec.rb b/spec/ruby/library/matrix/imaginary_spec.rb
index ceae4bbe8d..e7f0e49d31 100644
--- a/spec/ruby/library/matrix/imaginary_spec.rb
+++ b/spec/ruby/library/matrix/imaginary_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/imaginary'
-describe "Matrix#imaginary" do
- it_behaves_like :matrix_imaginary, :imaginary
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/imaginary'
+
+ describe "Matrix#imaginary" do
+ it_behaves_like :matrix_imaginary, :imaginary
+ end
end
diff --git a/spec/ruby/library/matrix/inspect_spec.rb b/spec/ruby/library/matrix/inspect_spec.rb
index 508f478252..d754c0fe7f 100644
--- a/spec/ruby/library/matrix/inspect_spec.rb
+++ b/spec/ruby/library/matrix/inspect_spec.rb
@@ -1,27 +1,30 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix#inspect" do
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "returns a stringified representation of the Matrix" do
- Matrix[ [1,2], [2,1] ].inspect.should == "Matrix[[1, 2], [2, 1]]"
- end
+ describe "Matrix#inspect" do
- it "returns 'Matrix.empty(...)' for empty matrices" do
- Matrix[ [], [], [] ].inspect.should == "Matrix.empty(3, 0)"
- Matrix.columns([ [], [], [] ]).inspect.should == "Matrix.empty(0, 3)"
- end
+ it "returns a stringified representation of the Matrix" do
+ Matrix[ [1,2], [2,1] ].inspect.should == "Matrix[[1, 2], [2, 1]]"
+ end
- it "calls inspect on its contents" do
- obj = mock("some_value")
- obj.should_receive(:inspect).and_return("some_value")
- Matrix[ [1, 2], [3, obj] ].inspect.should == "Matrix[[1, 2], [3, some_value]]"
- end
+ it "returns 'Matrix.empty(...)' for empty matrices" do
+ Matrix[ [], [], [] ].inspect.should == "Matrix.empty(3, 0)"
+ Matrix.columns([ [], [], [] ]).inspect.should == "Matrix.empty(0, 3)"
+ end
+
+ it "calls inspect on its contents" do
+ obj = mock("some_value")
+ obj.should_receive(:inspect).and_return("some_value")
+ Matrix[ [1, 2], [3, obj] ].inspect.should == "Matrix[[1, 2], [3, some_value]]"
+ end
- describe "for a subclass of Matrix" do
- it "returns a string using the subclass' name" do
- MatrixSub.ins.inspect.should == "MatrixSub[[1, 0], [0, 1]]"
+ describe "for a subclass of Matrix" do
+ it "returns a string using the subclass' name" do
+ MatrixSub.ins.inspect.should == "MatrixSub[[1, 0], [0, 1]]"
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/inv_spec.rb b/spec/ruby/library/matrix/inv_spec.rb
index 82879a6d82..0ad817a253 100644
--- a/spec/ruby/library/matrix/inv_spec.rb
+++ b/spec/ruby/library/matrix/inv_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'shared/inverse'
-describe "Matrix#inv" do
- it_behaves_like :inverse, :inv
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'shared/inverse'
+
+ describe "Matrix#inv" do
+ it_behaves_like :inverse, :inv
+ end
end
diff --git a/spec/ruby/library/matrix/inverse_from_spec.rb b/spec/ruby/library/matrix/inverse_from_spec.rb
index 651d56a244..bca40542f6 100644
--- a/spec/ruby/library/matrix/inverse_from_spec.rb
+++ b/spec/ruby/library/matrix/inverse_from_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#inverse_from" do
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix#inverse_from" do
+ it "needs to be reviewed for spec completeness"
+ end
end
diff --git a/spec/ruby/library/matrix/inverse_spec.rb b/spec/ruby/library/matrix/inverse_spec.rb
index fa3fa7de8a..dd9099bec5 100644
--- a/spec/ruby/library/matrix/inverse_spec.rb
+++ b/spec/ruby/library/matrix/inverse_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'shared/inverse'
-describe "Matrix#inverse" do
- it_behaves_like :inverse, :inverse
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'shared/inverse'
+
+ describe "Matrix#inverse" do
+ it_behaves_like :inverse, :inverse
+ end
end
diff --git a/spec/ruby/library/matrix/lower_triangular_spec.rb b/spec/ruby/library/matrix/lower_triangular_spec.rb
index f3aa4501f4..0223b8b619 100644
--- a/spec/ruby/library/matrix/lower_triangular_spec.rb
+++ b/spec/ruby/library/matrix/lower_triangular_spec.rb
@@ -1,24 +1,27 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix.lower_triangular?" do
- it "returns true for a square lower triangular Matrix" do
- Matrix[[1, 0, 0], [1, 2, 0], [1, 2, 3]].lower_triangular?.should be_true
- Matrix.diagonal([1, 2, 3]).lower_triangular?.should be_true
- Matrix[[1, 0], [1, 2], [1, 2], [1, 2]].lower_triangular?.should be_true
- Matrix[[1, 0, 0, 0], [1, 2, 0, 0]].lower_triangular?.should be_true
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns true for an empty Matrix" do
- Matrix.empty(3, 0).lower_triangular?.should be_true
- Matrix.empty(0, 3).lower_triangular?.should be_true
- Matrix.empty(0, 0).lower_triangular?.should be_true
- end
+ describe "Matrix.lower_triangular?" do
+ it "returns true for a square lower triangular Matrix" do
+ Matrix[[1, 0, 0], [1, 2, 0], [1, 2, 3]].lower_triangular?.should be_true
+ Matrix.diagonal([1, 2, 3]).lower_triangular?.should be_true
+ Matrix[[1, 0], [1, 2], [1, 2], [1, 2]].lower_triangular?.should be_true
+ Matrix[[1, 0, 0, 0], [1, 2, 0, 0]].lower_triangular?.should be_true
+ end
+
+ it "returns true for an empty Matrix" do
+ Matrix.empty(3, 0).lower_triangular?.should be_true
+ Matrix.empty(0, 3).lower_triangular?.should be_true
+ Matrix.empty(0, 0).lower_triangular?.should be_true
+ end
- it "returns false for a non lower triangular square Matrix" do
- Matrix[[0, 1], [0, 0]].lower_triangular?.should be_false
- Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].lower_triangular?.should be_false
- Matrix[[0, 1], [0, 0], [0, 0], [0, 0]].lower_triangular?.should be_false
- Matrix[[0, 0, 0, 1], [0, 0, 0, 0]].lower_triangular?.should be_false
+ it "returns false for a non lower triangular square Matrix" do
+ Matrix[[0, 1], [0, 0]].lower_triangular?.should be_false
+ Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].lower_triangular?.should be_false
+ Matrix[[0, 1], [0, 0], [0, 0], [0, 0]].lower_triangular?.should be_false
+ Matrix[[0, 0, 0, 1], [0, 0, 0, 0]].lower_triangular?.should be_false
+ end
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb b/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb
index 9d733066c1..1ac4bc971e 100644
--- a/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb
@@ -1,21 +1,24 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::LUPDecomposition#determinant" do
- it "returns the determinant when the matrix is square" do
- a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
- a.lup.determinant.should == 15120 # == a.determinant
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::LUPDecomposition#determinant" do
+ it "returns the determinant when the matrix is square" do
+ a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
+ a.lup.determinant.should == 15120 # == a.determinant
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[7, 8, 9], [14, 46, 51]],
- Matrix[[7, 8], [14, 46], [28, 82]],
- ].each do |m|
- lup = m.lup
- -> {
- lup.determinant
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[7, 8, 9], [14, 46, 51]],
+ Matrix[[7, 8], [14, 46], [28, 82]],
+ ].each do |m|
+ lup = m.lup
+ -> {
+ lup.determinant
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb b/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb
index 36afb349e6..42f78c7540 100644
--- a/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb
@@ -1,13 +1,16 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::LUPDecomposition#initialize" do
- it "raises an error if argument is not a matrix" do
- -> {
- Matrix::LUPDecomposition.new([[]])
- }.should raise_error(TypeError)
- -> {
- Matrix::LUPDecomposition.new(42)
- }.should raise_error(TypeError)
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::LUPDecomposition#initialize" do
+ it "raises an error if argument is not a matrix" do
+ -> {
+ Matrix::LUPDecomposition.new([[]])
+ }.should raise_error(TypeError)
+ -> {
+ Matrix::LUPDecomposition.new(42)
+ }.should raise_error(TypeError)
+ end
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/l_spec.rb b/spec/ruby/library/matrix/lup_decomposition/l_spec.rb
index 9514ab5d06..6c751f12b7 100644
--- a/spec/ruby/library/matrix/lup_decomposition/l_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/l_spec.rb
@@ -1,18 +1,21 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::LUPDecomposition#l" do
- before :each do
- @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
- @lu = Matrix::LUPDecomposition.new(@a)
- @l = @lu.l
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns the first element of to_a" do
- @l.should == @lu.to_a[0]
- end
+ describe "Matrix::LUPDecomposition#l" do
+ before :each do
+ @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
+ @lu = Matrix::LUPDecomposition.new(@a)
+ @l = @lu.l
+ end
+
+ it "returns the first element of to_a" do
+ @l.should == @lu.to_a[0]
+ end
- it "returns a lower triangular matrix" do
- @l.lower_triangular?.should be_true
+ it "returns a lower triangular matrix" do
+ @l.lower_triangular?.should be_true
+ end
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/p_spec.rb b/spec/ruby/library/matrix/lup_decomposition/p_spec.rb
index c7b5e9196e..481f8a17d5 100644
--- a/spec/ruby/library/matrix/lup_decomposition/p_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/p_spec.rb
@@ -1,18 +1,21 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::LUPDecomposition#p" do
- before :each do
- @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
- @lu = Matrix::LUPDecomposition.new(@a)
- @p = @lu.p
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns the third element of to_a" do
- @p.should == @lu.to_a[2]
- end
+ describe "Matrix::LUPDecomposition#p" do
+ before :each do
+ @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
+ @lu = Matrix::LUPDecomposition.new(@a)
+ @p = @lu.p
+ end
+
+ it "returns the third element of to_a" do
+ @p.should == @lu.to_a[2]
+ end
- it "returns a permutation matrix" do
- @p.permutation?.should be_true
+ it "returns a permutation matrix" do
+ @p.permutation?.should be_true
+ end
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb b/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb
index 66242627e9..773fcb3e65 100644
--- a/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb
@@ -1,52 +1,55 @@
require_relative '../../../spec_helper'
-require 'matrix'
-
-describe "Matrix::LUPDecomposition#solve" do
- describe "for rectangular matrices" do
- it "raises an error for singular matrices" do
- a = Matrix[[1, 2, 3], [1, 3, 5], [2, 5, 8]]
- lu = Matrix::LUPDecomposition.new(a)
- -> {
- lu.solve(a)
- }.should raise_error(Matrix::ErrNotRegular)
- end
- describe "for non singular matrices" do
- before :each do
- @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
- @lu = Matrix::LUPDecomposition.new(@a)
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns the appropriate empty matrix when given an empty matrix" do
- @lu.solve(Matrix.empty(3,0)).should == Matrix.empty(3,0)
- empty = Matrix::LUPDecomposition.new(Matrix.empty(0, 0))
- empty.solve(Matrix.empty(0,3)).should == Matrix.empty(0,3)
+ describe "Matrix::LUPDecomposition#solve" do
+ describe "for rectangular matrices" do
+ it "raises an error for singular matrices" do
+ a = Matrix[[1, 2, 3], [1, 3, 5], [2, 5, 8]]
+ lu = Matrix::LUPDecomposition.new(a)
+ -> {
+ lu.solve(a)
+ }.should raise_error(Matrix::ErrNotRegular)
end
- it "returns the right matrix when given a matrix of the appropriate size" do
- solution = Matrix[[1, 2, 3, 4], [0, 1, 2, 3], [-1, -2, -3, -4]]
- values = Matrix[[-2, 4, 10, 16], [-37, -28, -19, -10], [-135, -188, -241, -294]] # == @a * solution
- @lu.solve(values).should == solution
- end
+ describe "for non singular matrices" do
+ before :each do
+ @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
+ @lu = Matrix::LUPDecomposition.new(@a)
+ end
- it "raises an error when given a matrix of the wrong size" do
- values = Matrix[[1, 2, 3, 4], [0, 1, 2, 3]]
- -> {
- @lu.solve(values)
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "returns the appropriate empty matrix when given an empty matrix" do
+ @lu.solve(Matrix.empty(3,0)).should == Matrix.empty(3,0)
+ empty = Matrix::LUPDecomposition.new(Matrix.empty(0, 0))
+ empty.solve(Matrix.empty(0,3)).should == Matrix.empty(0,3)
+ end
- it "returns the right vector when given a vector of the appropriate size" do
- solution = Vector[1, 2, -1]
- values = Vector[14, 55, 29] # == @a * solution
- @lu.solve(values).should == solution
- end
+ it "returns the right matrix when given a matrix of the appropriate size" do
+ solution = Matrix[[1, 2, 3, 4], [0, 1, 2, 3], [-1, -2, -3, -4]]
+ values = Matrix[[-2, 4, 10, 16], [-37, -28, -19, -10], [-135, -188, -241, -294]] # == @a * solution
+ @lu.solve(values).should == solution
+ end
- it "raises an error when given a vector of the wrong size" do
- values = Vector[14, 55]
- -> {
- @lu.solve(values)
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "raises an error when given a matrix of the wrong size" do
+ values = Matrix[[1, 2, 3, 4], [0, 1, 2, 3]]
+ -> {
+ @lu.solve(values)
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
+
+ it "returns the right vector when given a vector of the appropriate size" do
+ solution = Vector[1, 2, -1]
+ values = Vector[14, 55, 29] # == @a * solution
+ @lu.solve(values).should == solution
+ end
+
+ it "raises an error when given a vector of the wrong size" do
+ values = Vector[14, 55]
+ -> {
+ @lu.solve(values)
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb b/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb
index 9b1dccbbac..8702292865 100644
--- a/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb
@@ -1,33 +1,36 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::LUPDecomposition#to_a" do
- before :each do
- @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
- @lu = Matrix::LUPDecomposition.new(@a)
- @to_a = @lu.to_a
- @l, @u, @p = @to_a
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns an array of three matrices" do
- @to_a.should be_kind_of(Array)
- @to_a.length.should == 3
- @to_a.each{|m| m.should be_kind_of(Matrix)}
- end
+ describe "Matrix::LUPDecomposition#to_a" do
+ before :each do
+ @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
+ @lu = Matrix::LUPDecomposition.new(@a)
+ @to_a = @lu.to_a
+ @l, @u, @p = @to_a
+ end
- it "returns [l, u, p] such that l*u == a*p" do
- (@l * @u).should == (@p * @a)
- end
+ it "returns an array of three matrices" do
+ @to_a.should be_kind_of(Array)
+ @to_a.length.should == 3
+ @to_a.each{|m| m.should be_kind_of(Matrix)}
+ end
- it "returns the right values for rectangular matrices" do
- [
- Matrix[[7, 8, 9], [14, 46, 51]],
- Matrix[[4, 11], [5, 8], [3, 4]],
- ].each do |a|
- l, u, p = Matrix::LUPDecomposition.new(a).to_a
- (l * u).should == (p * a)
+ it "returns [l, u, p] such that l*u == a*p" do
+ (@l * @u).should == (@p * @a)
+ end
+
+ it "returns the right values for rectangular matrices" do
+ [
+ Matrix[[7, 8, 9], [14, 46, 51]],
+ Matrix[[4, 11], [5, 8], [3, 4]],
+ ].each do |a|
+ l, u, p = Matrix::LUPDecomposition.new(a).to_a
+ (l * u).should == (p * a)
+ end
end
- end
- it "has other properties implied by the specs of #l, #u and #p"
+ it "has other properties implied by the specs of #l, #u and #p"
+ end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/u_spec.rb b/spec/ruby/library/matrix/lup_decomposition/u_spec.rb
index ca3dfc1f00..cd884b88ec 100644
--- a/spec/ruby/library/matrix/lup_decomposition/u_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/u_spec.rb
@@ -1,18 +1,21 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::LUPDecomposition#u" do
- before :each do
- @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
- @lu = Matrix::LUPDecomposition.new(@a)
- @u = @lu.u
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns the second element of to_a" do
- @u.should == @lu.to_a[1]
- end
+ describe "Matrix::LUPDecomposition#u" do
+ before :each do
+ @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
+ @lu = Matrix::LUPDecomposition.new(@a)
+ @u = @lu.u
+ end
+
+ it "returns the second element of to_a" do
+ @u.should == @lu.to_a[1]
+ end
- it "returns an upper triangular matrix" do
- @u.upper_triangular?.should be_true
+ it "returns an upper triangular matrix" do
+ @u.upper_triangular?.should be_true
+ end
end
end
diff --git a/spec/ruby/library/matrix/map_spec.rb b/spec/ruby/library/matrix/map_spec.rb
index bc07c48cda..cde0df5441 100644
--- a/spec/ruby/library/matrix/map_spec.rb
+++ b/spec/ruby/library/matrix/map_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/collect'
-describe "Matrix#map" do
- it_behaves_like :collect, :map
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/collect'
+
+ describe "Matrix#map" do
+ it_behaves_like :collect, :map
+ end
end
diff --git a/spec/ruby/library/matrix/minor_spec.rb b/spec/ruby/library/matrix/minor_spec.rb
index 009826c3d6..0a6b0823c8 100644
--- a/spec/ruby/library/matrix/minor_spec.rb
+++ b/spec/ruby/library/matrix/minor_spec.rb
@@ -1,85 +1,88 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix#minor" do
- before :each do
- @matrix = Matrix[ [1,2], [3,4], [5,6] ]
- end
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- describe "with start_row, nrows, start_col, ncols" do
- it "returns the given portion of the Matrix" do
- @matrix.minor(0,1,0,2).should == Matrix[ [1, 2] ]
- @matrix.minor(1,2,1,1).should == Matrix[ [4], [6] ]
+ describe "Matrix#minor" do
+ before :each do
+ @matrix = Matrix[ [1,2], [3,4], [5,6] ]
end
- it "returns an empty Matrix if nrows or ncols is 0" do
- @matrix.minor(0,0,0,0).should == Matrix[]
- @matrix.minor(1,0,1,0).should == Matrix[]
- @matrix.minor(1,0,1,1).should == Matrix.columns([[]])
- @matrix.minor(1,1,1,0).should == Matrix[[]]
- end
+ describe "with start_row, nrows, start_col, ncols" do
+ it "returns the given portion of the Matrix" do
+ @matrix.minor(0,1,0,2).should == Matrix[ [1, 2] ]
+ @matrix.minor(1,2,1,1).should == Matrix[ [4], [6] ]
+ end
- it "returns nil for out-of-bounds start_row/col" do
- r = @matrix.row_size + 1
- c = @matrix.column_size + 1
- @matrix.minor(r,0,0,10).should == nil
- @matrix.minor(0,10,c,9).should == nil
- @matrix.minor(-r,0,0,10).should == nil
- @matrix.minor(0,10,-c,9).should == nil
- end
+ it "returns an empty Matrix if nrows or ncols is 0" do
+ @matrix.minor(0,0,0,0).should == Matrix[]
+ @matrix.minor(1,0,1,0).should == Matrix[]
+ @matrix.minor(1,0,1,1).should == Matrix.columns([[]])
+ @matrix.minor(1,1,1,0).should == Matrix[[]]
+ end
- it "returns nil for negative nrows or ncols" do
- @matrix.minor(0,1,0,-1).should == nil
- @matrix.minor(0,-1,0,1).should == nil
- end
+ it "returns nil for out-of-bounds start_row/col" do
+ r = @matrix.row_size + 1
+ c = @matrix.column_size + 1
+ @matrix.minor(r,0,0,10).should == nil
+ @matrix.minor(0,10,c,9).should == nil
+ @matrix.minor(-r,0,0,10).should == nil
+ @matrix.minor(0,10,-c,9).should == nil
+ end
- it "start counting backwards for start_row or start_col below zero" do
- @matrix.minor(0, 1, -1, 1).should == @matrix.minor(0, 1, 1, 1)
- @matrix.minor(-1, 1, 0, 1).should == @matrix.minor(2, 1, 0, 1)
- end
+ it "returns nil for negative nrows or ncols" do
+ @matrix.minor(0,1,0,-1).should == nil
+ @matrix.minor(0,-1,0,1).should == nil
+ end
- it "returns empty matrices for extreme start_row/col" do
- @matrix.minor(3,10,1,10).should == Matrix.columns([[]])
- @matrix.minor(1,10,2,10).should == Matrix[[], []]
- @matrix.minor(3,0,0,10).should == Matrix.columns([[], []])
- end
+ it "start counting backwards for start_row or start_col below zero" do
+ @matrix.minor(0, 1, -1, 1).should == @matrix.minor(0, 1, 1, 1)
+ @matrix.minor(-1, 1, 0, 1).should == @matrix.minor(2, 1, 0, 1)
+ end
- it "ignores big nrows or ncols" do
- @matrix.minor(0,1,0,20).should == Matrix[ [1, 2] ]
- @matrix.minor(1,20,1,1).should == Matrix[ [4], [6] ]
- end
- end
+ it "returns empty matrices for extreme start_row/col" do
+ @matrix.minor(3,10,1,10).should == Matrix.columns([[]])
+ @matrix.minor(1,10,2,10).should == Matrix[[], []]
+ @matrix.minor(3,0,0,10).should == Matrix.columns([[], []])
+ end
- describe "with col_range, row_range" do
- it "returns the given portion of the Matrix" do
- @matrix.minor(0..0, 0..1).should == Matrix[ [1, 2] ]
- @matrix.minor(1..2, 1..2).should == Matrix[ [4], [6] ]
- @matrix.minor(1...3, 1...3).should == Matrix[ [4], [6] ]
+ it "ignores big nrows or ncols" do
+ @matrix.minor(0,1,0,20).should == Matrix[ [1, 2] ]
+ @matrix.minor(1,20,1,1).should == Matrix[ [4], [6] ]
+ end
end
- it "returns nil if col_range or row_range is out of range" do
- r = @matrix.row_size + 1
- c = @matrix.column_size + 1
- @matrix.minor(r..6, c..6).should == nil
- @matrix.minor(0..1, c..6).should == nil
- @matrix.minor(r..6, 0..1).should == nil
- @matrix.minor(-r..6, -c..6).should == nil
- @matrix.minor(0..1, -c..6).should == nil
- @matrix.minor(-r..6, 0..1).should == nil
- end
+ describe "with col_range, row_range" do
+ it "returns the given portion of the Matrix" do
+ @matrix.minor(0..0, 0..1).should == Matrix[ [1, 2] ]
+ @matrix.minor(1..2, 1..2).should == Matrix[ [4], [6] ]
+ @matrix.minor(1...3, 1...3).should == Matrix[ [4], [6] ]
+ end
- it "start counting backwards for col_range or row_range below zero" do
- @matrix.minor(0..1, -2..-1).should == @matrix.minor(0..1, 0..1)
- @matrix.minor(0..1, -2..1).should == @matrix.minor(0..1, 0..1)
- @matrix.minor(-2..-1, 0..1).should == @matrix.minor(1..2, 0..1)
- @matrix.minor(-2..2, 0..1).should == @matrix.minor(1..2, 0..1)
+ it "returns nil if col_range or row_range is out of range" do
+ r = @matrix.row_size + 1
+ c = @matrix.column_size + 1
+ @matrix.minor(r..6, c..6).should == nil
+ @matrix.minor(0..1, c..6).should == nil
+ @matrix.minor(r..6, 0..1).should == nil
+ @matrix.minor(-r..6, -c..6).should == nil
+ @matrix.minor(0..1, -c..6).should == nil
+ @matrix.minor(-r..6, 0..1).should == nil
+ end
+
+ it "start counting backwards for col_range or row_range below zero" do
+ @matrix.minor(0..1, -2..-1).should == @matrix.minor(0..1, 0..1)
+ @matrix.minor(0..1, -2..1).should == @matrix.minor(0..1, 0..1)
+ @matrix.minor(-2..-1, 0..1).should == @matrix.minor(1..2, 0..1)
+ @matrix.minor(-2..2, 0..1).should == @matrix.minor(1..2, 0..1)
+ end
end
- end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.ins.minor(0, 1, 0, 1).should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.ins.minor(0, 1, 0, 1).should be_an_instance_of(MatrixSub)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/minus_spec.rb b/spec/ruby/library/matrix/minus_spec.rb
index 95cf4a6072..27dfbeaea5 100644
--- a/spec/ruby/library/matrix/minus_spec.rb
+++ b/spec/ruby/library/matrix/minus_spec.rb
@@ -1,42 +1,45 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix#-" do
- before :each do
- @a = Matrix[ [1, 2], [3, 4] ]
- @b = Matrix[ [4, 5], [6, 7] ]
- end
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "returns the result of subtracting the corresponding elements of other from self" do
- (@a - @b).should == Matrix[ [-3,-3], [-3,-3] ]
- end
+ describe "Matrix#-" do
+ before :each do
+ @a = Matrix[ [1, 2], [3, 4] ]
+ @b = Matrix[ [4, 5], [6, 7] ]
+ end
- it "returns an instance of Matrix" do
- (@a - @b).should be_kind_of(Matrix)
- end
+ it "returns the result of subtracting the corresponding elements of other from self" do
+ (@a - @b).should == Matrix[ [-3,-3], [-3,-3] ]
+ end
- it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a - Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "returns an instance of Matrix" do
+ (@a - @b).should be_kind_of(Matrix)
+ end
- it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do
- -> { @a - 2 }.should raise_error(Matrix::ErrOperationNotDefined)
- -> { @a - 1.2 }.should raise_error(Matrix::ErrOperationNotDefined)
- -> { @a - bignum_value }.should raise_error(Matrix::ErrOperationNotDefined)
- end
+ it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
+ -> { @a - Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
- it "raises a TypeError if other is of wrong type" do
- -> { @a - nil }.should raise_error(TypeError)
- -> { @a - "a" }.should raise_error(TypeError)
- -> { @a - [ [1, 2] ] }.should raise_error(TypeError)
- -> { @a - Object.new }.should raise_error(TypeError)
- end
+ it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do
+ -> { @a - 2 }.should raise_error(Matrix::ErrOperationNotDefined)
+ -> { @a - 1.2 }.should raise_error(Matrix::ErrOperationNotDefined)
+ -> { @a - bignum_value }.should raise_error(Matrix::ErrOperationNotDefined)
+ end
+
+ it "raises a TypeError if other is of wrong type" do
+ -> { @a - nil }.should raise_error(TypeError)
+ -> { @a - "a" }.should raise_error(TypeError)
+ -> { @a - [ [1, 2] ] }.should raise_error(TypeError)
+ -> { @a - Object.new }.should raise_error(TypeError)
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- m = MatrixSub.ins
- (m-m).should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ m = MatrixSub.ins
+ (m-m).should be_an_instance_of(MatrixSub)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/multiply_spec.rb b/spec/ruby/library/matrix/multiply_spec.rb
index 206868af92..a63fcf4020 100644
--- a/spec/ruby/library/matrix/multiply_spec.rb
+++ b/spec/ruby/library/matrix/multiply_spec.rb
@@ -1,69 +1,71 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
-describe "Matrix#*" do
- before :each do
- @a = Matrix[ [1, 2], [3, 4] ]
- @b = Matrix[ [4, 5], [6, 7] ]
- end
+ describe "Matrix#*" do
+ before :each do
+ @a = Matrix[ [1, 2], [3, 4] ]
+ @b = Matrix[ [4, 5], [6, 7] ]
+ end
- it "returns the result of multiplying the corresponding elements of self and a Matrix" do
- (@a * @b).should == Matrix[ [16,19], [36,43] ]
- end
+ it "returns the result of multiplying the corresponding elements of self and a Matrix" do
+ (@a * @b).should == Matrix[ [16,19], [36,43] ]
+ end
- it "returns the result of multiplying the corresponding elements of self and a Vector" do
- (@a * Vector[1,2]).should == Vector[5, 11]
- end
+ it "returns the result of multiplying the corresponding elements of self and a Vector" do
+ (@a * Vector[1,2]).should == Vector[5, 11]
+ end
- it "returns the result of multiplying the elements of self and a Fixnum" do
- (@a * 2).should == Matrix[ [2, 4], [6, 8] ]
- end
+ it "returns the result of multiplying the elements of self and a Fixnum" do
+ (@a * 2).should == Matrix[ [2, 4], [6, 8] ]
+ end
- it "returns the result of multiplying the elements of self and a Bignum" do
- (@a * bignum_value).should == Matrix[
- [18446744073709551616, 36893488147419103232],
- [55340232221128654848, 73786976294838206464]
- ]
- end
+ it "returns the result of multiplying the elements of self and a Bignum" do
+ (@a * bignum_value).should == Matrix[
+ [18446744073709551616, 36893488147419103232],
+ [55340232221128654848, 73786976294838206464]
+ ]
+ end
- it "returns the result of multiplying the elements of self and a Float" do
- (@a * 2.0).should == Matrix[ [2.0, 4.0], [6.0, 8.0] ]
- end
+ it "returns the result of multiplying the elements of self and a Float" do
+ (@a * 2.0).should == Matrix[ [2.0, 4.0], [6.0, 8.0] ]
+ end
- it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a * Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
+ -> { @a * Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
- it "returns a zero matrix if (nx0) * (0xn)" do
- (Matrix[[],[],[]] * Matrix.columns([[],[],[]])).should == Matrix.zero(3)
- end
+ it "returns a zero matrix if (nx0) * (0xn)" do
+ (Matrix[[],[],[]] * Matrix.columns([[],[],[]])).should == Matrix.zero(3)
+ end
- it "returns an empty matrix if (0xn) * (nx0)" do
- (Matrix.columns([[],[],[]]) * Matrix[[],[],[]]).should == Matrix[]
- end
+ it "returns an empty matrix if (0xn) * (nx0)" do
+ (Matrix.columns([[],[],[]]) * Matrix[[],[],[]]).should == Matrix[]
+ end
- it "returns a mx0 matrix if (mxn) * (nx0)" do
- (Matrix[[1,2],[3,4],[5,6]] * Matrix[[],[]]).should == Matrix[[],[],[]]
- end
+ it "returns a mx0 matrix if (mxn) * (nx0)" do
+ (Matrix[[1,2],[3,4],[5,6]] * Matrix[[],[]]).should == Matrix[[],[],[]]
+ end
- it "returns a 0xm matrix if (0xm) * (mxn)" do
- (Matrix.columns([[], [], []]) * Matrix[[1,2],[3,4],[5,6]]).should == Matrix.columns([[],[]])
- end
+ it "returns a 0xm matrix if (0xm) * (mxn)" do
+ (Matrix.columns([[], [], []]) * Matrix[[1,2],[3,4],[5,6]]).should == Matrix.columns([[],[]])
+ end
- it "raises a TypeError if other is of wrong type" do
- -> { @a * nil }.should raise_error(TypeError)
- -> { @a * "a" }.should raise_error(TypeError)
- -> { @a * [ [1, 2] ] }.should raise_error(TypeError)
- -> { @a * Object.new }.should raise_error(TypeError)
- end
+ it "raises a TypeError if other is of wrong type" do
+ -> { @a * nil }.should raise_error(TypeError)
+ -> { @a * "a" }.should raise_error(TypeError)
+ -> { @a * [ [1, 2] ] }.should raise_error(TypeError)
+ -> { @a * Object.new }.should raise_error(TypeError)
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- m = MatrixSub.ins
- (m*m).should be_an_instance_of(MatrixSub)
- (m*1).should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ m = MatrixSub.ins
+ (m*m).should be_an_instance_of(MatrixSub)
+ (m*1).should be_an_instance_of(MatrixSub)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/new_spec.rb b/spec/ruby/library/matrix/new_spec.rb
index 3005066846..4be2e17116 100644
--- a/spec/ruby/library/matrix/new_spec.rb
+++ b/spec/ruby/library/matrix/new_spec.rb
@@ -1,8 +1,11 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix.new" do
- it "is private" do
- Matrix.should have_private_method(:new)
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix.new" do
+ it "is private" do
+ Matrix.should have_private_method(:new)
+ end
end
end
diff --git a/spec/ruby/library/matrix/normal_spec.rb b/spec/ruby/library/matrix/normal_spec.rb
index a9e6c645fa..2f2e138c1b 100644
--- a/spec/ruby/library/matrix/normal_spec.rb
+++ b/spec/ruby/library/matrix/normal_spec.rb
@@ -1,26 +1,29 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix.normal?" do
- # it "returns false for non normal matrices" do
- # Matrix[[0, 1], [1, 2]].should_not.normal?
- # end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns true for normal matrices" do
- Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should.normal?
- Matrix[[0, Complex(0, 2)], [Complex(0, -2), 0]].should.normal?
- end
+ describe "Matrix.normal?" do
+ # it "returns false for non normal matrices" do
+ # Matrix[[0, 1], [1, 2]].should_not.normal?
+ # end
+
+ it "returns true for normal matrices" do
+ Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should.normal?
+ Matrix[[0, Complex(0, 2)], [Complex(0, -2), 0]].should.normal?
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.normal?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.normal?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/orthogonal_spec.rb b/spec/ruby/library/matrix/orthogonal_spec.rb
index 26afe89ff0..eb06305040 100644
--- a/spec/ruby/library/matrix/orthogonal_spec.rb
+++ b/spec/ruby/library/matrix/orthogonal_spec.rb
@@ -1,26 +1,29 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix.orthogonal?" do
- it "returns false for non orthogonal matrices" do
- Matrix[[0, 1], [1, 2]].should_not.orthogonal?
- Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should_not.orthogonal?
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns true for orthogonal matrices" do
- Matrix[[0, 1], [1, 0]].should.orthogonal?
- end
+ describe "Matrix.orthogonal?" do
+ it "returns false for non orthogonal matrices" do
+ Matrix[[0, 1], [1, 2]].should_not.orthogonal?
+ Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should_not.orthogonal?
+ end
+
+ it "returns true for orthogonal matrices" do
+ Matrix[[0, 1], [1, 0]].should.orthogonal?
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.orthogonal?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.orthogonal?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/permutation_spec.rb b/spec/ruby/library/matrix/permutation_spec.rb
index 825a9d982c..ed8edad755 100644
--- a/spec/ruby/library/matrix/permutation_spec.rb
+++ b/spec/ruby/library/matrix/permutation_spec.rb
@@ -1,32 +1,35 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#permutation?" do
- it "returns true for a permutation Matrix" do
- Matrix[[0, 1, 0], [0, 0, 1], [1, 0, 0]].permutation?.should be_true
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns false for a non permutation square Matrix" do
- Matrix[[0, 1], [0, 0]].permutation?.should be_false
- Matrix[[-1, 0], [0, -1]].permutation?.should be_false
- Matrix[[1, 0], [1, 0]].permutation?.should be_false
- Matrix[[1, 0], [1, 1]].permutation?.should be_false
- end
+ describe "Matrix#permutation?" do
+ it "returns true for a permutation Matrix" do
+ Matrix[[0, 1, 0], [0, 0, 1], [1, 0, 0]].permutation?.should be_true
+ end
- it "returns true for an empty 0x0 matrix" do
- Matrix.empty(0,0).permutation?.should be_true
- end
+ it "returns false for a non permutation square Matrix" do
+ Matrix[[0, 1], [0, 0]].permutation?.should be_false
+ Matrix[[-1, 0], [0, -1]].permutation?.should be_false
+ Matrix[[1, 0], [1, 0]].permutation?.should be_false
+ Matrix[[1, 0], [1, 1]].permutation?.should be_false
+ end
+
+ it "returns true for an empty 0x0 matrix" do
+ Matrix.empty(0,0).permutation?.should be_true
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.permutation?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.permutation?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/plus_spec.rb b/spec/ruby/library/matrix/plus_spec.rb
index 2706bad060..99e6615778 100644
--- a/spec/ruby/library/matrix/plus_spec.rb
+++ b/spec/ruby/library/matrix/plus_spec.rb
@@ -1,42 +1,45 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix#+" do
- before :each do
- @a = Matrix[ [1,2], [3,4] ]
- @b = Matrix[ [4,5], [6,7] ]
- end
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "returns the result of adding the corresponding elements of self and other" do
- (@a + @b).should == Matrix[ [5,7], [9,11] ]
- end
+ describe "Matrix#+" do
+ before :each do
+ @a = Matrix[ [1,2], [3,4] ]
+ @b = Matrix[ [4,5], [6,7] ]
+ end
- it "returns an instance of Matrix" do
- (@a + @b).should be_kind_of(Matrix)
- end
+ it "returns the result of adding the corresponding elements of self and other" do
+ (@a + @b).should == Matrix[ [5,7], [9,11] ]
+ end
- it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a + Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "returns an instance of Matrix" do
+ (@a + @b).should be_kind_of(Matrix)
+ end
- it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do
- -> { @a + 2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
- -> { @a + 1.2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
- -> { @a + bignum_value }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
- end
+ it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
+ -> { @a + Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
- it "raises a TypeError if other is of wrong type" do
- -> { @a + nil }.should raise_error(TypeError)
- -> { @a + "a" }.should raise_error(TypeError)
- -> { @a + [ [1, 2] ] }.should raise_error(TypeError)
- -> { @a + Object.new }.should raise_error(TypeError)
- end
+ it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do
+ -> { @a + 2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
+ -> { @a + 1.2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
+ -> { @a + bignum_value }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
+ end
+
+ it "raises a TypeError if other is of wrong type" do
+ -> { @a + nil }.should raise_error(TypeError)
+ -> { @a + "a" }.should raise_error(TypeError)
+ -> { @a + [ [1, 2] ] }.should raise_error(TypeError)
+ -> { @a + Object.new }.should raise_error(TypeError)
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- m = MatrixSub.ins
- (m+m).should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ m = MatrixSub.ins
+ (m+m).should be_an_instance_of(MatrixSub)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/rank_spec.rb b/spec/ruby/library/matrix/rank_spec.rb
index d4403d23ed..fc795b58c1 100644
--- a/spec/ruby/library/matrix/rank_spec.rb
+++ b/spec/ruby/library/matrix/rank_spec.rb
@@ -1,19 +1,22 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#rank" do
- it "returns the rank of the Matrix" do
- Matrix[ [7,6], [3,9] ].rank.should == 2
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "doesn't loop forever" do
- Matrix[ [1,2,3], [4,5,6], [7,8,9] ].rank.should == 2
- Matrix[ [1, 2, 0, 3], [1, -2, 3, 0], [0, 0, 4, 8], [2, 4, 0, 6] ].rank.
- should == 3
- end
+ describe "Matrix#rank" do
+ it "returns the rank of the Matrix" do
+ Matrix[ [7,6], [3,9] ].rank.should == 2
+ end
+
+ it "doesn't loop forever" do
+ Matrix[ [1,2,3], [4,5,6], [7,8,9] ].rank.should == 2
+ Matrix[ [1, 2, 0, 3], [1, -2, 3, 0], [0, 0, 4, 8], [2, 4, 0, 6] ].rank.
+ should == 3
+ end
- it "works for some easy rectangular matrices" do
- Matrix[[0,0],[0,0],[1,0]].rank.should == 1
- Matrix[[0,1],[0,0],[1,0]].rank.should == 2
+ it "works for some easy rectangular matrices" do
+ Matrix[[0,0],[0,0],[1,0]].rank.should == 1
+ Matrix[[0,1],[0,0],[1,0]].rank.should == 2
+ end
end
end
diff --git a/spec/ruby/library/matrix/real_spec.rb b/spec/ruby/library/matrix/real_spec.rb
index 38033c63c8..63a6bde923 100644
--- a/spec/ruby/library/matrix/real_spec.rb
+++ b/spec/ruby/library/matrix/real_spec.rb
@@ -1,43 +1,46 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix#real?" do
- it "returns true for matrices with all real entries" do
- Matrix[ [1, 2], [3, 4] ].real?.should be_true
- Matrix[ [1.9, 2], [3, 4] ].real?.should be_true
- end
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "returns true for empty matrices" do
- Matrix.empty.real?.should be_true
- end
+ describe "Matrix#real?" do
+ it "returns true for matrices with all real entries" do
+ Matrix[ [1, 2], [3, 4] ].real?.should be_true
+ Matrix[ [1.9, 2], [3, 4] ].real?.should be_true
+ end
- it "returns false if one element is a Complex" do
- Matrix[ [Complex(1,1), 2], [3, 4] ].real?.should be_false
- end
+ it "returns true for empty matrices" do
+ Matrix.empty.real?.should be_true
+ end
- # Guard against the Mathn library
- guard -> { !defined?(Math.rsqrt) } do
- it "returns false if one element is a Complex whose imaginary part is 0" do
- Matrix[ [Complex(1,0), 2], [3, 4] ].real?.should be_false
+ it "returns false if one element is a Complex" do
+ Matrix[ [Complex(1,1), 2], [3, 4] ].real?.should be_false
end
- end
-end
-describe "Matrix#real" do
- it "returns a matrix with the real part of the elements of the receiver" do
- Matrix[ [1, 2], [3, 4] ].real.should == Matrix[ [1, 2], [3, 4] ]
- Matrix[ [1.9, Complex(1,1)], [Complex(-0.42, 0), 4] ].real.should == Matrix[ [1.9, 1], [-0.42, 4] ]
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ it "returns false if one element is a Complex whose imaginary part is 0" do
+ Matrix[ [Complex(1,0), 2], [3, 4] ].real?.should be_false
+ end
+ end
end
- it "returns empty matrices on the same size if empty" do
- Matrix.empty(0, 3).real.should == Matrix.empty(0, 3)
- Matrix.empty(3, 0).real.should == Matrix.empty(3, 0)
- end
+ describe "Matrix#real" do
+ it "returns a matrix with the real part of the elements of the receiver" do
+ Matrix[ [1, 2], [3, 4] ].real.should == Matrix[ [1, 2], [3, 4] ]
+ Matrix[ [1.9, Complex(1,1)], [Complex(-0.42, 0), 4] ].real.should == Matrix[ [1.9, 1], [-0.42, 4] ]
+ end
+
+ it "returns empty matrices on the same size if empty" do
+ Matrix.empty(0, 3).real.should == Matrix.empty(0, 3)
+ Matrix.empty(3, 0).real.should == Matrix.empty(3, 0)
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.ins.real.should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.ins.real.should be_an_instance_of(MatrixSub)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/rect_spec.rb b/spec/ruby/library/matrix/rect_spec.rb
index 83a0404e47..b3b7ac05c9 100644
--- a/spec/ruby/library/matrix/rect_spec.rb
+++ b/spec/ruby/library/matrix/rect_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/rectangular'
-describe "Matrix#rect" do
- it_behaves_like :matrix_rectangular, :rect
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/rectangular'
+
+ describe "Matrix#rect" do
+ it_behaves_like :matrix_rectangular, :rect
+ end
end
diff --git a/spec/ruby/library/matrix/rectangular_spec.rb b/spec/ruby/library/matrix/rectangular_spec.rb
index a235fac640..1fc2e0e60d 100644
--- a/spec/ruby/library/matrix/rectangular_spec.rb
+++ b/spec/ruby/library/matrix/rectangular_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/rectangular'
-describe "Matrix#rectangular" do
- it_behaves_like :matrix_rectangular, :rectangular
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/rectangular'
+
+ describe "Matrix#rectangular" do
+ it_behaves_like :matrix_rectangular, :rectangular
+ end
end
diff --git a/spec/ruby/library/matrix/regular_spec.rb b/spec/ruby/library/matrix/regular_spec.rb
index 3699d0ef8b..f6688bba30 100644
--- a/spec/ruby/library/matrix/regular_spec.rb
+++ b/spec/ruby/library/matrix/regular_spec.rb
@@ -1,31 +1,34 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#regular?" do
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns false for singular matrices" do
- m = Matrix[ [1,2,3], [3,4,3], [0,0,0] ]
- m.regular?.should be_false
+ describe "Matrix#regular?" do
- m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ]
- m.regular?.should be_false
- end
+ it "returns false for singular matrices" do
+ m = Matrix[ [1,2,3], [3,4,3], [0,0,0] ]
+ m.regular?.should be_false
- it "returns true if the Matrix is regular" do
- Matrix[ [0,1], [1,0] ].regular?.should be_true
- end
+ m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ]
+ m.regular?.should be_false
+ end
- it "returns true for an empty 0x0 matrix" do
- Matrix.empty(0,0).regular?.should be_true
- end
+ it "returns true if the Matrix is regular" do
+ Matrix[ [0,1], [1,0] ].regular?.should be_true
+ end
+
+ it "returns true for an empty 0x0 matrix" do
+ Matrix.empty(0,0).regular?.should be_true
+ end
- it "raises an error for rectangular matrices" do
- -> {
- Matrix[[1], [2], [3]].regular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "raises an error for rectangular matrices" do
+ -> {
+ Matrix[[1], [2], [3]].regular?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
- -> {
- Matrix.empty(3,0).regular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> {
+ Matrix.empty(3,0).regular?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
end
end
diff --git a/spec/ruby/library/matrix/round_spec.rb b/spec/ruby/library/matrix/round_spec.rb
index 1dc29df890..db33268414 100644
--- a/spec/ruby/library/matrix/round_spec.rb
+++ b/spec/ruby/library/matrix/round_spec.rb
@@ -1,21 +1,24 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix#round" do
- it "returns a matrix with all entries rounded" do
- Matrix[ [1, 2.34], [5.67, 8] ].round.should == Matrix[ [1, 2], [6, 8] ]
- Matrix[ [1, 2.34], [5.67, 8] ].round(1).should == Matrix[ [1, 2.3], [5.7, 8] ]
- end
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "returns empty matrices on the same size if empty" do
- Matrix.empty(0, 3).round.should == Matrix.empty(0, 3)
- Matrix.empty(3, 0).round(42).should == Matrix.empty(3, 0)
- end
+ describe "Matrix#round" do
+ it "returns a matrix with all entries rounded" do
+ Matrix[ [1, 2.34], [5.67, 8] ].round.should == Matrix[ [1, 2], [6, 8] ]
+ Matrix[ [1, 2.34], [5.67, 8] ].round(1).should == Matrix[ [1, 2.3], [5.7, 8] ]
+ end
+
+ it "returns empty matrices on the same size if empty" do
+ Matrix.empty(0, 3).round.should == Matrix.empty(0, 3)
+ Matrix.empty(3, 0).round(42).should == Matrix.empty(3, 0)
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.ins.round.should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.ins.round.should be_an_instance_of(MatrixSub)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/row_size_spec.rb b/spec/ruby/library/matrix/row_size_spec.rb
index eb3aef2e2f..fca5a846ab 100644
--- a/spec/ruby/library/matrix/row_size_spec.rb
+++ b/spec/ruby/library/matrix/row_size_spec.rb
@@ -1,13 +1,16 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#row_size" do
- it "returns the number rows" do
- Matrix[ [1,2], [3, 4], [5, 6] ].row_size.should == 3
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns the number rows even for some empty matrices" do
- Matrix[ [], [], [] ].row_size.should == 3
- end
+ describe "Matrix#row_size" do
+ it "returns the number rows" do
+ Matrix[ [1,2], [3, 4], [5, 6] ].row_size.should == 3
+ end
+ it "returns the number rows even for some empty matrices" do
+ Matrix[ [], [], [] ].row_size.should == 3
+ end
+
+ end
end
diff --git a/spec/ruby/library/matrix/row_spec.rb b/spec/ruby/library/matrix/row_spec.rb
index 00b1f02a8e..eb05cd9273 100644
--- a/spec/ruby/library/matrix/row_spec.rb
+++ b/spec/ruby/library/matrix/row_spec.rb
@@ -1,36 +1,39 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#row" do
- before :all do
- @m = Matrix[ [1, 2], [2, 3], [3, 4] ]
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns a Vector when called without a block" do
- @m.row(0).should == Vector[1,2]
- end
+ describe "Matrix#row" do
+ before :all do
+ @m = Matrix[ [1, 2], [2, 3], [3, 4] ]
+ end
- it "yields the elements of the row when called with a block" do
- a = []
- @m.row(0) {|x| a << x}
- a.should == [1,2]
- end
+ it "returns a Vector when called without a block" do
+ @m.row(0).should == Vector[1,2]
+ end
- it "counts backwards for negative argument" do
- @m.row(-1).should == Vector[3, 4]
- end
+ it "yields the elements of the row when called with a block" do
+ a = []
+ @m.row(0) {|x| a << x}
+ a.should == [1,2]
+ end
- it "returns self when called with a block" do
- @m.row(0) { |x| x }.should equal(@m)
- end
+ it "counts backwards for negative argument" do
+ @m.row(-1).should == Vector[3, 4]
+ end
- it "returns nil when out of bounds" do
- @m.row(3).should == nil
- @m.row(-4).should == nil
- end
+ it "returns self when called with a block" do
+ @m.row(0) { |x| x }.should equal(@m)
+ end
+
+ it "returns nil when out of bounds" do
+ @m.row(3).should == nil
+ @m.row(-4).should == nil
+ end
- it "never yields when out of bounds" do
- -> { @m.row(3){ raise } }.should_not raise_error
- -> { @m.row(-4){ raise } }.should_not raise_error
+ it "never yields when out of bounds" do
+ -> { @m.row(3){ raise } }.should_not raise_error
+ -> { @m.row(-4){ raise } }.should_not raise_error
+ end
end
end
diff --git a/spec/ruby/library/matrix/row_vector_spec.rb b/spec/ruby/library/matrix/row_vector_spec.rb
index 341437ee05..4c97d6013a 100644
--- a/spec/ruby/library/matrix/row_vector_spec.rb
+++ b/spec/ruby/library/matrix/row_vector_spec.rb
@@ -1,24 +1,27 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix.row_vector" do
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "returns a Matrix" do
- Matrix.row_vector([]).should be_an_instance_of(Matrix)
- end
+ describe "Matrix.row_vector" do
- it "returns a single-row Matrix with the specified values" do
- Matrix.row_vector([1,2]).should == Matrix[ [1,2] ]
- end
+ it "returns a Matrix" do
+ Matrix.row_vector([]).should be_an_instance_of(Matrix)
+ end
- it "returns a 1x0 matrix when called with an empty Array" do
- Matrix.row_vector([]).should == Matrix[ [] ]
- end
+ it "returns a single-row Matrix with the specified values" do
+ Matrix.row_vector([1,2]).should == Matrix[ [1,2] ]
+ end
+
+ it "returns a 1x0 matrix when called with an empty Array" do
+ Matrix.row_vector([]).should == Matrix[ [] ]
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.row_vector([1]).should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.row_vector([1]).should be_an_instance_of(MatrixSub)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/row_vectors_spec.rb b/spec/ruby/library/matrix/row_vectors_spec.rb
index 6f99c439a6..d01a4ca10d 100644
--- a/spec/ruby/library/matrix/row_vectors_spec.rb
+++ b/spec/ruby/library/matrix/row_vectors_spec.rb
@@ -1,26 +1,29 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#row_vectors" do
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- before :each do
- @vectors = Matrix[ [1,2], [3,4] ].row_vectors
- end
+ describe "Matrix#row_vectors" do
- it "returns an Array" do
- Matrix[ [1,2], [3,4] ].row_vectors.should be_an_instance_of(Array)
- end
+ before :each do
+ @vectors = Matrix[ [1,2], [3,4] ].row_vectors
+ end
- it "returns an Array of Vectors" do
- @vectors.all? {|v| v.should be_an_instance_of(Vector)}
- end
+ it "returns an Array" do
+ Matrix[ [1,2], [3,4] ].row_vectors.should be_an_instance_of(Array)
+ end
- it "returns each row as a Vector" do
- @vectors.should == [Vector[1,2], Vector[3,4]]
- end
+ it "returns an Array of Vectors" do
+ @vectors.all? {|v| v.should be_an_instance_of(Vector)}
+ end
+
+ it "returns each row as a Vector" do
+ @vectors.should == [Vector[1,2], Vector[3,4]]
+ end
- it "returns an empty Array for empty matrices" do
- Matrix[].row_vectors.should == []
- Matrix[ [] ].row_vectors.should == [ Vector[] ]
+ it "returns an empty Array for empty matrices" do
+ Matrix[].row_vectors.should == []
+ Matrix[ [] ].row_vectors.should == [ Vector[] ]
+ end
end
end
diff --git a/spec/ruby/library/matrix/rows_spec.rb b/spec/ruby/library/matrix/rows_spec.rb
index 41ba635775..5f0515a37b 100644
--- a/spec/ruby/library/matrix/rows_spec.rb
+++ b/spec/ruby/library/matrix/rows_spec.rb
@@ -1,41 +1,44 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix.rows" do
- before :each do
- @a = [1, 2]
- @b = [3, 4]
- @m = Matrix.rows([@a, @b])
- end
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "returns a Matrix" do
- @m.should be_kind_of(Matrix)
- end
+ describe "Matrix.rows" do
+ before :each do
+ @a = [1, 2]
+ @b = [3, 4]
+ @m = Matrix.rows([@a, @b])
+ end
- it "creates a matrix from argument rows" do
- @m.row(0).to_a.should == @a
- @m.row(1).to_a.should == @b
- end
+ it "returns a Matrix" do
+ @m.should be_kind_of(Matrix)
+ end
- it "copies the original rows by default" do
- @a << 3
- @b << 6
- @m.row(0).should_not equal(@a)
- @m.row(1).should_not equal(@b)
- end
+ it "creates a matrix from argument rows" do
+ @m.row(0).to_a.should == @a
+ @m.row(1).to_a.should == @b
+ end
- it "references the original rows if copy is false" do
- @m_ref = Matrix.rows([@a, @b], false)
- @a << 3
- @b << 6
- @m_ref.row(0).to_a.should == @a
- @m_ref.row(1).to_a.should == @b
- end
+ it "copies the original rows by default" do
+ @a << 3
+ @b << 6
+ @m.row(0).should_not equal(@a)
+ @m.row(1).should_not equal(@b)
+ end
+
+ it "references the original rows if copy is false" do
+ @m_ref = Matrix.rows([@a, @b], false)
+ @a << 3
+ @b << 6
+ @m_ref.row(0).to_a.should == @a
+ @m_ref.row(1).to_a.should == @b
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.rows([[0, 1], [0, 1]]).should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.rows([[0, 1], [0, 1]]).should be_an_instance_of(MatrixSub)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/scalar/Fail_spec.rb b/spec/ruby/library/matrix/scalar/Fail_spec.rb
index 9d8f9bd5e8..4f774eda28 100644
--- a/spec/ruby/library/matrix/scalar/Fail_spec.rb
+++ b/spec/ruby/library/matrix/scalar/Fail_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::Scalar#Fail" do
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::Scalar#Fail" do
+ it "needs to be reviewed for spec completeness"
+ end
end
diff --git a/spec/ruby/library/matrix/scalar/Raise_spec.rb b/spec/ruby/library/matrix/scalar/Raise_spec.rb
index 27e11c1f77..b405b6d6c5 100644
--- a/spec/ruby/library/matrix/scalar/Raise_spec.rb
+++ b/spec/ruby/library/matrix/scalar/Raise_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::Scalar#Raise" do
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::Scalar#Raise" do
+ it "needs to be reviewed for spec completeness"
+ end
end
diff --git a/spec/ruby/library/matrix/scalar/divide_spec.rb b/spec/ruby/library/matrix/scalar/divide_spec.rb
index 5d726943fe..0ef2206bf6 100644
--- a/spec/ruby/library/matrix/scalar/divide_spec.rb
+++ b/spec/ruby/library/matrix/scalar/divide_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::Scalar#/" do
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::Scalar#/" do
+ it "needs to be reviewed for spec completeness"
+ end
end
diff --git a/spec/ruby/library/matrix/scalar/exponent_spec.rb b/spec/ruby/library/matrix/scalar/exponent_spec.rb
index 8e9ef52ff2..87eea283d1 100644
--- a/spec/ruby/library/matrix/scalar/exponent_spec.rb
+++ b/spec/ruby/library/matrix/scalar/exponent_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::Scalar#**" do
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::Scalar#**" do
+ it "needs to be reviewed for spec completeness"
+ end
end
diff --git a/spec/ruby/library/matrix/scalar/included_spec.rb b/spec/ruby/library/matrix/scalar/included_spec.rb
index cb3beb2ecd..bab80e5120 100644
--- a/spec/ruby/library/matrix/scalar/included_spec.rb
+++ b/spec/ruby/library/matrix/scalar/included_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::Scalar.included" do
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::Scalar.included" do
+ it "needs to be reviewed for spec completeness"
+ end
end
diff --git a/spec/ruby/library/matrix/scalar/initialize_spec.rb b/spec/ruby/library/matrix/scalar/initialize_spec.rb
index 23145ad0de..af51562b43 100644
--- a/spec/ruby/library/matrix/scalar/initialize_spec.rb
+++ b/spec/ruby/library/matrix/scalar/initialize_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::Scalar#initialize" do
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::Scalar#initialize" do
+ it "needs to be reviewed for spec completeness"
+ end
end
diff --git a/spec/ruby/library/matrix/scalar/minus_spec.rb b/spec/ruby/library/matrix/scalar/minus_spec.rb
index c727ea1659..966db1d75b 100644
--- a/spec/ruby/library/matrix/scalar/minus_spec.rb
+++ b/spec/ruby/library/matrix/scalar/minus_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::Scalar#-" do
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::Scalar#-" do
+ it "needs to be reviewed for spec completeness"
+ end
end
diff --git a/spec/ruby/library/matrix/scalar/multiply_spec.rb b/spec/ruby/library/matrix/scalar/multiply_spec.rb
index 1a2a83d83e..21caac478b 100644
--- a/spec/ruby/library/matrix/scalar/multiply_spec.rb
+++ b/spec/ruby/library/matrix/scalar/multiply_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::Scalar#*" do
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::Scalar#*" do
+ it "needs to be reviewed for spec completeness"
+ end
end
diff --git a/spec/ruby/library/matrix/scalar/plus_spec.rb b/spec/ruby/library/matrix/scalar/plus_spec.rb
index c94689a702..78cdf9367f 100644
--- a/spec/ruby/library/matrix/scalar/plus_spec.rb
+++ b/spec/ruby/library/matrix/scalar/plus_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Matrix::Scalar#+" do
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix::Scalar#+" do
+ it "needs to be reviewed for spec completeness"
+ end
end
diff --git a/spec/ruby/library/matrix/scalar_spec.rb b/spec/ruby/library/matrix/scalar_spec.rb
index 7fdd64c9d9..1ec64d2d78 100644
--- a/spec/ruby/library/matrix/scalar_spec.rb
+++ b/spec/ruby/library/matrix/scalar_spec.rb
@@ -1,65 +1,68 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix.scalar" do
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- before :each do
- @side = 3
- @value = 8
- @a = Matrix.scalar(@side, @value)
- end
+ describe "Matrix.scalar" do
- it "returns a Matrix" do
- @a.should be_kind_of(Matrix)
- end
+ before :each do
+ @side = 3
+ @value = 8
+ @a = Matrix.scalar(@side, @value)
+ end
- it "returns a n x n matrix" do
- @a.row_size.should == @side
- @a.column_size.should == @side
- end
+ it "returns a Matrix" do
+ @a.should be_kind_of(Matrix)
+ end
- it "initializes diagonal to value" do
- (0...@a.row_size).each do |i|
- @a[i, i].should == @value
+ it "returns a n x n matrix" do
+ @a.row_size.should == @side
+ @a.column_size.should == @side
+ end
+
+ it "initializes diagonal to value" do
+ (0...@a.row_size).each do |i|
+ @a[i, i].should == @value
+ end
end
- end
- it "initializes all non-diagonal values to 0" do
- (0...@a.row_size).each do |i|
- (0...@a.column_size).each do |j|
- if i != j
- @a[i, j].should == 0
+ it "initializes all non-diagonal values to 0" do
+ (0...@a.row_size).each do |i|
+ (0...@a.column_size).each do |j|
+ if i != j
+ @a[i, j].should == 0
+ end
end
end
end
- end
- before :each do
- @side = 3
- @value = 8
- @a = Matrix.scalar(@side, @value)
- end
+ before :each do
+ @side = 3
+ @value = 8
+ @a = Matrix.scalar(@side, @value)
+ end
- it "returns a Matrix" do
- @a.should be_kind_of(Matrix)
- end
+ it "returns a Matrix" do
+ @a.should be_kind_of(Matrix)
+ end
- it "returns a square matrix, where the first argument specifies the side of the square" do
- @a.row_size.should == @side
- @a.column_size.should == @side
- end
+ it "returns a square matrix, where the first argument specifies the side of the square" do
+ @a.row_size.should == @side
+ @a.column_size.should == @side
+ end
- it "puts the second argument in all diagonal values" do
- (0...@a.row_size).each do |i|
- @a[i, i].should == @value
+ it "puts the second argument in all diagonal values" do
+ (0...@a.row_size).each do |i|
+ @a[i, i].should == @value
+ end
end
- end
- it "fills all values not on the main diagonal with 0" do
- (0...@a.row_size).each do |i|
- (0...@a.column_size).each do |j|
- if i != j
- @a[i, j].should == 0
+ it "fills all values not on the main diagonal with 0" do
+ (0...@a.row_size).each do |i|
+ (0...@a.column_size).each do |j|
+ if i != j
+ @a[i, j].should == 0
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/singular_spec.rb b/spec/ruby/library/matrix/singular_spec.rb
index 7bba36a54a..341c2675a8 100644
--- a/spec/ruby/library/matrix/singular_spec.rb
+++ b/spec/ruby/library/matrix/singular_spec.rb
@@ -1,31 +1,34 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#singular?" do
- it "returns true for singular matrices" do
- m = Matrix[ [1,2,3], [3,4,3], [0,0,0] ]
- m.singular?.should be_true
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ]
- m.singular?.should be_true
- end
+ describe "Matrix#singular?" do
+ it "returns true for singular matrices" do
+ m = Matrix[ [1,2,3], [3,4,3], [0,0,0] ]
+ m.singular?.should be_true
- it "returns false if the Matrix is regular" do
- Matrix[ [0,1], [1,0] ].singular?.should be_false
- end
+ m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ]
+ m.singular?.should be_true
+ end
- it "returns false for an empty 0x0 matrix" do
- Matrix.empty(0,0).singular?.should be_false
- end
+ it "returns false if the Matrix is regular" do
+ Matrix[ [0,1], [1,0] ].singular?.should be_false
+ end
- it "raises an error for rectangular matrices" do
- -> {
- Matrix[[1], [2], [3]].singular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "returns false for an empty 0x0 matrix" do
+ Matrix.empty(0,0).singular?.should be_false
+ end
- -> {
- Matrix.empty(3,0).singular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error for rectangular matrices" do
+ -> {
+ Matrix[[1], [2], [3]].singular?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+
+ -> {
+ Matrix.empty(3,0).singular?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
+ end
end
diff --git a/spec/ruby/library/matrix/square_spec.rb b/spec/ruby/library/matrix/square_spec.rb
index 25d2d1ad9c..e678f1c702 100644
--- a/spec/ruby/library/matrix/square_spec.rb
+++ b/spec/ruby/library/matrix/square_spec.rb
@@ -1,28 +1,31 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#square?" do
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns true when the Matrix is square" do
- Matrix[ [1,2], [2,4] ].square?.should be_true
- Matrix[ [100,3,5], [9.5, 4.9, 8], [2,0,77] ].square?.should be_true
- end
+ describe "Matrix#square?" do
- it "returns true when the Matrix has only one element" do
- Matrix[ [9] ].square?.should be_true
- end
+ it "returns true when the Matrix is square" do
+ Matrix[ [1,2], [2,4] ].square?.should be_true
+ Matrix[ [100,3,5], [9.5, 4.9, 8], [2,0,77] ].square?.should be_true
+ end
- it "returns false when the Matrix is rectangular" do
- Matrix[ [1, 2] ].square?.should be_false
- end
+ it "returns true when the Matrix has only one element" do
+ Matrix[ [9] ].square?.should be_true
+ end
- it "returns false when the Matrix is rectangular" do
- Matrix[ [1], [2] ].square?.should be_false
- end
+ it "returns false when the Matrix is rectangular" do
+ Matrix[ [1, 2] ].square?.should be_false
+ end
+
+ it "returns false when the Matrix is rectangular" do
+ Matrix[ [1], [2] ].square?.should be_false
+ end
- it "returns handles empty matrices" do
- Matrix[].square?.should be_true
- Matrix[[]].square?.should be_false
- Matrix.columns([[]]).square?.should be_false
+ it "returns handles empty matrices" do
+ Matrix[].square?.should be_true
+ Matrix[[]].square?.should be_false
+ Matrix.columns([[]]).square?.should be_false
+ end
end
end
diff --git a/spec/ruby/library/matrix/symmetric_spec.rb b/spec/ruby/library/matrix/symmetric_spec.rb
index 6f2a99276a..9eed28ac0d 100644
--- a/spec/ruby/library/matrix/symmetric_spec.rb
+++ b/spec/ruby/library/matrix/symmetric_spec.rb
@@ -1,29 +1,32 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix.symmetric?" do
- it "returns true for a symmetric Matrix" do
- Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, 3), 5, 6]].symmetric?.should be_true
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns true for a 0x0 empty matrix" do
- Matrix.empty.symmetric?.should be_true
- end
+ describe "Matrix.symmetric?" do
+ it "returns true for a symmetric Matrix" do
+ Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, 3), 5, 6]].symmetric?.should be_true
+ end
- it "returns false for an asymmetric Matrix" do
- Matrix[[1, 2],[-2, 1]].symmetric?.should be_false
- end
+ it "returns true for a 0x0 empty matrix" do
+ Matrix.empty.symmetric?.should be_true
+ end
+
+ it "returns false for an asymmetric Matrix" do
+ Matrix[[1, 2],[-2, 1]].symmetric?.should be_false
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.symmetric?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.symmetric?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/t_spec.rb b/spec/ruby/library/matrix/t_spec.rb
index 6f1a5178e0..6eb54371ee 100644
--- a/spec/ruby/library/matrix/t_spec.rb
+++ b/spec/ruby/library/matrix/t_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/transpose'
-describe "Matrix#transpose" do
- it_behaves_like :matrix_transpose, :t
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/transpose'
+
+ describe "Matrix#transpose" do
+ it_behaves_like :matrix_transpose, :t
+ end
end
diff --git a/spec/ruby/library/matrix/to_a_spec.rb b/spec/ruby/library/matrix/to_a_spec.rb
index b5d55c5d67..0222a663ac 100644
--- a/spec/ruby/library/matrix/to_a_spec.rb
+++ b/spec/ruby/library/matrix/to_a_spec.rb
@@ -1,11 +1,14 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#to_a" do
- it "returns the array of arrays that describe the rows of the matrix" do
- Matrix[].to_a.should == []
- Matrix[[]].to_a.should == [[]]
- Matrix[[1]].to_a.should == [[1]]
- Matrix[[1, 2], [3, 4]].to_a.should == [[1, 2],[3, 4]]
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix#to_a" do
+ it "returns the array of arrays that describe the rows of the matrix" do
+ Matrix[].to_a.should == []
+ Matrix[[]].to_a.should == [[]]
+ Matrix[[1]].to_a.should == [[1]]
+ Matrix[[1, 2], [3, 4]].to_a.should == [[1, 2],[3, 4]]
+ end
end
end
diff --git a/spec/ruby/library/matrix/to_s_spec.rb b/spec/ruby/library/matrix/to_s_spec.rb
index f529fe3bcd..7d38655e0d 100644
--- a/spec/ruby/library/matrix/to_s_spec.rb
+++ b/spec/ruby/library/matrix/to_s_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix#to_s" do
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Matrix#to_s" do
+ it "needs to be reviewed for spec completeness"
+ end
end
diff --git a/spec/ruby/library/matrix/tr_spec.rb b/spec/ruby/library/matrix/tr_spec.rb
index e17bd790d7..bbf274bb5e 100644
--- a/spec/ruby/library/matrix/tr_spec.rb
+++ b/spec/ruby/library/matrix/tr_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'shared/trace'
-require 'matrix'
-describe "Matrix#tr" do
- it_behaves_like :trace, :tr
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/trace'
+ require 'matrix'
+
+ describe "Matrix#tr" do
+ it_behaves_like :trace, :tr
+ end
end
diff --git a/spec/ruby/library/matrix/trace_spec.rb b/spec/ruby/library/matrix/trace_spec.rb
index 290e7cb1f7..ac6ce7927d 100644
--- a/spec/ruby/library/matrix/trace_spec.rb
+++ b/spec/ruby/library/matrix/trace_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'shared/trace'
-require 'matrix'
-describe "Matrix#trace" do
- it_behaves_like :trace, :trace
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/trace'
+ require 'matrix'
+
+ describe "Matrix#trace" do
+ it_behaves_like :trace, :trace
+ end
end
diff --git a/spec/ruby/library/matrix/transpose_spec.rb b/spec/ruby/library/matrix/transpose_spec.rb
index 79600dd439..d7f495b946 100644
--- a/spec/ruby/library/matrix/transpose_spec.rb
+++ b/spec/ruby/library/matrix/transpose_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/transpose'
-describe "Matrix#transpose" do
- it_behaves_like :matrix_transpose, :transpose
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/transpose'
+
+ describe "Matrix#transpose" do
+ it_behaves_like :matrix_transpose, :transpose
+ end
end
diff --git a/spec/ruby/library/matrix/unit_spec.rb b/spec/ruby/library/matrix/unit_spec.rb
index 6a41d729c7..439e0d616b 100644
--- a/spec/ruby/library/matrix/unit_spec.rb
+++ b/spec/ruby/library/matrix/unit_spec.rb
@@ -1,6 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'shared/identity'
-describe "Matrix.unit" do
- it_behaves_like :matrix_identity, :unit
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/identity'
+
+ describe "Matrix.unit" do
+ it_behaves_like :matrix_identity, :unit
+ end
end
diff --git a/spec/ruby/library/matrix/unitary_spec.rb b/spec/ruby/library/matrix/unitary_spec.rb
index c214ee9b2f..b579cb244d 100644
--- a/spec/ruby/library/matrix/unitary_spec.rb
+++ b/spec/ruby/library/matrix/unitary_spec.rb
@@ -1,32 +1,36 @@
require_relative '../../spec_helper'
-require 'matrix'
+ruby_version_is ""..."3.1" do
+ require 'matrix'
-describe "Matrix.unitary?" do
- it "returns false for non unitary matrices" do
- Matrix[[0, 1], [1, 2]].should_not.unitary?
- Matrix[[0, Complex(0, 2)], [Complex(0, 2), 0]].should_not.unitary?
- Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should_not.unitary?
- end
+ describe "Matrix.unitary?" do
+ it "returns false for non unitary matrices" do
+ Matrix[[0, 1], [1, 2]].should_not.unitary?
+ Matrix[[0, Complex(0, 2)], [Complex(0, 2), 0]].should_not.unitary?
+ Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should_not.unitary?
+ end
- it "returns true for unitary matrices" do
- Matrix[[0, Complex(0, 1)], [Complex(0, 1), 0]].should.unitary?
- end
+ it "returns true for unitary matrices" do
+ Matrix[[0, Complex(0, 1)], [Complex(0, 1), 0]].should.unitary?
+ end
- it "returns true for unitary matrices with a Complex and a negative #imag" do
- Matrix[[0, Complex(0, 1)], [Complex(0, -1), 0]].should.unitary?
- end
+ version_is((Matrix::const_defined?(:VERSION) ? Matrix::VERSION : "0.1.0"), "0.3.0") do
+ it "returns true for unitary matrices with a Complex and a negative #imag" do
+ Matrix[[0, Complex(0, 1)], [Complex(0, -1), 0]].should.unitary?
+ end
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.unitary?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.unitary?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/upper_triangular_spec.rb b/spec/ruby/library/matrix/upper_triangular_spec.rb
index 2514294a80..cc2aeb7233 100644
--- a/spec/ruby/library/matrix/upper_triangular_spec.rb
+++ b/spec/ruby/library/matrix/upper_triangular_spec.rb
@@ -1,24 +1,27 @@
require_relative '../../spec_helper'
-require 'matrix'
-describe "Matrix.upper_triangular?" do
- it "returns true for an upper triangular Matrix" do
- Matrix[[1, 2, 3], [0, 2, 3], [0, 0, 3]].upper_triangular?.should be_true
- Matrix.diagonal([1, 2, 3]).upper_triangular?.should be_true
- Matrix[[1, 2], [0, 2], [0, 0], [0, 0]].upper_triangular?.should be_true
- Matrix[[1, 2, 3, 4], [0, 2, 3, 4]].upper_triangular?.should be_true
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns false for a non upper triangular square Matrix" do
- Matrix[[0, 0], [1, 0]].upper_triangular?.should be_false
- Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].upper_triangular?.should be_false
- Matrix[[0, 0], [0, 0], [0, 0], [0, 1]].upper_triangular?.should be_false
- Matrix[[0, 0, 0, 0], [1, 0, 0, 0]].upper_triangular?.should be_false
- end
+ describe "Matrix.upper_triangular?" do
+ it "returns true for an upper triangular Matrix" do
+ Matrix[[1, 2, 3], [0, 2, 3], [0, 0, 3]].upper_triangular?.should be_true
+ Matrix.diagonal([1, 2, 3]).upper_triangular?.should be_true
+ Matrix[[1, 2], [0, 2], [0, 0], [0, 0]].upper_triangular?.should be_true
+ Matrix[[1, 2, 3, 4], [0, 2, 3, 4]].upper_triangular?.should be_true
+ end
+
+ it "returns false for a non upper triangular square Matrix" do
+ Matrix[[0, 0], [1, 0]].upper_triangular?.should be_false
+ Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].upper_triangular?.should be_false
+ Matrix[[0, 0], [0, 0], [0, 0], [0, 1]].upper_triangular?.should be_false
+ Matrix[[0, 0, 0, 0], [1, 0, 0, 0]].upper_triangular?.should be_false
+ end
- it "returns true for an empty matrix" do
- Matrix.empty(3,0).upper_triangular?.should be_true
- Matrix.empty(0,3).upper_triangular?.should be_true
- Matrix.empty(0,0).upper_triangular?.should be_true
+ it "returns true for an empty matrix" do
+ Matrix.empty(3,0).upper_triangular?.should be_true
+ Matrix.empty(0,3).upper_triangular?.should be_true
+ Matrix.empty(0,0).upper_triangular?.should be_true
+ end
end
end
diff --git a/spec/ruby/library/matrix/vector/cross_product_spec.rb b/spec/ruby/library/matrix/vector/cross_product_spec.rb
index c2698ade4c..88523824cd 100644
--- a/spec/ruby/library/matrix/vector/cross_product_spec.rb
+++ b/spec/ruby/library/matrix/vector/cross_product_spec.rb
@@ -1,14 +1,17 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Vector#cross_product" do
- it "returns the cross product of a vector" do
- Vector[1, 2, 3].cross_product(Vector[0, -4, 5]).should == Vector[22, -5, -4]
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Vector#cross_product" do
+ it "returns the cross product of a vector" do
+ Vector[1, 2, 3].cross_product(Vector[0, -4, 5]).should == Vector[22, -5, -4]
+ end
- it "raises an error unless both vectors have dimension 3" do
- -> {
- Vector[1, 2, 3].cross_product(Vector[0, -4])
- }.should raise_error(Vector::ErrDimensionMismatch)
+ it "raises an error unless both vectors have dimension 3" do
+ -> {
+ Vector[1, 2, 3].cross_product(Vector[0, -4])
+ }.should raise_error(Vector::ErrDimensionMismatch)
+ end
end
end
diff --git a/spec/ruby/library/matrix/vector/each2_spec.rb b/spec/ruby/library/matrix/vector/each2_spec.rb
index 10d2fc404d..bdd6966472 100644
--- a/spec/ruby/library/matrix/vector/each2_spec.rb
+++ b/spec/ruby/library/matrix/vector/each2_spec.rb
@@ -1,49 +1,52 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Vector.each2" do
- before :all do
- @v = Vector[1, 2, 3]
- @v2 = Vector[4, 5, 6]
- end
-
- it "requires one argument" do
- -> { @v.each2(@v2, @v2){} }.should raise_error(ArgumentError)
- -> { @v.each2(){} }.should raise_error(ArgumentError)
- end
-
- describe "given one argument" do
- it "accepts an Array argument" do
- a = []
- @v.each2([7, 8, 9]){|x, y| a << x << y}
- a.should == [1, 7, 2, 8, 3, 9]
- end
-
- it "raises a DimensionMismatch error if the Vector size is different" do
- -> { @v.each2(Vector[1,2]){} }.should raise_error(Vector::ErrDimensionMismatch)
- -> { @v.each2(Vector[1,2,3,4]){} }.should raise_error(Vector::ErrDimensionMismatch)
- end
-
- it "yields arguments in sequence" do
- a = []
- @v.each2(@v2){|first, second| a << [first, second]}
- a.should == [[1, 4], [2, 5], [3, 6]]
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "yield arguments in pairs" do
- a = []
- @v.each2(@v2){|*pair| a << pair}
- a.should == [[1, 4], [2, 5], [3, 6]]
+ describe "Vector.each2" do
+ before :all do
+ @v = Vector[1, 2, 3]
+ @v2 = Vector[4, 5, 6]
end
- it "returns self when given a block" do
- @v.each2(@v2){}.should equal(@v)
+ it "requires one argument" do
+ -> { @v.each2(@v2, @v2){} }.should raise_error(ArgumentError)
+ -> { @v.each2(){} }.should raise_error(ArgumentError)
end
- it "returns an enumerator if no block given" do
- enum = @v.each2(@v2)
- enum.should be_an_instance_of(Enumerator)
- enum.to_a.should == [[1, 4], [2, 5], [3, 6]]
+ describe "given one argument" do
+ it "accepts an Array argument" do
+ a = []
+ @v.each2([7, 8, 9]){|x, y| a << x << y}
+ a.should == [1, 7, 2, 8, 3, 9]
+ end
+
+ it "raises a DimensionMismatch error if the Vector size is different" do
+ -> { @v.each2(Vector[1,2]){} }.should raise_error(Vector::ErrDimensionMismatch)
+ -> { @v.each2(Vector[1,2,3,4]){} }.should raise_error(Vector::ErrDimensionMismatch)
+ end
+
+ it "yields arguments in sequence" do
+ a = []
+ @v.each2(@v2){|first, second| a << [first, second]}
+ a.should == [[1, 4], [2, 5], [3, 6]]
+ end
+
+ it "yield arguments in pairs" do
+ a = []
+ @v.each2(@v2){|*pair| a << pair}
+ a.should == [[1, 4], [2, 5], [3, 6]]
+ end
+
+ it "returns self when given a block" do
+ @v.each2(@v2){}.should equal(@v)
+ end
+
+ it "returns an enumerator if no block given" do
+ enum = @v.each2(@v2)
+ enum.should be_an_instance_of(Enumerator)
+ enum.to_a.should == [[1, 4], [2, 5], [3, 6]]
+ end
end
end
end
diff --git a/spec/ruby/library/matrix/vector/eql_spec.rb b/spec/ruby/library/matrix/vector/eql_spec.rb
index eb2451b550..fa086bd33a 100644
--- a/spec/ruby/library/matrix/vector/eql_spec.rb
+++ b/spec/ruby/library/matrix/vector/eql_spec.rb
@@ -1,16 +1,19 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Vector#eql?" do
- before do
- @vector = Vector[1, 2, 3, 4, 5]
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns true for self" do
- @vector.eql?(@vector).should be_true
- end
+ describe "Vector#eql?" do
+ before do
+ @vector = Vector[1, 2, 3, 4, 5]
+ end
+
+ it "returns true for self" do
+ @vector.eql?(@vector).should be_true
+ end
- it "returns false when there are a pair corresponding elements which are not equal in the sense of Kernel#eql?" do
- @vector.eql?(Vector[1, 2, 3, 4, 5.0]).should be_false
+ it "returns false when there are a pair corresponding elements which are not equal in the sense of Kernel#eql?" do
+ @vector.eql?(Vector[1, 2, 3, 4, 5.0]).should be_false
+ end
end
end
diff --git a/spec/ruby/library/matrix/vector/inner_product_spec.rb b/spec/ruby/library/matrix/vector/inner_product_spec.rb
index 1cf8771e04..95dc4806b5 100644
--- a/spec/ruby/library/matrix/vector/inner_product_spec.rb
+++ b/spec/ruby/library/matrix/vector/inner_product_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Vector#inner_product" do
- it "returns the inner product of a vector" do
- Vector[1, 2, 3].inner_product(Vector[0, -4, 5]).should == 7
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
- it "returns 0 for empty vectors" do
- Vector[].inner_product(Vector[]).should == 0
- end
+ describe "Vector#inner_product" do
+ it "returns the inner product of a vector" do
+ Vector[1, 2, 3].inner_product(Vector[0, -4, 5]).should == 7
+ end
- it "raises an error for mismatched vectors" do
- -> {
- Vector[1, 2, 3].inner_product(Vector[0, -4])
- }.should raise_error(Vector::ErrDimensionMismatch)
- end
+ it "returns 0 for empty vectors" do
+ Vector[].inner_product(Vector[]).should == 0
+ end
+
+ it "raises an error for mismatched vectors" do
+ -> {
+ Vector[1, 2, 3].inner_product(Vector[0, -4])
+ }.should raise_error(Vector::ErrDimensionMismatch)
+ end
- it "uses the conjugate of its argument" do
- Vector[Complex(1,2)].inner_product(Vector[Complex(3,4)]).should == Complex(11, 2)
+ it "uses the conjugate of its argument" do
+ Vector[Complex(1,2)].inner_product(Vector[Complex(3,4)]).should == Complex(11, 2)
+ end
end
end
diff --git a/spec/ruby/library/matrix/vector/normalize_spec.rb b/spec/ruby/library/matrix/vector/normalize_spec.rb
index 527c9260de..7345e11fa4 100644
--- a/spec/ruby/library/matrix/vector/normalize_spec.rb
+++ b/spec/ruby/library/matrix/vector/normalize_spec.rb
@@ -1,18 +1,21 @@
require_relative '../../../spec_helper'
-require 'matrix'
-describe "Vector#normalize" do
- it "returns a normalized copy of the vector" do
- x = 0.2672612419124244
- Vector[1, 2, 3].normalize.should == Vector[x, x * 2, x * 3]
- end
+ruby_version_is ""..."3.1" do
+ require 'matrix'
+
+ describe "Vector#normalize" do
+ it "returns a normalized copy of the vector" do
+ x = 0.2672612419124244
+ Vector[1, 2, 3].normalize.should == Vector[x, x * 2, x * 3]
+ end
- it "raises an error for zero vectors" do
- -> {
- Vector[].normalize
- }.should raise_error(Vector::ZeroVectorError)
- -> {
- Vector[0, 0, 0].normalize
- }.should raise_error(Vector::ZeroVectorError)
+ it "raises an error for zero vectors" do
+ -> {
+ Vector[].normalize
+ }.should raise_error(Vector::ZeroVectorError)
+ -> {
+ Vector[0, 0, 0].normalize
+ }.should raise_error(Vector::ZeroVectorError)
+ end
end
end
diff --git a/spec/ruby/library/matrix/zero_spec.rb b/spec/ruby/library/matrix/zero_spec.rb
index 68e8567c26..80162a03d0 100644
--- a/spec/ruby/library/matrix/zero_spec.rb
+++ b/spec/ruby/library/matrix/zero_spec.rb
@@ -1,52 +1,55 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require 'matrix'
-describe "Matrix.zero" do
- it "returns an object of type Matrix" do
- Matrix.zero(3).should be_kind_of(Matrix)
- end
+ruby_version_is ""..."3.1" do
+ require_relative 'fixtures/classes'
+ require 'matrix'
- it "creates a n x n matrix" do
- m3 = Matrix.zero(3)
- m3.row_size.should == 3
- m3.column_size.should == 3
+ describe "Matrix.zero" do
+ it "returns an object of type Matrix" do
+ Matrix.zero(3).should be_kind_of(Matrix)
+ end
- m8 = Matrix.zero(8)
- m8.row_size.should == 8
- m8.column_size.should == 8
- end
+ it "creates a n x n matrix" do
+ m3 = Matrix.zero(3)
+ m3.row_size.should == 3
+ m3.column_size.should == 3
- it "initializes all cells to 0" do
- size = 10
- m = Matrix.zero(size)
+ m8 = Matrix.zero(8)
+ m8.row_size.should == 8
+ m8.column_size.should == 8
+ end
- (0...size).each do |i|
- (0...size).each do |j|
- m[i, j].should == 0
+ it "initializes all cells to 0" do
+ size = 10
+ m = Matrix.zero(size)
+
+ (0...size).each do |i|
+ (0...size).each do |j|
+ m[i, j].should == 0
+ end
end
end
- end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.zero(3).should be_an_instance_of(MatrixSub)
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.zero(3).should be_an_instance_of(MatrixSub)
+ end
end
end
-end
-describe "Matrix.zero?" do
- it "returns true for empty matrices" do
- Matrix.empty.should.zero?
- Matrix.empty(3,0).should.zero?
- Matrix.empty(0,3).should.zero?
- end
+ describe "Matrix.zero?" do
+ it "returns true for empty matrices" do
+ Matrix.empty.should.zero?
+ Matrix.empty(3,0).should.zero?
+ Matrix.empty(0,3).should.zero?
+ end
- it "returns true for matrices with zero entries" do
- Matrix.zero(2,3).should.zero?
- end
+ it "returns true for matrices with zero entries" do
+ Matrix.zero(2,3).should.zero?
+ end
- it "returns false for matrices with non zero entries" do
- Matrix[[1]].should_not.zero?
+ it "returns false for matrices with non zero entries" do
+ Matrix[[1]].should_not.zero?
+ end
end
end
diff --git a/spec/ruby/library/monitor/exit_spec.rb b/spec/ruby/library/monitor/exit_spec.rb
deleted file mode 100644
index 952ad9525d..0000000000
--- a/spec/ruby/library/monitor/exit_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../spec_helper'
-require 'monitor'
-
-describe "Monitor#exit" do
- it "raises ThreadError when monitor is not entered" do
- m = Monitor.new
-
- -> { m.exit }.should raise_error(ThreadError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/FTPError_spec.rb b/spec/ruby/library/net-ftp/FTPError_spec.rb
deleted file mode 100644
index 0c31b65dcc..0000000000
--- a/spec/ruby/library/net-ftp/FTPError_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require 'net/ftp'
-
-describe "Net::FTPError" do
- it "is an Exception" do
- Net::FTPError.should < Exception
- end
-end
diff --git a/spec/ruby/library/net-ftp/FTPPermError_spec.rb b/spec/ruby/library/net-ftp/FTPPermError_spec.rb
deleted file mode 100644
index b43e12c503..0000000000
--- a/spec/ruby/library/net-ftp/FTPPermError_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../spec_helper'
-require 'net/ftp'
-
-describe "Net::FTPPermError" do
- it "is an Exception" do
- Net::FTPPermError.should < Exception
- end
-
- it "is a subclass of Net::FTPError" do
- Net::FTPPermError.should < Net::FTPError
- end
-end
diff --git a/spec/ruby/library/net-ftp/FTPProtoError_spec.rb b/spec/ruby/library/net-ftp/FTPProtoError_spec.rb
deleted file mode 100644
index e7abbc0dd8..0000000000
--- a/spec/ruby/library/net-ftp/FTPProtoError_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../spec_helper'
-require 'net/ftp'
-
-describe "Net::FTPProtoError" do
- it "is an Exception" do
- Net::FTPProtoError.should < Exception
- end
-
- it "is a subclass of Net::FTPError" do
- Net::FTPPermError.should < Net::FTPError
- end
-end
diff --git a/spec/ruby/library/net-ftp/FTPReplyError_spec.rb b/spec/ruby/library/net-ftp/FTPReplyError_spec.rb
deleted file mode 100644
index fcc7501fc1..0000000000
--- a/spec/ruby/library/net-ftp/FTPReplyError_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../spec_helper'
-require 'net/ftp'
-
-describe "Net::FTPReplyError" do
- it "is an Exception" do
- Net::FTPReplyError.should < Exception
- end
-
- it "is a subclass of Net::FTPError" do
- Net::FTPPermError.should < Net::FTPError
- end
-end
diff --git a/spec/ruby/library/net-ftp/FTPTempError_spec.rb b/spec/ruby/library/net-ftp/FTPTempError_spec.rb
deleted file mode 100644
index f4b045dfb5..0000000000
--- a/spec/ruby/library/net-ftp/FTPTempError_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../spec_helper'
-require 'net/ftp'
-
-describe "Net::FTPTempError" do
- it "is an Exception" do
- Net::FTPTempError.should < Exception
- end
-
- it "is a subclass of Net::FTPError" do
- Net::FTPPermError.should < Net::FTPError
- end
-end
diff --git a/spec/ruby/library/net-ftp/abort_spec.rb b/spec/ruby/library/net-ftp/abort_spec.rb
deleted file mode 100644
index 335d056512..0000000000
--- a/spec/ruby/library/net-ftp/abort_spec.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#abort" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the ABOR command to the server" do
- -> { @ftp.abort }.should_not raise_error
- end
-
- it "ignores the response" do
- @ftp.abort
- @ftp.last_response.should == "220 Dummy FTP Server ready!\n"
- end
-
- it "returns the full response" do
- @ftp.abort.should == "226 Closing data connection. (ABOR)\n"
- end
-
- it "does not raise any error when the response code is 225" do
- @server.should_receive(:abor).and_respond("225 Data connection open; no transfer in progress.")
- -> { @ftp.abort }.should_not raise_error
- end
-
- it "does not raise any error when the response code is 226" do
- @server.should_receive(:abor).and_respond("226 Closing data connection.")
- -> { @ftp.abort }.should_not raise_error
- end
-
- it "raises a Net::FTPProtoError when the response code is 500" do
- @server.should_receive(:abor).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPProtoError when the response code is 501" do
- @server.should_receive(:abor).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPProtoError when the response code is 502" do
- @server.should_receive(:abor).and_respond("502 Command not implemented.")
- -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPProtoError when the response code is 421" do
- @server.should_receive(:abor).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/acct_spec.rb b/spec/ruby/library/net-ftp/acct_spec.rb
deleted file mode 100644
index ab093448a2..0000000000
--- a/spec/ruby/library/net-ftp/acct_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#acct" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "writes the ACCT command to the server" do
- @ftp.acct("my_account")
- @ftp.last_response.should == "230 User 'my_account' logged in, proceed. (ACCT)\n"
- end
-
- it "returns nil" do
- @ftp.acct("my_account").should == nil
- end
-
- it "does not raise any error when the response code is 230" do
- @server.should_receive(:acct).and_respond("230 User logged in, proceed.")
- -> { @ftp.acct("my_account") }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:acct).and_respond("530 Not logged in.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:acct).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:acct).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 503" do
- @server.should_receive(:acct).and_respond("503 Bad sequence of commands.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:acct).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPTempError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/binary_spec.rb b/spec/ruby/library/net-ftp/binary_spec.rb
deleted file mode 100644
index 1e0585b795..0000000000
--- a/spec/ruby/library/net-ftp/binary_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-
-describe "Net::FTP#binary" do
- it "returns true when self is in binary mode" do
- ftp = Net::FTP.new
- ftp.binary.should be_true
-
- ftp.binary = false
- ftp.binary.should be_false
- end
-end
-
-describe "Net::FTP#binary=" do
- it "sets self to binary mode when passed true" do
- ftp = Net::FTP.new
-
- ftp.binary = true
- ftp.binary.should be_true
-
- ftp.binary = false
- ftp.binary.should be_false
- end
-end
diff --git a/spec/ruby/library/net-ftp/chdir_spec.rb b/spec/ruby/library/net-ftp/chdir_spec.rb
deleted file mode 100644
index cc129b5e42..0000000000
--- a/spec/ruby/library/net-ftp/chdir_spec.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#chdir" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- describe "when switching to the parent directory" do
- it "sends the 'CDUP' command to the server" do
- @ftp.chdir("..")
- @ftp.last_response.should == "200 Command okay. (CDUP)\n"
- end
-
- it "returns nil" do
- @ftp.chdir("..").should be_nil
- end
-
- it "does not raise a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:cdup).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.chdir("..") }.should_not raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:cdup).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:cdup).and_respond("502 Command not implemented.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:cdup).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:cdup).and_respond("530 Not logged in.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:cdup).and_respond("550 Requested action not taken.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
- end
- end
-
- it "writes the 'CWD' command with the passed directory to the socket" do
- @ftp.chdir("test")
- @ftp.last_response.should == "200 Command okay. (CWD test)\n"
- end
-
- it "returns nil" do
- @ftp.chdir("test").should be_nil
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:cwd).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:cwd).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:cwd).and_respond("502 Command not implemented.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:cwd).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:cwd).and_respond("530 Not logged in.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:cwd).and_respond("550 Requested action not taken.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/close_spec.rb b/spec/ruby/library/net-ftp/close_spec.rb
deleted file mode 100644
index 183f14a84b..0000000000
--- a/spec/ruby/library/net-ftp/close_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-
-describe "Net::FTP#close" do
- before :each do
- @socket = mock("Socket")
- @socket.stub!(:closed?).and_return(false)
- @socket.stub!(:read_timeout).and_return(60)
- @socket.stub!(:read_timeout=).and_return(3)
-
- @ftp = Net::FTP.new
- @ftp.instance_variable_set(:@sock, @socket)
- end
-
- it "closes the socket" do
- @socket.should_receive(:close)
- @ftp.close.should be_nil
- end
-
- it "does not try to close the socket if it has already been closed" do
- @socket.should_receive(:closed?).and_return(true)
- @socket.should_not_receive(:close)
- @ftp.close.should be_nil
- end
-
- it "does not try to close the socket if it is nil" do
- @ftp.instance_variable_set(:@sock, nil)
- @ftp.close.should be_nil
- end
-end
diff --git a/spec/ruby/library/net-ftp/closed_spec.rb b/spec/ruby/library/net-ftp/closed_spec.rb
deleted file mode 100644
index 84001cdc0f..0000000000
--- a/spec/ruby/library/net-ftp/closed_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-
-describe "Net::FTP#closed?" do
- before :each do
- @socket = mock("Socket")
-
- @ftp = Net::FTP.new
- @ftp.instance_variable_set(:@sock, @socket)
- end
-
- it "returns true when the socket is closed" do
- @socket.should_receive(:closed?).and_return(true)
- @ftp.closed?.should be_true
- end
-
- it "returns true when the socket is nil" do
- @ftp.instance_variable_set(:@sock, nil)
- @ftp.closed?.should be_true
- end
-end
diff --git a/spec/ruby/library/net-ftp/connect_spec.rb b/spec/ruby/library/net-ftp/connect_spec.rb
deleted file mode 100644
index 4330d430b4..0000000000
--- a/spec/ruby/library/net-ftp/connect_spec.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-# TODO: Add specs for using the SOCKSSocket
-describe "Net::FTP#connect" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- end
-
- after :each do
- @server.connect_message = nil
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "tries to connect to the FTP Server on the given host and port" do
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should_not raise_error
- end
-
- it "returns nil" do
- @ftp.connect(@server.hostname, @server.server_port).should be_nil
- end
-
- ruby_version_is ""..."3.1" do
- it "prints a small debug line when in debug mode" do
- @ftp.debug_mode = true
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should output(/connect: #{@server.hostname}, #{@server.server_port}\nget: 220 Dummy FTP Server ready!/)
- @ftp.debug_mode = false
- end
- end
-
- it "does not raise any error when the response code is 220" do
- @server.connect_message = "220 Dummy FTP Server ready!"
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should_not raise_error
- end
-
- it "raises a Net::FTPReplyError when the response code is 120" do
- @server.connect_message = "120 Service ready in nnn minutes."
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should raise_error(Net::FTPReplyError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.connect_message = "421 Service not available, closing control connection."
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should raise_error(Net::FTPTempError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/debug_mode_spec.rb b/spec/ruby/library/net-ftp/debug_mode_spec.rb
deleted file mode 100644
index f2ef53c089..0000000000
--- a/spec/ruby/library/net-ftp/debug_mode_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-
-describe "Net::FTP#debug_mode" do
- it "returns true when self is in debug mode" do
- ftp = Net::FTP.new
- ftp.debug_mode.should be_false
-
- ftp.debug_mode = true
- ftp.debug_mode.should be_true
- end
-end
-
-describe "Net::FTP#debug_mode=" do
- it "sets self into debug mode when passed true" do
- ftp = Net::FTP.new
- ftp.debug_mode = true
- ftp.debug_mode.should be_true
-
- ftp.debug_mode = false
- ftp.debug_mode.should be_false
- end
-end
diff --git a/spec/ruby/library/net-ftp/default_passive_spec.rb b/spec/ruby/library/net-ftp/default_passive_spec.rb
deleted file mode 100644
index 3f14f6187e..0000000000
--- a/spec/ruby/library/net-ftp/default_passive_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-
-describe "Net::FTP#default_passive" do
- it "is true by default" do
- ruby_exe(fixture(__FILE__, "default_passive.rb")).should == "true\ntrue\n"
- end
-end
diff --git a/spec/ruby/library/net-ftp/delete_spec.rb b/spec/ruby/library/net-ftp/delete_spec.rb
deleted file mode 100644
index bfb7da1ffe..0000000000
--- a/spec/ruby/library/net-ftp/delete_spec.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#delete" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the DELE command with the passed filename to the server" do
- @ftp.delete("test.file")
- @ftp.last_response.should == "250 Requested file action okay, completed. (DELE test.file)\n"
- end
-
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:dele).and_respond("450 Requested file action not taken.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:dele).and_respond("550 Requested action not taken.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:dele).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:dele).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:dele).and_respond("502 Command not implemented.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:dele).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:dele).and_respond("530 Not logged in.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/dir_spec.rb b/spec/ruby/library/net-ftp/dir_spec.rb
deleted file mode 100644
index 894f03dd7b..0000000000
--- a/spec/ruby/library/net-ftp/dir_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/list'
-
-describe "Net::FTP#dir" do
- it_behaves_like :net_ftp_list, :dir
-end
diff --git a/spec/ruby/library/net-ftp/get_spec.rb b/spec/ruby/library/net-ftp/get_spec.rb
deleted file mode 100644
index 1bc1bd744b..0000000000
--- a/spec/ruby/library/net-ftp/get_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/gettextfile'
-require_relative 'shared/getbinaryfile'
-
-describe "Net::FTP#get (binary mode)" do
- before :each do
- @binary_mode = true
- end
-
- it_behaves_like :net_ftp_getbinaryfile, :get
-end
-
-describe "Net::FTP#get (text mode)" do
- before :each do
- @binary_mode = false
- end
-
- it_behaves_like :net_ftp_gettextfile, :get
-end
diff --git a/spec/ruby/library/net-ftp/getbinaryfile_spec.rb b/spec/ruby/library/net-ftp/getbinaryfile_spec.rb
deleted file mode 100644
index e9898fccc7..0000000000
--- a/spec/ruby/library/net-ftp/getbinaryfile_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/getbinaryfile'
-
-describe "Net::FTP#getbinaryfile" do
- it_behaves_like :net_ftp_getbinaryfile, :getbinaryfile
-end
diff --git a/spec/ruby/library/net-ftp/getdir_spec.rb b/spec/ruby/library/net-ftp/getdir_spec.rb
deleted file mode 100644
index 756d6a23af..0000000000
--- a/spec/ruby/library/net-ftp/getdir_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'shared/pwd'
-
-describe "Net::FTP#getdir" do
- it_behaves_like :net_ftp_pwd, :getdir
-end
diff --git a/spec/ruby/library/net-ftp/gettextfile_spec.rb b/spec/ruby/library/net-ftp/gettextfile_spec.rb
deleted file mode 100644
index cdd1b4c797..0000000000
--- a/spec/ruby/library/net-ftp/gettextfile_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/gettextfile'
-
-describe "Net::FTP#gettextfile" do
- it_behaves_like :net_ftp_gettextfile, :gettextfile
-end
diff --git a/spec/ruby/library/net-ftp/help_spec.rb b/spec/ruby/library/net-ftp/help_spec.rb
deleted file mode 100644
index c562be50b2..0000000000
--- a/spec/ruby/library/net-ftp/help_spec.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#help" do
- def with_connection
- yield
- end
-
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "writes the HELP command to the server" do
- @ftp.help
- @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
- end
-
- it "returns the server's response" do
- @ftp.help.should == "211 System status, or system help reply. (HELP)\n"
- end
-
- it "writes the HELP command with an optional parameter to the socket" do
- @ftp.help("some parameter").should == "211 System status, or system help reply. (HELP some parameter)\n"
- end
-
- it "does not raise any error when the response code is 211" do
- @server.should_receive(:help).and_respond("211 System status, or system help reply.")
- -> { @ftp.help }.should_not raise_error
- end
-
- it "does not raise any error when the response code is 214" do
- @server.should_receive(:help).and_respond("214 Help message.")
- -> { @ftp.help }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.help }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:help).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.help }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:help).and_respond("502 Command not implemented.")
- -> { @ftp.help }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:help).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.help }.should raise_error(Net::FTPTempError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/initialize_spec.rb b/spec/ruby/library/net-ftp/initialize_spec.rb
deleted file mode 100644
index 4d775e8dc1..0000000000
--- a/spec/ruby/library/net-ftp/initialize_spec.rb
+++ /dev/null
@@ -1,405 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-
-describe "Net::FTP#initialize" do
- before :each do
- @ftp = Net::FTP.allocate
- @ftp.stub!(:connect)
- @port_args = []
- @port_args << 21
- end
-
- it "is private" do
- Net::FTP.should have_private_instance_method(:initialize)
- end
-
- it "sets self into binary mode" do
- @ftp.binary.should be_nil
- @ftp.send(:initialize)
- @ftp.binary.should be_true
- end
-
- it "sets self into active mode" do
- @ftp.passive.should be_nil
- @ftp.send(:initialize)
- @ftp.passive.should be_false
- end
-
- it "sets self into non-debug mode" do
- @ftp.debug_mode.should be_nil
- @ftp.send(:initialize)
- @ftp.debug_mode.should be_false
- end
-
- it "sets self to not resume file uploads/downloads" do
- @ftp.resume.should be_nil
- @ftp.send(:initialize)
- @ftp.resume.should be_false
- end
-
- describe "when passed no arguments" do
- it "does not try to connect" do
- @ftp.should_not_receive(:connect)
- @ftp.send(:initialize)
- end
- end
-
- describe "when passed host" do
- it "tries to connect to the passed host" do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
- @ftp.send(:initialize, "localhost")
- end
- end
-
- describe "when passed host, user" do
- it "tries to connect to the passed host" do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
- @ftp.send(:initialize, "localhost")
- end
-
- it "tries to login with the passed username" do
- @ftp.should_receive(:login).with("rubyspec", nil, nil)
- @ftp.send(:initialize, "localhost", "rubyspec")
- end
- end
-
- describe "when passed host, user, password" do
- it "tries to connect to the passed host" do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
- @ftp.send(:initialize, "localhost")
- end
-
- it "tries to login with the passed username and password" do
- @ftp.should_receive(:login).with("rubyspec", "rocks", nil)
- @ftp.send(:initialize, "localhost", "rubyspec", "rocks")
- end
- end
-
- describe "when passed host, user" do
- it "tries to connect to the passed host" do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
- @ftp.send(:initialize, "localhost")
- end
-
- it "tries to login with the passed username, password and account" do
- @ftp.should_receive(:login).with("rubyspec", "rocks", "account")
- @ftp.send(:initialize, "localhost", "rubyspec", "rocks", "account")
- end
- end
-
- before :each do
- @ftp.stub!(:login)
- end
-
- describe 'when the host' do
- describe 'is set' do
- describe 'and port option' do
- describe 'is set' do
- it 'tries to connect to the host on the specified port' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ port: 8080 })
- @ftp.should_receive(:connect).with('localhost', 8080)
-
- @ftp.send(:initialize, 'localhost', options)
- end
- end
-
- describe 'is not set' do
- it 'tries to connect to the host without a port' do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
-
- @ftp.send(:initialize, 'localhost')
- end
- end
- end
-
- describe 'when the username option' do
- describe 'is set' do
- describe 'and the password option' do
- describe 'is set' do
- describe 'and the account option' do
- describe 'is set' do
- it 'tries to log in with the supplied parameters' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ username: 'a', password: 'topsecret', account: 'b' })
- @ftp.should_receive(:login).with('a', 'topsecret', 'b')
-
- @ftp.send(:initialize, 'localhost', options)
- end
- end
-
- describe 'is unset' do
- it 'tries to log in with the supplied parameters' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ username: 'a', password: 'topsecret' })
- @ftp.should_receive(:login).with('a', 'topsecret', nil)
-
- @ftp.send(:initialize, 'localhost', options)
- end
- end
- end
- end
-
- describe 'is unset' do
- describe 'and the account option' do
- describe 'is set' do
- it 'tries to log in with the supplied parameters' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ username: 'a', account: 'b' })
- @ftp.should_receive(:login).with('a', nil, 'b')
-
- @ftp.send(:initialize, 'localhost', options)
- end
- end
-
- describe 'is unset' do
- it 'tries to log in with the supplied parameters' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ username: 'a'})
- @ftp.should_receive(:login).with('a', nil, nil)
-
- @ftp.send(:initialize, 'localhost', options)
- end
- end
- end
- end
- end
- end
-
- describe 'is not set' do
- it 'does not try to log in' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({})
- @ftp.should_not_receive(:login)
-
- @ftp.send(:initialize, 'localhost', options)
- end
- end
- end
- end
-
- describe 'is unset' do
- it 'does not try to connect' do
- @ftp.should_not_receive(:connect)
-
- @ftp.send(:initialize)
- end
-
- it 'does not try to log in' do
- @ftp.should_not_receive(:login)
-
- @ftp.send(:initialize)
- end
- end
- end
-
- describe 'when the passive option' do
- describe 'is set' do
- describe 'to true' do
- it 'sets passive to true' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ passive: true })
-
- @ftp.send(:initialize, nil, options)
- @ftp.passive.should == true
- end
- end
-
- describe 'to false' do
- it 'sets passive to false' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ passive: false })
-
- @ftp.send(:initialize, nil, options)
- @ftp.passive.should == false
- end
- end
- end
-
- describe 'is unset' do
- it 'sets passive to false' do
- @ftp.send(:initialize)
- @ftp.passive.should == false
- end
- end
- end
-
- describe 'when the debug_mode option' do
- describe 'is set' do
- describe 'to true' do
- it 'sets debug_mode to true' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ debug_mode: true })
-
- @ftp.send(:initialize, nil, options)
- @ftp.debug_mode.should == true
- end
- end
-
- describe 'to false' do
- it 'sets debug_mode to false' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ debug_mode: false })
-
- @ftp.send(:initialize, nil, options)
- @ftp.debug_mode.should == false
- end
- end
- end
-
- describe 'is unset' do
- it 'sets debug_mode to false' do
- @ftp.send(:initialize)
- @ftp.debug_mode.should == false
- end
- end
- end
-
- describe 'when the open_timeout option' do
- describe 'is set' do
- it 'sets open_timeout to the specified value' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ open_timeout: 42 })
-
- @ftp.send(:initialize, nil, options)
- @ftp.open_timeout.should == 42
- end
- end
-
- describe 'is not set' do
- it 'sets open_timeout to nil' do
- @ftp.send(:initialize)
- @ftp.open_timeout.should == nil
- end
- end
- end
-
- describe 'when the read_timeout option' do
- describe 'is set' do
- it 'sets read_timeout to the specified value' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ read_timeout: 100 })
-
- @ftp.send(:initialize, nil, options)
- @ftp.read_timeout.should == 100
- end
- end
-
- describe 'is not set' do
- it 'sets read_timeout to the default value' do
- @ftp.send(:initialize)
- @ftp.read_timeout.should == 60
- end
- end
- end
-
- describe 'when the ssl_handshake_timeout option' do
- describe 'is set' do
- it 'sets ssl_handshake_timeout to the specified value' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl_handshake_timeout: 23 })
-
- @ftp.send(:initialize, nil, options)
- @ftp.ssl_handshake_timeout.should == 23
- end
- end
-
- describe 'is not set' do
- it 'sets ssl_handshake_timeout to nil' do
- @ftp.send(:initialize)
- @ftp.ssl_handshake_timeout.should == nil
- end
- end
- end
-
- describe 'when the ssl option' do
- describe 'is set' do
- describe "and the ssl option's value is true" do
- it 'initializes ssl_context to a blank SSLContext object' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl: true })
-
- ssl_context = OpenSSL::SSL::SSLContext.allocate
- ssl_context.stub!(:set_params)
-
- OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ssl_context)
- ssl_context.should_receive(:set_params).with({})
-
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@ssl_context).should == ssl_context
- end
- end
-
- describe "and the ssl option's value is a hash" do
- it 'initializes ssl_context to a configured SSLContext object' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl: {key: 'value'} })
-
- ssl_context = OpenSSL::SSL::SSLContext.allocate
- ssl_context.stub!(:set_params)
-
- OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ssl_context)
- ssl_context.should_receive(:set_params).with({key: 'value'})
-
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@ssl_context).should == ssl_context
- end
- end
-
- describe 'and private_data_connection' do
- describe 'is set' do
- it 'sets private_data_connection to that value' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl: true, private_data_connection: 'true' })
-
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@private_data_connection).should == 'true'
- end
- end
-
- describe 'is not set' do
- it 'sets private_data_connection to nil' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl: true })
-
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@private_data_connection).should == true
- end
- end
- end
- end
-
- describe 'is not set' do
- it 'sets ssl_context to nil' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({})
-
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@ssl_context).should == nil
- end
-
- describe 'private_data_connection' do
- describe 'is set' do
- it 'raises an ArgumentError' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ private_data_connection: true })
-
- -> {
- @ftp.send(:initialize, nil, options)
- }.should raise_error(ArgumentError, /private_data_connection can be set to true only when ssl is enabled/)
- end
- end
-
- describe 'is not set' do
- it 'sets private_data_connection to false' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({})
-
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@private_data_connection).should == false
- end
- end
- end
- end
- end
-end
diff --git a/spec/ruby/library/net-ftp/last_response_code_spec.rb b/spec/ruby/library/net-ftp/last_response_code_spec.rb
deleted file mode 100644
index c17c28f0f8..0000000000
--- a/spec/ruby/library/net-ftp/last_response_code_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'shared/last_response_code'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#last_response_code" do
- it_behaves_like :net_ftp_last_response_code, :last_response_code
-end
diff --git a/spec/ruby/library/net-ftp/last_response_spec.rb b/spec/ruby/library/net-ftp/last_response_spec.rb
deleted file mode 100644
index c9d9d70f35..0000000000
--- a/spec/ruby/library/net-ftp/last_response_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#last_response" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "returns the last response" do
- @ftp.last_response.should == "220 Dummy FTP Server ready!\n"
- @ftp.help
- @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
- end
-end
diff --git a/spec/ruby/library/net-ftp/lastresp_spec.rb b/spec/ruby/library/net-ftp/lastresp_spec.rb
deleted file mode 100644
index e0c1b862a0..0000000000
--- a/spec/ruby/library/net-ftp/lastresp_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'shared/last_response_code'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#lastresp" do
- it_behaves_like :net_ftp_last_response_code, :lastresp
-end
diff --git a/spec/ruby/library/net-ftp/list_spec.rb b/spec/ruby/library/net-ftp/list_spec.rb
deleted file mode 100644
index 6cb1bbc4b8..0000000000
--- a/spec/ruby/library/net-ftp/list_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/list'
-
-describe "Net::FTP#list" do
- it_behaves_like :net_ftp_list, :list
-end
diff --git a/spec/ruby/library/net-ftp/login_spec.rb b/spec/ruby/library/net-ftp/login_spec.rb
deleted file mode 100644
index 0de2f5cc63..0000000000
--- a/spec/ruby/library/net-ftp/login_spec.rb
+++ /dev/null
@@ -1,195 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#login" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- describe "when passed no arguments" do
- it "sends the USER command with 'anonymous' as name to the server" do
- @ftp.login
- @server.login_user.should == "anonymous"
- end
-
- it "sends 'anonymous@' as a password when required" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @ftp.login
- @server.login_pass.should == "anonymous@"
- end
-
- it "raises a Net::FTPReplyError when the server requests an account" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- -> { @ftp.login }.should raise_error(Net::FTPReplyError)
- end
- end
-
- describe "when passed name" do
- it "sends the USER command with the passed name to the server" do
- @ftp.login("rubyspec")
- @server.login_user.should == "rubyspec"
- end
-
- it "raises a Net::FTPReplyError when the server requests a password, but none was given" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- -> { @ftp.login("rubyspec") }.should raise_error(Net::FTPReplyError)
- end
-
- it "raises a Net::FTPReplyError when the server requests an account, but none was given" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- -> { @ftp.login("rubyspec") }.should raise_error(Net::FTPReplyError)
- end
- end
-
- describe "when passed name, password" do
- it "sends the USER command with the passed name to the server" do
- @ftp.login("rubyspec", "rocks")
- @server.login_user.should == "rubyspec"
- end
-
- it "sends the passed password when required" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @ftp.login("rubyspec", "rocks")
- @server.login_pass.should == "rocks"
- end
-
- it "raises a Net::FTPReplyError when the server requests an account" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- -> { @ftp.login("rubyspec", "rocks") }.should raise_error(Net::FTPReplyError)
- end
- end
-
- describe "when passed name, password, account" do
- it "sends the USER command with the passed name to the server" do
- @ftp.login("rubyspec", "rocks", "account")
- @server.login_user.should == "rubyspec"
- end
-
- it "sends the passed password when required" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @ftp.login("rubyspec", "rocks", "account")
- @server.login_pass.should == "rocks"
- end
-
- it "sends the passed account when required" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- @ftp.login("rubyspec", "rocks", "account")
- @server.login_acct.should == "account"
- end
- end
-
- describe "when the USER command fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:user).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:user).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:user).and_respond("502 Command not implemented.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:user).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:user).and_respond("530 Not logged in.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when the PASS command fails" do
- before :each do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- end
-
- it "does not raise an Error when the response code is 202" do
- @server.should_receive(:pass).and_respond("202 Command not implemented, superfluous at this site.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:pass).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:pass).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:pass).and_respond("502 Command not implemented.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:pass).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:pass).and_respond("530 Not logged in.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when the ACCT command fails" do
- before :each do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- end
-
- it "does not raise an Error when the response code is 202" do
- @server.should_receive(:acct).and_respond("202 Command not implemented, superfluous at this site.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:acct).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:acct).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:acct).and_respond("502 Command not implemented.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:acct).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:acct).and_respond("530 Not logged in.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net-ftp/ls_spec.rb b/spec/ruby/library/net-ftp/ls_spec.rb
deleted file mode 100644
index acd7e9e523..0000000000
--- a/spec/ruby/library/net-ftp/ls_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/list'
-
-describe "Net::FTP#ls" do
- it_behaves_like :net_ftp_list, :ls
-end
diff --git a/spec/ruby/library/net-ftp/mdtm_spec.rb b/spec/ruby/library/net-ftp/mdtm_spec.rb
deleted file mode 100644
index a504507c84..0000000000
--- a/spec/ruby/library/net-ftp/mdtm_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#mdtm" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the MDTM with the passed filename command to the server" do
- @ftp.mdtm("test.file")
- @ftp.last_response.should == "213 19980705132316\n"
- end
-
- it "returns the last modification time of the passed file" do
- @ftp.mdtm("test.file").should == "19980705132316"
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:mdtm).and_respond("550 Requested action not taken.")
- -> { @ftp.mdtm("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:mdtm).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.mdtm("test.file") }.should raise_error(Net::FTPTempError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/mkdir_spec.rb b/spec/ruby/library/net-ftp/mkdir_spec.rb
deleted file mode 100644
index 8cc6ae785e..0000000000
--- a/spec/ruby/library/net-ftp/mkdir_spec.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#mkdir" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the MKD command with the passed pathname to the server" do
- @ftp.mkdir("test.folder")
- @ftp.last_response.should == %{257 "test.folder" created.\n}
- end
-
- it "returns the path to the newly created directory" do
- @ftp.mkdir("test.folder").should == "test.folder"
- @ftp.mkdir("/absolute/path/to/test.folder").should == "/absolute/path/to/test.folder"
- @ftp.mkdir("relative/path/to/test.folder").should == "relative/path/to/test.folder"
- @ftp.mkdir('/usr/dm/foo"bar').should == '/usr/dm/foo"bar'
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:mkd).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:mkd).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:mkd).and_respond("502 Command not implemented.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:mkd).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:mkd).and_respond("530 Not logged in.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:mkd).and_respond("550 Requested action not taken.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/mtime_spec.rb b/spec/ruby/library/net-ftp/mtime_spec.rb
deleted file mode 100644
index 9dde1278a8..0000000000
--- a/spec/ruby/library/net-ftp/mtime_spec.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#mtime" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the MDTM with the passed filename command to the server" do
- @ftp.mtime("test.file")
- @ftp.last_response.should == "213 19980705132316\n"
- end
-
- describe "when passed filename" do
- it "returns the last modification time of the passed file as a Time object in the local time" do
- @ftp.mtime("test.file").should == Time.gm("1998", "07", "05", "13", "23", "16")
- end
- end
-
- describe "when passed filename, local_time" do
- it "returns the last modification time as a Time object in UTC when local_time is true" do
- @ftp.mtime("test.file", true).should == Time.local("1998", "07", "05", "13", "23", "16")
- end
-
- it "returns the last modification time as a Time object in the local time when local_time is false" do
- @ftp.mtime("test.file", false).should == Time.gm("1998", "07", "05", "13", "23", "16")
- end
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:mdtm).and_respond("550 Requested action not taken.")
- -> { @ftp.mtime("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:mdtm).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.mtime("test.file") }.should raise_error(Net::FTPTempError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/nlst_spec.rb b/spec/ruby/library/net-ftp/nlst_spec.rb
deleted file mode 100644
index 2f22543af6..0000000000
--- a/spec/ruby/library/net-ftp/nlst_spec.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#nlst" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.passive = false
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- describe "when passed no arguments" do
- it "returns an Array containing a list of files in the current dir" do
- @ftp.nlst.should == ["last_response_code.rb", "list.rb", "pwd.rb"]
- @ftp.last_response.should == "226 transfer complete (NLST)\n"
- end
- end
-
- describe "when passed dir" do
- it "returns an Array containing a list of files in the passed dir" do
- @ftp.nlst("test.folder").should == ["last_response_code.rb", "list.rb", "pwd.rb"]
- @ftp.last_response.should == "226 transfer complete (NLST test.folder)\n"
- end
- end
-
- describe "when the NLST command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:nlst).and_respond("450 Requested file action not taken..")
- -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:nlst).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:nlst).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:nlst).and_respond("502 Command not implemented.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:nlst).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:nlst).and_respond("530 Not logged in.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net-ftp/noop_spec.rb b/spec/ruby/library/net-ftp/noop_spec.rb
deleted file mode 100644
index 4743a39ef6..0000000000
--- a/spec/ruby/library/net-ftp/noop_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#noop" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the NOOP command to the server" do
- @ftp.noop
- @ftp.last_response.should == "200 Command okay. (NOOP)\n"
- end
-
- it "returns nil" do
- @ftp.noop.should be_nil
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:noop).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.noop }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:noop).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.noop }.should raise_error(Net::FTPTempError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/open_spec.rb b/spec/ruby/library/net-ftp/open_spec.rb
deleted file mode 100644
index e59496dc3c..0000000000
--- a/spec/ruby/library/net-ftp/open_spec.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-
-describe "Net::FTP.open" do
- before :each do
- @ftp = mock("Net::FTP instance")
- Net::FTP.stub!(:new).and_return(@ftp)
- end
-
- describe "when passed no block" do
- it "returns a new Net::FTP instance" do
- Net::FTP.open("localhost").should equal(@ftp)
- end
-
- it "passes the passed arguments down to Net::FTP.new" do
- Net::FTP.should_receive(:new).with("localhost", "user", "password", "account")
- Net::FTP.open("localhost", "user", "password", "account")
- end
- end
-
- describe "when passed a block" do
- before :each do
- @ftp.stub!(:close)
- end
-
- it "yields a new Net::FTP instance to the passed block" do
- yielded = false
- Net::FTP.open("localhost") do |ftp|
- yielded = true
- ftp.should equal(@ftp)
- end
- yielded.should be_true
- end
-
- it "closes the Net::FTP instance after yielding" do
- Net::FTP.open("localhost") do |ftp|
- ftp.should_receive(:close)
- end
- end
-
- it "closes the Net::FTP instance even if an exception is raised while yielding" do
- begin
- Net::FTP.open("localhost") do |ftp|
- ftp.should_receive(:close)
- raise ArgumentError, "some exception"
- end
- rescue ArgumentError
- end
- end
-
- it "returns the block's return value" do
- Net::FTP.open("localhost") { :test }.should == :test
- end
- end
-end
diff --git a/spec/ruby/library/net-ftp/passive_spec.rb b/spec/ruby/library/net-ftp/passive_spec.rb
deleted file mode 100644
index 97659f1b68..0000000000
--- a/spec/ruby/library/net-ftp/passive_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-
-describe "Net::FTP#passive" do
- it "returns true when self is in passive mode" do
- ftp = Net::FTP.new
- ftp.passive.should be_false
-
- ftp.passive = true
- ftp.passive.should be_true
- end
-
- it "is the value of Net::FTP.default_value by default" do
- ruby_exe(fixture(__FILE__, "passive.rb")).should == "true"
- end
-end
-
-describe "Net::FTP#passive=" do
- it "sets self to passive mode when passed true" do
- ftp = Net::FTP.new
-
- ftp.passive = true
- ftp.passive.should be_true
-
- ftp.passive = false
- ftp.passive.should be_false
- end
-end
diff --git a/spec/ruby/library/net-ftp/put_spec.rb b/spec/ruby/library/net-ftp/put_spec.rb
deleted file mode 100644
index 6d40d3d5b9..0000000000
--- a/spec/ruby/library/net-ftp/put_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/puttextfile'
-require_relative 'shared/putbinaryfile'
-
-describe "Net::FTP#put (binary mode)" do
- before :each do
- @binary_mode = true
- end
-
- it_behaves_like :net_ftp_putbinaryfile, :put
-end
-
-describe "Net::FTP#put (text mode)" do
- before :each do
- @binary_mode = false
- end
-
- it_behaves_like :net_ftp_puttextfile, :put
-end
diff --git a/spec/ruby/library/net-ftp/putbinaryfile_spec.rb b/spec/ruby/library/net-ftp/putbinaryfile_spec.rb
deleted file mode 100644
index d0398229e5..0000000000
--- a/spec/ruby/library/net-ftp/putbinaryfile_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/putbinaryfile'
-
-describe "Net::FTP#putbinaryfile" do
- it_behaves_like :net_ftp_putbinaryfile, :putbinaryfile
-end
diff --git a/spec/ruby/library/net-ftp/puttextfile_spec.rb b/spec/ruby/library/net-ftp/puttextfile_spec.rb
deleted file mode 100644
index b8bcac33df..0000000000
--- a/spec/ruby/library/net-ftp/puttextfile_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-require_relative 'shared/puttextfile'
-
-describe "Net::FTP#puttextfile" do
- it_behaves_like :net_ftp_puttextfile, :puttextfile
-end
diff --git a/spec/ruby/library/net-ftp/pwd_spec.rb b/spec/ruby/library/net-ftp/pwd_spec.rb
deleted file mode 100644
index 992e2c4ed2..0000000000
--- a/spec/ruby/library/net-ftp/pwd_spec.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#pwd" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the PWD command to the server" do
- @ftp.pwd
- @ftp.last_response.should == "257 \"/some/dir/\" - current directory\n"
- end
-
- it "returns the current directory" do
- @ftp.pwd.should == "/some/dir/"
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:pwd).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:pwd).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:pwd).and_respond("502 Command not implemented.")
- -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:pwd).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.pwd }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:pwd).and_respond("550 Requested action not taken.")
- -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/quit_spec.rb b/spec/ruby/library/net-ftp/quit_spec.rb
deleted file mode 100644
index c5352ceada..0000000000
--- a/spec/ruby/library/net-ftp/quit_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#quit" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the QUIT command to the server" do
- @ftp.quit
- @ftp.last_response.should == "221 OK, bye\n"
- end
-
- it "does not close the socket automatically" do
- @ftp.quit
- @ftp.closed?.should be_false
- end
-
- it "returns nil" do
- @ftp.quit.should be_nil
- end
-end
diff --git a/spec/ruby/library/net-ftp/rename_spec.rb b/spec/ruby/library/net-ftp/rename_spec.rb
deleted file mode 100644
index 48f81b7deb..0000000000
--- a/spec/ruby/library/net-ftp/rename_spec.rb
+++ /dev/null
@@ -1,94 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#rename" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- describe "when passed from_name, to_name" do
- it "sends the RNFR command with the passed from_name and the RNTO command with the passed to_name to the server" do
- @ftp.rename("from.file", "to.file")
- @ftp.last_response.should == "250 Requested file action okay, completed. (Renamed from.file to to.file)\n"
- end
-
- it "returns something" do
- @ftp.rename("from.file", "to.file").should be_nil
- end
- end
-
- describe "when the RNFR command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:rnfr).and_respond("450 Requested file action not taken.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:rnfr).and_respond("550 Requested action not taken.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:rnfr).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:rnfr).and_respond("502 Command not implemented.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:rnfr).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:rnfr).and_respond("530 Not logged in.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when the RNTO command fails" do
- it "raises a Net::FTPPermError when the response code is 532" do
- @server.should_receive(:rnfr).and_respond("532 Need account for storing files.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 553" do
- @server.should_receive(:rnto).and_respond("553 Requested action not taken.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:rnto).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:rnto).and_respond("502 Command not implemented.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:rnto).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:rnto).and_respond("530 Not logged in.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net-ftp/resume_spec.rb b/spec/ruby/library/net-ftp/resume_spec.rb
deleted file mode 100644
index 6592fc5bb0..0000000000
--- a/spec/ruby/library/net-ftp/resume_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-
-describe "Net::FTP#resume" do
- it "returns true when self is set to resume uploads/downloads" do
- ftp = Net::FTP.new
- ftp.resume.should be_false
-
- ftp.resume = true
- ftp.resume.should be_true
- end
-end
-
-describe "Net::FTP#resume=" do
- it "sets self to resume uploads/downloads when set to true" do
- ftp = Net::FTP.new
- ftp.resume = true
- ftp.resume.should be_true
-
- ftp.resume = false
- ftp.resume.should be_false
- end
-end
diff --git a/spec/ruby/library/net-ftp/retrbinary_spec.rb b/spec/ruby/library/net-ftp/retrbinary_spec.rb
deleted file mode 100644
index de024208aa..0000000000
--- a/spec/ruby/library/net-ftp/retrbinary_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#retrbinary" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the passed command to the server" do
- @ftp.retrbinary("RETR test", 4096) {}
- @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
- end
-
- it "yields the received content as binary blocks of the passed size" do
- res = []
- @ftp.retrbinary("RETR test", 10) { |bin| res << bin }
- res.should == [ "This is th", "e content\n", "of the fil", "e named 't", "est'.\n" ]
- end
-end
diff --git a/spec/ruby/library/net-ftp/retrlines_spec.rb b/spec/ruby/library/net-ftp/retrlines_spec.rb
deleted file mode 100644
index 866ecb5f40..0000000000
--- a/spec/ruby/library/net-ftp/retrlines_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#retrlines" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the passed command over the socket" do
- @ftp.retrlines("LIST test.dir") {}
- @ftp.last_response.should == "226 transfer complete (LIST test.dir)\n"
- end
-
- it "yields each received line to the passed block" do
- res = []
- @ftp.retrlines("LIST test.dir") { |x| res << x }
- res.should == [
- "-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb",
- "-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb",
- "-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb"
- ]
- end
-end
diff --git a/spec/ruby/library/net-ftp/return_code_spec.rb b/spec/ruby/library/net-ftp/return_code_spec.rb
deleted file mode 100644
index 35a6232f7e..0000000000
--- a/spec/ruby/library/net-ftp/return_code_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-
-describe "Net::FTP#return_code" do
- before :each do
- @ftp = Net::FTP.new
- end
-
- it "outputs a warning and returns a newline" do
- -> do
- @ftp.return_code.should == "\n"
- end.should complain(/warning: Net::FTP#return_code is obsolete and do nothing/)
- end
-end
-
-describe "Net::FTP#return_code=" do
- before :each do
- @ftp = Net::FTP.new
- end
-
- it "outputs a warning" do
- -> { @ftp.return_code = 123 }.should complain(/warning: Net::FTP#return_code= is obsolete and do nothing/)
- end
-end
diff --git a/spec/ruby/library/net-ftp/rmdir_spec.rb b/spec/ruby/library/net-ftp/rmdir_spec.rb
deleted file mode 100644
index 400874d60d..0000000000
--- a/spec/ruby/library/net-ftp/rmdir_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#rmdir" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the RMD command with the passed pathname to the server" do
- @ftp.rmdir("test.folder")
- @ftp.last_response.should == "250 Requested file action okay, completed. (RMD test.folder)\n"
- end
-
- it "returns nil" do
- @ftp.rmdir("test.folder").should be_nil
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:rmd).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:rmd).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:rmd).and_respond("502 Command not implemented.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:rmd).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:rmd).and_respond("530 Not logged in.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:rmd).and_respond("550 Requested action not taken.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/sendcmd_spec.rb b/spec/ruby/library/net-ftp/sendcmd_spec.rb
deleted file mode 100644
index c50b373869..0000000000
--- a/spec/ruby/library/net-ftp/sendcmd_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#sendcmd" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the passed command to the server" do
- @ftp.sendcmd("HELP")
- @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
- end
-
- it "returns the server's response" do
- @ftp.sendcmd("HELP").should == "211 System status, or system help reply. (HELP)\n"
- end
-
- it "raises no error when the response code is 1xx, 2xx or 3xx" do
- @server.should_receive(:help).and_respond("120 Service ready in nnn minutes.")
- -> { @ftp.sendcmd("HELP") }.should_not raise_error
-
- @server.should_receive(:help).and_respond("200 Command okay.")
- -> { @ftp.sendcmd("HELP") }.should_not raise_error
-
- @server.should_receive(:help).and_respond("350 Requested file action pending further information.")
- -> { @ftp.sendcmd("HELP") }.should_not raise_error
- end
-
- it "raises a Net::FTPTempError when the response code is 4xx" do
- @server.should_receive(:help).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 5xx" do
- @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPProtoError when the response code is not between 1xx-5xx" do
- @server.should_receive(:help).and_respond("999 Invalid response.")
- -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPProtoError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/set_socket_spec.rb b/spec/ruby/library/net-ftp/set_socket_spec.rb
deleted file mode 100644
index 8182dd8b33..0000000000
--- a/spec/ruby/library/net-ftp/set_socket_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-
-describe "Net::FTP#set_socket" do
- # TODO: I won't spec this method, as it is not used
- # anywhere and it should be private anyway.
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/library/net-ftp/shared/getbinaryfile.rb b/spec/ruby/library/net-ftp/shared/getbinaryfile.rb
deleted file mode 100644
index ceec8e7cd5..0000000000
--- a/spec/ruby/library/net-ftp/shared/getbinaryfile.rb
+++ /dev/null
@@ -1,150 +0,0 @@
-describe :net_ftp_getbinaryfile, shared: true do
- before :each do
- @fixture_file = __dir__ + "/../fixtures/getbinaryfile"
- @tmp_file = tmp("getbinaryfile")
-
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- @ftp.binary = @binary_mode
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @tmp_file
- end
-
- it "sends the RETR command to the server" do
- @ftp.send(@method, "test", @tmp_file)
- @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
- end
-
- it "returns nil" do
- @ftp.send(@method, "test", @tmp_file).should be_nil
- end
-
- it "saves the contents of the passed remote file to the passed local file" do
- @ftp.send(@method, "test", @tmp_file)
- File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
- end
-
- describe "when passed a block" do
- it "yields the received content as binary blocks of the passed size" do
- res = []
- @ftp.send(@method, "test", @tmp_file, 10) { |bin| res << bin }
- res.should == [ "This is th", "e content\n", "of the fil", "e named 't", "est'.\n" ]
- end
- end
-
- describe "when resuming an existing file" do
- before :each do
- @tmp_file = tmp("getbinaryfile_resume")
-
- File.open(@tmp_file, "wb") do |f|
- f << "This is the content\n"
- end
-
- @ftp.resume = true
- end
-
- it "saves the remaining content of the passed remote file to the passed local file" do
- @ftp.send(@method, "test", @tmp_file)
- File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
- end
-
- describe "and the REST command fails" do
- it "raises a Net::FTPProtoError when the response code is 550" do
- @server.should_receive(:rest).and_respond("Requested action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:rest).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:rest).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:rest).and_respond("502 Command not implemented.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:rest).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:rest).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
- end
- end
-
- describe "when the RETR command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:retr).and_respond("450 Requested file action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPProtoError when the response code is 550" do
- @server.should_receive(:retr).and_respond("Requested action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:retr).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:retr).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:retr).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:retr).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net-ftp/shared/gettextfile.rb b/spec/ruby/library/net-ftp/shared/gettextfile.rb
deleted file mode 100644
index 7fe14f7dfb..0000000000
--- a/spec/ruby/library/net-ftp/shared/gettextfile.rb
+++ /dev/null
@@ -1,100 +0,0 @@
-describe :net_ftp_gettextfile, shared: true do
- before :each do
- @tmp_file = tmp("gettextfile")
-
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- @ftp.binary = @binary_mode
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @tmp_file
- end
-
- it "sends the RETR command to the server" do
- @ftp.send(@method, "test", @tmp_file)
- @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
- end
-
- it "returns nil" do
- @ftp.send(@method, "test", @tmp_file).should be_nil
- end
-
- it "saves the contents of the passed remote file to the passed local file" do
- @ftp.send(@method, "test", @tmp_file)
- File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
- end
-
- describe "when passed a block" do
- it "yields each line of the retrieved file to the passed block" do
- res = []
- @ftp.send(@method, "test", @tmp_file) { |line| res << line }
- res.should == [ "This is the content", "of the file named 'test'."]
- end
- end
-
- describe "when the RETR command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:retr).and_respond("450 Requested file action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPProtoError when the response code is 550" do
- @server.should_receive(:retr).and_respond("Requested action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:retr).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:retr).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:retr).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:retr).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net-ftp/shared/putbinaryfile.rb b/spec/ruby/library/net-ftp/shared/putbinaryfile.rb
deleted file mode 100644
index 45f53adc2a..0000000000
--- a/spec/ruby/library/net-ftp/shared/putbinaryfile.rb
+++ /dev/null
@@ -1,167 +0,0 @@
-describe :net_ftp_putbinaryfile, shared: true do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @local_fixture_file = __dir__ + "/../fixtures/putbinaryfile"
- @remote_tmp_file = tmp("binaryfile", false)
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- @ftp.binary = @binary_mode
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @remote_tmp_file
- end
-
- it "sends the STOR command to the server" do
- @ftp.send(@method, @local_fixture_file, "binary")
- @ftp.last_response.should == "200 OK, Data received. (STOR binary)\n"
- end
-
- it "sends the contents of the passed local_file, without modifications" do
- @ftp.send(@method, @local_fixture_file, "binary")
-
- remote_lines = File.readlines(@remote_tmp_file)
- local_lines = File.readlines(@local_fixture_file)
-
- remote_lines.should == local_lines
- end
-
- it "returns nil" do
- @ftp.send(@method, @local_fixture_file, "binary").should be_nil
- end
-
- describe "when passed a block" do
- it "yields the transmitted content as binary blocks of the passed size" do
- res = []
- @ftp.send(@method, @local_fixture_file, "binary", 10) { |x| res << x }
- res.should == [
- "This is an", " example f",
- "ile\nwhich ", "is going t",
- "o be trans", "mitted\nusi",
- "ng #putbin", "aryfile.\n"
- ]
- end
- end
-
- describe "when resuming an existing file" do
- before :each do
- File.open(@remote_tmp_file, "w") do |f|
- f << "This is an example file\n"
- end
-
- @ftp.resume = true
- end
-
- it "sends the remaining content of the passed local_file to the passed remote_file" do
- @ftp.send(@method, @local_fixture_file, "binary")
- File.read(@remote_tmp_file).should == File.read(@local_fixture_file)
- end
-
- describe "and the APPE command fails" do
- it "raises a Net::FTPProtoError when the response code is 550" do
- @server.should_receive(:appe).and_respond("Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:appe).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:appe).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:appe).and_respond("502 Command not implemented.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:appe).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:appe).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
- end
- end
-
- describe "when the STOR command fails" do
- it "raises a Net::FTPPermError when the response code is 532" do
- @server.should_receive(:stor).and_respond("532 Need account for storing files.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:stor).and_respond("450 Requested file action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPTempError when the response code is 452" do
- @server.should_receive(:stor).and_respond("452 Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 553" do
- @server.should_receive(:stor).and_respond("553 Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:stor).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:stor).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:stor).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:stor).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net-ftp/shared/puttextfile.rb b/spec/ruby/library/net-ftp/shared/puttextfile.rb
deleted file mode 100644
index e2c0453352..0000000000
--- a/spec/ruby/library/net-ftp/shared/puttextfile.rb
+++ /dev/null
@@ -1,128 +0,0 @@
-describe :net_ftp_puttextfile, shared: true do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @local_fixture_file = __dir__ + "/../fixtures/puttextfile"
- @remote_tmp_file = tmp("textfile", false)
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- @ftp.binary = @binary_mode
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @remote_tmp_file
- end
-
- it "sends the STOR command to the server" do
- @ftp.send(@method, @local_fixture_file, "text")
- @ftp.last_response.should == "200 OK, Data received. (STOR text)\n"
- end
-
- it "sends the contents of the passed local_file, using \\r\\n as the newline separator" do
- @ftp.send(@method, @local_fixture_file, "text")
-
- remote_lines = File.binread(@remote_tmp_file)
- local_lines = File.binread(@local_fixture_file)
-
- remote_lines.should_not == local_lines
- remote_lines.should == local_lines.gsub("\n", "\r\n")
- end
-
- guard -> { Net::FTP::VERSION < '0.3.6' } do
- it "returns nil" do
- @ftp.send(@method, @local_fixture_file, "text").should be_nil
- end
- end
-
- guard -> { Net::FTP::VERSION >= '0.3.6' } do
- it "returns the response" do
- @ftp.send(@method, @local_fixture_file, "text").should == @ftp.last_response
- end
- end
-
- describe "when passed a block" do
- it "yields each transmitted line" do
- res = []
- @ftp.send(@method, @local_fixture_file, "text") { |x| res << x }
- res.should == [
- "This is an example file\r\n",
- "which is going to be transmitted\r\n",
- "using #puttextfile.\r\n"
- ]
- end
- end
-
- describe "when the STOR command fails" do
- it "raises a Net::FTPPermError when the response code is 532" do
- @server.should_receive(:stor).and_respond("532 Need account for storing files.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:stor).and_respond("450 Requested file action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPTempError when the response code is 452" do
- @server.should_receive(:stor).and_respond("452 Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 553" do
- @server.should_receive(:stor).and_respond("553 Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:stor).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:stor).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:stor).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:stor).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net-ftp/site_spec.rb b/spec/ruby/library/net-ftp/site_spec.rb
deleted file mode 100644
index c3e589a920..0000000000
--- a/spec/ruby/library/net-ftp/site_spec.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#site" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the SITE command with the passed argument to the server" do
- @ftp.site("param")
- @ftp.last_response.should == "200 Command okay. (SITE param)\n"
- end
-
- it "returns nil" do
- @ftp.site("param").should be_nil
- end
-
- it "does not raise an error when the response code is 202" do
- @server.should_receive(:site).and_respond("202 Command not implemented, superfluous at this site.")
- -> { @ftp.site("param") }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:site).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:site).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:site).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.site("param") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:site).and_respond("530 Requested action not taken.")
- -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/size_spec.rb b/spec/ruby/library/net-ftp/size_spec.rb
deleted file mode 100644
index 0cf2e24477..0000000000
--- a/spec/ruby/library/net-ftp/size_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#size" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the SIZE command to the server" do
- @ftp.size("test.file")
- @ftp.last_response.should == "213 1024\n"
- end
-
- it "returns the size of the passed file as Integer" do
- @ftp.size("test.file").should eql(1024)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:size).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:size).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:size).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.size("test.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:size).and_respond("550 Requested action not taken.")
- -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/status_spec.rb b/spec/ruby/library/net-ftp/status_spec.rb
deleted file mode 100644
index 9d9f86c381..0000000000
--- a/spec/ruby/library/net-ftp/status_spec.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#status" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the STAT command to the server" do
- @ftp.status
- @ftp.last_response.should == "211 System status, or system help reply. (STAT)\n"
- end
-
- it "sends the STAT command with an optional parameter to the server" do
- @ftp.status("/pub").should == "211 System status, or system help reply. (STAT /pub)\n"
- end
-
- it "returns the received information" do
- @ftp.status.should == "211 System status, or system help reply. (STAT)\n"
- end
-
- it "does not raise an error when the response code is 212" do
- @server.should_receive(:stat).and_respond("212 Directory status.")
- -> { @ftp.status }.should_not raise_error
- end
-
- it "does not raise an error when the response code is 213" do
- @server.should_receive(:stat).and_respond("213 File status.")
- -> { @ftp.status }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:stat).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.status }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:stat).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.status }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:stat).and_respond("502 Command not implemented.")
- -> { @ftp.status }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:stat).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.status }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:stat).and_respond("530 Requested action not taken.")
- -> { @ftp.status }.should raise_error(Net::FTPPermError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/storbinary_spec.rb b/spec/ruby/library/net-ftp/storbinary_spec.rb
deleted file mode 100644
index aa4c51f2e8..0000000000
--- a/spec/ruby/library/net-ftp/storbinary_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-require_relative '../../spec_helper'
-
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#storbinary" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @local_fixture_file = __dir__ + "/fixtures/putbinaryfile"
- @tmp_file = tmp("binaryfile", false)
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @tmp_file
- end
-
- it "sends the passed command and the passed File object's content to the server" do
- File.open(@local_fixture_file) do |f|
- f.binmode
-
- @ftp.storbinary("STOR binary", f, 4096) {}
- @ftp.last_response.should == "200 OK, Data received. (STOR binary)\n"
- end
- end
-
- it "yields the transmitted content as binary blocks of the passed size" do
- File.open(@local_fixture_file) do |f|
- f.binmode
-
- res = []
- @ftp.storbinary("STOR binary", f, 10) { |x| res << x }
- res.should == [
- "This is an", " example f",
- "ile\nwhich ", "is going t",
- "o be trans", "mitted\nusi",
- "ng #putbin", "aryfile.\n"
- ]
- end
- end
-end
diff --git a/spec/ruby/library/net-ftp/storlines_spec.rb b/spec/ruby/library/net-ftp/storlines_spec.rb
deleted file mode 100644
index dc6830da7b..0000000000
--- a/spec/ruby/library/net-ftp/storlines_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-require_relative '../../spec_helper'
-
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#storlines" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @local_fixture_file = __dir__ + "/fixtures/puttextfile"
- @tmp_file = tmp("textfile", false)
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @tmp_file
- end
-
- it "sends the passed command and the passed File object's content to the server" do
- File.open(@local_fixture_file) do |f|
- @ftp.storlines("STOR text", f) {}
- @ftp.last_response.should == "200 OK, Data received. (STOR text)\n"
- end
- end
-
- it "yields each line of the transmitted content" do
- File.open(@local_fixture_file) do |f|
- res = []
- @ftp.storlines("STOR text", f) { |x| res << x }
- res.should == [
- "This is an example file\r\n",
- "which is going to be transmitted\r\n",
- "using #puttextfile.\r\n"
- ]
- end
- end
-end
diff --git a/spec/ruby/library/net-ftp/system_spec.rb b/spec/ruby/library/net-ftp/system_spec.rb
deleted file mode 100644
index 2b7f0d2560..0000000000
--- a/spec/ruby/library/net-ftp/system_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#system" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the SYST command to the server" do
- @ftp.system
- @ftp.last_response.should =~ /\A215 FTP Dummy Server \(SYST\)\Z/
- end
-
- it "returns the received information" do
- @ftp.system.should =~ /\AFTP Dummy Server \(SYST\)\Z/
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:syst).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.system }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:syst).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.system }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:syst).and_respond("502 Command not implemented.")
- -> { @ftp.system }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:syst).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.system }.should raise_error(Net::FTPTempError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/voidcmd_spec.rb b/spec/ruby/library/net-ftp/voidcmd_spec.rb
deleted file mode 100644
index f2536fe697..0000000000
--- a/spec/ruby/library/net-ftp/voidcmd_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#voidcmd" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the passed command to the server" do
- @server.should_receive(:help).and_respond("2xx Does not raise.")
- -> { @ftp.voidcmd("HELP") }.should_not raise_error
- end
-
- it "returns nil" do
- @server.should_receive(:help).and_respond("2xx Does not raise.")
- @ftp.voidcmd("HELP").should be_nil
- end
-
- it "raises a Net::FTPReplyError when the response code is 1xx" do
- @server.should_receive(:help).and_respond("1xx Does raise a Net::FTPReplyError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPReplyError)
- end
-
- it "raises a Net::FTPReplyError when the response code is 3xx" do
- @server.should_receive(:help).and_respond("3xx Does raise a Net::FTPReplyError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPReplyError)
- end
-
- it "raises a Net::FTPTempError when the response code is 4xx" do
- @server.should_receive(:help).and_respond("4xx Does raise a Net::FTPTempError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 5xx" do
- @server.should_receive(:help).and_respond("5xx Does raise a Net::FTPPermError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPProtoError when the response code is not valid" do
- @server.should_receive(:help).and_respond("999 Does raise a Net::FTPProtoError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPProtoError)
- end
-end
diff --git a/spec/ruby/library/net-ftp/welcome_spec.rb b/spec/ruby/library/net-ftp/welcome_spec.rb
deleted file mode 100644
index 4279127ce3..0000000000
--- a/spec/ruby/library/net-ftp/welcome_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'spec_helper'
-require_relative 'fixtures/server'
-
-describe "Net::FTP#welcome" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "returns the server's welcome message" do
- @ftp.welcome.should be_nil
- @ftp.login
- @ftp.welcome.should == "230 User logged in, proceed. (USER anonymous)\n"
- end
-end
diff --git a/spec/ruby/library/net-http/HTTPBadResponse_spec.rb b/spec/ruby/library/net-http/HTTPBadResponse_spec.rb
deleted file mode 100644
index 8f2e8ccfaf..0000000000
--- a/spec/ruby/library/net-http/HTTPBadResponse_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPBadResponse" do
- it "is a subclass of StandardError" do
- Net::HTTPBadResponse.should < StandardError
- end
-end
diff --git a/spec/ruby/library/net-http/HTTPClientExcepton_spec.rb b/spec/ruby/library/net-http/HTTPClientExcepton_spec.rb
deleted file mode 100644
index 2992e6596f..0000000000
--- a/spec/ruby/library/net-http/HTTPClientExcepton_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPClientException" do
- it "is a subclass of Net::ProtoServerError" do
- Net::HTTPClientException.should < Net::ProtoServerError
- end
-
- it "includes the Net::HTTPExceptions module" do
- Net::HTTPClientException.should < Net::HTTPExceptions
- end
-end
diff --git a/spec/ruby/library/net-http/HTTPError_spec.rb b/spec/ruby/library/net-http/HTTPError_spec.rb
deleted file mode 100644
index 7f79eef8cf..0000000000
--- a/spec/ruby/library/net-http/HTTPError_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPError" do
- it "is a subclass of Net::ProtocolError" do
- Net::HTTPError.should < Net::ProtocolError
- end
-
- it "includes the Net::HTTPExceptions module" do
- Net::HTTPError.should < Net::HTTPExceptions
- end
-end
diff --git a/spec/ruby/library/net-http/HTTPFatalError_spec.rb b/spec/ruby/library/net-http/HTTPFatalError_spec.rb
deleted file mode 100644
index 0113b9da2d..0000000000
--- a/spec/ruby/library/net-http/HTTPFatalError_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPFatalError" do
- it "is a subclass of Net::ProtoFatalError" do
- Net::HTTPFatalError.should < Net::ProtoFatalError
- end
-
- it "includes the Net::HTTPExceptions module" do
- Net::HTTPFatalError.should < Net::HTTPExceptions
- end
-end
diff --git a/spec/ruby/library/net-http/HTTPHeaderSyntaxError_spec.rb b/spec/ruby/library/net-http/HTTPHeaderSyntaxError_spec.rb
deleted file mode 100644
index b3b73ff46f..0000000000
--- a/spec/ruby/library/net-http/HTTPHeaderSyntaxError_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPHeaderSyntaxError" do
- it "is a subclass of StandardError" do
- Net::HTTPHeaderSyntaxError.should < StandardError
- end
-end
diff --git a/spec/ruby/library/net-http/HTTPRetriableError_spec.rb b/spec/ruby/library/net-http/HTTPRetriableError_spec.rb
deleted file mode 100644
index 677731fb68..0000000000
--- a/spec/ruby/library/net-http/HTTPRetriableError_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPRetriableError" do
- it "is a subclass of Net::ProtoRetriableError" do
- Net::HTTPRetriableError.should < Net::ProtoRetriableError
- end
-
- it "includes the Net::HTTPExceptions module" do
- Net::HTTPRetriableError.should < Net::HTTPExceptions
- end
-end
diff --git a/spec/ruby/library/net-http/HTTPServerException_spec.rb b/spec/ruby/library/net-http/HTTPServerException_spec.rb
deleted file mode 100644
index 5e0a833fee..0000000000
--- a/spec/ruby/library/net-http/HTTPServerException_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPServerException" do
- it "is a subclass of Net::ProtoServerError and is warned as deprecated" do
- -> { Net::HTTPServerException.should < Net::ProtoServerError }.should complain(/warning: constant Net::HTTPServerException is deprecated/)
- end
-
- it "includes the Net::HTTPExceptions module and is warned as deprecated" do
- -> { Net::HTTPServerException.should < Net::HTTPExceptions }.should complain(/warning: constant Net::HTTPServerException is deprecated/)
- end
-end
diff --git a/spec/ruby/library/net-http/http/Proxy_spec.rb b/spec/ruby/library/net-http/http/Proxy_spec.rb
deleted file mode 100644
index a1a04fa00b..0000000000
--- a/spec/ruby/library/net-http/http/Proxy_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.Proxy" do
- it "returns a new subclass of Net::HTTP" do
- Net::HTTP.Proxy("localhost").should < Net::HTTP
- end
-
- it "returns Net::HTTP when the passed address is nil" do
- Net::HTTP.Proxy(nil).should == Net::HTTP
- end
-
- it "sets the returned subclasses' proxy options based on the passed arguments" do
- http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.proxy_address.should == "localhost"
- http_with_proxy.proxy_port.should eql(1234)
- http_with_proxy.proxy_user.should == "rspec"
- http_with_proxy.proxy_pass.should == "rocks"
- end
-end
-
-describe "Net::HTTP#proxy?" do
- describe "when self is no proxy class instance" do
- it "returns false" do
- Net::HTTP.new("localhost", 3333).proxy?.should be_false
- end
- end
-
- describe "when self is a proxy class instance" do
- it "returns false" do
- http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.new("localhost", 3333).proxy?.should be_true
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/active_spec.rb b/spec/ruby/library/net-http/http/active_spec.rb
deleted file mode 100644
index c260274594..0000000000
--- a/spec/ruby/library/net-http/http/active_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/started'
-
-describe "Net::HTTP#active?" do
- it_behaves_like :net_http_started_p, :active?
-end
diff --git a/spec/ruby/library/net-http/http/address_spec.rb b/spec/ruby/library/net-http/http/address_spec.rb
deleted file mode 100644
index 7c5b82a8f9..0000000000
--- a/spec/ruby/library/net-http/http/address_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#address" do
- it "returns the current host name" do
- net = Net::HTTP.new("localhost")
- net.address.should == "localhost"
- end
-end
diff --git a/spec/ruby/library/net-http/http/close_on_empty_response_spec.rb b/spec/ruby/library/net-http/http/close_on_empty_response_spec.rb
deleted file mode 100644
index 9cc756befb..0000000000
--- a/spec/ruby/library/net-http/http/close_on_empty_response_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#close_on_empty_response" do
- it "needs to be reviewed for spec completeness"
-end
-
-describe "Net::HTTP#close_on_empty_response=" do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/library/net-http/http/copy_spec.rb b/spec/ruby/library/net-http/http/copy_spec.rb
deleted file mode 100644
index fba96c0f11..0000000000
--- a/spec/ruby/library/net-http/http/copy_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#copy" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a COPY request to the passed path and returns the response" do
- response = @http.copy("/request")
- response.should be_kind_of(Net::HTTPResponse)
- response.body.should == "Request type: COPY"
- end
-end
diff --git a/spec/ruby/library/net-http/http/default_port_spec.rb b/spec/ruby/library/net-http/http/default_port_spec.rb
deleted file mode 100644
index 95b7316a0c..0000000000
--- a/spec/ruby/library/net-http/http/default_port_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.default_port" do
- it "returns 80" do
- Net::HTTP.http_default_port.should eql(80)
- end
-end
diff --git a/spec/ruby/library/net-http/http/delete_spec.rb b/spec/ruby/library/net-http/http/delete_spec.rb
deleted file mode 100644
index d73aa5b375..0000000000
--- a/spec/ruby/library/net-http/http/delete_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#delete" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a DELETE request to the passed path and returns the response" do
- response = @http.delete("/request")
- response.should be_kind_of(Net::HTTPResponse)
- response.body.should == "Request type: DELETE"
- end
-end
diff --git a/spec/ruby/library/net-http/http/finish_spec.rb b/spec/ruby/library/net-http/http/finish_spec.rb
deleted file mode 100644
index d4aa00dffe..0000000000
--- a/spec/ruby/library/net-http/http/finish_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#finish" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.new("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- describe "when self has been started" do
- it "closes the tcp connection" do
- @http.start
- @http.finish
- @http.started?.should be_false
- end
- end
-
- describe "when self has not been started yet" do
- it "raises an IOError" do
- -> { @http.finish }.should raise_error(IOError)
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/get2_spec.rb b/spec/ruby/library/net-http/http/get2_spec.rb
deleted file mode 100644
index 57c05ec64b..0000000000
--- a/spec/ruby/library/net-http/http/get2_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_get'
-
-describe "Net::HTTP#get2" do
- it_behaves_like :net_http_request_get, :get2
-end
diff --git a/spec/ruby/library/net-http/http/get_print_spec.rb b/spec/ruby/library/net-http/http/get_print_spec.rb
deleted file mode 100644
index 3c24ce44ea..0000000000
--- a/spec/ruby/library/net-http/http/get_print_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP.get_print" do
- before :each do
- NetHTTPSpecs.start_server
- @port = NetHTTPSpecs.port
- end
-
- after :each do
- NetHTTPSpecs.stop_server
- end
-
- describe "when passed URI" do
- it "it prints the body of the specified uri to $stdout" do
- -> do
- Net::HTTP.get_print URI.parse("http://localhost:#{@port}/")
- end.should output(/This is the index page\./)
- end
- end
-
- describe "when passed host, path, port" do
- it "it prints the body of the specified uri to $stdout" do
- -> do
- Net::HTTP.get_print 'localhost', "/", @port
- end.should output(/This is the index page\./)
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/get_response_spec.rb b/spec/ruby/library/net-http/http/get_response_spec.rb
deleted file mode 100644
index 7133ef8101..0000000000
--- a/spec/ruby/library/net-http/http/get_response_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP.get_response" do
- before :each do
- NetHTTPSpecs.start_server
- @port = NetHTTPSpecs.port
- end
-
- after :each do
- NetHTTPSpecs.stop_server
- end
-
- describe "when passed URI" do
- it "returns the response for the specified uri" do
- res = Net::HTTP.get_response(URI.parse("http://localhost:#{@port}/"))
- res.content_type.should == "text/plain"
- res.body.should == "This is the index page."
- end
- end
-
- describe "when passed host, path, port" do
- it "returns the response for the specified host-path-combination" do
- res = Net::HTTP.get_response('localhost', "/", @port)
- res.content_type.should == "text/plain"
- res.body.should == "This is the index page."
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/get_spec.rb b/spec/ruby/library/net-http/http/get_spec.rb
deleted file mode 100644
index e64a61c52c..0000000000
--- a/spec/ruby/library/net-http/http/get_spec.rb
+++ /dev/null
@@ -1,94 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP.get" do
- before :each do
- NetHTTPSpecs.start_server
- @port = NetHTTPSpecs.port
- end
-
- after :each do
- NetHTTPSpecs.stop_server
- end
-
- describe "when passed URI" do
- it "returns the body of the specified uri" do
- Net::HTTP.get(URI.parse("http://localhost:#{@port}/")).should == "This is the index page."
- end
- end
-
- describe "when passed host, path, port" do
- it "returns the body of the specified host-path-combination" do
- Net::HTTP.get('localhost', "/", @port).should == "This is the index page."
- end
- end
-end
-
-quarantine! do # These specs fail frequently with CHECK_LEAKS=true
-describe "Net::HTTP.get" do
- describe "when reading gzipped contents" do
- def start_threads
- require 'zlib'
- require 'stringio'
-
- server = nil
- server_thread = Thread.new do
- server = TCPServer.new("127.0.0.1", 0)
- begin
- c = server.accept
- ensure
- server.close
- end
- c.print "HTTP/1.1 200\r\n"
- c.print "Content-Type: text/plain\r\n"
- c.print "Content-Encoding: gzip\r\n"
- s = StringIO.new
- z = Zlib::GzipWriter.new(s)
- begin
- z.write 'Hello World!'
- ensure
- z.close
- end
- c.print "Content-Length: #{s.length}\r\n\r\n"
- # Write partial gzip content
- c.write s.string.byteslice(0..-2)
- c.flush
- c
- end
- Thread.pass until server && server_thread.stop?
-
- client_thread = Thread.new do
- Thread.current.report_on_exception = false
- Net::HTTP.get("127.0.0.1", '/', server.connect_address.ip_port)
- end
-
- socket = server_thread.value
- Thread.pass until client_thread.stop?
-
- [socket, client_thread]
- end
-
- it "propagates exceptions interrupting the thread and does not replace it with Zlib::BufError" do
- my_exception = Class.new(RuntimeError)
- socket, client_thread = start_threads
- begin
- client_thread.raise my_exception, "my exception"
- -> { client_thread.value }.should raise_error(my_exception)
- ensure
- socket.close
- end
- end
-
- it "lets the kill Thread exception goes through and does not replace it with Zlib::BufError" do
- socket, client_thread = start_threads
- begin
- client_thread.kill
- client_thread.value.should == nil
- ensure
- socket.close
- end
- end
- end
-end
-end
diff --git a/spec/ruby/library/net-http/http/head2_spec.rb b/spec/ruby/library/net-http/http/head2_spec.rb
deleted file mode 100644
index 84cfff33d7..0000000000
--- a/spec/ruby/library/net-http/http/head2_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_head'
-
-describe "Net::HTTP#head2" do
- it_behaves_like :net_http_request_head, :head2
-end
diff --git a/spec/ruby/library/net-http/http/head_spec.rb b/spec/ruby/library/net-http/http/head_spec.rb
deleted file mode 100644
index 64621fa87b..0000000000
--- a/spec/ruby/library/net-http/http/head_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#head" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a HEAD request to the passed path and returns the response" do
- response = @http.head("/request")
- # HEAD requests have no responses
- response.body.should be_nil
- end
-
- it "returns a Net::HTTPResponse" do
- @http.head("/request").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net-http/http/http_default_port_spec.rb b/spec/ruby/library/net-http/http/http_default_port_spec.rb
deleted file mode 100644
index 3b17bcd0a5..0000000000
--- a/spec/ruby/library/net-http/http/http_default_port_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.http_default_port" do
- it "returns 80" do
- Net::HTTP.http_default_port.should eql(80)
- end
-end
diff --git a/spec/ruby/library/net-http/http/https_default_port_spec.rb b/spec/ruby/library/net-http/http/https_default_port_spec.rb
deleted file mode 100644
index 8c24e1d97c..0000000000
--- a/spec/ruby/library/net-http/http/https_default_port_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.https_default_port" do
- it "returns 443" do
- Net::HTTP.https_default_port.should eql(443)
- end
-end
diff --git a/spec/ruby/library/net-http/http/initialize_spec.rb b/spec/ruby/library/net-http/http/initialize_spec.rb
deleted file mode 100644
index 78aa01e1aa..0000000000
--- a/spec/ruby/library/net-http/http/initialize_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#initialize" do
- it "is private" do
- Net::HTTP.should have_private_instance_method(:initialize)
- end
-
- describe "when passed address" do
- before :each do
- @net = Net::HTTP.allocate
- @net.send(:initialize, "localhost")
- end
-
- it "sets the new Net::HTTP instance's address to the passed address" do
- @net.address.should == "localhost"
- end
-
- it "sets the new Net::HTTP instance's port to the default HTTP port" do
- @net.port.should eql(Net::HTTP.default_port)
- end
-
- it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
- end
- end
-
- describe "when passed address, port" do
- before :each do
- @net = Net::HTTP.allocate
- @net.send(:initialize, "localhost", 3333)
- end
-
- it "sets the new Net::HTTP instance's address to the passed address" do
- @net.address.should == "localhost"
- end
-
- it "sets the new Net::HTTP instance's port to the passed port" do
- @net.port.should eql(3333)
- end
-
- it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/inspect_spec.rb b/spec/ruby/library/net-http/http/inspect_spec.rb
deleted file mode 100644
index b8f650809e..0000000000
--- a/spec/ruby/library/net-http/http/inspect_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#inspect" do
- before :each do
- NetHTTPSpecs.start_server
- @port = NetHTTPSpecs.port
- @http = Net::HTTP.new("localhost", @port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "returns a String representation of self" do
- @http.inspect.should be_kind_of(String)
- @http.inspect.should == "#<Net::HTTP localhost:#{@port} open=false>"
-
- @http.start
- @http.inspect.should == "#<Net::HTTP localhost:#{@port} open=true>"
- end
-end
diff --git a/spec/ruby/library/net-http/http/is_version_1_1_spec.rb b/spec/ruby/library/net-http/http/is_version_1_1_spec.rb
deleted file mode 100644
index bdb343f9e0..0000000000
--- a/spec/ruby/library/net-http/http/is_version_1_1_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'shared/version_1_1'
-
-describe "Net::HTTP.is_version_1_1?" do
- it_behaves_like :net_http_version_1_1_p, :is_version_1_1?
-end
diff --git a/spec/ruby/library/net-http/http/is_version_1_2_spec.rb b/spec/ruby/library/net-http/http/is_version_1_2_spec.rb
deleted file mode 100644
index 555bb205dd..0000000000
--- a/spec/ruby/library/net-http/http/is_version_1_2_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'shared/version_1_2'
-
-describe "Net::HTTP.is_version_1_2?" do
- it_behaves_like :net_http_version_1_2_p, :is_version_1_2?
-end
diff --git a/spec/ruby/library/net-http/http/lock_spec.rb b/spec/ruby/library/net-http/http/lock_spec.rb
deleted file mode 100644
index aa1f944196..0000000000
--- a/spec/ruby/library/net-http/http/lock_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#lock" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a LOCK request to the passed path and returns the response" do
- response = @http.lock("/request", "test=test")
- response.should be_kind_of(Net::HTTPResponse)
- response.body.should == "Request type: LOCK"
- end
-end
diff --git a/spec/ruby/library/net-http/http/mkcol_spec.rb b/spec/ruby/library/net-http/http/mkcol_spec.rb
deleted file mode 100644
index f8009f9059..0000000000
--- a/spec/ruby/library/net-http/http/mkcol_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#mkcol" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a MKCOL request to the passed path and returns the response" do
- response = @http.mkcol("/request")
- response.should be_kind_of(Net::HTTPResponse)
- response.body.should == "Request type: MKCOL"
- end
-end
diff --git a/spec/ruby/library/net-http/http/move_spec.rb b/spec/ruby/library/net-http/http/move_spec.rb
deleted file mode 100644
index ae43016a2c..0000000000
--- a/spec/ruby/library/net-http/http/move_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#head" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a MOVE request to the passed path and returns the response" do
- response = @http.move("/request")
- # HEAD requests have no responses
- response.body.should == "Request type: MOVE"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.move("/request").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net-http/http/new_spec.rb b/spec/ruby/library/net-http/http/new_spec.rb
deleted file mode 100644
index 1ec6bbd0c0..0000000000
--- a/spec/ruby/library/net-http/http/new_spec.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.new" do
- describe "when passed address" do
- before :each do
- @http = Net::HTTP.new("localhost")
- end
-
- it "returns a Net::HTTP instance" do
- @http.proxy?.should be_false
- @http.instance_of?(Net::HTTP).should be_true
- end
-
- it "sets the new Net::HTTP instance's address to the passed address" do
- @http.address.should == "localhost"
- end
-
- it "sets the new Net::HTTP instance's port to the default HTTP port" do
- @http.port.should eql(Net::HTTP.default_port)
- end
-
- it "does not start the new Net::HTTP instance" do
- @http.started?.should be_false
- end
- end
-
- describe "when passed address, port" do
- before :each do
- @http = Net::HTTP.new("localhost", 3333)
- end
-
- it "returns a Net::HTTP instance" do
- @http.proxy?.should be_false
- @http.instance_of?(Net::HTTP).should be_true
- end
-
- it "sets the new Net::HTTP instance's address to the passed address" do
- @http.address.should == "localhost"
- end
-
- it "sets the new Net::HTTP instance's port to the passed port" do
- @http.port.should eql(3333)
- end
-
- it "does not start the new Net::HTTP instance" do
- @http.started?.should be_false
- end
- end
-
- describe "when passed address, port, *proxy_options" do
- it "returns a Net::HTTP instance" do
- http = Net::HTTP.new("localhost", 3333, "localhost")
- http.proxy?.should be_true
- http.instance_of?(Net::HTTP).should be_true
- http.should be_kind_of(Net::HTTP)
- end
-
- it "correctly sets the passed Proxy options" do
- http = Net::HTTP.new("localhost", 3333, "localhost")
- http.proxy_address.should == "localhost"
- http.proxy_port.should eql(80)
- http.proxy_user.should be_nil
- http.proxy_pass.should be_nil
-
- http = Net::HTTP.new("localhost", 3333, "localhost", 1234)
- http.proxy_address.should == "localhost"
- http.proxy_port.should eql(1234)
- http.proxy_user.should be_nil
- http.proxy_pass.should be_nil
-
- http = Net::HTTP.new("localhost", 3333, "localhost", 1234, "rubyspec")
- http.proxy_address.should == "localhost"
- http.proxy_port.should eql(1234)
- http.proxy_user.should == "rubyspec"
- http.proxy_pass.should be_nil
-
- http = Net::HTTP.new("localhost", 3333, "localhost", 1234, "rubyspec", "rocks")
- http.proxy_address.should == "localhost"
- http.proxy_port.should eql(1234)
- http.proxy_user.should == "rubyspec"
- http.proxy_pass.should == "rocks"
- end
- end
-
-end
diff --git a/spec/ruby/library/net-http/http/newobj_spec.rb b/spec/ruby/library/net-http/http/newobj_spec.rb
deleted file mode 100644
index e19b30fca9..0000000000
--- a/spec/ruby/library/net-http/http/newobj_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.newobj" do
- before :each do
- @net = Net::HTTP.newobj("localhost")
- end
-
- describe "when passed address" do
- it "returns a new Net::HTTP instance" do
- @net.should be_kind_of(Net::HTTP)
- end
-
- it "sets the new Net::HTTP instance's address to the passed address" do
- @net.address.should == "localhost"
- end
-
- it "sets the new Net::HTTP instance's port to the default HTTP port" do
- @net.port.should eql(Net::HTTP.default_port)
- end
-
- it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
- end
- end
-
- describe "when passed address, port" do
- before :each do
- @net = Net::HTTP.newobj("localhost", 3333)
- end
-
- it "returns a new Net::HTTP instance" do
- @net.should be_kind_of(Net::HTTP)
- end
-
- it "sets the new Net::HTTP instance's address to the passed address" do
- @net.address.should == "localhost"
- end
-
- it "sets the new Net::HTTP instance's port to the passed port" do
- @net.port.should eql(3333)
- end
-
- it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/open_timeout_spec.rb b/spec/ruby/library/net-http/http/open_timeout_spec.rb
deleted file mode 100644
index 0d93752271..0000000000
--- a/spec/ruby/library/net-http/http/open_timeout_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#open_timeout" do
- it "returns the seconds to wait till the connection is open" do
- net = Net::HTTP.new("localhost")
- net.open_timeout.should eql(60)
- net.open_timeout = 10
- net.open_timeout.should eql(10)
- end
-end
-
-describe "Net::HTTP#open_timeout=" do
- it "sets the seconds to wait till the connection is open" do
- net = Net::HTTP.new("localhost")
- net.open_timeout = 10
- net.open_timeout.should eql(10)
- end
-
- it "returns the newly set value" do
- net = Net::HTTP.new("localhost")
- (net.open_timeout = 10).should eql(10)
- end
-end
diff --git a/spec/ruby/library/net-http/http/options_spec.rb b/spec/ruby/library/net-http/http/options_spec.rb
deleted file mode 100644
index 3d9887a557..0000000000
--- a/spec/ruby/library/net-http/http/options_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#options" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends an options request to the passed path and returns the response" do
- response = @http.options("/request")
-
- response.body.should == "Request type: OPTIONS"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.options("/request").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net-http/http/port_spec.rb b/spec/ruby/library/net-http/http/port_spec.rb
deleted file mode 100644
index 0984d5e6ce..0000000000
--- a/spec/ruby/library/net-http/http/port_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#port" do
- it "returns the current port number" do
- net = Net::HTTP.new("localhost", 3333)
- net.port.should eql(3333)
- end
-end
diff --git a/spec/ruby/library/net-http/http/post2_spec.rb b/spec/ruby/library/net-http/http/post2_spec.rb
deleted file mode 100644
index abc998709f..0000000000
--- a/spec/ruby/library/net-http/http/post2_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_post'
-
-describe "Net::HTTP#post2" do
- it_behaves_like :net_http_request_post, :post2
-end
diff --git a/spec/ruby/library/net-http/http/post_form_spec.rb b/spec/ruby/library/net-http/http/post_form_spec.rb
deleted file mode 100644
index de64a25bae..0000000000
--- a/spec/ruby/library/net-http/http/post_form_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP.post_form when passed URI" do
- before :each do
- NetHTTPSpecs.start_server
- @port = NetHTTPSpecs.port
- end
-
- after :each do
- NetHTTPSpecs.stop_server
- end
-
- it "POSTs the passed form data to the given uri" do
- uri = URI.parse("http://localhost:#{@port}/request/body")
- data = { test: :data }
-
- res = Net::HTTP.post_form(uri, data)
- res.body.should == "test=data"
- end
-end
diff --git a/spec/ruby/library/net-http/http/post_spec.rb b/spec/ruby/library/net-http/http/post_spec.rb
deleted file mode 100644
index ac020bd6be..0000000000
--- a/spec/ruby/library/net-http/http/post_spec.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require 'uri'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP.post" do
- before :each do
- NetHTTPSpecs.start_server
- end
-
- after :each do
- NetHTTPSpecs.stop_server
- end
-
- it "sends post request to the specified URI and returns response" do
- response = Net::HTTP.post(
- URI("http://localhost:#{NetHTTPSpecs.port}/request"),
- '{ "q": "ruby", "max": "50" }',
- "Content-Type" => "application/json")
- response.body.should == "Request type: POST"
- end
-
- it "returns a Net::HTTPResponse" do
- response = Net::HTTP.post(URI("http://localhost:#{NetHTTPSpecs.port}/request"), "test=test")
- response.should be_kind_of(Net::HTTPResponse)
- end
-
- it "sends Content-Type: application/x-www-form-urlencoded by default" do
- response = Net::HTTP.post(URI("http://localhost:#{NetHTTPSpecs.port}/request/header"), "test=test")
- response.body.should include({ "Content-Type" => "application/x-www-form-urlencoded" }.inspect.delete("{}"))
- end
-
- it "does not support HTTP Basic Auth" do
- response = Net::HTTP.post(
- URI("http://john:qwerty@localhost:#{NetHTTPSpecs.port}/request/basic_auth"),
- "test=test")
- response.body.should == "username: \npassword: "
- end
-end
-
-describe "Net::HTTP#post" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends an post request to the passed path and returns the response" do
- response = @http.post("/request", "test=test")
- response.body.should == "Request type: POST"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.post("/request", "test=test").should be_kind_of(Net::HTTPResponse)
- end
-
- describe "when passed a block" do
- it "yields fragments of the response body to the passed block" do
- str = +""
- @http.post("/request", "test=test") do |res|
- str << res
- end
- str.should == "Request type: POST"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.post("/request", "test=test") {}.should be_kind_of(Net::HTTPResponse)
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/propfind_spec.rb b/spec/ruby/library/net-http/http/propfind_spec.rb
deleted file mode 100644
index f3742d1b1a..0000000000
--- a/spec/ruby/library/net-http/http/propfind_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#propfind" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends an propfind request to the passed path and returns the response" do
- response = @http.propfind("/request", "test=test")
- response.body.should == "Request type: PROPFIND"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.propfind("/request", "test=test").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net-http/http/proppatch_spec.rb b/spec/ruby/library/net-http/http/proppatch_spec.rb
deleted file mode 100644
index 0163d24d46..0000000000
--- a/spec/ruby/library/net-http/http/proppatch_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#proppatch" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends an proppatch request to the passed path and returns the response" do
- response = @http.proppatch("/request", "test=test")
- response.body.should == "Request type: PROPPATCH"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.proppatch("/request", "test=test").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net-http/http/proxy_address_spec.rb b/spec/ruby/library/net-http/http/proxy_address_spec.rb
deleted file mode 100644
index 5b5efb7ac0..0000000000
--- a/spec/ruby/library/net-http/http/proxy_address_spec.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.proxy_address" do
- describe "when self is no proxy class" do
- it "returns nil" do
- Net::HTTP.proxy_address.should be_nil
- end
- end
-
- describe "when self is a proxy class" do
- it "returns the address for self's proxy connection" do
- Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_address.should == "localhost"
- end
- end
-end
-
-describe "Net::HTTP#proxy_address" do
- describe "when self is no proxy class instance" do
- it "returns nil" do
- Net::HTTP.new("localhost", 3333).proxy_address.should be_nil
- end
- end
-
- describe "when self is a proxy class instance" do
- it "returns the password for self's proxy connection" do
- http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.new("localhost", 3333).proxy_address.should == "localhost"
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/proxy_class_spec.rb b/spec/ruby/library/net-http/http/proxy_class_spec.rb
deleted file mode 100644
index 00975aef4e..0000000000
--- a/spec/ruby/library/net-http/http/proxy_class_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.proxy_class?" do
- it "returns true if self is a class created with Net::HTTP.Proxy" do
- Net::HTTP.proxy_class?.should be_false
- Net::HTTP.Proxy("localhost").proxy_class?.should be_true
- end
-end
diff --git a/spec/ruby/library/net-http/http/proxy_pass_spec.rb b/spec/ruby/library/net-http/http/proxy_pass_spec.rb
deleted file mode 100644
index 4e393a53ff..0000000000
--- a/spec/ruby/library/net-http/http/proxy_pass_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.proxy_pass" do
- describe "when self is no proxy class" do
- it "returns nil" do
- Net::HTTP.proxy_pass.should be_nil
- end
- end
-
- describe "when self is a proxy class" do
- it "returns nil if no password was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").proxy_pass.should be_nil
- end
-
- it "returns the password for self's proxy connection" do
- Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_pass.should == "rocks"
- end
- end
-end
-
-describe "Net::HTTP#proxy_pass" do
- describe "when self is no proxy class instance" do
- it "returns nil" do
- Net::HTTP.new("localhost", 3333).proxy_pass.should be_nil
- end
- end
-
- describe "when self is a proxy class instance" do
- it "returns nil if no password was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_pass.should be_nil
- end
-
- it "returns the password for self's proxy connection" do
- http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.new("localhost", 3333).proxy_pass.should == "rocks"
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/proxy_port_spec.rb b/spec/ruby/library/net-http/http/proxy_port_spec.rb
deleted file mode 100644
index d7d37f3927..0000000000
--- a/spec/ruby/library/net-http/http/proxy_port_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.proxy_port" do
- describe "when self is no proxy class" do
- it "returns nil" do
- Net::HTTP.proxy_port.should be_nil
- end
- end
-
- describe "when self is a proxy class" do
- it "returns 80 if no port was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").proxy_port.should eql(80)
- end
-
- it "returns the port for self's proxy connection" do
- Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_port.should eql(1234)
- end
- end
-end
-
-describe "Net::HTTP#proxy_port" do
- describe "when self is no proxy class instance" do
- it "returns nil" do
- Net::HTTP.new("localhost", 3333).proxy_port.should be_nil
- end
- end
-
- describe "when self is a proxy class instance" do
- it "returns 80 if no port was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_port.should eql(80)
- end
-
- it "returns the port for self's proxy connection" do
- http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.new("localhost", 3333).proxy_port.should eql(1234)
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/proxy_user_spec.rb b/spec/ruby/library/net-http/http/proxy_user_spec.rb
deleted file mode 100644
index ef7654425d..0000000000
--- a/spec/ruby/library/net-http/http/proxy_user_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.proxy_user" do
- describe "when self is no proxy class" do
- it "returns nil" do
- Net::HTTP.proxy_user.should be_nil
- end
- end
-
- describe "when self is a proxy class" do
- it "returns nil if no username was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").proxy_user.should be_nil
- end
-
- it "returns the username for self's proxy connection" do
- Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_user.should == "rspec"
- end
- end
-end
-
-describe "Net::HTTP#proxy_user" do
- describe "when self is no proxy class instance" do
- it "returns nil" do
- Net::HTTP.new("localhost", 3333).proxy_user.should be_nil
- end
- end
-
- describe "when self is a proxy class instance" do
- it "returns nil if no username was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_user.should be_nil
- end
-
- it "returns the username for self's proxy connection" do
- http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.new("localhost", 3333).proxy_user.should == "rspec"
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/put2_spec.rb b/spec/ruby/library/net-http/http/put2_spec.rb
deleted file mode 100644
index 7b03a39d0b..0000000000
--- a/spec/ruby/library/net-http/http/put2_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_put'
-
-describe "Net::HTTP#put2" do
- it_behaves_like :net_http_request_put, :put2
-end
diff --git a/spec/ruby/library/net-http/http/put_spec.rb b/spec/ruby/library/net-http/http/put_spec.rb
deleted file mode 100644
index 75f3c243d4..0000000000
--- a/spec/ruby/library/net-http/http/put_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#put" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends an put request to the passed path and returns the response" do
- response = @http.put("/request", "test=test")
- response.body.should == "Request type: PUT"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.put("/request", "test=test").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net-http/http/read_timeout_spec.rb b/spec/ruby/library/net-http/http/read_timeout_spec.rb
deleted file mode 100644
index 7a0d2f1d72..0000000000
--- a/spec/ruby/library/net-http/http/read_timeout_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#read_timeout" do
- it "returns the seconds to wait until reading one block" do
- net = Net::HTTP.new("localhost")
- net.read_timeout.should eql(60)
- net.read_timeout = 10
- net.read_timeout.should eql(10)
- end
-end
-
-describe "Net::HTTP#read_timeout=" do
- it "sets the seconds to wait till the connection is open" do
- net = Net::HTTP.new("localhost")
- net.read_timeout = 10
- net.read_timeout.should eql(10)
- end
-
- it "returns the newly set value" do
- net = Net::HTTP.new("localhost")
- (net.read_timeout = 10).should eql(10)
- end
-end
diff --git a/spec/ruby/library/net-http/http/request_get_spec.rb b/spec/ruby/library/net-http/http/request_get_spec.rb
deleted file mode 100644
index 98025a14a1..0000000000
--- a/spec/ruby/library/net-http/http/request_get_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_get'
-
-describe "Net::HTTP#request_get" do
- it_behaves_like :net_http_request_get, :get2
-end
diff --git a/spec/ruby/library/net-http/http/request_head_spec.rb b/spec/ruby/library/net-http/http/request_head_spec.rb
deleted file mode 100644
index 8f514d4eee..0000000000
--- a/spec/ruby/library/net-http/http/request_head_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_head'
-
-describe "Net::HTTP#request_head" do
- it_behaves_like :net_http_request_head, :request_head
-end
diff --git a/spec/ruby/library/net-http/http/request_post_spec.rb b/spec/ruby/library/net-http/http/request_post_spec.rb
deleted file mode 100644
index 719bd5a7ee..0000000000
--- a/spec/ruby/library/net-http/http/request_post_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_post'
-
-describe "Net::HTTP#request_post" do
- it_behaves_like :net_http_request_post, :request_post
-end
diff --git a/spec/ruby/library/net-http/http/request_put_spec.rb b/spec/ruby/library/net-http/http/request_put_spec.rb
deleted file mode 100644
index 9fcf3a98d6..0000000000
--- a/spec/ruby/library/net-http/http/request_put_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_put'
-
-describe "Net::HTTP#request_put" do
- it_behaves_like :net_http_request_put, :request_put
-end
diff --git a/spec/ruby/library/net-http/http/request_spec.rb b/spec/ruby/library/net-http/http/request_spec.rb
deleted file mode 100644
index 356e605b3b..0000000000
--- a/spec/ruby/library/net-http/http/request_spec.rb
+++ /dev/null
@@ -1,109 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#request" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- describe "when passed request_object" do
- it "makes a HTTP Request based on the passed request_object" do
- response = @http.request(Net::HTTP::Get.new("/request"), "test=test")
- response.body.should == "Request type: GET"
-
- response = @http.request(Net::HTTP::Head.new("/request"), "test=test")
- response.body.should be_nil
-
- response = @http.request(Net::HTTP::Post.new("/request"), "test=test")
- response.body.should == "Request type: POST"
-
- response = @http.request(Net::HTTP::Put.new("/request"), "test=test")
- response.body.should == "Request type: PUT"
-
- response = @http.request(Net::HTTP::Proppatch.new("/request"), "test=test")
- response.body.should == "Request type: PROPPATCH"
-
- response = @http.request(Net::HTTP::Lock.new("/request"), "test=test")
- response.body.should == "Request type: LOCK"
-
- response = @http.request(Net::HTTP::Unlock.new("/request"), "test=test")
- response.body.should == "Request type: UNLOCK"
-
- # TODO: Does not work?
- #response = @http.request(Net::HTTP::Options.new("/request"), "test=test")
- #response.body.should be_nil
-
- response = @http.request(Net::HTTP::Propfind.new("/request"), "test=test")
- response.body.should == "Request type: PROPFIND"
-
- response = @http.request(Net::HTTP::Delete.new("/request"), "test=test")
- response.body.should == "Request type: DELETE"
-
- response = @http.request(Net::HTTP::Move.new("/request"), "test=test")
- response.body.should == "Request type: MOVE"
-
- response = @http.request(Net::HTTP::Copy.new("/request"), "test=test")
- response.body.should == "Request type: COPY"
-
- response = @http.request(Net::HTTP::Mkcol.new("/request"), "test=test")
- response.body.should == "Request type: MKCOL"
-
- response = @http.request(Net::HTTP::Trace.new("/request"), "test=test")
- response.body.should == "Request type: TRACE"
- end
- end
-
- describe "when passed request_object and request_body" do
- it "sends the passed request_body when making the HTTP Request" do
- response = @http.request(Net::HTTP::Get.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Head.new("/request/body"), "test=test")
- response.body.should be_nil
-
- response = @http.request(Net::HTTP::Post.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Put.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Proppatch.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Lock.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Unlock.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- # TODO: Does not work?
- #response = @http.request(Net::HTTP::Options.new("/request/body"), "test=test")
- #response.body.should be_nil
-
- response = @http.request(Net::HTTP::Propfind.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Delete.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Move.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Copy.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Mkcol.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Trace.new("/request/body"), "test=test")
- response.body.should == "test=test"
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/request_types_spec.rb b/spec/ruby/library/net-http/http/request_types_spec.rb
deleted file mode 100644
index 53aef1ee58..0000000000
--- a/spec/ruby/library/net-http/http/request_types_spec.rb
+++ /dev/null
@@ -1,254 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP::Get" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Get.should < Net::HTTPRequest
- end
-
- it "represents the 'GET'-Request-Method" do
- Net::HTTP::Get::METHOD.should == "GET"
- end
-
- it "has no Request Body" do
- Net::HTTP::Get::REQUEST_HAS_BODY.should be_false
- end
-
- it "has a Response Body" do
- Net::HTTP::Get::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Head" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Head.should < Net::HTTPRequest
- end
-
- it "represents the 'HEAD'-Request-Method" do
- Net::HTTP::Head::METHOD.should == "HEAD"
- end
-
- it "has no Request Body" do
- Net::HTTP::Head::REQUEST_HAS_BODY.should be_false
- end
-
- it "has no Response Body" do
- Net::HTTP::Head::RESPONSE_HAS_BODY.should be_false
- end
-end
-
-describe "Net::HTTP::Post" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Post.should < Net::HTTPRequest
- end
-
- it "represents the 'POST'-Request-Method" do
- Net::HTTP::Post::METHOD.should == "POST"
- end
-
- it "has a Request Body" do
- Net::HTTP::Post::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Post::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Put" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Put.should < Net::HTTPRequest
- end
-
- it "represents the 'PUT'-Request-Method" do
- Net::HTTP::Put::METHOD.should == "PUT"
- end
-
- it "has a Request Body" do
- Net::HTTP::Put::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Put::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Delete" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Delete.should < Net::HTTPRequest
- end
-
- it "represents the 'DELETE'-Request-Method" do
- Net::HTTP::Delete::METHOD.should == "DELETE"
- end
-
- it "has no Request Body" do
- Net::HTTP::Delete::REQUEST_HAS_BODY.should be_false
- end
-
- it "has a Response Body" do
- Net::HTTP::Delete::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Options" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Options.should < Net::HTTPRequest
- end
-
- it "represents the 'OPTIONS'-Request-Method" do
- Net::HTTP::Options::METHOD.should == "OPTIONS"
- end
-
- it "has no Request Body" do
- Net::HTTP::Options::REQUEST_HAS_BODY.should be_false
- end
-
- it "has no Response Body" do
- Net::HTTP::Options::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Trace" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Trace.should < Net::HTTPRequest
- end
-
- it "represents the 'TRACE'-Request-Method" do
- Net::HTTP::Trace::METHOD.should == "TRACE"
- end
-
- it "has no Request Body" do
- Net::HTTP::Trace::REQUEST_HAS_BODY.should be_false
- end
-
- it "has a Response Body" do
- Net::HTTP::Trace::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Propfind" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Propfind.should < Net::HTTPRequest
- end
-
- it "represents the 'PROPFIND'-Request-Method" do
- Net::HTTP::Propfind::METHOD.should == "PROPFIND"
- end
-
- it "has a Request Body" do
- Net::HTTP::Propfind::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Propfind::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Proppatch" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Proppatch.should < Net::HTTPRequest
- end
-
- it "represents the 'PROPPATCH'-Request-Method" do
- Net::HTTP::Proppatch::METHOD.should == "PROPPATCH"
- end
-
- it "has a Request Body" do
- Net::HTTP::Proppatch::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Proppatch::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Mkcol" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Mkcol.should < Net::HTTPRequest
- end
-
- it "represents the 'MKCOL'-Request-Method" do
- Net::HTTP::Mkcol::METHOD.should == "MKCOL"
- end
-
- it "has a Request Body" do
- Net::HTTP::Mkcol::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Mkcol::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Copy" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Copy.should < Net::HTTPRequest
- end
-
- it "represents the 'COPY'-Request-Method" do
- Net::HTTP::Copy::METHOD.should == "COPY"
- end
-
- it "has no Request Body" do
- Net::HTTP::Copy::REQUEST_HAS_BODY.should be_false
- end
-
- it "has a Response Body" do
- Net::HTTP::Copy::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Move" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Move.should < Net::HTTPRequest
- end
-
- it "represents the 'MOVE'-Request-Method" do
- Net::HTTP::Move::METHOD.should == "MOVE"
- end
-
- it "has no Request Body" do
- Net::HTTP::Move::REQUEST_HAS_BODY.should be_false
- end
-
- it "has a Response Body" do
- Net::HTTP::Move::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Lock" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Lock.should < Net::HTTPRequest
- end
-
- it "represents the 'LOCK'-Request-Method" do
- Net::HTTP::Lock::METHOD.should == "LOCK"
- end
-
- it "has a Request Body" do
- Net::HTTP::Lock::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Lock::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Unlock" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Unlock.should < Net::HTTPRequest
- end
-
- it "represents the 'UNLOCK'-Request-Method" do
- Net::HTTP::Unlock::METHOD.should == "UNLOCK"
- end
-
- it "has a Request Body" do
- Net::HTTP::Unlock::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Unlock::RESPONSE_HAS_BODY.should be_true
- end
-end
diff --git a/spec/ruby/library/net-http/http/send_request_spec.rb b/spec/ruby/library/net-http/http/send_request_spec.rb
deleted file mode 100644
index af35c068ce..0000000000
--- a/spec/ruby/library/net-http/http/send_request_spec.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#send_request" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
-
- # HEAD is special so handled separately
- @methods = %w[
- GET POST PUT DELETE
- OPTIONS
- PROPFIND PROPPATCH LOCK UNLOCK
- ]
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- # TODO: Does only work with GET and POST requests
- describe "when passed type, path" do
- it "sends a HTTP Request of the passed type to the passed path" do
- response = @http.send_request("HEAD", "/request")
- response.body.should be_nil
-
- (@methods - %w[POST PUT]).each do |method|
- response = @http.send_request(method, "/request")
- response.body.should == "Request type: #{method}"
- end
- end
- end
-
- describe "when passed type, path, body" do
- it "sends a HTTP Request with the passed body" do
- response = @http.send_request("HEAD", "/request/body", "test=test")
- response.body.should be_nil
-
- @methods.each do |method|
- response = @http.send_request(method, "/request/body", "test=test")
- response.body.should == "test=test"
- end
- end
- end
-
- describe "when passed type, path, body, headers" do
- it "sends a HTTP Request with the passed headers" do
- referer = 'https://www.ruby-lang.org/'.freeze
-
- response = @http.send_request("HEAD", "/request/header", "test=test", "referer" => referer)
- response.body.should be_nil
-
- @methods.each do |method|
- response = @http.send_request(method, "/request/header", "test=test", "referer" => referer)
- response.body.should include({ "Referer" => referer }.inspect.delete("{}"))
- end
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/set_debug_output_spec.rb b/spec/ruby/library/net-http/http/set_debug_output_spec.rb
deleted file mode 100644
index 5ceecb39fb..0000000000
--- a/spec/ruby/library/net-http/http/set_debug_output_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require "stringio"
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#set_debug_output when passed io" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.new("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sets the passed io as output stream for debugging" do
- io = StringIO.new
-
- @http.set_debug_output(io)
- @http.start
- io.string.should_not be_empty
- size = io.string.size
-
- @http.get("/")
- io.string.size.should > size
- end
-
- it "outputs a warning when the connection has already been started" do
- @http.start
- -> { @http.set_debug_output(StringIO.new) }.should complain(/Net::HTTP#set_debug_output called after HTTP started/)
- end
-end
diff --git a/spec/ruby/library/net-http/http/socket_type_spec.rb b/spec/ruby/library/net-http/http/socket_type_spec.rb
deleted file mode 100644
index f6826777b0..0000000000
--- a/spec/ruby/library/net-http/http/socket_type_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.socket_type" do
- it "returns BufferedIO" do
- Net::HTTP.socket_type.should == Net::BufferedIO
- end
-end
diff --git a/spec/ruby/library/net-http/http/start_spec.rb b/spec/ruby/library/net-http/http/start_spec.rb
deleted file mode 100644
index 0ce3e79269..0000000000
--- a/spec/ruby/library/net-http/http/start_spec.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP.start" do
- before :each do
- NetHTTPSpecs.start_server
- @port = NetHTTPSpecs.port
- end
-
- after :each do
- NetHTTPSpecs.stop_server
- end
-
- describe "when not passed a block" do
- before :each do
- @http = Net::HTTP.start("localhost", @port)
- end
-
- after :each do
- @http.finish if @http.started?
- end
-
- it "returns a new Net::HTTP object for the passed address and port" do
- @http.should be_kind_of(Net::HTTP)
- @http.address.should == "localhost"
- @http.port.should == @port
- end
-
- it "opens the tcp connection" do
- @http.started?.should be_true
- end
- end
-
- describe "when passed a block" do
- it "returns the blocks return value" do
- Net::HTTP.start("localhost", @port) { :test }.should == :test
- end
-
- it "yields the new Net::HTTP object to the block" do
- yielded = false
- Net::HTTP.start("localhost", @port) do |net|
- yielded = true
- net.should be_kind_of(Net::HTTP)
- end
- yielded.should be_true
- end
-
- it "opens the tcp connection before yielding" do
- Net::HTTP.start("localhost", @port) { |http| http.started?.should be_true }
- end
-
- it "closes the tcp connection after yielding" do
- net = nil
- Net::HTTP.start("localhost", @port) { |x| net = x }
- net.started?.should be_false
- end
- end
-end
-
-describe "Net::HTTP#start" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.new("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "returns self" do
- @http.start.should equal(@http)
- end
-
- it "opens the tcp connection" do
- @http.start
- @http.started?.should be_true
- end
-
- describe "when self has already been started" do
- it "raises an IOError" do
- @http.start
- -> { @http.start }.should raise_error(IOError)
- end
- end
-
- describe "when passed a block" do
- it "returns the blocks return value" do
- @http.start { :test }.should == :test
- end
-
- it "yields the new Net::HTTP object to the block" do
- yielded = false
- @http.start do |http|
- yielded = true
- http.should equal(@http)
- end
- yielded.should be_true
- end
-
- it "opens the tcp connection before yielding" do
- @http.start { |http| http.started?.should be_true }
- end
-
- it "closes the tcp connection after yielding" do
- @http.start { }
- @http.started?.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/net-http/http/started_spec.rb b/spec/ruby/library/net-http/http/started_spec.rb
deleted file mode 100644
index cbb82ceefa..0000000000
--- a/spec/ruby/library/net-http/http/started_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/started'
-
-describe "Net::HTTP#started?" do
- it_behaves_like :net_http_started_p, :started?
-end
diff --git a/spec/ruby/library/net-http/http/trace_spec.rb b/spec/ruby/library/net-http/http/trace_spec.rb
deleted file mode 100644
index 9809d537c5..0000000000
--- a/spec/ruby/library/net-http/http/trace_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#trace" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a TRACE request to the passed path and returns the response" do
- response = @http.trace("/request")
- response.body.should == "Request type: TRACE"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.trace("/request").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net-http/http/unlock_spec.rb b/spec/ruby/library/net-http/http/unlock_spec.rb
deleted file mode 100644
index adf0b49f65..0000000000
--- a/spec/ruby/library/net-http/http/unlock_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#unlock" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends an UNLOCK request to the passed path and returns the response" do
- response = @http.unlock("/request", "test=test")
- response.body.should == "Request type: UNLOCK"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.unlock("/request", "test=test").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net-http/http/use_ssl_spec.rb b/spec/ruby/library/net-http/http/use_ssl_spec.rb
deleted file mode 100644
index 912a62a8ba..0000000000
--- a/spec/ruby/library/net-http/http/use_ssl_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#use_ssl?" do
- it "returns false" do
- http = Net::HTTP.new("localhost")
- http.use_ssl?.should be_false
- end
-end
diff --git a/spec/ruby/library/net-http/http/version_1_1_spec.rb b/spec/ruby/library/net-http/http/version_1_1_spec.rb
deleted file mode 100644
index 34a4ac8a6b..0000000000
--- a/spec/ruby/library/net-http/http/version_1_1_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'shared/version_1_1'
-
-describe "Net::HTTP.version_1_1?" do
- it_behaves_like :net_http_version_1_1_p, :version_1_1?
-end
diff --git a/spec/ruby/library/net-http/http/version_1_2_spec.rb b/spec/ruby/library/net-http/http/version_1_2_spec.rb
deleted file mode 100644
index e994511aea..0000000000
--- a/spec/ruby/library/net-http/http/version_1_2_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'shared/version_1_2'
-
-describe "Net::HTTP.version_1_2" do
- it "turns on net/http 1.2 features" do
- Net::HTTP.version_1_2
-
- Net::HTTP.version_1_2?.should be_true
- Net::HTTP.version_1_1?.should be_false
- end
-
- it "returns true" do
- Net::HTTP.version_1_2.should be_true
- end
-end
-
-describe "Net::HTTP.version_1_2?" do
- it_behaves_like :net_http_version_1_2_p, :version_1_2?
-end
diff --git a/spec/ruby/library/net-http/httpexceptions/initialize_spec.rb b/spec/ruby/library/net-http/httpexceptions/initialize_spec.rb
deleted file mode 100644
index 5316cca69d..0000000000
--- a/spec/ruby/library/net-http/httpexceptions/initialize_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPExceptions#initialize when passed message, response" do
- before :each do
- @exception = NetHTTPExceptionsSpecs::Simple.new("error message", "a http response")
- end
-
- it "calls super with the passed message" do
- @exception.message.should == "error message"
- end
-
- it "sets self's response to the passed response" do
- @exception.response.should == "a http response"
- end
-end
diff --git a/spec/ruby/library/net-http/httpexceptions/response_spec.rb b/spec/ruby/library/net-http/httpexceptions/response_spec.rb
deleted file mode 100644
index d718b1ae21..0000000000
--- a/spec/ruby/library/net-http/httpexceptions/response_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPExceptions#response" do
- it "returns self's response" do
- exception = NetHTTPExceptionsSpecs::Simple.new("error message", "a http response")
- exception.response.should == "a http response"
- end
-end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb
deleted file mode 100644
index 6c886499ca..0000000000
--- a/spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#body_exist?" do
- it "returns true when the response is expected to have a body" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.body_exist?.should be_true
-
- request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
- request.body_exist?.should be_false
- end
-
- describe "when $VERBOSE is true" do
- it "emits a warning" do
- request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
- -> {
- request.body_exist?
- }.should complain(/body_exist\? is obsolete/, verbose: true)
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb
deleted file mode 100644
index 5f7315f303..0000000000
--- a/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require "stringio"
-
-describe "Net::HTTPGenericRequest#body" do
- it "returns self's request body" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.body.should be_nil
-
- request.body = "Some Content"
- request.body.should == "Some Content"
- end
-end
-
-describe "Net::HTTPGenericRequest#body=" do
- before :each do
- @request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- end
-
- it "sets self's body content to the passed String" do
- @request.body = "Some Content"
- @request.body.should == "Some Content"
- end
-
- it "sets self's body stream to nil" do
- @request.body_stream = StringIO.new("")
- @request.body = "Some Content"
- @request.body_stream.should be_nil
- end
-end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb
deleted file mode 100644
index dea1c8c883..0000000000
--- a/spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require "stringio"
-
-describe "Net::HTTPGenericRequest#body_stream" do
- it "returns self's body stream Object" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.body_stream.should be_nil
-
- stream = StringIO.new("test")
- request.body_stream = stream
- request.body_stream.should equal(stream)
- end
-end
-
-describe "Net::HTTPGenericRequest#body_stream=" do
- before :each do
- @request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- @stream = StringIO.new("test")
- end
-
- it "sets self's body stream to the passed Object" do
- @request.body_stream = @stream
- @request.body_stream.should equal(@stream)
- end
-
- it "sets self's body to nil" do
- @request.body = "Some Content"
- @request.body_stream = @stream
- @request.body.should be_nil
- end
-end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb
deleted file mode 100644
index 7de03d7da0..0000000000
--- a/spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb
+++ /dev/null
@@ -1,131 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require "stringio"
-
-describe "Net::HTTPGenericRequest#exec when passed socket, version, path" do
- before :each do
- @socket = StringIO.new(+"")
- @buffered_socket = Net::BufferedIO.new(@socket)
- end
-
- it "executes the request over the socket to the path using the HTTP version" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
-
- request.exec(@buffered_socket, "1.1", "/some/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str[-4..-1].should == "\r\n\r\n"
-
- request = Net::HTTPGenericRequest.new("GET", true, true, "/some/path",
- "Content-Type" => "text/html")
-
- request.exec(@buffered_socket, "1.0", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[GET /some/other/path HTTP/1.0\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: text/html\r\n]
- str[-4..-1].should == "\r\n\r\n"
- end
-
- describe "when a request body is set" do
- it "sets the 'Content-Type' header to 'application/x-www-form-urlencoded' unless the 'Content-Type' header is supplied" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.body = "Some Content"
-
- request.exec(@buffered_socket, "1.1", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: application/x-www-form-urlencoded\r\n]
- str.should =~ %r[Content-Length: 12\r\n]
- str[-16..-1].should == "\r\n\r\nSome Content"
- end
-
- it "correctly sets the 'Content-Length' header and includes the body" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
- "Content-Type" => "text/html")
- request.body = "Some Content"
-
- request.exec(@buffered_socket, "1.1", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: text/html\r\n]
- str.should =~ %r[Content-Length: 12\r\n]
- str[-16..-1].should == "\r\n\r\nSome Content"
- end
- end
-
- describe "when a body stream is set" do
- it "sets the 'Content-Type' header to 'application/x-www-form-urlencoded' unless the 'Content-Type' header is supplied" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
- "Content-Length" => "10")
- request.body_stream = StringIO.new("a" * 20)
-
- request.exec(@buffered_socket, "1.1", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: application/x-www-form-urlencoded\r\n]
- str.should =~ %r[Content-Length: 10\r\n]
- str[-24..-1].should == "\r\n\r\naaaaaaaaaaaaaaaaaaaa"
- end
-
- it "sends the whole stream, regardless of the 'Content-Length' header" do
- request = Net::HTTPGenericRequest.new("POST", true, true,"/some/path",
- "Content-Type" => "text/html",
- "Content-Length" => "10")
- request.body_stream = StringIO.new("a" * 20)
-
- request.exec(@buffered_socket, "1.1", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: text/html\r\n]
- str.should =~ %r[Content-Length: 10\r\n]
- str[-24..-1].should == "\r\n\r\naaaaaaaaaaaaaaaaaaaa"
- end
-
- it "sends the request in chunks when 'Transfer-Encoding' is set to 'chunked'" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
- "Content-Type" => "text/html",
- "Transfer-Encoding" => "chunked")
- datasize = 1024 * 10
- request.body_stream = StringIO.new("a" * datasize)
-
- request.exec(@buffered_socket, "1.1", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: text/html\r\n]
- str.should =~ %r[Transfer-Encoding: chunked\r\n]
- str =~ %r[\r\n\r\n]
- str = $'
- while datasize > 0
- chunk_size_line, str = str.split(/\r\n/, 2)
- chunk_size = chunk_size_line[/\A[0-9A-Fa-f]+/].to_i(16)
- str.slice!(0, chunk_size).should == 'a' * chunk_size
- datasize -= chunk_size
- str.slice!(0, 2).should == "\r\n"
- end
- datasize.should == 0
- str.should == %"0\r\n\r\n"
- end
-
- it "raises an ArgumentError when the 'Content-Length' is not set or 'Transfer-Encoding' is not set to 'chunked'" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
- "Content-Type" => "text/html")
- request.body_stream = StringIO.new("Some Content")
-
- -> { request.exec(@buffered_socket, "1.1", "/some/other/path") }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/inspect_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/inspect_spec.rb
deleted file mode 100644
index d03b6e6953..0000000000
--- a/spec/ruby/library/net-http/httpgenericrequest/inspect_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#inspect" do
- it "returns a String representation of self" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.inspect.should == "#<Net::HTTPGenericRequest POST>"
-
- request = Net::HTTPGenericRequest.new("GET", false, true, "/some/path")
- request.inspect.should == "#<Net::HTTPGenericRequest GET>"
-
- request = Net::HTTPGenericRequest.new("BLA", true, true, "/some/path")
- request.inspect.should == "#<Net::HTTPGenericRequest BLA>"
-
- # Subclasses
- request = Net::HTTP::Get.new("/some/path")
- request.inspect.should == "#<Net::HTTP::Get GET>"
-
- request = Net::HTTP::Post.new("/some/path")
- request.inspect.should == "#<Net::HTTP::Post POST>"
-
- request = Net::HTTP::Trace.new("/some/path")
- request.inspect.should == "#<Net::HTTP::Trace TRACE>"
- end
-end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/method_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/method_spec.rb
deleted file mode 100644
index 794bd328cd..0000000000
--- a/spec/ruby/library/net-http/httpgenericrequest/method_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#method" do
- it "returns self's request method" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.method.should == "POST"
-
- request = Net::HTTPGenericRequest.new("GET", false, true, "/some/path")
- request.method.should == "GET"
-
- request = Net::HTTPGenericRequest.new("BLA", true, true, "/some/path")
- request.method.should == "BLA"
- end
-end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/path_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/path_spec.rb
deleted file mode 100644
index a9fac3f67e..0000000000
--- a/spec/ruby/library/net-http/httpgenericrequest/path_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#path" do
- it "returns self's request path" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.path.should == "/some/path"
-
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/other/path")
- request.path.should == "/some/other/path"
- end
-end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb
deleted file mode 100644
index 1713b59baf..0000000000
--- a/spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#request_body_permitted?" do
- it "returns true when the request is expected to have a body" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.request_body_permitted?.should be_true
-
- request = Net::HTTPGenericRequest.new("POST", false, true, "/some/path")
- request.request_body_permitted?.should be_false
- end
-end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb
deleted file mode 100644
index 2f0751c344..0000000000
--- a/spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#response_body_permitted?" do
- it "returns true when the response is expected to have a body" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.response_body_permitted?.should be_true
-
- request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
- request.response_body_permitted?.should be_false
- end
-end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb
deleted file mode 100644
index 358aa6cde3..0000000000
--- a/spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#set_body_internal when passed string" do
- before :each do
- @request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- end
-
- it "sets self's body to the passed string" do
- @request.set_body_internal("Some Content")
- @request.body.should == "Some Content"
- end
-
- it "raises an ArgumentError when the body or body_stream of self have already been set" do
- @request.body = "Some Content"
- -> { @request.set_body_internal("Some other Content") }.should raise_error(ArgumentError)
-
- @request.body_stream = "Some Content"
- -> { @request.set_body_internal("Some other Content") }.should raise_error(ArgumentError)
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/add_field_spec.rb b/spec/ruby/library/net-http/httpheader/add_field_spec.rb
deleted file mode 100644
index 8cd3d33517..0000000000
--- a/spec/ruby/library/net-http/httpheader/add_field_spec.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#add_field when passed key, value" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "adds the passed value to the header entry with the passed key" do
- @headers.add_field("My-Header", "a")
- @headers.get_fields("My-Header").should == ["a"]
-
- @headers.add_field("My-Header", "b")
- @headers.get_fields("My-Header").should == ["a", "b"]
-
- @headers.add_field("My-Header", "c")
- @headers.get_fields("My-Header").should == ["a", "b", "c"]
- end
-
- it "is case-insensitive" do
- @headers.add_field("My-Header", "a")
- @headers.get_fields("My-Header").should == ["a"]
-
- @headers.add_field("my-header", "b")
- @headers.get_fields("My-Header").should == ["a", "b"]
-
- @headers.add_field("MY-HEADER", "c")
- @headers.get_fields("My-Header").should == ["a", "b", "c"]
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/basic_auth_spec.rb b/spec/ruby/library/net-http/httpheader/basic_auth_spec.rb
deleted file mode 100644
index db7ca84d13..0000000000
--- a/spec/ruby/library/net-http/httpheader/basic_auth_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#basic_auth when passed account, password" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "sets the 'Authorization' Header entry for basic authorization" do
- @headers.basic_auth("rubyspec", "rocks")
- @headers["Authorization"].should == "Basic cnVieXNwZWM6cm9ja3M="
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/canonical_each_spec.rb b/spec/ruby/library/net-http/httpheader/canonical_each_spec.rb
deleted file mode 100644
index 64a5cae89e..0000000000
--- a/spec/ruby/library/net-http/httpheader/canonical_each_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/each_capitalized'
-
-describe "Net::HTTPHeader#canonical_each" do
- it_behaves_like :net_httpheader_each_capitalized, :canonical_each
-end
diff --git a/spec/ruby/library/net-http/httpheader/chunked_spec.rb b/spec/ruby/library/net-http/httpheader/chunked_spec.rb
deleted file mode 100644
index b32a0aab38..0000000000
--- a/spec/ruby/library/net-http/httpheader/chunked_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#chunked?" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns true if the 'Transfer-Encoding' header entry is set to chunked" do
- @headers.chunked?.should be_false
-
- @headers["Transfer-Encoding"] = "bla"
- @headers.chunked?.should be_false
-
- @headers["Transfer-Encoding"] = "blachunkedbla"
- @headers.chunked?.should be_false
-
- @headers["Transfer-Encoding"] = "chunked"
- @headers.chunked?.should be_true
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/content_length_spec.rb b/spec/ruby/library/net-http/httpheader/content_length_spec.rb
deleted file mode 100644
index f05c5f8d8b..0000000000
--- a/spec/ruby/library/net-http/httpheader/content_length_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#content_length" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns nil if no 'Content-Length' header entry is set" do
- @headers.content_length.should be_nil
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Length' header entry has an invalid format" do
- @headers["Content-Length"] = "invalid"
- -> { @headers.content_length }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-
- it "returns the value of the 'Content-Length' header entry as an Integer" do
- @headers["Content-Length"] = "123"
- @headers.content_length.should eql(123)
-
- @headers["Content-Length"] = "123valid"
- @headers.content_length.should eql(123)
-
- @headers["Content-Length"] = "valid123"
- @headers.content_length.should eql(123)
- end
-end
-
-describe "Net::HTTPHeader#content_length=" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "removes the 'Content-Length' entry if passed false or nil" do
- @headers["Content-Length"] = "123"
- @headers.content_length = nil
- @headers["Content-Length"].should be_nil
- end
-
- it "sets the 'Content-Length' entry to the passed value" do
- @headers.content_length = "123"
- @headers["Content-Length"].should == "123"
-
- @headers.content_length = "123valid"
- @headers["Content-Length"].should == "123"
- end
-
- it "sets the 'Content-Length' entry to 0 if the passed value is not valid" do
- @headers.content_length = "invalid123"
- @headers["Content-Length"].should == "0"
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/content_range_spec.rb b/spec/ruby/library/net-http/httpheader/content_range_spec.rb
deleted file mode 100644
index 09737141a5..0000000000
--- a/spec/ruby/library/net-http/httpheader/content_range_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#content_range" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns a Range object that represents the 'Content-Range' header entry" do
- @headers["Content-Range"] = "bytes 0-499/1234"
- @headers.content_range.should == (0..499)
-
- @headers["Content-Range"] = "bytes 500-1233/1234"
- @headers.content_range.should == (500..1233)
- end
-
- it "returns nil when there is no 'Content-Range' header entry" do
- @headers.content_range.should be_nil
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Range' has an invalid format" do
- @headers["Content-Range"] = "invalid"
- -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
-
- @headers["Content-Range"] = "bytes 123-abc"
- -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
-
- @headers["Content-Range"] = "bytes abc-123"
- -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/content_type_spec.rb b/spec/ruby/library/net-http/httpheader/content_type_spec.rb
deleted file mode 100644
index a6e1ae1093..0000000000
--- a/spec/ruby/library/net-http/httpheader/content_type_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/set_content_type'
-
-describe "Net::HTTPHeader#content_type" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns the content type string, as per 'Content-Type' header entry" do
- @headers["Content-Type"] = "text/html"
- @headers.content_type.should == "text/html"
-
- @headers["Content-Type"] = "text/html;charset=utf-8"
- @headers.content_type.should == "text/html"
- end
-
- it "returns nil if the 'Content-Type' header entry does not exist" do
- @headers.content_type.should be_nil
- end
-end
-
-describe "Net::HTTPHeader#content_type=" do
- it_behaves_like :net_httpheader_set_content_type, :content_type=
-end
diff --git a/spec/ruby/library/net-http/httpheader/delete_spec.rb b/spec/ruby/library/net-http/httpheader/delete_spec.rb
deleted file mode 100644
index 8d929dbd86..0000000000
--- a/spec/ruby/library/net-http/httpheader/delete_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#delete when passed key" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "removes the header entry with the passed key" do
- @headers["My-Header"] = "test"
- @headers.delete("My-Header")
-
- @headers["My-Header"].should be_nil
- @headers.size.should eql(0)
- end
-
- it "returns the removed values" do
- @headers["My-Header"] = "test"
- @headers.delete("My-Header").should == ["test"]
- end
-
- it "is case-insensitive" do
- @headers["My-Header"] = "test"
- @headers.delete("my-header")
-
- @headers["My-Header"].should be_nil
- @headers.size.should eql(0)
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb b/spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb
deleted file mode 100644
index 27713577f9..0000000000
--- a/spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#each_capitalized_name" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- @headers["My-Header"] = "test"
- @headers.add_field("My-Other-Header", "a")
- @headers.add_field("My-Other-Header", "b")
- end
-
- describe "when passed a block" do
- it "yields each header key to the passed block (keys capitalized)" do
- res = []
- @headers.each_capitalized_name do |key|
- res << key
- end
- res.sort.should == ["My-Header", "My-Other-Header"]
- end
- end
-
- describe "when passed no block" do
- it "returns an Enumerator" do
- enumerator = @headers.each_capitalized_name
- enumerator.should be_an_instance_of(Enumerator)
-
- res = []
- enumerator.each do |key|
- res << key
- end
- res.sort.should == ["My-Header", "My-Other-Header"]
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/each_capitalized_spec.rb b/spec/ruby/library/net-http/httpheader/each_capitalized_spec.rb
deleted file mode 100644
index 1e853995ea..0000000000
--- a/spec/ruby/library/net-http/httpheader/each_capitalized_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/each_capitalized'
-
-describe "Net::HTTPHeader#each_capitalized" do
- it_behaves_like :net_httpheader_each_capitalized, :each_capitalized
-end
diff --git a/spec/ruby/library/net-http/httpheader/each_header_spec.rb b/spec/ruby/library/net-http/httpheader/each_header_spec.rb
deleted file mode 100644
index 869feebacf..0000000000
--- a/spec/ruby/library/net-http/httpheader/each_header_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/each_header'
-
-describe "Net::HTTPHeader#each_header" do
- it_behaves_like :net_httpheader_each_header, :each_header
-end
diff --git a/spec/ruby/library/net-http/httpheader/each_key_spec.rb b/spec/ruby/library/net-http/httpheader/each_key_spec.rb
deleted file mode 100644
index 1ad145629f..0000000000
--- a/spec/ruby/library/net-http/httpheader/each_key_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/each_name'
-
-describe "Net::HTTPHeader#each_key" do
- it_behaves_like :net_httpheader_each_name, :each_key
-end
diff --git a/spec/ruby/library/net-http/httpheader/each_name_spec.rb b/spec/ruby/library/net-http/httpheader/each_name_spec.rb
deleted file mode 100644
index f819bd989d..0000000000
--- a/spec/ruby/library/net-http/httpheader/each_name_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/each_name'
-
-describe "Net::HTTPHeader#each_name" do
- it_behaves_like :net_httpheader_each_name, :each_name
-end
diff --git a/spec/ruby/library/net-http/httpheader/each_spec.rb b/spec/ruby/library/net-http/httpheader/each_spec.rb
deleted file mode 100644
index ff37249d0a..0000000000
--- a/spec/ruby/library/net-http/httpheader/each_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/each_header'
-
-describe "Net::HTTPHeader#each" do
- it_behaves_like :net_httpheader_each_header, :each
-end
diff --git a/spec/ruby/library/net-http/httpheader/each_value_spec.rb b/spec/ruby/library/net-http/httpheader/each_value_spec.rb
deleted file mode 100644
index b71df58c65..0000000000
--- a/spec/ruby/library/net-http/httpheader/each_value_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#each_value" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- @headers["My-Header"] = "test"
- @headers.add_field("My-Other-Header", "a")
- @headers.add_field("My-Other-Header", "b")
- end
-
- describe "when passed a block" do
- it "yields each header entry's joined values" do
- res = []
- @headers.each_value do |value|
- res << value
- end
- res.sort.should == ["a, b", "test"]
- end
- end
-
- describe "when passed no block" do
- it "returns an Enumerator" do
- enumerator = @headers.each_value
- enumerator.should be_an_instance_of(Enumerator)
-
- res = []
- enumerator.each do |key|
- res << key
- end
- res.sort.should == ["a, b", "test"]
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/element_reference_spec.rb b/spec/ruby/library/net-http/httpheader/element_reference_spec.rb
deleted file mode 100644
index 1003c41af9..0000000000
--- a/spec/ruby/library/net-http/httpheader/element_reference_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#[] when passed key" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns the value of the header entry with the passed key" do
- @headers["My-Header"] = "test"
- @headers["My-Header"].should == "test"
- @headers["My-Other-Header"] = "another test"
- @headers["My-Other-Header"].should == "another test"
- end
-
- it "is case-insensitive" do
- @headers["My-Header"] = "test"
-
- @headers['My-Header'].should == "test"
- @headers['my-Header'].should == "test"
- @headers['My-header'].should == "test"
- @headers['my-header'].should == "test"
- @headers['MY-HEADER'].should == "test"
- end
-
- it "returns multi-element values joined together" do
- @headers["My-Header"] = "test"
- @headers.add_field("My-Header", "another test")
- @headers.add_field("My-Header", "and one more")
-
- @headers["My-Header"].should == "test, another test, and one more"
- end
-
- it "returns nil for non-existing entries" do
- @headers["My-Header"].should be_nil
- @headers["My-Other-Header"].should be_nil
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/element_set_spec.rb b/spec/ruby/library/net-http/httpheader/element_set_spec.rb
deleted file mode 100644
index 376df2f977..0000000000
--- a/spec/ruby/library/net-http/httpheader/element_set_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#[]= when passed key, value" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "sets the header entry with the passed key to the passed value" do
- @headers["My-Header"] = "test"
- @headers["My-Header"].should == "test"
-
- @headers["My-Header"] = "overwritten"
- @headers["My-Header"].should == "overwritten"
-
- @headers["My-Other-Header"] = "another test"
- @headers["My-Other-Header"].should == "another test"
- end
-
- it "is case-insensitive" do
- @headers['My-Header'] = "test"
- @headers['my-Header'] = "another test"
- @headers['My-header'] = "and one more test"
- @headers['my-header'] = "and another one"
- @headers['MY-HEADER'] = "last one"
-
- @headers["My-Header"].should == "last one"
- @headers.size.should eql(1)
- end
-
- it "removes the header entry with the passed key when the value is false or nil" do
- @headers['My-Header'] = "test"
- @headers['My-Header'] = nil
- @headers['My-Header'].should be_nil
-
- @headers['My-Header'] = "test"
- @headers['My-Header'] = false
- @headers['My-Header'].should be_nil
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/fetch_spec.rb b/spec/ruby/library/net-http/httpheader/fetch_spec.rb
deleted file mode 100644
index 58c69c0377..0000000000
--- a/spec/ruby/library/net-http/httpheader/fetch_spec.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#fetch" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- describe "when passed key" do
- it "returns the header entry for the passed key" do
- @headers["My-Header"] = "test"
- @headers.fetch("My-Header").should == "test"
-
- @headers.add_field("My-Other-Header", "a")
- @headers.add_field("My-Other-Header", "b")
- @headers.add_field("My-Other-Header", "c")
- @headers.fetch("My-Other-Header").should == "a, b, c"
- end
-
- it "is case-insensitive" do
- @headers["My-Header"] = "test"
- @headers.fetch("my-header").should == "test"
- @headers.fetch("MY-HEADER").should == "test"
- end
-
- it "returns nil when there is no entry for the passed key" do
- -> { @headers.fetch("my-header") }.should raise_error(IndexError)
- end
- end
-
- describe "when passed key, default" do
- it "returns the header entry for the passed key" do
- @headers["My-Header"] = "test"
- @headers.fetch("My-Header", "bla").should == "test"
-
- @headers.add_field("My-Other-Header", "a")
- @headers.add_field("My-Other-Header", "b")
- @headers.add_field("My-Other-Header", "c")
- @headers.fetch("My-Other-Header", "bla").should == "a, b, c"
- end
-
- # TODO: This raises a NoMethodError: undefined method `join' for "bla":String
- it "returns the default value when there is no entry for the passed key" do
- @headers.fetch("My-Header", "bla").should == "bla"
- end
- end
-
- describe "when passed key and block" do
- it "returns the header entry for the passed key" do
- @headers["My-Header"] = "test"
- @headers.fetch("My-Header") {}.should == "test"
-
- @headers.add_field("My-Other-Header", "a")
- @headers.add_field("My-Other-Header", "b")
- @headers.add_field("My-Other-Header", "c")
- -> {
- @result = @headers.fetch("My-Other-Header", "bla") {}
- }.should complain(/block supersedes default value argument/)
- @result.should == "a, b, c"
- end
-
- # TODO: This raises a NoMethodError: undefined method `join' for "redaeh-ym":String
- it "yieldsand returns the block's return value when there is no entry for the passed key" do
- @headers.fetch("My-Header") { |key| key.reverse }.should == "redaeh-ym"
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/form_data_spec.rb b/spec/ruby/library/net-http/httpheader/form_data_spec.rb
deleted file mode 100644
index acd913f53a..0000000000
--- a/spec/ruby/library/net-http/httpheader/form_data_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/set_form_data'
-
-describe "Net::HTTPHeader#form_data=" do
- it_behaves_like :net_httpheader_set_form_data, :form_data=
-end
diff --git a/spec/ruby/library/net-http/httpheader/get_fields_spec.rb b/spec/ruby/library/net-http/httpheader/get_fields_spec.rb
deleted file mode 100644
index 0278bcede2..0000000000
--- a/spec/ruby/library/net-http/httpheader/get_fields_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#get_fields when passed key" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns an Array containing the values of the header entry with the passed key" do
- @headers["My-Header"] = "a"
- @headers.get_fields("My-Header").should == ["a"]
-
- @headers.add_field("My-Header", "b")
- @headers.get_fields("My-Header").should == ["a", "b"]
- end
-
- it "returns a copy of the header entry values" do
- @headers["My-Header"] = "a"
-
- @headers.get_fields("My-Header").clear
- @headers.get_fields("My-Header").should == ["a"]
-
- @headers.get_fields("My-Header") << "b"
- @headers.get_fields("My-Header").should == ["a"]
- end
-
- it "returns nil for non-existing header entries" do
- @headers.get_fields("My-Header").should be_nil
- @headers.get_fields("My-Other-header").should be_nil
- end
-
- it "is case-insensitive" do
- @headers["My-Header"] = "test"
- @headers.get_fields("My-Header").should == ["test"]
- @headers.get_fields("my-header").should == ["test"]
- @headers.get_fields("MY-HEADER").should == ["test"]
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/initialize_http_header_spec.rb b/spec/ruby/library/net-http/httpheader/initialize_http_header_spec.rb
deleted file mode 100644
index f9e6d208e5..0000000000
--- a/spec/ruby/library/net-http/httpheader/initialize_http_header_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#initialize_http_header when passed Hash" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.allocate
- end
-
- it "initializes the HTTP Header using the passed Hash" do
- @headers.initialize_http_header("My-Header" => "test", "My-Other-Header" => "another test")
- @headers["My-Header"].should == "test"
- @headers["My-Other-Header"].should == "another test"
- end
-
- it "complains about duplicate keys when in verbose mode" do
- -> do
- @headers.initialize_http_header("My-Header" => "test", "my-header" => "another test")
- end.should complain(/duplicated HTTP header/, verbose: true)
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/key_spec.rb b/spec/ruby/library/net-http/httpheader/key_spec.rb
deleted file mode 100644
index 2b7aeb9c2a..0000000000
--- a/spec/ruby/library/net-http/httpheader/key_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#key? when passed key" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns true if the header entry with the passed key exists" do
- @headers.key?("My-Header").should be_false
- @headers["My-Header"] = "test"
- @headers.key?("My-Header").should be_true
- end
-
- it "is case-insensitive" do
- @headers["My-Header"] = "test"
- @headers.key?("my-header").should be_true
- @headers.key?("MY-HEADER").should be_true
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/length_spec.rb b/spec/ruby/library/net-http/httpheader/length_spec.rb
deleted file mode 100644
index 57e32742e4..0000000000
--- a/spec/ruby/library/net-http/httpheader/length_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/size'
-
-describe "Net::HTTPHeader#length" do
- it_behaves_like :net_httpheader_size, :length
-end
diff --git a/spec/ruby/library/net-http/httpheader/main_type_spec.rb b/spec/ruby/library/net-http/httpheader/main_type_spec.rb
deleted file mode 100644
index 4dd551d8f4..0000000000
--- a/spec/ruby/library/net-http/httpheader/main_type_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#main_type" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns the 'main-content-type', as per 'Content-Type' header entry" do
- @headers["Content-Type"] = "text/html"
- @headers.main_type.should == "text"
-
- @headers["Content-Type"] = "application/pdf"
- @headers.main_type.should == "application"
-
- @headers["Content-Type"] = "text/html;charset=utf-8"
- @headers.main_type.should == "text"
- end
-
- it "returns nil if the 'Content-Type' header entry does not exist" do
- @headers.main_type.should be_nil
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/proxy_basic_auth_spec.rb b/spec/ruby/library/net-http/httpheader/proxy_basic_auth_spec.rb
deleted file mode 100644
index d9f6afc5a7..0000000000
--- a/spec/ruby/library/net-http/httpheader/proxy_basic_auth_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#proxy_basic_auth when passed account, password" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "sets the 'Proxy-Authorization' Header entry for basic authorization" do
- @headers.proxy_basic_auth("rubyspec", "rocks")
- @headers["Proxy-Authorization"].should == "Basic cnVieXNwZWM6cm9ja3M="
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/range_length_spec.rb b/spec/ruby/library/net-http/httpheader/range_length_spec.rb
deleted file mode 100644
index 77323ac872..0000000000
--- a/spec/ruby/library/net-http/httpheader/range_length_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#range_length" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns the length of the Range represented by the 'Content-Range' header entry" do
- @headers["Content-Range"] = "bytes 0-499/1234"
- @headers.range_length.should eql(500)
-
- @headers["Content-Range"] = "bytes 500-1233/1234"
- @headers.range_length.should eql(734)
- end
-
- it "returns nil when there is no 'Content-Range' header entry" do
- @headers.range_length.should be_nil
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Range' has an invalid format" do
- @headers["Content-Range"] = "invalid"
- -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
-
- @headers["Content-Range"] = "bytes 123-abc"
- -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
-
- @headers["Content-Range"] = "bytes abc-123"
- -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/range_spec.rb b/spec/ruby/library/net-http/httpheader/range_spec.rb
deleted file mode 100644
index 2de80a825e..0000000000
--- a/spec/ruby/library/net-http/httpheader/range_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/set_range'
-
-describe "Net::HTTPHeader#range" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns a Range object that represents the 'Range' header entry" do
- @headers["Range"] = "bytes=0-499"
- @headers.range.should == [0..499]
-
- @headers["Range"] = "bytes=500-1233"
- @headers.range.should == [500..1233]
-
- @headers["Range"] = "bytes=10-"
- @headers.range.should == [10..-1]
-
- @headers["Range"] = "bytes=-10"
- @headers.range.should == [-10..-1]
- end
-
- it "returns nil when there is no 'Range' header entry" do
- @headers.range.should be_nil
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when the 'Range' has an invalid format" do
- @headers["Range"] = "invalid"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
-
- @headers["Range"] = "bytes 123-abc"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
-
- @headers["Range"] = "bytes abc-123"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when the 'Range' was not specified" do
- @headers["Range"] = "bytes=-"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-end
-
-describe "Net::HTTPHeader#range=" do
- it_behaves_like :net_httpheader_set_range, :range=
-end
diff --git a/spec/ruby/library/net-http/httpheader/set_content_type_spec.rb b/spec/ruby/library/net-http/httpheader/set_content_type_spec.rb
deleted file mode 100644
index 7ec4f90b8e..0000000000
--- a/spec/ruby/library/net-http/httpheader/set_content_type_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/set_content_type'
-
-describe "Net::HTTPHeader#set_content_type" do
- it_behaves_like :net_httpheader_set_content_type, :set_content_type
-end
diff --git a/spec/ruby/library/net-http/httpheader/set_form_data_spec.rb b/spec/ruby/library/net-http/httpheader/set_form_data_spec.rb
deleted file mode 100644
index 7aac19f045..0000000000
--- a/spec/ruby/library/net-http/httpheader/set_form_data_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/set_form_data'
-
-describe "Net::HTTPHeader#set_form_data" do
- it_behaves_like :net_httpheader_set_form_data, :set_form_data
-end
diff --git a/spec/ruby/library/net-http/httpheader/set_range_spec.rb b/spec/ruby/library/net-http/httpheader/set_range_spec.rb
deleted file mode 100644
index 0f98de55e6..0000000000
--- a/spec/ruby/library/net-http/httpheader/set_range_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/set_range'
-
-describe "Net::HTTPHeader#set_range" do
- it_behaves_like :net_httpheader_set_range, :set_range
-end
diff --git a/spec/ruby/library/net-http/httpheader/size_spec.rb b/spec/ruby/library/net-http/httpheader/size_spec.rb
deleted file mode 100644
index 210060ce21..0000000000
--- a/spec/ruby/library/net-http/httpheader/size_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/size'
-
-describe "Net::HTTPHeader#size" do
- it_behaves_like :net_httpheader_size, :size
-end
diff --git a/spec/ruby/library/net-http/httpheader/sub_type_spec.rb b/spec/ruby/library/net-http/httpheader/sub_type_spec.rb
deleted file mode 100644
index b39b57fe8d..0000000000
--- a/spec/ruby/library/net-http/httpheader/sub_type_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#sub_type" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns the 'sub-content-type', as per 'Content-Type' header entry" do
- @headers["Content-Type"] = "text/html"
- @headers.sub_type.should == "html"
-
- @headers["Content-Type"] = "application/pdf"
- @headers.sub_type.should == "pdf"
-
- @headers["Content-Type"] = "text/html;charset=utf-8"
- @headers.sub_type.should == "html"
- end
-
- it "returns nil if no 'sub-content-type' is set" do
- @headers["Content-Type"] = "text"
- @headers.sub_type.should be_nil
-
- @headers["Content-Type"] = "text;charset=utf-8"
- @headers.sub_type.should be_nil
- end
-
- it "returns nil if the 'Content-Type' header entry does not exist" do
- @headers.sub_type.should be_nil
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/to_hash_spec.rb b/spec/ruby/library/net-http/httpheader/to_hash_spec.rb
deleted file mode 100644
index 3cebc519a6..0000000000
--- a/spec/ruby/library/net-http/httpheader/to_hash_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#to_hash" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns a Hash representing all Header entries (keys in lower case, values as arrays)" do
- @headers.to_hash.should == {}
-
- @headers["My-Header"] = "test"
- @headers.to_hash.should == { "my-header" => ["test"] }
-
- @headers.add_field("My-Header", "another test")
- @headers.to_hash.should == { "my-header" => ["test", "another test"] }
- end
-
- it "does not allow modifying the headers from the returned hash" do
- @headers.to_hash["my-header"] = ["test"]
- @headers.to_hash.should == {}
- @headers.key?("my-header").should be_false
- end
-end
diff --git a/spec/ruby/library/net-http/httpheader/type_params_spec.rb b/spec/ruby/library/net-http/httpheader/type_params_spec.rb
deleted file mode 100644
index ac97e2b48c..0000000000
--- a/spec/ruby/library/net-http/httpheader/type_params_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#type_params" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns additional 'Content-Type' information as a Hash" do
- @headers["Content-Type"] = "text/html;charset=utf-8"
- @headers.type_params.should == {"charset" => "utf-8"}
-
- @headers["Content-Type"] = "text/html; charset=utf-8; rubyspec=rocks"
- @headers.type_params.should == {"charset" => "utf-8", "rubyspec" => "rocks"}
- end
-
- it "returns an empty Hash when no additional 'Content-Type' information is set" do
- @headers.type_params.should == {}
-
- @headers["Content-Type"] = "text/html"
- @headers.type_params.should == {}
- end
-end
diff --git a/spec/ruby/library/net-http/httprequest/initialize_spec.rb b/spec/ruby/library/net-http/httprequest/initialize_spec.rb
deleted file mode 100644
index d009a00ed2..0000000000
--- a/spec/ruby/library/net-http/httprequest/initialize_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-module NetHTTPRequestSpecs
- class TestRequest < Net::HTTPRequest
- METHOD = "TEST"
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
- end
-end
-
-describe "Net::HTTPRequest#initialize" do
- before :each do
- @req = NetHTTPRequestSpecs::TestRequest.allocate
- end
-
- it "uses the METHOD constants to set the request method" do
- @req.send(:initialize, "/some/path")
- @req.method.should == "TEST"
- end
-
- it "uses the REQUEST_HAS_BODY to set whether the Request has a body or not" do
- @req.send(:initialize, "/some/path")
- @req.request_body_permitted?.should be_false
- end
-
- it "uses the RESPONSE_HAS_BODY to set whether the Response can have a body or not" do
- @req.send(:initialize, "/some/path")
- @req.response_body_permitted?.should be_true
- end
-
- describe "when passed path" do
- it "sets self's path to the passed path" do
- @req.send(:initialize, "/some/path")
- @req.path.should == "/some/path"
- end
- end
-
- describe "when passed path, headers" do
- it "uses the passed headers Hash to initialize self's header entries" do
- @req.send(:initialize, "/some/path", "Content-Type" => "text/html")
- @req["Content-Type"].should == "text/html"
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/body_permitted_spec.rb b/spec/ruby/library/net-http/httpresponse/body_permitted_spec.rb
deleted file mode 100644
index 68965de4a1..0000000000
--- a/spec/ruby/library/net-http/httpresponse/body_permitted_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse.body_permitted?" do
- it "returns true if this response type can have a response body" do
- Net::HTTPUnknownResponse.should.body_permitted?
- Net::HTTPInformation.should_not.body_permitted?
- Net::HTTPSuccess.should.body_permitted?
- Net::HTTPRedirection.should.body_permitted?
- Net::HTTPClientError.should.body_permitted?
- Net::HTTPServerError.should.body_permitted?
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/body_spec.rb b/spec/ruby/library/net-http/httpresponse/body_spec.rb
deleted file mode 100644
index ddfcd834c4..0000000000
--- a/spec/ruby/library/net-http/httpresponse/body_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'shared/body'
-
-describe "Net::HTTPResponse#body" do
- it_behaves_like :net_httpresponse_body, :body
-end
diff --git a/spec/ruby/library/net-http/httpresponse/code_spec.rb b/spec/ruby/library/net-http/httpresponse/code_spec.rb
deleted file mode 100644
index 699062ad97..0000000000
--- a/spec/ruby/library/net-http/httpresponse/code_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#code" do
- it "returns the result code string" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.code.should == "???"
-
- res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- res.code.should == "1xx"
-
- res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- res.code.should == "2xx"
-
- res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- res.code.should == "3xx"
-
- res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- res.code.should == "4xx"
-
- res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- res.code.should == "5xx"
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/code_type_spec.rb b/spec/ruby/library/net-http/httpresponse/code_type_spec.rb
deleted file mode 100644
index beb661cbbe..0000000000
--- a/spec/ruby/library/net-http/httpresponse/code_type_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#code_type" do
- it "returns self's class" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.code_type.should == Net::HTTPUnknownResponse
-
- res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- res.code_type.should == Net::HTTPInformation
-
- res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- res.code_type.should == Net::HTTPSuccess
-
- res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- res.code_type.should == Net::HTTPRedirection
-
- res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- res.code_type.should == Net::HTTPClientError
-
- res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- res.code_type.should == Net::HTTPServerError
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/entity_spec.rb b/spec/ruby/library/net-http/httpresponse/entity_spec.rb
deleted file mode 100644
index ca8c4b29c0..0000000000
--- a/spec/ruby/library/net-http/httpresponse/entity_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require_relative 'shared/body'
-
-describe "Net::HTTPResponse#entity" do
- it_behaves_like :net_httpresponse_body, :entity
-end
diff --git a/spec/ruby/library/net-http/httpresponse/error_spec.rb b/spec/ruby/library/net-http/httpresponse/error_spec.rb
deleted file mode 100644
index 6ced90fa23..0000000000
--- a/spec/ruby/library/net-http/httpresponse/error_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#error!" do
- it "raises self's class 'EXCEPTION_TYPE' Exception" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- -> { res.error! }.should raise_error(Net::HTTPError)
-
- res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPError)
-
- res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPError)
-
- res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPRetriableError)
-
- res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPClientException)
-
- res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPFatalError)
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/error_type_spec.rb b/spec/ruby/library/net-http/httpresponse/error_type_spec.rb
deleted file mode 100644
index 3969621a5e..0000000000
--- a/spec/ruby/library/net-http/httpresponse/error_type_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#error_type" do
- it "returns self's class 'EXCEPTION_TYPE' constant" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.error_type.should == Net::HTTPError
-
- res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- res.error_type.should == Net::HTTPError
-
- res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- res.error_type.should == Net::HTTPError
-
- res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- res.error_type.should == Net::HTTPRetriableError
-
- res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- res.error_type.should == Net::HTTPClientException
-
- res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- res.error_type.should == Net::HTTPFatalError
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/exception_type_spec.rb b/spec/ruby/library/net-http/httpresponse/exception_type_spec.rb
deleted file mode 100644
index dd2761a744..0000000000
--- a/spec/ruby/library/net-http/httpresponse/exception_type_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse.exception_type" do
- it "returns self's 'EXCEPTION_TYPE' constant" do
- Net::HTTPUnknownResponse.exception_type.should == Net::HTTPError
- Net::HTTPInformation.exception_type.should == Net::HTTPError
- Net::HTTPSuccess.exception_type.should == Net::HTTPError
- Net::HTTPRedirection.exception_type.should == Net::HTTPRetriableError
- Net::HTTPClientError.exception_type.should == Net::HTTPClientException
- Net::HTTPServerError.exception_type.should == Net::HTTPFatalError
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/header_spec.rb b/spec/ruby/library/net-http/httpresponse/header_spec.rb
deleted file mode 100644
index a403dbd2c3..0000000000
--- a/spec/ruby/library/net-http/httpresponse/header_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#header" do
- it "returns self" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.response.should equal(res)
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/http_version_spec.rb b/spec/ruby/library/net-http/httpresponse/http_version_spec.rb
deleted file mode 100644
index a3e413a360..0000000000
--- a/spec/ruby/library/net-http/httpresponse/http_version_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#http_version" do
- it "returns self's http version" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.http_version.should == "1.0"
-
- res = Net::HTTPUnknownResponse.new("1.1", "???", "test response")
- res.http_version.should == "1.1"
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/initialize_spec.rb b/spec/ruby/library/net-http/httpresponse/initialize_spec.rb
deleted file mode 100644
index 673c11a245..0000000000
--- a/spec/ruby/library/net-http/httpresponse/initialize_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#initialize when passed http_version, response_code, response_message" do
- it "sets self http_version, response_code and response_message to the passed values" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.http_version.should == "1.0"
- res.code.should == "???"
- res.message.should == "test response"
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/inspect_spec.rb b/spec/ruby/library/net-http/httpresponse/inspect_spec.rb
deleted file mode 100644
index 43071ec8cd..0000000000
--- a/spec/ruby/library/net-http/httpresponse/inspect_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require "stringio"
-
-describe "Net::HTTPResponse#inspect" do
- it "returns a String representation of self" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=false>"
-
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- socket = Net::BufferedIO.new(StringIO.new("test body"))
- res.reading_body(socket, true) {}
- res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=true>"
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/message_spec.rb b/spec/ruby/library/net-http/httpresponse/message_spec.rb
deleted file mode 100644
index 5ba73bb449..0000000000
--- a/spec/ruby/library/net-http/httpresponse/message_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#message" do
- it "returns self's response message" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.message.should == "test response"
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/msg_spec.rb b/spec/ruby/library/net-http/httpresponse/msg_spec.rb
deleted file mode 100644
index 04f5836d7a..0000000000
--- a/spec/ruby/library/net-http/httpresponse/msg_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#msg" do
- it "returns self's response message" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.message.should == "test response"
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/read_body_spec.rb b/spec/ruby/library/net-http/httpresponse/read_body_spec.rb
deleted file mode 100644
index 4530a26bfc..0000000000
--- a/spec/ruby/library/net-http/httpresponse/read_body_spec.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require 'stringio'
-
-describe "Net::HTTPResponse#read_body" do
- before :each do
- @res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- @socket = Net::BufferedIO.new(StringIO.new("test body"))
- end
-
- describe "when passed no arguments" do
- it "returns the read body" do
- @res.reading_body(@socket, true) do
- @res.read_body.should == "test body"
- end
- end
-
- it "returns the previously read body if called a second time" do
- @res.reading_body(@socket, true) do
- @res.read_body.should equal(@res.read_body)
- end
- end
- end
-
- describe "when passed a buffer" do
- it "reads the body to the passed buffer" do
- @res.reading_body(@socket, true) do
- buffer = +""
- @res.read_body(buffer)
- buffer.should == "test body"
- end
- end
-
- it "returns the passed buffer" do
- @res.reading_body(@socket, true) do
- buffer = +""
- @res.read_body(buffer).should equal(buffer)
- end
- end
-
- it "raises an IOError if called a second time" do
- @res.reading_body(@socket, true) do
- @res.read_body(+"")
- -> { @res.read_body(+"") }.should raise_error(IOError)
- end
- end
- end
-
- describe "when passed a block" do
- it "reads the body and yields it to the passed block (in chunks)" do
- @res.reading_body(@socket, true) do
- yielded = false
-
- buffer = +""
- @res.read_body do |body|
- yielded = true
- buffer << body
- end
-
- yielded.should be_true
- buffer.should == "test body"
- end
- end
-
- it "returns the ReadAdapter" do
- @res.reading_body(@socket, true) do
- @res.read_body { nil }.should be_kind_of(Net::ReadAdapter)
- end
- end
-
- it "raises an IOError if called a second time" do
- @res.reading_body(@socket, true) do
- @res.read_body {}
- -> { @res.read_body {} }.should raise_error(IOError)
- end
- end
- end
-
- describe "when passed buffer and block" do
- it "raises an ArgumentError" do
- @res.reading_body(@socket, true) do
- -> { @res.read_body(+"") {} }.should raise_error(ArgumentError)
- end
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/read_header_spec.rb b/spec/ruby/library/net-http/httpresponse/read_header_spec.rb
deleted file mode 100644
index 3ea4ee834b..0000000000
--- a/spec/ruby/library/net-http/httpresponse/read_header_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#read_header" do
- it "returns self" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.response.should equal(res)
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/read_new_spec.rb b/spec/ruby/library/net-http/httpresponse/read_new_spec.rb
deleted file mode 100644
index 82f7a47ce8..0000000000
--- a/spec/ruby/library/net-http/httpresponse/read_new_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require 'stringio'
-
-describe "Net::HTTPResponse.read_new" do
- it "creates a HTTPResponse object based on the response read from the passed socket" do
- socket = Net::BufferedIO.new(StringIO.new(<<EOS))
-HTTP/1.1 200 OK
-Content-Type: text/html; charset=utf-8
-
-test-body
-EOS
- response = Net::HTTPResponse.read_new(socket)
-
- response.should be_kind_of(Net::HTTPOK)
- response.code.should == "200"
- response["Content-Type"].should == "text/html; charset=utf-8"
-
- response.reading_body(socket, true) do
- response.body.should == "test-body\n"
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb b/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb
deleted file mode 100644
index 637a2806f8..0000000000
--- a/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-require "stringio"
-
-describe "Net::HTTPResponse#reading_body" do
- before :each do
- @res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- @socket = Net::BufferedIO.new(StringIO.new("test body"))
- end
-
- describe "when body_allowed is true" do
- it "reads and returns the response body for self from the passed socket" do
- @res.reading_body(@socket, true) {}.should == "test body"
- @res.body.should == "test body"
- end
-
- it "yields the passed block before reading the body" do
- yielded = false
-
- @res.reading_body(@socket, true) do
- @res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=false>"
- yielded = true
- end
-
- yielded.should be_true
- end
-
- describe "but the response type is not allowed to have a body" do
- before :each do
- @res = Net::HTTPInformation.new("1.0", "???", "test response")
- end
-
- it "returns nil" do
- @res.reading_body(@socket, false) {}.should be_nil
- @res.body.should be_nil
- end
-
- it "yields the passed block" do
- yielded = false
- @res.reading_body(@socket, true) { yielded = true }
- yielded.should be_true
- end
- end
- end
-
- describe "when body_allowed is false" do
- it "returns nil" do
- @res.reading_body(@socket, false) {}.should be_nil
- @res.body.should be_nil
- end
-
- it "yields the passed block" do
- yielded = false
- @res.reading_body(@socket, true) { yielded = true }
- yielded.should be_true
- end
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/response_spec.rb b/spec/ruby/library/net-http/httpresponse/response_spec.rb
deleted file mode 100644
index caa0ca2d19..0000000000
--- a/spec/ruby/library/net-http/httpresponse/response_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#response" do
- it "returns self" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.response.should equal(res)
- end
-end
diff --git a/spec/ruby/library/net-http/httpresponse/value_spec.rb b/spec/ruby/library/net-http/httpresponse/value_spec.rb
deleted file mode 100644
index 2df8beaa10..0000000000
--- a/spec/ruby/library/net-http/httpresponse/value_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#value" do
- it "raises an HTTP error for non 2xx HTTP Responses" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- -> { res.value }.should raise_error(Net::HTTPError)
-
- res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPError)
-
- res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- -> { res.value }.should_not raise_error(Net::HTTPError)
-
- res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPRetriableError)
-
- res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPClientException)
-
- res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPFatalError)
- end
-end
diff --git a/spec/ruby/library/net/FTPError_spec.rb b/spec/ruby/library/net/FTPError_spec.rb
new file mode 100644
index 0000000000..84128511db
--- /dev/null
+++ b/spec/ruby/library/net/FTPError_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require 'net/ftp'
+
+ describe "Net::FTPError" do
+ it "is an Exception" do
+ Net::FTPError.should < Exception
+ end
+ end
+end
diff --git a/spec/ruby/library/net/FTPPermError_spec.rb b/spec/ruby/library/net/FTPPermError_spec.rb
new file mode 100644
index 0000000000..0da35e7d82
--- /dev/null
+++ b/spec/ruby/library/net/FTPPermError_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require 'net/ftp'
+
+ describe "Net::FTPPermError" do
+ it "is an Exception" do
+ Net::FTPPermError.should < Exception
+ end
+
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
+ end
+end
diff --git a/spec/ruby/library/net/FTPProtoError_spec.rb b/spec/ruby/library/net/FTPProtoError_spec.rb
new file mode 100644
index 0000000000..20e30dd2dd
--- /dev/null
+++ b/spec/ruby/library/net/FTPProtoError_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require 'net/ftp'
+
+ describe "Net::FTPProtoError" do
+ it "is an Exception" do
+ Net::FTPProtoError.should < Exception
+ end
+
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
+ end
+end
diff --git a/spec/ruby/library/net/FTPReplyError_spec.rb b/spec/ruby/library/net/FTPReplyError_spec.rb
new file mode 100644
index 0000000000..cc774aabe5
--- /dev/null
+++ b/spec/ruby/library/net/FTPReplyError_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require 'net/ftp'
+
+ describe "Net::FTPReplyError" do
+ it "is an Exception" do
+ Net::FTPReplyError.should < Exception
+ end
+
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
+ end
+end
diff --git a/spec/ruby/library/net/FTPTempError_spec.rb b/spec/ruby/library/net/FTPTempError_spec.rb
new file mode 100644
index 0000000000..e2fbdfd842
--- /dev/null
+++ b/spec/ruby/library/net/FTPTempError_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require 'net/ftp'
+
+ describe "Net::FTPTempError" do
+ it "is an Exception" do
+ Net::FTPTempError.should < Exception
+ end
+
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/abort_spec.rb b/spec/ruby/library/net/ftp/abort_spec.rb
new file mode 100644
index 0000000000..ebdfed4b16
--- /dev/null
+++ b/spec/ruby/library/net/ftp/abort_spec.rb
@@ -0,0 +1,65 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#abort" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the ABOR command to the server" do
+ -> { @ftp.abort }.should_not raise_error
+ end
+
+ it "ignores the response" do
+ @ftp.abort
+ @ftp.last_response.should == "220 Dummy FTP Server ready!\n"
+ end
+
+ it "returns the full response" do
+ @ftp.abort.should == "226 Closing data connection. (ABOR)\n"
+ end
+
+ it "does not raise any error when the response code is 225" do
+ @server.should_receive(:abor).and_respond("225 Data connection open; no transfer in progress.")
+ -> { @ftp.abort }.should_not raise_error
+ end
+
+ it "does not raise any error when the response code is 226" do
+ @server.should_receive(:abor).and_respond("226 Closing data connection.")
+ -> { @ftp.abort }.should_not raise_error
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 500" do
+ @server.should_receive(:abor).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 501" do
+ @server.should_receive(:abor).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 502" do
+ @server.should_receive(:abor).and_respond("502 Command not implemented.")
+ -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 421" do
+ @server.should_receive(:abor).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/acct_spec.rb b/spec/ruby/library/net/ftp/acct_spec.rb
new file mode 100644
index 0000000000..a960ae20a4
--- /dev/null
+++ b/spec/ruby/library/net/ftp/acct_spec.rb
@@ -0,0 +1,61 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#acct" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "writes the ACCT command to the server" do
+ @ftp.acct("my_account")
+ @ftp.last_response.should == "230 User 'my_account' logged in, proceed. (ACCT)\n"
+ end
+
+ it "returns nil" do
+ @ftp.acct("my_account").should == nil
+ end
+
+ it "does not raise any error when the response code is 230" do
+ @server.should_receive(:acct).and_respond("230 User logged in, proceed.")
+ -> { @ftp.acct("my_account") }.should_not raise_error
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:acct).and_respond("530 Not logged in.")
+ -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:acct).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:acct).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 503" do
+ @server.should_receive(:acct).and_respond("503 Bad sequence of commands.")
+ -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:acct).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.acct("my_account") }.should raise_error(Net::FTPTempError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/binary_spec.rb b/spec/ruby/library/net/ftp/binary_spec.rb
new file mode 100644
index 0000000000..da7e2d6c14
--- /dev/null
+++ b/spec/ruby/library/net/ftp/binary_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+
+ describe "Net::FTP#binary" do
+ it "returns true when self is in binary mode" do
+ ftp = Net::FTP.new
+ ftp.binary.should be_true
+
+ ftp.binary = false
+ ftp.binary.should be_false
+ end
+ end
+
+ describe "Net::FTP#binary=" do
+ it "sets self to binary mode when passed true" do
+ ftp = Net::FTP.new
+
+ ftp.binary = true
+ ftp.binary.should be_true
+
+ ftp.binary = false
+ ftp.binary.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/chdir_spec.rb b/spec/ruby/library/net/ftp/chdir_spec.rb
new file mode 100644
index 0000000000..741c3c845e
--- /dev/null
+++ b/spec/ruby/library/net/ftp/chdir_spec.rb
@@ -0,0 +1,102 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#chdir" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ describe "when switching to the parent directory" do
+ it "sends the 'CDUP' command to the server" do
+ @ftp.chdir("..")
+ @ftp.last_response.should == "200 Command okay. (CDUP)\n"
+ end
+
+ it "returns nil" do
+ @ftp.chdir("..").should be_nil
+ end
+
+ it "does not raise a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:cdup).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.chdir("..") }.should_not raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:cdup).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:cdup).and_respond("502 Command not implemented.")
+ -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:cdup).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.chdir("..") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:cdup).and_respond("530 Not logged in.")
+ -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:cdup).and_respond("550 Requested action not taken.")
+ -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ it "writes the 'CWD' command with the passed directory to the socket" do
+ @ftp.chdir("test")
+ @ftp.last_response.should == "200 Command okay. (CWD test)\n"
+ end
+
+ it "returns nil" do
+ @ftp.chdir("test").should be_nil
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:cwd).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:cwd).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:cwd).and_respond("502 Command not implemented.")
+ -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:cwd).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.chdir("test") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:cwd).and_respond("530 Not logged in.")
+ -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:cwd).and_respond("550 Requested action not taken.")
+ -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/close_spec.rb b/spec/ruby/library/net/ftp/close_spec.rb
new file mode 100644
index 0000000000..49cdf4dea7
--- /dev/null
+++ b/spec/ruby/library/net/ftp/close_spec.rb
@@ -0,0 +1,33 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+
+ describe "Net::FTP#close" do
+ before :each do
+ @socket = mock("Socket")
+ @socket.stub!(:closed?).and_return(false)
+ @socket.stub!(:read_timeout).and_return(60)
+ @socket.stub!(:read_timeout=).and_return(3)
+
+ @ftp = Net::FTP.new
+ @ftp.instance_variable_set(:@sock, @socket)
+ end
+
+ it "closes the socket" do
+ @socket.should_receive(:close)
+ @ftp.close.should be_nil
+ end
+
+ it "does not try to close the socket if it has already been closed" do
+ @socket.should_receive(:closed?).and_return(true)
+ @socket.should_not_receive(:close)
+ @ftp.close.should be_nil
+ end
+
+ it "does not try to close the socket if it is nil" do
+ @ftp.instance_variable_set(:@sock, nil)
+ @ftp.close.should be_nil
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/closed_spec.rb b/spec/ruby/library/net/ftp/closed_spec.rb
new file mode 100644
index 0000000000..a81917090a
--- /dev/null
+++ b/spec/ruby/library/net/ftp/closed_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+
+ describe "Net::FTP#closed?" do
+ before :each do
+ @socket = mock("Socket")
+
+ @ftp = Net::FTP.new
+ @ftp.instance_variable_set(:@sock, @socket)
+ end
+
+ it "returns true when the socket is closed" do
+ @socket.should_receive(:closed?).and_return(true)
+ @ftp.closed?.should be_true
+ end
+
+ it "returns true when the socket is nil" do
+ @ftp.instance_variable_set(:@sock, nil)
+ @ftp.closed?.should be_true
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/connect_spec.rb b/spec/ruby/library/net/ftp/connect_spec.rb
new file mode 100644
index 0000000000..b45e46c530
--- /dev/null
+++ b/spec/ruby/library/net/ftp/connect_spec.rb
@@ -0,0 +1,52 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ # TODO: Add specs for using the SOCKSSocket
+ describe "Net::FTP#connect" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ end
+
+ after :each do
+ @server.connect_message = nil
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "tries to connect to the FTP Server on the given host and port" do
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should_not raise_error
+ end
+
+ it "returns nil" do
+ @ftp.connect(@server.hostname, @server.server_port).should be_nil
+ end
+
+ it "prints a small debug line when in debug mode" do
+ @ftp.debug_mode = true
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should output(/#{"connect: "}#{@server.hostname}#{", "}#{@server.server_port}#{"\\nget: 220 Dummy FTP Server ready!"}/)
+ @ftp.debug_mode = false
+ end
+
+ it "does not raise any error when the response code is 220" do
+ @server.connect_message = "220 Dummy FTP Server ready!"
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should_not raise_error
+ end
+
+ it "raises a Net::FTPReplyError when the response code is 120" do
+ @server.connect_message = "120 Service ready in nnn minutes."
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should raise_error(Net::FTPReplyError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.connect_message = "421 Service not available, closing control connection."
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should raise_error(Net::FTPTempError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/debug_mode_spec.rb b/spec/ruby/library/net/ftp/debug_mode_spec.rb
new file mode 100644
index 0000000000..46d207bbea
--- /dev/null
+++ b/spec/ruby/library/net/ftp/debug_mode_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+
+ describe "Net::FTP#debug_mode" do
+ it "returns true when self is in debug mode" do
+ ftp = Net::FTP.new
+ ftp.debug_mode.should be_false
+
+ ftp.debug_mode = true
+ ftp.debug_mode.should be_true
+ end
+ end
+
+ describe "Net::FTP#debug_mode=" do
+ it "sets self into debug mode when passed true" do
+ ftp = Net::FTP.new
+ ftp.debug_mode = true
+ ftp.debug_mode.should be_true
+
+ ftp.debug_mode = false
+ ftp.debug_mode.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/default_passive_spec.rb b/spec/ruby/library/net/ftp/default_passive_spec.rb
new file mode 100644
index 0000000000..9348d3294d
--- /dev/null
+++ b/spec/ruby/library/net/ftp/default_passive_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+
+ describe "Net::FTP#default_passive" do
+ it "is true by default" do
+ ruby_exe(fixture(__FILE__, "default_passive.rb")).should == "true\ntrue\n"
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/delete_spec.rb b/spec/ruby/library/net/ftp/delete_spec.rb
new file mode 100644
index 0000000000..43bfcc1541
--- /dev/null
+++ b/spec/ruby/library/net/ftp/delete_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#delete" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the DELE command with the passed filename to the server" do
+ @ftp.delete("test.file")
+ @ftp.last_response.should == "250 Requested file action okay, completed. (DELE test.file)\n"
+ end
+
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:dele).and_respond("450 Requested file action not taken.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:dele).and_respond("550 Requested action not taken.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:dele).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:dele).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:dele).and_respond("502 Command not implemented.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:dele).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:dele).and_respond("530 Not logged in.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/dir_spec.rb b/spec/ruby/library/net/ftp/dir_spec.rb
new file mode 100644
index 0000000000..dce50a5ac5
--- /dev/null
+++ b/spec/ruby/library/net/ftp/dir_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/list'
+
+ describe "Net::FTP#dir" do
+ it_behaves_like :net_ftp_list, :dir
+ end
+end
diff --git a/spec/ruby/library/net-ftp/fixtures/default_passive.rb b/spec/ruby/library/net/ftp/fixtures/default_passive.rb
index b6995d6f34..b6995d6f34 100644
--- a/spec/ruby/library/net-ftp/fixtures/default_passive.rb
+++ b/spec/ruby/library/net/ftp/fixtures/default_passive.rb
diff --git a/spec/ruby/library/net-ftp/fixtures/passive.rb b/spec/ruby/library/net/ftp/fixtures/passive.rb
index 6b5cde82df..6b5cde82df 100644
--- a/spec/ruby/library/net-ftp/fixtures/passive.rb
+++ b/spec/ruby/library/net/ftp/fixtures/passive.rb
diff --git a/spec/ruby/library/net-ftp/fixtures/putbinaryfile b/spec/ruby/library/net/ftp/fixtures/putbinaryfile
index f3130c6e43..f3130c6e43 100644
--- a/spec/ruby/library/net-ftp/fixtures/putbinaryfile
+++ b/spec/ruby/library/net/ftp/fixtures/putbinaryfile
diff --git a/spec/ruby/library/net-ftp/fixtures/puttextfile b/spec/ruby/library/net/ftp/fixtures/puttextfile
index b4f3b2b62d..b4f3b2b62d 100644
--- a/spec/ruby/library/net-ftp/fixtures/puttextfile
+++ b/spec/ruby/library/net/ftp/fixtures/puttextfile
diff --git a/spec/ruby/library/net-ftp/fixtures/server.rb b/spec/ruby/library/net/ftp/fixtures/server.rb
index ecbed591d5..ecbed591d5 100644
--- a/spec/ruby/library/net-ftp/fixtures/server.rb
+++ b/spec/ruby/library/net/ftp/fixtures/server.rb
diff --git a/spec/ruby/library/net/ftp/get_spec.rb b/spec/ruby/library/net/ftp/get_spec.rb
new file mode 100644
index 0000000000..892b30061c
--- /dev/null
+++ b/spec/ruby/library/net/ftp/get_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/gettextfile'
+ require_relative 'shared/getbinaryfile'
+
+ describe "Net::FTP#get (binary mode)" do
+ before :each do
+ @binary_mode = true
+ end
+
+ it_behaves_like :net_ftp_getbinaryfile, :get
+ end
+
+ describe "Net::FTP#get (text mode)" do
+ before :each do
+ @binary_mode = false
+ end
+
+ it_behaves_like :net_ftp_gettextfile, :get
+ end
+end
diff --git a/spec/ruby/library/net/ftp/getbinaryfile_spec.rb b/spec/ruby/library/net/ftp/getbinaryfile_spec.rb
new file mode 100644
index 0000000000..c5abdd67e7
--- /dev/null
+++ b/spec/ruby/library/net/ftp/getbinaryfile_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/getbinaryfile'
+
+ describe "Net::FTP#getbinaryfile" do
+ it_behaves_like :net_ftp_getbinaryfile, :getbinaryfile
+ end
+end
diff --git a/spec/ruby/library/net/ftp/getdir_spec.rb b/spec/ruby/library/net/ftp/getdir_spec.rb
new file mode 100644
index 0000000000..8f6fca5bfb
--- /dev/null
+++ b/spec/ruby/library/net/ftp/getdir_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'shared/pwd'
+
+ describe "Net::FTP#getdir" do
+ it_behaves_like :net_ftp_pwd, :getdir
+ end
+end
diff --git a/spec/ruby/library/net/ftp/gettextfile_spec.rb b/spec/ruby/library/net/ftp/gettextfile_spec.rb
new file mode 100644
index 0000000000..e272ae73b1
--- /dev/null
+++ b/spec/ruby/library/net/ftp/gettextfile_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/gettextfile'
+
+ describe "Net::FTP#gettextfile" do
+ it_behaves_like :net_ftp_gettextfile, :gettextfile
+ end
+end
diff --git a/spec/ruby/library/net/ftp/help_spec.rb b/spec/ruby/library/net/ftp/help_spec.rb
new file mode 100644
index 0000000000..9b15f42ede
--- /dev/null
+++ b/spec/ruby/library/net/ftp/help_spec.rb
@@ -0,0 +1,69 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#help" do
+ def with_connection
+ yield
+ end
+
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "writes the HELP command to the server" do
+ @ftp.help
+ @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
+ end
+
+ it "returns the server's response" do
+ @ftp.help.should == "211 System status, or system help reply. (HELP)\n"
+ end
+
+ it "writes the HELP command with an optional parameter to the socket" do
+ @ftp.help("some parameter").should == "211 System status, or system help reply. (HELP some parameter)\n"
+ end
+
+ it "does not raise any error when the response code is 211" do
+ @server.should_receive(:help).and_respond("211 System status, or system help reply.")
+ -> { @ftp.help }.should_not raise_error
+ end
+
+ it "does not raise any error when the response code is 214" do
+ @server.should_receive(:help).and_respond("214 Help message.")
+ -> { @ftp.help }.should_not raise_error
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.help }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:help).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.help }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:help).and_respond("502 Command not implemented.")
+ -> { @ftp.help }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:help).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.help }.should raise_error(Net::FTPTempError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/initialize_spec.rb b/spec/ruby/library/net/ftp/initialize_spec.rb
new file mode 100644
index 0000000000..80f71a9161
--- /dev/null
+++ b/spec/ruby/library/net/ftp/initialize_spec.rb
@@ -0,0 +1,408 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+
+ describe "Net::FTP#initialize" do
+ before :each do
+ @ftp = Net::FTP.allocate
+ @ftp.stub!(:connect)
+ @port_args = []
+ @port_args << 21
+ end
+
+ it "is private" do
+ Net::FTP.should have_private_instance_method(:initialize)
+ end
+
+ it "sets self into binary mode" do
+ @ftp.binary.should be_nil
+ @ftp.send(:initialize)
+ @ftp.binary.should be_true
+ end
+
+ it "sets self into active mode" do
+ @ftp.passive.should be_nil
+ @ftp.send(:initialize)
+ @ftp.passive.should be_false
+ end
+
+ it "sets self into non-debug mode" do
+ @ftp.debug_mode.should be_nil
+ @ftp.send(:initialize)
+ @ftp.debug_mode.should be_false
+ end
+
+ it "sets self to not resume file uploads/downloads" do
+ @ftp.resume.should be_nil
+ @ftp.send(:initialize)
+ @ftp.resume.should be_false
+ end
+
+ describe "when passed no arguments" do
+ it "does not try to connect" do
+ @ftp.should_not_receive(:connect)
+ @ftp.send(:initialize)
+ end
+ end
+
+ describe "when passed host" do
+ it "tries to connect to the passed host" do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+ @ftp.send(:initialize, "localhost")
+ end
+ end
+
+ describe "when passed host, user" do
+ it "tries to connect to the passed host" do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+ @ftp.send(:initialize, "localhost")
+ end
+
+ it "tries to login with the passed username" do
+ @ftp.should_receive(:login).with("rubyspec", nil, nil)
+ @ftp.send(:initialize, "localhost", "rubyspec")
+ end
+ end
+
+ describe "when passed host, user, password" do
+ it "tries to connect to the passed host" do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+ @ftp.send(:initialize, "localhost")
+ end
+
+ it "tries to login with the passed username and password" do
+ @ftp.should_receive(:login).with("rubyspec", "rocks", nil)
+ @ftp.send(:initialize, "localhost", "rubyspec", "rocks")
+ end
+ end
+
+ describe "when passed host, user" do
+ it "tries to connect to the passed host" do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+ @ftp.send(:initialize, "localhost")
+ end
+
+ it "tries to login with the passed username, password and account" do
+ @ftp.should_receive(:login).with("rubyspec", "rocks", "account")
+ @ftp.send(:initialize, "localhost", "rubyspec", "rocks", "account")
+ end
+ end
+
+ before :each do
+ @ftp.stub!(:login)
+ end
+
+ describe 'when the host' do
+ describe 'is set' do
+ describe 'and port option' do
+ describe 'is set' do
+ it 'tries to connect to the host on the specified port' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ port: 8080 })
+ @ftp.should_receive(:connect).with('localhost', 8080)
+
+ @ftp.send(:initialize, 'localhost', options)
+ end
+ end
+
+ describe 'is not set' do
+ it 'tries to connect to the host without a port' do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+
+ @ftp.send(:initialize, 'localhost')
+ end
+ end
+ end
+
+ describe 'when the username option' do
+ describe 'is set' do
+ describe 'and the password option' do
+ describe 'is set' do
+ describe 'and the account option' do
+ describe 'is set' do
+ it 'tries to log in with the supplied parameters' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ username: 'a', password: 'topsecret', account: 'b' })
+ @ftp.should_receive(:login).with('a', 'topsecret', 'b')
+
+ @ftp.send(:initialize, 'localhost', options)
+ end
+ end
+
+ describe 'is unset' do
+ it 'tries to log in with the supplied parameters' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ username: 'a', password: 'topsecret' })
+ @ftp.should_receive(:login).with('a', 'topsecret', nil)
+
+ @ftp.send(:initialize, 'localhost', options)
+ end
+ end
+ end
+ end
+
+ describe 'is unset' do
+ describe 'and the account option' do
+ describe 'is set' do
+ it 'tries to log in with the supplied parameters' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ username: 'a', account: 'b' })
+ @ftp.should_receive(:login).with('a', nil, 'b')
+
+ @ftp.send(:initialize, 'localhost', options)
+ end
+ end
+
+ describe 'is unset' do
+ it 'tries to log in with the supplied parameters' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ username: 'a'})
+ @ftp.should_receive(:login).with('a', nil, nil)
+
+ @ftp.send(:initialize, 'localhost', options)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ describe 'is not set' do
+ it 'does not try to log in' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({})
+ @ftp.should_not_receive(:login)
+
+ @ftp.send(:initialize, 'localhost', options)
+ end
+ end
+ end
+ end
+
+ describe 'is unset' do
+ it 'does not try to connect' do
+ @ftp.should_not_receive(:connect)
+
+ @ftp.send(:initialize)
+ end
+
+ it 'does not try to log in' do
+ @ftp.should_not_receive(:login)
+
+ @ftp.send(:initialize)
+ end
+ end
+ end
+
+ describe 'when the passive option' do
+ describe 'is set' do
+ describe 'to true' do
+ it 'sets passive to true' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ passive: true })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.passive.should == true
+ end
+ end
+
+ describe 'to false' do
+ it 'sets passive to false' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ passive: false })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.passive.should == false
+ end
+ end
+ end
+
+ describe 'is unset' do
+ it 'sets passive to false' do
+ @ftp.send(:initialize)
+ @ftp.passive.should == false
+ end
+ end
+ end
+
+ describe 'when the debug_mode option' do
+ describe 'is set' do
+ describe 'to true' do
+ it 'sets debug_mode to true' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ debug_mode: true })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.debug_mode.should == true
+ end
+ end
+
+ describe 'to false' do
+ it 'sets debug_mode to false' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ debug_mode: false })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.debug_mode.should == false
+ end
+ end
+ end
+
+ describe 'is unset' do
+ it 'sets debug_mode to false' do
+ @ftp.send(:initialize)
+ @ftp.debug_mode.should == false
+ end
+ end
+ end
+
+ describe 'when the open_timeout option' do
+ describe 'is set' do
+ it 'sets open_timeout to the specified value' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ open_timeout: 42 })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.open_timeout.should == 42
+ end
+ end
+
+ describe 'is not set' do
+ it 'sets open_timeout to nil' do
+ @ftp.send(:initialize)
+ @ftp.open_timeout.should == nil
+ end
+ end
+ end
+
+ describe 'when the read_timeout option' do
+ describe 'is set' do
+ it 'sets read_timeout to the specified value' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ read_timeout: 100 })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.read_timeout.should == 100
+ end
+ end
+
+ describe 'is not set' do
+ it 'sets read_timeout to the default value' do
+ @ftp.send(:initialize)
+ @ftp.read_timeout.should == 60
+ end
+ end
+ end
+
+ describe 'when the ssl_handshake_timeout option' do
+ describe 'is set' do
+ it 'sets ssl_handshake_timeout to the specified value' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl_handshake_timeout: 23 })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.ssl_handshake_timeout.should == 23
+ end
+ end
+
+ describe 'is not set' do
+ it 'sets ssl_handshake_timeout to nil' do
+ @ftp.send(:initialize)
+ @ftp.ssl_handshake_timeout.should == nil
+ end
+ end
+ end
+
+ describe 'when the ssl option' do
+ describe 'is set' do
+ describe "and the ssl option's value is true" do
+ it 'initializes ssl_context to a blank SSLContext object' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl: true })
+
+ ssl_context = OpenSSL::SSL::SSLContext.allocate
+ ssl_context.stub!(:set_params)
+
+ OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ssl_context)
+ ssl_context.should_receive(:set_params).with({})
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@ssl_context).should == ssl_context
+ end
+ end
+
+ describe "and the ssl option's value is a hash" do
+ it 'initializes ssl_context to a configured SSLContext object' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl: {key: 'value'} })
+
+ ssl_context = OpenSSL::SSL::SSLContext.allocate
+ ssl_context.stub!(:set_params)
+
+ OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ssl_context)
+ ssl_context.should_receive(:set_params).with({key: 'value'})
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@ssl_context).should == ssl_context
+ end
+ end
+
+ describe 'and private_data_connection' do
+ describe 'is set' do
+ it 'sets private_data_connection to that value' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl: true, private_data_connection: 'true' })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@private_data_connection).should == 'true'
+ end
+ end
+
+ describe 'is not set' do
+ it 'sets private_data_connection to nil' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl: true })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@private_data_connection).should == true
+ end
+ end
+ end
+ end
+
+ describe 'is not set' do
+ it 'sets ssl_context to nil' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({})
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@ssl_context).should == nil
+ end
+
+ describe 'private_data_connection' do
+ describe 'is set' do
+ it 'raises an ArgumentError' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ private_data_connection: true })
+
+ -> {
+ @ftp.send(:initialize, nil, options)
+ }.should raise_error(ArgumentError, /private_data_connection can be set to true only when ssl is enabled/)
+ end
+ end
+
+ describe 'is not set' do
+ it 'sets private_data_connection to false' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({})
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@private_data_connection).should == false
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/last_response_code_spec.rb b/spec/ruby/library/net/ftp/last_response_code_spec.rb
new file mode 100644
index 0000000000..86f2b9a695
--- /dev/null
+++ b/spec/ruby/library/net/ftp/last_response_code_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'shared/last_response_code'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#last_response_code" do
+ it_behaves_like :net_ftp_last_response_code, :last_response_code
+ end
+end
diff --git a/spec/ruby/library/net/ftp/last_response_spec.rb b/spec/ruby/library/net/ftp/last_response_spec.rb
new file mode 100644
index 0000000000..1d29b9b73f
--- /dev/null
+++ b/spec/ruby/library/net/ftp/last_response_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#last_response" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "returns the last response" do
+ @ftp.last_response.should == "220 Dummy FTP Server ready!\n"
+ @ftp.help
+ @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/lastresp_spec.rb b/spec/ruby/library/net/ftp/lastresp_spec.rb
new file mode 100644
index 0000000000..9d26efb8f8
--- /dev/null
+++ b/spec/ruby/library/net/ftp/lastresp_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'shared/last_response_code'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#lastresp" do
+ it_behaves_like :net_ftp_last_response_code, :lastresp
+ end
+end
diff --git a/spec/ruby/library/net/ftp/list_spec.rb b/spec/ruby/library/net/ftp/list_spec.rb
new file mode 100644
index 0000000000..6cffafeb4f
--- /dev/null
+++ b/spec/ruby/library/net/ftp/list_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/list'
+
+ describe "Net::FTP#list" do
+ it_behaves_like :net_ftp_list, :list
+ end
+end
diff --git a/spec/ruby/library/net/ftp/login_spec.rb b/spec/ruby/library/net/ftp/login_spec.rb
new file mode 100644
index 0000000000..981b439082
--- /dev/null
+++ b/spec/ruby/library/net/ftp/login_spec.rb
@@ -0,0 +1,198 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#login" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ describe "when passed no arguments" do
+ it "sends the USER command with 'anonymous' as name to the server" do
+ @ftp.login
+ @server.login_user.should == "anonymous"
+ end
+
+ it "sends 'anonymous@' as a password when required" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @ftp.login
+ @server.login_pass.should == "anonymous@"
+ end
+
+ it "raises a Net::FTPReplyError when the server requests an account" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ -> { @ftp.login }.should raise_error(Net::FTPReplyError)
+ end
+ end
+
+ describe "when passed name" do
+ it "sends the USER command with the passed name to the server" do
+ @ftp.login("rubyspec")
+ @server.login_user.should == "rubyspec"
+ end
+
+ it "raises a Net::FTPReplyError when the server requests a password, but none was given" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ -> { @ftp.login("rubyspec") }.should raise_error(Net::FTPReplyError)
+ end
+
+ it "raises a Net::FTPReplyError when the server requests an account, but none was given" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ -> { @ftp.login("rubyspec") }.should raise_error(Net::FTPReplyError)
+ end
+ end
+
+ describe "when passed name, password" do
+ it "sends the USER command with the passed name to the server" do
+ @ftp.login("rubyspec", "rocks")
+ @server.login_user.should == "rubyspec"
+ end
+
+ it "sends the passed password when required" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @ftp.login("rubyspec", "rocks")
+ @server.login_pass.should == "rocks"
+ end
+
+ it "raises a Net::FTPReplyError when the server requests an account" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ -> { @ftp.login("rubyspec", "rocks") }.should raise_error(Net::FTPReplyError)
+ end
+ end
+
+ describe "when passed name, password, account" do
+ it "sends the USER command with the passed name to the server" do
+ @ftp.login("rubyspec", "rocks", "account")
+ @server.login_user.should == "rubyspec"
+ end
+
+ it "sends the passed password when required" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @ftp.login("rubyspec", "rocks", "account")
+ @server.login_pass.should == "rocks"
+ end
+
+ it "sends the passed account when required" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ @ftp.login("rubyspec", "rocks", "account")
+ @server.login_acct.should == "account"
+ end
+ end
+
+ describe "when the USER command fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:user).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:user).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:user).and_respond("502 Command not implemented.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:user).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:user).and_respond("530 Not logged in.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when the PASS command fails" do
+ before :each do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ end
+
+ it "does not raise an Error when the response code is 202" do
+ @server.should_receive(:pass).and_respond("202 Command not implemented, superfluous at this site.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should_not raise_error
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:pass).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:pass).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:pass).and_respond("502 Command not implemented.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:pass).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:pass).and_respond("530 Not logged in.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when the ACCT command fails" do
+ before :each do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ end
+
+ it "does not raise an Error when the response code is 202" do
+ @server.should_receive(:acct).and_respond("202 Command not implemented, superfluous at this site.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should_not raise_error
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:acct).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:acct).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:acct).and_respond("502 Command not implemented.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:acct).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:acct).and_respond("530 Not logged in.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/ls_spec.rb b/spec/ruby/library/net/ftp/ls_spec.rb
new file mode 100644
index 0000000000..f262515865
--- /dev/null
+++ b/spec/ruby/library/net/ftp/ls_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/list'
+
+ describe "Net::FTP#ls" do
+ it_behaves_like :net_ftp_list, :ls
+ end
+end
diff --git a/spec/ruby/library/net/ftp/mdtm_spec.rb b/spec/ruby/library/net/ftp/mdtm_spec.rb
new file mode 100644
index 0000000000..ea55533c43
--- /dev/null
+++ b/spec/ruby/library/net/ftp/mdtm_spec.rb
@@ -0,0 +1,41 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#mdtm" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the MDTM with the passed filename command to the server" do
+ @ftp.mdtm("test.file")
+ @ftp.last_response.should == "213 19980705132316\n"
+ end
+
+ it "returns the last modification time of the passed file" do
+ @ftp.mdtm("test.file").should == "19980705132316"
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:mdtm).and_respond("550 Requested action not taken.")
+ -> { @ftp.mdtm("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:mdtm).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.mdtm("test.file") }.should raise_error(Net::FTPTempError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/mkdir_spec.rb b/spec/ruby/library/net/ftp/mkdir_spec.rb
new file mode 100644
index 0000000000..2cb437a076
--- /dev/null
+++ b/spec/ruby/library/net/ftp/mkdir_spec.rb
@@ -0,0 +1,64 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#mkdir" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the MKD command with the passed pathname to the server" do
+ @ftp.mkdir("test.folder")
+ @ftp.last_response.should == %{257 "test.folder" created.\n}
+ end
+
+ it "returns the path to the newly created directory" do
+ @ftp.mkdir("test.folder").should == "test.folder"
+ @ftp.mkdir("/absolute/path/to/test.folder").should == "/absolute/path/to/test.folder"
+ @ftp.mkdir("relative/path/to/test.folder").should == "relative/path/to/test.folder"
+ @ftp.mkdir('/usr/dm/foo"bar').should == '/usr/dm/foo"bar'
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:mkd).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:mkd).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:mkd).and_respond("502 Command not implemented.")
+ -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:mkd).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:mkd).and_respond("530 Not logged in.")
+ -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:mkd).and_respond("550 Requested action not taken.")
+ -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/mtime_spec.rb b/spec/ruby/library/net/ftp/mtime_spec.rb
new file mode 100644
index 0000000000..7265667a52
--- /dev/null
+++ b/spec/ruby/library/net/ftp/mtime_spec.rb
@@ -0,0 +1,53 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#mtime" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the MDTM with the passed filename command to the server" do
+ @ftp.mtime("test.file")
+ @ftp.last_response.should == "213 19980705132316\n"
+ end
+
+ describe "when passed filename" do
+ it "returns the last modification time of the passed file as a Time object in the local time" do
+ @ftp.mtime("test.file").should == Time.gm("1998", "07", "05", "13", "23", "16")
+ end
+ end
+
+ describe "when passed filename, local_time" do
+ it "returns the last modification time as a Time object in UTC when local_time is true" do
+ @ftp.mtime("test.file", true).should == Time.local("1998", "07", "05", "13", "23", "16")
+ end
+
+ it "returns the last modification time as a Time object in the local time when local_time is false" do
+ @ftp.mtime("test.file", false).should == Time.gm("1998", "07", "05", "13", "23", "16")
+ end
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:mdtm).and_respond("550 Requested action not taken.")
+ -> { @ftp.mtime("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:mdtm).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.mtime("test.file") }.should raise_error(Net::FTPTempError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/nlst_spec.rb b/spec/ruby/library/net/ftp/nlst_spec.rb
new file mode 100644
index 0000000000..0de84b3a76
--- /dev/null
+++ b/spec/ruby/library/net/ftp/nlst_spec.rb
@@ -0,0 +1,95 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#nlst" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.passive = false
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ describe "when passed no arguments" do
+ it "returns an Array containing a list of files in the current dir" do
+ @ftp.nlst.should == ["last_response_code.rb", "list.rb", "pwd.rb"]
+ @ftp.last_response.should == "226 transfer complete (NLST)\n"
+ end
+ end
+
+ describe "when passed dir" do
+ it "returns an Array containing a list of files in the passed dir" do
+ @ftp.nlst("test.folder").should == ["last_response_code.rb", "list.rb", "pwd.rb"]
+ @ftp.last_response.should == "226 transfer complete (NLST test.folder)\n"
+ end
+ end
+
+ describe "when the NLST command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:nlst).and_respond("450 Requested file action not taken..")
+ -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:nlst).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:nlst).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:nlst).and_respond("502 Command not implemented.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:nlst).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:nlst).and_respond("530 Not logged in.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/noop_spec.rb b/spec/ruby/library/net/ftp/noop_spec.rb
new file mode 100644
index 0000000000..71011d4af7
--- /dev/null
+++ b/spec/ruby/library/net/ftp/noop_spec.rb
@@ -0,0 +1,41 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#noop" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the NOOP command to the server" do
+ @ftp.noop
+ @ftp.last_response.should == "200 Command okay. (NOOP)\n"
+ end
+
+ it "returns nil" do
+ @ftp.noop.should be_nil
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:noop).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.noop }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:noop).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.noop }.should raise_error(Net::FTPTempError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/open_spec.rb b/spec/ruby/library/net/ftp/open_spec.rb
new file mode 100644
index 0000000000..89187b9802
--- /dev/null
+++ b/spec/ruby/library/net/ftp/open_spec.rb
@@ -0,0 +1,58 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+
+ describe "Net::FTP.open" do
+ before :each do
+ @ftp = mock("Net::FTP instance")
+ Net::FTP.stub!(:new).and_return(@ftp)
+ end
+
+ describe "when passed no block" do
+ it "returns a new Net::FTP instance" do
+ Net::FTP.open("localhost").should equal(@ftp)
+ end
+
+ it "passes the passed arguments down to Net::FTP.new" do
+ Net::FTP.should_receive(:new).with("localhost", "user", "password", "account")
+ Net::FTP.open("localhost", "user", "password", "account")
+ end
+ end
+
+ describe "when passed a block" do
+ before :each do
+ @ftp.stub!(:close)
+ end
+
+ it "yields a new Net::FTP instance to the passed block" do
+ yielded = false
+ Net::FTP.open("localhost") do |ftp|
+ yielded = true
+ ftp.should equal(@ftp)
+ end
+ yielded.should be_true
+ end
+
+ it "closes the Net::FTP instance after yielding" do
+ Net::FTP.open("localhost") do |ftp|
+ ftp.should_receive(:close)
+ end
+ end
+
+ it "closes the Net::FTP instance even if an exception is raised while yielding" do
+ begin
+ Net::FTP.open("localhost") do |ftp|
+ ftp.should_receive(:close)
+ raise ArgumentError, "some exception"
+ end
+ rescue ArgumentError
+ end
+ end
+
+ it "returns the block's return value" do
+ Net::FTP.open("localhost") { :test }.should == :test
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/passive_spec.rb b/spec/ruby/library/net/ftp/passive_spec.rb
new file mode 100644
index 0000000000..f9c34efb7d
--- /dev/null
+++ b/spec/ruby/library/net/ftp/passive_spec.rb
@@ -0,0 +1,31 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+
+ describe "Net::FTP#passive" do
+ it "returns true when self is in passive mode" do
+ ftp = Net::FTP.new
+ ftp.passive.should be_false
+
+ ftp.passive = true
+ ftp.passive.should be_true
+ end
+
+ it "is the value of Net::FTP.default_value by default" do
+ ruby_exe(fixture(__FILE__, "passive.rb")).should == "true"
+ end
+ end
+
+ describe "Net::FTP#passive=" do
+ it "sets self to passive mode when passed true" do
+ ftp = Net::FTP.new
+
+ ftp.passive = true
+ ftp.passive.should be_true
+
+ ftp.passive = false
+ ftp.passive.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/put_spec.rb b/spec/ruby/library/net/ftp/put_spec.rb
new file mode 100644
index 0000000000..36ba6c1963
--- /dev/null
+++ b/spec/ruby/library/net/ftp/put_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/puttextfile'
+ require_relative 'shared/putbinaryfile'
+
+ describe "Net::FTP#put (binary mode)" do
+ before :each do
+ @binary_mode = true
+ end
+
+ it_behaves_like :net_ftp_putbinaryfile, :put
+ end
+
+ describe "Net::FTP#put (text mode)" do
+ before :each do
+ @binary_mode = false
+ end
+
+ it_behaves_like :net_ftp_puttextfile, :put
+ end
+end
diff --git a/spec/ruby/library/net/ftp/putbinaryfile_spec.rb b/spec/ruby/library/net/ftp/putbinaryfile_spec.rb
new file mode 100644
index 0000000000..6ced5246fe
--- /dev/null
+++ b/spec/ruby/library/net/ftp/putbinaryfile_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/putbinaryfile'
+
+ describe "Net::FTP#putbinaryfile" do
+ it_behaves_like :net_ftp_putbinaryfile, :putbinaryfile
+ end
+end
diff --git a/spec/ruby/library/net/ftp/puttextfile_spec.rb b/spec/ruby/library/net/ftp/puttextfile_spec.rb
new file mode 100644
index 0000000000..0cab6bd3c3
--- /dev/null
+++ b/spec/ruby/library/net/ftp/puttextfile_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+ require_relative 'shared/puttextfile'
+
+ describe "Net::FTP#puttextfile" do
+ it_behaves_like :net_ftp_puttextfile, :puttextfile
+ end
+end
diff --git a/spec/ruby/library/net/ftp/pwd_spec.rb b/spec/ruby/library/net/ftp/pwd_spec.rb
new file mode 100644
index 0000000000..856ff5ff9b
--- /dev/null
+++ b/spec/ruby/library/net/ftp/pwd_spec.rb
@@ -0,0 +1,56 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#pwd" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the PWD command to the server" do
+ @ftp.pwd
+ @ftp.last_response.should == "257 \"/some/dir/\" - current directory\n"
+ end
+
+ it "returns the current directory" do
+ @ftp.pwd.should == "/some/dir/"
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:pwd).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:pwd).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:pwd).and_respond("502 Command not implemented.")
+ -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:pwd).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.pwd }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:pwd).and_respond("550 Requested action not taken.")
+ -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/quit_spec.rb b/spec/ruby/library/net/ftp/quit_spec.rb
new file mode 100644
index 0000000000..12b9fd3cee
--- /dev/null
+++ b/spec/ruby/library/net/ftp/quit_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#quit" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the QUIT command to the server" do
+ @ftp.quit
+ @ftp.last_response.should == "221 OK, bye\n"
+ end
+
+ it "does not close the socket automatically" do
+ @ftp.quit
+ @ftp.closed?.should be_false
+ end
+
+ it "returns nil" do
+ @ftp.quit.should be_nil
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/rename_spec.rb b/spec/ruby/library/net/ftp/rename_spec.rb
new file mode 100644
index 0000000000..aa7c1360b5
--- /dev/null
+++ b/spec/ruby/library/net/ftp/rename_spec.rb
@@ -0,0 +1,97 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#rename" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ describe "when passed from_name, to_name" do
+ it "sends the RNFR command with the passed from_name and the RNTO command with the passed to_name to the server" do
+ @ftp.rename("from.file", "to.file")
+ @ftp.last_response.should == "250 Requested file action okay, completed. (Renamed from.file to to.file)\n"
+ end
+
+ it "returns something" do
+ @ftp.rename("from.file", "to.file").should be_nil
+ end
+ end
+
+ describe "when the RNFR command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:rnfr).and_respond("450 Requested file action not taken.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:rnfr).and_respond("550 Requested action not taken.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:rnfr).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:rnfr).and_respond("502 Command not implemented.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:rnfr).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:rnfr).and_respond("530 Not logged in.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when the RNTO command fails" do
+ it "raises a Net::FTPPermError when the response code is 532" do
+ @server.should_receive(:rnfr).and_respond("532 Need account for storing files.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 553" do
+ @server.should_receive(:rnto).and_respond("553 Requested action not taken.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:rnto).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:rnto).and_respond("502 Command not implemented.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:rnto).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:rnto).and_respond("530 Not logged in.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/resume_spec.rb b/spec/ruby/library/net/ftp/resume_spec.rb
new file mode 100644
index 0000000000..1b575c29f1
--- /dev/null
+++ b/spec/ruby/library/net/ftp/resume_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+
+ describe "Net::FTP#resume" do
+ it "returns true when self is set to resume uploads/downloads" do
+ ftp = Net::FTP.new
+ ftp.resume.should be_false
+
+ ftp.resume = true
+ ftp.resume.should be_true
+ end
+ end
+
+ describe "Net::FTP#resume=" do
+ it "sets self to resume uploads/downloads when set to true" do
+ ftp = Net::FTP.new
+ ftp.resume = true
+ ftp.resume.should be_true
+
+ ftp.resume = false
+ ftp.resume.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/retrbinary_spec.rb b/spec/ruby/library/net/ftp/retrbinary_spec.rb
new file mode 100644
index 0000000000..1f89f0d454
--- /dev/null
+++ b/spec/ruby/library/net/ftp/retrbinary_spec.rb
@@ -0,0 +1,33 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#retrbinary" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the passed command to the server" do
+ @ftp.retrbinary("RETR test", 4096) {}
+ @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
+ end
+
+ it "yields the received content as binary blocks of the passed size" do
+ res = []
+ @ftp.retrbinary("RETR test", 10) { |bin| res << bin }
+ res.should == [ "This is th", "e content\n", "of the fil", "e named 't", "est'.\n" ]
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/retrlines_spec.rb b/spec/ruby/library/net/ftp/retrlines_spec.rb
new file mode 100644
index 0000000000..f26b008680
--- /dev/null
+++ b/spec/ruby/library/net/ftp/retrlines_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#retrlines" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the passed command over the socket" do
+ @ftp.retrlines("LIST test.dir") {}
+ @ftp.last_response.should == "226 transfer complete (LIST test.dir)\n"
+ end
+
+ it "yields each received line to the passed block" do
+ res = []
+ @ftp.retrlines("LIST test.dir") { |x| res << x }
+ res.should == [
+ "-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb",
+ "-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb",
+ "-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb"
+ ]
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/return_code_spec.rb b/spec/ruby/library/net/ftp/return_code_spec.rb
new file mode 100644
index 0000000000..67fc9d3b19
--- /dev/null
+++ b/spec/ruby/library/net/ftp/return_code_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+
+ describe "Net::FTP#return_code" do
+ before :each do
+ @ftp = Net::FTP.new
+ end
+
+ it "outputs a warning and returns a newline" do
+ -> do
+ @ftp.return_code.should == "\n"
+ end.should complain(/warning: Net::FTP#return_code is obsolete and do nothing/)
+ end
+ end
+
+ describe "Net::FTP#return_code=" do
+ before :each do
+ @ftp = Net::FTP.new
+ end
+
+ it "outputs a warning" do
+ -> { @ftp.return_code = 123 }.should complain(/warning: Net::FTP#return_code= is obsolete and do nothing/)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/rmdir_spec.rb b/spec/ruby/library/net/ftp/rmdir_spec.rb
new file mode 100644
index 0000000000..5b9586c6f0
--- /dev/null
+++ b/spec/ruby/library/net/ftp/rmdir_spec.rb
@@ -0,0 +1,61 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#rmdir" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the RMD command with the passed pathname to the server" do
+ @ftp.rmdir("test.folder")
+ @ftp.last_response.should == "250 Requested file action okay, completed. (RMD test.folder)\n"
+ end
+
+ it "returns nil" do
+ @ftp.rmdir("test.folder").should be_nil
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:rmd).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:rmd).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:rmd).and_respond("502 Command not implemented.")
+ -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:rmd).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:rmd).and_respond("530 Not logged in.")
+ -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:rmd).and_respond("550 Requested action not taken.")
+ -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/sendcmd_spec.rb b/spec/ruby/library/net/ftp/sendcmd_spec.rb
new file mode 100644
index 0000000000..fefb89ae0b
--- /dev/null
+++ b/spec/ruby/library/net/ftp/sendcmd_spec.rb
@@ -0,0 +1,57 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#sendcmd" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the passed command to the server" do
+ @ftp.sendcmd("HELP")
+ @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
+ end
+
+ it "returns the server's response" do
+ @ftp.sendcmd("HELP").should == "211 System status, or system help reply. (HELP)\n"
+ end
+
+ it "raises no error when the response code is 1xx, 2xx or 3xx" do
+ @server.should_receive(:help).and_respond("120 Service ready in nnn minutes.")
+ -> { @ftp.sendcmd("HELP") }.should_not raise_error
+
+ @server.should_receive(:help).and_respond("200 Command okay.")
+ -> { @ftp.sendcmd("HELP") }.should_not raise_error
+
+ @server.should_receive(:help).and_respond("350 Requested file action pending further information.")
+ -> { @ftp.sendcmd("HELP") }.should_not raise_error
+ end
+
+ it "raises a Net::FTPTempError when the response code is 4xx" do
+ @server.should_receive(:help).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 5xx" do
+ @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is not between 1xx-5xx" do
+ @server.should_receive(:help).and_respond("999 Invalid response.")
+ -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPProtoError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/set_socket_spec.rb b/spec/ruby/library/net/ftp/set_socket_spec.rb
new file mode 100644
index 0000000000..6c8b58fb79
--- /dev/null
+++ b/spec/ruby/library/net/ftp/set_socket_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+
+ describe "Net::FTP#set_socket" do
+ # TODO: I won't spec this method, as it is not used
+ # anywhere and it should be private anyway.
+ it "needs to be reviewed for spec completeness"
+ end
+end
diff --git a/spec/ruby/library/net/ftp/shared/getbinaryfile.rb b/spec/ruby/library/net/ftp/shared/getbinaryfile.rb
new file mode 100644
index 0000000000..f324f5b85d
--- /dev/null
+++ b/spec/ruby/library/net/ftp/shared/getbinaryfile.rb
@@ -0,0 +1,150 @@
+describe :net_ftp_getbinaryfile, shared: :true do
+ before :each do
+ @fixture_file = File.dirname(__FILE__) + "/../fixtures/getbinaryfile"
+ @tmp_file = tmp("getbinaryfile")
+
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ @ftp.binary = @binary_mode
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+
+ rm_r @tmp_file
+ end
+
+ it "sends the RETR command to the server" do
+ @ftp.send(@method, "test", @tmp_file)
+ @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
+ end
+
+ it "returns nil" do
+ @ftp.send(@method, "test", @tmp_file).should be_nil
+ end
+
+ it "saves the contents of the passed remote file to the passed local file" do
+ @ftp.send(@method, "test", @tmp_file)
+ File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
+ end
+
+ describe "when passed a block" do
+ it "yields the received content as binary blocks of the passed size" do
+ res = []
+ @ftp.send(@method, "test", @tmp_file, 10) { |bin| res << bin }
+ res.should == [ "This is th", "e content\n", "of the fil", "e named 't", "est'.\n" ]
+ end
+ end
+
+ describe "when resuming an existing file" do
+ before :each do
+ @tmp_file = tmp("getbinaryfile_resume")
+
+ File.open(@tmp_file, "wb") do |f|
+ f << "This is the content\n"
+ end
+
+ @ftp.resume = true
+ end
+
+ it "saves the remaining content of the passed remote file to the passed local file" do
+ @ftp.send(@method, "test", @tmp_file)
+ File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
+ end
+
+ describe "and the REST command fails" do
+ it "raises a Net::FTPProtoError when the response code is 550" do
+ @server.should_receive(:rest).and_respond("Requested action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:rest).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:rest).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:rest).and_respond("502 Command not implemented.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:rest).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:rest).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+ end
+ end
+
+ describe "when the RETR command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:retr).and_respond("450 Requested file action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 550" do
+ @server.should_receive(:retr).and_respond("Requested action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:retr).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:retr).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:retr).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:retr).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/shared/gettextfile.rb b/spec/ruby/library/net/ftp/shared/gettextfile.rb
new file mode 100644
index 0000000000..82bec2a4a7
--- /dev/null
+++ b/spec/ruby/library/net/ftp/shared/gettextfile.rb
@@ -0,0 +1,100 @@
+describe :net_ftp_gettextfile, shared: :true do
+ before :each do
+ @tmp_file = tmp("gettextfile")
+
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ @ftp.binary = @binary_mode
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+
+ rm_r @tmp_file
+ end
+
+ it "sends the RETR command to the server" do
+ @ftp.send(@method, "test", @tmp_file)
+ @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
+ end
+
+ it "returns nil" do
+ @ftp.send(@method, "test", @tmp_file).should be_nil
+ end
+
+ it "saves the contents of the passed remote file to the passed local file" do
+ @ftp.send(@method, "test", @tmp_file)
+ File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
+ end
+
+ describe "when passed a block" do
+ it "yields each line of the retrieved file to the passed block" do
+ res = []
+ @ftp.send(@method, "test", @tmp_file) { |line| res << line }
+ res.should == [ "This is the content", "of the file named 'test'."]
+ end
+ end
+
+ describe "when the RETR command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:retr).and_respond("450 Requested file action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 550" do
+ @server.should_receive(:retr).and_respond("Requested action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:retr).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:retr).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:retr).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:retr).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-ftp/shared/last_response_code.rb b/spec/ruby/library/net/ftp/shared/last_response_code.rb
index 4fe53677db..4fe53677db 100644
--- a/spec/ruby/library/net-ftp/shared/last_response_code.rb
+++ b/spec/ruby/library/net/ftp/shared/last_response_code.rb
diff --git a/spec/ruby/library/net-ftp/shared/list.rb b/spec/ruby/library/net/ftp/shared/list.rb
index adc3fa59c1..adc3fa59c1 100644
--- a/spec/ruby/library/net-ftp/shared/list.rb
+++ b/spec/ruby/library/net/ftp/shared/list.rb
diff --git a/spec/ruby/library/net/ftp/shared/putbinaryfile.rb b/spec/ruby/library/net/ftp/shared/putbinaryfile.rb
new file mode 100644
index 0000000000..1163a1cfea
--- /dev/null
+++ b/spec/ruby/library/net/ftp/shared/putbinaryfile.rb
@@ -0,0 +1,167 @@
+describe :net_ftp_putbinaryfile, shared: :true do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @local_fixture_file = File.dirname(__FILE__) + "/../fixtures/putbinaryfile"
+ @remote_tmp_file = tmp("binaryfile", false)
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ @ftp.binary = @binary_mode
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+
+ rm_r @remote_tmp_file
+ end
+
+ it "sends the STOR command to the server" do
+ @ftp.send(@method, @local_fixture_file, "binary")
+ @ftp.last_response.should == "200 OK, Data received. (STOR binary)\n"
+ end
+
+ it "sends the contents of the passed local_file, without modifications" do
+ @ftp.send(@method, @local_fixture_file, "binary")
+
+ remote_lines = File.readlines(@remote_tmp_file)
+ local_lines = File.readlines(@local_fixture_file)
+
+ remote_lines.should == local_lines
+ end
+
+ it "returns nil" do
+ @ftp.send(@method, @local_fixture_file, "binary").should be_nil
+ end
+
+ describe "when passed a block" do
+ it "yields the transmitted content as binary blocks of the passed size" do
+ res = []
+ @ftp.send(@method, @local_fixture_file, "binary", 10) { |x| res << x }
+ res.should == [
+ "This is an", " example f",
+ "ile\nwhich ", "is going t",
+ "o be trans", "mitted\nusi",
+ "ng #putbin", "aryfile.\n"
+ ]
+ end
+ end
+
+ describe "when resuming an existing file" do
+ before :each do
+ File.open(@remote_tmp_file, "w") do |f|
+ f << "This is an example file\n"
+ end
+
+ @ftp.resume = true
+ end
+
+ it "sends the remaining content of the passed local_file to the passed remote_file" do
+ @ftp.send(@method, @local_fixture_file, "binary")
+ File.read(@remote_tmp_file).should == File.read(@local_fixture_file)
+ end
+
+ describe "and the APPE command fails" do
+ it "raises a Net::FTPProtoError when the response code is 550" do
+ @server.should_receive(:appe).and_respond("Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:appe).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:appe).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:appe).and_respond("502 Command not implemented.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:appe).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:appe).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+ end
+ end
+
+ describe "when the STOR command fails" do
+ it "raises a Net::FTPPermError when the response code is 532" do
+ @server.should_receive(:stor).and_respond("532 Need account for storing files.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:stor).and_respond("450 Requested file action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 452" do
+ @server.should_receive(:stor).and_respond("452 Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 553" do
+ @server.should_receive(:stor).and_respond("553 Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:stor).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:stor).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:stor).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:stor).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/shared/puttextfile.rb b/spec/ruby/library/net/ftp/shared/puttextfile.rb
new file mode 100644
index 0000000000..50e8de28e6
--- /dev/null
+++ b/spec/ruby/library/net/ftp/shared/puttextfile.rb
@@ -0,0 +1,120 @@
+describe :net_ftp_puttextfile, shared: true do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @local_fixture_file = File.dirname(__FILE__) + "/../fixtures/puttextfile"
+ @remote_tmp_file = tmp("textfile", false)
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ @ftp.binary = @binary_mode
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+
+ rm_r @remote_tmp_file
+ end
+
+ it "sends the STOR command to the server" do
+ @ftp.send(@method, @local_fixture_file, "text")
+ @ftp.last_response.should == "200 OK, Data received. (STOR text)\n"
+ end
+
+ it "sends the contents of the passed local_file, using \\r\\n as the newline separator" do
+ @ftp.send(@method, @local_fixture_file, "text")
+
+ remote_lines = open(@remote_tmp_file, "rb") {|f| f.read }
+ local_lines = open(@local_fixture_file, "rb") {|f| f.read }
+
+ remote_lines.should_not == local_lines
+ remote_lines.should == local_lines.gsub("\n", "\r\n")
+ end
+
+ it "returns nil" do
+ @ftp.send(@method, @local_fixture_file, "text").should be_nil
+ end
+
+ describe "when passed a block" do
+ it "yields each transmitted line" do
+ res = []
+ @ftp.send(@method, @local_fixture_file, "text") { |x| res << x }
+ res.should == [
+ "This is an example file\r\n",
+ "which is going to be transmitted\r\n",
+ "using #puttextfile.\r\n"
+ ]
+ end
+ end
+
+ describe "when the STOR command fails" do
+ it "raises a Net::FTPPermError when the response code is 532" do
+ @server.should_receive(:stor).and_respond("532 Need account for storing files.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:stor).and_respond("450 Requested file action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 452" do
+ @server.should_receive(:stor).and_respond("452 Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 553" do
+ @server.should_receive(:stor).and_respond("553 Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:stor).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:stor).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:stor).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:stor).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-ftp/shared/pwd.rb b/spec/ruby/library/net/ftp/shared/pwd.rb
index 951d020f2d..951d020f2d 100644
--- a/spec/ruby/library/net-ftp/shared/pwd.rb
+++ b/spec/ruby/library/net/ftp/shared/pwd.rb
diff --git a/spec/ruby/library/net/ftp/site_spec.rb b/spec/ruby/library/net/ftp/site_spec.rb
new file mode 100644
index 0000000000..ca4f499112
--- /dev/null
+++ b/spec/ruby/library/net/ftp/site_spec.rb
@@ -0,0 +1,56 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#site" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the SITE command with the passed argument to the server" do
+ @ftp.site("param")
+ @ftp.last_response.should == "200 Command okay. (SITE param)\n"
+ end
+
+ it "returns nil" do
+ @ftp.site("param").should be_nil
+ end
+
+ it "does not raise an error when the response code is 202" do
+ @server.should_receive(:site).and_respond("202 Command not implemented, superfluous at this site.")
+ -> { @ftp.site("param") }.should_not raise_error
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:site).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:site).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:site).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.site("param") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:site).and_respond("530 Requested action not taken.")
+ -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/size_spec.rb b/spec/ruby/library/net/ftp/size_spec.rb
new file mode 100644
index 0000000000..0c20b10549
--- /dev/null
+++ b/spec/ruby/library/net/ftp/size_spec.rb
@@ -0,0 +1,51 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#size" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the SIZE command to the server" do
+ @ftp.size("test.file")
+ @ftp.last_response.should == "213 1024\n"
+ end
+
+ it "returns the size of the passed file as Integer" do
+ @ftp.size("test.file").should eql(1024)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:size).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:size).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:size).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.size("test.file") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:size).and_respond("550 Requested action not taken.")
+ -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-ftp/spec_helper.rb b/spec/ruby/library/net/ftp/spec_helper.rb
index c87d16218b..c87d16218b 100644
--- a/spec/ruby/library/net-ftp/spec_helper.rb
+++ b/spec/ruby/library/net/ftp/spec_helper.rb
diff --git a/spec/ruby/library/net/ftp/status_spec.rb b/spec/ruby/library/net/ftp/status_spec.rb
new file mode 100644
index 0000000000..03bc5d6e05
--- /dev/null
+++ b/spec/ruby/library/net/ftp/status_spec.rb
@@ -0,0 +1,70 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#status" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the STAT command to the server" do
+ @ftp.status
+ @ftp.last_response.should == "211 System status, or system help reply. (STAT)\n"
+ end
+
+ it "sends the STAT command with an optional parameter to the server" do
+ @ftp.status("/pub").should == "211 System status, or system help reply. (STAT /pub)\n"
+ end
+
+ it "returns the received information" do
+ @ftp.status.should == "211 System status, or system help reply. (STAT)\n"
+ end
+
+ it "does not raise an error when the response code is 212" do
+ @server.should_receive(:stat).and_respond("212 Directory status.")
+ -> { @ftp.status }.should_not raise_error
+ end
+
+ it "does not raise an error when the response code is 213" do
+ @server.should_receive(:stat).and_respond("213 File status.")
+ -> { @ftp.status }.should_not raise_error
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:stat).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.status }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:stat).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.status }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:stat).and_respond("502 Command not implemented.")
+ -> { @ftp.status }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:stat).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.status }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:stat).and_respond("530 Requested action not taken.")
+ -> { @ftp.status }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/storbinary_spec.rb b/spec/ruby/library/net/ftp/storbinary_spec.rb
new file mode 100644
index 0000000000..64c9090760
--- /dev/null
+++ b/spec/ruby/library/net/ftp/storbinary_spec.rb
@@ -0,0 +1,51 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#storbinary" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @local_fixture_file = File.dirname(__FILE__) + "/fixtures/putbinaryfile"
+ @tmp_file = tmp("binaryfile", false)
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+
+ rm_r @tmp_file
+ end
+
+ it "sends the passed command and the passed File object's content to the server" do
+ File.open(@local_fixture_file) do |f|
+ f.binmode
+
+ @ftp.storbinary("STOR binary", f, 4096) {}
+ @ftp.last_response.should == "200 OK, Data received. (STOR binary)\n"
+ end
+ end
+
+ it "yields the transmitted content as binary blocks of the passed size" do
+ File.open(@local_fixture_file) do |f|
+ f.binmode
+
+ res = []
+ @ftp.storbinary("STOR binary", f, 10) { |x| res << x }
+ res.should == [
+ "This is an", " example f",
+ "ile\nwhich ", "is going t",
+ "o be trans", "mitted\nusi",
+ "ng #putbin", "aryfile.\n"
+ ]
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/storlines_spec.rb b/spec/ruby/library/net/ftp/storlines_spec.rb
new file mode 100644
index 0000000000..a4bb7af799
--- /dev/null
+++ b/spec/ruby/library/net/ftp/storlines_spec.rb
@@ -0,0 +1,46 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#storlines" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @local_fixture_file = File.dirname(__FILE__) + "/fixtures/puttextfile"
+ @tmp_file = tmp("textfile", false)
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+
+ rm_r @tmp_file
+ end
+
+ it "sends the passed command and the passed File object's content to the server" do
+ File.open(@local_fixture_file) do |f|
+ @ftp.storlines("STOR text", f) {}
+ @ftp.last_response.should == "200 OK, Data received. (STOR text)\n"
+ end
+ end
+
+ it "yields each line of the transmitted content" do
+ File.open(@local_fixture_file) do |f|
+ res = []
+ @ftp.storlines("STOR text", f) { |x| res << x }
+ res.should == [
+ "This is an example file\r\n",
+ "which is going to be transmitted\r\n",
+ "using #puttextfile.\r\n"
+ ]
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/system_spec.rb b/spec/ruby/library/net/ftp/system_spec.rb
new file mode 100644
index 0000000000..0630bbe1f6
--- /dev/null
+++ b/spec/ruby/library/net/ftp/system_spec.rb
@@ -0,0 +1,51 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#system" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the SYST command to the server" do
+ @ftp.system
+ @ftp.last_response.should =~ /\A215 FTP Dummy Server \(SYST\)\Z/
+ end
+
+ it "returns the received information" do
+ @ftp.system.should =~ /\AFTP Dummy Server \(SYST\)\Z/
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:syst).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.system }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:syst).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.system }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:syst).and_respond("502 Command not implemented.")
+ -> { @ftp.system }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:syst).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.system }.should raise_error(Net::FTPTempError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/voidcmd_spec.rb b/spec/ruby/library/net/ftp/voidcmd_spec.rb
new file mode 100644
index 0000000000..ee74455d63
--- /dev/null
+++ b/spec/ruby/library/net/ftp/voidcmd_spec.rb
@@ -0,0 +1,57 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#voidcmd" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the passed command to the server" do
+ @server.should_receive(:help).and_respond("2xx Does not raise.")
+ -> { @ftp.voidcmd("HELP") }.should_not raise_error
+ end
+
+ it "returns nil" do
+ @server.should_receive(:help).and_respond("2xx Does not raise.")
+ @ftp.voidcmd("HELP").should be_nil
+ end
+
+ it "raises a Net::FTPReplyError when the response code is 1xx" do
+ @server.should_receive(:help).and_respond("1xx Does raise a Net::FTPReplyError.")
+ -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPReplyError)
+ end
+
+ it "raises a Net::FTPReplyError when the response code is 3xx" do
+ @server.should_receive(:help).and_respond("3xx Does raise a Net::FTPReplyError.")
+ -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPReplyError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 4xx" do
+ @server.should_receive(:help).and_respond("4xx Does raise a Net::FTPTempError.")
+ -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 5xx" do
+ @server.should_receive(:help).and_respond("5xx Does raise a Net::FTPPermError.")
+ -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is not valid" do
+ @server.should_receive(:help).and_respond("999 Does raise a Net::FTPProtoError.")
+ -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPProtoError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/welcome_spec.rb b/spec/ruby/library/net/ftp/welcome_spec.rb
new file mode 100644
index 0000000000..e5414ef607
--- /dev/null
+++ b/spec/ruby/library/net/ftp/welcome_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.1" do
+ require_relative 'spec_helper'
+ require_relative 'fixtures/server'
+
+ describe "Net::FTP#welcome" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "returns the server's welcome message" do
+ @ftp.welcome.should be_nil
+ @ftp.login
+ @ftp.welcome.should == "230 User logged in, proceed. (USER anonymous)\n"
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/HTTPBadResponse_spec.rb b/spec/ruby/library/net/http/HTTPBadResponse_spec.rb
new file mode 100644
index 0000000000..be644968f5
--- /dev/null
+++ b/spec/ruby/library/net/http/HTTPBadResponse_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPBadResponse" do
+ it "is a subclass of StandardError" do
+ Net::HTTPBadResponse.should < StandardError
+ end
+end
diff --git a/spec/ruby/library/net/http/HTTPClientExcepton_spec.rb b/spec/ruby/library/net/http/HTTPClientExcepton_spec.rb
new file mode 100644
index 0000000000..d576349a57
--- /dev/null
+++ b/spec/ruby/library/net/http/HTTPClientExcepton_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPClientException" do
+ it "is a subclass of Net::ProtoServerError" do
+ Net::HTTPClientException.should < Net::ProtoServerError
+ end
+
+ it "includes the Net::HTTPExceptions module" do
+ Net::HTTPClientException.should < Net::HTTPExceptions
+ end
+end
diff --git a/spec/ruby/library/net/http/HTTPError_spec.rb b/spec/ruby/library/net/http/HTTPError_spec.rb
new file mode 100644
index 0000000000..ab5f491bb7
--- /dev/null
+++ b/spec/ruby/library/net/http/HTTPError_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPError" do
+ it "is a subclass of Net::ProtocolError" do
+ Net::HTTPError.should < Net::ProtocolError
+ end
+
+ it "includes the Net::HTTPExceptions module" do
+ Net::HTTPError.should < Net::HTTPExceptions
+ end
+end
diff --git a/spec/ruby/library/net/http/HTTPFatalError_spec.rb b/spec/ruby/library/net/http/HTTPFatalError_spec.rb
new file mode 100644
index 0000000000..6ab36bff6c
--- /dev/null
+++ b/spec/ruby/library/net/http/HTTPFatalError_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPFatalError" do
+ it "is a subclass of Net::ProtoFatalError" do
+ Net::HTTPFatalError.should < Net::ProtoFatalError
+ end
+
+ it "includes the Net::HTTPExceptions module" do
+ Net::HTTPFatalError.should < Net::HTTPExceptions
+ end
+end
diff --git a/spec/ruby/library/net/http/HTTPHeaderSyntaxError_spec.rb b/spec/ruby/library/net/http/HTTPHeaderSyntaxError_spec.rb
new file mode 100644
index 0000000000..38e9454f99
--- /dev/null
+++ b/spec/ruby/library/net/http/HTTPHeaderSyntaxError_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPHeaderSyntaxError" do
+ it "is a subclass of StandardError" do
+ Net::HTTPHeaderSyntaxError.should < StandardError
+ end
+end
diff --git a/spec/ruby/library/net/http/HTTPRetriableError_spec.rb b/spec/ruby/library/net/http/HTTPRetriableError_spec.rb
new file mode 100644
index 0000000000..3a4bb9146c
--- /dev/null
+++ b/spec/ruby/library/net/http/HTTPRetriableError_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPRetriableError" do
+ it "is a subclass of Net::ProtoRetriableError" do
+ Net::HTTPRetriableError.should < Net::ProtoRetriableError
+ end
+
+ it "includes the Net::HTTPExceptions module" do
+ Net::HTTPRetriableError.should < Net::HTTPExceptions
+ end
+end
diff --git a/spec/ruby/library/net/http/HTTPServerException_spec.rb b/spec/ruby/library/net/http/HTTPServerException_spec.rb
new file mode 100644
index 0000000000..23b0657364
--- /dev/null
+++ b/spec/ruby/library/net/http/HTTPServerException_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPServerException" do
+ it "is a subclass of Net::ProtoServerError and is warned as deprecated" do
+ -> { Net::HTTPServerException.should < Net::ProtoServerError }.should complain(/warning: constant Net::HTTPServerException is deprecated/)
+ end
+
+ it "includes the Net::HTTPExceptions module and is warned as deprecated" do
+ -> { Net::HTTPServerException.should < Net::HTTPExceptions }.should complain(/warning: constant Net::HTTPServerException is deprecated/)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/Proxy_spec.rb b/spec/ruby/library/net/http/http/Proxy_spec.rb
new file mode 100644
index 0000000000..f85ccc0ee9
--- /dev/null
+++ b/spec/ruby/library/net/http/http/Proxy_spec.rb
@@ -0,0 +1,35 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.Proxy" do
+ it "returns a new subclass of Net::HTTP" do
+ Net::HTTP.Proxy("localhost").should < Net::HTTP
+ end
+
+ it "returns Net::HTTP when the passed address is nil" do
+ Net::HTTP.Proxy(nil).should == Net::HTTP
+ end
+
+ it "sets the returned subclasses' proxy options based on the passed arguments" do
+ http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
+ http_with_proxy.proxy_address.should == "localhost"
+ http_with_proxy.proxy_port.should eql(1234)
+ http_with_proxy.proxy_user.should == "rspec"
+ http_with_proxy.proxy_pass.should == "rocks"
+ end
+end
+
+describe "Net::HTTP#proxy?" do
+ describe "when self is no proxy class instance" do
+ it "returns false" do
+ Net::HTTP.new("localhost", 3333).proxy?.should be_false
+ end
+ end
+
+ describe "when self is a proxy class instance" do
+ it "returns false" do
+ http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
+ http_with_proxy.new("localhost", 3333).proxy?.should be_true
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/active_spec.rb b/spec/ruby/library/net/http/http/active_spec.rb
new file mode 100644
index 0000000000..ef657243ba
--- /dev/null
+++ b/spec/ruby/library/net/http/http/active_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/started'
+
+describe "Net::HTTP#active?" do
+ it_behaves_like :net_http_started_p, :active?
+end
diff --git a/spec/ruby/library/net/http/http/address_spec.rb b/spec/ruby/library/net/http/http/address_spec.rb
new file mode 100644
index 0000000000..5fce76d767
--- /dev/null
+++ b/spec/ruby/library/net/http/http/address_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#address" do
+ it "returns the current host name" do
+ net = Net::HTTP.new("localhost")
+ net.address.should == "localhost"
+ end
+end
diff --git a/spec/ruby/library/net/http/http/close_on_empty_response_spec.rb b/spec/ruby/library/net/http/http/close_on_empty_response_spec.rb
new file mode 100644
index 0000000000..a97b7b6c43
--- /dev/null
+++ b/spec/ruby/library/net/http/http/close_on_empty_response_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#close_on_empty_response" do
+ it "needs to be reviewed for spec completeness"
+end
+
+describe "Net::HTTP#close_on_empty_response=" do
+ it "needs to be reviewed for spec completeness"
+end
diff --git a/spec/ruby/library/net/http/http/copy_spec.rb b/spec/ruby/library/net/http/http/copy_spec.rb
new file mode 100644
index 0000000000..5ebfdc334e
--- /dev/null
+++ b/spec/ruby/library/net/http/http/copy_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#copy" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a COPY request to the passed path and returns the response" do
+ response = @http.copy("/request")
+ response.should be_kind_of(Net::HTTPResponse)
+ response.body.should == "Request type: COPY"
+ end
+end
diff --git a/spec/ruby/library/net/http/http/default_port_spec.rb b/spec/ruby/library/net/http/http/default_port_spec.rb
new file mode 100644
index 0000000000..30db18efae
--- /dev/null
+++ b/spec/ruby/library/net/http/http/default_port_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.default_port" do
+ it "returns 80" do
+ Net::HTTP.http_default_port.should eql(80)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/delete_spec.rb b/spec/ruby/library/net/http/http/delete_spec.rb
new file mode 100644
index 0000000000..160c653115
--- /dev/null
+++ b/spec/ruby/library/net/http/http/delete_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#delete" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a DELETE request to the passed path and returns the response" do
+ response = @http.delete("/request")
+ response.should be_kind_of(Net::HTTPResponse)
+ response.body.should == "Request type: DELETE"
+ end
+end
diff --git a/spec/ruby/library/net/http/http/finish_spec.rb b/spec/ruby/library/net/http/http/finish_spec.rb
new file mode 100644
index 0000000000..f98bc7be13
--- /dev/null
+++ b/spec/ruby/library/net/http/http/finish_spec.rb
@@ -0,0 +1,29 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#finish" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.new("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ describe "when self has been started" do
+ it "closes the tcp connection" do
+ @http.start
+ @http.finish
+ @http.started?.should be_false
+ end
+ end
+
+ describe "when self has not been started yet" do
+ it "raises an IOError" do
+ -> { @http.finish }.should raise_error(IOError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/fixtures/http_server.rb b/spec/ruby/library/net/http/http/fixtures/http_server.rb
index c1cedbfa76..c1cedbfa76 100644
--- a/spec/ruby/library/net-http/http/fixtures/http_server.rb
+++ b/spec/ruby/library/net/http/http/fixtures/http_server.rb
diff --git a/spec/ruby/library/net/http/http/get2_spec.rb b/spec/ruby/library/net/http/http/get2_spec.rb
new file mode 100644
index 0000000000..519e4c2599
--- /dev/null
+++ b/spec/ruby/library/net/http/http/get2_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_get'
+
+describe "Net::HTTP#get2" do
+ it_behaves_like :net_http_request_get, :get2
+end
diff --git a/spec/ruby/library/net/http/http/get_print_spec.rb b/spec/ruby/library/net/http/http/get_print_spec.rb
new file mode 100644
index 0000000000..f59dd68c81
--- /dev/null
+++ b/spec/ruby/library/net/http/http/get_print_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP.get_print" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @port = NetHTTPSpecs.port
+ end
+
+ after :each do
+ NetHTTPSpecs.stop_server
+ end
+
+ describe "when passed URI" do
+ it "it prints the body of the specified uri to $stdout" do
+ -> do
+ Net::HTTP.get_print URI.parse("http://localhost:#{@port}/")
+ end.should output(/This is the index page\./)
+ end
+ end
+
+ describe "when passed host, path, port" do
+ it "it prints the body of the specified uri to $stdout" do
+ -> do
+ Net::HTTP.get_print 'localhost', "/", @port
+ end.should output(/This is the index page\./)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/get_response_spec.rb b/spec/ruby/library/net/http/http/get_response_spec.rb
new file mode 100644
index 0000000000..941b35e773
--- /dev/null
+++ b/spec/ruby/library/net/http/http/get_response_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP.get_response" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @port = NetHTTPSpecs.port
+ end
+
+ after :each do
+ NetHTTPSpecs.stop_server
+ end
+
+ describe "when passed URI" do
+ it "returns the response for the specified uri" do
+ res = Net::HTTP.get_response(URI.parse("http://localhost:#{@port}/"))
+ res.content_type.should == "text/plain"
+ res.body.should == "This is the index page."
+ end
+ end
+
+ describe "when passed host, path, port" do
+ it "returns the response for the specified host-path-combination" do
+ res = Net::HTTP.get_response('localhost', "/", @port)
+ res.content_type.should == "text/plain"
+ res.body.should == "This is the index page."
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/get_spec.rb b/spec/ruby/library/net/http/http/get_spec.rb
new file mode 100644
index 0000000000..9f6c45f26b
--- /dev/null
+++ b/spec/ruby/library/net/http/http/get_spec.rb
@@ -0,0 +1,96 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP.get" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @port = NetHTTPSpecs.port
+ end
+
+ after :each do
+ NetHTTPSpecs.stop_server
+ end
+
+ describe "when passed URI" do
+ it "returns the body of the specified uri" do
+ Net::HTTP.get(URI.parse("http://localhost:#{@port}/")).should == "This is the index page."
+ end
+ end
+
+ describe "when passed host, path, port" do
+ it "returns the body of the specified host-path-combination" do
+ Net::HTTP.get('localhost', "/", @port).should == "This is the index page."
+ end
+ end
+end
+
+quarantine! do # These specs fail frequently with CHECK_LEAKS=true
+describe "Net::HTTP.get" do
+ describe "when reading gzipped contents" do
+ def start_threads
+ require 'zlib'
+ require 'stringio'
+
+ server = nil
+ server_thread = Thread.new do
+ server = TCPServer.new("127.0.0.1", 0)
+ begin
+ c = server.accept
+ ensure
+ server.close
+ end
+ c.print "HTTP/1.1 200\r\n"
+ c.print "Content-Type: text/plain\r\n"
+ c.print "Content-Encoding: gzip\r\n"
+ s = StringIO.new
+ z = Zlib::GzipWriter.new(s)
+ begin
+ z.write 'Hello World!'
+ ensure
+ z.close
+ end
+ c.print "Content-Length: #{s.length}\r\n\r\n"
+ # Write partial gzip content
+ c.write s.string.byteslice(0..-2)
+ c.flush
+ c
+ end
+ Thread.pass until server && server_thread.stop?
+
+ client_thread = Thread.new do
+ Thread.current.report_on_exception = false
+ Net::HTTP.get("127.0.0.1", '/', server.connect_address.ip_port)
+ end
+
+ socket = server_thread.value
+ Thread.pass until client_thread.stop?
+
+ [socket, client_thread]
+ end
+
+ it "propagates exceptions interrupting the thread and does not replace it with Zlib::BufError" do
+ my_exception = Class.new(RuntimeError)
+ socket, client_thread = start_threads
+ begin
+ client_thread.raise my_exception, "my exception"
+ -> { client_thread.value }.should raise_error(my_exception)
+ ensure
+ socket.close
+ end
+ end
+
+ ruby_version_is "3.0" do # https://bugs.ruby-lang.org/issues/13882#note-6
+ it "lets the kill Thread exception goes through and does not replace it with Zlib::BufError" do
+ socket, client_thread = start_threads
+ begin
+ client_thread.kill
+ client_thread.value.should == nil
+ ensure
+ socket.close
+ end
+ end
+ end
+ end
+end
+end
diff --git a/spec/ruby/library/net/http/http/head2_spec.rb b/spec/ruby/library/net/http/http/head2_spec.rb
new file mode 100644
index 0000000000..6958204ee1
--- /dev/null
+++ b/spec/ruby/library/net/http/http/head2_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_head'
+
+describe "Net::HTTP#head2" do
+ it_behaves_like :net_http_request_head, :head2
+end
diff --git a/spec/ruby/library/net/http/http/head_spec.rb b/spec/ruby/library/net/http/http/head_spec.rb
new file mode 100644
index 0000000000..925a8e6043
--- /dev/null
+++ b/spec/ruby/library/net/http/http/head_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#head" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a HEAD request to the passed path and returns the response" do
+ response = @http.head("/request")
+ # HEAD requests have no responses
+ response.body.should be_nil
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.head("/request").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/http_default_port_spec.rb b/spec/ruby/library/net/http/http/http_default_port_spec.rb
new file mode 100644
index 0000000000..cf7f73e630
--- /dev/null
+++ b/spec/ruby/library/net/http/http/http_default_port_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.http_default_port" do
+ it "returns 80" do
+ Net::HTTP.http_default_port.should eql(80)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/https_default_port_spec.rb b/spec/ruby/library/net/http/http/https_default_port_spec.rb
new file mode 100644
index 0000000000..fbf0bd1abc
--- /dev/null
+++ b/spec/ruby/library/net/http/http/https_default_port_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.https_default_port" do
+ it "returns 443" do
+ Net::HTTP.https_default_port.should eql(443)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/initialize_spec.rb b/spec/ruby/library/net/http/http/initialize_spec.rb
new file mode 100644
index 0000000000..7683713a0e
--- /dev/null
+++ b/spec/ruby/library/net/http/http/initialize_spec.rb
@@ -0,0 +1,46 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#initialize" do
+ it "is private" do
+ Net::HTTP.should have_private_instance_method(:initialize)
+ end
+
+ describe "when passed address" do
+ before :each do
+ @net = Net::HTTP.allocate
+ @net.send(:initialize, "localhost")
+ end
+
+ it "sets the new Net::HTTP instance's address to the passed address" do
+ @net.address.should == "localhost"
+ end
+
+ it "sets the new Net::HTTP instance's port to the default HTTP port" do
+ @net.port.should eql(Net::HTTP.default_port)
+ end
+
+ it "does not start the new Net::HTTP instance" do
+ @net.started?.should be_false
+ end
+ end
+
+ describe "when passed address, port" do
+ before :each do
+ @net = Net::HTTP.allocate
+ @net.send(:initialize, "localhost", 3333)
+ end
+
+ it "sets the new Net::HTTP instance's address to the passed address" do
+ @net.address.should == "localhost"
+ end
+
+ it "sets the new Net::HTTP instance's port to the passed port" do
+ @net.port.should eql(3333)
+ end
+
+ it "does not start the new Net::HTTP instance" do
+ @net.started?.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/inspect_spec.rb b/spec/ruby/library/net/http/http/inspect_spec.rb
new file mode 100644
index 0000000000..b1e799ca34
--- /dev/null
+++ b/spec/ruby/library/net/http/http/inspect_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#inspect" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @port = NetHTTPSpecs.port
+ @http = Net::HTTP.new("localhost", @port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "returns a String representation of self" do
+ @http.inspect.should be_kind_of(String)
+ @http.inspect.should == "#<Net::HTTP localhost:#{@port} open=false>"
+
+ @http.start
+ @http.inspect.should == "#<Net::HTTP localhost:#{@port} open=true>"
+ end
+end
diff --git a/spec/ruby/library/net/http/http/is_version_1_1_spec.rb b/spec/ruby/library/net/http/http/is_version_1_1_spec.rb
new file mode 100644
index 0000000000..f37695b777
--- /dev/null
+++ b/spec/ruby/library/net/http/http/is_version_1_1_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'shared/version_1_1'
+
+describe "Net::HTTP.is_version_1_1?" do
+ it_behaves_like :net_http_version_1_1_p, :is_version_1_1?
+end
diff --git a/spec/ruby/library/net/http/http/is_version_1_2_spec.rb b/spec/ruby/library/net/http/http/is_version_1_2_spec.rb
new file mode 100644
index 0000000000..82dbdc87aa
--- /dev/null
+++ b/spec/ruby/library/net/http/http/is_version_1_2_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'shared/version_1_2'
+
+describe "Net::HTTP.is_version_1_2?" do
+ it_behaves_like :net_http_version_1_2_p, :is_version_1_2?
+end
diff --git a/spec/ruby/library/net/http/http/lock_spec.rb b/spec/ruby/library/net/http/http/lock_spec.rb
new file mode 100644
index 0000000000..bb76607a8b
--- /dev/null
+++ b/spec/ruby/library/net/http/http/lock_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#lock" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a LOCK request to the passed path and returns the response" do
+ response = @http.lock("/request", "test=test")
+ response.should be_kind_of(Net::HTTPResponse)
+ response.body.should == "Request type: LOCK"
+ end
+end
diff --git a/spec/ruby/library/net/http/http/mkcol_spec.rb b/spec/ruby/library/net/http/http/mkcol_spec.rb
new file mode 100644
index 0000000000..33017625e2
--- /dev/null
+++ b/spec/ruby/library/net/http/http/mkcol_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#mkcol" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a MKCOL request to the passed path and returns the response" do
+ response = @http.mkcol("/request")
+ response.should be_kind_of(Net::HTTPResponse)
+ response.body.should == "Request type: MKCOL"
+ end
+end
diff --git a/spec/ruby/library/net/http/http/move_spec.rb b/spec/ruby/library/net/http/http/move_spec.rb
new file mode 100644
index 0000000000..4d6b828150
--- /dev/null
+++ b/spec/ruby/library/net/http/http/move_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#head" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a MOVE request to the passed path and returns the response" do
+ response = @http.move("/request")
+ # HEAD requests have no responses
+ response.body.should == "Request type: MOVE"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.move("/request").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/new_spec.rb b/spec/ruby/library/net/http/http/new_spec.rb
new file mode 100644
index 0000000000..491d1d01fd
--- /dev/null
+++ b/spec/ruby/library/net/http/http/new_spec.rb
@@ -0,0 +1,86 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.new" do
+ describe "when passed address" do
+ before :each do
+ @http = Net::HTTP.new("localhost")
+ end
+
+ it "returns a Net::HTTP instance" do
+ @http.proxy?.should be_false
+ @http.instance_of?(Net::HTTP).should be_true
+ end
+
+ it "sets the new Net::HTTP instance's address to the passed address" do
+ @http.address.should == "localhost"
+ end
+
+ it "sets the new Net::HTTP instance's port to the default HTTP port" do
+ @http.port.should eql(Net::HTTP.default_port)
+ end
+
+ it "does not start the new Net::HTTP instance" do
+ @http.started?.should be_false
+ end
+ end
+
+ describe "when passed address, port" do
+ before :each do
+ @http = Net::HTTP.new("localhost", 3333)
+ end
+
+ it "returns a Net::HTTP instance" do
+ @http.proxy?.should be_false
+ @http.instance_of?(Net::HTTP).should be_true
+ end
+
+ it "sets the new Net::HTTP instance's address to the passed address" do
+ @http.address.should == "localhost"
+ end
+
+ it "sets the new Net::HTTP instance's port to the passed port" do
+ @http.port.should eql(3333)
+ end
+
+ it "does not start the new Net::HTTP instance" do
+ @http.started?.should be_false
+ end
+ end
+
+ describe "when passed address, port, *proxy_options" do
+ it "returns a Net::HTTP instance" do
+ http = Net::HTTP.new("localhost", 3333, "localhost")
+ http.proxy?.should be_true
+ http.instance_of?(Net::HTTP).should be_true
+ http.should be_kind_of(Net::HTTP)
+ end
+
+ it "correctly sets the passed Proxy options" do
+ http = Net::HTTP.new("localhost", 3333, "localhost")
+ http.proxy_address.should == "localhost"
+ http.proxy_port.should eql(80)
+ http.proxy_user.should be_nil
+ http.proxy_pass.should be_nil
+
+ http = Net::HTTP.new("localhost", 3333, "localhost", 1234)
+ http.proxy_address.should == "localhost"
+ http.proxy_port.should eql(1234)
+ http.proxy_user.should be_nil
+ http.proxy_pass.should be_nil
+
+ http = Net::HTTP.new("localhost", 3333, "localhost", 1234, "rubyspec")
+ http.proxy_address.should == "localhost"
+ http.proxy_port.should eql(1234)
+ http.proxy_user.should == "rubyspec"
+ http.proxy_pass.should be_nil
+
+ http = Net::HTTP.new("localhost", 3333, "localhost", 1234, "rubyspec", "rocks")
+ http.proxy_address.should == "localhost"
+ http.proxy_port.should eql(1234)
+ http.proxy_user.should == "rubyspec"
+ http.proxy_pass.should == "rocks"
+ end
+ end
+
+end
diff --git a/spec/ruby/library/net/http/http/newobj_spec.rb b/spec/ruby/library/net/http/http/newobj_spec.rb
new file mode 100644
index 0000000000..b261dcc5db
--- /dev/null
+++ b/spec/ruby/library/net/http/http/newobj_spec.rb
@@ -0,0 +1,48 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.newobj" do
+ before :each do
+ @net = Net::HTTP.newobj("localhost")
+ end
+
+ describe "when passed address" do
+ it "returns a new Net::HTTP instance" do
+ @net.should be_kind_of(Net::HTTP)
+ end
+
+ it "sets the new Net::HTTP instance's address to the passed address" do
+ @net.address.should == "localhost"
+ end
+
+ it "sets the new Net::HTTP instance's port to the default HTTP port" do
+ @net.port.should eql(Net::HTTP.default_port)
+ end
+
+ it "does not start the new Net::HTTP instance" do
+ @net.started?.should be_false
+ end
+ end
+
+ describe "when passed address, port" do
+ before :each do
+ @net = Net::HTTP.newobj("localhost", 3333)
+ end
+
+ it "returns a new Net::HTTP instance" do
+ @net.should be_kind_of(Net::HTTP)
+ end
+
+ it "sets the new Net::HTTP instance's address to the passed address" do
+ @net.address.should == "localhost"
+ end
+
+ it "sets the new Net::HTTP instance's port to the passed port" do
+ @net.port.should eql(3333)
+ end
+
+ it "does not start the new Net::HTTP instance" do
+ @net.started?.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/open_timeout_spec.rb b/spec/ruby/library/net/http/http/open_timeout_spec.rb
new file mode 100644
index 0000000000..44b33615e6
--- /dev/null
+++ b/spec/ruby/library/net/http/http/open_timeout_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#open_timeout" do
+ it "returns the seconds to wait till the connection is open" do
+ net = Net::HTTP.new("localhost")
+ net.open_timeout.should eql(60)
+ net.open_timeout = 10
+ net.open_timeout.should eql(10)
+ end
+end
+
+describe "Net::HTTP#open_timeout=" do
+ it "sets the seconds to wait till the connection is open" do
+ net = Net::HTTP.new("localhost")
+ net.open_timeout = 10
+ net.open_timeout.should eql(10)
+ end
+
+ it "returns the newly set value" do
+ net = Net::HTTP.new("localhost")
+ (net.open_timeout = 10).should eql(10)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/options_spec.rb b/spec/ruby/library/net/http/http/options_spec.rb
new file mode 100644
index 0000000000..d798e69197
--- /dev/null
+++ b/spec/ruby/library/net/http/http/options_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#options" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends an options request to the passed path and returns the response" do
+ response = @http.options("/request")
+
+ response.body.should == "Request type: OPTIONS"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.options("/request").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/port_spec.rb b/spec/ruby/library/net/http/http/port_spec.rb
new file mode 100644
index 0000000000..7de295ca75
--- /dev/null
+++ b/spec/ruby/library/net/http/http/port_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#port" do
+ it "returns the current port number" do
+ net = Net::HTTP.new("localhost", 3333)
+ net.port.should eql(3333)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/post2_spec.rb b/spec/ruby/library/net/http/http/post2_spec.rb
new file mode 100644
index 0000000000..ccc95068fb
--- /dev/null
+++ b/spec/ruby/library/net/http/http/post2_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_post'
+
+describe "Net::HTTP#post2" do
+ it_behaves_like :net_http_request_post, :post2
+end
diff --git a/spec/ruby/library/net/http/http/post_form_spec.rb b/spec/ruby/library/net/http/http/post_form_spec.rb
new file mode 100644
index 0000000000..891e05e7af
--- /dev/null
+++ b/spec/ruby/library/net/http/http/post_form_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP.post_form when passed URI" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @port = NetHTTPSpecs.port
+ end
+
+ after :each do
+ NetHTTPSpecs.stop_server
+ end
+
+ it "POSTs the passed form data to the given uri" do
+ uri = URI.parse("http://localhost:#{@port}/request/body")
+ data = { test: :data }
+
+ res = Net::HTTP.post_form(uri, data)
+ res.body.should == "test=data"
+ end
+end
diff --git a/spec/ruby/library/net/http/http/post_spec.rb b/spec/ruby/library/net/http/http/post_spec.rb
new file mode 100644
index 0000000000..891e20aaca
--- /dev/null
+++ b/spec/ruby/library/net/http/http/post_spec.rb
@@ -0,0 +1,74 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require 'uri'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP.post" do
+ before :each do
+ NetHTTPSpecs.start_server
+ end
+
+ after :each do
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends post request to the specified URI and returns response" do
+ response = Net::HTTP.post(
+ URI("http://localhost:#{NetHTTPSpecs.port}/request"),
+ '{ "q": "ruby", "max": "50" }',
+ "Content-Type" => "application/json")
+ response.body.should == "Request type: POST"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ response = Net::HTTP.post(URI("http://localhost:#{NetHTTPSpecs.port}/request"), "test=test")
+ response.should be_kind_of(Net::HTTPResponse)
+ end
+
+ it "sends Content-Type: application/x-www-form-urlencoded by default" do
+ response = Net::HTTP.post(URI("http://localhost:#{NetHTTPSpecs.port}/request/header"), "test=test")
+ response.body.should include('"Content-Type"=>"application/x-www-form-urlencoded"')
+ end
+
+ it "does not support HTTP Basic Auth" do
+ response = Net::HTTP.post(
+ URI("http://john:qwerty@localhost:#{NetHTTPSpecs.port}/request/basic_auth"),
+ "test=test")
+ response.body.should == "username: \npassword: "
+ end
+end
+
+describe "Net::HTTP#post" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends an post request to the passed path and returns the response" do
+ response = @http.post("/request", "test=test")
+ response.body.should == "Request type: POST"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.post("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ end
+
+ describe "when passed a block" do
+ it "yields fragments of the response body to the passed block" do
+ str = ""
+ @http.post("/request", "test=test") do |res|
+ str << res
+ end
+ str.should == "Request type: POST"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.post("/request", "test=test") {}.should be_kind_of(Net::HTTPResponse)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/propfind_spec.rb b/spec/ruby/library/net/http/http/propfind_spec.rb
new file mode 100644
index 0000000000..5240171618
--- /dev/null
+++ b/spec/ruby/library/net/http/http/propfind_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#propfind" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends an propfind request to the passed path and returns the response" do
+ response = @http.propfind("/request", "test=test")
+ response.body.should == "Request type: PROPFIND"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.propfind("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/proppatch_spec.rb b/spec/ruby/library/net/http/http/proppatch_spec.rb
new file mode 100644
index 0000000000..7a761a9f23
--- /dev/null
+++ b/spec/ruby/library/net/http/http/proppatch_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#proppatch" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends an proppatch request to the passed path and returns the response" do
+ response = @http.proppatch("/request", "test=test")
+ response.body.should == "Request type: PROPPATCH"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.proppatch("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/proxy_address_spec.rb b/spec/ruby/library/net/http/http/proxy_address_spec.rb
new file mode 100644
index 0000000000..8d152b8d44
--- /dev/null
+++ b/spec/ruby/library/net/http/http/proxy_address_spec.rb
@@ -0,0 +1,31 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.proxy_address" do
+ describe "when self is no proxy class" do
+ it "returns nil" do
+ Net::HTTP.proxy_address.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class" do
+ it "returns the address for self's proxy connection" do
+ Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_address.should == "localhost"
+ end
+ end
+end
+
+describe "Net::HTTP#proxy_address" do
+ describe "when self is no proxy class instance" do
+ it "returns nil" do
+ Net::HTTP.new("localhost", 3333).proxy_address.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class instance" do
+ it "returns the password for self's proxy connection" do
+ http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
+ http_with_proxy.new("localhost", 3333).proxy_address.should == "localhost"
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/proxy_class_spec.rb b/spec/ruby/library/net/http/http/proxy_class_spec.rb
new file mode 100644
index 0000000000..2d32a39f01
--- /dev/null
+++ b/spec/ruby/library/net/http/http/proxy_class_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.proxy_class?" do
+ it "returns true if self is a class created with Net::HTTP.Proxy" do
+ Net::HTTP.proxy_class?.should be_false
+ Net::HTTP.Proxy("localhost").proxy_class?.should be_true
+ end
+end
diff --git a/spec/ruby/library/net/http/http/proxy_pass_spec.rb b/spec/ruby/library/net/http/http/proxy_pass_spec.rb
new file mode 100644
index 0000000000..94a0034544
--- /dev/null
+++ b/spec/ruby/library/net/http/http/proxy_pass_spec.rb
@@ -0,0 +1,39 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.proxy_pass" do
+ describe "when self is no proxy class" do
+ it "returns nil" do
+ Net::HTTP.proxy_pass.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class" do
+ it "returns nil if no password was set for self's proxy connection" do
+ Net::HTTP.Proxy("localhost").proxy_pass.should be_nil
+ end
+
+ it "returns the password for self's proxy connection" do
+ Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_pass.should == "rocks"
+ end
+ end
+end
+
+describe "Net::HTTP#proxy_pass" do
+ describe "when self is no proxy class instance" do
+ it "returns nil" do
+ Net::HTTP.new("localhost", 3333).proxy_pass.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class instance" do
+ it "returns nil if no password was set for self's proxy connection" do
+ Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_pass.should be_nil
+ end
+
+ it "returns the password for self's proxy connection" do
+ http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
+ http_with_proxy.new("localhost", 3333).proxy_pass.should == "rocks"
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/proxy_port_spec.rb b/spec/ruby/library/net/http/http/proxy_port_spec.rb
new file mode 100644
index 0000000000..339f7ee850
--- /dev/null
+++ b/spec/ruby/library/net/http/http/proxy_port_spec.rb
@@ -0,0 +1,39 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.proxy_port" do
+ describe "when self is no proxy class" do
+ it "returns nil" do
+ Net::HTTP.proxy_port.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class" do
+ it "returns 80 if no port was set for self's proxy connection" do
+ Net::HTTP.Proxy("localhost").proxy_port.should eql(80)
+ end
+
+ it "returns the port for self's proxy connection" do
+ Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_port.should eql(1234)
+ end
+ end
+end
+
+describe "Net::HTTP#proxy_port" do
+ describe "when self is no proxy class instance" do
+ it "returns nil" do
+ Net::HTTP.new("localhost", 3333).proxy_port.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class instance" do
+ it "returns 80 if no port was set for self's proxy connection" do
+ Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_port.should eql(80)
+ end
+
+ it "returns the port for self's proxy connection" do
+ http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
+ http_with_proxy.new("localhost", 3333).proxy_port.should eql(1234)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/proxy_user_spec.rb b/spec/ruby/library/net/http/http/proxy_user_spec.rb
new file mode 100644
index 0000000000..01fda400e9
--- /dev/null
+++ b/spec/ruby/library/net/http/http/proxy_user_spec.rb
@@ -0,0 +1,39 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.proxy_user" do
+ describe "when self is no proxy class" do
+ it "returns nil" do
+ Net::HTTP.proxy_user.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class" do
+ it "returns nil if no username was set for self's proxy connection" do
+ Net::HTTP.Proxy("localhost").proxy_user.should be_nil
+ end
+
+ it "returns the username for self's proxy connection" do
+ Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_user.should == "rspec"
+ end
+ end
+end
+
+describe "Net::HTTP#proxy_user" do
+ describe "when self is no proxy class instance" do
+ it "returns nil" do
+ Net::HTTP.new("localhost", 3333).proxy_user.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class instance" do
+ it "returns nil if no username was set for self's proxy connection" do
+ Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_user.should be_nil
+ end
+
+ it "returns the username for self's proxy connection" do
+ http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
+ http_with_proxy.new("localhost", 3333).proxy_user.should == "rspec"
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/put2_spec.rb b/spec/ruby/library/net/http/http/put2_spec.rb
new file mode 100644
index 0000000000..99329a5fd9
--- /dev/null
+++ b/spec/ruby/library/net/http/http/put2_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_put'
+
+describe "Net::HTTP#put2" do
+ it_behaves_like :net_http_request_put, :put2
+end
diff --git a/spec/ruby/library/net/http/http/put_spec.rb b/spec/ruby/library/net/http/http/put_spec.rb
new file mode 100644
index 0000000000..3ca0d0963e
--- /dev/null
+++ b/spec/ruby/library/net/http/http/put_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#put" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends an put request to the passed path and returns the response" do
+ response = @http.put("/request", "test=test")
+ response.body.should == "Request type: PUT"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.put("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/read_timeout_spec.rb b/spec/ruby/library/net/http/http/read_timeout_spec.rb
new file mode 100644
index 0000000000..e23ee76025
--- /dev/null
+++ b/spec/ruby/library/net/http/http/read_timeout_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#read_timeout" do
+ it "returns the seconds to wait until reading one block" do
+ net = Net::HTTP.new("localhost")
+ net.read_timeout.should eql(60)
+ net.read_timeout = 10
+ net.read_timeout.should eql(10)
+ end
+end
+
+describe "Net::HTTP#read_timeout=" do
+ it "sets the seconds to wait till the connection is open" do
+ net = Net::HTTP.new("localhost")
+ net.read_timeout = 10
+ net.read_timeout.should eql(10)
+ end
+
+ it "returns the newly set value" do
+ net = Net::HTTP.new("localhost")
+ (net.read_timeout = 10).should eql(10)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/request_get_spec.rb b/spec/ruby/library/net/http/http/request_get_spec.rb
new file mode 100644
index 0000000000..9932ef0beb
--- /dev/null
+++ b/spec/ruby/library/net/http/http/request_get_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_get'
+
+describe "Net::HTTP#request_get" do
+ it_behaves_like :net_http_request_get, :get2
+end
diff --git a/spec/ruby/library/net/http/http/request_head_spec.rb b/spec/ruby/library/net/http/http/request_head_spec.rb
new file mode 100644
index 0000000000..788101c951
--- /dev/null
+++ b/spec/ruby/library/net/http/http/request_head_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_head'
+
+describe "Net::HTTP#request_head" do
+ it_behaves_like :net_http_request_head, :request_head
+end
diff --git a/spec/ruby/library/net/http/http/request_post_spec.rb b/spec/ruby/library/net/http/http/request_post_spec.rb
new file mode 100644
index 0000000000..7ac67cf95d
--- /dev/null
+++ b/spec/ruby/library/net/http/http/request_post_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_post'
+
+describe "Net::HTTP#request_post" do
+ it_behaves_like :net_http_request_post, :request_post
+end
diff --git a/spec/ruby/library/net/http/http/request_put_spec.rb b/spec/ruby/library/net/http/http/request_put_spec.rb
new file mode 100644
index 0000000000..110ac43ca6
--- /dev/null
+++ b/spec/ruby/library/net/http/http/request_put_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_put'
+
+describe "Net::HTTP#request_put" do
+ it_behaves_like :net_http_request_put, :request_put
+end
diff --git a/spec/ruby/library/net/http/http/request_spec.rb b/spec/ruby/library/net/http/http/request_spec.rb
new file mode 100644
index 0000000000..e63dde9c8d
--- /dev/null
+++ b/spec/ruby/library/net/http/http/request_spec.rb
@@ -0,0 +1,109 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#request" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ describe "when passed request_object" do
+ it "makes a HTTP Request based on the passed request_object" do
+ response = @http.request(Net::HTTP::Get.new("/request"), "test=test")
+ response.body.should == "Request type: GET"
+
+ response = @http.request(Net::HTTP::Head.new("/request"), "test=test")
+ response.body.should be_nil
+
+ response = @http.request(Net::HTTP::Post.new("/request"), "test=test")
+ response.body.should == "Request type: POST"
+
+ response = @http.request(Net::HTTP::Put.new("/request"), "test=test")
+ response.body.should == "Request type: PUT"
+
+ response = @http.request(Net::HTTP::Proppatch.new("/request"), "test=test")
+ response.body.should == "Request type: PROPPATCH"
+
+ response = @http.request(Net::HTTP::Lock.new("/request"), "test=test")
+ response.body.should == "Request type: LOCK"
+
+ response = @http.request(Net::HTTP::Unlock.new("/request"), "test=test")
+ response.body.should == "Request type: UNLOCK"
+
+ # TODO: Does not work?
+ #response = @http.request(Net::HTTP::Options.new("/request"), "test=test")
+ #response.body.should be_nil
+
+ response = @http.request(Net::HTTP::Propfind.new("/request"), "test=test")
+ response.body.should == "Request type: PROPFIND"
+
+ response = @http.request(Net::HTTP::Delete.new("/request"), "test=test")
+ response.body.should == "Request type: DELETE"
+
+ response = @http.request(Net::HTTP::Move.new("/request"), "test=test")
+ response.body.should == "Request type: MOVE"
+
+ response = @http.request(Net::HTTP::Copy.new("/request"), "test=test")
+ response.body.should == "Request type: COPY"
+
+ response = @http.request(Net::HTTP::Mkcol.new("/request"), "test=test")
+ response.body.should == "Request type: MKCOL"
+
+ response = @http.request(Net::HTTP::Trace.new("/request"), "test=test")
+ response.body.should == "Request type: TRACE"
+ end
+ end
+
+ describe "when passed request_object and request_body" do
+ it "sends the passed request_body when making the HTTP Request" do
+ response = @http.request(Net::HTTP::Get.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Head.new("/request/body"), "test=test")
+ response.body.should be_nil
+
+ response = @http.request(Net::HTTP::Post.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Put.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Proppatch.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Lock.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Unlock.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ # TODO: Does not work?
+ #response = @http.request(Net::HTTP::Options.new("/request/body"), "test=test")
+ #response.body.should be_nil
+
+ response = @http.request(Net::HTTP::Propfind.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Delete.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Move.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Copy.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Mkcol.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Trace.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/request_types_spec.rb b/spec/ruby/library/net/http/http/request_types_spec.rb
new file mode 100644
index 0000000000..99d754d3d1
--- /dev/null
+++ b/spec/ruby/library/net/http/http/request_types_spec.rb
@@ -0,0 +1,254 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP::Get" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Get.should < Net::HTTPRequest
+ end
+
+ it "represents the 'GET'-Request-Method" do
+ Net::HTTP::Get::METHOD.should == "GET"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Get::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Get::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Head" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Head.should < Net::HTTPRequest
+ end
+
+ it "represents the 'HEAD'-Request-Method" do
+ Net::HTTP::Head::METHOD.should == "HEAD"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Head::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has no Response Body" do
+ Net::HTTP::Head::RESPONSE_HAS_BODY.should be_false
+ end
+end
+
+describe "Net::HTTP::Post" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Post.should < Net::HTTPRequest
+ end
+
+ it "represents the 'POST'-Request-Method" do
+ Net::HTTP::Post::METHOD.should == "POST"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Post::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Post::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Put" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Put.should < Net::HTTPRequest
+ end
+
+ it "represents the 'PUT'-Request-Method" do
+ Net::HTTP::Put::METHOD.should == "PUT"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Put::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Put::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Delete" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Delete.should < Net::HTTPRequest
+ end
+
+ it "represents the 'DELETE'-Request-Method" do
+ Net::HTTP::Delete::METHOD.should == "DELETE"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Delete::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Delete::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Options" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Options.should < Net::HTTPRequest
+ end
+
+ it "represents the 'OPTIONS'-Request-Method" do
+ Net::HTTP::Options::METHOD.should == "OPTIONS"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Options::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has no Response Body" do
+ Net::HTTP::Options::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Trace" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Trace.should < Net::HTTPRequest
+ end
+
+ it "represents the 'TRACE'-Request-Method" do
+ Net::HTTP::Trace::METHOD.should == "TRACE"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Trace::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Trace::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Propfind" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Propfind.should < Net::HTTPRequest
+ end
+
+ it "represents the 'PROPFIND'-Request-Method" do
+ Net::HTTP::Propfind::METHOD.should == "PROPFIND"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Propfind::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Propfind::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Proppatch" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Proppatch.should < Net::HTTPRequest
+ end
+
+ it "represents the 'PROPPATCH'-Request-Method" do
+ Net::HTTP::Proppatch::METHOD.should == "PROPPATCH"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Proppatch::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Proppatch::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Mkcol" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Mkcol.should < Net::HTTPRequest
+ end
+
+ it "represents the 'MKCOL'-Request-Method" do
+ Net::HTTP::Mkcol::METHOD.should == "MKCOL"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Mkcol::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Mkcol::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Copy" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Copy.should < Net::HTTPRequest
+ end
+
+ it "represents the 'COPY'-Request-Method" do
+ Net::HTTP::Copy::METHOD.should == "COPY"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Copy::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Copy::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Move" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Move.should < Net::HTTPRequest
+ end
+
+ it "represents the 'MOVE'-Request-Method" do
+ Net::HTTP::Move::METHOD.should == "MOVE"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Move::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Move::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Lock" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Lock.should < Net::HTTPRequest
+ end
+
+ it "represents the 'LOCK'-Request-Method" do
+ Net::HTTP::Lock::METHOD.should == "LOCK"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Lock::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Lock::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Unlock" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Unlock.should < Net::HTTPRequest
+ end
+
+ it "represents the 'UNLOCK'-Request-Method" do
+ Net::HTTP::Unlock::METHOD.should == "UNLOCK"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Unlock::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Unlock::RESPONSE_HAS_BODY.should be_true
+ end
+end
diff --git a/spec/ruby/library/net/http/http/send_request_spec.rb b/spec/ruby/library/net/http/http/send_request_spec.rb
new file mode 100644
index 0000000000..83e9448b8b
--- /dev/null
+++ b/spec/ruby/library/net/http/http/send_request_spec.rb
@@ -0,0 +1,61 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#send_request" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+
+ # HEAD is special so handled separately
+ @methods = %w[
+ GET POST PUT DELETE
+ OPTIONS
+ PROPFIND PROPPATCH LOCK UNLOCK
+ ]
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ # TODO: Does only work with GET and POST requests
+ describe "when passed type, path" do
+ it "sends a HTTP Request of the passed type to the passed path" do
+ response = @http.send_request("HEAD", "/request")
+ response.body.should be_nil
+
+ (@methods - %w[POST PUT]).each do |method|
+ response = @http.send_request(method, "/request")
+ response.body.should == "Request type: #{method}"
+ end
+ end
+ end
+
+ describe "when passed type, path, body" do
+ it "sends a HTTP Request with the passed body" do
+ response = @http.send_request("HEAD", "/request/body", "test=test")
+ response.body.should be_nil
+
+ @methods.each do |method|
+ response = @http.send_request(method, "/request/body", "test=test")
+ response.body.should == "test=test"
+ end
+ end
+ end
+
+ describe "when passed type, path, body, headers" do
+ it "sends a HTTP Request with the passed headers" do
+ referer = 'https://www.ruby-lang.org/'.freeze
+
+ response = @http.send_request("HEAD", "/request/header", "test=test", "referer" => referer)
+ response.body.should be_nil
+
+ @methods.each do |method|
+ response = @http.send_request(method, "/request/header", "test=test", "referer" => referer)
+ response.body.should include('"Referer"=>"' + referer + '"')
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/set_debug_output_spec.rb b/spec/ruby/library/net/http/http/set_debug_output_spec.rb
new file mode 100644
index 0000000000..94b6f4499d
--- /dev/null
+++ b/spec/ruby/library/net/http/http/set_debug_output_spec.rb
@@ -0,0 +1,33 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require "stringio"
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#set_debug_output when passed io" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.new("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sets the passed io as output stream for debugging" do
+ io = StringIO.new
+
+ @http.set_debug_output(io)
+ @http.start
+ io.string.should_not be_empty
+ size = io.string.size
+
+ @http.get("/")
+ io.string.size.should > size
+ end
+
+ it "outputs a warning when the connection has already been started" do
+ @http.start
+ -> { @http.set_debug_output(StringIO.new) }.should complain(/Net::HTTP#set_debug_output called after HTTP started/)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/shared/request_get.rb b/spec/ruby/library/net/http/http/shared/request_get.rb
index d25f32049b..d25f32049b 100644
--- a/spec/ruby/library/net-http/http/shared/request_get.rb
+++ b/spec/ruby/library/net/http/http/shared/request_get.rb
diff --git a/spec/ruby/library/net-http/http/shared/request_head.rb b/spec/ruby/library/net/http/http/shared/request_head.rb
index 78b555884b..78b555884b 100644
--- a/spec/ruby/library/net-http/http/shared/request_head.rb
+++ b/spec/ruby/library/net/http/http/shared/request_head.rb
diff --git a/spec/ruby/library/net-http/http/shared/request_post.rb b/spec/ruby/library/net/http/http/shared/request_post.rb
index e832411c48..e832411c48 100644
--- a/spec/ruby/library/net-http/http/shared/request_post.rb
+++ b/spec/ruby/library/net/http/http/shared/request_post.rb
diff --git a/spec/ruby/library/net-http/http/shared/request_put.rb b/spec/ruby/library/net/http/http/shared/request_put.rb
index 3b902f4957..3b902f4957 100644
--- a/spec/ruby/library/net-http/http/shared/request_put.rb
+++ b/spec/ruby/library/net/http/http/shared/request_put.rb
diff --git a/spec/ruby/library/net-http/http/shared/started.rb b/spec/ruby/library/net/http/http/shared/started.rb
index 9ff6272c31..9ff6272c31 100644
--- a/spec/ruby/library/net-http/http/shared/started.rb
+++ b/spec/ruby/library/net/http/http/shared/started.rb
diff --git a/spec/ruby/library/net-http/http/shared/version_1_1.rb b/spec/ruby/library/net/http/http/shared/version_1_1.rb
index db3d6a986d..db3d6a986d 100644
--- a/spec/ruby/library/net-http/http/shared/version_1_1.rb
+++ b/spec/ruby/library/net/http/http/shared/version_1_1.rb
diff --git a/spec/ruby/library/net-http/http/shared/version_1_2.rb b/spec/ruby/library/net/http/http/shared/version_1_2.rb
index b044182c60..b044182c60 100644
--- a/spec/ruby/library/net-http/http/shared/version_1_2.rb
+++ b/spec/ruby/library/net/http/http/shared/version_1_2.rb
diff --git a/spec/ruby/library/net/http/http/socket_type_spec.rb b/spec/ruby/library/net/http/http/socket_type_spec.rb
new file mode 100644
index 0000000000..5c844ddf94
--- /dev/null
+++ b/spec/ruby/library/net/http/http/socket_type_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.socket_type" do
+ it "returns BufferedIO" do
+ Net::HTTP.socket_type.should == Net::BufferedIO
+ end
+end
diff --git a/spec/ruby/library/net/http/http/start_spec.rb b/spec/ruby/library/net/http/http/start_spec.rb
new file mode 100644
index 0000000000..a2768eed18
--- /dev/null
+++ b/spec/ruby/library/net/http/http/start_spec.rb
@@ -0,0 +1,111 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP.start" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @port = NetHTTPSpecs.port
+ end
+
+ after :each do
+ NetHTTPSpecs.stop_server
+ end
+
+ describe "when not passed a block" do
+ before :each do
+ @http = Net::HTTP.start("localhost", @port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ end
+
+ it "returns a new Net::HTTP object for the passed address and port" do
+ @http.should be_kind_of(Net::HTTP)
+ @http.address.should == "localhost"
+ @http.port.should == @port
+ end
+
+ it "opens the tcp connection" do
+ @http.started?.should be_true
+ end
+ end
+
+ describe "when passed a block" do
+ it "returns the blocks return value" do
+ Net::HTTP.start("localhost", @port) { :test }.should == :test
+ end
+
+ it "yields the new Net::HTTP object to the block" do
+ yielded = false
+ Net::HTTP.start("localhost", @port) do |net|
+ yielded = true
+ net.should be_kind_of(Net::HTTP)
+ end
+ yielded.should be_true
+ end
+
+ it "opens the tcp connection before yielding" do
+ Net::HTTP.start("localhost", @port) { |http| http.started?.should be_true }
+ end
+
+ it "closes the tcp connection after yielding" do
+ net = nil
+ Net::HTTP.start("localhost", @port) { |x| net = x }
+ net.started?.should be_false
+ end
+ end
+end
+
+describe "Net::HTTP#start" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.new("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "returns self" do
+ @http.start.should equal(@http)
+ end
+
+ it "opens the tcp connection" do
+ @http.start
+ @http.started?.should be_true
+ end
+
+ describe "when self has already been started" do
+ it "raises an IOError" do
+ @http.start
+ -> { @http.start }.should raise_error(IOError)
+ end
+ end
+
+ describe "when passed a block" do
+ it "returns the blocks return value" do
+ @http.start { :test }.should == :test
+ end
+
+ it "yields the new Net::HTTP object to the block" do
+ yielded = false
+ @http.start do |http|
+ yielded = true
+ http.should equal(@http)
+ end
+ yielded.should be_true
+ end
+
+ it "opens the tcp connection before yielding" do
+ @http.start { |http| http.started?.should be_true }
+ end
+
+ it "closes the tcp connection after yielding" do
+ @http.start { }
+ @http.started?.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/started_spec.rb b/spec/ruby/library/net/http/http/started_spec.rb
new file mode 100644
index 0000000000..ea441ed16a
--- /dev/null
+++ b/spec/ruby/library/net/http/http/started_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/started'
+
+describe "Net::HTTP#started?" do
+ it_behaves_like :net_http_started_p, :started?
+end
diff --git a/spec/ruby/library/net/http/http/trace_spec.rb b/spec/ruby/library/net/http/http/trace_spec.rb
new file mode 100644
index 0000000000..94a1bf6655
--- /dev/null
+++ b/spec/ruby/library/net/http/http/trace_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#trace" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a TRACE request to the passed path and returns the response" do
+ response = @http.trace("/request")
+ response.body.should == "Request type: TRACE"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.trace("/request").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/unlock_spec.rb b/spec/ruby/library/net/http/http/unlock_spec.rb
new file mode 100644
index 0000000000..a4f1b7a1d1
--- /dev/null
+++ b/spec/ruby/library/net/http/http/unlock_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#unlock" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends an UNLOCK request to the passed path and returns the response" do
+ response = @http.unlock("/request", "test=test")
+ response.body.should == "Request type: UNLOCK"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.unlock("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/use_ssl_spec.rb b/spec/ruby/library/net/http/http/use_ssl_spec.rb
new file mode 100644
index 0000000000..be1ec7fa25
--- /dev/null
+++ b/spec/ruby/library/net/http/http/use_ssl_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#use_ssl?" do
+ it "returns false" do
+ http = Net::HTTP.new("localhost")
+ http.use_ssl?.should be_false
+ end
+end
diff --git a/spec/ruby/library/net/http/http/version_1_1_spec.rb b/spec/ruby/library/net/http/http/version_1_1_spec.rb
new file mode 100644
index 0000000000..1c069e9ea6
--- /dev/null
+++ b/spec/ruby/library/net/http/http/version_1_1_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'shared/version_1_1'
+
+describe "Net::HTTP.version_1_1?" do
+ it_behaves_like :net_http_version_1_1_p, :version_1_1?
+end
diff --git a/spec/ruby/library/net/http/http/version_1_2_spec.rb b/spec/ruby/library/net/http/http/version_1_2_spec.rb
new file mode 100644
index 0000000000..4e601462c9
--- /dev/null
+++ b/spec/ruby/library/net/http/http/version_1_2_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'shared/version_1_2'
+
+describe "Net::HTTP.version_1_2" do
+ it "turns on net/http 1.2 features" do
+ Net::HTTP.version_1_2
+
+ Net::HTTP.version_1_2?.should be_true
+ Net::HTTP.version_1_1?.should be_false
+ end
+
+ it "returns true" do
+ Net::HTTP.version_1_2.should be_true
+ end
+end
+
+describe "Net::HTTP.version_1_2?" do
+ it_behaves_like :net_http_version_1_2_p, :version_1_2?
+end
diff --git a/spec/ruby/library/net-http/httpexceptions/fixtures/classes.rb b/spec/ruby/library/net/http/httpexceptions/fixtures/classes.rb
index abe8855eff..abe8855eff 100644
--- a/spec/ruby/library/net-http/httpexceptions/fixtures/classes.rb
+++ b/spec/ruby/library/net/http/httpexceptions/fixtures/classes.rb
diff --git a/spec/ruby/library/net/http/httpexceptions/initialize_spec.rb b/spec/ruby/library/net/http/httpexceptions/initialize_spec.rb
new file mode 100644
index 0000000000..8e3fd8cc02
--- /dev/null
+++ b/spec/ruby/library/net/http/httpexceptions/initialize_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPExceptions#initialize when passed message, response" do
+ before :each do
+ @exception = NetHTTPExceptionsSpecs::Simple.new("error message", "a http response")
+ end
+
+ it "calls super with the passed message" do
+ @exception.message.should == "error message"
+ end
+
+ it "sets self's response to the passed response" do
+ @exception.response.should == "a http response"
+ end
+end
diff --git a/spec/ruby/library/net/http/httpexceptions/response_spec.rb b/spec/ruby/library/net/http/httpexceptions/response_spec.rb
new file mode 100644
index 0000000000..205b2bc212
--- /dev/null
+++ b/spec/ruby/library/net/http/httpexceptions/response_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPExceptions#response" do
+ it "returns self's response" do
+ exception = NetHTTPExceptionsSpecs::Simple.new("error message", "a http response")
+ exception.response.should == "a http response"
+ end
+end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/body_exist_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/body_exist_spec.rb
new file mode 100644
index 0000000000..7d081939b8
--- /dev/null
+++ b/spec/ruby/library/net/http/httpgenericrequest/body_exist_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#body_exist?" do
+ it "returns true when the response is expected to have a body" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.body_exist?.should be_true
+
+ request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
+ request.body_exist?.should be_false
+ end
+
+ describe "when $VERBOSE is true" do
+ it "emits a warning" do
+ request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
+ -> {
+ request.body_exist?
+ }.should complain(/body_exist\? is obsolete/, verbose: true)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/body_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/body_spec.rb
new file mode 100644
index 0000000000..a215895b57
--- /dev/null
+++ b/spec/ruby/library/net/http/httpgenericrequest/body_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require "stringio"
+
+describe "Net::HTTPGenericRequest#body" do
+ it "returns self's request body" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.body.should be_nil
+
+ request.body = "Some Content"
+ request.body.should == "Some Content"
+ end
+end
+
+describe "Net::HTTPGenericRequest#body=" do
+ before :each do
+ @request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ end
+
+ it "sets self's body content to the passed String" do
+ @request.body = "Some Content"
+ @request.body.should == "Some Content"
+ end
+
+ it "sets self's body stream to nil" do
+ @request.body_stream = StringIO.new("")
+ @request.body = "Some Content"
+ @request.body_stream.should be_nil
+ end
+end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/body_stream_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/body_stream_spec.rb
new file mode 100644
index 0000000000..c2a60e6836
--- /dev/null
+++ b/spec/ruby/library/net/http/httpgenericrequest/body_stream_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require "stringio"
+
+describe "Net::HTTPGenericRequest#body_stream" do
+ it "returns self's body stream Object" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.body_stream.should be_nil
+
+ stream = StringIO.new("test")
+ request.body_stream = stream
+ request.body_stream.should equal(stream)
+ end
+end
+
+describe "Net::HTTPGenericRequest#body_stream=" do
+ before :each do
+ @request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ @stream = StringIO.new("test")
+ end
+
+ it "sets self's body stream to the passed Object" do
+ @request.body_stream = @stream
+ @request.body_stream.should equal(@stream)
+ end
+
+ it "sets self's body to nil" do
+ @request.body = "Some Content"
+ @request.body_stream = @stream
+ @request.body.should be_nil
+ end
+end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/exec_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/exec_spec.rb
new file mode 100644
index 0000000000..da5b1a63be
--- /dev/null
+++ b/spec/ruby/library/net/http/httpgenericrequest/exec_spec.rb
@@ -0,0 +1,131 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require "stringio"
+
+describe "Net::HTTPGenericRequest#exec when passed socket, version, path" do
+ before :each do
+ @socket = StringIO.new("")
+ @buffered_socket = Net::BufferedIO.new(@socket)
+ end
+
+ it "executes the request over the socket to the path using the HTTP version" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+
+ request.exec(@buffered_socket, "1.1", "/some/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str[-4..-1].should == "\r\n\r\n"
+
+ request = Net::HTTPGenericRequest.new("GET", true, true, "/some/path",
+ "Content-Type" => "text/html")
+
+ request.exec(@buffered_socket, "1.0", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[GET /some/other/path HTTP/1.0\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: text/html\r\n]
+ str[-4..-1].should == "\r\n\r\n"
+ end
+
+ describe "when a request body is set" do
+ it "sets the 'Content-Type' header to 'application/x-www-form-urlencoded' unless the 'Content-Type' header is supplied" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.body = "Some Content"
+
+ request.exec(@buffered_socket, "1.1", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: application/x-www-form-urlencoded\r\n]
+ str.should =~ %r[Content-Length: 12\r\n]
+ str[-16..-1].should == "\r\n\r\nSome Content"
+ end
+
+ it "correctly sets the 'Content-Length' header and includes the body" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
+ "Content-Type" => "text/html")
+ request.body = "Some Content"
+
+ request.exec(@buffered_socket, "1.1", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: text/html\r\n]
+ str.should =~ %r[Content-Length: 12\r\n]
+ str[-16..-1].should == "\r\n\r\nSome Content"
+ end
+ end
+
+ describe "when a body stream is set" do
+ it "sets the 'Content-Type' header to 'application/x-www-form-urlencoded' unless the 'Content-Type' header is supplied" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
+ "Content-Length" => "10")
+ request.body_stream = StringIO.new("a" * 20)
+
+ request.exec(@buffered_socket, "1.1", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: application/x-www-form-urlencoded\r\n]
+ str.should =~ %r[Content-Length: 10\r\n]
+ str[-24..-1].should == "\r\n\r\naaaaaaaaaaaaaaaaaaaa"
+ end
+
+ it "sends the whole stream, regardless of the 'Content-Length' header" do
+ request = Net::HTTPGenericRequest.new("POST", true, true,"/some/path",
+ "Content-Type" => "text/html",
+ "Content-Length" => "10")
+ request.body_stream = StringIO.new("a" * 20)
+
+ request.exec(@buffered_socket, "1.1", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: text/html\r\n]
+ str.should =~ %r[Content-Length: 10\r\n]
+ str[-24..-1].should == "\r\n\r\naaaaaaaaaaaaaaaaaaaa"
+ end
+
+ it "sends the request in chunks when 'Transfer-Encoding' is set to 'chunked'" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
+ "Content-Type" => "text/html",
+ "Transfer-Encoding" => "chunked")
+ datasize = 1024 * 10
+ request.body_stream = StringIO.new("a" * datasize)
+
+ request.exec(@buffered_socket, "1.1", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: text/html\r\n]
+ str.should =~ %r[Transfer-Encoding: chunked\r\n]
+ str =~ %r[\r\n\r\n]
+ str = $'
+ while datasize > 0
+ chunk_size_line, str = str.split(/\r\n/, 2)
+ chunk_size = chunk_size_line[/\A[0-9A-Fa-f]+/].to_i(16)
+ str.slice!(0, chunk_size).should == 'a' * chunk_size
+ datasize -= chunk_size
+ str.slice!(0, 2).should == "\r\n"
+ end
+ datasize.should == 0
+ str.should == %"0\r\n\r\n"
+ end
+
+ it "raises an ArgumentError when the 'Content-Length' is not set or 'Transfer-Encoding' is not set to 'chunked'" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
+ "Content-Type" => "text/html")
+ request.body_stream = StringIO.new("Some Content")
+
+ -> { request.exec(@buffered_socket, "1.1", "/some/other/path") }.should raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/inspect_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/inspect_spec.rb
new file mode 100644
index 0000000000..36240949c3
--- /dev/null
+++ b/spec/ruby/library/net/http/httpgenericrequest/inspect_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#inspect" do
+ it "returns a String representation of self" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.inspect.should == "#<Net::HTTPGenericRequest POST>"
+
+ request = Net::HTTPGenericRequest.new("GET", false, true, "/some/path")
+ request.inspect.should == "#<Net::HTTPGenericRequest GET>"
+
+ request = Net::HTTPGenericRequest.new("BLA", true, true, "/some/path")
+ request.inspect.should == "#<Net::HTTPGenericRequest BLA>"
+
+ # Subclasses
+ request = Net::HTTP::Get.new("/some/path")
+ request.inspect.should == "#<Net::HTTP::Get GET>"
+
+ request = Net::HTTP::Post.new("/some/path")
+ request.inspect.should == "#<Net::HTTP::Post POST>"
+
+ request = Net::HTTP::Trace.new("/some/path")
+ request.inspect.should == "#<Net::HTTP::Trace TRACE>"
+ end
+end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/method_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/method_spec.rb
new file mode 100644
index 0000000000..3f7c2cbf2b
--- /dev/null
+++ b/spec/ruby/library/net/http/httpgenericrequest/method_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#method" do
+ it "returns self's request method" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.method.should == "POST"
+
+ request = Net::HTTPGenericRequest.new("GET", false, true, "/some/path")
+ request.method.should == "GET"
+
+ request = Net::HTTPGenericRequest.new("BLA", true, true, "/some/path")
+ request.method.should == "BLA"
+ end
+end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/path_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/path_spec.rb
new file mode 100644
index 0000000000..fc4cf9af53
--- /dev/null
+++ b/spec/ruby/library/net/http/httpgenericrequest/path_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#path" do
+ it "returns self's request path" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.path.should == "/some/path"
+
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/other/path")
+ request.path.should == "/some/other/path"
+ end
+end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/request_body_permitted_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/request_body_permitted_spec.rb
new file mode 100644
index 0000000000..50cd1ff637
--- /dev/null
+++ b/spec/ruby/library/net/http/httpgenericrequest/request_body_permitted_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#request_body_permitted?" do
+ it "returns true when the request is expected to have a body" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.request_body_permitted?.should be_true
+
+ request = Net::HTTPGenericRequest.new("POST", false, true, "/some/path")
+ request.request_body_permitted?.should be_false
+ end
+end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/response_body_permitted_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/response_body_permitted_spec.rb
new file mode 100644
index 0000000000..0c4165d0ab
--- /dev/null
+++ b/spec/ruby/library/net/http/httpgenericrequest/response_body_permitted_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#response_body_permitted?" do
+ it "returns true when the response is expected to have a body" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.response_body_permitted?.should be_true
+
+ request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
+ request.response_body_permitted?.should be_false
+ end
+end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/set_body_internal_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/set_body_internal_spec.rb
new file mode 100644
index 0000000000..7494c69173
--- /dev/null
+++ b/spec/ruby/library/net/http/httpgenericrequest/set_body_internal_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#set_body_internal when passed string" do
+ before :each do
+ @request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ end
+
+ it "sets self's body to the passed string" do
+ @request.set_body_internal("Some Content")
+ @request.body.should == "Some Content"
+ end
+
+ it "raises an ArgumentError when the body or body_stream of self have already been set" do
+ @request.body = "Some Content"
+ -> { @request.set_body_internal("Some other Content") }.should raise_error(ArgumentError)
+
+ @request.body_stream = "Some Content"
+ -> { @request.set_body_internal("Some other Content") }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/add_field_spec.rb b/spec/ruby/library/net/http/httpheader/add_field_spec.rb
new file mode 100644
index 0000000000..882d5ac5bb
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/add_field_spec.rb
@@ -0,0 +1,31 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#add_field when passed key, value" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "adds the passed value to the header entry with the passed key" do
+ @headers.add_field("My-Header", "a")
+ @headers.get_fields("My-Header").should == ["a"]
+
+ @headers.add_field("My-Header", "b")
+ @headers.get_fields("My-Header").should == ["a", "b"]
+
+ @headers.add_field("My-Header", "c")
+ @headers.get_fields("My-Header").should == ["a", "b", "c"]
+ end
+
+ it "is case-insensitive" do
+ @headers.add_field("My-Header", "a")
+ @headers.get_fields("My-Header").should == ["a"]
+
+ @headers.add_field("my-header", "b")
+ @headers.get_fields("My-Header").should == ["a", "b"]
+
+ @headers.add_field("MY-HEADER", "c")
+ @headers.get_fields("My-Header").should == ["a", "b", "c"]
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/basic_auth_spec.rb b/spec/ruby/library/net/http/httpheader/basic_auth_spec.rb
new file mode 100644
index 0000000000..fa2a710fe1
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/basic_auth_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#basic_auth when passed account, password" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "sets the 'Authorization' Header entry for basic authorization" do
+ @headers.basic_auth("rubyspec", "rocks")
+ @headers["Authorization"].should == "Basic cnVieXNwZWM6cm9ja3M="
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/canonical_each_spec.rb b/spec/ruby/library/net/http/httpheader/canonical_each_spec.rb
new file mode 100644
index 0000000000..0dddd3049b
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/canonical_each_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_capitalized'
+
+describe "Net::HTTPHeader#canonical_each" do
+ it_behaves_like :net_httpheader_each_capitalized, :canonical_each
+end
diff --git a/spec/ruby/library/net/http/httpheader/chunked_spec.rb b/spec/ruby/library/net/http/httpheader/chunked_spec.rb
new file mode 100644
index 0000000000..96b758981b
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/chunked_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#chunked?" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns true if the 'Transfer-Encoding' header entry is set to chunked" do
+ @headers.chunked?.should be_false
+
+ @headers["Transfer-Encoding"] = "bla"
+ @headers.chunked?.should be_false
+
+ @headers["Transfer-Encoding"] = "blachunkedbla"
+ @headers.chunked?.should be_false
+
+ @headers["Transfer-Encoding"] = "chunked"
+ @headers.chunked?.should be_true
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/content_length_spec.rb b/spec/ruby/library/net/http/httpheader/content_length_spec.rb
new file mode 100644
index 0000000000..e344817e82
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/content_length_spec.rb
@@ -0,0 +1,54 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#content_length" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns nil if no 'Content-Length' header entry is set" do
+ @headers.content_length.should be_nil
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Length' header entry has an invalid format" do
+ @headers["Content-Length"] = "invalid"
+ -> { @headers.content_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+ end
+
+ it "returns the value of the 'Content-Length' header entry as an Integer" do
+ @headers["Content-Length"] = "123"
+ @headers.content_length.should eql(123)
+
+ @headers["Content-Length"] = "123valid"
+ @headers.content_length.should eql(123)
+
+ @headers["Content-Length"] = "valid123"
+ @headers.content_length.should eql(123)
+ end
+end
+
+describe "Net::HTTPHeader#content_length=" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "removes the 'Content-Length' entry if passed false or nil" do
+ @headers["Content-Length"] = "123"
+ @headers.content_length = nil
+ @headers["Content-Length"].should be_nil
+ end
+
+ it "sets the 'Content-Length' entry to the passed value" do
+ @headers.content_length = "123"
+ @headers["Content-Length"].should == "123"
+
+ @headers.content_length = "123valid"
+ @headers["Content-Length"].should == "123"
+ end
+
+ it "sets the 'Content-Length' entry to 0 if the passed value is not valid" do
+ @headers.content_length = "invalid123"
+ @headers["Content-Length"].should == "0"
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/content_range_spec.rb b/spec/ruby/library/net/http/httpheader/content_range_spec.rb
new file mode 100644
index 0000000000..ba75f9a9a1
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/content_range_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#content_range" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns a Range object that represents the 'Content-Range' header entry" do
+ @headers["Content-Range"] = "bytes 0-499/1234"
+ @headers.content_range.should == (0..499)
+
+ @headers["Content-Range"] = "bytes 500-1233/1234"
+ @headers.content_range.should == (500..1233)
+ end
+
+ it "returns nil when there is no 'Content-Range' header entry" do
+ @headers.content_range.should be_nil
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Range' has an invalid format" do
+ @headers["Content-Range"] = "invalid"
+ -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
+
+ @headers["Content-Range"] = "bytes 123-abc"
+ -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
+
+ @headers["Content-Range"] = "bytes abc-123"
+ -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/content_type_spec.rb b/spec/ruby/library/net/http/httpheader/content_type_spec.rb
new file mode 100644
index 0000000000..1f8b4ba326
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/content_type_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/set_content_type'
+
+describe "Net::HTTPHeader#content_type" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns the content type string, as per 'Content-Type' header entry" do
+ @headers["Content-Type"] = "text/html"
+ @headers.content_type.should == "text/html"
+
+ @headers["Content-Type"] = "text/html;charset=utf-8"
+ @headers.content_type.should == "text/html"
+ end
+
+ it "returns nil if the 'Content-Type' header entry does not exist" do
+ @headers.content_type.should be_nil
+ end
+end
+
+describe "Net::HTTPHeader#content_type=" do
+ it_behaves_like :net_httpheader_set_content_type, :content_type=
+end
diff --git a/spec/ruby/library/net/http/httpheader/delete_spec.rb b/spec/ruby/library/net/http/httpheader/delete_spec.rb
new file mode 100644
index 0000000000..603ae198de
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/delete_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#delete when passed key" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "removes the header entry with the passed key" do
+ @headers["My-Header"] = "test"
+ @headers.delete("My-Header")
+
+ @headers["My-Header"].should be_nil
+ @headers.size.should eql(0)
+ end
+
+ it "returns the removed values" do
+ @headers["My-Header"] = "test"
+ @headers.delete("My-Header").should == ["test"]
+ end
+
+ it "is case-insensitive" do
+ @headers["My-Header"] = "test"
+ @headers.delete("my-header")
+
+ @headers["My-Header"].should be_nil
+ @headers.size.should eql(0)
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/each_capitalized_name_spec.rb b/spec/ruby/library/net/http/httpheader/each_capitalized_name_spec.rb
new file mode 100644
index 0000000000..1af2c6939c
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/each_capitalized_name_spec.rb
@@ -0,0 +1,35 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#each_capitalized_name" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ @headers["My-Header"] = "test"
+ @headers.add_field("My-Other-Header", "a")
+ @headers.add_field("My-Other-Header", "b")
+ end
+
+ describe "when passed a block" do
+ it "yields each header key to the passed block (keys capitalized)" do
+ res = []
+ @headers.each_capitalized_name do |key|
+ res << key
+ end
+ res.sort.should == ["My-Header", "My-Other-Header"]
+ end
+ end
+
+ describe "when passed no block" do
+ it "returns an Enumerator" do
+ enumerator = @headers.each_capitalized_name
+ enumerator.should be_an_instance_of(Enumerator)
+
+ res = []
+ enumerator.each do |key|
+ res << key
+ end
+ res.sort.should == ["My-Header", "My-Other-Header"]
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/each_capitalized_spec.rb b/spec/ruby/library/net/http/httpheader/each_capitalized_spec.rb
new file mode 100644
index 0000000000..961a2d051f
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/each_capitalized_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_capitalized'
+
+describe "Net::HTTPHeader#each_capitalized" do
+ it_behaves_like :net_httpheader_each_capitalized, :each_capitalized
+end
diff --git a/spec/ruby/library/net/http/httpheader/each_header_spec.rb b/spec/ruby/library/net/http/httpheader/each_header_spec.rb
new file mode 100644
index 0000000000..19634a001b
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/each_header_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_header'
+
+describe "Net::HTTPHeader#each_header" do
+ it_behaves_like :net_httpheader_each_header, :each_header
+end
diff --git a/spec/ruby/library/net/http/httpheader/each_key_spec.rb b/spec/ruby/library/net/http/httpheader/each_key_spec.rb
new file mode 100644
index 0000000000..ebb17d2eac
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/each_key_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_name'
+
+describe "Net::HTTPHeader#each_key" do
+ it_behaves_like :net_httpheader_each_name, :each_key
+end
diff --git a/spec/ruby/library/net/http/httpheader/each_name_spec.rb b/spec/ruby/library/net/http/httpheader/each_name_spec.rb
new file mode 100644
index 0000000000..f4533ebcfb
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/each_name_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_name'
+
+describe "Net::HTTPHeader#each_name" do
+ it_behaves_like :net_httpheader_each_name, :each_name
+end
diff --git a/spec/ruby/library/net/http/httpheader/each_spec.rb b/spec/ruby/library/net/http/httpheader/each_spec.rb
new file mode 100644
index 0000000000..7ba8434f75
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/each_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_header'
+
+describe "Net::HTTPHeader#each" do
+ it_behaves_like :net_httpheader_each_header, :each
+end
diff --git a/spec/ruby/library/net/http/httpheader/each_value_spec.rb b/spec/ruby/library/net/http/httpheader/each_value_spec.rb
new file mode 100644
index 0000000000..3224de7703
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/each_value_spec.rb
@@ -0,0 +1,35 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#each_value" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ @headers["My-Header"] = "test"
+ @headers.add_field("My-Other-Header", "a")
+ @headers.add_field("My-Other-Header", "b")
+ end
+
+ describe "when passed a block" do
+ it "yields each header entry's joined values" do
+ res = []
+ @headers.each_value do |value|
+ res << value
+ end
+ res.sort.should == ["a, b", "test"]
+ end
+ end
+
+ describe "when passed no block" do
+ it "returns an Enumerator" do
+ enumerator = @headers.each_value
+ enumerator.should be_an_instance_of(Enumerator)
+
+ res = []
+ enumerator.each do |key|
+ res << key
+ end
+ res.sort.should == ["a, b", "test"]
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/element_reference_spec.rb b/spec/ruby/library/net/http/httpheader/element_reference_spec.rb
new file mode 100644
index 0000000000..4a35e20d20
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/element_reference_spec.rb
@@ -0,0 +1,39 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#[] when passed key" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns the value of the header entry with the passed key" do
+ @headers["My-Header"] = "test"
+ @headers["My-Header"].should == "test"
+ @headers["My-Other-Header"] = "another test"
+ @headers["My-Other-Header"].should == "another test"
+ end
+
+ it "is case-insensitive" do
+ @headers["My-Header"] = "test"
+
+ @headers['My-Header'].should == "test"
+ @headers['my-Header'].should == "test"
+ @headers['My-header'].should == "test"
+ @headers['my-header'].should == "test"
+ @headers['MY-HEADER'].should == "test"
+ end
+
+ it "returns multi-element values joined together" do
+ @headers["My-Header"] = "test"
+ @headers.add_field("My-Header", "another test")
+ @headers.add_field("My-Header", "and one more")
+
+ @headers["My-Header"].should == "test, another test, and one more"
+ end
+
+ it "returns nil for non-existing entries" do
+ @headers["My-Header"].should be_nil
+ @headers["My-Other-Header"].should be_nil
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/element_set_spec.rb b/spec/ruby/library/net/http/httpheader/element_set_spec.rb
new file mode 100644
index 0000000000..e9ad64fafc
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/element_set_spec.rb
@@ -0,0 +1,41 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#[]= when passed key, value" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "sets the header entry with the passed key to the passed value" do
+ @headers["My-Header"] = "test"
+ @headers["My-Header"].should == "test"
+
+ @headers["My-Header"] = "overwritten"
+ @headers["My-Header"].should == "overwritten"
+
+ @headers["My-Other-Header"] = "another test"
+ @headers["My-Other-Header"].should == "another test"
+ end
+
+ it "is case-insensitive" do
+ @headers['My-Header'] = "test"
+ @headers['my-Header'] = "another test"
+ @headers['My-header'] = "and one more test"
+ @headers['my-header'] = "and another one"
+ @headers['MY-HEADER'] = "last one"
+
+ @headers["My-Header"].should == "last one"
+ @headers.size.should eql(1)
+ end
+
+ it "removes the header entry with the passed key when the value is false or nil" do
+ @headers['My-Header'] = "test"
+ @headers['My-Header'] = nil
+ @headers['My-Header'].should be_nil
+
+ @headers['My-Header'] = "test"
+ @headers['My-Header'] = false
+ @headers['My-Header'].should be_nil
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/fetch_spec.rb b/spec/ruby/library/net/http/httpheader/fetch_spec.rb
new file mode 100644
index 0000000000..ea15679acb
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/fetch_spec.rb
@@ -0,0 +1,68 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#fetch" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ describe "when passed key" do
+ it "returns the header entry for the passed key" do
+ @headers["My-Header"] = "test"
+ @headers.fetch("My-Header").should == "test"
+
+ @headers.add_field("My-Other-Header", "a")
+ @headers.add_field("My-Other-Header", "b")
+ @headers.add_field("My-Other-Header", "c")
+ @headers.fetch("My-Other-Header").should == "a, b, c"
+ end
+
+ it "is case-insensitive" do
+ @headers["My-Header"] = "test"
+ @headers.fetch("my-header").should == "test"
+ @headers.fetch("MY-HEADER").should == "test"
+ end
+
+ it "returns nil when there is no entry for the passed key" do
+ -> { @headers.fetch("my-header") }.should raise_error(IndexError)
+ end
+ end
+
+ describe "when passed key, default" do
+ it "returns the header entry for the passed key" do
+ @headers["My-Header"] = "test"
+ @headers.fetch("My-Header", "bla").should == "test"
+
+ @headers.add_field("My-Other-Header", "a")
+ @headers.add_field("My-Other-Header", "b")
+ @headers.add_field("My-Other-Header", "c")
+ @headers.fetch("My-Other-Header", "bla").should == "a, b, c"
+ end
+
+ # TODO: This raises a NoMethodError: undefined method `join' for "bla":String
+ it "returns the default value when there is no entry for the passed key" do
+ @headers.fetch("My-Header", "bla").should == "bla"
+ end
+ end
+
+ describe "when passed key and block" do
+ it "returns the header entry for the passed key" do
+ @headers["My-Header"] = "test"
+ @headers.fetch("My-Header") {}.should == "test"
+
+ @headers.add_field("My-Other-Header", "a")
+ @headers.add_field("My-Other-Header", "b")
+ @headers.add_field("My-Other-Header", "c")
+ -> {
+ @result = @headers.fetch("My-Other-Header", "bla") {}
+ }.should complain(/block supersedes default value argument/)
+ @result.should == "a, b, c"
+ end
+
+ # TODO: This raises a NoMethodError: undefined method `join' for "redaeh-ym":String
+ it "yieldsand returns the block's return value when there is no entry for the passed key" do
+ @headers.fetch("My-Header") { |key| key.reverse }.should == "redaeh-ym"
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/fixtures/classes.rb b/spec/ruby/library/net/http/httpheader/fixtures/classes.rb
index b5ec6abd75..b5ec6abd75 100644
--- a/spec/ruby/library/net-http/httpheader/fixtures/classes.rb
+++ b/spec/ruby/library/net/http/httpheader/fixtures/classes.rb
diff --git a/spec/ruby/library/net/http/httpheader/form_data_spec.rb b/spec/ruby/library/net/http/httpheader/form_data_spec.rb
new file mode 100644
index 0000000000..9b29a03159
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/form_data_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/set_form_data'
+
+describe "Net::HTTPHeader#form_data=" do
+ it_behaves_like :net_httpheader_set_form_data, :form_data=
+end
diff --git a/spec/ruby/library/net/http/httpheader/get_fields_spec.rb b/spec/ruby/library/net/http/httpheader/get_fields_spec.rb
new file mode 100644
index 0000000000..1b623bf2a3
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/get_fields_spec.rb
@@ -0,0 +1,39 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#get_fields when passed key" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns an Array containing the values of the header entry with the passed key" do
+ @headers["My-Header"] = "a"
+ @headers.get_fields("My-Header").should == ["a"]
+
+ @headers.add_field("My-Header", "b")
+ @headers.get_fields("My-Header").should == ["a", "b"]
+ end
+
+ it "returns a copy of the header entry values" do
+ @headers["My-Header"] = "a"
+
+ @headers.get_fields("My-Header").clear
+ @headers.get_fields("My-Header").should == ["a"]
+
+ @headers.get_fields("My-Header") << "b"
+ @headers.get_fields("My-Header").should == ["a"]
+ end
+
+ it "returns nil for non-existing header entries" do
+ @headers.get_fields("My-Header").should be_nil
+ @headers.get_fields("My-Other-header").should be_nil
+ end
+
+ it "is case-insensitive" do
+ @headers["My-Header"] = "test"
+ @headers.get_fields("My-Header").should == ["test"]
+ @headers.get_fields("my-header").should == ["test"]
+ @headers.get_fields("MY-HEADER").should == ["test"]
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/initialize_http_header_spec.rb b/spec/ruby/library/net/http/httpheader/initialize_http_header_spec.rb
new file mode 100644
index 0000000000..efc5e7d0b2
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/initialize_http_header_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#initialize_http_header when passed Hash" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.allocate
+ end
+
+ it "initializes the HTTP Header using the passed Hash" do
+ @headers.initialize_http_header("My-Header" => "test", "My-Other-Header" => "another test")
+ @headers["My-Header"].should == "test"
+ @headers["My-Other-Header"].should == "another test"
+ end
+
+ it "complains about duplicate keys when in verbose mode" do
+ -> do
+ @headers.initialize_http_header("My-Header" => "test", "my-header" => "another test")
+ end.should complain(/duplicated HTTP header/, verbose: true)
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/key_spec.rb b/spec/ruby/library/net/http/httpheader/key_spec.rb
new file mode 100644
index 0000000000..9099024229
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/key_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#key? when passed key" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns true if the header entry with the passed key exists" do
+ @headers.key?("My-Header").should be_false
+ @headers["My-Header"] = "test"
+ @headers.key?("My-Header").should be_true
+ end
+
+ it "is case-insensitive" do
+ @headers["My-Header"] = "test"
+ @headers.key?("my-header").should be_true
+ @headers.key?("MY-HEADER").should be_true
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/length_spec.rb b/spec/ruby/library/net/http/httpheader/length_spec.rb
new file mode 100644
index 0000000000..0d1da149f4
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/length_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/size'
+
+describe "Net::HTTPHeader#length" do
+ it_behaves_like :net_httpheader_size, :length
+end
diff --git a/spec/ruby/library/net/http/httpheader/main_type_spec.rb b/spec/ruby/library/net/http/httpheader/main_type_spec.rb
new file mode 100644
index 0000000000..3e18de6b5b
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/main_type_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#main_type" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns the 'main-content-type', as per 'Content-Type' header entry" do
+ @headers["Content-Type"] = "text/html"
+ @headers.main_type.should == "text"
+
+ @headers["Content-Type"] = "application/pdf"
+ @headers.main_type.should == "application"
+
+ @headers["Content-Type"] = "text/html;charset=utf-8"
+ @headers.main_type.should == "text"
+ end
+
+ it "returns nil if the 'Content-Type' header entry does not exist" do
+ @headers.main_type.should be_nil
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/proxy_basic_auth_spec.rb b/spec/ruby/library/net/http/httpheader/proxy_basic_auth_spec.rb
new file mode 100644
index 0000000000..8b576ee164
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/proxy_basic_auth_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#proxy_basic_auth when passed account, password" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "sets the 'Proxy-Authorization' Header entry for basic authorization" do
+ @headers.proxy_basic_auth("rubyspec", "rocks")
+ @headers["Proxy-Authorization"].should == "Basic cnVieXNwZWM6cm9ja3M="
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/range_length_spec.rb b/spec/ruby/library/net/http/httpheader/range_length_spec.rb
new file mode 100644
index 0000000000..b8fce4f690
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/range_length_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#range_length" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns the length of the Range represented by the 'Content-Range' header entry" do
+ @headers["Content-Range"] = "bytes 0-499/1234"
+ @headers.range_length.should eql(500)
+
+ @headers["Content-Range"] = "bytes 500-1233/1234"
+ @headers.range_length.should eql(734)
+ end
+
+ it "returns nil when there is no 'Content-Range' header entry" do
+ @headers.range_length.should be_nil
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Range' has an invalid format" do
+ @headers["Content-Range"] = "invalid"
+ -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+
+ @headers["Content-Range"] = "bytes 123-abc"
+ -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+
+ @headers["Content-Range"] = "bytes abc-123"
+ -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/range_spec.rb b/spec/ruby/library/net/http/httpheader/range_spec.rb
new file mode 100644
index 0000000000..005177f6be
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/range_spec.rb
@@ -0,0 +1,48 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/set_range'
+
+describe "Net::HTTPHeader#range" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns a Range object that represents the 'Range' header entry" do
+ @headers["Range"] = "bytes=0-499"
+ @headers.range.should == [0..499]
+
+ @headers["Range"] = "bytes=500-1233"
+ @headers.range.should == [500..1233]
+
+ @headers["Range"] = "bytes=10-"
+ @headers.range.should == [10..-1]
+
+ @headers["Range"] = "bytes=-10"
+ @headers.range.should == [-10..-1]
+ end
+
+ it "returns nil when there is no 'Range' header entry" do
+ @headers.range.should be_nil
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when the 'Range' has an invalid format" do
+ @headers["Range"] = "invalid"
+ -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+
+ @headers["Range"] = "bytes 123-abc"
+ -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+
+ @headers["Range"] = "bytes abc-123"
+ -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when the 'Range' was not specified" do
+ @headers["Range"] = "bytes=-"
+ -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ end
+end
+
+describe "Net::HTTPHeader#range=" do
+ it_behaves_like :net_httpheader_set_range, :range=
+end
diff --git a/spec/ruby/library/net/http/httpheader/set_content_type_spec.rb b/spec/ruby/library/net/http/httpheader/set_content_type_spec.rb
new file mode 100644
index 0000000000..125f7a7e0d
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/set_content_type_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/set_content_type'
+
+describe "Net::HTTPHeader#set_content_type" do
+ it_behaves_like :net_httpheader_set_content_type, :set_content_type
+end
diff --git a/spec/ruby/library/net/http/httpheader/set_form_data_spec.rb b/spec/ruby/library/net/http/httpheader/set_form_data_spec.rb
new file mode 100644
index 0000000000..14c66ae01c
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/set_form_data_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/set_form_data'
+
+describe "Net::HTTPHeader#set_form_data" do
+ it_behaves_like :net_httpheader_set_form_data, :set_form_data
+end
diff --git a/spec/ruby/library/net/http/httpheader/set_range_spec.rb b/spec/ruby/library/net/http/httpheader/set_range_spec.rb
new file mode 100644
index 0000000000..85b9c50422
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/set_range_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/set_range'
+
+describe "Net::HTTPHeader#set_range" do
+ it_behaves_like :net_httpheader_set_range, :set_range
+end
diff --git a/spec/ruby/library/net-http/httpheader/shared/each_capitalized.rb b/spec/ruby/library/net/http/httpheader/shared/each_capitalized.rb
index 3bac409876..3bac409876 100644
--- a/spec/ruby/library/net-http/httpheader/shared/each_capitalized.rb
+++ b/spec/ruby/library/net/http/httpheader/shared/each_capitalized.rb
diff --git a/spec/ruby/library/net-http/httpheader/shared/each_header.rb b/spec/ruby/library/net/http/httpheader/shared/each_header.rb
index 6bf3a6ddfe..6bf3a6ddfe 100644
--- a/spec/ruby/library/net-http/httpheader/shared/each_header.rb
+++ b/spec/ruby/library/net/http/httpheader/shared/each_header.rb
diff --git a/spec/ruby/library/net-http/httpheader/shared/each_name.rb b/spec/ruby/library/net/http/httpheader/shared/each_name.rb
index efc6a09dfd..efc6a09dfd 100644
--- a/spec/ruby/library/net-http/httpheader/shared/each_name.rb
+++ b/spec/ruby/library/net/http/httpheader/shared/each_name.rb
diff --git a/spec/ruby/library/net-http/httpheader/shared/set_content_type.rb b/spec/ruby/library/net/http/httpheader/shared/set_content_type.rb
index b7359bdca6..b7359bdca6 100644
--- a/spec/ruby/library/net-http/httpheader/shared/set_content_type.rb
+++ b/spec/ruby/library/net/http/httpheader/shared/set_content_type.rb
diff --git a/spec/ruby/library/net-http/httpheader/shared/set_form_data.rb b/spec/ruby/library/net/http/httpheader/shared/set_form_data.rb
index db20b18803..db20b18803 100644
--- a/spec/ruby/library/net-http/httpheader/shared/set_form_data.rb
+++ b/spec/ruby/library/net/http/httpheader/shared/set_form_data.rb
diff --git a/spec/ruby/library/net-http/httpheader/shared/set_range.rb b/spec/ruby/library/net/http/httpheader/shared/set_range.rb
index 87f51d46f3..87f51d46f3 100644
--- a/spec/ruby/library/net-http/httpheader/shared/set_range.rb
+++ b/spec/ruby/library/net/http/httpheader/shared/set_range.rb
diff --git a/spec/ruby/library/net-http/httpheader/shared/size.rb b/spec/ruby/library/net/http/httpheader/shared/size.rb
index e2b1e4c22b..e2b1e4c22b 100644
--- a/spec/ruby/library/net-http/httpheader/shared/size.rb
+++ b/spec/ruby/library/net/http/httpheader/shared/size.rb
diff --git a/spec/ruby/library/net/http/httpheader/size_spec.rb b/spec/ruby/library/net/http/httpheader/size_spec.rb
new file mode 100644
index 0000000000..a7d78f96e0
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/size_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/size'
+
+describe "Net::HTTPHeader#size" do
+ it_behaves_like :net_httpheader_size, :size
+end
diff --git a/spec/ruby/library/net/http/httpheader/sub_type_spec.rb b/spec/ruby/library/net/http/httpheader/sub_type_spec.rb
new file mode 100644
index 0000000000..3c73ca0027
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/sub_type_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#sub_type" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns the 'sub-content-type', as per 'Content-Type' header entry" do
+ @headers["Content-Type"] = "text/html"
+ @headers.sub_type.should == "html"
+
+ @headers["Content-Type"] = "application/pdf"
+ @headers.sub_type.should == "pdf"
+
+ @headers["Content-Type"] = "text/html;charset=utf-8"
+ @headers.sub_type.should == "html"
+ end
+
+ it "returns nil if no 'sub-content-type' is set" do
+ @headers["Content-Type"] = "text"
+ @headers.sub_type.should be_nil
+
+ @headers["Content-Type"] = "text;charset=utf-8"
+ @headers.sub_type.should be_nil
+ end
+
+ it "returns nil if the 'Content-Type' header entry does not exist" do
+ @headers.sub_type.should be_nil
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/to_hash_spec.rb b/spec/ruby/library/net/http/httpheader/to_hash_spec.rb
new file mode 100644
index 0000000000..8c1d36c30a
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/to_hash_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#to_hash" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns a Hash representing all Header entries (keys in lower case, values as arrays)" do
+ @headers.to_hash.should == {}
+
+ @headers["My-Header"] = "test"
+ @headers.to_hash.should == { "my-header" => ["test"] }
+
+ @headers.add_field("My-Header", "another test")
+ @headers.to_hash.should == { "my-header" => ["test", "another test"] }
+ end
+
+ it "does not allow modifying the headers from the returned hash" do
+ @headers.to_hash["my-header"] = ["test"]
+ @headers.to_hash.should == {}
+ @headers.key?("my-header").should be_false
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/type_params_spec.rb b/spec/ruby/library/net/http/httpheader/type_params_spec.rb
new file mode 100644
index 0000000000..e77be7ea85
--- /dev/null
+++ b/spec/ruby/library/net/http/httpheader/type_params_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#type_params" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns additional 'Content-Type' information as a Hash" do
+ @headers["Content-Type"] = "text/html;charset=utf-8"
+ @headers.type_params.should == {"charset" => "utf-8"}
+
+ @headers["Content-Type"] = "text/html; charset=utf-8; rubyspec=rocks"
+ @headers.type_params.should == {"charset" => "utf-8", "rubyspec" => "rocks"}
+ end
+
+ it "returns an empty Hash when no additional 'Content-Type' information is set" do
+ @headers.type_params.should == {}
+
+ @headers["Content-Type"] = "text/html"
+ @headers.type_params.should == {}
+ end
+end
diff --git a/spec/ruby/library/net/http/httprequest/initialize_spec.rb b/spec/ruby/library/net/http/httprequest/initialize_spec.rb
new file mode 100644
index 0000000000..88e9fb1c77
--- /dev/null
+++ b/spec/ruby/library/net/http/httprequest/initialize_spec.rb
@@ -0,0 +1,45 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+module NetHTTPRequestSpecs
+ class TestRequest < Net::HTTPRequest
+ METHOD = "TEST"
+ REQUEST_HAS_BODY = false
+ RESPONSE_HAS_BODY = true
+ end
+end
+
+describe "Net::HTTPRequest#initialize" do
+ before :each do
+ @req = NetHTTPRequestSpecs::TestRequest.allocate
+ end
+
+ it "uses the METHOD constants to set the request method" do
+ @req.send(:initialize, "/some/path")
+ @req.method.should == "TEST"
+ end
+
+ it "uses the REQUEST_HAS_BODY to set whether the Request has a body or not" do
+ @req.send(:initialize, "/some/path")
+ @req.request_body_permitted?.should be_false
+ end
+
+ it "uses the RESPONSE_HAS_BODY to set whether the Response can have a body or not" do
+ @req.send(:initialize, "/some/path")
+ @req.response_body_permitted?.should be_true
+ end
+
+ describe "when passed path" do
+ it "sets self's path to the passed path" do
+ @req.send(:initialize, "/some/path")
+ @req.path.should == "/some/path"
+ end
+ end
+
+ describe "when passed path, headers" do
+ it "uses the passed headers Hash to initialize self's header entries" do
+ @req.send(:initialize, "/some/path", "Content-Type" => "text/html")
+ @req["Content-Type"].should == "text/html"
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/body_permitted_spec.rb b/spec/ruby/library/net/http/httpresponse/body_permitted_spec.rb
new file mode 100644
index 0000000000..8ade46689f
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/body_permitted_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse.body_permitted?" do
+ it "returns true if this response type can have a response body" do
+ Net::HTTPUnknownResponse.should.body_permitted?
+ Net::HTTPInformation.should_not.body_permitted?
+ Net::HTTPSuccess.should.body_permitted?
+ Net::HTTPRedirection.should.body_permitted?
+ Net::HTTPClientError.should.body_permitted?
+ Net::HTTPServerError.should.body_permitted?
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/body_spec.rb b/spec/ruby/library/net/http/httpresponse/body_spec.rb
new file mode 100644
index 0000000000..79569441f1
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/body_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'shared/body'
+
+describe "Net::HTTPResponse#body" do
+ it_behaves_like :net_httpresponse_body, :body
+end
diff --git a/spec/ruby/library/net/http/httpresponse/code_spec.rb b/spec/ruby/library/net/http/httpresponse/code_spec.rb
new file mode 100644
index 0000000000..114277cb43
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/code_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#code" do
+ it "returns the result code string" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.code.should == "???"
+
+ res = Net::HTTPInformation.new("1.0", "1xx", "test response")
+ res.code.should == "1xx"
+
+ res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
+ res.code.should == "2xx"
+
+ res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
+ res.code.should == "3xx"
+
+ res = Net::HTTPClientError.new("1.0", "4xx", "test response")
+ res.code.should == "4xx"
+
+ res = Net::HTTPServerError.new("1.0", "5xx", "test response")
+ res.code.should == "5xx"
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/code_type_spec.rb b/spec/ruby/library/net/http/httpresponse/code_type_spec.rb
new file mode 100644
index 0000000000..fa2d572e9a
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/code_type_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#code_type" do
+ it "returns self's class" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.code_type.should == Net::HTTPUnknownResponse
+
+ res = Net::HTTPInformation.new("1.0", "1xx", "test response")
+ res.code_type.should == Net::HTTPInformation
+
+ res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
+ res.code_type.should == Net::HTTPSuccess
+
+ res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
+ res.code_type.should == Net::HTTPRedirection
+
+ res = Net::HTTPClientError.new("1.0", "4xx", "test response")
+ res.code_type.should == Net::HTTPClientError
+
+ res = Net::HTTPServerError.new("1.0", "5xx", "test response")
+ res.code_type.should == Net::HTTPServerError
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/entity_spec.rb b/spec/ruby/library/net/http/httpresponse/entity_spec.rb
new file mode 100644
index 0000000000..f1639042c1
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/entity_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require_relative 'shared/body'
+
+describe "Net::HTTPResponse#entity" do
+ it_behaves_like :net_httpresponse_body, :entity
+end
diff --git a/spec/ruby/library/net/http/httpresponse/error_spec.rb b/spec/ruby/library/net/http/httpresponse/error_spec.rb
new file mode 100644
index 0000000000..89f4a47f60
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/error_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#error!" do
+ it "raises self's class 'EXCEPTION_TYPE' Exception" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ -> { res.error! }.should raise_error(Net::HTTPError)
+
+ res = Net::HTTPInformation.new("1.0", "1xx", "test response")
+ -> { res.error! }.should raise_error(Net::HTTPError)
+
+ res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
+ -> { res.error! }.should raise_error(Net::HTTPError)
+
+ res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
+ -> { res.error! }.should raise_error(Net::HTTPRetriableError)
+
+ res = Net::HTTPClientError.new("1.0", "4xx", "test response")
+ -> { res.error! }.should raise_error(Net::HTTPClientException)
+
+ res = Net::HTTPServerError.new("1.0", "5xx", "test response")
+ -> { res.error! }.should raise_error(Net::HTTPFatalError)
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/error_type_spec.rb b/spec/ruby/library/net/http/httpresponse/error_type_spec.rb
new file mode 100644
index 0000000000..8885b7706b
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/error_type_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#error_type" do
+ it "returns self's class 'EXCEPTION_TYPE' constant" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.error_type.should == Net::HTTPError
+
+ res = Net::HTTPInformation.new("1.0", "1xx", "test response")
+ res.error_type.should == Net::HTTPError
+
+ res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
+ res.error_type.should == Net::HTTPError
+
+ res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
+ res.error_type.should == Net::HTTPRetriableError
+
+ res = Net::HTTPClientError.new("1.0", "4xx", "test response")
+ res.error_type.should == Net::HTTPClientException
+
+ res = Net::HTTPServerError.new("1.0", "5xx", "test response")
+ res.error_type.should == Net::HTTPFatalError
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/exception_type_spec.rb b/spec/ruby/library/net/http/httpresponse/exception_type_spec.rb
new file mode 100644
index 0000000000..0c9c11291f
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/exception_type_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse.exception_type" do
+ it "returns self's 'EXCEPTION_TYPE' constant" do
+ Net::HTTPUnknownResponse.exception_type.should == Net::HTTPError
+ Net::HTTPInformation.exception_type.should == Net::HTTPError
+ Net::HTTPSuccess.exception_type.should == Net::HTTPError
+ Net::HTTPRedirection.exception_type.should == Net::HTTPRetriableError
+ Net::HTTPClientError.exception_type.should == Net::HTTPClientException
+ Net::HTTPServerError.exception_type.should == Net::HTTPFatalError
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/header_spec.rb b/spec/ruby/library/net/http/httpresponse/header_spec.rb
new file mode 100644
index 0000000000..a9615feda8
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/header_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#header" do
+ it "returns self" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.response.should equal(res)
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/http_version_spec.rb b/spec/ruby/library/net/http/httpresponse/http_version_spec.rb
new file mode 100644
index 0000000000..db85696d77
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/http_version_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#http_version" do
+ it "returns self's http version" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.http_version.should == "1.0"
+
+ res = Net::HTTPUnknownResponse.new("1.1", "???", "test response")
+ res.http_version.should == "1.1"
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/initialize_spec.rb b/spec/ruby/library/net/http/httpresponse/initialize_spec.rb
new file mode 100644
index 0000000000..eb77e2e277
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/initialize_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#initialize when passed http_version, response_code, response_message" do
+ it "sets self http_version, response_code and response_message to the passed values" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.http_version.should == "1.0"
+ res.code.should == "???"
+ res.message.should == "test response"
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/inspect_spec.rb b/spec/ruby/library/net/http/httpresponse/inspect_spec.rb
new file mode 100644
index 0000000000..1e1a2c7cc7
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/inspect_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require "stringio"
+
+describe "Net::HTTPResponse#inspect" do
+ it "returns a String representation of self" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=false>"
+
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ socket = Net::BufferedIO.new(StringIO.new("test body"))
+ res.reading_body(socket, true) {}
+ res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=true>"
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/message_spec.rb b/spec/ruby/library/net/http/httpresponse/message_spec.rb
new file mode 100644
index 0000000000..ae8e3678a1
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/message_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#message" do
+ it "returns self's response message" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.message.should == "test response"
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/msg_spec.rb b/spec/ruby/library/net/http/httpresponse/msg_spec.rb
new file mode 100644
index 0000000000..0e5e7eb4aa
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/msg_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#msg" do
+ it "returns self's response message" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.message.should == "test response"
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/read_body_spec.rb b/spec/ruby/library/net/http/httpresponse/read_body_spec.rb
new file mode 100644
index 0000000000..ec9b42f919
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/read_body_spec.rb
@@ -0,0 +1,86 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require 'stringio'
+
+describe "Net::HTTPResponse#read_body" do
+ before :each do
+ @res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ @socket = Net::BufferedIO.new(StringIO.new("test body"))
+ end
+
+ describe "when passed no arguments" do
+ it "returns the read body" do
+ @res.reading_body(@socket, true) do
+ @res.read_body.should == "test body"
+ end
+ end
+
+ it "returns the previously read body if called a second time" do
+ @res.reading_body(@socket, true) do
+ @res.read_body.should equal(@res.read_body)
+ end
+ end
+ end
+
+ describe "when passed a buffer" do
+ it "reads the body to the passed buffer" do
+ @res.reading_body(@socket, true) do
+ buffer = ""
+ @res.read_body(buffer)
+ buffer.should == "test body"
+ end
+ end
+
+ it "returns the passed buffer" do
+ @res.reading_body(@socket, true) do
+ buffer = ""
+ @res.read_body(buffer).should equal(buffer)
+ end
+ end
+
+ it "raises an IOError if called a second time" do
+ @res.reading_body(@socket, true) do
+ @res.read_body("")
+ -> { @res.read_body("") }.should raise_error(IOError)
+ end
+ end
+ end
+
+ describe "when passed a block" do
+ it "reads the body and yields it to the passed block (in chunks)" do
+ @res.reading_body(@socket, true) do
+ yielded = false
+
+ buffer = ""
+ @res.read_body do |body|
+ yielded = true
+ buffer << body
+ end
+
+ yielded.should be_true
+ buffer.should == "test body"
+ end
+ end
+
+ it "returns the ReadAdapter" do
+ @res.reading_body(@socket, true) do
+ @res.read_body { nil }.should be_kind_of(Net::ReadAdapter)
+ end
+ end
+
+ it "raises an IOError if called a second time" do
+ @res.reading_body(@socket, true) do
+ @res.read_body {}
+ -> { @res.read_body {} }.should raise_error(IOError)
+ end
+ end
+ end
+
+ describe "when passed buffer and block" do
+ it "raises an ArgumentError" do
+ @res.reading_body(@socket, true) do
+ -> { @res.read_body("") {} }.should raise_error(ArgumentError)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/read_header_spec.rb b/spec/ruby/library/net/http/httpresponse/read_header_spec.rb
new file mode 100644
index 0000000000..6af8c6bd6a
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/read_header_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#read_header" do
+ it "returns self" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.response.should equal(res)
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/read_new_spec.rb b/spec/ruby/library/net/http/httpresponse/read_new_spec.rb
new file mode 100644
index 0000000000..dc2cdc9621
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/read_new_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require 'stringio'
+
+describe "Net::HTTPResponse.read_new" do
+ it "creates a HTTPResponse object based on the response read from the passed socket" do
+ socket = Net::BufferedIO.new(StringIO.new(<<EOS))
+HTTP/1.1 200 OK
+Content-Type: text/html; charset=utf-8
+
+test-body
+EOS
+ response = Net::HTTPResponse.read_new(socket)
+
+ response.should be_kind_of(Net::HTTPOK)
+ response.code.should == "200"
+ response["Content-Type"].should == "text/html; charset=utf-8"
+
+ response.reading_body(socket, true) do
+ response.body.should == "test-body\n"
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/reading_body_spec.rb b/spec/ruby/library/net/http/httpresponse/reading_body_spec.rb
new file mode 100644
index 0000000000..ebdab891e1
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/reading_body_spec.rb
@@ -0,0 +1,58 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+require "stringio"
+
+describe "Net::HTTPResponse#reading_body" do
+ before :each do
+ @res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ @socket = Net::BufferedIO.new(StringIO.new("test body"))
+ end
+
+ describe "when body_allowed is true" do
+ it "reads and returns the response body for self from the passed socket" do
+ @res.reading_body(@socket, true) {}.should == "test body"
+ @res.body.should == "test body"
+ end
+
+ it "yields the passed block before reading the body" do
+ yielded = false
+
+ @res.reading_body(@socket, true) do
+ @res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=false>"
+ yielded = true
+ end
+
+ yielded.should be_true
+ end
+
+ describe "but the response type is not allowed to have a body" do
+ before :each do
+ @res = Net::HTTPInformation.new("1.0", "???", "test response")
+ end
+
+ it "returns nil" do
+ @res.reading_body(@socket, false) {}.should be_nil
+ @res.body.should be_nil
+ end
+
+ it "yields the passed block" do
+ yielded = false
+ @res.reading_body(@socket, true) { yielded = true }
+ yielded.should be_true
+ end
+ end
+ end
+
+ describe "when body_allowed is false" do
+ it "returns nil" do
+ @res.reading_body(@socket, false) {}.should be_nil
+ @res.body.should be_nil
+ end
+
+ it "yields the passed block" do
+ yielded = false
+ @res.reading_body(@socket, true) { yielded = true }
+ yielded.should be_true
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/response_spec.rb b/spec/ruby/library/net/http/httpresponse/response_spec.rb
new file mode 100644
index 0000000000..f6035f3695
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/response_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#response" do
+ it "returns self" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.response.should equal(res)
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/shared/body.rb b/spec/ruby/library/net/http/httpresponse/shared/body.rb
index 618e3936fb..618e3936fb 100644
--- a/spec/ruby/library/net-http/httpresponse/shared/body.rb
+++ b/spec/ruby/library/net/http/httpresponse/shared/body.rb
diff --git a/spec/ruby/library/net/http/httpresponse/value_spec.rb b/spec/ruby/library/net/http/httpresponse/value_spec.rb
new file mode 100644
index 0000000000..5cd58316ef
--- /dev/null
+++ b/spec/ruby/library/net/http/httpresponse/value_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#value" do
+ it "raises an HTTP error for non 2xx HTTP Responses" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ -> { res.value }.should raise_error(Net::HTTPError)
+
+ res = Net::HTTPInformation.new("1.0", "1xx", "test response")
+ -> { res.value }.should raise_error(Net::HTTPError)
+
+ res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
+ -> { res.value }.should_not raise_error(Net::HTTPError)
+
+ res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
+ -> { res.value }.should raise_error(Net::HTTPRetriableError)
+
+ res = Net::HTTPClientError.new("1.0", "4xx", "test response")
+ -> { res.value }.should raise_error(Net::HTTPClientException)
+
+ res = Net::HTTPServerError.new("1.0", "5xx", "test response")
+ -> { res.value }.should raise_error(Net::HTTPFatalError)
+ end
+end
diff --git a/spec/ruby/library/objectspace/dump_all_spec.rb b/spec/ruby/library/objectspace/dump_all_spec.rb
deleted file mode 100644
index e9b449a905..0000000000
--- a/spec/ruby/library/objectspace/dump_all_spec.rb
+++ /dev/null
@@ -1,112 +0,0 @@
-require_relative '../../spec_helper'
-require 'objspace'
-
-describe "ObjectSpace.dump_all" do
- it "dumps Ruby heap to string when passed output: :string" do
- stdout = ruby_exe(<<~RUBY, options: "-robjspace")
- string = "abc"
- dump = ObjectSpace.dump_all(output: :string)
- puts dump.class
- puts dump.include?('"value":"abc"')
- RUBY
-
- stdout.should == "String\ntrue\n"
- end
-
- it "dumps Ruby heap to a temporary file when passed output: :file" do
- stdout = ruby_exe(<<~RUBY, options: "-robjspace")
- string = "abc"
- file = ObjectSpace.dump_all(output: :file)
-
- begin
- file.flush
- file.rewind
- content = file.read
-
- puts file.class
- puts content.include?('"value":"abc"')
- ensure
- file.close
- File.unlink file.path
- end
- RUBY
-
- stdout.should == "File\ntrue\n"
- end
-
- it "dumps Ruby heap to a temporary file when :output not specified" do
- stdout = ruby_exe(<<~RUBY, options: "-robjspace")
- string = "abc"
- file = ObjectSpace.dump_all
-
- begin
- file.flush
- file.rewind
- content = file.read
-
- puts file.class
- puts content.include?('"value":"abc"')
- ensure
- file.close
- File.unlink file.path
- end
- RUBY
-
- stdout.should == "File\ntrue\n"
- end
-
- it "dumps Ruby heap to a temporary file when passed output: :nil" do
- stdout = ruby_exe(<<~RUBY, options: "-robjspace")
- string = "abc"
- file = ObjectSpace.dump_all(output: nil)
-
- begin
- file.flush
- file.rewind
- content = file.read
-
- puts file.class
- puts content.include?('"value":"abc"')
- ensure
- file.close
- File.unlink file.path
- end
- RUBY
-
- stdout.should == "File\ntrue\n"
- end
-
- it "dumps Ruby heap to stdout when passed output: :stdout" do
- stdout = ruby_exe(<<~RUBY, options: "-robjspace")
- string = "abc"
- ObjectSpace.dump_all(output: :stdout)
- RUBY
-
- stdout.should include('"value":"abc"')
- end
-
- it "dumps Ruby heap to provided IO when passed output: IO" do
- stdout = ruby_exe(<<~RUBY, options: "-robjspace -rtempfile")
- string = "abc"
- io = Tempfile.create("object_space_dump_all")
-
- begin
- result = ObjectSpace.dump_all(output: io)
- io.rewind
- content = io.read
-
- puts result.equal?(io)
- puts content.include?('"value":"abc"')
- ensure
- io.close
- File.unlink io.path
- end
- RUBY
-
- stdout.should == "true\ntrue\n"
- end
-
- it "raises ArgumentError when passed not supported :output value" do
- -> { ObjectSpace.dump_all(output: Object.new) }.should raise_error(ArgumentError, /wrong output option/)
- end
-end
diff --git a/spec/ruby/library/objectspace/dump_spec.rb b/spec/ruby/library/objectspace/dump_spec.rb
deleted file mode 100644
index e22ee3df1e..0000000000
--- a/spec/ruby/library/objectspace/dump_spec.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-require_relative '../../spec_helper'
-require 'objspace'
-
-describe "ObjectSpace.dump" do
- it "dumps the content of object as JSON" do
- require 'json'
- string = ObjectSpace.dump("abc")
- dump = JSON.parse(string)
-
- dump['type'].should == "STRING"
- dump['value'].should == "abc"
- end
-
- it "dumps to string when passed output: :string" do
- string = ObjectSpace.dump("abc", output: :string)
- string.should be_kind_of(String)
- string.should include('"value":"abc"')
- end
-
- it "dumps to string when :output not specified" do
- string = ObjectSpace.dump("abc")
- string.should be_kind_of(String)
- string.should include('"value":"abc"')
- end
-
- it "dumps to a temporary file when passed output: :file" do
- file = ObjectSpace.dump("abc", output: :file)
- file.should be_kind_of(File)
-
- file.rewind
- content = file.read
- content.should include('"value":"abc"')
- ensure
- file.close
- File.unlink file.path
- end
-
- it "dumps to a temporary file when passed output: :nil" do
- file = ObjectSpace.dump("abc", output: nil)
- file.should be_kind_of(File)
-
- file.rewind
- file.read.should include('"value":"abc"')
- ensure
- file.close
- File.unlink file.path
- end
-
- it "dumps to stdout when passed output: :stdout" do
- stdout = ruby_exe('ObjectSpace.dump("abc", output: :stdout)', options: "-robjspace").chomp
- stdout.should include('"value":"abc"')
- end
-
- it "dumps to provided IO when passed output: IO" do
- filename = tmp("io_read.txt")
- io = File.open(filename, "w+")
- result = ObjectSpace.dump("abc", output: io)
- result.should.equal? io
-
- io.rewind
- io.read.should include('"value":"abc"')
- ensure
- io.close
- rm_r filename
- end
-
- it "raises ArgumentError when passed not supported :output value" do
- -> { ObjectSpace.dump("abc", output: Object.new) }.should raise_error(ArgumentError, /wrong output option/)
- end
-end
diff --git a/spec/ruby/library/objectspace/fixtures/trace.rb b/spec/ruby/library/objectspace/fixtures/trace.rb
index e53a7a0cac..fd4524b0ba 100644
--- a/spec/ruby/library/objectspace/fixtures/trace.rb
+++ b/spec/ruby/library/objectspace/fixtures/trace.rb
@@ -1,4 +1,3 @@
-# frozen_string_literal: false
require "objspace/trace"
a = "foo"
b = "b" + "a" + "r"
diff --git a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
index dee5961663..7e70bc8569 100644
--- a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
+++ b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
@@ -38,6 +38,7 @@ describe "ObjectSpace.reachable_objects_from" do
end
it "finds an object stored in a Queue" do
+ require 'thread'
o = Object.new
q = Queue.new
q << o
@@ -48,6 +49,7 @@ describe "ObjectSpace.reachable_objects_from" do
end
it "finds an object stored in a SizedQueue" do
+ require 'thread'
o = Object.new
q = SizedQueue.new(3)
q << o
diff --git a/spec/ruby/library/objectspace/trace_spec.rb b/spec/ruby/library/objectspace/trace_spec.rb
index 532c282ce4..59952a006c 100644
--- a/spec/ruby/library/objectspace/trace_spec.rb
+++ b/spec/ruby/library/objectspace/trace_spec.rb
@@ -6,8 +6,8 @@ ruby_version_is "3.1" do
file = fixture(__FILE__ , "trace.rb")
ruby_exe(file, args: "2>&1").lines(chomp: true).should == [
"objspace/trace is enabled",
- "\"foo\" @ #{file}:3",
- "\"bar\" @ #{file}:4",
+ "\"foo\" @ #{file}:2",
+ "\"bar\" @ #{file}:3",
"42"
]
end
diff --git a/spec/ruby/library/openssl/config/freeze_spec.rb b/spec/ruby/library/openssl/config/freeze_spec.rb
new file mode 100644
index 0000000000..c814341b86
--- /dev/null
+++ b/spec/ruby/library/openssl/config/freeze_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../../spec_helper'
+require_relative '../shared/constants'
+
+require 'openssl'
+
+version_is(OpenSSL::VERSION, ""..."2.2") do
+ describe "OpenSSL::Config#freeze" do
+ it "needs to be reviewed for completeness"
+
+ it "freezes" do
+ c = OpenSSL::Config.new
+ -> {
+ c['foo'] = [ ['key', 'value'] ]
+ }.should_not raise_error
+ c.freeze
+ c.frozen?.should be_true
+ -> {
+ c['foo'] = [ ['key', 'value'] ]
+ }.should raise_error(TypeError)
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/digest/append_spec.rb b/spec/ruby/library/openssl/digest/append_spec.rb
deleted file mode 100644
index 08802b7253..0000000000
--- a/spec/ruby/library/openssl/digest/append_spec.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative 'shared/update'
-
-describe "OpenSSL::Digest#<<" do
- it_behaves_like :openssl_digest_update, :<<
-end
diff --git a/spec/ruby/library/openssl/digest/block_length_spec.rb b/spec/ruby/library/openssl/digest/block_length_spec.rb
deleted file mode 100644
index 444ed9d20d..0000000000
--- a/spec/ruby/library/openssl/digest/block_length_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../../../library/digest/sha1/shared/constants'
-require_relative '../../../library/digest/sha256/shared/constants'
-require_relative '../../../library/digest/sha384/shared/constants'
-require_relative '../../../library/digest/sha512/shared/constants'
-require 'openssl'
-
-describe "OpenSSL::Digest#block_length" do
- context "when the digest object is created via a name argument" do
- it "returns a SHA1 block length" do
- OpenSSL::Digest.new('sha1').block_length.should == SHA1Constants::BlockLength
- end
-
- it "returns a SHA256 block length" do
- OpenSSL::Digest.new('sha256').block_length.should == SHA256Constants::BlockLength
- end
-
- it "returns a SHA384 block length" do
- OpenSSL::Digest.new('sha384').block_length.should == SHA384Constants::BlockLength
- end
-
- it "returns a SHA512 block length" do
- OpenSSL::Digest.new('sha512').block_length.should == SHA512Constants::BlockLength
- end
- end
-
- context "when the digest object is created via a subclass" do
- it "returns a SHA1 block length" do
- OpenSSL::Digest::SHA1.new.block_length.should == SHA1Constants::BlockLength
- end
-
- it "returns a SHA256 block length" do
- OpenSSL::Digest::SHA256.new.block_length.should == SHA256Constants::BlockLength
- end
-
- it "returns a SHA384 block length" do
- OpenSSL::Digest::SHA384.new.block_length.should == SHA384Constants::BlockLength
- end
-
- it "returns a SHA512 block length" do
- OpenSSL::Digest::SHA512.new.block_length.should == SHA512Constants::BlockLength
- end
- end
-end
diff --git a/spec/ruby/library/openssl/digest/digest_length_spec.rb b/spec/ruby/library/openssl/digest/digest_length_spec.rb
deleted file mode 100644
index 37d1cba9a7..0000000000
--- a/spec/ruby/library/openssl/digest/digest_length_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../../../library/digest/sha1/shared/constants'
-require_relative '../../../library/digest/sha256/shared/constants'
-require_relative '../../../library/digest/sha384/shared/constants'
-require_relative '../../../library/digest/sha512/shared/constants'
-require 'openssl'
-
-describe "OpenSSL::Digest#digest_length" do
- context "when the digest object is created via a name argument" do
- it "returns a SHA1 digest length" do
- OpenSSL::Digest.new('sha1').digest_length.should == SHA1Constants::DigestLength
- end
-
- it "returns a SHA256 digest length" do
- OpenSSL::Digest.new('sha256').digest_length.should == SHA256Constants::DigestLength
- end
-
- it "returns a SHA384 digest length" do
- OpenSSL::Digest.new('sha384').digest_length.should == SHA384Constants::DigestLength
- end
-
- it "returns a SHA512 digest length" do
- OpenSSL::Digest.new('sha512').digest_length.should == SHA512Constants::DigestLength
- end
- end
-
- context "when the digest object is created via a subclass" do
- it "returns a SHA1 digest length" do
- OpenSSL::Digest::SHA1.new.digest_length.should == SHA1Constants::DigestLength
- end
-
- it "returns a SHA256 digest length" do
- OpenSSL::Digest::SHA256.new.digest_length.should == SHA256Constants::DigestLength
- end
-
- it "returns a SHA384 digest length" do
- OpenSSL::Digest::SHA384.new.digest_length.should == SHA384Constants::DigestLength
- end
-
- it "returns a SHA512 digest length" do
- OpenSSL::Digest::SHA512.new.digest_length.should == SHA512Constants::DigestLength
- end
- end
-end
diff --git a/spec/ruby/library/openssl/digest/digest_spec.rb b/spec/ruby/library/openssl/digest/digest_spec.rb
deleted file mode 100644
index cf27d01b6d..0000000000
--- a/spec/ruby/library/openssl/digest/digest_spec.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../../../library/digest/sha1/shared/constants'
-require_relative '../../../library/digest/sha256/shared/constants'
-require_relative '../../../library/digest/sha384/shared/constants'
-require_relative '../../../library/digest/sha512/shared/constants'
-require 'openssl'
-
-describe "OpenSSL::Digest class methods" do
- describe ".digest" do
- it "returns a SHA1 digest" do
- OpenSSL::Digest.digest('sha1', SHA1Constants::Contents).should == SHA1Constants::Digest
- end
-
- it "returns a SHA256 digest" do
- OpenSSL::Digest.digest('sha256', SHA256Constants::Contents).should == SHA256Constants::Digest
- end
-
- it "returns a SHA384 digest" do
- OpenSSL::Digest.digest('sha384', SHA384Constants::Contents).should == SHA384Constants::Digest
- end
-
- it "returns a SHA512 digest" do
- OpenSSL::Digest.digest('sha512', SHA512Constants::Contents).should == SHA512Constants::Digest
- end
- end
-
- describe ".hexdigest" do
- it "returns a SHA1 hexdigest" do
- OpenSSL::Digest.hexdigest('sha1', SHA1Constants::Contents).should == SHA1Constants::Hexdigest
- end
-
- it "returns a SHA256 hexdigest" do
- OpenSSL::Digest.hexdigest('sha256', SHA256Constants::Contents).should == SHA256Constants::Hexdigest
- end
-
- it "returns a SHA384 hexdigest" do
- OpenSSL::Digest.hexdigest('sha384', SHA384Constants::Contents).should == SHA384Constants::Hexdigest
- end
-
- it "returns a SHA512 hexdigest" do
- OpenSSL::Digest.hexdigest('sha512', SHA512Constants::Contents).should == SHA512Constants::Hexdigest
- end
- end
-
- describe ".base64digest" do
- it "returns a SHA1 base64digest" do
- OpenSSL::Digest.base64digest('sha1', SHA1Constants::Contents).should == SHA1Constants::Base64digest
- end
-
- it "returns a SHA256 base64digest" do
- OpenSSL::Digest.base64digest('sha256', SHA256Constants::Contents).should == SHA256Constants::Base64digest
- end
-
- it "returns a SHA384 base64digest" do
- OpenSSL::Digest.base64digest('sha384', SHA384Constants::Contents).should == SHA384Constants::Base64digest
- end
-
- it "returns a SHA512 base64digest" do
- OpenSSL::Digest.base64digest('sha512', SHA512Constants::Contents).should == SHA512Constants::Base64digest
- end
- end
-end
diff --git a/spec/ruby/library/openssl/digest/initialize_spec.rb b/spec/ruby/library/openssl/digest/initialize_spec.rb
deleted file mode 100644
index 1cd0409c4d..0000000000
--- a/spec/ruby/library/openssl/digest/initialize_spec.rb
+++ /dev/null
@@ -1,141 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../../../library/digest/sha1/shared/constants'
-require_relative '../../../library/digest/sha256/shared/constants'
-require_relative '../../../library/digest/sha384/shared/constants'
-require_relative '../../../library/digest/sha512/shared/constants'
-require 'openssl'
-
-describe "OpenSSL::Digest#initialize" do
- describe "can be called with a digest name" do
- it "returns a SHA1 object" do
- OpenSSL::Digest.new("sha1").name.should == "SHA1"
- end
-
- it "returns a SHA256 object" do
- OpenSSL::Digest.new("sha256").name.should == "SHA256"
- end
-
- it "returns a SHA384 object" do
- OpenSSL::Digest.new("sha384").name.should == "SHA384"
- end
-
- it "returns a SHA512 object" do
- OpenSSL::Digest.new("sha512").name.should == "SHA512"
- end
-
- it "throws an error when called with an unknown digest" do
- -> { OpenSSL::Digest.new("wd40") }.should raise_error(RuntimeError, /Unsupported digest algorithm \(wd40\)/)
- end
-
- it "cannot be called with a symbol" do
- -> { OpenSSL::Digest.new(:SHA1) }.should raise_error(TypeError, /wrong argument type Symbol/)
- end
-
- it "does not call #to_str on the argument" do
- name = mock("digest name")
- name.should_not_receive(:to_str)
- -> { OpenSSL::Digest.new(name) }.should raise_error(TypeError, /wrong argument type/)
- end
- end
-
- describe "can be called with a digest object" do
- it "returns a SHA1 object" do
- OpenSSL::Digest.new(OpenSSL::Digest::SHA1.new).name.should == "SHA1"
- end
-
- it "returns a SHA256 object" do
- OpenSSL::Digest.new(OpenSSL::Digest::SHA256.new).name.should == "SHA256"
- end
-
- it "returns a SHA384 object" do
- OpenSSL::Digest.new(OpenSSL::Digest::SHA384.new).name.should == "SHA384"
- end
-
- it "returns a SHA512 object" do
- OpenSSL::Digest.new(OpenSSL::Digest::SHA512.new).name.should == "SHA512"
- end
-
- it "ignores the state of the digest object" do
- sha1 = OpenSSL::Digest.new('sha1', SHA1Constants::Contents)
- OpenSSL::Digest.new(sha1).digest.should == SHA1Constants::BlankDigest
- end
- end
-
- it "cannot be called with a digest class" do
- -> { OpenSSL::Digest.new(OpenSSL::Digest::SHA1) }.should raise_error(TypeError, /wrong argument type Class/)
- end
-
- context "when called without an initial String argument" do
- it "returns a SHA1 digest" do
- OpenSSL::Digest.new("sha1").digest.should == SHA1Constants::BlankDigest
- end
-
- it "returns a SHA256 digest" do
- OpenSSL::Digest.new("sha256").digest.should == SHA256Constants::BlankDigest
- end
-
- it "returns a SHA384 digest" do
- OpenSSL::Digest.new("sha384").digest.should == SHA384Constants::BlankDigest
- end
-
- it "returns a SHA512 digest" do
- OpenSSL::Digest.new("sha512").digest.should == SHA512Constants::BlankDigest
- end
- end
-
- context "when called with an initial String argument" do
- it "returns a SHA1 digest of that argument" do
- OpenSSL::Digest.new("sha1", SHA1Constants::Contents).digest.should == SHA1Constants::Digest
- end
-
- it "returns a SHA256 digest of that argument" do
- OpenSSL::Digest.new("sha256", SHA256Constants::Contents).digest.should == SHA256Constants::Digest
- end
-
- it "returns a SHA384 digest of that argument" do
- OpenSSL::Digest.new("sha384", SHA384Constants::Contents).digest.should == SHA384Constants::Digest
- end
-
- it "returns a SHA512 digest of that argument" do
- OpenSSL::Digest.new("sha512", SHA512Constants::Contents).digest.should == SHA512Constants::Digest
- end
- end
-
- context "can be called on subclasses" do
- describe "can be called without an initial String argument on subclasses" do
- it "returns a SHA1 digest" do
- OpenSSL::Digest::SHA1.new.digest.should == SHA1Constants::BlankDigest
- end
-
- it "returns a SHA256 digest" do
- OpenSSL::Digest::SHA256.new.digest.should == SHA256Constants::BlankDigest
- end
-
- it "returns a SHA384 digest" do
- OpenSSL::Digest::SHA384.new.digest.should == SHA384Constants::BlankDigest
- end
-
- it "returns a SHA512 digest" do
- OpenSSL::Digest::SHA512.new.digest.should == SHA512Constants::BlankDigest
- end
- end
-
- describe "can be called with an initial String argument on subclasses" do
- it "returns a SHA1 digest" do
- OpenSSL::Digest::SHA1.new(SHA1Constants::Contents).digest.should == SHA1Constants::Digest
- end
-
- it "returns a SHA256 digest" do
- OpenSSL::Digest::SHA256.new(SHA256Constants::Contents).digest.should == SHA256Constants::Digest
- end
-
- it "returns a SHA384 digest" do
- OpenSSL::Digest::SHA384.new(SHA384Constants::Contents).digest.should == SHA384Constants::Digest
- end
-
- it "returns a SHA512 digest" do
- OpenSSL::Digest::SHA512.new(SHA512Constants::Contents).digest.should == SHA512Constants::Digest
- end
- end
- end
-end
diff --git a/spec/ruby/library/openssl/digest/name_spec.rb b/spec/ruby/library/openssl/digest/name_spec.rb
deleted file mode 100644
index b379f35c1c..0000000000
--- a/spec/ruby/library/openssl/digest/name_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require_relative '../../../spec_helper'
-require 'openssl'
-
-describe "OpenSSL::Digest#name" do
- it "returns the name of digest" do
- OpenSSL::Digest.new('SHA1').name.should == 'SHA1'
- end
-
- it "converts the name to the internal representation of OpenSSL" do
- OpenSSL::Digest.new('sha1').name.should == 'SHA1'
- end
-
- it "works on subclasses too" do
- OpenSSL::Digest::SHA1.new.name.should == 'SHA1'
- end
-end
diff --git a/spec/ruby/library/openssl/digest/reset_spec.rb b/spec/ruby/library/openssl/digest/reset_spec.rb
deleted file mode 100644
index c19bf46633..0000000000
--- a/spec/ruby/library/openssl/digest/reset_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../../../library/digest/sha1/shared/constants'
-require_relative '../../../library/digest/sha256/shared/constants'
-require_relative '../../../library/digest/sha384/shared/constants'
-require_relative '../../../library/digest/sha512/shared/constants'
-require 'openssl'
-
-describe "OpenSSL::Digest#reset" do
- it "works for a SHA1 digest" do
- digest = OpenSSL::Digest.new('sha1', SHA1Constants::Contents)
- digest.reset
- digest.update(SHA1Constants::Contents)
- digest.digest.should == SHA1Constants::Digest
- end
-
- it "works for a SHA256 digest" do
- digest = OpenSSL::Digest.new('sha256', SHA256Constants::Contents)
- digest.reset
- digest.update(SHA256Constants::Contents)
- digest.digest.should == SHA256Constants::Digest
- end
-
- it "works for a SHA384 digest" do
- digest = OpenSSL::Digest.new('sha384', SHA384Constants::Contents)
- digest.reset
- digest.update(SHA384Constants::Contents)
- digest.digest.should == SHA384Constants::Digest
- end
-
- it "works for a SHA512 digest" do
- digest = OpenSSL::Digest.new('sha512', SHA512Constants::Contents)
- digest.reset
- digest.update(SHA512Constants::Contents)
- digest.digest.should == SHA512Constants::Digest
- end
-end
diff --git a/spec/ruby/library/openssl/digest/shared/update.rb b/spec/ruby/library/openssl/digest/shared/update.rb
deleted file mode 100644
index e5ff9dcb16..0000000000
--- a/spec/ruby/library/openssl/digest/shared/update.rb
+++ /dev/null
@@ -1,123 +0,0 @@
-require_relative '../../../../library/digest/sha1/shared/constants'
-require_relative '../../../../library/digest/sha256/shared/constants'
-require_relative '../../../../library/digest/sha384/shared/constants'
-require_relative '../../../../library/digest/sha512/shared/constants'
-require 'openssl'
-
-describe :openssl_digest_update, shared: true do
- context "when given input as a single string" do
- it "returns a SHA1 digest" do
- digest = OpenSSL::Digest.new('sha1')
- digest.send(@method, SHA1Constants::Contents)
- digest.digest.should == SHA1Constants::Digest
- end
-
- it "returns a SHA256 digest" do
- digest = OpenSSL::Digest.new('sha256')
- digest.send(@method, SHA256Constants::Contents)
- digest.digest.should == SHA256Constants::Digest
- end
-
- it "returns a SHA384 digest" do
- digest = OpenSSL::Digest.new('sha384')
- digest.send(@method, SHA384Constants::Contents)
- digest.digest.should == SHA384Constants::Digest
- end
-
- it "returns a SHA512 digest" do
- digest = OpenSSL::Digest.new('sha512')
- digest.send(@method, SHA512Constants::Contents)
- digest.digest.should == SHA512Constants::Digest
- end
- end
-
- context "when given input as multiple smaller substrings" do
- it "returns a SHA1 digest" do
- digest = OpenSSL::Digest.new('sha1')
- SHA1Constants::Contents.each_char { |b| digest.send(@method, b) }
- digest.digest.should == SHA1Constants::Digest
- end
-
- it "returns a SHA256 digest" do
- digest = OpenSSL::Digest.new('sha256')
- SHA256Constants::Contents.each_char { |b| digest.send(@method, b) }
- digest.digest.should == SHA256Constants::Digest
- end
-
- it "returns a SHA384 digest" do
- digest = OpenSSL::Digest.new('sha384')
- SHA384Constants::Contents.each_char { |b| digest.send(@method, b) }
- digest.digest.should == SHA384Constants::Digest
- end
-
- it "returns a SHA512 digest" do
- digest = OpenSSL::Digest.new('sha512')
- SHA512Constants::Contents.each_char { |b| digest.send(@method, b) }
- digest.digest.should == SHA512Constants::Digest
- end
- end
-
- context "when input is not a String and responds to #to_str" do
- it "returns a SHA1 digest" do
- str = mock('str')
- str.should_receive(:to_str).and_return(SHA1Constants::Contents)
- digest = OpenSSL::Digest.new('sha1')
- digest.send(@method, str)
- digest.digest.should == SHA1Constants::Digest
- end
-
- it "returns a SHA256 digest" do
- str = mock('str')
- str.should_receive(:to_str).and_return(SHA256Constants::Contents)
- digest = OpenSSL::Digest.new('sha256')
- digest.send(@method, str)
- digest.digest.should == SHA256Constants::Digest
- end
-
- it "returns a SHA384 digest" do
- str = mock('str')
- str.should_receive(:to_str).and_return(SHA384Constants::Contents)
- digest = OpenSSL::Digest.new('sha384')
- digest.send(@method, str)
- digest.digest.should == SHA384Constants::Digest
- end
-
- it "returns a SHA512 digest" do
- str = mock('str')
- str.should_receive(:to_str).and_return(SHA512Constants::Contents)
- digest = OpenSSL::Digest.new('sha512')
- digest.send(@method, str)
- digest.digest.should == SHA512Constants::Digest
- end
- end
-
- context "when input is not a String and does not respond to #to_str" do
- it "raises a TypeError with SHA1" do
- digest = OpenSSL::Digest.new('sha1')
- -> {
- digest.send(@method, Object.new)
- }.should raise_error(TypeError, 'no implicit conversion of Object into String')
- end
-
- it "raises a TypeError with SHA256" do
- digest = OpenSSL::Digest.new('sha256')
- -> {
- digest.send(@method, Object.new)
- }.should raise_error(TypeError, 'no implicit conversion of Object into String')
- end
-
- it "raises a TypeError with SHA384" do
- digest = OpenSSL::Digest.new('sha384')
- -> {
- digest.send(@method, Object.new)
- }.should raise_error(TypeError, 'no implicit conversion of Object into String')
- end
-
- it "raises a TypeError with SHA512" do
- digest = OpenSSL::Digest.new('sha512')
- -> {
- digest.send(@method, Object.new)
- }.should raise_error(TypeError, 'no implicit conversion of Object into String')
- end
- end
-end
diff --git a/spec/ruby/library/openssl/digest/update_spec.rb b/spec/ruby/library/openssl/digest/update_spec.rb
deleted file mode 100644
index 3a90b06c6b..0000000000
--- a/spec/ruby/library/openssl/digest/update_spec.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative 'shared/update'
-
-describe "OpenSSL::Digest#update" do
- it_behaves_like :openssl_digest_update, :update
-end
diff --git a/spec/ruby/library/openssl/digest_spec.rb b/spec/ruby/library/openssl/digest_spec.rb
new file mode 100644
index 0000000000..b8e82d073f
--- /dev/null
+++ b/spec/ruby/library/openssl/digest_spec.rb
@@ -0,0 +1,63 @@
+require_relative '../../spec_helper'
+require_relative '../../library/digest/sha1/shared/constants'
+require_relative '../../library/digest/sha256/shared/constants'
+require_relative '../../library/digest/sha384/shared/constants'
+require_relative '../../library/digest/sha512/shared/constants'
+require 'openssl'
+
+describe "OpenSSL::Digest" do
+
+ describe ".digest" do
+ it "returns a SHA1 digest" do
+ OpenSSL::Digest.digest('sha1', SHA1Constants::Contents).should == SHA1Constants::Digest
+ end
+
+ it "returns a SHA256 digest" do
+ OpenSSL::Digest.digest('sha256', SHA256Constants::Contents).should == SHA256Constants::Digest
+ end
+
+ it "returns a SHA384 digest" do
+ OpenSSL::Digest.digest('sha384', SHA384Constants::Contents).should == SHA384Constants::Digest
+ end
+
+ it "returns a SHA512 digest" do
+ OpenSSL::Digest.digest('sha512', SHA512Constants::Contents).should == SHA512Constants::Digest
+ end
+ end
+
+ describe ".hexdigest" do
+ it "returns a SHA1 hexdigest" do
+ OpenSSL::Digest.hexdigest('sha1', SHA1Constants::Contents).should == SHA1Constants::Hexdigest
+ end
+
+ it "returns a SHA256 hexdigest" do
+ OpenSSL::Digest.hexdigest('sha256', SHA256Constants::Contents).should == SHA256Constants::Hexdigest
+ end
+
+ it "returns a SHA384 hexdigest" do
+ OpenSSL::Digest.hexdigest('sha384', SHA384Constants::Contents).should == SHA384Constants::Hexdigest
+ end
+
+ it "returns a SHA512 hexdigest" do
+ OpenSSL::Digest.hexdigest('sha512', SHA512Constants::Contents).should == SHA512Constants::Hexdigest
+ end
+ end
+
+ describe ".base64digest" do
+ it "returns a SHA1 base64digest" do
+ OpenSSL::Digest.base64digest('sha1', SHA1Constants::Contents).should == SHA1Constants::Base64digest
+ end
+
+ it "returns a SHA256 base64digest" do
+ OpenSSL::Digest.base64digest('sha256', SHA256Constants::Contents).should == SHA256Constants::Base64digest
+ end
+
+ it "returns a SHA384 base64digest" do
+ OpenSSL::Digest.base64digest('sha384', SHA384Constants::Contents).should == SHA384Constants::Base64digest
+ end
+
+ it "returns a SHA512 base64digest" do
+ OpenSSL::Digest.base64digest('sha512', SHA512Constants::Contents).should == SHA512Constants::Base64digest
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb b/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb
deleted file mode 100644
index 5a2ca168b5..0000000000
--- a/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-require_relative '../../spec_helper'
-require 'openssl'
-
-describe "OpenSSL.fixed_length_secure_compare" do
- it "returns true for two strings with the same content" do
- input1 = "the quick brown fox jumps over the lazy dog"
- input2 = "the quick brown fox jumps over the lazy dog"
- OpenSSL.fixed_length_secure_compare(input1, input2).should be_true
- end
-
- it "returns false for two strings of equal size with different content" do
- input1 = "the quick brown fox jumps over the lazy dog"
- input2 = "the lazy dog jumps over the quick brown fox"
- OpenSSL.fixed_length_secure_compare(input1, input2).should be_false
- end
-
- it "converts both arguments to strings using #to_str" do
- input1 = mock("input1")
- input1.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
- input2 = mock("input2")
- input2.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
- OpenSSL.fixed_length_secure_compare(input1, input2).should be_true
- end
-
- it "does not accept arguments that are not string and cannot be coerced into strings" do
- -> {
- OpenSSL.fixed_length_secure_compare("input1", :input2)
- }.should raise_error(TypeError, 'no implicit conversion of Symbol into String')
-
- -> {
- OpenSSL.fixed_length_secure_compare(Object.new, "input2")
- }.should raise_error(TypeError, 'no implicit conversion of Object into String')
- end
-
- it "raises an ArgumentError for two strings of different size" do
- input1 = "the quick brown fox jumps over the lazy dog"
- input2 = "the quick brown fox"
- -> {
- OpenSSL.fixed_length_secure_compare(input1, input2)
- }.should raise_error(ArgumentError, 'inputs must be of equal length')
- end
-end
diff --git a/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb b/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb
deleted file mode 100644
index 40f8597275..0000000000
--- a/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb
+++ /dev/null
@@ -1,168 +0,0 @@
-require_relative '../../../spec_helper'
-require 'openssl'
-
-describe "OpenSSL::KDF.pbkdf2_hmac" do
- before :each do
- @defaults = {
- salt: "\x00".b * 16,
- iterations: 20_000,
- length: 16,
- hash: "sha1"
- }
- end
-
- it "creates the same value with the same input" do
- key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults)
- key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
- end
-
- it "supports nullbytes embedded in the password" do
- key = OpenSSL::KDF.pbkdf2_hmac("sec\x00ret".b, **@defaults)
- key.should == "\xB9\x7F\xB0\xC2\th\xC8<\x86\xF3\x94Ij7\xEF\xF1".b
- end
-
- it "coerces the password into a String using #to_str" do
- pass = mock("pass")
- pass.should_receive(:to_str).and_return("secret")
- key = OpenSSL::KDF.pbkdf2_hmac(pass, **@defaults)
- key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
- end
-
- it "coerces the salt into a String using #to_str" do
- salt = mock("salt")
- salt.should_receive(:to_str).and_return("\x00".b * 16)
- key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, salt: salt)
- key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
- end
-
- it "coerces the iterations into an Integer using #to_int" do
- iterations = mock("iterations")
- iterations.should_receive(:to_int).and_return(20_000)
- key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: iterations)
- key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
- end
-
- it "coerces the length into an Integer using #to_int" do
- length = mock("length")
- length.should_receive(:to_int).and_return(16)
- key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: length)
- key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
- end
-
- it "accepts a OpenSSL::Digest object as hash" do
- hash = OpenSSL::Digest.new("sha1")
- key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: hash)
- key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
- end
-
- it "accepts an empty password" do
- key = OpenSSL::KDF.pbkdf2_hmac("", **@defaults)
- key.should == "k\x9F-\xB1\xF7\x9A\v\xA1(C\xF9\x85!P\xEF\x8C".b
- end
-
- it "accepts an empty salt" do
- key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, salt: "")
- key.should == "\xD5f\xE5\xEA\xF91\x1D\xD3evD\xED\xDB\xE80\x80".b
- end
-
- it "accepts an empty length" do
- key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: 0)
- key.should.empty?
- end
-
- it "accepts an arbitrary length" do
- key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: 19)
- key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0\xCF\xBB\x7F".b
- end
-
- it "accepts any hash function known to OpenSSL" do
- key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: "sha512")
- key.should == "N\x12}D\xCE\x99\xDBC\x8E\xEC\xAAr\xEA1\xDF\xFF".b
- end
-
- it "raises a TypeError when password is not a String and does not respond to #to_str" do
- -> {
- OpenSSL::KDF.pbkdf2_hmac(Object.new, **@defaults)
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
-
- it "raises a TypeError when salt is not a String and does not respond to #to_str" do
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, salt: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
-
- it "raises a TypeError when iterations is not an Integer and does not respond to #to_int" do
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
- end
-
- it "raises a TypeError when length is not an Integer and does not respond to #to_int" do
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
- end
-
- it "raises a TypeError when hash is neither a String nor an OpenSSL::Digest" do
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: Object.new)
- }.should raise_error(TypeError, "wrong argument type Object (expected OpenSSL/Digest)")
- end
-
- it "raises a TypeError when hash is neither a String nor an OpenSSL::Digest, it does not try to call #to_str" do
- hash = mock("hash")
- hash.should_not_receive(:to_str)
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: hash)
- }.should raise_error(TypeError, "wrong argument type MockObject (expected OpenSSL/Digest)")
- end
-
- it "raises a RuntimeError for unknown digest algorithms" do
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: "wd40")
- }.should raise_error(RuntimeError, /Unsupported digest algorithm \(wd40\)/)
- end
-
- it "treats salt as a required keyword" do
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:salt))
- }.should raise_error(ArgumentError, 'missing keyword: :salt')
- end
-
- it "treats iterations as a required keyword" do
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:iterations))
- }.should raise_error(ArgumentError, 'missing keyword: :iterations')
- end
-
- it "treats length as a required keyword" do
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:length))
- }.should raise_error(ArgumentError, 'missing keyword: :length')
- end
-
- it "treats hash as a required keyword" do
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:hash))
- }.should raise_error(ArgumentError, 'missing keyword: :hash')
- end
-
- it "treats all keywords as required" do
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret")
- }.should raise_error(ArgumentError, 'missing keywords: :salt, :iterations, :length, :hash')
- end
-
- guard -> { OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000 } do
- it "raises an OpenSSL::KDF::KDFError for 0 or less iterations" do
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: 0)
- }.should raise_error(OpenSSL::KDF::KDFError, "PKCS5_PBKDF2_HMAC: invalid iteration count")
-
- -> {
- OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: -1)
- }.should raise_error(OpenSSL::KDF::KDFError, /PKCS5_PBKDF2_HMAC/)
- end
- end
-end
diff --git a/spec/ruby/library/openssl/kdf/scrypt_spec.rb b/spec/ruby/library/openssl/kdf/scrypt_spec.rb
deleted file mode 100644
index 5dc9f2f281..0000000000
--- a/spec/ruby/library/openssl/kdf/scrypt_spec.rb
+++ /dev/null
@@ -1,209 +0,0 @@
-require_relative '../../../spec_helper'
-require 'openssl'
-
-guard -> { OpenSSL::KDF.respond_to?(:scrypt) } do
- describe "OpenSSL::KDF.scrypt" do
- before :each do
- @defaults = {
- salt: "\x00".b * 16,
- N: 2**14,
- r: 8,
- p: 1,
- length: 32
- }
- end
-
- it "creates the same value with the same input" do
- key = OpenSSL::KDF.scrypt("secret", **@defaults)
- key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
- end
-
- it "supports nullbytes embedded into the password" do
- key = OpenSSL::KDF.scrypt("sec\x00ret".b, **@defaults)
- key.should == "\xF9\xA4\xA0\xF1p\xF4\xF0\xCAT\xB4v\xEB\r7\x88N\xF7\x15]Ns\xFCwt4a\xC9\xC6\xA7\x13\x81&".b
- end
-
- it "coerces the password into a String using #to_str" do
- pass = mock("pass")
- pass.should_receive(:to_str).and_return("secret")
- key = OpenSSL::KDF.scrypt(pass, **@defaults)
- key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
- end
-
- it "coerces the salt into a String using #to_str" do
- salt = mock("salt")
- salt.should_receive(:to_str).and_return("\x00".b * 16)
- key = OpenSSL::KDF.scrypt("secret", **@defaults, salt: salt)
- key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
- end
-
- it "coerces the N into an Integer using #to_int" do
- n = mock("N")
- n.should_receive(:to_int).and_return(2**14)
- key = OpenSSL::KDF.scrypt("secret", **@defaults, N: n)
- key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
- end
-
- it "coerces the r into an Integer using #to_int" do
- r = mock("r")
- r.should_receive(:to_int).and_return(8)
- key = OpenSSL::KDF.scrypt("secret", **@defaults, r: r)
- key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
- end
-
- it "coerces the p into an Integer using #to_int" do
- p = mock("p")
- p.should_receive(:to_int).and_return(1)
- key = OpenSSL::KDF.scrypt("secret", **@defaults, p: p)
- key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
- end
-
- it "coerces the length into an Integer using #to_int" do
- length = mock("length")
- length.should_receive(:to_int).and_return(32)
- key = OpenSSL::KDF.scrypt("secret", **@defaults, length: length)
- key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
- end
-
- it "accepts an empty password" do
- key = OpenSSL::KDF.scrypt("", **@defaults)
- key.should == "\xAA\xFC\xF5^E\x94v\xFFk\xE6\xF0vR\xE7\x13\xA7\xF5\x15'\x9A\xE4C\x9Dn\x18F_E\xD2\v\e\xB3".b
- end
-
- it "accepts an empty salt" do
- key = OpenSSL::KDF.scrypt("secret", **@defaults, salt: "")
- key.should == "\x96\xACDl\xCB3/aN\xB0F\x8A#\xD7\x92\xD2O\x1E\v\xBB\xCE\xC0\xAA\xB9\x0F]\xB09\xEA8\xDD\e".b
- end
-
- it "accepts a zero length" do
- key = OpenSSL::KDF.scrypt("secret", **@defaults, length: 0)
- key.should.empty?
- end
-
- it "accepts an arbitrary length" do
- key = OpenSSL::KDF.scrypt("secret", **@defaults, length: 19)
- key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D".b
- end
-
- it "raises a TypeError when password is not a String and does not respond to #to_str" do
- -> {
- OpenSSL::KDF.scrypt(Object.new, **@defaults)
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
-
- it "raises a TypeError when salt is not a String and does not respond to #to_str" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, salt: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
-
- it "raises a TypeError when N is not an Integer and does not respond to #to_int" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, N: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
- end
-
- it "raises a TypeError when r is not an Integer and does not respond to #to_int" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, r: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
- end
-
- it "raises a TypeError when p is not an Integer and does not respond to #to_int" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, p: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
- end
-
- it "raises a TypeError when length is not an Integer and does not respond to #to_int" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, length: Object.new)
- }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
- end
-
- it "treats salt as a required keyword" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults.except(:salt))
- }.should raise_error(ArgumentError, 'missing keyword: :salt')
- end
-
- it "treats N as a required keyword" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults.except(:N))
- }.should raise_error(ArgumentError, 'missing keyword: :N')
- end
-
- it "treats r as a required keyword" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults.except(:r))
- }.should raise_error(ArgumentError, 'missing keyword: :r')
- end
-
- it "treats p as a required keyword" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults.except(:p))
- }.should raise_error(ArgumentError, 'missing keyword: :p')
- end
-
- it "treats length as a required keyword" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults.except(:length))
- }.should raise_error(ArgumentError, 'missing keyword: :length')
- end
-
- it "treats all keywords as required" do
- -> {
- OpenSSL::KDF.scrypt("secret")
- }.should raise_error(ArgumentError, 'missing keywords: :salt, :N, :r, :p, :length')
- end
-
- it "requires N to be a power of 2" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, N: 2**14 - 1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
- end
-
- it "requires N to be at least 2" do
- key = OpenSSL::KDF.scrypt("secret", **@defaults, N: 2)
- key.should == "\x06A$a\xA9!\xBE\x01\x85\xA7\x18\xBCEa\x82\xC5\xFEl\x93\xAB\xBD\xF7\x8B\x84\v\xFC\eN\xEBQ\xE6\xD2".b
-
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, N: 1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
-
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, N: 0)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
-
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, N: -1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
- end
-
- it "requires r to be positive" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, r: 0)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
-
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, r: -1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
- end
-
- it "requires p to be positive" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, p: 0)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
-
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, p: -1)
- }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
- end
-
- it "requires length to be not negative" do
- -> {
- OpenSSL::KDF.scrypt("secret", **@defaults, length: -1)
- }.should raise_error(ArgumentError, "negative string size (or size too big)")
- end
- end
-end
diff --git a/spec/ruby/library/openssl/random/shared/random_bytes.rb b/spec/ruby/library/openssl/random/shared/random_bytes.rb
index f97ccd9974..037f10d409 100644
--- a/spec/ruby/library/openssl/random/shared/random_bytes.rb
+++ b/spec/ruby/library/openssl/random/shared/random_bytes.rb
@@ -1,7 +1,7 @@
require_relative '../../../../spec_helper'
require 'openssl'
-describe :openssl_random_bytes, shared: true do
+describe :openssl_random_bytes, shared: true do |cmd|
it "generates a random binary string of specified length" do
(1..64).each do |idx|
bytes = OpenSSL::Random.send(@method, idx)
diff --git a/spec/ruby/library/openssl/secure_compare_spec.rb b/spec/ruby/library/openssl/secure_compare_spec.rb
deleted file mode 100644
index cec48e01e7..0000000000
--- a/spec/ruby/library/openssl/secure_compare_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative '../../spec_helper'
-require 'openssl'
-
-describe "OpenSSL.secure_compare" do
- it "returns true for two strings with the same content" do
- input1 = "the quick brown fox jumps over the lazy dog"
- input2 = "the quick brown fox jumps over the lazy dog"
- OpenSSL.secure_compare(input1, input2).should be_true
- end
-
- it "returns false for two strings with different content" do
- input1 = "the quick brown fox jumps over the lazy dog"
- input2 = "the lazy dog jumps over the quick brown fox"
- OpenSSL.secure_compare(input1, input2).should be_false
- end
-
- it "converts both arguments to strings using #to_str, but adds equality check for the original objects" do
- input1 = mock("input1")
- input1.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
- input2 = mock("input2")
- input2.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
- OpenSSL.secure_compare(input1, input2).should be_false
-
- input = mock("input")
- input.should_receive(:to_str).twice.and_return("the quick brown fox jumps over the lazy dog")
- OpenSSL.secure_compare(input, input).should be_true
- end
-
- it "does not accept arguments that are not string and cannot be coerced into strings" do
- -> {
- OpenSSL.secure_compare("input1", :input2)
- }.should raise_error(TypeError, 'no implicit conversion of Symbol into String')
-
- -> {
- OpenSSL.secure_compare(Object.new, "input2")
- }.should raise_error(TypeError, 'no implicit conversion of Object into String')
- end
-end
diff --git a/spec/ruby/library/openssl/x509/name/verify_spec.rb b/spec/ruby/library/openssl/x509/name/verify_spec.rb
new file mode 100644
index 0000000000..6dcfc99466
--- /dev/null
+++ b/spec/ruby/library/openssl/x509/name/verify_spec.rb
@@ -0,0 +1,78 @@
+require_relative '../../../../spec_helper'
+require 'openssl'
+
+describe "OpenSSL::X509::Name.verify" do
+ it "returns true for valid certificate" do
+ key = OpenSSL::PKey::RSA.new 2048
+ cert = OpenSSL::X509::Certificate.new
+ cert.version = 2
+ cert.serial = 1
+ cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA"
+ cert.issuer = cert.subject
+ cert.public_key = key.public_key
+ cert.not_before = Time.now - 10
+ cert.not_after = cert.not_before + 365 * 24 * 60 * 60
+ cert.sign key, OpenSSL::Digest.new('SHA256')
+ store = OpenSSL::X509::Store.new
+ store.add_cert(cert)
+ [store.verify(cert), store.error, store.error_string].should == [true, 0, "ok"]
+ end
+
+ it "returns false for an expired certificate" do
+ key = OpenSSL::PKey::RSA.new 2048
+ cert = OpenSSL::X509::Certificate.new
+ cert.version = 2
+ cert.serial = 1
+ cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA"
+ cert.issuer = cert.subject
+ cert.public_key = key.public_key
+ cert.not_before = Time.now - 10
+ cert.not_after = Time.now - 5
+ cert.sign key, OpenSSL::Digest.new('SHA256')
+ store = OpenSSL::X509::Store.new
+ store.add_cert(cert)
+ store.verify(cert).should == false
+ end
+
+ it "returns false for an expired root certificate" do
+ root_key = OpenSSL::PKey::RSA.new 2048
+ root_cert = OpenSSL::X509::Certificate.new
+ root_cert.version = 2
+ root_cert.serial = 1
+ root_cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA"
+ root_cert.issuer = root_cert.subject
+ root_cert.public_key = root_key.public_key
+ root_cert.not_before = Time.now - 10
+ root_cert.not_after = Time.now - 5
+ ef = OpenSSL::X509::ExtensionFactory.new
+ ef.subject_certificate = root_cert
+ ef.issuer_certificate = root_cert
+ root_cert.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true))
+ root_cert.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
+ root_cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
+ root_cert.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false))
+ root_cert.sign(root_key, OpenSSL::Digest.new('SHA256'))
+
+
+ key = OpenSSL::PKey::RSA.new 2048
+ cert = OpenSSL::X509::Certificate.new
+ cert.version = 2
+ cert.serial = 2
+ cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby certificate"
+ cert.issuer = root_cert.subject
+ cert.public_key = key.public_key
+ cert.not_before = Time.now
+ cert.not_after = cert.not_before + 1 * 365 * 24 * 60 * 60
+ ef = OpenSSL::X509::ExtensionFactory.new
+ ef.subject_certificate = cert
+ ef.issuer_certificate = root_cert
+ cert.add_extension(ef.create_extension("keyUsage","digitalSignature", true))
+ cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
+ cert.sign(root_key, OpenSSL::Digest.new('SHA256'))
+
+ store = OpenSSL::X509::Store.new
+ store.add_cert(root_cert)
+ store.add_cert(cert)
+ store.verify(cert).should == false
+ end
+end
diff --git a/spec/ruby/library/openssl/x509/store/verify_spec.rb b/spec/ruby/library/openssl/x509/store/verify_spec.rb
deleted file mode 100644
index 6a6a53d992..0000000000
--- a/spec/ruby/library/openssl/x509/store/verify_spec.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'openssl'
-
-describe "OpenSSL::X509::Store#verify" do
- it "returns true for valid certificate" do
- key = OpenSSL::PKey::RSA.new 2048
- cert = OpenSSL::X509::Certificate.new
- cert.version = 2
- cert.serial = 1
- cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA"
- cert.issuer = cert.subject
- cert.public_key = key.public_key
- cert.not_before = Time.now - 10
- cert.not_after = cert.not_before + 365 * 24 * 60 * 60
- cert.sign key, OpenSSL::Digest.new('SHA256')
- store = OpenSSL::X509::Store.new
- store.add_cert(cert)
- [store.verify(cert), store.error, store.error_string].should == [true, 0, "ok"]
- end
-
- it "returns false for an expired certificate" do
- key = OpenSSL::PKey::RSA.new 2048
- cert = OpenSSL::X509::Certificate.new
- cert.version = 2
- cert.serial = 1
- cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA"
- cert.issuer = cert.subject
- cert.public_key = key.public_key
- cert.not_before = Time.now - 10
- cert.not_after = Time.now - 5
- cert.sign key, OpenSSL::Digest.new('SHA256')
- store = OpenSSL::X509::Store.new
- store.add_cert(cert)
- store.verify(cert).should == false
- end
-
- it "returns false for an expired root certificate" do
- root_key = OpenSSL::PKey::RSA.new 2048
- root_cert = OpenSSL::X509::Certificate.new
- root_cert.version = 2
- root_cert.serial = 1
- root_cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA"
- root_cert.issuer = root_cert.subject
- root_cert.public_key = root_key.public_key
- root_cert.not_before = Time.now - 10
- root_cert.not_after = Time.now - 5
- ef = OpenSSL::X509::ExtensionFactory.new
- ef.subject_certificate = root_cert
- ef.issuer_certificate = root_cert
- root_cert.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true))
- root_cert.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
- root_cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
- root_cert.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false))
- root_cert.sign(root_key, OpenSSL::Digest.new('SHA256'))
-
-
- key = OpenSSL::PKey::RSA.new 2048
- cert = OpenSSL::X509::Certificate.new
- cert.version = 2
- cert.serial = 2
- cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby certificate"
- cert.issuer = root_cert.subject
- cert.public_key = key.public_key
- cert.not_before = Time.now
- cert.not_after = cert.not_before + 1 * 365 * 24 * 60 * 60
- ef = OpenSSL::X509::ExtensionFactory.new
- ef.subject_certificate = cert
- ef.issuer_certificate = root_cert
- cert.add_extension(ef.create_extension("keyUsage","digitalSignature", true))
- cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
- cert.sign(root_key, OpenSSL::Digest.new('SHA256'))
-
- store = OpenSSL::X509::Store.new
- store.add_cert(root_cert)
- store.add_cert(cert)
- store.verify(cert).should == false
- end
-end
diff --git a/spec/ruby/library/pathname/relative_path_from_spec.rb b/spec/ruby/library/pathname/relative_path_from_spec.rb
index 133a149849..abe9c80a45 100644
--- a/spec/ruby/library/pathname/relative_path_from_spec.rb
+++ b/spec/ruby/library/pathname/relative_path_from_spec.rb
@@ -48,8 +48,4 @@ describe "Pathname#relative_path_from" do
relative_path_str('..', '..').should == '.'
relative_path_str('..', '.').should == '..'
end
-
- it 'converts string argument to Pathname' do
- Pathname.new('/usr/bin/ls').relative_path_from('/usr').to_s.should == 'bin/ls'
- end
end
diff --git a/spec/ruby/library/pp/pp_spec.rb b/spec/ruby/library/pp/pp_spec.rb
index e45a6bb94f..243478efd9 100644
--- a/spec/ruby/library/pp/pp_spec.rb
+++ b/spec/ruby/library/pp/pp_spec.rb
@@ -25,6 +25,6 @@ describe "PP.pp" do
hash = { 'key' => 42 }
-> {
PP.pp hash
- }.should output("#{hash.inspect}\n")
+ }.should output('{"key"=>42}' + "\n")
end
end
diff --git a/spec/ruby/library/prime/each_spec.rb b/spec/ruby/library/prime/each_spec.rb
index b99cf7cf0e..c89e871582 100644
--- a/spec/ruby/library/prime/each_spec.rb
+++ b/spec/ruby/library/prime/each_spec.rb
@@ -1,167 +1,170 @@
require_relative '../../spec_helper'
-require 'prime'
-describe :prime_each, shared: true do
- before :each do
- ScratchPad.record []
- end
+ruby_version_is ""..."3.1" do
+ require 'prime'
- it "enumerates primes" do
- primes = Prime.instance
- result = []
+ describe :prime_each, shared: true do
+ before :each do
+ ScratchPad.record []
+ end
- primes.each { |p|
- result << p
- break if p > 10
- }
+ it "enumerates primes" do
+ primes = Prime.instance
+ result = []
- result.should == [2, 3, 5, 7, 11]
- end
+ primes.each { |p|
+ result << p
+ break if p > 10
+ }
- it "yields ascending primes to the block" do
- previous = 1
- @object.each do |prime|
- break if prime > 1000
- ScratchPad << prime
- prime.should > previous
- previous = prime
+ result.should == [2, 3, 5, 7, 11]
end
- all_prime = true
- ScratchPad.recorded.all? do |prime|
- all_prime &&= (2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
+ it "yields ascending primes to the block" do
+ previous = 1
+ @object.each do |prime|
+ break if prime > 1000
+ ScratchPad << prime
+ prime.should > previous
+ previous = prime
+ end
+
+ all_prime = true
+ ScratchPad.recorded.all? do |prime|
+ all_prime &&= (2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
+ end
+
+ all_prime.should be_true
end
- all_prime.should be_true
- end
+ it "returns the last evaluated expression in the passed block" do
+ @object.each { break :value }.should equal(:value)
+ end
- it "returns the last evaluated expression in the passed block" do
- @object.each { break :value }.should equal(:value)
- end
+ describe "when not passed a block" do
+ before :each do
+ @prime_enum = @object.each
+ end
- describe "when not passed a block" do
- before :each do
- @prime_enum = @object.each
- end
+ it "returns an object that is Enumerable" do
+ @prime_enum.each.should be_kind_of(Enumerable)
+ end
- it "returns an object that is Enumerable" do
- @prime_enum.each.should be_kind_of(Enumerable)
- end
+ it "returns an object that responds to #with_index" do
+ @prime_enum.should respond_to(:with_index)
+ end
- it "returns an object that responds to #with_index" do
- @prime_enum.should respond_to(:with_index)
- end
+ it "returns an object that responds to #with_object" do
+ @prime_enum.should respond_to(:with_object)
+ end
- it "returns an object that responds to #with_object" do
- @prime_enum.should respond_to(:with_object)
- end
+ it "returns an object that responds to #next" do
+ @prime_enum.should respond_to(:next)
+ end
- it "returns an object that responds to #next" do
- @prime_enum.should respond_to(:next)
- end
+ it "returns an object that responds to #rewind" do
+ @prime_enum.should respond_to(:rewind)
+ end
- it "returns an object that responds to #rewind" do
- @prime_enum.should respond_to(:rewind)
- end
+ it "yields primes starting at 2 independent of prior enumerators" do
+ @prime_enum.next.should == 2
+ @prime_enum.next.should == 3
- it "yields primes starting at 2 independent of prior enumerators" do
- @prime_enum.next.should == 2
- @prime_enum.next.should == 3
+ @object.each { |prime| break prime }.should == 2
+ end
- @object.each { |prime| break prime }.should == 2
+ it "returns an enumerator that yields previous primes when #rewind is called" do
+ @prime_enum.next.should == 2
+ @prime_enum.next.should == 3
+ @prime_enum.rewind
+ @prime_enum.next.should == 2
+ end
+
+ it "returns independent enumerators" do
+ enum = @object.each
+ enum.next.should == 2
+ enum.next.should == 3
+
+ @prime_enum.next.should == 2
+
+ enum.next.should == 5
+ end
end
+ end
- it "returns an enumerator that yields previous primes when #rewind is called" do
- @prime_enum.next.should == 2
- @prime_enum.next.should == 3
- @prime_enum.rewind
- @prime_enum.next.should == 2
+ describe :prime_each_with_arguments, shared: true do
+ before :each do
+ ScratchPad.record []
end
- it "returns independent enumerators" do
- enum = @object.each
- enum.next.should == 2
- enum.next.should == 3
+ it "yields ascending primes less than or equal to the argument" do
+ bound = 1000
+ previous = 1
+ @object.each(bound) do |prime|
+ ScratchPad << prime
+ prime.should > previous
+ previous = prime
+ end
- @prime_enum.next.should == 2
+ ScratchPad.recorded.all? do |prime|
+ (2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
+ end.should be_true
- enum.next.should == 5
+ ScratchPad.recorded.all? { |prime| prime <= bound }.should be_true
end
- end
-end
-describe :prime_each_with_arguments, shared: true do
- before :each do
- ScratchPad.record []
- end
+ it "returns nil when no prime is generated" do
+ @object.each(1) { :value }.should be_nil
+ end
- it "yields ascending primes less than or equal to the argument" do
- bound = 1000
- previous = 1
- @object.each(bound) do |prime|
- ScratchPad << prime
- prime.should > previous
- previous = prime
+ it "yields primes starting at 2 independent of prior enumeration" do
+ @object.each(10) { |prime| prime }.should == 7
+ @object.each(10) { |prime| break prime }.should == 2
end
- ScratchPad.recorded.all? do |prime|
- (2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
- end.should be_true
+ it "accepts a pseudo-prime generator as the second argument" do
+ generator = mock('very bad pseudo-prime generator')
+ generator.should_receive(:upper_bound=).with(100)
+ generator.should_receive(:each).and_yield(2).and_yield(3).and_yield(4)
- ScratchPad.recorded.all? { |prime| prime <= bound }.should be_true
- end
+ @object.each(100, generator) { |prime| ScratchPad << prime }
+ ScratchPad.recorded.should == [2, 3, 4]
+ end
- it "returns nil when no prime is generated" do
- @object.each(1) { :value }.should be_nil
+ describe "when not passed a block" do
+ it "returns an object that returns primes less than or equal to the bound" do
+ bound = 100
+ @object.each(bound).all? { |prime| prime <= bound }.should be_true
+ end
+ end
end
- it "yields primes starting at 2 independent of prior enumeration" do
- @object.each(10) { |prime| prime }.should == 7
- @object.each(10) { |prime| break prime }.should == 2
+ describe "Prime.each" do
+ it_behaves_like :prime_each, :each, Prime
end
- it "accepts a pseudo-prime generator as the second argument" do
- generator = mock('very bad pseudo-prime generator')
- generator.should_receive(:upper_bound=).with(100)
- generator.should_receive(:each).and_yield(2).and_yield(3).and_yield(4)
-
- @object.each(100, generator) { |prime| ScratchPad << prime }
- ScratchPad.recorded.should == [2, 3, 4]
+ describe "Prime.each" do
+ it_behaves_like :prime_each_with_arguments, :each, Prime
end
- describe "when not passed a block" do
- it "returns an object that returns primes less than or equal to the bound" do
- bound = 100
- @object.each(bound).all? { |prime| prime <= bound }.should be_true
- end
+ describe "Prime#each with Prime.instance" do
+ it_behaves_like :prime_each, :each, Prime.instance
end
-end
-describe "Prime.each" do
- it_behaves_like :prime_each, :each, Prime
-end
-
-describe "Prime.each" do
- it_behaves_like :prime_each_with_arguments, :each, Prime
-end
-
-describe "Prime#each with Prime.instance" do
- it_behaves_like :prime_each, :each, Prime.instance
-end
-
-describe "Prime#each with Prime.instance" do
- it_behaves_like :prime_each_with_arguments, :each, Prime.instance
-end
-
-describe "Prime#each with Prime.instance" do
- before :each do
- @object = Prime.instance
+ describe "Prime#each with Prime.instance" do
+ it_behaves_like :prime_each_with_arguments, :each, Prime.instance
end
- it_behaves_like :prime_each, :each
+ describe "Prime#each with Prime.instance" do
+ before :each do
+ @object = Prime.instance
+ end
+
+ it_behaves_like :prime_each, :each
- it "resets the enumerator with each call" do
- @object.each { |prime| break if prime > 10 }
- @object.each { |prime| break prime }.should == 2
+ it "resets the enumerator with each call" do
+ @object.each { |prime| break if prime > 10 }
+ @object.each { |prime| break prime }.should == 2
+ end
end
end
diff --git a/spec/ruby/library/prime/instance_spec.rb b/spec/ruby/library/prime/instance_spec.rb
index 5183f36901..82f21913b7 100644
--- a/spec/ruby/library/prime/instance_spec.rb
+++ b/spec/ruby/library/prime/instance_spec.rb
@@ -1,21 +1,24 @@
require_relative '../../spec_helper'
-require 'prime'
-describe "Prime.instance" do
- it "returns a object representing the set of prime numbers" do
- Prime.instance.should be_kind_of(Prime)
- end
+ruby_version_is ""..."3.1" do
+ require 'prime'
- it "returns a object with no obsolete features" do
- Prime.instance.should_not respond_to(:succ)
- Prime.instance.should_not respond_to(:next)
- end
+ describe "Prime.instance" do
+ it "returns a object representing the set of prime numbers" do
+ Prime.instance.should be_kind_of(Prime)
+ end
- it "does not complain anything" do
- -> { Prime.instance }.should_not complain
- end
+ it "returns a object with no obsolete features" do
+ Prime.instance.should_not respond_to(:succ)
+ Prime.instance.should_not respond_to(:next)
+ end
+
+ it "does not complain anything" do
+ -> { Prime.instance }.should_not complain
+ end
- it "raises a ArgumentError when is called with some arguments" do
- -> { Prime.instance(1) }.should raise_error(ArgumentError)
+ it "raises a ArgumentError when is called with some arguments" do
+ -> { Prime.instance(1) }.should raise_error(ArgumentError)
+ end
end
end
diff --git a/spec/ruby/library/prime/int_from_prime_division_spec.rb b/spec/ruby/library/prime/int_from_prime_division_spec.rb
index 5abb7221df..5c881aefa1 100644
--- a/spec/ruby/library/prime/int_from_prime_division_spec.rb
+++ b/spec/ruby/library/prime/int_from_prime_division_spec.rb
@@ -1,13 +1,16 @@
require_relative '../../spec_helper'
-require 'prime'
-describe "Prime.int_from_prime_division" do
- it "returns the product of the given factorization" do
- Prime.int_from_prime_division([[2,3], [3,3], [5,3], [7,3], [11,3], [13,3], [17,3]]).
- should == 2**3 * 3**3 * 5**3 * 7**3 * 11**3 * 13**3 * 17**3
- end
+ruby_version_is ""..."3.1" do
+ require 'prime'
+
+ describe "Prime.int_from_prime_division" do
+ it "returns the product of the given factorization" do
+ Prime.int_from_prime_division([[2,3], [3,3], [5,3], [7,3], [11,3], [13,3], [17,3]]).
+ should == 2**3 * 3**3 * 5**3 * 7**3 * 11**3 * 13**3 * 17**3
+ end
- it "returns 1 for an empty factorization" do
- Prime.int_from_prime_division([]).should == 1
+ it "returns 1 for an empty factorization" do
+ Prime.int_from_prime_division([]).should == 1
+ end
end
end
diff --git a/spec/ruby/library/prime/integer/each_prime_spec.rb b/spec/ruby/library/prime/integer/each_prime_spec.rb
index a71296b0df..6034802e73 100644
--- a/spec/ruby/library/prime/integer/each_prime_spec.rb
+++ b/spec/ruby/library/prime/integer/each_prime_spec.rb
@@ -1,13 +1,16 @@
require_relative '../../../spec_helper'
-require 'prime'
-describe "Integer.each_prime" do
- it "is transferred to Prime.each" do
- Prime.should_receive(:each).with(100).and_yield(2).and_yield(3).and_yield(5)
- yielded = []
- Integer.each_prime(100) do |prime|
- yielded << prime
+ruby_version_is ""..."3.1" do
+ require 'prime'
+
+ describe "Integer.each_prime" do
+ it "is transferred to Prime.each" do
+ Prime.should_receive(:each).with(100).and_yield(2).and_yield(3).and_yield(5)
+ yielded = []
+ Integer.each_prime(100) do |prime|
+ yielded << prime
+ end
+ yielded.should == [2,3,5]
end
- yielded.should == [2,3,5]
end
end
diff --git a/spec/ruby/library/prime/integer/from_prime_division_spec.rb b/spec/ruby/library/prime/integer/from_prime_division_spec.rb
index e0e74fb336..5422bc651c 100644
--- a/spec/ruby/library/prime/integer/from_prime_division_spec.rb
+++ b/spec/ruby/library/prime/integer/from_prime_division_spec.rb
@@ -1,13 +1,16 @@
require_relative '../../../spec_helper'
-require 'prime'
-describe "Integer.from_prime_division" do
- it "returns the product of the given factorization" do
- Integer.from_prime_division([[2,3], [3,3], [5,3], [7,3], [11,3], [13,3], [17,3]]).
- should == 2**3 * 3**3 * 5**3 * 7**3 * 11**3 * 13**3 * 17**3
- end
+ruby_version_is ""..."3.1" do
+ require 'prime'
+
+ describe "Integer.from_prime_division" do
+ it "returns the product of the given factorization" do
+ Integer.from_prime_division([[2,3], [3,3], [5,3], [7,3], [11,3], [13,3], [17,3]]).
+ should == 2**3 * 3**3 * 5**3 * 7**3 * 11**3 * 13**3 * 17**3
+ end
- it "returns 1 for an empty factorization" do
- Integer.from_prime_division([]).should == 1
+ it "returns 1 for an empty factorization" do
+ Integer.from_prime_division([]).should == 1
+ end
end
end
diff --git a/spec/ruby/library/prime/integer/prime_division_spec.rb b/spec/ruby/library/prime/integer/prime_division_spec.rb
index be03438a6f..03be0be27b 100644
--- a/spec/ruby/library/prime/integer/prime_division_spec.rb
+++ b/spec/ruby/library/prime/integer/prime_division_spec.rb
@@ -1,19 +1,22 @@
require_relative '../../../spec_helper'
-require 'prime'
-describe "Integer#prime_division" do
- it "returns an array of a prime factor and a corresponding exponent" do
- (2*3*5*7*11*13*17).prime_division.should ==
- [[2,1], [3,1], [5,1], [7,1], [11,1], [13,1], [17,1]]
- end
+ruby_version_is ""..."3.1" do
+ require 'prime'
- it "returns an empty array for 1" do
- 1.prime_division.should == []
- end
- it "returns an empty array for -1" do
- -1.prime_division.should == [[-1, 1]]
- end
- it "raises ZeroDivisionError for 0" do
- -> { 0.prime_division }.should raise_error(ZeroDivisionError)
+ describe "Integer#prime_division" do
+ it "returns an array of a prime factor and a corresponding exponent" do
+ (2*3*5*7*11*13*17).prime_division.should ==
+ [[2,1], [3,1], [5,1], [7,1], [11,1], [13,1], [17,1]]
+ end
+
+ it "returns an empty array for 1" do
+ 1.prime_division.should == []
+ end
+ it "returns an empty array for -1" do
+ -1.prime_division.should == [[-1, 1]]
+ end
+ it "raises ZeroDivisionError for 0" do
+ -> { 0.prime_division }.should raise_error(ZeroDivisionError)
+ end
end
end
diff --git a/spec/ruby/library/prime/integer/prime_spec.rb b/spec/ruby/library/prime/integer/prime_spec.rb
index 53de76d5ab..65b779e319 100644
--- a/spec/ruby/library/prime/integer/prime_spec.rb
+++ b/spec/ruby/library/prime/integer/prime_spec.rb
@@ -1,17 +1,20 @@
require_relative '../../../spec_helper'
-require 'prime'
-describe "Integer#prime?" do
- it "returns a true value for prime numbers" do
- 2.prime?.should be_true
- 3.prime?.should be_true
- (2**31-1).prime?.should be_true # 8th Mersenne prime (M8)
- end
+ruby_version_is ""..."3.1" do
+ require 'prime'
+
+ describe "Integer#prime?" do
+ it "returns a true value for prime numbers" do
+ 2.prime?.should be_true
+ 3.prime?.should be_true
+ (2**31-1).prime?.should be_true # 8th Mersenne prime (M8)
+ end
- it "returns a false value for composite numbers" do
- 4.prime?.should be_false
- 15.prime?.should be_false
- (2**32-1).prime?.should be_false
- ( (2**17-1)*(2**19-1) ).prime?.should be_false # M6*M7
+ it "returns a false value for composite numbers" do
+ 4.prime?.should be_false
+ 15.prime?.should be_false
+ (2**32-1).prime?.should be_false
+ ( (2**17-1)*(2**19-1) ).prime?.should be_false # M6*M7
+ end
end
end
diff --git a/spec/ruby/library/prime/next_spec.rb b/spec/ruby/library/prime/next_spec.rb
index 39c4ae16ae..8e805ed044 100644
--- a/spec/ruby/library/prime/next_spec.rb
+++ b/spec/ruby/library/prime/next_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'shared/next'
-require 'prime'
-describe "Prime#next" do
- it_behaves_like :prime_next, :next
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/next'
+ require 'prime'
+
+ describe "Prime#next" do
+ it_behaves_like :prime_next, :next
+ end
end
diff --git a/spec/ruby/library/prime/prime_division_spec.rb b/spec/ruby/library/prime/prime_division_spec.rb
index 6293478f59..4c93d5936a 100644
--- a/spec/ruby/library/prime/prime_division_spec.rb
+++ b/spec/ruby/library/prime/prime_division_spec.rb
@@ -1,25 +1,28 @@
require_relative '../../spec_helper'
-require 'prime'
-describe "Prime.prime_division" do
- it "returns an array of a prime factor and a corresponding exponent" do
- Prime.prime_division(2*3*5*7*11*13*17).should ==
- [[2,1], [3,1], [5,1], [7,1], [11,1], [13,1], [17,1]]
- end
+ruby_version_is ""..."3.1" do
+ require 'prime'
- it "returns an empty array for 1" do
- Prime.prime_division(1).should == []
- end
+ describe "Prime.prime_division" do
+ it "returns an array of a prime factor and a corresponding exponent" do
+ Prime.prime_division(2*3*5*7*11*13*17).should ==
+ [[2,1], [3,1], [5,1], [7,1], [11,1], [13,1], [17,1]]
+ end
- it "returns [[-1, 1]] for -1" do
- Prime.prime_division(-1).should == [[-1, 1]]
- end
+ it "returns an empty array for 1" do
+ Prime.prime_division(1).should == []
+ end
- it "includes [[-1, 1]] in the divisors of a negative number" do
- Prime.prime_division(-10).should include([-1, 1])
- end
+ it "returns [[-1, 1]] for -1" do
+ Prime.prime_division(-1).should == [[-1, 1]]
+ end
+
+ it "includes [[-1, 1]] in the divisors of a negative number" do
+ Prime.prime_division(-10).should include([-1, 1])
+ end
- it "raises ZeroDivisionError for 0" do
- -> { Prime.prime_division(0) }.should raise_error(ZeroDivisionError)
+ it "raises ZeroDivisionError for 0" do
+ -> { Prime.prime_division(0) }.should raise_error(ZeroDivisionError)
+ end
end
end
diff --git a/spec/ruby/library/prime/prime_spec.rb b/spec/ruby/library/prime/prime_spec.rb
index 0896c7f0f3..e2afddd5b2 100644
--- a/spec/ruby/library/prime/prime_spec.rb
+++ b/spec/ruby/library/prime/prime_spec.rb
@@ -1,17 +1,20 @@
require_relative '../../spec_helper'
-require 'prime'
-describe "Prime#prime?" do
- it "returns a true value for prime numbers" do
- Prime.prime?(2).should be_true
- Prime.prime?(3).should be_true
- Prime.prime?(2**31-1).should be_true # 8th Mersenne prime (M8)
- end
+ruby_version_is ""..."3.1" do
+ require 'prime'
+
+ describe "Prime#prime?" do
+ it "returns a true value for prime numbers" do
+ Prime.prime?(2).should be_true
+ Prime.prime?(3).should be_true
+ Prime.prime?(2**31-1).should be_true # 8th Mersenne prime (M8)
+ end
- it "returns a false value for composite numbers" do
- Prime.prime?(4).should be_false
- Prime.prime?(15).should be_false
- Prime.prime?(2**32-1).should be_false
- Prime.prime?( (2**17-1)*(2**19-1) ).should be_false # M6*M7
+ it "returns a false value for composite numbers" do
+ Prime.prime?(4).should be_false
+ Prime.prime?(15).should be_false
+ Prime.prime?(2**32-1).should be_false
+ Prime.prime?( (2**17-1)*(2**19-1) ).should be_false # M6*M7
+ end
end
end
diff --git a/spec/ruby/library/prime/succ_spec.rb b/spec/ruby/library/prime/succ_spec.rb
index 34c18d2ba0..9843dae25d 100644
--- a/spec/ruby/library/prime/succ_spec.rb
+++ b/spec/ruby/library/prime/succ_spec.rb
@@ -1,7 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'shared/next'
-require 'prime'
-describe "Prime#succ" do
- it_behaves_like :prime_next, :succ
+ruby_version_is ""..."3.1" do
+ require_relative 'shared/next'
+ require 'prime'
+
+ describe "Prime#succ" do
+ it_behaves_like :prime_next, :succ
+ end
end
diff --git a/spec/ruby/library/rbconfig/rbconfig_spec.rb b/spec/ruby/library/rbconfig/rbconfig_spec.rb
index 3e06219621..b90cc90970 100644
--- a/spec/ruby/library/rbconfig/rbconfig_spec.rb
+++ b/spec/ruby/library/rbconfig/rbconfig_spec.rb
@@ -88,30 +88,6 @@ describe 'RbConfig::CONFIG' do
end
end
end
-
- guard -> { %w[aarch64 arm64].include? RbConfig::CONFIG['host_cpu'] } do
- it "['host_cpu'] returns CPU architecture properly for AArch64" do
- platform_is :darwin do
- RbConfig::CONFIG['host_cpu'].should == 'arm64'
- end
-
- platform_is_not :darwin do
- RbConfig::CONFIG['host_cpu'].should == 'aarch64'
- end
- end
- end
-
- guard -> { platform_is(:linux) || platform_is(:darwin) } do
- it "['host_os'] returns a proper OS name or platform" do
- platform_is :darwin do
- RbConfig::CONFIG['host_os'].should.match?(/darwin/)
- end
-
- platform_is :linux do
- RbConfig::CONFIG['host_os'].should.match?(/linux/)
- end
- end
- end
end
describe "RbConfig::TOPDIR" do
@@ -123,34 +99,3 @@ describe "RbConfig::TOPDIR" do
end
end
end
-
-describe "RUBY_PLATFORM" do
- it "RUBY_PLATFORM contains a proper CPU architecture" do
- RUBY_PLATFORM.should.include? RbConfig::CONFIG['host_cpu']
- end
-
- guard -> { platform_is(:linux) || platform_is(:darwin) } do
- it "RUBY_PLATFORM contains OS name" do
- # don't use RbConfig::CONFIG['host_os'] as far as it could be slightly different, e.g. linux-gnu
- platform_is(:linux) do
- RUBY_PLATFORM.should.include? 'linux'
- end
-
- platform_is(:darwin) do
- RUBY_PLATFORM.should.include? 'darwin'
- end
- end
- end
-end
-
-describe "RUBY_DESCRIPTION" do
- guard_not -> { RUBY_ENGINE == "ruby" && !RbConfig::TOPDIR } do
- it "contains version" do
- RUBY_DESCRIPTION.should.include? RUBY_VERSION
- end
-
- it "contains RUBY_PLATFORM" do
- RUBY_DESCRIPTION.should.include? RUBY_PLATFORM
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/clone_spec.rb b/spec/ruby/library/rexml/attribute/clone_spec.rb
new file mode 100644
index 0000000000..5c86468d45
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/clone_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#clone" do
+ it "returns a copy of this Attribute" do
+ orig = REXML::Attribute.new("name", "value&&")
+ orig.should == orig.clone
+ orig.clone.to_s.should == orig.to_s
+ orig.clone.to_string.should == orig.to_string
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/element_spec.rb b/spec/ruby/library/rexml/attribute/element_spec.rb
new file mode 100644
index 0000000000..0e4ce46a4f
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/element_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#element" do
+ it "returns the parent element" do
+ e = REXML::Element.new "root"
+
+ REXML::Attribute.new("name", "value", e).element.should == e
+ REXML::Attribute.new("name", "default_constructor").element.should == nil
+ end
+ end
+
+ describe "REXML::Attribute#element=" do
+ it "sets the parent element" do
+ e = REXML::Element.new "root"
+ f = REXML::Element.new "temp"
+ a = REXML::Attribute.new("name", "value", e)
+ a.element.should == e
+
+ a.element = f
+ a.element.should == f
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/equal_value_spec.rb b/spec/ruby/library/rexml/attribute/equal_value_spec.rb
new file mode 100644
index 0000000000..1498bae624
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/equal_value_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#==" do
+ it "returns true if other has equal name and value" do
+ a1 = REXML::Attribute.new("foo", "bar")
+ a1.should == a1.clone
+
+ a2 = REXML::Attribute.new("foo", "bar")
+ a1.should == a2
+
+ a3 = REXML::Attribute.new("foo", "bla")
+ a1.should_not == a3
+
+ a4 = REXML::Attribute.new("baz", "bar")
+ a1.should_not == a4
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/hash_spec.rb b/spec/ruby/library/rexml/attribute/hash_spec.rb
new file mode 100644
index 0000000000..7e0cbcc1ea
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/hash_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#hash" do
+ # These are not really complete, any idea on how to make them more
+ # "testable" will be appreciated.
+ it "returns a hashcode made of the name and value of self" do
+ a = REXML::Attribute.new("name", "value")
+ a.hash.should be_kind_of(Numeric)
+ b = REXML::Attribute.new(a)
+ a.hash.should == b.hash
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/initialize_spec.rb b/spec/ruby/library/rexml/attribute/initialize_spec.rb
new file mode 100644
index 0000000000..35b87b0733
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/initialize_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#initialize" do
+ before :each do
+ @e = REXML::Element.new "root"
+ @name = REXML::Attribute.new("name", "Nicko")
+ @e.add_attribute @name
+ end
+
+ it "receives two strings for name and value" do
+ @e.attributes["name"].should == "Nicko"
+ @e.add_attribute REXML::Attribute.new("last_name", nil)
+ @e.attributes["last_name"].should == ""
+ end
+
+ it "receives an Attribute and clones it" do
+ copy = REXML::Attribute.new(@name)
+ copy.should == @name
+ end
+
+ it "receives a parent node" do
+ last_name = REXML::Attribute.new("last_name", "McBrain", @e)
+ last_name.element.should == @e
+
+ last_name = REXML::Attribute.new(@name, @e)
+ last_name.element.should == @e
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/inspect_spec.rb b/spec/ruby/library/rexml/attribute/inspect_spec.rb
new file mode 100644
index 0000000000..ee5236b98e
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/inspect_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#inspect" do
+ it "returns the name and value as a string" do
+ a = REXML::Attribute.new("my_name", "my_value")
+ a.inspect.should == "my_name='my_value'"
+ end
+
+ it "accepts attributes with no value" do
+ a = REXML::Attribute.new("my_name")
+ a.inspect.should == "my_name=''"
+ end
+
+ it "does not escape text" do
+ a = REXML::Attribute.new("name", "<>")
+ a.inspect.should == "name='<>'"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/namespace_spec.rb b/spec/ruby/library/rexml/attribute/namespace_spec.rb
new file mode 100644
index 0000000000..645b3cd1b1
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/namespace_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#namespace" do
+ it "returns the namespace url" do
+ e = REXML::Element.new("root")
+ e.add_attribute REXML::Attribute.new("xmlns:ns", "http://some_uri")
+ e.namespace("ns").should == "http://some_uri"
+ end
+
+ it "returns nil if namespace is not defined" do
+ e = REXML::Element.new("root")
+ e.add_attribute REXML::Attribute.new("test", "value")
+ e.namespace("test").should == nil
+ e.namespace("ns").should == nil
+ end
+
+ it "defaults arg to nil" do
+ e = REXML::Element.new("root")
+ e.add_attribute REXML::Attribute.new("xmlns:ns", "http://some_uri")
+ e.namespace.should == ""
+ e.namespace("ns").should == "http://some_uri"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/node_type_spec.rb b/spec/ruby/library/rexml/attribute/node_type_spec.rb
new file mode 100644
index 0000000000..da055ae8f0
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/node_type_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#node_type" do
+ it "always returns :attribute" do
+ attr = REXML::Attribute.new("foo", "bar")
+ attr.node_type.should == :attribute
+ REXML::Attribute.new(attr).node_type.should == :attribute
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/prefix_spec.rb b/spec/ruby/library/rexml/attribute/prefix_spec.rb
new file mode 100644
index 0000000000..87bff4822b
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/prefix_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#prefix" do
+ it "returns the namespace of the Attribute" do
+ ans = REXML::Attribute.new("ns:someattr", "some_value")
+ out = REXML::Attribute.new("out:something", "some_other_value")
+
+ ans.prefix.should == "ns"
+ out.prefix.should == "out"
+ end
+
+ it "returns an empty string for Attributes with no prefixes" do
+ attr = REXML::Attribute.new("foo", "bar")
+
+ attr.prefix.should == ""
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/remove_spec.rb b/spec/ruby/library/rexml/attribute/remove_spec.rb
new file mode 100644
index 0000000000..5f928b1286
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/remove_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#remove" do
+ before :each do
+ @e = REXML::Element.new "Root"
+ @attr = REXML::Attribute.new("foo", "bar")
+ end
+
+ it "deletes this Attribute from parent" do
+ @e.add_attribute(@attr)
+ @e.attributes["foo"].should_not == nil
+ @attr.remove
+ @e.attributes["foo"].should == nil
+ end
+
+ it "does not anything if element has no parent" do
+ -> {@attr.remove}.should_not raise_error(Exception)
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/to_s_spec.rb b/spec/ruby/library/rexml/attribute/to_s_spec.rb
new file mode 100644
index 0000000000..e362cee8f1
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/to_s_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#to_s" do
+ it "returns the value of the Attribute" do
+ REXML::Attribute.new("name", "some_value").to_s.should == "some_value"
+ end
+
+ it "returns the escaped value if it was created from Attribute" do
+ orig = REXML::Attribute.new("name", "<&>")
+ copy = REXML::Attribute.new(orig)
+ copy.to_s.should == "&lt;&amp;&gt;"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/to_string_spec.rb b/spec/ruby/library/rexml/attribute/to_string_spec.rb
new file mode 100644
index 0000000000..a9d249f5bb
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/to_string_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#to_string" do
+ it "returns the attribute as XML" do
+ attr = REXML::Attribute.new("name", "value")
+ attr_empty = REXML::Attribute.new("name")
+ attr_ns = REXML::Attribute.new("xmlns:ns", "http://uri")
+
+ attr.to_string.should == "name='value'"
+ attr_empty.to_string.should == "name=''"
+ attr_ns.to_string.should == "xmlns:ns='http://uri'"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/value_spec.rb b/spec/ruby/library/rexml/attribute/value_spec.rb
new file mode 100644
index 0000000000..77071f6f70
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/value_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#value" do
+ it "returns the value of the Attribute unnormalized" do
+ attr = REXML::Attribute.new("name", "value")
+ attr_ents = REXML::Attribute.new("name", "<&>")
+ attr_empty = REXML::Attribute.new("name")
+
+ attr.value.should == "value"
+ attr_ents.value.should == "<&>"
+ attr_empty.value.should == ""
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/write_spec.rb b/spec/ruby/library/rexml/attribute/write_spec.rb
new file mode 100644
index 0000000000..0012b3cc77
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/write_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#write" do
+ before :each do
+ @attr = REXML::Attribute.new("name", "Charlotte")
+ @s = ""
+ end
+
+ it "writes the name and value to output" do
+ @attr.write(@s)
+ @s.should == "name='Charlotte'"
+ end
+
+ it "currently ignores the second argument" do
+ @attr.write(@s, 3)
+ @s.should == "name='Charlotte'"
+
+ @s = ""
+ @attr.write(@s, "foo")
+ @s.should == "name='Charlotte'"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attribute/xpath_spec.rb b/spec/ruby/library/rexml/attribute/xpath_spec.rb
new file mode 100644
index 0000000000..0a09046b01
--- /dev/null
+++ b/spec/ruby/library/rexml/attribute/xpath_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attribute#xpath" do
+
+ before :each do
+ @e = REXML::Element.new "root"
+ @attr = REXML::Attribute.new("year", "1989")
+ end
+
+ it "returns the path for Attribute" do
+ @e.add_attribute @attr
+ @attr.xpath.should == "root/@year"
+ end
+
+ it "raises an error if attribute has no parent" do
+ -> { @attr.xpath }.should raise_error(Exception)
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/add_spec.rb b/spec/ruby/library/rexml/attributes/add_spec.rb
new file mode 100644
index 0000000000..e24e9fabbc
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/add_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require_relative 'shared/add'
+ require 'rexml/document'
+
+ describe "REXML::Attributes#add" do
+ it_behaves_like :rexml_attribute_add, :add
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/append_spec.rb b/spec/ruby/library/rexml/attributes/append_spec.rb
new file mode 100644
index 0000000000..f96a727f47
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/append_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require_relative 'shared/add'
+ require 'rexml/document'
+
+ describe "REXML::Attributes#<<" do
+ it_behaves_like :rexml_attribute_add, :<<
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/delete_all_spec.rb b/spec/ruby/library/rexml/attributes/delete_all_spec.rb
new file mode 100644
index 0000000000..707baa235b
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/delete_all_spec.rb
@@ -0,0 +1,34 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attributes#delete_all" do
+ before :each do
+ @e = REXML::Element.new("root")
+ end
+
+ it "deletes all attributes that match name" do
+ uri = REXML::Attribute.new("uri", "http://something")
+ @e.attributes << uri
+ @e.attributes.delete_all("uri")
+ @e.attributes.should be_empty
+ @e.attributes["uri"].should == nil
+ end
+
+ it "deletes all attributes that match name with a namespace" do
+ ns_uri = REXML::Attribute.new("xmlns:uri", "http://something_here_too")
+ @e.attributes << ns_uri
+ @e.attributes.delete_all("xmlns:uri")
+ @e.attributes.should be_empty
+ @e.attributes["xmlns:uri"].should == nil
+ end
+
+ it "returns the removed attribute" do
+ uri = REXML::Attribute.new("uri", "http://something_here_too")
+ @e.attributes << uri
+ attrs = @e.attributes.delete_all("uri")
+ attrs.first.should == uri
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/delete_spec.rb b/spec/ruby/library/rexml/attributes/delete_spec.rb
new file mode 100644
index 0000000000..723fa70751
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/delete_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attributes#delete" do
+ before :each do
+ @e = REXML::Element.new("root")
+ @name = REXML::Attribute.new("name", "Pepe")
+ end
+
+ it "takes an attribute name and deletes the attribute" do
+ @e.attributes.delete("name")
+ @e.attributes["name"].should be_nil
+ @e.attributes.should be_empty
+ end
+
+ it "takes an Attribute and deletes it" do
+ @e.attributes.delete(@name)
+ @e.attributes["name"].should be_nil
+ @e.attributes.should be_empty
+ end
+
+ it "returns the element with the attribute removed" do
+ ret_val = @e.attributes.delete(@name)
+ ret_val.should == @e
+ ret_val.attributes.should be_empty
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/each_attribute_spec.rb b/spec/ruby/library/rexml/attributes/each_attribute_spec.rb
new file mode 100644
index 0000000000..692cf4f943
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/each_attribute_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attributes#each_attribute" do
+ it "iterates over the attributes yielding actual Attribute objects" do
+ e = REXML::Element.new("root")
+ name = REXML::Attribute.new("name", "Joe")
+ ns_uri = REXML::Attribute.new("xmlns:ns", "http://some_uri")
+ e.add_attribute name
+ e.add_attribute ns_uri
+
+ attributes = []
+
+ e.attributes.each_attribute do |attr|
+ attributes << attr
+ end
+
+ attributes = attributes.sort_by {|a| a.name }
+ attributes.first.should == name
+ attributes.last.should == ns_uri
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/each_spec.rb b/spec/ruby/library/rexml/attributes/each_spec.rb
new file mode 100644
index 0000000000..49add3b77b
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/each_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attributes#each" do
+ before :each do
+ @e = REXML::Element.new("root")
+ @name = REXML::Attribute.new("name", "Joe")
+ @ns_uri = REXML::Attribute.new("xmlns:ns", "http://some_uri")
+ @e.add_attribute @name
+ @e.add_attribute @ns_uri
+ end
+
+ it "iterates over the attributes yielding expanded-name/value" do
+ attributes = []
+ @e.attributes.each do |attr|
+ attr.should be_kind_of(Array)
+ attributes << attr
+ end
+ attributes = attributes.sort_by {|a| a.first }
+ attributes.first.should == ["name", "Joe"]
+ attributes.last.should == ["xmlns:ns", "http://some_uri"]
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/element_reference_spec.rb b/spec/ruby/library/rexml/attributes/element_reference_spec.rb
new file mode 100644
index 0000000000..0d089eaab2
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/element_reference_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attributes#[]" do
+ before :each do
+ @e = REXML::Element.new("root")
+ @lang = REXML::Attribute.new("language", "english")
+ @e.attributes << @lang
+ end
+
+ it "returns the value of an attribute" do
+ @e.attributes["language"].should == "english"
+ end
+
+ it "returns nil if the attribute does not exist" do
+ @e.attributes["chunky bacon"].should == nil
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/element_set_spec.rb b/spec/ruby/library/rexml/attributes/element_set_spec.rb
new file mode 100644
index 0000000000..834ad682a6
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/element_set_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attributes#[]=" do
+ before :each do
+ @e = REXML::Element.new("song")
+ @name = REXML::Attribute.new("name", "Holy Smoke!")
+ @e.attributes << @name
+ end
+
+ it "sets an attribute" do
+ @e.attributes["author"] = "_why's foxes"
+ @e.attributes["author"].should == "_why's foxes"
+ end
+
+ it "overwrites an existing attribute" do
+ @e.attributes["name"] = "Chunky Bacon"
+ @e.attributes["name"].should == "Chunky Bacon"
+ end
+
+ it "deletes an attribute is value is nil" do
+ @e.attributes["name"] = nil
+ @e.attributes.length.should == 0
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/get_attribute_ns_spec.rb b/spec/ruby/library/rexml/attributes/get_attribute_ns_spec.rb
new file mode 100644
index 0000000000..1109ff519c
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/get_attribute_ns_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attributes#get_attribute_ns" do
+ it "returns an attribute by name and namespace" do
+ e = REXML::Element.new("root")
+ attr = REXML::Attribute.new("xmlns:ns", "http://some_url")
+ e.attributes << attr
+ attr.prefix.should == "xmlns"
+ # This might be a bug in Attribute, commenting until those specs
+ # are ready
+ # e.attributes.get_attribute_ns(attr.prefix, "name").should == "http://some_url"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/get_attribute_spec.rb b/spec/ruby/library/rexml/attributes/get_attribute_spec.rb
new file mode 100644
index 0000000000..cc94191729
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/get_attribute_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attributes#get_attribute" do
+ before :each do
+ @e = REXML::Element.new("root")
+ @name = REXML::Attribute.new("name", "Dave")
+ @e.attributes << @name
+ end
+
+ it "fetches an attributes" do
+ @e.attributes.get_attribute("name").should == @name
+ end
+
+ it "fetches an namespaced attribute" do
+ ns_name = REXML::Attribute.new("im:name", "Murray")
+ @e.attributes << ns_name
+ @e.attributes.get_attribute("name").should == @name
+ @e.attributes.get_attribute("im:name").should == ns_name
+ end
+
+ it "returns an Attribute" do
+ @e.attributes.get_attribute("name").should be_kind_of(REXML::Attribute)
+ end
+
+ it "returns nil if it attribute does not exist" do
+ @e.attributes.get_attribute("fake").should be_nil
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/initialize_spec.rb b/spec/ruby/library/rexml/attributes/initialize_spec.rb
new file mode 100644
index 0000000000..42ec742e60
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/initialize_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attributes#initialize" do
+ it "is auto initialized by Element" do
+ e = REXML::Element.new "root"
+ e.attributes.should be_kind_of(REXML::Attributes)
+
+ e.attributes << REXML::Attribute.new("name", "Paul")
+ e.attributes["name"].should == "Paul"
+ end
+
+ it "receives a parent node" do
+ e = REXML::Element.new "root"
+ e.attributes << REXML::Attribute.new("name", "Vic")
+ e.attributes["name"].should == "Vic"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/length_spec.rb b/spec/ruby/library/rexml/attributes/length_spec.rb
new file mode 100644
index 0000000000..81733b4a96
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/length_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require_relative 'shared/length'
+ require 'rexml/document'
+
+ describe "REXML::Attributes#length" do
+ it_behaves_like :rexml_attribute_length, :length
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/namespaces_spec.rb b/spec/ruby/library/rexml/attributes/namespaces_spec.rb
new file mode 100644
index 0000000000..b88346854f
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/namespaces_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attributes#namespaces" do
+ it "needs to be reviewed for spec completeness"
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/prefixes_spec.rb b/spec/ruby/library/rexml/attributes/prefixes_spec.rb
new file mode 100644
index 0000000000..574b7ffbaf
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/prefixes_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attributes#prefixes" do
+ before :each do
+ @e = REXML::Element.new("root")
+ a1 = REXML::Attribute.new("xmlns:a", "bar")
+ a2 = REXML::Attribute.new("xmlns:b", "bla")
+ a3 = REXML::Attribute.new("xmlns:c", "baz")
+ @e.attributes << a1
+ @e.attributes << a2
+ @e.attributes << a3
+
+ @e.attributes << REXML::Attribute.new("xmlns", "foo")
+ end
+
+ it "returns an array with the prefixes of each attribute" do
+ @e.attributes.prefixes.sort.should == ["a", "b", "c"]
+ end
+
+ it "does not include the default namespace" do
+ @e.attributes.prefixes.include?("xmlns").should == false
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/shared/add.rb b/spec/ruby/library/rexml/attributes/shared/add.rb
new file mode 100644
index 0000000000..872f149f45
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/shared/add.rb
@@ -0,0 +1,17 @@
+describe :rexml_attribute_add, shared: true do
+ before :each do
+ @e = REXML::Element.new("root")
+ @attr = REXML::Attributes.new(@e)
+ @name = REXML::Attribute.new("name", "Joe")
+ end
+
+ it "adds an attribute" do
+ @attr.send(@method, @name)
+ @attr["name"].should == "Joe"
+ end
+
+ it "replaces an existing attribute" do
+ @attr.send(@method, REXML::Attribute.new("name", "Bruce"))
+ @attr["name"].should == "Bruce"
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/shared/length.rb b/spec/ruby/library/rexml/attributes/shared/length.rb
new file mode 100644
index 0000000000..7848f9bf33
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/shared/length.rb
@@ -0,0 +1,13 @@
+require_relative '../../../../spec_helper'
+require 'rexml/document'
+
+describe :rexml_attribute_length, shared: true do
+ it "returns the number of attributes" do
+ e = REXML::Element.new("root")
+ e.attributes.send(@method).should == 0
+
+ e.attributes << REXML::Attribute.new("name", "John")
+ e.attributes << REXML::Attribute.new("another_name", "Leo")
+ e.attributes.send(@method).should == 2
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/size_spec.rb b/spec/ruby/library/rexml/attributes/size_spec.rb
new file mode 100644
index 0000000000..13ef08f644
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/size_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require_relative 'shared/length'
+ require 'rexml/document'
+
+ describe "REXML::Attributes#size" do
+ it_behaves_like :rexml_attribute_length, :size
+ end
+end
diff --git a/spec/ruby/library/rexml/attributes/to_a_spec.rb b/spec/ruby/library/rexml/attributes/to_a_spec.rb
new file mode 100644
index 0000000000..902cd86a29
--- /dev/null
+++ b/spec/ruby/library/rexml/attributes/to_a_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Attributes#to_a" do
+ it "returns an array with the attributes" do
+ e = REXML::Element.new("root")
+ name = REXML::Attribute.new("name", "Dave")
+ last = REXML::Attribute.new("last_name", "Murray")
+
+ e.attributes << name
+ e.attributes << last
+
+ e.attributes.to_a.sort{|a,b|a.to_s<=>b.to_s}.should == [name, last]
+ end
+
+ it "returns an empty array if it has no attributes" do
+ REXML::Element.new("root").attributes.to_a.should == []
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/cdata/clone_spec.rb b/spec/ruby/library/rexml/cdata/clone_spec.rb
new file mode 100644
index 0000000000..abe1a0b062
--- /dev/null
+++ b/spec/ruby/library/rexml/cdata/clone_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::CData#clone" do
+ it "makes a copy of itself" do
+ c = REXML::CData.new("some text")
+ c.clone.to_s.should == c.to_s
+ c.clone.should == c
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/cdata/initialize_spec.rb b/spec/ruby/library/rexml/cdata/initialize_spec.rb
new file mode 100644
index 0000000000..1393d97f4a
--- /dev/null
+++ b/spec/ruby/library/rexml/cdata/initialize_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::CData#initialize" do
+ it "creates a new CData object" do
+ c = REXML::CData.new("some text")
+ c.should be_kind_of(REXML::CData)
+ c.should be_kind_of(REXML::Text)
+ end
+
+ it "respects whitespace if whitespace is true" do
+ c = REXML::CData.new("whitespace test", true)
+ c1 = REXML::CData.new("whitespace test", false)
+
+ c.to_s.should == "whitespace test"
+ c1.to_s.should == "whitespace test"
+ end
+
+ it "receives parent as third argument" do
+ e = REXML::Element.new("root")
+ REXML::CData.new("test", true, e)
+ e.to_s.should == "<root><![CDATA[test]]></root>"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/cdata/shared/to_s.rb b/spec/ruby/library/rexml/cdata/shared/to_s.rb
new file mode 100644
index 0000000000..f8c4951c95
--- /dev/null
+++ b/spec/ruby/library/rexml/cdata/shared/to_s.rb
@@ -0,0 +1,11 @@
+describe :rexml_cdata_to_s, shared: true do
+ it "returns the contents of the CData" do
+ c = REXML::CData.new("some text")
+ c.send(@method).should == "some text"
+ end
+
+ it "does not escape text" do
+ c1 = REXML::CData.new("some& text\n")
+ c1.send(@method).should == "some& text\n"
+ end
+end
diff --git a/spec/ruby/library/rexml/cdata/to_s_spec.rb b/spec/ruby/library/rexml/cdata/to_s_spec.rb
new file mode 100644
index 0000000000..a5c061f116
--- /dev/null
+++ b/spec/ruby/library/rexml/cdata/to_s_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require_relative 'shared/to_s'
+ require 'rexml/document'
+
+ describe "REXML::CData#to_s" do
+ it_behaves_like :rexml_cdata_to_s, :to_s
+ end
+end
diff --git a/spec/ruby/library/rexml/cdata/value_spec.rb b/spec/ruby/library/rexml/cdata/value_spec.rb
new file mode 100644
index 0000000000..9f36226976
--- /dev/null
+++ b/spec/ruby/library/rexml/cdata/value_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require_relative 'shared/to_s'
+ require 'rexml/document'
+
+ describe "REXML::CData#value" do
+ it_behaves_like :rexml_cdata_to_s, :value
+ end
+end
diff --git a/spec/ruby/library/rexml/document/add_element_spec.rb b/spec/ruby/library/rexml/document/add_element_spec.rb
new file mode 100644
index 0000000000..29dec0b24e
--- /dev/null
+++ b/spec/ruby/library/rexml/document/add_element_spec.rb
@@ -0,0 +1,34 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Document#add_element" do
+ it "adds arg1 with attributes arg2 as root node" do
+ d = REXML::Document.new
+ e = REXML::Element.new("root")
+ d.add_element e
+ d.root.should == e
+ end
+
+ it "sets arg2 as arg1's attributes" do
+ d = REXML::Document.new
+ e = REXML::Element.new("root")
+ attr = {"foo" => "bar"}
+ d.add_element(e,attr)
+ d.root.attributes["foo"].should == attr["foo"]
+ end
+
+ it "accepts a node name as arg1 and adds it as root" do
+ d = REXML::Document.new
+ d.add_element "foo"
+ d.root.name.should == "foo"
+ end
+
+ it "sets arg1's context to the root's context" do
+ d = REXML::Document.new("", {"foo" => "bar"})
+ d.add_element "foo"
+ d.root.context.should == d.context
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/document/add_spec.rb b/spec/ruby/library/rexml/document/add_spec.rb
new file mode 100644
index 0000000000..8666d3dbf9
--- /dev/null
+++ b/spec/ruby/library/rexml/document/add_spec.rb
@@ -0,0 +1,60 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ # This spec defines Document#add and Document#<<
+
+ describe :rexml_document_add, shared: true do
+ before :each do
+ @doc = REXML::Document.new("<root/>")
+ @decl = REXML::XMLDecl.new("1.0")
+ end
+
+ it "sets document's XML declaration" do
+ @doc.send(@method, @decl)
+ @doc.xml_decl.should == @decl
+ end
+
+ it "inserts XML declaration as first node" do
+ @doc.send(@method, @decl)
+ @doc.children[0].version.should == "1.0"
+ end
+
+ it "overwrites existing XML declaration" do
+ @doc.send(@method, @decl)
+ @doc.send(@method, REXML::XMLDecl.new("2.0"))
+ @doc.xml_decl.version.should == "2.0"
+ end
+
+ it "sets document DocType" do
+ @doc.send(@method, REXML::DocType.new("transitional"))
+ @doc.doctype.name.should == "transitional"
+ end
+
+ it "overwrites existing DocType" do
+ @doc.send(@method, REXML::DocType.new("transitional"))
+ @doc.send(@method, REXML::DocType.new("strict"))
+ @doc.doctype.name.should == "strict"
+ end
+
+ it "adds root node unless it exists" do
+ d = REXML::Document.new("")
+ elem = REXML::Element.new "root"
+ d.send(@method, elem)
+ d.root.should == elem
+ end
+
+ it "refuses to add second root" do
+ -> { @doc.send(@method, REXML::Element.new("foo")) }.should raise_error(RuntimeError)
+ end
+ end
+
+ describe "REXML::Document#add" do
+ it_behaves_like :rexml_document_add, :add
+ end
+
+ describe "REXML::Document#<<" do
+ it_behaves_like :rexml_document_add, :<<
+ end
+end
diff --git a/spec/ruby/library/rexml/document/clone_spec.rb b/spec/ruby/library/rexml/document/clone_spec.rb
new file mode 100644
index 0000000000..137fe8a073
--- /dev/null
+++ b/spec/ruby/library/rexml/document/clone_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ # According to the MRI documentation (http://www.ruby-doc.org/stdlib/libdoc/rexml/rdoc/index.html),
+ # clone's behavior "should be obvious". Apparently "obvious" means cloning
+ # only the attributes and the context of the document, not its children.
+ describe "REXML::Document#clone" do
+ it "clones document attributes" do
+ d = REXML::Document.new("foo")
+ d.attributes["foo"] = "bar"
+ e = d.clone
+ e.attributes.should == d.attributes
+ end
+
+ it "clones document context" do
+ d = REXML::Document.new("foo", {"foo" => "bar"})
+ e = d.clone
+ e.context.should == d.context
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/document/doctype_spec.rb b/spec/ruby/library/rexml/document/doctype_spec.rb
new file mode 100644
index 0000000000..e1b7ba4916
--- /dev/null
+++ b/spec/ruby/library/rexml/document/doctype_spec.rb
@@ -0,0 +1,18 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Document#doctype" do
+ it "returns the doctype" do
+ d = REXML::Document.new
+ dt = REXML::DocType.new("foo")
+ d.add dt
+ d.doctype.should == dt
+ end
+
+ it "returns nil if there's no doctype" do
+ REXML::Document.new.doctype.should == nil
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/document/encoding_spec.rb b/spec/ruby/library/rexml/document/encoding_spec.rb
new file mode 100644
index 0000000000..2cc947f06a
--- /dev/null
+++ b/spec/ruby/library/rexml/document/encoding_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Document#encoding" do
+ before :each do
+ @doc = REXML::Document.new
+ end
+
+ it "returns encoding from XML declaration" do
+ @doc.add REXML::XMLDecl.new(nil, "UTF-16", nil)
+ @doc.encoding.should == "UTF-16"
+ end
+
+ it "returns encoding from XML declaration (for UTF-16 as well)" do
+ @doc.add REXML::XMLDecl.new("1.0", "UTF-8", nil)
+ @doc.encoding.should == "UTF-8"
+ end
+
+ it "uses UTF-8 as default encoding" do
+ @doc.encoding.should == "UTF-8"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/document/expanded_name_spec.rb b/spec/ruby/library/rexml/document/expanded_name_spec.rb
new file mode 100644
index 0000000000..9d1025b5e0
--- /dev/null
+++ b/spec/ruby/library/rexml/document/expanded_name_spec.rb
@@ -0,0 +1,19 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe :document_expanded_name, shared: true do
+ it "returns an empty string for root" do # root nodes have no expanded name
+ REXML::Document.new.send(@method).should == ""
+ end
+ end
+
+ describe "REXML::Document#expanded_name" do
+ it_behaves_like :document_expanded_name, :expanded_name
+ end
+
+ describe "REXML::Document#name" do
+ it_behaves_like :document_expanded_name, :name
+ end
+end
diff --git a/spec/ruby/library/rexml/document/new_spec.rb b/spec/ruby/library/rexml/document/new_spec.rb
new file mode 100644
index 0000000000..4e24b6f5a1
--- /dev/null
+++ b/spec/ruby/library/rexml/document/new_spec.rb
@@ -0,0 +1,39 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Document#new" do
+
+ it "initializes context of {} unless specified" do
+ d = REXML::Document.new("<foo />")
+ d.context.should == {}
+ end
+
+ it "has empty attributes if source is nil" do
+ d = REXML::Document.new(nil)
+ d.elements.should be_empty
+ end
+
+ it "can use other document context" do
+ s = REXML::Document.new("")
+ d = REXML::Document.new(s)
+ d.context.should == s.context
+ end
+
+ it "clones source attributes" do
+ s = REXML::Document.new("<root />")
+ s.attributes["some_attr"] = "some_val"
+ d = REXML::Document.new(s)
+ d.attributes.should == s.attributes
+ end
+
+ it "raises an error if source is not a Document, String or IO" do
+ -> {REXML::Document.new(3)}.should raise_error(RuntimeError)
+ end
+
+ it "does not perform XML validation" do
+ REXML::Document.new("Invalid document").should be_kind_of(REXML::Document)
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/document/node_type_spec.rb b/spec/ruby/library/rexml/document/node_type_spec.rb
new file mode 100644
index 0000000000..b6d7e7a7da
--- /dev/null
+++ b/spec/ruby/library/rexml/document/node_type_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Document#node_type" do
+ it "returns :document" do
+ REXML::Document.new.node_type.should == :document
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/document/root_spec.rb b/spec/ruby/library/rexml/document/root_spec.rb
new file mode 100644
index 0000000000..1a584a720b
--- /dev/null
+++ b/spec/ruby/library/rexml/document/root_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Document#root" do
+ it "returns document root tag name" do
+ REXML::Document.new("<foo/>").root.name.should == "foo"
+ end
+
+ it "returns nil if there is not root" do
+ REXML::Document.new.root.should == nil
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/document/stand_alone_spec.rb b/spec/ruby/library/rexml/document/stand_alone_spec.rb
new file mode 100644
index 0000000000..e1c721e782
--- /dev/null
+++ b/spec/ruby/library/rexml/document/stand_alone_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Document#stand_alone?" do
+ it "returns the XMLDecl standalone value" do
+ d = REXML::Document.new
+ decl = REXML::XMLDecl.new("1.0", "UTF-8", "yes")
+ d.add decl
+ d.stand_alone?.should == "yes"
+ end
+
+ # According to the docs this should return the default XMLDecl but that
+ # will carry some more problems when printing the document. Currently, it
+ # returns nil. See http://www.ruby-forum.com/topic/146812#650061
+ it "returns the default value when no XML declaration present" do
+ REXML::Document.new.stand_alone?.should == nil
+ end
+
+ end
+end
diff --git a/spec/ruby/library/rexml/document/version_spec.rb b/spec/ruby/library/rexml/document/version_spec.rb
new file mode 100644
index 0000000000..4f6b40551b
--- /dev/null
+++ b/spec/ruby/library/rexml/document/version_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Document#version" do
+ it "returns XML version from declaration" do
+ d = REXML::Document.new
+ d.add REXML::XMLDecl.new("1.1")
+ d.version.should == "1.1"
+ end
+
+ it "returns the default version when declaration is not present" do
+ REXML::Document.new.version.should == REXML::XMLDecl::DEFAULT_VERSION
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/document/write_spec.rb b/spec/ruby/library/rexml/document/write_spec.rb
new file mode 100644
index 0000000000..00c22141b3
--- /dev/null
+++ b/spec/ruby/library/rexml/document/write_spec.rb
@@ -0,0 +1,38 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+ require 'rexml/formatters/transitive'
+
+ # Maybe this can be cleaned
+ describe "REXML::Document#write" do
+ before :each do
+ @d = REXML::Document.new
+ city = REXML::Element.new "Springfield"
+ street = REXML::Element.new "EvergreenTerrace"
+ address = REXML::Element.new "House742"
+ @d << city << street << address
+ @str = ""
+ end
+
+ it "returns document source as string" do
+ @d.write(@str)
+ @str.should == "<Springfield><EvergreenTerrace><House742/></EvergreenTerrace></Springfield>"
+ end
+
+ it "returns document indented" do
+ @d.write(@str, 2)
+ @str.should =~ /\s*<Springfield>\s*<EvergreenTerrace>\s*<House742\/>\s*<\/EvergreenTerrace>\s*<\/Springfield>/
+ end
+
+ it "returns document with transitive support" do
+ @d.write(@str, 2, true)
+ @str.should =~ /\s*<Springfield\s*><EvergreenTerrace\s*><House742\s*\/><\/EvergreenTerrace\s*><\/Springfield\s*>/
+ end
+
+ it "returns document with support for IE" do
+ @d.write(@str, -1, false, true)
+ @str.should == "<Springfield><EvergreenTerrace><House742 /></EvergreenTerrace></Springfield>"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/document/xml_decl_spec.rb b/spec/ruby/library/rexml/document/xml_decl_spec.rb
new file mode 100644
index 0000000000..8ac47510b0
--- /dev/null
+++ b/spec/ruby/library/rexml/document/xml_decl_spec.rb
@@ -0,0 +1,18 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Document#xml_decl" do
+ it "returns XML declaration of the document" do
+ d = REXML::Document.new
+ decl = REXML::XMLDecl.new("1.0", "UTF-16", "yes")
+ d.add decl
+ d.xml_decl.should == decl
+ end
+
+ it "returns default XML declaration unless present" do
+ REXML::Document.new.xml_decl.should == REXML::XMLDecl.new
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/add_attribute_spec.rb b/spec/ruby/library/rexml/element/add_attribute_spec.rb
new file mode 100644
index 0000000000..64f2ec84a3
--- /dev/null
+++ b/spec/ruby/library/rexml/element/add_attribute_spec.rb
@@ -0,0 +1,44 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#add_attribute" do
+ before :each do
+ @person = REXML::Element.new "person"
+ @person.attributes["name"] = "Bill"
+ end
+
+ it "adds a new attribute" do
+ @person.add_attribute("age", "17")
+ @person.attributes["age"].should == "17"
+ end
+
+ it "overwrites an existing attribute" do
+ @person.add_attribute("name", "Bill")
+ @person.attributes["name"].should == "Bill"
+ end
+
+ it "accepts a pair of strings" do
+ @person.add_attribute("male", "true")
+ @person.attributes["male"].should == "true"
+ end
+
+ it "accepts an Attribute for key" do
+ attr = REXML::Attribute.new("male", "true")
+ @person.add_attribute attr
+ @person.attributes["male"].should == "true"
+ end
+
+ it "ignores value if key is an Attribute" do
+ attr = REXML::Attribute.new("male", "true")
+ @person.add_attribute(attr, "false")
+ @person.attributes["male"].should == "true"
+ end
+
+ it "returns the attribute added" do
+ attr = REXML::Attribute.new("name", "Tony")
+ @person.add_attribute(attr).should == attr
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/add_attributes_spec.rb b/spec/ruby/library/rexml/element/add_attributes_spec.rb
new file mode 100644
index 0000000000..f331803dd8
--- /dev/null
+++ b/spec/ruby/library/rexml/element/add_attributes_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#add_attributes" do
+ before :each do
+ @person = REXML::Element.new "person"
+ @person.attributes["name"] = "Bill"
+ end
+
+ it "adds multiple attributes from a hash" do
+ @person.add_attributes({"name" => "Joe", "age" => "27"})
+ @person.attributes["name"].should == "Joe"
+ @person.attributes["age"].should == "27"
+ end
+
+ it "adds multiple attributes from an array" do
+ attrs = { "name" => "Joe", "age" => "27"}
+ @person.add_attributes attrs.to_a
+ @person.attributes["name"].should == "Joe"
+ @person.attributes["age"].should == "27"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/add_element_spec.rb b/spec/ruby/library/rexml/element/add_element_spec.rb
new file mode 100644
index 0000000000..8ba023f2c7
--- /dev/null
+++ b/spec/ruby/library/rexml/element/add_element_spec.rb
@@ -0,0 +1,41 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#add_element" do
+ before :each do
+ @root = REXML::Element.new("root")
+ end
+
+ it "adds a child without attributes" do
+ name = REXML::Element.new("name")
+ @root.add_element name
+ @root.elements["name"].name.should == name.name
+ @root.elements["name"].attributes.should == name.attributes
+ @root.elements["name"].context.should == name.context
+ end
+
+ it "adds a child with attributes" do
+ person = REXML::Element.new("person")
+ @root.add_element(person, {"name" => "Madonna"})
+ @root.elements["person"].name.should == person.name
+ @root.elements["person"].attributes.should == person.attributes
+ @root.elements["person"].context.should == person.context
+ end
+
+ it "adds a child with name" do
+ @root.add_element "name"
+ @root.elements["name"].name.should == "name"
+ @root.elements["name"].attributes.should == {}
+ @root.elements["name"].context.should == nil
+ end
+
+ it "returns the added child" do
+ name = @root.add_element "name"
+ @root.elements["name"].name.should == name.name
+ @root.elements["name"].attributes.should == name.attributes
+ @root.elements["name"].context.should == name.context
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/add_namespace_spec.rb b/spec/ruby/library/rexml/element/add_namespace_spec.rb
new file mode 100644
index 0000000000..44b074bac7
--- /dev/null
+++ b/spec/ruby/library/rexml/element/add_namespace_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#add_namespace" do
+ before :each do
+ @elem = REXML::Element.new("person")
+ end
+
+ it "adds a namespace to element" do
+ @elem.add_namespace("foo", "bar")
+ @elem.namespace("foo").should == "bar"
+ end
+
+ it "accepts a prefix string as prefix" do
+ @elem.add_namespace("xmlns:foo", "bar")
+ @elem.namespace("foo").should == "bar"
+ end
+
+ it "uses prefix as URI if uri is nil" do
+ @elem.add_namespace("some_uri", nil)
+ @elem.namespace.should == "some_uri"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/add_text_spec.rb b/spec/ruby/library/rexml/element/add_text_spec.rb
new file mode 100644
index 0000000000..3a0531ad42
--- /dev/null
+++ b/spec/ruby/library/rexml/element/add_text_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#add_text" do
+ before :each do
+ @name = REXML::Element.new "Name"
+ end
+
+ it "adds text to an element" do
+ @name.add_text "Ringo"
+ @name.to_s.should == "<Name>Ringo</Name>"
+ end
+
+ it "accepts a Text" do
+ @name.add_text(REXML::Text.new("Ringo"))
+ @name.to_s.should == "<Name>Ringo</Name>"
+ end
+
+ it "joins the new text with the old one" do
+ @name.add_text "Ringo"
+ @name.add_text " Starr"
+ @name.to_s.should == "<Name>Ringo Starr</Name>"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/attribute_spec.rb b/spec/ruby/library/rexml/element/attribute_spec.rb
new file mode 100644
index 0000000000..b223d3440c
--- /dev/null
+++ b/spec/ruby/library/rexml/element/attribute_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#attribute" do
+ it "returns an attribute by name" do
+ person = REXML::Element.new "Person"
+ attribute = REXML::Attribute.new("drink", "coffee")
+ person.add_attribute(attribute)
+ person.attribute("drink").should == attribute
+ end
+
+ it "supports attributes inside namespaces" do
+ e = REXML::Element.new("element")
+ e.add_attributes({"xmlns:ns" => "http://some_uri"})
+ e.attribute("ns", "ns").to_s.should == "http://some_uri"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/attributes_spec.rb b/spec/ruby/library/rexml/element/attributes_spec.rb
new file mode 100644
index 0000000000..92bcecc40a
--- /dev/null
+++ b/spec/ruby/library/rexml/element/attributes_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#attributes" do
+ it "returns element's Attributes" do
+ p = REXML::Element.new "Person"
+
+ name = REXML::Attribute.new("name", "John")
+ attrs = REXML::Attributes.new(p)
+ attrs.add name
+
+ p.add_attribute name
+ p.attributes.should == attrs
+ end
+
+ it "returns an empty hash if element has no attributes" do
+ REXML::Element.new("Person").attributes.should == {}
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/cdatas_spec.rb b/spec/ruby/library/rexml/element/cdatas_spec.rb
new file mode 100644
index 0000000000..988b2cb422
--- /dev/null
+++ b/spec/ruby/library/rexml/element/cdatas_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#cdatas" do
+ before :each do
+ @e = REXML::Element.new("Root")
+ end
+
+ it "returns the array of children cdatas" do
+ c = REXML::CData.new("Primary")
+ d = REXML::CData.new("Secondary")
+ @e << c
+ @e << d
+ @e.cdatas.should == [c, d]
+ end
+
+ it "freezes the returned array" do
+ @e.cdatas.should.frozen?
+ end
+
+ it "returns an empty array if element has no cdata" do
+ @e.cdatas.should == []
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/clone_spec.rb b/spec/ruby/library/rexml/element/clone_spec.rb
new file mode 100644
index 0000000000..490e43181f
--- /dev/null
+++ b/spec/ruby/library/rexml/element/clone_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#clone" do
+ before :each do
+ @e = REXML::Element.new "a"
+ end
+ it "creates a copy of element" do
+ @e.clone.to_s.should == @e.to_s
+ end
+
+ it "copies the attributes" do
+ @e.add_attribute("foo", "bar")
+ @e.clone.to_s.should == @e.to_s
+ end
+
+ it "does not copy the text" do
+ @e.add_text "some text..."
+ @e.clone.to_s.should_not == @e
+ @e.clone.to_s.should == "<a/>"
+ end
+
+ it "does not copy the child elements" do
+ b = REXML::Element.new "b"
+ @e << b
+ @e.clone.should_not == @e
+ @e.clone.to_s.should == "<a/>"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/comments_spec.rb b/spec/ruby/library/rexml/element/comments_spec.rb
new file mode 100644
index 0000000000..84ab9a7469
--- /dev/null
+++ b/spec/ruby/library/rexml/element/comments_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#comments" do
+ before :each do
+ @e = REXML::Element.new "root"
+ @c1 = REXML::Comment.new "this is a comment"
+ @c2 = REXML::Comment.new "this is another comment"
+ @e << @c1
+ @e << @c2
+ end
+
+ it "returns the array of comments" do
+ @e.comments.should == [@c1, @c2]
+ end
+
+ it "returns a frozen object" do
+ @e.comments.should.frozen?
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/delete_attribute_spec.rb b/spec/ruby/library/rexml/element/delete_attribute_spec.rb
new file mode 100644
index 0000000000..e2ba81eb0d
--- /dev/null
+++ b/spec/ruby/library/rexml/element/delete_attribute_spec.rb
@@ -0,0 +1,42 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#delete_attribute" do
+ before :each do
+ @e = REXML::Element.new("Person")
+ @attr = REXML::Attribute.new("name", "Sean")
+ @e.add_attribute(@attr)
+ end
+
+ it "deletes an attribute from the element" do
+ @e.delete_attribute("name")
+ @e.attributes["name"].should be_nil
+ end
+
+ # Bug was filled with a patch in Ruby's tracker #20298
+ quarantine! do
+ it "receives an Attribute" do
+ @e.add_attribute(@attr)
+ @e.delete_attribute(@attr)
+ @e.attributes["name"].should be_nil
+ end
+ end
+
+ # Docs say that it returns the removed attribute but then examples
+ # show it returns the element with the attribute removed.
+ # Also fixed in #20298
+ it "returns the element with the attribute removed" do
+ elem = @e.delete_attribute("name")
+ elem.attributes.should be_empty
+ elem.to_s.should eql("<Person/>")
+ end
+
+ it "returns nil if the attribute does not exist" do
+ @e.delete_attribute("name")
+ at = @e.delete_attribute("name")
+ at.should be_nil
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/delete_element_spec.rb b/spec/ruby/library/rexml/element/delete_element_spec.rb
new file mode 100644
index 0000000000..c0b486a6f7
--- /dev/null
+++ b/spec/ruby/library/rexml/element/delete_element_spec.rb
@@ -0,0 +1,52 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#delete_element" do
+ before :each do
+ @root = REXML::Element.new("root")
+ end
+
+ it "deletes the child element" do
+ node = REXML::Element.new("some_node")
+ @root.add_element node
+ @root.delete_element node
+ @root.elements.size.should == 0
+ end
+
+ it "deletes a child via XPath" do
+ @root.add_element "some_node"
+ @root.delete_element "some_node"
+ @root.elements.size.should == 0
+ end
+
+ it "deletes the child at index" do
+ @root.add_element "some_node"
+ @root.delete_element 1
+ @root.elements.size.should == 0
+ end
+
+ # According to the docs this should return the deleted element
+ # but it won't if it's an Element.
+ it "deletes Element and returns it" do
+ node = REXML::Element.new("some_node")
+ @root.add_element node
+ del_node = @root.delete_element node
+ del_node.should == node
+ end
+
+ # Note how passing the string will return the removed element
+ # but passing the Element as above won't.
+ it "deletes an element and returns it" do
+ node = REXML::Element.new("some_node")
+ @root.add_element node
+ del_node = @root.delete_element "some_node"
+ del_node.should == node
+ end
+
+ it "returns nil unless element exists" do
+ @root.delete_element("something").should == nil
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/delete_namespace_spec.rb b/spec/ruby/library/rexml/element/delete_namespace_spec.rb
new file mode 100644
index 0000000000..a7763d51e8
--- /dev/null
+++ b/spec/ruby/library/rexml/element/delete_namespace_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#delete_namespace" do
+
+ before :each do
+ @doc = REXML::Document.new "<a xmlns:foo='bar' xmlns='twiddle'/>"
+ end
+
+ it "deletes a namespace from the element" do
+ @doc.root.delete_namespace 'foo'
+ @doc.root.namespace("foo").should be_nil
+ @doc.root.to_s.should == "<a xmlns='twiddle'/>"
+ end
+
+ it "deletes default namespace when called with no args" do
+ @doc.root.delete_namespace
+ @doc.root.namespace.should be_empty
+ @doc.root.to_s.should == "<a xmlns:foo='bar'/>"
+ end
+
+ it "returns the element" do
+ @doc.root.delete_namespace.should == @doc.root
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/document_spec.rb b/spec/ruby/library/rexml/element/document_spec.rb
new file mode 100644
index 0000000000..754f27d8a0
--- /dev/null
+++ b/spec/ruby/library/rexml/element/document_spec.rb
@@ -0,0 +1,19 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#document" do
+
+ it "returns the element's document" do
+ d = REXML::Document.new("<root><elem/></root>")
+ d << REXML::XMLDecl.new
+ d.root.document.should == d
+ d.root.document.to_s.should == d.to_s
+ end
+
+ it "returns nil if it belongs to no document" do
+ REXML::Element.new("standalone").document.should be_nil
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/each_element_with_attribute_spec.rb b/spec/ruby/library/rexml/element/each_element_with_attribute_spec.rb
new file mode 100644
index 0000000000..dcc6dbbf17
--- /dev/null
+++ b/spec/ruby/library/rexml/element/each_element_with_attribute_spec.rb
@@ -0,0 +1,38 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#each_element_with_attributes" do
+ before :each do
+ @document = REXML::Element.new("people")
+ @father = REXML::Element.new("Person")
+ @father.attributes["name"] = "Joe"
+ @son = REXML::Element.new("Child")
+ @son.attributes["name"] = "Fred"
+ @document.root << @father
+ @document.root << @son
+ @children = []
+ end
+
+ it "returns children with attribute" do
+ @document.each_element_with_attribute("name") { |elem| @children << elem }
+ @children[0].should == @father
+ @children[1].should == @son
+ end
+
+ it "takes attribute value as second argument" do
+ @document.each_element_with_attribute("name", "Fred"){ |elem| elem.should == @son }
+ end
+
+ it "takes max number of children as third argument" do
+ @document.each_element_with_attribute("name", nil, 1) { |elem| @children << elem }
+ @children.size.should == 1
+ @children[0].should == @father
+ end
+
+ it "takes XPath filter as fourth argument" do
+ @document.each_element_with_attribute("name", nil, 0, "Child"){ |elem| elem.should == @son}
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/each_element_with_text_spec.rb b/spec/ruby/library/rexml/element/each_element_with_text_spec.rb
new file mode 100644
index 0000000000..a4a200d237
--- /dev/null
+++ b/spec/ruby/library/rexml/element/each_element_with_text_spec.rb
@@ -0,0 +1,34 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#each_element_with_text" do
+ before :each do
+ @document = REXML::Element.new("people")
+
+ @joe = REXML::Element.new("Person")
+ @joe.text = "Joe"
+ @fred = REXML::Element.new("Person")
+ @fred.text = "Fred"
+ @another = REXML::Element.new("AnotherPerson")
+ @another.text = "Fred"
+ @document.root << @joe
+ @document.root << @fred
+ @document.root << @another
+ @children = []
+ end
+
+ it "returns children with text" do
+ @document.each_element_with_text("Joe"){|c| c.should == @joe}
+ end
+
+ it "takes max as second argument" do
+ @document.each_element_with_text("Fred", 1){ |c| c.should == @fred}
+ end
+
+ it "takes XPath filter as third argument" do
+ @document.each_element_with_text("Fred", 0, "Person"){ |c| c.should == @fred}
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/element_reference_spec.rb b/spec/ruby/library/rexml/element/element_reference_spec.rb
new file mode 100644
index 0000000000..9e5d371ce4
--- /dev/null
+++ b/spec/ruby/library/rexml/element/element_reference_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#[]" do
+
+ before :each do
+ @doc = REXML::Document.new("<root foo='bar'></root>")
+ @child = REXML::Element.new("child")
+ @doc.root.add_element @child
+ end
+
+ it "return attribute value if argument is string or symbol" do
+ @doc.root[:foo].should == 'bar'
+ @doc.root['foo'].should == 'bar'
+ end
+
+ it "return nth element if argument is int" do
+ @doc.root[0].should == @child
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/get_text_spec.rb b/spec/ruby/library/rexml/element/get_text_spec.rb
new file mode 100644
index 0000000000..0fa8d7cb3f
--- /dev/null
+++ b/spec/ruby/library/rexml/element/get_text_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#get_text" do
+ before :each do
+ @doc = REXML::Document.new "<p>some text<b>this is bold!</b> more text</p>"
+ end
+
+ it "returns the first text child node" do
+ @doc.root.get_text.value.should == "some text"
+ @doc.root.get_text.should be_kind_of(REXML::Text)
+ end
+
+ it "returns text from an element matching path" do
+ @doc.root.get_text("b").value.should == "this is bold!"
+ @doc.root.get_text("b").should be_kind_of(REXML::Text)
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/has_attributes_spec.rb b/spec/ruby/library/rexml/element/has_attributes_spec.rb
new file mode 100644
index 0000000000..af3ce8ce1b
--- /dev/null
+++ b/spec/ruby/library/rexml/element/has_attributes_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#has_attributes?" do
+ before :each do
+ @e = REXML::Element.new("test_elem")
+ end
+
+ it "returns true when element has any attributes" do
+ @e.add_attribute("name", "Joe")
+ @e.has_attributes?.should be_true
+ end
+
+ it "returns false if element has no attributes" do
+ @e.has_attributes?.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/has_elements_spec.rb b/spec/ruby/library/rexml/element/has_elements_spec.rb
new file mode 100644
index 0000000000..04c7fe01a5
--- /dev/null
+++ b/spec/ruby/library/rexml/element/has_elements_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#has_elements?" do
+ before :each do
+ @e = REXML::Element.new("root")
+ end
+
+ it "returns true if element has child elements" do
+ child = REXML::Element.new("child")
+ @e << child
+ @e.has_elements?.should be_true
+ end
+
+ it "returns false if element doesn't have child elements" do
+ @e.has_elements?.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/has_text_spec.rb b/spec/ruby/library/rexml/element/has_text_spec.rb
new file mode 100644
index 0000000000..206c167ae6
--- /dev/null
+++ b/spec/ruby/library/rexml/element/has_text_spec.rb
@@ -0,0 +1,19 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#has_text?" do
+
+ it "returns true if element has a Text child" do
+ e = REXML::Element.new("Person")
+ e.text = "My text"
+ e.has_text?.should be_true
+ end
+
+ it "returns false if it has no Text children" do
+ e = REXML::Element.new("Person")
+ e.has_text?.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/inspect_spec.rb b/spec/ruby/library/rexml/element/inspect_spec.rb
new file mode 100644
index 0000000000..ec16c136ee
--- /dev/null
+++ b/spec/ruby/library/rexml/element/inspect_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#inspect" do
+
+ before :each do
+ @name = REXML::Element.new "name"
+ end
+
+ it "returns the node as a string" do
+ @name.inspect.should == "<name/>"
+ end
+
+ it "inserts '...' if the node has children" do
+ e = REXML::Element.new "last_name"
+ @name << e
+ @name.inspect.should == "<name> ... </>"
+ # This might make more sense but differs from MRI's default behavior
+ # @name.inspect.should == "<name> ... </name>"
+ end
+
+ it "inserts the attributes in the string" do
+ @name.add_attribute "language"
+ @name.attributes["language"] = "english"
+ @name.inspect.should == "<name language='english'/>"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/instructions_spec.rb b/spec/ruby/library/rexml/element/instructions_spec.rb
new file mode 100644
index 0000000000..11f1396df0
--- /dev/null
+++ b/spec/ruby/library/rexml/element/instructions_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#instructions" do
+ before :each do
+ @elem = REXML::Element.new("root")
+ end
+ it "returns the Instruction children nodes" do
+ inst = REXML::Instruction.new("xml-stylesheet", "href='headlines.css'")
+ @elem << inst
+ @elem.instructions.first.should == inst
+ end
+
+ it "returns an empty array if it has no Instruction children" do
+ @elem.instructions.should be_empty
+ end
+
+ it "freezes the returned array" do
+ @elem.instructions.frozen?.should be_true
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/namespace_spec.rb b/spec/ruby/library/rexml/element/namespace_spec.rb
new file mode 100644
index 0000000000..28966289c5
--- /dev/null
+++ b/spec/ruby/library/rexml/element/namespace_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#namespace" do
+ before :each do
+ @doc = REXML::Document.new("<a xmlns='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>")
+ @elem = @doc.elements["//b"]
+ end
+
+ it "returns the default namespace" do
+ @elem.namespace.should == "1"
+ end
+
+ it "accepts a namespace prefix" do
+ @elem.namespace("y").should == "2"
+ @doc.elements["//c"].namespace("z").should == "3"
+ end
+
+ it "returns an empty String if default namespace is not defined" do
+ e = REXML::Document.new("<a/>")
+ e.root.namespace.should be_empty
+ end
+
+ it "returns nil if namespace is not defined" do
+ @elem.namespace("z").should be_nil
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/namespaces_spec.rb b/spec/ruby/library/rexml/element/namespaces_spec.rb
new file mode 100644
index 0000000000..4544540173
--- /dev/null
+++ b/spec/ruby/library/rexml/element/namespaces_spec.rb
@@ -0,0 +1,35 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#namespaces" do
+ before :each do
+ doc = REXML::Document.new("<a xmlns='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>")
+ @elem = doc.elements["//c"]
+ end
+
+ it "returns a hash of the namespaces" do
+ ns = {"y"=>"2", "z"=>"3", "xmlns"=>"1"}
+ @elem.namespaces.keys.sort.should == ns.keys.sort
+ @elem.namespaces.values.sort.should == ns.values.sort
+ end
+
+ it "returns an empty hash if no namespaces exist" do
+ e = REXML::Element.new "element"
+ e.namespaces.kind_of?(Hash).should == true
+ e.namespaces.should be_empty
+ end
+
+ it "uses namespace prefixes as keys" do
+ prefixes = ["y", "z", "xmlns"]
+ @elem.namespaces.keys.sort.should == prefixes.sort
+ end
+
+ it "uses namespace values as the hash values" do
+ values = ["2", "3", "1"]
+ @elem.namespaces.values.sort.should == values.sort
+ end
+
+ end
+end
diff --git a/spec/ruby/library/rexml/element/new_spec.rb b/spec/ruby/library/rexml/element/new_spec.rb
new file mode 100644
index 0000000000..c6ab289476
--- /dev/null
+++ b/spec/ruby/library/rexml/element/new_spec.rb
@@ -0,0 +1,38 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#new" do
+
+ it "creates element from tag name" do
+ REXML::Element.new("foo").name.should == "foo"
+ end
+
+ it "creates element with default attributes" do
+ e = REXML::Element.new
+ e.name.should == REXML::Element::UNDEFINED
+ e.context.should == nil
+ e.parent.should == nil
+ end
+
+ it "creates element from another element" do
+ e = REXML::Element.new "foo"
+ f = REXML::Element.new e
+ e.name.should == f.name
+ e.context.should == f.context
+ e.parent.should == f.parent
+ end
+
+ it "takes parent as second argument" do
+ parent = REXML::Element.new "foo"
+ child = REXML::Element.new "bar", parent
+ child.parent.should == parent
+ end
+
+ it "takes context as third argument" do
+ context = {"some_key" => "some_value"}
+ REXML::Element.new("foo", nil, context).context.should == context
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/next_element_spec.rb b/spec/ruby/library/rexml/element/next_element_spec.rb
new file mode 100644
index 0000000000..46d8f74760
--- /dev/null
+++ b/spec/ruby/library/rexml/element/next_element_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#next_element" do
+ before :each do
+ @a = REXML::Element.new "a"
+ @b = REXML::Element.new "b"
+ @c = REXML::Element.new "c"
+ @a.root << @b
+ @a.root << @c
+ end
+ it "returns next existing element" do
+ @a.elements["b"].next_element.should == @c
+ end
+
+ it "returns nil on last element" do
+ @a.elements["c"].next_element.should == nil
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/node_type_spec.rb b/spec/ruby/library/rexml/element/node_type_spec.rb
new file mode 100644
index 0000000000..a39c2deca5
--- /dev/null
+++ b/spec/ruby/library/rexml/element/node_type_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#node_type" do
+ it "returns :element" do
+ REXML::Element.new("MyElem").node_type.should == :element
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/prefixes_spec.rb b/spec/ruby/library/rexml/element/prefixes_spec.rb
new file mode 100644
index 0000000000..ea4caab4bc
--- /dev/null
+++ b/spec/ruby/library/rexml/element/prefixes_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#prefixes" do
+ before :each do
+ doc = REXML::Document.new("<a xmlns='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>")
+ @elem = doc.elements["//c"]
+ end
+
+ it "returns an array of the prefixes of the namespaces" do
+ @elem.prefixes.should == ["y", "z"]
+ end
+
+ it "does not include the default namespace" do
+ @elem.prefixes.include?("xmlns").should == false
+ end
+
+ it "returns an empty array if no namespace was defined" do
+ doc = REXML::Document.new "<root><something/></root>"
+ root = doc.elements["//root"]
+ root.prefixes.should == []
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/previous_element_spec.rb b/spec/ruby/library/rexml/element/previous_element_spec.rb
new file mode 100644
index 0000000000..a43b1ddd10
--- /dev/null
+++ b/spec/ruby/library/rexml/element/previous_element_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#previous_element" do
+ before :each do
+ @a = REXML::Element.new "a"
+ @b = REXML::Element.new "b"
+ @c = REXML::Element.new "c"
+ @a.root << @b
+ @a.root << @c
+ end
+
+ it "returns previous element" do
+ @a.elements["c"].previous_element.should == @b
+ end
+
+ it "returns nil on first element" do
+ @a.elements["b"].previous_element.should == nil
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/raw_spec.rb b/spec/ruby/library/rexml/element/raw_spec.rb
new file mode 100644
index 0000000000..200a99d194
--- /dev/null
+++ b/spec/ruby/library/rexml/element/raw_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#raw" do
+ it "returns true if raw mode is set to all" do
+ REXML::Element.new("MyElem", nil, {raw: :all}).raw.should == true
+ end
+
+ it "returns true if raw mode is set to expanded_name" do
+ REXML::Element.new("MyElem", nil, {raw: "MyElem"}).raw.should == true
+ end
+
+ it "returns false if raw mode is not set" do
+ REXML::Element.new("MyElem", nil, {raw: ""}).raw.should == false
+ end
+
+ it "returns false if raw is not :all or expanded_name" do
+ REXML::Element.new("MyElem", nil, {raw: "Something"}).raw.should == false
+ end
+
+ it "returns nil if context is not set" do
+ REXML::Element.new("MyElem").raw.should == nil
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/root_spec.rb b/spec/ruby/library/rexml/element/root_spec.rb
new file mode 100644
index 0000000000..52aa4571b9
--- /dev/null
+++ b/spec/ruby/library/rexml/element/root_spec.rb
@@ -0,0 +1,31 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#root" do
+ before :each do
+ @doc = REXML::Document.new
+ @root = REXML::Element.new "root"
+ @node = REXML::Element.new "node"
+ @doc << @root << @node
+ end
+
+ it "returns first child on documents" do
+ @doc.root.should == @root
+ end
+
+ it "returns self on root nodes" do
+ @root.root.should == @root
+ end
+
+ it "returns parent's root on child nodes" do
+ @node.root.should == @root
+ end
+
+ it "returns self on standalone nodes" do
+ e = REXML::Element.new "Elem" # Note that it doesn't have a parent node
+ e.root.should == e
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/text_spec.rb b/spec/ruby/library/rexml/element/text_spec.rb
new file mode 100644
index 0000000000..3234bba153
--- /dev/null
+++ b/spec/ruby/library/rexml/element/text_spec.rb
@@ -0,0 +1,49 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#text" do
+ before :each do
+ @e = REXML::Element.new "name"
+ @e.text = "John"
+ end
+
+ it "returns the text node of element" do
+ @e.text.should == "John"
+ end
+
+ it "returns the text node value" do
+ t = REXML::Text.new "Joe"
+ @e.text = t
+ @e.text.should == "Joe"
+ @e.text.should_not == t
+ end
+
+ it "returns nil if no text is attached" do
+ elem = REXML::Element.new "name"
+ elem.text.should == nil
+ end
+ end
+
+ describe "REXML::Element#text=" do
+ before :each do
+ @e = REXML::Element.new "name"
+ @e.text = "John"
+ end
+
+ it "sets the text node" do
+ @e.to_s.should == "<name>John</name>"
+ end
+
+ it "replaces existing text" do
+ @e.text = "Joe"
+ @e.to_s.should == "<name>Joe</name>"
+ end
+
+ it "receives nil as an argument" do
+ @e.text = nil
+ @e.to_s.should == "<name/>"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/texts_spec.rb b/spec/ruby/library/rexml/element/texts_spec.rb
new file mode 100644
index 0000000000..2d374d5e66
--- /dev/null
+++ b/spec/ruby/library/rexml/element/texts_spec.rb
@@ -0,0 +1,19 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#texts" do
+
+ it "returns an array of the Text children" do
+ e = REXML::Element.new("root")
+ e.add_text "First"
+ e.add_text "Second"
+ e.texts.should == ["FirstSecond"]
+ end
+
+ it "returns an empty array if it has no Text children" do
+ REXML::Element.new("root").texts.should == []
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/element/whitespace_spec.rb b/spec/ruby/library/rexml/element/whitespace_spec.rb
new file mode 100644
index 0000000000..f455067922
--- /dev/null
+++ b/spec/ruby/library/rexml/element/whitespace_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Element#whitespace" do
+ it "returns true if whitespace is respected in the element" do
+ e = REXML::Element.new("root")
+ e.whitespace.should be_true
+
+ e = REXML::Element.new("root", nil, respect_whitespace: :all)
+ e.whitespace.should be_true
+
+ e = REXML::Element.new("root", nil, respect_whitespace: ["root"])
+ e.whitespace.should be_true
+ end
+
+ it "returns false if whitespace is ignored inside element" do
+ e = REXML::Element.new("root", nil, compress_whitespace: :all)
+ e.whitespace.should be_false
+
+ e = REXML::Element.new("root", nil, compress_whitespace: ["root"])
+ e.whitespace.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/node/each_recursive_spec.rb b/spec/ruby/library/rexml/node/each_recursive_spec.rb
new file mode 100644
index 0000000000..da347b1389
--- /dev/null
+++ b/spec/ruby/library/rexml/node/each_recursive_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Node#each_recursive" do
+ before :each do
+ @doc = REXML::Document.new
+ @doc << REXML::XMLDecl.new
+ @root = REXML::Element.new "root"
+ @child1 = REXML::Element.new "child1"
+ @child2 = REXML::Element.new "child2"
+ @root << @child1
+ @root << @child2
+ @doc << @root
+ end
+
+ it "visits all subnodes of self" do
+ nodes = []
+ @doc.each_recursive { |node| nodes << node}
+ nodes.should == [@root, @child1, @child2]
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/node/find_first_recursive_spec.rb b/spec/ruby/library/rexml/node/find_first_recursive_spec.rb
new file mode 100644
index 0000000000..2a4f1097ae
--- /dev/null
+++ b/spec/ruby/library/rexml/node/find_first_recursive_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Node#find_first_recursive" do
+ before :each do
+ @e = REXML::Element.new("root")
+ @node1 = REXML::Element.new("node")
+ @node2 = REXML::Element.new("another node")
+ @subnode = REXML::Element.new("another node")
+ @node1 << @subnode
+ @e << @node1
+ @e << @node2
+ end
+
+ it "finds the first element that matches block" do
+ found = @e.find_first_recursive { |n| n.to_s == "<node><another node/></node>"}
+ found.should == @node1
+ end
+
+ it "visits the nodes in preorder" do
+ found = @e.find_first_recursive { |n| n.to_s == "<another node/>"}
+ found.should == @subnode
+ found.should_not == @node2
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/node/index_in_parent_spec.rb b/spec/ruby/library/rexml/node/index_in_parent_spec.rb
new file mode 100644
index 0000000000..55909f86d6
--- /dev/null
+++ b/spec/ruby/library/rexml/node/index_in_parent_spec.rb
@@ -0,0 +1,18 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Node#index_in_parent" do
+ it "returns the index (starting from 1) of self in parent" do
+ e = REXML::Element.new("root")
+ node1 = REXML::Element.new("node")
+ node2 = REXML::Element.new("another node")
+ e << node1
+ e << node2
+
+ node1.index_in_parent.should == 1
+ node2.index_in_parent.should == 2
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/node/next_sibling_node_spec.rb b/spec/ruby/library/rexml/node/next_sibling_node_spec.rb
new file mode 100644
index 0000000000..7aae861d75
--- /dev/null
+++ b/spec/ruby/library/rexml/node/next_sibling_node_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Node#next_sibling_node" do
+ before :each do
+ @e = REXML::Element.new("root")
+ @node1 = REXML::Element.new("node")
+ @node2 = REXML::Element.new("another node")
+ @e << @node1
+ @e << @node2
+ end
+
+ it "returns the next child node in parent" do
+ @node1.next_sibling_node.should == @node2
+ end
+
+ it "returns nil if there are no more child nodes next" do
+ @node2.next_sibling_node.should == nil
+ @e.next_sibling_node.should == nil
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/node/parent_spec.rb b/spec/ruby/library/rexml/node/parent_spec.rb
new file mode 100644
index 0000000000..43c3a747e0
--- /dev/null
+++ b/spec/ruby/library/rexml/node/parent_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Node#parent?" do
+ it "returns true for Elements" do
+ e = REXML::Element.new("foo")
+ e.should.parent?
+ end
+
+ it "returns true for Documents" do
+ e = REXML::Document.new
+ e.should.parent?
+ end
+
+ # This includes attributes, CData and declarations.
+ it "returns false for Texts" do
+ e = REXML::Text.new("foo")
+ e.should_not.parent?
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/node/previous_sibling_node_spec.rb b/spec/ruby/library/rexml/node/previous_sibling_node_spec.rb
new file mode 100644
index 0000000000..11263968a7
--- /dev/null
+++ b/spec/ruby/library/rexml/node/previous_sibling_node_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Node#previous_sibling_node" do
+ before :each do
+ @e = REXML::Element.new("root")
+ @node1 = REXML::Element.new("node")
+ @node2 = REXML::Element.new("another node")
+ @e << @node1
+ @e << @node2
+ end
+
+ it "returns the previous child node in parent" do
+ @node2.previous_sibling_node.should == @node1
+ end
+
+ it "returns nil if there are no more child nodes before" do
+ @node1.previous_sibling_node.should == nil
+ @e.previous_sibling_node.should == nil
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/shared/each_element.rb b/spec/ruby/library/rexml/shared/each_element.rb
new file mode 100644
index 0000000000..2e0871161d
--- /dev/null
+++ b/spec/ruby/library/rexml/shared/each_element.rb
@@ -0,0 +1,36 @@
+require 'rexml/document'
+require_relative '../../../spec_helper'
+
+describe :rexml_each_element, shared: true do
+ before :each do
+ @e = REXML::Element.new "root"
+ s1 = REXML::Element.new "node1"
+ s2 = REXML::Element.new "node2"
+ s3 = REXML::Element.new "node3"
+ s4 = REXML::Element.new "sub_node"
+ @e << s1
+ @e << s2
+ @e << s3
+ @e << s4
+ end
+
+ it "iterates through element" do
+ str = ""
+ @e.send(@method) { |elem| str << elem.name << " " }
+ str.should == "node1 node2 node3 sub_node "
+ end
+
+ it "iterates through element filtering with XPath" do
+ str = ""
+ @e.send(@method, "/*"){ |e| str << e.name << " "}
+ str.should == "node1 node2 node3 sub_node "
+ end
+end
+
+describe "REXML::Element#each_element" do
+ it_behaves_like :rexml_each_element, :each_element
+end
+
+describe "REXML::Elements#each" do
+ it_behaves_like :rexml_each_element, :each
+end
diff --git a/spec/ruby/library/rexml/shared/elements_to_a.rb b/spec/ruby/library/rexml/shared/elements_to_a.rb
new file mode 100644
index 0000000000..b7169f0b2e
--- /dev/null
+++ b/spec/ruby/library/rexml/shared/elements_to_a.rb
@@ -0,0 +1,34 @@
+require 'rexml/document'
+require_relative '../../../spec_helper'
+
+describe :rexml_elements_to_a, shared: true do
+ before :each do
+ @e = REXML::Element.new "root"
+ @first = REXML::Element.new("FirstChild")
+ @second = REXML::Element.new("SecondChild")
+ @e << @first
+ @e << @second
+ end
+
+ it "returns elements that match xpath" do
+ @e.elements.send(@method, "FirstChild").first.should == @first
+ end
+
+ # According to the docs REXML::Element#get_elements is an alias for
+ # REXML::Elements.to_a. Implementation wise there's a difference, get_elements
+ # always needs the first param (even if it's nil).
+ # A patch was submitted:
+ # http://rubyforge.org/tracker/index.php?func=detail&aid=19354&group_id=426&atid=1698
+ it "returns all children if xpath is nil" do
+ @e.elements.send(@method).should == [@first, @second]
+ end
+
+end
+
+describe "REXML::REXML::Elements#to_a" do
+ it_behaves_like :rexml_elements_to_a, :to_a
+end
+
+describe "REXML::REXML::Element#get_elements" do
+ it_behaves_like :rexml_elements_to_a, :get_elements
+end
diff --git a/spec/ruby/library/rexml/text/append_spec.rb b/spec/ruby/library/rexml/text/append_spec.rb
new file mode 100644
index 0000000000..5e7a5bae7c
--- /dev/null
+++ b/spec/ruby/library/rexml/text/append_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text#<<" do
+ it "appends a string to this text node" do
+ text = REXML::Text.new("foo")
+ text << "bar"
+ text.should == "foobar"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/clone_spec.rb b/spec/ruby/library/rexml/text/clone_spec.rb
new file mode 100644
index 0000000000..7801782ff5
--- /dev/null
+++ b/spec/ruby/library/rexml/text/clone_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text#clone" do
+ it "creates a copy of this node" do
+ text = REXML::Text.new("foo")
+ text.clone.should == "foo"
+ text.clone.should == text
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/comparison_spec.rb b/spec/ruby/library/rexml/text/comparison_spec.rb
new file mode 100644
index 0000000000..119dd050a6
--- /dev/null
+++ b/spec/ruby/library/rexml/text/comparison_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text#<=>" do
+ before :each do
+ @first = REXML::Text.new("abc")
+ @last = REXML::Text.new("def")
+ end
+
+ it "returns -1 if lvalue is less than rvalue" do
+ val = @first <=> @last
+ val.should == -1
+ end
+
+ it "returns -1 if lvalue is greater than rvalue" do
+ val = @last <=> @first
+ val.should == 1
+ end
+
+ it "returns 0 if both values are equal" do
+ tmp = REXML::Text.new("tmp")
+ val = tmp <=> tmp
+ val.should == 0
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/empty_spec.rb b/spec/ruby/library/rexml/text/empty_spec.rb
new file mode 100644
index 0000000000..4c9c899bcb
--- /dev/null
+++ b/spec/ruby/library/rexml/text/empty_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text#empty?" do
+ it "returns true if the text is empty" do
+ REXML::Text.new("").should.empty?
+ end
+
+ it "returns false if the text is not empty" do
+ REXML::Text.new("some_text").should_not.empty?
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/indent_text_spec.rb b/spec/ruby/library/rexml/text/indent_text_spec.rb
new file mode 100644
index 0000000000..73065c37da
--- /dev/null
+++ b/spec/ruby/library/rexml/text/indent_text_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text#indent_text" do
+ before :each do
+ @t = REXML::Text.new("")
+ end
+ it "indents a string with default parameters" do
+ @t.indent_text("foo").should == "\tfoo"
+ end
+
+ it "accepts a custom indentation level as second argument" do
+ @t.indent_text("foo", 2, "\t", true).should == "\t\tfoo"
+ end
+
+ it "accepts a custom separator as third argument" do
+ @t.indent_text("foo", 1, "\n", true).should == "\nfoo"
+ end
+
+ it "accepts a fourth parameter to skip the first line" do
+ @t.indent_text("foo", 1, "\t", false).should == "foo"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/inspect_spec.rb b/spec/ruby/library/rexml/text/inspect_spec.rb
new file mode 100644
index 0000000000..af389890ee
--- /dev/null
+++ b/spec/ruby/library/rexml/text/inspect_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text#inspect" do
+ it "inspects the string attribute as a string" do
+ REXML::Text.new("a text").inspect.should == "a text".inspect
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/new_spec.rb b/spec/ruby/library/rexml/text/new_spec.rb
new file mode 100644
index 0000000000..8b33da9294
--- /dev/null
+++ b/spec/ruby/library/rexml/text/new_spec.rb
@@ -0,0 +1,51 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text.new" do
+
+ it "creates a Text child node with no parent" do
+ t = REXML::Text.new("test")
+ t.should be_kind_of(REXML::Child)
+ t.should == "test"
+ t.parent.should == nil
+ end
+
+ it "respects whitespace if second argument is true" do
+ t = REXML::Text.new("testing whitespace", true)
+ t.should == "testing whitespace"
+ t = REXML::Text.new(" ", true)
+ t.should == " "
+ end
+
+ it "receives a parent as third argument" do
+ e = REXML::Element.new("root")
+ t = REXML::Text.new("test", false, e)
+ t.parent.should == e
+ e.to_s.should == "<root>test</root>"
+ end
+
+ it "expects escaped text if raw is true" do
+ t = REXML::Text.new("&lt;&amp;&gt;", false, nil, true)
+ t.should == "&lt;&amp;&gt;"
+
+ ->{ REXML::Text.new("<&>", false, nil, true)}.should raise_error(Exception)
+ end
+
+ it "uses raw value of the parent if raw is nil" do
+ e1 = REXML::Element.new("root", nil, { raw: :all})
+ -> {REXML::Text.new("<&>", false, e1)}.should raise_error(Exception)
+
+ e2 = REXML::Element.new("root", nil, { raw: []})
+ e2.raw.should be_false
+ t1 = REXML::Text.new("<&>", false, e2)
+ t1.should == "&lt;&amp;&gt;"
+ end
+
+ it "escapes the values if raw is false" do
+ t = REXML::Text.new("<&>", false, nil, false)
+ t.should == "&lt;&amp;&gt;"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/node_type_spec.rb b/spec/ruby/library/rexml/text/node_type_spec.rb
new file mode 100644
index 0000000000..f44a1ede3e
--- /dev/null
+++ b/spec/ruby/library/rexml/text/node_type_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text#node_type" do
+ it "returns :text" do
+ REXML::Text.new("test").node_type.should == :text
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/normalize_spec.rb b/spec/ruby/library/rexml/text/normalize_spec.rb
new file mode 100644
index 0000000000..cde11ec3c9
--- /dev/null
+++ b/spec/ruby/library/rexml/text/normalize_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text.normalize" do
+ it "escapes a string with <, >, &, ' and \" " do
+ REXML::Text.normalize("< > & \" '").should == "&lt; &gt; &amp; &quot; &apos;"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/read_with_substitution_spec.rb b/spec/ruby/library/rexml/text/read_with_substitution_spec.rb
new file mode 100644
index 0000000000..7ff26f4d53
--- /dev/null
+++ b/spec/ruby/library/rexml/text/read_with_substitution_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text.read_with_substitution" do
+ it "reads a text and escapes entities" do
+ REXML::Text.read_with_substitution("&lt; &gt; &amp; &quot; &apos;").should == "< > & \" '"
+ end
+
+ it "accepts an regex for invalid expressions and raises an error if text matches" do
+ -> {REXML::Text.read_with_substitution("this is illegal", /illegal/)}.should raise_error(Exception)
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/to_s_spec.rb b/spec/ruby/library/rexml/text/to_s_spec.rb
new file mode 100644
index 0000000000..e67632c9a1
--- /dev/null
+++ b/spec/ruby/library/rexml/text/to_s_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text#to_s" do
+ it "returns the string of this Text node" do
+ u = REXML::Text.new("sean russell", false, nil, true)
+ u.to_s.should == "sean russell"
+
+ t = REXML::Text.new("some test text")
+ t.to_s.should == "some test text"
+ end
+
+ it "escapes the text" do
+ t = REXML::Text.new("& < >")
+ t.to_s.should == "&amp; &lt; &gt;"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/unnormalize_spec.rb b/spec/ruby/library/rexml/text/unnormalize_spec.rb
new file mode 100644
index 0000000000..7b507194d0
--- /dev/null
+++ b/spec/ruby/library/rexml/text/unnormalize_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text.unnormalize" do
+ it "unescapes a string with the values defined in SETUTITSBUS" do
+ REXML::Text.unnormalize("&lt; &gt; &amp; &quot; &apos;").should == "< > & \" '"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/value_spec.rb b/spec/ruby/library/rexml/text/value_spec.rb
new file mode 100644
index 0000000000..53d40c765f
--- /dev/null
+++ b/spec/ruby/library/rexml/text/value_spec.rb
@@ -0,0 +1,40 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text#value" do
+ it "returns the text value of this node" do
+ REXML::Text.new("test").value.should == "test"
+ end
+
+ it "does not escape entities" do
+ REXML::Text.new("& \"").value.should == "& \""
+ end
+
+ it "follows the respect_whitespace attribute" do
+ REXML::Text.new("test bar", false).value.should == "test bar"
+ REXML::Text.new("test bar", true).value.should == "test bar"
+ end
+
+ it "ignores the raw attribute" do
+ REXML::Text.new("sean russell", false, nil, true).value.should == "sean russell"
+ end
+ end
+
+ describe "REXML::Text#value=" do
+ before :each do
+ @t = REXML::Text.new("new")
+ end
+
+ it "sets the text of the node" do
+ @t.value = "another text"
+ @t.to_s.should == "another text"
+ end
+
+ it "escapes entities" do
+ @t.value = "<a>"
+ @t.to_s.should == "&lt;a&gt;"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/wrap_spec.rb b/spec/ruby/library/rexml/text/wrap_spec.rb
new file mode 100644
index 0000000000..331a8439e2
--- /dev/null
+++ b/spec/ruby/library/rexml/text/wrap_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text#wrap" do
+ before :each do
+ @t = REXML::Text.new("abc def")
+ end
+
+ it "wraps the text at width" do
+ @t.wrap("abc def", 3, false).should == "abc\ndef"
+ end
+
+ it "returns the string if width is greater than the size of the string" do
+ @t.wrap("abc def", 10, false).should == "abc def"
+ end
+
+ it "takes a newline at the beginning option as the third parameter" do
+ @t.wrap("abc def", 3, true).should == "\nabc\ndef"
+ end
+ end
+end
diff --git a/spec/ruby/library/rexml/text/write_with_substitution_spec.rb b/spec/ruby/library/rexml/text/write_with_substitution_spec.rb
new file mode 100644
index 0000000000..840f141e3d
--- /dev/null
+++ b/spec/ruby/library/rexml/text/write_with_substitution_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ''...'3.0' do
+ require 'rexml/document'
+
+ describe "REXML::Text#write_with_substitution" do
+ before :each do
+ @t = REXML::Text.new("test")
+ @f = tmp("rexml_spec")
+ @file = File.open(@f, "w+")
+ end
+
+ after :each do
+ @file.close
+ rm_r @f
+ end
+
+ it "writes out the input to a String" do
+ s = ""
+ @t.write_with_substitution(s, "some text")
+ s.should == "some text"
+ end
+
+ it "writes out the input to an IO" do
+ @t.write_with_substitution(@file, "some text")
+ @file.rewind
+ @file.gets.should == "some text"
+ end
+
+ it "escapes characters" do
+ @t.write_with_substitution(@file, "& < >")
+ @file.rewind
+ @file.gets.should == "&amp; &lt; &gt;"
+ end
+ end
+end
diff --git a/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb b/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb
index 9b37eaa43c..58913cddab 100644
--- a/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb
+++ b/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb
@@ -3,7 +3,7 @@ require 'rubygems'
describe "Gem.load_path_insert_index" do
guard -> { RbConfig::TOPDIR } do
- it "is set for an installed Ruby" do
+ it "is set for an installed an installed Ruby" do
Gem.load_path_insert_index.should be_kind_of Integer
end
end
diff --git a/spec/ruby/library/set/compare_by_identity_spec.rb b/spec/ruby/library/set/compare_by_identity_spec.rb
index 602d1e758e..9ed1602189 100644
--- a/spec/ruby/library/set/compare_by_identity_spec.rb
+++ b/spec/ruby/library/set/compare_by_identity_spec.rb
@@ -5,7 +5,7 @@ describe "Set#compare_by_identity" do
it "compares its members by identity" do
a = "a"
b1 = "b"
- b2 = b1.dup
+ b2 = "b"
set = Set.new
set.compare_by_identity
diff --git a/spec/ruby/library/set/comparison_spec.rb b/spec/ruby/library/set/comparison_spec.rb
index ddcfbae0af..b851ea3d57 100644
--- a/spec/ruby/library/set/comparison_spec.rb
+++ b/spec/ruby/library/set/comparison_spec.rb
@@ -1,27 +1,29 @@
-require_relative '../../spec_helper'
-require 'set'
-
-describe "Set#<=>" do
- it "returns 0 if the sets are equal" do
- (Set[] <=> Set[]).should == 0
- (Set[:a, :b, :c] <=> Set[:a, :b, :c]).should == 0
- end
-
- it "returns -1 if the set is a proper subset of the other set" do
- (Set[] <=> Set[1]).should == -1
- (Set[1, 2] <=> Set[1, 2, 3]).should == -1
- end
-
- it "returns +1 if the set is a proper superset of other set" do
- (Set[1] <=> Set[]).should == +1
- (Set[1, 2, 3] <=> Set[1, 2]).should == +1
- end
-
- it "returns nil if the set has unique elements" do
- (Set[1, 2, 3] <=> Set[:a, :b, :c]).should be_nil
- end
-
- it "returns nil when the argument is not set-like" do
- (Set[] <=> false).should be_nil
- end
-end
+require_relative '../../spec_helper'
+require 'set'
+
+ruby_version_is "3.0" do
+ describe "Set#<=>" do
+ it "returns 0 if the sets are equal" do
+ (Set[] <=> Set[]).should == 0
+ (Set[:a, :b, :c] <=> Set[:a, :b, :c]).should == 0
+ end
+
+ it "returns -1 if the set is a proper subset of the other set" do
+ (Set[] <=> Set[1]).should == -1
+ (Set[1, 2] <=> Set[1, 2, 3]).should == -1
+ end
+
+ it "returns +1 if the set is a proper superset of other set" do
+ (Set[1] <=> Set[]).should == +1
+ (Set[1, 2, 3] <=> Set[1, 2]).should == +1
+ end
+
+ it "returns nil if the set has unique elements" do
+ (Set[1, 2, 3] <=> Set[:a, :b, :c]).should be_nil
+ end
+
+ it "returns nil when the argument is not set-like" do
+ (Set[] <=> false).should be_nil
+ end
+ end
+end
diff --git a/spec/ruby/library/set/divide_spec.rb b/spec/ruby/library/set/divide_spec.rb
index 998a1b292c..fdd8cd9622 100644
--- a/spec/ruby/library/set/divide_spec.rb
+++ b/spec/ruby/library/set/divide_spec.rb
@@ -13,11 +13,11 @@ describe "Set#divide" do
ret.sort.should == ["five", "four", "one", "three", "two"]
end
- it "returns an enumerator when not passed a block" do
- ret = Set[1, 2, 3, 4].divide
- ret.should be_kind_of(Enumerator)
- ret.each(&:even?).should == Set[Set[1, 3], Set[2, 4]]
- end
+ # BUG: Does not raise a LocalJumpError, but a NoMethodError
+ #
+ # it "raises a LocalJumpError when not passed a block" do
+ # lambda { Set[1].divide }.should raise_error(LocalJumpError)
+ # end
end
describe "Set#divide when passed a block with an arity of 2" do
@@ -31,29 +31,4 @@ describe "Set#divide when passed a block with an arity of 2" do
Set[1, 2].divide { |x, y| ret << [x, y] }
ret.sort.should == [[1, 1], [1, 2], [2, 1], [2, 2]]
end
-
- it "returns an enumerator when not passed a block" do
- ret = Set[1, 2, 3, 4].divide
- ret.should be_kind_of(Enumerator)
- ret.each { |a, b| (a + b).even? }.should == Set[Set[1, 3], Set[2, 4]]
- end
-end
-
-describe "Set#divide when passed a block with an arity of > 2" do
- it "only uses the first element if the arity > 2" do
- set = Set["one", "two", "three", "four", "five"].divide do |x, y, z|
- y.should be_nil
- z.should be_nil
- x.length
- end
- set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
- end
-
- it "only uses the first element if the arity = -1" do
- set = Set["one", "two", "three", "four", "five"].divide do |*xs|
- xs.size.should == 1
- xs.first.length
- end
- set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
- end
end
diff --git a/spec/ruby/library/set/each_spec.rb b/spec/ruby/library/set/each_spec.rb
index 44e185a4da..9bb5ead03a 100644
--- a/spec/ruby/library/set/each_spec.rb
+++ b/spec/ruby/library/set/each_spec.rb
@@ -18,7 +18,6 @@ describe "Set#each" do
it "returns an Enumerator when not passed a block" do
enum = @set.each
- enum.should be_an_instance_of(Enumerator)
ret = []
enum.each { |x| ret << x }
diff --git a/spec/ruby/library/set/enumerable/to_set_spec.rb b/spec/ruby/library/set/enumerable/to_set_spec.rb
index b2d850515b..3790d8deee 100644
--- a/spec/ruby/library/set/enumerable/to_set_spec.rb
+++ b/spec/ruby/library/set/enumerable/to_set_spec.rb
@@ -7,6 +7,14 @@ describe "Enumerable#to_set" do
{a: 1, b: 2}.to_set.should == Set[[:b, 2], [:a, 1]]
end
+ ruby_version_is ''...'3.0' do
+ it "allows passing an alternate class for Set" do
+ sorted_set = [1, 2, 3].to_set(SortedSet)
+ sorted_set.should == SortedSet[1, 2, 3]
+ sorted_set.instance_of?(SortedSet).should == true
+ end
+ end
+
it "passes down passed blocks" do
[1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9]
end
diff --git a/spec/ruby/library/set/flatten_spec.rb b/spec/ruby/library/set/flatten_spec.rb
index 51b58d6439..4ac83ea825 100644
--- a/spec/ruby/library/set/flatten_spec.rb
+++ b/spec/ruby/library/set/flatten_spec.rb
@@ -1,7 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/set_like'
require 'set'
-set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
describe "Set#flatten" do
it "returns a copy of self with each included Set flattened" do
@@ -46,11 +45,9 @@ describe "Set#flatten!" do
-> { set.flatten! }.should raise_error(ArgumentError)
end
- version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
- context "when Set contains a Set-like object" do
- it "flattens self, including Set-like objects" do
- Set[SetSpecs::SetLike.new([1])].flatten!.should == Set[1]
- end
+ context "when Set contains a Set-like object" do
+ it "flattens self, including Set-like objects" do
+ Set[SetSpecs::SetLike.new([1])].flatten!.should == Set[1]
end
end
end
diff --git a/spec/ruby/library/set/initialize_clone_spec.rb b/spec/ruby/library/set/initialize_clone_spec.rb
index bda42cd6e8..62985987fa 100644
--- a/spec/ruby/library/set/initialize_clone_spec.rb
+++ b/spec/ruby/library/set/initialize_clone_spec.rb
@@ -2,15 +2,17 @@ require_relative '../../spec_helper'
require 'set'
describe "Set#initialize_clone" do
- # See https://bugs.ruby-lang.org/issues/14266
- it "does not freeze the new Set when called from clone(freeze: false)" do
- set1 = Set[1, 2]
- set1.freeze
- set2 = set1.clone(freeze: false)
- set1.frozen?.should == true
- set2.frozen?.should == false
- set2.add 3
- set1.should == Set[1, 2]
- set2.should == Set[1, 2, 3]
+ ruby_version_is "3.0" do
+ # See https://bugs.ruby-lang.org/issues/14266
+ it "does not freeze the new Set when called from clone(freeze: false)" do
+ set1 = Set[1, 2]
+ set1.freeze
+ set2 = set1.clone(freeze: false)
+ set1.frozen?.should == true
+ set2.frozen?.should == false
+ set2.add 3
+ set1.should == Set[1, 2]
+ set2.should == Set[1, 2, 3]
+ end
end
end
diff --git a/spec/ruby/library/set/join_spec.rb b/spec/ruby/library/set/join_spec.rb
index 3f511a84e4..7498a91d98 100644
--- a/spec/ruby/library/set/join_spec.rb
+++ b/spec/ruby/library/set/join_spec.rb
@@ -1,29 +1,31 @@
require_relative '../../spec_helper'
require 'set'
-describe "Set#join" do
- it "returns an empty string if the Set is empty" do
- Set[].join.should == ''
- end
+ruby_version_is "3.0" do
+ describe "Set#join" do
+ it "returns an empty string if the Set is empty" do
+ Set[].join.should == ''
+ end
- it "returns a new string formed by joining elements after conversion" do
- set = Set[:a, :b, :c]
- set.join.should == "abc"
- end
+ it "returns a new string formed by joining elements after conversion" do
+ set = Set[:a, :b, :c]
+ set.join.should == "abc"
+ end
- it "does not separate elements when the passed separator is nil" do
- set = Set[:a, :b, :c]
- set.join(nil).should == "abc"
- end
+ it "does not separate elements when the passed separator is nil" do
+ set = Set[:a, :b, :c]
+ set.join(nil).should == "abc"
+ end
- it "returns a string formed by concatenating each element separated by the separator" do
- set = Set[:a, :b, :c]
- set.join(' | ').should == "a | b | c"
- end
+ it "returns a string formed by concatenating each element separated by the separator" do
+ set = Set[:a, :b, :c]
+ set.join(' | ').should == "a | b | c"
+ end
- it "calls #to_a to convert the Set in to an Array" do
- set = Set[:a, :b, :c]
- set.should_receive(:to_a).and_return([:a, :b, :c])
- set.join.should == "abc"
+ it "calls #to_a to convert the Set in to an Array" do
+ set = Set[:a, :b, :c]
+ set.should_receive(:to_a).and_return([:a, :b, :c])
+ set.join.should == "abc"
+ end
end
end
diff --git a/spec/ruby/library/set/proper_subset_spec.rb b/spec/ruby/library/set/proper_subset_spec.rb
index 6b51dedc9f..1f496a6199 100644
--- a/spec/ruby/library/set/proper_subset_spec.rb
+++ b/spec/ruby/library/set/proper_subset_spec.rb
@@ -1,7 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/set_like'
require 'set'
-set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
describe "Set#proper_subset?" do
before :each do
@@ -34,11 +33,9 @@ describe "Set#proper_subset?" do
-> { Set[].proper_subset?(Object.new) }.should raise_error(ArgumentError)
end
- version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
- context "when comparing to a Set-like object" do
- it "returns true if passed a Set-like object that self is a proper subset of" do
- Set[1, 2, 3].proper_subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true
- end
+ context "when comparing to a Set-like object" do
+ it "returns true if passed a Set-like object that self is a proper subset of" do
+ Set[1, 2, 3].proper_subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true
end
end
end
diff --git a/spec/ruby/library/set/set_spec.rb b/spec/ruby/library/set/set_spec.rb
deleted file mode 100644
index 2a4edc6dfc..0000000000
--- a/spec/ruby/library/set/set_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../spec_helper'
-
-describe 'Set' do
- ruby_version_is '3.2' do
- it 'is available without explicit requiring' do
- output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1')
- puts Set.new([1, 2, 3])
- RUBY
- output.chomp.should == "#<Set: {1, 2, 3}>"
- end
- end
-end
diff --git a/spec/ruby/library/set/shared/inspect.rb b/spec/ruby/library/set/shared/inspect.rb
index adb6ddb4c9..69fbdd12f6 100644
--- a/spec/ruby/library/set/shared/inspect.rb
+++ b/spec/ruby/library/set/shared/inspect.rb
@@ -1,4 +1,4 @@
-describe :set_inspect, shared: true do
+describe "set_inspect", shared: true do
it "returns a String representation of self" do
Set[].send(@method).should be_kind_of(String)
Set[nil, false, true].send(@method).should be_kind_of(String)
@@ -7,19 +7,9 @@ describe :set_inspect, shared: true do
Set[:a, "b", Set[?c]].send(@method).should be_kind_of(String)
end
- it "does include the elements of the set" do
- Set["1"].send(@method).should == '#<Set: {"1"}>'
- end
-
- it "puts spaces between the elements" do
- Set["1", "2"].send(@method).should include('", "')
- end
-
- it "correctly handles cyclic-references" do
- set1 = Set[]
- set2 = Set[set1]
- set1 << set2
- set1.send(@method).should be_kind_of(String)
- set1.send(@method).should include("#<Set: {...}>")
+ it "correctly handles self-references" do
+ (set = Set[]) << set
+ set.send(@method).should be_kind_of(String)
+ set.send(@method).should include("#<Set: {...}>")
end
end
diff --git a/spec/ruby/library/set/sortedset/add_spec.rb b/spec/ruby/library/set/sortedset/add_spec.rb
new file mode 100644
index 0000000000..4f3bb252e1
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/add_spec.rb
@@ -0,0 +1,42 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+ require_relative 'shared/add'
+
+ describe "SortedSet#add" do
+ it_behaves_like :sorted_set_add, :add
+
+ it "takes only values which responds <=>" do
+ obj = mock('no_comparison_operator')
+ obj.stub!(:respond_to?).with(:<=>).and_return(false)
+ -> { SortedSet["hello"].add(obj) }.should raise_error(ArgumentError)
+ end
+
+ it "raises on incompatible <=> comparison" do
+ # Use #to_a here as elements are sorted only when needed.
+ # Therefore the <=> incompatibility is only noticed on sorting.
+ -> { SortedSet['1', '2'].add(3).to_a }.should raise_error(ArgumentError)
+ end
+ end
+
+ describe "SortedSet#add?" do
+ before :each do
+ @set = SortedSet.new
+ end
+
+ it "adds the passed Object to self" do
+ @set.add?("cat")
+ @set.should include("cat")
+ end
+
+ it "returns self when the Object has not yet been added to self" do
+ @set.add?("cat").should equal(@set)
+ end
+
+ it "returns nil when the Object has already been added to self" do
+ @set.add?("cat")
+ @set.add?("cat").should be_nil
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/append_spec.rb b/spec/ruby/library/set/sortedset/append_spec.rb
new file mode 100644
index 0000000000..d72d70b21f
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/append_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+ require_relative 'shared/add'
+
+ describe "SortedSet#<<" do
+ it_behaves_like :sorted_set_add, :<<
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/case_equality_spec.rb b/spec/ruby/library/set/sortedset/case_equality_spec.rb
new file mode 100644
index 0000000000..d7c296b626
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/case_equality_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require_relative 'shared/include'
+ require 'set'
+
+ describe "SortedSet#===" do
+ it_behaves_like :sorted_set_include, :===
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/classify_spec.rb b/spec/ruby/library/set/sortedset/classify_spec.rb
new file mode 100644
index 0000000000..4011e58b82
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/classify_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#classify" do
+ before :each do
+ @set = SortedSet["one", "two", "three", "four"]
+ end
+
+ it "yields each Object in self in sorted order" do
+ res = []
+ @set.classify { |x| res << x }
+ res.should == ["one", "two", "three", "four"].sort
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.classify
+ enum.should be_an_instance_of(Enumerator)
+
+ classified = enum.each { |x| x.length }
+ classified.should == { 3 => SortedSet["one", "two"], 4 => SortedSet["four"], 5 => SortedSet["three"] }
+ end
+
+ it "classifies the Objects in self based on the block's return value" do
+ classified = @set.classify { |x| x.length }
+ classified.should == { 3 => SortedSet["one", "two"], 4 => SortedSet["four"], 5 => SortedSet["three"] }
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/clear_spec.rb b/spec/ruby/library/set/sortedset/clear_spec.rb
new file mode 100644
index 0000000000..879aa824d8
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/clear_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#clear" do
+ before :each do
+ @set = SortedSet["one", "two", "three", "four"]
+ end
+
+ it "removes all elements from self" do
+ @set.clear
+ @set.should be_empty
+ end
+
+ it "returns self" do
+ @set.clear.should equal(@set)
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/collect_spec.rb b/spec/ruby/library/set/sortedset/collect_spec.rb
new file mode 100644
index 0000000000..0674f0d130
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/collect_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+ require_relative 'shared/collect'
+
+ describe "SortedSet#collect!" do
+ it_behaves_like :sorted_set_collect_bang, :collect!
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/constructor_spec.rb b/spec/ruby/library/set/sortedset/constructor_spec.rb
new file mode 100644
index 0000000000..31f30fd892
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/constructor_spec.rb
@@ -0,0 +1,18 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet[]" do
+ it "returns a new SortedSet populated with the passed Objects" do
+ set = SortedSet[1, 2, 3]
+
+ set.instance_of?(SortedSet).should be_true
+ set.size.should eql(3)
+
+ set.should include(1)
+ set.should include(2)
+ set.should include(3)
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/delete_if_spec.rb b/spec/ruby/library/set/sortedset/delete_if_spec.rb
new file mode 100644
index 0000000000..787639ae12
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/delete_if_spec.rb
@@ -0,0 +1,41 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#delete_if" do
+ before :each do
+ @set = SortedSet["one", "two", "three"]
+ end
+
+ it "yields each Object in self in sorted order" do
+ ret = []
+ @set.delete_if { |x| ret << x }
+ ret.should == ["one", "two", "three"].sort
+ end
+
+ it "deletes every element from self for which the passed block returns true" do
+ @set.delete_if { |x| x.size == 3 }
+ @set.size.should eql(1)
+
+ @set.should_not include("one")
+ @set.should_not include("two")
+ @set.should include("three")
+ end
+
+ it "returns self" do
+ @set.delete_if { |x| x }.should equal(@set)
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.delete_if
+ enum.should be_an_instance_of(Enumerator)
+
+ enum.each { |x| x.size == 3 }
+
+ @set.should_not include("one")
+ @set.should_not include("two")
+ @set.should include("three")
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/delete_spec.rb b/spec/ruby/library/set/sortedset/delete_spec.rb
new file mode 100644
index 0000000000..0e2a6accf3
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/delete_spec.rb
@@ -0,0 +1,40 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#delete" do
+ before :each do
+ @set = SortedSet["a", "b", "c"]
+ end
+
+ it "deletes the passed Object from self" do
+ @set.delete("a")
+ @set.should_not include("a")
+ end
+
+ it "returns self" do
+ @set.delete("a").should equal(@set)
+ @set.delete("x").should equal(@set)
+ end
+ end
+
+ describe "SortedSet#delete?" do
+ before :each do
+ @set = SortedSet["a", "b", "c"]
+ end
+
+ it "deletes the passed Object from self" do
+ @set.delete?("a")
+ @set.should_not include("a")
+ end
+
+ it "returns self when the passed Object is in self" do
+ @set.delete?("a").should equal(@set)
+ end
+
+ it "returns nil when the passed Object is not in self" do
+ @set.delete?("x").should be_nil
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/difference_spec.rb b/spec/ruby/library/set/sortedset/difference_spec.rb
new file mode 100644
index 0000000000..fb064bdff9
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/difference_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+ require_relative 'shared/difference'
+
+ describe "SortedSet#difference" do
+ it_behaves_like :sorted_set_difference, :difference
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/divide_spec.rb b/spec/ruby/library/set/sortedset/divide_spec.rb
new file mode 100644
index 0000000000..31ab6037e4
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/divide_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#divide" do
+ it "divides self into a set of subsets based on the blocks return values" do
+ set = SortedSet["one", "two", "three", "four", "five"].divide { |x| x.length }
+ set.map { |x| x.to_a }.to_a.sort.should == [["five", "four"], ["one", "two"], ["three"]]
+ end
+
+ it "yields each Object in self in sorted order" do
+ ret = []
+ SortedSet["one", "two", "three", "four", "five"].divide { |x| ret << x }
+ ret.should == ["one", "two", "three", "four", "five"].sort
+ end
+
+ # BUG: Does not raise a LocalJumpError, but a NoMethodError
+ #
+ # it "raises a LocalJumpError when not passed a block" do
+ # lambda { SortedSet[1].divide }.should raise_error(LocalJumpError)
+ # end
+ end
+
+ describe "SortedSet#divide when passed a block with an arity of 2" do
+ it "divides self into a set of subsets based on the blocks return values" do
+ set = SortedSet[1, 3, 4, 6, 9, 10, 11].divide { |x, y| (x - y).abs == 1 }
+ set.map { |x| x.to_a }.to_a.sort.should == [[1], [3, 4], [6], [9, 10, 11]]
+ end
+
+ it "yields each two Objects to the block" do
+ ret = []
+ SortedSet[1, 2].divide { |x, y| ret << [x, y] }
+ ret.should == [[1, 1], [1, 2], [2, 1], [2, 2]]
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/each_spec.rb b/spec/ruby/library/set/sortedset/each_spec.rb
new file mode 100644
index 0000000000..79d8aee223
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/each_spec.rb
@@ -0,0 +1,29 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#each" do
+ before :each do
+ @set = SortedSet[1, 2, 3]
+ end
+
+ it "yields each Object in self in sorted order" do
+ ret = []
+ SortedSet["one", "two", "three"].each { |x| ret << x }
+ ret.should == ["one", "two", "three"].sort
+ end
+
+ it "returns self" do
+ @set.each { |x| x }.should equal(@set)
+ end
+
+ it "returns an Enumerator when not passed a block" do
+ enum = @set.each
+
+ ret = []
+ enum.each { |x| ret << x }
+ ret.sort.should == [1, 2, 3]
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/empty_spec.rb b/spec/ruby/library/set/sortedset/empty_spec.rb
new file mode 100644
index 0000000000..2e52c3e81a
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/empty_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#empty?" do
+ it "returns true if self is empty" do
+ SortedSet[].empty?.should be_true
+ SortedSet[1].empty?.should be_false
+ SortedSet[1,2,3].empty?.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/eql_spec.rb b/spec/ruby/library/set/sortedset/eql_spec.rb
new file mode 100644
index 0000000000..050464994b
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/eql_spec.rb
@@ -0,0 +1,19 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#eql?" do
+ it "returns true when the passed argument is a SortedSet and contains the same elements" do
+ SortedSet[].should eql(SortedSet[])
+ SortedSet[1, 2, 3].should eql(SortedSet[1, 2, 3])
+ SortedSet[1, 2, 3].should eql(SortedSet[3, 2, 1])
+
+ # SortedSet["a", :b, ?c].should eql(SortedSet[?c, :b, "a"])
+
+ SortedSet[1, 2, 3].should_not eql(SortedSet[1.0, 2, 3])
+ SortedSet[1, 2, 3].should_not eql(SortedSet[2, 3])
+ SortedSet[1, 2, 3].should_not eql(SortedSet[])
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/equal_value_spec.rb b/spec/ruby/library/set/sortedset/equal_value_spec.rb
new file mode 100644
index 0000000000..30422f5b95
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/equal_value_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#==" do
+ it "returns true when the passed Object is a SortedSet and self and the Object contain the same elements" do
+ SortedSet[].should == SortedSet[]
+ SortedSet[1, 2, 3].should == SortedSet[1, 2, 3]
+ SortedSet["1", "2", "3"].should == SortedSet["1", "2", "3"]
+
+ SortedSet[1, 2, 3].should_not == SortedSet[1.0, 2, 3]
+ SortedSet[1, 2, 3].should_not == [1, 2, 3]
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/exclusion_spec.rb b/spec/ruby/library/set/sortedset/exclusion_spec.rb
new file mode 100644
index 0000000000..1967dfbfa6
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/exclusion_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#^" do
+ before :each do
+ @set = SortedSet[1, 2, 3, 4]
+ end
+
+ it "returns a new SortedSet containing elements that are not in both self and the passed Enumerable" do
+ (@set ^ SortedSet[3, 4, 5]).should == SortedSet[1, 2, 5]
+ (@set ^ [3, 4, 5]).should == SortedSet[1, 2, 5]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set ^ 3 }.should raise_error(ArgumentError)
+ -> { @set ^ Object.new }.should raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/filter_spec.rb b/spec/ruby/library/set/sortedset/filter_spec.rb
new file mode 100644
index 0000000000..3b9dcb63c9
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/filter_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require_relative 'shared/select'
+ require 'set'
+
+ describe "SortedSet#filter!" do
+ it_behaves_like :sorted_set_select_bang, :filter!
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/flatten_merge_spec.rb b/spec/ruby/library/set/sortedset/flatten_merge_spec.rb
new file mode 100644
index 0000000000..0d67cb331e
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/flatten_merge_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#flatten_merge" do
+ it "is protected" do
+ SortedSet.should have_protected_instance_method("flatten_merge")
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/flatten_spec.rb b/spec/ruby/library/set/sortedset/flatten_spec.rb
new file mode 100644
index 0000000000..e83ad1044a
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/flatten_spec.rb
@@ -0,0 +1,47 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ # Note: Flatten make little sens on sorted sets, because SortedSets are not (by default)
+ # comparable. For a SortedSet to be both valid and nested, we need to define a comparison operator:
+ module SortedSet_FlattenSpecs
+ class ComparableSortedSet < SortedSet
+ def <=>(other)
+ return puts "#{other} vs #{self}" unless other.is_a?(ComparableSortedSet)
+ to_a <=> other.to_a
+ end
+ end
+ end
+
+ describe "SortedSet#flatten" do
+ it "returns a copy of self with each included SortedSet flattened" do
+ klass = SortedSet_FlattenSpecs::ComparableSortedSet
+ set = klass[klass[1,2], klass[3,4], klass[5,6,7], klass[8]]
+ flattened_set = set.flatten
+
+ flattened_set.should_not equal(set)
+ flattened_set.should == klass[1, 2, 3, 4, 5, 6, 7, 8]
+ end
+ end
+
+ describe "SortedSet#flatten!" do
+ it "flattens self" do
+ klass = SortedSet_FlattenSpecs::ComparableSortedSet
+ set = klass[klass[1,2], klass[3,4], klass[5,6,7], klass[8]]
+ set.flatten!
+ set.should == klass[1, 2, 3, 4, 5, 6, 7, 8]
+ end
+
+ it "returns self when self was modified" do
+ klass = SortedSet_FlattenSpecs::ComparableSortedSet
+ set = klass[klass[1,2], klass[3,4]]
+ set.flatten!.should equal(set)
+ end
+
+ it "returns nil when self was not modified" do
+ set = SortedSet[1, 2, 3, 4]
+ set.flatten!.should be_nil
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/hash_spec.rb b/spec/ruby/library/set/sortedset/hash_spec.rb
new file mode 100644
index 0000000000..40676de7fc
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/hash_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#hash" do
+ it "is static" do
+ SortedSet[].hash.should == SortedSet[].hash
+ SortedSet[1, 2, 3].hash.should == SortedSet[1, 2, 3].hash
+ SortedSet["a", "b", "c"].hash.should == SortedSet["c", "b", "a"].hash
+
+ SortedSet[].hash.should_not == SortedSet[1, 2, 3].hash
+ SortedSet[1, 2, 3].hash.should_not == SortedSet["a", "b", "c"].hash
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/include_spec.rb b/spec/ruby/library/set/sortedset/include_spec.rb
new file mode 100644
index 0000000000..ec2ad987d5
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/include_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require_relative 'shared/include'
+ require 'set'
+
+ describe "SortedSet#include?" do
+ it_behaves_like :sorted_set_include, :include?
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/initialize_spec.rb b/spec/ruby/library/set/sortedset/initialize_spec.rb
new file mode 100644
index 0000000000..4d1707b72a
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/initialize_spec.rb
@@ -0,0 +1,33 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#initialize" do
+ it "is private" do
+ SortedSet.should have_private_instance_method("initialize")
+ end
+
+ it "adds all elements of the passed Enumerable to self" do
+ s = SortedSet.new([1, 2, 3])
+ s.size.should eql(3)
+ s.should include(1)
+ s.should include(2)
+ s.should include(3)
+ end
+
+ it "preprocesses all elements by a passed block before adding to self" do
+ s = SortedSet.new([1, 2, 3]) { |x| x * x }
+ s.size.should eql(3)
+ s.should include(1)
+ s.should include(4)
+ s.should include(9)
+ end
+
+ it "raises on incompatible <=> comparison" do
+ # Use #to_a here as elements are sorted only when needed.
+ # Therefore the <=> incompatibility is only noticed on sorting.
+ -> { SortedSet.new(['00', nil]).to_a }.should raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/inspect_spec.rb b/spec/ruby/library/set/sortedset/inspect_spec.rb
new file mode 100644
index 0000000000..1c4dd9e6e2
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/inspect_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#inspect" do
+ it "returns a String representation of self" do
+ SortedSet[].inspect.should be_kind_of(String)
+ SortedSet[1, 2, 3].inspect.should be_kind_of(String)
+ SortedSet["1", "2", "3"].inspect.should be_kind_of(String)
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/intersection_spec.rb b/spec/ruby/library/set/sortedset/intersection_spec.rb
new file mode 100644
index 0000000000..6daa271b73
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/intersection_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require_relative 'shared/intersection'
+ require 'set'
+
+ describe "SortedSet#intersection" do
+ it_behaves_like :sorted_set_intersection, :intersection
+ end
+
+ describe "SortedSet#&" do
+ it_behaves_like :sorted_set_intersection, :&
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/keep_if_spec.rb b/spec/ruby/library/set/sortedset/keep_if_spec.rb
new file mode 100644
index 0000000000..3e5f3bbc47
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/keep_if_spec.rb
@@ -0,0 +1,34 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#keep_if" do
+ before :each do
+ @set = SortedSet["one", "two", "three"]
+ end
+
+ it "yields each Object in self in sorted order" do
+ ret = []
+ @set.keep_if { |x| ret << x }
+ ret.should == ["one", "two", "three"].sort
+ end
+
+ it "keeps every element from self for which the passed block returns true" do
+ @set.keep_if { |x| x.size != 3 }
+ @set.to_a.should == ["three"]
+ end
+
+ it "returns self" do
+ @set.keep_if {}.should equal(@set)
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.keep_if
+ enum.should be_an_instance_of(Enumerator)
+
+ enum.each { |x| x.size != 3 }
+ @set.to_a.should == ["three"]
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/length_spec.rb b/spec/ruby/library/set/sortedset/length_spec.rb
new file mode 100644
index 0000000000..de6791f6bb
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/length_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require_relative 'shared/length'
+ require 'set'
+
+ describe "SortedSet#length" do
+ it_behaves_like :sorted_set_length, :length
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/map_spec.rb b/spec/ruby/library/set/sortedset/map_spec.rb
new file mode 100644
index 0000000000..4971b9529b
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/map_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+ require_relative 'shared/collect'
+
+ describe "SortedSet#map!" do
+ it_behaves_like :sorted_set_collect_bang, :map!
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/member_spec.rb b/spec/ruby/library/set/sortedset/member_spec.rb
new file mode 100644
index 0000000000..142b09b651
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/member_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require_relative 'shared/include'
+ require 'set'
+
+ describe "SortedSet#member?" do
+ it_behaves_like :sorted_set_include, :member?
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/merge_spec.rb b/spec/ruby/library/set/sortedset/merge_spec.rb
new file mode 100644
index 0000000000..c4cbc6d2b4
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/merge_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#merge" do
+ it "adds the elements of the passed Enumerable to self" do
+ SortedSet["a", "b"].merge(SortedSet["b", "c", "d"]).should == SortedSet["a", "b", "c", "d"]
+ SortedSet[1, 2].merge([3, 4]).should == SortedSet[1, 2, 3, 4]
+ end
+
+ it "returns self" do
+ set = SortedSet[1, 2]
+ set.merge([3, 4]).should equal(set)
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { SortedSet[1, 2].merge(1) }.should raise_error(ArgumentError)
+ -> { SortedSet[1, 2].merge(Object.new) }.should raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/minus_spec.rb b/spec/ruby/library/set/sortedset/minus_spec.rb
new file mode 100644
index 0000000000..d6abc5e204
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/minus_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+ require_relative 'shared/difference'
+
+ describe "SortedSet#-" do
+ it_behaves_like :sorted_set_difference, :-
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/plus_spec.rb b/spec/ruby/library/set/sortedset/plus_spec.rb
new file mode 100644
index 0000000000..13fc873ad1
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/plus_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require_relative 'shared/union'
+ require 'set'
+
+ describe "SortedSet#+" do
+ it_behaves_like :sorted_set_union, :+
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/pretty_print_cycle_spec.rb b/spec/ruby/library/set/sortedset/pretty_print_cycle_spec.rb
new file mode 100644
index 0000000000..e97f509406
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/pretty_print_cycle_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#pretty_print_cycle" do
+ it "passes the 'pretty print' representation of a self-referencing SortedSet to the pretty print writer" do
+ pp = mock("PrettyPrint")
+ pp.should_receive(:text).with("#<SortedSet: {...}>")
+ SortedSet[1, 2, 3].pretty_print_cycle(pp)
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/pretty_print_spec.rb b/spec/ruby/library/set/sortedset/pretty_print_spec.rb
new file mode 100644
index 0000000000..a8088bf797
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/pretty_print_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#pretty_print" do
+ it "passes the 'pretty print' representation of self to the pretty print writer" do
+ pp = mock("PrettyPrint")
+ set = SortedSet[1, 2, 3]
+
+ pp.should_receive(:text).with("#<SortedSet: {")
+ pp.should_receive(:text).with("}>")
+
+ pp.should_receive(:nest).with(1).and_yield
+ pp.should_receive(:seplist).with(set)
+
+ set.pretty_print(pp)
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/proper_subset_spec.rb b/spec/ruby/library/set/sortedset/proper_subset_spec.rb
new file mode 100644
index 0000000000..34fb89d13d
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/proper_subset_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#proper_subset?" do
+ before :each do
+ @set = SortedSet[1, 2, 3, 4]
+ end
+
+ it "returns true if passed a SortedSet that self is a proper subset of" do
+ SortedSet[].proper_subset?(@set).should be_true
+ SortedSet[].proper_subset?(SortedSet[1, 2, 3]).should be_true
+ SortedSet[].proper_subset?(SortedSet["a", "b", "c"]).should be_true
+
+ SortedSet[1, 2, 3].proper_subset?(@set).should be_true
+ SortedSet[1, 3].proper_subset?(@set).should be_true
+ SortedSet[1, 2].proper_subset?(@set).should be_true
+ SortedSet[1].proper_subset?(@set).should be_true
+
+ SortedSet[5].proper_subset?(@set).should be_false
+ SortedSet[1, 5].proper_subset?(@set).should be_false
+ SortedSet["test"].proper_subset?(@set).should be_false
+
+ @set.proper_subset?(@set).should be_false
+ SortedSet[].proper_subset?(SortedSet[]).should be_false
+ end
+
+ it "raises an ArgumentError when passed a non-SortedSet" do
+ -> { SortedSet[].proper_subset?([]) }.should raise_error(ArgumentError)
+ -> { SortedSet[].proper_subset?(1) }.should raise_error(ArgumentError)
+ -> { SortedSet[].proper_subset?("test") }.should raise_error(ArgumentError)
+ -> { SortedSet[].proper_subset?(Object.new) }.should raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/proper_superset_spec.rb b/spec/ruby/library/set/sortedset/proper_superset_spec.rb
new file mode 100644
index 0000000000..8b92444f72
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/proper_superset_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#proper_superset?" do
+ before :each do
+ @set = SortedSet[1, 2, 3, 4]
+ end
+
+ it "returns true if passed a SortedSet that self is a proper superset of" do
+ @set.proper_superset?(SortedSet[]).should be_true
+ SortedSet[1, 2, 3].proper_superset?(SortedSet[]).should be_true
+ SortedSet["a", "b", "c"].proper_superset?(SortedSet[]).should be_true
+
+ @set.proper_superset?(SortedSet[1, 2, 3]).should be_true
+ @set.proper_superset?(SortedSet[1, 3]).should be_true
+ @set.proper_superset?(SortedSet[1, 2]).should be_true
+ @set.proper_superset?(SortedSet[1]).should be_true
+
+ @set.proper_superset?(SortedSet[5]).should be_false
+ @set.proper_superset?(SortedSet[1, 5]).should be_false
+ @set.proper_superset?(SortedSet["test"]).should be_false
+
+ @set.proper_superset?(@set).should be_false
+ SortedSet[].proper_superset?(SortedSet[]).should be_false
+ end
+
+ it "raises an ArgumentError when passed a non-SortedSet" do
+ -> { SortedSet[].proper_superset?([]) }.should raise_error(ArgumentError)
+ -> { SortedSet[].proper_superset?(1) }.should raise_error(ArgumentError)
+ -> { SortedSet[].proper_superset?("test") }.should raise_error(ArgumentError)
+ -> { SortedSet[].proper_superset?(Object.new) }.should raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/reject_spec.rb b/spec/ruby/library/set/sortedset/reject_spec.rb
new file mode 100644
index 0000000000..396b864cc5
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/reject_spec.rb
@@ -0,0 +1,45 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#reject!" do
+ before :each do
+ @set = SortedSet["one", "two", "three"]
+ end
+
+ it "yields each Object in self in sorted order" do
+ res = []
+ @set.reject! { |x| res << x }
+ res.should == ["one", "two", "three"].sort
+ end
+
+ it "deletes every element from self for which the passed block returns true" do
+ @set.reject! { |x| x.size == 3 }
+ @set.size.should eql(1)
+
+ @set.should_not include("one")
+ @set.should_not include("two")
+ @set.should include("three")
+ end
+
+ it "returns self when self was modified" do
+ @set.reject! { |x| true }.should equal(@set)
+ end
+
+ it "returns nil when self was not modified" do
+ @set.reject! { |x| false }.should be_nil
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.reject!
+ enum.should be_an_instance_of(Enumerator)
+
+ enum.each { |x| x.size == 3 }
+
+ @set.should_not include("one")
+ @set.should_not include("two")
+ @set.should include("three")
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/replace_spec.rb b/spec/ruby/library/set/sortedset/replace_spec.rb
new file mode 100644
index 0000000000..2900221c01
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/replace_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#replace" do
+ before :each do
+ @set = SortedSet["a", "b", "c"]
+ end
+
+ it "replaces the contents with other and returns self" do
+ @set.replace(SortedSet[1, 2, 3]).should == @set
+ @set.should == SortedSet[1, 2, 3]
+ end
+
+ it "accepts any enumerable as other" do
+ @set.replace([1, 2, 3]).should == SortedSet[1, 2, 3]
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/select_spec.rb b/spec/ruby/library/set/sortedset/select_spec.rb
new file mode 100644
index 0000000000..fc4c15ee4d
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/select_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require_relative 'shared/select'
+ require 'set'
+
+ describe "SortedSet#select!" do
+ it_behaves_like :sorted_set_select_bang, :select!
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/shared/add.rb b/spec/ruby/library/set/sortedset/shared/add.rb
new file mode 100644
index 0000000000..95ef1b090e
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/shared/add.rb
@@ -0,0 +1,14 @@
+describe :sorted_set_add, shared: true do
+ before :each do
+ @set = SortedSet.new
+ end
+
+ it "adds the passed Object to self" do
+ @set.send(@method, "dog")
+ @set.should include("dog")
+ end
+
+ it "returns self" do
+ @set.send(@method, "dog").should equal(@set)
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/shared/collect.rb b/spec/ruby/library/set/sortedset/shared/collect.rb
new file mode 100644
index 0000000000..e53304d427
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/shared/collect.rb
@@ -0,0 +1,20 @@
+describe :sorted_set_collect_bang, shared: true do
+ before :each do
+ @set = SortedSet[1, 2, 3, 4, 5]
+ end
+
+ it "yields each Object in self in sorted order" do
+ res = []
+ SortedSet["one", "two", "three"].send(@method) { |x| res << x; x }
+ res.should == ["one", "two", "three"].sort
+ end
+
+ it "returns self" do
+ @set.send(@method) { |x| x }.should equal(@set)
+ end
+
+ it "replaces self with the return values of the block" do
+ @set.send(@method) { |x| x * 2 }
+ @set.should == SortedSet[2, 4, 6, 8, 10]
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/shared/difference.rb b/spec/ruby/library/set/sortedset/shared/difference.rb
new file mode 100644
index 0000000000..688e23a7a7
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/shared/difference.rb
@@ -0,0 +1,15 @@
+describe :sorted_set_difference, shared: true do
+ before :each do
+ @set = SortedSet["a", "b", "c"]
+ end
+
+ it "returns a new SortedSet containing self's elements excluding the elements in the passed Enumerable" do
+ @set.send(@method, SortedSet["a", "b"]).should == SortedSet["c"]
+ @set.send(@method, ["b", "c"]).should == SortedSet["a"]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set.send(@method, 1) }.should raise_error(ArgumentError)
+ -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/shared/include.rb b/spec/ruby/library/set/sortedset/shared/include.rb
new file mode 100644
index 0000000000..cd1758819d
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/shared/include.rb
@@ -0,0 +1,7 @@
+describe :sorted_set_include, shared: true do
+ it "returns true when self contains the passed Object" do
+ set = SortedSet["a", "b", "c"]
+ set.send(@method, "a").should be_true
+ set.send(@method, "e").should be_false
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/shared/intersection.rb b/spec/ruby/library/set/sortedset/shared/intersection.rb
new file mode 100644
index 0000000000..045716ad05
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/shared/intersection.rb
@@ -0,0 +1,15 @@
+describe :sorted_set_intersection, shared: true do
+ before :each do
+ @set = SortedSet["a", "b", "c"]
+ end
+
+ it "returns a new SortedSet containing only elements shared by self and the passed Enumerable" do
+ @set.send(@method, SortedSet["b", "c", "d", "e"]).should == SortedSet["b", "c"]
+ @set.send(@method, ["b", "c", "d"]).should == SortedSet["b", "c"]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set.send(@method, 1) }.should raise_error(ArgumentError)
+ -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/shared/length.rb b/spec/ruby/library/set/sortedset/shared/length.rb
new file mode 100644
index 0000000000..d1dfee1cff
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/shared/length.rb
@@ -0,0 +1,6 @@
+describe :sorted_set_length, shared: true do
+ it "returns the number of elements in the set" do
+ set = SortedSet["a", "b", "c"]
+ set.send(@method).should == 3
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/shared/select.rb b/spec/ruby/library/set/sortedset/shared/select.rb
new file mode 100644
index 0000000000..e13311eda5
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/shared/select.rb
@@ -0,0 +1,35 @@
+require_relative '../../../../spec_helper'
+require 'set'
+
+describe :sorted_set_select_bang, shared: true do
+ before :each do
+ @set = SortedSet["one", "two", "three"]
+ end
+
+ it "yields each Object in self in sorted order" do
+ res = []
+ @set.send(@method) { |x| res << x }
+ res.should == ["one", "two", "three"].sort
+ end
+
+ it "keeps every element from self for which the passed block returns true" do
+ @set.send(@method) { |x| x.size != 3 }
+ @set.to_a.should == ["three"]
+ end
+
+ it "returns self when self was modified" do
+ @set.send(@method) { false }.should equal(@set)
+ end
+
+ it "returns nil when self was not modified" do
+ @set.send(@method) { true }.should be_nil
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.send(@method)
+ enum.should be_an_instance_of(Enumerator)
+
+ enum.each { |x| x.size != 3 }
+ @set.to_a.should == ["three"]
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/shared/union.rb b/spec/ruby/library/set/sortedset/shared/union.rb
new file mode 100644
index 0000000000..9015bdc8e3
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/shared/union.rb
@@ -0,0 +1,15 @@
+describe :sorted_set_union, shared: true do
+ before :each do
+ @set = SortedSet["a", "b", "c"]
+ end
+
+ it "returns a new SortedSet containing all elements of self and the passed Enumerable" do
+ @set.send(@method, SortedSet["b", "d", "e"]).should == SortedSet["a", "b", "c", "d", "e"]
+ @set.send(@method, ["b", "e"]).should == SortedSet["a", "b", "c", "e"]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set.send(@method, 1) }.should raise_error(ArgumentError)
+ -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/size_spec.rb b/spec/ruby/library/set/sortedset/size_spec.rb
new file mode 100644
index 0000000000..d908b33b53
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/size_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require_relative 'shared/length'
+ require 'set'
+
+ describe "SortedSet#size" do
+ it_behaves_like :sorted_set_length, :size
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/sortedset_spec.rb b/spec/ruby/library/set/sortedset/sortedset_spec.rb
index 67993dee29..3ead5495fc 100644
--- a/spec/ruby/library/set/sortedset/sortedset_spec.rb
+++ b/spec/ruby/library/set/sortedset/sortedset_spec.rb
@@ -1,12 +1,22 @@
require_relative '../../../spec_helper'
require 'set'
-describe "SortedSet" do
- it "raises error including message that it has been extracted from the set stdlib" do
- -> {
- SortedSet
- }.should raise_error(RuntimeError) { |e|
- e.message.should.include?("The `SortedSet` class has been extracted from the `set` library")
- }
+ruby_version_is "3.0" do
+ describe "SortedSet" do
+ it "raises error including message that it has been extracted from the set stdlib" do
+ -> {
+ SortedSet
+ }.should raise_error(RuntimeError) { |e|
+ e.message.should.include?("The `SortedSet` class has been extracted from the `set` library")
+ }
+ end
+ end
+end
+
+ruby_version_is ""..."3.0" do
+ describe "SortedSet" do
+ it "is part of the set stdlib" do
+ SortedSet.superclass.should == Set
+ end
end
end
diff --git a/spec/ruby/library/set/sortedset/subset_spec.rb b/spec/ruby/library/set/sortedset/subset_spec.rb
new file mode 100644
index 0000000000..272e3f985e
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/subset_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#subset?" do
+ before :each do
+ @set = SortedSet[1, 2, 3, 4]
+ end
+
+ it "returns true if passed a SortedSet that is equal to self or self is a subset of" do
+ @set.subset?(@set).should be_true
+ SortedSet[].subset?(SortedSet[]).should be_true
+
+ SortedSet[].subset?(@set).should be_true
+ SortedSet[].subset?(SortedSet[1, 2, 3]).should be_true
+ SortedSet[].subset?(SortedSet["a", "b", "c"]).should be_true
+
+ SortedSet[1, 2, 3].subset?(@set).should be_true
+ SortedSet[1, 3].subset?(@set).should be_true
+ SortedSet[1, 2].subset?(@set).should be_true
+ SortedSet[1].subset?(@set).should be_true
+
+ SortedSet[5].subset?(@set).should be_false
+ SortedSet[1, 5].subset?(@set).should be_false
+ SortedSet["test"].subset?(@set).should be_false
+ end
+
+ it "raises an ArgumentError when passed a non-SortedSet" do
+ -> { SortedSet[].subset?([]) }.should raise_error(ArgumentError)
+ -> { SortedSet[].subset?(1) }.should raise_error(ArgumentError)
+ -> { SortedSet[].subset?("test") }.should raise_error(ArgumentError)
+ -> { SortedSet[].subset?(Object.new) }.should raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/subtract_spec.rb b/spec/ruby/library/set/sortedset/subtract_spec.rb
new file mode 100644
index 0000000000..b2af127f89
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/subtract_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#subtract" do
+ before :each do
+ @set = SortedSet["a", "b", "c"]
+ end
+
+ it "deletes any elements contained in other and returns self" do
+ @set.subtract(SortedSet["b", "c"]).should == @set
+ @set.should == SortedSet["a"]
+ end
+
+ it "accepts any enumerable as other" do
+ @set.subtract(["c"]).should == SortedSet["a", "b"]
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/superset_spec.rb b/spec/ruby/library/set/sortedset/superset_spec.rb
new file mode 100644
index 0000000000..a1bbacb966
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/superset_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#superset?" do
+ before :each do
+ @set = SortedSet[1, 2, 3, 4]
+ end
+
+ it "returns true if passed a SortedSet that equals self or self is a proper superset of" do
+ @set.superset?(@set).should be_true
+ SortedSet[].superset?(SortedSet[]).should be_true
+
+ @set.superset?(SortedSet[]).should be_true
+ SortedSet[1, 2, 3].superset?(SortedSet[]).should be_true
+ SortedSet["a", "b", "c"].superset?(SortedSet[]).should be_true
+
+ @set.superset?(SortedSet[1, 2, 3]).should be_true
+ @set.superset?(SortedSet[1, 3]).should be_true
+ @set.superset?(SortedSet[1, 2]).should be_true
+ @set.superset?(SortedSet[1]).should be_true
+
+ @set.superset?(SortedSet[5]).should be_false
+ @set.superset?(SortedSet[1, 5]).should be_false
+ @set.superset?(SortedSet["test"]).should be_false
+ end
+
+ it "raises an ArgumentError when passed a non-SortedSet" do
+ -> { SortedSet[].superset?([]) }.should raise_error(ArgumentError)
+ -> { SortedSet[].superset?(1) }.should raise_error(ArgumentError)
+ -> { SortedSet[].superset?("test") }.should raise_error(ArgumentError)
+ -> { SortedSet[].superset?(Object.new) }.should raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/to_a_spec.rb b/spec/ruby/library/set/sortedset/to_a_spec.rb
new file mode 100644
index 0000000000..bb54cd7cdb
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/to_a_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require 'set'
+
+ describe "SortedSet#to_a" do
+ it "returns an array containing elements" do
+ set = SortedSet.new [1, 2, 3]
+ set.to_a.should == [1, 2, 3]
+ end
+
+ it "returns a sorted array containing elements" do
+ set = SortedSet[2, 3, 1]
+ set.to_a.should == [1, 2, 3]
+
+ set = SortedSet.new [5, 6, 4, 4]
+ set.to_a.should == [4, 5, 6]
+ end
+ end
+end
diff --git a/spec/ruby/library/set/sortedset/union_spec.rb b/spec/ruby/library/set/sortedset/union_spec.rb
new file mode 100644
index 0000000000..c942f20d3e
--- /dev/null
+++ b/spec/ruby/library/set/sortedset/union_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is ""..."3.0" do
+ require_relative 'shared/union'
+ require 'set'
+
+ describe "SortedSet#union" do
+ it_behaves_like :sorted_set_union, :union
+ end
+
+ describe "SortedSet#|" do
+ it_behaves_like :sorted_set_union, :|
+ end
+end
diff --git a/spec/ruby/library/set/subset_spec.rb b/spec/ruby/library/set/subset_spec.rb
index 85666d633f..f375efa6df 100644
--- a/spec/ruby/library/set/subset_spec.rb
+++ b/spec/ruby/library/set/subset_spec.rb
@@ -1,7 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/set_like'
require 'set'
-set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
describe "Set#subset?" do
before :each do
@@ -34,11 +33,9 @@ describe "Set#subset?" do
-> { Set[].subset?(Object.new) }.should raise_error(ArgumentError)
end
- version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
- context "when comparing to a Set-like object" do
- it "returns true if passed a Set-like object that self is a subset of" do
- Set[1, 2, 3].subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true
- end
+ context "when comparing to a Set-like object" do
+ it "returns true if passed a Set-like object that self is a subset of" do
+ Set[1, 2, 3].subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true
end
end
end
diff --git a/spec/ruby/library/set/to_s_spec.rb b/spec/ruby/library/set/to_s_spec.rb
index 3c26ae9346..7b9f7b6603 100644
--- a/spec/ruby/library/set/to_s_spec.rb
+++ b/spec/ruby/library/set/to_s_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../spec_helper"
require_relative 'shared/inspect'
require 'set'
diff --git a/spec/ruby/library/shellwords/shellwords_spec.rb b/spec/ruby/library/shellwords/shellwords_spec.rb
index fe86b6faab..2975fd9974 100644
--- a/spec/ruby/library/shellwords/shellwords_spec.rb
+++ b/spec/ruby/library/shellwords/shellwords_spec.rb
@@ -1,33 +1,34 @@
require_relative '../../spec_helper'
require 'shellwords'
+include Shellwords
describe "Shellwords#shellwords" do
it "honors quoted strings" do
- Shellwords.shellwords('a "b b" a').should == ['a', 'b b', 'a']
+ shellwords('a "b b" a').should == ['a', 'b b', 'a']
end
it "honors escaped double quotes" do
- Shellwords.shellwords('a "\"b\" c" d').should == ['a', '"b" c', 'd']
+ shellwords('a "\"b\" c" d').should == ['a', '"b" c', 'd']
end
it "honors escaped single quotes" do
- Shellwords.shellwords("a \"'b' c\" d").should == ['a', "'b' c", 'd']
+ shellwords("a \"'b' c\" d").should == ['a', "'b' c", 'd']
end
it "honors escaped spaces" do
- Shellwords.shellwords('a b\ c d').should == ['a', 'b c', 'd']
+ shellwords('a b\ c d').should == ['a', 'b c', 'd']
end
it "raises ArgumentError when double quoted strings are misquoted" do
- -> { Shellwords.shellwords('a "b c d e') }.should raise_error(ArgumentError)
+ -> { shellwords('a "b c d e') }.should raise_error(ArgumentError)
end
it "raises ArgumentError when single quoted strings are misquoted" do
- -> { Shellwords.shellwords("a 'b c d e") }.should raise_error(ArgumentError)
+ -> { shellwords("a 'b c d e") }.should raise_error(ArgumentError)
end
# https://bugs.ruby-lang.org/issues/10055
it "matches POSIX sh behavior for backslashes within double quoted strings" do
- Shellwords.shellsplit('printf "%s\n"').should == ['printf', '%s\n']
+ shellsplit('printf "%s\n"').should == ['printf', '%s\n']
end
end
diff --git a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb b/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb
index 4f7cf439a0..c32da5986d 100644
--- a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb
+++ b/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb
@@ -1,4 +1,5 @@
-describe :socket_addrinfo_to_sockaddr, shared: true do
+describe :socket_addrinfo_to_sockaddr, :shared => true do
+
describe "for an ipv4 socket" do
before :each do
@addrinfo = Addrinfo.tcp("127.0.0.1", 80)
@@ -46,4 +47,5 @@ describe :socket_addrinfo_to_sockaddr, shared: true do
addr.send(@method).should == Socket.sockaddr_in(0, '')
end
end
+
end
diff --git a/spec/ruby/library/socket/basicsocket/read_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/read_nonblock_spec.rb
index ea5e65da5c..df44a50afa 100644
--- a/spec/ruby/library/socket/basicsocket/read_nonblock_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/read_nonblock_spec.rb
@@ -18,37 +18,7 @@ describe "BasicSocket#read_nonblock" do
it "receives data after it's ready" do
IO.select([@r], nil, nil, 2)
- @r.read_nonblock(5).should == "aaa"
- end
-
- platform_is_not :windows do
- it 'returned data is binary encoded regardless of the external encoding' do
- IO.select([@r], nil, nil, 2)
- @r.read_nonblock(1).encoding.should == Encoding::BINARY
-
- @w.send("bbb", 0, @r.getsockname)
- @r.set_encoding(Encoding::ISO_8859_1)
- IO.select([@r], nil, nil, 2)
- buffer = @r.read_nonblock(3)
- buffer.should == "bbb"
- buffer.encoding.should == Encoding::BINARY
- end
- end
-
- it 'replaces the content of the provided buffer without changing its encoding' do
- buffer = "initial data".dup.force_encoding(Encoding::UTF_8)
-
- IO.select([@r], nil, nil, 2)
- @r.read_nonblock(3, buffer)
- buffer.should == "aaa"
- buffer.encoding.should == Encoding::UTF_8
-
- @w.send("bbb", 0, @r.getsockname)
- @r.set_encoding(Encoding::ISO_8859_1)
- IO.select([@r], nil, nil, 2)
- @r.read_nonblock(3, buffer)
- buffer.should == "bbb"
- buffer.encoding.should == Encoding::UTF_8
+ @r.recv_nonblock(5).should == "aaa"
end
platform_is :linux do
diff --git a/spec/ruby/library/socket/basicsocket/read_spec.rb b/spec/ruby/library/socket/basicsocket/read_spec.rb
deleted file mode 100644
index ba9de7d5cf..0000000000
--- a/spec/ruby/library/socket/basicsocket/read_spec.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-require_relative '../spec_helper'
-require_relative '../fixtures/classes'
-
-describe "BasicSocket#read" do
- SocketSpecs.each_ip_protocol do |family, ip_address|
- before :each do
- @r = Socket.new(family, :DGRAM)
- @w = Socket.new(family, :DGRAM)
-
- @r.bind(Socket.pack_sockaddr_in(0, ip_address))
- @w.send("aaa", 0, @r.getsockname)
- end
-
- after :each do
- @r.close unless @r.closed?
- @w.close unless @w.closed?
- end
-
- it "receives data after it's ready" do
- @r.read(3).should == "aaa"
- end
-
- it 'returned data is binary encoded regardless of the external encoding' do
- @r.read(3).encoding.should == Encoding::BINARY
-
- @w.send("bbb", 0, @r.getsockname)
- @r.set_encoding(Encoding::UTF_8)
- buffer = @r.read(3)
- buffer.should == "bbb"
- buffer.encoding.should == Encoding::BINARY
- end
-
- it 'replaces the content of the provided buffer without changing its encoding' do
- buffer = "initial data".dup.force_encoding(Encoding::UTF_8)
-
- @r.read(3, buffer)
- buffer.should == "aaa"
- buffer.encoding.should == Encoding::UTF_8
-
- @w.send("bbb", 0, @r.getsockname)
- @r.set_encoding(Encoding::ISO_8859_1)
- @r.read(3, buffer)
- buffer.should == "bbb"
- buffer.encoding.should == Encoding::UTF_8
- end
- end
-end
diff --git a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
index df42c116fb..b6ab8a9cea 100644
--- a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
@@ -52,19 +52,9 @@ describe "Socket::BasicSocket#recv_nonblock" do
@s2.send("data", 0, @s1.getsockname)
IO.select([@s1], nil, nil, 2)
- buffer = +"foo"
- @s1.recv_nonblock(5, 0, buffer).should.equal?(buffer)
- buffer.should == "data"
- end
-
- it "preserves the encoding of the given buffer" do
- @s1.bind(Socket.pack_sockaddr_in(0, ip_address))
- @s2.send("data", 0, @s1.getsockname)
- IO.select([@s1], nil, nil, 2)
-
- buffer = ''.encode(Encoding::ISO_8859_1)
- @s1.recv_nonblock(5, 0, buffer)
- buffer.encoding.should == Encoding::ISO_8859_1
+ buf = "foo"
+ @s1.recv_nonblock(5, 0, buf)
+ buf.should == "data"
end
it "does not block if there's no data available" do
diff --git a/spec/ruby/library/socket/basicsocket/recv_spec.rb b/spec/ruby/library/socket/basicsocket/recv_spec.rb
index e82a357d3d..b6ccda5d00 100644
--- a/spec/ruby/library/socket/basicsocket/recv_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recv_spec.rb
@@ -32,25 +32,6 @@ describe "BasicSocket#recv" do
ScratchPad.recorded.should == 'hello'
end
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- packet = client.recv(10)
- client.close
- packet
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
-
- t.value.should be_nil
- end
- end
-
platform_is_not :solaris do
it "accepts flags to specify unusual receiving behaviour" do
t = Thread.new do
@@ -100,29 +81,13 @@ describe "BasicSocket#recv" do
socket.write("data")
client = @server.accept
- buffer = +"foo"
- begin
- client.recv(4, 0, buffer).should.equal?(buffer)
- ensure
- client.close
- end
- buffer.should == "data"
-
- socket.close
- end
-
- it "preserves the encoding of the given buffer" do
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.write("data")
-
- client = @server.accept
- buffer = ''.encode(Encoding::ISO_8859_1)
+ buf = "foo"
begin
- client.recv(4, 0, buffer)
+ client.recv(4, 0, buf)
ensure
client.close
end
- buffer.encoding.should == Encoding::ISO_8859_1
+ buf.should == "data"
socket.close
end
diff --git a/spec/ruby/library/socket/basicsocket/send_spec.rb b/spec/ruby/library/socket/basicsocket/send_spec.rb
index 86b5567026..868801df30 100644
--- a/spec/ruby/library/socket/basicsocket/send_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/send_spec.rb
@@ -17,12 +17,12 @@ describe "BasicSocket#send" do
end
it "sends a message to another socket and returns the number of bytes sent" do
- data = +""
+ data = ""
t = Thread.new do
client = @server.accept
loop do
got = client.recv(5)
- break if got.nil? || got.empty?
+ break if got.empty?
data << got
end
client.close
@@ -62,12 +62,12 @@ describe "BasicSocket#send" do
end
it "accepts a sockaddr as recipient address" do
- data = +""
+ data = ""
t = Thread.new do
client = @server.accept
loop do
got = client.recv(5)
- break if got.nil? || got.empty?
+ break if got.empty?
data << got
end
client.close
diff --git a/spec/ruby/library/socket/basicsocket/shutdown_spec.rb b/spec/ruby/library/socket/basicsocket/shutdown_spec.rb
index c78b32de38..41d9581bde 100644
--- a/spec/ruby/library/socket/basicsocket/shutdown_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/shutdown_spec.rb
@@ -23,7 +23,7 @@ platform_is_not :windows do # hangs
it 'shuts down a socket for reading' do
@client.shutdown(Socket::SHUT_RD)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).should be_empty
end
it 'shuts down a socket for writing' do
@@ -35,7 +35,7 @@ platform_is_not :windows do # hangs
it 'shuts down a socket for reading and writing' do
@client.shutdown(Socket::SHUT_RDWR)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).should be_empty
-> { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
@@ -49,13 +49,13 @@ platform_is_not :windows do # hangs
it 'shuts down a socket for reading using :RD' do
@client.shutdown(:RD)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).should be_empty
end
it 'shuts down a socket for reading using :SHUT_RD' do
@client.shutdown(:SHUT_RD)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).should be_empty
end
it 'shuts down a socket for writing using :WR' do
@@ -73,7 +73,7 @@ platform_is_not :windows do # hangs
it 'shuts down a socket for reading and writing' do
@client.shutdown(:RDWR)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).should be_empty
-> { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
@@ -87,13 +87,13 @@ platform_is_not :windows do # hangs
it 'shuts down a socket for reading using "RD"' do
@client.shutdown('RD')
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).should be_empty
end
it 'shuts down a socket for reading using "SHUT_RD"' do
@client.shutdown('SHUT_RD')
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).should be_empty
end
it 'shuts down a socket for writing using "WR"' do
@@ -123,7 +123,7 @@ platform_is_not :windows do # hangs
@client.shutdown(@dummy)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).should be_empty
end
it 'shuts down a socket for reading using "SHUT_RD"' do
@@ -131,7 +131,7 @@ platform_is_not :windows do # hangs
@client.shutdown(@dummy)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).should be_empty
end
it 'shuts down a socket for reading and writing' do
@@ -139,7 +139,7 @@ platform_is_not :windows do # hangs
@client.shutdown(@dummy)
- @client.recv(1).to_s.should be_empty
+ @client.recv(1).should be_empty
-> { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
diff --git a/spec/ruby/library/socket/fixtures/classes.rb b/spec/ruby/library/socket/fixtures/classes.rb
index 786629d2ef..4a590502ca 100644
--- a/spec/ruby/library/socket/fixtures/classes.rb
+++ b/spec/ruby/library/socket/fixtures/classes.rb
@@ -37,9 +37,7 @@ module SocketSpecs
# Check for too long unix socket path (max 104 bytes on macOS)
# Note that Linux accepts not null-terminated paths but the man page advises against it.
if path.bytesize > 104
- # rm_r in spec/mspec/lib/mspec/helpers/fs.rb fails against
- # "/tmp/unix_server_spec.socket"
- skip "too long unix socket path: #{path}"
+ path = "/tmp/unix_server_spec.socket"
end
rm_socket(path)
path
@@ -113,7 +111,7 @@ module SocketSpecs
begin
data = socket.recv(1024)
- return if data.nil? || data.empty?
+ return if data.empty?
log "SpecTCPServer received: #{data.inspect}"
return if data == "QUIT"
diff --git a/spec/ruby/library/socket/ipsocket/getaddress_spec.rb b/spec/ruby/library/socket/ipsocket/getaddress_spec.rb
index 329f8267d3..746d2ab86b 100644
--- a/spec/ruby/library/socket/ipsocket/getaddress_spec.rb
+++ b/spec/ruby/library/socket/ipsocket/getaddress_spec.rb
@@ -2,6 +2,7 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe "Socket::IPSocket#getaddress" do
+
it "returns the IP address of hostname" do
addr_local = IPSocket.getaddress(SocketSpecs.hostname)
["127.0.0.1", "::1"].include?(addr_local).should == true
@@ -13,16 +14,12 @@ describe "Socket::IPSocket#getaddress" do
IPSocket.getaddress('::1').should == '::1'
end
- it 'returns IPv4 compatible IPv6 addresses' do
- IPSocket.getaddress('::ffff:192.168.1.1').should == '::ffff:192.168.1.1'
- end
-
# There is no way to make this fail-proof on all machines, because
# DNS servers like opendns return A records for ANY host, including
# traditionally invalidly named ones.
it "raises an error on unknown hostnames" do
-> {
- IPSocket.getaddress("rubyspecdoesntexist.ruby-lang.org")
+ IPSocket.getaddress("rubyspecdoesntexist.fallingsnow.net")
}.should raise_error(SocketError)
end
end
diff --git a/spec/ruby/library/socket/shared/pack_sockaddr.rb b/spec/ruby/library/socket/shared/pack_sockaddr.rb
index 26fdf682b1..9f6238e7bc 100644
--- a/spec/ruby/library/socket/shared/pack_sockaddr.rb
+++ b/spec/ruby/library/socket/shared/pack_sockaddr.rb
@@ -17,9 +17,6 @@ describe :socket_pack_sockaddr_in, shared: true do
sockaddr_in = Socket.public_send(@method, nil, '127.0.0.1')
Socket.unpack_sockaddr_in(sockaddr_in).should == [0, '127.0.0.1']
-
- sockaddr_in = Socket.public_send(@method, 80, Socket::INADDR_ANY)
- Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '0.0.0.0']
end
platform_is_not :solaris do
diff --git a/spec/ruby/library/socket/shared/partially_closable_sockets.rb b/spec/ruby/library/socket/shared/partially_closable_sockets.rb
index b1c2ebabe1..1bdff08bf6 100644
--- a/spec/ruby/library/socket/shared/partially_closable_sockets.rb
+++ b/spec/ruby/library/socket/shared/partially_closable_sockets.rb
@@ -1,4 +1,4 @@
-describe :partially_closable_sockets, shared: true do
+describe "partially closable sockets", shared: true do
it "if the write end is closed then the other side can read past EOF without blocking" do
@s1.write("foo")
@s1.close_write
diff --git a/spec/ruby/library/socket/socket/getnameinfo_spec.rb b/spec/ruby/library/socket/socket/getnameinfo_spec.rb
index 4f13bf484d..b406348aa8 100644
--- a/spec/ruby/library/socket/socket/getnameinfo_spec.rb
+++ b/spec/ruby/library/socket/socket/getnameinfo_spec.rb
@@ -70,7 +70,7 @@ describe 'Socket.getnameinfo' do
it 'raises SocketError or TypeError when using an invalid String' do
-> { Socket.getnameinfo('cats') }.should raise_error(Exception) { |e|
- (e.is_a?(SocketError) || e.is_a?(TypeError)).should == true
+ [SocketError, TypeError].should include(e.class)
}
end
diff --git a/spec/ruby/library/socket/socket/new_spec.rb b/spec/ruby/library/socket/socket/new_spec.rb
new file mode 100644
index 0000000000..b2ec607f6a
--- /dev/null
+++ b/spec/ruby/library/socket/socket/new_spec.rb
@@ -0,0 +1,2 @@
+require_relative '../spec_helper'
+require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb b/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb
index ef2a2d4ba9..63d4724453 100644
--- a/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb
+++ b/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb
@@ -2,6 +2,6 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/pack_sockaddr'
-describe "Socket.pack_sockaddr_in" do
+describe "Socket#pack_sockaddr_in" do
it_behaves_like :socket_pack_sockaddr_in, :pack_sockaddr_in
end
diff --git a/spec/ruby/library/socket/socket/pair_spec.rb b/spec/ruby/library/socket/socket/pair_spec.rb
index 8dd470a95e..292eacd38d 100644
--- a/spec/ruby/library/socket/socket/pair_spec.rb
+++ b/spec/ruby/library/socket/socket/pair_spec.rb
@@ -2,6 +2,6 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/socketpair'
-describe "Socket.pair" do
+describe "Socket#pair" do
it_behaves_like :socket_socketpair, :pair
end
diff --git a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
index 5596f91bb8..94f58ac49f 100644
--- a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
+++ b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
@@ -52,27 +52,6 @@ describe 'Socket#recvfrom_nonblock' do
end
end
- it "allows an output buffer as third argument" do
- @client.write('hello')
-
- IO.select([@server])
- buffer = +''
- message, = @server.recvfrom_nonblock(5, 0, buffer)
-
- message.should.equal?(buffer)
- buffer.should == 'hello'
- end
-
- it "preserves the encoding of the given buffer" do
- @client.write('hello')
-
- IO.select([@server])
- buffer = ''.encode(Encoding::ISO_8859_1)
- @server.recvfrom_nonblock(5, 0, buffer)
-
- buffer.encoding.should == Encoding::ISO_8859_1
- end
-
describe 'the returned data' do
it 'is the same as the sent data' do
5.times do
diff --git a/spec/ruby/library/socket/socket/socketpair_spec.rb b/spec/ruby/library/socket/socket/socketpair_spec.rb
index 551c376d49..5b8311124e 100644
--- a/spec/ruby/library/socket/socket/socketpair_spec.rb
+++ b/spec/ruby/library/socket/socket/socketpair_spec.rb
@@ -2,6 +2,6 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/socketpair'
-describe "Socket.socketpair" do
+describe "Socket#socketpair" do
it_behaves_like :socket_socketpair, :socketpair
end
diff --git a/spec/ruby/library/socket/tcpserver/accept_spec.rb b/spec/ruby/library/socket/tcpserver/accept_spec.rb
index d8892cd5f0..d38d95e0e1 100644
--- a/spec/ruby/library/socket/tcpserver/accept_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/accept_spec.rb
@@ -69,7 +69,7 @@ describe "TCPServer#accept" do
Thread.pass while t.status and t.status != "sleep"
# Thread#backtrace uses SIGVTALRM on TruffleRuby and potentially other implementations.
# Sending a signal to a thread is not possible with Ruby APIs.
- t.backtrace.join("\n").should =~ /in [`'](?:TCPServer#)?accept'/
+ t.backtrace.join("\n").should.include?("in `accept'")
socket = TCPSocket.new('127.0.0.1', @port)
socket.write("OK")
@@ -114,19 +114,6 @@ describe 'TCPServer#accept' do
@socket = @server.accept
@socket.should be_an_instance_of(TCPSocket)
end
-
- platform_is_not :windows do
- it "returns a TCPSocket which is set to nonblocking" do
- require 'io/nonblock'
- @socket = @server.accept
- @socket.should.nonblock?
- end
- end
-
- it "returns a TCPSocket which is set to close on exec" do
- @socket = @server.accept
- @socket.should.close_on_exec?
- end
end
end
end
diff --git a/spec/ruby/library/socket/tcpserver/new_spec.rb b/spec/ruby/library/socket/tcpserver/new_spec.rb
index dd1ba676bd..8d9696c9d8 100644
--- a/spec/ruby/library/socket/tcpserver/new_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/new_spec.rb
@@ -97,12 +97,6 @@ describe "TCPServer.new" do
addr[1].should be_kind_of(Integer)
end
- it "does not use the given block and warns to use TCPServer::open" do
- -> {
- @server = TCPServer.new(0) { raise }
- }.should complain(/warning: TCPServer::new\(\) does not take block; use TCPServer::open\(\) instead/)
- end
-
it "raises Errno::EADDRNOTAVAIL when the address is unknown" do
-> { TCPServer.new("1.2.3.4", 0) }.should raise_error(Errno::EADDRNOTAVAIL)
end
diff --git a/spec/ruby/library/socket/tcpsocket/initialize_spec.rb b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
index d7feb9751b..065c8f4190 100644
--- a/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
@@ -4,27 +4,6 @@ require_relative 'shared/new'
describe 'TCPSocket#initialize' do
it_behaves_like :tcpsocket_new, :new
-
- describe "with a running server" do
- before :each do
- @server = SocketSpecs::SpecTCPServer.new
- @hostname = @server.hostname
- end
-
- after :each do
- if @socket
- @socket.write "QUIT"
- @socket.close
- end
- @server.shutdown
- end
-
- it "does not use the given block and warns to use TCPSocket::open" do
- -> {
- @socket = TCPSocket.new(@hostname, @server.port, nil) { raise }
- }.should complain(/warning: TCPSocket::new\(\) does not take block; use TCPSocket::open\(\) instead/)
- end
- end
end
describe 'TCPSocket#initialize' do
@@ -72,19 +51,6 @@ describe 'TCPSocket#initialize' do
@client.remote_address.ip_port.should == @server.local_address.ip_port
end
- platform_is_not :windows do
- it "creates a socket which is set to nonblocking" do
- require 'io/nonblock'
- @client = TCPSocket.new(ip_address, @port)
- @client.should.nonblock?
- end
- end
-
- it "creates a socket which is set to close on exec" do
- @client = TCPSocket.new(ip_address, @port)
- @client.should.close_on_exec?
- end
-
describe 'using a local address and service' do
it 'binds the client socket to the local address and service' do
@client = TCPSocket.new(ip_address, @port, ip_address, 0)
diff --git a/spec/ruby/library/socket/tcpsocket/open_spec.rb b/spec/ruby/library/socket/tcpsocket/open_spec.rb
index 0c0b579064..31b630a23b 100644
--- a/spec/ruby/library/socket/tcpsocket/open_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/open_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative 'shared/new'
describe "TCPSocket.open" do
diff --git a/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb b/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb
index d365ecd335..a381627a39 100644
--- a/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb
@@ -16,6 +16,6 @@ describe "TCPSocket partial closability" do
@s2.close
end
- it_should_behave_like :partially_closable_sockets
+ it_should_behave_like "partially closable sockets"
end
diff --git a/spec/ruby/library/socket/tcpsocket/shared/new.rb b/spec/ruby/library/socket/tcpsocket/shared/new.rb
index 90f8d7e6a2..e7eb2f3c13 100644
--- a/spec/ruby/library/socket/tcpsocket/shared/new.rb
+++ b/spec/ruby/library/socket/tcpsocket/shared/new.rb
@@ -14,14 +14,11 @@ describe :tcpsocket_new, shared: true do
}
end
- ruby_version_is ""..."3.2" do
+ ruby_version_is "3.0"..."3.1" do
it 'raises Errno::ETIMEDOUT with :connect_timeout when no server is listening on the given address' do
-> {
TCPSocket.send(@method, "192.0.2.1", 80, connect_timeout: 0)
}.should raise_error(Errno::ETIMEDOUT)
- rescue Errno::ENETUNREACH
- # In the case all network interfaces down.
- # raise_error cannot deal with multiple expected exceptions
end
end
@@ -30,9 +27,6 @@ describe :tcpsocket_new, shared: true do
-> {
TCPSocket.send(@method, "192.0.2.1", 80, connect_timeout: 0)
}.should raise_error(IO::TimeoutError)
- rescue Errno::ENETUNREACH
- # In the case all network interfaces down.
- # raise_error cannot deal with multiple expected exceptions
end
end
@@ -98,9 +92,11 @@ describe :tcpsocket_new, shared: true do
@socket.addr[2].should =~ /^#{@hostname}/
end
- it "connects to a server when passed connect_timeout argument" do
- @socket = TCPSocket.send(@method, @hostname, @server.port, connect_timeout: 1)
- @socket.should be_an_instance_of(TCPSocket)
+ ruby_version_is "3.0" do
+ it "connects to a server when passed connect_timeout argument" do
+ @socket = TCPSocket.send(@method, @hostname, @server.port, connect_timeout: 1)
+ @socket.should be_an_instance_of(TCPSocket)
+ end
end
end
end
diff --git a/spec/ruby/library/socket/udpsocket/initialize_spec.rb b/spec/ruby/library/socket/udpsocket/initialize_spec.rb
index ecf0043c10..1d635149f7 100644
--- a/spec/ruby/library/socket/udpsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/initialize_spec.rb
@@ -30,19 +30,6 @@ describe 'UDPSocket#initialize' do
@socket.binmode?.should be_true
end
- platform_is_not :windows do
- it 'sets the socket to nonblock' do
- require 'io/nonblock'
- @socket = UDPSocket.new(:INET)
- @socket.should.nonblock?
- end
- end
-
- it 'sets the socket to close on exec' do
- @socket = UDPSocket.new(:INET)
- @socket.should.close_on_exec?
- end
-
it 'raises Errno::EAFNOSUPPORT or Errno::EPROTONOSUPPORT when given an invalid address family' do
-> {
UDPSocket.new(666)
diff --git a/spec/ruby/library/socket/udpsocket/new_spec.rb b/spec/ruby/library/socket/udpsocket/new_spec.rb
index 79bfcb624d..6cc0cadbcb 100644
--- a/spec/ruby/library/socket/udpsocket/new_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/new_spec.rb
@@ -26,12 +26,6 @@ describe 'UDPSocket.new' do
@socket.should be_an_instance_of(UDPSocket)
end
- it "does not use the given block and warns to use UDPSocket::open" do
- -> {
- @socket = UDPSocket.new { raise }
- }.should complain(/warning: UDPSocket::new\(\) does not take block; use UDPSocket::open\(\) instead/)
- end
-
it 'raises Errno::EAFNOSUPPORT or Errno::EPROTONOSUPPORT if unsupported family passed' do
-> { UDPSocket.new(-1) }.should raise_error(SystemCallError) { |e|
[Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT].should include(e.class)
diff --git a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
index b804099589..650a061221 100644
--- a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
@@ -58,15 +58,6 @@ describe 'UDPSocket#recvfrom_nonblock' do
buffer.should == 'h'
end
- it "preserves the encoding of the given buffer" do
- buffer = ''.encode(Encoding::ISO_8859_1)
- IO.select([@server])
- message, = @server.recvfrom_nonblock(1, 0, buffer)
-
- message.should.equal?(buffer)
- buffer.encoding.should == Encoding::ISO_8859_1
- end
-
describe 'the returned Array' do
before do
IO.select([@server])
diff --git a/spec/ruby/library/socket/udpsocket/send_spec.rb b/spec/ruby/library/socket/udpsocket/send_spec.rb
index 6dd5f67bea..5d5de684af 100644
--- a/spec/ruby/library/socket/udpsocket/send_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/send_spec.rb
@@ -63,7 +63,7 @@ describe "UDPSocket#send" do
@msg[1][3].should == "127.0.0.1"
end
- it "raises EMSGSIZE if data is too big" do
+ it "raises EMSGSIZE if data is too too big" do
@socket = UDPSocket.open
begin
-> do
diff --git a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb
index dba3de7359..30688b46b6 100644
--- a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb
+++ b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb
@@ -1,8 +1,9 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXServer#accept_nonblock" do
+describe "UNIXServer#accept_nonblock" do
+
+ platform_is_not :windows do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -32,7 +33,9 @@ with_feature :unix_socket do
@server.accept_nonblock(exception: false).should == :wait_readable
end
end
+end
+with_feature :unix_socket do
describe 'UNIXServer#accept_nonblock' do
before do
@path = SocketSpecs.socket_path
diff --git a/spec/ruby/library/socket/unixserver/accept_spec.rb b/spec/ruby/library/socket/unixserver/accept_spec.rb
index 1305bc6220..c05fbe7f22 100644
--- a/spec/ruby/library/socket/unixserver/accept_spec.rb
+++ b/spec/ruby/library/socket/unixserver/accept_spec.rb
@@ -1,7 +1,7 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
+platform_is_not :windows do
describe "UNIXServer#accept" do
before :each do
@path = SocketSpecs.socket_path
@@ -110,17 +110,6 @@ with_feature :unix_socket do
@socket = @server.accept
@socket.recv(5).should == 'hello'
end
-
- it "is set to nonblocking" do
- require 'io/nonblock'
- @socket = @server.accept
- @socket.should.nonblock?
- end
-
- it "is set to close on exec" do
- @socket = @server.accept
- @socket.should.close_on_exec?
- end
end
end
end
diff --git a/spec/ruby/library/socket/unixserver/for_fd_spec.rb b/spec/ruby/library/socket/unixserver/for_fd_spec.rb
index 8cc55ef391..4f3816ad37 100644
--- a/spec/ruby/library/socket/unixserver/for_fd_spec.rb
+++ b/spec/ruby/library/socket/unixserver/for_fd_spec.rb
@@ -1,8 +1,8 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXServer.for_fd" do
+platform_is_not :windows do
+ describe "UNIXServer#for_fd" do
before :each do
@unix_path = SocketSpecs.socket_path
@unix = UNIXServer.new(@unix_path)
diff --git a/spec/ruby/library/socket/unixserver/new_spec.rb b/spec/ruby/library/socket/unixserver/new_spec.rb
index a160e3ce5c..f831f40bc6 100644
--- a/spec/ruby/library/socket/unixserver/new_spec.rb
+++ b/spec/ruby/library/socket/unixserver/new_spec.rb
@@ -1,14 +1,6 @@
require_relative '../spec_helper'
require_relative 'shared/new'
-with_feature :unix_socket do
- describe "UNIXServer.new" do
- it_behaves_like :unixserver_new, :new
-
- it "does not use the given block and warns to use UNIXServer::open" do
- -> {
- @server = UNIXServer.new(@path) { raise }
- }.should complain(/warning: UNIXServer::new\(\) does not take block; use UNIXServer::open\(\) instead/)
- end
- end
+describe "UNIXServer.new" do
+ it_behaves_like :unixserver_new, :new
end
diff --git a/spec/ruby/library/socket/unixserver/open_spec.rb b/spec/ruby/library/socket/unixserver/open_spec.rb
index 16453dd3bd..f2506d9f6f 100644
--- a/spec/ruby/library/socket/unixserver/open_spec.rb
+++ b/spec/ruby/library/socket/unixserver/open_spec.rb
@@ -2,10 +2,10 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/new'
-with_feature :unix_socket do
- describe "UNIXServer.open" do
- it_behaves_like :unixserver_new, :open
+describe "UNIXServer.open" do
+ it_behaves_like :unixserver_new, :open
+ platform_is_not :windows do
before :each do
@path = SocketSpecs.socket_path
end
diff --git a/spec/ruby/library/socket/unixserver/shared/new.rb b/spec/ruby/library/socket/unixserver/shared/new.rb
index b537f2a871..35395826c9 100644
--- a/spec/ruby/library/socket/unixserver/shared/new.rb
+++ b/spec/ruby/library/socket/unixserver/shared/new.rb
@@ -2,19 +2,21 @@ require_relative '../../spec_helper'
require_relative '../../fixtures/classes'
describe :unixserver_new, shared: true do
- before :each do
- @path = SocketSpecs.socket_path
- end
+ platform_is_not :windows do
+ before :each do
+ @path = SocketSpecs.socket_path
+ end
- after :each do
- @server.close if @server
- @server = nil
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @server.close if @server
+ @server = nil
+ SocketSpecs.rm_socket @path
+ end
- it "creates a new UNIXServer" do
- @server = UNIXServer.send(@method, @path)
- @server.path.should == @path
- @server.addr.should == ["AF_UNIX", @path]
+ it "creates a new UNIXServer" do
+ @server = UNIXServer.send(@method, @path)
+ @server.path.should == @path
+ @server.addr.should == ["AF_UNIX", @path]
+ end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/addr_spec.rb b/spec/ruby/library/socket/unixsocket/addr_spec.rb
index d93e061312..e8431bea16 100644
--- a/spec/ruby/library/socket/unixsocket/addr_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/addr_spec.rb
@@ -1,8 +1,9 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#addr" do
+describe "UNIXSocket#addr" do
+
+ platform_is_not :windows do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
diff --git a/spec/ruby/library/socket/unixsocket/initialize_spec.rb b/spec/ruby/library/socket/unixsocket/initialize_spec.rb
index bf7896ab0e..13b6972f03 100644
--- a/spec/ruby/library/socket/unixsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/initialize_spec.rb
@@ -33,16 +33,6 @@ with_feature :unix_socket do
it 'sets the socket to binmode' do
@socket.binmode?.should be_true
end
-
- it 'sets the socket to nonblock' do
- require 'io/nonblock'
- @socket.should.nonblock?
- end
-
- it 'sets the socket to close on exec' do
- @socket.should.close_on_exec?
- end
-
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/inspect_spec.rb b/spec/ruby/library/socket/unixsocket/inspect_spec.rb
index a542ba6db5..d2e3cabbd3 100644
--- a/spec/ruby/library/socket/unixsocket/inspect_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/inspect_spec.rb
@@ -1,8 +1,8 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#inspect" do
+describe "UNIXSocket#inspect" do
+ platform_is_not :windows do
it "returns sockets fd for unnamed sockets" do
begin
s1, s2 = UNIXSocket.socketpair
diff --git a/spec/ruby/library/socket/unixsocket/local_address_spec.rb b/spec/ruby/library/socket/unixsocket/local_address_spec.rb
index 734253e7f5..cbf315f9f4 100644
--- a/spec/ruby/library/socket/unixsocket/local_address_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/local_address_spec.rb
@@ -46,7 +46,9 @@ with_feature :unix_socket do
end
end
end
+end
+with_feature :unix_socket do
describe 'UNIXSocket#local_address with a UNIX socket pair' do
before :each do
@sock, @sock2 = Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
diff --git a/spec/ruby/library/socket/unixsocket/new_spec.rb b/spec/ruby/library/socket/unixsocket/new_spec.rb
index 6d8ea6dcfe..05a6b3eda2 100644
--- a/spec/ruby/library/socket/unixsocket/new_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/new_spec.rb
@@ -1,14 +1,6 @@
require_relative '../spec_helper'
require_relative 'shared/new'
-with_feature :unix_socket do
- describe "UNIXSocket.new" do
- it_behaves_like :unixsocket_new, :new
-
- it "does not use the given block and warns to use UNIXSocket::open" do
- -> {
- @client = UNIXSocket.new(@path) { raise }
- }.should complain(/warning: UNIXSocket::new\(\) does not take block; use UNIXSocket::open\(\) instead/)
- end
- end
+describe "UNIXSocket.new" do
+ it_behaves_like :unixsocket_new, :new
end
diff --git a/spec/ruby/library/socket/unixsocket/open_spec.rb b/spec/ruby/library/socket/unixsocket/open_spec.rb
index 61def30abb..99ad151bb8 100644
--- a/spec/ruby/library/socket/unixsocket/open_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/open_spec.rb
@@ -2,12 +2,12 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/new'
-with_feature :unix_socket do
- describe "UNIXSocket.open" do
- it_behaves_like :unixsocket_new, :open
- end
+describe "UNIXSocket.open" do
+ it_behaves_like :unixsocket_new, :open
+end
- describe "UNIXSocket.open" do
+describe "UNIXSocket.open" do
+ platform_is_not :windows do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
diff --git a/spec/ruby/library/socket/unixsocket/pair_spec.rb b/spec/ruby/library/socket/unixsocket/pair_spec.rb
index b0a3b2af99..845ff76ecc 100644
--- a/spec/ruby/library/socket/unixsocket/pair_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/pair_spec.rb
@@ -1,12 +1,11 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/partially_closable_sockets'
-require_relative 'shared/pair'
-with_feature :unix_socket do
- describe "UNIXSocket.pair" do
- it_should_behave_like :unixsocket_pair
- it_should_behave_like :partially_closable_sockets
+describe "UNIXSocket#pair" do
+ platform_is_not :windows do
+
+ it_should_behave_like "partially closable sockets"
before :each do
@s1, @s2 = UNIXSocket.pair
@@ -16,5 +15,25 @@ with_feature :unix_socket do
@s1.close
@s2.close
end
+
+ it "returns a pair of connected sockets" do
+ @s1.puts "foo"
+ @s2.gets.should == "foo\n"
+ end
+
+ it "returns sockets with no name" do
+ @s1.path.should == @s2.path
+ @s1.path.should == ""
+ end
+
+ it "returns sockets with no address" do
+ @s1.addr.should == ["AF_UNIX", ""]
+ @s2.addr.should == ["AF_UNIX", ""]
+ end
+
+ it "returns sockets with no peeraddr" do
+ @s1.peeraddr.should == ["AF_UNIX", ""]
+ @s2.peeraddr.should == ["AF_UNIX", ""]
+ end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb b/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb
index ef7d0f0b2a..78a64fe6be 100644
--- a/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb
@@ -2,8 +2,9 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/partially_closable_sockets'
-with_feature :unix_socket do
+platform_is_not :windows do
describe "UNIXSocket partial closability" do
+
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -18,6 +19,7 @@ with_feature :unix_socket do
SocketSpecs.rm_socket @path
end
- it_should_behave_like :partially_closable_sockets
+ it_should_behave_like "partially closable sockets"
+
end
end
diff --git a/spec/ruby/library/socket/unixsocket/path_spec.rb b/spec/ruby/library/socket/unixsocket/path_spec.rb
index a608378e4f..317ffc0975 100644
--- a/spec/ruby/library/socket/unixsocket/path_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/path_spec.rb
@@ -1,8 +1,9 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#path" do
+describe "UNIXSocket#path" do
+
+ platform_is_not :windows do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -23,4 +24,5 @@ with_feature :unix_socket do
@client.path.should == ""
end
end
+
end
diff --git a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb
index 72bc96b1fe..0b6b1ccf04 100644
--- a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb
@@ -1,8 +1,9 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#peeraddr" do
+describe "UNIXSocket#peeraddr" do
+
+ platform_is_not :windows do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -25,4 +26,5 @@ with_feature :unix_socket do
}.should raise_error(Errno::ENOTCONN)
end
end
+
end
diff --git a/spec/ruby/library/socket/unixsocket/recv_io_spec.rb b/spec/ruby/library/socket/unixsocket/recv_io_spec.rb
index 1dbc4538e3..533f02a0fa 100644
--- a/spec/ruby/library/socket/unixsocket/recv_io_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/recv_io_spec.rb
@@ -1,8 +1,9 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#recv_io" do
+describe "UNIXSocket#recv_io" do
+
+ platform_is_not :windows do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -40,7 +41,9 @@ with_feature :unix_socket do
@io.should be_an_instance_of(File)
end
end
+end
+with_feature :unix_socket do
describe 'UNIXSocket#recv_io' do
before do
@file = File.open('/dev/null', 'w')
diff --git a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
index d849fdc302..c0e1cf670b 100644
--- a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
@@ -1,8 +1,8 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#recvfrom" do
+describe "UNIXSocket#recvfrom" do
+ platform_is_not :windows do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -31,29 +31,6 @@ with_feature :unix_socket do
sock.close
end
- it "allows an output buffer as third argument" do
- buffer = +''
-
- @client.send("foobar", 0)
- sock = @server.accept
- message, = sock.recvfrom(6, 0, buffer)
- sock.close
-
- message.should.equal?(buffer)
- buffer.should == "foobar"
- end
-
- it "preserves the encoding of the given buffer" do
- buffer = ''.encode(Encoding::ISO_8859_1)
-
- @client.send("foobar", 0)
- sock = @server.accept
- sock.recvfrom(6, 0, buffer)
- sock.close
-
- buffer.encoding.should == Encoding::ISO_8859_1
- end
-
it "uses different message options" do
@client.send("foobar", Socket::MSG_PEEK)
sock = @server.accept
@@ -65,7 +42,10 @@ with_feature :unix_socket do
sock.close
end
end
+end
+
+with_feature :unix_socket do
describe 'UNIXSocket#recvfrom' do
describe 'using a socket pair' do
before do
diff --git a/spec/ruby/library/socket/unixsocket/send_io_spec.rb b/spec/ruby/library/socket/unixsocket/send_io_spec.rb
index 80f3550c6d..a2a7d26539 100644
--- a/spec/ruby/library/socket/unixsocket/send_io_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/send_io_spec.rb
@@ -1,8 +1,9 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-with_feature :unix_socket do
- describe "UNIXSocket#send_io" do
+describe "UNIXSocket#send_io" do
+
+ platform_is_not :windows do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -31,7 +32,9 @@ with_feature :unix_socket do
@io.read.should == File.read(@send_io_path)
end
end
+end
+with_feature :unix_socket do
describe 'UNIXSocket#send_io' do
before do
@file = File.open('/dev/null', 'w')
diff --git a/spec/ruby/library/socket/unixsocket/shared/new.rb b/spec/ruby/library/socket/unixsocket/shared/new.rb
index f075b03c5e..bfb7ed3886 100644
--- a/spec/ruby/library/socket/unixsocket/shared/new.rb
+++ b/spec/ruby/library/socket/unixsocket/shared/new.rb
@@ -2,21 +2,23 @@ require_relative '../../spec_helper'
require_relative '../../fixtures/classes'
describe :unixsocket_new, shared: true do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- end
+ platform_is_not :windows do
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ end
- after :each do
- @client.close if @client
- @server.close
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @client.close if @client
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
- it "opens a unix socket on the specified file" do
- @client = UNIXSocket.send(@method, @path)
+ it "opens a unix socket on the specified file" do
+ @client = UNIXSocket.send(@method, @path)
- @client.addr[0].should == "AF_UNIX"
- @client.should_not.closed?
+ @client.addr[0].should == "AF_UNIX"
+ @client.should_not.closed?
+ end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/shared/pair.rb b/spec/ruby/library/socket/unixsocket/shared/pair.rb
deleted file mode 100644
index ade7fc9852..0000000000
--- a/spec/ruby/library/socket/unixsocket/shared/pair.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative '../../spec_helper'
-require_relative '../../fixtures/classes'
-
-describe :unixsocket_pair, shared: true do
- it "returns two UNIXSockets" do
- @s1.should be_an_instance_of(UNIXSocket)
- @s2.should be_an_instance_of(UNIXSocket)
- end
-
- it "returns a pair of connected sockets" do
- @s1.puts "foo"
- @s2.gets.should == "foo\n"
- end
-
- it "sets the socket paths to empty Strings" do
- @s1.path.should == ""
- @s2.path.should == ""
- end
-
- it "sets the socket addresses to empty Strings" do
- @s1.addr.should == ["AF_UNIX", ""]
- @s2.addr.should == ["AF_UNIX", ""]
- end
-
- it "sets the socket peer addresses to empty Strings" do
- @s1.peeraddr.should == ["AF_UNIX", ""]
- @s2.peeraddr.should == ["AF_UNIX", ""]
- end
-end
diff --git a/spec/ruby/library/socket/unixsocket/socketpair_spec.rb b/spec/ruby/library/socket/unixsocket/socketpair_spec.rb
index 5f34008df3..3e9646f76b 100644
--- a/spec/ruby/library/socket/unixsocket/socketpair_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/socketpair_spec.rb
@@ -1,20 +1,40 @@
require_relative '../spec_helper'
-require_relative '../fixtures/classes'
-require_relative '../shared/partially_closable_sockets'
-require_relative 'shared/pair'
with_feature :unix_socket do
- describe "UNIXSocket.socketpair" do
- it_should_behave_like :unixsocket_pair
- it_should_behave_like :partially_closable_sockets
-
- before :each do
+ describe 'UNIXSocket.socketpair' do
+ before do
@s1, @s2 = UNIXSocket.socketpair
end
- after :each do
+ after do
@s1.close
@s2.close
end
+
+ it 'returns two UNIXSockets' do
+ @s1.should be_an_instance_of(UNIXSocket)
+ @s2.should be_an_instance_of(UNIXSocket)
+ end
+
+ it 'connects the sockets to each other' do
+ @s1.write('hello')
+
+ @s2.recv(5).should == 'hello'
+ end
+
+ it 'sets the socket paths to empty Strings' do
+ @s1.path.should == ''
+ @s2.path.should == ''
+ end
+
+ it 'sets the socket addresses to empty Strings' do
+ @s1.addr.should == ['AF_UNIX', '']
+ @s2.addr.should == ['AF_UNIX', '']
+ end
+
+ it 'sets the socket peer addresses to empty Strings' do
+ @s1.peeraddr.should == ['AF_UNIX', '']
+ @s2.peeraddr.should == ['AF_UNIX', '']
+ end
end
end
diff --git a/spec/ruby/library/stringio/append_spec.rb b/spec/ruby/library/stringio/append_spec.rb
index cb50d73d1b..981229fc10 100644
--- a/spec/ruby/library/stringio/append_spec.rb
+++ b/spec/ruby/library/stringio/append_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#<< when passed [Object]" do
before :each do
- @io = StringIO.new(+"example")
+ @io = StringIO.new("example")
end
it "returns self" do
@@ -29,6 +29,13 @@ describe "StringIO#<< when passed [Object]" do
@io.string.should == "example\000\000\000\000\000\000\000\000just testing"
end
+ ruby_version_is ""..."3.0" do
+ it "does not taint self when the passed argument is tainted" do
+ (@io << "test".taint)
+ @io.tainted?.should be_false
+ end
+ end
+
it "updates self's position" do
@io << "test"
@io.pos.should eql(4)
@@ -44,10 +51,10 @@ end
describe "StringIO#<< when self is not writable" do
it "raises an IOError" do
- io = StringIO.new(+"test", "r")
+ io = StringIO.new("test", "r")
-> { io << "test" }.should raise_error(IOError)
- io = StringIO.new(+"test")
+ io = StringIO.new("test")
io.close_write
-> { io << "test" }.should raise_error(IOError)
end
@@ -55,7 +62,7 @@ end
describe "StringIO#<< when in append mode" do
before :each do
- @io = StringIO.new(+"example", "a")
+ @io = StringIO.new("example", "a")
end
it "appends the passed argument to the end of self, ignoring current position" do
diff --git a/spec/ruby/library/stringio/binmode_spec.rb b/spec/ruby/library/stringio/binmode_spec.rb
index 9e92c63814..853d9c9bd6 100644
--- a/spec/ruby/library/stringio/binmode_spec.rb
+++ b/spec/ruby/library/stringio/binmode_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#binmode" do
it "returns self" do
- io = StringIO.new(+"example")
+ io = StringIO.new("example")
io.binmode.should equal(io)
end
diff --git a/spec/ruby/library/stringio/bytes_spec.rb b/spec/ruby/library/stringio/bytes_spec.rb
new file mode 100644
index 0000000000..4ef7a490a5
--- /dev/null
+++ b/spec/ruby/library/stringio/bytes_spec.rb
@@ -0,0 +1,29 @@
+require_relative '../../spec_helper'
+require 'stringio'
+require_relative 'shared/each_byte'
+
+ruby_version_is ''...'3.0' do
+ describe "StringIO#bytes" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :stringio_each_byte, :bytes
+ end
+
+ describe "StringIO#bytes when self is not readable" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :stringio_each_byte_not_readable, :bytes
+ end
+end
diff --git a/spec/ruby/library/stringio/chars_spec.rb b/spec/ruby/library/stringio/chars_spec.rb
new file mode 100644
index 0000000000..58cba77634
--- /dev/null
+++ b/spec/ruby/library/stringio/chars_spec.rb
@@ -0,0 +1,29 @@
+require_relative '../../spec_helper'
+require 'stringio'
+require_relative 'shared/each_char'
+
+ruby_version_is ''...'3.0' do
+ describe "StringIO#chars" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :stringio_each_char, :chars
+ end
+
+ describe "StringIO#chars when self is not readable" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :stringio_each_char_not_readable, :chars
+ end
+end
diff --git a/spec/ruby/library/stringio/close_read_spec.rb b/spec/ruby/library/stringio/close_read_spec.rb
index 0f08e1ff2e..80bd547e85 100644
--- a/spec/ruby/library/stringio/close_read_spec.rb
+++ b/spec/ruby/library/stringio/close_read_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#close_read" do
before :each do
- @io = StringIO.new(+"example")
+ @io = StringIO.new("example")
end
it "returns nil" do
@@ -21,7 +21,7 @@ describe "StringIO#close_read" do
end
it "raises an IOError when in write-only mode" do
- io = StringIO.new(+"example", "w")
+ io = StringIO.new("example", "w")
-> { io.close_read }.should raise_error(IOError)
io = StringIO.new("example")
diff --git a/spec/ruby/library/stringio/close_write_spec.rb b/spec/ruby/library/stringio/close_write_spec.rb
index c86c3f9826..1a4cfa113e 100644
--- a/spec/ruby/library/stringio/close_write_spec.rb
+++ b/spec/ruby/library/stringio/close_write_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#close_write" do
before :each do
- @io = StringIO.new(+"example")
+ @io = StringIO.new("example")
end
it "returns nil" do
@@ -21,10 +21,10 @@ describe "StringIO#close_write" do
end
it "raises an IOError when in read-only mode" do
- io = StringIO.new(+"example", "r")
+ io = StringIO.new("example", "r")
-> { io.close_write }.should raise_error(IOError)
- io = StringIO.new(+"example")
+ io = StringIO.new("example")
io.close_write
io.close_write.should == nil
end
diff --git a/spec/ruby/library/stringio/closed_read_spec.rb b/spec/ruby/library/stringio/closed_read_spec.rb
index b4dcadc3a4..cb4267ac98 100644
--- a/spec/ruby/library/stringio/closed_read_spec.rb
+++ b/spec/ruby/library/stringio/closed_read_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#closed_read?" do
it "returns true if self is not readable" do
- io = StringIO.new(+"example", "r+")
+ io = StringIO.new("example", "r+")
io.close_write
io.closed_read?.should be_false
io.close_read
diff --git a/spec/ruby/library/stringio/closed_spec.rb b/spec/ruby/library/stringio/closed_spec.rb
index bf7ba63184..ca8a2232a8 100644
--- a/spec/ruby/library/stringio/closed_spec.rb
+++ b/spec/ruby/library/stringio/closed_spec.rb
@@ -3,13 +3,13 @@ require_relative 'fixtures/classes'
describe "StringIO#closed?" do
it "returns true if self is completely closed" do
- io = StringIO.new(+"example", "r+")
+ io = StringIO.new("example", "r+")
io.close_read
io.closed?.should be_false
io.close_write
io.closed?.should be_true
- io = StringIO.new(+"example", "r+")
+ io = StringIO.new("example", "r+")
io.close
io.closed?.should be_true
end
diff --git a/spec/ruby/library/stringio/closed_write_spec.rb b/spec/ruby/library/stringio/closed_write_spec.rb
index 2bd3e6fa8b..5c111affd8 100644
--- a/spec/ruby/library/stringio/closed_write_spec.rb
+++ b/spec/ruby/library/stringio/closed_write_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#closed_write?" do
it "returns true if self is not writable" do
- io = StringIO.new(+"example", "r+")
+ io = StringIO.new("example", "r+")
io.close_read
io.closed_write?.should be_false
io.close_write
diff --git a/spec/ruby/library/stringio/codepoints_spec.rb b/spec/ruby/library/stringio/codepoints_spec.rb
new file mode 100644
index 0000000000..ceaadefc32
--- /dev/null
+++ b/spec/ruby/library/stringio/codepoints_spec.rb
@@ -0,0 +1,19 @@
+# -*- encoding: utf-8 -*-
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/codepoints'
+
+ruby_version_is ''...'3.0' do
+ # See redmine #1667
+ describe "StringIO#codepoints" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :stringio_codepoints, :codepoints
+ end
+end
diff --git a/spec/ruby/library/stringio/flush_spec.rb b/spec/ruby/library/stringio/flush_spec.rb
index 4dc58b1d48..17a16dfdd5 100644
--- a/spec/ruby/library/stringio/flush_spec.rb
+++ b/spec/ruby/library/stringio/flush_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#flush" do
it "returns self" do
- io = StringIO.new(+"flush")
+ io = StringIO.new("flush")
io.flush.should equal(io)
end
end
diff --git a/spec/ruby/library/stringio/fsync_spec.rb b/spec/ruby/library/stringio/fsync_spec.rb
index 85053cb2e5..8fb2b59a24 100644
--- a/spec/ruby/library/stringio/fsync_spec.rb
+++ b/spec/ruby/library/stringio/fsync_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#fsync" do
it "returns zero" do
- io = StringIO.new(+"fsync")
+ io = StringIO.new("fsync")
io.fsync.should eql(0)
end
end
diff --git a/spec/ruby/library/stringio/gets_spec.rb b/spec/ruby/library/stringio/gets_spec.rb
index 4af7704a41..d597ec0e45 100644
--- a/spec/ruby/library/stringio/gets_spec.rb
+++ b/spec/ruby/library/stringio/gets_spec.rb
@@ -233,7 +233,7 @@ end
describe "StringIO#gets when in write-only mode" do
it "raises an IOError" do
- io = StringIO.new(+"xyz", "w")
+ io = StringIO.new("xyz", "w")
-> { io.gets }.should raise_error(IOError)
io = StringIO.new("xyz")
diff --git a/spec/ruby/library/stringio/initialize_spec.rb b/spec/ruby/library/stringio/initialize_spec.rb
index 6f4d2e456c..c597e328d3 100644
--- a/spec/ruby/library/stringio/initialize_spec.rb
+++ b/spec/ruby/library/stringio/initialize_spec.rb
@@ -13,99 +13,99 @@ describe "StringIO#initialize when passed [Object, mode]" do
it "sets the mode based on the passed mode" do
io = StringIO.allocate
- io.send(:initialize, +"example", "r")
+ io.send(:initialize, "example", "r")
io.closed_read?.should be_false
io.closed_write?.should be_true
io = StringIO.allocate
- io.send(:initialize, +"example", "rb")
+ io.send(:initialize, "example", "rb")
io.closed_read?.should be_false
io.closed_write?.should be_true
io = StringIO.allocate
- io.send(:initialize, +"example", "r+")
+ io.send(:initialize, "example", "r+")
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", "rb+")
+ io.send(:initialize, "example", "rb+")
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", "w")
+ io.send(:initialize, "example", "w")
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", "wb")
+ io.send(:initialize, "example", "wb")
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", "w+")
+ io.send(:initialize, "example", "w+")
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", "wb+")
+ io.send(:initialize, "example", "wb+")
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", "a")
+ io.send(:initialize, "example", "a")
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", "ab")
+ io.send(:initialize, "example", "ab")
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", "a+")
+ io.send(:initialize, "example", "a+")
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", "ab+")
+ io.send(:initialize, "example", "ab+")
io.closed_read?.should be_false
io.closed_write?.should be_false
end
it "allows passing the mode as an Integer" do
io = StringIO.allocate
- io.send(:initialize, +"example", IO::RDONLY)
+ io.send(:initialize, "example", IO::RDONLY)
io.closed_read?.should be_false
io.closed_write?.should be_true
io = StringIO.allocate
- io.send(:initialize, +"example", IO::RDWR)
+ io.send(:initialize, "example", IO::RDWR)
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", IO::WRONLY)
+ io.send(:initialize, "example", IO::WRONLY)
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", IO::WRONLY | IO::TRUNC)
+ io.send(:initialize, "example", IO::WRONLY | IO::TRUNC)
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", IO::RDWR | IO::TRUNC)
+ io.send(:initialize, "example", IO::RDWR | IO::TRUNC)
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", IO::WRONLY | IO::APPEND)
+ io.send(:initialize, "example", IO::WRONLY | IO::APPEND)
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, +"example", IO::RDWR | IO::APPEND)
+ io.send(:initialize, "example", IO::RDWR | IO::APPEND)
io.closed_read?.should be_false
io.closed_write?.should be_false
end
@@ -118,7 +118,7 @@ describe "StringIO#initialize when passed [Object, mode]" do
it "tries to convert the passed mode to a String using #to_str" do
obj = mock('to_str')
obj.should_receive(:to_str).and_return("r")
- @io.send(:initialize, +"example", obj)
+ @io.send(:initialize, "example", obj)
@io.closed_read?.should be_false
@io.closed_write?.should be_true
@@ -130,26 +130,6 @@ describe "StringIO#initialize when passed [Object, mode]" do
-> { @io.send(:initialize, str, "w") }.should raise_error(Errno::EACCES)
-> { @io.send(:initialize, str, "a") }.should raise_error(Errno::EACCES)
end
-
- it "truncates all the content if passed w mode" do
- io = StringIO.allocate
- source = +"example".encode(Encoding::ISO_8859_1);
-
- io.send(:initialize, source, "w")
-
- io.string.should.empty?
- io.string.encoding.should == Encoding::ISO_8859_1
- end
-
- it "truncates all the content if passed IO::TRUNC mode" do
- io = StringIO.allocate
- source = +"example".encode(Encoding::ISO_8859_1);
-
- io.send(:initialize, source, IO::TRUNC)
-
- io.string.should.empty?
- io.string.encoding.should == Encoding::ISO_8859_1
- end
end
describe "StringIO#initialize when passed [Object]" do
@@ -162,18 +142,12 @@ describe "StringIO#initialize when passed [Object]" do
@io.string.should equal(str)
end
- it "sets the mode to read-write if the string is mutable" do
- @io.send(:initialize, +"example")
+ it "sets the mode to read-write" do
+ @io.send(:initialize, "example")
@io.closed_read?.should be_false
@io.closed_write?.should be_false
end
- it "sets the mode to read if the string is frozen" do
- @io.send(:initialize, -"example")
- @io.closed_read?.should be_false
- @io.closed_write?.should be_true
- end
-
it "tries to convert the passed Object to a String using #to_str" do
obj = mock('to_str')
obj.should_receive(:to_str).and_return("example")
@@ -192,28 +166,28 @@ end
# NOTE: Synchronise with core/io/new_spec.rb (core/io/shared/new.rb)
describe "StringIO#initialize when passed keyword arguments" do
it "sets the mode based on the passed :mode option" do
- io = StringIO.new("example", mode: "r")
+ io = StringIO.new("example", "r")
io.closed_read?.should be_false
io.closed_write?.should be_true
end
it "accepts a mode argument set to nil with a valid :mode option" do
- @io = StringIO.new(+'', nil, mode: "w")
+ @io = StringIO.new('', nil, mode: "w")
@io.write("foo").should == 3
end
it "accepts a mode argument with a :mode option set to nil" do
- @io = StringIO.new(+'', "w", mode: nil)
+ @io = StringIO.new('', "w", mode: nil)
@io.write("foo").should == 3
end
it "sets binmode from :binmode option" do
- @io = StringIO.new(+'', 'w', binmode: true)
+ @io = StringIO.new('', 'w', binmode: true)
@io.external_encoding.to_s.should == "ASCII-8BIT" # #binmode? isn't implemented in StringIO
end
it "does not set binmode from false :binmode" do
- @io = StringIO.new(+'', 'w', binmode: false)
+ @io = StringIO.new('', 'w', binmode: false)
@io.external_encoding.to_s.should == "UTF-8" # #binmode? isn't implemented in StringIO
end
end
@@ -222,54 +196,54 @@ end
describe "StringIO#initialize when passed keyword arguments and error happens" do
it "raises an error if passed encodings two ways" do
-> {
- @io = StringIO.new(+'', 'w:ISO-8859-1', encoding: 'ISO-8859-1')
+ @io = StringIO.new('', 'w:ISO-8859-1', encoding: 'ISO-8859-1')
}.should raise_error(ArgumentError)
-> {
- @io = StringIO.new(+'', 'w:ISO-8859-1', external_encoding: 'ISO-8859-1')
+ @io = StringIO.new('', 'w:ISO-8859-1', external_encoding: 'ISO-8859-1')
}.should raise_error(ArgumentError)
-> {
- @io = StringIO.new(+'', 'w:ISO-8859-1:UTF-8', internal_encoding: 'ISO-8859-1')
+ @io = StringIO.new('', 'w:ISO-8859-1:UTF-8', internal_encoding: 'ISO-8859-1')
}.should raise_error(ArgumentError)
end
it "raises an error if passed matching binary/text mode two ways" do
-> {
- @io = StringIO.new(+'', "wb", binmode: true)
+ @io = StringIO.new('', "wb", binmode: true)
}.should raise_error(ArgumentError)
-> {
- @io = StringIO.new(+'', "wt", textmode: true)
+ @io = StringIO.new('', "wt", textmode: true)
}.should raise_error(ArgumentError)
-> {
- @io = StringIO.new(+'', "wb", textmode: false)
+ @io = StringIO.new('', "wb", textmode: false)
}.should raise_error(ArgumentError)
-> {
- @io = StringIO.new(+'', "wt", binmode: false)
+ @io = StringIO.new('', "wt", binmode: false)
}.should raise_error(ArgumentError)
end
it "raises an error if passed conflicting binary/text mode two ways" do
-> {
- @io = StringIO.new(+'', "wb", binmode: false)
+ @io = StringIO.new('', "wb", binmode: false)
}.should raise_error(ArgumentError)
-> {
- @io = StringIO.new(+'', "wt", textmode: false)
+ @io = StringIO.new('', "wt", textmode: false)
}.should raise_error(ArgumentError)
-> {
- @io = StringIO.new(+'', "wb", textmode: true)
+ @io = StringIO.new('', "wb", textmode: true)
}.should raise_error(ArgumentError)
-> {
- @io = StringIO.new(+'', "wt", binmode: true)
+ @io = StringIO.new('', "wt", binmode: true)
}.should raise_error(ArgumentError)
end
it "raises an error when trying to set both binmode and textmode" do
-> {
- @io = StringIO.new(+'', "w", textmode: true, binmode: true)
+ @io = StringIO.new('', "w", textmode: true, binmode: true)
}.should raise_error(ArgumentError)
-> {
- @io = StringIO.new(+'', File::Constants::WRONLY, textmode: true, binmode: true)
+ @io = StringIO.new('', File::Constants::WRONLY, textmode: true, binmode: true)
}.should raise_error(ArgumentError)
end
end
@@ -284,7 +258,7 @@ describe "StringIO#initialize when passed no arguments" do
end
it "sets the mode to read-write" do
- @io.send(:initialize)
+ @io.send(:initialize, "example")
@io.closed_read?.should be_false
@io.closed_write?.should be_false
end
@@ -315,14 +289,19 @@ describe "StringIO#initialize sets" do
end
it "the encoding to the encoding of the String when passed a String" do
- s = ''.dup.force_encoding(Encoding::EUC_JP)
+ s = ''.force_encoding(Encoding::EUC_JP)
io = StringIO.new(s)
io.string.encoding.should == Encoding::EUC_JP
end
- it "the #external_encoding to the encoding of the String when passed a String" do
- s = ''.dup.force_encoding(Encoding::EUC_JP)
- io = StringIO.new(s)
- io.external_encoding.should == Encoding::EUC_JP
+ guard_not -> { # [Bug #16497]
+ stringio_version = StringIO.const_defined?(:VERSION) ? StringIO::VERSION : "0.0.2"
+ version_is(stringio_version, "0.0.3"..."0.1.1")
+ } do
+ it "the #external_encoding to the encoding of the String when passed a String" do
+ s = ''.force_encoding(Encoding::EUC_JP)
+ io = StringIO.new(s)
+ io.external_encoding.should == Encoding::EUC_JP
+ end
end
end
diff --git a/spec/ruby/library/stringio/lines_spec.rb b/spec/ruby/library/stringio/lines_spec.rb
new file mode 100644
index 0000000000..42d11772ae
--- /dev/null
+++ b/spec/ruby/library/stringio/lines_spec.rb
@@ -0,0 +1,53 @@
+require_relative '../../spec_helper'
+require 'stringio'
+require_relative 'shared/each'
+
+ruby_version_is ''...'3.0' do
+ describe "StringIO#lines when passed a separator" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :stringio_each_separator, :lines
+ end
+
+ describe "StringIO#lines when passed no arguments" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :stringio_each_no_arguments, :lines
+ end
+
+ describe "StringIO#lines when self is not readable" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :stringio_each_not_readable, :lines
+ end
+
+ describe "StringIO#lines when passed chomp" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ end
+
+ after :each do
+ $VERBOSE = @verbose
+ end
+
+ it_behaves_like :stringio_each_chomp, :lines
+ end
+end
diff --git a/spec/ruby/library/stringio/new_spec.rb b/spec/ruby/library/stringio/new_spec.rb
index ec4b32aa11..e36d210caa 100644
--- a/spec/ruby/library/stringio/new_spec.rb
+++ b/spec/ruby/library/stringio/new_spec.rb
@@ -2,9 +2,7 @@ require_relative '../../spec_helper'
require 'stringio'
describe "StringIO.new" do
- it "does not use the given block and warns to use StringIO::open" do
- -> {
- StringIO.new { raise }
- }.should complain(/warning: StringIO::new\(\) does not take block; use StringIO::open\(\) instead/)
+ it "warns when called with a block" do
+ -> { eval("StringIO.new {}") }.should complain(/StringIO::new\(\) does not take block; use StringIO::open\(\) instead/)
end
-end
+end \ No newline at end of file
diff --git a/spec/ruby/library/stringio/open_spec.rb b/spec/ruby/library/stringio/open_spec.rb
index b7c90661f9..3068e19435 100644
--- a/spec/ruby/library/stringio/open_spec.rb
+++ b/spec/ruby/library/stringio/open_spec.rb
@@ -8,26 +8,26 @@ describe "StringIO.open when passed [Object, mode]" do
end
it "returns the blocks return value when yielding" do
- ret = StringIO.open(+"example", "r") { :test }
+ ret = StringIO.open("example", "r") { :test }
ret.should equal(:test)
end
it "yields self to the passed block" do
io = nil
- StringIO.open(+"example", "r") { |strio| io = strio }
+ StringIO.open("example", "r") { |strio| io = strio }
io.should be_kind_of(StringIO)
end
it "closes self after yielding" do
io = nil
- StringIO.open(+"example", "r") { |strio| io = strio }
+ StringIO.open("example", "r") { |strio| io = strio }
io.closed?.should be_true
end
it "even closes self when an exception is raised while yielding" do
io = nil
begin
- StringIO.open(+"example", "r") do |strio|
+ StringIO.open("example", "r") do |strio|
io = strio
raise "Error"
end
@@ -38,14 +38,14 @@ describe "StringIO.open when passed [Object, mode]" do
it "sets self's string to nil after yielding" do
io = nil
- StringIO.open(+"example", "r") { |strio| io = strio }
+ StringIO.open("example", "r") { |strio| io = strio }
io.string.should be_nil
end
it "even sets self's string to nil when an exception is raised while yielding" do
io = nil
begin
- StringIO.open(+"example", "r") do |strio|
+ StringIO.open("example", "r") do |strio|
io = strio
raise "Error"
end
@@ -55,81 +55,81 @@ describe "StringIO.open when passed [Object, mode]" do
end
it "sets the mode based on the passed mode" do
- io = StringIO.open(+"example", "r")
+ io = StringIO.open("example", "r")
io.closed_read?.should be_false
io.closed_write?.should be_true
- io = StringIO.open(+"example", "rb")
+ io = StringIO.open("example", "rb")
io.closed_read?.should be_false
io.closed_write?.should be_true
- io = StringIO.open(+"example", "r+")
+ io = StringIO.open("example", "r+")
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open(+"example", "rb+")
+ io = StringIO.open("example", "rb+")
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open(+"example", "w")
+ io = StringIO.open("example", "w")
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open(+"example", "wb")
+ io = StringIO.open("example", "wb")
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open(+"example", "w+")
+ io = StringIO.open("example", "w+")
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open(+"example", "wb+")
+ io = StringIO.open("example", "wb+")
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open(+"example", "a")
+ io = StringIO.open("example", "a")
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open(+"example", "ab")
+ io = StringIO.open("example", "ab")
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open(+"example", "a+")
+ io = StringIO.open("example", "a+")
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open(+"example", "ab+")
+ io = StringIO.open("example", "ab+")
io.closed_read?.should be_false
io.closed_write?.should be_false
end
it "allows passing the mode as an Integer" do
- io = StringIO.open(+"example", IO::RDONLY)
+ io = StringIO.open("example", IO::RDONLY)
io.closed_read?.should be_false
io.closed_write?.should be_true
- io = StringIO.open(+"example", IO::RDWR)
+ io = StringIO.open("example", IO::RDWR)
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open(+"example", IO::WRONLY)
+ io = StringIO.open("example", IO::WRONLY)
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open(+"example", IO::WRONLY | IO::TRUNC)
+ io = StringIO.open("example", IO::WRONLY | IO::TRUNC)
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open(+"example", IO::RDWR | IO::TRUNC)
+ io = StringIO.open("example", IO::RDWR | IO::TRUNC)
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open(+"example", IO::WRONLY | IO::APPEND)
+ io = StringIO.open("example", IO::WRONLY | IO::APPEND)
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open(+"example", IO::RDWR | IO::APPEND)
+ io = StringIO.open("example", IO::RDWR | IO::APPEND)
io.closed_read?.should be_false
io.closed_write?.should be_false
end
@@ -141,7 +141,7 @@ describe "StringIO.open when passed [Object, mode]" do
it "tries to convert the passed mode to a String using #to_str" do
obj = mock('to_str')
obj.should_receive(:to_str).and_return("r")
- io = StringIO.open(+"example", obj)
+ io = StringIO.open("example", obj)
io.closed_read?.should be_false
io.closed_write?.should be_true
@@ -163,16 +163,16 @@ describe "StringIO.open when passed [Object]" do
it "yields self to the passed block" do
io = nil
- ret = StringIO.open(+"example") { |strio| io = strio }
+ ret = StringIO.open("example") { |strio| io = strio }
io.should equal(ret)
end
it "sets the mode to read-write (r+)" do
- io = StringIO.open(+"example")
+ io = StringIO.open("example")
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.new(+"example")
+ io = StringIO.new("example")
io.printf("%d", 123)
io.string.should == "123mple"
end
@@ -204,7 +204,7 @@ describe "StringIO.open when passed no arguments" do
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.new(+"example")
+ io = StringIO.new("example")
io.printf("%d", 123)
io.string.should == "123mple"
end
diff --git a/spec/ruby/library/stringio/print_spec.rb b/spec/ruby/library/stringio/print_spec.rb
index 00c33367dc..6ac6430900 100644
--- a/spec/ruby/library/stringio/print_spec.rb
+++ b/spec/ruby/library/stringio/print_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#print" do
before :each do
- @io = StringIO.new(+'example')
+ @io = StringIO.new('example')
end
it "prints $_ when passed no arguments" do
@@ -73,7 +73,7 @@ end
describe "StringIO#print when in append mode" do
before :each do
- @io = StringIO.new(+"example", "a")
+ @io = StringIO.new("example", "a")
end
it "appends the passed argument to the end of self" do
@@ -92,10 +92,10 @@ end
describe "StringIO#print when self is not writable" do
it "raises an IOError" do
- io = StringIO.new(+"test", "r")
+ io = StringIO.new("test", "r")
-> { io.print("test") }.should raise_error(IOError)
- io = StringIO.new(+"test")
+ io = StringIO.new("test")
io.close_write
-> { io.print("test") }.should raise_error(IOError)
end
diff --git a/spec/ruby/library/stringio/printf_spec.rb b/spec/ruby/library/stringio/printf_spec.rb
index ca82e84757..f3f669a185 100644
--- a/spec/ruby/library/stringio/printf_spec.rb
+++ b/spec/ruby/library/stringio/printf_spec.rb
@@ -41,7 +41,7 @@ end
describe "StringIO#printf when in read-write mode" do
before :each do
- @io = StringIO.new(+"example", "r+")
+ @io = StringIO.new("example", "r+")
end
it "starts from the beginning" do
@@ -62,7 +62,7 @@ end
describe "StringIO#printf when in append mode" do
before :each do
- @io = StringIO.new(+"example", "a")
+ @io = StringIO.new("example", "a")
end
it "appends the passed argument to the end of self" do
@@ -81,10 +81,10 @@ end
describe "StringIO#printf when self is not writable" do
it "raises an IOError" do
- io = StringIO.new(+"test", "r")
+ io = StringIO.new("test", "r")
-> { io.printf("test") }.should raise_error(IOError)
- io = StringIO.new(+"test")
+ io = StringIO.new("test")
io.close_write
-> { io.printf("test") }.should raise_error(IOError)
end
diff --git a/spec/ruby/library/stringio/putc_spec.rb b/spec/ruby/library/stringio/putc_spec.rb
index 9f1ac8ffb2..1ce53b7ef2 100644
--- a/spec/ruby/library/stringio/putc_spec.rb
+++ b/spec/ruby/library/stringio/putc_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#putc when passed [String]" do
before :each do
- @io = StringIO.new(+'example')
+ @io = StringIO.new('example')
end
it "overwrites the character at the current position" do
@@ -54,7 +54,7 @@ end
describe "StringIO#putc when passed [Object]" do
before :each do
- @io = StringIO.new(+'example')
+ @io = StringIO.new('example')
end
it "it writes the passed Integer % 256 to self" do
@@ -85,7 +85,7 @@ end
describe "StringIO#putc when in append mode" do
it "appends to the end of self" do
- io = StringIO.new(+"test", "a")
+ io = StringIO.new("test", "a")
io.putc(?t)
io.string.should == "testt"
end
@@ -93,10 +93,10 @@ end
describe "StringIO#putc when self is not writable" do
it "raises an IOError" do
- io = StringIO.new(+"test", "r")
+ io = StringIO.new("test", "r")
-> { io.putc(?a) }.should raise_error(IOError)
- io = StringIO.new(+"test")
+ io = StringIO.new("test")
io.close_write
-> { io.putc("t") }.should raise_error(IOError)
end
diff --git a/spec/ruby/library/stringio/puts_spec.rb b/spec/ruby/library/stringio/puts_spec.rb
index 054ec8227f..9c890262dd 100644
--- a/spec/ruby/library/stringio/puts_spec.rb
+++ b/spec/ruby/library/stringio/puts_spec.rb
@@ -145,7 +145,7 @@ end
describe "StringIO#puts when in append mode" do
before :each do
- @io = StringIO.new(+"example", "a")
+ @io = StringIO.new("example", "a")
end
it "appends the passed argument to the end of self" do
@@ -164,10 +164,10 @@ end
describe "StringIO#puts when self is not writable" do
it "raises an IOError" do
- io = StringIO.new(+"test", "r")
+ io = StringIO.new("test", "r")
-> { io.puts }.should raise_error(IOError)
- io = StringIO.new(+"test")
+ io = StringIO.new("test")
io.close_write
-> { io.puts }.should raise_error(IOError)
end
@@ -175,7 +175,7 @@ end
describe "StringIO#puts when passed an encoded string" do
it "stores the bytes unmodified" do
- io = StringIO.new(+"")
+ io = StringIO.new("")
io.puts "\x00\x01\x02"
io.puts "æåø"
diff --git a/spec/ruby/library/stringio/read_nonblock_spec.rb b/spec/ruby/library/stringio/read_nonblock_spec.rb
index 74736f7792..d4ec56d9aa 100644
--- a/spec/ruby/library/stringio/read_nonblock_spec.rb
+++ b/spec/ruby/library/stringio/read_nonblock_spec.rb
@@ -8,7 +8,7 @@ describe "StringIO#read_nonblock when passed length, buffer" do
it "accepts :exception option" do
io = StringIO.new("example")
- io.read_nonblock(3, buffer = +"", exception: true)
+ io.read_nonblock(3, buffer = "", exception: true)
buffer.should == "exa"
end
end
@@ -40,7 +40,7 @@ describe "StringIO#read_nonblock" do
context "when exception option is set to false" do
context "when the end is reached" do
it "returns nil" do
- stringio = StringIO.new(+'')
+ stringio = StringIO.new('')
stringio << "hello"
stringio.rewind
diff --git a/spec/ruby/library/stringio/read_spec.rb b/spec/ruby/library/stringio/read_spec.rb
index e49f262127..52ab3dcf47 100644
--- a/spec/ruby/library/stringio/read_spec.rb
+++ b/spec/ruby/library/stringio/read_spec.rb
@@ -53,7 +53,7 @@ describe "StringIO#read when passed length and a buffer" do
end
it "reads [length] characters into the buffer" do
- buf = +"foo"
+ buf = "foo"
result = @io.read(10, buf)
buf.should == "abcdefghij"
diff --git a/spec/ruby/library/stringio/readline_spec.rb b/spec/ruby/library/stringio/readline_spec.rb
index b16a16e23f..b794e5fade 100644
--- a/spec/ruby/library/stringio/readline_spec.rb
+++ b/spec/ruby/library/stringio/readline_spec.rb
@@ -113,7 +113,7 @@ end
describe "StringIO#readline when in write-only mode" do
it "raises an IOError" do
- io = StringIO.new(+"xyz", "w")
+ io = StringIO.new("xyz", "w")
-> { io.readline }.should raise_error(IOError)
io = StringIO.new("xyz")
diff --git a/spec/ruby/library/stringio/readlines_spec.rb b/spec/ruby/library/stringio/readlines_spec.rb
index ed7cc22b3d..c471d0fd73 100644
--- a/spec/ruby/library/stringio/readlines_spec.rb
+++ b/spec/ruby/library/stringio/readlines_spec.rb
@@ -83,7 +83,7 @@ end
describe "StringIO#readlines when in write-only mode" do
it "raises an IOError" do
- io = StringIO.new(+"xyz", "w")
+ io = StringIO.new("xyz", "w")
-> { io.readlines }.should raise_error(IOError)
io = StringIO.new("xyz")
diff --git a/spec/ruby/library/stringio/readpartial_spec.rb b/spec/ruby/library/stringio/readpartial_spec.rb
index f25cef4014..2601fe8c42 100644
--- a/spec/ruby/library/stringio/readpartial_spec.rb
+++ b/spec/ruby/library/stringio/readpartial_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#readpartial" do
before :each do
- @string = StringIO.new(+'Stop, look, listen')
+ @string = StringIO.new('Stop, look, listen')
end
after :each do
@@ -48,7 +48,7 @@ describe "StringIO#readpartial" do
end
it "discards the existing buffer content upon successful read" do
- buffer = +"existing"
+ buffer = "existing"
@string.readpartial(11, buffer)
buffer.should == "Stop, look,"
end
@@ -59,7 +59,7 @@ describe "StringIO#readpartial" do
end
it "discards the existing buffer content upon error" do
- buffer = +'hello'
+ buffer = 'hello'
@string.readpartial(100)
-> { @string.readpartial(1, buffer) }.should raise_error(EOFError)
buffer.should be_empty
diff --git a/spec/ruby/library/stringio/reopen_spec.rb b/spec/ruby/library/stringio/reopen_spec.rb
index 7021ff17e5..4863a5332b 100644
--- a/spec/ruby/library/stringio/reopen_spec.rb
+++ b/spec/ruby/library/stringio/reopen_spec.rb
@@ -12,20 +12,31 @@ describe "StringIO#reopen when passed [Object, Integer]" do
@io.closed_write?.should be_true
@io.string.should == "reopened"
- @io.reopen(+"reopened, twice", IO::WRONLY)
+ @io.reopen("reopened, twice", IO::WRONLY)
@io.closed_read?.should be_true
@io.closed_write?.should be_false
@io.string.should == "reopened, twice"
- @io.reopen(+"reopened, another time", IO::RDWR)
+ @io.reopen("reopened, another time", IO::RDWR)
@io.closed_read?.should be_false
@io.closed_write?.should be_false
@io.string.should == "reopened, another time"
end
+ ruby_version_is ""..."3.0" do
+ # NOTE: WEIRD!
+ it "does not taint self when the passed Object was tainted" do
+ @io.reopen("reopened".taint, IO::RDONLY)
+ @io.tainted?.should be_false
+
+ @io.reopen("reopened".taint, IO::WRONLY)
+ @io.tainted?.should be_false
+ end
+ end
+
it "tries to convert the passed Object to a String using #to_str" do
obj = mock("to_str")
- obj.should_receive(:to_str).and_return(+"to_str")
+ obj.should_receive(:to_str).and_return("to_str")
@io.reopen(obj, IO::RDWR)
@io.string.should == "to_str"
end
@@ -60,27 +71,38 @@ describe "StringIO#reopen when passed [Object, Object]" do
@io.closed_write?.should be_true
@io.string.should == "reopened"
- @io.reopen(+"reopened, twice", "r+")
+ @io.reopen("reopened, twice", "r+")
@io.closed_read?.should be_false
@io.closed_write?.should be_false
@io.string.should == "reopened, twice"
- @io.reopen(+"reopened, another", "w+")
+ @io.reopen("reopened, another", "w+")
@io.closed_read?.should be_false
@io.closed_write?.should be_false
@io.string.should == ""
- @io.reopen(+"reopened, another time", "r+")
+ @io.reopen("reopened, another time", "r+")
@io.closed_read?.should be_false
@io.closed_write?.should be_false
@io.string.should == "reopened, another time"
end
it "truncates the passed String when opened in truncate mode" do
- @io.reopen(str = +"reopened", "w")
+ @io.reopen(str = "reopened", "w")
str.should == ""
end
+ ruby_version_is ""..."3.0" do
+ # NOTE: WEIRD!
+ it "does not taint self when the passed Object was tainted" do
+ @io.reopen("reopened".taint, "r")
+ @io.tainted?.should be_false
+
+ @io.reopen("reopened".taint, "w")
+ @io.tainted?.should be_false
+ end
+ end
+
it "tries to convert the passed Object to a String using #to_str" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return("to_str")
@@ -94,13 +116,13 @@ describe "StringIO#reopen when passed [Object, Object]" do
it "resets self's position to 0" do
@io.read(5)
- @io.reopen(+"reopened")
+ @io.reopen("reopened")
@io.pos.should eql(0)
end
it "resets self's line number to 0" do
@io.gets
- @io.reopen(+"reopened")
+ @io.reopen("reopened")
@io.lineno.should eql(0)
end
@@ -134,7 +156,7 @@ describe "StringIO#reopen when passed [String]" do
it "reopens self with the passed String in read-write mode" do
@io.close
- @io.reopen(+"reopened")
+ @io.reopen("reopened")
@io.closed_write?.should be_false
@io.closed_read?.should be_false
@@ -142,15 +164,23 @@ describe "StringIO#reopen when passed [String]" do
@io.string.should == "reopened"
end
+ ruby_version_is ""..."3.0" do
+ # NOTE: WEIRD!
+ it "does not taint self when the passed Object was tainted" do
+ @io.reopen("reopened".taint)
+ @io.tainted?.should be_false
+ end
+ end
+
it "resets self's position to 0" do
@io.read(5)
- @io.reopen(+"reopened")
+ @io.reopen("reopened")
@io.pos.should eql(0)
end
it "resets self's line number to 0" do
@io.gets
- @io.reopen(+"reopened")
+ @io.reopen("reopened")
@io.lineno.should eql(0)
end
end
@@ -172,7 +202,7 @@ describe "StringIO#reopen when passed [Object]" do
it "tries to convert the passed Object to a StringIO using #to_strio" do
obj = mock("to_strio")
- obj.should_receive(:to_strio).and_return(StringIO.new(+"to_strio"))
+ obj.should_receive(:to_strio).and_return(StringIO.new("to_strio"))
@io.reopen(obj)
@io.string.should == "to_strio"
end
@@ -208,40 +238,40 @@ end
# for details.
describe "StringIO#reopen" do
before :each do
- @io = StringIO.new(+'hello', 'a')
+ @io = StringIO.new('hello','a')
end
# TODO: find out if this is really a bug
it "reopens a stream when given a String argument" do
- @io.reopen(+'goodbye').should == @io
+ @io.reopen('goodbye').should == @io
@io.string.should == 'goodbye'
@io << 'x'
@io.string.should == 'xoodbye'
end
it "reopens a stream in append mode when flagged as such" do
- @io.reopen(+'goodbye', 'a').should == @io
+ @io.reopen('goodbye', 'a').should == @io
@io.string.should == 'goodbye'
@io << 'x'
@io.string.should == 'goodbyex'
end
it "reopens and truncate when reopened in write mode" do
- @io.reopen(+'goodbye', 'wb').should == @io
+ @io.reopen('goodbye', 'wb').should == @io
@io.string.should == ''
@io << 'x'
@io.string.should == 'x'
end
it "truncates the given string, not a copy" do
- str = +'goodbye'
+ str = 'goodbye'
@io.reopen(str, 'w')
@io.string.should == ''
str.should == ''
end
it "does not truncate the content even when the StringIO argument is in the truncate mode" do
- orig_io = StringIO.new(+"Original StringIO", IO::RDWR|IO::TRUNC)
+ orig_io = StringIO.new("Original StringIO", IO::RDWR|IO::TRUNC)
orig_io.write("BLAH") # make sure the content is not empty
@io.reopen(orig_io)
diff --git a/spec/ruby/library/stringio/set_encoding_spec.rb b/spec/ruby/library/stringio/set_encoding_spec.rb
index 19ca0875bf..21d45750f3 100644
--- a/spec/ruby/library/stringio/set_encoding_spec.rb
+++ b/spec/ruby/library/stringio/set_encoding_spec.rb
@@ -17,12 +17,4 @@ describe "StringIO#set_encoding" do
io.set_encoding Encoding::UTF_8
io.string.encoding.should == Encoding::US_ASCII
end
-
- it "accepts a String" do
- str = "".encode(Encoding::US_ASCII)
- io = StringIO.new(str)
- io.set_encoding("ASCII-8BIT")
- io.external_encoding.should == Encoding::BINARY
- str.encoding.should == Encoding::BINARY
- end
end
diff --git a/spec/ruby/library/stringio/shared/codepoints.rb b/spec/ruby/library/stringio/shared/codepoints.rb
index 25333bb0fd..9d84aa4919 100644
--- a/spec/ruby/library/stringio/shared/codepoints.rb
+++ b/spec/ruby/library/stringio/shared/codepoints.rb
@@ -27,7 +27,7 @@ describe :stringio_codepoints, shared: true do
@io.close_read
-> { @enum.to_a }.should raise_error(IOError)
- io = StringIO.new(+"xyz", "w")
+ io = StringIO.new("xyz", "w")
-> { io.send(@method).to_a }.should raise_error(IOError)
end
diff --git a/spec/ruby/library/stringio/shared/each.rb b/spec/ruby/library/stringio/shared/each.rb
index e0dd3f9b8f..bf3265ee46 100644
--- a/spec/ruby/library/stringio/shared/each.rb
+++ b/spec/ruby/library/stringio/shared/each.rb
@@ -36,7 +36,7 @@ describe :stringio_each_separator, shared: true do
seen.should == ["2 1 2 1 2"]
end
- version_is StringIO::VERSION, ""..."3.0.4" do #ruby_version_is ""..."3.2" do
+ ruby_version_is ''..."3.2" do
it "yields each paragraph with two separation characters when passed an empty String as separator" do
seen = []
io = StringIO.new("para1\n\npara2\n\n\npara3")
@@ -45,7 +45,7 @@ describe :stringio_each_separator, shared: true do
end
end
- version_is StringIO::VERSION, "3.0.4" do #ruby_version_is "3.2" do
+ ruby_version_is "3.2" do
it "yields each paragraph with all separation characters when passed an empty String as separator" do
seen = []
io = StringIO.new("para1\n\npara2\n\n\npara3")
@@ -107,7 +107,7 @@ end
describe :stringio_each_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new(+"a b c d e", "w")
+ io = StringIO.new("a b c d e", "w")
-> { io.send(@method) { |b| b } }.should raise_error(IOError)
io = StringIO.new("a b c d e")
diff --git a/spec/ruby/library/stringio/shared/each_byte.rb b/spec/ruby/library/stringio/shared/each_byte.rb
index b51fa38f2f..56734ff99d 100644
--- a/spec/ruby/library/stringio/shared/each_byte.rb
+++ b/spec/ruby/library/stringio/shared/each_byte.rb
@@ -38,7 +38,7 @@ end
describe :stringio_each_byte_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new(+"xyz", "w")
+ io = StringIO.new("xyz", "w")
-> { io.send(@method) { |b| b } }.should raise_error(IOError)
io = StringIO.new("xyz")
diff --git a/spec/ruby/library/stringio/shared/each_char.rb b/spec/ruby/library/stringio/shared/each_char.rb
index 197237c1c8..bcdac53282 100644
--- a/spec/ruby/library/stringio/shared/each_char.rb
+++ b/spec/ruby/library/stringio/shared/each_char.rb
@@ -26,7 +26,7 @@ end
describe :stringio_each_char_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new(+"xyz", "w")
+ io = StringIO.new("xyz", "w")
-> { io.send(@method) { |b| b } }.should raise_error(IOError)
io = StringIO.new("xyz")
diff --git a/spec/ruby/library/stringio/shared/getc.rb b/spec/ruby/library/stringio/shared/getc.rb
index ba65040bce..6318bcc30f 100644
--- a/spec/ruby/library/stringio/shared/getc.rb
+++ b/spec/ruby/library/stringio/shared/getc.rb
@@ -33,7 +33,7 @@ end
describe :stringio_getc_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new(+"xyz", "w")
+ io = StringIO.new("xyz", "w")
-> { io.send(@method) }.should raise_error(IOError)
io = StringIO.new("xyz")
diff --git a/spec/ruby/library/stringio/shared/isatty.rb b/spec/ruby/library/stringio/shared/isatty.rb
index c9e7ee7321..3da5999953 100644
--- a/spec/ruby/library/stringio/shared/isatty.rb
+++ b/spec/ruby/library/stringio/shared/isatty.rb
@@ -1,5 +1,5 @@
describe :stringio_isatty, shared: true do
it "returns false" do
- StringIO.new("tty").send(@method).should be_false
+ StringIO.new('tty').send(@method).should be_false
end
end
diff --git a/spec/ruby/library/stringio/shared/read.rb b/spec/ruby/library/stringio/shared/read.rb
index 8ef6ec2734..252a85d89d 100644
--- a/spec/ruby/library/stringio/shared/read.rb
+++ b/spec/ruby/library/stringio/shared/read.rb
@@ -5,37 +5,19 @@ describe :stringio_read, shared: true do
it "returns the passed buffer String" do
# Note: Rubinius bug:
- # @io.send(@method, 7, buffer = +"").should equal(buffer)
- ret = @io.send(@method, 7, buffer = +"")
+ # @io.send(@method, 7, buffer = "").should equal(buffer)
+ ret = @io.send(@method, 7, buffer = "")
ret.should equal(buffer)
end
it "reads length bytes and writes them to the buffer String" do
- @io.send(@method, 7, buffer = +"").should.equal?(buffer)
+ @io.send(@method, 7, buffer = "")
buffer.should == "example"
end
- ruby_version_is ""..."3.4" do
- it "does not preserve the encoding of the given buffer" do
- buffer = ''.encode(Encoding::ISO_8859_1)
- @io.send(@method, 7, buffer)
-
- buffer.encoding.should_not == Encoding::ISO_8859_1
- end
- end
-
- ruby_version_is "3.4" do
- it "preserves the encoding of the given buffer" do
- buffer = ''.encode(Encoding::ISO_8859_1)
- @io.send(@method, 7, buffer)
-
- buffer.encoding.should == Encoding::ISO_8859_1
- end
- end
-
it "tries to convert the passed buffer Object to a String using #to_str" do
obj = mock("to_str")
- obj.should_receive(:to_str).and_return(buffer = +"")
+ obj.should_receive(:to_str).and_return(buffer = "")
@io.send(@method, 7, obj)
buffer.should == "example"
@@ -93,7 +75,7 @@ end
describe :stringio_read_no_arguments, shared: true do
before :each do
- @io = StringIO.new(+"example")
+ @io = StringIO.new("example")
end
it "reads the whole content starting from the current position" do
@@ -135,7 +117,7 @@ end
describe :stringio_read_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new(+"test", "w")
+ io = StringIO.new("test", "w")
-> { io.send(@method) }.should raise_error(IOError)
io = StringIO.new("test")
diff --git a/spec/ruby/library/stringio/shared/readchar.rb b/spec/ruby/library/stringio/shared/readchar.rb
index 72d7446c36..4248e75420 100644
--- a/spec/ruby/library/stringio/shared/readchar.rb
+++ b/spec/ruby/library/stringio/shared/readchar.rb
@@ -19,7 +19,7 @@ end
describe :stringio_readchar_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new(+"a b c d e", "w")
+ io = StringIO.new("a b c d e", "w")
-> { io.send(@method) }.should raise_error(IOError)
io = StringIO.new("a b c d e")
diff --git a/spec/ruby/library/stringio/shared/sysread.rb b/spec/ruby/library/stringio/shared/sysread.rb
index 937bac705c..3376bd9907 100644
--- a/spec/ruby/library/stringio/shared/sysread.rb
+++ b/spec/ruby/library/stringio/shared/sysread.rb
@@ -1,4 +1,4 @@
-describe :stringio_sysread_length, shared: true do
+describe :stringio_sysread_length, :shared => true do
before :each do
@io = StringIO.new("example")
end
diff --git a/spec/ruby/library/stringio/shared/write.rb b/spec/ruby/library/stringio/shared/write.rb
index 404e08b93d..d9c21028e0 100644
--- a/spec/ruby/library/stringio/shared/write.rb
+++ b/spec/ruby/library/stringio/shared/write.rb
@@ -1,6 +1,6 @@
describe :stringio_write, shared: true do
before :each do
- @io = StringIO.new(+'12345')
+ @io = StringIO.new('12345')
end
it "tries to convert the passed Object to a String using #to_s" do
@@ -13,7 +13,7 @@ end
describe :stringio_write_string, shared: true do
before :each do
- @io = StringIO.new(+'12345')
+ @io = StringIO.new('12345')
end
# TODO: RDoc says that #write appends at the current position.
@@ -60,6 +60,13 @@ describe :stringio_write_string, shared: true do
@io.string.size.should == n.times.map(&:to_s).join.size
end
+ ruby_version_is ""..."3.0" do
+ it "does not taint self when the passed argument is tainted" do
+ @io.send(@method, "test".taint)
+ @io.tainted?.should be_false
+ end
+ end
+
it "handles writing non-ASCII UTF-8 after seek" do
@io.binmode
@io << "\x80"
@@ -81,35 +88,14 @@ describe :stringio_write_string, shared: true do
@io.write "fghi"
@io.string.should == "12fghi"
end
-
- it "transcodes the given string when the external encoding is set and neither is BINARY" do
- utf8_str = "hello"
- io = StringIO.new.set_encoding(Encoding::UTF_16BE)
- io.external_encoding.should == Encoding::UTF_16BE
-
- io.send(@method, utf8_str)
-
- expected = [0, 104, 0, 101, 0, 108, 0, 108, 0, 111] # UTF-16BE bytes for "hello"
- io.string.bytes.should == expected
- end
-
- it "does not transcode the given string when the external encoding is set and the string encoding is BINARY" do
- str = "été".b
- io = StringIO.new.set_encoding(Encoding::UTF_16BE)
- io.external_encoding.should == Encoding::UTF_16BE
-
- io.send(@method, str)
-
- io.string.bytes.should == str.bytes
- end
end
describe :stringio_write_not_writable, shared: true do
it "raises an IOError" do
- io = StringIO.new(+"test", "r")
+ io = StringIO.new("test", "r")
-> { io.send(@method, "test") }.should raise_error(IOError)
- io = StringIO.new(+"test")
+ io = StringIO.new("test")
io.close_write
-> { io.send(@method, "test") }.should raise_error(IOError)
end
@@ -117,7 +103,7 @@ end
describe :stringio_write_append, shared: true do
before :each do
- @io = StringIO.new(+"example", "a")
+ @io = StringIO.new("example", "a")
end
it "appends the passed argument to the end of self" do
diff --git a/spec/ruby/library/stringio/truncate_spec.rb b/spec/ruby/library/stringio/truncate_spec.rb
index 592ca5a6e1..e8d7f1a15d 100644
--- a/spec/ruby/library/stringio/truncate_spec.rb
+++ b/spec/ruby/library/stringio/truncate_spec.rb
@@ -3,7 +3,7 @@ require "stringio"
describe "StringIO#truncate when passed [length]" do
before :each do
- @io = StringIO.new(+'123456789')
+ @io = StringIO.new('123456789')
end
it "returns an Integer" do
@@ -16,7 +16,7 @@ describe "StringIO#truncate when passed [length]" do
end
it "does not create a copy of the underlying string" do
- io = StringIO.new(str = +"123456789")
+ io = StringIO.new(str = "123456789")
io.truncate(4)
io.string.should equal(str)
end
@@ -52,10 +52,10 @@ end
describe "StringIO#truncate when self is not writable" do
it "raises an IOError" do
- io = StringIO.new(+"test", "r")
+ io = StringIO.new("test", "r")
-> { io.truncate(2) }.should raise_error(IOError)
- io = StringIO.new(+"test")
+ io = StringIO.new("test")
io.close_write
-> { io.truncate(2) }.should raise_error(IOError)
end
diff --git a/spec/ruby/library/stringio/ungetc_spec.rb b/spec/ruby/library/stringio/ungetc_spec.rb
index bceafa79ff..91ef2100a1 100644
--- a/spec/ruby/library/stringio/ungetc_spec.rb
+++ b/spec/ruby/library/stringio/ungetc_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#ungetc when passed [char]" do
before :each do
- @io = StringIO.new(+'1234')
+ @io = StringIO.new('1234')
end
it "writes the passed char before the current position" do
@@ -45,11 +45,11 @@ end
describe "StringIO#ungetc when self is not readable" do
it "raises an IOError" do
- io = StringIO.new(+"test", "w")
+ io = StringIO.new("test", "w")
io.pos = 1
-> { io.ungetc(?A) }.should raise_error(IOError)
- io = StringIO.new(+"test")
+ io = StringIO.new("test")
io.pos = 1
io.close_read
-> { io.ungetc(?A) }.should raise_error(IOError)
@@ -60,11 +60,11 @@ end
#
# describe "StringIO#ungetc when self is not writable" do
# it "raises an IOError" do
-# io = StringIO.new(+"test", "r")
+# io = StringIO.new("test", "r")
# io.pos = 1
# lambda { io.ungetc(?A) }.should raise_error(IOError)
#
-# io = StringIO.new(+"test")
+# io = StringIO.new("test")
# io.pos = 1
# io.close_write
# lambda { io.ungetc(?A) }.should raise_error(IOError)
diff --git a/spec/ruby/library/stringio/write_nonblock_spec.rb b/spec/ruby/library/stringio/write_nonblock_spec.rb
index b48ef6698a..a457b97667 100644
--- a/spec/ruby/library/stringio/write_nonblock_spec.rb
+++ b/spec/ruby/library/stringio/write_nonblock_spec.rb
@@ -10,7 +10,7 @@ describe "StringIO#write_nonblock when passed [String]" do
it_behaves_like :stringio_write_string, :write_nonblock
it "accepts :exception option" do
- io = StringIO.new(+"12345", "a")
+ io = StringIO.new("12345", "a")
io.write_nonblock("67890", exception: true)
io.string.should == "1234567890"
end
diff --git a/spec/ruby/library/stringscanner/check_until_spec.rb b/spec/ruby/library/stringscanner/check_until_spec.rb
index 1d89f88a25..ad222fd76b 100644
--- a/spec/ruby/library/stringscanner/check_until_spec.rb
+++ b/spec/ruby/library/stringscanner/check_until_spec.rb
@@ -13,11 +13,9 @@ describe "StringScanner#check_until" do
@s.check_until(/test/).should == "This is a test"
end
- ruby_version_is ""..."3.4" do
- it "raises TypeError if given a String" do
- -> {
- @s.check_until('T')
- }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
- end
+ it "raises TypeError if given a String" do
+ -> {
+ @s.check_until('T')
+ }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
end
end
diff --git a/spec/ruby/library/stringscanner/exist_spec.rb b/spec/ruby/library/stringscanner/exist_spec.rb
index a18f5ce352..ff860a0d3e 100644
--- a/spec/ruby/library/stringscanner/exist_spec.rb
+++ b/spec/ruby/library/stringscanner/exist_spec.rb
@@ -22,11 +22,9 @@ describe "StringScanner#exist?" do
@s.exist?(/i/).should == nil
end
- ruby_version_is ""..."3.4" do
- it "raises TypeError if given a String" do
- -> {
- @s.exist?('T')
- }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
- end
+ it "raises TypeError if given a String" do
+ -> {
+ @s.exist?('T')
+ }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
end
end
diff --git a/spec/ruby/library/stringscanner/getch_spec.rb b/spec/ruby/library/stringscanner/getch_spec.rb
index 449c20ad3b..a6be0d4221 100644
--- a/spec/ruby/library/stringscanner/getch_spec.rb
+++ b/spec/ruby/library/stringscanner/getch_spec.rb
@@ -13,7 +13,7 @@ describe "StringScanner#getch" do
it "is multi-byte character sensitive" do
# Japanese hiragana "A" in EUC-JP
- src = "\244\242".dup.force_encoding("euc-jp")
+ src = "\244\242".force_encoding("euc-jp")
s = StringScanner.new(src)
s.getch.should == src
diff --git a/spec/ruby/library/stringscanner/scan_until_spec.rb b/spec/ruby/library/stringscanner/scan_until_spec.rb
index 1e318d053b..6b7782572d 100644
--- a/spec/ruby/library/stringscanner/scan_until_spec.rb
+++ b/spec/ruby/library/stringscanner/scan_until_spec.rb
@@ -7,9 +7,9 @@ describe "StringScanner#scan_until" do
end
it "returns the substring up to and including the end of the match" do
- @s.scan_until(/a/).should == "This is a"
- @s.pre_match.should == "This is "
- @s.post_match.should == " test"
+ @s.scan_until(/a/).should == "This is a"
+ @s.pre_match.should == "This is "
+ @s.post_match.should == " test"
end
it "returns nil if there's no match" do
@@ -21,11 +21,9 @@ describe "StringScanner#scan_until" do
@s.scan_until(/^h/).should == "h"
end
- ruby_version_is ""..."3.4" do
- it "raises TypeError if given a String" do
- -> {
- @s.scan_until('T')
- }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
- end
+ it "raises TypeError if given a String" do
+ -> {
+ @s.scan_until('T')
+ }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
end
end
diff --git a/spec/ruby/library/stringscanner/search_full_spec.rb b/spec/ruby/library/stringscanner/search_full_spec.rb
index 713ab00d22..7d2a714fa5 100644
--- a/spec/ruby/library/stringscanner/search_full_spec.rb
+++ b/spec/ruby/library/stringscanner/search_full_spec.rb
@@ -28,11 +28,9 @@ describe "StringScanner#search_full" do
@s.pos.should == 4
end
- ruby_version_is ""..."3.4" do
- it "raises TypeError if given a String" do
- -> {
- @s.search_full('T', true, true)
- }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
- end
+ it "raises TypeError if given a String" do
+ -> {
+ @s.search_full('T', true, true)
+ }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
end
end
diff --git a/spec/ruby/library/stringscanner/shared/concat.rb b/spec/ruby/library/stringscanner/shared/concat.rb
index 1dbae11f7c..cb884a5c01 100644
--- a/spec/ruby/library/stringscanner/shared/concat.rb
+++ b/spec/ruby/library/stringscanner/shared/concat.rb
@@ -1,6 +1,6 @@
describe :strscan_concat, shared: true do
it "concatenates the given argument to self and returns self" do
- s = StringScanner.new(+"hello ")
+ s = StringScanner.new("hello ")
s.send(@method, 'world').should == s
s.string.should == "hello world"
s.eos?.should be_false
diff --git a/spec/ruby/library/stringscanner/skip_until_spec.rb b/spec/ruby/library/stringscanner/skip_until_spec.rb
index b6a020f9ba..7b56f13e4f 100644
--- a/spec/ruby/library/stringscanner/skip_until_spec.rb
+++ b/spec/ruby/library/stringscanner/skip_until_spec.rb
@@ -16,11 +16,9 @@ describe "StringScanner#skip_until" do
@s.skip_until(/d+/).should == nil
end
- ruby_version_is ""..."3.4" do
- it "raises TypeError if given a String" do
- -> {
- @s.skip_until('T')
- }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
- end
+ it "raises TypeError if given a String" do
+ -> {
+ @s.skip_until('T')
+ }.should raise_error(TypeError, 'wrong argument type String (expected Regexp)')
end
end
diff --git a/spec/ruby/library/stringscanner/string_spec.rb b/spec/ruby/library/stringscanner/string_spec.rb
index cba6bd51dd..28e2f0ed37 100644
--- a/spec/ruby/library/stringscanner/string_spec.rb
+++ b/spec/ruby/library/stringscanner/string_spec.rb
@@ -3,7 +3,7 @@ require 'strscan'
describe "StringScanner#string" do
before :each do
- @string = +"This is a test"
+ @string = "This is a test"
@s = StringScanner.new(@string)
end
diff --git a/spec/ruby/library/time/iso8601_spec.rb b/spec/ruby/library/time/iso8601_spec.rb
index 9e2607fbd0..4a9eb45613 100644
--- a/spec/ruby/library/time/iso8601_spec.rb
+++ b/spec/ruby/library/time/iso8601_spec.rb
@@ -3,5 +3,5 @@ require_relative 'shared/xmlschema'
require 'time'
describe "Time.xmlschema" do
- it_behaves_like :time_library_xmlschema, :iso8601
+ it_behaves_like :time_xmlschema, :iso8601
end
diff --git a/spec/ruby/library/time/shared/xmlschema.rb b/spec/ruby/library/time/shared/xmlschema.rb
index 831d8509a7..44d33cda7e 100644
--- a/spec/ruby/library/time/shared/xmlschema.rb
+++ b/spec/ruby/library/time/shared/xmlschema.rb
@@ -1,4 +1,4 @@
-describe :time_library_xmlschema, shared: true do
+describe :time_xmlschema, shared: true do
it "parses ISO-8601 strings" do
t = Time.utc(1985, 4, 12, 23, 20, 50, 520000)
s = "1985-04-12T23:20:50.52Z"
diff --git a/spec/ruby/library/time/to_date_spec.rb b/spec/ruby/library/time/to_date_spec.rb
new file mode 100644
index 0000000000..baeafe0847
--- /dev/null
+++ b/spec/ruby/library/time/to_date_spec.rb
@@ -0,0 +1,42 @@
+
+require_relative '../../spec_helper'
+require 'time'
+
+describe "Time#to_date" do
+ it "yields accurate julian date for ambiguous pre-Gregorian reform value" do
+ Time.utc(1582, 10, 4).to_date.jd.should == Date::ITALY - 11 # 2299150j
+ end
+
+ it "yields accurate julian date for Julian-Gregorian gap value" do
+ Time.utc(1582, 10, 14).to_date.jd.should == Date::ITALY - 1 # 2299160j
+ end
+
+ it "yields accurate julian date for post-Gregorian reform value" do
+ Time.utc(1582, 10, 15).to_date.jd.should == Date::ITALY # 2299161j
+ end
+
+ it "yields same julian day regardless of UTC time value" do
+ Time.utc(1582, 10, 15, 00, 00, 00).to_date.jd.should == Date::ITALY
+ Time.utc(1582, 10, 15, 23, 59, 59).to_date.jd.should == Date::ITALY
+ end
+
+ it "yields same julian day regardless of local time or zone" do
+
+ with_timezone("Pacific/Pago_Pago", -11) do
+ Time.local(1582, 10, 15, 00, 00, 00).to_date.jd.should == Date::ITALY
+ Time.local(1582, 10, 15, 23, 59, 59).to_date.jd.should == Date::ITALY
+ end
+
+ with_timezone("Asia/Kamchatka", +12) do
+ Time.local(1582, 10, 15, 00, 00, 00).to_date.jd.should == Date::ITALY
+ Time.local(1582, 10, 15, 23, 59, 59).to_date.jd.should == Date::ITALY
+ end
+
+ end
+
+ it "yields date with default Calendar reform day" do
+ Time.utc(1582, 10, 4).to_date.start.should == Date::ITALY
+ Time.utc(1582, 10, 14).to_date.start.should == Date::ITALY
+ Time.utc(1582, 10, 15).to_date.start.should == Date::ITALY
+ end
+end
diff --git a/spec/ruby/library/time/to_datetime_spec.rb b/spec/ruby/library/time/to_datetime_spec.rb
new file mode 100644
index 0000000000..6025950b59
--- /dev/null
+++ b/spec/ruby/library/time/to_datetime_spec.rb
@@ -0,0 +1,41 @@
+require_relative '../../spec_helper'
+require 'time'
+
+describe "Time#to_datetime" do
+ it "returns a DateTime representing the same instant" do
+ time = Time.utc(2012, 12, 31, 23, 58, 59)
+ datetime = time.to_datetime
+ datetime.year.should == 2012
+ datetime.month.should == 12
+ datetime.day.should == 31
+ datetime.hour.should == 23
+ datetime.min.should == 58
+ datetime.sec.should == 59
+ end
+
+ date_version = defined?(Date::VERSION) ? Date::VERSION : '0.0.0'
+ version_is(date_version, '3.2.3') do
+ it "returns a DateTime representing the same instant before Gregorian" do
+ time = Time.utc(1582, 10, 14, 23, 58, 59)
+ datetime = time.to_datetime
+ datetime.year.should == 1582
+ datetime.month.should == 10
+ datetime.day.should == 4
+ datetime.hour.should == 23
+ datetime.min.should == 58
+ datetime.sec.should == 59
+ end
+ end
+
+ it "roundtrips" do
+ time = Time.utc(3, 12, 31, 23, 58, 59)
+ datetime = time.to_datetime
+ datetime.to_time.utc.should == time
+ end
+
+ it "yields a DateTime with the default Calendar reform day" do
+ Time.utc(1582, 10, 4, 1, 2, 3).to_datetime.start.should == Date::ITALY
+ Time.utc(1582, 10, 14, 1, 2, 3).to_datetime.start.should == Date::ITALY
+ Time.utc(1582, 10, 15, 1, 2, 3).to_datetime.start.should == Date::ITALY
+ end
+end
diff --git a/spec/ruby/library/time/xmlschema_spec.rb b/spec/ruby/library/time/xmlschema_spec.rb
index ff3c864a02..4279311199 100644
--- a/spec/ruby/library/time/xmlschema_spec.rb
+++ b/spec/ruby/library/time/xmlschema_spec.rb
@@ -3,5 +3,5 @@ require_relative 'shared/xmlschema'
require 'time'
describe "Time.xmlschema" do
- it_behaves_like :time_library_xmlschema, :xmlschema
+ it_behaves_like :time_xmlschema, :xmlschema
end
diff --git a/spec/ruby/library/uri/generic/host_spec.rb b/spec/ruby/library/uri/generic/host_spec.rb
index 210124ef66..f2076d2bc1 100644
--- a/spec/ruby/library/uri/generic/host_spec.rb
+++ b/spec/ruby/library/uri/generic/host_spec.rb
@@ -2,12 +2,7 @@ require_relative '../../../spec_helper'
require 'uri'
describe "URI::Generic#host" do
- version_is URI::VERSION, "0.12" do #ruby_version_is "3.2" do
- # https://hackerone.com/reports/156615
- it "returns empty string when host is empty" do
- URI.parse('http:////foo.com').host.should == ''
- end
- end
+ it "needs to be reviewed for spec completeness"
end
describe "URI::Generic#host=" do
diff --git a/spec/ruby/library/uri/generic/to_s_spec.rb b/spec/ruby/library/uri/generic/to_s_spec.rb
index 8cebd374a1..8c90d7645b 100644
--- a/spec/ruby/library/uri/generic/to_s_spec.rb
+++ b/spec/ruby/library/uri/generic/to_s_spec.rb
@@ -2,10 +2,5 @@ require_relative '../../../spec_helper'
require 'uri'
describe "URI::Generic#to_s" do
- version_is URI::VERSION, "0.12" do #ruby_version_is "3.2" do
- # https://hackerone.com/reports/156615
- it "preserves / characters when host is empty" do
- URI('http:///foo.com').to_s.should == 'http:///foo.com'
- end
- end
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/library/uri/shared/parse.rb b/spec/ruby/library/uri/shared/parse.rb
index c5057b6c4b..87e1ee933e 100644
--- a/spec/ruby/library/uri/shared/parse.rb
+++ b/spec/ruby/library/uri/shared/parse.rb
@@ -192,15 +192,8 @@ describe :uri_parse, shared: true do
file.should be_kind_of(URI::Generic)
end
- if URI::DEFAULT_PARSER == URI::RFC2396_Parser
- it "raises errors on malformed URIs" do
- -> { @object.parse('http://a_b:80/') }.should raise_error(URI::InvalidURIError)
- -> { @object.parse('http://a_b/') }.should raise_error(URI::InvalidURIError)
- end
- elsif URI::DEFAULT_PARSER == URI::RFC3986_Parser
- it "does not raise errors on URIs contained underscore" do
- -> { @object.parse('http://a_b:80/') }.should_not raise_error(URI::InvalidURIError)
- -> { @object.parse('http://a_b/') }.should_not raise_error(URI::InvalidURIError)
- end
+ it "raises errors on malformed URIs" do
+ -> { @object.parse('http://a_b:80/') }.should raise_error(URI::InvalidURIError)
+ -> { @object.parse('http://a_b/') }.should raise_error(URI::InvalidURIError)
end
end
diff --git a/spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb b/spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb
index 52cb978bea..940eebfb91 100644
--- a/spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb b/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb
index 994c2e6d36..91f5091d24 100644
--- a/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/codepage_spec.rb b/spec/ruby/library/win32ole/win32ole/codepage_spec.rb
index 07e93646ac..4e0cf5ca55 100644
--- a/spec/ruby/library/win32ole/win32ole/codepage_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/codepage_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/connect_spec.rb b/spec/ruby/library/win32ole/win32ole/connect_spec.rb
index ac0976ddc1..72dceb1572 100644
--- a/spec/ruby/library/win32ole/win32ole/connect_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/connect_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/const_load_spec.rb b/spec/ruby/library/win32ole/win32ole/const_load_spec.rb
index 2099c4aa66..cacc7a2b22 100644
--- a/spec/ruby/library/win32ole/win32ole/const_load_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/const_load_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/constants_spec.rb b/spec/ruby/library/win32ole/win32ole/constants_spec.rb
index 8533741440..978b7ade92 100644
--- a/spec/ruby/library/win32ole/win32ole/constants_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/constants_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/create_guid_spec.rb b/spec/ruby/library/win32ole/win32ole/create_guid_spec.rb
index 8aa853df9e..2e18b6ab11 100644
--- a/spec/ruby/library/win32ole/win32ole/create_guid_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/create_guid_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/invoke_spec.rb b/spec/ruby/library/win32ole/win32ole/invoke_spec.rb
index d6ff7fade3..08a5156e05 100644
--- a/spec/ruby/library/win32ole/win32ole/invoke_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/invoke_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/locale_spec.rb b/spec/ruby/library/win32ole/win32ole/locale_spec.rb
index 78ede4375a..75a82ddd7f 100644
--- a/spec/ruby/library/win32ole/win32ole/locale_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/locale_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/new_spec.rb b/spec/ruby/library/win32ole/win32ole/new_spec.rb
index 7e91c2d3ea..6b717195f1 100644
--- a/spec/ruby/library/win32ole/win32ole/new_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/new_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb
index 2bbe8c27d4..75748182fe 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb
index c1d1970214..a991624a23 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb
index 9cb3f9e6cf..8a26d79a20 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
require_relative 'shared/ole_method'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_method_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_method_spec.rb
index e48ff8d905..f82a212f5d 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_method_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_method_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
require_relative 'shared/ole_method'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb
index fe161ce9f0..5ac9ae9cfa 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb
index afcf16a051..ef8944ee39 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb
index c091c83c95..727291e9f0 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/setproperty_spec.rb b/spec/ruby/library/win32ole/win32ole/setproperty_spec.rb
index bacdee63da..7409823f20 100644
--- a/spec/ruby/library/win32ole/win32ole/setproperty_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/setproperty_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
require_relative 'shared/setproperty'
diff --git a/spec/ruby/library/win32ole/win32ole_event/new_spec.rb b/spec/ruby/library/win32ole/win32ole_event/new_spec.rb
index 94fabb1e3b..a1a1612393 100644
--- a/spec/ruby/library/win32ole/win32ole_event/new_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_event/new_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb b/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb
index 0957bdd2d4..feb26b0637 100644
--- a/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
guard -> { WIN32OLESpecs::MSXML_AVAILABLE } do
diff --git a/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb b/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb
index ece71df0d4..69068683b7 100644
--- a/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb b/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb
index 78634d2fde..70c8b30cca 100644
--- a/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
guard -> { WIN32OLESpecs::SYSTEM_MONITOR_CONTROL_AVAILABLE } do
diff --git a/spec/ruby/library/win32ole/win32ole_method/event_spec.rb b/spec/ruby/library/win32ole/win32ole_method/event_spec.rb
index 9b642a010c..c41f8fe99d 100644
--- a/spec/ruby/library/win32ole/win32ole_method/event_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/event_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
guard -> { WIN32OLESpecs::SYSTEM_MONITOR_CONTROL_AVAILABLE } do
diff --git a/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb b/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb
index d1c5ee3be2..21b3ae8bde 100644
--- a/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb b/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb
index 59dad9244c..b6d0a19a37 100644
--- a/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb b/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb
index b2f24ba151..9f940fd4a0 100644
--- a/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb b/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb
index d7fedf0d36..7fff479daf 100644
--- a/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb b/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb
index d5536fd17b..e8638abd91 100644
--- a/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/name_spec.rb b/spec/ruby/library/win32ole/win32ole_method/name_spec.rb
index 477b820f4d..cd5404fc54 100644
--- a/spec/ruby/library/win32ole/win32ole_method/name_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_method/new_spec.rb b/spec/ruby/library/win32ole/win32ole_method/new_spec.rb
index 4e427421b9..8ebf93b992 100644
--- a/spec/ruby/library/win32ole/win32ole_method/new_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/new_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb b/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb
index b3da9a8303..8e50c39787 100644
--- a/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/params_spec.rb b/spec/ruby/library/win32ole/win32ole_method/params_spec.rb
index 09fb0eb5ac..2f8da3d45b 100644
--- a/spec/ruby/library/win32ole/win32ole_method/params_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/params_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb b/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb
index 582a5951d5..f8ce3e1b3a 100644
--- a/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb b/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb
index dd8add402d..58e26df77b 100644
--- a/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb b/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb
index 3fca3d54ed..dc159dd09e 100644
--- a/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb b/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb
index fe9facb53a..a38fe5c681 100644
--- a/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb b/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb
index 8ea6e61e7d..0c5a94c338 100644
--- a/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb
index 11107a77fc..ecb3c08038 100644
--- a/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb b/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb
index d1a50523fc..918b6ef782 100644
--- a/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/default_spec.rb b/spec/ruby/library/win32ole/win32ole_param/default_spec.rb
index 44bd3d7fd3..af08c84782 100644
--- a/spec/ruby/library/win32ole/win32ole_param/default_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/default_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/input_spec.rb b/spec/ruby/library/win32ole/win32ole_param/input_spec.rb
index e9134b1df8..e2a90daa56 100644
--- a/spec/ruby/library/win32ole/win32ole_param/input_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/input_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/name_spec.rb b/spec/ruby/library/win32ole/win32ole_param/name_spec.rb
index 67a8955ba4..0c20c24720 100644
--- a/spec/ruby/library/win32ole/win32ole_param/name_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb b/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb
index f05455e3f1..e683d1c16e 100644
--- a/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb b/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb
index 1467130e03..b9a3639c3e 100644
--- a/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb b/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb
index b39ee41179..3fb9dc1867 100644
--- a/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb b/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb
index dd613dd29a..f5546e79e5 100644
--- a/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb
index e9153a2eb2..5b4b4c1c80 100644
--- a/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb b/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb
index abdf8d34b9..25907c8e32 100644
--- a/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb b/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb
index eee23abc56..d436835188 100644
--- a/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb b/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb
index 3a0a9ead94..01e6945138 100644
--- a/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb b/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb
index 9ab0004668..3bd2cbe5dd 100644
--- a/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb b/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb
index 7d2731f778..7dae16617d 100644
--- a/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb b/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb
index 3904e78d42..ff412dd100 100644
--- a/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/name_spec.rb b/spec/ruby/library/win32ole/win32ole_type/name_spec.rb
index d76998d7dc..b7a28c553a 100644
--- a/spec/ruby/library/win32ole/win32ole_type/name_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_type/new_spec.rb b/spec/ruby/library/win32ole/win32ole_type/new_spec.rb
index cc691ffa67..3c3aa1c390 100644
--- a/spec/ruby/library/win32ole/win32ole_type/new_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/new_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb b/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb
index a3a1d4ac58..0ce0fc98a4 100644
--- a/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb b/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb
index 3b99b97a61..9265549d20 100644
--- a/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb b/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb
index 24292b1c4f..2bc19aa85e 100644
--- a/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb b/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb
index 340fdb34e8..f0d80ba39e 100644
--- a/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb b/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb
index 793535b48d..19d8bf56e0 100644
--- a/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb b/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb
index 3f89fe702a..71e304d80a 100644
--- a/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb
index 9f086a5a35..b713990ed2 100644
--- a/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb b/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb
index 391d505e01..35f3562721 100644
--- a/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb b/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb
index a487208caa..369e0274f3 100644
--- a/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb b/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb
index 7f61b8af95..fbf3dd0341 100644
--- a/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb b/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb
index 99e34edcdd..403b2b843b 100644
--- a/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_variable/name_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/name_spec.rb
index dd9bfa594f..8bac1a9891 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/name_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/name_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb
index 7a9c791494..dab4edabaa 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb
index 03a9aa4c74..d08acc9bde 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb
index d4cab8e924..000ac14d7e 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb
index b7849793c5..4f240b561c 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb
index 7a79d32ddc..4cca7f8874 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb
index 9d7b8238c8..56cd1c337a 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb
index 60252e8139..7f7a557b57 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/yaml/dump_spec.rb b/spec/ruby/library/yaml/dump_spec.rb
index ea94b2f856..3107a8f51d 100644
--- a/spec/ruby/library/yaml/dump_spec.rb
+++ b/spec/ruby/library/yaml/dump_spec.rb
@@ -1,21 +1,17 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/common'
-require 'yaml'
-
+# TODO: WTF is this using a global?
describe "YAML.dump" do
- before :each do
- @test_file = tmp("yaml_test_file")
- end
-
after :each do
- rm_r @test_file
+ rm_r $test_file
end
it "converts an object to YAML and write result to io when io provided" do
- File.open(@test_file, 'w' ) do |io|
+ File.open($test_file, 'w' ) do |io|
YAML.dump( ['badger', 'elephant', 'tiger'], io )
end
- YAML.load_file(@test_file).should == ['badger', 'elephant', 'tiger']
+ YAML.load_file($test_file).should == ['badger', 'elephant', 'tiger']
end
it "returns a string containing dumped YAML when no io provided" do
diff --git a/spec/ruby/library/yaml/dump_stream_spec.rb b/spec/ruby/library/yaml/dump_stream_spec.rb
index f0578fa800..9d30fef819 100644
--- a/spec/ruby/library/yaml/dump_stream_spec.rb
+++ b/spec/ruby/library/yaml/dump_stream_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
-
-require 'yaml'
+require_relative 'fixtures/common'
describe "YAML.dump_stream" do
it "returns a YAML stream containing the objects passed" do
diff --git a/spec/ruby/library/yaml/fixtures/common.rb b/spec/ruby/library/yaml/fixtures/common.rb
new file mode 100644
index 0000000000..f7fb4037e7
--- /dev/null
+++ b/spec/ruby/library/yaml/fixtures/common.rb
@@ -0,0 +1,4 @@
+require 'yaml'
+
+$test_file = tmp("yaml_test_file")
+$test_parse_file = File.dirname(__FILE__) + "/test_yaml.yml"
diff --git a/spec/ruby/library/yaml/fixtures/strings.rb b/spec/ruby/library/yaml/fixtures/strings.rb
index f478f89823..6f66dc3659 100644
--- a/spec/ruby/library/yaml/fixtures/strings.rb
+++ b/spec/ruby/library/yaml/fixtures/strings.rb
@@ -1,26 +1,36 @@
-module YAMLSpecs
- COMPLEX_KEY_1 = <<~EOY
- ? # PLAY SCHEDULE
- - Detroit Tigers
- - Chicago Cubs
- :
- - 2001-07-23
+$complex_key_1 = <<EOY
+ ? # PLAY SCHEDULE
+ - Detroit Tigers
+ - Chicago Cubs
+ :
+ - 2001-07-23
- ? [ New York Yankees,
- Atlanta Braves ]
- : [ 2001-07-02, 2001-08-12,
- 2001-08-14 ]
- EOY
+ ? [ New York Yankees,
+ Atlanta Braves ]
+ : [ 2001-07-02, 2001-08-12,
+ 2001-08-14 ]
+EOY
- MULTIDOCUMENT = <<~EOY
- ---
- - Mark McGwire
- - Sammy Sosa
- - Ken Griffey
+$to_yaml_hash =
+<<EOY
+-
+ avg: 0.278
+ hr: 65
+ name: Mark McGwire
+-
+ avg: 0.288
+ hr: 63
+ name: Sammy Sosa
+EOY
- # Team ranking
- ---
- - Chicago Cubs
- - St Louis Cardinals
- EOY
-end
+$multidocument = <<EOY
+---
+- Mark McGwire
+- Sammy Sosa
+- Ken Griffey
+
+# Team ranking
+---
+- Chicago Cubs
+- St Louis Cardinals
+EOY
diff --git a/spec/ruby/library/yaml/load_file_spec.rb b/spec/ruby/library/yaml/load_file_spec.rb
index 4941d0485b..2363c08120 100644
--- a/spec/ruby/library/yaml/load_file_spec.rb
+++ b/spec/ruby/library/yaml/load_file_spec.rb
@@ -1,18 +1,13 @@
require_relative '../../spec_helper'
-
-require 'yaml'
+require_relative 'fixtures/common'
describe "YAML.load_file" do
- before :each do
- @test_file = tmp("yaml_test_file")
- end
-
after :each do
- rm_r @test_file
+ rm_r $test_file
end
it "returns a hash" do
- File.open(@test_file,'w' ){|io| YAML.dump( {"bar"=>2, "car"=>1}, io ) }
- YAML.load_file(@test_file).should == {"bar"=>2, "car"=>1}
+ File.open($test_file,'w' ){|io| YAML.dump( {"bar"=>2, "car"=>1}, io ) }
+ YAML.load_file($test_file).should == {"bar"=>2, "car"=>1}
end
end
diff --git a/spec/ruby/library/yaml/load_stream_spec.rb b/spec/ruby/library/yaml/load_stream_spec.rb
index 31bc862f5e..689653c8cd 100644
--- a/spec/ruby/library/yaml/load_stream_spec.rb
+++ b/spec/ruby/library/yaml/load_stream_spec.rb
@@ -1,9 +1,8 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/common'
require_relative 'fixtures/strings'
require_relative 'shared/each_document'
-require 'yaml'
-
describe "YAML.load_stream" do
it_behaves_like :yaml_each_document, :load_stream
end
diff --git a/spec/ruby/library/yaml/parse_file_spec.rb b/spec/ruby/library/yaml/parse_file_spec.rb
index 7bffcdc62f..8c59a2d7ef 100644
--- a/spec/ruby/library/yaml/parse_file_spec.rb
+++ b/spec/ruby/library/yaml/parse_file_spec.rb
@@ -1,10 +1,8 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/common'
-require 'yaml'
-
-describe "YAML.parse_file" do
+describe "YAML#parse_file" do
it "returns a YAML::Syck::Map object after parsing a YAML file" do
- test_parse_file = fixture __FILE__, "test_yaml.yml"
- YAML.parse_file(test_parse_file).should be_kind_of(Psych::Nodes::Document)
+ YAML.parse_file($test_parse_file).should be_kind_of(Psych::Nodes::Document)
end
end
diff --git a/spec/ruby/library/yaml/parse_spec.rb b/spec/ruby/library/yaml/parse_spec.rb
index 37e2b7fa0a..d5dbfdcee2 100644
--- a/spec/ruby/library/yaml/parse_spec.rb
+++ b/spec/ruby/library/yaml/parse_spec.rb
@@ -1,14 +1,13 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/common'
-require 'yaml'
-
-describe "YAML.parse with an empty string" do
+describe "YAML#parse with an empty string" do
it "returns false" do
YAML.parse('').should be_false
end
end
-describe "YAML.parse" do
+describe "YAML#parse" do
before :each do
@string_yaml = "foo".to_yaml
end
diff --git a/spec/ruby/library/yaml/shared/each_document.rb b/spec/ruby/library/yaml/shared/each_document.rb
index 6f00aee297..999123dc2a 100644
--- a/spec/ruby/library/yaml/shared/each_document.rb
+++ b/spec/ruby/library/yaml/shared/each_document.rb
@@ -1,7 +1,7 @@
describe :yaml_each_document, shared: true do
it "calls the block on each successive document" do
documents = []
- YAML.send(@method, YAMLSpecs::MULTIDOCUMENT) do |doc|
+ YAML.send(@method, $multidocument) do |doc|
documents << doc
end
documents.should == [["Mark McGwire", "Sammy Sosa", "Ken Griffey"],
@@ -9,8 +9,7 @@ describe :yaml_each_document, shared: true do
end
it "works on files" do
- test_parse_file = fixture __FILE__, "test_yaml.yml"
- File.open(test_parse_file, "r") do |file|
+ File.open($test_parse_file, "r") do |file|
YAML.send(@method, file) do |doc|
doc.should == {"project"=>{"name"=>"RubySpec"}}
end
diff --git a/spec/ruby/library/yaml/shared/load.rb b/spec/ruby/library/yaml/shared/load.rb
index bd55332fe5..185a5a60cd 100644
--- a/spec/ruby/library/yaml/shared/load.rb
+++ b/spec/ruby/library/yaml/shared/load.rb
@@ -1,16 +1,14 @@
+require_relative '../fixtures/common'
require_relative '../fixtures/strings'
-require 'yaml'
-
describe :yaml_load_safe, shared: true do
it "returns a document from current io stream when io provided" do
- @test_file = tmp("yaml_test_file")
- File.open(@test_file, 'w') do |io|
+ File.open($test_file, 'w') do |io|
YAML.dump( ['badger', 'elephant', 'tiger'], io )
end
- File.open(@test_file) { |yf| YAML.send(@method, yf ) }.should == ['badger', 'elephant', 'tiger']
+ File.open($test_file) { |yf| YAML.send(@method, yf ) }.should == ['badger', 'elephant', 'tiger']
ensure
- rm_r @test_file
+ rm_r $test_file
end
it "loads strings" do
@@ -106,7 +104,7 @@ describe :yaml_load_unsafe, shared: true do
Date.new( 2001, 8, 12 ),
Date.new( 2001, 8, 14 ) ]
}
- YAML.send(@method, YAMLSpecs::COMPLEX_KEY_1).should == expected
+ YAML.send(@method, $complex_key_1).should == expected
end
describe "with iso8601 timestamp" do
diff --git a/spec/ruby/library/yaml/to_yaml_spec.rb b/spec/ruby/library/yaml/to_yaml_spec.rb
index 547009c942..8e80b02cb4 100644
--- a/spec/ruby/library/yaml/to_yaml_spec.rb
+++ b/spec/ruby/library/yaml/to_yaml_spec.rb
@@ -1,8 +1,7 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/common'
require_relative 'fixtures/example_class'
-require 'yaml'
-
describe "Object#to_yaml" do
it "returns the YAML representation of an Array object" do
@@ -13,21 +12,13 @@ describe "Object#to_yaml" do
{ "a" => "b"}.to_yaml.should match_yaml("--- \na: b\n")
end
- it "returns the YAML representation of an object" do
- YAMLSpecs::Example.new("baz").to_yaml.should match_yaml("--- !ruby/object:YAMLSpecs::Example\nname: baz\n")
- end
-
it "returns the YAML representation of a Class object" do
- YAMLSpecs::Example.to_yaml.should match_yaml("--- !ruby/class 'YAMLSpecs::Example'\n")
- end
-
- it "returns the YAML representation of a Module object" do
- Enumerable.to_yaml.should match_yaml("--- !ruby/module 'Enumerable'\n")
+ YAMLSpecs::Example.new("baz").to_yaml.should match_yaml("--- !ruby/object:YAMLSpecs::Example\nname: baz\n")
end
it "returns the YAML representation of a Date object" do
require 'date'
- Date.new(1997, 12, 30).to_yaml.should match_yaml("--- 1997-12-30\n")
+ Date.parse('1997/12/30').to_yaml.should match_yaml("--- 1997-12-30\n")
end
it "returns the YAML representation of a FalseClass" do
@@ -67,11 +58,6 @@ describe "Object#to_yaml" do
Person.new("Jane", "female").to_yaml.should match_yaml("--- !ruby/struct:Person\nname: Jane\ngender: female\n")
end
- it "returns the YAML representation of an unnamed Struct object" do
- person = Struct.new(:name, :gender)
- person.new("Jane", "female").to_yaml.should match_yaml("--- !ruby/struct\nname: Jane\ngender: female\n")
- end
-
it "returns the YAML representation of a Symbol object" do
:symbol.to_yaml.should match_yaml("--- :symbol\n")
end
diff --git a/spec/ruby/library/zlib/deflate/deflate_spec.rb b/spec/ruby/library/zlib/deflate/deflate_spec.rb
index e16e6ad0ef..50a563ef6f 100644
--- a/spec/ruby/library/zlib/deflate/deflate_spec.rb
+++ b/spec/ruby/library/zlib/deflate/deflate_spec.rb
@@ -23,7 +23,7 @@ describe "Zlib::Deflate.deflate" do
it "deflates chunked data" do
random_generator = Random.new(0)
- deflated = +''
+ deflated = ''
Zlib::Deflate.deflate(random_generator.bytes(20000)) do |chunk|
deflated << chunk
@@ -70,7 +70,7 @@ describe "Zlib::Deflate#deflate" do
before :each do
@deflator = Zlib::Deflate.new
@random_generator = Random.new(0)
- @original = +''
+ @original = ''
@chunks = []
end
diff --git a/spec/ruby/library/zlib/deflate/new_spec.rb b/spec/ruby/library/zlib/deflate/new_spec.rb
new file mode 100644
index 0000000000..e15f14f95f
--- /dev/null
+++ b/spec/ruby/library/zlib/deflate/new_spec.rb
@@ -0,0 +1 @@
+require_relative '../../../spec_helper'
diff --git a/spec/ruby/library/zlib/deflate/params_spec.rb b/spec/ruby/library/zlib/deflate/params_spec.rb
index 0242653528..0b1cca8c8a 100644
--- a/spec/ruby/library/zlib/deflate/params_spec.rb
+++ b/spec/ruby/library/zlib/deflate/params_spec.rb
@@ -3,7 +3,7 @@ require 'zlib'
describe "Zlib::Deflate#params" do
it "changes the deflate parameters" do
- data = +'abcdefghijklm'
+ data = 'abcdefghijklm'
d = Zlib::Deflate.new Zlib::NO_COMPRESSION, Zlib::MAX_WBITS,
Zlib::DEF_MEM_LEVEL, Zlib::DEFAULT_STRATEGY
diff --git a/spec/ruby/library/zlib/gzipreader/each_line_spec.rb b/spec/ruby/library/zlib/gzipreader/each_line_spec.rb
index 6f17365879..efaf27d6bb 100644
--- a/spec/ruby/library/zlib/gzipreader/each_line_spec.rb
+++ b/spec/ruby/library/zlib/gzipreader/each_line_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative 'shared/each'
describe "Zlib::GzipReader#each_line" do
diff --git a/spec/ruby/library/zlib/gzipreader/each_spec.rb b/spec/ruby/library/zlib/gzipreader/each_spec.rb
index 3b98391a87..59aa63e52c 100644
--- a/spec/ruby/library/zlib/gzipreader/each_spec.rb
+++ b/spec/ruby/library/zlib/gzipreader/each_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require_relative 'shared/each'
describe "Zlib::GzipReader#each" do
diff --git a/spec/ruby/library/zlib/gzipreader/mtime_spec.rb b/spec/ruby/library/zlib/gzipreader/mtime_spec.rb
deleted file mode 100644
index e8e71fa72e..0000000000
--- a/spec/ruby/library/zlib/gzipreader/mtime_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-require 'zlib'
-require 'stringio'
-
-describe "Zlib::GzipReader#mtime" do
- it "returns the timestamp from the Gzip header" do
- io = StringIO.new "\x1f\x8b\x08\x00\x44\x33\x22\x11\x00\xff\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00"
- gz = Zlib::GzipReader.new(io)
- gz.mtime.to_i.should == 0x11223344
- end
-end
diff --git a/spec/ruby/library/zlib/gzipreader/new_spec.rb b/spec/ruby/library/zlib/gzipreader/new_spec.rb
new file mode 100644
index 0000000000..e15f14f95f
--- /dev/null
+++ b/spec/ruby/library/zlib/gzipreader/new_spec.rb
@@ -0,0 +1 @@
+require_relative '../../../spec_helper'
diff --git a/spec/ruby/library/zlib/inflate/finish_spec.rb b/spec/ruby/library/zlib/inflate/finish_spec.rb
index 3e0663e265..f6e592fb6b 100644
--- a/spec/ruby/library/zlib/inflate/finish_spec.rb
+++ b/spec/ruby/library/zlib/inflate/finish_spec.rb
@@ -1,4 +1,3 @@
-require_relative "../../../spec_helper"
require 'zlib'
describe "Zlib::Inflate#finish" do
diff --git a/spec/ruby/library/zlib/inflate/inflate_spec.rb b/spec/ruby/library/zlib/inflate/inflate_spec.rb
index b308a4ba67..79b72bf91c 100644
--- a/spec/ruby/library/zlib/inflate/inflate_spec.rb
+++ b/spec/ruby/library/zlib/inflate/inflate_spec.rb
@@ -72,7 +72,7 @@ describe "Zlib::Inflate.inflate" do
data = [120, 156, 75, 203, 207, 7, 0, 2, 130, 1, 69].pack('C*')
z = Zlib::Inflate.new
# add bytes, one by one
- result = +""
+ result = ""
data.each_byte { |d| result << z.inflate(d.chr)}
result << z.finish
result.should == "foo"
@@ -82,7 +82,7 @@ describe "Zlib::Inflate.inflate" do
data = [120, 156, 75, 203, 207, 7, 0, 2, 130, 1, 69].pack('C*')[0,5]
z = Zlib::Inflate.new
# add bytes, one by one, but not all
- result = +""
+ result = ""
data.each_byte { |d| result << z.inflate(d.chr)}
-> { result << z.finish }.should raise_error(Zlib::BufError)
end
@@ -90,7 +90,7 @@ describe "Zlib::Inflate.inflate" do
it "properly handles excessive data, byte-by-byte" do
main_data = [120, 156, 75, 203, 207, 7, 0, 2, 130, 1, 69].pack('C*')
data = main_data * 2
- result = +""
+ result = ""
z = Zlib::Inflate.new
# add bytes, one by one
@@ -105,7 +105,7 @@ describe "Zlib::Inflate.inflate" do
it "properly handles excessive data, in one go" do
main_data = [120, 156, 75, 203, 207, 7, 0, 2, 130, 1, 69].pack('C*')
data = main_data * 2
- result = +""
+ result = ""
z = Zlib::Inflate.new
result << z.inflate(data)
diff --git a/spec/ruby/library/zlib/inflate/new_spec.rb b/spec/ruby/library/zlib/inflate/new_spec.rb
new file mode 100644
index 0000000000..e15f14f95f
--- /dev/null
+++ b/spec/ruby/library/zlib/inflate/new_spec.rb
@@ -0,0 +1 @@
+require_relative '../../../spec_helper'
diff --git a/spec/ruby/optional/capi/array_spec.rb b/spec/ruby/optional/capi/array_spec.rb
index 9c35017e21..8e90980c6a 100644
--- a/spec/ruby/optional/capi/array_spec.rb
+++ b/spec/ruby/optional/capi/array_spec.rb
@@ -343,40 +343,6 @@ describe "C-API Array function" do
end
end
- describe "rb_iterate" do
- it "calls an callback function as a block passed to an method" do
- s = [1,2,3,4]
- s2 = @s.rb_iterate(s)
-
- s2.should == s
-
- # Make sure they're different objects
- s2.equal?(s).should be_false
- end
-
- it "calls a function with the other function available as a block" do
- h = {a: 1, b: 2}
-
- @s.rb_iterate_each_pair(h).sort.should == [1,2]
- end
-
- it "calls a function which can yield into the original block" do
- s2 = []
-
- o = Object.new
- def o.each
- yield 1
- yield 2
- yield 3
- yield 4
- end
-
- @s.rb_iterate_then_yield(o) { |x| s2 << x }
-
- s2.should == [1,2,3,4]
- end
- end
-
describe "rb_block_call" do
it "calls an callback function as a block passed to an method" do
s = [1,2,3,4]
diff --git a/spec/ruby/optional/capi/bignum_spec.rb b/spec/ruby/optional/capi/bignum_spec.rb
index 179f053eec..cde929af28 100644
--- a/spec/ruby/optional/capi/bignum_spec.rb
+++ b/spec/ruby/optional/capi/bignum_spec.rb
@@ -7,23 +7,21 @@ def ensure_bignum(n)
n
end
-full_range_longs = (fixnum_max == max_long)
-max_ulong = begin
- require 'rbconfig/sizeof'
- RbConfig::LIMITS['ULONG_MAX']
-rescue LoadError
- nil
-end
-# If the system doesn't offer ULONG_MAX, assume 2's complement and derive it
-# from LONG_MAX.
-max_ulong ||= 2 * (max_long + 1) - 1
+full_range_longs = (fixnum_max == 2**(0.size * 8 - 1) - 1)
describe "CApiBignumSpecs" do
before :each do
@s = CApiBignumSpecs.new
- @max_long = max_long
- @min_long = min_long
- @max_ulong = ensure_bignum(max_ulong)
+
+ if full_range_longs
+ @max_long = 2**(0.size * 8 - 1) - 1
+ @min_long = -@max_long - 1
+ @max_ulong = ensure_bignum(2**(0.size * 8) - 1)
+ else
+ @max_long = ensure_bignum(2**(0.size * 8 - 1) - 1)
+ @min_long = ensure_bignum(-@max_long - 1)
+ @max_ulong = ensure_bignum(2**(0.size * 8) - 1)
+ end
end
describe "rb_big2long" do
@@ -125,7 +123,7 @@ describe "CApiBignumSpecs" do
val.should == @max_ulong
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
it "packs max_ulong into 2 ulongs to allow sign bit" do
val = @s.rb_big_pack_length(@max_ulong)
val.should == 2
diff --git a/spec/ruby/optional/capi/class_spec.rb b/spec/ruby/optional/capi/class_spec.rb
index a231245ebe..66af381243 100644
--- a/spec/ruby/optional/capi/class_spec.rb
+++ b/spec/ruby/optional/capi/class_spec.rb
@@ -119,21 +119,23 @@ describe "C-API Class function" do
end
end
- describe "rb_class_new_instance_kw" do
- it "passes arguments and keywords to the #initialize method" do
- obj = @s.rb_class_new_instance_kw([{pos: 1}, {kw: 2}], CApiClassSpecs::KeywordAlloc)
- obj.args.should == [{pos: 1}]
- obj.kwargs.should == {kw: 2}
+ ruby_version_is "3.0" do
+ describe "rb_class_new_instance_kw" do
+ it "passes arguments and keywords to the #initialize method" do
+ obj = @s.rb_class_new_instance_kw([{pos: 1}, {kw: 2}], CApiClassSpecs::KeywordAlloc)
+ obj.args.should == [{pos: 1}]
+ obj.kwargs.should == {kw: 2}
- obj = @s.rb_class_new_instance_kw([{}], CApiClassSpecs::KeywordAlloc)
- obj.args.should == []
- obj.kwargs.should == {}
- end
+ obj = @s.rb_class_new_instance_kw([{}], CApiClassSpecs::KeywordAlloc)
+ obj.args.should == []
+ obj.kwargs.should == {}
+ end
- it "raises TypeError if the last argument is not a Hash" do
- -> {
- @s.rb_class_new_instance_kw([42], CApiClassSpecs::KeywordAlloc)
- }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash')
+ it "raises TypeError if the last argument is not a Hash" do
+ -> {
+ @s.rb_class_new_instance_kw([42], CApiClassSpecs::KeywordAlloc)
+ }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash')
+ end
end
end
@@ -487,16 +489,4 @@ describe "C-API Class function" do
@s.rb_class_real(0).should == 0
end
end
-
- describe "rb_class_get_superclass" do
- it "returns parent class for a provided class" do
- a = Class.new
- @s.rb_class_get_superclass(Class.new(a)).should == a
- end
-
- it "returns false when there is no parent class" do
- @s.rb_class_get_superclass(BasicObject).should == false
- @s.rb_class_get_superclass(Module.new).should == false
- end
- end
end
diff --git a/spec/ruby/optional/capi/data_spec.rb b/spec/ruby/optional/capi/data_spec.rb
index d000eba6e3..18c769332e 100644
--- a/spec/ruby/optional/capi/data_spec.rb
+++ b/spec/ruby/optional/capi/data_spec.rb
@@ -1,53 +1,52 @@
require_relative 'spec_helper'
-ruby_version_is ""..."3.4" do
- load_extension("data")
- describe "CApiAllocSpecs (a class with an alloc func defined)" do
- it "calls the alloc func" do
- @s = CApiAllocSpecs.new
- @s.wrapped_data.should == 42 # not defined in initialize
- end
+load_extension("data")
+
+describe "CApiAllocSpecs (a class with an alloc func defined)" do
+ it "calls the alloc func" do
+ @s = CApiAllocSpecs.new
+ @s.wrapped_data.should == 42 # not defined in initialize
+ end
+end
+
+describe "CApiWrappedStruct" do
+ before :each do
+ @s = CApiWrappedStructSpecs.new
+ end
+
+ it "wraps with Data_Wrap_Struct and Data_Get_Struct returns data" do
+ a = @s.wrap_struct(1024)
+ @s.get_struct(a).should == 1024
end
- describe "CApiWrappedStruct" do
- before :each do
- @s = CApiWrappedStructSpecs.new
+ describe "RDATA()" do
+ it "returns the struct data" do
+ a = @s.wrap_struct(1024)
+ @s.get_struct_rdata(a).should == 1024
end
- it "wraps with Data_Wrap_Struct and Data_Get_Struct returns data" do
+ it "allows changing the wrapped struct" do
a = @s.wrap_struct(1024)
- @s.get_struct(a).should == 1024
+ @s.change_struct(a, 100)
+ @s.get_struct(a).should == 100
end
- describe "RDATA()" do
- it "returns the struct data" do
- a = @s.wrap_struct(1024)
- @s.get_struct_rdata(a).should == 1024
- end
-
- it "allows changing the wrapped struct" do
- a = @s.wrap_struct(1024)
- @s.change_struct(a, 100)
- @s.get_struct(a).should == 100
- end
-
- it "raises a TypeError if the object does not wrap a struct" do
- -> { @s.get_struct(Object.new) }.should raise_error(TypeError)
- end
+ it "raises a TypeError if the object does not wrap a struct" do
+ -> { @s.get_struct(Object.new) }.should raise_error(TypeError)
end
+ end
- describe "rb_check_type" do
- it "does not raise an exception when checking data objects" do
- a = @s.wrap_struct(1024)
- @s.rb_check_type(a, a).should == true
- end
+ describe "rb_check_type" do
+ it "does not raise an exception when checking data objects" do
+ a = @s.wrap_struct(1024)
+ @s.rb_check_type(a, a).should == true
end
+ end
- describe "DATA_PTR" do
- it "returns the struct data" do
- a = @s.wrap_struct(1024)
- @s.get_struct_data_ptr(a).should == 1024
- end
+ describe "DATA_PTR" do
+ it "returns the struct data" do
+ a = @s.wrap_struct(1024)
+ @s.get_struct_data_ptr(a).should == 1024
end
end
end
diff --git a/spec/ruby/optional/capi/debug_spec.rb b/spec/ruby/optional/capi/debug_spec.rb
index 148b8c38fb..c8c91417d1 100644
--- a/spec/ruby/optional/capi/debug_spec.rb
+++ b/spec/ruby/optional/capi/debug_spec.rb
@@ -17,7 +17,6 @@ describe "C-API Debug function" do
describe "rb_debug_inspector_frame_self_get" do
it "returns self" do
@o.rb_debug_inspector_frame_self_get(0).should == @o
- @o.rb_debug_inspector_frame_self_get(1).should == self
end
end
@@ -36,14 +35,10 @@ describe "C-API Debug function" do
end
it "matches the locations in rb_debug_inspector_backtrace_locations" do
- frames = @o.rb_debug_inspector_open(42)
+ frames = @o.rb_debug_inspector_open(42);
frames.each do |_s, _klass, binding, _iseq, backtrace_location|
if binding
- binding.source_location.should == [backtrace_location.path, backtrace_location.lineno]
- method_name = binding.eval('__method__')
- if method_name
- method_name.should == backtrace_location.base_label.to_sym
- end
+ "#{backtrace_location.path}:#{backtrace_location.lineno}".should == "#{binding.source_location[0]}:#{binding.source_location[1]}"
end
end
end
diff --git a/spec/ruby/optional/capi/encoding_spec.rb b/spec/ruby/optional/capi/encoding_spec.rb
index 1529e012b0..aa632b963b 100644
--- a/spec/ruby/optional/capi/encoding_spec.rb
+++ b/spec/ruby/optional/capi/encoding_spec.rb
@@ -1,9 +1,8 @@
# -*- encoding: utf-8 -*-
-# frozen_string_literal: false
require_relative 'spec_helper'
require_relative 'fixtures/encoding'
-extension_path = load_extension('encoding')
+load_extension('encoding')
describe :rb_enc_get_index, shared: true do
it "returns the index of the encoding of a String" do
@@ -560,19 +559,19 @@ describe "C-API Encoding function" do
describe "rb_ascii8bit_encindex" do
it "returns an index for the ASCII-8BIT encoding" do
- @s.rb_ascii8bit_encindex().should == 0
+ @s.rb_ascii8bit_encindex().should >= 0
end
end
describe "rb_utf8_encindex" do
it "returns an index for the UTF-8 encoding" do
- @s.rb_utf8_encindex().should == 1
+ @s.rb_utf8_encindex().should >= 0
end
end
describe "rb_usascii_encindex" do
it "returns an index for the US-ASCII encoding" do
- @s.rb_usascii_encindex().should == 2
+ @s.rb_usascii_encindex().should >= 0
end
end
@@ -658,20 +657,6 @@ describe "C-API Encoding function" do
end
end
- describe "rb_enc_raise" do
- it "forces exception message encoding to the specified one" do
- utf_8_incompatible_string = "\x81".b
-
- -> {
- @s.rb_enc_raise(Encoding::UTF_8, RuntimeError, utf_8_incompatible_string)
- }.should raise_error { |e|
- e.message.encoding.should == Encoding::UTF_8
- e.message.valid_encoding?.should == false
- e.message.bytes.should == utf_8_incompatible_string.bytes
- }
- end
- end
-
describe "rb_uv_to_utf8" do
it 'converts a Unicode codepoint to a UTF-8 C string' do
str = ' ' * 6
@@ -689,22 +674,6 @@ describe "C-API Encoding function" do
end
end
- describe "rb_enc_left_char_head" do
- it 'returns the head position of a character' do
- @s.rb_enc_left_char_head("é", 1).should == 0
- @s.rb_enc_left_char_head("éééé", 7).should == 6
-
- @s.rb_enc_left_char_head("a", 0).should == 0
-
- # unclear if this is intended to work
- @s.rb_enc_left_char_head("a", 1).should == 1
-
- # Works because for single-byte encodings rb_enc_left_char_head() just returns the pointer
- @s.rb_enc_left_char_head("a".force_encoding(Encoding::US_ASCII), 88).should == 88
- @s.rb_enc_left_char_head("a".b, 88).should == 88
- end
- end
-
describe "ONIGENC_MBC_CASE_FOLD" do
it "returns the correct case fold for the given string" do
@s.ONIGENC_MBC_CASE_FOLD("lower").should == ["l", 1]
@@ -722,27 +691,4 @@ describe "C-API Encoding function" do
str.bytes.should == [0, 0x24]
end
end
-
- describe "rb_define_dummy_encoding" do
- it "defines the dummy encoding" do
- @s.rb_define_dummy_encoding("FOO")
- enc = Encoding.find("FOO")
- enc.should.dummy?
- end
-
- it "returns the index of the dummy encoding" do
- index = @s.rb_define_dummy_encoding("BAR")
- index.should == Encoding.list.size - 1
- end
-
- ruby_version_is "3.2" do
- it "raises EncodingError if too many encodings" do
- code = <<-RUBY
- require #{extension_path.dump}
- 1_000.times {|i| CApiEncodingSpecs.new.rb_define_dummy_encoding("R_\#{i}") }
- RUBY
- ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
- end
- end
- end
end
diff --git a/spec/ruby/optional/capi/exception_spec.rb b/spec/ruby/optional/capi/exception_spec.rb
index 5bb60608b2..b0a8a2860e 100644
--- a/spec/ruby/optional/capi/exception_spec.rb
+++ b/spec/ruby/optional/capi/exception_spec.rb
@@ -100,40 +100,6 @@ describe "C-API Exception function" do
end
end
- describe "rb_syserr_new" do
- it "returns system error with default message when passed message is NULL" do
- exception = @s.rb_syserr_new(Errno::ENOENT::Errno, nil)
- exception.class.should == Errno::ENOENT
- exception.message.should include("No such file or directory")
- exception.should.is_a?(SystemCallError)
- end
-
- it "returns system error with custom message" do
- exception = @s.rb_syserr_new(Errno::ENOENT::Errno, "custom message")
-
- exception.message.should include("custom message")
- exception.class.should == Errno::ENOENT
- exception.should.is_a?(SystemCallError)
- end
- end
-
- describe "rb_syserr_new_str" do
- it "returns system error with default message when passed message is nil" do
- exception = @s.rb_syserr_new_str(Errno::ENOENT::Errno, nil)
-
- exception.message.should include("No such file or directory")
- exception.class.should == Errno::ENOENT
- exception.should.is_a?(SystemCallError)
- end
-
- it "returns system error with custom message" do
- exception = @s.rb_syserr_new_str(Errno::ENOENT::Errno, "custom message")
- exception.message.should include("custom message")
- exception.class.should == Errno::ENOENT
- exception.should.is_a?(SystemCallError)
- end
- end
-
describe "rb_make_exception" do
it "returns a RuntimeError when given a String argument" do
e = @s.rb_make_exception(["Message"])
diff --git a/spec/ruby/optional/capi/ext/array_spec.c b/spec/ruby/optional/capi/ext/array_spec.c
index 2347798bb4..9386239813 100644
--- a/spec/ruby/optional/capi/ext/array_spec.c
+++ b/spec/ruby/optional/capi/ext/array_spec.c
@@ -196,14 +196,6 @@ static VALUE copy_ary(RB_BLOCK_CALL_FUNC_ARGLIST(el, new_ary)) {
return rb_ary_push(new_ary, el);
}
-static VALUE array_spec_rb_iterate(VALUE self, VALUE ary) {
- VALUE new_ary = rb_ary_new();
-
- rb_iterate(rb_each, ary, copy_ary, new_ary);
-
- return new_ary;
-}
-
static VALUE array_spec_rb_block_call(VALUE self, VALUE ary) {
VALUE new_ary = rb_ary_new();
@@ -216,18 +208,6 @@ static VALUE sub_pair(RB_BLOCK_CALL_FUNC_ARGLIST(el, holder)) {
return rb_ary_push(holder, rb_ary_entry(el, 1));
}
-static VALUE each_pair(VALUE obj) {
- return rb_funcall(obj, rb_intern("each_pair"), 0);
-}
-
-static VALUE array_spec_rb_iterate_each_pair(VALUE self, VALUE obj) {
- VALUE new_ary = rb_ary_new();
-
- rb_iterate(each_pair, obj, sub_pair, new_ary);
-
- return new_ary;
-}
-
static VALUE array_spec_rb_block_call_each_pair(VALUE self, VALUE obj) {
VALUE new_ary = rb_ary_new();
@@ -241,11 +221,6 @@ static VALUE iter_yield(RB_BLOCK_CALL_FUNC_ARGLIST(el, ary)) {
return Qnil;
}
-static VALUE array_spec_rb_iterate_then_yield(VALUE self, VALUE obj) {
- rb_iterate(rb_each, obj, iter_yield, obj);
- return Qnil;
-}
-
static VALUE array_spec_rb_block_call_then_yield(VALUE self, VALUE obj) {
rb_block_call(obj, rb_intern("each"), 0, 0, iter_yield, obj);
return Qnil;
@@ -308,9 +283,6 @@ void Init_array_spec(void) {
rb_define_method(cls, "rb_ary_plus", array_spec_rb_ary_plus, 2);
rb_define_method(cls, "rb_ary_unshift", array_spec_rb_ary_unshift, 2);
rb_define_method(cls, "rb_assoc_new", array_spec_rb_assoc_new, 2);
- rb_define_method(cls, "rb_iterate", array_spec_rb_iterate, 1);
- rb_define_method(cls, "rb_iterate_each_pair", array_spec_rb_iterate_each_pair, 1);
- rb_define_method(cls, "rb_iterate_then_yield", array_spec_rb_iterate_then_yield, 1);
rb_define_method(cls, "rb_block_call", array_spec_rb_block_call, 1);
rb_define_method(cls, "rb_block_call_each_pair", array_spec_rb_block_call_each_pair, 1);
rb_define_method(cls, "rb_block_call_then_yield", array_spec_rb_block_call_then_yield, 1);
diff --git a/spec/ruby/optional/capi/ext/class_spec.c b/spec/ruby/optional/capi/ext/class_spec.c
index c13f02ecf2..589025f677 100644
--- a/spec/ruby/optional/capi/ext/class_spec.c
+++ b/spec/ruby/optional/capi/ext/class_spec.c
@@ -72,17 +72,13 @@ static VALUE class_spec_rb_class_new_instance_kw(VALUE self, VALUE args, VALUE k
#endif
static VALUE class_spec_rb_class_real(VALUE self, VALUE object) {
- if (rb_type_p(object, T_FIXNUM)) {
+ if(rb_type_p(object, T_FIXNUM)) {
return INT2FIX(rb_class_real(FIX2INT(object)));
} else {
return rb_class_real(CLASS_OF(object));
}
}
-static VALUE class_spec_rb_class_get_superclass(VALUE self, VALUE klass) {
- return rb_class_get_superclass(klass);
-}
-
static VALUE class_spec_rb_class_superclass(VALUE self, VALUE klass) {
return rb_class_superclass(klass);
}
@@ -120,19 +116,19 @@ VALUE class_spec_define_attr(VALUE self, VALUE klass, VALUE sym, VALUE read, VAL
}
static VALUE class_spec_rb_define_class(VALUE self, VALUE name, VALUE super) {
- if (NIL_P(super)) super = 0;
+ if(NIL_P(super)) super = 0;
return rb_define_class(RSTRING_PTR(name), super);
}
static VALUE class_spec_rb_define_class_under(VALUE self, VALUE outer,
VALUE name, VALUE super) {
- if (NIL_P(super)) super = 0;
+ if(NIL_P(super)) super = 0;
return rb_define_class_under(outer, RSTRING_PTR(name), super);
}
static VALUE class_spec_rb_define_class_id_under(VALUE self, VALUE outer,
VALUE name, VALUE super) {
- if (NIL_P(super)) super = 0;
+ if(NIL_P(super)) super = 0;
return rb_define_class_id_under(outer, SYM2ID(name), super);
}
@@ -164,7 +160,6 @@ void Init_class_spec(void) {
rb_define_method(cls, "rb_class_new_instance_kw", class_spec_rb_class_new_instance_kw, 2);
#endif
rb_define_method(cls, "rb_class_real", class_spec_rb_class_real, 1);
- rb_define_method(cls, "rb_class_get_superclass", class_spec_rb_class_get_superclass, 1);
rb_define_method(cls, "rb_class_superclass", class_spec_rb_class_superclass, 1);
rb_define_method(cls, "rb_cvar_defined", class_spec_cvar_defined, 2);
rb_define_method(cls, "rb_cvar_get", class_spec_cvar_get, 2);
diff --git a/spec/ruby/optional/capi/ext/data_spec.c b/spec/ruby/optional/capi/ext/data_spec.c
index efefe37c3a..ef069ef0ba 100644
--- a/spec/ruby/optional/capi/ext/data_spec.c
+++ b/spec/ruby/optional/capi/ext/data_spec.c
@@ -3,7 +3,6 @@
#include <string.h>
-#ifndef RUBY_VERSION_IS_3_4
#ifdef __cplusplus
extern "C" {
#endif
@@ -71,10 +70,8 @@ VALUE sws_rb_check_type(VALUE self, VALUE obj, VALUE other) {
rb_check_type(obj, TYPE(other));
return Qtrue;
}
-#endif
void Init_data_spec(void) {
-#ifndef RUBY_VERSION_IS_3_4
VALUE cls = rb_define_class("CApiAllocSpecs", rb_cObject);
rb_define_alloc_func(cls, sdaf_alloc_func);
rb_define_method(cls, "wrapped_data", sdaf_get_struct, 0);
@@ -85,7 +82,6 @@ void Init_data_spec(void) {
rb_define_method(cls, "get_struct_data_ptr", sws_get_struct_data_ptr, 1);
rb_define_method(cls, "change_struct", sws_change_struct, 2);
rb_define_method(cls, "rb_check_type", sws_rb_check_type, 2);
-#endif
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/debug_spec.c b/spec/ruby/optional/capi/ext/debug_spec.c
index 9131eda78b..344dfc33fa 100644
--- a/spec/ruby/optional/capi/ext/debug_spec.c
+++ b/spec/ruby/optional/capi/ext/debug_spec.c
@@ -45,7 +45,7 @@ static VALUE rb_debug_inspector_frame_iseq_get_callback(const rb_debug_inspector
return rb_debug_inspector_frame_iseq_get(dc, NUM2LONG((VALUE) ptr));
}
-static VALUE debug_spec_callback_data(VALUE self) {
+static VALUE debug_spec_callback_data(VALUE self){
return callback_data;
}
diff --git a/spec/ruby/optional/capi/ext/encoding_spec.c b/spec/ruby/optional/capi/ext/encoding_spec.c
index aa8662cfbd..a0136530f2 100644
--- a/spec/ruby/optional/capi/ext/encoding_spec.c
+++ b/spec/ruby/optional/capi/ext/encoding_spec.c
@@ -12,7 +12,7 @@ static VALUE encoding_spec_MBCLEN_CHARFOUND_P(VALUE self, VALUE obj) {
}
static VALUE encoding_spec_ENC_CODERANGE_ASCIIONLY(VALUE self, VALUE obj) {
- if (ENC_CODERANGE_ASCIIONLY(obj)) {
+ if(ENC_CODERANGE_ASCIIONLY(obj)) {
return Qtrue;
} else {
return Qfalse;
@@ -61,13 +61,13 @@ static VALUE encoding_spec_rb_filesystem_encindex(VALUE self) {
static VALUE encoding_spec_rb_default_internal_encoding(VALUE self) {
rb_encoding* enc = rb_default_internal_encoding();
- if (enc == 0) return Qnil;
+ if(enc == 0) return Qnil;
return rb_str_new2(enc->name);
}
static VALUE encoding_spec_rb_default_external_encoding(VALUE self) {
rb_encoding* enc = rb_default_external_encoding();
- if (enc == 0) return Qnil;
+ if(enc == 0) return Qnil;
return rb_str_new2(enc->name);
}
@@ -86,7 +86,7 @@ static VALUE encoding_spec_rb_enc_associate_index(VALUE self, VALUE obj, VALUE i
static VALUE encoding_spec_rb_enc_compatible(VALUE self, VALUE a, VALUE b) {
rb_encoding* enc = rb_enc_compatible(a, b);
- if (!enc) return INT2FIX(0);
+ if(!enc) return INT2FIX(0);
return rb_enc_from_encoding(enc);
}
@@ -271,13 +271,6 @@ static VALUE encoding_spec_rb_enc_str_asciionly_p(VALUE self, VALUE str) {
}
}
-static VALUE encoding_spec_rb_enc_raise(VALUE self, VALUE encoding, VALUE exception_class, VALUE format) {
- rb_encoding *e = rb_to_encoding(encoding);
- const char *f = RSTRING_PTR(format);
-
- rb_enc_raise(e, exception_class, "%s", f);
-}
-
static VALUE encoding_spec_rb_uv_to_utf8(VALUE self, VALUE buf, VALUE num) {
int len = rb_uv_to_utf8(RSTRING_PTR(buf), NUM2INT(num));
RB_ENC_CODERANGE_CLEAR(buf);
@@ -314,16 +307,6 @@ static VALUE encoding_spec_rb_enc_strlen(VALUE self, VALUE str, VALUE length, VA
return LONG2FIX(rb_enc_strlen(p, e, rb_to_encoding(encoding)));
}
-static VALUE encoding_spec_rb_enc_left_char_head(VALUE self, VALUE str, VALUE offset) {
- char *ptr = RSTRING_PTR(str);
- char *result = rb_enc_left_char_head(ptr, ptr + NUM2INT(offset), RSTRING_END(str), rb_enc_get(str));
- return LONG2NUM(result - ptr);
-}
-
-static VALUE encoding_spec_rb_define_dummy_encoding(VALUE self, VALUE name) {
- return INT2NUM(rb_define_dummy_encoding(RSTRING_PTR(name)));
-}
-
void Init_encoding_spec(void) {
VALUE cls;
native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*));
@@ -379,11 +362,8 @@ void Init_encoding_spec(void) {
rb_define_method(cls, "rb_enc_nth", encoding_spec_rb_enc_nth, 2);
rb_define_method(cls, "rb_enc_codepoint_len", encoding_spec_rb_enc_codepoint_len, 1);
rb_define_method(cls, "rb_enc_str_asciionly_p", encoding_spec_rb_enc_str_asciionly_p, 1);
- rb_define_method(cls, "rb_enc_raise", encoding_spec_rb_enc_raise, 3);
rb_define_method(cls, "rb_uv_to_utf8", encoding_spec_rb_uv_to_utf8, 2);
rb_define_method(cls, "ONIGENC_MBC_CASE_FOLD", encoding_spec_ONIGENC_MBC_CASE_FOLD, 1);
- rb_define_method(cls, "rb_enc_left_char_head", encoding_spec_rb_enc_left_char_head, 2);
- rb_define_method(cls, "rb_define_dummy_encoding", encoding_spec_rb_define_dummy_encoding, 1);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/exception_spec.c b/spec/ruby/optional/capi/ext/exception_spec.c
index 0e8347ab0d..e1114aabb8 100644
--- a/spec/ruby/optional/capi/ext/exception_spec.c
+++ b/spec/ruby/optional/capi/ext/exception_spec.c
@@ -27,7 +27,7 @@ VALUE exception_spec_rb_exc_new3(VALUE self, VALUE str) {
}
VALUE exception_spec_rb_exc_raise(VALUE self, VALUE exc) {
- if (self != Qundef) rb_exc_raise(exc);
+ if (self != Qundef) rb_exc_raise(exc);
return Qnil;
}
@@ -36,21 +36,6 @@ VALUE exception_spec_rb_set_errinfo(VALUE self, VALUE exc) {
return Qnil;
}
-VALUE exception_spec_rb_syserr_new(VALUE self, VALUE num, VALUE msg) {
- int n = NUM2INT(num);
- char *cstr = NULL;
-
- if (msg != Qnil) {
- cstr = StringValuePtr(msg);
- }
-
- return rb_syserr_new(n, cstr);
-}
-
-VALUE exception_spec_rb_syserr_new_str(VALUE self, VALUE num, VALUE msg) {
- int n = NUM2INT(num);
- return rb_syserr_new_str(n, msg);
-}
VALUE exception_spec_rb_make_exception(VALUE self, VALUE ary) {
int argc = RARRAY_LENINT(ary);
@@ -66,8 +51,6 @@ void Init_exception_spec(void) {
rb_define_method(cls, "rb_exc_new3", exception_spec_rb_exc_new3, 1);
rb_define_method(cls, "rb_exc_raise", exception_spec_rb_exc_raise, 1);
rb_define_method(cls, "rb_set_errinfo", exception_spec_rb_set_errinfo, 1);
- rb_define_method(cls, "rb_syserr_new", exception_spec_rb_syserr_new, 2);
- rb_define_method(cls, "rb_syserr_new_str", exception_spec_rb_syserr_new_str, 2);
rb_define_method(cls, "rb_make_exception", exception_spec_rb_make_exception, 1);
}
diff --git a/spec/ruby/optional/capi/ext/gc_spec.c b/spec/ruby/optional/capi/ext/gc_spec.c
index 2637ad27ac..b323c2456d 100644
--- a/spec/ruby/optional/capi/ext/gc_spec.c
+++ b/spec/ruby/optional/capi/ext/gc_spec.c
@@ -8,16 +8,9 @@ extern "C" {
VALUE registered_tagged_value;
VALUE registered_reference_value;
VALUE registered_before_rb_gc_register_address;
-VALUE registered_before_rb_global_variable_string;
-VALUE registered_before_rb_global_variable_bignum;
-VALUE registered_before_rb_global_variable_float;
-VALUE registered_after_rb_global_variable_string;
-VALUE registered_after_rb_global_variable_bignum;
-VALUE registered_after_rb_global_variable_float;
+VALUE registered_before_rb_global_variable;
VALUE rb_gc_register_address_outside_init;
-VALUE rb_gc_register_mark_object_not_referenced_float;
-
static VALUE registered_tagged_address(VALUE self) {
return registered_tagged_value;
}
@@ -30,28 +23,8 @@ static VALUE get_registered_before_rb_gc_register_address(VALUE self) {
return registered_before_rb_gc_register_address;
}
-static VALUE get_registered_before_rb_global_variable_string(VALUE self) {
- return registered_before_rb_global_variable_string;
-}
-
-static VALUE get_registered_before_rb_global_variable_bignum(VALUE self) {
- return registered_before_rb_global_variable_bignum;
-}
-
-static VALUE get_registered_before_rb_global_variable_float(VALUE self) {
- return registered_before_rb_global_variable_float;
-}
-
-static VALUE get_registered_after_rb_global_variable_string(VALUE self) {
- return registered_after_rb_global_variable_string;
-}
-
-static VALUE get_registered_after_rb_global_variable_bignum(VALUE self) {
- return registered_after_rb_global_variable_bignum;
-}
-
-static VALUE get_registered_after_rb_global_variable_float(VALUE self) {
- return registered_after_rb_global_variable_float;
+static VALUE get_registered_before_rb_global_variable(VALUE self) {
+ return registered_before_rb_global_variable;
}
static VALUE gc_spec_rb_gc_register_address(VALUE self) {
@@ -78,7 +51,7 @@ static VALUE gc_spec_rb_gc(VALUE self) {
return Qnil;
}
-static VALUE gc_spec_rb_gc_latest_gc_info(VALUE self, VALUE hash_or_key) {
+static VALUE gc_spec_rb_gc_latest_gc_info(VALUE self, VALUE hash_or_key){
return rb_gc_latest_gc_info(hash_or_key);
}
@@ -92,47 +65,23 @@ static VALUE gc_spec_rb_gc_register_mark_object(VALUE self, VALUE obj) {
return Qnil;
}
-static VALUE gc_spec_rb_gc_register_mark_object_not_referenced_float(VALUE self) {
- return rb_gc_register_mark_object_not_referenced_float;
-}
-
void Init_gc_spec(void) {
VALUE cls = rb_define_class("CApiGCSpecs", rb_cObject);
rb_gc_register_address(&registered_tagged_value);
rb_gc_register_address(&registered_reference_value);
rb_gc_register_address(&registered_before_rb_gc_register_address);
- rb_global_variable(&registered_before_rb_global_variable_string);
- rb_global_variable(&registered_before_rb_global_variable_bignum);
- rb_global_variable(&registered_before_rb_global_variable_float);
+ rb_global_variable(&registered_before_rb_global_variable);
registered_tagged_value = INT2NUM(10);
registered_reference_value = rb_str_new2("Globally registered data");
registered_before_rb_gc_register_address = rb_str_new_cstr("registered before rb_gc_register_address()");
-
- registered_before_rb_global_variable_string = rb_str_new_cstr("registered before rb_global_variable()");
- registered_before_rb_global_variable_bignum = LL2NUM(INT64_MAX);
- registered_before_rb_global_variable_float = DBL2NUM(3.14);
-
- registered_after_rb_global_variable_string = rb_str_new_cstr("registered after rb_global_variable()");
- rb_global_variable(&registered_after_rb_global_variable_string);
- registered_after_rb_global_variable_bignum = LL2NUM(INT64_MAX);
- rb_global_variable(&registered_after_rb_global_variable_bignum);
- registered_after_rb_global_variable_float = DBL2NUM(6.28);
- rb_global_variable(&registered_after_rb_global_variable_float);
-
- rb_gc_register_mark_object_not_referenced_float = DBL2NUM(1.61);
- rb_gc_register_mark_object(rb_gc_register_mark_object_not_referenced_float);
+ registered_before_rb_global_variable = rb_str_new_cstr("registered before rb_global_variable()");
rb_define_method(cls, "registered_tagged_address", registered_tagged_address, 0);
rb_define_method(cls, "registered_reference_address", registered_reference_address, 0);
rb_define_method(cls, "registered_before_rb_gc_register_address", get_registered_before_rb_gc_register_address, 0);
- rb_define_method(cls, "registered_before_rb_global_variable_string", get_registered_before_rb_global_variable_string, 0);
- rb_define_method(cls, "registered_before_rb_global_variable_bignum", get_registered_before_rb_global_variable_bignum, 0);
- rb_define_method(cls, "registered_before_rb_global_variable_float", get_registered_before_rb_global_variable_float, 0);
- rb_define_method(cls, "registered_after_rb_global_variable_string", get_registered_after_rb_global_variable_string, 0);
- rb_define_method(cls, "registered_after_rb_global_variable_bignum", get_registered_after_rb_global_variable_bignum, 0);
- rb_define_method(cls, "registered_after_rb_global_variable_float", get_registered_after_rb_global_variable_float, 0);
+ rb_define_method(cls, "registered_before_rb_global_variable", get_registered_before_rb_global_variable, 0);
rb_define_method(cls, "rb_gc_register_address", gc_spec_rb_gc_register_address, 0);
rb_define_method(cls, "rb_gc_unregister_address", gc_spec_rb_gc_unregister_address, 0);
rb_define_method(cls, "rb_gc_enable", gc_spec_rb_gc_enable, 0);
@@ -140,7 +89,6 @@ void Init_gc_spec(void) {
rb_define_method(cls, "rb_gc", gc_spec_rb_gc, 0);
rb_define_method(cls, "rb_gc_adjust_memory_usage", gc_spec_rb_gc_adjust_memory_usage, 1);
rb_define_method(cls, "rb_gc_register_mark_object", gc_spec_rb_gc_register_mark_object, 1);
- rb_define_method(cls, "rb_gc_register_mark_object_not_referenced_float", gc_spec_rb_gc_register_mark_object_not_referenced_float, 0);
rb_define_method(cls, "rb_gc_latest_gc_info", gc_spec_rb_gc_latest_gc_info, 1);
}
diff --git a/spec/ruby/optional/capi/ext/hash_spec.c b/spec/ruby/optional/capi/ext/hash_spec.c
index 69ef02d5da..7f38708915 100644
--- a/spec/ruby/optional/capi/ext/hash_spec.c
+++ b/spec/ruby/optional/capi/ext/hash_spec.c
@@ -105,12 +105,6 @@ VALUE hash_spec_rb_hash_new(VALUE self) {
return rb_hash_new();
}
-#ifdef RUBY_VERSION_IS_3_2
-VALUE hash_spec_rb_hash_new_capa(VALUE self, VALUE capacity) {
- return rb_hash_new_capa(NUM2LONG(capacity));
-}
-#endif
-
VALUE rb_ident_hash_new(void); /* internal.h, used in ripper */
VALUE hash_spec_rb_ident_hash_new(VALUE self) {
@@ -155,9 +149,6 @@ void Init_hash_spec(void) {
rb_define_method(cls, "rb_hash_lookup2", hash_spec_rb_hash_lookup2, 3);
rb_define_method(cls, "rb_hash_lookup2_default_undef", hash_spec_rb_hash_lookup2_default_undef, 2);
rb_define_method(cls, "rb_hash_new", hash_spec_rb_hash_new, 0);
-#ifdef RUBY_VERSION_IS_3_2
- rb_define_method(cls, "rb_hash_new_capa", hash_spec_rb_hash_new_capa, 1);
-#endif
rb_define_method(cls, "rb_ident_hash_new", hash_spec_rb_ident_hash_new, 0);
rb_define_method(cls, "rb_hash_size", hash_spec_rb_hash_size, 1);
rb_define_method(cls, "rb_hash_set_ifnone", hash_spec_rb_hash_set_ifnone, 2);
diff --git a/spec/ruby/optional/capi/ext/integer_spec.c b/spec/ruby/optional/capi/ext/integer_spec.c
index 792fc0652a..16cd95f111 100644
--- a/spec/ruby/optional/capi/ext/integer_spec.c
+++ b/spec/ruby/optional/capi/ext/integer_spec.c
@@ -6,7 +6,8 @@ extern "C" {
#endif
static VALUE integer_spec_rb_integer_pack(VALUE self, VALUE value,
- VALUE words, VALUE numwords, VALUE wordsize, VALUE nails, VALUE flags) {
+ VALUE words, VALUE numwords, VALUE wordsize, VALUE nails, VALUE flags)
+{
int result = rb_integer_pack(value, (void*)RSTRING_PTR(words), FIX2INT(numwords),
FIX2INT(wordsize), FIX2INT(nails), FIX2INT(flags));
return INT2FIX(result);
@@ -14,7 +15,7 @@ static VALUE integer_spec_rb_integer_pack(VALUE self, VALUE value,
RUBY_EXTERN VALUE rb_int_positive_pow(long x, unsigned long y); /* internal.h, used in ripper */
-static VALUE integer_spec_rb_int_positive_pow(VALUE self, VALUE a, VALUE b) {
+static VALUE integer_spec_rb_int_positive_pow(VALUE self, VALUE a, VALUE b){
return rb_int_positive_pow(FIX2INT(a), FIX2INT(b));
}
diff --git a/spec/ruby/optional/capi/ext/io_spec.c b/spec/ruby/optional/capi/ext/io_spec.c
index e0b1df0de7..f257cef554 100644
--- a/spec/ruby/optional/capi/ext/io_spec.c
+++ b/spec/ruby/optional/capi/ext/io_spec.c
@@ -28,13 +28,9 @@ static int set_non_blocking(int fd) {
}
static int io_spec_get_fd(VALUE io) {
-#ifdef RUBY_VERSION_IS_3_1
- return rb_io_descriptor(io);
-#else
rb_io_t* fp;
GetOpenFile(io, fp);
return fp->fd;
-#endif
}
VALUE io_spec_GetOpenFile_fd(VALUE self, VALUE io) {
@@ -134,7 +130,7 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) {
rb_sys_fail("set_non_blocking failed");
#ifndef SET_NON_BLOCKING_FAILS_ALWAYS
- if (RTEST(read_p)) {
+ if(RTEST(read_p)) {
if (read(fd, buf, RB_IO_WAIT_READABLE_BUF) != -1) {
return Qnil;
}
@@ -143,13 +139,9 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) {
errno = saved_errno;
}
-#ifdef RUBY_VERSION_IS_3_1
- ret = rb_io_maybe_wait_readable(errno, io, Qnil);
-#else
ret = rb_io_wait_readable(fd);
-#endif
- if (RTEST(read_p)) {
+ if(RTEST(read_p)) {
ssize_t r = read(fd, buf, RB_IO_WAIT_READABLE_BUF);
if (r != RB_IO_WAIT_READABLE_BUF) {
perror("read");
@@ -161,100 +153,28 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) {
return ret ? Qtrue : Qfalse;
#else
- UNREACHABLE_RETURN(Qnil);
+ UNREACHABLE;
#endif
}
VALUE io_spec_rb_io_wait_writable(VALUE self, VALUE io) {
-#ifdef RUBY_VERSION_IS_3_1
- int ret = rb_io_maybe_wait_writable(errno, io, Qnil);
-#else
int ret = rb_io_wait_writable(io_spec_get_fd(io));
-#endif
return ret ? Qtrue : Qfalse;
}
-#ifdef RUBY_VERSION_IS_3_1
-VALUE io_spec_rb_io_maybe_wait_writable(VALUE self, VALUE error, VALUE io, VALUE timeout) {
- int ret = rb_io_maybe_wait_writable(NUM2INT(error), io, timeout);
- return INT2NUM(ret);
-}
-#endif
-
-#ifdef RUBY_VERSION_IS_3_1
-#ifdef SET_NON_BLOCKING_FAILS_ALWAYS
-NORETURN(VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p));
-#endif
-
-VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p) {
- int fd = io_spec_get_fd(io);
-#ifndef SET_NON_BLOCKING_FAILS_ALWAYS
- char buf[RB_IO_WAIT_READABLE_BUF];
- int ret, saved_errno;
-#endif
-
- if (set_non_blocking(fd) == -1)
- rb_sys_fail("set_non_blocking failed");
-
-#ifndef SET_NON_BLOCKING_FAILS_ALWAYS
- if (RTEST(read_p)) {
- if (read(fd, buf, RB_IO_WAIT_READABLE_BUF) != -1) {
- return Qnil;
- }
- saved_errno = errno;
- rb_ivar_set(self, rb_intern("@write_data"), Qtrue);
- errno = saved_errno;
- }
-
- // main part
- ret = rb_io_maybe_wait_readable(NUM2INT(error), io, timeout);
-
- if (RTEST(read_p)) {
- ssize_t r = read(fd, buf, RB_IO_WAIT_READABLE_BUF);
- if (r != RB_IO_WAIT_READABLE_BUF) {
- perror("read");
- return SSIZET2NUM(r);
- }
- rb_ivar_set(self, rb_intern("@read_data"),
- rb_str_new(buf, RB_IO_WAIT_READABLE_BUF));
- }
-
- return INT2NUM(ret);
-#else
- UNREACHABLE_RETURN(Qnil);
-#endif
-}
-#endif
-
-#ifdef RUBY_VERSION_IS_3_1
-VALUE io_spec_rb_io_maybe_wait(VALUE self, VALUE error, VALUE io, VALUE events, VALUE timeout) {
- return rb_io_maybe_wait(NUM2INT(error), io, events, timeout);
-}
-#endif
-
VALUE io_spec_rb_thread_wait_fd(VALUE self, VALUE io) {
rb_thread_wait_fd(io_spec_get_fd(io));
return Qnil;
}
VALUE io_spec_rb_wait_for_single_fd(VALUE self, VALUE io, VALUE events, VALUE secs, VALUE usecs) {
-#ifdef RUBY_VERSION_IS_3_0
- VALUE timeout = Qnil;
- if (!NIL_P(secs)) {
- timeout = rb_float_new((double)FIX2INT(secs) + (0.000001f * FIX2INT(usecs)));
- }
- VALUE result = rb_io_wait(io, events, timeout);
- if (result == Qfalse) return INT2FIX(0);
- else return result;
-#else
+ int fd = io_spec_get_fd(io);
struct timeval tv;
if (!NIL_P(secs)) {
tv.tv_sec = FIX2INT(secs);
tv.tv_usec = FIX2INT(usecs);
}
- int fd = io_spec_get_fd(io);
return INT2FIX(rb_wait_for_single_fd(fd, FIX2INT(events), NIL_P(secs) ? NULL : &tv));
-#endif
}
VALUE io_spec_rb_thread_fd_writable(VALUE self, VALUE io) {
@@ -329,7 +249,7 @@ VALUE io_spec_rb_io_set_nonblock(VALUE self, VALUE io) {
GetOpenFile(io, fp);
rb_io_set_nonblock(fp);
#ifdef F_GETFL
- flags = fcntl(io_spec_get_fd(io), F_GETFL, 0);
+ flags = fcntl(fp->fd, F_GETFL, 0);
return flags & O_NONBLOCK ? Qtrue : Qfalse;
#else
return Qfalse;
@@ -348,31 +268,15 @@ static VALUE io_spec_errno_set(VALUE self, VALUE val) {
}
VALUE io_spec_mode_sync_flag(VALUE self, VALUE io) {
- int mode;
-#ifdef RUBY_VERSION_IS_3_3
- mode = rb_io_mode(io);
-#else
rb_io_t *fp;
GetOpenFile(io, fp);
- mode = fp->mode;
-#endif
- if (mode & FMODE_SYNC) {
+ if (fp->mode & FMODE_SYNC) {
return Qtrue;
} else {
return Qfalse;
}
}
-#if defined(RUBY_VERSION_IS_3_3) || defined(TRUFFLERUBY)
-static VALUE io_spec_rb_io_mode(VALUE self, VALUE io) {
- return INT2FIX(rb_io_mode(io));
-}
-
-static VALUE io_spec_rb_io_path(VALUE self, VALUE io) {
- return rb_io_path(io);
-}
-#endif
-
void Init_io_spec(void) {
VALUE cls = rb_define_class("CApiIOSpecs", rb_cObject);
rb_define_method(cls, "GetOpenFile_fd", io_spec_GetOpenFile_fd, 1);
@@ -390,11 +294,6 @@ void Init_io_spec(void) {
rb_define_method(cls, "rb_io_taint_check", io_spec_rb_io_taint_check, 1);
rb_define_method(cls, "rb_io_wait_readable", io_spec_rb_io_wait_readable, 2);
rb_define_method(cls, "rb_io_wait_writable", io_spec_rb_io_wait_writable, 1);
-#ifdef RUBY_VERSION_IS_3_1
- rb_define_method(cls, "rb_io_maybe_wait_writable", io_spec_rb_io_maybe_wait_writable, 3);
- rb_define_method(cls, "rb_io_maybe_wait_readable", io_spec_rb_io_maybe_wait_readable, 4);
- rb_define_method(cls, "rb_io_maybe_wait", io_spec_rb_io_maybe_wait, 4);
-#endif
rb_define_method(cls, "rb_thread_wait_fd", io_spec_rb_thread_wait_fd, 1);
rb_define_method(cls, "rb_thread_fd_writable", io_spec_rb_thread_fd_writable, 1);
rb_define_method(cls, "rb_thread_fd_select_read", io_spec_rb_thread_fd_select_read, 1);
@@ -406,10 +305,6 @@ void Init_io_spec(void) {
rb_define_method(cls, "rb_cloexec_open", io_spec_rb_cloexec_open, 3);
rb_define_method(cls, "errno=", io_spec_errno_set, 1);
rb_define_method(cls, "rb_io_mode_sync_flag", io_spec_mode_sync_flag, 1);
-#if defined(RUBY_VERSION_IS_3_3) || defined(TRUFFLERUBY)
- rb_define_method(cls, "rb_io_mode", io_spec_rb_io_mode, 1);
- rb_define_method(cls, "rb_io_path", io_spec_rb_io_path, 1);
-#endif
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c
index 04252b2848..e194ba8fde 100644
--- a/spec/ruby/optional/capi/ext/kernel_spec.c
+++ b/spec/ruby/optional/capi/ext/kernel_spec.c
@@ -220,8 +220,8 @@ static VALUE kernel_spec_rb_eval_string_protect(VALUE self, VALUE str, VALUE ary
VALUE kernel_spec_rb_sys_fail(VALUE self, VALUE msg) {
errno = 1;
- if (msg == Qnil) {
- rb_sys_fail(NULL);
+ if(msg == Qnil) {
+ rb_sys_fail(0);
} else if (self != Qundef) {
rb_sys_fail(StringValuePtr(msg));
}
@@ -229,7 +229,7 @@ VALUE kernel_spec_rb_sys_fail(VALUE self, VALUE msg) {
}
VALUE kernel_spec_rb_syserr_fail(VALUE self, VALUE err, VALUE msg) {
- if (msg == Qnil) {
+ if(msg == Qnil) {
rb_syserr_fail(NUM2INT(err), NULL);
} else if (self != Qundef) {
rb_syserr_fail(NUM2INT(err), StringValuePtr(msg));
@@ -292,9 +292,9 @@ static VALUE kernel_spec_rb_yield_values2(VALUE self, VALUE ary) {
}
static VALUE do_rec(VALUE obj, VALUE arg, int is_rec) {
- if (is_rec) {
+ if(is_rec) {
return obj;
- } else if (arg == Qtrue) {
+ } else if(arg == Qtrue) {
return rb_exec_recursive(do_rec, obj, Qnil);
} else {
return Qnil;
@@ -340,12 +340,8 @@ static VALUE kernel_spec_rb_funcallv_public(VALUE self, VALUE obj, VALUE method)
return rb_funcallv_public(obj, SYM2ID(method), 0, NULL);
}
-static VALUE kernel_spec_rb_funcall_with_block(VALUE self, VALUE obj, VALUE method, VALUE args, VALUE block) {
- return rb_funcall_with_block(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args), block);
-}
-
-static VALUE kernel_spec_rb_funcall_with_block_kw(VALUE self, VALUE obj, VALUE method, VALUE args, VALUE block) {
- return rb_funcall_with_block_kw(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args), block, RB_PASS_KEYWORDS);
+static VALUE kernel_spec_rb_funcall_with_block(VALUE self, VALUE obj, VALUE method, VALUE block) {
+ return rb_funcall_with_block(obj, SYM2ID(method), 0, NULL, block);
}
static VALUE kernel_spec_rb_funcall_many_args(VALUE self, VALUE obj, VALUE method) {
@@ -355,15 +351,6 @@ static VALUE kernel_spec_rb_funcall_many_args(VALUE self, VALUE obj, VALUE metho
INT2FIX(5), INT2FIX(4), INT2FIX(3), INT2FIX(2), INT2FIX(1));
}
-static VALUE kernel_spec_rb_check_funcall(VALUE self, VALUE receiver, VALUE method, VALUE args) {
- VALUE ret = rb_check_funcall(receiver, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args));
- if (ret == Qundef) {
- return ID2SYM(rb_intern("Qundef"));
- } else {
- return ret;
- }
-}
-
void Init_kernel_spec(void) {
VALUE cls = rb_define_class("CApiKernelSpecs", rb_cObject);
rb_define_method(cls, "rb_block_given_p", kernel_spec_rb_block_given_p, 0);
@@ -410,9 +397,7 @@ void Init_kernel_spec(void) {
#endif
rb_define_method(cls, "rb_funcallv_public", kernel_spec_rb_funcallv_public, 2);
rb_define_method(cls, "rb_funcall_many_args", kernel_spec_rb_funcall_many_args, 2);
- rb_define_method(cls, "rb_funcall_with_block", kernel_spec_rb_funcall_with_block, 4);
- rb_define_method(cls, "rb_funcall_with_block_kw", kernel_spec_rb_funcall_with_block_kw, 4);
- rb_define_method(cls, "rb_check_funcall", kernel_spec_rb_check_funcall, 3);
+ rb_define_method(cls, "rb_funcall_with_block", kernel_spec_rb_funcall_with_block, 3);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/object_spec.c b/spec/ruby/optional/capi/ext/object_spec.c
index aa60662e1e..30ac44cf1f 100644
--- a/spec/ruby/optional/capi/ext/object_spec.c
+++ b/spec/ruby/optional/capi/ext/object_spec.c
@@ -154,12 +154,30 @@ static VALUE object_specs_rb_obj_method(VALUE self, VALUE obj, VALUE method) {
return rb_obj_method(obj, method);
}
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wdeprecated-declarations")
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+# endif
+#endif
+
#ifndef RUBY_VERSION_IS_3_2
static VALUE object_spec_rb_obj_taint(VALUE self, VALUE obj) {
return rb_obj_taint(obj);
}
#endif
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+# pragma GCC diagnostic pop
+#elif defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wdeprecated-declarations")
+# pragma clang diagnostic pop
+# endif
+#endif
+
static VALUE so_require(VALUE self) {
rb_require("fixtures/foo");
return Qnil;
@@ -179,7 +197,11 @@ static VALUE object_spec_rb_method_boundp(VALUE self, VALUE obj, VALUE method, V
}
static VALUE object_spec_rb_special_const_p(VALUE self, VALUE value) {
- return rb_special_const_p(value);
+ if (rb_special_const_p(value)) {
+ return Qtrue;
+ } else {
+ return Qfalse;
+ }
}
static VALUE so_to_id(VALUE self, VALUE obj) {
@@ -196,126 +218,126 @@ static VALUE so_check_type(VALUE self, VALUE obj, VALUE other) {
}
static VALUE so_is_type_nil(VALUE self, VALUE obj) {
- if (TYPE(obj) == T_NIL) {
+ if(TYPE(obj) == T_NIL) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_type_object(VALUE self, VALUE obj) {
- if (TYPE(obj) == T_OBJECT) {
+ if(TYPE(obj) == T_OBJECT) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_type_array(VALUE self, VALUE obj) {
- if (TYPE(obj) == T_ARRAY) {
+ if(TYPE(obj) == T_ARRAY) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_type_module(VALUE self, VALUE obj) {
- if (TYPE(obj) == T_MODULE) {
+ if(TYPE(obj) == T_MODULE) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_type_class(VALUE self, VALUE obj) {
- if (TYPE(obj) == T_CLASS) {
+ if(TYPE(obj) == T_CLASS) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_type_data(VALUE self, VALUE obj) {
- if (TYPE(obj) == T_DATA) {
+ if(TYPE(obj) == T_DATA) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_rb_type_p_nil(VALUE self, VALUE obj) {
- if (rb_type_p(obj, T_NIL)) {
+ if(rb_type_p(obj, T_NIL)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_rb_type_p_object(VALUE self, VALUE obj) {
- if (rb_type_p(obj, T_OBJECT)) {
+ if(rb_type_p(obj, T_OBJECT)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_rb_type_p_array(VALUE self, VALUE obj) {
- if (rb_type_p(obj, T_ARRAY)) {
+ if(rb_type_p(obj, T_ARRAY)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_rb_type_p_module(VALUE self, VALUE obj) {
- if (rb_type_p(obj, T_MODULE)) {
+ if(rb_type_p(obj, T_MODULE)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_rb_type_p_class(VALUE self, VALUE obj) {
- if (rb_type_p(obj, T_CLASS)) {
+ if(rb_type_p(obj, T_CLASS)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_rb_type_p_data(VALUE self, VALUE obj) {
- if (rb_type_p(obj, T_DATA)) {
+ if(rb_type_p(obj, T_DATA)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_rb_type_p_file(VALUE self, VALUE obj) {
- if (rb_type_p(obj, T_FILE)) {
+ if(rb_type_p(obj, T_FILE)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_builtin_type_object(VALUE self, VALUE obj) {
- if (BUILTIN_TYPE(obj) == T_OBJECT) {
+ if(BUILTIN_TYPE(obj) == T_OBJECT) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_builtin_type_array(VALUE self, VALUE obj) {
- if (BUILTIN_TYPE(obj) == T_ARRAY) {
+ if(BUILTIN_TYPE(obj) == T_ARRAY) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_builtin_type_module(VALUE self, VALUE obj) {
- if (BUILTIN_TYPE(obj) == T_MODULE) {
+ if(BUILTIN_TYPE(obj) == T_MODULE) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_builtin_type_class(VALUE self, VALUE obj) {
- if (BUILTIN_TYPE(obj) == T_CLASS) {
+ if(BUILTIN_TYPE(obj) == T_CLASS) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_builtin_type_data(VALUE self, VALUE obj) {
- if (BUILTIN_TYPE(obj) == T_DATA) {
+ if(BUILTIN_TYPE(obj) == T_DATA) {
return Qtrue;
}
return Qfalse;
@@ -384,28 +406,36 @@ static VALUE object_spec_rb_ivar_foreach(VALUE self, VALUE obj) {
}
static VALUE speced_allocator(VALUE klass) {
- VALUE super = rb_class_get_superclass(klass);
- VALUE instance = rb_get_alloc_func(super)(klass);
+ VALUE flags = 0;
+ VALUE instance;
+ if (RTEST(rb_class_inherited_p(klass, rb_cString))) {
+ flags = T_STRING;
+ } else if (RTEST(rb_class_inherited_p(klass, rb_cArray))) {
+ flags = T_ARRAY;
+ } else {
+ flags = T_OBJECT;
+ }
+ instance = rb_newobj_of(klass, flags);
rb_iv_set(instance, "@from_custom_allocator", Qtrue);
return instance;
}
-static VALUE object_spec_rb_define_alloc_func(VALUE self, VALUE klass) {
+static VALUE define_alloc_func(VALUE self, VALUE klass) {
rb_define_alloc_func(klass, speced_allocator);
return Qnil;
}
-static VALUE object_spec_rb_undef_alloc_func(VALUE self, VALUE klass) {
+static VALUE undef_alloc_func(VALUE self, VALUE klass) {
rb_undef_alloc_func(klass);
return Qnil;
}
-static VALUE object_spec_speced_allocator_p(VALUE self, VALUE klass) {
+static VALUE speced_allocator_p(VALUE self, VALUE klass) {
rb_alloc_func_t allocator = rb_get_alloc_func(klass);
return (allocator == speced_allocator) ? Qtrue : Qfalse;
}
-static VALUE object_spec_custom_alloc_func_p(VALUE self, VALUE klass) {
+static VALUE custom_alloc_func_p(VALUE self, VALUE klass) {
rb_alloc_func_t allocator = rb_get_alloc_func(klass);
return allocator ? Qtrue : Qfalse;
}
@@ -485,10 +515,10 @@ void Init_object_spec(void) {
rb_define_method(cls, "rb_ivar_defined", object_spec_rb_ivar_defined, 2);
rb_define_method(cls, "rb_copy_generic_ivar", object_spec_rb_copy_generic_ivar, 2);
rb_define_method(cls, "rb_free_generic_ivar", object_spec_rb_free_generic_ivar, 1);
- rb_define_method(cls, "rb_define_alloc_func", object_spec_rb_define_alloc_func, 1);
- rb_define_method(cls, "rb_undef_alloc_func", object_spec_rb_undef_alloc_func, 1);
- rb_define_method(cls, "speced_allocator?", object_spec_speced_allocator_p, 1);
- rb_define_method(cls, "custom_alloc_func?", object_spec_custom_alloc_func_p, 1);
+ rb_define_method(cls, "rb_define_alloc_func", define_alloc_func, 1);
+ rb_define_method(cls, "rb_undef_alloc_func", undef_alloc_func, 1);
+ rb_define_method(cls, "speced_allocator?", speced_allocator_p, 1);
+ rb_define_method(cls, "custom_alloc_func?", custom_alloc_func_p, 1);
rb_define_method(cls, "not_implemented_method", rb_f_notimplement, -1);
rb_define_method(cls, "rb_ivar_foreach", object_spec_rb_ivar_foreach, 1);
}
diff --git a/spec/ruby/optional/capi/ext/proc_spec.c b/spec/ruby/optional/capi/ext/proc_spec.c
index b7cd5d6262..1137f4156b 100644
--- a/spec/ruby/optional/capi/ext/proc_spec.c
+++ b/spec/ruby/optional/capi/ext/proc_spec.c
@@ -76,18 +76,6 @@ VALUE proc_spec_rb_proc_call(VALUE self, VALUE prc, VALUE args) {
return rb_proc_call(prc, args);
}
-VALUE proc_spec_rb_proc_call_kw(VALUE self, VALUE prc, VALUE args) {
- return rb_proc_call_kw(prc, args, RB_PASS_KEYWORDS);
-}
-
-VALUE proc_spec_rb_proc_call_with_block(VALUE self, VALUE prc, VALUE args, VALUE block) {
- return rb_proc_call_with_block(prc, RARRAY_LENINT(args), RARRAY_PTR(args), block);
-}
-
-static VALUE proc_spec_rb_proc_call_with_block_kw(VALUE self, VALUE prc, VALUE args, VALUE block) {
- return rb_proc_call_with_block_kw(prc, RARRAY_LENINT(args), RARRAY_PTR(args), block, RB_PASS_KEYWORDS);
-}
-
VALUE proc_spec_rb_obj_is_proc(VALUE self, VALUE prc) {
return rb_obj_is_proc(prc);
}
@@ -135,9 +123,6 @@ void Init_proc_spec(void) {
rb_define_method(cls, "rb_proc_new_block_given_p", proc_spec_rb_proc_new_block_given_p, 0);
rb_define_method(cls, "rb_proc_arity", proc_spec_rb_proc_arity, 1);
rb_define_method(cls, "rb_proc_call", proc_spec_rb_proc_call, 2);
- rb_define_method(cls, "rb_proc_call_kw", proc_spec_rb_proc_call_kw, 2);
- rb_define_method(cls, "rb_proc_call_with_block", proc_spec_rb_proc_call_with_block, 3);
- rb_define_method(cls, "rb_proc_call_with_block_kw", proc_spec_rb_proc_call_with_block_kw, 3);
rb_define_method(cls, "rb_Proc_new", proc_spec_rb_Proc_new, 1);
rb_define_method(cls, "rb_obj_is_proc", proc_spec_rb_obj_is_proc, 1);
}
diff --git a/spec/ruby/optional/capi/ext/range_spec.c b/spec/ruby/optional/capi/ext/range_spec.c
index b0cf1a8662..7a475ec695 100644
--- a/spec/ruby/optional/capi/ext/range_spec.c
+++ b/spec/ruby/optional/capi/ext/range_spec.c
@@ -7,7 +7,7 @@ extern "C" {
VALUE range_spec_rb_range_new(int argc, VALUE* argv, VALUE self) {
int exclude_end = 0;
- if (argc == 3) {
+ if(argc == 3) {
exclude_end = RTEST(argv[2]);
}
return rb_range_new(argv[0], argv[1], exclude_end);
diff --git a/spec/ruby/optional/capi/ext/rbasic_spec.c b/spec/ruby/optional/capi/ext/rbasic_spec.c
index 26be2fed6d..9178e5f639 100644
--- a/spec/ruby/optional/capi/ext/rbasic_spec.c
+++ b/spec/ruby/optional/capi/ext/rbasic_spec.c
@@ -5,14 +5,6 @@
extern "C" {
#endif
-#ifndef RBASIC_FLAGS
-#define RBASIC_FLAGS(obj) (RBASIC(obj)->flags)
-#endif
-
-#ifndef RBASIC_SET_FLAGS
-#define RBASIC_SET_FLAGS(obj, flags_to_set) (RBASIC(obj)->flags = flags_to_set)
-#endif
-
#ifndef FL_SHAREABLE
static const VALUE VISIBLE_BITS = FL_TAINT | FL_FREEZE;
static const VALUE DATA_VISIBLE_BITS = FL_TAINT | FL_FREEZE | ~(FL_USER0 - 1);
@@ -42,53 +34,47 @@ VALUE rbasic_spec_freeze_flag(VALUE self) {
return VALUE2NUM(RUBY_FL_FREEZE);
}
-static VALUE spec_get_flags(VALUE obj, VALUE visible_bits) {
- VALUE flags = RB_FL_TEST(obj, visible_bits);
+ static VALUE spec_get_flags(const struct RBasic *b, VALUE visible_bits) {
+ VALUE flags = b->flags & visible_bits;
return VALUE2NUM(flags);
}
-static VALUE spec_set_flags(VALUE obj, VALUE flags, VALUE visible_bits) {
+static VALUE spec_set_flags(struct RBasic *b, VALUE flags, VALUE visible_bits) {
flags &= visible_bits;
-
- // Could also be done like:
- // RB_FL_UNSET(obj, visible_bits);
- // RB_FL_SET(obj, flags);
- // But that seems rather indirect
- RBASIC_SET_FLAGS(obj, (RBASIC_FLAGS(obj) & ~visible_bits) | flags);
-
+ b->flags = (b->flags & ~visible_bits) | flags;
return VALUE2NUM(flags);
}
-static VALUE rbasic_spec_get_flags(VALUE self, VALUE obj) {
- return spec_get_flags(obj, VISIBLE_BITS);
+VALUE rbasic_spec_get_flags(VALUE self, VALUE val) {
+ return spec_get_flags(RBASIC(val), VISIBLE_BITS);
}
-static VALUE rbasic_spec_set_flags(VALUE self, VALUE obj, VALUE flags) {
- return spec_set_flags(obj, NUM2VALUE(flags), VISIBLE_BITS);
+VALUE rbasic_spec_set_flags(VALUE self, VALUE val, VALUE flags) {
+ return spec_set_flags(RBASIC(val), NUM2VALUE(flags), VISIBLE_BITS);
}
-static VALUE rbasic_spec_copy_flags(VALUE self, VALUE to, VALUE from) {
- return spec_set_flags(to, RBASIC_FLAGS(from), VISIBLE_BITS);
+VALUE rbasic_spec_copy_flags(VALUE self, VALUE to, VALUE from) {
+ return spec_set_flags(RBASIC(to), RBASIC(from)->flags, VISIBLE_BITS);
}
-static VALUE rbasic_spec_get_klass(VALUE self, VALUE obj) {
- return RBASIC_CLASS(obj);
+VALUE rbasic_spec_get_klass(VALUE self, VALUE val) {
+ return RBASIC(val)->klass;
}
-static VALUE rbasic_rdata_spec_get_flags(VALUE self, VALUE structure) {
- return spec_get_flags(structure, DATA_VISIBLE_BITS);
+VALUE rbasic_rdata_spec_get_flags(VALUE self, VALUE structure) {
+ return spec_get_flags(&RDATA(structure)->basic, DATA_VISIBLE_BITS);
}
-static VALUE rbasic_rdata_spec_set_flags(VALUE self, VALUE structure, VALUE flags) {
- return spec_set_flags(structure, NUM2VALUE(flags), DATA_VISIBLE_BITS);
+VALUE rbasic_rdata_spec_set_flags(VALUE self, VALUE structure, VALUE flags) {
+ return spec_set_flags(&RDATA(structure)->basic, NUM2VALUE(flags), DATA_VISIBLE_BITS);
}
-static VALUE rbasic_rdata_spec_copy_flags(VALUE self, VALUE to, VALUE from) {
- return spec_set_flags(to, RBASIC_FLAGS(from), DATA_VISIBLE_BITS);
+VALUE rbasic_rdata_spec_copy_flags(VALUE self, VALUE to, VALUE from) {
+ return spec_set_flags(&RDATA(to)->basic, RDATA(from)->basic.flags, DATA_VISIBLE_BITS);
}
-static VALUE rbasic_rdata_spec_get_klass(VALUE self, VALUE structure) {
- return RBASIC_CLASS(structure);
+VALUE rbasic_rdata_spec_get_klass(VALUE self, VALUE structure) {
+ return RDATA(structure)->basic.klass;
}
void Init_rbasic_spec(void) {
diff --git a/spec/ruby/optional/capi/ext/rubyspec.h b/spec/ruby/optional/capi/ext/rubyspec.h
index 1df274ead1..245669d200 100644
--- a/spec/ruby/optional/capi/ext/rubyspec.h
+++ b/spec/ruby/optional/capi/ext/rubyspec.h
@@ -11,29 +11,6 @@
# include <version.h>
#endif
-/* copied from ext/-test-/cxxanyargs/cxxanyargs.cpp */
-#if 0 /* Ignore deprecation warnings */
-
-#elif defined(_MSC_VER)
-#pragma warning(disable : 4996)
-
-#elif defined(__INTEL_COMPILER)
-#pragma warning(disable : 1786)
-
-#elif defined(__clang__)
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-
-#elif defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-
-#elif defined(__SUNPRO_CC)
-#pragma error_messages (off,symdeprecated)
-
-#else
-// :FIXME: improve here for your compiler.
-
-#endif
-
#ifndef RUBY_VERSION_MAJOR
#define RUBY_VERSION_MAJOR RUBY_API_VERSION_MAJOR
#define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
@@ -44,25 +21,16 @@
((RUBY_VERSION_MAJOR < (major)) || \
(RUBY_VERSION_MAJOR == (major) && RUBY_VERSION_MINOR < (minor)) || \
(RUBY_VERSION_MAJOR == (major) && RUBY_VERSION_MINOR == (minor) && RUBY_VERSION_TEENY < (teeny)))
-#define RUBY_VERSION_SINCE(major,minor,teeny) (!RUBY_VERSION_BEFORE(major, minor, teeny))
-
-#if RUBY_VERSION_SINCE(3, 4, 0)
-#define RUBY_VERSION_IS_3_4
-#endif
-
-#if RUBY_VERSION_SINCE(3, 3, 0)
-#define RUBY_VERSION_IS_3_3
-#endif
-#if RUBY_VERSION_SINCE(3, 2, 0)
+#if RUBY_VERSION_MAJOR > 3 || (RUBY_VERSION_MAJOR == 3 && RUBY_VERSION_MINOR >= 2)
#define RUBY_VERSION_IS_3_2
#endif
-#if RUBY_VERSION_SINCE(3, 1, 0)
+#if RUBY_VERSION_MAJOR > 3 || (RUBY_VERSION_MAJOR == 3 && RUBY_VERSION_MINOR >= 1)
#define RUBY_VERSION_IS_3_1
#endif
-#if RUBY_VERSION_SINCE(3, 0, 0)
+#if RUBY_VERSION_MAJOR > 3 || (RUBY_VERSION_MAJOR == 3 && RUBY_VERSION_MINOR >= 0)
#define RUBY_VERSION_IS_3_0
#endif
diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c
index cec3f65f45..a858936243 100644
--- a/spec/ruby/optional/capi/ext/string_spec.c
+++ b/spec/ruby/optional/capi/ext/string_spec.c
@@ -51,12 +51,18 @@ VALUE string_spec_rb_str_set_len_RSTRING_LEN(VALUE self, VALUE str, VALUE len) {
return INT2FIX(RSTRING_LEN(str));
}
+VALUE rb_fstring(VALUE str); /* internal.h, used in ripper */
+
+VALUE string_spec_rb_str_fstring(VALUE self, VALUE str) {
+ return rb_fstring(str);
+}
+
VALUE string_spec_rb_str_buf_new(VALUE self, VALUE len, VALUE str) {
VALUE buf;
buf = rb_str_buf_new(NUM2LONG(len));
- if (RTEST(str)) {
+ if(RTEST(str)) {
snprintf(RSTRING_PTR(buf), NUM2LONG(len), "%s", RSTRING_PTR(str));
}
@@ -123,7 +129,7 @@ VALUE string_spec_rb_str_conv_enc(VALUE self, VALUE str, VALUE from, VALUE to) {
from_enc = rb_to_encoding(from);
- if (NIL_P(to)) {
+ if(NIL_P(to)) {
to_enc = 0;
} else {
to_enc = rb_to_encoding(to);
@@ -133,13 +139,14 @@ VALUE string_spec_rb_str_conv_enc(VALUE self, VALUE str, VALUE from, VALUE to) {
}
VALUE string_spec_rb_str_conv_enc_opts(VALUE self, VALUE str, VALUE from, VALUE to,
- VALUE ecflags, VALUE ecopts) {
+ VALUE ecflags, VALUE ecopts)
+{
rb_encoding* from_enc;
rb_encoding* to_enc;
from_enc = rb_to_encoding(from);
- if (NIL_P(to)) {
+ if(NIL_P(to)) {
to_enc = 0;
} else {
to_enc = rb_to_encoding(to);
@@ -193,7 +200,7 @@ VALUE string_spec_rb_str_new_offset(VALUE self, VALUE str, VALUE offset, VALUE l
}
VALUE string_spec_rb_str_new2(VALUE self, VALUE str) {
- if (NIL_P(str)) {
+ if(NIL_P(str)) {
return rb_str_new2("");
} else {
return rb_str_new2(RSTRING_PTR(str));
@@ -209,7 +216,7 @@ VALUE string_spec_rb_str_export_to_enc(VALUE self, VALUE str, VALUE enc) {
}
VALUE string_spec_rb_str_new_cstr(VALUE self, VALUE str) {
- if (NIL_P(str)) {
+ if(NIL_P(str)) {
return rb_str_new_cstr("");
} else {
return rb_str_new_cstr(RSTRING_PTR(str));
@@ -248,6 +255,16 @@ VALUE string_spec_rb_str_new5(VALUE self, VALUE str, VALUE ptr, VALUE len) {
return rb_str_new5(str, RSTRING_PTR(ptr), FIX2INT(len));
}
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#elif defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wdeprecated-declarations")
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated-declarations"
+# endif
+#endif
+
#ifndef RUBY_VERSION_IS_3_2
VALUE string_spec_rb_tainted_str_new(VALUE self, VALUE str, VALUE len) {
return rb_tainted_str_new(RSTRING_PTR(str), FIX2INT(len));
@@ -258,6 +275,14 @@ VALUE string_spec_rb_tainted_str_new2(VALUE self, VALUE str) {
}
#endif
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+# pragma GCC diagnostic pop
+#elif defined(__clang__) && defined(__has_warning)
+# if __has_warning("-Wdeprecated-declarations")
+# pragma clang diagnostic pop
+# endif
+#endif
+
VALUE string_spec_rb_str_plus(VALUE self, VALUE str1, VALUE str2) {
return rb_str_plus(str1, str2);
}
@@ -365,7 +390,7 @@ VALUE string_spec_RSTRING_PTR_set(VALUE self, VALUE str, VALUE i, VALUE chr) {
VALUE string_spec_RSTRING_PTR_after_funcall(VALUE self, VALUE str, VALUE cb) {
/* Silence gcc 4.3.2 warning about computed value not used */
- if (RSTRING_PTR(str)) { /* force it out */
+ if(RSTRING_PTR(str)) { /* force it out */
rb_funcall(cb, rb_intern("call"), 1, str);
}
@@ -548,7 +573,7 @@ static VALUE string_spec_rb_utf8_str_new_cstr(VALUE self) {
}
PRINTF_ARGS(static VALUE call_rb_str_vcatf(VALUE mesg, const char *fmt, ...), 2, 3);
-static VALUE call_rb_str_vcatf(VALUE mesg, const char *fmt, ...) {
+static VALUE call_rb_str_vcatf(VALUE mesg, const char *fmt, ...){
va_list ap;
va_start(ap, fmt);
VALUE result = rb_str_vcatf(mesg, fmt, ap);
@@ -572,6 +597,9 @@ static VALUE string_spec_rb_str_unlocktmp(VALUE self, VALUE str) {
return rb_str_unlocktmp(str);
}
+VALUE rb_str_to_interned_str(VALUE str);
+VALUE rb_enc_interned_str_cstr(const char *ptr, rb_encoding *enc);
+
static VALUE string_spec_rb_enc_interned_str_cstr(VALUE self, VALUE str, VALUE enc) {
rb_encoding *e = NIL_P(enc) ? 0 : rb_to_encoding(enc);
return rb_enc_interned_str_cstr(RSTRING_PTR(str), e);
@@ -585,6 +613,7 @@ void Init_string_spec(void) {
VALUE cls = rb_define_class("CApiStringSpecs", rb_cObject);
rb_define_method(cls, "rb_cstr2inum", string_spec_rb_cstr2inum, 2);
rb_define_method(cls, "rb_cstr_to_inum", string_spec_rb_cstr_to_inum, 3);
+ rb_define_method(cls, "rb_fstring", string_spec_rb_str_fstring, 1);
rb_define_method(cls, "rb_str2inum", string_spec_rb_str2inum, 2);
rb_define_method(cls, "rb_str_append", string_spec_rb_str_append, 2);
rb_define_method(cls, "rb_str_buf_new", string_spec_rb_str_buf_new, 2);
diff --git a/spec/ruby/optional/capi/ext/struct_spec.c b/spec/ruby/optional/capi/ext/struct_spec.c
index 9c45bd5672..0393d6937d 100644
--- a/spec/ruby/optional/capi/ext/struct_spec.c
+++ b/spec/ruby/optional/capi/ext/struct_spec.c
@@ -15,11 +15,13 @@ static VALUE struct_spec_rb_struct_getmember(VALUE self, VALUE st, VALUE key) {
return rb_struct_getmember(st, SYM2ID(key));
}
-static VALUE struct_spec_rb_struct_s_members(VALUE self, VALUE klass) {
+static VALUE struct_spec_rb_struct_s_members(VALUE self, VALUE klass)
+{
return rb_ary_dup(rb_struct_s_members(klass));
}
-static VALUE struct_spec_rb_struct_members(VALUE self, VALUE st) {
+static VALUE struct_spec_rb_struct_members(VALUE self, VALUE st)
+{
return rb_ary_dup(rb_struct_members(st));
}
@@ -54,11 +56,14 @@ static VALUE struct_spec_struct_define_under(VALUE self, VALUE outer,
}
static VALUE struct_spec_rb_struct_new(VALUE self, VALUE klass,
- VALUE a, VALUE b, VALUE c) {
+ VALUE a, VALUE b, VALUE c)
+{
+
return rb_struct_new(klass, a, b, c);
}
-static VALUE struct_spec_rb_struct_size(VALUE self, VALUE st) {
+static VALUE struct_spec_rb_struct_size(VALUE self, VALUE st)
+{
return rb_struct_size(st);
}
diff --git a/spec/ruby/optional/capi/ext/thread_spec.c b/spec/ruby/optional/capi/ext/thread_spec.c
index 3511c2fbcf..be812d796f 100644
--- a/spec/ruby/optional/capi/ext/thread_spec.c
+++ b/spec/ruby/optional/capi/ext/thread_spec.c
@@ -8,10 +8,7 @@
#include <unistd.h>
#endif
#if defined(_WIN32)
-#include "ruby/win32.h"
-#define read rb_w32_read
-#define write rb_w32_write
-#define pipe rb_w32_pipe
+#define pipe(p) rb_w32_pipe(p)
#endif
#ifndef _WIN32
@@ -26,6 +23,10 @@ static VALUE thread_spec_rb_thread_alone(VALUE self) {
return rb_thread_alone() ? Qtrue : Qfalse;
}
+#if defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
/* This is unblocked by unblock_func(). */
static void* blocking_gvl_func(void* data) {
int rfd = *(int *)data;
@@ -67,7 +68,7 @@ static VALUE thread_spec_rb_thread_call_without_gvl(VALUE self) {
}
/* This is unblocked by a signal. */
-static void* blocking_gvl_func_for_ubf_io(void *data) {
+static void* blocking_gvl_func_for_udf_io(void *data) {
int rfd = (int)(size_t)data;
char dummy;
@@ -87,7 +88,7 @@ static VALUE thread_spec_rb_thread_call_without_gvl_with_ubf_io(VALUE self) {
rb_raise(rb_eRuntimeError, "could not create pipe");
}
- ret = rb_thread_call_without_gvl(blocking_gvl_func_for_ubf_io,
+ ret = rb_thread_call_without_gvl(blocking_gvl_func_for_udf_io,
(void*)(size_t)fds[0], RUBY_UBF_IO, 0);
close(fds[0]);
close(fds[1]);
diff --git a/spec/ruby/optional/capi/ext/tracepoint_spec.c b/spec/ruby/optional/capi/ext/tracepoint_spec.c
index 6666c8f85c..78c459d6cb 100644
--- a/spec/ruby/optional/capi/ext/tracepoint_spec.c
+++ b/spec/ruby/optional/capi/ext/tracepoint_spec.c
@@ -17,7 +17,7 @@ static VALUE tracepoint_spec_rb_tracepoint_new(VALUE self, VALUE data) {
return rb_tracepoint_new(Qnil, RUBY_EVENT_LINE, callback, (void*) data);
}
-static VALUE tracepoint_spec_callback_called(VALUE self) {
+static VALUE tracepoint_spec_callback_called(VALUE self){
return callback_called;
}
diff --git a/spec/ruby/optional/capi/ext/typed_data_spec.c b/spec/ruby/optional/capi/ext/typed_data_spec.c
index 221f1c8ac4..eca2b667cc 100644
--- a/spec/ruby/optional/capi/ext/typed_data_spec.c
+++ b/spec/ruby/optional/capi/ext/typed_data_spec.c
@@ -106,14 +106,6 @@ VALUE sws_typed_wrap_struct(VALUE self, VALUE val) {
return TypedData_Wrap_Struct(rb_cObject, &sample_typed_wrapped_struct_data_type, bar);
}
-#undef RUBY_UNTYPED_DATA_WARNING
-#define RUBY_UNTYPED_DATA_WARNING 0
-VALUE sws_untyped_wrap_struct(VALUE self, VALUE val) {
- int* data = (int*) malloc(sizeof(int));
- *data = FIX2INT(val);
- return Data_Wrap_Struct(rb_cObject, NULL, free, data);
-}
-
VALUE sws_typed_get_struct(VALUE self, VALUE obj) {
struct sample_typed_wrapped_struct* bar;
TypedData_Get_Struct(obj, struct sample_typed_wrapped_struct, &sample_typed_wrapped_struct_data_type, bar);
@@ -173,17 +165,12 @@ VALUE sws_typed_rb_check_typeddata_different_type(VALUE self, VALUE obj) {
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_other_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
}
-VALUE sws_typed_RTYPEDDATA_P(VALUE self, VALUE obj) {
- return RTYPEDDATA_P(obj) ? Qtrue : Qfalse;
-}
-
void Init_typed_data_spec(void) {
VALUE cls = rb_define_class("CApiAllocTypedSpecs", rb_cObject);
rb_define_alloc_func(cls, sdaf_alloc_typed_func);
rb_define_method(cls, "typed_wrapped_data", sdaf_typed_get_struct, 0);
cls = rb_define_class("CApiWrappedTypedStructSpecs", rb_cObject);
rb_define_method(cls, "typed_wrap_struct", sws_typed_wrap_struct, 1);
- rb_define_method(cls, "untyped_wrap_struct", sws_untyped_wrap_struct, 1);
rb_define_method(cls, "typed_get_struct", sws_typed_get_struct, 1);
rb_define_method(cls, "typed_get_struct_other", sws_typed_get_struct_different_type, 1);
rb_define_method(cls, "typed_get_struct_parent", sws_typed_get_struct_parent_type, 1);
@@ -194,7 +181,6 @@ void Init_typed_data_spec(void) {
rb_define_method(cls, "rb_check_typeddata_same_type", sws_typed_rb_check_typeddata_same_type, 1);
rb_define_method(cls, "rb_check_typeddata_same_type_parent", sws_typed_rb_check_typeddata_same_type_parent, 1);
rb_define_method(cls, "rb_check_typeddata_different_type", sws_typed_rb_check_typeddata_different_type, 1);
- rb_define_method(cls, "RTYPEDDATA_P", sws_typed_RTYPEDDATA_P, 1);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/util_spec.c b/spec/ruby/optional/capi/ext/util_spec.c
index b5bde420d2..95ba71ea9d 100644
--- a/spec/ruby/optional/capi/ext/util_spec.c
+++ b/spec/ruby/optional/capi/ext/util_spec.c
@@ -62,17 +62,22 @@ static VALUE util_spec_rb_get_kwargs(VALUE self, VALUE keyword_hash, VALUE keys,
int len = RARRAY_LENINT(keys);
int values_len = req + (opt < 0 ? -1 - opt : opt);
+ int i = 0;
- ID *ids = (ID *)alloca(sizeof(VALUE) * len);
- VALUE *results = (VALUE *)alloca(sizeof(VALUE) * values_len);
+ ID *ids = (ID*) malloc(sizeof(VALUE) * len);
+ VALUE *results = (VALUE*) malloc(sizeof(VALUE) * values_len);
+ int extracted = 0;
+ VALUE ary = Qundef;
- for (int i = 0; i < len; i++) {
+ for (i = 0; i < len; i++) {
ids[i] = SYM2ID(rb_ary_entry(keys, i));
}
- int extracted = rb_get_kwargs(keyword_hash, ids, req, opt, results);
-
- return rb_ary_new_from_values(extracted, results);
+ extracted = rb_get_kwargs(keyword_hash, ids, req, opt, results);
+ ary = rb_ary_new_from_values(extracted, results);
+ free(results);
+ free(ids);
+ return ary;
}
static VALUE util_spec_rb_long2int(VALUE self, VALUE n) {
diff --git a/spec/ruby/optional/capi/file_spec.rb b/spec/ruby/optional/capi/file_spec.rb
index 12449b4e34..96d731e4fa 100644
--- a/spec/ruby/optional/capi/file_spec.rb
+++ b/spec/ruby/optional/capi/file_spec.rb
@@ -69,7 +69,7 @@ describe "C-API File function" do
end
it "does not call #to_str on a String" do
- obj = +"path"
+ obj = "path"
obj.should_not_receive(:to_str)
@s.FilePathValue(obj).should eql(obj)
end
diff --git a/spec/ruby/optional/capi/fixnum_spec.rb b/spec/ruby/optional/capi/fixnum_spec.rb
index e691aa3893..aa02a0543b 100644
--- a/spec/ruby/optional/capi/fixnum_spec.rb
+++ b/spec/ruby/optional/capi/fixnum_spec.rb
@@ -25,7 +25,7 @@ describe "CApiFixnumSpecs" do
end
end
- platform_is c_long_size: 64 do # sizeof(long) > sizeof(int)
+ platform_is wordsize: 64 do # sizeof(long) > sizeof(int)
it "raises a TypeError if passed nil" do
-> { @s.FIX2INT(nil) }.should raise_error(TypeError)
end
@@ -74,7 +74,7 @@ describe "CApiFixnumSpecs" do
end
end
- platform_is c_long_size: 64 do # sizeof(long) > sizeof(int)
+ platform_is wordsize: 64 do # sizeof(long) > sizeof(int)
it "raises a TypeError if passed nil" do
-> { @s.FIX2UINT(nil) }.should raise_error(TypeError)
end
diff --git a/spec/ruby/optional/capi/fixtures/kernel.rb b/spec/ruby/optional/capi/fixtures/kernel.rb
deleted file mode 100644
index d3fc7c57e8..0000000000
--- a/spec/ruby/optional/capi/fixtures/kernel.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class CApiKernelSpecs
- class ClassWithPublicMethod
- def public_method(*, **)
- :public
- end
- end
-
- class ClassWithPrivateMethod
- private def private_method(*, **)
- :private
- end
- end
-
- class ClassWithProtectedMethod
- protected def protected_method(*, **)
- :protected
- end
- end
-end
diff --git a/spec/ruby/optional/capi/gc_spec.rb b/spec/ruby/optional/capi/gc_spec.rb
index d9661328ab..d76ea7394f 100644
--- a/spec/ruby/optional/capi/gc_spec.rb
+++ b/spec/ruby/optional/capi/gc_spec.rb
@@ -27,36 +27,9 @@ describe "CApiGCSpecs" do
end
describe "rb_global_variable" do
- before :all do
+ it "keeps the value alive even if the value is assigned after rb_global_variable() is called" do
GC.start
- end
-
- describe "keeps the value alive even if the value is assigned after rb_global_variable() is called" do
- it "for a string" do
- @f.registered_before_rb_global_variable_string.should == "registered before rb_global_variable()"
- end
-
- it "for a bignum" do
- @f.registered_before_rb_global_variable_bignum.should == 2**63 - 1
- end
-
- it "for a Float" do
- @f.registered_before_rb_global_variable_float.should == 3.14
- end
- end
-
- describe "keeps the value alive when the value is assigned before rb_global_variable() is called" do
- it "for a string" do
- @f.registered_after_rb_global_variable_string.should == "registered after rb_global_variable()"
- end
-
- it "for a bignum" do
- @f.registered_after_rb_global_variable_bignum.should == 2**63 - 1
- end
-
- it "for a Float" do
- @f.registered_after_rb_global_variable_float.should == 6.28
- end
+ @f.registered_before_rb_global_variable.should == "registered before rb_global_variable()"
end
end
@@ -108,10 +81,6 @@ describe "CApiGCSpecs" do
it "can be called with an object" do
@f.rb_gc_register_mark_object(Object.new).should be_nil
end
-
- it "keeps the value alive even if the value is not referenced by any Ruby object" do
- @f.rb_gc_register_mark_object_not_referenced_float.should == 1.61
- end
end
describe "rb_gc_latest_gc_info" do
diff --git a/spec/ruby/optional/capi/hash_spec.rb b/spec/ruby/optional/capi/hash_spec.rb
index a0e49ffc4c..a60467a66b 100644
--- a/spec/ruby/optional/capi/hash_spec.rb
+++ b/spec/ruby/optional/capi/hash_spec.rb
@@ -50,22 +50,6 @@ describe "C-API Hash function" do
end
end
- ruby_version_is '3.2' do
- describe "rb_hash_new_capa" do
- it "returns a new hash" do
- @s.rb_hash_new_capa(3).should == {}
- end
-
- it "creates a hash with no default proc" do
- @s.rb_hash_new_capa(3) {}.default_proc.should be_nil
- end
-
- it "raises RuntimeError when negative index is provided" do
- -> { @s.rb_hash_new_capa(-1) }.should raise_error(RuntimeError, "st_table too big")
- end
- end
- end
-
describe "rb_ident_hash_new" do
it "returns a new compare by identity hash" do
result = @s.rb_ident_hash_new
diff --git a/spec/ruby/optional/capi/integer_spec.rb b/spec/ruby/optional/capi/integer_spec.rb
index 089872381c..e26735824e 100644
--- a/spec/ruby/optional/capi/integer_spec.rb
+++ b/spec/ruby/optional/capi/integer_spec.rb
@@ -140,23 +140,6 @@ describe "CApiIntegerSpecs" do
result.should == -1
@words.should == "\x11\x32\x54\x76\x98\xBA\xDC\xFE"
end
-
- it "converts numbers near the fixnum limit successfully" do
- result = @s.rb_integer_pack(0x7123_4567_89ab_cdef, @words, 1, 8, 0,
- CApiIntegerSpecs::NATIVE|CApiIntegerSpecs::PACK_2COMP)
- result.should == 1
- @words.should == "\xEF\xCD\xAB\x89\x67\x45\x23\x71"
-
- result = @s.rb_integer_pack(2**62-1, @words, 1, 8, 0,
- CApiIntegerSpecs::NATIVE|CApiIntegerSpecs::PACK_2COMP)
- result.should == 1
- @words.should == "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x3F"
-
- result = @s.rb_integer_pack(2**63-1, @words, 1, 8, 0,
- CApiIntegerSpecs::NATIVE|CApiIntegerSpecs::PACK_2COMP)
- result.should == 1
- @words.should == "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"
- end
end
end
end
diff --git a/spec/ruby/optional/capi/io_spec.rb b/spec/ruby/optional/capi/io_spec.rb
index 01588408e1..95717351a6 100644
--- a/spec/ruby/optional/capi/io_spec.rb
+++ b/spec/ruby/optional/capi/io_spec.rb
@@ -1,5 +1,4 @@
require_relative 'spec_helper'
-require_relative '../../fixtures/io'
load_extension('io')
@@ -176,18 +175,13 @@ describe "C-API IO function" do
end
end
- describe "rb_io_descriptor or GetOpenFile" do
+ describe "GetOpenFile" do
it "allows access to the system fileno" do
@o.GetOpenFile_fd($stdin).should == 0
@o.GetOpenFile_fd($stdout).should == 1
@o.GetOpenFile_fd($stderr).should == 2
@o.GetOpenFile_fd(@io).should == @io.fileno
end
-
- it "raises IOError if the IO is closed" do
- @io.close
- -> { @o.GetOpenFile_fd(@io) }.should raise_error(IOError, "closed stream")
- end
end
describe "rb_io_binmode" do
@@ -262,43 +256,6 @@ describe "C-API IO function" do
end
end
- ruby_version_is "3.1" do
- describe "rb_io_maybe_wait_writable" do
- it "returns mask for events if operation was interrupted" do
- @o.rb_io_maybe_wait_writable(Errno::EINTR::Errno, @w_io, nil).should == IO::WRITABLE
- end
-
- it "returns 0 if there is no error condition" do
- @o.rb_io_maybe_wait_writable(0, @w_io, nil).should == 0
- end
-
- it "raises an IOError if the IO is closed" do
- @w_io.close
- -> { @o.rb_io_maybe_wait_writable(0, @w_io, nil) }.should raise_error(IOError, "closed stream")
- end
-
- it "raises an IOError if the IO is not initialized" do
- -> { @o.rb_io_maybe_wait_writable(0, IO.allocate, nil) }.should raise_error(IOError, "uninitialized stream")
- end
-
- it "can be interrupted" do
- IOSpec.exhaust_write_buffer(@w_io)
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
-
- t = Thread.new do
- @o.rb_io_maybe_wait_writable(0, @w_io, 10)
- end
-
- Thread.pass until t.stop?
- t.kill
- t.join
-
- finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- (finish - start).should < 9
- end
- end
- end
-
describe "rb_thread_fd_writable" do
it "waits til an fd is ready for writing" do
@o.rb_thread_fd_writable(@w_io).should be_nil
@@ -348,55 +305,6 @@ describe "C-API IO function" do
thr.join
end
end
-
- ruby_version_is "3.1" do
- describe "rb_io_maybe_wait_readable" do
- it "returns mask for events if operation was interrupted" do
- @o.rb_io_maybe_wait_readable(Errno::EINTR::Errno, @r_io, nil, false).should == IO::READABLE
- end
-
- it "returns 0 if there is no error condition" do
- @o.rb_io_maybe_wait_readable(0, @r_io, nil, false).should == 0
- end
-
- it "blocks until the io is readable and returns events that actually occurred" do
- @o.instance_variable_set :@write_data, false
- thr = Thread.new do
- Thread.pass until @o.instance_variable_get(:@write_data)
- @w_io.write "rb_io_wait_readable"
- end
-
- @o.rb_io_maybe_wait_readable(Errno::EAGAIN::Errno, @r_io, IO::READABLE, true).should == IO::READABLE
- @o.instance_variable_get(:@read_data).should == "rb_io_wait_re"
-
- thr.join
- end
-
- it "can be interrupted" do
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
-
- t = Thread.new do
- @o.rb_io_maybe_wait_readable(0, @r_io, 10, false)
- end
-
- Thread.pass until t.stop?
- t.kill
- t.join
-
- finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- (finish - start).should < 9
- end
-
- it "raises an IOError if the IO is closed" do
- @r_io.close
- -> { @o.rb_io_maybe_wait_readable(0, @r_io, nil, false) }.should raise_error(IOError, "closed stream")
- end
-
- it "raises an IOError if the IO is not initialized" do
- -> { @o.rb_io_maybe_wait_readable(0, IO.allocate, nil, false) }.should raise_error(IOError, "uninitialized stream")
- end
- end
- end
end
describe "rb_thread_wait_fd" do
@@ -436,98 +344,10 @@ describe "C-API IO function" do
@o.rb_wait_for_single_fd(@r_io, 1, 0, 0).should == 0
end
end
-
- ruby_version_is "3.1" do
- describe "rb_io_maybe_wait" do
- it "waits til an fd is ready for reading" do
- start = false
- thr = Thread.new do
- start = true
- sleep 0.05
- @w_io.write "rb_io_maybe_wait"
- end
-
- Thread.pass until start
-
- @o.rb_io_maybe_wait(Errno::EAGAIN::Errno, @r_io, IO::READABLE, nil).should == IO::READABLE
-
- thr.join
- end
-
- it "returns mask for events if operation was interrupted" do
- @o.rb_io_maybe_wait(Errno::EINTR::Errno, @w_io, IO::WRITABLE, nil).should == IO::WRITABLE
- end
-
- it "raises an IOError if the IO is closed" do
- @w_io.close
- -> { @o.rb_io_maybe_wait(0, @w_io, IO::WRITABLE, nil) }.should raise_error(IOError, "closed stream")
- end
-
- it "raises an IOError if the IO is not initialized" do
- -> { @o.rb_io_maybe_wait(0, IO.allocate, IO::WRITABLE, nil) }.should raise_error(IOError, "uninitialized stream")
- end
-
- it "can be interrupted when waiting for READABLE event" do
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
-
- t = Thread.new do
- @o.rb_io_maybe_wait(0, @r_io, IO::READABLE, 10)
- end
-
- Thread.pass until t.stop?
- t.kill
- t.join
-
- finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- (finish - start).should < 9
- end
-
- it "can be interrupted when waiting for WRITABLE event" do
- IOSpec.exhaust_write_buffer(@w_io)
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
-
- t = Thread.new do
- @o.rb_io_maybe_wait(0, @w_io, IO::WRITABLE, 10)
- end
-
- Thread.pass until t.stop?
- t.kill
- t.join
-
- finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
- (finish - start).should < 9
- end
- end
- end
-
- ruby_version_is "3.3" do
- describe "rb_io_mode" do
- it "returns the mode" do
- (@o.rb_io_mode(@r_io) & 0b11).should == 0b01
- (@o.rb_io_mode(@w_io) & 0b11).should == 0b10
- (@o.rb_io_mode(@rw_io) & 0b11).should == 0b11
- end
- end
-
- describe "rb_io_path" do
- it "returns the IO#path" do
- @o.rb_io_path(@r_io).should == @r_io.path
- @o.rb_io_path(@rw_io).should == @rw_io.path
- @o.rb_io_path(@rw_io).should == @name
- end
- end
- end
-
- ruby_version_is "3.4" do
- describe "rb_io_maybe_wait" do
- it "returns nil if there is no error condition" do
- @o.rb_io_maybe_wait(0, @w_io, IO::WRITABLE, nil).should == nil
- end
- end
- end
end
describe "rb_fd_fix_cloexec" do
+
before :each do
@o = CApiIOSpecs.new
diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb
index 3b61d4f0f1..54d8d8a8d3 100644
--- a/spec/ruby/optional/capi/kernel_spec.rb
+++ b/spec/ruby/optional/capi/kernel_spec.rb
@@ -1,5 +1,4 @@
require_relative 'spec_helper'
-require_relative 'fixtures/kernel'
kernel_path = load_extension("kernel")
@@ -503,11 +502,6 @@ describe "C-API Kernel function" do
it "evaluates a string of ruby code" do
@s.rb_eval_string("1+1").should == 2
end
-
- it "captures local variables when called within a method" do
- a = 2
- @s.rb_eval_string("a+1").should == 3
- end
end
describe "rb_eval_cmd_kw" do
@@ -603,65 +597,47 @@ describe "C-API Kernel function" do
@s.rb_funcallv(self, :empty, []).should == 42
@s.rb_funcallv(self, :sum, [1, 2]).should == 3
end
-
- it "calls a private method" do
- object = CApiKernelSpecs::ClassWithPrivateMethod.new
- @s.rb_funcallv(object, :private_method, []).should == :private
- end
-
- it "calls a protected method" do
- object = CApiKernelSpecs::ClassWithProtectedMethod.new
- @s.rb_funcallv(object, :protected_method, []).should == :protected
- end
end
- describe "rb_funcallv_kw" do
- it "passes keyword arguments to the callee" do
- def m(*args, **kwargs)
- [args, kwargs]
- end
-
- @s.rb_funcallv_kw(self, :m, [{}]).should == [[], {}]
- @s.rb_funcallv_kw(self, :m, [{a: 1}]).should == [[], {a: 1}]
- @s.rb_funcallv_kw(self, :m, [{b: 2}, {a: 1}]).should == [[{b: 2}], {a: 1}]
- @s.rb_funcallv_kw(self, :m, [{b: 2}, {}]).should == [[{b: 2}], {}]
- end
+ ruby_version_is "3.0" do
+ describe "rb_funcallv_kw" do
+ it "passes keyword arguments to the callee" do
+ def m(*args, **kwargs)
+ [args, kwargs]
+ end
- it "calls a private method" do
- object = CApiKernelSpecs::ClassWithPrivateMethod.new
- @s.rb_funcallv_kw(object, :private_method, [{}]).should == :private
- end
+ @s.rb_funcallv_kw(self, :m, [{}]).should == [[], {}]
+ @s.rb_funcallv_kw(self, :m, [{a: 1}]).should == [[], {a: 1}]
+ @s.rb_funcallv_kw(self, :m, [{b: 2}, {a: 1}]).should == [[{b: 2}], {a: 1}]
+ @s.rb_funcallv_kw(self, :m, [{b: 2}, {}]).should == [[{b: 2}], {}]
+ end
- it "calls a protected method" do
- object = CApiKernelSpecs::ClassWithProtectedMethod.new
- @s.rb_funcallv_kw(object, :protected_method, [{}]).should == :protected
- end
+ it "raises TypeError if the last argument is not a Hash" do
+ def m(*args, **kwargs)
+ [args, kwargs]
+ end
- it "raises TypeError if the last argument is not a Hash" do
- def m(*args, **kwargs)
- [args, kwargs]
+ -> {
+ @s.rb_funcallv_kw(self, :m, [42])
+ }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash')
end
-
- -> {
- @s.rb_funcallv_kw(self, :m, [42])
- }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash')
end
- end
- describe "rb_keyword_given_p" do
- it "returns whether keywords were given to the C extension method" do
- h = {a: 1}
- empty = {}
- @s.rb_keyword_given_p(a: 1).should == true
- @s.rb_keyword_given_p("foo" => "bar").should == true
- @s.rb_keyword_given_p(**h).should == true
+ describe "rb_keyword_given_p" do
+ it "returns whether keywords were given to the C extension method" do
+ h = {a: 1}
+ empty = {}
+ @s.rb_keyword_given_p(a: 1).should == true
+ @s.rb_keyword_given_p("foo" => "bar").should == true
+ @s.rb_keyword_given_p(**h).should == true
- @s.rb_keyword_given_p(h).should == false
- @s.rb_keyword_given_p().should == false
- @s.rb_keyword_given_p(**empty).should == false
+ @s.rb_keyword_given_p(h).should == false
+ @s.rb_keyword_given_p().should == false
+ @s.rb_keyword_given_p(**empty).should == false
- @s.rb_funcallv_kw(@s, :rb_keyword_given_p, [{a: 1}]).should == true
- @s.rb_funcallv_kw(@s, :rb_keyword_given_p, [{}]).should == false
+ @s.rb_funcallv_kw(@s, :rb_keyword_given_p, [{a: 1}]).should == true
+ @s.rb_funcallv_kw(@s, :rb_keyword_given_p, [{}]).should == false
+ end
end
end
@@ -700,91 +676,21 @@ describe "C-API Kernel function" do
end
describe 'rb_funcall_with_block' do
- it "calls a method with block" do
+ before :each do
@obj = Object.new
class << @obj
- def method_public(*args); [args, yield] end
+ def method_public; yield end
+ def method_private; yield end
+ private :method_private
end
-
- @s.rb_funcall_with_block(@obj, :method_public, [1, 2], proc { :result }).should == [[1, 2], :result]
- end
-
- it "does not call a private method" do
- object = CApiKernelSpecs::ClassWithPrivateMethod.new
-
- -> {
- @s.rb_funcall_with_block(object, :private_method, [], proc { })
- }.should raise_error(NoMethodError, /private/)
- end
-
- it "does not call a protected method" do
- object = CApiKernelSpecs::ClassWithProtectedMethod.new
-
- -> {
- @s.rb_funcall_with_block(object, :protected_method, [], proc { })
- }.should raise_error(NoMethodError, /protected/)
end
- end
-
- describe 'rb_funcall_with_block_kw' do
- it "calls a method with keyword arguments and a block" do
- @obj = Object.new
- class << @obj
- def method_public(*args, **kw, &block); [args, kw, block.call] end
- end
- @s.rb_funcall_with_block_kw(@obj, :method_public, [1, 2, {a: 2}], proc { :result }).should == [[1, 2], {a: 2}, :result]
+ it "calls a method with block" do
+ @s.rb_funcall_with_block(@obj, :method_public, proc { :result }).should == :result
end
it "does not call a private method" do
- object = CApiKernelSpecs::ClassWithPrivateMethod.new
-
- -> {
- @s.rb_funcall_with_block_kw(object, :private_method, [{}], proc { })
- }.should raise_error(NoMethodError, /private/)
- end
-
- it "does not call a protected method" do
- object = CApiKernelSpecs::ClassWithProtectedMethod.new
-
- -> {
- @s.rb_funcall_with_block_kw(object, :protected_method, [{}], proc { })
- }.should raise_error(NoMethodError, /protected/)
- end
- end
-
- describe "rb_check_funcall" do
- it "calls a method" do
- @s.rb_check_funcall(1, :+, [2]).should == 3
- end
-
- it "returns Qundef if the method is not defined" do
- obj = Object.new
- @s.rb_check_funcall(obj, :foo, []).should == :Qundef
- end
-
- it "uses #respond_to? to check if the method is defined" do
- ScratchPad.record []
- obj = Object.new
- def obj.respond_to?(name, priv)
- ScratchPad << name
- name == :foo || super
- end
- def obj.method_missing(name, *args)
- name == :foo ? [name, 42] : super
- end
- @s.rb_check_funcall(obj, :foo, []).should == [:foo, 42]
- ScratchPad.recorded.should == [:foo]
- end
-
- it "calls a private method" do
- object = CApiKernelSpecs::ClassWithPrivateMethod.new
- @s.rb_check_funcall(object, :private_method, []).should == :private
- end
-
- it "calls a protected method" do
- object = CApiKernelSpecs::ClassWithProtectedMethod.new
- @s.rb_check_funcall(object, :protected_method, []).should == :protected
+ -> { @s.rb_funcall_with_block(@obj, :method_private, proc { :result }) }.should raise_error(NoMethodError, /private/)
end
end
end
diff --git a/spec/ruby/optional/capi/numeric_spec.rb b/spec/ruby/optional/capi/numeric_spec.rb
index e9667da5ba..95213d3f2b 100644
--- a/spec/ruby/optional/capi/numeric_spec.rb
+++ b/spec/ruby/optional/capi/numeric_spec.rb
@@ -106,7 +106,7 @@ describe "CApiNumericSpecs" do
@s.NUM2LONG(5).should == 5
end
- platform_is c_long_size: 32 do
+ platform_is wordsize: 32 do
it "converts -1 to an signed number" do
@s.NUM2LONG(-1).should == -1
end
@@ -120,7 +120,7 @@ describe "CApiNumericSpecs" do
end
end
- platform_is c_long_size: 64 do
+ platform_is wordsize: 64 do
it "converts -1 to an signed number" do
@s.NUM2LONG(-1).should == -1
end
@@ -210,7 +210,7 @@ describe "CApiNumericSpecs" do
@s.NUM2ULONG(5).should == 5
end
- platform_is c_long_size: 32 do
+ platform_is wordsize: 32 do
it "converts -1 to an unsigned number" do
@s.NUM2ULONG(-1).should == 4294967295
end
@@ -231,7 +231,7 @@ describe "CApiNumericSpecs" do
end
end